diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/CREDITS linux-2.4.21-pre6/CREDITS
--- linux-2.4.20/CREDITS	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-pre6/CREDITS	2003-03-26 23:49:09.000000000 +0000
@@ -733,7 +733,7 @@
 D: Dell PowerEdge server, SCSI layer, misc drivers, and other patches
 S: Dell Computer Corporation
 S: One Dell Way
-S: Round Rock, TX  78681
+S: Round Rock, TX  78682
 S: USA
 
 N: Eddie C. Dost
@@ -1008,7 +1008,7 @@
 S: USA
 
 N: Jeff Garzik
-E: jgarzik@mandrakesoft.com
+E: jgarzik@pobox.com
 
 N: Jacques Gelinas
 E: jacques@solucorp.qc.ca
@@ -1065,6 +1065,11 @@
 D: Transformed old user space bdflush into 1st kernel thread - kflushd.
 D: Many other patches, documentation files, mini kernels, utilities, ...
 
+N: Masanori GOTO
+E: gotom@debian.or.jp
+D: Workbit NinjaSCSI-32Bi/UDE driver
+S: Japan
+
 N: John E. Gotts
 E: jgotts@linuxsavvy.com
 D: kernel hacker
@@ -1231,16 +1236,18 @@
 
 N: Christoph Hellwig
 E: hch@infradead.org
-D: misc driver & makefile hacking
+E: hch@sgi.com
+D: all kinds of driver, filesystem & core kernel hacking
 D: freevxfs driver
 D: sysvfs maintainer
-S: Triftstraße 26
-S: 38644 Goslar
+D: chief codingstyle nitpicker
+S: Auweg 38
+S: 85748 Garching
 S: Germany
 
 N: Richard Henderson
 E: rth@twiddle.net
-E: rth@cygnus.com
+E: rth@redhat.com
 D: Alpha hacker, kernel and userland
 S: 1668 California St.
 S: Mountain View, California 94041
@@ -1488,7 +1495,7 @@
 S: United Kingdom
 
 N: Ani Joshi
-E: ajoshi@shell.unixbox.com
+E: ajoshi@kernel.crashing.org
 D: fbdev hacking
 
 N: Bernhard Kaindl
@@ -1888,7 +1895,8 @@
 E: pavel@ucw.cz
 E: pavel@suse.cz
 D: Softcursor for vga, hypertech cdrom support, vcsa bugfix, nbd
-D: sun4/330 port, capabilities for elf, speedup for rm on ext2, USB
+D: sun4/330 port, capabilities for elf, speedup for rm on ext2, USB,
+D: x86-64 port, software suspend
 S: Volkova 1131
 S: 198 00 Praha 9
 S: Czech Republic
@@ -2210,11 +2218,12 @@
 S: United Kingdom
 
 N: Ian S. Nelson
-E: ian.nelson@echostar.com
+E: nelsonis@earthlink.net
 D: Minor mmap and ide hacks
 S: 1370 Atlantis Ave.
 S: Lafayette CO, 80026
 S: USA
+P: 1024D/DD478240 4073 9AF8 027F 278D CBBB  DA3C 9905 0415 DD47 8240
 
 N: Russell Nelson
 E: nelson@crynwr.com
@@ -2226,6 +2235,15 @@
 S: Potsdam, New York 13676
 S: USA
 
+N: Dave Neuer
+E: dneuer@innovation-charter.com
+E: mr_fred_smoothie@yahoo.com
+D: Helped implement support for Compaq's H31xx series iPAQs
+D: Other mostly minor tweaks & bugfixes
+S: 325 E. Main St., Suite 3
+S: Carnegie, PA 15105
+S: USA
+
 N: Michael Neuffer
 E: mike@i-Connect.Net
 E: neuffer@goofy.zdv.uni-mainz.de
@@ -2397,13 +2415,10 @@
 D: CDROM driver "sonycd535" (Sony CDU-535/531)
 
 N: Stelian Pop
-E: stelian.pop@fr.alcove.com
+E: stelian@popies.net
 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
+S: Paris, France
 
 N: Frederic Potter 
 E: fpotter@cirpack.com
@@ -3282,6 +3297,12 @@
 S: Socorro NM, 87801
 S: USA
 
+N: Hiroshi YOKOTA
+E: yokota@netlab.is.tsukuba.ac.jp
+D: Workbit NinjaSCSI-3/32Bi PCMCIA driver
+D: Workbit NinjaSCSI-32Bi/UDE driver
+S: Japan
+
 N: Eric Youngdale
 E: eric@andante.org
 W: http://www.andante.org
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/BK-usage/00-INDEX linux-2.4.21-pre6/Documentation/BK-usage/00-INDEX
--- linux-2.4.20/Documentation/BK-usage/00-INDEX	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/BK-usage/00-INDEX	2003-03-26 23:49:31.000000000 +0000
@@ -0,0 +1,38 @@
+bk-kernel-howto.txt: Description of kernel workflow under BitKeeper
+
+bk-make-sum: Create summary of changesets in one repository and not
+another, typically in preparation to be sent to an upstream maintainer.
+Typical usage:
+	cd my-updated-repo
+	bk-make-sum ~/repo/original-repo
+	mv /tmp/linus.txt ../original-repo.txt
+
+bksend: Create readable text output containing summary of changes, GNU
+patch of the changes, and BK metadata of changes (as needed for proper
+importing into BitKeeper by an upstream maintainer).  This output is
+suitable for emailing BitKeeper changes.  The recipient of this output
+may pipe it directly to 'bk receive'.
+
+bz64wrap: helper script. Uncompressed input is piped to this script,
+which compresses its input, and then outputs the uu-/base64-encoded
+version of the compressed input.
+
+csets-to-patches: Produces a delta of two BK repositories, in the form
+of individual files, each containing a single cset as a GNU patch.
+Output is several files, each with the filename "/tmp/rev-$REV.patch"
+Typical usage:
+	cd my-updated-repo
+	bk changes -L ~/repo/original-repo 2>&1 | \
+		perl csets-to-patches
+
+cset-to-linus: Produces a delta of two BK repositories, in the form of
+changeset descriptions, with 'diffstat' output created for each
+individual changset.
+Typical usage:
+	cd my-updated-repo
+	bk changes -L ~/repo/original-repo 2>&1 | \
+		perl cset-to-linus > summary.txt
+
+unbz64wrap: Reverse an encoded, compressed data stream created by
+bz64wrap into an uncompressed, typically text/plain output.
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/BK-usage/bk-kernel-howto.txt linux-2.4.21-pre6/Documentation/BK-usage/bk-kernel-howto.txt
--- linux-2.4.20/Documentation/BK-usage/bk-kernel-howto.txt	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/BK-usage/bk-kernel-howto.txt	2003-03-26 23:49:34.000000000 +0000
@@ -32,7 +32,7 @@
 
 Let's start with this progression:
 Each BitKeeper source tree on disk is a repository unto itself.
-Each repository has a parent.
+Each repository has a parent (except the root/original, of course).
 Each repository contains a set of a changesets ("csets").
 Each cset is one or more changed files, bundled together.
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/Configure.help linux-2.4.21-pre6/Documentation/Configure.help
--- linux-2.4.20/Documentation/Configure.help	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/Configure.help	2003-03-26 23:49:54.000000000 +0000
@@ -246,14 +246,22 @@
 
   If unsure, say N.
 
-Multiquad support for NUMA systems
-CONFIG_MULTIQUAD
+Multiquad support for NUMAQ systems
+CONFIG_X86_NUMAQ
   This option is used for getting Linux to run on a (IBM/Sequent) NUMA 
   multiquad box. This changes the way that processors are bootstrapped,
   and uses Clustered Logical APIC addressing mode instead of Flat Logical.
   You will need a new lynxer.elf file to flash your firmware with - send
   email to Martin.Bligh@us.ibm.com
 
+Support for IBM Summit (EXA) systems
+CONFIG_X86_SUMMIT
+  This option is needed for IBM systems that use the Summit/EXA chipset.
+  (EXA: Extendable Xseries Architecture)In particular, it is needed for 
+  the x440 (even for the 4-CPU model).
+
+  If you don't have this computer, you may safely say N.
+
 IO-APIC support on uniprocessors
 CONFIG_X86_UP_IOAPIC
   An IO-APIC (I/O Advanced Programmable Interrupt Controller) is an
@@ -1033,7 +1041,7 @@
 
 Pacific Digital A-DMA support (EXPERIMENTAL)
 CONFIG_BLK_DEV_PDC_ADMA
-  Please read the comments at the top of <file:drivers/ide/ide-pci.c>.
+  Please read the comments at the top of <file:drivers/ide/setup-pci.c>.
 
 3ware Hardware ATA-RAID support
 CONFIG_BLK_DEV_3W_XXXX_RAID
@@ -1063,13 +1071,13 @@
   The ATP860 is an UltraDMA 66 chipset base.
   The ATP860M(acintosh) version is an UltraDMA 66 chipset base.
 
-  Please read the comments at the top of <file:drivers/ide/aec62xx.c>.
+  Please read the comments at the top of <file:drivers/ide/pci/aec62xx.c>.
   If you say Y here, then say Y to "Use DMA by default when available"
   as well.
 
 AEC62XX Tuning support
 CONFIG_AEC62XX_TUNING
-  Please read the comments at the top of <file:drivers/ide/aec62xx.c>.
+  Please read the comments at the top of <file:drivers/ide/pci/aec62xx.c>.
   If unsure, say N.
 
 ALI M15x3 chipset support
@@ -1080,7 +1088,7 @@
 
   If you say Y here, you also need to say Y to "Use DMA by default
   when available", above.  Please read the comments at the top of
-  <file:drivers/ide/alim15x3.c>.
+  <file:drivers/ide/pci/alim15x3.c>.
 
   If unsure, say N.
 
@@ -1104,7 +1112,7 @@
 
   If you say Y here, you also need to say Y to "Use DMA by default
   when available", above.
-  Please read the comments at the top of <file:drivers/ide/amd74xx.c>.
+  Please read the comments at the top of <file:drivers/ide/pci/amd74xx.c>.
 
   If unsure, say N.
 
@@ -1114,10 +1122,10 @@
   This effect can be also invoked by calling "idex=ata66"
   If unsure, say N.
 
-CMD64X and CMD680 chipset support
+CMD64X/CMD680 chipset support
 CONFIG_BLK_DEV_CMD64X
   Say Y here if you have an IDE controller which uses any of these
-  chipsets: CMD643, CMD646, CMD648, CMD649 or CMD680.
+  chipsets: CMD643, CMD646 and CMD648.
 
 CY82C693 chipset support
 CONFIG_BLK_DEV_CY82C693
@@ -1148,16 +1156,18 @@
 HPT34X AUTODMA support (WIP)
 CONFIG_HPT34X_AUTODMA
   This is a dangerous thing to attempt currently! Please read the
-  comments at the top of <file:drivers/ide/hpt34x.c>.  If you say Y
+  comments at the top of <file:drivers/ide/pci/hpt34x.c>.  If you say Y
   here, then say Y to "Use DMA by default when available" as well.
 
   If unsure, say N.
 
-HPT366/368/370 chipset support
+HPT36X/37X chipset support
 CONFIG_BLK_DEV_HPT366
   HPT366 is an Ultra DMA chipset for ATA-66.
   HPT368 is an Ultra DMA chipset for ATA-66 RAID Based.
   HPT370 is an Ultra DMA chipset for ATA-100.
+  HPT372 is an Ultra DMA chipset for ATA-133.
+  HPT374 is an Ultra DMA chipset for ATA-133.
 
   This driver adds up to 4 more EIDE devices sharing a single
   interrupt.
@@ -1179,12 +1189,12 @@
   This driver adds detection and support for the NS87415 chip
   (used in SPARC64, among others).
 
-  Please read the comments at the top of <file:drivers/ide/ns87415.c>.
+  Please read the comments at the top of <file:drivers/ide/pci/ns87415.c>.
 
 OPTi 82C621 chipset enhanced support (EXPERIMENTAL)
 CONFIG_BLK_DEV_OPTI621
   This is a driver for the OPTi 82C621 EIDE controller.
-  Please read the comments at the top of <file:drivers/ide/opti621.c>.
+  Please read the comments at the top of <file:drivers/ide/pci/opti621.c>.
 
 ServerWorks OSB4/CSB5 chipset support
 CONFIG_BLK_DEV_SVWKS
@@ -1198,7 +1208,7 @@
   PIO 0-4 mode settings, this allows dynamic tuning of the chipset
   via the standard end-user tool 'hdparm'.
 
-  Please read the comments at the top of <file:drivers/ide/piix.c>.
+  Please read the comments at the top of <file:drivers/ide/pci/piix.c>.
 
   If you say Y here, you should also say Y to "PIIXn Tuning support",
   below.
@@ -1218,7 +1228,7 @@
   If unsure, say N.
 
 PROMISE PDC20246/PDC20262/PDC20265/PDC20267/PDC20268 support
-CONFIG_BLK_DEV_PDC202XX
+CONFIG_BLK_DEV_PDC202XX_OLD
   Promise Ultra33 or PDC20246
   Promise Ultra66 or PDC20262
   Promise Ultra100 or PDC20265/PDC20267/PDC20268
@@ -1236,7 +1246,7 @@
   available" as well.
 
   Please read the comments at the top of
-  <file:drivers/ide/pdc202xx.c>.
+  <file:drivers/ide/pci/pdc202xx_old.c>.
 
   If unsure, say N.
 
@@ -1251,7 +1261,7 @@
   when the PDC20265 BIOS has been disabled (for faster boot up).
 
   Please read the comments at the top of
-  <file:drivers/ide/pdc202xx.c>.
+  <file:drivers/ide/pci/pdc202xx_old.c>.
 
   If unsure, say N.
 
@@ -1274,7 +1284,12 @@
   If you say Y here, you need to say Y to "Use DMA by default when
   available" as well.
 
-  Please read the comments at the top of <file:drivers/ide/sis5513.c>.
+  Please read the comments at the top of <file:drivers/ide/pci/sis5513.c>.
+
+Silicon Image chipset support
+CONFIG_BLK_DEV_SIIMAGE
+  This driver provides (U)DMA support for the SII3112 SATA controllers and
+  for the CMD/SI680 UDMA/DMA ATA controller.
 
 SLC90E66 chipset support
 CONFIG_BLK_DEV_SLC90E66
@@ -1288,7 +1303,7 @@
   available" as well.
 
   Please read the comments at the top of
-  <file:drivers/ide/slc90e66.c>.
+  <file:drivers/ide/pci/slc90e66.c>.
 
 Winbond SL82c105 support
 CONFIG_BLK_DEV_SL82C105
@@ -1301,7 +1316,7 @@
   This driver adds support for bus master DMA transfers
   using the Tekram TRM290 PCI IDE chip. Volunteers are
   needed for further tweaking and development.
-  Please read the comments at the top of <file:drivers/ide/trm290.c>.
+  Please read the comments at the top of <file:drivers/ide/pci/trm290.c>.
 
 VIA82CXXX chipset support
 CONFIG_BLK_DEV_VIA82CXXX
@@ -1313,7 +1328,7 @@
   system" support.
 
   Please read the comments at the top of
-  <file:drivers/ide/via82cxxx.c>.
+  <file:drivers/ide/pci/via82cxxx.c>.
 
   If you say Y here, then say Y to "Use DMA by default when available"
   as well.
@@ -1353,7 +1368,7 @@
   boot parameter.  It enables support for the secondary IDE interface
   of the ALI M1439/1443/1445/1487/1489 chipsets, and permits faster
   I/O speeds to be set as well.  See the files
-  <file:Documentation/ide.txt> and <file:drivers/ide/ali14xx.c> for
+  <file:Documentation/ide.txt> and <file:drivers/ide/legacy/ali14xx.c> for
   more info.
 
 DTC-2278 support
@@ -1362,7 +1377,7 @@
   boot parameter. It enables support for the secondary IDE interface
   of the DTC-2278 card, and permits faster I/O speeds to be set as
   well. See the <file:Documentation/ide.txt> and
-  <file:drivers/ide/dtc2278.c> files for more info.
+  <file:drivers/ide/legacy/dtc2278.c> files for more info.
 
 Holtek HT6560B support
 CONFIG_BLK_DEV_HT6560B
@@ -1370,7 +1385,7 @@
   boot parameter. It enables support for the secondary IDE interface
   of the Holtek card, and permits faster I/O speeds to be set as well.
   See the <file:Documentation/ide.txt> and
-  <file:drivers/ide/ht6560b.c> files for more info.
+  <file:drivers/ide/legacy/ht6560b.c> files for more info.
 
 PROMISE DC4030 support (EXPERIMENTAL)
 CONFIG_BLK_DEV_PDC4030
@@ -1380,14 +1395,14 @@
   attached to the secondary interface.  CD-ROM and TAPE devices are
   not supported yet.  This driver is enabled at runtime using the
   "ide0=dc4030" kernel boot parameter.  See the
-  <file:Documentation/ide.txt> and <file:drivers/ide/pdc4030.c> files
+  <file:Documentation/ide.txt> and <file:drivers/ide/legacy/pdc4030.c> files
   for more info.
 
 QDI QD65XX support
 CONFIG_BLK_DEV_QD65XX
   This driver is enabled at runtime using the "ide0=qd65xx" kernel
   boot parameter.  It permits faster I/O speeds to be set.  See the
-  <file:Documentation/ide.txt> and <file:drivers/ide/qd65xx.c> for
+  <file:Documentation/ide.txt> and <file:drivers/ide/legacy/qd65xx.c> for
   more info.
 
 UMC 8672 support
@@ -1396,7 +1411,7 @@
   boot parameter. It enables support for the secondary IDE interface
   of the UMC-8672, and permits faster I/O speeds to be set as well.
   See the files <file:Documentation/ide.txt> and
-  <file:drivers/ide/umc8672.c> for more info.
+  <file:drivers/ide/legacy/umc8672.c> for more info.
 
 Amiga Gayle IDE interface support
 CONFIG_BLK_DEV_GAYLE
@@ -3543,6 +3558,13 @@
   You should say Y here if you use XFree86 3.3.6 or 4.x and want to
   use GLX or DRI.  If unsure, say N.
 
+CONFIG_AGP_AMD_8151
+  This option gives you AGP support for the GLX component of
+  XFree86 on AMD K8 with an AGP 8151 chipset.
+
+  You should say Y here if you use XFree86 3.3.6 or 4.x and want to
+  use GLX or DRI.  If unsure, say N.
+
 Generic SiS support
 CONFIG_AGP_SIS
   This option gives you AGP support for the GLX component of the "soon
@@ -4155,6 +4177,7 @@
    - "Winchip-2" for IDT Winchip 2.
    - "Winchip-2A" for IDT Winchips with 3dNow! capabilities.
    - "CyrixIII" for VIA Cyrix III or VIA C3.
+   - "VIA C3-2 for VIA C3-2 "Nehemiah" (model 9 and above).
 
   If you don't know what to do, choose "386".
 
@@ -4176,6 +4199,13 @@
   Select this for a Pentium Classic processor with the RDTSC (Read
   Time Stamp Counter) instruction for benchmarking.
 
+VIA C3-2 (Nehemiah)
+CONFIG_MVIAC3_2
+  Select this for a VIA C3 "Nehemiah". Selecting this enables usage of SSE
+  and tells gcc to treat the CPU as a 686.
+
+  Note, this kernel will not boot on older (pre model 9) C3s.
+
 32-bit PDC
 CONFIG_PDC_NARROW
   Saying Y here will allow developers with a C180, C200, C240, C360,
@@ -4416,7 +4446,7 @@
 
   The driver is also available as a module ( = code which can be
   inserted and removed from the running kernel whenever you want). The
-  module will be called rivafb.o. If you want to compile it as a
+  module will be called tridentfb.o. If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
 
 ATI Mach64 display support
@@ -4563,14 +4593,11 @@
   BIOS routines contained in a ROM chip in HP PA-RISC based machines.
   Enabling this option will implement the linux framebuffer device and
   an fbcon color text console using calls to the STI BIOS routines.
-  The HP framebuffer device is usually planar, uses a strange memory
+  The HP framebuffer device is sometimes planar, using a strange memory
   layout, and changing the plane mask to create colored pixels
-  requires a call to the STI routines, so do not expect /dev/fb to
-  actually be useful.  However, it is the best we have as far as
-  graphics on the HP chipsets due to lack of hardware level
-  documentation for the various on-board HP chipsets used in these
-  systems.  It is sufficient for basic text console functions,
-  including fonts.
+  can require a call to the STI routines, so /dev/fb may not actually 
+  be useful.  However, on some systems packed pixel formats are supported.  
+  It is sufficient for basic text console functions, including fonts.
 
   You should probably enable this option, unless you are having
   trouble getting video when booting the kernel (make sure it isn't
@@ -7907,6 +7934,17 @@
 
   The common answer here is N, but answering Y is safe.
 
+Workbit NinjaSCSI-32Bi/UDE support
+CONFIG_SCSI_NSP32
+  This is support for the Workbit NinjaSCSI-32Bi/UDE PCI/Cardbus
+  SCSI host adapter. Please read the SCSI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called nsp32.o.
+
 IBMMCA SCSI support
 CONFIG_SCSI_IBMMCA
   This is support for the IBM SCSI adapter found in many of the PS/2
@@ -10816,6 +10854,15 @@
   say M here and read <file:Documentation/modules.txt>.  This is
   recommended.  The module will be called yellowfin.o.
 
+Realtek 8169 Gigabit Ethernet support
+CONFIG_R8169
+  Say Y here if you have a Realtek 8169 PCI 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 <file:Documentation/modules.txt>.  This is
+  recommended.  The module will be called r8169.o.
+
 General Instruments Surfboard 1000
 CONFIG_NET_SB1000
   This is a driver for the General Instrument (also known as
@@ -10875,31 +10922,41 @@
 
   The safe and default value for this is N.
 
-SysKonnect SK-98xx support
+SysKonnect SK-98xx and SK-95xx Gigabit Ethernet Adapter family support
 CONFIG_SK98LIN
-  Say Y here if you have a SysKonnect SK-98xx Gigabit Ethernet Server
-  Adapter. The following adapters are supported by this driver:
-  - SK-9841 (single link 1000Base-LX)
-  - SK-9842 (dual link   1000Base-LX)
-  - SK-9843 (single link 1000Base-SX)
-  - SK-9844 (dual link   1000Base-SX)
-  - SK-9821 (single link 1000Base-T)
-  - SK-9822 (dual link   1000Base-T)
-  - SK-9861 (single link Volition connector)
-  - SK-9862 (dual link   Volition connector)
-  The driver also supports the following adapters from Allied Telesyn:
-  - AT2970...
-
-  The dual link adapters support a link-failover feature.  Read
-  <file:Documentation/networking/sk98lin.txt> for information about
+  Say Y here if you have a SysKonnect SK-98xx or SK-95xx Gigabit 
+  Ethernet Server Adapter. The following adapters are supported by 
+  this driver:
+  - SK-9521 10/100/1000Base-T Adapter
+  - SK-9821 Gigabit Ethernet 1000Base-T Server Adapter
+  - SK-9822 Gigabit Ethernet 1000Base-T Dual Port Server Adapter
+  - SK-9841 Gigabit Ethernet 1000Base-LX Server Adapter
+  - SK-9842 Gigabit Ethernet 1000Base-LX Dual Port Server Adapter
+  - SK-9843 Gigabit Ethernet 1000Base-SX Server Adapter
+  - SK-9844 Gigabit Ethernet 1000Base-SX Dual Port Server Adapter
+  - SK-9861 Gigabit Ethernet 1000Base-SX Server Adapter
+  - SK-9862 Gigabit Ethernet 1000Base-SX Dual Port Server Adapter
+  - SK-9871 Gigabit Ethernet 1000Base-ZX Server Adapter
+  - SK-9872 Gigabit Ethernet 1000Base-ZX Dual Port Server Adapter
+  - SK-9821 V2.0 Gigabit Ethernet 10/100/1000Base-T Adapter
+  - SK-9841 V2.0 Gigabit Ethernet 1000Base-LX Adapter
+  - SK-9843 V2.0 Gigabit Ethernet 1000Base-SX Adapter
+  - SK-9851 V2.0 Gigabit Ethernet 1000Base-SX Adapter
+  - SK-9861 V2.0 Gigabit Ethernet 1000Base-SX Adapter
+  - SK-9871 V2.0 Gigabit Ethernet 1000Base-ZX Adapter
+
+  The adapters support Jumbo Frames.
+  The dual link adapters support link-failover and dual port features.
+  The V2.0 adapters support the scatter-gather functionality with
+  sendfile(). Read Documentation/networking/sk98lin.txt for information about
   optional driver parameters.
   Questions concerning this driver may be addressed to:
     linux@syskonnect.de
 
   If you want to compile this driver as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
-  say M here and read <file:Documentation/modules.txt>.  This is
-  recommended.  The module will be called sk98lin.o.
+  say M here and read Documentation/modules.txt. This is recommended.
+  The module will be called sk98lin.o.
 
 Sun GEM support
 CONFIG_SUNGEM
@@ -11227,6 +11284,24 @@
   say M here and read <file:Documentation/modules.txt>.  The module
   will be called 3c59x.o.
 
+3cr990 series "Typhoon" support
+CONFIG_TYPHOON
+  This option enables driver support for the 3cr990 series of cards:
+
+  3C990-TX, 3CR990-TX-95, 3CR990-TX-97, 3CR990-FX-95, 3CR990-FX-97,
+  3CR990SVR, 3CR990SVR95, 3CR990SVR97, 3CR990-FX-95 Server,
+  3CR990-FX-97 Server, 3C990B-TX-M, 3C990BSVR
+
+  If you have a network (Ethernet) card of this type, say Y and read
+  the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called typhoon.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
 Other ISA cards
 CONFIG_NET_ISA
   If your network (Ethernet) card hasn't been mentioned yet and its
@@ -11644,6 +11719,18 @@
   module, say M here and read <file:Documentation/modules.txt> as well
   as <file:Documentation/networking/net-modules.txt>.
 
+AMD 8111 (new PCI lance) support
+CONFIG_AMD8111_ETH
+  If you have an AMD 8111-based PCI lance ethernet card,
+  answer Y here and read the Ethernet-HOWTO, available from
+  <http://www.tldp.org/docs.html#howto>.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called amd8111e.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
 Ansel Communications EISA 3200 support
 CONFIG_AC3200
   If you have a network (Ethernet) card of this type, say Y and read
@@ -11771,6 +11858,13 @@
   a module, say M here and read <file:Documentation/modules.txt> as
   well as <file:Documentation/networking/net-modules.txt>.
 
+Use PIO instead of MMIO
+CONFIG_EEPRO100_PIO
+  This instructs the driver to use programmed I/O ports (PIO) instead
+  of PCI shared memory (MMIO).  This can possibly solve some problems
+  in case your mainboard has memory consistency issues.  If unsure,
+  say N.
+
 Enable Power Management
 CONFIG_EEPRO100_PM
   Many Intel EtherExpress PRO/100 PCI network cards are capable
@@ -13764,6 +13858,21 @@
   The module will be called wacom.o.  If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
 
+Griffin Technology PowerMate support
+CONFIG_USB_POWERMATE
+  Say Y here if you want to use the Griffin Technology, Inc. USB
+  PowerMate device. This device is an aluminum dial which can
+  measure clockwise and anticlockwise rotation. The dial also
+  acts as a pushbutton. The base contains an LED which can be
+  instructed to pulse or to switch to a particular intensity.
+
+  You can download userspace tools from http://sowerbutts.com/powermate/
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called powermate.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
 Aiptek 6000U/8000U tablet support
 CONFIG_USB_AIPTEK
   Say Y here if you want to use the USB version of the Aiptek 6000U/8000U
@@ -13858,8 +13967,8 @@
 USB Scanner support
 CONFIG_USB_SCANNER
   Say Y here if you want to connect a USB scanner to your computer's
-  USB port. Please read <file:Documentation/usb/scanner.txt> and
-  <file:Documentation/usb/scanner-hp-sane.txt> for more information.
+  USB port. Please read <file:Documentation/usb/scanner.txt> for more
+  information.
 
   This code is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -13955,10 +14064,10 @@
   The module will be called visor.o. If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
 
-USB Compaq iPAQ Driver
+USB PocketPC PDA Driver
 CONFIG_USB_SERIAL_IPAQ
-  Say Y here if you want to connect to your Compaq iPAQ, HP Jornada 548/568
-  or Casio EM500 running Windows CE 3.0 or PocketPC 2002 using a USB
+  Say Y here if you want to connect to your Compaq iPAQ, HP Jornada,
+  or any other PDA running Windows CE 3.0 or PocketPC 2002 using a USB
   cradle/cable. For information on using the driver,
   read <file:Documentation/usb/usb-serial.txt>.
 
@@ -14145,6 +14254,17 @@
   The module will be called pl2303.o.  If you want to compile it as
   a module, say M here and read <file:Documentation/modules.txt>.
 
+USB KOBIL chipcard reader
+CONFIG_USB_SERIAL_KOBIL_SCT
+  Say Y here if you want to use one of the following KOBIL USB chipcard 
+  readers: TWIN, KAAN Standard Plus, SecOVID Reader Plus, B1 PRO, KAAN PRO
+
+  Note that you need a current CT-API.
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called kobil_sct.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
 USB REINER SCT cyberJack pinpad/e-com chipcard reader
 CONFIG_USB_SERIAL_CYBERJACK
   Say Y here if you want to use a cyberJack pinpad/e-com USB chipcard
@@ -14235,6 +14355,21 @@
   you load the module.  Read <file:Documentation/usb/ibmcam.txt> to
   learn more.
 
+CONFIG_USB_KONICAWC
+  Say Y here if you want support for webcams based on a Konica
+  chipset. This is known to work with the Intel YC76 webcam.
+
+  This driver uses the Video For Linux API.  You must enable
+  (Y or M in config) Video For Linux (under Character Devices)
+  to use this driver.  Information on this API and pointers to
+  "v4l" programs may be found on the WWW at
+  <http://roadrunner.swansea.uk.linux.org/v4l.shtml>.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called konicawc.o. If you want to compile it as
+  a module, say M here and read <file:Documentation/modules.txt>.
+
 USB OV511 Camera support
 CONFIG_USB_OV511
   Say Y here if you want to connect this type of camera to your
@@ -14361,7 +14496,7 @@
   If in doubt then look at linux/drivers/usb/pegasus.h for the complete
   list of supported devices.
   If your particular adapter is not in the list and you are _sure_ it
-  is Pegasus or Pegasus-II based then send me (pmanolov@users.sourceforge.net)
+  is Pegasus or Pegasus-II based then send me (petkan@users.sourceforge.net)
   vendor and device IDs.
   
   This code is also available as a module ( = code which can be
@@ -14620,7 +14755,7 @@
   The module will be called rio500.o. If you want to compile it as
   a module, say M here and read <file:Documenatation/modules.txt>.
 
-USB Auerswald ISDN device support
+Auerswald device support
 CONFIG_USB_AUERSWALD
   Say Y here if you want to connect an Auerswald USB ISDN Device
   to your computer's USB port.
@@ -14630,8 +14765,18 @@
   The module will be called auerswald.o. If you want to compile it as
   a module, say M here and read <file:Documenatation/modules.txt>
 
+USB Auerswald ISDN modem support
+CONFIG_USB_AUERISDN
+  Say Y here if you want to enable the ISDN modem option
+  of your Auerswald ISDN devices. 
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called auerswald.o. If you want to compile it as
+  a module, say M here and read <file:Documenatation/modules.txt>
+
 CONFIG_USB_TIGL
-  If you own a Texas Instruments graphing calculator and use a 
+  If you own a Texas Instruments graphing calculator and use a
   TI-GRAPH LINK USB cable (aka SilverLink), then you might be 
   interested in this driver.
 
@@ -14649,6 +14794,28 @@
 
   If unsure, say N.
 
+Texas Instruments parallel link cable support
+CONFIG_TIPAR
+  If you own a Texas Instruments graphing calculator and use a
+  parallel link cable, then you might be interested in this driver.
+
+  If you enable this driver, you will be able to communicate with
+  your calculator through a set of device nodes under /dev. The
+  main advantage of this driver is that you don't have to be root
+  to use this precise link cable (depending on the permissions on
+  the device nodes, though).
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called tipar.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>
+
+  If you don't know what a parallel link cable is or what a Texas
+  Instruments graphing calculator is, then you probably don't need this
+  driver.
+
+  If unsure, say N.
+
 Tieman Voyager USB Braille display support
 CONFIG_USB_BRLVOYAGER
   Say Y here if you want to use the Voyager USB Braille display from
@@ -14949,8 +15116,7 @@
 CONFIG_USB_BLUETOOTH
   Say Y here if you want to connect a USB Bluetooth device to your
   computer's USB port. You will need the Bluetooth stack (available
-  at <http://developer.axis.com/software/index.shtml>) to fully use
-  the device.
+  at <http://developer.axis.com/software>) to fully use the device.
 
   This code is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -19052,10 +19218,11 @@
   The module will be called cs461x.o.  If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
 
-Aureal Vortex and Trident 4DWave gameports
+Aureal Vortex, Trident 4DWave, and ALi 5451 gameports
 CONFIG_INPUT_PCIGAME
   Say Y here if you have a Trident 4DWave DX/NX or Aureal Vortex 1/2
-  card. For more information on how to use the driver please read
+  card or an ALi 5451 chip on your motherboard. For more information
+  on how to use the driver please read
   <file:Documentation/input/joystick.txt>.
 
   This driver is also available as a module ( = code which can be
@@ -21278,6 +21445,8 @@
                HCI Device drivers (interface to the hardware)
                L2CAP Module (L2CAP protocol)
                SCO Module (SCO links)
+               RFCOMM Module (RFCOMM protocol)
+               BNEP Module (BNEP protocol)
 
   Say Y here to enable Linux Bluetooth support and to build BlueZ Core
   layer.
@@ -21306,6 +21475,19 @@
   Say Y here to compile SCO support into the kernel or say M to
   compile it as module (sco.o).
 
+RFCOMM protocol support
+CONFIG_BLUEZ_RFCOMM
+  RFCOMM provides connection oriented stream transport. RFCOMM
+  support is required for Dialup Networking, OBEX and other Bluetooth
+  applications.
+
+  Say Y here to compile RFCOMM support into the kernel or say M to
+  compile it as module (rfcomm.o).
+
+RFCOMM TTY emulation support
+CONFIG_BLUEZ_RFCOMM_TTY
+  This option enables TTY emulation support for RFCOMM channels.
+
 BNEP protocol support
 CONFIG_BLUEZ_BNEP
   BNEP (Bluetooth Network Encapsulation Protocol) is Ethernet
@@ -21319,6 +21501,14 @@
   Say Y here to compile BNEP support into the kernel or say M to
   compile it as module (bnep.o).
 
+BNEP multicast filter support
+CONFIG_BLUEZ_BNEP_MC_FILTER
+  This option enables the multicast filter support for BNEP.
+
+BNEP protocol filter support
+CONFIG_BLUEZ_BNEP_PROTO_FILTER
+  This option enables the protocol filter support for BNEP.
+
 HCI UART driver
 CONFIG_BLUEZ_HCIUART
   Bluetooth HCI UART driver.
@@ -21333,11 +21523,26 @@
 HCI UART (H4) protocol support 
 CONFIG_BLUEZ_HCIUART_H4
   UART (H4) is serial protocol for communication between Bluetooth 
-  device and host. This protocol is required for most UART based 
-  Bluetooth device (including PCMCIA and CF). 
+  device and host. This protocol is required for most Bluetooth devices 
+  with UART interface, including PCMCIA and CF cards. 
 
   Say Y here to compile support for HCI UART (H4) protocol.
 
+HCI BCSP protocol support 
+CONFIG_BLUEZ_HCIUART_BCSP
+  BCSP (BlueCore Serial Protocol) is serial protocol for communication 
+  between Bluetooth device and host. This protocol is required for non
+  USB Bluetooth devices based on CSR BlueCore chip, including PCMCIA and 
+  CF cards.
+
+  Say Y here to compile support for HCI BCSP protocol.
+
+HCI BCSP transmit CRC with every BCSP packet
+CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
+  If you say Y here, a 16-bit CRC checksum will be transmitted along with
+  every BCSP (BlueCore Serial Protocol) packet sent to the Bluetooth chip.
+  This increases reliability, but slightly reduces efficiency.
+
 HCI USB driver
 CONFIG_BLUEZ_HCIUSB
   Bluetooth HCI USB driver.
@@ -21399,6 +21604,20 @@
   Say Y here to compile support for HCI BlueCard devices into the
   kernel or say M to compile it as module (bluecard_cs.o).
 
+HCI UART (PC Card) device driver
+CONFIG_BLUEZ_HCIBTUART
+  Bluetooth HCI UART (PC Card) driver.
+  This driver provides support for Bluetooth PCMCIA devices with
+  an UART interface:
+     Xircom CreditCard Bluetooth Adapter
+     Xircom RealPort2 Bluetooth Adapter
+     Sphinx PICO Card
+     H-Soft blue+Card
+     Cyber-blue Compact Flash Card
+
+  Say Y here to compile support for HCI UART devices into the
+  kernel or say M to compile it as module (btuart_cs.o).
+
 # The following options are for Linux when running on the Hitachi
 # SuperH family of RISC microprocessors.
 
@@ -21884,8 +22103,8 @@
 Sun3 NCR5380 SCSI
 CONFIG_SUN3_SCSI
   This option will enable support for the OBIO (onboard io) NCR5380
-  SCSI controller found in the Sun 3/50 and 3/60.  Note that this
-  driver does not provide support for VME SCSI boards.
+  SCSI controller found in the Sun 3/50 and 3/60, as well as for
+  "Sun3" type VME scsi controllers also based on the NCR5380.
   General Linux information on the Sun 3 series (now discontinued)
   is at <http://www.angelfire.com/ca2/tech68k/sun3.html>.
 
@@ -24413,13 +24632,24 @@
   say M here and read <file:Documentation/modules.txt>.  The module
   will be called ns83820.o.
 
+Toshiba Type-O IR Port device driver (old driver)
+CONFIG_TOSHIBA_OLD
+  Say Y here if you want to build support for the Toshiba Type-O IR
+  chipset.  This chipset is used by the Toshiba Libretto 100CT, and
+  many more laptops. This driver is obsolete, will no more be
+  maintained and will be removed in favor of the new driver.
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.
+  The module will be called toshoboe.o.
+
 Toshiba Type-O IR Port device driver
 CONFIG_TOSHIBA_FIR
   Say Y here if you want to build support for the Toshiba Type-O IR
-  chipset.  This chipset is used by the Toshiba Libretto 100CT, and
-  many more laptops.  If you want to compile it as a module, say M
-  here and read <file:Documentation/modules.txt>.  The module will be
-  called toshoboe.o.
+  and Donau oboe chipsets. These chipsets are used by the Toshiba
+  Libretto 100/110CT, Tecra 8100, Portege 7020 and many more laptops.
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.
+  The module will be called donauboe.o.
 
 SMC IrCC
 CONFIG_SMC_IRCC_FIR
@@ -25438,16 +25668,6 @@
   for the zx1 IOMMU and makes root bus bridges appear in PCI config space
   (required for zx1 agpgart support).
 
-CONFIG_IA64_SGI_SN_SIM
-  Build a kernel that runs on both the SGI simulator AND on hardware.
-  There is a very slight performance penalty on hardware for including this
-  option.
-
-CONFIG_IA64_SGI_SN_DEBUG
-  This enables addition debug code that helps isolate
-  platform/kernel bugs. There is a small but measurable performance
-  degradation when this option is enabled.
-
 # Choice: pagesize
 Kernel page size
 CONFIG_IA64_PAGE_SIZE_4KB
@@ -26181,7 +26401,7 @@
   If you want to compile this as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
   say M here and read Documentation/modules.txt.  The module
-  will be called amdtp.o.
+  will be called cmp.o.
 
 OHCI-DV I/O support
 CONFIG_IEEE1394_DV1394
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/DocBook/journal-api.tmpl linux-2.4.21-pre6/Documentation/DocBook/journal-api.tmpl
--- linux-2.4.20/Documentation/DocBook/journal-api.tmpl	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/DocBook/journal-api.tmpl	2003-03-26 23:49:07.000000000 +0000
@@ -196,6 +196,8 @@
 Lock is also providing through journal_{un,}lock_updates(),
 ext3 uses this when it wants a window with a clean and stable fs for a moment.
 eg. 
+</para>
+
 <programlisting>
 
 	journal_lock_updates() //stop new stuff happening..
@@ -204,11 +206,12 @@
 	journal_unlock_updates() // carry on with filesystem use.
 </programlisting>
 
+<para>
 The opportunities for abuse and DOS attacks with this should be obvious,
 if you allow unprivileged userspace to trigger codepaths containing these
 calls.
 
-<para>
+</para>
 </sect1>
 <sect1>
 <title>Summary</title>
@@ -216,9 +219,13 @@
 Using the journal is a matter of wrapping the different context changes,
 being each mount, each modification (transaction) and each changed buffer
 to tell the journalling layer about them.
+</para>
 
+<para>
 Here is a some pseudo code to give you an idea of how it works, as
 an example.
+</para>
+
 <programlisting>
   journal_t* my_jnrl = journal_create();
   journal_init_{dev,inode}(jnrl,...)
@@ -244,6 +251,7 @@
    }
    journal_destroy(my_jrnl);
 </programlisting>
+</sect1>
 
 </chapter>
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/DocBook/kernel-api.tmpl linux-2.4.21-pre6/Documentation/DocBook/kernel-api.tmpl
--- linux-2.4.20/Documentation/DocBook/kernel-api.tmpl	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/DocBook/kernel-api.tmpl	2003-03-26 23:48:57.000000000 +0000
@@ -85,7 +85,11 @@
      <title>Memory Management in Linux</title>
      <sect1><title>The Slab Cache</title>
 !Emm/slab.c
-      </sect1>
+     </sect1>
+     <sect1><title>User Space Memory Access</title>
+!Iinclude/asm-i386/uaccess.h
+!Iarch/i386/lib/usercopy.c
+     </sect1>
   </chapter>
 
   <chapter id="proc">
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/DocBook/kernel-hacking.tmpl linux-2.4.21-pre6/Documentation/DocBook/kernel-hacking.tmpl
--- linux-2.4.20/Documentation/DocBook/kernel-hacking.tmpl	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/DocBook/kernel-hacking.tmpl	2003-03-26 23:49:39.000000000 +0000
@@ -1139,11 +1139,6 @@
     </listitem>
     <listitem>
      <para>
-      Labeled elements
-     </para>
-    </listitem>
-    <listitem>
-     <para>
       typeof
      </para>
     </listitem>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/DocBook/kernel-locking.tmpl linux-2.4.21-pre6/Documentation/DocBook/kernel-locking.tmpl
--- linux-2.4.20/Documentation/DocBook/kernel-locking.tmpl	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/DocBook/kernel-locking.tmpl	2003-03-26 23:49:29.000000000 +0000
@@ -1055,10 +1055,8 @@
       Another common problem is deleting timers which restart
       themselves (by calling <function>add_timer()</function> at the end 
       of their timer function).  Because this is a fairly common case 
-      which is prone to races, you can put a call to
-      <function>timer_exit()</function> at the very end of your timer function,
-      and user <function>del_timer_sync()</function> 
-      (<filename class=headerfile>include/linux/timer.h</filename>)
+      which is prone to races, you should use <function>del_timer_sync()</function> 
+      (<filename class=headerfile>include/linux/timer.h</filename>) 
       to handle this case.  It returns the number of times the timer 
       had to be deleted before we finally stopped it from adding itself back 
       in.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/DocBook/mousedrivers.tmpl linux-2.4.21-pre6/Documentation/DocBook/mousedrivers.tmpl
--- linux-2.4.20/Documentation/DocBook/mousedrivers.tmpl	2001-09-30 19:26:05.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/DocBook/mousedrivers.tmpl	2003-03-26 23:49:50.000000000 +0000
@@ -153,11 +153,17 @@
 __init ourmouse_init(void)
 {
 
-        if(check_region(OURMOUSE_BASE, 3))
+        if (request_region(OURMOUSE_BASE, 3, "ourmouse") < 0) {
+		printk(KERN_ERR "ourmouse: request_region failed.\n");
                 return -ENODEV;
-        request_region(OURMOUSE_BASE, 3, "ourmouse");
+	}
+
+        if (misc_register(&amp;our_mouse) < 0) {
+		printk(KERN_ERR "ourmouse: cannot register misc device.\n");
+		release_region(OURMOUSE_BASE, 3);
+		return -EBUSY;
+	}
 
-        misc_register(&amp;our_mouse);
         return 0;
 }
   </programlisting>
@@ -177,18 +183,20 @@
     so it is a good idea to obtain a current copy of this file first.
   </para>
   <para>
-    Our code then is fairly simple. We check nobody else has taken our 
-    address space. Having done so we reserve it to ensure nobody stamps 
-    on our device while probing for other ISA bus devices. Such a probe 
-    might confuse our device.
+    Our code then is fairly simple. We reserve our I/O address space with
+    request_region, checking to make sure that it succeeded (i.e. the
+    space wasn't reserved by anyone else). 
   </para>
   <para>
-    Then we tell the misc driver that we wish to own a minor number. We also
+    Then we ask the misc driver to allocate our minor device number. We also
     hand it our name (which is used in 
     <filename class="directory">/proc/misc</filename>) and a set of file 
     operations that are to be used. The file operations work exactly like the 
     file operations you would register for a normal character device. The misc 
     device itself is simply acting as a redirector for requests.
+    Since misc_register can fail, it is important to check for failure
+    and act accordingly (which in the case of a mouse driver is to abort,
+    since you can't use the mouse without a working device node).
   </para>
   <para>
     Next, in order to be able to use and test our code we need to add some 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/DocBook/procfs-guide.tmpl linux-2.4.21-pre6/Documentation/DocBook/procfs-guide.tmpl
--- linux-2.4.20/Documentation/DocBook/procfs-guide.tmpl	2001-09-08 19:20:25.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/DocBook/procfs-guide.tmpl	2003-03-26 23:49:50.000000000 +0000
@@ -99,7 +99,7 @@
 
     <para>
       I'd like to thank Jeff Garzik
-      <email>jgarzik@mandrakesoft.com</email> and Alexander Viro
+      <email>jgarzik@pobox.com</email> and Alexander Viro
       <email>viro@math.psu.edu</email> for their input, Tim Waugh
       <email>twaugh@redhat.com</email> for his <ulink
       url="http://people.redhat.com/twaugh/docbook/selfdocbook/">Selfdocbook</ulink>,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/DocBook/tulip-user.tmpl linux-2.4.21-pre6/Documentation/DocBook/tulip-user.tmpl
--- linux-2.4.20/Documentation/DocBook/tulip-user.tmpl	2001-10-05 19:06:51.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/DocBook/tulip-user.tmpl	2003-03-26 23:49:19.000000000 +0000
@@ -10,7 +10,7 @@
     <surname>Garzik</surname>
     <affiliation>
      <address>
-      <email>jgarzik@mandrakesoft.com</email>
+      <email>jgarzik@pobox.com</email>
      </address>
     </affiliation>
    </author>
@@ -57,7 +57,7 @@
     <title>Introduction</title>
 <para>
 The Tulip Ethernet Card Driver
-is maintained by Jeff Garzik (<email>jgarzik@mandrakesoft.com</email>).
+is maintained by Jeff Garzik (<email>jgarzik@pobox.com</email>).
 </para>
 
 <para>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/DocBook/via-audio.tmpl linux-2.4.21-pre6/Documentation/DocBook/via-audio.tmpl
--- linux-2.4.20/Documentation/DocBook/via-audio.tmpl	2001-12-21 17:41:53.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/DocBook/via-audio.tmpl	2003-03-26 23:49:56.000000000 +0000
@@ -2,7 +2,7 @@
 
 <book id="ViaAudioGuide">
  <bookinfo>
-  <title>Via 686 Audio Driver for Linux</title>
+  <title>Via 686/8233/8235 Audio Driver for Linux</title>
   
   <authorgroup>
    <author>
@@ -54,7 +54,9 @@
   	The Via VT82C686A "super southbridge" chips contain
 	AC97-compatible audio logic which features dual 16-bit stereo
 	PCM sound channels (full duplex), plus a third PCM channel intended for use
-	in hardware-assisted FM synthesis.
+	in hardware-assisted FM synthesis. The VIA VT8233/8235 extends this
+	support to include six channel output and additional record
+	facilities.
   </para>
   <para>
   	The current Linux kernel audio driver for this family of chips
@@ -199,7 +201,9 @@
   <para>
 	This driver by default supports all PCI audio devices which report
 	a vendor id of 0x1106, and a device id of 0x3058.  Subsystem vendor
-	and device ids are not examined.
+	and device ids are not examined. The 8233 support covers all devices
+	with a device id of 0x3059 and vendor id of 0x1106. Again subsystem
+	ids are ignored as they usually hold the AC97 codec vendor information.
   </para>
   <para>
 	GNU indent formatting options:
@@ -224,6 +228,21 @@
   <chapter id="changelog">
       <title>Driver ChangeLog</title>
 
+<sect1 id="version191ac"><title>
+Version 1.9.1-ac
+</title>
+  <itemizedlist spacing=compact>
+   <listitem>
+    <para>
+    Added VIA 8233/8235 support including six channel support. We don't
+    yet support S/PDIF, EAPD, using the second DSP channel and FM channels
+    as extra dsp devices, or the extra record channel. New features tested
+    on a VIA EPIA-M kindly provided by VIA.
+    </para>
+   </listitem>
+  </itemizedlist>
+</sect1>
+
 <sect1 id="version191"><title>
 Version 1.9.1
 </title>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/DocBook/videobook.tmpl linux-2.4.21-pre6/Documentation/DocBook/videobook.tmpl
--- linux-2.4.20/Documentation/DocBook/videobook.tmpl	2001-07-15 23:15:44.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/DocBook/videobook.tmpl	2003-03-26 23:49:38.000000000 +0000
@@ -146,16 +146,17 @@
 
 int __init myradio_init(struct video_init *v)
 {
-        if(check_region(io, MY_IO_SIZE))
+        if(!request_region(io, MY_IO_SIZE, "myradio"))
         {
                 printk(KERN_ERR 
                     "myradio: port 0x%03X is in use.\n", io);
                 return -EBUSY;
         }
 
-        if(video_device_register(&amp;my_radio, VFL_TYPE_RADIO)==-1)
+        if(video_device_register(&amp;my_radio, VFL_TYPE_RADIO)==-1) {
+                release_region(io, MY_IO_SIZE);
                 return -EINVAL;
-        request_region(io, MY_IO_SIZE, "myradio");
+        }		
         return 0;
 }
 
@@ -920,7 +921,7 @@
 
 int __init mycamera_init(struct video_init *v)
 {
-        if(check_region(io, MY_IO_SIZE))
+        if(!request_region(io, MY_IO_SIZE, "mycamera"))
         {
                 printk(KERN_ERR 
                       "mycamera: port 0x%03X is in use.\n", io);
@@ -928,9 +929,10 @@
         }
 
         if(video_device_register(&amp;my_camera, 
-            VFL_TYPE_GRABBER)==-1)
+            VFL_TYPE_GRABBER)==-1) {
+                release_region(io, MY_IO_SIZE);
                 return -EINVAL;
-        request_region(io, MY_IO_SIZE, "mycamera");
+        }
         return 0;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/IPMI.txt linux-2.4.21-pre6/Documentation/IPMI.txt
--- linux-2.4.20/Documentation/IPMI.txt	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/IPMI.txt	2003-03-26 23:49:07.000000000 +0000
@@ -0,0 +1,364 @@
+
+                          The Linux IPMI Driver
+			  ---------------------
+			      Corey Minyard
+			  <minyard@mvista.com>
+			    <minyard@acm.org>
+
+The Intelligent Platform Management Interface, or IPMI, is a
+standard for controlling intelligent devices that monitor a system.
+It provides for dynamic discovery of sensors in the system and the
+ability to monitor the sensors and be informed when the sensor's
+values change or go outside certain boundaries.  It also has a
+standardized database for field-replacable units (FRUs) and a watchdog
+timer.
+
+To use this, you need an interface to an IPMI controller in your
+system (called a Baseboard Management Controller, or BMC) and
+management software that can use the IPMI system.
+
+This document describes how to use the IPMI driver for Linux.  If you
+are not familiar with IPMI itself, see the web site at
+http://www.intel.com/design/servers/ipmi/index.htm.  IPMI is a big
+subject and I can't cover it all here!
+
+Basic Design
+------------
+
+The Linux IPMI driver is designed to be very modular and flexible, you
+only need to take the pieces you need and you can use it in many
+different ways.  Because of that, it's broken into many chunks of
+code.  These chunks are:
+
+ipmi_msghandler - This is the central piece of software for the IPMI
+system.  It handles all messages, message timing, and responses.  The
+IPMI users tie into this, and the IPMI physical interfaces (called
+System Management Interfaces, or SMIs) also tie in here.  This
+provides the kernelland interface for IPMI, but does not provide an
+interface for use by application processes.
+
+ipmi_devintf - This provides a userland IOCTL interface for the IPMI
+driver, each open file for this device ties in to the message handler
+as an IPMI user.
+
+ipmi_kcs_drv - A driver for the KCS SMI.  Most system have a KCS
+interface for IPMI.
+
+
+Much documentation for the interface is in the include files.  The
+IPMI include files are:
+
+ipmi.h - Contains the user interface and IOCTL interface for IPMI.
+
+ipmi_smi.h - Contains the interface for SMI drivers to use.
+
+ipmi_msgdefs.h - General definitions for base IPMI messaging.
+
+
+Addressing
+----------
+
+The IPMI addressing works much like IP addresses, you have an overlay
+to handle the different address types.  The overlay is:
+
+  struct ipmi_addr
+  {
+	int   addr_type;
+	short channel;
+	char  data[IPMI_MAX_ADDR_SIZE];
+  };
+
+The addr_type determines what the address really is.  The driver
+currently understands two different types of addresses.
+
+"System Interface" addresses are defined as:
+
+  struct ipmi_system_interface_addr
+  {
+	int   addr_type;
+	short channel;
+  };
+
+and the type is IPMI_SYSTEM_INTERFACE_ADDR_TYPE.  This is used for talking
+straight to the BMC on the current card.  The channel must be
+IPMI_BMC_CHANNEL.
+
+Messages that are destined to go out on the IPMB bus use the
+IPMI_IPMB_ADDR_TYPE address type.  The format is
+
+  struct ipmi_ipmb_addr
+  {
+	int           addr_type;
+	short         channel;
+	unsigned char slave_addr;
+	unsigned char lun;
+  };
+
+The "channel" here is generally zero, but some devices support more
+than one channel, it corresponds to the channel as defined in the IPMI
+spec.
+
+
+Messages
+--------
+
+Messages are defined as:
+
+struct ipmi_msg
+{
+	unsigned char netfn;
+	unsigned char lun;
+	unsigned char cmd;
+	unsigned char *data;
+	int           data_len;
+};
+
+The driver takes care of adding/stripping the header information.  The
+data portion is just the data to be send (do NOT put addressing info
+here) or the response.  Note that the completion code of a response is
+the first item in "data", it is not stripped out because that is how
+all the messages are defined in the spec (and thus makes counting the
+offsets a little easier :-).
+
+When using the IOCTL interface from userland, you must provide a block
+of data for "data", fill it, and set data_len to the length of the
+block of data, even when receiving messages.  Otherwise the driver
+will have no place to put the message.
+
+Messages coming up from the message handler in kernelland will come in
+as:
+
+  struct ipmi_recv_msg
+  {
+	struct list_head link;
+
+	/* The type of message as defined in the "Receive Types"
+           defines above. */
+	int         recv_type;
+
+	ipmi_user_t      *user;
+	struct ipmi_addr addr;
+	long             msgid;
+	struct ipmi_msg  msg;
+
+	/* Call this when done with the message.  It will presumably free
+	   the message and do any other necessary cleanup. */
+	void (*done)(struct ipmi_recv_msg *msg);
+
+	/* Place-holder for the data, don't make any assumptions about
+	   the size or existence of this, since it may change. */
+	unsigned char   msg_data[IPMI_MAX_MSG_LENGTH];
+  };
+
+You should look at the receive type and handle the message
+appropriately.
+
+
+The Upper Layer Interface (Message Handler)
+-------------------------------------------
+
+The upper layer of the interface provides the users with a consistent
+view of the IPMI interfaces.  It allows multiple SMI interfaces to be
+addressed (because some boards actually have multiple BMCs on them)
+and the user should not have to care what type of SMI is below them.
+
+
+Creating the User
+
+To user the message handler, you must first create a user using
+ipmi_create_user.  The interface number specifies which SMI you want
+to connect to, and you must supply callback functions to be called
+when data comes in.  The callback function can run at interrupt level,
+so be careful using the callbacks.  This also allows to you pass in a
+piece of data, the handler_data, that will be passed back to you on
+all calls.
+
+Once you are done, call ipmi_destroy_user() to get rid of the user.
+
+From userland, opening the device automatically creates a user, and
+closing the device automatically destroys the user.
+
+
+Messaging
+
+To send a message from kernel-land, the ipmi_request() call does
+pretty much all message handling.  Most of the parameter are
+self-explanatory.  However, it takes a "msgid" parameter.  This is NOT
+the sequence number of messages.  It is simply a long value that is
+passed back when the response for the message is returned.  You may
+use it for anything you like.
+
+Responses come back in the function pointed to by the ipmi_recv_hndl
+field of the "handler" that you passed in to ipmi_create_user().
+Remember again, these may be running at interrupt level.  Remember to
+look at the receive type, too.
+
+From userland, you fill out an ipmi_req_t structure and use the
+IPMICTL_SEND_COMMAND ioctl.  For incoming stuff, you can use select()
+or poll() to wait for messages to come in.  However, you cannot use
+read() to get them, you must call the IPMICTL_RECEIVE_MSG with the
+ipmi_recv_t structure to actually get the message.  Remember that you
+must supply a pointer to a block of data in the msg.data field, and
+you must fill in the msg.data_len field with the size of the data.
+This gives the receiver a place to actually put the message.
+
+If the message cannot fit into the data you provide, you will get an
+EMSGSIZE error and the driver will leave the data in the receive
+queue.  If you want to get it and have it truncate the message, us
+the IPMICTL_RECEIVE_MSG_TRUNC ioctl.
+
+When you send a command (which is defined by the lowest-order bit of
+the netfn per the IPMI spec) on the IPMB bus, the driver will
+automatically assign the sequence number to the command and save the
+command.  If the response is not receive in the IPMI-specified 5
+seconds, it will generate a response automatically saying the command
+timed out.  If an unsolicited response comes in (if it was after 5
+seconds, for instance), that response will be ignored.
+
+In kernelland, after you receive a message and are done with it, you
+MUST call ipmi_free_recv_msg() on it, or you will leak messages.  Note
+that you should NEVER mess with the "done" field of a message, that is
+required to properly clean up the message.
+
+Note that when sending, there is an ipmi_request_supply_msgs() call
+that lets you supply the smi and receive message.  This is useful for
+pieces of code that need to work even if the system is out of buffers
+(the watchdog timer uses this, for instance).  You supply your own
+buffer and own free routines.  This is not recommended for normal use,
+though, since it is tricky to manage your own buffers.
+
+
+Events and Incoming Commands
+
+The driver takes care of polling for IPMI events and receiving
+commands (commands are messages that are not responses, they are
+commands that other things on the IPMB bus have sent you).  To receive
+these, you must register for them, they will not automatically be sent
+to you.
+
+To receive events, you must call ipmi_set_gets_events() and set the
+"val" to non-zero.  Any events that have been received by the driver
+since startup will immediately be delivered to the first user that
+registers for events.  After that, if multiple users are registered
+for events, they will all receive all events that come in.
+
+For receiving commands, you have to individually register commands you
+want to receive.  Call ipmi_register_for_cmd() and supply the netfn
+and command name for each command you want to receive.  Only one user
+may be registered for each netfn/cmd, but different users may register
+for different commands.
+
+From userland, equivalent IOCTLs are provided to do these functions.
+
+
+The Lower Layer (SMI) Interface
+-------------------------------
+
+As mentioned before, multiple SMI interfaces may be registered to the
+message handler, each of these is assigned an interface number when
+they register with the message handler.  They are generally assigned
+in the order they register, although if an SMI unregisters and then
+another one registers, all bets are off.
+
+The ipmi_smi.h defines the interface for SMIs, see that for more
+details.
+
+
+The KCS Driver
+--------------
+
+The KCS driver allows up to 4 KCS interfaces to be configured in the
+system.  By default, the driver will register one KCS interface at the
+spec-specified I/O port 0xca2 without interrupts.  You can change this
+at module load time (for a module) with:
+
+  insmod ipmi_kcs_drv.o kcs_ports=<port1>,<port2>... kcs_addrs=<addr1>,<addr2>
+       kcs_irqs=<irq1>,<irq2>... kcs_trydefaults=[0|1]
+
+The KCS driver supports two types of interfaces, ports (for I/O port
+based KCS interfaces) and memory addresses (for KCS interfaces in
+memory).  The driver will support both of them simultaneously, setting
+the port to zero (or just not specifying it) will allow the memory
+address to be used.  The port will override the memory address if it
+is specified and non-zero.  kcs_trydefaults sets whether the standard
+IPMI interface at 0xca2 and any interfaces specified by ACPE are
+tried.  By default, the driver tries it, set this value to zero to
+turn this off.
+
+When compiled into the kernel, the addresses can be specified on the
+kernel command line as:
+
+  ipmi_kcs=<bmc1>:<irq1>,<bmc2>:<irq2>....,[nodefault]
+
+The <bmcx> values is either "p<port>" or "m<addr>" for port or memory
+addresses.  So for instance, a KCS interface at port 0xca2 using
+interrupt 9 and a memory interface at address 0xf9827341 with no
+interrupt would be specified "ipmi_kcs=p0xca2:9,m0xf9827341".
+If you specify zero for in irq or don't specify it, the driver will
+run polled unless the software can detect the interrupt to use in the
+ACPI tables.
+
+By default, the driver will attempt to detect a KCS device at the
+spec-specified 0xca2 address and any address specified by ACPI.  If
+you want to turn this off, use the "nodefault" option.
+
+If you have high-res timers compiled into the kernel, the driver will
+use them to provide much better performance.  Note that if you do not
+have high-res timers enabled in the kernel and you don't have
+interrupts enabled, the driver will run VERY slowly.  Don't blame me,
+the KCS interface sucks.
+
+
+Other Pieces
+------------
+
+Watchdog
+
+A watchdog timer is provided that implements the Linux-standard
+watchdog timer interface.  It has three module parameters that can be
+used to control it:
+
+  insmod ipmi_watchdog timeout=<t> pretimeout=<t> action=<action type>
+      preaction=<preaction type> preop=<preop type>
+
+The timeout is the number of seconds to the action, and the pretimeout
+is the amount of seconds before the reset that the pre-timeout panic will
+occur (if pretimeout is zero, then pretimeout will not be enabled).
+
+The action may be "reset", "power_cycle", or "power_off", and
+specifies what to do when the timer times out, and defaults to
+"reset".
+
+The preaction may be "pre_smi" for an indication through the SMI
+interface, "pre_int" for an indication through the SMI with an
+interrupts, and "pre_nmi" for a NMI on a preaction.  This is how
+the driver is informed of the pretimeout.
+
+The preop may be set to "preop_none" for no operation on a pretimeout,
+"preop_panic" to set the preoperation to panic, or "preop_give_data"
+to provide data to read from the watchdog device when the pretimeout
+occurs.  A "pre_nmi" setting CANNOT be used with "preop_give_data"
+because you can't do data operations from an NMI.
+
+When preop is set to "preop_give_data", one byte comes ready to read
+on the device when the pretimeout occurs.  Select and fasync work on
+the device, as well.
+
+When compiled into the kernel, the kernel command line is available
+for configuring the watchdog:
+
+  ipmi_wdog=<timeout>[,<pretimeout>[,<option>[,<options>....]]]
+
+The options are the actions and preaction above (if an option
+controlling the same thing is specified twice, the last is taken).  An
+options "start_now" is also there, if included, the watchdog will
+start running immediately when all the drivers are ready, it doesn't
+have to have a user hooked up to start it.
+
+The watchdog will panic and start a 120 second reset timeout if it
+gets a pre-action.  During a panic or a reboot, the watchdog will
+start a 120 timer if it is running to make sure the reboot occurs.
+
+Note that if you use the NMI preaction for the watchdog, you MUST
+NOT use nmi watchdog mode 1.  If you use the NMI watchdog, you
+must use mode 2.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/arm/Booting linux-2.4.21-pre6/Documentation/arm/Booting
--- linux-2.4.20/Documentation/arm/Booting	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/arm/Booting	2003-03-26 23:49:34.000000000 +0000
@@ -0,0 +1,137 @@
+			Booting ARM Linux
+			=================
+
+Author:	Russell King
+Date  : 18 May 2002
+
+The following documentation is relevant to 2.4.18-rmk6 and beyond.
+
+In order to boot ARM Linux, you require a boot loader, which is a small
+program that runs before the main kernel.  The boot loader is expected
+to initialise various devices, and eventually call the Linux kernel,
+passing information to the kernel.
+
+Essentially, the boot loader should provide (as a minimum) the
+following:
+
+1. Setup and initialise the RAM.
+2. Initialise one serial port.
+3. Detect the machine type.
+4. Setup the kernel tagged list.
+5. Call the kernel image.
+
+
+1. Setup and initialise RAM
+---------------------------
+
+Existing boot loaders:		MANDATORY
+New boot loaders:		MANDATORY
+
+The boot loader is expected to find and initialise all RAM that the
+kernel will use for volatile data storage in the system.  It performs
+this in a machine dependent manner.  (It may use internal algorithms
+to automatically locate and size all RAM, or it may use knowledge of
+the RAM in the machine, or any other method the boot loader designer
+sees fit.)
+
+
+2. Initialise one serial port
+-----------------------------
+
+Existing boot loaders:		OPTIONAL, RECOMMENDED
+New boot loaders:		OPTIONAL, RECOMMENDED
+
+The boot loader should initialise and enable one serial port on the
+target.  This allows the kernel serial driver to automatically detect
+which serial port it should use for the kernel console (generally
+used for debugging purposes, or communication with the target.)
+
+As an alternative, the boot loader can pass the relevant 'console='
+option to the kernel via the tagged lists specifing the port, and
+serial format options as described in
+
+       linux/Documentation/kernel-parameters.txt.
+
+
+3. Detect the machine type
+--------------------------
+
+Existing boot loaders:		OPTIONAL
+New boot loaders:		MANDATORY
+
+The boot loader should detect the machine type its running on by some
+method.  Whether this is a hard coded value or some algorithm that
+looks at the connected hardware is beyond the scope of this document.
+The boot loader must ultimately be able to provide a MACH_TYPE_xxx
+value to the kernel. (see linux/arch/arm/tools/mach-types).
+
+
+4. Setup the kernel tagged list
+-------------------------------
+
+Existing boot loaders:		OPTIONAL, HIGHLY RECOMMENDED
+New boot loaders:		MANDATORY
+
+The boot loader must create and initialise the kernel tagged list.
+A valid tagged list starts with ATAG_CORE and ends with ATAG_NONE.
+The ATAG_CORE tag may or may not be empty.  An empty ATAG_CORE tag
+has the size field set to '2' (0x00000002).  The ATAG_NONE must set
+the size field to zero.
+
+Any number of tags can be placed in the list.  It is undefined
+whether a repeated tag appends to the information carried by the
+previous tag, or whether it replaces the information in its
+entirety; some tags behave as the former, others the latter.
+
+The boot loader must pass at a minimum the size and location of
+the system memory, and root filesystem location.  Therefore, the
+minimum tagged list should look:
+
+	+-----------+
+base ->	| ATAG_CORE |  |
+	+-----------+  |
+	| ATAG_MEM  |  | increasing address
+	+-----------+  |
+	| ATAG_NONE |  |
+	+-----------+  v
+
+The tagged list should be stored in system RAM.
+
+The tagged list must be placed in a region of memory where neither
+the kernel decompressor nor initrd 'bootp' program will overwrite
+it.  The recommended placement is in the first 16KiB of RAM.
+
+5. Calling the kernel image
+---------------------------
+
+Existing boot loaders:		MANDATORY
+New boot loaders:		MANDATORY
+
+There are two options for calling the kernel zImage.  If the zImage
+is stored in flash, and is linked correctly to be run from flash,
+then it is legal for the boot loader to call the zImage in flash
+directly.
+
+The zImage may also be placed in system RAM (at any location) and
+called there.  Note that the kernel uses 16K of RAM below the image
+to store page tables.  The recommended placement is 32KiB into RAM.
+
+In either case, the following conditions must be met:
+
+- CPU register settings
+  r0 = 0,
+  r1 = machine type number discovered in (3) above.
+  r2 = physical address of tagged list in system RAM.
+
+- CPU mode
+  All forms of interrupts must be disabled (IRQs and FIQs)
+  The CPU must be in SVC mode.  (A special exception exists for Angel)
+
+- Caches, MMUs
+  The MMU must be off.
+  Instruction cache may be on or off.
+  Data cache must be off.
+
+- The boot loader is expected to call the kernel image by jumping
+  directly to the first instruction of the kernel image.
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/arm/ConfigVars linux-2.4.21-pre6/Documentation/arm/ConfigVars
--- linux-2.4.20/Documentation/arm/ConfigVars	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/arm/ConfigVars	2003-03-26 23:49:30.000000000 +0000
@@ -0,0 +1,26 @@
+CONFIG_ARCH_CO285		- co-ebsa285
+CONFIG_ARCH_FOOTBRIDGE		- all other footbridge systems
+
+  CONFIG_ARCH_CATS		- CATS support
+  CONFIG_ARCH_PERSONAL_SERVER	- personal server support
+  CONFIG_ARCH_EBSA285_ADDIN	- add-in ebsa285 support
+  CONFIG_ARCH_EBSA285_HOST	- host ebsa285 support
+  CONFIG_ARCH_NETWINDER 	- netwinder support
+
+CONFIG_FOOTBRIDGE		- any system with a footbridge chip
+ |- (CONFIG_ARCH_CO285)
+ \- (CONFIG_ARCH_FOOTBRIDGE)
+
+CONFIG_FOOTBRIDGE_HOST		- any system with host mode footbridge support
+ |- (CONFIG_ARCH_CATS)
+ |- (CONFIG_ARCH_EBSA285_HOST)
+ |- (CONFIG_ARCH_NETWINDER)
+ \- (CONFIG_ARCH_PERSONAL_SERVER)
+
+CONFIG_FOOTBRIDGE_ADDIN 	- any system with addin mode footbridge support
+ |- (CONFIG_ARCH_CO285)
+ \- (CONFIG_ARCH_EBSA285_ADDIN)
+
+CONFIG_ARCH_EBSA285		- either host or add-in ebsa285 support, but
+ |- (CONFIG_ARCH_EBSA285_ADDIN)   not co-ebsa285
+ \- (CONFIG_ARCH_EBSA285_HOST)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/arm/MEMC linux-2.4.21-pre6/Documentation/arm/MEMC
--- linux-2.4.20/Documentation/arm/MEMC	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/arm/MEMC	2003-03-26 23:49:07.000000000 +0000
@@ -0,0 +1,57 @@
+MEMC enhancements for Linux 2.3
+-------------------------------
+
+The current interface:
+
+  There is a cache of the MEMC settings held in tsk->tss.memcmap, which is
+  kept up to date by the following functions (from the page tables):
+
+  update_memc_all()				hits:	2
+	Updates all MEMC caches on all processes.  Update the real MEMC
+	to reflect the `current' tasks page tables.
+
+  update_memc_tsk(tsk)				hits:	0
+	Update the MEMC cache for the specified task.  If tsk is the
+	`current' task, then update the real MEMC as well.
+
+  update_memc_mm(mm)				hits:	16
+	Update the MEMC cache for any task which has a mm_struct
+	corresponding to `mm'.  If the `current' tasks mm_struct
+	includes this, then update the real MEMC as well.
+
+  update_memc_addr(mm, addr, pte)		hits:	8
+	Update the MEMC cache entry defined by the physical address
+	in pte for any task which has a mm_struct corresponding to `mm'.
+	If the `current' tasks mm_struct includes this, then update the
+	real MEMC as well.
+
+The proposed interface:
+
+  Couple the MEMC cache into the mm_struct so that we only have to
+  keep one copy per mm_struct.  This also allows us to reduce the
+  number of loops through all existing tasks on each MEMC change.
+
+  memc_clear(mm, physaddr)			hits:	6
+	Clear the MEMC mapping associated with the physical address
+	`physaddr'.  If the `current' tasks mm_struct is `mm', then
+	update the real MEMC as well.	(should equate to a possible
+	two writes and zero reads).
+
+  memc_update_addr(mm, pte, logaddr)		hits:	10
+	Change the MEMC mapping for the physical address specified
+	in `pte' to point to the logical address `logaddr', with the
+	protection specified in `pte'.  If the `current' tasks mm_struct
+	is `mm', then update the real MEMC as well.  (should again equate
+	to a possible two writes and zero reads).
+
+  memc_update_mm(mm)				hits:	7
+	Rebuild the MEMC mappings for the specified `mm' in the same way
+	that update_memc_mm used to.  If the `current' tasks mm_struct
+	is `mm', update the real MEMC as well.
+
+  memc_update_all()				hits:	2
+	Rebuild the MEMC mappings for all mm_structs, including the real
+	MEMC.
+
+The hit numbers are approximate usage of each function in the 2.2.7
+memory management (mm) code, and there are other uses outside this area.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/arm/SA1100/SA1100_USB linux-2.4.21-pre6/Documentation/arm/SA1100/SA1100_USB
--- linux-2.4.20/Documentation/arm/SA1100/SA1100_USB	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/arm/SA1100/SA1100_USB	2003-03-26 23:49:39.000000000 +0000
@@ -0,0 +1,344 @@
+StrongARM SA-1100 USB function Driver
+Ward Willats <ward.willats@extenex.com> -  08Mar01
+
+1. History
+''''''''''
+Brad Parker <brad@parker.boston.ma.us> ported the DEC/Compaq "Itsy"
+SA-1100 USB Function driver to the 2.4.x code base in late 2000, for
+use as an "ethernet over usb" link. His original notes are here in
+section 4. Nicolas Pitre <nico@cam.org> rewrote the transmitter and
+reciver (endpoints 1 and 2) in late 2000 to use the standard SA DMA
+API and I added a bulk character interface and reworked the control
+control module code and rewrote endpoint zero in early 2001.
+
+This release (22Feb01) is the first that completely separates
+client modules (usb-eth.c and usb-char.c) from the SA-1100 USB core.
+(usb_ctl, usb_ep0, usb_send and usb_receive)and makes the whole
+mess a module. Oleg Drokin has done a huge amount of work, fixing
+things I break and adding support for the generic usbnet driver
+from the AC tree.
+
+2. Usage
+''''''''
+Turn on CONFIG_SA1100_USB_NETLINK to use the "ethernet over usb"
+functionality. Turn it off to use the character oriented
+interface. The character driver currently uses mknod c 10 240.
+
+Programming:
+The public interface is in sa1100_usb.h. For a client USB service
+to use the SA-1100 USB core driver it should:
+
+1. Call sa1100_usb_open() to get the usb core assigned to it.
+
+2. Setup descriptors as appropriate for the task at hand. Esp.
+important are endpoint max packet lengths, vendor and product IDs,
+and type of endpoint (bulk or interrupt). Call
+sa1100_get_descriptor_ptr() to get this.
+
+3. Call sa1100_usb_start() to actually start the usb hardware.
+At this time the host will configure the device.
+
+...at shutdown...
+
+4. Call sa1100_usb_stop() to stop the USB core.
+5. Call sa1100_usb_close() to free the core for use by another
+client.
+
+3. Netlink Usage
+''''''''''''''''
+StrongARM SA-1100 USB function "ethernet over usb driver"
+Brad Parker <brad@parker.boston.ma.us>
+
+I ported the DEC "Itsy" usb "ethernet over usb driver" code to the 2.4.x
+base and made some enhacements and bug fixes.  This code has 2 sides and
+implements a simple "ethernet over usb" functionality.
+
+function (SA1100) side:
+- the driver has two endpoints and uses interrupt and bulk transfer to
+receive/send packets.  the driver does not require any other usb code
+and should work on most any sa1100.
+
+host (SA1111) side:
+- because the SA1111 usb host is not working yet I tested this driver
+(usb-net-host.c) on a 2.2.14 based PC with the latest usb backport.
+It has been fully converted to use URBs and worked well with my UHCI
+based controller.
+
+TESTING:
+
+To test you need an assabet on the 'function' side, a PC on the 'host'
+side and a USB A-B cable to connect them together.
+
+Boot a kernel on the assabet with "USB function and net-host support"
+(CONFIG_SA1100_USB) turned on.  This will define an interface named
+"usbf".  Once it's booted you can setup the interface with
+
+	mount -t proc /proc /proc
+	/sbin/ifconfig usbf 1.1.1.2
+
+I used a 2.2.14 kernel on a x86 PC for the host side.  It has a built
+in UHCI usb controller chip.  I installed the latest USB backport from
+http://www.linux-usb.org onto the 2.2.14 kernel sources and turned on
+"USB net-host" (CONFIG_USB_NET_HOST) as a module.  Load the module
+"usb-net-host.o" and connect the USB cable to the assabet.  Configure
+the usb network interface with
+
+	/sbin/ifconfig usb0 1.1.1.1
+
+You should be able to "ping" the assabet now with
+
+	ping -c 1 1.1.1.2
+
+If the assabet is running inetd the usual network services such as
+telnet and ftp should work.
+
+Oleg Drokin in 2.4.2-rmk1-np2 (08Mar01) added module config params for
+read and write size to the usb-eth.c client to allow dynamic setting
+of the DATA0/DATA1 packet size on the usb wire:
+
+usb_rsize - number of bytes in OUT packets from host to SA1100
+usb_wsize - number of bytes in IN packets from SA1100 to host
+
+This allows dynamic tuning for performance or to prevent overruning
+the the host with data.
+
+4. Known Issues
+'''''''''''''''
+- We are fiddling with various ways to set the IMP register in
+usb_send.c. A small percentage of the time, this value does not
+"take."
+
+- I've started to bring back the /proc interface, but clients
+of the sa-usb core currently don't have a directory or something
+to put their stats into.
+
+- Only a useful subset of ep0 setup calls have been implemented.
+
+
+5. Mysteries of the Universe
+''''''''''''''''''''''''''''
+This driver has been hard to develop because the documentation
+provided by Intel is incomplete, and the UDC itself seems to have a
+variety of bugs. The errata for the part is particularly scary! This
+section is an attempt to document some of the discoveries and
+questions I have come across while working on this thing.
+
+pp 11-63 of the "Intel Strong ARM SA-1110 Microprocessor Advanced
+Developer Information" give an ominous warning about how "due to
+internal synchronization required by the UDC configuration registers,
+it is possible for the procesor to write the UDC refisters and FIFOs
+too fast." This has led to a variety of approaches that attempt to
+bang on the hardware repeatedly and read it back until the write
+"sticks."
+
+All of these approaches have been problematic. Currently some macros
+in udc_ctl.h that Nicolas wrote are being used. My hardware guy told
+me that writes would never be "lost" but stuck on some internal bus in
+the UDC module and propagated to the rest of the circuit when the time
+was right. Indeed this seemed to be the case, for example, it seems
+impossible to reliably read back the interrupt mask register of the UDC when in
+the interrupt service routine. Often times the state was not reflected
+on a read until after pending interrupt sources were cleared.
+
+I was feeling prety good about this and was ripping out the looping
+macros right and left until I came upon a situation where, while
+receiving a continuous set of 1 character packets, ep1 (usb_receive.c)
+could not clear receive packet complete (RPC). After much desperate
+faliling about it turns out changing the UDC_flip() macro to bang like
+crazy on the RPC bit did in fact clear it, and clear it
+consistently. So go figure.
+
+Other items of interest:
+
+- Upon emerging from a reset, the UDC will clear the mask register except
+for a mask on suspend.
+
+- USB 1.0 spec says maximum size of a DATA0/1 packet is 64 bytes,
+which is what the character driver is using. However, the UDC can do
+256 bytes and every host I've tried can handle it, even though they
+are not required to. (Perhaps it is a problem when hubs are on the
+line, but the SA UDC has other problems in a hub environment -- like
+even getting the correct address -- per the errata).
+
+- Endpoint zero FIFOs: ARGHHH! Just leave those routines alone.
+Believe me, I have tried every other variation you can think of.
+Probably.
+
+- Sometimes I get a setup request of 0x80 from Windows hosts. I have
+not determined if this is a read_fifo error (none is reported) or if
+this is some undocumented secret Redmond handshake only known to
+initiates of the inner-order.
+
+6. Test Program
+'''''''''''''''
+This is now in the /proc interface. (For good or ill, probably don't
+actually need to dump all this stuff..)
+
+7. Errors and Notes on Intel's 1110 Documentation
+'''''''''''''''''''''''''''''''''''''''''''''''''
+These corrections apply to "Intel StrongARM SA-1110 Microprocessor,
+Advanced Developer's Manual of December 1999" Some of these have been
+corrected in later editions, some not. There have been several updates
+to this document published through 2000. Always use the latest
+available on http://developer.intel.com/design/strong/collateral.htm.
+
+pp 11-65 section 11.8.3.8 bit 2, reserved is now the resume interrupt
+mask. SRM is now SUSIM on SA-1110, and masks only the suspend
+interrupt.
+
+pp 11-67 section 11.8.6, Max IN register, end should be 9 _bytes_
+not 9 bits.
+
+pp 11-68 section 11.8.7.3, SST. This is set by the CPU _not_ the UDC.
+And it looks like you don't get a SST if you FST yourself.
+
+pp 11-68 section 11.8.7.5, DE. This is set by the CPU _not_ the UDC.
+
+pp 11-73 section 11.8.9.7, UDCCS2 table, bit 2, Should be "valid only
+when _TPC_ (not RPC) is set.
+
+pp 11-74 section 11.8.10, should end with a GET_DESCRIPTOR _or
+similar_ command. (Like, for example, GET_CONFIGURATION).
+
+
+8. Change History
+'''''''''''''''''
+Following are current chages  8Mar01 (released in 2.4.2-rmk1-np2?)
+
+- Resetting UDC when coming out of suspend helped enumeration get
+going considerably.
+
+- Added support for client-supplied notify routine to be called
+by the USB core when core reaches "configured" state.
+
+- Added error returns from interrupt reads and buffer flush ioctl
+calls to usb-char. Added usb-char.h file for ioctl calls.
+
+- Fixed bug that kept usb-char transmitter from working the second
+time the module was loaded.
+
+- Turned off a lot of the noise in /proc
+
+- Added specialty routines in ep0 to set and clear bits.
+
+- More enumeration fiddling.
+
+- There are horrible hacks to set max IN length in usb_send
+  that ARE GOING AWAY SOON! REALLY!
+
+*** Following changes 26Feb01 (released in 2.4.2-rmk1-np1)
+
+- usb-eth integration with generic usbnet from AC tree.
+
+- Creation of public interface for usb clients in sa1100_usb.h
+and final separation into a "core" driver (usb_ctl.c, usb_ep0.c
+usb_recv.c usb_send.c) and "client" services (usb-eth.c and
+usb-char.c). Modularized.
+
+- Descriptor handling rewritten. Support for string descriptors
+added. More bugs in ep0 fixed. More setup packets handled.
+
+- /proc interface in usb_ctl returning
+
+- removed client specific stuff from usbd_info_t and hid the
+structure in usb_ctl. Removed RAM-backing of address and pktsize
+in this structure. Now the descriptor values are gospel.
+
+- usb_dbg.h eliminated
+
+- Many bugs fixed in usb-char.c
+
+- Fiddled startup sequence so should start everytime.
+
+- Arch specific "soft connect" hook in usb_ctl.c
+
+- Bumped the interation count in write/set/clear macros
+in usb_ctl.h up to 10000. This seemed to help various bit
+setting in ep0 and usb_send.c.
+
+*** Following changes 10Feb01 release:
+
+- endpoint zero entirely rewitten
+
+- Various changes by Oleg to make Netlink work again after the
+  2.4.1-rmk1-np1 release.
+
+- Resetting of new max packet length done after clearing TPC
+in usb_send, per Nicolas Pitre.
+
+
+*** Following changes 23Jan01 (came out in 2.4.1-rmk1-np1):
+
+- Moved host initiated SET/GET feature stall into endpoint code of
+usb_send.c and usb_receive.c and removed stallep from usb_ctl.c
+Opposite of a SET_FEATURE stall is a reset, so no code to unstall is
+provided.
+
+- Added explicit USB state machine to usb_ctl so driver and device
+state can be tracked closely and explicitly. Added hard-wired
+notification routines in endpoints 1 and 2 so they can track device
+state changes as required. State machine has notion of "zombie" state
+the covers USB states NONATTACHED, ATTACHED and POWERED since these
+are murky, and USB driver currently has no way to differentiate
+between the two.
+
+- Reworked ISR in usb_ctl so reset has higher priority than any other
+event. Stopped using sync macros to clear interrupt pending flags and set
+mask registers since it appears mask register changes are not
+always reflected on a mask register read until the pending flag is
+cleared (yet other tests show they are always cleared
+eventually). Toggle suspend/resume interrupt masks back and forth during
+suspend and resume to debounce and keep UDC internal state machine in
+sync per Intel documentation.
+
+- Flipped UDC flip, clear, write and set macros from do{}while to
+while() loops. Theory is you might save a loop iteration if value
+becomes valid immediately. Also, my hardware guy says writes are never
+"lost", just pipelined and not executed immediately depending on
+internal device conditions (like setting int masks when ints
+pending), so moved write cycles in macros outside of loops.
+
+- Added #defines to SA-1110.h for suspend and resume interrupt mask
+bits per Intel eratta. Submitted to ARM patch system (444/1).
+
+- Removed task queue and defered execution of configure() from
+usb_ctl.
+
+- Removed usb_write_reg() from usb_ctl.c, and various cruft from
+usb_ctl.h.
+
+- Added sa1100_usb_xmitter_avail() to usb_send.c. Makes implementing
+poll() fileop easier.
+
+- Added sa1100_usb_send_reset() to usb_send.c. Makes implementing
+transmitter timeout easier.
+
+- Added API to usb_ctl to set vendor and product ID
+
+- Changed BMATTR descriptor fron int to bulk, when not using netlink. (All
+the docs say UDC does not support INT xfers -- though, at the protocol
+level I don't see why not, since bulk and int are both just
+IN-DATA-ACK. I figure netlink may rely on this, and not just a
+continuous pending read from the host, but for "pure bulk" host
+polling may not be generally correct.)
+
+- Removed unused rx_lock and tx_lock from usb_ctl
+
+- Converted everyone to SA-1100.h and nuked hardware defines in usb_ctl.h
+
+- Removed udc_init() in usb_ctl.c and folded functionality into udc_start().
+
+- Clear force stall (FST) in udc_start and reset so UDC actually runs when
+first turned on.
+
+- Emit NAK in receiver until ep1_start() for error (RPE) case too.
+
+- Remove enable/disable UDC from reset handler in udc_ctl. The UDC has
+already been reset, so no need to do this again.
+
+- Explicitly set address to zero in ep0_reset()
+
+- Added "naking" boolean to usb_receiv.c. An attempt to solve a
+hypothetical race condition where we are in the critical section
+initiating a read from base-level code, a RPC happens, and start()
+might clear the condition before the packet is handled by the ISR.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/arm/SA1100/nanoEngine linux-2.4.21-pre6/Documentation/arm/SA1100/nanoEngine
--- linux-2.4.20/Documentation/arm/SA1100/nanoEngine	2001-09-07 16:28:38.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/arm/SA1100/nanoEngine	2003-03-26 23:49:18.000000000 +0000
@@ -7,5 +7,7 @@
 (Ref: Stuart Adams <sja@brightstareng.com>)
 
 Also visit Larry Doolittle's "Linux for the nanoEngine" site:
-http://recycle.lbl.gov/~ldoolitt/bse/
-
+  http://recycle.lbl.gov/~ldoolitt/bse/
+This page includes translation code that builds the parameter
+blocks for the Linux kernel, which must happen before each
+kernel boot.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/cciss.txt linux-2.4.21-pre6/Documentation/cciss.txt
--- linux-2.4.20/Documentation/cciss.txt	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/cciss.txt	2003-03-26 23:49:07.000000000 +0000
@@ -9,6 +9,9 @@
 	* SA 5i 
 	* SA 532
 	* SA 5312
+	* SA 641
+	* SA 642
+	* SA 6400
 
 If nodes are not already created in the /dev/cciss directory
 
@@ -86,7 +89,7 @@
 
 Hot plugging of SCSI tape drives is supported, with some caveats.
 The cciss driver must be informed that changes to the SCSI bus
-have been made, in addition to and prior to informing the the SCSI 
+have been made, in addition to and prior to informing the SCSI 
 mid layer.  This may be done via the /proc filesystem.  For example:
 
 	echo "rescan" > /proc/scsi/cciss0/1
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/fb/clgenfb.txt linux-2.4.21-pre6/Documentation/fb/clgenfb.txt
--- linux-2.4.20/Documentation/fb/clgenfb.txt	2001-11-19 23:19:42.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/fb/clgenfb.txt	2003-03-26 23:48:58.000000000 +0000
@@ -1,6 +1,6 @@
 
 		Framebuffer driver for Cirrus Logic chipsets
-		Copyright 1999 Jeff Garzik <jgarzik@mandrakesoft.com>
+		Copyright 1999 Jeff Garzik <jgarzik@pobox.com>
 
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/filesystems/Locking linux-2.4.21-pre6/Documentation/filesystems/Locking
--- linux-2.4.20/Documentation/filesystems/Locking	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/filesystems/Locking	2003-03-26 23:49:25.000000000 +0000
@@ -93,6 +93,7 @@
 	void (*delete_inode) (struct inode *);
 	void (*put_super) (struct super_block *);
 	void (*write_super) (struct super_block *);
+	int (*sync_fs) (struct super_block *);
 	int (*statfs) (struct super_block *, struct statfs *);
 	int (*remount_fs) (struct super_block *, int *, char *);
 	void (*clear_inode) (struct inode *);
@@ -108,6 +109,7 @@
 clear_inode:	no	
 put_super:	yes	yes	maybe		(see below)
 write_super:	yes	yes	maybe		(see below)
+sync_fs:	yes	no	maybe		(see below)
 statfs:		yes	no	no
 remount_fs:	yes	yes	maybe		(see below)
 umount_begin:	yes	no	maybe		(see below)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/filesystems/jfs.txt linux-2.4.21-pre6/Documentation/filesystems/jfs.txt
--- linux-2.4.20/Documentation/filesystems/jfs.txt	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/filesystems/jfs.txt	2003-03-26 23:49:40.000000000 +0000
@@ -28,8 +28,6 @@
 Plans for our near term development items
 
    - enhance support for logfile on dedicated partition
-   - get access control list functionality operational
-   - get extended attributes functionality operational
 
 Longer term work items
 
@@ -37,7 +35,7 @@
    - add quota support
    - add support for block sizes (512,1024,2048)
 
-Please send bugs, comments, cards and letters to linuxjfs@us.ibm.com.
+Please send bugs, comments, cards and letters to shaggy@austin.ibm.com.
 
 The JFS mailing list can be subscribed to by using the link labeled
 "Mail list Subscribe" at our web page http://oss.software.ibm.com/jfs/.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/filesystems/proc.txt linux-2.4.21-pre6/Documentation/filesystems/proc.txt
--- linux-2.4.20/Documentation/filesystems/proc.txt	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/filesystems/proc.txt	2003-03-26 23:49:20.000000000 +0000
@@ -952,15 +952,14 @@
 Table 2-2: Parameters in /proc/sys/vm/bdflush 
 ..............................................................................
  Value      Meaning                                                            
- nfract     Percentage of buffer cache dirty to  activate bdflush              
+ nfract     Percentage of buffer cache dirty to activate bdflush              
  ndirty     Maximum number of dirty blocks to  write out per wake-cycle        
- nrefill    Number of clean buffers to try to obtain  each time we call refill 
- nref_dirt  buffer threshold for activating bdflush when trying to refill
-            buffers. 
  dummy      Unused                                                             
- age_buffer Time for normal buffer to age before we flush it                   
- age_super  Time for superblock to age before we flush it                      
  dummy      Unused                                                             
+ interval   jiffies delay between kupdate flushes
+ age_buffer Time for normal buffer to age before we flush it                   
+ nfract_sync Percentage of buffer cache dirty to activate bdflush synchronously
+ nfract_stop_bdflush Percetange of buffer cache dirty to stop bdflush
  dummy      Unused                                                             
 ..............................................................................
 
@@ -974,6 +973,12 @@
 long time, but it also means that it will have to do a lot of I/O at once when
 memory becomes short. A lower value will spread out disk I/O more evenly.
 
+interval
+--------
+
+The interval between two kupdate runs. The value is expressed in
+jiffies (clockticks),  the  number of jiffies per second is 100.
+
 ndirty
 ------
 
@@ -981,29 +986,18 @@
 disk at  one  time.  A high value will mean delayed, bursty I/O, while a small
 value can lead to memory shortage when bdflush isn't woken up often enough.
 
-nrefill
--------
-
-This is  the  number  of  buffers  that  bdflush  will add to the list of free
-buffers when  refill_freelist()  is  called.  It is necessary to allocate free
-buffers beforehand,  since  the  buffers  are  often  different sizes than the
-memory pages  and some bookkeeping needs to be done beforehand. The higher the
-number, the  more  memory  will be wasted and the less often refill_freelist()
-will need to run.
-
-nref_dirt
----------
+age_buffer
+----------
 
-When refill_freelist() comes across more than nref_dirt dirty buffers, it will
-wake up bdflush.
+Finally, the age_buffer parameter govern the maximum time Linux
+waits before  writing  out  a  dirty buffer to disk. The value is expressed in
+jiffies (clockticks),  the  number of jiffies per second is 100.
 
-age_buffer and age_super
-------------------------
+nfract_sync
+-----------
 
-Finally, the age_buffer and age_super parameters govern the maximum time Linux
-waits before  writing  out  a  dirty buffer to disk. The value is expressed in
-jiffies (clockticks),  the  number of jiffies per second is 100. Age_buffer is
-the maximum age for data blocks, while age_super is for filesystems meta data.
+nfract_stop_bdflush
+-------------------
 
 buffermem
 ---------
@@ -1582,10 +1576,14 @@
 error_burst and error_cost
 --------------------------
 
-These parameters  are used to limit the warning messages written to the kernel
-log from  the  routing  code.  The  higher the error_cost factor is, the fewer
-messages will  be written. Error_burst controls when messages will be dropped.
-The default settings limit warning messages to one every five seconds.
+These  parameters  are used to limit how many ICMP destination unreachable to 
+send  from  the  host  in question. ICMP destination unreachable messages are 
+sent  when  we can not reach the next hop, while trying to transmit a packet. 
+It  will also print some error messages to kernel logs if someone is ignoring 
+our   ICMP  redirects.  The  higher  the  error_cost  factor  is,  the  fewer 
+destination  unreachable  and error messages will be let through. Error_burst 
+controls  when  destination  unreachable  messages and error messages will be
+dropped. The default settings limit warning messages to five every second.
 
 flush
 -----
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/i810_rng.txt linux-2.4.21-pre6/Documentation/i810_rng.txt
--- linux-2.4.20/Documentation/i810_rng.txt	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/i810_rng.txt	2003-03-26 23:49:50.000000000 +0000
@@ -1,5 +1,5 @@
 	Hardware driver for Intel i810 Random Number Generator (RNG)
-	Copyright 2000,2001 Jeff Garzik <jgarzik@mandrakesoft.com>
+	Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>
 	Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>
 
 Introduction:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/networking/00-INDEX linux-2.4.21-pre6/Documentation/networking/00-INDEX
--- linux-2.4.20/Documentation/networking/00-INDEX	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/networking/00-INDEX	2003-03-26 23:49:51.000000000 +0000
@@ -97,7 +97,8 @@
 sis900.txt
 	- SiS 900/7016 Fast Ethernet device driver info.
 sk98lin.txt
-	- SysKonnect SK-NET (SK-98xx) Gigabit Ethernet driver info.
+	- SysKonnect SK-98xx and SK-98xx Gigabit Ethernet Adapter family 
+	  driver info.
 skfp.txt
 	- SysKonnect FDDI (SK-5xxx, Compaq Netelligent) driver info.
 smc9.txt
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/networking/8139too.txt linux-2.4.21-pre6/Documentation/networking/8139too.txt
--- linux-2.4.20/Documentation/networking/8139too.txt	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/networking/8139too.txt	2003-03-26 23:49:40.000000000 +0000
@@ -2,7 +2,7 @@
 		"8139too" Fast Ethernet driver for Linux
 	 RTL-8139, -8129, and -8130 10/100 Fast Ethernet adapters
 
-	Copyright 2000,2001 Jeff Garzik <jgarzik@mandrakesoft.com>
+	Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>
 
                 http://sourceforge.net/projects/gkernel/
 
@@ -93,6 +93,8 @@
 ---------------
 AOpen ALN-325C
 AT-2500TX 10/100 PCI Fast Ethernet Network Adapter Card
+Cnet CNF401 'SinglePoint' 10/100 Base-TX
+Genius GF 100TXR4 Fast Ethernet 10/100M PCI Network Card
 KTI KF-230TX
 KTI KF-230TX/2
 Lantech FastNet TX
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/networking/NAPI_HOWTO.txt linux-2.4.21-pre6/Documentation/networking/NAPI_HOWTO.txt
--- linux-2.4.20/Documentation/networking/NAPI_HOWTO.txt	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/networking/NAPI_HOWTO.txt	2003-03-26 23:49:40.000000000 +0000
@@ -721,6 +721,23 @@
 
 
 
+
+APPENDIX 3: Scheduling issues.
+==============================
+As seen NAPI moves processing to softirq level. Linux uses the ksoftirqd as the 
+general solution to schedule softirq's to run before next interrupt and by putting 
+them under scheduler control. Also this prevents consecutive softirq's from 
+monopolize the CPU. This also have the effect that the priority of ksoftirq needs 
+to be considered when running very CPU-intensive applications and networking to
+get the proper balance of softirq/user balance. Increasing ksoftirq priority to 0 
+(eventually more) is reported cure problems with low network performance at high 
+CPU load.
+
+Most used processes in a GIGE router:
+USER       PID %CPU %MEM  SIZE   RSS TTY STAT START   TIME COMMAND
+root         3  0.2  0.0     0     0  ?  RWN Aug 15 602:00 (ksoftirqd_CPU0)
+root       232  0.0  7.9 41400 40884  ?  S   Aug 15  74:12 gated 
+
 --------------------------------------------------------------------
 
 relevant sites:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/networking/bonding.txt linux-2.4.21-pre6/Documentation/networking/bonding.txt
--- linux-2.4.20/Documentation/networking/bonding.txt	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/networking/bonding.txt	2003-03-26 23:49:19.000000000 +0000
@@ -17,6 +17,23 @@
 For new versions of the driver, patches for older kernels and the updated
 userspace tools, please follow the links at the end of this file.
 
+
+Table of Contents
+=================
+ 
+Installation
+Bond Configuration
+Module Parameters
+Configuring Multiple Bonds
+Switch Configuration
+Verifying Bond Configuration
+Frequently Asked Questions
+High Availability
+Promiscuous Sniffing notes
+Limitations
+Resources and Links
+
+
 Installation
 ============
 
@@ -51,16 +68,21 @@
     # gcc -Wall -Wstrict-prototypes -O -I/usr/src/linux/include ifenslave.c -o ifenslave 
     # cp ifenslave /sbin/ifenslave
 
-3) Configure your system
-------------------------
-Also see the following section on the module parameters. You will need to add
-at least the following line to /etc/conf.modules (or /etc/modules.conf):
+
+Bond Configuration
+==================
+
+You will need to add at least the following line to /etc/modules.conf
+so the bonding driver will automatically load when the bond0 interface is 
+configured. Refer to the modules.conf manual page for specific modules.conf 
+syntax details. The Module Parameters section of this document describes each 
+bonding driver parameter. 
 
 	alias bond0 bonding
 
-Use standard distribution techniques to define bond0 network interface. For
-example, on modern RedHat distributions, create ifcfg-bond0 file in
-/etc/sysconfig/network-scripts directory that looks like this:
+Use standard distribution techniques to define the bond0 network interface. For
+example, on modern Red Hat distributions, create an ifcfg-bond0 file in
+the /etc/sysconfig/network-scripts directory that resembles the following:
 
 DEVICE=bond0
 IPADDR=192.168.1.1
@@ -71,12 +93,12 @@
 BOOTPROTO=none
 USERCTL=no
 
-(put the appropriate values for you network instead of 192.168.1).
+(use appropriate values for your network above)
 
-All interfaces that are part of the trunk, should have SLAVE and MASTER
-definitions. For example, in the case of RedHat, if you wish to make eth0 and
-eth1 (or other interfaces) a part of the bonding interface bond0, their config
-files (ifcfg-eth0, ifcfg-eth1, etc.) should look like this:
+All interfaces that are part of a bond should have SLAVE and MASTER
+definitions. For example, in the case of Red Hat, if you wish to make eth0 and
+eth1 a part of the bonding interface bond0, their config files (ifcfg-eth0 and
+ifcfg-eth1) should resemble the following:
 
 DEVICE=eth0
 USERCTL=no
@@ -85,89 +107,261 @@
 SLAVE=yes
 BOOTPROTO=none
 
-(use DEVICE=eth1 for eth1 and MASTER=bond1 for bond1 if you have configured
-second bonding interface). 
+Use DEVICE=eth1 in the ifcfg-eth1 config file. If you configure a second bonding
+interface (bond1), use MASTER=bond1 in the config file to make the network
+interface be a slave of bond1.
 
 Restart the networking subsystem or just bring up the bonding device if your
-administration tools allow it. Otherwise, reboot. (For the case of RedHat
-distros, you can do `ifup bond0' or `/etc/rc.d/init.d/network restart'.)
+administration tools allow it. Otherwise, reboot. On Red Hat distros you can 
+issue `ifup bond0' or `/etc/rc.d/init.d/network restart'.
 
 If the administration tools of your distribution do not support master/slave
-notation in configuration of network interfaces, you will need to configure
-the bonding device with the following commands manually:
+notation in configuring network interfaces, you will need to manually configure 
+the bonding device with the following commands:
+
+    # /sbin/ifconfig bond0 192.168.1.1 netmask 255.255.255.0 \
+      broadcast 192.168.1.255 up
 
-    # /sbin/ifconfig bond0 192.168.1.1 up
     # /sbin/ifenslave bond0 eth0
     # /sbin/ifenslave bond0 eth1
 
-(substitute 192.168.1.1 with your IP address and add custom network and custom
-netmask to the arguments of ifconfig if required).
+(use appropriate values for your network above)
 
-You can then create a script with these commands and put it into the appropriate
-rc directory.
+You can then create a script containing these commands and place it in the 
+appropriate rc directory.
 
-If you specifically need that all your network drivers are loaded before the
-bonding driver, use one of modutils' powerful features : in your modules.conf,
-tell that when asked for bond0, modprobe should first load all your interfaces :
+If you specifically need all network drivers loaded before the bonding driver,
+adding the following line to modules.conf will cause the network driver for 
+eth0 and eth1 to be loaded before the bonding driver.
 
 probeall bond0 eth0 eth1 bonding
 
-Be careful not to reference bond0 itself at the end of the line, or modprobe will
-die in an endless recursive loop.
-
-4) Module parameters.
----------------------
-The following module parameters can be passed:
+Be careful not to reference bond0 itself at the end of the line, or modprobe 
+will die in an endless recursive loop.
 
-    mode=
+To have device characteristics (such as MTU size) propagate to slave devices, 
+set the bond characteristics before enslaving the device.  The characteristics 
+are propagated during the enslave process.
+
+If running SNMP agents, the bonding driver should be loaded before any network 
+drivers participating in a bond. This requirement is due to the the interface 
+index (ipAdEntIfIndex) being associated to the first interface found with a 
+given IP address. That is, there is only one ipAdEntIfIndex for each IP 
+address. For example, if eth0 and eth1 are slaves of bond0 and the driver for 
+eth0 is loaded before the bonding driver, the interface for the IP address 
+will be associated with the eth0 interface. This configuration is shown below, 
+the IP address 192.168.1.1 has an interface index of 2 which indexes to eth0 
+in the ifDescr table (ifDescr.2).
+
+     interfaces.ifTable.ifEntry.ifDescr.1 = lo
+     interfaces.ifTable.ifEntry.ifDescr.2 = eth0
+     interfaces.ifTable.ifEntry.ifDescr.3 = eth1
+     interfaces.ifTable.ifEntry.ifDescr.4 = eth2
+     interfaces.ifTable.ifEntry.ifDescr.5 = eth3
+     interfaces.ifTable.ifEntry.ifDescr.6 = bond0
+     ip.ipAddrTable.ipAddrEntry.ipAdEntIfIndex.10.10.10.10 = 5
+     ip.ipAddrTable.ipAddrEntry.ipAdEntIfIndex.192.168.1.1 = 2
+     ip.ipAddrTable.ipAddrEntry.ipAdEntIfIndex.10.74.20.94 = 4
+     ip.ipAddrTable.ipAddrEntry.ipAdEntIfIndex.127.0.0.1 = 1
+
+This problem is avoided by loading the bonding driver before any network
+drivers participating in a bond. Below is an example of loading the bonding 
+driver first, the IP address 192.168.1.1 is correctly associated with ifDescr.2.
+
+     interfaces.ifTable.ifEntry.ifDescr.1 = lo
+     interfaces.ifTable.ifEntry.ifDescr.2 = bond0
+     interfaces.ifTable.ifEntry.ifDescr.3 = eth0
+     interfaces.ifTable.ifEntry.ifDescr.4 = eth1
+     interfaces.ifTable.ifEntry.ifDescr.5 = eth2
+     interfaces.ifTable.ifEntry.ifDescr.6 = eth3
+     ip.ipAddrTable.ipAddrEntry.ipAdEntIfIndex.10.10.10.10 = 6
+     ip.ipAddrTable.ipAddrEntry.ipAdEntIfIndex.192.168.1.1 = 2
+     ip.ipAddrTable.ipAddrEntry.ipAdEntIfIndex.10.74.20.94 = 5
+     ip.ipAddrTable.ipAddrEntry.ipAdEntIfIndex.127.0.0.1 = 1
+
+While some distributions may not report the interface name in ifDescr,
+the association between the IP address and IfIndex remains and SNMP
+functions such as Interface_Scan_Next will report that association.
 
-Possible values are 0 (round robin policy, default) and 1 (active backup
-policy), and 2 (XOR).  See question 9 and the HA section for additional info.
 
-    miimon=
-
-Use integer value for the frequency (in ms) of MII link monitoring. Zero value
-is default and means the link monitoring will be disabled. A good value is 100
-if you wish to use link monitoring. See HA section for additional info.
+Module Parameters
+=================
 
-    downdelay=
+Optional parameters for the bonding driver can be supplied as command line 
+arguments to the insmod command. Typically, these parameters are specified in 
+the file /etc/modules.conf (see the manual page for modules.conf). The 
+available bonding driver parameters are listed below. If a parameter is not 
+specified the default value is used. When initially configuring a bond, it
+is recommended "tail -f /var/log/messages" be run in a separate window to
+watch for bonding driver error messages.
+
+It is critical that either the miimon or arp_interval and arp_ip_target
+parameters be specified, otherwise serious network degradation will occur
+during link failures.
+
+mode
+        Specifies one of four bonding policies. The default is round-robin.
+        Possible values are:
+ 
+        0       Round-robin policy: Transmit in a sequential order from the
+                first available slave through the last. This mode provides
+                load balancing and fault tolerance.
+
+        1       Active-backup policy: Only one slave in the bond is active. A 
+                different slave becomes active if, and only if, the active slave
+                fails. The bond's MAC address is externally visible on only 
+                one port (network adapter) to avoid confusing the switch.
+                This mode provides fault tolerance.
+ 
+ 
+        2       XOR policy: Transmit based on [(source MAC address XOR'd with 
+                destination MAC address) modula slave count]. This selects the 
+                same slave for each destination MAC address. This mode provides
+                load balancing and fault tolerance.
+
+        3       Broadcast policy: transmits everything on all slave interfaces.
+                This mode provides fault tolerance.
+
+miimon
+ 
+        Specifies the frequency in milli-seconds that MII link monitoring will 
+        occur. A value of zero disables MII link monitoring. A value of 
+        100 is a good starting point. See High Availability section for 
+        additional information. The default value is 0.
+
+downdelay
+ 
+        Specifies the delay time in milli-seconds to disable a link after a 
+        link failure has been detected. This should be a multiple of miimon
+        value, otherwise the value will be rounded. The default value is 0.
+
+updelay
+ 
+        Specifies the delay time in milli-seconds to enable a link after a 
+        link up status has been detected. This should be a multiple of miimon
+        value, otherwise the value will be rounded. The default value is 0.
+ 
+arp_interval
+ 
+        Specifies the ARP monitoring frequency in milli-seconds. 
+        If ARP monitoring is used in a load-balancing mode (mode 0 or 2), the 
+        switch should be configured in a mode that evenly distributes packets 
+        across all links - such as round-robin. If the switch is configured to 
+        distribute the packets in an XOR fashion, all replies from the ARP 
+        targets will be received on the same link which could cause the other 
+        team members to fail. ARP monitoring should not be used in conjunction
+        with miimon. A value of 0 disables ARP monitoring. The default value 
+        is 0.
+ 
+arp_ip_target
+ 
+        Specifies the ip addresses to use when arp_interval is > 0. These are
+        the targets of the ARP request sent to determine the health of the link
+        to the targets. Specify these values in ddd.ddd.ddd.ddd format.
+        Multiple ip adresses must be seperated by a comma. At least one ip
+        address needs to be given for ARP monitoring to work. The maximum number
+        of targets that can be specified is set at 16.
+
+primary
+
+        A string (eth0, eth2, etc) to equate to a primary device. If this 
+        value is entered, and the device is on-line, it will be used first as 
+        the output media. Only when this device is off-line, will alternate 
+        devices be used. Otherwise, once a failover is detected and a new 
+        default output is chosen, it will remain the output media until it too 
+        fails. This is useful when one slave was preferred over another, i.e. 
+        when one slave is 1000Mbps and another is 100Mbps. If the 1000Mbps 
+        slave fails and is later restored, it may be preferred the faster slave
+        gracefully become the active slave - without deliberately failing the
+        100Mbps slave. Specifying a primary is only valid in active-backup mode.
+
+multicast
+
+        Integer value for the mode of operation for multicast support.
+        Possible values are:
+
+        0       Disabled (no multicast support)
+
+        1       Enabled on active slave only, useful in active-backup mode
+
+        2       Enabled on all slaves, this is the default
+
+
+Configuring Multiple Bonds
+==========================
+
+If several bonding interfaces are required, the driver must be loaded
+multiple times. For example, to configure two bonding interfaces with link 
+monitoring performed every 100 milli-seconds, the /etc/conf.modules should
+resemble the following:
 
-Use integer value for delaying disabling a link by this number (in ms) after
-the link failure has been detected. Must be a multiple of miimon. Default
-value is zero. See HA section for additional info.
+alias bond0 bonding
+alias bond1 bonding
 
-    updelay=
+options bond0 miimon=100
+options bond1 -o bonding1 miimon=100
 
-Use integer value for delaying enabling a link by this number (in ms) after
-the "link up" status has been detected. Must be a multiple of miimon. Default
-value is zero. See HA section for additional info.
+Configuring Multiple ARP Targets
+================================
 
-    arp_interval=
+While ARP monitoring can be done with just one target, it can be usefull
+in a High Availability setup to have several targets to monitor. In the
+case of just one target,  the target itself may go down or have a problem
+making it unresponsive to ARP requests. Having an additional target (or
+several) would increase the reliability of the ARP monitoring.
+Multiple ARP targets must be seperated by commas as follows:
 
-Use integer value for the frequency (in ms) of arp monitoring.  Zero value 
-is default and means the arp monitoring will be disabled.  See HA section
-for additional info.   This field is value in active_backup mode only.
+# example options for ARP monitoring with three targets
+alias bond0 bonding
+options bond0 arp_interval=60 arp_ip_target=192.168.0.1,192.168.0.3,192.168.0.9
 
-    arp_ip_target=
+For just a single target the options would resemble:
 
-An ip address to use when arp_interval is > 0.  This is the target of the
-arp request sent to determine the health of the link to the target.  
-Specify this value in ddd.ddd.ddd.ddd format.
+# example options for ARP monitoring with one target
+alias bond0 bonding
+options bond0 arp_interval=60 arp_ip_target=192.168.0.100
 
-If you need to configure several bonding devices, the driver must be loaded
-several times. I.e. for two bonding devices, your /etc/conf.modules must look
-like this:
 
-alias bond0 bonding
-alias bond1 bonding
 
-options bond0 miimon=100
-options bond1 -o bonding1 miimon=100
+Switch Configuration
+====================
 
-5) Testing configuration
-------------------------
-You can test the configuration and transmit policy with ifconfig. For example,
-for round robin policy, you should get something like this:
+While the switch does not need to be configured when the active-backup
+policy is used (mode=1), it does need to be configured for the round-robin, 
+XOR, and broadcast policies (mode=0, mode=2, and mode=3). 
+
+
+Verifying Bond Configuration
+============================
+
+1) Bonding information files
+----------------------------
+The bonding driver information files reside in the /proc/net/bond* directories. 
+
+Sample contents of /proc/net/bond0/info after the driver is loaded with 
+parameters of mode=0 and miimon=1000 is shown below.
+ 
+        Bonding Mode: load balancing (round-robin)
+        Currently Active Slave: eth0
+        MII Status: up
+        MII Polling Interval (ms): 1000
+        Up Delay (ms): 0
+        Down Delay (ms): 0
+ 
+        Slave Interface: eth1
+        MII Status: up
+        Link Failure Count: 1
+ 
+        Slave Interface: eth0
+        MII Status: up
+        Link Failure Count: 1
+
+2) Network verification
+-----------------------
+The network configuration can be verified using the ifconfig command. In
+the example below, the bond0 interface is the master (MASTER) while eth0 and 
+eth1 are slaves (SLAVE). Notice all slaves of bond0 have the same MAC address 
+(HWaddr) as bond0.
 
 [root]# /sbin/ifconfig
 bond0     Link encap:Ethernet  HWaddr 00:C0:F0:1F:37:B4  
@@ -193,12 +387,13 @@
           collisions:0 txqueuelen:100 
           Interrupt:9 Base address:0x1400 
 
-Questions :
-===========
+
+Frequently Asked Questions
+==========================
 
 1.  Is it SMP safe?
 
-	Yes.  The old 2.0.xx channel bonding patch was not SMP safe.
+	Yes. The old 2.0.xx channel bonding patch was not SMP safe.
 	The new driver was designed to be SMP safe from the start.
 
 2.  What type of cards will work with it?
@@ -209,31 +404,30 @@
 
 3.  How many bonding devices can I have?
 
-	One for each module you load. See section on module parameters for how
+	One for each module you load. See section on Module Parameters for how
 	to accomplish this.
 
 4.  How many slaves can a bonding device have?
 
-	Limited by the number of network interfaces Linux supports and the
-	number of cards you can place in your system.
+	Limited by the number of network interfaces Linux supports and/or the
+	number of network cards you can place in your system.
 
 5.  What happens when a slave link dies?
 
-	If your ethernet cards support MII status monitoring and the MII
-	monitoring has been enabled in the driver (see description of module
-	parameters), there will be no adverse consequences. This release
-	of the bonding driver knows how to get the MII information and
+	If your ethernet cards support MII or ETHTOOL link status monitoring 
+        and the MII monitoring has been enabled in the driver (see description 
+        of module parameters), there will be no adverse consequences. This 
+        release of the bonding driver knows how to get the MII information and
 	enables or disables its slaves according to their link status.
-	See section on HA for additional information.
+	See section on High Availability for additional information.
 
-	For ethernet cards not supporting MII status, or if you wish to 
-	verify that packets have been both send and received, you may
-	configure the arp_interval and arp_ip_target.  If packets have
-	not been sent or received during this interval, an arp request
-	is sent to the target to generate send and receive traffic.  
-	If after this interval, either the successful send and/or 
-	receive count has not incremented, the next slave in the sequence
-	will become the active slave.
+	For ethernet cards not supporting MII status, the arp_interval and
+        arp_ip_target parameters must be specified for bonding to work
+        correctly. If packets have not been sent or received during the
+        specified arp_interval durration, an ARP request is sent to the targets 
+        to generate send and receive traffic. If after this interval, either 
+        the successful send and/or receive count has not incremented, the next 
+        slave in the sequence will become the active slave.
 
 	If neither mii_monitor and arp_interval is configured, the bonding
 	driver will not handle this situation very well. The driver will 
@@ -245,11 +439,12 @@
 6.  Can bonding be used for High Availability?
 
 	Yes, if you use MII monitoring and ALL your cards support MII link
-	status reporting. See section on HA for more information.
+	status reporting. See section on High Availability for more information.
 
 7.  Which switches/systems does it work with?
 
-	In round-robin mode, it works with systems that support trunking:
+	In round-robin and XOR mode, it works with systems that support 
+	trunking:
 	
 	* Cisco 5500 series (look for EtherChannel support).
 	* SunTrunking software.
@@ -259,14 +454,15 @@
 	  units.
 	* Linux bonding, of course !
 	
-	In Active-backup mode, it should work with any Layer-II switches.
+	In active-backup mode, it should work with any Layer-II switche.
+
 
 8.  Where does a bonding device get its MAC address from?
 
 	If not explicitly configured with ifconfig, the MAC address of the
 	bonding device is taken from its first slave device. This MAC address
 	is then passed to all following slaves and remains persistent (even if
-	the the first slave is removed) until the bonding device is brought
+	the first slave is removed) until the bonding device is brought
 	down or reconfigured.
 	
 	If you wish to change the MAC address, you can set it with ifconfig:
@@ -297,55 +493,68 @@
 
 9.  Which transmit polices can be used?
 
-	Round robin, based on the order of enslaving, the output device
-	is selected base on the next available slave.  Regardless of
+	Round-robin, based on the order of enslaving, the output device
+	is selected base on the next available slave. Regardless of
 	the source and/or destination of the packet.
 
-	XOR, based on (src hw addr XOR dst hw addr) % slave cnt.  This
-	selects the same slave for each destination hw address.
-
 	Active-backup policy that ensures that one and only one device will
 	transmit at any given moment. Active-backup policy is useful for
 	implementing high availability solutions using two hubs (see
-	section on HA).
+	section on High Availability).
+
+	XOR, based on (src hw addr XOR dst hw addr) % slave count. This
+	policy selects the same slave for each destination hw address.
 
-High availability
+	Broadcast policy transmits everything on all slave interfaces.
+
+
+High Availability
 =================
 
-To implement high availability using the bonding driver, you need to
-compile the driver as module because currently it is the only way to pass
-parameters to the driver. This may change in the future.
-
-High availability is achieved by using MII status reporting. You need to
-verify that all your interfaces support MII link status reporting. On Linux
-kernel 2.2.17, all the 100 Mbps capable drivers and yellowfin gigabit driver
-support it. If your system has an interface that does not support MII status
-reporting, a failure of its link will not be detected!
-
-The bonding driver can regularly check all its slaves links by checking the
-MII status registers. The check interval is specified by the module argument
-"miimon" (MII monitoring). It takes an integer that represents the
-checking time in milliseconds. It should not come to close to (1000/HZ)
-(10 ms on i386) because it may then reduce the system interactivity. 100 ms
-seems to be a good value. It means that a dead link will be detected at most
-100 ms after it goes down.
+To implement high availability using the bonding driver, the driver needs to be
+compiled as a module, because currently it is the only way to pass parameters 
+to the driver. This may change in the future.
+
+High availability is achieved by using MII or ETHTOOL status reporting. You 
+need to verify that all your interfaces support MII or ETHTOOL link status 
+reporting.  On Linux kernel 2.2.17, all the 100 Mbps capable drivers and 
+yellowfin gigabit driver support MII. To determine if ETHTOOL link reporting 
+is available for interface eth0, type "ethtool eth0" and the "Link detected:" 
+line should contain the correct link status. If your system has an interface 
+that does not support MII or ETHTOOL status reporting, a failure of its link 
+will not be detected! A message indicating MII and ETHTOOL is not supported by 
+a network driver is logged when the bonding driver is loaded with a non-zero 
+miimon value.
+
+The bonding driver can regularly check all its slaves links using the ETHTOOL
+IOCTL (ETHTOOL_GLINK command) or by checking the MII status registers. The 
+check interval is specified by the module argument "miimon" (MII monitoring). 
+It takes an integer that represents the checking time in milliseconds. It 
+should not come to close to (1000/HZ) (10 milli-seconds on i386) because it 
+may then reduce the system interactivity. A value of 100 seems to be a good 
+starting point. It means that a dead link will be detected at most 100 
+milli-seconds after it goes down.
 
 Example:
 
    # modprobe bonding miimon=100
 
-Or, put in your /etc/modules.conf :
+Or, put the following lines in /etc/modules.conf:
 
    alias bond0 bonding
    options bond0 miimon=100
 
-There are currently two policies for high availability, depending on whether
-a) hosts are connected to a single host or switch that support trunking
-b) hosts are connected to several different switches or a single switch that
-   does not support trunking.
+There are currently two policies for high availability. They are dependent on 
+whether:
+
+   a) hosts are connected to a single host or switch that support trunking
+
+   b) hosts are connected to several different switches or a single switch that
+      does not support trunking
 
-1) HA on a single switch or host - load balancing
--------------------------------------------------
+
+1) High Availability on a single switch or host - load balancing
+----------------------------------------------------------------
 It is the easiest to set up and to understand. Simply configure the
 remote equipment (host or switch) to aggregate traffic over several
 ports (Trunk, EtherChannel, etc.) and configure the bonding interfaces.
@@ -356,7 +565,7 @@
 long time if all ports in a trunk go down. This is not Linux, but really
 the switch (reboot it to ensure).
 
-Example 1 : host to host at double speed
+Example 1 : host to host at twice the speed
 
           +----------+                          +----------+
           |          |eth0                  eth0|          |
@@ -370,7 +579,7 @@
      # ifconfig bond0 addr
      # ifenslave bond0 eth0 eth1
 
-Example 2 : host to switch at double speed
+Example 2 : host to switch at twice the speed
 
           +----------+                          +----------+
           |          |eth0                 port1|          |
@@ -384,7 +593,9 @@
      # ifconfig bond0 addr                     and port2
      # ifenslave bond0 eth0 eth1
 
-2) HA on two or more switches (or a single switch without trunking support)
+
+2) High Availability on two or more switches (or a single switch without 
+   trunking support)
 ---------------------------------------------------------------------------
 This mode is more problematic because it relies on the fact that there
 are multiple ports and the host's MAC address should be visible on one
@@ -423,14 +634,14 @@
                +--------------+ host2 +----------------+
                          eth0 +-------+ eth1
 
-In this configuration, there are an ISL - Inter Switch Link (could be a trunk),
+In this configuration, there is an ISL - Inter Switch Link (could be a trunk),
 several servers (host1, host2 ...) attached to both switches each, and one or
 more ports to the outside world (port3...). One an only one slave on each host
 is active at a time, while all links are still monitored (the system can
 detect a failure of active and backup links).
 
 Each time a host changes its active interface, it sticks to the new one until
-it goes down. In this example, the hosts are not too much affected by the
+it goes down. In this example, the hosts are negligibly affected by the
 expiration time of the switches' forwarding tables.
 
 If host1 and host2 have the same functionality and are used in load balancing
@@ -460,6 +671,7 @@
 it goes down. In this example, the host is strongly affected by the expiration
 time of the switch forwarding table.
 
+
 3) Adapting to your switches' timing
 ------------------------------------
 If your switches take a long time to go into backup mode, it may be
@@ -488,8 +700,34 @@
     # modprobe bonding miimon=100 mode=1 downdelay=2000 updelay=5000
     # modprobe bonding miimon=100 mode=0 downdelay=0 updelay=5000
 
-4) Limitations
---------------
+
+Promiscuous Sniffing notes
+==========================
+
+If you wish to bond channels together for a network sniffing
+application --- you wish to run tcpdump, or ethereal, or an IDS like
+snort, with its input aggregated from multiple interfaces using the
+bonding driver --- then you need to handle the Promiscuous interface
+setting by hand. Specifically, when you "ifconfing bond0 up" you
+must add the promisc flag there; it will be propagated down to the
+slave interfaces at ifenslave time; a full example might look like:
+
+   grep bond0 /etc/modules.conf || echo alias bond0 bonding >/etc/modules.conf
+   ifconfig bond0 promisc up
+   for if in eth1 eth2 ...;do
+       ifconfig $if up
+       ifenslave bond0 $if
+   done
+   snort ... -i bond0 ...
+
+Ifenslave also wants to propagate addresses from interface to
+interface, appropriately for its design functions in HA and channel
+capacity aggregating; but it works fine for unnumbered interfaces;
+just ignore all the warnings it emits.
+
+
+Limitations
+===========
 The main limitations are :
   - only the link status is monitored. If the switch on the other side is
     partially down (e.g. doesn't forward anymore, but the link is OK), the link
@@ -500,7 +738,13 @@
     Use the arp_interval/arp_ip_target parameters to count incoming/outgoing
     frames.  
 
-Resources and links
+  - A Transmit Load Balancing policy is not currently available. This mode 
+    allows every slave in the bond to transmit while only one receives. If 
+    the "receiving" slave fails, another slave takes over the MAC address of 
+    the failed receiving slave.
+
+
+Resources and Links
 ===================
 
 Current development on this driver is posted to:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/networking/generic-hdlc.txt linux-2.4.21-pre6/Documentation/networking/generic-hdlc.txt
--- linux-2.4.20/Documentation/networking/generic-hdlc.txt	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/networking/generic-hdlc.txt	2003-03-26 23:49:55.000000000 +0000
@@ -0,0 +1,115 @@
+Generic HDLC layer for Linux kernel 2.4/2.5
+Krzysztof Halasa <khc@pm.waw.pl>
+May, 2001
+
+
+Generic HDLC layer currently supports:
+- Frame Relay (ANSI, CCITT and no LMI), with ARP support (no InARP),
+- raw HDLC (IPv4 only),
+- Cisco HDLC,
+- PPP (uses syncppp.c),
+- X.25 (uses X.25 routines).
+
+There are hardware drivers for the following cards:
+- C101 by Moxa Technologies Co., Ltd.
+- RISCom/N2 by SDL Communications Inc.
+- and others, some not in the official kernel.
+
+Make sure the hdlc.o and the hardware driver are loaded. It should
+create a number of "hdlc" (hdlc0 etc) network devices, one for each
+WAN port. You'll need the "sethdlc" utility, get it from:
+	http://hq.pm.waw.pl/hdlc/
+
+Compile sethdlc.c utility:
+	gcc -O2 -Wall -o sethdlc sethdlc.c
+Make sure you're using a correct version of sethdlc for your kernel.
+
+Use sethdlc to set physical interface, clock rate, HDLC mode used,
+and add any required PVCs if using Frame Relay.
+Usually you want something like:
+
+	sethdlc hdlc0 clock int rate 128000
+	sethdlc hdlc0 cisco interval 10 timeout 25
+or
+	sethdlc hdlc0 rs232 clock ext
+	sethdlc fr lmi ansi
+	sethdlc create 99
+
+In Frame Relay mode, ifconfig master hdlc device up (without assigning
+any IP address to it) before using pvc devices.
+
+
+Setting interface:
+
+* v35 | rs232 | x21 | t1 | e1 - sets physical interface for a given port
+                                if the card has software-selectable interfaces
+  loopback - activate hardware loopback (for testing only)
+* clock ext - external clock (uses DTE RX and TX clock)
+* clock int - internal clock (provides clock signal on DCE clock output)
+* clock txint - TX internal, RX external (provides TX clock on DCE output)
+* clock txfromrx - TX clock derived from RX clock (TX clock on DCE output)
+* rate - sets clock rate in bps (not required for external clock or
+                                 for txfromrx)
+
+Setting protocol:
+
+* hdlc - sets raw HDLC (IP-only) mode
+  nrz / nrzi / fm-mark / fm-space / manchester - sets transmission code
+  no-parity / crc16 / crc16-pr0 (CRC16 with preset zeros) / crc32-itu
+  crc16-itu (CRC16 with ITU-T polynomial) / crc16-itu-pr0 - sets parity
+
+* cisco - sets Cisco HDLC mode (IP, IPv6 and IPX supported)
+  interval - time in seconds between keepalive packets
+  timeout - time in seconds after last received keepalive packet before
+            we assume the link is down
+
+* ppp - sets synchronous PPP mode
+
+* x25 - sets X.25 mode
+
+* fr - Frame Relay mode
+  lmi ansi / ccitt / none - LMI (link management) type
+  dce - Frame Relay DCE (network) side LMI instead of default DTE (user).
+  It has nothing to do with clocks!
+  t391 - link integrity verification polling timer (in seconds) - user
+  t392 - polling verification timer (in seconds) - network
+  n391 - full status polling counter - user
+  n392 - error threshold - both user and network
+  n393 - monitored events count - both user and network
+
+* create | delete n - FR only - adds / deletes PVC interface with DLCI #n.
+
+
+
+
+Board-specific issues
+---------------------
+
+n2.o and c101.o need parameters to work (note double quotes):
+
+	insmod n2 hw='"io,irq,ram,ports[:io,irq,...]"'
+example:
+	insmod n2 hw='"0x300,10,0xD0000,01"'
+
+or
+	insmod c101 hw='"irq,ram[:irq,...]"
+example:
+	insmod c101 hw='"9,0xdc000"'
+
+If built into the kernel, these drivers need kernel (command line) parameters:
+	n2=io,irq,ram,ports:...
+or
+	c101=irq,ram:...
+
+
+
+If you have a problem with N2 or C101 card, you can issue the "private"
+command to see port's packet descriptor rings:
+
+	sethdlc hdlc0 private
+
+The hardware driver have to be build with CONFIG_HDLC_DEBUG_RINGS.
+Attaching this info to bug reports would be helpful. Anyway, let me know
+if you have problems using this.
+
+For patches and other info look at http://hq.pm.waw.pl/hdlc/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/networking/ifenslave.c linux-2.4.21-pre6/Documentation/networking/ifenslave.c
--- linux-2.4.20/Documentation/networking/ifenslave.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/networking/ifenslave.c	2003-03-26 23:49:09.000000000 +0000
@@ -41,6 +41,16 @@
  *    - 2002/02/18 Erik Habbinga <erik_habbinga @ hp dot com> :
  *       - ifr2.ifr_flags was not initialized in the hwaddr_notset case,
  *         SIOCGIFFLAGS now called before hwaddr_notset test
+ *
+ *    - 2002/10/31 Tony Cureington <tony.cureington * hp_com> :
+ *       - If the master does not have a hardware address when the first slave
+ *         is enslaved, the master is assigned the hardware address of that 
+ *         slave - there is a comment in bonding.c stating "ifenslave takes 
+ *         care of this now." This corrects the problem of slaves having 
+ *         different hardware addresses in active-backup mode when 
+ *         multiple interfaces are specified on a single ifenslave command
+ *         (ifenslave bond0 eth0 eth1).
+ *
  */
 
 static char *version =
@@ -131,6 +141,7 @@
 	sa_family_t master_family;
 	char **spp, *master_ifname, *slave_ifname;
 	int hwaddr_notset;
+	int master_up;
 
 	while ((c = getopt_long(argc, argv, "acdfrvV?h", longopts, 0)) != EOF)
 		switch (c) {
@@ -300,10 +311,86 @@
 				return 1;
 			}
 
-			if (hwaddr_notset) { /* we do nothing */
+			if (hwaddr_notset) {
+				/* assign the slave hw address to the 
+				 * master since it currently does not 
+				 * have one; otherwise, slaves may
+				 * have different hw addresses in 
+				 * active-backup mode as seen when enslaving 
+				 * using "ifenslave bond0 eth0 eth1" because
+				 * hwaddr_notset is set outside this loop.
+				 * TODO: put this and the "else" portion in
+				 *       a function.
+				 */
+				goterr = 0;
+				master_up = 0;
+				if (if_flags.ifr_flags & IFF_UP) {
+					if_flags.ifr_flags &= ~IFF_UP;
+					if (ioctl(skfd, SIOCSIFFLAGS, 
+							&if_flags) < 0) {
+						goterr = 1;
+						fprintf(stderr, 
+							"Shutting down "
+							"interface %s failed: "
+							"%s\n",
+							master_ifname, 
+							strerror(errno));
+					} else {
+						/* we took the master down, 
+						 * so we must bring it up 
+						 */
+						master_up = 1; 
+					}
+				}
 
-			}
-			else {  /* we'll assign master's hwaddr to this slave */
+				if (!goterr) {
+					/* get the slaves MAC address */
+					strncpy(if_hwaddr.ifr_name, 
+							slave_ifname, IFNAMSIZ);
+					if (ioctl(skfd, SIOCGIFHWADDR, 
+							&if_hwaddr) < 0) {
+						fprintf(stderr, 
+							"Could not get MAC "
+							"address of %s: %s\n",
+							slave_ifname, 
+							strerror(errno));
+						strncpy(if_hwaddr.ifr_name, 
+							master_ifname, 
+							IFNAMSIZ);
+						goterr=1;
+					}
+				}
+
+				if (!goterr) {
+					strncpy(if_hwaddr.ifr_name, 
+						master_ifname, IFNAMSIZ);
+					if (ioctl(skfd, SIOCSIFHWADDR, 
+							&if_hwaddr) < 0) {
+						fprintf(stderr, 
+							"Could not set MAC "
+							"address of %s: %s\n",
+							master_ifname, 
+							strerror(errno));
+						goterr=1;
+					} else {
+						hwaddr_notset = 0;
+					}
+				}
+
+				if (master_up) {
+					if_flags.ifr_flags |= IFF_UP;
+					if (ioctl(skfd, SIOCSIFFLAGS, 
+							&if_flags) < 0) {
+						fprintf(stderr, 
+							"Bringing up interface "
+							"%s failed: %s\n",
+							master_ifname, 
+							strerror(errno));
+					}
+				}
+
+			} else {  
+				/* we'll assign master's hwaddr to this slave */
 				if (ifr2.ifr_flags & IFF_UP) {
 					ifr2.ifr_flags &= ~IFF_UP;
 					if (ioctl(skfd, SIOCSIFFLAGS, &ifr2) < 0) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/networking/ip-sysctl.txt linux-2.4.21-pre6/Documentation/networking/ip-sysctl.txt
--- linux-2.4.20/Documentation/networking/ip-sysctl.txt	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/networking/ip-sysctl.txt	2003-03-26 23:49:34.000000000 +0000
@@ -281,6 +281,14 @@
 	asassination.	
 	Default: 0
 
+tcp_low_latency - BOOLEAN
+	If set, the TCP stack makes decisions that prefer lower
+	latency as opposed to higher throughput.  By default, this
+	option is not set meaning that higher throughput is preferred.
+	An example of an application where this default should be
+	changed would be a Beowulf compute cluster.
+	Default: 0
+
 ip_local_port_range - 2 INTEGERS
 	Defines the local port range that is used by TCP and UDP to
 	choose the local port. The first number is the first, the 
@@ -351,15 +359,26 @@
 	Change the maximum number of multicast groups we can subscribe to.
 	Default: 20
 
-conf/interface/*: 
-conf/all/* is special and changes the settings for all interfaces.
-	Change special settings per interface.
+conf/interface/*  changes special settings per interface (where "interface" is 
+		  the name of your network interface)
+conf/all/*	  is special, changes the settings for all interfaces
+
 
 log_martians - BOOLEAN
 	Log packets with impossible addresses to kernel log.
+	log_martians for the interface will be enabled if at least one of
+	conf/{all,interface}/log_martians is set to TRUE,
+	it will be disabled otherwise
 
 accept_redirects - BOOLEAN
 	Accept ICMP redirect messages.
+	accept_redirects for the interface will be enabled if:
+	- both conf/{all,interface}/accept_redirects are TRUE in the case forwarding
+	  for the interface is enabled
+	or
+	- at least one of conf/{all,interface}/accept_redirects is TRUE in the case
+	  forwarding for the interface is disabled
+	accept_redirects for the interface will be disabled otherwise
 	default TRUE (host)
 		FALSE (router)
 
@@ -369,6 +388,8 @@
 mc_forwarding - BOOLEAN
 	Do multicast routing. The kernel needs to be compiled with CONFIG_MROUTE
 	and a multicast routing daemon is required.
+	conf/all/mc_forwarding must also be set to TRUE to enable multicast routing
+	for the interface
 
 medium_id - INTEGER
 	Integer value used to differentiate the devices by the medium they
@@ -383,30 +404,46 @@
 
 proxy_arp - BOOLEAN
 	Do proxy arp.
+	proxy_arp for the interface will be enabled if at least one of
+	conf/{all,interface}/proxy_arp is set to TRUE,
+	it will be disabled otherwise
 
 shared_media - BOOLEAN
 	Send(router) or accept(host) RFC1620 shared media redirects.
 	Overrides ip_secure_redirects.
+	shared_media for the interface will be enabled if at least one of
+	conf/{all,interface}/shared_media is set to TRUE,
+	it will be disabled otherwise
 	default TRUE
 
 secure_redirects - BOOLEAN
 	Accept ICMP redirect messages only for gateways,
 	listed in default gateway list.
+	secure_redirects for the interface will be enabled if at least one of
+	conf/{all,interface}/secure_redirects is set to TRUE,
+	it will be disabled otherwise
 	default TRUE
 
 send_redirects - BOOLEAN
-	Send redirects, if router. Default: TRUE
+	Send redirects, if router.
+	send_redirects for the interface will be enabled if at least one of
+	conf/{all,interface}/send_redirects is set to TRUE,
+	it will be disabled otherwise
+	Default: TRUE
 
 bootp_relay - BOOLEAN
 	Accept packets with source address 0.b.c.d destined
 	not to this host as local ones. It is supposed, that
 	BOOTP relay daemon will catch and forward such packets.
-
+	conf/all/bootp_relay must also be set to TRUE to enable BOOTP relay
+	for the interface
 	default FALSE
 	Not Implemented Yet.
 
 accept_source_route - BOOLEAN
 	Accept packets with SRR option.
+	conf/all/accept_source_route must also be set to TRUE to accept packets
+	with SRR option on the interface
 	default TRUE (router)
 		FALSE (host)
 
@@ -417,7 +454,10 @@
 	    networks running a slow unreliable protocol (sort of RIP),
 	    or using static routes.
 
-	0 - No source validation. 
+	0 - No source validation.
+
+	conf/all/rp_filter must also be set to TRUE to do source validation
+	on the interface
 
 	Default value is 0. Note that some distributions enable it
 	in startup scripts.
@@ -437,6 +477,10 @@
 	particular interfaces. Only for more complex setups like load-
 	balancing, does this behaviour cause problems.
 
+	arp_filter for the interface will be enabled if at least one of
+	conf/{all,interface}/arp_filter is set to TRUE,
+	it will be disabled otherwise
+
 tag - INTEGER
 	Allows you to write a number, which can be used as required.
 	Default value is 0.
@@ -451,8 +495,8 @@
 Updated by:
 Andi Kleen
 ak@muc.de
-
-
+Nicolas Delon
+delon.nicolas@wanadoo.fr
 
 
 
@@ -462,6 +506,15 @@
 IPv6 has no global variables such as tcp_*.  tcp_* settings under ipv4/ also
 apply to IPv6 [XXX?].
 
+bindv6only - BOOLEAN
+	Default value for IPV6_V6ONLY socket option,
+	which restricts use of the IPv6 socket to IPv6 communication 
+	only.
+		TRUE: disable IPv4-mapped address feature
+		FALSE: enable IPv4-mapped address feature
+
+	Default: FALSE (as specified in RFC2553bis)
+
 conf/default/*:
 	Change the interface-specific default settings.
 
@@ -560,8 +613,14 @@
 	routers are present.
 	Default: 3
 
+icmp/*:
+ratelimit - INTEGER
+	Limit the maximal rates for sending ICMPv6 packets.
+	0 to disable any limiting, otherwise the maximal rate in jiffies(1)
+	Default: 100
+
 IPv6 Update by:
-Pekka Savola
-pekkas@netcore.fi
+Pekka Savola <pekkas@netcore.fi>
+YOSHIFUJI Hideaki / USAGI Project <yoshfuji@linux-ipv6.org>
 
 $Id: ip-sysctl.txt,v 1.19.2.1 2001/12/13 08:59:27 davem Exp $
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/networking/netdevices.txt linux-2.4.21-pre6/Documentation/networking/netdevices.txt
--- linux-2.4.20/Documentation/networking/netdevices.txt	2000-11-09 03:09:49.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/networking/netdevices.txt	2003-03-26 23:49:19.000000000 +0000
@@ -12,31 +12,39 @@
 struct net_device synchronization rules
 =======================================
 dev->open:
-	Locking: Inside rtnl_lock() semaphore.
-	Sleeping: OK
+	Synchronization: rtnl_lock() semaphore.
+	Context: process
 
 dev->stop:
-	Locking: Inside rtnl_lock() semaphore.
-	Sleeping: OK
+	Synchronization: rtnl_lock() semaphore.
+	Context: process
+	Note1: netif_running() is guaranteed false
+	Note2: dev->poll() is guaranteed to be stopped
 
 dev->do_ioctl:
-	Locking: Inside rtnl_lock() semaphore.
-	Sleeping: OK
+	Synchronization: rtnl_lock() semaphore.
+	Context: process
 
 dev->get_stats:
-	Locking: Inside dev_base_lock spinlock.
-	Sleeping: NO
+	Synchronization: dev_base_lock rwlock.
+	Context: nominally process, but don't sleep inside an rwlock
 
 dev->hard_start_xmit:
-	Locking: Inside dev->xmit_lock spinlock.
-	Sleeping: NO
+	Synchronization: dev->xmit_lock spinlock.
+	Context: BHs disabled
+	Notes: netif_queue_stopped() is guaranteed false
 
 dev->tx_timeout:
-	Locking: Inside dev->xmit_lock spinlock.
-	Sleeping: NO
+	Synchronization: dev->xmit_lock spinlock.
+	Context: BHs disabled
+	Notes: netif_queue_stopped() is guaranteed true
 
 dev->set_multicast_list:
-	Locking: Inside dev->xmit_lock spinlock.
-	Sleeping: NO
+	Synchronization: dev->xmit_lock spinlock.
+	Context: BHs disabled
 
+dev->poll:
+	Synchronization: __LINK_STATE_RX_SCHED bit in dev->state.  See
+		dev_close code and comments in net/core/dev.c for more info.
+	Context: softirq
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/networking/pktgen.txt linux-2.4.21-pre6/Documentation/networking/pktgen.txt
--- linux-2.4.20/Documentation/networking/pktgen.txt	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/networking/pktgen.txt	2003-03-26 23:49:54.000000000 +0000
@@ -6,7 +6,7 @@
 3. Edit script to set preferred device and destination IP address.
 3a.  Create more scripts for different interfaces.  Up to thirty-two
      pktgen processes can be configured and run at once by using the
-     32 /proc/net/pg* files.
+     32 /proc/net/pktgen/pg* files.
 4. Run in shell: ". ipg"
 5. After this two commands are defined:
    A. "pg" to start generator and to get results.
@@ -52,7 +52,7 @@
 
 modprobe pktgen
 
-PGDEV=/proc/net/pg/pg0
+PGDEV=/proc/net/pktgen/pg0
 
 function pgset() {
     local result
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/networking/sk98lin.txt linux-2.4.21-pre6/Documentation/networking/sk98lin.txt
--- linux-2.4.20/Documentation/networking/sk98lin.txt	2001-07-02 20:56:40.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/networking/sk98lin.txt	2003-03-26 23:49:50.000000000 +0000
@@ -1,120 +1,158 @@
-(C)Copyright 1999-2001 SysKonnect GmbH.
+(C)Copyright 1999-2002 SysKonnect GmbH.
 All rights reserved
 ===========================================================================
 
-sk98lin.txt created 28-May-2001
+sk98lin.txt created 19-Dec-2002
 
-Readme File for sk98lin v4.06
-SK-NET Gigabit Ethernet PCI driver for LINUX
+Readme File for sk98lin v6.02
+SysKonnect SK-98xx Gigabit Ethernet Adapter family driver for LINUX
 
 This file contains
-(1) OVERVIEW
-(2) REQUIRED FILES
-(3) INSTALLATION
-(4) INCLUSION OF ADAPTER AT SYSTEM START
-(5) DRIVER PARAMETERS
-(6) LARGE FRAME SUPPORT
-(7) TROUBLESHOOTING
-(8) HISTORY
+ 1  Overview
+ 2  Required Files
+ 3  Installation
+    3.1  Driver Installation
+    3.2  Inclusion of adapter at system start
+ 4  Driver Parameters
+    4.1  Per-Port Parameters
+    4.2  Adapter Parameters
+ 5  Large Frame Support
+ 6  VLAN and Link Aggregation Support (IEEE 802.1, 802.1q, 802.3ad)
+ 7  Troubleshooting
+ 8  History
 
 ===========================================================================
 
 
-(1) OVERVIEW
-============
+1  Overview
+===========
 
-The sk98lin driver supports the SysKonnect SK-NET Gigabit Ethernet
-Adapter SK-98xx family on Linux 2.2.x and above.
-It has been tested with Linux on Intel/x86 machines.
-From v3.02 on, the driver is integrated in the linux kernel source.
+The sk98lin driver supports the SysKonnect SK-98xx and SK-95xx family 
+on Linux. It has been tested with Linux on Intel/x86 machines.
 ***
 
 
-(2) REQUIRED FILES
-==================
+2  Required Files
+=================
 
 The linux kernel source.
 No additional files required.
 ***
 
 
-(3) INSTALLATION
-================
+3  Installation
+===============
+
+It is recommended to download the latest version of the driver from the 
+SysKonnect web site www.syskonnect.com. If you have downloaded the latest
+driver, the Linux kernel has to be patched before the driver can be 
+installed. For details on how to patch a Linux kernel, refer to the 
+patch.txt file.
+
+3.1  Driver Installation
+------------------------
 
 The following steps describe the actions that are required to install
 the driver and to start it manually. These steps should be carried
 out for the initial driver setup. Once confirmed to be ok, they can
-be included in the system start which is described in the next
-chapter.
+be included in the system start.
 
-NOTE 1: You must have 'root' access to the system to perform
-        the following tasks.
-NOTE 2:	IMPORTANT: In case of problems, please read the section
-	"Troubleshooting" below.
-
-1) The driver can either be integrated into the kernel or it can
-   be compiled as a module.
-   Select the appropriate option during the kernel configuration.
-   For use as a module, your kernel must have
-   'loadable module support' enabled.
-   For automatic driver start, you also need 'Kernel module loader'
-   enabled.
-   Configure those options, build and install the new kernel. If you
-   choose to use the driver as a module, do "make modules" and
-   "make modules_install".
-   Reboot your system.
-
-2) Load the module manually by entering:
-       modprobe sk98lin
-   If the SysKonnect SK-98xx adapter is installed in your
-   computer and you have a /proc filesystem, running the command
-   'more /proc/net/dev' should produce an output containing a
-   line with the following format:
-       eth0:    0    0 ...
-   which means that your adapter has been found and initialized.
+NOTE 1: To perform the following tasks you need 'root' access.
+
+NOTE 2: In case of problems, please read the section "Troubleshooting" 
+        below.
+
+The driver can either be integrated into the kernel or it can be compiled 
+as a module. Select the appropriate option during the kernel 
+configuration.
+
+Compile/use the driver as a module
+----------------------------------
+To compile the driver, go to the directory /usr/src/linux and
+execute the command "make menuconfig" or "make xconfig" and proceed as 
+follows:
+
+To integrate the driver permanently into the kernel, proceed as follows:
+
+1. Select the menu "Network device support" and then "Ethernet(1000Mbit)"
+2. Mark "SysKonnect SK-98xx and SK-95xx Gigabit Ethernet Adapter
+   family support" with (*) 
+3. Build a new kernel when the configuration of the above options is 
+   finished.
+4. Install the new kernel.
+5. Reboot your system.
+
+To use the driver as a module, proceed as follows:
+
+1. Enable 'loadable module support' in the kernel.
+2. For automatic driver start, enable the 'Kernel module loader'.
+3. Select the menu "Network device support" and then "Ethernet(1000Mbit)"
+4. Mark "SysKonnect SK-98xx and SK-95xx Gigabit Ethernet Adapter
+   family support" with (M)
+5. Execute the command "make modules".
+6. Execute the command "make modules_install".
+   The appropiate modules will be installed.
+7. Reboot your system.
+
+
+Load the module manually
+------------------------
+To load the module manually, proceed as follows:
+
+1. Enter "modprobe sk98lin".
+2. If the SysKonnect SK-98xx adapter is installed in your computer and you
+   have a /proc file system, execute the command:
+   "ls /proc/net/sk98lin/" 
+   This should produce an output containing a line with the following 
+   format:
+   eth0   eth1  ...
+   which indicates that your adapter has been found and initialized.
    
-   NOTE 1: If you have more than one SysKonnect SK-98xx adapter, the
-           adapters will be listed as 'eth0', 'eth1', 'eth2', etc.
-           For each adapter, repeat the steps 3) and 4).
-   NOTE 2: If you have other Ethernet adapters installed,
-           your SysKonnect SK-98xx adapter can be mapped to 'eth1' or
-	   'eth2' ...
-	   The module installation message (in system logfile or
-	   on console, depending on /etc/syslog.conf) prints a line
-	   for each adapter that is found, containing the
-	   corresponding 'ethX'.
+   NOTE 1: If you have more than one SysKonnect SK-98xx adapter installed,
+           the adapters will be listed as 'eth0', 'eth1', 'eth2', etc.
+           For each adapter, repeat steps 3 and 4 below.
+
+   NOTE 2: If you have other Ethernet adapters installed, your SysKonnect
+           SK-98xx adapter will be mapped to the next available number, 
+           e.g. 'eth1'. The mapping is executed automatically.
+           The module installation message (displayed either in a system
+           log file or on the console) prints a line for each adapter 
+           found containing the corresponding 'ethX'.
 
-3) Select an IP address and assign it to the respective adapter by
+3. Select an IP address and assign it to the respective adapter by 
    entering:
-       ifconfig eth0 <ip-address>
-   This causes the adapter to connect to the ethernet. The solitary
-   yellow LED at the adapter is now active, the link status LED of
-   the primary port is on and the link status LED of the secondary
-   port (on dual port adapters) is blinking (only if the laters are
-   connected to a switch or hub).
-   You will also get a status message on the console saying
-   "ethX: network connection up using port Y" and indicating
-   the selected connection parameters.
+   ifconfig eth0 <ip-address>
+   With this command, the adapter is connected to the Ethernet. 
    
+   SK-98xx Gigabit Ethernet Server Adapters: The yellow LED on the adapter 
+   is now active, the link status LED of the primary port is active and 
+   the link status LED of the secondary port (on dual port adapters) is 
+   blinking (if the ports are connected to a switch or hub).
+   SK-98xx V2.0 Gigabit Ethernet Adapters: The link status LED is active.
+   In addition, you will receive a status message on the console stating
+   "ethX: network connection up using port Y" and showing the selected 
+   connection parameters (x stands for the ethernet device number 
+   (0,1,2, etc), y stands for the port name (A or B)).
+
    NOTE: If you are in doubt about IP addresses, ask your network
          administrator for assistance.
+  
+4. Your adapter should now be fully operational.
+   Use 'ping <otherstation>' to verify the connection to other computers 
+   on your network.
+5. To check the adapter configuration view /proc/net/sk98lin/[devicename].
+   For example by executing:	
+   "cat /proc/net/sk98lin/eth0" 
+
+Unload the module
+-----------------
+To stop and unload the driver modules, proceed as follows:
 
-4) Your adapter should now be fully operational.
-   Use 'ping <otherstation>' to verify the connection to other
-   computers on your network.
-   By viewing /proc/net/sk98lin/[devicename], you can check some 
-   information regarding to the adapter configuration.
-
-
-5) The driver module can be stopped and unloaded using the following
-   commands:
-       ifconfig eth0 down
-       rmmod sk98lin
-***
-
+1. Execute the command "ifconfig eth0 down".
+2. Execute the command "rmmod sk98lin".
 
-(4) INCLUSION OF ADAPTER AT SYSTEM START
-========================================
+3.2  Inclusion of adapter at system start
+-----------------------------------------
 
 Since a large number of different Linux distributions are 
 available, we are unable to describe a general installation procedure
@@ -122,41 +160,45 @@
 Because the driver is now integrated in the kernel, installation should
 be easy, using the standard mechanism of your distribution.
 Refer to the distribution's manual for installation of ethernet adapters.
+
 ***
 
+4  Driver Parameters
+====================
 
-(5) DRIVER PARAMETERS
-=====================
+Parameters can be set at the command line after the module has been 
+loaded with the command 'modprobe'.
+In some distributions, the configuration tools are able to pass parameters
+to the driver module.
 
-Parameters can be set at the command line while loading the
-module with 'modprobe'. The configuration tools of some distributions
-can also give parameters to the driver module.
 If you use the kernel module loader, you can set driver parameters
 in the file /etc/modules.conf (or old name: /etc/conf.modules).
-Insert a line of the form:
-
-options sk98lin ...
+To set the driver parameters in this file, proceed as follows:
 
-For "...", use the same syntax as described below for the command
-line paramaters of modprobe.
-You either have to reboot your computer or unload and reload
-the driver to activate the new parameters.
-The syntax of the driver parameters is:
-
-modprobe sk98lin parameter=value1[,value2[,value3...]]
-
-value1 is for the first adapter, value2 for the second one etc.
-All Parameters are case sensitive, so write them exactly as
-shown below.
-
-Sample: Suppose you have two adapters. You want to set AutoNegotiation
-	on Port A of the first adapter to ON and on Port A of the
-	second adapter to OFF.
-	You also want to set DuplexCapabilities on Port A of the first
-	adapter to FULL and on Port A of the second adapter to HALF.
-	You must enter:
+1. Insert a line of the form :
+   options sk98lin ...
+   For "...", the same syntax is required as described for the command
+   line paramaters of modprobe below.
+2. To activate the new parameters, either reboot your computer
+   or 
+   unload and reload the driver.
+   The syntax of the driver parameters is:
+
+ 	modprobe sk98lin parameter=value1[,value2[,value3...]]
+
+   where value1 refers to the first adapter, value2 to the second etc.
+
+NOTE: All parameters are case sensitive. Write them exactly as shown 
+      below.
+
+Example:
+Suppose you have two adapters. You want to set auto-negotiation
+on the first adapter to ON and on the second adapter to OFF.
+You also want to set DuplexCapabilities on the first adapter
+to FULL, and on the second adapter to HALF.
+Then, you must enter:
 
-	modprobe sk98lin AutoNeg_A=On,Off DupCap_A=Full,Half
+ 	modprobe sk98lin AutoNeg=On,Off DupCap=Full,Half
 
 NOTE: The number of adapters that can be configured this way is
       limited in the driver (file skge.c, constant SK_MAX_CARD_PARAM).
@@ -164,221 +206,324 @@
       more adapters, adjust this and recompile.
 
 
-5.1 Per-Port Parameters
------------------------
-Those setting are available for each port on the adapter.
+4.1  Per-Port Parameters
+------------------------
+
+These settings are available for each port on the adapter.
 In the following description, '?' stands for the port for
 which you set the parameter (A or B).
 
-- Auto Negotiation
-  Parameter:	AutoNeg_?
-  Values:	On, Off, Sense
-  Default:	Sense
+Speed
+-----
+Parameter:    Speed_?
+Values:       10, 100, 1000, Auto
+Default:      Auto
+
+This parameter is used to set the speed capabilities. It is only valid 
+for the SK-98xx V2.0 copper adapters.
+Usually, the speed is negotiated between the two ports during link 
+establishment. If this fails, a port can be forced to a specific setting
+with this parameter.
+
+Auto-Negotiation
+----------------
+Parameter:    AutoNeg_?
+Values:       On, Off, Sense
+Default:      On
   
-  The "Sense"-mode finds out automatically whether the link
-  partner supports autonegotiation or not.
+The "Sense"-mode automatically detects whether the link partner supports
+auto-negotiation or not.
 
-- Duplex Capabilities
-  Parameter:	DupCap_?
-  Values:	Half, Full, Both
-  Default:	Both
-
-  This parameters is relevant only if autonegotiation for
-  this port is not "Sense". If autonegotiation is "On", all
-  three values are possible. If it is "Off", only "Full" and
-  "Half" are allowed.
-  It is usefull if your link partner does not support all
-  possible combinations.
-
-- Flow Control
-  Parameter:	FlowCtrl_?
-  Values:	Sym, SymOrRem, LocSend, None
-  Default:	SymOrRem
-
-  This parameter can be used to set the flow control capabilities
-  that the port reports during autonegotiation.
-  The meaning of the different modes is:
--- Sym = Symetric: both link partners are allowed to send PAUSE frames
--- SymOrRem = SymetricOrRemote: both or only remote partner are allowed
-   to send PAUSE frames
--- LocSend = LocalSend: only local link partner is allowed to send
-   PAUSE frames
--- None: no link partner is allowed to send PAUSE frames
+Duplex Capabilities
+-------------------
+Parameter:    DupCap_?
+Values:       Half, Full, Both
+Default:      Both
+
+This parameters is only relevant if auto-negotiation for this port is 
+not set to "Sense". If auto-negotiation is set to "On", all three values
+are possible. If it is set to "Off", only "Full" and "Half" are allowed.
+This parameter is usefull if your link partner does not support all
+possible combinations.
+
+Flow Control
+------------
+Parameter:    FlowCtrl_?
+Values:       Sym, SymOrRem, LocSend, None
+Default:      SymOrRem
+
+This parameter can be used to set the flow control capabilities the 
+port reports during auto-negotiation. It can be set for each port 
+individually.
+Possible modes:
+   -- Sym      = Symetric: both link partners are allowed to send 
+                  PAUSE frames
+   -- SymOrRem = SymetricOrRemote: both or only remote partner 
+                  are allowed to send PAUSE frames
+   -- LocSend  = LocalSend: only local link partner is allowed 
+                  to send PAUSE frames
+   -- None     = no link partner is allowed to send PAUSE frames
   
-  NOTE: This parameter is ignored if autonegotiation is set to "Off".
+NOTE: This parameter is ignored if auto-negotiation is set to "Off".
 
-- Role in Master-Slave-Negotiation (1000Base-T only).
-  Parameter:    Role_?
-  Values:       Auto, Master, Slave
-  Default:      Auto
-  
-  This parameter is only valid for the SK-9821 and SK-9822 adapters.
-  For two 1000Base-T ports to communicate, one must take the role as
-  master (providing timing information), while the other must be slave.
-  Normally, this is negotiated between the two ports during link 
-  establishment. If this should ever fail, you can force a port to a
-  specific setting with this parameter.
-  
+Role in Master-Slave-Negotiation (1000Base-T only)
+--------------------------------------------------
+Parameter:    Role_?
+Values:       Auto, Master, Slave
+Default:      Auto
+
+This parameter is only valid for the SK-9821 and SK-9822 adapters.
+For two 1000Base-T ports to communicate, one must take the role of the
+master (providing timing information), while the other must be the 
+slave. Usually, this is negotiated between the two ports during link 
+establishment. If this fails, a port can be forced to a specific setting
+with this parameter.
 
-5.2 Per-Adapter Parameters
---------------------------
 
-- Preferred Port
-  Parameter:	PrefPort
-  Values:	A, B
-  Default:	A
-
-  This is used to force the preferred port to A or B (on two-port NICs).
-  The preferred port is the one that is used if both are detected as
-  fully functional.
-
-- RLMT (Redundant Link Management Technology) Mode
-  Parameter:	RlmtMode
-  Values:	CheckLinkState,CheckLocalPort, CheckSeg, DualNet
-  Default:	CheckLinkState
-
-  RLMT (the driver part that decides which port to use) knows three
-  ways of checking if a port is available for use:
-
--- CheckLinkState = Check link state only: RLMT uses the link state
-   reported by the adapter hardware for each individual port to determine
-   whether a port can be used for all network traffic or not.
-
--- CheckLocalPort - Check other port on adapter: RLMT sends test frames
-   from each port to each other port and checks if they are received by
-   the other port, respectively. Thus, the ports must be connected to the
-   network such that LLC test frames can be exchanged between them
-   (i.e. there must be no routers between the ports).
-
--- CheckSeg - Check other port and segmentation: RLMT checks the other port
-   and in addition requests information from the Gigabit Ethernet
-   switch next to each port to see if the network is segmented between
-   the ports. Thus, this mode is only to be used if you have Gigabit
-   Ethernet switches installed in your network that have been configured
-   to use the Spanning Tree protocol.
-
--- DualNet - Both ports A and B are used as separate devices at the same
-   time. So if you have a dual port adapter, port A will show up as eth0
-   and port B as eth1. Both ports can be used independend with distinct
-   IP addresses.
-   The preferred port setting is not used. Rlmt is turned off.
-   
+4.2  Adapter Parameters
+-----------------------
 
-  NOTE: The modes CheckLocalPort and CheckSeg are meant to operate in
-        configurations where a network path between the ports on one
-        adapter exists. Especially, they are not designed to work where
-        adapters are connected back-to-back.
+Preferred Port
+--------------
+Parameter:    PrefPort
+Values:       A, B
+Default:      A
+
+This is used to force the preferred port to A or B (on dual-port network 
+adapters). The preferred port is the one that is used if both are detected
+as fully functional.
+
+RLMT Mode (Redundant Link Management Technology)
+------------------------------------------------
+Parameter:    RlmtMode
+Values:       CheckLinkState,CheckLocalPort, CheckSeg, DualNet
+Default:      CheckLinkState
+
+RLMT monitors the status of the port. If the link of the active port 
+fails, RLMT switches immediately to the standby link. The virtual link is 
+maintained as long as at least one 'physical' link is up. 
+
+Possible modes:
+
+   -- CheckLinkState - Check link state only: RLMT uses the link state
+      reported by the adapter hardware for each individual port to 
+      determine whether a port can be used for all network traffic or 
+      not.
+
+   -- CheckLocalPort - In this mode, RLMT monitors the network path 
+      between the two ports of an adapter by regularly exchanging packets
+      between them. This mode requires a network configuration in which 
+      the two ports are able to "see" each other (i.e. there must not be 
+      any router between the ports).
+
+   -- CheckSeg - Check local port and segmentation: This mode supports the
+      same functions as the CheckLocalPort mode and additionally checks 
+      network segmentation between the ports. Therefore, this mode is only
+      to be used if Gigabit Ethernet switches are installed on the network
+      that have been configured to use the Spanning Tree protocol. 
+
+   -- DualNet - In this mode, ports A and B are used as separate devices. 
+      If you have a dual port adapter, port A will be configured as eth0 
+      and port B as eth1. Both ports can be used independently with 
+      distinct IP addresses. The preferred port setting is not used. 
+      RLMT is turned off.
+   
+NOTE: RLMT modes CLP and CLPSS are designed to operate in configurations 
+      where a network path between the ports on one adapter exists. 
+      Moreover, they are not designed to work where adapters are connected
+      back-to-back.
 ***
 
 
-(6) LARGE FRAME SUPPORT
-=======================
+5  Large Frame Support
+======================
 
-Large frames (also called jumbo frames) are now supported by the
-driver. This can result in a greatly improved throughput if
-transfering large amounts of data.
-To enable large frames, set the MTU (maximum transfer unit)
-of the interface to the value you wish (up to 9000). The command
-for this is:
-  ifconfig eth0 mtu 9000
+The driver supports large frames (also called jumbo frames). Using large 
+frames can result in an improved throughput if transferring large amounts 
+of data.
+To enable large frames, set the MTU (maximum transfer unit) of the 
+interface to the desired value (up to 9000), execute the following 
+command:
+      ifconfig eth0 mtu 9000
 This will only work if you have two adapters connected back-to-back
-or if you use a switch that supports large frames. When using a
-switch, it should be configured to allow large frames, without
-autonegotiating for them.
-The setting must be done on all adapters that can be reached by
-the large frames. If one adapter is not set to receive large frames,
-it will simply drop them.
+or if you use a switch that supports large frames. When using a switch, 
+it should be configured to allow large frames and auto-negotiation should  
+be set to OFF. The setting must be configured on all adapters that can be 
+reached by the large frames. If one adapter is not set to receive large 
+frames, it will simply drop them.
+
+You can switch back to the standard ethernet frame size by executing the 
+following command:
+      ifconfig eth0 mtu 1500
 
-You can switch back to the standard ethernet frame size with:
-  ifconfig eth0 mtu 1500
-
-To make this setting persitent, add a script with the 'ifconfig'
-line to the system startup sequence (named something like "S99sk98lin"
+To permanently configure this setting, add a script with the 'ifconfig' 
+line to the system startup sequence (named something like "S99sk98lin" 
 in /etc/rc.d/rc2.d).
 ***
 
 
-(7) TROUBLESHOOTING
-===================
+6  VLAN and Link Aggregation Support (IEEE 802.1, 802.1q, 802.3ad)
+==================================================================
+
+The SysKonnect Linux drivers are able to support VLAN and Link Aggregation
+according to IEEE standards 802.1, 802.1q, and 802.3ad. These features are
+only available after installation of open source modules available on the 
+Internet:
+For VLAN go to: http://scry.wanfear.com/~greear/vlan.html
+For Link Aggregation go to: http://www.st.rim.or.jp/~yumo
+
+NOTE: SysKonnect GmbH does not offer any support for these open source 
+      modules and does not take the responsibility for any kind of 
+      failures or problems arising in connection with these modules.
+
+NOTE: Configuring Link Aggregation on a SysKonnect dual link adapter may 
+      cause problems when unloading the driver.
+
+
+7  Troubleshooting
+==================
+
+If any problems occur during the installation process, check the 
+following list:
 
-If you run into problems during installation, check those items:
 
 Problem:  The SK-98xx adapter can not be found by the driver.
-Reason:   Look in /proc/pci for the following entry:
+Solution: In /proc/pci search for the following entry:
              'Ethernet controller: SysKonnect SK-98xx ...'
-	  If this entry exists, then the SK-98xx adapter has been
-	  found by the system and should be able to be used.
-	  If this entry does not exist or if the file '/proc/pci'
-	  is not there, then you may have a hardware problem or PCI
-	  support may not be enabled in your kernel.
-	  The adapter can be checked using the diagnostic program
-	  which is available from the SysKonnect web site:
-	      www.syskonnect.de
-	  Some COMPAQ machines have a problem with PCI under
-	  Linux. This is described in the 'PCI howto' document
-	  (included in some distributions or available from the
-	  www, e.g. at 'www.linux.org'). This might be fixed in the
-	  2.2.x kernel series (I've not tested it).
-
-Problem:  Programs such as 'ifconfig' or 'route' can not be found or
-          you get an error message 'Operation not permitted'.
-Reason:   You are not logged in as user 'root'. Logout and 
-          login as root or change to root via 'su'.
-
-Problem:  Using the command 'ping <address>', you get a message
-          "ping: sendto: Network is unreachable".
-Reason:   Your route is not set up correct.
-	  If you are using RedHat, you probably forgot
-	  to set up the route in 'network configuration'.
-	  Check the existing routes with the 'route' command
-	  and check if there is an entry for 'eth0' and if
-	  it is correct.
-
-Problem:  The driver can be started, the adapter is connected
-          to the network, but you can not receive or transmit
-          any packet; e.g. 'ping' does not work.
-Reason:   You have an incorrect route in your routing table.
-          Check the routing table with the command 'route' and
-	  read the manual pages about route ('man route').
-NOTE:	  Although the 2.2.x kernel versions generate the routing
-	  entry automatically, you may have problems of this kind
-	  here, too. We found a case where the driver started correct
-	  at system boot, but after removing and reloading the driver,
-	  the route of the adapter's network pointed to the 'dummy0'
-	  device and had to be corrected manually.
-	  
-Problem:  You want to use your computer as a router between
-          multiple IP subnetworks (using multiple adapters), but
-	  you can not reach computers in other subnetworks.
-Reason:   Either the router's kernel is not configured for IP
-	  forwarding or there is a problem with the routing table
-	  and gateway configuration in at least one of the
-	  computers.
-
-Problem:  At the start of the driver, you get an error message:
-	  "eth0: -- ERROR --
-	   Class: internal Software error
-	   Nr: 0xcc
-	   Msg: SkGeInitPort() cannot init running ports"
-Reason:	  You are using a driver compiled for single processor
-	  machines on an multiprocessor machine with SMP (Symetric
-	  MultiProcessor) kernel.
-	  Configure your kernel appropriate and recompile the kernel or
-	  the modules.
+          If this entry exists, the SK-98xx or SK-98xx V2.0 adapter has 
+          been found by the system and should be operational.
+          If this entry does not exist or if the file '/proc/pci' is not 
+          found, there may be a hardware problem or the PCI support may 
+          not be enabled in your kernel.
+          The adapter can be checked using the diagnostics program which 
+          is available on the SysKonnect web site:
+          www.syskonnect.com
+          
+          Some COMPAQ machines have problems dealing with PCI under Linux.
+          Linux. This problem is described in the 'PCI howto' document
+          (included in some distributions or available from the
+          web, e.g. at 'www.linux.org'). 
+
+
+Problem:  Programs such as 'ifconfig' or 'route' can not be found or the 
+          error message 'Operation not permitted' is displayed.
+Reason:   You are not logged in as user 'root'.
+Solution: Logout and login as 'root' or change to 'root' via 'su'.
+
+
+Problem:  Upon use of the command 'ping <address>' the message
+          "ping: sendto: Network is unreachable" is displayed.
+Reason:   Your route is not set correctly.
+Solution: If you are using RedHat, you probably forgot to set up the 
+          route in the 'network configuration'.
+          Check the existing routes with the 'route' command and check 
+          if an entry for 'eth0' exists, and if so, if it is set correctly.
+
+
+Problem:  The driver can be started, the adapter is connected to the 
+          network, but you cannot receive or transmit any packets; 
+          e.g. 'ping' does not work.
+Reason:   There is an incorrect route in your routing table.
+Solution: Check the routing table with the command 'route' and read the 
+          manual help pages dealing with routes (enter 'man route').
+
+NOTE: Although the 2.2.x kernel versions generate the routing entry 
+      automatically, problems of this kind may occur here as well. We've 
+      come across a situation in which the driver started correctly at 
+      system start, but after the driver has been removed and reloaded,
+      the route of the adapter's network pointed to the 'dummy0'device 
+      and had to be corrected manually.
+
+
+Problem:  Your computer should act as a router between multiple 
+          IP subnetworks (using multiple adapters), but computers in 
+          other subnetworks cannot be reached.
+Reason:   Either the router's kernel is not configured for IP forwarding 
+          or the routing table and gateway configuration of at least one 
+          computer is not working.
+
+Problem:  Upon driver start, the following error message is displayed:
+          "eth0: -- ERROR --
+          Class: internal Software error
+          Nr:    0xcc
+          Msg:   SkGeInitPort() cannot init running ports"
+Reason:   You are using a driver compiled for single processor machines 
+          on a multiprocessor machine with SMP (Symetric MultiProcessor) 
+          kernel.
+Solution: Configure your kernel appropriately and recompile the kernel or
+          the modules.
+
+
 
 If your problem is not listed here, please contact SysKonnect's technical
 support for help (linux@syskonnect.de).
-When contacting our technical support, please ensure that the
-following information is available:
+When contacting our technical support, please ensure that the following 
+information is available:
 - System Manufacturer and Model
 - Boards in your system
 - Distribution
 - Kernel version
+- Driver version
 ***
 
+8  History
+==========
 
-(8) HISTORY
-===========
+VERSION 6.00 (In-Kernel version)
+New Features:
+- Support for SK-98xx V2.0 adapters
+- Support for gmac
+- Support for kernel 2.4.x and kernel 2.2.x
+- Zerocopy support for kernel 2.4.x with sendfile()
+- Support for scatter-gather functionality with sendfile()
+- Speed support for SK-98xx V2.0 adapters
+- New ProcFs entries
+- New module parameters
+Problems fixed:
+- ProcFS initialization
+- csum packet error
+- Ierror/crc counter error (#10767)
+- rx_too_long counter error (#10751)
+Known limitations:
+- None
+
+VERSION 4.11
+New Features:
+- none
+Problems fixed:
+- Error statistic counter fix (#10620)
+- RLMT-Fixes (#10659, #10639, #10650)
+- LM80 sensor initialization fix (#10623)
+- SK-CSUM memory fixes (#10610).
+Known limitations:
+- None
+
+VERSION 4.10
+New Features:
+- New ProcFs entries
+Problems fixed:
+- Corrected some printk's
+Known limitations:
+- None
+
+VERSION 4.09
+New Features:
+- IFF_RUNNING support (link status)
+- New ProcFs entries
+Problems fixed:
+- too long counters
+- too short counters
+- Kernel error compilation
+Known limitations:
+- None
+ 
+VERSION 4.06 (In-Kernel version)
+Problems fixed:
+- MTU init problems
+ 
+VERSION 4.04
+Problems fixed:
+- removed VLAN error messages
 
 VERSION 4.02 (In-Kernel version)
 New Features:
@@ -518,3 +663,4 @@
 ***End of Readme File***
 
 
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/sonypi.txt linux-2.4.21-pre6/Documentation/sonypi.txt
--- linux-2.4.20/Documentation/sonypi.txt	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/sonypi.txt	2003-03-26 23:48:58.000000000 +0000
@@ -1,6 +1,7 @@
 Sony Programmable I/O Control Device Driver Readme
 --------------------------------------------------
-	Copyright (C) 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
+	Copyright (C) 2001-2003 Stelian Pop <stelian@popies.net>
+	Copyright (C) 2001-2002 Alcôve <www.alcove.com>
 	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>
@@ -15,14 +16,14 @@
 	- capture button events (only on Vaio Picturebook series)
 	- Fn keys
 	- bluetooth button (only on C1VR model)
-	- back button (PCG-GR7/K model)
-	- lid open/close events (Z600NE model)
+	- programmable keys, back, help, zoom, thumbphrase buttons, etc.
+	  (when available)
 
 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/>
+can be downloaded at: <http://popies.net/sonypi/>
 
 This driver supports also some ioctl commands for setting the LCD screen
 brightness and querying the batteries charge information (some more 
@@ -43,7 +44,7 @@
 to /etc/modules.conf file, when the driver is compiled as a module or by
 adding the following to the kernel command line (in your bootloader):
 
-	sonypi=minor[,verbose[,fnkeyinit[,camera[,compat[,nojogdial]]]]]
+	sonypi=minor[,verbose[,fnkeyinit[,camera[,compat[,mask[,useinput]]]]]]
 
 where:
 
@@ -64,15 +65,42 @@
 			with it and it shouldn't be required anyway if 
 			ACPI is already enabled).
 
-	verbose:	print unknown events from the sonypi device
+	verbose:	set to 1 to print unknown events received from the 
+			sonypi device.
+			set to 2 to print all events received from the 
+			sonypi device.
 
 	compat:		uses some compatibility code for enabling the sonypi
 			events. If the driver worked for you in the past
 			(prior to version 1.5) and does not work anymore,
 			add this option and report to the author.
 
-	nojogdial:	gives more accurate PKEY events on those Vaio models
-			which don't have a jogdial (like the FX series).
+	mask:		event mask telling the driver what events will be
+			reported to the user. This parameter is required for some 
+			Vaio models where the hardware reuses values used in 
+			other Vaio models (like the FX series who does not
+			have a jogdial but reuses the jogdial events for
+			programmable keys events). The default event mask is
+			set to 0xffffffff, meaning that all possible events will be
+			tried. You can use the following bits to construct
+			your own event mask (from drivers/char/sonypi.h):
+				SONYPI_JOGGER_MASK 		0x0001
+				SONYPI_CAPTURE_MASK 		0x0002
+				SONYPI_FNKEY_MASK 		0x0004
+				SONYPI_BLUETOOTH_MASK 		0x0008
+				SONYPI_PKEY_MASK 		0x0010
+				SONYPI_BACK_MASK 		0x0020
+				SONYPI_HELP_MASK 		0x0040
+				SONYPI_LID_MASK 		0x0080
+				SONYPI_ZOOM_MASK 		0x0100
+				SONYPI_THUMBPHRASE_MASK 	0x0200
+				SONYPI_MEYE_MASK		0x0400
+				SONYPI_MEMORYSTICK_MASK		0x0800
+
+	useinput:	if set (which is the default) jogdial events are
+			forwarded to the input subsystem as mouse wheel
+			events.
+			
 
 Module use:
 -----------
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/tipar.txt linux-2.4.21-pre6/Documentation/tipar.txt
--- linux-2.4.20/Documentation/tipar.txt	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/tipar.txt	2003-03-26 23:49:19.000000000 +0000
@@ -0,0 +1,93 @@
+
+		Parallel link cable for Texas Instruments handhelds
+		===================================================
+
+
+Author: Romain Lievin
+Homepage: http://lpg.ticalc.org/prj_tidev
+
+
+INTRODUCTION:
+
+This is a driver for the very common home-made parallel link cable, a cable 
+designed for connecting TI8x/9x graphing calculators (handhelds) to a computer
+or workstation (Alpha, Sparc). Given that driver is built on parport, the 
+parallel port abstraction layer, this driver is independant of the platform.
+
+It can also be used with another device plugged on the same port (such as a
+ZIP drive). I have a 100MB ZIP and both of them work fine !
+
+If you need more information, please visit the 'TI drivers' homepage at the URL
+above.
+
+WHAT YOU NEED:
+
+A TI calculator of course and a program capable to communicate with your 
+calculator.
+TiLP will work for sure (since I am his developer !). yal92 may be able to use
+it by changing tidev for tipar (may require some hacking...).
+
+HOW TO USE IT:
+
+You must have first compiled parport support (CONFIG_PARPORT_DEV): either 
+compiled in your kernel, either as a module. 
+This driver supports the new device hierarchy (devfs).
+
+Next, (as root) from your appropriate modules directory (lib/modules/2.5.XX):
+
+       modprobe parport
+       insmod tipar.o
+
+If it is not already there (it usually is), create the device:
+
+       mknod /dev/tipar0 c 115 0
+       mknod /dev/tipar1 c 115 1
+       mknod /dev/tipar2 c 115 2
+
+You will have to set permissions on this device to allow you to read/write
+from it:
+
+       chmod 666 /dev/tipar?
+       
+Now you are ready to run a linking program such as TiLP. Be sure to configure 
+it properly (RTFM).
+       
+MODULE PARAMETERS:
+
+  You can set these with:  insmod tipar NAME=VALUE
+  There is currently no way to set these on a per-cable basis.
+
+  NAME: timeout
+  TYPE: integer
+  DEFAULT: 15
+  DESC: Timeout value in tenth of seconds. If no data is available once this 
+	time has expired then the driver will return with a timeout error.
+
+  NAME: delay
+  TYPE: integer
+  DEFAULT: 10
+  DESC: Inter-bit delay in micro-seconds. An lower value gives an higher data 
+	rate but makes transmission less reliable.
+
+These parameters can be changed at run time by any program via ioctl(2) calls 
+as listed in ./include/linux/ticable.h
+Rather than write 50 pages describing the ioctl() and so on, it is
+perhaps more useful you look at ticables library (dev_link.c) that demonstrates
+how to use them, and demonstrates the features of the driver. This is
+probably a lot more useful to people interested in writing applications
+that will be using this driver.
+
+QUIRKS/BUGS:
+
+None.
+
+HOW TO CONTACT US:
+
+You can email me at roms@lpg.ticalc.org. Please prefix the subject line
+with "TIPAR: " so that I am certain to notice your message.
+You can also mail JB at jb@jblache.org. He packaged these drivers for Debian.
+
+CREDITS:
+
+The code is based on tidev.c & parport.c.
+The driver has been developed independantly of Texas Instruments.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/usb/auerswald.txt linux-2.4.21-pre6/Documentation/usb/auerswald.txt
--- linux-2.4.20/Documentation/usb/auerswald.txt	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/usb/auerswald.txt	2003-03-26 23:49:39.000000000 +0000
@@ -23,8 +23,15 @@
 	...
 	mknod -m 666 /dev/usb/auer15 c 180 127
 
-Future plans
+ISDN support
 ============
-- Connection to ISDN4LINUX (the hisax interface)
+If you enable CONFIG_USB_AUERISDN, you will get full
+ISDN modem support via the HISAX ISDN4LINUX driver.
+
+Of course, as for every USB-based ISDN adaptor, you
+will have to modify your hotplug scripts to load
+the isdn subsystem and configure the network interfaces.
+Same procedure as for the ST5481 driver.
+
 
 The maintainer of this driver is wolfgang@iksw-muees.de
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/usb/ehci.txt linux-2.4.21-pre6/Documentation/usb/ehci.txt
--- linux-2.4.20/Documentation/usb/ehci.txt	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/usb/ehci.txt	2003-03-26 23:49:55.000000000 +0000
@@ -1,4 +1,4 @@
-26-Apr-2002
+27-Dec-2002
 
 The EHCI driver is used to talk to high speed USB 2.0 devices using
 USB 2.0-capable host controller hardware.  The USB 2.0 standard is
@@ -21,11 +21,15 @@
 
 At this writing, this driver has been seen to work with implementations
 of EHCI from (in alphabetical order):  Intel, NEC, Philips, and VIA.
+Other EHCI implementations are becoming available from other vendors;
+you should expect this driver to work with them too.
 
-At this writing, high speed devices are finally beginning to appear.
-While usb-storage devices have been available for some time (working
+While usb-storage devices have been available since mid-2001 (working
 quite speedily on the 2.4 version of this driver), hubs have only
-very recently become available.
+been available since late 2001, and other kinds of high speed devices
+appear to be on hold until more systems come with USB 2.0 built-in.
+Such new systems have been available since early 2002, and became much
+more typical in the second half of 2002.
 
 Note that USB 2.0 support involves more than just EHCI.  It requires
 other changes to the Linux-USB core APIs, including the hub driver,
@@ -43,26 +47,29 @@
 It's believed to do all the right PCI magic so that I/O works even on
 systems with interesting DMA mapping issues.
 
-At this writing the driver should comfortably handle all control and bulk
-transfers, including requests to USB 1.1 devices through transaction
-translators (TTs) in USB 2.0 hubs.  However, there some situations where
-the hub driver needs to clear TT error state, which it doesn't yet do.
-
-Interrupt transfer support is newly functional and not yet as robust as
-control and bulk traffic.  As yet there is no support for split transaction
-scheduling for interrupt transfers, which means among other things that
-connecting USB 1.1 hubs, keyboards, and mice to USB 2.0 hubs won't work.
-Connect them to USB 1.1 hubs, or to a root hub.
-
-Isochronous (ISO) transfer support is also newly functional.  No production
-high speed devices are available which would need it (though high quality
-webcams are in the works!).  Note that split transaction support for ISO
+Transfer Types
+
+At this writing the driver should comfortably handle all control, bulk,
+and interrupt transfers, including requests to USB 1.1 devices through
+transaction translators (TTs) in USB 2.0 hubs.  But you may find bugs.
+
+High Speed Isochronous (ISO) transfer support is also functional, but
+at this writing no Linux drivers have been using that support.
+
+Full Speed Isochronous transfer support, through transaction translators,
+is not yet available.  Note that split transaction support for ISO
 transfers can't share much code with the code for high speed ISO transfers,
 since EHCI represents these with a different data structure.  So for now,
-most USB audio and video devices have the same restrictions as hubs, mice,
-and keyboards:  don't connect them using high speed USB hubs.
+most USB audio and video devices can't be connected to high speed buses.
+
+Driver Behavior
 
-The EHCI root hub code should hand off USB 1.1 devices to its companion
+Transfers of all types can be queued.  This means that control transfers
+from a driver on one interface (or through usbfs) won't interfere with
+ones from another driver, and that interrupt transfers can use periods
+of one frame without risking data loss due to interrupt processing costs.
+
+The EHCI root hub code hands off USB 1.1 devices to its companion
 controller.  This driver doesn't need to know anything about those
 drivers; a OHCI or UHCI driver that works already doesn't need to change
 just because the EHCI driver is also present.
@@ -70,6 +77,11 @@
 There are some issues with power management; suspend/resume doesn't
 behave quite right at the moment.
 
+Also, some shortcuts have been taken with the scheduling periodic
+transactions (interrupt and isochronous transfers).  These place some
+limits on the number of periodic transactions that can be scheduled,
+and prevent use of polling intervals of less than one frame.
+
 
 USE BY
 
@@ -83,10 +95,10 @@
     # rmmod ehci-hcd
 
 You should also have a driver for a "companion controller", such as
-"ohci-hcd", "usb-ohci", "usb-uhci", or "uhci".  In case of any trouble
-with the EHCI driver, remove its module and then the driver for that
-companion controller will take over (at lower speed) all the devices
-that were previously handled by the EHCI driver.
+"ohci-hcd"  or "uhci-hcd".  In case of any trouble with the EHCI driver,
+remove its module and then the driver for that companion controller will
+take over (at lower speed) all the devices that were previously handled
+by the EHCI driver.
 
 Module parameters (pass to "modprobe") include:
 
@@ -96,9 +108,20 @@
 	is 6, indicating 2^6 = 64 microframes.  This controls how often
 	the EHCI controller can issue interrupts.
 
-The EHCI interrupt handler just acknowledges interrupts and schedules
-a tasklet to handle whatever needs handling.  That keeps latencies low,
-no matter how often interrupts are issued.
+If you're using this driver on a 2.5 kernel, and you've enabled USB
+debugging support, you'll see three files in the "sysfs" directory for
+any EHCI controller:
+
+	"async" dumps the asynchronous schedule, used for control
+		and bulk transfers.  Shows each active qh and the qtds
+		pending, usually one qtd per urb.  (Look at it with
+		usb-storage doing disk I/O; watch the request queues!)
+	"periodic" dumps the periodic schedule, used for interrupt
+		and isochronous transfers.  Doesn't show qtds.
+	"registers" show controller register state, and
+
+The contents of those files can help identify driver problems.
+
 
 Device drivers shouldn't care whether they're running over EHCI or not,
 but they may want to check for "usb_device->speed == USB_SPEED_HIGH".
@@ -107,6 +130,11 @@
 Also, some values in device descriptors (such as polling intervals for
 periodic transfers) use different encodings when operating at high speed.
 
+However, do make a point of testing device drivers through USB 2.0 hubs.
+Those hubs report some failures, such as disconnections, differently when
+transaction translators are in use; some drivers have been seen to behave
+badly when they see different faults than OHCI or UHCI report.
+
 
 PERFORMANCE
 
@@ -122,13 +150,18 @@
 and at most 13 of those fit into one USB 2.0 microframe.  Eight USB 2.0
 microframes fit in a USB 1.1 frame; a microframe is 1 msec/8 = 125 usec.
 
+So more than 50 MByte/sec is available for bulk transfers, when both
+hardware and device driver software allow it.  Periodic transfer modes
+(isochronous and interrupt) allow the larger packet sizes which let you
+approach the quoted 480 MBit/sec transfer rate.
+
 Hardware Performance
 
 At this writing, individual USB 2.0 devices tend to max out at around
 20 MByte/sec transfer rates.  This is of course subject to change;
 and some devices now go faster, while others go slower.
 
-The NEC implementation of EHCI seems to have a hardware bottleneck
+The first NEC implementation of EHCI seems to have a hardware bottleneck
 at around 28 MByte/sec aggregate transfer rate.  While this is clearly
 enough for a single device at 20 MByte/sec, putting three such devices
 onto one bus does not get you 60 MByte/sec.  The issue appears to be
@@ -136,9 +169,11 @@
 so that it's only trying six (or maybe seven) USB transactions each
 microframe rather than thirteen.  (Seems like a reasonable trade off
 for a product that beat all the others to market by over a year!)
+
 It's expected that newer implementations will better this, throwing
 more silicon real estate at the problem so that new motherboard chip
-sets will get closer to that 60 MByte/sec target.
+sets will get closer to that 60 MByte/sec target.  That includes an
+updated implementation from NEC, as well as other vendors' silicon.
 
 There's a minimum latency of one microframe (125 usec) for the host
 to receive interrupts from the EHCI controller indicating completion
@@ -161,10 +196,16 @@
 sequence of 128 KB chunks would waste a lot less.
 
 But rather than depending on such large I/O buffers to make synchronous
-I/O be efficient, it's better to just queue all several (bulk) requests
+I/O be efficient, it's better to just queue up several (bulk) requests
 to the HC, and wait for them all to complete (or be canceled on error).
 Such URB queuing should work with all the USB 1.1 HC drivers too.
 
+In the Linux 2.5 kernels, new usb_sg_*() api calls have been defined; they
+queue all the buffers from a scatterlist.  They also use scatterlist DMA
+mapping (which might apply an IOMMU) and IRQ reduction, all of which will
+help make high speed transfers run as fast as they can.
+
+
 TBD:  Interrupt and ISO transfer performance issues.  Those periodic
 transfers are fully scheduled, so the main issue is likely to be how
 to trigger "high bandwidth" modes.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/usb/ov511.txt linux-2.4.21-pre6/Documentation/usb/ov511.txt
--- linux-2.4.20/Documentation/usb/ov511.txt	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/usb/ov511.txt	2003-03-26 23:49:00.000000000 +0000
@@ -276,6 +276,15 @@
 	might be necessary if your camera has a custom lens assembly. This has
 	no effect with video capture devices.
 
+  NAME: ov518_color
+  TYPE: integer (Boolean)
+  DEFAULT: 0 (off)
+  DESC: Enable OV518 color support. This is off by default since it doesn't
+	work most of the time. If you want to try it, you must also load
+	ov518_decomp with the "nouv=0" parameter. If you get improper colors or
+	diagonal lines through the image, restart your video app and try again.
+	Repeat as necessary.
+
 WORKING FEATURES:
  o Color streaming/capture at most widths and heights that are multiples of 8.
  o RGB24, RGB565, YUV420/YUV420P, YUV422/YUYV, and YUV422P color
@@ -285,6 +294,7 @@
  o /proc status reporting
  o SAA7111A video capture support at 320x240 and 640x480
  o Compression support
+ o SMP compatibility
 
 HOW TO CONTACT ME:
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/usb/scanner-hp-sane.txt linux-2.4.21-pre6/Documentation/usb/scanner-hp-sane.txt
--- linux-2.4.20/Documentation/usb/scanner-hp-sane.txt	2000-05-02 20:49:18.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/usb/scanner-hp-sane.txt	1970-01-01 00:00:00.000000000 +0000
@@ -1,81 +0,0 @@
-Copyright (C) 1999, 2000 David E. Nelson
-
-April 26, 2000
-
-CHANGES
-
-- Amended for Linux-2.3.99-pre6-3
-- Updated for multiple scanner support
-
-INTRODUCTION
-
-This document will hopefully provide enough info on how to get SANE
-working with a Hewlett Packard USB capable scanner using the USB
-interface.  The majority of HP Scanners support the Scanner Control
-Language (SCL) which is both published by HP and supported by SANE.
-The only HP Scanners that I'm aware of that do not support SCL are the
-4200C ,3300C, and the PhotoSmart S20.  All other HP scanners with USB
-interfaces should work (4100C, 5200C, 6200C, and 6300C) as do models
-that are derived from the models above. ie the 6350C which is a 6300C
-with a transparency adaptor included with the scanner at time of
-purchase.  Of course as HP releases new scanners this information may
-change.
-
-
-REQUIREMENTS
-
-In order to get this running you'll need USB support in your kernel in
-addition to USB Scanner support.  Please refer to scanner.txt for
-issues pertaining to Linux USB and USB Scanner support.
-
-An installed version of SANE which is available from
-http://www.mostang.com/sane/.  Testing has been performed using
-version SANE-1.0.1.  For instructions on building and installing SANE,
-refer to the various README files within the SANE distribution.
-
-The latest SANE HP backend is available from http://www.kirchgessner.net.
-At the time of this writing, version 0.83 was available.
-
-
-OK, I'VE INSTALLED SANE. SO WHAT DO I DO NOW?
-
-NOTE: $INSTALL_DIR is the location where SANE is installed.  It may be
-/usr/local, /usr, /opt or somewhere else.  If you don't know, ask your
-system administrator.
-
-1) Make sure that you have the libsane-hp.* libraries under the
-$INSTALL_DIR/lib/sane/ directory.  If you don't, then the HP backend
-was either not compiled or installed properly.
-
-2) Under the directory $INSTALL_DIR/etc/sane.d/ edit the following
-files: dll.conf, hp.conf.
-
-  dll.conf:  Make sure that the 'hp' entry is present and uncommented.
-
-  hp.conf: This should contain two lines:
-
-    /dev/usbscanner
-    option connect-device
-
-NOTE: If you are using multiple scanners, make sure to have the correct
-device, ie /dev/usbscanner0.  See scanner.txt for more info.
-
-3) You should now be able to use SANE (xscanimage or scanimage).
-
-Don't forget to read any relevant man pages regarding the usage of
-SANE.  If you have other entries uncommented in 'dll.conf', you may
-have to specify the device to (x)scanimage.  Again, `man` is your
-friend.  The xscanimage (1) man page has info on how to get 'The Gimp'
-to work with xscanimage.  Note that Gimp support must be compiled into
-SANE for it to work.  If you are dealing with a RedHat system, this
-means that you'll also need to install the gimp-devel rpm package
-prior to compiling SANE.
-
-NOTE: The issues regarding core dumping by (x)scanimage have (or seem
-to be thus far) been resolved with version 0.2+ of the USB scanner
-driver which should be available in linux-2.3.23.  If you notice
-otherwise, please contact me.
-
-David /\/elson
-dnelson@jump.net
-http://www.jump.net/~dnelson
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/usb/scanner.txt linux-2.4.21-pre6/Documentation/usb/scanner.txt
--- linux-2.4.20/Documentation/usb/scanner.txt	2001-12-21 17:41:53.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/usb/scanner.txt	2003-03-26 23:49:55.000000000 +0000
@@ -1,154 +1,114 @@
 Copyright (C) 1999, 2000 David E. Nelson <dnelson@jump.net>
+Updated 2003 by Henning Meier-Geinitz <henning@meier-geinitz.de>
 
-April 26, 2000
-
-CHANGES
-
-- Amended for linux-2.4.12
-- Updated devfs support
-- Amended for linux-2.3.99-pre6-3
-- Appended hp_scan.c to end of this README
-- Removed most references to HP
-- Updated uhci/ohci host controller info
-- Updated support for multiple scanner support
-- Updated supported scanners list
-- Updated usbdevfs info
-- Spellcheck
 
 OVERVIEW
 
-This README addresses issues regarding how to configure the kernel
-to access a USB scanner.  Although the driver was originally conceived
-for USB HP scanners, it's general enough so that it can be used with
-other scanners.  Also, one can now pass the USB Vendor and Product
-ID's using module parameters for unknown scanners.  Refer to the
-document scanner-hp-sane.txt for guidance on how to configure SANE to
-use a USB HP Scanner.
+This README addresses issues regarding how to configure the kernel to access a
+USB scanner.  Although the driver was originally conceived for USB HP
+scanners, it's general enough so that it can be used with most other USB
+scanners.  Also, one can pass the USB Vendor and Product IDs using module
+parameters for unknown scanners.
+
+There are two drivers for SCSI-over-USB scanners: 
+* The "hpusbscsi" module for Hewlett-Packard 53xx series, Hewlett-Packard 7400,
+  Minolta Scan Dual II, Minolta Elite II
+* The "microtek" module for the Microtek Scanmaker X6
+
+In addition to the kernel driver, user-space tools like SANE are necessary to
+actually use the scanner.  SANE ("Scanner Access Now Easy") provides drivers
+for a variety of USB scanners.  See the appropriate SANE man page for details,
+e.g. man sane-usb and man sane-hp (for HP scanners).
+
+NOTE: Just because a product is detected by this driver does not mean that
+applications exist that support the product.  It's in the hopes that this will
+allow developers a means to produce applications that will support the listed
+USB products.
 
 
 ADDITIONAL INFORMATION
 
-http://www.linux-usb.org/
+http://www.linux-usb.org/           (General information, mailing lists, links)
+http://www.mostang.com/sane/        (SANE user-space tools)
+http://www.meier-geinitz.de/kernel/ (USB scanner driver information and patches)
 
 
 REQUIREMENTS
 
-A host with a USB port.  Ideally, either a UHCI (Intel) or OHCI
-(Compaq and others) hardware port should work.  At the time of this
-writing, there are two UHCI drivers and one OHCI.
-
-A Linux kernel with USB support enabled or a backported version to
-linux-2.2.x.  See http://www.linux-usb.org for more information on
-accomplishing this.
-
-'lspci' which is only needed to determine the type of USB hardware
-available/installed in your machine.
-
-CONFIGURATION
-
-Using `lspci -v`, determine the type of USB hardware available/installed.
+A host with a USB port.  Ideally, either a UHCI (Intel), OHCI (Compaq and
+others) or EHCI hardware should work.  
 
-  If you see something like:
+Using "make menuconfig" or your preferred method for configuring the kernel,
+select "Support for USB", "OHCI/UHCI/EHCI" depending on your hardware, "USB
+Scanner support", and "Preliminary USB device filesystem".  Compile and
+install the modules (you may need to execute "depmod -a" to update the module
+dependencies).  If any of the USB sections were compiled into the kernel, a
+reboot is necessary.  NOTE: Updating the boot disk with "lilo" may also be
+required.  Testing was performed only as modules, YMMV.
+
+Up to 16 scanners can be connected/used simultaneously.  If devfs support is
+enabled, see next section.  Otherwise, the device files must be created
+manually if they don't exist yet, either by MAKEDEV or mknod.
+
+MAKEDEV method:
+  cd /dev
+  MAKEDEV usb
+  Check that the device files "/dev/usb/scanner0" - "/dev/usb/scanner15" have
+  been created.
+
+mknod method:
+  mknod /dev/usb/scanner0 c 180 48
+  mknod /dev/usb/scanner1 c 180 49
+                  . 
+                  .
+  mknod /dev/usb/scanner15 c 180 63
 
-    USB Controller: ......
-    Flags: .....
-    I/O ports at ....
-
-  Then you have a UHCI based controller.
-
-  If you see something like:
-
-     USB Controller: .....
-     Flags: ....
-     Memory at .....
-
-  Then you have a OHCI based controller.
-
-Using `make menuconfig` or your preferred method for configuring the
-kernel, select 'Support for USB', 'OHCI/UHCI' depending on your
-hardware (determined from the steps above), 'USB Scanner support', and
-'Preliminary USB device filesystem'.  Compile and install the modules
-(you may need to execute `depmod -a` to update the module
-dependencies). If any of the USB sections were compiled into the
-kernel, a reboot is necessary. NOTE: Updating the boot disk with
-'lilo' may also be required. Testing was performed only as modules,
-YMMV.
-
-Beginning with version 0.4 of the driver, up to 16 scanners can be
-connected/used simultaneously.  For devfs support, see next section.
-If you intend to use more than one scanner at a time w/o devfs support:
-
-   Add a device for the USB scanner:
-	`mknod /dev/usbscanner0 c 180 48`
-	`mknod /dev/usbscanner1 c 180 49`
-                      . 
-                      .
-	`mknod /dev/usbscanner15 c 180 63`
-
-
-If you foresee using only one scanner it is best to:
-	`mknod /dev/usbscanner0 c 180 48`
-	`ln -s /dev/usbscanner0 /dev/usbscanner`
-
-
-Set appropriate permissions for /dev/usbscanner[0-15] (don't forget
+Set appropriate permissions for /dev/usb/scanner[0-15] (don't forget
 about group and world permissions).  Both read and write permissions
-are required for proper operation. For example:
-	`chmod 666 /dev/usbscanner0`
+are required for proper operation.  For example:
+  chmod 666 /dev/usb/scanner0
 
 Load the appropriate modules (if compiled as modules):
 
-  OHCI:
-    modprobe usb-ohci
-    modprobe scanner
-
-  UHCI:
-    modprobe usb-uhci
-    modprobe scanner
+  modprobe usb-ohci (or uhci, usb-uhci, ehci)
+  modprobe scanner
+
 
 DEVFS
 
 The later versions of the Linux kernel (2.4.8'ish) included a dynamic
-device filesystem call 'devfs'.  With devfs, there is no need to
+device filesystem call "devfs".  With devfs, there is no need to
 create the device files as explained above; instead, they are
 dynamically created for you.  For USB Scanner, the device is created
 in /dev/usb/scannerX where X can range from 0 to 15 depending on the
 number of scanners connected to the system.
 
-To see if you have devfs, issue the command `cat /proc/filesytems`.
-If devfs is listed you should be ready to go.  You sould also have a
-process running called 'devfsd'.  In order to make sure, issue the
-command `ps aux | grep '[d]evfsd'`.
-
-If you would like to maintain /dev/usbscanner0 in order to maintain
-compatibility with applications, then add the following to
-/etc/devfsd.conf:
-
-REGISTER ^usb/scanner0$ CFUNCTION GLOBAL symlink usb/scanner0 usbscanner0
-UNREGISTER ^usb/scanner0$ CFUNCTION GLOBAL unlink usbscanner0
+To see if you have devfs, issue the command "cat /proc/filesytems".
+If devfs is listed you should be ready to go.  You should also have a
+process running called "devfsd".  In order to make sure, issue the
+command "ps aux | grep '[d]evfsd'".
 
-Then reset the scanner (reseat the USB connector or power cycle). This
-will create the necessary symlinks in /dev to /dev/usb.
 
 CONCLUSION
 
-That's it.  SANE should now be able to access the device.  
+That's it.  SANE should now be able to access the device.  To make sure the
+device was detected, use "cat /proc/bus/usb/devices".  Your scanner should be
+listed and the line starting with "I:" should look similar to this example:
+
+  I:  If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=usbscanner
+
+The important part is "Driver=usbscanner".  If it reads "Driver=(none)", the
+USB scanner driver didn't recognize the scanner.  Have a look at the MODULE
+PARAMETERS section for what to do in this case.
+
+For more details on the format of "/proc/bus/usb/devices" see
+Documentation/usb/proc_usb_info.txt.
 
-There is a small test program (hp_scan.c -- appended below) that can
-be used to test the scanner device if it's an HP scanner that supports
-SCL (Scanner Control Language).  Known HP scanner that support SCL are
-the 4100, 5200, 6200, the 6300 -- note that the 4200 is *not*
-supported since it does not understand SCL; it's also strongly
-suspected that the 3300 and the PhotoSmart S20 are not SCL compliant.
-Hp_scan.c's purpose is to test the driver without having to
-retrieve/configure SANE.  Hp_scan.c will scan the entire bed and put
-the output into a file called 'out.dat' in the current directory.  The
-data in the file is raw data so it's not very useful for imaging.
 
 MESSAGES
 
 usb_control/bulk_msg: timeout -- On occasions this message will appear
-in '/var/adm/messages', on the console, or both depending on how
+in "/var/adm/messages", on the console, or both depending on how
 your system is configured.  This is a side effect that scanners are
 sometimes very slow at warming up and/or initializing.  In most cases,
 however, only several of these messages should appear and is generally
@@ -165,122 +125,90 @@
 
 probe_scanner: Endpoint determination failed -- This means that the
 driver is unable to detect a supported configuration for means to
-communicate with the scanner.  See also 'probe_scanner: Undetected
-endpoint'.
+communicate with the scanner.  See also "probe_scanner: Undetected
+endpoint".
 
 funky result -- Most of the time the data flow between the computer
 and the scanner goes smoothly.  However, due to whatever reason,
 whether it be solar flares or stray neutrons, sometimes the
 communications don't work as expected.  The driver tries to handle
 most types of errors but not all.  When this message is seen,
-something weird happened.  Please contact the maintaner listed at the
-top of this file.
-
-SUPPORTED SCANNERS
-
-NOTE: Just because a product is listed here does not mean that
-applications exist that support the product.  It's in the hopes that
-this will allow developers a means to produce applications that will
-support the listed USB products.
-
-At the time of this writing, the following scanners were supported by
-scanner.c:
-
- Acer
-	 Prisa Acerscan 620U & 640U (!)
-	 Prisa AcerScan 620U (!)
- Agfa
-	 SnapScan 1212U
-	 Another SnapScan 1212U (?)
-	 SnapScan Touch
- Colorado -- See Primax/Colorado below
- Epson -- See Seiko/Epson below
- Genius
-         ColorPage-Vivid Pro
- Hewlett Packard
-	 3300C
-	 4100C
-	 4200C
-	 PhotoSmart S20
-	 5200C
-	 6200C
-	 6300C
- Microtek
-	 ScanMaker X6 - X6U
-	 Phantom 336CX - C3
-	 Phantom 336CX - C3 #2
-	 Phantom C6
-	 ScanMaker V6USL
-	 ScanMaker V6USL #2
-	 ScanMaker V6UL - SpicyU
- Mustek
-	 1200 CU
- Primax/Colorado
-	 G2-300 #1
-	 G2-600 #1
-	 G2E-300 #1
-	 ReadyScan 636i
-	 G2-300 #2
-	 G2-600 #2
-	 G2E-300 #2
-	 G2E-600
-	 Colorado USB 9600
-	 Colorado USB 19200
-	 Colorado 600u
-	 Colorado 1200u
- Seiko/Epson Corp.
-	 Perfection 636U and 636Photo
-	 Perfection 610
-	 Perfection 1200U and 1200Photo
- Umax
-	 Astra 1220U
-	 Astra 1236U
-	 Astra 2000U
-	 Astra 2200U
- Visioneer
-	 OneTouch 5300
-	 OneTouch 7600 duplicate ID (!)
-	 6100
+something weird happened.  Please contact the mailing list (see
+CONTACT section for details).
 
 
 MODULE PARAMETERS
 
 If you have a device that you wish to experiment with or try using
-this driver with, but the Vendor and Product ID's are not coded in,
+this driver with, but the Vendor and Product IDs are not coded in,
 don't despair.  If the driver was compiled as a module, you can pass
 options to the driver.  Simply add 
 
   options scanner vendor=0x#### product=0x****
 
 to the /etc/modules.conf file replacing the #'s and the *'s with the
-correct ID's.  The ID's can be retrieved from the messages file or
-using `cat /proc/bus/usb/devices`. Note that USB /proc support must be
-enabled during kernel configuration.  If the 'scanner' module is
-already loaded into memory, it must be reloaded for the module
-parameters to take effect.  In essence, `rmmod scanner; modprobe
-scanner` must be performed.
+correct IDs.  The IDs can be retrieved from the messages file or
+using "cat /proc/bus/usb/devices".
 
-**NOTE**: In later kernels (2.3.38+), a new filesystem was introduced,
-usbdevfs.  To mount the filesystem, issue the command (as root):
+If the default timeout is too low, i.e. there are frequent "timeout" messages,
+you may want to increase the timeout manually by using the parameter
+"read_timeout".  The time is given in seconds.  This is an example for
+modules.conf with a timeout of 60 seconds:
+
+  options scanner read_timeout=60
+ 
+If the "scanner" module is already loaded into memory, it must be reloaded for
+the module parameters to take effect.  In essence, "rmmod scanner; modprobe
+scanner" must be performed.
 
-  mount -t usbdevfs /proc/bus/usb /proc/bus/usb
 
-An alternative and more permanent method would be to add
+BUGS
 
-  none  /proc/bus/usb  usbdevfs  defaults  0  0
+Just look at the list of fixes in the source files. 
 
-to /etc/fstab.  This will mount usbdevfs at each reboot.  You can then
-issue `cat /proc/bus/usb/devices` to extract USB device information.
 
+CONTACT
 
-BUGS
+For asking about problems and fixes, use the linux-usb-users mailing list. For
+patches, linux-usb-devel should be used. Information on both lists can be
+found on http://www.linux-usb.org/.
+
+
+CHANGES
+
+- Added information about read_timeout
+- Added more details about /proc/bus/usb/devices
+- Added/updated links
+- Added pointers two "special" scanner drivers
+- Reordering, spell-checking, formatting
+- Used /dev/usb/scanner[0-15] instead of /dev/usbscanner[0-15]
+- Removed some basic USB configuration stuff
+- Added EHCI
+- Removed some more references to HP
+- Amended for linux-2.4.12
+- Updated devfs support
+- Amended for linux-2.3.99-pre6-3
+- Appended hp_scan.c to end of this README
+- Removed most references to HP
+- Updated uhci/ohci host controller info
+- Updated support for multiple scanner support
+- Updated supported scanners list
+- Updated usbdevfs info
+- Spellcheck
 
-Just look at the list of fixes in the source files.  So, if you
-encounter any problems feel free to drop me an email.
 
-David /\/elson
-dnelson@jump.net
-http://www.jump.net/~dnelson
+HP TEST PROGRAM
+
+There is a small test program (hp_scan.c -- appended below) that can
+be used to test the scanner device if it's an HP scanner that supports
+SCL (Scanner Control Language).  Known HP scanner that support SCL are
+the 4100, 5200, 6200, the 6300 -- note that the 4200 is *not*
+supported since it does not understand SCL; it's also strongly
+suspected that the 3300 and the PhotoSmart S20 are not SCL compliant.
+Hp_scan.c's purpose is to test the driver without having to
+retrieve/configure SANE.  Hp_scan.c will scan the entire bed and put
+the output into a file called "out.dat" in the current directory.  The
+data in the file is raw data so it's not very useful for imaging.
 
 --------------- snip -- hp_scan.c -- snip ---------------
 /*
@@ -347,7 +275,7 @@
 		exit (1);
 	}
 	
-	if((fp=open("/dev/usbscanner", O_RDWR)) < 0) {
+	if((fp=open("/dev/usb/scanner0", O_RDWR)) < 0) {
 		perror("Unable to open scanner device");
 		exit (1);
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/usb/usb-serial.txt linux-2.4.21-pre6/Documentation/usb/usb-serial.txt
--- linux-2.4.20/Documentation/usb/usb-serial.txt	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/usb/usb-serial.txt	2003-03-26 23:49:00.000000000 +0000
@@ -95,50 +95,27 @@
   Kroah-Hartman at greg@kroah.com
 
 
-Compaq iPAQ, HP Jornada and Casio EM500 driver
+PocketPC PDA Driver
 
-  This driver can be used to connect to Compaq iPAQ, HP Jornada and Casio EM500
-  PDAs running Windows CE 3.0 or PocketPC 2002 using a USB cable/cradle. It
-  has been tested only on the Compaq H3135, but is rumoured to work on
-  with the H3600 and later models as well as the Jornada 548 and 568.
-  With minor modifications, it may work for other CE based handhelds too.
+  This driver can be used to connect to Compaq iPAQ, HP Jornada, Casio EM500
+  and other PDAs running Windows CE 3.0 or PocketPC 2002 using a USB
+  cable/cradle.
+  Most devices supported by ActiveSync are supported out of the box.
+  For others, please use module parameters to specify the product and vendor
+  id. e.g. modprobe ipaq vendor=0x3f0 product=0x1125
 
   The driver presents a serial interface (usually on /dev/ttyUSB0) over
-  which one may run ppp and establish a TCP/IP link to the iPAQ. Once this
+  which one may run ppp and establish a TCP/IP link to the PDA. Once this
   is done, you can transfer files, backup, download email etc. The most
-  significant advantage of using USB is speed - you can get 73 to 113
-  kbytes/sec for download/upload to the iPAQ.
+  significant advantage of using USB is speed - I can get 73 to 113
+  kbytes/sec for download/upload to my iPAQ.
 
-  The driver works intermittently with the usb-uhci driver but quite
-  reliably with the uhci driver. However, performance is much better
-  with usb-uhci. It does not seem to work with ohci at all.
-
-  You must setup hotplug to invoke pppd as soon as the iPAQ is connected.
-  A ppp script like the one below should be kept in the file
-  /etc/hotplug/usb/ipaq Remember to chmod +x. Make sure there are no
-  options in /etc/ppp/options or ~/.ppprc which conflict with the ones
-  given below.
-
-	#!/bin/bash
-
-	MYIP=linux.box.ip
-	REMOTEIP=ipaq.ip
-	MYDNS=my.dns.server
-	killall -9 pppd
-	/usr/sbin/pppd /dev/ttyUSB0 \
-	connect "/usr/sbin/chat -v TIMEOUT 60 CLIENT 'CLIENTSERVER\c'" \
-	nocrtscts local debug passive $MYIP:$REMOTEIP ms-dns $MYDNS noauth \
-	proxyarp
-
-  You must also download and install asyncd from http://synce.sourceforge.net
-  This is required to emulate keep-alive packets which are exchanged by
-  ActiveSync and the iPAQ.
-
-  On connecting the cable, you should see the usual "Device Connected",
-  "User Authenticated" messages flash by on your iPAQ. Once connected,
-  you can use Win CE programs like ftpView, Pocket Outlook from the iPAQ
-  and xcerdisp, synce utilities from the Linux side. Remember to enable IP
-  forwarding. 
+  This driver is only one of a set of components required to utilize
+  the USB connection. Please visit http://synce.sourceforge.net which
+  contains the necessary packages and a simple step-by-step howto.
+
+  Once connected, you can use Win CE programs like ftpView, Pocket Outlook
+  from the PDA and xcerdisp, synce utilities from the Linux side.
 
   To use Pocket IE, follow the instructions given at
   http://www.tekguru.co.uk/EM500/usbtonet.htm to achieve the same thing
@@ -153,8 +130,18 @@
 
   If it doesn't work for some reason, load both the usbserial and ipaq module
   with the module parameter "debug" set to 1 and examine the system log.
-  You can also try soft-resetting your iPAQ before attempting a connection.
+  You can also try soft-resetting your PDA before attempting a connection.
 
+  Other functionality may be possible depending on your PDA. According to
+  Wes Cilldhaire <billybobjoehenrybob@hotmail.com>, with the Toshiba E570,
+  ...if you boot into the bootloader (hold down the power when hitting the
+  reset button, continuing to hold onto the power until the bootloader screen
+  is displayed), then put it in the cradle with the ipaq driver loaded, open
+  a terminal on /dev/ttyUSB0, it gives you a "USB Reflash" terminal, which can
+  be used to flash the ROM, as well as the microP code..  so much for needing
+  Toshiba's $350 serial cable for flashing!! :D
+  NOTE: This has NOT been tested. Use at your own risk.
+ 
   For any questions or problems with the driver, please contact Ganesh
   Varadarajan <ganesh@veritas.com>
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/video4linux/bttv/CARDLIST linux-2.4.21-pre6/Documentation/video4linux/bttv/CARDLIST
--- linux-2.4.20/Documentation/video4linux/bttv/CARDLIST	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/video4linux/bttv/CARDLIST	2003-03-26 23:49:07.000000000 +0000
@@ -2,7 +2,7 @@
   card=0 -  *** UNKNOWN/GENERIC *** 
   card=1 - MIRO PCTV
   card=2 - Hauppauge (bt848)
-  card=3 - STB
+  card=3 - STB, Gateway P/N 6000699 (bt848)
   card=4 - Intel Create and Share PCI/ Smart Video Recorder III
   card=5 - Diamond DTV2000
   card=6 - AVerMedia TVPhone
@@ -22,24 +22,24 @@
   card=20 - CEI Raffles Card
   card=21 - Lifeview FlyVideo 98/ Lucky Star Image World ConferenceTV LR50
   card=22 - Askey CPH050/ Phoebe Tv Master + FM
-  card=23 - Modular Technology MM205 PCTV, bt878
+  card=23 - Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV, bt878
   card=24 - Askey CPH05X/06X (bt878) [many vendors]
-  card=25 - Terratec Terra TV+ Version 1.0 (Bt848)/Vobis TV-Boostar
+  card=25 - Terratec TerraTV+ Version 1.0 (Bt848)/ Terra TValue Version 1.0/ Vobis TV-Boostar
   card=26 - Hauppauge WinCam newer (bt878)
   card=27 - Lifeview FlyVideo 98/ MAXI TV Video PCI2 LR50
-  card=28 - Terratec TerraTV+
+  card=28 - Terratec TerraTV+ Version 1.1 (bt878)
   card=29 - Imagenation PXC200
   card=30 - Lifeview FlyVideo 98 LR50
   card=31 - Formac iProTV
   card=32 - Intel Create and Share PCI/ Smart Video Recorder III
-  card=33 - Terratec TerraTValue
-  card=34 - Leadtek WinFast 2000
+  card=33 - Terratec TerraTValue Version Bt878
+  card=34 - Leadtek WinFast 2000/ WinFast 2000 XP
   card=35 - Lifeview FlyVideo 98 LR50 / Chronos Video Shuttle II
   card=36 - Lifeview FlyVideo 98FM LR50 / Typhoon TView TV/FM Tuner
   card=37 - Prolink PixelView PlayTV pro
   card=38 - Askey CPH06X TView99
   card=39 - Pinnacle PCTV Studio/Rave
-  card=40 - STB2
+  card=40 - STB TV PCI FM, Gateway P/N 6000704 (bt878), 3Dfx VoodooTV 100
   card=41 - AVerMedia TVPhone 98
   card=42 - ProVideo PV951
   card=43 - Little OnAir TV
@@ -69,7 +69,7 @@
   card=67 - IODATA GV-BCTV4/PCI
   card=68 - 3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA)
   card=69 - Active Imaging AIMMS
-  card=70 - Prolink Pixelview PV-BT878P+ (Rev.4C)
+  card=70 - Prolink Pixelview PV-BT878P+ (Rev.4C,8E)
   card=71 - Lifeview FlyVideo 98EZ (capture only) LR51
   card=72 - Prolink Pixelview PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM)
   card=73 - Sensoray 311
@@ -80,11 +80,28 @@
   card=78 - Jetway TV/Capture JW-TV878-FBK, Kworld KW-TV878RF
   card=79 - DSP Design TCVIDEO
   card=80 - Hauppauge WinTV PVR
+  card=81 - GV-BCTV5/PCI
+  card=82 - Osprey 100/150 (878)
+  card=83 - Osprey 100/150 (848)
+  card=84 - Osprey 101 (848)
+  card=85 - Osprey 101/151
+  card=86 - Osprey 101/151 w/ svid
+  card=87 - Osprey 200/201/250/251
+  card=88 - Osprey 200/250
+  card=89 - Osprey 210/220
+  card=90 - Osprey 500
+  card=91 - Osprey 540
+  card=92 - Osprey 2000
+  card=93 - IDS Eagle
+  card=94 - Pinnacle PCTV Sat
+  card=95 - Formac ProTV II
+  card=96 - MachTV
+  card=97 - Euresys Picolo
 
 tuner.o
   type=0 - Temic PAL (4002 FH5)
   type=1 - Philips PAL_I (FI1246 and compatibles)
-  type=2 - Philips NTSC (FI1236 and compatibles)
+  type=2 - Philips NTSC (FI1236,FM1236 and compatibles)
   type=3 - Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF)
   type=4 - NoTuner
   type=5 - Philips PAL_BG (FI1216 and compatibles)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/video4linux/bttv/Cards linux-2.4.21-pre6/Documentation/video4linux/bttv/Cards
--- linux-2.4.20/Documentation/video4linux/bttv/Cards	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/video4linux/bttv/Cards	2003-03-26 23:49:10.000000000 +0000
@@ -4,25 +4,27 @@
 
 
 Suppported cards:
-
-
 Bt848/Bt848a/Bt849/Bt878/Bt879 cards
 ------------------------------------
 
-All cards with Bt848/Bt848a/Bt849/Bt878/Bt879 and normal Composite/S-VHS inputs
-are supported.
-Teletext and Intercast support (PAL only) for ALL cards via VBI sample decoding
-in software.
+All cards with Bt848/Bt848a/Bt849/Bt878/Bt879 and normal
+Composite/S-VHS inputs are supported.  Teletext and Intercast support
+(PAL only) for ALL cards via VBI sample decoding in software.
+
+Some cards with additional multiplexing of inputs or other additional
+fancy chips are only partially supported (unless specifications by the
+card manufacturer are given).  When a card is listed here it isn't
+necessarily fully supported.
 
-Some cards with additional multiplexing of inputs are only partially 
-supported (unless specifications by the card manufacturer are given).
+All other cards only differ by additional components as tuners, sound
+decoders, EEPROMs, teletext decoders ...
 
-All other cards only differ by additional components as tuners, sound decoders,
-EEPROMs, teletext decoders ...
 
 Unsupported Cards: 
 ------------------
-Cards with Zoran (ZR) or Philips (SAA) or ISA are not supported by this driver. 
+
+Cards with Zoran (ZR) or Philips (SAA) or ISA are not supported by
+this driver.
 
 
 MATRIX Vision
@@ -177,7 +179,8 @@
   has not yet been seen (perhaps it was the german name for LR90 [stereo]).
   These cards are sold by many OEMs too.
 
-  FlyVideo A2 = LR90 Rev.F (w/Remote, w/o FM, stereo TV by tda9821) {Germany}
+  FlyVideo A2 (Elta 8680)= LR90 Rev.F (w/Remote, w/o FM, stereo TV by tda9821) {Germany}
+  Lifeview 3000 (Elta 8681) as sold by Plus(April 2002), Germany = LR138 w/ saa7134
 
 
 Typhoon TV card series:
@@ -197,7 +200,7 @@
   50686 "TV Tuner"                       = KNC1 TV Station
   50687 "TV Tuner stereo"                = KNC1 TV Station pro
   50688 "TV Tuner RDS" (black package)   = KNC1 TV Station RDS
-  50689  TV SAT DVB-S CARD CI PCI (SAA7146AH)
+  50689  TV SAT DVB-S CARD CI PCI (SAA7146AH, SU1278?) = "KNC1 TV Station DVB-S"
   50692 "TV/FM Tuner" (small PCB)
   50694  TV TUNER CARD RDS (PHILIPS CHIPSET SAA7134HL)
   50696  TV TUNER STEREO (PHILIPS CHIPSET SAA7134HL, MK3ME Tuner)
@@ -234,10 +237,20 @@
    PixelView PowerStudio PAK - (Model: PV-M3600 REV 4E)
    PixelView DigitalVCR PAK -  (Model: PV-M2400 REV 4C / 8D / 10A )
 
+   PixelView PlayTV PAK II (TV/FM card + usb camera)  PV-M3800 
+   PixelView PlayTV XP PV-M4700,PV-M4700(w/FM)
+   PixelView PlayTV DVR PV-M4600  package contents:PixelView PlayTV pro, windvr & videoMail s/w
+
    Further Cards:
    PV-BT878P+rev.9B (Play TV Pro, opt. w/FM w/NICAM)
    PV-BT878P+rev.2F
    PV-BT878P Rev.1D (bt878, capture only)
+
+   XCapture PV-CX881P (cx23881)
+   PlayTV HD PV-CX881PL+, PV-CX881PL+(w/FM) (cx23881)
+
+   DTV3000 PV-DTV3000P+ DVB-S CI = Twinhan VP-1030
+   DTV2000 DVB-S = Twinhan VP-1020
    
    Video Conferencing:
    PixelView Meeting PAK - (Model: PV-BT878P)
@@ -245,6 +258,9 @@
    PixelView Meeting PAK plus - (Model: PV-BT878P+rev 4C/8D/10A)
    PixelView Capture - (Model: PV-BT848P)
 
+   PixelView PlayTV USB pro
+   Model No. PV-NT1004+, PV-NT1004+ (w/FM) = NT1004 USB decoder chip + SAA7113 video decoder chip
+
 Dynalink
 --------
    These are CPH series.
@@ -275,6 +291,7 @@
    WinView 601 (Bt848)
    WinView 610 (Zoran)
    WinFast2000
+   WinFast2000 XP
 
 KNC One
 -------
@@ -283,18 +300,37 @@
    TV-Station pro (+TV stereo)
    TV-Station FM (+Radio)
    TV-Station RDS (+RDS)
+   TV Station SAT (analog satellite)
+   TV-Station DVB-S
 
    newer Cards have saa7134, but model name stayed the same?
 
-Provideo PV951 
---------------
-  These are sold as:
+Provideo 
+--------
+  PV951 or PV-951 (also are sold as:
    Boeder TV-FM Video Capture Card
    Titanmedia Supervision TV-2400
    Provideo PV951 TF
    3DeMon PV951
    MediaForte TV-Vision PV951
    Yoko PV951
+   Vivanco Tuner Card PCI Art.-Nr.: 68404
+  ) now named PV-951T
+
+  Surveillance Series
+  PV-141
+  PV-143
+  PV-147
+  PV-148 (capture only)
+  PV-150
+  PV-151
+
+  TV-FM Tuner Series
+  PV-951TDV (tv tuner + 1394)
+  PV-951T/TF
+  PV-951PT/TF
+  PV-956T/TF Low Profile
+  PV-911
 
 Highscreen
 ----------
@@ -324,12 +360,45 @@
 
    PCB      PCI-ID      Model-Name      Eeprom  Tuner  Sound    Country
    --------------------------------------------------------------------
-   M1A8-A      --       AVer TV-Phone           FM1216  --
+   M101.C   ISA !
+   M108-B      Bt848                     --     FR1236		 US   (2),(3)
+   M1A8-A      Bt848    AVer TV-Phone           FM1216  --
    M168-T   1461:0003   AVerTV Studio   48:17   FM1216 TDA9840T  D    (1) w/FM w/Remote
    M168-U   1461:0004   TVCapture98     40:11   FI1216   --      D    w/Remote
    M168II-B 1461:0003   Medion MD9592   48:16   FM1216 TDA9873H  D    w/FM
 
    (1) Daughterboard MB68-A with TDA9820T and TDA9840T
+   (2) Sony NE41S soldered (stereo sound?)
+   (3) Daughterboard M118-A w/ pic 16c54 and 4 MHz quartz
+ 
+   US site has different drivers for (as of 09/2002):
+   EZ Capture/InterCam PCI (BT-848 chip)
+   EZ Capture/InterCam PCI (BT-878 chip)
+   TV-Phone (BT-848 chip)
+   TV98 (BT-848 chip)
+   TV98 With Remote (BT-848 chip)
+   TV98 (BT-878 chip)
+   TV98 With Remote (BT-878)
+   TV/FM98 (BT-878 chip)
+   AVerTV
+   AverTV Stereo
+   AVerTV Studio
+
+   DE hat diverse Treiber fuer diese Modelle (Stand 09/2002):
+   TVPhone (848) mit Philips tuner FR12X6 (w/ FM radio)
+   TVPhone (848) mit Philips tuner FM12X6 (w/ FM radio)
+   TVCapture (848) w/Philips tuner FI12X6
+   TVCapture (848) non-Philips tuner
+   TVCapture98 (Bt878)
+   TVPhone98 (Bt878)
+   AVerTV und TVCapture98 w/VCR (Bt 878)
+   AVerTVStudio und TVPhone98 w/VCR (Bt878)
+   AVerTV GO Serie (Kein SVideo Input)
+   AVerTV98 (BT-878 chip)
+   AVerTV98 mit Fernbedienung (BT-878 chip)
+   AVerTV/FM98 (BT-878 chip)
+
+   VDOmate (www.averm.com.cn) = M168U ?
 
 Aimslab
 -------
@@ -338,22 +407,25 @@
 
 IXMicro (former: IMS=Integrated Micro Solutions)
 -------
-   IXTV BT848
+   IXTV BT848 (=TurboTV)
    IXTV BT878
-   TurboTV (Bt848)
+   IMS TurboTV (Bt848)
 
 Lifetec/Medion/Tevion/Aldi
 --------------------------
    LT9306/MD9306 = CPH061
    LT9415/MD9415 = LR90 Rev.F or Rev.G
           MD9592 = Avermedia TVphone98 (PCI_ID=1461:0003), PCB-Rev=M168II-B (w/TDA9873H)
-          MD9717 = KNC One (Rev D4, saa7134)
+          MD9717 = KNC One (Rev D4, saa7134, FM1216 MK2 tuner)
+          MD5044 = KNC One (Rev D4, saa7134, FM1216ME MK3 tuner)
 
 Modular Technologies (www.modulartech.com) UK
 ---------------------------------------------
    MM100 PCTV (Bt848)
+   MM201 PCTV (Bt878, Bt832) w/ Quartzsight camera
+   MM202 PCTV (Bt878, Bt832, tda9874)
    MM205 PCTV (Bt878)
-   MM210 PCTV (Bt878) (Galaxy TV)
+   MM210 PCTV (Bt878) (Galaxy TV, Galaxymedia ?)
 
 Terratec
 --------
@@ -365,11 +437,13 @@
    Terra TValue Version BT878,    "80-CP2830110-0 TTTV4" printed on the PCB, 
 				     "CPH011-D83" on back
    Terra TValue Version 1.0       "ceb105.PCB" (really identical to Terra TV+ Version 1.0)
+   Terra TValue New Revision	  "LR102 Rec.C"
    Terra Active Radio Upgrade (tea5757h, saa6588t)
 
    LR74 is a newer PCB revision of ceb105 (both incl. connector for Active Radio Upgrade)
 
    Cinergy 400 (saa7134), "E877 11(S)", "PM820092D" printed on PCB
+   Cinergy 600 (saa7134)
 
 Technisat
 ---------
@@ -380,7 +454,7 @@
    Mediafocus I (zr36120/zr36125, drp3510, Sat. analog + ADR Radio)
    Mediafocus II (saa7146, Sat. analog)
          SatADR Rev 2.1 (saa7146a, saa7113h, stv0056a, msp3400c, drp3510a, BSKE3-307A)
-   SkyStar 1 DVB  (AV7110)
+   SkyStar 1 DVB  (AV7110) = Technotrend Premium
    SkyStar 2 DVB  (B2C2) (=Sky2PC)
 
 Siemens
@@ -394,6 +468,9 @@
 Powercolor
 ----------
    MTV878
+       Package comes with different contents:
+       a) pcb "MTV878" (CARD=75)
+       b) Pixelview Rev. 4_
    MTV878R w/Remote Control
    MTV878F w/Remote Control w/FM radio
 
@@ -401,10 +478,15 @@
 --------
    Mirovideo PCTV (Bt848)
    Mirovideo PCTV SE (Bt848)
-   Mirovideo PCTV Pro (Bt848 + Daughterboard)
+   Mirovideo PCTV Pro (Bt848 + Daughterboard for TV Stereo and FM)
+   Studio PCTV Rave (Bt848 Version = Mirovideo PCTV)
    Studio PCTV Rave (Bt878 package w/o infrared)
    Studio PCTV      (Bt878)
    Studio PCTV Pro  (Bt878 stereo w/ FM)
+   Pinnacle PCTV    (Bt878, MT2032)
+   Pinnacle PCTV Pro (Bt878, MT2032)
+   Pinncale PCTV Sat (bt878a, HM1821/1221) ["Conexant CX24110 with CX24108 tuner, aka HM1221/HM1811"]
+   Pinnacle PCTV Sat XE
 
    M(J)PEG capture and playback:
    DC1+ (ISA)
@@ -477,7 +559,7 @@
 ------
    iProTV (Card for iMac Mezzanine slot, Bt848+SCSI)
    ProTV (Bt848)
-   ProTV II = ProTV Stereo (Bt878)
+   ProTV II = ProTV Stereo (Bt878) ["stereo" means FM stereo, tv is still mono]
 
 ATI
 ---
@@ -502,8 +584,10 @@
 
 STB
 ---
-   TV PCI (Temic4032FY5, tda9850??)
-   other variants?
+   STB Gateway 6000704 (bt878)
+   STB Gateway 6000699 (bt848)
+   STB Gateway 6000402 (bt848)
+   STB TV130 PCI
 
 Videologic
 ----------
@@ -514,6 +598,17 @@
 ------------
    TT-SAT PCI (PCB "Sat-PCI Rev.:1.3.1"; zr36125, vpx3225d, stc0056a, Tuner:BSKE6-155A
    TT-DVB-Sat
+    revisions 1.1, 1.3, 1.5, 1.6 and 2.1
+    This card is sold as OEM from:
+	Siemens DVB-s Card
+	Hauppauge WinTV DVB-S
+	Technisat SkyStar 1 DVB
+	Galaxis DVB Sat
+    Now this card is called TT-PCline Premium Family
+   TT-Budget (saa7146, bsru6-701a)
+    This card is sold as OEM from:
+	Hauppauge WinTV Nova
+	Satelco Standard PCI (DVB-S)
    TT-DVB-C PCI
 
 Teles
@@ -549,14 +644,99 @@
    Galaxis DVB Card C CI
    Galaxis DVB Card S
    Galaxis DVB Card C
+   Galaxis plug.in S [neuer Name: Galaxis DVB Card S CI
 
 Hauppauge
 ---------
    many many WinTV models ...
-   WinTV DVBs
-   WinTV NOVA
-   WinTV NOVA-CI
-   WinTV-Nexus-s
+   WinTV DVBs = Technotrend Premium 1.3
+   WinTV NOVA = Technotrend Budget 1.1 "S-DVB DATA"
+   WinTV NOVA-CI "SDVBACI"
+   WinTV Nova USB (=Technotrend USB 1.0)
+   WinTV-Nexus-s (=Technotrend Premium 2.1 or 2.2)
+   WinTV PVR
+   WinTV PVR 250
+   WinTV PVR 450
+
+  US models
+  990 WinTV-PVR-350 (249USD) (iTVC15 chipset + radio)
+  980 WinTV-PVR-250 (149USD) (iTVC15 chipset)
+  880 WinTV-PVR-PCI (199USD) (KFIR chipset + bt878)
+  881 WinTV-PVR-USB
+  190 WinTV-GO
+  191 WinTV-GO-FM
+  404 WinTV
+  401 WinTV-radio
+  495 WinTV-Theater
+  602 WinTV-USB
+  621 WinTV-USB-FM
+  600 USB-Live
+  698 WinTV-HD
+  697 WinTV-D
+  564 WinTV-Nexus-S
+
+  Deutsche Modelle
+  603 WinTV GO
+  719 WinTV Primio-FM
+  718 WinTV PCI-FM
+  497 WinTV Theater
+  569 WinTV USB
+  568 WinTV USB-FM
+  882 WinTV PVR
+  981 WinTV PVR 250
+  891 WinTV-PVR-USB
+  541 WinTV Nova
+  488 WinTV Nova-Ci
+  564 WinTV-Nexus-s
+  727 WinTV-DVB-c
+  545 Common Interface
+  898 WinTV-Nova-USB
+
+  UK models
+  607 WinTV Go
+  693,793 WinTV Primio FM
+  647,747 WinTV PCI FM
+  498 WinTV Theater
+  883 WinTV PVR
+  893 WinTV PVR USB  (Duplicate entry)
+  566 WinTV USB (UK)
+  573 WinTV USB FM
+  429 Impact VCB (bt848)
+  600 USB Live (Video-In 1x Comp, 1xSVHS)
+  542 WinTV Nova
+  717 WinTV DVB-S
+  909 Nova-t PCI
+  893 Nova-t USB   (Duplicate entry)
+  802 MyTV
+  804 MyView
+  809 MyVideo
+  872 MyTV2Go FM
+
+ 
+  546 WinTV Nova-S CI
+  543 WinTV Nova
+  907 Nova-S USB
+  908 Nova-T USB
+  717 WinTV Nexus-S
+  157 DEC3000-s Standalone + USB
+
+  Spain
+  685 WinTV-Go
+  690 WinTV-PrimioFM
+  416 WinTV-PCI Nicam Estereo
+  677 WinTV-PCI-FM
+  699 WinTV-Theater
+  683 WinTV-USB
+  678 WinTV-USB-FM
+  983 WinTV-PVR-250
+  883 WinTV-PVR-PCI
+  993 WinTV-PVR-350
+  893 WinTV-PVR-USB
+  728 WinTV-DVB-C PCI
+  832 MyTV2Go
+  869 MyTV2Go-FM
+  805 MyVideo (USB)
+  
 
 Matrix-Vision
 -------------
@@ -567,6 +747,7 @@
 Conceptronic (.net)
 ------------
    TVCON FM,  TV card w/ FM = CPH05x
+   TVCON = CPH06x
 
 BestData
 --------
@@ -601,11 +782,22 @@
 
 Kworld (www.kworld.com.tw)
 --------------------------
-   KWORLD KW-TV878RF-Pro TV Capture with FM Radio
-   KWORLD KW-TV878R-Pro TV
-   KWORLD KW-TVL878RF  (low profile)
-   KWORLD KW-TV878R TV Capture (No FM Radio)
-   KWORLD KW-TV878RF TV
+  PC TV Station
+   KWORLD KW-TV878R  TV (no radio)
+   KWORLD KW-TV878RF TV (w/ radio)
+
+   KWORLD KW-TVL878RF (low profile)
+
+   KWORLD KW-TV713XRF (saa7134)
+
+
+  MPEG TV Station (same cards as above plus WinDVR Software MPEG en/decoder)
+   KWORLD KW-TV878R -Pro   TV (no Radio)
+   KWORLD KW-TV878RF-Pro   TV (w/ Radio)
+   KWORLD KW-TV878R -Ultra TV (no Radio)
+   KWORLD KW-TV878RF-Ultra TV (w/ Radio)
+
+
 
 JTT/ Justy Corp.http://www.justy.co.jp/ (www.jtt.com.jp website down)
 ---------------------------------------------------------------------
@@ -622,7 +814,7 @@
 
 NoBrand
 -------
-   TV Excel = Australian Name for "PV-BT878P+ 8E" or so
+   TV Excel = Australian Name for "PV-BT878P+ 8E" or "878TV Rev.3_"
 
 Mach www.machspeed.com
 ----
@@ -642,9 +834,13 @@
    HS-878 Mini PCI Capture Add-on Card
    HS-879 Mini PCI 3D Audio and Capture Add-on Card (w/ ES1938 Solo-1)
 
-Satelco
+Satelco www.citycom-gmbh.de, www.satelco.de
 -------
    TV-FM =KNC1 saa7134
+   Standard PCI (DVB-S) = Technotrend Budget
+   Standard PCI (DVB-S) w/ CI
+   Satelco Highend PCI (DVB-S) = Technotrend Premium
+
 
 Sensoray www.sensoray.com
 --------
@@ -661,3 +857,105 @@
    Manufacturer of video cards is listed as:
    Cogent Electronics Industries [CEI]
 
+AITech
+------
+   Wavewatcher TV (ISA)
+   AITech WaveWatcher TV-PCI = can be LR26 (Bt848) or LR50 (BT878)
+   WaveWatcher TVR-202 TV/FM Radio Card (ISA)
+
+MAXRON
+------
+   Maxron MaxTV/FM Radio (KW-TV878-FNT) = Kworld or JW-TV878-FBK
+
+www.ids-imaging.de
+------------------
+   Falcon Series (capture only)
+ In USA: http://www.theimagingsource.com/
+   DFG/LC1	
+
+www.sknet-web.co.jp
+-------------------
+   SKnet Monster TV (saa7134)
+
+A-Max www.amaxhk.com (Colormax, Amax, Napa)
+-------------------
+   APAC Viewcomp 878
+
+Cybertainment
+-------------
+   CyberMail AV Video Email Kit w/ PCI Capture Card (capture only)
+   CyberMail Xtreme
+  These are Flyvideo
+
+VCR (http://www.vcrinc.com/) 
+---
+  Video Catcher 16
+
+Twinhan
+-------
+   DST Card/DST-IP (bt878, twinhan asic) VP-1020
+    Sold as:
+     KWorld DVBS Satellite TV-Card
+     Powercolor DSTV Satellite Tuner Card
+     Prolink Pixelview DTV2000
+     Provideo PV-911 Digital Satellite TV Tuner Card With Common Interface ?
+   DST-CI Card (DVB Satellite) VP-1030
+   DCT Card (DVB cable)
+
+MSI
+---
+    MSI TV@nywhere Tuner Card (MS-8876) (CX23881/883) Not Bt878 compatible.
+    MS-8401 DVB-S
+
+Focus www.focusinfo.com
+-----
+    InVideo PCI (bt878)
+
+Sdisilk www.sdisilk.com/
+-------
+    SDI Silk 100
+    SDI Silk 200 SDI Input Card
+
+www.euresys.com
+    PICOLO series 
+
+PMC/Pace
+www.pacecom.co.uk website closed
+
+Mercury www.kobian.com (UK and FR)
+    LR50
+    LR138RBG-Rx  == LR138
+
+TEC sound (package and manuals don't have any other manufacturer info) TecSound
+    Though educated googling found: www.techmakers.com
+    TV-Mate = Zoltrix VP-8482
+
+Lorenzen www.lorenzen.de
+--------
+     SL DVB-S PCI = Technotrend Budget PCI (su1278 or bsru version)
+
+Origo (.uk) www.origo2000.com
+     PC TV Card = LR50
+
+I/O Magic www.iomagic.com
+---------
+    PC PVR - Desktop TV Personal Video Recorder DR-PCTV100 = Pinnacle ROB2D-51009464 4.0 + Cyberlink PowerVCR II
+
+Arowana
+-------
+    TV-Karte / Poso Power TV (?) = Zoltrix VP-8482 (?)
+
+iTVC15 boards:
+-------------
+kuroutoshikou.com ITVC15
+yuan.com MPG160 PCI TV (Internal PCI MPEG2 encoder card plus TV-tuner)
+
+Asus www.asuscom.com
+   Asus TV Tuner Card 880 NTSC (low profile, cx23880)
+   Asus TV (saa7134)
+
+Hoontech
+--------
+http://www.hoontech.com/korean/download/down_driver_list03.html
+   HART Vision 848 (H-ART Vision 848)
+   HART Vision 878 (H-Art Vision 878)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/video4linux/bttv/Sound-FAQ linux-2.4.21-pre6/Documentation/video4linux/bttv/Sound-FAQ
--- linux-2.4.20/Documentation/video4linux/bttv/Sound-FAQ	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/video4linux/bttv/Sound-FAQ	2003-03-26 23:49:39.000000000 +0000
@@ -79,10 +79,11 @@
 What you have to do is figure out the correct values for gpiomask and
 the audiomux array.  If you have Windows and the drivers four your
 card installed, you might to check out if you can read these registers
-values used by the windows driver.  A tool to do this is available from
-ftp://telepresence.dmem.strath.ac.uk/pub/bt848/winutil, but it does'nt
-work with bt878 boards according to some reports I received.  Another
-one is available from http://www.kki.net.pl/~borgx/bTV.html.
+values used by the windows driver.  A tool to do this is available
+from ftp://telepresence.dmem.strath.ac.uk/pub/bt848/winutil, but it
+does'nt work with bt878 boards according to some reports I received.
+Another one with bt878 suport is available from
+http://btwincap.sourceforge.net/Files/btspy2.00.zip
 
 You might also dig around in the *.ini files of the Windows applications.
 You can have a look at the board to see which of the gpio pins are
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/video4linux/meye.txt linux-2.4.21-pre6/Documentation/video4linux/meye.txt
--- linux-2.4.20/Documentation/video4linux/meye.txt	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/video4linux/meye.txt	2003-03-26 23:49:16.000000000 +0000
@@ -1,6 +1,7 @@
 Vaio Picturebook Motion Eye Camera Driver Readme
 ------------------------------------------------
-	Copyright (C) 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
+	Copyright (C) 2001-2003 Stelian Pop <stelian@popies.net>
+	Copyright (C) 2001-2002 Alcôve <www.alcove.com>
 	Copyright (C) 2000 Andrew Tridgell <tridge@samba.org>
 
 This driver enable the use of video4linux compatible applications with the
@@ -52,7 +53,7 @@
 				or
 			xawtv -c /dev/video0 -geometry 320x240
 
-	motioneye (<http://www.alcove-labs.org/en/software/meye/>)
+	motioneye (<http://popies.net/meye/>)
 		for getting ppm or jpg snapshots, mjpeg video
 
 Private API:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/watchdog-api.txt linux-2.4.21-pre6/Documentation/watchdog-api.txt
--- linux-2.4.20/Documentation/watchdog-api.txt	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/watchdog-api.txt	2003-03-26 23:49:40.000000000 +0000
@@ -278,7 +278,7 @@
 	when the timeout runs out which can be 0 = RESET (default), 
 	1 = SMI, 2 = NMI, 3 = SCI.
 
-	Supports CONFIG_WATCHDOG_NOWAYOUT and the the magic character
+	Supports CONFIG_WATCHDOG_NOWAYOUT and the magic character
 	'V' close handling.
 
 	GETSUPPORT returns WDIOF_KEEPALIVEPING, and the GETSTATUS call
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Documentation/x86_64/mm.txt linux-2.4.21-pre6/Documentation/x86_64/mm.txt
--- linux-2.4.20/Documentation/x86_64/mm.txt	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-pre6/Documentation/x86_64/mm.txt	2003-03-26 23:49:20.000000000 +0000
@@ -2,7 +2,6 @@
 
 o	per process virtual address space limit of 512 Gigabytes
 o	top of userspace stack located at address 0x0000007fffffffff
-o	PAGE_OFFSET = 0xffff800000000000
 o	start of the kernel mapping =  0x0000010000000000
 o	global RAM per system 508*512GB=254 Terabytes
 o	no need of any common code change
@@ -65,6 +64,7 @@
         1    unmapped
         2    __PAGE_OFFSET - start of direct mapping of physical memory
         ...  direct mapping in further slots as needed.
+	509  some io mappings (others are in a memory hole below 4gb)
         510  vmalloc and ioremap space
 	511  kernel code mapping, fixmaps and modules.  
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/MAINTAINERS linux-2.4.21-pre6/MAINTAINERS
--- linux-2.4.20/MAINTAINERS	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-pre6/MAINTAINERS	2003-03-26 23:49:40.000000000 +0000
@@ -90,6 +90,12 @@
 L:	linux-net@vger.kernel.org
 S:	Maintained
 
+3CR990 NETWORK DRIVER
+P:	David Dillow
+M:	dave@thedillows.org
+L:	linux-net@vger.kernel.org
+S:	Maintained
+
 53C700 AND 53C700-66 SCSI DRIVER
 P:	James E.J. Bottomley
 M:	James.Bottomley@HansenPartnership.com
@@ -104,12 +110,12 @@
 
 8139CP 10/100 FAST ETHERNET DRIVER
 P:	Jeff Garzik
-M:	jgarzik@mandrakesoft.com
+M:	jgarzik@pobox.com
 S:	Maintained
 
 8139TOO 10/100 FAST ETHERNET DRIVER
 P:	Jeff Garzik
-M:	jgarzik@mandrakesoft.com
+M:	jgarzik@pobox.com
 W:	http://sourceforge.net/projects/gkernel/
 S:	Maintained
 
@@ -154,6 +160,14 @@
 W:	http://www.ibm.com/linux/ltc/
 S:	Supported
 
+AACRAID SCSI RAID DRIVER
+P:	Adaptec OEM Raid Solutions
+M:	linux-aacraid-devel@dell.com
+L:	linux-aacraid-devel@dell.com
+L:	linux-aacraid-announce@dell.com
+W:	http://domsch.com/linux
+S:	Supported
+
 ACPI
 P:	Andy Grover
 M:	andrew.grover@intel.com
@@ -192,6 +206,13 @@
 L:	linux-scsi@vger.kernel.org
 S:	Maintained
 
+ALTERA EPXA1/EPXA10 DEVELOPMENT BOARD PORT
+P:	Clive Davies
+M:	cdavies@altera.com
+L:	linux-arm-kernel@lists.arm.linux.org.uk
+W:      http://www.arm.linux.org.uk/
+S:	Maintained
+
 APM DRIVER
 P:	Stephen Rothwell
 M:	sfr@canb.auug.org.au
@@ -210,6 +231,13 @@
 M:	linux@treblig.org
 S:	Maintained
 
+ARM/PT DIGITAL BOARD PORT
+P:	Stefan Eletzhofer
+M:	stefan.eletzhofer@eletztrick.de
+L:	linux-arm-kernel@lists.arm.linux.org.uk
+W:	http://www.arm.linux.org.uk/
+S:	Maintained
+
 ARM/SHARK MACHINE SUPPORT
 P:	Alexander Schulz
 M:	alex@shark-linux.de
@@ -229,6 +257,13 @@
 L:	linux-net@vger.kernel.org
 S:	Maintained
 
+ATM
+P:	Chas Williams
+M:	chas@cmf.nrl.navy.mil
+L:	linux-atm-general@lists.sourceforge.net
+W:	http://linux-atm.sourceforge.net
+S:	Maintained
+
 AX.25 NETWORK LAYER
 P:	Matthias Welwarsky
 M:	dg2fef@afthd.tu-darmstadt.de
@@ -245,7 +280,7 @@
 BEFS FILE SYSTEM
 P:	Will Dyson
 M:	will@cs.earlham.edu
-W:	http://cs.earlham.edu/~will/software/linux/kernel/BeFS.html
+W:	http://befs-driver.sourceforge.net/
 S:	Maintained
 
 BERKSHIRE PRODUCTS PC WATCHDOG DRIVER
@@ -279,6 +314,15 @@
 W:	http://www.holtmann.org/linux/bluetooth/
 S:	Maintained
 
+BONDING DRIVER
+P:   Chad Tindel
+M:   ctindel@users.sourceforge.net
+P:   Jay Vosburgh
+M:   fubar@us.ibm.com
+L:   bonding-devel@lists.sourceforge.net
+W:   http://sourceforge.net/projects/bonding/
+S:   Supported
+
 BTTV VIDEO4LINUX DRIVER
 P:	Gerd Knorr
 M:	kraxel@bytesex.org
@@ -286,16 +330,9 @@
 W:	http://bytesex.org/bttv/
 S:	Maintained
 
-BUSLOGIC SCSI DRIVER
-P:	Leonard N. Zubkoff
-M:	Leonard N. Zubkoff <lnz@dandelion.com>
-L:	linux-scsi@vger.kernel.org
-W:	http://www.dandelion.com/Linux/
-S:	Maintained
-
 CIRRUS LOGIC GENERIC FBDEV DRIVER
 P:	Jeff Garzik
-M:	jgarzik@mandrakesoft.com
+M:	jgarzik@pobox.com
 L:	linux-fbdev-devel@lists.sourceforge.net
 S:	Odd Fixes
 
@@ -710,6 +747,13 @@
 W:	http://www.linuxia64.org/
 S:	Maintained
 
+SN-IA64 (Itanium) SUB-PLATFORM
+P:	John Hesterberg
+M:	jh@sgi.com
+L:	linux-ia64@linuxia64.org
+W:	http://www.sgi.com/altix
+S:	Maintained
+
 IBM MCA SCSI SUBSYSTEM DRIVER
 P:	Michael Lang
 M:	langa2@kph.uni-mainz.de
@@ -792,7 +836,7 @@
 
 INTEL I8XX RANDOM NUMBER GENERATOR SUPPORT
 P:	Jeff Garzik
-M:	jgarzik@mandrakesoft.com
+M:	jgarzik@pobox.com
 W:	http://sourceforge.net/projects/gkernel/
 S:	Maintained
 
@@ -1041,6 +1085,12 @@
 L:	linux-kernel@vger.kernel.org
 S:	Maintained
 
+MOTION EYE VAIO PICTUREBOOK CAMERA DRIVER
+P:	Stelian Pop
+M:	stelian@popies.net
+W:	http://popies.net/meye/
+S:	Maintained
+
 MOUSE AND MISC DEVICES [GENERAL]
 P:	Alessandro Rubini
 M:	rubini@ipvvis.unipv.it
@@ -1106,7 +1156,7 @@
 P:	Andrew Morton
 M:	akpm@zip.com.au
 P:	Jeff Garzik
-M:	jgarzik@mandrakesoft.com
+M:	jgarzik@pobox.com
 L:	linux-net@vger.kernel.org
 S:	Maintained
 
@@ -1123,6 +1173,8 @@
 M:	kuznet@ms2.inr.ac.ru
 P:	Pekka Savola (ipv6)
 M:	pekkas@netcore.fi
+P:	James Morris
+M:	jmorris@intercode.com.au
 L:	netdev@oss.sgi.com
 S:	Maintained
 
@@ -1145,6 +1197,14 @@
 W:	http://www.netlab.is.tsukuba.ac.jp/~yokota/izumi/ninja/
 S:	Maintained
 
+NINJA SCSI-32Bi/UDE PCI/CARDBUS SCSI HOST ADAPTER DRIVER
+P:	GOTO Masanori
+M:	gotom@debian.or.jp
+P:	YOKOTA Hiroshi
+M:	yokota@netlab.is.tsukuba.ac.jp
+W:	http://www.netlab.is.tsukuba.ac.jp/~yokota/izumi/ninja/
+S:	Maintained
+
 NON-IDE/NON-SCSI CDROM DRIVERS [GENERAL] (come on, crew - mark your responsibility)
 P:	Eberhard Moenkeberg
 M:	emoenke@gwdg.de
@@ -1160,7 +1220,7 @@
 
 NVIDIA (RIVA) FRAMEBUFFER DRIVER
 P:	Ani Joshi
-M:	ajoshi@shell.unixbox.com
+M:	ajoshi@kernel.crashing.org
 L:	linux-nvidia@lists.surfsouth.com
 S:	Maintained
 
@@ -1277,6 +1337,13 @@
 W:	http://www.realitydiluted.com/projects/nino
 S:	Maintained
 
+PHILIPS NINO PALM PC
+P:	Steven Hill
+M:	sjhill@realitydiluted.com
+L:	linux-mips@oss.sgi.com
+W:	http://www.realitydiluted.com/projects/nino
+S:	Maintained
+
 PNP SUPPORT
 P:	Tom Lees
 M:	tom@lpsg.demon.co.uk
@@ -1316,17 +1383,6 @@
 W:	http://www.pnd-pc.demon.co.uk/promise/
 S:	Maintained
 
-PROMISE PDC202XX IDE CONTROLLER DRIVER
-P:	Hank Yang
-M:	support@promise.com.tw [TAIWAN]
-P:	Jordan Rhody
-M:	support@promise.com [U.S.A]
-P:	Jack Hu
-M:	support-china@promise.com [CHINA]
-W:	http://www.promise.com/support/linux_eng.asp
-W:	http://www.promise.com.tw/support/linux_eng.asp
-S:	Maintained
-
 QNX4 FILESYSTEM
 P:	Anders Larsen
 M:	al@alarsen.net
@@ -1401,7 +1457,7 @@
 SA1100 SUPPORT
 P:	Nicolas Pitre
 M:	nico@cam.org
-L:	sa1100-linux@pa.dec.com
+L:	linux-arm@lists.arm.linux.org.uk
 S:	Maintained
 
 SBPCD CDROM DRIVER
@@ -1439,6 +1495,12 @@
 L:	linux-scsi@vger.kernel.org
 S:	Maintained
 
+SCx200 CPU SUPPORT
+P:	Christer Weinigel
+M:	christer@weinigel.se
+W:	http://www.weinigel.se
+S:	Supported
+
 SGI VISUAL WORKSTATION 320 AND 540
 P:	Bent Hagemark
 M:	bh@sgi.com
@@ -1487,12 +1549,18 @@
 L:	linux-net@vger.kernel.org
 S:	Maintained
 
+SONY VAIO CONTROL DEVICE DRIVER
+P:	Stelian Pop
+M:	stelian@popies.net
+W:	http://popies.net/sonypi/
+S:	Maintained
+
 SOUND
 P:	Alan Cox
 M:	alan@redhat.com
 S:	Maintained for 2.2 only
 
-SPARC:
+UltraSPARC (sparc64):
 P:	David S. Miller
 M:	davem@redhat.com
 P:	Eddie C. Dost
@@ -1505,6 +1573,10 @@
 L:	ultralinux@vger.kernel.org
 S:	Maintained
 
+SPARC (sparc32):
+L:	sparclinux@vger.kernel.org
+S:	Unmaintained - please send patches to mailing list
+
 SPECIALIX IO8+ MULTIPORT SERIAL CARD DRIVER
 P:	Roger Wolff
 M:	R.E.Wolff@BitWizard.nl
@@ -1580,6 +1652,11 @@
 M:      jb@technologeek.org
 S:      Maintained
 
+TI PARALLEL LINK CABLE DRIVER
+P:     Romain Lievin
+M:     roms@lpg.ticalc.org
+S:     Maintained
+
 TIEMAN VOYAGER USB BRAILLE DISPLAY DRIVER
 P:	Stephane Dalton
 M:	sdalton@videotron.ca
@@ -1631,7 +1708,7 @@
 
 TULIP NETWORK DRIVER
 P:	Jeff Garzik
-M:	jgarzik@mandrakesoft.com
+M:	jgarzik@pobox.com
 L:	tulip-users@lists.sourceforge.net
 W:	http://sourceforge.net/projects/tulip/
 S:	Maintained
@@ -1773,6 +1850,14 @@
 L:	linux-usb-devel@lists.sourceforge.net
 S:	Maintained
 
+USB SCANNER DRIVER
+P:	Henning Meier-Geinitz
+M:	henning@meier-geinitz.de
+L:	linux-usb-users@lists.sourceforge.net
+L:	linux-usb-devel@lists.sourceforge.net
+W:	http://www.meier-geinitz.de/kernel/
+S:	Maintained
+
 USB SE401 DRIVER
 P:	Jeroen Vreeken
 M:	pe1rxq@amsat.org
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/Makefile linux-2.4.21-pre6/Makefile
--- linux-2.4.20/Makefile	2002-11-28 23:53:16.000000000 +0000
+++ linux-2.4.21-pre6/Makefile	2003-03-26 23:49:07.000000000 +0000
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
-SUBLEVEL = 20
-EXTRAVERSION =
+SUBLEVEL = 21
+EXTRAVERSION = -pre6
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
@@ -137,8 +137,7 @@
 DRIVERS-y += drivers/char/char.o \
 	drivers/block/block.o \
 	drivers/misc/misc.o \
-	drivers/net/net.o \
-	drivers/media/media.o
+	drivers/net/net.o
 DRIVERS-$(CONFIG_AGP) += drivers/char/agp/agp.o
 DRIVERS-$(CONFIG_DRM_NEW) += drivers/char/drm/drm.o
 DRIVERS-$(CONFIG_DRM_OLD) += drivers/char/drm-4.0/drm.o
@@ -179,6 +178,7 @@
 DRIVERS-$(CONFIG_HAMRADIO) += drivers/net/hamradio/hamradio.o
 DRIVERS-$(CONFIG_TC) += drivers/tc/tc.a
 DRIVERS-$(CONFIG_USB) += drivers/usb/usbdrv.o
+DRIVERS-y +=drivers/media/media.o
 DRIVERS-$(CONFIG_INPUT) += drivers/input/inputdrv.o
 DRIVERS-$(CONFIG_HIL) += drivers/hil/hil.o
 DRIVERS-$(CONFIG_I2O) += drivers/message/i2o/i2o.o
@@ -488,12 +488,13 @@
 	find . -type f -print | sort | xargs sum > .SUMS
 
 dep-files: scripts/mkdep archdep include/linux/version.h
-	scripts/mkdep -- init/*.c > .depend
-	scripts/mkdep -- `find $(FINDHPATH) \( -name SCCS -o -name .svn \) -prune -o -follow -name \*.h ! -name modversions.h -print` > .hdepend
+	rm -f .depend .hdepend
 	$(MAKE) $(patsubst %,_sfdep_%,$(SUBDIRS)) _FASTDEP_ALL_SUB_DIRS="$(SUBDIRS)"
 ifdef CONFIG_MODVERSIONS
 	$(MAKE) update-modverfile
 endif
+	scripts/mkdep -- `find $(FINDHPATH) \( -name SCCS -o -name .svn \) -prune -o -follow -name \*.h ! -name modversions.h -print` > .hdepend
+	scripts/mkdep -- init/*.c > .depend
 
 ifdef CONFIG_MODVERSIONS
 MODVERFILE := $(TOPDIR)/include/linux/modversions.h
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/REPORTING-BUGS linux-2.4.21-pre6/REPORTING-BUGS
--- linux-2.4.20/REPORTING-BUGS	2001-04-06 17:42:48.000000000 +0000
+++ linux-2.4.21-pre6/REPORTING-BUGS	2003-03-26 23:49:39.000000000 +0000
@@ -9,7 +9,7 @@
 bug report. This explains what you should do with the "Oops" information
 to make it useful to the recipient.
 
-      Send the output the maintainer of the kernel area that seems to
+      Send the output to the maintainer of the kernel area that seems to
 be involved with the problem. Don't worry too much about getting the
 wrong person. If you are unsure send it to the person responsible for the
 code relevant to what you were doing. If it occurs repeatably try and
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/config.in linux-2.4.21-pre6/arch/alpha/config.in
--- linux-2.4.20/arch/alpha/config.in	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/config.in	2003-03-26 23:49:18.000000000 +0000
@@ -42,6 +42,7 @@
 	 Eiger			CONFIG_ALPHA_EIGER		\
 	 Jensen			CONFIG_ALPHA_JENSEN		\
 	 LX164			CONFIG_ALPHA_LX164		\
+	 Marvel			CONFIG_ALPHA_MARVEL		\
 	 Miata			CONFIG_ALPHA_MIATA		\
 	 Mikasa			CONFIG_ALPHA_MIKASA		\
 	 Nautilus		CONFIG_ALPHA_NAUTILUS		\
@@ -181,6 +182,12 @@
 	define_bool CONFIG_ALPHA_EV6 y
 	define_bool CONFIG_ALPHA_EV67 y
 fi
+if [ "$CONFIG_ALPHA_MARVEL" = "y" ]
+then
+	define_bool CONFIG_ALPHA_EV6 y
+	define_bool CONFIG_ALPHA_EV67 y
+	define_bool CONFIG_ALPHA_EV7 y
+fi
 if [ "$CONFIG_ALPHA_RAWHIDE" = "y" ]
 then
 	define_bool CONFIG_ALPHA_EV5 y
@@ -208,7 +215,8 @@
 	-o "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_NORITAKE" = "y" \
 	-o "$CONFIG_ALPHA_DP264" = "y" -o "$CONFIG_ALPHA_RAWHIDE" = "y" \
 	-o "$CONFIG_ALPHA_EIGER" = "y" -o "$CONFIG_ALPHA_WILDFIRE" = "y" \
-	-o "$CONFIG_ALPHA_TITAN" = "y" -o "$CONFIG_ALPHA_SHARK" = "y" ]
+	-o "$CONFIG_ALPHA_TITAN" = "y" -o "$CONFIG_ALPHA_SHARK" = "y" \
+	-o "$CONFIG_ALPHA_MARVEL" = "y" ]
 then
 	define_bool CONFIG_ALPHA_SRM y
 fi
@@ -222,6 +230,8 @@
   bool 'Use SRM as bootloader' CONFIG_ALPHA_SRM
 fi
 
+bool 'Verbose Machine Checks' CONFIG_VERBOSE_MCHECK
+
 if [ "$CONFIG_ALPHA_ALCOR" = "y" -o "$CONFIG_ALPHA_MIKASA" = "y" \
 	-o "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_NORITAKE" = "y" \
 	-o "$CONFIG_ALPHA_RAWHIDE" = "y" ]
@@ -240,7 +250,7 @@
 if [ "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_RAWHIDE" = "y" \
 	-o "$CONFIG_ALPHA_DP264" = "y" -o "$CONFIG_ALPHA_WILDFIRE" = "y" \
 	-o "$CONFIG_ALPHA_TITAN" = "y" -o "$CONFIG_ALPHA_GENERIC" = "y" \
-	-o "$CONFIG_ALPHA_SHARK" = "y" ]
+	-o "$CONFIG_ALPHA_SHARK" = "y" -o "$CONFIG_ALPHA_MARVEL" = "y" ]
 then
 	bool 'Symmetric multi-processing support' CONFIG_SMP
 fi
@@ -249,6 +259,10 @@
    define_bool CONFIG_HAVE_DEC_LOCK y
 fi
 
+if [ "$CONFIG_ALPHA_GENERIC" = "y" -o "$CONFIG_ALPHA_SRM" = "y" ]; then
+	define_bool CONFIG_EARLY_PRINTK y
+fi
+
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
    bool 'Discontiguous Memory Support (EXPERIMENTAL)' CONFIG_DISCONTIGMEM
    if [ "$CONFIG_DISCONTIGMEM" = "y" ]; then
@@ -311,6 +325,7 @@
 tristate 'ATA/IDE/MFM/RLL support' CONFIG_IDE
 
 if [ "$CONFIG_IDE" != "n" ]; then
+  int '  Maximum IDE interfaces' MAX_HWIFS 4
   source drivers/ide/Config.in
 else
   define_bool CONFIG_BLK_DEV_IDE_MODES n
@@ -330,6 +345,7 @@
 
 if [ "$CONFIG_PCI" = "y" ]; then
   source drivers/message/fusion/Config.in
+  source drivers/ieee1394/Config.in
 fi
 
 if [ "$CONFIG_NET" = "y" ]; then
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/defconfig linux-2.4.21-pre6/arch/alpha/defconfig
--- linux-2.4.20/arch/alpha/defconfig	2001-11-19 23:19:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/defconfig	2003-03-26 23:49:39.000000000 +0000
@@ -51,6 +51,7 @@
 # CONFIG_ALPHA_TAKARA is not set
 # CONFIG_ALPHA_TITAN is not set
 # CONFIG_ALPHA_WILDFIRE is not set
+CONFIG_VERBOSE_MCHECK=y
 CONFIG_ISA=y
 CONFIG_EISA=y
 # CONFIG_SBUS is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/Makefile linux-2.4.21-pre6/arch/alpha/kernel/Makefile
--- linux-2.4.20/arch/alpha/kernel/Makefile	2001-08-12 17:51:41.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/kernel/Makefile	2003-03-26 23:49:34.000000000 +0000
@@ -17,7 +17,8 @@
 export-objs := alpha_ksyms.o
 
 obj-y    := entry.o traps.o process.o osf_sys.o irq.o irq_alpha.o \
-	    signal.o setup.o ptrace.o time.o semaphore.o alpha_ksyms.o
+	    signal.o setup.o ptrace.o time.o semaphore.o alpha_ksyms.o \
+	    err_common.o
 
 #
 # FIXME!
@@ -38,20 +39,27 @@
 
 obj-y 	 += core_apecs.o core_cia.o core_irongate.o core_lca.o core_mcpcia.o \
 	    core_polaris.o core_t2.o core_tsunami.o core_titan.o \
+	    core_wildfire.o core_marvel.o \
 	    sys_alcor.o sys_cabriolet.o sys_dp264.o sys_eb64p.o sys_eiger.o \
 	    sys_jensen.o sys_miata.o sys_mikasa.o sys_nautilus.o sys_titan.o \
 	    sys_noritake.o sys_rawhide.o sys_ruffian.o sys_rx164.o \
 	    sys_sable.o sys_sio.o sys_sx164.o sys_takara.o sys_rx164.o \
-	    sys_wildfire.o core_wildfire.o irq_pyxis.o
+	    sys_wildfire.o sys_marvel.o \
+	    err_titan.o err_marvel.o \
+	    irq_pyxis.o srmcons.o gct.o
 
 else
 
+# Misc support
+obj-$(CONFIG_ALPHA_SRM) += srmcons.o gct.o
+
 # Core logic support
 obj-$(CONFIG_ALPHA_APECS) += core_apecs.o
 obj-$(CONFIG_ALPHA_CIA) += core_cia.o
 
 obj-$(CONFIG_ALPHA_IRONGATE) += core_irongate.o
 obj-$(CONFIG_ALPHA_LCA) += core_lca.o
+obj-$(CONFIG_ALPHA_MARVEL) += core_marvel.o
 obj-$(CONFIG_ALPHA_MCPCIA) += core_mcpcia.o
 obj-$(CONFIG_ALPHA_T2) += core_t2.o
 obj-$(CONFIG_ALPHA_TSUNAMI) += core_tsunami.o
@@ -69,7 +77,7 @@
 
 obj-$(CONFIG_ALPHA_DP264) += sys_dp264.o
 obj-$(CONFIG_ALPHA_SHARK) += sys_dp264.o
-obj-$(CONFIG_ALPHA_TITAN) += sys_titan.o
+obj-$(CONFIG_ALPHA_TITAN) += sys_titan.o err_titan.o
 
 ifneq ($(CONFIG_ALPHA_EB64P)$(CONFIG_ALPHA_EB66),)
 obj-y    += sys_eb64p.o
@@ -77,6 +85,7 @@
 
 obj-$(CONFIG_ALPHA_EIGER) += sys_eiger.o
 obj-$(CONFIG_ALPHA_JENSEN) += sys_jensen.o pci-noop.o
+obj-$(CONFIG_ALPHA_MARVEL) += sys_marvel.o err_marvel.o
 obj-$(CONFIG_ALPHA_MIATA) += sys_miata.o
 obj-$(CONFIG_ALPHA_MIKASA) += sys_mikasa.o
 obj-$(CONFIG_ALPHA_NAUTILUS) += sys_nautilus.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/alpha_ksyms.c linux-2.4.21-pre6/arch/alpha/kernel/alpha_ksyms.c
--- linux-2.4.20/arch/alpha/kernel/alpha_ksyms.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/kernel/alpha_ksyms.c	2003-03-26 23:49:00.000000000 +0000
@@ -37,6 +37,8 @@
 
 extern struct hwrpb_struct *hwrpb;
 extern void dump_thread(struct pt_regs *, struct user *);
+extern void dump_elf_thread(elf_gregset_t dest, struct pt_regs *pt,
+			    struct task_struct *task);
 extern int dump_fpu(struct pt_regs *, elf_fpregset_t *);
 extern spinlock_t kernel_flag;
 extern spinlock_t rtc_lock;
@@ -119,7 +121,7 @@
 EXPORT_SYMBOL(clear_page);
 
 EXPORT_SYMBOL(__delay);
-EXPORT_SYMBOL(__udelay);
+EXPORT_SYMBOL(ndelay);
 EXPORT_SYMBOL(udelay);
 
 EXPORT_SYMBOL(__direct_map_base);
@@ -142,6 +144,7 @@
 #endif
 
 EXPORT_SYMBOL(dump_thread);
+EXPORT_SYMBOL(dump_elf_thread);
 EXPORT_SYMBOL(dump_fpu);
 EXPORT_SYMBOL(hwrpb);
 EXPORT_SYMBOL(wrusp);
@@ -237,6 +240,13 @@
 EXPORT_SYMBOL(cpu_present_mask);
 #endif /* CONFIG_SMP */
 
+/*
+ * NUMA specific symbols
+ */
+#ifdef CONFIG_DISCONTIGMEM
+EXPORT_SYMBOL(plat_node_data);
+#endif /* CONFIG_DISCONTIGMEM */
+
 EXPORT_SYMBOL(rtc_lock);
 
 /*
@@ -266,3 +276,11 @@
 EXPORT_SYMBOL(irongate_ioremap);
 EXPORT_SYMBOL(irongate_iounmap);
 #endif
+#ifdef CONFIG_ALPHA_TITAN
+EXPORT_SYMBOL(titan_ioremap);
+EXPORT_SYMBOL(titan_iounmap);
+#endif
+#ifdef CONFIG_ALPHA_MARVEL
+EXPORT_SYMBOL(marvel_ioremap);
+EXPORT_SYMBOL(marvel_iounmap);
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/core_cia.c linux-2.4.21-pre6/arch/alpha/kernel/core_cia.c
--- linux-2.4.20/arch/alpha/kernel/core_cia.c	2001-10-21 17:30:58.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/kernel/core_cia.c	2003-03-26 23:49:40.000000000 +0000
@@ -47,6 +47,15 @@
 
 #define vip	volatile int  *
 
+/* Save CIA configuration data as the console had it set up.  */
+
+struct 
+{
+	unsigned int w_base;
+	unsigned int w_mask;
+	unsigned int t_base;
+} saved_config[4] __attribute((common));
+
 /*
  * Given a bus, device, and function number, compute resulting
  * configuration space address.  It is therefore not safe to have
@@ -370,7 +379,7 @@
 }
 
 static inline void
-cia_prepare_tbia_workaround(void)
+cia_prepare_tbia_workaround(int window)
 {
 	unsigned long *ppte, pte;
 	long i;
@@ -382,10 +391,10 @@
 	for (i = 0; i < CIA_BROKEN_TBIA_SIZE / sizeof(unsigned long); ++i)
 		ppte[i] = pte;
 
-	*(vip)CIA_IOC_PCI_W1_BASE = CIA_BROKEN_TBIA_BASE | 3;
-	*(vip)CIA_IOC_PCI_W1_MASK = (CIA_BROKEN_TBIA_SIZE*1024 - 1)
-				    & 0xfff00000;
-	*(vip)CIA_IOC_PCI_T1_BASE = virt_to_phys(ppte) >> 2;
+	*(vip)CIA_IOC_PCI_Wn_BASE(window) = CIA_BROKEN_TBIA_BASE | 3;
+	*(vip)CIA_IOC_PCI_Wn_MASK(window)
+	  = (CIA_BROKEN_TBIA_SIZE*1024 - 1) & 0xfff00000;
+	*(vip)CIA_IOC_PCI_Tn_BASE(window) = virt_to_phys(ppte) >> 2;
 }
 
 static void __init
@@ -605,8 +614,7 @@
 do_init_arch(int is_pyxis)
 {
 	struct pci_controller *hose;
-	int temp;
-	int cia_rev;
+	int temp, cia_rev, tbia_window;
 
 	cia_rev = *(vip)CIA_IOC_CIA_REV & CIA_REV_MASK;
 	printk("pci: cia revision %d%s\n",
@@ -681,13 +689,31 @@
 		hose->dense_io_base = CIA_BW_IO - IDENT_ADDR;
 	}
 
+	/* Save CIA configuration data as the console had it set up.  */
+
+	saved_config[0].w_base = *(vip)CIA_IOC_PCI_W0_BASE;
+	saved_config[0].w_mask = *(vip)CIA_IOC_PCI_W0_MASK;
+	saved_config[0].t_base = *(vip)CIA_IOC_PCI_T0_BASE;
+
+	saved_config[1].w_base = *(vip)CIA_IOC_PCI_W1_BASE;
+	saved_config[1].w_mask = *(vip)CIA_IOC_PCI_W1_MASK;
+	saved_config[1].t_base = *(vip)CIA_IOC_PCI_T1_BASE;
+
+	saved_config[2].w_base = *(vip)CIA_IOC_PCI_W2_BASE;
+	saved_config[2].w_mask = *(vip)CIA_IOC_PCI_W2_MASK;
+	saved_config[2].t_base = *(vip)CIA_IOC_PCI_T2_BASE;
+
+	saved_config[3].w_base = *(vip)CIA_IOC_PCI_W3_BASE;
+	saved_config[3].w_mask = *(vip)CIA_IOC_PCI_W3_MASK;
+	saved_config[3].t_base = *(vip)CIA_IOC_PCI_T3_BASE;
+
 	/*
 	 * Set up the PCI to main memory translation windows.
 	 *
-	 * Window 0 is scatter-gather 8MB at 8MB (for isa)
-	 * Window 1 is scatter-gather 1MB at 768MB (for tbia)
+	 * Window 0 is S/G 8MB at 8MB (for isa)
+	 * Window 1 is S/G 1MB at 768MB (for tbia) (unused for CIA rev 1)
 	 * Window 2 is direct access 2GB at 2GB
-	 * Window 3 is DAC access 4GB at 8GB
+	 * Window 3 is DAC access 4GB at 8GB (or S/G for tbia if CIA rev 1)
 	 *
 	 * ??? NetBSD hints that page tables must be aligned to 32K,
 	 * possibly due to a hardware bug.  This is over-aligned
@@ -697,6 +723,7 @@
 
 	hose->sg_pci = NULL;
 	hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 32768);
+
 	__direct_map_base = 0x80000000;
 	__direct_map_size = 0x80000000;
 
@@ -715,8 +742,20 @@
 	   are compared against W_DAC.  We can, however, directly map 4GB,
 	   which is better than before.  However, due to assumptions made
 	   elsewhere, we should not claim that we support DAC unless that
-	   4GB covers all of physical memory.  */
-	if (is_pyxis || max_low_pfn > (0x100000000 >> PAGE_SHIFT)) {
+	   4GB covers all of physical memory.
+
+	   On CIA rev 1, apparently W1 and W2 can't be used for SG.
+	   At least, there are reports that it doesn't work for Alcor.
+	   In that case, we have no choice but to use W3 for the TBIA
+	   workaround, which means we can't use DAC at all.  */
+
+	tbia_window = 1;
+	if (is_pyxis) {
+		*(vip)CIA_IOC_PCI_W3_BASE = 0;
+	} else if (cia_rev == 1) {
+		*(vip)CIA_IOC_PCI_W1_BASE = 0;
+		tbia_window = 3;
+	} else if (max_low_pfn > (0x100000000UL >> PAGE_SHIFT)) {
 		*(vip)CIA_IOC_PCI_W3_BASE = 0;
 	} else {
 		*(vip)CIA_IOC_PCI_W3_BASE = 0x00000000 | 1 | 8;
@@ -728,7 +767,7 @@
 	}
 
 	/* Prepare workaround for apparently broken tbia. */
-	cia_prepare_tbia_workaround();
+	cia_prepare_tbia_workaround(tbia_window);
 }
 
 void __init
@@ -762,6 +801,26 @@
 	do_init_arch(1);
 }
 
+void
+cia_kill_arch(int mode)
+{
+	*(vip)CIA_IOC_PCI_W0_BASE = saved_config[0].w_base;
+	*(vip)CIA_IOC_PCI_W0_MASK = saved_config[0].w_mask;
+	*(vip)CIA_IOC_PCI_T0_BASE = saved_config[0].t_base;
+
+	*(vip)CIA_IOC_PCI_W1_BASE = saved_config[1].w_base;
+	*(vip)CIA_IOC_PCI_W1_MASK = saved_config[1].w_mask;
+	*(vip)CIA_IOC_PCI_T1_BASE = saved_config[1].t_base;
+
+	*(vip)CIA_IOC_PCI_W2_BASE = saved_config[2].w_base;
+	*(vip)CIA_IOC_PCI_W2_MASK = saved_config[2].w_mask;
+	*(vip)CIA_IOC_PCI_T2_BASE = saved_config[2].t_base;
+
+	*(vip)CIA_IOC_PCI_W3_BASE = saved_config[3].w_base;
+	*(vip)CIA_IOC_PCI_W3_MASK = saved_config[3].w_mask;
+	*(vip)CIA_IOC_PCI_T3_BASE = saved_config[3].t_base;
+}
+
 void __init
 cia_init_pci(void)
 {
@@ -781,6 +840,7 @@
 	*(vip)CIA_IOC_CIA_ERR;		/* re-read to force write.  */
 }
 
+#ifdef CONFIG_VERBOSE_MCHECK
 static void
 cia_decode_pci_error(struct el_CIA_sysdata_mcheck *cia, const char *msg)
 {
@@ -1048,13 +1108,13 @@
 	printk(KERN_CRIT "  Command: %s, Parity bit: %d\n", cmd, par);
 	printk(KERN_CRIT "  Address: %#010lx, Mask: %#lx\n", addr, mask);
 }
+#endif
 
 static int
 cia_decode_mchk(unsigned long la_ptr)
 {
 	struct el_common *com;
 	struct el_CIA_sysdata_mcheck *cia;
-	int which;
 
 	com = (void *)la_ptr;
 	cia = (void *)(la_ptr + com->sys_offset);
@@ -1062,8 +1122,8 @@
 	if ((cia->cia_err & CIA_ERR_VALID) == 0)
 		return 0;
 
-	which = cia->cia_err & 0xfff;
-	switch (ffs(which) - 1) {
+#ifdef CONFIG_VERBOSE_MCHECK
+	switch (ffs(cia->cia_err & 0xfff) - 1) {
 	case 0: /* CIA_ERR_COR_ERR */
 		cia_decode_ecc_error(cia, "Corrected ECC error");
 		break;
@@ -1135,6 +1195,7 @@
 	if (cia->cia_err & CIA_ERR_LOST_IOA_TIMEOUT)
 		printk(KERN_CRIT "CIA lost machine check: "
 		       "I/O timeout\n");
+#endif
 
 	return 1;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/core_irongate.c linux-2.4.21-pre6/arch/alpha/kernel/core_irongate.c
--- linux-2.4.20/arch/alpha/kernel/core_irongate.c	2001-09-13 22:21:32.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/kernel/core_irongate.c	2003-03-26 23:49:08.000000000 +0000
@@ -25,13 +25,11 @@
 #include <asm/core_irongate.h>
 #undef __EXTERN_INLINE
 
+#include <linux/bootmem.h>
+
 #include "proto.h"
 #include "pci_impl.h"
 
-#undef DEBUG_IRONGATE 		/* define to enable verbose Irongate debug */
-
-#define IRONGATE_DEFAULT_AGP_APER_SIZE	(256*1024*1024) /* 256MB */
-
 /*
  * BIOS32-style PCI interface:
  */
@@ -44,6 +42,7 @@
 # define DBG_CFG(args)
 #endif
 
+igcsr32 *IronECC;
 
 /*
  * Given a bus, device, and function number, compute resulting
@@ -197,143 +196,6 @@
 	write_dword:	irongate_write_config_dword
 };
 
-#ifdef DEBUG_IRONGATE
-static void
-irongate_register_dump(const char *function_name)
-{
-	printk("%s: Irongate registers:\n"
-	       "\tFunction 0:\n"
-	       "\tdev_vendor\t0x%08x\n"
-	       "\tstat_cmd\t0x%08x\n"
-	       "\tclass\t\t0x%08x\n"
-	       "\tlatency\t\t0x%08x\n"
-	       "\tbar0\t\t0x%08x\n"
-	       "\tbar1\t\t0x%08x\n"
-	       "\tbar2\t\t0x%08x\n"
-	       "\trsrvd0[0]\t0x%08x\n"
-	       "\trsrvd0[1]\t0x%08x\n"
-	       "\trsrvd0[2]\t0x%08x\n"
-	       "\trsrvd0[3]\t0x%08x\n"
-	       "\trsrvd0[4]\t0x%08x\n"
-	       "\trsrvd0[5]\t0x%08x\n"
-	       "\tcapptr\t\t0x%08x\n"
-	       "\trsrvd1[0]\t0x%08x\n"
-	       "\trsrvd1[1]\t0x%08x\n"
-	       "\tbacsr10\t\t0x%08x\n"
-	       "\tbacsr32\t\t0x%08x\n"
-	       "\tbacsr54\t\t0x%08x\n"
-	       "\trsrvd2[0]\t0x%08x\n"
-	       "\tdrammap\t\t0x%08x\n"
-	       "\tdramtm\t\t0x%08x\n"
-	       "\tdramms\t\t0x%08x\n"
-	       "\trsrvd3[0]\t0x%08x\n"
-	       "\tbiu0\t\t0x%08x\n"
-	       "\tbiusip\t\t0x%08x\n"
-	       "\trsrvd4[0]\t0x%08x\n"
-	       "\trsrvd4[1]\t0x%08x\n"
-	       "\tmro\t\t0x%08x\n"
-	       "\trsrvd5[0]\t0x%08x\n"
-	       "\trsrvd5[1]\t0x%08x\n"
-	       "\trsrvd5[2]\t0x%08x\n"
-	       "\twhami\t\t0x%08x\n"
-	       "\tpciarb\t\t0x%08x\n"
-	       "\tpcicfg\t\t0x%08x\n"
-	       "\trsrvd6[0]\t0x%08x\n"
-	       "\trsrvd6[1]\t0x%08x\n"
-	       "\trsrvd6[2]\t0x%08x\n"
-	       "\trsrvd6[3]\t0x%08x\n"
-	       "\trsrvd6[4]\t0x%08x\n"
-	       "\tagpcap\t\t0x%08x\n"
-	       "\tagpstat\t\t0x%08x\n"
-	       "\tagpcmd\t\t0x%08x\n"
-	       "\tagpva\t\t0x%08x\n"
-	       "\tagpmode\t\t0x%08x\n"
-
-	       "\n\tFunction 1:\n"
-	       "\tdev_vendor:\t0x%08x\n"
-	       "\tcmd_status:\t0x%08x\n"
-	       "\trevid_etc :\t0x%08x\n"
-	       "\thtype_etc :\t0x%08x\n"
-	       "\trsrvd0[0] :\t0x%08x\n"
-	       "\trsrvd0[1] :\t0x%08x\n"
-	       "\tbus_nmbers:\t0x%08x\n"
-	       "\tio_baselim:\t0x%08x\n"
-	       "\tmem_bselim:\t0x%08x\n"
-	       "\tpf_baselib:\t0x%08x\n"
-	       "\trsrvd1[0] :\t0x%08x\n"
-	       "\trsrvd1[1] :\t0x%08x\n"
-	       "\tio_baselim:\t0x%08x\n"
-	       "\trsrvd2[0] :\t0x%08x\n"
-	       "\trsrvd2[1] :\t0x%08x\n"
-	       "\tinterrupt :\t0x%08x\n",
-
-	       function_name,
-	       IRONGATE0->dev_vendor,
-	       IRONGATE0->stat_cmd,
-	       IRONGATE0->class,
-	       IRONGATE0->latency,
-	       IRONGATE0->bar0,
-	       IRONGATE0->bar1,
-	       IRONGATE0->bar2,
-	       IRONGATE0->rsrvd0[0],
-	       IRONGATE0->rsrvd0[1],
-	       IRONGATE0->rsrvd0[2],
-	       IRONGATE0->rsrvd0[3],
-	       IRONGATE0->rsrvd0[4],
-	       IRONGATE0->rsrvd0[5],
-	       IRONGATE0->capptr,
-	       IRONGATE0->rsrvd1[0],
-	       IRONGATE0->rsrvd1[1],
-	       IRONGATE0->bacsr10,
-	       IRONGATE0->bacsr32,
-	       IRONGATE0->bacsr54,
-	       IRONGATE0->rsrvd2[0],
-	       IRONGATE0->drammap,
-	       IRONGATE0->dramtm,
-	       IRONGATE0->dramms,
-	       IRONGATE0->rsrvd3[0],
-	       IRONGATE0->biu0,
-	       IRONGATE0->biusip,
-	       IRONGATE0->rsrvd4[0],
-	       IRONGATE0->rsrvd4[1],
-	       IRONGATE0->mro,
-	       IRONGATE0->rsrvd5[0],
-	       IRONGATE0->rsrvd5[1],
-	       IRONGATE0->rsrvd5[2],
-	       IRONGATE0->whami,
-	       IRONGATE0->pciarb,
-	       IRONGATE0->pcicfg,
-	       IRONGATE0->rsrvd6[0],
-	       IRONGATE0->rsrvd6[1],
-	       IRONGATE0->rsrvd6[2],
-	       IRONGATE0->rsrvd6[3],
-	       IRONGATE0->rsrvd6[4],
-	       IRONGATE0->agpcap,
-	       IRONGATE0->agpstat,
-	       IRONGATE0->agpcmd,
-	       IRONGATE0->agpva,
-	       IRONGATE0->agpmode,
-	       IRONGATE1->dev_vendor,
-	       IRONGATE1->stat_cmd,
-	       IRONGATE1->class,
-	       IRONGATE1->htype,
-	       IRONGATE1->rsrvd0[0],
-	       IRONGATE1->rsrvd0[1],
-	       IRONGATE1->busnos,
-	       IRONGATE1->io_baselim_regs,
-	       IRONGATE1->mem_baselim,
-	       IRONGATE1->pfmem_baselim,
-	       IRONGATE1->rsrvd1[0],
-	       IRONGATE1->rsrvd1[1],
-	       IRONGATE1->io_baselim,
-	       IRONGATE1->rsrvd2[0],
-	       IRONGATE1->rsrvd2[1],
-	       IRONGATE1->interrupt );
-}
-#else
-#define irongate_register_dump(x)
-#endif
-
 int
 irongate_pci_clr_err(void)
 {
@@ -347,11 +209,11 @@
 	mb();
 	IRONGATE_jd = IRONGATE0->stat_cmd;  /* re-read to force write */
 
-	IRONGATE_jd = IRONGATE0->dramms;
-	printk("Iron dramms %x\n", IRONGATE_jd);
-	IRONGATE0->dramms = IRONGATE_jd; /* write again clears error bits */
+	IRONGATE_jd = *IronECC;
+	printk("Iron ECC %x\n", IRONGATE_jd);
+	*IronECC = IRONGATE_jd; /* write again clears error bits */
 	mb();
-	IRONGATE_jd = IRONGATE0->dramms;  /* re-read to force write */
+	IRONGATE_jd = *IronECC;  /* re-read to force write */
 
 	/* Clear ALI NMI */
         nmi_ctl = inb(0x61);
@@ -360,28 +222,88 @@
         nmi_ctl &= ~0x0c;
         outb(nmi_ctl, 0x61);
 
-	IRONGATE_jd = IRONGATE0->dramms;
+	IRONGATE_jd = *IronECC;
 	if (IRONGATE_jd & 0x300) goto again;
 
 	return 0;
 }
 
+#define IRONGATE_3GB 0xc0000000UL
+
+/* On Albacore (aka UP1500) with 4Gb of RAM we have to reserve some
+   memory for PCI. At this point we just reserve memory above 3Gb. Most
+   of this memory will be freed after PCI setup is done. */
+static void __init
+albacore_init_arch(void)
+{
+	unsigned long memtop = max_low_pfn << PAGE_SHIFT;
+	unsigned long pci_mem = (memtop + 0x1000000UL) & ~0xffffffUL;
+	struct percpu_struct *cpu;
+	int pal_rev, pal_var;
+
+	cpu = (struct percpu_struct*)((char*)hwrpb + hwrpb->processor_offset);
+	pal_rev = cpu->pal_revision & 0xffff;
+	pal_var = (cpu->pal_revision >> 16) & 0xff;
+
+	/* Consoles earlier than A5.6-18 (OSF PALcode v1.62-2) set up
+	   the CPU incorrectly (leave speculative stores enabled),
+	   which causes memory corruption under certain conditions.
+	   Issue a warning for such consoles. */
+	if (alpha_using_srm &&
+	    (pal_rev < 0x13e ||	(pal_rev == 0x13e && pal_var < 2)))
+		printk(KERN_WARNING "WARNING! Upgrade to SRM A5.6-19 "
+				    "or later\n");
+
+	if (pci_mem > IRONGATE_3GB)
+		pci_mem = IRONGATE_3GB;
+	IRONGATE0->pci_mem = pci_mem;
+	alpha_mv.min_mem_address = pci_mem;
+	if (memtop > pci_mem) {
+#ifdef CONFIG_BLK_DEV_INITRD
+		extern unsigned long initrd_start, initrd_end;
+		extern void *move_initrd(unsigned long);
+
+		/* Move the initrd out of the way. */
+		if (initrd_end && __pa(initrd_end) > pci_mem) {
+			unsigned long size;
+
+			size = initrd_end - initrd_start;
+			free_bootmem(__pa(initrd_start), PAGE_ALIGN(size));
+			if (!move_initrd(pci_mem))
+				printk("irongate_init_arch: initrd too big "
+				       "(%ldK)\ndisabling initrd\n",
+				       size / 1024);
+		}
+#endif
+		reserve_bootmem(pci_mem, memtop - pci_mem);
+		printk("irongate_init_arch: temporarily reserving "
+			"region %08lx-%08lx for PCI\n", pci_mem, memtop - 1);
+	}
+}
+
+static void __init
+irongate_setup_agp(void)
+{
+	/* Disable the GART window. AGPGART doesn't work due to yet
+	   unresolved memory coherency issues... */
+	IRONGATE0->agpva = IRONGATE0->agpva & ~0xf;
+	alpha_agpgart_size = 0;
+}
+
 void __init
 irongate_init_arch(void)
 {
 	struct pci_controller *hose;
+	int amd761 = (IRONGATE0->dev_vendor >> 16) > 0x7006;	/* Albacore? */
+
+	IronECC = amd761 ? &IRONGATE0->bacsr54_eccms761 : &IRONGATE0->dramms;
 
-	IRONGATE0->stat_cmd = IRONGATE0->stat_cmd & ~0x100;
 	irongate_pci_clr_err();
-	irongate_register_dump(__FUNCTION__);
 
-	/*
-	 * HACK: set AGP aperture size to 256MB.
-	 * This should really be changed during PCI probe, when the
-	 * size of the aperture the AGP card wants is known.
-	 */
-	printk("irongate_init_arch: AGPVA was 0x%x\n", IRONGATE0->agpva);
-	IRONGATE0->agpva = (IRONGATE0->agpva & ~0x0000000f) | 0x00000007;
+	if (amd761)
+		albacore_init_arch();
+
+	irongate_setup_agp();
 
 	/*
 	 * Create our single hose.
@@ -412,88 +334,9 @@
  * IO map and AGP support
  */
 #include <linux/vmalloc.h>
-#include <asm/pgalloc.h>
-
-static inline void 
-irongate_remap_area_pte(pte_t * pte, unsigned long address, unsigned long size, 
-		     unsigned long phys_addr, unsigned long flags)
-{
-	unsigned long end;
-
-	address &= ~PMD_MASK;
-	end = address + size;
-	if (end > PMD_SIZE)
-		end = PMD_SIZE;
-	if (address >= end)
-		BUG();
-	do {
-		if (!pte_none(*pte)) {
-			printk("irongate_remap_area_pte: page already exists\n");
-			BUG();
-		}
-		set_pte(pte, 
-			mk_pte_phys(phys_addr, 
-				    __pgprot(_PAGE_VALID | _PAGE_ASM | 
-					     _PAGE_KRE | _PAGE_KWE | flags)));
-		address += PAGE_SIZE;
-		phys_addr += PAGE_SIZE;
-		pte++;
-	} while (address && (address < end));
-}
-
-static inline int 
-irongate_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;
-		irongate_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
-irongate_remap_area_pages(unsigned long address, unsigned long phys_addr,
-		       unsigned long size, unsigned long flags)
-{
-	pgd_t * dir;
-	unsigned long end = address + size;
-
-	phys_addr -= address;
-	dir = pgd_offset(&init_mm, address);
-	flush_cache_all();
-	if (address >= end)
-		BUG();
-	do {
-		pmd_t *pmd;
-		pmd = pmd_alloc(&init_mm, dir, address);
-		if (!pmd)
-			return -ENOMEM;
-		if (irongate_remap_area_pmd(pmd, address, end - address,
-					 phys_addr + address, flags))
-			return -ENOMEM;
-		address = (address + PGDIR_SIZE) & PGDIR_MASK;
-		dir++;
-	} while (address && (address < end));
-	return 0;
-}
-
 #include <linux/agp_backend.h>
 #include <linux/agpgart.h>
+#include <asm/pgalloc.h>
 
 #define GET_PAGE_DIR_OFF(addr) (addr >> 22)
 #define GET_PAGE_DIR_IDX(addr) (GET_PAGE_DIR_OFF(addr))
@@ -508,15 +351,13 @@
 	unsigned long vaddr;
 	unsigned long baddr, last;
 	u32 *mmio_regs, *gatt_pages, *cur_gatt, pte;
-	unsigned long gart_bus_addr, gart_aper_size;
+	unsigned long gart_bus_addr;
 
-	gart_bus_addr = (unsigned long)IRONGATE0->bar0 &
-			PCI_BASE_ADDRESS_MEM_MASK; 
-
-	if (!gart_bus_addr) /* FIXME - there must be a better way!!! */
+	if (!alpha_agpgart_size)
 		return addr + IRONGATE_MEM;
 
-	gart_aper_size = IRONGATE_DEFAULT_AGP_APER_SIZE; /* FIXME */
+	gart_bus_addr = (unsigned long)IRONGATE0->bar0 &
+			PCI_BASE_ADDRESS_MEM_MASK; 
 
 	/* 
 	 * Check for within the AGP aperture...
@@ -526,7 +367,7 @@
 		 * Check the AGP area
 		 */
 		if (addr >= gart_bus_addr && addr + size - 1 < 
-		    gart_bus_addr + gart_aper_size)
+		    gart_bus_addr + alpha_agpgart_size)
 			break;
 
 		/*
@@ -580,8 +421,8 @@
 		cur_gatt = phys_to_virt(GET_GATT(baddr) & ~1);
 		pte = cur_gatt[GET_GATT_OFF(baddr)] & ~1;
 
-		if (irongate_remap_area_pages(VMALLOC_VMADDR(vaddr), 
-					   pte, PAGE_SIZE, 0)) {
+		if (__alpha_remap_area_pages(VMALLOC_VMADDR(vaddr), 
+					     pte, PAGE_SIZE, 0)) {
 			printk("AGP ioremap: FAILED to map...\n");
 			vfree(area->addr);
 			return (unsigned long)NULL;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/core_marvel.c linux-2.4.21-pre6/arch/alpha/kernel/core_marvel.c
--- linux-2.4.20/arch/alpha/kernel/core_marvel.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/kernel/core_marvel.c	2003-03-26 23:49:09.000000000 +0000
@@ -0,0 +1,1125 @@
+/*
+ *	linux/arch/alpha/kernel/core_marvel.c
+ *
+ * Code common to all Marvel based systems.
+ */
+
+#include <linux/config.h>
+
+#define __EXTERN_INLINE inline
+#include <asm/io.h>
+#include <asm/core_marvel.h>
+#undef __EXTERN_INLINE
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+#include <linux/mc146818rtc.h>
+
+#include <asm/ptrace.h>
+#include <asm/system.h>
+#include <asm/smp.h>
+#include <asm/hwrpb.h>
+#include <asm/gct.h>
+#include <asm/pgalloc.h>
+
+#include <linux/bootmem.h>
+
+#include "proto.h"
+#include "pci_impl.h"
+
+
+/*
+ * Debug helpers
+ */
+#define DEBUG_CONFIG 0
+
+#if DEBUG_CONFIG
+# define DBG_CFG(args) printk args
+#else
+# define DBG_CFG(args)
+#endif
+
+
+/*
+ * Private data
+ */
+static struct io7 *io7_head = NULL;
+
+
+/*
+ * Helper functions
+ */
+static unsigned long __attribute__ ((unused))
+read_ev7_csr(int pe, unsigned long offset)
+{
+	ev7_csr *ev7csr = EV7_CSR_KERN(pe, offset);
+	unsigned long q;
+
+	mb();
+	q = ev7csr->csr;
+	mb();
+
+	return q;
+}
+
+static void __attribute__ ((unused))
+write_ev7_csr(int pe, unsigned long offset, unsigned long q)
+{
+	ev7_csr *ev7csr = EV7_CSR_KERN(pe, offset);
+
+	mb();
+	ev7csr->csr = q;
+	mb();
+}
+
+static char * __init
+mk_resource_name(int pe, int port, char *str)
+{
+	char tmp[80];
+	char *name;
+	
+	sprintf(tmp, "PCI %s PE %d PORT %d", str, pe, port);
+	name = alloc_bootmem(strlen(tmp) + 1);
+	strcpy(name, tmp);
+
+	return name;
+}
+
+inline struct io7 *
+marvel_next_io7(struct io7 *prev)
+{
+	return (prev ? prev->next : io7_head);
+}
+
+struct io7 *
+marvel_find_io7(int pe)
+{
+	struct io7 *io7;
+
+	for (io7 = io7_head; io7 && io7->pe != pe; io7 = io7->next)
+		continue;
+
+	return io7;
+}
+
+static struct io7 * __init
+alloc_io7(unsigned int pe)
+{
+	struct io7 *io7;
+	struct io7 *insp;
+	int h;
+
+	if (marvel_find_io7(pe)) {
+		printk(KERN_WARNING "IO7 at PE %d already allocated!\n", pe);
+		return NULL;
+	}
+
+	io7 = alloc_bootmem(sizeof(*io7));
+	io7->pe = pe;
+	io7->irq_lock = SPIN_LOCK_UNLOCKED;
+
+	for (h = 0; h < 4; h++) {
+		io7->ports[h].io7 = io7;
+		io7->ports[h].port = h;
+		io7->ports[h].enabled = 0; /* default to disabled */
+	}
+
+	/*
+	 * Insert in pe sorted order.
+	 */
+	if (NULL == io7_head)			/* empty list */
+		io7_head = io7;	
+	else if (io7_head->pe > io7->pe) {	/* insert at head */
+		io7->next = io7_head;
+		io7_head = io7;
+	} else {				/* insert at position */
+		for (insp = io7_head; insp; insp = insp->next) {
+			if (insp->pe == io7->pe) {
+				printk(KERN_ERR "Too many IO7s at PE %d\n", 
+				       io7->pe);
+				return NULL;
+			}
+
+			if (NULL == insp->next || 
+			    insp->next->pe > io7->pe) { /* insert here */
+				io7->next = insp->next;
+				insp->next = io7;
+				break;
+			}
+		}
+
+		if (NULL == insp) { /* couldn't insert ?!? */
+			printk(KERN_WARNING "Failed to insert IO7 at PE %d "
+			       " - adding at head of list\n", io7->pe);
+			io7->next = io7_head;
+			io7_head = io7;
+		}
+	}
+	
+	return io7;
+}
+
+void
+io7_clear_errors(struct io7 *io7)
+{
+	io7_port7_csrs *p7csrs;
+	io7_ioport_csrs *csrs;
+	int port;
+
+
+	/*
+	 * First the IO ports.
+	 */
+	for (port = 0; port < 4; port++) {
+		csrs = IO7_CSRS_KERN(io7->pe, port);
+
+		csrs->POx_ERR_SUM.csr = -1UL;
+		csrs->POx_TLB_ERR.csr = -1UL;
+		csrs->POx_SPL_COMPLT.csr = -1UL;
+		csrs->POx_TRANS_SUM.csr = -1UL;
+	}
+
+	/*
+	 * Then the common ones.
+	 */
+	p7csrs = IO7_PORT7_CSRS_KERN(io7->pe);
+
+	p7csrs->PO7_ERROR_SUM.csr = -1UL;
+	p7csrs->PO7_UNCRR_SYM.csr = -1UL;
+	p7csrs->PO7_CRRCT_SYM.csr = -1UL;
+}
+
+
+/*
+ * IO7 PCI, PCI/X, AGP configuration.
+ */
+static void __init
+io7_init_hose(struct io7 *io7, int port)
+{
+	static int hose_index = 0;
+
+	struct pci_controller *hose = alloc_pci_controller();
+	struct io7_port *io7_port = &io7->ports[port];
+	io7_ioport_csrs *csrs = IO7_CSRS_KERN(io7->pe, port);
+	int i;
+
+	hose->index = hose_index++;	/* arbitrary */
+	
+	/*
+	 * We don't have an isa or legacy hose, but glibc expects to be
+	 * able to use the bus == 0 / dev == 0 form of the iobase syscall
+	 * to determine information about the i/o system. Since XFree86 
+	 * relies on glibc's determination to tell whether or not to use
+	 * sparse access, we need to point the pci_isa_hose at a real hose
+	 * so at least that determination is correct.
+	 */
+	if (hose->index == 0)
+		pci_isa_hose = hose;
+
+	io7_port->csrs = csrs;
+	io7_port->hose = hose;
+	hose->sysdata = io7_port;
+
+	hose->io_space = alloc_resource();
+	hose->mem_space = alloc_resource();
+
+	/*
+	 * Base addresses for userland consumption. Since these are going
+	 * to be mapped, they are pure physical addresses.
+	 */
+	hose->sparse_mem_base = hose->sparse_io_base = 0;
+	hose->dense_mem_base = IO7_MEM_PHYS(io7->pe, port);
+	hose->dense_io_base = IO7_IO_PHYS(io7->pe, port);
+
+	/*
+	 * Base addresses and resource ranges for kernel consumption.
+	 */
+	hose->config_space_base = (unsigned long)IO7_CONF_KERN(io7->pe, port);
+
+	hose->io_space->start = (unsigned long)IO7_IO_KERN(io7->pe, port);
+	hose->io_space->end = hose->io_space->start + IO7_IO_SPACE - 1;
+	hose->io_space->name = mk_resource_name(io7->pe, port, "IO");
+	hose->io_space->flags = IORESOURCE_IO;
+
+	hose->mem_space->start = (unsigned long)IO7_MEM_KERN(io7->pe, port);
+	hose->mem_space->end = hose->mem_space->start + IO7_MEM_SPACE - 1;
+	hose->mem_space->name = mk_resource_name(io7->pe, port, "MEM");
+	hose->mem_space->flags = IORESOURCE_MEM;
+
+	if (request_resource(&ioport_resource, hose->io_space) < 0)
+		printk(KERN_ERR "Failed to request IO on hose %d\n", 
+		       hose->index);
+	if (request_resource(&iomem_resource, hose->mem_space) < 0)
+		printk(KERN_ERR "Failed to request MEM on hose %d\n", 
+		       hose->index);
+
+	/*
+	 * Save the existing DMA window settings for later restoration.
+	 */
+	for (i = 0; i < 4; i++) {
+		io7_port->saved_wbase[i] = csrs->POx_WBASE[i].csr;
+		io7_port->saved_wmask[i] = csrs->POx_WMASK[i].csr;
+		io7_port->saved_tbase[i] = csrs->POx_TBASE[i].csr;
+	}
+
+	/*
+	 * Set up the PCI to main memory translation windows.
+	 *
+	 * Window 0 is scatter-gather 8MB at 8MB
+	 * Window 1 is direct access 1GB at 2GB
+	 * Window 2 is scatter-gather (up-to) 1GB at 3GB
+	 * Window 3 is disabled
+	 */
+
+	/*
+	 * TBIA before modifying windows.
+	 */
+	marvel_pci_tbi(hose, 0, -1);
+
+	/*
+	 * Set up window 0 for scatter-gather 8MB at 8MB.
+	 */
+	hose->sg_isa = iommu_arena_new_node(marvel_cpuid_to_nid(io7->pe),
+					    hose, 0x00800000, 0x00800000, 0);
+	hose->sg_isa->align_entry = 8;	/* cache line boundary */
+	csrs->POx_WBASE[0].csr = 
+		hose->sg_isa->dma_base | wbase_m_ena | wbase_m_sg;
+	csrs->POx_WMASK[0].csr = (hose->sg_isa->size - 1) & wbase_m_addr;
+	csrs->POx_TBASE[0].csr = virt_to_phys(hose->sg_isa->ptes);
+
+	/*
+	 * Set up window 1 for direct-mapped 1GB at 2GB.
+	 */
+	csrs->POx_WBASE[1].csr = __direct_map_base | wbase_m_ena;
+	csrs->POx_WMASK[1].csr = (__direct_map_size - 1) & wbase_m_addr;
+	csrs->POx_TBASE[1].csr = 0;
+
+	/*
+	 * Set up window 2 for scatter-gather (up-to) 1GB at 3GB.
+	 */
+	hose->sg_pci = iommu_arena_new_node(marvel_cpuid_to_nid(io7->pe),
+					    hose, 0xc0000000, 0x40000000, 0);
+	hose->sg_pci->align_entry = 8;	/* cache line boundary */
+	csrs->POx_WBASE[2].csr = 
+		hose->sg_pci->dma_base | wbase_m_ena | wbase_m_sg;
+	csrs->POx_WMASK[2].csr = (hose->sg_pci->size - 1) & wbase_m_addr;
+	csrs->POx_TBASE[2].csr = virt_to_phys(hose->sg_pci->ptes);
+
+	/*
+	 * Disable window 3.
+	 */
+	csrs->POx_WBASE[3].csr = 0;
+
+	/*
+	 * Make sure that the AGP Monster Window is disabled.
+	 */
+	csrs->POx_CTRL.csr &= ~(1UL << 61);
+
+#if 1
+	printk("FIXME: disabling master aborts\n");
+	csrs->POx_MSK_HEI.csr &= ~(3UL << 14);
+#endif
+	/*
+	 * TBIA after modifying windows.
+	 */
+	marvel_pci_tbi(hose, 0, -1);
+}
+
+static void __init
+marvel_init_io7(struct io7 *io7)
+{
+	int i;
+
+	printk("Initializing IO7 at PID %d\n", io7->pe);
+
+	/*
+	 * Get the Port 7 CSR pointer.
+	 */
+	io7->csrs = IO7_PORT7_CSRS_KERN(io7->pe);
+
+	/*
+	 * Init this IO7's hoses.
+	 */
+	for (i = 0; i < IO7_NUM_PORTS; i++) {
+		io7_ioport_csrs *csrs = IO7_CSRS_KERN(io7->pe, i);
+		if (csrs->POx_CACHE_CTL.csr == 8) {
+			io7->ports[i].enabled = 1;
+			io7_init_hose(io7, i);
+		}
+	}
+}
+
+void
+marvel_io7_present(gct6_node *node)
+{
+	int pe;
+
+	if (node->type != GCT_TYPE_HOSE ||
+	    node->subtype != GCT_SUBTYPE_IO_PORT_MODULE) 
+		return;
+
+	pe = (node->id >> 8) & 0xff;
+	printk("Found an IO7 at PID %d\n", pe);
+
+	alloc_io7(pe);
+}
+
+static void __init
+marvel_init_vga_hose(void)
+{
+#ifdef CONFIG_VGA_HOSE
+	u64 *pu64 = (u64 *)((u64)hwrpb + hwrpb->ctbt_offset);
+
+	if (pu64[7] == 3) {	/* TERM_TYPE == graphics */
+		struct pci_controller *hose = NULL;
+		int h = (pu64[30] >> 24) & 0xff; /* TERM_OUT_LOC, hose # */
+		struct io7 *io7;
+		int pid, port;
+
+		/* FIXME - encoding is going to have to change for Marvel
+		 *         since hose will be able to overflow a byte...
+		 *         need to fix this decode when the console 
+		 *         changes its encoding
+		 */
+		printk("console graphics is on hose %d (console)\n", h);
+
+		/*
+		 * The console's hose numbering is:
+		 *
+		 *	hose<n:2>: PID
+		 *	hose<1:0>: PORT
+		 *
+		 * We need to find the hose at that pid and port
+		 */
+		pid = h >> 2;
+		port = h & 3;
+		if ((io7 = marvel_find_io7(pid)))
+			hose = io7->ports[port].hose;
+
+		if (hose) {
+			printk("Console graphics on hose %d\n", hose->index);
+			pci_vga_hose = hose;
+		}
+	}
+#endif /* CONFIG_VGA_HOSE */
+}
+
+gct6_search_struct gct_wanted_node_list[] = {
+	{ GCT_TYPE_HOSE, GCT_SUBTYPE_IO_PORT_MODULE, marvel_io7_present },
+	{ 0, 0, NULL }
+};
+
+/*
+ * In case the GCT is not complete, let the user specify PIDs with IO7s
+ * at boot time. Syntax is 'io7=a,b,c,...,n' where a-n are the PIDs (decimal)
+ * where IO7s are connected
+ */
+static int __init
+marvel_specify_io7(char *str)
+{
+	unsigned long pid;
+	struct io7 *io7;
+	char *pchar;
+
+	do {
+		pid = simple_strtoul(str, &pchar, 0);
+		if (pchar != str) {
+			printk("User-specified IO7 at PID %lu\n", pid);
+			io7 = alloc_io7(pid);
+			if (io7) marvel_init_io7(io7);
+		}
+
+		if (pchar == str) pchar++;
+		str = pchar;
+	} while(*str);
+
+	return 0;
+}
+__setup("io7=", marvel_specify_io7);
+
+void __init
+marvel_init_arch(void)
+{
+	struct io7 *io7;
+
+	/* With multiple PCI busses, we play with I/O as physical addrs.  */
+	ioport_resource.end = ~0UL;
+	iomem_resource.end = ~0UL;
+
+	/* PCI DMA Direct Mapping is 1GB at 2GB.  */
+	__direct_map_base = 0x80000000;
+	__direct_map_size = 0x40000000;
+
+	/* Parse the config tree.  */
+	gct6_find_nodes(GCT_NODE_PTR(0), gct_wanted_node_list);
+
+	/* Init the io7s.  */
+	for (io7 = NULL; NULL != (io7 = marvel_next_io7(io7)); ) 
+		marvel_init_io7(io7);
+
+	/* Check for graphic console location (if any).  */
+	marvel_init_vga_hose();
+}
+
+void
+marvel_kill_arch(int mode)
+{
+}
+
+
+/*
+ * PCI Configuration Space access functions
+ *
+ * Configuration space addresses have the following format:
+ *
+ * 	|2 2 2 2|1 1 1 1|1 1 1 1|1 1 
+ * 	|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
+ * 	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * 	|B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|R|R|
+ * 	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ *	 n:24	reserved for hose base
+ *	23:16	bus number (8 bits = 128 possible buses)
+ *	15:11	Device number (5 bits)
+ *	10:8	function number
+ *	 7:2	register number
+ *  
+ * Notes:
+ *	IO7 determines whether to use a type 0 or type 1 config cycle
+ *	based on the bus number. Therefore the bus number must be set 
+ *	to 0 for the root bus on any hose.
+ *	
+ *	The function number selects which function of a multi-function device 
+ *	(e.g., SCSI and Ethernet).
+ * 
+ */
+
+static inline unsigned long
+build_conf_addr(struct pci_controller *hose, u8 bus, 
+		unsigned int devfn, int where)
+{
+	return (hose->config_space_base | (bus << 16) | (devfn << 8) | where);
+}
+
+static unsigned long
+mk_conf_addr(struct pci_dev *dev, int where)
+{
+	struct pci_controller *hose = dev->sysdata;
+	unsigned long addr = 0;
+	struct io7_port *io7_port;
+	u8 bus;
+
+	if (!hose)
+		return addr;
+	
+	/* Check for enabled.  */
+	io7_port = hose->sysdata;
+	if (!io7_port->enabled)
+		return addr;
+
+	bus = dev->bus->number;
+
+	if (hose->first_busno == bus) {
+		/* Don't support idsel > 20 on primary bus.  */
+		if (dev->devfn >= PCI_DEVFN(21, 0))
+			return addr;
+		bus = 0;
+	}
+
+	addr = build_conf_addr(hose, bus, dev->devfn, where);
+
+	DBG_CFG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
+	return addr;
+}
+
+static int
+marvel_read_config_byte(struct pci_dev *dev, int where, u8 *value)
+{
+	unsigned long addr;
+	
+	if (0 == (addr = mk_conf_addr(dev, where)))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	*value = __kernel_ldbu(*(vucp)addr);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+marvel_read_config_word(struct pci_dev *dev, int where, u16 *value)
+{
+	unsigned long addr;
+	
+	if (0 == (addr = mk_conf_addr(dev, where)))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	*value = __kernel_ldwu(*(vusp)addr);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+marvel_read_config_dword(struct pci_dev *dev, int where, u32 *value)
+{
+	unsigned long addr;
+	
+	if (0 == (addr = mk_conf_addr(dev, where)))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	*value = *(vuip)addr;
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+marvel_write_config_byte(struct pci_dev *dev, int where, u8 value)
+{
+	unsigned long addr;
+	
+	if (0 == (addr = mk_conf_addr(dev, where)))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	__kernel_stb(value, *(vucp)addr);
+	mb();
+	__kernel_ldbu(*(vucp)addr);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+marvel_write_config_word(struct pci_dev *dev, int where, u16 value)
+{
+	unsigned long addr;
+	
+	if (0 == (addr = mk_conf_addr(dev, where)))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	__kernel_stw(value, *(vusp)addr);
+	mb();
+	__kernel_ldwu(*(vusp)addr);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+marvel_write_config_dword(struct pci_dev *dev, int where, u32 value)
+{
+	unsigned long addr;
+	
+	if (0 == (addr = mk_conf_addr(dev, where)))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	*(vuip)addr = value;
+	mb();
+	*(vuip)addr;
+	return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops marvel_pci_ops =
+{
+	read_byte:	marvel_read_config_byte,
+	read_word:	marvel_read_config_word,
+	read_dword:	marvel_read_config_dword,
+	write_byte:	marvel_write_config_byte,
+	write_word:	marvel_write_config_word,
+	write_dword:	marvel_write_config_dword
+};
+
+
+/*
+ * Other PCI helper functions.
+ */
+void
+marvel_pci_tbi(struct pci_controller *hose, dma_addr_t start, dma_addr_t end)
+{
+	io7_ioport_csrs *csrs = ((struct io7_port *)hose->sysdata)->csrs;
+
+	wmb();
+	csrs->POx_SG_TBIA.csr = 0;
+	mb();
+	csrs->POx_SG_TBIA.csr;
+}
+
+
+/*
+ * IO map support.
+ */
+unsigned long
+marvel_ioremap(unsigned long addr, unsigned long size)
+{
+	struct pci_controller *hose;
+	unsigned long baddr, last;
+	struct vm_struct *area;
+	unsigned long vaddr;
+	unsigned long *ptes;
+	unsigned long pfn;
+
+	/*
+	 * Adjust the addr.
+	 */ 
+#ifdef CONFIG_VGA_HOSE
+	if (pci_vga_hose && __marvel_is_mem_vga(addr)) {
+		addr += pci_vga_hose->mem_space->start;
+	}
+#endif
+
+	if (!marvel_is_ioaddr(addr))
+		return 0UL;
+
+	/*
+	 * Find the hose.
+	 */
+	for (hose = hose_head; hose; hose = hose->next) {
+		if ((addr >> 32) == (hose->mem_space->start >> 32))
+			break;
+	}
+	if (!hose)
+		return 0UL;
+
+	/*
+	 * We have the hose - calculate the bus limits.
+	 */
+	baddr = addr - hose->mem_space->start;
+	last = baddr + size - 1;
+
+	/*
+	 * Is it direct-mapped?
+	 */
+	if ((baddr >= __direct_map_base) && 
+	    ((baddr + size - 1) < __direct_map_base + __direct_map_size)) 
+		return IDENT_ADDR | (baddr - __direct_map_base);
+
+	/* 
+	 * Check the scatter-gather arena.
+	 */
+	if (hose->sg_pci &&
+	    baddr >= (unsigned long)hose->sg_pci->dma_base &&
+	    last < (unsigned long)hose->sg_pci->dma_base + hose->sg_pci->size){
+
+		/*
+		 * Adjust the limits (mappings must be page aligned)
+		 */
+		baddr -= hose->sg_pci->dma_base;
+		last -= hose->sg_pci->dma_base;
+		baddr &= PAGE_MASK;
+		size = PAGE_ALIGN(last) - baddr;
+
+		/*
+		 * Map it.
+		 */
+		area = get_vm_area(size, VM_IOREMAP);
+		if (!area) return (unsigned long)NULL;
+		ptes = hose->sg_pci->ptes;
+		for (vaddr = (unsigned long)area->addr; 
+		    baddr <= last; 
+		    baddr += PAGE_SIZE, vaddr += PAGE_SIZE) {
+			pfn = ptes[baddr >> PAGE_SHIFT];
+			if (!(pfn & 1)) {
+				printk("ioremap failed... pte not valid...\n");
+				vfree(area->addr);
+				return 0UL;
+			}
+			pfn >>= 1;	/* make it a true pfn */
+			
+			if (__alpha_remap_area_pages(VMALLOC_VMADDR(vaddr), 
+						     pfn << PAGE_SHIFT, 
+						     PAGE_SIZE, 0)) {
+				printk("FAILED to map...\n");
+				vfree(area->addr);
+				return 0UL;
+			}
+		}
+
+		flush_tlb_all();
+
+		vaddr = (unsigned long)area->addr + (addr & ~PAGE_MASK);
+
+		return vaddr;
+	}
+
+	/*
+	 * Not found - assume legacy ioremap.
+	 */
+	return addr;
+}
+
+void
+marvel_iounmap(unsigned long addr)
+{
+	if (((long)addr >> 41) == -2)
+		return;	/* kseg map, nothing to do */
+	if (addr)
+		return vfree((void *)(PAGE_MASK & addr)); 
+}
+
+
+/*
+ * RTC Support
+ */
+struct marvel_rtc_access_info {
+	unsigned long function;
+	unsigned long index;
+	unsigned long data;
+};
+
+static void
+__marvel_access_rtc(void *info)
+{
+	struct marvel_rtc_access_info *rtc_access = info;
+
+	register unsigned long __r0 __asm__("$0");
+	register unsigned long __r16 __asm__("$16") = rtc_access->function;
+	register unsigned long __r17 __asm__("$17") = rtc_access->index;
+	register unsigned long __r18 __asm__("$18") = rtc_access->data;
+	
+	__asm__ __volatile__(
+		"call_pal %4 # cserve rtc"
+		: "=r"(__r16), "=r"(__r17), "=r"(__r18), "=r"(__r0)
+		: "i"(PAL_cserve), "0"(__r16), "1"(__r17), "2"(__r18)
+		: "$1", "$22", "$23", "$24", "$25");
+
+	rtc_access->data = __r0;
+}
+
+u8
+__marvel_rtc_io(int write, u8 b, unsigned long addr)
+{
+	struct marvel_rtc_access_info rtc_access = {0, };
+	static u8 index = 0;
+	u8 ret = 0;
+
+	switch(addr) {
+	case 0x70:					/* RTC_PORT(0) */
+		if (write) index = b;
+		ret = index;
+		break;
+
+	case 0x71:					/* RTC_PORT(1) */
+		rtc_access.index = index;
+		rtc_access.data = BCD_TO_BIN(b);
+		rtc_access.function = 0x49;		/* GET_TOY */
+		if (write) rtc_access.function = 0x48;	/* PUT_TOY */
+
+#if CONFIG_SMP
+		if (smp_processor_id() != boot_cpuid)
+			smp_call_function_on_cpu(__marvel_access_rtc,
+						 &rtc_access,
+						 1,	/* retry */
+						 1,	/* wait  */
+						 1UL << boot_cpuid);
+		else
+			__marvel_access_rtc(&rtc_access);
+#else
+		__marvel_access_rtc(&rtc_access);
+#endif
+		ret = BIN_TO_BCD(rtc_access.data);
+		
+		break;
+
+	default:
+		printk(KERN_WARNING "Illegal RTC port %lx\n", addr);
+		break;
+	}
+
+	return ret;
+}
+
+
+/*
+ * NUMA Support
+ */
+/**********
+ * FIXME - for now each cpu is a node by itself 
+ *              -- no real support for striped mode 
+ **********
+ */
+int
+marvel_pa_to_nid(unsigned long pa)
+{
+	int cpuid;
+
+	if ((pa >> 43) & 1) 	/* I/O */ 
+		cpuid = (~(pa >> 35) & 0xff);
+	else			/* mem */
+		cpuid = ((pa >> 34) & 0x3) | ((pa >> (37 - 2)) & (0x1f << 2));
+
+	return marvel_cpuid_to_nid(cpuid);
+}
+
+int
+marvel_cpuid_to_nid(int cpuid)
+{
+	return cpuid;
+}
+
+unsigned long
+marvel_node_mem_start(int nid)
+{
+	unsigned long pa;
+
+	pa = (nid & 0x3) | ((nid & (0x1f << 2)) << 1);
+	pa <<= 34;
+
+	return pa;
+}
+
+unsigned long
+marvel_node_mem_size(int nid)
+{
+	return 16UL * 1024 * 1024 * 1024; /* 16GB */
+}
+
+
+/* 
+ * AGP GART Support.
+ */
+#include <linux/agp_backend.h>
+#include <asm/agp_backend.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+struct marvel_agp_aperture {
+	struct pci_iommu_arena *arena;
+	long pg_start;
+	long pg_count;
+};
+
+static int
+marvel_agp_setup(alpha_agp_info *agp)
+{
+	struct marvel_agp_aperture *aper;
+
+	if (!alpha_agpgart_size)
+		return -ENOMEM;
+
+	aper = kmalloc(sizeof(*aper), GFP_KERNEL);
+	if (aper == NULL) return -ENOMEM;
+
+	aper->arena = agp->hose->sg_pci;
+	aper->pg_count = alpha_agpgart_size / PAGE_SIZE;
+	aper->pg_start = iommu_reserve(aper->arena, aper->pg_count,
+				       aper->pg_count - 1);
+
+	if (aper->pg_start < 0) {
+		printk(KERN_ERR "Failed to reserve AGP memory\n");
+		kfree(aper);
+		return -ENOMEM;
+	}
+
+	agp->aperture.bus_base = 
+		aper->arena->dma_base + aper->pg_start * PAGE_SIZE;
+	agp->aperture.size = aper->pg_count * PAGE_SIZE;
+	agp->aperture.sysdata = aper;
+
+	return 0;
+}
+
+static void
+marvel_agp_cleanup(alpha_agp_info *agp)
+{
+	struct marvel_agp_aperture *aper = agp->aperture.sysdata;
+	int status;
+
+	status = iommu_release(aper->arena, aper->pg_start, aper->pg_count);
+	if (status == -EBUSY) {
+		printk(KERN_WARNING
+		       "Attempted to release bound AGP memory - unbinding\n");
+		iommu_unbind(aper->arena, aper->pg_start, aper->pg_count);
+		status = iommu_release(aper->arena, aper->pg_start, 
+				       aper->pg_count);
+	}
+	if (status < 0)
+		printk(KERN_ERR "Failed to release AGP memory\n");
+
+	kfree(aper);
+	kfree(agp);
+}
+
+static int
+marvel_agp_configure(alpha_agp_info *agp)
+{
+	io7_ioport_csrs *csrs = ((struct io7_port *)agp->hose->sysdata)->csrs;
+	struct io7 *io7 = ((struct io7_port *)agp->hose->sysdata)->io7;
+	unsigned int new_rate = 0;
+	unsigned long agp_pll;
+
+	/*
+	 * Check the requested mode against the PLL setting.
+	 * The agpgart_be code has not programmed the card yet,
+	 * so we can still tweak mode here.
+	 */
+	agp_pll = io7->csrs->POx_RST[IO7_AGP_PORT].csr;
+	switch(IO7_PLL_RNGB(agp_pll)) {
+	case 0x4:				/* 2x only */
+		/* 
+		 * The PLL is only programmed for 2x, so adjust the
+		 * rate to 2x, if necessary.
+		 */
+		if (agp->mode.bits.rate != 2) 
+			new_rate = 2;
+		break;
+
+	case 0x6:				/* 1x / 4x */
+		/*
+		 * The PLL is programmed for 1x or 4x.  Don't go faster
+		 * than requested, so if the requested rate is 2x, use 1x.
+		 */
+		if (agp->mode.bits.rate == 2) 
+			new_rate = 1;
+		break;
+
+	default:				/* ??????? */
+		/*
+		 * Don't know what this PLL setting is, take the requested
+		 * rate, but warn the user.
+		 */
+		printk("%s: unknown PLL setting RNGB=%lx (PLL6_CTL=%016lx)\n",
+		       __FUNCTION__, IO7_PLL_RNGB(agp_pll), agp_pll);
+		break;
+	}
+
+	/*
+	 * Set the new rate, if necessary.
+	 */
+	if (new_rate) {
+		printk("Requested AGP Rate %dX not compatible "
+		       "with PLL setting - using %dX\n",
+		       agp->mode.bits.rate,
+		       new_rate);
+
+		agp->mode.bits.rate = new_rate;
+	}
+		
+	printk("Enabling AGP on hose %d: %dX%s RQ %d\n", 
+	       agp->hose->index, agp->mode.bits.rate, 
+	       agp->mode.bits.sba ? " - SBA" : "", agp->mode.bits.rq);
+
+	csrs->AGP_CMD.csr = agp->mode.lw;
+
+	return 0;
+}
+
+static int 
+marvel_agp_bind_memory(alpha_agp_info *agp, off_t pg_start, agp_memory *mem)
+{
+	struct marvel_agp_aperture *aper = agp->aperture.sysdata;
+	return iommu_bind(aper->arena, aper->pg_start + pg_start, 
+			  mem->page_count, mem->memory);
+}
+
+static int 
+marvel_agp_unbind_memory(alpha_agp_info *agp, off_t pg_start, agp_memory *mem)
+{
+	struct marvel_agp_aperture *aper = agp->aperture.sysdata;
+	return iommu_unbind(aper->arena, aper->pg_start + pg_start,
+			    mem->page_count);
+}
+
+static unsigned long
+marvel_agp_translate(alpha_agp_info *agp, dma_addr_t addr)
+{
+	struct marvel_agp_aperture *aper = agp->aperture.sysdata;
+	unsigned long baddr = addr - aper->arena->dma_base;
+	unsigned long pte;
+
+	if (addr < agp->aperture.bus_base ||
+	    addr >= agp->aperture.bus_base + agp->aperture.size) {
+		printk("%s: addr out of range\n", __FUNCTION__);
+		return -EINVAL;
+	}
+
+	pte = aper->arena->ptes[baddr >> PAGE_SHIFT];
+	if (!(pte & 1)) {
+		printk("%s: pte not valid\n", __FUNCTION__);
+		return -EINVAL;
+	} 
+	return (pte >> 1) << PAGE_SHIFT;
+}
+
+struct alpha_agp_ops marvel_agp_ops =
+{
+	setup:		marvel_agp_setup,
+	cleanup:	marvel_agp_cleanup,
+	configure:	marvel_agp_configure,
+	bind:		marvel_agp_bind_memory,
+	unbind:		marvel_agp_unbind_memory,
+	translate:	marvel_agp_translate
+};
+
+alpha_agp_info *
+marvel_agp_info(void)
+{
+	struct pci_controller *hose;
+	io7_ioport_csrs *csrs;
+	alpha_agp_info *agp;
+	struct io7 *io7;
+
+	/*
+	 * Find the first IO7 with an AGP card.
+	 *
+	 * FIXME -- there should be a better way (we want to be able to
+	 * specify and what if the agp card is not video???)
+	 */
+	hose = NULL;
+	for (io7 = NULL; (io7 = marvel_next_io7(io7)) != NULL; ) {
+		struct pci_controller *h;
+		vuip addr;
+
+		if (!io7->ports[IO7_AGP_PORT].enabled)
+			continue;
+
+		h = io7->ports[IO7_AGP_PORT].hose;
+		addr = (vuip)build_conf_addr(h, 0, PCI_DEVFN(5, 0), 0);
+
+		if (*addr != 0xffffffffu) {
+			hose = h;
+			break;
+		}
+	}
+
+	if (!hose || !hose->sg_pci)
+		return NULL;
+
+	printk("MARVEL - using hose %d as AGP\n", hose->index);
+
+	/* 
+	 * Get the csrs from the hose.
+	 */
+	csrs = ((struct io7_port *)hose->sysdata)->csrs;
+
+	/*
+	 * Allocate the info structure.
+	 */
+	agp = kmalloc(sizeof(*agp), GFP_KERNEL);
+
+	/*
+	 * Fill it in.
+	 */
+	agp->type = 0 /* FIXME: ALPHA_CORE_AGP */;
+	agp->hose = hose;
+	agp->private = NULL;
+	agp->ops = &marvel_agp_ops;
+
+	/*
+	 * Aperture - not configured until ops.setup().
+	 */
+	agp->aperture.bus_base = 0;
+	agp->aperture.size = 0;
+	agp->aperture.sysdata = NULL;
+
+	/*
+	 * Capabilities.
+	 *
+	 * NOTE: IO7 reports through AGP_STAT that it can support a read queue
+	 *       depth of 17 (rq = 0x10). It actually only supports a depth of
+	 * 	 16 (rq = 0xf).
+	 */
+	agp->capability.lw = csrs->AGP_STAT.csr;
+	agp->capability.bits.rq = 0xf;
+	
+	/*
+	 * Mode.
+	 */
+	agp->mode.lw = csrs->AGP_CMD.csr;
+
+	return agp;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/core_t2.c linux-2.4.21-pre6/arch/alpha/kernel/core_t2.c
--- linux-2.4.20/arch/alpha/kernel/core_t2.c	2001-03-02 19:12:07.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/kernel/core_t2.c	2003-03-26 23:48:58.000000000 +0000
@@ -26,6 +26,18 @@
 #include "proto.h"
 #include "pci_impl.h"
 
+/*
+ * By default, we direct-map starting at 2GB, in order to allow the
+ * maximum size direct-map window (2GB) to match the maximum amount of
+ * memory (2GB) that can be present on SABLEs. But that limits the
+ * floppy to DMA only via the scatter/gather window set up for 8MB
+ * ISA DMA, since the maximum ISA DMA address is 2GB-1.
+ *
+ * For now, this seems a reasonable trade-off: even though most SABLEs
+ * have far less than even 1GB of memory, floppy usage/performance will
+ * not really be affected by forcing it to go via scatter/gather...
+ */
+#define T2_DIRECTMAP_2G 1
 
 /*
  * NOTE: Herein lie back-to-back mb instructions.  They are magic. 
@@ -325,6 +337,7 @@
 t2_init_arch(void)
 {
 	struct pci_controller *hose;
+	unsigned long t2_iocsr;
 	unsigned int i;
 
 	for (i = 0; i < NR_CPUS; i++) {
@@ -333,43 +346,80 @@
 	}
 
 #if 0
-	{
-	  /* Set up error reporting.  */
-	  unsigned long t2_err;
+	/* Set up error reporting.  */
+	t2_iocsr = *(vulp)T2_IOCSR;
+	*(vulp)T2_IOCSR = t2_iocsr | (0x1UL << 7); /* TLB error check */
+	mb();
+	*(vulp)T2_IOCSR; /* read it back to make sure */
+#endif
 
-	  t2_err = *(vulp)T2_IOCSR;
-	  t2_err |= (0x1 << 7);   /* master abort */
-	  *(vulp)T2_IOCSR = t2_err;
-	  mb();
+	/* Enable scatter/gather TLB use.  */
+	t2_iocsr = *(vulp)T2_IOCSR;
+	if (!(t2_iocsr & (0x1UL << 26))) {
+		printk("t2_init_arch: enabling SG TLB, IOCSR was 0x%lx\n",
+		       t2_iocsr);
+		*(vulp)T2_IOCSR = t2_iocsr | (0x1UL << 26);
+		mb();	
+		*(vulp)T2_IOCSR; /* read it back to make sure */
 	}
-#endif
 
-	printk("t2_init: HBASE was 0x%lx\n", *(vulp)T2_HBASE);
 #if 0
-	printk("t2_init: WBASE1=0x%lx WMASK1=0x%lx TBASE1=0x%lx\n",
-	       *(vulp)T2_WBASE1,
-	       *(vulp)T2_WMASK1,
-	       *(vulp)T2_TBASE1);
-	printk("t2_init: WBASE2=0x%lx WMASK2=0x%lx TBASE2=0x%lx\n",
-	       *(vulp)T2_WBASE2,
-	       *(vulp)T2_WMASK2,
-	       *(vulp)T2_TBASE2);
+	printk("t2_init_arch: HBASE was 0x%lx\n", *(vulp)T2_HBASE);
+	printk("t2_init_arch: WBASE1=0x%lx WMASK1=0x%lx TBASE1=0x%lx\n",
+	       *(vulp)T2_WBASE1, *(vulp)T2_WMASK1, *(vulp)T2_TBASE1);
+	printk("t2_init_arch: WBASE2=0x%lx WMASK2=0x%lx TBASE2=0x%lx\n",
+	       *(vulp)T2_WBASE2, *(vulp)T2_WMASK2, *(vulp)T2_TBASE2);
 #endif
 
 	/*
+	 * Create our single hose.
+	 */
+
+	pci_isa_hose = hose = alloc_pci_controller();
+	hose->io_space = &ioport_resource;
+	hose->mem_space = &iomem_resource;
+	hose->index = 0;
+
+	hose->sparse_mem_base = T2_SPARSE_MEM - IDENT_ADDR;
+	hose->dense_mem_base = T2_DENSE_MEM - IDENT_ADDR;
+	hose->sparse_io_base = T2_IO - IDENT_ADDR;
+	hose->dense_io_base = 0;
+
+	/* Note we can only do 1 SG window, as the other is for direct, so
+	   do an ISA SG area, especially for the floppy. */
+	hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 0);
+	hose->sg_pci = NULL;
+
+	/*
 	 * Set up the PCI->physical memory translation windows.
-	 * For now, window 2 is  disabled.  In the future, we may
-	 * want to use it to do scatter/gather DMA. 
 	 *
-	 * Window 1 goes at 1 GB and is 1 GB large.
+	 * Window 1 goes at ? GB and is ?GB large, direct mapped.
+	 * Window 2 goes at 8 MB and is 8MB large, scatter/gather (for ISA).
 	 */
 
-	/* WARNING!! must correspond to the DMA_WIN params!!! */
+#if T2_DIRECTMAP_2G
+	__direct_map_base = 0x80000000UL;
+	__direct_map_size = 0x80000000UL;
+
+	/* WARNING!! must correspond to the direct map window params!!! */
+	*(vulp)T2_WBASE1 = 0x80080fffU;
+	*(vulp)T2_WMASK1 = 0x7ff00000U;
+	*(vulp)T2_TBASE1 = 0;
+#else /* T2_DIRECTMAP_2G */
+	__direct_map_base = 0x40000000UL;
+	__direct_map_size = 0x40000000UL;
+
+	/* WARNING!! must correspond to the direct map window params!!! */
 	*(vulp)T2_WBASE1 = 0x400807ffU;
 	*(vulp)T2_WMASK1 = 0x3ff00000U;
 	*(vulp)T2_TBASE1 = 0;
+#endif /* T2_DIRECTMAP_2G */
+
+	/* WARNING!! must correspond to the SG arena/window params!!! */
+	*(vulp)T2_WBASE2 = 0x008c000fU;
+	*(vulp)T2_WMASK2 = 0x00700000U;
+	*(vulp)T2_TBASE2 = virt_to_phys(hose->sg_isa->ptes) >> 1;
 
-	*(vulp)T2_WBASE2 = 0x0;
 	*(vulp)T2_HBASE = 0x0;
 
 	/* Zero HAE.  */
@@ -377,26 +427,28 @@
 	*(vulp)T2_HAE_2 = 0; mb();
 	*(vulp)T2_HAE_3 = 0; mb();
 #if 0
-	*(vulp)T2_HAE_4 = 0; mb(); /* do not touch this */
+	*(vulp)T2_HAE_4 = 0; mb(); /* DO NOT TOUCH THIS!!! */
 #endif
 
-	/*
-	 * Create our single hose.
-	 */
+	t2_pci_tbi(hose, 0, -1); /* flush TLB all */
+}
 
-	pci_isa_hose = hose = alloc_pci_controller();
-	hose->io_space = &ioport_resource;
-	hose->mem_space = &iomem_resource;
-	hose->index = 0;
+void
+t2_pci_tbi(struct pci_controller *hose, dma_addr_t start, dma_addr_t end)
+{
+	unsigned long t2_iocsr;
 
-	hose->sparse_mem_base = T2_SPARSE_MEM - IDENT_ADDR;
-	hose->dense_mem_base = T2_DENSE_MEM - IDENT_ADDR;
-	hose->sparse_io_base = T2_IO - IDENT_ADDR;
-	hose->dense_io_base = 0;
+	t2_iocsr = *(vulp)T2_IOCSR;
 
-	hose->sg_isa = hose->sg_pci = NULL;
-	__direct_map_base = 0x40000000;
-	__direct_map_size = 0x40000000;
+	/* set the TLB Clear bit */
+	*(vulp)T2_IOCSR = t2_iocsr | (0x1UL << 28);
+	mb();
+	*(vulp)T2_IOCSR; /* read it back to make sure */
+
+	/* clear the TLB Clear bit */
+	*(vulp)T2_IOCSR = t2_iocsr & ~(0x1UL << 28);
+	mb();
+	*(vulp)T2_IOCSR; /* read it back to make sure */
 }
 
 #define SIC_SEIC (1UL << 33)    /* System Event Clear */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/core_titan.c linux-2.4.21-pre6/arch/alpha/kernel/core_titan.c
--- linux-2.4.20/arch/alpha/kernel/core_titan.c	2001-10-21 17:30:58.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/kernel/core_titan.c	2003-03-26 23:49:21.000000000 +0000
@@ -10,10 +10,13 @@
 #include <linux/pci.h>
 #include <linux/sched.h>
 #include <linux/init.h>
+#include <linux/vmalloc.h>
 
+#include <asm/hwrpb.h>
 #include <asm/ptrace.h>
 #include <asm/system.h>
 #include <asm/smp.h>
+#include <asm/pgalloc.h>
 
 #define __EXTERN_INLINE inline
 #include <asm/io.h>
@@ -25,14 +28,14 @@
 #include "proto.h"
 #include "pci_impl.h"
 
-unsigned TITAN_agp = 0;
+/* Save Titan configuration data as the console had it set up.  */
 
-static struct
+struct
 {
 	unsigned long wsba[4];
 	unsigned long wsm[4];
 	unsigned long tba[4];
-} saved_pachip_port[4];
+} saved_config[4] __attribute__((common));
 
 /*
  * BIOS32-style PCI interface:
@@ -47,6 +50,31 @@
 # define DBG_CFG(args)
 #endif
 
+
+/*
+ * Routines to access TIG registers.
+ */
+static inline volatile unsigned long *
+mk_tig_addr(int offset)
+{
+	return (volatile unsigned long *)(TITAN_TIG_SPACE + (offset << 6));
+}
+
+static inline u8 
+titan_read_tig(int offset, u8 value)
+{
+	volatile unsigned long *tig_addr = mk_tig_addr(offset);
+	return (u8)(*tig_addr & 0xff);
+}
+
+static inline void 
+titan_write_tig(int offset, u8 value)
+{
+	volatile unsigned long *tig_addr = mk_tig_addr(offset);
+	*tig_addr = (unsigned long)value;
+}
+
+
 /*
  * Given a bus, device, and function number, compute resulting
  * configuration space address
@@ -94,7 +122,7 @@
 		 "pci_addr=0x%p, type1=0x%p)\n",
 		 bus, device_fn, where, pci_addr, type1));
 
-        if (hose->first_busno == dev->bus->number)
+        if (hose->first_busno == bus)
 		bus = 0;
         *type1 = (bus != 0);
 
@@ -210,13 +238,16 @@
 	volatile unsigned long *csr;
 	unsigned long value;
 
-	/* Get the right hose */
+	/* Get the right hose.  */
 	port = &pachip->g_port;
 	if (hose->index & 2) 
 		port = &pachip->a_port;
 
 	/* We can invalidate up to 8 tlb entries in a go.  The flush
-	   matches against <31:16> in the pci address.  */
+	   matches against <31:16> in the pci address.  
+	   Note that gtlbi* and atlbi* are in the same place in the g_port
+	   and a_port, respectively, so the g_port offset can be used
+	   even if hose is an a_port */
 	csr = &port->port_specific.g.gtlbia.csr;
 	if (((start ^ end) & 0xffff0000) == 0)
 		csr = &port->port_specific.g.gtlbiv.csr;
@@ -231,9 +262,7 @@
 	*csr;
 }
 
-#define FN __FUNCTION__
-
-static int __init
+static int
 titan_query_agp(titan_pachip_port *port)
 {
 	union TPAchipPCTL pctl;
@@ -244,42 +273,11 @@
 	return pctl.pctl_r_bits.apctl_v_agp_present;
 
 }
-static void __init
-titan_init_agp(titan_pachip_port *port, struct pci_controller *hose)
-{
-	union TPAchipPCTL pctl;
-
-	if (!titan_query_agp(port))
-		return;
-
-	printk("AGP present on hose %d\n", hose->index);
-
-	/* get APCTL */
-	pctl.pctl_q_whole = port->pctl.csr;
-
-
-	pctl.pctl_r_bits.apctl_v_agp_en = 1;	/* enable AGP */
-	pctl.pctl_r_bits.apctl_v_agp_lp_rd = 0;	
-	pctl.pctl_r_bits.apctl_v_agp_hp_rd = 0;	
-
-	port->pctl.csr = pctl.pctl_q_whole;
-
-	TITAN_agp |= 1 << hose->index;
-
-#ifdef CONFIG_VGA_HOSE	
-	/* is a graphics card on the AGP? (always device 5) */
-	if (hose != NULL &&
-	    __kernel_ldwu(*(vusp)(hose->config_space_base + 0x280a)) == 
-	    PCI_CLASS_DISPLAY_VGA)
-		set_vga_hose(hose);
-#endif
-}
 
 static void __init
 titan_init_one_pachip_port(titan_pachip_port *port, int index)
 {
 	struct pci_controller *hose;
-	unsigned long sg_size;
 
 	hose = alloc_pci_controller();
 	if (index == 0)
@@ -287,10 +285,13 @@
 	hose->io_space = alloc_resource();
 	hose->mem_space = alloc_resource();
 
-	/* This is for userland consumption.  For some reason, the 40-bit
-	   PIO bias that we use in the kernel through KSEG didn't work for
-	   the page table based user mappings.  So make sure we get the
-	   43-bit PIO bias.  */
+	/*
+	 * This is for userland consumption.  The 40-bit PIO bias that we 
+	 * use in the kernel through KSEG doesn't work in the page table 
+	 * based user mappings. (43-bit KSEG sign extends the physical
+	 * address from bit 40 to hit the I/O bit - mapped addresses don't).
+	 * So make sure we get the 43-bit PIO bias.  
+	 */
 	hose->sparse_mem_base = 0;
 	hose->sparse_io_base = 0;
 	hose->dense_mem_base
@@ -316,65 +317,64 @@
 	if (request_resource(&iomem_resource, hose->mem_space) < 0)
 		printk(KERN_ERR "Failed to request MEM on hose %d\n", index);
 
-	/* It's safe to call this for both G-Ports and A-Ports */
-	titan_init_agp(port, hose);
-
 	/*
 	 * Save the existing PCI window translations.  SRM will 
 	 * need them when we go to reboot.
 	 */
-	saved_pachip_port[index].wsba[0] = port->wsba[0].csr;
-	saved_pachip_port[index].wsm[0]  = port->wsm[0].csr;
-	saved_pachip_port[index].tba[0]  = port->tba[0].csr;
-
-	saved_pachip_port[index].wsba[1] = port->wsba[1].csr;
-	saved_pachip_port[index].wsm[1]  = port->wsm[1].csr;
-	saved_pachip_port[index].tba[1]  = port->tba[1].csr;
-
-	saved_pachip_port[index].wsba[2] = port->wsba[2].csr;
-	saved_pachip_port[index].wsm[2]  = port->wsm[2].csr;
-	saved_pachip_port[index].tba[2]  = port->tba[2].csr;
-
-	saved_pachip_port[index].wsba[3] = port->wsba[3].csr;
-	saved_pachip_port[index].wsm[3]  = port->wsm[3].csr;
-	saved_pachip_port[index].tba[3]  = port->tba[3].csr;
+	saved_config[index].wsba[0] = port->wsba[0].csr;
+	saved_config[index].wsm[0]  = port->wsm[0].csr;
+	saved_config[index].tba[0]  = port->tba[0].csr;
+
+	saved_config[index].wsba[1] = port->wsba[1].csr;
+	saved_config[index].wsm[1]  = port->wsm[1].csr;
+	saved_config[index].tba[1]  = port->tba[1].csr;
+
+	saved_config[index].wsba[2] = port->wsba[2].csr;
+	saved_config[index].wsm[2]  = port->wsm[2].csr;
+	saved_config[index].tba[2]  = port->tba[2].csr;
+
+	saved_config[index].wsba[3] = port->wsba[3].csr;
+	saved_config[index].wsm[3]  = port->wsm[3].csr;
+	saved_config[index].tba[3]  = port->tba[3].csr;
 
 	/*
 	 * Set up the PCI to main memory translation windows.
 	 *
-	 * Note: Window 3 on Titan is Scatter-Gather ONLY
+	 * Note: Window 3 on Titan is Scatter-Gather ONLY.
 	 *
 	 * Window 0 is scatter-gather 8MB at 8MB (for isa)
-	 * Window 1 is scatter-gather (up to) 1GB at 1GB
-	 * Window 2 is direct access 2GB at 2GB
+	 * Window 1 is direct access 1GB at 2GB
+	 * Window 2 is scatter-gather 1GB at 3GB
 	 */
 	hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 0);
 	hose->sg_isa->align_entry = 8; /* 64KB for ISA */
 
-	hose->sg_pci = iommu_arena_new(hose, 0x40000000,
-				       size_for_memory(0x40000000), 0);
+	hose->sg_pci = iommu_arena_new(hose, 0xc0000000, 0x40000000, 0);
 	hose->sg_pci->align_entry = 4; /* Titan caches 4 PTEs at a time */
 
-	__direct_map_base = 0x80000000;
-	__direct_map_size = 0x80000000;
-
 	port->wsba[0].csr = hose->sg_isa->dma_base | 3;
 	port->wsm[0].csr  = (hose->sg_isa->size - 1) & 0xfff00000;
 	port->tba[0].csr  = virt_to_phys(hose->sg_isa->ptes);
 
-	port->wsba[1].csr = hose->sg_pci->dma_base | 3;
-	port->wsm[1].csr  = (hose->sg_pci->size - 1) & 0xfff00000;
-	port->tba[1].csr  = virt_to_phys(hose->sg_pci->ptes);
-
-	port->wsba[2].csr = 0x80000000 | 1;
-	port->wsm[2].csr  = (0x80000000 - 1) & 0xfff00000;
-	port->tba[2].csr  = 0;
+	port->wsba[1].csr = __direct_map_base | 1;
+	port->wsm[1].csr  = (__direct_map_size - 1) & 0xfff00000;
+	port->tba[1].csr  = 0;
+
+	port->wsba[2].csr = hose->sg_pci->dma_base | 3;
+	port->wsm[2].csr  = (hose->sg_pci->size - 1) & 0xfff00000;
+	port->tba[2].csr  = virt_to_phys(hose->sg_pci->ptes);
 
 	port->wsba[3].csr = 0;
 
-	/* Enable the Monster Window to make DAC pci64 possible. */
+	/* Enable the Monster Window to make DAC pci64 possible.  */
 	port->pctl.csr |= pctl_m_mwin;
 
+	/*
+	 * If it's an AGP port, initialize agplastwr.
+	 */
+	if (titan_query_agp(port)) 
+		port->port_specific.a.agplastwr.csr = __direct_map_base;
+
 	titan_pci_tbi(hose, 0, -1);
 }
 
@@ -392,25 +392,51 @@
 		titan_init_one_pachip_port(&pachip1->a_port, 3);/* hose 3 */
 }
 
+static void __init
+titan_init_vga_hose(void)
+{
+#ifdef CONFIG_VGA_HOSE
+	u64 *pu64 = (u64 *)((u64)hwrpb + hwrpb->ctbt_offset);
+
+	if (pu64[7] == 3) {	/* TERM_TYPE == graphics */
+		struct pci_controller *hose;
+		int h = (pu64[30] >> 24) & 0xff;	/* console hose # */
+
+		/*
+		 * Our hose numbering matches the console's, so just find
+		 * the right one...
+		 */
+		for (hose = hose_head; hose; hose = hose->next) {
+			if (hose->index == h) break;
+		}
+
+		if (hose) {
+			printk("Console graphics on hose %d\n", hose->index);
+			pci_vga_hose = hose;
+		}
+	}
+#endif /* CONFIG_VGA_HOSE */
+}
+
 void __init
 titan_init_arch(void)
 {
 #if 0
-	printk("%s: titan_init_arch()\n", FN);
-	printk("%s: CChip registers:\n", FN);
-	printk("%s: CSR_CSC 0x%lx\n", FN, TITAN_cchip->csc.csr);
-	printk("%s: CSR_MTR 0x%lx\n", FN, TITAN_cchip->mtr.csr);
-	printk("%s: CSR_MISC 0x%lx\n", FN, TITAN_cchip->misc.csr);
-	printk("%s: CSR_DIM0 0x%lx\n", FN, TITAN_cchip->dim0.csr);
-	printk("%s: CSR_DIM1 0x%lx\n", FN, TITAN_cchip->dim1.csr);
-	printk("%s: CSR_DIR0 0x%lx\n", FN, TITAN_cchip->dir0.csr);
-	printk("%s: CSR_DIR1 0x%lx\n", FN, TITAN_cchip->dir1.csr);
-	printk("%s: CSR_DRIR 0x%lx\n", FN, TITAN_cchip->drir.csr);
-
-	printk("%s: DChip registers:\n", FN);
-	printk("%s: CSR_DSC 0x%lx\n", FN, TITAN_dchip->dsc.csr);
-	printk("%s: CSR_STR 0x%lx\n", FN, TITAN_dchip->str.csr);
-	printk("%s: CSR_DREV 0x%lx\n", FN, TITAN_dchip->drev.csr);
+	printk("%s: titan_init_arch()\n", __FUNCTION__);
+	printk("%s: CChip registers:\n", __FUNCTION__);
+	printk("%s: CSR_CSC 0x%lx\n", __FUNCTION__, TITAN_cchip->csc.csr);
+	printk("%s: CSR_MTR 0x%lx\n", __FUNCTION__, TITAN_cchip->mtr.csr);
+	printk("%s: CSR_MISC 0x%lx\n", __FUNCTION__, TITAN_cchip->misc.csr);
+	printk("%s: CSR_DIM0 0x%lx\n", __FUNCTION__, TITAN_cchip->dim0.csr);
+	printk("%s: CSR_DIM1 0x%lx\n", __FUNCTION__, TITAN_cchip->dim1.csr);
+	printk("%s: CSR_DIR0 0x%lx\n", __FUNCTION__, TITAN_cchip->dir0.csr);
+	printk("%s: CSR_DIR1 0x%lx\n", __FUNCTION__, TITAN_cchip->dir1.csr);
+	printk("%s: CSR_DRIR 0x%lx\n", __FUNCTION__, TITAN_cchip->drir.csr);
+
+	printk("%s: DChip registers:\n", __FUNCTION__);
+	printk("%s: CSR_DSC 0x%lx\n", __FUNCTION__, TITAN_dchip->dsc.csr);
+	printk("%s: CSR_STR 0x%lx\n", __FUNCTION__, TITAN_dchip->str.csr);
+	printk("%s: CSR_DREV 0x%lx\n", __FUNCTION__, TITAN_dchip->drev.csr);
 #endif
 
 	boot_cpuid = __hard_smp_processor_id();
@@ -419,28 +445,35 @@
 	ioport_resource.end = ~0UL;
 	iomem_resource.end = ~0UL;
 
-	/* Init the PA chip(s) */
+	/* PCI DMA Direct Mapping is 1GB at 2GB.  */
+	__direct_map_base = 0x80000000;
+	__direct_map_size = 0x40000000;
+
+	/* Init the PA chip(s).  */
 	titan_init_pachips(TITAN_pachip0, TITAN_pachip1);
+
+	/* Check for graphic console location (if any).  */
+	titan_init_vga_hose();
 }
 
 static void
 titan_kill_one_pachip_port(titan_pachip_port *port, int index)
 {
-	port->wsba[0].csr = saved_pachip_port[index].wsba[0];
-	port->wsm[0].csr  = saved_pachip_port[index].wsm[0];
-	port->tba[0].csr  = saved_pachip_port[index].tba[0];
-
-	port->wsba[1].csr = saved_pachip_port[index].wsba[1];
-	port->wsm[1].csr  = saved_pachip_port[index].wsm[1];
-	port->tba[1].csr  = saved_pachip_port[index].tba[1];
-
-	port->wsba[2].csr = saved_pachip_port[index].wsba[2];
-	port->wsm[2].csr  = saved_pachip_port[index].wsm[2];
-	port->tba[2].csr  = saved_pachip_port[index].tba[2];
-
-	port->wsba[3].csr = saved_pachip_port[index].wsba[3];
-	port->wsm[3].csr  = saved_pachip_port[index].wsm[3];
-	port->tba[3].csr  = saved_pachip_port[index].tba[3];
+	port->wsba[0].csr = saved_config[index].wsba[0];
+	port->wsm[0].csr  = saved_config[index].wsm[0];
+	port->tba[0].csr  = saved_config[index].tba[0];
+
+	port->wsba[1].csr = saved_config[index].wsba[1];
+	port->wsm[1].csr  = saved_config[index].wsm[1];
+	port->tba[1].csr  = saved_config[index].tba[1];
+
+	port->wsba[2].csr = saved_config[index].wsba[2];
+	port->wsm[2].csr  = saved_config[index].wsm[2];
+	port->tba[2].csr  = saved_config[index].tba[2];
+
+	port->wsba[3].csr = saved_config[index].wsba[3];
+	port->wsm[3].csr  = saved_config[index].wsm[3];
+	port->tba[3].csr  = saved_config[index].tba[3];
 }
 
 static void
@@ -449,8 +482,8 @@
 	int pchip1_present = TITAN_cchip->csc.csr & 1L<<14;
 
 	if (pchip1_present) {
-		titan_kill_one_pachip_port(&pachip0->g_port, 1);
-		titan_kill_one_pachip_port(&pachip0->a_port, 3);
+		titan_kill_one_pachip_port(&pachip1->g_port, 1);
+		titan_kill_one_pachip_port(&pachip1->a_port, 3);
 	}
 	titan_kill_one_pachip_port(&pachip0->g_port, 0);
 	titan_kill_one_pachip_port(&pachip0->a_port, 2);
@@ -462,38 +495,333 @@
 	titan_kill_pachips(TITAN_pachip0, TITAN_pachip1);
 }
 
-static inline void
-titan_pci_clr_err_1(titan_pachip *pachip)
+
+/*
+ * IO map support.
+ */
+unsigned long
+titan_ioremap(unsigned long addr, unsigned long size)
 {
-	unsigned int jd;
+	int h = (addr & TITAN_HOSE_MASK) >> TITAN_HOSE_SHIFT;
+	unsigned long baddr = addr & ~TITAN_HOSE_MASK;
+	unsigned long last = baddr + size - 1;
+	struct pci_controller *hose;	
+	struct vm_struct *area;
+	unsigned long vaddr;
+	unsigned long *ptes;
+	unsigned long pfn;
+
+	/*
+	 * Adjust the addr.
+	 */ 
+#ifdef CONFIG_VGA_HOSE
+	if (pci_vga_hose && __titan_is_mem_vga(addr)) {
+		h = pci_vga_hose->index;
+		addr += pci_vga_hose->mem_space->start;
+	}
+#endif
+
+	/*
+	 * Find the hose.
+	 */
+	for (hose = hose_head; hose; hose = hose->next)
+		if (hose->index == h) break;
+	if (!hose) return (unsigned long)NULL;
+
+	/*
+	 * Is it direct-mapped?
+	 */
+	if ((baddr >= __direct_map_base) && 
+	    ((baddr + size - 1) < __direct_map_base + __direct_map_size)) 
+		return addr - __direct_map_base + TITAN_MEM_BIAS;
+
+	/* 
+	 * Check the scatter-gather arena.
+	 */
+	if (hose->sg_pci &&
+	    baddr >= (unsigned long)hose->sg_pci->dma_base &&
+	    last < (unsigned long)hose->sg_pci->dma_base + hose->sg_pci->size){
+
+		/*
+		 * Adjust the limits (mappings must be page aligned)
+		 */
+		baddr -= hose->sg_pci->dma_base;
+		last -= hose->sg_pci->dma_base;
+		baddr &= PAGE_MASK;
+		size = PAGE_ALIGN(last) - baddr;
+
+		/*
+		 * Map it
+		 */
+		area = get_vm_area(size, VM_IOREMAP);
+		if (!area) return (unsigned long)NULL;
+		ptes = hose->sg_pci->ptes;
+		for (vaddr = (unsigned long)area->addr; 
+		    baddr <= last; 
+		    baddr += PAGE_SIZE, vaddr += PAGE_SIZE) {
+			pfn = ptes[baddr >> PAGE_SHIFT];
+			if (!(pfn & 1)) {
+				printk("ioremap failed... pte not valid...\n");
+				vfree(area->addr);
+				return (unsigned long)NULL;
+			}
+			pfn >>= 1;	/* make it a true pfn */
+			
+			if (__alpha_remap_area_pages(VMALLOC_VMADDR(vaddr), 
+						     pfn << PAGE_SHIFT, 
+						     PAGE_SIZE, 0)) {
+				printk("FAILED to map...\n");
+				vfree(area->addr);
+				return (unsigned long)NULL;
+			}
+		}
+
+		flush_tlb_all();
+
+		vaddr = (unsigned long)area->addr + (addr & ~PAGE_MASK);
+		return vaddr;
+	}
+
+	/*
+	 * Not found - assume legacy ioremap.
+	 */
+	return addr + TITAN_MEM_BIAS;
 
-	jd = pachip->g_port.port_specific.g.gperror.csr;
-	pachip->g_port.port_specific.g.gperror.csr = jd;
-	mb();
-	pachip->g_port.port_specific.g.gperror.csr;
 }
 
-static inline void
-titan_pci_clr_err(void)
+void
+titan_iounmap(unsigned long addr)
 {
-	titan_pci_clr_err_1(TITAN_pachip0);
+	if (((long)addr >> 41) == -2)
+		return;	/* kseg map, nothing to do */
+	if (addr)
+		vfree((void *)(PAGE_MASK & addr)); 
+}
 
-	if (TITAN_cchip->csc.csr & 1L<<14)
-	    titan_pci_clr_err_1(TITAN_pachip1);
+
+/*
+ * AGP GART Support.
+ */
+#include <linux/agp_backend.h>
+#include <asm/agp_backend.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+struct titan_agp_aperture {
+	struct pci_iommu_arena *arena;
+	long pg_start;
+	long pg_count;
+};
+
+static int
+titan_agp_setup(alpha_agp_info *agp)
+{
+	struct titan_agp_aperture *aper;
+
+	if (!alpha_agpgart_size)
+		return -ENOMEM;
+
+	aper = kmalloc(sizeof(struct titan_agp_aperture), GFP_KERNEL);
+	if (aper == NULL)
+		return -ENOMEM;
+
+	aper->arena = agp->hose->sg_pci;
+	aper->pg_count = alpha_agpgart_size / PAGE_SIZE;
+	aper->pg_start = iommu_reserve(aper->arena, aper->pg_count,
+				       aper->pg_count - 1);
+	if (aper->pg_start < 0) {
+		printk(KERN_ERR "Failed to reserve AGP memory\n");
+		kfree(aper);
+		return -ENOMEM;
+	}
+
+	agp->aperture.bus_base = 
+		aper->arena->dma_base + aper->pg_start * PAGE_SIZE;
+	agp->aperture.size = aper->pg_count * PAGE_SIZE;
+	agp->aperture.sysdata = aper;
+
+	return 0;
 }
 
-void
-titan_machine_check(unsigned long vector, unsigned long la_ptr,
-		      struct pt_regs * regs)
+static void
+titan_agp_cleanup(alpha_agp_info *agp)
 {
-	/* clear error before any reporting. */
-	mb();
-	draina();
-	titan_pci_clr_err();
-	wrmces(0x7);
-	mb();
+	struct titan_agp_aperture *aper = agp->aperture.sysdata;
+	int status;
 
-	process_mcheck_info(vector, la_ptr, regs, "TITAN",
-			    mcheck_expected(smp_processor_id()));
+	status = iommu_release(aper->arena, aper->pg_start, aper->pg_count);
+	if (status == -EBUSY) {
+		printk(KERN_WARNING 
+		       "Attempted to release bound AGP memory - unbinding\n");
+		iommu_unbind(aper->arena, aper->pg_start, aper->pg_count);
+		status = iommu_release(aper->arena, aper->pg_start, 
+				       aper->pg_count);
+	}
+	if (status < 0)
+		printk(KERN_ERR "Failed to release AGP memory\n");
+
+	kfree(aper);
+	kfree(agp);
 }
 
+static int
+titan_agp_configure(alpha_agp_info *agp)
+{
+	union TPAchipPCTL pctl;
+	titan_pachip_port *port = agp->private;
+	pctl.pctl_q_whole = port->pctl.csr;
+
+	/* Side-Band Addressing? */
+	pctl.pctl_r_bits.apctl_v_agp_sba_en = agp->mode.bits.sba;
+
+	/* AGP Rate? */
+	pctl.pctl_r_bits.apctl_v_agp_rate = 0;		/* 1x */
+	if (agp->mode.bits.rate & 2) 
+		pctl.pctl_r_bits.apctl_v_agp_rate = 1;	/* 2x */
+#if 0
+	if (agp->mode.bits.rate & 4) 
+		pctl.pctl_r_bits.apctl_v_agp_rate = 2;	/* 4x */
+#endif
+	
+	/* RQ Depth? */
+	pctl.pctl_r_bits.apctl_v_agp_hp_rd = 2;
+	pctl.pctl_r_bits.apctl_v_agp_lp_rd = 7;
+
+	/*
+	 * AGP Enable.
+	 */
+	pctl.pctl_r_bits.apctl_v_agp_en = agp->mode.bits.enable;
+
+	/* Tell the user.  */
+	printk("Enabling AGP: %dX%s\n", 
+	       1 << pctl.pctl_r_bits.apctl_v_agp_rate,
+	       pctl.pctl_r_bits.apctl_v_agp_sba_en ? " - SBA" : "");
+	       
+	/* Write it.  */
+	port->pctl.csr = pctl.pctl_q_whole;
+	
+	/* And wait at least 5000 66MHz cycles (per Titan spec).  */
+	udelay(100);
+
+	return 0;
+}
+
+static int 
+titan_agp_bind_memory(alpha_agp_info *agp, off_t pg_start, agp_memory *mem)
+{
+	struct titan_agp_aperture *aper = agp->aperture.sysdata;
+	return iommu_bind(aper->arena, aper->pg_start + pg_start, 
+			  mem->page_count, mem->memory);
+}
+
+static int 
+titan_agp_unbind_memory(alpha_agp_info *agp, off_t pg_start, agp_memory *mem)
+{
+	struct titan_agp_aperture *aper = agp->aperture.sysdata;
+	return iommu_unbind(aper->arena, aper->pg_start + pg_start,
+			    mem->page_count);
+}
+
+static unsigned long
+titan_agp_translate(alpha_agp_info *agp, dma_addr_t addr)
+{
+	struct titan_agp_aperture *aper = agp->aperture.sysdata;
+	unsigned long baddr = addr - aper->arena->dma_base;
+	unsigned long pte;
+
+	if (addr < agp->aperture.bus_base ||
+	    addr >= agp->aperture.bus_base + agp->aperture.size) {
+		printk("%s: addr out of range\n", __FUNCTION__);
+		return -EINVAL;
+	}
+
+	pte = aper->arena->ptes[baddr >> PAGE_SHIFT];
+	if (!(pte & 1)) {
+		printk("%s: pte not valid\n", __FUNCTION__);
+		return -EINVAL;
+	}
+
+	return (pte >> 1) << PAGE_SHIFT;
+}
+
+struct alpha_agp_ops titan_agp_ops =
+{
+	setup:		titan_agp_setup,
+	cleanup:	titan_agp_cleanup,
+	configure:	titan_agp_configure,
+	bind:		titan_agp_bind_memory,
+	unbind:		titan_agp_unbind_memory,
+	translate:	titan_agp_translate
+};
+
+alpha_agp_info *
+titan_agp_info(void)
+{
+	alpha_agp_info *agp;
+	struct pci_controller *hose;
+	titan_pachip_port *port;
+	int hosenum = -1;
+	union TPAchipPCTL pctl;
+
+	/*
+	 * Find the AGP port.
+	 */
+	port = &TITAN_pachip0->a_port;
+	if (titan_query_agp(port))
+		hosenum = 2;
+	if (hosenum < 0 && 
+	    titan_query_agp(port = &TITAN_pachip1->a_port)) 
+		hosenum = 3;
+	
+	/*
+	 * Find the hose the port is on.
+	 */
+	for (hose = hose_head; hose; hose = hose->next)
+		if (hose->index == hosenum)
+			break;
+
+	if (!hose || !hose->sg_pci)
+		return NULL;
+
+	/*
+	 * Allocate the info structure.
+	 */
+	agp = kmalloc(sizeof(*agp), GFP_KERNEL);
+
+	/*
+	 * Fill it in.
+	 */
+	agp->type = 0 /* FIXME: ALPHA_CORE_AGP */;
+	agp->hose = hose;
+	agp->private = port;
+	agp->ops = &titan_agp_ops;
+
+	/*
+	 * Aperture - not configured until ops.setup().
+	 *
+	 * FIXME - should we go ahead and allocate it here?
+	 */
+	agp->aperture.bus_base = 0;
+	agp->aperture.size = 0;
+	agp->aperture.sysdata = NULL;
+
+	/*
+	 * Capabilities.
+	 */
+	agp->capability.lw = 0;
+	agp->capability.bits.rate = 3; 	/* 2x, 1x */
+	agp->capability.bits.sba = 1;
+	agp->capability.bits.rq = 7;	/* 8 - 1 */
+
+	/*
+	 * Mode.
+	 */
+	pctl.pctl_q_whole = port->pctl.csr;
+	agp->mode.lw = 0;
+	agp->mode.bits.rate = 1 << pctl.pctl_r_bits.apctl_v_agp_rate;
+	agp->mode.bits.sba = pctl.pctl_r_bits.apctl_v_agp_sba_en;
+	agp->mode.bits.rq = 7;	/* RQ Depth? */
+	agp->mode.bits.enable = pctl.pctl_r_bits.apctl_v_agp_en;
+
+	return agp;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/core_tsunami.c linux-2.4.21-pre6/arch/alpha/kernel/core_tsunami.c
--- linux-2.4.20/arch/alpha/kernel/core_tsunami.c	2001-10-21 17:30:58.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/kernel/core_tsunami.c	2003-03-26 23:49:29.000000000 +0000
@@ -350,10 +350,17 @@
 	 * Window 0 is scatter-gather 8MB at 8MB (for isa)
 	 * Window 1 is scatter-gather (up to) 1GB at 1GB
 	 * Window 2 is direct access 2GB at 2GB
+	 *
+	 * NOTE: we need the align_entry settings for Acer devices on ES40,
+	 * specifically floppy and IDE when memory is larger than 2GB.
 	 */
 	hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 0);
+	/* Initially set for 4 PTEs, but will be overridden to 64K for ISA. */
+	hose->sg_isa->align_entry = 4;
+
 	hose->sg_pci = iommu_arena_new(hose, 0x40000000,
 				       size_for_memory(0x40000000), 0);
+	hose->sg_pci->align_entry = 4; /* Tsunami caches 4 PTEs at a time */
 
 	__direct_map_base = 0x80000000;
 	__direct_map_size = 0x80000000;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/core_wildfire.c linux-2.4.21-pre6/arch/alpha/kernel/core_wildfire.c
--- linux-2.4.20/arch/alpha/kernel/core_wildfire.c	2001-03-02 19:12:07.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/kernel/core_wildfire.c	2003-03-26 23:48:57.000000000 +0000
@@ -475,6 +475,33 @@
 	write_dword:	wildfire_write_config_dword
 };
 
+
+/*
+ * NUMA Support
+ */
+int wildfire_pa_to_nid(unsigned long pa)
+{
+	return pa >> 36;
+}
+
+int wildfire_cpuid_to_nid(int cpuid)
+{
+	/* assume 4 CPUs per node */
+	return cpuid >> 2;
+}
+
+unsigned long wildfire_node_mem_start(int nid)
+{
+	/* 64GB per node */
+	return (unsigned long)nid * (64UL * 1024 * 1024 * 1024);
+}
+
+unsigned long wildfire_node_mem_size(int nid)
+{
+	/* 64GB per node */
+	return 64UL * 1024 * 1024 * 1024;
+}
+
 #if DEBUG_DUMP_REGS
 
 static void __init
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/entry.S linux-2.4.21-pre6/arch/alpha/kernel/entry.S
--- linux-2.4.20/arch/alpha/kernel/entry.S	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/kernel/entry.S	2003-03-26 23:48:57.000000000 +0000
@@ -231,12 +231,12 @@
 .end	kernel_clone
 
 /*
- * kernel_thread(fn, arg, clone_flags)
+ * arch_kernel_thread(fn, arg, clone_flags)
  */
 .align 3
 .globl	kernel_thread
 .ent	kernel_thread
-kernel_thread:
+arch_kernel_thread:
 	ldgp	$29,0($27)	/* we can be called from a module */
 	.frame $30, 4*8, $26
 	subq	$30,4*8,$30
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/err_common.c linux-2.4.21-pre6/arch/alpha/kernel/err_common.c
--- linux-2.4.20/arch/alpha/kernel/err_common.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/kernel/err_common.c	2003-03-26 23:49:06.000000000 +0000
@@ -0,0 +1,772 @@
+/*
+ *	linux/arch/alpha/kernel/err_common.c
+ *
+ *	Copyright (C) 2000 Jeff Wiedemeier (Compaq Computer Corporation)
+ *
+ *	Error handling code supporting Alpha systems
+ */
+
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+
+#include <asm/io.h>
+#include <asm/hwrpb.h>
+#include <asm/smp.h>
+
+#include "err_impl.h"
+#include "proto.h"
+
+/*
+ * err_print_prefix -- error handling print routines should prefix
+ * all prints with this
+ */
+char *err_print_prefix = KERN_NOTICE;
+
+/*
+ * Forward references
+ */
+static void el_print_timestamp(union el_timestamp);
+static void el_process_subpackets(struct el_subpacket *, int);
+
+
+/*
+ * Generic
+ */
+void
+mchk_dump_mem(void *data, size_t length, char **annotation)
+{
+	unsigned long *ldata = data;
+	size_t i;
+	
+	for (i = 0; (i * sizeof(*ldata)) < length; i++) {
+		if (annotation && !annotation[i]) 
+			annotation = NULL;
+		printk("%s    %08x: %016lx    %s\n",
+		       err_print_prefix,
+		       (unsigned)(i * sizeof(*ldata)), ldata[i],
+		       annotation ? annotation[i] : "");
+	}
+}
+
+void
+mchk_dump_logout_frame(struct el_common *mchk_header)
+{
+	printk("%s  -- Frame Header --\n"
+	         "    Frame Size:   %d (0x%x) bytes\n"
+	         "    Flags:        %s%s\n"
+	         "    MCHK Code:    0x%x\n"
+	         "    Frame Rev:    %d\n"
+	         "    Proc Offset:  0x%08x\n"
+	         "    Sys Offset:   0x%08x\n"
+  	         "  -- Processor Region --\n",
+	       err_print_prefix, 
+	       mchk_header->size, mchk_header->size,
+	       mchk_header->retry ? "RETRY " : "", 
+  	         mchk_header->err2 ? "SECOND_ERR " : "",
+	       mchk_header->code,
+	       mchk_header->frame_rev,
+	       mchk_header->proc_offset,
+	       mchk_header->sys_offset);
+
+	mchk_dump_mem((void *)
+		      ((unsigned long)mchk_header + mchk_header->proc_offset),
+		      mchk_header->sys_offset - mchk_header->proc_offset,
+		      NULL);
+	
+	printk("%s  -- System Region --\n", err_print_prefix);
+	mchk_dump_mem((void *)
+		      ((unsigned long)mchk_header + mchk_header->sys_offset),
+		      mchk_header->size - mchk_header->sys_offset,
+		      NULL);
+	printk("%s  -- End of Frame --\n", err_print_prefix);
+}
+
+
+/*
+ * EV7 generic
+ */
+#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_EV7)
+
+void
+ev7_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs)
+{
+	/*
+	 * Sync the processor
+	 */
+	mb();
+	draina();
+
+	/*
+	 * Parse the logout frame without printing first. If the only error(s)
+	 * found are have a disposition of "dismiss", then just dismiss them
+	 * and don't print any message
+	 */
+	printk("%sEV7 MACHINE CHECK vector %lx\n", err_print_prefix, vector);
+
+	/* 
+	 * Release the logout frame 
+	 */
+	wrmces(0x7);
+	mb();
+}
+
+struct ev7_pal_subpacket {
+	union {
+		struct {
+			u32 mchk_code;
+			u32 subpacket_count;
+			u64 whami;
+			u64 rbox_whami;
+			u64 rbox_int;
+			u64 exc_addr;
+			union el_timestamp timestamp;
+			u64 halt_code;
+			u64 reserved;
+		} logout;
+	} by_type;
+};
+
+static char *el_ev7_processor_subpacket_annotation[] = {
+	"Subpacket Header",	"I_STAT",	"DC_STAT",
+	"C_ADDR",		"C_SYNDROME_1",	"C_SYNDROME_0",
+	"C_STAT",		"C_STS",	"MM_STAT",
+	"EXC_ADDR",		"IER_CM",	"ISUM",
+	"PAL_BASE",		"I_CTL",	"PROCESS_CONTEXT",
+	"CBOX_CTL",		"CBOX_STP_CTL",	"CBOX_ACC_CTL",
+	"CBOX_LCL_SET",		"CBOX_GLB_SET",	"BBOX_CTL",
+	"BBOX_ERR_STS",		"BBOX_ERR_IDX",	"CBOX_DDP_ERR_STS",
+	"BBOX_DAT_RMP",		NULL
+};
+
+static char *el_ev7_zbox_subpacket_annotation[] = {
+	"Subpacket Header", 	
+	"ZBOX(0): DRAM_ERR_STATUS_2 / DRAM_ERR_STATUS_1",
+	"ZBOX(0): DRAM_ERROR_CTL    / DRAM_ERR_STATUS_3",
+	"ZBOX(0): DIFT_TIMEOUT      / DRAM_ERR_ADR",
+	"ZBOX(0): FRC_ERR_ADR       / DRAM_MAPPER_CTL",
+	"ZBOX(0): reserved          / DIFT_ERR_STATUS",
+	"ZBOX(1): DRAM_ERR_STATUS_2 / DRAM_ERR_STATUS_1",
+	"ZBOX(1): DRAM_ERROR_CTL    / DRAM_ERR_STATUS_3",
+	"ZBOX(1): DIFT_TIMEOUT      / DRAM_ERR_ADR",
+	"ZBOX(1): FRC_ERR_ADR       / DRAM_MAPPER_CTL",
+	"ZBOX(1): reserved          / DIFT_ERR_STATUS",
+	"CBOX_CTL",		"CBOX_STP_CTL",
+	"ZBOX(0)_ERROR_PA",	"ZBOX(1)_ERROR_PA",
+	"ZBOX(0)_ORED_SYNDROME","ZBOX(1)_ORED_SYNDROME",
+	NULL
+};
+
+static char *el_ev7_rbox_subpacket_annotation[] = {
+	"Subpacket Header",	"RBOX_CFG",	"RBOX_N_CFG",
+	"RBOX_S_CFG",		"RBOX_E_CFG",	"RBOX_W_CFG",
+	"RBOX_N_ERR",		"RBOX_S_ERR",	"RBOX_E_ERR",
+	"RBOX_W_ERR",		"RBOX_IO_CFG",	"RBOX_IO_ERR",
+	"RBOX_L_ERR",		"RBOX_WHOAMI",	"RBOX_IMASL",
+	"RBOX_INTQ",		"RBOX_INT",	NULL
+};
+
+static char *el_ev7_io_subpacket_annotation[] = {
+	"Subpacket Header",	"IO_ASIC_REV",	"IO_SYS_REV",
+	"IO7_UPH",		"HPI_CTL",	"CRD_CTL",
+	"HEI_CTL",		"PO7_ERROR_SUM","PO7_UNCRR_SYM",
+	"PO7_CRRCT_SYM",	"PO7_UGBGE_SYM","PO7_ERR_PKT0",
+	"PO7_ERR_PKT1",		"reserved",	"reserved",
+	"PO0_ERR_SUM",		"PO0_TLB_ERR",	"PO0_SPL_COMPLT",
+	"PO0_TRANS_SUM",	"PO0_FIRST_ERR","PO0_MULT_ERR",
+	"DM CSR PH",		"DM CSR PH",	"DM CSR PH",
+	"DM CSR PH",		"reserved",
+	"PO1_ERR_SUM",		"PO1_TLB_ERR",	"PO1_SPL_COMPLT",
+	"PO1_TRANS_SUM",	"PO1_FIRST_ERR","PO1_MULT_ERR",
+	"DM CSR PH",		"DM CSR PH",	"DM CSR PH",
+	"DM CSR PH",		"reserved",
+	"PO2_ERR_SUM",		"PO2_TLB_ERR",	"PO2_SPL_COMPLT",
+	"PO2_TRANS_SUM",	"PO2_FIRST_ERR","PO2_MULT_ERR",
+	"DM CSR PH",		"DM CSR PH",	"DM CSR PH",
+	"DM CSR PH",		"reserved",
+	"PO3_ERR_SUM",		"PO3_TLB_ERR",	"PO3_SPL_COMPLT",
+	"PO3_TRANS_SUM",	"PO3_FIRST_ERR","PO3_MULT_ERR",
+	"DM CSR PH",		"DM CSR PH",	"DM CSR PH",
+	"DM CSR PH",		"reserved",	
+	NULL
+};
+	
+static struct el_subpacket_annotation el_ev7_pal_annotations[] = {
+	SUBPACKET_ANNOTATION(EL_CLASS__PAL,
+			     EL_TYPE__PAL__EV7_PROCESSOR,
+			     1,
+			     "EV7 Processor Subpacket",
+			     el_ev7_processor_subpacket_annotation),
+	SUBPACKET_ANNOTATION(EL_CLASS__PAL,
+			     EL_TYPE__PAL__EV7_ZBOX,
+			     1,
+			     "EV7 ZBOX Subpacket",
+			     el_ev7_zbox_subpacket_annotation),
+	SUBPACKET_ANNOTATION(EL_CLASS__PAL,
+			     EL_TYPE__PAL__EV7_RBOX,
+			     1,
+			     "EV7 RBOX Subpacket",
+			     el_ev7_rbox_subpacket_annotation),
+	SUBPACKET_ANNOTATION(EL_CLASS__PAL,
+			     EL_TYPE__PAL__EV7_IO,
+			     1,
+			     "EV7 IO Subpacket",
+			     el_ev7_io_subpacket_annotation)
+};
+
+static struct el_subpacket *
+ev7_process_pal_subpacket(struct el_subpacket *header)
+{
+	struct ev7_pal_subpacket *packet;
+
+	if (header->class != EL_CLASS__PAL) {
+		printk("%s  ** Unexpected header CLASS %d TYPE %d, aborting\n",
+		       err_print_prefix,
+		       header->class, header->type);
+		return NULL;
+	}
+
+	packet = (struct ev7_pal_subpacket *)header->by_type.raw.data_start;
+
+	switch(header->type) {
+	case EL_TYPE__PAL__LOGOUT_FRAME:
+		printk("%s*** MCHK occurred on LPID %ld (RBOX %lx)\n",
+		       err_print_prefix,
+		       packet->by_type.logout.whami, 
+		       packet->by_type.logout.rbox_whami);
+		el_print_timestamp(packet->by_type.logout.timestamp);
+		printk("%s  EXC_ADDR: %016lx\n"
+		         "  HALT_CODE: %lx\n", 
+		       err_print_prefix,
+		       packet->by_type.logout.exc_addr,
+		       packet->by_type.logout.halt_code);
+		el_process_subpackets(header,
+                                      packet->by_type.logout.subpacket_count);
+		break;
+	default:
+		printk("%s  ** PAL TYPE %d SUBPACKET\n", 
+		       err_print_prefix,
+		       header->type);
+		el_annotate_subpacket(header);
+		break;
+	}
+	
+	return (struct el_subpacket *)((unsigned long)header + header->length);
+}
+
+struct el_subpacket_handler ev7_pal_subpacket_handler =
+	SUBPACKET_HANDLER_INIT(EL_CLASS__PAL, ev7_process_pal_subpacket);
+
+void 
+ev7_register_error_handlers(void)
+{
+	int i;
+
+	for(i = 0;
+	    i<sizeof(el_ev7_pal_annotations)/sizeof(el_ev7_pal_annotations[1]);
+	    i++) {
+		cdl_register_subpacket_annotation(&el_ev7_pal_annotations[i]);
+	}	
+	cdl_register_subpacket_handler(&ev7_pal_subpacket_handler);
+}
+
+#endif /* CONFIG_ALPHA_GENERIC || CONFIG_ALPHA_EV7 */
+
+
+/*
+ * EV6 generic
+ */
+
+#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_EV6)
+
+static int
+ev6_parse_ibox(u64 i_stat, int print)
+{
+	int status = MCHK_DISPOSITION_REPORT;
+
+#define EV6__I_STAT__PAR	(1UL << 29)
+#define EV6__I_STAT__ERRMASK	(EV6__I_STAT__PAR)
+
+	if (!(i_stat & EV6__I_STAT__ERRMASK))
+		return MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+	if (!print)
+		return status;
+
+	if (i_stat & EV6__I_STAT__PAR)
+		printk("%s    Icache parity error\n", err_print_prefix);
+
+	return status;
+}
+
+static int
+ev6_parse_mbox(u64 mm_stat, u64 d_stat, u64 c_stat, int print)
+{
+	int status = MCHK_DISPOSITION_REPORT;
+
+#define EV6__MM_STAT__DC_TAG_PERR	(1UL << 10)
+#define EV6__MM_STAT__ERRMASK		(EV6__MM_STAT__DC_TAG_PERR)
+#define EV6__D_STAT__TPERR_P0		(1UL << 0)
+#define EV6__D_STAT__TPERR_P1		(1UL << 1)
+#define EV6__D_STAT__ECC_ERR_ST		(1UL << 2)
+#define EV6__D_STAT__ECC_ERR_LD		(1UL << 3)
+#define EV6__D_STAT__SEO		(1UL << 4)
+#define EV6__D_STAT__ERRMASK		(EV6__D_STAT__TPERR_P0 |	\
+                                         EV6__D_STAT__TPERR_P1 | 	\
+                                         EV6__D_STAT__ECC_ERR_ST | 	\
+                                         EV6__D_STAT__ECC_ERR_LD | 	\
+                                         EV6__D_STAT__SEO)
+
+	if (!(d_stat & EV6__D_STAT__ERRMASK) && 
+	    !(mm_stat & EV6__MM_STAT__ERRMASK))
+		return MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+	if (!print)
+		return status;
+
+	if (mm_stat & EV6__MM_STAT__DC_TAG_PERR)
+		printk("%s    Dcache tag parity error on probe\n",
+		       err_print_prefix);
+	if (d_stat & EV6__D_STAT__TPERR_P0)
+		printk("%s    Dcache tag parity error - pipe 0\n",
+		       err_print_prefix);
+	if (d_stat & EV6__D_STAT__TPERR_P1)
+		printk("%s    Dcache tag parity error - pipe 1\n",
+		       err_print_prefix);
+	if (d_stat & EV6__D_STAT__ECC_ERR_ST)
+		printk("%s    ECC error occurred on a store\n", 
+		       err_print_prefix);
+	if (d_stat & EV6__D_STAT__ECC_ERR_LD)
+		printk("%s    ECC error occurred on a %s load\n",
+		       err_print_prefix,
+		       c_stat ? "" : "speculative ");
+	if (d_stat & EV6__D_STAT__SEO)
+		printk("%s    Dcache second error\n", err_print_prefix);
+
+	return status;
+}
+
+static int
+ev6_parse_cbox(u64 c_addr, u64 c1_syn, u64 c2_syn, 
+	       u64 c_stat, u64 c_sts, int print)
+{
+	char *sourcename[] = { "UNKNOWN", "UNKNOWN", "UNKNOWN",
+			       "MEMORY", "BCACHE", "DCACHE", 
+			       "BCACHE PROBE", "BCACHE PROBE" };
+	char *streamname[] = { "D", "I" };
+	char *bitsname[] = { "SINGLE", "DOUBLE" };
+	int status = MCHK_DISPOSITION_REPORT;
+	int source = -1, stream = -1, bits = -1;
+
+#define EV6__C_STAT__BC_PERR		(0x01)
+#define EV6__C_STAT__DC_PERR		(0x02)
+#define EV6__C_STAT__DSTREAM_MEM_ERR	(0x03)
+#define EV6__C_STAT__DSTREAM_BC_ERR	(0x04)
+#define EV6__C_STAT__DSTREAM_DC_ERR	(0x05)
+#define EV6__C_STAT__PROBE_BC_ERR0	(0x06)	/* both 6 and 7 indicate... */
+#define EV6__C_STAT__PROBE_BC_ERR1	(0x07)	/* ...probe bc error.       */
+#define EV6__C_STAT__ISTREAM_MEM_ERR	(0x0B)
+#define EV6__C_STAT__ISTREAM_BC_ERR	(0x0C)
+#define EV6__C_STAT__DSTREAM_MEM_DBL	(0x13)
+#define EV6__C_STAT__DSTREAM_BC_DBL	(0x14)
+#define EV6__C_STAT__ISTREAM_MEM_DBL	(0x1B)
+#define EV6__C_STAT__ISTREAM_BC_DBL	(0x1C)
+#define EV6__C_STAT__SOURCE_MEMORY	(0x03)
+#define EV6__C_STAT__SOURCE_BCACHE	(0x04)
+#define EV6__C_STAT__SOURCE__S		(0)
+#define EV6__C_STAT__SOURCE__M 		(0x07)
+#define EV6__C_STAT__ISTREAM__S		(3)
+#define EV6__C_STAT__ISTREAM__M		(0x01)
+#define EV6__C_STAT__DOUBLE__S		(4)
+#define EV6__C_STAT__DOUBLE__M		(0x01)
+#define EV6__C_STAT__ERRMASK		(0x1F)
+#define EV6__C_STS__SHARED		(1 << 0)
+#define EV6__C_STS__DIRTY		(1 << 1)
+#define EV6__C_STS__VALID		(1 << 2)
+#define EV6__C_STS__PARITY		(1 << 3)
+
+	if (!(c_stat & EV6__C_STAT__ERRMASK))
+		return MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+	if (!print)
+		return status;
+
+	source = EXTRACT(c_stat, EV6__C_STAT__SOURCE);
+	stream = EXTRACT(c_stat, EV6__C_STAT__ISTREAM);
+	bits = EXTRACT(c_stat, EV6__C_STAT__DOUBLE);
+
+	if (c_stat & EV6__C_STAT__BC_PERR) {
+		printk("%s    Bcache tag parity error\n", err_print_prefix);
+		source = -1;
+	}
+
+	if (c_stat & EV6__C_STAT__DC_PERR) {
+		printk("%s    Dcache tag parity error\n", err_print_prefix);
+		source = -1;
+	}
+
+	if (c_stat == EV6__C_STAT__PROBE_BC_ERR0 ||
+	    c_stat == EV6__C_STAT__PROBE_BC_ERR1) {
+		printk("%s    Bcache single-bit error on a probe hit\n",
+		       err_print_prefix);
+		source = -1;
+	}
+
+	if (source != -1) 
+		printk("%s    %s-STREAM %s-BIT ECC error from %s\n",
+		       err_print_prefix,
+		       streamname[stream], bitsname[bits], sourcename[source]);
+
+	printk("%s    Address: 0x%016lx\n"
+	         "    Syndrome[upper.lower]: %02lx.%02lx\n", 
+	       err_print_prefix,
+	       c_addr,
+	       c2_syn, c1_syn);
+
+	if (source == EV6__C_STAT__SOURCE_MEMORY ||
+	    source == EV6__C_STAT__SOURCE_BCACHE) 
+		printk("%s    Block status: %s%s%s%s\n",
+		       err_print_prefix,
+		       (c_sts & EV6__C_STS__SHARED) ? "SHARED " : "",
+		       (c_sts & EV6__C_STS__DIRTY)  ? "DIRTY "  : "",
+		       (c_sts & EV6__C_STS__VALID)  ? "VALID "  : "",
+		       (c_sts & EV6__C_STS__PARITY) ? "PARITY " : "");
+		
+	return status;
+}
+
+int
+ev6_process_logout_frame(struct el_common *mchk_header, int print)
+{
+	struct el_common_EV6_mcheck *ev6mchk = 
+		(struct el_common_EV6_mcheck *)mchk_header;
+	int status = MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+	status |= ev6_parse_ibox(ev6mchk->I_STAT, print);
+	status |= ev6_parse_mbox(ev6mchk->MM_STAT, ev6mchk->DC_STAT, 
+				 ev6mchk->C_STAT, print);
+	status |= ev6_parse_cbox(ev6mchk->C_ADDR, ev6mchk->DC1_SYNDROME,
+				 ev6mchk->DC0_SYNDROME, ev6mchk->C_STAT,
+				 ev6mchk->C_STS, print);
+
+	if (!print)
+		return status;
+
+	if (status != MCHK_DISPOSITION_DISMISS) {
+		char *saved_err_prefix = err_print_prefix;
+
+		/*
+		 * Dump some additional information from the frame
+		 */
+		printk("%s    EXC_ADDR: 0x%016lx   IER_CM: 0x%016lx"
+		            "   ISUM: 0x%016lx\n"
+		         "    PAL_BASE: 0x%016lx   I_CTL:  0x%016lx"
+		            "   PCTX: 0x%016lx\n",
+		       err_print_prefix,
+		       ev6mchk->EXC_ADDR, ev6mchk->IER_CM, ev6mchk->ISUM,
+		       ev6mchk->PAL_BASE, ev6mchk->I_CTL, ev6mchk->PCTX);
+
+		if (status == MCHK_DISPOSITION_UNKNOWN_ERROR) {
+			printk("%s    UNKNOWN error, frame follows:\n",
+			       err_print_prefix);
+		} else {
+			/* had decode -- downgrade print level for frame */
+			err_print_prefix = KERN_NOTICE;
+		}
+
+		mchk_dump_logout_frame(mchk_header);
+
+		err_print_prefix = saved_err_prefix;
+	}
+
+	return status;
+}
+
+void
+ev6_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs)
+{
+	struct el_common *mchk_header = (struct el_common *)la_ptr;
+
+	/*
+	 * Sync the processor
+	 */
+	mb();
+	draina();
+
+	/*
+	 * Parse the logout frame without printing first. If the only error(s)
+	 * found are have a disposition of "dismiss", then just dismiss them
+	 * and don't print any message
+	 */
+	if (ev6_process_logout_frame(mchk_header, 0) != 
+	    MCHK_DISPOSITION_DISMISS) {
+		char *saved_err_prefix = err_print_prefix;
+		err_print_prefix = KERN_CRIT;
+
+		/*
+		 * Either a nondismissable error was detected or no
+		 * recognized error was detected  in the logout frame 
+		 * -- report the error in either case
+		 */
+		printk("%s*CPU %s Error (Vector 0x%x) reported on CPU %d:\n", 
+		       err_print_prefix,
+		       (vector == SCB_Q_PROCERR)?"Correctable":"Uncorrectable",
+		       (unsigned int)vector, (int)smp_processor_id());
+		
+		ev6_process_logout_frame(mchk_header, 1);
+		dik_show_regs(regs, NULL);
+
+		err_print_prefix = saved_err_prefix;
+	}
+
+	/* 
+	 * Release the logout frame 
+	 */
+	wrmces(0x7);
+	mb();
+}
+
+#endif /* CONFIG_ALPHA_GENERIC || CONFIG_ALPHA_EV6 */
+
+
+/*
+ * Console Data Log
+ */
+/* Data */
+static struct el_subpacket_handler *subpacket_handler_list = NULL;
+static struct el_subpacket_annotation *subpacket_annotation_list = NULL;
+
+static void
+el_print_timestamp(union el_timestamp timestamp)
+{
+	if (timestamp.as_int)
+		printk("%s  TIMESTAMP: %d/%d/%02d %d:%02d:%0d\n", 
+		       err_print_prefix,
+		       timestamp.b.month, timestamp.b.day,
+		       timestamp.b.year, timestamp.b.hour,
+		       timestamp.b.minute, timestamp.b.second);
+}
+
+static struct el_subpacket *
+el_process_header_subpacket(struct el_subpacket *header)
+{
+	union el_timestamp timestamp;
+	char *name = "UNKNOWN EVENT";
+	int packet_count = 0;
+	int length = 0;
+
+	if (header->class != EL_CLASS__HEADER) {
+		printk("%s** Unexpected header CLASS %d TYPE %d, aborting\n",
+		       err_print_prefix,
+		       header->class, header->type);
+		return NULL;
+	}
+
+	switch(header->type) {
+	case EL_TYPE__HEADER__SYSTEM_ERROR_FRAME:
+		name = "SYSTEM ERROR";
+		length = header->by_type.sys_err.frame_length;
+		packet_count = 
+			header->by_type.sys_err.frame_packet_count;
+		timestamp.as_int = 0;
+		break;
+	case EL_TYPE__HEADER__SYSTEM_EVENT_FRAME:
+		name = "SYSTEM EVENT";
+		length = header->by_type.sys_event.frame_length;
+		packet_count = 
+			header->by_type.sys_event.frame_packet_count;
+		timestamp = header->by_type.sys_event.timestamp;
+		break;
+	case EL_TYPE__HEADER__HALT_FRAME:
+		name = "ERROR HALT";
+		length = header->by_type.err_halt.frame_length;
+		packet_count = 
+			header->by_type.err_halt.frame_packet_count;
+		timestamp = header->by_type.err_halt.timestamp;
+		break;
+	case EL_TYPE__HEADER__LOGOUT_FRAME:
+		name = "LOGOUT FRAME";
+		length = header->by_type.logout_header.frame_length;
+		packet_count = 1;
+		timestamp.as_int = 0;
+		break;
+	default: /* Unknown */
+		printk("%s** Unknown header - CLASS %d TYPE %d, aborting\n",
+		       err_print_prefix,
+		       header->class, header->type);
+		return NULL;		
+	}
+
+	printk("%s*** %s:\n"
+	         "  CLASS %d, TYPE %d\n", 
+	       err_print_prefix,
+	       name,
+	       header->class, header->type);
+	el_print_timestamp(timestamp);
+	
+	/*
+	 * Process the subpackets
+	 */
+	el_process_subpackets(header, packet_count);
+
+	/* return the next header */
+	header = (struct el_subpacket *)
+		((unsigned long)header + header->length + length);
+	return header;
+}
+
+static void
+el_process_subpackets(struct el_subpacket *header, int packet_count)
+{
+	struct el_subpacket *subpacket;
+	int i;
+
+	subpacket = (struct el_subpacket *)
+		((unsigned long)header + header->length);
+
+	for (i = 0; subpacket && i < packet_count; i++) {
+		printk("%sPROCESSING SUBPACKET %d\n", err_print_prefix, i);
+		subpacket = el_process_subpacket(subpacket);
+	}
+}
+
+static struct el_subpacket *
+el_process_subpacket_reg(struct el_subpacket *header)
+{
+	struct el_subpacket *next = NULL;
+	struct el_subpacket_handler *h = subpacket_handler_list;
+
+	for (; h && h->class != header->class; h = h->next);
+	if (h) next = h->handler(header);
+
+	return next;
+}
+
+struct el_subpacket *
+el_process_subpacket(struct el_subpacket *header)
+{
+	struct el_subpacket *next = NULL;
+
+	switch(header->class) {
+	case EL_CLASS__TERMINATION:
+		/* Termination packet, there are no more */
+		break;
+	case EL_CLASS__HEADER: 
+		next = el_process_header_subpacket(header);
+		break;
+	default:
+		if (NULL == (next = el_process_subpacket_reg(header))) {
+			printk("%s** Unexpected header CLASS %d TYPE %d"
+			       " -- aborting.\n",
+			       err_print_prefix,
+			       header->class, header->type);
+		}
+		break;
+	}
+
+	return next;
+}
+
+void 
+el_annotate_subpacket(struct el_subpacket *header)
+{
+	struct el_subpacket_annotation *a;
+	char **annotation = NULL;
+
+	for (a = subpacket_annotation_list; a; a = a->next) {
+		if (a->class == header->class &&
+		    a->type == header->type &&
+		    a->revision == header->revision) {
+			/*
+			 * We found the annotation
+			 */
+			annotation = a->annotation;
+			printk("%s  %s\n", err_print_prefix, a->description);
+			break;
+		}
+	}
+
+	mchk_dump_mem(header, header->length, annotation);
+}
+
+static void __init
+cdl_process_console_data_log(int cpu, struct percpu_struct *pcpu)
+{
+	struct el_subpacket *header = (struct el_subpacket *)
+		(IDENT_ADDR | pcpu->console_data_log_pa);
+	int err;
+
+	printk("%s******* CONSOLE DATA LOG FOR CPU %d. *******\n"
+	         "*** Error(s) were logged on a previous boot\n",
+	       err_print_prefix, cpu);
+	
+	for (err = 0; header && (header->class != EL_CLASS__TERMINATION); err++)
+		header = el_process_subpacket(header);
+
+	/* let the console know it's ok to clear the error(s) at restart */
+	pcpu->console_data_log_pa = 0;
+
+	printk("%s*** %d total error(s) logged\n"
+	         "**** END OF CONSOLE DATA LOG FOR CPU %d ****\n", 
+	       err_print_prefix, err, cpu);
+}
+
+void __init
+cdl_check_console_data_log(void)
+{
+	struct percpu_struct *pcpu;
+	unsigned long cpu;
+
+	for (cpu = 0; cpu < hwrpb->nr_processors; cpu++) {
+		pcpu = (struct percpu_struct *)
+			((unsigned long)hwrpb + hwrpb->processor_offset 
+			 + cpu * hwrpb->processor_size);
+		if (pcpu->console_data_log_pa)
+			cdl_process_console_data_log(cpu, pcpu);
+	}
+
+}
+
+int __init
+cdl_register_subpacket_annotation(struct el_subpacket_annotation *new)
+{
+	struct el_subpacket_annotation *a = subpacket_annotation_list;
+
+	if (a == NULL) subpacket_annotation_list = new;
+	else {
+		for (; a->next != NULL; a = a->next) {
+			if ((a->class == new->class && a->type == new->type) ||
+			    a == new) {
+				printk("Attempted to re-register "
+				       "subpacket annotation\n");
+				return -EINVAL;
+			}
+		}
+		a->next = new;
+	}
+	new->next = NULL;
+
+	return 0;
+}
+
+int __init
+cdl_register_subpacket_handler(struct el_subpacket_handler *new)
+{
+	struct el_subpacket_handler *h = subpacket_handler_list;
+
+	if (h == NULL) subpacket_handler_list = new;
+	else {
+		for (; h->next != NULL; h = h->next) {
+			if (h->class == new->class || h == new) {
+				printk("Attempted to re-register "
+				       "subpacket handler\n");
+				return -EINVAL;
+			}
+		}
+		h->next = new;
+	}
+	new->next = NULL;
+
+	return 0;
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/err_impl.h linux-2.4.21-pre6/arch/alpha/kernel/err_impl.h
--- linux-2.4.20/arch/alpha/kernel/err_impl.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/kernel/err_impl.h	2003-03-26 23:49:35.000000000 +0000
@@ -0,0 +1,162 @@
+/*
+ *	linux/arch/alpha/kernel/err_impl.h
+ *
+ *	Copyright (C) 2000 Jeff Wiedemeier (Compaq Computer Corporation)
+ *
+ *	Contains declarations and macros to support Alpha error handling
+ * 	implementations.
+ */
+
+/*
+ * SCB Vector definitions
+ */
+#define SCB_Q_SYSERR	0x620
+#define SCB_Q_PROCERR	0x630
+#define SCB_Q_SYSMCHK	0x660
+#define SCB_Q_PROCMCHK	0x670
+#define SCB_Q_SYSEVENT	0x680
+
+/*
+ * Disposition definitions for logout frame parser
+ */
+#define MCHK_DISPOSITION_UNKNOWN_ERROR		0x00
+#define MCHK_DISPOSITION_REPORT			0x01
+#define MCHK_DISPOSITION_DISMISS		0x02
+
+/*
+ * Error Log definitions
+ */
+/*
+ * Types
+ */
+
+#define EL_CLASS__TERMINATION		(0)
+#  define EL_TYPE__TERMINATION__TERMINATION		(0)
+#define EL_CLASS__HEADER		(5)
+#  define EL_TYPE__HEADER__SYSTEM_ERROR_FRAME		(1)
+#  define EL_TYPE__HEADER__SYSTEM_EVENT_FRAME		(2)
+#  define EL_TYPE__HEADER__HALT_FRAME			(3)
+#  define EL_TYPE__HEADER__LOGOUT_FRAME			(19)
+#define EL_CLASS__GENERAL_NOTIFICATION	(9)
+#define EL_CLASS__PCI_ERROR_FRAME	(11)
+#define EL_CLASS__REGATTA_FAMILY	(12)
+#  define EL_TYPE__REGATTA__PROCESSOR_ERROR_FRAME	(1)
+#  define EL_TYPE__REGATTA__SYSTEM_ERROR_FRAME		(2)
+#  define EL_TYPE__REGATTA__ENVIRONMENTAL_FRAME		(3)
+#  define EL_TYPE__REGATTA__TITAN_PCHIP0_EXTENDED	(8)
+#  define EL_TYPE__REGATTA__TITAN_PCHIP1_EXTENDED	(9)
+#  define EL_TYPE__REGATTA__TITAN_MEMORY_EXTENDED	(10)
+#  define EL_TYPE__REGATTA__PROCESSOR_DBL_ERROR_HALT	(11)
+#  define EL_TYPE__REGATTA__SYSTEM_DBL_ERROR_HALT	(12)
+#define EL_CLASS__PAL                   (14)
+#  define EL_TYPE__PAL__LOGOUT_FRAME                    (1)
+#  define EL_TYPE__PAL__EV7_PROCESSOR			(4)
+#  define EL_TYPE__PAL__EV7_ZBOX			(5)
+#  define EL_TYPE__PAL__EV7_RBOX			(6)
+#  define EL_TYPE__PAL__EV7_IO				(7)
+
+union el_timestamp {
+	struct {
+		u8 second;
+		u8 minute;
+		u8 hour;
+		u8 day;
+		u8 month;
+		u8 year;
+	} b;
+	u64 as_int;
+};
+
+struct el_subpacket {
+	u16 length;		/* length of header (in bytes)	*/
+	u16 class;		/* header class and type...   	*/
+	u16 type;		/* ...determine content     	*/
+	u16 revision;		/* header revision 		*/
+	union {
+		struct {	/* Class 5, Type 1 - System Error	*/
+			u32 frame_length;
+			u32 frame_packet_count;			
+		} sys_err;			
+		struct {	/* Class 5, Type 2 - System Event 	*/
+			union el_timestamp timestamp;
+			u32 frame_length;
+			u32 frame_packet_count;			
+		} sys_event;
+		struct {	/* Class 5, Type 3 - Double Error Halt	*/
+			u16 halt_code;
+			u16 reserved;
+			union el_timestamp timestamp;
+			u32 frame_length;
+			u32 frame_packet_count;
+		} err_halt;
+		struct {	/* Clasee 5, Type 19 - Logout Frame Header */
+			u32 frame_length;
+			u32 frame_flags;
+			u32 cpu_offset;	
+			u32 system_offset;
+		} logout_header;
+		struct {	/* Class 12 - Regatta			*/
+			u64 cpuid;
+			u64 data_start[1];
+		} regatta_frame;
+		struct {	/* Raw 				        */
+			u64 data_start[1];
+		} raw;
+	} by_type;
+};
+
+struct el_subpacket_annotation {
+	struct el_subpacket_annotation *next;
+	u16 class;
+	u16 type;
+	u16 revision;
+	char *description;
+	char **annotation;
+};
+#define SUBPACKET_ANNOTATION(c, t, r, d, a) {NULL, (c), (t), (r), (d), (a)}
+
+struct el_subpacket_handler {
+	struct el_subpacket_handler *next;
+	u16 class;
+	struct el_subpacket *(*handler)(struct el_subpacket *);
+};
+#define SUBPACKET_HANDLER_INIT(c, h) {NULL, (c), (h)}
+
+/*
+ * Extract a field from a register given it's name. defines
+ * for the LSB (__S - shift count) and bitmask (__M) are required
+ */
+#define EXTRACT(u, f) (((u) >> f##__S) & f##__M)
+
+/*
+ * err_common.c
+ */
+extern char *err_print_prefix;
+
+extern void mchk_dump_mem(void *, size_t, char **);
+extern void mchk_dump_logout_frame(struct el_common *);
+extern void ev7_register_error_handlers(void);
+extern void ev7_machine_check(u64, u64, struct pt_regs *);
+extern void ev6_register_error_handlers(void);
+extern int ev6_process_logout_frame(struct el_common *, int);
+extern void ev6_machine_check(u64, u64, struct pt_regs *);
+extern struct el_subpacket *el_process_subpacket(struct el_subpacket *);
+extern void el_annotate_subpacket(struct el_subpacket *);
+extern void cdl_check_console_data_log(void);
+extern int cdl_register_subpacket_annotation(struct el_subpacket_annotation *);
+extern int cdl_register_subpacket_handler(struct el_subpacket_handler *);
+
+/*
+ * err_marvel.c
+ */
+extern void marvel_machine_check(u64, u64, struct pt_regs *);
+extern void marvel_register_error_handlers(void);
+
+/*
+ * err_titan.c
+ */
+extern int titan_process_logout_frame(struct el_common *, int);
+extern void titan_machine_check(u64, u64, struct pt_regs *);
+extern void titan_register_error_handlers(void);
+extern int privateer_process_logout_frame(struct el_common *, int);
+extern void privateer_machine_check(u64, u64, struct pt_regs *);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/err_marvel.c linux-2.4.21-pre6/arch/alpha/kernel/err_marvel.c
--- linux-2.4.20/arch/alpha/kernel/err_marvel.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/kernel/err_marvel.c	2003-03-26 23:49:09.000000000 +0000
@@ -0,0 +1,57 @@
+/*
+ *	linux/arch/alpha/kernel/err_marvel.c
+ *
+ *	Copyright (C) 2001 Jeff Wiedemeier (Compaq Computer Corporation)
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+
+#include <asm/io.h>
+#include <asm/console.h>
+#include <asm/core_marvel.h>
+#include <asm/hwrpb.h>
+#include <asm/smp.h>
+
+#include "err_impl.h"
+#include "proto.h"
+
+
+void
+marvel_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs)
+{
+	struct el_subpacket *el_ptr = (struct el_subpacket *)la_ptr;
+
+	/*
+	 * Sync the processor
+	 */
+	mb();
+	draina();
+
+	el_process_subpacket(el_ptr);
+
+	switch(vector) {
+	case SCB_Q_SYSEVENT:
+		printk(KERN_CRIT "MARVEL SYSEVENT %ld\n", vector);
+		break;
+	case SCB_Q_SYSMCHK:
+	case SCB_Q_SYSERR:
+		printk(KERN_CRIT "MARVEL SYSMCHK/ERR %ld\n", vector);
+		break;
+	default:
+		/* Don't know it - pass it up.  */
+		return ev7_machine_check(vector, la_ptr, regs);
+	}	
+
+        /* Release the logout frame.  */
+	wrmces(0x7);
+	mb();
+}
+
+void
+marvel_register_error_handlers(void)
+{
+	ev7_register_error_handlers();
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/err_titan.c linux-2.4.21-pre6/arch/alpha/kernel/err_titan.c
--- linux-2.4.20/arch/alpha/kernel/err_titan.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/kernel/err_titan.c	2003-03-26 23:49:50.000000000 +0000
@@ -0,0 +1,747 @@
+/*
+ *	linux/arch/alpha/kernel/err_titan.c
+ *
+ *	Copyright (C) 2000 Jeff Wiedemeier (Compaq Computer Corporation)
+ *
+ *	Error handling code supporting TITAN systems
+ */
+
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+
+#include <asm/io.h>
+#include <asm/core_titan.h>
+#include <asm/hwrpb.h>
+#include <asm/smp.h>
+
+#include "err_impl.h"
+#include "proto.h"
+
+
+static int
+titan_parse_c_misc(u64 c_misc, int print)
+{
+	char *src;
+	int nxs = 0;
+	int status = MCHK_DISPOSITION_REPORT;
+
+#define TITAN__CCHIP_MISC__NXM		(1UL << 28)
+#define TITAN__CCHIP_MISC__NXS__S	(29)
+#define TITAN__CCHIP_MISC__NXS__M	(0x7)
+
+	if (!(c_misc & TITAN__CCHIP_MISC__NXM))
+		return MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+#ifdef CONFIG_VERBOSE_MCHECK
+	if (!print)
+		return status;
+
+	nxs = EXTRACT(c_misc, TITAN__CCHIP_MISC__NXS);
+	switch(nxs) {
+	case 0:	/* CPU 0 */
+	case 1:	/* CPU 1 */
+	case 2:	/* CPU 2 */
+	case 3:	/* CPU 3 */
+		src = "CPU";
+		/* num is already the CPU number */
+		break;
+	case 4:	/* Pchip 0 */
+	case 5:	/* Pchip 1 */
+		src = "Pchip";
+		nxs -= 4;
+		break;
+	default:/* reserved */
+		src = "Unknown, NXS =";
+		/* leave num untouched */
+		break;
+	}
+
+	printk("%s    Non-existent memory access from: %s %d\n", 
+	       err_print_prefix, src, nxs);
+#endif /* CONFIG_VERBOSE_MCHECK */
+
+	return status;
+}
+
+static int
+titan_parse_p_serror(int which, u64 serror, int print)
+{
+	int status = MCHK_DISPOSITION_REPORT;
+
+#ifdef CONFIG_VERBOSE_MCHECK
+	char *serror_src[] = {"GPCI", "APCI", "AGP HP", "AGP LP"};
+	char *serror_cmd[] = {"DMA Read", "DMA RMW", "SGTE Read", "Reserved"};
+#endif /* CONFIG_VERBOSE_MCHECK */
+
+#define TITAN__PCHIP_SERROR__LOST_UECC	(1UL << 0)
+#define TITAN__PCHIP_SERROR__UECC	(1UL << 1)
+#define TITAN__PCHIP_SERROR__CRE	(1UL << 2)
+#define TITAN__PCHIP_SERROR__NXIO	(1UL << 3)
+#define TITAN__PCHIP_SERROR__LOST_CRE	(1UL << 4)
+#define TITAN__PCHIP_SERROR__ECCMASK	(TITAN__PCHIP_SERROR__UECC |	  \
+					 TITAN__PCHIP_SERROR__CRE)
+#define TITAN__PCHIP_SERROR__ERRMASK	(TITAN__PCHIP_SERROR__LOST_UECC | \
+					 TITAN__PCHIP_SERROR__UECC |	  \
+					 TITAN__PCHIP_SERROR__CRE |	  \
+					 TITAN__PCHIP_SERROR__NXIO |	  \
+					 TITAN__PCHIP_SERROR__LOST_CRE)
+#define TITAN__PCHIP_SERROR__SRC__S	(52)
+#define TITAN__PCHIP_SERROR__SRC__M	(0x3)
+#define TITAN__PCHIP_SERROR__CMD__S	(54)
+#define TITAN__PCHIP_SERROR__CMD__M	(0x3)
+#define TITAN__PCHIP_SERROR__SYN__S	(56)
+#define TITAN__PCHIP_SERROR__SYN__M	(0xff)
+#define TITAN__PCHIP_SERROR__ADDR__S	(15)
+#define TITAN__PCHIP_SERROR__ADDR__M	(0xffffffffUL)
+
+	if (!(serror & TITAN__PCHIP_SERROR__ERRMASK))
+		return MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+#ifdef CONFIG_VERBOSE_MCHECK
+	if (!print)
+		return status;
+
+	printk("%s  PChip %d SERROR: %016lx\n", 
+	       err_print_prefix, which, serror);
+	if (serror & TITAN__PCHIP_SERROR__ECCMASK) {
+		printk("%s    %sorrectable ECC Error:\n"
+		       "      Source: %-6s  Command: %-8s  Syndrome: 0x%08x\n"
+		       "      Address: 0x%lx\n", 
+		       err_print_prefix,
+		       (serror & TITAN__PCHIP_SERROR__UECC) ? "Unc" : "C",
+		       serror_src[EXTRACT(serror, TITAN__PCHIP_SERROR__SRC)],
+		       serror_cmd[EXTRACT(serror, TITAN__PCHIP_SERROR__CMD)],
+		       (unsigned)EXTRACT(serror, TITAN__PCHIP_SERROR__SYN),
+		       EXTRACT(serror, TITAN__PCHIP_SERROR__ADDR));
+	}
+	if (serror & TITAN__PCHIP_SERROR__NXIO)
+		printk("%s    Non Existent I/O Error\n", err_print_prefix);
+	if (serror & TITAN__PCHIP_SERROR__LOST_UECC)
+		printk("%s    Lost Uncorrectable ECC Error\n", 
+		       err_print_prefix);
+	if (serror & TITAN__PCHIP_SERROR__LOST_CRE)
+		printk("%s    Lost Correctable ECC Error\n", err_print_prefix);
+#endif /* CONFIG_VERBOSE_MCHECK */
+
+	return status;
+}
+
+static int 
+titan_parse_p_perror(int which, int port, u64 perror, int print)
+{
+	int cmd;
+	unsigned long addr;
+	int status = MCHK_DISPOSITION_REPORT;
+
+#ifdef CONFIG_VERBOSE_MCHECK
+	char *perror_cmd[] = { "Interrupt Acknowledge", "Special Cycle",
+			       "I/O Read",	       	"I/O Write",
+			       "Reserved",	       	"Reserved",
+			       "Memory Read",		"Memory Write",
+			       "Reserved",		"Reserved",
+			       "Configuration Read",	"Configuration Write",
+			       "Memory Read Multiple",	"Dual Address Cycle",
+			       "Memory Read Line","Memory Write and Invalidate"
+	};
+#endif /* CONFIG_VERBOSE_MCHECK */
+
+#define TITAN__PCHIP_PERROR__LOST	(1UL << 0)
+#define TITAN__PCHIP_PERROR__SERR	(1UL << 1)
+#define TITAN__PCHIP_PERROR__PERR	(1UL << 2)
+#define TITAN__PCHIP_PERROR__DCRTO	(1UL << 3)
+#define TITAN__PCHIP_PERROR__SGE	(1UL << 4)
+#define TITAN__PCHIP_PERROR__APE	(1UL << 5)
+#define TITAN__PCHIP_PERROR__TA		(1UL << 6)
+#define TITAN__PCHIP_PERROR__DPE	(1UL << 7)
+#define TITAN__PCHIP_PERROR__NDS	(1UL << 8)
+#define TITAN__PCHIP_PERROR__IPTPR	(1UL << 9)
+#define TITAN__PCHIP_PERROR__IPTPW	(1UL << 10)
+#define TITAN__PCHIP_PERROR__ERRMASK	(TITAN__PCHIP_PERROR__LOST |	\
+					 TITAN__PCHIP_PERROR__SERR |	\
+					 TITAN__PCHIP_PERROR__PERR |	\
+					 TITAN__PCHIP_PERROR__DCRTO |	\
+					 TITAN__PCHIP_PERROR__SGE |	\
+					 TITAN__PCHIP_PERROR__APE |	\
+					 TITAN__PCHIP_PERROR__TA |	\
+					 TITAN__PCHIP_PERROR__DPE |	\
+					 TITAN__PCHIP_PERROR__NDS |	\
+					 TITAN__PCHIP_PERROR__IPTPR |	\
+					 TITAN__PCHIP_PERROR__IPTPW)
+#define TITAN__PCHIP_PERROR__DAC	(1UL << 47)
+#define TITAN__PCHIP_PERROR__MWIN	(1UL << 48)
+#define TITAN__PCHIP_PERROR__CMD__S	(52)
+#define TITAN__PCHIP_PERROR__CMD__M	(0x0f)
+#define TITAN__PCHIP_PERROR__ADDR__S	(14)
+#define TITAN__PCHIP_PERROR__ADDR__M	(0x1ffffffff)
+
+	if (!(perror & TITAN__PCHIP_PERROR__ERRMASK))
+		return MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+	cmd = EXTRACT(perror, TITAN__PCHIP_PERROR__CMD);
+	addr = EXTRACT(perror, TITAN__PCHIP_PERROR__ADDR) << 2;
+
+	/*
+	 * Initializing the BIOS on a video card on a bus without
+	 * a south bridge (subtractive decode agent) can result in 
+	 * master aborts as the BIOS probes the capabilities of the
+	 * card. XFree86 does such initialization. If the error
+	 * is a master abort (No DevSel as PCI Master) and the command
+	 * is an I/O read or write below the address where we start
+	 * assigning PCI I/O spaces (SRM uses 0x1000), then mark the
+	 * error as dismissable so starting XFree86 doesn't result
+	 * in a series of uncorrectable errors being reported. Also
+	 * dismiss master aborts to VGA frame buffer space
+	 * (0xA0000 - 0xC0000) and legacy BIOS space (0xC0000 - 0x100000)
+	 * for the same reason.
+	 *
+	 * Also mark the error dismissible if it looks like the right
+	 * error but only the Lost bit is set. Since the BIOS initialization
+	 * can cause multiple master aborts and the error interrupt can
+	 * be handled on a different CPU than the BIOS code is run on,
+	 * it is possible for a second master abort to occur between the
+	 * time the PALcode reads PERROR and the time it writes PERROR
+	 * to acknowledge the error. If this timing happens, a second
+	 * error will be signalled after the first, and if no additional
+	 * errors occur, will look like a Lost error with no additional 
+	 * errors on the same transaction as the previous error.
+	 */
+	if (((perror & TITAN__PCHIP_PERROR__NDS) || 
+	     ((perror & TITAN__PCHIP_PERROR__ERRMASK) == 
+	      TITAN__PCHIP_PERROR__LOST)) &&
+	    ((((cmd & 0xE) == 2) && (addr < 0x1000)) ||
+	     (((cmd & 0xE) == 6) && (addr >= 0xA0000) && (addr < 0x100000)))) {
+		status = MCHK_DISPOSITION_DISMISS;
+	}
+
+#ifdef CONFIG_VERBOSE_MCHECK
+	if (!print) 
+		return status;
+
+	printk("%s  PChip %d %cPERROR: %016lx\n", 
+	       err_print_prefix, which, 
+	       port ? 'A' : 'G', perror);
+	if (perror & TITAN__PCHIP_PERROR__IPTPW)
+		printk("%s    Invalid Peer-to-Peer Write\n", err_print_prefix);
+	if (perror & TITAN__PCHIP_PERROR__IPTPR)
+		printk("%s    Invalid Peer-to-Peer Read\n", err_print_prefix);
+	if (perror & TITAN__PCHIP_PERROR__NDS)
+		printk("%s    No DEVSEL as PCI Master [Master Abort]\n",
+		       err_print_prefix);
+	if (perror & TITAN__PCHIP_PERROR__DPE)
+		printk("%s    Data Parity Error\n", err_print_prefix);
+	if (perror & TITAN__PCHIP_PERROR__TA)
+		printk("%s    Target Abort\n", err_print_prefix);
+	if (perror & TITAN__PCHIP_PERROR__APE)
+		printk("%s    Address Parity Error\n", err_print_prefix);
+	if (perror & TITAN__PCHIP_PERROR__SGE)
+		printk("%s    Scatter-Gather Error, Invalid PTE\n", 
+		       err_print_prefix);
+	if (perror & TITAN__PCHIP_PERROR__DCRTO)
+		printk("%s    Delayed-Completion Retry Timeout\n", 
+		       err_print_prefix);
+	if (perror & TITAN__PCHIP_PERROR__PERR)
+		printk("%s    PERR Asserted\n", err_print_prefix);
+	if (perror & TITAN__PCHIP_PERROR__SERR)
+		printk("%s    SERR Asserted\n", err_print_prefix);
+	if (perror & TITAN__PCHIP_PERROR__LOST)
+		printk("%s    Lost Error\n", err_print_prefix);
+	printk("%s      Command: 0x%x - %s\n"
+		 "      Address: 0x%lx\n",
+	       err_print_prefix,
+	       cmd, perror_cmd[cmd],
+	       addr);
+	if (perror & TITAN__PCHIP_PERROR__DAC)
+		printk("%s      Dual Address Cycle\n", err_print_prefix);
+	if (perror & TITAN__PCHIP_PERROR__MWIN)
+		printk("%s      Hit in Monster Window\n", err_print_prefix);
+#endif /* CONFIG_VERBOSE_MCHECK */
+
+	return status;
+}
+
+static int
+titan_parse_p_agperror(int which, u64 agperror, int print)
+{
+	int cmd, len;
+	unsigned long addr;
+	int status = MCHK_DISPOSITION_REPORT;
+
+#ifdef CONFIG_VERBOSE_MCHECK
+	char *agperror_cmd[] = { "Read (low-priority)",	"Read (high-priority)",
+				 "Write (low-priority)",
+				 "Write (high-priority)",
+				 "Reserved",		"Reserved",
+				 "Flush",		"Fence"
+	};
+#endif /* CONFIG_VERBOSE_MCHECK */
+
+#define TITAN__PCHIP_AGPERROR__LOST	(1UL << 0)
+#define TITAN__PCHIP_AGPERROR__LPQFULL	(1UL << 1)
+#define TITAN__PCHIP_AGPERROR__HPQFULL	(1UL << 2)
+#define TITAN__PCHIP_AGPERROR__RESCMD	(1UL << 3)
+#define TITAN__PCHIP_AGPERROR__IPTE	(1UL << 4)
+#define TITAN__PCHIP_AGPERROR__PTP	(1UL << 5)
+#define TITAN__PCHIP_AGPERROR__NOWINDOW	(1UL << 6)
+#define TITAN__PCHIP_AGPERROR__ERRMASK	(TITAN__PCHIP_AGPERROR__LOST |    \
+					 TITAN__PCHIP_AGPERROR__LPQFULL | \
+					 TITAN__PCHIP_AGPERROR__HPQFULL | \
+					 TITAN__PCHIP_AGPERROR__RESCMD |  \
+					 TITAN__PCHIP_AGPERROR__IPTE |    \
+					 TITAN__PCHIP_AGPERROR__PTP |     \
+					 TITAN__PCHIP_AGPERROR__NOWINDOW)
+#define TITAN__PCHIP_AGPERROR__DAC	(1UL << 48)
+#define TITAN__PCHIP_AGPERROR__MWIN	(1UL << 49)
+#define TITAN__PCHIP_AGPERROR__FENCE	(1UL << 59)
+#define TITAN__PCHIP_AGPERROR__CMD__S	(50)
+#define TITAN__PCHIP_AGPERROR__CMD__M	(0x07)
+#define TITAN__PCHIP_AGPERROR__ADDR__S	(15)
+#define TITAN__PCHIP_AGPERROR__ADDR__M  (0xffffffffUL)
+#define TITAN__PCHIP_AGPERROR__LEN__S	(53)
+#define TITAN__PCHIP_AGPERROR__LEN__M	(0x3f)
+
+	if (!(agperror & TITAN__PCHIP_AGPERROR__ERRMASK))
+		return MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+#ifdef CONFIG_VERBOSE_MCHECK
+	if (!print)
+		return status;
+
+	cmd = EXTRACT(agperror, TITAN__PCHIP_AGPERROR__CMD);
+	addr = EXTRACT(agperror, TITAN__PCHIP_AGPERROR__ADDR) << 3;
+	len = EXTRACT(agperror, TITAN__PCHIP_AGPERROR__LEN);
+
+	printk("%s  PChip %d AGPERROR: %016lx\n", err_print_prefix,
+	       which, agperror);
+	if (agperror & TITAN__PCHIP_AGPERROR__NOWINDOW)
+		printk("%s    No Window\n", err_print_prefix);
+	if (agperror & TITAN__PCHIP_AGPERROR__PTP)
+		printk("%s    Peer-to-Peer set\n", err_print_prefix);
+	if (agperror & TITAN__PCHIP_AGPERROR__IPTE)
+		printk("%s    Invalid PTE\n", err_print_prefix);
+	if (agperror & TITAN__PCHIP_AGPERROR__RESCMD)
+		printk("%s    Reserved Command\n", err_print_prefix);
+	if (agperror & TITAN__PCHIP_AGPERROR__HPQFULL)
+		printk("%s    HP Transaction Received while Queue Full\n", 
+		       err_print_prefix);
+	if (agperror & TITAN__PCHIP_AGPERROR__LPQFULL)
+		printk("%s    LP Transaction Received while Queue Full\n", 
+		       err_print_prefix);
+	if (agperror & TITAN__PCHIP_AGPERROR__LOST)
+		printk("%s    Lost Error\n", err_print_prefix);
+	printk("%s      Command: 0x%x - %s, %d Quadwords%s\n"
+		 "      Address: 0x%lx\n",
+	       err_print_prefix, cmd, agperror_cmd[cmd], len,
+	       (agperror & TITAN__PCHIP_AGPERROR__FENCE) ? ", FENCE" : "",
+	       addr);
+	if (agperror & TITAN__PCHIP_AGPERROR__DAC)
+		printk("%s      Dual Address Cycle\n", err_print_prefix);
+	if (agperror & TITAN__PCHIP_AGPERROR__MWIN)
+		printk("%s      Hit in Monster Window\n", err_print_prefix);
+#endif /* CONFIG_VERBOSE_MCHECK */
+
+	return status;
+}	
+
+static int
+titan_parse_p_chip(int which, u64 serror, u64 gperror, 
+		   u64 aperror, u64 agperror, int print)
+{
+	int status = MCHK_DISPOSITION_UNKNOWN_ERROR;
+	status |= titan_parse_p_serror(which, serror, print);
+	status |= titan_parse_p_perror(which, 0, gperror, print);
+	status |= titan_parse_p_perror(which, 1, aperror, print);
+	status |= titan_parse_p_agperror(which, agperror, print);
+	return status;
+}
+
+int
+titan_process_logout_frame(struct el_common *mchk_header, int print)
+{
+	struct el_TITAN_sysdata_mcheck *tmchk =
+		(struct el_TITAN_sysdata_mcheck *)
+		((unsigned long)mchk_header + mchk_header->sys_offset);
+	int status = MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+	status |= titan_parse_c_misc(tmchk->c_misc, print);
+	status |= titan_parse_p_chip(0, tmchk->p0_serror, tmchk->p0_gperror,
+				     tmchk->p0_aperror, tmchk->p0_agperror, 
+				     print);
+	status |= titan_parse_p_chip(1, tmchk->p1_serror, tmchk->p1_gperror,
+				     tmchk->p1_aperror, tmchk->p1_agperror, 
+				     print);
+
+	return status;
+}
+
+void
+titan_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs)
+{
+	struct el_common *mchk_header = (struct el_common *)la_ptr;
+	struct el_TITAN_sysdata_mcheck *tmchk =
+		(struct el_TITAN_sysdata_mcheck *)
+		((unsigned long)mchk_header + mchk_header->sys_offset);
+	u64 irqmask;
+
+	/*
+	 * Mask of Titan interrupt sources which are reported as machine checks
+	 *
+	 * 63 - CChip Error
+	 * 62 - PChip 0 H_Error
+	 * 61 - PChip 1 H_Error
+	 * 60 - PChip 0 C_Error
+	 * 59 - PChip 1 C_Error
+	 */
+#define TITAN_MCHECK_INTERRUPT_MASK	0xF800000000000000UL
+
+	/*
+	 * Sync the processor
+	 */
+	mb();
+	draina();
+	
+	/*
+	 * Only handle system errors here 
+	 */
+	if ((vector != SCB_Q_SYSMCHK) && (vector != SCB_Q_SYSERR)) 
+		return ev6_machine_check(vector, la_ptr, regs);
+
+	/* 
+	 * It's a system error, handle it here
+	 *
+	 * The PALcode has already cleared the error, so just parse it
+	 */
+	
+	/* 
+	 * Parse the logout frame without printing first. If the only error(s)
+	 * found are classified as "dismissable", then just dismiss them and
+	 * don't print any message
+	 */
+	if (titan_process_logout_frame(mchk_header, 0) != 
+	    MCHK_DISPOSITION_DISMISS) {
+		char *saved_err_prefix = err_print_prefix;
+		err_print_prefix = KERN_CRIT;
+
+		/*
+		 * Either a nondismissable error was detected or no
+		 * recognized error was detected  in the logout frame 
+		 * -- report the error in either case
+		 */
+		printk("%s"
+		       "*System %s Error (Vector 0x%x) reported on CPU %d:\n", 
+		       err_print_prefix,
+		       (vector == SCB_Q_SYSERR)?"Correctable":"Uncorrectable",
+		       (unsigned int)vector, (int)smp_processor_id());
+		
+#ifdef CONFIG_VERBOSE_MCHECK
+		titan_process_logout_frame(mchk_header, 1);
+		dik_show_regs(regs, NULL);
+#endif /* CONFIG_VERBOSE_MCHECK */
+
+		err_print_prefix = saved_err_prefix;
+
+		/*
+		 * Convert any pending interrupts which report as system
+		 * machine checks to interrupts
+		 */
+		irqmask = tmchk->c_dirx & TITAN_MCHECK_INTERRUPT_MASK;
+		titan_dispatch_irqs(irqmask, regs);
+	}	
+
+
+	/* 
+	 * Release the logout frame 
+	 */
+	wrmces(0x7);
+	mb();
+}
+
+/*
+ * Subpacket Annotations
+ */
+static char *el_titan_pchip0_extended_annotation[] = {
+	"Subpacket Header", 	"P0_SCTL",	"P0_SERREN",
+	"P0_APCTL",		"P0_APERREN",	"P0_AGPERREN",
+	"P0_ASPRST",		"P0_AWSBA0",	"P0_AWSBA1",
+	"P0_AWSBA2",		"P0_AWSBA3",	"P0_AWSM0",
+	"P0_AWSM1",		"P0_AWSM2",	"P0_AWSM3",
+	"P0_ATBA0",		"P0_ATBA1",	"P0_ATBA2",
+	"P0_ATBA3",		"P0_GPCTL",	"P0_GPERREN",
+	"P0_GSPRST",		"P0_GWSBA0",	"P0_GWSBA1",
+	"P0_GWSBA2",		"P0_GWSBA3",	"P0_GWSM0",
+	"P0_GWSM1",		"P0_GWSM2",	"P0_GWSM3",
+	"P0_GTBA0",		"P0_GTBA1",	"P0_GTBA2",
+	"P0_GTBA3",		NULL 
+};
+static char *el_titan_pchip1_extended_annotation[] = {
+	"Subpacket Header", 	"P1_SCTL",	"P1_SERREN",
+	"P1_APCTL",		"P1_APERREN",	"P1_AGPERREN",
+	"P1_ASPRST",		"P1_AWSBA0",	"P1_AWSBA1",
+	"P1_AWSBA2",		"P1_AWSBA3",	"P1_AWSM0",
+	"P1_AWSM1",		"P1_AWSM2",	"P1_AWSM3",
+	"P1_ATBA0",		"P1_ATBA1",	"P1_ATBA2",
+	"P1_ATBA3",		"P1_GPCTL",	"P1_GPERREN",
+	"P1_GSPRST",		"P1_GWSBA0",	"P1_GWSBA1",
+	"P1_GWSBA2",		"P1_GWSBA3",	"P1_GWSM0",
+	"P1_GWSM1",		"P1_GWSM2",	"P1_GWSM3",
+	"P1_GTBA0",		"P1_GTBA1",	"P1_GTBA2",
+	"P1_GTBA3",		NULL 
+};
+static char *el_titan_memory_extended_annotation[] = {
+	"Subpacket Header", 	"AAR0",		"AAR1",
+	"AAR2",			"AAR3",		"P0_SCTL",
+	"P0_GPCTL",		"P0_APCTL",	"P1_SCTL",
+	"P1_GPCTL",		"P1_SCTL",	NULL 
+};
+
+static struct el_subpacket_annotation el_titan_annotations[] = {
+	SUBPACKET_ANNOTATION(EL_CLASS__REGATTA_FAMILY,
+			     EL_TYPE__REGATTA__TITAN_PCHIP0_EXTENDED,
+			     1,
+			     "Titan PChip 0 Extended Frame",
+			     el_titan_pchip0_extended_annotation),
+	SUBPACKET_ANNOTATION(EL_CLASS__REGATTA_FAMILY,
+			     EL_TYPE__REGATTA__TITAN_PCHIP1_EXTENDED,
+			     1,
+			     "Titan PChip 1 Extended Frame",
+			     el_titan_pchip1_extended_annotation),
+	SUBPACKET_ANNOTATION(EL_CLASS__REGATTA_FAMILY,
+			     EL_TYPE__REGATTA__TITAN_MEMORY_EXTENDED,
+			     1,
+			     "Titan Memory Extended Frame",
+			     el_titan_memory_extended_annotation),
+	SUBPACKET_ANNOTATION(EL_CLASS__REGATTA_FAMILY,
+			     EL_TYPE__TERMINATION__TERMINATION,
+			     1,
+			     "Termination Subpacket",
+			     NULL)
+};
+
+static struct el_subpacket *
+el_process_regatta_subpacket(struct el_subpacket *header)
+{
+	int status;
+
+	if (header->class != EL_CLASS__REGATTA_FAMILY) {
+		printk("%s  ** Unexpected header CLASS %d TYPE %d, aborting\n",
+		       err_print_prefix,
+		       header->class, header->type);
+		return NULL;
+	}
+
+	switch(header->type) {
+	case EL_TYPE__REGATTA__PROCESSOR_ERROR_FRAME:
+	case EL_TYPE__REGATTA__SYSTEM_ERROR_FRAME:
+	case EL_TYPE__REGATTA__ENVIRONMENTAL_FRAME:
+	case EL_TYPE__REGATTA__PROCESSOR_DBL_ERROR_HALT:
+	case EL_TYPE__REGATTA__SYSTEM_DBL_ERROR_HALT:
+		printk("%s  ** Occurred on CPU %d:\n", 
+		       err_print_prefix,
+		       (int)header->by_type.regatta_frame.cpuid);
+		status = privateer_process_logout_frame((struct el_common *)
+			header->by_type.regatta_frame.data_start, 1);
+		break;
+	default:
+		printk("%s  ** REGATTA TYPE %d SUBPACKET\n", 
+		       err_print_prefix, header->type);
+		el_annotate_subpacket(header);
+		break;
+	}
+
+
+	return (struct el_subpacket *)((unsigned long)header + header->length);
+} 
+
+static struct el_subpacket_handler titan_subpacket_handler = 
+	SUBPACKET_HANDLER_INIT(EL_CLASS__REGATTA_FAMILY, 
+			       el_process_regatta_subpacket);
+
+void
+titan_register_error_handlers(void)
+{
+	size_t i;
+
+	for (i = 0; i < ARRAY_SIZE (el_titan_annotations); i++)
+		cdl_register_subpacket_annotation(&el_titan_annotations[i]);
+
+	cdl_register_subpacket_handler(&titan_subpacket_handler);
+}
+
+
+/*
+ * Privateer
+ */
+
+static int
+privateer_process_680_frame(struct el_common *mchk_header, int print)
+{
+	struct el_PRIVATEER_envdata_mcheck *emchk =
+		(struct el_PRIVATEER_envdata_mcheck *)
+		((unsigned long)mchk_header + mchk_header->sys_offset);
+	int status = MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+	/* TODO - catagorize errors, for now, no error */
+
+#ifdef CONFIG_VERBOSE_MCHECK
+	if (!print)
+		return status;
+
+	/* TODO - decode instead of just dumping... */
+	printk("%s  Summary Flags:         %016lx\n"
+ 	         "  CChip DIRx:            %016lx\n"
+		 "  System Management IR:  %016lx\n"
+		 "  CPU IR:                %016lx\n"
+		 "  Power Supply IR:       %016lx\n"
+		 "  LM78 Fault Status:     %016lx\n"
+		 "  System Doors:          %016lx\n"
+		 "  Temperature Warning:   %016lx\n"
+		 "  Fan Control:           %016lx\n"
+		 "  Fatal Power Down Code: %016lx\n",
+	       err_print_prefix,
+	       emchk->summary,
+	       emchk->c_dirx,
+	       emchk->smir,
+	       emchk->cpuir,
+	       emchk->psir,
+	       emchk->fault,
+	       emchk->sys_doors,
+	       emchk->temp_warn,
+	       emchk->fan_ctrl,
+	       emchk->code);
+#endif /* CONFIG_VERBOSE_MCHECK */
+
+	return status;
+}
+
+int
+privateer_process_logout_frame(struct el_common *mchk_header, int print)
+{
+	struct el_common_EV6_mcheck *ev6mchk = 
+		(struct el_common_EV6_mcheck *)mchk_header;
+	int status = MCHK_DISPOSITION_UNKNOWN_ERROR;
+
+	/*
+	 * Machine check codes
+	 */
+#define PRIVATEER_MCHK__CORR_ECC		0x86	/* 630 */
+#define PRIVATEER_MCHK__DC_TAG_PERR		0x9E	/* 630 */
+#define PRIVATEER_MCHK__PAL_BUGCHECK		0x8E	/* 670 */
+#define PRIVATEER_MCHK__OS_BUGCHECK		0x90	/* 670 */
+#define PRIVATEER_MCHK__PROC_HRD_ERR		0x98	/* 670 */
+#define PRIVATEER_MCHK__ISTREAM_CMOV_PRX	0xA0	/* 670 */
+#define PRIVATEER_MCHK__ISTREAM_CMOV_FLT	0xA2	/* 670 */
+#define PRIVATEER_MCHK__SYS_HRD_ERR		0x202	/* 660 */
+#define PRIVATEER_MCHK__SYS_CORR_ERR		0x204	/* 620 */
+#define PRIVATEER_MCHK__SYS_ENVIRON		0x206	/* 680 */
+
+	switch(ev6mchk->MCHK_Code) {
+	/*
+	 * Vector 630 - Processor, Correctable
+	 */
+	case PRIVATEER_MCHK__CORR_ECC:
+	case PRIVATEER_MCHK__DC_TAG_PERR:
+		/*
+		 * Fall through to vector 670 for processing...
+		 */
+	/*
+	 * Vector 670 - Processor, Uncorrectable
+	 */
+	case PRIVATEER_MCHK__PAL_BUGCHECK:
+	case PRIVATEER_MCHK__OS_BUGCHECK:
+	case PRIVATEER_MCHK__PROC_HRD_ERR:
+	case PRIVATEER_MCHK__ISTREAM_CMOV_PRX:
+	case PRIVATEER_MCHK__ISTREAM_CMOV_FLT:
+		status |= ev6_process_logout_frame(mchk_header, print);
+		break;
+
+	/*
+	 * Vector 620 - System, Correctable
+	 */
+	case PRIVATEER_MCHK__SYS_CORR_ERR:
+		/*
+		 * Fall through to vector 660 for processing...
+		 */
+	/*
+	 * Vector 660 - System, Uncorrectable
+	 */
+	case PRIVATEER_MCHK__SYS_HRD_ERR:
+		status |= titan_process_logout_frame(mchk_header, print);
+		break;
+
+	/* 
+	 * Vector 680 - System, Environmental
+	 */
+	case PRIVATEER_MCHK__SYS_ENVIRON:	/* System, Environmental */
+		status |= privateer_process_680_frame(mchk_header, print);
+		break;
+
+	/* 
+	 * Unknown
+	 */
+	default:
+		status |= MCHK_DISPOSITION_REPORT;
+		if (print) {
+			printk("%s** Unknown Error, frame follows\n", 
+			       err_print_prefix);
+			mchk_dump_logout_frame(mchk_header);
+		}
+
+	}
+
+	return status;
+}
+
+void
+privateer_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs)
+{
+	struct el_common *mchk_header = (struct el_common *)la_ptr;
+	struct el_TITAN_sysdata_mcheck *tmchk =
+		(struct el_TITAN_sysdata_mcheck *)
+		(la_ptr + mchk_header->sys_offset);
+	u64 irqmask;
+	char *saved_err_prefix = err_print_prefix;
+
+#define PRIVATEER_680_INTERRUPT_MASK		(0xE00UL)
+#define PRIVATEER_HOTPLUG_INTERRUPT_MASK	(0xE00UL)
+
+	/*
+	 * Sync the processor.
+	 */
+	mb();
+	draina();
+
+	/* 
+	 * Only handle system events here.
+	 */
+	if (vector != SCB_Q_SYSEVENT) 
+		return titan_machine_check(vector, la_ptr, regs);
+
+	/*
+	 * Report the event - System Events should be reported even if no
+	 * error is indicated since the event could indicate the return
+	 * to normal status.
+	 */
+	err_print_prefix = KERN_CRIT;
+	printk("%s*System Event (Vector 0x%x) reported on CPU %d:\n", 
+	       err_print_prefix,
+	       (unsigned int)vector, (int)smp_processor_id());
+	privateer_process_680_frame(mchk_header, 1);
+	err_print_prefix = saved_err_prefix;
+	
+	/* 
+	 * Convert any pending interrupts which report as 680 machine
+	 * checks to interrupts.
+	 */
+	irqmask = tmchk->c_dirx & PRIVATEER_680_INTERRUPT_MASK;
+
+	/*
+	 * Dispatch the interrupt(s).
+	 */
+	titan_dispatch_irqs(irqmask, regs);
+
+	/* 
+	 * Release the logout frame.
+	 */
+	wrmces(0x7);
+	mb();
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/gct.c linux-2.4.21-pre6/arch/alpha/kernel/gct.c
--- linux-2.4.20/arch/alpha/kernel/gct.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/kernel/gct.c	2003-03-26 23:49:25.000000000 +0000
@@ -0,0 +1,48 @@
+/*
+ *	linux/arch/alpha/kernel/gct.c
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+
+#include <asm/hwrpb.h>
+#include <asm/gct.h>
+
+int
+gct6_find_nodes(gct6_node *node, gct6_search_struct *search)
+{
+	gct6_search_struct *wanted;
+	int status = 0;
+
+	/* First check the magic number.  */
+	if (node->magic != GCT_NODE_MAGIC) {
+		printk(KERN_ERR "GCT Node MAGIC incorrect - GCT invalid\n");
+		return -EINVAL;
+	}
+
+	/* Check against the search struct.  */
+	for (wanted = search; 
+	     wanted && (wanted->type | wanted->subtype); 
+	     wanted++) {
+		if (node->type != wanted->type)
+			continue;
+		if (node->subtype != wanted->subtype)
+			continue;
+
+		/* Found it -- call out.  */
+		if (wanted->callout)
+			wanted->callout(node);
+	}
+
+	/* Now walk the tree, siblings first.  */
+	if (node->next) 
+		status |= gct6_find_nodes(GCT_NODE_PTR(node->next), search);
+
+	/* Then the children.  */
+	if (node->child) 
+		status |= gct6_find_nodes(GCT_NODE_PTR(node->child), search);
+
+	return status;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/irq.c linux-2.4.21-pre6/arch/alpha/kernel/irq.c
--- linux-2.4.20/arch/alpha/kernel/irq.c	2001-09-17 20:16:30.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/kernel/irq.c	2003-03-26 23:49:51.000000000 +0000
@@ -374,15 +374,17 @@
 	irq_dir[irq] = proc_mkdir(name, root_irq_dir);
 
 #ifdef CONFIG_SMP
-	/* create /proc/irq/1234/smp_affinity */
-	entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]);
+	if (irq_desc[irq].handler->set_affinity) {
+		/* create /proc/irq/1234/smp_affinity */
+		entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]);
+
+		entry->nlink = 1;
+		entry->data = (void *)(long)irq;
+		entry->read_proc = irq_affinity_read_proc;
+		entry->write_proc = irq_affinity_write_proc;
 
-	entry->nlink = 1;
-	entry->data = (void *)(long)irq;
-	entry->read_proc = irq_affinity_read_proc;
-	entry->write_proc = irq_affinity_write_proc;
-
-	smp_affinity_entry[irq] = entry;
+		smp_affinity_entry[irq] = entry;
+	}
 #endif
 }
 
@@ -410,12 +412,16 @@
 #endif
 
 	/*
-	 * Create entries for all existing IRQs.
+	 * Create entries for all existing IRQs. If the number of IRQs
+	 * is greater the 1/4 the total dynamic inode space for /proc,
+	 * don't pollute the inode space
 	 */
-	for (i = 0; i < NR_IRQS; i++) {
-		if (irq_desc[i].handler == &no_irq_type)
-			continue;
-		register_irq_proc(i);
+	if (ACTUAL_NR_IRQS < (PROC_NDYNAMIC / 4)) {
+		for (i = 0; i < ACTUAL_NR_IRQS; i++) {
+			if (irq_desc[i].handler == &no_irq_type)
+				continue;
+			register_irq_proc(i);
+		}
 	}
 }
 
@@ -534,7 +540,7 @@
 	*p++ = '\n';
 #endif
 
-	for (i = 0; i < NR_IRQS; i++) {
+	for (i = 0; i < ACTUAL_NR_IRQS; i++) {
 		action = irq_desc[i].action;
 		if (!action) 
 			continue;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/irq_alpha.c linux-2.4.21-pre6/arch/alpha/kernel/irq_alpha.c
--- linux-2.4.20/arch/alpha/kernel/irq_alpha.c	2001-10-05 01:47:08.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/kernel/irq_alpha.c	2003-03-26 23:49:18.000000000 +0000
@@ -152,7 +152,7 @@
 
 	mchk_header = (struct el_common *)la_ptr;
 
-	printk(KERN_CRIT "%s machine check: vector=0x%lx pc=0x%lx code=0x%lx\n",
+	printk(KERN_CRIT "%s machine check: vector=0x%lx pc=0x%lx code=0x%x\n",
 	       machine, vector, regs->pc, mchk_header->code);
 
 	switch ((unsigned int) mchk_header->code) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/machvec_impl.h linux-2.4.21-pre6/arch/alpha/kernel/machvec_impl.h
--- linux-2.4.20/arch/alpha/kernel/machvec_impl.h	2001-09-13 22:21:32.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/kernel/machvec_impl.h	2003-03-26 23:49:10.000000000 +0000
@@ -9,10 +9,12 @@
 #include <linux/config.h>
 #include <asm/pgalloc.h>
 
-/* Whee.  IRONGATE, POLARIS, TSUNAMI, TITAN, and WILDFIRE don't have an HAE.
+/* Whee.  These systems don't have an HAE:
+       IRONGATE, MARVEL, POLARIS, TSUNAMI, TITAN, WILDFIRE
    Fix things up for the GENERIC kernel by defining the HAE address
    to be that of the cache. Now we can read and write it as we like.  ;-)  */
 #define IRONGATE_HAE_ADDRESS	(&alpha_mv.hae_cache)
+#define MARVEL_HAE_ADDRESS	(&alpha_mv.hae_cache)
 #define POLARIS_HAE_ADDRESS	(&alpha_mv.hae_cache)
 #define TSUNAMI_HAE_ADDRESS	(&alpha_mv.hae_cache)
 #define TITAN_HAE_ADDRESS	(&alpha_mv.hae_cache)
@@ -32,7 +34,6 @@
 #define T2_IACK_SC		1
 #define WILDFIRE_IACK_SC	1 /* FIXME */
 
-
 /*
  * Some helpful macros for filling in the blanks.
  */
@@ -63,6 +64,13 @@
 	mv_flush_tlb_current:		ev5_flush_tlb_current,		\
 	mv_flush_tlb_current_page:	ev5_flush_tlb_current_page
 
+#define DO_EV7_MMU							\
+	max_asn:			EV6_MAX_ASN,			\
+	mv_switch_mm:			ev5_switch_mm,			\
+	mv_activate_mm:			ev5_activate_mm,		\
+	mv_flush_tlb_current:		ev5_flush_tlb_current,		\
+	mv_flush_tlb_current_page:	ev5_flush_tlb_current_page
+
 #define IO_LITE(UP,low)							\
 	hae_register:		(unsigned long *) CAT(UP,_HAE_ADDRESS),	\
 	iack_sc:		CAT(UP,_IACK_SC),			\
@@ -91,6 +99,7 @@
 #define DO_CIA_IO	IO(CIA,cia)
 #define DO_IRONGATE_IO	IO(IRONGATE,irongate)
 #define DO_LCA_IO	IO(LCA,lca)
+#define DO_MARVEL_IO	IO(MARVEL,marvel)
 #define DO_MCPCIA_IO	IO(MCPCIA,mcpcia)
 #define DO_POLARIS_IO	IO(POLARIS,polaris)
 #define DO_T2_IO	IO(T2,t2)
@@ -109,6 +118,7 @@
 #define DO_CIA_BUS	BUS(cia)
 #define DO_IRONGATE_BUS	BUS(irongate)
 #define DO_LCA_BUS	BUS(lca)
+#define DO_MARVEL_BUS	BUS(marvel)
 #define DO_MCPCIA_BUS	BUS(mcpcia)
 #define DO_POLARIS_BUS	BUS(polaris)
 #define DO_T2_BUS	BUS(t2)
@@ -116,7 +126,6 @@
 #define DO_TITAN_BUS	BUS(titan)
 #define DO_WILDFIRE_BUS	BUS(wildfire)
 
-
 /*
  * In a GENERIC kernel, we have lots of these vectors floating about,
  * all but one of which we want to go away.  In a non-GENERIC kernel,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/osf_sys.c linux-2.4.21-pre6/arch/alpha/kernel/osf_sys.c
--- linux-2.4.20/arch/alpha/kernel/osf_sys.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/kernel/osf_sys.c	2003-03-26 23:48:57.000000000 +0000
@@ -462,13 +462,8 @@
 
 asmlinkage int osf_swapon(const char *path, int flags, int lowat, int hiwat)
 {
-	int ret;
-
 	/* for now, simply ignore lowat and hiwat... */
-	lock_kernel();
-	ret = sys_swapon(path, flags);
-	unlock_kernel();
-	return ret;
+	return sys_swapon(path, flags);
 }
 
 asmlinkage unsigned long sys_getpagesize(void)
@@ -529,18 +524,13 @@
 	unsigned long raddr;
 	long err;
 
-	lock_kernel();
 	err = sys_shmat(shmid, shmaddr, shmflg, &raddr);
-	if (err)
-		goto out;
+
 	/*
 	 * This works because all user-level addresses are
 	 * non-negative longs!
 	 */
-	err = raddr;
-out:
-	unlock_kernel();
-	return err;
+	return err ? err : (long)raddr;
 }
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/pci.c linux-2.4.21-pre6/arch/alpha/kernel/pci.c
--- linux-2.4.20/arch/alpha/kernel/pci.c	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/kernel/pci.c	2003-03-26 23:49:00.000000000 +0000
@@ -41,6 +41,8 @@
 
 const char pci_hae0_name[] = "HAE0";
 
+/* Indicate whether we respect the PCI setup left by console. */
+int __initdata pci_probe_only;
 
 /*
  * The PCI controller list.
@@ -66,17 +68,6 @@
 }
 
 static void __init
-quirk_ali_ide_ports(struct pci_dev *dev)
-{
-	if (dev->resource[0].end == 0xffff)
-		dev->resource[0].end = dev->resource[0].start + 7;
-	if (dev->resource[2].end == 0xffff)
-		dev->resource[2].end = dev->resource[2].start + 7;
-	if (dev->resource[3].end == 0xffff)
-		dev->resource[3].end = dev->resource[3].start + 7;
-}
-
-static void __init
 quirk_cypress(struct pci_dev *dev)
 {
 	/* The Notorious Cy82C693 chip.  */
@@ -114,8 +105,6 @@
 	  quirk_eisa_bridge },
 	{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82378,
 	  quirk_isa_bridge },
-	{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229,
-	  quirk_ali_ide_ports },
 	{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693,
 	  quirk_cypress },
 	{ 0 }
@@ -243,10 +232,25 @@
 	struct pci_dev *dev = bus->self;
 
 	if (!dev) {
-		/* Root bus */
+		/* Root bus. */
+		u32 pci_mem_end;
+		u32 sg_base = hose->sg_pci ? hose->sg_pci->dma_base : ~0;
+		unsigned long end;
+
 		bus->resource[0] = hose->io_space;
 		bus->resource[1] = hose->mem_space;
-	}
+
+		/* Adjust hose mem_space limit to prevent PCI allocations
+		   in the iommu windows. */
+		pci_mem_end = min((u32)__direct_map_base, sg_base) - 1;
+		end = hose->mem_space->start + pci_mem_end;
+		if (hose->mem_space->end > end)
+			hose->mem_space->end = end;
+ 	} else if (pci_probe_only &&
+ 		   (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
+ 		pci_read_bridge_bases(bus);
+ 		pcibios_fixup_device_resources(dev, bus);
+	} 
 
 	for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) {
 		struct pci_dev *dev = pci_dev_b(ln);
@@ -359,6 +363,30 @@
 	pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
 }
 
+static void __init
+pcibios_claim_console_setup(void)
+{
+	struct list_head *lb;
+
+	for(lb = pci_root_buses.next; lb != &pci_root_buses; lb = lb->next) {
+		struct pci_bus *b = pci_bus_b(lb);
+		struct list_head *ld;
+
+		for (ld = b->devices.next; ld != &b->devices; ld = ld->next) {
+			struct pci_dev *dev = pci_dev_b(ld);
+			int i;
+
+			for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+				struct resource *r = &dev->resource[i];
+
+				if (r->parent || !r->start || !r->flags)
+					continue;
+				pci_claim_resource(dev, i);
+			}
+		}
+	}
+}
+
 void __init
 common_init_pci(void)
 {
@@ -376,7 +404,12 @@
 		next_busno += 1;
 	}
 
-	pci_assign_unassigned_resources();
+	if (pci_probe_only)
+		pcibios_claim_console_setup();
+	else	/* FIXME: `else' will be removed when
+		   pci_assign_unassigned_resources() is able to work
+		   correctly with [partially] allocated PCI tree. */
+		pci_assign_unassigned_resources();
 	pci_fixup_irqs(alpha_mv.pci_swizzle, alpha_mv.pci_map_irq);
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/pci_impl.h linux-2.4.21-pre6/arch/alpha/kernel/pci_impl.h
--- linux-2.4.20/arch/alpha/kernel/pci_impl.h	2001-10-12 22:35:53.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/kernel/pci_impl.h	2003-03-26 23:49:54.000000000 +0000
@@ -52,15 +52,16 @@
 #define APECS_AND_LCA_DEFAULT_MEM_BASE ((16+2)*1024*1024)
 
 /*
- * Because the MCPCIA core logic supports more bits for physical addresses,
- * it should allow an expanded range of SPARSE memory addresses.
- * However, we do not use them all, in order to avoid the HAE manipulation
- * that would be needed.
+ * Because MCPCIA and T2 core logic support more bits for
+ * physical addresses, they should allow an expanded range of SPARSE
+ * memory addresses.  However, we do not use them all, in order to
+ * avoid the HAE manipulation that would be needed.
  */
 #define MCPCIA_DEFAULT_MEM_BASE ((32+2)*1024*1024)
+#define T2_DEFAULT_MEM_BASE ((16+1)*1024*1024)
 
 /*
- * Because CIA and PYXIS and T2 have more bits for physical addresses,
+ * Because CIA and PYXIS have more bits for physical addresses,
  * they support an expanded range of SPARSE memory addresses.
  */
 #define DEFAULT_MEM_BASE ((128+16)*1024*1024)
@@ -70,6 +71,8 @@
 
 #define IRONGATE_DEFAULT_MEM_BASE ((256*8-16)*1024*1024)
 
+#define DEFAULT_AGP_APER_SIZE	(64*1024*1024)
+
 /* 
  * A small note about bridges and interrupts.  The DECchip 21050 (and
  * later) adheres to the PCI-PCI bridge specification.  This says that
@@ -149,16 +152,23 @@
 extern struct pci_controller *hose_head, **hose_tail;
 extern struct pci_controller *pci_isa_hose;
 
+/* Indicate that we trust the console to configure things properly.  */
+extern int pci_probe_only;
+
+extern unsigned long alpha_agpgart_size;
+
 extern void common_init_pci(void);
 extern u8 common_swizzle(struct pci_dev *, u8 *);
 extern struct pci_controller *alloc_pci_controller(void);
 extern struct resource *alloc_resource(void);
 
+extern struct pci_iommu_arena *iommu_arena_new_node(int,
+						    struct pci_controller *,
+					            dma_addr_t, unsigned long,
+					            unsigned long);
 extern struct pci_iommu_arena *iommu_arena_new(struct pci_controller *,
 					       dma_addr_t, unsigned long,
 					       unsigned long);
-extern long iommu_arena_alloc(struct pci_iommu_arena *arena, long n);
-
 extern const char *const pci_io_names[];
 extern const char *const pci_mem_names[];
 extern const char pci_hae0_name[];
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/pci_iommu.c linux-2.4.21-pre6/arch/alpha/kernel/pci_iommu.c
--- linux-2.4.20/arch/alpha/kernel/pci_iommu.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/kernel/pci_iommu.c	2003-03-26 23:49:55.000000000 +0000
@@ -30,10 +30,9 @@
 #define DEBUG_NODIRECT 0
 #define DEBUG_FORCEDAC 0
 
-/* Most Alphas support 32-bit ISA DMA. Exceptions are XL, Ruffian and
-   Nautilus (see asm/dma.h for details). */
-#define ISA_DMA_MASK	(MAX_DMA_ADDRESS - IDENT_ADDR - 1 < 0xffffffff ? \
-			 MAX_DMA_ADDRESS - IDENT_ADDR - 1 : 0xffffffff)
+/* Most Alphas support 32-bit ISA DMA. Exceptions are XL, Ruffian,
+   Sable, and Alcor (see asm-alpha/dma.h for details). */
+#define ISA_DMA_MASK	(MAX_DMA_ADDRESS - IDENT_ADDR - 1)
 
 static inline unsigned long
 mk_iommu_pte(unsigned long paddr)
@@ -61,8 +60,8 @@
 }
 
 struct pci_iommu_arena *
-iommu_arena_new(struct pci_controller *hose, dma_addr_t base,
-		unsigned long window_size, unsigned long align)
+iommu_arena_new_node(int nid, struct pci_controller *hose, dma_addr_t base,
+		     unsigned long window_size, unsigned long align)
 {
 	unsigned long mem_size;
 	struct pci_iommu_arena *arena;
@@ -76,9 +75,36 @@
 	if (align < mem_size)
 		align = mem_size;
 
+
+#ifdef CONFIG_DISCONTIGMEM
+
+        if (!NODE_DATA(nid) ||
+            (NULL == (arena = alloc_bootmem_node(NODE_DATA(nid),
+                                                 sizeof(*arena))))) {
+                printk("%s: couldn't allocate arena from node %d\n"
+                       "    falling back to system-wide allocation\n",
+                       __FUNCTION__, nid);
+                arena = alloc_bootmem(sizeof(*arena));
+        }
+
+        if (!NODE_DATA(nid) ||
+            (NULL == (arena->ptes = __alloc_bootmem_node(NODE_DATA(nid),
+                                                         mem_size,
+                                                         align,
+                                                         0)))) {
+                printk("%s: couldn't allocate arena ptes from node %d\n"
+                       "    falling back to system-wide allocation\n",
+                       __FUNCTION__, nid);
+                arena->ptes = __alloc_bootmem(mem_size, align, 0);
+        }
+
+#else /* CONFIG_DISCONTIGMEM */
+
 	arena = alloc_bootmem(sizeof(*arena));
 	arena->ptes = __alloc_bootmem(mem_size, align, 0);
 
+#endif /* CONFIG_DISCONTIGMEM */
+
 	spin_lock_init(&arena->lock);
 	arena->hose = hose;
 	arena->dma_base = base;
@@ -92,6 +118,13 @@
 	return arena;
 }
 
+struct pci_iommu_arena *
+iommu_arena_new(struct pci_controller *hose, dma_addr_t base,
+		unsigned long window_size, unsigned long align)
+{
+	return iommu_arena_new_node(0, hose, base, window_size, align);
+}
+
 /* Must be called with the arena lock held */
 static long
 iommu_arena_find_pages(struct pci_iommu_arena *arena, long n, long mask)
@@ -133,8 +166,8 @@
 	return p;
 }
 
-long
-iommu_arena_alloc(struct pci_iommu_arena *arena, long n)
+static long
+iommu_arena_alloc(struct pci_iommu_arena *arena, long n, unsigned int align)
 {
 	unsigned long flags;
 	unsigned long *ptes;
@@ -144,7 +177,7 @@
 
 	/* Search for N empty ptes */
 	ptes = arena->ptes;
-	mask = arena->align_entry - 1;
+	mask = max(align, arena->align_entry) - 1;
 	p = iommu_arena_find_pages(arena, n, mask);
 	if (p < 0) {
 		spin_unlock_irqrestore(&arena->lock, flags);
@@ -233,7 +266,8 @@
 		arena = hose->sg_isa;
 
 	npages = calc_npages((paddr & ~PAGE_MASK) + size);
-	dma_ofs = iommu_arena_alloc(arena, npages);
+	/* Force allocation to 64KB boundary for all ISA devices. */
+	dma_ofs = iommu_arena_alloc(arena, npages, pdev ? 0 : 8);
 	if (dma_ofs < 0) {
 		printk(KERN_WARNING "pci_map_single failed: "
 		       "could not allocate dma page tables\n");
@@ -361,8 +395,10 @@
 {
 	void *cpu_addr;
 	long order = get_order(size);
+	int gfp = GFP_ATOMIC;
 
-	cpu_addr = (void *)__get_free_pages(GFP_ATOMIC, order);
+try_again:
+	cpu_addr = (void *)__get_free_pages(gfp, order);
 	if (! cpu_addr) {
 		printk(KERN_INFO "pci_alloc_consistent: "
 		       "get_free_pages failed from %p\n",
@@ -376,7 +412,12 @@
 	*dma_addrp = pci_map_single_1(pdev, cpu_addr, size, 0);
 	if (*dma_addrp == 0) {
 		free_pages((unsigned long)cpu_addr, order);
-		return NULL;
+		if (alpha_mv.mv_pci_tbi || (gfp & GFP_DMA))
+			return NULL;
+		/* The address doesn't fit required mask and we
+		   do not have iommu. Try again with GFP_DMA. */
+		gfp |= GFP_DMA;
+		goto try_again;
 	}
 		
 	DBGA2("pci_alloc_consistent: %lx -> [%p,%x] from %p\n",
@@ -505,7 +546,7 @@
 
 	paddr &= ~PAGE_MASK;
 	npages = calc_npages(paddr + size);
-	dma_ofs = iommu_arena_alloc(arena, npages);
+	dma_ofs = iommu_arena_alloc(arena, npages, 0);
 	if (dma_ofs < 0) {
 		/* If we attempted a direct map above but failed, die.  */
 		if (leader->dma_address == 0)
@@ -742,6 +783,10 @@
 	if (arena && arena->dma_base + arena->size - 1 <= mask)
 		return 1;
 
+	/* As last resort try ZONE_DMA.  */
+	if (!__direct_map_base && MAX_DMA_ADDRESS - IDENT_ADDR - 1 <= mask)
+		return 1;
+
 	return 0;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/process.c linux-2.4.21-pre6/arch/alpha/kernel/process.c
--- linux-2.4.20/arch/alpha/kernel/process.c	2001-09-30 19:26:08.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/kernel/process.c	2003-03-26 23:49:25.000000000 +0000
@@ -336,7 +336,7 @@
 }
 
 /*
- * fill in the user structure for a core dump..
+ * Fill in the user structure for an ECOFF core dump.
  */
 void
 dump_thread(struct pt_regs * pt, struct user * dump)
@@ -396,6 +396,55 @@
 	memcpy((char *)dump->regs + EF_SIZE, sw->fp, 32 * 8);
 }
 
+/*
+ * Fill in the user structure for a ELF core dump.
+ */
+void
+dump_elf_thread(elf_gregset_t dest, struct pt_regs *pt,
+		struct task_struct *task)
+{
+	/* switch stack follows right below pt_regs: */
+	struct switch_stack * sw = ((struct switch_stack *) pt) - 1;
+
+	dest[ 0] = pt->r0;
+	dest[ 1] = pt->r1;
+	dest[ 2] = pt->r2;
+	dest[ 3] = pt->r3;
+	dest[ 4] = pt->r4;
+	dest[ 5] = pt->r5;
+	dest[ 6] = pt->r6;
+	dest[ 7] = pt->r7;
+	dest[ 8] = pt->r8;
+	dest[ 9] = sw->r9;
+	dest[10] = sw->r10;
+	dest[11] = sw->r11;
+	dest[12] = sw->r12;
+	dest[13] = sw->r13;
+	dest[14] = sw->r14;
+	dest[15] = sw->r15;
+	dest[16] = pt->r16;
+	dest[17] = pt->r17;
+	dest[18] = pt->r18;
+	dest[19] = pt->r19;
+	dest[20] = pt->r20;
+	dest[21] = pt->r21;
+	dest[22] = pt->r22;
+	dest[23] = pt->r23;
+	dest[24] = pt->r24;
+	dest[25] = pt->r25;
+	dest[26] = pt->r26;
+	dest[27] = pt->r27;
+	dest[28] = pt->r28;
+	dest[29] = pt->gp;
+	dest[30] = rdusp();
+	dest[31] = pt->pc;
+
+	/* Once upon a time this was the PS value.  Which is stupid
+	   since that is always 8 for usermode.  Usurped for the more
+	   useful value of the thread's UNIQUE field.  */
+	dest[32] = task->thread.unique;
+}
+
 int
 dump_fpu(struct pt_regs * regs, elf_fpregset_t *r)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/proto.h linux-2.4.21-pre6/arch/alpha/kernel/proto.h
--- linux-2.4.20/arch/alpha/kernel/proto.h	2002-02-25 19:37:52.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/kernel/proto.h	2003-03-26 23:49:18.000000000 +0000
@@ -1,4 +1,6 @@
 #include <linux/config.h>
+
+
 /* Prototypes of functions used across modules here in this directory.  */
 
 #define vucp	volatile unsigned char  *
@@ -24,6 +26,7 @@
 extern void cia_init_pci(void);
 extern void cia_init_arch(void);
 extern void pyxis_init_arch(void);
+extern void cia_kill_arch(int);
 extern void cia_machine_check(u64, u64, struct pt_regs *);
 extern void cia_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
 
@@ -40,6 +43,21 @@
 extern void lca_machine_check(u64, u64, struct pt_regs *);
 extern void lca_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
 
+/* core_marvel.c */
+extern struct pci_ops marvel_pci_ops;
+extern void marvel_init_arch(void);
+extern void marvel_kill_arch(int);
+extern void marvel_machine_check(u64, u64, struct pt_regs *);
+extern void marvel_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
+extern int marvel_pa_to_nid(unsigned long);
+extern int marvel_cpuid_to_nid(int);
+extern unsigned long marvel_node_mem_start(int);
+extern unsigned long marvel_node_mem_size(int);
+extern struct _alpha_agp_info *marvel_agp_info(void);
+struct io7 *marvel_find_io7(int pe);
+struct io7 *marvel_next_io7(struct io7 *prev);
+void io7_clear_errors(struct io7 *io7);
+
 /* core_mcpcia.c */
 extern struct pci_ops mcpcia_pci_ops;
 extern void mcpcia_init_arch(void);
@@ -59,7 +77,7 @@
 extern struct pci_ops t2_pci_ops;
 extern void t2_init_arch(void);
 extern void t2_machine_check(u64, u64, struct pt_regs *);
-#define t2_pci_tbi ((void *)0)
+extern void t2_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
 
 /* core_titan.c */
 extern struct pci_ops titan_pci_ops;
@@ -67,6 +85,7 @@
 extern void titan_kill_arch(int);
 extern void titan_machine_check(u64, u64, struct pt_regs *);
 extern void titan_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
+extern struct _alpha_agp_info *titan_agp_info(void);
 
 /* core_tsunami.c */
 extern struct pci_ops tsunami_pci_ops;
@@ -81,13 +100,23 @@
 extern void wildfire_kill_arch(int);
 extern void wildfire_machine_check(u64, u64, struct pt_regs *);
 extern void wildfire_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
+extern int wildfire_pa_to_nid(unsigned long);
+extern int wildfire_cpuid_to_nid(int);
+extern unsigned long wildfire_node_mem_start(int);
+extern unsigned long wildfire_node_mem_size(int);
 
 /* setup.c */
 extern unsigned long srm_hae;
 extern int boot_cpuid;
-extern int srmcons_output;
+
+/* srmcons.c */
+#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM)
 extern void register_srm_console(void);
 extern void unregister_srm_console(void);
+#else
+#define register_srm_console()
+#define unregister_srm_console()
+#endif
 
 /* smp.c */
 extern void setup_smp(void);
@@ -148,6 +177,10 @@
 extern void switch_to_system_map(void);
 extern void srm_paging_stop(void);
 
+/* ../mm/remap.c */
+extern int __alpha_remap_area_pages(unsigned long, unsigned long, 
+				    unsigned long, unsigned long);
+
 /* irq.c */
 
 #ifdef CONFIG_SMP
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/ptrace.c linux-2.4.21-pre6/arch/alpha/kernel/ptrace.c
--- linux-2.4.20/arch/alpha/kernel/ptrace.c	2001-09-19 00:03:51.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/kernel/ptrace.c	2003-03-26 23:49:54.000000000 +0000
@@ -102,7 +102,9 @@
 
 	if (regno == 30) {
 		addr = &task->thread.usp;
-	} else if (regno == 31 || regno > 64) {
+	} else if (regno == 65) {
+		addr = &task->thread.unique;
+	} else if (regno == 31 || regno > 65) {
 		zero = 0;
 		addr = &zero;
 	} else {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/setup.c linux-2.4.21-pre6/arch/alpha/kernel/setup.c
--- linux-2.4.20/arch/alpha/kernel/setup.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/kernel/setup.c	2003-03-26 23:49:09.000000000 +0000
@@ -71,18 +71,25 @@
 
  * "srmcons" specified in the boot command arguments allows us to
  * see kernel messages during the period of time before the true
- * console device is "registered" during console_init(). As of this
- * version (2.4.10), time_init() is the last Alpha-specific code
- * called before console_init(), so we put "unregister" code
- * there to prevent schizophrenic console behavior later... ;-}
+ * console device is "registered" during console_init(). 
+ * As of this version (2.4.20), console_init() will call
+ * disable_early_printk() as the last action before initializing
+ * the console drivers. That's the last possible time srmcons can be 
+ * unregistered without interfering with console behavior.
  *
- * By default, OFF; set it with a bootcommand arg of "srmcons".
+ * By default, OFF; set it with a bootcommand arg of "srmcons" or 
+ * "console=srm". The meaning of these two args is:
+ *     "srmcons"     - early callback prints 
+ *     "console=srm" - full callback based console, including early prints
  */
 int srmcons_output = 0;
 
 /* Enforce a memory size limit; useful for testing. By default, none. */
 unsigned long mem_size_limit = 0;
 
+/* Set AGP GART window size (0 means disabled). */
+unsigned long alpha_agpgart_size = DEFAULT_AGP_APER_SIZE;
+
 #ifdef CONFIG_ALPHA_GENERIC
 struct alpha_machine_vector alpha_mv;
 int alpha_using_srm;
@@ -147,6 +154,7 @@
 WEAK(eiger_mv);
 WEAK(jensen_mv);
 WEAK(lx164_mv);
+WEAK(marvel_ev7_mv);
 WEAK(miata_mv);
 WEAK(mikasa_mv);
 WEAK(mikasa_primo_mv);
@@ -166,6 +174,7 @@
 WEAK(shark_mv);
 WEAK(sx164_mv);
 WEAK(takara_mv);
+WEAK(titan_mv);
 WEAK(webbrick_mv);
 WEAK(wildfire_mv);
 WEAK(xl_mv);
@@ -243,6 +252,27 @@
         return end >> PAGE_SHIFT; /* Return the PFN of the limit. */
 }
 
+#ifdef CONFIG_BLK_DEV_INITRD
+void * __init
+move_initrd(unsigned long mem_limit)
+{
+	void *start;
+	unsigned long size;
+
+	size = initrd_end - initrd_start;
+	start = __alloc_bootmem(size, PAGE_SIZE, 0);
+	if (!start || __pa(start) + size > mem_limit) {
+		initrd_start = initrd_end = 0;
+		return NULL;
+	}
+	memmove(start, (void *)initrd_start, size);
+	initrd_start = (unsigned long)start;
+	initrd_end = initrd_start + size;
+	printk(KERN_INFO "initrd moved to %p\n", start);
+	return start;
+}
+#endif
+
 #ifndef CONFIG_DISCONTIGMEM
 static void __init
 setup_memory(void *kernel_end)
@@ -274,6 +304,24 @@
 			max_low_pfn = end;
 	}
 
+	/*
+	 * Except for the NUMA systems (wildfire, marvel) all of the 
+	 * Alpha systems we run on support 32GB of memory or less.
+	 * Since the NUMA systems introduce large holes in memory addressing,
+	 * we can get into a situation where there is not enough contiguous
+	 * memory for the memory map. 
+	 *
+	 * Limit memory to the first 32GB to limit the NUMA systems to 
+	 * memory on their first node (wildfire) or 2 (marvel) to avoid 
+	 * not being able to produce the memory map. In order to access 
+	 * all of the memory on the NUMA systems, build with discontiguous
+	 * memory support.
+	 *
+	 * If the user specified a memory limit, let that memory limit stand.
+	 */
+	if (!mem_size_limit) 
+		mem_size_limit = (32ul * 1024 * 1024 * 1024) >> PAGE_SHIFT;
+
 	if (mem_size_limit && max_low_pfn >= mem_size_limit)
 	{
 		printk("setup: forcing memory size to %ldK (from %ldK).\n",
@@ -371,11 +419,11 @@
 		       (void *) initrd_start, INITRD_SIZE);
 
 		if ((void *)initrd_end > phys_to_virt(PFN_PHYS(max_low_pfn))) {
-			printk("initrd extends beyond end of memory "
-			       "(0x%08lx > 0x%p)\ndisabling initrd\n",
-			       initrd_end,
-			       phys_to_virt(PFN_PHYS(max_low_pfn)));
-			initrd_start = initrd_end = 0;
+			if (!move_initrd(PFN_PHYS(max_low_pfn)))
+				printk("initrd extends beyond end of memory "
+				       "(0x%08lx > 0x%p)\ndisabling initrd\n",
+				       initrd_end,
+				       phys_to_virt(PFN_PHYS(max_low_pfn)));
 		} else {
 			reserve_bootmem(virt_to_phys((void *)initrd_start),
 					INITRD_SIZE);
@@ -412,57 +460,6 @@
 #undef PFN_PHYS
 #undef PFN_MAX
 
-#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM)
-/*
- *      Manage the SRM callbacks as a "console".
- */
-static struct console srmcons;
-
-void __init register_srm_console(void)
-{
-        register_console(&srmcons);
-}
-
-void __init unregister_srm_console(void)
-{
-        unregister_console(&srmcons);
-}
-
-static void srm_console_write(struct console *co, const char *s,
-                                unsigned count)
-{
-	srm_printk(s);
-}
-
-static kdev_t srm_console_device(struct console *c)
-{
-  /* Huh? */
-        return MKDEV(TTY_MAJOR, 64 + c->index);
-}
-
-static int __init srm_console_setup(struct console *co, char *options)
-{
-	return 1;
-}
-
-static struct console srmcons = {
-	name:		"srm0",
-	write:		srm_console_write,
-	device:		srm_console_device,
-	setup:		srm_console_setup,
-	flags:		CON_PRINTBUFFER | CON_ENABLED, /* fake it out */
-	index:		-1,
-};
-
-#else
-void __init register_srm_console(void)
-{
-}
-void __init unregister_srm_console(void)
-{
-}
-#endif
-
 void __init
 setup_arch(char **cmdline_p)
 {
@@ -523,7 +520,16 @@
 			continue;
 		}
 		if (strncmp(p, "srmcons", 7) == 0) {
-			srmcons_output = 1;
+			srmcons_output |= 1;
+			continue;
+		}
+		if (strncmp(p, "console=srm", 11) == 0) {
+			srmcons_output |= 2;
+			continue;
+		}
+		if (strncmp(p, "gartsize=", 9) == 0) {
+			alpha_agpgart_size =
+				get_mem_size_limit(p+9) << PAGE_SHIFT;
 			continue;
 		}
 	}
@@ -534,6 +540,13 @@
 	/* If we want SRM console printk echoing early, do it now. */
 	if (alpha_using_srm && srmcons_output) {
 		register_srm_console();
+
+		/*
+		 * If "console=srm" was specified, clear the srmcons_output
+		 * flag now so that time.c won't unregister_srm_console
+		 */
+		if (srmcons_output & 2)
+			srmcons_output = 0;
 	}
 
 	/*
@@ -628,6 +641,15 @@
 	paging_init();
 }
 
+void __init
+disable_early_printk(void)
+{
+	if (alpha_using_srm && srmcons_output) {
+		unregister_srm_console();
+		srmcons_output = 0;
+	}
+}
+
 static char sys_unknown[] = "Unknown";
 static char systype_names[][16] = {
 	"0",
@@ -637,7 +659,7 @@
 	"Mikasa", "EB64", "EB66", "EB64+", "AlphaBook1",
 	"Rawhide", "K2", "Lynx", "XL", "EB164", "Noritake",
 	"Cortex", "29", "Miata", "XXM", "Takara", "Yukon",
-	"Tsunami", "Wildfire", "CUSCO", "Eiger", "Titan"
+	"Tsunami", "Wildfire", "CUSCO", "Eiger", "Titan", "Marvel"
 };
 
 static char unofficial_names[][8] = {"100", "Ruffian"};
@@ -656,15 +678,20 @@
 static char eb66_names[][8] = {"EB66", "EB66+"};
 static int eb66_indices[] = {0,0,1};
 
+static char marvel_names[][16] = {
+	"Marvel/EV7"
+};
+static int marvel_indices[] = { 0 };
+
 static char rawhide_names[][16] = {
 	"Dodge", "Wrangler", "Durango", "Tincup", "DaVinci"
 };
 static int rawhide_indices[] = {0,0,0,1,1,2,2,3,3,4,4};
 
 static char titan_names[][16] = {
-	"0", "Privateer"
+	"DEFAULT", "Privateer", "Falcon", "Granite"
 };
-static int titan_indices[] = {0,1};
+static int titan_indices[] = {0,1,2,2,3};
 
 static char tsunami_names[][16] = {
 	"0", "DP264", "Warhol", "Windjammer", "Monet", "Clipper",
@@ -717,6 +744,7 @@
 		NULL,		/* CUSCO */
 		&eiger_mv,	/* Eiger */
 		NULL,		/* Titan */
+		NULL,		/* Marvel */
 	};
 
 	static struct alpha_machine_vector *unofficial_vecs[] __initdata =
@@ -754,10 +782,17 @@
 		&eb66p_mv
 	};
 
+	static struct alpha_machine_vector *marvel_vecs[] __initdata =
+	{
+		&marvel_ev7_mv,
+	};
+
 	static struct alpha_machine_vector *titan_vecs[] __initdata =
 	{
-		NULL,
+		&titan_mv,		/* default   */
 		&privateer_mv,		/* privateer */
+		&titan_mv,		/* falcon    */
+		&privateer_mv,		/* granite   */
 	};
 
 	static struct alpha_machine_vector *tsunami_vecs[]  __initdata =
@@ -826,7 +861,12 @@
 			if (member < N(eb66_indices))
 				vec = eb66_vecs[eb66_indices[member]];
 			break;
+		case ST_DEC_MARVEL:
+			if (member < N(marvel_indices))
+				vec = marvel_vecs[marvel_indices[member]];
+			break;
 		case ST_DEC_TITAN:
+			vec = titan_vecs[0];	/* default */
 			if (member < N(titan_indices))
 				vec = titan_vecs[titan_indices[member]];
 			break;
@@ -968,11 +1008,16 @@
 		if (member < N(eb66_indices))
 			*variation_name = eb66_names[eb66_indices[member]];
 		break;
+	case ST_DEC_MARVEL:
+		if (member < N(marvel_indices))
+			*variation_name = marvel_names[marvel_indices[member]];
+		break;
 	case ST_DEC_RAWHIDE:
 		if (member < N(rawhide_indices))
 			*variation_name = rawhide_names[rawhide_indices[member]];
 		break;
 	case ST_DEC_TITAN:
+		*variation_name = titan_names[0];	/* default */
 		if (member < N(titan_indices))
 			*variation_name = titan_names[titan_indices[member]];
 		break;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/smp.c linux-2.4.21-pre6/arch/alpha/kernel/smp.c
--- linux-2.4.20/arch/alpha/kernel/smp.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/kernel/smp.c	2003-03-26 23:49:20.000000000 +0000
@@ -77,11 +77,10 @@
 /* cpus reported in the hwrpb */
 static unsigned long hwrpb_cpu_present_mask __initdata = 0;
 
-static int max_cpus = -1;	/* Command-line limitation.  */
+static int max_cpus = NR_CPUS;	/* Command-line limitation.  */
 int smp_num_probed;		/* Internal processor count */
 int smp_num_cpus = 1;		/* Number that came online.  */
 int smp_threads_ready;		/* True once the per process idle is forked. */
-cycles_t cacheflush_time;
 
 int __cpu_number_map[NR_CPUS];
 int __cpu_logical_map[NR_CPUS];
@@ -104,7 +103,7 @@
 	return 1;
 }
 
-__setup("maxcpus", maxcpus);
+__setup("maxcpus=", maxcpus);
 
 
 /*
@@ -175,6 +174,9 @@
 	/* Get our local ticker going. */
 	smp_setup_percpu_timer(cpuid);
 
+	/* Call platform-specific callin, if specified */
+	if (alpha_mv.smp_callin) alpha_mv.smp_callin();
+
 	/* Must have completely accurate bogos.  */
 	__sti();
 
@@ -184,20 +186,20 @@
 	 */
 	wait_boot_cpu_to_stop(cpuid);
 	mb();
- try_again:
+
 	calibrate_delay();
 
 	smp_store_cpu_info(cpuid);
 
 	{
 #define LPJ(c) ((long)cpu_data[c].loops_per_jiffy)
-	  static int tries = 3;
 	  long diff = LPJ(boot_cpuid) - LPJ(cpuid);
 	  if (diff < 0) diff = -diff;
 				
-	  if (diff > LPJ(boot_cpuid)/10 && --tries) {
-	    printk("Bogus BogoMIPS for cpu %d - retrying...\n", cpuid);
-	    goto try_again;
+	  if (diff > LPJ(boot_cpuid)/10) {
+	  	printk("Bogus BogoMIPS for cpu %d - trusting boot CPU\n",
+		       cpuid);
+		loops_per_jiffy = LPJ(cpuid) = LPJ(boot_cpuid);
 	  }
 	}
 
@@ -225,64 +227,6 @@
 	cpu_idle();
 }
 
-
-/*
- * Rough estimation for SMP scheduling, this is the number of cycles it
- * takes for a fully memory-limited process to flush the SMP-local cache.
- *
- * We are not told how much cache there is, so we have to guess.
- */
-static void __init
-smp_tune_scheduling (int cpuid)
-{
-	struct percpu_struct *cpu;
-	unsigned long on_chip_cache;
-	unsigned long freq;
-
-	cpu = (struct percpu_struct*)((char*)hwrpb + hwrpb->processor_offset
-				      + cpuid * hwrpb->processor_size);
-	switch (cpu->type)
-	{
-	case EV45_CPU:
-		on_chip_cache = 16 + 16;
-		break;
-
-	case EV5_CPU:
-	case EV56_CPU:
-		on_chip_cache = 8 + 8 + 96;
-		break;
-
-	case PCA56_CPU:
-		on_chip_cache = 16 + 8;
-		break;
-
-	case EV6_CPU:
-	case EV67_CPU:
-		on_chip_cache = 64 + 64;
-		break;
-
-	default:
-		on_chip_cache = 8 + 8;
-		break;
-	}
-
-	freq = hwrpb->cycle_freq ? : est_cycle_freq;
-
-#if 0
-	/* Magic estimation stolen from x86 port.  */
-	cacheflush_time = freq / 1024L * on_chip_cache / 5000L;
-
-        printk("Using heuristic of %d cycles.\n",
-               cacheflush_time);
-#else
-	/* Magic value to force potential preemption of other CPUs.  */
-	cacheflush_time = INT_MAX;
-
-        printk("Using heuristic of %d cycles.\n",
-               cacheflush_time);
-#endif
-}
-
 /*
  * Send a message to a secondary's console.  "START" is one such
  * interesting message.  ;-)
@@ -622,7 +566,6 @@
 	current->processor = boot_cpuid;
 
 	smp_store_cpu_info(boot_cpuid);
-	smp_tune_scheduling(boot_cpuid);
 	smp_setup_percpu_timer(boot_cpuid);
 
 	init_idle();
@@ -641,6 +584,9 @@
 
 	cpu_count = 1;
 	for (i = 0; i < NR_CPUS; i++) {
+		if (cpu_count >= max_cpus)
+			break;
+
 		if (i == boot_cpuid)
 			continue;
 
@@ -666,8 +612,8 @@
 	}
 	printk(KERN_INFO "SMP: Total of %d processors activated "
 	       "(%lu.%02lu BogoMIPS).\n",
-	       cpu_count, (bogosum + 2500) / (500000/HZ),
-	       ((bogosum + 2500) / (5000/HZ)) % 100);
+	       cpu_count, bogosum / (500000/HZ),
+	       (bogosum / (5000/HZ)) % 100);
 
 	smp_num_cpus = cpu_count;
 }
@@ -922,11 +868,36 @@
 	       && time_before (jiffies, timeout))
 		barrier();
 
-	/* We either got one or timed out -- clear the lock.  */
+	/* If there's no response yet, log a message but allow a longer
+	 * timeout period -- if we get a response this time, log
+	 * a message saying when we got it.. 
+	 */
+	if (atomic_read(&data.unstarted_count) > 0) {
+		long start_time = jiffies;
+		printk(KERN_ERR "%s: initial timeout -- trying long wait\n",
+		       __FUNCTION__);
+		timeout = jiffies + 30 * HZ;
+		while (atomic_read(&data.unstarted_count) > 0
+		       && time_before(jiffies, timeout))
+			barrier();
+		if (atomic_read(&data.unstarted_count) <= 0) {
+			long delta = jiffies - start_time;
+			printk(KERN_ERR 
+			       "%s: response %ld.%ld seconds into long wait\n",
+			       __FUNCTION__, delta / HZ,
+			       (100 * (delta - ((delta / HZ) * HZ))) / HZ);
+		}
+	}
+
+	/* We either got one or timed out -- clear the lock. */
 	mb();
 	smp_call_function_data = 0;
-	if (atomic_read (&data.unstarted_count) > 0)
-		return -ETIMEDOUT;
+
+	/* 
+	 * If after both the initial and long timeout periods we still don't
+	 * have a response, something is very wrong...
+	 */
+	BUG_ON(atomic_read (&data.unstarted_count) > 0);
 
 	/* Wait for a complete response, if needed.  */
 	if (wait) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/srmcons.c linux-2.4.21-pre6/arch/alpha/kernel/srmcons.c
--- linux-2.4.20/arch/alpha/kernel/srmcons.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/kernel/srmcons.c	2003-03-26 23:49:24.000000000 +0000
@@ -0,0 +1,361 @@
+/*
+ *	linux/arch/alpha/kernel/srmcons.c
+ *
+ * Callback based driver for SRM Console console device.
+ * (TTY driver and console driver)
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/timer.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+
+#include <asm/console.h>
+#include <asm/uaccess.h>
+
+
+static spinlock_t srmcons_callback_lock = SPIN_LOCK_UNLOCKED;
+static int srm_is_registered_console = 0;
+
+/* 
+ * The TTY driver
+ */
+#define MAX_SRM_CONSOLE_DEVICES 1	/* only support 1 console device */
+
+static int srmcons_refcount;
+static struct tty_struct *srmcons_table[MAX_SRM_CONSOLE_DEVICES];
+static struct termios *srmcons_termios[MAX_SRM_CONSOLE_DEVICES];
+static struct termios *srmcons_termios_locked[MAX_SRM_CONSOLE_DEVICES];
+
+struct srmcons_private {
+	struct tty_struct *tty;
+	struct timer_list timer;
+	spinlock_t lock;
+};
+
+typedef union _srmcons_result {
+	struct {
+		unsigned long c :61;
+		unsigned long status :3;
+	} bits;
+	long as_long;
+} srmcons_result;
+
+/* called with callback_lock held */
+static int
+srmcons_do_receive_chars(struct tty_struct *tty)
+{
+	srmcons_result result;
+	int count = 0, loops = 0;
+
+	do {
+		result.as_long = callback_getc(0);
+		if (result.bits.status < 2) {
+			tty_insert_flip_char(tty, (char)result.bits.c, 0);
+			count++;
+		}
+	} while((result.bits.status & 1) && (++loops < 10));
+
+	if (count)
+		tty_schedule_flip(tty);
+
+	return count;
+}
+
+static void
+srmcons_receive_chars(unsigned long data)
+{
+	struct srmcons_private *srmconsp = (struct srmcons_private *)data;
+	unsigned long flags;
+	int incr = 10;
+
+	local_irq_save(flags);
+	if (spin_trylock(&srmcons_callback_lock)) {
+		if (!srmcons_do_receive_chars(srmconsp->tty))
+			incr = 100;
+		spin_unlock(&srmcons_callback_lock);
+	} 
+
+	spin_lock(&srmconsp->lock);
+	if (srmconsp->tty) {
+		srmconsp->timer.expires = jiffies + incr;
+		add_timer(&srmconsp->timer);
+	}
+	spin_unlock(&srmconsp->lock);
+
+	local_irq_restore(flags);
+}
+
+/* called with callback_lock held */
+static int
+srmcons_do_write(struct tty_struct *tty, const unsigned char *buf, int count)
+{
+	unsigned char *str_cr = "\r";
+	long c, remaining = count;
+	srmcons_result result;
+	unsigned char *cur;
+	int need_cr;
+
+	for (cur = (unsigned char *)buf; remaining > 0; ) {
+		need_cr = 0;
+		/* 
+		 * Break it up into reasonable size chunks to allow a chance
+		 * for input to get in
+		 */
+		for (c = 0; c < min_t(long, 128L, remaining) && !need_cr; c++)
+			if (cur[c] == '\n')
+				need_cr = 1;
+		
+		while (c > 0) {
+			result.as_long = callback_puts(0, cur, c);
+			c -= result.bits.c;
+			remaining -= result.bits.c;
+			cur += result.bits.c;
+
+			/*
+			 * Check for pending input iff a tty was provided
+			 */
+			if (tty)
+				srmcons_do_receive_chars(tty);
+		}
+
+		while (need_cr) {
+			result.as_long = callback_puts(0, str_cr, 1);
+			if (result.bits.c > 0)
+				need_cr = 0;
+		}
+	}
+	return count;
+}
+
+static int
+srmcons_write(struct tty_struct *tty, int from_user,
+	      const unsigned char *buf, int count)
+{
+	unsigned long flags;
+
+	if (from_user) {
+		unsigned char tmp[512];
+		int ret = 0;
+		size_t c;
+
+		while ((c = count) > 0) {
+			if (c > sizeof(tmp))
+				c = sizeof(tmp);
+			
+			c -= copy_from_user(tmp, buf, c);
+
+			if (!c) { 
+				printk("%s: EFAULT (count %d)\n",
+				       __FUNCTION__, count);
+				return -EFAULT;
+			}
+
+			spin_lock_irqsave(&srmcons_callback_lock, flags);
+			srmcons_do_write(tty, tmp, c);
+			spin_unlock_irqrestore(&srmcons_callback_lock, flags);
+
+			buf += c;
+			count -= c;
+			ret += c;
+		}
+
+		return ret;
+	}
+
+	spin_lock_irqsave(&srmcons_callback_lock, flags);
+	srmcons_do_write(tty, buf, count);
+	spin_unlock_irqrestore(&srmcons_callback_lock, flags);
+
+	return count;
+}
+
+static int
+srmcons_write_room(struct tty_struct *tty)
+{
+	return 512;
+}
+
+static int
+srmcons_chars_in_buffer(struct tty_struct *tty)
+{
+	return 0;
+}
+
+static int
+srmcons_get_private_struct(struct srmcons_private **ps)
+{
+	static struct srmcons_private *srmconsp = NULL;
+	static spinlock_t srmconsp_lock = SPIN_LOCK_UNLOCKED;
+	unsigned long flags;
+	int retval = 0;
+
+	spin_lock_irqsave(&srmconsp_lock, flags);
+
+	do {
+		if (srmconsp != NULL) {
+			*ps = srmconsp;
+			break;
+		}
+
+		srmconsp = kmalloc(sizeof(*srmconsp), GFP_KERNEL);
+		if (srmconsp == NULL) {
+			retval = -ENOMEM;
+			break;
+		}
+
+		srmconsp->tty = NULL;
+		srmconsp->lock = SPIN_LOCK_UNLOCKED;
+		init_timer(&srmconsp->timer);
+
+		*ps = srmconsp;
+	} while(0);
+
+	spin_unlock_irqrestore(&srmconsp_lock, flags);
+
+	return retval;
+}
+
+static int
+srmcons_open(struct tty_struct *tty, struct file *filp)
+{
+	struct srmcons_private *srmconsp;
+	unsigned long flags;
+	int retval;
+
+	retval = srmcons_get_private_struct(&srmconsp);
+	if (retval)
+		return retval;
+
+	spin_lock_irqsave(&srmconsp->lock, flags);
+
+	if (!srmconsp->tty) {
+		tty->driver_data = srmconsp;
+
+		srmconsp->tty = tty;
+		srmconsp->timer.function = srmcons_receive_chars;
+		srmconsp->timer.data = (unsigned long)srmconsp;
+		srmconsp->timer.expires = jiffies + 10;
+		add_timer(&srmconsp->timer);
+	}
+
+	spin_unlock_irqrestore(&srmconsp->lock, flags);
+
+	return 0;
+}
+
+static void
+srmcons_close(struct tty_struct *tty, struct file *filp)
+{
+	struct srmcons_private *srmconsp = tty->driver_data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&srmconsp->lock, flags);
+
+	if (tty->count == 1) {
+		srmconsp->tty = NULL;
+		del_timer(&srmconsp->timer);
+	}
+
+	spin_unlock_irqrestore(&srmconsp->lock, flags);
+}
+
+
+static struct tty_driver srmcons_driver = {
+	.driver_name	= "srm",
+	.name		= "srm",
+	.magic		= TTY_DRIVER_MAGIC,
+	.major		= 0, 	/* dynamic */
+	.minor_start	= 0,
+	.num		= MAX_SRM_CONSOLE_DEVICES,
+	.type		= TTY_DRIVER_TYPE_SYSTEM,
+	.subtype	= SYSTEM_TYPE_SYSCONS,
+
+	.table		= srmcons_table,
+	.termios	= srmcons_termios,
+	.termios_locked	= srmcons_termios_locked,
+	.refcount	= &srmcons_refcount,
+
+	.open		= srmcons_open,
+	.close		= srmcons_close,
+	.write		= srmcons_write,
+	.write_room	= srmcons_write_room,
+	.chars_in_buffer= srmcons_chars_in_buffer,
+};
+
+static int __init
+srmcons_init(void)
+{
+	if (srm_is_registered_console) {
+		srmcons_driver.init_termios = tty_std_termios;
+		return tty_register_driver(&srmcons_driver);
+	}
+
+	return -ENODEV;
+}
+
+module_init(srmcons_init);
+
+
+/*
+ * The console driver
+ */
+static void
+srm_console_write(struct console *co, const char *s, unsigned count)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&srmcons_callback_lock, flags);
+	srmcons_do_write(NULL, s, count);
+	spin_unlock_irqrestore(&srmcons_callback_lock, flags);
+}
+
+static kdev_t
+srm_console_device(struct console *co)
+{
+	return mk_kdev(srmcons_driver.major,
+		       srmcons_driver.minor_start + co->index);
+}
+
+static int __init
+srm_console_setup(struct console *co, char *options)
+{
+	return 0;
+}
+
+static struct console srmcons = {
+	.name		= "srm",
+	.write		= srm_console_write,
+	.device		= srm_console_device,
+	.setup		= srm_console_setup,
+	.flags		= CON_PRINTBUFFER,
+	.index		= -1,
+};
+
+void __init
+register_srm_console(void)
+{
+	if (!srm_is_registered_console) {
+		callback_open_console();
+		register_console(&srmcons);
+		srm_is_registered_console = 1;
+	}
+}
+
+void __init
+unregister_srm_console(void)
+{
+	if (srm_is_registered_console) {
+		callback_close_console();
+		unregister_console(&srmcons);
+		srm_is_registered_console = 0;
+	}
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/sys_alcor.c linux-2.4.21-pre6/arch/alpha/kernel/sys_alcor.c
--- linux-2.4.20/arch/alpha/kernel/sys_alcor.c	2001-06-27 23:18:13.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/kernel/sys_alcor.c	2003-03-26 23:49:34.000000000 +0000
@@ -220,6 +220,8 @@
 static void
 alcor_kill_arch(int mode)
 {
+	cia_kill_arch(mode);
+
 	switch(mode) {
 	case LINUX_REBOOT_CMD_RESTART:
 		/* Who said DEC engineer's have no sense of humor? ;-)  */
@@ -250,7 +252,7 @@
 	DO_CIA_IO,
 	DO_CIA_BUS,
 	machine_check:		cia_machine_check,
-	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
+	max_dma_address:	ALPHA_ALCOR_MAX_DMA_ADDRESS,
 	min_io_address:		EISA_DEFAULT_IO_BASE,
 	min_mem_address:	CIA_DEFAULT_MEM_BASE,
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/sys_cabriolet.c linux-2.4.21-pre6/arch/alpha/kernel/sys_cabriolet.c
--- linux-2.4.20/arch/alpha/kernel/sys_cabriolet.c	2001-10-12 22:35:53.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/kernel/sys_cabriolet.c	2003-03-26 23:49:20.000000000 +0000
@@ -365,6 +365,7 @@
 	init_irq:		cabriolet_init_irq,
 	init_rtc:		common_init_rtc,
 	init_pci:		cia_cab_init_pci,
+	kill_arch:		cia_kill_arch,
 	pci_map_irq:		cabriolet_map_irq,
 	pci_swizzle:		common_swizzle,
 };
@@ -416,6 +417,7 @@
 	init_irq:		cabriolet_init_irq,
 	init_rtc:		common_init_rtc,
 	init_pci:		alphapc164_init_pci,
+	kill_arch:		cia_kill_arch,
 	pci_map_irq:		alphapc164_map_irq,
 	pci_swizzle:		common_swizzle,
 };
@@ -441,6 +443,7 @@
 	init_irq:		pc164_init_irq,
 	init_rtc:		common_init_rtc,
 	init_pci:		alphapc164_init_pci,
+	kill_arch:		cia_kill_arch,
 	pci_map_irq:		alphapc164_map_irq,
 	pci_swizzle:		common_swizzle,
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/sys_marvel.c linux-2.4.21-pre6/arch/alpha/kernel/sys_marvel.c
--- linux-2.4.20/arch/alpha/kernel/sys_marvel.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/kernel/sys_marvel.c	2003-03-26 23:49:26.000000000 +0000
@@ -0,0 +1,499 @@
+/*
+ * linux/arch/alpha/kernel/sys_marvel.c
+ *
+ * Marvel / IO7 support
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+
+#include <asm/ptrace.h>
+#include <asm/system.h>
+#include <asm/dma.h>
+#include <asm/irq.h>
+#include <asm/bitops.h>
+#include <asm/mmu_context.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/core_marvel.h>
+#include <asm/hwrpb.h>
+
+#include "proto.h"
+#include "err_impl.h"
+#include "irq_impl.h"
+#include "pci_impl.h"
+#include "machvec_impl.h"
+
+#if NR_IRQS < MARVEL_NR_IRQS
+# error NR_IRQS < MARVEL_NR_IRQS !!!
+#endif
+
+
+/*
+ * Interrupt handling.
+ */
+static void 
+io7_device_interrupt(unsigned long vector, struct pt_regs * regs)
+{
+	unsigned int pid;
+	unsigned int irq;
+
+	/*
+	 * Vector is 0x800 + (interrupt)
+	 *
+	 * where (interrupt) is:
+	 *
+	 *	...16|15 14|13     4|3 0
+	 *	-----+-----+--------+---
+	 *	  PE |  0  |   irq  | 0
+	 *
+	 * where (irq) is 
+	 *
+	 *       0x0800 - 0x0ff0	 - 0x0800 + (LSI id << 4)
+	 *	 0x1000 - 0x2ff0	 - 0x1000 + (MSI_DAT<8:0> << 4)
+	 */
+	pid = vector >> 16;
+	irq = ((vector & 0xffff) - 0x800) >> 4;
+
+	irq += 16;				/* offset for legacy */
+	irq &= MARVEL_IRQ_VEC_IRQ_MASK;		/* not too many bits */
+	irq |= pid << MARVEL_IRQ_VEC_PE_SHIFT;	/* merge the pid     */
+
+	handle_irq(irq, regs);
+}
+
+static volatile unsigned long *
+io7_get_irq_ctl(unsigned int irq, struct io7 **pio7)
+{
+	volatile unsigned long *ctl;
+	unsigned int pid;
+	struct io7 *io7;
+
+	pid = irq >> MARVEL_IRQ_VEC_PE_SHIFT;
+
+	if (!(io7 = marvel_find_io7(pid))) {
+		printk(KERN_ERR 
+		       "%s for nonexistent io7 -- vec %x, pid %d\n",
+		       __FUNCTION__, irq, pid);
+		return NULL;
+	}
+
+	irq &= MARVEL_IRQ_VEC_IRQ_MASK;	/* isolate the vector    */
+	irq -= 16;			/* subtract legacy bias  */
+
+	if (irq >= 0x180) {
+		printk(KERN_ERR 
+		       "%s for invalid irq -- pid %d adjusted irq %x\n",
+		       __FUNCTION__, pid, irq);
+		return NULL;
+	}
+
+	ctl = &io7->csrs->PO7_LSI_CTL[irq & 0xff].csr; /* assume LSI */
+	if (irq >= 0x80)	     	/* MSI */
+		ctl = &io7->csrs->PO7_MSI_CTL[((irq - 0x80) >> 5) & 0x0f].csr;
+
+	if (pio7) *pio7 = io7;
+	return ctl;
+}
+
+static void
+io7_enable_irq(unsigned int irq)
+{
+	volatile unsigned long *ctl;
+	struct io7 *io7;
+
+	ctl = io7_get_irq_ctl(irq, &io7);
+	if (!ctl || !io7) {
+		printk(KERN_ERR "%s: get_ctl failed for irq %x\n", 
+		       __FUNCTION__, irq);
+		return;
+	}
+		
+	spin_lock(&io7->irq_lock);
+	*ctl |= 1UL << 24;
+	mb();
+	*ctl;
+	spin_unlock(&io7->irq_lock);
+}
+
+static void
+io7_disable_irq(unsigned int irq)
+{
+	volatile unsigned long *ctl;
+	struct io7 *io7;
+
+	ctl = io7_get_irq_ctl(irq, &io7);
+	if (!ctl || !io7) {
+		printk(KERN_ERR "%s: get_ctl failed for irq %x\n", 
+		       __FUNCTION__, irq);
+		return;
+	}
+		
+	spin_lock(&io7->irq_lock);
+	*ctl &= ~(1UL << 24);
+	mb();
+	*ctl;
+	spin_unlock(&io7->irq_lock);
+}
+
+static unsigned int
+io7_startup_irq(unsigned int irq)
+{
+	io7_enable_irq(irq);
+	return 0;	/* never anything pending */
+}
+
+static void
+io7_end_irq(unsigned int irq)
+{
+	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+		io7_enable_irq(irq);
+}
+
+static void
+marvel_irq_noop(unsigned int irq) 
+{ 
+	return; 
+}
+
+static unsigned int
+marvel_irq_noop_return(unsigned int irq) 
+{ 
+	return 0; 
+}
+
+static struct hw_interrupt_type marvel_legacy_irq_type = {
+	typename:	"LEGACY",
+	startup:	marvel_irq_noop_return,
+	shutdown:	marvel_irq_noop,
+	enable:		marvel_irq_noop,
+	disable:	marvel_irq_noop,
+	ack:		marvel_irq_noop,
+	end:		marvel_irq_noop,
+};
+
+static struct hw_interrupt_type io7_lsi_irq_type = {
+	typename:	"LSI",
+	startup:	io7_startup_irq,
+	shutdown:	io7_disable_irq,
+	enable:		io7_enable_irq,
+	disable:	io7_disable_irq,
+	ack:		io7_disable_irq,
+	end:		io7_end_irq,
+};
+
+static struct hw_interrupt_type io7_msi_irq_type = {
+	typename:	"MSI",
+	startup:	io7_startup_irq,
+	shutdown:	io7_disable_irq,
+	enable:		io7_enable_irq,
+	disable:	io7_disable_irq,
+	ack:		marvel_irq_noop,
+	end:		io7_end_irq,
+};
+
+static void
+io7_redirect_irq(struct io7 *io7, 
+		 volatile unsigned long *csr, 
+		 unsigned int where)
+{
+	unsigned long val;
+	
+	val = *csr;
+	val &= ~(0x1ffUL << 24);		/* clear the target pid   */
+	val |= ((unsigned long)where << 24);	/* set the new target pid */
+	
+	*csr = val;
+	mb();
+	*csr;
+}
+
+static void 
+io7_redirect_one_lsi(struct io7 *io7, unsigned int which, unsigned int where)
+{
+	unsigned long val;
+
+	/*
+	 * LSI_CTL has target PID @ 14
+	 */
+	val = io7->csrs->PO7_LSI_CTL[which].csr;
+	val &= ~(0x1ffUL << 14);		/* clear the target pid */
+	val |= ((unsigned long)where << 14);	/* set teh new target pid */
+
+	io7->csrs->PO7_LSI_CTL[which].csr = val;
+	mb();
+	io7->csrs->PO7_LSI_CTL[which].csr;
+}
+
+static void 
+io7_redirect_one_msi(struct io7 *io7, unsigned int which, unsigned int where)
+{
+	unsigned long val;
+
+	/*
+	 * MSI_CTL has target PID @ 14
+	 */
+	val = io7->csrs->PO7_MSI_CTL[which].csr;
+	val &= ~(0x1ffUL << 14);		/* clear the target pid */
+	val |= ((unsigned long)where << 14);	/* set teh new target pid */
+
+	io7->csrs->PO7_MSI_CTL[which].csr = val;
+	mb();
+	io7->csrs->PO7_MSI_CTL[which].csr;
+}
+
+static void __init
+init_one_io7_lsi(struct io7 *io7, unsigned int which, unsigned int where)
+{
+	/*
+	 * LSI_CTL has target PID @ 14
+	 */
+	io7->csrs->PO7_LSI_CTL[which].csr = ((unsigned long)where << 14);
+	mb();
+	io7->csrs->PO7_LSI_CTL[which].csr;
+}
+
+static void __init
+init_one_io7_msi(struct io7 *io7, unsigned int which, unsigned int where)
+{
+	/*
+	 * MSI_CTL has target PID @ 14
+	 */
+	io7->csrs->PO7_MSI_CTL[which].csr = ((unsigned long)where << 14);
+	mb();
+	io7->csrs->PO7_MSI_CTL[which].csr;
+}
+
+static void __init
+init_io7_irqs(struct io7 *io7, 
+	      struct hw_interrupt_type *lsi_ops,
+	      struct hw_interrupt_type *msi_ops)
+{
+	long base = (io7->pe << MARVEL_IRQ_VEC_PE_SHIFT) + 16;
+	long i;
+
+	printk("Initializing interrupts for IO7 at PE %u - base %lx\n",
+		io7->pe, base);
+
+	/*
+	 * Where should interrupts from this IO7 go?
+	 *
+	 * They really should be sent to the local CPU to avoid having to
+	 * traverse the mesh, but if it's not an SMP kernel, they have to
+	 * go to the boot CPU. Send them all to the boot CPU for now,
+	 * as each secondary starts, it can redirect it's local device
+	 * interrupts.
+	 */
+	printk("  Interrupts reported to CPU at PE %u\n", boot_cpuid);
+
+	spin_lock(&io7->irq_lock);
+
+	/* set up the error irqs */
+	io7_redirect_irq(io7, &io7->csrs->HLT_CTL.csr, boot_cpuid);
+	io7_redirect_irq(io7, &io7->csrs->HPI_CTL.csr, boot_cpuid);
+	io7_redirect_irq(io7, &io7->csrs->CRD_CTL.csr, boot_cpuid);
+	io7_redirect_irq(io7, &io7->csrs->STV_CTL.csr, boot_cpuid);
+	io7_redirect_irq(io7, &io7->csrs->HEI_CTL.csr, boot_cpuid);
+
+	/* Set up the lsi irqs.  */
+	for (i = 0; i < 128; ++i) {
+		irq_desc[base + i].status = IRQ_DISABLED | IRQ_LEVEL;
+		irq_desc[base + i].handler = lsi_ops;
+	}
+
+	/* Disable the implemented irqs in hardware.  */
+	for (i = 0; i < 0x60; ++i) 
+		init_one_io7_lsi(io7, i, boot_cpuid);
+
+	init_one_io7_lsi(io7, 0x74, boot_cpuid);
+	init_one_io7_lsi(io7, 0x75, boot_cpuid);
+
+
+	/* Set up the msi irqs.  */
+	for (i = 128; i < (128 + 512); ++i) {
+		irq_desc[base + i].status = IRQ_DISABLED | IRQ_LEVEL;
+		irq_desc[base + i].handler = msi_ops;
+	}
+
+	for (i = 0; i < 16; ++i)
+		init_one_io7_msi(io7, i, boot_cpuid);
+
+	spin_unlock(&io7->irq_lock);
+}
+
+static void __init
+marvel_init_irq(void)
+{
+	int i;
+	struct io7 *io7 = NULL;
+
+	/* Reserve the legacy irqs.  */
+	for (i = 0; i < 16; ++i) {
+		irq_desc[i].status = IRQ_DISABLED;
+		irq_desc[i].handler = &marvel_legacy_irq_type;
+	}
+
+	/* Init the io7 irqs.  */
+	for (io7 = NULL; (io7 = marvel_next_io7(io7)) != NULL; )
+		init_io7_irqs(io7, &io7_lsi_irq_type, &io7_msi_irq_type);
+}
+
+static int 
+marvel_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+	struct pci_controller *hose = dev->sysdata;
+	struct io7_port *io7_port = hose->sysdata;
+	struct io7 *io7 = io7_port->io7;
+	int msi_loc, msi_data_off;
+	u16 msg_ctl;
+	u16 msg_dat;
+	u8 intline; 
+	int irq;
+
+	pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &intline);
+	irq = intline;
+
+	msi_loc = pci_find_capability(dev, PCI_CAP_ID_MSI);
+	msg_ctl = 0;
+	if (msi_loc) 
+		pci_read_config_word(dev, msi_loc + PCI_MSI_FLAGS, &msg_ctl);
+
+	if (msg_ctl & PCI_MSI_FLAGS_ENABLE) {
+ 		msi_data_off = PCI_MSI_DATA_32;
+		if (msg_ctl & PCI_MSI_FLAGS_64BIT) 
+			msi_data_off = PCI_MSI_DATA_64;
+		pci_read_config_word(dev, msi_loc + msi_data_off, &msg_dat);
+
+		irq = msg_dat & 0x1ff;		/* we use msg_data<8:0> */
+		irq += 0x80;			/* offset for lsi       */
+
+#if 1
+		printk("PCI:%d:%d:%d (hose %d) [%s] is using MSI\n",
+		       dev->bus->number, 
+		       PCI_SLOT(dev->devfn), 
+		       PCI_FUNC(dev->devfn),
+		       hose->index,
+		       dev->name);
+		printk("  %d message(s) from 0x%04x\n", 
+		       1 << ((msg_ctl & PCI_MSI_FLAGS_QSIZE) >> 4),
+		       msg_dat);
+		printk("  reporting on %d IRQ(s) from %d (0x%x)\n", 
+		       1 << ((msg_ctl & PCI_MSI_FLAGS_QSIZE) >> 4),
+		       (irq + 16) | (io7->pe << MARVEL_IRQ_VEC_PE_SHIFT),
+		       (irq + 16) | (io7->pe << MARVEL_IRQ_VEC_PE_SHIFT));
+#endif
+
+#if 0
+		pci_write_config_word(dev, msi_loc + PCI_MSI_FLAGS,
+				      msg_ctl & ~PCI_MSI_FLAGS_ENABLE);
+		pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &intline);
+		irq = intline;
+
+		printk("  forcing LSI interrupt on irq %d [0x%x]\n", irq, irq);
+#endif
+	}
+
+	irq += 16;					/* offset for legacy */
+	irq |= io7->pe << MARVEL_IRQ_VEC_PE_SHIFT;	/* merge the pid     */
+
+	return irq; 
+}
+
+static void __init
+marvel_init_pci(void)
+{
+	struct io7 *io7;
+
+	marvel_register_error_handlers();
+
+	pci_probe_only = 1;
+	common_init_pci();
+
+#ifdef CONFIG_VGA_HOSE
+	locate_and_init_vga(NULL);
+#endif
+
+	/* Clear any io7 errors.  */
+	for (io7 = NULL; (io7 = marvel_next_io7(io7)) != NULL; ) 
+		io7_clear_errors(io7);
+}
+
+static void
+marvel_init_rtc(void)
+{
+	init_rtc_irq();
+}
+
+static void
+marvel_smp_callin(void)
+{
+	int cpuid = hard_smp_processor_id();
+	struct io7 *io7 = marvel_find_io7(cpuid);
+	unsigned int i;
+
+	if (!io7)
+		return;
+
+	/* 
+	 * There is a local IO7 - redirect all of it's interrupts here.
+	 */
+	printk("Redirecting IO7 interrupts to local CPU at PE %u\n", cpuid);
+
+	/* Redirect the error IRQS here.  */
+	io7_redirect_irq(io7, &io7->csrs->HLT_CTL.csr, cpuid);
+	io7_redirect_irq(io7, &io7->csrs->HPI_CTL.csr, cpuid);
+	io7_redirect_irq(io7, &io7->csrs->CRD_CTL.csr, cpuid);
+	io7_redirect_irq(io7, &io7->csrs->STV_CTL.csr, cpuid);
+	io7_redirect_irq(io7, &io7->csrs->HEI_CTL.csr, cpuid);
+
+	/* Redirect the implemented LSIs here.  */
+	for (i = 0; i < 0x60; ++i) 
+		io7_redirect_one_lsi(io7, i, cpuid);
+
+	io7_redirect_one_lsi(io7, 0x74, cpuid);
+	io7_redirect_one_lsi(io7, 0x75, cpuid);
+
+	/* Redirect the MSIs here.  */
+	for (i = 0; i < 16; ++i)
+		io7_redirect_one_msi(io7, i, cpuid);
+}
+
+/*
+ * System Vectors
+ */
+struct alpha_machine_vector marvel_ev7_mv __initmv = {
+	vector_name:		"MARVEL/EV7",
+	DO_EV7_MMU,
+	DO_DEFAULT_RTC,
+	DO_MARVEL_IO,
+	DO_MARVEL_BUS,
+	machine_check:		marvel_machine_check,
+	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
+	min_io_address:		DEFAULT_IO_BASE,
+	min_mem_address:	DEFAULT_MEM_BASE,
+	pci_dac_offset:		IO7_DAC_OFFSET,
+
+	nr_irqs:		MARVEL_NR_IRQS,
+	device_interrupt:	io7_device_interrupt,
+
+	agp_info:		marvel_agp_info,
+
+	smp_callin:		marvel_smp_callin,
+	init_arch:		marvel_init_arch,
+	init_irq:		marvel_init_irq,
+	init_rtc:		marvel_init_rtc,
+	init_pci:		marvel_init_pci,
+	kill_arch:		marvel_kill_arch,
+	pci_map_irq:		marvel_map_irq,
+	pci_swizzle:		common_swizzle,
+
+	pa_to_nid:		marvel_pa_to_nid,
+	cpuid_to_nid:		marvel_cpuid_to_nid,
+	node_mem_start:		marvel_node_mem_start,
+	node_mem_size:		marvel_node_mem_size,
+};
+ALIAS_MV(marvel_ev7)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/sys_miata.c linux-2.4.21-pre6/arch/alpha/kernel/sys_miata.c
--- linux-2.4.20/arch/alpha/kernel/sys_miata.c	2002-02-25 19:37:52.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/kernel/sys_miata.c	2003-03-26 23:49:39.000000000 +0000
@@ -245,6 +245,8 @@
 static void
 miata_kill_arch(int mode)
 {
+	cia_kill_arch(mode);
+
 	switch(mode) {
 	case LINUX_REBOOT_CMD_RESTART:
 		/* Who said DEC engineers have no sense of humor? ;-)  */ 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/sys_mikasa.c linux-2.4.21-pre6/arch/alpha/kernel/sys_mikasa.c
--- linux-2.4.20/arch/alpha/kernel/sys_mikasa.c	2000-10-27 17:55:01.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/kernel/sys_mikasa.c	2003-03-26 23:49:51.000000000 +0000
@@ -259,6 +259,7 @@
 	init_irq:		mikasa_init_irq,
 	init_rtc:		common_init_rtc,
 	init_pci:		cia_init_pci,
+	kill_arch:		cia_kill_arch,
 	pci_map_irq:		mikasa_map_irq,
 	pci_swizzle:		common_swizzle,
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/sys_nautilus.c linux-2.4.21-pre6/arch/alpha/kernel/sys_nautilus.c
--- linux-2.4.20/arch/alpha/kernel/sys_nautilus.c	2001-05-21 20:40:39.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/kernel/sys_nautilus.c	2003-03-26 23:49:29.000000000 +0000
@@ -31,6 +31,7 @@
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/reboot.h>
+#include <linux/bootmem.h>
 
 #include <asm/ptrace.h>
 #include <asm/system.h>
@@ -45,6 +46,7 @@
 #include <asm/hwrpb.h>
 
 #include "proto.h"
+#include "err_impl.h"
 #include "irq_impl.h"
 #include "pci_impl.h"
 #include "machvec_impl.h"
@@ -99,324 +101,12 @@
 	}
 }
 
-/* Machine check handler code
- *
- * Perform analysis of a machine check that was triggered by the EV6
- * CPU's fault-detection mechanism.
- */
-
-/* IPR structures for EV6, containing the necessary data for the
- * machine check handler to unpick the logout frame
- */
-
-/* I_STAT */
-
-#define EV6__I_STAT__PAR                ( 1 << 29 )
-
-/* MM_STAT */
-
-#define EV6__MM_STAT__DC_TAG_PERR       ( 1 << 10 )
-
-/* DC_STAT */
-
-#define EV6__DC_STAT__SEO               ( 1 << 4 )
-#define EV6__DC_STAT__ECC_ERR_LD        ( 1 << 3 )
-#define EV6__DC_STAT__ECC_ERR_ST        ( 1 << 2 )
-#define EV6__DC_STAT__TPERR_P1          ( 1 << 1 )
-#define EV6__DC_STAT__TPERR_P0          ( 1      )
-
-/* C_STAT */
-
-#define EV6__C_STAT__BC_PERR            ( 0x01 )
-#define EV6__C_STAT__DC_PERR            ( 0x02 )
-#define EV6__C_STAT__DSTREAM_MEM_ERR    ( 0x03 )
-#define EV6__C_STAT__DSTREAM_BC_ERR     ( 0x04 )
-#define EV6__C_STAT__DSTREAM_DC_ERR     ( 0x05 )
-#define EV6__C_STAT__PROBE_BC_ERR0      ( 0x06 )
-#define EV6__C_STAT__PROBE_BC_ERR1      ( 0x07 )
-#define EV6__C_STAT__ISTREAM_MEM_ERR    ( 0x0B )
-#define EV6__C_STAT__ISTREAM_BC_ERR     ( 0x0C )
-#define EV6__C_STAT__DSTREAM_MEM_DBL    ( 0x13 )
-#define EV6__C_STAT__DSTREAM_BC_DBL     ( 0x14 )
-#define EV6__C_STAT__ISTREAM_MEM_DBL    ( 0x1B )
-#define EV6__C_STAT__ISTREAM_BC_DBL     ( 0x1C )
-
-
-/* Take the two syndromes from the CBOX error chain and convert them
- * into a bit number.  */
-
-/* NOTE - since I don't know of any difference between C0 and C1 I
-   just ignore C1, since in all cases I've seen so far they are
-   identical.  */
-
-static const unsigned char ev6_bit_to_syndrome[72] =
-{
-	0xce, 0xcb, 0xd3, 0xd5, 0xd6, 0xd9, 0xda, 0xdc,     /* 0 */
-	0x23, 0x25, 0x26, 0x29, 0x2a, 0x2c, 0x31, 0x34,     /* 8 */
-	0x0e, 0x0b, 0x13, 0x15, 0x16, 0x19, 0x1a, 0x1c,     /* 16 */
-	0xe3, 0xe5, 0xe6, 0xe9, 0xea, 0xec, 0xf1, 0xf4,     /* 24 */
-	0x4f, 0x4a, 0x52, 0x54, 0x57, 0x58, 0x5b, 0x5d,     /* 32 */
-	0xa2, 0xa4, 0xa7, 0xa8, 0xab, 0xad, 0xb0, 0xb5,     /* 40 */
-	0x8f, 0x8a, 0x92, 0x94, 0x97, 0x98, 0x9b, 0x9d,     /* 48 */
-	0x62, 0x64, 0x67, 0x68, 0x6b, 0x6d, 0x70, 0x75,     /* 56 */
-	0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80      /* 64 */
-};
-
-
-static int ev6_syn2bit(unsigned long c0, unsigned long c1)
-{
-	int bit;
-
-	for (bit = 0; bit < 72; bit++)
-		if (ev6_bit_to_syndrome[bit] == c0)	return bit;
-	for (bit = 0; bit < 72; bit++)
-		if (ev6_bit_to_syndrome[bit] == c1)	return bit + 64;
-
-	return -1;                  /* not found */
-}
-
-
-/* Single bit ECC errors are categorized here.  */
-
-#if 0
-static const char *interr = "CPU internal error";
-static const char *slotb= "Slot-B error";
-static const char *membus= "Memory/EV6-bus error";
-#else
-static const char *interr = "";
-static const char *slotb = "";
-static const char *membus = "";
-#endif
-
-static void
-ev6_crd_interp(char *interp, struct el_common_EV6_mcheck * L)
-{
-	/* Icache data or tag parity error.  */
-	if (L->I_STAT & EV6__I_STAT__PAR) {
-		sprintf(interp, "%s: I_STAT[PAR]\n "
-			"Icache data or tag parity error", interr);
-		return;
-	}
-
-	/* Dcache tag parity error (on issue) (DFAULT).  */
-	if (L->MM_STAT & EV6__MM_STAT__DC_TAG_PERR) {
-		sprintf(interp, "%s: MM_STAT[DC_TAG_PERR]\n "
-			"Dcache tag parity error(on issue)", interr);
-		return;
-	}
-
-	/* Errors relating to D-stream set non-zero DC_STAT.
-	   Mask CRD bits.  */
-	switch (L->DC_STAT & (EV6__DC_STAT__ECC_ERR_ST
-			      | EV6__DC_STAT__ECC_ERR_LD)) {
-	case EV6__DC_STAT__ECC_ERR_ST:
-		/* Dcache single-bit ECC error on small store */
-		sprintf(interp, "%s: DC_STAT[ECC_ERR_ST]\n "
-			"Dcache single-bit ECC error on small store", interr);
-		return;
-
-	case EV6__DC_STAT__ECC_ERR_LD:
-		switch (L->C_STAT) {
-		case 0:
-			/* Dcache single-bit error on speculative load */
-			/* Bcache victim read on Dcache/Bcache miss */
-			sprintf(interp, "%s: DC_STAT[ECC_ERR_LD] C_STAT=0\n "
-				"Dcache single-bit ECC error on speculative load",
-				slotb);
-			return;
-
-		case EV6__C_STAT__DSTREAM_DC_ERR:
-			/* Dcache single bit error on load */
-			sprintf(interp, "%s: DC_STAT[ECC_ERR_LD] C_STAT[DSTREAM_DC_ERR]\n"
-				" Dcache single-bit ECC error on speculative load, bit %d",
-				interr, ev6_syn2bit(L->DC0_SYNDROME, L->DC1_SYNDROME));
-			return;
-
-		case EV6__C_STAT__DSTREAM_BC_ERR:
-			/* Bcache single-bit error on Dcache fill */
-			sprintf(interp, "%s: DC_STAT[ECC_ERR_LD] C_STAT[DSTREAM_BC_ERR]\n"
-				" Bcache single-bit error on Dcache fill, bit %d",
-				slotb, ev6_syn2bit(L->DC0_SYNDROME, L->DC1_SYNDROME));
-			return;
-
-		case EV6__C_STAT__DSTREAM_MEM_ERR:
-			/* Memory single-bit error on Dcache fill */
-			sprintf(interp, "%s (to Dcache): DC_STAT[ECC_ERR_LD] "
-				"C_STAT[DSTREAM_MEM_ERR]\n "
-				"Memory single-bit error on Dcache fill, "
-				"Address 0x%lX, bit %d",
-				membus, L->C_ADDR, ev6_syn2bit(L->DC0_SYNDROME,
-							       L->DC1_SYNDROME));
-			return;
-		}
-	}
-
-	/* I-stream, other misc errors go on C_STAT alone */
-	switch (L->C_STAT) {
-	case EV6__C_STAT__ISTREAM_BC_ERR:
-		/* Bcache single-bit error on Icache fill (also MCHK) */
-		sprintf(interp, "%s: C_STAT[ISTREAM_BC_ERR]\n "
-			"Bcache single-bit error on Icache fill, bit %d",
-			slotb, ev6_syn2bit(L->DC0_SYNDROME, L->DC1_SYNDROME));
-		return;
-
-	case EV6__C_STAT__ISTREAM_MEM_ERR:
-		/* Memory single-bit error on Icache fill (also MCHK) */
-		sprintf(interp, "%s : C_STATISTREAM_MEM_ERR]\n "
-			"Memory single-bit error on Icache fill "
-			"addr 0x%lX, bit %d",
-			membus, L->C_ADDR, ev6_syn2bit(L->DC0_SYNDROME,
-						       L->DC1_SYNDROME));
-		return;
-
-	case EV6__C_STAT__PROBE_BC_ERR0:
-	case EV6__C_STAT__PROBE_BC_ERR1:
-		/* Bcache single-bit error on a probe hit */
-		sprintf(interp, "%s: C_STAT[PROBE_BC_ERR]\n "
-			"Bcache single-bit error on a probe hit, "
-			"addr 0x%lx, bit %d",
-			slotb, L->C_ADDR, ev6_syn2bit(L->DC0_SYNDROME,
-						      L->DC1_SYNDROME));
-		return;
-	}
-}
-
-static void
-ev6_mchk_interp(char *interp, struct el_common_EV6_mcheck * L)
-{
-	/* Machine check errors described by DC_STAT */
-	switch (L->DC_STAT) {
-	case EV6__DC_STAT__TPERR_P0:
-	case EV6__DC_STAT__TPERR_P1:
-		/* Dcache tag parity error (on retry) */
-		sprintf(interp, "%s: DC_STAT[TPERR_P0|TPERR_P1]\n "
-			"Dcache tag parity error(on retry)", interr);
-		return;
-
-	case EV6__DC_STAT__SEO:
-		/* Dcache second error on store */
-		sprintf(interp, "%s: DC_STAT[SEO]\n "
-			"Dcache second error during mcheck", interr);
-		return;
-	}
-
-	/* Machine check errors described by C_STAT */
-	switch (L->C_STAT) {
-	case EV6__C_STAT__DC_PERR:
-		/* Dcache duplicate tag parity error */
-		sprintf(interp, "%s: C_STAT[DC_PERR]\n "
-			"Dcache duplicate tag parity error at 0x%lX",
-			interr, L->C_ADDR);
-		return;
-
-	case EV6__C_STAT__BC_PERR:
-		/* Bcache tag parity error */
-		sprintf(interp, "%s: C_STAT[BC_PERR]\n "
-			"Bcache tag parity error at 0x%lX",
-			slotb, L->C_ADDR);
-		return;
-
-	case EV6__C_STAT__ISTREAM_BC_ERR:
-		/* Bcache single-bit error on Icache fill (also CRD) */
-		sprintf(interp, "%s: C_STAT[ISTREAM_BC_ERR]\n "
-			"Bcache single-bit error on Icache fill 0x%lX bit %d",
-			slotb, L->C_ADDR,
-			ev6_syn2bit(L->DC0_SYNDROME, L->DC1_SYNDROME));
-		return;
-
-
-	case EV6__C_STAT__ISTREAM_MEM_ERR:
-		/* Memory single-bit error on Icache fill (also CRD) */
-		sprintf(interp, "%s: C_STAT[ISTREAM_MEM_ERR]\n "
-			"Memory single-bit error on Icache fill 0x%lX, bit %d",
-			membus, L->C_ADDR,
-			ev6_syn2bit(L->DC0_SYNDROME, L->DC1_SYNDROME));
-		return;
-
-
-	case EV6__C_STAT__ISTREAM_BC_DBL:
-		/* Bcache double-bit error on Icache fill */
-		sprintf(interp, "%s: C_STAT[ISTREAM_BC_DBL]\n "
-			"Bcache double-bit error on Icache fill at 0x%lX",
-			slotb, L->C_ADDR);
-		return;
-	case EV6__C_STAT__DSTREAM_BC_DBL:
-		/* Bcache double-bit error on Dcache fill */
-		sprintf(interp, "%s: C_STAT[DSTREAM_BC_DBL]\n "
-			"Bcache double-bit error on Dcache fill at 0x%lX",
-			slotb, L->C_ADDR);
-		return;
-
-	case EV6__C_STAT__ISTREAM_MEM_DBL:
-		/* Memory double-bit error on Icache fill */
-		sprintf(interp, "%s: C_STAT[ISTREAM_MEM_DBL]\n "
-			"Memory double-bit error on Icache fill at 0x%lX",
-			membus, L->C_ADDR);
-		return;
-
-	case EV6__C_STAT__DSTREAM_MEM_DBL:
-		/* Memory double-bit error on Dcache fill */
-		sprintf(interp, "%s: C_STAT[DSTREAM_MEM_DBL]\n "
-			"Memory double-bit error on Dcache fill at 0x%lX",
-			membus, L->C_ADDR);
-		return;
-	}
-}
-
-static void
-ev6_cpu_machine_check(unsigned long vector, struct el_common_EV6_mcheck *L,
-		      struct pt_regs *regs)
-{
-	char interp[80];
-
-	/* This is verbose and looks intimidating.  Should it be printed for
-	   corrected (CRD) machine checks? */
-
-	printk(KERN_CRIT "PALcode logout frame:  "
-	       "MCHK_Code       %d  "
-	       "MCHK_Frame_Rev  %d\n"
-	       "I_STAT  %016lx  "
-	       "DC_STAT %016lx  "
-	       "C_ADDR  %016lx\n"
-	       "SYND1   %016lx  "
-	       "SYND0   %016lx  "
-	       "C_STAT  %016lx\n"
-	       "C_STS   %016lx  "
-	       "RES     %016lx  "
-	       "EXC_ADDR%016lx\n"
-	       "IER_CM  %016lx  "
-	       "ISUM    %016lx  "
-	       "MM_STAT %016lx\n"
-	       "PALBASE %016lx  "
-	       "I_CTL   %016lx  "
-	       "PCTX    %016lx\n"
-	       "CPU registers: "
-	       "PC      %016lx  "
-	       "Return  %016lx\n",
-	       L->MCHK_Code, L->MCHK_Frame_Rev, L->I_STAT, L->DC_STAT,
-	       L->C_ADDR, L->DC1_SYNDROME, L->DC0_SYNDROME, L->C_STAT,
-	       L->C_STS, L->RESERVED0, L->EXC_ADDR, L->IER_CM, L->ISUM,
-	       L->MM_STAT, L->PAL_BASE, L->I_CTL, L->PCTX,
-	       regs->pc, regs->r26);
-
-	/* Attempt an interpretation on the meanings of the fields above.  */
-	sprintf(interp, "No interpretation available!" );
-	if (vector == SCB_Q_PROCERR)
-		ev6_crd_interp(interp, L);
-	else if (vector == SCB_Q_PROCMCHK)
-		ev6_mchk_interp(interp, L);
-
-	printk(KERN_CRIT "interpretation: %s\n\n", interp);
-}
-
-
 /* Perform analysis of a machine check that arrived from the system (NMI) */
 
 static void
 naut_sys_machine_check(unsigned long vector, unsigned long la_ptr,
 		       struct pt_regs *regs)
 {
-	printk("xtime %lx\n", CURRENT_TIME);
 	printk("PC %lx RA %lx\n", regs->pc, regs->r26);
 	irongate_pci_clr_err();
 }
@@ -429,7 +119,6 @@
 		       struct pt_regs *regs)
 {
 	char *mchk_class;
-	unsigned cpu_analysis=0, sys_analysis=0;
 
 	/* Now for some analysis.  Machine checks fall into two classes --
 	   those picked up by the system, and those picked up by the CPU.
@@ -462,39 +151,20 @@
 		return;
 	}
 
-	switch (vector) {
-	case SCB_Q_SYSERR:
-		mchk_class = "Correctable System Machine Check (NMI)";
-		sys_analysis = 1;
-		break;
-	case SCB_Q_SYSMCHK:
-		mchk_class = "Fatal System Machine Check (NMI)";
-		sys_analysis = 1;
-		break;
-
-	case SCB_Q_PROCERR:
-		mchk_class = "Correctable Processor Machine Check";
-		cpu_analysis = 1;
-		break;
-	case SCB_Q_PROCMCHK:
-		mchk_class = "Fatal Processor Machine Check";
-		cpu_analysis = 1;
-		break;
-
-	default:
-		mchk_class = "Unknown vector!";
-		break;
+	if (vector == SCB_Q_SYSERR)
+		mchk_class = "Correctable";
+	else if (vector == SCB_Q_SYSMCHK)
+		mchk_class = "Fatal";
+	else {
+		ev6_machine_check(vector, la_ptr, regs);
+		return;
 	}
 
-	printk(KERN_CRIT "NAUTILUS Machine check 0x%lx [%s]\n",
+	printk(KERN_CRIT "NAUTILUS Machine check 0x%lx "
+			 "[%s System Machine Check (NMI)]\n",
 	       vector, mchk_class);
 
-	if (cpu_analysis)
-		ev6_cpu_machine_check(vector,
-				      (struct el_common_EV6_mcheck *)la_ptr,
-				      regs);
-	if (sys_analysis)
-		naut_sys_machine_check(vector, la_ptr, regs);
+	naut_sys_machine_check(vector, la_ptr, regs);
 
 	/* Tell the PALcode to clear the machine check */
 	draina();
@@ -503,6 +173,76 @@
 }
 
 
+extern void free_reserved_mem(void *, void *);
+extern void pbus_size_bridges(struct pci_bus *);
+extern void pbus_assign_resources(struct pci_bus *);
+
+void __init
+nautilus_init_pci(void)
+{
+	struct pci_controller *hose = hose_head;
+	struct pci_bus *bus;
+	struct pci_dev *irongate, *dev;
+	unsigned long saved_io_start, saved_io_end;
+	unsigned long saved_mem_start, saved_mem_end;
+	unsigned long bus_align, bus_size, pci_mem;
+	unsigned long memtop = max_low_pfn << PAGE_SHIFT;
+
+	/* Scan our single hose.  */
+	bus = pci_scan_bus(0, alpha_mv.pci_ops, hose);
+	hose->bus = bus;
+	hose->last_busno = bus->subordinate;
+
+	/* We're going to size the root bus, so we must
+	   - have a non-NULL PCI device associated with the bus
+	   - preserve hose resources. */
+	irongate = pci_find_slot(0, 0);
+	bus->self = irongate;
+	saved_io_start = bus->resource[0]->start;
+	saved_io_end = bus->resource[0]->end;
+	saved_mem_start = bus->resource[1]->start;
+	saved_mem_end = bus->resource[1]->end;
+
+	pbus_size_bridges(bus);
+
+	/* Don't care about IO. */
+	bus->resource[0]->start = saved_io_start;
+	bus->resource[0]->end = saved_io_end;
+
+	bus_align = bus->resource[1]->start;
+	bus_size = bus->resource[1]->end + 1 - bus_align;
+	/* Align to 16Mb. */
+	if (bus_align < 0x1000000UL)
+		bus_align = 0x1000000UL;
+
+	/* Restore hose MEM resource. */
+	bus->resource[1]->start = saved_mem_start;
+	bus->resource[1]->end = saved_mem_end;
+
+	pci_mem = (0x100000000UL - bus_size) & -bus_align;
+
+	if (pci_mem < memtop && pci_mem > alpha_mv.min_mem_address) {
+		free_reserved_mem(__va(alpha_mv.min_mem_address),
+				  __va(pci_mem));
+		printk("nautilus_init_arch: %ldk freed\n",
+			(pci_mem - alpha_mv.min_mem_address) >> 10);
+	}
+
+	alpha_mv.min_mem_address = pci_mem;
+	if ((IRONGATE0->dev_vendor >> 16) > 0x7006)	/* Albacore? */
+		IRONGATE0->pci_mem = pci_mem;
+
+	pbus_assign_resources(bus);
+
+	pci_for_each_dev(dev) {
+		pdev_enable_device(dev);
+	}
+
+	/* To break the loop in common_swizzle() */
+	bus->self = NULL;
+
+	pci_fixup_irqs(alpha_mv.pci_swizzle, alpha_mv.pci_map_irq);
+}
 
 /*
  * The System Vectors
@@ -525,7 +265,7 @@
 	init_arch:		irongate_init_arch,
 	init_irq:		nautilus_init_irq,
 	init_rtc:		common_init_rtc,
-	init_pci:		common_init_pci,
+	init_pci:		nautilus_init_pci,
 	kill_arch:		nautilus_kill_arch,
 	pci_map_irq:		nautilus_map_irq,
 	pci_swizzle:		common_swizzle,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/sys_ruffian.c linux-2.4.21-pre6/arch/alpha/kernel/sys_ruffian.c
--- linux-2.4.20/arch/alpha/kernel/sys_ruffian.c	2001-10-12 22:35:53.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/kernel/sys_ruffian.c	2003-03-26 23:49:40.000000000 +0000
@@ -84,6 +84,7 @@
 static void
 ruffian_kill_arch (int mode)
 {
+	cia_kill_arch(mode);
 #if 0
 	/* This only causes re-entry to ARCSBIOS */
 	/* Perhaps this works for other PYXIS as well?  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/sys_sable.c linux-2.4.21-pre6/arch/alpha/kernel/sys_sable.c
--- linux-2.4.20/arch/alpha/kernel/sys_sable.c	2001-06-12 18:44:59.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/kernel/sys_sable.c	2003-03-26 23:49:06.000000000 +0000
@@ -289,9 +289,9 @@
 	DO_T2_IO,
 	DO_T2_BUS,
 	machine_check:		t2_machine_check,
-	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
+	max_dma_address:	ALPHA_SABLE_MAX_DMA_ADDRESS,
 	min_io_address:		EISA_DEFAULT_IO_BASE,
-	min_mem_address:	DEFAULT_MEM_BASE,
+	min_mem_address:	T2_DEFAULT_MEM_BASE,
 
 	nr_irqs:		40,
 	device_interrupt:	sable_srm_device_interrupt,
@@ -321,9 +321,9 @@
 	DO_T2_IO,
 	DO_T2_BUS,
 	machine_check:		t2_machine_check,
-	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
+	max_dma_address:	ALPHA_SABLE_MAX_DMA_ADDRESS,
 	min_io_address:		EISA_DEFAULT_IO_BASE,
-	min_mem_address:	DEFAULT_MEM_BASE,
+	min_mem_address:	T2_DEFAULT_MEM_BASE,
 
 	nr_irqs:		40,
 	device_interrupt:	sable_srm_device_interrupt,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/sys_sx164.c linux-2.4.21-pre6/arch/alpha/kernel/sys_sx164.c
--- linux-2.4.20/arch/alpha/kernel/sys_sx164.c	2001-10-12 22:35:53.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/kernel/sys_sx164.c	2003-03-26 23:49:35.000000000 +0000
@@ -171,7 +171,7 @@
 	init_irq:		sx164_init_irq,
 	init_rtc:		common_init_rtc,
 	init_pci:		sx164_init_pci,
-	kill_arch:		NULL,
+	kill_arch:		cia_kill_arch,
 	pci_map_irq:		sx164_map_irq,
 	pci_swizzle:		common_swizzle,
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/sys_titan.c linux-2.4.21-pre6/arch/alpha/kernel/sys_titan.c
--- linux-2.4.20/arch/alpha/kernel/sys_titan.c	2001-10-12 22:35:53.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/kernel/sys_titan.c	2003-03-26 23:49:54.000000000 +0000
@@ -8,6 +8,8 @@
  *
  * Code supporting TITAN systems (EV6+TITAN), currently:
  *      Privateer
+ *	Falcon
+ *	Granite
  */
 
 #include <linux/config.h>
@@ -33,12 +35,26 @@
 #include "irq_impl.h"
 #include "pci_impl.h"
 #include "machvec_impl.h"
+#include "err_impl.h"
 
-/* Note mask bit is true for ENABLED irqs. */
-static unsigned long cached_irq_mask;
-/* Titan boards handle at most four CPUs.  */
-static unsigned long cpu_irq_affinity[4] = { ~0UL, ~0UL, ~0UL, ~0UL };
+
+/*
+ * Titan generic
+ */
+
+/*
+ * Titan supports up to 4 CPUs
+ */
+static unsigned long titan_cpu_irq_affinity[4] = { ~0UL, ~0UL, ~0UL, ~0UL };
 
+/*
+ * Mask is set (1) if enabled
+ */
+static unsigned long titan_cached_irq_mask;
+
+/*
+ * Need SMP-safe access to interrupt CSRs
+ */
 spinlock_t titan_irq_lock = SPIN_LOCK_UNLOCKED;
 
 static void
@@ -54,10 +70,10 @@
 	unsigned long mask0, mask1, mask2, mask3, dummy;
 
 	mask &= ~isa_enable;
-	mask0 = mask & cpu_irq_affinity[0];
-	mask1 = mask & cpu_irq_affinity[1];
-	mask2 = mask & cpu_irq_affinity[2];
-	mask3 = mask & cpu_irq_affinity[3];
+	mask0 = mask & titan_cpu_irq_affinity[0];
+	mask1 = mask & titan_cpu_irq_affinity[1];
+	mask2 = mask & titan_cpu_irq_affinity[2];
+	mask3 = mask & titan_cpu_irq_affinity[3];
 
 	if (bcpu == 0) mask0 |= isa_enable;
 	else if (bcpu == 1) mask1 |= isa_enable;
@@ -84,8 +100,8 @@
 	*dim3;
 #else
 	volatile unsigned long *dimB;
-	if (bcpu == 0) dimB = &cchip->dim0.csr;
-	else if (bcpu == 1) dimB = &cchip->dim1.csr;
+	dimB = &cchip->dim0.csr;
+	if (bcpu == 1) dimB = &cchip->dim1.csr;
 	else if (bcpu == 2) dimB = &cchip->dim2.csr;
 	else if (bcpu == 3) dimB = &cchip->dim3.csr;
 
@@ -96,79 +112,68 @@
 }
 
 static inline void
-privateer_enable_irq(unsigned int irq)
+titan_enable_irq(unsigned int irq)
 {
 	spin_lock(&titan_irq_lock);
-	cached_irq_mask |= 1UL << (irq - 16);
-	titan_update_irq_hw(cached_irq_mask);
+	titan_cached_irq_mask |= 1UL << (irq - 16);
+	titan_update_irq_hw(titan_cached_irq_mask);
 	spin_unlock(&titan_irq_lock);
 }
 
 static inline void
-privateer_disable_irq(unsigned int irq)
+titan_disable_irq(unsigned int irq)
 {
 	spin_lock(&titan_irq_lock);
-	cached_irq_mask &= ~(1UL << (irq - 16));
-	titan_update_irq_hw(cached_irq_mask);
+	titan_cached_irq_mask &= ~(1UL << (irq - 16));
+	titan_update_irq_hw(titan_cached_irq_mask);
 	spin_unlock(&titan_irq_lock);
 }
 
 static unsigned int
-privateer_startup_irq(unsigned int irq)
+titan_startup_irq(unsigned int irq)
 {
-	privateer_enable_irq(irq);
+	titan_enable_irq(irq);
 	return 0;	/* never anything pending */
 }
 
 static void
-privateer_end_irq(unsigned int irq)
+titan_end_irq(unsigned int irq)
 {
 	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
-		privateer_enable_irq(irq);
+		titan_enable_irq(irq);
 }
 
 static void
-cpu_set_irq_affinity(unsigned int irq, unsigned long affinity)
+titan_cpu_set_irq_affinity(unsigned int irq, unsigned long affinity)
 {
 	int cpu;
 
 	for (cpu = 0; cpu < 4; cpu++) {
 		if (affinity & (1UL << cpu))
-			cpu_irq_affinity[cpu] |= 1UL << irq;
+			titan_cpu_irq_affinity[cpu] |= 1UL << irq;
 		else
-			cpu_irq_affinity[cpu] &= ~(1UL << irq);
+			titan_cpu_irq_affinity[cpu] &= ~(1UL << irq);
 	}
 
 }
 
 static void
-privateer_set_affinity(unsigned int irq, unsigned long affinity)
+titan_set_irq_affinity(unsigned int irq, unsigned long affinity)
 { 
 	spin_lock(&titan_irq_lock);
-	cpu_set_irq_affinity(irq - 16, affinity);
-	titan_update_irq_hw(cached_irq_mask);
+	titan_cpu_set_irq_affinity(irq - 16, affinity);
+	titan_update_irq_hw(titan_cached_irq_mask);
 	spin_unlock(&titan_irq_lock);
 }
 
-static struct hw_interrupt_type privateer_irq_type = {
-	typename:	"PRIVATEER",
-	startup:	privateer_startup_irq,
-	shutdown:	privateer_disable_irq,
-	enable:		privateer_enable_irq,
-	disable:	privateer_disable_irq,
-	ack:		privateer_disable_irq,
-	end:		privateer_end_irq,
-	set_affinity:	privateer_set_affinity,
-};
-
 static void
-privateer_device_interrupt(unsigned long vector, struct pt_regs * regs)
+titan_device_interrupt(unsigned long vector, struct pt_regs * regs)
 {
-	printk("privateer_device_interrupt: NOT IMPLEMENTED YET!! \n");
+	printk("titan_device_interrupt: NOT IMPLEMENTED YET!! \n");
 }
 
 static void 
-privateer_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
+titan_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
 {
 	int irq;
 
@@ -181,192 +186,209 @@
 init_titan_irqs(struct hw_interrupt_type * ops, int imin, int imax)
 {
 	long i;
-	for(i = imin; i <= imax; ++i) {
+	for (i = imin; i <= imax; ++i) {
 		irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
 		irq_desc[i].handler = ops;
 	}
 }
 
+static struct hw_interrupt_type titan_irq_type = {
+	typename:	"TITAN",
+	startup:	titan_startup_irq,
+	shutdown:	titan_disable_irq,
+	enable:		titan_enable_irq,
+	disable:	titan_disable_irq,
+	ack:		titan_disable_irq,
+	end:		titan_end_irq,
+	set_affinity:	titan_set_irq_affinity,
+};
+
+static void
+titan_intr_nop(int irq, void *dev_id, struct pt_regs *regs)
+{
+	/*
+	 * This is a NOP interrupt handler for the purposes of
+	 * event counting -- just return.
+	 */
+}
+
 static void __init
-privateer_init_irq(void)
+titan_init_irq(void)
 {
-	extern asmlinkage void entInt(void);
-	int cpu;
+	if (alpha_using_srm && !alpha_mv.device_interrupt)
+		alpha_mv.device_interrupt = titan_srm_device_interrupt;
+	if (!alpha_mv.device_interrupt)
+		alpha_mv.device_interrupt = titan_device_interrupt;
 
+	titan_update_irq_hw(0);
+
+	init_titan_irqs(&titan_irq_type, 16, 63 + 16);
+}
+
+static void __init
+titan_legacy_init_irq(void)
+{
+	/* init the legacy dma controller */
 	outb(0, DMA1_RESET_REG);
 	outb(0, DMA2_RESET_REG);
 	outb(DMA_MODE_CASCADE, DMA2_MODE_REG);
 	outb(0, DMA2_MASK_REG);
 
-	if (alpha_using_srm)
-		alpha_mv.device_interrupt = privateer_srm_device_interrupt;
+	/* init the legacy irq controller */
+	init_i8259a_irqs();
 
-	titan_update_irq_hw(0UL);
+	/* init the titan irqs */
+	titan_init_irq();
+}
 
-	init_i8259a_irqs();
-	init_titan_irqs(&privateer_irq_type, 16, 63 + 16);
+void
+titan_dispatch_irqs(u64 mask, struct pt_regs *regs)
+{
+	unsigned long vector;
+
+	/*
+	 * Mask down to those interrupts which are enable on this processor
+	 */
+	mask &= titan_cpu_irq_affinity[smp_processor_id()];
+
+	/*
+	 * Dispatch all requested interrupts 
+	 */
+	while (mask) {
+		/* convert to SRM vector... priority is <63> -> <0> */
+		__asm__("ctlz %1, %0" : "=r"(vector) : "r"(mask));
+		vector = 63 - vector;
+		mask &= ~(1UL << vector);	/* clear it out 	 */
+		vector = 0x900 + (vector << 4);	/* convert to SRM vector */
+		
+		/* dispatch it */
+		alpha_mv.device_interrupt(vector, regs);
+	}
 }
 
+
 /*
- * Privateer PCI Fixup configuration.
- *
- * PCHIP 0 BUS 0 (Hose 0)
- *
- *     IDSEL	Dev	What
- *     -----	---	----
- *	18	 7	Embedded Southbridge
- *	19	 8	Slot 0 
- *	20	 9	Slot 1
- *	21	10	Slot 2 
- *	22	11	Slot 3
- *	23	12	Embedded HotPlug controller
- *	27	16	Embedded Southbridge IDE
- *	29	18     	Embedded Southbridge PMU
- *	31	20	Embedded Southbridge USB
- *
- * PCHIP 1 BUS 0 (Hose 1)
- *
- *     IDSEL	Dev	What
- *     -----	---	----
- *	12	 1	Slot 0
- * 	13	 2	Slot 1
- *	17	 6	Embedded hotPlug controller
- *
- * PCHIP 0 BUS 1 (Hose 2)
- *
- *     IDSEL	What
- *     -----	----
- *	NONE	AGP
- *
- * PCHIP 1 BUS 1 (Hose 3)
- *
- *     IDSEL	Dev	What
- *     -----	---	----
- *	12	 1	Slot 0
- * 	13	 2	Slot 1
- *	17	 6	Embedded hotPlug controller
- *
- * Summary @ TITAN_CSR_DIM0:
- * Bit      Meaning
- *  0-7     Unused
- *  8       PCHIP 0 BUS 1 YUKON (if present)
- *  9       PCHIP 1 BUS 1 YUKON
- * 10       PCHIP 1 BUS 0 YUKON
- * 11       PCHIP 0 BUS 0 YUKON
- * 12       PCHIP 0 BUS 0 SLOT 2 INT A
- * 13       PCHIP 0 BUS 0 SLOT 2 INT B
- * 14       PCHIP 0 BUS 0 SLOT 2 INT C
- * 15       PCHIP 0 BUS 0 SLOT 2 INT D
- * 16       PCHIP 0 BUS 0 SLOT 3 INT A
- * 17       PCHIP 0 BUS 0 SLOT 3 INT B
- * 18       PCHIP 0 BUS 0 SLOT 3 INT C
- * 19       PCHIP 0 BUS 0 SLOT 3 INT D
- * 20       PCHIP 0 BUS 0 SLOT 0 INT A
- * 21       PCHIP 0 BUS 0 SLOT 0 INT B
- * 22       PCHIP 0 BUS 0 SLOT 0 INT C
- * 23       PCHIP 0 BUS 0 SLOT 0 INT D
- * 24       PCHIP 0 BUS 0 SLOT 1 INT A
- * 25       PCHIP 0 BUS 0 SLOT 1 INT B
- * 26       PCHIP 0 BUS 0 SLOT 1 INT C
- * 27       PCHIP 0 BUS 0 SLOT 1 INT D
- * 28       PCHIP 1 BUS 0 SLOT 0 INT A
- * 29       PCHIP 1 BUS 0 SLOT 0 INT B
- * 30       PCHIP 1 BUS 0 SLOT 0 INT C
- * 31       PCHIP 1 BUS 0 SLOT 0 INT D
- * 32       PCHIP 1 BUS 0 SLOT 1 INT A
- * 33       PCHIP 1 BUS 0 SLOT 1 INT B
- * 34       PCHIP 1 BUS 0 SLOT 1 INT C
- * 35       PCHIP 1 BUS 0 SLOT 1 INT D
- * 36       PCHIP 1 BUS 1 SLOT 0 INT A
- * 37       PCHIP 1 BUS 1 SLOT 0 INT B
- * 38       PCHIP 1 BUS 1 SLOT 0 INT C
- * 39       PCHIP 1 BUS 1 SLOT 0 INT D
- * 40       PCHIP 1 BUS 1 SLOT 1 INT A
- * 41       PCHIP 1 BUS 1 SLOT 1 INT B
- * 42       PCHIP 1 BUS 1 SLOT 1 INT C
- * 43       PCHIP 1 BUS 1 SLOT 1 INT D
- * 44       AGP INT A
- * 45       AGP INT B
- * 46-47    Unused
- * 49       Reserved for Sleep mode
- * 50       Temperature Warning (optional)
- * 51       Power Warning (optional)
- * 52       Reserved
- * 53       South Bridge NMI
- * 54       South Bridge SMI INT
- * 55       South Bridge ISA Interrupt
- * 56-58    Unused
- * 59       PCHIP1_C_ERROR
- * 60       PCHIP0_C_ERROR 
- * 61       PCHIP1_H_ERROR
- * 62       PCHIP0_H_ERROR
- * 63       Reserved
- *
+ * Titan Family
  */
-static int __init
-privateer_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+static void __init
+titan_late_init(void)
 {
-	u8 irq;
-	
-	pcibios_read_config_byte(dev->bus->number,
-				 dev->devfn,
-				 PCI_INTERRUPT_LINE,
-				 &irq);
-
-	/* is it routed through ISA? */
-	if ((irq & 0xF0) == 0xE0)
-		return (int)irq;
+	/*
+	 * Enable the system error interrupts. These interrupts are 
+	 * all reported to the kernel as machine checks, so the handler
+	 * is a nop so it can be called to count the individual events.
+	 */
+	request_irq(63+16, titan_intr_nop, SA_INTERRUPT, 
+		    "CChip Error", NULL);
+	request_irq(62+16, titan_intr_nop, SA_INTERRUPT, 
+		    "PChip 0 H_Error", NULL);
+	request_irq(61+16, titan_intr_nop, SA_INTERRUPT, 
+		    "PChip 1 H_Error", NULL);
+	request_irq(60+16, titan_intr_nop, SA_INTERRUPT, 
+		    "PChip 0 C_Error", NULL);
+	request_irq(59+16, titan_intr_nop, SA_INTERRUPT, 
+		    "PChip 1 C_Error", NULL);
+
+	/* 
+	 * Register our error handlers.
+	 */
+	titan_register_error_handlers();
+
+	/*
+	 * Check if the console left us any error logs.
+	 */
+	cdl_check_console_data_log();
 
-	return (int)irq + 16;	/* HACK -- this better only be called once */
 }
 
-#ifdef CONFIG_VGA_HOSE
-static struct pci_controller * __init
-privateer_vga_hose_select(struct pci_controller *h1, struct pci_controller *h2)
+static int __devinit
+titan_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
 {
-	struct pci_controller *hose = h1;
-	int agp1, agp2;
-
-	/* which hose(s) are agp? */
-	agp1 = (0 != (TITAN_agp & (1 << h1->index)));
-	agp2 = (0 != (TITAN_agp & (1 << h2->index)));
-       
-	hose = h1;			/* default to h1 */
-	if (agp1 ^ agp2) {
-		if (agp2) hose = h2;	/* take agp if only one */
-	} else if (h2->index < h1->index)
-		hose = h2;		/* first hose if 2xpci or 2xagp */
+	u8 intline;
+	int irq;
 
-	return hose;
+ 	/* Get the current intline.  */
+	pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &intline);
+	irq = intline;
+
+ 	/* Is it explicitly routed through ISA?  */
+ 	if ((irq & 0xF0) == 0xE0)
+ 		return irq;
+ 
+ 	/* Offset by 16 to make room for ISA interrupts 0 - 15.  */
+ 	return irq + 16;
 }
-#endif
 
 static void __init
-privateer_init_pci(void)
+titan_init_pci(void)
 {
+ 	/*
+ 	 * This isn't really the right place, but there's some init
+ 	 * that needs to be done after everything is basically up.
+ 	 */
+ 	titan_late_init();
+ 
+	pci_probe_only = 1;
 	common_init_pci();
 	SMC669_Init(0);
 #ifdef CONFIG_VGA_HOSE
-	locate_and_init_vga(privateer_vga_hose_select);
+	locate_and_init_vga(NULL);
 #endif
 }
 
-void
-privateer_machine_check(unsigned long vector, unsigned long la_ptr,
-			struct pt_regs * regs)
+
+/*
+ * Privateer
+ */
+static void __init
+privateer_init_pci(void)
 {
-	/* only handle system events here */
-	if (vector != SCB_Q_SYSEVENT) 
-		return titan_machine_check(vector, la_ptr, regs);
-
-	/* it's a system event, handle it here */
-	printk("PRIVATEER 680 Machine Check on CPU %d\n", smp_processor_id());
+	/*
+	 * Hook a couple of extra err interrupts that the
+	 * common titan code won't.
+	 */
+	request_irq(53+16, titan_intr_nop, SA_INTERRUPT, 
+		    "NMI", NULL);
+	request_irq(50+16, titan_intr_nop, SA_INTERRUPT, 
+		    "Temperature Warning", NULL);
+
+	/*
+	 * Finish with the common version.
+	 */
+	return titan_init_pci();
 }
 
-
+
 /*
- * The System Vectors
+ * The System Vectors.
  */
+struct alpha_machine_vector titan_mv __initmv = {
+	vector_name:		"TITAN",
+	DO_EV6_MMU,
+	DO_DEFAULT_RTC,
+	DO_TITAN_IO,
+	DO_TITAN_BUS,
+	machine_check:		titan_machine_check,
+	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
+	min_io_address:		DEFAULT_IO_BASE,
+	min_mem_address:	DEFAULT_MEM_BASE,
+	pci_dac_offset:		TITAN_DAC_OFFSET,
+
+	nr_irqs:		80,	/* 64 + 16 */
+	/* device_interrupt will be filled in by titan_init_irq */
+
+	agp_info:		titan_agp_info,
+
+	init_arch:		titan_init_arch,
+	init_irq:		titan_legacy_init_irq,
+	init_rtc:		common_init_rtc,
+	init_pci:		titan_init_pci,
+
+	kill_arch:		titan_kill_arch,
+	pci_map_irq:		titan_map_irq,
+	pci_swizzle:		common_swizzle,
+};
+ALIAS_MV(titan)
 
 struct alpha_machine_vector privateer_mv __initmv = {
 	vector_name:		"PRIVATEER",
@@ -381,14 +403,18 @@
 	pci_dac_offset:		TITAN_DAC_OFFSET,
 
 	nr_irqs:		80,	/* 64 + 16 */
-	device_interrupt:	privateer_device_interrupt,
+	/* device_interrupt will be filled in by titan_init_irq */
+
+	agp_info:		titan_agp_info,
 
 	init_arch:		titan_init_arch,
-	init_irq:		privateer_init_irq,
+	init_irq:		titan_legacy_init_irq,
 	init_rtc:		common_init_rtc,
 	init_pci:		privateer_init_pci,
+
 	kill_arch:		titan_kill_arch,
-	pci_map_irq:		privateer_map_irq,
+	pci_map_irq:		titan_map_irq,
 	pci_swizzle:		common_swizzle,
 };
-ALIAS_MV(privateer)
+/* No alpha_mv alias for privateer since we compile it
+   in unconditionally with titan; setup_arch knows how to cope. */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/sys_wildfire.c linux-2.4.21-pre6/arch/alpha/kernel/sys_wildfire.c
--- linux-2.4.20/arch/alpha/kernel/sys_wildfire.c	2001-03-02 19:12:07.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/kernel/sys_wildfire.c	2003-03-26 23:49:30.000000000 +0000
@@ -352,5 +352,10 @@
 	kill_arch:		wildfire_kill_arch,
 	pci_map_irq:		wildfire_map_irq,
 	pci_swizzle:		common_swizzle,
+
+	pa_to_nid:		wildfire_pa_to_nid,
+	cpuid_to_nid:		wildfire_cpuid_to_nid,
+	node_mem_start:		wildfire_node_mem_start,
+	node_mem_size:		wildfire_node_mem_size,
 };
 ALIAS_MV(wildfire)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/time.c linux-2.4.21-pre6/arch/alpha/kernel/time.c
--- linux-2.4.20/arch/alpha/kernel/time.c	2002-02-25 19:37:52.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/kernel/time.c	2003-03-26 23:49:39.000000000 +0000
@@ -143,7 +143,9 @@
 
 	/* Reset periodic interrupt frequency.  */
 	x = CMOS_READ(RTC_FREQ_SELECT) & 0x3f;
-	if (x != 0x26 && x != 0x19 && x != 0x06) {
+	/* Test includes known working values on various platforms
+	   where 0x26 is wrong; we refuse to change those. */
+	if (x != 0x26 && x != 0x25 && x != 0x19 && x != 0x06) {
 		printk("Setting RTC_FREQ to 1024 Hz (%x)\n", x);
 		CMOS_WRITE(0x26, RTC_FREQ_SELECT);
 	}
@@ -183,8 +185,8 @@
 		unsigned int min, max;
 	} cpu_hz[] __initdata = {
 		[EV3_CPU]    = {   50000000,  200000000 },	/* guess */
-		[EV4_CPU]    = {  150000000,  300000000 },
-		[LCA4_CPU]   = {  150000000,  300000000 },	/* guess */
+		[EV4_CPU]    = {  100000000,  300000000 },
+		[LCA4_CPU]   = {  100000000,  300000000 },	/* guess */
 		[EV45_CPU]   = {  200000000,  300000000 },
 		[EV5_CPU]    = {  250000000,  433000000 },
 		[EV56_CPU]   = {  333000000,  667000000 },
@@ -255,12 +257,12 @@
 
 	cc = rpcc();
 	do {
-		count++;
+	  count += 100; /* by 1 takes too long to timeout from 0 */
 	} while ((inb(0x61) & 0x20) == 0 && count > 0);
 	cc = rpcc() - cc;
 
 	/* Error: ECTCNEVERSET or ECPUTOOFAST.  */
-	if (count <= 1)
+	if (count <= 100)
 		return 0;
 
 	/* Error: ECPUTOOSLOW.  */
@@ -378,21 +380,6 @@
 
 	/* Startup the timer source. */
 	alpha_mv.init_rtc();
-
-	/*
-	 * If we had wanted SRM console printk echoing early, undo it now.
-	 *
-	 * "srmcons" specified in the boot command arguments allows us to
-	 * see kernel messages during the period of time before the true
-	 * console device is "registered" during console_init(). As of this
-	 * version (2.4.10), time_init() is the last Alpha-specific code
-	 * called before console_init(), so we put this "unregister" code
-	 * here to prevent schizophrenic console behavior later... ;-}
-	 */
-	if (alpha_using_srm && srmcons_output) {
-		unregister_srm_console();
-		srmcons_output = 0;
-	}
 }
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/kernel/traps.c linux-2.4.21-pre6/arch/alpha/kernel/traps.c
--- linux-2.4.20/arch/alpha/kernel/traps.c	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/kernel/traps.c	2003-03-26 23:49:20.000000000 +0000
@@ -29,6 +29,7 @@
 */
 static int opDEC_testing = 0;
 static int opDEC_fix = 0;
+static int opDEC_checked = 0;
 static unsigned long opDEC_test_pc = 0;
 
 static void
@@ -36,6 +37,8 @@
 {
 	unsigned long test_pc;
 
+	if (opDEC_checked) return;
+
 	lock_kernel();
 	opDEC_testing = 1;
 
@@ -48,6 +51,7 @@
 		: );
 
 	opDEC_testing = 0;
+	opDEC_checked = 1;
 	unlock_kernel();
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/lib/callback_srm.S linux-2.4.21-pre6/arch/alpha/lib/callback_srm.S
--- linux-2.4.20/arch/alpha/lib/callback_srm.S	2000-06-20 00:59:33.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/lib/callback_srm.S	2003-03-26 23:49:29.000000000 +0000
@@ -78,6 +78,8 @@
 CALLBACK(open, CCB_OPEN, 3)
 CALLBACK(close, CCB_CLOSE, 2)
 CALLBACK(read, CCB_READ, 5)
+CALLBACK(open_console, CCB_OPEN_CONSOLE, 1)
+CALLBACK(close_console, CCB_CLOSE_CONSOLE, 1)
 CALLBACK(getenv, CCB_GET_ENV, 4)
 CALLBACK(setenv, CCB_SET_ENV, 4)
 CALLBACK(getc, CCB_GETC, 2)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/lib/ev6-strncpy_from_user.S linux-2.4.21-pre6/arch/alpha/lib/ev6-strncpy_from_user.S
--- linux-2.4.20/arch/alpha/lib/ev6-strncpy_from_user.S	2000-12-04 01:45:20.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/lib/ev6-strncpy_from_user.S	2003-03-26 23:49:55.000000000 +0000
@@ -27,7 +27,7 @@
 
 
 #include <asm/errno.h>
-#include <alpha/regdef.h>
+#include <asm/regdef.h>
 
 
 /* Allow an exception for an insn; exit if we get one.  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/lib/ev6-stxcpy.S linux-2.4.21-pre6/arch/alpha/lib/ev6-stxcpy.S
--- linux-2.4.20/arch/alpha/lib/ev6-stxcpy.S	2000-12-11 21:46:26.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/lib/ev6-stxcpy.S	2003-03-26 23:48:57.000000000 +0000
@@ -30,7 +30,7 @@
  * Try not to change the actual algorithm if possible for consistency.
  */
 
-#include <alpha/regdef.h>
+#include <asm/regdef.h>
 
 	.set noat
 	.set noreorder
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/lib/ev6-stxncpy.S linux-2.4.21-pre6/arch/alpha/lib/ev6-stxncpy.S
--- linux-2.4.20/arch/alpha/lib/ev6-stxncpy.S	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/lib/ev6-stxncpy.S	2003-03-26 23:49:51.000000000 +0000
@@ -25,7 +25,7 @@
  *	a0  = unaligned address of the last *word* written
  *	a2  = the number of full words left in COUNT
  *
- * Furthermore, v0, a3-a5, t11, t12, and $at are untouched.
+ * Furthermore, v0, a3-a5, t11, and $at are untouched.
  *
  * Much of the information about 21264 scheduling/coding comes from:
  *	Compiler Writer's Guide for the Alpha 21264
@@ -38,7 +38,7 @@
  * Try not to change the actual algorithm if possible for consistency.
  */
 
-#include <alpha/regdef.h>
+#include <asm/regdef.h>
 
 	.set noat
 	.set noreorder
@@ -324,7 +324,7 @@
 	extqh	t2, a1, t0	# U : extract low bits for last word (stall)
 	or	t1, t0, t1	# E : (stall)
 
-	cmpbge	zero, t1, t8	# E :
+1:	cmpbge	zero, t1, t8	# E :
 	mov	t1, t0		# E :
 
 $u_eocfin:			# end-of-count, final word
@@ -350,17 +350,17 @@
 	mskql	t6, a0, t6	# U :
 	nop
 	nop
-1:	subq	a1, t4, a1	# E : sub dest misalignment from src addr
+	subq	a1, t4, a1	# E : sub dest misalignment from src addr
 
 	/* If source misalignment is larger than dest misalignment, we need
 	   extra startup checks to avoid SEGV.  */
 
-	cmplt	t4, t5, t12	# E :
+1:	cmplt	t4, t5, t12	# E :
 	extql	t1, a1, t1	# U : shift src into place
 	lda	t2, -1		# E : for creating masks later
 	beq	t12, $u_head	# U : (stall)
 
-	mskqh	t2, t5, t2	# U : begin src byte validity mask
+	nop
 	cmpbge	zero, t1, t8	# E : is there a zero?
 	extql	t2, a1, t2	# U :
 	or	t8, t10, t5	# E : test for end-of-count too
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/lib/ev67-strchr.S linux-2.4.21-pre6/arch/alpha/lib/ev67-strchr.S
--- linux-2.4.20/arch/alpha/lib/ev67-strchr.S	2000-12-11 21:46:26.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/lib/ev67-strchr.S	2003-03-26 23:48:58.000000000 +0000
@@ -16,7 +16,7 @@
  * Try not to change the actual algorithm if possible for consistency.
  */
 
-#include <alpha/regdef.h>
+#include <asm/regdef.h>
 
 	.set noreorder
 	.set noat
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/lib/ev67-strlen_user.S linux-2.4.21-pre6/arch/alpha/lib/ev67-strlen_user.S
--- linux-2.4.20/arch/alpha/lib/ev67-strlen_user.S	2000-12-04 01:45:20.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/lib/ev67-strlen_user.S	2003-03-26 23:49:35.000000000 +0000
@@ -23,7 +23,7 @@
  * Try not to change the actual algorithm if possible for consistency.
  */
 
-#include <alpha/regdef.h>
+#include <asm/regdef.h>
 
 
 /* Allow an exception for an insn; exit if we get one.  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/lib/ev67-strrchr.S linux-2.4.21-pre6/arch/alpha/lib/ev67-strrchr.S
--- linux-2.4.20/arch/alpha/lib/ev67-strrchr.S	2000-12-30 19:13:36.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/lib/ev67-strrchr.S	2003-03-26 23:49:40.000000000 +0000
@@ -19,7 +19,7 @@
  */
 
 
-#include <alpha/regdef.h>
+#include <asm/regdef.h>
 
 	.set noreorder
 	.set noat
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/lib/strchr.S linux-2.4.21-pre6/arch/alpha/lib/strchr.S
--- linux-2.4.20/arch/alpha/lib/strchr.S	1996-10-18 08:53:20.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/lib/strchr.S	2003-03-26 23:49:35.000000000 +0000
@@ -6,7 +6,7 @@
  * string, or null if it is not found.
  */
 
-#include <alpha/regdef.h>
+#include <asm/regdef.h>
 
 	.set noreorder
 	.set noat
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/lib/strlen_user.S linux-2.4.21-pre6/arch/alpha/lib/strlen_user.S
--- linux-2.4.20/arch/alpha/lib/strlen_user.S	1999-10-11 17:06:34.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/lib/strlen_user.S	2003-03-26 23:49:39.000000000 +0000
@@ -12,7 +12,7 @@
  * boundary when doing so.
  */
 
-#include <alpha/regdef.h>
+#include <asm/regdef.h>
 
 
 /* Allow an exception for an insn; exit if we get one.  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/lib/strncpy_from_user.S linux-2.4.21-pre6/arch/alpha/lib/strncpy_from_user.S
--- linux-2.4.20/arch/alpha/lib/strncpy_from_user.S	1999-04-25 00:54:08.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/lib/strncpy_from_user.S	2003-03-26 23:49:00.000000000 +0000
@@ -12,7 +12,7 @@
 
 
 #include <asm/errno.h>
-#include <alpha/regdef.h>
+#include <asm/regdef.h>
 
 
 /* Allow an exception for an insn; exit if we get one.  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/lib/strrchr.S linux-2.4.21-pre6/arch/alpha/lib/strrchr.S
--- linux-2.4.20/arch/alpha/lib/strrchr.S	1997-11-19 22:07:33.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/lib/strrchr.S	2003-03-26 23:49:54.000000000 +0000
@@ -6,7 +6,7 @@
  * within a null-terminated string, or null if it is not found.
  */
 
-#include <alpha/regdef.h>
+#include <asm/regdef.h>
 
 	.set noreorder
 	.set noat
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/lib/stxcpy.S linux-2.4.21-pre6/arch/alpha/lib/stxcpy.S
--- linux-2.4.20/arch/alpha/lib/stxcpy.S	2000-12-11 21:46:26.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/lib/stxcpy.S	2003-03-26 23:49:19.000000000 +0000
@@ -20,7 +20,7 @@
  * Furthermore, v0, a3-a5, t11, and t12 are untouched.
  */
 
-#include <alpha/regdef.h>
+#include <asm/regdef.h>
 
 	.set noat
 	.set noreorder
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/lib/stxncpy.S linux-2.4.21-pre6/arch/alpha/lib/stxncpy.S
--- linux-2.4.20/arch/alpha/lib/stxncpy.S	2002-11-28 23:53:08.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/lib/stxncpy.S	2003-03-26 23:49:55.000000000 +0000
@@ -25,10 +25,10 @@
  *	a0  = unaligned address of the last *word* written
  *	a2  = the number of full words left in COUNT
  *
- * Furthermore, v0, a3-a5, t11, t12, and $at are untouched.
+ * Furthermore, v0, a3-a5, t11, and $at are untouched.
  */
 
-#include <alpha/regdef.h>
+#include <asm/regdef.h>
 
 	.set noat
 	.set noreorder
@@ -269,7 +269,7 @@
 	   t1 == the shifted high-order bits from the previous source word  */
 $u_eoc:
 	and	a1, 7, t6	# e1    :
-	sll	t12, t6, t6	# e0    :
+	sll	t10, t6, t6	# e0    :
 	and	t6, 0xff, t6	# e0    :
 	bne	t6, 1f		# .. e1 :
 
@@ -303,18 +303,17 @@
 	ldq_u	t0, 0(a0)	# e0    :
 	lda	t6, -1		# .. e1 :
 	mskql	t6, a0, t6	# e0    :
-1:
 	subq	a1, t4, a1	# .. e1 : sub dest misalignment from src addr
 
 	/* If source misalignment is larger than dest misalignment, we need
 	   extra startup checks to avoid SEGV.  */
 
-	cmplt	t4, t5, t12	# e1    :
+1:	cmplt	t4, t5, t12	# e1    :
 	extql	t1, a1, t1	# .. e0 : shift src into place
 	lda	t2, -1		# e0    : for creating masks later
-	beq	t12, $u_head	# e1    :
+	beq	t12, $u_head	# .. e1 :
 
-	mskqh	t2, t5, t2	# e0    : begin src byte validity mask
+	nop			# e0    :
 	cmpbge	zero, t1, t8	# .. e1 : is there a zero?
 	extql	t2, a1, t2	# e0    :
 	or	t8, t10, t5	# .. e1 : test for end-of-count too
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/lib/udelay.c linux-2.4.21-pre6/arch/alpha/lib/udelay.c
--- linux-2.4.20/arch/alpha/lib/udelay.c	2001-06-20 18:10:27.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/lib/udelay.c	2003-03-26 23:49:08.000000000 +0000
@@ -18,7 +18,8 @@
  * a 1GHz box, that's about 2 seconds.
  */
 
-void __delay(int loops)
+void
+__delay(int loops)
 {
 	int tmp;
 	__asm__ __volatile__(
@@ -30,18 +31,22 @@
 		: "=&r" (tmp), "=r" (loops) : "1"(loops));
 }
 
-void __udelay(unsigned long usecs, unsigned long lpj)
-{
-	usecs *= (((unsigned long)HZ << 32) / 1000000) * lpj;
-	__delay((long)usecs >> 32);
-}
-
-void udelay(unsigned long usecs)
-{
 #ifdef CONFIG_SMP
-	__udelay(usecs, cpu_data[smp_processor_id()].loops_per_jiffy);
+#define LPJ	cpu_data[smp_processor_id()].loops_per_jiffy
 #else
-	__udelay(usecs, loops_per_jiffy);
+#define LPJ	loops_per_jiffy
 #endif
+
+void
+ndelay(unsigned long nsecs)
+{
+	nsecs *= (((unsigned long)HZ << 32) / 1000000000) * LPJ;
+	__delay((long)nsecs >> 32);
 }
 
+void
+udelay(unsigned long usecs)
+{
+	usecs *= (((unsigned long)HZ << 32) / 1000000) * LPJ;
+	__delay((long)usecs >> 32);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/mm/Makefile linux-2.4.21-pre6/arch/alpha/mm/Makefile
--- linux-2.4.20/arch/alpha/mm/Makefile	2001-05-24 22:20:18.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/mm/Makefile	2003-03-26 23:49:55.000000000 +0000
@@ -9,7 +9,7 @@
 
 O_TARGET := mm.o
 
-obj-y	:= init.o fault.o extable.o
+obj-y	:= init.o fault.o extable.o remap.o
 
 obj-$(CONFIG_DISCONTIGMEM) += numa.o
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/mm/init.c linux-2.4.21-pre6/arch/alpha/mm/init.c
--- linux-2.4.20/arch/alpha/mm/init.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/mm/init.c	2003-03-26 23:49:27.000000000 +0000
@@ -368,18 +368,23 @@
 #endif /* CONFIG_DISCONTIGMEM */
 
 void
-free_initmem (void)
+free_reserved_mem(void *start, void *end)
 {
-	extern char __init_begin, __init_end;
-	unsigned long addr;
-
-	addr = (unsigned long)(&__init_begin);
-	for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
-		ClearPageReserved(virt_to_page(addr));
-		set_page_count(virt_to_page(addr), 1);
-		free_page(addr);
+	void *__start = start;
+	for (; __start < end; __start += PAGE_SIZE) {
+		ClearPageReserved(virt_to_page(__start));
+		set_page_count(virt_to_page(__start), 1);
+		free_page((long)__start);
 		totalram_pages++;
 	}
+}
+
+void
+free_initmem(void)
+{
+	extern char __init_begin, __init_end;
+
+	free_reserved_mem(&__init_begin, &__init_end);
 	printk (KERN_INFO "Freeing unused kernel memory: %ldk freed\n",
 		(&__init_end - &__init_begin) >> 10);
 }
@@ -388,14 +393,9 @@
 void
 free_initrd_mem(unsigned long start, unsigned long end)
 {
-	unsigned long __start = start;
-	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 (KERN_INFO "Freeing initrd memory: %ldk freed\n", (end - __start) >> 10);
+	free_reserved_mem((void *)start, (void *)end);
+	printk(KERN_INFO "Freeing initrd memory: %ldk freed\n",
+	       (end - start) >> 10);
 }
 #endif
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/mm/numa.c linux-2.4.21-pre6/arch/alpha/mm/numa.c
--- linux-2.4.20/arch/alpha/mm/numa.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/mm/numa.c	2003-03-26 23:48:59.000000000 +0000
@@ -64,20 +64,22 @@
 	unsigned long bootmap_size, bootmap_pages, bootmap_start;
 	unsigned long start, end;
 	unsigned long node_pfn_start, node_pfn_end;
+	unsigned long node_min_pfn, node_max_pfn;
 	int i;
 	unsigned long node_datasz = PFN_UP(sizeof(plat_pg_data_t));
 	int show_init = 0;
 
 	/* Find the bounds of current node */
-	node_pfn_start = (nid * NODE_MAX_MEM_SIZE) >> PAGE_SHIFT;
-	node_pfn_end = node_pfn_start + (NODE_MAX_MEM_SIZE >> PAGE_SHIFT);
+	node_pfn_start = (NODE_MEM_START(nid)) >> PAGE_SHIFT;
+	node_pfn_end = node_pfn_start + (NODE_MEM_SIZE(nid) >> PAGE_SHIFT);
 	
 	/* Find free clusters, and init and free the bootmem accordingly.  */
 	memdesc = (struct memdesc_struct *)
 	  (hwrpb->mddt_offset + (unsigned long) hwrpb);
 
-	/* find the bounds of this node (min_low_pfn/max_low_pfn) */
-	min_low_pfn = ~0UL;
+	/* find the bounds of this node (node_min_pfn/node_max_pfn) */
+	node_min_pfn = ~0UL;
+	node_max_pfn = 0UL;
 	for_each_mem_cluster(memdesc, cluster, i) {
 		/* Bit 0 is console/PALcode reserved.  Bit 1 is
 		   non-volatile memory -- we might want to mark
@@ -104,36 +106,46 @@
 		if (end > node_pfn_end)
 			end = node_pfn_end;
 
-		if (start < min_low_pfn)
-			min_low_pfn = start;
-		if (end > max_low_pfn)
-			max_low_pfn = end;
+		if (start < node_min_pfn)
+			node_min_pfn = start;
+		if (end > node_max_pfn)
+			node_max_pfn = end;
 	}
 
-	if (mem_size_limit && max_low_pfn >= mem_size_limit) {
-		printk("setup: forcing memory size to %ldK (from %ldK).\n",
-		       mem_size_limit << (PAGE_SHIFT - 10),
-		       max_low_pfn    << (PAGE_SHIFT - 10));
-		max_low_pfn = mem_size_limit;
+	if (mem_size_limit && node_max_pfn > mem_size_limit) {
+		static int msg_shown = 0;
+		if (!msg_shown) {
+			msg_shown = 1;
+			printk("setup: forcing memory size to %ldK (from %ldK).\n",
+			       mem_size_limit << (PAGE_SHIFT - 10),
+			       node_max_pfn   << (PAGE_SHIFT - 10));
+		}
+		node_max_pfn = mem_size_limit;
 	}
 
-	if (min_low_pfn >= max_low_pfn)
+	if (node_min_pfn >= node_max_pfn)
 		return;
 
-	num_physpages += max_low_pfn - min_low_pfn;
+	/* Update global {min,max}_low_pfn from node information. */
+	if (node_min_pfn < min_low_pfn)
+		min_low_pfn = node_min_pfn;
+	if (node_max_pfn > max_low_pfn)
+		max_low_pfn = node_max_pfn;
+
+	num_physpages += node_max_pfn - node_min_pfn;
 
 	/* Cute trick to make sure our local node data is on local memory */
-	PLAT_NODE_DATA(nid) = (plat_pg_data_t *)(__va(min_low_pfn << PAGE_SHIFT));
+	PLAT_NODE_DATA(nid) = (plat_pg_data_t *)(__va(node_min_pfn << PAGE_SHIFT));
 	/* Quasi-mark the plat_pg_data_t as in-use */
-	min_low_pfn += node_datasz;
-	if (min_low_pfn >= max_low_pfn) {
+	node_min_pfn += node_datasz;
+	if (node_min_pfn >= node_max_pfn) {
 		printk(" not enough mem to reserve PLAT_NODE_DATA");
 		return;
 	}
 	NODE_DATA(nid)->bdata = &plat_node_bdata[nid];
 
 	printk(" Detected node memory:   start %8lu, end %8lu\n",
-	       min_low_pfn, max_low_pfn);
+	       node_min_pfn, node_max_pfn);
 
 	DBGDCONT(" DISCONTIG: plat_node_data[%d]   is at 0x%p\n", nid, PLAT_NODE_DATA(nid));
 	DBGDCONT(" DISCONTIG: NODE_DATA(%d)->bdata is at 0x%p\n", nid, NODE_DATA(nid)->bdata);
@@ -143,15 +155,15 @@
 	end_kernel_pfn = PFN_UP(virt_to_phys(kernel_end));
 	bootmap_start = -1;
 
-	if (!nid && (max_low_pfn < end_kernel_pfn || min_low_pfn > start_kernel_pfn))
+	if (!nid && (node_max_pfn < end_kernel_pfn || node_min_pfn > start_kernel_pfn))
 		panic("kernel loaded out of ram");
 
 	/* Zone start phys-addr must be 2^(MAX_ORDER-1) aligned */
-	min_low_pfn = (min_low_pfn + ((1UL << (MAX_ORDER-1))-1)) & ~((1UL << (MAX_ORDER-1))-1);
+	node_min_pfn = (node_min_pfn + ((1UL << (MAX_ORDER-1))-1)) & ~((1UL << (MAX_ORDER-1))-1);
 
 	/* We need to know how many physically contiguous pages
 	   we'll need for the bootmap.  */
-	bootmap_pages = bootmem_bootmap_pages(max_low_pfn-min_low_pfn);
+	bootmap_pages = bootmem_bootmap_pages(node_max_pfn-node_min_pfn);
 
 	/* Now find a good region where to allocate the bootmap.  */
 	for_each_mem_cluster(memdesc, cluster, i) {
@@ -161,13 +173,13 @@
 		start = cluster->start_pfn;
 		end = start + cluster->numpages;
 
-		if (start >= max_low_pfn || end <= min_low_pfn)
+		if (start >= node_max_pfn || end <= node_min_pfn)
 			continue;
 
-		if (end > max_low_pfn)
-			end = max_low_pfn;
-		if (start < min_low_pfn)
-			start = min_low_pfn;
+		if (end > node_max_pfn)
+			end = node_max_pfn;
+		if (start < node_min_pfn)
+			start = node_min_pfn;
 
 		if (start < start_kernel_pfn) {
 			if (end > end_kernel_pfn
@@ -189,7 +201,7 @@
 
 	/* Allocate the bootmap and mark the whole MM as reserved.  */
 	bootmap_size = init_bootmem_node(NODE_DATA(nid), bootmap_start,
-					 min_low_pfn, max_low_pfn);
+					 node_min_pfn, node_max_pfn);
 	DBGDCONT(" bootmap_start %lu, bootmap_size %lu, bootmap_pages %lu\n",
 		 bootmap_start, bootmap_size, bootmap_pages);
 
@@ -201,13 +213,13 @@
 		start = cluster->start_pfn;
 		end = cluster->start_pfn + cluster->numpages;
 
-		if (start >= max_low_pfn || end <= min_low_pfn)
+		if (start >= node_max_pfn || end <= node_min_pfn)
 			continue;
 
-		if (end > max_low_pfn)
-			end = max_low_pfn;
-		if (start < min_low_pfn)
-			start = min_low_pfn;
+		if (end > node_max_pfn)
+			end = node_max_pfn;
+		if (start < node_min_pfn)
+			start = node_min_pfn;
 
 		if (start < start_kernel_pfn) {
 			if (end > end_kernel_pfn) {
@@ -243,22 +255,27 @@
 	show_mem_layout();
 
 	numnodes = 0;
+
+	min_low_pfn = ~0UL;
+	max_low_pfn = 0UL;
 	for (nid = 0; nid < MAX_NUMNODES; nid++)
 		setup_memory_node(nid, kernel_end);
 
 #ifdef CONFIG_BLK_DEV_INITRD
 	initrd_start = INITRD_START;
 	if (initrd_start) {
+		extern void *move_initrd(unsigned long);
+
 		initrd_end = initrd_start+INITRD_SIZE;
 		printk("Initial ramdisk at: 0x%p (%lu bytes)\n",
 		       (void *) initrd_start, INITRD_SIZE);
 
 		if ((void *)initrd_end > phys_to_virt(PFN_PHYS(max_low_pfn))) {
-			printk("initrd extends beyond end of memory "
-			       "(0x%08lx > 0x%p)\ndisabling initrd\n",
-			       initrd_end,
-			       phys_to_virt(PFN_PHYS(max_low_pfn)));
-			initrd_start = initrd_end = 0;
+			if (!move_initrd(PFN_PHYS(max_low_pfn)))
+				printk("initrd extends beyond end of memory "
+				       "(0x%08lx > 0x%p)\ndisabling initrd\n",
+				       initrd_end,
+				       phys_to_virt(PFN_PHYS(max_low_pfn)));
 		} else {
 			reserve_bootmem_node(NODE_DATA(KVADDR_TO_NID(initrd_start)),
 					     virt_to_phys((void *)initrd_start),
@@ -383,8 +400,8 @@
 	initsize =  (unsigned long) &__init_end - (unsigned long) &__init_begin;
 
 	printk("Memory: %luk/%luk available (%luk kernel code, %luk reserved, "
-		"%luk data, %luk init)\n",
-	       nr_free_pages() << (PAGE_SHIFT-10),
+	       "%luk data, %luk init)\n",
+	       (unsigned long)nr_free_pages() << (PAGE_SHIFT-10),
 	       num_physpages << (PAGE_SHIFT-10),
 	       codesize >> 10,
 	       reservedpages << (PAGE_SHIFT-10),
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/mm/remap.c linux-2.4.21-pre6/arch/alpha/mm/remap.c
--- linux-2.4.20/arch/alpha/mm/remap.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/mm/remap.c	2003-03-26 23:49:25.000000000 +0000
@@ -0,0 +1,88 @@
+#include <linux/vmalloc.h>
+#include <asm/pgalloc.h>
+
+/* called with the page_table_lock held */
+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;
+
+	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(_PAGE_VALID | _PAGE_ASM | 
+					     _PAGE_KRE | _PAGE_KWE | flags)));
+		address += PAGE_SIZE;
+		phys_addr += PAGE_SIZE;
+		pte++;
+	} while (address && (address < end));
+}
+
+/* called with the page_table_lock held */
+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;
+}
+
+int
+__alpha_remap_area_pages(unsigned long address, unsigned long phys_addr,
+			 unsigned long size, unsigned long flags)
+{
+	pgd_t * dir;
+	int error = 0;
+	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);
+	return error;
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/alpha/vmlinux.lds.in linux-2.4.21-pre6/arch/alpha/vmlinux.lds.in
--- linux-2.4.20/arch/alpha/vmlinux.lds.in	2001-11-22 18:54:10.000000000 +0000
+++ linux-2.4.21-pre6/arch/alpha/vmlinux.lds.in	2003-03-26 23:49:39.000000000 +0000
@@ -8,7 +8,7 @@
 #ifdef CONFIG_ALPHA_LEGACY_START_ADDRESS
   . = 0xfffffc0000310000;
 #else
-  . = 0xfffffc0000810000;
+  . = 0xfffffc0001010000;
 #endif
 
   _text = .;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/config.in linux-2.4.21-pre6/arch/arm/config.in
--- linux-2.4.20/arch/arm/config.in	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/arm/config.in	2003-03-26 23:49:10.000000000 +0000
@@ -83,7 +83,7 @@
    choice 'Cerf Flash available'  \
         "8MB    CONFIG_SA1100_CERF_FLASH_8MB \
          16MB   CONFIG_SA1100_CERF_FLASH_16MB \
-         32MB   CONFIG_SA1100_CERF_FLASH_32MB" CerfFlash
+         32MB   CONFIG_SA1100_CERF_FLASH_32MB" 8MB
    bool 'Cerf w/CPLD support (CerfPDA)' CONFIG_SA1100_CERF_CPLD
 fi
 dep_bool '  Compaq iPAQ H3100' CONFIG_SA1100_H3100 $CONFIG_ARCH_SA1100
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/def-configs/badge4 linux-2.4.21-pre6/arch/arm/def-configs/badge4
--- linux-2.4.20/arch/arm/def-configs/badge4	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/arm/def-configs/badge4	2003-03-26 23:49:53.000000000 +0000
@@ -798,6 +798,7 @@
 # CONFIG_RADIO_MIROPCM20 is not set
 # CONFIG_RADIO_MIROPCM20_RDS is not set
 # CONFIG_RADIO_SF16FMI is not set
+# CONFIG_RADIO_SF16FMR2 is not set
 # CONFIG_RADIO_TERRATEC is not set
 # CONFIG_RADIO_TRUST is not set
 # CONFIG_RADIO_TYPHOON is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/def-configs/empeg linux-2.4.21-pre6/arch/arm/def-configs/empeg
--- linux-2.4.20/arch/arm/def-configs/empeg	1999-10-20 23:29:08.000000000 +0000
+++ linux-2.4.21-pre6/arch/arm/def-configs/empeg	2003-03-26 23:49:20.000000000 +0000
@@ -119,6 +119,7 @@
 # CONFIG_VIDEO_PMS is not set
 # CONFIG_VIDEO_SAA5249 is not set
 # CONFIG_RADIO_SF16FMI is not set
+# CONFIG_RADIO_SF16FMR2 is not set
 # CONFIG_RADIO_TYPHOON is not set
 # CONFIG_RADIO_ZOLTRIX is not set
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/def-configs/footbridge linux-2.4.21-pre6/arch/arm/def-configs/footbridge
--- linux-2.4.20/arch/arm/def-configs/footbridge	2000-11-28 01:07:59.000000000 +0000
+++ linux-2.4.21-pre6/arch/arm/def-configs/footbridge	2003-03-26 23:49:25.000000000 +0000
@@ -599,6 +599,7 @@
 # CONFIG_RADIO_MAESTRO is not set
 # CONFIG_RADIO_MIROPCM20 is not set
 # CONFIG_RADIO_SF16FMI is not set
+# CONFIG_RADIO_SF16FMR2 is not set
 # CONFIG_RADIO_TERRATEC is not set
 # CONFIG_RADIO_TRUST is not set
 # CONFIG_RADIO_TYPHOON is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/kernel/arthur.c linux-2.4.21-pre6/arch/arm/kernel/arthur.c
--- linux-2.4.20/arch/arm/kernel/arthur.c	2001-09-10 20:04:33.000000000 +0000
+++ linux-2.4.21-pre6/arch/arm/kernel/arthur.c	2003-03-26 23:49:18.000000000 +0000
@@ -43,20 +43,48 @@
 	24,	25,	26,	27,	28,	29,	30,	31
 };
 
+/*
+ * Linux to Arthur signal map.
+ */
 static unsigned long linux_to_arthur_signals[32] = {
-	0,		-1,		ARTHUR_SIGINT,	-1,
-       	ARTHUR_SIGILL,	5,		ARTHUR_SIGABRT,	7,
-	ARTHUR_SIGFPE,	9,		ARTHUR_SIGUSR1,	ARTHUR_SIGSEGV,	
-	ARTHUR_SIGUSR2,	13,		14,		ARTHUR_SIGTERM,
-	16,		17,		18,		19,
-	20,		21,		22,		23,
-	24,		25,		26,		27,
-	28,		29,		30,		31
+	[0]		= 0,
+	[SIGHUP]	= -1,
+	[SIGINT]	= ARTHUR_SIGINT,
+	[SIGQUIT]	= -1,
+	[SIGILL]	= ARTHUR_SIGILL,
+	[SIGTRAP]	= 5,
+	[SIGABRT]	= ARTHUR_SIGABRT,
+	[SIGBUS]	= 7,
+	[SIGFPE]	= ARTHUR_SIGFPE,
+	[SIGKILL]	= 9,
+	[SIGUSR1]	= ARTHUR_SIGUSR1,
+	[SIGSEGV]	= ARTHUR_SIGSEGV,	
+	[SIGUSR2]	= ARTHUR_SIGUSR2,
+	[SIGPIPE]	= 13,
+	[SIGALRM]	= 14,
+	[SIGTERM]	= ARTHUR_SIGTERM,
+	[SIGSTKFLT]	= 16,
+	[SIGCHLD]	= 17,
+	[SIGCONT]	= 18,
+	[SIGSTOP]	= 19,
+	[SIGTSTP]	= 20,
+	[SIGTTIN]	= 21,
+	[SIGTTOU]	= 22,
+	[SIGURG]	= 23,
+	[SIGXCPU]	= 24,
+	[SIGXFSZ]	= 25,
+	[SIGVTALRM]	= 26,
+	[SIGPROF]	= 27,
+	[SIGWINCH]	= 28,
+	[SIGIO]		= 29,
+	[SIGPWR]	= 30,
+	[SIGSYS]	= 31
 };
 
 static void arthur_lcall7(int nr, struct pt_regs *regs)
 {
 	struct siginfo info;
+
 	info.si_signo = SIGSWI;
 	info.si_errno = nr;
 	/* Bounce it to the emulator */
@@ -64,13 +92,13 @@
 }
 
 static struct exec_domain arthur_exec_domain = {
-	"Arthur",	/* name */
-	arthur_lcall7,
-	PER_RISCOS, PER_RISCOS,
-	arthur_to_linux_signals,
-	linux_to_arthur_signals,
-	THIS_MODULE,
-	NULL		/* Nothing after this in the list. */
+	.name		= "Arthur",	/* name */
+	.handler	= arthur_lcall7,
+	.pers_low	= PER_RISCOS,
+	.pers_high	= PER_RISCOS,
+	.signal_map	= arthur_to_linux_signals,
+	.signal_invmap	= linux_to_arthur_signals,
+	.module		= THIS_MODULE,
 };
 
 /*
@@ -78,15 +106,18 @@
  * processes are using it.
  */
 
-int __init arthur_init(void)
+static int __init arthur_init(void)
 {
 	return register_exec_domain(&arthur_exec_domain);
 }
 
-void __exit arthur_exit(void)
+static void __exit arthur_exit(void)
 {
 	unregister_exec_domain(&arthur_exec_domain);
 }
 
 module_init(arthur_init);
 module_exit(arthur_exit);
+
+MODULE_AUTHOR("Philip Blundell");
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/kernel/dma-arc.c linux-2.4.21-pre6/arch/arm/kernel/dma-arc.c
--- linux-2.4.20/arch/arm/kernel/dma-arc.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/arm/kernel/dma-arc.c	2003-03-26 23:49:50.000000000 +0000
@@ -106,23 +106,23 @@
 }
 
 static struct dma_ops arc_floppy_data_dma_ops = {
-	type:		"FIQDMA",
-	enable:		arc_floppy_data_enable_dma,
-	disable:	arc_disable_dma,
-	residue:	arc_floppy_data_get_dma_residue,
+	.type		= "FIQDMA",
+	.enable		= arc_floppy_data_enable_dma,
+	.disable	= arc_disable_dma,
+	.residue	= arc_floppy_data_get_dma_residue,
 };
 
 static struct dma_ops arc_floppy_cmdend_dma_ops = {
-	type:		"FIQCMD",
-	enable:		arc_floppy_cmdend_enable_dma,
-	disable:	arc_disable_dma,
-	residue:	arc_floppy_cmdend_get_dma_residue,
+	.type		= "FIQCMD",
+	.enable		= arc_floppy_cmdend_enable_dma,
+	.disable	= arc_disable_dma,
+	.residue	= arc_floppy_cmdend_get_dma_residue,
 };
 #endif
 
 #ifdef CONFIG_ARCH_A5K
 static struct fiq_handler fh = {
-	name:	"floppydata"
+	.name		= "floppydata",
 };
 
 static int a5k_floppy_get_dma_residue(dmach_t channel, dma_t *dma)
@@ -168,10 +168,10 @@
 }
 
 static struct dma_ops a5k_floppy_dma_ops = {
-	type:		"FIQDMA",
-	enable:		a5k_floppy_enable_dma,
-	disable:	a5k_floppy_disable_dma,
-	residue:	a5k_floppy_get_dma_residue,
+	.type		= "FIQDMA",
+	.enable		= a5k_floppy_enable_dma,
+	.disable	= a5k_floppy_disable_dma,
+	.residue	= a5k_floppy_get_dma_residue,
 };
 #endif
 
@@ -183,9 +183,9 @@
 }
 
 static struct dma_ops sound_dma_ops = {
-	type:		"VIRTUAL",
-	enable:		sound_enable_disable_dma,
-	disable:	sound_enable_disable_dma,
+	.type		= "VIRTUAL",
+	.enable		= sound_enable_disable_dma,
+	.disable	= sound_enable_disable_dma,
 };
 
 void __init arch_dma_init(dma_t *dma)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/kernel/dma-footbridge.c linux-2.4.21-pre6/arch/arm/kernel/dma-footbridge.c
--- linux-2.4.20/arch/arm/kernel/dma-footbridge.c	2000-09-18 22:15:24.000000000 +0000
+++ linux-2.4.21-pre6/arch/arm/kernel/dma-footbridge.c	2003-03-26 23:49:29.000000000 +0000
@@ -35,10 +35,10 @@
 }
 
 static struct dma_ops fb_dma_ops = {
-	type:		"fb",
-	request:	fb_dma_request,
-	enable:		fb_dma_enable,
-	disable:	fb_dma_disable,
+	.type		= "fb",
+	.request	= fb_dma_request,
+	.enable		= fb_dma_enable,
+	.disable	= fb_dma_disable,
 };
 #endif
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/kernel/dma-isa.c linux-2.4.21-pre6/arch/arm/kernel/dma-isa.c
--- linux-2.4.20/arch/arm/kernel/dma-isa.c	2001-10-11 16:04:57.000000000 +0000
+++ linux-2.4.21-pre6/arch/arm/kernel/dma-isa.c	2003-03-26 23:49:38.000000000 +0000
@@ -133,10 +133,10 @@
 }
 
 static struct dma_ops isa_dma_ops = {
-	type:		"ISA",
-	enable:		isa_enable_dma,
-	disable:	isa_disable_dma,
-	residue:	isa_get_dma_residue,
+	.type		= "ISA",
+	.enable		= isa_enable_dma,
+	.disable	= isa_disable_dma,
+	.residue	= isa_get_dma_residue,
 };
 
 static struct resource dma_resources[] = {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/kernel/dma-rpc.c linux-2.4.21-pre6/arch/arm/kernel/dma-rpc.c
--- linux-2.4.20/arch/arm/kernel/dma-rpc.c	2001-02-09 19:29:44.000000000 +0000
+++ linux-2.4.21-pre6/arch/arm/kernel/dma-rpc.c	2003-03-26 23:49:35.000000000 +0000
@@ -257,16 +257,16 @@
 }
 
 static struct dma_ops iomd_dma_ops = {
-	type:		"IOMD",
-	request:	iomd_request_dma,
-	free:		iomd_free_dma,
-	enable:		iomd_enable_dma,
-	disable:	iomd_disable_dma,
-	setspeed:	iomd_set_dma_speed,
+	.type		= "IOMD",
+	.request	= iomd_request_dma,
+	.free		= iomd_free_dma,
+	.enable		= iomd_enable_dma,
+	.disable	= iomd_disable_dma,
+	.setspeed	= iomd_set_dma_speed,
 };
 
 static struct fiq_handler fh = {
-	name: "floppydma"
+	.name		= "floppydma"
 };
 
 static void floppy_enable_dma(dmach_t channel, dma_t *dma)
@@ -313,10 +313,10 @@
 }
 
 static struct dma_ops floppy_dma_ops = {
-	type:		"FIQDMA",
-	enable:		floppy_enable_dma,
-	disable:	floppy_disable_dma,
-	residue:	floppy_get_residue,
+	.type		= "FIQDMA",
+	.enable		= floppy_enable_dma,
+	.disable	= floppy_disable_dma,
+	.residue	= floppy_get_residue,
 };
 
 /*
@@ -327,9 +327,9 @@
 }
 
 static struct dma_ops sound_dma_ops = {
-	type:		"VIRTUAL",
-	enable:		sound_enable_disable_dma,
-	disable:	sound_enable_disable_dma,
+	.type		= "VIRTUAL",
+	.enable		= sound_enable_disable_dma,
+	.disable	= sound_enable_disable_dma,
 };
 
 void __init arch_dma_init(dma_t *dma)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/kernel/ecard.c linux-2.4.21-pre6/arch/arm/kernel/ecard.c
--- linux-2.4.20/arch/arm/kernel/ecard.c	2001-08-12 18:13:59.000000000 +0000
+++ linux-2.4.21-pre6/arch/arm/kernel/ecard.c	2003-03-26 23:49:51.000000000 +0000
@@ -420,7 +420,7 @@
 }
 
 static struct notifier_block ecard_reboot_notifier = {
-	notifier_call:	ecard_reboot,
+	.notifier_call	= ecard_reboot,
 };
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/kernel/fiq.c linux-2.4.21-pre6/arch/arm/kernel/fiq.c
--- linux-2.4.20/arch/arm/kernel/fiq.c	2001-06-27 21:12:04.000000000 +0000
+++ linux-2.4.21-pre6/arch/arm/kernel/fiq.c	2003-03-26 23:49:53.000000000 +0000
@@ -86,8 +86,8 @@
 }
 
 static struct fiq_handler default_owner = {
-	name:	"default",
-	fiq_op:	fiq_def_op,
+	.name	= "default",
+	.fiq_op	= fiq_def_op,
 };
 
 static struct fiq_handler *current_fiq = &default_owner;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/kernel/ftv-pci.c linux-2.4.21-pre6/arch/arm/kernel/ftv-pci.c
--- linux-2.4.20/arch/arm/kernel/ftv-pci.c	2000-09-18 22:15:25.000000000 +0000
+++ linux-2.4.21-pre6/arch/arm/kernel/ftv-pci.c	2003-03-26 23:49:39.000000000 +0000
@@ -44,8 +44,8 @@
 
 /* ftv host-specific stuff */
 struct hw_pci ftv_pci __initdata = {
-	init:		plx90x0_init,
-	swizzle:	ftv_swizzle,
-	map_irq:	ftv_map_irq,
+	.init		= plx90x0_init,
+	.swizzle	= ftv_swizzle,
+	.map_irq	= ftv_map_irq,
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/kernel/process.c linux-2.4.21-pre6/arch/arm/kernel/process.c
--- linux-2.4.20/arch/arm/kernel/process.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/arm/kernel/process.c	2003-03-26 23:49:27.000000000 +0000
@@ -366,7 +366,7 @@
  * a system call from a "real" process, but the process memory space will
  * not be free'd until both the parent and the child have exited.
  */
-pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
+pid_t arch_kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
 {
 	pid_t __ret;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/kernel/time.c linux-2.4.21-pre6/arch/arm/kernel/time.c
--- linux-2.4.20/arch/arm/kernel/time.c	2001-10-11 16:04:57.000000000 +0000
+++ linux-2.4.21-pre6/arch/arm/kernel/time.c	2003-03-26 23:49:50.000000000 +0000
@@ -202,7 +202,7 @@
 }
 
 static struct irqaction timer_irq = {
-	name: "timer",
+	.name	= "timer",
 };
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/mach-anakin/irq.c linux-2.4.21-pre6/arch/arm/mach-anakin/irq.c
--- linux-2.4.20/arch/arm/mach-anakin/irq.c	2001-08-12 18:13:59.000000000 +0000
+++ linux-2.4.21-pre6/arch/arm/mach-anakin/irq.c	2003-03-26 23:48:58.000000000 +0000
@@ -49,9 +49,9 @@
 }
 
 static struct irqaction anakin_irq = {
-	name:		"Anakin IRQ",
-	handler:	anakin_interrupt,
-	flags:		SA_INTERRUPT
+	.name		= "Anakin IRQ",
+	.handler	= anakin_interrupt,
+	.flags		= SA_INTERRUPT,
 };
  
 void __init
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/mach-footbridge/cats-pci.c linux-2.4.21-pre6/arch/arm/mach-footbridge/cats-pci.c
--- linux-2.4.20/arch/arm/mach-footbridge/cats-pci.c	2001-07-04 22:43:05.000000000 +0000
+++ linux-2.4.21-pre6/arch/arm/mach-footbridge/cats-pci.c	2003-03-26 23:49:08.000000000 +0000
@@ -32,9 +32,9 @@
 }
 
 struct hw_pci cats_pci __initdata = {
-	setup_resources:	dc21285_setup_resources,
-	init:			dc21285_init,
-	mem_offset:		DC21285_PCI_MEM,
-	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 -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/mach-footbridge/ebsa285-pci.c linux-2.4.21-pre6/arch/arm/mach-footbridge/ebsa285-pci.c
--- linux-2.4.20/arch/arm/mach-footbridge/ebsa285-pci.c	2001-07-04 22:43:05.000000000 +0000
+++ linux-2.4.21-pre6/arch/arm/mach-footbridge/ebsa285-pci.c	2003-03-26 23:49:55.000000000 +0000
@@ -34,9 +34,9 @@
 }
 
 struct hw_pci ebsa285_pci __initdata = {
-	setup_resources:	dc21285_setup_resources,
-	init:			dc21285_init,
-	mem_offset:		DC21285_PCI_MEM,
-	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 -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/mach-footbridge/netwinder-pci.c linux-2.4.21-pre6/arch/arm/mach-footbridge/netwinder-pci.c
--- linux-2.4.20/arch/arm/mach-footbridge/netwinder-pci.c	2001-07-04 22:43:05.000000000 +0000
+++ linux-2.4.21-pre6/arch/arm/mach-footbridge/netwinder-pci.c	2003-03-26 23:48:58.000000000 +0000
@@ -49,9 +49,9 @@
 }
 
 struct hw_pci netwinder_pci __initdata = {
-	setup_resources:	dc21285_setup_resources,
-	init:			dc21285_init,
-	mem_offset:		DC21285_PCI_MEM,
-	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 -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/mach-footbridge/personal-pci.c linux-2.4.21-pre6/arch/arm/mach-footbridge/personal-pci.c
--- linux-2.4.20/arch/arm/mach-footbridge/personal-pci.c	2001-07-04 22:43:05.000000000 +0000
+++ linux-2.4.21-pre6/arch/arm/mach-footbridge/personal-pci.c	2003-03-26 23:49:29.000000000 +0000
@@ -38,9 +38,9 @@
 }
 
 struct hw_pci personal_server_pci __initdata = {
-	setup_resources:	dc21285_setup_resources,
-	init:			dc21285_init,
-	mem_offset:		DC21285_PCI_MEM,
-	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 -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/mach-integrator/arch.c linux-2.4.21-pre6/arch/arm/mach-integrator/arch.c
--- linux-2.4.20/arch/arm/mach-integrator/arch.c	2001-08-12 18:13:59.000000000 +0000
+++ linux-2.4.21-pre6/arch/arm/mach-integrator/arch.c	2003-03-26 23:49:50.000000000 +0000
@@ -36,17 +36,17 @@
 
 #ifdef CONFIG_KMI_KEYB
 static struct kmi_info integrator_keyboard __initdata = {
-	base:	IO_ADDRESS(KMI0_BASE),
-	irq:	IRQ_KMIINT0,
-	divisor: 24 / 8 - 1,
-	type:	KMI_KEYBOARD,
+	.base		= IO_ADDRESS(KMI0_BASE),
+	.irq		= IRQ_KMIINT0,
+	.divisor	= 24 / 8 - 1,
+	.type		= KMI_KEYBOARD,
 };
 
 static struct kmi_info integrator_mouse __initdata = {
-	base:	IO_ADDRESS(KMI1_BASE),
-	irq:	IRQ_KMIINT1,
-	divisor: 24 / 8 - 1,
-	type:	KMI_MOUSE,
+	.base		= IO_ADDRESS(KMI1_BASE),
+	.irq		= IRQ_KMIINT1,
+	.divisor	= 24 / 8 - 1,
+	.type		= KMI_MOUSE,
 };
 #endif
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/mach-integrator/pci.c linux-2.4.21-pre6/arch/arm/mach-integrator/pci.c
--- linux-2.4.20/arch/arm/mach-integrator/pci.c	2001-08-12 18:13:59.000000000 +0000
+++ linux-2.4.21-pre6/arch/arm/mach-integrator/pci.c	2003-03-26 23:49:39.000000000 +0000
@@ -114,9 +114,9 @@
 extern void pci_v3_init(void *);
 
 struct hw_pci integrator_pci __initdata = {
-	setup_resources:	pci_v3_setup_resources,
-	init:			pci_v3_init,
-	mem_offset:		0x40000000,
-	swizzle:		integrator_swizzle,
-	map_irq:		integrator_map_irq,
+	.setup_resources	= pci_v3_setup_resources,
+	.init			= pci_v3_init,
+	.mem_offset		= 0x40000000,
+	.swizzle		= integrator_swizzle,
+	.map_irq		= integrator_map_irq,
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/mach-integrator/pci_v3.c linux-2.4.21-pre6/arch/arm/mach-integrator/pci_v3.c
--- linux-2.4.20/arch/arm/mach-integrator/pci_v3.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/arm/mach-integrator/pci_v3.c	2003-03-26 23:49:09.000000000 +0000
@@ -390,26 +390,26 @@
 }
 
 static struct pci_ops pci_v3_ops = {
-	read_byte:	v3_read_config_byte,
-	read_word:	v3_read_config_word,
-	read_dword:	v3_read_config_dword,
-	write_byte:	v3_write_config_byte,
-	write_word:	v3_write_config_word,
-	write_dword:	v3_write_config_dword,
+	.read_byte	= v3_read_config_byte,
+	.read_word	= v3_read_config_word,
+	.read_dword	= v3_read_config_dword,
+	.write_byte	= v3_write_config_byte,
+	.write_word	= v3_write_config_word,
+	.write_dword	= v3_write_config_dword,
 };
 
 static struct resource non_mem = {
-	name:	"PCI non-prefetchable",
-	start:	0x40000000 + PCI_BUS_NONMEM_START,
-	end:	0x40000000 + PCI_BUS_NONMEM_START + PCI_BUS_NONMEM_SIZE - 1,
-	flags:	IORESOURCE_MEM,
+	.name	= "PCI non-prefetchable",
+	.start	= 0x40000000 + PCI_BUS_NONMEM_START,
+	.end	= 0x40000000 + PCI_BUS_NONMEM_START + PCI_BUS_NONMEM_SIZE - 1,
+	.flags	= IORESOURCE_MEM,
 };
 
 static struct resource pre_mem = {
-	name:	"PCI prefetchable",
-	start:	0x40000000 + PCI_BUS_PREMEM_START,
-	end:	0x40000000 + PCI_BUS_PREMEM_START + PCI_BUS_PREMEM_SIZE - 1,
-	flags:	IORESOURCE_MEM | IORESOURCE_PREFETCH,
+	.name	= "PCI prefetchable",
+	.start	= 0x40000000 + PCI_BUS_PREMEM_START,
+	.end	= 0x40000000 + PCI_BUS_PREMEM_START + PCI_BUS_PREMEM_SIZE - 1,
+	.flags	= IORESOURCE_MEM | IORESOURCE_PREFETCH,
 };
 
 int __init pci_v3_setup_resources(struct resource **resource)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/mach-sa1100/adsbitsy.c linux-2.4.21-pre6/arch/arm/mach-sa1100/adsbitsy.c
--- linux-2.4.20/arch/arm/mach-sa1100/adsbitsy.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/arm/mach-sa1100/adsbitsy.c	2003-03-26 23:48:58.000000000 +0000
@@ -149,7 +149,7 @@
 }
 
 static struct sa1100_port_fns adsbitsy_port_fns __initdata = {
-	open:	adsbitsy_uart_open,
+	.open	= adsbitsy_uart_open,
 };
 
 static void __init adsbitsy_map_io(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/mach-sa1100/assabet.c linux-2.4.21-pre6/arch/arm/mach-sa1100/assabet.c
--- linux-2.4.20/arch/arm/mach-sa1100/assabet.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/arm/mach-sa1100/assabet.c	2003-03-26 23:48:58.000000000 +0000
@@ -285,9 +285,9 @@
 }
 
 static struct sa1100_port_fns assabet_port_fns __initdata = {
-	set_mctrl:	assabet_set_mctrl,
-	get_mctrl:	assabet_get_mctrl,
-	pm:		assabet_uart_pm,
+	.set_mctrl	= assabet_set_mctrl,
+	.get_mctrl	= assabet_get_mctrl,
+	.pm		= assabet_uart_pm,
 };
 
 static void __init assabet_map_io(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/mach-sa1100/badge4.c linux-2.4.21-pre6/arch/arm/mach-sa1100/badge4.c
--- linux-2.4.20/arch/arm/mach-sa1100/badge4.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/arm/mach-sa1100/badge4.c	2003-03-26 23:49:54.000000000 +0000
@@ -14,6 +14,7 @@
  *
  */
 
+#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/mach-sa1100/cpu-sa1100.c linux-2.4.21-pre6/arch/arm/mach-sa1100/cpu-sa1100.c
--- linux-2.4.20/arch/arm/mach-sa1100/cpu-sa1100.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/arm/mach-sa1100/cpu-sa1100.c	2003-03-26 23:49:00.000000000 +0000
@@ -216,7 +216,7 @@
 
 
 static struct notifier_block sa1100_dram_block = {
-	notifier_call: sa1100_dram_notifier,
+	.notifier_call = sa1100_dram_notifier,
 };
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/mach-sa1100/h3600.c linux-2.4.21-pre6/arch/arm/mach-sa1100/h3600.c
--- linux-2.4.20/arch/arm/mach-sa1100/h3600.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/arm/mach-sa1100/h3600.c	2003-03-26 23:49:18.000000000 +0000
@@ -144,11 +144,11 @@
 }
 
 static struct ipaq_model_ops h3100_model_ops __initdata = {
-	model	     : IPAQ_H3100,
-	generic_name : "3100",
-	initialize   : h3100_init_egpio,
-	control      : h3100_control_egpio,
-	read	     : h3100_read_egpio
+	.model		= IPAQ_H3100,
+	.generic_name	= "3100",
+	.initialize	= h3100_init_egpio,
+	.control	= h3100_control_egpio,
+	.read		= h3100_read_egpio
 };
 
 
@@ -223,11 +223,11 @@
 }
 
 static struct ipaq_model_ops h3600_model_ops __initdata = {
-	model	     : IPAQ_H3600,
-	generic_name : "3600",
-	initialize   : h3600_init_egpio,
-	control      : h3600_control_egpio,
-	read	     : h3600_read_egpio
+	.model		= IPAQ_H3600,
+	.generic_name	= "3600",
+	.initialize	= h3600_init_egpio,
+	.control	= h3600_control_egpio,
+	.read		= h3600_read_egpio
 };
 
 /************************* H3800 *************************/
@@ -331,11 +331,11 @@
 }
 
 static struct ipaq_model_ops h3800_model_ops __initdata = {
-	model	     : IPAQ_H3800,
-	generic_name : "3800",
-	initialize   : h3800_init_egpio,
-	control      : h3800_control_egpio,
-	read	     : h3800_read_egpio
+	.model		= IPAQ_H3800,
+	.generic_name	= "3800",
+	.initialize	= h3800_init_egpio,
+	.control	= h3800_control_egpio,
+	.read		= h3800_read_egpio
 };
 
 
@@ -468,12 +468,12 @@
 }
 
 static struct sa1100_port_fns h3600_port_fns __initdata = {
-	set_mctrl:	h3600_uart_set_mctrl,
-	get_mctrl:	h3600_uart_get_mctrl,
-	pm:		h3600_uart_pm,
-	set_wake:	h3600_uart_set_wake,
-	open:		h3600_uart_open,
-	close:		h3600_uart_close,
+	.set_mctrl	= h3600_uart_set_mctrl,
+	.get_mctrl	= h3600_uart_get_mctrl,
+	.pm		= h3600_uart_pm,
+	.set_wake	= h3600_uart_set_wake,
+	.open		= h3600_uart_open,
+	.close		= h3600_uart_close,
 };
 
 static struct map_desc h3600_io_desc[] __initdata = {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/mach-sa1100/neponset.c linux-2.4.21-pre6/arch/arm/mach-sa1100/neponset.c
--- linux-2.4.20/arch/arm/mach-sa1100/neponset.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/arm/mach-sa1100/neponset.c	2003-03-26 23:49:38.000000000 +0000
@@ -54,9 +54,9 @@
 }
 
 static struct irqaction neponset_irq = {
-	name:		"Neponset",
-	handler:	neponset_IRQ_demux,
-	flags:		SA_INTERRUPT
+	.name		= "Neponset",
+	.handler	= neponset_IRQ_demux,
+	.flags		= SA_INTERRUPT
 };
 
 static void __init neponset_init_irq(void)
@@ -214,8 +214,8 @@
 }
 
 static struct sa1100_port_fns neponset_port_fns __initdata = {
-	set_mctrl:	neponset_set_mctrl,
-	get_mctrl:	neponset_get_mctrl,
+	.set_mctrl	= neponset_set_mctrl,
+	.get_mctrl	= neponset_get_mctrl,
 };
 
 void __init neponset_map_io(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/mach-sa1100/sa1111.c linux-2.4.21-pre6/arch/arm/mach-sa1100/sa1111.c
--- linux-2.4.20/arch/arm/mach-sa1100/sa1111.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/arm/mach-sa1100/sa1111.c	2003-03-26 23:49:29.000000000 +0000
@@ -35,7 +35,7 @@
 #include "sa1111.h"
 
 struct resource sa1111_resource = {
-	name:	"SA1111",
+	.name	= "SA1111",
 };
 
 EXPORT_SYMBOL(sa1111_resource);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/mach-sa1100/simpad.c linux-2.4.21-pre6/arch/arm/mach-sa1100/simpad.c
--- linux-2.4.20/arch/arm/mach-sa1100/simpad.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/arm/mach-sa1100/simpad.c	2003-03-26 23:49:05.000000000 +0000
@@ -76,7 +76,7 @@
 }
 
 static struct sa1100_port_fns simpad_port_fns __initdata = {
-	pm:	simpad_uart_pm,
+	.pm	= simpad_uart_pm,
 };
 
 static void __init simpad_map_io(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/mach-sa1100/system3.c linux-2.4.21-pre6/arch/arm/mach-sa1100/system3.c
--- linux-2.4.20/arch/arm/mach-sa1100/system3.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/arm/mach-sa1100/system3.c	2003-03-26 23:48:57.000000000 +0000
@@ -107,19 +107,19 @@
 };
 
 static struct sa1100_port_fns system3_port_fns __initdata = {
-	set_mctrl:	system3_set_mctrl,
-	get_mctrl:	system3_get_mctrl,
-	pm:		system3_uart_pm,
+	.set_mctrl	= system3_set_mctrl,
+	.get_mctrl	= system3_get_mctrl,
+	.pm		= system3_uart_pm,
 };
 
 static struct irqaction system3_irq = {
-	name:		"PT Digital Board SA1111 IRQ",
-	handler:	system3_IRQ_demux,
-	flags:		SA_INTERRUPT
+	.name		= "PT Digital Board SA1111 IRQ",
+	.handler	= system3_IRQ_demux,
+	.flags		= SA_INTERRUPT
 };
 
 static struct notifier_block system3_clkchg_block = {
-	notifier_call:	sdram_notifier,
+	.notifier_call	= sdram_notifier,
 };
 
 /**********************************************************************
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/mach-shark/pci.c linux-2.4.21-pre6/arch/arm/mach-shark/pci.c
--- linux-2.4.20/arch/arm/mach-shark/pci.c	2000-09-19 15:31:53.000000000 +0000
+++ linux-2.4.21-pre6/arch/arm/mach-shark/pci.c	2003-03-26 23:49:25.000000000 +0000
@@ -21,7 +21,7 @@
 }
 
 struct hw_pci shark_pci __initdata = {
-	init: via82c505_init,
-	swizzle: no_swizzle,
-	map_irq: shark_map_irq
+	.init		= via82c505_init,
+	.swizzle	= no_swizzle,
+	.map_irq	= shark_map_irq,
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/arm/mm/discontig.c linux-2.4.21-pre6/arch/arm/mm/discontig.c
--- linux-2.4.20/arch/arm/mm/discontig.c	2001-08-12 18:13:59.000000000 +0000
+++ linux-2.4.21-pre6/arch/arm/mm/discontig.c	2003-03-26 23:49:54.000000000 +0000
@@ -20,7 +20,7 @@
 #endif
 
 /*
- * Our node_data structure for discontigous memory.
+ * Our node_data structure for discontiguous memory.
  */
 
 static bootmem_data_t node_bootmem_data[NR_NODES];
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/boot/compressed/decompress.ld linux-2.4.21-pre6/arch/cris/boot/compressed/decompress.ld
--- linux-2.4.20/arch/cris/boot/compressed/decompress.ld	2001-07-26 22:10:06.000000000 +0000
+++ linux-2.4.21-pre6/arch/cris/boot/compressed/decompress.ld	2003-03-26 23:49:02.000000000 +0000
@@ -13,6 +13,7 @@
 		_stext = . ;
 		*(.text)
 		*(.rodata)
+		*(.rodata.*)
 		_etext = . ;
 	} > dram
 	.data :
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/boot/rescue/Makefile linux-2.4.21-pre6/arch/cris/boot/rescue/Makefile
--- linux-2.4.20/arch/cris/boot/rescue/Makefile	2002-02-25 19:37:52.000000000 +0000
+++ linux-2.4.21-pre6/arch/cris/boot/rescue/Makefile	2003-03-26 23:49:31.000000000 +0000
@@ -53,7 +53,7 @@
 
 modules:
 
-modules-install:
+modules_install:
 
 depend:
 	$(CC) -M *.S > .depend
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/config.in linux-2.4.21-pre6/arch/cris/config.in
--- linux-2.4.20/arch/cris/config.in	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/cris/config.in	2003-03-26 23:48:58.000000000 +0000
@@ -154,6 +154,11 @@
 
 source drivers/md/Config.in
 
+source drivers/pcmcia/Config.in
+if [ "$CONFIG_PCMCIA" != "n" ]; then
+   define_bool CONFIG_VIRTUAL_BUS y
+fi
+
 if [ "$CONFIG_NET" = "y" ]; then
   source net/Config.in
 fi
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/Config.in linux-2.4.21-pre6/arch/cris/drivers/Config.in
--- linux-2.4.20/arch/cris/drivers/Config.in	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/cris/drivers/Config.in	2003-03-26 23:49:18.000000000 +0000
@@ -26,46 +26,150 @@
   bool '  Use fast timers for serial DMA flush (experimental)' CONFIG_ETRAX_SERIAL_FAST_TIMER
   if [ "$CONFIG_ETRAX_SERIAL_FAST_TIMER" = "n" ]; then
     bool '  Fast serial port DMA flush' CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST
-    if [ "$CONFIG_ETRAX100_SERIAL_FLUSH_DMA_FAST" = "n" ]; then
+    if [ "$CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST" = "n" ]; then
       int '  Receive flush timeout (ticks) ' CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS 5
     fi
   fi
   bool '  Serial port 0 enabled' CONFIG_ETRAX_SERIAL_PORT0
   if [ "$CONFIG_ETRAX_SERIAL_PORT0" = "y" ]; then
-    bool '  Ser0 DTR, RI, DSR, CD on PB' CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB
-    if [ "$CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB" = "y" ]; then
-      int '    Ser0 DTR on PB bit' CONFIG_ETRAX_SER0_DTR_ON_PB_BIT 4
-      int '    Ser0 RI  on PB bit' CONFIG_ETRAX_SER0_RI_ON_PB_BIT 5
-      int '    Ser0 DSR on PB bit' CONFIG_ETRAX_SER0_DSR_ON_PB_BIT 6
-      int '    Ser0 CD  on PB bit' CONFIG_ETRAX_SER0_CD_ON_PB_BIT 7
+  choice 'Ser0 DTR, RI, DSR and CD assignment' \
+  "No_DTR_RI_DSR_CD      CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_NONE \
+   DTR_RI_DSR_CD_on_PA   CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PA \
+   DTR_RI_DSR_CD_on_PB   CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB \
+   DTR_RI_DSR_CD_mixed_on_PA_and_PB  CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED" \
+     No_DTR_RI_DSR_CD
+
+    if [ "$CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PA" = "y" -o \
+         "$CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED" = "y" ]; then
+      int '    Ser0 DTR on PA bit (-1 = not used)' CONFIG_ETRAX_SER0_DTR_ON_PA_BIT 4
+      int '    Ser0 RI  on PA bit (-1 = not used)' CONFIG_ETRAX_SER0_RI_ON_PA_BIT 5
+      int '    Ser0 DSR on PA bit (-1 = not used)' CONFIG_ETRAX_SER0_DSR_ON_PA_BIT 6
+      int '    Ser0 CD  on PA bit (-1 = not used)' CONFIG_ETRAX_SER0_CD_ON_PA_BIT 7
+    else
+      define_int CONFIG_ETRAX_SER0_DTR_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER0_RI_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER0_DSR_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER0_CD_ON_PA_BIT -1
+    fi
+    if [ "$CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB" = "y" -o \
+         "$CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED" = "y" ]; then
+      int '    Ser0 DTR on PB bit (-1 = not used)' CONFIG_ETRAX_SER0_DTR_ON_PB_BIT 4
+      int '    Ser0 RI  on PB bit (-1 = not used)' CONFIG_ETRAX_SER0_RI_ON_PB_BIT 5
+      int '    Ser0 DSR on PB bit (-1 = not used)' CONFIG_ETRAX_SER0_DSR_ON_PB_BIT 6
+      int '    Ser0 CD  on PB bit (-1 = not used)' CONFIG_ETRAX_SER0_CD_ON_PB_BIT 7
+    else
+      define_int CONFIG_ETRAX_SER0_DTR_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER0_RI_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER0_DSR_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER0_CD_ON_PB_BIT -1
     fi
   fi
 
   bool '  Serial port 1 enabled' CONFIG_ETRAX_SERIAL_PORT1
   if [ "$CONFIG_ETRAX_SERIAL_PORT1" = "y" ]; then
-    bool '  Ser1 DTR, RI, DSR, CD on PB' CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB
-    if [ "$CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB" = "y" ]; then
-      int '    Ser1 DTR on PB bit' CONFIG_ETRAX_SER1_DTR_ON_PB_BIT 4
-      int '    Ser1 RI  on PB bit' CONFIG_ETRAX_SER1_RI_ON_PB_BIT 5
-      int '    Ser1 DSR on PB bit' CONFIG_ETRAX_SER1_DSR_ON_PB_BIT 6
-      int '    Ser1 CD  on PB bit' CONFIG_ETRAX_SER1_CD_ON_PB_BIT 7
+  choice 'Ser1 DTR, RI, DSR and CD assignment' \
+  "No_DTR_RI_DSR_CD      CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_NONE \
+   DTR_RI_DSR_CD_on_PA   CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PA \
+   DTR_RI_DSR_CD_on_PB   CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB \
+   DTR_RI_DSR_CD_mixed_on_PA_and_PB  CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED" \
+     No_DTR_RI_DSR_CD
+
+    if [ "$CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PA" = "y" -o \
+         "$CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED" = "y" ]; then
+      int '    Ser1 DTR on PA bit (-1 = not used)' CONFIG_ETRAX_SER1_DTR_ON_PA_BIT 4
+      int '    Ser1 RI  on PA bit (-1 = not used)' CONFIG_ETRAX_SER1_RI_ON_PA_BIT 5
+      int '    Ser1 DSR on PA bit (-1 = not used)' CONFIG_ETRAX_SER1_DSR_ON_PA_BIT 6
+      int '    Ser1 CD  on PA bit (-1 = not used)' CONFIG_ETRAX_SER1_CD_ON_PA_BIT 7
+    else
+      define_int CONFIG_ETRAX_SER1_DTR_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER1_RI_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER1_DSR_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER1_CD_ON_PA_BIT -1
+    fi
+    if [ "$CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB" = "y" -o \
+         "$CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED" = "y" ]; then
+      int '    Ser1 DTR on PB bit (-1 = not used)' CONFIG_ETRAX_SER1_DTR_ON_PB_BIT 4
+      int '    Ser1 RI  on PB bit (-1 = not used)' CONFIG_ETRAX_SER1_RI_ON_PB_BIT 5
+      int '    Ser1 DSR on PB bit (-1 = not used)' CONFIG_ETRAX_SER1_DSR_ON_PB_BIT 6
+      int '    Ser1 CD  on PB bit (-1 = not used)' CONFIG_ETRAX_SER1_CD_ON_PB_BIT 7
+    else
+      define_int CONFIG_ETRAX_SER1_DTR_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER1_RI_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER1_DSR_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER1_CD_ON_PB_BIT -1
     fi
   fi
+
   if [ "$CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB" = "y" -a \
        "$CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB" = "y" ]; then
     comment 'Make sure you dont have the same PB bits more than once!'
   fi
   bool '  Serial port 2 enabled' CONFIG_ETRAX_SERIAL_PORT2
   if [ "$CONFIG_ETRAX_SERIAL_PORT2" = "y" ]; then
-    bool '    Ser2 DTR, RI, DSR, CD on PA' CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA
-    if [ "$CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA" = "y" ]; then
-      int '      Ser2 DTR on PA bit' CONFIG_ETRAX_SER2_DTR_ON_PA_BIT 4
-      int '      Ser2 RI  on PA bit' CONFIG_ETRAX_SER2_RI_ON_PA_BIT 5
-      int '      Ser2 DSR on PA bit' CONFIG_ETRAX_SER2_DSR_ON_PA_BIT 6
-      int '      Ser2 CD  on PA bit' CONFIG_ETRAX_SER2_CD_ON_PA_BIT 7
-    fi 
+  choice 'Ser2 DTR, RI, DSR and CD assignment' \
+  "No_DTR_RI_DSR_CD      CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_NONE \
+   DTR_RI_DSR_CD_on_PA   CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA \
+   DTR_RI_DSR_CD_on_PB   CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PB \
+   DTR_RI_DSR_CD_mixed_on_PA_and_PB  CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED" \
+     No_DTR_RI_DSR_CD
+    if [ "$CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA" = "y" -o \
+         "$CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED" = "y" ]; then
+      int '    Ser2 DTR on PA bit (-1 = not used)' CONFIG_ETRAX_SER2_DTR_ON_PA_BIT 4
+      int '    Ser2 RI  on PA bit (-1 = not used)' CONFIG_ETRAX_SER2_RI_ON_PA_BIT 5
+      int '    Ser2 DSR on PA bit (-1 = not used)' CONFIG_ETRAX_SER2_DSR_ON_PA_BIT 6
+      int '    Ser2 CD  on PA bit (-1 = not used)' CONFIG_ETRAX_SER2_CD_ON_PA_BIT 7
+    else
+      define_int CONFIG_ETRAX_SER2_DTR_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER2_RI_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER2_DSR_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER2_CD_ON_PA_BIT -1
+    fi
+    if [ "$CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PB" = "y" -o \
+         "$CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED" = "y" ]; then
+      int '    Ser2 DTR on PB bit (-1 = not used)' CONFIG_ETRAX_SER2_DTR_ON_PB_BIT 4
+      int '    Ser2 RI  on PB bit (-1 = not used)' CONFIG_ETRAX_SER2_RI_ON_PB_BIT 5
+      int '    Ser2 DSR on PB bit (-1 = not used)' CONFIG_ETRAX_SER2_DSR_ON_PB_BIT 6
+      int '    Ser2 CD  on PB bit (-1 = not used)' CONFIG_ETRAX_SER2_CD_ON_PB_BIT 7
+    else
+      define_int CONFIG_ETRAX_SER2_DTR_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER2_RI_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER2_DSR_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER2_CD_ON_PB_BIT -1
+    fi
   fi
   bool '  Serial port 3 enabled' CONFIG_ETRAX_SERIAL_PORT3
+  if [ "$CONFIG_ETRAX_SERIAL_PORT3" = "y" ]; then
+  choice 'Ser3 DTR, RI, DSR and CD assignment' \
+  "No_DTR_RI_DSR_CD      CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_ON_NONE \
+   DTR_RI_DSR_CD_on_PA   CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_ON_PA \
+   DTR_RI_DSR_CD_on_PB   CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_ON_PB \
+   DTR_RI_DSR_CD_mixed_on_PA_and_PB  CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED" \
+     No_DTR_RI_DSR_CD
+    if [ "$CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_ON_PA" = "y" -o \
+         "$CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED" = "y" ]; then
+      int '    Ser3 DTR on PA bit (-1 = not used)' CONFIG_ETRAX_SER3_DTR_ON_PA_BIT -1
+      int '    Ser3 RI  on PA bit (-1 = not used)' CONFIG_ETRAX_SER3_RI_ON_PA_BIT -1
+      int '    Ser3 DSR on PA bit (-1 = not used)' CONFIG_ETRAX_SER3_DSR_ON_PA_BIT -1
+      int '    Ser3 CD  on PA bit (-1 = not used)' CONFIG_ETRAX_SER3_CD_ON_PA_BIT -1
+    else
+      define_int CONFIG_ETRAX_SER3_DTR_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER3_RI_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER3_DSR_ON_PA_BIT -1
+      define_int CONFIG_ETRAX_SER3_CD_ON_PA_BIT -1
+    fi
+    if [ "$CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_ON_PB" = "y" -o \
+         "$CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED" = "y" ]; then
+      int '    Ser3 DTR on PB bit (-1 = not used)' CONFIG_ETRAX_SER3_DTR_ON_PB_BIT -1
+      int '    Ser3 RI  on PB bit (-1 = not used)' CONFIG_ETRAX_SER3_RI_ON_PB_BIT -1
+      int '    Ser3 DSR on PB bit (-1 = not used)' CONFIG_ETRAX_SER3_DSR_ON_PB_BIT -1
+      int '    Ser3 CD  on PB bit (-1 = not used)' CONFIG_ETRAX_SER3_CD_ON_PB_BIT -1
+    else
+      define_int CONFIG_ETRAX_SER3_DTR_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER3_RI_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER3_DSR_ON_PB_BIT -1
+      define_int CONFIG_ETRAX_SER3_CD_ON_PB_BIT -1
+    fi
+  fi
   bool '  RS-485 support' CONFIG_ETRAX_RS485
   if [ "$CONFIG_ETRAX_RS485" = "y" ]; then
     bool '    RS-485 mode on PA' CONFIG_ETRAX_RS485_ON_PA
@@ -139,7 +243,6 @@
 	define_bool CONFIG_MTD y
 
 	define_bool CONFIG_MTD_CFI y
-	define_bool CONFIG_MTD_CFI_INTELEXT n
 	define_bool CONFIG_MTD_CFI_AMDSTD y
 
 	define_bool CONFIG_MTD_OBSOLETE_CHIPS y
@@ -148,6 +251,7 @@
 	define_bool CONFIG_MTD_CHAR y
 	define_bool CONFIG_MTD_BLOCK y
 	define_bool CONFIG_MTD_PARTITIONS y
+	define_bool CONFIG_MTD_CONCAT y
 fi
 
 bool 'I2C support' CONFIG_ETRAX_I2C
@@ -209,6 +313,7 @@
   int '  DS1302 RST bit number' CONFIG_ETRAX_DS1302_RSTBIT 2
   int '  DS1302 SCL bit number' CONFIG_ETRAX_DS1302_SCLBIT 1
   int '  DS1302 SDA bit number' CONFIG_ETRAX_DS1302_SDABIT 0
+  int '  DS1302 Trickle charger value' CONFIG_ETRAX_DS1302_TRICKLE_CHARGE 0
 fi
 
 endmenu
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/Makefile linux-2.4.21-pre6/arch/cris/drivers/Makefile
--- linux-2.4.20/arch/cris/drivers/Makefile	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/cris/drivers/Makefile	2003-03-26 23:48:57.000000000 +0000
@@ -18,6 +18,7 @@
 obj-$(CONFIG_ETRAX_SYNCHRONOUS_SERIAL)  += sync_serial.o
 obj-$(CONFIG_ETRAX_PARPORT)             += parport.o
 obj-$(CONFIG_ETRAX_DS1302)              += ds1302.o
+obj-$(CONFIG_ETRAX_PCF8563)		+= pcf8563.o
 
 
 obj-$(CONFIG_ETRAX_ETHERNET_LPSLAVE)    += lpslave/lpslavedrivers.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/axisflashmap.c linux-2.4.21-pre6/arch/cris/drivers/axisflashmap.c
--- linux-2.4.20/arch/cris/drivers/axisflashmap.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/cris/drivers/axisflashmap.c	2003-03-26 23:49:51.000000000 +0000
@@ -11,6 +11,26 @@
  * partition split defined below.
  *
  * $Log: axisflashmap.c,v $
+ * Revision 1.28  2002/10/01 08:08:43  jonashg
+ * The first partition ends at the start of the partition table.
+ *
+ * Revision 1.27  2002/08/21 09:23:13  jonashg
+ * Speling.
+ *
+ * Revision 1.26  2002/08/21 08:35:20  jonashg
+ * Cosmetic change to printouts.
+ *
+ * Revision 1.25  2002/08/21 08:15:42  jonashg
+ * Made it compile even without CONFIG_MTD_CONCAT defined.
+ *
+ * Revision 1.24  2002/08/20 13:12:35  jonashg
+ * * New approach to probing. Probe cse0 and cse1 separately and (mtd)concat
+ *   the results.
+ * * Removed compile time tests concerning how the mtdram driver has been
+ *   configured. The user will know about the misconfiguration at runtime
+ *   instead. (The old approach made it impossible to use mtdram for anything
+ *   else than RAM boot).
+ *
  * Revision 1.23  2002/05/13 12:12:28  johana
  * Allow compile without CONFIG_MTD_MTDRAM but warn at compiletime and
  * be informative at runtime.
@@ -98,13 +118,15 @@
 #include <linux/kernel.h>
 #include <linux/config.h>
 
-#include <linux/mtd/mtd.h>
+#include <linux/mtd/concat.h>
 #include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
+#include <linux/mtd/mtd.h>
 #include <linux/mtd/mtdram.h>
+#include <linux/mtd/partitions.h>
 
 #include <asm/axisflashmap.h>
 #include <asm/mmu.h>
+#include <asm/sv_addr_ag.h>
 
 #ifdef CONFIG_CRIS_LOW_MAP
 #define FLASH_UNCACHED_ADDR  KSEG_8
@@ -114,63 +136,65 @@
 #define FLASH_CACHED_ADDR    KSEG_F
 #endif
 
-/*
- * WINDOW_SIZE is the total size where the flash chips may be mapped.
- * MTD probes should find all devices there and it does not matter
- * if there are unmapped gaps or aliases (mirrors of flash devices).
- * The MTD probes will ignore them.
- */
-
-#define WINDOW_SIZE  (128 * 1024 * 1024)
-
-extern unsigned long romfs_start, romfs_length, romfs_in_flash; /* From head.S */
+/* From head.S */
+extern unsigned long romfs_start, romfs_length, romfs_in_flash;
 
-/* 
- * Map driver
- *
- * We run into tricky coherence situations if we mix cached with uncached
- * accesses to we use the uncached version here.
- */
+/* Map driver functions. */
 
 static __u8 flash_read8(struct map_info *map, unsigned long ofs)
 {
-	return *(__u8 *)(FLASH_UNCACHED_ADDR + ofs);
+	return *(__u8 *)(map->map_priv_1 + ofs);
 }
 
 static __u16 flash_read16(struct map_info *map, unsigned long ofs)
 {
-	return *(__u16 *)(FLASH_UNCACHED_ADDR + ofs);
+	return *(__u16 *)(map->map_priv_1 + ofs);
 }
 
 static __u32 flash_read32(struct map_info *map, unsigned long ofs)
 {
-	return *(volatile unsigned int *)(FLASH_UNCACHED_ADDR + ofs);
+	return *(volatile unsigned int *)(map->map_priv_1 + ofs);
 }
 
 static void flash_copy_from(struct map_info *map, void *to,
 			    unsigned long from, ssize_t len)
 {
-	memcpy(to, (void *)(FLASH_UNCACHED_ADDR + from), len);
+	memcpy(to, (void *)(map->map_priv_1 + from), len);
 }
 
 static void flash_write8(struct map_info *map, __u8 d, unsigned long adr)
 {
-	*(__u8 *)(FLASH_UNCACHED_ADDR + adr) = d;
+	*(__u8 *)(map->map_priv_1 + adr) = d;
 }
 
 static void flash_write16(struct map_info *map, __u16 d, unsigned long adr)
 {
-	*(__u16 *)(FLASH_UNCACHED_ADDR + adr) = d;
+	*(__u16 *)(map->map_priv_1 + adr) = d;
 }
 
 static void flash_write32(struct map_info *map, __u32 d, unsigned long adr)
 {
-	*(__u32 *)(FLASH_UNCACHED_ADDR + adr) = d;
+	*(__u32 *)(map->map_priv_1 + adr) = d;
 }
 
-static struct map_info axis_map = {
-	name: "Axis flash",
-	size: WINDOW_SIZE,
+/*
+ * The map for chip select e0.
+ *
+ * We run into tricky coherence situations if we mix cached with uncached
+ * accesses to we only use the uncached version here.
+ *
+ * The size field is the total size where the flash chips may be mapped on the
+ * chip select. MTD probes should find all devices there and it does not matter
+ * if there are unmapped gaps or aliases (mirrors of flash devices). The MTD
+ * probes will ignore them.
+ *
+ * The start address in map_priv_1 is in virtual memory so we cannot use
+ * MEM_CSE0_START but must rely on that FLASH_UNCACHED_ADDR is the start
+ * address of cse0.
+ */
+static struct map_info map_cse0 = {
+	name: "cse0",
+	size: MEM_CSE0_SIZE,
 	buswidth: CONFIG_ETRAX_FLASH_BUSWIDTH,
 	read8: flash_read8,
 	read16: flash_read16,
@@ -179,15 +203,35 @@
 	write8: flash_write8,
 	write16: flash_write16,
 	write32: flash_write32,
+	map_priv_1: FLASH_UNCACHED_ADDR
 };
 
-/* If no partition-table was found, we use this default-set.
+/*
+ * The map for chip select e1.
+ *
+ * If there was a gap between cse0 and cse1, map_priv_1 would get the wrong
+ * address, but there isn't.
  */
+static struct map_info map_cse1 = {
+	name: "cse1",
+	size: MEM_CSE1_SIZE,
+	buswidth: CONFIG_ETRAX_FLASH_BUSWIDTH,
+	read8: flash_read8,
+	read16: flash_read16,
+	read32: flash_read32,
+	copy_from: flash_copy_from,
+	write8: flash_write8,
+	write16: flash_write16,
+	write32: flash_write32,
+	map_priv_1: FLASH_UNCACHED_ADDR + MEM_CSE0_SIZE
+};
 
+/* If no partition-table was found, we use this default-set. */
 #define MAX_PARTITIONS         7  
 #define NUM_DEFAULT_PARTITIONS 3
 
-/* Default flash size is 2MB. CONFIG_ETRAX_PTABLE_SECTOR is most likely the
+/*
+ * 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.
  */
@@ -209,10 +253,11 @@
 	}
 };
 
+/* Initialize the ones normally used. */
 static struct mtd_partition axis_partitions[MAX_PARTITIONS] = {
 	{
 		name: "part0",
-		size: 0,
+		size: CONFIG_ETRAX_PTABLE_SECTOR,
 		offset: 0
 	},
 	{
@@ -247,48 +292,118 @@
 	},
 };
 
+/*
+ * Probe a chip select for AMD-compatible (JEDEC) or CFI-compatible flash
+ * chips in that order (because the amd_flash-driver is faster).
+ */
+static struct mtd_info *probe_cs(struct map_info *map_cs)
+{
+	struct mtd_info *mtd_cs = NULL;
+
+	printk("%s: Probing a 0x%08lx bytes large window at 0x%08lx.\n",
+	       map_cs->name, map_cs->size, map_cs->map_priv_1);
+
+#ifdef CONFIG_MTD_AMDSTD
+	mtd_cs = do_map_probe("amd_flash", map_cs);
+#endif
+#ifdef CONFIG_MTD_CFI
+	if (!mtd_cs) {
+		mtd_cs = do_map_probe("cfi_probe", map_cs);
+	}
+#endif
+
+	return mtd_cs;
+}
+
 /* 
- * This is the master MTD device for which all the others are just
- * auto-relocating aliases.
+ * Probe each chip select individually for flash chips. If there are chips on
+ * both cse0 and cse1, the mtd_info structs will be concatenated to one struct
+ * so that MTD partitions can cross chip boundries.
+ *
+ * The only known restriction to how you can mount your chips is that each
+ * chip select must hold similar flash chips. But you need external hardware
+ * to do that anyway and you can put totally different chips on cse0 and cse1
+ * so it isn't really much of a restriction.
  */
-static struct mtd_info *mymtd;
+static struct mtd_info *flash_probe(void)
+{
+	struct mtd_info *mtd_cse0;
+	struct mtd_info *mtd_cse1;
+	struct mtd_info *mtd_cse;
+
+	mtd_cse0 = probe_cs(&map_cse0);
+	mtd_cse1 = probe_cs(&map_cse1);
+
+	if (!mtd_cse0 && !mtd_cse1) {
+		/* No chip found. */
+		return NULL;
+	}
+
+	if (mtd_cse0 && mtd_cse1) {
+#ifdef CONFIG_MTD_CONCAT
+		struct mtd_info *mtds[] = { mtd_cse0, mtd_cse1 };
+		
+		/* Since the concatenation layer adds a small overhead we
+		 * could try to figure out if the chips in cse0 and cse1 are
+		 * identical and reprobe the whole cse0+cse1 window. But since
+		 * flash chips are slow, the overhead is relatively small.
+		 * So we use the MTD concatenation layer instead of further
+		 * complicating the probing procedure.
+		 */
+		mtd_cse = mtd_concat_create(mtds,
+					    sizeof(mtds) / sizeof(mtds[0]),
+					    "cse0+cse1");
+#else
+		printk(KERN_ERR "%s and %s: Cannot concatenate due to kernel "
+		       "(mis)configuration!\n", map_cse0.name, map_cse1.name);
+		mtd_cse = NULL;
+#endif
+		if (!mtd_cse) {
+			printk(KERN_ERR "%s and %s: Concatenation failed!\n",
+			       map_cse0.name, map_cse1.name);
+
+			/* The best we can do now is to only use what we found
+			 * at cse0.
+			 */ 
+			mtd_cse = mtd_cse0;
+			map_destroy(mtd_cse1);
+		}
+	} else {
+		mtd_cse = mtd_cse0? mtd_cse0 : mtd_cse1;
+	}
+
+	return mtd_cse;
+}
 
-/* CFI-scan the flash, and if there was a chip, read the partition-table
+/*
+ * Probe the flash chip(s) and, if it succeeds, read the partition-table
  * and register the partitions with MTD.
  */
-
-static int __init
-init_axis_flash(void)
+static int __init init_axis_flash(void)
 {
+	struct mtd_info *mymtd;
 	int err = 0;
 	int pidx = 0;
 	struct partitiontable_head *ptable_head;
 	struct partitiontable_entry *ptable;
-	int use_default_ptable = 1; /* Until proven otherwise */
-	const char *pmsg = "  /dev/flash%d at 0x%x, size 0x%x\n";
-
-	printk(KERN_NOTICE "Axis flash mapping: %x at %lx\n",
-	       WINDOW_SIZE, FLASH_CACHED_ADDR);
-#ifdef CONFIG_MTD_AMDSTD
-	mymtd = (struct mtd_info *)do_map_probe("amd_flash", &axis_map);
-#endif
+	int use_default_ptable = 1; /* Until proven otherwise. */
+	const char *pmsg = "  /dev/flash%d at 0x%08x, size 0x%08x\n";
 
-#ifdef CONFIG_MTD_CFI
-	if (!mymtd) {
-		mymtd = (struct mtd_info *)do_map_probe("cfi_probe", &axis_map);
+	if (!(mymtd = flash_probe())) {
+		/* There's no reason to use this module if no flash chip can
+		 * be identified. Make sure that's understood.
+		 */
+		panic("axisflashmap found no flash chip!\n");
 	}
-#endif
 
-	if(!mymtd) {
-		printk("%s: No flash chip found!\n", axis_map.name);
-		return -ENXIO;
-	}
+	printk("%s: 0x%08x bytes of flash memory.\n",
+	       mymtd->name, mymtd->size);
 
 	mymtd->module = THIS_MODULE;
 
 	ptable_head = (struct partitiontable_head *)(FLASH_CACHED_ADDR +
-		CONFIG_ETRAX_PTABLE_SECTOR + PARTITION_TABLE_OFFSET);
-	pidx++;  /* first partition is always set to the default */
+		      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 <
@@ -322,20 +437,17 @@
 			csum += *p++;
 			csum += *p++;
 		}
-		/* printk("  total csum: 0x%08X 0x%08X\n",
-		   csum, ptable_head->checksum); */
 		ptable_ok = (csum == ptable_head->checksum);
 
 		/* Read the entries and use/show the info.  */
-		printk(" Found %s partition table at 0x%08lX-0x%08lX.\n",
-		       (ptable_ok ? "valid" : "invalid"),
-		       (unsigned long)ptable_head,
-		       (unsigned long)max_addr);
+		printk(" Found a%s partition table at 0x%p-0x%p.\n",
+		       (ptable_ok ? " valid" : "n invalid"), ptable_head,
+		       max_addr);
 
 		/* We have found a working bootblock.  Now read the
-		   partition table.  Scan the table.  It ends when
-		   there is 0xffffffff, that is, empty flash.  */
-		
+		 * partition table.  Scan the table.  It ends when
+		 * there is 0xffffffff, that is, empty flash.
+		 */
 		while (ptable_ok
 		       && ptable->offset != 0xffffffff
 		       && ptable < max_addr
@@ -352,59 +464,64 @@
 		use_default_ptable = !ptable_ok;
 	}
 
+	if (romfs_in_flash) {
+		/* Add an overlapping device for the root partition (romfs). */
+
+		axis_partitions[pidx].name = "romfs";
+		axis_partitions[pidx].size = romfs_length;
+		axis_partitions[pidx].offset = romfs_start - FLASH_CACHED_ADDR;
+		axis_partitions[pidx].mask_flags |= MTD_WRITEABLE;
+
+		printk(" Adding readonly flash partition for romfs image:\n");
+		printk(pmsg, pidx, axis_partitions[pidx].offset,
+		       axis_partitions[pidx].size);
+		pidx++;
+	}
+
 	if (use_default_ptable) {
-		printk(" Using default partition table\n");
+		printk(" Using default partition table.\n");
 		err = add_mtd_partitions(mymtd, axis_default_partitions,
 		                         NUM_DEFAULT_PARTITIONS);
 	} else {
-		if (romfs_in_flash) {
-			axis_partitions[pidx].name = "romfs";
-			axis_partitions[pidx].size = romfs_length;
-			axis_partitions[pidx].offset = romfs_start -
-						       FLASH_CACHED_ADDR;
-			axis_partitions[pidx].mask_flags |= MTD_WRITEABLE;
-
-			printk(" Adding readonly partition for romfs image:\n");
-			printk(pmsg, pidx, axis_partitions[pidx].offset,
-			       axis_partitions[pidx].size);
-			pidx++;
-		}
-
 		err = add_mtd_partitions(mymtd, axis_partitions, pidx);
 	}
-	if (!err && !romfs_in_flash) {
-#ifdef CONFIG_MTD_MTDRAM
-		/* Allocate, initialise and forget the mtd ram struct
-		 * when booting from RAM
-		 */
-		struct mtd_info *romfs_mtd = (struct mtd_info *)kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
-		printk("MTD RAM device romfs_start: 0x%08lX len %lu\n",
-		       romfs_start, romfs_length);
 
-#if (CONFIG_MTDRAM_TOTAL_SIZE != 0) || (CONFIG_MTDRAM_ABS_POS != 0)
-#error "You must set CONFIG_MTDRAM_TOTAL_SIZE and CONFIG_MTDRAM_ABS_POS to 0"
-#endif
-		err = mtdram_init_device(romfs_mtd, (void*)romfs_start, 
-		                         romfs_length, "romfs in RAM");
+	if (err) {
+		panic("axisflashmap could not add MTD partitions!\n");
+	}
+
+	if (!romfs_in_flash) {
+		/* Create an RAM device for the root partition (romfs). */
+
+#if !defined(CONFIG_MTD_MTDRAM) || (CONFIG_MTDRAM_TOTAL_SIZE != 0) || (CONFIG_MTDRAM_ABS_POS != 0)
+		/* No use trying to boot this kernel from RAM. Panic! */
+		printk(KERN_EMERG "axisflashmap: Cannot create an MTD RAM "
+		       "device due to kernel (mis)configuration!\n");
+		panic("This kernel cannot boot from RAM!\n");
 #else
-#warning ######################################
-#warning # You must enable CONFIG_MTD_MTDRAM  #
-#warning # with TOTAL_SIZE 0 and ABS_POS 0 to # 
-#warning # be able to boot with cramfs in RAM #
-#warning ######################################
-/* Maybe overkill to save these bytes in non debug builds, but let's do it..
- * (No point in printing if we don't have a debug port anyway...)
- */
-#ifndef CONFIG_ETRAX_DEBUG_PORT_NULL
-		printk("## Can't mount romfs in RAM using MTDRAM.\n");
-		printk("## You must enable MTD_MTDRAM with TOTAL_SIZE 0 and ABS_POS 0\n");
+		struct mtd_info *mtd_ram;
+
+		mtd_ram = (struct mtd_info *)kmalloc(sizeof(struct mtd_info),
+						     GFP_KERNEL);
+		if (!mtd_ram) {
+			panic("axisflashmap couldn't allocate memory for "
+			      "mtd_info!\n");
+		}
+
+		printk(" Adding RAM partition for romfs image:\n");
+		printk(pmsg, pidx, romfs_start, romfs_length);
+
+		err = mtdram_init_device(mtd_ram, (void*)romfs_start, 
+		                         romfs_length, "romfs");
+		if (err) {
+			panic("axisflashmap could not initialize MTD RAM "
+			      "device!\n");
+		}
 #endif
-#endif /* CONFIG_MTD_MTDRAM */
 	}
+
 	return err;
 }
 
-/* This adds the above to the kernels init-call chain */
-
+/* This adds the above to the kernels init-call chain. */
 module_init(init_axis_flash);
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/bluetooth/Makefile linux-2.4.21-pre6/arch/cris/drivers/bluetooth/Makefile
--- linux-2.4.20/arch/cris/drivers/bluetooth/Makefile	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/cris/drivers/bluetooth/Makefile	2003-03-26 23:49:49.000000000 +0000
@@ -1,19 +1,10 @@
-include $(APPS)/Rules.elinux
+include $(AXIS_TOP_DIR)/tools/build/Rules.axis
 
 all:
 
 install:	src/bluetooth.c include/btcommon.h
 	ln -sfn ../../arch/cris/drivers/bluetooth/include ../../../../include/linux/bluetooth
-	if ! grep arch/cris/drivers/bluetooth/src/Config.in ../Config.in; then \
-	  echo '' >> ../Config.in; \
-	  echo '# The following if statement was added by arch/cris/drivers/bluetooth/Makefile' >> ../Config.in; \
-	  echo 'if [ "$$CONFIG_ETRAX_SERIAL" = "y" ]; then' >> ../Config.in; \
-	  echo '  source arch/cris/drivers/bluetooth/src/Config.in' >> ../Config.in; \
-	  echo 'fi' >> ../Config.in; \
-	fi
-	if ! grep bluetooth/src/bt.o ../Makefile; then \
-	  perl -pi -e "s:include:\# The following two lines were added by arch/cris/drivers/bluetooth/Makefile\nobj-\\\$$(CONFIG_BLUETOOTH)                 += bluetooth/src/bt.o\nsubdir-\\\$$(CONFIG_BLUETOOTH)              += bluetooth/src\n\ninclude:" ../Makefile; \
-	fi
+	(cd .. && patch -N -r /tmp/bt.rej < bluetooth/bt.patch >/dev/null || true)
 
 clean:
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/bluetooth/bt.patch linux-2.4.21-pre6/arch/cris/drivers/bluetooth/bt.patch
--- linux-2.4.20/arch/cris/drivers/bluetooth/bt.patch	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/cris/drivers/bluetooth/bt.patch	2003-03-26 23:49:05.000000000 +0000
@@ -0,0 +1,33 @@
+Index: Config.in
+===================================================================
+RCS file: /usr/local/cvs/linux/os/linux/arch/cris/drivers/Config.in,v
+retrieving revision 1.46
+diff -u -d -r1.46 Config.in
+--- Config.in	11 Oct 2002 16:14:33 -0000	1.46
++++ Config.in	31 Oct 2002 08:44:37 -0000
+@@ -317,3 +317,8 @@
+ fi
+ 
+ endmenu
++
++# The following if statement was added by arch/cris/drivers/bluetooth/Makefile
++if [ "$CONFIG_ETRAX_SERIAL" = "y" ]; then
++  source arch/cris/drivers/bluetooth/src/Config.in
++fi
+Index: Makefile
+===================================================================
+RCS file: /usr/local/cvs/linux/os/linux/arch/cris/drivers/Makefile,v
+retrieving revision 1.20
+diff -u -d -r1.20 Makefile
+--- Makefile	14 Aug 2002 18:32:33 -0000	1.20
++++ Makefile	31 Oct 2002 08:44:37 -0000
+@@ -24,5 +24,9 @@
+ obj-$(CONFIG_ETRAX_ETHERNET_LPSLAVE)    += lpslave/lpslavedrivers.o
+ subdir-$(CONFIG_ETRAX_ETHERNET_LPSLAVE) += lpslave
+ 
++# The following two lines were added by arch/cris/drivers/bluetooth/Makefile
++obj-$(CONFIG_BLUETOOTH)                 += bluetooth/src/bt.o
++subdir-$(CONFIG_BLUETOOTH)              += bluetooth/src
++
+ include $(TOPDIR)/Rules.make
+ 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/ds1302.c linux-2.4.21-pre6/arch/cris/drivers/ds1302.c
--- linux-2.4.20/arch/cris/drivers/ds1302.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/cris/drivers/ds1302.c	2003-03-26 23:49:54.000000000 +0000
@@ -7,6 +7,13 @@
 *! Functions exported: ds1302_readreg, ds1302_writereg, ds1302_init, get_rtc_status
 *!
 *! $Log: ds1302.c,v $
+*! Revision 1.15  2002/10/11 16:14:33  johana
+*! Added CONFIG_ETRAX_DS1302_TRICKLE_CHARGE and initial setting of the
+*! trcklecharge register.
+*!
+*! Revision 1.14  2002/10/10 12:15:38  magnusmn
+*! Added support for having the RST signal on bit g0
+*!
 *! Revision 1.13  2002/05/29 15:16:08  johana
 *! Removed unused variables.
 *!
@@ -88,7 +95,7 @@
 *!
 *! (C) Copyright 1999, 2000, 2001  Axis Communications AB, LUND, SWEDEN
 *!
-*! $Id: ds1302.c,v 1.13 2002/05/29 15:16:08 johana Exp $
+*! $Id: ds1302.c,v 1.15 2002/10/11 16:14:33 johana Exp $
 *!
 *!***************************************************************************/
 
@@ -493,17 +500,25 @@
 { 
 	if (!ds1302_probe()) {
 #ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT
+#if CONFIG_ETRAX_DS1302_RSTBIT == 27
 		/*
 		 * 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_MASK(R_GEN_CONFIG, ata)) | 
 				   (IO_STATE(R_GEN_CONFIG, ata, select)));    
     		*R_GEN_CONFIG = genconfig_shadow;
-    		if (!ds1302_probe())
+#elif CONFIG_ETRAX_DS1302_RSTBIT == 0
+		
+		/* Set the direction of this bit to out. */		
+    		genconfig_shadow = ((genconfig_shadow &
+				     ~IO_MASK(R_GEN_CONFIG, g0dir)) | 
+				   (IO_STATE(R_GEN_CONFIG, g0dir, out)));    
+    		*R_GEN_CONFIG = genconfig_shadow;
+#endif
+		if (!ds1302_probe())
       			return -1;
 #else
     		return -1;
@@ -515,5 +530,8 @@
 		       ds1302_name, RTC_MAJOR_NR);
 		return -1;
 	}
+	/* Initialise trickle charger */
+	ds1302_writereg(RTC_TRICKLECHARGER,
+			RTC_TCR_PATTERN |(CONFIG_ETRAX_DS1302_TRICKLE_CHARGE & 0x0F));
 	return 0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/eeprom.c linux-2.4.21-pre6/arch/cris/drivers/eeprom.c
--- linux-2.4.20/arch/cris/drivers/eeprom.c	2001-07-26 22:10:06.000000000 +0000
+++ linux-2.4.21-pre6/arch/cris/drivers/eeprom.c	2003-03-26 23:49:29.000000000 +0000
@@ -808,7 +808,7 @@
       i2c_outbyte( eeprom.select_cmd | 1 );
     }
 
-    if(i2c_getack());
+    if(i2c_getack())
     {
       break;
     }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/ethernet.c linux-2.4.21-pre6/arch/cris/drivers/ethernet.c
--- linux-2.4.20/arch/cris/drivers/ethernet.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/cris/drivers/ethernet.c	2003-03-26 23:49:35.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: ethernet.c,v 1.30 2002/05/07 18:50:08 johana Exp $
+/* $Id: ethernet.c,v 1.34 2002/12/13 07:17:44 starvik Exp $
  *
  * e100net.c: A network driver for the ETRAX 100LX network controller.
  *
@@ -7,6 +7,22 @@
  * The outline of this driver comes from skeleton.c.
  *
  * $Log: ethernet.c,v $
+ * Revision 1.34  2002/12/13 07:17:44  starvik
+ * Basic ethtool and MII ioctls
+ * Handle out of memory when allocating new buffers
+ *
+ * Revision 1.33  2002/10/02 20:16:17  hp
+ * SETF, SETS: Use underscored IO_x_ macros rather than incorrect token concatenation
+ *
+ * Revision 1.32  2002/09/16 06:05:58  starvik
+ * Align memory returned by dev_alloc_skb
+ * Moved handling of sent packets to interrupt to avoid reference counting problem
+ *
+ * Revision 1.31  2002/09/10 13:28:23  larsv
+ * Return -EINVAL for unknown ioctls to avoid confusing tools that tests
+ * for supported functionality by issuing special ioctls, i.e. wireless
+ * extensions.
+ *
  * Revision 1.30  2002/05/07 18:50:08  johana
  * Correct spelling in comments.
  *
@@ -152,9 +168,12 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 
+#include <linux/if.h>
+#include <linux/mii.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+#include <linux/ethtool.h>
 
 #include <asm/svinto.h>     /* DMA and register descriptions */
 #include <asm/io.h>         /* LED_* I/O functions */
@@ -163,6 +182,8 @@
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/ethernet.h>
+#include <asm/cache.h>
+#include <asm/uaccess.h>
 
 //#define ETHDEBUG
 #define D(x)
@@ -264,10 +285,10 @@
 #define GET_BIT(bit,val)   (((val) >> (bit)) & 0x01)
 
 /* Define some macros to access ETRAX 100 registers */
-#define SETF(var, reg, field, val) var = (var & ~IO_MASK(##reg##, field)) | \
-					  IO_FIELD(##reg##, field, val)
-#define SETS(var, reg, field, val) var = (var & ~IO_MASK(##reg##, field)) | \
-					  IO_STATE(##reg##, field, val)
+#define SETF(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \
+					  IO_FIELD_(reg##_, field##_, val)
+#define SETS(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \
+					  IO_STATE_(reg##_, field##_, _##val)
 
 static etrax_eth_descr *myNextRxDesc;  /* Points to the next descriptor to
                                           to be processed */
@@ -304,12 +325,12 @@
 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 e100rxtx_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void e100nw_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 int e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+static int e100_ethtool_ioctl(struct net_device* dev, struct ifreq *ifr);
 static void e100_tx_timeout(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);
@@ -324,6 +345,7 @@
 static void e100_negotiate(void);
 
 static unsigned short e100_get_mdio_reg(unsigned char reg_num);
+static void e100_set_mdio_reg(unsigned char reg, unsigned short data);
 static void e100_send_mdio_cmd(unsigned short cmd, int write_cmd);
 static void e100_send_mdio_bit(unsigned char bit);
 static unsigned char e100_receive_mdio_bit(void);
@@ -399,11 +421,14 @@
 	/* Initialise receive descriptors */
 
 	for (i = 0; i < NBR_OF_RX_DESC; i++) {
-		RxDescList[i].skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE);
+		/* Allocate two extra cachelines to make sure that buffer used by DMA
+		 * does not share cacheline with any other data (to avoid cache bug)
+		 */
+		RxDescList[i].skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE + 2 * L1_CACHE_BYTES);
 		RxDescList[i].descr.ctrl   = 0;
 		RxDescList[i].descr.sw_len = MAX_MEDIA_DATA_SIZE;
 		RxDescList[i].descr.next   = virt_to_phys(&RxDescList[i + 1]);
-		RxDescList[i].descr.buf    = virt_to_phys(RxDescList[i].skb->data);
+		RxDescList[i].descr.buf    = L1_CACHE_ALIGN(virt_to_phys(RxDescList[i].skb->data));
 		RxDescList[i].descr.status = 0;
 		RxDescList[i].descr.hw_len = 0;
              
@@ -540,14 +565,14 @@
 
 	/* allocate the irq corresponding to the receiving DMA */
 
-	if (request_irq(NETWORK_DMA_RX_IRQ_NBR, e100rx_interrupt, 0,
+	if (request_irq(NETWORK_DMA_RX_IRQ_NBR, e100rxtx_interrupt, 0,
 			cardname, (void *)dev)) {
 		goto grace_exit0;
 	}
 
 	/* allocate the irq corresponding to the transmitting DMA */
 
-	if (request_irq(NETWORK_DMA_TX_IRQ_NBR, e100tx_interrupt, 0,
+	if (request_irq(NETWORK_DMA_TX_IRQ_NBR, e100rxtx_interrupt, 0,
 			cardname, (void *)dev)) {
 		goto grace_exit1;
 	}
@@ -685,9 +710,7 @@
 static void
 e100_negotiate(void)
 {
-	unsigned short cmd;
 	unsigned short data = e100_get_mdio_reg(MDIO_ADVERTISMENT_REG);
-	int bitCounter;
 
 	/* Discard old speed and duplex settings */
 	data &= ~(MDIO_ADVERT_100_HD | MDIO_ADVERT_100_FD | 
@@ -726,29 +749,13 @@
 			        MDIO_ADVERT_10_FD | MDIO_ADVERT_10_HD;
 	}
 
-	cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (MDIO_PHYS_ADDR << 7) |
-	      (MDIO_ADVERTISMENT_REG<< 2);
-
-	e100_send_mdio_cmd(cmd, 1);
-
-	/* Data... */
-	for (bitCounter=15; bitCounter>=0 ; bitCounter--) {
-		e100_send_mdio_bit(GET_BIT(bitCounter, data));
-	}
+	e100_set_mdio_reg(MDIO_ADVERTISMENT_REG, data);
 
 	/* Renegotiate with link partner */
 	data = e100_get_mdio_reg(MDIO_BASE_CONTROL_REG);
 	data |= MDIO_BC_NEGOTIATE;
 
-	cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (MDIO_PHYS_ADDR << 7) |
-	      (MDIO_BASE_CONTROL_REG<< 2);
-
-	e100_send_mdio_cmd(cmd, 1);
-
-	/* Data... */
-	for (bitCounter=15; bitCounter>=0 ; bitCounter--) {
-		e100_send_mdio_bit(GET_BIT(bitCounter, data));
-	}  
+	e100_set_mdio_reg(MDIO_BASE_CONTROL_REG, data);
 }
 
 static void
@@ -816,6 +823,24 @@
 }
 
 static void
+e100_set_mdio_reg(unsigned char reg, unsigned short data)
+{
+	int bitCounter;
+	unsigned short cmd;
+
+	cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (MDIO_PHYS_ADDR << 7) |
+	      (reg << 2);
+
+	e100_send_mdio_cmd(cmd, 1);
+
+	/* Data... */
+	for (bitCounter=15; bitCounter>=0 ; bitCounter--) {
+		e100_send_mdio_bit(GET_BIT(bitCounter, data));
+	}
+
+}
+
+static void
 e100_send_mdio_cmd(unsigned short cmd, int write_cmd)
 {
 	int bitCounter;
@@ -958,21 +983,6 @@
 		*R_IRQ_MASK2_SET = IO_STATE(R_IRQ_MASK2_SET, dma0_eop, set);
 		netif_stop_queue(dev);
 	}
-	else {
-	  /* Report any packets that have been sent */
-		while (myFirstTxDesc != phys_to_virt(*R_DMA_CH0_FIRST) &&
-		       myFirstTxDesc != myNextTxDesc)
-		{
-			np->stats.tx_bytes += myFirstTxDesc->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(myFirstTxDesc->skb);
-			myFirstTxDesc->skb = 0;
-			myFirstTxDesc = phys_to_virt(myFirstTxDesc->descr.next);				
-		}
-	}
 
 	spin_unlock_irq(&np->lock);
 
@@ -985,11 +995,13 @@
  */
 
 static void
-e100rx_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+e100rxtx_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
 	struct net_device *dev = (struct net_device *)dev_id;
+	struct net_local *np = (struct net_local *)dev->priv;
 	unsigned long irqbits = *R_IRQ_MASK2_RD;
  
+	/* Handle received packets */
 	if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma1_eop, active)) {
 		/* acknowledge the eop interrupt */
 
@@ -1014,44 +1026,26 @@
 			   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
- */
+	/* Report any packets that have been sent */
+	while (myFirstTxDesc != phys_to_virt(*R_DMA_CH0_FIRST) &&
+	       myFirstTxDesc != myNextTxDesc)
+	{
+		np->stats.tx_bytes += myFirstTxDesc->skb->len;
+		np->stats.tx_packets++;
 
-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;
+		/* dma is ready with the transmission of the data in tx_skb, so now
+		   we can release the skb memory */
+		dev_kfree_skb_irq(myFirstTxDesc->skb);
+		myFirstTxDesc->skb = 0;
+		myFirstTxDesc = phys_to_virt(myFirstTxDesc->descr.next);
+	}
 
-	/* check for a dma0_eop interrupt */
 	if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma0_eop, active)) {
-		/* Report all sent packets */
-		do {
-			/* acknowledge the eop interrupt */
-			*R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do);
-
-			np->stats.tx_bytes += myFirstTxDesc->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(myFirstTxDesc->skb);
-			myFirstTxDesc->skb = 0;
-
-			if (netif_queue_stopped(dev)) {
-			  	/* Queue is running, disable tx IRQ */
-			  	*R_IRQ_MASK2_CLR = IO_STATE(R_IRQ_MASK2_CLR, dma0_eop, clr);		
-				netif_wake_queue(dev);
-			}
-			myFirstTxDesc = phys_to_virt(myFirstTxDesc->descr.next);
-		} while (myFirstTxDesc != phys_to_virt(*R_DMA_CH0_FIRST) &&
-		         myFirstTxDesc != myNextTxDesc);
+		/* acknowledge the eop interrupt and wake up queue */
+		*R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do);
+		*R_IRQ_MASK2_CLR = IO_STATE(R_IRQ_MASK2_CLR, dma0_eop, clr);		
+		netif_wake_queue(dev);
 	}
 }
 
@@ -1140,11 +1134,24 @@
 		memcpy(skb_data_ptr, phys_to_virt(myNextRxDesc->descr.buf), length);
 	}
 	else {
-		/* Large packet, send directly to upper layers and allocate new memory */		 
+		/* Large packet, send directly to upper layers and allocate new 
+		 * memory (aligned to cache line boundary to avoid bug).
+		 * Before sending the skb to upper layers we must make sure that 
+		 * skb->data points to the aligned start of the packet. 
+		 */
+		int align;  
+		struct sk_buff *new_skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE + 2 * L1_CACHE_BYTES);
+		if (!new_skb) {
+			np->stats.rx_errors++;
+			printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
+			return;
+		}
 		skb = myNextRxDesc->skb;
-		skb_put(skb, length);
-		myNextRxDesc->skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE);
-		myNextRxDesc->descr.buf = virt_to_phys(myNextRxDesc->skb->data);
+		align = (int)phys_to_virt(myNextRxDesc->descr.buf) - (int)skb->data;	
+		skb_put(skb, length + align); 
+		skb_pull(skb, align); /* Remove alignment bytes */
+		myNextRxDesc->skb = new_skb;
+		myNextRxDesc->descr.buf = L1_CACHE_ALIGN(virt_to_phys(myNextRxDesc->skb->data));
 	}
 
 	skb->dev = dev;
@@ -1220,8 +1227,22 @@
 static int
 e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
-	/* Maybe default should return -EINVAL instead? */
+	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data;
+
 	switch (cmd) {
+		case SIOCETHTOOL:
+			return e100_ethtool_ioctl(dev,ifr);
+		case SIOCGMIIPHY: /* Get PHY address */
+			data->phy_id = MDIO_PHYS_ADDR;
+			break;
+		case SIOCGMIIREG: /* Read MII register */
+			data->val_out = e100_get_mdio_reg(data->reg_num);
+			break;
+		case SIOCSMIIREG: /* Write MII register */
+			e100_set_mdio_reg(data->reg_num, data->val_in);
+			break;
+		/* The ioctls below should be considered obsolete but are */
+		/* still present for compatability with old scripts/apps  */	
 		case SET_ETH_SPEED_10:                  /* 10 Mbps */
 			e100_set_speed(10);
 			break;
@@ -1240,10 +1261,90 @@
 		case SET_ETH_DUPLEX_AUTO:             /* Autonegotiate duplex*/
 			e100_set_duplex(autoneg);
 			break;
-		default: /* Auto neg */
-			e100_set_speed(0);
-			e100_set_duplex(autoneg);
-			break;
+		default:
+			return -EINVAL;
+	}
+	return 0;
+}
+
+static int
+e100_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr)
+{
+	struct ethtool_cmd ecmd;
+
+	if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd)))
+		return -EFAULT;
+
+	switch (ecmd.cmd) {
+		case ETHTOOL_GSET:
+		{
+			memset((void *) &ecmd, 0, sizeof (ecmd));
+			ecmd.supported = 
+			  SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII |
+			  SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | 
+			  SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full;
+			ecmd.port = PORT_TP;
+			ecmd.transceiver = XCVR_EXTERNAL;
+			ecmd.phy_address = MDIO_PHYS_ADDR;
+			ecmd.speed = current_speed;
+			ecmd.duplex = full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
+			ecmd.advertising = ADVERTISED_TP;
+			if (current_duplex == autoneg && current_speed_selection == 0)
+				ecmd.advertising |= ADVERTISED_Autoneg;
+			else {
+				ecmd.advertising |= 
+				  ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
+				  ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full;
+				if (current_speed_selection == 10)
+					ecmd.advertising &= ~(ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full);
+				else if (current_speed_selection == 100)
+					ecmd.advertising &= ~(ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full);
+				if (current_duplex == half)
+					ecmd.advertising &= ~(ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Full);
+				else if (current_duplex == full)
+					ecmd.advertising &= ~(ADVERTISED_10baseT_Half | ADVERTISED_100baseT_Half);
+			}
+			ecmd.autoneg = AUTONEG_ENABLE;
+			if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd)))
+				return -EFAULT;
+		}
+		break;
+		case ETHTOOL_SSET:
+		{
+			if (!capable(CAP_NET_ADMIN)) {
+				return -EPERM;
+			}
+			if (ecmd.autoneg == AUTONEG_ENABLE) {
+				e100_set_duplex(autoneg);
+				e100_set_speed(0);
+			} else {
+				e100_set_duplex(ecmd.duplex == DUPLEX_HALF ? half : full);
+				e100_set_speed(ecmd.speed == SPEED_10 ? 10: 100);
+			}
+		}
+		break;
+		case ETHTOOL_GDRVINFO:
+		{
+			struct ethtool_drvinfo info;
+			memset((void *) &info, 0, sizeof (info));
+			strncpy(info.driver, "ETRAX 100LX", sizeof(info.driver) - 1);
+			strncpy(info.version, "$Rev$", sizeof(info.version) - 1);
+			strncpy(info.fw_version, "N/A", sizeof(info.fw_version) - 1);
+			strncpy(info.bus_info, "N/A", sizeof(info.bus_info) - 1);
+			info.regdump_len = 0;
+			info.eedump_len = 0;
+			info.testinfo_len = 0;
+			if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
+				return -EFAULT;
+		}
+		break;
+		case ETHTOOL_NWAY_RST:
+			if (current_duplex == autoneg && current_speed_selection == 0)
+				e100_negotiate();
+		break;
+		default:
+			return -EOPNOTSUPP;
+		break;
 	}
 	return 0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/gpio.c linux-2.4.21-pre6/arch/cris/drivers/gpio.c
--- linux-2.4.20/arch/cris/drivers/gpio.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/cris/drivers/gpio.c	2003-03-26 23:48:57.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: gpio.c,v 1.17 2002/06/17 15:53:01 johana Exp $
+/* $Id: gpio.c,v 1.21 2002/12/02 08:11:41 starvik Exp $
  *
  * Etrax general port I/O device
  *
@@ -9,6 +9,29 @@
  *             Johan Adolfsson  (read/set directions, write, port G)
  *
  * $Log: gpio.c,v $
+ * Revision 1.21  2002/12/02 08:11:41  starvik
+ * Merge of Linux 2.4.20
+ *
+ * Revision 1.20  2002/10/16 21:16:24  johana
+ * Added support for PA high level interrupt.
+ * That gives 2ms response time with iodtest for high levels and 2-12 ms
+ * response time on low levels if the check is not made in
+ * process.c:cpu_idle() as well.
+ *
+ * Revision 1.19  2002/10/14 18:27:33  johana
+ * Implemented alarm handling so select() now works.
+ * Latency is around 6-9 ms with a etrax_gpio_wake_up_check() in
+ * cpu_idle().
+ * Otherwise I get 15-18 ms (same as doing the poll in userspace -
+ * but less overhead).
+ * TODO? Perhaps we should add the check in IMMEDIATE_BH (or whatever it
+ * is in 2.4) as well?
+ * TODO? Perhaps call request_irq()/free_irq() only when needed?
+ * Increased version to 2.5
+ *
+ * Revision 1.18  2002/10/11 15:02:00  johana
+ * Mask inverted 8 bit value in setget_input().
+ *
  * Revision 1.17  2002/06/17 15:53:01  johana
  * Added IO_READ_INBITS, IO_READ_OUTBITS, IO_SETGET_INPUT and IO_SETGET_OUTPUT
  * that take a pointer as argument and thus can handle 32 bit ports (G)
@@ -95,11 +118,19 @@
 #include <asm/svinto.h>
 #include <asm/io.h>
 #include <asm/system.h>
+#include <asm/irq.h>
 
 #define GPIO_MAJOR 120  /* experimental MAJOR number */
 
 #define D(x)
 
+#if 0
+static int dp_cnt;
+#define DP(x) do { dp_cnt++; if (dp_cnt % 1000 == 0) x; }while(0)
+#else
+#define DP(x)
+#endif
+	
 static char gpio_name[] = "etrax gpio";
 
 #if 0
@@ -137,6 +168,8 @@
 
 static struct gpio_private *alarmlist = 0;
 
+static int gpio_some_alarms = 0; /* Set if someone uses alarm */
+
 /* Port A and B use 8 bit access, but Port G is 32 bit */
 #define NUM_PORTS (GPIO_MINOR_B+1)
 
@@ -197,21 +230,81 @@
 
 
 static unsigned int 
-gpio_poll(struct file *filp,
-	  struct poll_table_struct *wait)
+gpio_poll(struct file *file,
+	  poll_table *wait)
 {
-	/* TODO poll on alarms! */
-#if 0
-	if (!ANYTHING_WANTED) {
-		D(printk("gpio_select sleeping task\n"));
-		select_wait(&gpio_wq, table);
+	unsigned int mask = 0;
+	struct gpio_private *priv = (struct gpio_private *)file->private_data;
+	unsigned long data;
+	poll_wait(file, &priv->alarm_wq, wait);
+	if (priv->minor == GPIO_MINOR_A) {
+		unsigned long tmp;
+		data = *R_PORT_PA_DATA;
+		/* PA has support for high level interrupt -
+		 * lets activate for those low and with highalarm set
+		 */
+		tmp = ~data & priv->highalarm & 0xFF;
+		*R_IRQ_MASK1_SET = (tmp << R_IRQ_MASK1_SET__pa0__BITNR);
+	} else if (priv->minor == GPIO_MINOR_B)
+		data = *R_PORT_PB_DATA;
+	else if (priv->minor == GPIO_MINOR_G)
+		data = *R_PORT_G_DATA;
+	else
 		return 0;
+	
+	if ((data & priv->highalarm) ||
+	    (~data & priv->lowalarm)) {
+		mask = POLLIN|POLLRDNORM;
+	}
+	
+	DP(printk("gpio_poll ready: mask 0x%08X\n", mask));
+	return mask;
+}
+
+void etrax_gpio_wake_up_check(void)
+{
+	struct gpio_private *priv = alarmlist;
+	unsigned long data = 0;
+	while (priv) {
+		if (USE_PORTS(priv)) {
+			data = *priv->port;
+		} else if (priv->minor == GPIO_MINOR_G) {
+			data = *R_PORT_G_DATA;
+		}
+		if ((data & priv->highalarm) ||
+		    (~data & priv->lowalarm)) {
+			DP(printk("etrax_gpio_wake_up_check %i\n",priv->minor));
+			wake_up_interruptible(&priv->alarm_wq);
+		}
+		priv = priv->next;
+	}
+}
+
+static void 
+gpio_poll_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	if (gpio_some_alarms) {
+		etrax_gpio_wake_up_check();
+	}
+}
+
+static void 
+gpio_pa_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned long tmp;
+	/* Find what PA interrupts are active */
+	tmp = (*R_IRQ_READ1 >> R_IRQ_READ1__pa0__BITNR) & 0xFF;
+	/* Clear them.. */
+	/* NOTE: Maybe we need to be more careful here if some other
+	 * driver uses PA interrupt as well?
+	 */
+	*R_IRQ_MASK1_CLR = (tmp << R_IRQ_MASK1_CLR__pa0__BITNR);
+	if (gpio_some_alarms) {
+		etrax_gpio_wake_up_check();
 	}
-	D(printk("gpio_select ready\n"));
-#endif
-	return 1;
 }
 
+
 static ssize_t gpio_write(struct file * file, const char * buf, size_t count,
                           loff_t *off)
 {
@@ -322,7 +415,7 @@
 {
 	struct gpio_private *p = alarmlist;
 	struct gpio_private *todel = (struct gpio_private *)filp->private_data;
-
+	
 	/* unlink from alarmlist and free the private structure */
 
 	if (p == todel) {
@@ -334,7 +427,17 @@
 	}
 
 	kfree(todel);
-
+	/* Check if there are still any alarms set */
+	p = alarmlist;
+	while (p) {
+		if (p->highalarm | p->lowalarm) {
+			gpio_some_alarms = 1;
+			return 0;
+		}
+		p = p->next;
+	}
+	gpio_some_alarms = 0;
+		
 	return 0;
 }
 
@@ -353,7 +456,7 @@
 		*priv->dir = *priv->dir_shadow &= 
 		~((unsigned char)arg & priv->changeable_dir);
 		restore_flags(flags);
-		return ~(*priv->dir_shadow);
+		return ~(*priv->dir_shadow) & 0xFF; /* Only 8 bits */
 	} else if (priv->minor == GPIO_MINOR_G) {
 		/* We must fiddle with R_GEN_CONFIG to change dir */
 		if (((arg & dir_g_in_bits) != arg) && 
@@ -491,10 +594,12 @@
 	case IO_HIGHALARM:
 		// set alarm when bits with 1 in arg go high
 		priv->highalarm |= arg;
+		gpio_some_alarms = 1;
 		break;
 	case IO_LOWALARM:
 		// set alarm when bits with 1 in arg go low
 		priv->lowalarm |= arg;
+		gpio_some_alarms = 1;
 		break;
 	case IO_CLRALARM:
 		// clear alarm for bits with 1 in arg
@@ -760,8 +865,21 @@
 
 #endif
 	gpio_init_port_g();
-	printk("ETRAX 100LX GPIO driver v2.4, (c) 2001, 2002 Axis Communications AB\n");
-
+	printk("ETRAX 100LX GPIO driver v2.5, (c) 2001, 2002 Axis Communications AB\n");
+	/* We call etrax_gpio_wake_up_check() from timer interrupt and
+	 * from cpu_idle() in kernel/process.c
+	 * The check in cpu_idle() reduces latency from ~15 ms to ~6 ms
+	 * in some tests.
+	 */  
+	if (request_irq(TIMER0_IRQ_NBR, gpio_poll_timer_interrupt,
+			SA_SHIRQ | SA_INTERRUPT,"gpio poll", NULL)) {
+		printk("err: timer0 irq for gpio\n");
+	}
+	if (request_irq(PA_IRQ_NBR, gpio_pa_interrupt,
+			SA_SHIRQ | SA_INTERRUPT,"gpio PA", NULL)) {
+		printk("err: PA irq for gpio\n");
+	}
+	
 	return res;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/i2c.c linux-2.4.21-pre6/arch/cris/drivers/i2c.c
--- linux-2.4.20/arch/cris/drivers/i2c.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/cris/drivers/i2c.c	2003-03-26 23:49:00.000000000 +0000
@@ -12,6 +12,12 @@
 *!                                 don't use PB_I2C if DS1302 uses same bits,
 *!                                 use PB.
 *! $Log: i2c.c,v $
+*! Revision 1.9  2002/10/31 15:32:26  starvik
+*! Update Port B register and shadow even when running with hardware support
+*!   to avoid glitches when reading bits
+*! Never set direction to out in i2c_inbyte
+*! Removed incorrect clock togling at end of i2c_inbyte
+*!
 *! Revision 1.8  2002/08/13 06:31:53  starvik
 *! Made SDA and SCL line configurable
 *! Modified i2c_inbyte to work with PCF8563
@@ -47,7 +53,7 @@
 *! (C) Copyright 1999-2002 Axis Communications AB, LUND, SWEDEN
 *!
 *!***************************************************************************/
-/* $Id: i2c.c,v 1.8 2002/08/13 06:31:53 starvik Exp $ */
+/* $Id: i2c.c,v 1.9 2002/10/31 15:32:26 starvik Exp $ */
 /****************** INCLUDE FILES SECTION ***********************************/
 
 #include <linux/module.h>
@@ -135,16 +141,24 @@
 
 /* enable or disable output-enable, to select output or input on the i2c bus */
 
-#define i2c_dir_out() *R_PORT_PB_I2C = (port_pb_i2c_shadow &= ~IO_MASK(R_PORT_PB_I2C, i2c_oe_))
-#define i2c_dir_in() *R_PORT_PB_I2C = (port_pb_i2c_shadow |= IO_MASK(R_PORT_PB_I2C, i2c_oe_))
+#define i2c_dir_out() \
+	*R_PORT_PB_I2C = (port_pb_i2c_shadow &= ~IO_MASK(R_PORT_PB_I2C, i2c_oe_)); \
+	REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, 0, 1); 
+#define i2c_dir_in() \
+	*R_PORT_PB_I2C = (port_pb_i2c_shadow |= IO_MASK(R_PORT_PB_I2C, i2c_oe_)); \
+	REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, 0, 0);
 
 /* control the i2c clock and data signals */
 
-#define i2c_clk(x) *R_PORT_PB_I2C = (port_pb_i2c_shadow = (port_pb_i2c_shadow & \
-       ~IO_MASK(R_PORT_PB_I2C, i2c_clk)) | IO_FIELD(R_PORT_PB_I2C, i2c_clk, (x)))
+#define i2c_clk(x) \
+	*R_PORT_PB_I2C = (port_pb_i2c_shadow = (port_pb_i2c_shadow & \
+       ~IO_MASK(R_PORT_PB_I2C, i2c_clk)) | IO_FIELD(R_PORT_PB_I2C, i2c_clk, (x))); \
+       REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, 1, x);
 
-#define i2c_data(x) *R_PORT_PB_I2C = (port_pb_i2c_shadow = (port_pb_i2c_shadow & \
-       ~IO_MASK(R_PORT_PB_I2C, i2c_d)) | IO_FIELD(R_PORT_PB_I2C, i2c_d, (x)))
+#define i2c_data(x) \
+	*R_PORT_PB_I2C = (port_pb_i2c_shadow = (port_pb_i2c_shadow & \
+	   ~IO_MASK(R_PORT_PB_I2C, i2c_d)) | IO_FIELD(R_PORT_PB_I2C, i2c_d, (x))); \
+	REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, 0, x);
 
 /* read a bit from the i2c interface */
 
@@ -221,10 +235,11 @@
 	i2c_dir_out();
 
 	for (i = 0; i < 8; i++) {
-		if (x & 0x80)
+		if (x & 0x80) {
 			i2c_data(I2C_DATA_HIGH);
-		else
+		} else {
 			i2c_data(I2C_DATA_LOW);
+		}
 		
 		i2c_delay(CLOCK_LOW_TIME/2);
 		i2c_clk(I2C_CLOCK_HIGH);
@@ -260,7 +275,6 @@
 
 	/* Enable I2C */
 	i2c_enable();
-	i2c_dir_out();
 	i2c_delay(CLOCK_LOW_TIME/2);
 
 	for (i = 1; i < 8; i++) {
@@ -281,12 +295,10 @@
 
 		/* Enable I2C */
 		i2c_enable();
-		i2c_dir_out();
 		i2c_delay(CLOCK_LOW_TIME/2);
 	}
 	i2c_clk(I2C_CLOCK_HIGH);
 	i2c_delay(CLOCK_HIGH_TIME);
-	i2c_clk(I2C_CLOCK_LOW);
 	return aBitByte;
 }
 
@@ -416,7 +428,7 @@
 {
 	int error, cntr = 3;
 	unsigned long flags;
-		
+
 	do {
 		error = 0;
 		/*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/ide.c linux-2.4.21-pre6/arch/cris/drivers/ide.c
--- linux-2.4.20/arch/cris/drivers/ide.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/cris/drivers/ide.c	2003-03-26 23:49:18.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: ide.c,v 1.24 2002/04/22 11:47:21 johana Exp $
+/* $Id: ide.c,v 1.26 2002/09/17 12:16:59 bjornw 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,12 @@
  *             Mikael Starvik     (pio setup stuff)
  *
  * $Log: ide.c,v $
+ * Revision 1.26  2002/09/17 12:16:59  bjornw
+ * Removed unnecessary cli/sti pair
+ *
+ * Revision 1.25  2002/08/19 08:07:19  matsfg
+ * Added IN_WORD.
+ *
  * Revision 1.24  2002/04/22 11:47:21  johana
  * Fix according to 2.4.19-pre7. time_after/time_before and
  * missing end of comment.
@@ -180,9 +186,14 @@
 			    IO_MASK(R_ATA_STATUS_DATA, tr_rdy)))
 		timeleft--;
 }
-
 unsigned char 
 IN_BYTE(ide_ioreg_t reg) {
+        /* data was in the lower 16 bits in the status reg */
+        return (unsigned char)(IN_WORD(reg));
+}
+
+unsigned short 
+IN_WORD(ide_ioreg_t reg) {
 	int status;
 	int timeleft;
 
@@ -226,7 +237,7 @@
 
 	LOWDB(printk("inb: 0x%x from reg 0x%x\n", status & 0xff, reg));
 
-	return (unsigned char)status; /* data was in the lower 16 bits in the status reg */
+        return (unsigned short)status;
 }
 
 /* PIO timing (in R_ATA_CONFIG)
@@ -303,9 +314,6 @@
 	pio = 4;
 	/* pio = ide_get_best_pio_mode(drive, pio, 4, NULL); */
 	
-	save_flags(flags);
-	cli();
-
 	/* set pio mode! */
   	 
 	switch(pio) {
@@ -350,7 +358,6 @@
 					  IO_FIELD( R_ATA_CONFIG, pio_hold,   ATA_PIO4_HOLD ) );
 			break;
 	}
-	restore_flags(flags);
 }
 
 void __init 
@@ -816,13 +823,13 @@
 			rq = HWGROUP(drive)->rq;
 			for (i = rq->nr_sectors; i > 0;) {
 				i -= rq->current_nr_sectors;
-				ide_end_request(1, HWGROUP(drive));
+				DRIVER(drive)->end_request(drive, 1);
 			}
 			return ide_stopped;
 		}
 		printk("%s: bad DMA status\n", drive->name);
 	}
-	return ide_error(drive, "dma_intr", stat);
+	return DRIVER(drive)->error(drive, "dma_intr", stat);
 }
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/parport.c linux-2.4.21-pre6/arch/cris/drivers/parport.c
--- linux-2.4.20/arch/cris/drivers/parport.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/cris/drivers/parport.c	2003-03-26 23:48:59.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: parport.c,v 1.9 2002/05/15 12:30:24 starvik Exp $
+/* $Id: parport.c,v 1.10 2002/10/03 05:54:24 starvik Exp $
  * 
  * Elinux parallel port driver
  * NOTE!
@@ -56,11 +56,11 @@
 //#define CONFIG_PAR0_INT 1
 //#define CONFIG_PAR1_INT 1
 
-#define SETF(var, reg, field, val) \
-	var = (var & ~IO_MASK(##reg##, field)) | IO_FIELD(##reg##, field, val)
-
-#define SETS(var, reg, field, val) \
-	var = (var & ~IO_MASK(##reg##, field)) | IO_STATE(##reg##, field, val)
+/* Define some macros to access ETRAX 100 registers */
+#define SETF(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \
+					  IO_FIELD_(reg##_, field##_, val)
+#define SETS(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \
+					  IO_STATE_(reg##_, field##_, _##val)
 
 struct etrax100par_struct {
 	/* parallell port control */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/pcf8563.c linux-2.4.21-pre6/arch/cris/drivers/pcf8563.c
--- linux-2.4.20/arch/cris/drivers/pcf8563.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/cris/drivers/pcf8563.c	2003-03-26 23:49:39.000000000 +0000
@@ -15,7 +15,7 @@
  *
  * Author: Tobias Anderberg <tobiasa@axis.com>.
  *
- * $Id: pcf8563.c,v 1.1 2002/08/12 13:46:02 starvik Exp $
+ * $Id: pcf8563.c,v 1.4 2002/10/15 09:22:42 tobiasa Exp $
  */
 
 #include <linux/config.h>
@@ -39,7 +39,11 @@
 #define PCF8563_MAJOR 121		/* Local major number. */
 #define DEVICE_NAME "rtc"		/* Name which is registered in /proc/devices. */
 #define PCF8563_NAME "PCF8563"
-#define DRIVER_VERSION "$Rev$"
+#define DRIVER_VERSION "$Revision: 1.4 $"
+
+/* I2C bus slave registers. */
+#define RTC_I2C_READ		0xa3
+#define RTC_I2C_WRITE		0xa2
 
 /* Two simple wrapper macros, saves a few keystrokes. */
 #define rtc_read(x) i2c_readreg(RTC_I2C_READ, x)
@@ -59,11 +63,38 @@
 	release: pcf8563_release,
 };
 
+unsigned char
+pcf8563_readreg(int reg) 
+{
+	unsigned char res = i2c_readreg(RTC_I2C_READ, reg);
+
+	/* The PCF8563 does not return 0 for unimplemented bits */
+	switch(reg)
+	{
+		case RTC_SECONDS:
+		case RTC_MINUTES:
+		     res &= 0x7f;
+		     break;
+		case RTC_HOURS:
+		case RTC_DAY_OF_MONTH:
+		     res &= 0x3f;
+		     break;
+		case RTC_MONTH:
+		     res = (res & 0x1f) - 1;  /* PCF8563 returns month in range 1-12 */
+		     break;
+	}
+	return res;
+}
+
+void
+pcf8563_writereg(int reg, unsigned char val) 
+{
+	i2c_writereg(RTC_I2C_WRITE,reg,val);
+}
+
 void
 get_rtc_time(struct rtc_time *tm)
 {
-	unsigned long flags;
-	
 	tm->tm_sec = rtc_read(RTC_SECONDS);
 	tm->tm_min = rtc_read(RTC_MINUTES);
 	tm->tm_hour = rtc_read(RTC_HOURS);
@@ -74,7 +105,7 @@
 	if (tm->tm_sec & 0x80)
 		printk(KERN_WARNING "%s: RTC Low Voltage - date/time is not reliable!\n", PCF8563_NAME);
 
-        tm->tm_year = BCD_TO_BIN(tm->tm_year) + ((tm->tm_mon & 0x80) ? 100 : 0);
+	tm->tm_year = BCD_TO_BIN(tm->tm_year) + ((tm->tm_mon & 0x80) ? 100 : 0);
 	tm->tm_sec &= 0x7f;
 	tm->tm_min &= 0x7f;
 	tm->tm_hour &= 0x3f;
@@ -93,8 +124,6 @@
 pcf8563_init(void)
 {
 	unsigned char ret;
-        struct rtc_time tm;
-        
 	/*
 	 * First of all we need to reset the chip. This is done by
 	 * clearing control1, control2 and clk freq, clear the 
@@ -134,7 +163,7 @@
 		return -1;
 	}
 
-	printk(KERN_INFO "%s Real-Time Driver, %s\n", PCF8563_NAME, DRIVER_VERSION);
+	printk(KERN_INFO "%s Real-Time Clock Driver, %s\n", PCF8563_NAME, DRIVER_VERSION);
         
 	/* Check for low voltage, and warn about it.. */
 	if (rtc_read(RTC_SECONDS) & 0x80)
@@ -163,7 +192,7 @@
 pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
 {
 	/* Some sanity checks. */
-	if (_IOC_TYPE(cmd) != PCF8563_MAGIC)
+	if (_IOC_TYPE(cmd) != RTC_MAGIC)
 		return -ENOTTY;
 
 	if (_IOC_NR(cmd) > RTC_MAX_IOCTL)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/serial.c linux-2.4.21-pre6/arch/cris/drivers/serial.c
--- linux-2.4.20/arch/cris/drivers/serial.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/cris/drivers/serial.c	2003-03-26 23:49:07.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: serial.c,v 1.37 2002/08/13 13:02:37 bjornw Exp $
+/* $Id: serial.c,v 1.44 2002/11/21 04:28:06 hp Exp $
  *
  * Serial port driver for the ETRAX 100LX chip
  *
@@ -7,6 +7,42 @@
  *      Many, many authors. Based once upon a time on serial.c for 16x50.
  *
  * $Log: serial.c,v $
+ * Revision 1.44  2002/11/21 04:28:06  hp
+ * Change static inline to extern inline where otherwise outlined with gcc-3.2
+ *
+ * Revision 1.43  2002/11/15 12:02:25  pkj
+ * Make sure we have a tty in flush_to_flip_buffer() before we
+ * try to use it...
+ *
+ * Revision 1.42  2002/11/05 09:08:47  johana
+ * Better implementation of rs_stop() and rs_start() that uses the XOFF
+ * register to start/stop transmission.
+ * change_speed() also initilises XOFF register correctly so that
+ * auto_xoff is enabled when IXON flag is set by user.
+ * This gives fast XOFF response times.
+ *
+ * Revision 1.41  2002/11/04 18:40:57  johana
+ * Implemented rs_stop() and rs_start().
+ * Simple tests using hwtestserial indicates that this should be enough
+ * to make it work.
+ *
+ * Revision 1.40  2002/10/14 05:33:18  starvik
+ * RS-485 uses fast timers even if SERIAL_FAST_TIMER is disabled
+ *
+ * Revision 1.39  2002/09/30 21:00:57  johana
+ * Support for CONFIG_ETRAX_SERx_DTR_RI_DSR_CD_MIXED where the status and
+ * control pins can be mixed between PA and PB.
+ * If no serial port uses MIXED old solution is used
+ * (saves a few bytes and cycles).
+ * control_pins struct uses masks instead of bit numbers.
+ * Corrected dummy values and polarity in line_info() so
+ * /proc/tty/driver/serial is now correct.
+ * (the E100_xxx_GET() macros is really active low - perhaps not obvious)
+ *
+ * Revision 1.38  2002/08/23 11:01:36  starvik
+ * Check that serial port is enabled in all interrupt handlers to avoid
+ * restarts of DMA channels not assigned to serial ports
+ *
  * Revision 1.37  2002/08/13 13:02:37  bjornw
  * Removed some warnings because of unused code
  *
@@ -321,7 +357,7 @@
  *
  */
 
-static char *serial_version = "$Revision: 1.37 $";
+static char *serial_version = "$Revision: 1.44 $";
 
 #include <linux/config.h>
 #include <linux/version.h>
@@ -429,7 +465,7 @@
 static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
 static int rs_write(struct tty_struct * tty, int from_user,
                     const unsigned char *buf, int count);
-static inline int raw_write(struct tty_struct * tty, int from_user,
+extern inline int raw_write(struct tty_struct * tty, int from_user,
                             const unsigned char *buf, int count);
 #ifdef CONFIG_ETRAX_RS485
 static int e100_write_rs485(struct tty_struct * tty, int from_user,
@@ -585,87 +621,214 @@
 static int rs485_pa_bit = CONFIG_ETRAX_RS485_ON_PA_BIT;
 #endif
 #endif
-  
 
-/* For now we assume that all bits are on the same port for each serial port */
+/* Info and macros needed for each ports extra control/status signals. */
+#define E100_STRUCT_PORT(line, pinname) \
+ ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \
+		(R_PORT_PA_DATA): ( \
+ (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \
+		(R_PORT_PB_DATA):&dummy_ser[##line##]))
+
+#define E100_STRUCT_SHADOW(line, pinname) \
+ ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \
+		(&port_pa_data_shadow): ( \
+ (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \
+		(&port_pb_data_shadow):&dummy_ser[line]))
+#define E100_STRUCT_MASK(line, pinname) \
+ ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \
+		(1<<CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT): ( \
+ (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \
+		(1<<CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT):DUMMY_##pinname##_MASK))
+
+#define DUMMY_DTR_MASK 1
+#define DUMMY_RI_MASK  2
+#define DUMMY_DSR_MASK 4
+#define DUMMY_CD_MASK  8
+static unsigned char dummy_ser[NR_PORTS] = {0xFF, 0xFF, 0xFF,0xFF};
+
+#if defined(CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED) || \
+    defined(CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED) || \
+    defined(CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED) || \
+    defined(CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED)
+#define CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED
+#endif
+
+#ifdef CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED
+/* The pins can be mixed on PA and PB */
+#define CONTROL_PINS_PORT_NOT_USED(line) \
+  &dummy_ser[line], &dummy_ser[line], \
+  &dummy_ser[line], &dummy_ser[line], \
+  &dummy_ser[line], &dummy_ser[line], \
+  &dummy_ser[line], &dummy_ser[line], \
+  DUMMY_DTR_MASK, DUMMY_RI_MASK, DUMMY_DSR_MASK, DUMMY_CD_MASK
+    
 
-/* Dummy shadow variables */
-#if !defined(CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB)
-static unsigned char dummy_ser0 = 0x00;
-static unsigned char dummy_dir_ser0 = 0x00;
-#endif
-#if !defined(CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB)
-static unsigned char dummy_ser1 = 0x00;
-static unsigned char dummy_dir_ser1 = 0x00;
-#endif
-#if !defined(CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA)
-static unsigned char dummy_ser2 = 0x00;
-static unsigned char dummy_dir_ser2 = 0x00;
-#endif
+struct control_pins
+{
+	volatile unsigned char *dtr_port;
+	unsigned char          *dtr_shadow;
+	volatile unsigned char *ri_port;
+	unsigned char          *ri_shadow;
+	volatile unsigned char *dsr_port;
+	unsigned char          *dsr_shadow;
+	volatile unsigned char *cd_port;
+	unsigned char          *cd_shadow;
+
+	unsigned char dtr_mask;
+	unsigned char ri_mask;
+	unsigned char dsr_mask;
+	unsigned char cd_mask;
+};
+
+static const struct control_pins e100_modem_pins[NR_PORTS] = 
+{
+	/* Ser 0 */
+	{
+#ifdef CONFIG_ETRAX_SERIAL_PORT0
+	E100_STRUCT_PORT(0,DTR), E100_STRUCT_SHADOW(0,DTR),
+	E100_STRUCT_PORT(0,RI),  E100_STRUCT_SHADOW(0,RI),
+	E100_STRUCT_PORT(0,DSR), E100_STRUCT_SHADOW(0,DSR),
+	E100_STRUCT_PORT(0,CD),  E100_STRUCT_SHADOW(0,CD),
+	E100_STRUCT_MASK(0,DTR),
+	E100_STRUCT_MASK(0,RI),
+	E100_STRUCT_MASK(0,DSR),
+	E100_STRUCT_MASK(0,CD)
+#else
+	CONTROL_PINS_PORT_NOT_USED(0)
+#endif	
+	},
+
+	/* Ser 1 */
+	{
+#ifdef CONFIG_ETRAX_SERIAL_PORT1	  
+	E100_STRUCT_PORT(1,DTR), E100_STRUCT_SHADOW(1,DTR),
+	E100_STRUCT_PORT(1,RI),  E100_STRUCT_SHADOW(1,RI),
+	E100_STRUCT_PORT(1,DSR), E100_STRUCT_SHADOW(1,DSR),
+	E100_STRUCT_PORT(1,CD),  E100_STRUCT_SHADOW(1,CD),
+	E100_STRUCT_MASK(1,DTR),
+	E100_STRUCT_MASK(1,RI),
+	E100_STRUCT_MASK(1,DSR),
+	E100_STRUCT_MASK(1,CD)
+#else
+	CONTROL_PINS_PORT_NOT_USED(1)
+#endif		
+	},
 
-static unsigned char dummy_ser3 = 0x00;
-static unsigned char dummy_dir_ser3 = 0x00;
+	/* Ser 2 */
+	{
+#ifdef CONFIG_ETRAX_SERIAL_PORT2	  
+	E100_STRUCT_PORT(2,DTR), E100_STRUCT_SHADOW(2,DTR),
+	E100_STRUCT_PORT(2,RI),  E100_STRUCT_SHADOW(2,RI),
+	E100_STRUCT_PORT(2,DSR), E100_STRUCT_SHADOW(2,DSR),
+	E100_STRUCT_PORT(2,CD),  E100_STRUCT_SHADOW(2,CD),
+	E100_STRUCT_MASK(2,DTR),
+	E100_STRUCT_MASK(2,RI),
+	E100_STRUCT_MASK(2,DSR),
+	E100_STRUCT_MASK(2,CD)
+#else
+	CONTROL_PINS_PORT_NOT_USED(2)
+#endif		
+	},
+
+	/* Ser 3 */
+	{
+#ifdef CONFIG_ETRAX_SERIAL_PORT3	  
+	E100_STRUCT_PORT(3,DTR), E100_STRUCT_SHADOW(3,DTR),
+	E100_STRUCT_PORT(3,RI),  E100_STRUCT_SHADOW(3,RI),
+	E100_STRUCT_PORT(3,DSR), E100_STRUCT_SHADOW(3,DSR),
+	E100_STRUCT_PORT(3,CD),  E100_STRUCT_SHADOW(3,CD),
+	E100_STRUCT_MASK(3,DTR),
+	E100_STRUCT_MASK(3,RI),
+	E100_STRUCT_MASK(3,DSR),
+	E100_STRUCT_MASK(3,CD)
+#else
+	CONTROL_PINS_PORT_NOT_USED(3)
+#endif		
+	}
+};
+#else  /* CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED */
+
+/* All pins are on either PA or PB for each serial port */
+#define CONTROL_PINS_PORT_NOT_USED(line) \
+  &dummy_ser[line], &dummy_ser[line], \
+  DUMMY_DTR_MASK, DUMMY_RI_MASK, DUMMY_DSR_MASK, DUMMY_CD_MASK
+    
 
-/* Info needed for each ports extra control/status signals.
-   We only supports that all pins uses same register for each port */
 struct control_pins
 {
 	volatile unsigned char *port;
-	volatile unsigned char *shadow;
-	volatile unsigned char *dir_shadow;
+	unsigned char          *shadow;
 
-	unsigned char dtr_bit;
-	unsigned char ri_bit;
-	unsigned char dsr_bit;
-	unsigned char cd_bit;
+	unsigned char dtr_mask;
+	unsigned char ri_mask;
+	unsigned char dsr_mask;
+	unsigned char cd_mask;
 };
 
+#define dtr_port port
+#define dtr_shadow shadow
+#define ri_port port
+#define ri_shadow shadow
+#define dsr_port port
+#define dsr_shadow shadow
+#define cd_port port
+#define cd_shadow shadow
+
 static const struct control_pins e100_modem_pins[NR_PORTS] = 
 {
 	/* Ser 0 */
 	{
-#if defined(CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB)
-		R_PORT_PB_DATA, &port_pb_data_shadow, &port_pb_dir_shadow,
-		CONFIG_ETRAX_SER0_DTR_ON_PB_BIT,
-		CONFIG_ETRAX_SER0_RI_ON_PB_BIT,
-		CONFIG_ETRAX_SER0_DSR_ON_PB_BIT,
-		CONFIG_ETRAX_SER0_CD_ON_PB_BIT
+#ifdef CONFIG_ETRAX_SERIAL_PORT0
+	E100_STRUCT_PORT(0,DTR), E100_STRUCT_SHADOW(0,DTR),
+	E100_STRUCT_MASK(0,DTR),
+	E100_STRUCT_MASK(0,RI),
+	E100_STRUCT_MASK(0,DSR),
+	E100_STRUCT_MASK(0,CD)
 #else
-		&dummy_ser0, &dummy_ser0, &dummy_dir_ser0, 0, 1, 2, 3
-#endif
+	CONTROL_PINS_PORT_NOT_USED(0)
+#endif	
 	},
 
 	/* Ser 1 */
 	{
-#if defined(CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB)
-		R_PORT_PB_DATA, &port_pb_data_shadow, &port_pb_dir_shadow,
-		CONFIG_ETRAX_SER1_DTR_ON_PB_BIT,
-		CONFIG_ETRAX_SER1_RI_ON_PB_BIT,
-		CONFIG_ETRAX_SER1_DSR_ON_PB_BIT,
-		CONFIG_ETRAX_SER1_CD_ON_PB_BIT
+#ifdef CONFIG_ETRAX_SERIAL_PORT1	  
+	E100_STRUCT_PORT(1,DTR), E100_STRUCT_SHADOW(1,DTR),
+	E100_STRUCT_MASK(1,DTR),
+	E100_STRUCT_MASK(1,RI),
+	E100_STRUCT_MASK(1,DSR),
+	E100_STRUCT_MASK(1,CD)
 #else
-		&dummy_ser1, &dummy_ser1, &dummy_dir_ser1, 0, 1, 2, 3
-#endif
+	CONTROL_PINS_PORT_NOT_USED(1)
+#endif		
 	},
 
 	/* Ser 2 */
 	{
-#if defined(CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA)
-		R_PORT_PA_DATA, &port_pa_data_shadow, &port_pa_dir_shadow,
-		CONFIG_ETRAX_SER2_DTR_ON_PA_BIT,
-		CONFIG_ETRAX_SER2_RI_ON_PA_BIT,
-		CONFIG_ETRAX_SER2_DSR_ON_PA_BIT,
-		CONFIG_ETRAX_SER2_CD_ON_PA_BIT
+#ifdef CONFIG_ETRAX_SERIAL_PORT2	  
+	E100_STRUCT_PORT(2,DTR), E100_STRUCT_SHADOW(2,DTR),
+	E100_STRUCT_MASK(2,DTR),
+	E100_STRUCT_MASK(2,RI),
+	E100_STRUCT_MASK(2,DSR),
+	E100_STRUCT_MASK(2,CD)
 #else
-		&dummy_ser2, &dummy_ser2, &dummy_dir_ser2, 0, 1, 2, 3
-#endif
+	CONTROL_PINS_PORT_NOT_USED(2)
+#endif		
 	},
 
 	/* Ser 3 */
 	{
-		&dummy_ser3, &dummy_ser3, &dummy_dir_ser3, 0, 1, 2, 3
+#ifdef CONFIG_ETRAX_SERIAL_PORT3	  
+	E100_STRUCT_PORT(3,DTR), E100_STRUCT_SHADOW(3,DTR),
+	E100_STRUCT_MASK(3,DTR),
+	E100_STRUCT_MASK(3,RI),
+	E100_STRUCT_MASK(3,DSR),
+	E100_STRUCT_MASK(3,CD)
+#else
+	CONTROL_PINS_PORT_NOT_USED(3)
+#endif		
 	}
 };
+#endif /* !CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED */
 
 #if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_RS485_ON_PA)
 unsigned char rs485_pa_port = CONFIG_ETRAX_RS485_ON_PA_BIT;
@@ -690,20 +853,16 @@
 
 /* These are typically PA or PB and 0 means 0V, 1 means 3.3V */
 /* Is an output */
-#define E100_DTR_GET(info) ((*e100_modem_pins[(info)->line].shadow) & (1 << e100_modem_pins[(info)->line].dtr_bit))
+#define E100_DTR_GET(info) ((*e100_modem_pins[(info)->line].dtr_shadow) & e100_modem_pins[(info)->line].dtr_mask)
 
 /* Normally inputs */
-#define E100_RI_GET(info) ((*e100_modem_pins[(info)->line].port) & (1 << e100_modem_pins[(info)->line].ri_bit))
-#define E100_CD_GET(info) ((*e100_modem_pins[(info)->line].port) & (1 << e100_modem_pins[(info)->line].cd_bit))
+#define E100_RI_GET(info) ((*e100_modem_pins[(info)->line].ri_port) & e100_modem_pins[(info)->line].ri_mask)
+#define E100_CD_GET(info) ((*e100_modem_pins[(info)->line].cd_port) & e100_modem_pins[(info)->line].cd_mask)
 
 /* Input */
-#define E100_DSR_GET(info) ((*e100_modem_pins[(info)->line].port) & (1 << e100_modem_pins[(info)->line].dsr_bit))
+#define E100_DSR_GET(info) ((*e100_modem_pins[(info)->line].dsr_port) & e100_modem_pins[(info)->line].dsr_mask)
 
 
-#ifndef MIN
-#define MIN(a,b)	((a) < (b) ? (a) : (b))
-#endif
-
 /*
  * tmp_buf is used as a temporary buffer by serial_write.  We need to
  * lock it in case the memcpy_fromfs blocks while swapping in a page,
@@ -837,16 +996,17 @@
  * any general port.
  */
 
+
 static inline void 
 e100_dtr(struct e100_serial *info, int set)
 {
 #ifndef CONFIG_SVINTO_SIM
-	unsigned char mask = (1 << e100_modem_pins[info->line].dtr_bit);
+	unsigned char mask = e100_modem_pins[info->line].dtr_mask;
 
 #ifdef SERIAL_DEBUG_IO  
 	printk("ser%i dtr %i mask: 0x%02X\n", info->line, set, mask);
 	printk("ser%i shadow before 0x%02X get: %i\n", 
-	       info->line, *e100_modem_pins[info->line].shadow,
+	       info->line, *e100_modem_pins[info->line].dtr_shadow,
 	       E100_DTR_GET(info));
 #endif
 	/* DTR is active low */
@@ -855,20 +1015,15 @@
 
 		save_flags(flags);
 		cli();
-		*e100_modem_pins[info->line].shadow &= ~mask;
-		*e100_modem_pins[info->line].shadow |= (set ? 0 : mask); 
-		*e100_modem_pins[info->line].port = *e100_modem_pins[info->line].shadow;
+		*e100_modem_pins[info->line].dtr_shadow &= ~mask;
+		*e100_modem_pins[info->line].dtr_shadow |= (set ? 0 : mask); 
+		*e100_modem_pins[info->line].dtr_port = *e100_modem_pins[info->line].dtr_shadow;
 		restore_flags(flags);
 	}
 	
-#if 0
-	REG_SHADOW_SET(e100_modem_pins[info->line].port,
-		       *e100_modem_pins[info->line].shadow,
-		       e100_modem_pins[info->line].dtr_bit, !set);
-#endif
 #ifdef SERIAL_DEBUG_IO
 	printk("ser%i shadow after 0x%02X get: %i\n", 
-	       info->line, *e100_modem_pins[info->line].shadow, 
+	       info->line, *e100_modem_pins[info->line].dtr_shadow, 
 	       E100_DTR_GET(info));
 #endif
 #endif
@@ -890,6 +1045,7 @@
 #endif
 }
 
+
 /* If this behaves as a modem, RI and CD is an output */
 static inline void 
 e100_ri_out(struct e100_serial *info, int set)
@@ -897,14 +1053,14 @@
 #ifndef CONFIG_SVINTO_SIM
 	/* RI is active low */
 	{
-		unsigned char mask = (1 << e100_modem_pins[info->line].ri_bit);
+		unsigned char mask = e100_modem_pins[info->line].ri_mask;
 		unsigned long flags;
 
 		save_flags(flags);
 		cli();
-		*e100_modem_pins[info->line].shadow &= ~mask;
-		*e100_modem_pins[info->line].shadow |= (set ? 0 : mask); 
-		*e100_modem_pins[info->line].port = *e100_modem_pins[info->line].shadow;
+		*e100_modem_pins[info->line].ri_shadow &= ~mask;
+		*e100_modem_pins[info->line].ri_shadow |= (set ? 0 : mask); 
+		*e100_modem_pins[info->line].ri_port = *e100_modem_pins[info->line].ri_shadow;
 		restore_flags(flags);
 	}
 #endif
@@ -915,14 +1071,14 @@
 #ifndef CONFIG_SVINTO_SIM
 	/* CD is active low */
 	{
-		unsigned char mask = (1 << e100_modem_pins[info->line].cd_bit);
+		unsigned char mask = e100_modem_pins[info->line].cd_mask;
 		unsigned long flags;
 
 		save_flags(flags);
 		cli();
-		*e100_modem_pins[info->line].shadow &= ~mask;
-		*e100_modem_pins[info->line].shadow |= (set ? 0 : mask); 
-		*e100_modem_pins[info->line].port = *e100_modem_pins[info->line].shadow;
+		*e100_modem_pins[info->line].cd_shadow &= ~mask;
+		*e100_modem_pins[info->line].cd_shadow |= (set ? 0 : mask); 
+		*e100_modem_pins[info->line].cd_port = *e100_modem_pins[info->line].cd_shadow;
 		restore_flags(flags);
 	}
 #endif
@@ -1078,23 +1234,49 @@
  * rs_stop() and rs_start()
  *
  * This routines are called before setting or resetting tty->stopped.
- * They enable or disable transmitter interrupts, as necessary.
+ * They enable or disable transmitter using the XOFF registers, as necessary.
  * ------------------------------------------------------------
  */
 
-/* FIXME - when are these used and what is the purpose ? 
- * In rs_stop we probably just can block the transmit DMA ready irq
- * and in rs_start we re-enable it (and then the old one will come).
- */
-
 static void 
 rs_stop(struct tty_struct *tty)
 {
+	struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+	if (info) {
+		unsigned long flags;
+		unsigned long xoff;
+		
+		save_flags(flags); cli();
+		xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->tty));
+		xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, stop);
+		if (tty->termios->c_iflag & IXON ) {
+			xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
+		}
+	
+		*((unsigned long *)&info->port[REG_XOFF]) = xoff;
+		restore_flags(flags);
+	}
 }
 
 static void 
 rs_start(struct tty_struct *tty)
 {
+	struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+	if (info) {
+		unsigned long flags;
+		unsigned long xoff;
+
+		save_flags(flags); cli();
+		xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(tty));
+		xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable);
+		if (tty->termios->c_iflag & IXON ) {
+			xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
+		}
+	
+		*((unsigned long *)&info->port[REG_XOFF]) = xoff;
+		
+		restore_flags(flags);
+	}
 }
 
 /*
@@ -1341,7 +1523,7 @@
 	return 1;
 }
 
-static _INLINE_ unsigned int
+extern _INLINE_ unsigned int
 handle_descr_data(struct e100_serial *info, struct etrax_dma_descr *descr, unsigned int recvl)
 {
 	struct etrax_recv_buffer *buffer = phys_to_virt(descr->buf) - sizeof *buffer;
@@ -1567,7 +1749,7 @@
 	
 	for (i = 0; i < NR_PORTS; i++) {
 		info = rs_table + i;
-		if (!info->uses_dma) 
+		if (!info->enabled || !info->uses_dma) 
 			continue; 
 		/* check for dma_descr (don't need to check for dma_eop in output dma for serial */
 		if (ireg & info->irq) {  
@@ -1613,7 +1795,7 @@
 	
 	for (i = 0; i < NR_PORTS; i++) {
 		info = rs_table + i;
-		if (!info->uses_dma) 
+		if (!info->enabled || !info->uses_dma) 
 			continue; 
 		/* check for both dma_eop and dma_descr for the input dma channel */
 		if (ireg & ((info->irq << 2) | (info->irq << 3))) {
@@ -1671,10 +1853,10 @@
 	return 1;
 }
 
-static _INLINE_ void
+extern _INLINE_ void
 flush_to_flip_buffer(struct e100_serial *info)
 {
-	struct tty_struct *tty = info->tty;
+	struct tty_struct *tty;
 	struct etrax_recv_buffer *buffer;
 	unsigned int length;
 	unsigned long flags;
@@ -1685,6 +1867,11 @@
 	save_flags(flags);
 	cli();
 
+	if (!(tty = info->tty)) {
+		restore_flags(flags);
+		return;
+	}
+
 	length = tty->flip.count;
 
 	while ((buffer = info->first_recv_buffer) && length < TTY_FLIPBUF_SIZE) {
@@ -1773,7 +1960,7 @@
 	
 	for (i = 0; i < NR_PORTS; i++) {
 		info = rs_table + i;
-		if (info->uses_dma) 
+		if (info->enabled && info->uses_dma) 
 			check_flush_timeout(info);
 	}
 } /* timeout_interrupt */
@@ -1880,7 +2067,7 @@
 
 */
 
-static void _INLINE_ handle_ser_interrupt(struct e100_serial *info)
+extern void _INLINE_ handle_ser_interrupt(struct e100_serial *info)
 {
 	unsigned char rstat = info->port[REG_STATUS];
 
@@ -2247,6 +2434,7 @@
 change_speed(struct e100_serial *info)
 {
 	unsigned int cflag;
+	unsigned long xoff;
 
 	/* first some safety checks */
 	
@@ -2316,7 +2504,13 @@
 	
 	info->port[REG_TR_CTRL] = info->tx_ctrl;
 	info->port[REG_REC_CTRL] = info->rx_ctrl;
-	*((unsigned long *)&info->port[REG_XOFF]) = 0;
+	xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->tty));
+	xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable);
+	if (info->tty->termios->c_iflag & IXON ) {
+		xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
+	}
+	
+	*((unsigned long *)&info->port[REG_XOFF]) = xoff;
 #endif /* !CONFIG_SVINTO_SIM */
 
 	update_char_time(info);
@@ -2349,7 +2543,7 @@
 	restore_flags(flags);
 }
 
-static inline int 
+extern inline int 
 raw_write(struct tty_struct * tty, int from_user,
 	  const unsigned char *buf, int count)
 {
@@ -2497,7 +2691,7 @@
 
 		/* Sleep until all sent */
 		tty_wait_until_sent(tty, 0);
-#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
+#ifdef CONFIG_ETRAX_FAST_TIMER
 		/* Now sleep a little more so that shift register is empty */
 		schedule_usleep(info->char_time_usec * 2);
 #endif
@@ -2805,14 +2999,15 @@
 	       E100_DSR_GET(info),
 	       E100_CTS_GET(info));
 #endif
+
 	result =  
 		(!E100_RTS_GET(info) ? TIOCM_RTS : 0)
 		| (!E100_DTR_GET(info) ? TIOCM_DTR : 0)
-		| (!E100_CD_GET(info) ? TIOCM_CAR : 0)
 		| (!E100_RI_GET(info) ? TIOCM_RNG : 0)
 		| (!E100_DSR_GET(info) ? TIOCM_DSR : 0)
+		| (!E100_CD_GET(info) ? TIOCM_CAR : 0)
 		| (!E100_CTS_GET(info) ? TIOCM_CTS : 0);
-	
+
 #ifdef SERIAL_DEBUG_IO 
 	printk("e100ser: modem state: %i 0x%08X\n", result, result);
 	{
@@ -3488,7 +3683,7 @@
  * /proc fs routines....
  */
 
-static inline int line_info(char *buf, struct e100_serial *info)
+extern inline int line_info(char *buf, struct e100_serial *info)
 {
 	char	stat_buf[30];
 	int	ret;
@@ -3503,17 +3698,17 @@
 
 	stat_buf[0] = 0;
 	stat_buf[1] = 0;
-	if (E100_RTS_GET(info))
+	if (!E100_RTS_GET(info))
 		strcat(stat_buf, "|RTS");
-	if (E100_CTS_GET(info))
+	if (!E100_CTS_GET(info))
 		strcat(stat_buf, "|CTS");
-	if (E100_DTR_GET(info))
+	if (!E100_DTR_GET(info))
 		strcat(stat_buf, "|DTR");
-	if (E100_DSR_GET(info))
+	if (!E100_DSR_GET(info))
 		strcat(stat_buf, "|DSR");
-	if (E100_CD_GET(info))
+	if (!E100_CD_GET(info))
 		strcat(stat_buf, "|CD");
-	if (E100_RI_GET(info))
+	if (!E100_RI_GET(info))
 		strcat(stat_buf, "|RI");
 
 	ret += sprintf(buf+ret, " baud:%d", info->baud);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/drivers/sync_serial.c linux-2.4.21-pre6/arch/cris/drivers/sync_serial.c
--- linux-2.4.20/arch/cris/drivers/sync_serial.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/cris/drivers/sync_serial.c	2003-03-26 23:49:06.000000000 +0000
@@ -64,13 +64,13 @@
 #define DEFAULT_FRAME_RATE 0
 #define DEFAULT_WORD_RATE 7
 
-#define DEBUG(x) 
+#define DEBUG(x)
 
 /* Define some macros to access ETRAX 100 registers */
-#define SETF(var, reg, field, val) var = (var & ~IO_MASK(##reg##, field)) | \
-					  IO_FIELD(##reg##, field, val)
-#define SETS(var, reg, field, val) var = (var & ~IO_MASK(##reg##, field)) | \
-					  IO_STATE(##reg##, field, val)
+#define SETF(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \
+					  IO_FIELD_(reg##_, field##_, val)
+#define SETS(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \
+					  IO_STATE_(reg##_, field##_, _##val)
 
 typedef struct sync_port
 {
@@ -107,8 +107,7 @@
 	char in_buffer[IN_BUFFER_SIZE];
 	volatile char* readp;  /* Next byte to be read by application */
 	volatile char* writep; /* Next byte to be written by etrax */
-	int odd_output; /* 1 if writing odd nible in 12 bit mode */
-	int odd_input;  /* 1 if reading odd nible in 12 bit mode */
+	int started; /* 1 if port has been started */
 } sync_port;
 
 
@@ -221,7 +220,6 @@
 	  IO_STATE(R_DMA_CH9_CLR_INTR, clr_descr, do); 
 	*R_IRQ_MASK2_SET =
 	  IO_STATE(R_IRQ_MASK2_SET, dma8_eop, set) |
-	  IO_STATE(R_IRQ_MASK2_SET, dma8_descr, set) |
           IO_STATE(R_IRQ_MASK2_SET, dma9_descr, set);
 	start_dma_in(&ports[0]);
 #else
@@ -229,7 +227,6 @@
 	initialize_port(0);
 	if (request_irq(8, manual_interrupt, SA_SHIRQ | SA_INTERRUPT, "synchronous serial manual irq", &ports[0]))
 		panic("Can't allocate sync serial manual irq");
-	*R_IRQ_MASK1_SET = IO_STATE(R_IRQ_MASK1_SET, ser1_data, set);	 
 #endif
 #endif
 
@@ -252,7 +249,6 @@
 	  IO_STATE(R_DMA_CH5_CLR_INTR, clr_descr, do); 
 	*R_IRQ_MASK2_SET =
 	  IO_STATE(R_IRQ_MASK2_SET, dma4_eop, set) |
-	  IO_STATE(R_IRQ_MASK2_SET, dma4_descr, set) |
 	  IO_STATE(R_IRQ_MASK2_SET, dma5_descr, set);
 	start_dma_in(&ports[1]);
 #else
@@ -263,7 +259,6 @@
 		if (request_irq(8, manual_interrupt, SA_SHIRQ | SA_INTERRUPT, "synchronous serial manual irq", &ports[1]))
 			panic("Can't allocate sync serial manual irq");
 	}
-	*R_IRQ_MASK1_SET = IO_STATE(R_IRQ_MASK1_SET, ser3_data, set);	 
 #endif
 #endif
 
@@ -292,12 +287,12 @@
 	struct sync_port* port = &ports[portnbr];
 
 	DEBUG(printk("Init sync serial port %d\n", portnbr));
-    
+
+	port->started = 0;    
 	port->port_nbr = portnbr;	
 	port->busy = 0;		
 	port->readp = port->in_buffer;
-	port->writep = port->in_buffer + IN_BUFFER_SIZE/2;
-	port->odd_input = 0;
+	port->writep = port->in_buffer;
 
 	init_waitqueue_head(&port->out_wait_q);
 	init_waitqueue_head(&port->in_wait_q);
@@ -422,6 +417,10 @@
 		case SSP_MODE:
 			if (arg > 5)
 				return -EINVAL;
+			if (arg == MASTER_OUTPUT || arg == SLAVE_OUTPUT)
+				*R_IRQ_MASK1_CLR = 1 << port->data_avail_bit;
+			else
+				*R_IRQ_MASK1_SET = 1 << port->data_avail_bit;
 			SETF(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, mode, arg);
 			break;
 		case SSP_FRAME_SYNC:
@@ -466,8 +465,8 @@
 			if (arg & CLOCK_NOT_GATED)
 				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_mode, normal);
 			else if (arg & CLOCK_GATED)
-				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_mode, gated);
-    
+				SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_mode, gated);    
+
 			break;
 		case SSP_IPOLARITY:
 			if (arg & CLOCK_NORMAL)
@@ -553,11 +552,10 @@
 	copy_from_user(port->out_buffer, buf, count);
 	port->outp = port->out_buffer;
 	port->out_count = count;
-	port->odd_output = 1;
 	add_wait_queue(&port->out_wait_q, &wait);
 	set_current_state(TASK_INTERRUPTIBLE);
-	*R_IRQ_MASK1_SET = 1 << port->ready_irq_bit; /* transmitter ready IRQ on */
 	send_word(port); /* Start sender by sending first word */
+	*R_IRQ_MASK1_SET = 1 << port->ready_irq_bit; /* transmitter ready IRQ on */
 	schedule();
 	set_current_state(TASK_RUNNING);
 	remove_wait_queue(&port->out_wait_q, &wait);
@@ -586,9 +584,15 @@
 
 	count = count > OUT_BUFFER_SIZE ? OUT_BUFFER_SIZE : count;
 
-	/* Make sure transmitter is running */
-	SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_halt, running);
-	SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, tr_enable, enable);
+	/* Make sure transmitter/receiver is running */
+	if (!port->started)
+	{
+		SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_halt, running);
+		SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, tr_enable, enable);
+		SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, rec_enable, enable);
+		port->started = 1;
+	}
+
 	*port->ctrl_data = port->ctrl_data_shadow;
 
 	if (!port->use_dma)
@@ -629,9 +633,14 @@
 
 	DEBUG(printk("Read dev %d count %d\n", dev, count));
 
-	/* Make sure receiver is running */
-	SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_halt, running);
-	SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, rec_enable, enable);
+	if (!port->started)
+	{
+		SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_halt, running);
+		SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, tr_enable, enable);
+		SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, rec_enable, enable);
+		port->started = 1;
+	}
+
 	*port->ctrl_data = port->ctrl_data_shadow;
 
 	/* Calculate number of available bytes */
@@ -680,13 +689,12 @@
 			*port->data_out = *port->outp++;
 			break;
 		case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size12bit):
-			port->out_count--;
-			if (port->odd_output)
-				*port->data_out = ((*port->outp) << 16) | (*(unsigned short *)(port->outp + 1));
-			else
-				*port->data_out = ((*(unsigned short *)port->outp) << 8) | (*(port->outp + 1));
-			port->odd_output = !port->odd_output;
-			port->outp++;
+			{
+				int data = (*port->outp++) << 8;
+				data |= *port->outp++;
+				port->out_count-=2;  
+				*port->data_out = data;
+			}
 			break;
 		case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size16bit):
 			port->out_count-=2;
@@ -710,7 +718,7 @@
 {
 	port->out_descr.hw_len = 0;
 	port->out_descr.next = 0;
-	port->out_descr.ctrl = d_int | d_eol | d_eop | d_wait;
+	port->out_descr.ctrl = d_eol | d_eop | d_wait;
 	port->out_descr.sw_len = count;
 	port->out_descr.buf = virt_to_phys(port->out_buffer);
 	port->out_descr.status = 0;
@@ -765,6 +773,9 @@
 	for (i = 0; i < NUMBER_OF_PORTS; i++) 
 	{
 		sync_port *port = &ports[i];
+		if (!port->enabled)
+			continue;
+
 		if (ireg & (1 << port->output_dma_bit)) /* IRQ active for the port? */
 		{
 			/* Clear IRQ */
@@ -783,19 +794,15 @@
 
 	for (i = 0; i < NUMBER_OF_PORTS; i++) 
 	{
-		int update = 0;
 		sync_port *port = &ports[i];
 
 		if (!port->enabled)
-		{
 			continue;
-		}    
 
 		if (ireg & (1 << port->input_dma_descr_bit)) /* Descriptor interrupt */
 		{
 			/* DMA has reached end of descriptor */
 			*port->input_dma_clr_irq = 
-			  IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do) | 
 			  IO_STATE(R_DMA_CH0_CLR_INTR, clr_descr, do);
 
 			/* Find out which descriptor that is ready */
@@ -847,18 +854,9 @@
 				case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size12bit):
 				{
 					int data = *(unsigned short *)port->data_in;
-					if (port->odd_input)
-					{
-						*port->writep |= (data & 0x0f00) >> 8;
-						*(port->writep + 1) = data & 0xff;
-					}
-					else
-					{
-						*port->writep = (data & 0x0ff0) >> 4;
-						*(port->writep + 1) = (data & 0x0f) << 4;
-					}
-					port->odd_input = !port->odd_input;
-					port->writep+=1;
+					*port->writep = (data & 0x0ff0) >> 4;
+					*(port->writep + 1) = data & 0x0f;
+					port->writep+=2;
 				}
 				break;
 				case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size16bit):
@@ -875,14 +873,14 @@
 					break;
 			}
 
-			if (port->writep > port->in_buffer + IN_BUFFER_SIZE) /* Wrap? */
+			if (port->writep >= port->in_buffer + IN_BUFFER_SIZE) /* Wrap? */
 				port->writep = port->in_buffer;
 			wake_up_interruptible(&port->in_wait_q); /* Wake up application */
 		}
 
 		if (*R_IRQ_MASK1_RD & (1 << port->transmitter_ready_bit)) /* Transmitter ready? */
 		{
-			if (port->out_count) /* More data to send */
+			if (port->out_count > 0) /* More data to send */
 				send_word(port);
 			else /* transmission finished */
 			{
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/kernel/entry.S linux-2.4.21-pre6/arch/cris/kernel/entry.S
--- linux-2.4.20/arch/cris/kernel/entry.S	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/cris/kernel/entry.S	2003-03-26 23:49:31.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.39 2002/04/24 00:46:45 bjornw Exp $
+/* $Id: entry.S,v 1.40 2002/12/02 08:11:41 starvik Exp $
  *
  *  linux/arch/cris/entry.S
  *
@@ -7,6 +7,9 @@
  *  Authors:	Bjorn Wesen (bjornw@axis.com)
  *
  *  $Log: entry.S,v $
+ *  Revision 1.40  2002/12/02 08:11:41  starvik
+ *  Merge of Linux 2.4.20
+ *
  *  Revision 1.39  2002/04/24 00:46:45  bjornw
  *  Added sys_tkill
  *
@@ -736,12 +739,12 @@
  * the grosser the code, at least with the gcc version in cris-dist-1.13.
  */
 
-/* int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) */
+/* int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) */
 /*                   r10                r11         r12  */
 
 	.text
-	.global kernel_thread
-kernel_thread:
+	.global arch_kernel_thread
+arch_kernel_thread:
 
 	/* Save ARG for later.  */
 	move.d $r11, $r13
@@ -1016,7 +1019,33 @@
         .long SYMBOL_NAME(sys_ni_syscall)       /* Reserved for Security */
         .long SYMBOL_NAME(sys_gettid)
         .long SYMBOL_NAME(sys_readahead)        /* 225 */
-	.long SYMBOL_NAME(sys_tkill)
+	.long SYMBOL_NAME(sys_setxattr)
+	.long SYMBOL_NAME(sys_lsetxattr)
+	.long SYMBOL_NAME(sys_fsetxattr)
+	.long SYMBOL_NAME(sys_getxattr)
+	.long SYMBOL_NAME(sys_lgetxattr)	/* 230 */
+	.long SYMBOL_NAME(sys_fgetxattr)
+	.long SYMBOL_NAME(sys_listxattr)
+	.long SYMBOL_NAME(sys_llistxattr)
+	.long SYMBOL_NAME(sys_flistxattr)
+	.long SYMBOL_NAME(sys_removexattr)	/* 235 */
+	.long SYMBOL_NAME(sys_lremovexattr)
+	.long SYMBOL_NAME(sys_fremovexattr)
+ 	.long SYMBOL_NAME(sys_tkill)
+	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for sendfile64 */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* 240 reserved for futex */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for sched_setaffinity */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for sched_getaffinity */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_set_thread_area */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_get_thread_area */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* 245 sys_io_setup */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_io_destroy */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_io_getevents */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_io_submit */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_io_cancel */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* 250 sys_alloc_hugepages */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_free_hugepages */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_exit_group */
 	
         /*
          * NOTE!! This doesn't have to be exact - we just have
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/kernel/fasttimer.c linux-2.4.21-pre6/arch/cris/kernel/fasttimer.c
--- linux-2.4.20/arch/cris/kernel/fasttimer.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/cris/kernel/fasttimer.c	2003-03-26 23:49:25.000000000 +0000
@@ -1,10 +1,13 @@
-/* $Id: fasttimer.c,v 1.4 2002/05/28 17:47:59 johana Exp $
+/* $Id: fasttimer.c,v 1.5 2002/10/15 06:21:39 starvik Exp $
  * linux/arch/cris/kernel/fasttimer.c
  *
  * Fast timers for ETRAX100/ETRAX100LX
  * This may be useful in other OS than Linux so use 2 space indentation...
  *
  * $Log: fasttimer.c,v $
+ * Revision 1.5  2002/10/15 06:21:39  starvik
+ * Added call to init_waitqueue_head
+ *
  * Revision 1.4  2002/05/28 17:47:59  johana
  * Added del_fast_timer()
  *
@@ -551,6 +554,8 @@
   struct fast_timer t;
 #ifdef DECLARE_WAITQUEUE
   wait_queue_head_t sleep_wait;
+  init_waitqueue_head(&sleep_wait);
+  {
   DECLARE_WAITQUEUE(wait, current);
 #else
   struct wait_queue *sleep_wait = NULL;
@@ -566,6 +571,9 @@
   set_current_state(TASK_RUNNING);
   remove_wait_queue(&sleep_wait, &wait);
   D1(printk("done schedule_usleep(%d)\n", us));
+#ifdef DECLARE_WAITQUEUE
+  }
+#endif  
 }
 
 #ifdef CONFIG_PROC_FS
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/kernel/ksyms.c linux-2.4.21-pre6/arch/cris/kernel/ksyms.c
--- linux-2.4.20/arch/cris/kernel/ksyms.c	2002-02-25 19:37:52.000000000 +0000
+++ linux-2.4.21-pre6/arch/cris/kernel/ksyms.c	2003-03-26 23:49:50.000000000 +0000
@@ -24,6 +24,7 @@
 extern void dump_thread(struct pt_regs *, struct user *);
 extern unsigned long get_cmos_time(void);
 extern void __Udiv(void);
+extern void __Umod(void);
 extern void __ashrdi3(void);
 extern void iounmap(void *addr);
 
@@ -47,9 +48,11 @@
 EXPORT_SYMBOL(strlen);
 EXPORT_SYMBOL(strncat);
 EXPORT_SYMBOL(strncmp);
+EXPORT_SYMBOL(strncpy);
 
 /* Math functions */
 EXPORT_SYMBOL(__Udiv);
+EXPORT_SYMBOL(__Umod);
 EXPORT_SYMBOL(__ashrdi3);
 
 /* Memory functions */
@@ -70,14 +73,13 @@
 EXPORT_SYMBOL(port_g_data_shadow);
 
 /* Userspace access functions */
-EXPORT_SYMBOL(strncpy_from_user);
-EXPORT_SYMBOL(__strncpy_from_user);
-EXPORT_SYMBOL(__generic_copy_from_user);
-EXPORT_SYMBOL(__generic_copy_to_user);
-EXPORT_SYMBOL(strnlen_user);
 EXPORT_SYMBOL(__copy_user_zeroing);
 EXPORT_SYMBOL(__copy_user);
 
+/* Cache flush functions */
+EXPORT_SYMBOL(flush_etrax_cache);
+EXPORT_SYMBOL(prepare_rx_descriptor);
+
 #undef memcpy
 #undef memset
 extern void * memset(void *, int, __kernel_size_t);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/kernel/process.c linux-2.4.21-pre6/arch/cris/kernel/process.c
--- linux-2.4.20/arch/cris/kernel/process.c	2002-02-25 19:37:52.000000000 +0000
+++ linux-2.4.21-pre6/arch/cris/kernel/process.c	2003-03-26 23:49:49.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.22 2001/11/13 09:40:43 orjanf Exp $
+/* $Id: process.c,v 1.23 2002/10/14 18:29:27 johana Exp $
  * 
  *  linux/arch/cris/kernel/process.c
  *
@@ -8,6 +8,10 @@
  *  Authors:   Bjorn Wesen (bjornw@axis.com)
  *
  *  $Log: process.c,v $
+ *  Revision 1.23  2002/10/14 18:29:27  johana
+ *  Call etrax_gpio_wake_up_check() from cpu_idle() to reduce gpio latency
+ *  from ~15 ms to ~6 ms.
+ *
  *  Revision 1.22  2001/11/13 09:40:43  orjanf
  *  Added dump_fpu (needed for core dumps).
  *
@@ -121,11 +125,18 @@
 {
 	hlt_counter--;
 }
- 
+#ifdef CONFIG_ETRAX_GPIO
+void etrax_gpio_wake_up_check(void); /* drivers/gpio.c */
+#endif
+
 int cpu_idle(void *unused)
 {
 	while(1) {
 		current->counter = -100;
+#ifdef CONFIG_ETRAX_GPIO
+		/* This can reduce latency from 15 ms to 6 ms */
+		etrax_gpio_wake_up_check(); /* drivers/gpio.c */
+#endif
 		schedule();
 	}
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/kernel/setup.c linux-2.4.21-pre6/arch/cris/kernel/setup.c
--- linux-2.4.20/arch/cris/kernel/setup.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/cris/kernel/setup.c	2003-03-26 23:49:54.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.26 2002/06/04 07:57:56 jonashg Exp $
+/* $Id: setup.c,v 1.27 2002/10/11 12:57:15 pkj Exp $
  *
  *  linux/arch/cris/kernel/setup.c
  *
@@ -232,33 +232,34 @@
 		info = &cpu_info[revision];
 
 	return seq_printf(m,
-		       "cpu\t\t: CRIS\n"
-		       "cpu revision\t: %lu\n"
-		       "cpu model\t: %s\n"
-		       "cache size\t: %d kB\n"
-		       "fpu\t\t: %s\n"
-		       "mmu\t\t: %s\n"
-		       "mmu DMA bug\t: %s\n"
-		       "ethernet\t: %s Mbps\n"
-		       "token ring\t: %s\n"
-		       "scsi\t\t: %s\n"
-		       "ata\t\t: %s\n"
-		       "usb\t\t: %s\n"
-		       "bogomips\t: %lu.%02lu\n",
-
-		       revision,
-		       info->model,
-		       info->cache,
-		       info->flags & HAS_FPU ? "yes" : "no",
-		       info->flags & HAS_MMU ? "yes" : "no",
-		       info->flags & HAS_MMU_BUG ? "yes" : "no",
-		       info->flags & HAS_ETHERNET100 ? "10/100" : "10",
-		       info->flags & HAS_TOKENRING ? "4/16 Mbps" : "no",
-		       info->flags & HAS_SCSI ? "yes" : "no",
-		       info->flags & HAS_ATA ? "yes" : "no",
-		       info->flags & HAS_USB ? "yes" : "no",
-		       (loops_per_jiffy * HZ + 500) / 500000,
-		       ((loops_per_jiffy * HZ + 500) / 5000) % 100);
+			  "processor\t: 0\n"
+			  "cpu\t\t: CRIS\n"
+			  "cpu revision\t: %lu\n"
+			  "cpu model\t: %s\n"
+			  "cache size\t: %d kB\n"
+			  "fpu\t\t: %s\n"
+			  "mmu\t\t: %s\n"
+			  "mmu DMA bug\t: %s\n"
+			  "ethernet\t: %s Mbps\n"
+			  "token ring\t: %s\n"
+			  "scsi\t\t: %s\n"
+			  "ata\t\t: %s\n"
+			  "usb\t\t: %s\n"
+			  "bogomips\t: %lu.%02lu\n",
+
+			  revision,
+			  info->model,
+			  info->cache,
+			  info->flags & HAS_FPU ? "yes" : "no",
+			  info->flags & HAS_MMU ? "yes" : "no",
+			  info->flags & HAS_MMU_BUG ? "yes" : "no",
+			  info->flags & HAS_ETHERNET100 ? "10/100" : "10",
+			  info->flags & HAS_TOKENRING ? "4/16 Mbps" : "no",
+			  info->flags & HAS_SCSI ? "yes" : "no",
+			  info->flags & HAS_ATA ? "yes" : "no",
+			  info->flags & HAS_USB ? "yes" : "no",
+			  (loops_per_jiffy * HZ + 500) / 500000,
+			  ((loops_per_jiffy * HZ + 500) / 5000) % 100);
 }
 
 static void *c_start(struct seq_file *m, loff_t *pos)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/kernel/signal.c linux-2.4.21-pre6/arch/cris/kernel/signal.c
--- linux-2.4.20/arch/cris/kernel/signal.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/cris/kernel/signal.c	2003-03-26 23:48:59.000000000 +0000
@@ -517,7 +517,7 @@
  * OK, we're invoking a handler
  */	
 
-static inline void
+extern inline void
 handle_signal(int canrestart, unsigned long sig, struct k_sigaction *ka,
 	      siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/kernel/time.c linux-2.4.21-pre6/arch/cris/kernel/time.c
--- linux-2.4.20/arch/cris/kernel/time.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/cris/kernel/time.c	2003-03-26 23:49:40.000000000 +0000
@@ -1,9 +1,9 @@
-/* $Id: time.c,v 1.14 2002/03/05 13:31:03 johana Exp $
+/* $Id: time.c,v 1.17 2002/11/15 14:49:24 oskarp Exp $
  *
  *  linux/arch/cris/kernel/time.c
  *
  *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
- *  Copyright (C) 1999, 2000, 2001 Axis Communications AB
+ *  Copyright (C) 1999, 2000, 2001, 2002 Axis Communications AB
  *
  * 1994-07-02    Alan Modra
  *	fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime
@@ -25,6 +25,9 @@
  *      resolution within a jiffie as well.
  * 2002-03-05    Johan Adolfsson
  *      Use prescaler in do_slow_gettimeoffset() to get 1 us resolution (40ns)
+ * 2002-09-06    Johan Adolfsson
+ *      Handle lost ticks by checking wall_jiffies, more efficient code 
+ *      by using local vars and not the pointer argument.
  *
  */
 
@@ -62,6 +65,8 @@
 
 #define TICK_SIZE tick
 
+extern unsigned long wall_jiffies;
+
 /* The timers count from their initial value down to 1 
  * The R_TIMER0_DATA counts down when R_TIM_PRESC_STATUS reaches halv
  * of the divider value.
@@ -171,10 +176,8 @@
 
 	/*
 	 * avoiding timer inconsistencies (they are rare, but they happen)...
-	 * there are three kinds of problems that must be avoided here:
+	 * there are one problem that must be avoided here:
 	 *  1. the timer counter underflows
-	 *  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 ) {
@@ -198,7 +201,8 @@
 	return usec_count;
 }
 
-static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset;
+
+#define do_gettimeoffset() do_slow_gettimeoffset()
 
 /*
  * This version of gettimeofday has near microsecond resolution.
@@ -206,20 +210,33 @@
 void do_gettimeofday(struct timeval *tv)
 {
 	unsigned long flags;
-
+	unsigned long usec, sec;
 	save_flags(flags);
 	cli();
-	*tv = xtime;
-	tv->tv_usec += do_gettimeoffset();
+	usec = do_gettimeoffset();
+	{
+		unsigned long lost = jiffies - wall_jiffies;
+		if (lost)
+			usec += lost * (1000000 / HZ);
+	}
+	sec = xtime.tv_sec;
+	usec += xtime.tv_usec;
 	restore_flags(flags);
-	while (tv->tv_usec >= 1000000) {
-		tv->tv_usec -= 1000000;
-		tv->tv_sec++;
+
+	while (usec >= 1000000) {
+		usec -= 1000000;
+		sec++;
 	}
+
+	tv->tv_sec = sec;
+	tv->tv_usec = usec;
 }
 
 void do_settimeofday(struct timeval *tv)
 {
+	unsigned long flags;
+	signed long new_usec, new_sec;
+	save_flags(flags);  
 	cli();
 	/* This is revolting. We need to set the xtime.tv_usec
 	 * correctly. However, the value in this location is
@@ -227,20 +244,23 @@
 	 * Discover what correction gettimeofday
 	 * would have done, and then undo it!
 	 */
-	tv->tv_usec -= do_gettimeoffset();
-
-	if (tv->tv_usec < 0) {
-		tv->tv_usec += 1000000;
-		tv->tv_sec--;
+	new_usec = tv->tv_usec;
+	new_usec -= do_gettimeoffset();
+	new_usec -= (jiffies - wall_jiffies) * (1000000 / HZ);
+	new_sec = tv->tv_sec;
+	while (new_usec < 0) {
+		new_usec += 1000000;
+		new_sec--;
 	}
+	xtime.tv_sec = new_sec;
+	xtime.tv_usec = new_usec;
 
-	xtime = *tv;
 	time_adjust = 0;		/* stop active adjtime() */
 	time_status |= STA_UNSYNC;
 	time_state = TIME_ERROR;	/* p. 24, (a) */
 	time_maxerror = NTP_PHASE_LIMIT;
 	time_esterror = NTP_PHASE_LIMIT;
-	sti();
+	restore_flags(flags);
 }
 
 
@@ -479,10 +499,16 @@
 void __init
 time_init(void)
 {	
-	/* probe for the RTC and read it if it exists */
+	/* Probe for the RTC and read it if it exists 
+	 * Before the RTC can be probed the loops_per_usec variable needs 
+	 * to be initialized to make usleep work. A better value for 
+	 * loops_per_usec is calculated by the kernel later once the 
+	 * clock has started.  
+	 */
+	loops_per_usec = 50;
 
 	if(RTC_INIT() < 0) {
-		/* no RTC, start at 1980 */
+		/* no RTC, start at the Epoch (00:00:00 UTC, January 1, 1970) */
 		xtime.tv_sec = 0;
 		xtime.tv_usec = 0;
 		have_rtc = 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/kernel/traps.c linux-2.4.21-pre6/arch/cris/kernel/traps.c
--- linux-2.4.20/arch/cris/kernel/traps.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/cris/kernel/traps.c	2003-03-26 23:49:54.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.17 2001/12/07 17:02:34 bjornw Exp $
+/* $Id: traps.c,v 1.18 2002/12/02 08:11:41 starvik Exp $
  *
  *  linux/arch/cris/traps.c
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/lib/dram_init.S linux-2.4.21-pre6/arch/cris/lib/dram_init.S
--- linux-2.4.20/arch/cris/lib/dram_init.S	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/cris/lib/dram_init.S	2003-03-26 23:49:25.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: dram_init.S,v 1.12 2002/08/09 11:37:37 orjanf Exp $
+/* $Id: dram_init.S,v 1.13 2002/10/30 07:42:28 starvik 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.13  2002/10/30 07:42:28  starvik
+ * Always read SDRAM command sequence from flash
+ *
  * Revision 1.12  2002/08/09 11:37:37  orjanf
  * Added double initialization work-around for Samsung SDRAMs.
  *
@@ -143,7 +146,9 @@
 	
 	; Issue initialization command sequence
 	move.d   _sdram_commands_start, $r2
+	and.d    0x00ffffff, $r2 ; Make sure commands are read from flash
 	move.d   _sdram_commands_end,  $r3
+	and.d    0x00ffffff, $r2
 1:	clear.d  $r4
 	move.b   [$r2+], $r4
 	lslq     9, $r4	; Command starts at bit 9
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/lib/hw_settings.S linux-2.4.21-pre6/arch/cris/lib/hw_settings.S
--- linux-2.4.20/arch/cris/lib/hw_settings.S	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/cris/lib/hw_settings.S	2003-03-26 23:49:35.000000000 +0000
@@ -1,11 +1,11 @@
 /*
- * $Id: hw_settings.S,v 1.4 2002/07/04 16:58:56 pkj Exp $
+ * $Id: hw_settings.S,v 1.5 2002/08/15 09:16:06 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
+ * Copyright (C) 2001, 2002 Axis Communications AB
  *
  * Authors:  Mikael Starvik (starvik@axis.com)	
  */
@@ -16,8 +16,8 @@
 		(CONFIG_ETRAX_DEF_R_PORT_PB_DIR << 8) | \
 		(CONFIG_ETRAX_DEF_R_PORT_PB_DATA))
 	
-	.ascii "HW_PARAM_MAGIC"					; Magic number
-	.dword CONFIG_ETRAX_DRAM_VIRTUAL_BASE | 0x80004000	; Kernel start address
+	.ascii "HW_PARAM_MAGIC"	; Magic number
+	.dword 0xc0004000	; Where to load the kernel image (physical!)
 
 	; Debug port
 #ifdef CONFIG_ETRAX_DEBUG_PORT0
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/lib/usercopy.c linux-2.4.21-pre6/arch/cris/lib/usercopy.c
--- linux-2.4.20/arch/cris/lib/usercopy.c	2001-10-08 18:43:54.000000000 +0000
+++ linux-2.4.21-pre6/arch/cris/lib/usercopy.c	2003-03-26 23:49:07.000000000 +0000
@@ -88,11 +88,11 @@
        If you want to check that the allocation was right; then
        check the equalities in the first comment.  It should say
        "r13=r13, r11=r11, r12=r12".  */
-    __asm__ volatile ("
-	;; Check that the following is true (same register names on
-	;; both sides of equal sign, as in r8=r8):
-	;; %0=r13, %1=r11, %2=r12 %3=r10
-	;;
+    __asm__ volatile ("\
+	.ifnc %0%1%2%3,$r13$r11$r12$r10					\n\
+	.err								\n\
+	.endif								\n\
+
 	;; Save the registers we'll use in the movem process
 	;; on the stack.
 	subq	11*4,$sp
@@ -189,7 +189,8 @@
 }
 
 /* Copy from user to kernel, zeroing the bytes that were inaccessible in
-   userland.  */
+   userland.  The return-value is the number of bytes that were
+   inaccessible.  */
 
 unsigned long
 __copy_user_zeroing (void *pdst, const void *psrc, unsigned long pn)
@@ -207,30 +208,34 @@
   register int n __asm__ ("r12") = pn;
   register int retn __asm__ ("r10") = 0;
 
-  /* When src is aligned but not dst, this makes a few extra needless
-     cycles.  I believe it would take as many to check that the
-     re-alignment was unnecessary.  */
-  if (((unsigned long) dst & 3) != 0
-      /* Don't align if we wouldn't copy more than a few bytes; so we
-	 don't have to check further for overflows.  */
-      && n >= 3)
+  /* The best reason to align src is that we then know that a read-fault
+     was for aligned bytes; there's no 1..3 remaining good bytes to
+     pickle.  */
+  if (((unsigned long) src & 3) != 0)
   {
-    if ((unsigned long) dst & 1)
+    if (((unsigned long) src & 1) && n != 0)
     {
       __asm_copy_from_user_1 (dst, src, retn);
       n--;
     }
 
-    if ((unsigned long) dst & 2)
+    if (((unsigned long) src & 2) && n >= 2)
     {
       __asm_copy_from_user_2 (dst, src, retn);
       n -= 2;
     }
+
+    /* We only need one check after the unalignment-adjustments, because
+       if both adjustments were done, either both or neither reference
+       had an exception.  */
+    if (retn != 0)
+      goto copy_exception_bytes;
   }
 
   /* Decide which copying method to use. */
   if (n >= 44*2)		/* Break even between movem and
-				   move16 is at 38.7*2, but modulo 44. */
+				   move16 is at 38.7*2, but modulo 44.
+				   FIXME: We use move4 now.  */
   {
     /* For large copies we use 'movem' */
 
@@ -249,10 +254,10 @@
        check the equalities in the first comment.  It should say
        "r13=r13, r11=r11, r12=r12" */
     __asm__ volatile ("
-	;; Check that the following is true (same register names on
-	;; both sides of equal sign, as in r8=r8):
-	;; %0=r13, %1=r11, %2=r12 %3=r10
-	;;
+	.ifnc %0%1%2%3,$r13$r11$r12$r10					\n\
+	.err								\n\
+	.endif								\n\
+
 	;; Save the registers we'll use in the movem process
 	;; on the stack.
 	subq	11*4,$sp
@@ -273,73 +278,30 @@
 	movem	$r10,[$r13+]
 
 	addq   44,$r12  ;; compensate for last loop underflowing n
-8:
+
 	;; Restore registers from stack
 	movem [$sp+],$r10
-
+4:
 	.section .fixup,\"ax\"
 
 ;; 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
+;; page fault somewhere on the line.  Without checking for page limits,
+;; we don't know where, but we need to copy accurately and keep an
+;; accurate count; not just clear the whole line.  To do that, we fall
+;; down in the code below, proceeding with smaller amounts.  It should
+;; be kept in mind that we have to cater to code like what at one time
+;; was in fs/super.c:
 ;;  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.
+;; A caveat here is that we must not fall through from a failing page
+;; to a valid page.
 
 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
-	clear.d $r2
-	clear.d $r3
-	clear.d $r4
-	clear.d $r5
-	clear.d $r6
-	clear.d $r7
-	clear.d $r8
-	clear.d $r9
-	clear.d $r10
-
-;; 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
+	movem  [$sp+],$r10
+	addq	44,$r12 ;; Get back count before faulting point.
+	subq	44,$r11 ;; Get back pointer to faulting movem-line.
+	jump	4b	;; Fall through, pretending the fault didn't happen.
 
 	.previous
 	.section __ex_table,\"a\"
@@ -354,25 +316,30 @@
   /* Either we directly start copying here, using dword copying in a loop,
      or we copy as much as possible with 'movem' and then the last block
      (<44 bytes) is copied here.  This will work since 'movem' will have
-     updated src, dst and n. */
+     updated src, dst and n.  (Except with failing src.)
 
-  while (n >= 16)
-  {
-    __asm_copy_from_user_16 (dst, src, retn);
-    n -= 16;
-  }
+     Since we want to keep src accurate, we can't use
+     __asm_copy_from_user_N with N != (1, 2, 4); it updates dst and
+     retn, but not src (by design; it's value is ignored elsewhere).  */
 
-  /* Having a separate by-four loops cuts down on cache footprint.
-     FIXME:  Test with and without; increasing switch to be 0..15.  */
   while (n >= 4)
   {
     __asm_copy_from_user_4 (dst, src, retn);
     n -= 4;
+
+    if (retn)
+      goto copy_exception_bytes;
   }
 
+  /* If we get here, there were no memory read faults.  */
   switch (n)
   {
+    /* These copies are at least "naturally aligned" (so we don't have
+       to check each byte), due to the src alignment code before the
+       movem loop.  The *_3 case *will* get the correct count for retn.  */
     case 0:
+      /* This case deliberately left in (if you have doubts check the
+	 generated assembly code).  */
       break;
     case 1:
       __asm_copy_from_user_1 (dst, src, retn);
@@ -385,7 +352,22 @@
       break;
   }
 
+  /* If we get here, retn correctly reflects the number of failing
+     bytes.  */
   return retn;
+
+copy_exception_bytes:
+  /* We already have "retn" bytes cleared, and need to clear the
+     remaining "n" bytes.  A non-optimized simple byte-for-byte in-line
+     memset is preferred here, since this isn't speed-critical code and
+     we'd rather have this a leaf-function than calling memset.  */
+  {
+    char *endp;
+    for (endp = dst + n; dst < endp; dst++)
+      *dst = 0;
+  }
+
+  return retn + n;
 }
 
 /* Zero userspace.  */
@@ -444,10 +426,10 @@
       check the equalities in the first comment.  It should say
       something like "r13=r13, r11=r11, r12=r12". */
     __asm__ volatile ("
-	;; Check that the following is true (same register names on
-	;; both sides of equal sign, as in r8=r8):
-	;; %0=r13, %1=r12 %2=r10
-	;;
+	.ifnc %0%1%2,$r13$r12$r10					\n\
+	.err								\n\
+	.endif								\n\
+
 	;; Save the registers we'll clobber in the movem process
 	;; on the stack.  Don't mention them to gcc, it will only be
 	;; upset.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/cris/mm/ioremap.c linux-2.4.21-pre6/arch/cris/mm/ioremap.c
--- linux-2.4.20/arch/cris/mm/ioremap.c	2001-05-01 23:04:56.000000000 +0000
+++ linux-2.4.21-pre6/arch/cris/mm/ioremap.c	2003-03-26 23:49:07.000000000 +0000
@@ -13,7 +13,7 @@
 #include <asm/io.h>
 #include <asm/pgalloc.h>
 
-static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
+extern inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
 	unsigned long phys_addr, unsigned long flags)
 {
 	unsigned long end;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/Makefile linux-2.4.21-pre6/arch/i386/Makefile
--- linux-2.4.20/arch/i386/Makefile	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/i386/Makefile	2003-03-26 23:49:27.000000000 +0000
@@ -23,8 +23,10 @@
 
 CFLAGS += -pipe
 
+check_gcc = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi)
+
 # prevent gcc from keeping the stack 16 byte aligned
-CFLAGS += $(shell if $(CC) -mpreferred-stack-boundary=2 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-mpreferred-stack-boundary=2"; fi)
+CFLAGS += $(call check_gcc,-mpreferred-stack-boundary=2,)
 
 ifdef CONFIG_M386
 CFLAGS += -march=i386
@@ -59,15 +61,16 @@
 endif
 
 ifdef CONFIG_MK6
-CFLAGS += $(shell if $(CC) -march=k6 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=k6"; else echo "-march=i586"; fi)
+CFLAGS += $(call check_gcc,-march=k6,-march=i586)
 endif
 
 ifdef CONFIG_MK7
-CFLAGS += $(shell if $(CC) -march=athlon -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=athlon"; else echo "-march=i686 -malign-functions=4"; fi) 
+CFLAGS += $(call check_gcc,-march=athlon,-march=i686 -malign-functions=4)
 endif
 
 ifdef CONFIG_MCRUSOE
-CFLAGS += -march=i686 -malign-functions=0 -malign-jumps=0 -malign-loops=0
+CFLAGS += -march=i686
+CFLAGS += $(call check_gcc,-falign-functions=0 -falign-jumps=0 -falign-loops=0,-malign-functions=0 -malign-jumps=0 -malign-loops=0)
 endif
 
 ifdef CONFIG_MWINCHIPC6
@@ -83,7 +86,12 @@
 endif
 
 ifdef CONFIG_MCYRIXIII
-CFLAGS += -march=i486 -malign-functions=0 -malign-jumps=0 -malign-loops=0
+CFLAGS += $(call check_gcc,-march=c3,-march=i486)
+CFLAGS += $(call check_gcc,-falign-functions=0 -falign-jumps=0 -falign-loops=0,-malign-functions=0 -malign-jumps=0 -malign-loops=0)
+endif
+
+ifdef CONFIG_MVIAC3_2
+CFLAGS += $(call check_gcc,-march=c3-2,-march=i686)
 endif
 
 HEAD := arch/i386/kernel/head.o arch/i386/kernel/init_task.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/config.in linux-2.4.21-pre6/arch/i386/config.in
--- linux-2.4.20/arch/i386/config.in	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/i386/config.in	2003-03-26 23:49:25.000000000 +0000
@@ -36,12 +36,14 @@
 	 Pentium-4				CONFIG_MPENTIUM4 \
 	 K6/K6-II/K6-III			CONFIG_MK6 \
 	 Athlon/Duron/K7			CONFIG_MK7 \
+	 Opteron/Athlon64/Hammer/K8		CONFIG_MK8 \
 	 Elan					CONFIG_MELAN \
 	 Crusoe					CONFIG_MCRUSOE \
 	 Winchip-C6				CONFIG_MWINCHIPC6 \
 	 Winchip-2				CONFIG_MWINCHIP2 \
 	 Winchip-2A/Winchip-3			CONFIG_MWINCHIP3D \
-	 CyrixIII/VIA-C3/VIA-C5			CONFIG_MCYRIXIII" Pentium-Pro
+	 CyrixIII/VIA-C3			CONFIG_MCYRIXIII \
+	 VIA-C3-2				CONFIG_MVIAC3_2" Pentium-Pro
 #
 # Define implied options from the CPU selection here
 #
@@ -99,7 +101,7 @@
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
    define_bool CONFIG_X86_HAS_TSC y
    define_bool CONFIG_X86_GOOD_APIC y
-   define_bool CONFIG_X86_PGE y
+   bool 'PGE extensions (not for Cyrix/Transmeta)' CONFIG_X86_PGE
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
    define_bool CONFIG_X86_PPRO_FENCE y
    define_bool CONFIG_X86_F00F_WORKS_OK y
@@ -126,6 +128,11 @@
    define_bool CONFIG_X86_HAS_TSC y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
 fi
+if [ "$CONFIG_MK8" = "y" ]; then
+   # for now. may later want to add SSE support and optimized
+   # functions
+   define_bool CONFIG_MK7 y
+fi
 if [ "$CONFIG_MK7" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 6
    define_bool CONFIG_X86_HAS_TSC y
@@ -147,6 +154,14 @@
    define_bool CONFIG_X86_ALIGNMENT_16 y
    define_bool CONFIG_X86_USE_3DNOW y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
+   define_bool CONFIG_X86_F00F_WORKS_OK y
+fi
+if [ "$CONFIG_MVIAC3_2" = "y" ]; then
+   define_int  CONFIG_X86_L1_CACHE_SHIFT 5
+   define_bool CONFIG_X86_HAS_TSC y
+   define_bool CONFIG_X86_ALIGNMENT_16 y
+   define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
+   define_bool CONFIG_X86_F00F_WORKS_OK y
 fi
 if [ "$CONFIG_MCRUSOE" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
@@ -216,12 +231,26 @@
       define_bool CONFIG_X86_IO_APIC y
    fi
 else
-   bool 'Multiquad NUMA system' CONFIG_MULTIQUAD
+   bool 'Multi-node NUMA system support' CONFIG_X86_NUMA
+   if [ "$CONFIG_X86_NUMA" = "y" ]; then
+      #Platform Choices
+      bool ' Multiquad (IBM/Sequent) NUMAQ support' CONFIG_X86_NUMAQ
+      if [ "$CONFIG_X86_NUMAQ" = "y" ]; then
+         define_bool CONFIG_X86_CLUSTERED_APIC y
+         define_bool CONFIG_MULTIQUAD y
+      fi
+      bool ' IBM x440 (Summit/EXA) support' CONFIG_X86_SUMMIT
+      if [ "$CONFIG_X86_SUMMIT" = "y" ]; then
+         define_bool CONFIG_X86_CLUSTERED_APIC y
+      fi
+   fi
 fi
 
-bool 'Unsynced TSC support' CONFIG_X86_TSC_DISABLE
-if [ "$CONFIG_X86_TSC_DISABLE" != "y" -a "$CONFIG_X86_HAS_TSC" = "y" ]; then
-   define_bool CONFIG_X86_TSC y
+if [ "$CONFIG_X86_NUMA" != "y" ]; then
+   bool 'Unsynced TSC support' CONFIG_X86_TSC_DISABLE
+   if [ "$CONFIG_X86_TSC_DISABLE" != "y" -a "$CONFIG_X86_HAS_TSC" = "y" ]; then
+      define_bool CONFIG_X86_TSC y
+   fi
 fi
 
 if [ "$CONFIG_SMP" = "y" -a "$CONFIG_X86_CMPXCHG" = "y" ]; then
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/apic.c linux-2.4.21-pre6/arch/i386/kernel/apic.c
--- linux-2.4.20/arch/i386/kernel/apic.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/i386/kernel/apic.c	2003-03-26 23:49:38.000000000 +0000
@@ -261,6 +261,16 @@
 	apic_write_around(APIC_LVT1, value);
 }
 
+static unsigned long calculate_ldr(unsigned long old)
+{
+	unsigned long id;
+	if(clustered_apic_mode == CLUSTERED_APIC_XAPIC)
+		id = physical_to_logical_apicid(hard_smp_processor_id());
+	else
+		id = 1UL << smp_processor_id();
+	return (old & ~APIC_LDR_MASK)|SET_APIC_LOGICAL_ID(id);
+}
+
 void __init setup_local_APIC (void)
 {
 	unsigned long value, ver, maxlvt;
@@ -298,15 +308,16 @@
 		 * for us. Otherwise put the APIC into clustered or flat
 		 * delivery mode. Must be "all ones" explicitly for 82489DX.
 		 */
-		apic_write_around(APIC_DFR, APIC_DFR_FLAT);
+		if(clustered_apic_mode == CLUSTERED_APIC_XAPIC)
+			apic_write_around(APIC_DFR, APIC_DFR_CLUSTER);
+		else
+			apic_write_around(APIC_DFR, APIC_DFR_FLAT);
 
 		/*
 		 * Set up the logical destination ID.
 		 */
 		value = apic_read(APIC_LDR);
-		value &= ~APIC_LDR_MASK;
-		value |= (1<<(smp_processor_id()+24));
-		apic_write_around(APIC_LDR, value);
+		apic_write_around(APIC_LDR, calculate_ldr(value));
 	}
 
 	/*
@@ -600,6 +611,8 @@
 	case X86_VENDOR_AMD:
 		if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model > 1)
 			break;
+		if (boot_cpu_data.x86 == 15 && cpu_has_apic)
+			break;
 		goto no_apic;
 	case X86_VENDOR_INTEL:
 		if (boot_cpu_data.x86 == 6 ||
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/apm.c linux-2.4.21-pre6/arch/i386/kernel/apm.c
--- linux-2.4.20/arch/i386/kernel/apm.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/i386/kernel/apm.c	2003-03-26 23:48:59.000000000 +0000
@@ -247,6 +247,7 @@
  *	    					powering off
  *	    [no-]debug			log some debugging messages
  *	    [no-]power[-_]off		power off on shutdown
+ *	    [no-]smp			Use apm even on an SMP box
  *	    bounce[-_]interval=<n>	number of ticks to ignore suspend
  *	    				bounces
  *          idle[-_]threshold=<n>       System idle percentage above which to
@@ -393,6 +394,7 @@
 static int			got_clock_diff;
 #endif
 static int			debug;
+static int			smp = 0;
 static int			apm_disabled = -1;
 #ifdef CONFIG_SMP
 static int			power_off;
@@ -494,6 +496,40 @@
 }
 
 /*
+ * Lock APM functionality to physical CPU 0
+ */
+ 
+#ifdef CONFIG_SMP
+
+static unsigned long apm_save_cpus(void)
+{
+	unsigned long x = current->cpus_allowed;
+	/* Some bioses don't like being called from CPU != 0 */
+	if (cpu_number_map(smp_processor_id()) != 0) {
+		set_cpus_allowed(current, 1 << cpu_logical_map(0));
+		if (unlikely(cpu_number_map(smp_processor_id()) != 0))
+			BUG();
+	}
+	return x;
+}
+
+static inline void apm_restore_cpus(unsigned long mask)
+{
+	set_cpus_allowed(current, mask);
+}
+
+#else
+
+/*
+ *	No CPU lockdown needed on a uniprocessor
+ */
+ 
+#define apm_save_cpus()	0
+#define apm_restore_cpus(x)	(void)(x)
+
+#endif
+
+/*
  * These are the actual BIOS calls.  Depending on APM_ZERO_SEGS and
  * apm_info.allow_ints, we are being really paranoid here!  Not only
  * are interrupts disabled, but all the segment registers (except SS)
@@ -566,7 +602,8 @@
 {
 	APM_DECL_SEGS
 	unsigned long	flags;
-
+	unsigned long cpus = apm_save_cpus();
+	
 	__save_flags(flags);
 	APM_DO_CLI;
 	APM_DO_SAVE_SEGS;
@@ -588,6 +625,9 @@
 		: "memory", "cc");
 	APM_DO_RESTORE_SEGS;
 	__restore_flags(flags);
+	
+	apm_restore_cpus(cpus);
+	
 	return *eax & 0xff;
 }
 
@@ -611,6 +651,8 @@
 	APM_DECL_SEGS
 	unsigned long	flags;
 
+	unsigned long cpus = apm_save_cpus();
+	
 	__save_flags(flags);
 	APM_DO_CLI;
 	APM_DO_SAVE_SEGS;
@@ -636,6 +678,9 @@
 	}
 	APM_DO_RESTORE_SEGS;
 	__restore_flags(flags);
+
+	apm_restore_cpus(cpus);
+	
 	return error;
 }
 
@@ -751,10 +796,12 @@
 	if (apm_bios_call_simple(APM_FUNC_IDLE, 0, 0, &eax)) {
 		static unsigned long t;
 
-		if (time_after(jiffies, t + 10 * HZ)) {
+		/* This always fails on some SMP boards running UP kernels.
+		 * Only report the failure the first 5 times.
+		 */
+		if (++t < 5) {
 			printk(KERN_DEBUG "apm_do_idle failed (%d)\n",
 					(eax >> 8) & 0xff);
-			t = jiffies;
 		}
 		return -1;
 	}
@@ -888,17 +935,12 @@
 	/*
 	 * This may be called on an SMP machine.
 	 */
-#ifdef CONFIG_SMP
-	/* Some bioses don't like being called from CPU != 0 */
-	if (cpu_number_map(smp_processor_id()) != 0) {
-		current->cpus_allowed = 1;
-		schedule();
-		if (unlikely(cpu_number_map(smp_processor_id()) != 0))
-			BUG();
-	}
-#endif
 	if (apm_info.realmode_power_off)
+	{
+		(void)apm_save_cpus();
 		machine_real_restart(po_bios_call, sizeof(po_bios_call));
+		/* Never returns */
+	}
 	else
 		(void) set_system_power_state(APM_STATE_OFF);
 }
@@ -1074,6 +1116,19 @@
 	}
 	if ((error == APM_SUCCESS) || (error == APM_NO_ERROR))
 		return 1;
+	if (error == APM_NOT_ENGAGED) {
+		static int tried;
+		int eng_error;
+		if (tried++ == 0) {
+			eng_error = apm_engage_power_management(APM_DEVICE_ALL, 1);
+			if (eng_error) {
+				apm_error("set display", error);
+				apm_error("engage interface", eng_error);
+				return 0;
+			} else
+				return apm_console_blank(blank);
+		}
+	}
 	apm_error("set display", error);
 	return 0;
 }
@@ -1397,7 +1452,7 @@
 	as = fp->private_data;
 	if (check_apm_user(as, "read"))
 		return -EIO;
-	if (count < sizeof(apm_event_t))
+	if ((int)count < sizeof(apm_event_t))
 		return -EINVAL;
 	if ((queue_empty(as)) && (fp->f_flags & O_NONBLOCK))
 		return -EAGAIN;
@@ -1571,7 +1626,7 @@
 
 	p = buf;
 
-	if ((smp_num_cpus == 1) &&
+	if ((smp_num_cpus == 1 || smp) &&
 	    !(error = apm_get_power_status(&bx, &cx, &dx))) {
 		ac_line_status = (bx >> 8) & 0xff;
 		battery_status = bx & 0xff;
@@ -1716,7 +1771,7 @@
 		}
 	}
 
-	if (debug) {
+	if (debug && (smp_num_cpus == 1 || smp )) {
 		error = apm_get_power_status(&bx, &cx, &dx);
 		if (error)
 			printk(KERN_INFO "apm: power status not available\n");
@@ -1760,7 +1815,7 @@
 		pm_power_off = apm_power_off;
 	register_sysrq_key('o', &sysrq_poweroff_op);
 
-	if (smp_num_cpus == 1) {
+	if (smp_num_cpus == 1 || smp) {
 #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
 		console_blank_hook = apm_console_blank;
 #endif
@@ -1799,6 +1854,11 @@
 			str += 3;
 		if (strncmp(str, "debug", 5) == 0)
 			debug = !invert;
+		if (strncmp(str, "smp", 3) == 0)
+		{
+			smp = !invert;
+			idle_threshold = 100;
+		}
 		if ((strncmp(str, "power-off", 9) == 0) ||
 		    (strncmp(str, "power_off", 9) == 0))
 			power_off = !invert;
@@ -1903,7 +1963,7 @@
 		printk(KERN_NOTICE "apm: disabled on user request.\n");
 		return -ENODEV;
 	}
-	if ((smp_num_cpus > 1) && !power_off) {
+	if ((smp_num_cpus > 1) && !power_off && !smp) {
 		printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n");
 		return -ENODEV;
 	}
@@ -1957,7 +2017,7 @@
 
 	kernel_thread(apm, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
 
-	if (smp_num_cpus > 1) {
+	if (smp_num_cpus > 1 && !smp) {
 		printk(KERN_NOTICE
 		   "apm: disabled - APM is not SMP safe (power off active).\n");
 		return 0;
@@ -2025,5 +2085,8 @@
 MODULE_PARM(idle_period, "i");
 MODULE_PARM_DESC(idle_period,
 	"Period (in sec/100) over which to caculate the idle percentage");
+MODULE_PARM(smp, "i");
+MODULE_PARM_DESC(smp,
+	"Set this to enable APM use on an SMP platform. Use with caution on older systems");
 
 EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/bluesmoke.c linux-2.4.21-pre6/arch/i386/kernel/bluesmoke.c
--- linux-2.4.20/arch/i386/kernel/bluesmoke.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/i386/kernel/bluesmoke.c	2003-03-26 23:49:25.000000000 +0000
@@ -221,7 +221,7 @@
 			/*
 			 *	AMD K7 machine check is Intel like
 			 */
-			if(c->x86 == 6)
+			if(c->x86 == 6 || c->x86 == 15)
 				intel_mcheck_init(c);
 			break;
 		case X86_VENDOR_INTEL:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/dmi_scan.c linux-2.4.21-pre6/arch/i386/kernel/dmi_scan.c
--- linux-2.4.20/arch/i386/kernel/dmi_scan.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/i386/kernel/dmi_scan.c	2003-03-26 23:49:29.000000000 +0000
@@ -99,14 +99,6 @@
 	u8 buf[15];
 	u32 fp=0xF0000;
 
-#ifdef CONFIG_SIMNOW
-	/*
- 	 *	Skip on x86/64 with simnow. Will eventually go away
- 	 *	If you see this ifdef in 2.6pre mail me !
- 	 */
-	return -1;
-#endif
- 	
 	while( fp < 0xFFFFF)
 	{
 		isa_memcpy_fromio(buf, fp, 15);
@@ -435,17 +427,6 @@
 }
 
 /*
- * ASUS K7V-RM has broken ACPI table defining sleep modes
- */
-
-static __init int broken_acpi_Sx(struct dmi_blacklist *d)
-{
-	printk(KERN_WARNING "Detected ASUS mainboard with broken ACPI sleep table\n");
-	dmi_broken |= BROKEN_ACPI_Sx;
-	return 0;
-}
-
-/*
  * Toshiba keyboard likes to repeat keys when they are not repeated.
  */
 
@@ -694,6 +675,18 @@
 			MATCH(DMI_BIOS_VERSION, "R0204P1"),
 			MATCH(DMI_BIOS_DATE, "09/12/00"), NO_MATCH
 			} },
+			
+	{ swab_apm_power_in_minutes, "Sony VAIO", {	/* Handle problems with APM on Sony Vaio PCG-Z600RE */
+			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
+			MATCH(DMI_BIOS_VERSION, "R0116Z1"),
+			NO_MATCH, NO_MATCH
+			} },
+	
+	{ swab_apm_power_in_minutes, "Sony VAIO", {	/* Handle problems with APM on Sony Vaio PCG-Z600RE */
+			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
+			MATCH(DMI_BIOS_VERSION, "RK116Z1"),
+			NO_MATCH, NO_MATCH
+			} },
 
 	/* Machines which have problems handling enabled local APICs */
 
@@ -760,12 +753,6 @@
 			NO_MATCH, NO_MATCH, NO_MATCH
 			} },
 			
-	{ broken_acpi_Sx, "ASUS K7V-RM", {		/* Bad ACPI Sx table */
-			MATCH(DMI_BIOS_VERSION,"ASUS K7V-RM ACPI BIOS Revision 1003A"),
-			MATCH(DMI_BOARD_NAME, "<K7V-RM>"),
-			NO_MATCH, NO_MATCH
-			} },
-			
 	{ broken_toshiba_keyboard, "Toshiba Satellite 4030cdt", { /* Keyboard generates spurious repeats */
 			MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"),
 			NO_MATCH, NO_MATCH, NO_MATCH
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/entry.S linux-2.4.21-pre6/arch/i386/kernel/entry.S
--- linux-2.4.20/arch/i386/kernel/entry.S	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/i386/kernel/entry.S	2003-03-26 23:49:19.000000000 +0000
@@ -643,7 +643,7 @@
 	.long SYMBOL_NAME(sys_lremovexattr)
 	.long SYMBOL_NAME(sys_fremovexattr)
  	.long SYMBOL_NAME(sys_tkill)
-	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for sendfile64 */
+	.long SYMBOL_NAME(sys_sendfile64)
 	.long SYMBOL_NAME(sys_ni_syscall)	/* 240 reserved for futex */
 	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for sched_setaffinity */
 	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for sched_getaffinity */
@@ -657,6 +657,12 @@
 	.long SYMBOL_NAME(sys_ni_syscall)	/* 250 sys_alloc_hugepages */
 	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_free_hugepages */
 	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_exit_group */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_lookup_dcookie */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_epoll_create */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_epoll_ctl 255 */
+	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_epoll_wait */
+ 	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_remap_file_pages */
+ 	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_set_tid_address */
 
 	.rept NR_syscalls-(.-sys_call_table)/4
 		.long SYMBOL_NAME(sys_ni_syscall)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/head.S linux-2.4.21-pre6/arch/i386/kernel/head.S
--- linux-2.4.20/arch/i386/kernel/head.S	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/i386/kernel/head.S	2003-03-26 23:49:06.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- *  linux/arch/i386/head.S -- the 32-bit startup code.
+ *  linux/arch/i386/kernel/head.S -- the 32-bit startup code.
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/i386_ksyms.c linux-2.4.21-pre6/arch/i386/kernel/i386_ksyms.c
--- linux-2.4.20/arch/i386/kernel/i386_ksyms.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/i386/kernel/i386_ksyms.c	2003-03-26 23:49:35.000000000 +0000
@@ -86,6 +86,7 @@
 /* Networking helper routines. */
 EXPORT_SYMBOL(csum_partial_copy_generic);
 /* Delay loops */
+EXPORT_SYMBOL(__ndelay);
 EXPORT_SYMBOL(__udelay);
 EXPORT_SYMBOL(__delay);
 EXPORT_SYMBOL(__const_udelay);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/io_apic.c linux-2.4.21-pre6/arch/i386/kernel/io_apic.c
--- linux-2.4.20/arch/i386/kernel/io_apic.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/i386/kernel/io_apic.c	2003-03-26 23:49:25.000000000 +0000
@@ -292,7 +292,7 @@
 
 	Dprintk("querying PCI -> IRQ mapping bus:%d, slot:%d, pin:%d.\n",
 		bus, slot, pin);
-	if (mp_bus_id_to_pci_bus[bus] == -1) {
+	if ((mp_bus_id_to_pci_bus==NULL) || (mp_bus_id_to_pci_bus[bus] == -1)) {
 		printk(KERN_WARNING "PCI BIOS passed nonexistent PCI bus %d!\n", bus);
 		return -1;
 	}
@@ -739,8 +739,9 @@
 
 void __init UNEXPECTED_IO_APIC(void)
 {
-	printk(KERN_WARNING " WARNING: unexpected IO-APIC, please mail\n");
-	printk(KERN_WARNING "          to linux-smp@vger.kernel.org\n");
+	printk(KERN_WARNING 
+		"An unexpected IO-APIC was found. If this kernel release is less than\n"
+		"three months old please report this to linux-smp@vger.kernel.org\n");
 }
 
 void __init print_IO_APIC(void)
@@ -793,6 +794,7 @@
 	printk(KERN_DEBUG ".......     : PRQ implemented: %X\n", reg_01.PRQ);
 	printk(KERN_DEBUG ".......     : IO APIC version: %04X\n", reg_01.version);
 	if (	(reg_01.version != 0x01) && /* 82489DX IO-APICs */
+		(reg_01.version != 0x02) && /* VIA */
 		(reg_01.version != 0x10) && /* oldest IO-APICs */
 		(reg_01.version != 0x11) && /* Pentium/Pro IO-APICs */
 		(reg_01.version != 0x13) && /* Xeon IO-APICs */
@@ -1067,7 +1069,7 @@
 		
 		old_id = mp_ioapics[apic].mpc_apicid;
 
-		if (mp_ioapics[apic].mpc_apicid >= 0xf) {
+		if (mp_ioapics[apic].mpc_apicid >= apic_broadcast_id) {
 			printk(KERN_ERR "BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n",
 				apic, mp_ioapics[apic].mpc_apicid);
 			printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n",
@@ -1079,14 +1081,16 @@
 		 * Sanity check, is the ID really free? Every APIC in a
 		 * system must have a unique ID or we get lots of nice
 		 * 'stuck on smp_invalidate_needed IPI wait' messages.
+		 * I/O APIC IDs no longer have any meaning for xAPICs and SAPICs.
 		 */
-		if (phys_id_present_map & (1 << mp_ioapics[apic].mpc_apicid)) {
+		if ((clustered_apic_mode != CLUSTERED_APIC_XAPIC) &&
+		    (phys_id_present_map & (1 << mp_ioapics[apic].mpc_apicid))) {
 			printk(KERN_ERR "BIOS bug, IO-APIC#%d ID %d is already used!...\n",
 				apic, mp_ioapics[apic].mpc_apicid);
 			for (i = 0; i < 0xf; i++)
 				if (!(phys_id_present_map & (1 << i)))
 					break;
-			if (i >= 0xf)
+			if (i >= apic_broadcast_id)
 				panic("Max APIC ID exceeded!\n");
 			printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n",
 				i);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/microcode.c linux-2.4.21-pre6/arch/i386/kernel/microcode.c
--- linux-2.4.20/arch/i386/kernel/microcode.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/i386/kernel/microcode.c	2003-03-26 23:49:18.000000000 +0000
@@ -55,7 +55,7 @@
  *		Tigran Aivazian <tigran@veritas.com>,
  *		Serialize updates as required on HT processors due to speculative
  *		nature of implementation.
- *	1.11	22 Mar 2001 Tigran Aivazian <tigran@veritas.com>
+ *	1.11	22 Mar 2002 Tigran Aivazian <tigran@veritas.com>
  *		Fix the panic when writing zero-length microcode chunk.
  */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/mpparse.c linux-2.4.21-pre6/arch/i386/kernel/mpparse.c
--- linux-2.4.20/arch/i386/kernel/mpparse.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/i386/kernel/mpparse.c	2003-03-26 23:49:25.000000000 +0000
@@ -36,18 +36,20 @@
  * MP-table.
  */
 int apic_version [MAX_APICS];
-int mp_bus_id_to_type [MAX_MP_BUSSES];
-int mp_bus_id_to_node [MAX_MP_BUSSES];
-int mp_bus_id_to_local [MAX_MP_BUSSES];
 int quad_local_to_mp_bus_id [NR_CPUS/4][4];
-int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 };
 int mp_current_pci_id;
+int *mp_bus_id_to_type;
+int *mp_bus_id_to_node;
+int *mp_bus_id_to_local;
+int *mp_bus_id_to_pci_bus;
+int max_mp_busses;
+int max_irq_sources;
 
 /* I/O APIC entries */
 struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS];
 
 /* # of MP IRQ source entries */
-struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES];
+struct mpc_config_intsrc *mp_irqs;
 
 /* MP IRQ source entries */
 int mp_irq_entries;
@@ -65,8 +67,14 @@
 
 /* Bitmask of physically existing CPUs */
 unsigned long phys_cpu_present_map;
+unsigned long logical_cpu_present_map;
 
+#ifdef CONFIG_X86_CLUSTERED_APIC
 unsigned char esr_disable = 0;
+unsigned char clustered_apic_mode = CLUSTERED_APIC_NONE;
+unsigned int apic_broadcast_id = APIC_BROADCAST_ID_APIC;
+#endif
+unsigned char raw_phys_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
 
 /*
  * Intel MP BIOS table parsing routines:
@@ -118,6 +126,8 @@
 		case 0x0F:
 			if (model == 0x00)
 				return("Pentium 4(tm)");
+			if (model == 0x01)
+				return("Pentium 4(tm)");
 			if (model == 0x02)
 				return("Pentium 4(tm) XEON(tm)");
 			if (model == 0x0F)
@@ -226,16 +236,14 @@
 	if (m->mpc_apicid > MAX_APICS) {
 		printk("Processor #%d INVALID. (Max ID: %d).\n",
 			m->mpc_apicid, MAX_APICS);
-			--num_processors;
+		--num_processors;
 		return;
 	}
 	ver = m->mpc_apicver;
 
-	if (clustered_apic_mode == CLUSTERED_APIC_NUMAQ) {
-		phys_cpu_present_map |= (logical_apicid&0xf) << (4*quad);
-	} else {
-		phys_cpu_present_map |= 1 << m->mpc_apicid;
-	}
+	logical_cpu_present_map |= 1 << (num_processors-1);
+ 	phys_cpu_present_map |= apicid_to_phys_cpu_present(m->mpc_apicid);
+ 
 	/*
 	 * Validate version
 	 */
@@ -244,6 +252,7 @@
 		ver = 0x10;
 	}
 	apic_version[m->mpc_apicid] = ver;
+	raw_phys_apicid[num_processors - 1] = m->mpc_apicid;
 }
 
 static void __init MP_bus_info (struct mpc_config_bus *m)
@@ -308,7 +317,7 @@
 			m->mpc_irqtype, m->mpc_irqflag & 3,
 			(m->mpc_irqflag >> 2) & 3, m->mpc_srcbus,
 			m->mpc_srcbusirq, m->mpc_dstapic, m->mpc_dstirq);
-	if (++mp_irq_entries == MAX_IRQ_SOURCES)
+	if (++mp_irq_entries == max_irq_sources)
 		panic("Max # of irq sources exceeded!!\n");
 }
 
@@ -398,9 +407,12 @@
 
 static int __init smp_read_mpc(struct mp_config_table *mpc)
 {
-	char str[16];
+	char oem[16], prod[14];
 	int count=sizeof(*mpc);
 	unsigned char *mpt=((unsigned char *)mpc)+count;
+	int num_bus = 0;
+	int num_irq = 0;
+	unsigned char *bus_data;
 
 	if (memcmp(mpc->mpc_signature,MPC_SIGNATURE,4)) {
 		panic("SMP mptable: bad signature [%c%c%c%c]!\n",
@@ -423,14 +435,16 @@
 		printk(KERN_ERR "SMP mptable: null local APIC address!\n");
 		return 0;
 	}
-	memcpy(str,mpc->mpc_oem,8);
-	str[8]=0;
-	printk("OEM ID: %s ",str);
-
-	memcpy(str,mpc->mpc_productid,12);
-	str[12]=0;
-	printk("Product ID: %s ",str);
+	memcpy(oem,mpc->mpc_oem,8);
+	oem[8]=0;
+	printk("OEM ID: %s ",oem);
+
+	memcpy(prod,mpc->mpc_productid,12);
+	prod[12]=0;
+	printk("Product ID: %s ",prod);
 
+	detect_clustered_apic(oem, prod);
+	
 	printk("APIC at: 0x%lX\n",mpc->mpc_lapic);
 
 	/* save the local APIC address, it might be non-default,
@@ -446,9 +460,70 @@
 		mpc_record = 0;
 	}
 
+	/* Pre-scan to determine the number of bus and 
+	 * interrupts records we have
+	 */
+	while (count < mpc->mpc_length) {
+		switch (*mpt) {
+			case MP_PROCESSOR:
+				mpt += sizeof(struct mpc_config_processor);
+				count += sizeof(struct mpc_config_processor);
+				break;
+			case MP_BUS:
+				++num_bus;
+				mpt += sizeof(struct mpc_config_bus);
+				count += sizeof(struct mpc_config_bus);
+				break;
+			case MP_INTSRC:
+				++num_irq;
+				mpt += sizeof(struct mpc_config_intsrc);
+				count += sizeof(struct mpc_config_intsrc);
+				break;
+			case MP_IOAPIC:
+				mpt += sizeof(struct mpc_config_ioapic);
+				count += sizeof(struct mpc_config_ioapic);
+				break;
+			case MP_LINTSRC:
+				mpt += sizeof(struct mpc_config_lintsrc);
+				count += sizeof(struct mpc_config_lintsrc);
+				break;
+			default:
+				count = mpc->mpc_length;
+				break;
+		}
+	}
+	/* 
+	 * Paranoia: Allocate one extra of both the number of busses and number
+	 * of irqs, and make sure that we have at least 4 interrupts per PCI
+	 * slot.  But some machines do not report very many busses, so we need
+	 * to fall back on the older defaults.
+	 */
+	++num_bus;
+	max_mp_busses = max(num_bus, MAX_MP_BUSSES);
+	if (num_irq < (4 * max_mp_busses))
+		num_irq = 4 * num_bus;	/* 4 intr/PCI slot */
+	++num_irq;
+	max_irq_sources = max(num_irq, MAX_IRQ_SOURCES);
+	
+	count = (max_mp_busses * sizeof(int)) * 4;
+	count += (max_irq_sources * sizeof(struct mpc_config_intsrc));
+	bus_data = alloc_bootmem(count);
+	if (!bus_data) {
+		printk(KERN_ERR "SMP mptable: out of memory!\n");
+		return 0;
+	}
+	mp_bus_id_to_type = (int *)&bus_data[0];
+	mp_bus_id_to_node = (int *)&bus_data[(max_mp_busses * sizeof(int))];
+	mp_bus_id_to_local = (int *)&bus_data[(max_mp_busses * sizeof(int)) * 2];
+	mp_bus_id_to_pci_bus = (int *)&bus_data[(max_mp_busses * sizeof(int)) * 3];
+	mp_irqs = (struct mpc_config_intsrc *)&bus_data[(max_mp_busses * sizeof(int)) * 4];
+	memset(mp_bus_id_to_pci_bus, -1, max_mp_busses);
+
 	/*
 	 *	Now process the configuration blocks.
 	 */
+	count = sizeof(*mpc);
+	mpt = ((unsigned char *)mpc)+count;
 	while (count < mpc->mpc_length) {
 		switch(*mpt) {
 			case MP_PROCESSOR:
@@ -510,9 +585,19 @@
 	}
 
 	if (clustered_apic_mode){
-		esr_disable = 1;
+		phys_cpu_present_map = logical_cpu_present_map;
 	}
 
+
+	printk("Enabling APIC mode: ");
+	if(clustered_apic_mode == CLUSTERED_APIC_NUMAQ)
+		printk("Clustered Logical.	");
+	else if(clustered_apic_mode == CLUSTERED_APIC_XAPIC)
+		printk("Physical.	");
+	else
+		printk("Flat.	");
+	printk("Using %d I/O APICs\n",nr_ioapics);
+
 	if (!num_processors)
 		printk(KERN_ERR "SMP mptable: no processors registered!\n");
 	return num_processors;
@@ -808,18 +893,16 @@
 	 * there is a real-mode segmented pointer pointing to the
 	 * 4K EBDA area at 0x40E, calculate and scan it here.
 	 *
-	 * NOTE! There are Linux loaders that will corrupt the EBDA
+	 * NOTE! There were Linux loaders that will corrupt the EBDA
 	 * area, and as such this kind of SMP config may be less
 	 * trustworthy, simply because the SMP table may have been
-	 * stomped on during early boot. These loaders are buggy and
-	 * should be fixed.
+	 * stomped on during early boot.  Thankfully the bootloaders
+	 * now honour the EBDA.
 	 */
 
 	address = *(unsigned short *)phys_to_virt(0x40E);
 	address <<= 4;
 	smp_scan_config(address, 0x1000);
-	if (smp_found_config)
-		printk(KERN_WARNING "WARNING: MP table in the EBDA can be UNSAFE, contact linux-smp@vger.kernel.org if you experience SMP problems!\n");
 }
 
 #else
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/mtrr.c linux-2.4.21-pre6/arch/i386/kernel/mtrr.c
--- linux-2.4.20/arch/i386/kernel/mtrr.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/i386/kernel/mtrr.c	2003-03-26 23:48:59.000000000 +0000
@@ -492,6 +492,14 @@
 		return 0;
 		}
 	}
+	/* Intel 450NX errata # 23. Non ascending cachline evictions to
+	   write combining memory may resulting in data corruption */
+	dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, NULL);
+	if(dev)
+	{
+		printk(KERN_INFO "mtrr: Intel 450NX MMC detected. Write-combining disabled.\n");
+		return 0;
+	}		
 
     switch ( mtrr_if )
     {
@@ -2143,7 +2151,7 @@
 		   query the width (in bits) of the physical
 		   addressable memory on the Hammer family.
 		 */
-		if (boot_cpu_data.x86 == 7 && (cpuid_eax(0x80000000) >= 0x80000008)) {
+		if (boot_cpu_data.x86 == 15 && (cpuid_eax(0x80000000) >= 0x80000008)) {
 			u32	phys_addr;
 			phys_addr = cpuid_eax(0x80000008) & 0xff ;
 			size_or_mask = ~((1 << (phys_addr - PAGE_SHIFT)) - 1);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/nmi.c linux-2.4.21-pre6/arch/i386/kernel/nmi.c
--- linux-2.4.20/arch/i386/kernel/nmi.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/i386/kernel/nmi.c	2003-03-26 23:49:40.000000000 +0000
@@ -72,18 +72,21 @@
 
 int __init check_nmi_watchdog (void)
 {
-	irq_cpustat_t tmp[NR_CPUS];
+	unsigned int prev_nmi_count[NR_CPUS];
 	int j, cpu;
 
 	printk(KERN_INFO "testing NMI watchdog ... ");
 
-	memcpy(tmp, irq_stat, sizeof(tmp));
+	for (j = 0; j < smp_num_cpus; j++) {
+		cpu = cpu_logical_map(j);
+		prev_nmi_count[cpu] = irq_stat[cpu].__nmi_count;
+	}
 	sti();
 	mdelay((10*1000)/nmi_hz); // wait 10 ticks
 
 	for (j = 0; j < smp_num_cpus; j++) {
 		cpu = cpu_logical_map(j);
-		if (nmi_count(cpu) - tmp[cpu].__nmi_count <= 5) {
+		if (nmi_count(cpu) - prev_nmi_count[cpu] <= 5) {
 			printk("CPU#%d: NMI appears to be stuck!\n", cpu);
 			return -1;
 		}
@@ -119,7 +122,7 @@
 		nmi_watchdog = nmi;
 	if ((nmi == NMI_LOCAL_APIC) &&
 			(boot_cpu_data.x86_vendor == X86_VENDOR_AMD) &&
-			(boot_cpu_data.x86 == 6))
+	       	    ((boot_cpu_data.x86 == 6) || (boot_cpu_data.x86 == 15)))
 		nmi_watchdog = nmi;
 	/*
 	 * We can enable the IO-APIC watchdog
@@ -278,7 +281,7 @@
 {
 	switch (boot_cpu_data.x86_vendor) {
 	case X86_VENDOR_AMD:
-		if (boot_cpu_data.x86 != 6)
+		if (boot_cpu_data.x86 != 6 && boot_cpu_data.x86 != 15)
 			return;
 		setup_k7_watchdog();
 		break;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/pci-irq.c linux-2.4.21-pre6/arch/i386/kernel/pci-irq.c
--- linux-2.4.20/arch/i386/kernel/pci-irq.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/i386/kernel/pci-irq.c	2003-03-26 23:49:55.000000000 +0000
@@ -779,9 +779,16 @@
 void pcibios_enable_irq(struct pci_dev *dev)
 {
 	u8 pin;
+	extern int interrupt_line_quirk;
+	
 	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
 	if (pin && !pcibios_lookup_irq(dev, 1) && !dev->irq) {
 		char *msg;
+
+		/* With IDE legacy devices the IRQ lookup failure is not a problem.. */
+		if (dev->class >> 8 == PCI_CLASS_STORAGE_IDE && !(dev->class & 0x5))
+			return;
+
 		if (io_apic_assign_pci_irqs)
 			msg = " Probably buggy MP table.";
 		else if (pci_probe & PCI_BIOS_IRQ_SCAN)
@@ -791,4 +798,9 @@
 		printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s.%s\n",
 		       'A' + pin - 1, dev->slot_name, msg);
 	}
+	/* VIA bridges use interrupt line for apic/pci steering across
+	   the V-Link */
+	else if (interrupt_line_quirk)
+		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+		
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/process.c linux-2.4.21-pre6/arch/i386/kernel/process.c
--- linux-2.4.20/arch/i386/kernel/process.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/i386/kernel/process.c	2003-03-26 23:48:57.000000000 +0000
@@ -485,7 +485,7 @@
 /*
  * Create a kernel thread
  */
-int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 {
 	long retval, d0;
 
@@ -508,6 +508,7 @@
 		 "r" (arg), "r" (fn),
 		 "b" (flags | CLONE_VM)
 		: "memory");
+
 	return retval;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/setup.c linux-2.4.21-pre6/arch/i386/kernel/setup.c
--- linux-2.4.20/arch/i386/kernel/setup.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/i386/kernel/setup.c	2003-03-26 23:49:37.000000000 +0000
@@ -71,6 +71,9 @@
  *  CacheSize bug workaround updates for AMD, Intel & VIA Cyrix.
  *  Dave Jones <davej@suse.de>, September, October 2001.
  *
+ *  Provisions for empty E820 memory regions (reported by certain BIOSes).
+ *  Alex Achenbach <xela@slit.de>, December 2002.
+ *
  */
 
 /*
@@ -501,7 +504,7 @@
 	int chgidx, still_changing;
 	int overlap_entries;
 	int new_bios_entry;
-	int old_nr, new_nr;
+	int old_nr, new_nr, chg_nr;
 	int i;
 
 	/*
@@ -555,20 +558,24 @@
 	for (i=0; i < 2*old_nr; i++)
 		change_point[i] = &change_point_list[i];
 
-	/* record all known change-points (starting and ending addresses) */
+	/* record all known change-points (starting and ending addresses),
+	   omitting those that are for empty memory regions */
 	chgidx = 0;
 	for (i=0; i < old_nr; i++)	{
-		change_point[chgidx]->addr = biosmap[i].addr;
-		change_point[chgidx++]->pbios = &biosmap[i];
-		change_point[chgidx]->addr = biosmap[i].addr + biosmap[i].size;
-		change_point[chgidx++]->pbios = &biosmap[i];
+		if (biosmap[i].size != 0) {
+			change_point[chgidx]->addr = biosmap[i].addr;
+			change_point[chgidx++]->pbios = &biosmap[i];
+			change_point[chgidx]->addr = biosmap[i].addr + biosmap[i].size;
+			change_point[chgidx++]->pbios = &biosmap[i];
+		}
 	}
+	chg_nr = chgidx;    	/* true number of change-points */
 
 	/* sort change-point list by memory addresses (low -> high) */
 	still_changing = 1;
 	while (still_changing)	{
 		still_changing = 0;
-		for (i=1; i < 2*old_nr; i++)  {
+		for (i=1; i < chg_nr; i++)  {
 			/* if <current_addr> > <last_addr>, swap */
 			/* or, if current=<start_addr> & last=<end_addr>, swap */
 			if ((change_point[i]->addr < change_point[i-1]->addr) ||
@@ -591,7 +598,7 @@
 	last_type = 0;		 /* start with undefined memory type */
 	last_addr = 0;		 /* start with 0 as last starting address */
 	/* loop through change-points, determining affect on the new bios map */
-	for (chgidx=0; chgidx < 2*old_nr; chgidx++)
+	for (chgidx=0; chgidx < chg_nr; chgidx++)
 	{
 		/* keep track of all overlapping bios entries */
 		if (change_point[chgidx]->addr == change_point[chgidx]->pbios->addr)
@@ -1259,19 +1266,19 @@
 			l2size = 256;
 	}
 
-	/* Intel PIII Tualatin. This comes in two flavours.
-	 * One has 256kb of cache, the other 512. We have no way
-	 * to determine which, so we use a boottime override
-	 * for the 512kb model, and assume 256 otherwise.
-	 */
-	if ((c->x86_vendor == X86_VENDOR_INTEL) && (c->x86 == 6) &&
-		(c->x86_model == 11) && (l2size == 0))
-		l2size = 256;
-
-	/* VIA C3 CPUs (670-68F) need further shifting. */
-	if (c->x86_vendor == X86_VENDOR_CENTAUR && (c->x86 == 6) &&
-		((c->x86_model == 7) || (c->x86_model == 8))) {
-		l2size = l2size >> 8;
+	if (c->x86_vendor == X86_VENDOR_CENTAUR) {
+		/* VIA C3 CPUs (670-68F) need further shifting. */
+		if ((c->x86 == 6) &&
+		    ((c->x86_model == 7) || (c->x86_model == 8))) {
+			l2size >>= 8;
+		}
+
+		/* VIA also screwed up Nehemiah stepping 1, and made
+		   it return '65KB' instead of '64KB'
+		   - Note, it seems this may only be in engineering samples. */
+		if ((c->x86==6) && (c->x86_model==9) &&
+		    (c->x86_mask==1) && (l2size==65))
+			l2size -= 1;
 	}
 
 	/* Allow user to override all this if necessary. */
@@ -1421,7 +1428,7 @@
 			 * If the BIOS didn't enable it already, enable it
 			 * here.
 			 */
-			if (c->x86_model == 6 || c->x86_model == 7) {
+			if (c->x86_model >= 6 && c->x86_model <= 10) {
 				if (!test_bit(X86_FEATURE_XMM,
 					      &c->x86_capability)) {
 					printk(KERN_INFO
@@ -1433,8 +1440,20 @@
                                                 &c->x86_capability);
 				}
 			}
-			break;
 
+			/* It's been determined by AMD that Athlons since model 8 stepping 1
+			 * are more robust with CLK_CTL set to 200xxxxx instead of 600xxxxx
+			 * As per AMD technical note 27212 0.2
+			 */
+			if ((c->x86_model == 8 && c->x86_mask>=1) || (c->x86_model > 8)) {
+				rdmsr(MSR_K7_CLK_CTL, l, h);
+				if ((l & 0xfff00000) != 0x20000000) {
+					printk ("CPU: CLK_CTL MSR was %x. Reprogramming to %x\n", l,
+						((l & 0x000fffff)|0x20000000));
+					wrmsr(MSR_K7_CLK_CTL, (l & 0x000fffff)|0x20000000, h);
+				}
+			}
+			break;
 	}
 
 	display_cacheinfo(c);
@@ -1478,11 +1497,9 @@
 }
 
 /*
- * Cx86_dir0_msb is a HACK needed by check_cx686_cpuid/slop in bugs.h in
- * order to identify the Cyrix CPU model after we're out of setup.c
- *
- * Actually since bugs.h doesn't even reference this perhaps someone should
- * fix the documentation ???
+ * Cx86_dir0_msb is a HACK needed by check_cx686_cpuid/slop in
+ * order to identify the Cyrix CPU model after we're out of the
+ * initial setup.
  */
 static unsigned char Cx86_dir0_msb __initdata = 0;
 
@@ -2076,6 +2093,10 @@
 					set_bit(X86_FEATURE_CX8, &c->x86_capability);
 					set_bit(X86_FEATURE_3DNOW, &c->x86_capability);
 
+					/* fall through */
+
+				case 9: /* Nehemiah */
+				default:
 					get_model_name(c);
 					display_cacheinfo(c);
 					break;
@@ -2183,6 +2204,7 @@
 #define LVL_1_DATA      2
 #define LVL_2           3
 #define LVL_3           4
+#define LVL_TRACE       5
 
 struct _cache_table
 {
@@ -2202,6 +2224,9 @@
 	{ 0x23, LVL_3,      1024 },
 	{ 0x25, LVL_3,      2048 },
 	{ 0x29, LVL_3,      4096 },
+	{ 0x39, LVL_2,      128 },
+	{ 0x3b, LVL_2,      128 },
+	{ 0x3C, LVL_2,      256 },
 	{ 0x41, LVL_2,      128 },
 	{ 0x42, LVL_2,      256 },
 	{ 0x43, LVL_2,      512 },
@@ -2210,11 +2235,15 @@
 	{ 0x66, LVL_1_DATA, 8 },
 	{ 0x67, LVL_1_DATA, 16 },
 	{ 0x68, LVL_1_DATA, 32 },
+	{ 0x70, LVL_TRACE,  12 },
+	{ 0x71, LVL_TRACE,  16 },
+	{ 0x72, LVL_TRACE,  32 },
 	{ 0x79, LVL_2,      128 },
 	{ 0x7A, LVL_2,      256 },
 	{ 0x7B, LVL_2,      512 },
 	{ 0x7C, LVL_2,      1024 },
 	{ 0x82, LVL_2,      256 },
+	{ 0x83, LVL_2,      512 },
 	{ 0x84, LVL_2,      1024 },
 	{ 0x85, LVL_2,      2048 },
 	{ 0x00, 0, 0}
@@ -2222,7 +2251,7 @@
 
 static void __init init_intel(struct cpuinfo_x86 *c)
 {
-	unsigned int l1i = 0, l1d = 0, l2 = 0, l3 = 0; /* Cache sizes */
+	unsigned int trace = 0, l1i = 0, l1d = 0, l2 = 0, l3 = 0; /* Cache sizes */
 	char *p = NULL;
 #ifndef CONFIG_X86_F00F_WORKS_OK
 	static int f00f_workaround_enabled = 0;
@@ -2282,8 +2311,10 @@
 						case LVL_3:
 							l3 += cache_table[k].size;
 							break;
+						case LVL_TRACE:
+							trace += cache_table[k].size;
+							break;
 						}
-
 						break;
 					}
 
@@ -2291,9 +2322,25 @@
 				}
 			}
 		}
-		if ( l1i || l1d )
-			printk(KERN_INFO "CPU: L1 I cache: %dK, L1 D cache: %dK\n",
-			       l1i, l1d);
+
+		/* Intel PIII Tualatin. This comes in two flavours.
+		 * One has 256kb of cache, the other 512. We have no way
+		 * to determine which, so we use a boottime override
+		 * for the 512kb model, and assume 256 otherwise.
+		 */
+		if ((c->x86 == 6) && (c->x86_model == 11) && (l2 == 0))
+			l2 = 256;
+		/* Allow user to override all this if necessary. */
+		if (cachesize_override != -1)
+			l2 = cachesize_override;
+
+		if ( trace )
+			printk (KERN_INFO "CPU: Trace cache: %dK uops", trace);
+		else if ( l1i )
+			printk (KERN_INFO "CPU: L1 I cache: %dK", l1i);
+		if ( l1d )
+			printk(", L1 D cache: %dK\n", l1d);
+
 		if ( l2 )
 			printk(KERN_INFO "CPU: L2 cache: %dK\n", l2);
 		if ( l3 )
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/smp.c linux-2.4.21-pre6/arch/i386/kernel/smp.c
--- linux-2.4.20/arch/i386/kernel/smp.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/i386/kernel/smp.c	2003-03-26 23:49:05.000000000 +0000
@@ -214,7 +214,10 @@
 			/*
 			 * prepare target chip field
 			 */
-			cfg = __prepare_ICR2(cpu_to_logical_apicid(query_cpu));
+			if(clustered_apic_mode == CLUSTERED_APIC_XAPIC)
+				cfg = __prepare_ICR2(cpu_to_physical_apicid(query_cpu));
+			else
+				cfg = __prepare_ICR2(cpu_to_logical_apicid(query_cpu));
 			apic_write_around(APIC_ICR2, cfg);
 		
 			/*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/smpboot.c linux-2.4.21-pre6/arch/i386/kernel/smpboot.c
--- linux-2.4.20/arch/i386/kernel/smpboot.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/i386/kernel/smpboot.c	2003-03-26 23:49:38.000000000 +0000
@@ -410,7 +410,7 @@
 	Dprintk("CALLIN, before setup_local_APIC().\n");
 	/*
 	 * Because we use NMIs rather than the INIT-STARTUP sequence to
-	 * bootstrap the CPUs, the APIC may be in a wierd state. Kick it.
+	 * bootstrap the CPUs, the APIC may be in a weird state. Kick it.
 	 */
 	if (clustered_apic_mode)
 		clear_local_APIC();
@@ -525,12 +525,12 @@
 	int apicid, cpu;
 
 	for (apicid = 0; apicid < MAX_APICID; apicid++) {
-		physical_apicid_2_cpu[apicid] = -1;
-		logical_apicid_2_cpu[apicid] = -1;
+		physical_apicid_2_cpu[apicid] = BAD_APICID;
+		logical_apicid_2_cpu[apicid] = BAD_APICID;
 	}
 	for (cpu = 0; cpu < NR_CPUS; cpu++) {
-		cpu_2_physical_apicid[cpu] = -1;
-		cpu_2_logical_apicid[cpu] = -1;
+		cpu_2_physical_apicid[cpu] = BAD_APICID;
+		cpu_2_logical_apicid[cpu] = BAD_APICID;
 	}
 }
 
@@ -540,7 +540,7 @@
  * else physical apic ids
  */
 {
-	if (clustered_apic_mode) {
+	if (clustered_apic_mode == CLUSTERED_APIC_NUMAQ) {
 		logical_apicid_2_cpu[apicid] = cpu;	
 		cpu_2_logical_apicid[cpu] = apicid;
 	} else {
@@ -555,12 +555,12 @@
  * else physical apic ids
  */
 {
-	if (clustered_apic_mode) {
-		logical_apicid_2_cpu[apicid] = -1;	
-		cpu_2_logical_apicid[cpu] = -1;
+	if (clustered_apic_mode == CLUSTERED_APIC_NUMAQ) {
+		logical_apicid_2_cpu[apicid] = BAD_APICID;
+		cpu_2_logical_apicid[cpu] = BAD_APICID;
 	} else {
-		physical_apicid_2_cpu[apicid] = -1;	
-		cpu_2_physical_apicid[cpu] = -1;
+		physical_apicid_2_cpu[apicid] = BAD_APICID;
+		cpu_2_physical_apicid[cpu] = BAD_APICID;
 	}
 }
 
@@ -785,7 +785,7 @@
 	unsigned long boot_error = 0;
 	int timeout, cpu;
 	unsigned long start_eip;
-	unsigned short nmi_high, nmi_low;
+	unsigned short nmi_high = 0, nmi_low = 0;
 
 	cpu = ++cpucount;
 	/*
@@ -1019,7 +1019,10 @@
 	 * We have the boot CPU online for sure.
 	 */
 	set_bit(0, &cpu_online_map);
-	boot_cpu_logical_apicid = logical_smp_processor_id();
+	if (clustered_apic_mode == CLUSTERED_APIC_XAPIC)
+		boot_cpu_logical_apicid = physical_to_logical_apicid(boot_cpu_physical_apicid);
+	else
+		boot_cpu_logical_apicid = logical_smp_processor_id();
 	map_cpu_to_boot_apicid(0, boot_cpu_apicid);
 
 	global_irq_holder = 0;
@@ -1111,7 +1114,7 @@
 		if (apicid == boot_cpu_apicid)
 			continue;
 
-		if (!(phys_cpu_present_map & (1 << bit)))
+		if (!(phys_cpu_present_map & (1ul << bit)))
 			continue;
 		if ((max_cpus >= 0) && (max_cpus <= cpucount+1))
 			continue;
@@ -1122,9 +1125,9 @@
 		 * Make sure we unmap all failed CPUs
 		 */
 		if ((boot_apicid_to_cpu(apicid) == -1) &&
-				(phys_cpu_present_map & (1 << bit)))
-			printk("CPU #%d not responding - cannot use it.\n",
-								apicid);
+				(phys_cpu_present_map & (1ul << bit)))
+			printk("CPU #%d/0x%02x not responding - cannot use it.\n",
+								bit, apicid);
 	}
 
 	/*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/kernel/time.c linux-2.4.21-pre6/arch/i386/kernel/time.c
--- linux-2.4.20/arch/i386/kernel/time.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/i386/kernel/time.c	2003-03-26 23:49:38.000000000 +0000
@@ -256,12 +256,185 @@
 
 static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset;
 
+
+/* IBM Summit (EXA) Cyclone Timer code*/
+#ifdef CONFIG_X86_SUMMIT
+
+#define CYCLONE_CBAR_ADDR 0xFEB00CD0
+#define CYCLONE_PMCC_OFFSET 0x51A0
+#define CYCLONE_MPMC_OFFSET 0x51D0
+#define CYCLONE_MPCS_OFFSET 0x51A8
+#define CYCLONE_TIMER_FREQ 100000000
+
+int use_cyclone = 0;
+int __init cyclone_setup(char *str) 
+{
+	use_cyclone = 1;
+	return 1;
+}
+
+static u32* volatile cyclone_timer;	/* Cyclone MPMC0 register */
+static u32 last_cyclone_timer;
+
+static inline void mark_timeoffset_cyclone(void)
+{
+	int count;
+	unsigned long delta = last_cyclone_timer;
+	spin_lock(&i8253_lock);
+	/* quickly read the cyclone timer */
+	if(cyclone_timer)
+		last_cyclone_timer = cyclone_timer[0];
+
+	/* calculate delay_at_last_interrupt */
+	outb_p(0x00, 0x43);     /* latch the count ASAP */
+
+	count = inb_p(0x40);    /* read the latched count */
+	count |= inb(0x40) << 8;
+	spin_unlock(&i8253_lock);
+
+	/*lost tick compensation*/
+	delta = last_cyclone_timer - delta;
+	if(delta > loops_per_jiffy+2000){
+		delta = (delta/loops_per_jiffy)-1;
+		jiffies += delta;
+	}
+               
+	count = ((LATCH-1) - count) * TICK_SIZE;
+	delay_at_last_interrupt = (count + LATCH/2) / LATCH;
+}
+
+static unsigned long do_gettimeoffset_cyclone(void)
+{
+	u32 offset;
+
+	if(!cyclone_timer)
+		return delay_at_last_interrupt;
+
+	/* Read the cyclone timer */
+	offset = cyclone_timer[0];
+
+	/* .. relative to previous jiffy */
+	offset = offset - last_cyclone_timer;
+
+	/* convert cyclone ticks to microseconds */	
+	/* XXX slow, can we speed this up? */
+	offset = offset/(CYCLONE_TIMER_FREQ/1000000);
+
+	/* our adjusted time offset in microseconds */
+	return delay_at_last_interrupt + offset;
+}
+
+static void __init init_cyclone_clock(void)
+{
+	u32* reg;	
+	u32 base;		/* saved cyclone base address */
+	u32 pageaddr;	/* page that contains cyclone_timer register */
+	u32 offset;		/* offset from pageaddr to cyclone_timer register */
+	int i;
+	
+	printk(KERN_INFO "Summit chipset: Starting Cyclone Counter.\n");
+
+	/* find base address */
+	pageaddr = (CYCLONE_CBAR_ADDR)&PAGE_MASK;
+	offset = (CYCLONE_CBAR_ADDR)&(~PAGE_MASK);
+	set_fixmap_nocache(FIX_CYCLONE_TIMER, pageaddr);
+	reg = (u32*)(fix_to_virt(FIX_CYCLONE_TIMER) + offset);
+	if(!reg){
+		printk(KERN_ERR "Summit chipset: Could not find valid CBAR register.\n");
+		use_cyclone = 0;
+		return;
+	}
+	base = *reg;	
+	if(!base){
+		printk(KERN_ERR "Summit chipset: Could not find valid CBAR value.\n");
+		use_cyclone = 0;
+		return;
+	}
+	
+	/* setup PMCC */
+	pageaddr = (base + CYCLONE_PMCC_OFFSET)&PAGE_MASK;
+	offset = (base + CYCLONE_PMCC_OFFSET)&(~PAGE_MASK);
+	set_fixmap_nocache(FIX_CYCLONE_TIMER, pageaddr);
+	reg = (u32*)(fix_to_virt(FIX_CYCLONE_TIMER) + offset);
+	if(!reg){
+		printk(KERN_ERR "Summit chipset: Could not find valid PMCC register.\n");
+		use_cyclone = 0;
+		return;
+	}
+	reg[0] = 0x00000001;
+
+	/* setup MPCS */
+	pageaddr = (base + CYCLONE_MPCS_OFFSET)&PAGE_MASK;
+	offset = (base + CYCLONE_MPCS_OFFSET)&(~PAGE_MASK);
+	set_fixmap_nocache(FIX_CYCLONE_TIMER, pageaddr);
+	reg = (u32*)(fix_to_virt(FIX_CYCLONE_TIMER) + offset);
+	if(!reg){
+		printk(KERN_ERR "Summit chipset: Could not find valid MPCS register.\n");
+		use_cyclone = 0;
+		return;
+	}
+	reg[0] = 0x00000001;
+
+	/* map in cyclone_timer */
+	pageaddr = (base + CYCLONE_MPMC_OFFSET)&PAGE_MASK;
+	offset = (base + CYCLONE_MPMC_OFFSET)&(~PAGE_MASK);
+	set_fixmap_nocache(FIX_CYCLONE_TIMER, pageaddr);
+	cyclone_timer = (u32*)(fix_to_virt(FIX_CYCLONE_TIMER) + offset);
+	if(!cyclone_timer){
+		printk(KERN_ERR "Summit chipset: Could not find valid MPMC register.\n");
+		use_cyclone = 0;
+		return;
+	}
+
+	/*quick test to make sure its ticking*/
+	for(i=0; i<3; i++){
+		u32 old = cyclone_timer[0];
+		int stall = 100;
+		while(stall--) barrier();
+		if(cyclone_timer[0] == old){
+			printk(KERN_ERR "Summit chipset: Counter not counting! DISABLED\n");
+			cyclone_timer = 0;
+			use_cyclone = 0;
+			return;
+		}
+	}
+	/* Everything looks good, so set do_gettimeoffset */
+	do_gettimeoffset = do_gettimeoffset_cyclone;	
+}
+void __cyclone_delay(unsigned long loops)
+{
+	unsigned long bclock, now;
+	if(!cyclone_timer)
+		return;
+	bclock = cyclone_timer[0];
+	do {
+		rep_nop();
+		now = cyclone_timer[0];
+	} while ((now-bclock) < loops);
+}
+#endif /* CONFIG_X86_SUMMIT */
+
 #else
 
 #define do_gettimeoffset()	do_fast_gettimeoffset()
 
 #endif
 
+/* No-cyclone stubs */
+#ifndef CONFIG_X86_SUMMIT
+int __init cyclone_setup(char *str) 
+{
+	printk(KERN_ERR "cyclone: Kernel not compiled with CONFIG_X86_SUMMIT, cannot use the cyclone-timer.\n");
+	return 1;
+}
+
+const int use_cyclone = 0;
+static void mark_timeoffset_cyclone(void) {}
+static unsigned long do_gettimeoffset_cyclone(void) {return 0;}
+static void init_cyclone_clock(void) {}
+void __cyclone_delay(unsigned long loops) {}
+#endif /* CONFIG_X86_SUMMIT */
+
 /*
  * This version of gettimeofday has microsecond resolution
  * and better than microsecond precision on fast x86 machines with TSC.
@@ -481,8 +654,9 @@
 	 */
 	write_lock(&xtime_lock);
 
-	if (use_tsc)
-	{
+	if(use_cyclone)
+		mark_timeoffset_cyclone();
+	else if (use_tsc) {
 		/*
 		 * It is important that these two operations happen almost at
 		 * the same time. We do the RDTSC stuff first, since it's
@@ -504,12 +678,34 @@
 
 		count = inb_p(0x40);    /* read the latched count */
 		count |= inb(0x40) << 8;
+
+		/* Any unpaired read will cause the above to swap MSB/LSB
+		   forever.  Try to detect this and reset the counter. 
+		   
+		   This happens very occasionally with buggy SMM bios
+		   code at least */
+		   
+		if (count > LATCH) {
+			printk(KERN_WARNING 
+			       "i8253 count too high! resetting..\n");
+			outb_p(0x34, 0x43);
+			outb_p(LATCH & 0xff, 0x40);
+			outb(LATCH >> 8, 0x40);
+			count = LATCH - 1;
+		}
+
 		spin_unlock(&i8253_lock);
 
+		/* Some i8253 clones hold the LATCH value visible
+		   momentarily as they flip back to zero */
+		if (count == LATCH) {
+			count--;
+		}
+
 		count = ((LATCH-1) - count) * TICK_SIZE;
 		delay_at_last_interrupt = (count + LATCH/2) / LATCH;
 	}
- 
+
 	do_timer_interrupt(irq, NULL, regs);
 
 	write_unlock(&xtime_lock);
@@ -670,21 +866,30 @@
  	 */
  
  	dodgy_tsc();
- 	
+
+ 	if(use_cyclone)
+		init_cyclone_clock();
+		
 	if (cpu_has_tsc) {
 		unsigned long tsc_quotient = calibrate_tsc();
 		if (tsc_quotient) {
 			fast_gettimeoffset_quotient = tsc_quotient;
-			use_tsc = 1;
-			/*
-			 *	We could be more selective here I suspect
-			 *	and just enable this for the next intel chips ?
+			/* XXX: This is messy
+			 * However, we want to allow for the cyclone timer 
+			 * to work w/ or w/o the TSCs being avaliable
+			 *      -johnstul@us.ibm.com
 			 */
-			x86_udelay_tsc = 1;
+			if(!use_cyclone){
+				/*
+				 *	We could be more selective here I suspect
+				 *	and just enable this for the next intel chips ?
+			 	 */
+				use_tsc = 1;
+				x86_udelay_tsc = 1;
 #ifndef do_gettimeoffset
-			do_gettimeoffset = do_fast_gettimeoffset;
+				do_gettimeoffset = do_fast_gettimeoffset;
 #endif
-
+			}
 			/* report CPU clock rate in Hz.
 			 * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) =
 			 * clock/second. Our precision is about 100 ppm.
@@ -699,6 +904,7 @@
 		}
 	}
 
+
 #ifdef CONFIG_VISWS
 	printk("Starting Cobalt Timer system clock\n");
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/lib/delay.c linux-2.4.21-pre6/arch/i386/lib/delay.c
--- linux-2.4.20/arch/i386/lib/delay.c	2001-08-12 17:29:44.000000000 +0000
+++ linux-2.4.21-pre6/arch/i386/lib/delay.c	2003-03-26 23:49:54.000000000 +0000
@@ -56,10 +56,13 @@
 		:"=&a" (d0)
 		:"0" (loops));
 }
-
+extern __cyclone_delay(unsigned long loops);
+extern int use_cyclone;
 void __delay(unsigned long loops)
 {
-	if (x86_udelay_tsc)
+	if (use_cyclone)
+		__cyclone_delay(loops);
+	else if (x86_udelay_tsc)
 		__rdtsc_delay(loops);
 	else
 		__loop_delay(loops);
@@ -78,3 +81,8 @@
 {
 	__const_udelay(usecs * 0x000010c6);  /* 2**32 / 1000000 */
 }
+
+void __ndelay(unsigned long nsecs)
+{
+	__const_udelay(nsecs * 0x00005);  /* 2**32 / 1000000000 (rounded up) */
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/lib/usercopy.c linux-2.4.21-pre6/arch/i386/lib/usercopy.c
--- linux-2.4.20/arch/i386/lib/usercopy.c	2001-11-09 21:58:02.000000000 +0000
+++ linux-2.4.21-pre6/arch/i386/lib/usercopy.c	2003-03-26 23:48:57.000000000 +0000
@@ -95,6 +95,26 @@
 		: "memory");						   \
 } while (0)
 
+/**
+ * __strncpy_from_user: - Copy a NUL terminated string from userspace, with less checking.
+ * @dst:   Destination address, in kernel space.  This buffer must be at
+ *         least @count bytes long.
+ * @src:   Source address, in user space.
+ * @count: Maximum number of bytes to copy, including the trailing NUL.
+ * 
+ * Copies a NUL-terminated string from userspace to kernel space.
+ * Caller must check the specified block with access_ok() before calling
+ * this function.
+ *
+ * On success, returns the length of the string (not including the trailing
+ * NUL).
+ *
+ * If access to userspace fails, returns -EFAULT (some data may have been
+ * copied).
+ *
+ * If @count is smaller than the length of the string, copies @count bytes
+ * and returns @count.
+ */
 long
 __strncpy_from_user(char *dst, const char *src, long count)
 {
@@ -103,6 +123,24 @@
 	return res;
 }
 
+/**
+ * strncpy_from_user: - Copy a NUL terminated string from userspace.
+ * @dst:   Destination address, in kernel space.  This buffer must be at
+ *         least @count bytes long.
+ * @src:   Source address, in user space.
+ * @count: Maximum number of bytes to copy, including the trailing NUL.
+ * 
+ * Copies a NUL-terminated string from userspace to kernel space.
+ *
+ * On success, returns the length of the string (not including the trailing
+ * NUL).
+ *
+ * If access to userspace fails, returns -EFAULT (some data may have been
+ * copied).
+ *
+ * If @count is smaller than the length of the string, copies @count bytes
+ * and returns @count.
+ */
 long
 strncpy_from_user(char *dst, const char *src, long count)
 {
@@ -138,6 +176,16 @@
 		: "r"(size & 3), "0"(size / 4), "1"(addr), "a"(0));	\
 } while (0)
 
+/**
+ * clear_user: - Zero a block of memory in user space.
+ * @to:   Destination address, in user space.
+ * @n:    Number of bytes to zero.
+ *
+ * Zero a block of memory in user space.
+ *
+ * Returns number of bytes that could not be cleared.
+ * On success, this will be zero.
+ */
 unsigned long
 clear_user(void *to, unsigned long n)
 {
@@ -146,6 +194,17 @@
 	return n;
 }
 
+/**
+ * __clear_user: - Zero a block of memory in user space, with less checking.
+ * @to:   Destination address, in user space.
+ * @n:    Number of bytes to zero.
+ *
+ * Zero a block of memory in user space.  Caller must check
+ * the specified block with access_ok() before calling this function.
+ *
+ * Returns number of bytes that could not be cleared.
+ * On success, this will be zero.
+ */
 unsigned long
 __clear_user(void *to, unsigned long n)
 {
@@ -153,12 +212,17 @@
 	return n;
 }
 
-/*
- * Return the size of a string (including the ending 0)
+/**
+ * strlen_user: - Get the size of a string in user space.
+ * @str: The string to measure.
+ * @n:   The maximum valid length
  *
- * Return 0 on exception, a value greater than N if too long
+ * Get the size of a NUL-terminated string in user space.
+ *
+ * Returns the size of the string INCLUDING the terminating NUL.
+ * On exception, returns 0.
+ * If the string is too long, returns a value greater than @n.
  */
-
 long strnlen_user(const char *s, long n)
 {
 	unsigned long mask = -__addr_ok(s);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/i386/mm/init.c linux-2.4.21-pre6/arch/i386/mm/init.c
--- linux-2.4.20/arch/i386/mm/init.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/i386/mm/init.c	2003-03-26 23:49:18.000000000 +0000
@@ -356,7 +356,7 @@
 
 #if CONFIG_X86_PAE
 	/*
-	 * We will bail out later - printk doesnt work right now so
+	 * We will bail out later - printk doesn't work right now so
 	 * the user would just see a hanging kernel.
 	 */
 	if (cpu_has_pae)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/boot/bootloader.c linux-2.4.21-pre6/arch/ia64/boot/bootloader.c
--- linux-2.4.20/arch/ia64/boot/bootloader.c	2001-07-31 17:30:08.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/boot/bootloader.c	2003-03-26 23:49:54.000000000 +0000
@@ -53,6 +53,15 @@
 
 #include "../kernel/fw-emu.c"
 
+/*
+ * Set a break point on this function so that symbols are available to set breakpoints in
+ * the kernel being debugged.
+ */
+static void
+debug_break (void)
+{
+}
+
 static void
 cons_write (const char *buf)
 {
@@ -187,6 +196,7 @@
 
 	ssc(0, (long) kpath, 0, 0, SSC_LOAD_SYMBOLS);
 
+	debug_break();
 	asm volatile ("mov sp=%2; mov r28=%1; br.sptk.few %0"
 		      :: "b"(e_entry), "r"(bp), "r"(__pa(&stack)));
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/config.in linux-2.4.21-pre6/arch/ia64/config.in
--- linux-2.4.20/arch/ia64/config.in	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/config.in	2003-03-26 23:49:39.000000000 +0000
@@ -51,8 +51,6 @@
 	 64KB			CONFIG_IA64_PAGE_SIZE_64KB" 16KB
 fi
 
-bool 'Virtually mapped mem_map?' CONFIG_VIRTUAL_MEM_MAP n
-
 if [ "$CONFIG_ITANIUM" = "y" ]; then
 	define_bool CONFIG_IA64_BRL_EMU y
 	bool '  Enable Itanium B-step specific code' CONFIG_ITANIUM_BSTEP_SPECIFIC
@@ -65,10 +63,6 @@
 
 if [ "$CONFIG_MCKINLEY" = "y" ]; then
 	define_int CONFIG_IA64_L1_CACHE_SHIFT 7
-	bool '  Enable McKinley A-step specific code' CONFIG_MCKINLEY_ASTEP_SPECIFIC
-	if [ "$CONFIG_MCKINLEY_ASTEP_SPECIFIC" = "y" ]; then
-	  bool '   Enable McKinley A0/A1-step specific code' CONFIG_MCKINLEY_A0_SPECIFIC
-	fi
 fi
 
 if [ "$CONFIG_IA64_GENERIC" = "y" -o "$CONFIG_IA64_DIG" = "y" -o "$CONFIG_IA64_HP_ZX1" = "y" ]; then
@@ -256,10 +250,10 @@
   mainmenu_option next_comment
   comment 'Simulated drivers'
 
-  bool 'Simulated Ethernet ' CONFIG_SIMETH
-  bool 'Simulated serial driver support' CONFIG_SIM_SERIAL
+  bool 'Simulated Ethernet ' CONFIG_HP_SIMETH
+  bool 'Simulated serial driver support' CONFIG_HP_SIMSERIAL
   if [ "$CONFIG_SCSI" != "n" ]; then
-    bool 'Simulated SCSI disk' CONFIG_SCSI_SIM
+    bool 'Simulated SCSI disk' CONFIG_HP_SIMSCSI
   fi
   endmenu
 fi
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/configs/dig linux-2.4.21-pre6/arch/ia64/configs/dig
--- linux-2.4.20/arch/ia64/configs/dig	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/configs/dig	2003-03-26 23:49:49.000000000 +0000
@@ -0,0 +1,946 @@
+#
+# Automatically generated make config: don't edit
+#
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+# CONFIG_KMOD is not set
+
+#
+# General setup
+#
+CONFIG_IA64=y
+# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_MCA is not set
+# CONFIG_SBUS is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_ITANIUM=y
+# CONFIG_MCKINLEY is not set
+# CONFIG_IA64_GENERIC is not set
+CONFIG_IA64_DIG=y
+# CONFIG_IA64_HP_SIM is not set
+# CONFIG_IA64_HP_ZX1 is not set
+# CONFIG_IA64_SGI_SN1 is not set
+# CONFIG_IA64_SGI_SN2 is not set
+# CONFIG_IA64_PAGE_SIZE_4KB is not set
+# CONFIG_IA64_PAGE_SIZE_8KB is not set
+CONFIG_IA64_PAGE_SIZE_16KB=y
+CONFIG_IA64_BRL_EMU=y
+# CONFIG_ITANIUM_BSTEP_SPECIFIC is not set
+CONFIG_IA64_L1_CACHE_SHIFT=6
+CONFIG_IA64_MCA=y
+CONFIG_PM=y
+CONFIG_KCORE_ELF=y
+CONFIG_SMP=y
+CONFIG_IA32_SUPPORT=y
+CONFIG_PERFMON=y
+CONFIG_IA64_PALINFO=y
+CONFIG_EFI_VARS=y
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_ACPI=y
+CONFIG_ACPI_EFI=y
+CONFIG_ACPI_INTERPRETER=y
+CONFIG_ACPI_KERNEL_CONFIG=y
+
+#
+# ACPI Support
+#
+CONFIG_ACPI_PCI=y
+CONFIG_ACPI=y
+CONFIG_ACPI_EFI=y
+CONFIG_ACPI_BOOT=y
+CONFIG_ACPI_BUS=y
+CONFIG_ACPI_INTERPRETER=y
+CONFIG_ACPI_POWER=y
+CONFIG_ACPI_SYSTEM=y
+# CONFIG_ACPI_BUTTON is not set
+# CONFIG_ACPI_FAN is not set
+# CONFIG_ACPI_PROCESSOR is not set
+# CONFIG_ACPI_THERMAL is not set
+# CONFIG_ACPI_DEBUG is not set
+CONFIG_PCI=y
+CONFIG_PCI_NAMES=y
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETFILTER is not set
+CONFIG_FILTER=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE 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
+# CONFIG_VLAN_8021Q is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK 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
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_STATS is not set
+
+#
+# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_PCI is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Fusion MPT device support
+#
+CONFIG_FUSION=y
+CONFIG_FUSION_BOOT=y
+CONFIG_FUSION_MAX_SGE=40
+# CONFIG_FUSION_ISENSE is not set
+# CONFIG_FUSION_CTL is not set
+# CONFIG_FUSION_LAN is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+CONFIG_IDE=y
+
+#
+# IDE, ATA and ATAPI Block devices
+#
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_BLK_DEV_IDEDISK=y
+CONFIG_IDEDISK_MULTI_MODE=y
+# CONFIG_IDEDISK_STROKE is not set
+# CONFIG_BLK_DEV_IDECS is not set
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+CONFIG_BLK_DEV_IDEFLOPPY=y
+CONFIG_BLK_DEV_IDESCSI=y
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
+CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_BLK_DEV_GENERIC is not set
+CONFIG_IDEPCI_SHARE_IRQ=y
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+# CONFIG_IDEDMA_PCI_AUTO is not set
+# CONFIG_IDEDMA_ONLYDISK is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_PCI_WIP is not set
+CONFIG_BLK_DEV_ADMA=y
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_WDC_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_AMD74XX_OVERRIDE is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_HPT34X_AUTODMA is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+CONFIG_BLK_DEV_PIIX=y
+# CONFIG_BLK_DEV_NFORCE is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_PDC202XX_BURST is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_PDC202XX_FORCE is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SIS5513 is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_IDEDMA_IVB is not set
+# CONFIG_DMA_NONPCI is not set
+CONFIG_BLK_DEV_IDE_MODES=y
+# CONFIG_BLK_DEV_ATARAID is not set
+# CONFIG_BLK_DEV_ATARAID_PDC is not set
+# CONFIG_BLK_DEV_ATARAID_HPT is not set
+# CONFIG_BLK_DEV_ATARAID_SII is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_SD_EXTRA_DEVS=40
+# CONFIG_CHR_DEV_ST is not set
+# 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=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_DEBUG_QUEUES=y
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# 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_AACRAID is not set
+CONFIG_SCSI_AIC7XXX=y
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=253
+CONFIG_AIC7XXX_RESET_DELAY_MS=15000
+# CONFIG_AIC7XXX_PROBE_EISA_VL is not set
+# CONFIG_AIC7XXX_BUILD_FIRMWARE is not set
+# CONFIG_SCSI_DPT_I2O 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_CPQFCTS 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_SYM53C8XX_2=y
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+CONFIG_SCSI_QLOGIC_1280=y
+# CONFIG_SCSI_QLOGIC_QLA2100 is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+CONFIG_DUMMY=y
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_SUNLANCE is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNBMAC is not set
+# CONFIG_SUNQE is not set
+# CONFIG_SUNGEM is not set
+# 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_HP100 is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+CONFIG_TULIP=y
+# CONFIG_TULIP_MWI is not set
+# CONFIG_TULIP_MMIO is not set
+# CONFIG_DE4X5 is not set
+# CONFIG_DGRS is not set
+# CONFIG_DM9102 is not set
+CONFIG_EEPRO100=y
+# CONFIG_EEPRO100_PIO is not set
+# CONFIG_E100 is not set
+# CONFIG_LNE390 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_NE3210 is not set
+# CONFIG_ES3210 is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_8139TOO_PIO is not set
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_8139TOO_8129 is not set
+# CONFIG_8139_OLD_RX_RESET is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_SUNDANCE_MMIO is not set
+# CONFIG_TLAN is not set
+# CONFIG_TC35815 is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_VIA_RHINE_MMIO is not set
+# CONFIG_WINBOND_840 is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+CONFIG_E1000=y
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SK98LIN is not set
+CONFIG_TIGON3=y
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# 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
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Input core support
+#
+CONFIG_INPUT=y
+CONFIG_INPUT_KEYBDEV=y
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+CONFIG_SERIAL_HCDP=y
+CONFIG_SERIAL_ACPI=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+CONFIG_MOUSE=y
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+# CONFIG_MK712_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_INPUT_NS558 is not set
+# CONFIG_INPUT_LIGHTNING is not set
+# CONFIG_INPUT_PCIGAME is not set
+# CONFIG_INPUT_CS461X is not set
+# CONFIG_INPUT_EMU10K1 is not set
+CONFIG_INPUT_SERIO=y
+CONFIG_INPUT_SERPORT=y
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_ANALOG is not set
+# CONFIG_INPUT_A3D is not set
+# CONFIG_INPUT_ADI is not set
+# CONFIG_INPUT_COBRA is not set
+# CONFIG_INPUT_GF2K is not set
+# CONFIG_INPUT_GRIP is not set
+# CONFIG_INPUT_INTERACT is not set
+# CONFIG_INPUT_TMDC is not set
+# CONFIG_INPUT_SIDEWINDER is not set
+# CONFIG_INPUT_IFORCE_USB is not set
+# CONFIG_INPUT_IFORCE_232 is not set
+# CONFIG_INPUT_WARRIOR is not set
+# CONFIG_INPUT_MAGELLAN is not set
+# CONFIG_INPUT_SPACEORB is not set
+# CONFIG_INPUT_SPACEBALL is not set
+# CONFIG_INPUT_STINGER is not set
+# CONFIG_INPUT_DB9 is not set
+# CONFIG_INPUT_GAMECON is not set
+# CONFIG_INPUT_TURBOGRAFX is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_INTEL_RNG is not set
+# CONFIG_AMD_PM768 is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+CONFIG_EFI_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+CONFIG_AGP=y
+# CONFIG_AGP_INTEL is not set
+# CONFIG_AGP_I810 is not set
+# CONFIG_AGP_VIA is not set
+# CONFIG_AGP_AMD is not set
+# CONFIG_AGP_AMD_8151 is not set
+# CONFIG_AGP_SIS is not set
+# CONFIG_AGP_ALI is not set
+# CONFIG_AGP_SWORKS is not set
+CONFIG_AGP_I460=y
+CONFIG_AGP_HP_ZX1=y
+CONFIG_DRM=y
+# CONFIG_DRM_OLD is not set
+
+#
+# DRM 4.1 drivers
+#
+CONFIG_DRM_NEW=y
+# CONFIG_DRM_TDFX is not set
+CONFIG_DRM_R128=y
+CONFIG_DRM_RADEON=y
+# CONFIG_DRM_I810 is not set
+# CONFIG_DRM_I810_XFREE_41 is not set
+# CONFIG_DRM_I830 is not set
+# CONFIG_DRM_MGA is not set
+# CONFIG_DRM_SIS is not set
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=y
+
+#
+# Video For Linux
+#
+CONFIG_VIDEO_PROC_FS=y
+# CONFIG_I2C_PARPORT is not set
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_PMS is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_STRADIS is not set
+# CONFIG_VIDEO_ZORAN is not set
+# CONFIG_VIDEO_ZORAN_BUZ is not set
+# CONFIG_VIDEO_ZORAN_DC10 is not set
+# CONFIG_VIDEO_ZORAN_LML33 is not set
+# CONFIG_VIDEO_ZR36120 is not set
+# CONFIG_VIDEO_MEYE is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_GEMTEK_PCI is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_MAESTRO is not set
+# CONFIG_RADIO_MIROPCM20 is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+CONFIG_AUTOFS_FS=y
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BEFS_DEBUG is not set
+# CONFIG_BFS_FS is not set
+CONFIG_EXT3_FS=y
+CONFIG_JBD=y
+CONFIG_JBD_DEBUG=y
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+# CONFIG_UMSDOS_FS is not set
+CONFIG_VFAT_FS=y
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_TMPFS is not set
+CONFIG_RAMFS=y
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS 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
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG 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
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_ROOT_NFS is not set
+CONFIG_NFSD=y
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_TCP is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+
+#
+# Partition Types
+#
+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_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+CONFIG_EFI_PARTITION=y
+# CONFIG_SMB_NLS is not set
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Console drivers
+#
+CONFIG_VGA_CONSOLE=y
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+# CONFIG_SOUND_ALI5455 is not set
+# CONFIG_SOUND_BT878 is not set
+# CONFIG_SOUND_CMPCI is not set
+# CONFIG_SOUND_EMU10K1 is not set
+# CONFIG_MIDI_EMU10K1 is not set
+# CONFIG_SOUND_FUSION is not set
+CONFIG_SOUND_CS4281=y
+# CONFIG_SOUND_ES1370 is not set
+# CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_ESSSOLO1 is not set
+# CONFIG_SOUND_MAESTRO is not set
+# CONFIG_SOUND_MAESTRO3 is not set
+CONFIG_SOUND_FORTE=y
+# CONFIG_SOUND_ICH is not set
+# CONFIG_SOUND_RME96XX is not set
+# CONFIG_SOUND_SONICVIBES is not set
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_VIA82CXXX is not set
+# CONFIG_MIDI_VIA82CXXX is not set
+# CONFIG_SOUND_OSS is not set
+# CONFIG_SOUND_TVMIXER is not set
+
+#
+# USB support
+#
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+
+#
+# USB Host Controller Drivers
+#
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_UHCI=y
+# CONFIG_USB_UHCI_ALT is not set
+CONFIG_USB_OHCI=y
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_BLUETOOTH is not set
+# CONFIG_USB_MIDI is not set
+# CONFIG_USB_STORAGE is not set
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_HP8200e is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# USB Human Interface Devices (HID)
+#
+CONFIG_USB_HID=y
+CONFIG_USB_HIDINPUT=y
+CONFIG_USB_HIDDEV=y
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_POWERMATE is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_DC2XX is not set
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_SCANNER is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_KONICAWC is not set
+# CONFIG_USB_OV511 is not set
+# CONFIG_USB_PWC is not set
+# CONFIG_USB_SE401 is not set
+# CONFIG_USB_STV680 is not set
+# CONFIG_USB_VICAM is not set
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_DABUSB is not set
+
+#
+# USB Network adaptors
+#
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_CDCETHER is not set
+# CONFIG_USB_USBNET is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_USS720 is not set
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_TIGL is not set
+# CONFIG_USB_BRLVGER is not set
+# CONFIG_USB_LCD is not set
+
+#
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Kernel hacking
+#
+CONFIG_IA64_GRANULE_16MB=y
+# CONFIG_IA64_GRANULE_64MB is not set
+# CONFIG_DEBUG_KERNEL is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/configs/generic linux-2.4.21-pre6/arch/ia64/configs/generic
--- linux-2.4.20/arch/ia64/configs/generic	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/configs/generic	2003-03-26 23:49:00.000000000 +0000
@@ -0,0 +1,969 @@
+#
+# Automatically generated make config: don't edit
+#
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+# CONFIG_KMOD is not set
+
+#
+# General setup
+#
+CONFIG_IA64=y
+# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_MCA is not set
+# CONFIG_SBUS is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_ITANIUM=y
+# CONFIG_MCKINLEY is not set
+CONFIG_IA64_GENERIC=y
+# CONFIG_IA64_DIG is not set
+# CONFIG_IA64_HP_SIM is not set
+# CONFIG_IA64_HP_ZX1 is not set
+# CONFIG_IA64_SGI_SN1 is not set
+# CONFIG_IA64_SGI_SN2 is not set
+# CONFIG_IA64_PAGE_SIZE_4KB is not set
+# CONFIG_IA64_PAGE_SIZE_8KB is not set
+CONFIG_IA64_PAGE_SIZE_16KB=y
+CONFIG_IA64_BRL_EMU=y
+# CONFIG_ITANIUM_BSTEP_SPECIFIC is not set
+CONFIG_IA64_L1_CACHE_SHIFT=6
+CONFIG_IA64_MCA=y
+CONFIG_PM=y
+CONFIG_KCORE_ELF=y
+CONFIG_SMP=y
+CONFIG_IA32_SUPPORT=y
+CONFIG_PERFMON=y
+CONFIG_IA64_PALINFO=y
+CONFIG_EFI_VARS=y
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_ACPI=y
+CONFIG_ACPI_EFI=y
+CONFIG_ACPI_INTERPRETER=y
+CONFIG_ACPI_KERNEL_CONFIG=y
+
+#
+# ACPI Support
+#
+CONFIG_ACPI_PCI=y
+CONFIG_ACPI=y
+CONFIG_ACPI_EFI=y
+CONFIG_ACPI_BOOT=y
+CONFIG_ACPI_BUS=y
+CONFIG_ACPI_INTERPRETER=y
+CONFIG_ACPI_POWER=y
+CONFIG_ACPI_SYSTEM=y
+# CONFIG_ACPI_BUTTON is not set
+# CONFIG_ACPI_FAN is not set
+# CONFIG_ACPI_PROCESSOR is not set
+# CONFIG_ACPI_THERMAL is not set
+# CONFIG_ACPI_DEBUG is not set
+CONFIG_PCI=y
+CONFIG_PCI_NAMES=y
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETFILTER is not set
+CONFIG_FILTER=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE 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
+# CONFIG_VLAN_8021Q is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK 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
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_STATS is not set
+
+#
+# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_PCI is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Fusion MPT device support
+#
+CONFIG_FUSION=y
+CONFIG_FUSION_BOOT=y
+CONFIG_FUSION_MAX_SGE=40
+# CONFIG_FUSION_ISENSE is not set
+# CONFIG_FUSION_CTL is not set
+# CONFIG_FUSION_LAN is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+CONFIG_IDE=y
+
+#
+# IDE, ATA and ATAPI Block devices
+#
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_BLK_DEV_IDEDISK=y
+CONFIG_IDEDISK_MULTI_MODE=y
+# CONFIG_IDEDISK_STROKE is not set
+# CONFIG_BLK_DEV_IDECS is not set
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+CONFIG_BLK_DEV_IDEFLOPPY=y
+CONFIG_BLK_DEV_IDESCSI=y
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
+CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_BLK_DEV_GENERIC is not set
+CONFIG_IDEPCI_SHARE_IRQ=y
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+# CONFIG_IDEDMA_PCI_AUTO is not set
+# CONFIG_IDEDMA_ONLYDISK is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_PCI_WIP is not set
+CONFIG_BLK_DEV_ADMA=y
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_WDC_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_AMD74XX_OVERRIDE is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_HPT34X_AUTODMA is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+CONFIG_BLK_DEV_PIIX=y
+# CONFIG_BLK_DEV_NFORCE is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_PDC202XX_BURST is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_PDC202XX_FORCE is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SIS5513 is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_IDEDMA_IVB is not set
+# CONFIG_DMA_NONPCI is not set
+CONFIG_BLK_DEV_IDE_MODES=y
+# CONFIG_BLK_DEV_ATARAID is not set
+# CONFIG_BLK_DEV_ATARAID_PDC is not set
+# CONFIG_BLK_DEV_ATARAID_HPT is not set
+# CONFIG_BLK_DEV_ATARAID_SII is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_SD_EXTRA_DEVS=40
+# CONFIG_CHR_DEV_ST is not set
+# 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=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_DEBUG_QUEUES=y
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# 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_AACRAID is not set
+CONFIG_SCSI_AIC7XXX=y
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=253
+CONFIG_AIC7XXX_RESET_DELAY_MS=15000
+# CONFIG_AIC7XXX_PROBE_EISA_VL is not set
+# CONFIG_AIC7XXX_BUILD_FIRMWARE is not set
+# CONFIG_SCSI_DPT_I2O 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_CPQFCTS 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_SYM53C8XX_2 is not set
+# CONFIG_SCSI_NCR53C8XX is not set
+CONFIG_SCSI_SYM53C8XX=y
+CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
+CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
+CONFIG_SCSI_NCR53C8XX_SYNC=20
+# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
+# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set
+# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+CONFIG_SCSI_QLOGIC_1280=y
+# CONFIG_SCSI_QLOGIC_QLA2100 is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+CONFIG_DUMMY=y
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_SUNLANCE is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNBMAC is not set
+# CONFIG_SUNQE is not set
+# CONFIG_SUNGEM is not set
+# 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_HP100 is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+CONFIG_TULIP=y
+# CONFIG_TULIP_MWI is not set
+# CONFIG_TULIP_MMIO is not set
+# CONFIG_DE4X5 is not set
+# CONFIG_DGRS is not set
+# CONFIG_DM9102 is not set
+CONFIG_EEPRO100=y
+# CONFIG_EEPRO100_PIO is not set
+# CONFIG_E100 is not set
+# CONFIG_LNE390 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_NE3210 is not set
+# CONFIG_ES3210 is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_8139TOO_PIO is not set
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_8139TOO_8129 is not set
+# CONFIG_8139_OLD_RX_RESET is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_SUNDANCE_MMIO is not set
+# CONFIG_TLAN is not set
+# CONFIG_TC35815 is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_VIA_RHINE_MMIO is not set
+# CONFIG_WINBOND_840 is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+CONFIG_E1000=y
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SK98LIN is not set
+CONFIG_TIGON3=y
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# 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
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Input core support
+#
+CONFIG_INPUT=y
+CONFIG_INPUT_KEYBDEV=y
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+CONFIG_SERIAL_HCDP=y
+CONFIG_SERIAL_ACPI=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+CONFIG_MOUSE=y
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+# CONFIG_MK712_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_INPUT_NS558 is not set
+# CONFIG_INPUT_LIGHTNING is not set
+# CONFIG_INPUT_PCIGAME is not set
+# CONFIG_INPUT_CS461X is not set
+# CONFIG_INPUT_EMU10K1 is not set
+CONFIG_INPUT_SERIO=y
+CONFIG_INPUT_SERPORT=y
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_ANALOG is not set
+# CONFIG_INPUT_A3D is not set
+# CONFIG_INPUT_ADI is not set
+# CONFIG_INPUT_COBRA is not set
+# CONFIG_INPUT_GF2K is not set
+# CONFIG_INPUT_GRIP is not set
+# CONFIG_INPUT_INTERACT is not set
+# CONFIG_INPUT_TMDC is not set
+# CONFIG_INPUT_SIDEWINDER is not set
+# CONFIG_INPUT_IFORCE_USB is not set
+# CONFIG_INPUT_IFORCE_232 is not set
+# CONFIG_INPUT_WARRIOR is not set
+# CONFIG_INPUT_MAGELLAN is not set
+# CONFIG_INPUT_SPACEORB is not set
+# CONFIG_INPUT_SPACEBALL is not set
+# CONFIG_INPUT_STINGER is not set
+# CONFIG_INPUT_DB9 is not set
+# CONFIG_INPUT_GAMECON is not set
+# CONFIG_INPUT_TURBOGRAFX is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_INTEL_RNG is not set
+# CONFIG_AMD_PM768 is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+CONFIG_EFI_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+CONFIG_AGP=y
+# CONFIG_AGP_INTEL is not set
+# CONFIG_AGP_I810 is not set
+# CONFIG_AGP_VIA is not set
+# CONFIG_AGP_AMD is not set
+# CONFIG_AGP_AMD_8151 is not set
+# CONFIG_AGP_SIS is not set
+# CONFIG_AGP_ALI is not set
+# CONFIG_AGP_SWORKS is not set
+CONFIG_AGP_I460=y
+CONFIG_AGP_HP_ZX1=y
+CONFIG_DRM=y
+# CONFIG_DRM_OLD is not set
+
+#
+# DRM 4.1 drivers
+#
+CONFIG_DRM_NEW=y
+# CONFIG_DRM_TDFX is not set
+CONFIG_DRM_R128=y
+CONFIG_DRM_RADEON=y
+# CONFIG_DRM_I810 is not set
+# CONFIG_DRM_I810_XFREE_41 is not set
+# CONFIG_DRM_I830 is not set
+# CONFIG_DRM_MGA is not set
+# CONFIG_DRM_SIS is not set
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=y
+
+#
+# Video For Linux
+#
+CONFIG_VIDEO_PROC_FS=y
+# CONFIG_I2C_PARPORT is not set
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_PMS is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_STRADIS is not set
+# CONFIG_VIDEO_ZORAN is not set
+# CONFIG_VIDEO_ZORAN_BUZ is not set
+# CONFIG_VIDEO_ZORAN_DC10 is not set
+# CONFIG_VIDEO_ZORAN_LML33 is not set
+# CONFIG_VIDEO_ZR36120 is not set
+# CONFIG_VIDEO_MEYE is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_GEMTEK_PCI is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_MAESTRO is not set
+# CONFIG_RADIO_MIROPCM20 is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+CONFIG_AUTOFS_FS=y
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BEFS_DEBUG is not set
+# CONFIG_BFS_FS is not set
+CONFIG_EXT3_FS=y
+CONFIG_JBD=y
+CONFIG_JBD_DEBUG=y
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+# CONFIG_UMSDOS_FS is not set
+CONFIG_VFAT_FS=y
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_TMPFS is not set
+CONFIG_RAMFS=y
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS 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
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG 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
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_ROOT_NFS is not set
+CONFIG_NFSD=y
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_TCP is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+
+#
+# Partition Types
+#
+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_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+CONFIG_EFI_PARTITION=y
+# CONFIG_SMB_NLS is not set
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Console drivers
+#
+CONFIG_VGA_CONSOLE=y
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+# CONFIG_SOUND_ALI5455 is not set
+# CONFIG_SOUND_BT878 is not set
+# CONFIG_SOUND_CMPCI is not set
+# CONFIG_SOUND_EMU10K1 is not set
+# CONFIG_MIDI_EMU10K1 is not set
+# CONFIG_SOUND_FUSION is not set
+CONFIG_SOUND_CS4281=y
+# CONFIG_SOUND_ES1370 is not set
+# CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_ESSSOLO1 is not set
+# CONFIG_SOUND_MAESTRO is not set
+# CONFIG_SOUND_MAESTRO3 is not set
+# CONFIG_SOUND_FORTE is not set
+# CONFIG_SOUND_ICH is not set
+# CONFIG_SOUND_RME96XX is not set
+# CONFIG_SOUND_SONICVIBES is not set
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_VIA82CXXX is not set
+# CONFIG_MIDI_VIA82CXXX is not set
+# CONFIG_SOUND_OSS is not set
+# CONFIG_SOUND_TVMIXER is not set
+
+#
+# USB support
+#
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+
+#
+# USB Host Controller Drivers
+#
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_UHCI=y
+# CONFIG_USB_UHCI_ALT is not set
+CONFIG_USB_OHCI=y
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_BLUETOOTH is not set
+# CONFIG_USB_MIDI is not set
+# CONFIG_USB_STORAGE is not set
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_HP8200e is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# USB Human Interface Devices (HID)
+#
+CONFIG_USB_HID=y
+CONFIG_USB_HIDINPUT=y
+CONFIG_USB_HIDDEV=y
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_POWERMATE is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_DC2XX is not set
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_SCANNER is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_KONICAWC is not set
+# CONFIG_USB_OV511 is not set
+# CONFIG_USB_PWC is not set
+# CONFIG_USB_SE401 is not set
+# CONFIG_USB_STV680 is not set
+# CONFIG_USB_VICAM is not set
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_DABUSB is not set
+
+#
+# USB Network adaptors
+#
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_CDCETHER is not set
+# CONFIG_USB_USBNET is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_USS720 is not set
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_TIGL is not set
+# CONFIG_USB_BRLVGER is not set
+# CONFIG_USB_LCD is not set
+
+#
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Simulated drivers
+#
+# CONFIG_HP_SIMETH is not set
+# CONFIG_HP_SIMSERIAL is not set
+# CONFIG_HP_SIMSCSI is not set
+
+#
+# Kernel hacking
+#
+CONFIG_IA64_GRANULE_16MB=y
+# CONFIG_IA64_GRANULE_64MB is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_IA64_PRINT_HAZARDS=y
+# CONFIG_DISABLE_VHPT is not set
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_IA64_EARLY_PRINTK=y
+CONFIG_IA64_EARLY_PRINTK_UART=y
+CONFIG_IA64_EARLY_PRINTK_UART_BASE=0
+# CONFIG_IA64_EARLY_PRINTK_VGA is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_IA64_DEBUG_CMPXCHG is not set
+# CONFIG_IA64_DEBUG_IRQ is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/configs/ski linux-2.4.21-pre6/arch/ia64/configs/ski
--- linux-2.4.20/arch/ia64/configs/ski	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/configs/ski	2003-03-26 23:49:19.000000000 +0000
@@ -0,0 +1,468 @@
+#
+# Automatically generated make config: don't edit
+#
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+# CONFIG_KMOD is not set
+
+#
+# General setup
+#
+CONFIG_IA64=y
+# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_MCA is not set
+# CONFIG_SBUS is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_ITANIUM=y
+# CONFIG_MCKINLEY is not set
+# CONFIG_IA64_GENERIC is not set
+# CONFIG_IA64_DIG is not set
+CONFIG_IA64_HP_SIM=y
+# CONFIG_IA64_HP_ZX1 is not set
+# CONFIG_IA64_SGI_SN1 is not set
+# CONFIG_IA64_SGI_SN2 is not set
+# CONFIG_IA64_PAGE_SIZE_4KB is not set
+# CONFIG_IA64_PAGE_SIZE_8KB is not set
+CONFIG_IA64_PAGE_SIZE_16KB=y
+CONFIG_IA64_BRL_EMU=y
+# CONFIG_ITANIUM_BSTEP_SPECIFIC is not set
+CONFIG_IA64_L1_CACHE_SHIFT=6
+CONFIG_KCORE_ELF=y
+CONFIG_SMP=y
+CONFIG_IA32_SUPPORT=y
+CONFIG_PERFMON=y
+CONFIG_IA64_PALINFO=y
+CONFIG_EFI_VARS=y
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETFILTER is not set
+CONFIG_FILTER=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE 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
+# CONFIG_VLAN_8021Q is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK 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
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
+# Block devices
+#
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_SD_EXTRA_DEVS=40
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_DEBUG_QUEUES=y
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AACRAID is not set
+CONFIG_SCSI_AIC7XXX=y
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=253
+CONFIG_AIC7XXX_RESET_DELAY_MS=15000
+# CONFIG_AIC7XXX_PROBE_EISA_VL is not set
+# CONFIG_AIC7XXX_BUILD_FIRMWARE is not set
+# CONFIG_SCSI_DPT_I2O 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_PPA is not set
+# CONFIG_SCSI_IMM 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_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+CONFIG_SERIAL_HCDP=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+# CONFIG_PRINTER is not set
+# CONFIG_PPDEV is not set
+# CONFIG_TIPAR is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+CONFIG_MOUSE=y
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+# CONFIG_MK712_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+
+#
+# Input core support is needed for gameports
+#
+
+#
+# Input core support is needed for joysticks
+#
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_INTEL_RNG is not set
+# CONFIG_AMD_PM768 is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+CONFIG_EFI_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=y
+
+#
+# Video For Linux
+#
+CONFIG_VIDEO_PROC_FS=y
+# CONFIG_I2C_PARPORT is not set
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_PMS is not set
+# CONFIG_VIDEO_BWQCAM is not set
+# CONFIG_VIDEO_CQCAM is not set
+# CONFIG_VIDEO_W9966 is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_STRADIS is not set
+# CONFIG_VIDEO_ZORAN is not set
+# CONFIG_VIDEO_ZORAN_BUZ is not set
+# CONFIG_VIDEO_ZORAN_DC10 is not set
+# CONFIG_VIDEO_ZORAN_LML33 is not set
+# CONFIG_VIDEO_ZR36120 is not set
+# CONFIG_VIDEO_MEYE is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_GEMTEK_PCI is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_MAESTRO is not set
+# CONFIG_RADIO_MIROPCM20 is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+CONFIG_AUTOFS_FS=y
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BEFS_DEBUG is not set
+# CONFIG_BFS_FS is not set
+CONFIG_EXT3_FS=y
+CONFIG_JBD=y
+CONFIG_JBD_DEBUG=y
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+# CONFIG_UMSDOS_FS is not set
+CONFIG_VFAT_FS=y
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_TMPFS is not set
+CONFIG_RAMFS=y
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS 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
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG 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
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_ROOT_NFS is not set
+CONFIG_NFSD=y
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_TCP is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+
+#
+# Partition Types
+#
+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_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+CONFIG_EFI_PARTITION=y
+# CONFIG_SMB_NLS is not set
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Simulated drivers
+#
+CONFIG_HP_SIMETH=y
+CONFIG_HP_SIMSERIAL=y
+CONFIG_HP_SIMSCSI=y
+
+#
+# Kernel hacking
+#
+# CONFIG_IA64_GRANULE_16MB is not set
+CONFIG_IA64_GRANULE_64MB=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_IA64_PRINT_HAZARDS=y
+# CONFIG_DISABLE_VHPT is not set
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_IA64_EARLY_PRINTK=y
+CONFIG_IA64_EARLY_PRINTK_UART=y
+CONFIG_IA64_EARLY_PRINTK_UART_BASE=0
+# CONFIG_IA64_EARLY_PRINTK_VGA is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_IA64_DEBUG_CMPXCHG is not set
+# CONFIG_IA64_DEBUG_IRQ is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/configs/zx1 linux-2.4.21-pre6/arch/ia64/configs/zx1
--- linux-2.4.20/arch/ia64/configs/zx1	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/configs/zx1	2003-03-26 23:49:25.000000000 +0000
@@ -0,0 +1,956 @@
+#
+# Automatically generated make config: don't edit
+#
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+# CONFIG_KMOD is not set
+
+#
+# General setup
+#
+CONFIG_IA64=y
+# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_MCA is not set
+# CONFIG_SBUS is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+# CONFIG_ITANIUM is not set
+CONFIG_MCKINLEY=y
+# CONFIG_IA64_GENERIC is not set
+# CONFIG_IA64_DIG is not set
+# CONFIG_IA64_HP_SIM is not set
+CONFIG_IA64_HP_ZX1=y
+# CONFIG_IA64_SGI_SN1 is not set
+# CONFIG_IA64_SGI_SN2 is not set
+# CONFIG_IA64_PAGE_SIZE_4KB is not set
+# CONFIG_IA64_PAGE_SIZE_8KB is not set
+CONFIG_IA64_PAGE_SIZE_16KB=y
+# CONFIG_IA64_PAGE_SIZE_64KB is not set
+CONFIG_IA64_L1_CACHE_SHIFT=7
+CONFIG_IA64_MCA=y
+CONFIG_PM=y
+CONFIG_KCORE_ELF=y
+CONFIG_SMP=y
+CONFIG_IA32_SUPPORT=y
+CONFIG_PERFMON=y
+CONFIG_IA64_PALINFO=y
+CONFIG_EFI_VARS=y
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_ACPI=y
+CONFIG_ACPI_EFI=y
+CONFIG_ACPI_INTERPRETER=y
+CONFIG_ACPI_KERNEL_CONFIG=y
+
+#
+# ACPI Support
+#
+CONFIG_ACPI_PCI=y
+CONFIG_ACPI=y
+CONFIG_ACPI_EFI=y
+CONFIG_ACPI_BOOT=y
+CONFIG_ACPI_BUS=y
+CONFIG_ACPI_INTERPRETER=y
+CONFIG_ACPI_POWER=y
+CONFIG_ACPI_SYSTEM=y
+# CONFIG_ACPI_BUTTON is not set
+# CONFIG_ACPI_FAN is not set
+# CONFIG_ACPI_PROCESSOR is not set
+# CONFIG_ACPI_THERMAL is not set
+# CONFIG_ACPI_DEBUG is not set
+CONFIG_PCI=y
+CONFIG_PCI_NAMES=y
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETFILTER is not set
+CONFIG_FILTER=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE 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
+# CONFIG_VLAN_8021Q is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK 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
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_STATS is not set
+
+#
+# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_PCI is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Fusion MPT device support
+#
+CONFIG_FUSION=y
+CONFIG_FUSION_BOOT=y
+CONFIG_FUSION_MAX_SGE=40
+# CONFIG_FUSION_ISENSE is not set
+# CONFIG_FUSION_CTL is not set
+# CONFIG_FUSION_LAN is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+CONFIG_IDE=y
+
+#
+# IDE, ATA and ATAPI Block devices
+#
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_BLK_DEV_IDEDISK=y
+CONFIG_IDEDISK_MULTI_MODE=y
+# CONFIG_IDEDISK_STROKE is not set
+# CONFIG_BLK_DEV_IDECS is not set
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+CONFIG_BLK_DEV_IDEFLOPPY=y
+CONFIG_BLK_DEV_IDESCSI=y
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
+CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_BLK_DEV_GENERIC is not set
+CONFIG_IDEPCI_SHARE_IRQ=y
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+# CONFIG_IDEDMA_PCI_AUTO is not set
+# CONFIG_IDEDMA_ONLYDISK is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_PCI_WIP is not set
+CONFIG_BLK_DEV_ADMA=y
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_WDC_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_AMD74XX_OVERRIDE is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_HPT34X_AUTODMA is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+CONFIG_BLK_DEV_PIIX=y
+# CONFIG_BLK_DEV_NFORCE is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_PDC202XX_BURST is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_PDC202XX_FORCE is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SIS5513 is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_IDEDMA_IVB is not set
+# CONFIG_DMA_NONPCI is not set
+CONFIG_BLK_DEV_IDE_MODES=y
+# CONFIG_BLK_DEV_ATARAID is not set
+# CONFIG_BLK_DEV_ATARAID_PDC is not set
+# CONFIG_BLK_DEV_ATARAID_HPT is not set
+# CONFIG_BLK_DEV_ATARAID_SII is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_SD_EXTRA_DEVS=40
+# CONFIG_CHR_DEV_ST is not set
+# 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=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_DEBUG_QUEUES=y
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# 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_AACRAID is not set
+CONFIG_SCSI_AIC7XXX=y
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=253
+CONFIG_AIC7XXX_RESET_DELAY_MS=15000
+# CONFIG_AIC7XXX_PROBE_EISA_VL is not set
+# CONFIG_AIC7XXX_BUILD_FIRMWARE is not set
+# CONFIG_SCSI_DPT_I2O 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_CPQFCTS 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_SYM53C8XX_2=y
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+CONFIG_SCSI_QLOGIC_1280=y
+# CONFIG_SCSI_QLOGIC_QLA2100 is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+CONFIG_DUMMY=y
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_SUNLANCE is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNBMAC is not set
+# CONFIG_SUNQE is not set
+# CONFIG_SUNGEM is not set
+# 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_HP100 is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+CONFIG_TULIP=y
+# CONFIG_TULIP_MWI is not set
+# CONFIG_TULIP_MMIO is not set
+# CONFIG_DE4X5 is not set
+# CONFIG_DGRS is not set
+# CONFIG_DM9102 is not set
+CONFIG_EEPRO100=y
+# CONFIG_EEPRO100_PIO is not set
+# CONFIG_E100 is not set
+# CONFIG_LNE390 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_NE3210 is not set
+# CONFIG_ES3210 is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_8139TOO_PIO is not set
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_8139TOO_8129 is not set
+# CONFIG_8139_OLD_RX_RESET is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_SUNDANCE_MMIO is not set
+# CONFIG_TLAN is not set
+# CONFIG_TC35815 is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_VIA_RHINE_MMIO is not set
+# CONFIG_WINBOND_840 is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+CONFIG_E1000=y
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SK98LIN is not set
+CONFIG_TIGON3=y
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# 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
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Input core support
+#
+CONFIG_INPUT=y
+CONFIG_INPUT_KEYBDEV=y
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+CONFIG_SERIAL_HCDP=y
+CONFIG_SERIAL_ACPI=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+CONFIG_MOUSE=y
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+# CONFIG_MK712_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_INPUT_NS558 is not set
+# CONFIG_INPUT_LIGHTNING is not set
+# CONFIG_INPUT_PCIGAME is not set
+# CONFIG_INPUT_CS461X is not set
+# CONFIG_INPUT_EMU10K1 is not set
+CONFIG_INPUT_SERIO=y
+CONFIG_INPUT_SERPORT=y
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_ANALOG is not set
+# CONFIG_INPUT_A3D is not set
+# CONFIG_INPUT_ADI is not set
+# CONFIG_INPUT_COBRA is not set
+# CONFIG_INPUT_GF2K is not set
+# CONFIG_INPUT_GRIP is not set
+# CONFIG_INPUT_INTERACT is not set
+# CONFIG_INPUT_TMDC is not set
+# CONFIG_INPUT_SIDEWINDER is not set
+# CONFIG_INPUT_IFORCE_USB is not set
+# CONFIG_INPUT_IFORCE_232 is not set
+# CONFIG_INPUT_WARRIOR is not set
+# CONFIG_INPUT_MAGELLAN is not set
+# CONFIG_INPUT_SPACEORB is not set
+# CONFIG_INPUT_SPACEBALL is not set
+# CONFIG_INPUT_STINGER is not set
+# CONFIG_INPUT_DB9 is not set
+# CONFIG_INPUT_GAMECON is not set
+# CONFIG_INPUT_TURBOGRAFX is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_INTEL_RNG is not set
+# CONFIG_AMD_PM768 is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+CONFIG_EFI_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+CONFIG_AGP=y
+# CONFIG_AGP_INTEL is not set
+# CONFIG_AGP_I810 is not set
+# CONFIG_AGP_VIA is not set
+# CONFIG_AGP_AMD is not set
+# CONFIG_AGP_AMD_8151 is not set
+# CONFIG_AGP_SIS is not set
+# CONFIG_AGP_ALI is not set
+# CONFIG_AGP_SWORKS is not set
+CONFIG_AGP_I460=y
+CONFIG_AGP_HP_ZX1=y
+CONFIG_DRM=y
+# CONFIG_DRM_OLD is not set
+
+#
+# DRM 4.1 drivers
+#
+CONFIG_DRM_NEW=y
+# CONFIG_DRM_TDFX is not set
+CONFIG_DRM_R128=y
+CONFIG_DRM_RADEON=y
+# CONFIG_DRM_I810 is not set
+# CONFIG_DRM_I810_XFREE_41 is not set
+# CONFIG_DRM_I830 is not set
+# CONFIG_DRM_MGA is not set
+# CONFIG_DRM_SIS is not set
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=y
+
+#
+# Video For Linux
+#
+CONFIG_VIDEO_PROC_FS=y
+# CONFIG_I2C_PARPORT is not set
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_PMS is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_STRADIS is not set
+# CONFIG_VIDEO_ZORAN is not set
+# CONFIG_VIDEO_ZORAN_BUZ is not set
+# CONFIG_VIDEO_ZORAN_DC10 is not set
+# CONFIG_VIDEO_ZORAN_LML33 is not set
+# CONFIG_VIDEO_ZR36120 is not set
+# CONFIG_VIDEO_MEYE is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_GEMTEK_PCI is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_MAESTRO is not set
+# CONFIG_RADIO_MIROPCM20 is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+CONFIG_AUTOFS_FS=y
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BEFS_DEBUG is not set
+# CONFIG_BFS_FS is not set
+CONFIG_EXT3_FS=y
+CONFIG_JBD=y
+CONFIG_JBD_DEBUG=y
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+# CONFIG_UMSDOS_FS is not set
+CONFIG_VFAT_FS=y
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_TMPFS is not set
+CONFIG_RAMFS=y
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS 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
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG 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
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_ROOT_NFS is not set
+CONFIG_NFSD=y
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_TCP is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+
+#
+# Partition Types
+#
+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_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+CONFIG_EFI_PARTITION=y
+# CONFIG_SMB_NLS is not set
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Console drivers
+#
+CONFIG_VGA_CONSOLE=y
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+# CONFIG_SOUND_ALI5455 is not set
+# CONFIG_SOUND_BT878 is not set
+# CONFIG_SOUND_CMPCI is not set
+# CONFIG_SOUND_EMU10K1 is not set
+# CONFIG_MIDI_EMU10K1 is not set
+# CONFIG_SOUND_FUSION is not set
+CONFIG_SOUND_CS4281=y
+# CONFIG_SOUND_ES1370 is not set
+# CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_ESSSOLO1 is not set
+# CONFIG_SOUND_MAESTRO is not set
+# CONFIG_SOUND_MAESTRO3 is not set
+CONFIG_SOUND_FORTE=y
+# CONFIG_SOUND_ICH is not set
+# CONFIG_SOUND_RME96XX is not set
+# CONFIG_SOUND_SONICVIBES is not set
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_VIA82CXXX is not set
+# CONFIG_MIDI_VIA82CXXX is not set
+# CONFIG_SOUND_OSS is not set
+# CONFIG_SOUND_TVMIXER is not set
+
+#
+# USB support
+#
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+
+#
+# USB Host Controller Drivers
+#
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_UHCI=y
+# CONFIG_USB_UHCI_ALT is not set
+CONFIG_USB_OHCI=y
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_BLUETOOTH is not set
+# CONFIG_USB_MIDI is not set
+# CONFIG_USB_STORAGE is not set
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_HP8200e is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# USB Human Interface Devices (HID)
+#
+CONFIG_USB_HID=y
+CONFIG_USB_HIDINPUT=y
+CONFIG_USB_HIDDEV=y
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_POWERMATE is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_DC2XX is not set
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_SCANNER is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_KONICAWC is not set
+# CONFIG_USB_OV511 is not set
+# CONFIG_USB_PWC is not set
+# CONFIG_USB_SE401 is not set
+# CONFIG_USB_STV680 is not set
+# CONFIG_USB_VICAM is not set
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_DABUSB is not set
+
+#
+# USB Network adaptors
+#
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_CDCETHER is not set
+# CONFIG_USB_USBNET is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_USS720 is not set
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_TIGL is not set
+# CONFIG_USB_BRLVGER is not set
+# CONFIG_USB_LCD is not set
+
+#
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Kernel hacking
+#
+CONFIG_IA64_GRANULE_16MB=y
+# CONFIG_IA64_GRANULE_64MB is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_IA64_PRINT_HAZARDS=y
+# CONFIG_DISABLE_VHPT is not set
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_IA64_EARLY_PRINTK=y
+CONFIG_IA64_EARLY_PRINTK_UART=y
+CONFIG_IA64_EARLY_PRINTK_UART_BASE=0
+# CONFIG_IA64_EARLY_PRINTK_VGA is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_IA64_DEBUG_CMPXCHG is not set
+# CONFIG_IA64_DEBUG_IRQ is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/defconfig linux-2.4.21-pre6/arch/ia64/defconfig
--- linux-2.4.20/arch/ia64/defconfig	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/defconfig	2003-03-26 23:49:05.000000000 +0000
@@ -35,7 +35,6 @@
 # CONFIG_IA64_PAGE_SIZE_4KB is not set
 # CONFIG_IA64_PAGE_SIZE_8KB is not set
 CONFIG_IA64_PAGE_SIZE_16KB=y
-CONFIG_VIRTUAL_MEM_MAP=y
 CONFIG_IA64_BRL_EMU=y
 # CONFIG_ITANIUM_BSTEP_SPECIFIC is not set
 CONFIG_IA64_L1_CACHE_SHIFT=6
@@ -164,6 +163,7 @@
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_RAM is not set
 # CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_STATS is not set
 
 #
 # IEEE 1394 (FireWire) support (EXPERIMENTAL)
@@ -197,6 +197,7 @@
 #
 CONFIG_FUSION=y
 CONFIG_FUSION_BOOT=y
+CONFIG_FUSION_MAX_SGE=40
 # CONFIG_FUSION_ISENSE is not set
 # CONFIG_FUSION_CTL is not set
 # CONFIG_FUSION_LAN is not set
@@ -219,15 +220,6 @@
 CONFIG_BLK_DEV_IDEDISK=y
 CONFIG_IDEDISK_MULTI_MODE=y
 # CONFIG_IDEDISK_STROKE is not set
-# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
-# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
-# CONFIG_BLK_DEV_IDEDISK_IBM is not set
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
 # CONFIG_BLK_DEV_IDECS is not set
 CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_IDETAPE is not set
@@ -241,8 +233,8 @@
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
 CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_BLK_DEV_GENERIC is not set
 CONFIG_IDEPCI_SHARE_IRQ=y
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
@@ -251,30 +243,31 @@
 # CONFIG_IDEDMA_ONLYDISK is not set
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_PCI_WIP is not set
-# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set
-# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
 CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_AEC62XX is not set
-# CONFIG_AEC62XX_TUNING is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
 # CONFIG_WDC_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD74XX is not set
 # CONFIG_AMD74XX_OVERRIDE is not set
 # CONFIG_BLK_DEV_CMD64X is not set
-# CONFIG_BLK_DEV_CMD680 is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5530 is not set
 # CONFIG_BLK_DEV_HPT34X is not set
 # CONFIG_HPT34X_AUTODMA is not set
 # CONFIG_BLK_DEV_HPT366 is not set
 CONFIG_BLK_DEV_PIIX=y
-# CONFIG_PIIX_TUNING is not set
+# CONFIG_BLK_DEV_NFORCE is not set
 # CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_PDC202XX is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
 # CONFIG_PDC202XX_BURST is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
 # CONFIG_PDC202XX_FORCE is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
 # CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
 # CONFIG_BLK_DEV_SIS5513 is not set
 # CONFIG_BLK_DEV_SLC90E66 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
@@ -287,6 +280,7 @@
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
+# CONFIG_BLK_DEV_ATARAID_SII is not set
 
 #
 # SCSI support
@@ -300,8 +294,10 @@
 CONFIG_SD_EXTRA_DEVS=40
 # CONFIG_CHR_DEV_ST is not set
 # CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-# CONFIG_CHR_DEV_SG 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=y
 
 #
 # Some SCSI devices (e.g. CD jukebox) support multiple LUNs
@@ -345,11 +341,16 @@
 # CONFIG_SCSI_INIA100 is not set
 # CONFIG_SCSI_NCR53C406A is not set
 # CONFIG_SCSI_NCR53C7xx is not set
-CONFIG_SCSI_SYM53C8XX_2=y
-CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
-CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
-CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
-# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_NCR53C8XX is not set
+CONFIG_SCSI_SYM53C8XX=y
+CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
+CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
+CONFIG_SCSI_NCR53C8XX_SYNC=20
+# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
+# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set
+# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
 # CONFIG_SCSI_PAS16 is not set
 # CONFIG_SCSI_PCI2000 is not set
 # CONFIG_SCSI_PCI2220I is not set
@@ -364,6 +365,7 @@
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
 
 #
@@ -398,17 +400,19 @@
 # CONFIG_NET_ISA is not set
 CONFIG_NET_PCI=y
 # CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
 # CONFIG_ADAPTEC_STARFIRE is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
 CONFIG_TULIP=y
-# CONFIG_TC35815 is not set
 # CONFIG_TULIP_MWI is not set
 # CONFIG_TULIP_MMIO is not set
 # CONFIG_DE4X5 is not set
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
 CONFIG_EEPRO100=y
+# CONFIG_EEPRO100_PIO is not set
+# CONFIG_E100 is not set
 # CONFIG_LNE390 is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
@@ -420,11 +424,13 @@
 # CONFIG_8139TOO_PIO is not set
 # CONFIG_8139TOO_TUNE_TWISTER is not set
 # CONFIG_8139TOO_8129 is not set
-# CONFIG_8139_NEW_RX_RESET is not set
+# CONFIG_8139_OLD_RX_RESET is not set
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
+# CONFIG_SUNDANCE_MMIO is not set
 # CONFIG_TLAN is not set
+# CONFIG_TC35815 is not set
 # CONFIG_VIA_RHINE is not set
 # CONFIG_VIA_RHINE_MMIO is not set
 # CONFIG_WINBOND_840 is not set
@@ -434,13 +440,13 @@
 # Ethernet (1000 Mbit)
 #
 # CONFIG_ACENIC is not set
-# CONFIG_NET_BROADCOM is not set
 # CONFIG_DL2K is not set
-# CONFIG_MYRI_SBUS is not set
 CONFIG_E1000=y
+# CONFIG_MYRI_SBUS is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 CONFIG_TIGON3=y
 # CONFIG_FDDI is not set
@@ -501,8 +507,8 @@
 CONFIG_SERIAL=y
 CONFIG_SERIAL_CONSOLE=y
 CONFIG_SERIAL_HCDP=y
+CONFIG_SERIAL_ACPI=y
 # CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_ACPI is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
@@ -557,12 +563,19 @@
 # CONFIG_INPUT_GAMECON is not set
 # CONFIG_INPUT_TURBOGRAFX is not set
 # CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
 # CONFIG_INTEL_RNG is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 CONFIG_EFI_RTC=y
@@ -579,23 +592,27 @@
 # CONFIG_AGP_I810 is not set
 # CONFIG_AGP_VIA is not set
 # CONFIG_AGP_AMD is not set
+# CONFIG_AGP_AMD_8151 is not set
 # CONFIG_AGP_SIS is not set
 # CONFIG_AGP_ALI is not set
 # CONFIG_AGP_SWORKS is not set
 CONFIG_AGP_I460=y
 CONFIG_AGP_HP_ZX1=y
 CONFIG_DRM=y
-CONFIG_DRM_OLD=y
+# CONFIG_DRM_OLD is not set
 
 #
-# DRM 4.0 drivers
+# DRM 4.1 drivers
 #
-CONFIG_DRM40_TDFX=y
-# CONFIG_DRM40_GAMMA is not set
-# CONFIG_DRM40_R128 is not set
-# CONFIG_DRM40_RADEON is not set
-# CONFIG_DRM40_I810 is not set
-# CONFIG_DRM40_MGA is not set
+CONFIG_DRM_NEW=y
+# CONFIG_DRM_TDFX is not set
+CONFIG_DRM_R128=y
+CONFIG_DRM_RADEON=y
+# CONFIG_DRM_I810 is not set
+# CONFIG_DRM_I810_XFREE_41 is not set
+# CONFIG_DRM_I830 is not set
+# CONFIG_DRM_MGA is not set
+# CONFIG_DRM_SIS is not set
 
 #
 # Multimedia devices
@@ -626,21 +643,10 @@
 #
 # Radio Adapters
 #
-# CONFIG_RADIO_CADET is not set
-# CONFIG_RADIO_RTRACK is not set
-# CONFIG_RADIO_RTRACK2 is not set
-# CONFIG_RADIO_AZTECH is not set
-# CONFIG_RADIO_GEMTEK is not set
 # CONFIG_RADIO_GEMTEK_PCI is not set
 # CONFIG_RADIO_MAXIRADIO is not set
 # CONFIG_RADIO_MAESTRO is not set
 # CONFIG_RADIO_MIROPCM20 is not set
-# CONFIG_RADIO_MIROPCM20_RDS is not set
-# CONFIG_RADIO_SF16FMI is not set
-# CONFIG_RADIO_TERRATEC is not set
-# CONFIG_RADIO_TRUST is not set
-# CONFIG_RADIO_TYPHOON is not set
-# CONFIG_RADIO_ZOLTRIX is not set
 
 #
 # File systems
@@ -655,9 +661,11 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BEFS_DEBUG is not set
 # CONFIG_BFS_FS is not set
-CONFIG_EXT3_FS=m
-CONFIG_JBD=m
+CONFIG_EXT3_FS=y
+CONFIG_JBD=y
 CONFIG_JBD_DEBUG=y
 CONFIG_FAT_FS=y
 CONFIG_MSDOS_FS=y
@@ -672,6 +680,9 @@
 CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
 # CONFIG_ZISOFS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
@@ -702,6 +713,7 @@
 # CONFIG_ROOT_NFS is not set
 CONFIG_NFSD=y
 CONFIG_NFSD_V3=y
+# CONFIG_NFSD_TCP is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
@@ -716,7 +728,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -796,9 +807,9 @@
 # Sound
 #
 CONFIG_SOUND=y
+# CONFIG_SOUND_ALI5455 is not set
 # CONFIG_SOUND_BT878 is not set
 # CONFIG_SOUND_CMPCI is not set
-# CONFIG_SOUND_FORTE is not set
 # CONFIG_SOUND_EMU10K1 is not set
 # CONFIG_MIDI_EMU10K1 is not set
 # CONFIG_SOUND_FUSION is not set
@@ -808,6 +819,7 @@
 # CONFIG_SOUND_ESSSOLO1 is not set
 # CONFIG_SOUND_MAESTRO is not set
 # CONFIG_SOUND_MAESTRO3 is not set
+# CONFIG_SOUND_FORTE is not set
 # CONFIG_SOUND_ICH is not set
 # CONFIG_SOUND_RME96XX is not set
 # CONFIG_SOUND_SONICVIBES is not set
@@ -830,15 +842,14 @@
 #
 CONFIG_USB_DEVICEFS=y
 # CONFIG_USB_BANDWIDTH is not set
-# CONFIG_USB_LONG_TIMEOUT is not set
 
 #
 # USB Host Controller Drivers
 #
-CONFIG_USB_EHCI_HCD=m
-CONFIG_USB_UHCI=m
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_UHCI=y
 # CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
+CONFIG_USB_OHCI=y
 
 #
 # USB Device Class drivers
@@ -846,6 +857,7 @@
 # CONFIG_USB_AUDIO is not set
 # CONFIG_USB_EMI26 is not set
 # CONFIG_USB_BLUETOOTH is not set
+# CONFIG_USB_MIDI is not set
 # CONFIG_USB_STORAGE is not set
 # CONFIG_USB_STORAGE_DEBUG is not set
 # CONFIG_USB_STORAGE_DATAFAB is not set
@@ -854,6 +866,7 @@
 # CONFIG_USB_STORAGE_DPCM is not set
 # CONFIG_USB_STORAGE_HP8200e is not set
 # CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
 # CONFIG_USB_STORAGE_JUMPSHOT is not set
 # CONFIG_USB_ACM is not set
 # CONFIG_USB_PRINTER is not set
@@ -861,12 +874,12 @@
 #
 # USB Human Interface Devices (HID)
 #
-CONFIG_USB_HID=m
+CONFIG_USB_HID=y
 CONFIG_USB_HIDINPUT=y
 CONFIG_USB_HIDDEV=y
-CONFIG_USB_KBD=m
-CONFIG_USB_MOUSE=m
+# CONFIG_USB_AIPTEK is not set
 # CONFIG_USB_WACOM is not set
+# CONFIG_USB_POWERMATE is not set
 
 #
 # USB Imaging devices
@@ -881,6 +894,7 @@
 # USB Multimedia devices
 #
 # CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_KONICAWC is not set
 # CONFIG_USB_OV511 is not set
 # CONFIG_USB_PWC is not set
 # CONFIG_USB_SE401 is not set
@@ -908,39 +922,21 @@
 # USB Serial Converter support
 #
 # CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IPAQ is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_KLSI is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
 
 #
 # USB Miscellaneous drivers
 #
 # CONFIG_USB_RIO500 is not set
 # CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_TIGL is not set
 # CONFIG_USB_BRLVGER is not set
+# CONFIG_USB_LCD is not set
+
+#
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
 
 #
 # Bluetooth support
@@ -950,15 +946,15 @@
 #
 # Simulated drivers
 #
-# CONFIG_SIMETH is not set
-# CONFIG_SIM_SERIAL is not set
-# CONFIG_SCSI_SIM is not set
+# CONFIG_HP_SIMETH is not set
+# CONFIG_HP_SIMSERIAL is not set
+# CONFIG_HP_SIMSCSI is not set
 
 #
 # Kernel hacking
 #
-# CONFIG_IA64_GRANULE_16MB is not set
-CONFIG_IA64_GRANULE_64MB=y
+CONFIG_IA64_GRANULE_16MB=y
+# CONFIG_IA64_GRANULE_64MB is not set
 CONFIG_DEBUG_KERNEL=y
 CONFIG_IA64_PRINT_HAZARDS=y
 # CONFIG_DISABLE_VHPT is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/hp/common/sba_iommu.c linux-2.4.21-pre6/arch/ia64/hp/common/sba_iommu.c
--- linux-2.4.20/arch/ia64/hp/common/sba_iommu.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/hp/common/sba_iommu.c	2003-03-26 23:49:41.000000000 +0000
@@ -39,8 +39,25 @@
 
 #define PFX "IOC: "
 
+/*
+** This option allows cards capable of 64bit DMA to bypass the IOMMU.  If
+** not defined, all DMA will be 32bit and go through the TLB.
+*/
 #define ALLOW_IOV_BYPASS
+
+/*
+** If a device prefetches beyond the end of a valid pdir entry, it will cause
+** a hard failure, ie. MCA.  Version 3.0 and later of the zx1 LBA should
+** disconnect on 4k boundaries and prevent such issues.  If the device is
+** particularly agressive, this option will keep the entire pdir valid such
+** that prefetching will hit a valid address.  This could severely impact
+** error containment, and is therefore off by default.  The page that is
+** used for spill-over is poisoned, so that should help debugging somewhat.
+*/
+#undef FULL_VALID_PDIR
+
 #define ENABLE_MARK_CLEAN
+
 /*
 ** The number of debug flags is a clue - this code is fragile.
 */
@@ -52,6 +69,10 @@
 #undef DEBUG_LARGE_SG_ENTRIES
 #undef DEBUG_BYPASS
 
+#if defined(FULL_VALID_PDIR) && defined(ASSERT_PDIR_SANITY)
+#error FULL_VALID_PDIR and ASSERT_PDIR_SANITY are mutually exclusive
+#endif
+
 #define SBA_INLINE	__inline__
 /* #define SBA_INLINE */
 
@@ -196,9 +217,12 @@
 static struct ioc *ioc_list;
 static int reserve_sba_gart = 1;
 
-#define sba_sg_iova(sg) (sg->address)
-#define sba_sg_len(sg) (sg->length)
-#define sba_sg_buffer(sg) (sg->orig_address)
+#define sba_sg_address(sg)	(sg->address ? sg->address : \
+				       page_address((sg)->page) + (sg)->offset)
+
+#ifdef FULL_VALID_PDIR
+static void* prefetch_spill_page;
+#endif
 
 #define GET_IOC(dev)	((struct ioc *) PCI_CONTROLLER(dev)->iommu)
 
@@ -338,10 +362,8 @@
 {
 	while (nents-- > 0) {
 		printk(" %d : %08lx/%05x %p\n",
-				nents,
-				(unsigned long) sba_sg_iova(startsg),
-				sba_sg_len(startsg),
-				sba_sg_buffer(startsg));
+				nents, startsg->dma_address,
+				startsg->dma_length, sba_sg_address(startsg));
 		startsg++;
 	}
 }
@@ -352,7 +374,7 @@
 	int the_nents = nents;
 
 	while (the_nents-- > 0) {
-		if (sba_sg_buffer(the_sg) == 0x0UL)
+		if (sba_sg_address(the_sg) == 0x0UL)
 			sba_dump_sg(NULL, startsg, nents);
 		the_sg++;
 	}
@@ -626,7 +648,7 @@
 	pg_addr = PAGE_ALIGN((unsigned long) addr);
 	end = (unsigned long) addr + size;
 	while (pg_addr + PAGE_SIZE <= end) {
-		struct page *page = virt_to_page(pg_addr);
+		struct page *page = virt_to_page((void *)pg_addr);
 		set_bit(PG_arch_1, &page->flags);
 		pg_addr += PAGE_SIZE;
 	}
@@ -673,6 +695,7 @@
 
 		iovp |= IOVP_SHIFT;     /* set "size" field for PCOM */
 
+#ifndef FULL_VALID_PDIR
 		/*
 		** clear I/O PDIR entry "valid" bit
 		** Do NOT clear the rest - save it for debugging.
@@ -680,6 +703,14 @@
 		** been enabled.
 		*/
 		ioc->pdir_base[off] &= ~(0x80000000000000FFULL);
+#else
+		/*
+  		** If we want to maintain the PDIR as valid, put in
+		** the spill page so devices prefetching won't
+		** cause a hard fail.
+		*/
+		ioc->pdir_base[off] = (0x80000000000000FFULL | (u64)prefetch_spill_page);
+#endif
 	} else {
 		u32 t = get_order(byte_cnt) + PAGE_SHIFT;
 
@@ -689,14 +720,18 @@
 		do {
 			/* verify this pdir entry is enabled */
 			ASSERT(ioc->pdir_base[off]  >> 63);
+#ifndef FULL_VALID_PDIR
 			/* clear I/O Pdir entry "valid" bit first */
 			ioc->pdir_base[off] &= ~(0x80000000000000FFULL);
+#else
+			ioc->pdir_base[off] = (0x80000000000000FFULL | (u64)prefetch_spill_page);
+#endif
 			off++;
 			byte_cnt -= IOVP_SIZE;
 		} while (byte_cnt > 0);
 	}
 
-	WRITE_REG(iovp, ioc->ioc_hpa+IOC_PCOM);
+	WRITE_REG(iovp | ioc->ibase, ioc->ioc_hpa+IOC_PCOM);
 }
 
 /**
@@ -991,32 +1026,28 @@
 
 	dma_sg--;
 	while (nents-- > 0) {
-		int     cnt = sba_sg_len(startsg);
-		sba_sg_len(startsg) = 0;
+		int     cnt = startsg->dma_length;
+		startsg->dma_length = 0;
 
 #ifdef DEBUG_LARGE_SG_ENTRIES
 		if (dump_run_sg)
 			printk(" %2d : %08lx/%05x %p\n",
-				nents,
-				(unsigned long) sba_sg_iova(startsg), cnt,
-				sba_sg_buffer(startsg)
-		);
+				nents, startsg->dma_address, cnt,
+				sba_sg_address(startsg));
 #else
 		DBG_RUN_SG(" %d : %08lx/%05x %p\n",
-				nents,
-				(unsigned long) sba_sg_iova(startsg), cnt,
-				sba_sg_buffer(startsg)
-		);
+				nents, startsg->dma_address, cnt,
+				sba_sg_address(startsg));
 #endif
 		/*
 		** Look for the start of a new DMA stream
 		*/
-		if ((u64)sba_sg_iova(startsg) & PIDE_FLAG) {
-			u32 pide = (u64)sba_sg_iova(startsg) & ~PIDE_FLAG;
+		if (startsg->dma_address & PIDE_FLAG) {
+			u32 pide = startsg->dma_address & ~PIDE_FLAG;
 			dma_offset = (unsigned long) pide & ~IOVP_MASK;
-			sba_sg_iova(startsg) = 0;
+			startsg->dma_address = 0;
 			dma_sg++;
-			sba_sg_iova(dma_sg) = (char *)(pide | ioc->ibase);
+			dma_sg->dma_address = pide | ioc->ibase;
 			pdirp = &(ioc->pdir_base[pide >> IOVP_SHIFT]);
 			n_mappings++;
 		}
@@ -1025,13 +1056,13 @@
 		** Look for a VCONTIG chunk
 		*/
 		if (cnt) {
-			unsigned long vaddr = (unsigned long) sba_sg_buffer(startsg);
+			unsigned long vaddr = (unsigned long) sba_sg_address(startsg);
 			ASSERT(pdirp);
 
 			/* Since multiple Vcontig blocks could make up
 			** one DMA stream, *add* cnt to dma_len.
 			*/
-			sba_sg_len(dma_sg) += cnt;
+			dma_sg->dma_length += cnt;
 			cnt += dma_offset;
 			dma_offset=0;	/* only want offset on first chunk */
 			cnt = ROUNDUP(cnt, IOVP_SIZE);
@@ -1091,20 +1122,18 @@
 	int n_mappings = 0;
 
 	while (nents > 0) {
-		unsigned long vaddr = (unsigned long) (startsg->address); 
+		unsigned long vaddr = (unsigned long) sba_sg_address(startsg); 
 
 		/*
 		** Prepare for first/next DMA stream
 		*/
 		dma_sg = vcontig_sg = startsg;
-		dma_len = vcontig_len = vcontig_end = sba_sg_len(startsg);
+		dma_len = vcontig_len = vcontig_end = startsg->length;
 		vcontig_end +=  vaddr;
 		dma_offset = vaddr & ~IOVP_MASK;
 
 		/* PARANOID: clear entries */
-		sba_sg_buffer(startsg) = sba_sg_iova(startsg);
-		sba_sg_iova(startsg) = 0;
-		sba_sg_len(startsg) = 0;
+		startsg->dma_address = startsg->dma_length = 0;
 
 		/*
 		** This loop terminates one iteration "early" since
@@ -1115,6 +1144,9 @@
 
 			startsg++;
 
+			/* PARANOID */
+			startsg->dma_address = startsg->dma_length = 0;
+
 			/* catch brokenness in SCSI layer */
 			ASSERT(startsg->length <= DMA_CHUNK_SIZE);
 
@@ -1131,15 +1163,12 @@
 			**
 			** append the next transaction?
 			*/
-			vaddr = (unsigned long) sba_sg_iova(startsg);
+			vaddr = (unsigned long) sba_sg_address(startsg);
 			if  (vcontig_end == vaddr)
 			{
-				vcontig_len += sba_sg_len(startsg);
-				vcontig_end += sba_sg_len(startsg);
-				dma_len     += sba_sg_len(startsg);
-				sba_sg_buffer(startsg) = (char *)vaddr;
-				sba_sg_iova(startsg) = 0;
-				sba_sg_len(startsg) = 0;
+				vcontig_len += startsg->length;
+				vcontig_end += startsg->length;
+				dma_len     += startsg->length;
 				continue;
 			}
 
@@ -1158,10 +1187,10 @@
 			** must start on page boundaries and dove tail
 			** with it's predecessor.
 			*/
-			sba_sg_len(vcontig_sg) = vcontig_len;
+			vcontig_sg->dma_length = vcontig_len;
 
 			vcontig_sg = startsg;
-			vcontig_len = sba_sg_len(startsg);
+			vcontig_len = startsg->length;
 
 			/*
 			** 3) do the entries end/start on page boundaries?
@@ -1171,8 +1200,6 @@
 			{
 				vcontig_end = vcontig_len + vaddr;
 				dma_len += vcontig_len;
-				sba_sg_buffer(startsg) = (char *)vaddr;
-				sba_sg_iova(startsg) = 0;
 				continue;
 			} else {
 				break;
@@ -1184,10 +1211,10 @@
 		** Terminate last VCONTIG block.
 		** Allocate space for DMA stream.
 		*/
-		sba_sg_len(vcontig_sg) = vcontig_len;
+		vcontig_sg->dma_length = vcontig_len;
 		dma_len = (dma_len + dma_offset + ~IOVP_MASK) & IOVP_MASK;
 		ASSERT(dma_len <= DMA_CHUNK_SIZE);
-		sba_sg_iova(dma_sg) = (char *) (PIDE_FLAG 
+		dma_sg->dma_address = (dma_addr_t) (PIDE_FLAG 
 			| (sba_alloc_range(ioc, dma_len) << IOVP_SHIFT)
 			| dma_offset);
 		n_mappings++;
@@ -1223,8 +1250,8 @@
 #ifdef ALLOW_IOV_BYPASS
 	if (dev->dma_mask >= ioc->dma_mask) {
 		for (sg = sglist ; filled < nents ; filled++, sg++){
-			sba_sg_buffer(sg) = sba_sg_iova(sg);
-			sba_sg_iova(sg) = (char *)virt_to_phys(sba_sg_buffer(sg));
+			sg->dma_length = sg->length;
+			sg->dma_address = virt_to_phys(sba_sg_address(sg));
 		}
 #ifdef CONFIG_PROC_FS
 		spin_lock_irqsave(&ioc->res_lock, flags);
@@ -1236,10 +1263,10 @@
 #endif
 	/* Fast path single entry scatterlists. */
 	if (nents == 1) {
-		sba_sg_buffer(sglist) = sba_sg_iova(sglist);
-		sba_sg_iova(sglist) = (char *)sba_map_single(dev,
-						sba_sg_buffer(sglist),
-						sba_sg_len(sglist), direction);
+		sglist->dma_length = sglist->length;
+		sglist->dma_address = sba_map_single(dev,
+		                                     sba_sg_address(sglist),
+		                                     sglist->length, direction);
 #ifdef CONFIG_PROC_FS
 		/*
 		** Should probably do some stats counting, but trying to
@@ -1318,7 +1345,7 @@
 #endif
 
 	DBG_RUN_SG("%s() START %d entries,  %p,%x\n",
-		__FUNCTION__, nents, sba_sg_buffer(sglist), sglist->length);
+		__FUNCTION__, nents, sba_sg_address(sglist), sglist->length);
 
 	ioc = GET_IOC(dev);
 	ASSERT(ioc);
@@ -1333,10 +1360,10 @@
 	spin_unlock_irqrestore(&ioc->res_lock, flags);
 #endif
 
-	while (sba_sg_len(sglist) && nents--) {
+	while (nents && sglist->dma_length) {
 
-		sba_unmap_single(dev, (dma_addr_t)sba_sg_iova(sglist),
-		                 sba_sg_len(sglist), direction);
+		sba_unmap_single(dev, sglist->dma_address,
+		                 sglist->dma_length, direction);
 #ifdef CONFIG_PROC_FS
 		/*
 		** This leaves inconsistent data in the stats, but we can't
@@ -1344,9 +1371,10 @@
 		** were coalesced to a single entry.  The stats are fun,
 		** but speed is more important.
 		*/
-		ioc->usg_pages += (((u64)sba_sg_iova(sglist) & ~IOVP_MASK) + sba_sg_len(sglist) + IOVP_SIZE - 1) >> PAGE_SHIFT;
+		ioc->usg_pages += ((sglist->dma_address & ~IOVP_MASK) + sglist->dma_length + IOVP_SIZE - 1) >> PAGE_SHIFT;
 #endif
-		++sglist;
+		sglist++;
+		nents--;
 	}
 
 	DBG_RUN_SG("%s() DONE (nents %d)\n", __FUNCTION__,  nents);
@@ -1359,12 +1387,6 @@
 
 }
 
-unsigned long
-sba_dma_address (struct scatterlist *sg)
-{
-	return ((unsigned long)sba_sg_iova(sg));
-}
-
 int
 sba_dma_supported (struct pci_dev *dev, u64 mask)
 {
@@ -1384,6 +1406,9 @@
 	int iov_order, tcnfg;
 	int agp_found = 0;
 	struct pci_dev *device;
+#ifdef FULL_VALID_PDIR
+	unsigned long index;
+#endif
 
 	/*
 	** Firmware programs the base and size of a "safe IOVA space"
@@ -1481,7 +1506,7 @@
 	** Clear I/O TLB of any possible entries.
 	** (Yes. This is a bit paranoid...but so what)
 	*/
-	WRITE_REG(0 | 31, ioc->ioc_hpa + IOC_PCOM);
+	WRITE_REG(ioc->ibase | (iov_order+PAGE_SHIFT), ioc->ioc_hpa + IOC_PCOM);
 
 	/*
 	** If an AGP device is present, only use half of the IOV space
@@ -1499,6 +1524,34 @@
 		ioc->pdir_size /= 2;
 		((u64 *)ioc->pdir_base)[PDIR_INDEX(ioc->iov_size/2)] = ZX1_SBA_IOMMU_COOKIE;
 	}
+#ifdef FULL_VALID_PDIR
+	/*
+  	** Check to see if the spill page has been allocated, we don't need more than
+	** one across multiple SBAs.
+	*/
+	if (!prefetch_spill_page) {
+		char *spill_poison = "SBAIOMMU POISON";
+		int poison_size = 16;
+		void *poison_addr;
+									
+		prefetch_spill_page = (void *)__get_free_pages(GFP_KERNEL, get_order(IOVP_SIZE));
+		if (!prefetch_spill_page)
+			panic(PFX "Couldn't allocate PDIR spill page\n");
+
+		poison_addr = prefetch_spill_page;
+		for (; (u64)poison_addr < (u64)prefetch_spill_page + IOVP_SIZE ; poison_addr += poison_size)
+			(void)memcpy(poison_addr,spill_poison,poison_size);
+
+		prefetch_spill_page = (void *)virt_to_phys(prefetch_spill_page);
+
+		DBG_INIT("%s() prefetch spill addr: %p\n", __FUNCTION__, prefetch_spill_page);
+	}
+	/*
+  	** Set all the PDIR entries valid w/ the spill page as the target
+	*/
+	for (index = 0 ; index < (ioc->pdir_size / sizeof(u64)) ; index++)
+		((u64 *)ioc->pdir_base)[index] = (0x80000000000000FFULL | (u64)prefetch_spill_page);
+#endif
 }
 
 static void __init
@@ -1525,6 +1578,11 @@
 	ioc->res_map[0] = 0x1;
 	ioc->pdir_base[0] = 0x8000000000000000ULL | ZX1_SBA_IOMMU_COOKIE;
 #endif
+#ifdef FULL_VALID_PDIR
+	/* Mark the last resource used so we don't prefetch beyond IOVA space */
+	ioc->res_map[ioc->res_size - 1] |= 0x80UL; /* res_map is chars */
+	ioc->pdir_base[(ioc->pdir_size / sizeof(u64)) - 1] = (0x80000000000000FFULL | (u64)prefetch_spill_page);
+#endif
 
 	DBG_INIT("%s() res_map %x %p\n", __FUNCTION__,
 		 ioc->res_size, (void *) ioc->res_map);
@@ -1608,15 +1666,23 @@
 				(info->init)(ioc);
 		}
 	}
-	if (!ioc->name)
-		ioc->name = "Unknown";
+
+	if (!ioc->name) {
+		ioc->name = kmalloc(24, GFP_KERNEL);
+		if (ioc->name)
+			sprintf(ioc->name, "Unknown (%04x:%04x)",
+				ioc->func_id & 0xFFFF,
+				(ioc->func_id >> 16) & 0xFFFF);
+		else
+			ioc->name = "Unknown";
+	}
 
 	ioc_iova_init(ioc);
 	ioc_resource_init(ioc);
 	ioc_sac_init(ioc);
 
 	printk(KERN_INFO PFX
-		"Found %s IOC %d.%d HPA 0x%lx IOVA space %dMb at 0x%lx\n",
+		"%s %d.%d HPA 0x%lx IOVA space %dMb at 0x%lx\n",
 		ioc->name, (ioc->rev >> 4) & 0xF, ioc->rev & 0xF,
 		hpa, ioc->iov_size >> 20, ioc->ibase);
 
@@ -1861,7 +1927,6 @@
 EXPORT_SYMBOL(sba_unmap_single);
 EXPORT_SYMBOL(sba_map_sg);
 EXPORT_SYMBOL(sba_unmap_sg);
-EXPORT_SYMBOL(sba_dma_address);
 EXPORT_SYMBOL(sba_dma_supported);
 EXPORT_SYMBOL(sba_alloc_consistent);
 EXPORT_SYMBOL(sba_free_consistent);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/hp/sim/Makefile linux-2.4.21-pre6/arch/ia64/hp/sim/Makefile
--- linux-2.4.20/arch/ia64/hp/sim/Makefile	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/hp/sim/Makefile	2003-03-26 23:49:54.000000000 +0000
@@ -1,6 +1,8 @@
 #
 # ia64/platform/hp/sim/Makefile
 #
+# Copyright (C) 2002 Hewlett-Packard Co.
+#	David Mosberger-Tang <davidm@hpl.hp.com>
 # Copyright (C) 1999 Silicon Graphics, Inc.
 # Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com)
 #
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/hp/zx1/hpzx1_misc.c linux-2.4.21-pre6/arch/ia64/hp/zx1/hpzx1_misc.c
--- linux-2.4.20/arch/ia64/hp/zx1/hpzx1_misc.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/hp/zx1/hpzx1_misc.c	2003-03-26 23:49:07.000000000 +0000
@@ -17,8 +17,6 @@
 #include <asm/dma.h>
 #include <asm/iosapic.h>
 
-extern acpi_status acpi_evaluate_integer (acpi_handle, acpi_string, acpi_object_list *, unsigned long *);
-
 #define PFX "hpzx1: "
 
 static int hpzx1_devices;
@@ -252,40 +250,8 @@
 	 * HWP0003: AGP LBA device
 	 */
 	acpi_get_devices("HWP0001", hpzx1_sba_probe, "HWP0001", NULL);
-#ifdef CONFIG_IA64_HP_PROTO
-	if (hpzx1_devices) {
-#endif
 	acpi_get_devices("HWP0002", hpzx1_lba_probe, "HWP0002 PCI LBA", NULL);
 	acpi_get_devices("HWP0003", hpzx1_lba_probe, "HWP0003 AGP LBA", NULL);
-
-#ifdef CONFIG_IA64_HP_PROTO
-	}
-
-#define ZX1_FUNC_ID_VALUE    (PCI_DEVICE_ID_HP_ZX1_SBA << 16) | PCI_VENDOR_ID_HP
-	/*
-	 * Early protos don't have bridges in the ACPI namespace, so
-	 * if we didn't find anything, add the things we know are
-	 * there.
-	 */
-	if (hpzx1_devices == 0) {
-		u64 hpa, csr_base;
-
-		csr_base = 0xfed00000UL;
-		hpa = (u64) ioremap(csr_base, 0x2000);
-		if (__raw_readl(hpa) == ZX1_FUNC_ID_VALUE) {
-			hpzx1_fake_pci_dev("HWP0001 SBA", 0, csr_base, 0x1000);
-			hpzx1_fake_pci_dev("HWP0001 IOC", 0, csr_base + 0x1000,
-					    0x1000);
-
-			csr_base = 0xfed24000UL;
-			iounmap(hpa);
-			hpa = (u64) ioremap(csr_base, 0x1000);
-			hpzx1_fake_pci_dev("HWP0003 AGP LBA", 0x40, csr_base,
-					    0x1000);
-		}
-		iounmap(hpa);
-	}
-#endif
 }
 
 extern void sba_init(void);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/ia32/ia32_entry.S linux-2.4.21-pre6/arch/ia64/ia32/ia32_entry.S
--- linux-2.4.20/arch/ia64/ia32/ia32_entry.S	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/ia32/ia32_entry.S	2003-03-26 23:49:40.000000000 +0000
@@ -180,7 +180,7 @@
 	data8 sys32_fork
 	data8 sys_read
 	data8 sys_write
-	data8 sys_open		  /* 5 */
+	data8 sys32_open	  /* 5 */
 	data8 sys_close
 	data8 sys32_waitpid
 	data8 sys_creat
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/ia32/ia32_signal.c linux-2.4.21-pre6/arch/ia64/ia32/ia32_signal.c
--- linux-2.4.20/arch/ia64/ia32/ia32_signal.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/ia32/ia32_signal.c	2003-03-26 23:48:58.000000000 +0000
@@ -39,6 +39,16 @@
 #define __IA32_NR_sigreturn            119
 #define __IA32_NR_rt_sigreturn         173
 
+register double f16 asm ("f16"); register double f17 asm ("f17");
+register double f18 asm ("f18"); register double f19 asm ("f19");
+register double f20 asm ("f20"); register double f21 asm ("f21");
+register double f22 asm ("f22"); register double f23 asm ("f23");
+
+register double f24 asm ("f24"); register double f25 asm ("f25");
+register double f26 asm ("f26"); register double f27 asm ("f27");
+register double f28 asm ("f28"); register double f29 asm ("f29");
+register double f30 asm ("f30"); register double f31 asm ("f31");
+
 struct sigframe_ia32
 {
        int pretcode;
@@ -143,6 +153,304 @@
 	return err;
 }
 
+
+/*
+ *  SAVE and RESTORE of ia32 fpstate info, from ia64 current state
+ *  Used in exception handler to pass the fpstate to the user, and restore
+ *  the fpstate while returning from the exception handler.
+ *
+ *    fpstate info and their mapping to IA64 regs:
+ *    fpstate    REG(BITS)      Attribute    Comments
+ *    cw         ar.fcr(0:12)                with bits 7 and 6 not used
+ *    sw         ar.fsr(0:15)
+ *    tag        ar.fsr(16:31)               with odd numbered bits not used
+ *                                           (read returns 0, writes ignored)
+ *    ipoff      ar.fir(0:31)
+ *    cssel      ar.fir(32:47)
+ *    dataoff    ar.fdr(0:31)
+ *    datasel    ar.fdr(32:47)
+ *
+ *    _st[(0+TOS)%8]   f8
+ *    _st[(1+TOS)%8]   f9                    (f8, f9 from ptregs)
+ *      : :            :                     (f10..f15 from live reg)
+ *      : :            :
+ *    _st[(7+TOS)%8]   f15                   TOS=sw.top(bits11:13)
+ *
+ *    status     Same as sw     RO
+ *    magic      0                           as X86_FXSR_MAGIC in ia32
+ *    mxcsr      Bits(7:15)=ar.fcr(39:47)
+ *               Bits(0:5) =ar.fsr(32:37)    with bit 6 reserved
+ *    _xmm[0..7] f16..f31                    (live registers)
+ *                                           with _xmm[0]
+ *                                             Bit(64:127)=f17(0:63)
+ *                                             Bit(0:63)=f16(0:63)
+ *    All other fields unused...
+ */
+
+#define __ldfe(regnum, x)						\
+({									\
+ 	register double __f__ asm ("f"#regnum);				\
+	__asm__ __volatile__ ("ldfe %0=[%1] ;;" :"=f"(__f__): "r"(x));	\
+})
+
+#define __ldf8(regnum, x)						\
+({									\
+ 	register double __f__ asm ("f"#regnum);				\
+	__asm__ __volatile__ ("ldf8 %0=[%1] ;;" :"=f"(__f__): "r"(x));	\
+})
+
+#define __stfe(x, regnum)							\
+({										\
+ 	register double __f__ asm ("f"#regnum);					\
+	__asm__ __volatile__ ("stfe [%0]=%1" :: "r"(x), "f"(__f__) : "memory");	\
+})
+
+#define __stf8(x, regnum)							\
+({										\
+ 	register double __f__ asm ("f"#regnum);					\
+	__asm__ __volatile__ ("stf8 [%0]=%1" :: "r"(x), "f"(__f__) : "memory");	\
+})
+
+static int
+save_ia32_fpstate_live (struct _fpstate_ia32 *save)
+{
+	struct task_struct *tsk = current;
+	struct pt_regs *ptp;
+	struct _fpreg_ia32 *fpregp;
+	char buf[32];
+	unsigned long fsr, fcr, fir, fdr;
+	unsigned long new_fsr;
+	unsigned long num128[2];
+	unsigned long mxcsr=0;
+	int fp_tos, fr8_st_map;
+
+	if (!access_ok(VERIFY_WRITE, save, sizeof(*save)))
+		return -EFAULT;
+
+	/* Readin fsr, fcr, fir, fdr and copy onto fpstate */
+	asm volatile ( "mov %0=ar.fsr;" : "=r"(fsr));
+	asm volatile ( "mov %0=ar.fcr;" : "=r"(fcr));
+	asm volatile ( "mov %0=ar.fir;" : "=r"(fir));
+	asm volatile ( "mov %0=ar.fdr;" : "=r"(fdr));
+	/*
+	 * We need to clear the exception state before calling the signal handler. Clear
+	 * the bits 15, bits 0-7 in fp status word. Similar to the functionality of fnclex
+	 * instruction.
+	 */
+	new_fsr = fsr & ~0x80ff;
+	asm volatile ( "mov ar.fsr=%0;" :: "r"(new_fsr));
+
+	__put_user(fcr & 0xffff, &save->cw);
+	__put_user(fsr & 0xffff, &save->sw);
+	__put_user((fsr>>16) & 0xffff, &save->tag);
+	__put_user(fir, &save->ipoff);
+	__put_user((fir>>32) & 0xffff, &save->cssel);
+	__put_user(fdr, &save->dataoff);
+	__put_user((fdr>>32) & 0xffff, &save->datasel);
+	__put_user(fsr & 0xffff, &save->status);
+
+	mxcsr = ((fcr>>32) & 0xff80) | ((fsr>>32) & 0x3f);
+	__put_user(mxcsr & 0xffff, &save->mxcsr);
+	__put_user( 0, &save->magic); //#define X86_FXSR_MAGIC   0x0000
+
+	/*
+	 * save f8 and f9  from pt_regs
+	 * save f10..f15 from live register set
+	 */
+	/*
+	 *  Find the location where f8 has to go in fp reg stack.  This depends on
+	 *  TOP(11:13) field of sw. Other f reg continue sequentially from where f8 maps
+	 *  to.
+	 */
+	fp_tos = (fsr>>11)&0x7;
+	fr8_st_map = (8-fp_tos)&0x7;
+	ptp = ia64_task_regs(tsk);
+	fpregp = (struct _fpreg_ia32 *)(((unsigned long)buf + 15) & ~15);
+	ia64f2ia32f(fpregp, &ptp->f8);
+	copy_to_user(&save->_st[(0+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32));
+	ia64f2ia32f(fpregp, &ptp->f9);
+	copy_to_user(&save->_st[(1+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32));
+
+	__stfe(fpregp, 10);
+	copy_to_user(&save->_st[(2+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32));
+	__stfe(fpregp, 11);
+	copy_to_user(&save->_st[(3+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32));
+	__stfe(fpregp, 12);
+	copy_to_user(&save->_st[(4+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32));
+	__stfe(fpregp, 13);
+	copy_to_user(&save->_st[(5+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32));
+	__stfe(fpregp, 14);
+	copy_to_user(&save->_st[(6+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32));
+	__stfe(fpregp, 15);
+	copy_to_user(&save->_st[(7+fr8_st_map)&0x7], fpregp, sizeof(struct _fpreg_ia32));
+
+	__stf8(&num128[0], 16);
+	__stf8(&num128[1], 17);
+	copy_to_user(&save->_xmm[0], num128, sizeof(struct _xmmreg_ia32));
+
+	__stf8(&num128[0], 18);
+	__stf8(&num128[1], 19);
+	copy_to_user(&save->_xmm[1], num128, sizeof(struct _xmmreg_ia32));
+
+	__stf8(&num128[0], 20);
+	__stf8(&num128[1], 21);
+	copy_to_user(&save->_xmm[2], num128, sizeof(struct _xmmreg_ia32));
+
+	__stf8(&num128[0], 22);
+	__stf8(&num128[1], 23);
+	copy_to_user(&save->_xmm[3], num128, sizeof(struct _xmmreg_ia32));
+
+	__stf8(&num128[0], 24);
+	__stf8(&num128[1], 25);
+	copy_to_user(&save->_xmm[4], num128, sizeof(struct _xmmreg_ia32));
+
+	__stf8(&num128[0], 26);
+	__stf8(&num128[1], 27);
+	copy_to_user(&save->_xmm[5], num128, sizeof(struct _xmmreg_ia32));
+
+	__stf8(&num128[0], 28);
+	__stf8(&num128[1], 29);
+	copy_to_user(&save->_xmm[6], num128, sizeof(struct _xmmreg_ia32));
+
+	__stf8(&num128[0], 30);
+	__stf8(&num128[1], 31);
+	copy_to_user(&save->_xmm[7], num128, sizeof(struct _xmmreg_ia32));
+	return 0;
+}
+
+static int
+restore_ia32_fpstate_live (struct _fpstate_ia32 *save)
+{
+	struct task_struct *tsk = current;
+	struct pt_regs *ptp;
+	unsigned int lo, hi;
+	unsigned long num128[2];
+	unsigned long num64, mxcsr;
+	struct _fpreg_ia32 *fpregp;
+	char buf[32];
+	unsigned long fsr, fcr, fir, fdr;
+	int fp_tos, fr8_st_map;
+
+	if (!access_ok(VERIFY_READ, save, sizeof(*save)))
+		return(-EFAULT);
+
+	/*
+	 * Updating fsr, fcr, fir, fdr.
+	 * Just a bit more complicated than save.
+	 * - Need to make sure that we dont write any value other than the
+	 *   specific fpstate info
+	 * - Need to make sure that the untouched part of frs, fdr, fir, fcr
+	 *   should remain same while writing.
+	 * So, we do a read, change specific fields and write.
+	 */
+	asm volatile ( "mov %0=ar.fsr;" : "=r"(fsr));
+	asm volatile ( "mov %0=ar.fcr;" : "=r"(fcr));
+	asm volatile ( "mov %0=ar.fir;" : "=r"(fir));
+	asm volatile ( "mov %0=ar.fdr;" : "=r"(fdr));
+
+	__get_user(mxcsr, (unsigned int *)&save->mxcsr);
+	/* setting bits 0..5 8..12 with cw and 39..47 from mxcsr */
+	__get_user(lo, (unsigned int *)&save->cw);
+	num64 = mxcsr & 0xff10;
+	num64 = (num64 << 32) | (lo & 0x1f3f);
+	fcr = (fcr & (~0xff1000001f3f)) | num64;
+
+	/* setting bits 0..31 with sw and tag and 32..37 from mxcsr */
+	__get_user(lo, (unsigned int *)&save->sw);
+	/* set bits 15,7 (fsw.b, fsw.es) to reflect the current error status */
+	if ( !(lo & 0x7f) )
+		lo &= (~0x8080);
+	__get_user(hi, (unsigned int *)&save->tag);
+	num64 = mxcsr & 0x3f;
+	num64 = (num64 << 16) | (hi & 0xffff);
+	num64 = (num64 << 16) | (lo & 0xffff);
+	fsr = (fsr & (~0x3fffffffff)) | num64;
+
+	/* setting bits 0..47 with cssel and ipoff */
+	__get_user(lo, (unsigned int *)&save->ipoff);
+	__get_user(hi, (unsigned int *)&save->cssel);
+	num64 = hi & 0xffff;
+	num64 = (num64 << 32) | lo;
+	fir = (fir & (~0xffffffffffff)) | num64;
+
+	/* setting bits 0..47 with datasel and dataoff */
+	__get_user(lo, (unsigned int *)&save->dataoff);
+	__get_user(hi, (unsigned int *)&save->datasel);
+	num64 = hi & 0xffff;
+	num64 = (num64 << 32) | lo;
+	fdr = (fdr & (~0xffffffffffff)) | num64;
+
+	asm volatile ( "mov ar.fsr=%0;" :: "r"(fsr));
+	asm volatile ( "mov ar.fcr=%0;" :: "r"(fcr));
+	asm volatile ( "mov ar.fir=%0;" :: "r"(fir));
+	asm volatile ( "mov ar.fdr=%0;" :: "r"(fdr));
+
+	/*
+	 * restore f8, f9 onto pt_regs
+	 * restore f10..f15 onto live registers
+	 */
+	/*
+	 *  Find the location where f8 has to go in fp reg stack.  This depends on
+	 *  TOP(11:13) field of sw. Other f reg continue sequentially from where f8 maps
+	 *  to.
+	 */
+	fp_tos = (fsr>>11)&0x7;
+	fr8_st_map = (8-fp_tos)&0x7;
+	fpregp = (struct _fpreg_ia32 *)(((unsigned long)buf + 15) & ~15);
+
+	ptp = ia64_task_regs(tsk);
+	copy_from_user(fpregp, &save->_st[(0+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32));
+	ia32f2ia64f(&ptp->f8, fpregp);
+	copy_from_user(fpregp, &save->_st[(1+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32));
+	ia32f2ia64f(&ptp->f9, fpregp);
+
+	copy_from_user(fpregp, &save->_st[(2+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32));
+	__ldfe(10, fpregp);
+	copy_from_user(fpregp, &save->_st[(3+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32));
+	__ldfe(11, fpregp);
+	copy_from_user(fpregp, &save->_st[(4+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32));
+	__ldfe(12, fpregp);
+	copy_from_user(fpregp, &save->_st[(5+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32));
+	__ldfe(13, fpregp);
+	copy_from_user(fpregp, &save->_st[(6+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32));
+	__ldfe(14, fpregp);
+	copy_from_user(fpregp, &save->_st[(7+fr8_st_map)&0x7], sizeof(struct _fpreg_ia32));
+	__ldfe(15, fpregp);
+
+	copy_from_user(num128, &save->_xmm[0], sizeof(struct _xmmreg_ia32));
+	__ldf8(16, &num128[0]);
+	__ldf8(17, &num128[1]);
+
+	copy_from_user(num128, &save->_xmm[1], sizeof(struct _xmmreg_ia32));
+	__ldf8(18, &num128[0]);
+	__ldf8(19, &num128[1]);
+
+	copy_from_user(num128, &save->_xmm[2], sizeof(struct _xmmreg_ia32));
+	__ldf8(20, &num128[0]);
+	__ldf8(21, &num128[1]);
+
+	copy_from_user(num128, &save->_xmm[3], sizeof(struct _xmmreg_ia32));
+	__ldf8(22, &num128[0]);
+	__ldf8(23, &num128[1]);
+
+	copy_from_user(num128, &save->_xmm[4], sizeof(struct _xmmreg_ia32));
+	__ldf8(24, &num128[0]);
+	__ldf8(25, &num128[1]);
+
+	copy_from_user(num128, &save->_xmm[5], sizeof(struct _xmmreg_ia32));
+	__ldf8(26, &num128[0]);
+	__ldf8(27, &num128[1]);
+
+	copy_from_user(num128, &save->_xmm[6], sizeof(struct _xmmreg_ia32));
+	__ldf8(28, &num128[0]);
+	__ldf8(29, &num128[1]);
+
+	copy_from_user(num128, &save->_xmm[7], sizeof(struct _xmmreg_ia32));
+	__ldf8(30, &num128[0]);
+	__ldf8(31, &num128[1]);
+	return 0;
+}
+
 static inline void
 sigact_set_handler (struct k_sigaction *sa, unsigned int handler, unsigned int restorer)
 {
@@ -371,6 +679,9 @@
 	int  err = 0;
 	unsigned long flag;
 
+	if (!access_ok(VERIFY_WRITE, sc, sizeof(*sc)))
+		return -EFAULT;
+
 	err |= __put_user((regs->r16 >> 32) & 0xffff, (unsigned int *)&sc->fs);
 	err |= __put_user((regs->r16 >> 48) & 0xffff, (unsigned int *)&sc->gs);
 	err |= __put_user((regs->r16 >> 16) & 0xffff, (unsigned int *)&sc->es);
@@ -397,6 +708,11 @@
 	err |= __put_user(regs->r12, &sc->esp_at_signal);
 	err |= __put_user((regs->r17 >> 16) & 0xffff, (unsigned int *)&sc->ss);
 
+	if ( save_ia32_fpstate_live(fpstate) < 0 )
+		err = -EFAULT;
+	else
+		err |= __put_user((u32)(u64)fpstate, &sc->fpstate);
+
 #if 0
 	tmp = save_i387(fpstate);
 	if (tmp < 0)
@@ -418,6 +734,9 @@
 {
 	unsigned int err = 0;
 
+	if (!access_ok(VERIFY_READ, sc, sizeof(*sc)))
+		return(-EFAULT);
+
 #define COPY(ia64x, ia32x)	err |= __get_user(regs->ia64x, &sc->ia32x)
 
 #define copyseg_gs(tmp)		(regs->r16 |= (unsigned long) tmp << 48)
@@ -477,6 +796,16 @@
 		regs->r1 = -1;	/* disable syscall checks, r1 is orig_eax */
 	}
 
+	{
+		struct _fpstate_ia32 *buf = NULL;
+		u32    fpstate_ptr;
+		err |= get_user(fpstate_ptr, &(sc->fpstate));
+		buf = (struct _fpstate_ia32 *)(u64)fpstate_ptr;
+		if (buf) {
+			err |= restore_ia32_fpstate_live(buf);
+		}
+	}
+
 #if 0
 	{
 		struct _fpstate * buf;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/ia32/ia32_support.c linux-2.4.21-pre6/arch/ia64/ia32/ia32_support.c
--- linux-2.4.20/arch/ia64/ia32/ia32_support.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/ia32/ia32_support.c	2003-03-26 23:49:00.000000000 +0000
@@ -95,8 +95,6 @@
 	struct pt_regs *regs = ia64_task_regs(t);
 	int nr = smp_processor_id();	/* LDT and TSS depend on CPU number: */
 
-	nr = smp_processor_id();
-
 	eflag = t->thread.eflag;
 	fsr = t->thread.fsr;
 	fcr = t->thread.fcr;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/ia32/sys_ia32.c linux-2.4.21-pre6/arch/ia64/ia32/sys_ia32.c
--- linux-2.4.20/arch/ia64/ia32/sys_ia32.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/ia32/sys_ia32.c	2003-03-26 23:49:40.000000000 +0000
@@ -623,7 +623,8 @@
 			/* end address is 4KB aligned but not page aligned. */
 			retval = mprotect_subpage(PAGE_START(end), prot);
 			if (retval < 0)
-				return retval;
+				goto out;
+
 			end = PAGE_START(end);
 		}
 		retval = sys_mprotect(start, end - start, prot);
@@ -2118,8 +2119,8 @@
 };
 
 struct ipc_kludge {
-	struct msgbuf *msgp;
-	long msgtyp;
+	u32 msgp;
+	s32 msgtyp;
 };
 
 #define SEMOP		 1
@@ -2843,20 +2844,6 @@
 	}
 }
 
-static inline void
-ia32f2ia64f (void *dst, void *src)
-{
-	asm volatile ("ldfe f6=[%1];; stf.spill [%0]=f6" :: "r"(dst), "r"(src) : "memory");
-	return;
-}
-
-static inline void
-ia64f2ia32f (void *dst, void *src)
-{
-	asm volatile ("ldf.fill f6=[%1];; stfe [%0]=f6" :: "r"(dst),  "r"(src) : "memory");
-	return;
-}
-
 static void
 put_fpreg (int regno, struct _fpreg_ia32 *reg, struct pt_regs *ptp, struct switch_stack *swp,
 	   int tos)
@@ -2913,57 +2900,152 @@
 }
 
 static int
-save_ia32_fpstate (struct task_struct *tsk, struct _fpstate_ia32 *save)
+save_ia32_fpstate (struct task_struct *tsk, struct ia32_user_i387_struct *save)
 {
 	struct switch_stack *swp;
 	struct pt_regs *ptp;
 	int i, tos;
 
 	if (!access_ok(VERIFY_WRITE, save, sizeof(*save)))
-		return -EIO;
-	__put_user(tsk->thread.fcr, &save->cw);
-	__put_user(tsk->thread.fsr, &save->sw);
-	__put_user(tsk->thread.fsr >> 32, &save->tag);
-	__put_user(tsk->thread.fir, &save->ipoff);
-	__put_user(__USER_CS, &save->cssel);
-	__put_user(tsk->thread.fdr, &save->dataoff);
-	__put_user(__USER_DS, &save->datasel);
+		return -EFAULT;
+
+	__put_user(tsk->thread.fcr & 0xffff, &save->cwd);
+	__put_user(tsk->thread.fsr & 0xffff, &save->swd);
+	__put_user((tsk->thread.fsr>>16) & 0xffff, &save->twd);
+	__put_user(tsk->thread.fir, &save->fip);
+	__put_user((tsk->thread.fir>>32) & 0xffff, &save->fcs);
+	__put_user(tsk->thread.fdr, &save->foo);
+	__put_user((tsk->thread.fdr>>32) & 0xffff, &save->fos);
+
 	/*
 	 *  Stack frames start with 16-bytes of temp space
 	 */
 	swp = (struct switch_stack *)(tsk->thread.ksp + 16);
 	ptp = ia64_task_regs(tsk);
-	tos = (tsk->thread.fsr >> 11) & 3;
+	tos = (tsk->thread.fsr >> 11) & 7;
 	for (i = 0; i < 8; i++)
-		put_fpreg(i, &save->_st[i], ptp, swp, tos);
+		put_fpreg(i, (struct _fpreg_ia32 *)&save->st_space[4*i], ptp, swp, tos);
 	return 0;
 }
 
 static int
-restore_ia32_fpstate (struct task_struct *tsk, struct _fpstate_ia32 *save)
+restore_ia32_fpstate (struct task_struct *tsk, struct ia32_user_i387_struct *save)
 {
 	struct switch_stack *swp;
 	struct pt_regs *ptp;
-	int i, tos, ret;
-	int fsrlo, fsrhi;
+	int i, tos;
+	unsigned int fsrlo, fsrhi, num32;
 
 	if (!access_ok(VERIFY_READ, save, sizeof(*save)))
-		return(-EIO);
-	ret = __get_user(tsk->thread.fcr, (unsigned int *)&save->cw);
-	ret |= __get_user(fsrlo, (unsigned int *)&save->sw);
-	ret |= __get_user(fsrhi, (unsigned int *)&save->tag);
-	tsk->thread.fsr = ((long)fsrhi << 32) | (long)fsrlo;
-	ret |= __get_user(tsk->thread.fir, (unsigned int *)&save->ipoff);
-	ret |= __get_user(tsk->thread.fdr, (unsigned int *)&save->dataoff);
+		return(-EFAULT);
+
+	__get_user(num32, (unsigned int *)&save->cwd);
+	tsk->thread.fcr = (tsk->thread.fcr & (~0x1f3f)) | (num32 & 0x1f3f);
+	__get_user(fsrlo, (unsigned int *)&save->swd);
+	__get_user(fsrhi, (unsigned int *)&save->twd);
+	num32 = (fsrhi << 16) | fsrlo;
+	tsk->thread.fsr = (tsk->thread.fsr & (~0xffffffff)) | num32;
+	__get_user(num32, (unsigned int *)&save->fip);
+	tsk->thread.fir = (tsk->thread.fir & (~0xffffffff)) | num32;
+	__get_user(num32, (unsigned int *)&save->foo);
+	tsk->thread.fdr = (tsk->thread.fdr & (~0xffffffff)) | num32;
+
 	/*
 	 *  Stack frames start with 16-bytes of temp space
 	 */
 	swp = (struct switch_stack *)(tsk->thread.ksp + 16);
 	ptp = ia64_task_regs(tsk);
-	tos = (tsk->thread.fsr >> 11) & 3;
+	tos = (tsk->thread.fsr >> 11) & 7;
 	for (i = 0; i < 8; i++)
-		get_fpreg(i, &save->_st[i], ptp, swp, tos);
-	return ret ? -EFAULT : 0;
+		get_fpreg(i, (struct _fpreg_ia32 *)&save->st_space[4*i], ptp, swp, tos);
+	return 0;
+}
+
+static int
+save_ia32_fpxstate (struct task_struct *tsk, struct ia32_user_fxsr_struct *save)
+{
+	struct switch_stack *swp;
+	struct pt_regs *ptp;
+	int i, tos;
+	unsigned long mxcsr=0;
+	unsigned long num128[2];
+
+	if (!access_ok(VERIFY_WRITE, save, sizeof(*save)))
+		return -EFAULT;
+
+	__put_user(tsk->thread.fcr & 0xffff, &save->cwd);
+	__put_user(tsk->thread.fsr & 0xffff, &save->swd);
+	__put_user((tsk->thread.fsr>>16) & 0xffff, &save->twd);
+	__put_user(tsk->thread.fir, &save->fip);
+	__put_user((tsk->thread.fir>>32) & 0xffff, &save->fcs);
+	__put_user(tsk->thread.fdr, &save->foo);
+	__put_user((tsk->thread.fdr>>32) & 0xffff, &save->fos);
+
+        /*
+         *  Stack frames start with 16-bytes of temp space
+         */
+        swp = (struct switch_stack *)(tsk->thread.ksp + 16);
+        ptp = ia64_task_regs(tsk);
+	tos = (tsk->thread.fsr >> 11) & 7;
+        for (i = 0; i < 8; i++)
+		put_fpreg(i, (struct _fpxreg_ia32 *)&save->st_space[4*i], ptp, swp, tos);
+
+	mxcsr = ((tsk->thread.fcr>>32) & 0xff80) | ((tsk->thread.fsr>>32) & 0x3f);
+	__put_user(mxcsr & 0xffff, &save->mxcsr);
+	for (i = 0; i < 8; i++) {
+		memcpy(&(num128[0]), &(swp->f16) + i*2, sizeof(unsigned long));
+		memcpy(&(num128[1]), &(swp->f17) + i*2, sizeof(unsigned long));
+		copy_to_user(&save->xmm_space[0] + 4*i, num128, sizeof(struct _xmmreg_ia32));
+	}
+	return 0;
+}
+
+static int
+restore_ia32_fpxstate (struct task_struct *tsk, struct ia32_user_fxsr_struct *save)
+{
+	struct switch_stack *swp;
+	struct pt_regs *ptp;
+	int i, tos;
+	unsigned int fsrlo, fsrhi, num32;
+	int mxcsr;
+	unsigned long num64;
+	unsigned long num128[2];
+
+	if (!access_ok(VERIFY_READ, save, sizeof(*save)))
+		return(-EFAULT);
+
+	__get_user(num32, (unsigned int *)&save->cwd);
+	tsk->thread.fcr = (tsk->thread.fcr & (~0x1f3f)) | (num32 & 0x1f3f);
+	__get_user(fsrlo, (unsigned int *)&save->swd);
+	__get_user(fsrhi, (unsigned int *)&save->twd);
+	num32 = (fsrhi << 16) | fsrlo;
+	tsk->thread.fsr = (tsk->thread.fsr & (~0xffffffff)) | num32;
+	__get_user(num32, (unsigned int *)&save->fip);
+	tsk->thread.fir = (tsk->thread.fir & (~0xffffffff)) | num32;
+	__get_user(num32, (unsigned int *)&save->foo);
+	tsk->thread.fdr = (tsk->thread.fdr & (~0xffffffff)) | num32;
+
+	/*
+	 *  Stack frames start with 16-bytes of temp space
+	 */
+	swp = (struct switch_stack *)(tsk->thread.ksp + 16);
+	ptp = ia64_task_regs(tsk);
+	tos = (tsk->thread.fsr >> 11) & 7;
+	for (i = 0; i < 8; i++)
+	get_fpreg(i, (struct _fpxreg_ia32 *)&save->st_space[4*i], ptp, swp, tos);
+
+	__get_user(mxcsr, (unsigned int *)&save->mxcsr);
+	num64 = mxcsr & 0xff10;
+	tsk->thread.fcr = (tsk->thread.fcr & (~0xff1000000000)) | (num64<<32);
+	num64 = mxcsr & 0x3f;
+	tsk->thread.fsr = (tsk->thread.fsr & (~0x3f00000000)) | (num64<<32);
+
+	for (i = 0; i < 8; i++) {
+		copy_from_user(num128, &save->xmm_space[0] + 4*i, sizeof(struct _xmmreg_ia32));
+		memcpy(&(swp->f16) + i*2, &(num128[0]), sizeof(unsigned long));
+		memcpy(&(swp->f17) + i*2, &(num128[1]), sizeof(unsigned long));
+	}
+	return 0;
 }
 
 extern asmlinkage long sys_ptrace (long, pid_t, unsigned long, unsigned long, long, long, long,
@@ -3075,11 +3157,19 @@
 		break;
 
 	      case IA32_PTRACE_GETFPREGS:
-		ret = save_ia32_fpstate(child, (struct _fpstate_ia32 *) A(data));
+		ret = save_ia32_fpstate(child, (struct ia32_user_i387_struct *) A(data));
+		break;
+
+	      case IA32_PTRACE_GETFPXREGS:
+		ret = save_ia32_fpxstate(child, (struct ia32_user_fxsr_struct *) A(data));
 		break;
 
 	      case IA32_PTRACE_SETFPREGS:
-		ret = restore_ia32_fpstate(child, (struct _fpstate_ia32 *) A(data));
+		ret = restore_ia32_fpstate(child, (struct ia32_user_i387_struct *) A(data));
+		break;
+
+	      case IA32_PTRACE_SETFPXREGS:
+		ret = restore_ia32_fpxstate(child, (struct ia32_user_fxsr_struct *) A(data));
 		break;
 
 	      case PTRACE_SYSCALL:	/* continue, stop after next syscall */
@@ -3825,6 +3915,37 @@
 	return ret;
 }
 
+/*
+ * Exactly like fs/open.c:sys_open(), except that it doesn't set the O_LARGEFILE flag.
+ */
+asmlinkage long
+sys32_open (const char * filename, int flags, int mode)
+{
+	char * tmp;
+	int fd, error;
+
+	tmp = getname(filename);
+	fd = PTR_ERR(tmp);
+	if (!IS_ERR(tmp)) {
+		fd = get_unused_fd();
+		if (fd >= 0) {
+			struct file *f = filp_open(tmp, flags, mode);
+			error = PTR_ERR(f);
+			if (IS_ERR(f))
+				goto out_error;
+			fd_install(fd, f);
+		}
+out:
+		putname(tmp);
+	}
+	return fd;
+
+out_error:
+	put_unused_fd(fd);
+	fd = error;
+	goto out;
+}
+
 #ifdef	NOTYET  /* UNTESTED FOR IA64 FROM HERE DOWN */
 
 struct ncp_mount_data32 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/acpi.c linux-2.4.21-pre6/arch/ia64/kernel/acpi.c
--- linux-2.4.20/arch/ia64/kernel/acpi.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/kernel/acpi.c	2003-03-26 23:49:38.000000000 +0000
@@ -102,8 +102,6 @@
 	return "sn2";
 # elif defined (CONFIG_IA64_DIG)
 	return "dig";
-# elif defined (CONFIG_IA64_HP_ZX1)
-	return "hpzx1";
 # else
 #	error Unknown platform.  Fix acpi.c.
 # endif
@@ -112,33 +110,7 @@
 
 #ifdef CONFIG_ACPI
 
-/**
- * acpi_get_crs - Return the current resource settings for a device
- * obj: A handle for this device
- * buf: A buffer to be populated by this call.
- *
- * Pass a valid handle, typically obtained by walking the namespace and a
- * pointer to an allocated buffer, and this function will fill in the buffer
- * with a list of acpi_resource structures.
- */
-acpi_status
-acpi_get_crs (acpi_handle obj, acpi_buffer *buf)
-{
-	acpi_status result;
-	buf->length = 0;
-	buf->pointer = NULL;
-
-	result = acpi_get_current_resources(obj, buf);
-	if (result != AE_BUFFER_OVERFLOW)
-		return result;
-	buf->pointer = kmalloc(buf->length, GFP_KERNEL);
-	if (!buf->pointer)
-		return -ENOMEM;
-
-	return acpi_get_current_resources(obj, buf);
-}
-
-acpi_resource *
+static acpi_resource *
 acpi_get_crs_next (acpi_buffer *buf, int *offset)
 {
 	acpi_resource *res;
@@ -146,12 +118,12 @@
 	if (*offset >= buf->length)
 		return NULL;
 
-	res = buf->pointer + *offset;
+	res = (acpi_resource *)((char *) buf->pointer + *offset);
 	*offset += res->length;
 	return res;
 }
 
-acpi_resource_data *
+static acpi_resource_data *
 acpi_get_crs_type (acpi_buffer *buf, int *offset, int type)
 {
 	for (;;) {
@@ -163,12 +135,6 @@
 	}
 }
 
-void
-acpi_dispose_crs (acpi_buffer *buf)
-{
-	kfree(buf->pointer);
-}
-
 static void
 acpi_get_crs_addr (acpi_buffer *buf, int type, u64 *base, u64 *length, u64 *tra)
 {
@@ -210,6 +176,9 @@
 					return;
 				}
 				break;
+			case ACPI_RSTYPE_END_TAG:
+				return;
+				break;
 		}
 	}
 }
@@ -218,13 +187,14 @@
 acpi_get_addr_space(acpi_handle obj, u8 type, u64 *base, u64 *length, u64 *tra)
 {
 	acpi_status status;
-	acpi_buffer buf;
+	acpi_buffer buf = { .length  = ACPI_ALLOCATE_BUFFER,
+			    .pointer = NULL };
 
 	*base = 0;
 	*length = 0;
 	*tra = 0;
 
-	status = acpi_get_crs(obj, &buf);
+	status = acpi_get_current_resources(obj, &buf);
 	if (ACPI_FAILURE(status)) {
 		printk(KERN_ERR PREFIX "Unable to get _CRS data on object\n");
 		return status;
@@ -232,7 +202,7 @@
 
 	acpi_get_crs_addr(&buf, type, base, length, tra);
 
-	acpi_dispose_crs(&buf);
+	acpi_os_free(buf.pointer);
 
 	return AE_OK;
 }
@@ -254,7 +224,8 @@
 {
 	int i, offset = 0;
 	acpi_status status;
-	acpi_buffer buf;
+	acpi_buffer buf = { .length  = ACPI_ALLOCATE_BUFFER,
+			    .pointer = NULL };
 	acpi_resource_vendor *res;
 	acpi_hp_vendor_long *hp_res;
 	efi_guid_t vendor_guid;
@@ -262,42 +233,41 @@
 	*csr_base = 0;
 	*csr_length = 0;
 
-	status = acpi_get_crs(obj, &buf);
+	status = acpi_get_current_resources(obj, &buf);
 	if (ACPI_FAILURE(status)) {
 		printk(KERN_ERR PREFIX "Unable to get _CRS data on object\n");
 		return status;
 	}
 
+	status = AE_NOT_FOUND;
 	res = (acpi_resource_vendor *)acpi_get_crs_type(&buf, &offset, ACPI_RSTYPE_VENDOR);
 	if (!res) {
 		printk(KERN_ERR PREFIX "Failed to find config space for device\n");
-		acpi_dispose_crs(&buf);
-		return AE_NOT_FOUND;
+		goto out;
 	}
 
+	status = AE_TYPE; /* Revisit error? */
 	hp_res = (acpi_hp_vendor_long *)(res->reserved);
 
 	if (res->length != HP_CCSR_LENGTH || hp_res->guid_id != HP_CCSR_TYPE) {
 		printk(KERN_ERR PREFIX "Unknown Vendor data\n");
-		acpi_dispose_crs(&buf);
-		return AE_TYPE; /* Revisit error? */
+		goto out;
 	}
 
 	memcpy(&vendor_guid, hp_res->guid, sizeof(efi_guid_t));
 	if (efi_guidcmp(vendor_guid, HP_CCSR_GUID) != 0) {
 		printk(KERN_ERR PREFIX "Vendor GUID does not match\n");
-		acpi_dispose_crs(&buf);
-		return AE_TYPE; /* Revisit error? */
+		goto out;
 	}
 
-	for (i = 0 ; i < 8 ; i++) {
-		*csr_base |= ((u64)(hp_res->csr_base[i]) << (i * 8));
-		*csr_length |= ((u64)(hp_res->csr_length[i]) << (i * 8));
-	}
-
-	acpi_dispose_crs(&buf);
+	/* It's probably unaligned, so use memcpy */
+	memcpy(csr_base, hp_res->csr_base, 8);
+	memcpy(csr_length, hp_res->csr_length, 8);
+	status = AE_OK;
 
-	return AE_OK;
+ out:
+	acpi_os_free(buf.pointer);
+	return status;
 }
 #endif /* CONFIG_ACPI */
 
@@ -368,6 +338,7 @@
 acpi_parse_lsapic (acpi_table_entry_header *header)
 {
 	struct acpi_table_lsapic *lsapic;
+	int phys_id;
 
 	lsapic = (struct acpi_table_lsapic *) header;
 	if (!lsapic)
@@ -375,13 +346,21 @@
 
 	acpi_table_print_madt_entry(header);
 
-	printk("CPU %d (0x%04x)", total_cpus, (lsapic->id << 8) | lsapic->eid);
+	phys_id = (lsapic->id << 8) | lsapic->eid;
+
+	if (total_cpus == NR_CPUS) {
+		printk(KERN_ERR PREFIX "Ignoring CPU (0x%04x) (NR_CPUS == %d)\n",
+			phys_id, NR_CPUS);
+		return 0;
+	}
+
+	printk("CPU %d (0x%04x)", total_cpus, phys_id);
 
 	if (lsapic->flags.enabled) {
 		available_cpus++;
 		printk(" enabled");
 #ifdef CONFIG_SMP
-		smp_boot_data.cpu_phys_id[total_cpus] = (lsapic->id << 8) | lsapic->eid;
+		smp_boot_data.cpu_phys_id[total_cpus] = phys_id;
 		if (hard_smp_processor_id() == smp_boot_data.cpu_phys_id[total_cpus])
 			printk(" (BSP)");
 #endif
@@ -464,9 +443,8 @@
 
 	if (iosapic_init) {
 #ifndef CONFIG_ITANIUM
-		/* PCAT_COMPAT flag indicates dual-8259 setup */
 		iosapic_init(iosapic->address, iosapic->global_irq_base,
-			     acpi_madt->flags.pcat_compat);
+			     has_8259);
 #else
 		/* Firmware on old Itanium systems is broken */
 		iosapic_init(iosapic->address, iosapic->global_irq_base, 1);
@@ -616,59 +594,6 @@
 }
 
 
-#ifdef CONFIG_SERIAL_ACPI
-
-#include <linux/acpi_serial.h>
-
-static int __init
-acpi_parse_spcr (unsigned long phys_addr, unsigned long size)
-{
-	acpi_ser_t *spcr;
-	u32 gsi, gsi_base;
-	char *iosapic_address;
-
-	if (!phys_addr || !size)
-		return -EINVAL;
-
-	if (!iosapic_register_intr)
-		return -ENODEV;
-
-	/*
-	 * ACPI is able to describe serial ports that live at non-standard
-	 * memory addresses and use non-standard interrupts, either via
-	 * direct SAPIC mappings or via PCI interrupts.  We handle interrupt
-	 * routing for SAPIC-based (non-PCI) devices here.  Interrupt routing
-	 * for PCI devices will be handled when processing the PCI Interrupt
-	 * Routing Table (PRT).
-	 */
-
-	spcr = (acpi_ser_t *) __va(phys_addr);
-	setup_serial_acpi(spcr);
-
-	if (spcr->length < sizeof(acpi_ser_t))
-		/* Table not long enough for full info, thus no interrupt */
-		return -ENODEV;
-
-	if ((spcr->base_addr.space_id != ACPI_SERIAL_PCICONF_SPACE) &&
-	    (spcr->int_type == ACPI_SERIAL_INT_SAPIC)) {
-
-		/* We have a UART in memory space with an SAPIC interrupt */
-
-		gsi = (spcr->global_int[3] << 24) |
-		      (spcr->global_int[2] << 16) |
-		      (spcr->global_int[1] << 8)  |
-		      (spcr->global_int[0]);
-
-		if (!acpi_find_iosapic(gsi, &gsi_base, &iosapic_address))
-			iosapic_register_intr(gsi, 1, 1,
-					      gsi_base, iosapic_address);
-	}
-	return 0;
-}
-
-#endif /*CONFIG_SERIAL_ACPI*/
-
-
 unsigned long __init
 acpi_find_rsdp (void)
 {
@@ -749,10 +674,6 @@
 	if (acpi_table_parse(ACPI_FACP, acpi_parse_fadt) < 1)
 		printk(KERN_ERR PREFIX "Can't find FADT\n");
 
-#ifdef CONFIG_SERIAL_ACPI
-	acpi_table_parse(ACPI_SPCR, acpi_parse_spcr);
-#endif
-
 #ifdef CONFIG_SMP
 	if (available_cpus == 0) {
 		printk("ACPI: Found 0 CPUS; assuming 1\n");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/efi.c linux-2.4.21-pre6/arch/ia64/kernel/efi.c
--- linux-2.4.20/arch/ia64/kernel/efi.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/kernel/efi.c	2003-03-26 23:48:59.000000000 +0000
@@ -51,66 +51,156 @@
 
 static unsigned long mem_limit = ~0UL;
 
-static efi_status_t
-phys_get_time (efi_time_t *tm, efi_time_cap_t *tc)
-{
-	return efi_call_phys(__va(runtime->get_time), __pa(tm), __pa(tc));
-}
-
-static efi_status_t
-phys_set_time (efi_time_t *tm)
-{
-	return efi_call_phys(__va(runtime->set_time), __pa(tm));
-}
+#define efi_call_virt(f, args...)	(*(f))(args)
 
-static efi_status_t
-phys_get_wakeup_time (efi_bool_t *enabled, efi_bool_t *pending, efi_time_t *tm)
-{
-	return efi_call_phys(__va(runtime->get_wakeup_time), __pa(enabled), __pa(pending),
-			     __pa(tm));
-}
-
-static efi_status_t
-phys_set_wakeup_time (efi_bool_t enabled, efi_time_t *tm)
-{
-	return efi_call_phys(__va(runtime->set_wakeup_time), enabled, __pa(tm));
-}
-
-static efi_status_t
-phys_get_variable (efi_char16_t *name, efi_guid_t *vendor, u32 *attr,
-		   unsigned long *data_size, void *data)
-{
-	return efi_call_phys(__va(runtime->get_variable), __pa(name), __pa(vendor), __pa(attr),
-			     __pa(data_size), __pa(data));
-}
-
-static efi_status_t
-phys_get_next_variable (unsigned long *name_size, efi_char16_t *name, efi_guid_t *vendor)
-{
-	return efi_call_phys(__va(runtime->get_next_variable), __pa(name_size), __pa(name),
-			     __pa(vendor));
-}
-
-static efi_status_t
-phys_set_variable (efi_char16_t *name, efi_guid_t *vendor, u32 attr,
-		   unsigned long data_size, void *data)
-{
-	return efi_call_phys(__va(runtime->set_variable), __pa(name), __pa(vendor), attr,
-			     data_size, __pa(data));
-}
-
-static efi_status_t
-phys_get_next_high_mono_count (u64 *count)
-{
-	return efi_call_phys(__va(runtime->get_next_high_mono_count), __pa(count));
-}
-
-static void
-phys_reset_system (int reset_type, efi_status_t status,
-		   unsigned long data_size, efi_char16_t *data)
-{
-	efi_call_phys(__va(runtime->reset_system), status, data_size, __pa(data));
-}
+#define STUB_GET_TIME(prefix, adjust_arg)							\
+static efi_status_t										\
+prefix##_get_time (efi_time_t *tm, efi_time_cap_t *tc)						\
+{												\
+	struct ia64_fpreg fr[6];								\
+	efi_status_t ret;									\
+												\
+	ia64_save_scratch_fpregs(fr);								\
+	ret = efi_call_##prefix((efi_get_time_t *) __va(runtime->get_time), adjust_arg(tm),	\
+				adjust_arg(tc));						\
+	ia64_load_scratch_fpregs(fr);								\
+	return ret;										\
+}
+
+#define STUB_SET_TIME(prefix, adjust_arg)							\
+static efi_status_t										\
+prefix##_set_time (efi_time_t *tm)								\
+{												\
+	struct ia64_fpreg fr[6];								\
+	efi_status_t ret;									\
+												\
+	ia64_save_scratch_fpregs(fr);								\
+	ret = efi_call_##prefix((efi_set_time_t *) __va(runtime->set_time), adjust_arg(tm));	\
+	ia64_load_scratch_fpregs(fr);								\
+	return ret;										\
+}
+
+#define STUB_GET_WAKEUP_TIME(prefix, adjust_arg)						\
+static efi_status_t										\
+prefix##_get_wakeup_time (efi_bool_t *enabled, efi_bool_t *pending, efi_time_t *tm)		\
+{												\
+	struct ia64_fpreg fr[6];								\
+	efi_status_t ret;									\
+												\
+	ia64_save_scratch_fpregs(fr);								\
+	ret = efi_call_##prefix((efi_get_wakeup_time_t *) __va(runtime->get_wakeup_time),	\
+				adjust_arg(enabled), adjust_arg(pending), adjust_arg(tm));	\
+	ia64_load_scratch_fpregs(fr);								\
+	return ret;										\
+}
+
+#define STUB_SET_WAKEUP_TIME(prefix, adjust_arg)						\
+static efi_status_t										\
+prefix##_set_wakeup_time (efi_bool_t enabled, efi_time_t *tm)					\
+{												\
+	struct ia64_fpreg fr[6];								\
+	efi_status_t ret;									\
+												\
+	ia64_save_scratch_fpregs(fr);								\
+	ret = efi_call_##prefix((efi_set_wakeup_time_t *) __va(runtime->set_wakeup_time),	\
+				enabled, adjust_arg(tm));					\
+	ia64_load_scratch_fpregs(fr);								\
+	return ret;										\
+}
+
+#define STUB_GET_VARIABLE(prefix, adjust_arg)						\
+static efi_status_t									\
+prefix##_get_variable (efi_char16_t *name, efi_guid_t *vendor, u32 *attr,		\
+		       unsigned long *data_size, void *data)				\
+{											\
+	struct ia64_fpreg fr[6];							\
+	efi_status_t ret;								\
+											\
+	ia64_save_scratch_fpregs(fr);							\
+	ret = efi_call_##prefix((efi_get_variable_t *) __va(runtime->get_variable),	\
+				adjust_arg(name), adjust_arg(vendor), adjust_arg(attr),	\
+				adjust_arg(data_size), adjust_arg(data));		\
+	ia64_load_scratch_fpregs(fr);							\
+	return ret;									\
+}
+
+#define STUB_GET_NEXT_VARIABLE(prefix, adjust_arg)						\
+static efi_status_t										\
+prefix##_get_next_variable (unsigned long *name_size, efi_char16_t *name, efi_guid_t *vendor)	\
+{												\
+	struct ia64_fpreg fr[6];								\
+	efi_status_t ret;									\
+												\
+	ia64_save_scratch_fpregs(fr);								\
+	ret = efi_call_##prefix((efi_get_next_variable_t *) __va(runtime->get_next_variable),	\
+				adjust_arg(name_size), adjust_arg(name), adjust_arg(vendor));	\
+	ia64_load_scratch_fpregs(fr);								\
+	return ret;										\
+}
+
+#define STUB_SET_VARIABLE(prefix, adjust_arg)						\
+static efi_status_t									\
+prefix##_set_variable (efi_char16_t *name, efi_guid_t *vendor, u32 attr,		\
+		       unsigned long data_size, void *data)				\
+{											\
+	struct ia64_fpreg fr[6];							\
+	efi_status_t ret;								\
+											\
+	ia64_save_scratch_fpregs(fr);							\
+	ret = efi_call_##prefix((efi_set_variable_t *) __va(runtime->set_variable),	\
+				adjust_arg(name), adjust_arg(vendor), attr, data_size,	\
+				adjust_arg(data));					\
+	ia64_load_scratch_fpregs(fr);							\
+	return ret;									\
+}
+
+#define STUB_GET_NEXT_HIGH_MONO_COUNT(prefix, adjust_arg)					\
+static efi_status_t										\
+prefix##_get_next_high_mono_count (u64 *count)							\
+{												\
+	struct ia64_fpreg fr[6];								\
+	efi_status_t ret;									\
+												\
+	ia64_save_scratch_fpregs(fr);								\
+	ret = efi_call_##prefix((efi_get_next_high_mono_count_t *)				\
+				__va(runtime->get_next_high_mono_count), adjust_arg(count));	\
+	ia64_load_scratch_fpregs(fr);								\
+	return ret;										\
+}
+
+#define STUB_RESET_SYSTEM(prefix, adjust_arg)					\
+static void									\
+prefix##_reset_system (int reset_type, efi_status_t status,			\
+		       unsigned long data_size, efi_char16_t *data)		\
+{										\
+	struct ia64_fpreg fr[6];						\
+										\
+	ia64_save_scratch_fpregs(fr);						\
+	efi_call_##prefix((efi_reset_system_t *) __va(runtime->reset_system),	\
+			  reset_type, status, data_size, adjust_arg(data));	\
+	/* should not return, but just in case... */				\
+	ia64_load_scratch_fpregs(fr);						\
+}
+
+STUB_GET_TIME(phys, __pa)
+STUB_SET_TIME(phys, __pa)
+STUB_GET_WAKEUP_TIME(phys, __pa)
+STUB_SET_WAKEUP_TIME(phys, __pa)
+STUB_GET_VARIABLE(phys, __pa)
+STUB_GET_NEXT_VARIABLE(phys, __pa)
+STUB_SET_VARIABLE(phys, __pa)
+STUB_GET_NEXT_HIGH_MONO_COUNT(phys, __pa)
+STUB_RESET_SYSTEM(phys, __pa)
+
+STUB_GET_TIME(virt, )
+STUB_SET_TIME(virt, )
+STUB_GET_WAKEUP_TIME(virt, )
+STUB_SET_WAKEUP_TIME(virt, )
+STUB_GET_VARIABLE(virt, )
+STUB_GET_NEXT_VARIABLE(virt, )
+STUB_SET_VARIABLE(virt, )
+STUB_GET_NEXT_HIGH_MONO_COUNT(virt, )
+STUB_RESET_SYSTEM(virt, )
 
 void
 efi_gettimeofday (struct timeval *tv)
@@ -207,7 +297,7 @@
 		u64 start;
 		u64 end;
 	} prev, curr;
-	void *efi_map_start, *efi_map_end, *p, *q;
+	void *efi_map_start, *efi_map_end, *p, *q, *r;
 	efi_memory_desc_t *md, *check_md;
 	u64 efi_desc_size, start, end, granule_addr, first_non_wb_addr = 0;
 
@@ -252,11 +342,10 @@
 
 			if (!(first_non_wb_addr > granule_addr))
 				continue;	/* couldn't find enough contiguous memory */
-		}
-
-		/* BUG_ON((md->phys_addr >> IA64_GRANULE_SHIFT) < first_non_wb_addr); */
 
-		trim_top(md, first_non_wb_addr);
+			for (r = p; r < q; r += efi_desc_size)
+				trim_top(r, first_non_wb_addr);
+		}
 
 		if (is_available_memory(md)) {
 			if (md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) > mem_limit) {
@@ -540,23 +629,22 @@
 			       efi_desc_size, ia64_boot_param->efi_memdesc_version,
 			       ia64_boot_param->efi_memmap);
 	if (status != EFI_SUCCESS) {
-		printk("Warning: unable to switch EFI into virtual mode (status=%lu)\n", status);
+		printk("Warning: unable to switch EFI into virtual mode (status=0x%lx)\n", status);
 		return;
 	}
 
 	/*
-	 * Now that EFI is in virtual mode, we arrange for EFI functions to be
-	 * called directly:
+	 * Now that EFI is in virtual mode, we call the EFI functions more efficiently:
 	 */
-	efi.get_time = __va(runtime->get_time);
-	efi.set_time = __va(runtime->set_time);
-	efi.get_wakeup_time = __va(runtime->get_wakeup_time);
-	efi.set_wakeup_time = __va(runtime->set_wakeup_time);
-	efi.get_variable = __va(runtime->get_variable);
-	efi.get_next_variable = __va(runtime->get_next_variable);
-	efi.set_variable = __va(runtime->set_variable);
-	efi.get_next_high_mono_count = __va(runtime->get_next_high_mono_count);
-	efi.reset_system = __va(runtime->reset_system);
+	efi.get_time = virt_get_time;
+	efi.set_time = virt_set_time;
+	efi.get_wakeup_time = virt_get_wakeup_time;
+	efi.set_wakeup_time = virt_set_wakeup_time;
+	efi.get_variable = virt_get_variable;
+	efi.get_next_variable = virt_get_next_variable;
+	efi.set_variable = virt_set_variable;
+	efi.get_next_high_mono_count = virt_get_next_high_mono_count;
+	efi.reset_system = virt_reset_system;
 }
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/entry.S linux-2.4.21-pre6/arch/ia64/kernel/entry.S
--- linux-2.4.20/arch/ia64/kernel/entry.S	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/kernel/entry.S	2003-03-26 23:49:19.000000000 +0000
@@ -1109,7 +1109,7 @@
 	data8 sys_mlock
 	data8 sys_mlockall
 	data8 sys_mprotect			// 1155
-	data8 sys_mremap
+	data8 ia64_mremap
 	data8 sys_msync
 	data8 sys_munlock
 	data8 sys_munlockall
@@ -1170,18 +1170,18 @@
 	data8 sys_getdents64
 	data8 sys_getunwind			// 1215
 	data8 sys_readahead
-	data8 ia64_ni_syscall
-	data8 ia64_ni_syscall
-	data8 ia64_ni_syscall
-	data8 ia64_ni_syscall			// 1220
-	data8 ia64_ni_syscall
-	data8 ia64_ni_syscall
-	data8 ia64_ni_syscall
-	data8 ia64_ni_syscall
-	data8 ia64_ni_syscall			// 1225
-	data8 ia64_ni_syscall
-	data8 ia64_ni_syscall
-	data8 ia64_ni_syscall
+	data8 sys_setxattr
+	data8 sys_lsetxattr
+	data8 sys_fsetxattr
+	data8 sys_getxattr			// 1220
+	data8 sys_lgetxattr
+	data8 sys_fgetxattr
+	data8 sys_listxattr
+	data8 sys_llistxattr
+	data8 sys_flistxattr			// 1225
+	data8 sys_removexattr
+	data8 sys_lremovexattr
+	data8 sys_fremovexattr
 	data8 sys_tkill
 	data8 ia64_ni_syscall			// 1230
 	data8 ia64_ni_syscall
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/fw-emu.c linux-2.4.21-pre6/arch/ia64/kernel/fw-emu.c
--- linux-2.4.20/arch/ia64/kernel/fw-emu.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/kernel/fw-emu.c	2003-03-26 23:48:59.000000000 +0000
@@ -2,7 +2,7 @@
  * PAL & SAL emulation.
  *
  * Copyright (C) 1998-2001 Hewlett-Packard Co
- * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
  *
  * For the HP simulator, this file gets include in boot/bootloader.c.
  * For SoftSDV, this file gets included in sys_softsdv.c.
@@ -19,10 +19,14 @@
 #include <asm/sal.h>
 
 #define MB	(1024*1024UL)
-#define GB	(1024*MB)
-#define TB	(1024*GB)
 
-#define NUM_MEM_DESCS	4
+#define SIMPLE_MEMMAP	1
+
+#if SIMPLE_MEMMAP
+# define NUM_MEM_DESCS	4
+#else
+# define NUM_MEM_DESCS	16
+#endif
 
 static char fw_mem[(  sizeof(struct ia64_boot_param)
 		    + sizeof(efi_system_table_t)
@@ -381,6 +385,17 @@
 	struct ia64_boot_param *bp;
 	unsigned char checksum = 0;
 	char *cp, *cmd_line;
+	int i = 0;
+#	define MAKE_MD(typ, attr, start, end)		\
+	do {						\
+		md = efi_memmap + i++;			\
+		md->type = typ;				\
+		md->pad = 0;				\
+		md->phys_addr = start;			\
+		md->virt_addr = 0;			\
+		md->num_pages = (end - start) >> 12;	\
+		md->attribute = attr;			\
+	} while (0)
 
 	memset(fw_mem, 0, sizeof(fw_mem));
 
@@ -466,41 +481,30 @@
 
 	sal_systab->checksum = -checksum;
 
+#if SIMPLE_MEMMAP
 	/* simulate free memory at physical address zero */
-	md = &efi_memmap[0];
-	md->type = EFI_BOOT_SERVICES_DATA;
-	md->pad = 0;
-	md->phys_addr = 0*MB;
-	md->virt_addr = 0;
-	md->num_pages = (1*MB) >> 12;	/* 1MB (in 4KB pages) */
-	md->attribute = EFI_MEMORY_WB | EFI_MEMORY_WC | EFI_MEMORY_UC;
-
-	/* fill in a memory descriptor: */
-	md = &efi_memmap[1];
-	md->type = EFI_CONVENTIONAL_MEMORY;
-	md->pad = 0;
-	md->phys_addr = 2*MB;
-	md->virt_addr = 0;
-	md->num_pages = (128*MB) >> 12;	/* 128MB (in 4KB pages) */
-	md->attribute = EFI_MEMORY_WB;
-
-	/* descriptor for firmware emulator: */
-	md = &efi_memmap[2];
-	md->type = EFI_PAL_CODE;
-	md->pad = 0;
-	md->phys_addr = 1*MB;
-	md->virt_addr = 1*MB;
-	md->num_pages = (1*MB) >> 12;	/* 1MB (in 4KB pages) */
-	md->attribute = EFI_MEMORY_WB | EFI_MEMORY_WC | EFI_MEMORY_UC;
-
-	/* descriptor for high memory (>4TB): */
-	md = &efi_memmap[3];
-	md->type = EFI_CONVENTIONAL_MEMORY;
-	md->pad = 0;
-	md->phys_addr = 4*TB;
-	md->virt_addr = 0;
-	md->num_pages = (64*MB) >> 12;	/* 64MB (in 4KB pages) */
-	md->attribute = EFI_MEMORY_WB;
+	MAKE_MD(EFI_BOOT_SERVICES_DATA,		EFI_MEMORY_WB,    0*MB,    1*MB);
+	MAKE_MD(EFI_PAL_CODE,			EFI_MEMORY_WB,    1*MB,    2*MB);
+	MAKE_MD(EFI_CONVENTIONAL_MEMORY,	EFI_MEMORY_WB,    2*MB,  130*MB);
+	MAKE_MD(EFI_CONVENTIONAL_MEMORY,	EFI_MEMORY_WB, 4096*MB, 4128*MB);
+#else
+	MAKE_MD( 4,		   0x9, 0x0000000000000000, 0x0000000000001000);
+	MAKE_MD( 7,		   0x9, 0x0000000000001000, 0x000000000008a000);
+	MAKE_MD( 4,		   0x9, 0x000000000008a000, 0x00000000000a0000);
+	MAKE_MD( 5, 0x8000000000000009, 0x00000000000c0000, 0x0000000000100000);
+	MAKE_MD( 7,		   0x9, 0x0000000000100000, 0x0000000004400000);
+	MAKE_MD( 2,		   0x9, 0x0000000004400000, 0x0000000004be5000);
+	MAKE_MD( 7,		   0x9, 0x0000000004be5000, 0x000000007f77e000);
+	MAKE_MD( 6, 0x8000000000000009, 0x000000007f77e000, 0x000000007fb94000);
+	MAKE_MD( 6, 0x8000000000000009, 0x000000007fb94000, 0x000000007fb95000);
+	MAKE_MD( 6, 0x8000000000000009, 0x000000007fb95000, 0x000000007fc00000);
+	MAKE_MD(13, 0x8000000000000009, 0x000000007fc00000, 0x000000007fc3a000);
+	MAKE_MD( 7,		   0x9, 0x000000007fc3a000, 0x000000007fea0000);
+	MAKE_MD( 5, 0x8000000000000009, 0x000000007fea0000, 0x000000007fea8000);
+	MAKE_MD( 7,		   0x9, 0x000000007fea8000, 0x000000007feab000);
+	MAKE_MD( 5, 0x8000000000000009, 0x000000007feab000, 0x000000007ffff000);
+	MAKE_MD( 7,		   0x9, 0x00000000ff400000, 0x0000000104000000);
+#endif
 
 	bp->efi_systab = __pa(&fw_mem);
 	bp->efi_memmap = __pa(efi_memmap);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/gate.S linux-2.4.21-pre6/arch/ia64/kernel/gate.S
--- linux-2.4.20/arch/ia64/kernel/gate.S	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/kernel/gate.S	2003-03-26 23:49:20.000000000 +0000
@@ -2,7 +2,7 @@
  * This file contains the code that gets mapped at the upper end of each task's text
  * region.  For now, it contains the signal trampoline code only.
  *
- * Copyright (C) 1999-2001 Hewlett-Packard Co
+ * Copyright (C) 1999-2002 Hewlett-Packard Co
  * 	David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
@@ -135,7 +135,7 @@
 	;;
 	ld8 r8=[base0]				// restore (perhaps modified) CFM0, EC0, and CPL0
 	cmp.ne p8,p0=r14,r15			// do we need to restore the rbs?
-(p8)	br.cond.spnt restore_rbs		// yup -> (clobbers r14 and r16)
+(p8)	br.cond.spnt restore_rbs		// yup -> (clobbers r14-r18, f6 & f7)
 	;;
 back_from_restore_rbs:
 	adds base0=(FR6_OFF+SIGCONTEXT_OFF),sp
@@ -189,20 +189,69 @@
 	.spillsp ar.rnat, RNAT_OFF+SIGCONTEXT_OFF
 	.body
 restore_rbs:
+	// On input:
+	//	r14 = bsp1 (bsp at the time of return from signal handler)
+	//	r15 = bsp0 (bsp at the time the signal occurred)
+	//
+	// Here, we need to calculate bspstore0, the value that ar.bspstore needs
+	// to be set to, based on bsp0 and the size of the dirty partition on
+	// the alternate stack (sc_loadrs >> 16).  This can be done with the
+	// following algorithm:
+	//
+	//  bspstore0 = rse_skip_regs(bsp0, -rse_num_regs(bsp1 - (loadrs >> 19), bsp1));
+	//
+	// This is what the code below does.
+	//
 	alloc r2=ar.pfs,0,0,0,0			// alloc null frame
 	adds r16=(LOADRS_OFF+SIGCONTEXT_OFF),sp
+	adds r18=(RNAT_OFF+SIGCONTEXT_OFF),sp
 	;;
-	ld8 r14=[r16]
-	adds r16=(RNAT_OFF+SIGCONTEXT_OFF),sp
+	ld8 r17=[r16]
+	ld8 r16=[r18]			// get new rnat
+	extr.u r18=r15,3,6	// r18 <- rse_slot_num(bsp0)
 	;;
-	mov ar.rsc=r14				// put RSE into enforced lazy mode
-	ld8 r14=[r16]				// get new rnat
+	mov ar.rsc=r17			// put RSE into enforced lazy mode
+	shr.u r17=r17,16
 	;;
-	loadrs					// restore dirty partition
+	sub r14=r14,r17		// r14 (bspstore1) <- bsp1 - (sc_loadrs >> 16)
+	shr.u r17=r17,3		// r17 <- (sc_loadrs >> 19)
+	;;
+	loadrs			// restore dirty partition
+	extr.u r14=r14,3,6	// r14 <- rse_slot_num(bspstore1)
+	;;
+	add r14=r14,r17		// r14 <- rse_slot_num(bspstore1) + (sc_loadrs >> 19)
+	;;
+	shr.u r14=r14,6		// r14 <- (rse_slot_num(bspstore1) + (sc_loadrs >> 19))/0x40
+	;;
+	sub r14=r14,r17		// r14 <- -rse_num_regs(bspstore1, bsp1)
+	movl r17=0x8208208208208209
+	;;
+	add r18=r18,r14		// r18 (delta) <- rse_slot_num(bsp0) - rse_num_regs(bspstore1,bsp1)
+	setf.sig f7=r17
+	cmp.lt p7,p0=r14,r0	// p7 <- (r14 < 0)?
+	;;
+(p7)	adds r18=-62,r18	// delta -= 62
+	;;
+	setf.sig f6=r18
+	;;
+	xmpy.h f6=f6,f7
+	;;
+	getf.sig r17=f6
+	;;
+	add r17=r17,r18
+	shr r18=r18,63
+	;;
+	shr r17=r17,5
+	;;
+	sub r17=r17,r18		// r17 = delta/63
+	;;
+	add r17=r14,r17		// r17 <- delta/63 - rse_num_regs(bspstore1, bsp1)
+	;;
+	shladd r15=r17,3,r15	// r15 <- bsp0 + 8*(delta/63 - rse_num_regs(bspstore1, bsp1))
 	;;
 	mov ar.bspstore=r15			// switch back to old register backing store area
 	;;
-	mov ar.rnat=r14				// restore RNaT
+	mov ar.rnat=r16				// restore RNaT
 	mov ar.rsc=0xf				// (will be restored later on from sc_ar_rsc)
 	// invala not necessary as that will happen when returning to user-mode
 	br.cond.sptk back_from_restore_rbs
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/head.S linux-2.4.21-pre6/arch/ia64/kernel/head.S
--- linux-2.4.20/arch/ia64/kernel/head.S	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/kernel/head.S	2003-03-26 23:49:50.000000000 +0000
@@ -13,6 +13,8 @@
  * Copyright (C) 1999 Intel Corp.
  * Copyright (C) 1999 Asit Mallick <Asit.K.Mallick@intel.com>
  * Copyright (C) 1999 Don Dugger <Don.Dugger@intel.com>
+ * Copyright (C) 2002 Fenghua Yu <fenghua.yu@intel.com>
+ *   -Optimize __ia64_save_fpu() and __ia64_load_fpu() for Itanium 2.
  */
 
 #include <linux/config.h>
@@ -262,302 +264,297 @@
 END(ia64_load_debug_regs)
 
 GLOBAL_ENTRY(__ia64_save_fpu)
-	alloc r2=ar.pfs,1,0,0,0
-	adds r3=16,in0
+	alloc r2=ar.pfs,1,4,0,0
+	adds loc0=96*16-16,in0
+	adds loc1=96*16-16-128,in0
 	;;
-	stf.spill.nta [in0]=f32,32
-	stf.spill.nta [ r3]=f33,32
+	stf.spill.nta [loc0]=f127,-256
+	stf.spill.nta [loc1]=f119,-256
 	;;
-	stf.spill.nta [in0]=f34,32
-	stf.spill.nta [ r3]=f35,32
+	stf.spill.nta [loc0]=f111,-256
+	stf.spill.nta [loc1]=f103,-256
 	;;
-	stf.spill.nta [in0]=f36,32
-	stf.spill.nta [ r3]=f37,32
+	stf.spill.nta [loc0]=f95,-256
+	stf.spill.nta [loc1]=f87,-256
 	;;
-	stf.spill.nta [in0]=f38,32
-	stf.spill.nta [ r3]=f39,32
+	stf.spill.nta [loc0]=f79,-256
+	stf.spill.nta [loc1]=f71,-256
 	;;
-	stf.spill.nta [in0]=f40,32
-	stf.spill.nta [ r3]=f41,32
+	stf.spill.nta [loc0]=f63,-256
+	stf.spill.nta [loc1]=f55,-256
+	adds loc2=96*16-32,in0
 	;;
-	stf.spill.nta [in0]=f42,32
-	stf.spill.nta [ r3]=f43,32
+	stf.spill.nta [loc0]=f47,-256
+	stf.spill.nta [loc1]=f39,-256
+	adds loc3=96*16-32-128,in0
 	;;
-	stf.spill.nta [in0]=f44,32
-	stf.spill.nta [ r3]=f45,32
+	stf.spill.nta [loc2]=f126,-256
+	stf.spill.nta [loc3]=f118,-256
 	;;
-	stf.spill.nta [in0]=f46,32
-	stf.spill.nta [ r3]=f47,32
+	stf.spill.nta [loc2]=f110,-256
+	stf.spill.nta [loc3]=f102,-256
 	;;
-	stf.spill.nta [in0]=f48,32
-	stf.spill.nta [ r3]=f49,32
+	stf.spill.nta [loc2]=f94,-256
+	stf.spill.nta [loc3]=f86,-256
 	;;
-	stf.spill.nta [in0]=f50,32
-	stf.spill.nta [ r3]=f51,32
+	stf.spill.nta [loc2]=f78,-256
+	stf.spill.nta [loc3]=f70,-256
 	;;
-	stf.spill.nta [in0]=f52,32
-	stf.spill.nta [ r3]=f53,32
+	stf.spill.nta [loc2]=f62,-256
+	stf.spill.nta [loc3]=f54,-256
+	adds loc0=96*16-48,in0
 	;;
-	stf.spill.nta [in0]=f54,32
-	stf.spill.nta [ r3]=f55,32
+	stf.spill.nta [loc2]=f46,-256
+	stf.spill.nta [loc3]=f38,-256
+	adds loc1=96*16-48-128,in0
 	;;
-	stf.spill.nta [in0]=f56,32
-	stf.spill.nta [ r3]=f57,32
+	stf.spill.nta [loc0]=f125,-256
+	stf.spill.nta [loc1]=f117,-256
 	;;
-	stf.spill.nta [in0]=f58,32
-	stf.spill.nta [ r3]=f59,32
+	stf.spill.nta [loc0]=f109,-256
+	stf.spill.nta [loc1]=f101,-256
 	;;
-	stf.spill.nta [in0]=f60,32
-	stf.spill.nta [ r3]=f61,32
+	stf.spill.nta [loc0]=f93,-256
+	stf.spill.nta [loc1]=f85,-256
 	;;
-	stf.spill.nta [in0]=f62,32
-	stf.spill.nta [ r3]=f63,32
+	stf.spill.nta [loc0]=f77,-256
+	stf.spill.nta [loc1]=f69,-256
 	;;
-	stf.spill.nta [in0]=f64,32
-	stf.spill.nta [ r3]=f65,32
+	stf.spill.nta [loc0]=f61,-256
+	stf.spill.nta [loc1]=f53,-256
+	adds loc2=96*16-64,in0
 	;;
-	stf.spill.nta [in0]=f66,32
-	stf.spill.nta [ r3]=f67,32
+	stf.spill.nta [loc0]=f45,-256
+	stf.spill.nta [loc1]=f37,-256
+	adds loc3=96*16-64-128,in0
 	;;
-	stf.spill.nta [in0]=f68,32
-	stf.spill.nta [ r3]=f69,32
+	stf.spill.nta [loc2]=f124,-256
+	stf.spill.nta [loc3]=f116,-256
 	;;
-	stf.spill.nta [in0]=f70,32
-	stf.spill.nta [ r3]=f71,32
+	stf.spill.nta [loc2]=f108,-256
+	stf.spill.nta [loc3]=f100,-256
 	;;
-	stf.spill.nta [in0]=f72,32
-	stf.spill.nta [ r3]=f73,32
+	stf.spill.nta [loc2]=f92,-256
+	stf.spill.nta [loc3]=f84,-256
 	;;
-	stf.spill.nta [in0]=f74,32
-	stf.spill.nta [ r3]=f75,32
+	stf.spill.nta [loc2]=f76,-256
+	stf.spill.nta [loc3]=f68,-256
 	;;
-	stf.spill.nta [in0]=f76,32
-	stf.spill.nta [ r3]=f77,32
+	stf.spill.nta [loc2]=f60,-256
+	stf.spill.nta [loc3]=f52,-256
+	adds loc0=96*16-80,in0
 	;;
-	stf.spill.nta [in0]=f78,32
-	stf.spill.nta [ r3]=f79,32
+	stf.spill.nta [loc2]=f44,-256
+	stf.spill.nta [loc3]=f36,-256
+	adds loc1=96*16-80-128,in0
 	;;
-	stf.spill.nta [in0]=f80,32
-	stf.spill.nta [ r3]=f81,32
+	stf.spill.nta [loc0]=f123,-256
+	stf.spill.nta [loc1]=f115,-256
 	;;
-	stf.spill.nta [in0]=f82,32
-	stf.spill.nta [ r3]=f83,32
+	stf.spill.nta [loc0]=f107,-256
+	stf.spill.nta [loc1]=f99,-256
 	;;
-	stf.spill.nta [in0]=f84,32
-	stf.spill.nta [ r3]=f85,32
+	stf.spill.nta [loc0]=f91,-256
+	stf.spill.nta [loc1]=f83,-256
 	;;
-	stf.spill.nta [in0]=f86,32
-	stf.spill.nta [ r3]=f87,32
+	stf.spill.nta [loc0]=f75,-256
+	stf.spill.nta [loc1]=f67,-256
 	;;
-	stf.spill.nta [in0]=f88,32
-	stf.spill.nta [ r3]=f89,32
+	stf.spill.nta [loc0]=f59,-256
+	stf.spill.nta [loc1]=f51,-256
+	adds loc2=96*16-96,in0
 	;;
-	stf.spill.nta [in0]=f90,32
-	stf.spill.nta [ r3]=f91,32
+	stf.spill.nta [loc0]=f43,-256
+	stf.spill.nta [loc1]=f35,-256
+	adds loc3=96*16-96-128,in0
 	;;
-	stf.spill.nta [in0]=f92,32
-	stf.spill.nta [ r3]=f93,32
+	stf.spill.nta [loc2]=f122,-256
+	stf.spill.nta [loc3]=f114,-256
 	;;
-	stf.spill.nta [in0]=f94,32
-	stf.spill.nta [ r3]=f95,32
+	stf.spill.nta [loc2]=f106,-256
+	stf.spill.nta [loc3]=f98,-256
 	;;
-	stf.spill.nta [in0]=f96,32
-	stf.spill.nta [ r3]=f97,32
+	stf.spill.nta [loc2]=f90,-256
+	stf.spill.nta [loc3]=f82,-256
 	;;
-	stf.spill.nta [in0]=f98,32
-	stf.spill.nta [ r3]=f99,32
+	stf.spill.nta [loc2]=f74,-256
+	stf.spill.nta [loc3]=f66,-256
 	;;
-	stf.spill.nta [in0]=f100,32
-	stf.spill.nta [ r3]=f101,32
+	stf.spill.nta [loc2]=f58,-256
+	stf.spill.nta [loc3]=f50,-256
+	adds loc0=96*16-112,in0
 	;;
-	stf.spill.nta [in0]=f102,32
-	stf.spill.nta [ r3]=f103,32
+	stf.spill.nta [loc2]=f42,-256
+	stf.spill.nta [loc3]=f34,-256
+	adds loc1=96*16-112-128,in0
 	;;
-	stf.spill.nta [in0]=f104,32
-	stf.spill.nta [ r3]=f105,32
+	stf.spill.nta [loc0]=f121,-256
+	stf.spill.nta [loc1]=f113,-256
 	;;
-	stf.spill.nta [in0]=f106,32
-	stf.spill.nta [ r3]=f107,32
+	stf.spill.nta [loc0]=f105,-256
+	stf.spill.nta [loc1]=f97,-256
 	;;
-	stf.spill.nta [in0]=f108,32
-	stf.spill.nta [ r3]=f109,32
+	stf.spill.nta [loc0]=f89,-256
+	stf.spill.nta [loc1]=f81,-256
 	;;
-	stf.spill.nta [in0]=f110,32
-	stf.spill.nta [ r3]=f111,32
+	stf.spill.nta [loc0]=f73,-256
+	stf.spill.nta [loc1]=f65,-256
 	;;
-	stf.spill.nta [in0]=f112,32
-	stf.spill.nta [ r3]=f113,32
+	stf.spill.nta [loc0]=f57,-256
+	stf.spill.nta [loc1]=f49,-256
+	adds loc2=96*16-128,in0
 	;;
-	stf.spill.nta [in0]=f114,32
-	stf.spill.nta [ r3]=f115,32
+	stf.spill.nta [loc0]=f41,-256
+	stf.spill.nta [loc1]=f33,-256
+	adds loc3=96*16-128-128,in0
 	;;
-	stf.spill.nta [in0]=f116,32
-	stf.spill.nta [ r3]=f117,32
+	stf.spill.nta [loc2]=f120,-256
+	stf.spill.nta [loc3]=f112,-256
 	;;
-	stf.spill.nta [in0]=f118,32
-	stf.spill.nta [ r3]=f119,32
+	stf.spill.nta [loc2]=f104,-256
+	stf.spill.nta [loc3]=f96,-256
 	;;
-	stf.spill.nta [in0]=f120,32
-	stf.spill.nta [ r3]=f121,32
+	stf.spill.nta [loc2]=f88,-256
+	stf.spill.nta [loc3]=f80,-256
 	;;
-	stf.spill.nta [in0]=f122,32
-	stf.spill.nta [ r3]=f123,32
+	stf.spill.nta [loc2]=f72,-256
+	stf.spill.nta [loc3]=f64,-256
 	;;
-	stf.spill.nta [in0]=f124,32
-	stf.spill.nta [ r3]=f125,32
+	stf.spill.nta [loc2]=f56,-256
+	stf.spill.nta [loc3]=f48,-256
 	;;
-	stf.spill.nta [in0]=f126,32
-	stf.spill.nta [ r3]=f127,32
+	stf.spill.nta [loc2]=f40
+	stf.spill.nta [loc3]=f32
 	br.ret.sptk.many rp
 END(__ia64_save_fpu)
 
 GLOBAL_ENTRY(__ia64_load_fpu)
-	alloc r2=ar.pfs,1,0,0,0
-	adds r3=16,in0
-	;;
-	ldf.fill.nta f32=[in0],32
-	ldf.fill.nta f33=[ r3],32
-	;;
-	ldf.fill.nta f34=[in0],32
-	ldf.fill.nta f35=[ r3],32
-	;;
-	ldf.fill.nta f36=[in0],32
-	ldf.fill.nta f37=[ r3],32
-	;;
-	ldf.fill.nta f38=[in0],32
-	ldf.fill.nta f39=[ r3],32
-	;;
-	ldf.fill.nta f40=[in0],32
-	ldf.fill.nta f41=[ r3],32
-	;;
-	ldf.fill.nta f42=[in0],32
-	ldf.fill.nta f43=[ r3],32
-	;;
-	ldf.fill.nta f44=[in0],32
-	ldf.fill.nta f45=[ r3],32
-	;;
-	ldf.fill.nta f46=[in0],32
-	ldf.fill.nta f47=[ r3],32
-	;;
-	ldf.fill.nta f48=[in0],32
-	ldf.fill.nta f49=[ r3],32
-	;;
-	ldf.fill.nta f50=[in0],32
-	ldf.fill.nta f51=[ r3],32
-	;;
-	ldf.fill.nta f52=[in0],32
-	ldf.fill.nta f53=[ r3],32
-	;;
-	ldf.fill.nta f54=[in0],32
-	ldf.fill.nta f55=[ r3],32
-	;;
-	ldf.fill.nta f56=[in0],32
-	ldf.fill.nta f57=[ r3],32
-	;;
-	ldf.fill.nta f58=[in0],32
-	ldf.fill.nta f59=[ r3],32
-	;;
-	ldf.fill.nta f60=[in0],32
-	ldf.fill.nta f61=[ r3],32
-	;;
-	ldf.fill.nta f62=[in0],32
-	ldf.fill.nta f63=[ r3],32
-	;;
-	ldf.fill.nta f64=[in0],32
-	ldf.fill.nta f65=[ r3],32
-	;;
-	ldf.fill.nta f66=[in0],32
-	ldf.fill.nta f67=[ r3],32
-	;;
-	ldf.fill.nta f68=[in0],32
-	ldf.fill.nta f69=[ r3],32
-	;;
-	ldf.fill.nta f70=[in0],32
-	ldf.fill.nta f71=[ r3],32
-	;;
-	ldf.fill.nta f72=[in0],32
-	ldf.fill.nta f73=[ r3],32
-	;;
-	ldf.fill.nta f74=[in0],32
-	ldf.fill.nta f75=[ r3],32
-	;;
-	ldf.fill.nta f76=[in0],32
-	ldf.fill.nta f77=[ r3],32
-	;;
-	ldf.fill.nta f78=[in0],32
-	ldf.fill.nta f79=[ r3],32
-	;;
-	ldf.fill.nta f80=[in0],32
-	ldf.fill.nta f81=[ r3],32
-	;;
-	ldf.fill.nta f82=[in0],32
-	ldf.fill.nta f83=[ r3],32
-	;;
-	ldf.fill.nta f84=[in0],32
-	ldf.fill.nta f85=[ r3],32
-	;;
-	ldf.fill.nta f86=[in0],32
-	ldf.fill.nta f87=[ r3],32
-	;;
-	ldf.fill.nta f88=[in0],32
-	ldf.fill.nta f89=[ r3],32
-	;;
-	ldf.fill.nta f90=[in0],32
-	ldf.fill.nta f91=[ r3],32
-	;;
-	ldf.fill.nta f92=[in0],32
-	ldf.fill.nta f93=[ r3],32
-	;;
-	ldf.fill.nta f94=[in0],32
-	ldf.fill.nta f95=[ r3],32
-	;;
-	ldf.fill.nta f96=[in0],32
-	ldf.fill.nta f97=[ r3],32
-	;;
-	ldf.fill.nta f98=[in0],32
-	ldf.fill.nta f99=[ r3],32
-	;;
-	ldf.fill.nta f100=[in0],32
-	ldf.fill.nta f101=[ r3],32
-	;;
-	ldf.fill.nta f102=[in0],32
-	ldf.fill.nta f103=[ r3],32
-	;;
-	ldf.fill.nta f104=[in0],32
-	ldf.fill.nta f105=[ r3],32
-	;;
-	ldf.fill.nta f106=[in0],32
-	ldf.fill.nta f107=[ r3],32
-	;;
-	ldf.fill.nta f108=[in0],32
-	ldf.fill.nta f109=[ r3],32
-	;;
-	ldf.fill.nta f110=[in0],32
-	ldf.fill.nta f111=[ r3],32
-	;;
-	ldf.fill.nta f112=[in0],32
-	ldf.fill.nta f113=[ r3],32
-	;;
-	ldf.fill.nta f114=[in0],32
-	ldf.fill.nta f115=[ r3],32
-	;;
-	ldf.fill.nta f116=[in0],32
-	ldf.fill.nta f117=[ r3],32
-	;;
-	ldf.fill.nta f118=[in0],32
-	ldf.fill.nta f119=[ r3],32
-	;;
-	ldf.fill.nta f120=[in0],32
-	ldf.fill.nta f121=[ r3],32
-	;;
-	ldf.fill.nta f122=[in0],32
-	ldf.fill.nta f123=[ r3],32
-	;;
-	ldf.fill.nta f124=[in0],32
-	ldf.fill.nta f125=[ r3],32
-	;;
-	ldf.fill.nta f126=[in0],32
-	ldf.fill.nta f127=[ r3],32
+	alloc r2=ar.pfs,1,2,0,0
+	adds r3=128,in0
+	adds r14=256,in0
+	adds r15=384,in0
+	mov loc0=512
+	mov loc1=-1024+16
+	;;
+	ldf.fill.nta f32=[in0],loc0
+	ldf.fill.nta f40=[ r3],loc0
+	ldf.fill.nta f48=[r14],loc0
+	ldf.fill.nta f56=[r15],loc0
+	;;
+	ldf.fill.nta f64=[in0],loc0
+	ldf.fill.nta f72=[ r3],loc0
+	ldf.fill.nta f80=[r14],loc0
+	ldf.fill.nta f88=[r15],loc0
+	;;
+	ldf.fill.nta f96=[in0],loc1
+	ldf.fill.nta f104=[ r3],loc1
+	ldf.fill.nta f112=[r14],loc1
+	ldf.fill.nta f120=[r15],loc1
+	;;
+	ldf.fill.nta f33=[in0],loc0
+	ldf.fill.nta f41=[ r3],loc0
+	ldf.fill.nta f49=[r14],loc0
+	ldf.fill.nta f57=[r15],loc0
+	;;
+	ldf.fill.nta f65=[in0],loc0
+	ldf.fill.nta f73=[ r3],loc0
+	ldf.fill.nta f81=[r14],loc0
+	ldf.fill.nta f89=[r15],loc0
+	;;
+	ldf.fill.nta f97=[in0],loc1
+	ldf.fill.nta f105=[ r3],loc1
+	ldf.fill.nta f113=[r14],loc1
+	ldf.fill.nta f121=[r15],loc1
+	;;
+	ldf.fill.nta f34=[in0],loc0
+	ldf.fill.nta f42=[ r3],loc0
+	ldf.fill.nta f50=[r14],loc0
+	ldf.fill.nta f58=[r15],loc0
+	;;
+	ldf.fill.nta f66=[in0],loc0
+	ldf.fill.nta f74=[ r3],loc0
+	ldf.fill.nta f82=[r14],loc0
+	ldf.fill.nta f90=[r15],loc0
+	;;
+	ldf.fill.nta f98=[in0],loc1
+	ldf.fill.nta f106=[ r3],loc1
+	ldf.fill.nta f114=[r14],loc1
+	ldf.fill.nta f122=[r15],loc1
+	;;
+	ldf.fill.nta f35=[in0],loc0
+	ldf.fill.nta f43=[ r3],loc0
+	ldf.fill.nta f51=[r14],loc0
+	ldf.fill.nta f59=[r15],loc0
+	;;
+	ldf.fill.nta f67=[in0],loc0
+	ldf.fill.nta f75=[ r3],loc0
+	ldf.fill.nta f83=[r14],loc0
+	ldf.fill.nta f91=[r15],loc0
+	;;
+	ldf.fill.nta f99=[in0],loc1
+	ldf.fill.nta f107=[ r3],loc1
+	ldf.fill.nta f115=[r14],loc1
+	ldf.fill.nta f123=[r15],loc1
+	;;
+	ldf.fill.nta f36=[in0],loc0
+	ldf.fill.nta f44=[ r3],loc0
+	ldf.fill.nta f52=[r14],loc0
+	ldf.fill.nta f60=[r15],loc0
+	;;
+	ldf.fill.nta f68=[in0],loc0
+	ldf.fill.nta f76=[ r3],loc0
+	ldf.fill.nta f84=[r14],loc0
+	ldf.fill.nta f92=[r15],loc0
+	;;
+	ldf.fill.nta f100=[in0],loc1
+	ldf.fill.nta f108=[ r3],loc1
+	ldf.fill.nta f116=[r14],loc1
+	ldf.fill.nta f124=[r15],loc1
+	;;
+	ldf.fill.nta f37=[in0],loc0
+	ldf.fill.nta f45=[ r3],loc0
+	ldf.fill.nta f53=[r14],loc0
+	ldf.fill.nta f61=[r15],loc0
+	;;
+	ldf.fill.nta f69=[in0],loc0
+	ldf.fill.nta f77=[ r3],loc0
+	ldf.fill.nta f85=[r14],loc0
+	ldf.fill.nta f93=[r15],loc0
+	;;
+	ldf.fill.nta f101=[in0],loc1
+	ldf.fill.nta f109=[ r3],loc1
+	ldf.fill.nta f117=[r14],loc1
+	ldf.fill.nta f125=[r15],loc1
+	;;
+	ldf.fill.nta f38 =[in0],loc0
+	ldf.fill.nta f46 =[ r3],loc0
+	ldf.fill.nta f54 =[r14],loc0
+	ldf.fill.nta f62 =[r15],loc0
+	;;
+	ldf.fill.nta f70 =[in0],loc0
+	ldf.fill.nta f78 =[ r3],loc0
+	ldf.fill.nta f86 =[r14],loc0
+	ldf.fill.nta f94 =[r15],loc0
+	;;
+	ldf.fill.nta f102=[in0],loc1
+	ldf.fill.nta f110=[ r3],loc1
+	ldf.fill.nta f118=[r14],loc1
+	ldf.fill.nta f126=[r15],loc1
+	;;
+	ldf.fill.nta f39 =[in0],loc0
+	ldf.fill.nta f47 =[ r3],loc0
+	ldf.fill.nta f55 =[r14],loc0
+	ldf.fill.nta f63 =[r15],loc0
+	;;
+	ldf.fill.nta f71 =[in0],loc0
+	ldf.fill.nta f79 =[ r3],loc0
+	ldf.fill.nta f87 =[r14],loc0
+	ldf.fill.nta f95 =[r15],loc0
+	;;
+	ldf.fill.nta f103=[in0]
+	ldf.fill.nta f111=[ r3]
+	ldf.fill.nta f119=[r14]
+	ldf.fill.nta f127=[r15]
 	br.ret.sptk.many rp
 END(__ia64_load_fpu)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/ia64_ksyms.c linux-2.4.21-pre6/arch/ia64/kernel/ia64_ksyms.c
--- linux-2.4.20/arch/ia64/kernel/ia64_ksyms.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/kernel/ia64_ksyms.c	2003-03-26 23:49:35.000000000 +0000
@@ -57,6 +57,10 @@
 #include <asm/page.h>
 EXPORT_SYMBOL(clear_page);
 
+#include <asm/pgtable.h>
+EXPORT_SYMBOL(vmalloc_end);
+EXPORT_SYMBOL(ia64_page_valid);
+
 #include <asm/processor.h>
 # ifndef CONFIG_NUMA
 EXPORT_SYMBOL(_cpu_data);
@@ -100,7 +104,7 @@
 
 #else /* !CONFIG_SMP */
 
-EXPORT_SYMBOL(__flush_tlb_all);
+EXPORT_SYMBOL(local_flush_tlb_all);
 
 #endif /* !CONFIG_SMP */
 
@@ -141,6 +145,8 @@
 EXPORT_SYMBOL(ia64_pal_call_phys_static);
 EXPORT_SYMBOL(ia64_pal_call_stacked);
 EXPORT_SYMBOL(ia64_pal_call_static);
+EXPORT_SYMBOL(ia64_load_scratch_fpregs);
+EXPORT_SYMBOL(ia64_save_scratch_fpregs);
 
 extern struct efi efi;
 EXPORT_SYMBOL(efi);
@@ -154,4 +160,8 @@
 EXPORT_SYMBOL(ia64_mv);
 #endif
 EXPORT_SYMBOL(machvec_noop);
-
+#ifdef CONFIG_PERFMON
+#include <asm/perfmon.h>
+EXPORT_SYMBOL(pfm_install_alternate_syswide_subsystem);
+EXPORT_SYMBOL(pfm_remove_alternate_syswide_subsystem);
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/iosapic.c linux-2.4.21-pre6/arch/ia64/kernel/iosapic.c
--- linux-2.4.20/arch/ia64/kernel/iosapic.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/kernel/iosapic.c	2003-03-26 23:49:35.000000000 +0000
@@ -590,7 +590,7 @@
 		      gsi_base, addr);
 
 	DBG("ISA: IRQ %u -> GSI 0x%x(%s,%s) -> CPU 0x%04x vector %d\n",
-	    isa_irq, global_vector,
+	    isa_irq, gsi,
 	    polarity ? "high" : "low", edge_triggered ? "edge" : "level",
 	    dest, vector);
 
@@ -661,7 +661,7 @@
 		register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY,
 			      0, 0, gsi_base, addr);
 
-		DBG("PCI: (%02x:%02x:%02x:%02x INT%c) -> GSI 0x%x -> vector %d\n",
+		DBG("PCI: (%02x:%02x:%02x INT%c) -> GSI 0x%x -> vector %d\n",
 		    segment, bus, slot, 'A' + pci_pin, gsi, vector);
 	}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/irq.c linux-2.4.21-pre6/arch/ia64/kernel/irq.c
--- linux-2.4.20/arch/ia64/kernel/irq.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/kernel/irq.c	2003-03-26 23:49:25.000000000 +0000
@@ -1060,7 +1060,7 @@
 
 	if (!shared) {
 		desc->depth = 0;
-		desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING);
+		desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING | IRQ_INPROGRESS);
 		desc->handler->startup(irq);
 	}
 	spin_unlock_irqrestore(&desc->lock,flags);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/irq_ia64.c linux-2.4.21-pre6/arch/ia64/kernel/irq_ia64.c
--- linux-2.4.20/arch/ia64/kernel/irq_ia64.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/kernel/irq_ia64.c	2003-03-26 23:49:30.000000000 +0000
@@ -178,7 +178,7 @@
 	register_percpu_irq(IA64_IPI_VECTOR, &ipi_irqaction);
 #endif
 #ifdef CONFIG_PERFMON
-	perfmon_init_percpu();
+	pfm_init_percpu();
 #endif
 	platform_irq_init();
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/machvec.c linux-2.4.21-pre6/arch/ia64/kernel/machvec.c
--- linux-2.4.20/arch/ia64/kernel/machvec.c	2001-01-04 20:50:17.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/kernel/machvec.c	2003-03-26 23:49:38.000000000 +0000
@@ -15,7 +15,7 @@
  * into a memory map index.
  */
 unsigned long
-map_nr_dense (unsigned long addr)
+map_nr_dense (void *addr)
 {
 	return MAP_NR_DENSE(addr);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/mca.c linux-2.4.21-pre6/arch/ia64/kernel/mca.c
--- linux-2.4.20/arch/ia64/kernel/mca.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/kernel/mca.c	2003-03-26 23:49:35.000000000 +0000
@@ -42,6 +42,9 @@
 #include <linux/smp_lock.h>
 #include <linux/bootmem.h>
 #include <linux/acpi.h>
+#include <linux/timer.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
 
 #include <asm/machvec.h>
 #include <asm/page.h>
@@ -69,10 +72,10 @@
 u64				ia64_mca_bspstore[1024];
 u64				ia64_init_stack[INIT_TASK_SIZE] __attribute__((aligned(16)));
 u64				ia64_mca_sal_data_area[1356];
-u64				ia64_mca_min_state_save_info;
 u64				ia64_tlb_functional;
 u64				ia64_os_mca_recovery_successful;
-
+/* TODO: need to assign min-state structure to UC memory */
+u64				ia64_mca_min_state_save_info[MIN_STATE_AREA_SIZE] __attribute__((aligned(512)));
 static void			ia64_mca_wakeup_ipi_wait(void);
 static void			ia64_mca_wakeup(int cpu);
 static void			ia64_mca_wakeup_all(void);
@@ -105,6 +108,11 @@
 	name:       "cpe_hndlr"
 };
 
+#define MAX_CPE_POLL_INTERVAL (15*60*HZ) /* 15 minutes */
+#define MIN_CPE_POLL_INTERVAL (2*60*HZ)  /* 2 minutes */
+
+static struct timer_list cpe_poll_timer;
+
 /*
  *  ia64_mca_log_sal_error_record
  *
@@ -116,7 +124,7 @@
  *  Outputs :   platform error status
  */
 int
-ia64_mca_log_sal_error_record(int sal_info_type)
+ia64_mca_log_sal_error_record(int sal_info_type, int called_from_init)
 {
 	int platform_err = 0;
 
@@ -131,7 +139,10 @@
 	 */
 
 	platform_err = ia64_log_print(sal_info_type, (prfunc_t)printk);
-	ia64_sal_clear_state_info(sal_info_type);
+	/* temporary: only clear SAL logs on hardware-corrected errors
+		or if we're logging an error after an MCA-initiated reboot */
+	if ((sal_info_type > 1) || (called_from_init))
+		ia64_sal_clear_state_info(sal_info_type);
 
 	return platform_err;
 }
@@ -152,7 +163,7 @@
 	IA64_MCA_DEBUG("ia64_mca_cpe_int_handler: received interrupt. vector = %#x\n", cpe_irq);
 
 	/* Get the CMC error record and log it */
-	ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CPE);
+	ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CPE, 0);
 }
 
 /*
@@ -205,7 +216,7 @@
 	/*
 	 *  If there is an MCA error record pending, get it and log it.
 	 */
-	ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA);
+	ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA, 1);
 }
 
 /*
@@ -257,15 +268,23 @@
  *
  */
 void
-ia64_process_min_state_save (pal_min_state_area_t *pmss, struct pt_regs *ptregs)
+ia64_process_min_state_save (pal_min_state_area_t *pmss)
 {
-	int i, max=57;
-	u64 *tpmss_ptr=(u64 *)pmss;
+	int i, max = MIN_STATE_AREA_SIZE;
+	u64 *tpmss_ptr = (u64 *)pmss;
+	u64 *return_min_state_ptr = ia64_mca_min_state_save_info;
 
 	/* dump out the min_state_area information */
 
 	for (i=0;i<max;i++) {
 
+		/* copy min-state register info for eventual return to PAL */
+		*return_min_state_ptr++ = *tpmss_ptr;
+
+#if 1
+		tpmss_ptr++;  /* skip to next entry */
+#else
+		/* the printing part */
 		if(!ia64_pmss_dump_bank0) {
 			if(strncmp("B0",min_state_labels[i],2)==0) {
 				tpmss_ptr++;  /* skip to next entry */
@@ -278,6 +297,7 @@
 		if (((i+1)%3)==0 || ((!strcmp("GR16",min_state_labels[i]))
 				     && !ia64_pmss_dump_bank0))
 			printk("\n");
+#endif
 	}
 }
 
@@ -510,8 +530,7 @@
 					setup_irq(irq, &mca_cpe_irqaction);
 				}
 			ia64_mca_register_cpev(cpev);
-		} else
-			printk("ia64_mca_init: Failed to get routed CPEI vector from ACPI.\n");
+		}
 	}
 
 	/* Initialize the areas set aside by the OS to buffer the
@@ -523,19 +542,17 @@
 	ia64_log_init(SAL_INFO_TYPE_CMC);
 	ia64_log_init(SAL_INFO_TYPE_CPE);
 
-	/* Zero the min state save info */
-	ia64_mca_min_state_save_info = 0;
-
 #if defined(MCA_TEST)
 	mca_test();
 #endif /* #if defined(MCA_TEST) */
 
 	printk("Mca related initialization done\n");
 
-#if 0   // Too early in initialization -- error log is lost
+	/* commented out because this is done elsewhere */
+#if 0
 	/* Do post-failure MCA error logging */
 	ia64_mca_check_errors();
-#endif  // Too early in initialization -- error log is lost
+#endif
 }
 
 /*
@@ -701,8 +718,8 @@
 	ia64_os_to_sal_handoff_state.imots_context = IA64_MCA_SAME_CONTEXT;
 
 	/* Register pointer to new min state values */
-	/* NOTE: need to do something with this during recovery phase */
-	ia64_os_to_sal_handoff_state.imots_new_min_state = &ia64_mca_min_state_save_info;
+	ia64_os_to_sal_handoff_state.imots_new_min_state =
+		(pal_min_state_area_t *)ia64_mca_min_state_save_info;
 }
 
 /*
@@ -727,7 +744,7 @@
 	int platform_err = 0;
 
 	/* Get the MCA error record and log it */
-	platform_err = ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA);
+	platform_err = ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA, 0);
 
 	/*
 	 *  Do Platform-specific mca error handling if required.
@@ -767,7 +784,7 @@
 		       cmc_irq, smp_processor_id());
 
 	/* Get the CMC error record and log it */
-	ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CMC);
+	ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CMC, 0);
 }
 
 /*
@@ -803,6 +820,62 @@
 #define IA64_LOG_CURR_BUFFER(it)   (void *)((ia64_state_log[it].isl_log[IA64_LOG_CURR_INDEX(it)]))
 
 /*
+ *  ia64_mca_cpe_poll
+ *
+ *	Poll for Corrected Platform Errors (CPEs), dynamically adjust
+ *	polling interval based on occurance of an event.
+ *
+ * Inputs   :   dummy(unused)
+ * Outputs  :   None
+ *
+ */
+static void
+ia64_mca_cpe_poll (unsigned long dummy)
+{
+	int start_index;
+	static int poll_time = MAX_CPE_POLL_INTERVAL;
+
+	start_index = IA64_LOG_CURR_INDEX(SAL_INFO_TYPE_CPE);
+
+	/* Call the interrupt handler */
+	ia64_mca_cpe_int_handler(0, NULL, NULL);
+
+	/*
+	 * If a log was recorded, increase our polling frequency,
+	 * otherwise, backoff.
+	 */
+	if (start_index != IA64_LOG_CURR_INDEX(SAL_INFO_TYPE_CPE)) {
+		poll_time = max(MIN_CPE_POLL_INTERVAL, poll_time/2);
+	} else {
+		poll_time = min(MAX_CPE_POLL_INTERVAL, poll_time * 2);
+	}
+	mod_timer(&cpe_poll_timer, jiffies + poll_time);
+}
+
+/*
+ * ia64_mca_late_init
+ *
+ *	Opportunity to setup things that require initialization later
+ *	than ia64_mca_init.  Setup a timer to poll for CPEs if the
+ *	platform doesn't support an interrupt driven mechanism.
+ *
+ *  Inputs  :   None
+ *  Outputs :   Status
+ */
+static int __init
+ia64_mca_late_init(void)
+{
+	if (acpi_request_vector(ACPI_INTERRUPT_CPEI) < 0) {
+		init_timer(&cpe_poll_timer);
+		cpe_poll_timer.function = ia64_mca_cpe_poll;
+		ia64_mca_cpe_poll(0);
+	}
+	return 0;
+}
+
+module_init(ia64_mca_late_init);
+
+/*
  * C portion of the OS INIT handler
  *
  * Called from ia64_monarch_init_handler
@@ -837,8 +910,7 @@
 	plog_ptr=(ia64_err_rec_t *)IA64_LOG_CURR_BUFFER(SAL_INFO_TYPE_INIT);
 	proc_ptr = &plog_ptr->proc_err;
 
-	ia64_process_min_state_save(&proc_ptr->processor_static_info.min_state_area,
-				    regs);
+	ia64_process_min_state_save(&proc_ptr->processor_static_info.min_state_area);
 
 	/* Clear the INIT SAL logs now that they have been saved in the OS buffer */
 	ia64_sal_clear_state_info(SAL_INFO_TYPE_INIT);
@@ -962,7 +1034,6 @@
 		return total_len;
 	} else {
 		IA64_LOG_UNLOCK(sal_info_type);
-		prfunc("ia64_log_get: No SAL error record available for type %d\n", sal_info_type);
 		return 0;
 	}
 }
@@ -1004,28 +1075,13 @@
 void
 ia64_log_rec_header_print (sal_log_record_header_t *lh, prfunc_t prfunc)
 {
-	char str_buf[32];
-
-	sprintf(str_buf, "%2d.%02d",
-		(lh->revision.major >> 4) * 10 + (lh->revision.major & 0xf),
-		(lh->revision.minor >> 4) * 10 + (lh->revision.minor & 0xf));
-	prfunc("+Err Record ID: %d    SAL Rev: %s\n", lh->id, str_buf);
-	sprintf(str_buf, "%02d/%02d/%04d/ %02d:%02d:%02d",
-		(lh->timestamp.slh_month >> 4) * 10 +
-		(lh->timestamp.slh_month & 0xf),
-		(lh->timestamp.slh_day >> 4) * 10 +
-		(lh->timestamp.slh_day & 0xf),
-		(lh->timestamp.slh_century >> 4) * 1000 +
-		(lh->timestamp.slh_century & 0xf) * 100 +
-		(lh->timestamp.slh_year >> 4) * 10 +
-		(lh->timestamp.slh_year & 0xf),
-		(lh->timestamp.slh_hour >> 4) * 10 +
-		(lh->timestamp.slh_hour & 0xf),
-		(lh->timestamp.slh_minute >> 4) * 10 +
-		(lh->timestamp.slh_minute & 0xf),
-		(lh->timestamp.slh_second >> 4) * 10 +
-		(lh->timestamp.slh_second & 0xf));
-	prfunc("+Time: %s    Severity %d\n", str_buf, lh->severity);
+	prfunc("+Err Record ID: %d    SAL Rev: %2x.%02x\n", lh->id,
+		lh->revision.major, lh->revision.minor);
+	prfunc("+Time: %02x/%02x/%02x%02x %02d:%02d:%02d    Severity %d\n",
+		lh->timestamp.slh_month, lh->timestamp.slh_day,
+		lh->timestamp.slh_century, lh->timestamp.slh_year,
+		lh->timestamp.slh_hour, lh->timestamp.slh_minute,
+		lh->timestamp.slh_second, lh->severity);
 }
 
 /*
@@ -1684,6 +1740,9 @@
 	if (slpi->valid.psi_static_struct) {
 		spsi = (sal_processor_static_info_t *)p_data;
 
+		/* copy interrupted context PAL min-state info */
+		ia64_process_min_state_save(&spsi->min_state_area);
+
 		/* Print branch register contents if valid */
 		if (spsi->valid.br)
 			ia64_log_processor_regs_print(spsi->br, 8, "Branch", "br",
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/pal.S linux-2.4.21-pre6/arch/ia64/kernel/pal.S
--- linux-2.4.20/arch/ia64/kernel/pal.S	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/kernel/pal.S	2003-03-26 23:49:55.000000000 +0000
@@ -245,3 +245,49 @@
 	br.ret.sptk.many b0
 END(ia64_pal_call_phys_stacked)
 
+/*
+ * Save scratch fp scratch regs (fp10-fp15)
+ *
+ * NOTE: We need to do this since firmware (SAL or PAL) uses more
+ * scratch fp regs than the Linux kernel does.
+ *
+ * Inputs:
+ *      in0         Address of stack storage for fp regs
+ */
+
+GLOBAL_ENTRY(ia64_save_scratch_fpregs)
+	alloc r3=ar.pfs,1,0,0,0
+	add r2=16,in0
+	;;
+	stf.spill [in0] = f10,32
+	stf.spill [r2]  = f11,32
+	;;
+	stf.spill [in0] = f12,32
+	stf.spill [r2]  = f13,32
+	;;
+	stf.spill [in0] = f14,32
+	stf.spill [r2]  = f15,32
+	br.ret.sptk.many rp
+END(ia64_save_scratch_fpregs)
+
+/*
+ * Load scratch fp scratch regs (fp10-fp15)
+ *
+ * Inputs:
+ *      in0         Address of stack storage for fp regs
+ */
+
+GLOBAL_ENTRY(ia64_load_scratch_fpregs)
+	alloc r3=ar.pfs,1,0,0,0
+	add r2=16,in0
+	;;
+	ldf.fill  f10 = [in0],32
+	ldf.fill  f11 = [r2],32
+	;;
+	ldf.fill  f12 = [in0],32
+	ldf.fill  f13 = [r2],32
+	;;
+	ldf.fill  f14 = [in0],32
+	ldf.fill  f15 = [r2],32
+	br.ret.sptk.many rp
+END(ia64_load_scratch_fpregs)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/pci.c linux-2.4.21-pre6/arch/ia64/kernel/pci.c
--- linux-2.4.20/arch/ia64/kernel/pci.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/kernel/pci.c	2003-03-26 23:49:35.000000000 +0000
@@ -43,6 +43,8 @@
 extern void ia64_mca_check_errors( void );
 #endif
 
+static unsigned int acpi_root_bridges;
+
 struct pci_fixup pcibios_fixups[1];
 
 struct pci_ops *pci_root_ops;
@@ -167,7 +169,7 @@
  */
 
 static struct pci_controller *
-alloc_pci_controller(int seg)
+alloc_pci_controller (int seg)
 {
 	struct pci_controller *controller;
 
@@ -181,7 +183,7 @@
 }
 
 static struct pci_bus *
-scan_root_bus(int bus, struct pci_ops *ops, void *sysdata)
+scan_root_bus (int bus, struct pci_ops *ops, void *sysdata)
 {
 	struct pci_bus *b;
 
@@ -211,24 +213,152 @@
 	return b;
 }
 
+static void
+alloc_resource (char *name, struct resource *root, unsigned long start, unsigned long end, unsigned long flags)
+{
+	struct resource *res;
+
+	res = kmalloc(sizeof(*res), GFP_KERNEL);
+	if (!res)
+		return;
+
+	memset(res, 0, sizeof(*res));
+	res->name = name;
+	res->start = start;
+	res->end = end;
+	res->flags = flags;
+
+	request_resource(root, res);
+}
+
+static u64
+add_io_space (acpi_resource_address64 *addr)
+{
+	u64 offset;
+	int sparse = 0;
+	int i;
+
+	if (addr->address_translation_offset == 0)
+		return IO_SPACE_BASE(0);	/* part of legacy IO space */
+
+	if (addr->attribute.io.translation_attribute == ACPI_SPARSE_TRANSLATION)
+		sparse = 1;
+
+	offset = (u64) ioremap(addr->address_translation_offset, 0);
+	for (i = 0; i < num_io_spaces; i++)
+		if (io_space[i].mmio_base == offset &&
+		    io_space[i].sparse == sparse)
+			return IO_SPACE_BASE(i);
+
+	if (num_io_spaces == MAX_IO_SPACES) {
+		printk("Too many IO port spaces\n");
+		return ~0;
+	}
+
+	i = num_io_spaces++;
+	io_space[i].mmio_base = offset;
+	io_space[i].sparse = sparse;
+
+	return IO_SPACE_BASE(i);
+}
+
+static acpi_status
+count_window (acpi_resource *resource, void *data)
+{
+	unsigned int *windows = (unsigned int *) data;
+	acpi_resource_address64 addr;
+	acpi_status status;
+
+	status = acpi_resource_to_address64(resource, &addr);
+	if (ACPI_SUCCESS(status))
+		if (addr.resource_type == ACPI_MEMORY_RANGE ||
+		    addr.resource_type == ACPI_IO_RANGE)
+			(*windows)++;
+
+	return AE_OK;
+}
+
+struct pci_root_info {
+	struct pci_controller *controller;
+	char *name;
+};
+
+static acpi_status
+add_window (acpi_resource *res, void *data)
+{
+	struct pci_root_info *info = (struct pci_root_info *) data;
+	struct pci_window *window;
+	acpi_resource_address64 addr;
+	acpi_status status;
+	unsigned long flags, offset = 0;
+	struct resource *root;
+
+	status = acpi_resource_to_address64(res, &addr);
+	if (ACPI_SUCCESS(status)) {
+		if (addr.resource_type == ACPI_MEMORY_RANGE) {
+			flags = IORESOURCE_MEM;
+			root = &iomem_resource;
+			offset = addr.address_translation_offset;
+		} else if (addr.resource_type == ACPI_IO_RANGE) {
+			flags = IORESOURCE_IO;
+			root = &ioport_resource;
+			offset = add_io_space(&addr);
+			if (offset == ~0)
+				return AE_OK;
+		} else
+			return AE_OK;
+
+		window = &info->controller->window[info->controller->windows++];
+		window->resource.flags |= flags;
+		window->resource.start  = addr.min_address_range;
+		window->resource.end    = addr.max_address_range;
+		window->offset		= offset;
+
+		alloc_resource(info->name, root, addr.min_address_range + offset,
+			addr.max_address_range + offset, flags);
+	}
+
+	return AE_OK;
+}
+
 struct pci_bus *
-pcibios_scan_root(void *handle, int seg, int bus)
+pcibios_scan_root (void *handle, int seg, int bus)
 {
+	struct pci_root_info info;
 	struct pci_controller *controller;
-	u64 base, size, offset;
+	unsigned int windows = 0;
+	char *name;
 
-	printk("PCI: Probing PCI hardware on bus (%02x:%02x)\n", seg, bus);
+	acpi_root_bridges++;
 
 	controller = alloc_pci_controller(seg);
 	if (!controller)
-		return NULL;
+		goto out1;
 
 	controller->acpi_handle = handle;
 
-	acpi_get_addr_space(handle, ACPI_MEMORY_RANGE, &base, &size, &offset);
-	controller->mem_offset = offset;
+	acpi_walk_resources(handle, METHOD_NAME__CRS, count_window, &windows);
+	controller->window = kmalloc(sizeof(*controller->window) * windows, GFP_KERNEL);
+	if (!controller->window)
+		goto out2;
+
+	name = kmalloc(16, GFP_KERNEL);
+	if (!name)
+		goto out3;
+
+	sprintf(name, "PCI Bus %02x:%02x", seg, bus);
+	info.controller = controller;
+	info.name = name;
+	acpi_walk_resources(handle, METHOD_NAME__CRS, add_window, &info);
 
 	return scan_root_bus(bus, pci_root_ops, controller);
+
+out3:
+	kfree(controller->window);
+out2:
+	kfree(controller);
+out1:
+	return NULL;
 }
 
 void __init
@@ -249,7 +379,7 @@
 void __init
 pcibios_init (void)
 {
-#	define PCI_BUSES_TO_SCAN 255
+#	define PCI_BUSES_TO_SCAN 256
 	int i = 0;
 	struct pci_controller *controller;
 
@@ -261,43 +391,52 @@
 
 	platform_pci_fixup(0);	/* phase 0 fixups (before buses scanned) */
 
-	printk("PCI: Probing PCI hardware\n");
-	controller = alloc_pci_controller(0);
-	if (controller)
-		for (i = 0; i < PCI_BUSES_TO_SCAN; i++)
-			pci_scan_bus(i, pci_root_ops, controller);
+	/* Only probe blindly if ACPI didn't tell us about root bridges */
+	if (!acpi_root_bridges) {
+		printk("PCI: Probing PCI hardware\n");
+		controller = alloc_pci_controller(0);
+		if (controller)
+			for (i = 0; i < PCI_BUSES_TO_SCAN; i++)
+				pci_scan_bus(i, pci_root_ops, controller);
+	}
 
 	platform_pci_fixup(1);	/* phase 1 fixups (after buses scanned) */
 
 	return;
 }
 
-static void __init
-pcibios_fixup_resource(struct resource *res, u64 offset)
-{
-	res->start += offset;
-	res->end += offset;
-}
-
 void __init
-pcibios_fixup_device_resources(struct pci_dev *dev, struct pci_bus *bus)
+pcibios_fixup_device_resources (struct pci_dev *dev, struct pci_bus *bus)
 {
-	int i;
+	struct pci_controller *controller = PCI_CONTROLLER(dev);
+	struct pci_window *window;
+	int i, j;
 
 	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
 		if (!dev->resource[i].start)
 			continue;
-		if (dev->resource[i].flags & IORESOURCE_MEM)
-			pcibios_fixup_resource(&dev->resource[i],
-				PCI_CONTROLLER(dev)->mem_offset);
+
+#define contains(win, res)	((res)->start >= (win)->start && \
+				 (res)->end   <= (win)->end)
+
+		for (j = 0; j < controller->windows; j++) {
+			window = &controller->window[j];
+			if (((dev->resource[i].flags & IORESOURCE_MEM &&
+			      window->resource.flags & IORESOURCE_MEM) ||
+			     (dev->resource[i].flags & IORESOURCE_IO &&
+			      window->resource.flags & IORESOURCE_IO)) &&
+			    contains(&window->resource, &dev->resource[i])) {
+				dev->resource[i].start += window->offset;
+				dev->resource[i].end   += window->offset;
+			}
+		}
 	}
 }
 
 /*
- *  Called after each bus is probed, but before its children
- *  are examined.
+ *  Called after each bus is probed, but before its children are examined.
  */
-void __init
+void __devinit
 pcibios_fixup_bus (struct pci_bus *b)
 {
 	struct list_head *ln;
@@ -306,7 +445,7 @@
 		pcibios_fixup_device_resources(pci_dev_b(ln), b);
 }
 
-void __init
+void __devinit
 pcibios_update_resource (struct pci_dev *dev, struct resource *root,
 			 struct resource *res, int resource)
 {
@@ -322,7 +461,7 @@
 	/* ??? FIXME -- record old value for shutdown.  */
 }
 
-void __init
+void __devinit
 pcibios_update_irq (struct pci_dev *dev, int irq)
 {
 	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
@@ -330,7 +469,7 @@
 	/* ??? FIXME -- record old value for shutdown.  */
 }
 
-void __init
+void __devinit
 pcibios_fixup_pbus_ranges (struct pci_bus * bus, struct pbus_set_ranges_data * ranges)
 {
 	ranges->io_start -= bus->resource[0]->start;
@@ -339,8 +478,8 @@
 	ranges->mem_end -= bus->resource[1]->start;
 }
 
-int
-pcibios_enable_device (struct pci_dev *dev)
+static inline int
+pcibios_enable_resources (struct pci_dev *dev, int mask)
 {
 	u16 cmd, old_cmd;
 	int idx;
@@ -349,11 +488,13 @@
 	if (!dev)
 		return -EINVAL;
 
- 	platform_pci_enable_device(dev);
-
 	pci_read_config_word(dev, PCI_COMMAND, &cmd);
 	old_cmd = cmd;
 	for (idx=0; idx<6; idx++) {
+		/* Only set up the desired resources.  */
+		if (!(mask & (1 << idx)))
+			continue;
+
 		r = &dev->resource[idx];
 		if (!r->start && r->end) {
 			printk(KERN_ERR
@@ -372,6 +513,19 @@
 		printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd);
 		pci_write_config_word(dev, PCI_COMMAND, cmd);
 	}
+	return 0;
+}
+
+int
+pcibios_enable_device (struct pci_dev *dev, int mask)
+{
+	int ret;
+
+	ret = pcibios_enable_resources(dev, mask);
+	if (ret < 0)
+		return ret;
+
+ 	platform_pci_enable_device(dev);
 
 	printk(KERN_INFO "PCI: Found IRQ %d for device %s\n", dev->irq, dev->slot_name);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/perfmon.c linux-2.4.21-pre6/arch/ia64/kernel/perfmon.c
--- linux-2.4.20/arch/ia64/kernel/perfmon.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/kernel/perfmon.c	2003-03-26 23:49:30.000000000 +0000
@@ -8,7 +8,7 @@
  * Modifications by Stephane Eranian, Hewlett-Packard Co.
  * Modifications by David Mosberger-Tang, Hewlett-Packard Co.
  *
- * Copyright (C) 1999-2002  Hewlett Packard Co
+ * Copyright (C) 1999-2003  Hewlett Packard Co
  *               Stephane Eranian <eranian@hpl.hp.com>
  *               David Mosberger-Tang <davidm@hpl.hp.com>
  */
@@ -28,7 +28,6 @@
 #include <asm/bitops.h>
 #include <asm/errno.h>
 #include <asm/page.h>
-#include <asm/pal.h>
 #include <asm/perfmon.h>
 #include <asm/processor.h>
 #include <asm/signal.h>
@@ -56,27 +55,53 @@
 /*
  * Reset register flags
  */
-#define PFM_RELOAD_LONG_RESET	1
-#define PFM_RELOAD_SHORT_RESET	2
+#define PFM_PMD_LONG_RESET	1
+#define PFM_PMD_SHORT_RESET	2
 
 /*
  * Misc macros and definitions
  */
 #define PMU_FIRST_COUNTER	4
+#define PMU_MAX_PMCS		256
+#define PMU_MAX_PMDS		256
 
-#define PFM_IS_DISABLED() pmu_conf.pfm_is_disabled
+/*
+ * type of a PMU register (bitmask).
+ * bitmask structure:
+ * 	bit0   : register implemented
+ * 	bit1   : end marker 
+ * 	bit2-3 : reserved
+ * 	bit4-7 : register type
+ * 	bit8-31: reserved
+ */
+#define PFM_REG_IMPL		0x1 /* register implemented */
+#define PFM_REG_END		0x2 /* end marker */
+#define PFM_REG_MONITOR		(0x1<<4|PFM_REG_IMPL) /* a PMC with a pmc.pm field only */
+#define PFM_REG_COUNTING	(0x2<<4|PFM_REG_IMPL) /* a PMC with a pmc.pm AND pmc.oi, a PMD used as a counter */
+#define PFM_REG_CONTROL		(0x3<<4|PFM_REG_IMPL) /* PMU control register */
+#define	PFM_REG_CONFIG		(0x4<<4|PFM_REG_IMPL) /* refine configuration */
+#define PFM_REG_BUFFER	 	(0x5<<4|PFM_REG_IMPL) /* PMD used as buffer */
+
+#define PMC_IS_LAST(i)	(pmu_conf.pmc_desc[i].type & PFM_REG_END)
+#define PMD_IS_LAST(i)	(pmu_conf.pmd_desc[i].type & PFM_REG_END)
+
+#define PFM_IS_DISABLED() pmu_conf.disabled
 
 #define PMC_OVFL_NOTIFY(ctx, i)	((ctx)->ctx_soft_pmds[i].flags &  PFM_REGFL_OVFL_NOTIFY)
 #define PFM_FL_INHERIT_MASK	(PFM_FL_INHERIT_NONE|PFM_FL_INHERIT_ONCE|PFM_FL_INHERIT_ALL)
 
 /* i assume unsigned */
-#define PMC_IS_IMPL(i)	  (i<pmu_conf.num_pmcs && pmu_conf.impl_regs[i>>6] & (1UL<< (i) %64))
-#define PMD_IS_IMPL(i)	  (i<pmu_conf.num_pmds &&  pmu_conf.impl_regs[4+(i>>6)] & (1UL<<(i) % 64))
+#define PMC_IS_IMPL(i)	  (i< PMU_MAX_PMCS && (pmu_conf.pmc_desc[i].type & PFM_REG_IMPL))
+#define PMD_IS_IMPL(i)	  (i< PMU_MAX_PMDS && (pmu_conf.pmd_desc[i].type & PFM_REG_IMPL))
 
 /* XXX: these three assume that register i is implemented */
 #define PMD_IS_COUNTING(i) (pmu_conf.pmd_desc[i].type == PFM_REG_COUNTING)
 #define PMC_IS_COUNTING(i) (pmu_conf.pmc_desc[i].type == PFM_REG_COUNTING)
-#define PMC_IS_MONITOR(c)  (pmu_conf.pmc_desc[i].type == PFM_REG_MONITOR)
+#define PMC_IS_MONITOR(i)  (pmu_conf.pmc_desc[i].type == PFM_REG_MONITOR)
+#define PMC_DFL_VAL(i)     pmu_conf.pmc_desc[i].default_value
+#define PMC_RSVD_MASK(i)   pmu_conf.pmc_desc[i].reserved_mask
+#define PMD_PMD_DEP(i)	   pmu_conf.pmd_desc[i].dep_pmd[0]
+#define PMC_PMD_DEP(i)	   pmu_conf.pmc_desc[i].dep_pmd[0]
 
 /* k assume unsigned */
 #define IBR_IS_IMPL(k)	  (k<pmu_conf.num_ibrs)
@@ -106,6 +131,9 @@
 
 #define PFM_REG_RETFLAG_SET(flags, val)	do { flags &= ~PFM_REG_RETFL_MASK; flags |= (val); } while(0)
 
+#define PFM_CPUINFO_CLEAR(v)	local_cpu_data->pfm_syst_info &= ~(v)
+#define PFM_CPUINFO_SET(v)	local_cpu_data->pfm_syst_info |= (v)
+
 #ifdef CONFIG_SMP
 #define cpu_is_online(i) (cpu_online_map & (1UL << i))
 #else
@@ -176,28 +204,17 @@
 #define UNLOCK_PSB(p)	spin_unlock(&(p)->psb_lock)
 
 /*
- * The possible type of a PMU register
- */
-typedef enum { 
-	PFM_REG_NOTIMPL, /* not implemented */
-	PFM_REG_NONE, 	 /* end marker */
-	PFM_REG_MONITOR, /* a PMC with a pmc.pm field only */
-	PFM_REG_COUNTING,/* a PMC with a pmc.pm AND pmc.oi, a PMD used as a counter */
-	PFM_REG_CONTROL, /* PMU control register */
-	PFM_REG_CONFIG,  /* refine configuration */
-	PFM_REG_BUFFER	 /* PMD used as buffer */
-} pfm_pmu_reg_type_t;
-
-/*
  * 64-bit software counter structure
  */
 typedef struct {
 	u64 val;	/* virtual 64bit counter value */
-	u64 ival;	/* initial value from user */
+	u64 lval;	/* last value */
 	u64 long_reset;	/* reset value on sampling overflow */
 	u64 short_reset;/* reset value on overflow */
 	u64 reset_pmds[4]; /* which other pmds to reset when this counter overflows */
-	int flags;	/* notify/do not notify */
+	u64 seed;	/* seed for random-number generator */
+	u64 mask;	/* mask for random-number generator */
+	unsigned int flags; /* notify/do not notify */
 } pfm_counter_t;
 
 /*
@@ -212,7 +229,8 @@
 	unsigned int frozen:1;		/* pmu must be kept frozen on ctxsw in */
 	unsigned int protected:1;	/* allow access to creator of context only */
 	unsigned int using_dbreg:1;	/* using range restrictions (debug registers) */
-	unsigned int reserved:24;
+	unsigned int excl_idle:1;	/* exclude idle task in system wide session */
+	unsigned int reserved:23;
 } pfm_context_flags_t;
 
 /*
@@ -247,7 +265,7 @@
 
 	u64			ctx_saved_psr;		/* copy of psr used for lazy ctxsw */
 	unsigned long		ctx_saved_cpus_allowed;	/* copy of the task cpus_allowed (system wide) */
-	unsigned long		ctx_cpu;		/* cpu to which perfmon is applied (system wide) */
+	unsigned int		ctx_cpu;		/* cpu to which perfmon is applied (system wide) */
 
 	atomic_t		ctx_saving_in_progress;	/* flag indicating actual save in progress */
 	atomic_t		ctx_is_busy;		/* context accessed by overflow handler */
@@ -260,6 +278,7 @@
 #define ctx_fl_frozen		ctx_flags.frozen
 #define ctx_fl_protected	ctx_flags.protected
 #define ctx_fl_using_dbreg	ctx_flags.using_dbreg
+#define ctx_fl_excl_idle	ctx_flags.excl_idle
 
 /*
  * global information about all sessions
@@ -268,10 +287,10 @@
 typedef struct {
 	spinlock_t		pfs_lock;		   /* lock the structure */
 
-	unsigned long		pfs_task_sessions;	   /* number of per task sessions */
-	unsigned long		pfs_sys_sessions;	   /* number of per system wide sessions */
-	unsigned long   	pfs_sys_use_dbregs;	   /* incremented when a system wide session uses debug regs */
-	unsigned long   	pfs_ptrace_use_dbregs;	   /* incremented when a process uses debug regs */
+	unsigned int 		pfs_task_sessions;	   /* number of per task sessions */
+	unsigned int		pfs_sys_sessions;	   /* number of per system wide sessions */
+	unsigned int		pfs_sys_use_dbregs;	   /* incremented when a system wide session uses debug regs */
+	unsigned int		pfs_ptrace_use_dbregs;	   /* incremented when a process uses debug regs */
 	struct task_struct	*pfs_sys_session[NR_CPUS]; /* point to task owning a system-wide session */
 } pfm_session_t;
 
@@ -281,13 +300,16 @@
  * dep_pmc[]: a bitmask of dependent PMC registers
  */
 typedef struct {
-	pfm_pmu_reg_type_t	type;
+	unsigned int		type;
 	int			pm_pos;
+	unsigned long		default_value;	/* power-on default value */
+	unsigned long		reserved_mask;	/* bitmask of reserved bits */
 	int			(*read_check)(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs);
 	int			(*write_check)(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs);
 	unsigned long		dep_pmd[4];
 	unsigned long		dep_pmc[4];
 } pfm_reg_desc_t;
+
 /* assume cnum is a valid monitor */
 #define PMC_PM(cnum, val)	(((val) >> (pmu_conf.pmc_desc[cnum].pm_pos)) & 0x1)
 #define PMC_WR_FUNC(cnum)	(pmu_conf.pmc_desc[cnum].write_check)
@@ -296,23 +318,22 @@
 
 /*
  * This structure is initialized at boot time and contains
- * a description of the PMU main characteristic as indicated
- * by PAL along with a list of inter-registers dependencies and configurations.
+ * a description of the PMU main characteristics.
  */
 typedef struct {
-	unsigned long pfm_is_disabled;	/* indicates if perfmon is working properly */
-	unsigned long perf_ovfl_val;	/* overflow value for generic counters   */
-	unsigned long max_counters;	/* upper limit on counter pair (PMC/PMD) */
-	unsigned long num_pmcs ;	/* highest PMC implemented (may have holes) */
-	unsigned long num_pmds;		/* highest PMD implemented (may have holes) */
-	unsigned long impl_regs[16];	/* buffer used to hold implememted PMC/PMD mask */
-	unsigned long num_ibrs;		/* number of instruction debug registers */
-	unsigned long num_dbrs;		/* number of data debug registers */
-	pfm_reg_desc_t *pmc_desc;	/* detailed PMC register descriptions */
-	pfm_reg_desc_t *pmd_desc;	/* detailed PMD register descriptions */
+	unsigned int  disabled;		/* indicates if perfmon is working properly */
+	unsigned long ovfl_val;		/* overflow value for generic counters   */
+	unsigned long impl_pmcs[4];	/* bitmask of implemented PMCS */
+	unsigned long impl_pmds[4];	/* bitmask of implemented PMDS */
+	unsigned int  num_pmcs;		/* number of implemented PMCS */
+	unsigned int  num_pmds;		/* number of implemented PMDS */
+	unsigned int  num_ibrs;		/* number of implemented IBRS */
+	unsigned int  num_dbrs;		/* number of implemented DBRS */
+	unsigned int  num_counters;	/* number of PMD/PMC counters */
+	pfm_reg_desc_t *pmc_desc;	/* detailed PMC register dependencies descriptions */
+	pfm_reg_desc_t *pmd_desc;	/* detailed PMD register dependencies descriptions */
 } pmu_config_t;
 
-
 /*
  * structure used to pass argument to/from remote CPU 
  * using IPI to check and possibly save the PMU context on SMP systems.
@@ -336,7 +357,7 @@
 
 #define PFM_CMD_PID		0x1	/* command requires pid argument */
 #define PFM_CMD_ARG_READ	0x2	/* command must read argument(s) */
-#define PFM_CMD_ARG_WRITE	0x4	/* command must write argument(s) */
+#define PFM_CMD_ARG_RW		0x4	/* command must read/write argument(s) */
 #define PFM_CMD_CTX		0x8	/* command needs a perfmon context */
 #define PFM_CMD_NOCHK		0x10	/* command does not need to check task's state */
 
@@ -347,7 +368,7 @@
 
 #define PFM_CMD_USE_PID(cmd)	((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_PID) != 0)
 #define PFM_CMD_READ_ARG(cmd)	((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_ARG_READ) != 0)
-#define PFM_CMD_WRITE_ARG(cmd)	((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_ARG_WRITE) != 0)
+#define PFM_CMD_RW_ARG(cmd)	((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_ARG_RW) != 0)
 #define PFM_CMD_USE_CTX(cmd)	((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_CTX) != 0)
 #define PFM_CMD_CHK(cmd)	((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_NOCHK) == 0)
 
@@ -366,15 +387,16 @@
 	unsigned long pfm_ovfl_intr_count; /* keep track of ovfl interrupts */
 	unsigned long pfm_recorded_samples_count;
 	unsigned long pfm_full_smpl_buffer_count; /* how many times the sampling buffer was full */
+	char pad[SMP_CACHE_BYTES] ____cacheline_aligned;
 } pfm_stats_t;
 
 /*
  * perfmon internal variables
  */
-static pmu_config_t	pmu_conf; 	/* PMU configuration */
 static pfm_session_t	pfm_sessions;	/* global sessions information */
 static struct proc_dir_entry *perfmon_dir; /* for debug only */
-static pfm_stats_t	pfm_stats;
+static pfm_stats_t	pfm_stats[NR_CPUS];
+static pfm_intr_handler_desc_t	*pfm_alternate_intr_handler;
 
 /* sysctl() controls */
 static pfm_sysctl_t pfm_sysctl;
@@ -395,12 +417,10 @@
 };
 static struct ctl_table_header *pfm_sysctl_header;
 
-static unsigned long reset_pmcs[IA64_NUM_PMC_REGS];	/* contains PAL reset values for PMCS */
-
 static void pfm_vm_close(struct vm_area_struct * area);
 
 static struct vm_operations_struct pfm_vm_ops={
-	close: pfm_vm_close
+	.close =  pfm_vm_close
 };
 
 /*
@@ -408,14 +428,15 @@
  */
 static struct {
 	struct task_struct *owner;
-} ____cacheline_aligned pmu_owners[NR_CPUS];
+	char pad[SMP_CACHE_BYTES] ____cacheline_aligned;
+} pmu_owners[NR_CPUS];
 
 
 
 /*
  * forward declarations
  */
-static void ia64_reset_pmu(struct task_struct *);
+static void pfm_reset_pmu(struct task_struct *);
 #ifdef CONFIG_SMP
 static void pfm_fetch_regs(int cpu, struct task_struct *task, pfm_context_t *ctx);
 #endif
@@ -429,43 +450,79 @@
 #include "perfmon_generic.h"
 #endif
 
+static inline void
+pfm_clear_psr_pp(void)
+{
+	__asm__ __volatile__ ("rsm psr.pp;; srlz.i;;"::: "memory");
+}
+
+static inline void
+pfm_set_psr_pp(void)
+{
+	__asm__ __volatile__ ("ssm psr.pp;; srlz.i;;"::: "memory");
+}
+
+static inline void
+pfm_clear_psr_up(void)
+{
+	__asm__ __volatile__ ("rum psr.up;; srlz.i;;"::: "memory");
+}
+
+static inline void
+pfm_set_psr_up(void)
+{
+	__asm__ __volatile__ ("sum psr.up;; srlz.i;;"::: "memory");
+}
+
+static inline unsigned long
+pfm_get_psr(void)
+{
+	unsigned long tmp;
+	__asm__ __volatile__ ("mov %0=psr;;": "=r"(tmp) :: "memory");
+	return tmp;
+}
+
+static inline void
+pfm_set_psr_l(unsigned long val)
+{
+	__asm__ __volatile__ ("mov psr.l=%0;; srlz.i;;"::"r"(val): "memory");
+}
+
+
+
+static inline void
+pfm_freeze_pmu(void)
+{
+	ia64_set_pmc(0,1UL);
+	ia64_srlz_d();
+}
+
+static inline void
+pfm_unfreeze_pmu(void)
+{
+	ia64_set_pmc(0,0UL);
+	ia64_srlz_d();
+}
+
+
 static inline unsigned long
 pfm_read_soft_counter(pfm_context_t *ctx, int i)
 {
-	return ctx->ctx_soft_pmds[i].val + (ia64_get_pmd(i) & pmu_conf.perf_ovfl_val);
+	return ctx->ctx_soft_pmds[i].val + (ia64_get_pmd(i) & pmu_conf.ovfl_val);
 }
 
 static inline void
 pfm_write_soft_counter(pfm_context_t *ctx, int i, unsigned long val)
 {
-	ctx->ctx_soft_pmds[i].val = val  & ~pmu_conf.perf_ovfl_val;
+	ctx->ctx_soft_pmds[i].val = val  & ~pmu_conf.ovfl_val;
 	/*
 	 * writing to unimplemented part is ignore, so we do not need to
 	 * mask off top part
 	 */
-	ia64_set_pmd(i, val & pmu_conf.perf_ovfl_val);
+	ia64_set_pmd(i, val & pmu_conf.ovfl_val);
 }
 
 /*
- * finds the number of PM(C|D) registers given
- * the bitvector returned by PAL
- */
-static unsigned long __init
-find_num_pm_regs(long *buffer)
-{
-	int i=3; /* 4 words/per bitvector */
-
-	/* start from the most significant word */
-	while (i>=0 && buffer[i] == 0 ) i--;
-	if (i< 0) {
-		printk(KERN_ERR "perfmon: No bit set in pm_buffer\n");
-		return 0;
-	}
-	return 1+ ia64_fls(buffer[i]) + 64 * i;
-}
-
-
-/*
  * Generates a unique (per CPU) timestamp
  */
 static inline unsigned long
@@ -477,31 +534,6 @@
 	return ia64_get_itc();
 }
 
-/* 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));
-			}
-		}
-	}
-	DBprintk(("[%d] uv2kva(%lx-->%lx)\n", current->pid, 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.
@@ -767,15 +799,14 @@
 	psb = kmalloc(sizeof(*psb), GFP_KERNEL);
 	if (psb == NULL) {
 		DBprintk(("Can't allocate sampling buffer descriptor\n"));
-		pfm_rvfree(smpl_buf, size);
-		return -ENOMEM;
+		goto error_kmalloc;
 	}
 
 	/* allocate vma */
 	vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
 	if (!vma) {
 		DBprintk(("Cannot allocate vma\n"));
-		goto error;
+		goto error_kmem;
 	}
 	/*
 	 * partially initialize the vma for the sampling buffer
@@ -875,11 +906,127 @@
 	return 0;
 
 error:
-	pfm_rvfree(smpl_buf, size);
+	kmem_cache_free(vm_area_cachep, vma);
+error_kmem:
 	kfree(psb);
+error_kmalloc:
+	pfm_rvfree(smpl_buf, size);
 	return -ENOMEM;
 }
 
+static int
+pfm_reserve_session(struct task_struct *task, int is_syswide, unsigned long cpu_mask)
+{
+	unsigned long m, undo_mask;
+	unsigned int n, i;
+
+	/*
+	 * validy checks on cpu_mask have been done upstream
+	 */
+	LOCK_PFS();
+
+	if (is_syswide) {
+		/* 
+		 * cannot mix system wide and per-task sessions
+		 */
+		if (pfm_sessions.pfs_task_sessions > 0UL) {
+			DBprintk(("system wide not possible, %u conflicting task_sessions\n", 
+			  	pfm_sessions.pfs_task_sessions));
+			goto abort;
+		}
+
+		m = cpu_mask; undo_mask = 0UL; n = 0;
+		DBprintk(("cpu_mask=0x%lx\n", cpu_mask));
+		for(i=0; m; i++, m>>=1) {
+
+			if ((m & 0x1) == 0UL) continue;
+
+			if (pfm_sessions.pfs_sys_session[i]) goto undo;
+
+			DBprintk(("reserving CPU%d currently on CPU%d\n", i, smp_processor_id()));
+
+			pfm_sessions.pfs_sys_session[i] = task;
+			undo_mask |= 1UL << i;
+			n++;
+		}
+		pfm_sessions.pfs_sys_sessions += n;
+	} else {
+		if (pfm_sessions.pfs_sys_sessions) goto abort;
+		pfm_sessions.pfs_task_sessions++;
+	}
+	UNLOCK_PFS();
+	return 0;
+undo:
+	DBprintk(("system wide not possible, conflicting session [%d] on CPU%d\n",
+  		pfm_sessions.pfs_sys_session[i]->pid, i));
+
+	for(i=0; undo_mask; i++, undo_mask >>=1) {
+		pfm_sessions.pfs_sys_session[i] = NULL;
+	}
+abort:
+	UNLOCK_PFS();
+
+	return -EBUSY;
+
+}
+
+static int
+pfm_unreserve_session(struct task_struct *task, int is_syswide, unsigned long cpu_mask)
+{
+	pfm_context_t *ctx;
+	unsigned long m;
+	unsigned int n, i;
+
+	ctx = task ? task->thread.pfm_context : NULL;
+
+	/*
+	 * validy checks on cpu_mask have been done upstream
+	 */
+	LOCK_PFS();
+
+	DBprintk(("[%d] sys_sessions=%u task_sessions=%u dbregs=%u syswide=%d cpu_mask=0x%lx\n",
+		task->pid,
+		pfm_sessions.pfs_sys_sessions,
+		pfm_sessions.pfs_task_sessions,
+		pfm_sessions.pfs_sys_use_dbregs,
+		is_syswide,
+		cpu_mask));
+		
+
+	if (is_syswide) {
+		m = cpu_mask; n = 0;
+		for(i=0; m; i++, m>>=1) {
+			if ((m & 0x1) == 0UL) continue;
+			pfm_sessions.pfs_sys_session[i] = NULL;
+			n++;
+		}
+		/* 
+		 * would not work with perfmon+more than one bit in cpu_mask
+		 */
+		if (ctx && ctx->ctx_fl_using_dbreg) {
+			if (pfm_sessions.pfs_sys_use_dbregs == 0) {
+				printk("perfmon: invalid release for [%d] sys_use_dbregs=0\n", task->pid);
+			} else {
+				pfm_sessions.pfs_sys_use_dbregs--;
+			}
+		}
+		pfm_sessions.pfs_sys_sessions -= n;
+
+		DBprintk(("CPU%d sys_sessions=%u\n", 
+			smp_processor_id(), pfm_sessions.pfs_sys_sessions));
+	} else {
+		pfm_sessions.pfs_task_sessions--;
+		DBprintk(("[%d] task_sessions=%u\n", 
+			task->pid, pfm_sessions.pfs_task_sessions));
+	}
+
+	UNLOCK_PFS();
+
+	return 0;
+}
+
+
+
 /*
  * XXX: do something better here
  */
@@ -895,6 +1042,7 @@
 static int
 pfx_is_sane(struct task_struct *task, pfarg_context_t *pfx)
 {
+	unsigned long smpl_pmds = pfx->ctx_smpl_regs[0];
 	int ctx_flags;
 	int cpu;
 
@@ -961,6 +1109,11 @@
 		}
 #endif
 	}
+	/* verify validity of smpl_regs */
+	if ((smpl_pmds & pmu_conf.impl_pmds[0]) != smpl_pmds) {
+		DBprintk(("invalid smpl_regs 0x%lx\n", smpl_pmds));
+		return -EINVAL;
+	}
 	/* probably more to add here */
 
 	return 0;
@@ -972,7 +1125,7 @@
 {
 	pfarg_context_t tmp;
 	void *uaddr = NULL;
-	int ret, cpu = 0;
+	int ret;
 	int ctx_flags;
 	pid_t notify_pid;
 
@@ -984,47 +1137,15 @@
 	 */
 	if (task != current) return -EINVAL;
 
-	if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
+	if (__copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
 
 	ret = pfx_is_sane(task, &tmp);
 	if (ret < 0) return ret;
 
 	ctx_flags = tmp.ctx_flags;
 
-	ret =  -EBUSY;
-
-	LOCK_PFS();
-
-	if (ctx_flags & PFM_FL_SYSTEM_WIDE) {
-
-		/* at this point, we know there is at least one bit set */
-		cpu = ffz(~tmp.ctx_cpu_mask);
-
-		DBprintk(("requesting CPU%d currently on CPU%d\n",cpu, smp_processor_id()));
-
-		if (pfm_sessions.pfs_task_sessions > 0) {
-			DBprintk(("system wide not possible, task_sessions=%ld\n", pfm_sessions.pfs_task_sessions));
-			goto abort;
-		}
-
-		if (pfm_sessions.pfs_sys_session[cpu]) {
-			DBprintk(("system wide not possible, conflicting session [%d] on CPU%d\n",pfm_sessions.pfs_sys_session[cpu]->pid, cpu));
-			goto abort;
-		}
-		pfm_sessions.pfs_sys_session[cpu] = task;
-		/*
-		 * count the number of system wide sessions
-		 */
-		pfm_sessions.pfs_sys_sessions++;
-
-	} else if (pfm_sessions.pfs_sys_sessions == 0) {
-		pfm_sessions.pfs_task_sessions++;
-	} else {
-		/* no per-process monitoring while there is a system wide session */
-		goto abort;
-	}
-
-	UNLOCK_PFS();
+	ret = pfm_reserve_session(task, ctx_flags & PFM_FL_SYSTEM_WIDE, tmp.ctx_cpu_mask);
+	if (ret) goto abort;
 
 	ret = -ENOMEM;
 
@@ -1040,8 +1161,8 @@
 
 	if (notify_pid == current->pid) {
 
-		ctx->ctx_notify_task = task = current;
-		current->thread.pfm_context = ctx;
+		ctx->ctx_notify_task = current;
+		task->thread.pfm_context = ctx;
 
 	} else if (notify_pid!=0) {
 		struct task_struct *notify_task;
@@ -1057,7 +1178,10 @@
 			/*
 			 * check if we can send this task a signal
 			 */
-			if (pfm_bad_permissions(notify_task)) goto buffer_error;
+			if (pfm_bad_permissions(notify_task)) {
+				read_unlock(&tasklist_lock);
+				goto buffer_error;
+			}
 
 			/* 
 		 	 * make visible
@@ -1067,7 +1191,7 @@
 		 	 * okay because child will do the scan for nothing which
 		 	 * won't hurt.
 		 	 */
-			current->thread.pfm_context = ctx;
+			task->thread.pfm_context = ctx;
 
 			/*
 			 * will cause task to check on exit for monitored
@@ -1104,6 +1228,7 @@
 	ctx->ctx_fl_inherit   = ctx_flags & PFM_FL_INHERIT_MASK;
 	ctx->ctx_fl_block     = (ctx_flags & PFM_FL_NOTIFY_BLOCK) ? 1 : 0;
 	ctx->ctx_fl_system    = (ctx_flags & PFM_FL_SYSTEM_WIDE) ? 1: 0;
+	ctx->ctx_fl_excl_idle = (ctx_flags & PFM_FL_EXCL_IDLE) ? 1: 0;
 	ctx->ctx_fl_frozen    = 0;
 	/*
 	 * setting this flag to 0 here means, that the creator or the task that the
@@ -1114,9 +1239,10 @@
 	ctx->ctx_fl_protected = 0;
 
 	/* for system wide mode only (only 1 bit set) */
-	ctx->ctx_cpu         = cpu;
+	ctx->ctx_cpu = ffz(~tmp.ctx_cpu_mask);
 
-	atomic_set(&ctx->ctx_last_cpu,-1); /* SMP only, means no CPU */
+	/* SMP only, means no CPU */
+	atomic_set(&ctx->ctx_last_cpu,-1); 
 
 	/* may be redudant with memset() but at least it's easier to remember */
 	atomic_set(&ctx->ctx_saving_in_progress, 0); 
@@ -1124,7 +1250,7 @@
 
 	sema_init(&ctx->ctx_restart_sem, 0); /* init this semaphore to locked */
 
-	if (copy_to_user(req, &tmp, sizeof(tmp))) {
+	if (__copy_to_user(req, &tmp, sizeof(tmp))) {
 		ret = -EFAULT;
 		goto buffer_error;
 	}
@@ -1132,9 +1258,9 @@
 	DBprintk(("context=%p, pid=%d notify_task=%p\n",
 			(void *)ctx, task->pid, ctx->ctx_notify_task));
 
-	DBprintk(("context=%p, pid=%d flags=0x%x inherit=%d block=%d system=%d\n", 
+	DBprintk(("context=%p, pid=%d flags=0x%x inherit=%d block=%d system=%d excl_idle=%d\n", 
 			(void *)ctx, task->pid, ctx_flags, ctx->ctx_fl_inherit, 
-			ctx->ctx_fl_block, ctx->ctx_fl_system));
+			ctx->ctx_fl_block, ctx->ctx_fl_system, ctx->ctx_fl_excl_idle));
 
 	/*
 	 * when no notification is required, we can make this visible at the last moment
@@ -1147,9 +1273,9 @@
 	 */
 	if (ctx->ctx_fl_system) {
 		ctx->ctx_saved_cpus_allowed = task->cpus_allowed;
-		task->cpus_allowed = 1UL << cpu;
+		task->cpus_allowed = tmp.ctx_cpu_mask;
 		task->need_resched = 1;
-		DBprintk(("[%d] rescheduled allowed=0x%lx\n", task->pid,task->cpus_allowed));
+		DBprintk(("[%d] rescheduled allowed=0x%lx\n", task->pid, task->cpus_allowed));
 	}
 
 	return 0;
@@ -1157,32 +1283,40 @@
 buffer_error:
 	pfm_context_free(ctx);
 error:
-	/*
-	 * undo session reservation
-	 */
-	LOCK_PFS();
-
-	if (ctx_flags & PFM_FL_SYSTEM_WIDE) {
-		pfm_sessions.pfs_sys_session[cpu] = NULL;
-		pfm_sessions.pfs_sys_sessions--;
-	} else {
-		pfm_sessions.pfs_task_sessions--;
-	}
+	pfm_unreserve_session(task, ctx_flags & PFM_FL_SYSTEM_WIDE , tmp.ctx_cpu_mask);
 abort:
-	UNLOCK_PFS();
+	/* make sure we don't leave anything behind */
+	task->thread.pfm_context = NULL;
 
 	return ret;
 }
 
+static inline unsigned long
+pfm_new_counter_value (pfm_counter_t *reg, int is_long_reset)
+{
+	unsigned long val = is_long_reset ? reg->long_reset : reg->short_reset;
+	unsigned long new_seed, old_seed = reg->seed, mask = reg->mask;
+	extern unsigned long carta_random32 (unsigned long seed);
+
+	if (reg->flags & PFM_REGFL_RANDOM) {
+		new_seed = carta_random32(old_seed);
+		val -= (old_seed & mask);	/* counter values are negative numbers! */
+		if ((mask >> 32) != 0)
+			/* construct a full 64-bit random value: */
+			new_seed |= carta_random32(old_seed >> 32) << 32;
+		reg->seed = new_seed;
+	}
+	reg->lval = val;
+	return val;
+}
+
 static void
 pfm_reset_regs(pfm_context_t *ctx, unsigned long *ovfl_regs, int flag)
 {
 	unsigned long mask = ovfl_regs[0];
 	unsigned long reset_others = 0UL;
 	unsigned long val;
-	int i;
-
-	DBprintk(("masks=0x%lx\n", mask));
+	int i, is_long_reset = (flag == PFM_PMD_LONG_RESET);
 
 	/*
 	 * now restore reset value on sampling overflowed counters
@@ -1190,15 +1324,11 @@
 	mask >>= PMU_FIRST_COUNTER;
 	for(i = PMU_FIRST_COUNTER; mask; i++, mask >>= 1) {
 		if (mask & 0x1) {
-			val  = flag == PFM_RELOAD_LONG_RESET ? 
-					ctx->ctx_soft_pmds[i].long_reset:
-					ctx->ctx_soft_pmds[i].short_reset;
-
+			val = pfm_new_counter_value(ctx->ctx_soft_pmds + i, is_long_reset);
 			reset_others |= ctx->ctx_soft_pmds[i].reset_pmds[0];
 
-			DBprintk(("[%d] %s reset soft_pmd[%d]=%lx\n", 
-			  	current->pid, 
-				flag == PFM_RELOAD_LONG_RESET ? "long" : "short", i, val));
+			DBprintk_ovfl(("[%d] %s reset soft_pmd[%d]=%lx\n", current->pid,
+				  is_long_reset ? "long" : "short", i, val));
 
 			/* upper part is ignored on rval */
 			pfm_write_soft_counter(ctx, i, val);
@@ -1212,23 +1342,17 @@
 
 		if ((reset_others & 0x1) == 0) continue;
 
-		val  = flag == PFM_RELOAD_LONG_RESET ? 
-					ctx->ctx_soft_pmds[i].long_reset:
-					ctx->ctx_soft_pmds[i].short_reset;
+		val = pfm_new_counter_value(ctx->ctx_soft_pmds + i, is_long_reset);
 
 		if (PMD_IS_COUNTING(i)) {
 			pfm_write_soft_counter(ctx, i, val);
 		} else {
 			ia64_set_pmd(i, val);
 		}
-
-		DBprintk(("[%d] %s reset_others pmd[%d]=%lx\n", 
-			  	current->pid, 
-				flag == PFM_RELOAD_LONG_RESET ? "long" : "short", i, val));
+		DBprintk_ovfl(("[%d] %s reset_others pmd[%d]=%lx\n", current->pid,
+			  is_long_reset ? "long" : "short", i, val));
 	}
 	ia64_srlz_d();
-	/* just in case ! */
-	ctx->ctx_ovfl_regs[0] = 0UL;
 }
 
 static int
@@ -1236,23 +1360,28 @@
 {
 	struct thread_struct *th = &task->thread;
 	pfarg_reg_t tmp, *req = (pfarg_reg_t *)arg;
-	unsigned int cnum;
+	unsigned long value, reset_pmds;
+	unsigned int cnum, reg_flags, flags;
 	int i;
-	int ret = 0, reg_retval = 0;
+	int ret = -EINVAL;
 
 	/* we don't quite support this right now */
 	if (task != current) return -EINVAL;
 
 	if (!CTX_IS_ENABLED(ctx)) return -EINVAL;
 
+
 	/* XXX: ctx locking may be required here */
 
 	for (i = 0; i < count; i++, req++) {
 
+		if (__copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
 
-		if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
-
-		cnum = tmp.reg_num;
+		cnum       = tmp.reg_num;
+		reg_flags  = tmp.reg_flags;
+		value      = tmp.reg_value;
+		reset_pmds = tmp.reg_reset_pmds[0];
+		flags      = 0;
 
 		/* 
 		 * we reject all non implemented PMC as well
@@ -1261,8 +1390,7 @@
 		 */
 		if (!PMC_IS_IMPL(cnum) || cnum < 4) {
 			DBprintk(("pmc[%u] is unimplemented or invalid\n", cnum));
-			ret = -EINVAL;
-			goto abort_mission;
+			goto error;
 		}
 		/*
 		 * A PMC used to configure monitors must be:
@@ -1271,73 +1399,83 @@
 		 * any other configuration is rejected.
 		 */
 		if (PMC_IS_MONITOR(cnum) || PMC_IS_COUNTING(cnum)) {
-			DBprintk(("pmc[%u].pm=%ld\n", cnum, PMC_PM(cnum, tmp.reg_value))); 
+			DBprintk(("pmc[%u].pm=%ld\n", cnum, PMC_PM(cnum, value))); 
 
-			if (ctx->ctx_fl_system ^ PMC_PM(cnum, tmp.reg_value)) {
-				DBprintk(("pmc_pm=%ld fl_system=%d\n", PMC_PM(cnum, tmp.reg_value), ctx->ctx_fl_system));
-				ret = -EINVAL;
-				goto abort_mission;
+			if (ctx->ctx_fl_system ^ PMC_PM(cnum, value)) {
+				DBprintk(("pmc_pm=%ld fl_system=%d\n", PMC_PM(cnum, value), ctx->ctx_fl_system));
+				goto error;
 			}
 		}
 
 		if (PMC_IS_COUNTING(cnum)) {
-			pfm_monitor_t *p = (pfm_monitor_t *)&tmp.reg_value;
+			pfm_monitor_t *p = (pfm_monitor_t *)&value;
 			/*
 		 	 * enforce generation of overflow interrupt. Necessary on all
 		 	 * CPUs.
 		 	 */
 			p->pmc_oi = 1;
 
-			if (tmp.reg_flags & PFM_REGFL_OVFL_NOTIFY) {
+			if (reg_flags & PFM_REGFL_OVFL_NOTIFY) {
 				/*
-				 * must have a target for the signal
-				 */
+			 	 * must have a target for the signal
+			 	 */
 				if (ctx->ctx_notify_task == NULL) {
-					DBprintk(("no notify_task && PFM_REGFL_OVFL_NOTIFY\n"));
-					ret = -EINVAL;
-					goto abort_mission;
+					DBprintk(("cannot set ovfl_notify: no notify_task\n"));
+					goto error;
 				}
+				flags |= PFM_REGFL_OVFL_NOTIFY;
+			}
 
-				ctx->ctx_soft_pmds[cnum].flags |= PFM_REGFL_OVFL_NOTIFY;
+			if (reg_flags & PFM_REGFL_RANDOM) flags |= PFM_REGFL_RANDOM;
+
+			/* verify validity of reset_pmds */
+			if ((reset_pmds & pmu_conf.impl_pmds[0]) != reset_pmds) {
+				DBprintk(("invalid reset_pmds 0x%lx for pmc%u\n", reset_pmds, cnum));
+				goto error;
 			}
-			/*
-			 * copy reset vector
-			 */
-			ctx->ctx_soft_pmds[cnum].reset_pmds[0] = tmp.reg_reset_pmds[0];
-			ctx->ctx_soft_pmds[cnum].reset_pmds[1] = tmp.reg_reset_pmds[1];
-			ctx->ctx_soft_pmds[cnum].reset_pmds[2] = tmp.reg_reset_pmds[2];
-			ctx->ctx_soft_pmds[cnum].reset_pmds[3] = tmp.reg_reset_pmds[3];
+		} else if (reg_flags & (PFM_REGFL_OVFL_NOTIFY|PFM_REGFL_RANDOM)) {
+				DBprintk(("cannot set ovfl_notify or random on pmc%u\n", cnum));
+				goto error;
 		}
+
 		/*
 		 * execute write checker, if any
 		 */
-		if (PMC_WR_FUNC(cnum)) ret = PMC_WR_FUNC(cnum)(task, cnum, &tmp.reg_value, regs);
-abort_mission:
-		if (ret == -EINVAL) reg_retval = PFM_REG_RETFL_EINVAL;
+		if (PMC_WR_FUNC(cnum)) {
+			ret = PMC_WR_FUNC(cnum)(task, cnum, &value, regs);
+			if (ret) goto error;
+			ret = -EINVAL;
+		}
 
-		PFM_REG_RETFLAG_SET(tmp.reg_flags, reg_retval);
+		/*
+		 * no error on this register
+		 */
+		PFM_REG_RETFLAG_SET(tmp.reg_flags, 0);
 
 		/*
 		 * update register return value, abort all if problem during copy.
+		 * we only modify the reg_flags field. no check mode is fine because
+		 * access has been verified upfront in sys_perfmonctl().
+		 *
+		 * If this fails, then the software state is not modified
 		 */
-		if (copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT;
+		if (__put_user(tmp.reg_flags, &req->reg_flags)) return -EFAULT;
 
 		/*
-		 * if there was something wrong on this register, don't touch
-		 * the hardware at all and abort write request for others.
-		 *
-		 * On error, the user mut sequentially scan the table and the first
-		 * entry which has a return flag set is the one that caused the error.
+		 * Now we commit the changes to the software state
 		 */
-		if (ret != 0) {
-			DBprintk(("[%d] pmc[%u]=0x%lx error %d\n",
-				  task->pid, cnum, tmp.reg_value, reg_retval));
-			break;
-		}
 
 		/* 
-		 * We can proceed with this register!
+		 * full flag update each time a register is programmed
 		 */
+		ctx->ctx_soft_pmds[cnum].flags = flags;
+
+		if (PMC_IS_COUNTING(cnum)) {
+			ctx->ctx_soft_pmds[cnum].reset_pmds[0] = reset_pmds;
+
+			/* mark all PMDS to be accessed as used */
+			CTX_USED_PMD(ctx, reset_pmds);
+		}
 
 		/*
 		 * Needed in case the user does not initialize the equivalent
@@ -1349,16 +1487,26 @@
 		/* 
 		 * keep copy the pmc, used for register reload
 		 */
-		th->pmc[cnum] = tmp.reg_value;
+		th->pmc[cnum] = value;
 
-		ia64_set_pmc(cnum, tmp.reg_value);
+		ia64_set_pmc(cnum, value);
 
 		DBprintk(("[%d] pmc[%u]=0x%lx flags=0x%x used_pmds=0x%lx\n", 
-			  task->pid, cnum, tmp.reg_value, 
+			  task->pid, cnum, value, 
 			  ctx->ctx_soft_pmds[cnum].flags, 
 			  ctx->ctx_used_pmds[0]));
 
 	}
+
+	return 0;
+
+error:
+	PFM_REG_RETFLAG_SET(tmp.reg_flags, PFM_REG_RETFL_EINVAL);
+
+	if (__put_user(tmp.reg_flags, &req->reg_flags)) ret = -EFAULT;
+
+	DBprintk(("[%d] pmc[%u]=0x%lx error %d\n", task->pid, cnum, value, ret));
+
 	return ret;
 }
 
@@ -1366,9 +1514,10 @@
 pfm_write_pmds(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
 {
 	pfarg_reg_t tmp, *req = (pfarg_reg_t *)arg;
+	unsigned long value, hw_value;
 	unsigned int cnum;
 	int i;
-	int ret = 0, reg_retval = 0;
+	int ret = -EINVAL;
 
 	/* we don't quite support this right now */
 	if (task != current) return -EINVAL;
@@ -1378,73 +1527,99 @@
 	 */
 	if (!CTX_IS_ENABLED(ctx)) return -EINVAL;
 
-
 	/* XXX: ctx locking may be required here */
 
+
 	for (i = 0; i < count; i++, req++) {
 
-		if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
+		if (__copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
+
+		cnum  = tmp.reg_num;
+		value = tmp.reg_value;
 
-		cnum = tmp.reg_num;
 		if (!PMD_IS_IMPL(cnum)) {
-			ret = -EINVAL;
+			DBprintk(("pmd[%u] is unimplemented or invalid\n", cnum));
 			goto abort_mission;
 		}
 
-		/* update virtualized (64bits) counter */
-		if (PMD_IS_COUNTING(cnum)) {
-			ctx->ctx_soft_pmds[cnum].ival = tmp.reg_value;
-			ctx->ctx_soft_pmds[cnum].val  = tmp.reg_value & ~pmu_conf.perf_ovfl_val;
-			ctx->ctx_soft_pmds[cnum].long_reset = tmp.reg_long_reset;
-			ctx->ctx_soft_pmds[cnum].short_reset = tmp.reg_short_reset;
-
-		}
 		/*
 		 * execute write checker, if any
 		 */
-		if (PMD_WR_FUNC(cnum)) ret = PMD_WR_FUNC(cnum)(task, cnum, &tmp.reg_value, regs);
-abort_mission:
-		if (ret == -EINVAL) reg_retval = PFM_REG_RETFL_EINVAL;
-
-		PFM_REG_RETFLAG_SET(tmp.reg_flags, reg_retval);
+		if (PMD_WR_FUNC(cnum)) {
+			unsigned long v = value;
+			ret = PMD_WR_FUNC(cnum)(task, cnum, &v, regs);
+			if (ret) goto abort_mission;
+			value = v;
+			ret = -EINVAL;
+		}
+		hw_value = value;
+		/*
+		 * no error on this register
+		 */
+		PFM_REG_RETFLAG_SET(tmp.reg_flags, 0);
 
-		if (copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT;
+		if (__put_user(tmp.reg_flags, &req->reg_flags)) return -EFAULT;
 
 		/*
-		 * if there was something wrong on this register, don't touch
-		 * the hardware at all and abort write request for others.
-		 *
-		 * On error, the user mut sequentially scan the table and the first
-		 * entry which has a return flag set is the one that caused the error.
+		 * now commit changes to software state
 		 */
-		if (ret != 0) {
-			DBprintk(("[%d] pmc[%u]=0x%lx error %d\n",
-				  task->pid, cnum, tmp.reg_value, reg_retval));
-			break;
+
+		/* update virtualized (64bits) counter */
+		if (PMD_IS_COUNTING(cnum)) {
+			ctx->ctx_soft_pmds[cnum].lval = value;
+			ctx->ctx_soft_pmds[cnum].val  = value & ~pmu_conf.ovfl_val;
+
+			hw_value = value & pmu_conf.ovfl_val;
+
+			ctx->ctx_soft_pmds[cnum].long_reset  = tmp.reg_long_reset;
+			ctx->ctx_soft_pmds[cnum].short_reset = tmp.reg_short_reset;
+
+			ctx->ctx_soft_pmds[cnum].seed = tmp.reg_random_seed;
+			ctx->ctx_soft_pmds[cnum].mask = tmp.reg_random_mask;
 		}
 
 		/* keep track of what we use */
 		CTX_USED_PMD(ctx, pmu_conf.pmd_desc[(cnum)].dep_pmd[0]);
+
 		/* mark this register as used as well */
 		CTX_USED_PMD(ctx, RDEP(cnum));
 
 		/* writes to unimplemented part is ignored, so this is safe */
-		ia64_set_pmd(cnum, tmp.reg_value & pmu_conf.perf_ovfl_val);
+		ia64_set_pmd(cnum, hw_value);
 
 		/* to go away */
 		ia64_srlz_d();
 
-		DBprintk(("[%d] pmd[%u]: soft_pmd=0x%lx  short_reset=0x%lx "
+		DBprintk(("[%d] pmd[%u]: value=0x%lx hw_value=0x%lx soft_pmd=0x%lx  short_reset=0x%lx "
 			  "long_reset=0x%lx hw_pmd=%lx notify=%c used_pmds=0x%lx reset_pmds=0x%lx\n",
 				task->pid, cnum,
+				value, hw_value,
 				ctx->ctx_soft_pmds[cnum].val,
 				ctx->ctx_soft_pmds[cnum].short_reset,
 				ctx->ctx_soft_pmds[cnum].long_reset,
-				ia64_get_pmd(cnum) & pmu_conf.perf_ovfl_val,
+				ia64_get_pmd(cnum) & pmu_conf.ovfl_val,
 				PMC_OVFL_NOTIFY(ctx, cnum) ? 'Y':'N',
 				ctx->ctx_used_pmds[0],
 				ctx->ctx_soft_pmds[cnum].reset_pmds[0]));
 	}
+
+	return 0;
+
+abort_mission:
+	/*
+	 * for now, we have only one possibility for error
+	 */
+	PFM_REG_RETFLAG_SET(tmp.reg_flags, PFM_REG_RETFL_EINVAL);
+
+	/*
+	 * we change the return value to EFAULT in case we cannot write register return code.
+	 * The caller first must correct this error, then a resubmission of the request will
+	 * eventually yield the EINVAL.
+	 */
+	if (__put_user(tmp.reg_flags, &req->reg_flags)) ret = -EFAULT;
+
+	DBprintk(("[%d] pmc[%u]=0x%lx ret %d\n", task->pid, cnum, value, ret));
+
 	return ret;
 }
 
@@ -1452,10 +1627,13 @@
 pfm_read_pmds(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
 {
 	struct thread_struct *th = &task->thread;
-	unsigned long val=0;
-	pfarg_reg_t tmp, *req = (pfarg_reg_t *)arg;
-	unsigned int cnum;
+	unsigned long val, lval;
+	pfarg_reg_t *req = (pfarg_reg_t *)arg;
+	unsigned int cnum, reg_flags = 0;
 	int i, ret = 0;
+#if __GNUC__ < 3
+	int foo;
+#endif
 
 	if (!CTX_IS_ENABLED(ctx)) return -EINVAL;
 
@@ -1471,11 +1649,17 @@
 	DBprintk(("ctx_last_cpu=%d for [%d]\n", atomic_read(&ctx->ctx_last_cpu), task->pid));
 
 	for (i = 0; i < count; i++, req++) {
-		unsigned long ctx_val = ~0UL;
-
-		if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
 
-		cnum = tmp.reg_num;
+#if __GNUC__ < 3
+		foo = __get_user(cnum, &req->reg_num);
+		if (foo) return -EFAULT;
+		foo = __get_user(reg_flags, &req->reg_flags);
+		if (foo) return -EFAULT;
+#else
+		if (__get_user(cnum, &req->reg_num)) return -EFAULT;
+		if (__get_user(reg_flags, &req->reg_flags)) return -EFAULT;
+#endif
+		lval = 0UL;
 
 		if (!PMD_IS_IMPL(cnum)) goto abort_mission;
 		/*
@@ -1523,36 +1707,47 @@
 			/*
 			 * XXX: need to check for overflow
 			 */
+			val &= pmu_conf.ovfl_val;
+			val += ctx->ctx_soft_pmds[cnum].val;
 
-			val &= pmu_conf.perf_ovfl_val;
-			val += ctx_val = ctx->ctx_soft_pmds[cnum].val;
+			lval = ctx->ctx_soft_pmds[cnum].lval;
 		} 
 
-		tmp.reg_value = val;
-
 		/*
 		 * execute read checker, if any
 		 */
 		if (PMD_RD_FUNC(cnum)) {
-			ret = PMD_RD_FUNC(cnum)(task, cnum, &tmp.reg_value, regs);
+			unsigned long v = val;
+			ret = PMD_RD_FUNC(cnum)(task, cnum, &v, regs);
+			val = v;
 		}
 
-		PFM_REG_RETFLAG_SET(tmp.reg_flags, ret);
+		PFM_REG_RETFLAG_SET(reg_flags, ret);
 
 		DBprintk(("read pmd[%u] ret=%d value=0x%lx pmc=0x%lx\n", 
 					cnum, ret, val, ia64_get_pmc(cnum)));
 
-		if (copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT;
+		/*
+		 * update register return value, abort all if problem during copy.
+		 * we only modify the reg_flags field. no check mode is fine because
+		 * access has been verified upfront in sys_perfmonctl().
+		 */
+		if (__put_user(cnum, &req->reg_num)) return -EFAULT;
+		if (__put_user(val, &req->reg_value)) return -EFAULT;
+		if (__put_user(reg_flags, &req->reg_flags)) return -EFAULT;
+		if (__put_user(lval, &req->reg_last_reset_value)) return -EFAULT;
 	}
+
 	return 0;
+
 abort_mission:
-	PFM_REG_RETFLAG_SET(tmp.reg_flags, PFM_REG_RETFL_EINVAL);
+	PFM_REG_RETFLAG_SET(reg_flags, PFM_REG_RETFL_EINVAL);
 	/* 
 	 * XXX: if this fails, we stick with the original failure, flag not updated!
 	 */
-	copy_to_user(req, &tmp, sizeof(tmp));
-	return -EINVAL;
+	__put_user(reg_flags, &req->reg_flags);
 
+	return -EINVAL;
 }
 
 #ifdef PFM_PMU_USES_DBR
@@ -1594,7 +1789,7 @@
 	else
 		pfm_sessions.pfs_ptrace_use_dbregs++;
 
-	DBprintk(("ptrace_use_dbregs=%lu  sys_use_dbregs=%lu by [%d] ret = %d\n", 
+	DBprintk(("ptrace_use_dbregs=%u  sys_use_dbregs=%u by [%d] ret = %d\n", 
 		  pfm_sessions.pfs_ptrace_use_dbregs, 
 		  pfm_sessions.pfs_sys_use_dbregs, 
 		  task->pid, ret));
@@ -1660,9 +1855,12 @@
 	if (!CTX_IS_ENABLED(ctx)) return -EINVAL;
 
 	if (task == current) {
-		DBprintk(("restarting self %d frozen=%d \n", current->pid, ctx->ctx_fl_frozen));
+		DBprintk(("restarting self %d frozen=%d ovfl_regs=0x%lx\n", 
+			task->pid, 
+			ctx->ctx_fl_frozen,
+			ctx->ctx_ovfl_regs[0]));
 
-		pfm_reset_regs(ctx, ctx->ctx_ovfl_regs, PFM_RELOAD_LONG_RESET);
+		pfm_reset_regs(ctx, ctx->ctx_ovfl_regs, PFM_PMD_LONG_RESET);
 
 		ctx->ctx_ovfl_regs[0] = 0UL;
 
@@ -1678,8 +1876,7 @@
 		}
 
 		/* simply unfreeze */
-		ia64_set_pmc(0, 0);
-		ia64_srlz_d();
+		pfm_unfreeze_pmu();
 
 		return 0;
 	} 
@@ -1721,44 +1918,6 @@
 	return 0;
 }
 
-#ifndef CONFIG_SMP
-/*
- * On UP kernels, we do not need to constantly set the psr.pp bit
- * when a task is scheduled. The psr.pp bit can only be changed in
- * the kernel because of a user request. Given we are on a UP non preeemptive 
- * kernel we know that no other task is running, so we cna simply update their
- * psr.pp from their saved state. There is this no impact on the context switch
- * code compared to the SMP case.
- */
-static void
-pfm_tasklist_toggle_pp(unsigned int val)
-{
-	struct task_struct *p;
-	struct pt_regs *regs;
-
-	DBprintk(("invoked by [%d] pp=%u\n", current->pid, val));
-
-	read_lock(&tasklist_lock);
-
-	for_each_task(p) {
-       		regs = (struct pt_regs *)((unsigned long) p + IA64_STK_OFFSET);
-
-		/*
-		 * position on pt_regs saved on stack on 1st entry into the kernel
-		 */
-		regs--;
-
-		/*
-		 * update psr.pp
-		 */
-		ia64_psr(regs)->pp = val;
-	}
-	read_unlock(&tasklist_lock);
-}
-#endif
-
-
-
 static int
 pfm_stop(struct task_struct *task, pfm_context_t *ctx, void *arg, int count, 
 	 struct pt_regs *regs)
@@ -1783,22 +1942,17 @@
 		ia64_set_dcr(ia64_get_dcr() & ~IA64_DCR_PP);
 
 		/* stop monitoring */
-		__asm__ __volatile__ ("rsm psr.pp;;"::: "memory");
-
+		pfm_clear_psr_pp();
 		ia64_srlz_i();
 
-#ifdef CONFIG_SMP
-		local_cpu_data->pfm_dcr_pp  = 0;
-#else
-		pfm_tasklist_toggle_pp(0);
-#endif
+		PFM_CPUINFO_CLEAR(PFM_CPUINFO_DCR_PP);
+
 		ia64_psr(regs)->pp = 0;
 
 	} else {
 
 		/* stop monitoring */
-		__asm__ __volatile__ ("rum psr.up;;"::: "memory");
-
+		pfm_clear_psr_up();
 		ia64_srlz_i();
 
 		/*
@@ -1960,14 +2114,9 @@
 	int i, ret = 0;
 
 	/*
-	 * for range restriction: psr.db must be cleared or the
-	 * the PMU will ignore the debug registers.
-	 *
-	 * XXX: may need more in system wide mode,
-	 * no task can have this bit set?
+	 * we do not need to check for ipsr.db because we do clear ibr.x, dbr.r, and dbr.w
+	 * ensuring that no real breakpoint can be installed via this call.
 	 */
-	if (ia64_psr(regs)->db == 1) return -EINVAL;
-
 
 	first_time = ctx->ctx_fl_using_dbreg == 0;
 
@@ -2036,9 +2185,8 @@
 	 * Now install the values into the registers
 	 */
 	for (i = 0; i < count; i++, req++) {
-
 		
-		if (copy_from_user(&tmp, req, sizeof(tmp))) goto abort_mission;
+		if (__copy_from_user(&tmp, req, sizeof(tmp))) goto abort_mission;
 		
 		rnum      = tmp.dbreg_num;
 		dbreg.val = tmp.dbreg_value;
@@ -2071,7 +2219,7 @@
 
 		PFM_REG_RETFLAG_SET(tmp.dbreg_flags, 0);
 
-		if (copy_to_user(req, &tmp, sizeof(tmp))) goto abort_mission;
+		if (__copy_to_user(req, &tmp, sizeof(tmp))) goto abort_mission;
 
 		/*
 		 * Debug registers, just like PMC, can only be modified
@@ -2126,7 +2274,7 @@
 		 * XXX: for now we can only come here on EINVAL
 		 */
 		PFM_REG_RETFLAG_SET(tmp.dbreg_flags, PFM_REG_RETFL_EINVAL);
-		copy_to_user(req, &tmp, sizeof(tmp));
+		if (__put_user(tmp.dbreg_flags, &req->dbreg_flags)) ret = -EFAULT;
 	}
 	return ret;
 }
@@ -2167,7 +2315,7 @@
 	tmp.ft_version      = PFM_VERSION;
 	tmp.ft_smpl_version = PFM_SMPL_VERSION;
 
-	if (copy_to_user(arg, &tmp, sizeof(tmp))) return -EFAULT;
+	if (__copy_to_user(arg, &tmp, sizeof(tmp))) return -EFAULT;
 
 	return 0;
 }
@@ -2196,16 +2344,13 @@
 
 	if (ctx->ctx_fl_system) {
 		
-#ifdef CONFIG_SMP
-		local_cpu_data->pfm_dcr_pp  = 1;
-#else
-		pfm_tasklist_toggle_pp(1);
-#endif
+		PFM_CPUINFO_SET(PFM_CPUINFO_DCR_PP);
+
 		/* set user level psr.pp */
 		ia64_psr(regs)->pp = 1;
 
 		/* start monitoring at kernel level */
-		__asm__ __volatile__ ("ssm psr.pp;;"::: "memory");
+		pfm_set_psr_pp();
 
 		/* enable dcr pp */
 		ia64_set_dcr(ia64_get_dcr()|IA64_DCR_PP);
@@ -2221,7 +2366,7 @@
 		ia64_psr(regs)->up = 1;
 
 		/* start monitoring at kernel level */
-		__asm__ __volatile__ ("sum psr.up;;"::: "memory");
+		pfm_set_psr_up();
 
 		ia64_srlz_i();
 	}
@@ -2234,13 +2379,16 @@
 	   struct pt_regs *regs)
 {
 	/* we don't quite support this right now */
-	if (task != current) return -EINVAL;
+	if (task != current) {
+		DBprintk(("task [%d] != current [%d]\n", task->pid, current->pid));
+		return -EINVAL;
+	}
 
 	if (ctx->ctx_fl_system == 0 && PMU_OWNER()  && PMU_OWNER() != current) 
 		pfm_lazy_save_regs(PMU_OWNER());
 
 	/* reset all registers to stable quiet state */
-	ia64_reset_pmu(task);
+	pfm_reset_pmu(task);
 
 	/* make sure nothing starts */
 	if (ctx->ctx_fl_system) {
@@ -2248,13 +2396,12 @@
 		ia64_psr(regs)->up = 0; /* just to make sure! */
 
 		/* make sure monitoring is stopped */
-		__asm__ __volatile__ ("rsm psr.pp;;"::: "memory");
+		pfm_clear_psr_pp();
 		ia64_srlz_i();
 
-#ifdef CONFIG_SMP
-		local_cpu_data->pfm_syst_wide = 1;
-		local_cpu_data->pfm_dcr_pp    = 0;
-#endif
+		PFM_CPUINFO_CLEAR(PFM_CPUINFO_DCR_PP);
+		PFM_CPUINFO_SET(PFM_CPUINFO_SYST_WIDE);
+		if (ctx->ctx_fl_excl_idle) PFM_CPUINFO_SET(PFM_CPUINFO_EXCL_IDLE);
 	} else {
 		/*
 		 * needed in case the task was a passive task during
@@ -2265,7 +2412,7 @@
 		ia64_psr(regs)->up = 0;
 
 		/* make sure monitoring is stopped */
-		__asm__ __volatile__ ("rum psr.up;;"::: "memory");
+		pfm_clear_psr_up();
 		ia64_srlz_i();
 
 		DBprintk(("clearing psr.sp for [%d]\n", current->pid));
@@ -2283,8 +2430,7 @@
 	atomic_set(&ctx->ctx_last_cpu, smp_processor_id());
 
 	/* simply unfreeze */
-	ia64_set_pmc(0, 0);
-	ia64_srlz_d();
+	pfm_unfreeze_pmu();
 
 	return 0;
 }
@@ -2295,32 +2441,30 @@
 {
 	pfarg_reg_t tmp, *req = (pfarg_reg_t *)arg;
 	unsigned int cnum;
-	int i;
+	int i, ret = -EINVAL;
 
 	for (i = 0; i < count; i++, req++) {
 
-		if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
+		if (__copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
 
 		cnum = tmp.reg_num;
 
 		if (!PMC_IS_IMPL(cnum)) goto abort_mission;
 
-		tmp.reg_value = reset_pmcs[cnum];
+		tmp.reg_value = PMC_DFL_VAL(cnum);
 
 		PFM_REG_RETFLAG_SET(tmp.reg_flags, 0);
 
 		DBprintk(("pmc_reset_val pmc[%u]=0x%lx\n", cnum, tmp.reg_value)); 
 
-		if (copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT;
+		if (__copy_to_user(req, &tmp, sizeof(tmp))) return -EFAULT;
 	}
 	return 0;
 abort_mission:
 	PFM_REG_RETFLAG_SET(tmp.reg_flags, PFM_REG_RETFL_EINVAL);
-	/* 
-	 * XXX: if this fails, we stick with the original failure, flag not updated!
-	 */
-	copy_to_user(req, &tmp, sizeof(tmp));
-	return -EINVAL;
+	if (__copy_to_user(req, &tmp, sizeof(tmp))) ret = -EFAULT;
+
+	return ret;
 }
 
 /*
@@ -2328,21 +2472,21 @@
  */
 static pfm_cmd_desc_t pfm_cmd_tab[]={
 /* 0  */{ NULL, 0, 0, 0}, /* not used */
-/* 1  */{ pfm_write_pmcs, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)}, 
-/* 2  */{ pfm_write_pmds, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_READ, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)},
-/* 3  */{ pfm_read_pmds,PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)}, 
+/* 1  */{ pfm_write_pmcs, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)}, 
+/* 2  */{ pfm_write_pmds, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)},
+/* 3  */{ pfm_read_pmds,PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)}, 
 /* 4  */{ pfm_stop, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
 /* 5  */{ pfm_start, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
 /* 6  */{ pfm_enable, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
 /* 7  */{ pfm_disable, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
-/* 8  */{ pfm_context_create, PFM_CMD_PID|PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, 1, sizeof(pfarg_context_t)},
+/* 8  */{ pfm_context_create, PFM_CMD_PID|PFM_CMD_ARG_RW, 1, sizeof(pfarg_context_t)},
 /* 9  */{ pfm_context_destroy, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
 /* 10 */{ pfm_restart, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_NOCHK, 0, 0},
 /* 11 */{ pfm_protect_context, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
-/* 12 */{ pfm_get_features, PFM_CMD_ARG_WRITE, 0, 0},
+/* 12 */{ pfm_get_features, PFM_CMD_ARG_RW, 0, 0},
 /* 13 */{ pfm_debug, 0, 1, sizeof(unsigned int)},
 /* 14 */{ pfm_context_unprotect, PFM_CMD_PID|PFM_CMD_CTX, 0, 0},
-/* 15 */{ pfm_get_pmc_reset, PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)},
+/* 15 */{ pfm_get_pmc_reset, PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, sizeof(pfarg_reg_t)},
 /* 16 */{ NULL, 0, 0, 0}, /* not used */
 /* 17 */{ NULL, 0, 0, 0}, /* not used */
 /* 18 */{ NULL, 0, 0, 0}, /* not used */
@@ -2360,8 +2504,8 @@
 /* 30 */{ NULL, 0, 0, 0}, /* not used */
 /* 31 */{ NULL, 0, 0, 0}, /* not used */
 #ifdef PFM_PMU_USES_DBR
-/* 32 */{ pfm_write_ibrs, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, PFM_CMD_ARG_MANY, sizeof(pfarg_dbreg_t)},
-/* 33 */{ pfm_write_dbrs, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_READ|PFM_CMD_ARG_WRITE, PFM_CMD_ARG_MANY, sizeof(pfarg_dbreg_t)}
+/* 32 */{ pfm_write_ibrs, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, sizeof(pfarg_dbreg_t)},
+/* 33 */{ pfm_write_dbrs, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, sizeof(pfarg_dbreg_t)}
 #endif
 };
 #define PFM_CMD_COUNT	(sizeof(pfm_cmd_tab)/sizeof(pfm_cmd_desc_t))
@@ -2379,11 +2523,15 @@
 	for (;;) {
 
 		task_lock(task);
+		DBprintk((" [%d] state=%ld\n", task->pid, task->state));
 		if (!task_has_cpu(task)) break;
 		task_unlock(task);
 
 		do {
-			if (task->state != TASK_ZOMBIE && task->state != TASK_STOPPED) return -EBUSY;
+			if (task->state != TASK_ZOMBIE && task->state != TASK_STOPPED) {
+				DBprintk(("warning [%d] not in stable state %ld\n", task->pid, task->state));
+				return -EBUSY;
+			}
 			barrier();
 			cpu_relax();
 		} while (task_has_cpu(task));
@@ -2398,7 +2546,7 @@
 	return ret;
 }
 
-asmlinkage int
+asmlinkage long
 sys_perfmonctl (pid_t pid, int cmd, void *arg, int count, long arg5, long arg6, long arg7, 
 		long arg8, long stack)
 {
@@ -2406,7 +2554,8 @@
 	struct task_struct *task = current;
 	pfm_context_t *ctx;
 	size_t sz;
-	int ret, narg;
+	long ret;
+	int narg;
 
 	/* 
 	 * reject any call if perfmon was disabled at initialization time
@@ -2426,7 +2575,7 @@
 
 	if (PFM_CMD_READ_ARG(cmd) && !access_ok(VERIFY_READ, arg, sz*count)) return -EFAULT;
 
-	if (PFM_CMD_WRITE_ARG(cmd) && !access_ok(VERIFY_WRITE, arg, sz*count)) return -EFAULT;
+	if (PFM_CMD_RW_ARG(cmd) && !access_ok(VERIFY_WRITE, arg, sz*count)) return -EFAULT;
 
 	if (PFM_CMD_USE_PID(cmd))  {
 		/* 
@@ -2484,15 +2633,9 @@
 	return ret;
 }
 
-#if __GNUC__ >= 3
-void asmlinkage
-pfm_ovfl_block_reset(u64 arg0, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5, 
-		      u64 arg6, u64 arg7, long info)
-#else
 void asmlinkage
 pfm_ovfl_block_reset(u64 arg0, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5, 
 		      u64 arg6, u64 arg7, long info)
-#endif
 {
 	struct thread_struct *th = &current->thread;
 	pfm_context_t *ctx = current->thread.pfm_context;
@@ -2537,7 +2680,7 @@
 		 * use the local reference
 		 */
 
-		pfm_reset_regs(ctx, ctx->ctx_ovfl_regs, PFM_RELOAD_LONG_RESET);
+		pfm_reset_regs(ctx, ctx->ctx_ovfl_regs, PFM_PMD_LONG_RESET);
 
 		ctx->ctx_ovfl_regs[0] = 0UL;
 
@@ -2550,8 +2693,7 @@
 			ctx->ctx_psb->psb_index = 0;
 		}
 
-		ia64_set_pmc(0, 0);
-		ia64_srlz_d();
+		pfm_unfreeze_pmu();
 
 		/* state restored, can go back to work (user mode) */
 	}
@@ -2577,12 +2719,12 @@
 	DBprintk_ovfl(("recording index=%ld entries=%ld\n", idx-1, psb->psb_entries));
 
 	/*
-	* XXX: there is a small chance that we could run out on index before resetting
-	* but index is unsigned long, so it will take some time.....
-	* We use > instead of == because fetch_and_add() is off by one (see below)
-	*
-	* This case can happen in non-blocking mode or with multiple processes.
-	* For non-blocking, we need to reload and continue.
+	 * XXX: there is a small chance that we could run out on index before resetting
+	 * but index is unsigned long, so it will take some time.....
+	 * We use > instead of == because fetch_and_add() is off by one (see below)
+	 *
+	 * This case can happen in non-blocking mode or with multiple processes.
+	 * For non-blocking, we need to reload and continue.
 	 */
 	if (idx > psb->psb_entries) return 0;
 
@@ -2596,13 +2738,12 @@
 	 */
 	h->pid  = current->pid;
 	h->cpu  = smp_processor_id();
-	h->rate = 0; /* XXX: add the sampling rate used here */
-	h->ip   = regs ? regs->cr_iip : 0x0;	/* where did the fault happened */
+	h->last_reset_value = ovfl_mask ? ctx->ctx_soft_pmds[ffz(~ovfl_mask)].lval : 0UL;
+	h->ip   = regs ? regs->cr_iip | ((regs->cr_ipsr >> 41) & 0x3): 0x0UL;
 	h->regs = ovfl_mask; 			/* which registers overflowed */
 
 	/* guaranteed to monotonically increase on each cpu */
 	h->stamp  = pfm_get_stamp();
-	h->period = 0UL; /* not yet used */
 
 	/* position for first pmd */
 	e = (unsigned long *)(h+1);
@@ -2617,15 +2758,13 @@
 
 		if (PMD_IS_COUNTING(j)) {
 			*e  =  pfm_read_soft_counter(ctx, j);
-			/* check if this pmd overflowed as well */
-			*e +=  ovfl_mask & (1UL<<j) ? 1 + pmu_conf.perf_ovfl_val : 0;
 		} else {
 			*e = ia64_get_pmd(j); /* slow */
 		}
 		DBprintk_ovfl(("e=%p pmd%d =0x%lx\n", (void *)e, j, *e));
 		e++;
 	}
-	pfm_stats.pfm_recorded_samples_count++;
+	pfm_stats[smp_processor_id()].pfm_recorded_samples_count++;
 
 	/*
 	 * make the new entry visible to user, needs to be atomic
@@ -2642,7 +2781,7 @@
 		/*
 		 * XXX: must reset buffer in blocking mode and lost notified
 		 */
-		pfm_stats.pfm_full_smpl_buffer_count++;
+		pfm_stats[smp_processor_id()].pfm_full_smpl_buffer_count++;
 		return 1;
 	}
 	return 0;
@@ -2719,23 +2858,13 @@
 			  i, ia64_get_pmd(i), ctx->ctx_soft_pmds[i].val));
 
 		/*
-		 * Because we sometimes (EARS/BTB) reset to a specific value, we cannot simply use
-		 * val to count the number of times we overflowed. Otherwise we would loose the 
-		 * current value in the PMD (which can be >0). So to make sure we don't loose
-		 * the residual counts we set val to contain full 64bits value of the counter.
+		 * Note that the pmd is not necessarily 0 at this point as qualified events
+		 * may have happened before the PMU was frozen. The residual count is not
+		 * taken into consideration here but will be with any read of the pmd via
+		 * pfm_read_pmds().
 		 */
 		old_val = ctx->ctx_soft_pmds[i].val;
-		ctx->ctx_soft_pmds[i].val = 1 + pmu_conf.perf_ovfl_val + pfm_read_soft_counter(ctx, i);
-
-		DBprintk_ovfl(("soft_pmd[%d].val=0x%lx old_val=0x%lx pmd=0x%lx\n", 
-			  i, ctx->ctx_soft_pmds[i].val, old_val, 
-			  ia64_get_pmd(i) & pmu_conf.perf_ovfl_val));
-
-		/*
-		 * now that we have extracted the hardware counter, we can clear it to ensure
-		 * that a subsequent PFM_READ_PMDS will not include it again.
-		 */
-		ia64_set_pmd(i, 0UL);
+		ctx->ctx_soft_pmds[i].val += 1 + pmu_conf.ovfl_val;
 
 		/*
 		 * check for overflow condition
@@ -2744,12 +2873,13 @@
 
 			ovfl_pmds |= 1UL << i;
 
-			DBprintk_ovfl(("soft_pmd[%d] overflowed flags=0x%x, ovfl=0x%lx\n", i, ctx->ctx_soft_pmds[i].flags, ovfl_pmds));
-
 			if (PMC_OVFL_NOTIFY(ctx, i)) {
 				ovfl_notify |= 1UL << i;
 			}
 		}
+		DBprintk_ovfl(("soft_pmd[%d].val=0x%lx old_val=0x%lx pmd=0x%lx ovfl_pmds=0x%lx ovfl_notify=0x%lx\n", 
+			  i, ctx->ctx_soft_pmds[i].val, old_val, 
+			  ia64_get_pmd(i) & pmu_conf.ovfl_val, ovfl_pmds, ovfl_notify));
 	}
 
 	/*
@@ -2784,7 +2914,7 @@
 	 */
 	if (ovfl_notify == 0UL) {
 		if (ovfl_pmds) 
-			pfm_reset_regs(ctx, &ovfl_pmds, PFM_RELOAD_SHORT_RESET);
+			pfm_reset_regs(ctx, &ovfl_pmds, PFM_PMD_SHORT_RESET);
 		return 0x0;
 	}
 
@@ -2932,13 +3062,21 @@
 }
 
 static void
-perfmon_interrupt (int irq, void *arg, struct pt_regs *regs)
+pfm_interrupt_handler(int irq, void *arg, struct pt_regs *regs)
 {
 	u64 pmc0;
 	struct task_struct *task;
 	pfm_context_t *ctx;
 
-	pfm_stats.pfm_ovfl_intr_count++;
+	pfm_stats[smp_processor_id()].pfm_ovfl_intr_count++;
+
+	/*
+	 * if an alternate handler is registered, just bypass the default one
+	 */
+	if (pfm_alternate_intr_handler) {
+		(*pfm_alternate_intr_handler->handler)(irq, arg, regs);
+		return;
+	}
 
 	/* 
 	 * srlz.d done before arriving here
@@ -2983,11 +3121,20 @@
 		pmc0 = pfm_overflow_handler(task, ctx, pmc0, regs);
 
 		/*
-		 * We always clear the overflow status bits and either unfreeze
-		 * or keep the PMU frozen.
+		 * we can only update pmc0 when the overflow
+		 * is for the current context. In UP the current
+		 * task may not be the one owning the PMU
 		 */
-		ia64_set_pmc(0, pmc0);
-		ia64_srlz_d();
+		if (task == current) {
+			/*
+		 	* We always clear the overflow status bits and either unfreeze
+		 	* or keep the PMU frozen.
+		 	*/
+			ia64_set_pmc(0, pmc0);
+			ia64_srlz_d();
+		} else {
+			task->thread.pmc[0] = pmc0;
+		}
 
 #ifdef CONFIG_SMP
 		/*
@@ -2996,42 +3143,38 @@
 		atomic_set(&ctx->ctx_is_busy, 0);
 #endif
 	} else {
-		pfm_stats.pfm_spurious_ovfl_intr_count++;
-
-		printk("perfmon: Spurious PMU overflow interrupt on CPU%d: pmc0=0x%lx owner=%p\n", 
-			smp_processor_id(), pmc0, (void *)PMU_OWNER());
+		pfm_stats[smp_processor_id()].pfm_spurious_ovfl_intr_count++;
 	}
 }
 
 /* for debug only */
 static int
-perfmon_proc_info(char *page)
+pfm_proc_info(char *page)
 {
 	char *p = page;
 	int i;
 
-	p += sprintf(p, "enabled          : %s\n", pmu_conf.pfm_is_disabled ? "No": "Yes");
-	p += sprintf(p, "fastctxsw        : %s\n", pfm_sysctl.fastctxsw > 0 ? "Yes": "No");
-	p += sprintf(p, "ovfl_mask        : 0x%lx\n", pmu_conf.perf_ovfl_val);
-	p += sprintf(p, "overflow intrs   : %lu\n", pfm_stats.pfm_ovfl_intr_count);
-	p += sprintf(p, "spurious intrs   : %lu\n", pfm_stats.pfm_spurious_ovfl_intr_count);
-	p += sprintf(p, "recorded samples : %lu\n", pfm_stats.pfm_recorded_samples_count);
-	p += sprintf(p, "smpl buffer full : %lu\n", pfm_stats.pfm_full_smpl_buffer_count);
+	p += sprintf(p, "fastctxsw              : %s\n", pfm_sysctl.fastctxsw > 0 ? "Yes": "No");
+	p += sprintf(p, "ovfl_mask              : 0x%lx\n", pmu_conf.ovfl_val);
 
-#ifdef CONFIG_SMP
-	p += sprintf(p, "CPU%d syst_wide   : %d\n"
-			"CPU%d dcr_pp      : %d\n", 
-			smp_processor_id(), 
-			local_cpu_data->pfm_syst_wide, 
-			smp_processor_id(), 
-			local_cpu_data->pfm_dcr_pp);
-#endif
+	for(i=0; i < NR_CPUS; i++) {
+		if (cpu_is_online(i) == 0) continue;
+		p += sprintf(p, "CPU%-2d overflow intrs   : %lu\n", i, pfm_stats[i].pfm_ovfl_intr_count);
+		p += sprintf(p, "CPU%-2d spurious intrs   : %lu\n", i, pfm_stats[i].pfm_spurious_ovfl_intr_count);
+		p += sprintf(p, "CPU%-2d recorded samples : %lu\n", i, pfm_stats[i].pfm_recorded_samples_count);
+		p += sprintf(p, "CPU%-2d smpl buffer full : %lu\n", i, pfm_stats[i].pfm_full_smpl_buffer_count);
+		p += sprintf(p, "CPU%-2d syst_wide        : %d\n", i, cpu_data(i)->pfm_syst_info & PFM_CPUINFO_SYST_WIDE ? 1 : 0);
+		p += sprintf(p, "CPU%-2d dcr_pp           : %d\n", i, cpu_data(i)->pfm_syst_info & PFM_CPUINFO_DCR_PP ? 1 : 0);
+		p += sprintf(p, "CPU%-2d exclude idle     : %d\n", i, cpu_data(i)->pfm_syst_info & PFM_CPUINFO_EXCL_IDLE ? 1 : 0);
+		p += sprintf(p, "CPU%-2d owner            : %d\n", i, pmu_owners[i].owner ? pmu_owners[i].owner->pid: -1);
+	}
 
 	LOCK_PFS();
-	p += sprintf(p, "proc_sessions    : %lu\n"
-			"sys_sessions     : %lu\n"
-			"sys_use_dbregs   : %lu\n"
-			"ptrace_use_dbregs: %lu\n", 
+
+	p += sprintf(p, "proc_sessions          : %u\n"
+			"sys_sessions           : %u\n"
+			"sys_use_dbregs         : %u\n"
+			"ptrace_use_dbregs      : %u\n", 
 			pfm_sessions.pfs_task_sessions, 
 			pfm_sessions.pfs_sys_sessions,
 			pfm_sessions.pfs_sys_use_dbregs,
@@ -3039,30 +3182,6 @@
 
 	UNLOCK_PFS();
 
-	for(i=0; i < NR_CPUS; i++) {
-		if (cpu_is_online(i)) {
-			p += sprintf(p, "CPU%d owner : %-6d\n",
-					i, 
-					pmu_owners[i].owner ? pmu_owners[i].owner->pid: -1);
-		}
-	}
-
-	for(i=0; pmd_desc[i].type != PFM_REG_NONE; i++) {
-		p += sprintf(p, "PMD%-2d: %d 0x%lx 0x%lx\n", 
-				i,
-				pmd_desc[i].type, 
-				pmd_desc[i].dep_pmd[0], 
-				pmd_desc[i].dep_pmc[0]); 
-	}
-
-	for(i=0; pmc_desc[i].type != PFM_REG_NONE; i++) {
-		p += sprintf(p, "PMC%-2d: %d 0x%lx 0x%lx\n", 
-				i, 
-				pmc_desc[i].type, 
-				pmc_desc[i].dep_pmd[0], 
-				pmc_desc[i].dep_pmc[0]); 
-	}
-
 	return p - page;
 }
 
@@ -3070,7 +3189,7 @@
 static int
 perfmon_read_entry(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
-	int len = perfmon_proc_info(page);
+	int len = pfm_proc_info(page);
 
 	if (len <= off+count) *eof = 1;
 
@@ -3083,21 +3202,60 @@
 	return len;
 }
 
-#ifdef CONFIG_SMP
+/*
+ * we come here as soon as local_cpu_data->pfm_syst_wide is set. this happens
+ * during pfm_enable() hence before pfm_start(). We cannot assume monitoring
+ * is active or inactive based on mode. We must rely on the value in 
+ * local_cpu_data->pfm_syst_info
+ */
 void
-pfm_syst_wide_update_task(struct task_struct *task, int mode)
+pfm_syst_wide_update_task(struct task_struct *task, unsigned long info, int is_ctxswin)
 {
-	struct pt_regs *regs = (struct pt_regs *)((unsigned long) task + IA64_STK_OFFSET);
+	struct pt_regs *regs;
+	unsigned long dcr;
+	unsigned long dcr_pp;
 
-	regs--;
+	dcr_pp = info & PFM_CPUINFO_DCR_PP ? 1 : 0;
 
 	/*
-	 * propagate the value of the dcr_pp bit to the psr
+	 * pid 0 is guaranteed to be the idle task. There is one such task with pid 0 
+	 * on every CPU, so we can rely on the pid to identify the idle task.
 	 */
-	ia64_psr(regs)->pp = mode ? local_cpu_data->pfm_dcr_pp : 0;
+	if ((info & PFM_CPUINFO_EXCL_IDLE) == 0 || task->pid) {
+		regs = (struct pt_regs *)((unsigned long) task + IA64_STK_OFFSET);
+		regs--;
+		ia64_psr(regs)->pp = is_ctxswin ? dcr_pp : 0;
+		return;
+	}
+	/*
+	 * we are the idle task  and there is exclusion.
+	 *
+	 * if monitoring has started
+	 */
+	if (dcr_pp) {
+		dcr = ia64_get_dcr();
+		/* 
+		 * context switching in? 
+		 */
+		if (is_ctxswin) {
+			/* mask monitoring for the idle task */
+			ia64_set_dcr(dcr & ~IA64_DCR_PP);
+			pfm_clear_psr_pp();
+			ia64_srlz_i();
+			return;
+		}
+		/* 
+		 * context switching out
+		 * restore normal kernel level settings 
+		 *
+		 * Due to inlining this odd if-then-else construction generates 
+		 * better code.
+	         */
+		ia64_set_dcr(dcr |IA64_DCR_PP);
+		pfm_set_psr_pp();
+		ia64_srlz_i();
+	}
 }
-#endif
-
 
 void
 pfm_save_regs (struct task_struct *task)
@@ -3107,11 +3265,10 @@
 
 	ctx = task->thread.pfm_context;
 
-
 	/*
 	 * save current PSR: needed because we modify it
 	 */
-	__asm__ __volatile__ ("mov %0=psr;;": "=r"(psr) :: "memory");
+	psr = pfm_get_psr();
 
 	/*
 	 * stop monitoring:
@@ -3120,7 +3277,7 @@
 	 * We do not need to set psr.sp because, it is irrelevant in kernel.
 	 * It will be restored from ipsr when going back to user level
 	 */
-	__asm__ __volatile__ ("rum psr.up;;"::: "memory");
+	pfm_clear_psr_up();
 	ia64_srlz_i();
 
 	ctx->ctx_saved_psr = psr;
@@ -3371,7 +3528,7 @@
 				atomic_read(&ctx->ctx_last_cpu), task->pid));
 
 		psr = ctx->ctx_saved_psr;
-		__asm__ __volatile__ ("mov psr.l=%0;; srlz.i;;"::"r"(psr): "memory");
+		pfm_set_psr_l(psr);
 
 		return;
 	}
@@ -3409,7 +3566,7 @@
 	 */
 	mask = pfm_sysctl.fastctxsw || ctx->ctx_fl_protected ?  ctx->ctx_used_pmds[0] : ctx->ctx_reload_pmds[0];
 	for (i=0; mask; i++, mask>>=1) {
-		if (mask & 0x1) ia64_set_pmd(i, t->pmd[i] & pmu_conf.perf_ovfl_val);
+		if (mask & 0x1) ia64_set_pmd(i, t->pmd[i] & pmu_conf.ovfl_val);
 	}
 
 	/* 
@@ -3433,8 +3590,7 @@
 	 * fl_frozen==1 when we are in blocking mode waiting for restart
 	 */
 	if (ctx->ctx_fl_frozen == 0) {
-		ia64_set_pmc(0, 0);
-		ia64_srlz_d();
+		pfm_unfreeze_pmu();
 	}
 	atomic_set(&ctx->ctx_last_cpu, smp_processor_id());
 
@@ -3444,55 +3600,51 @@
 	 * restore the psr we changed in pfm_save_regs()
 	 */
 	psr = ctx->ctx_saved_psr;
-	__asm__ __volatile__ ("mov psr.l=%0;; srlz.i;;"::"r"(psr): "memory");
-
+	pfm_set_psr_l(psr);
 }
 
 /*
  * XXX: make this routine able to work with non current context
  */
 static void
-ia64_reset_pmu(struct task_struct *task)
+pfm_reset_pmu(struct task_struct *task)
 {
 	struct thread_struct *t = &task->thread;
 	pfm_context_t *ctx = t->pfm_context;
-	unsigned long mask;
 	int i;
 
 	if (task != current) {
-		printk("perfmon: invalid task in ia64_reset_pmu()\n");
+		printk("perfmon: invalid task in pfm_reset_pmu()\n");
 		return;
 	}
 
 	/* Let's make sure the PMU is frozen */
-	ia64_set_pmc(0,1);
+	pfm_freeze_pmu();
 
 	/*
 	 * install reset values for PMC. We skip PMC0 (done above)
 	 * XX: good up to 64 PMCS
 	 */
-	mask = pmu_conf.impl_regs[0] >> 1;
-	for(i=1; mask; mask>>=1, i++) {
-		if (mask & 0x1) {
-			ia64_set_pmc(i, reset_pmcs[i]);
-			/*
-			 * When restoring context, we must restore ALL pmcs, even the ones 
-			 * that the task does not use to avoid leaks and possibly corruption
-			 * of the sesion because of configuration conflicts. So here, we 
-			 * initialize the entire set used in the context switch restore routine.
-	 		 */
-			t->pmc[i] = reset_pmcs[i];
-			DBprintk((" pmc[%d]=0x%lx\n", i, reset_pmcs[i]));
-						 
-		}
+	for (i=1; (pmu_conf.pmc_desc[i].type & PFM_REG_END) == 0; i++) {
+		if ((pmu_conf.pmc_desc[i].type & PFM_REG_IMPL) == 0) continue;
+		ia64_set_pmc(i, PMC_DFL_VAL(i));
+		/*
+		 * When restoring context, we must restore ALL pmcs, even the ones 
+		 * that the task does not use to avoid leaks and possibly corruption
+		 * of the sesion because of configuration conflicts. So here, we 
+		 * initialize the entire set used in the context switch restore routine.
+	 	 */
+		t->pmc[i] = PMC_DFL_VAL(i);
+		DBprintk(("pmc[%d]=0x%lx\n", i, t->pmc[i]));
 	}
+
 	/*
 	 * clear reset values for PMD. 
-	 * XXX: good up to 64 PMDS. Suppose that zero is a valid value.
+	 * XXX: good up to 64 PMDS.
 	 */
-	mask = pmu_conf.impl_regs[4];
-	for(i=0; mask; mask>>=1, i++) {
-		if (mask & 0x1) ia64_set_pmd(i, 0UL);
+	for (i=0; (pmu_conf.pmd_desc[i].type & PFM_REG_END) == 0; i++) {
+		if ((pmu_conf.pmd_desc[i].type & PFM_REG_IMPL) == 0) continue;
+		ia64_set_pmd(i, 0UL);
 		t->pmd[i] = 0UL;
 	}
 
@@ -3521,13 +3673,13 @@
 	  *
 	  * We never directly restore PMC0 so we do not include it in the mask.
 	  */
-	ctx->ctx_reload_pmcs[0] = pmu_conf.impl_regs[0] & ~0x1;
+	ctx->ctx_reload_pmcs[0] = pmu_conf.impl_pmcs[0] & ~0x1;
 	/*
 	 * We must include all the PMD in this mask to avoid picking
 	 * up stale value and leak information, especially directly
 	 * at the user level when psr.sp=0
 	 */
-	ctx->ctx_reload_pmds[0] = pmu_conf.impl_regs[4];
+	ctx->ctx_reload_pmds[0] = pmu_conf.impl_pmds[0];
 
 	/* 
 	 * Keep track of the pmds we want to sample
@@ -3537,7 +3689,7 @@
 	 *
 	 * We ignore the unimplemented pmds specified by the user
 	 */
-	ctx->ctx_used_pmds[0] = ctx->ctx_smpl_regs[0] & pmu_conf.impl_regs[4];
+	ctx->ctx_used_pmds[0] = ctx->ctx_smpl_regs[0];
 	ctx->ctx_used_pmcs[0] = 1; /* always save/restore PMC[0] */
 
 	/*
@@ -3586,26 +3738,20 @@
 	 */
 	if (ctx->ctx_fl_system) {
 
-
 		/* disable dcr pp */
 		ia64_set_dcr(ia64_get_dcr() & ~IA64_DCR_PP);
 
 		/* stop monitoring */
-		__asm__ __volatile__ ("rsm psr.pp;;"::: "memory");
-
+		pfm_clear_psr_pp();
 		ia64_srlz_i();
 
-#ifdef CONFIG_SMP
-		local_cpu_data->pfm_syst_wide = 0;
-		local_cpu_data->pfm_dcr_pp    = 0;
-#else
-		pfm_tasklist_toggle_pp(0);
-#endif
+		PFM_CPUINFO_CLEAR(PFM_CPUINFO_SYST_WIDE);
+		PFM_CPUINFO_CLEAR(PFM_CPUINFO_DCR_PP);
+		PFM_CPUINFO_CLEAR(PFM_CPUINFO_EXCL_IDLE);
 	} else  {
 
 		/* stop monitoring */
-		__asm__ __volatile__ ("rum psr.up;;"::: "memory");
-
+		pfm_clear_psr_up();
 		ia64_srlz_i();
 
 		/* no more save/restore on ctxsw */
@@ -3637,8 +3783,7 @@
 	 * This destroys the overflow information. This is required to make sure
 	 * next process does not start with monitoring on if not requested
 	 */
-	ia64_set_pmc(0, 1);
-	ia64_srlz_d();
+	pfm_freeze_pmu();
 
 	/*
 	 * We don't need to restore psr, because we are on our way out
@@ -3670,10 +3815,14 @@
 		val = ia64_get_pmd(i);
 
 		if (PMD_IS_COUNTING(i)) {
-			DBprintk(("[%d] pmd[%d] soft_pmd=0x%lx hw_pmd=0x%lx\n", task->pid, i, ctx->ctx_soft_pmds[i].val, val & pmu_conf.perf_ovfl_val));
+			DBprintk(("[%d] pmd[%d] soft_pmd=0x%lx hw_pmd=0x%lx\n", 
+				task->pid, 
+				i, 
+				ctx->ctx_soft_pmds[i].val, 
+				val & pmu_conf.ovfl_val));
 
 			/* collect latest results */
-			ctx->ctx_soft_pmds[i].val += val & pmu_conf.perf_ovfl_val;
+			ctx->ctx_soft_pmds[i].val += val & pmu_conf.ovfl_val;
 
 			/*
 			 * now everything is in ctx_soft_pmds[] and we need
@@ -3686,7 +3835,7 @@
 			 * take care of overflow inline
 			 */
 			if (pmc0 & (1UL << i)) {
-				ctx->ctx_soft_pmds[i].val += 1 + pmu_conf.perf_ovfl_val;
+				ctx->ctx_soft_pmds[i].val += 1 + pmu_conf.ovfl_val;
 				DBprintk(("[%d] pmd[%d] overflowed soft_pmd=0x%lx\n",
 					task->pid, i, ctx->ctx_soft_pmds[i].val));
 			}
@@ -3820,18 +3969,12 @@
 	m = nctx->ctx_used_pmds[0] >> PMU_FIRST_COUNTER;
 	for(i = PMU_FIRST_COUNTER ; m ; m>>=1, i++) {
 		if ((m & 0x1) && pmu_conf.pmd_desc[i].type == PFM_REG_COUNTING) {
-			nctx->ctx_soft_pmds[i].val = nctx->ctx_soft_pmds[i].ival & ~pmu_conf.perf_ovfl_val;
-			thread->pmd[i]	      	   = nctx->ctx_soft_pmds[i].ival & pmu_conf.perf_ovfl_val;
+			nctx->ctx_soft_pmds[i].val = nctx->ctx_soft_pmds[i].lval & ~pmu_conf.ovfl_val;
+			thread->pmd[i]	      	   = nctx->ctx_soft_pmds[i].lval & pmu_conf.ovfl_val;
+		} else {
+			thread->pmd[i]	      	   = 0UL; /* reset to initial state */
 		}
-		/* what about the other pmds? zero or keep as is */
-
 	}
-	/*
-	 * clear BTB index register
-	 * XXX: CPU-model specific knowledge!
-	 */
-	thread->pmd[16] = 0;
-
 
 	nctx->ctx_fl_frozen    = 0;
 	nctx->ctx_ovfl_regs[0] = 0UL;
@@ -3866,6 +4009,11 @@
 
 	sema_init(&nctx->ctx_restart_sem, 0); /* reset this semaphore to locked */
 
+	/*
+	 * propagate kernel psr in new context (used for first ctxsw in
+	 */
+	nctx->ctx_saved_psr = pfm_get_psr();
+
 	/* link with new task */
 	thread->pfm_context = nctx;
 
@@ -3994,31 +4142,15 @@
 
 	UNLOCK_CTX(ctx);
 
-	LOCK_PFS();
+	pfm_unreserve_session(task, ctx->ctx_fl_system, 1UL << ctx->ctx_cpu);
 
 	if (ctx->ctx_fl_system) {
-
-		pfm_sessions.pfs_sys_session[ctx->ctx_cpu] = NULL;
-		pfm_sessions.pfs_sys_sessions--;
-		DBprintk(("freeing syswide session on CPU%ld\n", ctx->ctx_cpu));
-
-		/* update perfmon debug register usage counter */
-		if (ctx->ctx_fl_using_dbreg) {
-			if (pfm_sessions.pfs_sys_use_dbregs == 0) {
-				printk("perfmon: invalid release for [%d] sys_use_dbregs=0\n", task->pid);
-			} else
-				pfm_sessions.pfs_sys_use_dbregs--;
-		}
-
 		/*
 	 	 * remove any CPU pinning
 	 	 */
 		task->cpus_allowed = ctx->ctx_saved_cpus_allowed;
 		task->need_resched = 1;
-	} else {
-		pfm_sessions.pfs_task_sessions--;
-	}
-	UNLOCK_PFS();
+	} 
 
 	pfm_context_free(ctx);
 	/* 
@@ -4178,125 +4310,165 @@
 }
 
 static struct irqaction perfmon_irqaction = {
-	handler:	perfmon_interrupt,
-	flags:		SA_INTERRUPT,
-	name:		"perfmon"
+	.handler = pfm_interrupt_handler,
+	.flags   = SA_INTERRUPT,
+	.name    = "perfmon"
 };
 
-
-static void
-pfm_pmu_snapshot(void)
+int
+pfm_install_alternate_syswide_subsystem(pfm_intr_handler_desc_t *hdl)
 {
-	int i;
+	int ret;
+
+	/* some sanity checks */
+	if (hdl == NULL || hdl->handler == NULL) return -EINVAL;
+
+	/* do the easy test first */
+	if (pfm_alternate_intr_handler) return -EBUSY;
 
-	for (i=0; i < IA64_NUM_PMC_REGS; i++) {
-		if (i >= pmu_conf.num_pmcs) break;
-		if (PMC_IS_IMPL(i)) reset_pmcs[i] = ia64_get_pmc(i);
+	/* reserve our session */
+	ret = pfm_reserve_session(NULL, 1, cpu_online_map);
+	if (ret) return ret;
+
+	if (pfm_alternate_intr_handler) {
+		printk("perfmon: install_alternate, intr_handler not NULL after reserve\n");
+		return -EINVAL;
 	}
-#ifdef CONFIG_MCKINLEY
-	/*
-	 * set the 'stupid' enable bit to power the PMU!
+
+	pfm_alternate_intr_handler = hdl;
+
+	return 0;
+}
+
+int
+pfm_remove_alternate_syswide_subsystem(pfm_intr_handler_desc_t *hdl)
+{
+	if (hdl == NULL) return -EINVAL;
+
+	/* cannot remove someone else's handler! */
+	if (pfm_alternate_intr_handler != hdl) return -EINVAL;
+
+	pfm_alternate_intr_handler = NULL;
+
+	/* 
+	 * XXX: assume cpu_online_map has not changed since reservation 
 	 */
-	reset_pmcs[4] |= 1UL << 23;
-#endif
+	pfm_unreserve_session(NULL, 1, cpu_online_map);
+
+	return 0;
 }
 
 /*
  * perfmon initialization routine, called from the initcall() table
  */
 int __init
-perfmon_init (void)
+pfm_init(void)
 {
-	pal_perf_mon_info_u_t pm_info;
-	s64 status;
+	unsigned int n, n_counters, i;
 
-	pmu_conf.pfm_is_disabled = 1;
+	pmu_conf.disabled = 1;
 
-	printk("perfmon: version %u.%u (sampling format v%u.%u) IRQ %u\n", 
+	printk("perfmon: version %u.%u IRQ %u\n", 
 		PFM_VERSION_MAJ, 
 		PFM_VERSION_MIN, 
-		PFM_SMPL_VERSION_MAJ, 
-		PFM_SMPL_VERSION_MIN, 
 		IA64_PERFMON_VECTOR);
 
-	if ((status=ia64_pal_perf_mon_info(pmu_conf.impl_regs, &pm_info)) != 0) {
-		printk("perfmon: PAL call failed (%ld), perfmon disabled\n", status);
-		return -1;
-	}
-
-	pmu_conf.perf_ovfl_val = (1UL << pm_info.pal_perf_mon_info_s.width) - 1;
-	pmu_conf.max_counters  = pm_info.pal_perf_mon_info_s.generic;
-	pmu_conf.num_pmcs      = find_num_pm_regs(pmu_conf.impl_regs);
-	pmu_conf.num_pmds      = find_num_pm_regs(&pmu_conf.impl_regs[4]);
-
-	printk("perfmon: %u bits counters\n", pm_info.pal_perf_mon_info_s.width);
-
-	printk("perfmon: %lu PMC/PMD pairs, %lu PMCs, %lu PMDs\n", 
-	       pmu_conf.max_counters, pmu_conf.num_pmcs, pmu_conf.num_pmds);
+	/*
+	 * compute the number of implemented PMD/PMC from the
+	 * description tables
+	 */
+	n = 0;
+	for (i=0; PMC_IS_LAST(i) == 0;  i++) {
+		if (PMC_IS_IMPL(i) == 0) continue;
+		pmu_conf.impl_pmcs[i>>6] |= 1UL << (i&63);
+		n++;
+	}
+	pmu_conf.num_pmcs = n;
+
+	n = 0; n_counters = 0;
+	for (i=0; PMD_IS_LAST(i) == 0;  i++) {
+		if (PMD_IS_IMPL(i) == 0) continue;
+		pmu_conf.impl_pmds[i>>6] |= 1UL << (i&63);
+		n++;
+		if (PMD_IS_COUNTING(i)) n_counters++;
+	}
+	pmu_conf.num_pmds      = n;
+	pmu_conf.num_counters  = n_counters;
+
+	printk("perfmon: %u PMCs, %u PMDs, %u counters (%lu bits)\n", 
+	       pmu_conf.num_pmcs, 
+	       pmu_conf.num_pmds,
+	       pmu_conf.num_counters,
+	       ffz(pmu_conf.ovfl_val));
 
 	/* sanity check */
 	if (pmu_conf.num_pmds >= IA64_NUM_PMD_REGS || pmu_conf.num_pmcs >= IA64_NUM_PMC_REGS) {
-		printk(KERN_ERR "perfmon: not enough pmc/pmd, perfmon is DISABLED\n");
-		return -1; /* no need to continue anyway */
-	}
-
-	if (ia64_pal_debug_info(&pmu_conf.num_ibrs, &pmu_conf.num_dbrs)) {
-		printk(KERN_WARNING "perfmon: unable to get number of debug registers\n");
-		pmu_conf.num_ibrs = pmu_conf.num_dbrs = 0;
+		printk(KERN_ERR "perfmon: not enough pmc/pmd, perfmon disabled\n");
+		return -1;
 	}
-	/* PAL reports the number of pairs */
-	pmu_conf.num_ibrs <<=1;
-	pmu_conf.num_dbrs <<=1;
 
 	/*
-	 * take a snapshot of all PMU registers. PAL is supposed
-	 * to configure them with stable/safe values, i.e., not
-	 * capturing anything.
-	 * We take a snapshot now, before we make any modifications. This
-	 * will become our master copy. Then we will reuse the snapshot
-	 * to reset the PMU in pfm_enable(). Using this technique, perfmon
-	 * does NOT have to know about the specific values to program for
-	 * the PMC/PMD. The safe values may be different from one CPU model to
-	 * the other.
+	 * for now here for debug purposes
 	 */
-	pfm_pmu_snapshot();
+	perfmon_dir = create_proc_read_entry ("perfmon", 0, 0, perfmon_read_entry, NULL);
+	if (perfmon_dir == NULL) {
+		printk(KERN_ERR "perfmon: cannot create /proc entry, perfmon disabled\n");
+		return -1; 
+	}
 
 	/*
-	 * setup the register configuration descriptions for the CPU
+	 * create /proc/sys/kernel/perfmon
 	 */
-	pmu_conf.pmc_desc = pmc_desc;
-	pmu_conf.pmd_desc = pmd_desc;
-
-	/* we are all set */
-	pmu_conf.pfm_is_disabled = 0;
+	pfm_sysctl_header = register_sysctl_table(pfm_sysctl_root, 0);
 
 	/*
-	 * for now here for debug purposes
+	 * initialize all our spinlocks
 	 */
-	perfmon_dir = create_proc_read_entry ("perfmon", 0, 0, perfmon_read_entry, NULL);
-
-	pfm_sysctl_header = register_sysctl_table(pfm_sysctl_root, 0);
-
 	spin_lock_init(&pfm_sessions.pfs_lock);
 
+	/* we are all set */
+	pmu_conf.disabled = 0;
+
 	return 0;
 }
 
-__initcall(perfmon_init);
+__initcall(pfm_init);
 
 void
-perfmon_init_percpu (void)
+pfm_init_percpu(void)
 {
+	int i;
+
 	if (smp_processor_id() == 0)
 		register_percpu_irq(IA64_PERFMON_VECTOR, &perfmon_irqaction);
 
 	ia64_set_pmv(IA64_PERFMON_VECTOR);
 	ia64_srlz_d();
+
+	/*
+	 * we first initialize the PMU to a stable state.
+	 * the values may have been changed from their power-up
+	 * values by software executed before the kernel took over.
+	 *
+	 * At this point, pmu_conf has not yet been initialized
+	 *
+	 * On McKinley, this code is ineffective until PMC4 is initialized.
+	 */
+	for (i=1; PMC_IS_LAST(i) == 0;  i++) {
+		if (PMC_IS_IMPL(i) == 0) continue;
+		ia64_set_pmc(i, PMC_DFL_VAL(i));
+	}
+
+	for (i=0; PMD_IS_LAST(i); i++) {
+		if (PMD_IS_IMPL(i) == 0) continue;
+		ia64_set_pmd(i, 0UL);
+	}
+	pfm_freeze_pmu();
 }
 
 #else /* !CONFIG_PERFMON */
 
-asmlinkage int
+asmlinkage long
 sys_perfmonctl (int pid, int cmd, void *req, int count, long arg5, long arg6, 
 		long arg7, long arg8, long stack)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/perfmon_generic.h linux-2.4.21-pre6/arch/ia64/kernel/perfmon_generic.h
--- linux-2.4.20/arch/ia64/kernel/perfmon_generic.h	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/kernel/perfmon_generic.h	2003-03-26 23:49:00.000000000 +0000
@@ -1,29 +1,48 @@
+/*
+ * This file contains the architected PMU register description tables
+ * and pmc checker used by perfmon.c.
+ *
+ * Copyright (C) 2002  Hewlett Packard Co
+ *               Stephane Eranian <eranian@hpl.hp.com>
+ */
 #define RDEP(x)	(1UL<<(x))
 
-#ifdef CONFIG_ITANIUM
-#error "This file should not be used when CONFIG_ITANIUM is defined"
+#if defined(CONFIG_ITANIUM) || defined (CONFIG_MCKINLEY)
+#error "This file should not be used when CONFIG_ITANIUM or CONFIG_MCKINLEY is defined"
 #endif
 
-static pfm_reg_desc_t pmc_desc[256]={
-/* pmc0  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc1  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc2  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc3  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc4  */ { PFM_REG_COUNTING, 0, NULL, NULL, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc5  */ { PFM_REG_COUNTING, 0, NULL, NULL, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc6  */ { PFM_REG_COUNTING, 0, NULL, NULL, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc7  */ { PFM_REG_COUNTING, 0, NULL, NULL, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-	    { PFM_REG_NONE, 0, NULL, NULL, {0,}, {0,}}, /* end marker */
+static pfm_reg_desc_t pmc_gen_desc[PMU_MAX_PMCS]={
+/* pmc0  */ { PFM_REG_CONTROL , 0, 0x1UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc1  */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc2  */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc3  */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc4  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc5  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc6  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc7  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+	    { PFM_REG_END     , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */
 };
 
-static pfm_reg_desc_t pmd_desc[256]={
-/* pmd0  */ { PFM_REG_NOTIMPL, 0, NULL, NULL, {0,}, {0,}},
-/* pmd1  */ { PFM_REG_NOTIMPL, 0, NULL, NULL, {0,}, {0,}},
-/* pmd2  */ { PFM_REG_NOTIMPL, 0, NULL, NULL, {0,}, {0,}},
-/* pmd3  */ { PFM_REG_NOTIMPL, 0, NULL, NULL, {0,}, {0,}},
-/* pmd4  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}},
-/* pmd5  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}},
-/* pmd6  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}},
-/* pmd7  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}},
-	    { PFM_REG_NONE, 0, NULL, NULL, {0,}, {0,}}, /* end marker */
+static pfm_reg_desc_t pmd_gen_desc[PMU_MAX_PMDS]={
+/* pmd0  */ { PFM_REG_NOTIMPL , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}},
+/* pmd1  */ { PFM_REG_NOTIMPL , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}},
+/* pmd2  */ { PFM_REG_NOTIMPL , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}},
+/* pmd3  */ { PFM_REG_NOTIMPL , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}},
+/* pmd4  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}},
+/* pmd5  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}},
+/* pmd6  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}},
+/* pmd7  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}},
+	    { PFM_REG_END     , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */
+};
+
+/*
+ * impl_pmcs, impl_pmds are computed at runtime to minimize errors!
+ */
+static pmu_config_t pmu_conf={
+	disabled:	1,
+	ovfl_val:	(1UL << 32) - 1,
+	num_ibrs:	8,
+	num_dbrs:	8,
+	pmd_desc:	pfm_gen_pmd_desc,
+	pmc_desc:	pfm_gen_pmc_desc
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/perfmon_itanium.h linux-2.4.21-pre6/arch/ia64/kernel/perfmon_itanium.h
--- linux-2.4.20/arch/ia64/kernel/perfmon_itanium.h	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/kernel/perfmon_itanium.h	2003-03-26 23:48:57.000000000 +0000
@@ -15,46 +15,59 @@
 static int pfm_ita_pmc_check(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs);
 static int pfm_write_ibr_dbr(int mode, struct task_struct *task, void *arg, int count, struct pt_regs *regs);
 
-static pfm_reg_desc_t pmc_desc[256]={
-/* pmc0  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc1  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc2  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc3  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc4  */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc5  */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc6  */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc7  */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc8  */ { PFM_REG_CONFIG, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc9  */ { PFM_REG_CONFIG, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc10 */ { PFM_REG_MONITOR, 6, NULL, NULL, {RDEP(0)|RDEP(1),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc11 */ { PFM_REG_MONITOR, 6, NULL, pfm_ita_pmc_check, {RDEP(2)|RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc12 */ { PFM_REG_MONITOR, 6, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc13 */ { PFM_REG_CONFIG, 0, NULL, pfm_ita_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-	    { PFM_REG_NONE, 0, NULL, NULL, {0,}, {0,}}, /* end marker */
+static pfm_reg_desc_t pfm_ita_pmc_desc[PMU_MAX_PMCS]={
+/* pmc0  */ { PFM_REG_CONTROL , 0, 0x1UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc1  */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc2  */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc3  */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc4  */ { PFM_REG_COUNTING, 6, 0x0UL, -1UL, NULL, NULL, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc5  */ { PFM_REG_COUNTING, 6, 0x0UL, -1UL, NULL, NULL, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc6  */ { PFM_REG_COUNTING, 6, 0x0UL, -1UL, NULL, NULL, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc7  */ { PFM_REG_COUNTING, 6, 0x0UL, -1UL, NULL, NULL, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc8  */ { PFM_REG_CONFIG  , 0, 0xf00000003ffffff8UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc9  */ { PFM_REG_CONFIG  , 0, 0xf00000003ffffff8UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc10 */ { PFM_REG_MONITOR , 6, 0x0UL, -1UL, NULL, NULL, {RDEP(0)|RDEP(1),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc11 */ { PFM_REG_MONITOR , 6, 0x0000000010000000UL, -1UL, NULL, pfm_ita_pmc_check, {RDEP(2)|RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc12 */ { PFM_REG_MONITOR , 6, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc13 */ { PFM_REG_CONFIG  , 0, 0x0003ffff00000001UL, -1UL, NULL, pfm_ita_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+	    { PFM_REG_END     , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */
 };
 
-static pfm_reg_desc_t pmd_desc[256]={
-/* pmd0  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(1),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
-/* pmd1  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(0),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
-/* pmd2  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
-/* pmd3  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(2)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
-/* pmd4  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}},
-/* pmd5  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}},
-/* pmd6  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}},
-/* pmd7  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}},
-/* pmd8  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd9  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd10 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd11 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd12 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd13 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd14 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd15 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd16 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd17 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(2)|RDEP(3),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
-	    { PFM_REG_NONE, 0, NULL, NULL, {0,}, {0,}}, /* end marker */
+static pfm_reg_desc_t pfm_ita_pmd_desc[PMU_MAX_PMDS]={
+/* pmd0  */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(1),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
+/* pmd1  */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(0),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
+/* pmd2  */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
+/* pmd3  */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(2)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
+/* pmd4  */ { PFM_REG_COUNTING, 0, 0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}},
+/* pmd5  */ { PFM_REG_COUNTING, 0, 0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}},
+/* pmd6  */ { PFM_REG_COUNTING, 0, 0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}},
+/* pmd7  */ { PFM_REG_COUNTING, 0, 0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}},
+/* pmd8  */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd9  */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd10 */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd11 */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd12 */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd13 */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd14 */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd15 */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd16 */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd17 */ { PFM_REG_BUFFER  , 0, 0UL, -1UL, NULL, NULL, {RDEP(2)|RDEP(3),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
+	    { PFM_REG_END     , 0, 0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */
 };
 
+/*
+ * impl_pmcs, impl_pmds are computed at runtime to minimize errors!
+ */
+static pmu_config_t pmu_conf={
+	disabled:	1,
+	ovfl_val:	(1UL << 32) - 1,
+	num_ibrs:	8,
+	num_dbrs:	8,
+	pmd_desc:	pfm_ita_pmd_desc,
+	pmc_desc:	pfm_ita_pmc_desc
+};
+
+
 static int
 pfm_ita_pmc_check(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/perfmon_mckinley.h linux-2.4.21-pre6/arch/ia64/kernel/perfmon_mckinley.h
--- linux-2.4.20/arch/ia64/kernel/perfmon_mckinley.h	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/kernel/perfmon_mckinley.h	2003-03-26 23:49:20.000000000 +0000
@@ -12,51 +12,86 @@
 #error "This file is only valid when CONFIG_MCKINLEY is defined"
 #endif
 
+static int pfm_mck_reserved(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs);
 static int pfm_mck_pmc_check(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs);
 static int pfm_write_ibr_dbr(int mode, struct task_struct *task, void *arg, int count, struct pt_regs *regs);
 
-static pfm_reg_desc_t pmc_desc[256]={
-/* pmc0  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc1  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc2  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc3  */ { PFM_REG_CONTROL, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc4  */ { PFM_REG_COUNTING, 6, NULL, pfm_mck_pmc_check, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc5  */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc6  */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc7  */ { PFM_REG_COUNTING, 6, NULL, NULL, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc8  */ { PFM_REG_CONFIG, 0, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc9  */ { PFM_REG_CONFIG, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc10 */ { PFM_REG_MONITOR, 4, NULL, NULL, {RDEP(0)|RDEP(1),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc11 */ { PFM_REG_MONITOR, 6, NULL, NULL, {RDEP(2)|RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc12 */ { PFM_REG_MONITOR, 6, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc13 */ { PFM_REG_CONFIG, 0, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc14 */ { PFM_REG_CONFIG, 0, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc15 */ { PFM_REG_CONFIG, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-	    { PFM_REG_NONE, 0, NULL, NULL, {0,}, {0,}}, /* end marker */
+static pfm_reg_desc_t pfm_mck_pmc_desc[PMU_MAX_PMCS]={
+/* pmc0  */ { PFM_REG_CONTROL , 0, 0x1UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc1  */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc2  */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc3  */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc4  */ { PFM_REG_COUNTING, 6, 0x0000000000800000UL, 0xfffff7fUL, NULL, pfm_mck_pmc_check, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc5  */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL,  pfm_mck_reserved, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc6  */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL,  pfm_mck_reserved, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc7  */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL,  pfm_mck_reserved, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc8  */ { PFM_REG_CONFIG  , 0, 0xffffffff3fffffffUL, 0xffffffff9fffffffUL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc9  */ { PFM_REG_CONFIG  , 0, 0xffffffff3ffffffcUL, 0xffffffff9fffffffUL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc10 */ { PFM_REG_MONITOR , 4, 0x0UL, 0xffffUL, NULL, pfm_mck_reserved, {RDEP(0)|RDEP(1),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc11 */ { PFM_REG_MONITOR , 6, 0x0UL, 0x30f01cf, NULL,  pfm_mck_reserved, {RDEP(2)|RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc12 */ { PFM_REG_MONITOR , 6, 0x0UL, 0xffffUL, NULL,  pfm_mck_reserved, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc13 */ { PFM_REG_CONFIG  , 0, 0x00002078fefefefeUL, 0x1e00018181818UL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc14 */ { PFM_REG_CONFIG  , 0, 0x0db60db60db60db6UL, 0x2492UL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc15 */ { PFM_REG_CONFIG  , 0, 0x00000000fffffff0UL, 0xfUL, NULL, pfm_mck_reserved, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+	    { PFM_REG_END     , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */
 };
 
-static pfm_reg_desc_t pmd_desc[256]={
-/* pmd0  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(1),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
-/* pmd1  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(0),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
-/* pmd2  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
-/* pmd3  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(2)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
-/* pmd4  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}},
-/* pmd5  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}},
-/* pmd6  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}},
-/* pmd7  */ { PFM_REG_COUNTING, 0, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}},
-/* pmd8  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd9  */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd10 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd11 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd12 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd13 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd14 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd15 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd16 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
-/* pmd17 */ { PFM_REG_BUFFER, 0, NULL, NULL, {RDEP(2)|RDEP(3),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
-	    { PFM_REG_NONE, 0, NULL, NULL, {0,}, {0,}}, /* end marker */
+static pfm_reg_desc_t pfm_mck_pmd_desc[PMU_MAX_PMDS]={
+/* pmd0  */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(1),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
+/* pmd1  */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(0),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
+/* pmd2  */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
+/* pmd3  */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(2)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
+/* pmd4  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}},
+/* pmd5  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}},
+/* pmd6  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}},
+/* pmd7  */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}},
+/* pmd8  */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd9  */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd10 */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd11 */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd12 */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd13 */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd14 */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd15 */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd16 */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+/* pmd17 */ { PFM_REG_BUFFER  , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(2)|RDEP(3),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
+	    { PFM_REG_END     , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */
 };
 
+/*
+ * impl_pmcs, impl_pmds are computed at runtime to minimize errors!
+ */
+static pmu_config_t pmu_conf={
+	disabled:	1,
+	ovfl_val:	(1UL << 47) - 1,
+	num_ibrs:	8,
+	num_dbrs:	8,
+	pmd_desc:	pfm_mck_pmd_desc,
+	pmc_desc:	pfm_mck_pmc_desc
+};
+
+
+/*
+ * PMC reserved fields must have their power-up values preserved
+ */
+static int
+pfm_mck_reserved(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs)
+{
+	unsigned long tmp1, tmp2, ival = *val;
+
+	/* remove reserved areas from user value */
+	tmp1 = ival & PMC_RSVD_MASK(cnum);
+
+	/* get reserved fields values */
+	tmp2 = PMC_DFL_VAL(cnum) & ~PMC_RSVD_MASK(cnum);
+
+	*val = tmp1 | tmp2;
+
+	DBprintk(("pmc[%d]=0x%lx, mask=0x%lx, reset=0x%lx, val=0x%lx\n", 
+		  cnum, ival, PMC_RSVD_MASK(cnum), PMC_DFL_VAL(cnum), *val)); 
+	return 0;
+}
+
 static int
 pfm_mck_pmc_check(struct task_struct *task, unsigned int cnum, unsigned long *val, struct pt_regs *regs)
 {
@@ -65,6 +100,9 @@
 	int ret = 0, check_case1 = 0;
 	unsigned long val8 = 0, val14 = 0, val13 = 0;
 
+	/* first preserve the reserved fields */
+	pfm_mck_reserved(task, cnum, val, regs);
+
 	/*
 	 * we must clear the debug registers if any pmc13.ena_dbrpX bit is enabled 
 	 * before they are written (fl_using_dbreg==0) to avoid picking up stale information. 
@@ -105,8 +143,11 @@
 		case  8: val8 = *val;
 			 val13 = th->pmc[13];
 			 val14 = th->pmc[14];
+			 *val |= 1UL << 2; /* bit 2 must always be 1 */
 			 check_case1 = 1;
 			 break;
+		case  9: *val |= 1UL << 2; /* bit 2 must always be 1 */
+			 break;
 		case 13: val8  = th->pmc[8];
 			 val13 = *val;
 			 val14 = th->pmc[14];
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/process.c linux-2.4.21-pre6/arch/ia64/kernel/process.c
--- linux-2.4.20/arch/ia64/kernel/process.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/kernel/process.c	2003-03-26 23:49:37.000000000 +0000
@@ -161,6 +161,10 @@
 void
 ia64_save_extra (struct task_struct *task)
 {
+#ifdef CONFIG_PERFMON
+	unsigned long info;
+#endif
+
 	if ((task->thread.flags & IA64_THREAD_DBG_VALID) != 0)
 		ia64_save_debug_regs(&task->thread.dbr[0]);
 
@@ -168,10 +172,9 @@
 	if ((task->thread.flags & IA64_THREAD_PM_VALID) != 0)
 		pfm_save_regs(task);
 
-# ifdef CONFIG_SMP
-	if (local_cpu_data->pfm_syst_wide)
-		pfm_syst_wide_update_task(task, 0);
-# endif
+	info = local_cpu_data->pfm_syst_info;
+	if (info & PFM_CPUINFO_SYST_WIDE)
+		pfm_syst_wide_update_task(task, info, 0);
 #endif
 
 #ifdef CONFIG_IA32_SUPPORT
@@ -183,6 +186,10 @@
 void
 ia64_load_extra (struct task_struct *task)
 {
+#ifdef CONFIG_PERFMON
+	unsigned long info;
+#endif
+
 	if ((task->thread.flags & IA64_THREAD_DBG_VALID) != 0)
 		ia64_load_debug_regs(&task->thread.dbr[0]);
 
@@ -190,10 +197,9 @@
 	if ((task->thread.flags & IA64_THREAD_PM_VALID) != 0)
 		pfm_load_regs(task);
 
-# ifdef CONFIG_SMP
-	if (local_cpu_data->pfm_syst_wide)
-		pfm_syst_wide_update_task(task, 1);
-# endif
+	info = local_cpu_data->pfm_syst_info;
+	if (info & PFM_CPUINFO_SYST_WIDE)
+		pfm_syst_wide_update_task(task, info, 1);
 #endif
 
 #ifdef CONFIG_IA32_SUPPORT
@@ -224,7 +230,7 @@
  *	|                     | <-- sp (lowest addr)
  *	+---------------------+
  *
- * Note: if we get called through kernel_thread() then the memory
+ * Note: if we get called through arch_kernel_thread() then the memory
  * above "(highest addr)" is valid kernel stack memory that needs to
  * be copied as well.
  *
@@ -479,7 +485,7 @@
 }
 
 pid_t
-kernel_thread (int (*fn)(void *), void *arg, unsigned long flags)
+arch_kernel_thread (int (*fn)(void *), void *arg, unsigned long flags)
 {
 	struct task_struct *parent = current;
 	int result, tid;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/ptrace.c linux-2.4.21-pre6/arch/ia64/kernel/ptrace.c
--- linux-2.4.20/arch/ia64/kernel/ptrace.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/kernel/ptrace.c	2003-03-26 23:49:55.000000000 +0000
@@ -10,6 +10,7 @@
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
@@ -459,6 +460,60 @@
 	pt->loadrs = 0;
 }
 
+static inline void
+sync_user_rbs_one_thread (struct task_struct *p, int make_writable)
+{
+	struct switch_stack *sw;
+	unsigned long urbs_end;
+	struct pt_regs *pt;
+
+	sw = (struct switch_stack *) (p->thread.ksp + 16);
+	pt = ia64_task_regs(p);
+	urbs_end = ia64_get_user_rbs_end(p, pt, NULL);
+	ia64_sync_user_rbs(p, sw, pt->ar_bspstore, urbs_end);
+	if (make_writable)
+		user_flushrs(p, pt);
+}
+
+struct task_list {
+	struct task_list *next;
+	struct task_struct *task;
+};
+
+#ifdef CONFIG_SMP
+
+static inline void
+collect_task (struct task_list **listp, struct task_struct *p, int make_writable)
+{
+	struct task_list *e;
+
+	e = kmalloc(sizeof(*e), GFP_KERNEL);
+	if (!e)
+		/* oops, can't collect more: finish at least what we collected so far... */
+		return;
+
+	get_task_struct(p);
+	e->task = p;
+	e->next = *listp;
+	*listp = e;
+}
+
+static inline struct task_list *
+finish_task (struct task_list *list, int make_writable)
+{
+	struct task_list *next = list->next;
+
+	sync_user_rbs_one_thread(list->task, make_writable);
+	free_task_struct(list->task);
+	kfree(list);
+	return next;
+}
+
+#else
+# define collect_task(list, p, make_writable)	sync_user_rbs_one_thread(p, make_writable)
+# define finish_task(list, make_writable)	(NULL)
+#endif
+
 /*
  * Synchronize the RSE backing store of CHILD and all tasks that share the address space
  * with it.  CHILD_URBS_END is the address of the end of the register backing store of
@@ -472,7 +527,6 @@
 threads_sync_user_rbs (struct task_struct *child, unsigned long child_urbs_end, int make_writable)
 {
 	struct switch_stack *sw;
-	unsigned long urbs_end;
 	struct task_struct *p;
 	struct mm_struct *mm;
 	struct pt_regs *pt;
@@ -492,20 +546,27 @@
 		if (make_writable)
 			user_flushrs(child, pt);
 	} else {
+		/*
+		 * Note: we can't call ia64_sync_user_rbs() while holding the
+		 * tasklist_lock because that may cause a dead-lock: ia64_sync_user_rbs()
+		 * may indirectly call tlb_flush_all(), which triggers an IPI.
+		 * Furthermore, tasklist_lock is acquired by fork() with interrupts
+		 * disabled, so with the right timing, the IPI never completes, hence
+		 * tasklist_lock never gets released, hence fork() never completes...
+		 */
+		struct task_list *list = NULL;
+
 		read_lock(&tasklist_lock);
 		{
 			for_each_task(p) {
-				if (p->mm == mm && p->state != TASK_RUNNING) {
-					sw = (struct switch_stack *) (p->thread.ksp + 16);
-					pt = ia64_task_regs(p);
-					urbs_end = ia64_get_user_rbs_end(p, pt, NULL);
-					ia64_sync_user_rbs(p, sw, pt->ar_bspstore, urbs_end);
-					if (make_writable)
-						user_flushrs(p, pt);
-				}
+				if (p->mm == mm && p->state != TASK_RUNNING)
+					collect_task(&list, p, make_writable);
 			}
 		}
 		read_unlock(&tasklist_lock);
+
+		while (list)
+			list = finish_task(list, make_writable);
 	}
 	child->thread.flags |= IA64_THREAD_KRBS_SYNCED;	/* set the flag in the child thread only */
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/setup.c linux-2.4.21-pre6/arch/ia64/kernel/setup.c
--- linux-2.4.20/arch/ia64/kernel/setup.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/kernel/setup.c	2003-03-26 23:49:07.000000000 +0000
@@ -65,6 +65,8 @@
 struct screen_info screen_info;
 
 unsigned long ia64_iobase;	/* virtual address for I/O accesses */
+struct io_space io_space[MAX_IO_SPACES];
+unsigned int num_io_spaces;
 
 unsigned char aux_device_present = 0xaa;        /* XXX remove this when legacy I/O is gone */
 
@@ -338,6 +340,11 @@
 	}
 	ia64_iobase = (unsigned long) ioremap(phys_iobase, 0);
 
+	/* setup legacy IO port space */
+	io_space[0].mmio_base = ia64_iobase;
+	io_space[0].sparse = 1;
+	num_io_spaces = 1;
+
 #ifdef CONFIG_SMP
 	cpu_physical_id(0) = hard_smp_processor_id();
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/signal.c linux-2.4.21-pre6/arch/ia64/kernel/signal.c
--- linux-2.4.20/arch/ia64/kernel/signal.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/kernel/signal.c	2003-03-26 23:49:40.000000000 +0000
@@ -41,6 +41,16 @@
 
 extern long ia64_do_signal (sigset_t *, struct sigscratch *, long);	/* forward decl */
 
+register double f16 asm ("f16"); register double f17 asm ("f17");
+register double f18 asm ("f18"); register double f19 asm ("f19");
+register double f20 asm ("f20"); register double f21 asm ("f21");
+register double f22 asm ("f22"); register double f23 asm ("f23");
+
+register double f24 asm ("f24"); register double f25 asm ("f25");
+register double f26 asm ("f26"); register double f27 asm ("f27");
+register double f28 asm ("f28"); register double f29 asm ("f29");
+register double f30 asm ("f30"); register double f31 asm ("f31");
+
 long
 ia64_rt_sigsuspend (sigset_t *uset, size_t sigsetsize, struct sigscratch *scr)
 {
@@ -354,6 +364,15 @@
 	return err;
 }
 
+/*
+ * Check whether the register-backing store is already on the signal stack.
+ */
+static inline int
+rbs_on_sig_stack (unsigned long bsp)
+{
+	return (bsp - current->sas_ss_sp < current->sas_ss_size);
+}
+
 static long
 setup_frame (int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set,
 	     struct sigscratch *scr)
@@ -366,10 +385,16 @@
 
 	frame = (void *) scr->pt.r12;
 	tramp_addr = GATE_ADDR + (ia64_sigtramp - __start_gate_section);
-	if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && !on_sig_stack((unsigned long) frame)) {
-		new_rbs  = (current->sas_ss_sp + sizeof(long) - 1) & ~(sizeof(long) - 1);
+	if ((ka->sa.sa_flags & SA_ONSTACK) && sas_ss_flags((unsigned long) frame) == 0) {
 		frame = (void *) ((current->sas_ss_sp + current->sas_ss_size)
 				  & ~(STACK_ALIGN - 1));
+  		/*
+		 * We need to check for the register stack being on the signal stack
+		 * separately, because it's switched separately (memory stack is switched
+		 * in the kernel, register stack is switched in the signal trampoline).
+  		 */
+		if (!rbs_on_sig_stack(scr->pt.ar_bspstore))
+			new_rbs  = (current->sas_ss_sp + sizeof(long) - 1) & ~(sizeof(long) - 1);
 	}
 	frame = (void *) frame - ((sizeof(*frame) + STACK_ALIGN - 1) & ~(STACK_ALIGN - 1));
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/smp.c linux-2.4.21-pre6/arch/ia64/kernel/smp.c
--- linux-2.4.20/arch/ia64/kernel/smp.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/kernel/smp.c	2003-03-26 23:49:55.000000000 +0000
@@ -188,8 +188,20 @@
 void
 smp_flush_tlb_all (void)
 {
-	smp_call_function ((void (*)(void *))__flush_tlb_all,0,1,1);
-	__flush_tlb_all();
+	smp_call_function((void (*)(void *))local_flush_tlb_all, 0, 1, 1);
+	local_flush_tlb_all();
+}
+
+void
+smp_flush_tlb_mm (struct mm_struct *mm)
+{
+	local_flush_tlb_mm(mm);
+
+	/* this happens for the common case of a single-threaded fork():  */
+	if (likely(mm == current->active_mm && atomic_read(&mm->mm_users) == 1))
+		return;
+
+	smp_call_function((void (*)(void *))local_flush_tlb_mm, mm, 1, 1);
 }
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/smpboot.c linux-2.4.21-pre6/arch/ia64/kernel/smpboot.c
--- linux-2.4.20/arch/ia64/kernel/smpboot.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/kernel/smpboot.c	2003-03-26 23:49:19.000000000 +0000
@@ -89,7 +89,7 @@
 struct smp_boot_data smp_boot_data __initdata;
 
 /* Set when the idlers are all forked */
-volatile int smp_threads_ready;
+int smp_threads_ready;
 
 unsigned long ap_wakeup_vector = -1; /* External Int use to wakeup APs */
 
@@ -321,7 +321,7 @@
 	extern void ia64_init_itm(void);
 
 #ifdef CONFIG_PERFMON
-	extern void perfmon_init_percpu(void);
+	extern void pfm_init_percpu(void);
 #endif
 
 	cpuid = smp_processor_id();
@@ -356,7 +356,7 @@
 #endif
 
 #ifdef CONFIG_PERFMON
-	perfmon_init_percpu();
+	pfm_init_percpu();
 #endif
 
 	local_irq_enable();
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/sys_ia64.c linux-2.4.21-pre6/arch/ia64/kernel/sys_ia64.c
--- linux-2.4.20/arch/ia64/kernel/sys_ia64.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/kernel/sys_ia64.c	2003-03-26 23:48:58.000000000 +0000
@@ -253,6 +253,29 @@
 	return addr;
 }
 
+asmlinkage unsigned long
+ia64_mremap (unsigned long addr, unsigned long old_len, unsigned long new_len, unsigned long flags,
+	     unsigned long new_addr)
+{
+	extern unsigned long do_mremap (unsigned long addr,
+					unsigned long old_len,
+					unsigned long new_len,
+					unsigned long flags,
+					unsigned long new_addr);
+
+	down_write(&current->mm->mmap_sem);
+	{
+		addr = do_mremap(addr, old_len, new_len, flags, new_addr);
+	}
+	up_write(&current->mm->mmap_sem);
+
+	if (IS_ERR((void *) addr))
+		return addr;
+
+	force_successful_syscall_return();
+	return addr;
+}
+
 asmlinkage long
 sys_vm86 (long arg0, long arg1, long arg2, long arg3)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/traps.c linux-2.4.21-pre6/arch/ia64/kernel/traps.c
--- linux-2.4.20/arch/ia64/kernel/traps.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/kernel/traps.c	2003-03-26 23:49:55.000000000 +0000
@@ -142,7 +142,8 @@
 	siginfo.si_isr = 0;
 
 	switch (break_num) {
-	      case 0: /* unknown error */
+	      case 0: /* unknown error (used by GCC for __builtin_abort()) */
+		die_if_kernel("Bad break", regs, break_num);
 		sig = SIGILL; code = ILL_ILLOPC;
 		break;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/unaligned.c linux-2.4.21-pre6/arch/ia64/kernel/unaligned.c
--- linux-2.4.20/arch/ia64/kernel/unaligned.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/kernel/unaligned.c	2003-03-26 23:49:54.000000000 +0000
@@ -5,6 +5,10 @@
  *	Stephane Eranian <eranian@hpl.hp.com>
  *	David Mosberger-Tang <davidm@hpl.hp.com>
  *
+ * 2002/12/09   Fix rotating register handling (off-by-1 error, missing fr-rotation).  Fix
+ *		get_rse_reg() to not leak kernel bits to user-level (reading an out-of-frame
+ *		stacked register returns an undefined value; it does NOT trigger a
+ *		"rsvd register fault").
  * 2001/10/11	Fix unaligned access to rotating registers in s/w pipelined loops.
  * 2001/08/13	Correct size of extended floats (float_fsz) from 16 to 10 bytes.
  * 2001/01/17	Add support emulation of unaligned kernel accesses.
@@ -275,6 +279,15 @@
 #	undef F
 }
 
+static inline unsigned long
+rotate_reg (unsigned long sor, unsigned long rrb, unsigned long reg)
+{
+	reg += rrb;
+	if (reg >= sor)
+		reg -= sor;
+	return reg;
+}
+
 static void
 set_rse_reg (struct pt_regs *regs, unsigned long r1, unsigned long val, int nat)
 {
@@ -286,26 +299,22 @@
 	long sof = (regs->cr_ifs) & 0x7f;
 	long sor = 8 * ((regs->cr_ifs >> 14) & 0xf);
 	long rrb_gr = (regs->cr_ifs >> 18) & 0x7f;
-	long ridx;
-
-	if ((r1 - 32) > sor)
-		ridx = -sof + (r1 - 32);
-	else if ((r1 - 32) < (sor - rrb_gr))
-		ridx = -sof + (r1 - 32) + rrb_gr;
-	else
-		ridx = -sof + (r1 - 32) - (sor - rrb_gr);
-
-	DPRINT("r%lu, sw.bspstore=%lx pt.bspstore=%lx sof=%ld sol=%ld ridx=%ld\n",
-	       r1, sw->ar_bspstore, regs->ar_bspstore, sof, (regs->cr_ifs >> 7) & 0x7f, ridx);
+	long ridx = r1 - 32;
 
-	if ((r1 - 32) >= sof) {
+	if (ridx >= sof) {
 		/* this should never happen, as the "rsvd register fault" has higher priority */
 		DPRINT("ignoring write to r%lu; only %lu registers are allocated!\n", r1, sof);
 		return;
 	}
 
+	if (ridx < sor)
+		ridx = rotate_reg(sor, rrb_gr, ridx);
+
+	DPRINT("r%lu, sw.bspstore=%lx pt.bspstore=%lx sof=%ld sol=%ld ridx=%ld\n",
+	       r1, sw->ar_bspstore, regs->ar_bspstore, sof, (regs->cr_ifs >> 7) & 0x7f, ridx);
+
 	on_kbs = ia64_rse_num_regs(kbs, (unsigned long *) sw->ar_bspstore);
-	addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, ridx);
+	addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, -sof + ridx);
 	if (addr >= kbs) {
 		/* the register is on the kernel backing store: easy... */
 		rnat_addr = ia64_rse_rnat_addr(addr);
@@ -333,7 +342,7 @@
 	bspstore = (unsigned long *)regs->ar_bspstore;
 	ubs_end = ia64_rse_skip_regs(bspstore, on_kbs);
 	bsp     = ia64_rse_skip_regs(ubs_end, -sof);
-	addr    = ia64_rse_skip_regs(bsp, ridx + sof);
+	addr    = ia64_rse_skip_regs(bsp, ridx);
 
 	DPRINT("ubs_end=%p bsp=%p addr=%p\n", (void *) ubs_end, (void *) bsp, (void *) addr);
 
@@ -367,26 +376,22 @@
 	long sof = (regs->cr_ifs) & 0x7f;
 	long sor = 8 * ((regs->cr_ifs >> 14) & 0xf);
 	long rrb_gr = (regs->cr_ifs >> 18) & 0x7f;
-	long ridx;
+	long ridx = r1 - 32;
 
-	if ((r1 - 32) > sor)
-		ridx = -sof + (r1 - 32);
-	else if ((r1 - 32) < (sor - rrb_gr))
-		ridx = -sof + (r1 - 32) + rrb_gr;
-	else
-		ridx = -sof + (r1 - 32) - (sor - rrb_gr);
+	if (ridx >= sof) {
+		/* read of out-of-frame register returns an undefined value; 0 in our case.  */
+		DPRINT("ignoring read from r%lu; only %lu registers are allocated!\n", r1, sof);
+		goto fail;
+	}
+
+	if (ridx < sor)
+		ridx = rotate_reg(sor, rrb_gr, ridx);
 
 	DPRINT("r%lu, sw.bspstore=%lx pt.bspstore=%lx sof=%ld sol=%ld ridx=%ld\n",
 	       r1, sw->ar_bspstore, regs->ar_bspstore, sof, (regs->cr_ifs >> 7) & 0x7f, ridx);
 
-	if ((r1 - 32) >= sof) {
-		/* this should never happen, as the "rsvd register fault" has higher priority */
-		DPRINT("ignoring read from r%lu; only %lu registers are allocated!\n", r1, sof);
-		return;
-	}
-
 	on_kbs = ia64_rse_num_regs(kbs, (unsigned long *) sw->ar_bspstore);
-	addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, ridx);
+	addr = ia64_rse_skip_regs((unsigned long *) sw->ar_bspstore, -sof + ridx);
 	if (addr >= kbs) {
 		/* the register is on the kernel backing store: easy... */
 		*val = *addr;
@@ -406,13 +411,13 @@
 	 */
 	if (regs->r12 >= TASK_SIZE) {
 		DPRINT("ignoring kernel read of r%lu; register isn't on the RBS!", r1);
-		return;
+		goto fail;
 	}
 
 	bspstore = (unsigned long *)regs->ar_bspstore;
 	ubs_end = ia64_rse_skip_regs(bspstore, on_kbs);
 	bsp     = ia64_rse_skip_regs(ubs_end, -sof);
-	addr    = ia64_rse_skip_regs(bsp, ridx + sof);
+	addr    = ia64_rse_skip_regs(bsp, ridx);
 
 	DPRINT("ubs_end=%p bsp=%p addr=%p\n", (void *) ubs_end, (void *) bsp, (void *) addr);
 
@@ -427,6 +432,13 @@
 		ia64_peek(current, sw, (unsigned long) ubs_end, (unsigned long) rnat_addr, &rnats);
 		*nat = (rnats & nat_mask) != 0;
 	}
+	return;
+
+  fail:
+	*val = 0;
+	if (nat)
+		*nat = 0;
+	return;
 }
 
 
@@ -485,7 +497,16 @@
 	DPRINT("*0x%lx=0x%lx NaT=%d new unat: %p=%lx\n", addr, val, nat, (void *) unat,*unat);
 }
 
-#define IA64_FPH_OFFS(r) (r - IA64_FIRST_ROTATING_FR)
+/*
+ * Return the (rotated) index for floating point register REGNUM (REGNUM must be in the
+ * range from 32-127, result is in the range from 0-95.
+ */
+static inline unsigned long
+fph_index (struct pt_regs *regs, long regnum)
+{
+	unsigned long rrb_fr = (regs->cr_ifs >> 25) & 0x7f;
+	return rotate_reg(96, rrb_fr, (regnum - IA64_FIRST_ROTATING_FR));
+}
 
 static void
 setfpreg (unsigned long regnum, struct ia64_fpreg *fpval, struct pt_regs *regs)
@@ -506,7 +527,7 @@
 	 */
 	if (regnum >= IA64_FIRST_ROTATING_FR) {
 		ia64_sync_fph(current);
-		current->thread.fph[IA64_FPH_OFFS(regnum)] = *fpval;
+		current->thread.fph[fph_index(regs, regnum)] = *fpval;
 	} else {
 		/*
 		 * pt_regs or switch_stack ?
@@ -565,7 +586,7 @@
 	 */
 	if (regnum >= IA64_FIRST_ROTATING_FR) {
 		ia64_flush_fph(current);
-		*fpval = current->thread.fph[IA64_FPH_OFFS(regnum)];
+		*fpval = current->thread.fph[fph_index(regs, regnum)];
 	} else {
 		/*
 		 * f0 = 0.0, f1= 1.0. Those registers are constant and are thus
@@ -650,8 +671,8 @@
 	 * just in case.
 	 */
 	if (ld.x6_op == 1 || ld.x6_op == 3) {
-		printk("%s %s: register update on speculative load, error\n", KERN_ERR, __FUNCTION__);
-		die_if_kernel("unaligned reference on specualtive load with register update\n",
+		printk(KERN_ERR "%s: register update on speculative load, error\n", __FUNCTION__);
+		die_if_kernel("unaligned reference on speculative load with register update\n",
 			      regs, 30);
 	}
 
@@ -1080,8 +1101,8 @@
 		 * For this reason we keep this sanity check
 		 */
 		if (ld.x6_op == 1 || ld.x6_op == 3)
-			printk("%s %s: register update on speculative load pair, "
-			       "error\n",KERN_ERR, __FUNCTION__);
+			printk(KERN_ERR "%s: register update on speculative load pair, error\n",
+			       __FUNCTION__);
 
 		setreg(ld.r3, ifa, 0, regs);
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/kernel/unwind.c linux-2.4.21-pre6/arch/ia64/kernel/unwind.c
--- linux-2.4.20/arch/ia64/kernel/unwind.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/kernel/unwind.c	2003-03-26 23:49:39.000000000 +0000
@@ -1997,16 +1997,18 @@
 {
 	extern char __start_gate_section[], __stop_gate_section[];
 	unsigned long *lp, start, end, segbase = unw.kernel_table.segment_base;
-	const struct unw_table_entry *entry, *first;
+	const struct unw_table_entry *entry, *first, *unw_table_end;
+	extern int ia64_unw_end;
 	size_t info_size, size;
 	char *info;
 
 	start = (unsigned long) __start_gate_section - segbase;
 	end   = (unsigned long) __stop_gate_section - segbase;
+	unw_table_end = (struct unw_table_entry *) &ia64_unw_end;
 	size  = 0;
 	first = lookup(&unw.kernel_table, start);
 
-	for (entry = first; entry->start_offset < end; ++entry)
+	for (entry = first; entry < unw_table_end && entry->start_offset < end; ++entry)
 		size += 3*8 + 8 + 8*UNW_LENGTH(*(u64 *) (segbase + entry->info_offset));
 	size += 8;	/* reserve space for "end of table" marker */
 
@@ -2021,7 +2023,7 @@
 	lp = unw.gate_table;
 	info = (char *) unw.gate_table + size;
 
-	for (entry = first; entry->start_offset < end; ++entry, lp += 3) {
+	for (entry = first; entry < unw_table_end && entry->start_offset < end; ++entry, lp += 3) {
 		info_size = 8 + 8*UNW_LENGTH(*(u64 *) (segbase + entry->info_offset));
 		info -= info_size;
 		memcpy(info, (char *) segbase + entry->info_offset, info_size);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/lib/Makefile linux-2.4.21-pre6/arch/ia64/lib/Makefile
--- linux-2.4.20/arch/ia64/lib/Makefile	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/lib/Makefile	2003-03-26 23:49:54.000000000 +0000
@@ -11,7 +11,7 @@
 
 obj-y := __divsi3.o __udivsi3.o __modsi3.o __umodsi3.o					\
 	__divdi3.o __udivdi3.o __moddi3.o __umoddi3.o					\
-	checksum.o clear_page.o csum_partial_copy.o					\
+	carta_random.o checksum.o clear_page.o csum_partial_copy.o					\
 	clear_user.o strncpy_from_user.o strlen_user.o strnlen_user.o			\
 	flush.o ip_fast_csum.o io.o do_csum.o						\
 	memset.o strlen.o swiotlb.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/lib/carta_random.S linux-2.4.21-pre6/arch/ia64/lib/carta_random.S
--- linux-2.4.20/arch/ia64/lib/carta_random.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/lib/carta_random.S	2003-03-26 23:49:55.000000000 +0000
@@ -0,0 +1,54 @@
+/*
+ * Fast, simple, yet decent quality random number generator based on
+ * a paper by David G. Carta ("Two Fast Implementations of the
+ * `Minimal Standard' Random Number Generator," Communications of the
+ * ACM, January, 1990).
+ *
+ * Copyright (C) 2002 Hewlett-Packard Co
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
+ */
+
+#include <asm/asmmacro.h>
+
+#define a	r2
+#define m	r3
+#define lo	r8
+#define hi	r9
+#define t0	r16
+#define t1	r17
+#define	seed	r32
+
+GLOBAL_ENTRY(carta_random32)
+	movl	a = (16807 << 16) | 16807
+	;;
+	pmpyshr2.u t0 = a, seed, 0
+	pmpyshr2.u t1 = a, seed, 16
+	;;
+	unpack2.l t0 = t1, t0
+	dep	m = -1, r0, 0, 31
+	;;
+	zxt4	lo = t0
+	shr.u	hi = t0, 32
+	;;
+	dep	t0 = 0, hi, 15, 49	// t0 = (hi & 0x7fff)
+	;;
+	shl	t0 = t0, 16		// t0 = (hi & 0x7fff) << 16
+	shr	t1 = hi, 15		// t1 = (hi >> 15)
+	;;
+	add	lo = lo, t0
+	;;
+	cmp.gtu	p6, p0 = lo, m
+	;;
+(p6)	and	lo = lo, m
+	;;
+(p6)	add	lo = 1, lo
+	;;
+	add	lo = lo, t1
+	;;
+	cmp.gtu p6, p0 = lo, m
+	;;
+(p6)	and	lo = lo, m
+	;;
+(p6)	add	lo = 1, lo
+	br.ret.sptk.many rp
+END(carta_random32)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/lib/memcpy_mck.S linux-2.4.21-pre6/arch/ia64/lib/memcpy_mck.S
--- linux-2.4.20/arch/ia64/lib/memcpy_mck.S	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/lib/memcpy_mck.S	2003-03-26 23:49:20.000000000 +0000
@@ -6,7 +6,10 @@
  *	in1:	source address
  *	in2:	number of bytes to copy
  * Output:
- * 	0 if success, or number of byte NOT copied if error occurred.
+ *	for bcopy:     return nothing
+ *	for memcpy:    return dest
+ * 	for copy_user: 0 if success,
+ *		       or number of bytes NOT copied if error occurred.
  *
  * Copyright (C) 2002 Intel Corp.
  * Copyright (C) 2002 Ken Chen <kenneth.w.chen@intel.com>
@@ -21,15 +24,6 @@
 # define EK(y,x...)	x
 #endif
 
-GLOBAL_ENTRY(bcopy)
-	.regstk 3,0,0,0
-	mov r8=in0
-	mov in0=in1
-	;;
-	mov in1=r8
-	;;
-END(bcopy)
-
 /* McKinley specific optimization */
 
 #define retval		r8
@@ -82,10 +76,19 @@
 #define in1		r33
 #define in2		r34
 
+GLOBAL_ENTRY(bcopy)
+	.regstk 3,0,0,0
+	mov r8=in0		// swap the src and dest arguments
+	mov in0=in1
+	;;
+	mov in1=r8
+	;;
+END(bcopy)			// fall through to memcpy
 GLOBAL_ENTRY(memcpy)
 	and	r28=0x7,in0
 	and	r29=0x7,in1
 	mov	f6=f0
+	mov	retval=in0
 	br.cond.sptk .common_code
 	;;
 END(memcpy)
@@ -97,7 +100,7 @@
 	mov	f6=f1
 	mov	saved_in0=in0	// save dest pointer
 	mov	saved_in1=in1	// save src pointer
-	mov	saved_in2=in2	// save len
+	mov	retval=r0	// initialize return value
 	;;
 .common_code:
 	cmp.gt	p15,p0=8,in2	// check for small size
@@ -105,7 +108,7 @@
 	cmp.ne	p14,p0=0,r29	// check src alignment
 	add	src0=0,in1
 	sub	r30=8,r28	// for .align_dest
-	mov	retval=r0	// initialize return value
+	mov	saved_in2=in2	// save len
 	;;
 	add	dst0=0,in0
 	add	dst1=1,in0	// dest odd index
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/lib/swiotlb.c linux-2.4.21-pre6/arch/ia64/lib/swiotlb.c
--- linux-2.4.20/arch/ia64/lib/swiotlb.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/lib/swiotlb.c	2003-03-26 23:49:50.000000000 +0000
@@ -351,7 +351,7 @@
 	pg_addr = PAGE_ALIGN((unsigned long) addr);
 	end = (unsigned long) addr + size;
 	while (pg_addr + PAGE_SIZE <= end) {
-		struct page *page = virt_to_page(pg_addr);
+		struct page *page = virt_to_page((void *)pg_addr);
 		set_bit(PG_arch_1, &page->flags);
 		pg_addr += PAGE_SIZE;
 	}
@@ -417,23 +417,23 @@
 int
 swiotlb_map_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction)
 {
-	void *addr;
 	int i;
 
 	if (direction == PCI_DMA_NONE)
 		BUG();
 
 	for (i = 0; i < nelems; i++, sg++) {
-		sg->orig_address = SG_ENT_VIRT_ADDRESS(sg);
-		if ((SG_ENT_PHYS_ADDRESS(sg) & ~hwdev->dma_mask) != 0) {
-			addr = map_single(hwdev, sg->orig_address, sg->length, direction);
-			if (sg->address)
-				sg->address = addr;
-			else {
-				sg->page = virt_to_page(addr);
-				sg->offset = (u64) addr & ~PAGE_MASK;
-			}
-		}
+		void * virt_address = SG_ENT_VIRT_ADDRESS(sg);
+		unsigned long phys_address = virt_to_phys(virt_address);
+
+		sg->dma_length = sg->length;
+		if (phys_address & ~hwdev->dma_mask)
+			sg->dma_address = virt_to_phys(map_single(hwdev,
+			                                          virt_address,
+			                                          sg->length,
+			                                          direction));
+		else
+			sg->dma_address = phys_address;
 	}
 	return nelems;
 }
@@ -451,14 +451,9 @@
 		BUG();
 
 	for (i = 0; i < nelems; i++, sg++)
-		if (sg->orig_address != SG_ENT_VIRT_ADDRESS(sg)) {
-			unmap_single(hwdev, SG_ENT_VIRT_ADDRESS(sg), sg->length, direction);
-			if (sg->address)
-				sg->address = sg->orig_address;
-			else {
-				sg->page = virt_to_page(sg->orig_address);
-				sg->offset = (u64) sg->orig_address & ~PAGE_MASK;
-			}
+		if (sg->dma_address != virt_to_phys(SG_ENT_VIRT_ADDRESS(sg))) {
+			unmap_single(hwdev, phys_to_virt(sg->dma_address),
+			             sg->dma_length, direction);
 		} else if (direction == PCI_DMA_FROMDEVICE)
 			mark_clean(SG_ENT_VIRT_ADDRESS(sg), sg->length);
 }
@@ -479,14 +474,9 @@
 		BUG();
 
 	for (i = 0; i < nelems; i++, sg++)
-		if (sg->orig_address != SG_ENT_VIRT_ADDRESS(sg))
-			sync_single(hwdev, SG_ENT_VIRT_ADDRESS(sg), sg->length, direction);
-}
-
-unsigned long
-swiotlb_dma_address (struct scatterlist *sg)
-{
-	return SG_ENT_PHYS_ADDRESS(sg);
+		if (sg->dma_address != virt_to_phys(SG_ENT_VIRT_ADDRESS(sg)))
+			sync_single(hwdev, phys_to_virt(sg->dma_address),
+			            sg->dma_length, direction);
 }
 
 /*
@@ -507,7 +497,6 @@
 EXPORT_SYMBOL(swiotlb_unmap_sg);
 EXPORT_SYMBOL(swiotlb_sync_single);
 EXPORT_SYMBOL(swiotlb_sync_sg);
-EXPORT_SYMBOL(swiotlb_dma_address);
 EXPORT_SYMBOL(swiotlb_alloc_consistent);
 EXPORT_SYMBOL(swiotlb_free_consistent);
 EXPORT_SYMBOL(swiotlb_pci_dma_supported);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/mm/Makefile linux-2.4.21-pre6/arch/ia64/mm/Makefile
--- linux-2.4.20/arch/ia64/mm/Makefile	2001-01-04 20:50:17.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/mm/Makefile	2003-03-26 23:49:25.000000000 +0000
@@ -9,6 +9,8 @@
 
 O_TARGET := mm.o
 
+export-objs := init.o
+
 obj-y	 := init.o fault.o tlb.o extable.o
 
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/mm/fault.c linux-2.4.21-pre6/arch/ia64/mm/fault.c
--- linux-2.4.20/arch/ia64/mm/fault.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/mm/fault.c	2003-03-26 23:49:55.000000000 +0000
@@ -58,7 +58,6 @@
 	if (in_interrupt() || !mm)
 		goto no_context;
 
-#ifdef CONFIG_VIRTUAL_MEM_MAP
 	/*
 	 * If fault is in region 5 and we are in the kernel, we may already
          * have the mmap_sem (VALID_PAGE macro is called during mmap). There
@@ -67,7 +66,6 @@
   	 */
 	if ((REGION_NUMBER(address) == 5) && !user_mode(regs))
 		goto bad_area_no_up;
-#endif
 
 	down_read(&mm->mmap_sem);
 
@@ -148,9 +146,7 @@
 
   bad_area:
 	up_read(&mm->mmap_sem);
-#ifdef CONFIG_VIRTUAL_MEM_MAP
   bad_area_no_up:
-#endif
 	if ((isr & IA64_ISR_SP)
 	    || ((isr & IA64_ISR_NA) && (isr & IA64_ISR_CODE_MASK) == IA64_ISR_CODE_LFETCH))
 	{
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/mm/init.c linux-2.4.21-pre6/arch/ia64/mm/init.c
--- linux-2.4.20/arch/ia64/mm/init.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/mm/init.c	2003-03-26 23:49:34.000000000 +0000
@@ -5,6 +5,7 @@
  *	David Mosberger-Tang <davidm@hpl.hp.com>
  */
 #include <linux/config.h>
+#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 
@@ -35,15 +36,14 @@
 extern void ia64_tlb_init (void);
 
 unsigned long MAX_DMA_ADDRESS = PAGE_OFFSET + 0x100000000UL;
+#define LARGE_GAP 0x40000000 /* Use virtual mem map if a hole is > than this */
 
 static unsigned long totalram_pages;
 
-#ifdef CONFIG_VIRTUAL_MEM_MAP
 unsigned long vmalloc_end = VMALLOC_END_INIT;
 
 static struct page *vmem_map;
 static unsigned long num_dma_physpages;
-#endif
 
 int
 do_check_pgt_cache (int low, int high)
@@ -114,8 +114,8 @@
 
 	addr = (unsigned long) &__init_begin;
 	for (; addr < (unsigned long) &__init_end; addr += PAGE_SIZE) {
-		clear_bit(PG_reserved, &virt_to_page(addr)->flags);
-		set_page_count(virt_to_page(addr), 1);
+		clear_bit(PG_reserved, &virt_to_page((void *)addr)->flags);
+		set_page_count(virt_to_page((void *)addr), 1);
 		free_page(addr);
 		++totalram_pages;
 	}
@@ -164,10 +164,10 @@
 		printk(KERN_INFO "Freeing initrd memory: %ldkB freed\n", (end - start) >> 10);
 
 	for (; start < end; start += PAGE_SIZE) {
-		if (!VALID_PAGE(virt_to_page(start)))
+		if (!VALID_PAGE(virt_to_page((void *)start)))
 			continue;
-		clear_bit(PG_reserved, &virt_to_page(start)->flags);
-		set_page_count(virt_to_page(start), 1);
+		clear_bit(PG_reserved, &virt_to_page((void *)start)->flags);
+		set_page_count(virt_to_page((void *)start), 1);
 		free_page(start);
 		++totalram_pages;
 	}
@@ -357,10 +357,6 @@
 	ia64_tlb_init();
 }
 
-#ifdef CONFIG_VIRTUAL_MEM_MAP
-
-#include <asm/pgtable.h>
-
 static int
 create_mem_map_page_table (u64 start, u64 end, void *arg)
 {
@@ -413,8 +409,8 @@
 
 	/* Should we use platform_map_nr here? */
 
-	map_start = vmem_map + MAP_NR_DENSE(start);
-	map_end   = vmem_map + MAP_NR_DENSE(end);
+	map_start = mem_map + MAP_NR_DENSE(start);
+	map_end   = mem_map + MAP_NR_DENSE(end);
 
 	if (map_start < args->start)
 		map_start = args->start;
@@ -444,15 +440,19 @@
 arch_memmap_init (memmap_init_callback_t *memmap_init, struct page *start,
 	struct page *end, int zone, unsigned long start_paddr, int highmem)
 {
-	struct memmap_init_callback_data args;
+	if (!vmem_map) 
+		memmap_init(start,end,zone,page_to_phys(start),highmem);
+	else {
+		struct memmap_init_callback_data args;
 
-	args.memmap_init = memmap_init;
-	args.start = start;
-	args.end = end;
-	args.zone = zone;
-	args.highmem = highmem;
+		args.memmap_init = memmap_init;
+		args.start = start;
+		args.end = end;
+		args.zone = zone;
+		args.highmem = highmem;
 
-	efi_memmap_walk(virtual_memmap_init, &args);
+		efi_memmap_walk(virtual_memmap_init, &args);
+	}
 
 	return page_to_phys(end);
 }
@@ -475,8 +475,6 @@
 	return __get_user(byte, (char *) page) == 0;
 }
 
-#endif /* CONFIG_VIRTUAL_MEM_MAP */
-
 static int
 count_pages (u64 start, u64 end, void *arg)
 {
@@ -486,47 +484,75 @@
 	return 0;
 }
 
+#ifndef CONFIG_DISCONTIGMEM
+static int
+find_largest_hole(u64 start, u64 end, void *arg)
+{
+	u64 *max_gap = arg;
+	static u64 last_end = PAGE_OFFSET;
+
+	/* NOTE: this algorithm assumes efi memmap table is ordered */
+
+	if (*max_gap < (start - last_end))
+		*max_gap = start - last_end;
+	last_end = end;
+	return 0;
+}
+#endif
+
 /*
  * Set up the page tables.
  */
 void
 paging_init (void)
 {
-	unsigned long max_dma, zones_size[MAX_NR_ZONES];
+	unsigned long max_dma;
+	unsigned long zones_size[MAX_NR_ZONES];
+	unsigned long zholes_size[MAX_NR_ZONES];
+#ifndef CONFIG_DISCONTIGMEM
+	unsigned long max_gap;
+#endif
 
 	/* initialize mem_map[] */
 
 	memset(zones_size, 0, sizeof(zones_size));
+	memset(zholes_size, 0, sizeof(zholes_size));
 
 	num_physpages = 0;
 	efi_memmap_walk(count_pages, &num_physpages);
 
-	max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT;
+	num_dma_physpages = 0;
+	efi_memmap_walk(count_dma_pages, &num_dma_physpages);
 
-#ifdef CONFIG_VIRTUAL_MEM_MAP
-	{
-		unsigned long zholes_size[MAX_NR_ZONES];
-		unsigned long map_size;
+	max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT;
 
-		memset(zholes_size, 0, sizeof(zholes_size));
+	if (max_low_pfn < max_dma) {
+		zones_size[ZONE_DMA] = max_low_pfn;
+		zholes_size[ZONE_DMA] = max_low_pfn - num_dma_physpages;
+	} else {
+		zones_size[ZONE_DMA] = max_dma;
+		zholes_size[ZONE_DMA] = max_dma - num_dma_physpages;
+		if (num_physpages > num_dma_physpages) {
+			zones_size[ZONE_NORMAL] = max_low_pfn - max_dma;
+			zholes_size[ZONE_NORMAL] = (max_low_pfn - max_dma)
+					- (num_physpages - num_dma_physpages);
+		}
+	}
 
-		num_dma_physpages = 0;
-		efi_memmap_walk(count_dma_pages, &num_dma_physpages);
+#ifdef CONFIG_DISCONTIGMEM
+	free_area_init_node(0, NULL, NULL, zones_size, 0, zholes_size);
+#else
+	max_gap = 0;
+	efi_memmap_walk(find_largest_hole, (u64 *)&max_gap);
 
-		if (max_low_pfn < max_dma) {
-			zones_size[ZONE_DMA] = max_low_pfn;
-			zholes_size[ZONE_DMA] = max_low_pfn - num_dma_physpages;
-		} else {
-			zones_size[ZONE_DMA] = max_dma;
-			zholes_size[ZONE_DMA] = max_dma - num_dma_physpages;
-			if (num_physpages > num_dma_physpages) {
-				zones_size[ZONE_NORMAL] = max_low_pfn - max_dma;
-				zholes_size[ZONE_NORMAL] = ((max_low_pfn - max_dma)
-							    - (num_physpages - num_dma_physpages));
-			}
-		}
+	if (max_gap < LARGE_GAP) {
+		vmem_map = (struct page *)0;
+		free_area_init_node(0, NULL, NULL, zones_size, 0, zholes_size);
+	}
+	else {
+		unsigned long map_size;
 
-		/* allocate virtual mem_map: */
+		/* allocate virtual mem_map */
 
 		map_size = PAGE_ALIGN(max_low_pfn*sizeof(struct page));
 		vmalloc_end -= map_size;
@@ -536,15 +562,7 @@
 		free_area_init_node(0, NULL, vmem_map, zones_size, 0, zholes_size);
 		printk("Virtual mem_map starts at 0x%p\n", mem_map);
 	}
-#else /* !CONFIG_VIRTUAL_MEM_MAP */
-	if (max_low_pfn < max_dma)
-		zones_size[ZONE_DMA] = max_low_pfn;
-	else {
-		zones_size[ZONE_DMA] = max_dma;
-		zones_size[ZONE_NORMAL] = max_low_pfn - max_dma;
-	}
-	free_area_init(zones_size);
-#endif /* !CONFIG_VIRTUAL_MEM_MAP */
+#endif
 }
 
 static int
@@ -554,7 +572,7 @@
 	unsigned long *count = arg;
 	struct page *pg;
 
-	for (pg = virt_to_page(start); pg < virt_to_page(end); ++pg)
+	for (pg = virt_to_page((void *)start); pg < virt_to_page((void *)end); ++pg)
 		if (PageReserved(pg))
 			++num_reserved;
 	*count += num_reserved;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/mm/tlb.c linux-2.4.21-pre6/arch/ia64/mm/tlb.c
--- linux-2.4.20/arch/ia64/mm/tlb.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/mm/tlb.c	2003-03-26 23:49:50.000000000 +0000
@@ -100,7 +100,7 @@
 }
 
 void
-__flush_tlb_all (void)
+local_flush_tlb_all (void)
 {
 	unsigned long i, j, flags, count0, count1, stride0, stride1, addr;
 
@@ -185,5 +185,5 @@
 	local_cpu_data->ptce_stride[0] = ptce_info.stride[0];
 	local_cpu_data->ptce_stride[1] = ptce_info.stride[1];
 
-	__flush_tlb_all();		/* nuke left overs from bootstrapping... */
+	local_flush_tlb_all();		/* nuke left overs from bootstrapping... */
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-bigsur-mp linux-2.4.21-pre6/arch/ia64/sn/configs/sn1/defconfig-bigsur-mp
--- linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-bigsur-mp	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/configs/sn1/defconfig-bigsur-mp	1970-01-01 00:00:00.000000000 +0000
@@ -1,777 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# General setup
-#
-CONFIG_IA64=y
-# CONFIG_ISA is not set
-# CONFIG_EISA is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_ACPI=y
-CONFIG_ACPI_EFI=y
-CONFIG_ACPI_INTERPRETER=y
-CONFIG_ACPI_KERNEL_CONFIG=y
-CONFIG_ITANIUM=y
-# CONFIG_MCKINLEY is not set
-# CONFIG_IA64_GENERIC is not set
-CONFIG_IA64_DIG=y
-# CONFIG_IA64_HP_SIM is not set
-# CONFIG_IA64_SGI_SN1 is not set
-# CONFIG_IA64_SGI_SN2 is not set
-# CONFIG_IA64_PAGE_SIZE_4KB is not set
-# CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
-CONFIG_IA64_BRL_EMU=y
-CONFIG_ITANIUM_BSTEP_SPECIFIC=y
-CONFIG_IA64_L1_CACHE_SHIFT=6
-# CONFIG_NUMA is not set
-# CONFIG_IA64_MCA is not set
-CONFIG_PM=y
-CONFIG_IA64_HAVE_SYNCRONIZED_ITC=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_DEBUG=y
-CONFIG_KCORE_ELF=y
-CONFIG_SMP=y
-CONFIG_IA32_SUPPORT=y
-CONFIG_PERFMON=y
-CONFIG_IA64_PALINFO=y
-# CONFIG_EFI_VARS is not set
-CONFIG_NET=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_ACPI_DEBUG is not set
-# CONFIG_ACPI_BUSMGR is not set
-# CONFIG_ACPI_SYS is not set
-# CONFIG_ACPI_CPU is not set
-# CONFIG_ACPI_BUTTON is not set
-# CONFIG_ACPI_AC is not set
-# CONFIG_ACPI_EC is not set
-# CONFIG_ACPI_CMBATT is not set
-# CONFIG_ACPI_THERMAL is not set
-CONFIG_PCI=y
-# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Networking options
-#
-# CONFIG_PACKET is not set
-# CONFIG_NETLINK is not set
-# CONFIG_NETFILTER is not set
-# CONFIG_FILTER is not set
-CONFIG_UNIX=y
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE 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
-
-#
-#  
-#
-# CONFIG_IPX is not set
-# 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
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-# CONFIG_PNPBIOS is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_LAN is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
-# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
-# CONFIG_BLK_DEV_IDEDISK_IBM is not set
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
-# CONFIG_BLK_DEV_IDECS is not set
-CONFIG_BLK_DEV_IDECD=y
-# CONFIG_BLK_DEV_IDETAPE is not set
-CONFIG_BLK_DEV_IDEFLOPPY=y
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-CONFIG_BLK_DEV_IDEPCI=y
-# CONFIG_IDEPCI_SHARE_IRQ is not set
-CONFIG_BLK_DEV_IDEDMA_PCI=y
-CONFIG_BLK_DEV_ADMA=y
-# CONFIG_BLK_DEV_OFFBOARD is not set
-# CONFIG_IDEDMA_PCI_AUTO is not set
-CONFIG_BLK_DEV_IDEDMA=y
-# CONFIG_IDEDMA_PCI_WIP is not set
-# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
-# CONFIG_BLK_DEV_AEC62XX is not set
-# CONFIG_AEC62XX_TUNING is not set
-# CONFIG_BLK_DEV_ALI15X3 is not set
-# CONFIG_WDC_ALI15X3 is not set
-# CONFIG_BLK_DEV_AMD74XX is not set
-# CONFIG_AMD74XX_OVERRIDE is not set
-# CONFIG_BLK_DEV_CMD64X is not set
-# CONFIG_BLK_DEV_CY82C693 is not set
-# CONFIG_BLK_DEV_CS5530 is not set
-# CONFIG_BLK_DEV_HPT34X is not set
-# CONFIG_HPT34X_AUTODMA is not set
-# CONFIG_BLK_DEV_HPT366 is not set
-# CONFIG_BLK_DEV_PIIX is not set
-# CONFIG_PIIX_TUNING is not set
-# CONFIG_BLK_DEV_NS87415 is not set
-# CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_PDC202XX is not set
-# CONFIG_PDC202XX_BURST is not set
-# CONFIG_PDC202XX_FORCE is not set
-# CONFIG_BLK_DEV_SVWKS is not set
-# CONFIG_BLK_DEV_SIS5513 is not set
-# CONFIG_BLK_DEV_SLC90E66 is not set
-# CONFIG_BLK_DEV_TRM290 is not set
-# CONFIG_BLK_DEV_VIA82CXXX is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_IDEDMA_IVB is not set
-# CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
-
-#
-# Alternate 1394 support
-#
-# CONFIG_X1394 is not set
-
-#
-# Alternate SCSI support
-#
-# CONFIG_XSCSI is not set
-
-#
-# SCSI support
-#
-CONFIG_SCSI=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-CONFIG_SD_EXTRA_DEVS=40
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-# 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=y
-CONFIG_SCSI_CONSTANTS=y
-CONFIG_SCSI_LOGGING=y
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# 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_DPT_I2O 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_CPQFCTS 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_NCR53C8XX is not set
-# CONFIG_SCSI_SYM53C8XX is not set
-# CONFIG_SCSI_PAS16 is not set
-# CONFIG_SCSI_PCI2000 is not set
-# CONFIG_SCSI_PCI2220I is not set
-# CONFIG_SCSI_PSI240I is not set
-# CONFIG_SCSI_QLOGIC_FAS is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
-# CONFIG_SCSI_QLOGIC_FC is not set
-CONFIG_SCSI_QLOGIC_1280=y
-# CONFIG_SCSI_QLOGIC_QLA2100 is not set
-# CONFIG_SCSI_SIM710 is not set
-# CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_T128 is not set
-# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_DEBUG is not set
-
-#
-# Network device support
-#
-CONFIG_NETDEVICES=y
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-CONFIG_DUMMY=y
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-# CONFIG_SUNLANCE is not set
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNBMAC is not set
-# CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
-# CONFIG_SUNGEM is not set
-# 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_HP100 is not set
-# CONFIG_NET_ISA is not set
-CONFIG_NET_PCI=y
-# CONFIG_PCNET32 is not set
-# CONFIG_ADAPTEC_STARFIRE is not set
-# CONFIG_APRICOT is not set
-# CONFIG_CS89x0 is not set
-# CONFIG_TULIP is not set
-# CONFIG_DE4X5 is not set
-# CONFIG_DGRS is not set
-# CONFIG_DM9102 is not set
-CONFIG_EEPRO100=y
-# CONFIG_LNE390 is not set
-# CONFIG_FEALNX is not set
-# CONFIG_NATSEMI is not set
-# CONFIG_NE2K_PCI is not set
-# CONFIG_NE3210 is not set
-# CONFIG_ES3210 is not set
-# CONFIG_8139CP is not set
-# CONFIG_8139TOO is not set
-# CONFIG_8139TOO_PIO is not set
-# CONFIG_8139TOO_TUNE_TWISTER is not set
-# CONFIG_8139TOO_8129 is not set
-# CONFIG_SIS900 is not set
-# CONFIG_EPIC100 is not set
-# CONFIG_SUNDANCE is not set
-# CONFIG_TLAN is not set
-# CONFIG_VIA_RHINE is not set
-# CONFIG_WINBOND_840 is not set
-# CONFIG_NET_POCKET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_MYRI_SBUS is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PLIP is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices
-#
-# 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
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_SERIAL=y
-CONFIG_SERIAL_CONSOLE=y
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-CONFIG_MOUSE=y
-CONFIG_PSMOUSE=y
-# CONFIG_82C710_MOUSE is not set
-# CONFIG_PC110_PAD is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
-
-#
-# Input core support is needed for joysticks
-#
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-# CONFIG_EFI_RTC is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_MWAVE is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# File systems
-#
-# CONFIG_QUOTA 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
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BFS_FS is not set
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
-# CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=y
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-# CONFIG_RAMFS is not set
-CONFIG_ISO9660_FS=y
-CONFIG_JOLIET=y
-# 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
-CONFIG_PROC_FS=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_MOUNT=y
-CONFIG_DEVFS_DEBUG=y
-CONFIG_DEVPTS_FS=y
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-# CONFIG_XFS_SUPPORT is not set
-
-#
-# Network File Systems
-#
-# CONFIG_CODA_FS is not set
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-# CONFIG_ROOT_NFS is not set
-CONFIG_NFSD=y
-CONFIG_NFSD_V3=y
-CONFIG_SUNRPC=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-# CONFIG_SMB_FS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_NCPFS_PACKET_SIGNING is not set
-# CONFIG_NCPFS_IOCTL_LOCKING is not set
-# CONFIG_NCPFS_STRONG is not set
-# CONFIG_NCPFS_NFS_NS is not set
-# CONFIG_NCPFS_OS2_NS is not set
-# CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_NCPFS_EXTRAS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-CONFIG_NLS=y
-
-#
-# Native Language Support
-#
-CONFIG_NLS_DEFAULT="iso8859-1"
-# CONFIG_NLS_CODEPAGE_437 is not set
-# CONFIG_NLS_CODEPAGE_737 is not set
-# CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
-# CONFIG_NLS_CODEPAGE_852 is not set
-# CONFIG_NLS_CODEPAGE_855 is not set
-# CONFIG_NLS_CODEPAGE_857 is not set
-# CONFIG_NLS_CODEPAGE_860 is not set
-# CONFIG_NLS_CODEPAGE_861 is not set
-# CONFIG_NLS_CODEPAGE_862 is not set
-# CONFIG_NLS_CODEPAGE_863 is not set
-# CONFIG_NLS_CODEPAGE_864 is not set
-# CONFIG_NLS_CODEPAGE_865 is not set
-# CONFIG_NLS_CODEPAGE_866 is not set
-# CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_936 is not set
-# CONFIG_NLS_CODEPAGE_950 is not set
-# CONFIG_NLS_CODEPAGE_932 is not set
-# CONFIG_NLS_CODEPAGE_949 is not set
-# CONFIG_NLS_CODEPAGE_874 is not set
-# CONFIG_NLS_ISO8859_8 is not set
-# CONFIG_NLS_CODEPAGE_1251 is not set
-# CONFIG_NLS_ISO8859_1 is not set
-# CONFIG_NLS_ISO8859_2 is not set
-# CONFIG_NLS_ISO8859_3 is not set
-# CONFIG_NLS_ISO8859_4 is not set
-# CONFIG_NLS_ISO8859_5 is not set
-# CONFIG_NLS_ISO8859_6 is not set
-# CONFIG_NLS_ISO8859_7 is not set
-# CONFIG_NLS_ISO8859_9 is not set
-# CONFIG_NLS_ISO8859_13 is not set
-# CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
-# CONFIG_NLS_KOI8_R is not set
-# CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
-
-#
-# Console drivers
-#
-CONFIG_VGA_CONSOLE=y
-
-#
-# Frame-buffer support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BLUEZ is not set
-
-#
-# Kernel hacking
-#
-CONFIG_DEBUG_KERNEL=y
-CONFIG_IA64_PRINT_HAZARDS=y
-# CONFIG_DISABLE_VHPT is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_IA64_EARLY_PRINTK=y
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_IA64_DEBUG_CMPXCHG is not set
-# CONFIG_IA64_DEBUG_IRQ is not set
-CONFIG_KDB=y
-CONFIG_KDB_MODULES=y
-# CONFIG_KDB_OFF is not set
-
-#
-#   Load all symbols for debugging is required for KDB
-#
-CONFIG_KALLSYMS=y
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-bigsur-sp linux-2.4.21-pre6/arch/ia64/sn/configs/sn1/defconfig-bigsur-sp
--- linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-bigsur-sp	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/configs/sn1/defconfig-bigsur-sp	1970-01-01 00:00:00.000000000 +0000
@@ -1,772 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# General setup
-#
-CONFIG_IA64=y
-# CONFIG_ISA is not set
-# CONFIG_EISA is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_ACPI=y
-CONFIG_ACPI_EFI=y
-CONFIG_ACPI_INTERPRETER=y
-CONFIG_ACPI_KERNEL_CONFIG=y
-CONFIG_ITANIUM=y
-# CONFIG_MCKINLEY is not set
-# CONFIG_IA64_GENERIC is not set
-CONFIG_IA64_DIG=y
-# CONFIG_IA64_HP_SIM is not set
-# CONFIG_IA64_SGI_SN1 is not set
-# CONFIG_IA64_SGI_SN2 is not set
-# CONFIG_IA64_PAGE_SIZE_4KB is not set
-# CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
-CONFIG_IA64_BRL_EMU=y
-CONFIG_ITANIUM_BSTEP_SPECIFIC=y
-CONFIG_IA64_L1_CACHE_SHIFT=6
-# CONFIG_NUMA is not set
-# CONFIG_IA64_MCA is not set
-CONFIG_PM=y
-CONFIG_IA64_HAVE_SYNCRONIZED_ITC=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_DEBUG=y
-CONFIG_KCORE_ELF=y
-# CONFIG_SMP is not set
-CONFIG_IA32_SUPPORT=y
-CONFIG_PERFMON=y
-CONFIG_IA64_PALINFO=y
-# CONFIG_EFI_VARS is not set
-CONFIG_NET=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_ACPI_DEBUG is not set
-# CONFIG_ACPI_BUSMGR is not set
-# CONFIG_ACPI_SYS is not set
-# CONFIG_ACPI_CPU is not set
-# CONFIG_ACPI_BUTTON is not set
-# CONFIG_ACPI_AC is not set
-# CONFIG_ACPI_EC is not set
-# CONFIG_ACPI_CMBATT is not set
-# CONFIG_ACPI_THERMAL is not set
-CONFIG_PCI=y
-# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Networking options
-#
-# CONFIG_PACKET is not set
-# CONFIG_NETLINK is not set
-# CONFIG_NETFILTER is not set
-# CONFIG_FILTER is not set
-CONFIG_UNIX=y
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE 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
-
-#
-#  
-#
-# CONFIG_IPX is not set
-# 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
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-# CONFIG_PNPBIOS is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_LAN is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
-# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
-# CONFIG_BLK_DEV_IDEDISK_IBM is not set
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
-# CONFIG_BLK_DEV_IDECS is not set
-CONFIG_BLK_DEV_IDECD=y
-# CONFIG_BLK_DEV_IDETAPE is not set
-CONFIG_BLK_DEV_IDEFLOPPY=y
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-CONFIG_BLK_DEV_IDEPCI=y
-# CONFIG_IDEPCI_SHARE_IRQ is not set
-CONFIG_BLK_DEV_IDEDMA_PCI=y
-CONFIG_BLK_DEV_ADMA=y
-# CONFIG_BLK_DEV_OFFBOARD is not set
-# CONFIG_IDEDMA_PCI_AUTO is not set
-CONFIG_BLK_DEV_IDEDMA=y
-# CONFIG_IDEDMA_PCI_WIP is not set
-# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
-# CONFIG_BLK_DEV_AEC62XX is not set
-# CONFIG_AEC62XX_TUNING is not set
-# CONFIG_BLK_DEV_ALI15X3 is not set
-# CONFIG_WDC_ALI15X3 is not set
-# CONFIG_BLK_DEV_AMD74XX is not set
-# CONFIG_AMD74XX_OVERRIDE is not set
-# CONFIG_BLK_DEV_CMD64X is not set
-# CONFIG_BLK_DEV_CY82C693 is not set
-# CONFIG_BLK_DEV_CS5530 is not set
-# CONFIG_BLK_DEV_HPT34X is not set
-# CONFIG_HPT34X_AUTODMA is not set
-# CONFIG_BLK_DEV_HPT366 is not set
-# CONFIG_BLK_DEV_PIIX is not set
-# CONFIG_PIIX_TUNING is not set
-# CONFIG_BLK_DEV_NS87415 is not set
-# CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_PDC202XX is not set
-# CONFIG_PDC202XX_BURST is not set
-# CONFIG_PDC202XX_FORCE is not set
-# CONFIG_BLK_DEV_SVWKS is not set
-# CONFIG_BLK_DEV_SIS5513 is not set
-# CONFIG_BLK_DEV_SLC90E66 is not set
-# CONFIG_BLK_DEV_TRM290 is not set
-# CONFIG_BLK_DEV_VIA82CXXX is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_IDEDMA_IVB is not set
-# CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
-
-#
-# Alternate 1394 support
-#
-# CONFIG_X1394 is not set
-
-#
-# Alternate SCSI support
-#
-# CONFIG_XSCSI is not set
-
-#
-# SCSI support
-#
-CONFIG_SCSI=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-CONFIG_SD_EXTRA_DEVS=40
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-# 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=y
-CONFIG_SCSI_CONSTANTS=y
-CONFIG_SCSI_LOGGING=y
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# 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_DPT_I2O 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_CPQFCTS 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_NCR53C8XX is not set
-# CONFIG_SCSI_SYM53C8XX is not set
-# CONFIG_SCSI_PAS16 is not set
-# CONFIG_SCSI_PCI2000 is not set
-# CONFIG_SCSI_PCI2220I is not set
-# CONFIG_SCSI_PSI240I is not set
-# CONFIG_SCSI_QLOGIC_FAS is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
-# CONFIG_SCSI_QLOGIC_FC is not set
-CONFIG_SCSI_QLOGIC_1280=y
-# CONFIG_SCSI_QLOGIC_QLA2100 is not set
-# CONFIG_SCSI_SIM710 is not set
-# CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_T128 is not set
-# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_DEBUG is not set
-
-#
-# Network device support
-#
-CONFIG_NETDEVICES=y
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-CONFIG_DUMMY=y
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-# CONFIG_SUNLANCE is not set
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNBMAC is not set
-# CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
-# CONFIG_SUNGEM is not set
-# 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_HP100 is not set
-# CONFIG_NET_ISA is not set
-CONFIG_NET_PCI=y
-# CONFIG_PCNET32 is not set
-# CONFIG_ADAPTEC_STARFIRE is not set
-# CONFIG_APRICOT is not set
-# CONFIG_CS89x0 is not set
-# CONFIG_TULIP is not set
-# CONFIG_DE4X5 is not set
-# CONFIG_DGRS is not set
-# CONFIG_DM9102 is not set
-CONFIG_EEPRO100=y
-# CONFIG_LNE390 is not set
-# CONFIG_FEALNX is not set
-# CONFIG_NATSEMI is not set
-# CONFIG_NE2K_PCI is not set
-# CONFIG_NE3210 is not set
-# CONFIG_ES3210 is not set
-# CONFIG_8139CP is not set
-# CONFIG_8139TOO is not set
-# CONFIG_8139TOO_PIO is not set
-# CONFIG_8139TOO_TUNE_TWISTER is not set
-# CONFIG_8139TOO_8129 is not set
-# CONFIG_SIS900 is not set
-# CONFIG_EPIC100 is not set
-# CONFIG_SUNDANCE is not set
-# CONFIG_TLAN is not set
-# CONFIG_VIA_RHINE is not set
-# CONFIG_WINBOND_840 is not set
-# CONFIG_NET_POCKET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_MYRI_SBUS is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PLIP is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices
-#
-# 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
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_SERIAL=y
-CONFIG_SERIAL_CONSOLE=y
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-CONFIG_MOUSE=y
-CONFIG_PSMOUSE=y
-# CONFIG_82C710_MOUSE is not set
-# CONFIG_PC110_PAD is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
-
-#
-# Input core support is needed for joysticks
-#
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-# CONFIG_EFI_RTC is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_MWAVE is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# File systems
-#
-# CONFIG_QUOTA 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
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BFS_FS is not set
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
-# CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=y
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-# CONFIG_RAMFS is not set
-CONFIG_ISO9660_FS=y
-CONFIG_JOLIET=y
-# 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
-CONFIG_PROC_FS=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_MOUNT=y
-CONFIG_DEVFS_DEBUG=y
-CONFIG_DEVPTS_FS=y
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-# CONFIG_XFS_SUPPORT is not set
-
-#
-# Network File Systems
-#
-# CONFIG_CODA_FS is not set
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-# CONFIG_ROOT_NFS is not set
-CONFIG_NFSD=y
-CONFIG_NFSD_V3=y
-CONFIG_SUNRPC=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-# CONFIG_SMB_FS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_NCPFS_PACKET_SIGNING is not set
-# CONFIG_NCPFS_IOCTL_LOCKING is not set
-# CONFIG_NCPFS_STRONG is not set
-# CONFIG_NCPFS_NFS_NS is not set
-# CONFIG_NCPFS_OS2_NS is not set
-# CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_NCPFS_EXTRAS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-CONFIG_NLS=y
-
-#
-# Native Language Support
-#
-CONFIG_NLS_DEFAULT="iso8859-1"
-# CONFIG_NLS_CODEPAGE_437 is not set
-# CONFIG_NLS_CODEPAGE_737 is not set
-# CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
-# CONFIG_NLS_CODEPAGE_852 is not set
-# CONFIG_NLS_CODEPAGE_855 is not set
-# CONFIG_NLS_CODEPAGE_857 is not set
-# CONFIG_NLS_CODEPAGE_860 is not set
-# CONFIG_NLS_CODEPAGE_861 is not set
-# CONFIG_NLS_CODEPAGE_862 is not set
-# CONFIG_NLS_CODEPAGE_863 is not set
-# CONFIG_NLS_CODEPAGE_864 is not set
-# CONFIG_NLS_CODEPAGE_865 is not set
-# CONFIG_NLS_CODEPAGE_866 is not set
-# CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_936 is not set
-# CONFIG_NLS_CODEPAGE_950 is not set
-# CONFIG_NLS_CODEPAGE_932 is not set
-# CONFIG_NLS_CODEPAGE_949 is not set
-# CONFIG_NLS_CODEPAGE_874 is not set
-# CONFIG_NLS_ISO8859_8 is not set
-# CONFIG_NLS_CODEPAGE_1251 is not set
-# CONFIG_NLS_ISO8859_1 is not set
-# CONFIG_NLS_ISO8859_2 is not set
-# CONFIG_NLS_ISO8859_3 is not set
-# CONFIG_NLS_ISO8859_4 is not set
-# CONFIG_NLS_ISO8859_5 is not set
-# CONFIG_NLS_ISO8859_6 is not set
-# CONFIG_NLS_ISO8859_7 is not set
-# CONFIG_NLS_ISO8859_9 is not set
-# CONFIG_NLS_ISO8859_13 is not set
-# CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
-# CONFIG_NLS_KOI8_R is not set
-# CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
-
-#
-# Console drivers
-#
-CONFIG_VGA_CONSOLE=y
-
-#
-# Frame-buffer support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BLUEZ is not set
-
-#
-# Kernel hacking
-#
-CONFIG_DEBUG_KERNEL=y
-CONFIG_IA64_PRINT_HAZARDS=y
-# CONFIG_DISABLE_VHPT is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_IA64_EARLY_PRINTK=y
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_IA64_DEBUG_CMPXCHG is not set
-# CONFIG_IA64_DEBUG_IRQ is not set
-# CONFIG_KDB is not set
-# CONFIG_KDB_MODULES is not set
-# CONFIG_KALLSYMS is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-dig-mp linux-2.4.21-pre6/arch/ia64/sn/configs/sn1/defconfig-dig-mp
--- linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-dig-mp	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/configs/sn1/defconfig-dig-mp	1970-01-01 00:00:00.000000000 +0000
@@ -1,459 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-
-#
-# Code maturity level options
-#
-# CONFIG_EXPERIMENTAL is not set
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# General setup
-#
-CONFIG_IA64=y
-# CONFIG_ISA is not set
-# CONFIG_EISA is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_ACPI=y
-CONFIG_ACPI_EFI=y
-CONFIG_ACPI_INTERPRETER=y
-CONFIG_ACPI_KERNEL_CONFIG=y
-CONFIG_ITANIUM=y
-# CONFIG_MCKINLEY is not set
-# CONFIG_IA64_GENERIC is not set
-CONFIG_IA64_DIG=y
-# CONFIG_IA64_HP_SIM is not set
-# CONFIG_IA64_SGI_SN1 is not set
-# CONFIG_IA64_SGI_SN2 is not set
-# CONFIG_IA64_PAGE_SIZE_4KB is not set
-# CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
-CONFIG_IA64_BRL_EMU=y
-CONFIG_ITANIUM_BSTEP_SPECIFIC=y
-CONFIG_IA64_L1_CACHE_SHIFT=6
-# CONFIG_NUMA is not set
-# CONFIG_IA64_MCA is not set
-CONFIG_PM=y
-CONFIG_IA64_HAVE_SYNCRONIZED_ITC=y
-# CONFIG_DEVFS_FS is not set
-CONFIG_KCORE_ELF=y
-CONFIG_SMP=y
-# CONFIG_IA32_SUPPORT is not set
-# CONFIG_PERFMON is not set
-# CONFIG_IA64_PALINFO is not set
-# CONFIG_EFI_VARS is not set
-# CONFIG_NET is not set
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_SYSCTL is not set
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_ACPI_DEBUG is not set
-# CONFIG_ACPI_BUSMGR is not set
-# CONFIG_ACPI_SYS is not set
-# CONFIG_ACPI_CPU is not set
-# CONFIG_ACPI_BUTTON is not set
-# CONFIG_ACPI_AC is not set
-# CONFIG_ACPI_EC is not set
-# CONFIG_ACPI_CMBATT is not set
-# CONFIG_ACPI_THERMAL is not set
-CONFIG_PCI=y
-# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
-# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
-# CONFIG_BLK_DEV_IDEDISK_IBM is not set
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
-# CONFIG_BLK_DEV_IDECS is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
-
-#
-# Alternate 1394 support
-#
-# CONFIG_X1394 is not set
-
-#
-# Alternate SCSI support
-#
-# CONFIG_XSCSI is not set
-
-#
-# SCSI support
-#
-# CONFIG_SCSI is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-# CONFIG_SERIAL is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
-
-#
-# Input core support is needed for joysticks
-#
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-# CONFIG_EFI_RTC is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_MWAVE is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# File systems
-#
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_FAT_FS is not set
-# CONFIG_MSDOS_FS is not set
-# CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-# 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
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVFS_MOUNT is not set
-# CONFIG_DEVFS_DEBUG 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
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-# CONFIG_XFS_SUPPORT is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_SMB_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-# CONFIG_NLS is not set
-
-#
-# Console drivers
-#
-CONFIG_VGA_CONSOLE=y
-
-#
-# Frame-buffer support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-
-#
-#   Networking support is needed for USB Networking device support
-#
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
-# Kernel hacking
-#
-CONFIG_DEBUG_KERNEL=y
-CONFIG_IA64_PRINT_HAZARDS=y
-# CONFIG_DISABLE_VHPT is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_IA64_EARLY_PRINTK=y
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_IA64_DEBUG_CMPXCHG is not set
-# CONFIG_IA64_DEBUG_IRQ is not set
-# CONFIG_KDB is not set
-# CONFIG_KDB_MODULES is not set
-# CONFIG_KALLSYMS is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-dig-sp linux-2.4.21-pre6/arch/ia64/sn/configs/sn1/defconfig-dig-sp
--- linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-dig-sp	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/configs/sn1/defconfig-dig-sp	1970-01-01 00:00:00.000000000 +0000
@@ -1,459 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-
-#
-# Code maturity level options
-#
-# CONFIG_EXPERIMENTAL is not set
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# General setup
-#
-CONFIG_IA64=y
-# CONFIG_ISA is not set
-# CONFIG_EISA is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_ACPI=y
-CONFIG_ACPI_EFI=y
-CONFIG_ACPI_INTERPRETER=y
-CONFIG_ACPI_KERNEL_CONFIG=y
-CONFIG_ITANIUM=y
-# CONFIG_MCKINLEY is not set
-# CONFIG_IA64_GENERIC is not set
-CONFIG_IA64_DIG=y
-# CONFIG_IA64_HP_SIM is not set
-# CONFIG_IA64_SGI_SN1 is not set
-# CONFIG_IA64_SGI_SN2 is not set
-# CONFIG_IA64_PAGE_SIZE_4KB is not set
-# CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
-CONFIG_IA64_BRL_EMU=y
-CONFIG_ITANIUM_BSTEP_SPECIFIC=y
-CONFIG_IA64_L1_CACHE_SHIFT=6
-# CONFIG_NUMA is not set
-# CONFIG_IA64_MCA is not set
-CONFIG_PM=y
-CONFIG_IA64_HAVE_SYNCRONIZED_ITC=y
-# CONFIG_DEVFS_FS is not set
-CONFIG_KCORE_ELF=y
-# CONFIG_SMP is not set
-# CONFIG_IA32_SUPPORT is not set
-# CONFIG_PERFMON is not set
-# CONFIG_IA64_PALINFO is not set
-# CONFIG_EFI_VARS is not set
-# CONFIG_NET is not set
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_SYSCTL is not set
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_ACPI_DEBUG is not set
-# CONFIG_ACPI_BUSMGR is not set
-# CONFIG_ACPI_SYS is not set
-# CONFIG_ACPI_CPU is not set
-# CONFIG_ACPI_BUTTON is not set
-# CONFIG_ACPI_AC is not set
-# CONFIG_ACPI_EC is not set
-# CONFIG_ACPI_CMBATT is not set
-# CONFIG_ACPI_THERMAL is not set
-CONFIG_PCI=y
-# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
-# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
-# CONFIG_BLK_DEV_IDEDISK_IBM is not set
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
-# CONFIG_BLK_DEV_IDECS is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
-
-#
-# Alternate 1394 support
-#
-# CONFIG_X1394 is not set
-
-#
-# Alternate SCSI support
-#
-# CONFIG_XSCSI is not set
-
-#
-# SCSI support
-#
-# CONFIG_SCSI is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-# CONFIG_SERIAL is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
-
-#
-# Input core support is needed for joysticks
-#
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-# CONFIG_EFI_RTC is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_MWAVE is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# File systems
-#
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_FAT_FS is not set
-# CONFIG_MSDOS_FS is not set
-# CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-# 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
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVFS_MOUNT is not set
-# CONFIG_DEVFS_DEBUG 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
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-# CONFIG_XFS_SUPPORT is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_SMB_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-# CONFIG_NLS is not set
-
-#
-# Console drivers
-#
-CONFIG_VGA_CONSOLE=y
-
-#
-# Frame-buffer support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-
-#
-#   Networking support is needed for USB Networking device support
-#
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
-# Kernel hacking
-#
-CONFIG_DEBUG_KERNEL=y
-CONFIG_IA64_PRINT_HAZARDS=y
-# CONFIG_DISABLE_VHPT is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_IA64_EARLY_PRINTK=y
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_IA64_DEBUG_CMPXCHG is not set
-# CONFIG_IA64_DEBUG_IRQ is not set
-# CONFIG_KDB is not set
-# CONFIG_KDB_MODULES is not set
-# CONFIG_KALLSYMS is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-generic-mp linux-2.4.21-pre6/arch/ia64/sn/configs/sn1/defconfig-generic-mp
--- linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-generic-mp	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/configs/sn1/defconfig-generic-mp	1970-01-01 00:00:00.000000000 +0000
@@ -1,460 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-
-#
-# Code maturity level options
-#
-# CONFIG_EXPERIMENTAL is not set
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# General setup
-#
-CONFIG_IA64=y
-# CONFIG_ISA is not set
-# CONFIG_EISA is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_ACPI=y
-CONFIG_ACPI_EFI=y
-CONFIG_ACPI_INTERPRETER=y
-CONFIG_ACPI_KERNEL_CONFIG=y
-CONFIG_ITANIUM=y
-# CONFIG_MCKINLEY is not set
-CONFIG_IA64_GENERIC=y
-# CONFIG_IA64_DIG is not set
-# CONFIG_IA64_HP_SIM is not set
-# CONFIG_IA64_SGI_SN1 is not set
-# CONFIG_IA64_SGI_SN2 is not set
-# CONFIG_IA64_PAGE_SIZE_4KB is not set
-# CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
-CONFIG_IA64_BRL_EMU=y
-CONFIG_ITANIUM_BSTEP_SPECIFIC=y
-CONFIG_IA64_L1_CACHE_SHIFT=6
-CONFIG_KCORE_ELF=y
-CONFIG_SMP=y
-# CONFIG_IA32_SUPPORT is not set
-CONFIG_PERFMON=y
-CONFIG_IA64_PALINFO=y
-# CONFIG_EFI_VARS is not set
-# CONFIG_NET is not set
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_SYSCTL is not set
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_ACPI_DEBUG is not set
-# CONFIG_ACPI_BUSMGR is not set
-# CONFIG_ACPI_SYS is not set
-# CONFIG_ACPI_CPU is not set
-# CONFIG_ACPI_BUTTON is not set
-# CONFIG_ACPI_AC is not set
-# CONFIG_ACPI_EC is not set
-# CONFIG_ACPI_CMBATT is not set
-# CONFIG_ACPI_THERMAL is not set
-CONFIG_PCI=y
-# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
-# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
-# CONFIG_BLK_DEV_IDEDISK_IBM is not set
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
-# CONFIG_BLK_DEV_IDECS is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
-
-#
-# Alternate 1394 support
-#
-# CONFIG_X1394 is not set
-
-#
-# Alternate SCSI support
-#
-# CONFIG_XSCSI is not set
-
-#
-# SCSI support
-#
-# CONFIG_SCSI is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-# CONFIG_SERIAL is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
-
-#
-# Input core support is needed for joysticks
-#
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-# CONFIG_EFI_RTC is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_MWAVE is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# File systems
-#
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_FAT_FS is not set
-# CONFIG_MSDOS_FS is not set
-# CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-# 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
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVFS_MOUNT is not set
-# CONFIG_DEVFS_DEBUG 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
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-# CONFIG_XFS_SUPPORT is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_SMB_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-# CONFIG_NLS is not set
-
-#
-# Console drivers
-#
-CONFIG_VGA_CONSOLE=y
-
-#
-# Frame-buffer support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-
-#
-#   Networking support is needed for USB Networking device support
-#
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
-# Simulated drivers
-#
-# CONFIG_SIMETH is not set
-# CONFIG_SIM_SERIAL is not set
-
-#
-# Kernel hacking
-#
-CONFIG_DEBUG_KERNEL=y
-CONFIG_IA64_PRINT_HAZARDS=y
-# CONFIG_DISABLE_VHPT is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_IA64_EARLY_PRINTK=y
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_IA64_DEBUG_CMPXCHG is not set
-# CONFIG_IA64_DEBUG_IRQ is not set
-# CONFIG_KDB is not set
-# CONFIG_KDB_MODULES is not set
-# CONFIG_KALLSYMS is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-generic-sp linux-2.4.21-pre6/arch/ia64/sn/configs/sn1/defconfig-generic-sp
--- linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-generic-sp	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/configs/sn1/defconfig-generic-sp	1970-01-01 00:00:00.000000000 +0000
@@ -1,460 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-
-#
-# Code maturity level options
-#
-# CONFIG_EXPERIMENTAL is not set
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# General setup
-#
-CONFIG_IA64=y
-# CONFIG_ISA is not set
-# CONFIG_EISA is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_ACPI=y
-CONFIG_ACPI_EFI=y
-CONFIG_ACPI_INTERPRETER=y
-CONFIG_ACPI_KERNEL_CONFIG=y
-CONFIG_ITANIUM=y
-# CONFIG_MCKINLEY is not set
-CONFIG_IA64_GENERIC=y
-# CONFIG_IA64_DIG is not set
-# CONFIG_IA64_HP_SIM is not set
-# CONFIG_IA64_SGI_SN1 is not set
-# CONFIG_IA64_SGI_SN2 is not set
-# CONFIG_IA64_PAGE_SIZE_4KB is not set
-# CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
-CONFIG_IA64_BRL_EMU=y
-CONFIG_ITANIUM_BSTEP_SPECIFIC=y
-CONFIG_IA64_L1_CACHE_SHIFT=6
-CONFIG_KCORE_ELF=y
-# CONFIG_SMP is not set
-# CONFIG_IA32_SUPPORT is not set
-CONFIG_PERFMON=y
-CONFIG_IA64_PALINFO=y
-# CONFIG_EFI_VARS is not set
-# CONFIG_NET is not set
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_SYSCTL is not set
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_ACPI_DEBUG is not set
-# CONFIG_ACPI_BUSMGR is not set
-# CONFIG_ACPI_SYS is not set
-# CONFIG_ACPI_CPU is not set
-# CONFIG_ACPI_BUTTON is not set
-# CONFIG_ACPI_AC is not set
-# CONFIG_ACPI_EC is not set
-# CONFIG_ACPI_CMBATT is not set
-# CONFIG_ACPI_THERMAL is not set
-CONFIG_PCI=y
-# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
-# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
-# CONFIG_BLK_DEV_IDEDISK_IBM is not set
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
-# CONFIG_BLK_DEV_IDECS is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
-
-#
-# Alternate 1394 support
-#
-# CONFIG_X1394 is not set
-
-#
-# Alternate SCSI support
-#
-# CONFIG_XSCSI is not set
-
-#
-# SCSI support
-#
-# CONFIG_SCSI is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-# CONFIG_SERIAL is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
-
-#
-# Input core support is needed for joysticks
-#
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-# CONFIG_EFI_RTC is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_MWAVE is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# File systems
-#
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_FAT_FS is not set
-# CONFIG_MSDOS_FS is not set
-# CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-# 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
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVFS_MOUNT is not set
-# CONFIG_DEVFS_DEBUG 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
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-# CONFIG_XFS_SUPPORT is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_SMB_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-# CONFIG_NLS is not set
-
-#
-# Console drivers
-#
-CONFIG_VGA_CONSOLE=y
-
-#
-# Frame-buffer support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-
-#
-#   Networking support is needed for USB Networking device support
-#
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
-# Simulated drivers
-#
-# CONFIG_SIMETH is not set
-# CONFIG_SIM_SERIAL is not set
-
-#
-# Kernel hacking
-#
-CONFIG_DEBUG_KERNEL=y
-CONFIG_IA64_PRINT_HAZARDS=y
-# CONFIG_DISABLE_VHPT is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_IA64_EARLY_PRINTK=y
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_IA64_DEBUG_CMPXCHG is not set
-# CONFIG_IA64_DEBUG_IRQ is not set
-# CONFIG_KDB is not set
-# CONFIG_KDB_MODULES is not set
-# CONFIG_KALLSYMS is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-hp-sp linux-2.4.21-pre6/arch/ia64/sn/configs/sn1/defconfig-hp-sp
--- linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-hp-sp	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/configs/sn1/defconfig-hp-sp	1970-01-01 00:00:00.000000000 +0000
@@ -1,334 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-
-#
-# Code maturity level options
-#
-# CONFIG_EXPERIMENTAL is not set
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# General setup
-#
-CONFIG_IA64=y
-# CONFIG_ISA is not set
-# CONFIG_EISA is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_ITANIUM=y
-# CONFIG_MCKINLEY is not set
-# CONFIG_IA64_GENERIC is not set
-# CONFIG_IA64_DIG is not set
-CONFIG_IA64_HP_SIM=y
-# CONFIG_IA64_SGI_SN1 is not set
-# CONFIG_IA64_SGI_SN2 is not set
-# CONFIG_IA64_PAGE_SIZE_4KB is not set
-# CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
-CONFIG_IA64_BRL_EMU=y
-CONFIG_ITANIUM_BSTEP_SPECIFIC=y
-CONFIG_IA64_L1_CACHE_SHIFT=6
-CONFIG_KCORE_ELF=y
-# CONFIG_SMP is not set
-# CONFIG_IA32_SUPPORT is not set
-# CONFIG_PERFMON is not set
-# CONFIG_IA64_PALINFO is not set
-# CONFIG_EFI_VARS is not set
-CONFIG_NET=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-
-#
-# Networking options
-#
-# CONFIG_PACKET is not set
-# CONFIG_NETLINK is not set
-# CONFIG_NETFILTER is not set
-# CONFIG_FILTER is not set
-CONFIG_UNIX=y
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_INET_ECN is not set
-# CONFIG_SYN_COOKIES is not set
-
-#
-#  
-#
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Alternate 1394 support
-#
-# CONFIG_X1394 is not set
-
-#
-# Alternate SCSI support
-#
-# CONFIG_XSCSI is not set
-
-#
-# SCSI support
-#
-CONFIG_SCSI=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-CONFIG_SD_EXTRA_DEVS=40
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-# 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_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_DPT_I2O 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_PPA is not set
-# CONFIG_SCSI_IMM 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
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-# CONFIG_SERIAL is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-# CONFIG_PRINTER is not set
-# CONFIG_PPDEV is not set
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
-
-#
-# Input core support is needed for joysticks
-#
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-CONFIG_EFI_RTC=y
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_MWAVE is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# File systems
-#
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_FAT_FS is not set
-# CONFIG_MSDOS_FS is not set
-# CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-# 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
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVFS_MOUNT is not set
-# CONFIG_DEVFS_DEBUG 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
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-# CONFIG_XFS_SUPPORT is not set
-
-#
-# Network File Systems
-#
-# CONFIG_CODA_FS is not set
-# CONFIG_NFS_FS is not set
-# CONFIG_NFS_V3 is not set
-# CONFIG_ROOT_NFS is not set
-# CONFIG_NFSD is not set
-# CONFIG_NFSD_V3 is not set
-# CONFIG_SUNRPC is not set
-# CONFIG_LOCKD is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_NCPFS_PACKET_SIGNING is not set
-# CONFIG_NCPFS_IOCTL_LOCKING is not set
-# CONFIG_NCPFS_STRONG is not set
-# CONFIG_NCPFS_NFS_NS is not set
-# CONFIG_NCPFS_OS2_NS is not set
-# CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_NCPFS_EXTRAS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-# CONFIG_NLS is not set
-
-#
-# Console drivers
-#
-CONFIG_VGA_CONSOLE=y
-
-#
-# Frame-buffer support
-#
-# CONFIG_FB is not set
-
-#
-# Simulated drivers
-#
-CONFIG_SIMETH=y
-CONFIG_SIM_SERIAL=y
-CONFIG_SCSI_SIM=y
-
-#
-# Kernel hacking
-#
-CONFIG_DEBUG_KERNEL=y
-CONFIG_IA64_PRINT_HAZARDS=y
-# CONFIG_DISABLE_VHPT is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_IA64_EARLY_PRINTK=y
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_IA64_DEBUG_CMPXCHG is not set
-# CONFIG_IA64_DEBUG_IRQ is not set
-# CONFIG_KDB is not set
-# CONFIG_KDB_MODULES is not set
-# CONFIG_KALLSYMS is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-prom-medusa linux-2.4.21-pre6/arch/ia64/sn/configs/sn1/defconfig-prom-medusa
--- linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-prom-medusa	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/configs/sn1/defconfig-prom-medusa	1970-01-01 00:00:00.000000000 +0000
@@ -1,529 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# General setup
-#
-CONFIG_IA64=y
-# CONFIG_ISA is not set
-# CONFIG_EISA is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_ACPI=y
-CONFIG_ACPI_EFI=y
-CONFIG_ACPI_INTERPRETER=y
-CONFIG_ACPI_KERNEL_CONFIG=y
-CONFIG_ITANIUM=y
-# CONFIG_MCKINLEY is not set
-# CONFIG_IA64_GENERIC is not set
-# CONFIG_IA64_DIG is not set
-# CONFIG_IA64_HP_SIM is not set
-CONFIG_IA64_SGI_SN1=y
-# CONFIG_IA64_SGI_SN2 is not set
-# CONFIG_IA64_PAGE_SIZE_4KB is not set
-# CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
-CONFIG_IA64_BRL_EMU=y
-CONFIG_ITANIUM_BSTEP_SPECIFIC=y
-CONFIG_IA64_L1_CACHE_SHIFT=7
-CONFIG_IA64_SGI_SN=y
-CONFIG_IA64_SGI_SN_DEBUG=y
-CONFIG_IA64_SGI_SN_SIM=y
-CONFIG_IA64_SGI_AUTOTEST=y
-CONFIG_DEVFS_FS=y
-# CONFIG_DEVFS_DEBUG is not set
-CONFIG_SERIAL_SGI_L1_PROTOCOL=y
-CONFIG_DISCONTIGMEM=y
-CONFIG_IA64_MCA=y
-CONFIG_NUMA=y
-CONFIG_PERCPU_IRQ=y
-CONFIG_PCIBA=y
-CONFIG_KCORE_ELF=y
-CONFIG_SMP=y
-# CONFIG_IA32_SUPPORT is not set
-CONFIG_PERFMON=y
-CONFIG_IA64_PALINFO=y
-# CONFIG_EFI_VARS is not set
-# CONFIG_NET is not set
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_ACPI_DEBUG is not set
-# CONFIG_ACPI_BUSMGR is not set
-# CONFIG_ACPI_SYS is not set
-# CONFIG_ACPI_CPU is not set
-# CONFIG_ACPI_BUTTON is not set
-# CONFIG_ACPI_AC is not set
-# CONFIG_ACPI_EC is not set
-# CONFIG_ACPI_CMBATT is not set
-# CONFIG_ACPI_THERMAL is not set
-CONFIG_PCI=y
-# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-# CONFIG_PNPBIOS is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
-# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
-# CONFIG_BLK_DEV_IDEDISK_IBM is not set
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
-# CONFIG_BLK_DEV_IDECS is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
-
-#
-# Alternate 1394 support
-#
-# CONFIG_X1394 is not set
-
-#
-# Alternate SCSI support
-#
-# CONFIG_XSCSI is not set
-
-#
-# SCSI support
-#
-CONFIG_SCSI=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-CONFIG_SD_EXTRA_DEVS=40
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-# 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 is not set
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# 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_DPT_I2O 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_CPQFCTS 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_NCR53C8XX is not set
-# CONFIG_SCSI_SYM53C8XX is not set
-# CONFIG_SCSI_PAS16 is not set
-# CONFIG_SCSI_PCI2000 is not set
-# CONFIG_SCSI_PCI2220I is not set
-# CONFIG_SCSI_PSI240I is not set
-# CONFIG_SCSI_QLOGIC_FAS is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
-CONFIG_SCSI_QLOGIC_FC=y
-# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set
-# CONFIG_SCSI_QLOGIC_1280 is not set
-# CONFIG_SCSI_QLOGIC_QLA2100 is not set
-# CONFIG_SCSI_SIM710 is not set
-# CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_T128 is not set
-# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_DEBUG is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
-# Character devices
-#
-# CONFIG_VT is not set
-CONFIG_SERIAL=y
-# CONFIG_SERIAL_CONSOLE is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
-
-#
-# Input core support is needed for joysticks
-#
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-# CONFIG_EFI_RTC is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_MWAVE is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# File systems
-#
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_FAT_FS is not set
-# CONFIG_MSDOS_FS is not set
-# CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-# 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
-CONFIG_PROC_FS=y
-CONFIG_DEVFS_FS=y
-# CONFIG_DEVFS_MOUNT is not set
-# CONFIG_DEVFS_DEBUG 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
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-# CONFIG_XFS_SUPPORT is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_SMB_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-# CONFIG_NLS is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-
-#
-#   Networking support is needed for USB Networking device support
-#
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# Kernel hacking
-#
-CONFIG_DEBUG_KERNEL=y
-CONFIG_IA64_PRINT_HAZARDS=y
-# CONFIG_DISABLE_VHPT is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_IA64_EARLY_PRINTK=y
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_IA64_DEBUG_CMPXCHG is not set
-# CONFIG_IA64_DEBUG_IRQ is not set
-# CONFIG_KDB is not set
-# CONFIG_KDB_MODULES is not set
-# CONFIG_KALLSYMS is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-sn1-mp linux-2.4.21-pre6/arch/ia64/sn/configs/sn1/defconfig-sn1-mp
--- linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-sn1-mp	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/configs/sn1/defconfig-sn1-mp	1970-01-01 00:00:00.000000000 +0000
@@ -1,736 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# General setup
-#
-CONFIG_IA64=y
-# CONFIG_ISA is not set
-# CONFIG_EISA is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_ACPI=y
-CONFIG_ACPI_EFI=y
-CONFIG_ACPI_INTERPRETER=y
-CONFIG_ACPI_KERNEL_CONFIG=y
-CONFIG_ITANIUM=y
-# CONFIG_MCKINLEY is not set
-# CONFIG_IA64_GENERIC is not set
-# CONFIG_IA64_DIG is not set
-# CONFIG_IA64_HP_SIM is not set
-CONFIG_IA64_SGI_SN1=y
-# CONFIG_IA64_SGI_SN2 is not set
-# CONFIG_IA64_PAGE_SIZE_4KB is not set
-# CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
-CONFIG_IA64_BRL_EMU=y
-CONFIG_ITANIUM_BSTEP_SPECIFIC=y
-CONFIG_IA64_L1_CACHE_SHIFT=7
-CONFIG_IA64_SGI_SN=y
-CONFIG_IA64_SGI_SN_DEBUG=y
-CONFIG_IA64_SGI_SN_SIM=y
-CONFIG_IA64_SGI_AUTOTEST=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_DEBUG=y
-CONFIG_SERIAL_SGI_L1_PROTOCOL=y
-CONFIG_DISCONTIGMEM=y
-CONFIG_IA64_MCA=y
-CONFIG_NUMA=y
-CONFIG_PERCPU_IRQ=y
-CONFIG_PCIBA=y
-CONFIG_KCORE_ELF=y
-CONFIG_SMP=y
-CONFIG_IA32_SUPPORT=y
-CONFIG_PERFMON=y
-CONFIG_IA64_PALINFO=y
-# CONFIG_EFI_VARS is not set
-CONFIG_NET=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_ACPI_DEBUG is not set
-# CONFIG_ACPI_BUSMGR is not set
-# CONFIG_ACPI_SYS is not set
-# CONFIG_ACPI_CPU is not set
-# CONFIG_ACPI_BUTTON is not set
-# CONFIG_ACPI_AC is not set
-# CONFIG_ACPI_EC is not set
-# CONFIG_ACPI_CMBATT is not set
-# CONFIG_ACPI_THERMAL is not set
-CONFIG_PCI=y
-# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK=y
-CONFIG_RTNETLINK=y
-CONFIG_NETLINK_DEV=y
-CONFIG_NETFILTER=y
-CONFIG_NETFILTER_DEBUG=y
-CONFIG_FILTER=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP 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=y
-
-#
-#   IP: Netfilter Configuration
-#
-# CONFIG_IP_NF_CONNTRACK is not set
-# CONFIG_IP_NF_QUEUE is not set
-# CONFIG_IP_NF_IPTABLES is not set
-# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
-# CONFIG_IPV6 is not set
-# CONFIG_KHTTPD is not set
-# CONFIG_ATM is not set
-
-#
-#  
-#
-# CONFIG_IPX is not set
-# 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
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-# CONFIG_PNPBIOS is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_LAN is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
-# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
-# CONFIG_BLK_DEV_IDEDISK_IBM is not set
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
-# CONFIG_BLK_DEV_IDECS is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
-
-#
-# Alternate 1394 support
-#
-# CONFIG_X1394 is not set
-
-#
-# Alternate SCSI support
-#
-CONFIG_XSCSI=y
-
-#
-# Alternate SCSI support
-#
-CONFIG_XSCSI_DKSC=y
-# CONFIG_XSCSI_QLFC is not set
-# CONFIG_XSCSI_QL is not set
-# CONFIG_XSCSI_SBP2 is not set
-
-#
-# SCSI support
-#
-CONFIG_SCSI=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-CONFIG_SD_EXTRA_DEVS=40
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-# 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 is not set
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# 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_DPT_I2O 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_CPQFCTS 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_NCR53C8XX is not set
-# CONFIG_SCSI_SYM53C8XX is not set
-# CONFIG_SCSI_PAS16 is not set
-# CONFIG_SCSI_PCI2000 is not set
-# CONFIG_SCSI_PCI2220I is not set
-# CONFIG_SCSI_PSI240I is not set
-# CONFIG_SCSI_QLOGIC_FAS is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
-CONFIG_SCSI_QLOGIC_FC=y
-# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set
-# CONFIG_SCSI_QLOGIC_1280 is not set
-# CONFIG_SCSI_QLOGIC_QLA2100 is not set
-# CONFIG_SCSI_SIM710 is not set
-# CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_T128 is not set
-# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_DEBUG is not set
-
-#
-# Network device support
-#
-CONFIG_NETDEVICES=y
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-CONFIG_SGI_IOC3_ETH=y
-# CONFIG_SUNLANCE is not set
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNBMAC is not set
-# CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
-# CONFIG_SUNGEM is not set
-# 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_HP100 is not set
-# CONFIG_NET_ISA is not set
-# CONFIG_NET_PCI is not set
-# CONFIG_NET_POCKET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_MYRI_SBUS is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PLIP is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices
-#
-# 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
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
-# Character devices
-#
-# CONFIG_VT is not set
-CONFIG_SERIAL=y
-# CONFIG_SERIAL_CONSOLE is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
-
-#
-# Input core support is needed for joysticks
-#
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-CONFIG_EFI_RTC=y
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_MWAVE is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# File systems
-#
-CONFIG_QUOTA=y
-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
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BFS_FS is not set
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
-# CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=y
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-# CONFIG_RAMFS 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
-CONFIG_PROC_FS=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_MOUNT=y
-CONFIG_DEVFS_DEBUG=y
-CONFIG_DEVPTS_FS=y
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-CONFIG_XFS_SUPPORT=y
-
-#
-# Network File Systems
-#
-# CONFIG_CODA_FS is not set
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-# CONFIG_ROOT_NFS is not set
-CONFIG_NFSD=y
-CONFIG_NFSD_V3=y
-CONFIG_SUNRPC=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-# CONFIG_SMB_FS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_NCPFS_PACKET_SIGNING is not set
-# CONFIG_NCPFS_IOCTL_LOCKING is not set
-# CONFIG_NCPFS_STRONG is not set
-# CONFIG_NCPFS_NFS_NS is not set
-# CONFIG_NCPFS_OS2_NS is not set
-# CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_NCPFS_EXTRAS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-CONFIG_NLS=y
-
-#
-# Native Language Support
-#
-CONFIG_NLS_DEFAULT="n"
-# CONFIG_NLS_CODEPAGE_437 is not set
-# CONFIG_NLS_CODEPAGE_737 is not set
-# CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
-# CONFIG_NLS_CODEPAGE_852 is not set
-# CONFIG_NLS_CODEPAGE_855 is not set
-# CONFIG_NLS_CODEPAGE_857 is not set
-# CONFIG_NLS_CODEPAGE_860 is not set
-# CONFIG_NLS_CODEPAGE_861 is not set
-# CONFIG_NLS_CODEPAGE_862 is not set
-# CONFIG_NLS_CODEPAGE_863 is not set
-# CONFIG_NLS_CODEPAGE_864 is not set
-# CONFIG_NLS_CODEPAGE_865 is not set
-# CONFIG_NLS_CODEPAGE_866 is not set
-# CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_936 is not set
-# CONFIG_NLS_CODEPAGE_950 is not set
-# CONFIG_NLS_CODEPAGE_932 is not set
-# CONFIG_NLS_CODEPAGE_949 is not set
-# CONFIG_NLS_CODEPAGE_874 is not set
-# CONFIG_NLS_ISO8859_8 is not set
-# CONFIG_NLS_CODEPAGE_1251 is not set
-# CONFIG_NLS_ISO8859_1 is not set
-# CONFIG_NLS_ISO8859_2 is not set
-# CONFIG_NLS_ISO8859_3 is not set
-# CONFIG_NLS_ISO8859_4 is not set
-# CONFIG_NLS_ISO8859_5 is not set
-# CONFIG_NLS_ISO8859_6 is not set
-# CONFIG_NLS_ISO8859_7 is not set
-# CONFIG_NLS_ISO8859_9 is not set
-# CONFIG_NLS_ISO8859_13 is not set
-# CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
-# CONFIG_NLS_KOI8_R is not set
-# CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BLUEZ is not set
-
-#
-# Kernel hacking
-#
-CONFIG_DEBUG_KERNEL=y
-CONFIG_IA64_PRINT_HAZARDS=y
-# CONFIG_DISABLE_VHPT is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_IA64_EARLY_PRINTK=y
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_IA64_DEBUG_CMPXCHG is not set
-# CONFIG_IA64_DEBUG_IRQ is not set
-CONFIG_KDB=y
-CONFIG_KDB_MODULES=y
-# CONFIG_KDB_OFF is not set
-
-#
-#   Load all symbols for debugging is required for KDB
-#
-CONFIG_KALLSYMS=y
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-modules linux-2.4.21-pre6/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-modules
--- linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-modules	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-modules	1970-01-01 00:00:00.000000000 +0000
@@ -1,738 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
-
-#
-# General setup
-#
-CONFIG_IA64=y
-# CONFIG_ISA is not set
-# CONFIG_EISA is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_ACPI=y
-CONFIG_ACPI_EFI=y
-CONFIG_ACPI_INTERPRETER=y
-CONFIG_ACPI_KERNEL_CONFIG=y
-CONFIG_ITANIUM=y
-# CONFIG_MCKINLEY is not set
-# CONFIG_IA64_GENERIC is not set
-# CONFIG_IA64_DIG is not set
-# CONFIG_IA64_HP_SIM is not set
-CONFIG_IA64_SGI_SN1=y
-# CONFIG_IA64_SGI_SN2 is not set
-# CONFIG_IA64_PAGE_SIZE_4KB is not set
-# CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
-CONFIG_IA64_BRL_EMU=y
-CONFIG_ITANIUM_BSTEP_SPECIFIC=y
-CONFIG_IA64_L1_CACHE_SHIFT=7
-CONFIG_IA64_SGI_SN=y
-CONFIG_IA64_SGI_SN_DEBUG=y
-CONFIG_IA64_SGI_SN_SIM=y
-CONFIG_IA64_SGI_AUTOTEST=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_DEBUG=y
-CONFIG_SERIAL_SGI_L1_PROTOCOL=y
-CONFIG_DISCONTIGMEM=y
-CONFIG_IA64_MCA=y
-CONFIG_NUMA=y
-CONFIG_PERCPU_IRQ=y
-CONFIG_PCIBA=y
-CONFIG_KCORE_ELF=y
-CONFIG_SMP=y
-CONFIG_IA32_SUPPORT=y
-CONFIG_PERFMON=y
-CONFIG_IA64_PALINFO=y
-# CONFIG_EFI_VARS is not set
-CONFIG_NET=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_ACPI_DEBUG is not set
-# CONFIG_ACPI_BUSMGR is not set
-# CONFIG_ACPI_SYS is not set
-# CONFIG_ACPI_CPU is not set
-# CONFIG_ACPI_BUTTON is not set
-# CONFIG_ACPI_AC is not set
-# CONFIG_ACPI_EC is not set
-# CONFIG_ACPI_CMBATT is not set
-# CONFIG_ACPI_THERMAL is not set
-CONFIG_PCI=y
-# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK=y
-CONFIG_RTNETLINK=y
-CONFIG_NETLINK_DEV=y
-CONFIG_NETFILTER=y
-CONFIG_NETFILTER_DEBUG=y
-CONFIG_FILTER=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP 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=y
-
-#
-#   IP: Netfilter Configuration
-#
-# CONFIG_IP_NF_CONNTRACK is not set
-# CONFIG_IP_NF_QUEUE is not set
-# CONFIG_IP_NF_IPTABLES is not set
-# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
-# CONFIG_IPV6 is not set
-# CONFIG_KHTTPD is not set
-# CONFIG_ATM is not set
-
-#
-#  
-#
-# CONFIG_IPX is not set
-# 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
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-# CONFIG_PNPBIOS is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_LAN is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
-# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
-# CONFIG_BLK_DEV_IDEDISK_IBM is not set
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
-# CONFIG_BLK_DEV_IDECS is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
-
-#
-# Alternate 1394 support
-#
-# CONFIG_X1394 is not set
-
-#
-# Alternate SCSI support
-#
-CONFIG_XSCSI=y
-
-#
-# Alternate SCSI support
-#
-CONFIG_XSCSI_DKSC=y
-# CONFIG_XSCSI_QLFC is not set
-# CONFIG_XSCSI_QL is not set
-# CONFIG_XSCSI_SBP2 is not set
-
-#
-# SCSI support
-#
-CONFIG_SCSI=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-CONFIG_SD_EXTRA_DEVS=40
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-# 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 is not set
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# 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_DPT_I2O 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_CPQFCTS 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_NCR53C8XX is not set
-# CONFIG_SCSI_SYM53C8XX is not set
-# CONFIG_SCSI_PAS16 is not set
-# CONFIG_SCSI_PCI2000 is not set
-# CONFIG_SCSI_PCI2220I is not set
-# CONFIG_SCSI_PSI240I is not set
-# CONFIG_SCSI_QLOGIC_FAS is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
-CONFIG_SCSI_QLOGIC_FC=y
-# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set
-# CONFIG_SCSI_QLOGIC_1280 is not set
-# CONFIG_SCSI_QLOGIC_QLA2100 is not set
-# CONFIG_SCSI_SIM710 is not set
-# CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_T128 is not set
-# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_DEBUG is not set
-
-#
-# Network device support
-#
-CONFIG_NETDEVICES=y
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-CONFIG_SGI_IOC3_ETH=y
-# CONFIG_SUNLANCE is not set
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNBMAC is not set
-# CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
-# CONFIG_SUNGEM is not set
-# 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_HP100 is not set
-# CONFIG_NET_ISA is not set
-# CONFIG_NET_PCI is not set
-# CONFIG_NET_POCKET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_MYRI_SBUS is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PLIP is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices
-#
-# 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
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
-# Character devices
-#
-# CONFIG_VT is not set
-CONFIG_SERIAL=y
-# CONFIG_SERIAL_CONSOLE is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
-
-#
-# Input core support is needed for joysticks
-#
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-CONFIG_EFI_RTC=y
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_MWAVE is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# File systems
-#
-CONFIG_QUOTA=y
-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
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BFS_FS is not set
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
-# CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=y
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-# CONFIG_RAMFS 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
-CONFIG_PROC_FS=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_MOUNT=y
-CONFIG_DEVFS_DEBUG=y
-CONFIG_DEVPTS_FS=y
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-CONFIG_XFS_SUPPORT=y
-
-#
-# Network File Systems
-#
-# CONFIG_CODA_FS is not set
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-# CONFIG_ROOT_NFS is not set
-CONFIG_NFSD=y
-CONFIG_NFSD_V3=y
-CONFIG_SUNRPC=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-# CONFIG_SMB_FS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_NCPFS_PACKET_SIGNING is not set
-# CONFIG_NCPFS_IOCTL_LOCKING is not set
-# CONFIG_NCPFS_STRONG is not set
-# CONFIG_NCPFS_NFS_NS is not set
-# CONFIG_NCPFS_OS2_NS is not set
-# CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_NCPFS_EXTRAS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-CONFIG_NLS=y
-
-#
-# Native Language Support
-#
-CONFIG_NLS_DEFAULT="n"
-# CONFIG_NLS_CODEPAGE_437 is not set
-# CONFIG_NLS_CODEPAGE_737 is not set
-# CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
-# CONFIG_NLS_CODEPAGE_852 is not set
-# CONFIG_NLS_CODEPAGE_855 is not set
-# CONFIG_NLS_CODEPAGE_857 is not set
-# CONFIG_NLS_CODEPAGE_860 is not set
-# CONFIG_NLS_CODEPAGE_861 is not set
-# CONFIG_NLS_CODEPAGE_862 is not set
-# CONFIG_NLS_CODEPAGE_863 is not set
-# CONFIG_NLS_CODEPAGE_864 is not set
-# CONFIG_NLS_CODEPAGE_865 is not set
-# CONFIG_NLS_CODEPAGE_866 is not set
-# CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_936 is not set
-# CONFIG_NLS_CODEPAGE_950 is not set
-# CONFIG_NLS_CODEPAGE_932 is not set
-# CONFIG_NLS_CODEPAGE_949 is not set
-# CONFIG_NLS_CODEPAGE_874 is not set
-# CONFIG_NLS_ISO8859_8 is not set
-# CONFIG_NLS_CODEPAGE_1251 is not set
-# CONFIG_NLS_ISO8859_1 is not set
-# CONFIG_NLS_ISO8859_2 is not set
-# CONFIG_NLS_ISO8859_3 is not set
-# CONFIG_NLS_ISO8859_4 is not set
-# CONFIG_NLS_ISO8859_5 is not set
-# CONFIG_NLS_ISO8859_6 is not set
-# CONFIG_NLS_ISO8859_7 is not set
-# CONFIG_NLS_ISO8859_9 is not set
-# CONFIG_NLS_ISO8859_13 is not set
-# CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
-# CONFIG_NLS_KOI8_R is not set
-# CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BLUEZ is not set
-
-#
-# Kernel hacking
-#
-CONFIG_DEBUG_KERNEL=y
-CONFIG_IA64_PRINT_HAZARDS=y
-# CONFIG_DISABLE_VHPT is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_IA64_EARLY_PRINTK=y
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_IA64_DEBUG_CMPXCHG is not set
-# CONFIG_IA64_DEBUG_IRQ is not set
-CONFIG_KDB=y
-CONFIG_KDB_MODULES=y
-# CONFIG_KDB_OFF is not set
-
-#
-#   Load all symbols for debugging is required for KDB
-#
-CONFIG_KALLSYMS=y
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-syn1-0 linux-2.4.21-pre6/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-syn1-0
--- linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-syn1-0	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/configs/sn1/defconfig-sn1-mp-syn1-0	1970-01-01 00:00:00.000000000 +0000
@@ -1,736 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# General setup
-#
-CONFIG_IA64=y
-# CONFIG_ISA is not set
-# CONFIG_EISA is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_ACPI=y
-CONFIG_ACPI_EFI=y
-CONFIG_ACPI_INTERPRETER=y
-CONFIG_ACPI_KERNEL_CONFIG=y
-CONFIG_ITANIUM=y
-# CONFIG_MCKINLEY is not set
-# CONFIG_IA64_GENERIC is not set
-# CONFIG_IA64_DIG is not set
-# CONFIG_IA64_HP_SIM is not set
-CONFIG_IA64_SGI_SN1=y
-# CONFIG_IA64_SGI_SN2 is not set
-# CONFIG_IA64_PAGE_SIZE_4KB is not set
-# CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
-CONFIG_IA64_BRL_EMU=y
-CONFIG_ITANIUM_BSTEP_SPECIFIC=y
-CONFIG_IA64_L1_CACHE_SHIFT=7
-CONFIG_IA64_SGI_SN=y
-CONFIG_IA64_SGI_SN_DEBUG=y
-CONFIG_IA64_SGI_SN_SIM=y
-CONFIG_IA64_SGI_AUTOTEST=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_DEBUG=y
-CONFIG_SERIAL_SGI_L1_PROTOCOL=y
-CONFIG_DISCONTIGMEM=y
-CONFIG_IA64_MCA=y
-CONFIG_NUMA=y
-CONFIG_PERCPU_IRQ=y
-CONFIG_PCIBA=y
-CONFIG_KCORE_ELF=y
-CONFIG_SMP=y
-CONFIG_IA32_SUPPORT=y
-CONFIG_PERFMON=y
-CONFIG_IA64_PALINFO=y
-# CONFIG_EFI_VARS is not set
-CONFIG_NET=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_ACPI_DEBUG is not set
-# CONFIG_ACPI_BUSMGR is not set
-# CONFIG_ACPI_SYS is not set
-# CONFIG_ACPI_CPU is not set
-# CONFIG_ACPI_BUTTON is not set
-# CONFIG_ACPI_AC is not set
-# CONFIG_ACPI_EC is not set
-# CONFIG_ACPI_CMBATT is not set
-# CONFIG_ACPI_THERMAL is not set
-CONFIG_PCI=y
-# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK=y
-CONFIG_RTNETLINK=y
-CONFIG_NETLINK_DEV=y
-CONFIG_NETFILTER=y
-CONFIG_NETFILTER_DEBUG=y
-CONFIG_FILTER=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP 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=y
-
-#
-#   IP: Netfilter Configuration
-#
-# CONFIG_IP_NF_CONNTRACK is not set
-# CONFIG_IP_NF_QUEUE is not set
-# CONFIG_IP_NF_IPTABLES is not set
-# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
-# CONFIG_IPV6 is not set
-# CONFIG_KHTTPD is not set
-# CONFIG_ATM is not set
-
-#
-#  
-#
-# CONFIG_IPX is not set
-# 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
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-# CONFIG_PNPBIOS is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_LAN is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
-# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
-# CONFIG_BLK_DEV_IDEDISK_IBM is not set
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
-# CONFIG_BLK_DEV_IDECS is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
-
-#
-# Alternate 1394 support
-#
-# CONFIG_X1394 is not set
-
-#
-# Alternate SCSI support
-#
-CONFIG_XSCSI=y
-
-#
-# Alternate SCSI support
-#
-CONFIG_XSCSI_DKSC=y
-# CONFIG_XSCSI_QLFC is not set
-# CONFIG_XSCSI_QL is not set
-# CONFIG_XSCSI_SBP2 is not set
-
-#
-# SCSI support
-#
-CONFIG_SCSI=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-CONFIG_SD_EXTRA_DEVS=40
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-# 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 is not set
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# 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_DPT_I2O 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_CPQFCTS 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_NCR53C8XX is not set
-# CONFIG_SCSI_SYM53C8XX is not set
-# CONFIG_SCSI_PAS16 is not set
-# CONFIG_SCSI_PCI2000 is not set
-# CONFIG_SCSI_PCI2220I is not set
-# CONFIG_SCSI_PSI240I is not set
-# CONFIG_SCSI_QLOGIC_FAS is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
-CONFIG_SCSI_QLOGIC_FC=y
-# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set
-# CONFIG_SCSI_QLOGIC_1280 is not set
-# CONFIG_SCSI_QLOGIC_QLA2100 is not set
-# CONFIG_SCSI_SIM710 is not set
-# CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_T128 is not set
-# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_DEBUG is not set
-
-#
-# Network device support
-#
-CONFIG_NETDEVICES=y
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-CONFIG_SGI_IOC3_ETH=y
-# CONFIG_SUNLANCE is not set
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNBMAC is not set
-# CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
-# CONFIG_SUNGEM is not set
-# 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_HP100 is not set
-# CONFIG_NET_ISA is not set
-# CONFIG_NET_PCI is not set
-# CONFIG_NET_POCKET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_MYRI_SBUS is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PLIP is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices
-#
-# 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
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
-# Character devices
-#
-# CONFIG_VT is not set
-CONFIG_SERIAL=y
-# CONFIG_SERIAL_CONSOLE is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
-
-#
-# Input core support is needed for joysticks
-#
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-CONFIG_EFI_RTC=y
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_MWAVE is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# File systems
-#
-CONFIG_QUOTA=y
-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
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BFS_FS is not set
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
-# CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=y
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-# CONFIG_RAMFS 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
-CONFIG_PROC_FS=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_MOUNT=y
-CONFIG_DEVFS_DEBUG=y
-CONFIG_DEVPTS_FS=y
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-CONFIG_XFS_SUPPORT=y
-
-#
-# Network File Systems
-#
-# CONFIG_CODA_FS is not set
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-# CONFIG_ROOT_NFS is not set
-CONFIG_NFSD=y
-CONFIG_NFSD_V3=y
-CONFIG_SUNRPC=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-# CONFIG_SMB_FS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_NCPFS_PACKET_SIGNING is not set
-# CONFIG_NCPFS_IOCTL_LOCKING is not set
-# CONFIG_NCPFS_STRONG is not set
-# CONFIG_NCPFS_NFS_NS is not set
-# CONFIG_NCPFS_OS2_NS is not set
-# CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_NCPFS_EXTRAS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-CONFIG_NLS=y
-
-#
-# Native Language Support
-#
-CONFIG_NLS_DEFAULT="n"
-# CONFIG_NLS_CODEPAGE_437 is not set
-# CONFIG_NLS_CODEPAGE_737 is not set
-# CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
-# CONFIG_NLS_CODEPAGE_852 is not set
-# CONFIG_NLS_CODEPAGE_855 is not set
-# CONFIG_NLS_CODEPAGE_857 is not set
-# CONFIG_NLS_CODEPAGE_860 is not set
-# CONFIG_NLS_CODEPAGE_861 is not set
-# CONFIG_NLS_CODEPAGE_862 is not set
-# CONFIG_NLS_CODEPAGE_863 is not set
-# CONFIG_NLS_CODEPAGE_864 is not set
-# CONFIG_NLS_CODEPAGE_865 is not set
-# CONFIG_NLS_CODEPAGE_866 is not set
-# CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_936 is not set
-# CONFIG_NLS_CODEPAGE_950 is not set
-# CONFIG_NLS_CODEPAGE_932 is not set
-# CONFIG_NLS_CODEPAGE_949 is not set
-# CONFIG_NLS_CODEPAGE_874 is not set
-# CONFIG_NLS_ISO8859_8 is not set
-# CONFIG_NLS_CODEPAGE_1251 is not set
-# CONFIG_NLS_ISO8859_1 is not set
-# CONFIG_NLS_ISO8859_2 is not set
-# CONFIG_NLS_ISO8859_3 is not set
-# CONFIG_NLS_ISO8859_4 is not set
-# CONFIG_NLS_ISO8859_5 is not set
-# CONFIG_NLS_ISO8859_6 is not set
-# CONFIG_NLS_ISO8859_7 is not set
-# CONFIG_NLS_ISO8859_9 is not set
-# CONFIG_NLS_ISO8859_13 is not set
-# CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
-# CONFIG_NLS_KOI8_R is not set
-# CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BLUEZ is not set
-
-#
-# Kernel hacking
-#
-CONFIG_DEBUG_KERNEL=y
-CONFIG_IA64_PRINT_HAZARDS=y
-# CONFIG_DISABLE_VHPT is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_IA64_EARLY_PRINTK=y
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_IA64_DEBUG_CMPXCHG is not set
-# CONFIG_IA64_DEBUG_IRQ is not set
-CONFIG_KDB=y
-CONFIG_KDB_MODULES=y
-# CONFIG_KDB_OFF is not set
-
-#
-#   Load all symbols for debugging is required for KDB
-#
-CONFIG_KALLSYMS=y
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-sn1-sp linux-2.4.21-pre6/arch/ia64/sn/configs/sn1/defconfig-sn1-sp
--- linux-2.4.20/arch/ia64/sn/configs/sn1/defconfig-sn1-sp	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/configs/sn1/defconfig-sn1-sp	1970-01-01 00:00:00.000000000 +0000
@@ -1,736 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# General setup
-#
-CONFIG_IA64=y
-# CONFIG_ISA is not set
-# CONFIG_EISA is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_ACPI=y
-CONFIG_ACPI_EFI=y
-CONFIG_ACPI_INTERPRETER=y
-CONFIG_ACPI_KERNEL_CONFIG=y
-CONFIG_ITANIUM=y
-# CONFIG_MCKINLEY is not set
-# CONFIG_IA64_GENERIC is not set
-# CONFIG_IA64_DIG is not set
-# CONFIG_IA64_HP_SIM is not set
-CONFIG_IA64_SGI_SN1=y
-# CONFIG_IA64_SGI_SN2 is not set
-# CONFIG_IA64_PAGE_SIZE_4KB is not set
-# CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
-CONFIG_IA64_BRL_EMU=y
-CONFIG_ITANIUM_BSTEP_SPECIFIC=y
-CONFIG_IA64_L1_CACHE_SHIFT=7
-CONFIG_IA64_SGI_SN=y
-CONFIG_IA64_SGI_SN_DEBUG=y
-CONFIG_IA64_SGI_SN_SIM=y
-CONFIG_IA64_SGI_AUTOTEST=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_DEBUG=y
-CONFIG_SERIAL_SGI_L1_PROTOCOL=y
-CONFIG_DISCONTIGMEM=y
-CONFIG_IA64_MCA=y
-CONFIG_NUMA=y
-CONFIG_PERCPU_IRQ=y
-CONFIG_PCIBA=y
-CONFIG_KCORE_ELF=y
-# CONFIG_SMP is not set
-CONFIG_IA32_SUPPORT=y
-CONFIG_PERFMON=y
-CONFIG_IA64_PALINFO=y
-# CONFIG_EFI_VARS is not set
-CONFIG_NET=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_ACPI_DEBUG is not set
-# CONFIG_ACPI_BUSMGR is not set
-# CONFIG_ACPI_SYS is not set
-# CONFIG_ACPI_CPU is not set
-# CONFIG_ACPI_BUTTON is not set
-# CONFIG_ACPI_AC is not set
-# CONFIG_ACPI_EC is not set
-# CONFIG_ACPI_CMBATT is not set
-# CONFIG_ACPI_THERMAL is not set
-CONFIG_PCI=y
-# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK=y
-CONFIG_RTNETLINK=y
-CONFIG_NETLINK_DEV=y
-CONFIG_NETFILTER=y
-CONFIG_NETFILTER_DEBUG=y
-CONFIG_FILTER=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP 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=y
-
-#
-#   IP: Netfilter Configuration
-#
-# CONFIG_IP_NF_CONNTRACK is not set
-# CONFIG_IP_NF_QUEUE is not set
-# CONFIG_IP_NF_IPTABLES is not set
-# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
-# CONFIG_IPV6 is not set
-# CONFIG_KHTTPD is not set
-# CONFIG_ATM is not set
-
-#
-#  
-#
-# CONFIG_IPX is not set
-# 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
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-# CONFIG_PNPBIOS is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_LAN is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
-# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
-# CONFIG_BLK_DEV_IDEDISK_IBM is not set
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
-# CONFIG_BLK_DEV_IDECS is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
-
-#
-# Alternate 1394 support
-#
-# CONFIG_X1394 is not set
-
-#
-# Alternate SCSI support
-#
-CONFIG_XSCSI=y
-
-#
-# Alternate SCSI support
-#
-CONFIG_XSCSI_DKSC=y
-# CONFIG_XSCSI_QLFC is not set
-# CONFIG_XSCSI_QL is not set
-# CONFIG_XSCSI_SBP2 is not set
-
-#
-# SCSI support
-#
-CONFIG_SCSI=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-CONFIG_SD_EXTRA_DEVS=40
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-# 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 is not set
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# 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_DPT_I2O 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_CPQFCTS 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_NCR53C8XX is not set
-# CONFIG_SCSI_SYM53C8XX is not set
-# CONFIG_SCSI_PAS16 is not set
-# CONFIG_SCSI_PCI2000 is not set
-# CONFIG_SCSI_PCI2220I is not set
-# CONFIG_SCSI_PSI240I is not set
-# CONFIG_SCSI_QLOGIC_FAS is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
-CONFIG_SCSI_QLOGIC_FC=y
-# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set
-# CONFIG_SCSI_QLOGIC_1280 is not set
-# CONFIG_SCSI_QLOGIC_QLA2100 is not set
-# CONFIG_SCSI_SIM710 is not set
-# CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_T128 is not set
-# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_DEBUG is not set
-
-#
-# Network device support
-#
-CONFIG_NETDEVICES=y
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-CONFIG_SGI_IOC3_ETH=y
-# CONFIG_SUNLANCE is not set
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNBMAC is not set
-# CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
-# CONFIG_SUNGEM is not set
-# 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_HP100 is not set
-# CONFIG_NET_ISA is not set
-# CONFIG_NET_PCI is not set
-# CONFIG_NET_POCKET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_MYRI_SBUS is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PLIP is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices
-#
-# 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
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
-# Character devices
-#
-# CONFIG_VT is not set
-CONFIG_SERIAL=y
-# CONFIG_SERIAL_CONSOLE is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
-
-#
-# Input core support is needed for joysticks
-#
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-CONFIG_EFI_RTC=y
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_MWAVE is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# File systems
-#
-CONFIG_QUOTA=y
-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
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BFS_FS is not set
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
-# CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=y
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-# CONFIG_RAMFS 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
-CONFIG_PROC_FS=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_MOUNT=y
-CONFIG_DEVFS_DEBUG=y
-CONFIG_DEVPTS_FS=y
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-CONFIG_XFS_SUPPORT=y
-
-#
-# Network File Systems
-#
-# CONFIG_CODA_FS is not set
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-# CONFIG_ROOT_NFS is not set
-CONFIG_NFSD=y
-CONFIG_NFSD_V3=y
-CONFIG_SUNRPC=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-# CONFIG_SMB_FS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_NCPFS_PACKET_SIGNING is not set
-# CONFIG_NCPFS_IOCTL_LOCKING is not set
-# CONFIG_NCPFS_STRONG is not set
-# CONFIG_NCPFS_NFS_NS is not set
-# CONFIG_NCPFS_OS2_NS is not set
-# CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_NCPFS_EXTRAS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-CONFIG_NLS=y
-
-#
-# Native Language Support
-#
-CONFIG_NLS_DEFAULT="n"
-# CONFIG_NLS_CODEPAGE_437 is not set
-# CONFIG_NLS_CODEPAGE_737 is not set
-# CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
-# CONFIG_NLS_CODEPAGE_852 is not set
-# CONFIG_NLS_CODEPAGE_855 is not set
-# CONFIG_NLS_CODEPAGE_857 is not set
-# CONFIG_NLS_CODEPAGE_860 is not set
-# CONFIG_NLS_CODEPAGE_861 is not set
-# CONFIG_NLS_CODEPAGE_862 is not set
-# CONFIG_NLS_CODEPAGE_863 is not set
-# CONFIG_NLS_CODEPAGE_864 is not set
-# CONFIG_NLS_CODEPAGE_865 is not set
-# CONFIG_NLS_CODEPAGE_866 is not set
-# CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_936 is not set
-# CONFIG_NLS_CODEPAGE_950 is not set
-# CONFIG_NLS_CODEPAGE_932 is not set
-# CONFIG_NLS_CODEPAGE_949 is not set
-# CONFIG_NLS_CODEPAGE_874 is not set
-# CONFIG_NLS_ISO8859_8 is not set
-# CONFIG_NLS_CODEPAGE_1251 is not set
-# CONFIG_NLS_ISO8859_1 is not set
-# CONFIG_NLS_ISO8859_2 is not set
-# CONFIG_NLS_ISO8859_3 is not set
-# CONFIG_NLS_ISO8859_4 is not set
-# CONFIG_NLS_ISO8859_5 is not set
-# CONFIG_NLS_ISO8859_6 is not set
-# CONFIG_NLS_ISO8859_7 is not set
-# CONFIG_NLS_ISO8859_9 is not set
-# CONFIG_NLS_ISO8859_13 is not set
-# CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
-# CONFIG_NLS_KOI8_R is not set
-# CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BLUEZ is not set
-
-#
-# Kernel hacking
-#
-CONFIG_DEBUG_KERNEL=y
-CONFIG_IA64_PRINT_HAZARDS=y
-# CONFIG_DISABLE_VHPT is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_IA64_EARLY_PRINTK=y
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_IA64_DEBUG_CMPXCHG is not set
-# CONFIG_IA64_DEBUG_IRQ is not set
-CONFIG_KDB=y
-CONFIG_KDB_MODULES=y
-# CONFIG_KDB_OFF is not set
-
-#
-#   Load all symbols for debugging is required for KDB
-#
-CONFIG_KALLSYMS=y
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/configs/sn2/defconfig-dig-numa linux-2.4.21-pre6/arch/ia64/sn/configs/sn2/defconfig-dig-numa
--- linux-2.4.20/arch/ia64/sn/configs/sn2/defconfig-dig-numa	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/configs/sn2/defconfig-dig-numa	1970-01-01 00:00:00.000000000 +0000
@@ -1,460 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-
-#
-# Code maturity level options
-#
-# CONFIG_EXPERIMENTAL is not set
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# General setup
-#
-CONFIG_IA64=y
-# CONFIG_ISA is not set
-# CONFIG_EISA is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_ACPI=y
-CONFIG_ACPI_EFI=y
-CONFIG_ACPI_INTERPRETER=y
-CONFIG_ACPI_KERNEL_CONFIG=y
-CONFIG_ITANIUM=y
-# CONFIG_MCKINLEY is not set
-# CONFIG_IA64_GENERIC is not set
-CONFIG_IA64_DIG=y
-# CONFIG_IA64_HP_SIM is not set
-# CONFIG_IA64_SGI_SN1 is not set
-# CONFIG_IA64_SGI_SN2 is not set
-# CONFIG_IA64_PAGE_SIZE_4KB is not set
-# CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
-CONFIG_IA64_BRL_EMU=y
-CONFIG_ITANIUM_BSTEP_SPECIFIC=y
-CONFIG_IA64_L1_CACHE_SHIFT=6
-CONFIG_NUMA=y
-CONFIG_DISCONTIGMEM=y
-# CONFIG_IA64_MCA is not set
-CONFIG_PM=y
-CONFIG_IA64_HAVE_SYNCRONIZED_ITC=y
-# CONFIG_DEVFS_FS is not set
-CONFIG_KCORE_ELF=y
-CONFIG_SMP=y
-# CONFIG_IA32_SUPPORT is not set
-# CONFIG_PERFMON is not set
-# CONFIG_IA64_PALINFO is not set
-# CONFIG_EFI_VARS is not set
-# CONFIG_NET is not set
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_SYSCTL is not set
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_ACPI_DEBUG is not set
-# CONFIG_ACPI_BUSMGR is not set
-# CONFIG_ACPI_SYS is not set
-# CONFIG_ACPI_CPU is not set
-# CONFIG_ACPI_BUTTON is not set
-# CONFIG_ACPI_AC is not set
-# CONFIG_ACPI_EC is not set
-# CONFIG_ACPI_CMBATT is not set
-# CONFIG_ACPI_THERMAL is not set
-CONFIG_PCI=y
-# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
-# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
-# CONFIG_BLK_DEV_IDEDISK_IBM is not set
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
-# CONFIG_BLK_DEV_IDECS is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
-
-#
-# Alternate 1394 support
-#
-# CONFIG_X1394 is not set
-
-#
-# Alternate SCSI support
-#
-# CONFIG_XSCSI is not set
-
-#
-# SCSI support
-#
-# CONFIG_SCSI is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-# CONFIG_SERIAL is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
-
-#
-# Input core support is needed for joysticks
-#
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-# CONFIG_EFI_RTC is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_MWAVE is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# File systems
-#
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_FAT_FS is not set
-# CONFIG_MSDOS_FS is not set
-# CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-# 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
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVFS_MOUNT is not set
-# CONFIG_DEVFS_DEBUG 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
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-# CONFIG_XFS_SUPPORT is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_SMB_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-# CONFIG_NLS is not set
-
-#
-# Console drivers
-#
-CONFIG_VGA_CONSOLE=y
-
-#
-# Frame-buffer support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-
-#
-#   Networking support is needed for USB Networking device support
-#
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
-# Kernel hacking
-#
-CONFIG_DEBUG_KERNEL=y
-CONFIG_IA64_PRINT_HAZARDS=y
-# CONFIG_DISABLE_VHPT is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_IA64_EARLY_PRINTK=y
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_IA64_DEBUG_CMPXCHG is not set
-# CONFIG_IA64_DEBUG_IRQ is not set
-# CONFIG_KDB is not set
-# CONFIG_KDB_MODULES is not set
-# CONFIG_KALLSYMS is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-mp linux-2.4.21-pre6/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-mp
--- linux-2.4.20/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-mp	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-mp	1970-01-01 00:00:00.000000000 +0000
@@ -1,459 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-
-#
-# Code maturity level options
-#
-# CONFIG_EXPERIMENTAL is not set
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# General setup
-#
-CONFIG_IA64=y
-# CONFIG_ISA is not set
-# CONFIG_EISA is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_ACPI=y
-CONFIG_ACPI_EFI=y
-CONFIG_ACPI_INTERPRETER=y
-CONFIG_ACPI_KERNEL_CONFIG=y
-CONFIG_ITANIUM=y
-# CONFIG_MCKINLEY is not set
-# CONFIG_IA64_GENERIC is not set
-CONFIG_IA64_DIG=y
-# CONFIG_IA64_HP_SIM is not set
-# CONFIG_IA64_SGI_SN1 is not set
-# CONFIG_IA64_SGI_SN2 is not set
-# CONFIG_IA64_PAGE_SIZE_4KB is not set
-# CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
-CONFIG_IA64_BRL_EMU=y
-CONFIG_ITANIUM_BSTEP_SPECIFIC=y
-CONFIG_IA64_L1_CACHE_SHIFT=6
-# CONFIG_NUMA is not set
-# CONFIG_IA64_MCA is not set
-CONFIG_PM=y
-CONFIG_IA64_HAVE_SYNCRONIZED_ITC=y
-# CONFIG_DEVFS_FS is not set
-CONFIG_KCORE_ELF=y
-CONFIG_SMP=y
-# CONFIG_IA32_SUPPORT is not set
-# CONFIG_PERFMON is not set
-# CONFIG_IA64_PALINFO is not set
-# CONFIG_EFI_VARS is not set
-# CONFIG_NET is not set
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_SYSCTL is not set
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_ACPI_DEBUG is not set
-# CONFIG_ACPI_BUSMGR is not set
-# CONFIG_ACPI_SYS is not set
-# CONFIG_ACPI_CPU is not set
-# CONFIG_ACPI_BUTTON is not set
-# CONFIG_ACPI_AC is not set
-# CONFIG_ACPI_EC is not set
-# CONFIG_ACPI_CMBATT is not set
-# CONFIG_ACPI_THERMAL is not set
-CONFIG_PCI=y
-# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
-# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
-# CONFIG_BLK_DEV_IDEDISK_IBM is not set
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
-# CONFIG_BLK_DEV_IDECS is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
-
-#
-# Alternate 1394 support
-#
-# CONFIG_X1394 is not set
-
-#
-# Alternate SCSI support
-#
-# CONFIG_XSCSI is not set
-
-#
-# SCSI support
-#
-# CONFIG_SCSI is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-# CONFIG_SERIAL is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
-
-#
-# Input core support is needed for joysticks
-#
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-# CONFIG_EFI_RTC is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_MWAVE is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# File systems
-#
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_FAT_FS is not set
-# CONFIG_MSDOS_FS is not set
-# CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-# 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
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVFS_MOUNT is not set
-# CONFIG_DEVFS_DEBUG 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
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-# CONFIG_XFS_SUPPORT is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_SMB_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-# CONFIG_NLS is not set
-
-#
-# Console drivers
-#
-CONFIG_VGA_CONSOLE=y
-
-#
-# Frame-buffer support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-
-#
-#   Networking support is needed for USB Networking device support
-#
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
-# Kernel hacking
-#
-CONFIG_DEBUG_KERNEL=y
-CONFIG_IA64_PRINT_HAZARDS=y
-# CONFIG_DISABLE_VHPT is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_IA64_EARLY_PRINTK=y
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_IA64_DEBUG_CMPXCHG is not set
-# CONFIG_IA64_DEBUG_IRQ is not set
-# CONFIG_KDB is not set
-# CONFIG_KDB_MODULES is not set
-# CONFIG_KALLSYMS is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-sp linux-2.4.21-pre6/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-sp
--- linux-2.4.20/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-sp	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/configs/sn2/defconfig-sn2-dig-sp	1970-01-01 00:00:00.000000000 +0000
@@ -1,459 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-
-#
-# Code maturity level options
-#
-# CONFIG_EXPERIMENTAL is not set
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# General setup
-#
-CONFIG_IA64=y
-# CONFIG_ISA is not set
-# CONFIG_EISA is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_ACPI=y
-CONFIG_ACPI_EFI=y
-CONFIG_ACPI_INTERPRETER=y
-CONFIG_ACPI_KERNEL_CONFIG=y
-CONFIG_ITANIUM=y
-# CONFIG_MCKINLEY is not set
-# CONFIG_IA64_GENERIC is not set
-CONFIG_IA64_DIG=y
-# CONFIG_IA64_HP_SIM is not set
-# CONFIG_IA64_SGI_SN1 is not set
-# CONFIG_IA64_SGI_SN2 is not set
-# CONFIG_IA64_PAGE_SIZE_4KB is not set
-# CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
-CONFIG_IA64_BRL_EMU=y
-CONFIG_ITANIUM_BSTEP_SPECIFIC=y
-CONFIG_IA64_L1_CACHE_SHIFT=6
-# CONFIG_NUMA is not set
-# CONFIG_IA64_MCA is not set
-CONFIG_PM=y
-CONFIG_IA64_HAVE_SYNCRONIZED_ITC=y
-# CONFIG_DEVFS_FS is not set
-CONFIG_KCORE_ELF=y
-# CONFIG_SMP is not set
-# CONFIG_IA32_SUPPORT is not set
-# CONFIG_PERFMON is not set
-# CONFIG_IA64_PALINFO is not set
-# CONFIG_EFI_VARS is not set
-# CONFIG_NET is not set
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_SYSCTL is not set
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_ACPI_DEBUG is not set
-# CONFIG_ACPI_BUSMGR is not set
-# CONFIG_ACPI_SYS is not set
-# CONFIG_ACPI_CPU is not set
-# CONFIG_ACPI_BUTTON is not set
-# CONFIG_ACPI_AC is not set
-# CONFIG_ACPI_EC is not set
-# CONFIG_ACPI_CMBATT is not set
-# CONFIG_ACPI_THERMAL is not set
-CONFIG_PCI=y
-# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
-# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
-# CONFIG_BLK_DEV_IDEDISK_IBM is not set
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
-# CONFIG_BLK_DEV_IDECS is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
-
-#
-# Alternate 1394 support
-#
-# CONFIG_X1394 is not set
-
-#
-# Alternate SCSI support
-#
-# CONFIG_XSCSI is not set
-
-#
-# SCSI support
-#
-# CONFIG_SCSI is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-# CONFIG_SERIAL is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
-
-#
-# Input core support is needed for joysticks
-#
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-# CONFIG_EFI_RTC is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_MWAVE is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# File systems
-#
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_FAT_FS is not set
-# CONFIG_MSDOS_FS is not set
-# CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-# 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
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVFS_MOUNT is not set
-# CONFIG_DEVFS_DEBUG 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
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-# CONFIG_XFS_SUPPORT is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_SMB_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-# CONFIG_NLS is not set
-
-#
-# Console drivers
-#
-CONFIG_VGA_CONSOLE=y
-
-#
-# Frame-buffer support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-
-#
-#   Networking support is needed for USB Networking device support
-#
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
-# Kernel hacking
-#
-CONFIG_DEBUG_KERNEL=y
-CONFIG_IA64_PRINT_HAZARDS=y
-# CONFIG_DISABLE_VHPT is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_IA64_EARLY_PRINTK=y
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_IA64_DEBUG_CMPXCHG is not set
-# CONFIG_IA64_DEBUG_IRQ is not set
-# CONFIG_KDB is not set
-# CONFIG_KDB_MODULES is not set
-# CONFIG_KALLSYMS is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/configs/sn2/defconfig-sn2-mp linux-2.4.21-pre6/arch/ia64/sn/configs/sn2/defconfig-sn2-mp
--- linux-2.4.20/arch/ia64/sn/configs/sn2/defconfig-sn2-mp	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/configs/sn2/defconfig-sn2-mp	1970-01-01 00:00:00.000000000 +0000
@@ -1,730 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# General setup
-#
-CONFIG_IA64=y
-# CONFIG_ISA is not set
-# CONFIG_EISA is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_ACPI=y
-CONFIG_ACPI_EFI=y
-CONFIG_ACPI_INTERPRETER=y
-CONFIG_ACPI_KERNEL_CONFIG=y
-# CONFIG_ITANIUM is not set
-CONFIG_MCKINLEY=y
-# CONFIG_IA64_GENERIC is not set
-# CONFIG_IA64_DIG is not set
-# CONFIG_IA64_HP_SIM is not set
-# CONFIG_IA64_SGI_SN1 is not set
-CONFIG_IA64_SGI_SN2=y
-# CONFIG_IA64_PAGE_SIZE_4KB is not set
-# CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
-CONFIG_IA64_L1_CACHE_SHIFT=7
-CONFIG_MCKINLEY_ASTEP_SPECIFIC=y
-CONFIG_MCKINLEY_A0_SPECIFIC=y
-CONFIG_IA64_SGI_SN=y
-CONFIG_IA64_SGI_SN_DEBUG=y
-CONFIG_IA64_SGI_SN_SIM=y
-CONFIG_IA64_SGI_AUTOTEST=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_DEBUG=y
-CONFIG_SERIAL_SGI_L1_PROTOCOL=y
-CONFIG_DISCONTIGMEM=y
-CONFIG_IA64_MCA=y
-CONFIG_NUMA=y
-CONFIG_PERCPU_IRQ=y
-CONFIG_PCIBA=y
-CONFIG_KCORE_ELF=y
-CONFIG_SMP=y
-CONFIG_IA32_SUPPORT=y
-CONFIG_PERFMON=y
-CONFIG_IA64_PALINFO=y
-# CONFIG_EFI_VARS is not set
-CONFIG_NET=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_ACPI_DEBUG is not set
-# CONFIG_ACPI_BUSMGR is not set
-# CONFIG_ACPI_SYS is not set
-# CONFIG_ACPI_CPU is not set
-# CONFIG_ACPI_BUTTON is not set
-# CONFIG_ACPI_AC is not set
-# CONFIG_ACPI_EC is not set
-# CONFIG_ACPI_CMBATT is not set
-# CONFIG_ACPI_THERMAL is not set
-CONFIG_PCI=y
-# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK=y
-CONFIG_RTNETLINK=y
-CONFIG_NETLINK_DEV=y
-CONFIG_NETFILTER=y
-CONFIG_NETFILTER_DEBUG=y
-CONFIG_FILTER=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP 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=y
-
-#
-#   IP: Netfilter Configuration
-#
-# CONFIG_IP_NF_CONNTRACK is not set
-# CONFIG_IP_NF_QUEUE is not set
-# CONFIG_IP_NF_IPTABLES is not set
-# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
-# CONFIG_IPV6 is not set
-# CONFIG_KHTTPD is not set
-# CONFIG_ATM is not set
-
-#
-#  
-#
-# CONFIG_IPX is not set
-# 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
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-# CONFIG_PNPBIOS is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_LAN is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
-# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
-# CONFIG_BLK_DEV_IDEDISK_IBM is not set
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
-# CONFIG_BLK_DEV_IDECS is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
-
-#
-# Alternate 1394 support
-#
-# CONFIG_X1394 is not set
-
-#
-# Alternate SCSI support
-#
-CONFIG_XSCSI=y
-
-#
-# Alternate SCSI support
-#
-CONFIG_XSCSI_DKSC=y
-# CONFIG_XSCSI_QLFC is not set
-# CONFIG_XSCSI_QL is not set
-# CONFIG_XSCSI_SBP2 is not set
-
-#
-# SCSI support
-#
-CONFIG_SCSI=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-CONFIG_SD_EXTRA_DEVS=40
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-# 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 is not set
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# 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_DPT_I2O 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_CPQFCTS 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_NCR53C8XX is not set
-# CONFIG_SCSI_SYM53C8XX is not set
-# CONFIG_SCSI_PAS16 is not set
-# CONFIG_SCSI_PCI2000 is not set
-# CONFIG_SCSI_PCI2220I is not set
-# CONFIG_SCSI_PSI240I is not set
-# CONFIG_SCSI_QLOGIC_FAS is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
-CONFIG_SCSI_QLOGIC_FC=y
-# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set
-# CONFIG_SCSI_QLOGIC_1280 is not set
-# CONFIG_SCSI_QLOGIC_QLA2100 is not set
-# CONFIG_SCSI_SIM710 is not set
-# CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_T128 is not set
-# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_DEBUG is not set
-
-#
-# Network device support
-#
-CONFIG_NETDEVICES=y
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-# CONFIG_SUNLANCE is not set
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNBMAC is not set
-# CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
-# CONFIG_SUNGEM is not set
-# 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_HP100 is not set
-# CONFIG_NET_ISA is not set
-# CONFIG_NET_PCI is not set
-# CONFIG_NET_POCKET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_MYRI_SBUS is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PLIP is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices
-#
-# 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
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
-# Character devices
-#
-# CONFIG_VT is not set
-CONFIG_SERIAL=y
-# CONFIG_SERIAL_CONSOLE is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
-
-#
-# Input core support is needed for joysticks
-#
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-CONFIG_EFI_RTC=y
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_MWAVE is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# File systems
-#
-CONFIG_QUOTA=y
-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
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BFS_FS is not set
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
-# CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=y
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-# CONFIG_RAMFS 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
-CONFIG_PROC_FS=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_MOUNT=y
-CONFIG_DEVFS_DEBUG=y
-CONFIG_DEVPTS_FS=y
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-CONFIG_XFS_SUPPORT=y
-
-#
-# Network File Systems
-#
-# CONFIG_CODA_FS is not set
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-# CONFIG_ROOT_NFS is not set
-CONFIG_NFSD=y
-CONFIG_NFSD_V3=y
-CONFIG_SUNRPC=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-# CONFIG_SMB_FS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_NCPFS_PACKET_SIGNING is not set
-# CONFIG_NCPFS_IOCTL_LOCKING is not set
-# CONFIG_NCPFS_STRONG is not set
-# CONFIG_NCPFS_NFS_NS is not set
-# CONFIG_NCPFS_OS2_NS is not set
-# CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_NCPFS_EXTRAS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-CONFIG_NLS=y
-
-#
-# Native Language Support
-#
-CONFIG_NLS_DEFAULT="n"
-# CONFIG_NLS_CODEPAGE_437 is not set
-# CONFIG_NLS_CODEPAGE_737 is not set
-# CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
-# CONFIG_NLS_CODEPAGE_852 is not set
-# CONFIG_NLS_CODEPAGE_855 is not set
-# CONFIG_NLS_CODEPAGE_857 is not set
-# CONFIG_NLS_CODEPAGE_860 is not set
-# CONFIG_NLS_CODEPAGE_861 is not set
-# CONFIG_NLS_CODEPAGE_862 is not set
-# CONFIG_NLS_CODEPAGE_863 is not set
-# CONFIG_NLS_CODEPAGE_864 is not set
-# CONFIG_NLS_CODEPAGE_865 is not set
-# CONFIG_NLS_CODEPAGE_866 is not set
-# CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_936 is not set
-# CONFIG_NLS_CODEPAGE_950 is not set
-# CONFIG_NLS_CODEPAGE_932 is not set
-# CONFIG_NLS_CODEPAGE_949 is not set
-# CONFIG_NLS_CODEPAGE_874 is not set
-# CONFIG_NLS_ISO8859_8 is not set
-# CONFIG_NLS_CODEPAGE_1251 is not set
-# CONFIG_NLS_ISO8859_1 is not set
-# CONFIG_NLS_ISO8859_2 is not set
-# CONFIG_NLS_ISO8859_3 is not set
-# CONFIG_NLS_ISO8859_4 is not set
-# CONFIG_NLS_ISO8859_5 is not set
-# CONFIG_NLS_ISO8859_6 is not set
-# CONFIG_NLS_ISO8859_7 is not set
-# CONFIG_NLS_ISO8859_9 is not set
-# CONFIG_NLS_ISO8859_13 is not set
-# CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
-# CONFIG_NLS_KOI8_R is not set
-# CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BLUEZ is not set
-
-#
-# Kernel hacking
-#
-CONFIG_DEBUG_KERNEL=y
-CONFIG_IA64_PRINT_HAZARDS=y
-# CONFIG_DISABLE_VHPT is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_IA64_EARLY_PRINTK=y
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_IA64_DEBUG_CMPXCHG is not set
-# CONFIG_IA64_DEBUG_IRQ is not set
-# CONFIG_KDB is not set
-# CONFIG_KDB_MODULES is not set
-CONFIG_KALLSYMS=y
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/configs/sn2/defconfig-sn2-mp-modules linux-2.4.21-pre6/arch/ia64/sn/configs/sn2/defconfig-sn2-mp-modules
--- linux-2.4.20/arch/ia64/sn/configs/sn2/defconfig-sn2-mp-modules	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/configs/sn2/defconfig-sn2-mp-modules	1970-01-01 00:00:00.000000000 +0000
@@ -1,732 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
-
-#
-# General setup
-#
-CONFIG_IA64=y
-# CONFIG_ISA is not set
-# CONFIG_EISA is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_ACPI=y
-CONFIG_ACPI_EFI=y
-CONFIG_ACPI_INTERPRETER=y
-CONFIG_ACPI_KERNEL_CONFIG=y
-# CONFIG_ITANIUM is not set
-CONFIG_MCKINLEY=y
-# CONFIG_IA64_GENERIC is not set
-# CONFIG_IA64_DIG is not set
-# CONFIG_IA64_HP_SIM is not set
-# CONFIG_IA64_SGI_SN1 is not set
-CONFIG_IA64_SGI_SN2=y
-# CONFIG_IA64_PAGE_SIZE_4KB is not set
-# CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
-CONFIG_IA64_L1_CACHE_SHIFT=7
-CONFIG_MCKINLEY_ASTEP_SPECIFIC=y
-CONFIG_MCKINLEY_A0_SPECIFIC=y
-CONFIG_IA64_SGI_SN=y
-CONFIG_IA64_SGI_SN_DEBUG=y
-CONFIG_IA64_SGI_SN_SIM=y
-CONFIG_IA64_SGI_AUTOTEST=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_DEBUG=y
-# CONFIG_SERIAL_SGI_L1_PROTOCOL is not set
-CONFIG_DISCONTIGMEM=y
-CONFIG_IA64_MCA=y
-CONFIG_NUMA=y
-CONFIG_PERCPU_IRQ=y
-CONFIG_PCIBA=y
-CONFIG_KCORE_ELF=y
-CONFIG_SMP=y
-CONFIG_IA32_SUPPORT=y
-CONFIG_PERFMON=y
-CONFIG_IA64_PALINFO=y
-# CONFIG_EFI_VARS is not set
-CONFIG_NET=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_ACPI_DEBUG is not set
-# CONFIG_ACPI_BUSMGR is not set
-# CONFIG_ACPI_SYS is not set
-# CONFIG_ACPI_CPU is not set
-# CONFIG_ACPI_BUTTON is not set
-# CONFIG_ACPI_AC is not set
-# CONFIG_ACPI_EC is not set
-# CONFIG_ACPI_CMBATT is not set
-# CONFIG_ACPI_THERMAL is not set
-CONFIG_PCI=y
-# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK=y
-CONFIG_RTNETLINK=y
-CONFIG_NETLINK_DEV=y
-CONFIG_NETFILTER=y
-CONFIG_NETFILTER_DEBUG=y
-CONFIG_FILTER=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP 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=y
-
-#
-#   IP: Netfilter Configuration
-#
-# CONFIG_IP_NF_CONNTRACK is not set
-# CONFIG_IP_NF_QUEUE is not set
-# CONFIG_IP_NF_IPTABLES is not set
-# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
-# CONFIG_IPV6 is not set
-# CONFIG_KHTTPD is not set
-# CONFIG_ATM is not set
-
-#
-#  
-#
-# CONFIG_IPX is not set
-# 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
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-# CONFIG_PNPBIOS is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_LAN is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
-# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
-# CONFIG_BLK_DEV_IDEDISK_IBM is not set
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
-# CONFIG_BLK_DEV_IDECS is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
-
-#
-# Alternate 1394 support
-#
-# CONFIG_X1394 is not set
-
-#
-# Alternate SCSI support
-#
-CONFIG_XSCSI=y
-
-#
-# Alternate SCSI support
-#
-CONFIG_XSCSI_DKSC=y
-# CONFIG_XSCSI_QLFC is not set
-# CONFIG_XSCSI_QL is not set
-# CONFIG_XSCSI_SBP2 is not set
-
-#
-# SCSI support
-#
-CONFIG_SCSI=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-CONFIG_SD_EXTRA_DEVS=40
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-# 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 is not set
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# 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_DPT_I2O 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_CPQFCTS 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_NCR53C8XX is not set
-# CONFIG_SCSI_SYM53C8XX is not set
-# CONFIG_SCSI_PAS16 is not set
-# CONFIG_SCSI_PCI2000 is not set
-# CONFIG_SCSI_PCI2220I is not set
-# CONFIG_SCSI_PSI240I is not set
-# CONFIG_SCSI_QLOGIC_FAS is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
-CONFIG_SCSI_QLOGIC_FC=y
-# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set
-# CONFIG_SCSI_QLOGIC_1280 is not set
-# CONFIG_SCSI_QLOGIC_QLA2100 is not set
-# CONFIG_SCSI_SIM710 is not set
-# CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_T128 is not set
-# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_DEBUG is not set
-
-#
-# Network device support
-#
-CONFIG_NETDEVICES=y
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-# CONFIG_SUNLANCE is not set
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNBMAC is not set
-# CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
-# CONFIG_SUNGEM is not set
-# 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_HP100 is not set
-# CONFIG_NET_ISA is not set
-# CONFIG_NET_PCI is not set
-# CONFIG_NET_POCKET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_MYRI_SBUS is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PLIP is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices
-#
-# 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
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
-# Character devices
-#
-# CONFIG_VT is not set
-CONFIG_SERIAL=y
-# CONFIG_SERIAL_CONSOLE is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
-
-#
-# Input core support is needed for joysticks
-#
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-CONFIG_EFI_RTC=y
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_MWAVE is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# File systems
-#
-CONFIG_QUOTA=y
-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
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BFS_FS is not set
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
-# CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=y
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-# CONFIG_RAMFS 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
-CONFIG_PROC_FS=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_MOUNT=y
-CONFIG_DEVFS_DEBUG=y
-CONFIG_DEVPTS_FS=y
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-CONFIG_XFS_SUPPORT=y
-
-#
-# Network File Systems
-#
-# CONFIG_CODA_FS is not set
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-# CONFIG_ROOT_NFS is not set
-CONFIG_NFSD=y
-CONFIG_NFSD_V3=y
-CONFIG_SUNRPC=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-# CONFIG_SMB_FS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_NCPFS_PACKET_SIGNING is not set
-# CONFIG_NCPFS_IOCTL_LOCKING is not set
-# CONFIG_NCPFS_STRONG is not set
-# CONFIG_NCPFS_NFS_NS is not set
-# CONFIG_NCPFS_OS2_NS is not set
-# CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_NCPFS_EXTRAS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-CONFIG_NLS=y
-
-#
-# Native Language Support
-#
-CONFIG_NLS_DEFAULT="n"
-# CONFIG_NLS_CODEPAGE_437 is not set
-# CONFIG_NLS_CODEPAGE_737 is not set
-# CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
-# CONFIG_NLS_CODEPAGE_852 is not set
-# CONFIG_NLS_CODEPAGE_855 is not set
-# CONFIG_NLS_CODEPAGE_857 is not set
-# CONFIG_NLS_CODEPAGE_860 is not set
-# CONFIG_NLS_CODEPAGE_861 is not set
-# CONFIG_NLS_CODEPAGE_862 is not set
-# CONFIG_NLS_CODEPAGE_863 is not set
-# CONFIG_NLS_CODEPAGE_864 is not set
-# CONFIG_NLS_CODEPAGE_865 is not set
-# CONFIG_NLS_CODEPAGE_866 is not set
-# CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_936 is not set
-# CONFIG_NLS_CODEPAGE_950 is not set
-# CONFIG_NLS_CODEPAGE_932 is not set
-# CONFIG_NLS_CODEPAGE_949 is not set
-# CONFIG_NLS_CODEPAGE_874 is not set
-# CONFIG_NLS_ISO8859_8 is not set
-# CONFIG_NLS_CODEPAGE_1251 is not set
-# CONFIG_NLS_ISO8859_1 is not set
-# CONFIG_NLS_ISO8859_2 is not set
-# CONFIG_NLS_ISO8859_3 is not set
-# CONFIG_NLS_ISO8859_4 is not set
-# CONFIG_NLS_ISO8859_5 is not set
-# CONFIG_NLS_ISO8859_6 is not set
-# CONFIG_NLS_ISO8859_7 is not set
-# CONFIG_NLS_ISO8859_9 is not set
-# CONFIG_NLS_ISO8859_13 is not set
-# CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
-# CONFIG_NLS_KOI8_R is not set
-# CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BLUEZ is not set
-
-#
-# Kernel hacking
-#
-CONFIG_DEBUG_KERNEL=y
-CONFIG_IA64_PRINT_HAZARDS=y
-# CONFIG_DISABLE_VHPT is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_IA64_EARLY_PRINTK=y
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_IA64_DEBUG_CMPXCHG is not set
-# CONFIG_IA64_DEBUG_IRQ is not set
-# CONFIG_KDB is not set
-# CONFIG_KDB_MODULES is not set
-CONFIG_KALLSYMS=y
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/configs/sn2/defconfig-sn2-prom-medusa linux-2.4.21-pre6/arch/ia64/sn/configs/sn2/defconfig-sn2-prom-medusa
--- linux-2.4.20/arch/ia64/sn/configs/sn2/defconfig-sn2-prom-medusa	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/configs/sn2/defconfig-sn2-prom-medusa	1970-01-01 00:00:00.000000000 +0000
@@ -1,537 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# General setup
-#
-CONFIG_IA64=y
-# CONFIG_ISA is not set
-# CONFIG_EISA is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_ACPI=y
-CONFIG_ACPI_EFI=y
-CONFIG_ACPI_INTERPRETER=y
-CONFIG_ACPI_KERNEL_CONFIG=y
-# CONFIG_ITANIUM is not set
-CONFIG_MCKINLEY=y
-# CONFIG_IA64_GENERIC is not set
-# CONFIG_IA64_DIG is not set
-# CONFIG_IA64_HP_SIM is not set
-# CONFIG_IA64_SGI_SN1 is not set
-CONFIG_IA64_SGI_SN2=y
-# CONFIG_IA64_PAGE_SIZE_4KB is not set
-# CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
-CONFIG_IA64_L1_CACHE_SHIFT=7
-CONFIG_MCKINLEY_ASTEP_SPECIFIC=y
-CONFIG_MCKINLEY_A0_SPECIFIC=y
-CONFIG_IA64_SGI_SN=y
-CONFIG_IA64_SGI_SN_DEBUG=y
-CONFIG_IA64_SGI_SN_SIM=y
-CONFIG_IA64_SGI_AUTOTEST=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_DEBUG=y
-CONFIG_SERIAL_SGI_L1_PROTOCOL=y
-CONFIG_DISCONTIGMEM=y
-CONFIG_IA64_MCA=y
-CONFIG_NUMA=y
-CONFIG_PERCPU_IRQ=y
-CONFIG_PCIBA=y
-CONFIG_KCORE_ELF=y
-CONFIG_SMP=y
-# CONFIG_IA32_SUPPORT is not set
-CONFIG_PERFMON=y
-CONFIG_IA64_PALINFO=y
-# CONFIG_EFI_VARS is not set
-# CONFIG_NET is not set
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_ACPI_DEBUG is not set
-# CONFIG_ACPI_BUSMGR is not set
-# CONFIG_ACPI_SYS is not set
-# CONFIG_ACPI_CPU is not set
-# CONFIG_ACPI_BUTTON is not set
-# CONFIG_ACPI_AC is not set
-# CONFIG_ACPI_EC is not set
-# CONFIG_ACPI_CMBATT is not set
-# CONFIG_ACPI_THERMAL is not set
-CONFIG_PCI=y
-# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-# CONFIG_PNPBIOS is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
-# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
-# CONFIG_BLK_DEV_IDEDISK_IBM is not set
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
-# CONFIG_BLK_DEV_IDECS is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
-
-#
-# Alternate 1394 support
-#
-# CONFIG_X1394 is not set
-
-#
-# Alternate SCSI support
-#
-CONFIG_XSCSI=y
-
-#
-# Alternate SCSI support
-#
-CONFIG_XSCSI_DKSC=y
-# CONFIG_XSCSI_QLFC is not set
-# CONFIG_XSCSI_QL is not set
-# CONFIG_XSCSI_SBP2 is not set
-
-#
-# SCSI support
-#
-CONFIG_SCSI=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-CONFIG_SD_EXTRA_DEVS=40
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-# 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 is not set
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# 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_DPT_I2O 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_CPQFCTS 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_NCR53C8XX is not set
-# CONFIG_SCSI_SYM53C8XX is not set
-# CONFIG_SCSI_PAS16 is not set
-# CONFIG_SCSI_PCI2000 is not set
-# CONFIG_SCSI_PCI2220I is not set
-# CONFIG_SCSI_PSI240I is not set
-# CONFIG_SCSI_QLOGIC_FAS is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
-CONFIG_SCSI_QLOGIC_FC=y
-# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set
-# CONFIG_SCSI_QLOGIC_1280 is not set
-# CONFIG_SCSI_QLOGIC_QLA2100 is not set
-# CONFIG_SCSI_SIM710 is not set
-# CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_T128 is not set
-# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_DEBUG is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
-# Character devices
-#
-# CONFIG_VT is not set
-CONFIG_SERIAL=y
-# CONFIG_SERIAL_CONSOLE is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
-
-#
-# Input core support is needed for joysticks
-#
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-# CONFIG_EFI_RTC is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_MWAVE is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# File systems
-#
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_FAT_FS is not set
-# CONFIG_MSDOS_FS is not set
-# CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-# 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
-CONFIG_PROC_FS=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_MOUNT=y
-CONFIG_DEVFS_DEBUG=y
-CONFIG_DEVPTS_FS=y
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-CONFIG_XFS_SUPPORT=y
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_SMB_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-# CONFIG_NLS is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-
-#
-#   Networking support is needed for USB Networking device support
-#
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# Kernel hacking
-#
-CONFIG_DEBUG_KERNEL=y
-CONFIG_IA64_PRINT_HAZARDS=y
-# CONFIG_DISABLE_VHPT is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_IA64_EARLY_PRINTK=y
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_IA64_DEBUG_CMPXCHG is not set
-# CONFIG_IA64_DEBUG_IRQ is not set
-# CONFIG_KDB is not set
-# CONFIG_KDB_MODULES is not set
-# CONFIG_KALLSYMS is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/configs/sn2/defconfig-sn2-sp linux-2.4.21-pre6/arch/ia64/sn/configs/sn2/defconfig-sn2-sp
--- linux-2.4.20/arch/ia64/sn/configs/sn2/defconfig-sn2-sp	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/configs/sn2/defconfig-sn2-sp	1970-01-01 00:00:00.000000000 +0000
@@ -1,730 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# General setup
-#
-CONFIG_IA64=y
-# CONFIG_ISA is not set
-# CONFIG_EISA is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-CONFIG_ACPI=y
-CONFIG_ACPI_EFI=y
-CONFIG_ACPI_INTERPRETER=y
-CONFIG_ACPI_KERNEL_CONFIG=y
-# CONFIG_ITANIUM is not set
-CONFIG_MCKINLEY=y
-# CONFIG_IA64_GENERIC is not set
-# CONFIG_IA64_DIG is not set
-# CONFIG_IA64_HP_SIM is not set
-# CONFIG_IA64_SGI_SN1 is not set
-CONFIG_IA64_SGI_SN2=y
-# CONFIG_IA64_PAGE_SIZE_4KB is not set
-# CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
-CONFIG_IA64_L1_CACHE_SHIFT=7
-CONFIG_MCKINLEY_ASTEP_SPECIFIC=y
-CONFIG_MCKINLEY_A0_SPECIFIC=y
-CONFIG_IA64_SGI_SN=y
-CONFIG_IA64_SGI_SN_DEBUG=y
-CONFIG_IA64_SGI_SN_SIM=y
-CONFIG_IA64_SGI_AUTOTEST=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_DEBUG=y
-CONFIG_SERIAL_SGI_L1_PROTOCOL=y
-CONFIG_DISCONTIGMEM=y
-CONFIG_IA64_MCA=y
-CONFIG_NUMA=y
-CONFIG_PERCPU_IRQ=y
-CONFIG_PCIBA=y
-CONFIG_KCORE_ELF=y
-# CONFIG_SMP is not set
-CONFIG_IA32_SUPPORT=y
-CONFIG_PERFMON=y
-CONFIG_IA64_PALINFO=y
-# CONFIG_EFI_VARS is not set
-CONFIG_NET=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_ACPI_DEBUG is not set
-# CONFIG_ACPI_BUSMGR is not set
-# CONFIG_ACPI_SYS is not set
-# CONFIG_ACPI_CPU is not set
-# CONFIG_ACPI_BUTTON is not set
-# CONFIG_ACPI_AC is not set
-# CONFIG_ACPI_EC is not set
-# CONFIG_ACPI_CMBATT is not set
-# CONFIG_ACPI_THERMAL is not set
-CONFIG_PCI=y
-# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK=y
-CONFIG_RTNETLINK=y
-CONFIG_NETLINK_DEV=y
-CONFIG_NETFILTER=y
-CONFIG_NETFILTER_DEBUG=y
-CONFIG_FILTER=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP 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=y
-
-#
-#   IP: Netfilter Configuration
-#
-# CONFIG_IP_NF_CONNTRACK is not set
-# CONFIG_IP_NF_QUEUE is not set
-# CONFIG_IP_NF_IPTABLES is not set
-# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
-# CONFIG_IPV6 is not set
-# CONFIG_KHTTPD is not set
-# CONFIG_ATM is not set
-
-#
-#  
-#
-# CONFIG_IPX is not set
-# 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
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-# CONFIG_PNPBIOS is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_LAN is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
-# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
-# CONFIG_BLK_DEV_IDEDISK_IBM is not set
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
-# CONFIG_BLK_DEV_IDECS is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
-# CONFIG_BLK_DEV_IDEPCI is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
-
-#
-# Alternate 1394 support
-#
-# CONFIG_X1394 is not set
-
-#
-# Alternate SCSI support
-#
-CONFIG_XSCSI=y
-
-#
-# Alternate SCSI support
-#
-CONFIG_XSCSI_DKSC=y
-# CONFIG_XSCSI_QLFC is not set
-# CONFIG_XSCSI_QL is not set
-# CONFIG_XSCSI_SBP2 is not set
-
-#
-# SCSI support
-#
-CONFIG_SCSI=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-CONFIG_SD_EXTRA_DEVS=40
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-# 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 is not set
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# 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_DPT_I2O 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_CPQFCTS 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_NCR53C8XX is not set
-# CONFIG_SCSI_SYM53C8XX is not set
-# CONFIG_SCSI_PAS16 is not set
-# CONFIG_SCSI_PCI2000 is not set
-# CONFIG_SCSI_PCI2220I is not set
-# CONFIG_SCSI_PSI240I is not set
-# CONFIG_SCSI_QLOGIC_FAS is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
-CONFIG_SCSI_QLOGIC_FC=y
-# CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set
-# CONFIG_SCSI_QLOGIC_1280 is not set
-# CONFIG_SCSI_QLOGIC_QLA2100 is not set
-# CONFIG_SCSI_SIM710 is not set
-# CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_T128 is not set
-# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_DEBUG is not set
-
-#
-# Network device support
-#
-CONFIG_NETDEVICES=y
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-# CONFIG_SUNLANCE is not set
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNBMAC is not set
-# CONFIG_SUNQE is not set
-# CONFIG_SUNLANCE is not set
-# CONFIG_SUNGEM is not set
-# 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_HP100 is not set
-# CONFIG_NET_ISA is not set
-# CONFIG_NET_PCI is not set
-# CONFIG_NET_POCKET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_MYRI_SBUS is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PLIP is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices
-#
-# 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
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
-# Character devices
-#
-# CONFIG_VT is not set
-CONFIG_SERIAL=y
-# CONFIG_SERIAL_CONSOLE is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-
-#
-# Input core support is needed for gameports
-#
-
-#
-# Input core support is needed for joysticks
-#
-# CONFIG_QIC02_TAPE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-CONFIG_EFI_RTC=y
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
-# CONFIG_MWAVE is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# File systems
-#
-CONFIG_QUOTA=y
-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
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BFS_FS is not set
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
-# CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=y
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-# CONFIG_RAMFS 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
-CONFIG_PROC_FS=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_MOUNT=y
-CONFIG_DEVFS_DEBUG=y
-CONFIG_DEVPTS_FS=y
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-CONFIG_XFS_SUPPORT=y
-
-#
-# Network File Systems
-#
-# CONFIG_CODA_FS is not set
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-# CONFIG_ROOT_NFS is not set
-CONFIG_NFSD=y
-CONFIG_NFSD_V3=y
-CONFIG_SUNRPC=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-# CONFIG_SMB_FS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_NCPFS_PACKET_SIGNING is not set
-# CONFIG_NCPFS_IOCTL_LOCKING is not set
-# CONFIG_NCPFS_STRONG is not set
-# CONFIG_NCPFS_NFS_NS is not set
-# CONFIG_NCPFS_OS2_NS is not set
-# CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_NCPFS_EXTRAS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-CONFIG_NLS=y
-
-#
-# Native Language Support
-#
-CONFIG_NLS_DEFAULT="n"
-# CONFIG_NLS_CODEPAGE_437 is not set
-# CONFIG_NLS_CODEPAGE_737 is not set
-# CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
-# CONFIG_NLS_CODEPAGE_852 is not set
-# CONFIG_NLS_CODEPAGE_855 is not set
-# CONFIG_NLS_CODEPAGE_857 is not set
-# CONFIG_NLS_CODEPAGE_860 is not set
-# CONFIG_NLS_CODEPAGE_861 is not set
-# CONFIG_NLS_CODEPAGE_862 is not set
-# CONFIG_NLS_CODEPAGE_863 is not set
-# CONFIG_NLS_CODEPAGE_864 is not set
-# CONFIG_NLS_CODEPAGE_865 is not set
-# CONFIG_NLS_CODEPAGE_866 is not set
-# CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_936 is not set
-# CONFIG_NLS_CODEPAGE_950 is not set
-# CONFIG_NLS_CODEPAGE_932 is not set
-# CONFIG_NLS_CODEPAGE_949 is not set
-# CONFIG_NLS_CODEPAGE_874 is not set
-# CONFIG_NLS_ISO8859_8 is not set
-# CONFIG_NLS_CODEPAGE_1251 is not set
-# CONFIG_NLS_ISO8859_1 is not set
-# CONFIG_NLS_ISO8859_2 is not set
-# CONFIG_NLS_ISO8859_3 is not set
-# CONFIG_NLS_ISO8859_4 is not set
-# CONFIG_NLS_ISO8859_5 is not set
-# CONFIG_NLS_ISO8859_6 is not set
-# CONFIG_NLS_ISO8859_7 is not set
-# CONFIG_NLS_ISO8859_9 is not set
-# CONFIG_NLS_ISO8859_13 is not set
-# CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
-# CONFIG_NLS_KOI8_R is not set
-# CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-
-#
-#   Input core support is needed for USB HID
-#
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BLUEZ is not set
-
-#
-# Kernel hacking
-#
-CONFIG_DEBUG_KERNEL=y
-CONFIG_IA64_PRINT_HAZARDS=y
-# CONFIG_DISABLE_VHPT is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_IA64_EARLY_PRINTK=y
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_IA64_DEBUG_CMPXCHG is not set
-# CONFIG_IA64_DEBUG_IRQ is not set
-# CONFIG_KDB is not set
-# CONFIG_KDB_MODULES is not set
-CONFIG_KALLSYMS=y
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/fakeprom/Makefile linux-2.4.21-pre6/arch/ia64/sn/fakeprom/Makefile
--- linux-2.4.20/arch/ia64/sn/fakeprom/Makefile	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/fakeprom/Makefile	2003-03-26 23:49:54.000000000 +0000
@@ -3,7 +3,7 @@
 # License.  See the file "COPYING" in the main directory of this archive
 # for more details.
 #
-#  Copyright (c) 2000-2001 Silicon Graphics, Inc.  All rights reserved.
+#  Copyright (c) 2000-2002 Silicon Graphics, Inc.  All rights reserved.
 #
 
 TOPDIR=../../../..
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/fakeprom/README linux-2.4.21-pre6/arch/ia64/sn/fakeprom/README
--- linux-2.4.20/arch/ia64/sn/fakeprom/README	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/fakeprom/README	2003-03-26 23:49:38.000000000 +0000
@@ -1,3 +1,35 @@
+/*
+ * Copyright (c) 2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify it 
+ * under the terms of version 2 of the GNU General Public License 
+ * as published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope that it would be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
+ * 
+ * Further, this software is distributed without any warranty that it is 
+ * free of the rightful claim of any third person regarding infringement 
+ * or the like.  Any license provided herein, whether implied or 
+ * otherwise, applies only to this software file.  Patent licenses, if 
+ * any, provided herein do not apply to combinations of this program with 
+ * other software, or any other product whatsoever.
+ * 
+ * You should have received a copy of the GNU General Public 
+ * License along with this program; if not, write the Free Software 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ * 
+ * Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, 
+ * Mountain View, CA  94043, or:
+ * 
+ * http://www.sgi.com 
+ * 
+ * For further information regarding this notice, see: 
+ * 
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan
+ */
+
 This directory contains the files required to build
 the fake PROM image that is currently being used to
 boot IA64 kernels running under the SGI Medusa kernel.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/fakeprom/fpmem.c linux-2.4.21-pre6/arch/ia64/sn/fakeprom/fpmem.c
--- linux-2.4.20/arch/ia64/sn/fakeprom/fpmem.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/fakeprom/fpmem.c	2003-03-26 23:49:29.000000000 +0000
@@ -54,10 +54,10 @@
 #define PROMRESERVED_SIZE	(1*MB)
 
 #ifdef CONFIG_IA64_SGI_SN1
-#define PHYS_ADDRESS(_n, _x)		(((long)_n<<33L) | (long)_x)
+#define PHYS_ADDRESS(_n, _x)		(((long)_n<<33) | (long)_x)
 #define MD_BANK_SHFT 30
 #else
-#define PHYS_ADDRESS(_n, _x)		(((long)_n<<38L) | (long)_x | 0x3000000000UL)
+#define PHYS_ADDRESS(_n, _x)		(((long)_n<<38) | (long)_x | 0x3000000000UL)
 #define MD_BANK_SHFT 34
 #endif
 
@@ -94,7 +94,7 @@
 int
 IsCpuPresent(int cnode, int cpu)
 {
-	return  sn_memmap[cnode].cpuconfig & (1<<cpu);
+	return  sn_memmap[cnode].cpuconfig & (1UL<<cpu);
 }
 
 
@@ -205,7 +205,17 @@
 				 */
 				numbytes = numbytes * 31 / 32;
 #endif
-				numbytes -= 1000;
+				/*
+				 * Only emulate the memory prom grabs
+				 * if we have lots of memory, to allow
+				 * us to simulate smaller memory configs than
+				 * we can actually run on h/w.  Otherwise,
+				 * linux throws away a whole "granule".
+				 */
+				if (cnode == 0 && bank == 0 &&
+				    numbytes > 128*1024*1024) {
+					numbytes -= 1000;
+				}
 
                                 /*
                                  * Check for the node 0 hole. Since banks cant
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/fakeprom/fprom.lds linux-2.4.21-pre6/arch/ia64/sn/fakeprom/fprom.lds
--- linux-2.4.20/arch/ia64/sn/fakeprom/fprom.lds	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/fakeprom/fprom.lds	2003-03-26 23:49:51.000000000 +0000
@@ -1,3 +1,34 @@
+/*
+ * Copyright (c) 2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify it 
+ * under the terms of version 2 of the GNU General Public License 
+ * as published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope that it would be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
+ * 
+ * Further, this software is distributed without any warranty that it is 
+ * free of the rightful claim of any third person regarding infringement 
+ * or the like.  Any license provided herein, whether implied or 
+ * otherwise, applies only to this software file.  Patent licenses, if 
+ * any, provided herein do not apply to combinations of this program with 
+ * other software, or any other product whatsoever.
+ * 
+ * You should have received a copy of the GNU General Public 
+ * License along with this program; if not, write the Free Software 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ * 
+ * Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, 
+ * Mountain View, CA  94043, or:
+ * 
+ * http://www.sgi.com 
+ * 
+ * For further information regarding this notice, see: 
+ * 
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan
+ */
 
 OUTPUT_FORMAT("elf64-ia64-little")
 OUTPUT_ARCH(ia64)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/fakeprom/fpromasm.S linux-2.4.21-pre6/arch/ia64/sn/fakeprom/fpromasm.S
--- linux-2.4.20/arch/ia64/sn/fakeprom/fpromasm.S	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/fakeprom/fpromasm.S	2003-03-26 23:49:19.000000000 +0000
@@ -180,7 +180,7 @@
 
 
 // Now call main & pass it the current LID value.
-	alloc 		r0=ar.pfs,0,0,2,0
+	alloc 		r2=ar.pfs,0,0,2,0
 	mov    		r32=r26
 	mov   		r33=r8;;
 	br.call.sptk.few rp=fmain
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/fakeprom/fw-emu.c linux-2.4.21-pre6/arch/ia64/sn/fakeprom/fw-emu.c
--- linux-2.4.20/arch/ia64/sn/fakeprom/fw-emu.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/fakeprom/fw-emu.c	2003-03-26 23:49:51.000000000 +0000
@@ -46,10 +46,26 @@
 #include <asm/sn/sn2/addrs.h>
 #include <asm/sn/sn2/shub_mmr.h>
 #endif
-#include <asm/acpi-ext.h>
+#include <linux/acpi.h>
 #include "fpmem.h"
 
-#define zzACPI_1_0	1		/* Include ACPI 1.0 tables */
+#define RSDP_NAME               "RSDP"
+#define RSDP_SIG                "RSD PTR "  /* RSDT Pointer signature */
+#define APIC_SIG                "APIC"      /* Multiple APIC Description Table */
+#define DSDT_SIG                "DSDT"      /* Differentiated System Description Table */
+#define FADT_SIG                "FACP"      /* Fixed ACPI Description Table */
+#define FACS_SIG                "FACS"      /* Firmware ACPI Control Structure */
+#define PSDT_SIG                "PSDT"      /* Persistent System Description Table */
+#define RSDT_SIG                "RSDT"      /* Root System Description Table */
+#define XSDT_SIG                "XSDT"      /* Extended  System Description Table */
+#define SSDT_SIG                "SSDT"      /* Secondary System Description Table */
+#define SBST_SIG                "SBST"      /* Smart Battery Specification Table */
+#define SPIC_SIG                "SPIC"      /* IOSAPIC table */
+#define SRAT_SIG                "SRAT"      /* SRAT table */
+#define SLIT_SIG                "SLIT"      /* SLIT table */
+#define BOOT_SIG                "BOOT"      /* Boot table */
+#define ACPI_SRAT_REVISION 1
+#define ACPI_SLIT_REVISION 1
 
 #define OEMID			"SGI"
 #ifdef CONFIG_IA64_SGI_SN1
@@ -77,11 +93,7 @@
 #define CPUS_PER_FSB		2
 #define CPUS_PER_FSB_MASK	(CPUS_PER_FSB-1)
 
-#ifdef ACPI_1_0
-#define NUM_EFI_DESCS		3
-#else
 #define NUM_EFI_DESCS		2
-#endif
 
 #define RSDP_CHECKSUM_LENGTH	20
 
@@ -139,22 +151,16 @@
 		    + sizeof(struct ia64_sal_systab)
 		    + sizeof(struct ia64_sal_desc_entry_point)
 		    + sizeof(struct ia64_sal_desc_ap_wakeup)
-#ifdef ACPI_1_0
-		    + sizeof(acpi_rsdp_t)
-		    + sizeof(acpi_rsdt_t)
-		    + sizeof(acpi_sapic_t)
-		    + MAX_LSAPICS*(sizeof(acpi_entry_lsapic_t))
-#endif
-		    + sizeof(acpi20_rsdp_t)
-		    + sizeof(acpi_xsdt_t)
-		    + sizeof(acpi_slit_t)
+		    + sizeof(struct acpi20_table_rsdp)
+		    + sizeof(struct acpi_table_xsdt)
+		    + sizeof(struct acpi_table_slit)
 		    +   MAX_SN_NODES*MAX_SN_NODES+8
-		    + sizeof(acpi_madt_t)
+		    + sizeof(struct acpi_table_madt)
 		    +   16*MAX_CPUS
 		    + (1+8*MAX_SN_NODES)*(sizeof(efi_memory_desc_t))
-		    + sizeof(acpi_srat_t)
-		    +   MAX_CPUS*sizeof(srat_cpu_affinity_t)
-		    +   MAX_SN_NODES*sizeof(srat_memory_affinity_t)
+		    + sizeof(struct acpi_table_srat)
+		    +   MAX_CPUS*sizeof(struct acpi_table_processor_affinity)
+		    +   MAX_SN_NODES*sizeof(struct acpi_table_memory_affinity)
 		    + sizeof(ia64_sal_desc_ptc_t) +
 		    + MAX_SN_NODES*sizeof(ia64_sal_ptc_domain_info_t) +
 		    + MAX_CPUS*sizeof(ia64_sal_ptc_domain_proc_entry_t) +
@@ -280,6 +286,7 @@
 	} else if (index == SAL_GET_STATE_INFO) {
 		;
 	} else if (index == SAL_GET_STATE_INFO_SIZE) {
+		r9 = 10000;
 		;
 	} else if (index == SAL_CLEAR_STATE_INFO) {
 		;
@@ -334,6 +341,8 @@
 		status = -1;
 	} else if (index == SN_SAL_CONSOLE_POLL) {
 		status = -1;
+	} else if (index == SN_SAL_SYSCTL_IOBRICK_MODULE_GET) {
+		status = -1;
 	} else {
 		status = -1;
 	}
@@ -402,7 +411,7 @@
 }
 
 void
-acpi_table_init(acpi_desc_table_hdr_t *p, char *sig, int siglen, int revision, int oem_revision)
+acpi_table_initx(struct acpi_table_header *p, char *sig, int siglen, int revision, int oem_revision)
 {
 	memcpy(p->signature, sig, siglen);
 	memcpy(p->oem_id, OEMID, 6);
@@ -410,12 +419,12 @@
 	memcpy(p->oem_table_id+4, PRODUCT, 4);
 	p->revision = revision;
 	p->oem_revision = (revision<<16) + oem_revision;
-	p->creator_id = 1;
-	p->creator_revision = 1;
+	memcpy(p->asl_compiler_id, "FPRM", 4);
+	p->asl_compiler_revision = 1;
 }
 
 void
-acpi_checksum(acpi_desc_table_hdr_t *p, int length)
+acpi_checksum(struct acpi_table_header *p, int length)
 {
 	u8	*cp, *cpe, checksum;
 
@@ -428,16 +437,22 @@
 }
 
 void
-acpi_checksum_rsdp20(acpi20_rsdp_t *p, int length)
+acpi_checksum_rsdp20(struct acpi20_table_rsdp *p, int length)
 {
 	u8	*cp, *cpe, checksum;
 
 	p->checksum = 0;
+	p->ext_checksum = 0;
 	p->length = length;
 	checksum = 0;
-	for (cp=(u8*)p, cpe=cp+RSDP_CHECKSUM_LENGTH; cp<cpe; cp++)
+	for (cp=(u8*)p, cpe=cp+20; cp<cpe; cp++)
 		checksum += *cp;
 	p->checksum = -checksum;
+
+	checksum = 0;
+	for (cp=(u8*)p, cpe=cp+length; cp<cpe; cp++)
+		checksum += *cp;
+	p->ext_checksum = -checksum;
 }
 
 int
@@ -462,21 +477,15 @@
 	static ia64_sal_desc_ptc_t *sal_ptc;
 	static ia64_sal_ptc_domain_info_t *sal_ptcdi;
 	static ia64_sal_ptc_domain_proc_entry_t *sal_ptclid;
-#ifdef ACPI_1_0
-	static acpi_rsdp_t *acpi_rsdp;
-	static acpi_rsdt_t *acpi_rsdt;
-	static acpi_sapic_t *acpi_sapic;
-	static acpi_entry_lsapic_t *acpi_lsapic;
-#endif
-	static acpi20_rsdp_t *acpi20_rsdp;
-	static acpi_xsdt_t *acpi_xsdt;
-	static acpi_slit_t *acpi_slit;
-	static acpi_madt_t *acpi_madt;
-	static acpi20_entry_lsapic_t *lsapic20;
+	static struct acpi20_table_rsdp *acpi20_rsdp;
+	static struct acpi_table_xsdt *acpi_xsdt;
+	static struct acpi_table_slit *acpi_slit;
+	static struct acpi_table_madt *acpi_madt;
+	static struct acpi_table_lsapic *lsapic20;
 	static struct ia64_sal_systab *sal_systab;
-	static acpi_srat_t *acpi_srat;
-	static srat_cpu_affinity_t *srat_cpu_affinity;
-	static srat_memory_affinity_t *srat_memory_affinity;
+	static struct acpi_table_srat *acpi_srat;
+	static struct acpi_table_processor_affinity *srat_cpu_affinity;
+	static struct acpi_table_memory_affinity *srat_memory_affinity;
 	static efi_memory_desc_t *efi_memmap, *md;
 	static unsigned long *pal_desc, *sal_desc;
 	static struct ia64_sal_desc_entry_point *sal_ed;
@@ -525,16 +534,10 @@
 	acpi_xsdt   = (void *) cp; cp += ALIGN8(sizeof(*acpi_xsdt) + 64); 
 			/* save space for more OS defined table pointers. */
 
-#ifdef ACPI_1_0
-	acpi_rsdp   = (void *) cp; cp += ALIGN8(sizeof(*acpi_rsdp));
-	acpi_rsdt   = (void *) cp; cp += ALIGN8(sizeof(*acpi_rsdt));
-	acpi_sapic  = (void *) cp; cp += sizeof(*acpi_sapic);
-	acpi_lsapic = (void *) cp; cp += num_cpus*sizeof(*acpi_lsapic);
-#endif
 	acpi_slit   = (void *) cp; cp += ALIGN8(sizeof(*acpi_slit) + 8 + (max_nasid+1)*(max_nasid+1));
-	acpi_madt   = (void *) cp; cp += ALIGN8(sizeof(*acpi_madt) + 8 * num_cpus+ 8);
-	acpi_srat   = (void *) cp; cp += ALIGN8(sizeof(acpi_srat_t));
-	cp         += sizeof(srat_cpu_affinity_t)*num_cpus + sizeof(srat_memory_affinity_t)*num_nodes;
+	acpi_madt   = (void *) cp; cp += ALIGN8(sizeof(*acpi_madt) + sizeof(struct acpi_table_lsapic) * (num_cpus+1));
+	acpi_srat   = (void *) cp; cp += ALIGN8(sizeof(struct acpi_table_srat));
+	cp         += sizeof(struct acpi_table_processor_affinity)*num_cpus + sizeof(struct acpi_table_memory_affinity)*num_nodes;
 	vendor 	    = (char *) cp; cp += ALIGN8(40);
 	efi_memmap  = (void *) cp; cp += ALIGN8(8*32*sizeof(*efi_memmap));
 	sal_ptcdi   = (void *) cp; cp += ALIGN8(CPUS_PER_FSB*(1+num_nodes)*sizeof(*sal_ptcdi));
@@ -585,11 +588,6 @@
 	efi_tables->guid = SAL_SYSTEM_TABLE_GUID;
 	efi_tables->table = __fwtab_pa(base_nasid, sal_systab);
 	efi_tables++;
-#ifdef ACPI_1_0
-	efi_tables->guid = ACPI_TABLE_GUID;
-	efi_tables->table = __fwtab_pa(base_nasid, acpi_rsdp);
-	efi_tables++;
-#endif
 	efi_tables->guid = ACPI_20_TABLE_GUID;
 	efi_tables->table = __fwtab_pa(base_nasid, acpi20_rsdp);
 	efi_tables++;
@@ -600,65 +598,32 @@
 	fix_function_pointer(&efi_reset_system);
 	fix_function_pointer(&efi_set_virtual_address_map);
 
-#ifdef ACPI_1_0
-	/* fill in the ACPI system table - has a pointer to the ACPI table header */
-	memcpy(acpi_rsdp->signature, "RSD PTR ", 8);
-	acpi_rsdp->rsdt = (struct acpi_rsdt*)__fwtab_pa(base_nasid, acpi_rsdt);
-
-	acpi_table_init(&acpi_rsdt->header, ACPI_RSDT_SIG, ACPI_RSDT_SIG_LEN, 1, 1);
-	acpi_rsdt->header.length = sizeof(acpi_rsdt_t);
-	acpi_rsdt->entry_ptrs[0] = __fwtab_pa(base_nasid, acpi_sapic);
-
-	memcpy(acpi_sapic->header.signature, "SPIC ", 4);
-	acpi_sapic->header.length = sizeof(acpi_sapic_t)+num_cpus*sizeof(acpi_entry_lsapic_t);
-
-	for (cnode=0; cnode<num_nodes; cnode++) {
-		nasid = GetNasid(cnode);
-		for(cpu=0; cpu<CPUS_PER_NODE; cpu++) {
-			if (!IsCpuPresent(cnode, cpu))
-				continue;
-			acpi_lsapic->type = ACPI_ENTRY_LOCAL_SAPIC;
-			acpi_lsapic->length = sizeof(acpi_entry_lsapic_t);
-			acpi_lsapic->acpi_processor_id = cnode*4+cpu;
-			acpi_lsapic->flags = LSAPIC_ENABLED|LSAPIC_PRESENT;
-#if defined(CONFIG_IA64_SGI_SN1)
-			acpi_lsapic->eid = cpu;
-			acpi_lsapic->id = nasid;
-#else
-			acpi_lsapic->eid = nasid&0xffff;
-			acpi_lsapic->id = (cpu<<4) | (nasid>>16);
-#endif
-			acpi_lsapic++;
-		}
-	}
-#endif
-
 
 	/* fill in the ACPI20 system table - has a pointer to the ACPI table header */
 	memcpy(acpi20_rsdp->signature, "RSD PTR ", 8);
-	acpi20_rsdp->xsdt = (struct acpi_xsdt*)__fwtab_pa(base_nasid, acpi_xsdt);
+	acpi20_rsdp->xsdt_address = (u64)__fwtab_pa(base_nasid, acpi_xsdt);
 	acpi20_rsdp->revision = 2;
-	acpi_checksum_rsdp20(acpi20_rsdp, sizeof(acpi20_rsdp_t));
+	acpi_checksum_rsdp20(acpi20_rsdp, sizeof(struct acpi20_table_rsdp));
 
 	/* Set up the XSDT table  - contains pointers to the other ACPI tables */
-	acpi_table_init(&acpi_xsdt->header, ACPI_XSDT_SIG, ACPI_XSDT_SIG_LEN, 1, 1);
-	acpi_xsdt->entry_ptrs[0] = __fwtab_pa(base_nasid, acpi_madt);
-	acpi_xsdt->entry_ptrs[1] = __fwtab_pa(base_nasid, acpi_slit);
-	acpi_xsdt->entry_ptrs[2] = __fwtab_pa(base_nasid, acpi_srat);
-	acpi_checksum(&acpi_xsdt->header, sizeof(acpi_xsdt_t) + 16);
-
-	/* Set up the MADT table */
-	acpi_table_init(&acpi_madt->header, ACPI_MADT_SIG, ACPI_MADT_SIG_LEN, 1, 1);
-	lsapic20 = (acpi20_entry_lsapic_t*) (acpi_madt + 1);
+	acpi_table_initx(&acpi_xsdt->header, XSDT_SIG, 4, 1, 1);
+	acpi_xsdt->entry[0] = __fwtab_pa(base_nasid, acpi_madt);
+	acpi_xsdt->entry[1] = __fwtab_pa(base_nasid, acpi_slit);
+	acpi_xsdt->entry[2] = __fwtab_pa(base_nasid, acpi_srat);
+	acpi_checksum(&acpi_xsdt->header, sizeof(struct acpi_table_xsdt) + 16);
+
+	/* Set up the APIC table */
+	acpi_table_initx(&acpi_madt->header, APIC_SIG, 4, 1, 1);
+	lsapic20 = (struct acpi_table_lsapic*) (acpi_madt + 1);
 	for (cnode=0; cnode<num_nodes; cnode++) {
 		nasid = GetNasid(cnode);
 		for(cpu=0; cpu<CPUS_PER_NODE; cpu++) {
 			if (!IsCpuPresent(cnode, cpu))
 				continue;
-			lsapic20->type = ACPI20_ENTRY_LOCAL_SAPIC;
-			lsapic20->length = sizeof(acpi_entry_lsapic_t);
-			lsapic20->acpi_processor_id = cnode*4+cpu;
-			lsapic20->flags = LSAPIC_ENABLED|LSAPIC_PRESENT;
+			lsapic20->header.type = ACPI_MADT_LSAPIC;
+			lsapic20->header.length = sizeof(struct acpi_table_lsapic);
+			lsapic20->acpi_id = cnode*4+cpu;
+			lsapic20->flags.enabled = 1;
 #if defined(CONFIG_IA64_SGI_SN1)
 			lsapic20->eid = cpu;
 			lsapic20->id = nasid;
@@ -666,20 +631,20 @@
 			lsapic20->eid = nasid&0xffff;
 			lsapic20->id = (cpu<<4) | (nasid>>16);
 #endif
-			lsapic20 = (acpi20_entry_lsapic_t*) ((long)lsapic20+sizeof(acpi_entry_lsapic_t));
+			lsapic20 = (struct acpi_table_lsapic*) ((long)lsapic20+sizeof(struct acpi_table_lsapic));
 		}
 	}
 	acpi_checksum(&acpi_madt->header, (char*)lsapic20 - (char*)acpi_madt);
 
 	/* Set up the SRAT table */
-	acpi_table_init(&acpi_srat->header, ACPI_SRAT_SIG, ACPI_SRAT_SIG_LEN, ACPI_SRAT_REVISION, 1);
+	acpi_table_initx(&acpi_srat->header, SRAT_SIG, 4, ACPI_SRAT_REVISION, 1);
 	ptr = acpi_srat+1;
 	for (cnode=0; cnode<num_nodes; cnode++) {
 		nasid = GetNasid(cnode);
 		srat_memory_affinity = ptr;
 		ptr = srat_memory_affinity+1;
-		srat_memory_affinity->type = SRAT_MEMORY_STRUCTURE;
-		srat_memory_affinity->length = sizeof(srat_memory_affinity_t);
+		srat_memory_affinity->header.type = ACPI_SRAT_MEMORY_AFFINITY;
+		srat_memory_affinity->header.length = sizeof(struct acpi_table_memory_affinity);
 		srat_memory_affinity->proximity_domain = PROXIMITY_DOMAIN(nasid);
 		srat_memory_affinity->base_addr_lo = 0;
 		srat_memory_affinity->length_lo = 0;
@@ -691,7 +656,7 @@
 		srat_memory_affinity->length_hi = SN2_NODE_SIZE>>32;
 #endif
 		srat_memory_affinity->memory_type = ACPI_ADDRESS_RANGE_MEMORY;
-		srat_memory_affinity->flags = SRAT_MEMORY_FLAGS_ENABLED;
+		srat_memory_affinity->flags.enabled = 1;
 	}
 
 	for (cnode=0; cnode<num_nodes; cnode++) {
@@ -701,15 +666,15 @@
 				continue;
 			srat_cpu_affinity = ptr;
 			ptr = srat_cpu_affinity + 1;
-			srat_cpu_affinity->type = SRAT_CPU_STRUCTURE;
-			srat_cpu_affinity->length = sizeof(srat_cpu_affinity_t);
+			srat_cpu_affinity->header.type = ACPI_SRAT_PROCESSOR_AFFINITY;
+			srat_cpu_affinity->header.length = sizeof(struct acpi_table_processor_affinity);
 			srat_cpu_affinity->proximity_domain = PROXIMITY_DOMAIN(nasid);
-			srat_cpu_affinity->flags = SRAT_CPU_FLAGS_ENABLED;
+			srat_cpu_affinity->flags.enabled = 1;
 #if defined(CONFIG_IA64_SGI_SN1)
 			srat_cpu_affinity->apic_id = nasid;
-			srat_cpu_affinity->local_sapic_eid = cpu;
+			srat_cpu_affinity->lsapic_eid = cpu;
 #else
-			srat_cpu_affinity->local_sapic_eid = nasid&0xffff;
+			srat_cpu_affinity->lsapic_eid = nasid&0xffff;
 			srat_cpu_affinity->apic_id = (cpu<<4) | (nasid>>16);
 #endif
 		}
@@ -718,9 +683,9 @@
 
 
 	/* Set up the SLIT table */
-	acpi_table_init(&acpi_slit->header, ACPI_SLIT_SIG, ACPI_SLIT_SIG_LEN, ACPI_SLIT_REVISION, 1);
+	acpi_table_initx(&acpi_slit->header, SLIT_SIG, 4, ACPI_SLIT_REVISION, 1);
 	acpi_slit->localities = PROXIMITY_DOMAIN(max_nasid)+1;
-	cp=acpi_slit->entries;
+	cp=acpi_slit->entry;
 	memset(cp, 255, acpi_slit->localities*acpi_slit->localities);
 
 	for (i=0; i<=max_nasid; i++)
@@ -728,7 +693,7 @@
 			if (nasid_present(i) && nasid_present(j))
 				*(cp+PROXIMITY_DOMAIN(i)*acpi_slit->localities+PROXIMITY_DOMAIN(j)) = 10 + MIN(254, 5*ABS(i-j));
 
-	cp = acpi_slit->entries + acpi_slit->localities*acpi_slit->localities;
+	cp = acpi_slit->entry + acpi_slit->localities*acpi_slit->localities;
 	acpi_checksum(&acpi_slit->header, cp - (char*)acpi_slit);
 
 
@@ -738,6 +703,8 @@
 	sal_systab->sal_rev_minor = 1;
 	sal_systab->sal_rev_major = 0;
 	sal_systab->entry_count = 3;
+	sal_systab->sal_b_rev_major = 0x1; /* set the SN SAL rev to */
+	sal_systab->sal_b_rev_minor = 0x0; /* 1.00 */
 
 	strcpy(sal_systab->oem_id, "SGI");
 	strcpy(sal_systab->product_id, "SN1");
@@ -792,11 +759,6 @@
 	 * table. We dont build enough table & the kernel aborts.
 	 * Note that the PROM hasd thhhe same problem!!
 	 */
-#ifdef DOESNT_WORK
-	for (checksum=0, cp=(char*)acpi_rsdp, cpe=cp+RSDP_CHECKSUM_LENGTH; cp<cpe; ++cp)
-		checksum += *cp;
-	acpi_rsdp->checksum = -checksum;
-#endif
 
 	md = &efi_memmap[0];
 	num_memmd = build_efi_memmap((void *)md, mdsize) ;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/fakeprom/klgraph_init.c linux-2.4.21-pre6/arch/ia64/sn/fakeprom/klgraph_init.c
--- linux-2.4.20/arch/ia64/sn/fakeprom/klgraph_init.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/fakeprom/klgraph_init.c	2003-03-26 23:49:00.000000000 +0000
@@ -49,8 +49,9 @@
 klgraph_init(void)
 {
 
-	u64	*temp;
-
+#ifdef CONFIG_IA64_SGI_SN1
+	u64 *temp;
+#endif
 	/*
 	 * Initialize some hub/xbow registers that allows access to 
 	 * Xbridge etc.  These are normally done in PROM.
@@ -109,6 +110,8 @@
 // [PI]       *(volatile u32 *)0xc00000080f000288L = 0xba98;
 #endif	/* CONFIG_IA64_SGI_SN1 */
 
+#ifdef CONFIG_IA64_SGI_SN1
+
 	/*
 	 * kldir entries initialization - mankato
 	 */
@@ -282,6 +285,7 @@
 	convert(0x8000000000002560, 0xffffffffffffffff, 0xffffffffffffffff);
 	convert(0x8000000000002570, 0xffffffffffffffff, 0xffffffffffffffff);
 	convert(0x8000000000002580, 0x000000000000ffff, 0x0000000000000000);
+#endif
 	
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/fakeprom/main.c linux-2.4.21-pre6/arch/ia64/sn/fakeprom/main.c
--- linux-2.4.20/arch/ia64/sn/fakeprom/main.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/fakeprom/main.c	2003-03-26 23:49:39.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2000-2001 Silicon Graphics, Inc.  All rights reserved.
+ * Copyright (C) 2000-2002 Silicon Graphics, Inc.  All rights reserved.
  */
 
 
@@ -98,7 +98,7 @@
 
 	/*
 	 * Enable all FSB flashed interrupts.
-	 * ZZZ - I'd really like defines for this......
+	 * I'd really like defines for this......
 	 */
 	base = (long*)0x80000e0000000000LL;		/* base of synergy regs */
 	for (off = 0x2a0; off < 0x2e0; off+=8)		/* offset for VEC_MASK_{0-3}_A/B */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/Makefile linux-2.4.21-pre6/arch/ia64/sn/io/Makefile
--- linux-2.4.20/arch/ia64/sn/io/Makefile	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/Makefile	2003-03-26 23:49:19.000000000 +0000
@@ -5,41 +5,29 @@
 #
 # Copyright (C) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
 #
-#
-# Makefile for the linux kernel.
-#
-# 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).
-#
+# Makefile for the sn kernel routines.
 
 EXTRA_CFLAGS    := -DLITTLE_ENDIAN
 
-O_TARGET := sgiio.o
-
-ifeq ($(CONFIG_MODULES),y)
-export-objs = pciio.o hcl.o pci_dma.o
+ifdef CONFIG_IA64_SGI_SN2
+EXTRA_CFLAGS    += -DSHUB_SWAP_WAR
 endif
 
-obj-y  := stubs.o sgi_if.o pciio.o xtalk.o xbow.o xswitch.o klgraph_hack.o \
-		hcl.o labelcl.o invent.o klgraph.o klconflib.o sgi_io_sim.o \
-		module.o sgi_io_init.o klgraph_hack.o ml_SN_init.o \
-		ml_iograph.o hcl_util.o cdl.o hubdev.o hubspc.o \
-		alenlist.o pci_bus_cvlink.o \
-		eeprom.o pci.o pci_dma.o l1.o l1_command.o ate_utils.o \
-		ifconfig_net.o efi-rtc.o io.o
-
-obj-$(CONFIG_IA64_SGI_SN1)   += sn1/ml_SN_intr.o sn1/mem_refcnt.o sn1/hubcounters.o \
-				sn1/ip37.o sn1/huberror.o sn1/hub_intr.o sn1/pcibr.o
-
-obj-$(CONFIG_IA64_SGI_SN2)   += sn2/ml_SN_intr.o sn2/shub_intr.o sn2/shuberror.o \
-				sn2/bte_error.o \
-				sn2/pcibr/pcibr_dvr.o sn2/pcibr/pcibr_ate.o \
-				sn2/pcibr/pcibr_config.o sn2/pcibr/pcibr_dvr.o \
-				sn2/pcibr/pcibr_hints.o \
-				sn2/pcibr/pcibr_idbg.o sn2/pcibr/pcibr_intr.o \
-				sn2/pcibr/pcibr_rrb.o sn2/pcibr/pcibr_slot.o 
+O_TARGET := sgiio.o
+ 
+export-objs := hcl.o pci_dma.o
+
+obj-y :=	stubs.o sgi_if.o xswitch.o klgraph_hack.o \
+		hcl.o labelcl.o invent.o sgi_io_sim.o \
+		klgraph_hack.o hcl_util.o cdl.o hubdev.o hubspc.o \
+		alenlist.o pci.o pci_dma.o ate_utils.o \
+		ifconfig_net.o io.o ifconfig_bus.o
+
+obj-$(CONFIG_IA64_SGI_SN1)	+= sn1/snio.o
+obj-$(CONFIG_IA64_SGI_SN2)	+= sn2/snio.o
+obj-$(CONFIG_PCIBA)		+= pciba.o
 
-obj-$(CONFIG_PCIBA) += pciba.o
+subdir-$(CONFIG_IA64_SGI_SN1)	+= sn1
+subdir-$(CONFIG_IA64_SGI_SN2)	+= sn2
 
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/cdl.c linux-2.4.21-pre6/arch/ia64/sn/io/cdl.c
--- linux-2.4.20/arch/ia64/sn/io/cdl.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/cdl.c	2003-03-26 23:49:20.000000000 +0000
@@ -7,6 +7,7 @@
  * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <asm/sn/sgi.h>
 #include <asm/io.h>
@@ -19,6 +20,8 @@
 /* these get called directly in cdl_add_connpt in fops bypass hack */
 extern int pcibr_attach(devfs_handle_t);
 extern int xbow_attach(devfs_handle_t);
+extern int pic_attach(devfs_handle_t);
+
 
 /*
  *    cdl: Connection and Driver List
@@ -35,13 +38,24 @@
     int (*attach) (devfs_handle_t);
 } dummy_reg;
 
+#ifdef CONFIG_IA64_SGI_SN1
 #define MAX_SGI_IO_INFRA_DRVR 4
-struct cdl sgi_infrastructure_drivers[MAX_SGI_IO_INFRA_DRVR] =
+#else
+#define MAX_SGI_IO_INFRA_DRVR 7
+#endif
+static struct cdl sgi_infrastructure_drivers[MAX_SGI_IO_INFRA_DRVR] =
 {
 	{ XBRIDGE_WIDGET_PART_NUM, XBRIDGE_WIDGET_MFGR_NUM, pcibr_attach /* &pcibr_fops  */},
 	{ BRIDGE_WIDGET_PART_NUM,  BRIDGE_WIDGET_MFGR_NUM,  pcibr_attach /* &pcibr_fops */},
+#ifndef CONFIG_IA64_SGI_SN1
+	{ PIC_WIDGET_PART_NUM_BUS0,  PIC_WIDGET_MFGR_NUM,   pic_attach /* &pic_fops */},
+	{ PIC_WIDGET_PART_NUM_BUS1,  PIC_WIDGET_MFGR_NUM,   pic_attach /* &pic_fops */},
+#endif
 	{ XXBOW_WIDGET_PART_NUM,   XXBOW_WIDGET_MFGR_NUM,   xbow_attach /* &xbow_fops */},
 	{ XBOW_WIDGET_PART_NUM,    XBOW_WIDGET_MFGR_NUM,    xbow_attach /* &xbow_fops */},
+#ifndef CONFIG_IA64_SGI_SN1
+	{ PXBOW_WIDGET_PART_NUM,   XXBOW_WIDGET_MFGR_NUM,   xbow_attach /* &xbow_fops */},
+#endif
 };
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/hcl.c linux-2.4.21-pre6/arch/ia64/sn/io/hcl.c
--- linux-2.4.20/arch/ia64/sn/io/hcl.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/hcl.c	2003-03-26 23:49:19.000000000 +0000
@@ -6,7 +6,7 @@
  *
  *  hcl - SGI's Hardware Graph compatibility layer.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 
 #include <linux/types.h>
@@ -155,7 +155,7 @@
 	/*
 	 * Create the hwgraph_root on devfs.
 	 */
-	rv = hwgraph_path_add(NULL, "hw", &hwgraph_root);
+	rv = hwgraph_path_add(NULL, EDGE_LBL_HW, &hwgraph_root);
 	if (rv)
 		printk ("WARNING: init_hcl: Failed to create hwgraph_root. Error = %d.\n", rv);
 
@@ -183,9 +183,9 @@
 	/*
 	 * Create the directory that links Linux bus numbers to our Xwidget.
 	 */
-	rv = hwgraph_path_add(hwgraph_root, "linux/busnum", &linux_busnum);
+	rv = hwgraph_path_add(hwgraph_root, EDGE_LBL_LINUX_BUS, &linux_busnum);
 	if (linux_busnum == NULL) {
-		panic("HCL: Unable to create hw/linux/busnum\n");
+		panic("HCL: Unable to create %s\n", EDGE_LBL_LINUX_BUS);
 		return(0);
 	}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/hcl_util.c linux-2.4.21-pre6/arch/ia64/sn/io/hcl_util.c
--- linux-2.4.20/arch/ia64/sn/io/hcl_util.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/hcl_util.c	2003-03-26 23:49:40.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 
 #include <linux/types.h>
@@ -96,6 +96,33 @@
 	}
 }
 
+static devfs_handle_t hwgraph_all_cpuids = GRAPH_VERTEX_NONE;
+extern int maxcpus;
+
+void
+mark_cpuvertex_as_cpu(devfs_handle_t vhdl, cpuid_t cpuid)
+{
+	if (cpuid == CPU_NONE)
+		return;
+
+	(void)labelcl_info_add_LBL(vhdl, INFO_LBL_CPUID, INFO_DESC_EXPORT,
+			(arbitrary_info_t)cpuid);
+	{
+		char cpuid_buffer[10];
+
+		if (hwgraph_all_cpuids == GRAPH_VERTEX_NONE) {
+			(void)hwgraph_path_add( hwgraph_root,
+						EDGE_LBL_CPUNUM,
+						&hwgraph_all_cpuids);
+		}
+
+		sprintf(cpuid_buffer, "%ld", cpuid);
+		(void)hwgraph_edge_add( hwgraph_all_cpuids,
+							vhdl,
+							cpuid_buffer);
+	}
+}
+
 /*
 ** If the specified device represents a node, return its
 ** compact node ID; otherwise, return CNODEID_NONE.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/hubdev.c linux-2.4.21-pre6/arch/ia64/sn/io/hubdev.c
--- linux-2.4.20/arch/ia64/sn/io/hubdev.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/hubdev.c	2003-03-26 23:49:50.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 
 #include <linux/config.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/hubspc.c linux-2.4.21-pre6/arch/ia64/sn/io/hubspc.c
--- linux-2.4.20/arch/ia64/sn/io/hubspc.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/hubspc.c	2003-03-26 23:49:40.000000000 +0000
@@ -161,69 +161,8 @@
 				sizeof(invent_miscinfo_t));
 }
 
-#define FPROM_CONFIG_ADDR	MD_JUNK_BUS_TIMING
-#define FPROM_ENABLE_MASK	MJT_FPROM_ENABLE_MASK
-#define FPROM_ENABLE_SHFT	MJT_FPROM_ENABLE_SHFT
-#define FPROM_SETUP_MASK	MJT_FPROM_SETUP_MASK
-#define FPROM_SETUP_SHFT	MJT_FPROM_SETUP_SHFT
+#endif  /* CONFIG_IA64_SGI_SN1 */
 
-/*ARGSUSED*/
-int
-cpuprom_map(devfs_handle_t dev, vhandl_t *vt, off_t addr, size_t len)
-{
-        int 		errcode = 0;
-	caddr_t 	kvaddr;
-	devfs_handle_t		node;
-	cnodeid_t 	cnode;
-
-	node = prominfo_nodeget(dev);
-
-	if (!node)
-		return EIO;
-        
-
-	kvaddr = hubdev_prombase_get(node);
-	cnode  = hubdev_cnodeid_get(node);
-#ifdef	HUBSPC_DEBUG
-	printk("cpuprom_map: hubnode %d kvaddr 0x%x\n", node, kvaddr);
-#endif
-
-	if (len > RBOOT_SIZE)
-		len = RBOOT_SIZE;
-        /*
-         * Map in the prom space
-         */
-	errcode = v_mapphys(vt, kvaddr, len);
-
-	if (errcode == 0 ){
-		/*
-		 * Set the MD configuration registers suitably.
-		 */
-		nasid_t		nasid;
-		uint64_t	value;
-		volatile hubreg_t	*regaddr;
-
-		nasid = COMPACT_TO_NASID_NODEID(cnode);
-		regaddr = REMOTE_HUB_ADDR(nasid, FPROM_CONFIG_ADDR);
-		value = HUB_L(regaddr);
-		value &= ~(FPROM_SETUP_MASK | FPROM_ENABLE_MASK);
-		{
-			value |= (((long)CONFIG_FPROM_SETUP << FPROM_SETUP_SHFT) | 
-				  ((long)CONFIG_FPROM_ENABLE << FPROM_ENABLE_SHFT));
-		}
-		HUB_S(regaddr, value);
-
-	}
-        return (errcode);
-}
-#endif	/* CONFIG_IA64_SGI_SN1 */
-
-/*ARGSUSED*/
-int
-cpuprom_unmap(devfs_handle_t dev, vhandl_t *vt)
-{
-        return 0;
-}
 
 /***********************************************************************/
 /* Base Hub Space Driver                                               */
@@ -245,13 +184,14 @@
         hubdev_register(mem_refcnt_attach);
 #endif
 
+#ifdef CONFIG_IA64_SGI_SN1
 	/* L1 system controller link */
 	if ( !IS_RUNNING_ON_SIMULATOR() ) {
 		/* initialize the L1 link */
 		extern void l1_init(void);
 		l1_init();
 	}
-
+#endif	/* CONFIG_IA64_SGI_SN1 */
 #ifdef	HUBSPC_DEBUG
 	printk("hubspc_init: Completed\n");
 #endif	/* HUBSPC_DEBUG */
@@ -283,7 +223,7 @@
 
 	/* check validity of request */
 	if( len == 0 ) {
-		return ENXIO;
+		return -ENXIO;
         }
 
 	return errcode;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/ifconfig_bus.c linux-2.4.21-pre6/arch/ia64/sn/io/ifconfig_bus.c
--- linux-2.4.20/arch/ia64/sn/io/ifconfig_bus.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/ifconfig_bus.c	2003-03-26 23:49:29.000000000 +0000
@@ -0,0 +1,345 @@
+/* $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.
+ *
+ *  ifconfig_bus - SGI's Persistent PCI Bus Numbering.
+ *
+ * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc.  All rights reserved.
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/pci.h>
+
+#include <asm/sn/sgi.h>
+#include <linux/devfs_fs.h>
+#include <linux/devfs_fs_kernel.h>
+#include <asm/io.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/labelcl.h>
+#include <asm//sn/sn_sal.h>
+#include <asm/sn/addrs.h>
+
+#define SGI_IFCONFIG_BUS "SGI-PERSISTENT PCI BUS NUMBERING"
+#define SGI_IFCONFIG_BUS_VERSION "1.0"
+
+/*
+ * Some Global definitions.
+ */
+devfs_handle_t ioconfig_bus_handle = NULL;
+unsigned long ioconfig_bus_debug = 0;
+
+#define IFCONFIG_BUS_DEBUG 1
+#ifdef IFCONFIG_BUS_DEBUG
+#define DBG(x...)	printk(x)
+#else
+#define DBG(x...)
+#endif
+
+u64 ioconfig_file = 0;
+u64 ioconfig_file_size = 0;
+
+
+/*
+ * PCI Bus Name for PCI
+ * 		 module/001c02/Ibrick/xtalk/14/pci - only 1 bus per widget
+ *
+ * PCI Bus Name for PCI-X
+ *		 module/001c02/Ibrick/xtalk/14/pci-x/0 - PCI bus 0 on Widget 14
+ *		 module/001c02/Ibrick/xtalk/14/pci-x/1 - PCI bus 1 on Widget 14
+ */
+
+struct	pcipath_to_busnum{
+	unsigned int  num;			/* persistent bus number */
+	unsigned int  len;			/* pci path length */
+	unsigned char	path[120];		/* pci path name */
+};
+
+struct  pcipath_to_busnum *ioconfig_bus_table;
+u64 ioconfig_bus_table_size = 0;
+
+
+struct pcipath_to_busnum pcibus_names[256];
+
+/*
+ * highest_pcibus_num : The highest PCI bus number allocated.  Use for next 
+ *			PCI Bus Number to be assigned.
+ * pcibus_names_index : The starting entry of any new configuration.  It also 
+ *			tracks the number of old config in the table.
+ * current_index : Next free index in the table for new config.
+ *		   current_index - pcibus_names_index = number new config.
+ */
+
+int	highest_pcibus_num = 0;
+int	pcibus_names_index = 0; /* Start of new config */
+int	current_index = 0; /* Next entry for new config */
+
+/*
+ * ioconfig_get_busnum():
+ *	ioconfig_get_busnum() returns the bus number given a pci path name.
+ *	If the pci path name exist in the persistent naming table, the
+ *	corresponding bun number is returned.  If the pci path name does not
+ *	exist, the next bus number is assigned to that path, added to the
+ *	persistent naming table and the new bus num returned.
+ */
+void
+ioconfig_get_busnum(char *pci_path, int *bus_num)
+{
+	struct	pcipath_to_busnum *temp;
+	int index;
+
+	*bus_num = -1;
+	temp = ioconfig_bus_table;
+	for (index = 0; index < current_index; ioconfig_bus_table++, index++) {
+		if ( (strncmp(pci_path, ioconfig_bus_table->path, strlen(pci_path) == 0)) ){
+			*bus_num = ioconfig_bus_table->num;
+			return;
+		}
+	}
+
+	/*
+	 * This is a new path and it is not in the config table.
+	 * Add it to the end.
+	 */
+	*bus_num = highest_pcibus_num;
+	highest_pcibus_num++;
+	ioconfig_bus_table->num = *bus_num;
+	strcpy((char *)&(ioconfig_bus_table->path), pci_path);
+	ioconfig_bus_table->len = strlen(pci_path);
+	current_index++;
+
+}
+
+void
+dump_ioconfig_table(struct pcipath_to_busnum *ioconfig_bus_table)
+{
+
+	int index = 0;
+	struct pcipath_to_busnum *temp;
+
+	temp = ioconfig_bus_table;
+	while (index < pcibus_names_index) {
+		printk("Bus Number %d PCI path %s\n", temp->num, temp->path);
+		temp++;
+		index++;
+	}
+		
+}
+/*
+ * nextline
+ *	This routine returns the nextline in the buffer.
+ */
+int nextline(char *buffer, char **next, char *line)
+{
+
+	char *temp;
+
+	if (buffer[0] == 0x0) {
+		return(0);
+	}
+
+	temp = buffer;
+	while (*temp != 0) {
+		*line = *temp;
+		if (*temp != '\n'){
+			*line = *temp;
+			temp++; line++;
+		} else
+			break;
+	}
+
+	if (*temp == 0)
+		*next = temp;
+	else
+		*next = ++temp;
+
+	return(1);
+}
+
+/*
+ * build_pcibus_name
+ *	This routine parses the ioconfig contents read into
+ *	memory by ioconfig command in EFI and builds the
+ *	persistent pci bus naming table.
+ */
+void
+build_pcibus_name(char *file_contents, struct pcipath_to_busnum *table)
+{
+	/*
+	 * Read the whole file into memory.
+	 */
+	int busnum;
+	int rc;
+	char *name;
+	char *temp;
+	char *next;
+	char *current;
+	char *line;
+	struct pcipath_to_busnum *pcibus;
+
+	line = kmalloc(256, GFP_KERNEL);
+	memset(line, 0,256);
+	name = kmalloc(125, GFP_KERNEL);
+	memset(name, 0, 125);
+	pcibus = table;
+	current = file_contents;
+	while (nextline(current, &next, line)){
+printk("current 0x%lx next 0x%lx\n", current, next);
+		temp = line;
+		/*
+		 * Skip all leading Blank lines ..
+		 */
+		while (isspace(*temp))
+			if (*temp != '\n')
+				temp++;
+			else
+				break;
+
+		if (*temp == '\n') {
+			current = next;
+			memset(line, 0, 256);
+			continue;
+		}
+ 
+		/*
+		 * Skip comment lines
+		 */
+		if (*temp == '#') {
+			current = next;
+			memset(line, 0, 256);
+			continue;
+		}
+
+		/*
+		 * Get the next free entry in the table.
+		 */
+		rc = sscanf(temp, "%d %s", &busnum, name);
+		pcibus->num = busnum;
+		pcibus->len = strlen(name);
+		strcpy(&pcibus->path[0], name);
+		DBG("pci number = %d pci path = %s\n", pcibus->num, pcibus->path);
+		if (busnum > highest_pcibus_num)
+			highest_pcibus_num = busnum;
+		else 
+			highest_pcibus_num = busnum; 
+ 
+		pcibus_names_index++;
+		pcibus++;
+		current = next;
+		memset(line, 0, 256);
+	}
+
+	DBG("highest_pcibus_num %d pcibus_names_index %d\n", highest_pcibus_num, pcibus_names_index);
+
+	current_index = pcibus_names_index;
+	kfree(line);
+	kfree(name);
+
+	return;
+}
+
+void
+ioconfig_bus_init(void)
+{
+
+	struct ia64_sal_retval ret_stuff;
+
+	DBG("ioconfig_bus_init called.\n");
+
+	/*
+	 * Make SAL call to get the address of the bus configuration table.
+	 */
+	ret_stuff.status = (uint64_t)0;
+	ret_stuff.v0 = (uint64_t)0;
+	ret_stuff.v1 = (uint64_t)0;
+	ret_stuff.v2 = (uint64_t)0;
+	SAL_CALL(ret_stuff, SN_SAL_BUS_CONFIG, 0, get_nasid(), 0, 0, 0, 0, 0);
+	if (ret_stuff.status != 0) {
+		DBG("ifconfig_bus_init: No Address given\n");
+	}
+
+	ioconfig_file = ret_stuff.v0;
+	ioconfig_file_size = ret_stuff.v1;
+	DBG("ioconfig_bus_init: ioconfig_file %p %d\n", 
+		(void *)ioconfig_file, (int)ioconfig_file_size);
+
+	/*
+	 * Convert the address to a Cache Address.
+	 */
+	ioconfig_file = (CACHEABLE_MEM_SPACE | 
+		(ioconfig_file & TO_PHYS_MASK));
+
+	ioconfig_bus_table = kmalloc( 512*sizeof(struct pcipath_to_busnum), 
+				GFP_KERNEL );
+
+	DBG("ioconfig_bus_init: Kernel virtual ioconfig_file %p ioconfig_bus_table %p\n", 
+		(void *)ioconfig_file, (void *)ioconfig_bus_table);
+
+	(void) build_pcibus_name((char *)ioconfig_file, ioconfig_bus_table);
+
+	(void) dump_ioconfig_table(ioconfig_bus_table);
+
+}
+
+/*
+ * ioconfig_bus_open - Opens the special device node "/dev/hw/.ioconfig_bus".
+ */
+static int ioconfig_bus_open(struct inode * inode, struct file * filp)
+{
+	if (ioconfig_bus_debug) {
+        	printk("ioconfig_bus_open called.\n");
+	}
+
+        return(0);
+
+}
+
+/*
+ * ioconfig_bus_close - Closes the special device node "/dev/hw/.ioconfig_bus".
+ */
+static int ioconfig_bus_close(struct inode * inode, struct file * filp)
+{
+
+	if (ioconfig_bus_debug) {
+        	printk("ioconfig_bus_close called.\n");
+	}
+
+        return(0);
+}
+
+struct file_operations ioconfig_bus_fops = {
+	/* ioctl:ioconfig_bus_ioctl, ioctl */
+	open:ioconfig_bus_open,		/* open */
+	release:ioconfig_bus_close	/* release */
+};
+
+
+/*
+ * init_ifconfig_net() - Boot time initialization.  Ensure that it is called 
+ *	after devfs has been initialized.
+ *
+ */
+int init_ioconfig_bus(void)
+{
+	ioconfig_bus_handle = NULL;
+	ioconfig_bus_handle = hwgraph_register(hwgraph_root, ".ioconfig_bus",
+			0, DEVFS_FL_AUTO_DEVNUM,
+			0, 0,
+			S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0,
+			&ioconfig_bus_fops, NULL);
+
+	if (ioconfig_bus_handle == NULL) {
+		panic("Unable to create SGI PERSISTENT BUS NUMBERING Driver.\n");
+	}
+
+	return(0);
+
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/invent.c linux-2.4.21-pre6/arch/ia64/sn/io/invent.c
--- linux-2.4.20/arch/ia64/sn/io/invent.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/invent.c	2003-03-26 23:49:39.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/io.c linux-2.4.21-pre6/arch/ia64/sn/io/io.c
--- linux-2.4.20/arch/ia64/sn/io/io.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/io.c	2003-03-26 23:49:34.000000000 +0000
@@ -7,6 +7,7 @@
  * Copyright (C) 1992-1997, 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
  */
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <asm/sn/types.h>
@@ -31,21 +32,6 @@
 extern void hub_intr_init(devfs_handle_t hubv);
 
 
-/*      
- * hub_device_desc_update               
- *      Update the passed in device descriptor with the actual the
- *      target cpu number and interrupt priority level.
- *      NOTE : These might be the same as the ones passed in thru
- *      the descriptor.
- */     
-void
-hub_device_desc_update(device_desc_t    dev_desc,
-                       ilvl_t           intr_swlevel, 
-                       cpuid_t          cpu)
-{       
-}
-
-
 /*
  * Perform any initializations needed to support hub-based I/O.
  * Called once during startup.
@@ -53,11 +39,6 @@
 void
 hubio_init(void)
 {
-#ifdef	LATER
-	/* This isn't needed unless we port the entire sio driver ... */
-        extern void early_brl1_port_init( void );
-	early_brl1_port_init();
-#endif
 }
 
 /* 
@@ -149,6 +130,10 @@
 	nasid_t nasid;
 	volatile hubreg_t junk;
 	unsigned long s;
+	caddr_t kvaddr;
+#ifdef PIOMAP_UNC_ACC_SPACE
+	uint64_t addr;
+#endif
 
 	/* sanity check */
 	if (byte_count_max > byte_count)
@@ -159,8 +144,19 @@
 	/* If xtalk_addr range is mapped by a small window, we don't have 
 	 * to do much 
 	 */
-	if (xtalk_addr + byte_count <= SWIN_SIZE)
-		return(hubinfo_swin_piomap_get(hubinfo, (int)widget));
+	if (xtalk_addr + byte_count <= SWIN_SIZE) {
+		hub_piomap_t piomap;
+
+		piomap = hubinfo_swin_piomap_get(hubinfo, (int)widget);
+#ifdef PIOMAP_UNC_ACC_SPACE
+		if (flags & PIOMAP_UNC_ACC) {
+			addr = (uint64_t)piomap->hpio_xtalk_info.xp_kvaddr;
+			addr |= PIOMAP_UNC_ACC_SPACE;
+			piomap->hpio_xtalk_info.xp_kvaddr = (caddr_t)addr;
+		}
+#endif
+		return piomap;
+	}
 
 	/* We need to use a big window mapping.  */
 
@@ -257,7 +253,15 @@
 	bw_piomap->hpio_xtalk_info.xp_dev = dev;
 	bw_piomap->hpio_xtalk_info.xp_target = widget;
 	bw_piomap->hpio_xtalk_info.xp_xtalk_addr = xtalk_addr;
-	bw_piomap->hpio_xtalk_info.xp_kvaddr = (caddr_t)NODE_BWIN_BASE(nasid, free_bw_index);
+	kvaddr = (caddr_t)NODE_BWIN_BASE(nasid, free_bw_index);
+#ifdef PIOMAP_UNC_ACC_SPACE
+	if (flags & PIOMAP_UNC_ACC) {
+		addr = (uint64_t)kvaddr;
+		addr |= PIOMAP_UNC_ACC_SPACE;
+		kvaddr = (caddr_t)addr;
+	}
+#endif
+	bw_piomap->hpio_xtalk_info.xp_kvaddr = kvaddr;
 	bw_piomap->hpio_holdcnt++;
 	bw_piomap->hpio_bigwin_num = free_bw_index;
 
@@ -378,12 +382,22 @@
 	devfs_handle_t hubv = xwidget_info_master_get(widget_info);
 	hub_piomap_t hub_piomap;
 	hubinfo_t hubinfo;
+	caddr_t addr;
 
 	hubinfo_get(hubv, &hubinfo);
 
 	if (xtalk_addr + byte_count <= SWIN_SIZE) {
 		hub_piomap = hubinfo_swin_piomap_get(hubinfo, (int)widget);
-		return(hub_piomap_addr(hub_piomap, xtalk_addr, byte_count));
+		addr = hub_piomap_addr(hub_piomap, xtalk_addr, byte_count);
+#ifdef PIOMAP_UNC_ACC_SPACE
+		if (flags & PIOMAP_UNC_ACC) {
+			uint64_t iaddr;
+			iaddr = (uint64_t)addr;
+			iaddr |= PIOMAP_UNC_ACC_SPACE;
+			addr = (caddr_t)iaddr;
+		}
+#endif
+		return(addr);
 	} else
 		return(0);
 }
@@ -392,19 +406,6 @@
 /* DMA MANAGEMENT */
 /* Mapping from crosstalk space to system physical space */
 
-/* 
- * There's not really very much to do here, since crosstalk maps
- * directly to system physical space.  It's quite possible that this
- * DMA layer will be bypassed in performance kernels.
- */
-
-
-/* ARGSUSED */
-void
-hub_dma_init(devfs_handle_t hubv)
-{
-}
-
 
 /*
  * Allocate resources needed to set up DMA mappings up to a specified size
@@ -478,7 +479,12 @@
 	}
 
 	/* There isn't actually any DMA mapping hardware on the hub. */
-	return(paddr);
+#ifdef CONFIG_IA64_SGI_SN2
+        return( (PHYS_TO_DMA(paddr)) );
+#else
+        /* no translation needed */
+        return(paddr);
+#endif
 }
 
 /*
@@ -549,8 +555,12 @@
 			size_t byte_count,	/* length */
 			unsigned flags)		/* defined in dma.h */
 {
+#ifdef CONFIG_IA64_SGI_SN2
+	return( (PHYS_TO_DMA(paddr)) );
+#else
 	/* no translation needed */
 	return(paddr);
+#endif
 }
 
 /*
@@ -565,6 +575,7 @@
 			alenlist_t palenlist,	/* system address/length list */
 			unsigned flags)		/* defined in dma.h */
 {
+	BUG();
 	/* no translation needed */
 	return(palenlist);
 }
@@ -603,11 +614,9 @@
 void
 hub_provider_startup(devfs_handle_t hubv)
 {
-	extern void hub_dma_init(devfs_handle_t hubv);
 	extern void hub_pio_init(devfs_handle_t hubv);
 
 	hub_pio_init(hubv);
-	hub_dma_init(hubv);
 	hub_intr_init(hubv);
 }
 
@@ -707,14 +716,12 @@
 {
 	iprb_t prb;
 	int prb_offset;
-#ifdef LATER
 	extern int force_fire_and_forget;
 	extern volatile int ignore_conveyor_override;
 
 	if (force_fire_and_forget && !ignore_conveyor_override)
 	    if (conveyor == HUB_PIO_CONVEYOR)
 		conveyor = HUB_PIO_FIRE_N_FORGET;
-#endif
 
 	/*
 	 * Get the current register value.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/klgraph_hack.c linux-2.4.21-pre6/arch/ia64/sn/io/klgraph_hack.c
--- linux-2.4.20/arch/ia64/sn/io/klgraph_hack.c	2002-08-03 00:39:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/klgraph_hack.c	2003-03-26 23:48:58.000000000 +0000
@@ -13,13 +13,16 @@
  * initial klgraph information that is normally provided by prom.
  */
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <asm/sn/sgi.h>
 #include <asm/sn/io.h>
 #include <asm/sn/klconfig.h>
+#include <asm/sn/simulator.h>
 
+extern u64 klgraph_addr[];
 void * real_port;
 void * real_io_base;
 void * real_addr;
@@ -45,10 +48,15 @@
 #define HUBREG                  ((char *)0xc0000a0001e00000)
 #define WIDGET0                 ((char *)0xc0000a0000000000)
 
+#define convert(a,b,c) temp = (u64 *)a; *temp = b; temp++; *temp = c
+
 void
 klgraph_hack_init(void)
 {
 
+	u64     *temp;
+
+#ifdef CONFIG_IA64_SGI_SN1
 	/*
 	 * We need to know whether we are booting from PROM or 
 	 * boot from disk.
@@ -60,6 +68,139 @@
 		panic("klgraph_hack_init: Unable to locate KLCONFIG TABLE\n");
 	}
 
+	convert(0x0000000000030000, 0x00000000beedbabe, 0x0000004800000000);
+
+#else
+
+	if (IS_RUNNING_ON_SIMULATOR()) {
+		printk("Creating FAKE Klconfig Structure for Embeded Kernel\n");
+		klgraph_addr[0] = 0xe000003000030000;
+
+        /*
+         * klconfig entries initialization - mankato
+         */
+        convert(0xe000003000030000, 0x00000000beedbabe, 0x0000004800000000);
+        convert(0xe000003000030010, 0x0003007000000018, 0x800002000f820178);
+        convert(0xe000003000030020, 0x80000a000f024000, 0x800002000f800000);
+        convert(0xe000003000030030, 0x0300fafa00012580, 0x00000000040f0000);
+        convert(0xe000003000030040, 0x0000000000000000, 0x0003097000030070);
+        convert(0xe000003000030050, 0x00030970000303b0, 0x0003181000033f70);
+        convert(0xe000003000030060, 0x0003d51000037570, 0x0000000000038330);
+        convert(0xe000003000030070, 0x0203110100030140, 0x0001000000000101);
+        convert(0xe000003000030080, 0x0900000000000000, 0x000000004e465e67);
+        convert(0xe000003000030090, 0x0003097000000000, 0x00030b1000030a40);
+        convert(0xe0000030000300a0, 0x00030cb000030be0, 0x000315a0000314d0);
+        convert(0xe0000030000300b0, 0x0003174000031670, 0x0000000000000000);
+        convert(0xe000003000030100, 0x000000000000001a, 0x3350490000000000);
+        convert(0xe000003000030110, 0x0000000000000037, 0x0000000000000000);
+        convert(0xe000003000030140, 0x0002420100030210, 0x0001000000000101);
+        convert(0xe000003000030150, 0x0100000000000000, 0xffffffffffffffff);
+        convert(0xe000003000030160, 0x00030d8000000000, 0x0000000000030e50);
+        convert(0xe0000030000301c0, 0x0000000000000000, 0x0000000000030070);
+        convert(0xe0000030000301d0, 0x0000000000000025, 0x424f490000000000);
+        convert(0xe0000030000301e0, 0x000000004b434952, 0x0000000000000000);
+        convert(0xe000003000030210, 0x00027101000302e0, 0x00010000000e4101);
+        convert(0xe000003000030220, 0x0200000000000000, 0xffffffffffffffff);
+        convert(0xe000003000030230, 0x00030f2000000000, 0x0000000000030ff0);
+        convert(0xe000003000030290, 0x0000000000000000, 0x0000000000030140);
+        convert(0xe0000030000302a0, 0x0000000000000026, 0x7262490000000000);
+        convert(0xe0000030000302b0, 0x00000000006b6369, 0x0000000000000000);
+        convert(0xe0000030000302e0, 0x0002710100000000, 0x00010000000f3101);
+        convert(0xe0000030000302f0, 0x0500000000000000, 0xffffffffffffffff);
+        convert(0xe000003000030300, 0x000310c000000000, 0x0003126000031190);
+        convert(0xe000003000030310, 0x0003140000031330, 0x0000000000000000);
+        convert(0xe000003000030360, 0x0000000000000000, 0x0000000000030140);
+        convert(0xe000003000030370, 0x0000000000000029, 0x7262490000000000);
+        convert(0xe000003000030380, 0x00000000006b6369, 0x0000000000000000);
+        convert(0xe000003000030970, 0x0000000002010102, 0x0000000000000000);
+        convert(0xe000003000030980, 0x000000004e465e67, 0xffffffff00000000);
+        /* convert(0x00000000000309a0, 0x0000000000037570, 0x0000000100000000); */
+        convert(0xe0000030000309a0, 0x0000000000037570, 0xffffffff00000000);
+        convert(0xe0000030000309b0, 0x0000000000030070, 0x0000000000000000);
+        convert(0xe0000030000309c0, 0x000000000003f420, 0x0000000000000000);
+        convert(0xe000003000030a40, 0x0000000002010125, 0x0000000000000000);
+        convert(0xe000003000030a50, 0xffffffffffffffff, 0xffffffff00000000);
+        convert(0xe000003000030a70, 0x0000000000037b78, 0x0000000000000000);
+        convert(0xe000003000030b10, 0x0000000002010125, 0x0000000000000000);
+        convert(0xe000003000030b20, 0xffffffffffffffff, 0xffffffff00000000);
+        convert(0xe000003000030b40, 0x0000000000037d30, 0x0000000000000001);
+        convert(0xe000003000030be0, 0x00000000ff010203, 0x0000000000000000);
+        convert(0xe000003000030bf0, 0xffffffffffffffff, 0xffffffff000000ff);
+        convert(0xe000003000030c10, 0x0000000000037ee8, 0x0100010000000200);
+        convert(0xe000003000030cb0, 0x00000000ff310111, 0x0000000000000000);
+        convert(0xe000003000030cc0, 0xffffffffffffffff, 0x0000000000000000);
+        convert(0xe000003000030d80, 0x0000000002010104, 0x0000000000000000);
+        convert(0xe000003000030d90, 0xffffffffffffffff, 0x00000000000000ff);
+        convert(0xe000003000030db0, 0x0000000000037f18, 0x0000000000000000);
+        convert(0xe000003000030dc0, 0x0000000000000000, 0x0003007000060000);
+        convert(0xe000003000030de0, 0x0000000000000000, 0x0003021000050000);
+        convert(0xe000003000030df0, 0x000302e000050000, 0x0000000000000000);
+        convert(0xe000003000030e30, 0x0000000000000000, 0x000000000000000a);
+        convert(0xe000003000030e50, 0x00000000ff00011a, 0x0000000000000000);
+        convert(0xe000003000030e60, 0xffffffffffffffff, 0x0000000000000000);
+        convert(0xe000003000030e80, 0x0000000000037fe0, 0x9e6e9e9e9e9e9e9e);
+        convert(0xe000003000030e90, 0x000000000000bc6e, 0x0000000000000000);
+        convert(0xe000003000030f20, 0x0000000002010205, 0x00000000d0020000);
+        convert(0xe000003000030f30, 0xffffffffffffffff, 0x0000000e0000000e);
+        convert(0xe000003000030f40, 0x000000000000000e, 0x0000000000000000);
+        convert(0xe000003000030f50, 0x0000000000038010, 0x00000000000007ff);
+        convert(0xe000003000030f70, 0x0000000000000000, 0x0000000022001077);
+        convert(0xe000003000030fa0, 0x0000000000000000, 0x000000000003f4a8);
+        convert(0xe000003000030ff0, 0x0000000000310120, 0x0000000000000000);
+        convert(0xe000003000031000, 0xffffffffffffffff, 0xffffffff00000002);
+        convert(0xe000003000031010, 0x000000000000000e, 0x0000000000000000);
+        convert(0xe000003000031020, 0x0000000000038088, 0x0000000000000000);
+        convert(0xe0000030000310c0, 0x0000000002010205, 0x00000000d0020000);
+        convert(0xe0000030000310d0, 0xffffffffffffffff, 0x0000000f0000000f);
+        convert(0xe0000030000310e0, 0x000000000000000f, 0x0000000000000000);
+        convert(0xe0000030000310f0, 0x00000000000380b8, 0x00000000000007ff);
+        convert(0xe000003000031120, 0x0000000022001077, 0x00000000000310a9);
+        convert(0xe000003000031130, 0x00000000580211c1, 0x000000008009104c);
+        convert(0xe000003000031140, 0x0000000000000000, 0x000000000003f4c0);
+        convert(0xe000003000031190, 0x0000000000310120, 0x0000000000000000);
+        convert(0xe0000030000311a0, 0xffffffffffffffff, 0xffffffff00000003);
+        convert(0xe0000030000311b0, 0x000000000000000f, 0x0000000000000000);
+        convert(0xe0000030000311c0, 0x0000000000038130, 0x0000000000000000);
+        convert(0xe000003000031260, 0x0000000000110106, 0x0000000000000000);
+        convert(0xe000003000031270, 0xffffffffffffffff, 0xffffffff00000004);
+        convert(0xe000003000031270, 0xffffffffffffffff, 0xffffffff00000004);
+        convert(0xe000003000031280, 0x000000000000000f, 0x0000000000000000);
+        convert(0xe0000030000312a0, 0x00000000ff110013, 0x0000000000000000);
+        convert(0xe0000030000312b0, 0xffffffffffffffff, 0xffffffff00000000);
+        convert(0xe0000030000312c0, 0x000000000000000f, 0x0000000000000000);
+        convert(0xe0000030000312e0, 0x0000000000110012, 0x0000000000000000);
+        convert(0xe0000030000312f0, 0xffffffffffffffff, 0xffffffff00000000);
+        convert(0xe000003000031300, 0x000000000000000f, 0x0000000000000000);
+        convert(0xe000003000031310, 0x0000000000038160, 0x0000000000000000);
+        convert(0xe000003000031330, 0x00000000ff310122, 0x0000000000000000);
+        convert(0xe000003000031340, 0xffffffffffffffff, 0xffffffff00000005);
+        convert(0xe000003000031350, 0x000000000000000f, 0x0000000000000000);
+        convert(0xe000003000031360, 0x0000000000038190, 0x0000000000000000);
+        convert(0xe000003000031400, 0x0000000000310121, 0x0000000000000000);
+        convert(0xe000003000031400, 0x0000000000310121, 0x0000000000000000);
+        convert(0xe000003000031410, 0xffffffffffffffff, 0xffffffff00000006);
+        convert(0xe000003000031420, 0x000000000000000f, 0x0000000000000000);
+        convert(0xe000003000031430, 0x00000000000381c0, 0x0000000000000000);
+        convert(0xe0000030000314d0, 0x00000000ff010201, 0x0000000000000000);
+        convert(0xe0000030000314e0, 0xffffffffffffffff, 0xffffffff00000000);
+        convert(0xe000003000031500, 0x00000000000381f0, 0x000030430000ffff);
+        convert(0xe000003000031510, 0x000000000000ffff, 0x0000000000000000);
+        convert(0xe0000030000315a0, 0x00000020ff000201, 0x0000000000000000);
+        convert(0xe0000030000315b0, 0xffffffffffffffff, 0xffffffff00000001);
+        convert(0xe0000030000315d0, 0x0000000000038240, 0x00003f3f0000ffff);
+        convert(0xe0000030000315e0, 0x000000000000ffff, 0x0000000000000000);
+        convert(0xe000003000031670, 0x00000000ff010201, 0x0000000000000000);
+        convert(0xe000003000031680, 0xffffffffffffffff, 0x0000000100000002);
+        convert(0xe0000030000316a0, 0x0000000000038290, 0x000030430000ffff);
+        convert(0xe0000030000316b0, 0x000000000000ffff, 0x0000000000000000);
+        convert(0xe000003000031740, 0x00000020ff000201, 0x0000000000000000);
+        convert(0xe000003000031750, 0xffffffffffffffff, 0x0000000500000003);
+        convert(0xe000003000031770, 0x00000000000382e0, 0x00003f3f0000ffff);
+        convert(0xe000003000031780, 0x000000000000ffff, 0x0000000000000000);
+}
+
+#endif
+
 }
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/labelcl.c linux-2.4.21-pre6/arch/ia64/sn/io/labelcl.c
--- linux-2.4.20/arch/ia64/sn/io/labelcl.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/labelcl.c	2003-03-26 23:49:30.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (c) 2001 Silicon Graphics, Inc.  All rights reserved.
+ * Copyright (c) 2001-2002 Silicon Graphics, Inc.  All rights reserved.
 */
 
 #include <linux/types.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/pci.c linux-2.4.21-pre6/arch/ia64/sn/io/pci.c
--- linux-2.4.20/arch/ia64/sn/io/pci.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/pci.c	2003-03-26 23:49:20.000000000 +0000
@@ -230,7 +230,7 @@
 void __init
 sn_pci_find_bios(void)
 {
-	extern struct pci_ops pci_conf;
+	extern struct pci_ops *pci_root_ops;
 	/*
 	 * Go initialize our IO Infrastructure ..
 	 */
@@ -239,7 +239,7 @@
 	sgi_master_io_infr_init();
 
 	/* sn_io_infrastructure_init(); */
-	pci_conf = snia64_pci_ops;
+	pci_root_ops = &snia64_pci_ops;
 }
 
 void
@@ -276,15 +276,9 @@
                 d->resource[i].flags = 0UL;
         }
 
-	/*
-	 * Hardcode Device 4 register(IOC3 is in Slot 4) to set the 
-	 * DEV_DIRECT bit.  This will not work if IOC3 is not on Slot 
-	 * 4.
-	 */
-	DBG("pci_fixup_ioc3: FIXME .. need to take NASID into account when setting IOC3 devreg 0x%x\n", *(volatile u32 *)0xc0000a000f000220);
-
- 	*(volatile u32 *)0xc0000a000f000220 |= 0x90000; 
-
+#ifdef CONFIG_IA64_SGI_SN1
+	*(volatile u32 *)0xc0000a000f000220 |= 0x90000;
+#endif
         d->subsystem_vendor = 0;
         d->subsystem_device = 0;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/pci_dma.c linux-2.4.21-pre6/arch/ia64/sn/io/pci_dma.c
--- linux-2.4.20/arch/ia64/sn/io/pci_dma.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/pci_dma.c	2003-03-26 23:49:21.000000000 +0000
@@ -9,6 +9,7 @@
  * a description of how these routines should be used.
  */
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/mm.h>
 #include <linux/string.h>
@@ -31,18 +32,6 @@
 #include <asm/sn/pci/pci_bus_cvlink.h>
 #include <asm/sn/nag.h>
 
-/* DMA, PIO, and memory allocation flags */
-#ifdef CONFIG_IA64_SGI_SN1
-#define DMA_DATA_FLAGS		( PCIIO_BYTE_STREAM | PCIIO_DMA_DATA )
-#define DMA_CONTROL_FLAGS	( PCIIO_BYTE_STREAM | PCIBR_BARRIER | \
-				  PCIIO_DMA_CMD )
-#elif defined(CONFIG_IA64_SGI_SN2)
-#define DMA_DATA_FLAGS		( PCIIO_DMA_DATA )
-#define DMA_CONTROL_FLAGS	( PCIBR_BARRIER | PCIIO_DMA_CMD )
-#else
-#error need to define DMA mapping flags for this platform
-#endif
-
 /*
  * For ATE allocations
  */
@@ -129,9 +118,6 @@
 		}
 	}
 
-	printk(KERN_WARNING "find_sn_dma_map: Unable find the corresponding "
-	       "dma map\n");
-
 	return NULL;
 }
 
@@ -151,12 +137,15 @@
 sn_dma_sync(struct pci_dev *hwdev)
 {
 
+#ifdef SN_DMA_SYNC
+
 	struct sn_device_sysdata *device_sysdata;
 	volatile unsigned long dummy;
 
 	/*
-	 * It is expected that on an IA64 platform, a DMA sync ensures that 
-	 * all the DMA from a particular device is complete and coherent.  We
+	 * A DMA sync is supposed to ensure that 
+	 * all the DMA from a particular device
+	 * is complete and coherent.  We
 	 * try to do this by
 	 *	1. flushing the write wuffers from Bridge
 	 *	2. flushing the Xbow port.
@@ -167,12 +156,13 @@
 	dummy = (volatile unsigned long ) *device_sysdata->dma_buf_sync;
 
 	/*
-	 * For the Xbow port flush, we maybe denied the request because 
+	 * For the Xbow port flush, we may be denied the request because 
 	 * someone else may be flushing the port .. try again.
 	 */
 	while((volatile unsigned long ) *device_sysdata->xbow_buf_sync) {
 		udelay(2);
 	}
+#endif
 }
 
 /**
@@ -183,13 +173,12 @@
  *
  * pci_alloc_consistent() returns a pointer to a memory region suitable for
  * coherent DMA traffic to/from a PCI device.  On SN platforms, this means
- * that @dma_handle will have the PCIBR_BARRIER and PCIIO_DMA_CMD flags
- * set.
+ * that @dma_handle will have the %PCIIO_DMA_CMD flag set.
  *
  * This interface is usually used for "command" streams (e.g. the command
  * queue for a SCSI controller).  See Documentation/DMA-mapping.txt for
- * more information.  Note that this routine should always put a 32 bit
- * DMA address into @dma_handle.  This is because most other platforms
+ * more information.  Note that this routine will always put a 32 bit
+ * DMA address into @dma_handle.  This is because most devices
  * that are capable of 64 bit PCI DMA transactions can't do 64 bit _coherent_
  * DMAs, and unfortunately this interface has to cater to the LCD.  Oh well.
  *
@@ -232,15 +221,40 @@
 	/* physical addr. of the memory we just got */
 	phys_addr = __pa(cpuaddr);
 
+	/*
+	 * This will try to use a Direct Map register to do the
+	 * 32 bit DMA mapping, but it may not succeed if another
+	 * device on the same bus is already mapped with different
+	 * attributes or to a different memory region.
+	 */
+#ifdef CONFIG_IA64_SGI_SN1
 	*dma_handle = pciio_dmatrans_addr(vhdl, NULL, phys_addr, size,
-					  DMA_CONTROL_FLAGS);
+					  PCIIO_BYTE_STREAM |
+					  PCIIO_DMA_CMD);
+#elif defined(CONFIG_IA64_SGI_SN2)
+	*dma_handle = pciio_dmatrans_addr(vhdl, NULL, phys_addr, size,
+			((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) |
+					  PCIIO_DMA_CMD);
+#else
+#error unsupported platform
+#endif
+
 	/*
 	 * It is a 32 bit card and we cannot do direct mapping,
-	 * so we use an ATE.
+	 * so we try to use an ATE.
 	 */
 	if (!(*dma_handle)) {
+#ifdef CONFIG_IA64_SGI_SN1
 		dma_map = pciio_dmamap_alloc(vhdl, NULL, size,
-					     DMA_CONTROL_FLAGS | PCIIO_FIXED);
+					     PCIIO_BYTE_STREAM |
+					     PCIIO_DMA_CMD);
+#elif defined(CONFIG_IA64_SGI_SN2)
+		dma_map = pciio_dmamap_alloc(vhdl, NULL, size,
+				((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) |
+					     PCIIO_DMA_CMD);
+#else
+#error unsupported platform
+#endif
 		if (!dma_map) {
 			printk(KERN_ERR "sn_pci_alloc_consistent: Unable to "
 			       "allocate anymore 32 bit page map entries.\n");
@@ -250,13 +264,7 @@
 							     size);
 		sn_dma_map = (struct sn_dma_maps_s *)dma_map;
 		sn_dma_map->dma_addr = *dma_handle;
-		printk(KERN_INFO "%s: PMU mapping: %p\n", __FUNCTION__,
-		       (void *)*dma_handle);
 	}
-	else
-		printk(KERN_INFO "%s: direct mapping: %p\n", __FUNCTION__,
-		       (void *)*dma_handle);
-	
 
         return cpuaddr;
 }
@@ -359,7 +367,9 @@
 		if (IS_PCIA64(hwdev)) {
 			dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr,
 						       sg->length,
-						       DMA_DATA_FLAGS | PCIIO_DMA_A64 );
+			       ((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) |
+						       PCIIO_DMA_DATA |
+						       PCIIO_DMA_A64);
 			sg->address = (char *)dma_addr;
 			continue;
 		}
@@ -368,9 +378,19 @@
 		 * Handle 32-63 bit cards via direct mapping
 		 */
 		if (IS_PCI32G(hwdev)) {
+#ifdef CONFIG_IA64_SGI_SN1
 			dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr,
 						       sg->length,
-						       DMA_DATA_FLAGS);
+						       PCIIO_BYTE_STREAM |
+						       PCIIO_DMA_DATA);
+#elif defined(CONFIG_IA64_SGI_SN2)
+			dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr,
+						       sg->length,
+					((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) |
+						       PCIIO_DMA_DATA);
+#else
+#error unsupported platform
+#endif
 			/*
 			 * See if we got a direct map entry
 			 */
@@ -386,8 +406,17 @@
 		 * so we use an ATE.
 		 */
 		dma_map = 0;
+#ifdef CONFIG_IA64_SGI_SN1
 		dma_map = pciio_dmamap_alloc(vhdl, NULL, sg->length,
-					     DMA_DATA_FLAGS);
+					     PCIIO_BYTE_STREAM |
+					     PCIIO_DMA_DATA);
+#elif defined(CONFIG_IA64_SGI_SN2)
+		dma_map = pciio_dmamap_alloc(vhdl, NULL, sg->length,
+				((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) |
+					     PCIIO_DMA_DATA);
+#else
+#error unsupported platform
+#endif
 		if (!dma_map) {
 			printk(KERN_ERR "sn_pci_map_sg: Unable to allocate "
 			       "anymore 32 bit page map entries.\n");
@@ -395,7 +424,7 @@
 		}
 		dma_addr = pciio_dmamap_addr(dma_map, phys_addr, sg->length);
 		sg->address = (char *)dma_addr;
-		sg->page = (char *)dma_map;
+		sg->page = (struct page *)dma_map;
 		
 	}
 
@@ -474,7 +503,8 @@
 		BUG();
 
 	/* SN cannot support DMA addresses smaller than 32 bits. */
-	if (IS_PCI32L(hwdev)) return 0;
+	if (IS_PCI32L(hwdev))
+		return 0;
 
 	/*
 	 * find vertex for the device
@@ -489,23 +519,32 @@
 	phys_addr = __pa(ptr);
 
 	if (IS_PCIA64(hwdev)) {
-		/*
-		 * This device supports 64 bit DMA addresses.
-		 */
+		/* This device supports 64 bit DMA addresses. */
 		dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr, size,
-					       DMA_DATA_FLAGS | PCIIO_DMA_A64);
+		       ((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) |
+					       PCIIO_DMA_DATA |
+					       PCIIO_DMA_A64);
 		return dma_addr;
 	}
 
 	/*
-	 * Devices that supports 32 bit to 63 bit DMA addresses get
+	 * Devices that support 32 bit to 63 bit DMA addresses get
 	 * 32 bit DMA addresses.
 	 *
 	 * First try to get a 32 bit direct map register.
 	 */
 	if (IS_PCI32G(hwdev)) {
+#ifdef CONFIG_IA64_SGI_SN1
 		dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr, size,
-					       DMA_DATA_FLAGS);
+					       PCIIO_BYTE_STREAM |
+					       PCIIO_DMA_DATA);
+#elif defined(CONFIG_IA64_SGI_SN2)
+		dma_addr = pciio_dmatrans_addr(vhdl, NULL, phys_addr, size,
+			((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) |
+					       PCIIO_DMA_DATA);
+#else
+#error unsupported platform
+#endif
 		if (dma_addr)
 			return dma_addr;
 	}
@@ -515,11 +554,20 @@
 	 * let's use the PMU instead.
 	 */
 	dma_map = NULL;
-	dma_map = pciio_dmamap_alloc(vhdl, NULL, size, DMA_DATA_FLAGS);
+#ifdef CONFIG_IA64_SGI_SN1
+	dma_map = pciio_dmamap_alloc(vhdl, NULL, size, PCIIO_BYTE_STREAM |
+				     PCIIO_DMA_DATA);
+#elif defined(CONFIG_IA64_SGI_SN2)
+	dma_map = pciio_dmamap_alloc(vhdl, NULL, size, 
+			((IS_PIC_DEVICE(hwdev)) ? 0 : PCIIO_BYTE_STREAM) |
+			PCIIO_DMA_DATA);
+#else
+#error unsupported platform
+#endif
 
 	if (!dma_map) {
 		printk(KERN_ERR "pci_map_single: Unable to allocate anymore "
-		       "32 bits page map entries.\n");
+		       "32 bit page map entries.\n");
 		BUG();
 	}
 
@@ -628,7 +676,9 @@
  * properly.  For example, if your device can only drive the low 24-bits
  * during PCI bus mastering, then you would pass 0x00ffffff as the mask to
  * this function.  Of course, SN only supports devices that have 32 or more
- * address bits.
+ * address bits when using the PMU.  We could theoretically support <32 bit
+ * cards using direct mapping, but we'll worry about that later--on the off
+ * chance that someone actually wants to use such a card.
  */
 int
 sn_pci_dma_supported(struct pci_dev *hwdev, u64 mask)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/pciba.c linux-2.4.21-pre6/arch/ia64/sn/io/pciba.c
--- linux-2.4.20/arch/ia64/sn/io/pciba.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/pciba.c	2003-03-26 23:48:59.000000000 +0000
@@ -285,45 +285,6 @@
 static devfs_handle_t pciba_devfs_handle;
 
 
-#if !defined(CONFIG_IA64_SGI_SN1)
-
-static status __init
-register_with_devfs(void)
-{
-	struct pci_dev * dev;
-	devfs_handle_t device_dir_handle;
-	char devfs_path[40];
-
-	TRACE();
-
-	pciba_devfs_handle = devfs_mk_dir(NULL, "pci", NULL);
-	if (pciba_devfs_handle == NULL)
-		return failure;
-
-	/* FIXME: don't forget /dev/pci/mem & /dev/pci/io */
-
-	pci_for_each_dev(dev) {
-		sprintf(devfs_path, "%02x/%02x.%x",
-			dev->bus->number,
-			PCI_SLOT(dev->devfn),
-			PCI_FUNC(dev->devfn));
-    
-		device_dir_handle =
-			devfs_mk_dir(pciba_devfs_handle, devfs_path, NULL);
-		if (device_dir_handle == NULL)
-			return failure;
-
-		if (register_pci_device(device_dir_handle, dev) == failure) {
-			devfs_unregister(pciba_devfs_handle);
-			return failure;
-		}
-	}
-
-	return success;
-}
-
-#else
-
 extern devfs_handle_t
 devfn_to_vertex(unsigned char busnum, unsigned int devfn);
 
@@ -352,9 +313,6 @@
 	return success;
 }
 
-#endif /* CONFIG_IA64_SGI_SN1 */
-
-
 static void __exit
 unregister_with_devfs(void)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sgi_if.c linux-2.4.21-pre6/arch/ia64/sn/io/sgi_if.c
--- linux-2.4.20/arch/ia64/sn/io/sgi_if.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sgi_if.c	2003-03-26 23:49:38.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 
 #include <linux/types.h>
@@ -20,14 +20,50 @@
 #include <asm/sn/pci/pciio.h>
 #include <asm/sn/slotnum.h>
 
+unsigned char Is_pic_on_this_nasid[512];	/* non-0 when this is a pic shub */
+
 void *
 snia_kmem_zalloc(size_t size, int flag)
 {
         void *ptr = kmalloc(size, GFP_KERNEL);
-        BZERO(ptr, size);
-        return ptr;
+	if ( ptr )
+        	BZERO(ptr, size);
+        return(ptr);
+}
+
+void
+snia_kmem_free(void *ptr, size_t size)
+{
+        kfree(ptr);
+}
+
+int
+nic_vertex_info_match(devfs_handle_t v, char *s)
+{
+	/* we don't support this */
+	return(0);
 }
 
+/*
+ * the alloc/free_node routines do a simple kmalloc for now ..
+ */
+void *
+snia_kmem_alloc_node(register size_t size, register int flags, cnodeid_t node)
+{
+	/* someday will Allocate on node 'node' */
+	return(kmalloc(size, GFP_KERNEL));
+}
+
+void *
+snia_kmem_zalloc_node(register size_t size, register int flags, cnodeid_t node)
+{
+	void *ptr = kmalloc(size, GFP_KERNEL);
+	if ( ptr )
+		BZERO(ptr, size);
+        return(ptr);
+}
+
+
 #define xtod(c)         ((c) <= '9' ? '0' - (c) : 'a' - (c) - 10)
 long
 atoi(register char *p)
@@ -67,3 +103,111 @@
         }
         return (neg ? n : -n);
 }
+
+char *
+strtok_r(char *string, const char *sepset, char **lasts)
+{
+        register char   *q, *r;
+
+        /*first or subsequent call*/
+        if (string == NULL)
+                string = *lasts;
+
+        if(string == 0)         /* return if no tokens remaining */
+                return(NULL);
+
+        q = string + strspn(string, sepset);    /* skip leading separators */
+
+        if(*q == '\0') {                /* return if no tokens remaining */
+                *lasts = 0;     /* indicate this is last token */
+                return(NULL);
+        }
+
+        if((r = strpbrk(q, sepset)) == NULL)    /* move past token */
+                *lasts = 0;     /* indicate this is last token */
+        else {
+                *r = '\0';
+                *lasts = r+1;
+        }
+        return(q);
+}
+
+/*
+ * print_register() allows formatted printing of bit fields.  individual
+ * bit fields are described by a struct reg_desc, multiple bit fields within
+ * a single word can be described by multiple reg_desc structures.
+ * %r outputs a string of the format "<bit field descriptions>"
+ * %R outputs a string of the format "0x%x<bit field descriptions>"
+ *
+ * The fields in a reg_desc are:
+ *	unsigned long long rd_mask; An appropriate mask to isolate the bit field
+ *				within a word, and'ed with val
+ *
+ *	int rd_shift;		A shift amount to be done to the isolated
+ *				bit field.  done before printing the isolate
+ *				bit field with rd_format and before searching
+ *				for symbolic value names in rd_values
+ *
+ *	char *rd_name;		If non-null, a bit field name to label any
+ *				out from rd_format or searching rd_values.
+ *				if neither rd_format or rd_values is non-null
+ *				rd_name is printed only if the isolated
+ *				bit field is non-null.
+ *
+ *	char *rd_format;	If non-null, the shifted bit field value
+ *				is printed using this format.
+ *
+ *	struct reg_values *rd_values;	If non-null, a pointer to a table
+ *				matching numeric values with symbolic names.
+ *				rd_values are searched and the symbolic
+ *				value is printed if a match is found, if no
+ *				match is found "???" is printed.
+ *				
+ */
+
+void
+print_register(unsigned long long reg, struct reg_desc *addr)
+{
+	register struct reg_desc *rd;
+	register struct reg_values *rv;
+	unsigned long long field;
+	int any;
+
+	printk("<");
+	any = 0;
+	for (rd = addr; rd->rd_mask; rd++) {
+		field = reg & rd->rd_mask;
+		field = (rd->rd_shift > 0) ? field << rd->rd_shift : field >> -rd->rd_shift;
+		if (any && (rd->rd_format || rd->rd_values || (rd->rd_name && field)))
+			printk(",");
+		if (rd->rd_name) {
+			if (rd->rd_format || rd->rd_values || field) {
+				printk("%s", rd->rd_name);
+				any = 1;
+			}
+			if (rd->rd_format || rd->rd_values) {
+				printk("=");
+				any = 1;
+			}
+		}
+		/* You can have any format so long as it is %x */
+		if (rd->rd_format) {
+			printk("%llx", field);
+			any = 1;
+			if (rd->rd_values)
+				printk(":");
+		}
+		if (rd->rd_values) {
+			any = 1;
+			for (rv = rd->rd_values; rv->rv_name; rv++) {
+				if (field == rv->rv_value) {
+					printk("%s", rv->rv_name);
+					break;
+				}
+			}
+			if (rv->rv_name == NULL)
+				printk("???");
+		}
+	}
+	printk(">\n");
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sgi_io_sim.c linux-2.4.21-pre6/arch/ia64/sn/io/sgi_io_sim.c
--- linux-2.4.20/arch/ia64/sn/io/sgi_io_sim.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sgi_io_sim.c	2003-03-26 23:49:25.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 
 #include <linux/config.h>
@@ -71,6 +71,9 @@
  */
 static __psunsigned_t master_bridge_base = (__psunsigned_t)NULL;
 nasid_t console_nasid = (nasid_t)-1;
+#if !defined(CONFIG_IA64_SGI_SN1)
+char master_baseio_wid;
+#endif
 static char console_wid;
 static char console_pcislot;
 
@@ -92,6 +95,7 @@
                 return 0;
 }
 
+#if defined(CONFIG_IA64_SGI_SN1)
 int
 is_master_nasid_widget(nasid_t test_nasid, xwidgetnum_t test_wid)
 {
@@ -111,6 +115,29 @@
                 return 0;
         }
 }
+#else
+int
+is_master_baseio_nasid_widget(nasid_t test_nasid, xwidgetnum_t test_wid)
+{
+	extern nasid_t master_baseio_nasid;
+
+        /*
+         * If the widget numbers are different, we're not the master.
+         */
+        if (test_wid != (xwidgetnum_t)master_baseio_wid) {
+                return 0;
+	}
+
+        /*
+         * If the NASIDs are the same or equivalent, we're the master.
+         */
+        if (check_nasid_equiv(test_nasid, master_baseio_nasid)) {
+                return 1;
+        } else {
+                return 0;
+        }
+}
+#endif	/* CONFIG_IA64_SGI_SN1 */
 
 /*
  * Routines provided by ml/SN/nvram.c
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn1/Makefile linux-2.4.21-pre6/arch/ia64/sn/io/sn1/Makefile
--- linux-2.4.20/arch/ia64/sn/io/sn1/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn1/Makefile	2003-03-26 23:48:57.000000000 +0000
@@ -0,0 +1,25 @@
+#
+# 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) 2002 Silicon Graphics, Inc.  All Rights Reserved.
+#
+# Makefile for the sn1 io routines.
+
+EXTRA_CFLAGS    := -DLITTLE_ENDIAN
+
+O_TARGET := snio.o
+
+export-objs := pciio.o
+
+obj-$(CONFIG_IA64_SGI_SN1)	+= ml_SN_intr.o mem_refcnt.o hubcounters.o \
+				   ip37.o huberror.o hub_intr.o pcibr.o \
+				   eeprom.o l1.o l1_command.o pciio.o \
+				   klconflib.o klgraph.o \
+				   efi-rtc.o xbow.o xtalk.o \
+				   ml_SN_init.o ml_iograph.o module.o \
+				   pci_bus_cvlink.o sgi_io_init.o
+
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn1/eeprom.c linux-2.4.21-pre6/arch/ia64/sn/io/sn1/eeprom.c
--- linux-2.4.20/arch/ia64/sn/io/sn1/eeprom.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn1/eeprom.c	2003-03-26 23:49:30.000000000 +0000
@@ -0,0 +1,1421 @@
+/*
+ * 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) 1999-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+/*
+ * WARNING:     There is more than one copy of this file in different isms.
+ *              All copies must be kept exactly in sync.
+ *              Do not modify this file without also updating the following:
+ *
+ *              irix/kern/io/eeprom.c
+ *              stand/arcs/lib/libsk/ml/eeprom.c
+ *		stand/arcs/lib/libkl/io/eeprom.c
+ *
+ *      (from time to time they might not be in sync but that's due to bringup
+ *       activity - this comment is to remind us that they eventually have to
+ *       get back together)
+ *
+ * eeprom.c
+ *
+ * access to board-mounted EEPROMs via the L1 system controllers
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/io.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/hcl_util.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/eeprom.h>
+#include <asm/sn/router.h>
+#include <asm/sn/module.h>
+#include <asm/sn/ksys/l1.h>
+#include <asm/sn/nodepda.h>
+#include <asm/sn/clksupport.h>
+#include <asm/sn/sn_cpuid.h>
+#include <asm/sn/simulator.h>
+
+#if defined(EEPROM_DEBUG)
+#define db_printf(x) printk x
+#else
+#define db_printf(x) printk x
+#endif
+
+#define BCOPY(x,y,z)	memcpy(y,x,z)
+
+#define UNDERSCORE	0	/* don't convert underscores to hyphens */
+#define HYPHEN		1	/* convert underscores to hyphens */
+
+void		copy_ascii_field( char *to, char *from, int length,
+			          int change_underscore );
+uint64_t	generate_unique_id( char *sn, int sn_len );
+uchar_t		char_to_base36( char c );
+int		nicify( char *dst, eeprom_brd_record_t *src );
+static void	int64_to_hex_string( char *out, uint64_t val );
+
+// extern int router_lock( net_vec_t, int, int );
+// extern int router_unlock( net_vec_t );
+#define ROUTER_LOCK(p) 	// router_lock(p, 10000, 3000000)
+#define ROUTER_UNLOCK(p) 	// router_unlock(p)
+
+#define IP27LOG_OVNIC           "OverrideNIC"
+
+
+/* the following function converts an EEPROM record to a close facsimile
+ * of the string returned by reading a Dallas Semiconductor NIC (see
+ * one of the many incarnations of nic.c for details on that driver)
+ */
+int nicify( char *dst, eeprom_brd_record_t *src )
+{
+    int field_len;
+    uint64_t unique_id;
+    char *cur_dst = dst;
+    eeprom_board_ia_t   *board;
+
+    board   = src->board_ia;
+    ASSERT( board );  /* there should always be a board info area */
+
+    /* copy part number */
+    strcpy( cur_dst, "Part:" );
+    cur_dst += strlen( cur_dst );
+    ASSERT( (board->part_num_tl & FIELD_FORMAT_MASK)
+	    == FIELD_FORMAT_ASCII );
+    field_len = board->part_num_tl & FIELD_LENGTH_MASK;
+    copy_ascii_field( cur_dst, board->part_num, field_len, HYPHEN );
+    cur_dst += field_len;
+
+    /* copy product name */
+    strcpy( cur_dst, ";Name:" );
+    cur_dst += strlen( cur_dst );
+    ASSERT( (board->product_tl & FIELD_FORMAT_MASK) == FIELD_FORMAT_ASCII );
+    field_len = board->product_tl & FIELD_LENGTH_MASK;
+    copy_ascii_field( cur_dst, board->product, field_len, UNDERSCORE );
+    cur_dst += field_len;
+
+    /* copy serial number */
+    strcpy( cur_dst, ";Serial:" );
+    cur_dst += strlen( cur_dst );
+    ASSERT( (board->serial_num_tl & FIELD_FORMAT_MASK)
+	    == FIELD_FORMAT_ASCII );
+    field_len = board->serial_num_tl & FIELD_LENGTH_MASK;
+    copy_ascii_field( cur_dst, board->serial_num, field_len,
+		      HYPHEN);
+
+    cur_dst += field_len;
+
+    /* copy revision */
+    strcpy( cur_dst, ";Revision:");
+    cur_dst += strlen( cur_dst );
+    ASSERT( (board->board_rev_tl & FIELD_FORMAT_MASK)
+	    == FIELD_FORMAT_ASCII );
+    field_len = board->board_rev_tl & FIELD_LENGTH_MASK;
+    copy_ascii_field( cur_dst, board->board_rev, field_len, HYPHEN );
+    cur_dst += field_len;
+
+    /* EEPROMs don't have equivalents for the Group, Capability and
+     * Variety fields, so we pad these with 0's
+     */
+    strcpy( cur_dst, ";Group:ff;Capability:ffffffff;Variety:ff" );
+    cur_dst += strlen( cur_dst );
+
+    /* use the board serial number to "fake" a laser id */
+    strcpy( cur_dst, ";Laser:" );
+    cur_dst += strlen( cur_dst );
+    unique_id = generate_unique_id( board->serial_num,
+				    board->serial_num_tl & FIELD_LENGTH_MASK );
+    int64_to_hex_string( cur_dst, unique_id );
+    strcat( dst, ";" );
+
+    return 1;
+}
+
+
+/* These functions borrow heavily from chars2* in nic.c
+ */
+void copy_ascii_field( char *to, char *from, int length,
+		       int change_underscore )
+{
+    int i;
+    for( i = 0; i < length; i++ ) {
+
+	/* change underscores to hyphens if requested */
+	if( from[i] == '_' && change_underscore == HYPHEN )
+	    to[i] = '-';
+
+	/* ; and ; are separators, so mustn't appear within
+	 * a field */
+	else if( from[i] == ':' || from[i] == ';' )
+	    to[i] = '?';
+
+	/* I'm not sure why or if ASCII character 0xff would
+	 * show up in an EEPROM field, but the NIC parsing
+	 * routines wouldn't like it if it did... so we
+	 * get rid of it, just in case. */
+	else if( (unsigned char)from[i] == (unsigned char)0xff )
+	    to[i] = ' ';
+	
+	/* unprintable characters are replaced with . */
+	else if( from[i] < ' ' || from[i] >= 0x7f )
+	    to[i] = '.';
+
+	/* otherwise, just copy the character */
+	else
+	    to[i] = from[i];
+    }
+
+    if( i == 0 ) {
+	to[i] = ' '; /* return at least a space... */
+	i++;
+    }
+    to[i] = 0;	     /* terminating null */
+}
+
+/* Note that int64_to_hex_string currently only has a big-endian
+ * implementation.
+ */
+#ifdef _MIPSEB
+static void int64_to_hex_string( char *out, uint64_t val )
+{
+    int i;
+    uchar_t table[] = "0123456789abcdef";
+    uchar_t *byte_ptr = (uchar_t *)&val;
+    for( i = 0; i < sizeof(uint64_t); i++ ) {
+	out[i*2] = table[ ((*byte_ptr) >> 4) & 0x0f ];
+	out[i*2+1] = table[ (*byte_ptr) & 0x0f ];
+	byte_ptr++;
+    }
+    out[i*2] = '\0';
+}
+
+#else /* little endian */
+
+static void int64_to_hex_string( char *out, uint64_t val )
+{
+
+
+	printk("int64_to_hex_string needs a little-endian implementation.\n");
+}
+#endif /* _MIPSEB */
+
+/* Convert a standard ASCII serial number to a unique integer
+ * id number by treating the serial number string as though
+ * it were a base 36 number
+ */
+uint64_t generate_unique_id( char *sn, int sn_len )
+{
+    int uid = 0;
+    int i;
+
+    #define VALID_BASE36(c)	((c >= '0' && c <='9') \
+			    ||   (c >= 'A' && c <='Z') \
+			    ||   (c >= 'a' && c <='z'))
+
+    for( i = 0; i < sn_len; i++ ) {
+	if( !VALID_BASE36(sn[i]) )
+	    continue;
+	uid *= 36;
+	uid += char_to_base36( sn[i] );
+    }
+
+    if( uid == 0 )
+	return rtc_time();
+
+    return uid;
+}
+
+uchar_t char_to_base36( char c )
+{
+    uchar_t val;
+
+    if( c >= '0' && c <= '9' )
+	val = (c - '0');
+
+    else if( c >= 'A' && c <= 'Z' )
+	val = (c - 'A' + 10);
+
+    else if( c >= 'a' && c <= 'z' )
+	val = (c - 'a' + 10);
+
+    else val = 0;
+
+    return val;
+}
+
+
+/* given a pointer to the three-byte little-endian EEPROM representation
+ * of date-of-manufacture, this function translates to a big-endian
+ * integer format
+ */
+int eeprom_xlate_board_mfr_date( uchar_t *src )
+{
+    int rval = 0;
+    rval += *src; src++;
+    rval += ((int)(*src) << 8); src ++;
+    rval += ((int)(*src) << 16);
+    return rval;
+}
+
+
+int eeprom_str( char *nic_str, nasid_t nasid, int component )
+{
+    eeprom_brd_record_t eep;
+    eeprom_board_ia_t board;
+    eeprom_chassis_ia_t chassis;
+    int r;
+
+    if( (component & C_DIMM) == C_DIMM ) {
+	/* this function isn't applicable to DIMMs */
+	return EEP_PARAM;
+    }
+    else {
+	eep.board_ia = &board;
+	eep.spd = NULL;
+	if( !(component & SUBORD_MASK) )
+	    eep.chassis_ia = &chassis;  /* only main boards have a chassis
+					 * info area */
+	else
+	    eep.chassis_ia = NULL;
+    }
+    
+    switch( component & BRICK_MASK ) {
+      case C_BRICK:
+	r = cbrick_eeprom_read( &eep, nasid, component );
+	break;
+      case IO_BRICK:
+	r = iobrick_eeprom_read( &eep, nasid, component );
+	break;
+      default:
+	return EEP_PARAM;  /* must be an invalid component */
+    }
+    if( r )
+	return r;
+    if( !nicify( nic_str, &eep ) )
+	return EEP_NICIFY;
+
+    return EEP_OK;
+}
+
+int vector_eeprom_str( char *nic_str, nasid_t nasid,
+		       int component, net_vec_t path )
+{
+    eeprom_brd_record_t eep;
+    eeprom_board_ia_t board;
+    eeprom_chassis_ia_t chassis;
+    int r;
+
+    eep.board_ia = &board;
+    if( !(component & SUBORD_MASK) )
+        eep.chassis_ia = &chassis;  /* only main boards have a chassis
+                                     * info area */
+    else
+        eep.chassis_ia = NULL;
+
+    if( !(component & VECTOR) )
+	return EEP_PARAM;
+
+    if( (r = vector_eeprom_read( &eep, nasid, path, component )) )
+	return r;
+
+    if( !nicify( nic_str, &eep ) )
+        return EEP_NICIFY;
+
+    return EEP_OK;
+}
+
+
+int is_iobrick( int nasid, int widget_num )
+{
+    uint32_t wid_reg;
+    int part_num, mfg_num;
+
+    /* Read the widget's WIDGET_ID register to get
+     * its part number and mfg number
+     */
+    wid_reg = *(volatile int32_t *)
+        (NODE_SWIN_BASE( nasid, widget_num ) + WIDGET_ID);
+
+    part_num = (wid_reg & WIDGET_PART_NUM) >> WIDGET_PART_NUM_SHFT;
+    mfg_num = (wid_reg & WIDGET_MFG_NUM) >> WIDGET_MFG_NUM_SHFT;
+
+    /* Is this the "xbow part" of an XBridge?  If so, this
+     * widget is definitely part of an I/O brick.
+     */
+    if( part_num == XXBOW_WIDGET_PART_NUM &&
+	mfg_num == XXBOW_WIDGET_MFGR_NUM )
+
+	return 1;
+
+    /* Is this a "bridge part" of an XBridge?  If so, once
+     * again, we know this widget is part of an I/O brick.
+     */
+    if( part_num == XBRIDGE_WIDGET_PART_NUM &&
+	mfg_num == XBRIDGE_WIDGET_MFGR_NUM )
+
+	return 1;
+
+    return 0;
+}
+
+
+int cbrick_uid_get( nasid_t nasid, uint64_t *uid )
+{
+    char uid_str[32];
+    char msg[BRL1_QSIZE];
+    int subch, len;
+    l1sc_t sc;
+    l1sc_t *scp;
+    int local = (nasid == get_nasid());
+
+    if ( IS_RUNNING_ON_SIMULATOR() )
+	return EEP_L1;
+
+    /* If the promlog variable pointed to by IP27LOG_OVNIC is set,
+     * use that value for the cbrick UID rather than the EEPROM
+     * serial number.
+     */
+#ifdef LOG_GETENV
+    if( ip27log_getenv( nasid, IP27LOG_OVNIC, uid_str, NULL, 0 ) >= 0 )
+    {
+	/* We successfully read IP27LOG_OVNIC, so return it as the UID. */
+	db_printf(( "cbrick_uid_get:"
+		    "Overriding UID with environment variable %s\n", 
+		    IP27LOG_OVNIC ));
+	*uid = strtoull( uid_str, NULL, 0 );
+	return EEP_OK;
+    }
+#endif
+
+    /* If this brick is retrieving its own uid, use the local l1sc_t to
+     * arbitrate access to the l1; otherwise, set up a new one.
+     */
+    if( local ) {
+	scp = get_l1sc();
+    }
+    else {
+	scp = &sc;
+	sc_init( &sc, nasid, BRL1_LOCALHUB_UART );
+    }
+
+    /* fill in msg with the opcode & params */
+    BZERO( msg, BRL1_QSIZE );
+    if( (subch = sc_open( scp, L1_ADDR_LOCAL )) < 0 )
+	return EEP_L1;
+
+    if( (len = sc_construct_msg( scp, subch, msg, BRL1_QSIZE,
+				 L1_ADDR_TASK_GENERAL,
+				 L1_REQ_SER_NUM, 0 )) < 0 )
+    {
+	sc_close( scp, subch );
+	return( EEP_L1 );
+    }
+
+    /* send the request to the L1 */
+    if( sc_command( scp, subch, msg, msg, &len ) ) {
+	sc_close( scp, subch );
+	return( EEP_L1 );
+    }
+
+    /* free up subchannel */
+    sc_close(scp, subch);
+
+    /* check response */
+    if( sc_interpret_resp( msg, 2, L1_ARG_ASCII, uid_str ) < 0 )
+    {
+	return( EEP_L1 );
+    }
+
+    *uid = generate_unique_id( uid_str, strlen( uid_str ) );
+
+    return EEP_OK;
+}
+
+
+int rbrick_uid_get( nasid_t nasid, net_vec_t path, uint64_t *uid )
+{
+    char uid_str[32];
+    char msg[BRL1_QSIZE];
+    int subch, len;
+    l1sc_t sc;
+
+    if ( IS_RUNNING_ON_SIMULATOR() )
+	return EEP_L1;
+
+#define FAIL								\
+    {									\
+	*uid = rtc_time();						\
+	printk( "rbrick_uid_get failed; using current time as uid\n" );	\
+	return EEP_OK;							\
+    }
+
+    ROUTER_LOCK(path);
+    sc_init( &sc, nasid, path );
+
+    /* fill in msg with the opcode & params */
+    BZERO( msg, BRL1_QSIZE );
+    if( (subch = sc_open( &sc, L1_ADDR_LOCAL )) < 0 ) {
+	ROUTER_UNLOCK(path);
+	FAIL;
+    }
+
+    if( (len = sc_construct_msg( &sc, subch, msg, BRL1_QSIZE,
+				 L1_ADDR_TASK_GENERAL,
+				 L1_REQ_SER_NUM, 0 )) < 0 )
+    {
+	ROUTER_UNLOCK(path);
+	sc_close( &sc, subch );
+	FAIL;
+    }
+
+    /* send the request to the L1 */
+    if( sc_command( &sc, subch, msg, msg, &len ) ) {
+	ROUTER_UNLOCK(path);
+	sc_close( &sc, subch );
+	FAIL;
+    }
+
+    /* free up subchannel */
+    ROUTER_UNLOCK(path);
+    sc_close(&sc, subch);
+
+    /* check response */
+    if( sc_interpret_resp( msg, 2, L1_ARG_ASCII, uid_str ) < 0 )
+    {
+	FAIL;
+    }
+
+    *uid = generate_unique_id( uid_str, strlen( uid_str ) );
+
+    return EEP_OK;
+}
+
+int iobrick_uid_get( nasid_t nasid, uint64_t *uid )
+{
+    eeprom_brd_record_t eep;
+    eeprom_board_ia_t board;
+    eeprom_chassis_ia_t chassis;
+    int r;
+
+    eep.board_ia = &board;
+    eep.chassis_ia = &chassis;
+    eep.spd = NULL;
+
+    r = iobrick_eeprom_read( &eep, nasid, IO_BRICK );
+    if( r != EEP_OK ) {
+        *uid = rtc_time();
+        return r;
+    }
+
+    *uid = generate_unique_id( board.serial_num,
+                               board.serial_num_tl & FIELD_LENGTH_MASK );
+
+    return EEP_OK;
+}
+
+
+int ibrick_mac_addr_get( nasid_t nasid, char *eaddr )
+{
+    eeprom_brd_record_t eep;
+    eeprom_board_ia_t board;
+    eeprom_chassis_ia_t chassis;
+    int r;
+    char *tmp;
+
+    eep.board_ia = &board;
+    eep.chassis_ia = &chassis;
+    eep.spd = NULL;
+
+    r = iobrick_eeprom_read( &eep, nasid, IO_BRICK );
+    if( (r != EEP_OK) || (board.mac_addr[0] == '\0') ) {
+	db_printf(( "ibrick_mac_addr_get: "
+		    "Couldn't read MAC address from EEPROM\n" ));
+	return EEP_L1;
+    }
+    else {
+	/* successfully read info area */
+	int ix;
+	tmp = board.mac_addr;
+	for( ix = 0; ix < (board.mac_addr_tl & FIELD_LENGTH_MASK); ix++ )
+	{
+	    *eaddr++ = *tmp++;
+	}
+	*eaddr = '\0';
+    }
+
+    return EEP_OK;
+}
+
+
+/* 
+ * eeprom_vertex_info_set
+ *
+ * Given a vertex handle, a component designation, a starting nasid
+ * and (in the case of a router) a vector path to the component, this
+ * function will read the EEPROM and attach the resulting information
+ * to the vertex in the same string format as that provided by the
+ * Dallas Semiconductor NIC drivers.  If the vertex already has the
+ * string, this function just returns the string.
+ */
+
+extern char *nic_vertex_info_get( devfs_handle_t );
+extern void nic_vmc_check( devfs_handle_t, char * );
+/* the following were lifted from nic.c - change later? */
+#define MAX_INFO 2048
+#define NEWSZ(ptr,sz)   ((ptr) = kern_malloc((sz)))
+#define DEL(ptr) (kern_free((ptr)))
+
+char *eeprom_vertex_info_set( int component, int nasid, devfs_handle_t v,
+                              net_vec_t path )
+{
+        char *info_tmp;
+        int info_len;
+        char *info;
+
+        /* see if this vertex is already marked */
+        info_tmp = nic_vertex_info_get(v);
+        if (info_tmp) return info_tmp;
+
+        /* get a temporary place for the data */
+        NEWSZ(info_tmp, MAX_INFO);
+        if (!info_tmp) return NULL;
+
+        /* read the EEPROM */
+	if( component & R_BRICK ) {
+	    if( RBRICK_EEPROM_STR( info_tmp, nasid, path ) != EEP_OK )
+		return NULL;
+	}
+	else {
+            if( eeprom_str( info_tmp, nasid, component ) != EEP_OK )
+	        return NULL;
+	}
+
+        /* allocate a smaller final place */
+        info_len = strlen(info_tmp)+1;
+        NEWSZ(info, info_len);
+        if (info) {
+                strcpy(info, info_tmp);
+                DEL(info_tmp);
+        } else {
+                info = info_tmp;
+        }
+
+        /* add info to the vertex */
+        hwgraph_info_add_LBL(v, INFO_LBL_NIC,
+                             (arbitrary_info_t) info);
+
+        /* see if someone else got there first */
+        info_tmp = nic_vertex_info_get(v);
+        if (info != info_tmp) {
+            DEL(info);
+            return info_tmp;
+        }
+
+        /* export the data */
+        hwgraph_info_export_LBL(v, INFO_LBL_NIC, info_len);
+
+        /* trigger all matching callbacks */
+        nic_vmc_check(v, info);
+
+        return info;
+}
+
+
+/*********************************************************************
+ *
+ * stubs for use until the Bedrock/L1 link is available
+ *
+ */
+
+#include <asm/sn/nic.h>
+
+/* #define EEPROM_TEST */
+
+/* fake eeprom reading functions (replace when the BR/L1 communication
+ * channel is in working order)
+ */
+
+
+/* generate a charater in [0-9A-Z]; if an "extra" character is
+ * specified (such as '_'), include it as one of the possibilities.
+ */
+char random_eeprom_ch( char extra ) 
+{
+    char ch;
+    int modval = 36;
+    if( extra )
+	modval++;
+    
+    ch = rtc_time() % modval;
+
+    if( ch < 10 )
+        ch += '0';
+    else if( ch >= 10 && ch < 36 )
+	ch += ('A' - 10);
+    else
+	ch = extra;
+
+    return ch;
+}
+
+/* create a part number of the form xxx-xxxx-xxx.
+ * It may be important later to generate different
+ * part numbers depending on the component we're
+ * supposed to be "reading" from, so the component
+ * paramter is provided.
+ */
+void fake_a_part_number( char *buf, int component )
+{
+    int i;
+    switch( component ) {
+
+    /* insert component-specific routines here */
+
+    case C_BRICK:
+	strcpy( buf, "030-1266-001" );
+	break;
+    default:
+        for( i = 0; i < 12; i++ ) {
+	    if( i == 3 || i == 8 )
+	        buf[i] = '-';
+	    else
+	        buf[i] = random_eeprom_ch(0);
+        }
+    }
+}
+
+
+/* create a six-character serial number */
+void fake_a_serial_number( char *buf, uint64_t ser )
+{
+    int i;
+    static const char hexchars[] = "0123456789ABCDEF";
+
+    if (ser) {
+	for( i = 5; i >=0; i-- ) {
+	    buf[i] = hexchars[ser & 0xf];
+	    ser >>= 4;
+	}
+    }
+    else {
+	for( i = 0; i < 6; i++ )
+	    buf[i] = random_eeprom_ch(0);
+    }
+}
+
+
+void fake_a_product_name( uchar_t *format, char* buf, int component )
+{
+    switch( component & BRICK_MASK ) {
+
+    case C_BRICK:
+	if( component & SUBORD_MASK ) {
+	    strcpy( buf, "C_BRICK_SUB" );
+	    *format = 0xCB;
+	}
+	else {
+	    strcpy( buf, "IP35" );
+	    *format = 0xC4;
+	}
+	break;
+
+    case R_BRICK:
+        if( component & SUBORD_MASK ) {
+            strcpy( buf, "R_BRICK_SUB" );
+            *format = 0xCB;
+        }
+        else {
+            strcpy( buf, "R_BRICK" );
+            *format = 0xC7;
+        }
+        break;
+
+    case IO_BRICK:
+        if( component & SUBORD_MASK ) {
+            strcpy( buf, "IO_BRICK_SUB" );
+            *format = 0xCC;
+        }
+        else {
+            strcpy( buf, "IO_BRICK" );
+            *format = 0xC8;
+        }
+        break;
+
+    default:
+	strcpy( buf, "UNK_DEVICE" );
+	*format = 0xCA;
+    }
+}
+
+
+
+int fake_an_eeprom_record( eeprom_brd_record_t *buf, int component, 
+			   uint64_t ser )
+{
+    eeprom_board_ia_t *board;
+    eeprom_chassis_ia_t *chassis;
+    int i, cs;
+
+    board = buf->board_ia;
+    chassis = buf->chassis_ia;
+
+    if( !(component & SUBORD_MASK) ) {
+	if( !chassis )
+	    return EEP_PARAM;
+	chassis->format = 0;
+	chassis->length = 5;
+	chassis->type = 0x17;
+
+	chassis->part_num_tl = 0xCC;
+	fake_a_part_number( chassis->part_num, component );
+	chassis->serial_num_tl = 0xC6;
+	fake_a_serial_number( chassis->serial_num, ser );
+
+	cs = chassis->format + chassis->length + chassis->type
+	    + chassis->part_num_tl + chassis->serial_num_tl;
+	for( i = 0; i < (chassis->part_num_tl & FIELD_LENGTH_MASK); i++ )
+	    cs += chassis->part_num[i];
+	for( i = 0; i < (chassis->serial_num_tl & FIELD_LENGTH_MASK); i++ )
+	    cs += chassis->serial_num[i];
+	chassis->checksum = 256 - (cs % 256);
+    }
+
+    if( !board )
+	return EEP_PARAM;
+    board->format = 0;
+    board->length = 10;
+    board->language = 0;
+    board->mfg_date = 1789200; /* noon, 5/26/99 */
+    board->manuf_tl = 0xC3;
+    strcpy( board->manuf, "SGI" );
+
+    fake_a_product_name( &(board->product_tl), board->product, component );
+
+    board->serial_num_tl = 0xC6;
+    fake_a_serial_number( board->serial_num, ser );
+
+    board->part_num_tl = 0xCC;
+    fake_a_part_number( board->part_num, component );
+
+    board->board_rev_tl = 0xC2;
+    board->board_rev[0] = '0';
+    board->board_rev[1] = '1';
+
+    board->eeprom_size_tl = 0x01;
+    board->eeprom_size = 1;
+
+    board->temp_waiver_tl = 0xC2;
+    board->temp_waiver[0] = '0';
+    board->temp_waiver[1] = '1';
+
+    cs = board->format + board->length + board->language
+	+ (board->mfg_date & 0xFF)
+	+ (board->mfg_date & 0xFF00)
+	+ (board->mfg_date & 0xFF0000)
+	+ board->manuf_tl + board->product_tl + board->serial_num_tl
+	+ board->part_num_tl + board->board_rev_tl
+	+ board->board_rev[0] + board->board_rev[1]
+	+ board->eeprom_size_tl + board->eeprom_size + board->temp_waiver_tl
+	+ board->temp_waiver[0] + board->temp_waiver[1];
+    for( i = 0; i < (board->manuf_tl & FIELD_LENGTH_MASK); i++ )
+	cs += board->manuf[i];
+    for( i = 0; i < (board->product_tl & FIELD_LENGTH_MASK); i++ )
+	cs += board->product[i];
+    for( i = 0; i < (board->serial_num_tl & FIELD_LENGTH_MASK); i++ )
+	cs += board->serial_num[i];
+    for( i = 0; i < (board->part_num_tl & FIELD_LENGTH_MASK); i++ )
+	cs += board->part_num[i];
+    
+    board->checksum = 256 - (cs % 256);
+
+    return EEP_OK;
+}
+
+#define EEPROM_CHUNKSIZE	64
+
+#if defined(EEPROM_DEBUG)
+#define RETURN_ERROR							\
+{									\
+    printk( "read_ia error return, component 0x%x, line %d"		\
+	    ", address 0x%x, ia code 0x%x\n",				\
+	    l1_compt, __LINE__, sc->subch[subch].target, ia_code );	\
+    return EEP_L1;							\
+}
+
+#else
+#define RETURN_ERROR	return(EEP_L1)
+#endif
+
+int read_ia( l1sc_t *sc, int subch, int l1_compt, 
+	     int ia_code, char *eep_record )
+{
+    char msg[BRL1_QSIZE]; 	   /* message buffer */
+    int len;              	   /* number of bytes used in message buffer */
+    int ia_len = EEPROM_CHUNKSIZE; /* remaining bytes in info area */
+    int offset = 0;                /* current offset into info area */
+
+    if ( IS_RUNNING_ON_SIMULATOR() )
+	return EEP_L1;
+
+    BZERO( msg, BRL1_QSIZE );
+
+    /* retrieve EEPROM data in 64-byte chunks
+     */
+
+    while( ia_len )
+    {
+	/* fill in msg with opcode & params */
+	if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE,
+				     L1_ADDR_TASK_GENERAL,
+				     L1_REQ_EEPROM, 8,
+				     L1_ARG_INT, l1_compt,
+				     L1_ARG_INT, ia_code,
+				     L1_ARG_INT, offset,
+				     L1_ARG_INT, ia_len )) < 0 )
+	{
+	    RETURN_ERROR;
+	}
+
+	/* send the request to the L1 */
+
+	if( sc_command( sc, subch, msg, msg, &len ) ) {
+	    RETURN_ERROR;
+	}
+
+	/* check response */
+	if( sc_interpret_resp( msg, 5, 
+			       L1_ARG_INT, &ia_len,
+			       L1_ARG_UNKNOWN, &len, eep_record ) < 0 )
+	{
+	    RETURN_ERROR;
+	}
+
+	if( ia_len > EEPROM_CHUNKSIZE )
+	    ia_len = EEPROM_CHUNKSIZE;
+
+	eep_record += EEPROM_CHUNKSIZE;
+	offset += EEPROM_CHUNKSIZE;
+    }
+
+    return EEP_OK;
+}
+
+
+int read_spd( l1sc_t *sc, int subch, int l1_compt,
+	      eeprom_spd_u *spd )
+{
+    char msg[BRL1_QSIZE]; 	    /* message buffer */
+    int len;              	    /* number of bytes used in message buffer */
+    int resp;                       /* l1 response code */
+    int spd_len = EEPROM_CHUNKSIZE; /* remaining bytes in spd record */
+    int offset = 0;		    /* current offset into spd record */
+    char *spd_p = spd->bytes;	    /* "thumb" for writing to spd */
+
+    if ( IS_RUNNING_ON_SIMULATOR() )
+	return EEP_L1;
+
+    BZERO( msg, BRL1_QSIZE );
+
+    /* retrieve EEPROM data in 64-byte chunks
+     */
+
+    while( spd_len )
+    {
+	/* fill in msg with opcode & params */
+	if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE,
+				     L1_ADDR_TASK_GENERAL,
+				     L1_REQ_EEPROM, 8,
+				     L1_ARG_INT, l1_compt,
+				     L1_ARG_INT, L1_EEP_SPD,
+				     L1_ARG_INT, offset,
+				     L1_ARG_INT, spd_len )) < 0 )
+	{
+	    return( EEP_L1 );
+	}
+
+	/* send the request to the L1 */
+	if( sc_command( sc, subch, msg, msg, &len ) ) {
+	    return( EEP_L1 );
+	}
+
+	/* check response */
+	if( (resp = sc_interpret_resp( msg, 5, 
+			       L1_ARG_INT, &spd_len,
+			       L1_ARG_UNKNOWN, &len, spd_p )) < 0 )
+	{
+            /*
+             * translate l1 response code to eeprom.c error codes:
+             * The L1 response will be L1_RESP_NAVAIL if the spd
+             * can't be read (i.e. the spd isn't physically there). It will
+             * return L1_RESP_INVAL if the spd exists, but fails the checksum
+             * test because the eeprom wasn't programmed, programmed incorrectly,
+             * or corrupted. L1_RESP_NAVAIL indicates the eeprom is likely not present,
+             * whereas L1_RESP_INVAL indicates the eeprom is present, but the data is
+             * invalid.
+             */
+            if(resp == L1_RESP_INVAL) {
+                resp = EEP_BAD_CHECKSUM;
+            } else {
+                resp = EEP_L1;
+            }
+            return( resp );
+	}
+
+	if( spd_len > EEPROM_CHUNKSIZE )
+	    spd_len = EEPROM_CHUNKSIZE;
+
+	spd_p += EEPROM_CHUNKSIZE;
+	offset += EEPROM_CHUNKSIZE;
+    }
+    return EEP_OK;
+}
+
+
+int read_chassis_ia( l1sc_t *sc, int subch, int l1_compt,
+		     eeprom_chassis_ia_t *ia )
+{
+    char eep_record[512];          /* scratch area for building up info area */
+    char *eep_rec_p = eep_record;  /* thumb for moving through eep_record */
+    int checksum = 0;              /* use to verify eeprom record checksum */
+    int i;
+
+    /* Read in info area record from the L1.
+     */
+    if( read_ia( sc, subch, l1_compt, L1_EEP_CHASSIS, eep_record )
+	!= EEP_OK )
+    {
+	return EEP_L1;
+    }
+
+    /* Now we've got the whole info area.  Transfer it to the data structure.
+     */
+
+    eep_rec_p = eep_record;
+    ia->format = *eep_rec_p++;
+    ia->length = *eep_rec_p++;
+    if( ia->length == 0 ) {
+	/* since we're using 8*ia->length-1 as an array index later, make
+	 * sure it's sane.
+	 */
+	db_printf(( "read_chassis_ia: eeprom length byte of ZERO\n" ));
+	return EEP_L1;
+    }
+    ia->type = *eep_rec_p++;
+   
+    ia->part_num_tl = *eep_rec_p++;
+
+    (void)BCOPY( eep_rec_p, ia->part_num, (ia->part_num_tl & FIELD_LENGTH_MASK) );
+    eep_rec_p += (ia->part_num_tl & FIELD_LENGTH_MASK);
+
+    ia->serial_num_tl = *eep_rec_p++;
+
+    BCOPY( eep_rec_p, ia->serial_num, 
+	   (ia->serial_num_tl & FIELD_LENGTH_MASK) );
+    eep_rec_p += (ia->serial_num_tl & FIELD_LENGTH_MASK);
+
+    ia->checksum = eep_record[(8 * ia->length) - 1];
+
+    /* verify checksum */
+    eep_rec_p = eep_record;
+    checksum = 0;
+    for( i = 0; i < (8 * ia->length); i++ ) {
+	checksum += *eep_rec_p++;
+    }
+
+    if( (checksum & 0xff) != 0 )
+    {
+	db_printf(( "read_chassis_ia: bad checksum\n" ));
+	db_printf(( "read_chassis_ia: target 0x%x  uart 0x%lx\n",
+			   sc->subch[subch].target, sc->uart ));
+	return EEP_BAD_CHECKSUM;
+    }
+
+    return EEP_OK;
+}
+
+
+int read_board_ia( l1sc_t *sc, int subch, int l1_compt,
+		   eeprom_board_ia_t *ia )
+{
+    char eep_record[512];          /* scratch area for building up info area */
+    char *eep_rec_p = eep_record;  /* thumb for moving through eep_record */
+    int checksum = 0;              /* running checksum total */
+    int i;
+
+    BZERO( ia, sizeof( eeprom_board_ia_t ) );
+
+    /* Read in info area record from the L1.
+     */
+    if( read_ia( sc, subch, l1_compt, L1_EEP_BOARD, eep_record )
+	!= EEP_OK )
+    {
+	db_printf(( "read_board_ia: error reading info area from L1\n" ));
+	return EEP_L1;
+    }
+
+     /* Now we've got the whole info area.  Transfer it to the data structure.
+      */
+
+    eep_rec_p = eep_record;
+    ia->format = *eep_rec_p++;
+    ia->length = *eep_rec_p++;
+    if( ia->length == 0 ) {
+	/* since we're using 8*ia->length-1 as an array index later, make
+	 * sure it's sane.
+	 */
+	db_printf(( "read_board_ia: eeprom length byte of ZERO\n" ));
+	return EEP_L1;
+    }
+    ia->language = *eep_rec_p++;
+    
+    ia->mfg_date = eeprom_xlate_board_mfr_date( (uchar_t *)eep_rec_p );
+    eep_rec_p += 3;
+
+    ia->manuf_tl = *eep_rec_p++;
+    
+    BCOPY( eep_rec_p, ia->manuf, (ia->manuf_tl & FIELD_LENGTH_MASK) );
+    eep_rec_p += (ia->manuf_tl & FIELD_LENGTH_MASK);
+
+    ia->product_tl = *eep_rec_p++;
+    
+    BCOPY( eep_rec_p, ia->product, (ia->product_tl & FIELD_LENGTH_MASK) );
+    eep_rec_p += (ia->product_tl & FIELD_LENGTH_MASK);
+
+    ia->serial_num_tl = *eep_rec_p++;
+    
+    BCOPY(eep_rec_p, ia->serial_num, (ia->serial_num_tl & FIELD_LENGTH_MASK));
+    eep_rec_p += (ia->serial_num_tl & FIELD_LENGTH_MASK);
+
+    ia->part_num_tl = *eep_rec_p++;
+
+    BCOPY( eep_rec_p, ia->part_num, (ia->part_num_tl & FIELD_LENGTH_MASK) );
+    eep_rec_p += (ia->part_num_tl & FIELD_LENGTH_MASK);
+
+    eep_rec_p++; /* we do not use the FRU file id */
+    
+    ia->board_rev_tl = *eep_rec_p++;
+    
+    BCOPY( eep_rec_p, ia->board_rev, (ia->board_rev_tl & FIELD_LENGTH_MASK) );
+    eep_rec_p += (ia->board_rev_tl & FIELD_LENGTH_MASK);
+
+    ia->eeprom_size_tl = *eep_rec_p++;
+    ia->eeprom_size = *eep_rec_p++;
+
+    ia->temp_waiver_tl = *eep_rec_p++;
+    
+    BCOPY( eep_rec_p, ia->temp_waiver, 
+	   (ia->temp_waiver_tl & FIELD_LENGTH_MASK) );
+    eep_rec_p += (ia->temp_waiver_tl & FIELD_LENGTH_MASK);
+
+    /* if there's more, we must be reading a main board; get
+     * additional fields
+     */
+    if( ((unsigned char)*eep_rec_p != (unsigned char)EEPROM_EOF) ) {
+
+	ia->ekey_G_tl = *eep_rec_p++;
+	BCOPY( eep_rec_p, (char *)&ia->ekey_G, 
+	       ia->ekey_G_tl & FIELD_LENGTH_MASK );
+	eep_rec_p += (ia->ekey_G_tl & FIELD_LENGTH_MASK);
+	
+	ia->ekey_P_tl = *eep_rec_p++;
+	BCOPY( eep_rec_p, (char *)&ia->ekey_P, 
+	       ia->ekey_P_tl & FIELD_LENGTH_MASK );
+	eep_rec_p += (ia->ekey_P_tl & FIELD_LENGTH_MASK);
+	
+	ia->ekey_Y_tl = *eep_rec_p++;
+	BCOPY( eep_rec_p, (char *)&ia->ekey_Y, 
+	       ia->ekey_Y_tl & FIELD_LENGTH_MASK );
+	eep_rec_p += (ia->ekey_Y_tl & FIELD_LENGTH_MASK);
+	
+	/* 
+	 * need to get a couple more fields if this is an I brick 
+	 */
+	if( ((unsigned char)*eep_rec_p != (unsigned char)EEPROM_EOF) ) {
+
+	    ia->mac_addr_tl = *eep_rec_p++;
+	    BCOPY( eep_rec_p, ia->mac_addr, 
+		   ia->mac_addr_tl & FIELD_LENGTH_MASK );
+	    eep_rec_p += (ia->mac_addr_tl & FIELD_LENGTH_MASK);
+	    
+	    ia->ieee1394_cfg_tl = *eep_rec_p++;
+	    BCOPY( eep_rec_p, ia->ieee1394_cfg,
+		   ia->ieee1394_cfg_tl & FIELD_LENGTH_MASK );
+	    
+	}
+    }
+
+    ia->checksum = eep_record[(ia->length * 8) - 1];
+
+    /* verify checksum */
+    eep_rec_p = eep_record;
+    checksum = 0;
+    for( i = 0; i < (8 * ia->length); i++ ) {
+	checksum += *eep_rec_p++;
+    }
+
+    if( (checksum & 0xff) != 0 )
+    {
+	db_printf(( "read_board_ia: bad checksum\n" ));
+	db_printf(( "read_board_ia: target 0x%x  uart 0x%lx\n",
+		    sc->subch[subch].target, sc->uart ));
+	return EEP_BAD_CHECKSUM;
+    }
+
+    return EEP_OK;
+}
+
+
+int _cbrick_eeprom_read( eeprom_brd_record_t *buf, l1sc_t *scp,
+			 int component )
+{
+    int r;
+    uint64_t uid = 0;
+#ifdef LOG_GETENV
+    char uid_str[32];
+#endif
+    int l1_compt, subch;
+
+    if ( IS_RUNNING_ON_SIMULATOR() )
+	return EEP_L1;
+
+    /* make sure we're targeting a cbrick */
+    if( !(component & C_BRICK) )
+	return EEP_PARAM;
+
+    /* If the promlog variable pointed to by IP27LOG_OVNIC is set,
+     * use that value for the cbrick UID rather than the EEPROM
+     * serial number.
+     */
+#ifdef LOG_GETENV
+    if( ip27log_getenv( scp->nasid, IP27LOG_OVNIC, uid_str, "0", 0 ) >= 0 )
+    {
+	db_printf(( "_cbrick_eeprom_read: "
+		    "Overriding UID with environment variable %s\n", 
+		    IP27LOG_OVNIC ));
+	uid = strtoull( uid_str, NULL, 0 );
+    }
+#endif
+
+    if( (subch = sc_open( scp, L1_ADDR_LOCAL )) < 0 )
+	return EEP_L1;
+
+    if((component & C_DIMM) == C_DIMM) {
+        l1_compt = L1_EEP_DIMM(component & COMPT_MASK);
+        r = read_spd(scp,subch,l1_compt, buf->spd);
+        sc_close(scp,subch);
+        return(r);
+    }
+
+    switch( component )
+    {
+      case C_BRICK:
+	/* c-brick motherboard */
+	l1_compt = L1_EEP_NODE;
+	r = read_chassis_ia( scp, subch, l1_compt, buf->chassis_ia );
+	if( r != EEP_OK ) {
+	    sc_close( scp, subch );
+	    db_printf(( "_cbrick_eeprom_read: using a fake eeprom record\n" ));
+	    return fake_an_eeprom_record( buf, component, uid );
+	}
+	if( uid ) {
+	    /* If IP27LOG_OVNIC is set, we want to put that value
+	     * in as our UID. */
+	    fake_a_serial_number( buf->chassis_ia->serial_num, uid );
+	    buf->chassis_ia->serial_num_tl = 6;
+	}
+	break;
+
+      case C_PIMM:
+	/* one of the PIMM boards */
+	l1_compt = L1_EEP_PIMM( component & COMPT_MASK );
+	break;
+
+      default:
+	/* unsupported board type */
+	sc_close( scp, subch );
+	return EEP_PARAM;
+    }
+	      
+    r = read_board_ia( scp, subch, l1_compt, buf->board_ia );
+    sc_close( scp, subch );
+    if( r != EEP_OK ) 
+    {
+	db_printf(( "_cbrick_eeprom_read: using a fake eeprom record\n" ));
+	return fake_an_eeprom_record( buf, component, uid );
+    }
+    return EEP_OK;
+}
+
+
+int cbrick_eeprom_read( eeprom_brd_record_t *buf, nasid_t nasid,
+    		        int component )
+{
+    l1sc_t *scp;
+    int local = (nasid == get_nasid());
+
+    if ( IS_RUNNING_ON_SIMULATOR() )
+	return EEP_L1;
+
+    /* If this brick is retrieving its own uid, use the local l1sc_t to
+     * arbitrate access to the l1; otherwise, set up a new one (prom) or
+     * use an existing remote l1sc_t (kernel)
+     */
+    if( local ) {
+	scp = get_l1sc();
+    }
+    else {
+	scp = &NODEPDA( NASID_TO_COMPACT_NODEID(nasid) )->module->elsc;
+    }
+
+    return _cbrick_eeprom_read( buf, scp, component );
+}
+
+
+int iobrick_eeprom_read( eeprom_brd_record_t *buf, nasid_t nasid,
+			 int component )
+{
+    int r;
+    int l1_compt, subch;
+    l1sc_t *scp;
+    int local = (nasid == get_nasid());
+
+    if ( IS_RUNNING_ON_SIMULATOR() )
+	return EEP_L1;
+
+    /* make sure we're talking to an applicable brick */
+    if( !(component & IO_BRICK) ) {
+	return EEP_PARAM;
+    }
+
+    /* If we're talking to this c-brick's attached io brick, use
+     * the local l1sc_t; otherwise, set up a new one (prom) or
+     * use an existing remote l1sc_t (kernel)
+     */
+    if( local ) {
+	scp = get_l1sc();
+    }
+    else {
+	scp = &NODEPDA( NASID_TO_COMPACT_NODEID(nasid) )->module->elsc;
+    }
+
+    if( (subch = sc_open( scp, L1_ADDR_LOCALIO )) < 0 )
+	return EEP_L1;
+
+
+    switch( component )
+    {
+      case IO_BRICK:
+	/* IO brick motherboard */
+	l1_compt = L1_EEP_LOGIC;
+	r = read_chassis_ia( scp, subch, l1_compt, buf->chassis_ia );
+
+	if( r != EEP_OK ) {
+	    sc_close( scp, subch );
+	/*
+	 * Whenever we no longer need to test on hardware
+	 * that does not have EEPROMS, then this can be removed.
+	 */
+	    r = fake_an_eeprom_record( buf, component, rtc_time() );
+	    return r;
+	}
+	break;
+
+      case IO_POWER:
+	/* IO brick power board */
+	l1_compt = L1_EEP_POWER;
+	break;
+
+      default:
+	/* unsupported board type */
+	sc_close( scp, subch );
+	return EEP_PARAM;
+    }
+
+    r = read_board_ia( scp, subch, l1_compt, buf->board_ia );
+    sc_close( scp, subch );
+    if( r != EEP_OK ) {
+	return r;
+    }
+    return EEP_OK;
+}
+
+
+int vector_eeprom_read( eeprom_brd_record_t *buf, nasid_t nasid,
+			net_vec_t path, int component )
+{
+    int r;
+    uint64_t uid = 0;
+    int l1_compt, subch;
+    l1sc_t sc;
+
+    if ( IS_RUNNING_ON_SIMULATOR() )
+	return EEP_L1;
+
+    /* make sure we're targeting an applicable brick */
+    if( !(component & VECTOR) )
+	return EEP_PARAM;
+
+    switch( component & BRICK_MASK )
+    {
+      case R_BRICK:
+	ROUTER_LOCK( path );
+	sc_init( &sc, nasid, path );
+
+	if( (subch = sc_open( &sc, L1_ADDR_LOCAL )) < 0 )
+	{
+	    db_printf(( "vector_eeprom_read: couldn't open subch\n" ));
+	    ROUTER_UNLOCK(path);
+	    return EEP_L1;
+	}
+	switch( component )
+	{
+	  case R_BRICK:
+	    /* r-brick motherboard */
+	    l1_compt = L1_EEP_LOGIC;
+    	    r = read_chassis_ia( &sc, subch, l1_compt, buf->chassis_ia );
+	    if( r != EEP_OK ) {
+		sc_close( &sc, subch );
+		ROUTER_UNLOCK( path );
+		printk( "vector_eeprom_read: couldn't get rbrick eeprom info;"
+			" using current time as uid\n" );
+		uid = rtc_time();
+		db_printf(("vector_eeprom_read: using a fake eeprom record\n"));
+		return fake_an_eeprom_record( buf, component, uid );
+	    }
+	    break;
+
+	  case R_POWER:
+	    /* r-brick power board */
+	    l1_compt = L1_EEP_POWER;
+	    break;
+
+	  default:
+	    /* unsupported board type */
+	    sc_close( &sc, subch );
+	    ROUTER_UNLOCK( path );
+	    return EEP_PARAM;
+	}
+	r = read_board_ia( &sc, subch, l1_compt, buf->board_ia );
+	sc_close( &sc, subch );
+	ROUTER_UNLOCK( path );
+	if( r != EEP_OK ) {
+	    db_printf(( "vector_eeprom_read: using a fake eeprom record\n" ));
+	    return fake_an_eeprom_record( buf, component, uid );
+	}
+	return EEP_OK;
+
+      case C_BRICK:
+	sc_init( &sc, nasid, path );
+	return _cbrick_eeprom_read( buf, &sc, component );
+
+      default:
+	/* unsupported brick type */
+	return EEP_PARAM;
+    }
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn1/efi-rtc.c linux-2.4.21-pre6/arch/ia64/sn/io/sn1/efi-rtc.c
--- linux-2.4.20/arch/ia64/sn/io/sn1/efi-rtc.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn1/efi-rtc.c	2003-03-26 23:49:54.000000000 +0000
@@ -0,0 +1,202 @@
+/*
+ * 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) 2001-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (C) 2001 by Ralf Baechle
+ */
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/errno.h>
+#include <linux/efi.h>
+#include <asm/sn/klclock.h>
+
+/*
+ * No locking necessary when this is called from efirtc which protects us
+ * from racing by efi_rtc_lock.
+ */
+#define __swizzle(addr) ((u8 *)((unsigned long)(addr) ^ 3))
+#define read_io_port(addr) (*(volatile u8 *) __swizzle(addr))
+#define write_io_port(addr, data) (*(volatile u8 *) __swizzle(addr) = (data))
+
+#define TOD_SGS_M48T35		1
+#define TOD_DALLAS_DS1386	2
+
+#define TYPE_IOC3		1
+#define TYPE_IOC4		2
+
+static unsigned long nvram_base = 0;
+static int tod_chip_type;
+static int ioc_type;
+
+static int
+get_tod_chip_type(void)
+{
+	unsigned char testval;
+
+	write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_DISABLE);
+	write_io_port(RTC_DAL_DAY_ADDR, 0xff);
+	write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_ENABLE);
+
+	testval = read_io_port(RTC_DAL_DAY_ADDR);
+	if (testval == 0xff)
+		return TOD_SGS_M48T35;
+
+	return TOD_DALLAS_DS1386;
+}
+
+efi_status_t
+ioc3_get_time(efi_time_t *time, efi_time_cap_t *caps)
+{
+	if (!nvram_base) {
+		printk(KERN_CRIT "nvram_base is zero\n");
+		return EFI_UNSUPPORTED;
+	}
+
+	memset(time, 0, sizeof(*time));
+
+	switch (tod_chip_type) {
+	case TOD_SGS_M48T35:
+		write_io_port(RTC_SGS_CONTROL_ADDR, RTC_SGS_READ_PROTECT);
+
+		time->year = BCD_TO_INT(read_io_port(RTC_SGS_YEAR_ADDR)) + YRREF;
+		time->month = BCD_TO_INT(read_io_port(RTC_SGS_MONTH_ADDR));
+		time->day = BCD_TO_INT(read_io_port(RTC_SGS_DATE_ADDR));
+		time->hour = BCD_TO_INT(read_io_port(RTC_SGS_HOUR_ADDR));
+		time->minute = BCD_TO_INT(read_io_port(RTC_SGS_MIN_ADDR));
+		time->second = BCD_TO_INT(read_io_port(RTC_SGS_SEC_ADDR));
+		time->nanosecond = 0;
+
+		write_io_port(RTC_SGS_CONTROL_ADDR, 0);
+		break;
+
+	case TOD_DALLAS_DS1386:
+		write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_DISABLE);
+
+		time->nanosecond = 0;
+		time->second = BCD_TO_INT(read_io_port(RTC_DAL_SEC_ADDR));
+		time->minute = BCD_TO_INT(read_io_port(RTC_DAL_MIN_ADDR));
+		time->hour = BCD_TO_INT(read_io_port(RTC_DAL_HOUR_ADDR));
+		time->day = BCD_TO_INT(read_io_port(RTC_DAL_DATE_ADDR));
+		time->month = BCD_TO_INT(read_io_port(RTC_DAL_MONTH_ADDR));
+		time->year = BCD_TO_INT(read_io_port(RTC_DAL_YEAR_ADDR)) + YRREF;
+
+		write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_ENABLE);
+		break;
+
+	default:
+		break;
+	}
+
+	if (caps) {
+		caps->resolution = 50000000;	/*  50PPM */
+		caps->accuracy = 1000;		/*  1ms */
+		caps->sets_to_zero = 0;
+	}
+
+	return EFI_SUCCESS;
+}
+
+static efi_status_t ioc3_set_time (efi_time_t *t)
+{
+	if (!nvram_base) {
+		printk(KERN_CRIT "nvram_base is zero\n");
+		return EFI_UNSUPPORTED;
+	}
+
+	switch (tod_chip_type) {
+	case TOD_SGS_M48T35:
+		write_io_port(RTC_SGS_CONTROL_ADDR, RTC_SGS_WRITE_ENABLE);
+        	write_io_port(RTC_SGS_YEAR_ADDR, INT_TO_BCD((t->year - YRREF)));
+		write_io_port(RTC_SGS_MONTH_ADDR,INT_TO_BCD(t->month));
+		write_io_port(RTC_SGS_DATE_ADDR, INT_TO_BCD(t->day));
+		write_io_port(RTC_SGS_HOUR_ADDR, INT_TO_BCD(t->hour));
+		write_io_port(RTC_SGS_MIN_ADDR,  INT_TO_BCD(t->minute));
+		write_io_port(RTC_SGS_SEC_ADDR,  INT_TO_BCD(t->second));
+		write_io_port(RTC_SGS_CONTROL_ADDR, 0);
+		break;
+
+	case TOD_DALLAS_DS1386:
+		write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_DISABLE);
+		write_io_port(RTC_DAL_SEC_ADDR,  INT_TO_BCD(t->second));
+		write_io_port(RTC_DAL_MIN_ADDR,  INT_TO_BCD(t->minute));
+		write_io_port(RTC_DAL_HOUR_ADDR, INT_TO_BCD(t->hour));
+		write_io_port(RTC_DAL_DATE_ADDR, INT_TO_BCD(t->day));
+		write_io_port(RTC_DAL_MONTH_ADDR,INT_TO_BCD(t->month));
+		write_io_port(RTC_DAL_YEAR_ADDR, INT_TO_BCD((t->year - YRREF)));
+		write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_ENABLE);
+		break;
+
+	default:
+		break;
+	}
+
+	return EFI_SUCCESS;
+}
+
+/* The following two are not supported atm.  */
+static efi_status_t
+ioc3_get_wakeup_time (efi_bool_t *enabled, efi_bool_t *pending, efi_time_t *tm)
+{
+	return EFI_UNSUPPORTED;
+}
+
+static efi_status_t
+ioc3_set_wakeup_time (efi_bool_t enabled, efi_time_t *tm)
+{
+	return EFI_UNSUPPORTED;
+}
+
+static __init int efi_ioc_time_init(void)
+{
+	struct pci_dev *dev = NULL;
+	static void *ioc_base;
+
+        while ( (dev = pci_find_subsys(PCI_VENDOR_ID_SGI,
+                               PCI_ANY_ID,
+                               PCI_ANY_ID,
+                               PCI_ANY_ID, dev))) {
+		if ( dev->device == PCI_DEVICE_ID_SGI_IOC3 ) {
+			ioc_type = TYPE_IOC3;
+			break;
+		}
+		else if ( dev->device == PCI_DEVICE_ID_SGI_IOC4 ) {
+			ioc_type = TYPE_IOC4;
+			break;
+		}
+		else
+			;; // keep looking
+	}
+
+	if ( !dev ) {
+		printk(KERN_CRIT "Couldn't find master IOC\n");
+		return -ENODEV;
+	}
+
+	ioc_base = ioremap(pci_resource_start(dev, 0), pci_resource_len(dev, 0));
+	if ( ioc_type == TYPE_IOC3 )
+		nvram_base = (unsigned long) ioc_base + IOC3_BYTEBUS_DEV0;
+	if ( ioc_type == TYPE_IOC4 )
+		nvram_base = (unsigned long) ioc_base + IOC4_BYTEBUS_DEV0;
+
+	tod_chip_type = get_tod_chip_type();
+	if (tod_chip_type == 1)
+		printk(KERN_NOTICE "TOD type is SGS M48T35\n");
+	else if (tod_chip_type == 2)
+		printk(KERN_NOTICE "TOD type is Dallas DS1386\n");
+	else
+		printk(KERN_CRIT "No or unknown TOD\n");
+
+	efi.get_time = ioc3_get_time;
+	efi.set_time = ioc3_set_time;
+	efi.get_wakeup_time = ioc3_get_wakeup_time;
+	efi.set_wakeup_time = ioc3_set_wakeup_time;
+
+	return 0;
+}
+
+module_init(efi_ioc_time_init);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn1/hubcounters.c linux-2.4.21-pre6/arch/ia64/sn/io/sn1/hubcounters.c
--- linux-2.4.20/arch/ia64/sn/io/sn1/hubcounters.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn1/hubcounters.c	2003-03-26 23:49:10.000000000 +0000
@@ -4,8 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000 - 2001 Silicon Graphics, Inc.
- * All rights reserved.
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All Rights Reserved.
  */
 #include <linux/kernel.h>
 #include <linux/slab.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn1/klconflib.c linux-2.4.21-pre6/arch/ia64/sn/io/sn1/klconflib.c
--- linux-2.4.20/arch/ia64/sn/io/sn1/klconflib.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn1/klconflib.c	2003-03-26 23:49:34.000000000 +0000
@@ -0,0 +1,979 @@
+/* $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) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+
+#include <linux/types.h>
+#include <linux/ctype.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/io.h>
+#include <asm/sn/sn_cpuid.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/klconfig.h>
+#include <asm/sn/nodepda.h>
+#include <asm/sn/module.h>
+#include <asm/sn/router.h>
+#include <asm/sn/xtalk/xbow.h>
+
+#define printf printk
+int hasmetarouter;
+
+#define LDEBUG 0
+#define NIC_UNKNOWN ((nic_t) -1)
+
+#undef DEBUG_KLGRAPH
+#ifdef DEBUG_KLGRAPH
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif /* DEBUG_KLGRAPH */
+
+static void sort_nic_names(lboard_t *) ;
+
+u64 klgraph_addr[MAX_COMPACT_NODES];
+int module_number = 0;
+
+lboard_t *
+find_lboard(lboard_t *start, unsigned char brd_type)
+{
+	/* Search all boards stored on this node. */
+	while (start) {
+		if (start->brd_type == brd_type)
+			return start;
+		start = KLCF_NEXT(start);
+	}
+
+	/* Didn't find it. */
+	return (lboard_t *)NULL;
+}
+
+lboard_t *
+find_lboard_class(lboard_t *start, unsigned char brd_type)
+{
+	/* Search all boards stored on this node. */
+	while (start) {
+		if (KLCLASS(start->brd_type) == KLCLASS(brd_type))
+			return start;
+		start = KLCF_NEXT(start);
+	}
+
+	/* Didn't find it. */
+	return (lboard_t *)NULL;
+}
+
+klinfo_t *
+find_component(lboard_t *brd, klinfo_t *kli, unsigned char struct_type)
+{
+	int index, j;
+
+	if (kli == (klinfo_t *)NULL) {
+		index = 0;
+	} else {
+		for (j = 0; j < KLCF_NUM_COMPS(brd); j++) {
+			if (kli == KLCF_COMP(brd, j))
+				break;
+		}
+		index = j;
+		if (index == KLCF_NUM_COMPS(brd)) {
+			DBG("find_component: Bad pointer: 0x%p\n", kli);
+			return (klinfo_t *)NULL;
+		}
+		index++;	/* next component */
+	}
+	
+	for (; index < KLCF_NUM_COMPS(brd); index++) {		
+		kli = KLCF_COMP(brd, index);
+		DBG("find_component: brd %p kli %p  request type = 0x%x kli type 0x%x\n", brd, kli, kli->struct_type, KLCF_COMP_TYPE(kli));
+		if (KLCF_COMP_TYPE(kli) == struct_type)
+			return kli;
+	}
+
+	/* Didn't find it. */
+	return (klinfo_t *)NULL;
+}
+
+klinfo_t *
+find_first_component(lboard_t *brd, unsigned char struct_type)
+{
+	return find_component(brd, (klinfo_t *)NULL, struct_type);
+}
+
+lboard_t *
+find_lboard_modslot(lboard_t *start, moduleid_t mod, slotid_t slot)
+{
+	/* Search all boards stored on this node. */
+	while (start) {
+		if (MODULE_MATCH(start->brd_module, mod) &&
+		    (start->brd_slot == slot))
+			return start;
+		start = KLCF_NEXT(start);
+	}
+
+	/* Didn't find it. */
+	return (lboard_t *)NULL;
+}
+
+lboard_t *
+find_lboard_module(lboard_t *start, moduleid_t mod)
+{
+        /* Search all boards stored on this node. */
+        while (start) {
+                if (MODULE_MATCH(start->brd_module, mod))
+                        return start;
+                start = KLCF_NEXT(start);
+        }
+
+        /* Didn't find it. */
+        return (lboard_t *)NULL;
+}
+
+lboard_t *
+find_lboard_module_class(lboard_t *start, moduleid_t mod,
+                                                unsigned char brd_type)
+{
+	while (start) {
+		DBG("find_lboard_module_class: lboard 0x%p, start->brd_module 0x%x, mod 0x%x, start->brd_type 0x%x, brd_type 0x%x\n", start, start->brd_module, mod, start->brd_type, brd_type);
+
+		if (MODULE_MATCH(start->brd_module, mod) &&
+			(KLCLASS(start->brd_type) == KLCLASS(brd_type)))
+			return start;
+		start = KLCF_NEXT(start);
+	}
+
+	/* Didn't find it. */
+	return (lboard_t *)NULL;
+}
+
+
+/*
+ * Convert a NIC name to a name for use in the hardware graph.
+ */
+void
+nic_name_convert(char *old_name, char *new_name)
+{
+        int i;
+        char c;
+        char *compare_ptr;
+
+	if ((old_name[0] == '\0') || (old_name[1] == '\0')) {
+                strcpy(new_name, EDGE_LBL_XWIDGET);
+        } else {
+                for (i = 0; i < strlen(old_name); i++) {
+                        c = old_name[i];
+
+                        if (isalpha(c))
+                                new_name[i] = tolower(c);
+                        else if (isdigit(c))
+                                new_name[i] = c;
+                        else
+                                new_name[i] = '_';
+                }
+                new_name[i] = '\0';
+        }
+
+        /* XXX -
+         * Since a bunch of boards made it out with weird names like
+         * IO6-fibbbed and IO6P2, we need to look for IO6 in a name and
+         * replace it with "baseio" to avoid confusion in the field.
+	 * We also have to make sure we don't report media_io instead of
+	 * baseio.
+         */
+
+        /* Skip underscores at the beginning of the name */
+        for (compare_ptr = new_name; (*compare_ptr) == '_'; compare_ptr++)
+                ;
+
+	/*
+	 * Check for some names we need to replace.  Early boards
+	 * had junk following the name so check only the first
+	 * characters.
+	 */
+        if (!strncmp(new_name, "io6", 3) || 
+            !strncmp(new_name, "mio", 3) || 
+	    !strncmp(new_name, "media_io", 8))
+		strcpy(new_name, "baseio");
+	else if (!strncmp(new_name, "divo", 4))
+		strcpy(new_name, "divo") ;
+
+}
+
+/* Check if the given board corresponds to the global 
+ * master io6
+ */
+int
+is_master_baseio(nasid_t nasid,moduleid_t module,slotid_t slot)
+{
+	lboard_t	*board;
+
+/* If this works then look for callers of is_master_baseio()
+ * (e.g. iograph.c) and let them pass in a slot if they want
+ */
+	board = find_lboard_module((lboard_t *)KL_CONFIG_INFO(nasid), module);
+
+#ifndef _STANDALONE
+	{
+		cnodeid_t cnode = NASID_TO_COMPACT_NODEID(nasid);
+
+		if (!board && (NODEPDA(cnode)->xbow_peer != INVALID_NASID))
+			board = find_lboard_module((lboard_t *)
+				    KL_CONFIG_INFO(NODEPDA(cnode)->xbow_peer),
+				    module);
+	}
+#endif
+	if (!board)
+		return(0);
+	return(board->brd_flags & GLOBAL_MASTER_IO6);
+}
+/*
+ * Find the lboard structure and get the board name.
+ * If we can't find the structure or it's too low a revision,
+ * use default name.
+ */
+lboard_t *
+get_board_name(nasid_t nasid, moduleid_t mod, slotid_t slot, char *name)
+{
+	lboard_t *brd;
+
+	brd = find_lboard_modslot((lboard_t *)KL_CONFIG_INFO(nasid),
+				  mod, slot);
+
+#ifndef _STANDALONE
+	{
+		cnodeid_t cnode = NASID_TO_COMPACT_NODEID(nasid);
+
+		if (!brd && (NODEPDA(cnode)->xbow_peer != INVALID_NASID))
+			brd = find_lboard_modslot((lboard_t *)
+				KL_CONFIG_INFO(NODEPDA(cnode)->xbow_peer),
+				mod, slot);
+	}
+#endif
+
+	if (!brd || (brd->brd_sversion < 2)) {
+		strcpy(name, EDGE_LBL_XWIDGET);
+	} else {
+		nic_name_convert(brd->brd_name, name);
+	}
+
+	/*
+ 	 * PV # 540860
+	 * If the name is not 'baseio' 
+	 * get the lowest of all the names in the nic string.
+	 * This is needed for boards like divo, which can have
+	 * a bunch of daughter cards, but would like to be called
+	 * divo. We could do this for baseio 
+ 	 * but it has some special case names that we would not
+ 	 * like to disturb at this point.
+	 */
+
+	/* gfx boards don't need any of this name scrambling */
+	if (brd && (KLCLASS(brd->brd_type) == KLCLASS_GFX)) {
+		return(brd);
+	}
+
+	if (!(!strcmp(name, "baseio") )) {
+		if (brd) {
+			sort_nic_names(brd) ;
+			/* Convert to small case, '-' to '_' etc */
+			nic_name_convert(brd->brd_name, name) ;
+		}
+	}
+
+	return(brd);
+}
+
+/*
+ * get_actual_nasid
+ *
+ *	Completely disabled brds have their klconfig on 
+ *	some other nasid as they have no memory. But their
+ *	actual nasid is hidden in the klconfig. Use this
+ *	routine to get it. Works for normal boards too.
+ */
+nasid_t
+get_actual_nasid(lboard_t *brd)
+{
+	klhub_t	*hub ;
+
+	if (!brd)
+		return INVALID_NASID ;
+
+	/* find out if we are a completely disabled brd. */
+
+        hub  = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB);
+	if (!hub)
+                return INVALID_NASID ;
+	if (!(hub->hub_info.flags & KLINFO_ENABLE))	/* disabled node brd */
+		return hub->hub_info.physid ;
+	else
+		return brd->brd_nasid ;
+}
+
+int
+xbow_port_io_enabled(nasid_t nasid, int link)
+{
+	lboard_t *brd;
+	klxbow_t *xbow_p;
+
+	/*
+	 * look for boards that might contain an xbow or xbridge
+	 */
+	brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IOBRICK_XBOW);
+	if (brd == NULL) return 0;
+		
+	if ((xbow_p = (klxbow_t *)find_component(brd, NULL, KLSTRUCT_XBOW))
+	    == NULL)
+	    return 0;
+
+	if (!XBOW_PORT_TYPE_IO(xbow_p, link) || !XBOW_PORT_IS_ENABLED(xbow_p, link))
+	    return 0;
+
+	return 1;
+}
+
+void
+board_to_path(lboard_t *brd, char *path)
+{
+	moduleid_t modnum;
+	char *board_name;
+
+	ASSERT(brd);
+
+	switch (KLCLASS(brd->brd_type)) {
+
+		case KLCLASS_NODE:
+			board_name = EDGE_LBL_NODE;
+			break;
+		case KLCLASS_ROUTER:
+			if (brd->brd_type == KLTYPE_META_ROUTER) {
+				board_name = EDGE_LBL_META_ROUTER;
+				hasmetarouter++;
+			} else if (brd->brd_type == KLTYPE_REPEATER_ROUTER) {
+				board_name = EDGE_LBL_REPEATER_ROUTER;
+				hasmetarouter++;
+			} else
+				board_name = EDGE_LBL_ROUTER;
+			break;
+		case KLCLASS_MIDPLANE:
+			board_name = EDGE_LBL_MIDPLANE;
+			break;
+		case KLCLASS_IO:
+			board_name = EDGE_LBL_IO;
+			break;
+		case KLCLASS_IOBRICK:
+			if (brd->brd_type == KLTYPE_PBRICK)
+				board_name = EDGE_LBL_PBRICK;
+			else if (brd->brd_type == KLTYPE_IBRICK)
+				board_name = EDGE_LBL_IBRICK;
+			else if (brd->brd_type == KLTYPE_XBRICK)
+				board_name = EDGE_LBL_XBRICK;
+			else
+				board_name = EDGE_LBL_IOBRICK;
+			break;
+		default:
+			board_name = EDGE_LBL_UNKNOWN;
+	}
+			
+	modnum = brd->brd_module;
+
+	/* ASSERT(modnum != MODULE_UNKNOWN && modnum != INVALID_MODULE); */
+if ((modnum == MODULE_UNKNOWN) || (modnum == INVALID_MODULE)) {
+	modnum = ++module_number;
+}
+#ifdef __ia64
+	{
+		char	buffer[16];
+		memset(buffer, 0, 16);
+		format_module_id(buffer, modnum, MODULE_FORMAT_BRIEF);
+		sprintf(path, EDGE_LBL_MODULE "/%s/%s", buffer, board_name);
+	}
+#else
+	sprintf(path, "%H/%s", modnum, board_name);
+#endif
+}
+
+/*
+ * Get the module number for a NASID.
+ */
+moduleid_t
+get_module_id(nasid_t nasid)
+{
+	lboard_t *brd;
+
+	brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA);
+
+	if (!brd)
+		return INVALID_MODULE;
+	else
+		return brd->brd_module;
+}
+
+
+#define MHZ	1000000
+
+
+/* Get the canonical hardware graph name for the given pci component
+ * on the given io board.
+ */
+void
+device_component_canonical_name_get(lboard_t 	*brd,
+				    klinfo_t 	*component,
+				    char 	*name)
+{
+	moduleid_t 	modnum;
+	slotid_t 	slot;
+	char 		board_name[20];
+
+	ASSERT(brd);
+
+	/* Get the module number of this board */
+	modnum = brd->brd_module;
+
+	/* Convert the [ CLASS | TYPE ] kind of slotid
+	 * into a string 
+	 */
+	slot = brd->brd_slot;
+	ASSERT(modnum != MODULE_UNKNOWN && modnum != INVALID_MODULE);
+
+	/* Get the io board name  */
+	if (!brd || (brd->brd_sversion < 2)) {
+		strcpy(name, EDGE_LBL_XWIDGET);
+	} else {
+		nic_name_convert(brd->brd_name, board_name);
+	}
+
+	/* Give out the canonical  name of the pci device*/
+	sprintf(name, 
+		"/dev/hw/"EDGE_LBL_MODULE "/%x/"EDGE_LBL_SLOT"/%s/"
+		EDGE_LBL_PCI"/%d", 
+		modnum, board_name,KLCF_BRIDGE_W_ID(component));
+}
+
+/*
+ * Get the serial number of the main  component of a board
+ * Returns 0 if a valid serial number is found
+ * 1 otherwise.
+ * Assumptions: Nic manufacturing string  has the following format
+ *			*Serial:<serial_number>;*
+ */
+static int
+component_serial_number_get(lboard_t 		*board,
+			    klconf_off_t 	mfg_nic_offset,
+			    char		*serial_number,
+			    char		*key_pattern)
+{
+
+	char	*mfg_nic_string;
+	char	*serial_string,*str;
+	int	i;
+	char	*serial_pattern = "Serial:";
+
+	/* We have an error on a null mfg nic offset */
+	if (!mfg_nic_offset)
+		return(1);
+	/* Get the hub's manufacturing nic information
+	 * which is in the form of a pre-formatted string
+	 */
+	mfg_nic_string = 
+		(char *)NODE_OFFSET_TO_K0(NASID_GET(board),
+					  mfg_nic_offset);
+	/* There is no manufacturing nic info */
+	if (!mfg_nic_string)
+		return(1);
+
+	str = mfg_nic_string;
+	/* Look for the key pattern first (if it is  specified)
+	 * and then print the serial number corresponding to that.
+	 */
+	if (strcmp(key_pattern,"") && 
+	    !(str = strstr(mfg_nic_string,key_pattern)))
+		return(1);
+
+	/* There is no serial number info in the manufacturing
+	 * nic info
+	 */
+	if (!(serial_string = strstr(str,serial_pattern)))
+		return(1);
+
+	serial_string = serial_string + strlen(serial_pattern);
+	/*  Copy the serial number information from the klconfig */
+	i = 0;
+	while (serial_string[i] != ';') {
+		serial_number[i] = serial_string[i];
+		i++;
+	}
+	serial_number[i] = 0;
+	
+	return(0);
+}
+/*
+ * Get the serial number of a board
+ * Returns 0 if a valid serial number is found
+ * 1 otherwise.
+ */
+
+int
+board_serial_number_get(lboard_t *board,char *serial_number)
+{
+	ASSERT(board && serial_number);
+	if (!board || !serial_number)
+		return(1);
+
+	strcpy(serial_number,"");
+	switch(KLCLASS(board->brd_type)) {
+	case KLCLASS_CPU: {	/* Node board */
+		klhub_t	*hub;
+		
+		/* Get the hub component information */
+		hub = (klhub_t *)find_first_component(board,
+						      KLSTRUCT_HUB);
+		/* If we don't have a hub component on an IP27
+		 * then we have a weird klconfig.
+		 */
+		if (!hub)
+			return(1);
+		/* Get the serial number information from
+		 * the hub's manufacturing nic info
+		 */
+		if (component_serial_number_get(board,
+						hub->hub_mfg_nic,
+						serial_number,
+						"IP37"))
+				return(1);
+		break;
+	}
+	case KLCLASS_IO: {	/* IO board */
+		if (KLTYPE(board->brd_type) == KLTYPE_TPU) {
+		/* Special case for TPU boards */
+			kltpu_t *tpu;	
+		
+			/* Get the tpu component information */
+			tpu = (kltpu_t *)find_first_component(board,
+						      KLSTRUCT_TPU);
+			/* If we don't have a tpu component on a tpu board
+			 * then we have a weird klconfig.
+			 */
+			if (!tpu)
+				return(1);
+			/* Get the serial number information from
+			 * the tpu's manufacturing nic info
+			 */
+			if (component_serial_number_get(board,
+						tpu->tpu_mfg_nic,
+						serial_number,
+						""))
+				return(1);
+			break;
+		} else  if ((KLTYPE(board->brd_type) == KLTYPE_GSN_A) ||
+		            (KLTYPE(board->brd_type) == KLTYPE_GSN_B)) {
+		/* Special case for GSN boards */
+			klgsn_t *gsn;	
+		
+			/* Get the gsn component information */
+			gsn = (klgsn_t *)find_first_component(board,
+			      ((KLTYPE(board->brd_type) == KLTYPE_GSN_A) ?
+					KLSTRUCT_GSN_A : KLSTRUCT_GSN_B));
+			/* If we don't have a gsn component on a gsn board
+			 * then we have a weird klconfig.
+			 */
+			if (!gsn)
+				return(1);
+			/* Get the serial number information from
+			 * the gsn's manufacturing nic info
+			 */
+			if (component_serial_number_get(board,
+						gsn->gsn_mfg_nic,
+						serial_number,
+						""))
+				return(1);
+			break;
+		} else {
+		     	klbri_t	*bridge;
+		
+			/* Get the bridge component information */
+			bridge = (klbri_t *)find_first_component(board,
+							 KLSTRUCT_BRI);
+			/* If we don't have a bridge component on an IO board
+			 * then we have a weird klconfig.
+			 */
+			if (!bridge)
+				return(1);
+			/* Get the serial number information from
+		 	 * the bridge's manufacturing nic info
+			 */
+			if (component_serial_number_get(board,
+						bridge->bri_mfg_nic,
+						serial_number,
+						""))
+				return(1);
+			break;
+		}
+	}
+	case KLCLASS_ROUTER: {	/* Router board */
+		klrou_t *router;	
+		
+		/* Get the router component information */
+		router = (klrou_t *)find_first_component(board,
+							 KLSTRUCT_ROU);
+		/* If we don't have a router component on a router board
+		 * then we have a weird klconfig.
+		 */
+		if (!router)
+			return(1);
+		/* Get the serial number information from
+		 * the router's manufacturing nic info
+		 */
+		if (component_serial_number_get(board,
+						router->rou_mfg_nic,
+						serial_number,
+						""))
+			return(1);
+		break;
+	}
+	case KLCLASS_GFX: {	/* Gfx board */
+		klgfx_t *graphics;
+		
+		/* Get the graphics component information */
+		graphics = (klgfx_t *)find_first_component(board, KLSTRUCT_GFX);
+		/* If we don't have a gfx component on a gfx board
+		 * then we have a weird klconfig.
+		 */
+		if (!graphics)
+			return(1);
+		/* Get the serial number information from
+		 * the graphics's manufacturing nic info
+		 */
+		if (component_serial_number_get(board,
+						graphics->gfx_mfg_nic,
+						serial_number,
+						""))
+			return(1);
+		break;
+	}
+	default:
+		strcpy(serial_number,"");
+		break;
+	}
+	return(0);
+}
+
+#include "asm/sn/sn_private.h"
+
+xwidgetnum_t
+nodevertex_widgetnum_get(devfs_handle_t node_vtx)
+{
+	hubinfo_t hubinfo_p;
+
+	hwgraph_info_get_LBL(node_vtx, INFO_LBL_NODE_INFO, 
+			     (arbitrary_info_t *) &hubinfo_p);
+	return(hubinfo_p->h_widgetid);
+}
+
+devfs_handle_t
+nodevertex_xbow_peer_get(devfs_handle_t node_vtx)
+{
+	hubinfo_t hubinfo_p;
+	nasid_t xbow_peer_nasid;
+	cnodeid_t xbow_peer;
+
+	hwgraph_info_get_LBL(node_vtx, INFO_LBL_NODE_INFO,
+				     (arbitrary_info_t *) &hubinfo_p);
+	xbow_peer_nasid = hubinfo_p->h_nodepda->xbow_peer;
+	if(xbow_peer_nasid == INVALID_NASID) 
+			return ( (devfs_handle_t)-1);
+	xbow_peer = NASID_TO_COMPACT_NODEID(xbow_peer_nasid);
+	return(NODEPDA(xbow_peer)->node_vertex);
+}
+
+/* NIC Sorting Support */
+
+#define MAX_NICS_PER_STRING 	32
+#define MAX_NIC_NAME_LEN	32
+
+static char *
+get_nic_string(lboard_t *lb)
+{
+        int         	i;
+        klinfo_t    	*k = NULL ;
+    	klconf_off_t    mfg_off = 0 ;
+    	char            *mfg_nic = NULL ;
+
+        for (i = 0; i < KLCF_NUM_COMPS(lb); i++) {
+                k = KLCF_COMP(lb, i) ;
+                switch(k->struct_type) {
+                        case KLSTRUCT_BRI:
+            			mfg_off = ((klbri_t *)k)->bri_mfg_nic ;
+				break ;
+
+                        case KLSTRUCT_HUB:
+            			mfg_off = ((klhub_t *)k)->hub_mfg_nic ;
+				break ;
+
+                        case KLSTRUCT_ROU:
+            			mfg_off = ((klrou_t *)k)->rou_mfg_nic ;
+				break ;
+
+                        case KLSTRUCT_GFX:
+            			mfg_off = ((klgfx_t *)k)->gfx_mfg_nic ;
+				break ;
+
+                        case KLSTRUCT_TPU:
+            			mfg_off = ((kltpu_t *)k)->tpu_mfg_nic ;
+				break ;
+
+                        case KLSTRUCT_GSN_A:
+                        case KLSTRUCT_GSN_B:
+            			mfg_off = ((klgsn_t *)k)->gsn_mfg_nic ;
+				break ;
+
+                        case KLSTRUCT_XTHD:
+                                mfg_off = ((klxthd_t *)k)->xthd_mfg_nic ;
+                                break;
+
+			default:
+				mfg_off = 0 ;
+                                break ;
+                }
+		if (mfg_off)
+			break ;
+        }
+
+	if ((mfg_off) && (k))
+		mfg_nic = (char *)NODE_OFFSET_TO_K0(k->nasid, mfg_off) ;
+
+        return mfg_nic ;
+}
+
+char *
+get_first_string(char **ptrs, int n)
+{
+        int     i ;
+        char    *tmpptr ;
+
+        if ((ptrs == NULL) || (n == 0))
+                return NULL ;
+
+        tmpptr = ptrs[0] ;
+
+        if (n == 1)
+                return tmpptr ;
+
+        for (i = 0 ; i < n ; i++) {
+                if (strcmp(tmpptr, ptrs[i]) > 0)
+                        tmpptr = ptrs[i] ;
+        }
+
+        return tmpptr ;
+}
+
+int
+get_ptrs(char *idata, char **ptrs, int n, char *label)
+{
+        int     i = 0 ;
+        char    *tmp = idata ;
+
+        if ((ptrs == NULL) || (idata == NULL) || (label == NULL) || (n == 0))
+                return 0 ;
+
+        while  ( (tmp = strstr(tmp, label)) ){
+                tmp += strlen(label) ;
+                /* check for empty name field, and last NULL ptr */
+                if ((i < (n-1)) && (*tmp != ';')) {
+                        ptrs[i++] = tmp ;
+                }
+        }
+
+        ptrs[i] = NULL ;
+
+        return i ;
+}
+
+/*
+ * sort_nic_names
+ *
+ * 	Does not really do sorting. Find the alphabetically lowest
+ *	name among all the nic names found in a nic string.
+ *
+ * Return:
+ *	Nothing
+ *
+ * Side Effects:
+ *
+ *	lb->brd_name gets the new name found
+ */
+
+static void
+sort_nic_names(lboard_t *lb)
+{
+	char 	*nic_str ;
+        char    *ptrs[MAX_NICS_PER_STRING] ;
+        char    name[MAX_NIC_NAME_LEN] ;
+        char    *tmp, *tmp1 ;
+
+	*name = 0 ;
+
+	/* Get the nic pointer from the lb */
+
+	if ((nic_str = get_nic_string(lb)) == NULL)
+		return ;
+
+        tmp = get_first_string(ptrs,
+                        get_ptrs(nic_str, ptrs, MAX_NICS_PER_STRING, "Name:")) ;
+
+        if (tmp == NULL)
+		return ;
+
+        if  ( (tmp1 = strchr(tmp, ';')) ){
+                strncpy(name, tmp, tmp1-tmp) ;
+                name[tmp1-tmp] = 0 ;
+        } else {
+                strncpy(name, tmp, (sizeof(name) -1)) ;
+                name[sizeof(name)-1] = 0 ;
+        }
+
+	strcpy(lb->brd_name, name) ;
+}
+
+
+
+char brick_types[MAX_BRICK_TYPES + 1] = "crikxdpn%#012345";
+
+
+/*
+ * Format a module id for printing.
+ */
+void
+format_module_id(char *buffer, moduleid_t m, int fmt)
+{
+	int rack, position;
+	char brickchar;
+
+	rack = MODULE_GET_RACK(m);
+	ASSERT(MODULE_GET_BTYPE(m) < MAX_BRICK_TYPES);
+	brickchar = MODULE_GET_BTCHAR(m);
+	position = MODULE_GET_BPOS(m);
+
+	if (fmt == MODULE_FORMAT_BRIEF) {
+	    /* Brief module number format, eg. 002c15 */
+
+	    /* Decompress the rack number */
+	    *buffer++ = '0' + RACK_GET_CLASS(rack);
+	    *buffer++ = '0' + RACK_GET_GROUP(rack);
+	    *buffer++ = '0' + RACK_GET_NUM(rack);
+
+	    /* Add the brick type */
+	    *buffer++ = brickchar;
+	}
+	else if (fmt == MODULE_FORMAT_LONG) {
+	    /* Fuller hwgraph format, eg. rack/002/bay/15 */
+
+	    strcpy(buffer, EDGE_LBL_RACK "/");  buffer += strlen(buffer);
+
+	    *buffer++ = '0' + RACK_GET_CLASS(rack);
+	    *buffer++ = '0' + RACK_GET_GROUP(rack);
+	    *buffer++ = '0' + RACK_GET_NUM(rack);
+
+	    strcpy(buffer, "/" EDGE_LBL_RPOS "/");  buffer += strlen(buffer);
+	}
+
+	/* Add the bay position, using at least two digits */
+	if (position < 10)
+	    *buffer++ = '0';
+	sprintf(buffer, "%d", position);
+
+}
+
+/*
+ * Parse a module id, in either brief or long form.
+ * Returns < 0 on error.
+ * The long form does not include a brick type, so it defaults to 0 (CBrick)
+ */
+int
+parse_module_id(char *buffer)
+{
+	unsigned int	v, rack, bay, type, form;
+	moduleid_t	m;
+	char 		c;
+
+	if (strstr(buffer, EDGE_LBL_RACK "/") == buffer) {
+		form = MODULE_FORMAT_LONG;
+		buffer += strlen(EDGE_LBL_RACK "/");
+
+		/* A long module ID must be exactly 5 non-template chars. */
+		if (strlen(buffer) != strlen("/" EDGE_LBL_RPOS "/") + 5)
+			return -1;
+	}
+	else {
+		form = MODULE_FORMAT_BRIEF;
+
+		/* A brief module id must be exactly 6 characters */
+		if (strlen(buffer) != 6)
+			return -2;
+	}
+
+	/* The rack number must be exactly 3 digits */
+	if (!(isdigit(buffer[0]) && isdigit(buffer[1]) && isdigit(buffer[2])))
+		return -3;
+
+	rack = 0;
+	v = *buffer++ - '0';
+	if (v > RACK_CLASS_MASK(rack) >> RACK_CLASS_SHFT(rack))
+		return -4;
+	RACK_ADD_CLASS(rack, v);
+
+	v = *buffer++ - '0';
+	if (v > RACK_GROUP_MASK(rack) >> RACK_GROUP_SHFT(rack))
+		return -5;
+	RACK_ADD_GROUP(rack, v);
+
+	v = *buffer++ - '0';
+	/* rack numbers are 1-based */
+	if (v-1 > RACK_NUM_MASK(rack) >> RACK_NUM_SHFT(rack))
+		return -6;
+	RACK_ADD_NUM(rack, v);
+
+	if (form == MODULE_FORMAT_BRIEF) {
+		/* Next should be a module type character.  Accept ucase or lcase. */
+		c = *buffer++;
+		if (!isalpha(c))
+			return -7;
+
+		/* strchr() returns a pointer into brick_types[], or NULL */
+		type = (unsigned int)(strchr(brick_types, tolower(c)) - brick_types);
+		if (type > MODULE_BTYPE_MASK >> MODULE_BTYPE_SHFT)
+			return -8;
+	}
+	else {
+		/* Hardcode the module type, and skip over the boilerplate */
+		type = MODULE_CBRICK;
+
+		if (strstr(buffer, "/" EDGE_LBL_RPOS "/") != buffer)
+			return -9;
+
+		buffer += strlen("/" EDGE_LBL_RPOS "/");
+	}
+		
+	/* The bay number is last.  Make sure it's exactly two digits */
+
+	if (!(isdigit(buffer[0]) && isdigit(buffer[1]) && !buffer[2]))
+		return -10;
+
+	bay = 10 * (buffer[0] - '0') + (buffer[1] - '0');
+
+	if (bay > MODULE_BPOS_MASK >> MODULE_BPOS_SHFT)
+		return -11;
+
+	m = RBT_TO_MODULE(rack, bay, type);
+
+	/* avoid sign extending the moduleid_t */
+	return (int)(unsigned short)m;
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn1/klgraph.c linux-2.4.21-pre6/arch/ia64/sn/io/sn1/klgraph.c
--- linux-2.4.20/arch/ia64/sn/io/sn1/klgraph.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn1/klgraph.c	2003-03-26 23:49:29.000000000 +0000
@@ -0,0 +1,940 @@
+/* $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) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+/*
+ * klgraph.c-
+ *      This file specifies the interface between the kernel and the PROM's
+ *      configuration data structures.
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/io.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/kldir.h>
+#include <asm/sn/gda.h> 
+#include <asm/sn/klconfig.h>
+#include <asm/sn/router.h>
+#include <asm/sn/xtalk/xbow.h>
+#include <asm/sn/hcl_util.h>
+
+/* #define KLGRAPH_DEBUG 1 */
+#ifdef KLGRAPH_DEBUG
+#define GRPRINTF(x)	printk x
+#define CE_GRPANIC	CE_PANIC
+#else
+#define GRPRINTF(x)
+#define CE_GRPANIC	CE_PANIC
+#endif
+
+#include <asm/sn/sn_private.h>
+
+extern char arg_maxnodes[];
+extern u64 klgraph_addr[];
+
+/*
+ * Support for verbose inventory via hardware graph. 
+ * klhwg_invent_alloc allocates the necessary size of inventory information
+ * and fills in the generic information.
+ */
+invent_generic_t *
+klhwg_invent_alloc(cnodeid_t cnode, int class, int size)
+{
+	invent_generic_t *invent;
+
+	invent = kern_malloc(size);
+	if (!invent) return NULL;
+	
+	invent->ig_module = NODE_MODULEID(cnode);
+	invent->ig_slot = SLOTNUM_GETSLOT(NODE_SLOTID(cnode));
+	invent->ig_invclass = class;
+
+	return invent;
+}
+
+/*
+ * Add detailed disabled cpu inventory info to the hardware graph.
+ */
+void
+klhwg_disabled_cpu_invent_info(devfs_handle_t cpuv,
+                               cnodeid_t cnode,
+                               klcpu_t *cpu, slotid_t slot)
+{
+	invent_cpuinfo_t *cpu_invent;
+	diag_inv_t       *diag_invent;
+
+	cpu_invent = (invent_cpuinfo_t *)
+	klhwg_invent_alloc(cnode, INV_PROCESSOR, sizeof(invent_cpuinfo_t));
+	if (!cpu_invent)
+		return;
+
+	/* Diag information on this processor */
+	diag_invent = (diag_inv_t *)
+	klhwg_invent_alloc(cnode, INV_CPUDIAGVAL, sizeof(diag_inv_t));
+
+	if (!diag_invent)
+		return;
+
+
+	/* Disabled CPU */
+	cpu_invent->ic_gen.ig_flag = 0x0;
+	cpu_invent->ic_gen.ig_slot = slot;
+	cpu_invent->ic_cpu_info.cpuflavor = cpu->cpu_prid;
+	cpu_invent->ic_cpu_info.cpufq = cpu->cpu_speed;
+	cpu_invent->ic_cpu_info.sdfreq = cpu->cpu_scachespeed;
+
+	cpu_invent->ic_cpu_info.sdsize = cpu->cpu_scachesz;
+	cpu_invent->ic_cpuid = cpu->cpu_info.virtid;
+	cpu_invent->ic_slice = cpu->cpu_info.physid;
+
+	/* Disabled CPU label */
+	hwgraph_info_add_LBL(cpuv, INFO_LBL_DETAIL_INVENT,
+			(arbitrary_info_t) cpu_invent);
+	hwgraph_info_export_LBL(cpuv, INFO_LBL_DETAIL_INVENT,
+			sizeof(invent_cpuinfo_t));
+
+	/* Diagval label - stores reason for disable +{virt,phys}id +diagval*/
+	hwgraph_info_add_LBL(cpuv, INFO_LBL_DIAGVAL,
+			(arbitrary_info_t) diag_invent);
+
+	hwgraph_info_export_LBL(cpuv, INFO_LBL_DIAGVAL,
+			sizeof(diag_inv_t));
+}
+
+/*
+ * Add detailed cpu inventory info to the hardware graph.
+ */
+void
+klhwg_cpu_invent_info(devfs_handle_t cpuv,
+			cnodeid_t cnode,
+			klcpu_t *cpu)
+{
+	invent_cpuinfo_t *cpu_invent;
+
+	cpu_invent = (invent_cpuinfo_t *)
+		klhwg_invent_alloc(cnode, INV_PROCESSOR, sizeof(invent_cpuinfo_t));
+	if (!cpu_invent)
+		return;
+
+	if (KLCONFIG_INFO_ENABLED((klinfo_t *)cpu))
+		cpu_invent->ic_gen.ig_flag = INVENT_ENABLED;
+	else
+		cpu_invent->ic_gen.ig_flag = 0x0;
+
+	cpu_invent->ic_cpu_info.cpuflavor = cpu->cpu_prid;
+	cpu_invent->ic_cpu_info.cpufq = cpu->cpu_speed;
+	cpu_invent->ic_cpu_info.sdfreq = cpu->cpu_scachespeed;
+
+	cpu_invent->ic_cpu_info.sdsize = cpu->cpu_scachesz;
+	cpu_invent->ic_cpuid = cpu->cpu_info.virtid;
+	cpu_invent->ic_slice = cpu_physical_id_to_slice(cpu->cpu_info.virtid);
+
+	hwgraph_info_add_LBL(cpuv, INFO_LBL_DETAIL_INVENT,
+			(arbitrary_info_t) cpu_invent);
+	hwgraph_info_export_LBL(cpuv, INFO_LBL_DETAIL_INVENT,
+			sizeof(invent_cpuinfo_t));
+}
+
+/* 
+ * Add information about the baseio prom version number
+ * as a part of detailed inventory info in the hwgraph.
+ */
+void
+klhwg_baseio_inventory_add(devfs_handle_t baseio_vhdl,cnodeid_t cnode)
+{
+	invent_miscinfo_t	*baseio_inventory;
+	unsigned char		version = 0,revision = 0;
+
+	/* Allocate memory for the "detailed inventory" info
+	 * for the baseio
+	 */
+	baseio_inventory = (invent_miscinfo_t *) 
+		klhwg_invent_alloc(cnode, INV_PROM, sizeof(invent_miscinfo_t));
+	baseio_inventory->im_type = INV_IO6PROM;
+	/* Store the revision info  in the inventory */
+	baseio_inventory->im_version = version;
+	baseio_inventory->im_rev = revision;
+	/* Put the inventory info in the hardware graph */
+	hwgraph_info_add_LBL(baseio_vhdl, INFO_LBL_DETAIL_INVENT, 
+			     (arbitrary_info_t) baseio_inventory);
+	/* Make the information available to the user programs
+	 * thru hwgfs.
+	 */
+        hwgraph_info_export_LBL(baseio_vhdl, INFO_LBL_DETAIL_INVENT,
+				sizeof(invent_miscinfo_t));
+}
+
+char	*hub_rev[] = {
+	"0.0",
+	"1.0",
+	"2.0",
+	"2.1",
+	"2.2",
+	"2.3"
+};
+
+/*
+ * Add detailed cpu inventory info to the hardware graph.
+ */
+void
+klhwg_hub_invent_info(devfs_handle_t hubv,
+		      cnodeid_t cnode, 
+		      klhub_t *hub)
+{
+	invent_miscinfo_t *hub_invent;
+
+	hub_invent = (invent_miscinfo_t *) 
+	    klhwg_invent_alloc(cnode, INV_MISC, sizeof(invent_miscinfo_t));
+	if (!hub_invent)
+	    return;
+
+	if (KLCONFIG_INFO_ENABLED((klinfo_t *)hub))
+	    hub_invent->im_gen.ig_flag = INVENT_ENABLED;
+
+	hub_invent->im_type = INV_HUB;
+	hub_invent->im_rev = hub->hub_info.revision;
+	hub_invent->im_speed = hub->hub_speed;
+	hwgraph_info_add_LBL(hubv, INFO_LBL_DETAIL_INVENT, 
+			     (arbitrary_info_t) hub_invent);
+        hwgraph_info_export_LBL(hubv, INFO_LBL_DETAIL_INVENT,
+				sizeof(invent_miscinfo_t));
+}
+
+/* ARGSUSED */
+void
+klhwg_add_hub(devfs_handle_t node_vertex, klhub_t *hub, cnodeid_t cnode)
+{
+	devfs_handle_t myhubv;
+	devfs_handle_t hub_mon;
+	devfs_handle_t synergy;
+	devfs_handle_t fsb0;
+	devfs_handle_t fsb1;
+	int rc;
+	extern struct file_operations hub_mon_fops;
+
+	GRPRINTF(("klhwg_add_hub: adding %s\n", EDGE_LBL_HUB));
+
+	(void) hwgraph_path_add(node_vertex, EDGE_LBL_HUB, &myhubv);
+	rc = device_master_set(myhubv, node_vertex);
+
+	/*
+	 * hub perf stats.
+	 */
+	rc = hwgraph_info_add_LBL(myhubv, INFO_LBL_HUB_INFO,
+                        (arbitrary_info_t)(&NODEPDA(cnode)->hubstats));
+
+	if (rc != GRAPH_SUCCESS) {
+		printk(KERN_WARNING  "klhwg_add_hub: Can't add hub info label 0x%p, code %d",
+			(void *)myhubv, rc);
+	}
+
+	klhwg_hub_invent_info(myhubv, cnode, hub);
+
+	hub_mon = hwgraph_register(myhubv, EDGE_LBL_PERFMON,
+	    0, DEVFS_FL_AUTO_DEVNUM,
+	    0, 0,
+	    S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0,
+	    &hub_mon_fops,
+	    (void *)(long)cnode);
+
+	init_hub_stats(cnode, NODEPDA(cnode));
+
+	/*
+	 * synergy perf
+	 */
+	(void) hwgraph_path_add(myhubv, EDGE_LBL_SYNERGY, &synergy);
+	(void) hwgraph_path_add(synergy, "0", &fsb0);
+	(void) hwgraph_path_add(synergy, "1", &fsb1);
+
+	fsb0 = hwgraph_register(fsb0, EDGE_LBL_PERFMON,
+	    0, DEVFS_FL_AUTO_DEVNUM,
+	    0, 0,
+	    S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0,
+	    &synergy_mon_fops, (void *)SYNERGY_PERF_INFO(cnode, 0));
+
+	fsb1 = hwgraph_register(fsb1, EDGE_LBL_PERFMON,
+	    0, DEVFS_FL_AUTO_DEVNUM,
+	    0, 0,
+	    S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0,
+	    &synergy_mon_fops, (void *)SYNERGY_PERF_INFO(cnode, 1));
+}
+
+/* ARGSUSED */
+void
+klhwg_add_disabled_cpu(devfs_handle_t node_vertex, cnodeid_t cnode, klcpu_t *cpu, slotid_t slot)
+{
+        devfs_handle_t my_cpu;
+        char name[120];
+        cpuid_t cpu_id;
+	nasid_t nasid;
+
+	nasid = COMPACT_TO_NASID_NODEID(cnode);
+        cpu_id = nasid_slice_to_cpuid(nasid, cpu->cpu_info.physid);
+        if(cpu_id != -1){
+		sprintf(name, "%s/%s/%c", EDGE_LBL_DISABLED, EDGE_LBL_CPU, 'a' + cpu->cpu_info.physid);
+		(void) hwgraph_path_add(node_vertex, name, &my_cpu);
+
+		mark_cpuvertex_as_cpu(my_cpu, cpu_id);
+		device_master_set(my_cpu, node_vertex);
+
+		klhwg_disabled_cpu_invent_info(my_cpu, cnode, cpu, slot);
+		return;
+        }
+}
+
+/* ARGSUSED */
+void
+klhwg_add_cpu(devfs_handle_t node_vertex, cnodeid_t cnode, klcpu_t *cpu)
+{
+        devfs_handle_t my_cpu, cpu_dir;
+        char name[120];
+        cpuid_t cpu_id;
+	nasid_t nasid;
+
+	nasid = COMPACT_TO_NASID_NODEID(cnode);
+        cpu_id = nasid_slice_to_cpuid(nasid, cpu->cpu_info.physid);
+
+        sprintf(name, "%s/%d/%c",
+                EDGE_LBL_CPUBUS,
+                0,
+                'a' + cpu->cpu_info.physid);
+
+        GRPRINTF(("klhwg_add_cpu: adding %s to vertex 0x%x\n", name, node_vertex));
+        (void) hwgraph_path_add(node_vertex, name, &my_cpu);
+        mark_cpuvertex_as_cpu(my_cpu, cpu_id);
+        device_master_set(my_cpu, node_vertex);
+
+        /* Add an alias under the node's CPU directory */
+        if (hwgraph_edge_get(node_vertex, EDGE_LBL_CPU, &cpu_dir) == GRAPH_SUCCESS) {
+                sprintf(name, "%c", 'a' + cpu->cpu_info.physid);
+                (void) hwgraph_edge_add(cpu_dir, my_cpu, name);
+        }
+
+        klhwg_cpu_invent_info(my_cpu, cnode, cpu);
+}
+
+
+void
+klhwg_add_xbow(cnodeid_t cnode, nasid_t nasid)
+{
+	lboard_t *brd;
+	klxbow_t *xbow_p;
+	nasid_t hub_nasid;
+	cnodeid_t hub_cnode;
+	int widgetnum;
+	devfs_handle_t xbow_v, hubv;
+	/*REFERENCED*/
+	graph_error_t err;
+
+	if ((brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IOBRICK_XBOW)) == NULL)
+			return;
+
+	if (KL_CONFIG_DUPLICATE_BOARD(brd))
+	    return;
+
+	GRPRINTF(("klhwg_add_xbow: adding cnode %d nasid %d xbow edges\n",
+			cnode, nasid));
+
+	if ((xbow_p = (klxbow_t *)find_component(brd, NULL, KLSTRUCT_XBOW))
+	    == NULL)
+	    return;
+
+#ifdef	LATER
+	/*
+	 * We cannot support this function in devfs .. see below where 
+	 * we use hwgraph_path_add() to create this vertex with a known 
+	 * name.
+	 */
+	err = hwgraph_vertex_create(&xbow_v);
+	ASSERT(err == GRAPH_SUCCESS);
+
+	xswitch_vertex_init(xbow_v);
+#endif /* LATER */
+
+	for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) {
+		if (!XBOW_PORT_TYPE_HUB(xbow_p, widgetnum)) 
+		    continue;
+
+		hub_nasid = XBOW_PORT_NASID(xbow_p, widgetnum);
+		if (hub_nasid == INVALID_NASID) {
+			printk(KERN_WARNING  "hub widget %d, skipping xbow graph\n", widgetnum);
+			continue;
+		}
+
+		hub_cnode = NASID_TO_COMPACT_NODEID(hub_nasid);
+
+		if (is_specified(arg_maxnodes) && hub_cnode == INVALID_CNODEID) {
+			continue;
+		}
+			
+		hubv = cnodeid_to_vertex(hub_cnode);
+
+		err = hwgraph_path_add(hubv, EDGE_LBL_XTALK, &xbow_v);
+                if (err != GRAPH_SUCCESS) {
+                        if (err == GRAPH_DUP)
+                                printk(KERN_WARNING  "klhwg_add_xbow: Check for "
+                                        "working routers and router links!");
+
+                        PRINT_PANIC("klhwg_add_xbow: Failed to add "
+                                "edge: vertex 0x%p to vertex 0x%p,"
+                                "error %d\n",
+                                (void *)hubv, (void *)xbow_v, err);
+                }
+		xswitch_vertex_init(xbow_v); 
+
+		NODEPDA(hub_cnode)->xbow_vhdl = xbow_v;
+
+		/*
+		 * XXX - This won't work is we ever hook up two hubs
+		 * by crosstown through a crossbow.
+		 */
+		if (hub_nasid != nasid) {
+			NODEPDA(hub_cnode)->xbow_peer = nasid;
+			NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->xbow_peer =
+				hub_nasid;
+		}
+
+		GRPRINTF(("klhwg_add_xbow: adding port nasid %d %s to vertex 0x%p\n",
+			hub_nasid, EDGE_LBL_XTALK, hubv));
+
+#ifdef	LATER
+		err = hwgraph_edge_add(hubv, xbow_v, EDGE_LBL_XTALK);
+		if (err != GRAPH_SUCCESS) {
+			if (err == GRAPH_DUP)
+				printk(KERN_WARNING  "klhwg_add_xbow: Check for "
+					"working routers and router links!");
+
+			PRINT_PANIC("klhwg_add_xbow: Failed to add "
+				"edge: vertex 0x%p (0x%p) to vertex 0x%p (0x%p), "
+				"error %d\n",
+				hubv, hubv, xbow_v, xbow_v, err);
+		}
+#endif
+	}
+}
+
+
+/* ARGSUSED */
+void
+klhwg_add_node(devfs_handle_t hwgraph_root, cnodeid_t cnode, gda_t *gdap)
+{
+	nasid_t nasid;
+	lboard_t *brd;
+	klhub_t *hub;
+	devfs_handle_t node_vertex = NULL;
+	char path_buffer[100];
+	int rv;
+	char *s;
+	int board_disabled = 0;
+	klcpu_t *cpu;
+
+	nasid = COMPACT_TO_NASID_NODEID(cnode);
+	brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA);
+	GRPRINTF(("klhwg_add_node: Adding cnode %d, nasid %d, brd 0x%p\n",
+                cnode, nasid, brd));
+	ASSERT(brd);
+
+	do {
+		devfs_handle_t cpu_dir;
+
+		/* Generate a hardware graph path for this board. */
+		board_to_path(brd, path_buffer);
+
+		GRPRINTF(("klhwg_add_node: adding %s to vertex 0x%p\n",
+			path_buffer, hwgraph_root));
+		rv = hwgraph_path_add(hwgraph_root, path_buffer, &node_vertex);
+
+		if (rv != GRAPH_SUCCESS)
+			PRINT_PANIC("Node vertex creation failed.  "
+					  "Path == %s",
+				path_buffer);
+
+		hub = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB);
+		ASSERT(hub);
+		if(hub->hub_info.flags & KLINFO_ENABLE)
+			board_disabled = 0;
+		else
+			board_disabled = 1;
+		
+		if(!board_disabled) {
+			mark_nodevertex_as_node(node_vertex,
+					    cnode + board_disabled * numnodes);
+
+			s = dev_to_name(node_vertex, path_buffer, sizeof(path_buffer));
+			NODEPDA(cnode)->hwg_node_name =
+						kmalloc(strlen(s) + 1,
+						GFP_KERNEL);
+			ASSERT_ALWAYS(NODEPDA(cnode)->hwg_node_name != NULL);
+			strcpy(NODEPDA(cnode)->hwg_node_name, s);
+
+			hubinfo_set(node_vertex, NODEPDA(cnode)->pdinfo);
+
+			/* Set up node board's slot */
+			NODEPDA(cnode)->slotdesc = brd->brd_slot;
+
+			/* Set up the module we're in */
+			NODEPDA(cnode)->module_id = brd->brd_module;
+			NODEPDA(cnode)->module = module_lookup(brd->brd_module);
+		}
+
+
+		/* Get the first CPU structure */
+		cpu = (klcpu_t *)find_first_component(brd, KLSTRUCT_CPU);
+
+		/*
+		* If there's at least 1 CPU, add a "cpu" directory to represent
+		* the collection of all CPUs attached to this node.
+		*/
+		if (cpu) {
+			graph_error_t rv;
+
+			rv = hwgraph_path_add(node_vertex, EDGE_LBL_CPU, &cpu_dir);
+			if (rv != GRAPH_SUCCESS)
+				panic("klhwg_add_node: Cannot create CPU directory\n");
+		}
+
+		/* Add each CPU */
+		while (cpu) {
+			cpuid_t cpu_id;
+			cpu_id = nasid_slice_to_cpuid(nasid,cpu->cpu_info.physid);
+			if (cpu_enabled(cpu_id))
+				klhwg_add_cpu(node_vertex, cnode, cpu);
+			else
+				klhwg_add_disabled_cpu(node_vertex, cnode, cpu, brd->brd_slot);
+
+			cpu = (klcpu_t *)
+				find_component(brd, (klinfo_t *)cpu, KLSTRUCT_CPU);
+		} /* while */
+
+		if(!board_disabled)
+		klhwg_add_hub(node_vertex, hub, cnode);
+		
+		brd = KLCF_NEXT(brd);
+		if (brd)
+			brd = find_lboard(brd, KLTYPE_SNIA);
+		else
+			break;
+	} while(brd);
+}
+
+
+/* ARGSUSED */
+void
+klhwg_add_all_routers(devfs_handle_t hwgraph_root)
+{
+	nasid_t nasid;
+	cnodeid_t cnode;
+	lboard_t *brd;
+	devfs_handle_t node_vertex;
+	char path_buffer[100];
+	int rv;
+
+	for (cnode = 0; cnode < numnodes; cnode++) {
+		nasid = COMPACT_TO_NASID_NODEID(cnode);
+
+		GRPRINTF(("klhwg_add_all_routers: adding router on cnode %d\n",
+			cnode));
+
+		brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid),
+				KLTYPE_ROUTER);
+
+		if (!brd)
+			/* No routers stored in this node's memory */
+			continue;
+
+		do {
+			ASSERT(brd);
+			GRPRINTF(("Router board struct is %p\n", brd));
+
+			/* Don't add duplicate boards. */
+			if (brd->brd_flags & DUPLICATE_BOARD)
+				continue;
+
+			GRPRINTF(("Router 0x%p module number is %d\n", brd, brd->brd_module));
+			/* Generate a hardware graph path for this board. */
+			board_to_path(brd, path_buffer);
+
+			GRPRINTF(("Router path is %s\n", path_buffer));
+
+			/* Add the router */
+			GRPRINTF(("klhwg_add_all_routers: adding %s to vertex 0x%p\n",
+				path_buffer, hwgraph_root));
+			rv = hwgraph_path_add(hwgraph_root, path_buffer, &node_vertex);
+
+			if (rv != GRAPH_SUCCESS)
+				PRINT_PANIC("Router vertex creation "
+						  "failed.  Path == %s",
+					path_buffer);
+
+			GRPRINTF(("klhwg_add_all_routers: get next board from 0x%p\n",
+					brd));
+		/* Find the rest of the routers stored on this node. */
+		} while ( (brd = find_lboard_class(KLCF_NEXT(brd),
+			 KLTYPE_ROUTER)) );
+
+		GRPRINTF(("klhwg_add_all_routers: Done.\n"));
+	}
+
+}
+
+/* ARGSUSED */
+void
+klhwg_connect_one_router(devfs_handle_t hwgraph_root, lboard_t *brd,
+			 cnodeid_t cnode, nasid_t nasid)
+{
+	klrou_t *router;
+	char path_buffer[50];
+	char dest_path[50];
+	devfs_handle_t router_hndl;
+	devfs_handle_t dest_hndl;
+	int rc;
+	int port;
+	lboard_t *dest_brd;
+
+	GRPRINTF(("klhwg_connect_one_router: Connecting router on cnode %d\n",
+			cnode));
+
+	/* Don't add duplicate boards. */
+	if (brd->brd_flags & DUPLICATE_BOARD) {
+		GRPRINTF(("klhwg_connect_one_router: Duplicate router 0x%p on cnode %d\n",
+			brd, cnode));
+		return;
+	}
+
+	/* Generate a hardware graph path for this board. */
+	board_to_path(brd, path_buffer);
+
+	rc = hwgraph_traverse(hwgraph_root, path_buffer, &router_hndl);
+
+	if (rc != GRAPH_SUCCESS && is_specified(arg_maxnodes))
+			return;
+
+	if (rc != GRAPH_SUCCESS)
+		printk(KERN_WARNING  "Can't find router: %s", path_buffer);
+
+	/* We don't know what to do with multiple router components */
+	if (brd->brd_numcompts != 1) {
+		PRINT_PANIC("klhwg_connect_one_router: %d cmpts on router\n",
+			brd->brd_numcompts);
+		return;
+	}
+
+
+	/* Convert component 0 to klrou_t ptr */
+	router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd),
+					      brd->brd_compts[0]);
+
+	for (port = 1; port <= MAX_ROUTER_PORTS; port++) {
+		/* See if the port's active */
+		if (router->rou_port[port].port_nasid == INVALID_NASID) {
+			GRPRINTF(("klhwg_connect_one_router: port %d inactive.\n",
+				 port));
+			continue;
+		}
+		if (is_specified(arg_maxnodes) && NASID_TO_COMPACT_NODEID(router->rou_port[port].port_nasid) 
+		    == INVALID_CNODEID) {
+			continue;
+		}
+
+		dest_brd = (lboard_t *)NODE_OFFSET_TO_K0(
+				router->rou_port[port].port_nasid,
+				router->rou_port[port].port_offset);
+
+		/* Generate a hardware graph path for this board. */
+		board_to_path(dest_brd, dest_path);
+
+		rc = hwgraph_traverse(hwgraph_root, dest_path, &dest_hndl);
+
+		if (rc != GRAPH_SUCCESS) {
+			if (is_specified(arg_maxnodes) && KL_CONFIG_DUPLICATE_BOARD(dest_brd))
+				continue;
+			PRINT_PANIC("Can't find router: %s", dest_path);
+		}
+		GRPRINTF(("klhwg_connect_one_router: Link from %s/%d to %s\n",
+			  path_buffer, port, dest_path));
+
+		sprintf(dest_path, "%d", port);
+
+		rc = hwgraph_edge_add(router_hndl, dest_hndl, dest_path);
+
+		if (rc == GRAPH_DUP) {
+			GRPRINTF(("Skipping port %d. nasid %d %s/%s\n",
+				  port, router->rou_port[port].port_nasid,
+				  path_buffer, dest_path));
+			continue;
+		}
+
+		if (rc != GRAPH_SUCCESS && !is_specified(arg_maxnodes))
+			PRINT_PANIC("Can't create edge: %s/%s to vertex 0x%p error 0x%x\n",
+				path_buffer, dest_path, (void *)dest_hndl, rc);
+		
+	}
+}
+
+
+void
+klhwg_connect_routers(devfs_handle_t hwgraph_root)
+{
+	nasid_t nasid;
+	cnodeid_t cnode;
+	lboard_t *brd;
+
+	for (cnode = 0; cnode < numnodes; cnode++) {
+		nasid = COMPACT_TO_NASID_NODEID(cnode);
+
+		GRPRINTF(("klhwg_connect_routers: Connecting routers on cnode %d\n",
+			cnode));
+
+		brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid),
+				KLTYPE_ROUTER);
+
+		if (!brd)
+			continue;
+
+		do {
+
+			nasid = COMPACT_TO_NASID_NODEID(cnode);
+
+			klhwg_connect_one_router(hwgraph_root, brd,
+						 cnode, nasid);
+
+		/* Find the rest of the routers stored on this node. */
+		} while ( (brd = find_lboard_class(KLCF_NEXT(brd), KLTYPE_ROUTER)) );
+	}
+}
+
+
+
+void
+klhwg_connect_hubs(devfs_handle_t hwgraph_root)
+{
+	nasid_t nasid;
+	cnodeid_t cnode;
+	lboard_t *brd;
+	klhub_t *hub;
+	lboard_t *dest_brd;
+	devfs_handle_t hub_hndl;
+	devfs_handle_t dest_hndl;
+	char path_buffer[50];
+	char dest_path[50];
+	graph_error_t rc;
+
+	for (cnode = 0; cnode < numnodes; cnode++) {
+		nasid = COMPACT_TO_NASID_NODEID(cnode);
+
+		GRPRINTF(("klhwg_connect_hubs: Connecting hubs on cnode %d\n",
+			cnode));
+
+		brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA);
+		ASSERT(brd);
+
+		hub = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB);
+		ASSERT(hub);
+
+		/* See if the port's active */
+		if (hub->hub_port.port_nasid == INVALID_NASID) {
+			GRPRINTF(("klhwg_connect_hubs: port inactive.\n"));
+			continue;
+		}
+
+		if (is_specified(arg_maxnodes) && NASID_TO_COMPACT_NODEID(hub->hub_port.port_nasid) == INVALID_CNODEID)
+			continue;
+
+		/* Generate a hardware graph path for this board. */
+		board_to_path(brd, path_buffer);
+
+		GRPRINTF(("klhwg_connect_hubs: Hub path is %s.\n", path_buffer));
+		rc = hwgraph_traverse(hwgraph_root, path_buffer, &hub_hndl);
+
+		if (rc != GRAPH_SUCCESS)
+			printk(KERN_WARNING  "Can't find hub: %s", path_buffer);
+
+		dest_brd = (lboard_t *)NODE_OFFSET_TO_K0(
+				hub->hub_port.port_nasid,
+				hub->hub_port.port_offset);
+
+		/* Generate a hardware graph path for this board. */
+		board_to_path(dest_brd, dest_path);
+
+		rc = hwgraph_traverse(hwgraph_root, dest_path, &dest_hndl);
+
+		if (rc != GRAPH_SUCCESS) {
+			if (is_specified(arg_maxnodes) && KL_CONFIG_DUPLICATE_BOARD(dest_brd))
+				continue;
+			PRINT_PANIC("Can't find board: %s", dest_path);
+		} else {
+		
+
+			GRPRINTF(("klhwg_connect_hubs: Link from %s to %s.\n",
+			  path_buffer, dest_path));
+
+			rc = hwgraph_edge_add(hub_hndl, dest_hndl, EDGE_LBL_INTERCONNECT);
+
+			if (rc != GRAPH_SUCCESS)
+				PRINT_PANIC("Can't create edge: %s/%s to vertex 0x%p, error 0x%x\n",
+				path_buffer, dest_path, (void *)dest_hndl, rc);
+
+		}
+	}
+}
+
+/* Store the pci/vme disabled board information as extended administrative
+ * hints which can later be used by the drivers using the device/driver
+ * admin interface. 
+ */
+void
+klhwg_device_disable_hints_add(void)
+{
+	cnodeid_t	cnode; 		/* node we are looking at */
+	nasid_t		nasid;		/* nasid of the node */
+	lboard_t	*board;		/* board we are looking at */
+	int		comp_index;	/* component index */
+	klinfo_t	*component;	/* component in the board we are
+					 * looking at 
+					 */
+	char		device_name[MAXDEVNAME];
+	
+	for(cnode = 0; cnode < numnodes; cnode++) {
+		nasid = COMPACT_TO_NASID_NODEID(cnode);
+		board = (lboard_t *)KL_CONFIG_INFO(nasid);
+		/* Check out all the board info stored  on a node */
+		while(board) {
+			/* No need to look at duplicate boards or non-io 
+			 * boards
+			 */
+			if (KL_CONFIG_DUPLICATE_BOARD(board) ||
+			    KLCLASS(board->brd_type) != KLCLASS_IO) {
+				board = KLCF_NEXT(board);
+				continue;
+			}
+			/* Check out all the components of a board */
+			for (comp_index = 0; 
+			     comp_index < KLCF_NUM_COMPS(board);
+			     comp_index++) {
+				component = KLCF_COMP(board,comp_index);
+				/* If the component is enabled move on to
+				 * the next component
+				 */
+				if (KLCONFIG_INFO_ENABLED(component))
+					continue;
+				/* NOTE : Since the prom only supports
+				 * the disabling of pci devices the following
+				 * piece of code makes sense. 
+				 * Make sure that this assumption is valid
+				 */
+				/* This component is disabled. Store this
+				 * hint in the extended device admin table
+				 */
+				/* Get the canonical name of the pci device */
+				device_component_canonical_name_get(board,
+							    component,
+							    device_name);
+#ifdef DEBUG
+				printf("%s DISABLED\n",device_name);
+#endif				
+			}
+			/* go to the next board info stored on this 
+			 * node 
+			 */
+			board = KLCF_NEXT(board);
+		}
+	}
+}
+
+void
+klhwg_add_all_modules(devfs_handle_t hwgraph_root)
+{
+	cmoduleid_t	cm;
+	char		name[128];
+	devfs_handle_t	vhdl;
+	int		rc;
+	char		buffer[16];
+
+	/* Add devices under each module */
+
+	for (cm = 0; cm < nummodules; cm++) {
+		/* Use module as module vertex fastinfo */
+
+#ifdef __ia64
+		memset(buffer, 0, 16);
+		format_module_id(buffer, modules[cm]->id, MODULE_FORMAT_BRIEF);
+		sprintf(name, EDGE_LBL_MODULE "/%s", buffer);
+#else
+		sprintf(name, EDGE_LBL_MODULE "/%x", modules[cm]->id);
+#endif
+
+		rc = hwgraph_path_add(hwgraph_root, name, &vhdl);
+		ASSERT(rc == GRAPH_SUCCESS);
+		rc = rc;
+
+		hwgraph_fastinfo_set(vhdl, (arbitrary_info_t) modules[cm]);
+
+		/* Add system controller */
+
+#ifdef __ia64
+		sprintf(name,
+			EDGE_LBL_MODULE "/%s/" EDGE_LBL_L1,
+			buffer);
+#else
+		sprintf(name,
+			EDGE_LBL_MODULE "/%x/" EDGE_LBL_L1,
+			modules[cm]->id);
+#endif
+
+		rc = hwgraph_path_add(hwgraph_root, name, &vhdl);
+		ASSERT_ALWAYS(rc == GRAPH_SUCCESS); 
+		rc = rc;
+
+		hwgraph_info_add_LBL(vhdl,
+				     INFO_LBL_ELSC,
+				     (arbitrary_info_t) (__psint_t) 1);
+
+#ifdef	LATER
+		sndrv_attach(vhdl);
+		/*
+		 * We need to call the drivers attach routine ..
+		 */
+		FIXME("klhwg_add_all_modules: Need code to call driver attach.\n");
+#endif
+	}
+}
+
+void
+klhwg_add_all_nodes(devfs_handle_t hwgraph_root)
+{
+	cnodeid_t	cnode;
+
+	for (cnode = 0; cnode < numnodes; cnode++) {
+		klhwg_add_node(hwgraph_root, cnode, NULL);
+	}
+
+	for (cnode = 0; cnode < numnodes; cnode++) {
+		klhwg_add_xbow(cnode, cnodeid_to_nasid(cnode));
+	}
+
+	/*
+	 * As for router hardware inventory information, we set this
+	 * up in router.c. 
+	 */
+	
+	klhwg_add_all_routers(hwgraph_root);
+	klhwg_connect_routers(hwgraph_root);
+	klhwg_connect_hubs(hwgraph_root);
+
+	/* Go through the entire system's klconfig
+	 * to figure out which pci components have been disabled
+	 */
+	klhwg_device_disable_hints_add();
+
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn1/l1.c linux-2.4.21-pre6/arch/ia64/sn/io/sn1/l1.c
--- linux-2.4.20/arch/ia64/sn/io/sn1/l1.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn1/l1.c	2003-03-26 23:49:35.000000000 +0000
@@ -0,0 +1,3124 @@
+/* $Id: l1.c,v 1.2 2002/11/16 02:23:19 steiner 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) 1992-1997, 2000-2002 Silicon Graphics, Inc.  All rights reserved.
+ */
+
+/* In general, this file is organized in a hierarchy from lower-level
+ * to higher-level layers, as follows:
+ *
+ *	UART routines
+ *	Bedrock/L1 "PPP-like" protocol implementation
+ *	System controller "message" interface (allows multiplexing
+ *		of various kinds of requests and responses with
+ *		console I/O)
+ *	Console interface:
+ *	  "l1_cons", the glue that allows the L1 to act
+ *		as the system console for the stdio libraries
+ *
+ * Routines making use of the system controller "message"-style interface
+ * can be found in l1_command.c.
+ */
+
+
+#include <linux/types.h>
+#include <linux/config.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/io.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/hcl_util.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/eeprom.h>
+#include <asm/sn/router.h>
+#include <asm/sn/module.h>
+#include <asm/sn/ksys/l1.h>
+#include <asm/sn/nodepda.h>
+#include <asm/sn/clksupport.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/sn_cpuid.h>
+#include <asm/sn/uart16550.h>
+#include <asm/sn/simulator.h>
+
+
+/* Make all console writes atomic */
+#define SYNC_CONSOLE_WRITE	1
+
+
+/*********************************************************************
+ * Hardware-level (UART) driver routines.
+ */
+
+/* macros for reading/writing registers */
+
+/* USLD and USSD are needed for SN2 - but since we moving this code out soon ... */
+#define LD(x)			(*(volatile uint64_t *)(x))
+#define USLD(x)			LD(x)			// (*(volatile ushort *)(x))
+#define SD(x, v)        	(LD(x) = (uint64_t) (v))
+#define USSD(x, v)        	SD(x,v)			// (USLD(x) = (ushort) (v))
+
+/* location of uart receive/xmit data register */
+#define L1_UART_BASE(n)		((ulong)REMOTE_HSPEC_ADDR((n), 0x00000080))
+#define LOCK_HUB		REMOTE_HUB_ADDR
+
+#define ADDR_L1_REG(n, r)	( L1_UART_BASE(n) | ( (r) << 3 ) )
+#define READ_L1_UART_REG(n, r)  ( LD(ADDR_L1_REG((n), (r))) )
+
+#define WRITE_L1_UART_REG(n, r, v) ( SD(ADDR_L1_REG((n), (r)), (v)) )
+
+/* upper layer interface calling methods */
+#define SERIAL_INTERRUPT_MODE	0
+#define SERIAL_POLLED_MODE	1
+
+
+/* UART-related #defines */
+
+#define UART_BAUD_RATE		57600
+#define UART_FIFO_DEPTH		16
+#define UART_DELAY_SPAN		10
+#define UART_PUTC_TIMEOUT	50000
+#define UART_INIT_TIMEOUT	100000
+
+/* error codes */
+#define UART_SUCCESS		  0
+#define UART_TIMEOUT		(-1)
+#define UART_LINK		(-2)
+#define UART_NO_CHAR		(-3)
+#define UART_VECTOR		(-4)
+
+#define UART_DELAY(x)		udelay(x)
+
+/* Some debug counters */
+#define L1C_INTERRUPTS		0
+#define L1C_OUR_R_INTERRUPTS	1
+#define L1C_OUR_X_INTERRUPTS	2
+#define L1C_SEND_CALLUPS	3
+#define L1C_RECEIVE_CALLUPS	4
+#define L1C_SET_BAUD		5
+#define L1C_ALREADY_LOCKED	L1C_SET_BAUD
+#define L1C_R_IRQ		6
+#define L1C_R_IRQ_RET		7
+#define L1C_LOCK_TIMEOUTS	8
+#define L1C_LOCK_COUNTER	9
+#define L1C_UNLOCK_COUNTER	10
+#define L1C_REC_STALLS		11
+#define L1C_CONNECT_CALLS	12
+#define L1C_SIZE		L1C_CONNECT_CALLS	/* Set to the last one */
+
+uint64_t L1_collectibles[L1C_SIZE + 1];
+
+
+/*
+ *	Some macros for handling Endian-ness
+ */
+
+#define COPY_INT_TO_BUFFER(_b, _i, _n)		\
+	{					\
+		_b[_i++] = (_n >> 24) & 0xff;	\
+		_b[_i++] = (_n >> 16) & 0xff;	\
+		_b[_i++] = (_n >>  8) & 0xff;	\
+		_b[_i++] =  _n        & 0xff;	\
+	}
+
+#define COPY_BUFFER_TO_INT(_b, _i, _n)		\
+	{					\
+		_n  = (_b[_i++] << 24) & 0xff;	\
+		_n |= (_b[_i++] << 16) & 0xff;	\
+		_n |= (_b[_i++] <<  8) & 0xff;	\
+		_n |=  _b[_i++]        & 0xff;	\
+	}
+
+#define COPY_BUFFER_TO_BUFFER(_b, _i, _bn)	\
+	{					\
+	    char *_xyz = (char *)_bn;		\
+	    _xyz[3] = _b[_i++];			\
+	    _xyz[2] = _b[_i++];			\
+	    _xyz[1] = _b[_i++];			\
+	    _xyz[0] = _b[_i++];			\
+	}
+
+void snia_kmem_free(void *where, int size);
+
+#define ALREADY_LOCKED		1
+#define NOT_LOCKED		0
+static int early_l1_serial_out(nasid_t, char *, int, int /* defines above*/ );
+
+#define BCOPY(x,y,z)	memcpy(y,x,z)
+
+uint8_t L1_interrupts_connected;		/* Non-zero when we are in interrupt mode */
+
+
+/*
+ * Console locking defines and functions.
+ *
+ */
+
+uint8_t L1_cons_is_inited = 0;			/* non-zero when console is init'd */
+nasid_t Master_console_nasid = (nasid_t)-1;
+extern nasid_t console_nasid;
+
+u64 ia64_sn_get_console_nasid(void);
+
+inline nasid_t
+get_master_nasid(void)
+{
+	nasid_t nasid = Master_console_nasid;
+
+	master_nasid = Master_console_nasid = nasid = 0;
+	if ( nasid == (nasid_t)-1 ) {
+		nasid = (nasid_t)ia64_sn_get_console_nasid();
+		if ( (nasid < 0) || (nasid >= MAX_NASIDS) ) {
+			/* Out of bounds, use local */
+			console_nasid = nasid = get_nasid();
+		}
+		else {
+			/* Got a valid nasid, set the console_nasid */
+			char xx[100];
+/* zzzzzz - force nasid to 0 for now */
+			sprintf(xx, "Master console is set to nasid %d (%d)\n", 0, (int)nasid);
+nasid = 0;
+/* end zzzzzz */
+			xx[99] = (char)0;
+			early_l1_serial_out(nasid, xx, strlen(xx), NOT_LOCKED);
+			Master_console_nasid = console_nasid = nasid;
+		}
+	}
+	return(nasid);
+}
+
+
+
+#define HUB_LOCK		16
+
+#define PRIMARY_LOCK_TIMEOUT    10000000
+#define HUB_LOCK_REG(n)         LOCK_HUB(n, MD_PERF_CNT0)
+
+#define SET_BITS(reg, bits)     SD(reg, LD(reg) |  (bits))
+#define CLR_BITS(reg, bits)     SD(reg, LD(reg) & ~(bits))
+#define TST_BITS(reg, bits)     ((LD(reg) & (bits)) != 0)
+
+#define HUB_TEST_AND_SET(n)	LD(LOCK_HUB(n,LB_SCRATCH_REG3_RZ))
+#define HUB_CLEAR(n)		SD(LOCK_HUB(n,LB_SCRATCH_REG3),0)
+
+#define RTC_TIME_MAX		((rtc_time_t) ~0ULL)
+
+/*
+ * primary_lock
+ *
+ *   Allows CPU's 0-3  to mutually exclude the hub from one another by
+ *   obtaining a blocking lock.  Does nothing if only one CPU is active.
+ *
+ *   This lock should be held just long enough to set or clear a global
+ *   lock bit.  After a relatively short timeout period, this routine
+ *   figures something is wrong, and steals the lock. It does not set
+ *   any other CPU to "dead".
+ */
+inline void
+primary_lock(nasid_t nasid)
+{
+	rtc_time_t          expire;
+
+	expire = rtc_time() + PRIMARY_LOCK_TIMEOUT;
+
+	while (HUB_TEST_AND_SET(nasid)) {
+		if (rtc_time() > expire) {
+			HUB_CLEAR(nasid);
+		}
+	}
+}
+
+/*
+ * primary_unlock (internal)
+ *
+ *   Counterpart to primary_lock
+ */
+
+inline void
+primary_unlock(nasid_t nasid)
+{
+	HUB_CLEAR(nasid);
+}
+
+/*
+ * hub_unlock
+ *
+ *   Counterpart to hub_lock_timeout and hub_lock
+ */
+
+inline void
+hub_unlock(nasid_t nasid, int level)
+{
+	uint64_t mask = 1ULL << level;
+
+	primary_lock(nasid);
+	CLR_BITS(HUB_LOCK_REG(nasid), mask);
+	primary_unlock(nasid);
+}
+
+/*
+ * hub_lock_timeout
+ *
+ *   Uses primary_lock to implement multiple lock levels.
+ *
+ *   There are 20 lock levels from 0 to 19 (limited by the number of bits
+ *   in HUB_LOCK_REG).  To prevent deadlock, multiple locks should be
+ *   obtained in order of increasingly higher level, and released in the
+ *   reverse order.
+ *
+ *   A timeout value of 0 may be used for no timeout.
+ *
+ *   Returns 0 if successful, -1 if lock times out.
+ */
+
+inline int
+hub_lock_timeout(nasid_t nasid, int level, rtc_time_t timeout)
+{
+	uint64_t mask = 1ULL << level;
+	rtc_time_t expire = (timeout ?  rtc_time() + timeout : RTC_TIME_MAX);
+	int done    = 0;
+
+	while (! done) {
+		while (TST_BITS(HUB_LOCK_REG(nasid), mask)) {
+			if (rtc_time() > expire)
+				return -1;
+		}
+
+		primary_lock(nasid);
+
+		if (! TST_BITS(HUB_LOCK_REG(nasid), mask)) {
+			SET_BITS(HUB_LOCK_REG(nasid), mask);
+			done = 1;
+		}
+		primary_unlock(nasid);
+	}
+	return 0;
+}
+
+
+#define LOCK_TIMEOUT	(0x1500000 * 1) /* 0x1500000 is ~30 sec */
+
+void
+lock_console(nasid_t nasid)
+{
+	int ret;
+
+	/* If we already have it locked, just return */
+	L1_collectibles[L1C_LOCK_COUNTER]++;
+
+	ret = hub_lock_timeout(nasid, HUB_LOCK, (rtc_time_t)LOCK_TIMEOUT);
+	if ( ret != 0 ) {
+		L1_collectibles[L1C_LOCK_TIMEOUTS]++;
+		/* timeout */
+		hub_unlock(nasid, HUB_LOCK);
+		/* If the 2nd lock fails, just pile ahead.... */
+		hub_lock_timeout(nasid, HUB_LOCK, (rtc_time_t)LOCK_TIMEOUT);
+		L1_collectibles[L1C_LOCK_TIMEOUTS]++;
+	}
+}
+
+inline void
+unlock_console(nasid_t nasid)
+{
+	L1_collectibles[L1C_UNLOCK_COUNTER]++;
+	hub_unlock(nasid, HUB_LOCK);
+}
+
+
+int 
+get_L1_baud(void)
+{
+    return UART_BAUD_RATE;
+}
+
+
+/* uart driver functions */
+
+static inline void
+uart_delay( rtc_time_t delay_span )
+{
+    UART_DELAY( delay_span );
+}
+
+#define UART_PUTC_READY(n)      (READ_L1_UART_REG((n), REG_LSR) & LSR_XHRE)
+
+static int
+uart_putc( l1sc_t *sc ) 
+{
+    WRITE_L1_UART_REG( sc->nasid, REG_DAT, sc->send[sc->sent] );
+    return UART_SUCCESS;
+}
+
+
+static int
+uart_getc( l1sc_t *sc )
+{
+    u_char lsr_reg = 0;
+    nasid_t nasid = sc->nasid;
+
+    if( (lsr_reg = READ_L1_UART_REG( nasid, REG_LSR )) & 
+	(LSR_RCA | LSR_PARERR | LSR_FRMERR) ) 
+    {
+	if( lsr_reg & LSR_RCA ) 
+	    return( (u_char)READ_L1_UART_REG( nasid, REG_DAT ) );
+	else if( lsr_reg & (LSR_PARERR | LSR_FRMERR) ) {
+	    return UART_LINK;
+	}
+    }
+    return UART_NO_CHAR;
+}
+
+
+#define PROM_SER_CLK_SPEED	12000000
+#define PROM_SER_DIVISOR(x)	(PROM_SER_CLK_SPEED / ((x) * 16))
+
+static void
+uart_init( l1sc_t *sc, int baud )
+{
+#if !defined(USE_SAL_CONSOLE_IO)
+    rtc_time_t expire;
+    int clkdiv;
+    nasid_t nasid;
+
+    clkdiv = PROM_SER_DIVISOR(baud);
+    expire = rtc_time() + UART_INIT_TIMEOUT;
+    nasid = sc->nasid;
+    
+    /* make sure the transmit FIFO is empty */
+    while( !(READ_L1_UART_REG( nasid, REG_LSR ) & LSR_XSRE) ) {
+	uart_delay( UART_DELAY_SPAN );
+	if( rtc_time() > expire ) {
+	    break;
+	}
+    }
+
+    if ( sc->uart == BRL1_LOCALHUB_UART )
+	lock_console(nasid);
+
+    /* Setup for the proper baud rate */
+    WRITE_L1_UART_REG( nasid, REG_LCR, LCR_DLAB );
+	uart_delay( UART_DELAY_SPAN );
+    WRITE_L1_UART_REG( nasid, REG_DLH, (clkdiv >> 8) & 0xff );
+	uart_delay( UART_DELAY_SPAN );
+    WRITE_L1_UART_REG( nasid, REG_DLL, clkdiv & 0xff );
+	uart_delay( UART_DELAY_SPAN );
+
+    /* set operating parameters and set DLAB to 0 */
+
+    /* 8bit, one stop, clear request to send, auto flow control */
+    WRITE_L1_UART_REG( nasid, REG_LCR, LCR_BITS8 | LCR_STOP1 );
+	uart_delay( UART_DELAY_SPAN );
+    WRITE_L1_UART_REG( nasid, REG_MCR, MCR_RTS | MCR_AFE );
+	uart_delay( UART_DELAY_SPAN );
+
+    /* disable interrupts */
+    WRITE_L1_UART_REG( nasid, REG_ICR, 0x0 );
+	uart_delay( UART_DELAY_SPAN );
+
+    /* enable FIFO mode and reset both FIFOs, trigger on 1 */
+    WRITE_L1_UART_REG( nasid, REG_FCR, FCR_FIFOEN );
+	uart_delay( UART_DELAY_SPAN );
+    WRITE_L1_UART_REG( nasid, REG_FCR, FCR_FIFOEN | FCR_RxFIFO | FCR_TxFIFO | RxLVL0);
+
+    if ( sc->uart == BRL1_LOCALHUB_UART )
+	unlock_console(nasid);
+#endif	/* !USE_SAL_CONSOLE_IO */
+}
+
+/* This requires the console lock */
+
+
+static void
+uart_intr_enable( l1sc_t *sc, u_char mask )
+{
+    u_char lcr_reg, icr_reg;
+    nasid_t nasid = sc->nasid;
+
+    if ( sc->uart == BRL1_LOCALHUB_UART )
+	lock_console(nasid);
+
+    /* make sure that the DLAB bit in the LCR register is 0
+     */
+    lcr_reg = READ_L1_UART_REG( nasid, REG_LCR );
+    lcr_reg &= ~(LCR_DLAB);
+    WRITE_L1_UART_REG( nasid, REG_LCR, lcr_reg );
+
+    /* enable indicated interrupts
+     */
+    icr_reg = READ_L1_UART_REG( nasid, REG_ICR );
+    icr_reg |= mask;
+    WRITE_L1_UART_REG( nasid, REG_ICR, icr_reg /*(ICR_RIEN | ICR_TIEN)*/ );
+
+    if ( sc->uart == BRL1_LOCALHUB_UART )
+	unlock_console(nasid);
+}
+
+/* This requires the console lock */
+static void
+uart_intr_disable( l1sc_t *sc, u_char mask )
+{
+    u_char lcr_reg, icr_reg;
+    nasid_t nasid = sc->nasid;
+
+    if ( sc->uart == BRL1_LOCALHUB_UART )
+	lock_console(nasid);
+
+    /* make sure that the DLAB bit in the LCR register is 0
+     */
+    lcr_reg = READ_L1_UART_REG( nasid, REG_LCR );
+    lcr_reg &= ~(LCR_DLAB);
+    WRITE_L1_UART_REG( nasid, REG_LCR, lcr_reg );
+
+    /* enable indicated interrupts
+     */
+    icr_reg = READ_L1_UART_REG( nasid, REG_ICR );
+    icr_reg &= mask;
+    WRITE_L1_UART_REG( nasid, REG_ICR, icr_reg /*(ICR_RIEN | ICR_TIEN)*/ );
+
+    if ( sc->uart == BRL1_LOCALHUB_UART )
+	unlock_console(nasid);
+}
+
+#define uart_enable_xmit_intr(sc) \
+	uart_intr_enable((sc), ICR_TIEN)
+
+#define uart_disable_xmit_intr(sc) \
+        uart_intr_disable((sc), ~(ICR_TIEN))
+
+#define uart_enable_recv_intr(sc) \
+        uart_intr_enable((sc), ICR_RIEN)
+
+#define uart_disable_recv_intr(sc) \
+        uart_intr_disable((sc), ~(ICR_RIEN))
+
+
+/*********************************************************************
+ * Routines for accessing a remote (router) UART
+ */
+
+#define READ_RTR_L1_UART_REG(p, n, r, v)		\
+    {							\
+	if( vector_read_node( (p), (n), 0,		\
+			      RR_JBUS1(r), (v) ) ) {	\
+	    return UART_VECTOR;				\
+	}						\
+    }
+
+#define WRITE_RTR_L1_UART_REG(p, n, r, v)		\
+    {							\
+	if( vector_write_node( (p), (n), 0,		\
+			       RR_JBUS1(r), (v) ) ) {	\
+	    return UART_VECTOR;				\
+	}						\
+    }
+
+#define RTR_UART_PUTC_TIMEOUT	UART_PUTC_TIMEOUT*10
+#define RTR_UART_DELAY_SPAN	UART_DELAY_SPAN
+#define RTR_UART_INIT_TIMEOUT	UART_INIT_TIMEOUT*10
+
+static int
+rtr_uart_putc( l1sc_t *sc )
+{
+    uint64_t regval, c;
+    nasid_t nasid = sc->nasid;
+    net_vec_t path = sc->uart;
+    rtc_time_t expire = rtc_time() + RTR_UART_PUTC_TIMEOUT;
+
+    c = (sc->send[sc->sent] & 0xffULL);
+    
+    while( 1 ) 
+    {
+        /* Check for "tx hold reg empty" bit. */
+	READ_RTR_L1_UART_REG( path, nasid, REG_LSR, &regval );
+	if( regval & LSR_XHRE )
+	{
+	    WRITE_RTR_L1_UART_REG( path, nasid, REG_DAT, c );
+	    return UART_SUCCESS;
+	}
+
+	if( rtc_time() >= expire ) 
+	{
+	    return UART_TIMEOUT;
+	}
+	uart_delay( RTR_UART_DELAY_SPAN );
+    }
+}
+
+
+static int
+rtr_uart_getc( l1sc_t *sc )
+{
+    uint64_t regval;
+    nasid_t nasid = sc->nasid;
+    net_vec_t path = sc->uart;
+
+    READ_RTR_L1_UART_REG( path, nasid, REG_LSR, &regval );
+    if( regval & (LSR_RCA | LSR_PARERR | LSR_FRMERR) )
+    {
+	if( regval & LSR_RCA )
+	{
+	    READ_RTR_L1_UART_REG( path, nasid, REG_DAT, &regval );
+	    return( (int)regval );
+	}
+	else
+	{
+	    return UART_LINK;
+	}
+    }
+
+    return UART_NO_CHAR;
+}
+
+
+static int
+rtr_uart_init( l1sc_t *sc, int baud )
+{
+    rtc_time_t expire;
+    int clkdiv;
+    nasid_t nasid;
+    net_vec_t path;
+    uint64_t regval;
+
+    clkdiv = PROM_SER_DIVISOR(baud);
+    expire = rtc_time() + RTR_UART_INIT_TIMEOUT;
+    nasid = sc->nasid;
+    path = sc->uart;
+
+    /* make sure the transmit FIFO is empty */
+    while(1) {
+	READ_RTR_L1_UART_REG( path, nasid, REG_LSR, &regval );
+	if( regval & LSR_XSRE ) {
+	    break;
+	}
+	if( rtc_time() > expire ) {
+	    break;
+	}
+	uart_delay( RTR_UART_DELAY_SPAN );
+    }
+
+    WRITE_RTR_L1_UART_REG( path, nasid, REG_LCR, LCR_DLAB  );
+	uart_delay( UART_DELAY_SPAN );
+    WRITE_RTR_L1_UART_REG( path, nasid, REG_DLH, (clkdiv >> 8) & 0xff  );
+	uart_delay( UART_DELAY_SPAN );
+    WRITE_RTR_L1_UART_REG( path, nasid, REG_DLL, clkdiv & 0xff  );
+	uart_delay( UART_DELAY_SPAN );
+
+    /* set operating parameters and set DLAB to 0 */
+    WRITE_RTR_L1_UART_REG( path, nasid, REG_LCR, LCR_BITS8 | LCR_STOP1  );
+	uart_delay( UART_DELAY_SPAN );
+    WRITE_RTR_L1_UART_REG( path, nasid, REG_MCR, MCR_RTS | MCR_AFE  );
+	uart_delay( UART_DELAY_SPAN );
+
+    /* disable interrupts */
+    WRITE_RTR_L1_UART_REG( path, nasid, REG_ICR, 0x0  );
+	uart_delay( UART_DELAY_SPAN );
+
+    /* enable FIFO mode and reset both FIFOs */
+    WRITE_RTR_L1_UART_REG( path, nasid, REG_FCR, FCR_FIFOEN  );
+	uart_delay( UART_DELAY_SPAN );
+    WRITE_RTR_L1_UART_REG( path, nasid, REG_FCR,
+	FCR_FIFOEN | FCR_RxFIFO | FCR_TxFIFO );
+
+    return 0;
+}
+
+/*********************************************************************
+ * locking macros 
+ */
+
+#define L1SC_SEND_LOCK(l,p)   { if ((l)->uart == BRL1_LOCALHUB_UART) spin_lock_irqsave(&((l)->send_lock),p); }
+#define L1SC_SEND_UNLOCK(l,p) { if ((l)->uart == BRL1_LOCALHUB_UART) spin_unlock_irqrestore(&((l)->send_lock), p); }
+#define L1SC_RECV_LOCK(l,p)   { if ((l)->uart == BRL1_LOCALHUB_UART) spin_lock_irqsave(&((l)->recv_lock), p); } 
+#define L1SC_RECV_UNLOCK(l,p) { if ((l)->uart == BRL1_LOCALHUB_UART) spin_unlock_irqrestore(&((l)->recv_lock), p); }
+
+
+/*********************************************************************
+ * subchannel manipulation 
+ *
+ * The SUBCH_[UN]LOCK macros are used to arbitrate subchannel
+ * allocation.  SUBCH_DATA_[UN]LOCK control access to data structures
+ * associated with particular subchannels (e.g., receive queues).
+ *
+ */
+#define SUBCH_LOCK(sc, p)		spin_lock_irqsave( &((sc)->subch_lock), p )
+#define SUBCH_UNLOCK(sc, p)		spin_unlock_irqrestore( &((sc)->subch_lock), p )
+#define SUBCH_DATA_LOCK(sbch, p) 	spin_lock_irqsave( &((sbch)->data_lock), p )
+#define SUBCH_DATA_UNLOCK(sbch, p)	spin_unlock_irqrestore( &((sbch)->data_lock), p )
+
+
+/*
+ * set a function to be called for subchannel ch in the event of
+ * a transmission low-water interrupt from the uart
+ */
+void
+subch_set_tx_notify( l1sc_t *sc, int ch, brl1_notif_t func )
+{
+    unsigned long pl = 0;
+
+    L1SC_SEND_LOCK( sc, pl );
+#if	!defined(SYNC_CONSOLE_WRITE)
+    if ( func && !sc->send_in_use )
+	uart_enable_xmit_intr( sc );
+#endif
+    sc->subch[ch].tx_notify = func;
+    L1SC_SEND_UNLOCK(sc, pl );
+}
+
+/*
+ * set a function to be called for subchannel ch when data is received
+ */
+void
+subch_set_rx_notify( l1sc_t *sc, int ch, brl1_notif_t func )
+{
+    unsigned long pl = 0;
+    brl1_sch_t *subch = &(sc->subch[ch]);
+
+    SUBCH_DATA_LOCK( subch, pl );
+    sc->subch[ch].rx_notify = func;
+    SUBCH_DATA_UNLOCK( subch, pl );
+}
+
+/*********************************************************************
+ * Queue manipulation macros
+ *
+ *
+ */
+#define NEXT(p)         (((p) + 1) & (BRL1_QSIZE-1)) /* assume power of 2 */
+
+#define cq_init(q)      bzero((q), sizeof (*(q)))
+#define cq_empty(q)     ((q)->ipos == (q)->opos)
+#define cq_full(q)      (NEXT((q)->ipos) == (q)->opos)
+#define cq_used(q)      ((q)->opos <= (q)->ipos ?                       \
+                         (q)->ipos - (q)->opos :                        \
+                         BRL1_QSIZE + (q)->ipos - (q)->opos)
+#define cq_room(q)      ((q)->opos <= (q)->ipos ?                       \
+                         BRL1_QSIZE - 1 + (q)->opos - (q)->ipos :       \
+                         (q)->opos - (q)->ipos - 1)
+#define cq_add(q, c)    ((q)->buf[(q)->ipos] = (u_char) (c),            \
+                         (q)->ipos = NEXT((q)->ipos))
+#define cq_rem(q, c)    ((c) = (q)->buf[(q)->opos],                     \
+                         (q)->opos = NEXT((q)->opos))
+#define cq_discard(q)	((q)->opos = NEXT((q)->opos))
+
+#define cq_tent_full(q)	(NEXT((q)->tent_next) == (q)->opos)
+#define cq_tent_len(q)	((q)->ipos <= (q)->tent_next ?			\
+			 (q)->tent_next - (q)->ipos :			\
+			 BRL1_QSIZE + (q)->tent_next - (q)->ipos)
+#define cq_tent_add(q, c)						\
+			((q)->buf[(q)->tent_next] = (u_char) (c),	\
+			 (q)->tent_next = NEXT((q)->tent_next))
+#define cq_commit_tent(q)						\
+			((q)->ipos = (q)->tent_next)
+#define cq_discard_tent(q)						\
+			((q)->tent_next = (q)->ipos)
+
+
+
+
+/*********************************************************************
+ * CRC-16 (for checking bedrock/L1 packets).
+ *
+ * These are based on RFC 1662 ("PPP in HDLC-like framing").
+ */
+
+static unsigned short fcstab[256] = {
+      0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+      0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+      0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+      0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+      0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+      0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+      0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+      0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+      0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+      0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+      0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+      0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+      0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+      0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+      0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+      0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+      0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+      0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+      0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+      0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+      0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+      0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+      0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+      0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+      0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+      0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+      0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+      0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+      0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+      0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+      0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+      0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
+
+#define INIT_CRC	0xFFFF	/* initial CRC value	  */
+#define	GOOD_CRC	0xF0B8	/* "good" final CRC value */
+
+static unsigned short crc16_calc( unsigned short crc, u_char c )
+{
+    return( (crc >> 8) ^ fcstab[(crc ^ c) & 0xff] );
+}
+
+
+/***********************************************************************
+ * The following functions implement the PPP-like bedrock/L1 protocol
+ * layer.
+ *
+ */
+
+#define BRL1_FLAG_CH	0x7e
+#define BRL1_ESC_CH	0x7d
+#define BRL1_XOR_CH	0x20
+
+/* L1<->Bedrock packet types */
+#define BRL1_REQUEST    0x00
+#define BRL1_RESPONSE   0x20
+#define BRL1_EVENT      0x40
+
+#define BRL1_PKT_TYPE_MASK      0xE0
+#define BRL1_SUBCH_MASK         0x1F
+
+#define PKT_TYPE(tsb)   ((tsb) & BRL1_PKT_TYPE_MASK)
+#define SUBCH(tsb)	((tsb) & BRL1_SUBCH_MASK)
+
+/* timeouts */
+#define BRL1_INIT_TIMEOUT	500000
+
+/*
+ * brl1_discard_packet is a dummy "receive callback" used to get rid
+ * of packets we don't want
+ */
+void brl1_discard_packet( int dummy0, void *dummy1, struct pt_regs *dummy2, l1sc_t *sc, int ch )
+{
+    unsigned long pl = 0;
+    brl1_sch_t *subch = &sc->subch[ch];
+
+    sc_cq_t *q = subch->iqp;
+    SUBCH_DATA_LOCK( subch, pl );
+    q->opos = q->ipos;
+    atomic_set(&(subch->packet_arrived), 0);
+    SUBCH_DATA_UNLOCK( subch, pl );
+}
+
+
+/*
+ * brl1_send_chars sends the send buffer in the l1sc_t structure
+ * out through the uart.  Assumes that the caller has locked the
+ * UART (or send buffer in the kernel).
+ *
+ * This routine doesn't block-- if you want it to, call it in
+ * a loop.
+ */
+static int
+brl1_send_chars( l1sc_t *sc )
+{
+    /* We track the depth of the C brick's UART's
+     * fifo in software, and only check if the UART is accepting
+     * characters when our count indicates that the fifo should
+     * be full.
+     *
+     * For remote (router) UARTs, we check with the UART before sending every
+     * character.
+     */
+    if( sc->uart == BRL1_LOCALHUB_UART ) {
+	if( !(sc->fifo_space) && UART_PUTC_READY( sc->nasid ) )
+	    sc->fifo_space = UART_FIFO_DEPTH;
+	
+	while( (sc->sent < sc->send_len) && (sc->fifo_space) ) {
+	    uart_putc( sc );
+	    sc->fifo_space--;
+	    sc->sent++;
+	}
+    }
+    else {
+
+	/* remote (router) UARTs */
+
+	int result;
+	int tries = 0;
+
+	while( sc->sent < sc->send_len ) {
+	    result = sc->putc_f( sc );
+	    if( result >= 0 ) {
+		(sc->sent)++;
+		continue;
+	    }
+	    if( result == UART_TIMEOUT ) {
+		tries++;
+		/* send this character in TIMEOUT_RETRIES... */
+		if( tries < 30 /* TIMEOUT_RETRIES */ ) {
+		    continue;
+		}
+		/* ...or else... */
+		else {
+		    /* ...drop the packet. */
+		    sc->sent = sc->send_len;
+		    return sc->send_len;
+		}
+	    }
+	    if( result < 0 ) {
+		return result;
+	    }
+	}
+    }
+    return sc->sent;
+}
+
+
+/* brl1_send formats up a packet and (at least begins to) send it
+ * to the uart.  If the send buffer is in use when this routine obtains
+ * the lock, it will behave differently depending on the "wait" parameter.
+ * For wait == 0 (most I/O), it will return 0 (as in "zero bytes sent"),
+ * hopefully encouraging the caller to back off (unlock any high-level 
+ * spinlocks) and allow the buffer some time to drain.  For wait==1 (high-
+ * priority I/O along the lines of kernel error messages), we will flush
+ * the current contents of the send buffer and beat on the uart
+ * until our message has been completely transmitted.
+ */
+
+static int
+brl1_send( l1sc_t *sc, char *msg, int len, u_char type_and_subch, int wait )
+{
+    unsigned long pl = 0;
+    int index;
+    int pkt_len = 0;
+    unsigned short crc = INIT_CRC;
+    char *send_ptr = sc->send;
+
+
+    if( sc->send_in_use && !(wait) ) {
+	/* We are in the middle of sending, but can wait until done */
+	return 0;
+    }
+    else if( sc->send_in_use ) {
+	/* buffer's in use, but we're synchronous I/O, so we're going
+	 * to send whatever's in there right now and take the buffer
+	 */
+	int counter = 0;
+
+	if ( sc->uart == BRL1_LOCALHUB_UART )
+		lock_console(sc->nasid);
+	L1SC_SEND_LOCK(sc, pl);
+	while( sc->sent < sc->send_len ) {
+		brl1_send_chars( sc );
+		if ( counter++ > 0xfffff ) {
+			char *str = "Looping waiting for uart to clear (1)\n";
+			early_l1_serial_out(sc->nasid, str, strlen(str), ALREADY_LOCKED);
+			break;
+		}
+	}
+    }
+    else {
+	if ( sc->uart == BRL1_LOCALHUB_UART )
+		lock_console(sc->nasid);
+	L1SC_SEND_LOCK(sc, pl);
+	sc->send_in_use = 1;
+    }
+    *send_ptr++ = BRL1_FLAG_CH;
+    *send_ptr++ = type_and_subch;
+    pkt_len += 2;
+    crc = crc16_calc( crc, type_and_subch );
+
+    /* limit number of characters accepted to max payload size */
+    if( len > (BRL1_QSIZE - 1) )
+	len = (BRL1_QSIZE - 1);
+
+    /* copy in the message buffer (inserting PPP 
+     * framing info where necessary)
+     */
+    for( index = 0; index < len; index++ ) {
+
+	switch( *msg ) {
+	    
+	  case BRL1_FLAG_CH:
+	    *send_ptr++ = BRL1_ESC_CH;
+	    *send_ptr++ = (*msg) ^ BRL1_XOR_CH;
+	    pkt_len += 2;
+	    break;
+	    
+	  case BRL1_ESC_CH:
+	    *send_ptr++ = BRL1_ESC_CH;
+	    *send_ptr++ = (*msg) ^ BRL1_XOR_CH;
+	    pkt_len += 2;
+	    break;
+	    
+	  default:
+	    *send_ptr++ = *msg;
+	    pkt_len++;
+	}
+	crc = crc16_calc( crc, *msg );
+	msg++;
+    }
+    crc ^= 0xffff;
+
+    for( index = 0; index < sizeof(crc); index++ ) {
+	char crc_char = (char)(crc & 0x00FF);
+	if( (crc_char == BRL1_ESC_CH) || (crc_char == BRL1_FLAG_CH) ) {
+	    *send_ptr++ = BRL1_ESC_CH;
+	    pkt_len++;
+	    crc_char ^= BRL1_XOR_CH;
+	}
+	*send_ptr++ = crc_char;
+	pkt_len++;
+	crc >>= 8;
+    }
+    
+    *send_ptr++ = BRL1_FLAG_CH;
+    pkt_len++;
+
+    sc->send_len = pkt_len;
+    sc->sent = 0;
+
+    {
+	int counter = 0;
+	do {
+		brl1_send_chars( sc );
+		if ( counter++ > 0xfffff ) {
+			char *str = "Looping waiting for uart to clear (2)\n";
+			early_l1_serial_out(sc->nasid, str, strlen(str), ALREADY_LOCKED);
+			break;
+		}
+	} while( (sc->sent < sc->send_len) && wait );
+    }
+
+    if ( sc->uart == BRL1_LOCALHUB_UART )
+	unlock_console(sc->nasid);
+
+    if( sc->sent == sc->send_len ) {
+	/* success! release the send buffer and call the callup */
+#if	!defined(SYNC_CONSOLE_WRITE)
+	brl1_notif_t callup;
+#endif
+
+	sc->send_in_use = 0;
+	/* call any upper layer that's asked for notification */
+#if	defined(XX_SYNC_CONSOLE_WRITE)
+	/*
+	 * This is probably not a good idea - since the l1_ write func can be called multiple
+	 * time within the callup function.
+	 */
+	callup = subch->tx_notify;
+	if( callup && (SUBCH(type_and_subch) == SC_CONS_SYSTEM) ) {
+		L1_collectibles[L1C_SEND_CALLUPS]++;
+		(*callup)(sc->subch[SUBCH(type_and_subch)].irq_frame.bf_irq,
+				sc->subch[SUBCH(type_and_subch)].irq_frame.bf_dev_id,
+				sc->subch[SUBCH(type_and_subch)].irq_frame.bf_regs, sc, SUBCH(type_and_subch));
+	}
+#endif	/* SYNC_CONSOLE_WRITE */
+    }
+#if	!defined(SYNC_CONSOLE_WRITE)
+    else if ( !wait ) {
+	/* enable low-water interrupts so buffer will be drained */
+	uart_enable_xmit_intr(sc);
+    }
+#endif
+
+    L1SC_SEND_UNLOCK(sc, pl);
+
+    return len;
+}
+
+/* brl1_send_cont is intended to be called as an interrupt service
+ * routine.  It sends until the UART won't accept any more characters,
+ * or until an error is encountered (in which case we surrender the
+ * send buffer and give up trying to send the packet).  Once the
+ * last character in the packet has been sent, this routine releases
+ * the send buffer and calls any previously-registered "low-water"
+ * output routines.
+ */
+
+#if	!defined(SYNC_CONSOLE_WRITE)
+
+int
+brl1_send_cont( l1sc_t *sc )
+{
+    unsigned long pl = 0;
+    int done = 0;
+    brl1_notif_t callups[BRL1_NUM_SUBCHANS];
+    brl1_notif_t *callup;
+    brl1_sch_t *subch;
+    int index;
+
+    /*
+     * I'm not sure how I think this is to be handled - whether the lock is held
+     * over the interrupt - but it seems like it is a bad idea....
+     */
+
+    if ( sc->uart == BRL1_LOCALHUB_UART )
+	lock_console(sc->nasid);
+    L1SC_SEND_LOCK(sc, pl);
+    brl1_send_chars( sc );
+    done = (sc->sent == sc->send_len);
+    if( done ) {
+	sc->send_in_use = 0;
+#if	!defined(SYNC_CONSOLE_WRITE)
+	uart_disable_xmit_intr(sc);
+#endif
+    }
+    if ( sc->uart == BRL1_LOCALHUB_UART )
+	unlock_console(sc->nasid);
+    /* Release the lock */
+    L1SC_SEND_UNLOCK(sc, pl);
+
+    return 0;
+}
+#endif	/* SYNC_CONSOLE_WRITE */
+
+/* internal function -- used by brl1_receive to read a character 
+ * from the uart and check whether errors occurred in the process.
+ */
+static int
+read_uart( l1sc_t *sc, int *c, int *result )
+{
+    *c = sc->getc_f( sc );
+
+    /* no character is available */
+    if( *c == UART_NO_CHAR ) {
+	*result = BRL1_NO_MESSAGE;
+	return 0;
+    }
+
+    /* some error in UART */
+    if( *c < 0 ) {
+	*result = BRL1_LINK;
+	return 0;
+    }
+
+    /* everything's fine */
+    *result = BRL1_VALID;
+    return 1;
+}
+
+
+/*
+ * brl1_receive
+ *
+ * This function reads a Bedrock-L1 protocol packet into the l1sc_t
+ * response buffer.
+ *
+ * The operation of this function can be expressed as a finite state
+ * machine:
+ *
+
+START STATE			INPUT		TRANSITION
+==========================================================
+BRL1_IDLE (reset or error)	flag		BRL1_FLAG
+				other		BRL1_IDLE@
+
+BRL1_FLAG (saw a flag (0x7e))	flag		BRL1_FLAG
+				escape		BRL1_IDLE@
+				header byte	BRL1_HDR
+				other		BRL1_IDLE@
+
+BRL1_HDR (saw a type/subch byte)(see below)	BRL1_BODY
+						BRL1_HDR
+
+BRL1_BODY (reading packet body)	flag		BRL1_FLAG
+				escape		BRL1_ESC
+				other		BRL1_BODY
+
+BRL1_ESC (saw an escape (0x7d))	flag		BRL1_FLAG@
+				escape		BRL1_IDLE@
+				other		BRL1_BODY
+==========================================================
+
+"@" denotes an error transition.
+
+ * The BRL1_HDR state is a transient state which doesn't read input,
+ * but just provides a way in to code which decides to whom an
+ * incoming packet should be directed.
+ *
+ * brl1_receive can be used to poll for input from the L1, or as 
+ * an interrupt service routine.  It reads as much data as is
+ * ready from the junk bus UART and places into the appropriate
+ * input queues according to subchannel.  The header byte is
+ * stripped from console-type data, but is retained for message-
+ * type data (L1 responses).  A length byte will also be
+ * prepended to message-type packets.
+ *
+ * This routine is non-blocking; if the caller needs to block
+ * for input, it must call brl1_receive in a loop.
+ *
+ * brl1_receive returns when there is no more input, the queue
+ * for the current incoming message is full, or there is an
+ * error (parity error, bad header, bad CRC, etc.).
+ */
+
+#define STATE_SET(l,s)		((l)->brl1_state = (s))
+#define STATE_GET(l)		((l)->brl1_state)
+
+#define LAST_HDR_SET(l,h)	((l)->brl1_last_hdr = (h))
+#define LAST_HDR_GET(l)		((l)->brl1_last_hdr)
+
+#define VALID_HDR(c)				\
+    ( SUBCH((c)) <= SC_CONS_SYSTEM		\
+	? PKT_TYPE((c)) == BRL1_REQUEST		\
+	: ( PKT_TYPE((c)) == BRL1_RESPONSE ||	\
+	    PKT_TYPE((c)) == BRL1_EVENT ) )
+
+#define IS_TTY_PKT(l)		( SUBCH(LAST_HDR_GET(l)) <= SC_CONS_SYSTEM ? 1 : 0 )
+
+
+int
+brl1_receive( l1sc_t *sc, int mode )
+{
+    int result;		/* value to be returned by brl1_receive */
+    int c;		/* most-recently-read character	     	*/
+    int done;		/* set done to break out of recv loop	*/
+    unsigned long pl = 0, cpl = 0;
+    sc_cq_t *q;		/* pointer to queue we're working with	*/
+
+    result = BRL1_NO_MESSAGE;
+
+    L1SC_RECV_LOCK(sc, cpl);
+
+    done = 0;
+    while( !done )
+    {
+	switch( STATE_GET(sc) )
+	{
+
+	  case BRL1_IDLE:
+	    /* Initial or error state.  Waiting for a flag character
+             * to resynchronize with the L1.
+             */
+
+	    if( !read_uart( sc, &c, &result ) ) {
+
+		/* error reading uart */
+		done = 1;
+		continue;
+	    }
+	    
+	    if( c == BRL1_FLAG_CH ) {
+		/* saw a flag character */
+		STATE_SET( sc, BRL1_FLAG );
+		continue;
+	    }
+	    break;
+	    
+	  case BRL1_FLAG:
+	    /* One or more flag characters have been read; look for
+	     * the beginning of a packet (header byte).
+	     */
+	    
+	    if( !read_uart( sc, &c, &result ) ) {
+
+		/* error reading uart */
+		if( c != UART_NO_CHAR )
+		    STATE_SET( sc, BRL1_IDLE );
+
+		done = 1;
+		continue;
+	    }
+	    
+	    if( c == BRL1_FLAG_CH ) {
+		/* multiple flags are OK */
+		continue;
+	    }
+
+	    if( !VALID_HDR( c ) ) {
+		/* if c isn't a flag it should have been
+		 * a valid header, so we have an error
+		 */
+		result = BRL1_PROTOCOL;
+		STATE_SET( sc, BRL1_IDLE );
+		done = 1;
+		continue;
+	    }
+
+	    /* we have a valid header byte */
+	    LAST_HDR_SET( sc, c );
+	    STATE_SET( sc, BRL1_HDR );
+
+	    break; 
+
+	  case BRL1_HDR:
+	    /* A header byte has been read. Do some bookkeeping. */
+	    q = sc->subch[ SUBCH( LAST_HDR_GET(sc) ) ].iqp;
+	    ASSERT(q);
+	    
+	    if( !IS_TTY_PKT(sc) ) {
+		/* if this is an event or command response rather
+		 * than console I/O, we need to reserve a couple
+		 * of extra spaces in the queue for the header
+		 * byte and a length byte; if we can't, stay in
+		 * the BRL1_HDR state.
+		 */
+		if( cq_room( q ) < 2 ) {
+		    result = BRL1_FULL_Q;
+		    done = 1;
+		    continue;
+		}
+		cq_tent_add( q, 0 );			/* reserve length byte */
+		cq_tent_add( q, LAST_HDR_GET( sc ) );	/* record header byte  */
+	    }
+	    STATE_SET( sc, BRL1_BODY );
+
+	    break;
+
+	  case BRL1_BODY:
+	    /* A header byte has been read.  We are now attempting
+	     * to receive the packet body.
+	     */
+
+	    q = sc->subch[ SUBCH( LAST_HDR_GET(sc) ) ].iqp;
+	    ASSERT(q);
+
+	    /* if the queue we want to write into is full, don't read from
+	     * the uart (this provides backpressure to the L1 side)
+	     */
+	    if( cq_tent_full( q ) ) {
+		result = BRL1_FULL_Q;
+		done = 1;
+		continue;
+	    }
+	    
+	    if( !read_uart( sc, &c, &result ) ) {
+
+		/* error reading uart */
+		if( c != UART_NO_CHAR )
+		    STATE_SET( sc, BRL1_IDLE );
+		done = 1;
+		continue;
+	    }
+
+	    if( c == BRL1_ESC_CH ) {
+		/* prepare to unescape the next character */
+		STATE_SET( sc, BRL1_ESC );
+		continue;
+	    }
+	    
+	    if( c == BRL1_FLAG_CH ) {
+		/* flag signifies the end of a packet */
+
+		unsigned short crc;	/* holds the crc as we calculate it */
+		int i;			/* index variable */
+		brl1_sch_t *subch;      /* subchannel for received packet */
+		brl1_notif_t callup;	/* "data ready" callup */
+
+		/* whatever else may happen, we've seen a flag and we're
+		 * starting a new packet
+		 */
+		STATE_SET( sc, BRL1_FLAG );
+
+		/* if the packet body has less than 2 characters,
+		 * it can't be a well-formed packet.  Discard it.
+		 */
+		if( cq_tent_len( q ) < /* 2 + possible length byte */
+		    (2 + (IS_TTY_PKT(sc) ? 0 : 1)) )
+		{
+		    result = BRL1_PROTOCOL;
+		    cq_discard_tent( q );
+		    STATE_SET( sc, BRL1_FLAG );
+		    done = 1;
+		    continue;
+		}
+		
+		/* check CRC */
+
+		/* accumulate CRC, starting with the header byte and
+		 * ending with the transmitted CRC.  This should
+		 * result in a known good value.
+		 */
+		crc = crc16_calc( INIT_CRC, LAST_HDR_GET(sc) );
+		for( i = (q->ipos + (IS_TTY_PKT(sc) ? 0 : 2)) % BRL1_QSIZE;
+		     i != q->tent_next;
+		     i = (i + 1) % BRL1_QSIZE )
+		{
+		    crc = crc16_calc( crc, q->buf[i] );
+		}
+
+		/* verify the caclulated crc against the "good" crc value;
+		 * if we fail, discard the bad packet and return an error.
+		 */
+		if( crc != (unsigned short)GOOD_CRC ) {
+		    result = BRL1_CRC;
+		    cq_discard_tent( q );
+		    STATE_SET( sc, BRL1_FLAG );
+		    done = 1;
+		    continue;
+		}
+		
+		/* so the crc check was ok.  Now we discard the CRC
+		 * from the end of the received bytes.
+		 */
+		q->tent_next += (BRL1_QSIZE - 2);
+		q->tent_next %= BRL1_QSIZE;
+
+		/* get the subchannel and lock it */
+		subch = &(sc->subch[SUBCH( LAST_HDR_GET(sc) )]);
+		SUBCH_DATA_LOCK( subch, pl );
+		
+		/* if this isn't a console packet, we need to record
+		 * a length byte
+		 */
+		if( !IS_TTY_PKT(sc) ) {
+		    q->buf[q->ipos] = cq_tent_len( q ) - 1;
+		}
+		
+		/* record packet for posterity */
+		cq_commit_tent( q );
+		result = BRL1_VALID;
+
+		/* notify subchannel owner that there's something
+		 * on the queue for them
+		 */
+		atomic_inc(&(subch->packet_arrived));
+		callup = subch->rx_notify;
+		SUBCH_DATA_UNLOCK( subch, pl );
+
+		if( callup && (mode == SERIAL_INTERRUPT_MODE) ) {
+		    L1SC_RECV_UNLOCK( sc, cpl );
+		    L1_collectibles[L1C_RECEIVE_CALLUPS]++;
+		    (*callup)( sc->subch[SUBCH(LAST_HDR_GET(sc))].irq_frame.bf_irq,
+				sc->subch[SUBCH(LAST_HDR_GET(sc))].irq_frame.bf_dev_id,
+				sc->subch[SUBCH(LAST_HDR_GET(sc))].irq_frame.bf_regs,
+				sc, SUBCH(LAST_HDR_GET(sc)) );
+		    L1SC_RECV_LOCK( sc, cpl );
+		}
+		continue;	/* go back for more! */
+	    }
+	    
+	    /* none of the special cases applied; we've got a normal
+	     * body character
+	     */
+	    cq_tent_add( q, c );
+
+	    break;
+
+	  case BRL1_ESC:
+	    /* saw an escape character.  The next character will need
+	     * to be unescaped.
+	     */
+
+	    q = sc->subch[ SUBCH( LAST_HDR_GET(sc) ) ].iqp;
+	    ASSERT(q);
+
+	    /* if the queue we want to write into is full, don't read from
+	     * the uart (this provides backpressure to the L1 side)
+	     */
+	    if( cq_tent_full( q ) ) {
+		result = BRL1_FULL_Q;
+		done = 1;
+		continue;
+	    }
+	    
+	    if( !read_uart( sc, &c, &result ) ) {
+
+		/* error reading uart */
+		if( c != UART_NO_CHAR ) {
+		    cq_discard_tent( q );
+		    STATE_SET( sc, BRL1_IDLE );
+		}
+		done = 1;
+		continue;
+	    }
+	    
+	    if( c == BRL1_FLAG_CH ) {
+		/* flag after escape is an error */
+		STATE_SET( sc, BRL1_FLAG );
+		cq_discard_tent( q );
+		result = BRL1_PROTOCOL;
+		done = 1;
+		continue;
+	    }
+
+	    if( c == BRL1_ESC_CH ) {
+		/* two consecutive escapes is an error */
+		STATE_SET( sc, BRL1_IDLE );
+		cq_discard_tent( q );
+		result = BRL1_PROTOCOL;
+		done = 1;
+		continue;
+	    }
+	    
+	    /* otherwise, we've got a character that needs
+	     * to be unescaped
+	     */
+	    cq_tent_add( q, (c ^ BRL1_XOR_CH) );
+	    STATE_SET( sc, BRL1_BODY );
+
+	    break;
+
+	} /* end of switch( STATE_GET(sc) ) */
+    } /* end of while(!done) */
+
+    L1SC_RECV_UNLOCK( sc, cpl );
+
+    return result;
+}	    
+
+
+/* brl1_init initializes the Bedrock/L1 protocol layer.  This includes
+ * zeroing out the send and receive state information.
+ */
+
+void
+brl1_init( l1sc_t *sc, nasid_t nasid, net_vec_t uart )
+{
+    int i;
+    brl1_sch_t *subch;
+
+    bzero( sc, sizeof( *sc ) );
+    sc->nasid = nasid;
+    sc->uart = uart;
+    sc->getc_f = (uart == BRL1_LOCALHUB_UART ? uart_getc : rtr_uart_getc);
+    sc->putc_f = (uart == BRL1_LOCALHUB_UART ? uart_putc : rtr_uart_putc);
+    sc->sol = 1;
+    subch = sc->subch;
+
+    /* initialize L1 subchannels
+     */
+
+    /* assign processor TTY channels */
+    for( i = 0; i < CPUS_PER_NODE; i++, subch++ ) {
+	subch->use = BRL1_SUBCH_RSVD;
+	subch->packet_arrived = ATOMIC_INIT(0);
+	spin_lock_init( &(subch->data_lock) );
+	sv_init( &(subch->arrive_sv), &(subch->data_lock), SV_MON_SPIN | SV_ORDER_FIFO /* | SV_INTS */ );
+	subch->tx_notify = NULL;
+	/* (for now, drop elscuart packets in the kernel) */
+	subch->rx_notify = brl1_discard_packet;
+	subch->iqp = &sc->garbage_q;
+    }
+
+    /* assign system TTY channel (first free subchannel after each
+     * processor's individual TTY channel has been assigned)
+     */
+    subch->use = BRL1_SUBCH_RSVD;
+    subch->packet_arrived = ATOMIC_INIT(0);
+    spin_lock_init( &(subch->data_lock) );
+    sv_init( &(subch->arrive_sv), &subch->data_lock, SV_MON_SPIN | SV_ORDER_FIFO /* | SV_INTS */ );
+    subch->tx_notify = NULL;
+    if( sc->uart == BRL1_LOCALHUB_UART ) {
+	subch->iqp = snia_kmem_zalloc_node( sizeof(sc_cq_t), KM_NOSLEEP, NASID_TO_COMPACT_NODEID(nasid) );
+	ASSERT( subch->iqp );
+	cq_init( subch->iqp );
+	subch->rx_notify = NULL;
+    }
+    else {
+	/* we shouldn't be getting console input from remote UARTs */
+	subch->iqp = &sc->garbage_q;
+	subch->rx_notify = brl1_discard_packet;
+    }
+    subch++; i++;
+
+    /* "reserved" subchannels (0x05-0x0F); for now, throw away
+     * incoming packets
+     */
+    for( ; i < 0x10; i++, subch++ ) {
+	subch->use = BRL1_SUBCH_FREE;
+	subch->packet_arrived = ATOMIC_INIT(0);
+	subch->tx_notify = NULL;
+	subch->rx_notify = brl1_discard_packet;
+	subch->iqp = &sc->garbage_q;
+    }
+
+    /* remaining subchannels are free */
+    for( ; i < BRL1_NUM_SUBCHANS; i++, subch++ ) {
+	subch->use = BRL1_SUBCH_FREE;
+	subch->packet_arrived = ATOMIC_INIT(0);
+	subch->tx_notify = NULL;
+	subch->rx_notify = brl1_discard_packet;
+	subch->iqp = &sc->garbage_q;
+    }
+
+    /* initialize synchronization structures
+     */
+    spin_lock_init( &(sc->subch_lock) );
+    spin_lock_init( &(sc->send_lock) );
+    spin_lock_init( &(sc->recv_lock) );
+
+    if( sc->uart == BRL1_LOCALHUB_UART ) {
+	uart_init( sc, UART_BAUD_RATE );
+    }
+    else {
+	rtr_uart_init( sc, UART_BAUD_RATE );
+    }
+
+    /* Set up remaining fields using L1 command functions-- elsc_module_get
+     * to read the module id, elsc_debug_get to see whether or not we're
+     * in verbose mode.
+     */
+    {
+	extern int elsc_module_get(l1sc_t *);
+
+	sc->modid = elsc_module_get( sc );
+	sc->modid = (sc->modid < 0 ? INVALID_MODULE : sc->modid);
+	sc->verbose = 1;
+    }
+}
+
+/*********************************************************************
+ * These are interrupt-related functions used in the kernel to service
+ * the L1.
+ */
+
+/*
+ * brl1_intrd is the function which is called on a console interrupt.
+ */
+
+
+static void
+brl1_intrd(int irq, void *dev_id, struct pt_regs *stuff)
+{
+    u_char isr_reg;
+    l1sc_t *sc = get_elsc();
+    int ret;
+
+    L1_collectibles[L1C_INTERRUPTS]++;
+    isr_reg = READ_L1_UART_REG(sc->nasid, REG_ISR);
+
+    /* Save for callup args in console */
+    sc->subch[SC_CONS_SYSTEM].irq_frame.bf_irq = irq;
+    sc->subch[SC_CONS_SYSTEM].irq_frame.bf_dev_id = dev_id;
+    sc->subch[SC_CONS_SYSTEM].irq_frame.bf_regs = stuff;
+
+#if	defined(SYNC_CONSOLE_WRITE)
+    while( isr_reg & ISR_RxRDY )
+#else
+    while( isr_reg & (ISR_RxRDY | ISR_TxRDY) )
+#endif
+    {
+	if( isr_reg & ISR_RxRDY ) {
+	    L1_collectibles[L1C_OUR_R_INTERRUPTS]++;
+	    ret = brl1_receive(sc, SERIAL_INTERRUPT_MODE);
+	    if ( (ret != BRL1_VALID) && (ret != BRL1_NO_MESSAGE) && (ret != BRL1_PROTOCOL) && (ret != BRL1_CRC) )
+		L1_collectibles[L1C_REC_STALLS] = ret;
+	}
+#if	!defined(SYNC_CONSOLE_WRITE)
+	if( (isr_reg & ISR_TxRDY) || (sc->send_in_use && UART_PUTC_READY(sc->nasid)) ) {
+	    L1_collectibles[L1C_OUR_X_INTERRUPTS]++;
+	    brl1_send_cont(sc);
+	}
+#endif	/* SYNC_CONSOLE_WRITE */
+	isr_reg = READ_L1_UART_REG(sc->nasid, REG_ISR);
+    }
+}
+
+
+/*
+ * Install a callback function for the system console subchannel 
+ * to allow an upper layer to be notified when the send buffer 
+ * has been emptied.
+ */
+static inline void
+l1_tx_notif( brl1_notif_t func )
+{
+	subch_set_tx_notify( &NODEPDA(NASID_TO_COMPACT_NODEID(get_master_nasid()))->module->elsc,
+			SC_CONS_SYSTEM, func );
+}
+
+
+/*
+ * Install a callback function for the system console subchannel
+ * to allow an upper layer to be notified when a packet has been
+ * received.
+ */
+static inline void
+l1_rx_notif( brl1_notif_t func )
+{
+	subch_set_rx_notify( &NODEPDA(NASID_TO_COMPACT_NODEID(get_master_nasid()))->module->elsc,
+				SC_CONS_SYSTEM, func );
+}
+
+
+/* brl1_intr is called directly from the uart interrupt; after it runs, the
+ * interrupt "daemon" xthread is signalled to continue.
+ */
+void
+brl1_intr( void )
+{
+}
+
+#define BRL1_INTERRUPT_LEVEL	65	/* linux request_irq() value */
+
+/* Return the current interrupt level */
+
+//#define CONSOLE_POLLING_ALSO
+
+int
+l1_get_intr_value( void )
+{
+#if defined(USE_SAL_CONSOLE_IO)
+	return(0);
+#else
+#if defined(CONSOLE_POLLING_ALSO)
+	return(0);
+#else
+	return(BRL1_INTERRUPT_LEVEL);
+#endif /* CONSOLE_POLLING_ALSO */
+#endif /* USE_SAL_CONSOLE_IO */
+}
+
+/* Disconnect the callup functions - throw away interrupts */
+
+void
+l1_unconnect_intr(void)
+{
+#if !defined(USE_SAL_CONSOLE_IO)
+	/* UnRegister the upper-level callup functions */
+	l1_rx_notif((brl1_notif_t)NULL);
+	l1_tx_notif((brl1_notif_t)NULL);
+	/* We do NOT unregister the interrupts */
+#endif /* !USE_SAL_CONSOLE_IO */
+}
+
+/* Set up uart interrupt handling for this node's uart */
+
+void
+l1_connect_intr(void *rx_notify, void *tx_notify)
+{
+#if defined(USE_SAL_CONSOLE_IO)
+#if 0
+	// Will need code here for sn2 - something like this
+	console_nodepda = NODEPDA(NASID_TO_COMPACT_NODEID(get_master_nasid());
+	intr_connect_level(console_nodepda->node_first_cpu,
+                                SGI_UART_VECTOR, INTPEND0_MAXMASK,
+                                dummy_intr_func);
+	request_irq(SGI_UART_VECTOR | (console_nodepda->node_first_cpu << 8),
+                                intr_func, SA_INTERRUPT | SA_SHIRQ,
+                                "l1_protocol_driver", (void *)sc);
+#endif
+#else
+	l1sc_t *sc;
+	nasid_t nasid;
+	int tmp;
+	nodepda_t *console_nodepda;
+	int intr_connect_level(cpuid_t, int, ilvl_t, intr_func_t);
+
+	if ( L1_interrupts_connected ) {
+		/* Interrupts are connected, so just register the callups */
+		l1_rx_notif((brl1_notif_t)rx_notify);
+		l1_tx_notif((brl1_notif_t)tx_notify);
+
+		L1_collectibles[L1C_CONNECT_CALLS]++;
+		return;
+	}
+	else
+		L1_interrupts_connected = 1;
+
+	nasid = get_master_nasid();
+	console_nodepda = NODEPDA(NASID_TO_COMPACT_NODEID(nasid));
+	sc = &console_nodepda->module->elsc;
+	sc->intr_cpu = console_nodepda->node_first_cpu;
+
+	if ( intr_connect_level(sc->intr_cpu, UART_INTR, INTPEND0_MAXMASK, (intr_func_t)brl1_intr) ) {
+		L1_interrupts_connected = 0; /* FAILS !! */
+	}
+	else {
+		void synergy_intr_connect(int, int);
+
+		synergy_intr_connect(UART_INTR, sc->intr_cpu);
+		L1_collectibles[L1C_R_IRQ]++;
+		tmp = request_irq(BRL1_INTERRUPT_LEVEL, brl1_intrd, SA_INTERRUPT | SA_SHIRQ, "l1_protocol_driver", (void *)sc);
+		L1_collectibles[L1C_R_IRQ_RET] = (uint64_t)tmp;
+		if ( tmp ) {
+			L1_interrupts_connected = 0; /* FAILS !! */
+		}
+		else {
+			/* Register the upper-level callup functions */
+			l1_rx_notif((brl1_notif_t)rx_notify);
+			l1_tx_notif((brl1_notif_t)tx_notify);
+
+			/* Set the uarts the way we like it */
+			uart_enable_recv_intr( sc );
+			uart_disable_xmit_intr( sc );
+		}
+	}
+#endif	/* USE_SAL_CONSOLE_IO */
+}
+
+
+/* These are functions to use from serial_in/out when in protocol
+ * mode to send and receive uart control regs. These are external
+ * interfaces into the protocol driver.
+ */
+
+void
+l1_control_out(int offset, int value)
+{
+#if defined(USE_SAL_CONSOLE_IO)
+	/* quietly ignore unless simulator */
+	if ( IS_RUNNING_ON_SIMULATOR() ) {
+		extern u64 master_node_bedrock_address;
+		if ( master_node_bedrock_address != (u64)0 ) {
+			writeb(value, (unsigned long)master_node_bedrock_address +
+				(offset<< 3));
+		}
+		return;
+	}
+#else
+	nasid_t nasid = get_master_nasid();
+	WRITE_L1_UART_REG(nasid, offset, value); 
+#endif
+}
+
+/* Console input exported interface. Return a register value.  */
+
+int
+l1_control_in_polled(int offset)
+{
+	static int l1_control_in_local(int, int);
+
+	return(l1_control_in_local(offset, SERIAL_POLLED_MODE));
+}
+
+int
+l1_control_in(int offset)
+{
+	static int l1_control_in_local(int, int);
+
+	return(l1_control_in_local(offset, SERIAL_INTERRUPT_MODE));
+}
+
+static int
+l1_control_in_local(int offset, int mode)
+{
+#if defined(USE_SAL_CONSOLE_IO)
+	int sal_call_status = 0, input;
+	int ret = 0;
+
+	if ( offset == REG_LSR ) {
+		ret = (LSR_XHRE | LSR_XSRE);	/* can send anytime */
+		sal_call_status = ia64_sn_console_check(&input);
+		if ( !sal_call_status && input ) {
+			/* input pending */
+			ret |= LSR_RCA;
+		}
+	}
+
+	/* If the sal call failed, do it the old-fashioned way */
+	if ( sal_call_status ) {
+		if ( IS_RUNNING_ON_SIMULATOR() ) {
+			extern u64 master_node_bedrock_address;
+			ret = readb((unsigned long)master_node_bedrock_address +
+					(offset<< 3));
+		}		
+		else {
+#endif	/* USE_SAL_CONSOLE_IO */
+			nasid_t nasid;
+			int ret, input;
+			static int l1_poll(l1sc_t *, int);
+
+			nasid = get_master_nasid();
+			ret = READ_L1_UART_REG(nasid, offset); 
+
+			if ( offset == REG_LSR ) {
+				ret |= (LSR_XHRE | LSR_XSRE);	/* can send anytime */
+				if ( L1_cons_is_inited ) {
+					if ( NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module != (module_t *)0 ) {
+						input = l1_poll(&NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module->elsc, mode);
+						if ( input ) {
+							ret |= LSR_RCA;
+						}
+					}
+				}
+			}
+#if defined(USE_SAL_CONSOLE_IO)
+		}
+	}
+#endif
+	return(ret);
+}
+
+/*
+ * Console input exported interface. Return a character (if one is available)
+ */
+
+int
+l1_serial_in_polled(void)
+{
+	static int l1_serial_in_local(int mode);
+
+	return(l1_serial_in_local(SERIAL_POLLED_MODE));
+}
+
+int
+l1_serial_in(void)
+{
+	static int l1_serial_in_local(int mode);
+
+	return(l1_serial_in_local(SERIAL_INTERRUPT_MODE));
+}
+
+static int
+l1_serial_in_local(int mode)
+{
+#if defined(USE_SAL_CONSOLE_IO)
+	int sal_call_status;
+	int ch;
+
+	sal_call_status = ia64_sn_console_getc(&ch);
+	if ( !sal_call_status ) {
+		return(ch);
+	}
+	else {
+		/* If the sal called failed - do it the old-fashioned way */
+		if ( IS_RUNNING_ON_SIMULATOR() ) {
+			extern u64 master_node_bedrock_address;
+			return(readb((unsigned long)master_node_bedrock_address + (REG_DAT<< 3)));
+		}		
+		else {
+#endif	/* USE_SAL_CONSOLE_IO */
+			nasid_t nasid;
+			l1sc_t *sc;
+			int value;
+			static int l1_getc( l1sc_t *, int );
+			static inline l1sc_t *early_sc_init(nasid_t);
+
+			nasid = get_master_nasid();
+			sc = early_sc_init(nasid);
+			if ( L1_cons_is_inited ) {
+				if ( NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module != (module_t *)0 ) {
+					sc = &NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module->elsc;
+				}
+			}
+			value = l1_getc(sc, mode);
+			return(value);
+#if defined(USE_SAL_CONSOLE_IO)
+		}
+	}
+#endif
+}
+
+/* Console output exported interface. Write message to the console.  */
+
+int
+l1_serial_out( char *str, int len )
+{
+#if defined(USE_SAL_CONSOLE_IO)
+	void early_sn_setup(void);
+	int sal_call_status = 0;
+	int counter = len;
+
+#if defined(CONFIG_IA64_EARLY_PRINTK)
+	{
+		static int inited;
+		if(!inited) {
+			inited=1;
+			early_sn_setup();
+		}
+	}
+#endif
+
+	/* Attempt to write things out thru the sal */
+	sal_call_status = ia64_sn_console_putb(str, len);
+	if ( sal_call_status ) {
+		/* If the sal called failed - do it the old-fashioned way */
+		if ( IS_RUNNING_ON_SIMULATOR() ) {
+			extern u64 master_node_bedrock_address;
+                        if (!master_node_bedrock_address)
+                                early_sn_setup();
+			if ( master_node_bedrock_address != (u64)0 ) {
+#ifdef FLAG_DIRECT_CONSOLE_WRITES
+				/* This is an easy way to pre-pend the output to know whether the output
+				 * was done via sal or directly */
+				writeb('[', (unsigned long)master_node_bedrock_address + (REG_DAT<< 3));
+				writeb('+', (unsigned long)master_node_bedrock_address + (REG_DAT<< 3));
+				writeb(']', (unsigned long)master_node_bedrock_address + (REG_DAT<< 3));
+				writeb(' ', (unsigned long)master_node_bedrock_address + (REG_DAT<< 3));
+#endif	/* FLAG_DIRECT_CONSOLE_WRITES */
+				while ( counter > 0 ) {
+					writeb(*str, (unsigned long)master_node_bedrock_address + (REG_DAT<< 3));
+					counter--;
+					str++;
+				}
+			}
+		}
+		else {
+#endif	/* USE_SAL_CONSOLE_IO */
+			nasid_t nasid = get_master_nasid();
+			int l1_write(l1sc_t *, char *, int, int);
+
+			if ( L1_cons_is_inited ) {
+				if ( NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module != (module_t *)0 )
+					return(l1_write(&NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->module->elsc, str, len,
+#if	defined(SYNC_CONSOLE_WRITE)
+							1
+#else
+							!L1_interrupts_connected
+#endif
+									));
+			}
+			return(early_l1_serial_out(nasid, str, len, NOT_LOCKED));
+#if defined(USE_SAL_CONSOLE_IO)
+		}
+	}
+	return((counter <= 0) ? 0 : (len - counter));
+#endif
+}
+
+
+/*
+ * These are the 'early' functions - when we need to do things before we have
+ * all the structs setup.
+ */
+
+
+static l1sc_t Early_console;		/* fake l1sc_t */
+static int Early_console_inited = 0;
+
+static void
+early_brl1_init( l1sc_t *sc, nasid_t nasid, net_vec_t uart )
+{
+    int i;
+    brl1_sch_t *subch;
+
+    bzero( sc, sizeof( *sc ) );
+    sc->nasid = nasid;
+    sc->uart = uart;
+    sc->getc_f = (uart == BRL1_LOCALHUB_UART ? uart_getc : rtr_uart_getc);
+    sc->putc_f = (uart == BRL1_LOCALHUB_UART ? uart_putc : rtr_uart_putc);
+    sc->sol = 1;
+    subch = sc->subch;
+
+    /* initialize L1 subchannels
+     */
+
+    /* assign processor TTY channels */
+    for( i = 0; i < CPUS_PER_NODE; i++, subch++ ) {
+	subch->use = BRL1_SUBCH_RSVD;
+	subch->packet_arrived = ATOMIC_INIT(0);
+	subch->tx_notify = NULL;
+	subch->rx_notify = NULL;
+	subch->iqp = &sc->garbage_q;
+    }
+
+    /* assign system TTY channel (first free subchannel after each
+     * processor's individual TTY channel has been assigned)
+     */
+    subch->use = BRL1_SUBCH_RSVD;
+    subch->packet_arrived = ATOMIC_INIT(0);
+    subch->tx_notify = NULL;
+    subch->rx_notify = NULL;
+    if( sc->uart == BRL1_LOCALHUB_UART ) {
+	static sc_cq_t x_iqp;
+
+	subch->iqp = &x_iqp;
+	ASSERT( subch->iqp );
+	cq_init( subch->iqp );
+    }
+    else {
+	/* we shouldn't be getting console input from remote UARTs */
+	subch->iqp = &sc->garbage_q;
+    }
+    subch++; i++;
+
+    /* "reserved" subchannels (0x05-0x0F); for now, throw away
+     * incoming packets
+     */
+    for( ; i < 0x10; i++, subch++ ) {
+	subch->use = BRL1_SUBCH_FREE;
+	subch->packet_arrived = ATOMIC_INIT(0);
+	subch->tx_notify = NULL;
+	subch->rx_notify = NULL;
+	subch->iqp = &sc->garbage_q;
+    }
+
+    /* remaining subchannels are free */
+    for( ; i < BRL1_NUM_SUBCHANS; i++, subch++ ) {
+	subch->use = BRL1_SUBCH_FREE;
+	subch->packet_arrived = ATOMIC_INIT(0);
+	subch->tx_notify = NULL;
+	subch->rx_notify = NULL;
+	subch->iqp = &sc->garbage_q;
+    }
+}
+
+static inline l1sc_t *
+early_sc_init(nasid_t nasid)
+{
+	/* This is for early I/O */
+	if ( Early_console_inited == 0 ) {
+    		early_brl1_init(&Early_console, nasid,  BRL1_LOCALHUB_UART);
+		Early_console_inited = 1;
+	}
+	return(&Early_console);
+}
+
+#define PUTCHAR(ch) \
+    { \
+        while( (!(READ_L1_UART_REG( nasid, REG_LSR ) & LSR_XHRE)) || \
+                (!(READ_L1_UART_REG( nasid, REG_MSR ) & MSR_CTS)) ); \
+        WRITE_L1_UART_REG( nasid, REG_DAT, (ch) ); \
+    }
+
+static int
+early_l1_serial_out( nasid_t nasid, char *str, int len, int lock_state )
+{
+	int ret, sent = 0;
+	char *msg = str;
+	static int early_l1_send( nasid_t nasid, char *str, int len, int lock_state );
+
+	while ( sent < len ) {
+		ret = early_l1_send(nasid, msg, len - sent, lock_state);
+		sent += ret;
+		msg += ret;
+	}
+	return(len);
+}
+
+static inline int
+early_l1_send( nasid_t nasid, char *str, int len, int lock_state )
+{
+    int sent;
+    char crc_char;
+    unsigned short crc = INIT_CRC;
+
+    if( len > (BRL1_QSIZE - 1) )
+	len = (BRL1_QSIZE - 1);
+
+    sent = len;
+    if ( lock_state == NOT_LOCKED )
+    	lock_console(nasid);
+
+    PUTCHAR( BRL1_FLAG_CH );
+    PUTCHAR( BRL1_EVENT | SC_CONS_SYSTEM );
+    crc = crc16_calc( crc, (BRL1_EVENT | SC_CONS_SYSTEM) );
+
+    while( len ) {
+
+	if( (*str == BRL1_FLAG_CH) || (*str == BRL1_ESC_CH) ) {
+	    PUTCHAR( BRL1_ESC_CH );
+	    PUTCHAR( (*str) ^ BRL1_XOR_CH );
+	}
+	else {
+	    PUTCHAR( *str );
+	}
+	
+	crc = crc16_calc( crc, *str );
+
+	str++; len--;
+    }
+    
+    crc ^= 0xffff;
+    crc_char = crc & 0xff;
+    if( (crc_char == BRL1_ESC_CH) || (crc_char == BRL1_FLAG_CH) ) {
+	crc_char ^= BRL1_XOR_CH;
+	PUTCHAR( BRL1_ESC_CH );
+    }
+    PUTCHAR( crc_char );
+    crc_char = (crc >> 8) & 0xff;
+    if( (crc_char == BRL1_ESC_CH) || (crc_char == BRL1_FLAG_CH) ) {
+	crc_char ^= BRL1_XOR_CH;
+	PUTCHAR( BRL1_ESC_CH );
+    }
+    PUTCHAR( crc_char );
+    PUTCHAR( BRL1_FLAG_CH );
+
+    if ( lock_state == NOT_LOCKED )
+    	unlock_console(nasid);
+    return sent;
+}
+
+/*********************************************************************
+ * l1_cons functions
+ *
+ * These allow the L1 to act as the system console.  They're intended
+ * to abstract away most of the br/l1 internal details from the
+ * _L1_cons_* functions (in the prom-- see "l1_console.c") and
+ * l1_* functions (in the kernel-- see "sio_l1.c") that they support.
+ *
+ */
+
+static int
+l1_poll( l1sc_t *sc, int mode )
+{
+    int ret;
+
+    /* in case this gets called before the l1sc_t structure for the module_t
+     * struct for this node is initialized (i.e., if we're called with a
+     * zero l1sc_t pointer)...
+     */
+
+
+    if( !sc ) {
+	return 0;
+    }
+
+    if( atomic_read(&sc->subch[SC_CONS_SYSTEM].packet_arrived) ) {
+	return 1;
+    }
+
+    ret = brl1_receive( sc, mode );
+    if ( (ret != BRL1_VALID) && (ret != BRL1_NO_MESSAGE) && (ret != BRL1_PROTOCOL) && (ret != BRL1_CRC) )
+	L1_collectibles[L1C_REC_STALLS] = ret;
+
+    if( atomic_read(&sc->subch[SC_CONS_SYSTEM].packet_arrived) ) {
+	return 1;
+    }
+    return 0;
+}
+
+
+/* pull a character off of the system console queue (if one is available)
+ */
+static int
+l1_getc( l1sc_t *sc, int mode )
+{
+    unsigned long pl = 0;
+    int c;
+
+    brl1_sch_t *subch = &(sc->subch[SC_CONS_SYSTEM]);
+    sc_cq_t *q = subch->iqp;
+
+    if( !l1_poll( sc, mode ) ) {
+	return 0;
+    }
+
+    SUBCH_DATA_LOCK( subch, pl );
+    if( cq_empty( q ) ) {
+	atomic_set(&subch->packet_arrived, 0);
+	SUBCH_DATA_UNLOCK( subch, pl );
+	return 0;
+    }
+    cq_rem( q, c );
+    if( cq_empty( q ) )
+	atomic_set(&subch->packet_arrived, 0);
+    SUBCH_DATA_UNLOCK( subch, pl );
+
+    return c;
+}
+
+/*
+ * Write a message to the L1 on the system console subchannel.
+ *
+ * Danger: don't use a non-zero value for the wait parameter unless you're
+ * someone important (like a kernel error message).
+ */
+
+int
+l1_write( l1sc_t *sc, char *msg, int len, int wait )
+{
+	int sent = 0, ret = 0;
+
+	if ( wait ) {
+		while ( sent < len ) {
+			ret = brl1_send( sc, msg, len - sent, (SC_CONS_SYSTEM | BRL1_EVENT), wait );
+			sent += ret;
+			msg += ret;
+		}
+		ret = len;
+	}
+	else {
+		ret = brl1_send( sc, msg, len, (SC_CONS_SYSTEM | BRL1_EVENT), wait );
+	}
+	return(ret);
+}
+
+/* initialize the system console subchannel
+ */
+void
+l1_init(void)
+{
+	/* All we do now is remember that we have been called */
+	L1_cons_is_inited = 1;
+}
+
+
+/*********************************************************************
+ * The following functions and definitions implement the "message"-
+ * style interface to the L1 system controller.
+ *
+ * Note that throughout this file, "sc" generally stands for "system
+ * controller", while "subchannels" tend to be represented by
+ * variables with names like subch or ch.
+ *
+ */
+
+#ifdef L1_DEBUG
+#define L1_DBG_PRF(x) printf x
+#else
+#define L1_DBG_PRF(x)
+#endif
+
+/*
+ * sc_data_ready is called to signal threads that are blocked on l1 input.
+ */
+void
+sc_data_ready( int dummy0, void *dummy1, struct pt_regs *dummy2, l1sc_t *sc, int ch )
+{
+    unsigned long pl = 0;
+
+    brl1_sch_t *subch = &(sc->subch[ch]);
+    SUBCH_DATA_LOCK( subch, pl );
+    sv_signal( &(subch->arrive_sv) );
+    SUBCH_DATA_UNLOCK( subch, pl );
+}
+
+/* sc_open reserves a subchannel to send a request to the L1 (the
+ * L1's response will arrive on the same channel).  The number
+ * returned by sc_open is the system controller subchannel
+ * acquired.
+ */
+int
+sc_open( l1sc_t *sc, uint target )
+{
+    /* The kernel version implements a locking scheme to arbitrate
+     * subchannel assignment.
+     */
+    int ch;
+    unsigned long pl = 0;
+    brl1_sch_t *subch;
+
+    SUBCH_LOCK( sc, pl );
+
+    /* Look for a free subchannel. Subchannels 0-15 are reserved
+     * for other purposes.
+     */
+    for( subch = &(sc->subch[BRL1_CMD_SUBCH]), ch = BRL1_CMD_SUBCH; 
+			ch < BRL1_NUM_SUBCHANS; subch++, ch++ ) {
+        if( subch->use == BRL1_SUBCH_FREE )
+            break;
+    }
+
+    if( ch == BRL1_NUM_SUBCHANS ) {
+        /* there were no subchannels available! */
+        SUBCH_UNLOCK( sc, pl );
+        return SC_NSUBCH;
+    }
+
+    subch->use = BRL1_SUBCH_RSVD;
+    SUBCH_UNLOCK( sc, pl );
+
+    atomic_set(&subch->packet_arrived, 0);
+    subch->target = target;
+    spin_lock_init( &(subch->data_lock) );
+    sv_init( &(subch->arrive_sv), &(subch->data_lock), SV_MON_SPIN | SV_ORDER_FIFO /* | SV_INTS */);
+    subch->tx_notify = NULL;
+    subch->rx_notify = sc_data_ready;
+    subch->iqp = snia_kmem_zalloc_node( sizeof(sc_cq_t), KM_NOSLEEP,
+				   NASID_TO_COMPACT_NODEID(sc->nasid) );
+    ASSERT( subch->iqp );
+    cq_init( subch->iqp );
+
+    return ch;
+}
+
+
+/* sc_close frees a Bedrock<->L1 subchannel.
+ */
+int
+sc_close( l1sc_t *sc, int ch )
+{
+    unsigned long pl = 0;
+    brl1_sch_t *subch;
+
+    SUBCH_LOCK( sc, pl );
+    subch = &(sc->subch[ch]);
+    if( subch->use != BRL1_SUBCH_RSVD ) {
+        /* we're trying to close a subchannel that's not open */
+	SUBCH_UNLOCK( sc, pl );
+        return SC_NOPEN;
+    }
+
+    atomic_set(&subch->packet_arrived, 0);
+    subch->use = BRL1_SUBCH_FREE;
+
+    sv_broadcast( &(subch->arrive_sv) );
+    sv_destroy( &(subch->arrive_sv) );
+    spin_lock_destroy( &(subch->data_lock) );
+
+    ASSERT( subch->iqp && (subch->iqp != &sc->garbage_q) );
+    snia_kmem_free( subch->iqp, sizeof(sc_cq_t) );
+    subch->iqp = &sc->garbage_q;
+    subch->tx_notify = NULL;
+    subch->rx_notify = brl1_discard_packet;
+
+    SUBCH_UNLOCK( sc, pl );
+
+    return SC_SUCCESS;
+}
+
+
+/* sc_construct_msg builds a bedrock-to-L1 request in the supplied
+ * buffer.  Returns the length of the message.  The
+ * safest course when passing a buffer to be filled in is to use
+ * BRL1_QSIZE as the buffer size.
+ *
+ * Command arguments are passed as type/argument pairs, i.e., to
+ * pass the number 5 as an argument to an L1 command, call
+ * sc_construct_msg as follows:
+ *
+ *    char msg[BRL1_QSIZE];
+ *    msg_len = sc_construct_msg( msg,
+ *				  BRL1_QSIZE,
+ *				  target_component,
+ *                                L1_ADDR_TASK_BOGUSTASK,
+ *                                L1_BOGUSTASK_REQ_BOGUSREQ,
+ *                                2,
+ *                                L1_ARG_INT, 5 );
+ *
+ * To pass an additional ASCII argument, you'd do the following:
+ *
+ *    char *str;
+ *    ... str points to a null-terminated ascii string ...
+ *    msg_len = sc_construct_msg( msg,
+ *                                BRL1_QSIZE,
+ *				  target_component,
+ *                                L1_ADDR_TASK_BOGUSTASK,
+ *                                L1_BOGUSTASK_REQ_BOGUSREQ,
+ *                                4,
+ *                                L1_ARG_INT, 5,
+ *                                L1_ARG_ASCII, str );
+ *
+ * Finally, arbitrary data of unknown type is passed using the argtype
+ * code L1_ARG_UNKNOWN, a data length, and a buffer pointer, e.g.
+ *
+ *    msg_len = sc_construct_msg( msg,
+ *                                BRL1_QSIZE,
+ *				  target_component,
+ *                                L1_ADDR_TASK_BOGUSTASK,
+ *                                L1_BOGUSTASK_REQ_BOGUSREQ,
+ *                                3,
+ *                                L1_ARG_UNKNOWN, 32, bufptr );
+ *
+ * ...passes 32 bytes of data starting at bufptr.  Note that no string or
+ * "unknown"-type argument should be long enough to overflow the message
+ * buffer.
+ *
+ * To construct a message for an L1 command that requires no arguments,
+ * you'd use the following:
+ *
+ *    msg_len = sc_construct_msg( msg,
+ *                                BRL1_QSIZE,
+ *				  target_component,
+ *                                L1_ADDR_TASK_BOGUSTASK,
+ *                                L1_BOGUSTASK_REQ_BOGUSREQ,
+ *                                0 );
+ *
+ * The final 0 means "no varargs".  Notice that this parameter is used to hold
+ * the number of additional arguments to sc_construct_msg, _not_ the actual
+ * number of arguments used by the L1 command (so 2 per L1_ARG_[INT,ASCII]
+ * type argument, and 3 per L1_ARG_UNKOWN type argument).  A call to construct
+ * an L1 command which required three integer arguments and two arguments of
+ * some arbitrary (unknown) type would pass 12 as the value for this parameter.
+ *
+ * ENDIANNESS WARNING: The following code does a lot of copying back-and-forth
+ * between byte arrays and four-byte big-endian integers.  Depending on the
+ * system controller connection and endianness of future architectures, some
+ * rewriting might be necessary.
+ */
+int
+sc_construct_msg( l1sc_t  *sc,		/* system controller struct */
+		  int	   ch,           /* subchannel for this message */
+		  char    *msg,          /* message buffer */
+		  int      msg_len,      /* size of message buffer */
+                  l1addr_t addr_task,    /* target system controller task */
+                  short    req_code,     /* 16-bit request code */
+                  int      req_nargs,    /* # of arguments (varargs) passed */
+                  ... )                 /* any additional parameters */
+{
+    uint32_t buf32;   /* 32-bit buffer used to bounce things around */
+    void *bufptr;       /* used to hold command argument addresses */
+    va_list al;         /* variable argument list */
+    int index;          /* current index into msg buffer */
+    int argno;          /* current position in varargs list */
+    int l1_argno;       /* running total of arguments to l1 */
+    int l1_arg_t;       /* argument type/length */
+    int l1_argno_byte;  /* offset of argument count byte */
+
+    index = argno = 0;
+
+    /* set up destination address */
+    if( (msg_len -= sizeof( buf32 )) < 0 )
+	return -1;
+    L1_ADDRESS_TO_TASK( &buf32, sc->subch[ch].target, addr_task );
+    COPY_INT_TO_BUFFER(msg, index, buf32);
+
+    /* copy request code */
+    if( (msg_len -= 2) < 0 )
+	return( -1 );
+    msg[index++] = ((req_code >> 8) & 0xff);
+    msg[index++] = (req_code & 0xff);
+
+    if( !req_nargs ) {
+        return index;
+    }
+
+    /* reserve a byte for the argument count */
+    if( (msg_len -= 1) < 0 )
+	return( -1 );
+    l1_argno_byte = index++;
+    l1_argno = 0;
+
+    /* copy additional arguments */
+    va_start( al, req_nargs );
+    while( argno < req_nargs ) {
+        l1_argno++;
+        l1_arg_t = va_arg( al, int ); argno++;
+        switch( l1_arg_t )
+        {
+          case L1_ARG_INT:
+	    if( (msg_len -= (sizeof( buf32 ) + 1)) < 0 )
+		return( -1 );
+            msg[index++] = L1_ARG_INT;
+            buf32 = (unsigned)va_arg( al, int ); argno++;
+	    COPY_INT_TO_BUFFER(msg, index, buf32);
+            break;
+
+          case L1_ARG_ASCII:
+            bufptr = va_arg( al, char* ); argno++;
+	    if( (msg_len -= (strlen( bufptr ) + 2)) < 0 )
+		return( -1 );
+            msg[index++] = L1_ARG_ASCII;
+            strcpy( (char *)&(msg[index]), (char *)bufptr );
+            index += (strlen( bufptr ) + 1); /* include terminating null */
+            break;
+
+	  case L1_ARG_UNKNOWN:
+              {
+                  int arglen;
+		  
+                  arglen = va_arg( al, int ); argno++;
+                  bufptr = va_arg( al, void* ); argno++;
+		  if( (msg_len -= (arglen + 1)) < 0 )
+		      return( -1 );
+                  msg[index++] = L1_ARG_UNKNOWN | arglen;
+                  BCOPY( bufptr, &(msg[index]), arglen  );
+                  index += arglen;
+		  break;
+              }
+	  
+	  default: /* unhandled argument type */
+	    return -1;
+        }
+    }
+
+    va_end( al );
+    msg[l1_argno_byte] = l1_argno;
+
+    return index;
+}
+
+
+
+/* sc_interpret_resp verifies an L1 response to a bedrock request, and
+ * breaks the response data up into the constituent parts.  If the
+ * response message indicates error, or if a mismatch is found in the
+ * expected number and type of arguments, an error is returned.  The
+ * arguments to this function work very much like the arguments to
+ * sc_construct_msg, above, except that L1_ARG_INTs must be followed
+ * by a _pointer_ to an integer that can be filled in by this function.
+ */
+int
+sc_interpret_resp( char *resp,          /* buffer received from L1 */
+                   int   resp_nargs,    /* number of _varargs_ passed in */
+                   ... )
+{
+    uint32_t buf32;   /* 32-bit buffer used to bounce things around */
+    void *bufptr;       /* used to hold response field addresses */
+    va_list al;         /* variable argument list */
+    int index;          /* current index into response buffer */
+    int argno;          /* current position in varargs list */
+    int l1_fldno;       /* number of resp fields received from l1 */
+    int l1_fld_t;       /* field type/length */
+
+    index = argno = 0;
+
+#if defined(L1_DEBUG)
+#define DUMP_RESP							  \
+    {									  \
+	int ix;								  \
+        char outbuf[512];						  \
+        sprintf( outbuf, "sc_interpret_resp error line %d: ", __LINE__ ); \
+	for( ix = 0; ix < 16; ix++ ) {					  \
+	    sprintf( &outbuf[strlen(outbuf)], "%x ", resp[ix] );	  \
+	}								  \
+	printk( "%s\n", outbuf );					  \
+    }
+#else
+#define DUMP_RESP
+#endif /* L1_DEBUG */
+
+    /* check response code */
+    COPY_BUFFER_TO_INT(resp, index, buf32);
+    if( buf32 != L1_RESP_OK ) {
+	DUMP_RESP;
+        return buf32;
+    }
+
+    /* get number of response fields */
+    l1_fldno = resp[index++];
+
+    va_start( al, resp_nargs );
+
+    /* copy out response fields */
+    while( argno < resp_nargs ) {
+        l1_fldno--;
+        l1_fld_t = va_arg( al, int ); argno++;
+        switch( l1_fld_t )
+        {
+          case L1_ARG_INT:
+            if( resp[index++] != L1_ARG_INT ) {
+                /* type mismatch */
+		va_end( al );
+		DUMP_RESP;
+		return -1;
+            }
+            bufptr = va_arg( al, int* ); argno++;
+	    COPY_BUFFER_TO_BUFFER(resp, index, bufptr);
+            break;
+
+          case L1_ARG_ASCII:
+            if( resp[index++] != L1_ARG_ASCII ) {
+                /* type mismatch */
+		va_end( al );
+		DUMP_RESP;
+                return -1;
+            }
+            bufptr = va_arg( al, char* ); argno++;
+            strcpy( (char *)bufptr, (char *)&(resp[index]) );
+            /* include terminating null */
+            index += (strlen( &(resp[index]) ) + 1);
+            break;
+
+          default:
+	    if( (l1_fld_t & L1_ARG_UNKNOWN) == L1_ARG_UNKNOWN )
+	    {
+		int *arglen;
+		
+		arglen = va_arg( al, int* ); argno++;
+		bufptr = va_arg( al, void* ); argno++;
+		*arglen = ((resp[index++] & ~L1_ARG_UNKNOWN) & 0xff);
+		BCOPY( &(resp[index]), bufptr, *arglen  );
+		index += (*arglen);
+	    }
+	    
+	    else {
+		/* unhandled type */
+		va_end( al );
+		DUMP_RESP;
+		return -1;
+	    }
+        }
+    }
+    va_end( al );
+  
+    if( (l1_fldno != 0) || (argno != resp_nargs) ) {
+        /* wrong number of arguments */
+	DUMP_RESP;
+        return -1;
+    }
+    return 0;
+}
+
+/* sc_send takes as arguments a system controller struct, a
+ * buffer which contains a Bedrock<->L1 "request" message,
+ * the message length, and the subchannel (presumably obtained
+ * from an earlier invocation of sc_open) over which the
+ * message is to be sent.  The final argument ("wait") indicates
+ * whether the send is to be performed synchronously or not.
+ *
+ * sc_send returns either zero or an error value.  Synchronous sends 
+ * (wait != 0) will not return until the data has actually been sent
+ * to the UART.  Synchronous sends generally receive privileged
+ * treatment.  The intent is that they be used sparingly, for such
+ * purposes as kernel printf's (the "ducons" routines).  Run-of-the-mill
+ * console output and L1 requests should NOT use a non-zero value
+ * for wait.
+ */
+int
+sc_send( l1sc_t *sc, int ch, char *msg, int len, int wait )
+{
+    char type_and_subch;
+    int result;
+
+    if( (ch < 0) || ( ch >= BRL1_NUM_SUBCHANS) ) {
+        return SC_BADSUBCH;
+    }
+
+    /* Verify that this is an open subchannel
+     */
+    if( sc->subch[ch].use == BRL1_SUBCH_FREE ) {
+        return SC_NOPEN;
+    }
+
+    type_and_subch = (BRL1_REQUEST | ((u_char)ch));
+    result = brl1_send( sc, msg, len, type_and_subch, wait );
+
+    /* If we sent as much as we asked to, return "ok". */
+    if( result == len )
+	return( SC_SUCCESS );
+
+    /* Or, if we sent less, than either the UART is busy or
+     * we're trying to send too large a packet anyway.
+     */
+    else if( result >= 0 && result < len )
+	return( SC_BUSY );
+
+    /* Or, if something else went wrong (result < 0), then
+     * return that error value.
+     */
+    else
+	return( result );
+}
+
+/* subch_pull_msg pulls a message off the receive queue for subch
+ * and places it the buffer pointed to by msg.  This routine should only
+ * be called when the caller already knows a message is available on the
+ * receive queue (and, in the kernel, only when the subchannel data lock
+ * is held by the caller).
+ */
+static void
+subch_pull_msg( brl1_sch_t *subch, char *msg, int *len )
+{
+    sc_cq_t *q;         /* receive queue */
+    int before_wrap,    /* packet may be split into two different       */
+        after_wrap;     /*   pieces to acommodate queue wraparound      */
+
+    /* pull message off the receive queue */
+    q = subch->iqp;
+
+    cq_rem( q, *len );   /* remove length byte and store */
+    cq_discard( q );     /* remove type/subch byte and discard */
+
+    if ( *len > 0 )
+	(*len)--;        /* don't count type/subch byte in length returned */
+
+    if( (q->opos + (*len)) > BRL1_QSIZE ) {
+        before_wrap = BRL1_QSIZE - q->opos;
+        after_wrap = (*len) - before_wrap;
+    }
+    else {
+        before_wrap = (*len);
+        after_wrap = 0;
+    }
+
+    BCOPY( q->buf + q->opos, msg, before_wrap  );
+    if( after_wrap ) {
+        BCOPY( q->buf, msg + before_wrap, after_wrap  );
+	q->opos = after_wrap;
+    }
+    else {
+	q->opos = ((q->opos + before_wrap) & (BRL1_QSIZE - 1));
+    }
+    atomic_dec(&(subch->packet_arrived));
+}
+
+
+/* sc_recv_poll can be called as a blocking or non-blocking function;
+ * it attempts to pull a message off of the subchannel specified
+ * in the argument list (ch).
+ *
+ * The "block" argument, if non-zero, is interpreted as a timeout
+ * delay (to avoid permanent waiting).
+ */
+
+int
+sc_recv_poll( l1sc_t *sc, int ch, char *msg, int *len, uint64_t block )
+{
+    int is_msg = 0;
+    unsigned long pl = 0;
+    brl1_sch_t *subch = &(sc->subch[ch]);
+
+    rtc_time_t exp_time = rtc_time() + block;
+
+    /* sanity check-- make sure this is an open subchannel */
+    if( subch->use == BRL1_SUBCH_FREE )
+	return( SC_NOPEN );
+
+    do {
+
+        /* kick the next lower layer and see if it pulls anything in
+         */
+	brl1_receive( sc, SERIAL_POLLED_MODE );
+	is_msg = atomic_read(&subch->packet_arrived);
+
+    } while( block && !is_msg && (rtc_time() < exp_time) );
+
+    if( !is_msg ) {
+	/* no message and we didn't care to wait for one */
+	return( SC_NMSG );
+    }
+
+    SUBCH_DATA_LOCK( subch, pl );
+    subch_pull_msg( subch, msg, len );
+    SUBCH_DATA_UNLOCK( subch, pl );
+
+    return( SC_SUCCESS );
+}
+    
+
+/* Like sc_recv_poll, sc_recv_intr can be called in either a blocking
+ * or non-blocking mode.  Rather than polling until an appointed timeout,
+ * however, sc_recv_intr sleeps on a syncrhonization variable until a
+ * signal from the lower layer tells us that a packet has arrived.
+ *
+ * sc_recv_intr can't be used with remote (router) L1s.
+ */
+int
+sc_recv_intr( l1sc_t *sc, int ch, char *msg, int *len, uint64_t block )
+{
+    int is_msg = 0;
+    unsigned long pl = 0;
+    brl1_sch_t *subch = &(sc->subch[ch]);
+
+    do {
+	SUBCH_DATA_LOCK(subch, pl);
+	is_msg = atomic_read(&subch->packet_arrived);
+	if( !is_msg && block ) {
+	    /* wake me when you've got something */
+	    subch->rx_notify = sc_data_ready;
+	    sv_wait( &(subch->arrive_sv), 0, 0);
+	    if( subch->use == BRL1_SUBCH_FREE ) {
+		/* oops-- somebody closed our subchannel while we were
+		 * sleeping!
+		 */
+
+		/* no need to unlock since the channel's closed anyhow */
+		return( SC_NOPEN );
+	    }
+	}
+    } while( !is_msg && block );
+
+    if( !is_msg ) {
+	/* no message and we didn't care to wait for one */
+	SUBCH_DATA_UNLOCK( subch, pl );
+	return( SC_NMSG );
+    }
+
+    subch_pull_msg( subch, msg, len );
+    SUBCH_DATA_UNLOCK( subch, pl );
+
+    return( SC_SUCCESS );
+}
+
+/* sc_command implements a (blocking) combination of sc_send and sc_recv.
+ * It is intended to be the SN1 equivalent of SN0's "elsc_command", which
+ * issued a system controller command and then waited for a response from
+ * the system controller before returning.
+ *
+ * cmd points to the outgoing command; resp points to the buffer in
+ * which the response is to be stored.  Both buffers are assumed to
+ * be the same length; if there is any doubt as to whether the
+ * response buffer is long enough to hold the L1's response, then
+ * make it BRL1_QSIZE bytes-- no Bedrock<->L1 message can be any
+ * bigger.
+ *
+ * Be careful using the same buffer for both cmd and resp; it could get
+ * hairy if there were ever an L1 command reqeuest that spanned multiple
+ * packets.  (On the other hand, that would require some additional
+ * rewriting of the L1 command interface anyway.)
+ */
+#define __RETRIES	50
+#define __WAIT_SEND	1	// ( sc->uart != BRL1_LOCALHUB_UART )
+#define __WAIT_RECV	10000000
+
+
+int
+sc_command( l1sc_t *sc, int ch, char *cmd, char *resp, int *len )
+{
+    int result;
+    int retries;
+
+    if ( IS_RUNNING_ON_SIMULATOR() )
+    	return SC_NMSG;
+
+    retries = __RETRIES;
+
+    while( (result = sc_send( sc, ch, cmd, *len, __WAIT_SEND )) < 0 ) {
+	if( result == SC_BUSY ) {
+	    retries--;
+	    if( retries <= 0 )
+		return result;
+	    uart_delay(500);
+	}
+	else {
+	    return result;
+	}
+    }
+    
+    /* block on sc_recv_* */
+    if( (sc->uart == BRL1_LOCALHUB_UART) && L1_interrupts_connected ) {
+	return( sc_recv_intr( sc, ch, resp, len, __WAIT_RECV ) );
+    }
+    else {
+	return( sc_recv_poll( sc, ch, resp, len, __WAIT_RECV ) );
+    }
+}
+
+/* sc_command_kern is a knuckle-dragging, no-patience version of sc_command
+ * used in situations where the kernel has a command that shouldn't be
+ * delayed until the send buffer clears.  sc_command should be used instead
+ * under most circumstances.
+ */
+
+int
+sc_command_kern( l1sc_t *sc, int ch, char *cmd, char *resp, int *len )
+{
+    int result;
+
+    if ( IS_RUNNING_ON_SIMULATOR() )
+    	return SC_NMSG;
+
+    if( (result = sc_send( sc, ch, cmd, *len, 1 )) < 0 ) {
+	return result;
+    }
+
+    return( sc_recv_poll( sc, ch, resp, len, __WAIT_RECV ) );
+}
+
+
+
+/* sc_poll checks the queue corresponding to the given
+ * subchannel to see if there's anything available.  If
+ * not, it kicks the brl1 layer and then checks again.
+ *
+ * Returns 1 if input is available on the given queue,
+ * 0 otherwise.
+ */
+
+int
+sc_poll( l1sc_t *sc, int ch )
+{
+    brl1_sch_t *subch = &(sc->subch[ch]);
+
+    if( atomic_read(&subch->packet_arrived) )
+	return 1;
+
+    brl1_receive( sc, SERIAL_POLLED_MODE );
+
+    if( atomic_read(&subch->packet_arrived) )
+	return 1;
+
+    return 0;
+}
+
+/* for now, sc_init just calls brl1_init */
+
+void
+sc_init( l1sc_t *sc, nasid_t nasid, net_vec_t uart )
+{
+    if ( !IS_RUNNING_ON_SIMULATOR() )
+    	brl1_init( sc, nasid, uart );
+}
+
+/* sc_dispatch_env_event handles events sent from the system control
+ * network's environmental monitor tasks.
+ */
+
+#if	defined(LINUX_KERNEL_THREADS)
+
+static void
+sc_dispatch_env_event( uint code, int argc, char *args, int maxlen )
+{
+    int j, i = 0;
+    uint32_t ESPcode;
+
+    switch( code ) {
+	/* for now, all codes do the same thing: grab two arguments
+	 * and print a cmn_err_tag message */
+      default:
+	/* check number of arguments */
+	if( argc != 2 ) {
+	    L1_DBG_PRF(( "sc_dispatch_env_event: "
+			 "expected 2 arguments, got %d\n", argc ));
+	    return;
+	}
+	
+	/* get ESP code (integer argument) */
+	if( args[i++] != L1_ARG_INT ) {
+	    L1_DBG_PRF(( "sc_dispatch_env_event: "
+			 "expected integer argument\n" ));
+	    return;
+	}
+	/* WARNING: highly endian */
+	COPY_BUFFER_TO_INT(args, i, ESPcode);
+
+	/* verify string argument */
+	if( args[i++] != L1_ARG_ASCII ) {
+	    L1_DBG_PRF(( "sc_dispatch_env_event: "
+			 "expected an ASCII string\n" ));
+	    return;
+	}
+	for( j = i; j < maxlen; j++ ) {
+	    if( args[j] == '\0' ) break; /* found string termination */
+	}
+	if( j == maxlen ) {
+	    j--;
+	    L1_DBG_PRF(( "sc_dispatch_env_event: "
+			 "message too long-- truncating\n" ));
+	}
+
+	/* strip out trailing cr/lf */
+	for( ; 
+	     j > 1 && ((args[j-1] == 0xd) || (args[j-1] == 0xa)); 
+	     j-- );
+	args[j] = '\0';
+	
+	/* strip out leading cr/lf */
+	for( ;
+	     i < j && ((args[i] == 0xd) || (args[i] == 0xa));
+	     i++ );
+    }
+}
+
+
+/* sc_event waits for events to arrive from the system controller, and
+ * prints appropriate messages to the syslog.
+ */
+
+static void
+sc_event( l1sc_t *sc, int ch )
+{
+    char event[BRL1_QSIZE];
+    int i;
+    int result;
+    int event_len;
+    uint32_t ev_src;
+    uint32_t ev_code;
+    int ev_argc;
+
+    while(1) {
+	
+	bzero( event, BRL1_QSIZE );
+
+	/*
+	 * wait for an event 
+	 */
+	result = sc_recv_intr( sc, ch, event, &event_len, 1 );
+	if( result != SC_SUCCESS ) {
+	    printk(KERN_WARNING  "Error receiving sysctl event on nasid %d\n",
+		     sc->nasid );
+	}
+	else {
+	    /*
+	     * an event arrived; break it down into useful pieces
+	     */
+#if defined(L1_DEBUG) && 0
+	    int ix;
+	    printf( "Event packet received:\n" );
+	    for (ix = 0; ix < 64; ix++) {
+		printf( "%x%x ", ((event[ix] >> 4) & ((uint64_t)0xf)),
+			(event[ix] & ((uint64_t)0xf)) );
+		if( (ix % 16) == 0xf ) printf( "\n" );
+	    }
+#endif /* L1_DEBUG */
+
+	    i = 0;
+
+	    /* get event source */
+	    COPY_BUFFER_TO_INT(event, i, ev_src);
+	    COPY_BUFFER_TO_INT(event, i, ev_code);
+
+	    /* get arg count */
+	    ev_argc = (event[i++] & 0xffUL);
+	    
+	    /* dispatch events by task */
+	    switch( (ev_src & L1_ADDR_TASK_MASK) >> L1_ADDR_TASK_SHFT )
+	    {
+	      case L1_ADDR_TASK_ENV: /* environmental monitor event */
+		sc_dispatch_env_event( ev_code, ev_argc, &(event[i]), 
+				       BRL1_QSIZE - i );
+		break;
+
+	      default: /* unhandled task type */
+		L1_DBG_PRF(( "Unhandled event type received from system "
+			     "controllers: source task %x\n",
+			     (ev_src & L1_ADDR_TASK_MASK) >> L1_ADDR_TASK_SHFT
+			   ));
+	    }
+	}
+	
+    }			
+}
+
+/* sc_listen sets up a service thread to listen for incoming events.
+ */
+
+void
+sc_listen( l1sc_t *sc )
+{
+    int result;
+    unsigned long pl = 0;
+    brl1_sch_t *subch;
+
+    char        msg[BRL1_QSIZE];
+    int         len;    /* length of message being sent */
+    int         ch;     /* system controller subchannel used */
+
+    extern int msc_shutdown_pri;
+
+    /* grab the designated "event subchannel" */
+    SUBCH_LOCK( sc, pl );
+    subch = &(sc->subch[BRL1_EVENT_SUBCH]);
+    if( subch->use != BRL1_SUBCH_FREE ) {
+	SUBCH_UNLOCK( sc, pl );
+	printk(KERN_WARNING  "sysctl event subchannel in use! "
+		 "Not monitoring sysctl events.\n" );
+	return;
+    }
+    subch->use = BRL1_SUBCH_RSVD;
+    SUBCH_UNLOCK( sc, pl );
+
+    atomic_set(&subch->packet_arrived, 0);
+    subch->target = BRL1_LOCALHUB_UART;
+    spin_lock_init( &(subch->data_lock) );
+    sv_init( &(subch->arrive_sv), &(subch->data_lock), SV_MON_SPIN | SV_ORDER_FIFO /* | SV_INTS */);
+    subch->tx_notify = NULL;
+    subch->rx_notify = sc_data_ready;
+    subch->iqp = snia_kmem_zalloc_node( sizeof(sc_cq_t), KM_NOSLEEP,
+				   NASID_TO_COMPACT_NODEID(sc->nasid) );
+    ASSERT( subch->iqp );
+    cq_init( subch->iqp );
+
+    /* set up a thread to listen for events */
+    sthread_create( "sysctl event handler", 0, 0, 0, msc_shutdown_pri,
+		    KT_PS, (st_func_t *) sc_event,
+		    (void *)sc, (void *)(uint64_t)BRL1_EVENT_SUBCH, 0, 0 );
+
+    /* signal the L1 to begin sending events */
+    bzero( msg, BRL1_QSIZE );
+    ch = sc_open( sc, L1_ADDR_LOCAL );
+
+    if( (len = sc_construct_msg( sc, ch, msg, BRL1_QSIZE,
+				 L1_ADDR_TASK_GENERAL,
+				 L1_REQ_EVENT_SUBCH, 2,
+				 L1_ARG_INT, BRL1_EVENT_SUBCH )) < 0 )
+    {
+	sc_close( sc, ch );
+	L1_DBG_PRF(( "Failure in sc_construct_msg (%d)\n", len ));
+	goto err_return;
+    }
+
+    result = sc_command_kern( sc, ch, msg, msg, &len );
+    if( result < 0 )
+    {
+	sc_close( sc, ch );
+	L1_DBG_PRF(( "Failure in sc_command_kern (%d)\n", result ));
+	goto err_return;
+    }
+
+    sc_close( sc, ch );
+
+    result = sc_interpret_resp( msg, 0 );
+    if( result < 0 )
+    {
+	L1_DBG_PRF(( "Failure in sc_interpret_resp (%d)\n", result ));
+	goto err_return;
+    }
+
+    /* everything went fine; just return */
+    return;
+	
+err_return:
+    /* there was a problem; complain */
+    printk(KERN_WARNING  "failed to set sysctl event-monitoring subchannel.  "
+	     "Sysctl events will not be monitored.\n" );
+}
+
+#endif	/* LINUX_KERNEL_THREADS */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn1/l1_command.c linux-2.4.21-pre6/arch/ia64/sn/io/sn1/l1_command.c
--- linux-2.4.20/arch/ia64/sn/io/sn1/l1_command.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn1/l1_command.c	2003-03-26 23:48:58.000000000 +0000
@@ -0,0 +1,1409 @@
+/* $Id: l1_command.c,v 1.2 2002/11/21 17:51:57 jh 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) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */ 
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/io.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/hcl_util.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/eeprom.h>
+#include <asm/sn/router.h>
+#include <asm/sn/module.h>
+#include <asm/sn/ksys/l1.h>
+#include <asm/sn/nodepda.h>
+#include <asm/sn/clksupport.h>
+#include <asm/sn/sn_cpuid.h>
+
+#define ELSC_TIMEOUT	1000000		/* ELSC response timeout (usec) */
+#define LOCK_TIMEOUT	5000000		/* Hub lock timeout (usec) */
+
+#define LD(x)		(*(volatile uint64_t *)(x))
+#define SD(x, v)	(LD(x) = (uint64_t) (v))
+
+#define hub_cpu_get()	0
+
+#define LBYTE(caddr)	(*(char *) caddr)
+
+extern char *bcopy(const char * src, char * dest, int count);
+
+#define LDEBUG		0
+
+/*
+ * ELSC data is in NVRAM page 7 at the following offsets.
+ */
+
+#define NVRAM_MAGIC_AD	0x700		/* magic number used for init */
+#define NVRAM_PASS_WD	0x701		/* password (4 bytes in length) */
+#define NVRAM_DBG1	0x705		/* virtual XOR debug switches */
+#define NVRAM_DBG2	0x706		/* physical XOR debug switches */
+#define NVRAM_CFG	0x707		/* ELSC Configuration info */
+#define NVRAM_MODULE	0x708		/* system module number */
+#define NVRAM_BIST_FLG	0x709		/* BIST flags (2 bits per nodeboard) */
+#define NVRAM_PARTITION 0x70a		/* module's partition id */
+#define	NVRAM_DOMAIN	0x70b		/* module's domain id */
+#define	NVRAM_CLUSTER	0x70c		/* module's cluster id */
+#define	NVRAM_CELL	0x70d		/* module's cellid */
+
+#define NVRAM_MAGIC_NO	0x37		/* value of magic number */
+#define NVRAM_SIZE	16		/* 16 bytes in nvram */
+
+/*
+ * Declare a static ELSC NVRAM buffer to hold all data read from
+ * and written to NVRAM.  This nvram "cache" will be used only during the
+ * IP27prom execution.
+ */
+static char elsc_nvram_buffer[NVRAM_SIZE];
+
+#define SC_COMMAND sc_command
+
+/*
+ * elsc_init
+ *
+ *   Initialize ELSC structure
+ */
+
+void elsc_init(elsc_t *e, nasid_t nasid)
+{
+    sc_init((l1sc_t *)e, nasid, BRL1_LOCALHUB_UART);
+}
+
+
+/*
+ * elsc_errmsg
+ *
+ *   Given a negative error code,
+ *   returns a corresponding static error string.
+ */
+
+char *elsc_errmsg(int code)
+{
+    switch (code) {
+    case ELSC_ERROR_CMD_SEND:
+	return "Command send error";
+    case ELSC_ERROR_CMD_CHECKSUM:
+	return "Command packet checksum error";
+    case ELSC_ERROR_CMD_UNKNOWN:
+	return "Unknown command";
+    case ELSC_ERROR_CMD_ARGS:
+	return "Invalid command argument(s)";
+    case ELSC_ERROR_CMD_PERM:
+	return "Permission denied";
+    case ELSC_ERROR_RESP_TIMEOUT:
+	return "System controller response timeout";
+    case ELSC_ERROR_RESP_CHECKSUM:
+	return "Response packet checksum error";
+    case ELSC_ERROR_RESP_FORMAT:
+	return "Response format error";
+    case ELSC_ERROR_RESP_DIR:
+	return "Response direction error";
+    case ELSC_ERROR_MSG_LOST:
+	return "Message lost because queue is full";
+    case ELSC_ERROR_LOCK_TIMEOUT:
+	return "Timed out getting ELSC lock";
+    case ELSC_ERROR_DATA_SEND:
+	return "Error sending data";
+    case ELSC_ERROR_NIC:
+	return "NIC protocol error";
+    case ELSC_ERROR_NVMAGIC:
+	return "Bad magic number in NVRAM";
+    case ELSC_ERROR_MODULE:
+	return "Module location protocol error";
+    default:
+	return "Unknown error";
+    }
+}
+
+/*
+ * elsc_nvram_init
+ *
+ *   Initializes reads and writes to NVRAM.  This will perform a single
+ *   read to NVRAM, getting all data at once.  When the PROM tries to
+ *   read NVRAM, it returns the data from the buffer being read.  If the
+ *   PROM tries to write out to NVRAM, the write is done, and the internal
+ *   buffer is updated.
+ */
+
+void elsc_nvram_init(nasid_t nasid, uchar_t *elsc_nvram_data)
+{
+    /* This might require implementation of multiple-packet request/responses
+     * if it's to provide the same behavior that was available in SN0.
+     */
+    nasid = nasid;
+    elsc_nvram_data = elsc_nvram_data;
+}
+
+/*
+ * elsc_nvram_copy
+ *
+ *   Copies the content of a buffer into the static buffer in this library.
+ */
+
+void elsc_nvram_copy(uchar_t *elsc_nvram_data)
+{
+    memcpy(elsc_nvram_buffer, elsc_nvram_data, NVRAM_SIZE);
+}
+
+/*
+ * elsc_nvram_write
+ *
+ *   Copies bytes from 'buf' into NVRAM, starting at NVRAM address
+ *   'addr' which must be between 0 and 2047.
+ *
+ *   If 'len' is non-negative, the routine copies 'len' bytes.
+ *
+ *   If 'len' is negative, the routine treats the data as a string and
+ *   copies bytes up to and including a NUL-terminating zero, but not
+ *   to exceed '-len' bytes.
+ */
+
+int elsc_nvram_write(elsc_t *e, int addr, char *buf, int len)
+{
+    /* Here again, we might need to work out the details of a
+     * multiple-packet protocol.
+     */
+
+    /* For now, pretend it worked. */
+    e = e;
+    addr = addr;
+    buf = buf;
+    return (len < 0 ? -len : len);
+}
+
+/*
+ * elsc_nvram_read
+ *
+ *   Copies bytes from NVRAM into 'buf', starting at NVRAM address
+ *   'addr' which must be between 0 and 2047.
+ *
+ *   If 'len' is non-negative, the routine copies 'len' bytes.
+ *
+ *   If 'len' is negative, the routine treats the data as a string and
+ *   copies bytes up to and including a NUL-terminating zero, but not
+ *   to exceed '-len' bytes.  NOTE:  This method is no longer supported.
+ *   It was never used in the first place.
+ */
+
+int elsc_nvram_read(elsc_t *e, int addr, char *buf, int len)
+{
+    /* multiple packets? */
+    e = e;
+    addr = addr;
+    buf = buf;
+    len = len;
+    return -1;
+}
+
+
+/*
+ * Command Set
+ */
+
+int elsc_version(elsc_t *e, char *result)
+{
+    char	msg[BRL1_QSIZE];
+    int		len;    /* length of message being sent */
+    int		subch;  /* system controller subchannel used */
+    int		major,  /* major rev number */
+	        minor,  /* minor rev number */
+                bugfix; /* bugfix rev number */
+
+    /* fill in msg with the opcode & params */
+    bzero( msg, BRL1_QSIZE );
+    subch = sc_open( (l1sc_t *)e, L1_ADDR_LOCAL );
+
+    if( (len = sc_construct_msg( (l1sc_t *)e, subch, msg, BRL1_QSIZE,
+				 L1_ADDR_TASK_GENERAL,
+				 L1_REQ_FW_REV, 0 )) < 0 )
+    {
+	sc_close( e, subch );
+	return( ELSC_ERROR_CMD_ARGS );
+    }
+
+    /* send the request to the L1 */
+    if( SC_COMMAND( (l1sc_t *)e, subch, msg, msg, &len ) < 0 )
+    {
+	sc_close( e, subch );
+	return( ELSC_ERROR_CMD_SEND );
+    }
+
+    /* free up subchannel */
+    sc_close( (l1sc_t *)e, subch );
+
+    /* check response */
+    if( sc_interpret_resp( msg, 6, L1_ARG_INT, &major,
+			   L1_ARG_INT, &minor, L1_ARG_INT, &bugfix )
+	< 0 )
+    {
+	return( ELSC_ERROR_RESP_FORMAT );
+    }
+
+    sprintf( result, "%d.%d.%d", major, minor, bugfix );
+
+    return 0;
+}
+
+int elsc_debug_set(elsc_t *e, u_char byte1, u_char byte2)
+{
+    /* shush compiler */
+    e = e;
+    byte1 = byte1;
+    byte2 = byte2;
+
+    /* fill in a buffer with the opcode & params; call sc_command */
+
+    return 0;
+}
+
+int elsc_debug_get(elsc_t *e, u_char *byte1, u_char *byte2)
+{
+    char	msg[BRL1_QSIZE];
+    int		subch;  /* system controller subchannel used */
+    int		dbg_sw; /* holds debug switch settings */
+    int		len;	/* number of msg buffer bytes used */
+
+    /* fill in msg with the opcode & params */
+    bzero( msg, BRL1_QSIZE );
+    if( (subch = sc_open( (l1sc_t *)e, L1_ADDR_LOCAL )) < 0 ) {
+	return( ELSC_ERROR_CMD_SEND );
+    }
+
+    if( (len = sc_construct_msg( (l1sc_t *)e, subch, msg, BRL1_QSIZE,
+				 L1_ADDR_TASK_GENERAL,
+				 L1_REQ_RDBG, 0 ) ) < 0 )
+    {
+	sc_close( e, subch );
+	return( ELSC_ERROR_CMD_ARGS );
+    }
+
+    /* send the request to the L1 */
+    if( sc_command( (l1sc_t *)e, subch, msg, msg, &len ) < 0 )
+    {
+	sc_close( e, subch );
+	return( ELSC_ERROR_CMD_SEND );
+    }
+
+    /* free up subchannel */
+    sc_close( (l1sc_t *)e, subch );
+
+    /* check response */
+    if( sc_interpret_resp( msg, 2, L1_ARG_INT, &dbg_sw ) < 0 )
+    {
+	return( ELSC_ERROR_RESP_FORMAT );
+    }
+
+    /* copy out debug switch settings (last two bytes of the
+     * integer response)
+     */
+    *byte1 = ((dbg_sw >> 8) & 0xFF);
+    *byte2 = (dbg_sw & 0xFF);
+
+    return 0;
+}
+
+
+/*
+ * elsc_rack_bay_get fills in the two int * arguments with the
+ * rack number and bay number of the L1 being addressed
+ */
+int elsc_rack_bay_get(elsc_t *e, uint *rack, uint *bay)
+{
+    char msg[BRL1_QSIZE];	/* L1 request/response info */
+    int subch;			/* system controller subchannel used */
+    int len;			/* length of message */
+    uint32_t	buf32;		/* used to copy 32-bit rack/bay out of msg */
+
+    /* fill in msg with the opcode & params */
+    bzero( msg, BRL1_QSIZE );
+    if( (subch = sc_open( (l1sc_t *)e, L1_ADDR_LOCAL )) < 0 ) {
+	return( ELSC_ERROR_CMD_SEND );
+    }
+
+    if( (len = sc_construct_msg( (l1sc_t *)e, subch, msg, BRL1_QSIZE,
+				 L1_ADDR_TASK_GENERAL,
+				 L1_REQ_RRACK, 0 )) < 0 ) 
+    {
+	sc_close( e, subch );
+	return( ELSC_ERROR_CMD_ARGS );
+    }
+
+
+    /* send the request to the L1 */
+    if( sc_command( (l1sc_t *)e, subch, msg, msg, &len ) ) {
+	sc_close( e, subch );
+	return( ELSC_ERROR_CMD_SEND );
+    }
+
+    /* free up subchannel */
+    sc_close(e, subch);
+
+    /* check response */
+    if( sc_interpret_resp( msg, 2, L1_ARG_INT, &buf32 ) < 0 )
+    {
+	return( ELSC_ERROR_RESP_FORMAT );
+    }
+
+    /* extract rack/bay info
+     *
+     * note that the 32-bit value returned by the L1 actually
+     * only uses the low-order sixteen bits for rack and bay
+     * information.  A "normal" L1 address puts rack and bay
+     * information in bit positions 12 through 28.  So if
+     * we initially shift the value returned 12 bits to the left,
+     * we can use the L1 addressing #define's to extract the
+     * values we need (see ksys/l1.h for a complete list of the
+     * various fields of an L1 address).
+     */
+    buf32 <<= L1_ADDR_BAY_SHFT;
+
+    *rack = (buf32 & L1_ADDR_RACK_MASK) >> L1_ADDR_RACK_SHFT;
+    *bay = (buf32 & L1_ADDR_BAY_MASK) >> L1_ADDR_BAY_SHFT;
+
+    return 0;
+}
+
+
+/* elsc_rack_bay_type_get fills in the three int * arguments with the
+ * rack number, bay number and brick type of the L1 being addressed.  Note
+ * that if the L1 operation fails and this function returns an error value, 
+ * garbage may be written to brick_type.
+ */
+int elsc_rack_bay_type_get( l1sc_t *sc, uint *rack, 
+			       uint *bay, uint *brick_type )
+{
+    char msg[BRL1_QSIZE];       /* L1 request/response info */
+    int subch;                  /* system controller subchannel used */
+    int len;                    /* length of message */
+    uint32_t buf32;	        /* used to copy 32-bit rack & bay out of msg */
+
+    /* fill in msg with the opcode & params */
+    bzero( msg, BRL1_QSIZE );
+    if( (subch = sc_open( sc, L1_ADDR_LOCAL )) < 0 ) {
+	return ELSC_ERROR_CMD_SEND;
+    }
+
+    if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE,
+				 L1_ADDR_TASK_GENERAL,
+				 L1_REQ_RRBT, 0 )) < 0 )
+    {
+	sc_close( sc, subch );
+	return( ELSC_ERROR_CMD_ARGS );
+    }
+
+    /* send the request to the L1 */
+    if( SC_COMMAND( sc, subch, msg, msg, &len ) ) {
+	sc_close( sc, subch );
+	return( ELSC_ERROR_CMD_SEND );
+    }
+
+    /* free up subchannel */
+    sc_close( sc, subch );
+
+    /* check response */
+    if( sc_interpret_resp( msg, 4, L1_ARG_INT, &buf32, 
+			           L1_ARG_INT, brick_type ) < 0 )
+    {
+	return( ELSC_ERROR_RESP_FORMAT );
+    }
+
+    /* extract rack/bay info
+     *
+     * note that the 32-bit value returned by the L1 actually
+     * only uses the low-order sixteen bits for rack and bay
+     * information.  A "normal" L1 address puts rack and bay
+     * information in bit positions 12 through 28.  So if
+     * we initially shift the value returned 12 bits to the left,
+     * we can use the L1 addressing #define's to extract the
+     * values we need (see ksys/l1.h for a complete list of the
+     * various fields of an L1 address).
+     */
+    buf32 <<= L1_ADDR_BAY_SHFT;
+
+    *rack = (buf32 & L1_ADDR_RACK_MASK) >> L1_ADDR_RACK_SHFT;
+    *bay = (buf32 & L1_ADDR_BAY_MASK) >> L1_ADDR_BAY_SHFT;
+
+    /* convert brick_type to lower case */
+    *brick_type = *brick_type - 'A' + 'a';
+
+    return 0;
+}
+
+
+int elsc_module_get(elsc_t *e)
+{
+    extern char brick_types[];
+    uint rnum, rack, bay, bricktype, t;
+    int ret;
+
+    /* construct module ID from rack and slot info */
+
+    if ((ret = elsc_rack_bay_type_get(e, &rnum, &bay, &bricktype)) < 0) {
+	return ret;
+    }
+
+    /* report unset location info. with a special, otherwise invalid modid */
+    if (rnum == 0 && bay == 0)
+	return MODULE_NOT_SET;
+
+    if (bay > MODULE_BPOS_MASK >> MODULE_BPOS_SHFT)
+	return ELSC_ERROR_MODULE;
+
+    /* Build a moduleid_t-compatible rack number */
+
+    rack = 0;		
+    t = rnum / 100;		/* rack class (CPU/IO) */
+    if (t > RACK_CLASS_MASK(rack) >> RACK_CLASS_SHFT(rack))
+	return ELSC_ERROR_MODULE;
+    RACK_ADD_CLASS(rack, t);
+    rnum %= 100;
+
+    t = rnum / 10;		/* rack group */
+    if (t > RACK_GROUP_MASK(rack) >> RACK_GROUP_SHFT(rack))
+	return ELSC_ERROR_MODULE;
+    RACK_ADD_GROUP(rack, t);
+
+    t = rnum % 10;		/* rack number (one-based) */
+    if (t-1 > RACK_NUM_MASK(rack) >> RACK_NUM_SHFT(rack))
+	return ELSC_ERROR_MODULE;
+    RACK_ADD_NUM(rack, t);
+
+    for( t = 0; t < MAX_BRICK_TYPES; t++ ) {
+	if( brick_types[t] == bricktype )
+	    return RBT_TO_MODULE(rack, bay, t);
+    }
+    
+    return ELSC_ERROR_MODULE;
+}
+
+int elsc_partition_set(elsc_t *e, int partition)
+{
+    char msg[BRL1_QSIZE];       /* L1 request/response info */
+    int subch;                  /* system controller subchannel used */
+    int len;                    /* length of message */
+
+    /* fill in msg with the opcode & params */
+    bzero( msg, BRL1_QSIZE );
+    if( (subch = sc_open( e, L1_ADDR_LOCAL )) < 0 ) {
+	return ELSC_ERROR_CMD_SEND;
+    }
+
+    if( (len = sc_construct_msg( e, subch, msg, BRL1_QSIZE,
+				 L1_ADDR_TASK_GENERAL,
+				 L1_REQ_PARTITION_SET, 2,
+				 L1_ARG_INT, partition )) < 0 )
+    {
+	
+	sc_close( e, subch );
+	return( ELSC_ERROR_CMD_ARGS );
+    }
+
+    /* send the request to the L1 */
+    if( sc_command( e, subch, msg, msg, &len ) ) {
+	sc_close( e, subch );
+	return( ELSC_ERROR_CMD_SEND );
+    }
+
+    /* free up subchannel */
+    sc_close( e, subch );
+
+    /* check response */
+    if( sc_interpret_resp( msg, 0 ) < 0 )
+    {
+	return( ELSC_ERROR_RESP_FORMAT );
+    }
+    
+    return( 0 );
+}
+
+int elsc_partition_get(elsc_t *e)
+{
+    char msg[BRL1_QSIZE];       /* L1 request/response info */
+    int subch;                  /* system controller subchannel used */
+    int len;                    /* length of message */
+    uint32_t partition_id;    /* used to copy partition id out of msg */
+
+    /* fill in msg with the opcode & params */
+    bzero( msg, BRL1_QSIZE );
+    if( (subch = sc_open( e, L1_ADDR_LOCAL )) < 0 ) {
+	return ELSC_ERROR_CMD_SEND;
+    }
+
+    if( (len = sc_construct_msg( e, subch, msg, BRL1_QSIZE,
+				 L1_ADDR_TASK_GENERAL,
+				 L1_REQ_PARTITION_GET, 0 )) < 0 )
+
+    {
+	sc_close( e, subch );
+	return( ELSC_ERROR_CMD_ARGS );
+    }
+
+    /* send the request to the L1 */
+    if( sc_command( e, subch, msg, msg, &len ) ) {
+	sc_close( e, subch );
+	return( ELSC_ERROR_CMD_SEND );
+    }
+
+    /* free up subchannel */
+    sc_close( e, subch );
+
+    /* check response */
+    if( sc_interpret_resp( msg, 2, L1_ARG_INT, &partition_id ) < 0 )
+    {
+	return( ELSC_ERROR_RESP_FORMAT );
+    }
+    
+    return( partition_id );
+}
+
+
+/*
+ * elsc_cons_subch selects the "active" console subchannel for this node
+ * (i.e., the one that will currently receive input)
+ */
+int elsc_cons_subch(elsc_t *e, uint ch)
+{
+    char msg[BRL1_QSIZE];       /* L1 request/response info */
+    int subch;                  /* system controller subchannel used */
+    int len;                    /* length of message */
+
+    /* fill in msg with the opcode & params */
+    bzero( msg, BRL1_QSIZE );
+    subch = sc_open( e, L1_ADDR_LOCAL );
+    
+    if( (len = sc_construct_msg( e, subch, msg, BRL1_QSIZE,
+				 L1_ADDR_TASK_GENERAL,
+				 L1_REQ_CONS_SUBCH, 2,
+				 L1_ARG_INT, ch)) < 0 )
+    {
+	sc_close( e, subch );
+	return( ELSC_ERROR_CMD_ARGS );
+    }
+
+    /* send the request to the L1 */
+    if( SC_COMMAND( e, subch, msg, msg, &len ) ) {
+	sc_close( e, subch );
+	return( ELSC_ERROR_CMD_SEND );
+    }
+
+    /* free up subchannel */
+    sc_close( e, subch );
+
+    /* check response */
+    if( sc_interpret_resp( msg, 0 ) < 0 )
+    {
+	return( ELSC_ERROR_RESP_FORMAT );
+    }
+
+    return 0;
+}
+
+
+/*
+ * elsc_cons_node should only be executed by one node.  It declares to
+ * the system controller that the node from which it is called will be
+ * the owner of the system console.
+ */
+int elsc_cons_node(elsc_t *e)
+{
+    char msg[BRL1_QSIZE];       /* L1 request/response info */
+    int subch;                  /* system controller subchannel used */
+    int len;                    /* length of message */
+
+    /* fill in msg with the opcode & params */
+    bzero( msg, BRL1_QSIZE );
+    subch = sc_open( e, L1_ADDR_LOCAL );
+    
+    if( (len = sc_construct_msg( e, subch, msg, BRL1_QSIZE,
+				 L1_ADDR_TASK_GENERAL,
+				 L1_REQ_CONS_NODE, 0 )) < 0 )
+    {
+	sc_close( e, subch );
+	return( ELSC_ERROR_CMD_ARGS );
+    }
+
+    /* send the request to the L1 */
+    if( SC_COMMAND( e, subch, msg, msg, &len ) ) {
+	sc_close( e, subch );
+	return( ELSC_ERROR_CMD_SEND );
+    }
+
+    /* free up subchannel */
+    sc_close( e, subch );
+
+    /* check response */
+    if( sc_interpret_resp( msg, 0 ) < 0 )
+    {
+	return( ELSC_ERROR_RESP_FORMAT );
+    }
+
+    return 0;
+}
+    
+
+/* elsc_display_line writes up to 12 characters to either the top or bottom
+ * line of the L1 display.  line points to a buffer containing the message
+ * to be displayed.  The zero-based line number is specified by lnum (so
+ * lnum == 0 specifies the top line and lnum == 1 specifies the bottom).
+ * Lines longer than 12 characters, or line numbers not less than
+ * L1_DISPLAY_LINES, cause elsc_display_line to return an error.
+ */
+int elsc_display_line(elsc_t *e, char *line, int lnum)
+{
+    char	msg[BRL1_QSIZE];
+    int		subch;  /* system controller subchannel used */
+    int		len;	/* number of msg buffer bytes used */
+
+    /* argument sanity checking */
+    if( !(lnum < L1_DISPLAY_LINES) )
+	return( ELSC_ERROR_CMD_ARGS );
+    if( !(strlen( line ) <= L1_DISPLAY_LINE_LENGTH) )
+	return( ELSC_ERROR_CMD_ARGS );
+
+    /* fill in msg with the opcode & params */
+    bzero( msg, BRL1_QSIZE );
+    subch = sc_open( (l1sc_t *)e, L1_ADDR_LOCAL );
+
+    if( (len = sc_construct_msg( (l1sc_t *)e, subch, msg, BRL1_QSIZE,
+				 L1_ADDR_TASK_GENERAL,
+				 (L1_REQ_DISP1+lnum), 2,
+				 L1_ARG_ASCII, line )) < 0 )
+    {
+	sc_close( e, subch );
+	return( ELSC_ERROR_CMD_ARGS );
+    }
+
+    /* send the request to the L1 */
+    if( SC_COMMAND( (l1sc_t *)e, subch, msg, msg, &len ) < 0 )
+    {
+	sc_close( e, subch );
+	return( ELSC_ERROR_CMD_SEND );
+    }
+
+    /* free up subchannel */
+    sc_close( (l1sc_t *)e, subch );
+
+    /* check response */
+    if( sc_interpret_resp( msg, 0 ) < 0 )
+    {
+	return( ELSC_ERROR_RESP_FORMAT );
+    }
+
+    return 0;
+}
+
+
+/* elsc_display_mesg silently drops message characters beyond the 12th.
+ */
+int elsc_display_mesg(elsc_t *e, char *chr)
+{
+
+    char line[L1_DISPLAY_LINE_LENGTH+1];
+    int numlines, i;
+    int result;
+
+    numlines = (strlen( chr ) + L1_DISPLAY_LINE_LENGTH - 1) /
+	L1_DISPLAY_LINE_LENGTH;
+
+    if( numlines > L1_DISPLAY_LINES )
+	numlines = L1_DISPLAY_LINES;
+
+    for( i = 0; i < numlines; i++ )
+    {
+	strncpy( line, chr, L1_DISPLAY_LINE_LENGTH );
+	line[L1_DISPLAY_LINE_LENGTH] = '\0';
+
+	/* generally we want to leave the first line of the L1 display
+	 * alone (so the L1 can manipulate it).  If you need to be able
+	 * to display to both lines (for debugging purposes), define
+	 * L1_DISP_2LINES in irix/kern/ksys/l1.h, or add -DL1_DISP_2LINES
+	 * to your 'defs file.
+	 */
+#if defined(L1_DISP_2LINES)
+	if( (result = elsc_display_line( e, line, i )) < 0 )
+#else
+	if( (result = elsc_display_line( e, line, i+1 )) < 0 )
+#endif
+
+	    return result;
+
+	chr += L1_DISPLAY_LINE_LENGTH;
+    }
+    
+    return 0;
+}
+
+
+int elsc_password_set(elsc_t *e, char *password)
+{
+    /* shush compiler */
+    e = e;
+    password = password;
+
+    /* fill in buffer with the opcode & params; call elsc_command */
+
+    return 0;
+}
+
+int elsc_password_get(elsc_t *e, char *password)
+{
+    /* shush compiler */
+    e = e;
+    password = password;
+
+    /* fill in buffer with the opcode & params; call elsc_command */
+
+    return 0;
+}
+
+
+/*
+ * sc_portspeed_get
+ *
+ * retrieve the current portspeed setting for the bedrock II
+ */
+int sc_portspeed_get(l1sc_t *sc)
+{
+    char	msg[BRL1_QSIZE];
+    int         len;    /* length of message being sent */
+    int         subch;  /* system controller subchannel used */
+    int		portspeed_a, portspeed_b;
+			/* ioport clock rates */
+
+    bzero( msg, BRL1_QSIZE );
+    subch = sc_open( sc, L1_ADDR_LOCAL );
+
+    if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE,
+                                 L1_ADDR_TASK_GENERAL,
+				 L1_REQ_PORTSPEED,
+				 0 )) < 0 )
+    {
+	sc_close( sc, subch );
+	return( ELSC_ERROR_CMD_ARGS );
+    }
+    
+    /* send the request to the L1 */
+    if( sc_command( sc, subch, msg, msg, &len ) < 0 )
+    {
+        sc_close( sc, subch );
+        return( ELSC_ERROR_CMD_SEND );
+    }
+
+    /* free up subchannel */
+    sc_close( sc, subch );
+
+    /* check response */
+    if( sc_interpret_resp( msg, 4, 
+			   L1_ARG_INT, &portspeed_a,
+			   L1_ARG_INT, &portspeed_b ) < 0 )
+    {
+	return( ELSC_ERROR_RESP_FORMAT );
+    }
+
+    /* for the c-brick, we ignore the portspeed_b value */
+    return (portspeed_a ? 600 : 400);
+}
+
+/*
+ * elsc_power_query
+ *
+ *   To be used after system reset, this command returns 1 if the reset
+ *   was the result of a power-on, 0 otherwise.
+ *
+ *   The power query status is cleared to 0 after it is read.
+ */
+
+int elsc_power_query(elsc_t *e)
+{
+    e = e; /* shush the compiler */
+
+    /* fill in buffer with the opcode & params; call elsc_command */
+
+    return 1;
+}
+
+int elsc_rpwr_query(elsc_t *e, int is_master)
+{
+    /* shush the compiler */
+    e = e;
+    is_master = is_master;
+
+    /* fill in buffer with the opcode & params; call elsc_command */
+
+    return 0;
+} 
+
+/*
+ * elsc_power_down
+ *
+ *   Sets up system to shut down in "sec" seconds (or modifies the
+ *   shutdown time if one is already in effect).  Use 0 to power
+ *   down immediately.
+ */
+
+int elsc_power_down(elsc_t *e, int sec)
+{
+    /* shush compiler */
+    e = e;
+    sec = sec;
+
+    /* fill in buffer with the opcode & params; call elsc_command */
+
+    return 0;
+}
+
+
+int elsc_system_reset(elsc_t *e)
+{
+    char	msg[BRL1_QSIZE];
+    int		subch;  /* system controller subchannel used */
+    int		len;	/* number of msg buffer bytes used */
+    int		result;
+
+    /* fill in msg with the opcode & params */
+    bzero( msg, BRL1_QSIZE );
+    if( (subch = sc_open( e, L1_ADDR_LOCAL )) < 0 ) {
+	return ELSC_ERROR_CMD_SEND;
+    }
+
+    if( (len = sc_construct_msg( e, subch, msg, BRL1_QSIZE,
+				 L1_ADDR_TASK_GENERAL,
+				 L1_REQ_RESET, 0 )) < 0 )
+    {
+	sc_close( e, subch );
+	return( ELSC_ERROR_CMD_ARGS );
+    }
+
+    /* send the request to the L1 */
+    if( (result = sc_command( e, subch, msg, msg, &len )) ) {
+	sc_close( e, subch );
+	if( result == SC_NMSG ) {
+	    /* timeout is OK.  We've sent the reset.  Now it's just
+	     * a matter of time...
+	     */
+	    return( 0 );
+	}
+	return( ELSC_ERROR_CMD_SEND );
+    }
+
+    /* free up subchannel */
+    sc_close( e, subch );
+
+    /* check response */
+    if( sc_interpret_resp( msg, 0 ) < 0 )
+    {
+	return( ELSC_ERROR_RESP_FORMAT );
+    }
+
+    return 0;
+}
+
+
+int elsc_power_cycle(elsc_t *e)
+{
+    /* shush compiler */
+    e = e;
+
+    /* fill in buffer with the opcode & params; call sc_command */
+
+    return 0;
+}
+
+
+int _elsc_hbt(elsc_t *e, int ival, int rdly)
+{
+    e = e;
+    ival = ival;
+    rdly = rdly;
+
+    /* fill in buffer with the opcode & params; call elsc_command */
+
+    return 0;
+}
+
+
+/* send a command string to an L1 */
+int sc_command_interp( l1sc_t *sc, l1addr_t compt, l1addr_t rack, l1addr_t bay,
+		       char *cmd )
+{
+    char        msg[BRL1_QSIZE];
+    int         len;    /* length of message being sent */
+    int         subch;  /* system controller subchannel used */
+    l1addr_t	target; /* target system controller for command */
+
+    /* fill in msg with the opcode & params */
+    bzero( msg, BRL1_QSIZE );
+
+    L1_BUILD_ADDR( &target, compt, rack, bay, 0 );
+    subch = sc_open( sc, target );
+
+    if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE,
+				 L1_ADDR_TASK_CMD, L1_REQ_EXEC_CMD, 2,
+				 L1_ARG_ASCII, cmd )) < 0 )
+    {
+	sc_close( sc, subch );
+	return( ELSC_ERROR_CMD_ARGS );
+    }
+		   
+    /* send the request to the L1 */
+    if( SC_COMMAND( sc, subch, msg, msg, &len ) < 0 )
+    {
+	sc_close( sc, subch );
+	return( ELSC_ERROR_CMD_SEND );
+    }
+
+    /* free up subchannel */
+    sc_close( sc, subch );
+    
+    /* check response */
+    if( sc_interpret_resp( msg, 0 ) < 0 )
+    {
+	return( ELSC_ERROR_RESP_FORMAT );
+    }
+
+    return 0;
+}
+
+/*
+ * sc_power_down
+ *
+ * Shuts down the c-brick associated with sc, and any attached I/O bricks
+ * or other c-bricks (won't go through r-bricks).
+ */
+
+int sc_power_down(l1sc_t *sc)
+{
+    return sc_command_interp( sc, L1_ADDR_TYPE_L1, L1_ADDR_RACK_LOCAL, 
+			      L1_ADDR_BAY_LOCAL, "* pwr d" );
+}
+
+
+/*
+ * sc_power_down_all
+ *
+ * Works similarly to sc_power_down, except that the request is sent to the
+ * closest L2 and EVERYBODY gets turned off.
+ */
+
+int sc_power_down_all(l1sc_t *sc)
+{
+    if( nodepda->num_routers > 0 ) {
+	return sc_command_interp( sc, L1_ADDR_TYPE_L2, L1_ADDR_RACK_LOCAL, 
+				  L1_ADDR_BAY_LOCAL, "* pwr d" );
+    }
+    else {
+	return sc_power_down( sc );
+    }
+}
+
+
+/*
+ * iobrick routines
+ */
+
+/* iobrick_rack_bay_type_get fills in the three int * arguments with the
+ * rack number, bay number and brick type of the L1 being addressed.  Note
+ * that if the L1 operation fails and this function returns an error value, 
+ * garbage may be written to brick_type.
+ */
+int iobrick_rack_bay_type_get( l1sc_t *sc, uint *rack, 
+			       uint *bay, uint *brick_type )
+{
+    char msg[BRL1_QSIZE];       /* L1 request/response info */
+    int subch;                  /* system controller subchannel used */
+    int len;                    /* length of message */
+    uint32_t buf32;	        /* used to copy 32-bit rack & bay out of msg */
+
+    /* fill in msg with the opcode & params */
+    bzero( msg, BRL1_QSIZE );
+    if( (subch = sc_open( sc, L1_ADDR_LOCALIO )) < 0 ) {
+	return( ELSC_ERROR_CMD_SEND );
+    }
+
+    if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE,
+				 L1_ADDR_TASK_GENERAL,
+				 L1_REQ_RRBT, 0 )) < 0 )
+    {
+	sc_close( sc, subch );
+	return( ELSC_ERROR_CMD_ARGS );
+    }
+
+    /* send the request to the L1 */
+    if( sc_command( sc, subch, msg, msg, &len ) ) {
+	sc_close( sc, subch );
+	return( ELSC_ERROR_CMD_SEND );
+    }
+
+    /* free up subchannel */
+    sc_close( sc, subch );
+
+    /* check response */
+    if( sc_interpret_resp( msg, 4, L1_ARG_INT, &buf32, 
+			           L1_ARG_INT, brick_type ) < 0 )
+    {
+	return( ELSC_ERROR_RESP_FORMAT );
+    }
+
+    /* extract rack/bay info
+     *
+     * note that the 32-bit value returned by the L1 actually
+     * only uses the low-order sixteen bits for rack and bay
+     * information.  A "normal" L1 address puts rack and bay
+     * information in bit positions 12 through 28.  So if
+     * we initially shift the value returned 12 bits to the left,
+     * we can use the L1 addressing #define's to extract the
+     * values we need (see ksys/l1.h for a complete list of the
+     * various fields of an L1 address).
+     */
+    buf32 <<= L1_ADDR_BAY_SHFT;
+
+    *rack = (buf32 & L1_ADDR_RACK_MASK) >> L1_ADDR_RACK_SHFT;
+    *bay = (buf32 & L1_ADDR_BAY_MASK) >> L1_ADDR_BAY_SHFT;
+
+    return 0;
+}
+
+
+int iobrick_module_get(l1sc_t *sc)
+{
+    uint rnum, rack, bay, brick_type, t;
+    int ret;
+
+    /* construct module ID from rack and slot info */
+
+    if ((ret = iobrick_rack_bay_type_get(sc, &rnum, &bay, &brick_type)) < 0)
+        return ret;
+
+    if (bay > MODULE_BPOS_MASK >> MODULE_BPOS_SHFT)
+        return ELSC_ERROR_MODULE;
+
+    /* Build a moduleid_t-compatible rack number */
+
+    rack = 0;           
+    t = rnum / 100;             /* rack class (CPU/IO) */
+    if (t > RACK_CLASS_MASK(rack) >> RACK_CLASS_SHFT(rack))
+        return ELSC_ERROR_MODULE;
+    RACK_ADD_CLASS(rack, t);
+    rnum %= 100;
+
+    t = rnum / 10;              /* rack group */
+    if (t > RACK_GROUP_MASK(rack) >> RACK_GROUP_SHFT(rack))
+        return ELSC_ERROR_MODULE;
+    RACK_ADD_GROUP(rack, t);
+
+    t = rnum % 10;              /* rack number (one-based) */
+    if (t-1 > RACK_NUM_MASK(rack) >> RACK_NUM_SHFT(rack))
+        return ELSC_ERROR_MODULE;
+    RACK_ADD_NUM(rack, t);
+
+    switch( brick_type ) {
+      case 'I': 
+	brick_type = MODULE_IBRICK; break;
+      case 'P':
+	brick_type = MODULE_PBRICK; break;
+      case 'X':
+	brick_type = MODULE_XBRICK; break;
+    }
+
+    ret = RBT_TO_MODULE(rack, bay, brick_type);
+
+    return ret;
+}
+
+/*
+ * iobrick_module_get_nasid() returns a module_id which has the brick
+ * type encoded in bits 15-12, but this is not the true brick type...
+ * The module_id returned by iobrick_module_get_nasid() is modified
+ * to make a PEBRICKs & PXBRICKs look like a PBRICK.  So this routine
+ * iobrick_type_get_nasid() returns the true unmodified brick type.
+ */
+int
+iobrick_type_get_nasid(nasid_t nasid)
+{
+    l1sc_t *sc = get_elsc();
+    elsc_t tmp_sc;
+    uint rack, bay, type;
+    int t, ret;
+
+#ifdef PIC_LATER
+    if (PEBRICK_NODE(nasid)) {
+        if (peer_iobrick_rack_bay_get(nasid, &rack, &bay)) {
+            printf("Could not read rack and bay location "
+                   "of PEBrick at nasid %d\n", nasid);
+        }
+        if ((ret = peer_iobrick_type_get(sc, rack, bay, &type)) < 0)
+            return ret;
+    }
+    else
+#endif	/* PIC_LATER */
+    if (nasid != get_nasid()) { /* get the io_moduleid from remote node */
+        elsc_init(&tmp_sc, nasid);
+        if ((ret = iobrick_rack_bay_type_get(&tmp_sc, &rack, &bay, &type)) < 0)
+            return ret;
+    }
+    else {
+        if ((ret = iobrick_rack_bay_type_get(sc, &rack, &bay, &type)) < 0)
+            return ret;
+    }
+
+    /*
+     * Some brick_types need special treatment.  NOTE: This switch is
+     * duplicated in iobrick_module_get(),  so if you change this switch
+     * you must also change it there.
+     */
+    switch (type)
+    {
+    case L1_BRICKTYPE_IP45:
+        /* treat speedo2 like Ibrick for moduleid purposes */
+        type = L1_BRICKTYPE_I;
+        break;
+    case L1_BRICKTYPE_X2:
+        /* give X2 bricks the same moduleid as earlier models */
+        type = L1_BRICKTYPE_X;
+        break;
+    }
+
+    /* convert brick_type to lower case */
+    if ((type >= 'A') && (type <= 'Z'))
+        type = type - 'A' + 'a';
+
+    /* convert to a module.h brick type */
+    for( t = 0; t < MAX_BRICK_TYPES; t++ ) {
+        if( brick_types[t] == type )
+            return t;
+    }
+
+    return -1;    /* unknown brick */
+}
+
+int iobrick_module_get_nasid(nasid_t nasid)
+{
+    int io_moduleid;
+    l1sc_t *sc = get_elsc();
+    elsc_t tmp_sc;
+
+#ifdef PIC_LATER
+    uint rack, bay;
+
+    if (PEBRICK_NODE(nasid)) {
+        if (peer_iobrick_rack_bay_get(nasid, &rack, &bay)) {
+            printf("Could not read rack and bay location "
+                   "of PEBrick at nasid %d\n", nasid);
+        }
+
+        io_moduleid = peer_iobrick_module_get(sc, rack, bay);
+    }
+    else
+#endif	/* PIC_LATER */
+    if (nasid != get_nasid()) { /* get the io_moduleid from remote node */
+        elsc_init(&tmp_sc, nasid);
+
+        io_moduleid = iobrick_module_get(&tmp_sc);
+    }
+    else {
+        io_moduleid = iobrick_module_get(sc);
+    }
+
+    return io_moduleid;
+}
+
+
+/* iobrick_get_sys_snum asks the attached iobrick for the system
+ * serial number.  This function will only be relevant to the master
+ * cbrick (the one attached to the bootmaster ibrick); other nodes
+ * may call the function, but the value returned to the master node
+ * will be the one used as the system serial number by the kernel.
+ */
+
+int
+iobrick_get_sys_snum( l1sc_t *sc, char *snum_str )
+{
+    char msg[BRL1_QSIZE];       /* L1 request/response info */
+    int subch;                  /* system controller subchannel used */
+    int len;                    /* length of message */
+    
+    /* fill in msg with the opcode & params */
+    bzero( msg, BRL1_QSIZE );
+    if( (subch = sc_open( sc, L1_ADDR_LOCALIO )) < 0 ) {
+	return( ELSC_ERROR_CMD_SEND );
+    }
+
+    if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE,
+				 L1_ADDR_TASK_GENERAL,
+				 L1_REQ_SYS_SERIAL, 0 )) < 0 )
+    {
+	sc_close( sc, subch );
+	return( ELSC_ERROR_CMD_ARGS );
+    }
+
+    /* send the request to the L1 */
+    if( sc_command( sc, subch, msg, msg, &len ) ) {
+	sc_close( sc, subch );
+	return( ELSC_ERROR_CMD_SEND );
+    }
+
+    /* free up subchannel */
+    sc_close( sc, subch );
+
+    /* check response */
+    return( sc_interpret_resp( msg, 2, L1_ARG_ASCII, snum_str ) );
+}
+
+
+/*
+ * The following functions apply (or cut off) power to the specified
+ * pci bus or slot.
+ */
+
+int
+iobrick_pci_pwr( l1sc_t *sc, int bus, int slot, int req_code )
+{
+#if 0 /* The "bedrock request" method of performing this function
+       * seems to be broken in the L1, so for now use the command-
+       * interpreter method
+       */
+
+    char	msg[BRL1_QSIZE];
+    int		len;    /* length of message being sent */
+    int		subch;  /* system controller subchannel used */
+
+    /* fill in msg with the opcode & params */
+    bzero( msg, BRL1_QSIZE );
+    subch = sc_open( sc, L1_ADDR_LOCALIO );
+
+    if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE,
+				 L1_ADDR_TASK_GENERAL,
+				 req_code, 4,
+				 L1_ARG_INT, bus,
+				 L1_ARG_INT, slot )) < 0 )
+    {
+	sc_close( sc, subch );
+	return( ELSC_ERROR_CMD_ARGS );
+    }
+
+    /* send the request to the L1 */
+    if( SC_COMMAND(sc, subch, msg, msg, &len ) < 0 )
+    {
+	sc_close( sc, subch );
+	return( ELSC_ERROR_CMD_SEND );
+    }
+
+    /* free up subchannel */
+    sc_close( sc, subch );
+
+    /* check response */
+    if( sc_interpret_resp( msg, 0 ) < 0 )
+    {
+	return( ELSC_ERROR_RESP_FORMAT );
+    }
+
+    return 0;
+
+#else
+    char cmd[64];
+    char *fxn;
+
+    switch( req_code )
+    {
+    case L1_REQ_PCI_UP:
+	fxn = "u";
+	break;
+    case L1_REQ_PCI_DOWN:
+	fxn = "d";
+	break;
+    case L1_REQ_PCI_RESET:
+	fxn = "rst";
+	break;
+    default:
+	return( ELSC_ERROR_CMD_ARGS );
+    }
+
+    if( slot == -1 ) 
+	sprintf( cmd, "pci %d %s", bus, fxn );
+    else
+        sprintf( cmd, "pci %d %d %s", bus, slot, fxn );
+	
+    return sc_command_interp( sc, L1_ADDR_TYPE_IOBRICK,
+	L1_ADDR_RACK_LOCAL, L1_ADDR_BAY_LOCAL, cmd );
+#endif
+}
+				 
+int
+iobrick_pci_slot_pwr( l1sc_t *sc, int bus, int slot, int up )
+{
+    return iobrick_pci_pwr( sc, bus, slot, up );
+}
+
+int
+iobrick_pci_bus_pwr( l1sc_t *sc, int bus, int up )
+{
+    return iobrick_pci_pwr( sc, bus, -1, up );
+}
+
+
+int
+iobrick_pci_slot_rst( l1sc_t *sc, int bus, int slot )
+{
+    return iobrick_pci_pwr( sc, bus, slot, L1_REQ_PCI_RESET );
+}
+
+int
+iobrick_pci_bus_rst( l1sc_t *sc, int bus )
+{
+    return iobrick_pci_pwr( sc, bus, -1, L1_REQ_PCI_RESET );
+}
+
+
+/* get the L1 firmware version for an iobrick */
+int
+iobrick_sc_version( l1sc_t *sc, char *result )
+{
+    char	msg[BRL1_QSIZE];
+    int		len;    /* length of message being sent */
+    int		subch;  /* system controller subchannel used */
+    int		major,  /* major rev number */
+	        minor,  /* minor rev number */
+                bugfix; /* bugfix rev number */
+
+    /* fill in msg with the opcode & params */
+    bzero( msg, BRL1_QSIZE );
+    subch = sc_open( sc, L1_ADDR_LOCALIO );
+
+    if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE,
+				 L1_ADDR_TASK_GENERAL,
+				 L1_REQ_FW_REV, 0 )) < 0 )
+    {
+	sc_close( sc, subch );
+	return( ELSC_ERROR_CMD_ARGS );
+    }
+
+    /* send the request to the L1 */
+    if( SC_COMMAND(sc, subch, msg, msg, &len ) < 0 )
+    {
+	sc_close( sc, subch );
+	return( ELSC_ERROR_CMD_SEND );
+    }
+
+    /* free up subchannel */
+    sc_close( sc, subch );
+
+    /* check response */
+    if( sc_interpret_resp( msg, 6, L1_ARG_INT, &major,
+			   L1_ARG_INT, &minor, L1_ARG_INT, &bugfix )
+	< 0 )
+    {
+	return( ELSC_ERROR_RESP_FORMAT );
+    }
+
+    sprintf( result, "%d.%d.%d", major, minor, bugfix );
+
+    return 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn1/mem_refcnt.c linux-2.4.21-pre6/arch/ia64/sn/io/sn1/mem_refcnt.c
--- linux-2.4.20/arch/ia64/sn/io/sn1/mem_refcnt.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn1/mem_refcnt.c	2003-03-26 23:49:20.000000000 +0000
@@ -7,7 +7,6 @@
  * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <asm/sn/arch.h>
 #include <asm/sn/sgi.h>
@@ -43,7 +42,7 @@
 int
 mem_refcnt_attach(devfs_handle_t hub)
 {
-#ifndef CONFIG_IA64_SGI_SN
+#if 0
         devfs_handle_t refcnt_dev;
         
         hwgraph_char_device_add(hub,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn1/ml_SN_init.c linux-2.4.21-pre6/arch/ia64/sn/io/sn1/ml_SN_init.c
--- linux-2.4.20/arch/ia64/sn/io/sn1/ml_SN_init.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn1/ml_SN_init.c	2003-03-26 23:49:39.000000000 +0000
@@ -0,0 +1,211 @@
+/* $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) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/bootmem.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/io.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/sn_private.h>
+#include <asm/sn/klconfig.h>
+#include <asm/sn/sn_cpuid.h>
+#include <asm/sn/snconfig.h>
+
+extern int numcpus;
+extern char arg_maxnodes[];
+extern cpuid_t master_procid;
+extern synergy_da_t    *Synergy_da_indr[];
+
+extern int hasmetarouter;
+
+int		maxcpus;
+cpumask_t	boot_cpumask;
+hubreg_t	region_mask = 0;
+
+
+extern xwidgetnum_t hub_widget_id(nasid_t);
+
+extern int valid_icache_reasons;	/* Reasons to flush the icache */
+extern int valid_dcache_reasons;	/* Reasons to flush the dcache */
+extern u_char miniroot;
+extern volatile int	need_utlbmiss_patch;
+extern void iograph_early_init(void);
+
+nasid_t master_nasid = INVALID_NASID;
+
+
+/*
+ * mlreset(int slave)
+ * 	very early machine reset - at this point NO interrupts have been
+ * 	enabled; nor is memory, tlb, p0, etc setup.
+ *
+ * 	slave is zero when mlreset is called for the master processor and
+ *	is nonzero thereafter.
+ */
+
+
+void
+mlreset(int slave)
+{
+	if (!slave) {
+		/*
+		 * We are the master cpu and node.
+		 */ 
+		master_nasid = get_nasid();
+		set_master_bridge_base();
+
+		/* We're the master processor */
+		master_procid = smp_processor_id();
+		master_nasid = cpuid_to_nasid(master_procid);
+
+		/*
+		 * master_nasid we get back better be same as one from
+		 * get_nasid()
+		 */
+		ASSERT_ALWAYS(master_nasid == get_nasid());
+
+		/* early initialization of iograph */
+		iograph_early_init();
+
+		/* Initialize Hub Pseudodriver Management */
+		hubdev_init();
+
+	} else { /* slave != 0 */
+		/*
+		 * This code is performed ONLY by slave processors.
+		 */
+
+	}
+}
+
+
+/* XXX - Move the meat of this to intr.c ? */
+/*
+ * Set up the platform-dependent fields in the nodepda.
+ */
+void init_platform_nodepda(nodepda_t *npda, cnodeid_t node)
+{
+	hubinfo_t hubinfo;
+	int	  sn;
+
+	extern void router_map_init(nodepda_t *);
+	extern void router_queue_init(nodepda_t *,cnodeid_t);
+	extern void intr_init_vecblk(nodepda_t *, cnodeid_t, int);
+
+	/* Allocate per-node platform-dependent data */
+	hubinfo = (hubinfo_t)alloc_bootmem_node(NODE_DATA(node), sizeof(struct hubinfo_s));
+
+	npda->pdinfo = (void *)hubinfo;
+	hubinfo->h_nodepda = npda;
+	hubinfo->h_cnodeid = node;
+	hubinfo->h_nasid = COMPACT_TO_NASID_NODEID(node);
+
+	spin_lock_init(&hubinfo->h_crblock);
+
+	hubinfo->h_widgetid = hub_widget_id(hubinfo->h_nasid);
+	npda->xbow_peer = INVALID_NASID;
+
+	/* 
+	 * Initialize the linked list of
+	 * router info pointers to the dependent routers
+	 */
+	npda->npda_rip_first = NULL;
+
+	/*
+	 * npda_rip_last always points to the place
+	 * where the next element is to be inserted
+	 * into the list 
+	 */
+	npda->npda_rip_last = &npda->npda_rip_first;
+	npda->module_id = INVALID_MODULE;
+
+	/*
+	* Initialize the interrupts.
+	* On sn2, this is done at pci init time,
+	* because sn2 needs the cpus checked in
+	* when it initializes interrupts.  This is
+	* so we don't see all the nodes as headless.
+	*/
+	for (sn=0; sn<NUM_SUBNODES; sn++) {
+		intr_init_vecblk(npda, node, sn);
+	}
+
+	mutex_init_locked(&npda->xbow_sema); /* init it locked? */
+}
+
+/* XXX - Move the interrupt stuff to intr.c ? */
+/*
+ * Set up the platform-dependent fields in the processor pda.
+ * Must be done _after_ init_platform_nodepda().
+ * If we need a lock here, something else is wrong!
+ */
+void init_platform_pda(cpuid_t cpu)
+{
+	hub_intmasks_t *intmasks;
+	int i, subnode;
+	cnodeid_t	cnode;
+	synergy_da_t	*sda;
+	int	which_synergy;
+
+
+	cnode = cpuid_to_cnodeid(cpu);
+	which_synergy = cpuid_to_synergy(cpu);
+
+	sda = Synergy_da_indr[(cnode * 2) + which_synergy];
+	intmasks = &sda->s_intmasks;
+
+	/* Clear INT_PEND0 masks. */
+	for (i = 0; i < N_INTPEND0_MASKS; i++)
+		intmasks->intpend0_masks[i] = 0;
+
+	/* Set up pointer to the vector block in the nodepda. */
+	/* (Cant use SUBNODEPDA - not working yet) */
+	subnode = cpuid_to_subnode(cpu);
+	intmasks->dispatch0 = &NODEPDA(cnode)->snpda[cpuid_to_subnode(cpu)].intr_dispatch0;
+	intmasks->dispatch1 = &NODEPDA(cnode)->snpda[cpuid_to_subnode(cpu)].intr_dispatch1;
+	if (intmasks->dispatch0 !=  &SUBNODEPDA(cnode, subnode)->intr_dispatch0 ||
+	   intmasks->dispatch1 !=  &SUBNODEPDA(cnode, subnode)->intr_dispatch1)
+	   	panic("xxx");
+	intmasks->dispatch0 = &SUBNODEPDA(cnode, subnode)->intr_dispatch0;
+	intmasks->dispatch1 = &SUBNODEPDA(cnode, subnode)->intr_dispatch1;
+
+	/* Clear INT_PEND1 masks. */
+	for (i = 0; i < N_INTPEND1_MASKS; i++)
+		intmasks->intpend1_masks[i] = 0;
+}
+
+void
+update_node_information(cnodeid_t cnodeid)
+{
+	nodepda_t *npda = NODEPDA(cnodeid);
+	nodepda_router_info_t *npda_rip;
+	
+	/* Go through the list of router info 
+	 * structures and copy some frequently
+	 * accessed info from the info hanging
+	 * off the corresponding router vertices
+	 */
+	npda_rip = npda->npda_rip_first;
+	while(npda_rip) {
+		if (npda_rip->router_infop) {
+			npda_rip->router_portmask = 
+				npda_rip->router_infop->ri_portmask;
+			npda_rip->router_slot = 
+				npda_rip->router_infop->ri_slotnum;
+		} else {
+			/* No router, no ports. */
+			npda_rip->router_portmask = 0;
+		}
+		npda_rip = npda_rip->router_next;
+	}
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn1/ml_iograph.c linux-2.4.21-pre6/arch/ia64/sn/io/sn1/ml_iograph.c
--- linux-2.4.20/arch/ia64/sn/io/sn1/ml_iograph.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn1/ml_iograph.c	2003-03-26 23:49:09.000000000 +0000
@@ -0,0 +1,1505 @@
+/* $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) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/io.h>
+#include <asm/sn/sn_cpuid.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/hcl_util.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/xtalk/xbow.h>
+#include <asm/sn/pci/bridge.h>
+#include <asm/sn/klconfig.h>
+#include <asm/sn/eeprom.h>
+#include <asm/sn/sn_private.h>
+#include <asm/sn/pci/pcibr.h>
+#include <asm/sn/xtalk/xtalk.h>
+#include <asm/sn/xtalk/xswitch.h>
+#include <asm/sn/xtalk/xwidget.h>
+#include <asm/sn/xtalk/xtalk_private.h>
+#include <asm/sn/xtalk/xtalkaddrs.h>
+
+/* #define IOGRAPH_DEBUG */
+#ifdef IOGRAPH_DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif /* IOGRAPH_DEBUG */
+
+/* #define PROBE_TEST */
+
+/* At most 2 hubs can be connected to an xswitch */
+#define NUM_XSWITCH_VOLUNTEER 2
+
+/*
+ * Track which hubs have volunteered to manage devices hanging off of
+ * a Crosstalk Switch (e.g. xbow).  This structure is allocated,
+ * initialized, and hung off the xswitch vertex early on when the
+ * xswitch vertex is created.
+ */
+typedef struct xswitch_vol_s {
+	mutex_t xswitch_volunteer_mutex;
+	int		xswitch_volunteer_count;
+	devfs_handle_t	xswitch_volunteer[NUM_XSWITCH_VOLUNTEER];
+} *xswitch_vol_t;
+
+void
+xswitch_vertex_init(devfs_handle_t xswitch)
+{
+	xswitch_vol_t xvolinfo;
+	int rc;
+
+	xvolinfo = kmalloc(sizeof(struct xswitch_vol_s), GFP_KERNEL);
+	mutex_init(&xvolinfo->xswitch_volunteer_mutex);
+	xvolinfo->xswitch_volunteer_count = 0;
+	rc = hwgraph_info_add_LBL(xswitch, 
+			INFO_LBL_XSWITCH_VOL,
+			(arbitrary_info_t)xvolinfo);
+	ASSERT(rc == GRAPH_SUCCESS); rc = rc;
+}
+
+
+/*
+ * When assignment of hubs to widgets is complete, we no longer need the
+ * xswitch volunteer structure hanging around.  Destroy it.
+ */
+static void
+xswitch_volunteer_delete(devfs_handle_t xswitch)
+{
+	xswitch_vol_t xvolinfo;
+	int rc;
+
+	rc = hwgraph_info_remove_LBL(xswitch, 
+				INFO_LBL_XSWITCH_VOL,
+				(arbitrary_info_t *)&xvolinfo);
+	kfree(xvolinfo);
+}
+/*
+ * A Crosstalk master volunteers to manage xwidgets on the specified xswitch.
+ */
+/* ARGSUSED */
+static void
+volunteer_for_widgets(devfs_handle_t xswitch, devfs_handle_t master)
+{
+	xswitch_vol_t xvolinfo = NULL;
+	devfs_handle_t hubv;
+	hubinfo_t hubinfo;
+
+	(void)hwgraph_info_get_LBL(xswitch, 
+				INFO_LBL_XSWITCH_VOL, 
+				(arbitrary_info_t *)&xvolinfo);
+	if (xvolinfo == NULL) {
+	    return;
+	}
+
+	mutex_lock(&xvolinfo->xswitch_volunteer_mutex);
+	ASSERT(xvolinfo->xswitch_volunteer_count < NUM_XSWITCH_VOLUNTEER);
+	xvolinfo->xswitch_volunteer[xvolinfo->xswitch_volunteer_count] = master;
+	xvolinfo->xswitch_volunteer_count++;
+
+	/*
+	 * if dual ported, make the lowest widgetid always be 
+	 * xswitch_volunteer[0].
+	 */
+	if (xvolinfo->xswitch_volunteer_count == NUM_XSWITCH_VOLUNTEER) {
+		hubv = xvolinfo->xswitch_volunteer[0];
+		hubinfo_get(hubv, &hubinfo);
+		if (hubinfo->h_widgetid != XBOW_HUBLINK_LOW) {
+			xvolinfo->xswitch_volunteer[0] = 
+						xvolinfo->xswitch_volunteer[1];
+			xvolinfo->xswitch_volunteer[1] = hubv;
+		}
+	}
+	mutex_unlock(&xvolinfo->xswitch_volunteer_mutex);
+}
+
+extern int xbow_port_io_enabled(nasid_t nasid, int widgetnum);
+
+/*
+ * Assign all the xwidgets hanging off the specified xswitch to the
+ * Crosstalk masters that have volunteered for xswitch duty.
+ */
+/* ARGSUSED */
+static void
+assign_widgets_to_volunteers(devfs_handle_t xswitch, devfs_handle_t hubv)
+{
+	xswitch_info_t xswitch_info;
+	xswitch_vol_t xvolinfo = NULL;
+	xwidgetnum_t widgetnum;
+	int num_volunteer;
+	nasid_t nasid;
+	hubinfo_t hubinfo;
+	extern int iobrick_type_get_nasid(nasid_t);
+
+
+	hubinfo_get(hubv, &hubinfo);
+	nasid = hubinfo->h_nasid;
+	
+	xswitch_info = xswitch_info_get(xswitch);
+	ASSERT(xswitch_info != NULL);
+
+	(void)hwgraph_info_get_LBL(xswitch, 
+				INFO_LBL_XSWITCH_VOL, 
+				(arbitrary_info_t *)&xvolinfo);
+	if (xvolinfo == NULL) {
+	    return;
+	}
+
+	num_volunteer = xvolinfo->xswitch_volunteer_count;
+	ASSERT(num_volunteer > 0);
+
+	/* Assign master hub for xswitch itself.  */
+	if (HUB_WIDGET_ID_MIN > 0) {
+		hubv = xvolinfo->xswitch_volunteer[0];
+		xswitch_info_master_assignment_set(xswitch_info, (xwidgetnum_t)0, hubv);
+	}
+
+	/*
+	 * TBD: Use administrative information to alter assignment of
+	 * widgets to hubs.
+	 */
+	for (widgetnum=HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) {
+		int i;
+
+		/*
+		 * Ignore disabled/empty ports.
+		 */
+		if (!xbow_port_io_enabled(nasid, widgetnum)) 
+		    continue;
+
+		/*
+		 * If this is the master IO board, assign it to the same 
+		 * hub that owned it in the prom.
+		 */
+		if (is_master_nasid_widget(nasid, widgetnum)) {
+			for (i=0; i<num_volunteer; i++) {
+				hubv = xvolinfo->xswitch_volunteer[i];
+				hubinfo_get(hubv, &hubinfo);
+				nasid = hubinfo->h_nasid;
+				if (nasid == get_console_nasid())
+					goto do_assignment;
+			}
+		}
+
+		/*
+		 * Assuming that we're dual-hosted and that PCI cards 
+		 * are naturally placed left-to-right, alternate PCI 
+		 * buses across both Cbricks.   For Pbricks, and Ibricks,
+                 * io_brick_map_widget() returns the PCI bus number
+                 * associated with the given brick type and widget number.
+                 * For Xbricks, it returns the XIO slot number.
+		 */
+
+		i = 0;
+		if (num_volunteer > 1) {
+                        int	       bt;
+
+                       	bt = iobrick_type_get_nasid(nasid);
+                        if (bt >= 0) {
+				/*
+				 * PXBRICK has two busses per widget so this
+				 * algorithm wouldn't work (all busses would
+				 * be assigned to one volunteer). Change the
+				 * bricktype to PBRICK whose mapping is setup
+				 * suchthat 2 of the PICs will be assigned to
+				 * one volunteer and the other one will be
+				 * assigned to the other volunteer.
+				 */
+				if (bt == MODULE_PXBRICK) 
+					bt = MODULE_PBRICK;
+
+			        i = io_brick_map_widget(bt, widgetnum) & 1;
+                        }
+                }
+
+		hubv = xvolinfo->xswitch_volunteer[i];
+
+do_assignment:
+		/*
+		 * At this point, we want to make hubv the master of widgetnum.
+		 */
+		xswitch_info_master_assignment_set(xswitch_info, widgetnum, hubv);
+	}
+
+	xswitch_volunteer_delete(xswitch);
+}
+
+/*
+ * Early iograph initialization.  Called by master CPU in mlreset().
+ * Useful for including iograph.o in kernel.o.
+ */
+void
+iograph_early_init(void)
+{
+/*
+ * Need new way to get this information ..
+ */
+	cnodeid_t cnode;
+	nasid_t nasid;
+	lboard_t *board;
+	
+	/*
+	 * Init. the board-to-hwgraph link early, so FRU analyzer
+	 * doesn't trip on leftover values if we panic early on.
+	 */
+	for(cnode = 0; cnode < numnodes; cnode++) {
+		nasid = COMPACT_TO_NASID_NODEID(cnode);
+		board = (lboard_t *)KL_CONFIG_INFO(nasid);
+		DBG("iograph_early_init: Found board 0x%p\n", board);
+
+		/* Check out all the board info stored on a node */
+		while(board) {
+			board->brd_graph_link = GRAPH_VERTEX_NONE;
+			board = KLCF_NEXT(board);
+			DBG("iograph_early_init: Found board 0x%p\n", board);
+		}
+	}
+
+	hubio_init();
+}
+
+/*
+ * Let boot processor know that we're done initializing our node's IO
+ * and then exit.
+ */
+/* ARGSUSED */
+static void
+io_init_done(cnodeid_t cnodeid,cpu_cookie_t c)
+{
+	/* Let boot processor know that we're done. */
+}
+
+/* 
+ * Probe to see if this hub's xtalk link is active.  If so,
+ * return the Crosstalk Identification of the widget that we talk to.  
+ * This is called before any of the Crosstalk infrastructure for 
+ * this hub is set up.  It's usually called on the node that we're
+ * probing, but not always.
+ *
+ * TBD: Prom code should actually do this work, and pass through 
+ * hwid for our use.
+ */
+static void
+early_probe_for_widget(devfs_handle_t hubv, xwidget_hwid_t hwid)
+{
+	hubreg_t llp_csr_reg;
+	nasid_t nasid;
+	hubinfo_t hubinfo;
+
+	hubinfo_get(hubv, &hubinfo);
+	nasid = hubinfo->h_nasid;
+
+	llp_csr_reg = REMOTE_HUB_L(nasid, IIO_LLP_CSR);
+	/* 
+	 * If link is up, read the widget's part number.
+	 * A direct connect widget must respond to widgetnum=0.
+	 */
+	if (llp_csr_reg & IIO_LLP_CSR_IS_UP) {
+		/* TBD: Put hub into "indirect" mode */
+		/*
+		 * We're able to read from a widget because our hub's 
+		 * WIDGET_ID was set up earlier.
+		 */
+		widgetreg_t widget_id = *(volatile widgetreg_t *)
+			(RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID);
+
+		DBG("early_probe_for_widget: Hub Vertex 0x%p is UP widget_id = 0x%x Register 0x%p\n", hubv, widget_id,
+		(volatile widgetreg_t *)(RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID) );
+
+		hwid->part_num = XWIDGET_PART_NUM(widget_id);
+		hwid->rev_num = XWIDGET_REV_NUM(widget_id);
+		hwid->mfg_num = XWIDGET_MFG_NUM(widget_id);
+
+		/* TBD: link reset */
+	} else {
+
+		hwid->part_num = XWIDGET_PART_NUM_NONE;
+		hwid->rev_num = XWIDGET_REV_NUM_NONE;
+		hwid->mfg_num = XWIDGET_MFG_NUM_NONE;
+	}
+}
+
+/* Add inventory information to the widget vertex 
+ * Right now (module,slot,revision) is being
+ * added as inventory information.
+ */
+static void
+xwidget_inventory_add(devfs_handle_t 		widgetv,
+		      lboard_t 			*board,
+		      struct xwidget_hwid_s 	hwid)
+{
+	if (!board)
+		return;
+	/* Donot add inventory information for the baseio
+	 * on a speedo with an xbox. It has already been
+	 * taken care of in SN00_vmc.
+	 * Speedo with xbox's baseio comes in at slot io1 (widget 9)
+	 */
+	device_inventory_add(widgetv,INV_IOBD,board->brd_type,
+			     board->brd_module,
+			     SLOTNUM_GETSLOT(board->brd_slot),
+			     hwid.rev_num);
+}
+
+/*
+ * io_xswitch_widget_init
+ *	
+ */
+
+void
+io_xswitch_widget_init(devfs_handle_t  	xswitchv,
+		       devfs_handle_t	hubv,
+		       xwidgetnum_t	widgetnum,
+		       async_attach_t	aa)
+{
+	xswitch_info_t		xswitch_info;
+	xwidgetnum_t		hub_widgetid;
+	devfs_handle_t		widgetv;
+	cnodeid_t		cnode;
+	widgetreg_t		widget_id;
+	nasid_t			nasid, peer_nasid;
+	struct xwidget_hwid_s 	hwid;
+	hubinfo_t		hubinfo;
+	/*REFERENCED*/
+	int			rc;
+	char 			pathname[128];
+	char			new_name[64];
+	moduleid_t		module;
+	slotid_t		slot;
+	lboard_t		*board = NULL;
+	char			buffer[16];
+	slotid_t get_widget_slotnum(int xbow, int widget);
+	
+	DBG("\nio_xswitch_widget_init: hubv 0x%p, xswitchv 0x%p, widgetnum 0x%x\n", hubv, xswitchv, widgetnum);
+
+	/*
+	 * Verify that xswitchv is indeed an attached xswitch.
+	 */
+	xswitch_info = xswitch_info_get(xswitchv);
+	ASSERT(xswitch_info != NULL);
+
+	hubinfo_get(hubv, &hubinfo);
+	nasid = hubinfo->h_nasid;
+	cnode = NASID_TO_COMPACT_NODEID(nasid);
+	hub_widgetid = hubinfo->h_widgetid;
+
+	/*
+	 * Check that the widget is an io widget and is enabled
+	 * on this nasid or the `peer' nasid.  The peer nasid
+	 * is the other hub/bedrock connected to the xbow.
+	 */
+	peer_nasid = NODEPDA(cnode)->xbow_peer;
+	if (peer_nasid == INVALID_NASID)
+		/* If I don't have a peer, use myself. */
+		peer_nasid = nasid;
+	if (!xbow_port_io_enabled(nasid, widgetnum) &&
+	    !xbow_port_io_enabled(peer_nasid, widgetnum)) {
+		return;
+	}
+
+	if (xswitch_info_link_ok(xswitch_info, widgetnum)) {
+		char			name[4];
+
+		/*
+		 * If the current hub is not supposed to be the master 
+		 * for this widgetnum, then skip this widget.
+		 */
+		if (xswitch_info_master_assignment_get(xswitch_info,
+						       widgetnum) != hubv) {
+			return;
+		}
+
+		module  = NODEPDA(cnode)->module_id;
+#ifdef XBRIDGE_REGS_SIM
+		/* hardwire for now...could do this with something like:
+		 * xbow_soft_t soft = hwgraph_fastinfo_get(vhdl);
+		 * xbow_t xbow = soft->base;
+		 * xbowreg_t xwidget_id = xbow->xb_wid_id;
+		 * but I don't feel like figuring out vhdl right now..
+		 * and I know for a fact the answer is 0x2d000049 
+		 */
+		DBG("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: reading xwidget id: hardwired to xbridge (0x2d000049).\n");
+		DBG("XWIDGET_PART_NUM(0x2d000049)= 0x%x\n", XWIDGET_PART_NUM(0x2d000049));
+		if (XWIDGET_PART_NUM(0x2d000049)==XXBOW_WIDGET_PART_NUM)
+#else
+		if (nasid_has_xbridge(nasid))
+#endif /* XBRIDGE_REGS_SIM */
+		{
+			board = find_lboard_module_class(
+				(lboard_t *)KL_CONFIG_INFO(nasid),
+				module,
+				KLTYPE_IOBRICK);
+
+DBG("io_xswitch_widget_init: Board 0x%p\n", board);
+{
+		lboard_t dummy;
+
+
+			if (board) {
+				DBG("io_xswitch_widget_init: Found KLTYPE_IOBRICK Board 0x%p brd_type 0x%x\n", board, board->brd_type);
+			} else {
+				DBG("io_xswitch_widget_init: FIXME did not find IOBOARD\n");
+				board = &dummy;
+			}
+				
+}
+
+			/*
+	 		 * Make sure we really want to say xbrick, pbrick,
+			 * etc. rather than XIO, graphics, etc.
+	 		 */
+
+#ifdef SUPPORT_PRINTING_M_FORMAT
+			sprintf(pathname, EDGE_LBL_MODULE "/%M/"
+				"%cbrick" "/%s/%d",
+				NODEPDA(cnode)->module_id,
+				
+#else
+			memset(buffer, 0, 16);
+			format_module_id(buffer, NODEPDA(cnode)->module_id, MODULE_FORMAT_BRIEF);
+			sprintf(pathname, EDGE_LBL_MODULE "/%s/"
+				"%cbrick" "/%s/%d",
+				buffer,
+#endif
+
+				(board->brd_type == KLTYPE_IBRICK) ? 'I' :
+				(board->brd_type == KLTYPE_PBRICK) ? 'P' :
+				(board->brd_type == KLTYPE_XBRICK) ? 'X' : '?',
+				EDGE_LBL_XTALK, widgetnum);
+		} 
+		
+		DBG("io_xswitch_widget_init: path= %s\n", pathname);
+		rc = hwgraph_path_add(hwgraph_root, pathname, &widgetv);
+		
+		ASSERT(rc == GRAPH_SUCCESS);
+
+		/* This is needed to let the user programs to map the
+		 * module,slot numbers to the corresponding widget numbers
+		 * on the crossbow.
+		 */
+		rc = device_master_set(hwgraph_connectpt_get(widgetv), hubv);
+
+		/* If we are looking at the global master io6
+		 * then add information about the version of
+		 * the io6prom as a part of "detailed inventory"
+		 * information.
+		 */
+		if (is_master_baseio(nasid,
+				     NODEPDA(cnode)->module_id,
+ 				     get_widget_slotnum(0,widgetnum))) {
+			extern void klhwg_baseio_inventory_add(devfs_handle_t,
+							       cnodeid_t);
+			module 	= NODEPDA(cnode)->module_id;
+
+#ifdef XBRIDGE_REGS_SIM
+			DBG("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: reading xwidget id: hardwired to xbridge (0x2d000049).\n");
+			if (XWIDGET_PART_NUM(0x2d000049)==XXBOW_WIDGET_PART_NUM)
+#else
+			if (nasid_has_xbridge(nasid))
+#endif /* XBRIDGE_REGS_SIM */
+			{
+				board = find_lboard_module(
+					(lboard_t *)KL_CONFIG_INFO(nasid),
+					module);
+				/*
+				 * Change iobrick to correct i/o brick
+				 */
+#ifdef SUPPORT_PRINTING_M_FORMAT
+				sprintf(pathname, EDGE_LBL_MODULE "/%M/"
+#else
+				sprintf(pathname, EDGE_LBL_MODULE "/%x/"
+#endif
+					"iobrick" "/%s/%d",
+					NODEPDA(cnode)->module_id,
+					EDGE_LBL_XTALK, widgetnum);
+			} else {
+				slot = get_widget_slotnum(0, widgetnum);
+				board = get_board_name(nasid, module, slot,
+								new_name);
+				/*
+			 	 * Create the vertex for the widget, 
+				 * using the decimal 
+			 	 * widgetnum as the name of the primary edge.
+			 	 */
+#ifdef SUPPORT_PRINTING_M_FORMAT
+				sprintf(pathname, EDGE_LBL_MODULE "/%M/"
+                                                EDGE_LBL_SLOT "/%s",
+                                        NODEPDA(cnode)->module_id,
+                                        new_name);
+#else
+				memset(buffer, 0, 16);
+				format_module_id(buffer, NODEPDA(cnode)->module_id, MODULE_FORMAT_BRIEF);
+				sprintf(pathname, EDGE_LBL_MODULE "/%s/"
+					  	EDGE_LBL_SLOT "/%s",
+					buffer,
+					new_name);
+#endif
+			}
+
+			rc = hwgraph_path_add(hwgraph_root, pathname, &widgetv);
+			DBG("io_xswitch_widget_init: (2) path= %s\n", pathname);
+		        /*
+		         * This is a weird ass code needed for error injection
+		         * purposes.
+		         */
+		        rc = device_master_set(hwgraph_connectpt_get(widgetv), hubv);
+			
+			klhwg_baseio_inventory_add(widgetv,cnode);
+		}
+		sprintf(name, "%d", widgetnum);
+		DBG("io_xswitch_widget_init: FIXME hwgraph_edge_add %s xswitchv 0x%p, widgetv 0x%p\n", name, xswitchv, widgetv);
+		rc = hwgraph_edge_add(xswitchv, widgetv, name);
+		
+		/*
+		 * crosstalk switch code tracks which
+		 * widget is attached to each link.
+		 */
+		xswitch_info_vhdl_set(xswitch_info, widgetnum, widgetv);
+		
+		/*
+		 * Peek at the widget to get its crosstalk part and
+		 * mfgr numbers, then present it to the generic xtalk
+		 * bus provider to have its driver attach routine
+		 * called (or not).
+		 */
+#ifdef XBRIDGE_REGS_SIM
+		widget_id = 0x2d000049;
+		DBG("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: id hardwired to widget_id\n");
+#else
+		widget_id = XWIDGET_ID_READ(nasid, widgetnum);
+#endif /* XBRIDGE_REGS_SIM */
+		hwid.part_num = XWIDGET_PART_NUM(widget_id);
+		hwid.rev_num = XWIDGET_REV_NUM(widget_id);
+		hwid.mfg_num = XWIDGET_MFG_NUM(widget_id);
+		/* Store some inventory information about
+		 * the xwidget in the hardware graph.
+		 */
+		xwidget_inventory_add(widgetv,board,hwid);
+		
+		(void)xwidget_register(&hwid, widgetv, widgetnum,
+				       hubv, hub_widgetid,
+				       aa);
+
+#ifdef	SN0_USE_BTE
+		bte_bpush_war(cnode, (void *)board);
+#endif
+	}
+}
+
+
+static void
+io_init_xswitch_widgets(devfs_handle_t xswitchv, cnodeid_t cnode)
+{
+	xwidgetnum_t		widgetnum;
+	async_attach_t          aa;
+
+	aa = async_attach_new();
+	
+	DBG("io_init_xswitch_widgets: xswitchv 0x%p for cnode %d\n", xswitchv, cnode);
+
+	for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; 
+	     widgetnum++) {
+		io_xswitch_widget_init(xswitchv,
+				       cnodeid_to_vertex(cnode),
+				       widgetnum, aa);
+	}
+	/* 
+	 * Wait for parallel attach threads, if any, to complete.
+	 */
+	async_attach_waitall(aa);
+	async_attach_free(aa);
+}
+
+/*
+ * For each PCI bridge connected to the xswitch, add a link from the
+ * board's klconfig info to the bridge's hwgraph vertex.  This lets
+ * the FRU analyzer find the bridge without traversing the hardware
+ * graph and risking hangs.
+ */
+static void
+io_link_xswitch_widgets(devfs_handle_t xswitchv, cnodeid_t cnodeid)
+{
+	xwidgetnum_t		widgetnum;
+	char 			pathname[128];
+	devfs_handle_t		vhdl;
+	nasid_t			nasid, peer_nasid;
+	lboard_t		*board;
+
+
+
+	/* And its connected hub's nasids */
+	nasid = COMPACT_TO_NASID_NODEID(cnodeid);
+	peer_nasid = NODEPDA(cnodeid)->xbow_peer;
+
+	/* 
+	 * Look for paths matching "<widgetnum>/pci" under xswitchv.
+	 * For every widget, init. its lboard's hwgraph link.  If the
+	 * board has a PCI bridge, point the link to it.
+	 */
+	for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX;
+		 widgetnum++) {
+		sprintf(pathname, "%d", widgetnum);
+		if (hwgraph_traverse(xswitchv, pathname, &vhdl) !=
+		    GRAPH_SUCCESS)
+			continue;
+
+		board = find_lboard_module((lboard_t *)KL_CONFIG_INFO(nasid),
+				NODEPDA(cnodeid)->module_id);
+		if (board == NULL && peer_nasid != INVALID_NASID) {
+			/*
+			 * Try to find the board on our peer
+			 */
+			board = find_lboard_module(
+				(lboard_t *)KL_CONFIG_INFO(peer_nasid),
+				NODEPDA(cnodeid)->module_id);
+		}
+		if (board == NULL) {
+#if defined(SUPPORT_PRINTING_V_FORMAT)
+			printk(KERN_WARNING  "Could not find PROM info for vertex %v, "
+				"FRU analyzer may fail",
+				vhdl);
+#else
+			printk(KERN_WARNING  "Could not find PROM info for vertex 0x%p, "
+				"FRU analyzer may fail",
+				(void *)vhdl);
+#endif
+			return;
+		}
+
+		sprintf(pathname, "%d/"EDGE_LBL_PCI, widgetnum);
+		if (hwgraph_traverse(xswitchv, pathname, &vhdl) == 
+		    GRAPH_SUCCESS)
+			board->brd_graph_link = vhdl;
+		else
+			board->brd_graph_link = GRAPH_VERTEX_NONE;
+	}
+}
+
+/*
+ * Initialize all I/O on the specified node.
+ */
+static void
+io_init_node(cnodeid_t cnodeid)
+{
+	/*REFERENCED*/
+	devfs_handle_t hubv, switchv, widgetv;
+	struct xwidget_hwid_s hwid;
+	hubinfo_t hubinfo;
+	int is_xswitch;
+	nodepda_t	*npdap;
+	struct semaphore *peer_sema = 0;
+	uint32_t	widget_partnum;
+	nodepda_router_info_t *npda_rip;
+	cpu_cookie_t	c = 0;
+	extern int hubdev_docallouts(devfs_handle_t);
+
+#ifdef LATER
+	/* Try to execute on the node that we're initializing. */
+	c = setnoderun(cnodeid);
+#endif
+	npdap = NODEPDA(cnodeid);
+
+	/*
+	 * Get the "top" vertex for this node's hardware
+	 * graph; it will carry the per-hub hub-specific
+	 * data, and act as the crosstalk provider master.
+	 * It's canonical path is probably something of the
+	 * form /hw/module/%M/slot/%d/node
+	 */
+	hubv = cnodeid_to_vertex(cnodeid);
+	DBG("io_init_node: Initialize IO for cnode %d hubv(node) 0x%p npdap 0x%p\n", cnodeid, hubv, npdap);
+
+	ASSERT(hubv != GRAPH_VERTEX_NONE);
+
+	hubdev_docallouts(hubv);
+
+	/*
+	 * Set up the dependent routers if we have any.
+	 */
+	npda_rip = npdap->npda_rip_first;
+
+	while(npda_rip) {
+		/* If the router info has not been initialized
+		 * then we need to do the router initialization
+		 */
+		if (!npda_rip->router_infop) {
+			router_init(cnodeid,0,npda_rip);
+		}
+		npda_rip = npda_rip->router_next;
+	}
+
+	/*
+	 * Read mfg info on this hub
+	 */
+
+	/* 
+	 * If nothing connected to this hub's xtalk port, we're done.
+	 */
+	early_probe_for_widget(hubv, &hwid);
+	if (hwid.part_num == XWIDGET_PART_NUM_NONE) {
+#ifdef PROBE_TEST
+		if ((cnodeid == 1) || (cnodeid == 2)) {
+			int index;
+
+			for (index = 0; index < 600; index++)
+				DBG("Interfering with device probing!!!\n");
+		}
+#endif
+		/* io_init_done takes cpu cookie as 2nd argument 
+		 * to do a restorenoderun for the setnoderun done 
+		 * at the start of this thread 
+		 */
+		
+		DBG("**** io_init_node: Node's 0x%p hub widget has XWIDGET_PART_NUM_NONE ****\n", hubv);
+		return;
+		/* NOTREACHED */
+	}
+
+	/* 
+	 * attach our hub_provider information to hubv,
+	 * so we can use it as a crosstalk provider "master"
+	 * vertex.
+	 */
+	xtalk_provider_register(hubv, &hub_provider);
+	xtalk_provider_startup(hubv);
+
+	/*
+	 * Create a vertex to represent the crosstalk bus
+	 * attached to this hub, and a vertex to be used
+	 * as the connect point for whatever is out there
+	 * on the other side of our crosstalk connection.
+	 *
+	 * Crosstalk Switch drivers "climb up" from their
+	 * connection point to try and take over the switch
+	 * point.
+	 *
+	 * Of course, the edges and verticies may already
+	 * exist, in which case our net effect is just to
+	 * associate the "xtalk_" driver with the connection
+	 * point for the device.
+	 */
+
+	(void)hwgraph_path_add(hubv, EDGE_LBL_XTALK, &switchv);
+
+	DBG("io_init_node: Created 'xtalk' entry to '../node/' xtalk vertex 0x%p\n", switchv);
+
+	ASSERT(switchv != GRAPH_VERTEX_NONE);
+
+	(void)hwgraph_edge_add(hubv, switchv, EDGE_LBL_IO);
+
+	DBG("io_init_node: Created symlink 'io' from ../node/io to ../node/xtalk \n");
+
+	/*
+	 * We need to find the widget id and update the basew_id field
+	 * accordingly. In particular, SN00 has direct connected bridge,
+	 * and hence widget id is Not 0.
+	 */
+
+	widget_partnum = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + WIDGET_ID))) & WIDGET_PART_NUM) >> WIDGET_PART_NUM_SHFT;
+
+	if (widget_partnum == BRIDGE_WIDGET_PART_NUM ||
+				widget_partnum == XBRIDGE_WIDGET_PART_NUM){
+		npdap->basew_id = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + BRIDGE_WID_CONTROL))) & WIDGET_WIDGET_ID);
+
+		DBG("io_init_node: Found XBRIDGE widget_partnum= 0x%x\n", widget_partnum);
+
+	} else if ((widget_partnum == XBOW_WIDGET_PART_NUM) ||
+			(widget_partnum == XXBOW_WIDGET_PART_NUM) ||
+			(widget_partnum == PXBOW_WIDGET_PART_NUM) ) {
+		/* 
+		 * Xbow control register does not have the widget ID field.
+		 * So, hard code the widget ID to be zero.
+		 */
+		DBG("io_init_node: Found XBOW widget_partnum= 0x%x\n", widget_partnum);
+		npdap->basew_id = 0;
+
+	} else {
+		npdap->basew_id = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + BRIDGE_WID_CONTROL))) & WIDGET_WIDGET_ID);
+
+		panic(" ****io_init_node: Unknown Widget Part Number 0x%x Widget ID 0x%x attached to Hubv 0x%p ****\n", widget_partnum, npdap->basew_id, (void *)hubv);
+
+		/*NOTREACHED*/
+	}
+	{
+		char widname[10];
+		sprintf(widname, "%x", npdap->basew_id);
+		(void)hwgraph_path_add(switchv, widname, &widgetv);
+		DBG("io_init_node: Created '%s' to '..node/xtalk/' vertex 0x%p\n", widname, widgetv);
+		ASSERT(widgetv != GRAPH_VERTEX_NONE);
+	}
+	
+	nodepda->basew_xc = widgetv;
+
+	is_xswitch = xwidget_hwid_is_xswitch(&hwid);
+
+	/* 
+	 * Try to become the master of the widget.  If this is an xswitch
+	 * with multiple hubs connected, only one will succeed.  Mastership
+	 * of an xswitch is used only when touching registers on that xswitch.
+	 * The slave xwidgets connected to the xswitch can be owned by various
+	 * masters.
+	 */
+	if (device_master_set(widgetv, hubv) == 0) {
+
+		/* Only one hub (thread) per Crosstalk device or switch makes
+		 * it to here.
+		 */
+
+		/* 
+		 * Initialize whatever xwidget is hanging off our hub.
+		 * Whatever it is, it's accessible through widgetnum 0.
+		 */
+		hubinfo_get(hubv, &hubinfo);
+
+		(void)xwidget_register(&hwid, widgetv, npdap->basew_id, hubv, hubinfo->h_widgetid, NULL);
+
+		if (!is_xswitch) {
+			/* io_init_done takes cpu cookie as 2nd argument 
+			 * to do a restorenoderun for the setnoderun done 
+			 * at the start of this thread 
+			 */
+			io_init_done(cnodeid,c);
+			/* NOTREACHED */
+		}
+
+		/* 
+		 * Special handling for Crosstalk Switches (e.g. xbow).
+		 * We need to do things in roughly the following order:
+		 *	1) Initialize xswitch hardware (done above)
+		 *	2) Determine which hubs are available to be widget masters
+		 *	3) Discover which links are active from the xswitch
+		 *	4) Assign xwidgets hanging off the xswitch to hubs
+		 *	5) Initialize all xwidgets on the xswitch
+		 */
+
+		volunteer_for_widgets(switchv, hubv);
+
+		/* If there's someone else on this crossbow, recognize him */
+		if (npdap->xbow_peer != INVALID_NASID) {
+			nodepda_t *peer_npdap = NODEPDA(NASID_TO_COMPACT_NODEID(npdap->xbow_peer));
+			peer_sema = &peer_npdap->xbow_sema;
+			volunteer_for_widgets(switchv, peer_npdap->node_vertex);
+		}
+
+		assign_widgets_to_volunteers(switchv, hubv);
+
+		/* Signal that we're done */
+		if (peer_sema) {
+			mutex_unlock(peer_sema);
+		}
+		
+	}
+	else {
+	    /* Wait 'til master is done assigning widgets. */
+	    mutex_lock(&npdap->xbow_sema);
+	}
+
+#ifdef PROBE_TEST
+	if ((cnodeid == 1) || (cnodeid == 2)) {
+		int index;
+
+		for (index = 0; index < 500; index++)
+			DBG("Interfering with device probing!!!\n");
+	}
+#endif
+	/* Now both nodes can safely inititialize widgets */
+	io_init_xswitch_widgets(switchv, cnodeid);
+	io_link_xswitch_widgets(switchv, cnodeid);
+
+	/* io_init_done takes cpu cookie as 2nd argument 
+	 * to do a restorenoderun for the setnoderun done 
+	 * at the start of this thread 
+	 */
+	io_init_done(cnodeid,c);
+
+	DBG("\nio_init_node: DONE INITIALIZED ALL I/O FOR CNODEID %d\n\n", cnodeid);
+}
+
+
+#define IOINIT_STKSZ	(16 * 1024)
+
+#define __DEVSTR1 	"/../.master/"
+#define __DEVSTR2 	"/target/"
+#define __DEVSTR3 	"/lun/0/disk/partition/"
+#define	__DEVSTR4	"/../ef"
+
+/*
+ * Currently, we need to allow for 5 IBrick slots with 1 FC each
+ * plus an internal 1394.
+ *
+ * ioconfig starts numbering SCSI's at NUM_BASE_IO_SCSI_CTLR.
+ */
+#define NUM_BASE_IO_SCSI_CTLR 6
+
+/*
+ * This tells ioconfig where it can start numbering scsi controllers.
+ * Below this base number, platform-specific handles the numbering.
+ * XXX Irix legacy..controller numbering should be part of devfsd's job
+ */
+int num_base_io_scsi_ctlr = 2; /* used by syssgi */
+devfs_handle_t		base_io_scsi_ctlr_vhdl[NUM_BASE_IO_SCSI_CTLR];
+static devfs_handle_t	baseio_enet_vhdl,baseio_console_vhdl;
+
+/*
+ * Put the logical controller number information in the 
+ * scsi controller vertices for each scsi controller that
+ * is in a "fixed position".
+ */
+static void
+scsi_ctlr_nums_add(devfs_handle_t pci_vhdl)
+{
+	{
+		int i;
+
+		num_base_io_scsi_ctlr = NUM_BASE_IO_SCSI_CTLR;
+
+		/* Initialize base_io_scsi_ctlr_vhdl array */
+		for (i=0; i<num_base_io_scsi_ctlr; i++)
+			base_io_scsi_ctlr_vhdl[i] = GRAPH_VERTEX_NONE;
+	}
+	{
+	/*
+	 * May want to consider changing the SN0 code, above, to work more like
+	 * the way this works.
+	 */
+	devfs_handle_t base_ibrick_xbridge_vhdl;
+	devfs_handle_t base_ibrick_xtalk_widget_vhdl;
+	devfs_handle_t scsi_ctlr_vhdl;
+	int i;
+	graph_error_t rv;
+
+	/*
+	 * This is a table of "well-known" SCSI controllers and their well-known
+	 * controller numbers.  The names in the table start from the base IBrick's
+	 * Xbridge vertex, so the first component is the xtalk widget number.
+	 */
+	static struct {
+		char	*base_ibrick_scsi_path;
+		int	controller_number;
+	} hardwired_scsi_controllers[] = {
+		{"15/" EDGE_LBL_PCI "/1/" EDGE_LBL_SCSI_CTLR "/0", 0},
+		{"15/" EDGE_LBL_PCI "/2/" EDGE_LBL_SCSI_CTLR "/0", 1},
+		{"15/" EDGE_LBL_PCI "/3/" EDGE_LBL_SCSI_CTLR "/0", 2},
+		{"14/" EDGE_LBL_PCI "/1/" EDGE_LBL_SCSI_CTLR "/0", 3},
+		{"14/" EDGE_LBL_PCI "/2/" EDGE_LBL_SCSI_CTLR "/0", 4},
+		{"15/" EDGE_LBL_PCI "/6/ohci/0/" EDGE_LBL_SCSI_CTLR "/0", 5},
+		{NULL, -1} /* must be last */
+	};
+
+	base_ibrick_xtalk_widget_vhdl = hwgraph_connectpt_get(pci_vhdl);
+	ASSERT_ALWAYS(base_ibrick_xtalk_widget_vhdl != GRAPH_VERTEX_NONE);
+
+	base_ibrick_xbridge_vhdl = hwgraph_connectpt_get(base_ibrick_xtalk_widget_vhdl);
+	ASSERT_ALWAYS(base_ibrick_xbridge_vhdl != GRAPH_VERTEX_NONE);
+	hwgraph_vertex_unref(base_ibrick_xtalk_widget_vhdl);
+
+	/*
+	 * Iterate through the list of well-known SCSI controllers.
+	 * For each controller found, set it's controller number according
+	 * to the table.
+	 */
+	for (i=0; hardwired_scsi_controllers[i].base_ibrick_scsi_path != NULL; i++) {
+		rv = hwgraph_path_lookup(base_ibrick_xbridge_vhdl,
+			hardwired_scsi_controllers[i].base_ibrick_scsi_path, &scsi_ctlr_vhdl, NULL);
+
+		if (rv != GRAPH_SUCCESS) /* No SCSI at this path */
+			continue;
+
+		ASSERT(hardwired_scsi_controllers[i].controller_number < NUM_BASE_IO_SCSI_CTLR);
+		base_io_scsi_ctlr_vhdl[hardwired_scsi_controllers[i].controller_number] = scsi_ctlr_vhdl;
+		device_controller_num_set(scsi_ctlr_vhdl, hardwired_scsi_controllers[i].controller_number);
+		hwgraph_vertex_unref(scsi_ctlr_vhdl); /* (even though we're actually keeping a reference) */
+	}
+
+	hwgraph_vertex_unref(base_ibrick_xbridge_vhdl);
+	}
+}
+
+
+#include <asm/sn/ioerror_handling.h>
+devfs_handle_t		sys_critical_graph_root = GRAPH_VERTEX_NONE;
+
+/* Define the system critical vertices and connect them through
+ * a canonical parent-child relationships for easy traversal
+ * during io error handling.
+ */
+static void
+sys_critical_graph_init(void)
+{
+	devfs_handle_t		bridge_vhdl,master_node_vhdl;
+	devfs_handle_t  		xbow_vhdl = GRAPH_VERTEX_NONE;
+	extern devfs_handle_t	hwgraph_root;
+	devfs_handle_t		pci_slot_conn;
+	int			slot;
+	devfs_handle_t		baseio_console_conn;
+
+	DBG("sys_critical_graph_init: FIXME.\n");
+	baseio_console_conn = hwgraph_connectpt_get(baseio_console_vhdl);
+
+	if (baseio_console_conn == NULL) {
+		return;
+	}
+
+	/* Get the vertex handle for the baseio bridge */
+	bridge_vhdl = device_master_get(baseio_console_conn);
+
+	/* Get the master node of the baseio card */
+	master_node_vhdl = cnodeid_to_vertex(
+				master_node_get(baseio_console_vhdl));
+	
+	/* Add the "root->node" part of the system critical graph */
+
+	sys_critical_graph_vertex_add(hwgraph_root,master_node_vhdl);
+
+	/* Check if we have a crossbow */
+	if (hwgraph_traverse(master_node_vhdl,
+			     EDGE_LBL_XTALK"/0",
+			     &xbow_vhdl) == GRAPH_SUCCESS) {
+		/* We have a crossbow.Add "node->xbow" part of the system 
+		 * critical graph.
+		 */
+		sys_critical_graph_vertex_add(master_node_vhdl,xbow_vhdl);
+		
+		/* Add "xbow->baseio bridge" of the system critical graph */
+		sys_critical_graph_vertex_add(xbow_vhdl,bridge_vhdl);
+
+		hwgraph_vertex_unref(xbow_vhdl);
+	} else 
+		/* We donot have a crossbow. Add "node->baseio_bridge"
+		 * part of the system critical graph.
+		 */
+		sys_critical_graph_vertex_add(master_node_vhdl,bridge_vhdl);
+
+	/* Add all the populated PCI slot vertices to the system critical
+	 * graph with the bridge vertex as the parent.
+	 */
+	for (slot = 0 ; slot < 8; slot++) {
+		char	slot_edge[10];
+
+		sprintf(slot_edge,"%d",slot);
+		if (hwgraph_traverse(bridge_vhdl,slot_edge, &pci_slot_conn)
+		    != GRAPH_SUCCESS)
+			continue;
+		sys_critical_graph_vertex_add(bridge_vhdl,pci_slot_conn);
+		hwgraph_vertex_unref(pci_slot_conn);
+	}
+
+	hwgraph_vertex_unref(bridge_vhdl);
+
+	/* Add the "ioc3 pci connection point  -> console ioc3" part 
+	 * of the system critical graph
+	 */
+
+	if (hwgraph_traverse(baseio_console_vhdl,"..",&pci_slot_conn) ==
+	    GRAPH_SUCCESS) {
+		sys_critical_graph_vertex_add(pci_slot_conn, 
+					      baseio_console_vhdl);
+		hwgraph_vertex_unref(pci_slot_conn);
+	}
+
+	/* Add the "ethernet pci connection point  -> base ethernet" part of 
+	 * the system  critical graph
+	 */
+	if (hwgraph_traverse(baseio_enet_vhdl,"..",&pci_slot_conn) ==
+	    GRAPH_SUCCESS) {
+		sys_critical_graph_vertex_add(pci_slot_conn, 
+					      baseio_enet_vhdl);
+		hwgraph_vertex_unref(pci_slot_conn);
+	}
+
+	/* Add the "scsi controller pci connection point  -> base scsi 
+	 * controller" part of the system critical graph
+	 */
+	if (hwgraph_traverse(base_io_scsi_ctlr_vhdl[0],
+			     "../..",&pci_slot_conn) == GRAPH_SUCCESS) {
+		sys_critical_graph_vertex_add(pci_slot_conn, 
+					      base_io_scsi_ctlr_vhdl[0]);
+		hwgraph_vertex_unref(pci_slot_conn);
+	}
+	if (hwgraph_traverse(base_io_scsi_ctlr_vhdl[1],
+			     "../..",&pci_slot_conn) == GRAPH_SUCCESS) {
+		sys_critical_graph_vertex_add(pci_slot_conn, 
+					      base_io_scsi_ctlr_vhdl[1]);
+		hwgraph_vertex_unref(pci_slot_conn);
+	}
+	hwgraph_vertex_unref(baseio_console_conn);
+
+}
+
+static void
+baseio_ctlr_num_set(void)
+{
+	char 			name[MAXDEVNAME];
+	devfs_handle_t		console_vhdl, pci_vhdl, enet_vhdl;
+	devfs_handle_t		ioc3_console_vhdl_get(void);
+
+
+	DBG("baseio_ctlr_num_set; FIXME\n");
+	console_vhdl = ioc3_console_vhdl_get();
+	if (console_vhdl == GRAPH_VERTEX_NONE)
+		return;
+	/* Useful for setting up the system critical graph */
+	baseio_console_vhdl = console_vhdl;
+
+	vertex_to_name(console_vhdl,name,MAXDEVNAME);
+
+	strcat(name,__DEVSTR1);
+	pci_vhdl =  hwgraph_path_to_vertex(name);
+	scsi_ctlr_nums_add(pci_vhdl);
+	/* Unref the pci_vhdl due to the reference by hwgraph_path_to_vertex
+	 */
+	hwgraph_vertex_unref(pci_vhdl);
+
+	vertex_to_name(console_vhdl, name, MAXDEVNAME);
+	strcat(name, __DEVSTR4);
+	enet_vhdl = hwgraph_path_to_vertex(name);
+
+	/* Useful for setting up the system critical graph */
+	baseio_enet_vhdl = enet_vhdl;
+
+	device_controller_num_set(enet_vhdl, 0);
+	/* Unref the enet_vhdl due to the reference by hwgraph_path_to_vertex
+	 */
+	hwgraph_vertex_unref(enet_vhdl);
+}
+/* #endif */
+
+void
+sn00_rrb_alloc(devfs_handle_t vhdl, int *vendor_list)
+{
+	/* REFERENCED */
+	int rtn_val;
+
+	/* 
+	** sn00 population:		errb	orrb
+	**	0- ql			3+?
+	**	1- ql			        2
+	**	2- ioc3 ethernet	2+?
+	**	3- ioc3 secondary	        1
+	**	4-                      0
+	** 	5- PCI slot
+	** 	6- PCI slot
+	** 	7- PCI slot
+	*/	
+	
+	/* The following code implements this heuristic for getting 
+	 * maximum usage out of the rrbs
+	 *
+	 * constraints:
+	 *  8 bit ql1 needs 1+1
+	 *  ql0 or ql5,6,7 wants 1+2
+	 *  ethernet wants 2 or more
+	 *
+	 * rules for even rrbs:
+	 *  if nothing in slot 6 
+	 *   4 rrbs to 0 and 2  (0xc8889999)
+	 *  else 
+         *   3 2 3 to slots 0 2 6  (0xc8899bbb)
+	 *
+         * rules for odd rrbs
+	 *  if nothing in slot 5 or 7  (0xc8889999)
+	 *   4 rrbs to 1 and 3
+	 *  else if 1 thing in 5 or 7  (0xc8899aaa) or (0xc8899bbb)
+         *   3 2 3 to slots 1 3 5|7
+         *  else
+         *   2 1 3 2 to slots 1 3 5 7 (note: if there's a ql card in 7 this
+	 *           (0xc89aaabb)      may short what it wants therefore the
+	 *			       rule should be to plug pci slots in order)
+	 */
+
+
+	if (vendor_list[6] != PCIIO_VENDOR_ID_NONE) {
+		/* something in slot 6 */
+		rtn_val = pcibr_alloc_all_rrbs(vhdl, 0, 3,1, 2,0, 0,0, 3,0);
+	}
+	else {
+		rtn_val = pcibr_alloc_all_rrbs(vhdl, 0, 4,1, 4,0, 0,0, 0,0);
+	}
+	if (rtn_val)
+		printk(KERN_WARNING  "sn00_rrb_alloc: pcibr_alloc_all_rrbs failed");
+
+	if ((vendor_list[5] != PCIIO_VENDOR_ID_NONE) && 
+	    (vendor_list[7] != PCIIO_VENDOR_ID_NONE)) {
+		/* soemthing in slot 5 and 7 */
+		rtn_val = pcibr_alloc_all_rrbs(vhdl, 1, 2,1, 1,0, 3,0, 2,0);
+	}
+	else if (vendor_list[5] != PCIIO_VENDOR_ID_NONE) {
+		/* soemthing in slot 5 but not 7 */
+		rtn_val = pcibr_alloc_all_rrbs(vhdl, 1, 3,1, 2,0, 3,0, 0,0);
+	}
+	else if (vendor_list[7] != PCIIO_VENDOR_ID_NONE) {
+		/* soemthing in slot 7 but not 5 */
+		rtn_val = pcibr_alloc_all_rrbs(vhdl, 1, 3,1, 2,0, 0,0, 3,0);
+	}
+	else {
+		/* nothing in slot 5 or 7 */
+		rtn_val = pcibr_alloc_all_rrbs(vhdl, 1, 4,1, 4,0, 0,0, 0,0);
+	}
+	if (rtn_val)
+		printk(KERN_WARNING  "sn00_rrb_alloc: pcibr_alloc_all_rrbs failed");
+}
+
+
+/*
+ * Initialize all I/O devices.  Starting closest to nodes, probe and
+ * initialize outward.
+ */
+void
+init_all_devices(void)
+{
+	/* Governor on init threads..bump up when safe 
+	 * (beware many devfs races) 
+	 */
+	cnodeid_t cnodeid, active;
+
+	active = 0;
+	for (cnodeid = 0; cnodeid < numnodes; cnodeid++) {
+                DBG("init_all_devices: Calling io_init_node() for cnode %d\n", cnodeid);
+                io_init_node(cnodeid);
+
+		DBG("init_all_devices: Done io_init_node() for cnode %d\n", cnodeid);
+	}
+
+	for (cnodeid = 0; cnodeid < numnodes; cnodeid++)
+		/*
+	 	 * Update information generated by IO init.
+		 */
+		update_node_information(cnodeid);
+
+	baseio_ctlr_num_set();
+	/* Setup the system critical graph (which is a subgraph of the
+	 * main hwgraph). This information is useful during io error
+	 * handling.
+	 */
+	sys_critical_graph_init();
+
+#if HWG_PRINT
+	hwgraph_print();
+#endif
+
+}
+
+#define toint(x) ((int)(x) - (int)('0'))
+
+void
+devnamefromarcs(char *devnm)
+{
+	int 			val;
+	char 			tmpnm[MAXDEVNAME];
+	char 			*tmp1, *tmp2;
+	
+	val = strncmp(devnm, "dks", 3);
+	if (val != 0) 
+		return;
+	tmp1 = devnm + 3;
+	if (!isdigit(*tmp1))
+		return;
+
+	val = 0;
+	while (isdigit(*tmp1)) {
+		val = 10*val+toint(*tmp1);
+		tmp1++;
+	}
+
+	if(*tmp1 != 'd')
+		return;
+	else
+		tmp1++;
+
+	if ((val < 0) || (val >= num_base_io_scsi_ctlr)) {
+		int i;
+		int viable_found = 0;
+
+		DBG("Only controller numbers 0..%d  are supported for\n", NUM_BASE_IO_SCSI_CTLR-1);
+		DBG("prom \"root\" variables of the form dksXdXsX.\n");
+		DBG("To use another disk you must use the full hardware graph path\n\n");
+		DBG("Possible controller numbers for use in 'dksXdXsX' on this system: ");
+		for (i=0; i<NUM_BASE_IO_SCSI_CTLR; i++) {
+			if (base_io_scsi_ctlr_vhdl[i] != GRAPH_VERTEX_NONE) {
+				DBG("%d ", i);
+				viable_found=1;
+			}
+		}
+		if (viable_found)
+			DBG("\n");
+		else
+			DBG("none found!\n");
+
+		DELAY(15000000);
+		//prom_reboot();
+		panic("FIXME: devnamefromarcs: should call prom_reboot here.\n");
+		/* NOTREACHED */
+	}
+		
+	ASSERT(base_io_scsi_ctlr_vhdl[val] != GRAPH_VERTEX_NONE);
+	vertex_to_name(base_io_scsi_ctlr_vhdl[val],
+		       tmpnm,
+		       MAXDEVNAME);
+	tmp2 = 	tmpnm + strlen(tmpnm);
+	strcpy(tmp2, __DEVSTR2);
+	tmp2 += strlen(__DEVSTR2);
+	while (*tmp1 != 's') {
+		if((*tmp2++ = *tmp1++) == '\0')
+			return;
+	}	
+	tmp1++;
+	strcpy(tmp2, __DEVSTR3);
+	tmp2 += strlen(__DEVSTR3);
+	while ( (*tmp2++ = *tmp1++) )
+		;
+	tmp2--;
+	*tmp2++ = '/';
+	strcpy(tmp2, EDGE_LBL_BLOCK);
+	strcpy(devnm,tmpnm);
+}
+
+static
+struct io_brick_map_s io_brick_tab[] = {
+
+/* Ibrick widget number to PCI bus number map */
+ {      MODULE_IBRICK,                          /* Ibrick type    */ 
+    /*  PCI Bus #                                  Widget #       */
+    {   0, 0, 0, 0, 0, 0, 0, 0,                 /* 0x0 - 0x7      */
+        0,                                      /* 0x8            */
+        0,                                      /* 0x9            */
+        0, 0,                                   /* 0xa - 0xb      */
+        0,                                      /* 0xc            */
+        0,                                      /* 0xd            */
+        2,                                      /* 0xe            */
+        1                                       /* 0xf            */
+     }
+ },
+
+/* Pbrick widget number to PCI bus number map */
+ {      MODULE_PBRICK,                          /* Pbrick type    */ 
+    /*  PCI Bus #                                  Widget #       */
+    {   0, 0, 0, 0, 0, 0, 0, 0,                 /* 0x0 - 0x7      */
+        2,                                      /* 0x8            */
+        1,                                      /* 0x9            */
+        0, 0,                                   /* 0xa - 0xb      */
+        5,                                      /* 0xc            */
+        6,                                      /* 0xd            */
+        4,                                      /* 0xe            */
+        3                                       /* 0xf            */
+    }
+ },
+
+/* PXbrick widget number to PCI bus number map */
+ {      MODULE_PXBRICK,                         /* PXbrick type   */ 
+    /*  PCI Bus #                                  Widget #       */
+    {   0, 0, 0, 0, 0, 0, 0, 0,                 /* 0x0 - 0x7      */
+        0,                                      /* 0x8            */
+        0,                                      /* 0x9            */
+        0, 0,                                   /* 0xa - 0xb      */
+        1,                                      /* 0xc            */
+        5,                                      /* 0xd            */
+        0,                                      /* 0xe            */
+        3                                       /* 0xf            */
+    }
+ },
+
+/* Xbrick widget to XIO slot map */
+ {      MODULE_XBRICK,                          /* Xbrick type    */ 
+    /*  XIO Slot #                                 Widget #       */
+    {   0, 0, 0, 0, 0, 0, 0, 0,                 /* 0x0 - 0x7      */
+        1,                                      /* 0x8            */
+        3,                                      /* 0x9            */
+        0, 0,                                   /* 0xa - 0xb      */
+        2,                                      /* 0xc            */
+        4,                                      /* 0xd            */
+        0,                                      /* 0xe            */
+        0                                       /* 0xf            */
+    }
+ }
+};
+
+/*
+ * Use the brick's type to map a widget number to a meaningful int
+ */
+int
+io_brick_map_widget(int brick_type, int widget_num)
+{
+        int num_bricks, i;
+
+        /* Calculate number of bricks in table */
+        num_bricks = sizeof(io_brick_tab)/sizeof(io_brick_tab[0]);
+
+        /* Look for brick prefix in table */
+        for (i = 0; i < num_bricks; i++) {
+               if (brick_type == io_brick_tab[i].ibm_type)
+                       return(io_brick_tab[i].ibm_map_wid[widget_num]);
+        }
+
+        return 0;
+
+}
+
+/*
+ * Use the device's vertex to map the device's widget to a meaningful int
+ */
+int
+io_path_map_widget(devfs_handle_t vertex)
+{
+        char hw_path_name[MAXDEVNAME];
+        char *wp, *bp, *sp = NULL;
+        int  widget_num;
+	long atoi(char *);
+	int hwgraph_vertex_name_get(devfs_handle_t vhdl, char *buf, uint buflen);
+
+
+        /* Get the full path name of the vertex */
+        if (GRAPH_SUCCESS != hwgraph_vertex_name_get(vertex, hw_path_name,
+                                                     MAXDEVNAME))
+                return 0;
+
+        /* Find the widget number in the path name */
+        wp = strstr(hw_path_name, "/"EDGE_LBL_XTALK"/");
+        if (wp == NULL)
+                return 0;
+        widget_num = atoi(wp+7);
+        if (widget_num < XBOW_PORT_8 || widget_num > XBOW_PORT_F)
+                return 0;
+
+        /* Find "brick" in the path name */
+        bp = strstr(hw_path_name, "brick");
+        if (bp == NULL)
+                return 0;
+
+        /* Find preceding slash */
+        sp = bp;
+        while (sp > hw_path_name) {
+                sp--;
+                if (*sp == '/')
+                        break;
+        }
+
+        /* Invalid if no preceding slash */
+        if (!sp)
+                return 0;
+
+        /* Bump slash pointer to "brick" prefix */
+        sp++;
+        /*
+         * Verify "brick" prefix length;  valid exaples:
+         * 'I' from "/Ibrick"
+         * 'P' from "/Pbrick"
+         * 'X' from "/Xbrick"
+         */
+         if ((bp - sp) != 1)
+                return 0;
+
+        return (io_brick_map_widget((int)*sp, widget_num));
+
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn1/module.c linux-2.4.21-pre6/arch/ia64/sn/io/sn1/module.c
--- linux-2.4.20/arch/ia64/sn/io/sn1/module.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn1/module.c	2003-03-26 23:49:40.000000000 +0000
@@ -0,0 +1,311 @@
+/* $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) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/io.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/xtalk/xbow.h>
+#include <asm/sn/pci/bridge.h>
+#include <asm/sn/klconfig.h>
+#include <asm/sn/sn1/hubdev.h>
+#include <asm/sn/module.h>
+#include <asm/sn/pci/pcibr.h>
+#include <asm/sn/xtalk/xswitch.h>
+#include <asm/sn/nodepda.h>
+#include <asm/sn/sn_cpuid.h>
+
+
+/* #define LDEBUG	1 */
+
+#ifdef LDEBUG
+#define DPRINTF		printk
+#define printf		printk
+#else
+#define DPRINTF(x...)
+#endif
+
+module_t	       *modules[MODULE_MAX];
+int			nummodules;
+
+#define SN00_SERIAL_FUDGE	0x3b1af409d513c2
+#define SN0_SERIAL_FUDGE	0x6e
+
+void
+encode_int_serial(uint64_t src,uint64_t *dest)
+{
+    uint64_t val;
+    int i;
+
+    val = src + SN00_SERIAL_FUDGE;
+
+
+    for (i = 0; i < sizeof(long long); i++) {
+	((char*)dest)[i] =
+	    ((char*)&val)[sizeof(long long)/2 +
+			 ((i%2) ? ((i/2 * -1) - 1) : (i/2))];
+    }
+}
+
+
+void
+decode_int_serial(uint64_t src, uint64_t *dest)
+{
+    uint64_t val;
+    int i;
+
+    for (i = 0; i < sizeof(long long); i++) {
+	((char*)&val)[sizeof(long long)/2 +
+		     ((i%2) ? ((i/2 * -1) - 1) : (i/2))] =
+	    ((char*)&src)[i];
+    }
+
+    *dest = val - SN00_SERIAL_FUDGE;
+}
+
+
+void
+encode_str_serial(const char *src, char *dest)
+{
+    int i;
+
+    for (i = 0; i < MAX_SERIAL_NUM_SIZE; i++) {
+
+	dest[i] = src[MAX_SERIAL_NUM_SIZE/2 +
+		     ((i%2) ? ((i/2 * -1) - 1) : (i/2))] +
+	    SN0_SERIAL_FUDGE;
+    }
+}
+
+void
+decode_str_serial(const char *src, char *dest)
+{
+    int i;
+
+    for (i = 0; i < MAX_SERIAL_NUM_SIZE; i++) {
+	dest[MAX_SERIAL_NUM_SIZE/2 +
+	    ((i%2) ? ((i/2 * -1) - 1) : (i/2))] = src[i] -
+	    SN0_SERIAL_FUDGE;
+    }
+}
+
+
+module_t *module_lookup(moduleid_t id)
+{
+    int			i;
+
+    for (i = 0; i < nummodules; i++)
+	if (modules[i]->id == id) {
+	    DPRINTF("module_lookup: found m=0x%p\n", modules[i]);
+	    return modules[i];
+	}
+
+    return NULL;
+}
+
+/*
+ * module_add_node
+ *
+ *   The first time a new module number is seen, a module structure is
+ *   inserted into the module list in order sorted by module number
+ *   and the structure is initialized.
+ *
+ *   The node number is added to the list of nodes in the module.
+ */
+
+module_t *module_add_node(moduleid_t id, cnodeid_t n)
+{
+    module_t	       *m;
+    int			i;
+    char		buffer[16];
+
+#ifdef __ia64
+    memset(buffer, 0, 16);
+    format_module_id(buffer, id, MODULE_FORMAT_BRIEF);
+    DPRINTF("module_add_node: id=%s node=%d\n", buffer, n);
+#endif
+
+    if ((m = module_lookup(id)) == 0) {
+#ifdef LATER
+	m = kmem_zalloc_node(sizeof (module_t), KM_NOSLEEP, n);
+#else
+	m = kmalloc(sizeof (module_t), GFP_KERNEL);
+	memset(m, 0 , sizeof(module_t));
+#endif
+	ASSERT_ALWAYS(m);
+
+	m->id = id;
+	spin_lock_init(&m->lock);
+
+	mutex_init_locked(&m->thdcnt);
+
+	elsc_init(&m->elsc, COMPACT_TO_NASID_NODEID(n));
+	spin_lock_init(&m->elsclock);
+
+	/* Insert in sorted order by module number */
+
+	for (i = nummodules; i > 0 && modules[i - 1]->id > id; i--)
+	    modules[i] = modules[i - 1];
+
+	modules[i] = m;
+	nummodules++;
+    }
+
+    m->nodes[m->nodecnt++] = n;
+
+    DPRINTF("module_add_node: module %s now has %d nodes\n", buffer, m->nodecnt);
+
+    return m;
+}
+
+int module_probe_snum(module_t *m, nasid_t nasid)
+{
+    lboard_t	       *board;
+    klmod_serial_num_t *comp;
+    char * bcopy(const char * src, char * dest, int count);
+    char serial_number[16];
+
+    /*
+     * record brick serial number
+     */
+    board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid), KLTYPE_SNIA);
+
+    if (! board || KL_CONFIG_DUPLICATE_BOARD(board))
+    {
+#if	LDEBUG
+	printf ("module_probe_snum: no IP35 board found!\n");
+#endif
+	return 0;
+    }
+
+    board_serial_number_get( board, serial_number );
+    if( serial_number[0] != '\0' ) {
+	encode_str_serial( serial_number, m->snum.snum_str );
+	m->snum_valid = 1;
+    }
+#if	LDEBUG
+    else {
+	printf("module_probe_snum: brick serial number is null!\n");
+    }
+    printf("module_probe_snum: brick serial number == %s\n", serial_number);
+#endif /* DEBUG */
+
+    board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid),
+			KLTYPE_IOBRICK_XBOW);
+
+    if (! board || KL_CONFIG_DUPLICATE_BOARD(board))
+	return 0;
+
+    comp = GET_SNUM_COMP(board);
+
+    if (comp) {
+#if LDEBUG
+	    int i;
+
+	    printf("********found module with id %x and string", m->id);
+
+	    for (i = 0; i < MAX_SERIAL_NUM_SIZE; i++)
+		printf(" %x ", comp->snum.snum_str[i]);
+
+	    printf("\n");	/* Fudged string is not ASCII */
+#endif
+
+	    if (comp->snum.snum_str[0] != '\0') {
+		bcopy(comp->snum.snum_str,
+		      m->sys_snum,
+		      MAX_SERIAL_NUM_SIZE);
+		m->sys_snum_valid = 1;
+	    }
+    }
+
+    if (m->sys_snum_valid)
+	return 1;
+    else {
+	DPRINTF("Invalid serial number for module %d, "
+		"possible missing or invalid NIC.", m->id);
+	return 0;
+    }
+}
+
+void
+io_module_init(void)
+{
+    cnodeid_t		node;
+    lboard_t	       *board;
+    nasid_t		nasid;
+    int			nserial;
+    module_t	       *m;
+
+    DPRINTF("*******module_init\n");
+
+    nserial = 0;
+
+    for (node = 0; node < numnodes; node++) {
+	nasid = COMPACT_TO_NASID_NODEID(node);
+
+	board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid), KLTYPE_SNIA);
+	ASSERT(board);
+
+	m = module_add_node(board->brd_module, node);
+
+	if (! m->snum_valid && module_probe_snum(m, nasid))
+	    nserial++;
+    }
+
+    DPRINTF("********found total of %d serial numbers in the system\n",
+	    nserial);
+
+    if (nserial == 0)
+	printk(KERN_WARNING  "io_module_init: No serial number found.\n");
+}
+
+elsc_t *get_elsc(void)
+{
+	return &NODEPDA(cpuid_to_cnodeid(smp_processor_id()))->module->elsc;
+}
+
+int
+get_kmod_info(cmoduleid_t cmod, module_info_t *mod_info)
+{
+    int i;
+
+    if (cmod < 0 || cmod >= nummodules)
+	return -EINVAL;
+
+    if (! modules[cmod]->snum_valid)
+	return -ENXIO;
+
+    mod_info->mod_num = modules[cmod]->id;
+    {
+	char temp[MAX_SERIAL_NUM_SIZE];
+
+	decode_str_serial(modules[cmod]->snum.snum_str, temp);
+
+	/* if this is an invalid serial number return an error */
+	if (temp[0] != 'K')
+	    return -ENXIO;
+
+	mod_info->serial_num = 0;
+
+	for (i = 0; i < MAX_SERIAL_NUM_SIZE && temp[i] != '\0'; i++) {
+	    mod_info->serial_num <<= 4;
+	    mod_info->serial_num |= (temp[i] & 0xf);
+
+	    mod_info->serial_str[i] = temp[i];
+	}
+
+	mod_info->serial_str[i] = '\0';
+    }
+
+    return 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn1/pci_bus_cvlink.c linux-2.4.21-pre6/arch/ia64/sn/io/sn1/pci_bus_cvlink.c
--- linux-2.4.20/arch/ia64/sn/io/sn1/pci_bus_cvlink.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn1/pci_bus_cvlink.c	2003-03-26 23:49:18.000000000 +0000
@@ -0,0 +1,696 @@
+/* $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) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <asm/sn/types.h>
+#include <asm/sn/hack.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/io.h>
+#include <asm/sn/driver.h>
+#include <asm/sn/iograph.h>
+#include <asm/param.h>
+#include <asm/sn/pio.h>
+#include <asm/sn/xtalk/xwidget.h>
+#include <asm/sn/sn_private.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/hcl_util.h>
+#include <asm/sn/intr.h>
+#include <asm/sn/xtalk/xtalkaddrs.h>
+#include <asm/sn/klconfig.h>
+#include <asm/sn/nodepda.h>
+#include <asm/sn/pci/pciio.h>
+#include <asm/sn/pci/pcibr.h>
+#include <asm/sn/pci/pcibr_private.h>
+#include <asm/sn/pci/pci_bus_cvlink.h>
+#include <asm/sn/simulator.h>
+#include <asm/sn/sn_cpuid.h>
+
+extern int bridge_rev_b_data_check_disable;
+
+devfs_handle_t busnum_to_pcibr_vhdl[MAX_PCI_XWIDGET];
+nasid_t busnum_to_nid[MAX_PCI_XWIDGET];
+void * busnum_to_atedmamaps[MAX_PCI_XWIDGET];
+unsigned char num_bridges;
+static int done_probing = 0;
+
+static int pci_bus_map_create(devfs_handle_t xtalk);
+devfs_handle_t devfn_to_vertex(unsigned char busnum, unsigned int devfn);
+
+#define SN_IOPORTS_UNIT 256
+#define MAX_IOPORTS 0xffff
+#define MAX_IOPORTS_CHUNKS (MAX_IOPORTS / SN_IOPORTS_UNIT)
+struct ioports_to_tlbs_s ioports_to_tlbs[MAX_IOPORTS_CHUNKS];
+unsigned long sn_allocate_ioports(unsigned long pci_address);
+extern unsigned char Is_pic_on_this_nasid[512];
+
+extern void sn_init_irq_desc(void);
+
+
+/*
+ * For the given device, initialize whether it is a PIC device.
+ */
+static void
+set_isPIC(struct sn_device_sysdata *device_sysdata)
+{
+	pciio_info_t pciio_info = pciio_info_get(device_sysdata->vhdl);
+	pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);
+
+	device_sysdata->isPIC = IS_PIC_SOFT(pcibr_soft);;
+}
+
+/*
+ * pci_bus_cvlink_init() - To be called once during initialization before 
+ *	SGI IO Infrastructure init is called.
+ */
+void
+pci_bus_cvlink_init(void)
+{
+	memset(busnum_to_pcibr_vhdl, 0x0, sizeof(devfs_handle_t) * MAX_PCI_XWIDGET);
+	memset(busnum_to_nid, 0x0, sizeof(nasid_t) * MAX_PCI_XWIDGET);
+
+	memset(busnum_to_atedmamaps, 0x0, sizeof(void *) * MAX_PCI_XWIDGET);
+
+	memset(ioports_to_tlbs, 0x0, sizeof(ioports_to_tlbs));
+
+	num_bridges = 0;
+}
+
+/*
+ * pci_bus_to_vertex() - Given a logical Linux Bus Number returns the associated 
+ *	pci bus vertex from the SGI IO Infrastructure.
+ */
+devfs_handle_t
+pci_bus_to_vertex(unsigned char busnum)
+{
+
+	devfs_handle_t	pci_bus = NULL;
+
+
+	/*
+	 * First get the xwidget vertex.
+	 */
+	pci_bus = busnum_to_pcibr_vhdl[busnum];
+	return(pci_bus);
+}
+
+/*
+ * devfn_to_vertex() - returns the vertex of the device given the bus, slot, 
+ *	and function numbers.
+ */
+devfs_handle_t
+devfn_to_vertex(unsigned char busnum, unsigned int devfn)
+{
+
+	int slot = 0;
+	int func = 0;
+	char	name[16];
+	devfs_handle_t  pci_bus = NULL;
+	devfs_handle_t	device_vertex = (devfs_handle_t)NULL;
+
+	/*
+	 * Go get the pci bus vertex.
+	 */
+	pci_bus = pci_bus_to_vertex(busnum);
+	if (!pci_bus) {
+		/*
+		 * During probing, the Linux pci code invents non existant
+		 * bus numbers and pci_dev structures and tries to access
+		 * them to determine existance. Don't crib during probing.
+		 */
+		if (done_probing)
+			printk("devfn_to_vertex: Invalid bus number %d given.\n", busnum);
+		return(NULL);
+	}
+
+
+	/*
+	 * Go get the slot&function vertex.
+	 * Should call pciio_slot_func_to_name() when ready.
+	 */
+	slot = PCI_SLOT(devfn);
+	func = PCI_FUNC(devfn);
+
+	/*
+	 * For a NON Multi-function card the name of the device looks like:
+	 * ../pci/1, ../pci/2 ..
+	 */
+	if (func == 0) {
+        	sprintf(name, "%d", slot);
+		if (hwgraph_traverse(pci_bus, name, &device_vertex) == 
+			GRAPH_SUCCESS) {
+			if (device_vertex) {
+				return(device_vertex);
+			}
+		}
+	}
+			
+	/*
+	 * This maybe a multifunction card.  It's names look like:
+	 * ../pci/1a, ../pci/1b, etc.
+	 */
+	sprintf(name, "%d%c", slot, 'a'+func);
+	if (hwgraph_traverse(pci_bus, name, &device_vertex) != GRAPH_SUCCESS) {
+		if (!device_vertex) {
+			return(NULL);
+		}
+	}
+
+	return(device_vertex);
+}
+
+/*
+ * For the given device, initialize the addresses for both the Device(x) Flush 
+ * Write Buffer register and the Xbow Flush Register for the port the PCI bus 
+ * is connected.
+ */
+static void
+set_flush_addresses(struct pci_dev *device_dev, 
+	struct sn_device_sysdata *device_sysdata)
+{
+	pciio_info_t pciio_info = pciio_info_get(device_sysdata->vhdl);
+	pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info);
+	pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);
+    	bridge_t               *bridge = pcibr_soft->bs_base;
+
+	device_sysdata->dma_buf_sync = (volatile unsigned int *) 
+		&(bridge->b_wr_req_buf[pciio_slot].reg);
+	device_sysdata->xbow_buf_sync = (volatile unsigned int *)
+		XBOW_PRIO_LINKREGS_PTR(NODE_SWIN_BASE(get_nasid(), 0), 
+		pcibr_soft->bs_xid);
+#ifdef DEBUG
+
+	printk("set_flush_addresses: dma_buf_sync %p xbow_buf_sync %p\n", 
+		device_sysdata->dma_buf_sync, device_sysdata->xbow_buf_sync);
+
+	while((volatile unsigned int )*device_sysdata->dma_buf_sync);
+	while((volatile unsigned int )*device_sysdata->xbow_buf_sync);
+#endif
+
+}
+
+/*
+ * Most drivers currently do not properly tell the arch specific pci dma
+ * interfaces whether they can handle A64. Here is where we privately
+ * keep track of this.
+ */
+static void __init
+set_sn_pci64(struct pci_dev *dev)
+{
+	unsigned short vendor = dev->vendor;
+	unsigned short device = dev->device;
+
+	if (vendor == PCI_VENDOR_ID_QLOGIC) {
+		if ((device == PCI_DEVICE_ID_QLOGIC_ISP2100) ||
+				(device == PCI_DEVICE_ID_QLOGIC_ISP2200)) {
+			SET_PCIA64(dev);
+			return;
+		}
+	}
+
+	if (vendor == PCI_VENDOR_ID_SGI) {
+		if (device == PCI_DEVICE_ID_SGI_IOC3) {
+			SET_PCIA64(dev);
+			return;
+		}
+	}
+
+}
+
+/*
+ * sn_allocate_ioports() - This routine provides the allocation and 
+ *	mappings between Linux style IOPORTs management.
+ *
+ *	For simplicity sake, SN1 will allocate IOPORTs in chunks of 
+ *	256bytes .. irrespective of what the card desires.  This may 
+ *	have to change when we understand how to deal with legacy ioports 
+ *	which are hardcoded in some drivers e.g. SVGA.
+ *
+ *	Ofcourse, the SN1 IO Infrastructure has no concept of IOPORT numbers.
+ *	It will remain so.  The IO Infrastructure will continue to map 
+ *	IO Resource just like IRIX.  When this is done, we map IOPORT 
+ *	chunks to these resources.  The Linux drivers will see and use real 
+ *	IOPORT numbers.  The various IOPORT access macros e.g. inb/outb etc. 
+ *	does the munging of these IOPORT numbers to make a Uncache Virtual 
+ *	Address.  This address via the tlb entries generates the PCI Address 
+ *	allocated by the SN1 IO Infrastructure Layer.
+ */
+static unsigned long sn_ioport_num = 0x1000; /* Reserve room for Legacy stuff */
+unsigned long
+sn_allocate_ioports(unsigned long pci_address)
+{
+	
+	unsigned long ioport_index;
+
+	/*
+	 * Just some idiot checking ..
+	 */
+	if ( sn_ioport_num > 0xffff ) {
+		printk("sn_allocate_ioports: No more IO PORTS available\n");
+		return(-1);
+	}
+
+	/*
+	 * See Section 4.1.1.5 of Intel IA-64 Acrchitecture Software Developer's
+	 * Manual for details.
+	 */
+	ioport_index = sn_ioport_num / SN_IOPORTS_UNIT;
+
+	ioports_to_tlbs[ioport_index].p = 1; /* Present Bit */
+	ioports_to_tlbs[ioport_index].rv_1 = 0; /* 1 Bit */
+	ioports_to_tlbs[ioport_index].ma = 4; /* Memory Attributes 3 bits*/
+	ioports_to_tlbs[ioport_index].a = 1; /* Set Data Access Bit Fault 1 Bit*/
+	ioports_to_tlbs[ioport_index].d = 1; /* Dirty Bit */
+	ioports_to_tlbs[ioport_index].pl = 0;/* Privilege Level - All levels can R/W*/
+	ioports_to_tlbs[ioport_index].ar = 3; /* Access Rights - R/W only*/
+	ioports_to_tlbs[ioport_index].ppn = pci_address >> 12; /* 4K page size */
+	ioports_to_tlbs[ioport_index].ed = 0; /* Exception Deferral Bit */
+	ioports_to_tlbs[ioport_index].ig = 0; /* Ignored */
+
+	/* printk("sn_allocate_ioports: ioport_index 0x%x ioports_to_tlbs 0x%p\n", ioport_index, ioports_to_tlbs[ioport_index]); */
+	
+	sn_ioport_num += SN_IOPORTS_UNIT;
+
+	return(sn_ioport_num - SN_IOPORTS_UNIT);
+}
+
+/*
+ * sn_pci_fixup() - This routine is called when platform_pci_fixup() is 
+ *	invoked at the end of pcibios_init() to link the Linux pci 
+ *	infrastructure to SGI IO Infrasturcture - ia64/kernel/pci.c
+ *
+ *	Other platform specific fixup can also be done here.
+ */
+void
+sn_pci_fixup(int arg)
+{
+	struct list_head *ln;
+	struct pci_bus *pci_bus = NULL;
+	struct pci_dev *device_dev = NULL;
+	struct sn_widget_sysdata *widget_sysdata;
+	struct sn_device_sysdata *device_sysdata;
+#ifdef SN_IOPORTS
+	unsigned long ioport;
+#endif
+	pciio_intr_t intr_handle;
+	int cpuid, bit;
+	devfs_handle_t device_vertex;
+	pciio_intr_line_t lines;
+	extern void sn_pci_find_bios(void);
+
+	if (arg == 0) {
+		sn_init_irq_desc();
+		sn_pci_find_bios();
+		return;
+	}
+
+	done_probing = 1;
+
+	/*
+	 * Initialize the pci bus vertex in the pci_bus struct.
+	 */
+	for( ln = pci_root_buses.next; ln != &pci_root_buses; ln = ln->next) {
+		pci_bus = pci_bus_b(ln);
+		widget_sysdata = kmalloc(sizeof(struct sn_widget_sysdata), 
+					GFP_KERNEL);
+		widget_sysdata->vhdl = pci_bus_to_vertex(pci_bus->number);
+		pci_bus->sysdata = (void *)widget_sysdata;
+	}
+
+	/*
+ 	 * set the root start and end so that drivers calling check_region()
+	 * won't see a conflict
+	 */
+#ifdef SN_IOPORTS
+	ioport_resource.start  = sn_ioport_num;
+	ioport_resource.end = 0xffff;
+#else
+	if ( IS_RUNNING_ON_SIMULATOR() ) {
+		/*
+		 * IDE legacy IO PORTs are supported in Medusa.
+		 * Just open up IO PORTs from 0 .. ioport_resource.end.
+		 */
+		ioport_resource.start = 0;
+	} else {
+		/*
+		 * We do not support Legacy IO PORT numbers.
+		 */
+		ioport_resource.start |= IO_SWIZ_BASE | __IA64_UNCACHED_OFFSET;
+	}
+	ioport_resource.end |= (HSPEC_SWIZ_BASE-1) | __IA64_UNCACHED_OFFSET;
+#endif
+
+	/*
+	 * Set the root start and end for Mem Resource.
+	 */
+	iomem_resource.start = 0;
+	iomem_resource.end = 0xffffffffffffffff;
+
+	/*
+	 * Initialize the device vertex in the pci_dev struct.
+	 */
+	pci_for_each_dev(device_dev) {
+		unsigned int irq;
+		int idx;
+		u16 cmd;
+		devfs_handle_t vhdl;
+		unsigned long size;
+		extern int bit_pos_to_irq(int);
+
+		if (device_dev->vendor == PCI_VENDOR_ID_SGI &&
+				device_dev->device == PCI_DEVICE_ID_SGI_IOC3) {
+			extern void pci_fixup_ioc3(struct pci_dev *d);
+			pci_fixup_ioc3(device_dev);
+		}
+
+		/* Set the device vertex */
+
+		device_sysdata = kmalloc(sizeof(struct sn_device_sysdata),
+					GFP_KERNEL);
+		device_sysdata->vhdl = devfn_to_vertex(device_dev->bus->number, device_dev->devfn);
+		device_sysdata->isa64 = 0;
+		/*
+		 * Set the xbridge Device(X) Write Buffer Flush and Xbow Flush 
+		 * register addresses.
+		 */
+		(void) set_flush_addresses(device_dev, device_sysdata);
+
+		device_dev->sysdata = (void *) device_sysdata;
+		set_sn_pci64(device_dev);
+		set_isPIC(device_sysdata);
+
+		pci_read_config_word(device_dev, PCI_COMMAND, &cmd);
+
+		/*
+		 * Set the resources address correctly.  The assumption here 
+		 * is that the addresses in the resource structure has been
+		 * read from the card and it was set in the card by our
+		 * Infrastructure ..
+		 */
+		vhdl = device_sysdata->vhdl;
+		for (idx = 0; idx < PCI_ROM_RESOURCE; idx++) {
+			size = 0;
+			size = device_dev->resource[idx].end -
+				device_dev->resource[idx].start;
+			if (size) {
+				device_dev->resource[idx].start = (unsigned long)pciio_pio_addr(vhdl, 0, PCIIO_SPACE_WIN(idx), 0, size, 0, (IS_PIC_DEVICE(device_dev)) ? 0 : PCIIO_BYTE_STREAM);
+				device_dev->resource[idx].start |= __IA64_UNCACHED_OFFSET;
+			}
+			else
+				continue;
+
+			device_dev->resource[idx].end = 
+				device_dev->resource[idx].start + size;
+
+			/*
+			 * Adjust the addresses to go to the SWIZZLE ..
+			 */
+			device_dev->resource[idx].start = 
+				device_dev->resource[idx].start & 0xfffff7ffffffffff;
+			device_dev->resource[idx].end = 
+				device_dev->resource[idx].end & 0xfffff7ffffffffff;
+
+			if (device_dev->resource[idx].flags & IORESOURCE_IO) {
+				cmd |= PCI_COMMAND_IO;
+#ifdef SN_IOPORTS
+				ioport = sn_allocate_ioports(device_dev->resource[idx].start);
+				if (ioport < 0) {
+					printk("sn_pci_fixup: PCI Device 0x%x on PCI Bus %d not mapped to IO PORTs .. IO PORTs exhausted\n", device_dev->devfn, device_dev->bus->number);
+					continue;
+				}
+				pciio_config_set(vhdl, (unsigned) PCI_BASE_ADDRESS_0 + (idx * 4), 4, (res + (ioport & 0xfff)));
+
+				printk("sn_pci_fixup: ioport number %d mapped to pci address 0x%lx\n", ioport, (res + (ioport & 0xfff)));
+
+				device_dev->resource[idx].start = ioport;
+				device_dev->resource[idx].end = ioport + SN_IOPORTS_UNIT;
+#endif
+			}
+			if (device_dev->resource[idx].flags & IORESOURCE_MEM)
+				cmd |= PCI_COMMAND_MEMORY;
+		}
+		/*
+		 * Now handle the ROM resource ..
+		 */
+		size = device_dev->resource[PCI_ROM_RESOURCE].end -
+			device_dev->resource[PCI_ROM_RESOURCE].start;
+
+		if (size) {
+			device_dev->resource[PCI_ROM_RESOURCE].start =
+			(unsigned long) pciio_pio_addr(vhdl, 0, PCIIO_SPACE_ROM, 0, 
+				size, 0, (IS_PIC_DEVICE(device_dev)) ? 0 : PCIIO_BYTE_STREAM);
+			device_dev->resource[PCI_ROM_RESOURCE].start |= __IA64_UNCACHED_OFFSET;
+			device_dev->resource[PCI_ROM_RESOURCE].end =
+			device_dev->resource[PCI_ROM_RESOURCE].start + size;
+
+                	/*
+                 	 * go through synergy swizzled space
+                 	 */
+			device_dev->resource[PCI_ROM_RESOURCE].start &= 0xfffff7ffffffffffUL;
+			device_dev->resource[PCI_ROM_RESOURCE].end   &= 0xfffff7ffffffffffUL;
+
+		}
+
+		/*
+		 * Update the Command Word on the Card.
+		 */
+		cmd |= PCI_COMMAND_MASTER; /* If the device doesn't support */
+					   /* bit gets dropped .. no harm */
+		pci_write_config_word(device_dev, PCI_COMMAND, cmd);
+
+		pci_read_config_byte(device_dev, PCI_INTERRUPT_PIN, (unsigned char *)&lines);
+		if (device_dev->vendor == PCI_VENDOR_ID_SGI &&
+			device_dev->device == PCI_DEVICE_ID_SGI_IOC3 ) {
+				lines = 1;
+		}
+ 
+		device_sysdata = (struct sn_device_sysdata *)device_dev->sysdata;
+		device_vertex = device_sysdata->vhdl;
+ 
+		intr_handle = pciio_intr_alloc(device_vertex, NULL, lines, device_vertex);
+
+		bit = intr_handle->pi_irq;
+		cpuid = intr_handle->pi_cpu;
+		irq = bit_pos_to_irq(bit);
+		irq = irq + (cpuid << 8);
+		pciio_intr_connect(intr_handle);
+		device_dev->irq = irq;
+#ifdef ajmtestintr
+		{
+			int slot = PCI_SLOT(device_dev->devfn);
+			static int timer_set = 0;
+			pcibr_intr_t	pcibr_intr = (pcibr_intr_t)intr_handle;
+			pcibr_soft_t	pcibr_soft = pcibr_intr->bi_soft;
+			extern void intr_test_handle_intr(int, void*, struct pt_regs *);
+
+			if (!timer_set) {
+				intr_test_set_timer();
+				timer_set = 1;
+			}
+			intr_test_register_irq(irq, pcibr_soft, slot);
+			request_irq(irq, intr_test_handle_intr,0,NULL, NULL);
+		}
+#endif
+
+	}
+}
+
+/*
+ * pci_bus_map_create() - Called by pci_bus_to_hcl_cvlink() to finish the job.
+ *
+ *	Linux PCI Bus numbers are assigned from lowest module_id numbers
+ *	(rack/slot etc.) starting from HUB_WIDGET_ID_MAX down to 
+ *	HUB_WIDGET_ID_MIN:
+ *		widgetnum 15 gets lower Bus Number than widgetnum 14 etc.
+ *
+ *	Given 2 modules 001c01 and 001c02 we get the following mappings:
+ *		001c01, widgetnum 15 = Bus number 0
+ *		001c01, widgetnum 14 = Bus number 1
+ *		001c02, widgetnum 15 = Bus number 3
+ *		001c02, widgetnum 14 = Bus number 4
+ *		etc.
+ *
+ * The rational for starting Bus Number 0 with Widget number 15 is because 
+ * the system boot disks are always connected via Widget 15 Slot 0 of the 
+ * I-brick.  Linux creates /dev/sd* devices(naming) strating from Bus Number 0 
+ * Therefore, /dev/sda1 will be the first disk, on Widget 15 of the lowest 
+ * module id(Master Cnode) of the system.
+ *	
+ */
+static int 
+pci_bus_map_create(devfs_handle_t xtalk)
+{
+
+	devfs_handle_t master_node_vertex = NULL;
+	devfs_handle_t xwidget = NULL;
+	devfs_handle_t pci_bus = NULL;
+	hubinfo_t hubinfo = NULL;
+	xwidgetnum_t widgetnum;
+	char pathname[128];
+	graph_error_t rv;
+
+	/*
+	 * Loop throught this vertex and get the Xwidgets ..
+	 */
+	for (widgetnum = HUB_WIDGET_ID_MAX; widgetnum >= HUB_WIDGET_ID_MIN; widgetnum--) {
+
+#if 0
+        {
+                int pos;
+                char dname[256];
+                pos = devfs_generate_path(xtalk, dname, 256);
+                printk("%s : path= %s\n", __FUNCTION__, &dname[pos]);
+        }
+#endif
+
+		sprintf(pathname, "%d", widgetnum);
+		xwidget = NULL;
+		
+		/*
+		 * Example - /hw/module/001c16/Pbrick/xtalk/8 is the xwidget
+		 *	     /hw/module/001c16/Pbrick/xtalk/8/pci/1 is device
+		 */
+		rv = hwgraph_traverse(xtalk, pathname, &xwidget);
+		if ( (rv != GRAPH_SUCCESS) ) {
+			if (!xwidget) {
+				continue;
+}
+		}
+
+		sprintf(pathname, "%d/"EDGE_LBL_PCI, widgetnum);
+		pci_bus = NULL;
+		if (hwgraph_traverse(xtalk, pathname, &pci_bus) != GRAPH_SUCCESS)
+			if (!pci_bus) {
+				continue;
+}
+
+		/*
+		 * Assign the correct bus number and also the nasid of this 
+		 * pci Xwidget.
+		 * 
+		 * Should not be any race here ...
+		 */
+		num_bridges++;
+		busnum_to_pcibr_vhdl[num_bridges - 1] = pci_bus;
+
+		/*
+		 * Get the master node and from there get the NASID.
+		 */
+		master_node_vertex = device_master_get(xwidget);
+		if (!master_node_vertex) {
+			printk("WARNING: pci_bus_map_create: Unable to get .master for vertex 0x%p\n", (void *)xwidget);
+		}
+	
+		hubinfo_get(master_node_vertex, &hubinfo);
+		if (!hubinfo) {
+			printk("WARNING: pci_bus_map_create: Unable to get hubinfo for master node vertex 0x%p\n", (void *)master_node_vertex);
+			return(1);
+		} else {
+			busnum_to_nid[num_bridges - 1] = hubinfo->h_nasid;
+		}
+
+		/*
+		 * Pre assign DMA maps needed for 32 Bits Page Map DMA.
+		 */
+		busnum_to_atedmamaps[num_bridges - 1] = (void *) kmalloc(
+			sizeof(struct sn_dma_maps_s) * MAX_ATE_MAPS, GFP_KERNEL);
+		if (!busnum_to_atedmamaps[num_bridges - 1])
+			printk("WARNING: pci_bus_map_create: Unable to precreate ATE DMA Maps for busnum %d vertex 0x%p\n", num_bridges - 1, (void *)xwidget);
+
+		memset(busnum_to_atedmamaps[num_bridges - 1], 0x0, 
+			sizeof(struct sn_dma_maps_s) * MAX_ATE_MAPS);
+
+	}
+
+        return(0);
+}
+
+/*
+ * pci_bus_to_hcl_cvlink() - This routine is called after SGI IO Infrastructure   
+ *      initialization has completed to set up the mappings between Xbridge
+ *      and logical pci bus numbers.  We also set up the NASID for each of these
+ *      xbridges.
+ *
+ *      Must be called before pci_init() is invoked.
+ */
+int
+pci_bus_to_hcl_cvlink(void) 
+{
+
+	devfs_handle_t devfs_hdl = NULL;
+	devfs_handle_t xtalk = NULL;
+	int rv = 0;
+	char name[256];
+	int master_iobrick;
+	int i;
+
+	/*
+	 * Iterate throught each xtalk links in the system ..
+	 * /hw/module/001c01/node/xtalk/ 8|9|10|11|12|13|14|15 
+	 *
+	 * /hw/module/001c01/node/xtalk/15 -> /hw/module/001c01/Ibrick/xtalk/15
+	 *
+	 * What if it is not pci?
+	 */
+	devfs_hdl = hwgraph_path_to_vertex("/dev/hw/module");
+
+	/*
+	 * To provide consistent(not persistent) device naming, we need to start 
+	 * bus number allocation from the C-Brick with the lowest module id e.g. 001c01 
+	 * with an attached I-Brick.  Find the master_iobrick.
+	 */
+	master_iobrick = -1;
+	for (i = 0; i < nummodules; i++) {
+		moduleid_t iobrick_id; 
+		iobrick_id = iobrick_module_get(&modules[i]->elsc);
+		if (iobrick_id > 0) { /* Valid module id */
+			if (MODULE_GET_BTYPE(iobrick_id) == MODULE_IBRICK) {
+				master_iobrick = i;
+				break;
+			}
+		}
+	}
+
+	/*
+	 * The master_iobrick gets bus 0 and 1.
+	 */
+	if (master_iobrick >= 0) {
+		memset(name, 0, 256);
+		format_module_id(name, modules[master_iobrick]->id, MODULE_FORMAT_BRIEF);
+		strcat(name, "/node/xtalk");
+		xtalk = NULL;
+		rv = hwgraph_edge_get(devfs_hdl, name, &xtalk);
+		pci_bus_map_create(xtalk);
+	}
+		
+	/*
+	 * Now go do the rest of the modules, starting from the C-Brick with the lowest 
+	 * module id, remembering to skip the master_iobrick, which was done above.
+	 */
+	for (i = 0; i < nummodules; i++) {
+		if (i == master_iobrick) {
+			continue; /* Did the master_iobrick already. */
+		}
+
+		memset(name, 0, 256);
+		format_module_id(name, modules[i]->id, MODULE_FORMAT_BRIEF);
+		strcat(name, "/node/xtalk");
+		xtalk = NULL;
+		rv = hwgraph_edge_get(devfs_hdl, name, &xtalk);
+		pci_bus_map_create(xtalk);
+	}
+
+	return(0);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn1/pcibr.c linux-2.4.21-pre6/arch/ia64/sn/io/sn1/pcibr.c
--- linux-2.4.20/arch/ia64/sn/io/sn1/pcibr.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn1/pcibr.c	2003-03-26 23:49:07.000000000 +0000
@@ -9,7 +9,6 @@
 int NeedXbridgeSwap = 0;
 
 #include <linux/types.h>
-#include <linux/config.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <asm/sn/sgi.h>
@@ -332,7 +331,6 @@
 extern void rmfree(struct map *mp, size_t size, uint64_t a);
 extern int hwgraph_vertex_name_get(devfs_handle_t vhdl, char *buf, uint buflen);
 extern long atoi(register char *p);
-extern void *swap_ptr(void **loc, void *new);
 extern char *dev_to_name(devfs_handle_t dev, char *buf, uint buflen);
 extern cnodeid_t nodevertex_to_cnodeid(devfs_handle_t vhdl);
 extern graph_error_t hwgraph_edge_remove(devfs_handle_t from, char *name, devfs_handle_t *toptr);
@@ -1628,243 +1626,6 @@
 			  "BAD"};
 
 
-#ifdef LATER
-
-void
-pcibr_slot_func_info_return(pcibr_info_h pcibr_infoh,
-                            int func,
-                            pcibr_slot_func_info_resp_t funcp)
-{
-    pcibr_info_t                 pcibr_info = pcibr_infoh[func];
-    int                          win;
-
-    funcp->resp_f_status = 0;
-
-    if (!pcibr_info) {
-        return;
-    }
-
-    funcp->resp_f_status |= FUNC_IS_VALID;
-#ifdef SUPPORT_PRINTING_V_FORMAT
-    sprintf(funcp->resp_f_slot_name, "%v", pcibr_info->f_vertex);
-#else
-    sprintf(funcp->resp_f_slot_name, "%x", pcibr_info->f_vertex);
-#endif
-
-    if(is_sys_critical_vertex(pcibr_info->f_vertex)) {
-        funcp->resp_f_status |= FUNC_IS_SYS_CRITICAL;
-    }
-
-    funcp->resp_f_bus = pcibr_info->f_bus;
-    funcp->resp_f_slot = pcibr_info->f_slot;
-    funcp->resp_f_func = pcibr_info->f_func;
-#ifdef SUPPORT_PRINTING_V_FORMAT
-    sprintf(funcp->resp_f_master_name, "%v", pcibr_info->f_master);
-#else
-    sprintf(funcp->resp_f_master_name, "%x", pcibr_info->f_master);
-#endif
-    funcp->resp_f_pops = pcibr_info->f_pops;
-    funcp->resp_f_efunc = pcibr_info->f_efunc;
-    funcp->resp_f_einfo = pcibr_info->f_einfo;
-
-    funcp->resp_f_vendor = pcibr_info->f_vendor;
-    funcp->resp_f_device = pcibr_info->f_device;
-
-    for(win = 0 ; win < 6 ; win++) {
-        funcp->resp_f_window[win].resp_w_base =
-                                  pcibr_info->f_window[win].w_base;
-        funcp->resp_f_window[win].resp_w_size =
-                                  pcibr_info->f_window[win].w_size;
-        sprintf(funcp->resp_f_window[win].resp_w_space,
-                "%s",
-                pci_space_name[pcibr_info->f_window[win].w_space]);
-    }
-
-    funcp->resp_f_rbase = pcibr_info->f_rbase;
-    funcp->resp_f_rsize = pcibr_info->f_rsize;
-
-    for (win = 0 ; win < 4; win++) {
-        funcp->resp_f_ibit[win] = pcibr_info->f_ibit[win];
-    }
-
-    funcp->resp_f_att_det_error = pcibr_info->f_att_det_error;
-
-}
-
-int
-pcibr_slot_info_return(pcibr_soft_t             pcibr_soft,
-                       pciio_slot_t             slot,
-                       pcibr_slot_info_resp_t   respp)
-{
-    pcibr_soft_slot_t            pss;
-    int                          func;
-    bridge_t                    *bridge = pcibr_soft->bs_base;
-    reg_p                        b_respp;
-    pcibr_slot_info_resp_t       slotp;
-    pcibr_slot_func_info_resp_t  funcp;
-
-    slotp = snia_kmem_zalloc(sizeof(*slotp), KM_SLEEP);
-    if (slotp == NULL) {
-        return(ENOMEM);
-    }
-
-    pss = &pcibr_soft->bs_slot[slot];
-    
-    printk("\nPCI INFRASTRUCTURAL INFO FOR SLOT %d\n\n", slot);
-
-    slotp->resp_has_host = pss->has_host;
-    slotp->resp_host_slot = pss->host_slot;
-#ifdef SUPPORT_PRINTING_V_FORMAT
-    sprintf(slotp->resp_slot_conn_name, "%v", pss->slot_conn);
-#else
-    sprintf(slotp->resp_slot_conn_name, "%x", pss->slot_conn);
-#endif
-    slotp->resp_slot_status = pss->slot_status;
-    slotp->resp_l1_bus_num = io_path_map_widget(pcibr_soft->bs_vhdl);
-
-    if (is_sys_critical_vertex(pss->slot_conn)) {
-        slotp->resp_slot_status |= SLOT_IS_SYS_CRITICAL;
-    }
-
-    slotp->resp_bss_ninfo = pss->bss_ninfo;
-
-    for (func = 0; func < pss->bss_ninfo; func++) {
-        funcp = &(slotp->resp_func[func]);
-        pcibr_slot_func_info_return(pss->bss_infos, func, funcp);
-    }
-
-    sprintf(slotp->resp_bss_devio_bssd_space, "%s",
-            pci_space_name[pss->bss_devio.bssd_space]);
-    slotp->resp_bss_devio_bssd_base = pss->bss_devio.bssd_base;
-    slotp->resp_bss_device = pss->bss_device;
-
-    slotp->resp_bss_pmu_uctr = pss->bss_pmu_uctr;
-    slotp->resp_bss_d32_uctr = pss->bss_d32_uctr;
-    slotp->resp_bss_d64_uctr = pss->bss_d64_uctr;
-
-    slotp->resp_bss_d64_base = pss->bss_d64_base;
-    slotp->resp_bss_d64_flags = pss->bss_d64_flags;
-    slotp->resp_bss_d32_base = pss->bss_d32_base;
-    slotp->resp_bss_d32_flags = pss->bss_d32_flags;
-
-    slotp->resp_bss_ext_ates_active = atomic_read(&pss->bss_ext_ates_active);
-
-    slotp->resp_bss_cmd_pointer = pss->bss_cmd_pointer;
-    slotp->resp_bss_cmd_shadow = pss->bss_cmd_shadow;
-
-    slotp->resp_bs_rrb_valid = pcibr_soft->bs_rrb_valid[slot];
-    slotp->resp_bs_rrb_valid_v = pcibr_soft->bs_rrb_valid[slot +
-                                                      PCIBR_RRB_SLOT_VIRTUAL];
-    slotp->resp_bs_rrb_res = pcibr_soft->bs_rrb_res[slot];
-
-    if (slot & 1) {
-        b_respp = &bridge->b_odd_resp;
-    } else {
-        b_respp = &bridge->b_even_resp;
-    }
-
-    slotp->resp_b_resp = *b_respp;
-
-    slotp->resp_b_int_device = bridge->b_int_device;
-    slotp->resp_b_int_enable = bridge->b_int_enable;
-    slotp->resp_b_int_host = bridge->b_int_addr[slot].addr;
-
-    if (COPYOUT(slotp, respp, sizeof(*respp))) {
-        return(EFAULT);
-    }
-
-    snia_kmem_free(slotp, sizeof(*slotp));
-
-    return(0);
-}
-
-/*
- * pcibr_slot_query
- *	Return information about the PCI slot maintained by the infrastructure.
- *	Information is requested in the request structure.
- *
- *      Information returned in the response structure:
- *		Slot hwgraph name
- *		Vendor/Device info
- *		Base register info
- *		Interrupt mapping from device pins to the bridge pins
- *		Devio register
- *		Software RRB info
- *		RRB register info
- *		Host/Gues info
- *		PCI Bus #,slot #, function #
- *		Slot provider hwgraph name
- *		Provider Functions
- *		Error handler
- *		DMA mapping usage counters
- *		DMA direct translation info
- *		External SSRAM workaround info
- */
-int
-pcibr_slot_query(devfs_handle_t pcibr_vhdl, pcibr_slot_info_req_t reqp)
-{
-    pcibr_soft_t            pcibr_soft = pcibr_soft_get(pcibr_vhdl);
-    pciio_slot_t            slot = reqp->req_slot;
-    pciio_slot_t            tmp_slot;
-    pcibr_slot_info_resp_t  respp = (pcibr_slot_info_resp_t) reqp->req_respp;
-    int                     size = reqp->req_size;
-    int                     error;
-
-    /* Make sure that we are dealing with a bridge device vertex */
-    if (!pcibr_soft) {
-        return(EINVAL);
-    }
-
-    /* Make sure that we have a valid PCI slot number or PCIIO_SLOT_NONE */
-    if ((!PCIBR_VALID_SLOT(slot)) && (slot != PCIIO_SLOT_NONE)) {
-        return(EINVAL);
-    }
-
-    /* Return information for the requested PCI slot */
-    if (slot != PCIIO_SLOT_NONE) {
-        if (size < sizeof(*respp)) {
-            return(EINVAL);
-        }
-
-        /* Acquire read access to the slot */
-        mrlock(pcibr_soft->bs_slot[slot].slot_lock, MR_ACCESS, PZERO);
-
-        error = pcibr_slot_info_return(pcibr_soft, slot, respp);
-
-        /* Release the slot lock */
-        mrunlock(pcibr_soft->bs_slot[slot].slot_lock);
-
-        return(error);
-    }
-
-    /* Return information for all the slots */
-    for (tmp_slot = 0; tmp_slot < 8; tmp_slot++) {
-
-        if (size < sizeof(*respp)) {
-            return(EINVAL);
-        }
-
-        /* Acquire read access to the slot */
-        mrlock(pcibr_soft->bs_slot[tmp_slot].slot_lock, MR_ACCESS, PZERO);
-
-        error = pcibr_slot_info_return(pcibr_soft, tmp_slot, respp);
-
-        /* Release the slot lock */
-        mrunlock(pcibr_soft->bs_slot[tmp_slot].slot_lock);
-
-        if (error) {
-            return(error);
-        }
-
-        ++respp;
-        size -= sizeof(*respp);
-    }
-
-    return(error);
-}
-#endif	/* LATER */
-
-
 /*ARGSUSED */
 int
 pcibr_ioctl(devfs_handle_t dev,
@@ -3617,7 +3378,7 @@
 	self->bl_soft = pcibr_soft;
 	self->bl_vhdl = pcibr_vhdl;
 	self->bl_next = pcibr_list;
-	self->bl_next = swap_ptr((void **) &pcibr_list, (void *)self);
+        pcibr_list = self; 
     }
 #endif
 
@@ -6455,9 +6216,7 @@
 
 	    intr_bit = (short) xtalk_intr_vector_get(xtalk_intr);
 	    cpu = cpuvertex_to_cpuid(xtalk_intr_cpu_get(xtalk_intr));
-#if defined(CONFIG_IA64_SGI_SN1)
 	    REMOTE_CPU_SEND_INTR(cpu, intr_bit);
-#endif
 	}
 }
 
@@ -6822,13 +6581,8 @@
     bridgereg_t            *int_addr = (bridgereg_t *)
     xtalk_intr_sfarg_get(xtalk_intr);
 
-#ifdef CONFIG_IA64_SGI_SN2
-    *int_addr = ((BRIDGE_INT_ADDR_HOST & (addr >> 26)) |
-		 (BRIDGE_INT_ADDR_FLD & vect));
-#elif CONFIG_IA64_SGI_SN1
     *int_addr = ((BRIDGE_INT_ADDR_HOST & (addr >> 30)) |
 		 (BRIDGE_INT_ADDR_FLD & vect));
-#endif
 }
 
 /*ARGSUSED */
@@ -7485,7 +7239,7 @@
 
 #ifdef LITTLE_ENDIAN
 /*
- * on sn-ia we need to twiddle the the addresses going out
+ * on sn-ia we need to twiddle the addresses going out
  * the pci bus because we use the unswizzled synergy space
  * (the alternative is to use the swizzled synergy space
  * and byte swap the data)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn1/pciio.c linux-2.4.21-pre6/arch/ia64/sn/io/sn1/pciio.c
--- linux-2.4.20/arch/ia64/sn/io/sn1/pciio.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn1/pciio.c	2003-03-26 23:49:20.000000000 +0000
@@ -0,0 +1,1681 @@
+/* $Id: pciio.c,v 1.2 2002/11/16 02:23:19 steiner 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) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#define	USRPCI	0
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/xtalk/xbow.h>	/* Must be before iograph.h to get MAX_PORT_NUM */
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/hcl_util.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/pci/bridge.h>
+#include <asm/sn/ioerror_handling.h>
+#include <asm/sn/pci/pciio.h>
+#include <asm/sn/pci/pciio_private.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/io.h>
+#include <asm/sn/pci/pci_bus_cvlink.h>
+#include <asm/sn/ate_utils.h>
+#include <asm/sn/simulator.h>
+
+#ifdef __ia64
+#define rmallocmap atemapalloc
+#define rmfreemap atemapfree
+#define rmfree atefree
+#define rmalloc atealloc
+#endif
+
+#define DEBUG_PCIIO
+#undef DEBUG_PCIIO	/* turn this on for yet more console output */
+
+
+#define GET_NEW(ptr)	(ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL))
+#define DO_DEL(ptr)	(kfree(ptr))
+
+char                    pciio_info_fingerprint[] = "pciio_info";
+
+cdl_p                   pciio_registry = NULL;
+
+int
+badaddr_val(volatile void *addr, int len, volatile void *ptr)
+{
+	int ret = 0;
+	volatile void *new_addr;
+
+	switch (len) {
+		case 4:
+			new_addr = (void *)(((u64) addr)^4);
+			ret = ia64_sn_probe_io_slot((long)new_addr, len, (void *)ptr);
+			break;
+		default:
+			printk(KERN_WARNING "badaddr_val given len %x but supports len of 4 only\n", len);
+	}
+
+	if (ret < 0)
+		panic("badaddr_val: unexpected status (%d) in probing", ret);
+	return(ret);
+
+}
+
+
+nasid_t
+get_console_nasid(void)
+{
+	extern nasid_t console_nasid;
+	if (console_nasid < 0) {
+		console_nasid = ia64_sn_get_console_nasid();
+		if (console_nasid < 0) {
+// ZZZ What do we do if we don't get a console nasid on the hardware????
+			if (IS_RUNNING_ON_SIMULATOR() )
+				console_nasid = master_nasid;
+		}
+	} 
+	return console_nasid;
+}
+
+int
+hub_dma_enabled(devfs_handle_t xconn_vhdl)
+{
+	return(0);
+}
+
+int
+hub_error_devenable(devfs_handle_t xconn_vhdl, int devnum, int error_code)
+{
+	return(0);
+}
+
+void
+ioerror_dump(char *name, int error_code, int error_mode, ioerror_t *ioerror)
+{
+}
+
+/******
+ ****** end hack defines ......
+ ******/
+
+
+
+
+/* =====================================================================
+ *    PCI Generic Bus Provider
+ * Implement PCI provider operations.  The pciio* layer provides a
+ * platform-independent interface for PCI devices.  This layer
+ * switches among the possible implementations of a PCI adapter.
+ */
+
+/* =====================================================================
+ *    Provider Function Location SHORTCUT
+ *
+ * On platforms with only one possible PCI provider, macros can be
+ * set up at the top that cause the table lookups and indirections to
+ * completely disappear.
+ */
+
+/*
+ *    For the moment, we will assume that IP27
+ *      only use Bridge ASICs to provide PCI support.
+ */
+#include <asm/sn/pci/pcibr.h>
+#define DEV_FUNC(dev,func)	pcibr_##func
+#define CAST_PIOMAP(x)		((pcibr_piomap_t)(x))
+#define CAST_DMAMAP(x)		((pcibr_dmamap_t)(x))
+#define CAST_INTR(x)		((pcibr_intr_t)(x))
+
+/* =====================================================================
+ *    Function Table of Contents
+ */
+
+#if !defined(DEV_FUNC)
+static pciio_provider_t *pciio_to_provider_fns(devfs_handle_t dev);
+#endif
+
+pciio_piomap_t          pciio_piomap_alloc(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, size_t, unsigned);
+void                    pciio_piomap_free(pciio_piomap_t);
+caddr_t                 pciio_piomap_addr(pciio_piomap_t, iopaddr_t, size_t);
+
+void                    pciio_piomap_done(pciio_piomap_t);
+caddr_t                 pciio_piotrans_addr(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, unsigned);
+caddr_t			pciio_pio_addr(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, pciio_piomap_t *, unsigned);
+
+iopaddr_t               pciio_piospace_alloc(devfs_handle_t, device_desc_t, pciio_space_t, size_t, size_t);
+void                    pciio_piospace_free(devfs_handle_t, pciio_space_t, iopaddr_t, size_t);
+
+pciio_dmamap_t          pciio_dmamap_alloc(devfs_handle_t, device_desc_t, size_t, unsigned);
+void                    pciio_dmamap_free(pciio_dmamap_t);
+iopaddr_t               pciio_dmamap_addr(pciio_dmamap_t, paddr_t, size_t);
+alenlist_t              pciio_dmamap_list(pciio_dmamap_t, alenlist_t, unsigned);
+void                    pciio_dmamap_done(pciio_dmamap_t);
+iopaddr_t               pciio_dmatrans_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, unsigned);
+alenlist_t              pciio_dmatrans_list(devfs_handle_t, device_desc_t, alenlist_t, unsigned);
+void			pciio_dmamap_drain(pciio_dmamap_t);
+void			pciio_dmaaddr_drain(devfs_handle_t, paddr_t, size_t);
+void			pciio_dmalist_drain(devfs_handle_t, alenlist_t);
+iopaddr_t               pciio_dma_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, pciio_dmamap_t *, unsigned);
+
+pciio_intr_t            pciio_intr_alloc(devfs_handle_t, device_desc_t, pciio_intr_line_t, devfs_handle_t);
+void                    pciio_intr_free(pciio_intr_t);
+int                     pciio_intr_connect(pciio_intr_t);
+void                    pciio_intr_disconnect(pciio_intr_t);
+devfs_handle_t            pciio_intr_cpu_get(pciio_intr_t);
+
+void			pciio_slot_func_to_name(char *, pciio_slot_t, pciio_function_t);
+
+void                    pciio_provider_startup(devfs_handle_t);
+void                    pciio_provider_shutdown(devfs_handle_t);
+
+pciio_endian_t          pciio_endian_set(devfs_handle_t, pciio_endian_t, pciio_endian_t);
+pciio_priority_t        pciio_priority_set(devfs_handle_t, pciio_priority_t);
+devfs_handle_t            pciio_intr_dev_get(pciio_intr_t);
+
+devfs_handle_t            pciio_pio_dev_get(pciio_piomap_t);
+pciio_slot_t            pciio_pio_slot_get(pciio_piomap_t);
+pciio_space_t           pciio_pio_space_get(pciio_piomap_t);
+iopaddr_t               pciio_pio_pciaddr_get(pciio_piomap_t);
+ulong                   pciio_pio_mapsz_get(pciio_piomap_t);
+caddr_t                 pciio_pio_kvaddr_get(pciio_piomap_t);
+
+devfs_handle_t            pciio_dma_dev_get(pciio_dmamap_t);
+pciio_slot_t            pciio_dma_slot_get(pciio_dmamap_t);
+
+pciio_info_t            pciio_info_chk(devfs_handle_t);
+pciio_info_t            pciio_info_get(devfs_handle_t);
+void                    pciio_info_set(devfs_handle_t, pciio_info_t);
+devfs_handle_t            pciio_info_dev_get(pciio_info_t);
+pciio_slot_t            pciio_info_slot_get(pciio_info_t);
+pciio_function_t        pciio_info_function_get(pciio_info_t);
+pciio_vendor_id_t       pciio_info_vendor_id_get(pciio_info_t);
+pciio_device_id_t       pciio_info_device_id_get(pciio_info_t);
+devfs_handle_t            pciio_info_master_get(pciio_info_t);
+arbitrary_info_t        pciio_info_mfast_get(pciio_info_t);
+pciio_provider_t       *pciio_info_pops_get(pciio_info_t);
+error_handler_f	       *pciio_info_efunc_get(pciio_info_t);
+error_handler_arg_t    *pciio_info_einfo_get(pciio_info_t);
+pciio_space_t		pciio_info_bar_space_get(pciio_info_t, int);
+iopaddr_t		pciio_info_bar_base_get(pciio_info_t, int);
+size_t			pciio_info_bar_size_get(pciio_info_t, int);
+iopaddr_t		pciio_info_rom_base_get(pciio_info_t);
+size_t			pciio_info_rom_size_get(pciio_info_t);
+
+void                    pciio_init(void);
+int                     pciio_attach(devfs_handle_t);
+
+void                    pciio_provider_register(devfs_handle_t, pciio_provider_t *pciio_fns);
+void                    pciio_provider_unregister(devfs_handle_t);
+pciio_provider_t       *pciio_provider_fns_get(devfs_handle_t);
+
+int                     pciio_driver_register(pciio_vendor_id_t, pciio_device_id_t, char *driver_prefix, unsigned);
+void                    pciio_driver_unregister(char *driver_prefix);
+
+devfs_handle_t            pciio_device_register(devfs_handle_t, devfs_handle_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t);
+
+void			pciio_device_unregister(devfs_handle_t);
+pciio_info_t		pciio_device_info_new(pciio_info_t, devfs_handle_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t);
+void			pciio_device_info_free(pciio_info_t);
+devfs_handle_t		pciio_device_info_register(devfs_handle_t, pciio_info_t);
+void			pciio_device_info_unregister(devfs_handle_t, pciio_info_t);
+int                     pciio_device_attach(devfs_handle_t, int);
+int			pciio_device_detach(devfs_handle_t, int);
+void                    pciio_error_register(devfs_handle_t, error_handler_f *, error_handler_arg_t);
+
+int                     pciio_reset(devfs_handle_t);
+int                     pciio_write_gather_flush(devfs_handle_t);
+int                     pciio_slot_inuse(devfs_handle_t);
+
+/* =====================================================================
+ *    Provider Function Location
+ *
+ *      If there is more than one possible provider for
+ *      this platform, we need to examine the master
+ *      vertex of the current vertex for a provider
+ *      function structure, and indirect through the
+ *      appropriately named member.
+ */
+
+#if !defined(DEV_FUNC)
+
+static pciio_provider_t *
+pciio_to_provider_fns(devfs_handle_t dev)
+{
+    pciio_info_t            card_info;
+    pciio_provider_t       *provider_fns;
+
+    /*
+     * We're called with two types of vertices, one is
+     * the bridge vertex (ends with "pci") and the other is the
+     * pci slot vertex (ends with "pci/[0-8]").  For the first type
+     * we need to get the provider from the PFUNCS label.  For
+     * the second we get it from fastinfo/c_pops.
+     */
+    provider_fns = pciio_provider_fns_get(dev);
+    if (provider_fns == NULL) {
+	card_info = pciio_info_get(dev);
+	if (card_info != NULL) {
+		provider_fns = pciio_info_pops_get(card_info);
+	}
+    }
+
+    if (provider_fns == NULL)
+#if defined(SUPPORT_PRINTING_V_FORMAT)
+	PRINT_PANIC("%v: provider_fns == NULL", dev);
+#else
+	PRINT_PANIC("0x%p: provider_fns == NULL", (void *)dev);
+#endif
+
+    return provider_fns;
+
+}
+
+#define DEV_FUNC(dev,func)	pciio_to_provider_fns(dev)->func
+#define CAST_PIOMAP(x)		((pciio_piomap_t)(x))
+#define CAST_DMAMAP(x)		((pciio_dmamap_t)(x))
+#define CAST_INTR(x)		((pciio_intr_t)(x))
+#endif
+
+/*
+ * Many functions are not passed their vertex
+ * information directly; rather, they must
+ * dive through a resource map. These macros
+ * are available to coordinate this detail.
+ */
+#define PIOMAP_FUNC(map,func)		DEV_FUNC((map)->pp_dev,func)
+#define DMAMAP_FUNC(map,func)		DEV_FUNC((map)->pd_dev,func)
+#define INTR_FUNC(intr_hdl,func)	DEV_FUNC((intr_hdl)->pi_dev,func)
+
+/* =====================================================================
+ *          PIO MANAGEMENT
+ *
+ *      For mapping system virtual address space to
+ *      pciio space on a specified card
+ */
+
+pciio_piomap_t
+pciio_piomap_alloc(devfs_handle_t dev,	/* set up mapping for this device */
+		   device_desc_t dev_desc,	/* device descriptor */
+		   pciio_space_t space,	/* CFG, MEM, IO, or a device-decoded window */
+		   iopaddr_t addr,	/* lowest address (or offset in window) */
+		   size_t byte_count,	/* size of region containing our mappings */
+		   size_t byte_count_max,	/* maximum size of a mapping */
+		   unsigned flags)
+{					/* defined in sys/pio.h */
+    return (pciio_piomap_t) DEV_FUNC(dev, piomap_alloc)
+	(dev, dev_desc, space, addr, byte_count, byte_count_max, flags);
+}
+
+void
+pciio_piomap_free(pciio_piomap_t pciio_piomap)
+{
+    PIOMAP_FUNC(pciio_piomap, piomap_free)
+	(CAST_PIOMAP(pciio_piomap));
+}
+
+caddr_t
+pciio_piomap_addr(pciio_piomap_t pciio_piomap,	/* mapping resources */
+		  iopaddr_t pciio_addr,	/* map for this pciio address */
+		  size_t byte_count)
+{					/* map this many bytes */
+    pciio_piomap->pp_kvaddr = PIOMAP_FUNC(pciio_piomap, piomap_addr)
+	(CAST_PIOMAP(pciio_piomap), pciio_addr, byte_count);
+
+    return pciio_piomap->pp_kvaddr;
+}
+
+void
+pciio_piomap_done(pciio_piomap_t pciio_piomap)
+{
+    PIOMAP_FUNC(pciio_piomap, piomap_done)
+	(CAST_PIOMAP(pciio_piomap));
+}
+
+caddr_t
+pciio_piotrans_addr(devfs_handle_t dev,	/* translate for this device */
+		    device_desc_t dev_desc,	/* device descriptor */
+		    pciio_space_t space,	/* CFG, MEM, IO, or a device-decoded window */
+		    iopaddr_t addr,	/* starting address (or offset in window) */
+		    size_t byte_count,	/* map this many bytes */
+		    unsigned flags)
+{					/* (currently unused) */
+    return DEV_FUNC(dev, piotrans_addr)
+	(dev, dev_desc, space, addr, byte_count, flags);
+}
+
+caddr_t
+pciio_pio_addr(devfs_handle_t dev,	/* translate for this device */
+	       device_desc_t dev_desc,	/* device descriptor */
+	       pciio_space_t space,	/* CFG, MEM, IO, or a device-decoded window */
+	       iopaddr_t addr,		/* starting address (or offset in window) */
+	       size_t byte_count,	/* map this many bytes */
+	       pciio_piomap_t *mapp,	/* where to return the map pointer */
+	       unsigned flags)
+{					/* PIO flags */
+    pciio_piomap_t          map = 0;
+    int			    errfree = 0;
+    caddr_t                 res;
+
+    if (mapp) {
+	map = *mapp;			/* possible pre-allocated map */
+	*mapp = 0;			/* record "no map used" */
+    }
+
+    res = pciio_piotrans_addr
+	(dev, dev_desc, space, addr, byte_count, flags);
+    if (res)
+	return res;			/* pciio_piotrans worked */
+
+    if (!map) {
+	map = pciio_piomap_alloc
+	    (dev, dev_desc, space, addr, byte_count, byte_count, flags);
+	if (!map)
+	    return res;			/* pciio_piomap_alloc failed */
+	errfree = 1;
+    }
+
+    res = pciio_piomap_addr
+	(map, addr, byte_count);
+    if (!res) {
+	if (errfree)
+	    pciio_piomap_free(map);
+	return res;			/* pciio_piomap_addr failed */
+    }
+    if (mapp)
+	*mapp = map;			/* pass back map used */
+
+    return res;				/* pciio_piomap_addr succeeded */
+}
+
+iopaddr_t
+pciio_piospace_alloc(devfs_handle_t dev,	/* Device requiring space */
+		     device_desc_t dev_desc,	/* Device descriptor */
+		     pciio_space_t space,	/* MEM32/MEM64/IO */
+		     size_t byte_count,	/* Size of mapping */
+		     size_t align)
+{					/* Alignment needed */
+    if (align < NBPP)
+	align = NBPP;
+    return DEV_FUNC(dev, piospace_alloc)
+	(dev, dev_desc, space, byte_count, align);
+}
+
+void
+pciio_piospace_free(devfs_handle_t dev,	/* Device freeing space */
+		    pciio_space_t space,	/* Type of space        */
+		    iopaddr_t pciaddr,	/* starting address */
+		    size_t byte_count)
+{					/* Range of address   */
+    DEV_FUNC(dev, piospace_free)
+	(dev, space, pciaddr, byte_count);
+}
+
+/* =====================================================================
+ *          DMA MANAGEMENT
+ *
+ *      For mapping from pci space to system
+ *      physical space.
+ */
+
+pciio_dmamap_t
+pciio_dmamap_alloc(devfs_handle_t dev,	/* set up mappings for this device */
+		   device_desc_t dev_desc,	/* device descriptor */
+		   size_t byte_count_max,	/* max size of a mapping */
+		   unsigned flags)
+{					/* defined in dma.h */
+    return (pciio_dmamap_t) DEV_FUNC(dev, dmamap_alloc)
+	(dev, dev_desc, byte_count_max, flags);
+}
+
+void
+pciio_dmamap_free(pciio_dmamap_t pciio_dmamap)
+{
+    DMAMAP_FUNC(pciio_dmamap, dmamap_free)
+	(CAST_DMAMAP(pciio_dmamap));
+}
+
+iopaddr_t
+pciio_dmamap_addr(pciio_dmamap_t pciio_dmamap,	/* use these mapping resources */
+		  paddr_t paddr,	/* map for this address */
+		  size_t byte_count)
+{					/* map this many bytes */
+    return DMAMAP_FUNC(pciio_dmamap, dmamap_addr)
+	(CAST_DMAMAP(pciio_dmamap), paddr, byte_count);
+}
+
+alenlist_t
+pciio_dmamap_list(pciio_dmamap_t pciio_dmamap,	/* use these mapping resources */
+		  alenlist_t alenlist,	/* map this Address/Length List */
+		  unsigned flags)
+{
+    return DMAMAP_FUNC(pciio_dmamap, dmamap_list)
+	(CAST_DMAMAP(pciio_dmamap), alenlist, flags);
+}
+
+void
+pciio_dmamap_done(pciio_dmamap_t pciio_dmamap)
+{
+    DMAMAP_FUNC(pciio_dmamap, dmamap_done)
+	(CAST_DMAMAP(pciio_dmamap));
+}
+
+iopaddr_t
+pciio_dmatrans_addr(devfs_handle_t dev,	/* translate for this device */
+		    device_desc_t dev_desc,	/* device descriptor */
+		    paddr_t paddr,	/* system physical address */
+		    size_t byte_count,	/* length */
+		    unsigned flags)
+{					/* defined in dma.h */
+    return DEV_FUNC(dev, dmatrans_addr)
+	(dev, dev_desc, paddr, byte_count, flags);
+}
+
+alenlist_t
+pciio_dmatrans_list(devfs_handle_t dev,	/* translate for this device */
+		    device_desc_t dev_desc,	/* device descriptor */
+		    alenlist_t palenlist,	/* system address/length list */
+		    unsigned flags)
+{					/* defined in dma.h */
+    return DEV_FUNC(dev, dmatrans_list)
+	(dev, dev_desc, palenlist, flags);
+}
+
+iopaddr_t
+pciio_dma_addr(devfs_handle_t dev,	/* translate for this device */
+	       device_desc_t dev_desc,	/* device descriptor */
+	       paddr_t paddr,		/* system physical address */
+	       size_t byte_count,	/* length */
+	       pciio_dmamap_t *mapp,	/* map to use, then map we used */
+	       unsigned flags)
+{					/* PIO flags */
+    pciio_dmamap_t          map = 0;
+    int			    errfree = 0;
+    iopaddr_t               res;
+
+    if (mapp) {
+	map = *mapp;			/* possible pre-allocated map */
+	*mapp = 0;			/* record "no map used" */
+    }
+
+    res = pciio_dmatrans_addr
+	(dev, dev_desc, paddr, byte_count, flags);
+    if (res)
+	return res;			/* pciio_dmatrans worked */
+
+    if (!map) {
+	map = pciio_dmamap_alloc
+	    (dev, dev_desc, byte_count, flags);
+	if (!map)
+	    return res;			/* pciio_dmamap_alloc failed */
+	errfree = 1;
+    }
+
+    res = pciio_dmamap_addr
+	(map, paddr, byte_count);
+    if (!res) {
+	if (errfree)
+	    pciio_dmamap_free(map);
+	return res;			/* pciio_dmamap_addr failed */
+    }
+    if (mapp)
+	*mapp = map;			/* pass back map used */
+
+    return res;				/* pciio_dmamap_addr succeeded */
+}
+
+void
+pciio_dmamap_drain(pciio_dmamap_t map)
+{
+    DMAMAP_FUNC(map, dmamap_drain)
+	(CAST_DMAMAP(map));
+}
+
+void
+pciio_dmaaddr_drain(devfs_handle_t dev, paddr_t addr, size_t size)
+{
+    DEV_FUNC(dev, dmaaddr_drain)
+	(dev, addr, size);
+}
+
+void
+pciio_dmalist_drain(devfs_handle_t dev, alenlist_t list)
+{
+    DEV_FUNC(dev, dmalist_drain)
+	(dev, list);
+}
+
+/* =====================================================================
+ *          INTERRUPT MANAGEMENT
+ *
+ *      Allow crosstalk devices to establish interrupts
+ */
+
+/*
+ * Allocate resources required for an interrupt as specified in intr_desc.
+ * Return resource handle in intr_hdl.
+ */
+pciio_intr_t
+pciio_intr_alloc(devfs_handle_t dev,	/* which Crosstalk device */
+		 device_desc_t dev_desc,	/* device descriptor */
+		 pciio_intr_line_t lines,	/* INTR line(s) to attach */
+		 devfs_handle_t owner_dev)
+{					/* owner of this interrupt */
+    return (pciio_intr_t) DEV_FUNC(dev, intr_alloc)
+	(dev, dev_desc, lines, owner_dev);
+}
+
+/*
+ * Free resources consumed by intr_alloc.
+ */
+void
+pciio_intr_free(pciio_intr_t intr_hdl)
+{
+    INTR_FUNC(intr_hdl, intr_free)
+	(CAST_INTR(intr_hdl));
+}
+
+/*
+ * Associate resources allocated with a previous pciio_intr_alloc call with the
+ * described handler, arg, name, etc.
+ *
+ * Returns 0 on success, returns <0 on failure.
+ */
+int
+pciio_intr_connect(pciio_intr_t intr_hdl)	/* pciio intr resource handle */
+{
+    return INTR_FUNC(intr_hdl, intr_connect)
+	(CAST_INTR(intr_hdl));
+}
+
+/*
+ * Disassociate handler with the specified interrupt.
+ */
+void
+pciio_intr_disconnect(pciio_intr_t intr_hdl)
+{
+    INTR_FUNC(intr_hdl, intr_disconnect)
+	(CAST_INTR(intr_hdl));
+}
+
+/*
+ * Return a hwgraph vertex that represents the CPU currently
+ * targeted by an interrupt.
+ */
+devfs_handle_t
+pciio_intr_cpu_get(pciio_intr_t intr_hdl)
+{
+    return INTR_FUNC(intr_hdl, intr_cpu_get)
+	(CAST_INTR(intr_hdl));
+}
+
+void
+pciio_slot_func_to_name(char		       *name,
+			pciio_slot_t		slot,
+			pciio_function_t	func)
+{
+    /*
+     * standard connection points:
+     *
+     * PCIIO_SLOT_NONE:	.../pci/direct
+     * PCIIO_FUNC_NONE: .../pci/<SLOT>			ie. .../pci/3
+     * multifunction:   .../pci/<SLOT><FUNC>		ie. .../pci/3c
+     */
+
+    if (slot == PCIIO_SLOT_NONE)
+	sprintf(name, EDGE_LBL_DIRECT);
+    else if (func == PCIIO_FUNC_NONE)
+	sprintf(name, "%d", slot);
+    else
+	sprintf(name, "%d%c", slot, 'a'+func);
+}
+
+/* =====================================================================
+ *          CONFIGURATION MANAGEMENT
+ */
+
+/*
+ * Startup a crosstalk provider
+ */
+void
+pciio_provider_startup(devfs_handle_t pciio_provider)
+{
+    DEV_FUNC(pciio_provider, provider_startup)
+	(pciio_provider);
+}
+
+/*
+ * Shutdown a crosstalk provider
+ */
+void
+pciio_provider_shutdown(devfs_handle_t pciio_provider)
+{
+    DEV_FUNC(pciio_provider, provider_shutdown)
+	(pciio_provider);
+}
+
+/*
+ * Specify endianness constraints.  The driver tells us what the device
+ * does and how it would like to see things in memory.  We reply with
+ * how things will actually appear in memory.
+ */
+pciio_endian_t
+pciio_endian_set(devfs_handle_t dev,
+		 pciio_endian_t device_end,
+		 pciio_endian_t desired_end)
+{
+    ASSERT((device_end == PCIDMA_ENDIAN_BIG) || (device_end == PCIDMA_ENDIAN_LITTLE));
+    ASSERT((desired_end == PCIDMA_ENDIAN_BIG) || (desired_end == PCIDMA_ENDIAN_LITTLE));
+
+#if DEBUG
+#if defined(SUPPORT_PRINTING_V_FORMAT)
+    printk(KERN_ALERT  "%v: pciio_endian_set is going away.\n"
+	    "\tplease use PCIIO_BYTE_STREAM or PCIIO_WORD_VALUES in your\n"
+	    "\tpciio_dmamap_alloc and pciio_dmatrans calls instead.\n",
+	    dev);
+#else
+    printk(KERN_ALERT  "0x%x: pciio_endian_set is going away.\n"
+	    "\tplease use PCIIO_BYTE_STREAM or PCIIO_WORD_VALUES in your\n"
+	    "\tpciio_dmamap_alloc and pciio_dmatrans calls instead.\n",
+	    dev);
+#endif
+#endif
+
+    return DEV_FUNC(dev, endian_set)
+	(dev, device_end, desired_end);
+}
+
+/*
+ * Specify PCI arbitration priority.
+ */
+pciio_priority_t
+pciio_priority_set(devfs_handle_t dev,
+		   pciio_priority_t device_prio)
+{
+    ASSERT((device_prio == PCI_PRIO_HIGH) || (device_prio == PCI_PRIO_LOW));
+
+    return DEV_FUNC(dev, priority_set)
+	(dev, device_prio);
+}
+
+/*
+ * Read value of configuration register
+ */
+uint64_t
+pciio_config_get(devfs_handle_t	dev,
+		 unsigned	reg,
+		 unsigned	size)
+{
+    uint64_t	value = 0;
+    unsigned	shift = 0;
+
+    /* handle accesses that cross words here,
+     * since that's common code between all
+     * possible providers.
+     */
+    while (size > 0) {
+	unsigned	biw = 4 - (reg&3);
+	if (biw > size)
+	    biw = size;
+
+	value |= DEV_FUNC(dev, config_get)
+	    (dev, reg, biw) << shift;
+
+	shift += 8*biw;
+	reg += biw;
+	size -= biw;
+    }
+    return value;
+}
+
+/*
+ * Change value of configuration register
+ */
+void
+pciio_config_set(devfs_handle_t	dev,
+		 unsigned	reg,
+		 unsigned	size,
+		 uint64_t	value)
+{
+    /* handle accesses that cross words here,
+     * since that's common code between all
+     * possible providers.
+     */
+    while (size > 0) {
+	unsigned	biw = 4 - (reg&3);
+	if (biw > size)
+	    biw = size;
+	    
+	DEV_FUNC(dev, config_set)
+	    (dev, reg, biw, value);
+	reg += biw;
+	size -= biw;
+	value >>= biw * 8;
+    }
+}
+
+/* =====================================================================
+ *          GENERIC PCI SUPPORT FUNCTIONS
+ */
+
+/*
+ * Issue a hardware reset to a card.
+ */
+int
+pciio_reset(devfs_handle_t dev)
+{
+    return DEV_FUNC(dev, reset) (dev);
+}
+
+/*
+ * flush write gather buffers
+ */
+int
+pciio_write_gather_flush(devfs_handle_t dev)
+{
+    return DEV_FUNC(dev, write_gather_flush) (dev);
+}
+
+devfs_handle_t
+pciio_intr_dev_get(pciio_intr_t pciio_intr)
+{
+    return (pciio_intr->pi_dev);
+}
+
+/****** Generic crosstalk pio interfaces ******/
+devfs_handle_t
+pciio_pio_dev_get(pciio_piomap_t pciio_piomap)
+{
+    return (pciio_piomap->pp_dev);
+}
+
+pciio_slot_t
+pciio_pio_slot_get(pciio_piomap_t pciio_piomap)
+{
+    return (pciio_piomap->pp_slot);
+}
+
+pciio_space_t
+pciio_pio_space_get(pciio_piomap_t pciio_piomap)
+{
+    return (pciio_piomap->pp_space);
+}
+
+iopaddr_t
+pciio_pio_pciaddr_get(pciio_piomap_t pciio_piomap)
+{
+    return (pciio_piomap->pp_pciaddr);
+}
+
+ulong
+pciio_pio_mapsz_get(pciio_piomap_t pciio_piomap)
+{
+    return (pciio_piomap->pp_mapsz);
+}
+
+caddr_t
+pciio_pio_kvaddr_get(pciio_piomap_t pciio_piomap)
+{
+    return (pciio_piomap->pp_kvaddr);
+}
+
+/****** Generic crosstalk dma interfaces ******/
+devfs_handle_t
+pciio_dma_dev_get(pciio_dmamap_t pciio_dmamap)
+{
+    return (pciio_dmamap->pd_dev);
+}
+
+pciio_slot_t
+pciio_dma_slot_get(pciio_dmamap_t pciio_dmamap)
+{
+    return (pciio_dmamap->pd_slot);
+}
+
+/****** Generic pci slot information interfaces ******/
+
+pciio_info_t
+pciio_info_chk(devfs_handle_t pciio)
+{
+    arbitrary_info_t        ainfo = 0;
+
+    hwgraph_info_get_LBL(pciio, INFO_LBL_PCIIO, &ainfo);
+    return (pciio_info_t) ainfo;
+}
+
+pciio_info_t
+pciio_info_get(devfs_handle_t pciio)
+{
+    pciio_info_t            pciio_info;
+
+    pciio_info = (pciio_info_t) hwgraph_fastinfo_get(pciio);
+
+#ifdef DEBUG_PCIIO
+    {
+	int pos;
+	char dname[256];
+	pos = devfs_generate_path(pciio, dname, 256);
+	printk("%s : path= %s\n", __FUNCTION__, &dname[pos]);
+    }
+#endif /* DEBUG_PCIIO */
+
+    if ((pciio_info != NULL) &&
+	(pciio_info->c_fingerprint != pciio_info_fingerprint)
+	&& (pciio_info->c_fingerprint != NULL)) {
+
+	return((pciio_info_t)-1); /* Should panic .. */
+    }
+	
+
+    return pciio_info;
+}
+
+void
+pciio_info_set(devfs_handle_t pciio, pciio_info_t pciio_info)
+{
+    if (pciio_info != NULL)
+	pciio_info->c_fingerprint = pciio_info_fingerprint;
+    hwgraph_fastinfo_set(pciio, (arbitrary_info_t) pciio_info);
+
+    /* Also, mark this vertex as a PCI slot
+     * and use the pciio_info, so pciio_info_chk
+     * can work (and be fairly efficient).
+     */
+    hwgraph_info_add_LBL(pciio, INFO_LBL_PCIIO,
+			 (arbitrary_info_t) pciio_info);
+}
+
+devfs_handle_t
+pciio_info_dev_get(pciio_info_t pciio_info)
+{
+    return (pciio_info->c_vertex);
+}
+
+pciio_slot_t
+pciio_info_slot_get(pciio_info_t pciio_info)
+{
+    return (pciio_info->c_slot);
+}
+
+pciio_function_t
+pciio_info_function_get(pciio_info_t pciio_info)
+{
+    return (pciio_info->c_func);
+}
+
+pciio_vendor_id_t
+pciio_info_vendor_id_get(pciio_info_t pciio_info)
+{
+    return (pciio_info->c_vendor);
+}
+
+pciio_device_id_t
+pciio_info_device_id_get(pciio_info_t pciio_info)
+{
+    return (pciio_info->c_device);
+}
+
+devfs_handle_t
+pciio_info_master_get(pciio_info_t pciio_info)
+{
+    return (pciio_info->c_master);
+}
+
+arbitrary_info_t
+pciio_info_mfast_get(pciio_info_t pciio_info)
+{
+    return (pciio_info->c_mfast);
+}
+
+pciio_provider_t       *
+pciio_info_pops_get(pciio_info_t pciio_info)
+{
+    return (pciio_info->c_pops);
+}
+
+error_handler_f	       *
+pciio_info_efunc_get(pciio_info_t pciio_info)
+{
+    return (pciio_info->c_efunc);
+}
+
+error_handler_arg_t    *
+pciio_info_einfo_get(pciio_info_t pciio_info)
+{
+    return (pciio_info->c_einfo);
+}
+
+pciio_space_t
+pciio_info_bar_space_get(pciio_info_t info, int win)
+{
+    return info->c_window[win].w_space;
+}
+
+iopaddr_t
+pciio_info_bar_base_get(pciio_info_t info, int win)
+{
+    return info->c_window[win].w_base;
+}
+
+size_t
+pciio_info_bar_size_get(pciio_info_t info, int win)
+{
+    return info->c_window[win].w_size;
+}
+
+iopaddr_t
+pciio_info_rom_base_get(pciio_info_t info)
+{
+    return info->c_rbase;
+}
+
+size_t
+pciio_info_rom_size_get(pciio_info_t info)
+{
+    return info->c_rsize;
+}
+
+
+/* =====================================================================
+ *          GENERIC PCI INITIALIZATION FUNCTIONS
+ */
+
+/*
+ *    pciioinit: called once during device driver
+ *      initializtion if this driver is configured into
+ *      the system.
+ */
+void
+pciio_init(void)
+{
+    cdl_p                   cp;
+
+#if DEBUG && ATTACH_DEBUG
+    printf("pciio_init\n");
+#endif
+    /* Allocate the registry.
+     * We might already have one.
+     * If we don't, go get one.
+     * MPness: someone might have
+     * set one up for us while we
+     * were not looking; use an atomic
+     * compare-and-swap to commit to
+     * using the new registry if and
+     * only if nobody else did first.
+     * If someone did get there first,
+     * toss the one we allocated back
+     * into the pool.
+     */
+    if (pciio_registry == NULL) {
+	cp = cdl_new(EDGE_LBL_PCI, "vendor", "device");
+	if (!compare_and_swap_ptr((void **) &pciio_registry, NULL, (void *) cp)) {
+	    cdl_del(cp);
+	}
+    }
+    ASSERT(pciio_registry != NULL);
+}
+
+/*
+ *    pciioattach: called for each vertex in the graph
+ *      that is a PCI provider.
+ */
+/*ARGSUSED */
+int
+pciio_attach(devfs_handle_t pciio)
+{
+#if DEBUG && ATTACH_DEBUG
+#if defined(SUPPORT_PRINTING_V_FORMAT)
+    printk("%v: pciio_attach\n", pciio);
+#else
+    printk("0x%x: pciio_attach\n", pciio);
+#endif
+#endif
+    return 0;
+}
+
+/*
+ * Associate a set of pciio_provider functions with a vertex.
+ */
+void
+pciio_provider_register(devfs_handle_t provider, pciio_provider_t *pciio_fns)
+{
+    hwgraph_info_add_LBL(provider, INFO_LBL_PFUNCS, (arbitrary_info_t) pciio_fns);
+}
+
+/*
+ * Disassociate a set of pciio_provider functions with a vertex.
+ */
+void
+pciio_provider_unregister(devfs_handle_t provider)
+{
+    arbitrary_info_t        ainfo;
+
+    hwgraph_info_remove_LBL(provider, INFO_LBL_PFUNCS, (long *) &ainfo);
+}
+
+/*
+ * Obtain a pointer to the pciio_provider functions for a specified Crosstalk
+ * provider.
+ */
+pciio_provider_t       *
+pciio_provider_fns_get(devfs_handle_t provider)
+{
+    arbitrary_info_t        ainfo = 0;
+
+    (void) hwgraph_info_get_LBL(provider, INFO_LBL_PFUNCS, &ainfo);
+    return (pciio_provider_t *) ainfo;
+}
+
+/*ARGSUSED4 */
+int
+pciio_driver_register(
+			 pciio_vendor_id_t vendor_id,
+			 pciio_device_id_t device_id,
+			 char *driver_prefix,
+			 unsigned flags)
+{
+    /* a driver's init routine might call
+     * pciio_driver_register before the
+     * system calls pciio_init; so we
+     * make the init call ourselves here.
+     */
+    if (pciio_registry == NULL)
+	pciio_init();
+
+    return cdl_add_driver(pciio_registry,
+			  vendor_id, device_id,
+			  driver_prefix, flags, NULL);
+}
+
+/*
+ * Remove an initialization function.
+ */
+void
+pciio_driver_unregister(
+			   char *driver_prefix)
+{
+    /* before a driver calls unregister,
+     * it must have called register; so
+     * we can assume we have a registry here.
+     */
+    ASSERT(pciio_registry != NULL);
+
+    cdl_del_driver(pciio_registry, driver_prefix, NULL);
+}
+
+/* 
+ * Set the slot status for a device supported by the 
+ * driver being registered.
+ */
+void
+pciio_driver_reg_callback(
+                           devfs_handle_t pconn_vhdl,
+			   int key1,
+			   int key2,
+                           int error)
+{
+}
+
+/* 
+ * Set the slot status for a device supported by the 
+ * driver being unregistered.
+ */
+void
+pciio_driver_unreg_callback(
+                           devfs_handle_t pconn_vhdl,
+			   int key1,
+			   int key2,
+                           int error)
+{
+}
+
+/*
+ * Call some function with each vertex that
+ * might be one of this driver's attach points.
+ */
+void
+pciio_iterate(char *driver_prefix,
+	      pciio_iter_f * func)
+{
+    /* a driver's init routine might call
+     * pciio_iterate before the
+     * system calls pciio_init; so we
+     * make the init call ourselves here.
+     */
+    if (pciio_registry == NULL)
+	pciio_init();
+
+    ASSERT(pciio_registry != NULL);
+
+    cdl_iterate(pciio_registry, driver_prefix, (cdl_iter_f *) func);
+}
+
+devfs_handle_t
+pciio_device_register(
+		devfs_handle_t connectpt,	/* vertex for /hw/.../pciio/%d */
+		devfs_handle_t master,	/* card's master ASIC (PCI provider) */
+		pciio_slot_t slot,	/* card's slot */
+		pciio_function_t func,	/* card's func */
+		pciio_vendor_id_t vendor_id,
+		pciio_device_id_t device_id)
+{
+    return pciio_device_info_register
+	(connectpt, pciio_device_info_new (NULL, master, slot, func,
+					   vendor_id, device_id));
+}
+
+void
+pciio_device_unregister(devfs_handle_t pconn)
+{
+    DEV_FUNC(pconn,device_unregister)(pconn);
+}
+
+pciio_info_t
+pciio_device_info_new(
+		pciio_info_t pciio_info,
+		devfs_handle_t master,
+		pciio_slot_t slot,
+		pciio_function_t func,
+		pciio_vendor_id_t vendor_id,
+		pciio_device_id_t device_id)
+{
+    if (!pciio_info)
+	GET_NEW(pciio_info);
+    ASSERT(pciio_info != NULL);
+
+    pciio_info->c_slot = slot;
+    pciio_info->c_func = func;
+    pciio_info->c_vendor = vendor_id;
+    pciio_info->c_device = device_id;
+    pciio_info->c_master = master;
+    pciio_info->c_mfast = hwgraph_fastinfo_get(master);
+    pciio_info->c_pops = pciio_provider_fns_get(master);
+    pciio_info->c_efunc = 0;
+    pciio_info->c_einfo = 0;
+
+    return pciio_info;
+}
+
+void
+pciio_device_info_free(pciio_info_t pciio_info)
+{
+    /* NOTE : pciio_info is a structure within the pcibr_info
+     *	      and not a pointer to memory allocated on the heap !!
+     */
+    BZERO((char *)pciio_info,sizeof(pciio_info));
+}
+
+devfs_handle_t
+pciio_device_info_register(
+		devfs_handle_t connectpt,		/* vertex at center of bus */
+		pciio_info_t pciio_info)	/* details about the connectpt */
+{
+    char		name[32];
+    devfs_handle_t	pconn;
+    int device_master_set(devfs_handle_t, devfs_handle_t);
+
+    pciio_slot_func_to_name(name,
+			    pciio_info->c_slot,
+			    pciio_info->c_func);
+
+    if (GRAPH_SUCCESS !=
+	hwgraph_path_add(connectpt, name, &pconn))
+	return pconn;
+
+    pciio_info->c_vertex = pconn;
+    pciio_info_set(pconn, pciio_info);
+#ifdef DEBUG_PCIIO
+    {
+	int pos;
+	char dname[256];
+	pos = devfs_generate_path(pconn, dname, 256);
+	printk("%s : pconn path= %s \n", __FUNCTION__, &dname[pos]);
+    }
+#endif /* DEBUG_PCIIO */
+
+    /*
+     * create link to our pci provider
+     */
+
+    device_master_set(pconn, pciio_info->c_master);
+
+#if USRPCI
+    /*
+     * Call into usrpci provider to let it initialize for
+     * the given slot.
+     */
+    if (pciio_info->c_slot != PCIIO_SLOT_NONE)
+	usrpci_device_register(pconn, pciio_info->c_master, pciio_info->c_slot);
+#endif
+
+    return pconn;
+}
+
+void
+pciio_device_info_unregister(devfs_handle_t connectpt,
+			     pciio_info_t pciio_info)
+{
+    char		name[32];
+    devfs_handle_t	pconn;
+
+    if (!pciio_info)
+	return;
+
+    pciio_slot_func_to_name(name,
+			    pciio_info->c_slot,
+			    pciio_info->c_func);
+
+    hwgraph_edge_remove(connectpt,name,&pconn);
+    pciio_info_set(pconn,0);
+
+    /* Remove the link to our pci provider */
+    hwgraph_edge_remove(pconn, EDGE_LBL_MASTER, NULL);
+
+
+    hwgraph_vertex_unref(pconn);
+    hwgraph_vertex_destroy(pconn);
+    
+}
+/* Add the pci card inventory information to the hwgraph
+ */
+static void
+pciio_device_inventory_add(devfs_handle_t pconn_vhdl)
+{
+    pciio_info_t	pciio_info = pciio_info_get(pconn_vhdl);
+
+    ASSERT(pciio_info);
+    ASSERT(pciio_info->c_vertex == pconn_vhdl);
+
+    /* Donot add inventory  for non-existent devices */
+    if ((pciio_info->c_vendor == PCIIO_VENDOR_ID_NONE)	||
+	(pciio_info->c_device == PCIIO_DEVICE_ID_NONE))
+	return;
+    device_inventory_add(pconn_vhdl,INV_IOBD,INV_PCIADAP,
+			 pciio_info->c_vendor,pciio_info->c_device,
+			 pciio_info->c_slot);
+}
+
+/*ARGSUSED */
+int
+pciio_device_attach(devfs_handle_t pconn,
+		    int          drv_flags)
+{
+    pciio_info_t            pciio_info;
+    pciio_vendor_id_t       vendor_id;
+    pciio_device_id_t       device_id;
+
+
+    pciio_device_inventory_add(pconn);
+    pciio_info = pciio_info_get(pconn);
+
+    vendor_id = pciio_info->c_vendor;
+    device_id = pciio_info->c_device;
+
+    /* we don't start attaching things until
+     * all the driver init routines (including
+     * pciio_init) have been called; so we
+     * can assume here that we have a registry.
+     */
+    ASSERT(pciio_registry != NULL);
+
+    return(cdl_add_connpt(pciio_registry, vendor_id, device_id, pconn, drv_flags));
+}
+
+int
+pciio_device_detach(devfs_handle_t pconn,
+		    int          drv_flags)
+{
+    pciio_info_t            pciio_info;
+    pciio_vendor_id_t       vendor_id;
+    pciio_device_id_t       device_id;
+
+    pciio_info = pciio_info_get(pconn);
+
+    vendor_id = pciio_info->c_vendor;
+    device_id = pciio_info->c_device;
+
+    /* we don't start attaching things until
+     * all the driver init routines (including
+     * pciio_init) have been called; so we
+     * can assume here that we have a registry.
+     */
+    ASSERT(pciio_registry != NULL);
+
+    return(cdl_del_connpt(pciio_registry, vendor_id, device_id,
+		          pconn, drv_flags));
+
+}
+
+/* SN2 */
+/*
+ * Allocate (if necessary) and initialize a PCI window mapping structure.
+ */
+pciio_win_map_t
+pciio_device_win_map_new(pciio_win_map_t win_map,
+			 size_t region_size,
+			 size_t page_size)
+{
+	ASSERT((page_size & (page_size - 1)) == 0);
+	ASSERT((region_size & (page_size - 1)) == 0);
+
+	if (win_map == NULL)
+		NEW(win_map);
+
+	/*
+	 * The map array tracks the free ``pages'' in the region.  The worst
+	 * case scenario is when every other page in the region is free --
+	 * e.i. maximum fragmentation.  This leads to (max pages + 1) / 2 + 1
+	 * map entries.  The first "+1" handles the divide by 2 rounding; the
+	 * second handles the need for an end marker sentinel.
+	 */
+	win_map->wm_map = rmallocmap((region_size / page_size + 1) / 2 + 1);
+	win_map->wm_page_size = page_size;
+	ASSERT(win_map->wm_map != NULL);
+
+	return win_map;
+}
+
+/*
+ * Free resources associated with a PCI window mapping structure.
+ */
+extern void
+pciio_device_win_map_free(pciio_win_map_t win_map)
+{
+	rmfreemap(win_map->wm_map);
+	bzero(win_map, sizeof *win_map);
+}
+
+/*
+ * Populate window map with specified free range.
+ */
+void
+pciio_device_win_populate(pciio_win_map_t win_map,
+                          iopaddr_t ioaddr,
+                          size_t size)
+{
+	ASSERT((size & (win_map->wm_page_size - 1)) == 0);
+	ASSERT((ioaddr & (win_map->wm_page_size - 1)) == 0);
+
+	rmfree(win_map->wm_map,
+	       size / win_map->wm_page_size,
+	       (unsigned long)ioaddr / win_map->wm_page_size);
+	       
+}
+/*
+ * Allocate space from the specified PCI window mapping resource.  On
+ * success record information about the allocation in the supplied window
+ * allocation cookie (if non-NULL) and return the address of the allocated
+ * window.  On failure return NULL.
+ *
+ * The "size" parameter is usually from a PCI device's Base Address Register
+ * (BAR) decoder.  As such, the allocation must be aligned to be a multiple of
+ * that.  The "align" parameter acts as a ``minimum alignment'' allocation
+ * constraint.  The alignment contraint reflects system or device addressing
+ * restrictions such as the inability to share higher level ``windows''
+ * between devices, etc.  The returned PCI address allocation will be a
+ * multiple of the alignment constraint both in alignment and size.  Thus, the
+ * returned PCI address block is aligned to the maximum of the requested size
+ * and alignment.
+ */
+iopaddr_t
+pciio_device_win_alloc(pciio_win_map_t win_map,
+		       pciio_win_alloc_t win_alloc,
+		       size_t size, size_t align)
+{
+	unsigned long base;
+
+#ifdef PIC_LATER
+	ASSERT((size & (size - 1)) == 0);
+	ASSERT((align & (align - 1)) == 0);
+
+	/*
+	 * Convert size and alignment to pages.  If size is greated than the
+	 * requested alignment, we bump the alignment up to size; otherwise
+	 * convert the size into a multiple of the alignment request.
+	 */
+	size = (size + win_map->wm_page_size - 1) / win_map->wm_page_size;
+	align = align / win_map->wm_page_size;
+	if (size > align)
+		align = size;
+	else
+		size = (size + align - 1) & ~(align - 1);
+
+	/* XXXX */
+	base = rmalloc_align(win_map->wm_map, size, align, VM_NOSLEEP);
+	if (base == RMALLOC_FAIL)
+		return((iopaddr_t)NULL);
+#else
+    int                 index_page, index_page_align;
+    int                 align_pages, size_pages;
+    int                 alloc_pages, free_pages;
+    int                 addr_align;
+
+    /* Convert PCI bus alignment from bytes to pages */
+    align_pages = align / win_map->wm_page_size;
+
+    /* Convert PCI request from bytes to pages */
+    size_pages = (size / win_map->wm_page_size) +
+                  ((size % win_map->wm_page_size) ? 1 : 0);
+
+    /* Align address with the larger of the size or the requested slot align */
+    if (size_pages > align_pages)
+        align_pages = size_pages;
+  
+    /*
+     * Avoid wasting space by aligning - 1; this will prevent crossing
+     * another alignment boundary.
+     */
+    alloc_pages = size_pages + (align_pages - 1);
+
+    /* Allocate PCI bus space in pages */
+    index_page = (int) rmalloc(win_map->wm_map,
+                               (size_t) alloc_pages);
+
+    /* Error if no PCI bus address space available */
+    if (!index_page)
+        return 0;
+
+    /* PCI bus address index starts at 0 */
+    index_page--;
+
+    /* Align the page offset as requested */
+    index_page_align = (index_page + (align_pages - 1)) -
+                       ((index_page + (align_pages - 1)) % align_pages);
+
+    free_pages = (align_pages - 1) - (index_page_align - index_page);
+
+    /* Free unused PCI bus pages adjusting the index to start at 1 */
+    rmfree(win_map->wm_map, 
+           free_pages,
+           (index_page_align + 1) + size_pages);
+
+    /* Return aligned PCI bus space in bytes */ 
+    addr_align = (index_page_align * win_map->wm_page_size); 
+    base = index_page;
+    size = alloc_pages - free_pages;
+#endif	/* PIC_LATER */
+
+	/*
+	 * If a window allocation cookie has been supplied, use it to keep
+	 * track of all the allocated space assigned to this window.
+	 */
+	if (win_alloc) {
+		win_alloc->wa_map = win_map;
+		win_alloc->wa_base = base;
+		win_alloc->wa_pages = size;
+	}
+
+	return base * win_map->wm_page_size;
+}
+
+/*
+ * Free the specified window allocation back into the PCI window mapping
+ * resource.  As noted above, we keep page addresses offset by 1 ...
+ */
+void
+pciio_device_win_free(pciio_win_alloc_t win_alloc)
+{
+	if (win_alloc->wa_pages)
+		rmfree(win_alloc->wa_map->wm_map,
+		       win_alloc->wa_pages,
+		       win_alloc->wa_base);
+}
+
+/*
+ * pciio_error_register:
+ * arrange for a function to be called with
+ * a specified first parameter plus other
+ * information when an error is encountered
+ * and traced to the pci slot corresponding
+ * to the connection point pconn.
+ *
+ * may also be called with a null function
+ * pointer to "unregister" the error handler.
+ *
+ * NOTE: subsequent calls silently overwrite
+ * previous data for this vertex. We assume that
+ * cooperating drivers, well, cooperate ...
+ */
+void
+pciio_error_register(devfs_handle_t pconn,
+		     error_handler_f *efunc,
+		     error_handler_arg_t einfo)
+{
+    pciio_info_t            pciio_info;
+
+    pciio_info = pciio_info_get(pconn);
+    ASSERT(pciio_info != NULL);
+    pciio_info->c_efunc = efunc;
+    pciio_info->c_einfo = einfo;
+}
+
+/*
+ * Check if any device has been found in this slot, and return
+ * true or false
+ * vhdl is the vertex for the slot
+ */
+int
+pciio_slot_inuse(devfs_handle_t pconn_vhdl)
+{
+    pciio_info_t            pciio_info = pciio_info_get(pconn_vhdl);
+
+    ASSERT(pciio_info);
+    ASSERT(pciio_info->c_vertex == pconn_vhdl);
+    if (pciio_info->c_vendor) {
+	/*
+	 * Non-zero value for vendor indicate
+	 * a board being found in this slot.
+	 */
+	return 1;
+    }
+    return 0;
+}
+
+int
+pciio_dma_enabled(devfs_handle_t pconn_vhdl)
+{
+	return DEV_FUNC(pconn_vhdl, dma_enabled)(pconn_vhdl);
+}
+
+/*
+ * These are complementary Linux interfaces that takes in a pci_dev * as the 
+ * first arguement instead of devfs_handle_t.
+ */
+iopaddr_t               snia_pciio_dmatrans_addr(struct pci_dev *, device_desc_t, paddr_t, size_t, unsigned);
+pciio_dmamap_t          snia_pciio_dmamap_alloc(struct pci_dev *, device_desc_t, size_t, unsigned);
+void                    snia_pciio_dmamap_free(pciio_dmamap_t);
+iopaddr_t               snia_pciio_dmamap_addr(pciio_dmamap_t, paddr_t, size_t);
+void                    snia_pciio_dmamap_done(pciio_dmamap_t);
+pciio_endian_t          snia_pciio_endian_set(struct pci_dev *pci_dev, pciio_endian_t device_end,
+					      pciio_endian_t desired_end);
+
+#include <linux/module.h>
+EXPORT_SYMBOL(snia_pciio_dmatrans_addr);
+EXPORT_SYMBOL(snia_pciio_dmamap_alloc);
+EXPORT_SYMBOL(snia_pciio_dmamap_free);
+EXPORT_SYMBOL(snia_pciio_dmamap_addr);
+EXPORT_SYMBOL(snia_pciio_dmamap_done);
+EXPORT_SYMBOL(snia_pciio_endian_set);
+
+int
+snia_pcibr_rrb_alloc(struct pci_dev *pci_dev,
+	int *count_vchan0,
+	int *count_vchan1)
+{
+	devfs_handle_t dev = PCIDEV_VERTEX(pci_dev);
+
+	return pcibr_rrb_alloc(dev, count_vchan0, count_vchan1);
+}
+EXPORT_SYMBOL(snia_pcibr_rrb_alloc);
+
+pciio_endian_t
+snia_pciio_endian_set(struct pci_dev *pci_dev,
+	pciio_endian_t device_end,
+	pciio_endian_t desired_end)
+{
+	devfs_handle_t dev = PCIDEV_VERTEX(pci_dev);
+	
+	return DEV_FUNC(dev, endian_set)
+		(dev, device_end, desired_end);
+}
+
+iopaddr_t
+snia_pciio_dmatrans_addr(struct pci_dev *pci_dev, /* translate for this device */
+                    device_desc_t dev_desc,     /* device descriptor */
+                    paddr_t paddr,      /* system physical address */
+                    size_t byte_count,  /* length */
+                    unsigned flags)
+{                                       /* defined in dma.h */
+
+    devfs_handle_t dev = PCIDEV_VERTEX(pci_dev);
+
+    return DEV_FUNC(dev, dmatrans_addr)
+        (dev, dev_desc, paddr, byte_count, flags);
+}
+
+pciio_dmamap_t
+snia_pciio_dmamap_alloc(struct pci_dev *pci_dev,  /* set up mappings for this device */
+                   device_desc_t dev_desc,      /* device descriptor */
+                   size_t byte_count_max,       /* max size of a mapping */
+                   unsigned flags)
+{                                       /* defined in dma.h */
+
+    devfs_handle_t dev = PCIDEV_VERTEX(pci_dev);
+
+    return (pciio_dmamap_t) DEV_FUNC(dev, dmamap_alloc)
+        (dev, dev_desc, byte_count_max, flags);
+}
+
+void
+snia_pciio_dmamap_free(pciio_dmamap_t pciio_dmamap)
+{
+    DMAMAP_FUNC(pciio_dmamap, dmamap_free)
+        (CAST_DMAMAP(pciio_dmamap));
+}
+
+iopaddr_t
+snia_pciio_dmamap_addr(pciio_dmamap_t pciio_dmamap,  /* use these mapping resources */
+                  paddr_t paddr,        /* map for this address */
+                  size_t byte_count)
+{                                       /* map this many bytes */
+    return DMAMAP_FUNC(pciio_dmamap, dmamap_addr)
+        (CAST_DMAMAP(pciio_dmamap), paddr, byte_count);
+}
+
+void
+snia_pciio_dmamap_done(pciio_dmamap_t pciio_dmamap)
+{
+    DMAMAP_FUNC(pciio_dmamap, dmamap_done)
+        (CAST_DMAMAP(pciio_dmamap));
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn1/sgi_io_init.c linux-2.4.21-pre6/arch/ia64/sn/io/sn1/sgi_io_init.c
--- linux-2.4.20/arch/ia64/sn/io/sn1/sgi_io_init.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn1/sgi_io_init.c	2003-03-26 23:49:50.000000000 +0000
@@ -0,0 +1,324 @@
+/* $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) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#include <linux/types.h>
+#include <linux/config.h>
+#include <linux/slab.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/io.h>
+#include <asm/sn/sn_cpuid.h>
+#include <asm/sn/klconfig.h>
+#include <asm/sn/sn_private.h>
+#include <asm/sn/pci/pciba.h>
+#include <linux/smp.h>
+
+extern void mlreset(int );
+extern int init_hcl(void);
+extern void klgraph_hack_init(void);
+extern void hubspc_init(void);
+extern void pciio_init(void);
+extern void pcibr_init(void);
+extern void xtalk_init(void);
+extern void xbow_init(void);
+extern void xbmon_init(void);
+extern void pciiox_init(void);
+extern void usrpci_init(void);
+extern void ioc3_init(void);
+extern void initialize_io(void);
+extern void intr_clear_all(nasid_t);
+extern void klhwg_add_all_modules(devfs_handle_t);
+extern void klhwg_add_all_nodes(devfs_handle_t);
+
+void sn_mp_setup(void);
+extern devfs_handle_t hwgraph_root;
+extern void io_module_init(void);
+extern void pci_bus_cvlink_init(void);
+extern void temp_hack(void);
+
+extern int pci_bus_to_hcl_cvlink(void);
+
+/* #define DEBUG_IO_INIT 1 */
+#ifdef DEBUG_IO_INIT
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif /* DEBUG_IO_INIT */
+
+/*
+ * per_hub_init
+ *
+ * 	This code is executed once for each Hub chip.
+ */
+static void
+per_hub_init(cnodeid_t cnode)
+{
+	nasid_t		nasid;
+	nodepda_t	*npdap;
+	ii_icmr_u_t	ii_icmr;
+	ii_ibcr_u_t	ii_ibcr;
+
+	nasid = COMPACT_TO_NASID_NODEID(cnode);
+
+	ASSERT(nasid != INVALID_NASID);
+	ASSERT(NASID_TO_COMPACT_NODEID(nasid) == cnode);
+
+	npdap = NODEPDA(cnode);
+
+	/* initialize per-node synergy perf instrumentation */
+	npdap->synergy_perf_enabled = 0; /* off by default */
+	npdap->synergy_perf_lock = SPIN_LOCK_UNLOCKED;
+	npdap->synergy_perf_freq = SYNERGY_PERF_FREQ_DEFAULT;
+	npdap->synergy_inactive_intervals = 0;
+	npdap->synergy_active_intervals = 0;
+	npdap->synergy_perf_data = NULL;
+	npdap->synergy_perf_first = NULL;
+
+
+	/*
+	 * Set the total number of CRBs that can be used.
+	 */
+	ii_icmr.ii_icmr_regval= 0x0;
+	ii_icmr.ii_icmr_fld_s.i_c_cnt = 0xF;
+	REMOTE_HUB_S(nasid, IIO_ICMR, ii_icmr.ii_icmr_regval);
+
+	/*
+	 * Set the number of CRBs that both of the BTEs combined
+	 * can use minus 1.
+	 */
+	ii_ibcr.ii_ibcr_regval= 0x0;
+	ii_ibcr.ii_ibcr_fld_s.i_count = 0x8;
+	REMOTE_HUB_S(nasid, IIO_IBCR, ii_ibcr.ii_ibcr_regval);
+
+	/*
+	 * Set CRB timeout to be 10ms.
+	 */
+	REMOTE_HUB_S(nasid, IIO_ICTP, 0x1000 );
+	REMOTE_HUB_S(nasid, IIO_ICTO, 0xff);
+
+
+	/* Reserve all of the hardwired interrupt levels. */
+	intr_reserve_hardwired(cnode);
+
+	/* Initialize error interrupts for this hub. */
+	hub_error_init(cnode);
+}
+
+/*
+ * This routine is responsible for the setup of all the IRIX hwgraph style
+ * stuff that's been pulled into linux.  It's called by sn_pci_find_bios which
+ * is called just before the generic Linux PCI layer does its probing (by 
+ * platform_pci_fixup aka sn_pci_fixup).
+ *
+ * It is very IMPORTANT that this call is only made by the Master CPU!
+ *
+ */
+
+void
+sgi_master_io_infr_init(void)
+{
+	int cnode;
+
+	/*
+	 * Do any early init stuff .. einit_tbl[] etc.
+	 */
+	DBG("--> sgi_master_io_infr_init: calling init_hcl().\n");
+	init_hcl(); /* Sets up the hwgraph compatibility layer with devfs */
+
+#ifdef Colin
+
+printk("Testing out Xbridge Access .. if it hangs Xbridge is not init yet.\n");
+printk("	Reading Xbridge WID at address 0xc00000080f000000 0x%p\n", (* (volatile uint32_t *)(0xc00000080f000000)));
+
+printk("Testing out PCI Address Space Accesses\n");
+printk("	Testing PCI Config Read Byte: address 0xc00000080f020000 value 0x%x\n",(* (volatile uint8_t *)(0xc00000080f020000)));
+
+printk("	Testing PCI Config Read Byte: address 0xc00000080f020001 value 0x%x\n",(* (volatile uint8_t *)(0xc00000080f020001)));
+
+printk("	Testing PCI Config Read Byte: address 0xc00000080f020002 value 0x%x\n",(* (volatile uint8_t *)(0xc00000080f020002)));
+
+printk("	Testing PCI Config Read Byte: address 0xc00000080f020003 value 0x%x\n",(* (volatile uint8_t *)(0xc00000080f020003)));
+
+printk("        Testing PCI Config Read Byte: address 0xc00000080f020004 value 0x%x\n",(* (volatile uint8_t *)(0xc00000080f020004)));
+
+printk("        Testing PCI Config Read Byte: address 0xc00000080f020005 value 0x%x\n",(* (volatile uint8_t *)(0xc00000080f020005)));
+
+printk("        Testing PCI Config Read Byte: address 0xc00000080f020006 value 0x%x\n",(* (volatile uint8_t *)(0xc00000080f020006)));
+
+printk("        Testing PCI Config Read Byte: address 0xc00000080f020007 value 0x%x\n",(* (volatile uint8_t *)(0xc00000080f020007)));
+
+printk("	Testing PCI Config Word: address 0xc00000080f020004 value 0x%x\n",(* (volatile uint32_t *)(0xc00000080f020004)));
+
+printk("	Testing PCI Config Word: address 0xc00000080f020008 value 0x%x\n",(* (volatile uint32_t *)(0xc00000080f020008)));
+
+#endif
+
+	/*
+	 * initialize the Linux PCI to xwidget vertexes ..
+	 */
+	DBG("--> sgi_master_io_infr_init: calling pci_bus_cvlink_init().\n");
+	pci_bus_cvlink_init();
+
+#ifdef BRINGUP
+	/*
+	 * Hack to provide statically initialzed klgraph entries.
+	 */
+	DBG("--> sgi_master_io_infr_init: calling klgraph_hack_init()\n");
+	klgraph_hack_init();
+#endif /* BRINGUP */
+
+	/*
+	 * This is the Master CPU.  Emulate mlsetup and main.c in Irix.
+	 */
+	DBG("--> sgi_master_io_infr_init: calling mlreset(0).\n");
+	mlreset(0); /* Master .. */
+
+	/*
+	 * allowboot() is called by kern/os/main.c in main()
+	 * Emulate allowboot() ...
+	 *   per_cpu_init() - only need per_hub_init()
+	 *   cpu_io_setup() - Nothing to do.
+	 * 
+	 */
+	DBG("--> sgi_master_io_infr_init: calling sn_mp_setup().\n");
+	sn_mp_setup();
+
+	DBG("--> sgi_master_io_infr_init: calling per_hub_init(0).\n");
+	for (cnode = 0; cnode < numnodes; cnode++) {
+		per_hub_init(cnode);
+	}
+
+	/* We can do headless hub cnodes here .. */
+
+	/*
+	 * io_init[] stuff.
+	 *
+	 * Get SGI IO Infrastructure drivers to init and register with 
+	 * each other etc.
+	 */
+
+	DBG("--> sgi_master_io_infr_init: calling hubspc_init()\n");
+	hubspc_init();
+
+	DBG("--> sgi_master_io_infr_init: calling pciio_init()\n");
+	pciio_init();
+
+	DBG("--> sgi_master_io_infr_init: calling pcibr_init()\n");
+	pcibr_init();
+
+	DBG("--> sgi_master_io_infr_init: calling xtalk_init()\n");
+	xtalk_init();
+
+	DBG("--> sgi_master_io_infr_init: calling xbow_init()\n");
+	xbow_init();
+
+	DBG("--> sgi_master_io_infr_init: calling xbmon_init()\n");
+	xbmon_init();
+
+	DBG("--> sgi_master_io_infr_init: calling pciiox_init()\n");
+	pciiox_init();
+
+	DBG("--> sgi_master_io_infr_init: calling usrpci_init()\n");
+	usrpci_init();
+
+	DBG("--> sgi_master_io_infr_init: calling ioc3_init()\n");
+	ioc3_init();
+
+	/*
+	 *
+	 * Our IO Infrastructure drivers are in place .. 
+	 * Initialize the whole IO Infrastructure .. xwidget/device probes.
+	 *
+	 */
+	DBG("--> sgi_master_io_infr_init: Start Probe and IO Initialization\n");
+	initialize_io();
+
+	DBG("--> sgi_master_io_infr_init: Setting up SGI IO Links for Linux PCI\n");
+	pci_bus_to_hcl_cvlink();
+
+#ifdef CONFIG_PCIBA
+	DBG("--> sgi_master_io_infr_init: calling pciba_init()\n");
+ 	pciba_init();
+#endif
+
+	DBG("--> Leave sgi_master_io_infr_init: DONE setting up SGI Links for PCI\n");
+}
+
+/*
+ * sgi_slave_io_infr_init - This routine must be called on all cpus except 
+ * the Master CPU.
+ */
+void
+sgi_slave_io_infr_init(void)
+{
+	/* Emulate cboot() .. */
+	mlreset(1); /* This is a slave cpu */
+
+	// per_hub_init(0); /* Need to get and send in actual cnode number */
+
+	/* Done */
+}
+
+/*
+ * One-time setup for MP SN.
+ * Allocate per-node data, slurp prom klconfig information and
+ * convert it to hwgraph information.
+ */
+void
+sn_mp_setup(void)
+{
+	cnodeid_t	cnode;
+	cpuid_t		cpu;
+
+	for (cpu = 0; cpu < smp_num_cpus; cpu++) {
+		/* Skip holes in CPU space */
+		if (cpu_enabled(cpu)) {
+			init_platform_pda(cpu);
+		}
+	}
+
+	/*
+	 * Initialize platform-dependent vertices in the hwgraph:
+	 *	module
+	 *	node
+	 *	cpu
+	 *	memory
+	 *	slot
+	 *	hub
+	 *	router
+	 *	xbow
+	 */
+
+	DBG("sn_mp_io_setup: calling io_module_init()\n");
+	io_module_init(); /* Use to be called module_init() .. */
+
+	DBG("sn_mp_setup: calling klhwg_add_all_modules()\n");
+	klhwg_add_all_modules(hwgraph_root);
+	DBG("sn_mp_setup: calling klhwg_add_all_nodes()\n");
+	klhwg_add_all_nodes(hwgraph_root);
+
+
+	for (cnode = 0; cnode < numnodes; cnode++) {
+
+		/*
+		 * This routine clears the Hub's Interrupt registers.
+		 */
+		/*
+		 * We need to move this intr_clear_all() routine 
+		 * from SN/intr.c to a more appropriate file.
+		 * Talk to Al Mayer.
+		 */
+                intr_clear_all(COMPACT_TO_NASID_NODEID(cnode));
+		/* now init the hub */
+	//	per_hub_init(cnode);
+
+	}
+
+	synergy_perf_init();
+
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn1/xbow.c linux-2.4.21-pre6/arch/ia64/sn/io/sn1/xbow.c
--- linux-2.4.20/arch/ia64/sn/io/sn1/xbow.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn1/xbow.c	2003-03-26 23:49:38.000000000 +0000
@@ -0,0 +1,1086 @@
+/* $Id: xbow.c,v 1.3 2002/11/21 17:51:57 jh 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) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/hack.h>
+#include <asm/sn/pci/bridge.h>
+#include <asm/sn/xtalk/xtalk_private.h>
+#include <asm/sn/simulator.h>
+
+/* #define DEBUG		1 */
+/* #define XBOW_DEBUG	1 */
+
+
+/*
+ * Files needed to get the device driver entry points
+ */
+
+#include <asm/sn/xtalk/xbow.h>
+#include <asm/sn/xtalk/xtalk.h>
+#include <asm/sn/xtalk/xswitch.h>
+#include <asm/sn/xtalk/xwidget.h>
+
+#include <asm/sn/prio.h>
+#include <asm/sn/hcl_util.h>
+
+
+#define NEW(ptr)	(ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL))
+#define DEL(ptr)	(kfree(ptr))
+
+int                     xbow_devflag = D_MP;
+
+/*
+ * This file supports the Xbow chip.  Main functions: initializtion,
+ * error handling, and GBR.
+ */
+
+/*
+ * each vertex corresponding to an xbow chip
+ * has a "fastinfo" pointer pointing at one
+ * of these things.
+ */
+typedef struct xbow_soft_s *xbow_soft_t;
+
+struct xbow_soft_s {
+    devfs_handle_t            conn;	/* our connection point */
+    devfs_handle_t            vhdl;	/* xbow's private vertex */
+    devfs_handle_t            busv;	/* the xswitch vertex */
+    xbow_t                 *base;	/* PIO pointer to crossbow chip */
+    char                   *name;	/* hwgraph name */
+
+    xbow_perf_t             xbow_perfcnt[XBOW_PERF_COUNTERS];
+    xbow_perf_link_t        xbow_perflink[MAX_XBOW_PORTS];
+    xbow_link_status_t      xbow_link_status[MAX_XBOW_PORTS];
+    spinlock_t              xbow_perf_lock;
+    int                     link_monitor;
+    widget_cfg_t	   *wpio[MAX_XBOW_PORTS];	/* cached PIO pointer */
+
+    /* Bandwidth allocation state. Bandwidth values are for the
+     * destination port since contention happens there.
+     * Implicit mapping from xbow ports (8..f) -> (0..7) array indices.
+     */
+    spinlock_t		    xbow_bw_alloc_lock;		/* bw allocation lock */
+    unsigned long long	    bw_hiwm[MAX_XBOW_PORTS];	/* hiwater mark values */
+    unsigned long long      bw_cur_used[MAX_XBOW_PORTS]; /* bw used currently */
+};
+
+#define xbow_soft_set(v,i)	hwgraph_fastinfo_set((v), (arbitrary_info_t)(i))
+#define xbow_soft_get(v)	((xbow_soft_t)hwgraph_fastinfo_get((v)))
+
+/*
+ * Function Table of Contents
+ */
+
+void                    xbow_mlreset(xbow_t *);
+void                    xbow_init(void);
+int                     xbow_attach(devfs_handle_t);
+
+int                     xbow_open(devfs_handle_t *, int, int, cred_t *);
+int                     xbow_close(devfs_handle_t, int, int, cred_t *);
+
+int                     xbow_map(devfs_handle_t, vhandl_t *, off_t, size_t, uint);
+int                     xbow_unmap(devfs_handle_t, vhandl_t *);
+int                     xbow_ioctl(devfs_handle_t, int, void *, int, struct cred *, int *);
+
+int                     xbow_widget_present(xbow_t *, int);
+static int              xbow_link_alive(xbow_t *, int);
+devfs_handle_t            xbow_widget_lookup(devfs_handle_t, int);
+
+void                    xbow_intr_preset(void *, int, xwidgetnum_t, iopaddr_t, xtalk_intr_vector_t);
+
+
+
+void                    xbow_update_perf_counters(devfs_handle_t);
+xbow_perf_link_t       *xbow_get_perf_counters(devfs_handle_t);
+int                     xbow_enable_perf_counter(devfs_handle_t, int, int, int);
+xbow_link_status_t     *xbow_get_llp_status(devfs_handle_t);
+void                    xbow_update_llp_status(devfs_handle_t);
+
+int                     xbow_disable_llp_monitor(devfs_handle_t);
+int                     xbow_enable_llp_monitor(devfs_handle_t);
+int                     xbow_prio_bw_alloc(devfs_handle_t, xwidgetnum_t, xwidgetnum_t,
+                                unsigned long long, unsigned long long);
+
+xswitch_reset_link_f    xbow_reset_link;
+
+void                    idbg_xbowregs(int64_t);
+
+xswitch_provider_t      xbow_provider =
+{
+    xbow_reset_link,
+};
+
+/*
+ *    xbow_mlreset: called at mlreset time if the
+ *      platform specific code determines that there is
+ *      a crossbow in a critical path that must be
+ *      functional before the driver would normally get
+ *      the device properly set up.
+ *
+ *      what do we need to do, that the boot prom can
+ *      not be counted on to have already done, that is
+ *      generic across all platforms using crossbows?
+ */
+/*ARGSUSED */
+void
+xbow_mlreset(xbow_t * xbow)
+{
+}
+
+/*
+ *    xbow_init: called with the rest of the device
+ *      driver XXX_init routines. This platform *might*
+ *      have a Crossbow chip, or even several, but it
+ *      might have none. Register with the crosstalk
+ *      generic provider so when we encounter the chip
+ *      the right magic happens.
+ */
+void
+xbow_init(void)
+{
+
+#if DEBUG && ATTACH_DEBUG
+    printk("xbow_init\n");
+#endif
+
+    xwidget_driver_register(PXBOW_WIDGET_PART_NUM,
+			    0, /* XXBOW_WIDGET_MFGR_NUM, */
+			    "xbow_",
+			    CDL_PRI_HI);	/* attach before friends */
+
+
+    xwidget_driver_register(XXBOW_WIDGET_PART_NUM,
+			    0, /* XXBOW_WIDGET_MFGR_NUM, */
+			    "xbow_",
+			    CDL_PRI_HI);	/* attach before friends */
+
+    xwidget_driver_register(XBOW_WIDGET_PART_NUM,
+			    XBOW_WIDGET_MFGR_NUM,
+			    "xbow_",
+			    CDL_PRI_HI);	/* attach before friends */
+}
+
+#ifdef XBRIDGE_REGS_SIM
+/*    xbow_set_simulated_regs: sets xbow regs as needed
+ *	for powering through the boot
+ */
+void
+xbow_set_simulated_regs(xbow_t *xbow, int port)
+{
+    /*
+     * turn on link
+     */
+    xbow->xb_link(port).link_status = (1<<31);
+    /*
+     * and give it a live widget too
+     */
+    xbow->xb_link(port).link_aux_status = XB_AUX_STAT_PRESENT;
+    /*
+     * zero the link control reg
+     */
+    xbow->xb_link(port).link_control = 0x0;
+}
+#endif /* XBRIDGE_REGS_SIM */
+
+/*
+ *    xbow_attach: the crosstalk provider has
+ *      determined that there is a crossbow widget
+ *      present, and has handed us the connection
+ *      point for that vertex.
+ *
+ *      We not only add our own vertex, but add
+ *      some "xtalk switch" data to the switch
+ *      vertex (at the connect point's parent) if
+ *      it does not have any.
+ */
+
+/*ARGSUSED */
+int
+xbow_attach(devfs_handle_t conn)
+{
+    /*REFERENCED */
+    devfs_handle_t            vhdl;
+    devfs_handle_t            busv;
+    xbow_t                 *xbow;
+    xbow_soft_t             soft;
+    int                     port;
+    xswitch_info_t          info;
+    char                    devnm[MAXDEVNAME], *s;
+    xbowreg_t               id;
+    int                     rev;
+    int			    i;
+    int			    xbow_num;
+	
+#if DEBUG && ATTACH_DEBUG
+#if defined(SUPPORT_PRINTING_V_FORMAT)
+    printk("%v: xbow_attach\n", conn);
+#else
+    printk("0x%x: xbow_attach\n", conn);
+#endif
+#endif
+
+    /*
+     * Get a PIO pointer to the base of the crossbow
+     * chip.
+     */
+#ifdef XBRIDGE_REGS_SIM
+    printk("xbow_attach: XBRIDGE_REGS_SIM FIXME: allocating %ld bytes for xbow_s\n", sizeof(xbow_t));
+    xbow = (xbow_t *) kmalloc(sizeof(xbow_t), GFP_KERNEL);
+    /*
+     * turn on ports e and f like in a real live ibrick
+     */
+    xbow_set_simulated_regs(xbow, 0xe);
+    xbow_set_simulated_regs(xbow, 0xf);
+#else
+    xbow = (xbow_t *) xtalk_piotrans_addr(conn, 0, 0, sizeof(xbow_t), 0);
+#endif /* XBRIDGE_REGS_SIM */
+
+    /*
+     * Locate the "switch" vertex: it is the parent
+     * of our connection point.
+     */
+    busv = hwgraph_connectpt_get(conn);
+#if DEBUG && ATTACH_DEBUG
+    printk("xbow_attach: Bus Vertex 0x%p, conn 0x%p, xbow register 0x%p wid= 0x%x\n", busv, conn, xbow, *(volatile u32 *)xbow);
+#endif
+
+    ASSERT(busv != GRAPH_VERTEX_NONE);
+
+    /*
+     * Create our private vertex, and connect our
+     * driver information to it. This makes it possible
+     * for diagnostic drivers to open the crossbow
+     * vertex for access to registers.
+     */
+
+    /*
+     * We need to teach xbow drivers to provide the right set of
+     * file ops.
+     */
+    vhdl = NULL;
+    vhdl = hwgraph_register(conn, EDGE_LBL_XBOW,
+                        0, DEVFS_FL_AUTO_DEVNUM,
+                        0, 0,
+                        S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0,
+                        /* &hcl_fops */ (void *)&vhdl, NULL);
+    if (!vhdl) {
+        printk(KERN_WARNING "xbow_attach: Unable to create char device for xbow conn %p\n",
+                (void *)conn);
+    }
+
+    /*
+     * Allocate the soft state structure and attach
+     * it to the xbow's vertex
+     */
+    NEW(soft);
+    soft->conn = conn;
+    soft->vhdl = vhdl;
+    soft->busv = busv;
+    soft->base = xbow;
+    /* does the universe really need another macro?  */
+    /* xbow_soft_set(vhdl, (arbitrary_info_t) soft); */
+    hwgraph_fastinfo_set(vhdl, (arbitrary_info_t) soft);
+
+#define XBOW_NUM_SUFFIX_FORMAT	"[xbow# %d]"
+
+    /* Add xbow number as a suffix to the hwgraph name of the xbow.
+     * This is helpful while looking at the error/warning messages.
+     */
+    xbow_num = 0;
+
+    /*
+     * get the name of this xbow vertex and keep the info.
+     * This is needed during errors and interupts, but as
+     * long as we have it, we can use it elsewhere.
+     */
+    s = dev_to_name(vhdl, devnm, MAXDEVNAME);
+    soft->name = kmalloc(strlen(s) + strlen(XBOW_NUM_SUFFIX_FORMAT) + 1, 
+			    GFP_KERNEL);
+    sprintf(soft->name,"%s"XBOW_NUM_SUFFIX_FORMAT, s,xbow_num);
+
+#ifdef XBRIDGE_REGS_SIM
+    /* my o200/ibrick has id=0x2d002049, but XXBOW_WIDGET_PART_NUM is defined
+     * as 0xd000, so I'm using that for the partnum bitfield.
+     */
+    printk("xbow_attach: XBRIDGE_REGS_SIM FIXME: need xb_wid_id value!!\n");
+    id = 0x2d000049;
+#else
+    id = xbow->xb_wid_id;
+#endif /* XBRIDGE_REGS_SIM */
+    rev = XWIDGET_PART_REV_NUM(id);
+
+    mutex_spinlock_init(&soft->xbow_perf_lock);
+    soft->xbow_perfcnt[0].xp_perf_reg = &xbow->xb_perf_ctr_a;
+    soft->xbow_perfcnt[1].xp_perf_reg = &xbow->xb_perf_ctr_b;
+
+    /* Initialization for GBR bw allocation */
+    mutex_spinlock_init(&soft->xbow_bw_alloc_lock);
+
+#define	XBOW_8_BIT_PORT_BW_MAX		(400 * 1000 * 1000)	/* 400 MB/s */
+#define XBOW_16_BIT_PORT_BW_MAX		(800 * 1000 * 1000)	/* 800 MB/s */
+
+    /* Set bandwidth hiwatermark and current values */
+    for (i = 0; i < MAX_XBOW_PORTS; i++) {
+	soft->bw_hiwm[i] = XBOW_16_BIT_PORT_BW_MAX;	/* for now */
+	soft->bw_cur_used[i] = 0;
+    }
+
+    /*
+     * Enable xbow error interrupts
+     */
+    xbow->xb_wid_control = (XB_WID_CTRL_REG_ACC_IE | XB_WID_CTRL_XTALK_IE);
+
+    /*
+     * take a census of the widgets present,
+     * leaving notes at the switch vertex.
+     */
+    info = xswitch_info_new(busv);
+
+    for (port = MAX_PORT_NUM - MAX_XBOW_PORTS;
+	 port < MAX_PORT_NUM; ++port) {
+	if (!xbow_link_alive(xbow, port)) {
+#if DEBUG && XBOW_DEBUG
+	    printk(KERN_INFO "0x%p link %d is not alive\n",
+		    busv, port);
+#endif
+	    continue;
+	}
+	if (!xbow_widget_present(xbow, port)) {
+#if DEBUG && XBOW_DEBUG
+	    printk(KERN_INFO "0x%p link %d is alive but no widget is present\n", busv, port);
+#endif
+	    continue;
+	}
+#if DEBUG && XBOW_DEBUG
+	printk(KERN_INFO "0x%p link %d has a widget\n",
+		busv, port);
+#endif
+
+	xswitch_info_link_is_ok(info, port);
+	/*
+	 * Turn some error interrupts on
+	 * and turn others off. The PROM has
+	 * some things turned on we don't
+	 * want to see (bandwidth allocation
+	 * errors for instance); so if it
+	 * is not listed here, it is not on.
+	 */
+	xbow->xb_link(port).link_control =
+	    ( (xbow->xb_link(port).link_control
+	/*
+	 * Turn off these bits; they are non-fatal,
+	 * but we might want to save some statistics
+	 * on the frequency of these errors.
+	 * XXX FIXME XXX
+	 */
+	    & ~XB_CTRL_RCV_CNT_OFLOW_IE
+	    & ~XB_CTRL_XMT_CNT_OFLOW_IE
+	    & ~XB_CTRL_BNDWDTH_ALLOC_IE
+	    & ~XB_CTRL_RCV_IE)
+	/*
+	 * These are the ones we want to turn on.
+	 */
+	    | (XB_CTRL_ILLEGAL_DST_IE
+	    | XB_CTRL_OALLOC_IBUF_IE
+	    | XB_CTRL_XMT_MAX_RTRY_IE
+	    | XB_CTRL_MAXREQ_TOUT_IE
+	    | XB_CTRL_XMT_RTRY_IE
+	    | XB_CTRL_SRC_TOUT_IE) );
+    }
+
+    xswitch_provider_register(busv, &xbow_provider);
+
+    return 0;				/* attach successful */
+}
+
+/*ARGSUSED */
+int
+xbow_open(devfs_handle_t *devp, int oflag, int otyp, cred_t *credp)
+{
+    return 0;
+
+}
+
+/*ARGSUSED */
+int
+xbow_close(devfs_handle_t dev, int oflag, int otyp, cred_t *crp)
+{
+    return 0;
+}
+
+/*ARGSUSED */
+int
+xbow_map(devfs_handle_t dev, vhandl_t *vt, off_t off, size_t len, uint prot)
+{
+    devfs_handle_t            vhdl = dev_to_vhdl(dev);
+    xbow_soft_t             soft = xbow_soft_get(vhdl);
+    int                     error;
+
+    ASSERT(soft);
+    len = ctob(btoc(len));
+    /* XXX- this ignores the offset!!! */
+    error = v_mapphys(vt, (void *) soft->base, len);
+    return error;
+}
+
+/*ARGSUSED */
+int
+xbow_unmap(devfs_handle_t dev, vhandl_t *vt)
+{
+    return 0;
+}
+
+/* This contains special-case code for grio. There are plans to make
+ * this general sometime in the future, but till then this should
+ * be good enough.
+ */
+xwidgetnum_t
+xbow_widget_num_get(devfs_handle_t dev)
+{
+	devfs_handle_t	tdev;
+	char		devname[MAXDEVNAME];
+	xwidget_info_t	xwidget_info;
+	int		i;
+
+	vertex_to_name(dev, devname, MAXDEVNAME);
+
+	/* If this is a pci controller vertex, traverse up using
+	 * the ".." links to get to the widget.
+	 */
+	if (strstr(devname, EDGE_LBL_PCI) &&
+			strstr(devname, EDGE_LBL_CONTROLLER)) {
+		tdev = dev;
+		for (i=0; i< 2; i++) {
+			if (hwgraph_edge_get(tdev,
+				HWGRAPH_EDGELBL_DOTDOT, &tdev) !=
+					GRAPH_SUCCESS)
+				return XWIDGET_NONE;
+		}
+
+		if ((xwidget_info = xwidget_info_chk(tdev)) != NULL) {
+			return (xwidget_info_id_get(xwidget_info));
+		} else {
+			return XWIDGET_NONE;
+		}
+	}
+
+	return XWIDGET_NONE;
+}
+
+int
+xbow_ioctl(devfs_handle_t dev,
+	   int cmd,
+	   void *arg,
+	   int flag,
+	   struct cred *cr,
+	   int *rvalp)
+{
+    devfs_handle_t            vhdl;
+    int                     error = 0;
+
+#if defined (DEBUG)
+    int                     rc;
+    devfs_handle_t            conn;
+    struct xwidget_info_s  *xwidget_info;
+    xbow_soft_t             xbow_soft;
+#endif
+    *rvalp = 0;
+
+    vhdl = dev_to_vhdl(dev);
+#if defined (DEBUG)
+    xbow_soft = xbow_soft_get(vhdl);
+    conn = xbow_soft->conn;
+
+    xwidget_info = xwidget_info_get(conn);
+    ASSERT_ALWAYS(xwidget_info != NULL);
+
+    rc = xwidget_hwid_is_xswitch(&xwidget_info->w_hwid);
+    ASSERT_ALWAYS(rc != 0);
+#endif
+    switch (cmd) {
+
+    case XBOWIOC_LLP_ERROR_ENABLE:
+	if ((error = xbow_enable_llp_monitor(vhdl)) != 0)
+	    error = EINVAL;
+
+	break;
+
+    case XBOWIOC_LLP_ERROR_DISABLE:
+
+	if ((error = xbow_disable_llp_monitor(vhdl)) != 0)
+	    error = EINVAL;
+
+	break;
+
+    default:
+	break;
+
+    }
+    return error;
+}
+
+/*
+ * xbow_widget_present: See if a device is present
+ * on the specified port of this crossbow.
+ */
+int
+xbow_widget_present(xbow_t *xbow, int port)
+{
+	if ( IS_RUNNING_ON_SIMULATOR() ) {
+		if ( (port == 14) || (port == 15) ) {
+			return 1;
+		}
+		else {
+			return 0;
+		}
+	}
+	else {
+		/* WAR: port 0xf on PIC is missing present bit */
+		/* Need this for PIC */
+		if (IS_PIC_XBOW(xbow->xb_wid_id) && port == 0xf) {
+			return 1;
+		}
+		return xbow->xb_link(port).link_aux_status & XB_AUX_STAT_PRESENT;
+	}
+}
+
+static int
+xbow_link_alive(xbow_t * xbow, int port)
+{
+    xbwX_stat_t             xbow_linkstat;
+
+    xbow_linkstat.linkstatus = xbow->xb_link(port).link_status;
+    return (xbow_linkstat.link_alive);
+}
+
+/*
+ * xbow_widget_lookup
+ *      Lookup the edges connected to the xbow specified, and
+ *      retrieve the handle corresponding to the widgetnum
+ *      specified.
+ *      If not found, return 0.
+ */
+devfs_handle_t
+xbow_widget_lookup(devfs_handle_t vhdl,
+		   int widgetnum)
+{
+    xswitch_info_t          xswitch_info;
+    devfs_handle_t            conn;
+
+    xswitch_info = xswitch_info_get(vhdl);
+    conn = xswitch_info_vhdl_get(xswitch_info, widgetnum);
+    return conn;
+}
+
+/*
+ * xbow_intr_preset: called during mlreset time
+ * if the platform specific code needs to route
+ * an xbow interrupt before the xtalk infrastructure
+ * is available for use.
+ *
+ * Also called from xbow_setwidint, so we don't
+ * replicate the guts of the routine.
+ *
+ * XXX- probably should be renamed xbow_wid_intr_set or
+ * something to reduce confusion.
+ */
+/*ARGSUSED3 */
+void
+xbow_intr_preset(void *which_widget,
+		 int which_widget_intr,
+		 xwidgetnum_t targ,
+		 iopaddr_t addr,
+		 xtalk_intr_vector_t vect)
+{
+    xbow_t                 *xbow = (xbow_t *) which_widget;
+
+    xbow->xb_wid_int_upper = ((0xFF000000 & (vect << 24)) |
+			      (0x000F0000 & (targ << 16)) |
+			      XTALK_ADDR_TO_UPPER(addr));
+    xbow->xb_wid_int_lower = XTALK_ADDR_TO_LOWER(addr);
+
+}
+
+int                     xbow_xmit_retry_errors = 0;
+
+int
+xbow_xmit_retry_error(xbow_soft_t soft,
+		      int port)
+{
+    xswitch_info_t          info;
+    devfs_handle_t            vhdl;
+    widget_cfg_t           *wid;
+    widgetreg_t             id;
+    int                     part;
+    int                     mfgr;
+
+    wid = soft->wpio[port - BASE_XBOW_PORT];
+    if (wid == NULL) {
+	/* If we can't track down a PIO
+	 * pointer to our widget yet,
+	 * leave our caller knowing that
+	 * we are interested in this
+	 * interrupt if it occurs in
+	 * the future.
+	 */
+	info = xswitch_info_get(soft->busv);
+	if (!info)
+	    return 1;
+	vhdl = xswitch_info_vhdl_get(info, port);
+	if (vhdl == GRAPH_VERTEX_NONE)
+	    return 1;
+	wid = (widget_cfg_t *) xtalk_piotrans_addr
+	    (vhdl, 0, 0, sizeof *wid, 0);
+	if (!wid)
+	    return 1;
+	soft->wpio[port - BASE_XBOW_PORT] = wid;
+    }
+    id = wid->w_id;
+    part = XWIDGET_PART_NUM(id);
+    mfgr = XWIDGET_MFG_NUM(id);
+
+    /* If this thing is not a Bridge,
+     * do not activate the WAR, and
+     * tell our caller we do not need
+     * to be called again.
+     */
+    if ((part != BRIDGE_WIDGET_PART_NUM) ||
+	(mfgr != BRIDGE_WIDGET_MFGR_NUM)) {
+		/* FIXME: add Xbridge to the WAR.
+		 * Shouldn't hurt anything.  Later need to
+		 * check if we can remove this.
+                 */
+    		if ((part != XBRIDGE_WIDGET_PART_NUM) ||
+		    (mfgr != XBRIDGE_WIDGET_MFGR_NUM))
+			return 0;
+    }
+
+    /* count how many times we
+     * have picked up after
+     * LLP Transmit problems.
+     */
+    xbow_xmit_retry_errors++;
+
+    /* rewrite the control register
+     * to fix things up.
+     */
+    wid->w_control = wid->w_control;
+    wid->w_control;
+
+    return 1;
+}
+
+void
+xbow_update_perf_counters(devfs_handle_t vhdl)
+{
+    xbow_soft_t             xbow_soft = xbow_soft_get(vhdl);
+    xbow_perf_t            *xbow_perf = xbow_soft->xbow_perfcnt;
+    xbow_perf_link_t       *xbow_plink = xbow_soft->xbow_perflink;
+    xbow_perfcount_t        perf_reg;
+    unsigned long           s;
+    int                     link, i;
+
+    for (i = 0; i < XBOW_PERF_COUNTERS; i++, xbow_perf++) {
+	if (xbow_perf->xp_mode == XBOW_MONITOR_NONE)
+	    continue;
+
+	s = mutex_spinlock(&xbow_soft->xbow_perf_lock);
+
+	perf_reg.xb_counter_val = *(xbowreg_t *) xbow_perf->xp_perf_reg;
+
+	link = perf_reg.xb_perf.link_select;
+
+	(xbow_plink + link)->xlp_cumulative[xbow_perf->xp_curmode] +=
+	    ((perf_reg.xb_perf.count - xbow_perf->xp_current) & XBOW_COUNTER_MASK);
+	xbow_perf->xp_current = perf_reg.xb_perf.count;
+
+	mutex_spinunlock(&xbow_soft->xbow_perf_lock, s);
+    }
+}
+
+xbow_perf_link_t       *
+xbow_get_perf_counters(devfs_handle_t vhdl)
+{
+    xbow_soft_t             xbow_soft = xbow_soft_get(vhdl);
+    xbow_perf_link_t       *xbow_perf_link = xbow_soft->xbow_perflink;
+
+    return xbow_perf_link;
+}
+
+int
+xbow_enable_perf_counter(devfs_handle_t vhdl, int link, int mode, int counter)
+{
+    xbow_soft_t             xbow_soft = xbow_soft_get(vhdl);
+    xbow_perf_t            *xbow_perf = xbow_soft->xbow_perfcnt;
+    xbow_linkctrl_t         xbow_link_ctrl;
+    xbow_t                 *xbow = xbow_soft->base;
+    xbow_perfcount_t        perf_reg;
+    unsigned long           s;
+    int                     i;
+
+    link -= BASE_XBOW_PORT;
+    if ((link < 0) || (link >= MAX_XBOW_PORTS))
+	return -1;
+
+    if ((mode < XBOW_MONITOR_NONE) || (mode > XBOW_MONITOR_DEST_LINK))
+	return -1;
+
+    if ((counter < 0) || (counter >= XBOW_PERF_COUNTERS))
+	return -1;
+
+    s = mutex_spinlock(&xbow_soft->xbow_perf_lock);
+
+    if ((xbow_perf + counter)->xp_mode && mode) {
+	mutex_spinunlock(&xbow_soft->xbow_perf_lock, s);
+	return -1;
+    }
+    for (i = 0; i < XBOW_PERF_COUNTERS; i++) {
+	if (i == counter)
+	    continue;
+	if (((xbow_perf + i)->xp_link == link) &&
+	    ((xbow_perf + i)->xp_mode)) {
+	    mutex_spinunlock(&xbow_soft->xbow_perf_lock, s);
+	    return -1;
+	}
+    }
+    xbow_perf += counter;
+
+    xbow_perf->xp_curlink = xbow_perf->xp_link = link;
+    xbow_perf->xp_curmode = xbow_perf->xp_mode = mode;
+
+    xbow_link_ctrl.xbl_ctrlword = xbow->xb_link_raw[link].link_control;
+    xbow_link_ctrl.xb_linkcontrol.perf_mode = mode;
+    xbow->xb_link_raw[link].link_control = xbow_link_ctrl.xbl_ctrlword;
+
+    perf_reg.xb_counter_val = *(xbowreg_t *) xbow_perf->xp_perf_reg;
+    perf_reg.xb_perf.link_select = link;
+    *(xbowreg_t *) xbow_perf->xp_perf_reg = perf_reg.xb_counter_val;
+    xbow_perf->xp_current = perf_reg.xb_perf.count;
+
+    mutex_spinunlock(&xbow_soft->xbow_perf_lock, s);
+    return 0;
+}
+
+xbow_link_status_t     *
+xbow_get_llp_status(devfs_handle_t vhdl)
+{
+    xbow_soft_t             xbow_soft = xbow_soft_get(vhdl);
+    xbow_link_status_t     *xbow_llp_status = xbow_soft->xbow_link_status;
+
+    return xbow_llp_status;
+}
+
+void
+xbow_update_llp_status(devfs_handle_t vhdl)
+{
+    xbow_soft_t             xbow_soft = xbow_soft_get(vhdl);
+    xbow_link_status_t     *xbow_llp_status = xbow_soft->xbow_link_status;
+    xbow_t                 *xbow;
+    xbwX_stat_t             lnk_sts;
+    xbow_aux_link_status_t  aux_sts;
+    int                     link;
+    devfs_handle_t	    xwidget_vhdl;
+    char		   *xwidget_name;	
+
+    xbow = (xbow_t *) xbow_soft->base;
+    for (link = 0; link < MAX_XBOW_PORTS; link++, xbow_llp_status++) {
+	/* Get the widget name corresponding the current link.
+	 * Note : 0 <= link < MAX_XBOW_PORTS(8).
+	 * 	  BASE_XBOW_PORT(0x8) <= xwidget number < MAX_PORT_NUM (0x10)
+	 */
+	xwidget_vhdl = xbow_widget_lookup(xbow_soft->busv,link+BASE_XBOW_PORT);
+	xwidget_name = xwidget_name_get(xwidget_vhdl);
+	aux_sts.aux_linkstatus
+	    = xbow->xb_link_raw[link].link_aux_status;
+	lnk_sts.linkstatus = xbow->xb_link_raw[link].link_status_clr;
+
+	if (lnk_sts.link_alive == 0)
+	    continue;
+
+	xbow_llp_status->rx_err_count +=
+	    aux_sts.xb_aux_linkstatus.rx_err_cnt;
+
+	xbow_llp_status->tx_retry_count +=
+	    aux_sts.xb_aux_linkstatus.tx_retry_cnt;
+
+	if (lnk_sts.linkstatus & ~(XB_STAT_RCV_ERR | XB_STAT_XMT_RTRY_ERR | XB_STAT_LINKALIVE)) {
+#ifdef	LATER
+	    printk(KERN_WARNING  "link %d[%s]: bad status 0x%x\n",
+		    link, xwidget_name, lnk_sts.linkstatus);
+#endif
+	}
+    }
+}
+
+int
+xbow_disable_llp_monitor(devfs_handle_t vhdl)
+{
+    xbow_soft_t             xbow_soft = xbow_soft_get(vhdl);
+    int                     port;
+
+    for (port = 0; port < MAX_XBOW_PORTS; port++) {
+	xbow_soft->xbow_link_status[port].rx_err_count = 0;
+	xbow_soft->xbow_link_status[port].tx_retry_count = 0;
+    }
+
+    xbow_soft->link_monitor = 0;
+    return 0;
+}
+
+int
+xbow_enable_llp_monitor(devfs_handle_t vhdl)
+{
+    xbow_soft_t             xbow_soft = xbow_soft_get(vhdl);
+
+    xbow_soft->link_monitor = 1;
+    return 0;
+}
+
+
+int
+xbow_reset_link(devfs_handle_t xconn_vhdl)
+{
+    xwidget_info_t          widget_info;
+    xwidgetnum_t            port;
+    xbow_t                 *xbow;
+    xbowreg_t               ctrl;
+    xbwX_stat_t             stat;
+    unsigned                itick;
+    unsigned                dtick;
+    static int              ticks_per_ms = 0;
+
+    if (!ticks_per_ms) {
+	itick = get_timestamp();
+	us_delay(1000);
+	ticks_per_ms = get_timestamp() - itick;
+    }
+    widget_info = xwidget_info_get(xconn_vhdl);
+    port = xwidget_info_id_get(widget_info);
+
+#ifdef XBOW_K1PTR			/* defined if we only have one xbow ... */
+    xbow = XBOW_K1PTR;
+#else
+    {
+	devfs_handle_t            xbow_vhdl;
+	xbow_soft_t             xbow_soft;
+
+	hwgraph_traverse(xconn_vhdl, ".master/xtalk/0/xbow", &xbow_vhdl);
+	xbow_soft = xbow_soft_get(xbow_vhdl);
+	xbow = xbow_soft->base;
+    }
+#endif
+
+    /*
+     * This requires three PIOs (reset the link, check for the
+     * reset, restore the control register for the link) plus
+     * 10us to wait for the reset. We allow up to 1ms for the
+     * widget to come out of reset before giving up and
+     * returning a failure.
+     */
+    ctrl = xbow->xb_link(port).link_control;
+    xbow->xb_link(port).link_reset = 0;
+    itick = get_timestamp();
+    while (1) {
+	stat.linkstatus = xbow->xb_link(port).link_status;
+	if (stat.link_alive)
+	    break;
+	dtick = get_timestamp() - itick;
+	if (dtick > ticks_per_ms) {
+	    return -1;			/* never came out of reset */
+	}
+	DELAY(2);			/* don't beat on link_status */
+    }
+    xbow->xb_link(port).link_control = ctrl;
+    return 0;
+}
+
+/*
+ * Dump xbow registers.
+ * input parameter is either a pointer to
+ * the xbow chip or the vertex handle for
+ * an xbow vertex.
+ */
+void
+idbg_xbowregs(int64_t regs)
+{
+    xbow_t                 *xbow;
+    int                     i;
+    xb_linkregs_t          *link;
+
+    xbow = (xbow_t *) regs;
+
+#ifdef LATER
+    qprintf("Printing xbow registers starting at 0x%x\n", xbow);
+    qprintf("wid %x status %x erruppr %x errlower %x control %x timeout %x\n",
+	    xbow->xb_wid_id, xbow->xb_wid_stat, xbow->xb_wid_err_upper,
+	    xbow->xb_wid_err_lower, xbow->xb_wid_control,
+	    xbow->xb_wid_req_timeout);
+    qprintf("intr uppr %x lower %x errcmd %x llp ctrl %x arb_reload %x\n",
+	    xbow->xb_wid_int_upper, xbow->xb_wid_int_lower,
+	    xbow->xb_wid_err_cmdword, xbow->xb_wid_llp,
+	    xbow->xb_wid_arb_reload);
+#endif
+
+    for (i = 8; i <= 0xf; i++) {
+	link = &xbow->xb_link(i);
+#ifdef LATER
+	qprintf("Link %d registers\n", i);
+	qprintf("\tctrl %x stat %x arbuppr %x arblowr %x auxstat %x\n",
+		link->link_control, link->link_status,
+		link->link_arb_upper, link->link_arb_lower,
+		link->link_aux_status);
+#endif
+    }
+}
+
+
+#define XBOW_ARB_RELOAD_TICKS		25
+					/* granularity: 4 MB/s, max: 124 MB/s */
+#define GRANULARITY			((100 * 1000000) / XBOW_ARB_RELOAD_TICKS)
+
+#define XBOW_BYTES_TO_GBR(BYTES_per_s)	(int) (BYTES_per_s / GRANULARITY)
+
+#define XBOW_GBR_TO_BYTES(cnt)		(bandwidth_t) ((cnt) * GRANULARITY)
+
+#define CEILING_BYTES_TO_GBR(gbr, bytes_per_sec)	\
+			((XBOW_GBR_TO_BYTES(gbr) < bytes_per_sec) ? gbr+1 : gbr)
+
+#define XBOW_ARB_GBR_MAX		31
+
+#define ABS(x)				((x > 0) ? (x) : (-1 * x))
+					/* absolute value */
+
+int
+xbow_bytes_to_gbr(bandwidth_t old_bytes_per_sec, bandwidth_t bytes_per_sec)
+{
+    int                     gbr_granted;
+    int                     new_total_gbr;
+    int                     change_gbr;
+    bandwidth_t             new_total_bw;
+
+#ifdef GRIO_DEBUG
+    printk("xbow_bytes_to_gbr: old_bytes_per_sec %lld bytes_per_sec %lld\n",
+		old_bytes_per_sec, bytes_per_sec);
+#endif	/* GRIO_DEBUG */
+
+    gbr_granted = CEILING_BYTES_TO_GBR((XBOW_BYTES_TO_GBR(old_bytes_per_sec)),
+			old_bytes_per_sec);
+    new_total_bw = old_bytes_per_sec + bytes_per_sec;
+    new_total_gbr = CEILING_BYTES_TO_GBR((XBOW_BYTES_TO_GBR(new_total_bw)),
+			new_total_bw);
+
+    change_gbr = new_total_gbr - gbr_granted;
+
+#ifdef GRIO_DEBUG
+    printk("xbow_bytes_to_gbr: gbr_granted %d new_total_gbr %d change_gbr %d\n",
+		gbr_granted, new_total_gbr, change_gbr);
+#endif	/* GRIO_DEBUG */
+
+    return (change_gbr);
+}
+
+/* Conversion from GBR to bytes */
+bandwidth_t
+xbow_gbr_to_bytes(int gbr)
+{
+    return (XBOW_GBR_TO_BYTES(gbr));
+}
+
+/* Given the vhdl for the desired xbow, the src and dest. widget ids
+ * and the req_bw value, this xbow driver entry point accesses the
+ * xbow registers and allocates the desired bandwidth if available.
+ *
+ * If bandwidth allocation is successful, return success else return failure.
+ */
+int
+xbow_prio_bw_alloc(devfs_handle_t vhdl,
+		xwidgetnum_t src_wid,
+		xwidgetnum_t dest_wid,
+		unsigned long long old_alloc_bw,
+		unsigned long long req_bw)
+{
+    xbow_soft_t             soft = xbow_soft_get(vhdl);
+    volatile xbowreg_t     *xreg;
+    xbowreg_t               mask;
+    unsigned long           s;
+    int                     error = 0;
+    bandwidth_t             old_bw_BYTES, req_bw_BYTES;
+    xbowreg_t               old_xreg;
+    int                     old_bw_GBR, req_bw_GBR, new_bw_GBR;
+
+#ifdef GRIO_DEBUG
+    printk("xbow_prio_bw_alloc: vhdl %d src_wid %d dest_wid %d req_bw %lld\n",
+		(int) vhdl, (int) src_wid, (int) dest_wid, req_bw);
+#endif
+
+    ASSERT(XBOW_WIDGET_IS_VALID(src_wid));
+    ASSERT(XBOW_WIDGET_IS_VALID(dest_wid));
+
+    s = mutex_spinlock(&soft->xbow_bw_alloc_lock);
+
+    /* Get pointer to the correct register */
+    xreg = XBOW_PRIO_ARBREG_PTR(soft->base, dest_wid, src_wid);
+
+    /* Get mask for GBR count value */
+    mask = XB_ARB_GBR_MSK << XB_ARB_GBR_SHFT(src_wid);
+
+    req_bw_GBR = xbow_bytes_to_gbr(old_alloc_bw, req_bw);
+    req_bw_BYTES = (req_bw_GBR < 0) ? (-1 * xbow_gbr_to_bytes(ABS(req_bw_GBR)))
+		: xbow_gbr_to_bytes(req_bw_GBR);
+
+#ifdef GRIO_DEBUG
+    printk("req_bw %lld req_bw_BYTES %lld req_bw_GBR %d\n",
+		req_bw, req_bw_BYTES, req_bw_GBR);
+#endif	/* GRIO_DEBUG */
+
+    old_bw_BYTES = soft->bw_cur_used[(int) dest_wid - MAX_XBOW_PORTS];
+    old_xreg = *xreg;
+    old_bw_GBR = (((*xreg) & mask) >> XB_ARB_GBR_SHFT(src_wid));
+
+#ifdef GRIO_DEBUG
+    ASSERT(XBOW_BYTES_TO_GBR(old_bw_BYTES) == old_bw_GBR);
+
+    printk("old_bw_BYTES %lld old_bw_GBR %d\n", old_bw_BYTES, old_bw_GBR);
+
+    printk("req_bw_BYTES %lld old_bw_BYTES %lld soft->bw_hiwm %lld\n",
+		req_bw_BYTES, old_bw_BYTES,
+		soft->bw_hiwm[(int) dest_wid - MAX_XBOW_PORTS]);
+	   
+#endif				/* GRIO_DEBUG */
+
+    /* Accept the request only if we don't exceed the destination
+     * port HIWATER_MARK *AND* the max. link GBR arbitration count
+     */
+    if (((old_bw_BYTES + req_bw_BYTES) <=
+		soft->bw_hiwm[(int) dest_wid - MAX_XBOW_PORTS]) &&
+		(req_bw_GBR + old_bw_GBR <= XBOW_ARB_GBR_MAX)) {
+
+	new_bw_GBR = (old_bw_GBR + req_bw_GBR);
+
+	/* Set this in the xbow link register */
+	*xreg = (old_xreg & ~mask) | \
+	    (new_bw_GBR << XB_ARB_GBR_SHFT(src_wid) & mask);
+
+	soft->bw_cur_used[(int) dest_wid - MAX_XBOW_PORTS] =
+			xbow_gbr_to_bytes(new_bw_GBR);
+    } else {
+	error = 1;
+    }
+
+    mutex_spinunlock(&soft->xbow_bw_alloc_lock, s);
+
+    return (error);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn1/xtalk.c linux-2.4.21-pre6/arch/ia64/sn/io/sn1/xtalk.c
--- linux-2.4.20/arch/ia64/sn/io/sn1/xtalk.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn1/xtalk.c	2003-03-26 23:48:57.000000000 +0000
@@ -0,0 +1,1003 @@
+/* $Id: xtalk.c,v 1.2 2002/11/21 17:51:57 jh 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) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/driver.h>
+#include <asm/sn/io.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/hcl_util.h>
+#include <asm/sn/xtalk/xtalk.h>
+#include <asm/sn/xtalk/xswitch.h>
+#include <asm/sn/xtalk/xwidget.h>
+#include <asm/sn/xtalk/xtalk_private.h>
+
+/*
+ * Implement crosstalk provider operations.  The xtalk* layer provides a
+ * platform-independent interface for crosstalk devices.  This layer
+ * switches among the possible implementations of a crosstalk adapter.
+ *
+ * On platforms with only one possible xtalk provider, macros can be
+ * set up at the top that cause the table lookups and indirections to
+ * completely disappear.
+ */
+
+#define	NEW(ptr)	(ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL))
+#define	DEL(ptr)	(kfree(ptr))
+
+char                    widget_info_fingerprint[] = "widget_info";
+
+cdl_p                   xtalk_registry = NULL;
+
+#define	DEV_FUNC(dev,func)	hub_##func
+#define	CAST_PIOMAP(x)		((hub_piomap_t)(x))
+#define	CAST_DMAMAP(x)		((hub_dmamap_t)(x))
+#define	CAST_INTR(x)		((hub_intr_t)(x))
+
+/* =====================================================================
+ *            Function Table of Contents
+ */
+xtalk_piomap_t          xtalk_piomap_alloc(devfs_handle_t, device_desc_t, iopaddr_t, size_t, size_t, unsigned);
+void                    xtalk_piomap_free(xtalk_piomap_t);
+caddr_t                 xtalk_piomap_addr(xtalk_piomap_t, iopaddr_t, size_t);
+void                    xtalk_piomap_done(xtalk_piomap_t);
+caddr_t                 xtalk_piotrans_addr(devfs_handle_t, device_desc_t, iopaddr_t, size_t, unsigned);
+caddr_t                 xtalk_pio_addr(devfs_handle_t, device_desc_t, iopaddr_t, size_t, xtalk_piomap_t *, unsigned);
+void                    xtalk_set_early_piotrans_addr(xtalk_early_piotrans_addr_f *);
+caddr_t                 xtalk_early_piotrans_addr(xwidget_part_num_t, xwidget_mfg_num_t, int, iopaddr_t, size_t, unsigned);
+static caddr_t          null_xtalk_early_piotrans_addr(xwidget_part_num_t, xwidget_mfg_num_t, int, iopaddr_t, size_t, unsigned);
+xtalk_dmamap_t          xtalk_dmamap_alloc(devfs_handle_t, device_desc_t, size_t, unsigned);
+void                    xtalk_dmamap_free(xtalk_dmamap_t);
+iopaddr_t               xtalk_dmamap_addr(xtalk_dmamap_t, paddr_t, size_t);
+alenlist_t              xtalk_dmamap_list(xtalk_dmamap_t, alenlist_t, unsigned);
+void                    xtalk_dmamap_done(xtalk_dmamap_t);
+iopaddr_t               xtalk_dmatrans_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, unsigned);
+alenlist_t              xtalk_dmatrans_list(devfs_handle_t, device_desc_t, alenlist_t, unsigned);
+void			xtalk_dmamap_drain(xtalk_dmamap_t);
+void			xtalk_dmaaddr_drain(devfs_handle_t, iopaddr_t, size_t);
+void			xtalk_dmalist_drain(devfs_handle_t, alenlist_t);
+xtalk_intr_t            xtalk_intr_alloc(devfs_handle_t, device_desc_t, devfs_handle_t);
+xtalk_intr_t            xtalk_intr_alloc_nothd(devfs_handle_t, device_desc_t, devfs_handle_t);
+void                    xtalk_intr_free(xtalk_intr_t);
+int                     xtalk_intr_connect(xtalk_intr_t, xtalk_intr_setfunc_t, void *);
+void                    xtalk_intr_disconnect(xtalk_intr_t);
+devfs_handle_t            xtalk_intr_cpu_get(xtalk_intr_t);
+int                     xtalk_error_handler(devfs_handle_t, int, ioerror_mode_t, ioerror_t *);
+int                     xtalk_error_devenable(devfs_handle_t, int, int);
+void                    xtalk_provider_startup(devfs_handle_t);
+void                    xtalk_provider_shutdown(devfs_handle_t);
+devfs_handle_t            xtalk_intr_dev_get(xtalk_intr_t);
+xwidgetnum_t            xtalk_intr_target_get(xtalk_intr_t);
+xtalk_intr_vector_t     xtalk_intr_vector_get(xtalk_intr_t);
+iopaddr_t               xtalk_intr_addr_get(struct xtalk_intr_s *);
+void                   *xtalk_intr_sfarg_get(xtalk_intr_t);
+devfs_handle_t            xtalk_pio_dev_get(xtalk_piomap_t);
+xwidgetnum_t            xtalk_pio_target_get(xtalk_piomap_t);
+iopaddr_t               xtalk_pio_xtalk_addr_get(xtalk_piomap_t);
+ulong                   xtalk_pio_mapsz_get(xtalk_piomap_t);
+caddr_t                 xtalk_pio_kvaddr_get(xtalk_piomap_t);
+devfs_handle_t            xtalk_dma_dev_get(xtalk_dmamap_t);
+xwidgetnum_t            xtalk_dma_target_get(xtalk_dmamap_t);
+xwidget_info_t          xwidget_info_chk(devfs_handle_t);
+xwidget_info_t          xwidget_info_get(devfs_handle_t);
+void                    xwidget_info_set(devfs_handle_t, xwidget_info_t);
+devfs_handle_t            xwidget_info_dev_get(xwidget_info_t);
+xwidgetnum_t            xwidget_info_id_get(xwidget_info_t);
+devfs_handle_t            xwidget_info_master_get(xwidget_info_t);
+xwidgetnum_t            xwidget_info_masterid_get(xwidget_info_t);
+xwidget_part_num_t      xwidget_info_part_num_get(xwidget_info_t);
+xwidget_mfg_num_t       xwidget_info_mfg_num_get(xwidget_info_t);
+char 			*xwidget_info_name_get(xwidget_info_t);
+void                    xtalk_init(void);
+void                    xtalk_provider_register(devfs_handle_t, xtalk_provider_t *);
+void                    xtalk_provider_unregister(devfs_handle_t);
+xtalk_provider_t       *xtalk_provider_fns_get(devfs_handle_t);
+int                     xwidget_driver_register(xwidget_part_num_t, 
+						xwidget_mfg_num_t, 
+						char *, unsigned);
+void                    xwidget_driver_unregister(char *);
+int                     xwidget_register(xwidget_hwid_t, devfs_handle_t, 
+					 xwidgetnum_t, devfs_handle_t, 
+					 xwidgetnum_t, async_attach_t);
+int			xwidget_unregister(devfs_handle_t);
+void                    xwidget_reset(devfs_handle_t);
+char			*xwidget_name_get(devfs_handle_t);
+#if !defined(DEV_FUNC)
+/*
+ * There is more than one possible provider
+ * for this platform. We need to examine the
+ * master vertex of the current vertex for
+ * a provider function structure, and indirect
+ * through the appropriately named member.
+ */
+#define	DEV_FUNC(dev,func)	xwidget_to_provider_fns(dev)->func
+#define	CAST_PIOMAP(x)		((xtalk_piomap_t)(x))
+#define	CAST_DMAMAP(x)		((xtalk_dmamap_t)(x))
+#define	CAST_INTR(x)		((xtalk_intr_t)(x))
+
+static xtalk_provider_t *
+xwidget_to_provider_fns(devfs_handle_t xconn)
+{
+    xwidget_info_t          widget_info;
+    xtalk_provider_t       *provider_fns;
+
+    widget_info = xwidget_info_get(xconn);
+    ASSERT(widget_info != NULL);
+
+    provider_fns = xwidget_info_pops_get(widget_info);
+    ASSERT(provider_fns != NULL);
+
+    return (provider_fns);
+}
+#endif
+
+/*
+ * Many functions are not passed their vertex
+ * information directly; rather, they must
+ * dive through a resource map. These macros
+ * are available to coordinate this detail.
+ */
+#define	PIOMAP_FUNC(map,func)	DEV_FUNC(map->xp_dev,func)
+#define	DMAMAP_FUNC(map,func)	DEV_FUNC(map->xd_dev,func)
+#define	INTR_FUNC(intr,func)	DEV_FUNC(intr_hdl->xi_dev,func)
+
+/* =====================================================================
+ *                    PIO MANAGEMENT
+ *
+ *      For mapping system virtual address space to
+ *      xtalk space on a specified widget
+ */
+
+xtalk_piomap_t
+xtalk_piomap_alloc(devfs_handle_t dev,	/* set up mapping for this device */
+		   device_desc_t dev_desc,	/* device descriptor */
+		   iopaddr_t xtalk_addr,	/* map for this xtalk_addr range */
+		   size_t byte_count,
+		   size_t byte_count_max,	/* maximum size of a mapping */
+		   unsigned flags)
+{				/* defined in sys/pio.h */
+    return (xtalk_piomap_t) DEV_FUNC(dev, piomap_alloc)
+	(dev, dev_desc, xtalk_addr, byte_count, byte_count_max, flags);
+}
+
+
+void
+xtalk_piomap_free(xtalk_piomap_t xtalk_piomap)
+{
+    PIOMAP_FUNC(xtalk_piomap, piomap_free)
+	(CAST_PIOMAP(xtalk_piomap));
+}
+
+
+caddr_t
+xtalk_piomap_addr(xtalk_piomap_t xtalk_piomap,	/* mapping resources */
+		  iopaddr_t xtalk_addr,		/* map for this xtalk address */
+		  size_t byte_count)
+{				/* map this many bytes */
+    return PIOMAP_FUNC(xtalk_piomap, piomap_addr)
+	(CAST_PIOMAP(xtalk_piomap), xtalk_addr, byte_count);
+}
+
+
+void
+xtalk_piomap_done(xtalk_piomap_t xtalk_piomap)
+{
+    PIOMAP_FUNC(xtalk_piomap, piomap_done)
+	(CAST_PIOMAP(xtalk_piomap));
+}
+
+
+caddr_t
+xtalk_piotrans_addr(devfs_handle_t dev,	/* translate for this device */
+		    device_desc_t dev_desc,	/* device descriptor */
+		    iopaddr_t xtalk_addr,	/* Crosstalk address */
+		    size_t byte_count,	/* map this many bytes */
+		    unsigned flags)
+{				/* (currently unused) */
+    return DEV_FUNC(dev, piotrans_addr)
+	(dev, dev_desc, xtalk_addr, byte_count, flags);
+}
+
+caddr_t
+xtalk_pio_addr(devfs_handle_t dev,	/* translate for this device */
+	       device_desc_t dev_desc,	/* device descriptor */
+	       iopaddr_t addr,		/* starting address (or offset in window) */
+	       size_t byte_count,	/* map this many bytes */
+	       xtalk_piomap_t *mapp,	/* where to return the map pointer */
+	       unsigned flags)
+{					/* PIO flags */
+    xtalk_piomap_t          map = 0;
+    caddr_t                 res;
+
+    if (mapp)
+	*mapp = 0;			/* record "no map used" */
+
+    res = xtalk_piotrans_addr
+	(dev, dev_desc, addr, byte_count, flags);
+    if (res)
+	return res;			/* xtalk_piotrans worked */
+
+    map = xtalk_piomap_alloc
+	(dev, dev_desc, addr, byte_count, byte_count, flags);
+    if (!map)
+	return res;			/* xtalk_piomap_alloc failed */
+
+    res = xtalk_piomap_addr
+	(map, addr, byte_count);
+    if (!res) {
+	xtalk_piomap_free(map);
+	return res;			/* xtalk_piomap_addr failed */
+    }
+    if (mapp)
+	*mapp = map;			/* pass back map used */
+
+    return res;				/* xtalk_piomap_addr succeeded */
+}
+
+/* =====================================================================
+ *            EARLY PIOTRANS SUPPORT
+ *
+ *      There are places where drivers (mgras, for instance)
+ *      need to get PIO translations before the infrastructure
+ *      is extended to them (setting up textports, for
+ *      instance). These drivers should call
+ *      xtalk_early_piotrans_addr with their xtalk ID
+ *      information, a sequence number (so we can use the second
+ *      mgras for instance), and the usual piotrans parameters.
+ *
+ *      Machine specific code should provide an implementation
+ *      of early_piotrans_addr, and present a pointer to this
+ *      function to xtalk_set_early_piotrans_addr so it can be
+ *      used by clients without the clients having to know what
+ *      platform or what xtalk provider is in use.
+ */
+
+static xtalk_early_piotrans_addr_f null_xtalk_early_piotrans_addr;
+
+xtalk_early_piotrans_addr_f *impl_early_piotrans_addr = null_xtalk_early_piotrans_addr;
+
+/* xtalk_set_early_piotrans_addr:
+ * specify the early_piotrans_addr implementation function.
+ */
+void
+xtalk_set_early_piotrans_addr(xtalk_early_piotrans_addr_f *impl)
+{
+    impl_early_piotrans_addr = impl;
+}
+
+/* xtalk_early_piotrans_addr:
+ * figure out a PIO address for the "nth" crosstalk widget that
+ * matches the specified part and mfgr number. Returns NULL if
+ * there is no such widget, or if the requested mapping can not
+ * be constructed.
+ * Limitations on which crosstalk slots (and busses) are
+ * checked, and definitions of the ordering of the search across
+ * the crosstalk slots, are defined by the platform.
+ */
+caddr_t
+xtalk_early_piotrans_addr(xwidget_part_num_t part_num,
+			  xwidget_mfg_num_t mfg_num,
+			  int which,
+			  iopaddr_t xtalk_addr,
+			  size_t byte_count,
+			  unsigned flags)
+{
+    return impl_early_piotrans_addr
+	(part_num, mfg_num, which, xtalk_addr, byte_count, flags);
+}
+
+/* null_xtalk_early_piotrans_addr:
+ * used as the early_piotrans_addr implementation until and
+ * unless a real implementation is provided. In DEBUG kernels,
+ * we want to know who is calling before the implementation is
+ * registered; in non-DEBUG kernels, return NULL representing
+ * lack of mapping support.
+ */
+/*ARGSUSED */
+static caddr_t
+null_xtalk_early_piotrans_addr(xwidget_part_num_t part_num,
+			       xwidget_mfg_num_t mfg_num,
+			       int which,
+			       iopaddr_t xtalk_addr,
+			       size_t byte_count,
+			       unsigned flags)
+{
+#if DEBUG
+    PRINT_PANIC("null_xtalk_early_piotrans_addr");
+#endif
+    return NULL;
+}
+
+/* =====================================================================
+ *                    DMA MANAGEMENT
+ *
+ *      For mapping from crosstalk space to system
+ *      physical space.
+ */
+
+xtalk_dmamap_t
+xtalk_dmamap_alloc(devfs_handle_t dev,	/* set up mappings for this device */
+		   device_desc_t dev_desc,	/* device descriptor */
+		   size_t byte_count_max,	/* max size of a mapping */
+		   unsigned flags)
+{				/* defined in dma.h */
+    return (xtalk_dmamap_t) DEV_FUNC(dev, dmamap_alloc)
+	(dev, dev_desc, byte_count_max, flags);
+}
+
+
+void
+xtalk_dmamap_free(xtalk_dmamap_t xtalk_dmamap)
+{
+    DMAMAP_FUNC(xtalk_dmamap, dmamap_free)
+	(CAST_DMAMAP(xtalk_dmamap));
+}
+
+
+iopaddr_t
+xtalk_dmamap_addr(xtalk_dmamap_t xtalk_dmamap,	/* use these mapping resources */
+		  paddr_t paddr,	/* map for this address */
+		  size_t byte_count)
+{				/* map this many bytes */
+    return DMAMAP_FUNC(xtalk_dmamap, dmamap_addr)
+	(CAST_DMAMAP(xtalk_dmamap), paddr, byte_count);
+}
+
+
+alenlist_t
+xtalk_dmamap_list(xtalk_dmamap_t xtalk_dmamap,	/* use these mapping resources */
+		  alenlist_t alenlist,	/* map this Address/Length List */
+		  unsigned flags)
+{
+    return DMAMAP_FUNC(xtalk_dmamap, dmamap_list)
+	(CAST_DMAMAP(xtalk_dmamap), alenlist, flags);
+}
+
+
+void
+xtalk_dmamap_done(xtalk_dmamap_t xtalk_dmamap)
+{
+    DMAMAP_FUNC(xtalk_dmamap, dmamap_done)
+	(CAST_DMAMAP(xtalk_dmamap));
+}
+
+
+iopaddr_t
+xtalk_dmatrans_addr(devfs_handle_t dev,	/* translate for this device */
+		    device_desc_t dev_desc,	/* device descriptor */
+		    paddr_t paddr,	/* system physical address */
+		    size_t byte_count,	/* length */
+		    unsigned flags)
+{				/* defined in dma.h */
+    return DEV_FUNC(dev, dmatrans_addr)
+	(dev, dev_desc, paddr, byte_count, flags);
+}
+
+
+alenlist_t
+xtalk_dmatrans_list(devfs_handle_t dev,	/* translate for this device */
+		    device_desc_t dev_desc,	/* device descriptor */
+		    alenlist_t palenlist,	/* system address/length list */
+		    unsigned flags)
+{				/* defined in dma.h */
+    return DEV_FUNC(dev, dmatrans_list)
+	(dev, dev_desc, palenlist, flags);
+}
+
+void
+xtalk_dmamap_drain(xtalk_dmamap_t map)
+{
+    DMAMAP_FUNC(map, dmamap_drain)
+	(CAST_DMAMAP(map));
+}
+
+void
+xtalk_dmaaddr_drain(devfs_handle_t dev, paddr_t addr, size_t size)
+{
+    DEV_FUNC(dev, dmaaddr_drain)
+	(dev, addr, size);
+}
+
+void
+xtalk_dmalist_drain(devfs_handle_t dev, alenlist_t list)
+{
+    DEV_FUNC(dev, dmalist_drain)
+	(dev, list);
+}
+
+/* =====================================================================
+ *                    INTERRUPT MANAGEMENT
+ *
+ *      Allow crosstalk devices to establish interrupts
+ */
+
+/*
+ * Allocate resources required for an interrupt as specified in intr_desc.
+ * Return resource handle in intr_hdl.
+ */
+xtalk_intr_t
+xtalk_intr_alloc(devfs_handle_t dev,	/* which Crosstalk device */
+		 device_desc_t dev_desc,	/* device descriptor */
+		 devfs_handle_t owner_dev)
+{				/* owner of this interrupt */
+    return (xtalk_intr_t) DEV_FUNC(dev, intr_alloc)
+	(dev, dev_desc, owner_dev);
+}
+
+/*
+ * Allocate resources required for an interrupt as specified in dev_desc.
+ * Unconditionally setup resources to be non-threaded.
+ * Return resource handle in intr_hdl.
+ */
+xtalk_intr_t
+xtalk_intr_alloc_nothd(devfs_handle_t dev,	/* which Crosstalk device */
+		 	device_desc_t dev_desc,	/* device descriptor */
+		 	devfs_handle_t owner_dev)	/* owner of this interrupt */
+{
+    return (xtalk_intr_t) DEV_FUNC(dev, intr_alloc_nothd)
+	(dev, dev_desc, owner_dev);
+}
+
+/*
+ * Free resources consumed by intr_alloc.
+ */
+void
+xtalk_intr_free(xtalk_intr_t intr_hdl)
+{
+    INTR_FUNC(intr_hdl, intr_free)
+	(CAST_INTR(intr_hdl));
+}
+
+
+/*
+ * Associate resources allocated with a previous xtalk_intr_alloc call with the
+ * described handler, arg, name, etc.
+ *
+ * Returns 0 on success, returns <0 on failure.
+ */
+int
+xtalk_intr_connect(xtalk_intr_t intr_hdl,	/* xtalk intr resource handle */
+		   xtalk_intr_setfunc_t setfunc,	/* func to set intr hw */
+		   void *setfunc_arg)	/* arg to setfunc */
+{
+    return INTR_FUNC(intr_hdl, intr_connect)
+	(CAST_INTR(intr_hdl), setfunc, setfunc_arg);
+}
+
+
+/*
+ * Disassociate handler with the specified interrupt.
+ */
+void
+xtalk_intr_disconnect(xtalk_intr_t intr_hdl)
+{
+    INTR_FUNC(intr_hdl, intr_disconnect)
+	(CAST_INTR(intr_hdl));
+}
+
+
+/*
+ * Return a hwgraph vertex that represents the CPU currently
+ * targeted by an interrupt.
+ */
+devfs_handle_t
+xtalk_intr_cpu_get(xtalk_intr_t intr_hdl)
+{
+    return INTR_FUNC(intr_hdl, intr_cpu_get)
+	(CAST_INTR(intr_hdl));
+}
+
+
+/* =====================================================================
+ *                    CONFIGURATION MANAGEMENT
+ */
+
+/*
+ * Startup a crosstalk provider
+ */
+void
+xtalk_provider_startup(devfs_handle_t xtalk_provider)
+{
+    DEV_FUNC(xtalk_provider, provider_startup)
+	(xtalk_provider);
+}
+
+
+/*
+ * Shutdown a crosstalk provider
+ */
+void
+xtalk_provider_shutdown(devfs_handle_t xtalk_provider)
+{
+    DEV_FUNC(xtalk_provider, provider_shutdown)
+	(xtalk_provider);
+}
+
+/* 
+ * Enable a device on a xtalk widget 
+ */
+void
+xtalk_widgetdev_enable(devfs_handle_t xconn_vhdl, int devnum)
+{
+    DEV_FUNC(xconn_vhdl, widgetdev_enable) (xconn_vhdl, devnum);
+}
+
+/* 
+ * Shutdown a device on a xtalk widget 
+ */
+void
+xtalk_widgetdev_shutdown(devfs_handle_t xconn_vhdl, int devnum)
+{
+    DEV_FUNC(xconn_vhdl, widgetdev_shutdown) (xconn_vhdl, devnum);
+}
+
+int
+xtalk_dma_enabled(devfs_handle_t xconn_vhdl)
+{
+    return DEV_FUNC(xconn_vhdl, dma_enabled) (xconn_vhdl);
+}
+/*
+ * Generic crosstalk functions, for use with all crosstalk providers
+ * and all crosstalk devices.
+ */
+
+/****** Generic crosstalk interrupt interfaces ******/
+devfs_handle_t
+xtalk_intr_dev_get(xtalk_intr_t xtalk_intr)
+{
+    return (xtalk_intr->xi_dev);
+}
+
+xwidgetnum_t
+xtalk_intr_target_get(xtalk_intr_t xtalk_intr)
+{
+    return (xtalk_intr->xi_target);
+}
+
+xtalk_intr_vector_t
+xtalk_intr_vector_get(xtalk_intr_t xtalk_intr)
+{
+    return (xtalk_intr->xi_vector);
+}
+
+iopaddr_t
+xtalk_intr_addr_get(struct xtalk_intr_s *xtalk_intr)
+{
+    return (xtalk_intr->xi_addr);
+}
+
+void                   *
+xtalk_intr_sfarg_get(xtalk_intr_t xtalk_intr)
+{
+    return (xtalk_intr->xi_sfarg);
+}
+
+/****** Generic crosstalk pio interfaces ******/
+devfs_handle_t
+xtalk_pio_dev_get(xtalk_piomap_t xtalk_piomap)
+{
+    return (xtalk_piomap->xp_dev);
+}
+
+xwidgetnum_t
+xtalk_pio_target_get(xtalk_piomap_t xtalk_piomap)
+{
+    return (xtalk_piomap->xp_target);
+}
+
+iopaddr_t
+xtalk_pio_xtalk_addr_get(xtalk_piomap_t xtalk_piomap)
+{
+    return (xtalk_piomap->xp_xtalk_addr);
+}
+
+ulong
+xtalk_pio_mapsz_get(xtalk_piomap_t xtalk_piomap)
+{
+    return (xtalk_piomap->xp_mapsz);
+}
+
+caddr_t
+xtalk_pio_kvaddr_get(xtalk_piomap_t xtalk_piomap)
+{
+    return (xtalk_piomap->xp_kvaddr);
+}
+
+
+/****** Generic crosstalk dma interfaces ******/
+devfs_handle_t
+xtalk_dma_dev_get(xtalk_dmamap_t xtalk_dmamap)
+{
+    return (xtalk_dmamap->xd_dev);
+}
+
+xwidgetnum_t
+xtalk_dma_target_get(xtalk_dmamap_t xtalk_dmamap)
+{
+    return (xtalk_dmamap->xd_target);
+}
+
+
+/****** Generic crosstalk widget information interfaces ******/
+
+/* xwidget_info_chk:
+ * check to see if this vertex is a widget;
+ * if so, return its widget_info (if any).
+ * if not, return NULL.
+ */
+xwidget_info_t
+xwidget_info_chk(devfs_handle_t xwidget)
+{
+    arbitrary_info_t        ainfo = 0;
+
+    hwgraph_info_get_LBL(xwidget, INFO_LBL_XWIDGET, &ainfo);
+    return (xwidget_info_t) ainfo;
+}
+
+
+xwidget_info_t
+xwidget_info_get(devfs_handle_t xwidget)
+{
+    xwidget_info_t          widget_info;
+
+    widget_info = (xwidget_info_t)
+	hwgraph_fastinfo_get(xwidget);
+
+#ifdef	LATER
+    if ((widget_info != NULL) &&
+	(widget_info->w_fingerprint != widget_info_fingerprint))
+#ifdef SUPPORT_PRINTING_V_FORMAT
+	PRINT_PANIC("%v bad xwidget_info", xwidget);
+#else
+	PRINT_PANIC("%x bad xwidget_info", xwidget);
+#endif
+#endif	/* LATER */
+
+    return (widget_info);
+}
+
+void
+xwidget_info_set(devfs_handle_t xwidget, xwidget_info_t widget_info)
+{
+    if (widget_info != NULL)
+	widget_info->w_fingerprint = widget_info_fingerprint;
+
+    hwgraph_fastinfo_set(xwidget, (arbitrary_info_t) widget_info);
+
+    /* Also, mark this vertex as an xwidget,
+     * and use the widget_info, so xwidget_info_chk
+     * can work (and be fairly efficient).
+     */
+    hwgraph_info_add_LBL(xwidget, INFO_LBL_XWIDGET,
+			 (arbitrary_info_t) widget_info);
+}
+
+devfs_handle_t
+xwidget_info_dev_get(xwidget_info_t xwidget_info)
+{
+    if (xwidget_info == NULL)
+	panic("null xwidget_info");
+    return (xwidget_info->w_vertex);
+}
+
+xwidgetnum_t
+xwidget_info_id_get(xwidget_info_t xwidget_info)
+{
+    if (xwidget_info == NULL)
+	panic("null xwidget_info");
+    return (xwidget_info->w_id);
+}
+
+
+devfs_handle_t
+xwidget_info_master_get(xwidget_info_t xwidget_info)
+{
+    if (xwidget_info == NULL)
+	panic("null xwidget_info");
+    return (xwidget_info->w_master);
+}
+
+xwidgetnum_t
+xwidget_info_masterid_get(xwidget_info_t xwidget_info)
+{
+    if (xwidget_info == NULL)
+	panic("null xwidget_info");
+    return (xwidget_info->w_masterid);
+}
+
+xwidget_part_num_t
+xwidget_info_part_num_get(xwidget_info_t xwidget_info)
+{
+    if (xwidget_info == NULL)
+	panic("null xwidget_info");
+    return (xwidget_info->w_hwid.part_num);
+}
+
+xwidget_mfg_num_t
+xwidget_info_mfg_num_get(xwidget_info_t xwidget_info)
+{
+    if (xwidget_info == NULL)
+	panic("null xwidget_info");
+    return (xwidget_info->w_hwid.mfg_num);
+}
+/* Extract the widget name from the widget information
+ * for the xtalk widget.
+ */
+char *
+xwidget_info_name_get(xwidget_info_t xwidget_info)
+{
+    if (xwidget_info == NULL)
+	panic("null xwidget info");
+    return(xwidget_info->w_name);
+}
+/****** Generic crosstalk initialization interfaces ******/
+
+/*
+ * One-time initialization needed for systems that support crosstalk.
+ */
+void
+xtalk_init(void)
+{
+    cdl_p                   cp;
+
+#if DEBUG && ATTACH_DEBUG
+    printf("xtalk_init\n");
+#endif
+    /* Allocate the registry.
+     * We might already have one.
+     * If we don't, go get one.
+     * MPness: someone might have
+     * set one up for us while we
+     * were not looking; use an atomic
+     * compare-and-swap to commit to
+     * using the new registry if and
+     * only if nobody else did first.
+     * If someone did get there first,
+     * toss the one we allocated back
+     * into the pool.
+     */
+    if (xtalk_registry == NULL) {
+	cp = cdl_new(EDGE_LBL_XIO, "part", "mfgr");
+	if (!compare_and_swap_ptr((void **) &xtalk_registry, NULL, (void *) cp)) {
+	    cdl_del(cp);
+	}
+    }
+    ASSERT(xtalk_registry != NULL);
+}
+
+/*
+ * Associate a set of xtalk_provider functions with a vertex.
+ */
+void
+xtalk_provider_register(devfs_handle_t provider, xtalk_provider_t *xtalk_fns)
+{
+    hwgraph_fastinfo_set(provider, (arbitrary_info_t) xtalk_fns);
+}
+
+/*
+ * Disassociate a set of xtalk_provider functions with a vertex.
+ */
+void
+xtalk_provider_unregister(devfs_handle_t provider)
+{
+    hwgraph_fastinfo_set(provider, (arbitrary_info_t)NULL);
+}
+
+/*
+ * Obtain a pointer to the xtalk_provider functions for a specified Crosstalk
+ * provider.
+ */
+xtalk_provider_t       *
+xtalk_provider_fns_get(devfs_handle_t provider)
+{
+    return ((xtalk_provider_t *) hwgraph_fastinfo_get(provider));
+}
+
+/*
+ * Announce a driver for a particular crosstalk part.
+ * Returns 0 on success or -1 on failure.  Failure occurs if the
+ * specified hardware already has a driver.
+ */
+/*ARGSUSED4 */
+int
+xwidget_driver_register(xwidget_part_num_t part_num,
+			xwidget_mfg_num_t mfg_num,
+			char *driver_prefix,
+			unsigned flags)
+{
+    /* a driver's init routine could call
+     * xwidget_driver_register before the
+     * system calls xtalk_init; so, we
+     * make the call here.
+     */
+    if (xtalk_registry == NULL)
+	xtalk_init();
+
+    return cdl_add_driver(xtalk_registry,
+			  part_num, mfg_num,
+			  driver_prefix, flags, NULL);
+}
+
+/*
+ * Inform xtalk infrastructure that a driver is no longer available for
+ * handling any widgets.
+ */
+void
+xwidget_driver_unregister(char *driver_prefix)
+{
+    /* before a driver calls unregister,
+     * it must have called registger; so we
+     * can assume we have a registry here.
+     */
+    ASSERT(xtalk_registry != NULL);
+
+    cdl_del_driver(xtalk_registry, driver_prefix, NULL);
+}
+
+/*
+ * Call some function with each vertex that
+ * might be one of this driver's attach points.
+ */
+void
+xtalk_iterate(char *driver_prefix,
+	      xtalk_iter_f *func)
+{
+    ASSERT(xtalk_registry != NULL);
+
+    cdl_iterate(xtalk_registry, driver_prefix, (cdl_iter_f *)func);
+}
+
+/*
+ * xwidget_register:
+ *	Register a xtalk device (xwidget) by doing the following.
+ *      -allocate and initialize xwidget_info data
+ *      -allocate a hwgraph vertex with name based on widget number (id)
+ *      -look up the widget's initialization function and call it,
+ *      or remember the vertex for later initialization.
+ *
+ */
+int
+xwidget_register(xwidget_hwid_t hwid,		/* widget's hardware ID */
+		 devfs_handle_t 	widget,		/* widget to initialize */
+		 xwidgetnum_t 	id,		/* widget's target id (0..f) */
+		 devfs_handle_t 	master,		/* widget's master vertex */
+		 xwidgetnum_t 	targetid,	/* master's target id (9/a) */
+		 async_attach_t aa)
+{			
+    xwidget_info_t          widget_info;
+    char		    *s,devnm[MAXDEVNAME];
+
+    /* Allocate widget_info and associate it with widget vertex */
+    NEW(widget_info);
+
+    /* Initialize widget_info */
+    widget_info->w_vertex = widget;
+    widget_info->w_id = id;
+    widget_info->w_master = master;
+    widget_info->w_masterid = targetid;
+    widget_info->w_hwid = *hwid;	/* structure copy */
+    widget_info->w_efunc = 0;
+    widget_info->w_einfo = 0;
+    /*
+     * get the name of this xwidget vertex and keep the info.
+     * This is needed during errors and interupts, but as
+     * long as we have it, we can use it elsewhere.
+     */
+    s = dev_to_name(widget,devnm,MAXDEVNAME);
+    widget_info->w_name = kmalloc(strlen(s) + 1, GFP_KERNEL);
+    strcpy(widget_info->w_name,s);
+    
+    xwidget_info_set(widget, widget_info);
+
+    device_master_set(widget, master);
+
+    /* All the driver init routines (including
+     * xtalk_init) are called before we get into
+     * attaching devices, so we can assume we
+     * have a registry here.
+     */
+    ASSERT(xtalk_registry != NULL);
+
+    /* 
+     * Add pointer to async attach info -- tear down will be done when
+     * the particular descendant is done with the info.
+     */
+    if (aa)
+	    async_attach_add_info(widget, aa);
+
+    return cdl_add_connpt(xtalk_registry, hwid->part_num, hwid->mfg_num,
+                          widget, 0);
+}
+
+/*
+ * xwidget_unregister :
+ *	Unregister the xtalk device and detach all its hwgraph namespace.
+ */
+int
+xwidget_unregister(devfs_handle_t widget)
+{
+    xwidget_info_t	widget_info;
+    xwidget_hwid_t	hwid;
+
+    /* Make sure that we have valid widget information initialized */
+    if (!(widget_info = xwidget_info_get(widget)))
+	return(1);
+
+    /* Remove the inventory information associated
+     * with the widget.
+     */
+    hwgraph_inventory_remove(widget, -1, -1, -1, -1, -1);
+    
+    hwid = &(widget_info->w_hwid);
+
+    cdl_del_connpt(xtalk_registry, hwid->part_num, hwid->mfg_num,
+                   widget, 0);
+
+    /* Clean out the xwidget information */
+    (void)kfree(widget_info->w_name);
+    BZERO((void *)widget_info, sizeof(widget_info));
+    DEL(widget_info);
+    
+    return(0);
+}
+
+/*
+ * Issue a link reset to a widget.
+ */
+void
+xwidget_reset(devfs_handle_t xwidget)
+{
+    xswitch_reset_link(xwidget);
+
+}
+
+
+void
+xwidget_gfx_reset(devfs_handle_t xwidget)
+{
+    xwidget_info_t info;
+
+    xswitch_reset_link(xwidget);
+    info = xwidget_info_get(xwidget);
+#ifdef LATER
+    ASSERT_ALWAYS(info != NULL);
+#endif
+
+    /*
+     * Enable this for other architectures once we add widget_reset to the
+     * xtalk provider interface.
+     */
+    DEV_FUNC(xtalk_provider, widget_reset)
+	(xwidget_info_master_get(info), xwidget_info_id_get(info));
+}
+
+#define ANON_XWIDGET_NAME	"No Name"	/* Default Widget Name */
+
+/* Get the canonical hwgraph  name of xtalk widget */
+char *
+xwidget_name_get(devfs_handle_t xwidget_vhdl)
+{
+	xwidget_info_t  info;
+
+	/* If we have a bogus widget handle then return
+	 * a default anonymous widget name.
+	 */
+	if (xwidget_vhdl == GRAPH_VERTEX_NONE)
+	    return(ANON_XWIDGET_NAME);
+	/* Read the widget name stored in the widget info
+	 * for the widget setup during widget initialization.
+	 */
+	info = xwidget_info_get(xwidget_vhdl);
+	ASSERT(info != NULL);
+	return(xwidget_info_name_get(info));
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/Makefile linux-2.4.21-pre6/arch/ia64/sn/io/sn2/Makefile
--- linux-2.4.20/arch/ia64/sn/io/sn2/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn2/Makefile	2003-03-26 23:49:51.000000000 +0000
@@ -0,0 +1,27 @@
+#
+# 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) 2002 Silicon Graphics, Inc.  All Rights Reserved.
+#
+# Makefile for the sn2 io routines.
+
+EXTRA_CFLAGS    := -DLITTLE_ENDIAN
+
+O_TARGET := snio.o
+
+export-objs := pciio.o 
+
+obj-y				+= ml_SN_intr.o shub_intr.o shuberror.o shub.o \
+				   bte_error.o pcibr/pcibr.o pic.o geo_op.o \
+				   l1.o l1_command.o klconflib.o klgraph.o \
+				   ml_SN_init.o ml_iograph.o module.o pciio.o \
+				   xbow.o xtalk.o \
+				   pci_bus_cvlink.o sgi_io_init.o shubio.o
+
+subdir-y			+= pcibr
+
+obj-$(CONFIG_SHUB_1_0_SPECIFIC) += efi-rtc.o
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/bte_error.c linux-2.4.21-pre6/arch/ia64/sn/io/sn2/bte_error.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/bte_error.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn2/bte_error.c	2003-03-26 23:49:39.000000000 +0000
@@ -54,96 +54,14 @@
  *									*
  ************************************************************************/
 
-#ifdef BTE_ERROR
-// This routine is not called.  Yet.  It may be someday.  It probably
-// *should* be someday.  Until then, ifdef it out.
-bte_result_t
-bte_error_handler(bte_handle_t *bh)
-/*
- * Function: 	bte_error_handler
- * Purpose:	Process a BTE error after a transfer has failed.
- * Parameters:	bh - bte handle of bte that failed.
- * Returns:	The BTE error type.
- * Notes:
+/* 
+ * >>> bte_crb_error_handler needs to be broken into two parts.  The
+ * first should cleanup the CRB.  The second should wait until all bte
+ * related CRB's are complete and then do the error reset.
  */
-{
-    devfs_handle_t	hub_v;
-    hubinfo_t		hinfo;
-    int			il;
-    hubreg_t		iidsr, imem, ieclr;
-    hubreg_t		bte_status;
-
-    bh->bh_bte->bte_error_count++;
-
-    /* 
-     * Process any CRB logs - we know that the bte_context contains
-     * the BTE completion status, but to avoid a race with error
-     * processing, we force a call to pick up any CRB errors pending. 
-     * After this call, we know that we have any CRB errors related to 
-     * this BTE transfer in the context.
-     */
-    hub_v = cnodeid_to_vertex(bh->bh_bte->bte_cnode);
-    hubinfo_get(hub_v, &hinfo);
-    (void)hubiio_crb_error_handler(hub_v, hinfo);
-
-    /* Be sure BTE is stopped */
-
-    (void)BTE_LOAD(bh->bh_bte->bte_base, BTEOFF_CTRL);
-
-    /*	
-     * Now clear up the rest of the error - be sure to hold crblock 
-     * to avoid race with other cpu on this node.
-     */
-    imem = REMOTE_HUB_L(hinfo->h_nasid, IIO_IMEM);
-    ieclr = REMOTE_HUB_L(hinfo->h_nasid, IIO_IECLR);
-    if (bh->bh_bte->bte_num == 0) {
-	imem |= IIO_IMEM_W0ESD | IIO_IMEM_B0ESD;
-	ieclr|= IECLR_BTE0;
-    } else {
-	imem |= IIO_IMEM_W0ESD | IIO_IMEM_B1ESD;
-	ieclr|= IECLR_BTE1;
-    }
-
-    REMOTE_HUB_S(hinfo->h_nasid, IIO_IMEM, imem);
-    REMOTE_HUB_S(hinfo->h_nasid, IIO_IECLR, ieclr);
-
-    iidsr  = REMOTE_HUB_L(hinfo->h_nasid, IIO_IIDSR);
-    iidsr &= ~IIO_IIDSR_SENT_MASK;
-    iidsr |= IIO_IIDSR_ENB_MASK;
-    REMOTE_HUB_S(hinfo->h_nasid, IIO_IIDSR, iidsr);
-    mutex_spinunlock(&hinfo->h_crblock, il);
-
-    bte_status = BTE_LOAD(bh->bh_bte->bte_base, BTEOFF_STAT);
-    BTE_STORE(bh->bh_bte->bte_base, BTEOFF_STAT, bte_status & ~IBLS_BUSY);
-    ASSERT(!BTE_IS_BUSY(BTE_LOAD(bh->bh_bte->bte_base, BTEOFF_STAT)));
-
-    switch(bh->bh_error) {
-    case IIO_ICRB_ECODE_PERR:
-	return(BTEFAIL_POISON);
-    case IIO_ICRB_ECODE_WERR:
-	return(BTEFAIL_PROT);
-    case IIO_ICRB_ECODE_AERR:
-	return(BTEFAIL_ACCESS);
-    case IIO_ICRB_ECODE_TOUT:
-	return(BTEFAIL_TOUT);
-    case IIO_ICRB_ECODE_XTERR:
-	return(BTEFAIL_ERROR);
-    case IIO_ICRB_ECODE_DERR:
-	return(BTEFAIL_DIR);
-    case IIO_ICRB_ECODE_PWERR:
-    case IIO_ICRB_ECODE_PRERR:
-	/* NO BREAK */
-    default:
-	printk("BTE failure (%d) unexpected\n", 
-		bh->bh_error);
-	return(BTEFAIL_ERROR);
-    }
-}
-#endif // BTE_ERROR
-
 void
 bte_crb_error_handler(devfs_handle_t hub_v, int btenum, 
-		      int crbnum, ioerror_t *ioe)
+		      int crbnum, ioerror_t *ioe, int bteop)
 /*
  * Function: 	bte_crb_error_handler
  * Purpose:	Process a CRB for a specific HUB/BTE
@@ -162,29 +80,70 @@
 	icrba_t		crba; 
 	icrbb_t		crbb; 
 	nasid_t		n;
+	hubreg_t	iidsr, imem, ieclr;
 
 	hubinfo_get(hub_v, &hinfo);
 
 
 	n = hinfo->h_nasid;
 	
-	/* Step 1 */
-	crba.ii_icrb0_a_regval = REMOTE_HUB_L(n, IIO_ICRB_A(crbnum));
-	crbb.ii_icrb0_b_regval = REMOTE_HUB_L(n, IIO_ICRB_B(crbnum));
 
+	/*
+	 * The following 10 lines (or so) are adapted from IRIXs
+	 * bte_crb_error function.  No clear documentation tells
+	 * why the crb needs to complete normally in order for
+	 * the BTE to resume normal operations.  This first step
+	 * appears vital!
+	 */
 
-	/* Zero error and error code to prevent error_dump complaining
-	 * about these CRBs. 
+	/*
+	 * Zero error and error code to prevent error_dump complaining
+	 * about these CRBs. Copy the CRB to the notification line.
+	 * The crb address is in shub format (physical address shifted
+	 * right by cacheline size).
 	 */
+	crbb.ii_icrb0_b_regval = REMOTE_HUB_L(n, IIO_ICRB_B(crbnum));
 	crbb.b_error=0;
 	crbb.b_ecode=0;
+	REMOTE_HUB_S(n, IIO_ICRB_B(crbnum), crbb.ii_icrb0_b_regval);
 
-	/* Step 2 */
+	crba.ii_icrb0_a_regval = REMOTE_HUB_L(n, IIO_ICRB_A(crbnum));
+	crba.a_addr = TO_PHYS((u64)&nodepda->bte_if[btenum].notify) >> 3;
+	crba.a_valid = 1;
 	REMOTE_HUB_S(n, IIO_ICRB_A(crbnum), crba.ii_icrb0_a_regval);
-	/* Step 3 */
+
 	REMOTE_HUB_S(n, IIO_ICCR, 
 		     IIO_ICCR_PENDING | IIO_ICCR_CMD_FLUSH | crbnum);
+
 	while (REMOTE_HUB_L(n, IIO_ICCR) & IIO_ICCR_PENDING)
 	    ;
+
+
+	/* Terminate the BTE. */
+	/* >>> The other bte transfer will need to be restarted. */
+	HUB_L((shubreg_t *)((nodepda->bte_if[btenum].bte_base_addr +
+		       IIO_IBCT0 - IIO_IBLS0)));
+
+	imem = REMOTE_HUB_L(n, IIO_IMEM);
+	ieclr = REMOTE_HUB_L(n, IIO_IECLR);
+	if (btenum == 0) {
+		imem |= IIO_IMEM_W0ESD | IIO_IMEM_B0ESD;
+		ieclr|= IECLR_BTE0;
+	} else {
+		imem |= IIO_IMEM_W0ESD | IIO_IMEM_B1ESD;
+		ieclr|= IECLR_BTE1;
+	}
+	REMOTE_HUB_S(n, IIO_IMEM, imem);
+	REMOTE_HUB_S(n, IIO_IECLR, ieclr);
+		
+	iidsr  = REMOTE_HUB_L(n, IIO_IIDSR);
+	iidsr &= ~IIO_IIDSR_SENT_MASK;
+	iidsr |= IIO_IIDSR_ENB_MASK;
+	REMOTE_HUB_S(n, IIO_IIDSR, iidsr);
+
+
+ 	bte_reset_nasid(n);
+
+	*nodepda->bte_if[btenum].most_rcnt_na = IBLS_ERROR;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/efi-rtc.c linux-2.4.21-pre6/arch/ia64/sn/io/sn2/efi-rtc.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/efi-rtc.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn2/efi-rtc.c	2003-03-26 23:49:19.000000000 +0000
@@ -0,0 +1,202 @@
+/*
+ * 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) 2001-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (C) 2001 by Ralf Baechle
+ */
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/errno.h>
+#include <linux/efi.h>
+#include <asm/sn/klclock.h>
+
+/*
+ * No locking necessary when this is called from efirtc which protects us
+ * from racing by efi_rtc_lock.
+ */
+#define __swizzle(addr) ((u8 *)((unsigned long)(addr) ^ 3))
+#define read_io_port(addr) (*(volatile u8 *) __swizzle(addr))
+#define write_io_port(addr, data) (*(volatile u8 *) __swizzle(addr) = (data))
+
+#define TOD_SGS_M48T35		1
+#define TOD_DALLAS_DS1386	2
+
+#define TYPE_IOC3		1
+#define TYPE_IOC4		2
+
+static unsigned long nvram_base = 0;
+static int tod_chip_type;
+static int ioc_type;
+
+static int
+get_tod_chip_type(void)
+{
+	unsigned char testval;
+
+	write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_DISABLE);
+	write_io_port(RTC_DAL_DAY_ADDR, 0xff);
+	write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_ENABLE);
+
+	testval = read_io_port(RTC_DAL_DAY_ADDR);
+	if (testval == 0xff)
+		return TOD_SGS_M48T35;
+
+	return TOD_DALLAS_DS1386;
+}
+
+efi_status_t
+ioc3_get_time(efi_time_t *time, efi_time_cap_t *caps)
+{
+	if (!nvram_base) {
+		printk(KERN_CRIT "nvram_base is zero\n");
+		return EFI_UNSUPPORTED;
+	}
+
+	memset(time, 0, sizeof(*time));
+
+	switch (tod_chip_type) {
+	case TOD_SGS_M48T35:
+		write_io_port(RTC_SGS_CONTROL_ADDR, RTC_SGS_READ_PROTECT);
+
+		time->year = BCD_TO_INT(read_io_port(RTC_SGS_YEAR_ADDR)) + YRREF;
+		time->month = BCD_TO_INT(read_io_port(RTC_SGS_MONTH_ADDR));
+		time->day = BCD_TO_INT(read_io_port(RTC_SGS_DATE_ADDR));
+		time->hour = BCD_TO_INT(read_io_port(RTC_SGS_HOUR_ADDR));
+		time->minute = BCD_TO_INT(read_io_port(RTC_SGS_MIN_ADDR));
+		time->second = BCD_TO_INT(read_io_port(RTC_SGS_SEC_ADDR));
+		time->nanosecond = 0;
+
+		write_io_port(RTC_SGS_CONTROL_ADDR, 0);
+		break;
+
+	case TOD_DALLAS_DS1386:
+		write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_DISABLE);
+
+		time->nanosecond = 0;
+		time->second = BCD_TO_INT(read_io_port(RTC_DAL_SEC_ADDR));
+		time->minute = BCD_TO_INT(read_io_port(RTC_DAL_MIN_ADDR));
+		time->hour = BCD_TO_INT(read_io_port(RTC_DAL_HOUR_ADDR));
+		time->day = BCD_TO_INT(read_io_port(RTC_DAL_DATE_ADDR));
+		time->month = BCD_TO_INT(read_io_port(RTC_DAL_MONTH_ADDR));
+		time->year = BCD_TO_INT(read_io_port(RTC_DAL_YEAR_ADDR)) + YRREF;
+
+		write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_ENABLE);
+		break;
+
+	default:
+		break;
+	}
+
+	if (caps) {
+		caps->resolution = 50000000;	/*  50PPM */
+		caps->accuracy = 1000;		/*  1ms */
+		caps->sets_to_zero = 0;
+	}
+
+	return EFI_SUCCESS;
+}
+
+static efi_status_t ioc3_set_time (efi_time_t *t)
+{
+	if (!nvram_base) {
+		printk(KERN_CRIT "nvram_base is zero\n");
+		return EFI_UNSUPPORTED;
+	}
+
+	switch (tod_chip_type) {
+	case TOD_SGS_M48T35:
+		write_io_port(RTC_SGS_CONTROL_ADDR, RTC_SGS_WRITE_ENABLE);
+        	write_io_port(RTC_SGS_YEAR_ADDR, INT_TO_BCD((t->year - YRREF)));
+		write_io_port(RTC_SGS_MONTH_ADDR,INT_TO_BCD(t->month));
+		write_io_port(RTC_SGS_DATE_ADDR, INT_TO_BCD(t->day));
+		write_io_port(RTC_SGS_HOUR_ADDR, INT_TO_BCD(t->hour));
+		write_io_port(RTC_SGS_MIN_ADDR,  INT_TO_BCD(t->minute));
+		write_io_port(RTC_SGS_SEC_ADDR,  INT_TO_BCD(t->second));
+		write_io_port(RTC_SGS_CONTROL_ADDR, 0);
+		break;
+
+	case TOD_DALLAS_DS1386:
+		write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_DISABLE);
+		write_io_port(RTC_DAL_SEC_ADDR,  INT_TO_BCD(t->second));
+		write_io_port(RTC_DAL_MIN_ADDR,  INT_TO_BCD(t->minute));
+		write_io_port(RTC_DAL_HOUR_ADDR, INT_TO_BCD(t->hour));
+		write_io_port(RTC_DAL_DATE_ADDR, INT_TO_BCD(t->day));
+		write_io_port(RTC_DAL_MONTH_ADDR,INT_TO_BCD(t->month));
+		write_io_port(RTC_DAL_YEAR_ADDR, INT_TO_BCD((t->year - YRREF)));
+		write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_ENABLE);
+		break;
+
+	default:
+		break;
+	}
+
+	return EFI_SUCCESS;
+}
+
+/* The following two are not supported atm.  */
+static efi_status_t
+ioc3_get_wakeup_time (efi_bool_t *enabled, efi_bool_t *pending, efi_time_t *tm)
+{
+	return EFI_UNSUPPORTED;
+}
+
+static efi_status_t
+ioc3_set_wakeup_time (efi_bool_t enabled, efi_time_t *tm)
+{
+	return EFI_UNSUPPORTED;
+}
+
+static __init int efi_ioc_time_init(void)
+{
+	struct pci_dev *dev = NULL;
+	static void *ioc_base;
+
+        while ( (dev = pci_find_subsys(PCI_VENDOR_ID_SGI,
+                               PCI_ANY_ID,
+                               PCI_ANY_ID,
+                               PCI_ANY_ID, dev))) {
+		if ( dev->device == PCI_DEVICE_ID_SGI_IOC3 ) {
+			ioc_type = TYPE_IOC3;
+			break;
+		}
+		else if ( dev->device == PCI_DEVICE_ID_SGI_IOC4 ) {
+			ioc_type = TYPE_IOC4;
+			break;
+		}
+		else
+			;; // keep looking
+	}
+
+	if ( !dev ) {
+		printk(KERN_CRIT "Couldn't find master IOC\n");
+		return -ENODEV;
+	}
+
+	ioc_base = ioremap(pci_resource_start(dev, 0), pci_resource_len(dev, 0));
+	if ( ioc_type == TYPE_IOC3 )
+		nvram_base = (unsigned long) ioc_base + IOC3_BYTEBUS_DEV0;
+	if ( ioc_type == TYPE_IOC4 )
+		nvram_base = (unsigned long) ioc_base + IOC4_BYTEBUS_DEV0;
+
+	tod_chip_type = get_tod_chip_type();
+	if (tod_chip_type == 1)
+		printk(KERN_NOTICE "TOD type is SGS M48T35\n");
+	else if (tod_chip_type == 2)
+		printk(KERN_NOTICE "TOD type is Dallas DS1386\n");
+	else
+		printk(KERN_CRIT "No or unknown TOD\n");
+
+	efi.get_time = ioc3_get_time;
+	efi.set_time = ioc3_set_time;
+	efi.get_wakeup_time = ioc3_get_wakeup_time;
+	efi.set_wakeup_time = ioc3_set_wakeup_time;
+
+	return 0;
+}
+
+module_init(efi_ioc_time_init);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/geo_op.c linux-2.4.21-pre6/arch/ia64/sn/io/sn2/geo_op.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/geo_op.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn2/geo_op.c	2003-03-26 23:49:07.000000000 +0000
@@ -0,0 +1,314 @@
+/* $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) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+/*
+ * @doc file m:hwcfg
+ * DESCRIPTION:
+ * 
+ * This file contains routines for manipulating and generating 
+ * Geographic IDs.  They are in a file by themself since they have
+ * no dependencies on other modules.
+ *  
+ * ORIGIN:
+ * 
+ * New for SN2
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <asm/smp.h>
+#include <asm/irq.h>
+#include <asm/hw_irq.h>
+#include <asm/sn/types.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/io.h>
+#include <asm/sn/sn_private.h>
+#include <asm/sn/klconfig.h>
+#include <asm/sn/sn_cpuid.h>
+#include <asm/sn/pci/pciio.h>
+#include <asm/sn/pci/pcibr.h>
+#include <asm/sn/xtalk/xtalk.h>
+#include <asm/sn/pci/pcibr_private.h>
+#include <asm/sn/intr.h>
+#include <asm/sn/sn2/shub_mmr_t.h>
+#include <asm/sn/sn2/shubio.h>
+#include <asm/sal.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/module.h>
+#include <asm/sn/geo.h>
+
+/********** Global functions and data (visible outside the module) ***********/
+
+/*
+ * @doc gf:geo_module
+ * 
+ * moduleid_t geo_module(geoid_t g)
+ * 
+ * DESCRIPTION:
+ * 
+ * Return the moduleid component of a geoid.
+ *  
+ * INTERNALS:
+ * 
+ * Return INVALID_MODULE for an invalid geoid.  Otherwise extract the
+ * moduleid from the structure, and return it.
+ *   
+ * ORIGIN:
+ * 
+ * New for SN2
+ */
+
+moduleid_t
+geo_module(geoid_t g)
+{
+    if (g.any.type == GEO_TYPE_INVALID)
+	return INVALID_MODULE;
+    else
+	return g.any.module;
+}
+
+
+/*
+ * @doc gf:geo_slab
+ * 
+ * slabid_t geo_slab(geoid_t g)
+ * 
+ * DESCRIPTION:
+ * 
+ * Return the slabid component of a geoid.
+ *  
+ * INTERNALS:
+ * 
+ * Return INVALID_SLAB for an invalid geoid.  Otherwise extract the
+ * slabid from the structure, and return it.
+ *   
+ * ORIGIN:
+ * 
+ * New for SN2
+ */
+
+slabid_t
+geo_slab(geoid_t g)
+{
+    if (g.any.type == GEO_TYPE_INVALID)
+	return INVALID_SLAB;
+    else
+	return g.any.slab;
+}
+
+
+/*
+ * @doc gf:geo_type
+ * 
+ * geo_type_t geo_type(geoid_t g)
+ * 
+ * DESCRIPTION:
+ * 
+ * Return the type component of a geoid.
+ *  
+ * INTERNALS:
+ * 
+ * Extract the type from the structure, and return it.
+ *   
+ * ORIGIN:
+ * 
+ * New for SN2
+ */
+
+geo_type_t
+geo_type(geoid_t g)
+{
+    return g.any.type;
+}
+
+
+/*
+ * @doc gf:geo_valid
+ * 
+ * int geo_valid(geoid_t g)
+ * 
+ * DESCRIPTION:
+ * 
+ * Return nonzero if g has a valid geoid type.
+ *  
+ * INTERNALS:
+ * 
+ * Test the type against GEO_TYPE_INVALID, and return the result.
+ *   
+ * ORIGIN:
+ * 
+ * New for SN2
+ */
+
+int
+geo_valid(geoid_t g)
+{
+    return g.any.type != GEO_TYPE_INVALID;
+}
+
+
+/*
+ * @doc gf:geo_cmp
+ * 
+ * int geo_cmp(geoid_t g0, geoid_t g1)
+ * 
+ * DESCRIPTION:
+ * 
+ * Compare two geoid_t values, from the coarsest field to the finest.
+ * The comparison should be consistent with the physical locations of
+ * of the hardware named by the geoids.
+ *  
+ * INTERNALS:
+ * 
+ * First compare the module, then the slab, type, and type-specific fields.
+ *   
+ * ORIGIN:
+ * 
+ * New for SN2
+ */
+
+int
+geo_cmp(geoid_t g0, geoid_t g1)
+{
+    int rv;
+
+    /* Compare the common fields */
+    rv = MODULE_CMP(geo_module(g0), geo_module(g1));
+    if (rv != 0)
+	return rv;
+
+    rv = geo_slab(g0) - geo_slab(g1);
+    if (rv != 0)
+	return rv;
+
+    /* Within a slab, sort by type */
+    rv = geo_type(g0) - geo_type(g1);
+    if (rv != 0)
+	return rv;
+
+    switch(geo_type(g0)) {
+    case GEO_TYPE_CPU:
+	rv = g0.cpu.slice - g1.cpu.slice;
+	break;
+
+    case GEO_TYPE_IOCARD:
+	rv = g0.pcicard.bus - g1.pcicard.bus;
+	if (rv) break;
+	rv = SLOTNUM_GETSLOT(g0.pcicard.slot) -
+	    SLOTNUM_GETSLOT(g1.pcicard.slot);
+	break;
+
+    case GEO_TYPE_MEM:
+	rv = g0.mem.membus - g1.mem.membus;
+	if (rv) break;
+	rv = g0.mem.memslot - g1.mem.memslot;
+	break;
+
+    default:
+	rv = 0;
+    }
+
+    return rv;
+}
+
+
+/*
+ * @doc gf:geo_new
+ * 
+ * geoid_t geo_new(geo_type_t type, ...)
+ * 
+ * DESCRIPTION:
+ * 
+ * Generate a new geoid_t value of the given type from its components.
+ * Expected calling sequences:
+ * \@itemize \@bullet
+ * \@item
+ * \@code\{geo_new(GEO_TYPE_INVALID)\}
+ * \@item
+ * \@code\{geo_new(GEO_TYPE_MODULE, moduleid_t m)\}
+ * \@item
+ * \@code\{geo_new(GEO_TYPE_NODE, moduleid_t m, slabid_t s)\}
+ * \@item
+ * \@code\{geo_new(GEO_TYPE_RTR, moduleid_t m, slabid_t s)\}
+ * \@item
+ * \@code\{geo_new(GEO_TYPE_IOCNTL, moduleid_t m, slabid_t s)\}
+ * \@item
+ * \@code\{geo_new(GEO_TYPE_IOCARD, moduleid_t m, slabid_t s, char bus, slotid_t slot)\}
+ * \@item
+ * \@code\{geo_new(GEO_TYPE_CPU, moduleid_t m, slabid_t s, char slice)\}
+ * \@item
+ * \@code\{geo_new(GEO_TYPE_MEM, moduleid_t m, slabid_t s, char membus, char slot)\}
+ * \@end itemize
+ *
+ * Invalid types return a GEO_TYPE_INVALID geoid_t.
+ *  
+ * INTERNALS:
+ * 
+ * Use the type to determine which fields to expect.  Write the fields into
+ * a new geoid_t and return it.  Note:  scalars smaller than an "int" are
+ * promoted to "int" by the "..." operator, so we need extra casts on "char",
+ * "slotid_t", and "slabid_t".
+ *   
+ * ORIGIN:
+ * 
+ * New for SN2
+ */
+
+geoid_t
+geo_new(geo_type_t type, ...)
+{
+    va_list al;
+    geoid_t g;
+    memset(&g, 0, sizeof(g));
+
+    va_start(al, type);
+
+    /* Make sure the type is sane */
+    if (type >= GEO_TYPE_MAX)
+	type = GEO_TYPE_INVALID;
+
+    g.any.type = type;
+    if (type == GEO_TYPE_INVALID)
+	goto done;		/* invalid geoids have no components at all */
+
+    g.any.module = va_arg(al, moduleid_t);
+    if (type == GEO_TYPE_MODULE)
+	goto done;
+
+    g.any.slab = (slabid_t)va_arg(al, int);
+
+    /* Some types have additional components */
+    switch(type) {
+    case GEO_TYPE_CPU:
+	g.cpu.slice = (char)va_arg(al, int);
+	break;
+
+    case GEO_TYPE_IOCARD:
+	g.pcicard.bus = (char)va_arg(al, int);
+	g.pcicard.slot = (slotid_t)va_arg(al, int);
+	break;
+
+    case GEO_TYPE_MEM:
+	g.mem.membus = (char)va_arg(al, int);
+	g.mem.memslot = (char)va_arg(al, int);
+	break;
+
+    default:
+	break;
+    }
+
+ done:
+    va_end(al);
+    return g;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/klconflib.c linux-2.4.21-pre6/arch/ia64/sn/io/sn2/klconflib.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/klconflib.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn2/klconflib.c	2003-03-26 23:49:25.000000000 +0000
@@ -0,0 +1,933 @@
+/* $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) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+
+#include <linux/types.h>
+#include <linux/ctype.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/io.h>
+#include <asm/sn/sn_cpuid.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/klconfig.h>
+#include <asm/sn/nodepda.h>
+#include <asm/sn/module.h>
+#include <asm/sn/router.h>
+#include <asm/sn/xtalk/xbow.h>
+
+#define printf printk
+int hasmetarouter;
+
+#define LDEBUG 0
+#define NIC_UNKNOWN ((nic_t) -1)
+
+#undef DEBUG_KLGRAPH
+#ifdef DEBUG_KLGRAPH
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif /* DEBUG_KLGRAPH */
+
+static void sort_nic_names(lboard_t *) ;
+
+u64 klgraph_addr[MAX_COMPACT_NODES];
+int module_number = 0;
+
+lboard_t *
+find_lboard(lboard_t *start, unsigned char brd_type)
+{
+	/* Search all boards stored on this node. */
+	while (start) {
+		if (start->brd_type == brd_type)
+			return start;
+		start = KLCF_NEXT(start);
+	}
+
+	/* Didn't find it. */
+	return (lboard_t *)NULL;
+}
+
+lboard_t *
+find_lboard_class(lboard_t *start, unsigned char brd_type)
+{
+	/* Search all boards stored on this node. */
+	while (start) {
+		if (KLCLASS(start->brd_type) == KLCLASS(brd_type))
+			return start;
+		start = KLCF_NEXT(start);
+	}
+
+	/* Didn't find it. */
+	return (lboard_t *)NULL;
+}
+
+klinfo_t *
+find_component(lboard_t *brd, klinfo_t *kli, unsigned char struct_type)
+{
+	int index, j;
+
+	if (kli == (klinfo_t *)NULL) {
+		index = 0;
+	} else {
+		for (j = 0; j < KLCF_NUM_COMPS(brd); j++) {
+			if (kli == KLCF_COMP(brd, j))
+				break;
+		}
+		index = j;
+		if (index == KLCF_NUM_COMPS(brd)) {
+			DBG("find_component: Bad pointer: 0x%p\n", kli);
+			return (klinfo_t *)NULL;
+		}
+		index++;	/* next component */
+	}
+	
+	for (; index < KLCF_NUM_COMPS(brd); index++) {		
+		kli = KLCF_COMP(brd, index);
+		DBG("find_component: brd %p kli %p  request type = 0x%x kli type 0x%x\n", brd, kli, kli->struct_type, KLCF_COMP_TYPE(kli));
+		if (KLCF_COMP_TYPE(kli) == struct_type)
+			return kli;
+	}
+
+	/* Didn't find it. */
+	return (klinfo_t *)NULL;
+}
+
+klinfo_t *
+find_first_component(lboard_t *brd, unsigned char struct_type)
+{
+	return find_component(brd, (klinfo_t *)NULL, struct_type);
+}
+
+lboard_t *
+find_lboard_modslot(lboard_t *start, geoid_t geoid)
+{
+	/* Search all boards stored on this node. */
+	while (start) {
+		if (geo_cmp(start->brd_geoid, geoid))
+			return start;
+		start = KLCF_NEXT(start);
+	}
+
+	/* Didn't find it. */
+	return (lboard_t *)NULL;
+}
+
+lboard_t *
+find_lboard_module(lboard_t *start, geoid_t geoid)
+{
+        /* Search all boards stored on this node. */
+        while (start) {
+                if (geo_cmp(start->brd_geoid, geoid))
+                        return start;
+                start = KLCF_NEXT(start);
+        }
+
+        /* Didn't find it. */
+        return (lboard_t *)NULL;
+}
+
+lboard_t *
+find_lboard_module_class(lboard_t *start, geoid_t geoid,
+                                                unsigned char brd_type)
+{
+	while (start) {
+		DBG("find_lboard_module_class: lboard 0x%p, start->brd_geoid 0x%x, mod 0x%x, start->brd_type 0x%x, brd_type 0x%x\n", start, start->brd_geoid, geoid, start->brd_type, brd_type);
+
+		if (geo_cmp(start->brd_geoid, geoid) &&
+			(KLCLASS(start->brd_type) == KLCLASS(brd_type)))
+			return start;
+		start = KLCF_NEXT(start);
+	}
+
+	/* Didn't find it. */
+	return (lboard_t *)NULL;
+}
+
+/*
+ * Convert a NIC name to a name for use in the hardware graph.
+ */
+void
+nic_name_convert(char *old_name, char *new_name)
+{
+        int i;
+        char c;
+        char *compare_ptr;
+
+	if ((old_name[0] == '\0') || (old_name[1] == '\0')) {
+                strcpy(new_name, EDGE_LBL_XWIDGET);
+        } else {
+                for (i = 0; i < strlen(old_name); i++) {
+                        c = old_name[i];
+
+                        if (isalpha(c))
+                                new_name[i] = tolower(c);
+                        else if (isdigit(c))
+                                new_name[i] = c;
+                        else
+                                new_name[i] = '_';
+                }
+                new_name[i] = '\0';
+        }
+
+        /* XXX -
+         * Since a bunch of boards made it out with weird names like
+         * IO6-fibbbed and IO6P2, we need to look for IO6 in a name and
+         * replace it with "baseio" to avoid confusion in the field.
+	 * We also have to make sure we don't report media_io instead of
+	 * baseio.
+         */
+
+        /* Skip underscores at the beginning of the name */
+        for (compare_ptr = new_name; (*compare_ptr) == '_'; compare_ptr++)
+                ;
+
+	/*
+	 * Check for some names we need to replace.  Early boards
+	 * had junk following the name so check only the first
+	 * characters.
+	 */
+        if (!strncmp(new_name, "io6", 3) || 
+            !strncmp(new_name, "mio", 3) || 
+	    !strncmp(new_name, "media_io", 8))
+		strcpy(new_name, "baseio");
+	else if (!strncmp(new_name, "divo", 4))
+		strcpy(new_name, "divo") ;
+
+}
+
+/*
+ * Find the lboard structure and get the board name.
+ * If we can't find the structure or it's too low a revision,
+ * use default name.
+ */
+lboard_t *
+get_board_name(nasid_t nasid, geoid_t geoid, slotid_t slot, char *name)
+{
+	lboard_t *brd;
+
+	brd = find_lboard_modslot((lboard_t *)KL_CONFIG_INFO(nasid),
+				  geoid);
+
+#ifndef _STANDALONE
+	{
+		cnodeid_t cnode = NASID_TO_COMPACT_NODEID(nasid);
+
+		if (!brd && (NODEPDA(cnode)->xbow_peer != INVALID_NASID))
+			brd = find_lboard_modslot((lboard_t *)
+				KL_CONFIG_INFO(NODEPDA(cnode)->xbow_peer),
+				geoid);
+	}
+#endif
+
+	if (!brd || (brd->brd_sversion < 2)) {
+		strcpy(name, EDGE_LBL_XWIDGET);
+	} else {
+		nic_name_convert(brd->brd_name, name);
+	}
+
+	/*
+	 * PV # 540860
+	 * If the name is not 'baseio'
+	 * get the lowest of all the names in the nic string.
+	 * This is needed for boards like divo, which can have
+	 * a bunch of daughter cards, but would like to be called
+	 * divo. We could do this for baseio
+	 * but it has some special case names that we would not
+	 * like to disturb at this point.
+	 */
+
+	/* gfx boards don't need any of this name scrambling */
+	if (brd && (KLCLASS(brd->brd_type) == KLCLASS_GFX)) {
+		return(brd);
+	}
+
+	if (!(!strcmp(name, "baseio") )) {
+		if (brd) {
+			sort_nic_names(brd) ;
+			/* Convert to small case, '-' to '_' etc */
+			nic_name_convert(brd->brd_name, name) ;
+		}
+	}
+
+	return(brd);
+}
+
+/*
+ * get_actual_nasid
+ *
+ *	Completely disabled brds have their klconfig on 
+ *	some other nasid as they have no memory. But their
+ *	actual nasid is hidden in the klconfig. Use this
+ *	routine to get it. Works for normal boards too.
+ */
+nasid_t
+get_actual_nasid(lboard_t *brd)
+{
+	klhub_t	*hub ;
+
+	if (!brd)
+		return INVALID_NASID ;
+
+	/* find out if we are a completely disabled brd. */
+
+        hub  = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB);
+	if (!hub)
+                return INVALID_NASID ;
+	if (!(hub->hub_info.flags & KLINFO_ENABLE))	/* disabled node brd */
+		return hub->hub_info.physid ;
+	else
+		return brd->brd_nasid ;
+}
+
+int
+xbow_port_io_enabled(nasid_t nasid, int link)
+{
+	lboard_t *brd;
+	klxbow_t *xbow_p;
+
+	/*
+	 * look for boards that might contain an xbow or xbridge
+	 */
+	brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IOBRICK_XBOW);
+	if (brd == NULL) return 0;
+		
+	if ((xbow_p = (klxbow_t *)find_component(brd, NULL, KLSTRUCT_XBOW))
+	    == NULL)
+	    return 0;
+
+	if (!XBOW_PORT_TYPE_IO(xbow_p, link) || !XBOW_PORT_IS_ENABLED(xbow_p, link))
+	    return 0;
+
+	return 1;
+}
+
+void
+board_to_path(lboard_t *brd, char *path)
+{
+	moduleid_t modnum;
+	char *board_name;
+	char buffer[16];
+
+	ASSERT(brd);
+
+	switch (KLCLASS(brd->brd_type)) {
+
+		case KLCLASS_NODE:
+			board_name = EDGE_LBL_NODE;
+			break;
+		case KLCLASS_ROUTER:
+			if (brd->brd_type == KLTYPE_META_ROUTER) {
+				board_name = EDGE_LBL_META_ROUTER;
+				hasmetarouter++;
+			} else if (brd->brd_type == KLTYPE_REPEATER_ROUTER) {
+				board_name = EDGE_LBL_REPEATER_ROUTER;
+				hasmetarouter++;
+			} else
+				board_name = EDGE_LBL_ROUTER;
+			break;
+		case KLCLASS_MIDPLANE:
+			board_name = EDGE_LBL_MIDPLANE;
+			break;
+		case KLCLASS_IO:
+			board_name = EDGE_LBL_IO;
+			break;
+		case KLCLASS_IOBRICK:
+			if (brd->brd_type == KLTYPE_PBRICK)
+				board_name = EDGE_LBL_PBRICK;
+			else if (brd->brd_type == KLTYPE_IBRICK)
+				board_name = EDGE_LBL_IBRICK;
+			else if (brd->brd_type == KLTYPE_XBRICK)
+				board_name = EDGE_LBL_XBRICK;
+			else
+				board_name = EDGE_LBL_IOBRICK;
+			break;
+		default:
+			board_name = EDGE_LBL_UNKNOWN;
+	}
+			
+	modnum = geo_module(brd->brd_geoid);
+	memset(buffer, 0, 16);
+	format_module_id(buffer, modnum, MODULE_FORMAT_BRIEF);
+	sprintf(path, EDGE_LBL_MODULE "/%s/" EDGE_LBL_SLAB "/%d/%s", buffer, geo_slab(brd->brd_geoid), board_name);
+}
+
+/*
+ * Get the module number for a NASID.
+ */
+moduleid_t
+get_module_id(nasid_t nasid)
+{
+	lboard_t *brd;
+
+	brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA);
+
+	if (!brd)
+		return INVALID_MODULE;
+	else
+		return geo_module(brd->brd_geoid);
+}
+
+
+#define MHZ	1000000
+
+
+/* Get the canonical hardware graph name for the given pci component
+ * on the given io board.
+ */
+void
+device_component_canonical_name_get(lboard_t 	*brd,
+				    klinfo_t 	*component,
+				    char 	*name)
+{
+	slotid_t 	slot;
+	char 		board_name[20];
+
+	ASSERT(brd);
+
+	/* Convert the [ CLASS | TYPE ] kind of slotid
+	 * into a string
+	 */
+	slot = brd->brd_slot;
+
+	/* Get the io board name  */
+	if (!brd || (brd->brd_sversion < 2)) {
+		strcpy(name, EDGE_LBL_XWIDGET);
+	} else {
+		nic_name_convert(brd->brd_name, board_name);
+	}
+
+	/* Give out the canonical  name of the pci device*/
+	sprintf(name,
+		"/dev/hw/"EDGE_LBL_MODULE "/%x/"EDGE_LBL_SLAB"/%d/"
+		EDGE_LBL_SLOT"/%s/"EDGE_LBL_PCI"/%d",
+		geo_module(brd->brd_geoid), geo_slab(brd->brd_geoid), 
+		board_name, KLCF_BRIDGE_W_ID(component));
+}
+
+/*
+ * Get the serial number of the main  component of a board
+ * Returns 0 if a valid serial number is found
+ * 1 otherwise.
+ * Assumptions: Nic manufacturing string  has the following format
+ *			*Serial:<serial_number>;*
+ */
+static int
+component_serial_number_get(lboard_t 		*board,
+			    klconf_off_t 	mfg_nic_offset,
+			    char		*serial_number,
+			    char		*key_pattern)
+{
+
+	char	*mfg_nic_string;
+	char	*serial_string,*str;
+	int	i;
+	char	*serial_pattern = "Serial:";
+
+	/* We have an error on a null mfg nic offset */
+	if (!mfg_nic_offset)
+		return(1);
+	/* Get the hub's manufacturing nic information
+	 * which is in the form of a pre-formatted string
+	 */
+	mfg_nic_string = 
+		(char *)NODE_OFFSET_TO_K0(NASID_GET(board),
+					  mfg_nic_offset);
+	/* There is no manufacturing nic info */
+	if (!mfg_nic_string)
+		return(1);
+
+	str = mfg_nic_string;
+	/* Look for the key pattern first (if it is  specified)
+	 * and then print the serial number corresponding to that.
+	 */
+	if (strcmp(key_pattern,"") && 
+	    !(str = strstr(mfg_nic_string,key_pattern)))
+		return(1);
+
+	/* There is no serial number info in the manufacturing
+	 * nic info
+	 */
+	if (!(serial_string = strstr(str,serial_pattern)))
+		return(1);
+
+	serial_string = serial_string + strlen(serial_pattern);
+	/*  Copy the serial number information from the klconfig */
+	i = 0;
+	while (serial_string[i] != ';') {
+		serial_number[i] = serial_string[i];
+		i++;
+	}
+	serial_number[i] = 0;
+	
+	return(0);
+}
+/*
+ * Get the serial number of a board
+ * Returns 0 if a valid serial number is found
+ * 1 otherwise.
+ */
+
+int
+board_serial_number_get(lboard_t *board,char *serial_number)
+{
+	ASSERT(board && serial_number);
+	if (!board || !serial_number)
+		return(1);
+
+	strcpy(serial_number,"");
+	switch(KLCLASS(board->brd_type)) {
+	case KLCLASS_CPU: {	/* Node board */
+		klhub_t	*hub;
+		
+		/* Get the hub component information */
+		hub = (klhub_t *)find_first_component(board,
+						      KLSTRUCT_HUB);
+		/* If we don't have a hub component on an IP27
+		 * then we have a weird klconfig.
+		 */
+		if (!hub)
+			return(1);
+		/* Get the serial number information from
+		 * the hub's manufacturing nic info
+		 */
+		if (component_serial_number_get(board,
+						hub->hub_mfg_nic,
+						serial_number,
+						"IP37"))
+				return(1);
+		break;
+	}
+	case KLCLASS_IO: {	/* IO board */
+		if (KLTYPE(board->brd_type) == KLTYPE_TPU) {
+		/* Special case for TPU boards */
+			kltpu_t *tpu;	
+		
+			/* Get the tpu component information */
+			tpu = (kltpu_t *)find_first_component(board,
+						      KLSTRUCT_TPU);
+			/* If we don't have a tpu component on a tpu board
+			 * then we have a weird klconfig.
+			 */
+			if (!tpu)
+				return(1);
+			/* Get the serial number information from
+			 * the tpu's manufacturing nic info
+			 */
+			if (component_serial_number_get(board,
+						tpu->tpu_mfg_nic,
+						serial_number,
+						""))
+				return(1);
+			break;
+		} else  if ((KLTYPE(board->brd_type) == KLTYPE_GSN_A) ||
+		            (KLTYPE(board->brd_type) == KLTYPE_GSN_B)) {
+		/* Special case for GSN boards */
+			klgsn_t *gsn;	
+		
+			/* Get the gsn component information */
+			gsn = (klgsn_t *)find_first_component(board,
+			      ((KLTYPE(board->brd_type) == KLTYPE_GSN_A) ?
+					KLSTRUCT_GSN_A : KLSTRUCT_GSN_B));
+			/* If we don't have a gsn component on a gsn board
+			 * then we have a weird klconfig.
+			 */
+			if (!gsn)
+				return(1);
+			/* Get the serial number information from
+			 * the gsn's manufacturing nic info
+			 */
+			if (component_serial_number_get(board,
+						gsn->gsn_mfg_nic,
+						serial_number,
+						""))
+				return(1);
+			break;
+		} else {
+		     	klbri_t	*bridge;
+		
+			/* Get the bridge component information */
+			bridge = (klbri_t *)find_first_component(board,
+							 KLSTRUCT_BRI);
+			/* If we don't have a bridge component on an IO board
+			 * then we have a weird klconfig.
+			 */
+			if (!bridge)
+				return(1);
+			/* Get the serial number information from
+		 	 * the bridge's manufacturing nic info
+			 */
+			if (component_serial_number_get(board,
+						bridge->bri_mfg_nic,
+						serial_number,
+						""))
+				return(1);
+			break;
+		}
+	}
+	case KLCLASS_ROUTER: {	/* Router board */
+		klrou_t *router;	
+		
+		/* Get the router component information */
+		router = (klrou_t *)find_first_component(board,
+							 KLSTRUCT_ROU);
+		/* If we don't have a router component on a router board
+		 * then we have a weird klconfig.
+		 */
+		if (!router)
+			return(1);
+		/* Get the serial number information from
+		 * the router's manufacturing nic info
+		 */
+		if (component_serial_number_get(board,
+						router->rou_mfg_nic,
+						serial_number,
+						""))
+			return(1);
+		break;
+	}
+	case KLCLASS_GFX: {	/* Gfx board */
+		klgfx_t *graphics;
+		
+		/* Get the graphics component information */
+		graphics = (klgfx_t *)find_first_component(board, KLSTRUCT_GFX);
+		/* If we don't have a gfx component on a gfx board
+		 * then we have a weird klconfig.
+		 */
+		if (!graphics)
+			return(1);
+		/* Get the serial number information from
+		 * the graphics's manufacturing nic info
+		 */
+		if (component_serial_number_get(board,
+						graphics->gfx_mfg_nic,
+						serial_number,
+						""))
+			return(1);
+		break;
+	}
+	default:
+		strcpy(serial_number,"");
+		break;
+	}
+	return(0);
+}
+
+#include "asm/sn/sn_private.h"
+
+xwidgetnum_t
+nodevertex_widgetnum_get(devfs_handle_t node_vtx)
+{
+	hubinfo_t hubinfo_p;
+
+	hwgraph_info_get_LBL(node_vtx, INFO_LBL_NODE_INFO, 
+			     (arbitrary_info_t *) &hubinfo_p);
+	return(hubinfo_p->h_widgetid);
+}
+
+devfs_handle_t
+nodevertex_xbow_peer_get(devfs_handle_t node_vtx)
+{
+	hubinfo_t hubinfo_p;
+	nasid_t xbow_peer_nasid;
+	cnodeid_t xbow_peer;
+
+	hwgraph_info_get_LBL(node_vtx, INFO_LBL_NODE_INFO,
+				     (arbitrary_info_t *) &hubinfo_p);
+	xbow_peer_nasid = hubinfo_p->h_nodepda->xbow_peer;
+	if(xbow_peer_nasid == INVALID_NASID) 
+			return ( (devfs_handle_t)-1);
+	xbow_peer = NASID_TO_COMPACT_NODEID(xbow_peer_nasid);
+	return(NODEPDA(xbow_peer)->node_vertex);
+}
+
+/* NIC Sorting Support */
+
+#define MAX_NICS_PER_STRING 	32
+#define MAX_NIC_NAME_LEN	32
+
+static char *
+get_nic_string(lboard_t *lb)
+{
+        int         	i;
+        klinfo_t    	*k = NULL ;
+    	klconf_off_t    mfg_off = 0 ;
+    	char            *mfg_nic = NULL ;
+
+        for (i = 0; i < KLCF_NUM_COMPS(lb); i++) {
+                k = KLCF_COMP(lb, i) ;
+                switch(k->struct_type) {
+                        case KLSTRUCT_BRI:
+            			mfg_off = ((klbri_t *)k)->bri_mfg_nic ;
+				break ;
+
+                        case KLSTRUCT_HUB:
+            			mfg_off = ((klhub_t *)k)->hub_mfg_nic ;
+				break ;
+
+                        case KLSTRUCT_ROU:
+            			mfg_off = ((klrou_t *)k)->rou_mfg_nic ;
+				break ;
+
+                        case KLSTRUCT_GFX:
+            			mfg_off = ((klgfx_t *)k)->gfx_mfg_nic ;
+				break ;
+
+                        case KLSTRUCT_TPU:
+            			mfg_off = ((kltpu_t *)k)->tpu_mfg_nic ;
+				break ;
+
+                        case KLSTRUCT_GSN_A:
+                        case KLSTRUCT_GSN_B:
+            			mfg_off = ((klgsn_t *)k)->gsn_mfg_nic ;
+				break ;
+
+                        case KLSTRUCT_XTHD:
+                                mfg_off = ((klxthd_t *)k)->xthd_mfg_nic ;
+                                break;
+
+			default:
+				mfg_off = 0 ;
+                                break ;
+                }
+		if (mfg_off)
+			break ;
+        }
+
+	if ((mfg_off) && (k))
+		mfg_nic = (char *)NODE_OFFSET_TO_K0(k->nasid, mfg_off) ;
+
+        return mfg_nic ;
+}
+
+char *
+get_first_string(char **ptrs, int n)
+{
+        int     i ;
+        char    *tmpptr ;
+
+        if ((ptrs == NULL) || (n == 0))
+                return NULL ;
+
+        tmpptr = ptrs[0] ;
+
+        if (n == 1)
+                return tmpptr ;
+
+        for (i = 0 ; i < n ; i++) {
+                if (strcmp(tmpptr, ptrs[i]) > 0)
+                        tmpptr = ptrs[i] ;
+        }
+
+        return tmpptr ;
+}
+
+int
+get_ptrs(char *idata, char **ptrs, int n, char *label)
+{
+        int     i = 0 ;
+        char    *tmp = idata ;
+
+        if ((ptrs == NULL) || (idata == NULL) || (label == NULL) || (n == 0))
+                return 0 ;
+
+        while  ( (tmp = strstr(tmp, label)) ){
+                tmp += strlen(label) ;
+                /* check for empty name field, and last NULL ptr */
+                if ((i < (n-1)) && (*tmp != ';')) {
+                        ptrs[i++] = tmp ;
+                }
+        }
+
+        ptrs[i] = NULL ;
+
+        return i ;
+}
+
+/*
+ * sort_nic_names
+ *
+ * 	Does not really do sorting. Find the alphabetically lowest
+ *	name among all the nic names found in a nic string.
+ *
+ * Return:
+ *	Nothing
+ *
+ * Side Effects:
+ *
+ *	lb->brd_name gets the new name found
+ */
+
+static void
+sort_nic_names(lboard_t *lb)
+{
+	char 	*nic_str ;
+        char    *ptrs[MAX_NICS_PER_STRING] ;
+        char    name[MAX_NIC_NAME_LEN] ;
+        char    *tmp, *tmp1 ;
+
+	*name = 0 ;
+
+	/* Get the nic pointer from the lb */
+
+	if ((nic_str = get_nic_string(lb)) == NULL)
+		return ;
+
+        tmp = get_first_string(ptrs,
+                        get_ptrs(nic_str, ptrs, MAX_NICS_PER_STRING, "Name:")) ;
+
+        if (tmp == NULL)
+		return ;
+
+        if  ( (tmp1 = strchr(tmp, ';')) ){
+                strncpy(name, tmp, tmp1-tmp) ;
+                name[tmp1-tmp] = 0 ;
+        } else {
+                strncpy(name, tmp, (sizeof(name) -1)) ;
+                name[sizeof(name)-1] = 0 ;
+        }
+
+	strcpy(lb->brd_name, name) ;
+}
+
+
+
+char brick_types[MAX_BRICK_TYPES + 1] = "crikxdpn%#012345";
+
+/*
+ * Format a module id for printing.
+ */
+void
+format_module_id(char *buffer, moduleid_t m, int fmt)
+{
+	int rack, position;
+	char brickchar;
+
+	rack = MODULE_GET_RACK(m);
+	ASSERT(MODULE_GET_BTYPE(m) < MAX_BRICK_TYPES);
+	brickchar = MODULE_GET_BTCHAR(m);
+	position = MODULE_GET_BPOS(m);
+
+	if (fmt == MODULE_FORMAT_BRIEF) {
+	    /* Brief module number format, eg. 002c15 */
+
+	    /* Decompress the rack number */
+	    *buffer++ = '0' + RACK_GET_CLASS(rack);
+	    *buffer++ = '0' + RACK_GET_GROUP(rack);
+	    *buffer++ = '0' + RACK_GET_NUM(rack);
+
+	    /* Add the brick type */
+	    *buffer++ = brickchar;
+	}
+	else if (fmt == MODULE_FORMAT_LONG) {
+	    /* Fuller hwgraph format, eg. rack/002/bay/15 */
+
+	    strcpy(buffer, EDGE_LBL_RACK "/");  buffer += strlen(buffer);
+
+	    *buffer++ = '0' + RACK_GET_CLASS(rack);
+	    *buffer++ = '0' + RACK_GET_GROUP(rack);
+	    *buffer++ = '0' + RACK_GET_NUM(rack);
+
+	    strcpy(buffer, "/" EDGE_LBL_RPOS "/");  buffer += strlen(buffer);
+	}
+
+	/* Add the bay position, using at least two digits */
+	if (position < 10)
+	    *buffer++ = '0';
+	sprintf(buffer, "%d", position);
+
+}
+
+/*
+ * Parse a module id, in either brief or long form.
+ * Returns < 0 on error.
+ * The long form does not include a brick type, so it defaults to 0 (CBrick)
+ */
+int
+parse_module_id(char *buffer)
+{
+	unsigned int	v, rack, bay, type, form;
+	moduleid_t	m;
+	char 		c;
+
+	if (strstr(buffer, EDGE_LBL_RACK "/") == buffer) {
+		form = MODULE_FORMAT_LONG;
+		buffer += strlen(EDGE_LBL_RACK "/");
+
+		/* A long module ID must be exactly 5 non-template chars. */
+		if (strlen(buffer) != strlen("/" EDGE_LBL_RPOS "/") + 5)
+			return -1;
+	}
+	else {
+		form = MODULE_FORMAT_BRIEF;
+
+		/* A brief module id must be exactly 6 characters */
+		if (strlen(buffer) != 6)
+			return -2;
+	}
+
+	/* The rack number must be exactly 3 digits */
+	if (!(isdigit(buffer[0]) && isdigit(buffer[1]) && isdigit(buffer[2])))
+		return -3;
+
+	rack = 0;
+	v = *buffer++ - '0';
+	if (v > RACK_CLASS_MASK(rack) >> RACK_CLASS_SHFT(rack))
+		return -4;
+	RACK_ADD_CLASS(rack, v);
+
+	v = *buffer++ - '0';
+	if (v > RACK_GROUP_MASK(rack) >> RACK_GROUP_SHFT(rack))
+		return -5;
+	RACK_ADD_GROUP(rack, v);
+
+	v = *buffer++ - '0';
+	/* rack numbers are 1-based */
+	if (v-1 > RACK_NUM_MASK(rack) >> RACK_NUM_SHFT(rack))
+		return -6;
+	RACK_ADD_NUM(rack, v);
+
+	if (form == MODULE_FORMAT_BRIEF) {
+		/* Next should be a module type character.  Accept ucase or lcase. */
+		c = *buffer++;
+		if (!isalpha(c))
+			return -7;
+
+		/* strchr() returns a pointer into brick_types[], or NULL */
+		type = (unsigned int)(strchr(brick_types, tolower(c)) - brick_types);
+		if (type > MODULE_BTYPE_MASK >> MODULE_BTYPE_SHFT)
+			return -8;
+	}
+	else {
+		/* Hardcode the module type, and skip over the boilerplate */
+		type = MODULE_CBRICK;
+
+		if (strstr(buffer, "/" EDGE_LBL_RPOS "/") != buffer)
+			return -9;
+
+		buffer += strlen("/" EDGE_LBL_RPOS "/");
+	}
+		
+	/* The bay number is last.  Make sure it's exactly two digits */
+
+	if (!(isdigit(buffer[0]) && isdigit(buffer[1]) && !buffer[2]))
+		return -10;
+
+	bay = 10 * (buffer[0] - '0') + (buffer[1] - '0');
+
+	if (bay > MODULE_BPOS_MASK >> MODULE_BPOS_SHFT)
+		return -11;
+
+	m = RBT_TO_MODULE(rack, bay, type);
+
+	/* avoid sign extending the moduleid_t */
+	return (int)(unsigned short)m;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/klgraph.c linux-2.4.21-pre6/arch/ia64/sn/io/sn2/klgraph.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/klgraph.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn2/klgraph.c	2003-03-26 23:48:59.000000000 +0000
@@ -0,0 +1,866 @@
+/* $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) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+/*
+ * klgraph.c-
+ *      This file specifies the interface between the kernel and the PROM's
+ *      configuration data structures.
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/io.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/kldir.h>
+#include <asm/sn/gda.h> 
+#include <asm/sn/klconfig.h>
+#include <asm/sn/router.h>
+#include <asm/sn/xtalk/xbow.h>
+#include <asm/sn/hcl_util.h>
+
+// #define KLGRAPH_DEBUG 1
+#ifdef KLGRAPH_DEBUG
+#define GRPRINTF(x)	printk x
+#define CE_GRPANIC	CE_PANIC
+#else
+#define GRPRINTF(x)
+#define CE_GRPANIC	CE_PANIC
+#endif
+
+#include <asm/sn/sn_private.h>
+
+extern char arg_maxnodes[];
+extern u64 klgraph_addr[];
+void mark_cpuvertex_as_cpu(devfs_handle_t vhdl, cpuid_t cpuid);
+
+
+/*
+ * Support for verbose inventory via hardware graph. 
+ * klhwg_invent_alloc allocates the necessary size of inventory information
+ * and fills in the generic information.
+ */
+invent_generic_t *
+klhwg_invent_alloc(cnodeid_t cnode, int class, int size)
+{
+	invent_generic_t *invent;
+
+	invent = kern_malloc(size);
+	if (!invent) return NULL;
+	
+	invent->ig_module = NODE_MODULEID(cnode);
+	invent->ig_slot = SLOTNUM_GETSLOT(NODE_SLOTID(cnode));
+	invent->ig_invclass = class;
+
+	return invent;
+}
+
+/*
+ * Add detailed disabled cpu inventory info to the hardware graph.
+ */
+void
+klhwg_disabled_cpu_invent_info(devfs_handle_t cpuv,
+                               cnodeid_t cnode,
+                               klcpu_t *cpu, slotid_t slot)
+{
+	invent_cpuinfo_t *cpu_invent;
+	diag_inv_t       *diag_invent;
+
+	cpu_invent = (invent_cpuinfo_t *)
+	klhwg_invent_alloc(cnode, INV_PROCESSOR, sizeof(invent_cpuinfo_t));
+	if (!cpu_invent)
+		return;
+
+	/* Diag information on this processor */
+	diag_invent = (diag_inv_t *)
+	klhwg_invent_alloc(cnode, INV_CPUDIAGVAL, sizeof(diag_inv_t));
+
+	if (!diag_invent)
+		return;
+
+
+	/* Disabled CPU */
+	cpu_invent->ic_gen.ig_flag = 0x0;
+	cpu_invent->ic_gen.ig_slot = slot;
+	cpu_invent->ic_cpu_info.cpuflavor = cpu->cpu_prid;
+	cpu_invent->ic_cpu_info.cpufq = cpu->cpu_speed;
+	cpu_invent->ic_cpu_info.sdfreq = cpu->cpu_scachespeed;
+
+	cpu_invent->ic_cpu_info.sdsize = cpu->cpu_scachesz;
+	cpu_invent->ic_cpuid = cpu->cpu_info.virtid;
+	cpu_invent->ic_slice = cpu->cpu_info.physid;
+
+	/* Disabled CPU label */
+	hwgraph_info_add_LBL(cpuv, INFO_LBL_DETAIL_INVENT,
+			(arbitrary_info_t) cpu_invent);
+	hwgraph_info_export_LBL(cpuv, INFO_LBL_DETAIL_INVENT,
+			sizeof(invent_cpuinfo_t));
+
+	/* Diagval label - stores reason for disable +{virt,phys}id +diagval*/
+	hwgraph_info_add_LBL(cpuv, INFO_LBL_DIAGVAL,
+			(arbitrary_info_t) diag_invent);
+
+	hwgraph_info_export_LBL(cpuv, INFO_LBL_DIAGVAL,
+			sizeof(diag_inv_t));
+}
+
+/*
+ * Add detailed cpu inventory info to the hardware graph.
+ */
+void
+klhwg_cpu_invent_info(devfs_handle_t cpuv,
+			cnodeid_t cnode,
+			klcpu_t *cpu)
+{
+	invent_cpuinfo_t *cpu_invent;
+
+	cpu_invent = (invent_cpuinfo_t *)
+		klhwg_invent_alloc(cnode, INV_PROCESSOR, sizeof(invent_cpuinfo_t));
+	if (!cpu_invent)
+		return;
+
+	if (KLCONFIG_INFO_ENABLED((klinfo_t *)cpu))
+		cpu_invent->ic_gen.ig_flag = INVENT_ENABLED;
+	else
+		cpu_invent->ic_gen.ig_flag = 0x0;
+
+	cpu_invent->ic_cpu_info.cpuflavor = cpu->cpu_prid;
+	cpu_invent->ic_cpu_info.cpufq = cpu->cpu_speed;
+	cpu_invent->ic_cpu_info.sdfreq = cpu->cpu_scachespeed;
+
+	cpu_invent->ic_cpu_info.sdsize = cpu->cpu_scachesz;
+	cpu_invent->ic_cpuid = cpu->cpu_info.virtid;
+	cpu_invent->ic_slice = cpu_physical_id_to_slice(cpu->cpu_info.virtid);
+
+	hwgraph_info_add_LBL(cpuv, INFO_LBL_DETAIL_INVENT,
+			(arbitrary_info_t) cpu_invent);
+	hwgraph_info_export_LBL(cpuv, INFO_LBL_DETAIL_INVENT,
+			sizeof(invent_cpuinfo_t));
+}
+
+/* 
+ * Add information about the baseio prom version number
+ * as a part of detailed inventory info in the hwgraph.
+ */
+void
+klhwg_baseio_inventory_add(devfs_handle_t baseio_vhdl,cnodeid_t cnode)
+{
+	invent_miscinfo_t	*baseio_inventory;
+	unsigned char		version = 0,revision = 0;
+
+	/* Allocate memory for the "detailed inventory" info
+	 * for the baseio
+	 */
+	baseio_inventory = (invent_miscinfo_t *) 
+		klhwg_invent_alloc(cnode, INV_PROM, sizeof(invent_miscinfo_t));
+	baseio_inventory->im_type = INV_IO6PROM;
+	/* Store the revision info  in the inventory */
+	baseio_inventory->im_version = version;
+	baseio_inventory->im_rev = revision;
+	/* Put the inventory info in the hardware graph */
+	hwgraph_info_add_LBL(baseio_vhdl, INFO_LBL_DETAIL_INVENT, 
+			     (arbitrary_info_t) baseio_inventory);
+	/* Make the information available to the user programs
+	 * thru hwgfs.
+	 */
+        hwgraph_info_export_LBL(baseio_vhdl, INFO_LBL_DETAIL_INVENT,
+				sizeof(invent_miscinfo_t));
+}
+
+char	*hub_rev[] = {
+	"0.0",
+	"1.0",
+	"2.0",
+	"2.1",
+	"2.2",
+	"2.3"
+};
+
+/*
+ * Add detailed cpu inventory info to the hardware graph.
+ */
+void
+klhwg_hub_invent_info(devfs_handle_t hubv,
+		      cnodeid_t cnode, 
+		      klhub_t *hub)
+{
+	invent_miscinfo_t *hub_invent;
+
+	hub_invent = (invent_miscinfo_t *) 
+	    klhwg_invent_alloc(cnode, INV_MISC, sizeof(invent_miscinfo_t));
+	if (!hub_invent)
+	    return;
+
+	if (KLCONFIG_INFO_ENABLED((klinfo_t *)hub))
+	    hub_invent->im_gen.ig_flag = INVENT_ENABLED;
+
+	hub_invent->im_type = INV_HUB;
+	hub_invent->im_rev = hub->hub_info.revision;
+	hub_invent->im_speed = hub->hub_speed;
+	hwgraph_info_add_LBL(hubv, INFO_LBL_DETAIL_INVENT, 
+			     (arbitrary_info_t) hub_invent);
+        hwgraph_info_export_LBL(hubv, INFO_LBL_DETAIL_INVENT,
+				sizeof(invent_miscinfo_t));
+}
+
+/* ARGSUSED */
+void
+klhwg_add_hub(devfs_handle_t node_vertex, klhub_t *hub, cnodeid_t cnode)
+{
+	devfs_handle_t myhubv;
+	devfs_handle_t hub_mon;
+	int rc;
+	extern struct file_operations shub_mon_fops;
+
+	GRPRINTF(("klhwg_add_hub: adding %s\n", EDGE_LBL_HUB));
+	(void) hwgraph_path_add(node_vertex, EDGE_LBL_HUB, &myhubv);
+	rc = device_master_set(myhubv, node_vertex);
+	hub_mon = hwgraph_register(myhubv, EDGE_LBL_PERFMON,
+		0, DEVFS_FL_AUTO_DEVNUM,
+		0, 0,
+		S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0,
+		&shub_mon_fops, (void *)(long)cnode);
+}
+
+/* ARGSUSED */
+void
+klhwg_add_disabled_cpu(devfs_handle_t node_vertex, cnodeid_t cnode, klcpu_t *cpu, slotid_t slot)
+{
+        devfs_handle_t my_cpu;
+        char name[120];
+        cpuid_t cpu_id;
+	nasid_t nasid;
+
+	nasid = COMPACT_TO_NASID_NODEID(cnode);
+        cpu_id = nasid_slice_to_cpuid(nasid, cpu->cpu_info.physid);
+        if(cpu_id != -1){
+		sprintf(name, "%s/%s/%c", EDGE_LBL_DISABLED, EDGE_LBL_CPU, 'a' + cpu->cpu_info.physid);
+		(void) hwgraph_path_add(node_vertex, name, &my_cpu);
+
+		mark_cpuvertex_as_cpu(my_cpu, cpu_id);
+		device_master_set(my_cpu, node_vertex);
+
+		klhwg_disabled_cpu_invent_info(my_cpu, cnode, cpu, slot);
+		return;
+        }
+}
+
+/* ARGSUSED */
+void
+klhwg_add_cpu(devfs_handle_t node_vertex, cnodeid_t cnode, klcpu_t *cpu)
+{
+        devfs_handle_t my_cpu, cpu_dir;
+        char name[120];
+        cpuid_t cpu_id;
+	nasid_t nasid;
+
+	nasid = COMPACT_TO_NASID_NODEID(cnode);
+        cpu_id = nasid_slice_to_cpuid(nasid, cpu->cpu_info.physid);
+
+        sprintf(name, "%s/%d/%c",
+                EDGE_LBL_CPUBUS,
+                0,
+                'a' + cpu->cpu_info.physid);
+
+        GRPRINTF(("klhwg_add_cpu: adding %s to vertex 0x%p\n", name, node_vertex));
+        (void) hwgraph_path_add(node_vertex, name, &my_cpu);
+        mark_cpuvertex_as_cpu(my_cpu, cpu_id);
+        device_master_set(my_cpu, node_vertex);
+
+        /* Add an alias under the node's CPU directory */
+        if (hwgraph_edge_get(node_vertex, EDGE_LBL_CPU, &cpu_dir) == GRAPH_SUCCESS) {
+                sprintf(name, "%c", 'a' + cpu->cpu_info.physid);
+                (void) hwgraph_edge_add(cpu_dir, my_cpu, name);
+        }
+
+        klhwg_cpu_invent_info(my_cpu, cnode, cpu);
+}
+
+
+void
+klhwg_add_xbow(cnodeid_t cnode, nasid_t nasid)
+{
+	lboard_t *brd;
+	klxbow_t *xbow_p;
+	nasid_t hub_nasid;
+	cnodeid_t hub_cnode;
+	int widgetnum;
+	devfs_handle_t xbow_v, hubv;
+	/*REFERENCED*/
+	graph_error_t err;
+
+	if ((brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IOBRICK_XBOW)) == NULL)
+			return;
+
+	if (KL_CONFIG_DUPLICATE_BOARD(brd))
+	    return;
+
+	GRPRINTF(("klhwg_add_xbow: adding cnode %d nasid %d xbow edges\n",
+			cnode, nasid));
+
+	if ((xbow_p = (klxbow_t *)find_component(brd, NULL, KLSTRUCT_XBOW))
+	    == NULL)
+	    return;
+
+	for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) {
+		if (!XBOW_PORT_TYPE_HUB(xbow_p, widgetnum)) 
+		    continue;
+
+		hub_nasid = XBOW_PORT_NASID(xbow_p, widgetnum);
+		if (hub_nasid == INVALID_NASID) {
+			printk(KERN_WARNING  "hub widget %d, skipping xbow graph\n", widgetnum);
+			continue;
+		}
+
+		hub_cnode = NASID_TO_COMPACT_NODEID(hub_nasid);
+
+		if (is_specified(arg_maxnodes) && hub_cnode == INVALID_CNODEID) {
+			continue;
+		}
+			
+		hubv = cnodeid_to_vertex(hub_cnode);
+
+		err = hwgraph_path_add(hubv, EDGE_LBL_XTALK, &xbow_v);
+                if (err != GRAPH_SUCCESS) {
+                        if (err == GRAPH_DUP)
+                                printk(KERN_WARNING  "klhwg_add_xbow: Check for "
+                                        "working routers and router links!");
+
+                        PRINT_PANIC("klhwg_add_xbow: Failed to add "
+                                "edge: vertex 0x%p to vertex 0x%p,"
+                                "error %d\n",
+                                (void *)hubv, (void *)xbow_v, err);
+                }
+		xswitch_vertex_init(xbow_v); 
+
+		NODEPDA(hub_cnode)->xbow_vhdl = xbow_v;
+
+		/*
+		 * XXX - This won't work is we ever hook up two hubs
+		 * by crosstown through a crossbow.
+		 */
+		if (hub_nasid != nasid) {
+			NODEPDA(hub_cnode)->xbow_peer = nasid;
+			NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->xbow_peer =
+				hub_nasid;
+		}
+
+		GRPRINTF(("klhwg_add_xbow: adding port nasid %d %s to vertex 0x%p\n",
+			hub_nasid, EDGE_LBL_XTALK, hubv));
+	}
+}
+
+
+/* ARGSUSED */
+void
+klhwg_add_node(devfs_handle_t hwgraph_root, cnodeid_t cnode, gda_t *gdap)
+{
+	nasid_t nasid;
+	lboard_t *brd;
+	klhub_t *hub;
+	devfs_handle_t node_vertex = NULL;
+	char path_buffer[100];
+	int rv;
+	char *s;
+	int board_disabled = 0;
+	klcpu_t *cpu;
+
+	nasid = COMPACT_TO_NASID_NODEID(cnode);
+	brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA);
+	GRPRINTF(("klhwg_add_node: Adding cnode %d, nasid %d, brd 0x%p\n",
+                cnode, nasid, brd));
+	ASSERT(brd);
+
+	do {
+		devfs_handle_t cpu_dir;
+
+		/* Generate a hardware graph path for this board. */
+		board_to_path(brd, path_buffer);
+
+		GRPRINTF(("klhwg_add_node: adding %s to vertex 0x%p\n",
+			path_buffer, hwgraph_root));
+		rv = hwgraph_path_add(hwgraph_root, path_buffer, &node_vertex);
+
+		if (rv != GRAPH_SUCCESS)
+			PRINT_PANIC("Node vertex creation failed.  "
+					  "Path == %s",
+				path_buffer);
+
+		hub = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB);
+		ASSERT(hub);
+		if(hub->hub_info.flags & KLINFO_ENABLE)
+			board_disabled = 0;
+		else
+			board_disabled = 1;
+		
+		if(!board_disabled) {
+			mark_nodevertex_as_node(node_vertex,
+					    cnode + board_disabled * numnodes);
+
+			s = dev_to_name(node_vertex, path_buffer, sizeof(path_buffer));
+			NODEPDA(cnode)->hwg_node_name =
+						kmalloc(strlen(s) + 1,
+						GFP_KERNEL);
+			ASSERT_ALWAYS(NODEPDA(cnode)->hwg_node_name != NULL);
+			strcpy(NODEPDA(cnode)->hwg_node_name, s);
+
+			hubinfo_set(node_vertex, NODEPDA(cnode)->pdinfo);
+
+			/* Set up node board's slot */
+			NODEPDA(cnode)->slotdesc = brd->brd_slot;
+
+			/* Set up the module we're in */
+			NODEPDA(cnode)->geoid = brd->brd_geoid;
+			NODEPDA(cnode)->module = module_lookup(geo_module(brd->brd_geoid));
+		}
+
+		/* Get the first CPU structure */
+		cpu = (klcpu_t *)find_first_component(brd, KLSTRUCT_CPU);
+
+		/*
+		* If there's at least 1 CPU, add a "cpu" directory to represent
+		* the collection of all CPUs attached to this node.
+		*/
+		if (cpu) {
+			graph_error_t rv;
+
+			rv = hwgraph_path_add(node_vertex, EDGE_LBL_CPU, &cpu_dir);
+			if (rv != GRAPH_SUCCESS)
+				panic("klhwg_add_node: Cannot create CPU directory\n");
+		}
+
+		/* Add each CPU */
+		while (cpu) {
+			cpuid_t cpu_id;
+			cpu_id = nasid_slice_to_cpuid(nasid,cpu->cpu_info.physid);
+			if (cpu_enabled(cpu_id))
+				klhwg_add_cpu(node_vertex, cnode, cpu);
+			else
+				klhwg_add_disabled_cpu(node_vertex, cnode, cpu, brd->brd_slot);
+
+			cpu = (klcpu_t *)
+				find_component(brd, (klinfo_t *)cpu, KLSTRUCT_CPU);
+		} /* while */
+
+		if(!board_disabled)
+			klhwg_add_hub(node_vertex, hub, cnode);
+		
+		brd = KLCF_NEXT(brd);
+		if (brd)
+			brd = find_lboard(brd, KLTYPE_SNIA);
+		else
+			break;
+	} while(brd);
+}
+
+
+/* ARGSUSED */
+void
+klhwg_add_all_routers(devfs_handle_t hwgraph_root)
+{
+	nasid_t nasid;
+	cnodeid_t cnode;
+	lboard_t *brd;
+	devfs_handle_t node_vertex;
+	char path_buffer[100];
+	int rv;
+
+	for (cnode = 0; cnode < numnodes; cnode++) {
+		nasid = COMPACT_TO_NASID_NODEID(cnode);
+
+		GRPRINTF(("klhwg_add_all_routers: adding router on cnode %d\n",
+			cnode));
+
+		brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid),
+				KLTYPE_ROUTER);
+
+		if (!brd)
+			/* No routers stored in this node's memory */
+			continue;
+
+		do {
+			ASSERT(brd);
+			GRPRINTF(("Router board struct is %p\n", brd));
+
+			/* Don't add duplicate boards. */
+			if (brd->brd_flags & DUPLICATE_BOARD)
+				continue;
+
+			GRPRINTF(("Router 0x%p module number is %d\n", brd, brd->brd_geoid));
+			/* Generate a hardware graph path for this board. */
+			board_to_path(brd, path_buffer);
+
+			GRPRINTF(("Router path is %s\n", path_buffer));
+
+			/* Add the router */
+			GRPRINTF(("klhwg_add_all_routers: adding %s to vertex 0x%p\n",
+				path_buffer, hwgraph_root));
+			rv = hwgraph_path_add(hwgraph_root, path_buffer, &node_vertex);
+
+			if (rv != GRAPH_SUCCESS)
+				PRINT_PANIC("Router vertex creation "
+						  "failed.  Path == %s",
+					path_buffer);
+
+			GRPRINTF(("klhwg_add_all_routers: get next board from 0x%p\n",
+					brd));
+		/* Find the rest of the routers stored on this node. */
+		} while ( (brd = find_lboard_class(KLCF_NEXT(brd),
+			 KLTYPE_ROUTER)) );
+
+		GRPRINTF(("klhwg_add_all_routers: Done.\n"));
+	}
+
+}
+
+/* ARGSUSED */
+void
+klhwg_connect_one_router(devfs_handle_t hwgraph_root, lboard_t *brd,
+			 cnodeid_t cnode, nasid_t nasid)
+{
+	klrou_t *router;
+	char path_buffer[50];
+	char dest_path[50];
+	devfs_handle_t router_hndl;
+	devfs_handle_t dest_hndl;
+	int rc;
+	int port;
+	lboard_t *dest_brd;
+
+	GRPRINTF(("klhwg_connect_one_router: Connecting router on cnode %d\n",
+			cnode));
+
+	/* Don't add duplicate boards. */
+	if (brd->brd_flags & DUPLICATE_BOARD) {
+		GRPRINTF(("klhwg_connect_one_router: Duplicate router 0x%p on cnode %d\n",
+			brd, cnode));
+		return;
+	}
+
+	/* Generate a hardware graph path for this board. */
+	board_to_path(brd, path_buffer);
+
+	rc = hwgraph_traverse(hwgraph_root, path_buffer, &router_hndl);
+
+	if (rc != GRAPH_SUCCESS && is_specified(arg_maxnodes))
+			return;
+
+	if (rc != GRAPH_SUCCESS)
+		printk(KERN_WARNING  "Can't find router: %s", path_buffer);
+
+	/* We don't know what to do with multiple router components */
+	if (brd->brd_numcompts != 1) {
+		PRINT_PANIC("klhwg_connect_one_router: %d cmpts on router\n",
+			brd->brd_numcompts);
+		return;
+	}
+
+
+	/* Convert component 0 to klrou_t ptr */
+	router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd),
+					      brd->brd_compts[0]);
+
+	for (port = 1; port <= MAX_ROUTER_PORTS; port++) {
+		/* See if the port's active */
+		if (router->rou_port[port].port_nasid == INVALID_NASID) {
+			GRPRINTF(("klhwg_connect_one_router: port %d inactive.\n",
+				 port));
+			continue;
+		}
+		if (is_specified(arg_maxnodes) && NASID_TO_COMPACT_NODEID(router->rou_port[port].port_nasid) 
+		    == INVALID_CNODEID) {
+			continue;
+		}
+
+		dest_brd = (lboard_t *)NODE_OFFSET_TO_K0(
+				router->rou_port[port].port_nasid,
+				router->rou_port[port].port_offset);
+
+		/* Generate a hardware graph path for this board. */
+		board_to_path(dest_brd, dest_path);
+
+		rc = hwgraph_traverse(hwgraph_root, dest_path, &dest_hndl);
+
+		if (rc != GRAPH_SUCCESS) {
+			if (is_specified(arg_maxnodes) && KL_CONFIG_DUPLICATE_BOARD(dest_brd))
+				continue;
+			PRINT_PANIC("Can't find router: %s", dest_path);
+		}
+		GRPRINTF(("klhwg_connect_one_router: Link from %s/%d to %s\n",
+			  path_buffer, port, dest_path));
+
+		sprintf(dest_path, "%d", port);
+
+		rc = hwgraph_edge_add(router_hndl, dest_hndl, dest_path);
+
+		if (rc == GRAPH_DUP) {
+			GRPRINTF(("Skipping port %d. nasid %d %s/%s\n",
+				  port, router->rou_port[port].port_nasid,
+				  path_buffer, dest_path));
+			continue;
+		}
+
+		if (rc != GRAPH_SUCCESS && !is_specified(arg_maxnodes))
+			PRINT_PANIC("Can't create edge: %s/%s to vertex 0x%p error 0x%x\n",
+				path_buffer, dest_path, (void *)dest_hndl, rc);
+		
+	}
+}
+
+
+void
+klhwg_connect_routers(devfs_handle_t hwgraph_root)
+{
+	nasid_t nasid;
+	cnodeid_t cnode;
+	lboard_t *brd;
+
+	for (cnode = 0; cnode < numnodes; cnode++) {
+		nasid = COMPACT_TO_NASID_NODEID(cnode);
+
+		GRPRINTF(("klhwg_connect_routers: Connecting routers on cnode %d\n",
+			cnode));
+
+		brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid),
+				KLTYPE_ROUTER);
+
+		if (!brd)
+			continue;
+
+		do {
+
+			nasid = COMPACT_TO_NASID_NODEID(cnode);
+
+			klhwg_connect_one_router(hwgraph_root, brd,
+						 cnode, nasid);
+
+		/* Find the rest of the routers stored on this node. */
+		} while ( (brd = find_lboard_class(KLCF_NEXT(brd), KLTYPE_ROUTER)) );
+	}
+}
+
+
+
+void
+klhwg_connect_hubs(devfs_handle_t hwgraph_root)
+{
+	nasid_t nasid;
+	cnodeid_t cnode;
+	lboard_t *brd;
+	klhub_t *hub;
+	lboard_t *dest_brd;
+	devfs_handle_t hub_hndl;
+	devfs_handle_t dest_hndl;
+	char path_buffer[50];
+	char dest_path[50];
+	graph_error_t rc;
+	int port;
+
+	for (cnode = 0; cnode < numnodes; cnode++) {
+		nasid = COMPACT_TO_NASID_NODEID(cnode);
+
+		GRPRINTF(("klhwg_connect_hubs: Connecting hubs on cnode %d\n",
+			cnode));
+
+		brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA);
+		ASSERT(brd);
+
+		hub = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB);
+		ASSERT(hub);
+
+		for (port = 1; port <= MAX_NI_PORTS; port++) {
+			/* See if the port's active */
+			if (hub->hub_port[port].port_nasid == INVALID_NASID) {
+				GRPRINTF(("klhwg_connect_hubs: port inactive.\n"));
+				continue;
+			}
+
+			if (is_specified(arg_maxnodes) && NASID_TO_COMPACT_NODEID(hub->hub_port[port].port_nasid) == INVALID_CNODEID)
+				continue;
+
+			/* Generate a hardware graph path for this board. */
+			board_to_path(brd, path_buffer);
+
+			GRPRINTF(("klhwg_connect_hubs: Hub path is %s.\n", path_buffer));
+			rc = hwgraph_traverse(hwgraph_root, path_buffer, &hub_hndl);
+
+			if (rc != GRAPH_SUCCESS)
+				printk(KERN_WARNING  "Can't find hub: %s", path_buffer);
+
+			dest_brd = (lboard_t *)NODE_OFFSET_TO_K0(
+					hub->hub_port[port].port_nasid,
+					hub->hub_port[port].port_offset);
+
+			/* Generate a hardware graph path for this board. */
+			board_to_path(dest_brd, dest_path);
+
+			rc = hwgraph_traverse(hwgraph_root, dest_path, &dest_hndl);
+
+			if (rc != GRAPH_SUCCESS) {
+				if (is_specified(arg_maxnodes) && KL_CONFIG_DUPLICATE_BOARD(dest_brd))
+					continue;
+				PRINT_PANIC("Can't find board: %s", dest_path);
+			} else {
+				char buf[1024];
+		
+
+				GRPRINTF(("klhwg_connect_hubs: Link from %s to %s.\n",
+			  	path_buffer, dest_path));
+
+				rc = hwgraph_path_add(hub_hndl, EDGE_LBL_INTERCONNECT, &hub_hndl);
+				sprintf(buf,"%s/%s",path_buffer,EDGE_LBL_INTERCONNECT);
+				rc = hwgraph_traverse(hwgraph_root, buf, &hub_hndl);
+				sprintf(buf,"%d",port);
+				rc = hwgraph_edge_add(hub_hndl, dest_hndl, buf);
+
+				if (rc != GRAPH_SUCCESS)
+					PRINT_PANIC("Can't create edge: %s/%s to vertex 0x%p, error 0x%x\n",
+					path_buffer, dest_path, (void *)dest_hndl, rc);
+
+			}
+		}
+	}
+}
+
+/* Store the pci/vme disabled board information as extended administrative
+ * hints which can later be used by the drivers using the device/driver
+ * admin interface. 
+ */
+void
+klhwg_device_disable_hints_add(void)
+{
+	cnodeid_t	cnode; 		/* node we are looking at */
+	nasid_t		nasid;		/* nasid of the node */
+	lboard_t	*board;		/* board we are looking at */
+	int		comp_index;	/* component index */
+	klinfo_t	*component;	/* component in the board we are
+					 * looking at 
+					 */
+	char		device_name[MAXDEVNAME];
+	
+	for(cnode = 0; cnode < numnodes; cnode++) {
+		nasid = COMPACT_TO_NASID_NODEID(cnode);
+		board = (lboard_t *)KL_CONFIG_INFO(nasid);
+		/* Check out all the board info stored  on a node */
+		while(board) {
+			/* No need to look at duplicate boards or non-io 
+			 * boards
+			 */
+			if (KL_CONFIG_DUPLICATE_BOARD(board) ||
+			    KLCLASS(board->brd_type) != KLCLASS_IO) {
+				board = KLCF_NEXT(board);
+				continue;
+			}
+			/* Check out all the components of a board */
+			for (comp_index = 0; 
+			     comp_index < KLCF_NUM_COMPS(board);
+			     comp_index++) {
+				component = KLCF_COMP(board,comp_index);
+				/* If the component is enabled move on to
+				 * the next component
+				 */
+				if (KLCONFIG_INFO_ENABLED(component))
+					continue;
+				/* NOTE : Since the prom only supports
+				 * the disabling of pci devices the following
+				 * piece of code makes sense. 
+				 * Make sure that this assumption is valid
+				 */
+				/* This component is disabled. Store this
+				 * hint in the extended device admin table
+				 */
+				/* Get the canonical name of the pci device */
+				device_component_canonical_name_get(board,
+							    component,
+							    device_name);
+#ifdef DEBUG
+				printf("%s DISABLED\n",device_name);
+#endif				
+			}
+			/* go to the next board info stored on this 
+			 * node 
+			 */
+			board = KLCF_NEXT(board);
+		}
+	}
+}
+
+void
+klhwg_add_all_modules(devfs_handle_t hwgraph_root)
+{
+	cmoduleid_t	cm;
+	char		name[128];
+	devfs_handle_t	vhdl;
+	devfs_handle_t  module_vhdl;
+	int		rc;
+	char		buffer[16];
+
+	/* Add devices under each module */
+
+	for (cm = 0; cm < nummodules; cm++) {
+		/* Use module as module vertex fastinfo */
+
+		memset(buffer, 0, 16);
+		format_module_id(buffer, modules[cm]->id, MODULE_FORMAT_BRIEF);
+		sprintf(name, EDGE_LBL_MODULE "/%s", buffer);
+
+		rc = hwgraph_path_add(hwgraph_root, name, &module_vhdl);
+		ASSERT(rc == GRAPH_SUCCESS);
+		rc = rc;
+
+		hwgraph_fastinfo_set(module_vhdl, (arbitrary_info_t) modules[cm]);
+
+		/* Add system controller */
+		sprintf(name,
+			EDGE_LBL_MODULE "/%s/" EDGE_LBL_L1,
+			buffer);
+
+		rc = hwgraph_path_add(hwgraph_root, name, &vhdl);
+		ASSERT_ALWAYS(rc == GRAPH_SUCCESS); 
+		rc = rc;
+
+		hwgraph_info_add_LBL(vhdl,
+				     INFO_LBL_ELSC,
+				     (arbitrary_info_t) (__psint_t) 1);
+
+	}
+}
+
+void
+klhwg_add_all_nodes(devfs_handle_t hwgraph_root)
+{
+	cnodeid_t	cnode;
+
+	for (cnode = 0; cnode < numnodes; cnode++) {
+		klhwg_add_node(hwgraph_root, cnode, NULL);
+	}
+
+	for (cnode = 0; cnode < numnodes; cnode++) {
+		klhwg_add_xbow(cnode, cnodeid_to_nasid(cnode));
+	}
+
+	/*
+	 * As for router hardware inventory information, we set this
+	 * up in router.c. 
+	 */
+	
+	klhwg_add_all_routers(hwgraph_root);
+	klhwg_connect_routers(hwgraph_root);
+	klhwg_connect_hubs(hwgraph_root);
+
+	/* Go through the entire system's klconfig
+	 * to figure out which pci components have been disabled
+	 */
+	klhwg_device_disable_hints_add();
+
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/l1.c linux-2.4.21-pre6/arch/ia64/sn/io/sn2/l1.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/l1.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn2/l1.c	2003-03-26 23:49:09.000000000 +0000
@@ -0,0 +1,239 @@
+/* $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) 1992-1997, 2000-2002 Silicon Graphics, Inc.  All rights reserved.
+ */
+
+/* In general, this file is organized in a hierarchy from lower-level
+ * to higher-level layers, as follows:
+ *
+ *	UART routines
+ *	Bedrock/L1 "PPP-like" protocol implementation
+ *	System controller "message" interface (allows multiplexing
+ *		of various kinds of requests and responses with
+ *		console I/O)
+ *	Console interface:
+ *	  "l1_cons", the glue that allows the L1 to act
+ *		as the system console for the stdio libraries
+ *
+ * Routines making use of the system controller "message"-style interface
+ * can be found in l1_command.c.
+ */
+
+
+#include <linux/types.h>
+#include <linux/config.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/io.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/hcl_util.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/eeprom.h>
+#include <asm/sn/router.h>
+#include <asm/sn/module.h>
+#include <asm/sn/ksys/l1.h>
+#include <asm/sn/nodepda.h>
+#include <asm/sn/clksupport.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/sn_cpuid.h>
+#include <asm/sn/uart16550.h>
+#include <asm/sn/simulator.h>
+
+
+#define UART_BAUD_RATE          57600
+
+int 
+get_L1_baud(void)
+{
+    return UART_BAUD_RATE;
+}
+
+
+
+/* Return the current interrupt level */
+int
+l1_get_intr_value( void )
+{
+	return(0);
+}
+
+/* Disconnect the callup functions - throw away interrupts */
+
+void
+l1_unconnect_intr(void)
+{
+}
+
+/* Set up uart interrupt handling for this node's uart */
+
+void
+l1_connect_intr(void *rx_notify, void *tx_notify)
+{
+#if 0
+	// Will need code here for sn2 - something like this
+	console_nodepda = NODEPDA(NASID_TO_COMPACT_NODEID(get_master_nasid());
+	intr_connect_level(console_nodepda->node_first_cpu,
+                                SGI_UART_VECTOR, INTPEND0_MAXMASK,
+                                dummy_intr_func);
+	request_irq(SGI_UART_VECTOR | (console_nodepda->node_first_cpu << 8),
+                                intr_func, SA_INTERRUPT | SA_SHIRQ,
+                                "l1_protocol_driver", (void *)sc);
+#endif
+}
+
+
+/* These are functions to use from serial_in/out when in protocol
+ * mode to send and receive uart control regs. These are external
+ * interfaces into the protocol driver.
+ */
+
+void
+l1_control_out(int offset, int value)
+{
+	/* quietly ignore unless simulator */
+	if ( IS_RUNNING_ON_SIMULATOR() ) {
+		extern u64 master_node_bedrock_address;
+		if ( master_node_bedrock_address != (u64)0 ) {
+			writeb(value, (unsigned long)master_node_bedrock_address +
+				(offset<< 3));
+		}
+		return;
+	}
+}
+
+/* Console input exported interface. Return a register value.  */
+
+int
+l1_control_in_polled(int offset)
+{
+	static int l1_control_in_local(int);
+
+	return(l1_control_in_local(offset));
+}
+
+int
+l1_control_in(int offset)
+{
+	static int l1_control_in_local(int);
+
+	return(l1_control_in_local(offset));
+}
+
+static int
+l1_control_in_local(int offset)
+{
+	int sal_call_status = 0, input;
+	int ret = 0;
+
+	if ( IS_RUNNING_ON_SIMULATOR() ) {
+		extern u64 master_node_bedrock_address;
+		ret = readb((unsigned long)master_node_bedrock_address +
+				(offset<< 3));
+		return(ret);
+	}		
+	if ( offset == REG_LSR ) {
+		ret = (LSR_XHRE | LSR_XSRE);	/* can send anytime */
+		sal_call_status = ia64_sn_console_check(&input);
+		if ( !sal_call_status && input ) {
+			/* input pending */
+			ret |= LSR_RCA;
+		}
+	}
+	return(ret);
+}
+
+/*
+ * Console input exported interface. Return a character (if one is available)
+ */
+
+int
+l1_serial_in_polled(void)
+{
+	static int l1_serial_in_local(void);
+
+	return(l1_serial_in_local());
+}
+
+int
+l1_serial_in(void)
+{
+	static int l1_serial_in_local(void);
+
+	if ( IS_RUNNING_ON_SIMULATOR() ) {
+		extern u64 master_node_bedrock_address;
+		return(readb((unsigned long)master_node_bedrock_address + (REG_DAT<< 3)));
+	}	
+	return(l1_serial_in_local());
+}
+
+static int
+l1_serial_in_local(void)
+{
+	int ch;
+
+	if ( IS_RUNNING_ON_SIMULATOR() ) {
+		extern u64 master_node_bedrock_address;
+		return(readb((unsigned long)master_node_bedrock_address + (REG_DAT<< 3)));
+	}		
+
+	if ( !(ia64_sn_console_getc(&ch)) )
+		return(ch);
+	else
+		return(0);
+}
+
+/* Console output exported interface. Write message to the console.  */
+
+int
+l1_serial_out( char *str, int len )
+{
+	int counter = len;
+
+#if defined(CONFIG_IA64_EARLY_PRINTK)
+	/* Need to setup SAL calls so the PROM calls will work */
+	{
+		static int inited;
+		void early_sn_setup(void);
+		if(!inited) {
+			inited=1;
+			early_sn_setup();
+		}
+	}
+#endif
+
+	if ( IS_RUNNING_ON_SIMULATOR() ) {
+		extern u64 master_node_bedrock_address;
+		void early_sn_setup(void);
+		if (!master_node_bedrock_address)
+			early_sn_setup();
+		if ( master_node_bedrock_address != (u64)0 ) {
+#ifdef FLAG_DIRECT_CONSOLE_WRITES
+			/* This is an easy way to pre-pend the output to know whether the output
+			 * was done via sal or directly */
+			writeb('[', (unsigned long)master_node_bedrock_address + (REG_DAT<< 3));
+			writeb('+', (unsigned long)master_node_bedrock_address + (REG_DAT<< 3));
+			writeb(']', (unsigned long)master_node_bedrock_address + (REG_DAT<< 3));
+			writeb(' ', (unsigned long)master_node_bedrock_address + (REG_DAT<< 3));
+#endif	/* FLAG_DIRECT_CONSOLE_WRITES */
+			while ( counter > 0 ) {
+				writeb(*str, (unsigned long)master_node_bedrock_address + (REG_DAT<< 3));
+				counter--;
+				str++;
+			}
+		}
+		return(len);
+	}
+
+	/* Attempt to write things out thru the sal */
+	if ( ia64_sn_console_putb(str, len) )
+		return(0);
+	return((counter <= 0) ? 0 : (len - counter));
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/l1_command.c linux-2.4.21-pre6/arch/ia64/sn/io/sn2/l1_command.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/l1_command.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn2/l1_command.c	2003-03-26 23:49:15.000000000 +0000
@@ -0,0 +1,195 @@
+/* $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) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */ 
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/io.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/hcl_util.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/eeprom.h>
+#include <asm/sn/router.h>
+#include <asm/sn/module.h>
+#include <asm/sn/ksys/l1.h>
+#include <asm/sn/nodepda.h>
+#include <asm/sn/clksupport.h>
+#include <asm/sn/sn_cpuid.h>
+#include <asm/sn/sn_sal.h>
+#include <linux/ctype.h>
+
+#define ELSC_TIMEOUT	1000000		/* ELSC response timeout (usec) */
+#define LOCK_TIMEOUT	5000000		/* Hub lock timeout (usec) */
+
+#define hub_cpu_get()	0
+
+#define LBYTE(caddr)	(*(char *) caddr)
+
+extern char *bcopy(const char * src, char * dest, int count);
+
+#define LDEBUG		0
+
+/*
+ * ELSC data is in NVRAM page 7 at the following offsets.
+ */
+
+#define NVRAM_MAGIC_AD	0x700		/* magic number used for init */
+#define NVRAM_PASS_WD	0x701		/* password (4 bytes in length) */
+#define NVRAM_DBG1	0x705		/* virtual XOR debug switches */
+#define NVRAM_DBG2	0x706		/* physical XOR debug switches */
+#define NVRAM_CFG	0x707		/* ELSC Configuration info */
+#define NVRAM_MODULE	0x708		/* system module number */
+#define NVRAM_BIST_FLG	0x709		/* BIST flags (2 bits per nodeboard) */
+#define NVRAM_PARTITION 0x70a		/* module's partition id */
+#define	NVRAM_DOMAIN	0x70b		/* module's domain id */
+#define	NVRAM_CLUSTER	0x70c		/* module's cluster id */
+#define	NVRAM_CELL	0x70d		/* module's cellid */
+
+#define NVRAM_MAGIC_NO	0x37		/* value of magic number */
+#define NVRAM_SIZE	16		/* 16 bytes in nvram */
+
+
+/* elsc_display_line writes up to 12 characters to either the top or bottom
+ * line of the L1 display.  line points to a buffer containing the message
+ * to be displayed.  The zero-based line number is specified by lnum (so
+ * lnum == 0 specifies the top line and lnum == 1 specifies the bottom).
+ * Lines longer than 12 characters, or line numbers not less than
+ * L1_DISPLAY_LINES, cause elsc_display_line to return an error.
+ */
+int elsc_display_line(nasid_t nasid, char *line, int lnum)
+{
+    return 0;
+}
+
+/*
+ * iobrick routines
+ */
+
+/* iobrick_rack_bay_type_get fills in the three int * arguments with the
+ * rack number, bay number and brick type of the L1 being addressed.  Note
+ * that if the L1 operation fails and this function returns an error value, 
+ * garbage may be written to brick_type.
+ */
+
+
+int iobrick_rack_bay_type_get( nasid_t nasid, uint *rack, 
+			       uint *bay, uint *brick_type )
+{
+	int result = 0;
+
+	if ( ia64_sn_sysctl_iobrick_module_get(nasid, &result) )
+		return( ELSC_ERROR_CMD_SEND );
+
+	*rack = (result & L1_ADDR_RACK_MASK) >> L1_ADDR_RACK_SHFT;
+	*bay = (result & L1_ADDR_BAY_MASK) >> L1_ADDR_BAY_SHFT;
+	*brick_type = (result & L1_ADDR_TYPE_MASK) >> L1_ADDR_TYPE_SHFT;
+	*brick_type = toupper(*brick_type);
+
+	return 0;
+}
+
+
+int iobrick_module_get(nasid_t nasid)
+{
+    uint rnum, rack, bay, brick_type, t;
+    int ret;
+
+    /* construct module ID from rack and slot info */
+
+    if ((ret = iobrick_rack_bay_type_get(nasid, &rnum, &bay, &brick_type)) < 0)
+        return ret;
+
+    if (bay > MODULE_BPOS_MASK >> MODULE_BPOS_SHFT)
+        return ELSC_ERROR_MODULE;
+
+    /* Build a moduleid_t-compatible rack number */
+
+    rack = 0;           
+    t = rnum / 100;             /* rack class (CPU/IO) */
+    if (t > RACK_CLASS_MASK(rack) >> RACK_CLASS_SHFT(rack))
+        return ELSC_ERROR_MODULE;
+    RACK_ADD_CLASS(rack, t);
+    rnum %= 100;
+
+    t = rnum / 10;              /* rack group */
+    if (t > RACK_GROUP_MASK(rack) >> RACK_GROUP_SHFT(rack))
+        return ELSC_ERROR_MODULE;
+    RACK_ADD_GROUP(rack, t);
+
+    t = rnum % 10;              /* rack number (one-based) */
+    if (t-1 > RACK_NUM_MASK(rack) >> RACK_NUM_SHFT(rack))
+        return ELSC_ERROR_MODULE;
+    RACK_ADD_NUM(rack, t);
+
+    switch( brick_type ) {
+      case 'I': 
+	brick_type = MODULE_IBRICK; break;
+      case 'P':
+	brick_type = MODULE_PBRICK; break;
+      case 'X':
+	brick_type = MODULE_XBRICK; break;
+    }
+
+    ret = RBT_TO_MODULE(rack, bay, brick_type);
+
+    return ret;
+}
+
+/*
+ * iobrick_module_get_nasid() returns a module_id which has the brick
+ * type encoded in bits 15-12, but this is not the true brick type...
+ * The module_id returned by iobrick_module_get_nasid() is modified
+ * to make a PEBRICKs & PXBRICKs look like a PBRICK.  So this routine
+ * iobrick_type_get_nasid() returns the true unmodified brick type.
+ */
+int
+iobrick_type_get_nasid(nasid_t nasid)
+{
+    uint rack, bay, type;
+    int t, ret;
+    extern char brick_types[];
+
+    if ((ret = iobrick_rack_bay_type_get(nasid, &rack, &bay, &type)) < 0) {
+        return ret;
+    }
+
+    /* convert brick_type to lower case */
+    if ((type >= 'A') && (type <= 'Z'))
+        type = type - 'A' + 'a';
+
+    /* convert to a module.h brick type */
+    for( t = 0; t < MAX_BRICK_TYPES; t++ ) {
+        if( brick_types[t] == type )
+            return t;
+    }
+
+    return -1;    /* unknown brick */
+}
+
+int iobrick_module_get_nasid(nasid_t nasid)
+{
+    int io_moduleid;
+
+#ifdef PIC_LATER
+    uint rack, bay;
+
+    if (PEBRICK_NODE(nasid)) {
+        if (peer_iobrick_rack_bay_get(nasid, &rack, &bay)) {
+            printf("Could not read rack and bay location "
+                   "of PEBrick at nasid %d\n", nasid);
+        }
+
+        io_moduleid = peer_iobrick_module_get(sc, rack, bay);
+    }
+#endif	/* PIC_LATER */
+    io_moduleid = iobrick_module_get(nasid);
+    return io_moduleid;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/ml_SN_init.c linux-2.4.21-pre6/arch/ia64/sn/io/sn2/ml_SN_init.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/ml_SN_init.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn2/ml_SN_init.c	2003-03-26 23:49:20.000000000 +0000
@@ -0,0 +1,160 @@
+/* $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) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/bootmem.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/io.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/sn_private.h>
+#include <asm/sn/klconfig.h>
+#include <asm/sn/sn_cpuid.h>
+#include <asm/sn/snconfig.h>
+
+extern int numcpus;
+extern char arg_maxnodes[];
+extern cpuid_t master_procid;
+
+extern int hasmetarouter;
+
+int		maxcpus;
+cpumask_t	boot_cpumask;
+hubreg_t	region_mask = 0;
+
+
+extern xwidgetnum_t hub_widget_id(nasid_t);
+
+extern int valid_icache_reasons;	/* Reasons to flush the icache */
+extern int valid_dcache_reasons;	/* Reasons to flush the dcache */
+extern u_char miniroot;
+extern volatile int	need_utlbmiss_patch;
+extern void iograph_early_init(void);
+
+nasid_t master_nasid = INVALID_NASID;		/* This is the partition master nasid */
+nasid_t master_baseio_nasid = INVALID_NASID;	/* This is the master base I/O nasid */
+
+
+/*
+ * mlreset(void)
+ * 	very early machine reset - at this point NO interrupts have been
+ * 	enabled; nor is memory, tlb, p0, etc setup.
+ *
+ * 	slave is zero when mlreset is called for the master processor and
+ *	is nonzero thereafter.
+ */
+
+
+void
+mlreset(int slave)
+{
+	/*
+	 * We are the master cpu and node.
+	 */ 
+	master_nasid = get_nasid();
+	set_master_bridge_base();
+
+	/* We're the master processor */
+	master_procid = smp_processor_id();
+	master_nasid = cpuid_to_nasid(master_procid);
+
+	/*
+	 * master_nasid we get back better be same as one from
+	 * get_nasid()
+	 */
+	ASSERT_ALWAYS(master_nasid == get_nasid());
+
+	/* early initialization of iograph */
+	iograph_early_init();
+
+	/* Initialize Hub Pseudodriver Management */
+	hubdev_init();
+}
+
+
+/* XXX - Move the meat of this to intr.c ? */
+/*
+ * Set up the platform-dependent fields in the nodepda.
+ */
+void init_platform_nodepda(nodepda_t *npda, cnodeid_t node)
+{
+	hubinfo_t hubinfo;
+
+	extern void router_map_init(nodepda_t *);
+	extern void router_queue_init(nodepda_t *,cnodeid_t);
+	extern void intr_init_vecblk(nodepda_t *, cnodeid_t, int);
+
+	/* Allocate per-node platform-dependent data */
+	hubinfo = (hubinfo_t)alloc_bootmem_node(NODE_DATA(node), sizeof(struct hubinfo_s));
+
+	npda->pdinfo = (void *)hubinfo;
+	hubinfo->h_nodepda = npda;
+	hubinfo->h_cnodeid = node;
+	hubinfo->h_nasid = COMPACT_TO_NASID_NODEID(node);
+
+	spin_lock_init(&hubinfo->h_crblock);
+
+	hubinfo->h_widgetid = hub_widget_id(hubinfo->h_nasid);
+	npda->xbow_peer = INVALID_NASID;
+
+	/* 
+	 * Initialize the linked list of
+	 * router info pointers to the dependent routers
+	 */
+	npda->npda_rip_first = NULL;
+
+	/*
+	 * npda_rip_last always points to the place
+	 * where the next element is to be inserted
+	 * into the list 
+	 */
+	npda->npda_rip_last = &npda->npda_rip_first;
+	npda->geoid.any.type = GEO_TYPE_INVALID;
+
+	mutex_init_locked(&npda->xbow_sema); /* init it locked? */
+}
+
+/* XXX - Move the interrupt stuff to intr.c ? */
+/*
+ * Set up the platform-dependent fields in the processor pda.
+ * Must be done _after_ init_platform_nodepda().
+ * If we need a lock here, something else is wrong!
+ */
+void init_platform_pda(cpuid_t cpu)
+{
+}
+
+void
+update_node_information(cnodeid_t cnodeid)
+{
+	nodepda_t *npda = NODEPDA(cnodeid);
+	nodepda_router_info_t *npda_rip;
+	
+	/* Go through the list of router info 
+	 * structures and copy some frequently
+	 * accessed info from the info hanging
+	 * off the corresponding router vertices
+	 */
+	npda_rip = npda->npda_rip_first;
+	while(npda_rip) {
+		if (npda_rip->router_infop) {
+			npda_rip->router_portmask = 
+				npda_rip->router_infop->ri_portmask;
+			npda_rip->router_slot = 
+				npda_rip->router_infop->ri_slotnum;
+		} else {
+			/* No router, no ports. */
+			npda_rip->router_portmask = 0;
+		}
+		npda_rip = npda_rip->router_next;
+	}
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/ml_SN_intr.c linux-2.4.21-pre6/arch/ia64/sn/io/sn2/ml_SN_intr.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/ml_SN_intr.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn2/ml_SN_intr.c	2003-03-26 23:49:08.000000000 +0000
@@ -36,6 +36,7 @@
 #include <asm/sn/pci/pcibr_private.h>
 #include <asm/sn/intr.h>
 #include <asm/sn/sn2/shub_mmr_t.h>
+#include <asm/sn/sn2/shubio.h>
 #include <asm/sal.h>
 #include <asm/sn/sn_sal.h>
 
@@ -44,6 +45,26 @@
 extern nasid_t master_nasid;
 
 //  Initialize some shub registers for interrupts, both IO and error.
+//  
+
+#ifdef BRINGUP2
+static long vec1_opt, ii0_opt;
+static int __init set_vec1_opt(char *str)
+{
+        vec1_opt = 1;
+        return 1;
+}
+
+static int __init set_ii0_opt(char *str)
+{
+        ii0_opt = 1;
+        return 1;
+}
+
+__setup("vec1", set_vec1_opt);
+__setup("ii0", set_ii0_opt);
+#endif
+
 
 void
 intr_init_vecblk( nodepda_t *npda,
@@ -51,24 +72,15 @@
 		int sn)
 {
 	int 			nasid = cnodeid_to_nasid(node);
-	nasid_t			console_nasid;
 	sh_ii_int0_config_u_t	ii_int_config;
 	cpuid_t			cpu;
 	cpuid_t			cpu0, cpu1;
 	nodepda_t		*lnodepda;
 	sh_ii_int0_enable_u_t	ii_int_enable;
-	sh_local_int0_config_u_t	local_int_config;
-	sh_local_int0_enable_u_t	local_int_enable;
-	sh_fsb_system_agent_config_u_t	fsb_system_agent;
 	sh_int_node_id_config_u_t	node_id_config;
-	int is_console;
+	extern void sn_init_cpei_timer(void);
+	static int timer_added = 0;
 
-	console_nasid = get_console_nasid();
-	if (console_nasid < 0) {
-		console_nasid = master_nasid;
-	}
-
-	is_console = nasid == console_nasid;
 
 	if (is_headless_node(node) ) {
 		int cnode;
@@ -95,13 +107,15 @@
 	}
 
 	// Get the physical id's of the cpu's on this node.
-	cpu0 = id_eid_to_cpu_physical_id(nasid, 0);
-	cpu1 = id_eid_to_cpu_physical_id(nasid, 1);
+	cpu0 = nasid_slice_to_cpu_physical_id(nasid, 0);
+	cpu1 = nasid_slice_to_cpu_physical_id(nasid, 2);
 
 	HUB_S( (unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_PI_ERROR_MASK), 0);
 	HUB_S( (unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_PI_CRBP_ERROR_MASK), 0);
 
+
 	// The II_INT_CONFIG register for cpu 0.
+	ii_int_config.sh_ii_int0_config_regval = 0;
 	ii_int_config.sh_ii_int0_config_s.type = 0;
 	ii_int_config.sh_ii_int0_config_s.agt = 0;
 	ii_int_config.sh_ii_int0_config_s.pid = cpu0;
@@ -110,7 +124,9 @@
 	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_II_INT0_CONFIG),
 		ii_int_config.sh_ii_int0_config_regval);
 
+
 	// The II_INT_CONFIG register for cpu 1.
+	ii_int_config.sh_ii_int0_config_regval = 0;
 	ii_int_config.sh_ii_int0_config_s.type = 0;
 	ii_int_config.sh_ii_int0_config_s.agt = 0;
 	ii_int_config.sh_ii_int0_config_s.pid = cpu1;
@@ -119,101 +135,28 @@
 	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_II_INT1_CONFIG),
 		ii_int_config.sh_ii_int0_config_regval);
 
+
 	// Enable interrupts for II_INT0 and 1.
+	ii_int_enable.sh_ii_int0_enable_regval = 0;
 	ii_int_enable.sh_ii_int0_enable_s.ii_enable = 1;
+#if defined(BUS_INT_WAR) && defined(CONFIG_SHUB_1_0_SPECIFIC)
+	/* Dont enable any ints from II. We will poll for interrupts. */
+	ii_int_enable.sh_ii_int0_enable_s.ii_enable = 0;
+
+	/* Enable IPIs. We use them ONLY for send INITs to hung cpus */
+	*(volatile long*)GLOBAL_MMR_ADDR(nasid, SH_IPI_INT_ENABLE) = 1;
+#endif
 
 	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_II_INT0_ENABLE),
 		ii_int_enable.sh_ii_int0_enable_regval);
 	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_II_INT1_ENABLE),
 		ii_int_enable.sh_ii_int0_enable_regval);
 
-	// init error regs
-	// LOCAL_INT0 is for the UART only.
-
-	local_int_config.sh_local_int0_config_s.type = 0;
-	local_int_config.sh_local_int0_config_s.agt = 0;
-	local_int_config.sh_local_int0_config_s.pid = cpu;
-	local_int_config.sh_local_int0_config_s.base = 0;
-	local_int_config.sh_local_int0_config_s.idx = SGI_UART_VECTOR;
-
-	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT0_CONFIG),
-		local_int_config.sh_local_int0_config_regval);
-
-	// LOCAL_INT1 is for all hardware errors.
-	// It will send a BERR, which will result in an MCA.
-	local_int_config.sh_local_int0_config_s.idx = 0;
-
-	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT1_CONFIG),
-		local_int_config.sh_local_int0_config_regval);
-
-	// Clear the LOCAL_INT_ENABLE register.
-	local_int_enable.sh_local_int0_enable_regval = 0;
-
-	if (is_console) {
-		// Enable the UART interrupt.  Only applies to the console nasid.
-		local_int_enable.sh_local_int0_enable_s.uart_int = 1;
-
-		HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT0_ENABLE),
-			local_int_enable.sh_local_int0_enable_regval);
-	}
-
-	// Enable all the error interrupts.
-	local_int_enable.sh_local_int0_enable_s.uart_int = 0;
-	local_int_enable.sh_local_int0_enable_s.pi_hw_int = 1;
-	local_int_enable.sh_local_int0_enable_s.md_hw_int = 1;
-	local_int_enable.sh_local_int0_enable_s.xn_hw_int = 1;
-	local_int_enable.sh_local_int0_enable_s.lb_hw_int = 1;
-	local_int_enable.sh_local_int0_enable_s.ii_hw_int = 1;
-	local_int_enable.sh_local_int0_enable_s.pi_uce_int = 1;
-	local_int_enable.sh_local_int0_enable_s.md_uce_int = 1;
-	local_int_enable.sh_local_int0_enable_s.xn_uce_int = 1;
-	local_int_enable.sh_local_int0_enable_s.system_shutdown_int = 1;
-	local_int_enable.sh_local_int0_enable_s.l1_nmi_int = 1;
-	local_int_enable.sh_local_int0_enable_s.stop_clock = 1;
-
-
-	// Send BERR, rather than an interrupt, for shub errors.
-	local_int_config.sh_local_int0_config_s.agt = 1;
-	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT1_CONFIG),
-		local_int_config.sh_local_int0_config_regval);
-
-	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT1_ENABLE),
-		local_int_enable.sh_local_int0_enable_regval);
-
-	// Make sure BERR is enabled.
-	fsb_system_agent.sh_fsb_system_agent_config_regval = 
-		HUB_L( (unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_FSB_SYSTEM_AGENT_CONFIG) );
-	fsb_system_agent.sh_fsb_system_agent_config_s.berr_assert_en = 1;
-	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_FSB_SYSTEM_AGENT_CONFIG),
-		fsb_system_agent.sh_fsb_system_agent_config_regval);
-
-	// Set LOCAL_INT2 to field CEs
-
-	local_int_enable.sh_local_int0_enable_regval = 0;
-
-	local_int_config.sh_local_int0_config_s.agt = 0;
-	local_int_config.sh_local_int0_config_s.idx = SGI_SHUB_ERROR_VECTOR;
-	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT2_CONFIG),
-		local_int_config.sh_local_int0_config_regval);
-
-	local_int_enable.sh_local_int0_enable_s.pi_ce_int = 1;
-	local_int_enable.sh_local_int0_enable_s.md_ce_int = 1;
-	local_int_enable.sh_local_int0_enable_s.xn_ce_int = 1;
-
-	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT2_ENABLE),
-		local_int_enable.sh_local_int0_enable_regval);
-
-	// Make sure all the rest of the LOCAL_INT regs are disabled.
-	local_int_enable.sh_local_int0_enable_regval = 0;
-	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT3_ENABLE),
-		local_int_enable.sh_local_int0_enable_regval);
-
-	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT4_ENABLE),
-		local_int_enable.sh_local_int0_enable_regval);
-
-	HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT5_ENABLE),
-		local_int_enable.sh_local_int0_enable_regval);
 
+	if (!timer_added) { // can only init the timer once.
+		timer_added = 1;
+		sn_init_cpei_timer();
+	}
 }
 
 // (Un)Reserve an irq on this cpu.
@@ -225,12 +168,17 @@
 {
 	int i;
 	irqpda_t	*irqs = irqpdaindr[cpu];
+	static int	nextvec=IA64_SN2_FIRST_DEVICE_VECTOR;
 
 	if (reserve) {
 		if (bit < 0) {
-			for (i = IA64_SN2_FIRST_DEVICE_VECTOR; i <= IA64_SN2_LAST_DEVICE_VECTOR; i++) {
+			for (i = nextvec; i <= IA64_SN2_LAST_DEVICE_VECTOR; i++) {
 				if (irqs->irq_flags[i] == 0) {
 					bit = i;
+#ifdef BRINGUP2
+					if (vec1_opt)
+						nextvec = i+1;
+#endif
 					break;
 				}
 			}
@@ -343,6 +291,10 @@
 		if (min_count > intrs) {
 			min_count = intrs;
 			best_cpu = cpu;
+#ifdef BRINGUP2
+			if (ii0_opt)
+				break;
+#endif
 		}
 	}
 	return best_cpu;
@@ -393,31 +345,40 @@
 		int *resp_bit)
 {
 	cpuid_t		cpuid;
-	cnodeid_t	candidate = -1;
+	cpuid_t		candidate = CPU_NONE;
+	cnodeid_t	candidate_node;
 	devfs_handle_t	pconn_vhdl;
 	pcibr_soft_t	pcibr_soft;
+	int 		bit;
 
 /* SN2 + pcibr addressing limitation */
 /* Due to this limitation, all interrupts from a given bridge must go to the name node.*/
+/* The interrupt must also be targetted for the same processor. */
 /* This limitation does not exist on PIC. */
+/* But, the processor limitation will stay.  The limitation will be similar to */
+/* the bedrock/xbridge limit regarding PI's */
 
 	if ( (hwgraph_edge_get(dev, EDGE_LBL_PCI, &pconn_vhdl) == GRAPH_SUCCESS) &&
 		( (pcibr_soft = pcibr_soft_get(pconn_vhdl) ) != NULL) ) {
 			if (pcibr_soft->bsi_err_intr) {
-				candidate = cpuid_to_cnodeid( ((hub_intr_t)pcibr_soft->bsi_err_intr)->i_cpuid);
+				candidate =  ((hub_intr_t)pcibr_soft->bsi_err_intr)->i_cpuid;
 			}
 	}
 
-	if (candidate >= 0) {
-		// The node was chosen already when we assigned the error interrupt.
-		cpuid = intr_bit_reserve_test(CPU_NONE,
-						0,
-						candidate,
-						req_bit,
-						0,
-						owner_dev,
-						name,
-						resp_bit);
+
+	if (candidate != CPU_NONE) {
+		// The cpu was chosen already when we assigned the error interrupt.
+		bit = intr_reserve_level(candidate, 
+					req_bit, 
+					resflags, 
+					owner_dev, 
+					name);
+		if (bit < 0) {
+			cpuid = CPU_NONE;
+		} else {
+			cpuid = candidate;
+			*resp_bit = bit;
+		}
 	} else {
 		// Need to choose one.  Try the controlling c-brick first.
 		cpuid = intr_bit_reserve_test(CPU_NONE,
@@ -434,10 +395,9 @@
 		return cpuid;
 	}
 
-	if (candidate >= 0) {
-		printk("Cannot target interrupt to target node (%d).\n",candidate);
-		return CPU_NONE;
-	} else {
+	if (candidate  != CPU_NONE) {
+		printk("Cannot target interrupt to target node (%ld).\n",candidate);
+		return CPU_NONE; } else {
 		printk("Cannot target interrupt to closest node (%d) 0x%p\n",
 			master_node_get(dev), (void *)owner_dev);
 	}
@@ -448,11 +408,11 @@
 	{
 		static cnodeid_t last_node = -1;
 		if (last_node >= numnodes) last_node = 0;
-		for (candidate = last_node + 1; candidate != last_node; candidate++) {
-			if (candidate == numnodes) candidate = 0;
+		for (candidate_node = last_node + 1; candidate_node != last_node; candidate_node++) {
+			if (candidate_node == numnodes) candidate_node = 0;
 			cpuid = intr_bit_reserve_test(CPU_NONE,
 							0,
-							candidate,
+							candidate_node,
 							req_bit,
 							0,
 							owner_dev,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/ml_iograph.c linux-2.4.21-pre6/arch/ia64/sn/io/sn2/ml_iograph.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/ml_iograph.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn2/ml_iograph.c	2003-03-26 23:49:50.000000000 +0000
@@ -0,0 +1,1395 @@
+/* $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) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/io.h>
+#include <asm/sn/sn_cpuid.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/hcl_util.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/xtalk/xbow.h>
+#include <asm/sn/pci/bridge.h>
+#include <asm/sn/klconfig.h>
+#include <asm/sn/eeprom.h>
+#include <asm/sn/sn_private.h>
+#include <asm/sn/pci/pcibr.h>
+#include <asm/sn/xtalk/xtalk.h>
+#include <asm/sn/xtalk/xswitch.h>
+#include <asm/sn/xtalk/xwidget.h>
+#include <asm/sn/xtalk/xtalk_private.h>
+#include <asm/sn/xtalk/xtalkaddrs.h>
+
+/* #define IOGRAPH_DEBUG */
+#ifdef IOGRAPH_DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif /* IOGRAPH_DEBUG */
+
+/* #define PROBE_TEST */
+
+/* At most 2 hubs can be connected to an xswitch */
+#define NUM_XSWITCH_VOLUNTEER 2
+
+extern unsigned char Is_pic_on_this_nasid[512];
+
+/*
+ * Track which hubs have volunteered to manage devices hanging off of
+ * a Crosstalk Switch (e.g. xbow).  This structure is allocated,
+ * initialized, and hung off the xswitch vertex early on when the
+ * xswitch vertex is created.
+ */
+typedef struct xswitch_vol_s {
+	mutex_t xswitch_volunteer_mutex;
+	int		xswitch_volunteer_count;
+	devfs_handle_t	xswitch_volunteer[NUM_XSWITCH_VOLUNTEER];
+} *xswitch_vol_t;
+
+void
+xswitch_vertex_init(devfs_handle_t xswitch)
+{
+	xswitch_vol_t xvolinfo;
+	int rc;
+	extern void * snia_kmem_zalloc(size_t size, int flag);
+
+	xvolinfo = snia_kmem_zalloc(sizeof(struct xswitch_vol_s), GFP_KERNEL);
+	mutex_init(&xvolinfo->xswitch_volunteer_mutex);
+	rc = hwgraph_info_add_LBL(xswitch, 
+			INFO_LBL_XSWITCH_VOL,
+			(arbitrary_info_t)xvolinfo);
+	ASSERT(rc == GRAPH_SUCCESS); rc = rc;
+}
+
+
+/*
+ * When assignment of hubs to widgets is complete, we no longer need the
+ * xswitch volunteer structure hanging around.  Destroy it.
+ */
+static void
+xswitch_volunteer_delete(devfs_handle_t xswitch)
+{
+	xswitch_vol_t xvolinfo;
+	int rc;
+	extern void snia_kmem_free(void *ptr, size_t size);
+
+	rc = hwgraph_info_remove_LBL(xswitch, 
+				INFO_LBL_XSWITCH_VOL,
+				(arbitrary_info_t *)&xvolinfo);
+	snia_kmem_free(xvolinfo, sizeof(struct xswitch_vol_s));
+}
+/*
+ * A Crosstalk master volunteers to manage xwidgets on the specified xswitch.
+ */
+/* ARGSUSED */
+static void
+volunteer_for_widgets(devfs_handle_t xswitch, devfs_handle_t master)
+{
+	xswitch_vol_t xvolinfo = NULL;
+	devfs_handle_t hubv;
+	hubinfo_t hubinfo;
+
+	(void)hwgraph_info_get_LBL(xswitch, 
+				INFO_LBL_XSWITCH_VOL, 
+				(arbitrary_info_t *)&xvolinfo);
+	if (xvolinfo == NULL) {
+	    if (!is_headless_node_vertex(master))
+		    printk(KERN_WARNING
+			"volunteer for widgets: vertex 0x%p has no info label",
+			(void *)xswitch);
+	    return;
+	}
+
+	mutex_lock(&xvolinfo->xswitch_volunteer_mutex);
+	ASSERT(xvolinfo->xswitch_volunteer_count < NUM_XSWITCH_VOLUNTEER);
+	xvolinfo->xswitch_volunteer[xvolinfo->xswitch_volunteer_count] = master;
+	xvolinfo->xswitch_volunteer_count++;
+
+	/*
+	 * if dual ported, make the lowest widgetid always be 
+	 * xswitch_volunteer[0].
+	 */
+	if (xvolinfo->xswitch_volunteer_count == NUM_XSWITCH_VOLUNTEER) {
+		hubv = xvolinfo->xswitch_volunteer[0];
+		hubinfo_get(hubv, &hubinfo);
+		if (hubinfo->h_widgetid != XBOW_HUBLINK_LOW) {
+			xvolinfo->xswitch_volunteer[0] = 
+						xvolinfo->xswitch_volunteer[1];
+			xvolinfo->xswitch_volunteer[1] = hubv;
+		}
+	}
+	mutex_unlock(&xvolinfo->xswitch_volunteer_mutex);
+}
+
+extern int xbow_port_io_enabled(nasid_t nasid, int widgetnum);
+
+/*
+ * Assign all the xwidgets hanging off the specified xswitch to the
+ * Crosstalk masters that have volunteered for xswitch duty.
+ */
+/* ARGSUSED */
+static void
+assign_widgets_to_volunteers(devfs_handle_t xswitch, devfs_handle_t hubv)
+{
+	xswitch_info_t xswitch_info;
+	xswitch_vol_t xvolinfo = NULL;
+	xwidgetnum_t widgetnum;
+	int num_volunteer;
+	nasid_t nasid;
+	hubinfo_t hubinfo;
+	extern int iobrick_type_get_nasid(nasid_t);
+
+
+	hubinfo_get(hubv, &hubinfo);
+	nasid = hubinfo->h_nasid;
+	
+	xswitch_info = xswitch_info_get(xswitch);
+	ASSERT(xswitch_info != NULL);
+
+	(void)hwgraph_info_get_LBL(xswitch, 
+				INFO_LBL_XSWITCH_VOL, 
+				(arbitrary_info_t *)&xvolinfo);
+	if (xvolinfo == NULL) {
+	    if (!is_headless_node_vertex(hubv))
+		    printk(KERN_WARNING
+			"assign_widgets_to_volunteers:vertex 0x%p has "
+			" no info label",
+			(void *)xswitch);
+	    return;
+	}
+
+	num_volunteer = xvolinfo->xswitch_volunteer_count;
+	ASSERT(num_volunteer > 0);
+
+	/* Assign master hub for xswitch itself.  */
+	if (HUB_WIDGET_ID_MIN > 0) {
+		hubv = xvolinfo->xswitch_volunteer[0];
+		xswitch_info_master_assignment_set(xswitch_info, (xwidgetnum_t)0, hubv);
+	}
+
+	/*
+	 * TBD: Use administrative information to alter assignment of
+	 * widgets to hubs.
+	 */
+	for (widgetnum=HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) {
+		int i;
+
+		/*
+		 * Ignore disabled/empty ports.
+		 */
+		if (!xbow_port_io_enabled(nasid, widgetnum)) 
+		    continue;
+
+		/*
+		 * If this is the master IO board, assign it to the same 
+		 * hub that owned it in the prom.
+		 */
+		if (is_master_baseio_nasid_widget(nasid, widgetnum)) {
+			extern nasid_t get_master_baseio_nasid(void);
+			for (i=0; i<num_volunteer; i++) {
+				hubv = xvolinfo->xswitch_volunteer[i];
+				hubinfo_get(hubv, &hubinfo);
+				nasid = hubinfo->h_nasid;
+				if (nasid == get_master_baseio_nasid())
+					goto do_assignment;
+			}
+			PRINT_PANIC("Nasid == %d, console nasid == %d",
+				nasid, get_master_baseio_nasid());
+		}
+
+		/*
+		 * Assuming that we're dual-hosted and that PCI cards 
+		 * are naturally placed left-to-right, alternate PCI 
+		 * buses across both Cbricks.   For Pbricks, and Ibricks,
+                 * io_brick_map_widget() returns the PCI bus number
+                 * associated with the given brick type and widget number.
+                 * For Xbricks, it returns the XIO slot number.
+		 */
+
+		i = 0;
+		if (num_volunteer > 1) {
+                        int	       bt;
+
+                       	bt = iobrick_type_get_nasid(nasid);
+                        if (bt >= 0) {
+				/*
+				 * PXBRICK has two busses per widget so this
+				 * algorithm wouldn't work (all busses would
+				 * be assigned to one volunteer). Change the
+				 * bricktype to PBRICK whose mapping is setup
+				 * suchthat 2 of the PICs will be assigned to
+				 * one volunteer and the other one will be
+				 * assigned to the other volunteer.
+				 */
+				if (bt == MODULE_PXBRICK) 
+					bt = MODULE_PBRICK;
+
+			        i = io_brick_map_widget(bt, widgetnum) & 1;
+                        }
+                }
+
+		hubv = xvolinfo->xswitch_volunteer[i];
+
+do_assignment:
+		/*
+		 * At this point, we want to make hubv the master of widgetnum.
+		 */
+		xswitch_info_master_assignment_set(xswitch_info, widgetnum, hubv);
+	}
+
+	xswitch_volunteer_delete(xswitch);
+}
+
+/*
+ * Early iograph initialization.  Called by master CPU in mlreset().
+ * Useful for including iograph.o in kernel.o.
+ */
+void
+iograph_early_init(void)
+{
+/*
+ * Need new way to get this information ..
+ */
+	cnodeid_t cnode;
+	nasid_t nasid;
+	lboard_t *board;
+	
+	/*
+	 * Init. the board-to-hwgraph link early, so FRU analyzer
+	 * doesn't trip on leftover values if we panic early on.
+	 */
+	for(cnode = 0; cnode < numnodes; cnode++) {
+		nasid = COMPACT_TO_NASID_NODEID(cnode);
+		board = (lboard_t *)KL_CONFIG_INFO(nasid);
+		DBG("iograph_early_init: Found board 0x%p\n", board);
+
+		/* Check out all the board info stored on a node */
+		while(board) {
+			board->brd_graph_link = GRAPH_VERTEX_NONE;
+			board = KLCF_NEXT(board);
+			DBG("iograph_early_init: Found board 0x%p\n", board);
+		}
+	}
+
+	hubio_init();
+}
+
+/*
+ * Let boot processor know that we're done initializing our node's IO
+ * and then exit.
+ */
+/* ARGSUSED */
+static void
+io_init_done(cnodeid_t cnodeid,cpu_cookie_t c)
+{
+	/* Let boot processor know that we're done. */
+}
+
+/* 
+ * Probe to see if this hub's xtalk link is active.  If so,
+ * return the Crosstalk Identification of the widget that we talk to.  
+ * This is called before any of the Crosstalk infrastructure for 
+ * this hub is set up.  It's usually called on the node that we're
+ * probing, but not always.
+ *
+ * TBD: Prom code should actually do this work, and pass through 
+ * hwid for our use.
+ */
+static void
+early_probe_for_widget(devfs_handle_t hubv, xwidget_hwid_t hwid)
+{
+	hubreg_t llp_csr_reg;
+	nasid_t nasid;
+	hubinfo_t hubinfo;
+
+	hubinfo_get(hubv, &hubinfo);
+	nasid = hubinfo->h_nasid;
+
+	llp_csr_reg = REMOTE_HUB_L(nasid, IIO_LLP_CSR);
+	/* 
+	 * If link is up, read the widget's part number.
+	 * A direct connect widget must respond to widgetnum=0.
+	 */
+	if (llp_csr_reg & IIO_LLP_CSR_IS_UP) {
+		/* TBD: Put hub into "indirect" mode */
+		/*
+		 * We're able to read from a widget because our hub's 
+		 * WIDGET_ID was set up earlier.
+		 */
+		widgetreg_t widget_id = *(volatile widgetreg_t *)
+			(RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID);
+
+		DBG("early_probe_for_widget: Hub Vertex 0x%p is UP widget_id = 0x%x Register 0x%p\n", hubv, widget_id,
+		(volatile widgetreg_t *)(RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID) );
+
+		hwid->part_num = XWIDGET_PART_NUM(widget_id);
+		hwid->rev_num = XWIDGET_REV_NUM(widget_id);
+		hwid->mfg_num = XWIDGET_MFG_NUM(widget_id);
+
+		/* TBD: link reset */
+	} else {
+
+		hwid->part_num = XWIDGET_PART_NUM_NONE;
+		hwid->rev_num = XWIDGET_REV_NUM_NONE;
+		hwid->mfg_num = XWIDGET_MFG_NUM_NONE;
+	}
+}
+
+/* Add inventory information to the widget vertex 
+ * Right now (module,slot,revision) is being
+ * added as inventory information.
+ */
+static void
+xwidget_inventory_add(devfs_handle_t 		widgetv,
+		      lboard_t 			*board,
+		      struct xwidget_hwid_s 	hwid)
+{
+	if (!board)
+		return;
+	/* Donot add inventory information for the baseio
+	 * on a speedo with an xbox. It has already been
+	 * taken care of in SN00_vmc.
+	 * Speedo with xbox's baseio comes in at slot io1 (widget 9)
+	 */
+	device_inventory_add(widgetv,INV_IOBD,board->brd_type,
+			     geo_module(board->brd_geoid),
+			     SLOTNUM_GETSLOT(board->brd_slot),
+			     hwid.rev_num);
+}
+
+/*
+ * io_xswitch_widget_init
+ *	
+ */
+
+void
+io_xswitch_widget_init(devfs_handle_t  	xswitchv,
+		       devfs_handle_t	hubv,
+		       xwidgetnum_t	widgetnum,
+		       async_attach_t	aa)
+{
+	xswitch_info_t		xswitch_info;
+	xwidgetnum_t		hub_widgetid;
+	devfs_handle_t		widgetv;
+	cnodeid_t		cnode;
+	widgetreg_t		widget_id;
+	nasid_t			nasid, peer_nasid;
+	struct xwidget_hwid_s 	hwid;
+	hubinfo_t		hubinfo;
+	/*REFERENCED*/
+	int			rc;
+	char 			pathname[128];
+	lboard_t		*board = NULL;
+	char			buffer[16];
+	char			bt;
+	moduleid_t		io_module;
+	slotid_t get_widget_slotnum(int xbow, int widget);
+	
+	DBG("\nio_xswitch_widget_init: hubv 0x%p, xswitchv 0x%p, widgetnum 0x%x\n", hubv, xswitchv, widgetnum);
+
+	/*
+	 * Verify that xswitchv is indeed an attached xswitch.
+	 */
+	xswitch_info = xswitch_info_get(xswitchv);
+	ASSERT(xswitch_info != NULL);
+
+	hubinfo_get(hubv, &hubinfo);
+	nasid = hubinfo->h_nasid;
+	cnode = NASID_TO_COMPACT_NODEID(nasid);
+	hub_widgetid = hubinfo->h_widgetid;
+
+	/*
+	 * Check that the widget is an io widget and is enabled
+	 * on this nasid or the `peer' nasid.  The peer nasid
+	 * is the other hub/bedrock connected to the xbow.
+	 */
+	peer_nasid = NODEPDA(cnode)->xbow_peer;
+	if (peer_nasid == INVALID_NASID)
+		/* If I don't have a peer, use myself. */
+		peer_nasid = nasid;
+	if (!xbow_port_io_enabled(nasid, widgetnum) &&
+	    !xbow_port_io_enabled(peer_nasid, widgetnum)) {
+		return;
+	}
+
+	if (xswitch_info_link_ok(xswitch_info, widgetnum)) {
+		char			name[4];
+		lboard_t dummy;
+
+		/*
+		 * If the current hub is not supposed to be the master 
+		 * for this widgetnum, then skip this widget.
+		 */
+		if (xswitch_info_master_assignment_get(xswitch_info,
+						       widgetnum) != hubv) {
+			return;
+		}
+
+		board = find_lboard_class(
+				(lboard_t *)KL_CONFIG_INFO(nasid),
+				KLCLASS_IOBRICK);
+		if (!board && NODEPDA(cnode)->xbow_peer != INVALID_NASID) {
+		    	board = find_lboard_class(
+					(lboard_t *)KL_CONFIG_INFO( NODEPDA(cnode)->xbow_peer),
+						KLCLASS_IOBRICK);
+		}
+
+		if (board) {
+			DBG("io_xswitch_widget_init: Found KLTYPE_IOBRICK Board 0x%p brd_type 0x%x\n", board, board->brd_type);
+		} else {
+			DBG("io_xswitch_widget_init: FIXME did not find IOBOARD\n");
+			board = &dummy;
+		}
+
+
+		/* Copy over the nodes' geoid info */
+		{
+			lboard_t *brd;
+
+			brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA);
+			if ( brd != (lboard_t *)0 ) {
+				board->brd_geoid = brd->brd_geoid;
+			}
+		}
+
+		/*
+ 		 * Make sure we really want to say xbrick, pbrick,
+		 * etc. rather than XIO, graphics, etc.
+ 		 */
+
+		memset(buffer, 0, 16);
+		format_module_id(buffer, geo_module(board->brd_geoid), MODULE_FORMAT_BRIEF);
+		sprintf(pathname, EDGE_LBL_MODULE "/%s/" EDGE_LBL_SLAB "/%d" "/%cbrick" "/%s/%d",
+			buffer,
+			geo_slab(board->brd_geoid),
+			(board->brd_type == KLTYPE_IBRICK) ? 'I' :
+			(board->brd_type == KLTYPE_PBRICK) ? 'P' :
+			(board->brd_type == KLTYPE_XBRICK) ? 'X' : '?',
+			EDGE_LBL_XTALK, widgetnum);
+		
+		DBG("io_xswitch_widget_init: path= %s\n", pathname);
+		rc = hwgraph_path_add(hwgraph_root, pathname, &widgetv);
+		
+		ASSERT(rc == GRAPH_SUCCESS);
+
+		/* This is needed to let the user programs to map the
+		 * module,slot numbers to the corresponding widget numbers
+		 * on the crossbow.
+		 */
+		device_master_set(hwgraph_connectpt_get(widgetv), hubv);
+		sprintf(name, "%d", widgetnum);
+		DBG("io_xswitch_widget_init: FIXME hwgraph_edge_add %s xswitchv 0x%p, widgetv 0x%p\n", name, xswitchv, widgetv);
+		rc = hwgraph_edge_add(xswitchv, widgetv, name);
+		
+		/*
+		 * crosstalk switch code tracks which
+		 * widget is attached to each link.
+		 */
+		xswitch_info_vhdl_set(xswitch_info, widgetnum, widgetv);
+		
+		/*
+		 * Peek at the widget to get its crosstalk part and
+		 * mfgr numbers, then present it to the generic xtalk
+		 * bus provider to have its driver attach routine
+		 * called (or not).
+		 */
+		widget_id = XWIDGET_ID_READ(nasid, widgetnum);
+		hwid.part_num = XWIDGET_PART_NUM(widget_id);
+		hwid.rev_num = XWIDGET_REV_NUM(widget_id);
+		hwid.mfg_num = XWIDGET_MFG_NUM(widget_id);
+		/* Store some inventory information about
+		 * the xwidget in the hardware graph.
+		 */
+		xwidget_inventory_add(widgetv,board,hwid);
+
+		(void)xwidget_register(&hwid, widgetv, widgetnum,
+				       hubv, hub_widgetid,
+				       aa);
+
+		ia64_sn_sysctl_iobrick_module_get(nasid, &io_module);
+
+		if (io_module >= 0) {
+			char			buffer[16];
+			devfs_handle_t		to, from;
+
+			memset(buffer, 0, 16);
+			format_module_id(buffer, geo_module(board->brd_geoid), MODULE_FORMAT_BRIEF);
+
+			bt = toupper(MODULE_GET_BTCHAR(io_module));
+			/* Add a helper vertex so xbow monitoring
+			* can identify the brick type. It's simply
+			* an edge from the widget 0 vertex to the
+			*  brick vertex.
+			*/
+
+			sprintf(pathname, "/dev/hw/" EDGE_LBL_MODULE "/%s/"
+				EDGE_LBL_SLAB "/%d/"
+				EDGE_LBL_NODE "/" EDGE_LBL_XTALK "/"
+				"0",
+				buffer, geo_slab(board->brd_geoid));
+			from = hwgraph_path_to_vertex(pathname);
+			ASSERT_ALWAYS(from);
+			sprintf(pathname, "/dev/hw/" EDGE_LBL_MODULE "/%s/"
+				EDGE_LBL_SLAB "/%d/"
+				"%cbrick",
+				buffer, geo_slab(board->brd_geoid), bt);
+
+			to = hwgraph_path_to_vertex(pathname);
+			ASSERT_ALWAYS(to);
+			rc = hwgraph_edge_add(from, to,
+				EDGE_LBL_INTERCONNECT);
+			if (rc == -EEXIST)
+				goto link_done;
+			if (rc != GRAPH_SUCCESS) {
+				printk("%s: Unable to establish link"
+					" for xbmon.", pathname);
+			}
+link_done:
+		}
+
+#ifdef	SN0_USE_BTE
+		bte_bpush_war(cnode, (void *)board);
+#endif
+	}
+}
+
+
+static void
+io_init_xswitch_widgets(devfs_handle_t xswitchv, cnodeid_t cnode)
+{
+	xwidgetnum_t		widgetnum;
+	async_attach_t          aa;
+
+	aa = async_attach_new();
+	
+	DBG("io_init_xswitch_widgets: xswitchv 0x%p for cnode %d\n", xswitchv, cnode);
+
+	for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; 
+	     widgetnum++) {
+		io_xswitch_widget_init(xswitchv,
+				       cnodeid_to_vertex(cnode),
+				       widgetnum, aa);
+	}
+	/* 
+	 * Wait for parallel attach threads, if any, to complete.
+	 */
+	async_attach_waitall(aa);
+	async_attach_free(aa);
+}
+
+/*
+ * For each PCI bridge connected to the xswitch, add a link from the
+ * board's klconfig info to the bridge's hwgraph vertex.  This lets
+ * the FRU analyzer find the bridge without traversing the hardware
+ * graph and risking hangs.
+ */
+static void
+io_link_xswitch_widgets(devfs_handle_t xswitchv, cnodeid_t cnodeid)
+{
+	xwidgetnum_t		widgetnum;
+	char 			pathname[128];
+	devfs_handle_t		vhdl;
+	nasid_t			nasid, peer_nasid;
+	lboard_t		*board;
+
+
+
+	/* And its connected hub's nasids */
+	nasid = COMPACT_TO_NASID_NODEID(cnodeid);
+	peer_nasid = NODEPDA(cnodeid)->xbow_peer;
+
+	/* 
+	 * Look for paths matching "<widgetnum>/pci" under xswitchv.
+	 * For every widget, init. its lboard's hwgraph link.  If the
+	 * board has a PCI bridge, point the link to it.
+	 */
+	for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX;
+		 widgetnum++) {
+		sprintf(pathname, "%d", widgetnum);
+		if (hwgraph_traverse(xswitchv, pathname, &vhdl) !=
+		    GRAPH_SUCCESS)
+			continue;
+
+		board = find_lboard_module((lboard_t *)KL_CONFIG_INFO(nasid),
+				NODEPDA(cnodeid)->geoid);
+		if (board == NULL && peer_nasid != INVALID_NASID) {
+			/*
+			 * Try to find the board on our peer
+			 */
+			board = find_lboard_module(
+				(lboard_t *)KL_CONFIG_INFO(peer_nasid),
+				NODEPDA(cnodeid)->geoid);
+		}
+		if (board == NULL) {
+			printk(KERN_WARNING  "Could not find PROM info for vertex 0x%p, "
+				"FRU analyzer may fail",
+				(void *)vhdl);
+			return;
+		}
+
+		if ( Is_pic_on_this_nasid[nasid] ) {
+			/* Check both buses */
+			sprintf(pathname, "%d/"EDGE_LBL_PCIX_0, widgetnum);
+			if (hwgraph_traverse(xswitchv, pathname, &vhdl) == GRAPH_SUCCESS)
+				board->brd_graph_link = vhdl;
+			else {
+				sprintf(pathname, "%d/"EDGE_LBL_PCIX_1, widgetnum);
+				if (hwgraph_traverse(xswitchv, pathname, &vhdl) == GRAPH_SUCCESS)
+					board->brd_graph_link = vhdl;
+				else
+					board->brd_graph_link = GRAPH_VERTEX_NONE;
+			}
+		}
+		else {
+			sprintf(pathname, "%d/"EDGE_LBL_PCI, widgetnum);
+			if (hwgraph_traverse(xswitchv, pathname, &vhdl) == GRAPH_SUCCESS)
+				board->brd_graph_link = vhdl;
+			else
+				board->brd_graph_link = GRAPH_VERTEX_NONE;
+		}
+	}
+}
+
+/*
+ * Initialize all I/O on the specified node.
+ */
+static void
+io_init_node(cnodeid_t cnodeid)
+{
+	/*REFERENCED*/
+	devfs_handle_t hubv, switchv, widgetv;
+	struct xwidget_hwid_s hwid;
+	hubinfo_t hubinfo;
+	int is_xswitch;
+	nodepda_t	*npdap;
+	struct semaphore *peer_sema = 0;
+	uint32_t	widget_partnum;
+	nodepda_router_info_t *npda_rip;
+	cpu_cookie_t	c = 0;
+	extern int hubdev_docallouts(devfs_handle_t);
+
+	npdap = NODEPDA(cnodeid);
+
+	/*
+	 * Get the "top" vertex for this node's hardware
+	 * graph; it will carry the per-hub hub-specific
+	 * data, and act as the crosstalk provider master.
+	 * It's canonical path is probably something of the
+	 * form /hw/module/%M/slot/%d/node
+	 */
+	hubv = cnodeid_to_vertex(cnodeid);
+	DBG("io_init_node: Initialize IO for cnode %d hubv(node) 0x%p npdap 0x%p\n", cnodeid, hubv, npdap);
+
+	ASSERT(hubv != GRAPH_VERTEX_NONE);
+
+	hubdev_docallouts(hubv);
+
+	/*
+	 * Set up the dependent routers if we have any.
+	 */
+	npda_rip = npdap->npda_rip_first;
+
+	while(npda_rip) {
+		/* If the router info has not been initialized
+		 * then we need to do the router initialization
+		 */
+		if (!npda_rip->router_infop) {
+			router_init(cnodeid,0,npda_rip);
+		}
+		npda_rip = npda_rip->router_next;
+	}
+
+	/*
+	 * Read mfg info on this hub
+	 */
+
+	/* 
+	 * If nothing connected to this hub's xtalk port, we're done.
+	 */
+	early_probe_for_widget(hubv, &hwid);
+	if (hwid.part_num == XWIDGET_PART_NUM_NONE) {
+#ifdef PROBE_TEST
+		if ((cnodeid == 1) || (cnodeid == 2)) {
+			int index;
+
+			for (index = 0; index < 600; index++)
+				DBG("Interfering with device probing!!!\n");
+		}
+#endif
+		/* io_init_done takes cpu cookie as 2nd argument 
+		 * to do a restorenoderun for the setnoderun done 
+		 * at the start of this thread 
+		 */
+		
+		DBG("**** io_init_node: Node's 0x%p hub widget has XWIDGET_PART_NUM_NONE ****\n", hubv);
+		return;
+		/* NOTREACHED */
+	}
+
+	/* 
+	 * attach our hub_provider information to hubv,
+	 * so we can use it as a crosstalk provider "master"
+	 * vertex.
+	 */
+	xtalk_provider_register(hubv, &hub_provider);
+	xtalk_provider_startup(hubv);
+
+	/*
+	 * Create a vertex to represent the crosstalk bus
+	 * attached to this hub, and a vertex to be used
+	 * as the connect point for whatever is out there
+	 * on the other side of our crosstalk connection.
+	 *
+	 * Crosstalk Switch drivers "climb up" from their
+	 * connection point to try and take over the switch
+	 * point.
+	 *
+	 * Of course, the edges and verticies may already
+	 * exist, in which case our net effect is just to
+	 * associate the "xtalk_" driver with the connection
+	 * point for the device.
+	 */
+
+	(void)hwgraph_path_add(hubv, EDGE_LBL_XTALK, &switchv);
+
+	DBG("io_init_node: Created 'xtalk' entry to '../node/' xtalk vertex 0x%p\n", switchv);
+
+	ASSERT(switchv != GRAPH_VERTEX_NONE);
+
+	(void)hwgraph_edge_add(hubv, switchv, EDGE_LBL_IO);
+
+	DBG("io_init_node: Created symlink 'io' from ../node/io to ../node/xtalk \n");
+
+	/*
+	 * We need to find the widget id and update the basew_id field
+	 * accordingly. In particular, SN00 has direct connected bridge,
+	 * and hence widget id is Not 0.
+	 */
+
+	widget_partnum = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + WIDGET_ID))) & WIDGET_PART_NUM) >> WIDGET_PART_NUM_SHFT;
+
+	if (widget_partnum == BRIDGE_WIDGET_PART_NUM ||
+				widget_partnum == XBRIDGE_WIDGET_PART_NUM){
+		npdap->basew_id = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + BRIDGE_WID_CONTROL))) & WIDGET_WIDGET_ID);
+
+		DBG("io_init_node: Found XBRIDGE widget_partnum= 0x%x\n", widget_partnum);
+
+	} else if ((widget_partnum == XBOW_WIDGET_PART_NUM) ||
+			(widget_partnum == XXBOW_WIDGET_PART_NUM) ||
+			(widget_partnum == PXBOW_WIDGET_PART_NUM) ) {
+		/* 
+		 * Xbow control register does not have the widget ID field.
+		 * So, hard code the widget ID to be zero.
+		 */
+		DBG("io_init_node: Found XBOW widget_partnum= 0x%x\n", widget_partnum);
+		npdap->basew_id = 0;
+
+	} else {
+		npdap->basew_id = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + BRIDGE_WID_CONTROL))) & WIDGET_WIDGET_ID);
+
+		panic(" ****io_init_node: Unknown Widget Part Number 0x%x Widget ID 0x%x attached to Hubv 0x%p ****\n", widget_partnum, npdap->basew_id, (void *)hubv);
+
+		/*NOTREACHED*/
+	}
+	{
+		char widname[10];
+		sprintf(widname, "%x", npdap->basew_id);
+		(void)hwgraph_path_add(switchv, widname, &widgetv);
+		DBG("io_init_node: Created '%s' to '..node/xtalk/' vertex 0x%p\n", widname, widgetv);
+		ASSERT(widgetv != GRAPH_VERTEX_NONE);
+	}
+	
+	nodepda->basew_xc = widgetv;
+
+	is_xswitch = xwidget_hwid_is_xswitch(&hwid);
+
+	/* 
+	 * Try to become the master of the widget.  If this is an xswitch
+	 * with multiple hubs connected, only one will succeed.  Mastership
+	 * of an xswitch is used only when touching registers on that xswitch.
+	 * The slave xwidgets connected to the xswitch can be owned by various
+	 * masters.
+	 */
+	if (device_master_set(widgetv, hubv) == 0) {
+
+		/* Only one hub (thread) per Crosstalk device or switch makes
+		 * it to here.
+		 */
+
+		/* 
+		 * Initialize whatever xwidget is hanging off our hub.
+		 * Whatever it is, it's accessible through widgetnum 0.
+		 */
+		hubinfo_get(hubv, &hubinfo);
+
+		(void)xwidget_register(&hwid, widgetv, npdap->basew_id, hubv, hubinfo->h_widgetid, NULL);
+
+		if (!is_xswitch) {
+			/* io_init_done takes cpu cookie as 2nd argument 
+			 * to do a restorenoderun for the setnoderun done 
+			 * at the start of this thread 
+			 */
+			io_init_done(cnodeid,c);
+			/* NOTREACHED */
+		}
+
+		/* 
+		 * Special handling for Crosstalk Switches (e.g. xbow).
+		 * We need to do things in roughly the following order:
+		 *	1) Initialize xswitch hardware (done above)
+		 *	2) Determine which hubs are available to be widget masters
+		 *	3) Discover which links are active from the xswitch
+		 *	4) Assign xwidgets hanging off the xswitch to hubs
+		 *	5) Initialize all xwidgets on the xswitch
+		 */
+
+		volunteer_for_widgets(switchv, hubv);
+
+		/* If there's someone else on this crossbow, recognize him */
+		if (npdap->xbow_peer != INVALID_NASID) {
+			nodepda_t *peer_npdap = NODEPDA(NASID_TO_COMPACT_NODEID(npdap->xbow_peer));
+			peer_sema = &peer_npdap->xbow_sema;
+			volunteer_for_widgets(switchv, peer_npdap->node_vertex);
+		}
+
+		assign_widgets_to_volunteers(switchv, hubv);
+
+		/* Signal that we're done */
+		if (peer_sema) {
+			mutex_unlock(peer_sema);
+		}
+		
+	}
+	else {
+	    /* Wait 'til master is done assigning widgets. */
+	    mutex_lock(&npdap->xbow_sema);
+	}
+
+#ifdef PROBE_TEST
+	if ((cnodeid == 1) || (cnodeid == 2)) {
+		int index;
+
+		for (index = 0; index < 500; index++)
+			DBG("Interfering with device probing!!!\n");
+	}
+#endif
+	/* Now both nodes can safely inititialize widgets */
+	io_init_xswitch_widgets(switchv, cnodeid);
+	io_link_xswitch_widgets(switchv, cnodeid);
+
+	/* io_init_done takes cpu cookie as 2nd argument 
+	 * to do a restorenoderun for the setnoderun done 
+	 * at the start of this thread 
+	 */
+	io_init_done(cnodeid,c);
+
+	DBG("\nio_init_node: DONE INITIALIZED ALL I/O FOR CNODEID %d\n\n", cnodeid);
+}
+
+
+#define IOINIT_STKSZ	(16 * 1024)
+
+#define __DEVSTR1 	"/../.master/"
+#define __DEVSTR2 	"/target/"
+#define __DEVSTR3 	"/lun/0/disk/partition/"
+#define	__DEVSTR4	"/../ef"
+
+/*
+ * ioconfig starts numbering SCSI's at NUM_BASE_IO_SCSI_CTLR.
+ */
+#define NUM_BASE_IO_SCSI_CTLR 6
+/*
+ * This tells ioconfig where it can start numbering scsi controllers.
+ * Below this base number, platform-specific handles the numbering.
+ * XXX Irix legacy..controller numbering should be part of devfsd's job
+ */
+int num_base_io_scsi_ctlr = 2; /* used by syssgi */
+devfs_handle_t		base_io_scsi_ctlr_vhdl[NUM_BASE_IO_SCSI_CTLR];
+static devfs_handle_t	baseio_enet_vhdl,baseio_console_vhdl;
+
+/*
+ * Put the logical controller number information in the 
+ * scsi controller vertices for each scsi controller that
+ * is in a "fixed position".
+ */
+static void
+scsi_ctlr_nums_add(devfs_handle_t pci_vhdl)
+{
+	{
+		int i;
+
+		num_base_io_scsi_ctlr = NUM_BASE_IO_SCSI_CTLR;
+
+		/* Initialize base_io_scsi_ctlr_vhdl array */
+		for (i=0; i<num_base_io_scsi_ctlr; i++)
+			base_io_scsi_ctlr_vhdl[i] = GRAPH_VERTEX_NONE;
+	}
+	{
+	/*
+	 * May want to consider changing the SN0 code, above, to work more like
+	 * the way this works.
+	 */
+	devfs_handle_t base_ibrick_xbridge_vhdl;
+	devfs_handle_t base_ibrick_xtalk_widget_vhdl;
+	devfs_handle_t scsi_ctlr_vhdl;
+	int i;
+	graph_error_t rv;
+
+	/*
+	 * This is a table of "well-known" SCSI controllers and their well-known
+	 * controller numbers.  The names in the table start from the base IBrick's
+	 * Xbridge vertex, so the first component is the xtalk widget number.
+	 */
+	static struct {
+		char	*base_ibrick_scsi_path;
+		int	controller_number;
+	} hardwired_scsi_controllers[] = {
+		{"15/" EDGE_LBL_PCI "/1/" EDGE_LBL_SCSI_CTLR "/0", 0},
+		{"15/" EDGE_LBL_PCI "/2/" EDGE_LBL_SCSI_CTLR "/0", 1},
+		{"15/" EDGE_LBL_PCI "/3/" EDGE_LBL_SCSI_CTLR "/0", 2},
+		{"14/" EDGE_LBL_PCI "/1/" EDGE_LBL_SCSI_CTLR "/0", 3},
+		{"14/" EDGE_LBL_PCI "/2/" EDGE_LBL_SCSI_CTLR "/0", 4},
+		{"15/" EDGE_LBL_PCI "/6/ohci/0/" EDGE_LBL_SCSI_CTLR "/0", 5},
+		{NULL, -1} /* must be last */
+	};
+
+	base_ibrick_xtalk_widget_vhdl = hwgraph_connectpt_get(pci_vhdl);
+	ASSERT_ALWAYS(base_ibrick_xtalk_widget_vhdl != GRAPH_VERTEX_NONE);
+
+	base_ibrick_xbridge_vhdl = hwgraph_connectpt_get(base_ibrick_xtalk_widget_vhdl);
+	ASSERT_ALWAYS(base_ibrick_xbridge_vhdl != GRAPH_VERTEX_NONE);
+	hwgraph_vertex_unref(base_ibrick_xtalk_widget_vhdl);
+
+	/*
+	 * Iterate through the list of well-known SCSI controllers.
+	 * For each controller found, set it's controller number according
+	 * to the table.
+	 */
+	for (i=0; hardwired_scsi_controllers[i].base_ibrick_scsi_path != NULL; i++) {
+		rv = hwgraph_path_lookup(base_ibrick_xbridge_vhdl,
+			hardwired_scsi_controllers[i].base_ibrick_scsi_path, &scsi_ctlr_vhdl, NULL);
+
+		if (rv != GRAPH_SUCCESS) /* No SCSI at this path */
+			continue;
+
+		ASSERT(hardwired_scsi_controllers[i].controller_number < NUM_BASE_IO_SCSI_CTLR);
+		base_io_scsi_ctlr_vhdl[hardwired_scsi_controllers[i].controller_number] = scsi_ctlr_vhdl;
+		device_controller_num_set(scsi_ctlr_vhdl, hardwired_scsi_controllers[i].controller_number);
+		hwgraph_vertex_unref(scsi_ctlr_vhdl); /* (even though we're actually keeping a reference) */
+	}
+
+	hwgraph_vertex_unref(base_ibrick_xbridge_vhdl);
+	}
+}
+
+
+#include <asm/sn/ioerror_handling.h>
+devfs_handle_t		sys_critical_graph_root = GRAPH_VERTEX_NONE;
+
+/* Define the system critical vertices and connect them through
+ * a canonical parent-child relationships for easy traversal
+ * during io error handling.
+ */
+static void
+sys_critical_graph_init(void)
+{
+	devfs_handle_t		bridge_vhdl,master_node_vhdl;
+	devfs_handle_t  		xbow_vhdl = GRAPH_VERTEX_NONE;
+	extern devfs_handle_t	hwgraph_root;
+	devfs_handle_t		pci_slot_conn;
+	int			slot;
+	devfs_handle_t		baseio_console_conn;
+
+	DBG("sys_critical_graph_init: FIXME.\n");
+	baseio_console_conn = hwgraph_connectpt_get(baseio_console_vhdl);
+
+	if (baseio_console_conn == NULL) {
+		return;
+	}
+
+	/* Get the vertex handle for the baseio bridge */
+	bridge_vhdl = device_master_get(baseio_console_conn);
+
+	/* Get the master node of the baseio card */
+	master_node_vhdl = cnodeid_to_vertex(
+				master_node_get(baseio_console_vhdl));
+	
+	/* Add the "root->node" part of the system critical graph */
+
+	sys_critical_graph_vertex_add(hwgraph_root,master_node_vhdl);
+
+	/* Check if we have a crossbow */
+	if (hwgraph_traverse(master_node_vhdl,
+			     EDGE_LBL_XTALK"/0",
+			     &xbow_vhdl) == GRAPH_SUCCESS) {
+		/* We have a crossbow.Add "node->xbow" part of the system 
+		 * critical graph.
+		 */
+		sys_critical_graph_vertex_add(master_node_vhdl,xbow_vhdl);
+		
+		/* Add "xbow->baseio bridge" of the system critical graph */
+		sys_critical_graph_vertex_add(xbow_vhdl,bridge_vhdl);
+
+		hwgraph_vertex_unref(xbow_vhdl);
+	} else 
+		/* We donot have a crossbow. Add "node->baseio_bridge"
+		 * part of the system critical graph.
+		 */
+		sys_critical_graph_vertex_add(master_node_vhdl,bridge_vhdl);
+
+	/* Add all the populated PCI slot vertices to the system critical
+	 * graph with the bridge vertex as the parent.
+	 */
+	for (slot = 0 ; slot < 8; slot++) {
+		char	slot_edge[10];
+
+		sprintf(slot_edge,"%d",slot);
+		if (hwgraph_traverse(bridge_vhdl,slot_edge, &pci_slot_conn)
+		    != GRAPH_SUCCESS)
+			continue;
+		sys_critical_graph_vertex_add(bridge_vhdl,pci_slot_conn);
+		hwgraph_vertex_unref(pci_slot_conn);
+	}
+
+	hwgraph_vertex_unref(bridge_vhdl);
+
+	/* Add the "ioc3 pci connection point  -> console ioc3" part 
+	 * of the system critical graph
+	 */
+
+	if (hwgraph_traverse(baseio_console_vhdl,"..",&pci_slot_conn) ==
+	    GRAPH_SUCCESS) {
+		sys_critical_graph_vertex_add(pci_slot_conn, 
+					      baseio_console_vhdl);
+		hwgraph_vertex_unref(pci_slot_conn);
+	}
+
+	/* Add the "ethernet pci connection point  -> base ethernet" part of 
+	 * the system  critical graph
+	 */
+	if (hwgraph_traverse(baseio_enet_vhdl,"..",&pci_slot_conn) ==
+	    GRAPH_SUCCESS) {
+		sys_critical_graph_vertex_add(pci_slot_conn, 
+					      baseio_enet_vhdl);
+		hwgraph_vertex_unref(pci_slot_conn);
+	}
+
+	/* Add the "scsi controller pci connection point  -> base scsi 
+	 * controller" part of the system critical graph
+	 */
+	if (hwgraph_traverse(base_io_scsi_ctlr_vhdl[0],
+			     "../..",&pci_slot_conn) == GRAPH_SUCCESS) {
+		sys_critical_graph_vertex_add(pci_slot_conn, 
+					      base_io_scsi_ctlr_vhdl[0]);
+		hwgraph_vertex_unref(pci_slot_conn);
+	}
+	if (hwgraph_traverse(base_io_scsi_ctlr_vhdl[1],
+			     "../..",&pci_slot_conn) == GRAPH_SUCCESS) {
+		sys_critical_graph_vertex_add(pci_slot_conn, 
+					      base_io_scsi_ctlr_vhdl[1]);
+		hwgraph_vertex_unref(pci_slot_conn);
+	}
+	hwgraph_vertex_unref(baseio_console_conn);
+
+}
+
+static void
+baseio_ctlr_num_set(void)
+{
+	char 			name[MAXDEVNAME];
+	devfs_handle_t		console_vhdl, pci_vhdl, enet_vhdl;
+	devfs_handle_t		ioc3_console_vhdl_get(void);
+
+
+	DBG("baseio_ctlr_num_set; FIXME\n");
+	console_vhdl = ioc3_console_vhdl_get();
+	if (console_vhdl == GRAPH_VERTEX_NONE)
+		return;
+	/* Useful for setting up the system critical graph */
+	baseio_console_vhdl = console_vhdl;
+
+	vertex_to_name(console_vhdl,name,MAXDEVNAME);
+
+	strcat(name,__DEVSTR1);
+	pci_vhdl =  hwgraph_path_to_vertex(name);
+	scsi_ctlr_nums_add(pci_vhdl);
+	/* Unref the pci_vhdl due to the reference by hwgraph_path_to_vertex
+	 */
+	hwgraph_vertex_unref(pci_vhdl);
+
+	vertex_to_name(console_vhdl, name, MAXDEVNAME);
+	strcat(name, __DEVSTR4);
+	enet_vhdl = hwgraph_path_to_vertex(name);
+
+	/* Useful for setting up the system critical graph */
+	baseio_enet_vhdl = enet_vhdl;
+
+	device_controller_num_set(enet_vhdl, 0);
+	/* Unref the enet_vhdl due to the reference by hwgraph_path_to_vertex
+	 */
+	hwgraph_vertex_unref(enet_vhdl);
+}
+/* #endif */
+
+/*
+ * Initialize all I/O devices.  Starting closest to nodes, probe and
+ * initialize outward.
+ */
+void
+init_all_devices(void)
+{
+	/* Governor on init threads..bump up when safe 
+	 * (beware many devfs races) 
+	 */
+	cnodeid_t cnodeid, active;
+
+	active = 0;
+	for (cnodeid = 0; cnodeid < numnodes; cnodeid++) {
+                DBG("init_all_devices: Calling io_init_node() for cnode %d\n", cnodeid);
+                io_init_node(cnodeid);
+
+		DBG("init_all_devices: Done io_init_node() for cnode %d\n", cnodeid);
+	}
+
+	for (cnodeid = 0; cnodeid < numnodes; cnodeid++)
+		/*
+	 	 * Update information generated by IO init.
+		 */
+		update_node_information(cnodeid);
+
+	baseio_ctlr_num_set();
+	/* Setup the system critical graph (which is a subgraph of the
+	 * main hwgraph). This information is useful during io error
+	 * handling.
+	 */
+	sys_critical_graph_init();
+
+#if HWG_PRINT
+	hwgraph_print();
+#endif
+
+}
+
+#define toint(x) ((int)(x) - (int)('0'))
+
+void
+devnamefromarcs(char *devnm)
+{
+	int 			val;
+	char 			tmpnm[MAXDEVNAME];
+	char 			*tmp1, *tmp2;
+	
+	val = strncmp(devnm, "dks", 3);
+	if (val != 0) 
+		return;
+	tmp1 = devnm + 3;
+	if (!isdigit(*tmp1))
+		return;
+
+	val = 0;
+	while (isdigit(*tmp1)) {
+		val = 10*val+toint(*tmp1);
+		tmp1++;
+	}
+
+	if(*tmp1 != 'd')
+		return;
+	else
+		tmp1++;
+
+	if ((val < 0) || (val >= num_base_io_scsi_ctlr)) {
+		int i;
+		int viable_found = 0;
+
+		DBG("Only controller numbers 0..%d  are supported for\n", NUM_BASE_IO_SCSI_CTLR-1);
+		DBG("prom \"root\" variables of the form dksXdXsX.\n");
+		DBG("To use another disk you must use the full hardware graph path\n\n");
+		DBG("Possible controller numbers for use in 'dksXdXsX' on this system: ");
+		for (i=0; i<NUM_BASE_IO_SCSI_CTLR; i++) {
+			if (base_io_scsi_ctlr_vhdl[i] != GRAPH_VERTEX_NONE) {
+				DBG("%d ", i);
+				viable_found=1;
+			}
+		}
+		if (viable_found)
+			DBG("\n");
+		else
+			DBG("none found!\n");
+
+		DELAY(15000000);
+		//prom_reboot();
+		panic("FIXME: devnamefromarcs: should call prom_reboot here.\n");
+		/* NOTREACHED */
+	}
+		
+	ASSERT(base_io_scsi_ctlr_vhdl[val] != GRAPH_VERTEX_NONE);
+	vertex_to_name(base_io_scsi_ctlr_vhdl[val],
+		       tmpnm,
+		       MAXDEVNAME);
+	tmp2 = 	tmpnm + strlen(tmpnm);
+	strcpy(tmp2, __DEVSTR2);
+	tmp2 += strlen(__DEVSTR2);
+	while (*tmp1 != 's') {
+		if((*tmp2++ = *tmp1++) == '\0')
+			return;
+	}	
+	tmp1++;
+	strcpy(tmp2, __DEVSTR3);
+	tmp2 += strlen(__DEVSTR3);
+	while ( (*tmp2++ = *tmp1++) )
+		;
+	tmp2--;
+	*tmp2++ = '/';
+	strcpy(tmp2, EDGE_LBL_BLOCK);
+	strcpy(devnm,tmpnm);
+}
+
+static
+struct io_brick_map_s io_brick_tab[] = {
+
+/* Ibrick widget number to PCI bus number map */
+ {      MODULE_IBRICK,                          /* Ibrick type    */ 
+    /*  PCI Bus #                                  Widget #       */
+    {   0, 0, 0, 0, 0, 0, 0, 0,                 /* 0x0 - 0x7      */
+        0,                                      /* 0x8            */
+        0,                                      /* 0x9            */
+        0, 0,                                   /* 0xa - 0xb      */
+        0,                                      /* 0xc            */
+        0,                                      /* 0xd            */
+        2,                                      /* 0xe            */
+        1                                       /* 0xf            */
+     }
+ },
+
+/* Pbrick widget number to PCI bus number map */
+ {      MODULE_PBRICK,                          /* Pbrick type    */ 
+    /*  PCI Bus #                                  Widget #       */
+    {   0, 0, 0, 0, 0, 0, 0, 0,                 /* 0x0 - 0x7      */
+        2,                                      /* 0x8            */
+        1,                                      /* 0x9            */
+        0, 0,                                   /* 0xa - 0xb      */
+        5,                                      /* 0xc            */
+        6,                                      /* 0xd            */
+        4,                                      /* 0xe            */
+        3                                       /* 0xf            */
+    }
+ },
+
+/* PXbrick widget number to PCI bus number map */
+ {      MODULE_PXBRICK,                         /* PXbrick type   */ 
+    /*  PCI Bus #                                  Widget #       */
+    {   0, 0, 0, 0, 0, 0, 0, 0,                 /* 0x0 - 0x7      */
+        0,                                      /* 0x8            */
+        0,                                      /* 0x9            */
+        0, 0,                                   /* 0xa - 0xb      */
+        1,                                      /* 0xc            */
+        5,                                      /* 0xd            */
+        0,                                      /* 0xe            */
+        3                                       /* 0xf            */
+    }
+ },
+
+/* Xbrick widget to XIO slot map */
+ {      MODULE_XBRICK,                          /* Xbrick type    */ 
+    /*  XIO Slot #                                 Widget #       */
+    {   0, 0, 0, 0, 0, 0, 0, 0,                 /* 0x0 - 0x7      */
+        1,                                      /* 0x8            */
+        3,                                      /* 0x9            */
+        0, 0,                                   /* 0xa - 0xb      */
+        2,                                      /* 0xc            */
+        4,                                      /* 0xd            */
+        0,                                      /* 0xe            */
+        0                                       /* 0xf            */
+    }
+ }
+};
+
+/*
+ * Use the brick's type to map a widget number to a meaningful int
+ */
+int
+io_brick_map_widget(int brick_type, int widget_num)
+{
+        int num_bricks, i;
+
+        /* Calculate number of bricks in table */
+        num_bricks = sizeof(io_brick_tab)/sizeof(io_brick_tab[0]);
+
+        /* Look for brick prefix in table */
+        for (i = 0; i < num_bricks; i++) {
+               if (brick_type == io_brick_tab[i].ibm_type)
+                       return(io_brick_tab[i].ibm_map_wid[widget_num]);
+        }
+
+        return 0;
+
+}
+
+/*
+ * Use the device's vertex to map the device's widget to a meaningful int
+ */
+int
+io_path_map_widget(devfs_handle_t vertex)
+{
+        char hw_path_name[MAXDEVNAME];
+        char *wp, *bp, *sp = NULL;
+        int  widget_num;
+	long atoi(char *);
+	int hwgraph_vertex_name_get(devfs_handle_t vhdl, char *buf, uint buflen);
+
+
+        /* Get the full path name of the vertex */
+        if (GRAPH_SUCCESS != hwgraph_vertex_name_get(vertex, hw_path_name,
+                                                     MAXDEVNAME))
+                return 0;
+
+        /* Find the widget number in the path name */
+        wp = strstr(hw_path_name, "/"EDGE_LBL_XTALK"/");
+        if (wp == NULL)
+                return 0;
+        widget_num = atoi(wp+7);
+        if (widget_num < XBOW_PORT_8 || widget_num > XBOW_PORT_F)
+                return 0;
+
+        /* Find "brick" in the path name */
+        bp = strstr(hw_path_name, "brick");
+        if (bp == NULL)
+                return 0;
+
+        /* Find preceding slash */
+        sp = bp;
+        while (sp > hw_path_name) {
+                sp--;
+                if (*sp == '/')
+                        break;
+        }
+
+        /* Invalid if no preceding slash */
+        if (!sp)
+                return 0;
+
+        /* Bump slash pointer to "brick" prefix */
+        sp++;
+        /*
+         * Verify "brick" prefix length;  valid exaples:
+         * 'I' from "/Ibrick"
+         * 'P' from "/Pbrick"
+         * 'X' from "/Xbrick"
+         */
+         if ((bp - sp) != 1)
+                return 0;
+
+        return (io_brick_map_widget((int)*sp, widget_num));
+
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/module.c linux-2.4.21-pre6/arch/ia64/sn/io/sn2/module.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/module.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn2/module.c	2003-03-26 23:48:57.000000000 +0000
@@ -0,0 +1,280 @@
+/* $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) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/io.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/xtalk/xbow.h>
+#include <asm/sn/pci/bridge.h>
+#include <asm/sn/klconfig.h>
+#include <asm/sn/sn1/hubdev.h>
+#include <asm/sn/module.h>
+#include <asm/sn/pci/pcibr.h>
+#include <asm/sn/xtalk/xswitch.h>
+#include <asm/sn/nodepda.h>
+#include <asm/sn/sn_cpuid.h>
+
+
+/* #define LDEBUG	1  */
+
+#ifdef LDEBUG
+#define DPRINTF		printk
+#define printf		printk
+#else
+#define DPRINTF(x...)
+#endif
+
+module_t	       *modules[MODULE_MAX];
+int			nummodules;
+
+#define SN00_SERIAL_FUDGE	0x3b1af409d513c2
+#define SN0_SERIAL_FUDGE	0x6e
+
+void
+encode_int_serial(uint64_t src,uint64_t *dest)
+{
+    uint64_t val;
+    int i;
+
+    val = src + SN00_SERIAL_FUDGE;
+
+
+    for (i = 0; i < sizeof(long long); i++) {
+	((char*)dest)[i] =
+	    ((char*)&val)[sizeof(long long)/2 +
+			 ((i%2) ? ((i/2 * -1) - 1) : (i/2))];
+    }
+}
+
+
+void
+decode_int_serial(uint64_t src, uint64_t *dest)
+{
+    uint64_t val;
+    int i;
+
+    for (i = 0; i < sizeof(long long); i++) {
+	((char*)&val)[sizeof(long long)/2 +
+		     ((i%2) ? ((i/2 * -1) - 1) : (i/2))] =
+	    ((char*)&src)[i];
+    }
+
+    *dest = val - SN00_SERIAL_FUDGE;
+}
+
+
+void
+encode_str_serial(const char *src, char *dest)
+{
+    int i;
+
+    for (i = 0; i < MAX_SERIAL_NUM_SIZE; i++) {
+
+	dest[i] = src[MAX_SERIAL_NUM_SIZE/2 +
+		     ((i%2) ? ((i/2 * -1) - 1) : (i/2))] +
+	    SN0_SERIAL_FUDGE;
+    }
+}
+
+void
+decode_str_serial(const char *src, char *dest)
+{
+    int i;
+
+    for (i = 0; i < MAX_SERIAL_NUM_SIZE; i++) {
+	dest[MAX_SERIAL_NUM_SIZE/2 +
+	    ((i%2) ? ((i/2 * -1) - 1) : (i/2))] = src[i] -
+	    SN0_SERIAL_FUDGE;
+    }
+}
+
+
+module_t *module_lookup(moduleid_t id)
+{
+    int			i;
+
+    for (i = 0; i < nummodules; i++)
+	if (modules[i]->id == id) {
+	    DPRINTF("module_lookup: found m=0x%p\n", modules[i]);
+	    return modules[i];
+	}
+
+    return NULL;
+}
+
+/*
+ * module_add_node
+ *
+ *   The first time a new module number is seen, a module structure is
+ *   inserted into the module list in order sorted by module number
+ *   and the structure is initialized.
+ *
+ *   The node number is added to the list of nodes in the module.
+ */
+
+module_t *module_add_node(geoid_t geoid, cnodeid_t cnodeid)
+{
+    module_t	       *m;
+    int			i;
+    char		buffer[16];
+    moduleid_t		moduleid;
+
+    memset(buffer, 0, 16);
+    moduleid = geo_module(geoid);
+    format_module_id(buffer, moduleid, MODULE_FORMAT_BRIEF);
+    DPRINTF("module_add_node: moduleid=%s node=%d\n", buffer, cnodeid);
+
+    if ((m = module_lookup(moduleid)) == 0) {
+	m = kmalloc(sizeof (module_t), GFP_KERNEL);
+	memset(m, 0 , sizeof(module_t));
+	ASSERT_ALWAYS(m);
+
+	m->id = moduleid;
+	spin_lock_init(&m->lock);
+
+	mutex_init_locked(&m->thdcnt);
+
+	/* Insert in sorted order by module number */
+
+	for (i = nummodules; i > 0 && modules[i - 1]->id > moduleid; i--)
+	    modules[i] = modules[i - 1];
+
+	modules[i] = m;
+	nummodules++;
+    }
+
+    m->nodes[m->nodecnt] = cnodeid;
+    m->geoid[m->nodecnt] = geoid;
+    m->nodecnt++;
+
+    DPRINTF("module_add_node: module %s now has %d nodes\n", buffer, m->nodecnt);
+
+    return m;
+}
+
+int module_probe_snum(module_t *m, nasid_t nasid)
+{
+    lboard_t	       *board;
+    klmod_serial_num_t *comp;
+    char * bcopy(const char * src, char * dest, int count);
+    char serial_number[16];
+
+    /*
+     * record brick serial number
+     */
+    board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid), KLTYPE_SNIA);
+
+    if (! board || KL_CONFIG_DUPLICATE_BOARD(board))
+    {
+#if	LDEBUG
+	printf ("module_probe_snum: no IP35 board found!\n");
+#endif
+	return 0;
+    }
+
+    board_serial_number_get( board, serial_number );
+    if( serial_number[0] != '\0' ) {
+	encode_str_serial( serial_number, m->snum.snum_str );
+	m->snum_valid = 1;
+    }
+#if	LDEBUG
+    else {
+	printf("module_probe_snum: brick serial number is null!\n");
+    }
+    printf("module_probe_snum: brick serial number == %s\n", serial_number);
+#endif /* DEBUG */
+
+    board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid),
+			KLTYPE_IOBRICK_XBOW);
+
+    if (! board || KL_CONFIG_DUPLICATE_BOARD(board))
+	return 0;
+
+    comp = GET_SNUM_COMP(board);
+
+    if (comp) {
+#if LDEBUG
+	    int i;
+
+	    printf("********found module with id %x and string", m->id);
+
+	    for (i = 0; i < MAX_SERIAL_NUM_SIZE; i++)
+		printf(" %x ", comp->snum.snum_str[i]);
+
+	    printf("\n");	/* Fudged string is not ASCII */
+#endif
+
+	    if (comp->snum.snum_str[0] != '\0') {
+		bcopy(comp->snum.snum_str,
+		      m->sys_snum,
+		      MAX_SERIAL_NUM_SIZE);
+		m->sys_snum_valid = 1;
+	    }
+    }
+
+    if (m->sys_snum_valid)
+	return 1;
+    else {
+	DPRINTF("Invalid serial number for module %d, "
+		"possible missing or invalid NIC.", m->id);
+	return 0;
+    }
+}
+
+void
+io_module_init(void)
+{
+    cnodeid_t		node;
+    lboard_t	       *board;
+    nasid_t		nasid;
+    int			nserial;
+    module_t	       *m;
+
+    DPRINTF("*******module_init\n");
+
+    nserial = 0;
+
+    for (node = 0; node < numnodes; node++) {
+	nasid = COMPACT_TO_NASID_NODEID(node);
+
+	board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid), KLTYPE_SNIA);
+	ASSERT(board);
+
+	m = module_add_node(board->brd_geoid, node);
+
+	if (! m->snum_valid && module_probe_snum(m, nasid))
+	    nserial++;
+    }
+
+    DPRINTF("********found total of %d serial numbers in the system\n",
+	    nserial);
+
+    if (nserial == 0)
+	printk(KERN_WARNING  "io_module_init: No serial number found.\n");
+}
+
+int
+get_kmod_info(cmoduleid_t cmod, module_info_t *mod_info)
+{
+    if (cmod < 0 || cmod >= nummodules)
+	return -EINVAL;
+
+    mod_info->mod_num = modules[cmod]->id;
+
+    ia64_sn_sys_serial_get(mod_info->serial_str);
+    
+    mod_info->serial_num = ia64_sn_partition_serial_get();
+
+    return 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/pci_bus_cvlink.c linux-2.4.21-pre6/arch/ia64/sn/io/sn2/pci_bus_cvlink.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/pci_bus_cvlink.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn2/pci_bus_cvlink.c	2003-03-26 23:49:25.000000000 +0000
@@ -0,0 +1,811 @@
+/* $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) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <asm/sn/types.h>
+#include <asm/sn/hack.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/io.h>
+#include <asm/sn/driver.h>
+#include <asm/sn/iograph.h>
+#include <asm/param.h>
+#include <asm/sn/pio.h>
+#include <asm/sn/xtalk/xwidget.h>
+#include <asm/sn/sn_private.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/hcl_util.h>
+#include <asm/sn/intr.h>
+#include <asm/sn/xtalk/xtalkaddrs.h>
+#include <asm/sn/klconfig.h>
+#include <asm/sn/nodepda.h>
+#include <asm/sn/pci/pciio.h>
+#include <asm/sn/pci/pcibr.h>
+#include <asm/sn/pci/pcibr_private.h>
+#include <asm/sn/pci/pci_bus_cvlink.h>
+#include <asm/sn/simulator.h>
+#include <asm/sn/sn_cpuid.h>
+
+extern int bridge_rev_b_data_check_disable;
+
+devfs_handle_t busnum_to_pcibr_vhdl[MAX_PCI_XWIDGET];
+nasid_t busnum_to_nid[MAX_PCI_XWIDGET];
+void * busnum_to_atedmamaps[MAX_PCI_XWIDGET];
+unsigned char num_bridges;
+static int done_probing = 0;
+
+static int pci_bus_map_create(devfs_handle_t xtalk);
+devfs_handle_t devfn_to_vertex(unsigned char busnum, unsigned int devfn);
+
+extern unsigned char Is_pic_on_this_nasid[512];
+
+extern void sn_init_irq_desc(void);
+
+
+/*
+ * For the given device, initialize whether it is a PIC device.
+ */
+static void
+set_isPIC(struct sn_device_sysdata *device_sysdata)
+{
+	pciio_info_t pciio_info = pciio_info_get(device_sysdata->vhdl);
+	pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);
+
+	device_sysdata->isPIC = IS_PIC_SOFT(pcibr_soft);;
+}
+
+/*
+ * pci_bus_cvlink_init() - To be called once during initialization before 
+ *	SGI IO Infrastructure init is called.
+ */
+void
+pci_bus_cvlink_init(void)
+{
+
+	extern void ioconfig_bus_init(void);
+
+	memset(busnum_to_pcibr_vhdl, 0x0, sizeof(devfs_handle_t) * MAX_PCI_XWIDGET);
+	memset(busnum_to_nid, 0x0, sizeof(nasid_t) * MAX_PCI_XWIDGET);
+
+	memset(busnum_to_atedmamaps, 0x0, sizeof(void *) * MAX_PCI_XWIDGET);
+
+	num_bridges = 0;
+
+	// ioconfig_bus_init();
+}
+
+/*
+ * pci_bus_to_vertex() - Given a logical Linux Bus Number returns the associated 
+ *	pci bus vertex from the SGI IO Infrastructure.
+ */
+devfs_handle_t
+pci_bus_to_vertex(unsigned char busnum)
+{
+
+	devfs_handle_t	pci_bus = NULL;
+
+
+	/*
+	 * First get the xwidget vertex.
+	 */
+	pci_bus = busnum_to_pcibr_vhdl[busnum];
+	return(pci_bus);
+}
+
+/*
+ * devfn_to_vertex() - returns the vertex of the device given the bus, slot, 
+ *	and function numbers.
+ */
+devfs_handle_t
+devfn_to_vertex(unsigned char busnum, unsigned int devfn)
+{
+
+	int slot = 0;
+	int func = 0;
+	char	name[16];
+	devfs_handle_t  pci_bus = NULL;
+	devfs_handle_t	device_vertex = (devfs_handle_t)NULL;
+
+	/*
+	 * Go get the pci bus vertex.
+	 */
+	pci_bus = pci_bus_to_vertex(busnum);
+	if (!pci_bus) {
+		/*
+		 * During probing, the Linux pci code invents non existant
+		 * bus numbers and pci_dev structures and tries to access
+		 * them to determine existance. Don't crib during probing.
+		 */
+		if (done_probing)
+			printk("devfn_to_vertex: Invalid bus number %d given.\n", busnum);
+		return(NULL);
+	}
+
+
+	/*
+	 * Go get the slot&function vertex.
+	 * Should call pciio_slot_func_to_name() when ready.
+	 */
+	slot = PCI_SLOT(devfn);
+	func = PCI_FUNC(devfn);
+
+	/*
+	 * For a NON Multi-function card the name of the device looks like:
+	 * ../pci/1, ../pci/2 ..
+	 */
+	if (func == 0) {
+        	sprintf(name, "%d", slot);
+		if (hwgraph_traverse(pci_bus, name, &device_vertex) == 
+			GRAPH_SUCCESS) {
+			if (device_vertex) {
+				return(device_vertex);
+			}
+		}
+	}
+			
+	/*
+	 * This maybe a multifunction card.  It's names look like:
+	 * ../pci/1a, ../pci/1b, etc.
+	 */
+	sprintf(name, "%d%c", slot, 'a'+func);
+	if (hwgraph_traverse(pci_bus, name, &device_vertex) != GRAPH_SUCCESS) {
+		if (!device_vertex) {
+			return(NULL);
+		}
+	}
+
+	return(device_vertex);
+}
+
+/*
+ * For the given device, initialize the addresses for both the Device(x) Flush 
+ * Write Buffer register and the Xbow Flush Register for the port the PCI bus 
+ * is connected.
+ */
+static void
+set_flush_addresses(struct pci_dev *device_dev, 
+	struct sn_device_sysdata *device_sysdata)
+{
+	pciio_info_t pciio_info = pciio_info_get(device_sysdata->vhdl);
+	pciio_slot_t pciio_slot = pciio_info_slot_get(pciio_info);
+	pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);
+    	bridge_t               *bridge = pcibr_soft->bs_base;
+	nasid_t			nasid;
+
+	/*
+	 * Get the nasid from the bridge.
+	 */
+	nasid = NASID_GET(device_sysdata->dma_buf_sync);
+	if (IS_PIC_DEVICE(device_dev)) {
+		device_sysdata->dma_buf_sync = (volatile unsigned int *)
+			&bridge->b_wr_req_buf[pciio_slot].reg;
+		device_sysdata->xbow_buf_sync = (volatile unsigned int *)
+			XBOW_PRIO_LINKREGS_PTR(NODE_SWIN_BASE(nasid, 0),
+			pcibr_soft->bs_xid);
+	} else {
+		/*
+		 * Accessing Xbridge and Xbow register when SHUB swapoper is on!.
+		 */
+		device_sysdata->dma_buf_sync = (volatile unsigned int *)
+			((uint64_t)&(bridge->b_wr_req_buf[pciio_slot].reg)^4);
+		device_sysdata->xbow_buf_sync = (volatile unsigned int *)
+			((uint64_t)(XBOW_PRIO_LINKREGS_PTR(
+			NODE_SWIN_BASE(nasid, 0), pcibr_soft->bs_xid)) ^ 4);
+	}
+
+#ifdef DEBUG
+	printk("set_flush_addresses: dma_buf_sync %p xbow_buf_sync %p\n", 
+		device_sysdata->dma_buf_sync, device_sysdata->xbow_buf_sync);
+
+printk("set_flush_addresses: dma_buf_sync\n");
+	while((volatile unsigned int )*device_sysdata->dma_buf_sync);
+printk("set_flush_addresses: xbow_buf_sync\n");
+	while((volatile unsigned int )*device_sysdata->xbow_buf_sync);
+#endif
+
+}
+
+/*
+ * Most drivers currently do not properly tell the arch specific pci dma
+ * interfaces whether they can handle A64. Here is where we privately
+ * keep track of this.
+ */
+static void __init
+set_sn_pci64(struct pci_dev *dev)
+{
+	unsigned short vendor = dev->vendor;
+	unsigned short device = dev->device;
+
+	if (vendor == PCI_VENDOR_ID_QLOGIC) {
+		if ((device == PCI_DEVICE_ID_QLOGIC_ISP2100) ||
+				(device == PCI_DEVICE_ID_QLOGIC_ISP2200)) {
+			SET_PCIA64(dev);
+			return;
+		}
+	}
+
+	if (vendor == PCI_VENDOR_ID_SGI) {
+		if (device == PCI_DEVICE_ID_SGI_IOC3) {
+			SET_PCIA64(dev);
+			return;
+		}
+	}
+
+}
+
+/*
+ * sn_pci_fixup() - This routine is called when platform_pci_fixup() is 
+ *	invoked at the end of pcibios_init() to link the Linux pci 
+ *	infrastructure to SGI IO Infrasturcture - ia64/kernel/pci.c
+ *
+ *	Other platform specific fixup can also be done here.
+ */
+void
+sn_pci_fixup(int arg)
+{
+	struct list_head *ln;
+	struct pci_bus *pci_bus = NULL;
+	struct pci_dev *device_dev = NULL;
+	struct sn_widget_sysdata *widget_sysdata;
+	struct sn_device_sysdata *device_sysdata;
+	pciio_intr_t intr_handle;
+	int cpuid, bit;
+	devfs_handle_t device_vertex;
+	pciio_intr_line_t lines;
+	extern void sn_pci_find_bios(void);
+	extern int numnodes;
+	int cnode;
+	extern void io_sh_swapper(int, int);
+
+	for (cnode = 0; cnode < numnodes; cnode++) {
+		if ( !Is_pic_on_this_nasid[cnodeid_to_nasid(cnode)] )
+			io_sh_swapper((cnodeid_to_nasid(cnode)), 0);
+	}
+
+	if (arg == 0) {
+#ifdef CONFIG_PROC_FS
+		extern void register_sn_partition_id(void);
+		extern void register_sn_serial_numbers(void);
+#endif
+
+		sn_init_irq_desc();
+		sn_pci_find_bios();
+		for (cnode = 0; cnode < numnodes; cnode++) {
+			extern void intr_init_vecblk(nodepda_t *npda, cnodeid_t, int);
+			intr_init_vecblk(NODEPDA(cnode), cnode, 0);
+		} 
+
+		/*
+		 * When we return to generic Linux, Swapper is always on ..
+		 */
+		for (cnode = 0; cnode < numnodes; cnode++) {
+			if ( !Is_pic_on_this_nasid[cnodeid_to_nasid(cnode)] )
+				io_sh_swapper((cnodeid_to_nasid(cnode)), 1);
+		}
+#ifdef CONFIG_PROC_FS
+		register_sn_partition_id();
+		register_sn_serial_numbers();
+#endif
+		return;
+	}
+
+
+	done_probing = 1;
+
+	/*
+	 * Initialize the pci bus vertex in the pci_bus struct.
+	 */
+	for( ln = pci_root_buses.next; ln != &pci_root_buses; ln = ln->next) {
+		pci_bus = pci_bus_b(ln);
+		widget_sysdata = kmalloc(sizeof(struct sn_widget_sysdata), 
+					GFP_KERNEL);
+		widget_sysdata->vhdl = pci_bus_to_vertex(pci_bus->number);
+		pci_bus->sysdata = (void *)widget_sysdata;
+	}
+
+	/*
+ 	 * set the root start and end so that drivers calling check_region()
+	 * won't see a conflict
+	 */
+	ioport_resource.start  = 0xc000000000000000;
+	ioport_resource.end =    0xcfffffffffffffff;
+
+	/*
+	 * Set the root start and end for Mem Resource.
+	 */
+	iomem_resource.start = 0;
+	iomem_resource.end = 0xffffffffffffffff;
+
+	/*
+	 * Initialize the device vertex in the pci_dev struct.
+	 */
+	pci_for_each_dev(device_dev) {
+		unsigned int irq;
+		int idx;
+		u16 cmd;
+		devfs_handle_t vhdl;
+		unsigned long size;
+		extern int bit_pos_to_irq(int);
+
+		if (device_dev->vendor == PCI_VENDOR_ID_SGI &&
+				device_dev->device == PCI_DEVICE_ID_SGI_IOC3) {
+			extern void pci_fixup_ioc3(struct pci_dev *d);
+			pci_fixup_ioc3(device_dev);
+		}
+
+		/* Set the device vertex */
+
+		device_sysdata = kmalloc(sizeof(struct sn_device_sysdata),
+					GFP_KERNEL);
+		device_sysdata->vhdl = devfn_to_vertex(device_dev->bus->number, device_dev->devfn);
+		device_sysdata->isa64 = 0;
+		/*
+		 * Set the xbridge Device(X) Write Buffer Flush and Xbow Flush 
+		 * register addresses.
+		 */
+		(void) set_flush_addresses(device_dev, device_sysdata);
+
+		device_dev->sysdata = (void *) device_sysdata;
+		set_sn_pci64(device_dev);
+		set_isPIC(device_sysdata);
+
+		pci_read_config_word(device_dev, PCI_COMMAND, &cmd);
+
+		/*
+		 * Set the resources address correctly.  The assumption here 
+		 * is that the addresses in the resource structure has been
+		 * read from the card and it was set in the card by our
+		 * Infrastructure ..
+		 */
+		vhdl = device_sysdata->vhdl;
+		for (idx = 0; idx < PCI_ROM_RESOURCE; idx++) {
+			size = 0;
+			size = device_dev->resource[idx].end -
+				device_dev->resource[idx].start;
+			if (size) {
+				device_dev->resource[idx].start = (unsigned long)pciio_pio_addr(vhdl, 0, PCIIO_SPACE_WIN(idx), 0, size, 0, (IS_PIC_DEVICE(device_dev)) ? 0 : PCIIO_BYTE_STREAM);
+				device_dev->resource[idx].start |= __IA64_UNCACHED_OFFSET;
+			}
+			else
+				continue;
+
+			device_dev->resource[idx].end = 
+				device_dev->resource[idx].start + size;
+#ifdef BRINGUP2
+			printk("Device Vendor 0x%x, resource[%d] PIO Address = 0x%lx\n", device_dev->vendor, idx, (long)device_dev->resource[idx].start);
+#endif
+
+			if (device_dev->resource[idx].flags & IORESOURCE_IO)
+				cmd |= PCI_COMMAND_IO;
+
+			if (device_dev->resource[idx].flags & IORESOURCE_MEM)
+				cmd |= PCI_COMMAND_MEMORY;
+		}
+		/*
+		 * Now handle the ROM resource ..
+		 */
+#if 0
+	/*
+	 * Software WAR for a Software BUG.
+	 * This is only temporary.
+	 * See PV 872791
+	 */
+		size = device_dev->resource[PCI_ROM_RESOURCE].end -
+			device_dev->resource[PCI_ROM_RESOURCE].start;
+
+		if (size) {
+			device_dev->resource[PCI_ROM_RESOURCE].start =
+			(unsigned long) pciio_pio_addr(vhdl, 0, PCIIO_SPACE_ROM, 0, 
+				size, 0, (IS_PIC_DEVICE(device_dev)) ? 0 : PCIIO_BYTE_STREAM);
+			device_dev->resource[PCI_ROM_RESOURCE].start |= __IA64_UNCACHED_OFFSET;
+			device_dev->resource[PCI_ROM_RESOURCE].end =
+			device_dev->resource[PCI_ROM_RESOURCE].start + size;
+		}
+#endif
+
+		/*
+		 * Update the Command Word on the Card.
+		 */
+		cmd |= PCI_COMMAND_MASTER; /* If the device doesn't support */
+					   /* bit gets dropped .. no harm */
+		pci_write_config_word(device_dev, PCI_COMMAND, cmd);
+
+		pci_read_config_byte(device_dev, PCI_INTERRUPT_PIN, (unsigned char *)&lines);
+		if (device_dev->vendor == PCI_VENDOR_ID_SGI &&
+			device_dev->device == PCI_DEVICE_ID_SGI_IOC3 ) {
+				lines = 1;
+		}
+ 
+		device_sysdata = (struct sn_device_sysdata *)device_dev->sysdata;
+		device_vertex = device_sysdata->vhdl;
+ 
+		intr_handle = pciio_intr_alloc(device_vertex, NULL, lines, device_vertex);
+
+		bit = intr_handle->pi_irq;
+		cpuid = intr_handle->pi_cpu;
+		irq = bit;
+		irq = irq + (cpuid << 8);
+		pciio_intr_connect(intr_handle, (intr_func_t)0, (intr_arg_t)0);
+		device_dev->irq = irq;
+#ifdef ajmtestintr
+		{
+			int slot = PCI_SLOT(device_dev->devfn);
+			static int timer_set = 0;
+			pcibr_intr_t	pcibr_intr = (pcibr_intr_t)intr_handle;
+			pcibr_soft_t	pcibr_soft = pcibr_intr->bi_soft;
+			extern void intr_test_handle_intr(int, void*, struct pt_regs *);
+
+			if (!timer_set) {
+				intr_test_set_timer();
+				timer_set = 1;
+			}
+			intr_test_register_irq(irq, pcibr_soft, slot);
+			request_irq(irq, intr_test_handle_intr,0,NULL, NULL);
+		}
+#endif
+
+	}
+
+	for (cnode = 0; cnode < numnodes; cnode++) {
+		if ( !Is_pic_on_this_nasid[cnodeid_to_nasid(cnode)] )
+			io_sh_swapper((cnodeid_to_nasid(cnode)), 1);
+	}
+}
+
+/*
+ * linux_bus_cvlink() Creates a link between the Linux PCI Bus number 
+ *	to the actual hardware component that it represents:
+ *	/dev/hw/linux/busnum/0 -> ../../../hw/module/001c01/slab/0/Ibrick/xtalk/15/pci
+ */
+void
+linux_bus_cvlink(void)
+{
+	char name[8];
+	int index;
+	
+	for (index=0; index < MAX_PCI_XWIDGET; index++) {
+		if (!busnum_to_pcibr_vhdl[index])
+			continue;
+
+		sprintf(name, "%d", index);
+		(void) hwgraph_edge_add(linux_busnum, busnum_to_pcibr_vhdl[index], 
+				name);
+	}
+}
+
+/*
+ * pci_bus_map_create() - Called by pci_bus_to_hcl_cvlink() to finish the job.
+ *
+ *	Linux PCI Bus numbers are assigned from lowest module_id numbers
+ *	(rack/slot etc.) starting from HUB_WIDGET_ID_MAX down to 
+ *	HUB_WIDGET_ID_MIN:
+ *		widgetnum 15 gets lower Bus Number than widgetnum 14 etc.
+ *
+ *	Given 2 modules 001c01 and 001c02 we get the following mappings:
+ *		001c01, widgetnum 15 = Bus number 0
+ *		001c01, widgetnum 14 = Bus number 1
+ *		001c02, widgetnum 15 = Bus number 3
+ *		001c02, widgetnum 14 = Bus number 4
+ *		etc.
+ *
+ * The rational for starting Bus Number 0 with Widget number 15 is because 
+ * the system boot disks are always connected via Widget 15 Slot 0 of the 
+ * I-brick.  Linux creates /dev/sd* devices(naming) strating from Bus Number 0 
+ * Therefore, /dev/sda1 will be the first disk, on Widget 15 of the lowest 
+ * module id(Master Cnode) of the system.
+ *	
+ */
+static int 
+pci_bus_map_create(devfs_handle_t xtalk)
+{
+
+	devfs_handle_t master_node_vertex = NULL;
+	devfs_handle_t xwidget = NULL;
+	devfs_handle_t pci_bus = NULL;
+	hubinfo_t hubinfo = NULL;
+	xwidgetnum_t widgetnum;
+	char pathname[128];
+	graph_error_t rv;
+	int bus;
+
+	/*
+	 * Loop throught this vertex and get the Xwidgets ..
+	 */
+
+
+	/* PCI devices */
+
+	for (widgetnum = HUB_WIDGET_ID_MAX; widgetnum >= HUB_WIDGET_ID_MIN; widgetnum--) {
+
+#if  0
+        {
+                int pos;
+                char dname[256];
+                pos = devfs_generate_path(xtalk, dname, 256);
+                printk("%s : path= %s\n", __FUNCTION__, &dname[pos]);
+        }
+#endif
+
+		sprintf(pathname, "%d", widgetnum);
+		xwidget = NULL;
+		
+		/*
+		 * Example - /hw/module/001c16/Pbrick/xtalk/8 is the xwidget
+		 *	     /hw/module/001c16/Pbrick/xtalk/8/pci/1 is device
+		 */
+		rv = hwgraph_traverse(xtalk, pathname, &xwidget);
+		if ( (rv != GRAPH_SUCCESS) ) {
+			if (!xwidget) {
+				continue;
+}
+		}
+
+		sprintf(pathname, "%d/"EDGE_LBL_PCI, widgetnum);
+		pci_bus = NULL;
+		if (hwgraph_traverse(xtalk, pathname, &pci_bus) != GRAPH_SUCCESS)
+			if (!pci_bus) {
+				continue;
+}
+
+		/*
+		 * Assign the correct bus number and also the nasid of this 
+		 * pci Xwidget.
+		 * 
+		 * Should not be any race here ...
+		 */
+		num_bridges++;
+		busnum_to_pcibr_vhdl[num_bridges - 1] = pci_bus;
+
+		/*
+		 * Get the master node and from there get the NASID.
+		 */
+		master_node_vertex = device_master_get(xwidget);
+		if (!master_node_vertex) {
+			printk("WARNING: pci_bus_map_create: Unable to get .master for vertex 0x%p\n", (void *)xwidget);
+		}
+	
+		hubinfo_get(master_node_vertex, &hubinfo);
+		if (!hubinfo) {
+			printk("WARNING: pci_bus_map_create: Unable to get hubinfo for master node vertex 0x%p\n", (void *)master_node_vertex);
+			return(1);
+		} else {
+			busnum_to_nid[num_bridges - 1] = hubinfo->h_nasid;
+		}
+
+		/*
+		 * Pre assign DMA maps needed for 32 Bits Page Map DMA.
+		 */
+		busnum_to_atedmamaps[num_bridges - 1] = (void *) kmalloc(
+			sizeof(struct sn_dma_maps_s) * MAX_ATE_MAPS, GFP_KERNEL);
+		if (!busnum_to_atedmamaps[num_bridges - 1])
+			printk("WARNING: pci_bus_map_create: Unable to precreate ATE DMA Maps for busnum %d vertex 0x%p\n", num_bridges - 1, (void *)xwidget);
+
+		memset(busnum_to_atedmamaps[num_bridges - 1], 0x0, 
+			sizeof(struct sn_dma_maps_s) * MAX_ATE_MAPS);
+
+	}
+
+	/*
+	 * PCIX devices
+	 * We number busses differently for PCI-X devices.
+	 * We start from Lowest Widget on up ..
+	 */
+
+	for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) {
+
+		/* Do both buses */
+		for ( bus = 0; bus < 2; bus++ ) {
+			sprintf(pathname, "%d", widgetnum);
+			xwidget = NULL;
+			
+			/*
+			 * Example - /hw/module/001c16/Pbrick/xtalk/8 is the xwidget
+			 *	     /hw/module/001c16/Pbrick/xtalk/8/pci-x/0 is the bus
+			 *	     /hw/module/001c16/Pbrick/xtalk/8/pci-x/0/1 is device
+			 */
+			rv = hwgraph_traverse(xtalk, pathname, &xwidget);
+			if ( (rv != GRAPH_SUCCESS) ) {
+				if (!xwidget) {
+					continue;
+				}
+			}
+	
+			if ( bus == 0 )
+				sprintf(pathname, "%d/"EDGE_LBL_PCIX_0, widgetnum);
+			else
+				sprintf(pathname, "%d/"EDGE_LBL_PCIX_1, widgetnum);
+			pci_bus = NULL;
+			if (hwgraph_traverse(xtalk, pathname, &pci_bus) != GRAPH_SUCCESS)
+				if (!pci_bus) {
+					continue;
+				}
+	
+			/*
+			 * Assign the correct bus number and also the nasid of this 
+			 * pci Xwidget.
+			 * 
+			 * Should not be any race here ...
+			 */
+			num_bridges++;
+			busnum_to_pcibr_vhdl[num_bridges - 1] = pci_bus;
+	
+			/*
+			 * Get the master node and from there get the NASID.
+			 */
+			master_node_vertex = device_master_get(xwidget);
+			if (!master_node_vertex) {
+				printk("WARNING: pci_bus_map_create: Unable to get .master for vertex 0x%p\n", (void *)xwidget);
+			}
+		
+			hubinfo_get(master_node_vertex, &hubinfo);
+			if (!hubinfo) {
+				printk("WARNING: pci_bus_map_create: Unable to get hubinfo for master node vertex 0x%p\n", (void *)master_node_vertex);
+				return(1);
+			} else {
+				busnum_to_nid[num_bridges - 1] = hubinfo->h_nasid;
+			}
+	
+			/*
+			 * Pre assign DMA maps needed for 32 Bits Page Map DMA.
+			 */
+			busnum_to_atedmamaps[num_bridges - 1] = (void *) kmalloc(
+				sizeof(struct sn_dma_maps_s) * MAX_ATE_MAPS, GFP_KERNEL);
+			if (!busnum_to_atedmamaps[num_bridges - 1])
+				printk("WARNING: pci_bus_map_create: Unable to precreate ATE DMA Maps for busnum %d vertex 0x%p\n", num_bridges - 1, (void *)xwidget);
+	
+			memset(busnum_to_atedmamaps[num_bridges - 1], 0x0, 
+				sizeof(struct sn_dma_maps_s) * MAX_ATE_MAPS);
+		}
+	}
+
+        return(0);
+}
+
+/*
+ * pci_bus_to_hcl_cvlink() - This routine is called after SGI IO Infrastructure   
+ *      initialization has completed to set up the mappings between Xbridge
+ *      and logical pci bus numbers.  We also set up the NASID for each of these
+ *      xbridges.
+ *
+ *      Must be called before pci_init() is invoked.
+ */
+int
+pci_bus_to_hcl_cvlink(void) 
+{
+
+	devfs_handle_t devfs_hdl = NULL;
+	devfs_handle_t xtalk = NULL;
+	int rv = 0;
+	char name[256];
+	char tmp_name[256];
+	int master_iobrick;
+	slabid_t master_slab;
+	int i, ii;
+	extern nasid_t master_baseio_nasid;
+	extern nasid_t get_master_baseio_nasid(void);
+
+	/*
+	 * Iterate throught each xtalk links in the system ..
+	 * /hw/module/001c01/slab/0/node/xtalk/ 8|9|10|11|12|13|14|15 
+	 *
+	 * /hw/module/001c01/slab/0/node/xtalk/15 -> /hw/module/001c01/slab/0/Ibrick/xtalk/15
+	 *
+	 * What if it is not pci?
+	 */
+	devfs_hdl = hwgraph_path_to_vertex("/dev/hw/module");
+
+	/*
+	 * To provide consistent(not persistent) device naming, we need to start 
+	 * bus number allocation from the C-Brick with the lowest module id e.g. 001c01 
+	 * with an attached I-Brick.  Find the master_iobrick.
+	 */
+	master_baseio_nasid = get_master_baseio_nasid();
+	master_iobrick = -1;
+	master_slab = -1;
+	if ( master_baseio_nasid >= 0 ) {
+		/* Valid nasid, need the slab ID */
+		for (i = 0; i < nummodules; i++) {
+			extern int iobrick_module_get_nasid(nasid_t);
+			moduleid_t iobrick_id; 
+			nasid_t nasid = -1;
+			int n = 0;
+			for ( n = 0; n < modules[i]->nodecnt; n++ ) {
+				nasid = cnodeid_to_nasid(modules[i]->nodes[n]);
+				iobrick_id = iobrick_module_get_nasid(nasid);
+				if (iobrick_id > 0) { /* Valid module id */
+					if ( master_baseio_nasid == nasid ) {
+						master_iobrick = i;
+						master_slab = geo_slab(modules[i]->geoid[n]);
+						printk("pci_bus_to_hcl_cvlink: Found Master Base IO Brick type %d Master Base I/O nasid %d Master Cbrick Index %d Slab %d\n", MODULE_GET_BTYPE(iobrick_id), master_baseio_nasid, master_iobrick, master_slab);
+						break;
+					}
+				}
+			}
+			if (master_slab >= 0)
+				break;
+		}
+	}
+	else {
+		/* Not sure which nasid it is - call failed, so make a guess */
+		for (i = 0; i < nummodules; i++) {
+			extern int iobrick_module_get_nasid(nasid_t);
+			moduleid_t iobrick_id; 
+			nasid_t nasid = -1;
+			int n = 0;
+			for ( n = 0; n < modules[i]->nodecnt; n++ ) {
+				nasid = cnodeid_to_nasid(modules[i]->nodes[n]);
+				iobrick_id = iobrick_module_get_nasid(nasid);
+				if (iobrick_id > 0) { /* Valid module id */
+					if ( (MODULE_GET_BTYPE(iobrick_id) == MODULE_IBRICK) || 
+					   		(MODULE_GET_BTYPE(iobrick_id) == MODULE_PXBRICK) ||
+				   			(MODULE_GET_BTYPE(iobrick_id) == MODULE_PBRICK) ) {
+						master_iobrick = i;
+						master_baseio_nasid = nasid;
+						master_slab = geo_slab(modules[i]->geoid[n]);
+						printk("pci_bus_to_hcl_cvlink: Found Master Base IO Brick type %d Master Cbrick Index %d Slab %d\n", MODULE_GET_BTYPE(iobrick_id), master_iobrick, master_slab);
+						break;
+					}
+				}
+			}
+			if (master_iobrick >= 0)
+				break;
+		}
+	}
+
+	if (master_iobrick == -1) {
+		panic("Unable to find the Master BaseIO PCI/PCIX Bus\n");
+	}
+
+	/*
+	 * The master_iobrick gets bus 0 and 1.
+	 */
+	if (master_iobrick >= 0) {
+		memset(name, 0, 256);
+		memset(tmp_name, 0, 256);
+		format_module_id(name, modules[master_iobrick]->id, MODULE_FORMAT_BRIEF);
+		sprintf(tmp_name, "/slab/%d/node/xtalk", master_slab);
+		strcat(name, tmp_name);
+		xtalk = NULL;
+		rv = hwgraph_edge_get(devfs_hdl, name, &xtalk);
+		pci_bus_map_create(xtalk);
+	}
+		
+	/*
+	 * Now go do the rest of the modules, starting from the C-Brick with the lowest 
+	 * module id, remembering to skip the master_iobrick, which was done above.
+	 */
+	for (i = 0; i < nummodules ; i++) {
+		for ( ii = 0; ii < MAX_SLABS; ii++ ) {
+			if ((i == master_iobrick) && (master_slab == ii))
+				continue; /* Did the master_iobrick/slab already. */
+			memset(name, 0, 256);
+			memset(tmp_name, 0, 256);
+			format_module_id(name, modules[i]->id, MODULE_FORMAT_BRIEF);
+			sprintf(tmp_name, "/slab/%d/node/xtalk", ii);
+			strcat(name, tmp_name);
+			xtalk = NULL;
+			rv = hwgraph_edge_get(devfs_hdl, name, &xtalk);
+			pci_bus_map_create(xtalk);
+		}
+	}
+
+	/*
+	 * Create the Linux PCI bus number vertex link.
+	 */
+	(void)linux_bus_cvlink();
+
+	return(0);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/Makefile linux-2.4.21-pre6/arch/ia64/sn/io/sn2/pcibr/Makefile
--- linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn2/pcibr/Makefile	2003-03-26 23:49:25.000000000 +0000
@@ -0,0 +1,23 @@
+#
+# 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) 2002 Silicon Graphics, Inc.  All Rights Reserved.
+#
+# Makefile for the sn2 io pcibr routines.
+
+EXTRA_CFLAGS    := -DLITTLE_ENDIAN
+
+ifdef CONFIG_IA64_SGI_SN2
+EXTRA_CFLAGS    += -DSHUB_SWAP_WAR
+endif
+
+O_TARGET := pcibr.o
+
+obj-$(CONFIG_IA64_SGI_SN2)	+= pcibr_dvr.o pcibr_ate.o pcibr_config.o \
+                                   pcibr_dvr.o pcibr_hints.o \
+				   pcibr_intr.o pcibr_rrb.o pcibr_slot.o \
+				   pcibr_error.o
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/pcibr_ate.c linux-2.4.21-pre6/arch/ia64/sn/io/sn2/pcibr/pcibr_ate.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/pcibr_ate.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn2/pcibr/pcibr_ate.c	2003-03-26 23:49:20.000000000 +0000
@@ -44,24 +44,6 @@
 #endif
 
 
-#ifdef LATER
-#if (PCIBR_FREEZE_TIME) || PCIBR_ATE_DEBUG
-LOCAL struct reg_desc   ate_bits[] =
-{
-    {0xFFFF000000000000ull, -48, "RMF", "%x"},
-    {~(IOPGSIZE - 1) &			/* may trim off some low bits */
-     0x0000FFFFFFFFF000ull, 0, "XIO", "%x"},
-    {0x0000000000000F00ull, -8, "port", "%x"},
-    {0x0000000000000010ull, 0, "Barrier"},
-    {0x0000000000000008ull, 0, "Prefetch"},
-    {0x0000000000000004ull, 0, "Precise"},
-    {0x0000000000000002ull, 0, "Coherent"},
-    {0x0000000000000001ull, 0, "Valid"},
-    {0}
-};
-#endif
-#endif	/* LATER */
-
 #ifndef LOCAL
 #define LOCAL           static
 #endif
@@ -79,7 +61,7 @@
 	   			unsigned *freeze_time_ptr,
 #endif
 	   			unsigned *cmd_regs);
-void 	  ate_write(bridge_ate_p ate_ptr, int ate_count, bridge_ate_t ate);
+void 	  ate_write(pcibr_soft_t pcibr_soft, bridge_ate_p ate_ptr, int ate_count, bridge_ate_t ate);
 void ate_thaw(pcibr_dmamap_t pcibr_dmamap,
 	 			int ate_index,
 #if PCIBR_FREEZE_TIME
@@ -119,26 +101,73 @@
     int                     i, j;
     bridgereg_t             old_enable, new_enable;
     int                     s;
+    int			    this_is_pic = is_pic(bridge);
 
     /* Probe SSRAM to determine its size. */
-    old_enable = bridge->b_int_enable;
-    new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT;
-    bridge->b_int_enable = new_enable;
+    if ( this_is_pic ) {
+	old_enable = bridge->b_int_enable;
+	new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT;
+	bridge->b_int_enable = new_enable;
+    }
+    else {
+	if (io_get_sh_swapper(NASID_GET(bridge))) {
+		old_enable = BRIDGE_REG_GET32((&bridge->b_int_enable));
+		new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT;
+		BRIDGE_REG_SET32((&bridge->b_int_enable)) = new_enable;
+	}
+	else {
+		old_enable = bridge->b_int_enable;
+		new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT;
+		bridge->b_int_enable = new_enable;
+	}
+    }
 
     for (i = 1; i < ATE_NUM_SIZES; i++) {
 	/* Try writing a value */
-	bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] = ATE_PROBE_VALUE;
+	if ( this_is_pic ) {
+		bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] = ATE_PROBE_VALUE;
+	}
+	else {
+		if (io_get_sh_swapper(NASID_GET(bridge)))
+			bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] = __swab64(ATE_PROBE_VALUE);
+		else
+			bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] = ATE_PROBE_VALUE;
+	}
 
 	/* Guard against wrap */
 	for (j = 1; j < i; j++)
 	    bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(j) - 1] = 0;
 
 	/* See if value was written */
-	if (bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] == ATE_PROBE_VALUE)
-	    largest_working_size = i;
+	if ( this_is_pic ) {
+		if (bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] == ATE_PROBE_VALUE)
+				largest_working_size = i;
+	}
+	else {
+		if (io_get_sh_swapper(NASID_GET(bridge))) {
+			if (bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] == __swab64(ATE_PROBE_VALUE))
+					largest_working_size = i;
+			else {
+				if (bridge->b_ext_ate_ram[ATE_NUM_ENTRIES(i) - 1] == ATE_PROBE_VALUE)
+					largest_working_size = i;
+			}
+		}
+	}
+    }
+    if ( this_is_pic ) {
+	bridge->b_int_enable = old_enable;
+	bridge->b_wid_tflush;		/* wait until Bridge PIO complete */
+    }
+    else {
+	if (io_get_sh_swapper(NASID_GET(bridge))) {
+		BRIDGE_REG_SET32((&bridge->b_int_enable)) = old_enable;
+		BRIDGE_REG_GET32((&bridge->b_wid_tflush));   /* wait until Bridge PIO complete */
+	}
+	else {
+		bridge->b_int_enable = old_enable;
+		bridge->b_wid_tflush;               /* wait until Bridge PIO complete */
+	}
     }
-    bridge->b_int_enable = old_enable;
-    bridge->b_wid_tflush;		/* wait until Bridge PIO complete */
 
     /*
      * ensure that we write and read without any interruption.
@@ -146,20 +175,41 @@
      */
 
     s = splhi();
-    bridge->b_wid_control = (bridge->b_wid_control
-	& ~BRIDGE_CTRL_SSRAM_SIZE_MASK)
-	| BRIDGE_CTRL_SSRAM_SIZE(largest_working_size);
-    bridge->b_wid_control;		/* inval addr bug war */
+    if ( this_is_pic ) {
+	bridge->b_wid_control = (bridge->b_wid_control
+			& ~BRIDGE_CTRL_SSRAM_SIZE_MASK)
+			| BRIDGE_CTRL_SSRAM_SIZE(largest_working_size);
+	bridge->b_wid_control;		/* inval addr bug war */
+    }
+    else {
+	if (io_get_sh_swapper(NASID_GET(bridge))) {
+		BRIDGE_REG_SET32((&(bridge->b_wid_control))) = 
+				__swab32((BRIDGE_REG_GET32((&bridge->b_wid_control))
+					& ~BRIDGE_CTRL_SSRAM_SIZE_MASK)
+					| BRIDGE_CTRL_SSRAM_SIZE(largest_working_size));
+		BRIDGE_REG_GET32((&bridge->b_wid_control));/* inval addr bug war */
+	}
+	else {
+		bridge->b_wid_control = (bridge->b_wid_control & ~BRIDGE_CTRL_SSRAM_SIZE_MASK)
+				| BRIDGE_CTRL_SSRAM_SIZE(largest_working_size);
+		bridge->b_wid_control;              /* inval addr bug war */
+	}
+    }
     splx(s);
 
     num_entries = ATE_NUM_ENTRIES(largest_working_size);
 
-#if PCIBR_ATE_DEBUG
-    if (num_entries)
-	printk("bridge at 0x%x: clearing %d external ATEs\n", bridge, num_entries);
-    else
-	printk("bridge at 0x%x: no external ATE RAM found\n", bridge);
-#endif
+    if (pcibr_debug_mask & PCIBR_DEBUG_ATE) {
+	if (num_entries) {
+	    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATE, NULL,
+			"bridge at 0x%x: clearing %d external ATEs\n",
+			bridge, num_entries));
+	} else {
+	    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATE, NULL,
+			"bridge at 0x%x: no external ATE RAM found\n",
+			bridge));
+	}
+    }
 
     /* Initialize external mapping entries */
     for (entry = 0; entry < num_entries; entry++)
@@ -339,7 +389,8 @@
 #endif
 
     cmd_lwa = 0;
-    for (slot = 0; slot < 8; ++slot)
+    for (slot = pcibr_soft->bs_min_slot; 
+		slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot)
 	if (atomic_read(&pcibr_soft->bs_slot[slot].bss_ext_ates_active)) {
 	    cmd_reg = pcibr_soft->
 		bs_slot[slot].
@@ -366,28 +417,54 @@
 	    cmd_lwa[0];
 
 	    /* Flush all the write buffers in the bridge */
-	    for (slot = 0; slot < 8; ++slot)
+	    for (slot = pcibr_soft->bs_min_slot; 
+				slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) {
 		    if (atomic_read(&pcibr_soft->bs_slot[slot].bss_ext_ates_active)) {
 			    /* Flush the write buffer associated with this
 			     * PCI device which might be using dma map RAM.
 			     */
-			    bridge->b_wr_req_buf[slot].reg;
+			if ( is_pic(bridge) ) {
+				bridge->b_wr_req_buf[slot].reg;
+			}
+			else {
+				if (io_get_sh_swapper(NASID_GET(bridge)) ) {
+					BRIDGE_REG_GET32((&bridge->b_wr_req_buf[slot].reg));
+				}
+				else
+					bridge->b_wr_req_buf[slot].reg;
+			}
 		    }
+	    }
     }
     return s;
 }
 
-#define	ATE_WRITE()    ate_write(ate_ptr, ate_count, ate)
-
 void
-ate_write(bridge_ate_p ate_ptr,
+ate_write(pcibr_soft_t pcibr_soft,
+	  bridge_ate_p ate_ptr,
 	  int ate_count,
 	  bridge_ate_t ate)
 {
-    while (ate_count-- > 0) {
-	*ate_ptr++ = ate;
-	ate += IOPGSIZE;
-    }
+	if (IS_PIC_SOFT(pcibr_soft) ) {
+    		while (ate_count-- > 0) {
+			*ate_ptr++ = ate;
+			ate += IOPGSIZE;
+		}
+	}
+	else {
+		if (io_get_sh_swapper(NASID_GET(ate_ptr))) {
+    			while (ate_count-- > 0) {
+				*ate_ptr++ = __swab64(ate);
+				ate += IOPGSIZE;
+			}
+		}
+		else {
+    			while (ate_count-- > 0) {
+				*ate_ptr++ = ate;
+				ate += IOPGSIZE;
+			}
+		}
+	}
 }
 
 #if PCIBR_FREEZE_TIME
@@ -425,10 +502,24 @@
 	return;
 
     /* restore cmd regs */
-    for (slot = 0; slot < 8; ++slot)
-	if ((cmd_reg = cmd_regs[slot]) & PCI_CMD_BUS_MASTER)
-	    bridge->b_type0_cfg_dev[slot].l[PCI_CFG_COMMAND / 4] = cmd_reg;
-
+    for (slot = pcibr_soft->bs_min_slot; 
+		slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) {
+	if ((cmd_reg = cmd_regs[slot]) & PCI_CMD_BUS_MASTER) {
+		if ( IS_PIC_SOFT(pcibr_soft) ) {
+			pcibr_slot_config_set(bridge, slot, PCI_CFG_COMMAND/4, cmd_reg);
+		}
+		else {
+			if (io_get_sh_swapper(NASID_GET(bridge))) {
+				bridge->b_type0_cfg_dev[slot].l[PCI_CFG_COMMAND / 4] = __swab32(cmd_reg);
+			}
+			else {
+//				BUG(); /* Does this really work if called when io_get_sh_swapper = 0? */
+//				bridge->b_type0_cfg_dev[slot].l[PCI_CFG_COMMAND / 4] = cmd_reg;
+				pcibr_slot_config_set(bridge, slot, PCI_CFG_COMMAND/4, cmd_reg);
+			}
+		}
+	}
+    }
     pcibr_dmamap->bd_flags |= PCIBR_DMAMAP_BUSY;
     atomic_inc(&(pcibr_soft->bs_slot[dma_slot]. bss_ext_ates_active));
 
@@ -442,7 +533,7 @@
 	if (max_ate_total < ate_total)
 	    max_ate_total = ate_total;
 	pcibr_unlock(pcibr_soft, s);
-	printk("%s: pci freeze time %d usec for %d ATEs\n"
+	printk( "%s: pci freeze time %d usec for %d ATEs\n"
 		"\tfirst ate: %R\n",
 		pcibr_soft->bs_name,
 		freeze_time * 1000 / 1250,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c linux-2.4.21-pre6/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c	2003-03-26 23:48:57.000000000 +0000
@@ -10,6 +10,7 @@
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/byteorder/swab.h>
 #include <asm/sn/sgi.h>
 #include <asm/sn/sn_cpuid.h>
 #include <asm/sn/addrs.h>
@@ -34,14 +35,14 @@
 extern pcibr_info_t      pcibr_info_get(devfs_handle_t);
 
 uint64_t          pcibr_config_get(devfs_handle_t, unsigned, unsigned);
-uint64_t          do_pcibr_config_get(cfg_p, unsigned, unsigned);
+uint64_t          do_pcibr_config_get(int, cfg_p, unsigned, unsigned);
 void              pcibr_config_set(devfs_handle_t, unsigned, unsigned, uint64_t);
-void              do_pcibr_config_set(cfg_p, unsigned, unsigned, uint64_t);
+void       	  do_pcibr_config_set(int, cfg_p, unsigned, unsigned, uint64_t);
+static void	  swap_do_pcibr_config_set(cfg_p, unsigned, unsigned, uint64_t);
 
 #ifdef LITTLE_ENDIAN
-#ifdef CONFIG_IA64_SGI_SN1
 /*
- * on sn-ia we need to twiddle the the addresses going out
+ * on sn-ia we need to twiddle the addresses going out
  * the pci bus because we use the unswizzled synergy space
  * (the alternative is to use the swizzled synergy space
  * and byte swap the data)
@@ -49,73 +50,218 @@
 #define CB(b,r) (((volatile uint8_t *) b)[((r)^4)])
 #define CS(b,r) (((volatile uint16_t *) b)[((r^4)/2)])
 #define CW(b,r) (((volatile uint32_t *) b)[((r^4)/4)])
-#else
-#ifdef CONFIG_IA64_SGI_SN2
-/*
- * On sn-ia sn2 everything is little endian.  No swizzling 
- * or byte swapping of addresses required.
- */
-#define CB(b,r) (((volatile uint8_t *) b)[(r)])
-#define CS(b,r) (((volatile uint16_t *) b)[(r)/2])
-#define CW(b,r) (((volatile uint32_t *) b)[(r)/4])
-#endif
-#endif
+
+#define	CBP(b,r) (((volatile uint8_t *) b)[(r)^3])
+#define	CSP(b,r) (((volatile uint16_t *) b)[((r)/2)^1])
+#define	CWP(b,r) (((volatile uint32_t *) b)[(r)/4])
+
+#define SCB(b,r) (((volatile uint8_t *) b)[((r)^3)])
+#define SCS(b,r) (((volatile uint16_t *) b)[((r^2)/2)])
+#define SCW(b,r) (((volatile uint32_t *) b)[((r)/4)])
 #else
 #define	CB(b,r)	(((volatile uint8_t *) cfgbase)[(r)^3])
 #define	CS(b,r)	(((volatile uint16_t *) cfgbase)[((r)/2)^1])
 #define	CW(b,r)	(((volatile uint32_t *) cfgbase)[(r)/4])
 #endif
 
+/*
+ * Return a config space address for given slot / func / offset.  Note the
+ * returned pointer is a 32bit word (ie. cfg_p) aligned pointer pointing to
+ * the 32bit word that contains the "offset" byte.
+ */
+cfg_p
+pcibr_func_config_addr(bridge_t *bridge, pciio_bus_t bus, pciio_slot_t slot, 
+					pciio_function_t func, int offset)
+{
+	/*
+	 * Type 1 config space
+	 */
+	if (bus > 0) {
+		bridge->b_pci_cfg = ((bus << 16) | (slot << 11));
+		return &bridge->b_type1_cfg.f[func].l[(offset)];
+	}
+
+	/*
+	 * Type 0 config space
+	 */
+	if (is_pic(bridge))
+		slot++;
+	return &bridge->b_type0_cfg_dev[slot].f[func].l[offset];
+}
+
+/*
+ * Return config space address for given slot / offset.  Note the returned
+ * pointer is a 32bit word (ie. cfg_p) aligned pointer pointing to the
+ * 32bit word that contains the "offset" byte.
+ */
+cfg_p
+pcibr_slot_config_addr(bridge_t *bridge, pciio_slot_t slot, int offset)
+{
+	return pcibr_func_config_addr(bridge, 0, slot, 0, offset);
+}
+
+/*
+ * Return config space data for given slot / offset
+ */
+unsigned
+pcibr_slot_config_get(bridge_t *bridge, pciio_slot_t slot, int offset)
+{
+	cfg_p  cfg_base;
+	
+	cfg_base = pcibr_slot_config_addr(bridge, slot, 0);
+	return (do_pcibr_config_get(is_pic(bridge), cfg_base, offset, sizeof(unsigned)));
+}
+
+/*
+ * Return config space data for given slot / func / offset
+ */
+unsigned
+pcibr_func_config_get(bridge_t *bridge, pciio_slot_t slot, 
+					pciio_function_t func, int offset)
+{
+	cfg_p  cfg_base;
+
+	cfg_base = pcibr_func_config_addr(bridge, 0, slot, func, 0);
+	return (do_pcibr_config_get(is_pic(bridge), cfg_base, offset, sizeof(unsigned)));
+}
+
+/*
+ * Set config space data for given slot / offset
+ */
+void
+pcibr_slot_config_set(bridge_t *bridge, pciio_slot_t slot, 
+					int offset, unsigned val)
+{
+	cfg_p  cfg_base;
+
+	cfg_base = pcibr_slot_config_addr(bridge, slot, 0);
+	do_pcibr_config_set(is_pic(bridge), cfg_base, offset, sizeof(unsigned), val);
+}
+
+/*
+ * Set config space data for given slot / func / offset
+ */
+void
+pcibr_func_config_set(bridge_t *bridge, pciio_slot_t slot, 
+			pciio_function_t func, int offset, unsigned val)
+{
+	cfg_p  cfg_base;
+
+	cfg_base = pcibr_func_config_addr(bridge, 0, slot, func, 0);
+	do_pcibr_config_set(is_pic(bridge), cfg_base, offset, sizeof(unsigned), val);
+}
+
+int pcibr_config_debug = 0;
 
 cfg_p
 pcibr_config_addr(devfs_handle_t conn,
 		  unsigned reg)
 {
     pcibr_info_t            pcibr_info;
+    pciio_bus_t		    pciio_bus;
     pciio_slot_t            pciio_slot;
     pciio_function_t        pciio_func;
     pcibr_soft_t            pcibr_soft;
     bridge_t               *bridge;
     cfg_p                   cfgbase = (cfg_p)0;
+    pciio_info_t	    pciio_info;
 
+    pciio_info = pciio_info_get(conn);
     pcibr_info = pcibr_info_get(conn);
 
-    pciio_slot = pcibr_info->f_slot;
+    /*
+     * Determine the PCI bus/slot/func to generate a config address for.
+     */
+
+    if (pciio_info_type1_get(pciio_info)) {
+	/*
+	 * Conn is a vhdl which uses TYPE 1 addressing explicitly passed 
+	 * in reg.
+	 */
+	pciio_bus = PCI_TYPE1_BUS(reg);
+	pciio_slot = PCI_TYPE1_SLOT(reg);
+	pciio_func = PCI_TYPE1_FUNC(reg);
+
+	ASSERT(pciio_bus != 0);
+#if 0
+    } else if (conn != pciio_info_hostdev_get(pciio_info)) {
+	/*
+	 * Conn is on a subordinate bus, so get bus/slot/func directly from
+	 * its pciio_info_t structure.
+	 */
+	pciio_bus = pciio_info->c_bus;
+	pciio_slot = pciio_info->c_slot;
+	pciio_func = pciio_info->c_func;
+	if (pciio_func == PCIIO_FUNC_NONE) {
+		pciio_func = 0;
+	}
+#endif
+    } else {
+	/*
+	 * Conn is directly connected to the host bus.  PCI bus number is
+	 * hardcoded to 0 (even though it may have a logical bus number != 0)
+	 * and slot/function are derived from the pcibr_info_t associated
+	 * with the device.
+	 */
+	pciio_bus = 0;
+
+    pciio_slot = PCIBR_INFO_SLOT_GET_INT(pcibr_info);
     if (pciio_slot == PCIIO_SLOT_NONE)
 	pciio_slot = PCI_TYPE1_SLOT(reg);
 
     pciio_func = pcibr_info->f_func;
     if (pciio_func == PCIIO_FUNC_NONE)
 	pciio_func = PCI_TYPE1_FUNC(reg);
+    }
 
     pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast;
 
     bridge = pcibr_soft->bs_base;
 
-    cfgbase = bridge->b_type0_cfg_dev[pciio_slot].f[pciio_func].l;
+    cfgbase = pcibr_func_config_addr(bridge,
+			pciio_bus, pciio_slot, pciio_func, 0);
 
     return cfgbase;
 }
 
+extern unsigned char Is_pic_on_this_nasid[];
 uint64_t
 pcibr_config_get(devfs_handle_t conn,
 		 unsigned reg,
 		 unsigned size)
 {
-    return do_pcibr_config_get(pcibr_config_addr(conn, reg),
-			       PCI_TYPE1_REG(reg), size);
+    if ( !Is_pic_on_this_nasid[ NASID_GET((pcibr_config_addr(conn, reg)))] )
+    	return do_pcibr_config_get(0, pcibr_config_addr(conn, reg),
+				PCI_TYPE1_REG(reg), size);
+    else
+    	return do_pcibr_config_get(1, pcibr_config_addr(conn, reg),
+				PCI_TYPE1_REG(reg), size);
 }
 
 uint64_t
 do_pcibr_config_get(
+		       int pic,
 		       cfg_p cfgbase,
 		       unsigned reg,
 		       unsigned size)
 {
     unsigned                value;
 
-    value = CW(cfgbase, reg);
-
+    if ( pic ) {
+	value = CWP(cfgbase, reg);
+    }
+    else {
+	if ( io_get_sh_swapper(NASID_GET(cfgbase)) ) {
+	    /*
+	     * Shub Swapper on - 0 returns PCI Offset 0 but byte swapped!
+	     * Do not swizzle address and byte swap the result.
+	     */
+	    value = SCW(cfgbase, reg);
+	    value = __swab32(value);
+	} else {
+    	    value = CW(cfgbase, reg);
+	}
+    }
     if (reg & 3)
 	value >>= 8 * (reg & 3);
     if (size < 4)
@@ -129,39 +275,103 @@
 		 unsigned size,
 		 uint64_t value)
 {
-    do_pcibr_config_set(pcibr_config_addr(conn, reg),
+    if ( Is_pic_on_this_nasid[ NASID_GET((pcibr_config_addr(conn, reg)))] )
+    	do_pcibr_config_set(1, pcibr_config_addr(conn, reg),
+			PCI_TYPE1_REG(reg), size, value);
+    else
+	swap_do_pcibr_config_set(pcibr_config_addr(conn, reg),
 			PCI_TYPE1_REG(reg), size, value);
 }
 
 void
-do_pcibr_config_set(cfg_p cfgbase,
+do_pcibr_config_set(int pic,
+		    cfg_p cfgbase,
 		    unsigned reg,
 		    unsigned size,
 		    uint64_t value)
 {
+	if ( pic ) {
+		switch (size) {
+		case 1:
+			CBP(cfgbase, reg) = value;
+			break;
+		case 2:
+			if (reg & 1) {
+				CBP(cfgbase, reg) = value;
+				CBP(cfgbase, reg + 1) = value >> 8;
+			} else
+				CSP(cfgbase, reg) = value;
+			break;
+		case 3:
+			if (reg & 1) {
+				CBP(cfgbase, reg) = value;
+				CSP(cfgbase, (reg + 1)) = value >> 8;
+			} else {
+				CSP(cfgbase, reg) = value;
+				CBP(cfgbase, reg + 2) = value >> 16;
+			}
+			break;
+		case 4:
+			CWP(cfgbase, reg) = value;
+			break;
+   		}
+	}
+	else {
+		switch (size) {
+		case 1:
+			CB(cfgbase, reg) = value;
+			break;
+		case 2:
+			if (reg & 1) {
+				CB(cfgbase, reg) = value;
+				CB(cfgbase, reg + 1) = value >> 8;
+			} else
+				CS(cfgbase, reg) = value;
+			break;
+		case 3:
+			if (reg & 1) {
+				CB(cfgbase, reg) = value;
+				CS(cfgbase, (reg + 1)) = value >> 8;
+			} else {
+				CS(cfgbase, reg) = value;
+				CB(cfgbase, reg + 2) = value >> 16;
+			}
+			break;
+		case 4:
+			CW(cfgbase, reg) = value;
+			break;
+   		}
+	}
+}
+
+void
+swap_do_pcibr_config_set(cfg_p cfgbase,
+                    unsigned reg,
+                    unsigned size,
+                    uint64_t value)
+{
+
+    uint64_t temp_value = 0;
+
     switch (size) {
     case 1:
-	CB(cfgbase, reg) = value;
-	break;
+        SCB(cfgbase, reg) = value;
+        break;
     case 2:
-	if (reg & 1) {
-	    CB(cfgbase, reg) = value;
-	    CB(cfgbase, reg + 1) = value >> 8;
-	} else
-	    CS(cfgbase, reg) = value;
-	break;
+	temp_value = __swab16(value);
+        if (reg & 1) {
+            SCB(cfgbase, reg) = temp_value;
+            SCB(cfgbase, reg + 1) = temp_value >> 8;
+        } else
+            SCS(cfgbase, reg) = temp_value;
+        break;
     case 3:
-	if (reg & 1) {
-	    CB(cfgbase, reg) = value;
-	    CS(cfgbase, (reg + 1)) = value >> 8;
-	} else {
-	    CS(cfgbase, reg) = value;
-	    CB(cfgbase, reg + 2) = value >> 16;
-	}
-	break;
+	BUG();
+        break;
 
     case 4:
-	CW(cfgbase, reg) = value;
-	break;
+	temp_value = __swab32(value);
+        SCW(cfgbase, reg) = temp_value;
+        break;
     }
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c linux-2.4.21-pre6/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c	2003-03-26 23:49:30.000000000 +0000
@@ -7,7 +7,6 @@
  * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved.
  */
 
-
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/module.h>
@@ -40,6 +39,25 @@
 #endif
 
 /*
+ * global variables to toggle the different levels of pcibr debugging.  
+ *   -pcibr_debug_mask is the mask of the different types of debugging
+ *    you want to enable.  See sys/PCI/pcibr_private.h 
+ *   -pcibr_debug_module is the module you want to trace.  By default
+ *    all modules are trace.  For IP35 this value has the format of
+ *    something like "001c10".  For IP27 this value is a node number,
+ *    i.e. "1", "2"...  For IP30 this is undefined and should be set to
+ *    'all'.
+ *   -pcibr_debug_widget is the widget you want to trace.  For IP27
+ *    the widget isn't exposed in the hwpath so use the xio slot num.
+ *    i.e. for 'io2' set pcibr_debug_widget to "2".
+ *   -pcibr_debug_slot is the pci slot you want to trace.
+ */
+uint32_t pcibr_debug_mask = 0x0;	/* 0x00000000 to disable */
+char      *pcibr_debug_module = "all";		/* 'all' for all modules */
+int	   pcibr_debug_widget = -1;		/* '-1' for all widgets  */
+int	   pcibr_debug_slot = -1;		/* '-1' for all slots    */
+
+/*
  * Macros related to the Lucent USS 302/312 usb timeout workaround.  It
  * appears that if the lucent part can get into a retry loop if it sees a
  * DAC on the bus during a pio read retry.  The loop is broken after about
@@ -82,44 +100,6 @@
 	writev: NULL
 };
 
-#ifdef LATER
-
-#if PCIBR_ATE_DEBUG
-static struct reg_values ssram_sizes[] =
-{
-    {BRIDGE_CTRL_SSRAM_512K, "512k"},
-    {BRIDGE_CTRL_SSRAM_128K, "128k"},
-    {BRIDGE_CTRL_SSRAM_64K, "64k"},
-    {BRIDGE_CTRL_SSRAM_1K, "1k"},
-    {0}
-};
-
-static struct reg_desc   control_bits[] =
-{
-    {BRIDGE_CTRL_FLASH_WR_EN, 0, "FLASH_WR_EN"},
-    {BRIDGE_CTRL_EN_CLK50, 0, "EN_CLK50"},
-    {BRIDGE_CTRL_EN_CLK40, 0, "EN_CLK40"},
-    {BRIDGE_CTRL_EN_CLK33, 0, "EN_CLK33"},
-    {BRIDGE_CTRL_RST_MASK, -24, "RST", "%x"},
-    {BRIDGE_CTRL_IO_SWAP, 0, "IO_SWAP"},
-    {BRIDGE_CTRL_MEM_SWAP, 0, "MEM_SWAP"},
-    {BRIDGE_CTRL_PAGE_SIZE, 0, "PAGE_SIZE"},
-    {BRIDGE_CTRL_SS_PAR_BAD, 0, "SS_PAR_BAD"},
-    {BRIDGE_CTRL_SS_PAR_EN, 0, "SS_PAR_EN"},
-    {BRIDGE_CTRL_SSRAM_SIZE_MASK, 0, "SSRAM_SIZE", 0, ssram_sizes},
-    {BRIDGE_CTRL_F_BAD_PKT, 0, "F_BAD_PKT"},
-    {BRIDGE_CTRL_LLP_XBAR_CRD_MASK, -12, "LLP_XBAR_CRD", "%d"},
-    {BRIDGE_CTRL_CLR_RLLP_CNT, 0, "CLR_RLLP_CNT"},
-    {BRIDGE_CTRL_CLR_TLLP_CNT, 0, "CLR_TLLP_CNT"},
-    {BRIDGE_CTRL_SYS_END, 0, "SYS_END"},
-
-    {BRIDGE_CTRL_BUS_SPEED_MASK, -4, "BUS_SPEED", "%d"},
-    {BRIDGE_CTRL_WIDGET_ID_MASK, 0, "WIDGET_ID", "%x"},
-    {0}
-};
-#endif
-#endif	/* LATER */
-
 /* kbrick widgetnum-to-bus layout */
 int p_busnum[MAX_PORT_NUM] = {                  /* widget#      */
         0, 0, 0, 0, 0, 0, 0, 0,                 /* 0x0 - 0x7    */
@@ -132,18 +112,6 @@
         3,                                      /* 0xf          */
 };
 
-/*
- * Additional PIO spaces per slot are
- * recorded in this structure.
- */
-struct pciio_piospace_s {
-    pciio_piospace_t        next;       /* another space for this device */
-    char                    free;       /* 1 if free, 0 if in use               */
-    pciio_space_t           space;      /* Which space is in use                */
-    iopaddr_t               start;      /* Starting address of the PIO space    */
-    size_t                  count;      /* size of PIO space                    */
-};
-
 #if PCIBR_SOFT_LIST
 pcibr_list_p            pcibr_list = 0;
 #endif
@@ -152,15 +120,15 @@
 extern int              hub_device_flags_set(devfs_handle_t widget_dev, hub_widget_flags_t flags);
 extern long             atoi(register char *p);
 extern cnodeid_t        nodevertex_to_cnodeid(devfs_handle_t vhdl);
-extern void             *swap_ptr(void **loc, void *new);
 extern char             *dev_to_name(devfs_handle_t dev, char *buf, uint buflen);
 extern struct map       *atemapalloc(uint64_t);
 extern void             atefree(struct map *, size_t, uint64_t);
 extern void             atemapfree(struct map *);
 extern pciio_dmamap_t   get_free_pciio_dmamap(devfs_handle_t);
 extern void		free_pciio_dmamap(pcibr_dmamap_t);
+extern void		xwidget_error_register(devfs_handle_t, error_handler_f *, error_handler_arg_t);
 
-#define	ATE_WRITE()    ate_write(ate_ptr, ate_count, ate)
+#define	ATE_WRITE()    ate_write(pcibr_soft, ate_ptr, ate_count, ate)
 #if PCIBR_FREEZE_TIME
 #define	ATE_FREEZE()	s = ate_freeze(pcibr_dmamap, &freeze_time, cmd_regs)
 #else
@@ -173,7 +141,6 @@
 #define	ATE_THAW()	ate_thaw(pcibr_dmamap, ate_index, cmd_regs, s)
 #endif
 
-
 /* =====================================================================
  *    Function Table of Contents
  *
@@ -183,58 +150,54 @@
  *      perhaps bust this file into smaller chunks.
  */
 
-extern void              do_pcibr_rrb_clear(bridge_t *, int);
-extern void              do_pcibr_rrb_flush(bridge_t *, int);
-extern int               do_pcibr_rrb_count_valid(bridge_t *, pciio_slot_t);
-extern int               do_pcibr_rrb_count_avail(bridge_t *, pciio_slot_t);
-extern int               do_pcibr_rrb_alloc(bridge_t *, pciio_slot_t, int);
-extern int               do_pcibr_rrb_free(bridge_t *, pciio_slot_t, int);
-
-extern void              do_pcibr_rrb_autoalloc(pcibr_soft_t, int, int);
+extern int		 do_pcibr_rrb_free_all(pcibr_soft_t, bridge_t *, pciio_slot_t);
+extern void              do_pcibr_rrb_autoalloc(pcibr_soft_t, int, int, int);
 
 extern int  		 pcibr_wrb_flush(devfs_handle_t);
 extern int               pcibr_rrb_alloc(devfs_handle_t, int *, int *);
-extern int               pcibr_rrb_check(devfs_handle_t, int *, int *, int *, int *);
-extern int               pcibr_alloc_all_rrbs(devfs_handle_t, int, int, int, int, int, int, int, int, int);
 extern void              pcibr_rrb_flush(devfs_handle_t);
 
 static int                pcibr_try_set_device(pcibr_soft_t, pciio_slot_t, unsigned, bridgereg_t);
 void                     pcibr_release_device(pcibr_soft_t, pciio_slot_t, bridgereg_t);
 
-extern void              pcibr_clearwidint(bridge_t *);
 extern void              pcibr_setwidint(xtalk_intr_t);
+extern void              pcibr_clearwidint(bridge_t *);
+
+extern iopaddr_t         pcibr_bus_addr_alloc(pcibr_soft_t, pciio_win_info_t,
+                                              pciio_space_t, int, int, int);
 
 void                     pcibr_init(void);
 int                      pcibr_attach(devfs_handle_t);
+int			 pcibr_attach2(devfs_handle_t, bridge_t *, devfs_handle_t,
+				       int, pcibr_soft_t *);
 int			 pcibr_detach(devfs_handle_t);
 int                      pcibr_open(devfs_handle_t *, int, int, cred_t *);
 int                      pcibr_close(devfs_handle_t, int, int, cred_t *);
 int                      pcibr_map(devfs_handle_t, vhandl_t *, off_t, size_t, uint);
 int                      pcibr_unmap(devfs_handle_t, vhandl_t *);
 int                      pcibr_ioctl(devfs_handle_t, int, void *, int, struct cred *, int *);
-
-void                     pcibr_freeblock_sub(iopaddr_t *, iopaddr_t *, iopaddr_t, size_t);
-
+int			 pcibr_pcix_rbars_calc(pcibr_soft_t);
 extern int               pcibr_init_ext_ate_ram(bridge_t *);
 extern int               pcibr_ate_alloc(pcibr_soft_t, int);
 extern void              pcibr_ate_free(pcibr_soft_t, int, int);
+extern int 		 pcibr_widget_to_bus(devfs_handle_t pcibr_vhdl);
 
-extern unsigned          ate_freeze(pcibr_dmamap_t pcibr_dmamap,
+extern unsigned ate_freeze(pcibr_dmamap_t pcibr_dmamap,
 #if PCIBR_FREEZE_TIME
 	   		 unsigned *freeze_time_ptr,
 #endif
-						unsigned *cmd_regs);
-extern void              ate_write(bridge_ate_p ate_ptr, int ate_count, bridge_ate_t ate);
-extern void              ate_thaw(pcibr_dmamap_t pcibr_dmamap, int ate_index,
+	   		 unsigned *cmd_regs);
+extern void ate_write(pcibr_soft_t pcibr_soft, bridge_ate_p ate_ptr, int ate_count, bridge_ate_t ate);
+extern void ate_thaw(pcibr_dmamap_t pcibr_dmamap, int ate_index,
 #if PCIBR_FREEZE_TIME
-	 				bridge_ate_t ate,
-	 				int ate_total,
-	 				unsigned freeze_time_start,
+	 		bridge_ate_t ate,
+	 		int ate_total,
+	 		unsigned freeze_time_start,
 #endif
-	 				unsigned *cmd_regs,
-	 				unsigned s);
+	 		unsigned *cmd_regs,
+	 		unsigned s);
 
-pcibr_info_t             pcibr_info_get(devfs_handle_t);
+pcibr_info_t      pcibr_info_get(devfs_handle_t);
 
 static iopaddr_t         pcibr_addr_pci_to_xio(devfs_handle_t, pciio_slot_t, pciio_space_t, iopaddr_t, size_t, unsigned);
 
@@ -264,23 +227,23 @@
 void                    pcibr_dmalist_drain(devfs_handle_t, alenlist_t);
 iopaddr_t               pcibr_dmamap_pciaddr_get(pcibr_dmamap_t);
 
-extern unsigned		pcibr_intr_bits(pciio_info_t info, pciio_intr_line_t lines);
+extern unsigned		pcibr_intr_bits(pciio_info_t info, 
+					pciio_intr_line_t lines, int nslots);
 extern pcibr_intr_t     pcibr_intr_alloc(devfs_handle_t, device_desc_t, pciio_intr_line_t, devfs_handle_t);
 extern void             pcibr_intr_free(pcibr_intr_t);
 extern void             pcibr_setpciint(xtalk_intr_t);
-extern int              pcibr_intr_connect(pcibr_intr_t);
+extern int              pcibr_intr_connect(pcibr_intr_t, intr_func_t, intr_arg_t);
 extern void             pcibr_intr_disconnect(pcibr_intr_t);
 
 extern devfs_handle_t     pcibr_intr_cpu_get(pcibr_intr_t);
-extern void             pcibr_xintr_preset(void *, int, xwidgetnum_t, iopaddr_t, xtalk_intr_vector_t);
 extern void             pcibr_intr_func(intr_arg_t);
 
 extern void             print_bridge_errcmd(uint32_t, char *);
 
 extern void             pcibr_error_dump(pcibr_soft_t);
-extern uint32_t         pcibr_errintr_group(uint32_t);
+extern uint32_t       pcibr_errintr_group(uint32_t);
 extern void	        pcibr_pioerr_check(pcibr_soft_t);
-extern void             pcibr_error_intr_handler(intr_arg_t);
+extern void             pcibr_error_intr_handler(int, void *, struct pt_regs *);
 
 extern int              pcibr_addr_toslot(pcibr_soft_t, iopaddr_t, pciio_space_t *, iopaddr_t *, pciio_function_t *);
 extern void             pcibr_error_cleanup(pcibr_soft_t, int);
@@ -289,8 +252,7 @@
 extern int              pcibr_dmard_error(pcibr_soft_t, int, ioerror_mode_t, ioerror_t *);
 extern int              pcibr_dmawr_error(pcibr_soft_t, int, ioerror_mode_t, ioerror_t *);
 extern int              pcibr_error_handler(error_handler_arg_t, int, ioerror_mode_t, ioerror_t *);
-extern int              pcibr_error_devenable(devfs_handle_t, int);
-
+extern int              pcibr_error_handler_wrapper(error_handler_arg_t, int, ioerror_mode_t, ioerror_t *);
 void                    pcibr_provider_startup(devfs_handle_t);
 void                    pcibr_provider_shutdown(devfs_handle_t);
 
@@ -303,7 +265,6 @@
 extern cfg_p            pcibr_config_addr(devfs_handle_t, unsigned);
 extern uint64_t         pcibr_config_get(devfs_handle_t, unsigned, unsigned);
 extern void             pcibr_config_set(devfs_handle_t, unsigned, unsigned, uint64_t);
-extern void             do_pcibr_config_set(cfg_p, unsigned, unsigned, uint64_t);
 
 extern pcibr_hints_t    pcibr_hints_get(devfs_handle_t, int);
 extern void             pcibr_hints_fix_rrbs(devfs_handle_t);
@@ -313,38 +274,31 @@
 extern void             pcibr_hints_handsoff(devfs_handle_t);
 extern void             pcibr_hints_subdevs(devfs_handle_t, pciio_slot_t, uint64_t);
 
-#ifdef BRIDGE_B_DATACORR_WAR
-extern int              ql_bridge_rev_b_war(devfs_handle_t);
-extern int              bridge_rev_b_data_check_disable;
-char                   *rev_b_datacorr_warning =
-"***************************** WARNING! ******************************\n";
-char                   *rev_b_datacorr_mesg =
-"UNRECOVERABLE IO LINK ERROR. CONTACT SERVICE PROVIDER\n";
-#endif
-
 extern int		pcibr_slot_reset(devfs_handle_t,pciio_slot_t);
 extern int		pcibr_slot_info_init(devfs_handle_t,pciio_slot_t);
 extern int		pcibr_slot_info_free(devfs_handle_t,pciio_slot_t);
+extern int	        pcibr_slot_info_return(pcibr_soft_t, pciio_slot_t,
+                                               pcibr_slot_info_resp_t);
+extern void       	pcibr_slot_func_info_return(pcibr_info_h, int,
+                                                    pcibr_slot_func_info_resp_t);
 extern int		pcibr_slot_addr_space_init(devfs_handle_t,pciio_slot_t);
+extern int		pcibr_slot_pcix_rbar_init(pcibr_soft_t, pciio_slot_t);
 extern int		pcibr_slot_device_init(devfs_handle_t, pciio_slot_t);
 extern int		pcibr_slot_guest_info_init(devfs_handle_t,pciio_slot_t);
-extern int		pcibr_slot_call_device_attach(devfs_handle_t, pciio_slot_t, int);
-extern int		pcibr_slot_call_device_detach(devfs_handle_t, pciio_slot_t, int);
-extern int              pcibr_slot_attach(devfs_handle_t, pciio_slot_t, int, char *, int *);
-extern int              pcibr_slot_detach(devfs_handle_t, pciio_slot_t, int);
+extern int		pcibr_slot_call_device_attach(devfs_handle_t,
+						      pciio_slot_t, int);
+extern int		pcibr_slot_call_device_detach(devfs_handle_t,
+						      pciio_slot_t, int);
+extern int              pcibr_slot_attach(devfs_handle_t, pciio_slot_t, int, 
+                                                      char *, int *);
+extern int              pcibr_slot_detach(devfs_handle_t, pciio_slot_t, int,
+                                                      char *, int *);
 extern int 		pcibr_is_slot_sys_critical(devfs_handle_t, pciio_slot_t);
 
-#ifdef LATER
-extern int		pcibr_slot_startup(devfs_handle_t, pcibr_slot_req_t);
-extern int		pcibr_slot_shutdown(devfs_handle_t, pcibr_slot_req_t);
-extern int		pcibr_slot_query(devfs_handle_t, pcibr_slot_req_t);
-#endif
-
 extern int		pcibr_slot_initial_rrb_alloc(devfs_handle_t, pciio_slot_t);
 extern int		pcibr_initial_rrb(devfs_handle_t, pciio_slot_t, pciio_slot_t);
 
 
-
 /* =====================================================================
  *    Device(x) register management
  */
@@ -377,7 +331,7 @@
     bridgereg_t             xmask;
 
     xmask = mask;
-    if (pcibr_soft->bs_xbridge) {
+    if (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft)) {
     	if (mask == BRIDGE_DEV_PMU_BITS)
 		xmask = XBRIDGE_DEV_PMU_BITS;
 	if (mask == BRIDGE_DEV_D64_BITS)
@@ -464,10 +418,10 @@
 	new &= ~BRIDGE_DEV_WRGA_BITS;
 
     if (flags & PCIIO_BYTE_STREAM)
-	new |= (pcibr_soft->bs_xbridge) ? 
+	new |= (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft)) ? 
 			BRIDGE_DEV_SWAP_DIR : BRIDGE_DEV_SWAP_BITS;
     if (flags & PCIIO_WORD_VALUES)
-	new &= (pcibr_soft->bs_xbridge) ? 
+	new &= (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft)) ? 
 			~BRIDGE_DEV_SWAP_DIR : ~BRIDGE_DEV_SWAP_BITS;
 
     /* Provider-specific flags
@@ -492,13 +446,28 @@
     if (flags & PCIBR_NO64BIT)
 	new &= ~BRIDGE_DEV_DEV_SIZE;
 
+    /*
+     * PIC BRINGUP WAR (PV# 855271):
+     * Allow setting BRIDGE_DEV_VIRTUAL_EN on PIC iff we're a 64-bit
+     * device.  The bit is only intended for 64-bit devices and, on
+     * PIC, can cause problems for 32-bit devices.
+     */
+    if (IS_PIC_SOFT(pcibr_soft) && mask == BRIDGE_DEV_D64_BITS &&
+                                PCIBR_WAR_ENABLED(PV855271, pcibr_soft)) {
+        if (flags & PCIBR_VCHAN1) {
+                new |= BRIDGE_DEV_VIRTUAL_EN;
+                xmask |= BRIDGE_DEV_VIRTUAL_EN;
+        }
+    }
+
+
     chg = old ^ new;				/* what are we changing, */
     chg &= xmask;				/* of the interesting bits */
 
     if (chg) {
 
 	badd32 = slotp->bss_d32_uctr ? (BRIDGE_DEV_D32_BITS & chg) : 0;
-	if (pcibr_soft->bs_xbridge) {
+	if (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft)) {
 		badpmu = slotp->bss_pmu_uctr ? (XBRIDGE_DEV_PMU_BITS & chg) : 0;
 		badd64 = slotp->bss_d64_uctr ? (XBRIDGE_DEV_D64_BITS & chg) : 0;
 	} else {
@@ -517,7 +486,7 @@
 	     * the new stream at all.
 	     */
             if ( (fix = bad & (BRIDGE_DEV_PRECISE |
-                             BRIDGE_DEV_BARRIER)) ){
+                             BRIDGE_DEV_BARRIER)) ) {
 		bad &= ~fix;
 		/* don't change these bits if
 		 * they are already set in "old"
@@ -546,8 +515,10 @@
 	     */
 	    if (bad) {
 		pcibr_unlock(pcibr_soft, s);
-#if (DEBUG && PCIBR_DEV_DEBUG)
-		printk("pcibr_try_set_device: mod blocked by %R\n", bad, device_bits);
+#ifdef PIC_LATER
+		PCIBR_DEBUG((PCIBR_DEBUG_DEVREG, pcibr_soft->bs_vhdl,
+			    "pcibr_try_set_device: mod blocked by %x\n",
+			    bad, device_bits));
 #endif
 		return bad;
 	    }
@@ -571,14 +542,31 @@
 	pcibr_unlock(pcibr_soft, s);
 	return 0;
     }
-    bridge->b_device[slot].reg = new;
-    slotp->bss_device = new;
-    bridge->b_wid_tflush;		/* wait until Bridge PIO complete */
+    if ( IS_PIC_SOFT(pcibr_soft) ) {
+	bridge->b_device[slot].reg = new;
+	slotp->bss_device = new;
+	bridge->b_wid_tflush;		/* wait until Bridge PIO complete */
+    }
+    else {
+	if (io_get_sh_swapper(NASID_GET(bridge))) {
+		BRIDGE_REG_SET32((&bridge->b_device[slot].reg)) = __swab32(new);
+		slotp->bss_device = new;
+		BRIDGE_REG_GET32((&bridge->b_wid_tflush));  /* wait until Bridge PIO complete */
+	} else {
+		bridge->b_device[slot].reg = new;
+		slotp->bss_device = new;
+		bridge->b_wid_tflush;               /* wait until Bridge PIO complete */
+	}
+    }
     pcibr_unlock(pcibr_soft, s);
-#if DEBUG && PCIBR_DEV_DEBUG
-    printk("pcibr Device(%d): 0x%p\n", slot, bridge->b_device[slot].reg);
-#endif
 
+#ifdef PIC_LATER
+    PCIBR_DEBUG((PCIBR_DEBUG_DEVREG, pcibr_soft->bs_vhdl,
+		"pcibr_try_set_device: Device(%d): %x\n",
+		slot, new, device_bits));
+#else
+    printk("pcibr_try_set_device: Device(%d): %x\n", slot, new);
+#endif
     return 0;
 }
 
@@ -616,7 +604,17 @@
     volatile uint32_t     wrf;
     s = pcibr_lock(pcibr_soft);
     bridge = pcibr_soft->bs_base;
-    wrf = bridge->b_wr_req_buf[slot].reg;
+
+    if ( IS_PIC_SOFT(pcibr_soft) ) {
+	wrf = bridge->b_wr_req_buf[slot].reg;
+    }
+    else {
+	if (io_get_sh_swapper(NASID_GET(bridge))) {
+		wrf = BRIDGE_REG_GET32((&bridge->b_wr_req_buf[slot].reg));
+	} else {
+		wrf = bridge->b_wr_req_buf[slot].reg;
+	}
+    }
     pcibr_unlock(pcibr_soft, s);
 }
 
@@ -637,9 +635,7 @@
 void
 pcibr_init(void)
 {
-#if DEBUG && ATTACH_DEBUG
-    printk("pcibr_init\n");
-#endif
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INIT, NULL, "pcibr_init()\n"));
 
     xwidget_driver_register(XBRIDGE_WIDGET_PART_NUM,
 			    XBRIDGE_WIDGET_MFGR_NUM,
@@ -700,7 +696,7 @@
      * XXX- deprecate this in favor of using the
      * real flash driver ...
      */
-    if (!error &&
+    if (IS_BRIDGE_SOFT(pcibr_soft) && !error &&
 	((off == BRIDGE_EXTERNAL_FLASH) ||
 	 (len > BRIDGE_EXTERNAL_FLASH))) {
 	int                     s;
@@ -710,11 +706,16 @@
 	 * The read following the write is required for the Bridge war
 	 */
 	s = splhi();
-	bridge->b_wid_control |= BRIDGE_CTRL_FLASH_WR_EN;
-	bridge->b_wid_control;		/* inval addr bug war */
+
+	if (io_get_sh_swapper(NASID_GET(bridge))) {
+		BRIDGE_REG_SET32((&bridge->b_wid_control)) |= __swab32(BRIDGE_CTRL_FLASH_WR_EN);
+		BRIDGE_REG_GET32((&bridge->b_wid_control));          /* inval addr bug war */
+	} else {
+		bridge->b_wid_control |= BRIDGE_CTRL_FLASH_WR_EN;
+		bridge->b_wid_control;          /* inval addr bug war */
+	}
 	splx(s);
     }
-
     return error;
 }
 
@@ -728,21 +729,53 @@
 
     hwgraph_vertex_unref(pcibr_vhdl);
 
-    /*
-     * If flashprom write was enabled, disable it, as
-     * this is the last unmap.
-     */
-    if (bridge->b_wid_control & BRIDGE_CTRL_FLASH_WR_EN) {
-	int                     s;
-
+    if ( IS_PIC_SOFT(pcibr_soft) ) {
 	/*
-	 * ensure that we write and read without any interruption.
-	 * The read following the write is required for the Bridge war
+	 * If flashprom write was enabled, disable it, as
+	 * this is the last unmap.
 	 */
-	s = splhi();
-	bridge->b_wid_control &= ~BRIDGE_CTRL_FLASH_WR_EN;
-	bridge->b_wid_control;		/* inval addr bug war */
-	splx(s);
+	if (IS_BRIDGE_SOFT(pcibr_soft) && 
+			(bridge->b_wid_control & BRIDGE_CTRL_FLASH_WR_EN)) {
+		int                     s;
+
+		/*
+		 * ensure that we write and read without any interruption.
+		 * The read following the write is required for the Bridge war
+		 */
+		s = splhi();
+		bridge->b_wid_control &= ~BRIDGE_CTRL_FLASH_WR_EN;
+		bridge->b_wid_control;		/* inval addr bug war */
+		splx(s);
+	}
+    }
+    else {
+	if (io_get_sh_swapper(NASID_GET(bridge))) {
+		if (BRIDGE_REG_GET32((&bridge->b_wid_control)) & BRIDGE_CTRL_FLASH_WR_EN) {
+			int                     s;
+
+			/*
+			 * ensure that we write and read without any interruption.
+			 * The read following the write is required for the Bridge war
+			 */
+			s = splhi();
+			BRIDGE_REG_SET32((&bridge->b_wid_control)) &= __swab32((unsigned int)~BRIDGE_CTRL_FLASH_WR_EN);
+			BRIDGE_REG_GET32((&bridge->b_wid_control));          /* inval addr bug war */
+			splx(s);
+		} else {
+			if (bridge->b_wid_control & BRIDGE_CTRL_FLASH_WR_EN) {
+				int                     s;
+
+				/*
+				 * ensure that we write and read without any interruption.
+				 * The read following the write is required for the Bridge war
+				 */
+				s = splhi();
+				bridge->b_wid_control &= ~BRIDGE_CTRL_FLASH_WR_EN;
+				bridge->b_wid_control;          /* inval addr bug war */
+				splx(s);
+    			}
+		}
+	}
     }
     return 0;
 }
@@ -768,7 +801,7 @@
     while (tdev != GRAPH_VERTEX_NONE) {
 	pciio_info = pciio_info_chk(tdev);
 	if (pciio_info) {
-	    slot = pciio_info_slot_get(pciio_info);
+	    slot = PCIBR_INFO_SLOT_GET_INT(pciio_info);
 	    break;
 	}
 	hwgraph_vertex_unref(tdev);
@@ -788,167 +821,7 @@
 	    struct cred *cr,
 	    int *rvalp)
 {
-    devfs_handle_t            pcibr_vhdl = hwgraph_connectpt_get((devfs_handle_t)dev);
-#ifdef LATER
-    pcibr_soft_t            pcibr_soft = pcibr_soft_get(pcibr_vhdl);
-#endif
-    int                     error = 0;
-
-    hwgraph_vertex_unref(pcibr_vhdl);
-
-    switch (cmd) {
-#ifdef LATER
-    case GIOCSETBW:
-	{
-	    grio_ioctl_info_t       info;
-	    pciio_slot_t            slot = 0;
-
-	    if (!cap_able((uint64_t)CAP_DEVICE_MGT)) {
-		error = EPERM;
-		break;
-	    }
-	    if (COPYIN(arg, &info, sizeof(grio_ioctl_info_t))) {
-		error = EFAULT;
-		break;
-	    }
-#ifdef GRIO_DEBUG
-	    printk("pcibr:: prev_vhdl: %d reqbw: %lld\n",
-		    info.prev_vhdl, info.reqbw);
-#endif				/* GRIO_DEBUG */
-
-	    if ((slot = pcibr_device_slot_get(info.prev_vhdl)) ==
-		PCIIO_SLOT_NONE) {
-		error = EIO;
-		break;
-	    }
-	    if (info.reqbw)
-		pcibr_priority_bits_set(pcibr_soft, slot, PCI_PRIO_HIGH);
-	    break;
-	}
-
-    case GIOCRELEASEBW:
-	{
-	    grio_ioctl_info_t       info;
-	    pciio_slot_t            slot = 0;
-
-	    if (!cap_able(CAP_DEVICE_MGT)) {
-		error = EPERM;
-		break;
-	    }
-	    if (COPYIN(arg, &info, sizeof(grio_ioctl_info_t))) {
-		error = EFAULT;
-		break;
-	    }
-#ifdef GRIO_DEBUG
-	    printk("pcibr:: prev_vhdl: %d reqbw: %lld\n",
-		    info.prev_vhdl, info.reqbw);
-#endif				/* GRIO_DEBUG */
-
-	    if ((slot = pcibr_device_slot_get(info.prev_vhdl)) ==
-		PCIIO_SLOT_NONE) {
-		error = EIO;
-		break;
-	    }
-	    if (info.reqbw)
-		pcibr_priority_bits_set(pcibr_soft, slot, PCI_PRIO_LOW);
-	    break;
-	}
-
-    case PCIBR_SLOT_STARTUP:
-	{
-	    struct pcibr_slot_req_s        req;
-
-	    if (!cap_able(CAP_DEVICE_MGT)) {
-		error = EPERM;
-		break;
-	    }
-
-            if (COPYIN(arg, &req, sizeof(req))) {
-                error = EFAULT;
-                break;
-            }
-
-	    error = pcibr_slot_startup(pcibr_vhdl, &req);
-	    break;
-	}
-    case PCIBR_SLOT_SHUTDOWN:
-	{
-	    struct pcibr_slot_req_s        req;
-
-	    if (!cap_able(CAP_DEVICE_MGT)) {
-		error = EPERM;
-		break;
-	    }
-
-            if (COPYIN(arg, &req, sizeof(req))) {
-                error = EFAULT;
-                break;
-            }
-
-	    error = pcibr_slot_shutdown(pcibr_vhdl, &req);
-	    break;
-	}
-    case PCIBR_SLOT_QUERY:
-	{
-	    struct pcibr_slot_req_s        req;
-
-	    if (!cap_able(CAP_DEVICE_MGT)) {
-		error = EPERM;
-		break;
-	    }
-
-            if (COPYIN(arg, &req, sizeof(req))) {
-                error = EFAULT;
-                break;
-            }
-
-            error = pcibr_slot_query(pcibr_vhdl, &req);
-	    break;
-	}
-#endif	/* LATER */
-    default:
-	break;
-
-    }
-
-    return error;
-}
-
-void
-pcibr_freeblock_sub(iopaddr_t *free_basep,
-		    iopaddr_t *free_lastp,
-		    iopaddr_t base,
-		    size_t size)
-{
-    iopaddr_t               free_base = *free_basep;
-    iopaddr_t               free_last = *free_lastp;
-    iopaddr_t               last = base + size - 1;
-
-    if ((last < free_base) || (base > free_last));	/* free block outside arena */
-
-    else if ((base <= free_base) && (last >= free_last))
-	/* free block contains entire arena */
-	*free_basep = *free_lastp = 0;
-
-    else if (base <= free_base)
-	/* free block is head of arena */
-	*free_basep = last + 1;
-
-    else if (last >= free_last)
-	/* free block is tail of arena */
-	*free_lastp = base - 1;
-
-    /*
-     * We are left with two regions: the free area
-     * in the arena "below" the block, and the free
-     * area in the arena "above" the block. Keep
-     * the one that is bigger.
-     */
-
-    else if ((base - free_base) > (free_last - last))
-	*free_lastp = base - 1;		/* keep lower chunk */
-    else
-	*free_basep = last + 1;		/* keep upper chunk */
+    return 0;
 }
 
 pcibr_info_t
@@ -971,16 +844,22 @@
 
     func = (rfunc == PCIIO_FUNC_NONE) ? 0 : rfunc;
 
+    /*
+     * Create a pciio_info_s for this device.  pciio_device_info_new()
+     * will set the c_slot (which is suppose to represent the external
+     * slot (i.e the slot number silk screened on the back of the I/O
+     * brick)).  So for PIC we need to adjust this "internal slot" num
+     * passed into us, into it's external representation.  See comment
+     * for the PCIBR_DEVICE_TO_SLOT macro for more information.
+     */
     NEW(pcibr_info);
+    pciio_device_info_new(&pcibr_info->f_c, pcibr_soft->bs_vhdl,
+			  PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot),
+			  rfunc, vendor, device);
+    pcibr_info->f_dev = slot;
 
-    pciio_device_info_new(&pcibr_info->f_c,
-			  pcibr_soft->bs_vhdl,
-			  slot, rfunc,
-			  vendor, device);
-
-/* pfg - this is new ..... */
     /* Set PCI bus number */
-    pcibr_info->f_bus = io_path_map_widget(pcibr_soft->bs_vhdl);
+    pcibr_info->f_bus = pcibr_widget_to_bus(pcibr_soft->bs_vhdl);
 
     if (slot != PCIIO_SLOT_NONE) {
 
@@ -1016,30 +895,6 @@
 }
 
 
-/* FIXME:  for now this is needed by both pcibr.c and
- * pcibr_slot.c.  Need to find a better way, the least
- * of which would be to move it to pcibr_private.h
- */
-
-/*
- * PCI_ADDR_SPACE_LIMITS_STORE
- *	Sets the current values of
- *		pci io base, 
- *		pci io last,
- *		pci low memory base,
- *		pci low memory last,
- *		pci high memory base,
- * 		pci high memory last
- */
-#define PCI_ADDR_SPACE_LIMITS_STORE()			\
-    pcibr_soft->bs_spinfo.pci_io_base = pci_io_fb;	\
-    pcibr_soft->bs_spinfo.pci_io_last = pci_io_fl;	\
-    pcibr_soft->bs_spinfo.pci_swin_base = pci_lo_fb;	\
-    pcibr_soft->bs_spinfo.pci_swin_last = pci_lo_fl;	\
-    pcibr_soft->bs_spinfo.pci_mem_base = pci_hi_fb;	\
-    pcibr_soft->bs_spinfo.pci_mem_last = pci_hi_fl;
-
-
 /*
  * pcibr_device_unregister
  *	This frees up any hardware resources reserved for this PCI device
@@ -1062,7 +917,7 @@
     pciio_info = pciio_info_get(pconn_vhdl);
 
     pcibr_vhdl = pciio_info_master_get(pciio_info);
-    slot = pciio_info_slot_get(pciio_info);
+    slot = PCIBR_INFO_SLOT_GET_INT(pciio_info);
 
     pcibr_soft = pcibr_soft_get(pcibr_vhdl);
     bridge = pcibr_soft->bs_base;
@@ -1077,27 +932,24 @@
      * If the RRB configuration for this slot has changed, set it 
      * back to the boot-time default
      */
-    if (pcibr_soft->bs_rrb_valid_dflt[slot] >= 0) {
+    if (pcibr_soft->bs_rrb_valid_dflt[slot][VCHAN0] >= 0) {
 
         s = pcibr_lock(pcibr_soft);
 
-        /* Free the rrbs allocated to this slot */
-        error_call = do_pcibr_rrb_free(bridge, slot, 
-		                       pcibr_soft->bs_rrb_valid[slot] +
-		                       pcibr_soft->bs_rrb_valid[slot + 
-                                       PCIBR_RRB_SLOT_VIRTUAL]);
-
-        if (error_call)
-            error = ERANGE;
-   
-         pcibr_soft->bs_rrb_res[slot] = pcibr_soft->bs_rrb_res[slot] +
-                                        pcibr_soft->bs_rrb_valid[slot] +
-                                        pcibr_soft->bs_rrb_valid[slot +
-                                        PCIBR_RRB_SLOT_VIRTUAL];
-
-        count_vchan0 = pcibr_soft->bs_rrb_valid_dflt[slot];
-        count_vchan1 = pcibr_soft->bs_rrb_valid_dflt[slot +
-                                                     PCIBR_RRB_SLOT_VIRTUAL];
+	/* PIC NOTE: If this is a BRIDGE, VCHAN2 & VCHAN3 will be zero so
+	 * no need to conditionalize this (ie. "if (IS_PIC_SOFT())" ).
+	 */
+        pcibr_soft->bs_rrb_res[slot] = pcibr_soft->bs_rrb_res[slot] +
+                                       pcibr_soft->bs_rrb_valid[slot][VCHAN0] +
+                                       pcibr_soft->bs_rrb_valid[slot][VCHAN1] +
+                                       pcibr_soft->bs_rrb_valid[slot][VCHAN2] +
+                                       pcibr_soft->bs_rrb_valid[slot][VCHAN3];
+
+        /* Free the rrbs allocated to this slot, both the normal & virtual */
+	do_pcibr_rrb_free_all(pcibr_soft, bridge, slot);
+
+        count_vchan0 = pcibr_soft->bs_rrb_valid_dflt[slot][VCHAN0];
+        count_vchan1 = pcibr_soft->bs_rrb_valid_dflt[slot][VCHAN1];
 
         pcibr_unlock(pcibr_soft, s);
 
@@ -1147,12 +999,14 @@
     pcibr_info = pcibr_info_get(pconn_vhdl);
 
     pcibr_vhdl = pciio_info_master_get(pciio_info);
-    slot = pciio_info_slot_get(pciio_info);
+    slot = PCIBR_INFO_SLOT_GET_INT(pciio_info);
 
     pcibr_soft = pcibr_soft_get(pcibr_vhdl);
 
+#ifdef PIC_LATER
     /* This may be a loadable driver so lock out any pciconfig actions */
     mrlock(pcibr_soft->bs_bus_lock, MR_UPDATE, PZERO);
+#endif
 
     pcibr_info->f_att_det_error = error;
 
@@ -1164,9 +1018,10 @@
         pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_CMPLT;
     }
         
+#ifdef PIC_LATER
     /* Release the bus lock */
     mrunlock(pcibr_soft->bs_bus_lock);
-
+#endif
 }
 
 /*
@@ -1195,12 +1050,14 @@
     pcibr_info = pcibr_info_get(pconn_vhdl);
 
     pcibr_vhdl = pciio_info_master_get(pciio_info);
-    slot = pciio_info_slot_get(pciio_info);
+    slot = PCIBR_INFO_SLOT_GET_INT(pciio_info);
 
     pcibr_soft = pcibr_soft_get(pcibr_vhdl);
 
+#ifdef PIC_LATER
     /* This may be a loadable driver so lock out any pciconfig actions */
     mrlock(pcibr_soft->bs_bus_lock, MR_UPDATE, PZERO);
+#endif
 
     pcibr_info->f_att_det_error = error;
 
@@ -1211,10 +1068,11 @@
     } else {
         pcibr_soft->bs_slot[slot].slot_status |= SLOT_SHUTDOWN_CMPLT;
     }
-        
+
+#ifdef PIC_LATER
     /* Release the bus lock */
     mrunlock(pcibr_soft->bs_bus_lock);
-
+#endif
 }
 
 /* 
@@ -1226,7 +1084,7 @@
  * depends on hwgraph separator == '/'
  */
 int
-pcibr_bus_cnvlink(devfs_handle_t f_c, int slot)
+pcibr_bus_cnvlink(devfs_handle_t f_c)
 {
         char dst[MAXDEVNAME];
 	char *dp = dst;
@@ -1236,16 +1094,7 @@
 	devfs_handle_t nvtx, svtx;
 	int rv;
 
-#if DEBUG
-	printk("pcibr_bus_cnvlink: slot= %d f_c= %p\n", 
-		slot, f_c);
-	{
-		int pos;
-		char dname[256];
-		pos = devfs_generate_path(f_c, dname, 256);
-		printk("%s : path= %s\n", __FUNCTION__, &dname[pos]);
-	}
-#endif
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, f_c, "pcibr_bus_cnvlink\n"));
 
 	if (GRAPH_SUCCESS != hwgraph_vertex_name_get(f_c, dst, MAXDEVNAME))
 		return 0;
@@ -1261,7 +1110,7 @@
 		return 0;
 
 	/* remove "/pci/direct" from path */
-	cp = strstr(dst, "/" EDGE_LBL_PCI "/" "direct");
+	cp = strstr(dst, "/" EDGE_LBL_PCI "/" EDGE_LBL_DIRECT);
 	if (cp == NULL)
 		return 0;
 	*cp = (char)NULL;
@@ -1275,7 +1124,8 @@
 	/* dst example now == /hw/module/001c02/Pbrick */
 
 	/* get the bus number */
-        strcat(dst, "/bus");
+        strcat(dst, "/");
+        strcat(dst, EDGE_LBL_BUS);
         sprintf(pcibus, "%d", p_busnum[widgetnum]);
 
 	/* link to bus to widget */
@@ -1300,75 +1150,74 @@
     /* REFERENCED */
     graph_error_t           rc;
     devfs_handle_t            pcibr_vhdl;
+    bridge_t               *bridge;
+
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, xconn_vhdl, "pcibr_attach\n"));
+
+    bridge = (bridge_t *)
+	xtalk_piotrans_addr(xconn_vhdl, NULL,
+			    0, sizeof(bridge_t), 0);
+    /*
+     * Create the vertex for the PCI bus, which we
+     * will also use to hold the pcibr_soft and
+     * which will be the "master" vertex for all the
+     * pciio connection points we will hang off it.
+     * This needs to happen before we call nic_bridge_vertex_info
+     * as we are some of the *_vmc functions need access to the edges.
+     *
+     * Opening this vertex will provide access to
+     * the Bridge registers themselves.
+     */
+    rc = hwgraph_path_add(xconn_vhdl, EDGE_LBL_PCI, &pcibr_vhdl);
+    ASSERT(rc == GRAPH_SUCCESS);
+
+    pciio_provider_register(pcibr_vhdl, &pcibr_provider);
+    pciio_provider_startup(pcibr_vhdl);
+
+    return pcibr_attach2(xconn_vhdl, bridge, pcibr_vhdl, 0, NULL);
+}
+
+
+/*ARGSUSED */
+int
+pcibr_attach2(devfs_handle_t xconn_vhdl, bridge_t *bridge, 
+	      devfs_handle_t pcibr_vhdl, int busnum, pcibr_soft_t *ret_softp)
+{
+    /* REFERENCED */
     devfs_handle_t            ctlr_vhdl;
-    bridge_t               *bridge = NULL;
     bridgereg_t             id;
     int                     rev;
     pcibr_soft_t            pcibr_soft;
     pcibr_info_t            pcibr_info;
     xwidget_info_t          info;
     xtalk_intr_t            xtalk_intr;
-    device_desc_t           dev_desc = (device_desc_t)0;
     int                     slot;
     int                     ibit;
     devfs_handle_t            noslot_conn;
     char                    devnm[MAXDEVNAME], *s;
     pcibr_hints_t           pcibr_hints;
-    bridgereg_t             b_int_enable;
+    uint64_t              int_enable;
+    bridgereg_t             int_enable_32;
+    picreg_t                int_enable_64;
     unsigned                rrb_fixed = 0;
 
-    iopaddr_t               pci_io_fb, pci_io_fl;
-    iopaddr_t               pci_lo_fb, pci_lo_fl;
-    iopaddr_t               pci_hi_fb, pci_hi_fl;
-
     int                     spl_level;
-#ifdef LATER
-    char		    *nicinfo = (char *)0;
-#endif
 
 #if PCI_FBBE
     int                     fast_back_to_back_enable;
 #endif
-    l1sc_t		    *scp;
     nasid_t		    nasid;
+    int	                    iobrick_type_get_nasid(nasid_t nasid);
+    int                     iobrick_module_get_nasid(nasid_t nasid);
+    extern unsigned char    Is_pic_on_this_nasid[512];
 
-    async_attach_t          aa = NULL;
-
-    aa = async_attach_get_info(xconn_vhdl);
 
-#if DEBUG && ATTACH_DEBUG
-    printk("pcibr_attach: xconn_vhdl=  %p\n", xconn_vhdl);
-    {
-	int pos;
-	char dname[256];
-	pos = devfs_generate_path(xconn_vhdl, dname, 256);
-	printk("%s : path= %s \n", __FUNCTION__, &dname[pos]);
-    }
-#endif
-
-    /* Setup the PRB for the bridge in CONVEYOR BELT
-     * mode. PRBs are setup in default FIRE-AND-FORGET
-     * mode during the initialization.
-     */
-    hub_device_flags_set(xconn_vhdl, HUB_PIO_CONVEYOR);
+    async_attach_t          aa = NULL;
 
-    bridge = (bridge_t *)
-	xtalk_piotrans_addr(xconn_vhdl, NULL,
-			    0, sizeof(bridge_t), 0);
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, pcibr_vhdl,
+	        "pcibr_attach2: bridge=0x%p, busnum=%d\n", bridge, busnum));
 
-    /*
-     * Create the vertex for the PCI bus, which we
-     * will also use to hold the pcibr_soft and
-     * which will be the "master" vertex for all the
-     * pciio connection points we will hang off it.
-     * This needs to happen before we call nic_bridge_vertex_info
-     * as we are some of the *_vmc functions need access to the edges.
-     *
-     * Opening this vertex will provide access to
-     * the Bridge registers themselves.
-     */
-    rc = hwgraph_path_add(xconn_vhdl, EDGE_LBL_PCI, &pcibr_vhdl);
-    ASSERT(rc == GRAPH_SUCCESS);
+    aa = async_attach_get_info(xconn_vhdl);
 
     ctlr_vhdl = NULL;
     ctlr_vhdl = hwgraph_register(pcibr_vhdl, EDGE_LBL_CONTROLLER,
@@ -1380,15 +1229,6 @@
     ASSERT(ctlr_vhdl != NULL);
 
     /*
-     * decode the nic, and hang its stuff off our
-     * connection point where other drivers can get
-     * at it.
-     */
-#ifdef LATER
-    nicinfo = BRIDGE_VERTEX_MFG_INFO(xconn_vhdl, (nic_data_t) & bridge->b_nic);
-#endif
-
-    /*
      * Get the hint structure; if some NIC callback
      * marked this vertex as "hands-off" then we
      * just return here, before doing anything else.
@@ -1408,26 +1248,63 @@
      * fields, and hook it up to our vertex.
      */
     NEW(pcibr_soft);
+    if (ret_softp)
+	*ret_softp = pcibr_soft;
     BZERO(pcibr_soft, sizeof *pcibr_soft);
     pcibr_soft_set(pcibr_vhdl, pcibr_soft);
-
     pcibr_soft->bs_conn = xconn_vhdl;
     pcibr_soft->bs_vhdl = pcibr_vhdl;
     pcibr_soft->bs_base = bridge;
     pcibr_soft->bs_rev_num = rev;
-    pcibr_soft->bs_intr_bits = pcibr_intr_bits;
+    pcibr_soft->bs_intr_bits = (pcibr_intr_bits_f *)pcibr_intr_bits;
+
+    pcibr_soft->bs_min_slot = 0;		/* lowest possible slot# */
+    pcibr_soft->bs_max_slot = 7;		/* highest possible slot# */
+    pcibr_soft->bs_busnum = busnum;
     if (is_xbridge(bridge)) {
-	pcibr_soft->bs_int_ate_size = XBRIDGE_INTERNAL_ATES;
-	pcibr_soft->bs_xbridge = 1;
+	pcibr_soft->bs_bridge_type = PCIBR_BRIDGETYPE_XBRIDGE;
+    } else if (is_pic(bridge)) {
+	pcibr_soft->bs_bridge_type = PCIBR_BRIDGETYPE_PIC;
     } else {
+	pcibr_soft->bs_bridge_type = PCIBR_BRIDGETYPE_BRIDGE;
+    }
+    switch(pcibr_soft->bs_bridge_type) {
+    case PCIBR_BRIDGETYPE_BRIDGE:
 	pcibr_soft->bs_int_ate_size = BRIDGE_INTERNAL_ATES;
-	pcibr_soft->bs_xbridge = 0;
+	pcibr_soft->bs_bridge_mode = 0;	/* speed is not available in bridge */
+	break;
+    case PCIBR_BRIDGETYPE_PIC:
+        pcibr_soft->bs_min_slot = 0;
+	pcibr_soft->bs_max_slot = 3;
+	pcibr_soft->bs_int_ate_size = XBRIDGE_INTERNAL_ATES;
+	pcibr_soft->bs_bridge_mode = 
+	   (((bridge->p_wid_stat_64 & PIC_STAT_PCIX_SPEED) >> 33) |
+	    ((bridge->p_wid_stat_64 & PIC_STAT_PCIX_ACTIVE) >> 33));
+
+	/* We have to clear PIC's write request buffer to avoid parity
+	 * errors.  See PV#854845.
+	 */
+	{
+	int i;
+
+	for (i=0; i < PIC_WR_REQ_BUFSIZE; i++) {
+		bridge->p_wr_req_lower[i] = 0;
+		bridge->p_wr_req_upper[i] = 0;
+		bridge->p_wr_req_parity[i] = 0;
+	}
+	}
+
+	break;
+    case PCIBR_BRIDGETYPE_XBRIDGE:
+	pcibr_soft->bs_int_ate_size = XBRIDGE_INTERNAL_ATES;
+	pcibr_soft->bs_bridge_mode = 
+	   ((bridge->b_wid_control & BRIDGE_CTRL_PCI_SPEED) >> 3);
+	break;
     }
 
-    nasid = NASID_GET(bridge);
-    scp = &NODEPDA( NASID_TO_COMPACT_NODEID(nasid) )->module->elsc;
-    pcibr_soft->bs_l1sc = scp;
-    pcibr_soft->bs_moduleid = iobrick_module_get(scp);
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, pcibr_vhdl,
+		"pcibr_attach2: pcibr_soft=0x%x, mode=0x%x\n",
+                pcibr_soft, pcibr_soft->bs_bridge_mode));
     pcibr_soft->bsi_err_intr = 0;
 
     /* Bridges up through REV C
@@ -1439,6 +1316,9 @@
 	pcibr_soft->bs_pio_end_mem = PCIIO_WORD_VALUES;
     }
 #if PCIBR_SOFT_LIST
+    /*
+     * link all the pcibr_soft structs
+     */
     {
 	pcibr_list_p            self;
 
@@ -1446,9 +1326,9 @@
 	self->bl_soft = pcibr_soft;
 	self->bl_vhdl = pcibr_vhdl;
 	self->bl_next = pcibr_list;
-	self->bl_next = swap_ptr((void **) &pcibr_list, (void *)self);
+	pcibr_list = self;
     }
-#endif
+#endif /* PCIBR_SOFT_LIST */
 
     /*
      * get the name of this bridge vertex and keep the info. Use this
@@ -1458,45 +1338,114 @@
     pcibr_soft->bs_name = kmalloc(strlen(s) + 1, GFP_KERNEL);
     strcpy(pcibr_soft->bs_name, s);
 
-#if SHOW_REVS || DEBUG
-#if !DEBUG
-    if (kdebug)
-#endif
-	printk("%sBridge ASIC: rev %s (code=0x%x) at %s\n",
-		is_xbridge(bridge) ? "X" : "",
-		(rev == BRIDGE_PART_REV_A) ? "A" :
-		(rev == BRIDGE_PART_REV_B) ? "B" :
-		(rev == BRIDGE_PART_REV_C) ? "C" :
-		(rev == BRIDGE_PART_REV_D) ? "D" :
-		(rev == XBRIDGE_PART_REV_A) ? "A" :
-		(rev == XBRIDGE_PART_REV_B) ? "B" :
-		"unknown",
-		rev, pcibr_soft->bs_name);
-#endif
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, pcibr_vhdl,
+		"pcibr_attach2: %s ASIC: rev %s (code=0x%x)\n",
+		IS_XBRIDGE_SOFT(pcibr_soft) ? "XBridge" :
+			IS_PIC_SOFT(pcibr_soft) ? "PIC" : "Bridge", 
+		(rev == BRIDGE_PART_REV_A) ? "A" : 
+                (rev == BRIDGE_PART_REV_B) ? "B" :
+                (rev == BRIDGE_PART_REV_C) ? "C" :
+                (rev == BRIDGE_PART_REV_D) ? "D" :
+                (rev == XBRIDGE_PART_REV_A) ? "A" :
+                (rev == XBRIDGE_PART_REV_B) ? "B" :
+                (IS_PIC_PART_REV_A(rev)) ? "A" : 
+                "unknown", rev, pcibr_soft->bs_name));
 
     info = xwidget_info_get(xconn_vhdl);
     pcibr_soft->bs_xid = xwidget_info_id_get(info);
     pcibr_soft->bs_master = xwidget_info_master_get(info);
     pcibr_soft->bs_mxid = xwidget_info_masterid_get(info);
 
+    pcibr_soft->bs_first_slot = pcibr_soft->bs_min_slot;
+    pcibr_soft->bs_last_slot = pcibr_soft->bs_max_slot;
     /*
-     * Init bridge lock.
+     * Bridge can only reset slots 0, 1, 2, and 3.  Ibrick internal
+     * slots 4, 5, 6, and 7 must be reset as a group, so do not
+     * reset them.
      */
-    spin_lock_init(&pcibr_soft->bs_lock);
+    pcibr_soft->bs_last_reset = 3;
+
+    nasid = NASID_GET(bridge);
+
+    /* set whether it is a PIC or not */
+    Is_pic_on_this_nasid[nasid] = (IS_PIC_SOFT(pcibr_soft)) ? 1 : 0;
+
+
+    if ((pcibr_soft->bs_bricktype = iobrick_type_get_nasid(nasid)) < 0)
+	printk(KERN_WARNING "0x%p: Unknown bricktype : 0x%x\n", (void *)xconn_vhdl,
+				(unsigned int)pcibr_soft->bs_bricktype);
+
+    pcibr_soft->bs_moduleid = iobrick_module_get_nasid(nasid);
+
+    if (pcibr_soft->bs_bricktype > 0) {
+	switch (pcibr_soft->bs_bricktype) {
+	case MODULE_PXBRICK:
+	    pcibr_soft->bs_first_slot = 0;
+	    pcibr_soft->bs_last_slot = 1;
+	    pcibr_soft->bs_last_reset = 1;
+	    break;
+	case MODULE_PEBRICK:
+	case MODULE_PBRICK:
+            pcibr_soft->bs_first_slot = 1;
+            pcibr_soft->bs_last_slot = 2;
+            pcibr_soft->bs_last_reset = 2;
+            break;
+
+        case MODULE_IBRICK:
+	    /*
+	     * Here's the current baseio layout for SN1 style systems:
+	     *
+	     *    0    1    2    3    4    5    6    7		slot#
+	     *
+	     *    x    scsi x    x    ioc3 usb  x    x  	O300 Ibrick
+	     *
+             * x == never occupied
+             * E == external (add-in) slot
+	     *
+	     */
+            pcibr_soft->bs_first_slot = 1;	/* Ibrick first slot == 1 */
+            if (pcibr_soft->bs_xid == 0xe) { 
+                pcibr_soft->bs_last_slot = 2;
+                pcibr_soft->bs_last_reset = 2;
+            } else {
+		pcibr_soft->bs_last_slot = 6;
+	    }
+            break;
+	default:
+	    break;
+        }
+
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, pcibr_vhdl,
+		    "pcibr_attach2: %cbrick, slots %d-%d\n",
+		    MODULE_GET_BTCHAR(pcibr_soft->bs_moduleid),
+		    pcibr_soft->bs_first_slot, pcibr_soft->bs_last_slot));
+    }
 
     /*
+     * Initialize bridge and bus locks
+     */
+    spin_lock_init(&pcibr_soft->bs_lock);
+#ifdef PIC_LATER
+    mrinit(pcibr_soft->bs_bus_lock, "bus_lock");
+#endif
+    /*
      * If we have one, process the hints structure.
      */
     if (pcibr_hints) {
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, pcibr_vhdl,
+                    "pcibr_attach2: pcibr_hints=0x%x\n", pcibr_hints));
+
 	rrb_fixed = pcibr_hints->ph_rrb_fixed;
 
 	pcibr_soft->bs_rrb_fixed = rrb_fixed;
 
-	if (pcibr_hints->ph_intr_bits)
+	if (pcibr_hints->ph_intr_bits) {
 	    pcibr_soft->bs_intr_bits = pcibr_hints->ph_intr_bits;
+	}
 
-	for (slot = 0; slot < 8; ++slot) {
-	    int                     hslot = pcibr_hints->ph_host_slot[slot] - 1;
+	for (slot = pcibr_soft->bs_min_slot; 
+				slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) {
+	    int hslot = pcibr_hints->ph_host_slot[slot] - 1;
 
 	    if (hslot < 0) {
 		pcibr_soft->bs_slot[slot].host_slot = slot;
@@ -1507,13 +1456,16 @@
 	}
     }
     /*
-     * set up initial values for state fields
+     * Set-up initial values for state fields
      */
-    for (slot = 0; slot < 8; ++slot) {
+    for (slot = pcibr_soft->bs_min_slot; 
+				slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) {
 	pcibr_soft->bs_slot[slot].bss_devio.bssd_space = PCIIO_SPACE_NONE;
+	pcibr_soft->bs_slot[slot].bss_devio.bssd_ref_cnt = 0;
 	pcibr_soft->bs_slot[slot].bss_d64_base = PCIBR_D64_BASE_UNSET;
 	pcibr_soft->bs_slot[slot].bss_d32_base = PCIBR_D32_BASE_UNSET;
 	pcibr_soft->bs_slot[slot].bss_ext_ates_active = ATOMIC_INIT(0);
+	pcibr_soft->bs_rrb_valid_dflt[slot][VCHAN0] = -1;
     }
 
     for (ibit = 0; ibit < 8; ++ibit) {
@@ -1522,15 +1474,31 @@
 	pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_list = NULL;
 	pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_stat = 
 							&(bridge->b_int_status);
+	pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_ibit = ibit;
 	pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_hdlrcnt = 0;
 	pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_shared = 0;
 	pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_connected = 0;
     }
 
     /*
+     * connect up our error handler.  PIC has 2 busses (thus resulting in 2
+     * pcibr_soft structs under 1 widget), so only register a xwidget error
+     * handler for PIC's bus0.  NOTE: for PIC pcibr_error_handler_wrapper()
+     * is a wrapper routine we register that will call the real error handler
+     * pcibr_error_handler() with the correct pcibr_soft struct.
+     */
+    if (IS_PIC_SOFT(pcibr_soft)) {
+	if (busnum == 0) {
+	    xwidget_error_register(xconn_vhdl, pcibr_error_handler_wrapper, pcibr_soft);
+	}
+    } else {
+	xwidget_error_register(xconn_vhdl, pcibr_error_handler, pcibr_soft);
+    }
+
+    /*
      * Initialize various Bridge registers.
      */
-
+  
     /*
      * On pre-Rev.D bridges, set the PCI_RETRY_CNT
      * to zero to avoid dropping stores. (#475347)
@@ -1543,12 +1511,43 @@
      */
     bridge->b_int_rst_stat = (BRIDGE_IRR_ALL_CLR);
 
+    /* Initialize some PIC specific registers. */
+    if (IS_PIC_SOFT(pcibr_soft)) {
+	picreg_t pic_ctrl_reg = bridge->p_wid_control_64;
+
+	/* Bridges Requester ID: bus = busnum, dev = 0, func = 0 */
+	pic_ctrl_reg &= ~PIC_CTRL_BUS_NUM_MASK;
+	pic_ctrl_reg |= PIC_CTRL_BUS_NUM(busnum);
+	pic_ctrl_reg &= ~PIC_CTRL_DEV_NUM_MASK;
+	pic_ctrl_reg &= ~PIC_CTRL_FUN_NUM_MASK;
+
+	pic_ctrl_reg &= ~PIC_CTRL_NO_SNOOP;
+	pic_ctrl_reg &= ~PIC_CTRL_RELAX_ORDER;
+
+	/* enable parity checking on PICs internal RAM */
+	pic_ctrl_reg |= PIC_CTRL_PAR_EN_RESP;
+	pic_ctrl_reg |= PIC_CTRL_PAR_EN_ATE;
+	/* PIC BRINGUP WAR (PV# 862253): dont enable write request
+	 * parity checking.
+	 */
+	if (!PCIBR_WAR_ENABLED(PV862253, pcibr_soft)) {
+	    pic_ctrl_reg |= PIC_CTRL_PAR_EN_REQ;
+	}
+
+	bridge->p_wid_control_64 = pic_ctrl_reg;
+    }
+
     /*
      * Until otherwise set up,
      * assume all interrupts are
-     * from slot 7.
+     * from slot 7(Bridge/Xbridge) or 3(PIC).
+     * XXX. Not sure why we're doing this, made change for PIC
+     * just to avoid setting reserved bits.
      */
-    bridge->b_int_device = (uint32_t) 0xffffffff;
+    if (IS_PIC_SOFT(pcibr_soft))
+	bridge->b_int_device = (uint32_t) 0x006db6db;
+    else
+	bridge->b_int_device = (uint32_t) 0xffffffff;
 
     {
 	bridgereg_t             dirmap;
@@ -1560,6 +1559,11 @@
 	int                     entry;
 	cnodeid_t		cnodeid;
 	nasid_t			nasid;
+#ifdef PIC_LATER
+	char		       *node_val;
+	devfs_handle_t		node_vhdl;
+	char			vname[MAXDEVNAME];
+#endif
 
 	/* Set the Bridge's 32-bit PCI to XTalk
 	 * Direct Map register to the most useful
@@ -1578,6 +1582,30 @@
 	 */
 
 	cnodeid = 0;  /* default node id */
+	/*
+	 * Determine the base address node id to be used for all 32-bit
+	 * Direct Mapping I/O. The default is node 0, but this can be changed
+	 * via a DEVICE_ADMIN directive and the PCIBUS_DMATRANS_NODE
+	 * attribute in the irix.sm config file. A device driver can obtain
+	 * this node value via a call to pcibr_get_dmatrans_node().
+	 */
+#ifdef PIC_LATER
+// This probably needs to be addressed - pfg
+	node_val = device_admin_info_get(pcibr_vhdl, ADMIN_LBL_DMATRANS_NODE);
+	if (node_val != NULL) {
+	    node_vhdl = hwgraph_path_to_vertex(node_val);
+	    if (node_vhdl != GRAPH_VERTEX_NONE) {
+		cnodeid = nodevertex_to_cnodeid(node_vhdl);
+	    }
+	    if ((node_vhdl == GRAPH_VERTEX_NONE) || (cnodeid == CNODEID_NONE)) {
+		cnodeid = 0;
+		vertex_to_name(pcibr_vhdl, vname, sizeof(vname));
+		printk(KERN_WARNING "Invalid hwgraph node path specified:\n"
+			"    DEVICE_ADMIN: %s %s=%s\n",
+			vname, ADMIN_LBL_DMATRANS_NODE, node_val);
+	    }
+	}
+#endif	/* PIC_LATER */
 	nasid = COMPACT_TO_NASID_NODEID(cnodeid);
 	paddr = NODE_OFFSET(nasid) + 0;
 
@@ -1619,9 +1647,17 @@
 	 */
 	spl_level = splhi();
 #if IOPGSIZE == 4096
-	bridge->b_wid_control &= ~BRIDGE_CTRL_PAGE_SIZE;
+        if (IS_PIC_SOFT(pcibr_soft)) {
+            bridge->p_wid_control_64 &= ~BRIDGE_CTRL_PAGE_SIZE;
+        } else {
+            bridge->b_wid_control &= ~BRIDGE_CTRL_PAGE_SIZE;
+        }
 #elif IOPGSIZE == 16384
-	bridge->b_wid_control |= BRIDGE_CTRL_PAGE_SIZE;
+        if (IS_PIC_SOFT(pcibr_soft)) {
+            bridge->p_wid_control_64 |= BRIDGE_CTRL_PAGE_SIZE;
+        } else {
+            bridge->b_wid_control |= BRIDGE_CTRL_PAGE_SIZE;
+        }
 #else
 	<<<Unable to deal with IOPGSIZE >>>;
 #endif
@@ -1652,7 +1688,8 @@
 	 * recomparing against BRIDGE_INTERNAL_ATES every
 	 * time.
 	 */
-	if (is_xbridge(bridge))
+
+	if (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft))
 		num_entries = 0;
 	else
 		num_entries = pcibr_init_ext_ate_ram(bridge);
@@ -1662,9 +1699,6 @@
 	 */
 	pcibr_soft->bs_int_ate_map = rmallocmap(pcibr_soft->bs_int_ate_size);
 	pcibr_ate_free(pcibr_soft, 0, pcibr_soft->bs_int_ate_size);
-#if PCIBR_ATE_DEBUG
-	printk("pcibr_attach: %d INTERNAL ATEs\n", pcibr_soft->bs_int_ate_size);
-#endif
 
 	if (num_entries > pcibr_soft->bs_int_ate_size) {
 #if PCIBR_ATE_NOTBOTH			/* for debug -- forces us to use external ates */
@@ -1674,11 +1708,12 @@
 	    pcibr_soft->bs_ext_ate_map = rmallocmap(num_entries);
 	    pcibr_ate_free(pcibr_soft, pcibr_soft->bs_int_ate_size,
 			   num_entries - pcibr_soft->bs_int_ate_size);
-#if PCIBR_ATE_DEBUG
-	    printk("pcibr_attach: %d EXTERNAL ATEs\n",
-		    num_entries - pcibr_soft->bs_int_ate_size);
-#endif
 	}
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATE, pcibr_vhdl,
+		    "pcibr_attach2: %d ATEs, %d internal & %d external\n",
+		    num_entries ? num_entries : pcibr_soft->bs_int_ate_size,
+		    pcibr_soft->bs_int_ate_size,
+		    num_entries ? num_entries-pcibr_soft->bs_int_ate_size : 0));
     }
 
     {
@@ -1727,7 +1762,7 @@
      * knows to do this.
      */
 
-    xtalk_intr = xtalk_intr_alloc(xconn_vhdl, dev_desc, pcibr_vhdl);
+    xtalk_intr = xtalk_intr_alloc(xconn_vhdl, (device_desc_t)0, pcibr_vhdl);
     ASSERT(xtalk_intr != NULL);
 
     pcibr_soft->bsi_err_intr = xtalk_intr;
@@ -1740,17 +1775,124 @@
      */
     pcibr_clearwidint(bridge);
 
-    xtalk_intr_connect(xtalk_intr, (xtalk_intr_setfunc_t)pcibr_setwidint, (void *)bridge);
+    xtalk_intr_connect(xtalk_intr, (intr_func_t) pcibr_error_intr_handler,
+		(intr_arg_t) pcibr_soft, (xtalk_intr_setfunc_t)pcibr_setwidint, (void *)bridge);
+
+#ifdef BUS_INT_WAR_NOT_YET
+    request_irq(CPU_VECTOR_TO_IRQ(((hub_intr_t)xtalk_intr)->i_cpuid,
+			((hub_intr_t)xtalk_intr)->i_bit),
+				(intr_func_t)pcibr_error_intr_handler, 0, "PCIBR error",
+					(intr_arg_t) pcibr_soft);
+#endif
+
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_vhdl,
+		"pcibr_setwidint: b_wid_int_upper=0x%x, b_wid_int_lower=0x%x\n",
+		bridge->b_wid_int_upper, bridge->b_wid_int_lower));
 
     /*
      * now we can start handling error interrupts;
      * enable all of them.
      * NOTE: some PCI ints may already be enabled.
      */
-    b_int_enable = bridge->b_int_enable | BRIDGE_ISR_ERRORS;
+    /* We read the INT_ENABLE register as a 64bit picreg_t for PIC and a
+     * 32bit bridgereg_t for BRIDGE, but always process the result as a
+     * 64bit value so the code can be "common" for both PIC and BRIDGE...
+     */
+    if (IS_PIC_SOFT(pcibr_soft)) {
+	int_enable_64 = bridge->p_int_enable_64 | BRIDGE_ISR_ERRORS;
+        int_enable = (uint64_t)int_enable_64;
+    } else {
+	int_enable_32 = bridge->b_int_enable | (BRIDGE_ISR_ERRORS & 0xffffffff);
+	int_enable = ((uint64_t)int_enable_32 & 0xffffffff);
+    }
+#ifdef BUS_INT_WAR_NOT_YET
+    {
+	extern void sn_add_polled_interrupt(int irq, int interval);
+
+        sn_add_polled_interrupt(CPU_VECTOR_TO_IRQ(((hub_intr_t)xtalk_intr)->i_cpuid,
+				((hub_intr_t)xtalk_intr)->i_bit), 20000);
+    }
+#endif
+
+
+#if BRIDGE_ERROR_INTR_WAR
+    if (pcibr_soft->bs_rev_num == BRIDGE_PART_REV_A) {
+	/*
+	 * We commonly get master timeouts when talking to ql.
+	 * We also see RESP_XTALK_ERROR and LLP_TX_RETRY interrupts.
+	 * Insure that these are all disabled for now.
+	 */
+	int_enable &= ~(BRIDGE_IMR_PCI_MST_TIMEOUT |
+			BRIDGE_ISR_RESP_XTLK_ERR |
+			BRIDGE_ISR_LLP_TX_RETRY);
+    }
+    if (pcibr_soft->bs_rev_num < BRIDGE_PART_REV_C) {
+	int_enable &= ~BRIDGE_ISR_BAD_XRESP_PKT;
+    }
+#endif				/* BRIDGE_ERROR_INTR_WAR */
+
+#ifdef QL_SCSI_CTRL_WAR			/* for IP30 only */
+    /* Really a QL rev A issue, but all newer hearts have newer QLs.
+     * Forces all IO6/MSCSI to be new.
+     */
+    if (heart_rev() == HEART_REV_A)
+	int_enable &= ~BRIDGE_IMR_PCI_MST_TIMEOUT;
+#endif
+
+#ifdef BRIDGE1_TIMEOUT_WAR
+    if (pcibr_soft->bs_rev_num == BRIDGE_PART_REV_A) {
+	/*
+	 * Turn off these interrupts.  They can't be trusted in bridge 1
+	 */
+	int_enable &= ~(BRIDGE_IMR_XREAD_REQ_TIMEOUT |
+			BRIDGE_IMR_UNEXP_RESP);
+    }
+#endif
+
+#ifdef BRIDGE_B_DATACORR_WAR
+
+    /* WAR panic for Rev B silent data corruption.
+     * PIOERR turned off here because there is a problem
+     * with not re-arming it in pcibr_error_intr_handler.
+     * We don't get LLP error interrupts if we don't
+     * re-arm PIOERR interrupts! Just disable them here
+     */
 
+    if (pcibr_soft->bs_rev_num == BRIDGE_PART_REV_B) {
+	int_enable |= BRIDGE_IMR_LLP_REC_CBERR;
+	int_enable &= ~BRIDGE_ISR_PCIBUS_PIOERR;
 
-    bridge->b_int_enable = b_int_enable;
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, pcibr_vhdl,
+		    "Turning on LLP_REC_CBERR for Rev B Bridge.\n"));
+    }
+#endif
+
+    /* PIC BRINGUP WAR (PV# 856864 & 856865): allow the tnums that are
+     * locked out to be freed up sooner (by timing out) so that the
+     * read tnums are never completely used up.
+     */
+    if (IS_PIC_SOFT(pcibr_soft) && PCIBR_WAR_ENABLED(PV856864, pcibr_soft)) {
+        int_enable &= ~PIC_ISR_PCIX_REQ_TOUT;
+        int_enable &= ~BRIDGE_ISR_XREAD_REQ_TIMEOUT;
+
+        bridge->b_wid_req_timeout = 0x750;
+    }
+
+    /*
+     * PIC BRINGUP WAR (PV# 856866, 859504, 861476, 861478): Don't use
+     * RRB0, RRB8, RRB1, and RRB9.  Assign them to DEVICE[2|3]--VCHAN3
+     * so they are not used
+     */
+    if (IS_PIC_SOFT(pcibr_soft) && PCIBR_WAR_ENABLED(PV856866, pcibr_soft)) {
+        bridge->b_even_resp |= 0x000f000f;
+        bridge->b_odd_resp |= 0x000f000f;
+    }
+
+    if (IS_PIC_SOFT(pcibr_soft)) {
+        bridge->p_int_enable_64 = (picreg_t)int_enable;
+    } else {
+        bridge->b_int_enable = (bridgereg_t)int_enable;
+    }
     bridge->b_int_mode = 0;		/* do not send "clear interrupt" packets */
 
     bridge->b_wid_tflush;		/* wait until Bridge PIO complete */
@@ -1788,20 +1930,59 @@
 		(BRIDGE_WIDGET_PART_NUM << 4 | pcibr_wg_enable_rev))
 	pcibr_soft->bs_dma_flags |= PCIBR_NOWRITE_GATHER;
 
-    pciio_provider_register(pcibr_vhdl, &pcibr_provider);
-    pciio_provider_startup(pcibr_vhdl);
-
-    pci_io_fb = 0x00000004;		/* I/O FreeBlock Base */
-    pci_io_fl = 0xFFFFFFFF;		/* I/O FreeBlock Last */
-
-    pci_lo_fb = 0x00000010;		/* Low Memory FreeBlock Base */
-    pci_lo_fl = 0x001FFFFF;		/* Low Memory FreeBlock Last */
+    /* PIC only supports 64-bit direct mapping in PCI-X mode.  Since
+     * all PCI-X devices that initiate memory transactions must be
+     * capable of generating 64-bit addressed, we force 64-bit DMAs.
+     */
+    if (IS_PCIX(pcibr_soft)) {
+	pcibr_soft->bs_dma_flags |= PCIIO_DMA_A64;
+    }
 
-    pci_hi_fb = 0x00200000;		/* High Memory FreeBlock Base */
-    pci_hi_fl = 0x3FFFFFFF;		/* High Memory FreeBlock Last */
+    {
 
+    pciio_win_map_t         win_map_p;
+    iopaddr_t               prom_base_addr = pcibr_soft->bs_xid << 24;
+    int                     prom_base_size = 0x1000000;
+    iopaddr_t               prom_base_limit = prom_base_addr + prom_base_size; 
+
+    /* Allocate resource maps based on bus page size; for I/O and memory
+     * space, free all pages except those in the base area and in the
+     * range set by the PROM. 
+     *
+     * PROM creates BAR addresses in this format: 0x0ws00000 where w is
+     * the widget number and s is the device register offset for the slot.
+     */
 
-    PCI_ADDR_SPACE_LIMITS_STORE();
+    win_map_p = &pcibr_soft->bs_io_win_map;
+    pciio_device_win_map_new(win_map_p,
+			     PCIBR_BUS_IO_MAX + 1,
+			     PCIBR_BUS_IO_PAGE);
+    pciio_device_win_populate(win_map_p,
+			      PCIBR_BUS_IO_BASE,
+			      prom_base_addr - PCIBR_BUS_IO_BASE);
+    pciio_device_win_populate(win_map_p,
+			      prom_base_limit,
+			      (PCIBR_BUS_IO_MAX + 1) - prom_base_limit);
+
+    win_map_p = &pcibr_soft->bs_swin_map;
+    pciio_device_win_map_new(win_map_p,
+			     PCIBR_BUS_SWIN_MAX + 1,
+			     PCIBR_BUS_SWIN_PAGE);
+    pciio_device_win_populate(win_map_p,
+			      PCIBR_BUS_SWIN_BASE,
+			      (PCIBR_BUS_SWIN_MAX + 1) - PCIBR_BUS_SWIN_PAGE);
+
+    win_map_p = &pcibr_soft->bs_mem_win_map;
+    pciio_device_win_map_new(win_map_p,
+			     PCIBR_BUS_MEM_MAX + 1,
+			     PCIBR_BUS_MEM_PAGE);
+    pciio_device_win_populate(win_map_p,
+			      PCIBR_BUS_MEM_BASE,
+			      prom_base_addr - PCIBR_BUS_MEM_BASE);
+    pciio_device_win_populate(win_map_p,
+			      prom_base_limit,
+			      (PCIBR_BUS_MEM_MAX + 1) - prom_base_limit);
+    }
 
     /* build "no-slot" connection point
      */
@@ -1830,59 +2011,91 @@
     }
 #endif
 
-#ifdef LATER
-    /* If the bridge has been reset then there is no need to reset
-     * the individual PCI slots.
-     */
-    for (slot = 0; slot < 8; ++slot)  
-	/* Reset all the slots */
-	(void)pcibr_slot_reset(pcibr_vhdl, slot);
-#endif
-
-    for (slot = 0; slot < 8; ++slot)
+    for (slot = pcibr_soft->bs_min_slot; 
+				slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) {
 	/* Find out what is out there */
 	(void)pcibr_slot_info_init(pcibr_vhdl,slot);
+    }
+    for (slot = pcibr_soft->bs_min_slot; 
+				slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot)
+	/* Set up the address space for this slot in the PCI land */
+	(void)pcibr_slot_addr_space_init(pcibr_vhdl, slot);
 
-    for (slot = 0; slot < 8; ++slot)  
-	/* Set up the address space for this slot in the pci land */
-	(void)pcibr_slot_addr_space_init(pcibr_vhdl,slot);
-
-    for (slot = 0; slot < 8; ++slot)  
+    for (slot = pcibr_soft->bs_min_slot; 
+				slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot)
 	/* Setup the device register */
 	(void)pcibr_slot_device_init(pcibr_vhdl, slot);
 
-    for (slot = 0; slot < 8; ++slot)  
-	/* Setup host/guest relations */
-	(void)pcibr_slot_guest_info_init(pcibr_vhdl,slot);
-
-    for (slot = 0; slot < 8; ++slot)  
-	/* Initial RRB management */
-	(void)pcibr_slot_initial_rrb_alloc(pcibr_vhdl,slot);
+    if (IS_PCIX(pcibr_soft)) {
+        pcibr_soft->bs_pcix_rbar_inuse = 0;
+        pcibr_soft->bs_pcix_rbar_avail = NUM_RBAR;
+	pcibr_soft->bs_pcix_rbar_percent_allowed = 
+					pcibr_pcix_rbars_calc(pcibr_soft);
+
+	for (slot = pcibr_soft->bs_min_slot; 
+				slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot)
+	    /* Setup the PCI-X Read Buffer Attribute Registers (RBARs) */
+	    (void)pcibr_slot_pcix_rbar_init(pcibr_soft, slot);
+    }
+
+    /* Set up convenience links */
+    if (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft))
+	pcibr_bus_cnvlink(pcibr_soft->bs_vhdl);
 
-    /* driver attach routines should be called out from generic linux code */
-    for (slot = 0; slot < 8; ++slot)  
-	/* Call the device attach */
-	(void)pcibr_slot_call_device_attach(pcibr_vhdl, slot, 0);
+    for (slot = pcibr_soft->bs_min_slot; 
+				slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot)
+	/* Setup host/guest relations */
+	(void)pcibr_slot_guest_info_init(pcibr_vhdl, slot);
 
+    /* Handle initial RRB management for Bridge and Xbridge */
+    pcibr_initial_rrb(pcibr_vhdl, 
+                      pcibr_soft->bs_first_slot, pcibr_soft->bs_last_slot);
+    
+{  /* Before any drivers get called that may want to re-allocate
+    * RRB's, let's get some special cases pre-allocated. Drivers
+    * may override these pre-allocations, but by doing pre-allocations
+    * now we're assured not to step all over what the driver intended.
+    *
+    * Note: Someday this should probably be moved over to pcibr_rrb.c
+    */
     /*
      * Each Pbrick PCI bus only has slots 1 and 2.   Similarly for
      * widget 0xe on Ibricks.  Allocate RRB's accordingly.
      */
-    if (pcibr_soft->bs_moduleid > 0) {
-	switch (MODULE_GET_BTCHAR(pcibr_soft->bs_moduleid)) {
-	case 'p':		/* Pbrick */
-		do_pcibr_rrb_autoalloc(pcibr_soft, 1, 8);
-		do_pcibr_rrb_autoalloc(pcibr_soft, 2, 8);
+    if (pcibr_soft->bs_bricktype > 0) {
+	switch (pcibr_soft->bs_bricktype) {
+	case MODULE_PXBRICK:
+		/* 
+		 * If the IO9 is in the PXBrick (bus1, slot1) allocate
+                 * RRBs to all the devices
+		 */
+		if ((pcibr_widget_to_bus(pcibr_vhdl) == 1) &&
+		    (pcibr_soft->bs_slot[0].bss_vendor_id == 0x10A9) &&
+		    (pcibr_soft->bs_slot[0].bss_device_id == 0x100A)) {
+			do_pcibr_rrb_autoalloc(pcibr_soft, 0, VCHAN0, 4);
+			do_pcibr_rrb_autoalloc(pcibr_soft, 1, VCHAN0, 4);
+			do_pcibr_rrb_autoalloc(pcibr_soft, 2, VCHAN0, 4);
+			do_pcibr_rrb_autoalloc(pcibr_soft, 3, VCHAN0, 4);
+		} else {
+			do_pcibr_rrb_autoalloc(pcibr_soft, 0, VCHAN0, 8);
+			do_pcibr_rrb_autoalloc(pcibr_soft, 1, VCHAN0, 8);
+		}
+
+		break;
+	case MODULE_PEBRICK:
+	case MODULE_PBRICK:
+		do_pcibr_rrb_autoalloc(pcibr_soft, 1, VCHAN0, 8);
+		do_pcibr_rrb_autoalloc(pcibr_soft, 2, VCHAN0, 8);
 		break;
-	case 'i':		/* Ibrick */
+	case MODULE_IBRICK:
 	  	/* port 0xe on the Ibrick only has slots 1 and 2 */
 		if (pcibr_soft->bs_xid == 0xe) {
-			do_pcibr_rrb_autoalloc(pcibr_soft, 1, 8);
-			do_pcibr_rrb_autoalloc(pcibr_soft, 2, 8);
+			do_pcibr_rrb_autoalloc(pcibr_soft, 1, VCHAN0, 8);
+			do_pcibr_rrb_autoalloc(pcibr_soft, 2, VCHAN0, 8);
 		}
 		else {
 		    	/* allocate one RRB for the serial port */
-			do_pcibr_rrb_autoalloc(pcibr_soft, 0, 1);
+			do_pcibr_rrb_autoalloc(pcibr_soft, 0, VCHAN0, 1);
 		}
 		break;
 	} /* switch */
@@ -1890,33 +2103,80 @@
 
 #ifdef LATER
     if (strstr(nicinfo, XTALK_PCI_PART_NUM)) {
-	do_pcibr_rrb_autoalloc(pcibr_soft, 1, 8);
-#if PCIBR_RRB_DEBUG
-	printf("\n\nFound XTALK_PCI (030-1275) at %v\n", xconn_vhdl);
-
-	printf("pcibr_attach: %v Shoebox RRB MANAGEMENT: %d+%d free\n",
-		pcibr_vhdl,
-		pcibr_soft->bs_rrb_avail[0],
-		pcibr_soft->bs_rrb_avail[1]);
-
-	for (slot = 0; slot < 8; ++slot)
-	    printf("\t%d+%d+%d",
-	    0xFFF & pcibr_soft->bs_rrb_valid[slot],
-	    0xFFF & pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL],
-	    pcibr_soft->bs_rrb_res[slot]);
-
-	printf("\n");
+	do_pcibr_rrb_autoalloc(pcibr_soft, 1, VCHAN0, 8);
+    }
 #endif
+}  /* OK Special RRB allocations are done. */
+
+    for (slot = pcibr_soft->bs_min_slot; 
+				slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot)
+	/* Call the device attach */
+	(void)pcibr_slot_call_device_attach(pcibr_vhdl, slot, 0);
+
+#ifdef PIC_LATER
+#if (defined(USS302_TIMEOUT_WAR))
+    /*
+     * If this bridge holds a Lucent USS-302 or USS-312 pci/usb controller,
+     * increase the Bridge PCI retry backoff interval.  This part seems
+     * to go away for long periods of time if a DAC appears on the bus during
+     * a read command that is being retried.
+     */
+
+{
+    ii_ixtt_u_t ixtt;
+
+    for (slot = pcibr_soft->bs_min_slot; 
+				slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) {
+	if (pcibr_soft->bs_slot[slot].bss_vendor_id ==
+					LUCENT_USBHC_VENDOR_ID_NUM &&
+	    (pcibr_soft->bs_slot[slot].bss_device_id ==
+					LUCENT_USBHC302_DEVICE_ID_NUM ||
+	     pcibr_soft->bs_slot[slot].bss_device_id ==
+					LUCENT_USBHC312_DEVICE_ID_NUM)) {
+	    printk(KERN_NOTICE
+		    "pcibr_attach: %x Bus holds a usb part - setting"
+		    "bridge PCI_RETRY_HLD to %d\n",
+		    pcibr_vhdl, USS302_BRIDGE_TIMEOUT_HLD);
+
+	    bridge->b_bus_timeout &= ~BRIDGE_BUS_PCI_RETRY_HLD_MASK;
+	    bridge->b_bus_timeout |=
+			BRIDGE_BUS_PCI_RETRY_HLD(USS302_BRIDGE_TIMEOUT_HLD);
+
+	    /*
+	     * Have to consider the read response timer in the hub II as well
+	     */
+
+	    hubii_ixtt_get(xconn_vhdl, &ixtt);
+
+	    /*
+	     * bump rrsp_ps to allow at least 1ms for read
+ 	     * responses from this widget
+	     */
+
+	    ixtt.ii_ixtt_fld_s.i_rrsp_ps = 20000;
+	    hubii_ixtt_set(xconn_vhdl, &ixtt);
+
+	    /*
+	     * print the current setting
+	     */
+
+	    hubii_ixtt_get(xconn_vhdl, &ixtt);
+	    printk( "Setting hub ixtt.rrsp_ps field to 0x%x\n",
+		    ixtt.ii_ixtt_fld_s.i_rrsp_ps);
+
+	    break;	/* only need to do it once */
+	}
     }
+}
+#endif	/* (defined(USS302_TIMEOUT_WAR)) */
 #else
 	FIXME("pcibr_attach: Call do_pcibr_rrb_autoalloc nicinfo\n");
-#endif
+#endif	/* PIC_LATER */
 
     if (aa)
 	    async_attach_add_info(noslot_conn, aa);
 
-    pciio_device_attach(noslot_conn, 0);
-
+    pciio_device_attach(noslot_conn, (int)0);
 
     /* 
      * Tear down pointer to async attach info -- async threads for
@@ -1927,11 +2187,13 @@
 
     return 0;
 }
+
 /*
  * pcibr_detach:
  *	Detach the bridge device from the hwgraph after cleaning out all the 
  *	underlying vertices.
  */
+
 int
 pcibr_detach(devfs_handle_t xconn)
 {
@@ -1939,6 +2201,9 @@
     devfs_handle_t	pcibr_vhdl;
     pcibr_soft_t	pcibr_soft;
     bridge_t		*bridge;
+    unsigned             s;
+
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DETACH, xconn, "pcibr_detach\n"));
 
     /* Get the bridge vertex from its xtalk connection point */
     if (hwgraph_traverse(xconn, EDGE_LBL_PCI, &pcibr_vhdl) != GRAPH_SUCCESS)
@@ -1947,16 +2212,20 @@
     pcibr_soft = pcibr_soft_get(pcibr_vhdl);
     bridge = pcibr_soft->bs_base;
 
+
+    s = pcibr_lock(pcibr_soft);
     /* Disable the interrupts from the bridge */
-    bridge->b_int_enable = 0;
+    if (IS_PIC_SOFT(pcibr_soft)) {
+	bridge->p_int_enable_64 = 0;
+    } else {
+	bridge->b_int_enable = 0;
+    }
+    pcibr_unlock(pcibr_soft, s);
 
     /* Detach all the PCI devices talking to this bridge */
-    for(slot = 0; slot < 8; slot++) {
-#ifdef DEBUG
-	printk("pcibr_device_detach called for %p/%d\n",
-		pcibr_vhdl,slot);
-#endif
-	pcibr_slot_detach(pcibr_vhdl, slot, 0);
+    for (slot = pcibr_soft->bs_min_slot; 
+				slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) {
+	pcibr_slot_detach(pcibr_vhdl, slot, 0, (char *)NULL, (int *)NULL);
     }
 
     /* Unregister the no-slot connection point */
@@ -1998,17 +2267,29 @@
 int
 pcibr_asic_rev(devfs_handle_t pconn_vhdl)
 {
-    devfs_handle_t            pcibr_vhdl;
+    devfs_handle_t          pcibr_vhdl;
+    int                     tmp_vhdl;
     arbitrary_info_t        ainfo;
 
     if (GRAPH_SUCCESS !=
 	hwgraph_traverse(pconn_vhdl, EDGE_LBL_MASTER, &pcibr_vhdl))
 	return -1;
 
-    if (GRAPH_SUCCESS !=
-	hwgraph_info_get_LBL(pcibr_vhdl, INFO_LBL_PCIBR_ASIC_REV, &ainfo))
-	return -1;
+    tmp_vhdl = hwgraph_info_get_LBL(pcibr_vhdl, INFO_LBL_PCIBR_ASIC_REV, &ainfo);
+
+    /*
+     * Any hwgraph function that returns a vertex handle will implicity
+     * increment that vertex's reference count.  The caller must explicity
+     * decrement the vertex's referece count after the last reference to
+     * that vertex.
+     *
+     * Decrement reference count incremented by call to hwgraph_traverse().
+     *
+     */
+    hwgraph_vertex_unref(pcibr_vhdl);
 
+    if (tmp_vhdl != GRAPH_SUCCESS) 
+	return -1;
     return (int) ainfo;
 }
 
@@ -2018,7 +2299,7 @@
     pciio_info_t  pciio_info = pciio_info_get(pconn_vhdl);
     pcibr_soft_t  pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);
     pciio_slot_t  slot;
-    slot = pciio_info_slot_get(pciio_info);
+    slot = PCIBR_INFO_SLOT_GET_INT(pciio_info);
     pcibr_device_write_gather_flush(pcibr_soft, slot);
     return 0;
 }
@@ -2048,11 +2329,13 @@
     size_t                  wsize;	/* size of device decode on PCI */
 
     int                     try;	/* DevIO(x) window scanning order control */
+    int			    maxtry, halftry;
     int                     win;	/* which DevIO(x) window is being used */
     pciio_space_t           mspace;	/* target space for devio(x) register */
     iopaddr_t               mbase;	/* base of devio(x) mapped area on PCI */
     size_t                  msize;	/* size of devio(x) mapped area on PCI */
     size_t                  mmask;	/* addr bits stored in Device(x) */
+    char		    tmp_str[512];
 
     unsigned long           s;
 
@@ -2061,6 +2344,17 @@
     if (pcibr_soft->bs_slot[slot].has_host) {
 	slot = pcibr_soft->bs_slot[slot].host_slot;
 	pcibr_info = pcibr_soft->bs_slot[slot].bss_infos[0];
+
+	/*
+	 * Special case for dual-slot pci devices such as ioc3 on IP27
+	 * baseio.  In these cases, pconn_vhdl should never be for a pci
+	 * function on a subordiate PCI bus, so we can safely reset pciio_info
+	 * to be the info struct embedded in pcibr_info.  Failure to do this
+	 * results in using a bogus pciio_info_t for calculations done later
+	 * in this routine.
+	 */
+
+	pciio_info = &pcibr_info->f_c;
     }
     if (space == PCIIO_SPACE_NONE)
 	goto done;
@@ -2080,7 +2374,7 @@
 	 */
 	if (((flags & PCIIO_BYTE_STREAM) == 0) &&
 	    ((pci_addr + req_size) <= BRIDGE_TYPE0_CFG_FUNC_OFF))
-	    xio_addr = pci_addr + BRIDGE_TYPE0_CFG_DEV(slot);
+	    xio_addr = pci_addr + PCIBR_TYPE0_CFG_DEV(pcibr_soft, slot);
 
 	goto done;
     }
@@ -2090,8 +2384,8 @@
 	 * enabling and disabling
 	 * decodes properly.
 	 */
-	wbase = pcibr_info->f_rbase;
-	wsize = pcibr_info->f_rsize;
+	wbase = pciio_info->c_rbase;
+	wsize = pciio_info->c_rsize;
 
 	/*
 	 * While the driver should know better
@@ -2113,13 +2407,13 @@
      */
     bar = space - PCIIO_SPACE_WIN0;
     if (bar < 6) {
-	wspace = pcibr_info->f_window[bar].w_space;
+	wspace = pciio_info->c_window[bar].w_space;
 	if (wspace == PCIIO_SPACE_NONE)
 	    goto done;
 
 	/* get PCI base and size */
-	wbase = pcibr_info->f_window[bar].w_base;
-	wsize = pcibr_info->f_window[bar].w_size;
+	wbase = pciio_info->c_window[bar].w_base;
+	wsize = pciio_info->c_window[bar].w_size;
 
 	/*
 	 * While the driver should know better
@@ -2147,11 +2441,15 @@
      * We will not attempt to satisfy a single request
      * by concatinating multiple windows.
      */
-    for (try = 0; try < 16; ++try) {
+    maxtry = PCIBR_NUM_SLOTS(pcibr_soft) * 2;
+    halftry = PCIBR_NUM_SLOTS(pcibr_soft) - 1;
+    for (try = 0; try < maxtry; ++try) {
 	bridgereg_t             devreg;
 	unsigned                offset;
 
-	win = (try + slot) % 8;
+	/* calculate win based on slot, attempt, and max possible
+	   devices on bus */
+	win = (try + slot) % PCIBR_NUM_SLOTS(pcibr_soft);
 
 	/* If this DevIO(x) mapping area can provide
 	 * a mapping to this address, use it.
@@ -2176,7 +2474,7 @@
 	 * (only check this the second time through)
 	 */
 	mspace = pcibr_soft->bs_slot[win].bss_devio.bssd_space;
-	if ((try > 7) && (mspace == PCIIO_SPACE_NONE)) {
+	if ((try > halftry) && (mspace == PCIIO_SPACE_NONE)) {
 
 	    /* If this is the primary DevIO(x) window
 	     * for some other device, skip it.
@@ -2214,25 +2512,61 @@
 		devreg &= ~BRIDGE_DEV_DEV_SWAP;
 
 	    if (pcibr_soft->bs_slot[win].bss_device != devreg) {
-		bridge->b_device[win].reg = devreg;
-		pcibr_soft->bs_slot[win].bss_device = devreg;
-		bridge->b_wid_tflush;	/* wait until Bridge PIO complete */
+		if ( IS_PIC_SOFT(pcibr_soft) ) {
+			bridge->b_device[win].reg = devreg;
+			pcibr_soft->bs_slot[win].bss_device = devreg;
+			bridge->b_wid_tflush;   /* wait until Bridge PIO complete */
+		}
+		else {
+			if (io_get_sh_swapper(NASID_GET(bridge))) {
+				BRIDGE_REG_SET32((&bridge->b_device[win].reg)) = __swab32(devreg);
+				pcibr_soft->bs_slot[win].bss_device = devreg;
+				BRIDGE_REG_GET32((&bridge->b_wid_tflush)); /* wait until Bridge PIO complete */
+			} else {
+				bridge->b_device[win].reg = devreg;
+				pcibr_soft->bs_slot[win].bss_device = devreg;
+				bridge->b_wid_tflush;   /* wait until Bridge PIO complete */
+			}
+		}
 
-#if DEBUG && PCI_DEBUG
-		printk("pcibr Device(%d): 0x%lx\n", win, bridge->b_device[win].reg);
+#ifdef PCI_LATER
+		PCIBR_DEBUG((PCIBR_DEBUG_DEVREG, pconn_vhdl, 
+			    "pcibr_addr_pci_to_xio: Device(%d): %x\n",
+			    win, devreg, device_bits));
+#else
+	        printk("pcibr_addr_pci_to_xio: Device(%d): %x\n", win, devreg);
 #endif
 	    }
 	    pcibr_soft->bs_slot[win].bss_devio.bssd_space = space;
 	    pcibr_soft->bs_slot[win].bss_devio.bssd_base = mbase;
-	    xio_addr = BRIDGE_DEVIO(win) + (pci_addr - mbase);
+	    xio_addr = PCIBR_BRIDGE_DEVIO(pcibr_soft, win) + (pci_addr - mbase);
 
-#if DEBUG && PCI_DEBUG
-	    printk("%s LINE %d map to space %d space desc 0x%x[%lx..%lx] for slot %d allocates DevIO(%d) devreg 0x%x\n", 
-		    __FUNCTION__, __LINE__, space, space_desc,
-		    pci_addr, pci_addr + req_size - 1,
-		    slot, win, devreg);
-#endif
+            /* Increment this DevIO's use count */
+            pcibr_soft->bs_slot[win].bss_devio.bssd_ref_cnt++;
+
+            /* Save the DevIO register index used to access this BAR */
+            if (bar != -1)
+                pcibr_info->f_window[bar].w_devio_index = win;
 
+	    /*
+	     * The kernel only allows functions to have so many variable args,
+	     * attempting to call PCIBR_DEBUG_ALWAYS() with more than 5 printk
+	     * arguments fails so sprintf() it into a temporary string.
+	     */
+	    if (pcibr_debug_mask & PCIBR_DEBUG_PIOMAP) {
+#ifdef PIC_LATER
+	        sprintf(tmp_str, "pcibr_addr_pci_to_xio: map to %x[%x..%x] for "
+		        "slot %d allocates DevIO(%d) Device(%d) set to %x\n",
+		        space, space_desc, pci_addr, pci_addr + req_size - 1,
+		        slot, win, win, devreg, device_bits);
+#else
+	        sprintf(tmp_str, "pcibr_addr_pci_to_xio: map to [%lx..%lx] for "
+		        "slot %d allocates DevIO(%d) Device(%d) set to %lx\n",
+		        (unsigned long)pci_addr, (unsigned long)(pci_addr + req_size - 1),
+		        (unsigned int)slot, win, win, (unsigned long)devreg);
+#endif
+	        PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pconn_vhdl, "%s", tmp_str));
+	    }
 	    goto done;
 	}				/* endif DevIO(x) not pointed */
 	mbase = pcibr_soft->bs_slot[win].bss_devio.bssd_base;
@@ -2251,12 +2585,23 @@
 	 * final XIO address, release the lock and
 	 * return.
 	 */
-	xio_addr = BRIDGE_DEVIO(win) + (pci_addr - mbase);
+	xio_addr = PCIBR_BRIDGE_DEVIO(pcibr_soft, win) + (pci_addr - mbase);
+
+        /* Increment this DevIO's use count */
+        pcibr_soft->bs_slot[win].bss_devio.bssd_ref_cnt++;
 
-#if DEBUG && PCI_DEBUG
-	printk("%s LINE %d map to space %d [0x%p..0x%p] for slot %d uses DevIO(%d)\n",
-		__FUNCTION__, __LINE__, space,  pci_addr, pci_addr + req_size - 1, slot, win);
+        /* Save the DevIO register index used to access this BAR */
+        if (bar != -1)
+            pcibr_info->f_window[bar].w_devio_index = win;
+
+	if (pcibr_debug_mask & PCIBR_DEBUG_PIOMAP) {
+#ifdef PIC_LATER
+	    sprintf(tmp_str, "pcibr_addr_pci_to_xio: map to %x[%x..%x] for "
+		    "slot %d uses DevIO(%d)\n", space, space_desc, pci_addr,
+		    pci_addr + req_size - 1, slot, win);
 #endif
+	    PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pconn_vhdl, "%s", tmp_str));
+	}
 	goto done;
     }
 
@@ -2322,33 +2667,55 @@
 	if (bfn == bfo) {		/* we already match. */
 	    ;
 	} else if (bfo != 0) {		/* we have a conflict. */
-#if DEBUG && PCI_DEBUG
-	    printk("pcibr_addr_pci_to_xio: swap conflict in space %d , was%s%s, want%s%s\n",
-		    space, 
-		    bfo & PCIIO_BYTE_STREAM ? " BYTE_STREAM" : "",
-		    bfo & PCIIO_WORD_VALUES ? " WORD_VALUES" : "",
-		    bfn & PCIIO_BYTE_STREAM ? " BYTE_STREAM" : "",
-		    bfn & PCIIO_WORD_VALUES ? " WORD_VALUES" : "");
+	    if (pcibr_debug_mask & PCIBR_DEBUG_PIOMAP) {
+#ifdef PIC_LATER
+	        sprintf(tmp_str, "pcibr_addr_pci_to_xio: swap conflict in %x, "
+		        "was%s%s, want%s%s\n", space, space_desc,
+		        bfo & PCIIO_BYTE_STREAM ? " BYTE_STREAM" : "",
+		        bfo & PCIIO_WORD_VALUES ? " WORD_VALUES" : "",
+		        bfn & PCIIO_BYTE_STREAM ? " BYTE_STREAM" : "",
+		        bfn & PCIIO_WORD_VALUES ? " WORD_VALUES" : "");
 #endif
+	        PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pconn_vhdl, "%s", tmp_str));
+	    }
 	    xio_addr = XIO_NOWHERE;
 	} else {			/* OK to make the change. */
-	    bridgereg_t             octl, nctl;
-
 	    swb = (space == PCIIO_SPACE_IO) ? BRIDGE_CTRL_IO_SWAP : BRIDGE_CTRL_MEM_SWAP;
-	    octl = bridge->b_wid_control;
-	    nctl = bst ? octl | swb : octl & ~swb;
+	    if ( IS_PIC_SOFT(pcibr_soft) ) {
+	    	picreg_t             octl, nctl;
+		octl = bridge->p_wid_control_64;
+		nctl = bst ? octl | (uint64_t)swb : octl & ((uint64_t)~swb);
 
-	    if (octl != nctl)		/* make the change if any */
-		bridge->b_wid_control = nctl;
+		if (octl != nctl)		/* make the change if any */
+			bridge->b_wid_control = nctl;
+	    }
+	    else {
+	    	picreg_t             octl, nctl;
+		if (io_get_sh_swapper(NASID_GET(bridge))) {
+			octl = BRIDGE_REG_GET32((&bridge->b_wid_control));
+			nctl = bst ? octl | swb : octl & ~swb;
+
+			if (octl != nctl)           /* make the change if any */
+				BRIDGE_REG_SET32((&bridge->b_wid_control)) = __swab32(nctl);
+		} else {
+			octl = bridge->b_wid_control;
+			nctl = bst ? octl | swb : octl & ~swb;
 
+			if (octl != nctl)           /* make the change if any */
+				bridge->b_wid_control = nctl;
+		}
+	    }
 	    *bfp = bfn;			/* record the assignment */
 
-#if DEBUG && PCI_DEBUG
-	    printk("pcibr_addr_pci_to_xio: swap for space %d  set to%s%s\n",
-		    space, 
-		    bfn & PCIIO_BYTE_STREAM ? " BYTE_STREAM" : "",
-		    bfn & PCIIO_WORD_VALUES ? " WORD_VALUES" : "");
+	    if (pcibr_debug_mask & PCIBR_DEBUG_PIOMAP) {
+#ifdef PIC_LATER
+	        sprintf(tmp_str, "pcibr_addr_pci_to_xio: swap for %x set "
+			"to%s%s\n", space, space_desc,
+		        bfn & PCIIO_BYTE_STREAM ? " BYTE_STREAM" : "",
+		        bfn & PCIIO_WORD_VALUES ? " WORD_VALUES" : "");
 #endif
+	        PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pconn_vhdl, "%s", tmp_str));
+	    }
 	}
     }
   done:
@@ -2368,7 +2735,7 @@
 {
     pcibr_info_t	    pcibr_info = pcibr_info_get(pconn_vhdl);
     pciio_info_t            pciio_info = &pcibr_info->f_c;
-    pciio_slot_t            pciio_slot = pciio_info_slot_get(pciio_info);
+    pciio_slot_t            pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info);
     pcibr_soft_t            pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);
     devfs_handle_t            xconn_vhdl = pcibr_soft->bs_conn;
 
@@ -2380,8 +2747,11 @@
     unsigned long           s;
 
     /* Make sure that the req sizes are non-zero */
-    if ((req_size < 1) || (req_size_max < 1))
+    if ((req_size < 1) || (req_size_max < 1)) {
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_PIOMAP, pconn_vhdl,
+		    "pcibr_piomap_alloc: req_size | req_size_max < 1\n"));
 	return NULL;
+    }
 
     /*
      * Code to translate slot/space/addr
@@ -2390,8 +2760,11 @@
      */
     xio_addr = pcibr_addr_pci_to_xio(pconn_vhdl, pciio_slot, space, pci_addr, req_size, flags);
 
-    if (xio_addr == XIO_NOWHERE)
+    if (xio_addr == XIO_NOWHERE) {
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_PIOMAP, pconn_vhdl,
+		    "pcibr_piomap_alloc: xio_addr == XIO_NOWHERE\n"));
 	return NULL;
+    }
 
     /* Check the piomap list to see if there is already an allocated
      * piomap entry but not in use. If so use that one. Otherwise
@@ -2415,7 +2788,7 @@
     }
 
     pcibr_piomap->bp_dev = pconn_vhdl;
-    pcibr_piomap->bp_slot = pciio_slot;
+    pcibr_piomap->bp_slot = PCIBR_DEVICE_TO_SLOT(pcibr_soft, pciio_slot);
     pcibr_piomap->bp_flags = flags;
     pcibr_piomap->bp_space = space;
     pcibr_piomap->bp_pciaddr = pci_addr;
@@ -2446,6 +2819,10 @@
 	    pcibr_piomap = 0;
 	}
     }
+    
+    PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pconn_vhdl,
+		"pcibr_piomap_alloc: map=0x%x\n", pcibr_piomap));
+
     return pcibr_piomap;
 }
 
@@ -2453,6 +2830,9 @@
 void
 pcibr_piomap_free(pcibr_piomap_t pcibr_piomap)
 {
+    PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pcibr_piomap->bp_dev,
+		"pcibr_piomap_free: map=0x%x\n", pcibr_piomap));
+
     xtalk_piomap_free(pcibr_piomap->bp_xtalk_pio);
     pcibr_piomap->bp_xtalk_pio = 0;
     pcibr_piomap->bp_mapsz = 0;
@@ -2464,16 +2844,24 @@
 		  iopaddr_t pci_addr,
 		  size_t req_size)
 {
-    return xtalk_piomap_addr(pcibr_piomap->bp_xtalk_pio,
+    caddr_t	addr;
+    addr = xtalk_piomap_addr(pcibr_piomap->bp_xtalk_pio,
 			     pcibr_piomap->bp_xtalk_addr +
 			     pci_addr - pcibr_piomap->bp_pciaddr,
 			     req_size);
+    PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pcibr_piomap->bp_dev,
+                "pcibr_piomap_free: map=0x%x, addr=0x%x\n", 
+		pcibr_piomap, addr));
+
+    return(addr);
 }
 
 /*ARGSUSED */
 void
 pcibr_piomap_done(pcibr_piomap_t pcibr_piomap)
 {
+    PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pcibr_piomap->bp_dev,
+		"pcibr_piomap_done: map=0x%x\n", pcibr_piomap));
     xtalk_piomap_done(pcibr_piomap->bp_xtalk_pio);
 }
 
@@ -2487,26 +2875,34 @@
 		    unsigned flags)
 {
     pciio_info_t            pciio_info = pciio_info_get(pconn_vhdl);
-    pciio_slot_t            pciio_slot = pciio_info_slot_get(pciio_info);
+    pciio_slot_t            pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info);
     pcibr_soft_t            pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);
     devfs_handle_t            xconn_vhdl = pcibr_soft->bs_conn;
 
     iopaddr_t               xio_addr;
+    caddr_t		    addr;
 
     xio_addr = pcibr_addr_pci_to_xio(pconn_vhdl, pciio_slot, space, pci_addr, req_size, flags);
 
-    if (xio_addr == XIO_NOWHERE)
+    if (xio_addr == XIO_NOWHERE) {
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_PIODIR, pconn_vhdl,
+		    "pcibr_piotrans_addr: xio_addr == XIO_NOWHERE\n"));
 	return NULL;
+    }
 
-    return xtalk_piotrans_addr(xconn_vhdl, 0, xio_addr, req_size, flags & PIOMAP_FLAGS);
+    addr = xtalk_piotrans_addr(xconn_vhdl, 0, xio_addr, req_size, flags & PIOMAP_FLAGS);
+    PCIBR_DEBUG((PCIBR_DEBUG_PIODIR, pconn_vhdl,
+		"pcibr_piotrans_addr: xio_addr=0x%x, addr=0x%x\n",
+		xio_addr, addr));
+    return(addr);
 }
 
 /*
  * PIO Space allocation and management.
  *      Allocate and Manage the PCI PIO space (mem and io space)
  *      This routine is pretty simplistic at this time, and
- *      does pretty trivial management of allocation and freeing..
- *      The current scheme is prone for fragmentation..
+ *      does pretty trivial management of allocation and freeing.
+ *      The current scheme is prone for fragmentation.
  *      Change the scheme to use bitmaps.
  */
 
@@ -2525,7 +2921,6 @@
     pciio_piospace_t        piosp;
     unsigned long           s;
 
-    iopaddr_t              *pciaddr, *pcilast;
     iopaddr_t               start_addr;
     size_t                  align_mask;
 
@@ -2559,38 +2954,43 @@
     }
     ASSERT(!piosp);
 
+    /*
+     * Allocate PCI bus address, usually for the Universe chip driver;
+     * do not pass window info since the actual PCI bus address
+     * space will never be freed.  The space may be reused after it
+     * is logically released by pcibr_piospace_free().
+     */
     switch (space) {
     case PCIIO_SPACE_IO:
-	pciaddr = &pcibr_soft->bs_spinfo.pci_io_base;
-	pcilast = &pcibr_soft->bs_spinfo.pci_io_last;
+        start_addr = pcibr_bus_addr_alloc(pcibr_soft, NULL,
+                                          PCIIO_SPACE_IO,
+                                          0, req_size, alignment);
 	break;
+
     case PCIIO_SPACE_MEM:
     case PCIIO_SPACE_MEM32:
-	pciaddr = &pcibr_soft->bs_spinfo.pci_mem_base;
-	pcilast = &pcibr_soft->bs_spinfo.pci_mem_last;
+        start_addr = pcibr_bus_addr_alloc(pcibr_soft, NULL,
+                                          PCIIO_SPACE_MEM32,
+                                          0, req_size, alignment);
 	break;
+
     default:
 	ASSERT(0);
 	pcibr_unlock(pcibr_soft, s);
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_PIOMAP, pconn_vhdl,
+		    "pcibr_piospace_alloc: unknown space %d\n", space));
 	return 0;
     }
 
-    start_addr = *pciaddr;
-
     /*
-     * Align start_addr.
+     * If too big a request, reject it.
      */
-    if (start_addr & align_mask)
-	start_addr = (start_addr + align_mask) & ~align_mask;
-
-    if ((start_addr + req_size) > *pcilast) {
-	/*
-	 * If too big a request, reject it.
-	 */
+    if (!start_addr) {
 	pcibr_unlock(pcibr_soft, s);
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_PIOMAP, pconn_vhdl,
+		    "pcibr_piospace_alloc: request 0x%x to big\n", req_size));
 	return 0;
     }
-    *pciaddr = (start_addr + req_size);
 
     NEW(piosp);
     piosp->free = 0;
@@ -2601,6 +3001,10 @@
     pcibr_info->f_piospace = piosp;
 
     pcibr_unlock(pcibr_soft, s);
+
+    PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pconn_vhdl,
+		"pcibr_piospace_alloc: piosp=0x%x\n", piosp));
+
     return start_addr;
 }
 
@@ -2612,7 +3016,9 @@
 		    size_t req_size)
 {
     pcibr_info_t            pcibr_info = pcibr_info_get(pconn_vhdl);
+#ifdef PIC_LATER
     pcibr_soft_t            pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast;
+#endif
 
     pciio_piospace_t        piosp;
     unsigned long           s;
@@ -2655,6 +3061,9 @@
     }
     piosp->free = 1;
     pcibr_unlock(pcibr_soft, s);
+
+    PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pconn_vhdl,
+		"pcibr_piospace_free: piosp=0x%x\n", piosp));
     return;
 }
 
@@ -2713,7 +3122,7 @@
 	attributes &= ~PCI64_ATTR_PREF;
 
     /* the swap bit is in the address attributes for xbridge */
-    if (pcibr_soft->bs_xbridge) {
+    if (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft)) {
     	if (flags & PCIIO_BYTE_STREAM)
         	attributes |= PCI64_ATTR_SWAP;
     	if (flags & PCIIO_WORD_VALUES)
@@ -2742,6 +3151,11 @@
     if (flags & PCIBR_VCHAN0)
 	attributes &= ~PCI64_ATTR_VIRTUAL;
 
+    /* PIC in PCI-X mode only supports barrier & swap */
+    if (IS_PCIX(pcibr_soft)) {
+	attributes &= (PCI64_ATTR_BAR | PCI64_ATTR_SWAP);
+    }
+
     return (attributes);
 }
 
@@ -2762,6 +3176,7 @@
     pcibr_dmamap_t          pcibr_dmamap;
     int                     ate_count;
     int                     ate_index;
+    int			    vchan = VCHAN0;
 
     /* merge in forced flags */
     flags |= pcibr_soft->bs_dma_flags;
@@ -2778,17 +3193,16 @@
     xtalk_dmamap = xtalk_dmamap_alloc(xconn_vhdl, dev_desc, req_size_max,
 				      flags & DMAMAP_FLAGS);
     if (!xtalk_dmamap) {
-#if PCIBR_ATE_DEBUG
-	printk("pcibr_attach: xtalk_dmamap_alloc failed\n");
-#endif
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP, pconn_vhdl,
+		    "pcibr_dmamap_alloc: xtalk_dmamap_alloc failed\n"));
 	free_pciio_dmamap(pcibr_dmamap);
 	return 0;
     }
     xio_port = pcibr_soft->bs_mxid;
-    slot = pciio_info_slot_get(pciio_info);
+    slot = PCIBR_INFO_SLOT_GET_INT(pciio_info);
 
     pcibr_dmamap->bd_dev = pconn_vhdl;
-    pcibr_dmamap->bd_slot = slot;
+    pcibr_dmamap->bd_slot = PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot);
     pcibr_dmamap->bd_soft = pcibr_soft;
     pcibr_dmamap->bd_xtalk = xtalk_dmamap;
     pcibr_dmamap->bd_max_size = req_size_max;
@@ -2812,29 +3226,37 @@
 	    pcibr_dmamap->bd_xio_addr = 0;
 	    pcibr_dmamap->bd_pci_addr = pci_addr;
 
-	    /* Make sure we have an RRB (or two).
+	    /* If in PCI mode, make sure we have an RRB (or two). 
 	     */
-	    if (!(pcibr_soft->bs_rrb_fixed & (1 << slot))) {
+	    if (IS_PCI(pcibr_soft) && 
+		!(pcibr_soft->bs_rrb_fixed & (1 << slot))) {
 		if (flags & PCIBR_VCHAN1)
-		    slot += PCIBR_RRB_SLOT_VIRTUAL;
-		have_rrbs = pcibr_soft->bs_rrb_valid[slot];
+		    vchan = VCHAN1;
+		have_rrbs = pcibr_soft->bs_rrb_valid[slot][vchan];
 		if (have_rrbs < 2) {
 		    if (pci_addr & PCI64_ATTR_PREF)
 			min_rrbs = 2;
 		    else
 			min_rrbs = 1;
 		    if (have_rrbs < min_rrbs)
-			do_pcibr_rrb_autoalloc(pcibr_soft, slot, min_rrbs - have_rrbs);
+			do_pcibr_rrb_autoalloc(pcibr_soft, slot, vchan,
+					       min_rrbs - have_rrbs);
 		}
 	    }
-#if PCIBR_ATE_DEBUG
-	    printk("pcibr_dmamap_alloc: using direct64\n");
-#endif
+	    PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP | PCIBR_DEBUG_DMADIR, pconn_vhdl,
+		 	"pcibr_dmamap_alloc: using direct64, map=0x%x\n",
+			pcibr_dmamap));
 	    return pcibr_dmamap;
 	}
-#if PCIBR_ATE_DEBUG
-	printk("pcibr_dmamap_alloc: unable to use direct64\n");
-#endif
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP | PCIBR_DEBUG_DMADIR, pconn_vhdl,
+		    "pcibr_dmamap_alloc: unable to use direct64\n"));
+
+	/* PIC only supports 64-bit direct mapping in PCI-X mode. */
+	if (IS_PCIX(pcibr_soft)) {
+	    DEL(pcibr_dmamap);
+	    return 0;
+	}
+
 	flags &= ~PCIIO_DMA_A64;
     }
     if (flags & PCIIO_FIXED) {
@@ -2849,17 +3271,17 @@
 	     * Mapping calls may fail if target
 	     * is outside the direct32 range.
 	     */
-#if PCIBR_ATE_DEBUG
-	    printk("pcibr_dmamap_alloc: using direct32\n");
-#endif
+	    PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP | PCIBR_DEBUG_DMADIR, pconn_vhdl,
+			"pcibr_dmamap_alloc: using direct32, map=0x%x\n", 
+			pcibr_dmamap));
 	    pcibr_dmamap->bd_flags = flags;
 	    pcibr_dmamap->bd_xio_addr = pcibr_soft->bs_dir_xbase;
 	    pcibr_dmamap->bd_pci_addr = PCI32_DIRECT_BASE;
 	    return pcibr_dmamap;
 	}
-#if PCIBR_ATE_DEBUG
-	printk("pcibr_dmamap_alloc: unable to use direct32\n");
-#endif
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP | PCIBR_DEBUG_DMADIR, pconn_vhdl,
+		    "pcibr_dmamap_alloc: unable to use direct32\n"));
+
 	/* If the user demands FIXED and we can't
 	 * give it to him, fail.
 	 */
@@ -2892,9 +3314,9 @@
 	    int                     have_rrbs;
 	    int                     min_rrbs;
 
-#if PCIBR_ATE_DEBUG
-	    printk("pcibr_dmamap_alloc: using PMU\n");
-#endif
+	    PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP, pconn_vhdl,
+			"pcibr_dmamap_alloc: using PMU, ate_index=%d, "
+			"pcibr_dmamap=0x%x\n", ate_index, pcibr_dmamap));
 
 	    ate_proto = pcibr_flags_to_ate(flags);
 
@@ -2904,7 +3326,7 @@
 	    /*
 	     * for xbridge the byte-swap bit == bit 29 of PCI address
 	     */
-	    if (pcibr_soft->bs_xbridge) {
+	    if (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft)) {
 		    if (flags & PCIIO_BYTE_STREAM)
 			    ATE_SWAP_ON(pcibr_dmamap->bd_pci_addr);
 		    /*
@@ -2926,18 +3348,19 @@
 	    /* Make sure we have an RRB (or two).
 	     */
 	    if (!(pcibr_soft->bs_rrb_fixed & (1 << slot))) {
-		have_rrbs = pcibr_soft->bs_rrb_valid[slot];
+		have_rrbs = pcibr_soft->bs_rrb_valid[slot][vchan];
 		if (have_rrbs < 2) {
 		    if (ate_proto & ATE_PREF)
 			min_rrbs = 2;
 		    else
 			min_rrbs = 1;
 		    if (have_rrbs < min_rrbs)
-			do_pcibr_rrb_autoalloc(pcibr_soft, slot, min_rrbs - have_rrbs);
+			do_pcibr_rrb_autoalloc(pcibr_soft, slot, vchan,
+					       min_rrbs - have_rrbs);
 		}
 	    }
 	    if (ate_index >= pcibr_soft->bs_int_ate_size && 
-				!pcibr_soft->bs_xbridge) {
+				!IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft)) {
 		bridge_t               *bridge = pcibr_soft->bs_base;
 		volatile unsigned      *cmd_regp;
 		unsigned                cmd_reg;
@@ -2946,27 +3369,35 @@
 		pcibr_dmamap->bd_flags |= PCIBR_DMAMAP_SSRAM;
 
 		s = pcibr_lock(pcibr_soft);
-		cmd_regp = &(bridge->
-			     b_type0_cfg_dev[slot].
-			     l[PCI_CFG_COMMAND / 4]);
-		cmd_reg = *cmd_regp;
+		cmd_regp = pcibr_slot_config_addr(bridge, slot, 
+						PCI_CFG_COMMAND/4);
+		if ( IS_PIC_SOFT(pcibr_soft) ) {
+			cmd_reg = pcibr_slot_config_get(bridge, slot, PCI_CFG_COMMAND/4);
+		}
+		else {
+			if (io_get_sh_swapper(NASID_GET(bridge))) {
+				BRIDGE_REG_SET32((&cmd_reg)) = __swab32(*cmd_regp);
+			} else {
+				cmd_reg = pcibr_slot_config_get(bridge, slot, PCI_CFG_COMMAND/4);
+			}
+		}
 		pcibr_soft->bs_slot[slot].bss_cmd_pointer = cmd_regp;
 		pcibr_soft->bs_slot[slot].bss_cmd_shadow = cmd_reg;
 		pcibr_unlock(pcibr_soft, s);
 	    }
 	    return pcibr_dmamap;
 	}
-#if PCIBR_ATE_DEBUG
-	printk("pcibr_dmamap_alloc: unable to use PMU\n");
-#endif
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP, pconn_vhdl,
+		    "pcibr_dmamap_alloc: PMU use failed, ate_index=%d\n",
+		    ate_index));
+
 	pcibr_ate_free(pcibr_soft, ate_index, ate_count);
     }
     /* total failure: sorry, you just can't
      * get from here to there that way.
      */
-#if PCIBR_ATE_DEBUG
-    printk("pcibr_dmamap_alloc: complete failure.\n");
-#endif
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP, pconn_vhdl,
+		"pcibr_dmamap_alloc: complete failure.\n"));
     xtalk_dmamap_free(xtalk_dmamap);
     free_pciio_dmamap(pcibr_dmamap);
     return 0;
@@ -2977,7 +3408,8 @@
 pcibr_dmamap_free(pcibr_dmamap_t pcibr_dmamap)
 {
     pcibr_soft_t            pcibr_soft = pcibr_dmamap->bd_soft;
-    pciio_slot_t            slot = pcibr_dmamap->bd_slot;
+    pciio_slot_t            slot = PCIBR_SLOT_TO_DEVICE(pcibr_soft,
+							pcibr_dmamap->bd_slot);
 
     unsigned                flags = pcibr_dmamap->bd_flags;
 
@@ -3001,6 +3433,9 @@
 	pcibr_release_device(pcibr_soft, slot, BRIDGE_DEV_PMU_BITS);
     }
 
+    PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev,
+		"pcibr_dmamap_free: pcibr_dmamap=0x%x\n", pcibr_dmamap));
+
     free_pciio_dmamap(pcibr_dmamap);
 }
 
@@ -3029,15 +3464,15 @@
 	pci_addr = xio_addr - BRIDGE_PCI_MEM64_BASE;
 	return pci_addr;
     }
-    for (slot = 0; slot < 8; ++slot)
-	if ((xio_addr >= BRIDGE_DEVIO(slot)) &&
-	    (xio_lim < BRIDGE_DEVIO(slot + 1))) {
+    for (slot = soft->bs_min_slot; slot < PCIBR_NUM_SLOTS(soft); ++slot)
+	if ((xio_addr >= PCIBR_BRIDGE_DEVIO(soft, slot)) &&
+	    (xio_lim < PCIBR_BRIDGE_DEVIO(soft, slot + 1))) {
 	    bridgereg_t             dev;
 
 	    dev = soft->bs_slot[slot].bss_device;
 	    pci_addr = dev & BRIDGE_DEV_OFF_MASK;
 	    pci_addr <<= BRIDGE_DEV_OFF_ADDR_SHFT;
-	    pci_addr += xio_addr - BRIDGE_DEVIO(slot);
+	    pci_addr += xio_addr - PCIBR_BRIDGE_DEVIO(soft, slot);
 	    return (dev & BRIDGE_DEV_DEV_IO_MEM) ? pci_addr : PCI_NOWHERE;
 	}
     return 0;
@@ -3070,7 +3505,7 @@
     } else
 	xio_port = pcibr_dmamap->bd_xio_port;
 
-    /* If this DMA is to an address that
+    /* If this DMA is to an addres that
      * refers back to this Bridge chip,
      * reduce it back to the correct
      * PCI MEM address.
@@ -3099,14 +3534,12 @@
 	if (flags & PCIBR_NOPREFETCH)
 	    pci_addr &= ~PCI64_ATTR_PREF;
 
-#if DEBUG && PCIBR_DMA_DEBUG
-	printk("pcibr_dmamap_addr (direct64):\n"
-		"\twanted paddr [0x%x..0x%x]\n"
-		"\tXIO port 0x%x offset 0x%x\n"
-		"\treturning PCI 0x%x\n",
-		paddr, paddr + req_size - 1,
-		xio_port, xio_addr, pci_addr);
-#endif
+	PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP | PCIBR_DEBUG_DMADIR, 
+		    pcibr_dmamap->bd_dev,
+		    "pcibr_dmamap_addr: (direct64): wanted paddr [0x%x..0x%x] "
+		    "XIO port 0x%x offset 0x%x, returning PCI 0x%x\n",
+		    paddr, paddr + req_size - 1, xio_port, xio_addr, pci_addr));
+
     } else if (flags & PCIIO_FIXED) {
 	/* A32 direct DMA:
 	 * always use 32-bit direct mapping,
@@ -3126,14 +3559,12 @@
 	    pci_addr = pcibr_dmamap->bd_pci_addr +
 		xio_addr - pcibr_dmamap->bd_xio_addr;
 
-#if DEBUG && PCIBR_DMA_DEBUG
-	printk("pcibr_dmamap_addr (direct32):\n"
-		"\twanted paddr [0x%x..0x%x]\n"
-		"\tXIO port 0x%x offset 0x%x\n"
-		"\treturning PCI 0x%x\n",
-		paddr, paddr + req_size - 1,
-		xio_port, xio_addr, pci_addr);
-#endif
+	PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP | PCIBR_DEBUG_DMADIR, 
+		    pcibr_dmamap->bd_dev,
+		    "pcibr_dmamap_addr (direct32): wanted paddr [0x%x..0x%x] "
+		    "XIO port 0x%x offset 0x%x, returning PCI 0x%x\n",
+		    paddr, paddr + req_size - 1, xio_port, xio_addr, pci_addr));
+
     } else {
 	bridge_t               *bridge = pcibr_soft->bs_base;
 	iopaddr_t               offset = IOPGOFF(xio_addr);
@@ -3148,14 +3579,6 @@
 	int                     ate_total = ate_count;
 	unsigned                freeze_time;
 #endif
-
-#if PCIBR_ATE_DEBUG
-	bridge_ate_t            ate_cmp;
-	bridge_ate_p            ate_cptr;
-	unsigned                ate_lo, ate_hi;
-	int                     ate_bad = 0;
-	int                     ate_rbc = 0;
-#endif
 	bridge_ate_p            ate_ptr = pcibr_dmamap->bd_ate_ptr;
 	bridge_ate_t            ate;
 
@@ -3183,7 +3606,21 @@
 		ATE_FREEZE();
 		ATE_WRITE();
 		ATE_THAW();
-		bridge->b_wid_tflush;	/* wait until Bridge PIO complete */
+		if ( IS_PIC_SOFT(pcibr_soft) ) {
+			bridge->b_wid_tflush;	/* wait until Bridge PIO complete */
+		}
+		else {
+			if (io_get_sh_swapper(NASID_GET(bridge))) {
+				BRIDGE_REG_GET32((&bridge->b_wid_tflush));
+			} else {
+				bridge->b_wid_tflush;
+			}
+		}
+		PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev,
+			    "pcibr_dmamap_addr (PMU) : wanted paddr "
+			    "[0x%x..0x%x] returning PCI 0x%x\n", 
+			    paddr, paddr + req_size - 1, pci_addr));
+
 	} else {
 		/* The number of ATE's required is greater than the number
 		 * allocated for this map. One way this can happen is if
@@ -3193,14 +3630,12 @@
 		 * The other possibility is that the map is just plain too
 		 * small to handle the requested target area.
 		 */
-#if PCIBR_ATE_DEBUG
-		printk(KERN_WARNING "pcibr_dmamap_addr :\n"
-			"\twanted paddr [0x%x..0x%x]\n"
-			"\tate_count 0x%x bd_ate_count 0x%x\n"
-			"\tATE's required > number allocated\n",
-			paddr, paddr + req_size - 1,
-			ate_count, pcibr_dmamap->bd_ate_count);
-#endif
+		PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev, 
+		            "pcibr_dmamap_addr (PMU) : wanted paddr "
+			    "[0x%x..0x%x] ate_count 0x%x bd_ate_count 0x%x "
+			    "ATE's required > number allocated\n",
+			     paddr, paddr + req_size - 1,
+			     ate_count, pcibr_dmamap->bd_ate_count));
 		pci_addr = 0;
 	}
 
@@ -3250,17 +3685,24 @@
 
     xtalk_alenlist = xtalk_dmamap_list(pcibr_dmamap->bd_xtalk, palenlist,
 				       flags & DMAMAP_FLAGS);
-    if (!xtalk_alenlist)
+    if (!xtalk_alenlist) {
+        PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev,
+                    "pcibr_dmamap_list: xtalk_dmamap_list() failed, "
+		    "pcibr_dmamap=0x%x\n", pcibr_dmamap));
 	goto fail;
-
+    }
     alenlist_cursor_init(xtalk_alenlist, 0, NULL);
 
     if (inplace) {
 	pciio_alenlist = xtalk_alenlist;
     } else {
 	pciio_alenlist = alenlist_create(al_flags);
-	if (!pciio_alenlist)
+	if (!pciio_alenlist) {
+	    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev,
+			"pcibr_dmamap_list: alenlist_create() failed, "
+			"pcibr_dmamap=0x%lx\n", (unsigned long)pcibr_dmamap));
 	    goto fail;
+	}
     }
 
     direct64 = pcibr_dmamap->bd_flags & PCIIO_DMA_A64;
@@ -3286,8 +3728,12 @@
 
 	if (xio_port == pcibr_soft->bs_xid) {
 	    new_addr = pcibr_addr_xio_to_pci(pcibr_soft, xio_addr, length);
-	    if (new_addr == PCI_NOWHERE)
+	    if (new_addr == PCI_NOWHERE) {
+                PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev,
+                            "pcibr_dmamap_list: pcibr_addr_xio_to_pci failed, "
+                            "pcibr_dmamap=0x%x\n", pcibr_dmamap));
 		goto fail;
+	    }
 	} else if (direct64) {
 	    new_addr = pci_addr | xio_addr
 		| ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT);
@@ -3318,9 +3764,8 @@
 		| (xio_port << ATE_TIDSHIFT)
 		| (xio_addr - offset);
 	    if (ate == ate_prev) {
-#if PCIBR_ATE_DEBUG
-		printk("pcibr_dmamap_list: ATE share\n");
-#endif
+		PCIBR_DEBUG((PCIBR_DEBUG_ATE, pcibr_dmamap->bd_dev,
+			    "pcibr_dmamap_list: ATE share\n"));
 		ate_ptr--;
 		ate_index--;
 		pci_addr -= IOPGSIZE;
@@ -3335,14 +3780,13 @@
 
 	    /* Ensure that this map contains enough ATE's */
 	    if (ate_total > pcibr_dmamap->bd_ate_count) {
-#if PCIBR_ATE_DEBUG
-		printk(KERN_WARNING "pcibr_dmamap_list :\n"
-			"\twanted xio_addr [0x%x..0x%x]\n"
-			"\tate_total 0x%x bd_ate_count 0x%x\n"
-			"\tATE's required > number allocated\n",
-			xio_addr, xio_addr + length - 1,
-			ate_total, pcibr_dmamap->bd_ate_count);
-#endif
+		PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATE, pcibr_dmamap->bd_dev,
+			     "pcibr_dmamap_list :\n"
+			     "\twanted xio_addr [0x%x..0x%x]\n"
+			     "\tate_total 0x%x bd_ate_count 0x%x\n"
+			     "\tATE's required > number allocated\n",
+			     xio_addr, xio_addr + length - 1,
+			     ate_total, pcibr_dmamap->bd_ate_count));
 		goto fail;
 	    }
 
@@ -3362,13 +3806,22 @@
 	if (inplace) {
 	    if (ALENLIST_SUCCESS !=
 		alenlist_replace(pciio_alenlist, NULL,
-				 &new_addr, &length, al_flags))
+				 &new_addr, &length, al_flags)) {
+                PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev,
+                            "pcibr_dmamap_list: alenlist_replace() failed, "
+                            "pcibr_dmamap=0x%x\n", pcibr_dmamap));
+
 		goto fail;
+	    }
 	} else {
 	    if (ALENLIST_SUCCESS !=
 		alenlist_append(pciio_alenlist,
-				new_addr, length, al_flags))
+				new_addr, length, al_flags)) {
+                PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev,
+                            "pcibr_dmamap_list: alenlist_append() failed, "
+                            "pcibr_dmamap=0x%x\n", pcibr_dmamap));
 		goto fail;
+	    }
 	}
     }
     if (!inplace)
@@ -3386,8 +3839,21 @@
      */
     if (ate_freeze_done) {
 	ATE_THAW();
-	bridge->b_wid_tflush;		/* wait until Bridge PIO complete */
+	if ( IS_PIC_SOFT(pcibr_soft) ) {
+		bridge->b_wid_tflush;		/* wait until Bridge PIO complete */
+	}
+	else {
+		if (io_get_sh_swapper(NASID_GET(bridge))) {
+			BRIDGE_REG_GET32((&bridge->b_wid_tflush));
+		} else {
+			bridge->b_wid_tflush;
+		}
+	}
     }
+    PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev,
+		"pcibr_dmamap_list: pcibr_dmamap=0x%x, pciio_alenlist=0x%x\n",
+		pcibr_dmamap, pciio_alenlist));
+
     return pciio_alenlist;
 
   fail:
@@ -3398,7 +3864,16 @@
      */
     if (ate_freeze_done) {
 	ATE_THAW();
-	bridge->b_wid_tflush;
+	if ( IS_PIC_SOFT(pcibr_soft) ) {
+		bridge->b_wid_tflush;
+	}
+	else {
+		if (io_get_sh_swapper(NASID_GET(bridge))) {
+			BRIDGE_REG_GET32((&bridge->b_wid_tflush));
+		} else {
+			bridge->b_wid_tflush;
+		}
+	}
     }
     if (pciio_alenlist && !inplace)
 	alenlist_destroy(pciio_alenlist);
@@ -3409,6 +3884,10 @@
 void
 pcibr_dmamap_done(pcibr_dmamap_t pcibr_dmamap)
 {
+#ifdef PIC_LATER
+    pcibr_soft_t            pcibr_soft = pcibr_dmamap->bd_soft;
+    pciio_slot_t            slot = PCIBR_SLOT_TO_DEVICE(pcibr_soft,
+#endif
     /*
      * We could go through and invalidate ATEs here;
      * for performance reasons, we don't.
@@ -3423,6 +3902,9 @@
 	    atomic_dec(&(pcibr_dmamap->bd_soft->bs_slot[pcibr_dmamap->bd_slot]. bss_ext_ates_active));
     }
     xtalk_dmamap_done(pcibr_dmamap->bd_xtalk);
+
+    PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev,
+		"pcibr_dmamap_done: pcibr_dmamap=0x%x\n", pcibr_dmamap));
 }
 
 
@@ -3455,7 +3937,7 @@
     pciio_info_t            pciio_info = pciio_info_get(pconn_vhdl);
     pcibr_soft_t            pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);
     devfs_handle_t            xconn_vhdl = pcibr_soft->bs_conn;
-    pciio_slot_t            pciio_slot = pciio_info_slot_get(pciio_info);
+    pciio_slot_t            pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info);
     pcibr_soft_slot_t       slotp = &pcibr_soft->bs_slot[pciio_slot];
 
     xwidgetnum_t            xio_port;
@@ -3464,6 +3946,7 @@
 
     int                     have_rrbs;
     int                     min_rrbs;
+    int			    vchan = VCHAN0;
 
     /* merge in forced flags */
     flags |= pcibr_soft->bs_dma_flags;
@@ -3471,16 +3954,10 @@
     xio_addr = xtalk_dmatrans_addr(xconn_vhdl, 0, paddr, req_size,
 				   flags & DMAMAP_FLAGS);
     if (!xio_addr) {
-#if PCIBR_DMA_DEBUG
-	printk("pcibr_dmatrans_addr:\n"
-		"\tpciio connection point %v\n"
-		"\txtalk connection point %v\n"
-		"\twanted paddr [0x%x..0x%x]\n"
-		"\txtalk_dmatrans_addr returned 0x%x\n",
-		pconn_vhdl, xconn_vhdl,
-		paddr, paddr + req_size - 1,
-		xio_addr);
-#endif
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMADIR, pconn_vhdl,
+		    "pcibr_dmatrans_addr: wanted paddr [0x%x..0x%x], "
+		    "xtalk_dmatrans_addr failed with 0x%x\n",
+		    paddr, paddr + req_size - 1, xio_addr));
 	return 0;
     }
     /*
@@ -3488,16 +3965,10 @@
      */
     if (XIO_PACKED(xio_addr)) {
 	if (xio_addr == XIO_NOWHERE) {
-#if PCIBR_DMA_DEBUG
-	    printk("pcibr_dmatrans_addr:\n"
-		    "\tpciio connection point %v\n"
-		    "\txtalk connection point %v\n"
-		    "\twanted paddr [0x%x..0x%x]\n"
-		    "\txtalk_dmatrans_addr returned 0x%x\n",
-		    pconn_vhdl, xconn_vhdl,
-		    paddr, paddr + req_size - 1,
-		    xio_addr);
-#endif
+	    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMADIR, pconn_vhdl,
+		        "pcibr_dmatrans_addr: wanted paddr [0x%x..0x%x], "
+		        "xtalk_dmatrans_addr failed with XIO_NOWHERE\n",
+		        paddr, paddr + req_size - 1));
 	    return 0;
 	}
 	xio_port = XIO_PORT(xio_addr);
@@ -3515,6 +3986,10 @@
      */
     if (xio_port == pcibr_soft->bs_xid) {
 	pci_addr = pcibr_addr_xio_to_pci(pcibr_soft, xio_addr, req_size);
+        PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl,
+		    "pcibr_dmatrans_addr:  wanted paddr [0x%x..0x%x], "
+		    "xio_port=0x%x, pci_addr=0x%x\n",
+		    paddr, paddr + req_size - 1, xio_port, pci_addr));
 	return pci_addr;
     }
     /* If the caller can use A64, try to
@@ -3531,92 +4006,65 @@
 	if ((pci_addr != PCIBR_D64_BASE_UNSET) &&
 	    (flags == slotp->bss_d64_flags)) {
 
-#ifdef CONFIG_IA64_SGI_SN2
-	    pci_addr |= (PHYS_TO_DMA(xio_addr))
-		| ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT);
-#else
 	    pci_addr |=  xio_addr
 		| ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT);
-#endif
 
-#if DEBUG && PCIBR_DMA_DEBUG
 #if HWG_PERF_CHECK
 	    if (xio_addr != 0x20000000)
 #endif
-		printk("pcibr_dmatrans_addr: [reuse]\n"
-			"\tpciio connection point %v\n"
-			"\txtalk connection point %v\n"
-			"\twanted paddr [0x%x..0x%x]\n"
-			"\txtalk_dmatrans_addr returned 0x%x\n"
-			"\tdirect 64bit address is 0x%x\n",
-			pconn_vhdl, xconn_vhdl,
-			paddr, paddr + req_size - 1,
-			xio_addr, pci_addr);
-#endif
+		PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl,
+			    "pcibr_dmatrans_addr:  wanted paddr [0x%x..0x%x], "
+			    "xio_port=0x%x, direct64: pci_addr=0x%x\n",
+			    paddr, paddr + req_size - 1, xio_addr, pci_addr));
 	    return (pci_addr);
 	}
 	if (!pcibr_try_set_device(pcibr_soft, pciio_slot, flags, BRIDGE_DEV_D64_BITS)) {
 	    pci_addr = pcibr_flags_to_d64(flags, pcibr_soft);
 	    slotp->bss_d64_flags = flags;
 	    slotp->bss_d64_base = pci_addr;
-#ifdef CONFIG_IA64_SGI_SN2
-	    pci_addr |= (PHYS_TO_DMA(xio_addr))
-		| ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT);
-#else
             pci_addr |= xio_addr
 		| ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT);
-#endif
 
-	    /* Make sure we have an RRB (or two).
+	    /* If in PCI mode, make sure we have an RRB (or two).
 	     */
-	    if (!(pcibr_soft->bs_rrb_fixed & (1 << pciio_slot))) {
+	    if (IS_PCI(pcibr_soft) && 
+		!(pcibr_soft->bs_rrb_fixed & (1 << pciio_slot))) {
 		if (flags & PCIBR_VCHAN1)
-		    pciio_slot += PCIBR_RRB_SLOT_VIRTUAL;
-		have_rrbs = pcibr_soft->bs_rrb_valid[pciio_slot];
+		    vchan = VCHAN1;
+		have_rrbs = pcibr_soft->bs_rrb_valid[pciio_slot][vchan];
 		if (have_rrbs < 2) {
 		    if (pci_addr & PCI64_ATTR_PREF)
 			min_rrbs = 2;
 		    else
 			min_rrbs = 1;
 		    if (have_rrbs < min_rrbs)
-			do_pcibr_rrb_autoalloc(pcibr_soft, pciio_slot, min_rrbs - have_rrbs);
+			do_pcibr_rrb_autoalloc(pcibr_soft, pciio_slot, vchan,
+					       min_rrbs - have_rrbs);
 		}
 	    }
-#if PCIBR_DMA_DEBUG
 #if HWG_PERF_CHECK
 	    if (xio_addr != 0x20000000)
 #endif
-		printk("pcibr_dmatrans_addr:\n"
-			"\tpciio connection point %v\n"
-			"\txtalk connection point %v\n"
-			"\twanted paddr [0x%x..0x%x]\n"
-			"\txtalk_dmatrans_addr returned 0x%x\n"
-			"\tdirect 64bit address is 0x%x\n"
-			"\tnew flags: 0x%x\n",
-			pconn_vhdl, xconn_vhdl,
-			paddr, paddr + req_size - 1,
-			xio_addr, pci_addr, (uint64_t) flags);
-#endif
+		PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl,
+			    "pcibr_dmatrans_addr:  wanted paddr [0x%x..0x%x], "
+			    "xio_port=0x%x, direct64: pci_addr=0x%x, "
+			    "new flags: 0x%x\n", paddr, paddr + req_size - 1,
+			    xio_addr, pci_addr, (uint64_t) flags));
 	    return (pci_addr);
 	}
-	/* our flags conflict with Device(x).
-	 */
-	flags = flags
-	    & ~PCIIO_DMA_A64
-	    & ~PCIBR_VCHAN0
-	    ;
 
-#if PCIBR_DMA_DEBUG
-	printk("pcibr_dmatrans_addr:\n"
-		"\tpciio connection point %v\n"
-		"\txtalk connection point %v\n"
-		"\twanted paddr [0x%x..0x%x]\n"
-		"\txtalk_dmatrans_addr returned 0x%x\n"
-		"\tUnable to set Device(x) bits for Direct-64\n",
-		pconn_vhdl, xconn_vhdl,
-		paddr, paddr + req_size - 1,
-		xio_addr);
-#endif
+	PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl,
+		    "pcibr_dmatrans_addr:  wanted paddr [0x%x..0x%x], "
+		    "xio_port=0x%x, Unable to set direct64 Device(x) bits\n",
+		    paddr, paddr + req_size - 1, xio_addr));
+
+	/* PIC only supports 64-bit direct mapping in PCI-X mode */
+	if (IS_PCIX(pcibr_soft)) {
+	    return 0;
+	}
+
+	/* our flags conflict with Device(x). try direct32*/
+	flags = flags & ~(PCIIO_DMA_A64 | PCIBR_VCHAN0);
     }
     /* Try to satisfy the request with the 32-bit direct
      * map. This can fail if the configuration bits in
@@ -3633,17 +4081,11 @@
 	    (xio_addr < xio_base) ||
 	    (xio_port != pcibr_soft->bs_dir_xport) ||
 	    (endoff > map_size)) {
-#if PCIBR_DMA_DEBUG
-	    printk("pcibr_dmatrans_addr:\n"
-		    "\tpciio connection point %v\n"
-		    "\txtalk connection point %v\n"
-		    "\twanted paddr [0x%x..0x%x]\n"
-		    "\txtalk_dmatrans_addr returned 0x%x\n"
-		    "\txio region outside direct32 target\n",
-		    pconn_vhdl, xconn_vhdl,
-		    paddr, paddr + req_size - 1,
-		    xio_addr);
-#endif
+
+	    PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl,
+			"pcibr_dmatrans_addr:  wanted paddr [0x%x..0x%x], "
+			"xio_port=0x%x, xio region outside direct32 target\n",
+			paddr, paddr + req_size - 1, xio_addr));
 	} else {
 	    pci_addr = slotp->bss_d32_base;
 	    if ((pci_addr != PCIBR_D32_BASE_UNSET) &&
@@ -3651,18 +4093,11 @@
 
 		pci_addr |= offset;
 
-#if DEBUG && PCIBR_DMA_DEBUG
-		printk("pcibr_dmatrans_addr: [reuse]\n"
-			"\tpciio connection point %v\n"
-			"\txtalk connection point %v\n"
-			"\twanted paddr [0x%x..0x%x]\n"
-			"\txtalk_dmatrans_addr returned 0x%x\n"
-			"\tmapped via direct32 offset 0x%x\n"
-			"\twill DMA via pci addr 0x%x\n",
-			pconn_vhdl, xconn_vhdl,
-			paddr, paddr + req_size - 1,
-			xio_addr, offset, pci_addr);
-#endif
+		PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl,
+                            "pcibr_dmatrans_addr:  wanted paddr [0x%x..0x%x], "
+                            "xio_port=0x%x, direct32: pci_addr=0x%x\n",
+                            paddr, paddr + req_size - 1, xio_addr, pci_addr));
+
 		return (pci_addr);
 	    }
 	    if (!pcibr_try_set_device(pcibr_soft, pciio_slot, flags, BRIDGE_DEV_D32_BITS)) {
@@ -3675,61 +4110,41 @@
 		/* Make sure we have an RRB (or two).
 		 */
 		if (!(pcibr_soft->bs_rrb_fixed & (1 << pciio_slot))) {
-		    have_rrbs = pcibr_soft->bs_rrb_valid[pciio_slot];
+		    have_rrbs = pcibr_soft->bs_rrb_valid[pciio_slot][vchan];
 		    if (have_rrbs < 2) {
 			if (slotp->bss_device & BRIDGE_DEV_PREF)
 			    min_rrbs = 2;
 			else
 			    min_rrbs = 1;
 			if (have_rrbs < min_rrbs)
-			    do_pcibr_rrb_autoalloc(pcibr_soft, pciio_slot, min_rrbs - have_rrbs);
+			    do_pcibr_rrb_autoalloc(pcibr_soft, pciio_slot, 
+						   vchan, min_rrbs - have_rrbs);
 		    }
 		}
-#if PCIBR_DMA_DEBUG
 #if HWG_PERF_CHECK
 		if (xio_addr != 0x20000000)
 #endif
-		    printk("pcibr_dmatrans_addr:\n"
-			    "\tpciio connection point %v\n"
-			    "\txtalk connection point %v\n"
-			    "\twanted paddr [0x%x..0x%x]\n"
-			    "\txtalk_dmatrans_addr returned 0x%x\n"
-			    "\tmapped via direct32 offset 0x%x\n"
-			    "\twill DMA via pci addr 0x%x\n"
-			    "\tnew flags: 0x%x\n",
-			    pconn_vhdl, xconn_vhdl,
-			    paddr, paddr + req_size - 1,
-			    xio_addr, offset, pci_addr, (uint64_t) flags);
-#endif
+                    PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl,
+                            "pcibr_dmatrans_addr:  wanted paddr [0x%x..0x%x], "
+                            "xio_port=0x%x, direct32: pci_addr=0x%x, "
+			    "new flags: 0x%x\n", paddr, paddr + req_size - 1,
+			    xio_addr, pci_addr, (uint64_t) flags));
+
 		return (pci_addr);
 	    }
 	    /* our flags conflict with Device(x).
 	     */
-#if PCIBR_DMA_DEBUG
-	    printk("pcibr_dmatrans_addr:\n"
-		    "\tpciio connection point %v\n"
-		    "\txtalk connection point %v\n"
-		    "\twanted paddr [0x%x..0x%x]\n"
-		    "\txtalk_dmatrans_addr returned 0x%x\n"
-		    "\tUnable to set Device(x) bits for Direct-32\n",
-		    pconn_vhdl, xconn_vhdl,
-		    paddr, paddr + req_size - 1,
-		    xio_addr);
-#endif
+	    PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl,
+                    "pcibr_dmatrans_addr:  wanted paddr [0x%x..0x%x], "
+                    "xio_port=0x%x, Unable to set direct32 Device(x) bits\n",
+                    paddr, paddr + req_size - 1, xio_port));
 	}
     }
 
-#if PCIBR_DMA_DEBUG
-    printk("pcibr_dmatrans_addr:\n"
-	    "\tpciio connection point %v\n"
-	    "\txtalk connection point %v\n"
-	    "\twanted paddr [0x%x..0x%x]\n"
-	    "\txtalk_dmatrans_addr returned 0x%x\n"
-	    "\tno acceptable PCI address found or constructable\n",
-	    pconn_vhdl, xconn_vhdl,
-	    paddr, paddr + req_size - 1,
-	    xio_addr);
-#endif
+    PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl,
+		"pcibr_dmatrans_addr:  wanted paddr [0x%x..0x%x], "
+		"xio_port=0x%x, No acceptable PCI address found\n",
+		paddr, paddr + req_size - 1, xio_port));
 
     return 0;
 }
@@ -3744,7 +4159,7 @@
     pciio_info_t            pciio_info = pciio_info_get(pconn_vhdl);
     pcibr_soft_t            pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);
     devfs_handle_t            xconn_vhdl = pcibr_soft->bs_conn;
-    pciio_slot_t            pciio_slot = pciio_info_slot_get(pciio_info);
+    pciio_slot_t            pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info);
     pcibr_soft_slot_t       slotp = &pcibr_soft->bs_slot[pciio_slot];
     xwidgetnum_t            xio_port;
 
@@ -3781,6 +4196,9 @@
 	    /* reuse previous base info */
 	} else if (pcibr_try_set_device(pcibr_soft, pciio_slot, flags, BRIDGE_DEV_D64_BITS) < 0) {
 	    /* DMA configuration conflict */
+	    PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl,
+			"pcibr_dmatrans_list: DMA configuration conflict "
+			"for direct64, flags=0x%x\n", flags));
 	    goto fail;
 	} else {
 	    relbits = BRIDGE_DEV_D64_BITS;
@@ -3796,6 +4214,9 @@
 	    /* reuse previous base info */
 	} else if (pcibr_try_set_device(pcibr_soft, pciio_slot, flags, BRIDGE_DEV_D32_BITS) < 0) {
 	    /* DMA configuration conflict */
+	    PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl,
+			"pcibr_dmatrans_list: DMA configuration conflict "
+			"for direct32, flags=0x%x\n", flags));
 	    goto fail;
 	} else {
 	    relbits = BRIDGE_DEV_D32_BITS;
@@ -3805,8 +4226,12 @@
 
     xtalk_alenlist = xtalk_dmatrans_list(xconn_vhdl, 0, palenlist,
 					 flags & DMAMAP_FLAGS);
-    if (!xtalk_alenlist)
+    if (!xtalk_alenlist) {
+	    PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl,
+			"pcibr_dmatrans_list: xtalk_dmatrans_list failed "
+			"xtalk_alenlist=0x%x\n", xtalk_alenlist));
 	goto fail;
+    }
 
     alenlist_cursor_init(xtalk_alenlist, 0, NULL);
 
@@ -3814,8 +4239,12 @@
 	pciio_alenlist = xtalk_alenlist;
     } else {
 	pciio_alenlist = alenlist_create(al_flags);
-	if (!pciio_alenlist)
+	if (!pciio_alenlist) {
+	    PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl,
+			"pcibr_dmatrans_list: alenlist_create failed with "
+			" 0x%x\n", pciio_alenlist));
 	    goto fail;
+	}
     }
 
     while (ALENLIST_SUCCESS ==
@@ -3827,16 +4256,8 @@
 	 */
 	if (XIO_PACKED(xio_addr)) {
 	    if (xio_addr == XIO_NOWHERE) {
-#if PCIBR_DMA_DEBUG
-		printk("pcibr_dmatrans_addr:\n"
-			"\tpciio connection point %v\n"
-			"\txtalk connection point %v\n"
-			"\twanted paddr [0x%x..0x%x]\n"
-			"\txtalk_dmatrans_addr returned 0x%x\n",
-			pconn_vhdl, xconn_vhdl,
-			paddr, paddr + req_size - 1,
-			xio_addr);
-#endif
+	        PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl,
+			"pcibr_dmatrans_list: xio_addr == XIO_NOWHERE\n"));
 		return 0;
 	    }
 	    xio_port = XIO_PORT(xio_addr);
@@ -3853,8 +4274,12 @@
 	 */
 	if (xio_port == pcibr_soft->bs_xid) {
 	    pci_addr = pcibr_addr_xio_to_pci(pcibr_soft, xio_addr, xio_size);
-	    if ( (pci_addr == (alenaddr_t)NULL) )
+	    if (pci_addr == (alenaddr_t)NULL) {
+	        PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl,
+			"pcibr_dmatrans_list: pcibr_addr_xio_to_pci failed "
+			"xio_addr=0x%x, xio_size=0x%x\n", xio_addr, xio_size));
 		goto fail;
+	    }
 	} else if (direct64) {
 	    ASSERT(xio_port != 0);
 	    pci_addr = pci_base | xio_addr
@@ -3866,8 +4291,14 @@
 	    if ((xio_size > map_size) ||
 		(xio_addr < xio_base) ||
 		(xio_port != pcibr_soft->bs_dir_xport) ||
-		(endoff > map_size))
+		(endoff > map_size)) {
+		PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl,
+			    "pcibr_dmatrans_list: xio_size > map_size fail\n"
+			    "xio_addr=0x%x, xio_size=0x%x. map_size=0x%x, "
+			    "xio_port=0x%x, endoff=0x%x\n", 
+			    xio_addr, xio_size, map_size, xio_port, endoff));
 		goto fail;
+	    }
 
 	    pci_addr = pci_base + (xio_addr - xio_base);
 	}
@@ -3878,13 +4309,19 @@
 	if (inplace) {
 	    if (ALENLIST_SUCCESS !=
 		alenlist_replace(pciio_alenlist, NULL,
-				 &pci_addr, &xio_size, al_flags))
+				 &pci_addr, &xio_size, al_flags)) {
+		PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl,
+			    "pcibr_dmatrans_list: alenlist_replace failed\n"));
 		goto fail;
+	    }
 	} else {
 	    if (ALENLIST_SUCCESS !=
 		alenlist_append(pciio_alenlist,
-				pci_addr, xio_size, al_flags))
+				pci_addr, xio_size, al_flags)) {
+		PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl,
+			    "pcibr_dmatrans_list: alenlist_append failed\n"));
 		goto fail;
+	    }
 	}
     }
 
@@ -3904,6 +4341,11 @@
      * to the caller.
      */
     alenlist_cursor_init(pciio_alenlist, 0, NULL);
+
+    PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl,
+		"pcibr_dmatrans_list: pciio_alenlist=0x%x\n",
+		 pciio_alenlist));
+
     return pciio_alenlist;
 
   fail:
@@ -3973,8 +4415,9 @@
 int
 pcibr_reset(devfs_handle_t conn)
 {
+#ifdef PIC_LATER
     pciio_info_t            pciio_info = pciio_info_get(conn);
-    pciio_slot_t            pciio_slot = pciio_info_slot_get(pciio_info);
+    pciio_slot_t            pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info);
     pcibr_soft_t            pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);
     bridge_t               *bridge = pcibr_soft->bs_base;
     bridgereg_t             ctlreg;
@@ -3984,42 +4427,59 @@
     pcibr_info_h            pcibr_infoh;
     pcibr_info_t            pcibr_info;
     int                     win;
+    int                     error = 0;
+#endif	/* PIC_LATER */
 
+	BUG();
+#ifdef PIC_LATER
     if (pcibr_soft->bs_slot[pciio_slot].has_host) {
 	pciio_slot = pcibr_soft->bs_slot[pciio_slot].host_slot;
 	pcibr_info = pcibr_soft->bs_slot[pciio_slot].bss_infos[0];
     }
-    if (pciio_slot < 4) {
+
+    if ((pciio_slot >= pcibr_soft->bs_first_slot) &&
+        (pciio_slot <= pcibr_soft->bs_last_reset)) {
 	s = pcibr_lock(pcibr_soft);
 	nf = pcibr_soft->bs_slot[pciio_slot].bss_ninfo;
 	pcibr_infoh = pcibr_soft->bs_slot[pciio_slot].bss_infos;
 	for (f = 0; f < nf; ++f)
 	    if (pcibr_infoh[f])
-		cfgctl[f] = bridge->b_type0_cfg_dev[pciio_slot].f[f].l[PCI_CFG_COMMAND / 4];
+		cfgctl[f] = pcibr_func_config_get(bridge, pciio_slot, f,
+							PCI_CFG_COMMAND/4);
+
+        error = iobrick_pci_slot_rst(pcibr_soft->bs_l1sc,
+                             pcibr_widget_to_bus(pcibr_soft->bs_vhdl),
+                             PCIBR_DEVICE_TO_SLOT(pcibr_soft,pciio_slot),
+                             NULL);
 
 	ctlreg = bridge->b_wid_control;
-	bridge->b_wid_control = ctlreg | BRIDGE_CTRL_RST(pciio_slot);
-	/* XXX delay? */
-	bridge->b_wid_control = ctlreg;
-	/* XXX delay? */
+	bridge->b_wid_control = ctlreg & ~BRIDGE_CTRL_RST_PIN(pciio_slot);
+        nano_delay(&ts);
+	bridge->b_wid_control = ctlreg | BRIDGE_CTRL_RST_PIN(pciio_slot);
+        nano_delay(&ts);
 
 	for (f = 0; f < nf; ++f)
 	    if ((pcibr_info = pcibr_infoh[f]))
 		for (win = 0; win < 6; ++win)
 		    if (pcibr_info->f_window[win].w_base != 0)
-			bridge->b_type0_cfg_dev[pciio_slot].f[f].l[PCI_CFG_BASE_ADDR(win) / 4] =
-			    pcibr_info->f_window[win].w_base;
+			pcibr_func_config_set(bridge, pciio_slot, f,
+					PCI_CFG_BASE_ADDR(win) / 4, 
+					pcibr_info->f_window[win].w_base);
 	for (f = 0; f < nf; ++f)
 	    if (pcibr_infoh[f])
-		bridge->b_type0_cfg_dev[pciio_slot].f[f].l[PCI_CFG_COMMAND / 4] = cfgctl[f];
+		pcibr_func_config_set(bridge, pciio_slot, f,
+					PCI_CFG_COMMAND / 4,
+					cfgctl[f]);
 	pcibr_unlock(pcibr_soft, s);
 
+	if (error)
+            return(-1);
+
 	return 0;
     }
-#ifdef SUPPORT_PRINTING_V_FORMAT
-    printk(KERN_WARNING   "%v: pcibr_reset unimplemented for slot %d\n",
-	    conn, pciio_slot);
-#endif
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DETACH, conn,
+    		"pcibr_reset unimplemented for slot %d\n", conn, pciio_slot));
+#endif	/* PIC_LATER */
     return -1;
 }
 
@@ -4029,7 +4489,7 @@
 		 pciio_endian_t desired_end)
 {
     pciio_info_t            pciio_info = pciio_info_get(pconn_vhdl);
-    pciio_slot_t            pciio_slot = pciio_info_slot_get(pciio_info);
+    pciio_slot_t            pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info);
     pcibr_soft_t            pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);
     bridgereg_t             devreg;
     unsigned long           s;
@@ -4053,16 +4513,32 @@
     if (pcibr_soft->bs_slot[pciio_slot].bss_device != devreg) {
 	bridge_t               *bridge = pcibr_soft->bs_base;
 
-	bridge->b_device[pciio_slot].reg = devreg;
-	pcibr_soft->bs_slot[pciio_slot].bss_device = devreg;
-	bridge->b_wid_tflush;		/* wait until Bridge PIO complete */
+	if ( IS_PIC_SOFT(pcibr_soft) ) {
+		bridge->b_device[pciio_slot].reg = devreg;
+		pcibr_soft->bs_slot[pciio_slot].bss_device = devreg;
+		bridge->b_wid_tflush;		/* wait until Bridge PIO complete */
+	}
+	else {
+		if (io_get_sh_swapper(NASID_GET(bridge))) {
+			BRIDGE_REG_SET32((&bridge->b_device[pciio_slot].reg)) = __swab32(devreg);
+			pcibr_soft->bs_slot[pciio_slot].bss_device = devreg;
+			BRIDGE_REG_GET32((&bridge->b_wid_tflush));/* wait until Bridge PIO complete */
+		} else {
+			bridge->b_device[pciio_slot].reg = devreg;
+			pcibr_soft->bs_slot[pciio_slot].bss_device = devreg;
+			bridge->b_wid_tflush;           /* wait until Bridge PIO complete */
+		}
+	}
     }
     pcibr_unlock(pcibr_soft, s);
 
-#if DEBUG && PCIBR_DEV_DEBUG
-    printk("pcibr Device(%d): 0x%p\n", pciio_slot, bridge->b_device[pciio_slot].reg);
+#ifdef PIC_LATER
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DEVREG, pconn_vhdl,
+    		"pcibr_endian_set: Device(%d): %x\n",
+		pciio_slot, devreg, device_bits));
+#else
+    printk("pcibr_endian_set: Device(%d): %x\n", pciio_slot, devreg);
 #endif
-
     return desired_end;
 }
 
@@ -4130,9 +4606,22 @@
     if (pcibr_soft->bs_slot[pciio_slot].bss_device != devreg) {
 	bridge_t               *bridge = pcibr_soft->bs_base;
 
-	bridge->b_device[pciio_slot].reg = devreg;
-	pcibr_soft->bs_slot[pciio_slot].bss_device = devreg;
-	bridge->b_wid_tflush;		/* wait until Bridge PIO complete */
+	if ( IS_PIC_SOFT(pcibr_soft) ) {
+		bridge->b_device[pciio_slot].reg = devreg;
+		pcibr_soft->bs_slot[pciio_slot].bss_device = devreg;
+		bridge->b_wid_tflush;		/* wait until Bridge PIO complete */
+	}
+	else {
+		if (io_get_sh_swapper(NASID_GET(bridge))) {
+			BRIDGE_REG_SET32((&bridge->b_device[pciio_slot].reg)) = __swab32(devreg);
+			pcibr_soft->bs_slot[pciio_slot].bss_device = devreg;
+			BRIDGE_REG_GET32((&bridge->b_wid_tflush));/* wait until Bridge PIO complete */
+		} else {
+			bridge->b_device[pciio_slot].reg = devreg;
+			pcibr_soft->bs_slot[pciio_slot].bss_device = devreg;
+			bridge->b_wid_tflush;           /* wait until Bridge PIO complete */
+		}
+	}
     }
     pcibr_unlock(pcibr_soft, s);
 
@@ -4144,7 +4633,7 @@
 		   pciio_priority_t device_prio)
 {
     pciio_info_t            pciio_info = pciio_info_get(pconn_vhdl);
-    pciio_slot_t            pciio_slot = pciio_info_slot_get(pciio_info);
+    pciio_slot_t            pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info);
     pcibr_soft_t            pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);
 
     (void) pcibr_priority_bits_set(pcibr_soft, pciio_slot, device_prio);
@@ -4168,7 +4657,7 @@
 		       pcibr_device_flags_t flags)
 {
     pciio_info_t            pciio_info = pciio_info_get(pconn_vhdl);
-    pciio_slot_t            pciio_slot = pciio_info_slot_get(pciio_info);
+    pciio_slot_t            pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info);
     pcibr_soft_t            pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);
     bridgereg_t             set = 0;
     bridgereg_t             clr = 0;
@@ -4215,18 +4704,81 @@
 	if (pcibr_soft->bs_slot[pciio_slot].bss_device != devreg) {
 	    bridge_t               *bridge = pcibr_soft->bs_base;
 
-	    bridge->b_device[pciio_slot].reg = devreg;
-	    pcibr_soft->bs_slot[pciio_slot].bss_device = devreg;
-	    bridge->b_wid_tflush;	/* wait until Bridge PIO complete */
+	    if ( IS_PIC_SOFT(pcibr_soft) ) {
+		bridge->b_device[pciio_slot].reg = devreg;
+		pcibr_soft->bs_slot[pciio_slot].bss_device = devreg;
+		bridge->b_wid_tflush;	/* wait until Bridge PIO complete */
+	    }
+	    else {
+		if (io_get_sh_swapper(NASID_GET(bridge))) {
+			BRIDGE_REG_SET32((&bridge->b_device[pciio_slot].reg)) = __swab32(devreg);
+			pcibr_soft->bs_slot[pciio_slot].bss_device = devreg;
+			BRIDGE_REG_GET32((&bridge->b_wid_tflush));/* wait until Bridge PIO complete */
+		} else {
+			bridge->b_device[pciio_slot].reg = devreg;
+			pcibr_soft->bs_slot[pciio_slot].bss_device = devreg;
+			bridge->b_wid_tflush;       /* wait until Bridge PIO complete */
+		}
+	    }
 	}
 	pcibr_unlock(pcibr_soft, s);
-#if DEBUG && PCIBR_DEV_DEBUG
-	printk("pcibr Device(%d): %R\n", pciio_slot, bridge->b_device[pciio_slot].regbridge->b_device[pciio_slot].reg, device_bits);
+#ifdef PIC_LATER
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DEVREG, pconn_vhdl,
+		    "pcibr_device_flags_set: Device(%d): %x\n",
+		    pciio_slot, devreg, device_bits));
+#else
+	printk("pcibr_device_flags_set: Device(%d): %x\n", pciio_slot, devreg);
 #endif
     }
     return (1);
 }
 
+/*
+ * PIC has 16 RBARs per bus; meaning it can have a total of 16 outstanding 
+ * split transactions.  If the functions on the bus have requested a total 
+ * of 16 or less, then we can give them what they requested (ie. 100%). 
+ * Otherwise we have make sure each function can get at least one buffer
+ * and then divide the rest of the buffers up among the functions as ``A 
+ * PERCENTAGE OF WHAT THEY REQUESTED'' (i.e. 0% - 100% of a function's
+ * pcix_type0_status.max_out_split).  This percentage does not include the
+ * one RBAR that all functions get by default.
+ */
+int
+pcibr_pcix_rbars_calc(pcibr_soft_t pcibr_soft)
+{
+    /* 'percent_allowed' is the percentage of requested RBARs that functions
+     * are allowed, ***less the 1 RBAR that all functions get by default***
+     */
+    int percent_allowed; 
+
+    if (pcibr_soft->bs_pcix_num_funcs) {
+	if (pcibr_soft->bs_pcix_num_funcs > NUM_RBAR) {
+	    printk(KERN_WARNING
+		"%lx: Must oversubscribe Read Buffer Attribute Registers"
+		"(RBAR).  Bus has %d RBARs but %d funcs need them.\n",
+		(unsigned long)pcibr_soft->bs_vhdl, NUM_RBAR, pcibr_soft->bs_pcix_num_funcs);
+	    percent_allowed = 0;
+	} else {
+	    percent_allowed = (((NUM_RBAR-pcibr_soft->bs_pcix_num_funcs)*100) /
+		               pcibr_soft->bs_pcix_split_tot);
+
+	    /* +1 to percentage to solve rounding errors that occur because
+	     * we're not doing fractional math. (ie. ((3 * 66%) / 100) = 1)
+	     * but should be "2" if doing true fractional math.  NOTE: Since
+	     * the greatest number of outstanding transactions a function 
+	     * can request is 32, this "+1" will always work (i.e. we won't
+	     * accidentally oversubscribe the RBARs because of this rounding
+	     * of the percentage).
+	     */
+	    percent_allowed=(percent_allowed > 100) ? 100 : percent_allowed+1;
+	}
+    } else {
+	return(ENODEV);
+    }
+
+    return(percent_allowed);
+}
+
 pciio_provider_t        pcibr_provider =
 {
     (pciio_piomap_alloc_f *) pcibr_piomap_alloc,
@@ -4262,17 +4814,17 @@
     (pciio_priority_set_f *) pcibr_priority_set,
     (pciio_config_get_f *) pcibr_config_get,
     (pciio_config_set_f *) pcibr_config_set,
-
-    (pciio_error_devenable_f *) 0,
-    (pciio_error_extract_f *) 0,
-
-#ifdef LATER
+#ifdef PIC_LATER
+    (pciio_error_devenable_f *) pcibr_error_devenable,
+    (pciio_error_extract_f *) pcibr_error_extract,
     (pciio_driver_reg_callback_f *) pcibr_driver_reg_callback,
     (pciio_driver_unreg_callback_f *) pcibr_driver_unreg_callback,
 #else
+    (pciio_error_devenable_f *) 0,
+    (pciio_error_extract_f *) 0,
     (pciio_driver_reg_callback_f *) 0,
     (pciio_driver_unreg_callback_f *) 0,
-#endif
+#endif	/* PIC_LATER */
     (pciio_device_unregister_f 	*) pcibr_device_unregister,
     (pciio_dma_enabled_f		*) pcibr_dma_enabled,
 };
@@ -4286,3 +4838,83 @@
 
     return xtalk_dma_enabled(pcibr_soft->bs_conn);
 }
+
+
+/*
+ * pcibr_debug() is used to print pcibr debug messages to the console.  A
+ * user enables tracing by setting the following global variables:
+ *
+ *    pcibr_debug_mask 	   -Bitmask of what to trace. see pcibr_private.h
+ *    pcibr_debug_module   -Module to trace.  'all' means trace all modules
+ *    pcibr_debug_widget   -Widget to trace. '-1' means trace all widgets
+ *    pcibr_debug_slot	   -Slot to trace.  '-1' means trace all slots
+ *
+ * 'type' is the type of debugging that the current PCIBR_DEBUG macro is
+ * tracing.  'vhdl' (which can be NULL) is the vhdl associated with the
+ * debug statement.  If there is a 'vhdl' associated with this debug
+ * statement, it is parsed to obtain the module, widget, and slot.  If the
+ * globals above match the PCIBR_DEBUG params, then the debug info in the
+ * parameter 'format' is sent to the console.
+ */
+void
+pcibr_debug(uint32_t type, devfs_handle_t vhdl, char *format, ...)
+{
+    char hwpath[MAXDEVNAME] = "\0";
+    char copy_of_hwpath[MAXDEVNAME];
+    char *module = "all";
+    short widget = -1;
+    short slot = -1;
+    va_list ap;
+    char *strtok_r(char *string, const char *sepset, char **lasts);
+
+    if (pcibr_debug_mask & type) {
+        if (vhdl) {
+            if (!hwgraph_vertex_name_get(vhdl, hwpath, MAXDEVNAME)) {
+                char *cp;
+
+                if (strcmp(module, pcibr_debug_module)) {
+		    /* strtok_r() wipes out string, use a copy */
+                    (void)strcpy(copy_of_hwpath, hwpath);
+                    cp = strstr(copy_of_hwpath, "/module/");
+                    if (cp) {
+                        char *last = NULL;
+                        cp += strlen("/module");
+                        module = strtok_r(cp, "/", &last);
+                    }
+                }
+                if (pcibr_debug_widget != -1) {
+                    cp = strstr(hwpath, "/xtalk/");
+                    if (cp) {
+                        cp += strlen("/xtalk/");
+                        widget = atoi(cp);
+                    }
+                }
+                if (pcibr_debug_slot != -1) {
+                    cp = strstr(hwpath, "/pci/");
+                    if (cp) {
+                        cp += strlen("/pci/");
+                        slot = atoi(cp);
+                    }
+                }
+            }
+        }
+        if ((vhdl == NULL) ||
+            (!strcmp(module, pcibr_debug_module) &&
+             (widget == pcibr_debug_widget) &&
+             (slot == pcibr_debug_slot))) {
+#ifdef LATER
+            printk("PCIBR_DEBUG<%d>\t: %s :", cpuid(), hwpath);
+#else
+            printk("PCIBR_DEBUG\t: %s :", hwpath);
+#endif
+	    /*
+	     * Kernel printk translates to this 3 line sequence.
+	     * Since we have a variable length argument list, we
+	     * need to call printk this way rather than directly
+	     */
+	    va_start(ap, format);
+	    printk(format, ap);
+	    va_end(ap);
+        }
+    }
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/pcibr_error.c linux-2.4.21-pre6/arch/ia64/sn/io/sn2/pcibr/pcibr_error.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/pcibr_error.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn2/pcibr/pcibr_error.c	2003-03-26 23:49:25.000000000 +0000
@@ -39,6 +39,14 @@
 #endif
 
 extern int	hubii_check_widget_disabled(nasid_t, int);
+#ifdef BRIDGE_B_DATACORR_WAR
+extern int              ql_bridge_rev_b_war(devfs_handle_t);
+extern int              bridge_rev_b_data_check_disable;
+char                   *rev_b_datacorr_warning =
+"***************************** WARNING! ******************************\n";
+char                   *rev_b_datacorr_mesg =
+"UNRECOVERABLE IO LINK ERROR. CONTACT SERVICE PROVIDER\n";
+#endif
 
 /* =====================================================================
  *    ERROR HANDLING
@@ -54,15 +62,18 @@
 #define BRIDGE_PIOERR_TIMEOUT	1	/* Timeout in non-debug mode                            */
 #endif
 
+/* PIC has 64bit interrupt error registers, but BRIDGE has 32bit registers.
+ * Thus 'bridge_errors_to_dump needs' to default to the larger of the two.
+ */
 #ifdef  DEBUG
 #ifdef ERROR_DEBUG
-bridgereg_t bridge_errors_to_dump = ~BRIDGE_ISR_INT_MSK;
+uint64_t bridge_errors_to_dump = ~BRIDGE_ISR_INT_MSK;
 #else
-bridgereg_t bridge_errors_to_dump = BRIDGE_ISR_ERROR_DUMP;
+uint64_t bridge_errors_to_dump = BRIDGE_ISR_ERROR_DUMP;
 #endif
 #else
-bridgereg_t bridge_errors_to_dump = BRIDGE_ISR_ERROR_FATAL |
-                                BRIDGE_ISR_PCIBUS_PIOERR;
+uint64_t bridge_errors_to_dump = BRIDGE_ISR_ERROR_FATAL |
+                                   BRIDGE_ISR_PCIBUS_PIOERR;
 #endif
 
 #if defined (PCIBR_LLP_CONTROL_WAR)
@@ -71,8 +82,6 @@
 
 /* FIXME: can these arrays be local ? */
 
-#ifdef LATER
-
 struct reg_values xio_cmd_pactyp[] =
 {
     {0x0, "RdReq"},
@@ -113,7 +122,21 @@
 
 struct reg_desc         bridge_int_status_desc[] =
 {
-    F(31, "MULTI_ERR"),
+    F(45, "PCI_X_SPLIT_MES_PE"),/* PIC ONLY */
+    F(44, "PCI_X_SPLIT_EMES"),	/* PIC ONLY */
+    F(43, "PCI_X_SPLIT_TO"),	/* PIC ONLY */
+    F(42, "PCI_X_UNEX_COMP"),	/* PIC ONLY */
+    F(41, "INT_RAM_PERR"),	/* PIC ONLY */
+    F(40, "PCI_X_ARB_ERR"),	/* PIC ONLY */
+    F(39, "PCI_X_REQ_TOUT"),	/* PIC ONLY */
+    F(38, "PCI_X_TABORT"),	/* PIC ONLY */
+    F(37, "PCI_X_PERR"),	/* PIC ONLY */
+    F(36, "PCI_X_SERR"),	/* PIC ONLY */
+    F(35, "PCI_X_MRETRY"),	/* PIC ONLY */
+    F(34, "PCI_X_MTOUT"),	/* PIC ONLY */
+    F(33, "PCI_X_DA_PARITY"),	/* PIC ONLY */
+    F(32, "PCI_X_AD_PARITY"),	/* PIC ONLY */
+    F(31, "MULTI_ERR"),		/* BRIDGE ONLY */
     F(30, "PMU_ESIZE_EFAULT"),
     F(29, "UNEXPECTED_RESP"),
     F(28, "BAD_XRESP_PACKET"),
@@ -128,7 +151,7 @@
     F(19, "LLP_RCTY"),
     F(18, "LLP_TX_RETRY"),
     F(17, "LLP_TCTY"),
-    F(16, "SSRAM_PERR"),
+    F(16, "SSRAM_PERR"),	/* BRIDGE ONLY */
     F(15, "PCI_ABORT"),
     F(14, "PCI_PARITY"),
     F(13, "PCI_SERR"),
@@ -136,7 +159,7 @@
     F(11, "PCI_MASTER_TOUT"),
     F(10, "PCI_RETRY_CNT"),
     F(9, "XREAD_REQ_TOUT"),
-    F(8, "GIO_BENABLE_ERR"),
+    F(8, "GIO_BENABLE_ERR"),	/* BRIDGE ONLY */
     F(7, "INT7"),
     F(6, "INT6"),
     F(5, "INT5"),
@@ -195,20 +218,17 @@
     {0}
 };
 
-#endif	/* LATER */
-
 void
 print_bridge_errcmd(uint32_t cmdword, char *errtype)
 {
-    printk(
-	    "\t    Bridge %s Error Command Word Register %R\n",
-	    errtype, cmdword, xio_cmd_bits);
+    printk("\t    Bridge %s Error Command Word Register ", errtype);
+    print_register(cmdword, xio_cmd_bits);
 }
 
 char             *pcibr_isr_errs[] =
 {
     "", "", "", "", "", "", "", "",
-    "08: GIO non-contiguous byte enable in crosstalk packet",
+    "08: GIO non-contiguous byte enable in crosstalk packet", /* BRIDGE ONLY */
     "09: PCI to Crosstalk read request timeout",
     "10: PCI retry operation count exhausted.",
     "11: PCI bus device select timeout",
@@ -216,7 +236,7 @@
     "13: PCI Address/Cmd parity error ",
     "14: PCI Bridge detected parity error",
     "15: PCI abort condition",
-    "16: SSRAM parity error",
+    "16: SSRAM parity error", /* BRIDGE ONLY */
     "17: LLP Transmitter Retry count wrapped",
     "18: LLP Transmitter side required Retry",
     "19: LLP Receiver retry count wrapped",
@@ -231,13 +251,29 @@
     "28: Framing error, response cmd data size does not match actual",
     "29: Unexpected response arrived",
     "30: PMU Access Fault",
-    "31: Multiple errors occurred",
+    "31: Multiple errors occurred", /* BRIDGE ONLY */
+    
+    /* bits 32-45 are PIC ONLY */
+    "32: PCI-X address or attribute cycle parity error",
+    "33: PCI-X data cycle parity error",
+    "34: PCI-X master timeout (ie. master abort)",
+    "35: PCI-X pio retry counter exhausted",
+    "36: PCI-X SERR",
+    "37: PCI-X PERR", 
+    "38: PCI-X target abort",
+    "39: PCI-X read request timeout",
+    "40: PCI / PCI-X device requestin arbitration error",
+    "41: internal RAM parity error",
+    "42: PCI-X unexpected completion cycle to master",
+    "43: PCI-X split completion timeout",
+    "44: PCI-X split completion error message",
+    "45: PCI-X split completion message parity error",
 };
 
 #define BEM_ADD_STR(s)  printk("%s", (s))
-#define BEM_ADD_VAR(v)  printk("\t%20s: 0x%x\n", #v, (v))
-#define BEM_ADD_REG(r)  printk("\t%20s: %R\n", #r, (r), r ## _desc)
-#define BEM_ADD_NSPC(n,s)       printk("\t%20s: %R\n", n, s, space_desc)
+#define BEM_ADD_VAR(v)  printk("\t%20s: 0x%llx\n", #v, ((unsigned long long)v))
+#define BEM_ADD_REG(r)  printk("\t%20s: ", #r); print_register((r), r ## _desc)
+#define BEM_ADD_NSPC(n,s)       printk("\t%20s: ", n); print_register(s, space_desc)
 #define BEM_ADD_SPC(s)          BEM_ADD_NSPC(#s, s)
 
 /*
@@ -246,6 +282,7 @@
 void
 pcibr_show_dir_state(paddr_t paddr, char *prefix)
 {
+#ifdef LATER
 	int state;
 	uint64_t vec_ptr;
 	hubreg_t elo;
@@ -254,8 +291,9 @@
 
 	get_dir_ent(paddr, &state, &vec_ptr, &elo);
 
-	printf("%saddr 0x%x: state 0x%x owner 0x%x (%s)\n", 
+	printk("%saddr 0x%lx: state 0x%x owner 0x%lx (%s)\n", 
 		prefix, paddr, state, vec_ptr, dir_state_str[state]);
+#endif
 }
 
 
@@ -267,40 +305,70 @@
 pcibr_error_dump(pcibr_soft_t pcibr_soft)
 {
     bridge_t               *bridge = pcibr_soft->bs_base;
-    bridgereg_t             int_status;
-    bridgereg_t             mult_int;
-    int			    bit;
+    uint64_t		    int_status;
+    bridgereg_t             int_status_32;
+    picreg_t		    int_status_64;
+    uint64_t		    mult_int;
+    bridgereg_t             mult_int_32;
+    picreg_t		    mult_int_64;
+    uint64_t		    bit;
+    int			    number_bits;
     int                     i;
     char		    *reg_desc;
-    paddr_t		    addr;
+    paddr_t		    addr = (paddr_t)0;
+
+    /* We read the INT_STATUS register as a 64bit picreg_t for PIC and a
+     * 32bit bridgereg_t for BRIDGE, but always process the result as a
+     * 64bit value so the code can be "common" for both PIC and BRIDGE...
+     */
+    if (IS_PIC_SOFT(pcibr_soft)) {
+	int_status_64 = (bridge->p_int_status_64 & ~BRIDGE_ISR_INT_MSK);
+	int_status = (uint64_t)int_status_64;
+	number_bits = PCIBR_ISR_MAX_ERRS_PIC;
+    } else {
+	int_status_32 = (bridge->b_int_status & ~BRIDGE_ISR_INT_MSK);
+	int_status = ((uint64_t)int_status_32) & 0xffffffff;
+	number_bits = PCIBR_ISR_MAX_ERRS_BRIDGE;
+    }
 
-    int_status = (bridge->b_int_status & ~BRIDGE_ISR_INT_MSK);
     if (!int_status) {
 	/* No error bits set */
 	return;
     }
 
     /* Check if dumping the same error information multiple times */
-    if (test_and_set_int((int *) &pcibr_soft->bs_errinfo.bserr_intstat,
-	    int_status) == int_status) {
+    if ( pcibr_soft->bs_errinfo.bserr_intstat == int_status )
 	return;
-    }
+    pcibr_soft->bs_errinfo.bserr_intstat = int_status;
 
-    printk(KERN_ALERT "PCI BRIDGE ERROR: int_status is 0x%X for %s\n"
-	"    Dumping relevant %sBridge registers for each bit set...\n",
+    printk(KERN_ALERT "PCI BRIDGE ERROR: int_status is 0x%lx for %s\n"
+	"    Dumping relevant %s registers for each bit set...\n",
 	    int_status, pcibr_soft->bs_name,
-	    (is_xbridge(bridge) ? "X" : ""));
+	    (IS_PIC_SOFT(pcibr_soft) ? "PIC" : 
+	        (IS_BRIDGE_SOFT(pcibr_soft) ? "BRIDGE" : "XBRIDGE")));
 
-    for (i = PCIBR_ISR_ERR_START; i < PCIBR_ISR_MAX_ERRS; i++) {
-	bit = 1 << i;
+    for (i = PCIBR_ISR_ERR_START; i < number_bits; i++) {
+	bit = 1ull << i;
 
 	/*
 	 * A number of int_status bits are only defined for Bridge.
-	 * Ignore them in the case of an XBridge.
+	 * Ignore them in the case of an XBridge or PIC.
 	 */
-	if (is_xbridge(bridge) && ((bit == BRIDGE_ISR_MULTI_ERR) ||
-		(bit == BRIDGE_ISR_SSRAM_PERR) ||
-		(bit == BRIDGE_ISR_GIO_B_ENBL_ERR))) {
+	if ((IS_XBRIDGE_SOFT(pcibr_soft) || IS_PIC_SOFT(pcibr_soft)) &&
+	    ((bit == BRIDGE_ISR_MULTI_ERR) ||
+	     (bit == BRIDGE_ISR_SSRAM_PERR) ||
+	     (bit == BRIDGE_ISR_GIO_B_ENBL_ERR))) {
+	    continue;
+	}
+
+	/* A number of int_status bits are only valid for PIC's bus0 */
+	if ((IS_PIC_SOFT(pcibr_soft) && (pcibr_soft->bs_busnum != 0)) && 
+	    ((bit == BRIDGE_ISR_UNSUPPORTED_XOP) ||
+	     (bit == BRIDGE_ISR_LLP_REC_SNERR) ||
+	     (bit == BRIDGE_ISR_LLP_REC_CBERR) ||
+	     (bit == BRIDGE_ISR_LLP_RCTY) ||
+	     (bit == BRIDGE_ISR_LLP_TX_RETRY) ||
+	     (bit == BRIDGE_ISR_LLP_TCTY))) {
 	    continue;
 	}
 
@@ -308,91 +376,241 @@
 	    printk("\t%s\n", pcibr_isr_errs[i]);
 
 	    switch (bit) {
-	    case BRIDGE_ISR_PAGE_FAULT:		/* PMU_PAGE_FAULT  (XBridge) */
-/*	    case BRIDGE_ISR_PMU_ESIZE_FAULT:	   PMU_ESIZE_FAULT (Bridge) */
-		if (is_xbridge(bridge))
+
+	    case PIC_ISR_INT_RAM_PERR:	    /* bit41	INT_RAM_PERR */
+		/* XXX: should breakdown meaning of bits in reg */
+		printk( "\t	Internal RAM Parity Error: 0x%lx\n",
+		    bridge->p_ate_parity_err_64);
+		break;
+
+	    case PIC_ISR_PCIX_ARB_ERR:	    /* bit40	PCI_X_ARB_ERR */
+		/* XXX: should breakdown meaning of bits in reg */
+		printk( "\t	Arbitration Reg: 0x%x\n",
+		    bridge->b_arb);
+		break;
+
+	    case PIC_ISR_PCIX_REQ_TOUT:	    /* bit39	PCI_X_REQ_TOUT */
+		/* XXX: should breakdown meaning of attribute bit */
+		printk(
+		    "\t	   PCI-X DMA Request Error Address Reg: 0x%lx\n"
+		    "\t	   PCI-X DMA Request Error Attribute Reg: 0x%lx\n",
+		    bridge->p_pcix_dma_req_err_addr_64,
+		    bridge->p_pcix_dma_req_err_attr_64);
+		break;
+
+	    case PIC_ISR_PCIX_SPLIT_MSG_PE: /* bit45	PCI_X_SPLIT_MES_PE */
+	    case PIC_ISR_PCIX_SPLIT_EMSG:   /* bit44	PCI_X_SPLIT_EMESS */
+	    case PIC_ISR_PCIX_SPLIT_TO:	    /* bit43	PCI_X_SPLIT_TO */
+		/* XXX: should breakdown meaning of attribute bit */
+		printk(
+		    "\t	   PCI-X Split Request Address Reg: 0x%lx\n"
+		    "\t	   PCI-X Split Request Attribute Reg: 0x%lx\n",
+		    bridge->p_pcix_pio_split_addr_64,
+		    bridge->p_pcix_pio_split_attr_64);
+		/* FALL THRU */
+
+	    case PIC_ISR_PCIX_UNEX_COMP:    /* bit42	PCI_X_UNEX_COMP */
+	    case PIC_ISR_PCIX_TABORT:	    /* bit38	PCI_X_TABORT */
+	    case PIC_ISR_PCIX_PERR:	    /* bit37	PCI_X_PERR */
+	    case PIC_ISR_PCIX_SERR:	    /* bit36	PCI_X_SERR */
+	    case PIC_ISR_PCIX_MRETRY:	    /* bit35	PCI_X_MRETRY */
+	    case PIC_ISR_PCIX_MTOUT:	    /* bit34	PCI_X_MTOUT */
+	    case PIC_ISR_PCIX_DA_PARITY:    /* bit33	PCI_X_DA_PARITY */
+	    case PIC_ISR_PCIX_AD_PARITY:    /* bit32	PCI_X_AD_PARITY */
+		/* XXX: should breakdown meaning of attribute bit */
+		printk(
+		    "\t	   PCI-X Bus Error Address Reg: 0x%lx\n"
+		    "\t	   PCI-X Bus Error Attribute Reg: 0x%lx\n"
+		    "\t	   PCI-X Bus Error Data Reg: 0x%lx\n",
+		    bridge->p_pcix_bus_err_addr_64,
+		    bridge->p_pcix_bus_err_attr_64,
+		    bridge->p_pcix_bus_err_data_64);
+		break;
+
+	    case BRIDGE_ISR_PAGE_FAULT:	    /* bit30	PMU_PAGE_FAULT */
+/*	    case BRIDGE_ISR_PMU_ESIZE_FAULT:   bit30	PMU_ESIZE_FAULT */
+		if (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft))
 		    reg_desc = "Map Fault Address";
 		else
 		    reg_desc = "SSRAM Parity Error";
 
-		printk("\t    %s Register: 0x%x\n", reg_desc,
+		printk( "\t    %s Register: 0x%x\n", reg_desc,
 		    bridge->b_ram_perr_or_map_fault);
 		break;
 
-	    case BRIDGE_ISR_UNEXP_RESP:		/* UNEXPECTED_RESP */
-		print_bridge_errcmd(bridge->b_wid_aux_err, "Aux");
-		break;
+	    case BRIDGE_ISR_UNEXP_RESP:    /* bit29	UNEXPECTED_RESP */
+		print_bridge_errcmd(bridge->b_wid_aux_err, "Aux ");
 
-	    case BRIDGE_ISR_BAD_XRESP_PKT:		/* BAD_RESP_PACKET */
-	    case BRIDGE_ISR_RESP_XTLK_ERR:		/* RESP_XTALK_ERROR */
-	    case BRIDGE_ISR_XREAD_REQ_TIMEOUT:		/* XREAD_REQ_TOUT */
+		/* PIC in PCI-X mode, dump the PCIX DMA Request registers */
+		if (IS_PIC_SOFT(pcibr_soft) && IS_PCIX(pcibr_soft)) {
+		    /* XXX: should breakdown meaning of attr bit */
+		    printk( 
+			"\t    PCI-X DMA Request Error Addr Reg: 0x%lx\n"
+			"\t    PCI-X DMA Request Error Attr Reg: 0x%lx\n",
+			bridge->p_pcix_dma_req_err_addr_64,
+			bridge->p_pcix_dma_req_err_attr_64);
+		}
+		break;
 
-		addr = (((uint64_t) (bridge->b_wid_resp_upper & 0xFFFF) << 32)
-			| bridge->b_wid_resp_lower);
-		printk(
-		    "\t    Bridge Response Buffer Error Upper Address Register: 0x%x\n"
-		    "\t    Bridge Response Buffer Error Lower Address Register: 0x%x\n"
-		    "\t    dev-num %d buff-num %d addr 0x%x\n",
-		    bridge->b_wid_resp_upper, bridge->b_wid_resp_lower,
-		    ((bridge->b_wid_resp_upper >> 20) & 0x3),
-		    ((bridge->b_wid_resp_upper >> 16) & 0xF),
-		    addr);
+	    case BRIDGE_ISR_BAD_XRESP_PKT:  /* bit28	BAD_RESP_PACKET */
+	    case BRIDGE_ISR_RESP_XTLK_ERR:  /* bit26	RESP_XTALK_ERROR */
+		if (IS_PIC_SOFT(pcibr_soft)) {
+		    print_bridge_errcmd(bridge->b_wid_aux_err, "Aux ");
+		}
+		 
+		/* If PIC in PCI-X mode, DMA Request Error registers are
+		 * valid.  But PIC in PCI mode, Response Buffer Address 
+		 * register are valid.
+		 */
+		if (IS_PCIX(pcibr_soft)) {
+		    /* XXX: should breakdown meaning of attribute bit */
+		    printk( 
+			"\t    PCI-X DMA Request Error Addr Reg: 0x%lx\n"
+		        "\t    PCI-X DMA Request Error Attribute Reg: 0x%lx\n",
+		        bridge->p_pcix_dma_req_err_addr_64,
+		        bridge->p_pcix_dma_req_err_attr_64);
+		} else {
+		    addr= (((uint64_t)(bridge->b_wid_resp_upper & 0xFFFF)<<32)
+			   | bridge->b_wid_resp_lower);
+		    printk("\t    Bridge Response Buf Error Upper Addr Reg: 0x%x\n"
+		        "\t    Bridge Response Buf Error Lower Addr Reg: 0x%x\n"
+		        "\t    dev-num %d buff-num %d addr 0x%lx\n",
+		        bridge->b_wid_resp_upper, bridge->b_wid_resp_lower,
+		        ((bridge->b_wid_resp_upper >> 20) & 0x3),
+		        ((bridge->b_wid_resp_upper >> 16) & 0xF),
+		        addr);
+		}
 		if (bit == BRIDGE_ISR_RESP_XTLK_ERR) {
 			/* display memory directory associated with cacheline */
 			pcibr_show_dir_state(addr, "\t    ");
 		}
 		break;
 
-	    case BRIDGE_ISR_BAD_XREQ_PKT:		/* BAD_XREQ_PACKET */
-	    case BRIDGE_ISR_REQ_XTLK_ERR:		/* REQ_XTALK_ERROR */
-	    case BRIDGE_ISR_INVLD_ADDR:			/* INVALID_ADDRESS */
-	    case BRIDGE_ISR_UNSUPPORTED_XOP:		/* UNSUPPORTED_XOP */
-		print_bridge_errcmd(bridge->b_wid_aux_err, "");
-		printk("\t    Bridge Error Upper Address Register: 0x%x\n"
-		    "\t    Bridge Error Lower Address Register: 0x%x\n"
-		    "\t    Bridge Error Address: 0x%x\n",
+	    case BRIDGE_ISR_BAD_XREQ_PKT:   /* bit27	BAD_XREQ_PACKET */
+	    case BRIDGE_ISR_REQ_XTLK_ERR:   /* bit25	REQ_XTALK_ERROR */
+	    case BRIDGE_ISR_INVLD_ADDR:	    /* bit24	INVALID_ADDRESS */
+		print_bridge_errcmd(bridge->b_wid_err_cmdword, "");
+		printk( 
+		    "\t    Bridge Error Upper Address Register: 0x%lx\n"
+		    "\t    Bridge Error Lower Address Register: 0x%lx\n"
+		    "\t    Bridge Error Address: 0x%lx\n",
 		    (uint64_t) bridge->b_wid_err_upper,
 		    (uint64_t) bridge->b_wid_err_lower,
 		    (((uint64_t) bridge->b_wid_err_upper << 32) |
 		    bridge->b_wid_err_lower));
 		break;
 
-	    case BRIDGE_ISR_SSRAM_PERR:			/* SSRAM_PERR */
-		if (!is_xbridge(bridge)) {	/* only defined on Bridge */
+	    case BRIDGE_ISR_UNSUPPORTED_XOP:/* bit23	UNSUPPORTED_XOP */
+		if (IS_PIC_SOFT(pcibr_soft)) {
+		    print_bridge_errcmd(bridge->b_wid_aux_err, "Aux ");
+		    printk( 
+			"\t    Address Holding Link Side Error Reg: 0x%lx\n",
+			bridge->p_addr_lkerr_64);
+		} else {
+		    print_bridge_errcmd(bridge->b_wid_err_cmdword, "");
+		    printk( 
+			"\t    Bridge Error Upper Address Register: 0x%lx\n"
+		        "\t    Bridge Error Lower Address Register: 0x%lx\n"
+		        "\t    Bridge Error Address: 0x%lx\n",
+		        (uint64_t) bridge->b_wid_err_upper,
+		        (uint64_t) bridge->b_wid_err_lower,
+		        (((uint64_t) bridge->b_wid_err_upper << 32) |
+		        bridge->b_wid_err_lower));
+		}
+		break;
+
+	    case BRIDGE_ISR_XREQ_FIFO_OFLOW:/* bit22	XREQ_FIFO_OFLOW */
+		/* Link side error registers are only valid for PIC */
+		if (IS_PIC_SOFT(pcibr_soft)) {
+		    print_bridge_errcmd(bridge->b_wid_aux_err, "Aux ");
+		    printk(
+			"\t    Address Holding Link Side Error Reg: 0x%lx\n",
+			bridge->p_addr_lkerr_64);
+		}
+		break;
+
+	    case BRIDGE_ISR_SSRAM_PERR:	    /* bit16	SSRAM_PERR */
+		if (IS_BRIDGE_SOFT(pcibr_soft)) {
 		    printk(
 			"\t    Bridge SSRAM Parity Error Register: 0x%x\n",
 			bridge->b_ram_perr);
 		}
 		break;
 
-	    case BRIDGE_ISR_PCI_ABORT:			/* PCI_ABORT */
-	    case BRIDGE_ISR_PCI_PARITY:			/* PCI_PARITY */
-	    case BRIDGE_ISR_PCI_SERR:			/* PCI_SERR */
-	    case BRIDGE_ISR_PCI_PERR:			/* PCI_PERR */
-	    case BRIDGE_ISR_PCI_MST_TIMEOUT:		/* PCI_MASTER_TOUT */
-	    case BRIDGE_ISR_PCI_RETRY_CNT:		/* PCI_RETRY_CNT */
-	    case BRIDGE_ISR_GIO_B_ENBL_ERR:		/* GIO BENABLE_ERR */
-		printk("\t    PCI Error Upper Address Register: 0x%x\n"
-		    "\t    PCI Error Lower Address Register: 0x%x\n"
-		    "\t    PCI Error Address: 0x%x\n",
+	    case BRIDGE_ISR_PCI_ABORT:	    /* bit15	PCI_ABORT */
+	    case BRIDGE_ISR_PCI_PARITY:	    /* bit14	PCI_PARITY */
+	    case BRIDGE_ISR_PCI_SERR:	    /* bit13	PCI_SERR */
+	    case BRIDGE_ISR_PCI_PERR:	    /* bit12	PCI_PERR */
+	    case BRIDGE_ISR_PCI_MST_TIMEOUT:/* bit11	PCI_MASTER_TOUT */
+	    case BRIDGE_ISR_PCI_RETRY_CNT:  /* bit10	PCI_RETRY_CNT */
+	    case BRIDGE_ISR_GIO_B_ENBL_ERR: /* bit08	GIO BENABLE_ERR */
+		printk( 
+		    "\t    PCI Error Upper Address Register: 0x%lx\n"
+		    "\t    PCI Error Lower Address Register: 0x%lx\n"
+		    "\t    PCI Error Address: 0x%lx\n",
 		    (uint64_t) bridge->b_pci_err_upper,
 		    (uint64_t) bridge->b_pci_err_lower,
 		    (((uint64_t) bridge->b_pci_err_upper << 32) |
 		    bridge->b_pci_err_lower));
 		break;
+
+	    case BRIDGE_ISR_XREAD_REQ_TIMEOUT: /* bit09	XREAD_REQ_TOUT */
+		addr = (((uint64_t)(bridge->b_wid_resp_upper & 0xFFFF) << 32)
+		    | bridge->b_wid_resp_lower);
+		printk(
+		    "\t    Bridge Response Buf Error Upper Addr Reg: 0x%x\n"
+		    "\t    Bridge Response Buf Error Lower Addr Reg: 0x%x\n"
+		    "\t    dev-num %d buff-num %d addr 0x%lx\n",
+		    bridge->b_wid_resp_upper, bridge->b_wid_resp_lower,
+		    ((bridge->b_wid_resp_upper >> 20) & 0x3),
+		    ((bridge->b_wid_resp_upper >> 16) & 0xF),
+		    addr);
+		break;
 	    }
 	}
     }
 
-    if (is_xbridge(bridge) && (bridge->b_mult_int & ~BRIDGE_ISR_INT_MSK)) {
-	mult_int = bridge->b_mult_int;
-	printk("    XBridge Multiple Interrupt Register is 0x%x\n",
-		mult_int);
-	for (i = PCIBR_ISR_ERR_START; i < PCIBR_ISR_MAX_ERRS; i++) {
-	    if (mult_int & (1 << i))
-		printk("\t%s\n", pcibr_isr_errs[i]);
-	    }
+    /* We read the INT_MULT register as a 64bit picreg_t for PIC and a
+     * 32bit bridgereg_t for BRIDGE, but always process the result as a
+     * 64bit value so the code can be "common" for both PIC and BRIDGE...
+     */
+    if (IS_PIC_SOFT(pcibr_soft)) {
+	mult_int_64 = (bridge->p_mult_int_64 & ~BRIDGE_ISR_INT_MSK);
+	mult_int = (uint64_t)mult_int_64;
+	number_bits = PCIBR_ISR_MAX_ERRS_PIC;
+    } else {
+	mult_int_32 = (bridge->b_mult_int & ~BRIDGE_ISR_INT_MSK);
+	mult_int = ((uint64_t)mult_int_32) & 0xffffffff;
+	number_bits = PCIBR_ISR_MAX_ERRS_BRIDGE;
+    }
+
+    if (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft)&&(mult_int & ~BRIDGE_ISR_INT_MSK)) {
+	printk( "    %s Multiple Interrupt Register is 0x%lx\n",
+		IS_PIC_SOFT(pcibr_soft) ? "PIC" : "XBridge", mult_int);
+	for (i = PCIBR_ISR_ERR_START; i < number_bits; i++) {
+	    if (mult_int & (1ull << i))
+		printk( "\t%s\n", pcibr_isr_errs[i]);
 	}
+    }
+
+#if BRIDGE_ERROR_INTR_WAR
+    if (pcibr_soft->bs_rev_num == BRIDGE_PART_REV_A) {	/* known bridge bug */
+	/*
+	 * Should never receive interrupts for these reasons on Rev 1 bridge
+	 * as they are not enabled. Assert for it.
+	 */
+	ASSERT((int_status & (BRIDGE_IMR_PCI_MST_TIMEOUT |
+			      BRIDGE_ISR_RESP_XTLK_ERR |
+			      BRIDGE_ISR_LLP_TX_RETRY)) == 0);
+    }
+    if (pcibr_soft->bs_rev_num < BRIDGE_PART_REV_C) {	/* known bridge bug */
+	/*
+	 * This interrupt is turned off at init time. So, should never
+	 * see this interrupt.
+	 */
+	ASSERT((int_status & BRIDGE_ISR_BAD_XRESP_PKT) == 0);
+    }
+#endif
 }
 
 #define PCIBR_ERRINTR_GROUP(error)	\
@@ -430,9 +648,11 @@
 pcibr_pioerr_check(pcibr_soft_t soft)
 {
     bridge_t		   *bridge;
-    bridgereg_t		    b_int_status;
-    bridgereg_t		    b_pci_err_lower;
-    bridgereg_t		    b_pci_err_upper;
+    uint64_t              int_status;
+    bridgereg_t             int_status_32;
+    picreg_t                int_status_64;
+    bridgereg_t		    pci_err_lower;
+    bridgereg_t		    pci_err_upper;
     iopaddr_t		    pci_addr;
     pciio_slot_t	    slot;
     pcibr_piomap_t	    map;
@@ -442,40 +662,48 @@
     int			    func;
 
     bridge = soft->bs_base;
-    b_int_status = bridge->b_int_status;
-    if (b_int_status & BRIDGE_ISR_PCIBUS_PIOERR) {
-	b_pci_err_lower = bridge->b_pci_err_lower;
-	b_pci_err_upper = bridge->b_pci_err_upper;
-	b_int_status = bridge->b_int_status;
-	if (b_int_status & BRIDGE_ISR_PCIBUS_PIOERR) {
-
-	    pci_addr = b_pci_err_upper & BRIDGE_ERRUPPR_ADDRMASK;
-	    pci_addr = (pci_addr << 32) | b_pci_err_lower;
-
-	    slot = 8;
-	    while (slot-- > 0) {
-		int 		nfunc = soft->bs_slot[slot].bss_ninfo;
-		pcibr_info_h	pcibr_infoh = soft->bs_slot[slot].bss_infos;
-
-		for (func = 0; func < nfunc; func++) {
-		    pcibr_info_t 	pcibr_info = pcibr_infoh[func];
-
-		    if (!pcibr_info)
-			continue;
-
-		    for (map = pcibr_info->f_piomap;
-			 map != NULL; map = map->bp_next) {
-			base = map->bp_pciaddr;
-			size = map->bp_mapsz;
-			win = map->bp_space - PCIIO_SPACE_WIN(0);
-			if (win < 6)
-			    base += 
-				soft->bs_slot[slot].bss_window[win].bssw_base;
-			else if (map->bp_space == PCIIO_SPACE_ROM)
-			    base += pcibr_info->f_rbase;
-			if ((pci_addr >= base) && (pci_addr < (base + size)))
-			    atomicAddInt(map->bp_toc, 1);
-		    }
+
+    /* We read the INT_STATUS register as a 64bit picreg_t for PIC and a
+     * 32bit bridgereg_t for BRIDGE, but always process the result as a
+     * 64bit value so the code can be "common" for both PIC and BRIDGE...
+     */
+    if (IS_PIC_SOFT(soft)) {
+        int_status_64 = (bridge->p_int_status_64 & ~BRIDGE_ISR_INT_MSK);
+        int_status = (uint64_t)int_status_64;
+    } else {
+        int_status_32 = (bridge->b_int_status & ~BRIDGE_ISR_INT_MSK);
+        int_status = ((uint64_t)int_status_32) & 0xffffffff;
+    }
+
+    if (int_status & BRIDGE_ISR_PCIBUS_PIOERR) {
+	pci_err_lower = bridge->b_pci_err_lower;
+	pci_err_upper = bridge->b_pci_err_upper;
+
+	pci_addr = pci_err_upper & BRIDGE_ERRUPPR_ADDRMASK;
+	pci_addr = (pci_addr << 32) | pci_err_lower;
+
+	slot = PCIBR_NUM_SLOTS(soft);
+	while (slot-- > 0) {
+	    int 		nfunc = soft->bs_slot[slot].bss_ninfo;
+	    pcibr_info_h	pcibr_infoh = soft->bs_slot[slot].bss_infos;
+
+	    for (func = 0; func < nfunc; func++) {
+		pcibr_info_t 	pcibr_info = pcibr_infoh[func];
+
+		if (!pcibr_info)
+		    continue;
+
+		for (map = pcibr_info->f_piomap;
+		        map != NULL; map = map->bp_next) {
+		    base = map->bp_pciaddr;
+		    size = map->bp_mapsz;
+		    win = map->bp_space - PCIIO_SPACE_WIN(0);
+		    if (win < 6)
+			base += soft->bs_slot[slot].bss_window[win].bssw_base;
+		    else if (map->bp_space == PCIIO_SPACE_ROM)
+			base += pcibr_info->f_rbase;
+		    if ((pci_addr >= base) && (pci_addr < (base + size)))
+			atomic_inc(&map->bp_toc[0]);
 		}
 	    }
 	}
@@ -502,25 +730,33 @@
  *                due to read or write error!.
  */
 
-
 void
-pcibr_error_intr_handler(intr_arg_t arg)
+pcibr_error_intr_handler(int irq, void *arg, struct pt_regs *ep)
 {
     pcibr_soft_t            pcibr_soft;
     bridge_t               *bridge;
-    bridgereg_t             int_status;
-    bridgereg_t             err_status;
+    uint64_t              int_status;
+    uint64_t              err_status;
+    bridgereg_t             int_status_32;
+    picreg_t                int_status_64;
+    int			    number_bits;
     int                     i;
 
     /* REFERENCED */
-    bridgereg_t             disable_errintr_mask = 0;
+    uint64_t		    disable_errintr_mask = 0;
+#ifdef EHE_ENABLE
     int 		    rv;
     int 		    error_code = IOECODE_DMA | IOECODE_READ;
     ioerror_mode_t 	    mode = MODE_DEVERROR;
     ioerror_t 	            ioe;
+#endif /* EHE_ENABLE */
     nasid_t		    nasid;
 
+
 #if PCIBR_SOFT_LIST
+    /*
+     * Defensive code for linked pcibr_soft structs
+     */
     {
 	extern pcibr_list_p	pcibr_list;
 	pcibr_list_p            entry;
@@ -528,17 +764,14 @@
 	entry = pcibr_list;
 	while (1) {
 	    if (entry == NULL) {
-		PRINT_PANIC(
-			"pcibr_error_intr_handler:\n"
-			"\tmy parameter (0x%x) is not a pcibr_soft!",
-			arg);
+		PRINT_PANIC("pcibr_error_intr_handler:\tmy parameter (0x%p) is not a pcibr_soft!", arg);
 	    }
 	    if ((intr_arg_t) entry->bl_soft == arg)
 		break;
 	    entry = entry->bl_next;
 	}
     }
-#endif
+#endif /* PCIBR_SOFT_LIST */
     pcibr_soft = (pcibr_soft_t) arg;
     bridge = pcibr_soft->bs_base;
 
@@ -568,16 +801,37 @@
 
     nasid = NASID_GET(bridge);
     if (hubii_check_widget_disabled(nasid, pcibr_soft->bs_xid)) {
-	timeout(pcibr_error_intr_handler, pcibr_soft, BRIDGE_PIOERR_TIMEOUT);
+	DECLARE_WAIT_QUEUE_HEAD(wq);
+	sleep_on_timeout(&wq, BRIDGE_PIOERR_TIMEOUT*HZ );  /* sleep */
 	pcibr_soft->bs_errinfo.bserr_toutcnt++;
+	/* Let's go recursive */
+	return(pcibr_error_intr_handler(irq, arg, ep));
+#ifdef LATER
+	timeout(pcibr_error_intr_handler, pcibr_soft, BRIDGE_PIOERR_TIMEOUT);
+#endif
 	return;
     }
 
+    /* We read the INT_STATUS register as a 64bit picreg_t for PIC and a
+     * 32bit bridgereg_t for BRIDGE, but always process the result as a
+     * 64bit value so the code can be "common" for both PIC and BRIDGE...
+     */
+    if (IS_PIC_SOFT(pcibr_soft)) {
+        int_status_64 = (bridge->p_int_status_64 & ~BRIDGE_ISR_INT_MSK);
+        int_status = (uint64_t)int_status_64;
+        number_bits = PCIBR_ISR_MAX_ERRS_PIC;
+    } else {
+        int_status_32 = (bridge->b_int_status & ~BRIDGE_ISR_INT_MSK);
+        int_status = ((uint64_t)int_status_32) & 0xffffffff;
+        number_bits = PCIBR_ISR_MAX_ERRS_BRIDGE;
+    }
+
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ERROR, pcibr_soft->bs_conn,
+		"pcibr_error_intr_handler: int_status=0x%x\n", int_status));
+
     /* int_status is which bits we have to clear;
      * err_status is the bits we haven't handled yet.
      */
-
-    int_status = bridge->b_int_status &  ~BRIDGE_ISR_INT_MSK;
     err_status = int_status & ~BRIDGE_ISR_MULTI_ERR;
 
     if (!(int_status & ~BRIDGE_ISR_INT_MSK)) {
@@ -593,11 +847,29 @@
 	pcibr_pioerr_check(pcibr_soft);
     }
 
+#ifdef BRIDGE_B_DATACORR_WAR
+    if ((pcibr_soft->bs_rev_num == BRIDGE_PART_REV_B) &&
+	(err_status & BRIDGE_IMR_LLP_REC_CBERR)) {
+	if (bridge_rev_b_data_check_disable)
+	    printk(KERN_WARNING "\n%s%s: %s%s\n", rev_b_datacorr_warning,
+		    pcibr_soft->bs_name, rev_b_datacorr_mesg,
+		    rev_b_datacorr_warning);
+	else {
+	    ql_bridge_rev_b_war(pcibr_soft->bs_vhdl);
+	    PRINT_PANIC( "\n%s%s: %s%s\n", rev_b_datacorr_warning,
+		    pcibr_soft->bs_name, rev_b_datacorr_mesg,
+		    rev_b_datacorr_warning);
+	}
+
+	err_status &= ~BRIDGE_IMR_LLP_REC_CBERR;
+    }
+#endif				/* BRIDGE_B_DATACORR_WAR */
+
     if (err_status) {
 	struct bs_errintr_stat_s *bs_estat = pcibr_soft->bs_errintr_stat;
 
-	for (i = PCIBR_ISR_ERR_START; i < PCIBR_ISR_MAX_ERRS; i++, bs_estat++) {
-	    if (err_status & (1 << i)) {
+	for (i = PCIBR_ISR_ERR_START; i < number_bits; i++, bs_estat++) {
+	    if (err_status & (1ull << i)) {
 		uint32_t              errrate = 0;
 		uint32_t              errcount = 0;
 		uint32_t              errinterval = 0, current_tick = 0;
@@ -606,12 +878,14 @@
 
 		bs_estat->bs_errcount_total++;
 
-		current_tick = lbolt;
+		current_tick = jiffies;
 		errinterval = (current_tick - bs_estat->bs_lasterr_timestamp);
 		errcount = (bs_estat->bs_errcount_total -
 			    bs_estat->bs_lasterr_snapshot);
 
-		is_llp_tx_retry_intr = (BRIDGE_ISR_LLP_TX_RETRY == (1 << i));
+		/* LLP interrrupt errors are only valid on BUS0 of the PIC */
+		if (pcibr_soft->bs_busnum == 0)
+		    is_llp_tx_retry_intr = (BRIDGE_ISR_LLP_TX_RETRY==(1ull << i));
 
 		/* Check for the divide by zero condition while
 		 * calculating the error rates.
@@ -698,6 +972,15 @@
 			    bs_estat->bs_errcount_total;
 		    }
 		}
+		/* PIC BRINGUP WAR (PV# 856155):
+		 * Dont disable PCI_X_ARB_ERR interrupts, we need the
+		 * interrupt inorder to clear the DEV_BROKE bits in
+		 * b_arb register to re-enable the device.
+		 */
+		if (IS_PIC_SOFT(pcibr_soft) &&
+				!(err_status & PIC_ISR_PCIX_ARB_ERR) &&
+				PCIBR_WAR_ENABLED(PV856155, pcibr_soft)) {
+
 		if (bs_estat->bs_errcount_total > PCIBR_ERRINTR_DISABLE_LEVEL) {
 		    /*
 		     * We have seen a fairly large number of errors of
@@ -709,18 +992,26 @@
 			    pcibr_soft->bs_name,
 			    pcibr_isr_errs[i],
 			    bs_estat->bs_errcount_total);
-		    disable_errintr_mask |= (1 << i);
+		    disable_errintr_mask |= (1ull << i);
 		}
+		} /* PIC: WAR for PV 856155 end-of-if */
 	    }
 	}
     }
 
     if (disable_errintr_mask) {
+	unsigned s;
 	/*
 	 * Disable some high frequency errors as they
 	 * could eat up too much cpu time.
 	 */
-	bridge->b_int_enable &= ~disable_errintr_mask;
+	s = pcibr_lock(pcibr_soft);
+	if (IS_PIC_SOFT(pcibr_soft)) {
+	    bridge->p_int_enable_64 &= (picreg_t)(~disable_errintr_mask);
+	} else {
+	    bridge->b_int_enable &= (bridgereg_t)(~disable_errintr_mask);
+	}
+	pcibr_unlock(pcibr_soft, s);
     }
     /*
      * If we leave the PROM cacheable, T5 might
@@ -783,15 +1074,34 @@
     if (rv != IOERROR_HANDLED) {
 #endif /* EHE_ENABLE */
 
+    bridge_errors_to_dump |= BRIDGE_ISR_PCIBUS_PIOERR;
+
     /* Dump/Log Bridge error interrupt info */
     if (err_status & bridge_errors_to_dump) {
-	printk("BRIDGE ERR_STATUS 0x%x\n", err_status);
+	printk("BRIDGE ERR_STATUS 0x%lx\n", err_status);
 	pcibr_error_dump(pcibr_soft);
     }
 
+    /* PIC BRINGUP WAR (PV# 867308):
+     * Make BRIDGE_ISR_LLP_REC_SNERR & BRIDGE_ISR_LLP_REC_CBERR fatal errors
+     * so we know we've hit the problem defined in PV 867308 that we believe
+     * has only been seen in simulation
+     */
+    if (IS_PIC_SOFT(pcibr_soft) && PCIBR_WAR_ENABLED(PV867308, pcibr_soft) &&
+        (err_status & (BRIDGE_ISR_LLP_REC_SNERR | BRIDGE_ISR_LLP_REC_CBERR))) {
+        printk("BRIDGE ERR_STATUS 0x%x\n", err_status);
+        pcibr_error_dump(pcibr_soft);
+#ifdef LATER
+        machine_error_dump("");
+#endif
+        PRINT_PANIC("PCI Bridge Error interrupt killed the system");
+    }
+
     if (err_status & BRIDGE_ISR_ERROR_FATAL) {
+#ifdef LATER
 	machine_error_dump("");
-	cmn_err_tag(14, CE_PANIC, "PCI Bridge Error interrupt killed the system");
+#endif
+	PRINT_PANIC("PCI Bridge Error interrupt killed the system");
 	    /*NOTREACHED */
     }
 
@@ -804,11 +1114,27 @@
      * it would cause problems for devices like IOC3 (Lost
      * interrupts ?.). So, just cleanup the interrupt, and
      * use saved values later..
+     * 
+     * PIC doesn't require groups of interrupts to be cleared...
      */
-    bridge->b_int_rst_stat = pcibr_errintr_group(int_status);
+    if (IS_PIC_SOFT(pcibr_soft)) {
+	bridge->p_int_rst_stat_64 = (picreg_t)(int_status | BRIDGE_IRR_MULTI_CLR);
+    } else {
+	bridge->b_int_rst_stat = (bridgereg_t)pcibr_errintr_group(int_status);
+    }
+
+    /* PIC BRINGUP WAR (PV# 856155):
+     * On a PCI_X_ARB_ERR error interrupt clear the DEV_BROKE bits from
+     * the b_arb register to re-enable the device.
+     */
+    if (IS_PIC_SOFT(pcibr_soft) &&
+		(err_status & PIC_ISR_PCIX_ARB_ERR) &&
+		PCIBR_WAR_ENABLED(PV856155, pcibr_soft)) {
+	bridge->b_arb |= (0xf << 20);
+    }
 
     /* Zero out bserr_intstat field */
-    test_and_set_int((int *) &pcibr_soft->bs_errinfo.bserr_intstat, 0);
+    pcibr_soft->bs_errinfo.bserr_intstat = 0;
 }
 
 /*
@@ -832,7 +1158,7 @@
 		  iopaddr_t *offsetp,
 		  pciio_function_t *funcp)
 {
-    int                     s, f, w;
+    int                     s, f = 0, w;
     iopaddr_t               base;
     size_t                  size;
     pciio_piospace_t        piosp;
@@ -864,7 +1190,7 @@
 
 	return s;
     }
-    for (s = 0; s < 8; s++) {
+    for (s = pcibr_soft->bs_min_slot; s < PCIBR_NUM_SLOTS(pcibr_soft); ++s) {
 	int                     nf = pcibr_soft->bs_slot[s].bss_ninfo;
 	pcibr_info_h            pcibr_infoh = pcibr_soft->bs_slot[s].bss_infos;
 
@@ -874,8 +1200,7 @@
 	    if (!pcibr_info)
 		continue;
 	    for (w = 0; w < 6; w++) {
-		if (pcibr_info->f_window[w].w_space
-		    == PCIIO_SPACE_NONE) {
+		if (pcibr_info->f_window[w].w_space == PCIIO_SPACE_NONE) {
 		    continue;
 		}
 		base = pcibr_info->f_window[w].w_base;
@@ -898,7 +1223,7 @@
      * Check if the address was allocated as part of the
      * pcibr_piospace_alloc calls.
      */
-    for (s = 0; s < 8; s++) {
+    for (s = pcibr_soft->bs_min_slot; s < PCIBR_NUM_SLOTS(pcibr_soft); ++s) {
 	int                     nf = pcibr_soft->bs_slot[s].bss_ninfo;
 	pcibr_info_h            pcibr_infoh = pcibr_soft->bs_slot[s].bss_infos;
 
@@ -950,8 +1275,14 @@
     ASSERT(error_code & IOECODE_PIO);
     error_code = error_code;
 
-    bridge->b_int_rst_stat =
-	(BRIDGE_IRR_PCI_GRP_CLR | BRIDGE_IRR_MULTI_CLR);
+    if (IS_PIC_SOFT(pcibr_soft)) {
+        bridge->p_int_rst_stat_64 = BRIDGE_IRR_PCI_GRP_CLR |
+				    PIC_PCIX_GRP_CLR |
+				    BRIDGE_IRR_MULTI_CLR;
+    } else {
+        bridge->b_int_rst_stat = BRIDGE_IRR_PCI_GRP_CLR | BRIDGE_IRR_MULTI_CLR;
+    }
+
     (void) bridge->b_wid_tflush;	/* flushbus */
 }
 
@@ -1040,13 +1371,6 @@
  *      associated with this device.
  */
 
-#define BEM_ADD_STR(s)	printk("%s", (s))
-#define BEM_ADD_VAR(v)	printk("\t%20s: 0x%x\n", #v, (v))
-#define BEM_ADD_REG(r)	printk("\t%20s: %R\n", #r, (r), r ## _desc)
-
-#define BEM_ADD_NSPC(n,s)	printk("\t%20s: %R\n", n, s, space_desc)
-#define BEM_ADD_SPC(s)		BEM_ADD_NSPC(#s, s)
-
 /* BEM_ADD_IOE doesn't dump the whole ioerror, it just
  * decodes the PCI specific portions -- we count on our
  * callers to dump the raw IOE data.
@@ -1054,40 +1378,38 @@
 #define BEM_ADD_IOE(ioe)						\
 	do {								\
 	    if (IOERROR_FIELDVALID(ioe, busspace)) {			\
-		unsigned		spc;				\
-		unsigned		win;				\
+		iopaddr_t		spc;				\
+		iopaddr_t		win;				\
+		short			widdev;				\
+		iopaddr_t		busaddr;			\
 									\
-		spc = IOERROR_GETVALUE(ioe, busspace);			\
+		IOERROR_GETVALUE(spc, ioe, busspace);			\
 		win = spc - PCIIO_SPACE_WIN(0);				\
+		IOERROR_GETVALUE(busaddr, ioe, busaddr);		\
+		IOERROR_GETVALUE(widdev, ioe, widgetdev);		\
 									\
 		switch (spc) {						\
 		case PCIIO_SPACE_CFG:					\
-		    printk(					\
-			    "\tPCI Slot %d Func %d CFG space Offset 0x%x\n",	\
-	    pciio_widgetdev_slot_get(IOERROR_GETVALUE(ioe, widgetdev)),	\
-	    pciio_widgetdev_func_get(IOERROR_GETVALUE(ioe, widgetdev)),	\
-			    IOERROR_GETVALUE(ioe, busaddr));		\
+		    printk("\tPCI Slot %d Func %d CFG space Offset 0x%lx\n",\
+			    	pciio_widgetdev_slot_get(widdev),	\
+	    			pciio_widgetdev_func_get(widdev),	\
+				busaddr);				\
 		    break;						\
 		case PCIIO_SPACE_IO:					\
-		    printk(					\
-			    "\tPCI I/O space  Offset 0x%x\n",		\
-			    IOERROR_GETVALUE(ioe, busaddr));		\
+		    printk("\tPCI I/O space  Offset 0x%lx\n", busaddr);	\
 		    break;						\
 		case PCIIO_SPACE_MEM:					\
 		case PCIIO_SPACE_MEM32:					\
 		case PCIIO_SPACE_MEM64:					\
-		    printk(					\
-			    "\tPCI MEM space Offset 0x%x\n",		\
-			    IOERROR_GETVALUE(ioe, busaddr));		\
+		    printk("\tPCI MEM space Offset 0x%lx\n", busaddr);	\
 		    break;						\
 		default:						\
 		    if (win < 6) {					\
-		    printk(					\
-			    "\tPCI Slot %d Func %d Window %d Offset 0x%x\n",\
-	    pciio_widgetdev_slot_get(IOERROR_GETVALUE(ioe, widgetdev)),	\
-	    pciio_widgetdev_func_get(IOERROR_GETVALUE(ioe, widgetdev)),	\
-			    win,					\
-			    IOERROR_GETVALUE(ioe, busaddr));		\
+		    printk("\tPCI Slot %d Func %d Window %ld Offset 0x%lx\n",\
+	    			pciio_widgetdev_slot_get(widdev),	\
+	    			pciio_widgetdev_func_get(widdev),	\
+			    	win,					\
+			    	busaddr);				\
 		    }							\
 		    break;						\
 		}							\
@@ -1129,34 +1451,38 @@
      * and need to construct the slot/space/offset.
      */
 
-    bad_xaddr = IOERROR_GETVALUE(ioe, xtalkaddr);
+    IOERROR_GETVALUE(bad_xaddr, ioe, xtalkaddr);
+
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ERROR_HDLR, pcibr_soft->bs_conn,
+                "pcibr_pioerror: pcibr_soft=0x%x, bad_xaddr=0x%x\n",
+		pcibr_soft, bad_xaddr));
 
     slot = PCIIO_SLOT_NONE;
     func = PCIIO_FUNC_NONE;
     raw_space = PCIIO_SPACE_NONE;
     raw_paddr = 0;
 
-    if ((bad_xaddr >= BRIDGE_TYPE0_CFG_DEV0) &&
-	(bad_xaddr < BRIDGE_TYPE1_CFG)) {
-	raw_paddr = bad_xaddr - BRIDGE_TYPE0_CFG_DEV0;
+    if ((bad_xaddr >= PCIBR_BUS_TYPE0_CFG_DEV0(pcibr_soft)) &&
+	(bad_xaddr < PCIBR_TYPE1_CFG(pcibr_soft))) {
+	raw_paddr = bad_xaddr - PCIBR_BUS_TYPE0_CFG_DEV0(pcibr_soft);
 	slot = raw_paddr / BRIDGE_TYPE0_CFG_SLOT_OFF;
 	raw_paddr = raw_paddr % BRIDGE_TYPE0_CFG_SLOT_OFF;
 	raw_space = PCIIO_SPACE_CFG;
     }
-    if ((bad_xaddr >= BRIDGE_TYPE1_CFG) &&
-	(bad_xaddr < (BRIDGE_TYPE1_CFG + 0x1000))) {
+    if ((bad_xaddr >= PCIBR_TYPE1_CFG(pcibr_soft)) &&
+	(bad_xaddr < (PCIBR_TYPE1_CFG(pcibr_soft) + 0x1000))) {
 	/* Type 1 config space:
 	 * slot and function numbers not known.
 	 * Perhaps we can read them back?
 	 */
-	raw_paddr = bad_xaddr - BRIDGE_TYPE1_CFG;
+	raw_paddr = bad_xaddr - PCIBR_TYPE1_CFG(pcibr_soft);
 	raw_space = PCIIO_SPACE_CFG;
     }
-    if ((bad_xaddr >= BRIDGE_DEVIO0) &&
-	(bad_xaddr < BRIDGE_DEVIO(BRIDGE_DEV_CNT))) {
+    if ((bad_xaddr >= PCIBR_BRIDGE_DEVIO0(pcibr_soft)) &&
+	(bad_xaddr < PCIBR_BRIDGE_DEVIO(pcibr_soft, BRIDGE_DEV_CNT))) {
 	int                     x;
 
-	raw_paddr = bad_xaddr - BRIDGE_DEVIO0;
+	raw_paddr = bad_xaddr - PCIBR_BRIDGE_DEVIO0(pcibr_soft);
 	x = raw_paddr / BRIDGE_DEVIO_OFF;
 	raw_paddr %= BRIDGE_DEVIO_OFF;
 	/* first two devio windows are double-sized */
@@ -1223,7 +1549,9 @@
 	 * going on (no guessing).
 	 */
 
-	for (cs = 0; (cs < 8) && (slot == PCIIO_SLOT_NONE); cs++) {
+	for (cs = pcibr_soft->bs_min_slot; 
+		(cs < PCIBR_NUM_SLOTS(pcibr_soft)) && 
+					(slot == PCIIO_SLOT_NONE); cs++) {
 	    int                     nf = pcibr_soft->bs_slot[cs].bss_ninfo;
 	    pcibr_info_h            pcibr_infoh = pcibr_soft->bs_slot[cs].bss_infos;
 
@@ -1283,7 +1611,8 @@
      * strict count, the excess counts are not a
      * problem.
      */
-    for (cs = 0; cs < 8; ++cs) {
+    for (cs = pcibr_soft->bs_min_slot; 
+				cs < PCIBR_NUM_SLOTS(pcibr_soft); ++cs) {
 	int 		nf = pcibr_soft->bs_slot[cs].bss_ninfo;
 	pcibr_info_h	pcibr_infoh = pcibr_soft->bs_slot[cs].bss_infos;
 
@@ -1313,7 +1642,7 @@
 		wx = PCIIO_SPACE_MEM;
 	    wl = wb + ws;
 	    if ((wx == raw_space) && (raw_paddr >= wb) && (raw_paddr < wl)) {
-		atomicAddInt(map->bp_toc, 1);
+		atomic_inc(&map->bp_toc[0]);
 		if (slot == PCIIO_SLOT_NONE) {
 		    slot = cs;
 		    space = map->bp_space;
@@ -1325,15 +1654,21 @@
 	}
     }
 
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ERROR_HDLR, pcibr_soft->bs_conn,
+                "pcibr_pioerror: offset=0x%x, slot=0x%x, func=0x%x\n",
+		offset, slot, func));
+
     if (space != PCIIO_SPACE_NONE) {
-	if (slot != PCIIO_SLOT_NONE) 
-	    if (func != PCIIO_FUNC_NONE)
+	if (slot != PCIIO_SLOT_NONE) {
+	    if (func != PCIIO_FUNC_NONE) {
 		IOERROR_SETVALUE(ioe, widgetdev, 
 				 pciio_widgetdev_create(slot,func));
-	    else
+	    }
+	    else {
     		IOERROR_SETVALUE(ioe, widgetdev, 
 				 pciio_widgetdev_create(slot,0));
-
+	    }
+	}
 	IOERROR_SETVALUE(ioe, busspace, space);
 	IOERROR_SETVALUE(ioe, busaddr, offset);
     }
@@ -1360,7 +1695,7 @@
 
     if (space == PCIIO_SPACE_NONE) {
 	printk("XIO Bus Error at %s\n"
-		"\taccess to XIO bus offset 0x%x\n"
+		"\taccess to XIO bus offset 0x%lx\n"
 		"\tdoes not correspond to any PCI address\n",
 		pcibr_soft->bs_name, bad_xaddr);
 
@@ -1434,17 +1769,21 @@
 	     */
 
 	    BEM_ADD_STR("Raw info from Bridge/PCI layer:\n");
-	    if (bridge->b_int_status & BRIDGE_ISR_PCIBUS_PIOERR)
-		pcibr_error_dump(pcibr_soft);
+	    if (IS_PIC_SOFT(pcibr_soft)) {
+		if (bridge->p_int_status_64 & (picreg_t)BRIDGE_ISR_PCIBUS_PIOERR)
+		    pcibr_error_dump(pcibr_soft);
+	    } else {
+		if (bridge->b_int_status & (bridgereg_t)BRIDGE_ISR_PCIBUS_PIOERR)
+		    pcibr_error_dump(pcibr_soft);
+	    }
 	    BEM_ADD_SPC(raw_space);
 	    BEM_ADD_VAR(raw_paddr);
 	    if (IOERROR_FIELDVALID(ioe, widgetdev)) {
-
-		slot = pciio_widgetdev_slot_get(IOERROR_GETVALUE(ioe, 
-								 widgetdev));
-		func = pciio_widgetdev_func_get(IOERROR_GETVALUE(ioe, 
-								 widgetdev));
-		if (slot < 8) {
+		short widdev;
+		IOERROR_GETVALUE(widdev, ioe, widgetdev);
+		slot = pciio_widgetdev_slot_get(widdev);
+		func = pciio_widgetdev_func_get(widdev);
+		if (slot < PCIBR_NUM_SLOTS(pcibr_soft)) {
 		    bridgereg_t             device = bridge->b_device[slot].reg;
 
 		    BEM_ADD_VAR(slot);
@@ -1472,11 +1811,12 @@
 	 *      Need a way to ensure we don't inadvertently clear some
 	 *      other errors.
 	 */
-	if (IOERROR_FIELDVALID(ioe, widgetdev))
-	    pcibr_device_disable(pcibr_soft, 
-				 pciio_widgetdev_slot_get(
-					  IOERROR_GETVALUE(ioe, widgetdev)));
-
+	if (IOERROR_FIELDVALID(ioe, widgetdev)) {
+		short widdev;
+		IOERROR_GETVALUE(widdev, ioe, widgetdev);
+		pcibr_device_disable(pcibr_soft, 
+				 pciio_widgetdev_slot_get(widdev));
+	}
 	if (mode == MODE_DEVUSERERROR)
 	    pcibr_error_cleanup(pcibr_soft, error_code);
     }
@@ -1490,8 +1830,6 @@
  *      and try to invoke the appropriate bus service to handle this.
  */
 
-#define BRIDGE_DMA_READ_ERROR (BRIDGE_ISR_RESP_XTLK_ERR|BRIDGE_ISR_XREAD_REQ_TIMEOUT)
-
 int
 pcibr_dmard_error(
 		     pcibr_soft_t pcibr_soft,
@@ -1511,7 +1849,11 @@
      * Look up the address, in the bridge error registers, and
      * take appropriate action
      */
-    ASSERT(IOERROR_GETVALUE(ioe, widgetnum) == pcibr_soft->bs_xid);
+    {
+	short tmp;
+	IOERROR_GETVALUE(tmp, ioe, widgetnum);
+	ASSERT(tmp == pcibr_soft->bs_xid);
+    }
     ASSERT(bridge);
 
     /*
@@ -1540,10 +1882,11 @@
      */
 
     retval = pciio_error_handler(pcibr_vhdl, error_code, mode, ioe);
-    if (retval != IOERROR_HANDLED)
-	pcibr_device_disable(pcibr_soft, 
-			     pciio_widgetdev_slot_get(
-				      IOERROR_GETVALUE(ioe,widgetdev)));
+    if (retval != IOERROR_HANDLED) {
+	short tmp;
+	IOERROR_GETVALUE(tmp, ioe, widgetdev);
+	pcibr_device_disable(pcibr_soft, pciio_widgetdev_slot_get(tmp));
+    }
 
     /*
      * Re-enable bridge to interrupt on BRIDGE_IRR_RESP_BUF_GRP_CLR
@@ -1609,10 +1952,10 @@
     retval = pciio_error_handler(pcibr_vhdl, error_code, mode, ioe);
 
     if (retval != IOERROR_HANDLED) {
-	pcibr_device_disable(pcibr_soft, 
-			     pciio_widgetdev_slot_get(
-				      IOERROR_GETVALUE(ioe, widgetdev)));
+	short tmp;
 
+	IOERROR_GETVALUE(tmp, ioe, widgetdev);
+	pcibr_device_disable(pcibr_soft, pciio_widgetdev_slot_get(tmp));
     }
     return retval;
 }
@@ -1646,6 +1989,10 @@
 
     pcibr_soft = (pcibr_soft_t) einfo;
 
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ERROR_HDLR, pcibr_soft->bs_conn,
+		"pcibr_error_handler: pcibr_soft=0x%x, error_code=0x%x\n",
+		pcibr_soft, error_code));
+
 #ifdef EHE_ENABLE
     xconn_vhdl = pcibr_soft->bs_conn;
     pcibr_vhdl = pcibr_soft->bs_vhdl;
@@ -1664,7 +2011,7 @@
 #endif /* EHE_ENABLE */
 
 #if DEBUG && ERROR_DEBUG
-    printk("%s: pcibr_error_handler\n", pcibr_soft->bs_name);
+    printk( "%s: pcibr_error_handler\n", pcibr_soft->bs_name);
 #endif
 
     ASSERT(pcibr_soft != NULL);
@@ -1704,6 +2051,159 @@
 }
 
 /*
+ * PIC has 2 busses under a single widget so pcibr_attach2 registers this
+ * wrapper function rather than pcibr_error_handler() for PIC.  It's upto
+ * this wrapper to call pcibr_error_handler() with the correct pcibr_soft
+ * struct (ie. the pcibr_soft struct for the bus that saw the error).
+ *
+ * NOTE: this wrapper function is only registered for PIC ASICs and will
+ * only be called for a PIC
+ */
+int
+pcibr_error_handler_wrapper(
+		       error_handler_arg_t einfo,
+		       int error_code,
+		       ioerror_mode_t mode,
+		       ioerror_t *ioe)
+{
+    pcibr_soft_t       pcibr_soft = (pcibr_soft_t) einfo;
+    int                pio_retval = -1; 
+    int		       dma_retval = -1;
+
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ERROR_HDLR, pcibr_soft->bs_conn,
+                "pcibr_error_handler_wrapper: pcibr_soft=0x%x, "
+		"error_code=0x%x\n", pcibr_soft, error_code));
+
+    /*
+     * It is possible that both a IOECODE_PIO and a IOECODE_DMA, and both
+     * IOECODE_READ and IOECODE_WRITE could be set in error_code so we must
+     * process all.  Since we are a wrapper for pcibr_error_handler(), and
+     * will be calling it several times within this routine, we turn off the
+     * error_code bits we don't want it to be processing during that call.
+     */
+    /* 
+     * If the error was a result of a PIO, we tell what bus on the PIC saw
+     * the error from the PIO address.
+     */
+
+#if 0
+    if (mode == MODE_DEVPROBE)
+	pio_retval = IOERROR_HANDLED;
+    else {
+#endif
+    if (error_code & IOECODE_PIO) {
+	iopaddr_t               bad_xaddr;
+	/*
+	 * PIC bus0 PIO space 0x000000 - 0x7fffff or 0x40000000 - 0xbfffffff
+	 *     bus1 PIO space 0x800000 - 0xffffff or 0xc0000000 - 0x13fffffff
+	 */
+	IOERROR_GETVALUE(bad_xaddr, ioe, xtalkaddr);
+	if ((bad_xaddr <= 0x7fffff) ||
+	    ((bad_xaddr >= 0x40000000) && (bad_xaddr <= 0xbfffffff))) {
+	    /* bus 0 saw the error */
+	    pio_retval = pcibr_error_handler((error_handler_arg_t)pcibr_soft,
+			 (error_code & ~IOECODE_DMA), mode, ioe);
+	} else if (((bad_xaddr >= 0x800000) && (bad_xaddr <= 0xffffff)) ||
+	    ((bad_xaddr >= 0xc0000000) && (bad_xaddr <= 0x13fffffff))) {
+	    /* bus 1 saw the error */
+	    pcibr_soft = pcibr_soft->bs_peers_soft;
+	    if (!pcibr_soft) {
+#if DEBUG
+		printk(KERN_WARNING "pcibr_error_handler: "
+			"bs_peers_soft==NULL. bad_xaddr= 0x%x mode= 0x%x\n",
+						bad_xaddr, mode);
+#endif
+  		pio_retval = IOERROR_HANDLED;
+	    } else
+	        pio_retval= pcibr_error_handler((error_handler_arg_t)pcibr_soft,
+			 (error_code & ~IOECODE_DMA), mode, ioe);
+	} else {
+	    printk(KERN_WARNING "pcibr_error_handler_wrapper(): IOECODE_PIO: "
+		    "saw an invalid pio address: 0x%lx\n", bad_xaddr);
+	    pio_retval = IOERROR_UNHANDLED;
+	}
+    } 
+#if 0
+    } /* MODE_DEVPROBE */
+#endif
+
+    /* 
+     * If the error was a result of a DMA Write, we tell what bus on the PIC
+     * saw the error by looking at tnum.
+     */
+    if ((error_code & IOECODE_DMA) && (error_code & IOECODE_WRITE)) {
+	short tmp;
+	/*
+         * For DMA writes [X]Bridge encodes the TNUM field of a Xtalk
+         * packet like this:
+         *              bits  value
+         *              4:3   10b
+         *              2:0   device number
+         *
+         * BUT PIC needs the bus number so it does this:
+         *              bits  value
+         *              4:3   10b
+         *              2     busnumber
+         *              1:0   device number
+	 *
+	 * Pull out the bus number from `tnum' and reset the `widgetdev'
+	 * since when hubiio_crb_error_handler() set `widgetdev' it had
+	 * no idea if it was a PIC or a BRIDGE ASIC so it set it based
+	 * off bits 2:0
+	 */
+	IOERROR_GETVALUE(tmp, ioe, tnum);
+	IOERROR_SETVALUE(ioe, widgetdev, (tmp & 0x3));
+	if ((tmp & 0x4) == 0) {
+	    /* bus 0 saw the error. */
+	    dma_retval = pcibr_error_handler((error_handler_arg_t)pcibr_soft,
+			 (error_code & ~(IOECODE_PIO|IOECODE_READ)), mode, ioe);
+	} else {
+	    /* bus 1 saw the error */
+	    pcibr_soft = pcibr_soft->bs_peers_soft;
+	    dma_retval = pcibr_error_handler((error_handler_arg_t)pcibr_soft,
+			 (error_code & ~(IOECODE_PIO|IOECODE_READ)), mode, ioe);
+	}
+    } 
+    
+    /* 
+     * If the error was a result of a DMA READ, XXX ???
+     */
+    if ((error_code & IOECODE_DMA) && (error_code & IOECODE_READ)) {
+	/*
+	 * A DMA Read error will result in a BRIDGE_ISR_RESP_XTLK_ERR
+	 * or BRIDGE_ISR_BAD_XRESP_PKT bridge error interrupt which 
+	 * are fatal interrupts (ie. BRIDGE_ISR_ERROR_FATAL) causing
+	 * pcibr_error_intr_handler() to panic the system.  So is the
+	 * error handler even going to get called???  It appears that
+	 * the pcibr_dmard_error() attempts to clear the interrupts
+	 * so pcibr_error_intr_handler() won't see them, but there
+	 * appears to be nothing to prevent pcibr_error_intr_handler()
+	 * from running before pcibr_dmard_error() has a chance to
+	 * clear the interrupt.
+	 *
+	 * Since we'll be panicing anyways, don't bother handling the
+	 * error for now until we can fix this race condition mentioned
+	 * above.
+	 */
+	dma_retval = IOERROR_UNHANDLED;
+    } 
+    
+    /* XXX: pcibr_error_handler() should probably do the same thing, it over-
+     * write it's return value as it processes the different "error_code"s.
+     */
+    if ((pio_retval == -1) && (dma_retval == -1)) {
+    	return IOERROR_BADERRORCODE;
+    } else if (dma_retval != IOERROR_HANDLED) {
+	return dma_retval;
+    } else if (pio_retval != IOERROR_HANDLED) {
+	return pio_retval;
+    } else {
+	return IOERROR_HANDLED;
+    }
+}
+
+
+/*
  * Reenable a device after handling the error.
  * This is called by the lower layers when they wish to be reenabled
  * after an error.
@@ -1715,7 +2215,7 @@
 pcibr_error_devenable(devfs_handle_t pconn_vhdl, int error_code)
 {
     pciio_info_t            pciio_info = pciio_info_get(pconn_vhdl);
-    pciio_slot_t            pciio_slot = pciio_info_slot_get(pciio_info);
+    pciio_slot_t            pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info);
     pcibr_soft_t            pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);
 
     ASSERT(error_code & IOECODE_PIO);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/pcibr_hints.c linux-2.4.21-pre6/arch/ia64/sn/io/sn2/pcibr/pcibr_hints.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/pcibr_hints.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn2/pcibr/pcibr_hints.c	2003-03-26 23:49:25.000000000 +0000
@@ -85,11 +85,9 @@
 
     if (hint)
 	hint->ph_rrb_fixed = mask;
-#if DEBUG
     else
-	printk("pcibr_hints_fix_rrbs: pcibr_hints_get failed at\n"
-		"\t%p\n", xconn_vhdl);
-#endif
+        PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, xconn_vhdl,
+		    "pcibr_hints_fix_rrbs: pcibr_hints_get failed\n"));
 }
 
 void
@@ -107,11 +105,9 @@
 
     if (hint)
 	hint->ph_host_slot[guest] = host + 1;
-#if DEBUG
     else
-	printk("pcibr_hints_dualslot: pcibr_hints_get failed at\n"
-		"\t%p\n", xconn_vhdl);
-#endif
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, xconn_vhdl,
+		    "pcibr_hints_dualslot: pcibr_hints_get failed\n"));
 }
 
 void
@@ -122,11 +118,9 @@
 
     if (hint)
 	hint->ph_intr_bits = xxx_intr_bits;
-#if DEBUG
     else
-	printk("pcibr_hints_intr_bits: pcibr_hints_get failed at\n"
-	       "\t%p\n", xconn_vhdl);
-#endif
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, xconn_vhdl,
+		    "pcibr_hints_intr_bits: pcibr_hints_get failed\n"));
 }
 
 void
@@ -145,11 +139,9 @@
 
     if (hint)
 	hint->ph_hands_off = 1;
-#if DEBUG
     else
-	printk("pcibr_hints_handsoff: pcibr_hints_get failed at\n"
-		"\t%p\n", xconn_vhdl);
-#endif
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, xconn_vhdl,
+		    "pcibr_hints_handsoff: pcibr_hints_get failed\n"));
 }
 
 void
@@ -161,13 +153,11 @@
     char                    sdname[16];
     devfs_handle_t            pconn_vhdl = GRAPH_VERTEX_NONE;
 
-    sprintf(sdname, "pci/%d", slot);
+    sprintf(sdname, "%s/%d", EDGE_LBL_PCI, slot);
     (void) hwgraph_path_add(xconn_vhdl, sdname, &pconn_vhdl);
     if (pconn_vhdl == GRAPH_VERTEX_NONE) {
-#if DEBUG
-	printk("pcibr_hints_subdevs: hwgraph_path_create failed at\n"
-		"\t%p (seeking %s)\n", xconn_vhdl, sdname);
-#endif
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, xconn_vhdl,
+		    "pcibr_hints_subdevs: hwgraph_path_create failed\n"));
 	return;
     }
     hwgraph_info_get_LBL(pconn_vhdl, INFO_LBL_SUBDEVS, &ainfo);
@@ -176,10 +166,8 @@
 
 	NEW(subdevp);
 	if (!subdevp) {
-#if DEBUG
-	    printk("pcibr_hints_subdevs: subdev ptr alloc failed at\n"
-		    "\t%p\n", pconn_vhdl);
-#endif
+	    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, xconn_vhdl,
+			"pcibr_hints_subdevs: subdev ptr alloc failed\n"));
 	    return;
 	}
 	*subdevp = subdevs;
@@ -189,16 +177,12 @@
 	    return;
 	DEL(subdevp);
 	if (ainfo == (arbitrary_info_t) NULL) {
-#if DEBUG
-	    printk("pcibr_hints_subdevs: null subdevs ptr at\n"
-		    "\t%p\n", pconn_vhdl);
-#endif
+	    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, xconn_vhdl,
+			"pcibr_hints_subdevs: null subdevs ptr\n"));
 	    return;
 	}
-#if DEBUG
-	printk("pcibr_subdevs_get: dup subdev add_LBL at\n"
-		"\t%p\n", pconn_vhdl);
-#endif
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, xconn_vhdl,
+		    "pcibr_subdevs_get: dup subdev add_LBL\n"));
     }
     *(uint64_t *) ainfo = subdevs;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c linux-2.4.21-pre6/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c	2003-03-26 23:48:57.000000000 +0000
@@ -4,11 +4,10 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved.
  */
 
 #include <linux/types.h>
-#include <linux/config.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <asm/sn/sgi.h>
@@ -39,11 +38,11 @@
 #define rmalloc atealloc
 #endif
 
-unsigned		pcibr_intr_bits(pciio_info_t info, pciio_intr_line_t lines);
+unsigned		pcibr_intr_bits(pciio_info_t info, pciio_intr_line_t lines, int nslots);
 pcibr_intr_t            pcibr_intr_alloc(devfs_handle_t, device_desc_t, pciio_intr_line_t, devfs_handle_t);
 void                    pcibr_intr_free(pcibr_intr_t);
 void              pcibr_setpciint(xtalk_intr_t);
-int                     pcibr_intr_connect(pcibr_intr_t);
+int                     pcibr_intr_connect(pcibr_intr_t, intr_func_t, intr_arg_t);
 void                    pcibr_intr_disconnect(pcibr_intr_t);
 
 devfs_handle_t            pcibr_intr_cpu_get(pcibr_intr_t);
@@ -58,9 +57,9 @@
 
 unsigned
 pcibr_intr_bits(pciio_info_t info,
-		pciio_intr_line_t lines)
+		pciio_intr_line_t lines, int nslots)
 {
-    pciio_slot_t            slot = pciio_info_slot_get(info);
+    pciio_slot_t            slot = PCIBR_INFO_SLOT_GET_INT(info);
     unsigned		    bbits = 0;
 
     /*
@@ -79,7 +78,7 @@
      *      7       7 3 7 3
      */
 
-    if (slot < 8) {
+    if (slot < nslots) {
 	if (lines & (PCIIO_INTR_LINE_A| PCIIO_INTR_LINE_C))
 	    bbits |= 1 << slot;
 	if (lines & (PCIIO_INTR_LINE_B| PCIIO_INTR_LINE_D))
@@ -165,20 +164,26 @@
  *	to check if a specific Bridge b_int_status bit is set, and if so,
  *	cause the setting of the corresponding interrupt bit.
  *
- *	On a XBridge (IP35), we do this by writing the appropriate Bridge Force 
- *	Interrupt register.
+ *	On a XBridge (SN1), we do this by writing the appropriate Bridge Force 
+ *	Interrupt register. On SN0, or SN1 with an older Bridge, the Bridge 
+ *	Force Interrupt register does not exist, so we write the Hub 
+ *	INT_PEND_MOD register directly. Likewise for Octane, where we write the 
+ *	Heart Set Interrupt Status register directly.
  */
 void
 pcibr_force_interrupt(pcibr_intr_wrap_t wrap)
 {
+#ifdef PIC_LATER
 	unsigned	bit;
 	pcibr_soft_t    pcibr_soft = wrap->iw_soft;
 	bridge_t       *bridge = pcibr_soft->bs_base;
-	cpuid_t cpuvertex_to_cpuid(devfs_handle_t vhdl);
 
-	bit = wrap->iw_intr;
+	bit = wrap->iw_ibit;
 
-	if (pcibr_soft->bs_xbridge) {
+	PCIBR_DEBUG((PCIBR_DEBUG_INTR, pcibr_soft->bs_vhdl,
+		    "pcibr_force_interrupt: bit=0x%x\n", bit));
+
+	if (IS_XBRIDGE_OR_PIC_SOFT(pcibr_soft)) {
 	    bridge->b_force_pin[bit].intr = 1;
 	} else if ((1 << bit) & *wrap->iw_stat) {
 	    cpuid_t	    cpu;
@@ -187,11 +192,10 @@
 				pcibr_soft->bs_intr[bit].bsi_xtalk_intr;
 
 	    intr_bit = (short) xtalk_intr_vector_get(xtalk_intr);
-	    cpu = cpuvertex_to_cpuid(xtalk_intr_cpu_get(xtalk_intr));
-#if defined(CONFIG_IA64_SGI_SN1)
+	    cpu = xtalk_intr_cpuid_get(xtalk_intr);
 	    REMOTE_CPU_SEND_INTR(cpu, intr_bit);
-#endif
 	}
+#endif	/* PIC_LATER */
 }
 
 /*ARGSUSED */
@@ -202,12 +206,11 @@
 		 devfs_handle_t owner_dev)
 {
     pcibr_info_t            pcibr_info = pcibr_info_get(pconn_vhdl);
-    pciio_slot_t            pciio_slot = pcibr_info->f_slot;
+    pciio_slot_t            pciio_slot = PCIBR_INFO_SLOT_GET_INT(pcibr_info);
     pcibr_soft_t            pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast;
     devfs_handle_t            xconn_vhdl = pcibr_soft->bs_conn;
     bridge_t               *bridge = pcibr_soft->bs_base;
     int                     is_threaded = 0;
-    int                     thread_swlevel;
 
     xtalk_intr_t           *xtalk_intr_p;
     pcibr_intr_t           *pcibr_intr_p;
@@ -222,41 +225,32 @@
     pcibr_intr_list_t       intr_list;
     bridgereg_t             int_dev;
 
-#if DEBUG && INTR_DEBUG
-    printk("%v: pcibr_intr_alloc\n"
-	    "%v:%s%s%s%s%s\n",
-	    owner_dev, pconn_vhdl,
-	    !(lines & 15) ? " No INTs?" : "",
-	    lines & 1 ? " INTA" : "",
-	    lines & 2 ? " INTB" : "",
-	    lines & 4 ? " INTC" : "",
-	    lines & 8 ? " INTD" : "");
-#endif
+
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,
+    		"pcibr_intr_alloc: %s%s%s%s%s\n",
+		!(lines & 15) ? " No INTs?" : "",
+		lines & 1 ? " INTA" : "",
+		lines & 2 ? " INTB" : "",
+		lines & 4 ? " INTC" : "",
+		lines & 8 ? " INTD" : ""));
 
     NEW(pcibr_intr);
     if (!pcibr_intr)
 	return NULL;
 
-    if (dev_desc) {
-	cpuid_t intr_target_from_desc(device_desc_t, int);
-    } else {
-	extern int default_intr_pri;
-
-	is_threaded = 1; /* PCI interrupts are threaded, by default */
-	thread_swlevel = default_intr_pri;
-    }
-
     pcibr_intr->bi_dev = pconn_vhdl;
     pcibr_intr->bi_lines = lines;
     pcibr_intr->bi_soft = pcibr_soft;
     pcibr_intr->bi_ibits = 0;		/* bits will be added below */
+    pcibr_intr->bi_func = 0;            /* unset until connect */
+    pcibr_intr->bi_arg = 0;             /* unset until connect */
     pcibr_intr->bi_flags = is_threaded ? 0 : PCIIO_INTR_NOTHREAD;
     pcibr_intr->bi_mustruncpu = CPU_NONE;
     pcibr_intr->bi_ibuf.ib_in = 0;
     pcibr_intr->bi_ibuf.ib_out = 0;
     mutex_spinlock_init(&pcibr_intr->bi_ibuf.ib_lock);
-
-    pcibr_int_bits = pcibr_soft->bs_intr_bits((pciio_info_t)pcibr_info, lines);
+    pcibr_int_bits = pcibr_soft->bs_intr_bits((pciio_info_t)pcibr_info, lines, 
+		PCIBR_NUM_SLOTS(pcibr_soft));
 
 
     /*
@@ -265,9 +259,8 @@
      * to, and make sure there are xtalk resources
      * allocated for it.
      */
-#if DEBUG && INTR_DEBUG
-    printk("pcibr_int_bits: 0x%X\n", pcibr_int_bits);
-#endif 
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,
+		"pcibr_intr_alloc: pcibr_int_bits: 0x%x\n", pcibr_int_bits));
     for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit ++) {
 	if (pcibr_int_bits & (1 << pcibr_int_bit)) {
 	    xtalk_intr_p = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr;
@@ -282,10 +275,9 @@
 		 *    ordering problems with DMA, completion interrupts, and error
 		 *    interrupts. (Use of xconn_vhdl forces this.)
 		 *
-		 * 2) On IP35, addressing constraints on IP35 and Bridge force
+		 * 2) On SN1, addressing constraints on SN1 and Bridge force
 		 *    us to use a single PI number for all interrupts from a
-		 *    single Bridge. (IP35-specific code forces this, and we
-		 *    verify in pcibr_setwidint.)
+		 *    single Bridge. (SN1-specific code forces this).
 		 */
 
 		/*
@@ -298,9 +290,9 @@
 		 */
 		xtalk_intr = xtalk_intr_alloc_nothd(xconn_vhdl, dev_desc, 
 			owner_dev);
-#if DEBUG && INTR_DEBUG
-		printk("%v: xtalk_intr=0x%X\n", xconn_vhdl, xtalk_intr);
-#endif
+
+		PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,
+			    "pcibr_intr_alloc: xtalk_intr=0x%x\n", xtalk_intr));
 
 		/* both an assert and a runtime check on this:
 		 * we need to check in non-DEBUG kernels, and
@@ -338,10 +330,9 @@
 		    int_dev |= pciio_slot << BRIDGE_INT_DEV_SHFT(pcibr_int_bit);
 		    bridge->b_int_device = int_dev;	/* XXXMP */
 
-#if DEBUG && INTR_DEBUG
-		    printk("%v: bridge intr bit %d clears my wrb\n",
-			    pconn_vhdl, pcibr_int_bit);
-#endif
+		    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,
+		    		"bridge intr bit %d clears my wrb\n",
+				pcibr_int_bit));
 		} else {
 		    /* someone else got one allocated first;
 		     * free the one we just created, and
@@ -373,25 +364,17 @@
 	    intr_entry->il_wrbf = &(bridge->b_wr_req_buf[pciio_slot].reg);
 	    intr_list_p = 
 		&pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_list;
-#if DEBUG && INTR_DEBUG
-#if defined(SUPPORT_PRINTING_V_FORMAT)
-	    printk("0x%x: Bridge bit %d wrap=0x%x\n",
-		pconn_vhdl, pcibr_int_bit,
-		pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap);
-#else
-	    printk("%v: Bridge bit %d wrap=0x%x\n",
-		pconn_vhdl, pcibr_int_bit,
-		pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap);
-#endif
-#endif
+
+	    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,
+			"Bridge bit 0x%x wrap=0x%x\n", pcibr_int_bit,
+			pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap));
 
 	    if (compare_and_swap_ptr((void **) intr_list_p, NULL, intr_entry)) {
 		/* we are the first interrupt on this bridge bit.
 		 */
-#if DEBUG && INTR_DEBUG
-		printk("%v INT 0x%x (bridge bit %d) allocated [FIRST]\n",
-			pconn_vhdl, pcibr_int_bits, pcibr_int_bit);
-#endif
+		PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,
+			    "INT 0x%x (bridge bit %d) allocated [FIRST]\n",
+			    pcibr_int_bits, pcibr_int_bit));
 		continue;
 	    }
 	    intr_list = *intr_list_p;
@@ -402,10 +385,9 @@
 		 * don't need our intr_entry.
 		 */
 		DEL(intr_entry);
-#if DEBUG && INTR_DEBUG
-		printk("%v INT 0x%x (bridge bit %d) replaces erased first\n",
-			pconn_vhdl, pcibr_int_bits, pcibr_int_bit);
-#endif
+		PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,
+			    "INT 0x%x (bridge bit %d) replaces erased first\n",
+			    pcibr_int_bits, pcibr_int_bit));
 		continue;
 	    }
 	    intr_list_p = &intr_list->il_next;
@@ -413,10 +395,9 @@
 		/* we are the new second interrupt on this bit.
 		 */
 		pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared = 1;
-#if DEBUG && INTR_DEBUG
-		printk("%v INT 0x%x (bridge bit %d) is new SECOND\n",
-			pconn_vhdl, pcibr_int_bits, pcibr_int_bit);
-#endif
+		PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,
+			    "INT 0x%x (bridge bit %d) is new SECOND\n",
+			    pcibr_int_bits, pcibr_int_bit));
 		continue;
 	    }
 	    while (1) {
@@ -427,20 +408,19 @@
 		     * don't need our intr_entry.
 		     */
 		    DEL(intr_entry);
-#if DEBUG && INTR_DEBUG
-		    printk("%v INT 0x%x (bridge bit %d) replaces erased Nth\n",
-			    pconn_vhdl, pcibr_int_bits, pcibr_int_bit);
-#endif
+
+		    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,
+				"INT 0x%x (bridge bit %d) replaces erase Nth\n",
+				pcibr_int_bits, pcibr_int_bit));
 		    break;
 		}
 		intr_list_p = &intr_list->il_next;
 		if (compare_and_swap_ptr((void **) intr_list_p, NULL, intr_entry)) {
 		    /* entry appended to share list
 		     */
-#if DEBUG && INTR_DEBUG
-		    printk("%v INT 0x%x (bridge bit %d) is new Nth\n",
-			    pconn_vhdl, pcibr_int_bits, pcibr_int_bit);
-#endif
+		    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl,
+				"INT 0x%x (bridge bit %d) is new Nth\n",
+				pcibr_int_bits, pcibr_int_bit));
 		    break;
 		}
 		/* step to next record in chain
@@ -479,10 +459,11 @@
 		if (compare_and_swap_ptr((void **) &intr_list->il_intr, 
 					 pcibr_intr, 
 					 NULL)) {
-#if DEBUG && INTR_DEBUG
-		    printk("%s: cleared a handler from bit %d\n",
-			    pcibr_soft->bs_name, pcibr_int_bit);
-#endif
+
+		    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, 
+				pcibr_intr->bi_dev,
+		    		"pcibr_intr_free: cleared hdlr from bit 0x%x\n",
+				pcibr_int_bit));
 		}
 	    /* If this interrupt line is not being shared between multiple
 	     * devices release the xtalk interrupt resources.
@@ -515,34 +496,49 @@
 void
 pcibr_setpciint(xtalk_intr_t xtalk_intr)
 {
-    iopaddr_t               addr = xtalk_intr_addr_get(xtalk_intr);
-    xtalk_intr_vector_t     vect = xtalk_intr_vector_get(xtalk_intr);
-    bridgereg_t            *int_addr = (bridgereg_t *)
-    xtalk_intr_sfarg_get(xtalk_intr);
-
-    *int_addr = ((BRIDGE_INT_ADDR_HOST & (addr >> 30)) |
-		 (BRIDGE_INT_ADDR_FLD & vect));
+    iopaddr_t		 addr;
+    xtalk_intr_vector_t	 vect;
+    devfs_handle_t	 vhdl;
+    bridge_t		*bridge;
+
+    addr = xtalk_intr_addr_get(xtalk_intr);
+    vect = xtalk_intr_vector_get(xtalk_intr);
+    vhdl = xtalk_intr_dev_get(xtalk_intr);
+    bridge = (bridge_t *)xtalk_piotrans_addr(vhdl, 0, 0, sizeof(bridge_t), 0);
+
+    if (is_pic(bridge)) {
+	picreg_t	*int_addr;
+	int_addr = (picreg_t *)xtalk_intr_sfarg_get(xtalk_intr);
+	*int_addr = ((PIC_INT_ADDR_FLD & ((uint64_t)vect << 48)) |
+		     (PIC_INT_ADDR_HOST & addr));
+    } else {
+	bridgereg_t	*int_addr;
+	int_addr = (bridgereg_t *)xtalk_intr_sfarg_get(xtalk_intr);
+	*int_addr = ((BRIDGE_INT_ADDR_HOST & (addr >> 30)) |
+		     (BRIDGE_INT_ADDR_FLD & vect));
+    }
 }
 
 /*ARGSUSED */
 int
-pcibr_intr_connect(pcibr_intr_t pcibr_intr)
+pcibr_intr_connect(pcibr_intr_t pcibr_intr, intr_func_t intr_func, intr_arg_t intr_arg)
 {
     pcibr_soft_t            pcibr_soft = pcibr_intr->bi_soft;
     bridge_t               *bridge = pcibr_soft->bs_base;
     unsigned                pcibr_int_bits = pcibr_intr->bi_ibits;
     unsigned                pcibr_int_bit;
-    bridgereg_t             b_int_enable;
+    uint64_t		    int_enable;
     unsigned long           s;
 
     if (pcibr_intr == NULL)
 	return -1;
 
-#if DEBUG && INTR_DEBUG
-    printk("%v: pcibr_intr_connect\n",
-	    pcibr_intr->bi_dev);
-#endif
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev,
+		"pcibr_intr_connect: intr_func=0x%x\n",
+		pcibr_intr));
 
+    pcibr_intr->bi_func = intr_func;
+    pcibr_intr->bi_arg = intr_arg;
     *((volatile unsigned *)&pcibr_intr->bi_flags) |= PCIIO_INTR_CONNECTED;
 
     /*
@@ -553,9 +549,12 @@
      */
     for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++)
 	if (pcibr_int_bits & (1 << pcibr_int_bit)) {
+            pcibr_intr_wrap_t       intr_wrap;
 	    xtalk_intr_t            xtalk_intr;
+            void                   *int_addr;
 
 	    xtalk_intr = pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr;
+	    intr_wrap = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap;
 
 	    /*
 	     * If this interrupt line is being shared and the connect has
@@ -569,21 +568,43 @@
 	     * Use the pcibr wrapper function to handle all Bridge interrupts
 	     * regardless of whether the interrupt line is shared or not.
 	     */
-	    xtalk_intr_connect(xtalk_intr, (xtalk_intr_setfunc_t) pcibr_setpciint,
-			       (void *)&(bridge->b_int_addr[pcibr_int_bit].addr));
+	    if (IS_PIC_SOFT(pcibr_soft)) 
+		int_addr = (void *)&(bridge->p_int_addr_64[pcibr_int_bit]);
+	    else
+		int_addr = (void *)&(bridge->b_int_addr[pcibr_int_bit].addr);
+
+	    xtalk_intr_connect(xtalk_intr, pcibr_intr_func, (intr_arg_t) intr_wrap,
+					(xtalk_intr_setfunc_t) pcibr_setpciint,
+			       			(void *)int_addr);
+
 	    pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected = 1;
 
-#if DEBUG && INTR_DEBUG
-	    printk("%v bridge bit %d wrapper connected\n",
-		    pcibr_intr->bi_dev, pcibr_int_bit);
-#endif
+	    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev,
+			"pcibr_setpciint: int_addr=0x%x, *int_addr=0x%x, "
+			"pcibr_int_bit=0x%x\n", int_addr,
+			(is_pic(bridge) ? 
+			 *(picreg_t *)int_addr : *(bridgereg_t *)int_addr),
+			pcibr_int_bit));
 	}
-    s = pcibr_lock(pcibr_soft);
-    b_int_enable = bridge->b_int_enable;
-    b_int_enable |= pcibr_int_bits;
-    bridge->b_int_enable = b_int_enable;
-    bridge->b_wid_tflush;		/* wait until Bridge PIO complete */
-    pcibr_unlock(pcibr_soft, s);
+
+	/* PIC WAR. PV# 854697
+	 * On PIC we must write 64-bit MMRs with 64-bit stores
+	 */
+	s = pcibr_lock(pcibr_soft);
+	if (IS_PIC_SOFT(pcibr_soft) &&
+			PCIBR_WAR_ENABLED(PV854697, pcibr_soft)) {
+	    int_enable = bridge->p_int_enable_64;
+	    int_enable |= pcibr_int_bits;
+	    bridge->p_int_enable_64 = int_enable;
+	} else {
+	    bridgereg_t int_enable;
+
+	    int_enable = bridge->b_int_enable;
+	    int_enable |= pcibr_int_bits;
+	    bridge->b_int_enable = int_enable;
+	}
+	bridge->b_wid_tflush;	/* wait until Bridge PIO complete */
+	pcibr_unlock(pcibr_soft, s);
 
     return 0;
 }
@@ -596,13 +617,15 @@
     bridge_t               *bridge = pcibr_soft->bs_base;
     unsigned                pcibr_int_bits = pcibr_intr->bi_ibits;
     unsigned                pcibr_int_bit;
-    bridgereg_t             b_int_enable;
+    pcibr_intr_wrap_t       intr_wrap;
+    uint64_t                int_enable;
     unsigned long           s;
 
     /* Stop calling the function. Now.
      */
     *((volatile unsigned *)&pcibr_intr->bi_flags) &= ~PCIIO_INTR_CONNECTED;
-
+    pcibr_intr->bi_func = 0;
+    pcibr_intr->bi_arg = 0;
     /*
      * For each PCI interrupt line requested, figure
      * out which Bridge PCI Interrupt Line it maps
@@ -619,15 +642,30 @@
     if (!pcibr_int_bits)
 	return;
 
+    /* PIC WAR. PV# 854697
+     * On PIC we must write 64-bit MMRs with 64-bit stores
+     */
     s = pcibr_lock(pcibr_soft);
-    b_int_enable = bridge->b_int_enable;
-    b_int_enable &= ~pcibr_int_bits;
-    bridge->b_int_enable = b_int_enable;
+    if (IS_PIC_SOFT(pcibr_soft) && PCIBR_WAR_ENABLED(PV854697, pcibr_soft)) {
+	int_enable = bridge->p_int_enable_64;
+	int_enable &= ~pcibr_int_bits;
+	bridge->p_int_enable_64 = int_enable;
+    } else {
+	int_enable = (uint64_t)bridge->b_int_enable;
+	int_enable &= ~pcibr_int_bits;
+	bridge->b_int_enable = (bridgereg_t)int_enable;
+    }
     bridge->b_wid_tflush;		/* wait until Bridge PIO complete */
     pcibr_unlock(pcibr_soft, s);
 
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev,
+		"pcibr_intr_disconnect: disabled int_bits=0x%x\n", 
+		pcibr_int_bits));
+
     for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++)
 	if (pcibr_int_bits & (1 << pcibr_int_bit)) {
+            void                   *int_addr;
+
 	    /* if the interrupt line is now shared,
 	     * do not disconnect it.
 	     */
@@ -637,10 +675,9 @@
 	    xtalk_intr_disconnect(pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr);
 	    pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected = 0;
 
-#if DEBUG && INTR_DEBUG
-	    printk("%s: xtalk disconnect done for Bridge bit %d\n",
-		pcibr_soft->bs_name, pcibr_int_bit);
-#endif
+	    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev,
+			"pcibr_intr_disconnect: disconnect int_bits=0x%x\n",
+			pcibr_int_bits));
 
 	    /* if we are sharing the interrupt line,
 	     * connect us up; this closes the hole
@@ -650,9 +687,22 @@
 	    if (!pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared)
 		continue;
 
+	    intr_wrap = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap;
+            if (!pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared)
+                continue;
+
+            if (IS_PIC_SOFT(pcibr_soft))
+                int_addr = (void *)&(bridge->p_int_addr_64[pcibr_int_bit]);
+            else
+                int_addr = (void *)&(bridge->b_int_addr[pcibr_int_bit].addr);
+
 	    xtalk_intr_connect(pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr,
+				pcibr_intr_func, (intr_arg_t) intr_wrap,
 			       (xtalk_intr_setfunc_t)pcibr_setpciint,
-			       (void *) &(bridge->b_int_addr[pcibr_int_bit].addr));
+			       (void *)pcibr_int_bit);
+	    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev,
+			"pcibr_intr_disconnect: now-sharing int_bits=0x%x\n",
+			pcibr_int_bit));
 	}
 }
 
@@ -729,6 +779,10 @@
     bridge->b_wid_int_upper = NEW_b_wid_int_upper;
     bridge->b_wid_int_lower = NEW_b_wid_int_lower;
     bridge->b_int_host_err = vect;
+
+printk("pcibr_setwidint: b_wid_int_upper 0x%x b_wid_int_lower 0x%x b_int_host_err 0x%x\n",
+	NEW_b_wid_int_upper, NEW_b_wid_int_lower, vect);
+
 }
 
 /*
@@ -752,6 +806,9 @@
 				   XTALK_ADDR_TO_UPPER(addr));
 	bridge->b_wid_int_lower = XTALK_ADDR_TO_LOWER(addr);
 	bridge->b_int_host_err = vect;
+printk("pcibr_xintr_preset: b_wid_int_upper 0x%lx b_wid_int_lower 0x%lx b_int_host_err 0x%x\n",
+	( (0x000F0000 & (targ << 16)) | XTALK_ADDR_TO_UPPER(addr)),
+	XTALK_ADDR_TO_LOWER(addr), vect);
 
 	/* turn on all interrupts except
 	 * the PCI interrupt requests,
@@ -794,12 +851,37 @@
 {
     pcibr_intr_wrap_t       wrap = (pcibr_intr_wrap_t) arg;
     reg_p                   wrbf;
+    intr_func_t             func;
     pcibr_intr_t            intr;
     pcibr_intr_list_t       list;
     int                     clearit;
     int			    do_nonthreaded = 1;
     int			    is_threaded = 0;
     int			    x = 0;
+    pcibr_soft_t            pcibr_soft = wrap->iw_soft;
+    bridge_t               *bridge = pcibr_soft->bs_base;
+    uint64_t		    p_enable = pcibr_soft->bs_int_enable;
+    int			    bit = wrap->iw_ibit;
+
+	/*
+	 * PIC WAR.  PV#855272
+	 * Early attempt at a workaround for the runaway
+	 * interrupt problem.   Briefly disable the enable bit for
+	 * this device.
+	 */
+	if (IS_PIC_SOFT(pcibr_soft) &&
+			PCIBR_WAR_ENABLED(PV855272, pcibr_soft)) {
+		unsigned s;
+
+		/* disable-enable interrupts for this bridge pin */
+
+		p_enable &= ~(1 << bit);
+	        s = pcibr_lock(pcibr_soft);
+		bridge->p_int_enable_64 = p_enable;
+		p_enable |= (1 << bit);
+		bridge->p_int_enable_64 = p_enable;
+	        pcibr_unlock(pcibr_soft, s);
+	}
 
 	/*
 	 * If any handler is still running from a previous interrupt
@@ -821,35 +903,31 @@
 	clearit = 1;
 	while (do_nonthreaded) {
 	    for (list = wrap->iw_list; list != NULL; list = list->il_next) {
-		if ((intr = list->il_intr) &&
-		    (intr->bi_flags & PCIIO_INTR_CONNECTED)) {
+		if ((intr = list->il_intr) && (intr->bi_flags & PCIIO_INTR_CONNECTED)) {
 
-		/*
-		 * This device may have initiated write
-		 * requests since the bridge last saw
-		 * an edge on this interrupt input; flushing
-		 * the buffer prior to invoking the handler
-		 * should help but may not be sufficient if we 
-		 * get more requests after the flush, followed
-		 * by the card deciding it wants service, before
-		 * the interrupt handler checks to see if things need
-		 * to be done.
-		 *
-		 * There is a similar race condition if
-		 * an interrupt handler loops around and
-		 * notices further service is required.
-		 * Perhaps we need to have an explicit
-		 * call that interrupt handlers need to
-		 * do between noticing that DMA to memory
-		 * has completed, but before observing the
-		 * contents of memory?
-		 */
-
-			if ((do_nonthreaded) && (!is_threaded)) {
-			/* Non-threaded. 
-			 * Call the interrupt handler at interrupt level
-			 */
+		    /*
+		     * This device may have initiated write
+		     * requests since the bridge last saw
+		     * an edge on this interrupt input; flushing
+		     * the buffer prior to invoking the handler
+		     * should help but may not be sufficient if we 
+		     * get more requests after the flush, followed
+		     * by the card deciding it wants service, before
+		     * the interrupt handler checks to see if things need
+		     * to be done.
+		     *
+		     * There is a similar race condition if
+		     * an interrupt handler loops around and
+		     * notices further service is required.
+		     * Perhaps we need to have an explicit
+		     * call that interrupt handlers need to
+		     * do between noticing that DMA to memory
+		     * has completed, but before observing the
+		     * contents of memory?
+		     */
 
+		    if ((do_nonthreaded) && (!is_threaded)) {
+			/* Non-threaded -  Call the interrupt handler at interrupt level */
 			/* Only need to flush write buffers if sharing */
 
 			if ((wrap->iw_shared) && (wrbf = list->il_wrbf)) {
@@ -864,21 +942,23 @@
 				    (void *)list->il_intr->bi_dev, (long) wrbf);
 #endif
 			}
+			func = intr->bi_func;
+			if ( func )
+				func(intr->bi_arg);
 		    }
-
 		    clearit = 0;
 		}
 	    }
+	    do_nonthreaded = 0;
 
-		do_nonthreaded = 0;
-		/*
-		 * If the non-threaded handler was the last to complete,
-		 * (i.e., no threaded handlers still running) force an
-		 * interrupt to avoid a potential deadlock situation.
-		 */
-		if (wrap->iw_hdlrcnt == 0) {
-			pcibr_force_interrupt(wrap);
-		}
+	    /*
+	     * If the non-threaded handler was the last to complete,
+	     * (i.e., no threaded handlers still running) force an
+	     * interrupt to avoid a potential deadlock situation.
+	     */
+	    if (wrap->iw_hdlrcnt == 0) {
+		pcibr_force_interrupt(wrap);
+	    }
 	}
 
 	/* If there were no handlers,
@@ -892,14 +972,24 @@
 	if (clearit) {
 	    pcibr_soft_t            pcibr_soft = wrap->iw_soft;
 	    bridge_t               *bridge = pcibr_soft->bs_base;
-	    bridgereg_t             b_int_enable;
-	    bridgereg_t		    mask = 1 << wrap->iw_intr;
+	    bridgereg_t             int_enable;
+	    bridgereg_t		    mask = 1 << wrap->iw_ibit;
 	    unsigned long           s;
 
+	    /* PIC BRINUGP WAR (PV# 854697):
+	     * On PIC we must write 64-bit MMRs with 64-bit stores
+	     */
 	    s = pcibr_lock(pcibr_soft);
-	    b_int_enable = bridge->b_int_enable;
-	    b_int_enable &= ~mask;
-	    bridge->b_int_enable = b_int_enable;
+	    if (IS_PIC_SOFT(pcibr_soft) &&
+				PCIBR_WAR_ENABLED(PV854697, pcibr_soft)) {
+		int_enable = bridge->p_int_enable_64;
+		int_enable &= ~mask;
+		bridge->p_int_enable_64 = int_enable;
+	    } else {
+		int_enable = (uint64_t)bridge->b_int_enable;
+		int_enable &= ~mask;
+		bridge->b_int_enable = (bridgereg_t)int_enable;
+	    }
 	    bridge->b_wid_tflush;	/* wait until Bridge PIO complete */
 	    pcibr_unlock(pcibr_soft, s);
 	    return;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/pcibr_rrb.c linux-2.4.21-pre6/arch/ia64/sn/io/sn2/pcibr/pcibr_rrb.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/pcibr_rrb.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn2/pcibr/pcibr_rrb.c	2003-03-26 23:49:07.000000000 +0000
@@ -33,259 +33,478 @@
 
 void              do_pcibr_rrb_clear(bridge_t *, int);
 void              do_pcibr_rrb_flush(bridge_t *, int);
-int               do_pcibr_rrb_count_valid(bridge_t *, pciio_slot_t);
+int               do_pcibr_rrb_count_valid(bridge_t *, pciio_slot_t, int);
 int               do_pcibr_rrb_count_avail(bridge_t *, pciio_slot_t);
-int               do_pcibr_rrb_alloc(bridge_t *, pciio_slot_t, int);
-int               do_pcibr_rrb_free(bridge_t *, pciio_slot_t, int);
+int               do_pcibr_rrb_alloc(bridge_t *, pciio_slot_t, int, int);
+int               do_pcibr_rrb_free(bridge_t *, pciio_slot_t, int, int);
+void		  do_pcibr_rrb_free_all(pcibr_soft_t, bridge_t *, pciio_slot_t);
 
-void              do_pcibr_rrb_autoalloc(pcibr_soft_t, int, int);
+void              do_pcibr_rrb_autoalloc(pcibr_soft_t, int, int, int);
 
 int		  pcibr_wrb_flush(devfs_handle_t);
 int               pcibr_rrb_alloc(devfs_handle_t, int *, int *);
 int               pcibr_rrb_check(devfs_handle_t, int *, int *, int *, int *);
-int               pcibr_alloc_all_rrbs(devfs_handle_t, int, int, int, int, int, int, int, int, int);
 void              pcibr_rrb_flush(devfs_handle_t);
 int		  pcibr_slot_initial_rrb_alloc(devfs_handle_t,pciio_slot_t);
 
-/* 
- *    RRB Management
- */
-
-#define LSBIT(word)		((word) &~ ((word)-1))
-
-void
-do_pcibr_rrb_clear(bridge_t *bridge, int rrb)
-{
-    bridgereg_t             status;
-
-    /* bridge_lock must be held;
-     * this RRB must be disabled.
-     */
-
-    /* wait until RRB has no outstanduing XIO packets. */
-    while ((status = bridge->b_resp_status) & BRIDGE_RRB_INUSE(rrb)) {
-	;				/* XXX- beats on bridge. bad idea? */
-    }
-
-    /* if the RRB has data, drain it. */
-    if (status & BRIDGE_RRB_VALID(rrb)) {
-	bridge->b_resp_clear = BRIDGE_RRB_CLEAR(rrb);
-
-	/* wait until RRB is no longer valid. */
-	while ((status = bridge->b_resp_status) & BRIDGE_RRB_VALID(rrb)) {
-	    ;				/* XXX- beats on bridge. bad idea? */
-	}
-    }
-}
-
-void
-do_pcibr_rrb_flush(bridge_t *bridge, int rrbn)
-{
-    reg_p                   rrbp = &bridge->b_rrb_map[rrbn & 1].reg;
-    bridgereg_t             rrbv;
-    int                     shft = 4 * (rrbn >> 1);
-    unsigned                ebit = BRIDGE_RRB_EN << shft;
-
-    rrbv = *rrbp;
-    if (rrbv & ebit)
-	*rrbp = rrbv & ~ebit;
-
-    do_pcibr_rrb_clear(bridge, rrbn);
-
-    if (rrbv & ebit)
-	*rrbp = rrbv;
-}
+void		  pcibr_rrb_debug(char *, pcibr_soft_t);
 
 /*
- *    pcibr_rrb_count_valid: count how many RRBs are
- *      marked valid for the specified PCI slot on this
- *      bridge.
- *
- *      NOTE: The "slot" parameter for all pcibr_rrb
- *      management routines must include the "virtual"
- *      bit; when manageing both the normal and the
- *      virtual channel, separate calls to these
- *      routines must be made. To denote the virtual
- *      channel, add PCIBR_RRB_SLOT_VIRTUAL to the slot
- *      number.
- *
- *      IMPL NOTE: The obvious algorithm is to iterate
- *      through the RRB fields, incrementing a count if
- *      the RRB is valid and matches the slot. However,
- *      it is much simpler to use an algorithm derived
- *      from the "partitioned add" idea. First, XOR in a
- *      pattern such that the fields that match this
- *      slot come up "all ones" and all other fields
- *      have zeros in the mismatching bits. Then AND
- *      together the bits in the field, so we end up
- *      with one bit turned on for each field that
- *      matched. Now we need to count these bits. This
- *      can be done either with a series of shift/add
- *      instructions or by using "tmp % 15"; I expect
- *      that the cascaded shift/add will be faster.
- */
-
+ * RRB Management
+ *
+ * All the do_pcibr_rrb_ routines manipulate the Read Response Buffer (rrb)
+ * registers within the Bridge.	 Two 32 registers (b_rrb_map[2] also known
+ * as the b_even_resp & b_odd_resp registers) are used to allocate the 16
+ * rrbs to devices.  The b_even_resp register represents even num devices,
+ * and b_odd_resp represent odd number devices.	 Each rrb is represented by
+ * 4-bits within a register.
+ *   BRIDGE & XBRIDGE:	1 enable bit, 1 virtual channel bit, 2 device bits
+ *   PIC:		1 enable bit, 2 virtual channel bits, 1 device bit
+ * PIC has 4 devices per bus, and 4 virtual channels (1 normal & 3 virtual)
+ * per device.	BRIDGE & XBRIDGE have 8 devices per bus and 2 virtual
+ * channels (1 normal & 1 virtual) per device.	See the BRIDGE and PIC ASIC
+ * Programmers Reference guides for more information.
+ */ 
+ 
+#define RRB_MASK (0xf)			/* mask a single rrb within reg */
+#define RRB_SIZE (4)			/* sizeof rrb within reg (bits) */
+ 
+#define RRB_ENABLE_BIT(bridge)		(0x8)  /* [BRIDGE | PIC]_RRB_EN */
+#define NUM_PDEV_BITS(bridge)		(is_pic((bridge)) ? 1 : 2)
+#define NUM_VDEV_BITS(bridge)		(is_pic((bridge)) ? 2 : 1)
+#define NUMBER_VCHANNELS(bridge)	(is_pic((bridge)) ? 4 : 2)
+#define SLOT_2_PDEV(bridge, slot)	((slot) >> 1)
+#define SLOT_2_RRB_REG(bridge, slot)	((slot) & 0x1)
+ 
+/* validate that the slot and virtual channel are valid for a given bridge */
+#define VALIDATE_SLOT_n_VCHAN(bridge, s, v) \
+  (is_pic((bridge)) ? \
+    (((((s) != PCIIO_SLOT_NONE) && ((s) <= (pciio_slot_t)3)) && (((v) >= 0) && ((v) <= 3))) ? 1 : 0) : \
+    (((((s) != PCIIO_SLOT_NONE) && ((s) <= (pciio_slot_t)7)) && (((v) >= 0) && ((v) <= 1))) ? 1 : 0))
+ 
+/*  
+ * Count how many RRBs are marked valid for the specified PCI slot
+ * and virtual channel.	 Return the count.
+ */ 
 int
 do_pcibr_rrb_count_valid(bridge_t *bridge,
-			 pciio_slot_t slot)
+			 pciio_slot_t slot,
+			 int vchan)
 {
-    bridgereg_t             tmp;
+    bridgereg_t tmp;
+    uint16_t enable_bit, vchan_bits, pdev_bits, rrb_bits;
+    int rrb_index, cnt=0;
+
+    if (!VALIDATE_SLOT_n_VCHAN(bridge, slot, vchan)) {
+	printk(KERN_WARNING "do_pcibr_rrb_count_valid() invalid slot/vchan [%d/%d]\n", slot, vchan);
+	return 0;
+    }
+    
+    enable_bit = RRB_ENABLE_BIT(bridge);
+    vchan_bits = vchan << NUM_PDEV_BITS(bridge);
+    pdev_bits = SLOT_2_PDEV(bridge, slot);
+    rrb_bits = enable_bit | vchan_bits | pdev_bits;
+    
+    if ( is_pic(bridge) ) {
+	tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg;
+    }
+    else {
+	if (io_get_sh_swapper(NASID_GET(bridge))) {
+		tmp = BRIDGE_REG_GET32((&bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg));
+	} else {
+		tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg;
+	}
+    }
 
-    tmp = bridge->b_rrb_map[slot & 1].reg;
-    tmp ^= 0x11111111 * (7 - slot / 2);
-    tmp &= (0xCCCCCCCC & tmp) >> 2;
-    tmp &= (0x22222222 & tmp) >> 1;
-    tmp += tmp >> 4;
-    tmp += tmp >> 8;
-    tmp += tmp >> 16;
-    return tmp & 15;
+    for (rrb_index = 0; rrb_index < 8; rrb_index++) {
+	if ((tmp & RRB_MASK) == rrb_bits)
+	    cnt++;
+	tmp = (tmp >> RRB_SIZE);
+    }
+    return cnt;
 }
-
-/*
- *    do_pcibr_rrb_count_avail: count how many RRBs are
- *      available to be allocated for the specified slot.
- *
- *      IMPL NOTE: similar to the above, except we are
- *      just counting how many fields have the valid bit
- *      turned off.
- */
+ 
+ 
+/*  
+ * Count how many RRBs are available to be allocated to the specified
+ * slot.  Return the count.
+ */ 
 int
 do_pcibr_rrb_count_avail(bridge_t *bridge,
 			 pciio_slot_t slot)
 {
-    bridgereg_t             tmp;
+    bridgereg_t tmp;
+    uint16_t enable_bit;
+    int rrb_index, cnt=0;
+    
+    if (!VALIDATE_SLOT_n_VCHAN(bridge, slot, 0)) {
+	printk(KERN_WARNING "do_pcibr_rrb_count_avail() invalid slot/vchan");
+	return 0;
+    }
+    
+    enable_bit = RRB_ENABLE_BIT(bridge);
+
+    if ( is_pic(bridge) ) {
+	tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg;
+    }
+    else {
+	if (io_get_sh_swapper(NASID_GET(bridge))) {
+		tmp = BRIDGE_REG_GET32((&bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg));
+	} else {
+		tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg;
+	}
+    }
 
-    tmp = bridge->b_rrb_map[slot & 1].reg;
-    tmp = (0x88888888 & ~tmp) >> 3;
-    tmp += tmp >> 4;
-    tmp += tmp >> 8;
-    tmp += tmp >> 16;
-    return tmp & 15;
+    for (rrb_index = 0; rrb_index < 8; rrb_index++) {
+	if ((tmp & enable_bit) != enable_bit)
+	    cnt++;
+	tmp = (tmp >> RRB_SIZE);
+    }
+    return cnt;
 }
-
-/*
- *    do_pcibr_rrb_alloc: allocate some additional RRBs
- *      for the specified slot. Returns -1 if there were
- *      insufficient free RRBs to satisfy the request,
- *      or 0 if the request was fulfilled.
- *
- *      Note that if a request can be partially filled,
- *      it will be, even if we return failure.
- *
- *      IMPL NOTE: again we avoid iterating across all
- *      the RRBs; instead, we form up a word containing
- *      one bit for each free RRB, then peel the bits
- *      off from the low end.
- */
+ 
+ 
+/*  
+ * Allocate some additional RRBs for the specified slot and the specified
+ * virtual channel.  Returns -1 if there were insufficient free RRBs to
+ * satisfy the request, or 0 if the request was fulfilled.
+ *
+ * Note that if a request can be partially filled, it will be, even if
+ * we return failure.
+ */ 
 int
 do_pcibr_rrb_alloc(bridge_t *bridge,
 		   pciio_slot_t slot,
+		   int vchan,
 		   int more)
 {
-    int                     rv = 0;
-    bridgereg_t             reg, tmp, bit;
+    bridgereg_t reg, tmp = (bridgereg_t)0;
+    uint16_t enable_bit, vchan_bits, pdev_bits, rrb_bits;
+    int rrb_index;
+    
+    if (!VALIDATE_SLOT_n_VCHAN(bridge, slot, vchan)) {
+	printk(KERN_WARNING "do_pcibr_rrb_alloc() invalid slot/vchan");
+	return -1;
+    }
+    
+    enable_bit = RRB_ENABLE_BIT(bridge);
+    vchan_bits = vchan << NUM_PDEV_BITS(bridge);
+    pdev_bits = SLOT_2_PDEV(bridge, slot);
+    rrb_bits = enable_bit | vchan_bits | pdev_bits;
+
+    if ( is_pic(bridge) ) {
+	reg = tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg;
+    }
+    else {
+	if (io_get_sh_swapper(NASID_GET(bridge))) {
+		reg = tmp = BRIDGE_REG_GET32((&bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg));
+	} else {
+		reg = tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg;
+	}
+    }
+    
+    for (rrb_index = 0; ((rrb_index < 8) && (more > 0)); rrb_index++) {
+	if ((tmp & enable_bit) != enable_bit) {
+	    /* clear the rrb and OR in the new rrb into 'reg' */
+	    reg = reg & ~(RRB_MASK << (RRB_SIZE * rrb_index));
+	    reg = reg | (rrb_bits << (RRB_SIZE * rrb_index));
+	    more--;
+	}
+	tmp = (tmp >> RRB_SIZE);
+    }
 
-    reg = bridge->b_rrb_map[slot & 1].reg;
-    tmp = (0x88888888 & ~reg) >> 3;
-    while (more-- > 0) {
-	bit = LSBIT(tmp);
-	if (!bit) {
-	    rv = -1;
-	    break;
+    if ( is_pic(bridge) ) {
+	bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg = reg;
+    }
+    else {
+	if (io_get_sh_swapper(NASID_GET(bridge))) {
+		BRIDGE_REG_SET32((&bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg)) = reg;
+	} else {
+		bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg = reg;
 	}
-	tmp &= ~bit;
-	reg = ((reg & ~(bit * 15)) | (bit * (8 + slot / 2)));
     }
-    bridge->b_rrb_map[slot & 1].reg = reg;
-    return rv;
+    return (more ? -1 : 0);
 }
-
-/*
- *    do_pcibr_rrb_free: release some of the RRBs that
- *      have been allocated for the specified
- *      slot. Returns zero for success, or negative if
- *      it was unable to free that many RRBs.
- *
- *      IMPL NOTE: We form up a bit for each RRB
- *      allocated to the slot, aligned with the VALID
- *      bitfield this time; then we peel bits off one at
- *      a time, releasing the corresponding RRB.
- */
+ 
+ 
+/*  
+ * Release some of the RRBs that have been allocated for the specified
+ * slot. Returns zero for success, or negative if it was unable to free
+ * that many RRBs.
+ *
+ * Note that if a request can be partially fulfilled, it will be, even
+ * if we return failure.
+ */ 
 int
 do_pcibr_rrb_free(bridge_t *bridge,
 		  pciio_slot_t slot,
+		  int vchan,
 		  int less)
 {
-    int                     rv = 0;
-    bridgereg_t             reg, tmp, clr, bit;
-    int                     i;
+    bridgereg_t reg, tmp = (bridgereg_t)0, clr = 0;
+    uint16_t enable_bit, vchan_bits, pdev_bits, rrb_bits;
+    int rrb_index;
+    
+    if (!VALIDATE_SLOT_n_VCHAN(bridge, slot, vchan)) {
+	printk(KERN_WARNING "do_pcibr_rrb_free() invalid slot/vchan");
+	return -1;
+    }
+    
+    enable_bit = RRB_ENABLE_BIT(bridge);
+    vchan_bits = vchan << NUM_PDEV_BITS(bridge);
+    pdev_bits = SLOT_2_PDEV(bridge, slot);
+    rrb_bits = enable_bit | vchan_bits | pdev_bits;
+
+    if ( is_pic(bridge) ) {
+	reg = tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg;
+    }
+    else {
+	if (io_get_sh_swapper(NASID_GET(bridge))) {
+		reg = BRIDGE_REG_GET32((&bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg));
+	} else {
+		reg = tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg;
+	}
+    }
+    
+    for (rrb_index = 0; ((rrb_index < 8) && (less > 0)); rrb_index++) {
+	if ((tmp & RRB_MASK) == rrb_bits) {
+	   /*
+	    * the old do_pcibr_rrb_free() code only clears the enable bit
+	    * but I say we should clear the whole rrb (ie):
+	    *	  reg = reg & ~(RRB_MASK << (RRB_SIZE * rrb_index));
+	    * But to be compatable with old code we'll only clear enable.
+	    */
+	    reg = reg & ~(RRB_ENABLE_BIT(bridge) << (RRB_SIZE * rrb_index));
+	    clr = clr | (enable_bit << (RRB_SIZE * rrb_index));
+	    less--;
+	}
+	tmp = (tmp >> RRB_SIZE);
+    }
 
-    clr = 0;
-    reg = bridge->b_rrb_map[slot & 1].reg;
+    if ( is_pic(bridge) ) {
+	bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg = reg;
+    }
+    else {
+	if (io_get_sh_swapper(NASID_GET(bridge))) {
+		BRIDGE_REG_SET32((&bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg)) = reg;
+	} else {
+		bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg = reg;
+	}
+    }
 
-    /* This needs to be done otherwise the rrb's on the virtual channel
-     * for this slot won't be freed !!
+    /* call do_pcibr_rrb_clear() for all the rrbs we've freed */
+    for (rrb_index = 0; rrb_index < 8; rrb_index++) {
+	int evn_odd = SLOT_2_RRB_REG(bridge, slot);
+	if (clr & (enable_bit << (RRB_SIZE * rrb_index)))
+	    do_pcibr_rrb_clear(bridge, (2 * rrb_index) + evn_odd);
+    }
+    
+    return (less ? -1 : 0);
+}
+ 
+  
+/*  
+ * free all the rrbs (both the normal and virtual channels) for the
+ * specified slot.
+ */ 
+void
+do_pcibr_rrb_free_all(pcibr_soft_t pcibr_soft,
+		      bridge_t *bridge,
+		      pciio_slot_t slot)
+{
+    int vchan;
+    int vchan_total = NUMBER_VCHANNELS(bridge);
+    
+    /* pretend we own all 8 rrbs and just ignore the return value */
+    for (vchan = 0; vchan < vchan_total; vchan++) {
+	    (void)do_pcibr_rrb_free(bridge, slot, vchan, 8);
+	    pcibr_soft->bs_rrb_valid[slot][vchan] = 0;
+    }
+}
+ 
+ 
+/*
+ * Wait for the the specified rrb to have no outstanding XIO pkts
+ * and for all data to be drained.  Mark the rrb as no longer being 
+ * valid.
+ */
+void
+do_pcibr_rrb_clear(bridge_t *bridge, int rrb)
+{
+    bridgereg_t             status;
+
+    /* bridge_lock must be held;
+     * this RRB must be disabled.
      */
-    tmp = reg & 0xbbbbbbbb;
 
-    tmp ^= (0x11111111 * (7 - slot / 2));
-    tmp &= (0x33333333 & tmp) << 2;
-    tmp &= (0x44444444 & tmp) << 1;
-    while (less-- > 0) {
-	bit = LSBIT(tmp);
-	if (!bit) {
-	    rv = -1;
-	    break;
+    if ( is_pic(bridge) ) {
+	/* wait until RRB has no outstanduing XIO packets. */
+	while ((status = bridge->b_resp_status) & BRIDGE_RRB_INUSE(rrb)) {
+		;				/* XXX- beats on bridge. bad idea? */
+	}
+
+	/* if the RRB has data, drain it. */
+	if (status & BRIDGE_RRB_VALID(rrb)) {
+		bridge->b_resp_clear = BRIDGE_RRB_CLEAR(rrb);
+
+		/* wait until RRB is no longer valid. */
+		while ((status = bridge->b_resp_status) & BRIDGE_RRB_VALID(rrb)) {
+			;				/* XXX- beats on bridge. bad idea? */
+		}
+	}
+    }
+    else {
+	if (io_get_sh_swapper(NASID_GET(bridge))) {
+		while ((status = BRIDGE_REG_GET32((&bridge->b_resp_status))) & BRIDGE_RRB_INUSE(rrb)) {
+			;                               /* XXX- beats on bridge. bad idea? */
+		}
+
+		/* if the RRB has data, drain it. */
+		if (status & BRIDGE_RRB_VALID(rrb)) {
+			BRIDGE_REG_SET32((&bridge->b_resp_clear)) = __swab32(BRIDGE_RRB_CLEAR(rrb));
+
+			/* wait until RRB is no longer valid. */
+			while ((status = BRIDGE_REG_GET32((&bridge->b_resp_status))) & BRIDGE_RRB_VALID(rrb)) {
+				;                           /* XXX- beats on bridge. bad idea? */
+			}
+		}
+	} else { /* io_get_sh_swapper(NASID_GET(bridge)) */
+		while ((status = bridge->b_resp_status) & BRIDGE_RRB_INUSE(rrb)) {
+			;                               /* XXX- beats on bridge. bad idea? */
+		}
+
+		/* if the RRB has data, drain it. */
+		if (status & BRIDGE_RRB_VALID(rrb)) {
+			bridge->b_resp_clear = BRIDGE_RRB_CLEAR(rrb);
+			/* wait until RRB is no longer valid. */
+			while ((status = bridge->b_resp_status) & BRIDGE_RRB_VALID(rrb)) {
+				;                           /* XXX- beats on bridge. bad idea? */
+			}
+		}
+	}
+    }
+}
+
+
+/* 
+ * Flush the specified rrb by calling do_pcibr_rrb_clear().  This
+ * routine is just a wrapper to make sure the rrb is disabled 
+ * before calling do_pcibr_rrb_clear().
+ */
+void
+do_pcibr_rrb_flush(bridge_t *bridge, int rrbn)
+{
+    reg_p	 rrbp = &bridge->b_rrb_map[rrbn & 1].reg;
+    bridgereg_t	 rrbv;
+    int		 shft = (RRB_SIZE * (rrbn >> 1));
+    unsigned long	 ebit = RRB_ENABLE_BIT(bridge) << shft;
+
+    if ( is_pic(bridge) ) {
+	rrbv = *rrbp;
+    }
+    else {
+	if (io_get_sh_swapper(NASID_GET(bridge))) {
+		rrbv = BRIDGE_REG_GET32((&rrbp));
+	} else {
+		rrbv = *rrbp;
+	}
+    }
+
+    if (rrbv & ebit) {
+    	if ( is_pic(bridge) ) {
+		*rrbp = rrbv & ~ebit;
+	}
+	else {
+		if (io_get_sh_swapper(NASID_GET(bridge))) {
+			BRIDGE_REG_SET32((&rrbp)) = __swab32((rrbv & ~ebit));
+		} else {
+			*rrbp = rrbv & ~ebit;
+		}
 	}
-	tmp &= ~bit;
-	reg &= ~bit;
-	clr |= bit;
     }
-    bridge->b_rrb_map[slot & 1].reg = reg;
 
-    for (i = 0; i < 8; i++)
-	if (clr & (8 << (4 * i)))
-	    do_pcibr_rrb_clear(bridge, (2 * i) + (slot & 1));
+    do_pcibr_rrb_clear(bridge, rrbn);
 
-    return rv;
+    if (rrbv & ebit) {
+	if ( is_pic(bridge) ) {
+		*rrbp = rrbv;
+	}
+	else {
+		if (io_get_sh_swapper(NASID_GET(bridge))) {
+			BRIDGE_REG_SET32((&rrbp)) = __swab32(rrbv);
+		} else {
+			*rrbp = rrbv;
+		}
+	}
+    }
 }
 
+
 void
 do_pcibr_rrb_autoalloc(pcibr_soft_t pcibr_soft,
 		       int slot,
+		       int vchan, 
 		       int more_rrbs)
 {
     bridge_t               *bridge = pcibr_soft->bs_base;
     int                     got;
 
     for (got = 0; got < more_rrbs; ++got) {
-	if (pcibr_soft->bs_rrb_res[slot & 7] > 0)
-	    pcibr_soft->bs_rrb_res[slot & 7]--;
+	if (pcibr_soft->bs_rrb_res[slot] > 0)
+	    pcibr_soft->bs_rrb_res[slot]--;
 	else if (pcibr_soft->bs_rrb_avail[slot & 1] > 0)
 	    pcibr_soft->bs_rrb_avail[slot & 1]--;
 	else
 	    break;
-	if (do_pcibr_rrb_alloc(bridge, slot, 1) < 0)
+	if (do_pcibr_rrb_alloc(bridge, slot, vchan, 1) < 0)
 	    break;
-#if PCIBR_RRB_DEBUG
-	printk("do_pcibr_rrb_autoalloc: add one to slot %d%s\n",
-		slot & 7, slot & 8 ? "v" : "");
-#endif
-	pcibr_soft->bs_rrb_valid[slot]++;
-    }
-#if PCIBR_RRB_DEBUG
-    printk("%s: %d+%d free RRBs. Allocation list:\n", pcibr_soft->bs_name,
-	    pcibr_soft->bs_rrb_avail[0],
-	    pcibr_soft->bs_rrb_avail[1]);
-    for (slot = 0; slot < 8; ++slot)
-	printk("\t%d+%d+%d",
-		0xFFF & pcibr_soft->bs_rrb_valid[slot],
-		0xFFF & pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL],
-		pcibr_soft->bs_rrb_res[slot]);
-    printk("\n");
-#endif
+
+	pcibr_soft->bs_rrb_valid[slot][vchan]++;
+    }
+
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_soft->bs_vhdl,
+		"do_pcibr_rrb_autoalloc: added %d (of %d requested) RRBs "
+		"to slot %d, vchan %d\n", got, more_rrbs, 
+		PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), vchan));
+
+    pcibr_rrb_debug("do_pcibr_rrb_autoalloc", pcibr_soft);
 }
 
+
+/*
+ * Flush all the rrb's assigned to the specified connection point.
+ */
+void
+pcibr_rrb_flush(devfs_handle_t pconn_vhdl)
+{
+    pciio_info_t  pciio_info = pciio_info_get(pconn_vhdl);
+    pcibr_soft_t  pcibr_soft = (pcibr_soft_t)pciio_info_mfast_get(pciio_info);
+    pciio_slot_t  slot = PCIBR_INFO_SLOT_GET_INT(pciio_info);
+    bridge_t	 *bridge = pcibr_soft->bs_base;
+
+    bridgereg_t tmp;
+    uint16_t enable_bit, pdev_bits, rrb_bits, rrb_mask;
+    int rrb_index;
+    unsigned long s;
+
+    enable_bit = RRB_ENABLE_BIT(bridge);
+    pdev_bits = SLOT_2_PDEV(bridge, slot);
+    rrb_bits = enable_bit | pdev_bits;
+    rrb_mask = enable_bit | ((NUM_PDEV_BITS(bridge) << 1) - 1);
+
+    tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg;
+
+    s = pcibr_lock(pcibr_soft);
+    for (rrb_index = 0; rrb_index < 8; rrb_index++) {
+	int evn_odd = SLOT_2_RRB_REG(bridge, slot);
+	if ((tmp & rrb_mask) == rrb_bits)
+	    do_pcibr_rrb_flush(bridge, (2 * rrb_index) + evn_odd);
+	tmp = (tmp >> RRB_SIZE);
+    }
+    pcibr_unlock(pcibr_soft, s);
+}
+
+
 /*
  * Device driver interface to flush the write buffers for a specified
  * device hanging off the bridge.
@@ -294,14 +513,24 @@
 pcibr_wrb_flush(devfs_handle_t pconn_vhdl)
 {
     pciio_info_t            pciio_info = pciio_info_get(pconn_vhdl);
-    pciio_slot_t            pciio_slot = pciio_info_slot_get(pciio_info);
+    pciio_slot_t            pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info);
     pcibr_soft_t            pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);
     bridge_t               *bridge = pcibr_soft->bs_base;
     volatile bridgereg_t   *wrb_flush;
 
     wrb_flush = &(bridge->b_wr_req_buf[pciio_slot].reg);
-    while (*wrb_flush);
-
+    if ( IS_PIC_SOFT(pcibr_soft) ) {
+	while (*wrb_flush)
+		;
+    }
+    else {
+	if (io_get_sh_swapper(NASID_GET(bridge))) {
+		while (BRIDGE_REG_GET32((wrb_flush)));
+	} else {
+		while (*wrb_flush)
+			;
+	}
+    }
     return(0);
 }
 
@@ -322,7 +551,7 @@
 		int *count_vchan1)
 {
     pciio_info_t            pciio_info = pciio_info_get(pconn_vhdl);
-    pciio_slot_t            pciio_slot = pciio_info_slot_get(pciio_info);
+    pciio_slot_t            pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info);
     pcibr_soft_t            pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);
     bridge_t               *bridge = pcibr_soft->bs_base;
     int                     desired_vchan0;
@@ -335,7 +564,9 @@
     int                     final_vchan1;
     int                     avail_rrbs;
     int                     res_rrbs;
-    unsigned long           s;
+    int			    vchan_total;
+    int			    vchan;
+    unsigned long                s;
     int                     error;
 
     /*
@@ -352,20 +583,21 @@
 
     s = pcibr_lock(pcibr_soft);
 
+    vchan_total = NUMBER_VCHANNELS(bridge);
+
     /* Save the boot-time RRB configuration for this slot */
-    if (pcibr_soft->bs_rrb_valid_dflt[pciio_slot] < 0) {
-        pcibr_soft->bs_rrb_valid_dflt[pciio_slot] =
-                pcibr_soft->bs_rrb_valid[pciio_slot]; 
-        pcibr_soft->bs_rrb_valid_dflt[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL] =
-                pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL];
+    if (pcibr_soft->bs_rrb_valid_dflt[pciio_slot][VCHAN0] < 0) {
+	for (vchan = 0; vchan < vchan_total; vchan++) 
+	    pcibr_soft->bs_rrb_valid_dflt[pciio_slot][vchan] =
+		    pcibr_soft->bs_rrb_valid[pciio_slot][vchan];
         pcibr_soft->bs_rrb_res_dflt[pciio_slot] =
                 pcibr_soft->bs_rrb_res[pciio_slot];
                   
     }
 
     /* How many RRBs do we own? */
-    orig_vchan0 = pcibr_soft->bs_rrb_valid[pciio_slot];
-    orig_vchan1 = pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL];
+    orig_vchan0 = pcibr_soft->bs_rrb_valid[pciio_slot][VCHAN0];
+    orig_vchan1 = pcibr_soft->bs_rrb_valid[pciio_slot][VCHAN1];
 
     /* How many RRBs do we want? */
     desired_vchan0 = count_vchan0 ? *count_vchan0 : orig_vchan0;
@@ -417,14 +649,14 @@
 	/* Commit the allocations: free, then alloc.
 	 */
 	if (delta_vchan0 < 0)
-	    (void) do_pcibr_rrb_free(bridge, pciio_slot, -delta_vchan0);
+	    (void) do_pcibr_rrb_free(bridge, pciio_slot, VCHAN0, -delta_vchan0);
 	if (delta_vchan1 < 0)
-	    (void) do_pcibr_rrb_free(bridge, PCIBR_RRB_SLOT_VIRTUAL + pciio_slot, -delta_vchan1);
+	    (void) do_pcibr_rrb_free(bridge, pciio_slot, VCHAN1, -delta_vchan1);
 
 	if (delta_vchan0 > 0)
-	    (void) do_pcibr_rrb_alloc(bridge, pciio_slot, delta_vchan0);
+	    (void) do_pcibr_rrb_alloc(bridge, pciio_slot, VCHAN0, delta_vchan0);
 	if (delta_vchan1 > 0)
-	    (void) do_pcibr_rrb_alloc(bridge, PCIBR_RRB_SLOT_VIRTUAL + pciio_slot, delta_vchan1);
+	    (void) do_pcibr_rrb_alloc(bridge, pciio_slot, VCHAN1, delta_vchan1);
 
 	/* Return final values to caller.
 	 */
@@ -442,8 +674,8 @@
 	 * number of available RRBs.
 	 */
 
-	pcibr_soft->bs_rrb_valid[pciio_slot] = final_vchan0;
-	pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL] = final_vchan1;
+	pcibr_soft->bs_rrb_valid[pciio_slot][VCHAN0] = final_vchan0;
+	pcibr_soft->bs_rrb_valid[pciio_slot][VCHAN1] = final_vchan1;
 	pcibr_soft->bs_rrb_avail[pciio_slot & 1] =
 	    pcibr_soft->bs_rrb_avail[pciio_slot & 1]
 	    + pcibr_soft->bs_rrb_res[pciio_slot]
@@ -455,34 +687,21 @@
          * Reserve enough RRBs so this slot's RRB configuration can be
          * reset to its boot-time default following a hot-plug shut-down
          */
-        res_rrbs =   (pcibr_soft->bs_rrb_valid_dflt[pciio_slot] -
-                      pcibr_soft->bs_rrb_valid[pciio_slot]) 
-                   + (pcibr_soft->bs_rrb_valid_dflt[pciio_slot +
-                                                    PCIBR_RRB_SLOT_VIRTUAL] -
-                      pcibr_soft->bs_rrb_valid[pciio_slot +
-                                               PCIBR_RRB_SLOT_VIRTUAL])
-                   + (pcibr_soft->bs_rrb_res_dflt[pciio_slot] -
-                      pcibr_soft->bs_rrb_res[pciio_slot]);
-
-         if (res_rrbs > 0) {
-             pcibr_soft->bs_rrb_res[pciio_slot] = res_rrbs;
-             pcibr_soft->bs_rrb_avail[pciio_slot & 1] =
-                 pcibr_soft->bs_rrb_avail[pciio_slot & 1]
-                 - res_rrbs;
-         }
- 
-#if PCIBR_RRB_DEBUG
-	printk("pcibr_rrb_alloc: slot %d set to %d+%d; %d+%d free\n",
-		pciio_slot, final_vchan0, final_vchan1,
-		pcibr_soft->bs_rrb_avail[0],
-		pcibr_soft->bs_rrb_avail[1]);
-	for (pciio_slot = 0; pciio_slot < 8; ++pciio_slot)
-	    printk("\t%d+%d+%d",
-		    0xFFF & pcibr_soft->bs_rrb_valid[pciio_slot],
-		    0xFFF & pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL],
+	res_rrbs = (pcibr_soft->bs_rrb_res_dflt[pciio_slot] -
 		    pcibr_soft->bs_rrb_res[pciio_slot]);
-	printk("\n");
-#endif
+	for (vchan = 0; vchan < vchan_total; vchan++) {
+	    res_rrbs += (pcibr_soft->bs_rrb_valid_dflt[pciio_slot][vchan] -
+			 pcibr_soft->bs_rrb_valid[pciio_slot][vchan]);
+	}
+
+	if (res_rrbs > 0) {
+            pcibr_soft->bs_rrb_res[pciio_slot] = res_rrbs;
+            pcibr_soft->bs_rrb_avail[pciio_slot & 1] =
+                pcibr_soft->bs_rrb_avail[pciio_slot & 1]
+                - res_rrbs;
+        }
+ 
+	pcibr_rrb_debug("pcibr_rrb_alloc", pcibr_soft);
 
 	error = 0;
     }
@@ -543,22 +762,22 @@
     pciio_info_t            pciio_info;
     pciio_slot_t            pciio_slot;
     pcibr_soft_t            pcibr_soft;
-    unsigned long           s;
+    unsigned long                s;
     int                     error = -1;
 
     if ((pciio_info = pciio_info_get(pconn_vhdl)) &&
 	(pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info)) &&
-	((pciio_slot = pciio_info_slot_get(pciio_info)) < 8)) {
+	((pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info)) < PCIBR_NUM_SLOTS(pcibr_soft))) {
 
 	s = pcibr_lock(pcibr_soft);
 
 	if (count_vchan0)
 	    *count_vchan0 =
-		pcibr_soft->bs_rrb_valid[pciio_slot];
+		pcibr_soft->bs_rrb_valid[pciio_slot][VCHAN0];
 
 	if (count_vchan1)
 	    *count_vchan1 =
-		pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL];
+		pcibr_soft->bs_rrb_valid[pciio_slot][VCHAN1];
 
 	if (count_reserved)
 	    *count_reserved =
@@ -575,159 +794,6 @@
     return error;
 }
 
-/* pcibr_alloc_all_rrbs allocates all the rrbs available in the quantities
- * requested for each of the devices.  The evn_odd argument indicates whether
- * allocation is for the odd or even rrbs. The next group of four argument
- * pairs indicate the amount of rrbs to be assigned to each device. The first
- * argument of each pair indicate the total number of rrbs to allocate for that
- * device. The second argument of each pair indicates how many rrb's from the
- * first argument should be assigned to the virtual channel. The total of all
- * of the first arguments should be <= 8. The second argument should be <= the
- * first argument.
- * if even_odd = 0 the devices in order are 0, 2, 4, 6 
- * if even_odd = 1 the devices in order are 1, 3, 5, 7
- * returns 0 if no errors else returns -1
- */
-
-int
-pcibr_alloc_all_rrbs(devfs_handle_t vhdl, int even_odd,
-		     int dev_1_rrbs, int virt1, int dev_2_rrbs, int virt2,
-		     int dev_3_rrbs, int virt3, int dev_4_rrbs, int virt4)
-{
-    devfs_handle_t          pcibr_vhdl;
-    pcibr_soft_t            pcibr_soft = (pcibr_soft_t)0;
-    bridge_t               *bridge = NULL;
-
-    uint32_t                rrb_setting = 0;
-    int                     rrb_shift = 7;
-    uint32_t                cur_rrb;
-    int                     dev_rrbs[4];
-    int                     virt[4];
-    int                     i, j;
-    unsigned long           s;
-
-    if (GRAPH_SUCCESS ==
-	hwgraph_traverse(vhdl, EDGE_LBL_PCI, &pcibr_vhdl)) {
-	pcibr_soft = pcibr_soft_get(pcibr_vhdl);
-	if (pcibr_soft)
-	    bridge = pcibr_soft->bs_base;
-	hwgraph_vertex_unref(pcibr_vhdl);
-    }
-    if (bridge == NULL)
-	bridge = (bridge_t *) xtalk_piotrans_addr
-	    (vhdl, NULL, 0, sizeof(bridge_t), 0);
-
-    even_odd &= 1;
-
-    dev_rrbs[0] = dev_1_rrbs;
-    dev_rrbs[1] = dev_2_rrbs;
-    dev_rrbs[2] = dev_3_rrbs;
-    dev_rrbs[3] = dev_4_rrbs;
-
-    virt[0] = virt1;
-    virt[1] = virt2;
-    virt[2] = virt3;
-    virt[3] = virt4;
-
-    if ((dev_1_rrbs + dev_2_rrbs + dev_3_rrbs + dev_4_rrbs) > 8) {
-	return -1;
-    }
-    if ((dev_1_rrbs < 0) || (dev_2_rrbs < 0) || (dev_3_rrbs < 0) || (dev_4_rrbs < 0)) {
-	return -1;
-    }
-    /* walk through rrbs */
-    for (i = 0; i < 4; i++) {
-	if (virt[i]) {
-		for( j = 0; j < virt[i]; j++) {
-			cur_rrb = i | 0xc;
-			cur_rrb = cur_rrb << (rrb_shift * 4);
-			rrb_shift--;
-			rrb_setting = rrb_setting | cur_rrb;
-			dev_rrbs[i] = dev_rrbs[i] - 1;
-		}
-	}
-	for (j = 0; j < dev_rrbs[i]; j++) {
-	    cur_rrb = i | 0x8;
-	    cur_rrb = cur_rrb << (rrb_shift * 4);
-	    rrb_shift--;
-	    rrb_setting = rrb_setting | cur_rrb;
-	}
-    }
-
-    if (pcibr_soft)
-	s = pcibr_lock(pcibr_soft);
-
-    bridge->b_rrb_map[even_odd].reg = rrb_setting;
-
-    if (pcibr_soft) {
-
-	pcibr_soft->bs_rrb_fixed |= 0x55 << even_odd;
-
-	/* since we've "FIXED" the allocations
-	 * for these slots, we probably can dispense
-	 * with tracking avail/res/valid data, but
-	 * keeping it up to date helps debugging.
-	 */
-
-	pcibr_soft->bs_rrb_avail[even_odd] =
-	    8 - (dev_1_rrbs + dev_2_rrbs + dev_3_rrbs + dev_4_rrbs);
-
-	pcibr_soft->bs_rrb_res[even_odd + 0] = 0;
-	pcibr_soft->bs_rrb_res[even_odd + 2] = 0;
-	pcibr_soft->bs_rrb_res[even_odd + 4] = 0;
-	pcibr_soft->bs_rrb_res[even_odd + 6] = 0;
-
-	pcibr_soft->bs_rrb_valid[even_odd + 0] = dev_1_rrbs - virt1;
-	pcibr_soft->bs_rrb_valid[even_odd + 2] = dev_2_rrbs - virt2;
-	pcibr_soft->bs_rrb_valid[even_odd + 4] = dev_3_rrbs - virt3;
-	pcibr_soft->bs_rrb_valid[even_odd + 6] = dev_4_rrbs - virt4;
-
-	pcibr_soft->bs_rrb_valid[even_odd + 0 + PCIBR_RRB_SLOT_VIRTUAL] = virt1;
-	pcibr_soft->bs_rrb_valid[even_odd + 2 + PCIBR_RRB_SLOT_VIRTUAL] = virt2;
-	pcibr_soft->bs_rrb_valid[even_odd + 4 + PCIBR_RRB_SLOT_VIRTUAL] = virt3;
-	pcibr_soft->bs_rrb_valid[even_odd + 6 + PCIBR_RRB_SLOT_VIRTUAL] = virt4;
-
-	pcibr_unlock(pcibr_soft, s);
-    }
-    return 0;
-}
-
-/*
- *    pcibr_rrb_flush: chase down all the RRBs assigned
- *      to the specified connection point, and flush
- *      them.
- */
-void
-pcibr_rrb_flush(devfs_handle_t pconn_vhdl)
-{
-    pciio_info_t            pciio_info = pciio_info_get(pconn_vhdl);
-    pcibr_soft_t            pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info);
-    pciio_slot_t            pciio_slot = pciio_info_slot_get(pciio_info);
-    bridge_t               *bridge = pcibr_soft->bs_base;
-    unsigned long           s;
-    reg_p                   rrbp;
-    unsigned                rrbm;
-    int                     i;
-    int                     rrbn;
-    unsigned                sval;
-    unsigned                mask;
-
-    sval = BRIDGE_RRB_EN | (pciio_slot >> 1);
-    mask = BRIDGE_RRB_EN | BRIDGE_RRB_PDEV;
-    rrbn = pciio_slot & 1;
-    rrbp = &bridge->b_rrb_map[rrbn].reg;
-
-    s = pcibr_lock(pcibr_soft);
-    rrbm = *rrbp;
-    for (i = 0; i < 8; ++i) {
-	if ((rrbm & mask) == sval)
-	    do_pcibr_rrb_flush(bridge, rrbn);
-	rrbm >>= 4;
-	rrbn += 2;
-    }
-    pcibr_unlock(pcibr_soft, s);
-}
-
 /*
  * pcibr_slot_initial_rrb_alloc
  *	Allocate a default number of rrbs for this slot on 
@@ -743,75 +809,82 @@
     pcibr_info_h	 pcibr_infoh;
     pcibr_info_t	 pcibr_info;
     bridge_t		*bridge;
-    int                  c0, c1, r;
+    int 		 vchan_total;
+    int			 vchan;
+    int                  chan[4];
 
     pcibr_soft = pcibr_soft_get(pcibr_vhdl);
 
-    if (!pcibr_soft || !PCIBR_VALID_SLOT(slot))
+    if (!pcibr_soft)
 	return(EINVAL);
 
-    bridge = pcibr_soft->bs_base;
+    if (!PCIBR_VALID_SLOT(pcibr_soft, slot))
+	return(EINVAL);
 
-    /* How may RRBs are on this slot?
-     */
-    c0 = do_pcibr_rrb_count_valid(bridge, slot);
-    c1 = do_pcibr_rrb_count_valid(bridge, slot + PCIBR_RRB_SLOT_VIRTUAL);
+    bridge = pcibr_soft->bs_base;
 
-#if PCIBR_RRB_DEBUG
-    printk(
+    /* How many RRBs are on this slot? */
+    vchan_total = NUMBER_VCHANNELS(bridge);
+    for (vchan = 0; vchan < vchan_total; vchan++) 
+        chan[vchan] = do_pcibr_rrb_count_valid(bridge, slot, vchan);
+
+    if (IS_PIC_SOFT(pcibr_soft)) {
+ 	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_vhdl,
+	    "pcibr_slot_initial_rrb_alloc: slot %d started with %d+%d+%d+%d\n",
+	    PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), 
+	    chan[VCHAN0], chan[VCHAN1], chan[VCHAN2], chan[VCHAN3]));
+    } else {
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_vhdl,
 	    "pcibr_slot_initial_rrb_alloc: slot %d started with %d+%d\n",
-            slot, c0, c1);
-#endif
+	    PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), 
+	    chan[VCHAN0], chan[VCHAN1]));
+    }
 
     /* Do we really need any?
      */
     pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos;
     pcibr_info = pcibr_infoh[0];
-    if ((pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) &&
-	!pcibr_soft->bs_slot[slot].has_host) {
-	if (c0 > 0)
-	    do_pcibr_rrb_free(bridge, slot, c0);
-	if (c1 > 0)
-	    do_pcibr_rrb_free(bridge, slot + PCIBR_RRB_SLOT_VIRTUAL, c1);
-	pcibr_soft->bs_rrb_valid[slot] = 0x1000;
-	pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL] = 0x1000;
-	return(ENODEV);
-    }
 
-    pcibr_soft->bs_rrb_avail[slot & 1] -= c0 + c1;
-    pcibr_soft->bs_rrb_valid[slot] = c0;
-    pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL] = c1;
-
-    pcibr_soft->bs_rrb_avail[0] = do_pcibr_rrb_count_avail(bridge, 0);
-    pcibr_soft->bs_rrb_avail[1] = do_pcibr_rrb_count_avail(bridge, 1);
+    if (PCIBR_WAR_ENABLED(PV856866, pcibr_soft) && IS_PIC_SOFT(pcibr_soft) &&
+                        (slot == 2 || slot == 3) &&
+                        (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) &&
+                        !pcibr_soft->bs_slot[slot].has_host) {
+
+        for (vchan = 0; vchan < 2; vchan++) {
+            do_pcibr_rrb_free(bridge, slot, vchan, 8);
+            pcibr_soft->bs_rrb_valid[slot][vchan] = 0;
+        }
 
-    r = 3 - (c0 + c1);
+        pcibr_soft->bs_rrb_valid[slot][3] = chan[3];
 
-    if (r > 0) {
-	pcibr_soft->bs_rrb_res[slot] = r;
-	pcibr_soft->bs_rrb_avail[slot & 1] -= r;
+        return(ENODEV);
     }
 
-#if PCIBR_RRB_DEBUG
-    printk("\t%d+%d+%d",
-	    0xFFF & pcibr_soft->bs_rrb_valid[slot],
-	    0xFFF & pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL],
-	    pcibr_soft->bs_rrb_res[slot]);
-    printk("\n");
-#endif
+    for (vchan = 0; vchan < vchan_total; vchan++)
+        pcibr_soft->bs_rrb_valid[slot][vchan] = chan[vchan];
 
     return(0);
 }
 
+void
+rrb_reserved_free(pcibr_soft_t pcibr_soft, int slot)
+{
+        int res = pcibr_soft->bs_rrb_res[slot];
+
+        if (res) {
+                 pcibr_soft->bs_rrb_avail[slot & 1] += res;
+                 pcibr_soft->bs_rrb_res[slot] = 0;
+        }
+}
+
 /*
  * pcibr_initial_rrb
  *      Assign an equal total number of RRBs to all candidate slots, 
  *      where the total is the sum of the number of RRBs assigned to
  *      the normal channel, the number of RRBs assigned to the virtual
- *      channel, and the number of RRBs assigned as reserved. 
+ *      channels, and the number of RRBs assigned as reserved. 
  *
- *      A candidate slot is a populated slot on a non-SN1 system or 
- *      any existing (populated or empty) slot on an SN1 system.
+ *      A candidate slot is any existing (populated or empty) slot.
  *      Empty SN1 slots need RRBs to support hot-plug operations.
  */
 
@@ -822,7 +895,9 @@
     pcibr_soft_t            pcibr_soft = pcibr_soft_get(pcibr_vhdl);
     bridge_t               *bridge = pcibr_soft->bs_base;
     pciio_slot_t            slot;
-    int                     c0, c1;
+    int			    rrb_total;
+    int			    vchan_total;
+    int			    vchan;
     int                     have[2][3];
     int                     res[2];
     int                     eo;
@@ -831,16 +906,21 @@
     have[1][0] = have[1][1] = have[1][2] = 0;
     res[0] = res[1] = 0;
 
-    for (slot = 0; slot < 8; ++slot) {
+    vchan_total = NUMBER_VCHANNELS(bridge);
+
+    for (slot = pcibr_soft->bs_min_slot; 
+			slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) {
         /* Initial RRB management; give back RRBs in all non-existent slots */
         (void) pcibr_slot_initial_rrb_alloc(pcibr_vhdl, slot);
 
         /* Base calculations only on existing slots */
         if ((slot >= first) && (slot <= last)) {
-            c0 = pcibr_soft->bs_rrb_valid[slot];
-            c1 = pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL];
-            if ((c0 + c1) < 3)
-                have[slot & 1][c0 + c1]++;
+	    rrb_total = 0;
+	    for (vchan = 0; vchan < vchan_total; vchan++) 
+		rrb_total += pcibr_soft->bs_rrb_valid[slot][vchan];
+
+            if (rrb_total < 3)
+                have[slot & 1][rrb_total]++;
         }
     }
 
@@ -867,30 +947,70 @@
     for (slot = first; slot <= last; ++slot) {
         int                     r;
 
-        c0 = pcibr_soft->bs_rrb_valid[slot];
-        c1 = pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL];
-        r = res[slot & 1] - (c0 + c1);
+	rrb_total = 0;
+	for (vchan = 0; vchan < vchan_total; vchan++)
+		rrb_total += pcibr_soft->bs_rrb_valid[slot][vchan];
+
+        r = res[slot & 1] - (rrb_total);
 
         if (r > 0) {
             pcibr_soft->bs_rrb_res[slot] = r;
             pcibr_soft->bs_rrb_avail[slot & 1] -= r;
-            }
+        }
     }
 
-#if PCIBR_RRB_DEBUG
-    printk("%v RRB MANAGEMENT: %d+%d free\n",
-            pcibr_vhdl,
-            pcibr_soft->bs_rrb_avail[0],
-            pcibr_soft->bs_rrb_avail[1]);
-    for (slot = first; slot <= last; ++slot)
-        printk("\tslot %d: %d+%d+%d", slot,
-                0xFFF & pcibr_soft->bs_rrb_valid[slot],
-                0xFFF & pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL],
-                pcibr_soft->bs_rrb_res[slot]);
-    printk("\n");
-#endif
+    pcibr_rrb_debug("pcibr_initial_rrb", pcibr_soft);
 
     return 0;
 
 }
 
+/*
+ * Dump the pcibr_soft_t RRB state variable
+ */
+void
+pcibr_rrb_debug(char *calling_func, pcibr_soft_t pcibr_soft)
+{
+    pciio_slot_t slot;
+    char tmp_str[256];
+    
+    if (pcibr_debug_mask & PCIBR_DEBUG_RRB) {
+        PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_soft->bs_vhdl,
+                    "%s: rrbs available, even=%d, odd=%d\n", calling_func,
+                    pcibr_soft->bs_rrb_avail[0], pcibr_soft->bs_rrb_avail[1]));
+
+        if (IS_PIC_SOFT(pcibr_soft)) {
+            PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_soft->bs_vhdl,
+                        "\tslot\tvchan0\tvchan1\tvchan2\tvchan3\treserved\n"));
+        } else {
+	    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_soft->bs_vhdl,
+		        "\tslot\tvchan0\tvchan1\treserved\n"));
+        }
+
+        for (slot=0; slot < PCIBR_NUM_SLOTS(pcibr_soft); slot++) {
+	    /*
+             * The kernel only allows functions to have so many variable args,
+             * attempting to call PCIBR_DEBUG_ALWAYS() with more than 5 printf
+             * arguments fails so sprintf() it into a temporary string.
+             */
+	    if (IS_PIC_SOFT(pcibr_soft)) {
+                sprintf(tmp_str, "\t %d\t  %d\t  %d\t  %d\t  %d\t  %d\n", 
+		        PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot),
+                        0xFFF & pcibr_soft->bs_rrb_valid[slot][VCHAN0],
+                        0xFFF & pcibr_soft->bs_rrb_valid[slot][VCHAN1],
+                        0xFFF & pcibr_soft->bs_rrb_valid[slot][VCHAN2],
+                        0xFFF & pcibr_soft->bs_rrb_valid[slot][VCHAN3],
+                        pcibr_soft->bs_rrb_res[slot]);
+	    } else {
+	        sprintf(tmp_str, "\t %d\t  %d\t  %d\t  %d\n", 
+		        PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot),
+		        0xFFF & pcibr_soft->bs_rrb_valid[slot][VCHAN0],
+		        0xFFF & pcibr_soft->bs_rrb_valid[slot][VCHAN1],
+		        pcibr_soft->bs_rrb_res[slot]);
+	    }
+    
+            PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_soft->bs_vhdl,
+                        "%s", tmp_str));
+        }
+    }
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/pcibr_slot.c linux-2.4.21-pre6/arch/ia64/sn/io/sn2/pcibr/pcibr_slot.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/pcibr/pcibr_slot.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn2/pcibr/pcibr_slot.c	2003-03-26 23:49:18.000000000 +0000
@@ -10,6 +10,7 @@
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/pci.h>
 #include <asm/sn/sgi.h>
 #include <asm/sn/sn_cpuid.h>
 #include <asm/sn/addrs.h>
@@ -30,70 +31,90 @@
 #include <asm/sn/eeprom.h>
 #include <asm/sn/io.h>
 #include <asm/sn/sn_private.h>
+#include <asm/sn/ate_utils.h>
+
+#ifdef __ia64
+#define rmallocmap atemapalloc
+#define rmfreemap atemapfree
+#define rmfree atefree
+#define rmalloc atealloc
+#endif
+
 
 extern pcibr_info_t     pcibr_info_get(devfs_handle_t);
-extern int              pcibr_widget_to_bus(int);
+extern int              pcibr_widget_to_bus(devfs_handle_t pcibr_vhdl);
 extern pcibr_info_t     pcibr_device_info_new(pcibr_soft_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t);
-extern void             pcibr_freeblock_sub(iopaddr_t *, iopaddr_t *, iopaddr_t, size_t);
 extern int		pcibr_slot_initial_rrb_alloc(devfs_handle_t,pciio_slot_t);
-#if 0
-int pcibr_slot_reset(devfs_handle_t pcibr_vhdl, pciio_slot_t slot);
-#endif
+extern int		pcibr_pcix_rbars_calc(pcibr_soft_t);
 
 int pcibr_slot_info_init(devfs_handle_t pcibr_vhdl, pciio_slot_t slot);
 int pcibr_slot_info_free(devfs_handle_t pcibr_vhdl, pciio_slot_t slot);
 int pcibr_slot_addr_space_init(devfs_handle_t pcibr_vhdl,  pciio_slot_t slot);
+int pcibr_slot_pcix_rbar_init(pcibr_soft_t pcibr_soft,  pciio_slot_t slot);
 int pcibr_slot_device_init(devfs_handle_t pcibr_vhdl,  pciio_slot_t slot);
 int pcibr_slot_guest_info_init(devfs_handle_t pcibr_vhdl,  pciio_slot_t slot);
 int pcibr_slot_call_device_attach(devfs_handle_t pcibr_vhdl,
 		 pciio_slot_t slot, int drv_flags);
 int pcibr_slot_call_device_detach(devfs_handle_t pcibr_vhdl,
 		 pciio_slot_t slot, int drv_flags);
-int pcibr_slot_detach(devfs_handle_t pcibr_vhdl, pciio_slot_t slot, int drv_flags);
+int pcibr_slot_detach(devfs_handle_t pcibr_vhdl, pciio_slot_t slot,
+                 int drv_flags, char *l1_msg, int *sub_errorp);
 int pcibr_is_slot_sys_critical(devfs_handle_t pcibr_vhdl, pciio_slot_t slot);
-int pcibr_probe_slot(bridge_t *, cfg_p, unsigned int *);
-void		 pcibr_device_info_free(devfs_handle_t, pciio_slot_t);
-extern uint64_t  do_pcibr_config_get(cfg_p, unsigned, unsigned);
+static int pcibr_probe_slot(bridge_t *, cfg_p, unsigned int *);
+void pcibr_device_info_free(devfs_handle_t, pciio_slot_t);
+iopaddr_t pcibr_bus_addr_alloc(pcibr_soft_t, pciio_win_info_t, 
+                               pciio_space_t, int, int, int);
+void pciibr_bus_addr_free(pcibr_soft_t, pciio_win_info_t);
+cfg_p pcibr_find_capability(cfg_p, unsigned);
+extern uint64_t  do_pcibr_config_get(int, cfg_p, unsigned, unsigned);
+void do_pcibr_config_set(int, cfg_p, unsigned, unsigned, uint64_t); 
 
-#ifdef LATER
 int pcibr_slot_attach(devfs_handle_t pcibr_vhdl, pciio_slot_t slot,
                 int drv_flags, char *l1_msg, int *sub_errorp);
-int pcibr_slot_pwr(devfs_handle_t, pciio_slot_t, int, char *);
-int pcibr_slot_startup(devfs_handle_t, pcibr_slot_req_t);
-int pcibr_slot_shutdown(devfs_handle_t, pcibr_slot_req_t);
-void pcibr_slot_func_info_return(pcibr_info_h pcibr_infoh, int func,
-                 pcibr_slot_func_info_resp_t funcp);
+
 int pcibr_slot_info_return(pcibr_soft_t pcibr_soft, pciio_slot_t slot,
                  pcibr_slot_info_resp_t respp);
-int pcibr_slot_query(devfs_handle_t, pcibr_slot_req_t);
-#endif	/* LATER */
 
 extern devfs_handle_t baseio_pci_vhdl;
 int scsi_ctlr_nums_add(devfs_handle_t, devfs_handle_t);
 
+
 /* For now .... */
 /*
  * PCI Hot-Plug Capability Flags
+
  */
 #define D_PCI_HOT_PLUG_ATTACH  0x200  /* Driver supports PCI hot-plug attach */
 #define D_PCI_HOT_PLUG_DETACH  0x400  /* Driver supports PCI hot-plug detach */
 
 
+/* 
+ * PCI-X Max Outstanding Split Transactions translation array and Max Memory
+ * Read Byte Count translation array, as defined in the PCI-X Specification.
+ * Section 7.2.3 & 7.2.4 of PCI-X Specification - rev 1.0
+ */
+#define MAX_SPLIT_TABLE 8
+#define MAX_READCNT_TABLE 4
+int max_splittrans_to_numbuf[MAX_SPLIT_TABLE] = {1, 2, 3, 4, 8, 12, 16, 32};
+int max_readcount_to_bufsize[MAX_READCNT_TABLE] = {512, 1024, 2048, 4096 };
+
+
 /*==========================================================================
  *	BRIDGE PCI SLOT RELATED IOCTLs
  */
 
-#ifdef LATER
-
 /*
  * pcibr_slot_startup
  *	Software start-up the PCI slot.
  */
+
+#ifdef PIC_LATER
+
 int
 pcibr_slot_startup(devfs_handle_t pcibr_vhdl, pcibr_slot_req_t reqp)
 {
     pcibr_soft_t                   pcibr_soft = pcibr_soft_get(pcibr_vhdl);
-    pciio_slot_t                   slot = reqp->req_slot;
+    pciio_slot_t                   slot;
     int                            error = 0;
     char                           l1_msg[BRL1_QSIZE+1];
     struct pcibr_slot_up_resp_s    tmp_up_resp;
@@ -103,17 +124,22 @@
         return(PCI_NOT_A_BRIDGE);
     }
 
+    /* req_slot is the 'external' slot number, convert for internal use */
+    slot = PCIBR_SLOT_TO_DEVICE(pcibr_soft, reqp->req_slot);
+
     /* Do not allow start-up of a slot in a shoehorn */
     if(nic_vertex_info_match(pcibr_soft->bs_conn, XTALK_PCI_PART_NUM)) {
        return(PCI_SLOT_IN_SHOEHORN);
     }
  
     /* Check for the valid slot */
-    if (!PCIBR_VALID_SLOT(slot))
+    if (!PCIBR_VALID_SLOT(pcibr_soft, slot))
         return(PCI_NOT_A_SLOT);
 
+#ifdef PIC_LATER
     /* Acquire update access to the bus */
     mrlock(pcibr_soft->bs_bus_lock, MR_UPDATE, PZERO);
+#endif
 
     if (pcibr_soft->bs_slot[slot].slot_status & SLOT_STARTUP_CMPLT) {
         error = PCI_SLOT_ALREADY_UP;
@@ -132,9 +158,10 @@
 
     startup_unlock:
 
+#ifdef PIC_LATER
     /* Release the bus lock */
     mrunlock(pcibr_soft->bs_bus_lock);
-
+#endif
     return(error);
 }
 
@@ -147,7 +174,7 @@
 {
     pcibr_soft_t                   pcibr_soft = pcibr_soft_get(pcibr_vhdl);
     bridge_t                      *bridge;
-    pciio_slot_t                   slot = reqp->req_slot;
+    pciio_slot_t                   slot;
     int                            error = 0;
     char                           l1_msg[BRL1_QSIZE+1];
     struct pcibr_slot_down_resp_s  tmp_down_resp;
@@ -158,10 +185,13 @@
         return(PCI_NOT_A_BRIDGE);
     }
 
+    /* req_slot is the 'external' slot number, convert for internal use */
+    slot = PCIBR_SLOT_TO_DEVICE(pcibr_soft, reqp->req_slot);
+
     bridge = pcibr_soft->bs_base;
 
     /* Check for valid slot */
-    if (!PCIBR_VALID_SLOT(slot))
+    if (!PCIBR_VALID_SLOT(pcibr_soft, slot))
         return(PCI_NOT_A_SLOT);
 
     /* Do not allow shut-down of a slot in a shoehorn */
@@ -169,8 +199,10 @@
        return(PCI_SLOT_IN_SHOEHORN);
     }
 
+#ifdef PIC_LATER
     /* Acquire update access to the bus */
     mrlock(pcibr_soft->bs_bus_lock, MR_UPDATE, PZERO);
+#endif
 
     if ((pcibr_soft->bs_slot[slot].slot_status & SLOT_SHUTDOWN_CMPLT) ||
         ((pcibr_soft->bs_slot[slot].slot_status & SLOT_STATUS_MASK) == 0)) {
@@ -182,6 +214,13 @@
         goto shutdown_unlock;
     }
 
+    /* Do not allow a multi-function card to be hot-plug removed */
+    if (pcibr_soft->bs_slot[slot].bss_ninfo > 1) {
+        tmp_down_resp.resp_sub_errno = EPERM;
+        error = PCI_MULTI_FUNC_ERR;
+        goto shutdown_copyout;
+    }
+
     /* Do not allow the last 33 MHz card to be removed */
     if ((bridge->b_wid_control & BRIDGE_CTRL_BUS_SPEED_MASK) ==
          BRIDGE_CTRL_BUS_SPEED_33) {
@@ -204,17 +243,22 @@
     strncpy(tmp_down_resp.resp_l1_msg, l1_msg, L1_QSIZE);
     tmp_down_resp.resp_l1_msg[L1_QSIZE] = '\0';
 
+    shutdown_copyout:
+
     if (COPYOUT(&tmp_down_resp, reqp->req_respp.down, reqp->req_size)) {
         return(EFAULT);
     }
 
     shutdown_unlock:
 
+#ifdef PIC_LATER
     /* Release the bus lock */
     mrunlock(pcibr_soft->bs_bus_lock);
+#endif
 
     return(error);
 }
+#endif	/* PIC_LATER */
 
 char *pci_space_name[] = {"NONE", 
 			  "ROM",
@@ -240,6 +284,7 @@
 {
     pcibr_info_t                 pcibr_info = pcibr_infoh[func];
     int                          win;
+    boolean_t is_sys_critical_vertex(devfs_handle_t);
 
     funcp->resp_f_status = 0;
 
@@ -248,16 +293,19 @@
     }
 
     funcp->resp_f_status |= FUNC_IS_VALID;
+#if defined(SUPPORT_PRINTING_V_FORMAT)
     sprintf(funcp->resp_f_slot_name, "%v", pcibr_info->f_vertex);
-
+#endif
     if(is_sys_critical_vertex(pcibr_info->f_vertex)) {
         funcp->resp_f_status |= FUNC_IS_SYS_CRITICAL;
     }
 
     funcp->resp_f_bus = pcibr_info->f_bus;
-    funcp->resp_f_slot = pcibr_info->f_slot;
+    funcp->resp_f_slot = PCIBR_INFO_SLOT_GET_EXT(pcibr_info);
     funcp->resp_f_func = pcibr_info->f_func;
+#if defined(SUPPORT_PRINTING_V_FORMAT)
     sprintf(funcp->resp_f_master_name, "%v", pcibr_info->f_master);
+#endif
     funcp->resp_f_pops = pcibr_info->f_pops;
     funcp->resp_f_efunc = pcibr_info->f_efunc;
     funcp->resp_f_einfo = pcibr_info->f_einfo;
@@ -297,20 +345,29 @@
     reg_p                        b_respp;
     pcibr_slot_info_resp_t       slotp;
     pcibr_slot_func_info_resp_t  funcp;
+    boolean_t is_sys_critical_vertex(devfs_handle_t);
+    extern void snia_kmem_free(void *, int);
 
-    slotp = kmem_zalloc(sizeof(*slotp), KM_SLEEP);
+    slotp = snia_kmem_zalloc(sizeof(*slotp), 0);
     if (slotp == NULL) {
         return(ENOMEM);
     }
 
     pss = &pcibr_soft->bs_slot[slot];
 
+    slotp->resp_bs_bridge_mode = pcibr_soft->bs_bridge_mode;
+    slotp->resp_bs_bridge_type = pcibr_soft->bs_bridge_type;
+
     slotp->resp_has_host = pss->has_host;
     slotp->resp_host_slot = pss->host_slot;
+#if defined(SUPPORT_PRINTING_V_FORMAT)
     sprintf(slotp->resp_slot_conn_name, "%v", pss->slot_conn);
+#else
+    sprintf(slotp->resp_slot_conn_name, "%p", (void *)pss->slot_conn);
+#endif
     slotp->resp_slot_status = pss->slot_status;
 
-    slotp->resp_l1_bus_num = io_path_map_widget(pcibr_soft->bs_vhdl);
+    slotp->resp_l1_bus_num = pcibr_widget_to_bus(pcibr_soft->bs_vhdl);
 
     if (is_sys_critical_vertex(pss->slot_conn)) {
         slotp->resp_slot_status |= SLOT_IS_SYS_CRITICAL;
@@ -342,9 +399,10 @@
     slotp->resp_bss_cmd_pointer = pss->bss_cmd_pointer;
     slotp->resp_bss_cmd_shadow = pss->bss_cmd_shadow;
 
-    slotp->resp_bs_rrb_valid = pcibr_soft->bs_rrb_valid[slot];
-    slotp->resp_bs_rrb_valid_v = pcibr_soft->bs_rrb_valid[slot +
-                                                      PCIBR_RRB_SLOT_VIRTUAL];
+    slotp->resp_bs_rrb_valid = pcibr_soft->bs_rrb_valid[slot][VCHAN0];
+    slotp->resp_bs_rrb_valid_v1 = pcibr_soft->bs_rrb_valid[slot][VCHAN1];
+    slotp->resp_bs_rrb_valid_v2 = pcibr_soft->bs_rrb_valid[slot][VCHAN2];
+    slotp->resp_bs_rrb_valid_v3 = pcibr_soft->bs_rrb_valid[slot][VCHAN3];
     slotp->resp_bs_rrb_res = pcibr_soft->bs_rrb_res[slot];
 
     if (slot & 1) {
@@ -355,16 +413,21 @@
 
     slotp->resp_b_resp = *b_respp;
 
-    slotp->resp_b_wid_control = bridge->b_wid_control;
     slotp->resp_b_int_device = bridge->b_int_device;
-    slotp->resp_b_int_enable = bridge->b_int_enable;
-    slotp->resp_b_int_host = bridge->b_int_addr[slot].addr;
+
+    if (IS_PIC_SOFT(pcibr_soft)) {
+	slotp->resp_p_int_enable = bridge->p_int_enable_64;
+	slotp->resp_p_int_host = bridge->p_int_addr_64[slot];
+    } else {
+	slotp->resp_b_int_enable = bridge->b_int_enable;
+	slotp->resp_b_int_host = bridge->b_int_addr[slot].addr;
+    }
 
     if (COPYOUT(slotp, respp, sizeof(*respp))) {
         return(EFAULT);
     }
 
-    kmem_free(slotp, sizeof(*slotp));
+    snia_kmem_free(slotp, sizeof(*slotp));
 
     return(0);
 }
@@ -395,19 +458,26 @@
 pcibr_slot_query(devfs_handle_t pcibr_vhdl, pcibr_slot_req_t reqp)
 {
     pcibr_soft_t            pcibr_soft = pcibr_soft_get(pcibr_vhdl);
-    pciio_slot_t            slot = reqp->req_slot;
+    pciio_slot_t            slot;
     pciio_slot_t            tmp_slot;
     pcibr_slot_info_resp_t  respp = reqp->req_respp.query;
     int                     size = reqp->req_size;
-    int                     error;
+    int                     error = 0;
 
     /* Make sure that we are dealing with a bridge device vertex */
     if (!pcibr_soft) {
         return(PCI_NOT_A_BRIDGE);
     }
 
+    /* req_slot is the 'external' slot number, convert for internal use */
+    slot = PCIBR_SLOT_TO_DEVICE(pcibr_soft, reqp->req_slot);
+
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HOTPLUG, pcibr_vhdl,
+                "pcibr_slot_query: pcibr_soft=0x%x, slot=%d, reqp=0x%x\n",
+                pcibr_soft, slot, reqp));
+
     /* Make sure that we have a valid PCI slot number or PCIIO_SLOT_NONE */
-    if ((!PCIBR_VALID_SLOT(slot)) && (slot != PCIIO_SLOT_NONE)) {
+    if ((!PCIBR_VALID_SLOT(pcibr_soft, slot)) && (slot != PCIIO_SLOT_NONE)) {
         return(PCI_NOT_A_SLOT);
     }
 
@@ -422,32 +492,37 @@
             return(PCI_RESP_AREA_TOO_SMALL);
         }
 
+#ifdef PIC_LATER
         /* Acquire read access to the bus */
         mrlock(pcibr_soft->bs_bus_lock, MR_ACCESS, PZERO);
-
+#endif
         error = pcibr_slot_info_return(pcibr_soft, slot, respp);
 
+#ifdef PIC_LATER
         /* Release the bus lock */
         mrunlock(pcibr_soft->bs_bus_lock);
-
+#endif
         return(error);
     }
 
     /* Return information for all the slots */
-    for (tmp_slot = 0; tmp_slot < 8; tmp_slot++) {
+    for (tmp_slot = pcibr_soft->bs_min_slot; 
+		tmp_slot < PCIBR_NUM_SLOTS(pcibr_soft); tmp_slot++) {
 
         if (size < sizeof(*respp)) {
             return(PCI_RESP_AREA_TOO_SMALL);
         }
 
+#ifdef PIC_LATER
         /* Acquire read access to the bus */
         mrlock(pcibr_soft->bs_bus_lock, MR_ACCESS, PZERO);
-
+#endif
         error = pcibr_slot_info_return(pcibr_soft, tmp_slot, respp);
 
+#ifdef PCI_LATER
         /* Release the bus lock */
         mrunlock(pcibr_soft->bs_bus_lock);
-
+#endif
         if (error) {
             return(error);
         }
@@ -458,60 +533,92 @@
 
     return(error);
 }
-#endif	/* LATER */
 
-/* FIXME: there should be a better way to do this.
- * pcibr_attach() needs PCI_ADDR_SPACE_LIMITS_STORE
+#if 0
+/*
+ * pcibr_slot_reset
+ *	Reset the PCI device in the particular slot.
+ *
+ *      The Xbridge does not comply with the PCI Specification
+ *      when resetting an indiviaudl slot.  An individual slot is
+ *      is reset by toggling the slot's bit in the Xbridge Control
+ *      Register.  The Xbridge will assert the target slot's 
+ *      (non-bussed) RST signal, but does not assert the (bussed) 
+ *      REQ64 signal as required by the specification.   As
+ *      designed, the Xbridge cannot assert the REQ64 signal
+ *      becuase it may interfere with a bus transaction in progress.
+ *      The practical effects of this Xbridge implementation is
+ *      device dependent;  it probably will not adversely effect
+ *      32-bit cards, but may disable 64-bit data transfers by those
+ *      cards that normally support 64-bit data transfers.  
+ *
+ *      The Xbridge will assert REQ64 when all four slots are reset
+ *      by simultaneously toggling all four slot reset bits in the
+ *      Xbridge Control Register.  This is basically a PCI bus reset
+ *      and asserting the (bussed) REQ64 signal will not interfere
+ *      with any bus transactions in progress.
+ *
+ *      The Xbridge (and the SN0 Bridge) support resetting only
+ *      four PCI bus slots via the (X)bridge Control Register.
+ *
+ *      To reset an individual slot for the PCI Hot-Plug feature
+ *      use the L1 console commands to power-down and then 
+ *      power-up the slot, or use the kernel infrastructure
+ *      functions to power-down/up the slot when they are
+ *      implemented for SN1.
  */
+int
+pcibr_slot_reset(devfs_handle_t pcibr_vhdl, pciio_slot_t slot)
+{
+	pcibr_soft_t		 pcibr_soft = pcibr_soft_get(pcibr_vhdl);
+	bridge_t		*bridge;
+	bridgereg_t		 ctrlreg,tmp;
+	volatile bridgereg_t	*wrb_flush;
 
-/* 
- * PCI_ADDR_SPACE_LIMITS_LOAD
- *	Gets the current values of 
- *		pci io base, 
- *		pci io last,
- *		pci low memory base,
- *		pci low memory last,
- *		pci high memory base,
- * 		pci high memory last
- */
-#define PCI_ADDR_SPACE_LIMITS_LOAD()			\
-    pci_io_fb = pcibr_soft->bs_spinfo.pci_io_base;	\
-    pci_io_fl = pcibr_soft->bs_spinfo.pci_io_last;	\
-    pci_lo_fb = pcibr_soft->bs_spinfo.pci_swin_base;	\
-    pci_lo_fl = pcibr_soft->bs_spinfo.pci_swin_last;	\
-    pci_hi_fb = pcibr_soft->bs_spinfo.pci_mem_base;	\
-    pci_hi_fl = pcibr_soft->bs_spinfo.pci_mem_last;
-/*
- * PCI_ADDR_SPACE_LIMITS_STORE
- *	Sets the current values of
- *		pci io base, 
- *		pci io last,
- *		pci low memory base,
- *		pci low memory last,
- *		pci high memory base,
- * 		pci high memory last
- */
-#define PCI_ADDR_SPACE_LIMITS_STORE()			\
-    pcibr_soft->bs_spinfo.pci_io_base = pci_io_fb;	\
-    pcibr_soft->bs_spinfo.pci_io_last = pci_io_fl;	\
-    pcibr_soft->bs_spinfo.pci_swin_base = pci_lo_fb;	\
-    pcibr_soft->bs_spinfo.pci_swin_last = pci_lo_fl;	\
-    pcibr_soft->bs_spinfo.pci_mem_base = pci_hi_fb;	\
-    pcibr_soft->bs_spinfo.pci_mem_last = pci_hi_fl;
-
-#define PCI_ADDR_SPACE_LIMITS_PRINT()			\
-    printf("+++++++++++++++++++++++\n"			\
-	   "IO base 0x%x last 0x%x\n"			\
-	   "SWIN base 0x%x last 0x%x\n"			\
-	   "MEM base 0x%x last 0x%x\n"			\
-	   "+++++++++++++++++++++++\n",			\
-	   pcibr_soft->bs_spinfo.pci_io_base,		\
-	   pcibr_soft->bs_spinfo.pci_io_last,		\
-	   pcibr_soft->bs_spinfo.pci_swin_base,		\
-	   pcibr_soft->bs_spinfo.pci_swin_last,		\
-	   pcibr_soft->bs_spinfo.pci_mem_base,		\
-	   pcibr_soft->bs_spinfo.pci_mem_last);
+	if (!pcibr_soft)
+		return(EINVAL);
+
+	if (!PCIBR_VALID_SLOT(pcibr_soft, slot))
+		return(EINVAL);
+
+	/* Enable the DMA operations from this device of the xtalk widget
+	 * (PCI host bridge in this case).
+	 */
+	xtalk_widgetdev_enable(pcibr_soft->bs_conn, slot);
+
+	/* Set the reset slot bit in the bridge's wid control register
+	 * to reset the PCI slot 
+	 */
+	bridge = pcibr_soft->bs_base;
+
+	/* Read the bridge widget control and clear out the reset pin
+	 * bit for the corresponding slot. 
+	 */
+	tmp = ctrlreg = bridge->b_wid_control;
+
+	tmp &= ~BRIDGE_CTRL_RST_PIN(slot); 
+
+	bridge->b_wid_control = tmp;
+	tmp = bridge->b_wid_control;
+
+	/* Restore the old control register back.
+	 * NOTE : PCI card gets reset when the reset pin bit
+	 * changes from 0 (set above) to 1 (going to be set now).
+	 */
+
+	bridge->b_wid_control = ctrlreg;
 
+	/* Flush the write buffers if any !! */
+	wrb_flush = &(bridge->b_wr_req_buf[slot].reg);
+	while (*wrb_flush);
+
+	return(0);
+}
+#endif
+
+#define PROBE_LOCK 0	/* FIXME: we're attempting to lock around accesses
+			 * to b_int_enable.   This hangs pcibr_probe_slot()
+			 */
 
 /*
  * pcibr_slot_info_init
@@ -534,12 +641,12 @@
     pciio_vendor_id_t       vendor;
     pciio_device_id_t       device;
     unsigned                htype;
+    unsigned                lt_time;
+    int                     nbars;
     cfg_p                   wptr;
+    cfg_p                   pcix_cap;
     int                     win;
     pciio_space_t           space;
-    iopaddr_t		    pci_io_fb,	pci_io_fl;
-    iopaddr_t		    pci_lo_fb,  pci_lo_fl;
-    iopaddr_t		    pci_hi_fb,  pci_hi_fl;
     int			    nfunc;
     pciio_function_t	    rfunc;
     int			    func;
@@ -552,7 +659,7 @@
 	return(EINVAL);
 
     bridge = pcibr_soft->bs_base;
-    if (!PCIBR_VALID_SLOT(slot))
+    if (!PCIBR_VALID_SLOT(pcibr_soft, slot))
 	return(EINVAL);
 
     /* If we have a host slot (eg:- IOC3 has 2 PCI slots and the initialization
@@ -566,28 +673,35 @@
     if (pcibr_is_slot_sys_critical(pcibr_vhdl, slot))
         return(EPERM);
 
-    /* Load the current values of allocated PCI address spaces */
-    PCI_ADDR_SPACE_LIMITS_LOAD();
-    
     /* Try to read the device-id/vendor-id from the config space */
-    cfgw = bridge->b_type0_cfg_dev[slot].l;
+    cfgw = pcibr_slot_config_addr(bridge, slot, 0);
 
+#if PROBE_LOCK
+    s = pcibr_lock(pcibr_soft);
+#endif
     if (pcibr_probe_slot(bridge, cfgw, &idword)) 
 	return(ENODEV);
+#if PROBE_LOCK
+    pcibr_unlock(pcibr_soft, s);
+#endif
 
     slotp = &pcibr_soft->bs_slot[slot];
     slotp->slot_status |= SLOT_POWER_UP;
 
     vendor = 0xFFFF & idword;
+    device = 0xFFFF & (idword >> 16);
+
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_PROBE, pcibr_vhdl,
+		"pcibr_slot_info_init: slot=%d, vendor=0x%x, device=0x%x\n",
+		PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), vendor, device));
+
     /* If the vendor id is not valid then the slot is not populated
      * and we are done.
      */
     if (vendor == 0xFFFF) 
 	return(ENODEV);			
     
-    device = 0xFFFF & (idword >> 16);
-    htype = do_pcibr_config_get(cfgw, PCI_CFG_HEADER_TYPE, 1);
-
+    htype = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_HEADER_TYPE, 1);
     nfunc = 1;
     rfunc = PCIIO_FUNC_NONE;
     pfail = 0;
@@ -599,11 +713,17 @@
 
     if (htype & 0x80) {		/* MULTIFUNCTION */
 	for (func = 1; func < 8; ++func) {
-	    cfgw = bridge->b_type0_cfg_dev[slot].f[func].l;
+	    cfgw = pcibr_func_config_addr(bridge, 0, slot, func, 0);
+#if PROBE_LOCK
+            s = pcibr_lock(pcibr_soft);
+#endif
 	    if (pcibr_probe_slot(bridge, cfgw, &idwords[func])) {
 		pfail |= 1 << func;
 		continue;
 	    }
+#if PROBE_LOCK
+            pcibr_unlock(pcibr_soft, s);
+#endif
 	    vendor = 0xFFFF & idwords[func];
 	    if (vendor == 0xFFFF) {
 		pfail |= 1 << func;
@@ -612,7 +732,7 @@
 	    nfunc = func + 1;
 	    rfunc = 0;
 	}
-	cfgw = bridge->b_type0_cfg_dev[slot].l;
+        cfgw = pcibr_slot_config_addr(bridge, slot, 0);
     }
     NEWA(pcibr_infoh, nfunc);
     
@@ -627,39 +747,162 @@
 		continue;
 	    
 	    idword = idwords[func];
-	    cfgw = bridge->b_type0_cfg_dev[slot].f[func].l;
+	    cfgw = pcibr_func_config_addr(bridge, 0, slot, func, 0);
 	    
 	    device = 0xFFFF & (idword >> 16);
-	    htype = do_pcibr_config_get(cfgw, PCI_CFG_HEADER_TYPE, 1);
+	    htype = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_HEADER_TYPE, 1);
 	    rfunc = func;
 	}
 	htype &= 0x7f;
 	if (htype != 0x00) {
-	    printk(KERN_WARNING  "%s pcibr: pci slot %d func %d has strange header type 0x%x\n",
+	    printk(KERN_WARNING 
+		"%s pcibr: pci slot %d func %d has strange header type 0x%x\n",
 		    pcibr_soft->bs_name, slot, func, htype);
-	    continue;
+	    nbars = 2;
+	} else {
+	    nbars = PCI_CFG_BASE_ADDRS;
+	}
+
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_CONFIG, pcibr_vhdl,
+                "pcibr_slot_info_init: slot=%d, func=%d, cfgw=0x%x\n",
+		PCIBR_DEVICE_TO_SLOT(pcibr_soft,slot), func, cfgw));
+
+#ifdef PIC_LATER
+        /*
+         * Check for a Quad ATM PCI "card" and return all the PCI bus
+         * memory and I/O space.  This will work-around an apparent
+         * hardware problem with the Quad ATM XIO card handling large
+         * PIO addresses.  Releasing all the space for use by the card
+         * will lower the PIO addresses with the PCI bus address space.
+         * This is OK since the PROM did not assign any BAR addresses. 
+         *
+         * Only release all the PCI bus addresses once.
+         *
+         */
+        if ((vendor == LINC_VENDOR_ID_NUM) && (device == LINC_DEVICE_ID_NUM)) {
+            iopaddr_t               prom_base_addr = pcibr_soft->bs_xid << 24;
+            int                     prom_base_size = 0x1000000;
+
+            if (!(pcibr_soft->bs_bus_addr_status & PCIBR_BUS_ADDR_MEM_FREED)) {
+		pciio_device_win_populate(&pcibr_soft->bs_mem_win_map,
+					  prom_base_addr, prom_base_size);
+                pcibr_soft->bs_bus_addr_status |= PCIBR_BUS_ADDR_MEM_FREED;
+            }
+
+            if (!(pcibr_soft->bs_bus_addr_status & PCIBR_BUS_ADDR_IO_FREED)) {
+		pciio_device_win_populate(&pcibr_soft->bs_io_win_map,
+					  prom_base_addr, prom_base_size);
+                pcibr_soft->bs_bus_addr_status |= PCIBR_BUS_ADDR_IO_FREED;
+            }
+        }
+#endif	/* PIC_LATER */
+
+	/* 
+	 * If the latency timer has already been set, by prom or by the
+	 * card itself, use that value.  Otherwise look at the device's
+	 * 'min_gnt' and attempt to calculate a latency time. 
+	 *
+	 * NOTE: For now if the device is on the 'real time' arbitration
+	 * ring we dont set the latency timer.  
+	 *
+	 * WAR: SGI's IOC3 and RAD devices target abort if you write a 
+	 * single byte into their config space.  So don't set the Latency
+	 * Timer for these devices
+	 */
+
+	lt_time = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_LATENCY_TIMER, 1);
+
+	if ((lt_time == 0) && !(bridge->b_device[slot].reg & BRIDGE_DEV_RT) &&
+	    !((vendor == IOC3_VENDOR_ID_NUM) && 
+	      (
+#ifdef PIC_LATER
+	       (device == IOC3_DEVICE_ID_NUM) ||
+	       (device == LINC_DEVICE_ID_NUM) ||
+#endif
+	       (device == 0x5 /* RAD_DEV */)))) {
+	     unsigned	min_gnt;
+	     unsigned	min_gnt_mult;
+	    
+	    /* 'min_gnt' indicates how long of a burst period a device
+	     * needs in increments of 250ns.  But latency timer is in
+	     * PCI clock cycles, so a conversion is needed.
+	     */
+	    min_gnt = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_MIN_GNT, 1);
+
+	    if (IS_133MHZ(pcibr_soft))
+		min_gnt_mult = 32;	/* 250ns @ 133MHz in clocks */
+	    else if (IS_100MHZ(pcibr_soft))
+		min_gnt_mult = 24;	/* 250ns @ 100MHz in clocks */
+	    else if (IS_66MHZ(pcibr_soft))
+		min_gnt_mult = 16;	/* 250ns @ 66MHz, in clocks */
+	    else
+		min_gnt_mult = 8;	/* 250ns @ 33MHz, in clocks */
+
+	    if ((min_gnt != 0) && ((min_gnt * min_gnt_mult) < 256))
+		lt_time = (min_gnt * min_gnt_mult);
+	    else
+		lt_time = 4 * min_gnt_mult;	  /* 1 micro second */
+
+	    do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_LATENCY_TIMER, 1, lt_time);
+
+	    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_CONFIG, pcibr_vhdl,
+                    "pcibr_slot_info_init: set Latency Timer for slot=%d, "
+		    "func=%d, to 0x%x\n", 
+		    PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func, lt_time));
+	}
+
+	/* Get the PCI-X capability if running in PCI-X mode.  If the func
+	 * doesnt have a pcix capability, allocate a PCIIO_VENDOR_ID_NONE
+	 * pcibr_info struct so the device driver for that function is not
+	 * called.
+	 */
+	if (IS_PCIX(pcibr_soft)) {
+	    if (!(pcix_cap = pcibr_find_capability(cfgw, PCI_CAP_PCIX))) {
+		printk(KERN_WARNING
+#if defined(SUPPORT_PRINTING_V_FORMAT)
+		        "%v: Bus running in PCI-X mode, But card in slot %d, "
+		        "func %d not PCI-X capable\n", pcibr_vhdl, slot, func);
+#else
+		        "0x%lx: Bus running in PCI-X mode, But card in slot %d, "
+		        "func %d not PCI-X capable\n", (unsigned long)pcibr_vhdl, slot, func);
+#endif
+		pcibr_device_info_new(pcibr_soft, slot, PCIIO_FUNC_NONE,
+		               PCIIO_VENDOR_ID_NONE, PCIIO_DEVICE_ID_NONE);
+		continue;
+	    }
+	    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_CONFIG, pcibr_vhdl,
+                    "pcibr_slot_info_init: PCI-X capability at 0x%x for "
+		    "slot=%d, func=%d\n", 
+		    pcix_cap, PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func));
+	} else {
+	    pcix_cap = NULL;
 	}
-#if DEBUG && ATTACH_DEBUG
-	printk(KERN_NOTICE   
-		"%s pcibr: pci slot %d func %d: vendor 0x%x device 0x%x",
-		pcibr_soft->bs_name, slot, func, vendor, device);
-#endif	
 
 	pcibr_info = pcibr_device_info_new
 	    (pcibr_soft, slot, rfunc, vendor, device);
+
+	/* Keep a running total of the number of PIC-X functions on the bus
+         * and the number of max outstanding split trasnactions that they
+	 * have requested.  NOTE: "pcix_cap != NULL" implies IS_PCIX()
+	 */
+	pcibr_info->f_pcix_cap = (cap_pcix_type0_t *)pcix_cap;
+	if (pcibr_info->f_pcix_cap) {
+	    int max_out;      /* max outstanding splittrans from status reg */
+
+	    pcibr_soft->bs_pcix_num_funcs++;
+	    max_out = pcibr_info->f_pcix_cap->pcix_type0_status.max_out_split;
+	    pcibr_soft->bs_pcix_split_tot += max_splittrans_to_numbuf[max_out];
+	}
+
 	conn_vhdl = pciio_device_info_register(pcibr_vhdl, &pcibr_info->f_c);
 	if (func == 0)
 	    slotp->slot_conn = conn_vhdl;
 
-#ifdef SN1_LITTLE_ENDIAN
-	cmd_reg = cfgw[(PCI_CFG_COMMAND ^ 4) / 4];
-#else
-	cmd_reg = cfgw[PCI_CFG_COMMAND / 4];
-#endif
+	cmd_reg = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_COMMAND, 4);
 	
 	wptr = cfgw + PCI_CFG_BASE_ADDR_0 / 4;
 
-	for (win = 0; win < PCI_CFG_BASE_ADDRS; ++win) {
+	for (win = 0; win < nbars; ++win) {
 	    iopaddr_t               base, mask, code;
 	    size_t                  size;
 
@@ -706,11 +949,7 @@
 	     * this could be pushed up into pciio, when we
 	     * start supporting more PCI providers.
 	     */
-#ifdef SN1_LITTLE_ENDIAN
-	    base = wptr[((win*4)^4)/4];
-#else
-	    base = wptr[win];
-#endif
+	    base = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), wptr, (win * 4), 4);
 
 	    if (base & PCI_BA_IO_SPACE) {
 		/* BASE is in I/O space. */
@@ -736,11 +975,7 @@
 		} else if (base & 0xC0000000) {
 		    base = 0;	/* outside permissable range */
 		} else if ((code == PCI_BA_MEM_64BIT) &&
-#ifdef SN1_LITTLE_ENDIAN
-			   (wptr[(((win + 1)*4)^4)/4] != 0)) {
-#else 
-			   (wptr[win + 1] != 0)) {
-#endif /* LITTLE_ENDIAN */
+			   (do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), wptr, ((win + 1)*4), 4) != 0)) {
 		    base = 0;	/* outside permissable range */
 		}
 	    }
@@ -748,13 +983,8 @@
 	    if (base != 0) {	/* estimate size */
 		size = base & -base;
 	    } else {		/* calculate size */
-#ifdef SN1_LITTLE_ENDIAN
-		wptr[((win*4)^4)/4] = ~0;	/* turn on all bits */
-		size = wptr[((win*4)^4)/4];	/* get stored bits */
-#else 
-		wptr[win] = ~0;	/* turn on all bits */
-		size = wptr[win];	/* get stored bits */
-#endif /* LITTLE_ENDIAN */
+		do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), wptr, (win * 4), 4, ~0);    /* write 1's */
+		size = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), wptr, (win * 4), 4); /* read back */
 		size &= mask;	/* keep addr */
 		size &= -size;	/* keep lsbit */
 		if (size == 0)
@@ -765,28 +995,6 @@
 	    pcibr_info->f_window[win].w_base = base;
 	    pcibr_info->f_window[win].w_size = size;
 
-	    /*
-	     * If this window already has PCI space
-	     * allocated for it, "subtract" that space from
-	     * our running freeblocks. Don't worry about
-	     * overlaps in existing allocated windows; we
-	     * may be overstating their sizes anyway.
-	     */
-
-	    if (base && size) {
-		if (space == PCIIO_SPACE_IO) {
-		    pcibr_freeblock_sub(&pci_io_fb,
-					&pci_io_fl,
-					base, size);
-		} else {
-		    pcibr_freeblock_sub(&pci_lo_fb,
-					&pci_lo_fl,
-					base, size);
-		    pcibr_freeblock_sub(&pci_hi_fb,
-					&pci_hi_fl,
-					base, size);
-		}	
-	    }
 #if defined(IOC3_VENDOR_ID_NUM) && defined(IOC3_DEVICE_ID_NUM)
 	    /*
 	     * IOC3 BASE_ADDR* BUG WORKAROUND
@@ -825,21 +1033,55 @@
 #endif
 	    if (code == PCI_BA_MEM_64BIT) {
 		win++;		/* skip upper half */
-#ifdef SN1_LITTLE_ENDIAN
-		wptr[((win*4)^4)/4] = 0;	/* which must be zero */
-#else 
-		wptr[win] = 0;	/* which must be zero */
-#endif /* LITTLE_ENDIAN */
+		do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), wptr, (win * 4), 4, 0);  /* must be zero */
 	    }
 	}				/* next win */
     }				/* next func */
 
-    /* Store back the values for allocated PCI address spaces */
-    PCI_ADDR_SPACE_LIMITS_STORE();
     return(0);
 }					
 
 /*
+ * pcibr_find_capability
+ *	Walk the list of capabilities (if it exists) looking for
+ *	the requested capability.  Return a cfg_p pointer to the
+ *	capability if found, else return NULL
+ */
+cfg_p
+pcibr_find_capability(cfg_p	cfgw,
+		      unsigned	capability)
+{
+    unsigned		cap_nxt;
+    unsigned		cap_id;
+    int			defend_against_circular_linkedlist = 0;
+
+    /* Check to see if there is a capabilities pointer in the cfg header */
+    if (!(do_pcibr_config_get(1, cfgw, PCI_CFG_STATUS, 2) & PCI_STAT_CAP_LIST)) {
+	return (NULL);
+    }
+
+    /*
+     * Read up the capabilities head pointer from the configuration header.
+     * Capabilities are stored as a linked list in the lower 48 dwords of
+     * config space and are dword aligned. (Note: spec states the least two
+     * significant bits of the next pointer must be ignored,  so we mask
+     * with 0xfc).
+     */
+    cap_nxt = (do_pcibr_config_get(1, cfgw, PCI_CAPABILITIES_PTR, 1) & 0xfc);
+
+    while (cap_nxt && (defend_against_circular_linkedlist <= 48)) {
+	cap_id = do_pcibr_config_get(1, cfgw, cap_nxt, 1);
+	if (cap_id == capability) {
+	    return ((cfg_p)((char *)cfgw + cap_nxt));
+	}
+	cap_nxt = (do_pcibr_config_get(1, cfgw, cap_nxt+1, 1) & 0xfc);
+	defend_against_circular_linkedlist++;
+    }
+
+    return (NULL);
+}
+
+/*
  * pcibr_slot_info_free
  *	Remove all the PCI infrastructural information associated
  * 	with a particular PCI device.
@@ -854,7 +1096,10 @@
 
     pcibr_soft = pcibr_soft_get(pcibr_vhdl);
 
-    if (!pcibr_soft || !PCIBR_VALID_SLOT(slot))
+    if (!pcibr_soft)
+	return(EINVAL);
+
+    if (!PCIBR_VALID_SLOT(pcibr_soft, slot))
 	return(EINVAL);
 
     nfunc = pcibr_soft->bs_slot[slot].bss_ninfo;
@@ -868,6 +1113,109 @@
     return(0);
 }
 
+/*
+ * pcibr_slot_pcix_rbar_init
+ *	Allocate RBARs to the PCI-X functions on a given device
+ */
+int
+pcibr_slot_pcix_rbar_init(pcibr_soft_t pcibr_soft,
+			    pciio_slot_t slot)
+{
+    pcibr_info_h	 pcibr_infoh;
+    pcibr_info_t	 pcibr_info;
+    char		 tmp_str[256];
+    int		       	 nfunc;
+    int			 func;
+
+    if (!PCIBR_VALID_SLOT(pcibr_soft, slot))
+	return(EINVAL);
+
+    if ((nfunc = pcibr_soft->bs_slot[slot].bss_ninfo) < 1)
+	return(EINVAL);
+
+    if (!(pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos))
+	return(EINVAL);
+
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RBAR, pcibr_soft->bs_vhdl,
+		"pcibr_slot_pcix_rbar_init for slot %d\n", 
+		PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot)));
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RBAR, pcibr_soft->bs_vhdl,
+		"\tslot/func\trequested\tgiven\tinuse\tavail\n"));
+
+    for (func = 0; func < nfunc; ++func) {
+	cap_pcix_type0_t	*pcix_cap_p;
+	cap_pcix_stat_reg_t	*pcix_statreg_p;
+	cap_pcix_cmd_reg_t	*pcix_cmdreg_p;
+	int 			 num_rbar;
+
+	if (!(pcibr_info = pcibr_infoh[func]))
+	    continue;
+
+	if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE)
+	    continue;
+
+	if (!(pcix_cap_p = pcibr_info->f_pcix_cap))
+	    continue;
+
+	pcix_statreg_p = &pcix_cap_p->pcix_type0_status;
+	pcix_cmdreg_p = &pcix_cap_p->pcix_type0_command;
+
+	/* If there are enough RBARs to satify the number of "max outstanding 
+	 * transactions" each function requested (bs_pcix_rbar_percent_allowed
+	 * is 100%), then give each function what it requested, otherwise give 
+	 * the functions a "percentage of what they requested".
+	 */
+	if (pcibr_soft->bs_pcix_rbar_percent_allowed >= 100) {
+	    pcix_cmdreg_p->max_split = pcix_statreg_p->max_out_split;
+	    num_rbar = max_splittrans_to_numbuf[pcix_cmdreg_p->max_split];
+	    pcibr_soft->bs_pcix_rbar_inuse += num_rbar;
+	    pcibr_soft->bs_pcix_rbar_avail -= num_rbar;
+	    pcix_cmdreg_p->max_mem_read_cnt = pcix_statreg_p->max_mem_read_cnt;
+	} else {
+	    int index;	    /* index into max_splittrans_to_numbuf table */
+	    int max_out;    /* max outstanding transactions given to func */
+
+	    /* Calculate the percentage of RBARs this function can have.
+	     * NOTE: Every function gets at least 1 RBAR (thus the "+1").
+	     * bs_pcix_rbar_percent_allowed is the percentage of what was
+	     * requested less this 1 RBAR that all functions automatically 
+	     * gets
+	     */
+	    max_out = ((max_splittrans_to_numbuf[pcix_statreg_p->max_out_split]
+			* pcibr_soft->bs_pcix_rbar_percent_allowed) / 100) + 1;
+
+	    /* round down the newly caclulated max_out to a valid number in
+	     * max_splittrans_to_numbuf[]
+	     */
+	    for (index = 0; index < MAX_SPLIT_TABLE-1; index++)
+		if (max_splittrans_to_numbuf[index + 1] > max_out)
+		    break;
+
+	    pcix_cmdreg_p->max_split = index;
+	    num_rbar = max_splittrans_to_numbuf[pcix_cmdreg_p->max_split];
+	    pcibr_soft->bs_pcix_rbar_inuse += num_rbar;
+            pcibr_soft->bs_pcix_rbar_avail -= num_rbar;
+	    pcix_cmdreg_p->max_mem_read_cnt = pcix_statreg_p->max_mem_read_cnt;
+	}
+        /*
+         * The kernel only allows functions to have so many variable args,
+         * attempting to call PCIBR_DEBUG_ALWAYS() with more than 5 printf
+         * arguments fails so sprintf() it into a temporary string.
+         */
+	if (pcibr_debug_mask & PCIBR_DEBUG_RBAR) {
+            sprintf(tmp_str,"\t  %d/%d   \t    %d    \t  %d  \t  %d  \t  %d\n",
+	            PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func,
+	            max_splittrans_to_numbuf[pcix_statreg_p->max_out_split],
+	            max_splittrans_to_numbuf[pcix_cmdreg_p->max_split],
+	            pcibr_soft->bs_pcix_rbar_inuse, 
+		    pcibr_soft->bs_pcix_rbar_avail);
+            PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RBAR, pcibr_soft->bs_vhdl, 
+		        "%s", tmp_str));
+	}
+    }
+    return(0);
+}
+
 int as_debug = 0;
 /*
  * pcibr_slot_addr_space_init
@@ -878,34 +1226,27 @@
 pcibr_slot_addr_space_init(devfs_handle_t pcibr_vhdl,
 			   pciio_slot_t	slot)
 {
-    pcibr_soft_t	pcibr_soft;
-    pcibr_info_h	pcibr_infoh;
-    pcibr_info_t	pcibr_info;
+    pcibr_soft_t	 pcibr_soft;
+    pcibr_info_h	 pcibr_infoh;
+    pcibr_info_t	 pcibr_info;
     bridge_t		*bridge;
-    iopaddr_t		pci_io_fb, pci_io_fl;
-    iopaddr_t		pci_lo_fb, pci_lo_fl;
-    iopaddr_t		pci_hi_fb, pci_hi_fl;
-    size_t              align;
-    iopaddr_t           mask;
-    int		    	nbars;
-    int		       	nfunc;
-    int			func;
-    int			win;
+    size_t               align_slot;
+    iopaddr_t            mask;
+    int		       	 nbars;
+    int		       	 nfunc;
+    int			 func;
+    int			 win;
+    int                  rc = 0;
 
     pcibr_soft = pcibr_soft_get(pcibr_vhdl);
 
-    if (!pcibr_soft || !PCIBR_VALID_SLOT(slot))
+    if (!pcibr_soft)
 	return(EINVAL);
 
-    bridge = pcibr_soft->bs_base;
-
-    /* Get the current values for the allocated PCI address spaces */
-    PCI_ADDR_SPACE_LIMITS_LOAD();
+    if (!PCIBR_VALID_SLOT(pcibr_soft, slot))
+	return(EINVAL);
 
-    if (as_debug)
-#ifdef LATER
-    PCI_ADDR_SPACE_LIMITS_PRINT();
-#endif
+    bridge = pcibr_soft->bs_base;
 
     /* allocate address space,
      * for windows that have not been
@@ -934,10 +1275,7 @@
      * the entire "lo" area is only a
      * megabyte, total ...
      */
-    align = (slot < 2) ? 0x200000 : 0x100000;
-    mask = -align;
-    pci_io_fb = (pci_io_fb + align - 1) & mask;
-    pci_hi_fb = (pci_hi_fb + align - 1) & mask;
+    align_slot = (slot < 2) ? 0x200000 : 0x100000;
 
     for (func = 0; func < nfunc; ++func) {
 	cfg_p                   cfgw;
@@ -945,7 +1283,9 @@
 	pciio_space_t           space;
 	iopaddr_t               base;
 	size_t                  size;
-	cfg_p                   pci_cfg_cmd_reg_p;
+#ifdef PCI_LATER
+	char			tmp_str[256];
+#endif
 	unsigned                pci_cfg_cmd_reg;
 	unsigned                pci_cfg_cmd_reg_add = 0;
 
@@ -957,13 +1297,15 @@
 	if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE)
 	    continue;
 	
-	cfgw = bridge->b_type0_cfg_dev[slot].f[func].l;
+        cfgw = pcibr_func_config_addr(bridge, 0, slot, func, 0);
 	wptr = cfgw + PCI_CFG_BASE_ADDR_0 / 4;
 
-	nbars = PCI_CFG_BASE_ADDRS;
+	if ((do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_HEADER_TYPE, 1) & 0x7f) != 0)
+	    nbars = 2;
+	else
+	    nbars = PCI_CFG_BASE_ADDRS;
 
 	for (win = 0; win < nbars; ++win) {
-
 	    space = pcibr_info->f_window[win].w_space;
 	    base = pcibr_info->f_window[win].w_base;
 	    size = pcibr_info->f_window[win].w_size;
@@ -972,77 +1314,93 @@
 		continue;
 
 	    if (base >= size) {
-#if DEBUG && PCI_DEBUG
-		printk("pcibr: slot %d func %d window %d is in %d[0x%x..0x%x], alloc by prom\n",
-			slot, func, win, space, base, base + size - 1);
-#endif
+		/*
+         	 * The kernel only allows functions to have so many variable
+                 * args attempting to call PCIBR_DEBUG_ALWAYS() with more than
+         	 * 5 printf arguments fails so sprintf() it into a temporary 
+		 * string (tmp_str).
+         	 */
+#if defined(SUPPORT_PRINTING_R_FORMAT)
+		if (pcibr_debug_mask & PCIBR_DEBUG_BAR) {
+		    sprintf(tmp_str, "pcibr_slot_addr_space_init: slot=%d, "
+			"func=%d win %d is in %r [0x%x..0x%x], allocated by "
+			"prom\n", PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot),
+			func, win, space, space_desc, base, base + size - 1);
+		    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_BAR, pcibr_vhdl, 
+				"%s",tmp_str));
+		}
+#endif	/* SUPPORT_PRINTING_R_FORMAT */
 		continue;		/* already allocated */
 	    }
-	    align = size;		/* ie. 0x00001000 */
-	    if (align < _PAGESZ)
-		align = _PAGESZ;	/* ie. 0x00004000 */
-	    mask = -align;		/* ie. 0xFFFFC000 */
 
 	    switch (space) {
 	    case PCIIO_SPACE_IO:
-		base = (pci_io_fb + align - 1) & mask;
-		if ((base + size) > pci_io_fl) {
-		    base = 0;
-		    break;
-		}
-		pci_io_fb = base + size;
+                base = pcibr_bus_addr_alloc(pcibr_soft,
+                                            &pcibr_info->f_window[win],
+                                            PCIIO_SPACE_IO,
+                                            0, size, align_slot);
+                if (!base)
+                    rc = ENOSPC;
 		break;
 		
 	    case PCIIO_SPACE_MEM:
-#ifdef SN1_LITTLE_ENDIAN
-		if ((wptr[((win*4)^4)/4] & PCI_BA_MEM_LOCATION) ==
-#else
-		if ((wptr[win] & PCI_BA_MEM_LOCATION) ==
-#endif  /* LITTLE_ENDIAN */
-		    PCI_BA_MEM_1MEG) {
+		if ((do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), wptr, (win * 4), 4) &
+		     PCI_BA_MEM_LOCATION) == PCI_BA_MEM_1MEG) {
+                    int align = size;           /* ie. 0x00001000 */
+                    
+                    if (align < _PAGESZ)
+                        align = _PAGESZ;        /* ie. 0x00004000 */
+ 
 		    /* allocate from 20-bit PCI space */
-		    base = (pci_lo_fb + align - 1) & mask;
-		    if ((base + size) > pci_lo_fl) {
-			base = 0;
-			break;
-		    }
-		    pci_lo_fb = base + size;
+                    base = pcibr_bus_addr_alloc(pcibr_soft,
+                                                &pcibr_info->f_window[win],
+                                                PCIIO_SPACE_MEM,
+                                                0, size, align);
+                    if (!base)
+                        rc = ENOSPC;
 		} else {
 		    /* allocate from 32-bit or 64-bit PCI space */
-		    base = (pci_hi_fb + align - 1) & mask;
-		    if ((base + size) > pci_hi_fl) {
-			base = 0;
-			break;
-		    }
-		    pci_hi_fb = base + size;
+                    base = pcibr_bus_addr_alloc(pcibr_soft,
+                                                &pcibr_info->f_window[win],
+                                                PCIIO_SPACE_MEM32,
+                                                0, size, align_slot);
+		    if (!base) 
+			rc = ENOSPC;
 		}
 		break;
 		
 	    default:
 		base = 0;
-#if DEBUG && PCI_DEBUG
-		printk("pcibr: slot %d window %d had bad space code %d\n",
-			slot, win, space);
-#endif
+		PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_BAR, pcibr_vhdl,
+			    "pcibr_slot_addr_space_init: slot=%d, window %d "
+			    "had bad space code %d\n", 
+			    PCIBR_DEVICE_TO_SLOT(pcibr_soft,slot), win, space));
 	    }
 	    pcibr_info->f_window[win].w_base = base;
-#ifdef SN1_LITTLE_ENDIAN
-	    wptr[((win*4)^4)/4] = base;
-#if DEBUG && PCI_DEBUG
-		printk("Setting base address 0x%p base 0x%x\n", &(wptr[((win*4)^4)/4]), base);
-#endif
-#else
-	    wptr[win] = base;
-#endif  /* LITTLE_ENDIAN */
+	    do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), wptr, (win * 4), 4, base);
 
-#if DEBUG && PCI_DEBUG
-	    if (base >= size)
-		printk("pcibr: slot %d func %d window %d is in %d [0x%x..0x%x], alloc by pcibr\n",
-			slot, func, win, space, base, base + size - 1);
-	    else
-		printk("pcibr: slot %d func %d window %d, unable to alloc 0x%x in 0x%p\n",
-			slot, func, win, size, space);
-#endif
+#if defined(SUPPORT_PRINTING_R_FORMAT)
+	    if (pcibr_debug_mask & PCIBR_DEBUG_BAR) {
+                if (base >= size) {
+		    sprintf(tmp_str,"pcibr_slot_addr_space_init: slot=%d, func="
+				    "%d, win %d is in %r[0x%x..0x%x], "
+				    "allocated by pcibr\n",
+				    PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), 
+				    func, win, space, space_desc, base, 
+				    base + size - 1);
+		     PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_BAR, pcibr_vhdl, 
+				 "%s",tmp_str));
+	        }
+		else {
+		    sprintf(tmp_str,"pcibr_slot_addr_space_init: slot=%d, func="
+				    "%d, win %d, unable to alloc 0x%x in %r\n",
+				    PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), 
+				    func, win, size, space, space_desc);
+		    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_BAR, pcibr_vhdl, 
+				"%s",tmp_str));
+	        }
+	    }
+#endif	/* SUPPORT_PRINTING_R_FORMAT */
 	}				/* next base */
 
 	/*
@@ -1055,34 +1413,23 @@
 	    (pcibr_soft->bs_slot[slot].bss_device_id != IOC3_DEVICE_ID_NUM)) {
 
 	    wptr = cfgw + PCI_EXPANSION_ROM / 4;
-#ifdef SN1_LITTLE_ENDIAN
-	    wptr[1] = 0xFFFFF000;
-	    mask = wptr[1];
-#else
-	    *wptr = 0xFFFFF000;
-	    mask = *wptr;
-#endif  /* LITTLE_ENDIAN */
+	    do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), wptr, 0, 4, 0xFFFFF000);
+	    mask = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), wptr, 0, 4);
 	    if (mask & 0xFFFFF000) {
 		size = mask & -mask;
-		align = size;
-		if (align < _PAGESZ)
-		    align = _PAGESZ;
-		mask = -align;
-		base = (pci_hi_fb + align - 1) & mask;
-		if ((base + size) > pci_hi_fl)
-		    base = size = 0;
+                base = pcibr_bus_addr_alloc(pcibr_soft,
+                                            &pcibr_info->f_rwindow,
+                                            PCIIO_SPACE_MEM32, 
+                                            0, size, align_slot);
+		if (!base)
+		    rc = ENOSPC;
 		else {
-		    pci_hi_fb = base + size;
-#ifdef SN1_LITTLE_ENDIAN
-		    wptr[1] = base;
-#else
-		    *wptr = base;
-#endif  /* LITTLE_ENDIAN */
-#if DEBUG && PCI_DEBUG
-		    printk("%s/%d ROM in 0x%lx..0x%lx (alloc by pcibr)\n",
-			    pcibr_soft->bs_name, slot,
-			    base, base + size - 1);
-#endif
+		    do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), wptr, 0, 4, base);
+		    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_BAR, pcibr_vhdl,
+				"pcibr_slot_addr_space_init: slot=%d, func=%d, "
+				"ROM in [0x%X..0x%X], allocated by pcibr\n",
+				PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), 
+				func, base, base + size - 1));
 		}
 	    }
 	}
@@ -1116,30 +1463,25 @@
 
 	pci_cfg_cmd_reg_add |= PCI_CMD_BUS_MASTER;
 
-	pci_cfg_cmd_reg_p = cfgw + PCI_CFG_COMMAND / 4;
-	pci_cfg_cmd_reg = *pci_cfg_cmd_reg_p;
+	pci_cfg_cmd_reg = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_COMMAND, 4);
+
 #if PCI_FBBE	/* XXX- check here to see if dev can do fast-back-to-back */
 	if (!((pci_cfg_cmd_reg >> 16) & PCI_STAT_F_BK_BK_CAP))
 	    fast_back_to_back_enable = 0;
 #endif
 	pci_cfg_cmd_reg &= 0xFFFF;
 	if (pci_cfg_cmd_reg_add & ~pci_cfg_cmd_reg)
-	    *pci_cfg_cmd_reg_p = pci_cfg_cmd_reg | pci_cfg_cmd_reg_add;
-	
+	    do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_COMMAND, 4, 
+				pci_cfg_cmd_reg | pci_cfg_cmd_reg_add);
     }				/* next func */
-
-    /* Now that we have allocated new chunks of PCI address spaces to this
-     * card we need to update the bookkeeping values which indicate
-     * the current PCI address space allocations.
-     */
-    PCI_ADDR_SPACE_LIMITS_STORE();
-    return(0);
+    return(rc);
 }
 
 /*
  * pcibr_slot_device_init
  * 	Setup the device register in the bridge for this PCI slot.
  */
+
 int
 pcibr_slot_device_init(devfs_handle_t pcibr_vhdl,
 		       pciio_slot_t slot)
@@ -1150,7 +1492,10 @@
 
     pcibr_soft = pcibr_soft_get(pcibr_vhdl);
 
-    if (!pcibr_soft || !PCIBR_VALID_SLOT(slot))
+    if (!pcibr_soft)
+	return(EINVAL);
+
+    if (!PCIBR_VALID_SLOT(pcibr_soft, slot))
 	return(EINVAL);
 
     bridge = pcibr_soft->bs_base;
@@ -1161,21 +1506,28 @@
      */
     devreg = bridge->b_device[slot].reg;
     devreg &= ~BRIDGE_DEV_PAGE_CHK_DIS;
-    devreg |= BRIDGE_DEV_COH | BRIDGE_DEV_VIRTUAL_EN;
-#ifdef LITTLE_ENDIAN
-    devreg |= BRIDGE_DEV_DEV_SWAP;
-#endif
+
+    /*
+     * PIC WAR. PV# 855271
+     * Don't enable virtual channels in the PIC by default.
+     * Can cause problems with 32-bit devices. (The bit is only intended
+     * for 64-bit devices).  We set the bit in pcibr_try_set_device()
+     * if we're 64-bit and requesting virtual channels.
+     */
+    if (IS_PIC_SOFT(pcibr_soft) && PCIBR_WAR_ENABLED(PV855271, pcibr_soft))
+	devreg |= BRIDGE_DEV_COH;
+    else
+	devreg |= BRIDGE_DEV_COH | BRIDGE_DEV_VIRTUAL_EN;
     pcibr_soft->bs_slot[slot].bss_device = devreg;
     bridge->b_device[slot].reg = devreg;
 
-#if DEBUG && PCI_DEBUG
-	printk("pcibr Device(%d): 0x%lx\n", slot, bridge->b_device[slot].reg);
-#endif
-
-#if DEBUG && PCI_DEBUG
-    printk("pcibr: PCI space allocation done.\n");
+#ifdef PIC_LATER
+    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DEVREG, pcibr_vhdl,
+		"pcibr_slot_device_init: Device(%d): %R\n",
+		slot, devreg, device_bits));
+#else
+    printk("pcibr_slot_device_init: Device(%d) 0x%x\n", slot, devreg);
 #endif
-
     return(0);
 }
 
@@ -1194,7 +1546,10 @@
 
     pcibr_soft = pcibr_soft_get(pcibr_vhdl);
 
-    if (!pcibr_soft || !PCIBR_VALID_SLOT(slot))
+    if (!pcibr_soft)
+	return(EINVAL);
+
+    if (!PCIBR_VALID_SLOT(pcibr_soft, slot))
 	return(EINVAL);
 
     slotp = &pcibr_soft->bs_slot[slot];
@@ -1259,17 +1614,25 @@
     pcibr_info_t	pcibr_info;
     async_attach_t	aa = NULL;
     int			func;
-    devfs_handle_t	xconn_vhdl,conn_vhdl;
+    devfs_handle_t	xconn_vhdl, conn_vhdl;
+#ifdef PIC_LATER
+    devfs_handle_t	scsi_vhdl;
+#endif
     int			nfunc;
     int                 error_func;
     int                 error_slot = 0;
     int                 error = ENODEV;
+#ifdef PIC_LATER
+    int                 hwg_err;
+#endif
 
     pcibr_soft = pcibr_soft_get(pcibr_vhdl);
 
-    if (!pcibr_soft || !PCIBR_VALID_SLOT(slot))
+    if (!pcibr_soft)
 	return(EINVAL);
 
+    if (!PCIBR_VALID_SLOT(pcibr_soft, slot))
+	return(EINVAL);
 
     if (pcibr_soft->bs_slot[slot].has_host) {
         return(EPERM);
@@ -1303,6 +1666,40 @@
 
 	error_func = pciio_device_attach(conn_vhdl, drv_flags);
 
+#ifdef PIC_LATER
+        /*
+         * Try to assign well-known SCSI controller numbers for hot-plug
+         * insert
+         */
+        if (drv_flags) {
+
+            hwg_err = hwgraph_path_lookup(conn_vhdl, EDGE_LBL_SCSI_CTLR "/0",
+                                          &scsi_vhdl, NULL);
+
+            if (hwg_err == GRAPH_SUCCESS)
+                scsi_ctlr_nums_add(baseio_pci_vhdl, scsi_vhdl);
+
+            /* scsi_vhdl will be the final vertex in either the complete path
+             * on success or a partial path on failure;  in either case,
+             * unreference that vertex.
+             */
+            hwgraph_vertex_unref(scsi_vhdl);
+
+            hwg_err = hwgraph_path_lookup(conn_vhdl, EDGE_LBL_SCSI_CTLR "/1",
+                                          &scsi_vhdl, NULL);
+
+            if (hwg_err == GRAPH_SUCCESS)
+                scsi_ctlr_nums_add(baseio_pci_vhdl, scsi_vhdl);
+
+            /* scsi_vhdl will be the final vertex in either the complete path
+             * on success or a partial path on failure;  in either case,
+             * unreference that vertex.
+             */
+            hwgraph_vertex_unref(scsi_vhdl);
+
+        }
+#endif /* PIC_LATER */
+
         pcibr_info->f_att_det_error = error_func;
 
 	if (error_func)
@@ -1313,9 +1710,12 @@
     }				/* next func */
 
     if (error) {
-	if ((error != ENODEV) && (error != EUNATCH))
+	if ((error != ENODEV) && (error != EUNATCH) && (error != EPERM)) {
+	    pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK;
 	    pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_INCMPLT;
+	}
     } else {
+        pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK;
         pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_CMPLT;
     }
         
@@ -1344,16 +1744,15 @@
 
     pcibr_soft = pcibr_soft_get(pcibr_vhdl);
 
-    if (!pcibr_soft || !PCIBR_VALID_SLOT(slot))
+    if (!pcibr_soft)
+	return(EINVAL);
+
+    if (!PCIBR_VALID_SLOT(pcibr_soft, slot))
 	return(EINVAL);
 
     if (pcibr_soft->bs_slot[slot].has_host)
         return(EPERM);
 
-    /* Make sure that we do not detach a system critical function vertex */
-    if(pcibr_is_slot_sys_critical(pcibr_vhdl, slot))
-        return(EPERM);
-
     nfunc = pcibr_soft->bs_slot[slot].bss_ninfo;
     pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos;
 
@@ -1367,6 +1766,14 @@
 	if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE)
 	    continue;
 
+	if (IS_PCIX(pcibr_soft) && pcibr_info->f_pcix_cap) {
+	    int max_out;
+
+	    pcibr_soft->bs_pcix_num_funcs--;
+	    max_out = pcibr_info->f_pcix_cap->pcix_type0_status.max_out_split;
+	    pcibr_soft->bs_pcix_split_tot -= max_splittrans_to_numbuf[max_out];
+	}
+
 	conn_vhdl = pcibr_info->f_vertex;
 
 	error_func = pciio_device_detach(conn_vhdl, drv_flags);
@@ -1380,22 +1787,22 @@
 
     }				/* next func */
 
-    pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK;
 
     if (error) {
-	if ((error != ENODEV) && (error != EUNATCH))
+	if ((error != ENODEV) && (error != EUNATCH) && (error != EPERM)) {
+	    pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK;
             pcibr_soft->bs_slot[slot].slot_status |= SLOT_SHUTDOWN_INCMPLT;
+	}
     } else {
         if (conn_vhdl != GRAPH_VERTEX_NONE) 
             pcibr_device_unregister(conn_vhdl);
+        pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK;
         pcibr_soft->bs_slot[slot].slot_status |= SLOT_SHUTDOWN_CMPLT;
     }
         
     return(error);
 }
 
-#ifdef LATER
-
 /*
  * pcibr_slot_attach
  *	This is a place holder routine to keep track of all the
@@ -1411,81 +1818,16 @@
                   int         *sub_errorp)
 {
     pcibr_soft_t  pcibr_soft = pcibr_soft_get(pcibr_vhdl);
+#ifdef PIC_LATER
     timespec_t    ts;
-    int		  error;
-
-    if (!(pcibr_soft->bs_slot[slot].slot_status & SLOT_POWER_UP)) { 
-        /* Power-up the slot */
-        error = pcibr_slot_pwr(pcibr_vhdl, slot, L1_REQ_PCI_UP, l1_msg);
-        if (error) {
-            if (sub_errorp)
-                *sub_errorp = error;
-            return(PCI_L1_ERR);
-        } else {
-            pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_POWER_MASK;
-            pcibr_soft->bs_slot[slot].slot_status |= SLOT_POWER_UP;
-        }
-
-#ifdef LATER
-        /*
-         * Allow cards like the Alteon Gigabit Ethernet Adapter to complete
-         * on-card initialization following the slot reset
-         */
-         ts.tv_sec = 0;                      /* 0 secs */
-         ts.tv_nsec = 500 * (1000 * 1000);   /* 500 msecs */
-         nano_delay(&ts);
-#else
 #endif
-#if 0
-        /* Reset the slot */
-        error = pcibr_slot_reset(pcibr_vhdl, slot)
-        if (error) {
-            if (sub_errorp)
-                *sub_errorp = error;
-            return(PCI_SLOT_RESET_ERR);
-        }
-#endif
-
-        /* Find out what is out there */
-        error = pcibr_slot_info_init(pcibr_vhdl, slot);
-        if (error) {
-            if (sub_errorp)
-                *sub_errorp = error;
-            return(PCI_SLOT_INFO_INIT_ERR);
-        }
-
-        /* Set up the address space for this slot in the PCI land */
-        error = pcibr_slot_addr_space_init(pcibr_vhdl, slot);
-        if (error) {
-            if (sub_errorp)
-                *sub_errorp = error;
-            return(PCI_SLOT_ADDR_INIT_ERR);
-        }
-
-        /* Setup the device register */
-        error = pcibr_slot_device_init(pcibr_vhdl, slot);
-        if (error) {
-            if (sub_errorp)
-                *sub_errorp = error;
-            return(PCI_SLOT_DEV_INIT_ERR);
-        }
-
-        /* Setup host/guest relations */
-        error = pcibr_slot_guest_info_init(pcibr_vhdl, slot);
-        if (error) {
-            if (sub_errorp)
-                *sub_errorp = error;
-            return(PCI_SLOT_GUEST_INIT_ERR);
-        }
-
-        /* Initial RRB management */
-        error = pcibr_slot_initial_rrb_alloc(pcibr_vhdl, slot);
-        if (error) {
-            if (sub_errorp)
-                *sub_errorp = error;
-            return(PCI_SLOT_RRB_ALLOC_ERR);
-        }
+    int		  error;
 
+    /* Do not allow a multi-function card to be hot-plug inserted */
+    if (pcibr_soft->bs_slot[slot].bss_ninfo > 1) {
+        if (sub_errorp)
+            *sub_errorp = EPERM;
+        return(PCI_MULTI_FUNC_ERR);
     }
 
     /* Call the device attach */
@@ -1501,7 +1843,6 @@
 
     return(0);
 }
-#endif	/* LATER */
 
 /*
  * pcibr_slot_detach
@@ -1511,13 +1852,42 @@
 int
 pcibr_slot_detach(devfs_handle_t pcibr_vhdl,
 		  pciio_slot_t slot,
-		  int          drv_flags)
+		  int          drv_flags,
+		  char        *l1_msg,
+                  int         *sub_errorp)
 {
+    pcibr_soft_t  pcibr_soft = pcibr_soft_get(pcibr_vhdl);
     int		  error;
     
+    /* Make sure that we do not detach a system critical function vertex */
+    if(pcibr_is_slot_sys_critical(pcibr_vhdl, slot))
+        return(PCI_IS_SYS_CRITICAL);
+
     /* Call the device detach function */
     error = (pcibr_slot_call_device_detach(pcibr_vhdl, slot, drv_flags));
-    return (error);
+    if (error) {
+        if (sub_errorp)
+            *sub_errorp = error;       
+        return(PCI_SLOT_DRV_DETACH_ERR);
+    }
+
+    /* Recalculate the RBARs for all the devices on the bus since we've
+     * just freed some up and some of the devices could use them.
+     */
+    if (IS_PCIX(pcibr_soft)) {
+	int tmp_slot;
+
+	pcibr_soft->bs_pcix_rbar_inuse = 0;
+	pcibr_soft->bs_pcix_rbar_avail = NUM_RBAR;
+	pcibr_soft->bs_pcix_rbar_percent_allowed = 
+					pcibr_pcix_rbars_calc(pcibr_soft);
+
+	for (tmp_slot = pcibr_soft->bs_min_slot;
+			tmp_slot < PCIBR_NUM_SLOTS(pcibr_soft); ++tmp_slot)
+            (void)pcibr_slot_pcix_rbar_init(pcibr_soft, tmp_slot);
+    }
+
+    return (0);
 
 }
 
@@ -1540,11 +1910,14 @@
     devfs_handle_t        conn_vhdl = GRAPH_VERTEX_NONE;
     int                 nfunc;
     int                 func;
-    boolean_t		is_sys_critical_vertex(devfs_handle_t);
+    boolean_t is_sys_critical_vertex(devfs_handle_t);
 
     pcibr_soft = pcibr_soft_get(pcibr_vhdl);
-    if (!pcibr_soft || !PCIBR_VALID_SLOT(slot))
-        return(0);
+    if (!pcibr_soft)
+	return(EINVAL);
+
+    if (!PCIBR_VALID_SLOT(pcibr_soft, slot))
+	return(EINVAL);
 
     nfunc = pcibr_soft->bs_slot[slot].bss_ninfo;
     pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos;
@@ -1574,57 +1947,112 @@
 }
 
 /*
- * pcibr_probe_slot: read a config space word
- * while trapping any errors; reutrn zero if
+ * pcibr_probe_slot_pic: read a config space word
+ * while trapping any errors; return zero if
  * all went OK, or nonzero if there was an error.
  * The value read, if any, is passed back
  * through the valp parameter.
  */
-int
-pcibr_probe_slot(bridge_t *bridge,
-		 cfg_p cfg,
-		 unsigned *valp)
+static int
+pcibr_probe_slot_pic(bridge_t *bridge,
+                 cfg_p cfg,
+                 unsigned *valp)
 {
-    int                     rv;
-    bridgereg_t             old_enable, new_enable;
-    int badaddr_val(volatile void *, int, volatile void *);
-
-    old_enable = bridge->b_int_enable;
-    new_enable = old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT;
+	int rv;
+	picreg_t p_old_enable = (picreg_t)0, p_new_enable;
+	extern int badaddr_val(volatile void *, int, volatile void *);
+
+	p_old_enable = bridge->p_int_enable_64;
+	p_new_enable = p_old_enable & ~(BRIDGE_IMR_PCI_MST_TIMEOUT | PIC_ISR_PCIX_MTOUT);
+	bridge->p_int_enable_64 = p_new_enable;
+
+	if (bridge->p_err_int_view_64 & (BRIDGE_ISR_PCI_MST_TIMEOUT | PIC_ISR_PCIX_MTOUT))
+		bridge->p_int_rst_stat_64 = BRIDGE_IRR_MULTI_CLR;
+
+	if (bridge->p_int_status_64 & (BRIDGE_IRR_PCI_GRP | PIC_PCIX_GRP_CLR)) {
+		bridge->p_int_rst_stat_64 = (BRIDGE_IRR_PCI_GRP_CLR | PIC_PCIX_GRP_CLR);
+		(void) bridge->b_wid_tflush;	/* flushbus */
+	}
+	rv = badaddr_val((void *) cfg, 4, valp);
+	if (bridge->p_err_int_view_64 & (BRIDGE_ISR_PCI_MST_TIMEOUT | PIC_ISR_PCIX_MTOUT)) {
+		bridge->p_int_rst_stat_64 = BRIDGE_IRR_MULTI_CLR;
+		rv = 1;         /* unoccupied slot */
+	}
+	bridge->p_int_enable_64 = p_old_enable;
+	bridge->b_wid_tflush;		/* wait until Bridge PIO complete */
+	return(rv);
+}
 
-    bridge->b_int_enable = new_enable;
+/*
+ * pcibr_probe_slot_non_pic: read a config space word
+ * while trapping any errors; return zero if
+ * all went OK, or nonzero if there was an error.
+ * The value read, if any, is passed back
+ * through the valp parameter.
+ */
+static int
+pcibr_probe_slot_non_pic(bridge_t *bridge,
+                 cfg_p cfg,
+                 unsigned *valp)
+{
+	int                     rv;
+	bridgereg_t             b_old_enable = (bridgereg_t)0, b_new_enable = (bridgereg_t)0;
+	extern int              badaddr_val(volatile void *, int, volatile void *);
+
+        b_old_enable = bridge->b_int_enable;
+        b_new_enable = b_old_enable & ~BRIDGE_IMR_PCI_MST_TIMEOUT;
+        bridge->b_int_enable = b_new_enable;
 
 	/*
 	 * The xbridge doesn't clear b_err_int_view unless
 	 * multi-err is cleared...
 	 */
-	if (is_xbridge(bridge))
-	    if (bridge->b_err_int_view & BRIDGE_ISR_PCI_MST_TIMEOUT) {
+	if (is_xbridge(bridge)) {
+	    if (bridge->b_err_int_view & BRIDGE_ISR_PCI_MST_TIMEOUT)
 		bridge->b_int_rst_stat = BRIDGE_IRR_MULTI_CLR;
-	    }
-
-    if (bridge->b_int_status & BRIDGE_IRR_PCI_GRP) {
-	bridge->b_int_rst_stat = BRIDGE_IRR_PCI_GRP_CLR;
-	(void) bridge->b_wid_tflush;	/* flushbus */
-    }
-    rv = badaddr_val((void *) cfg, 4, valp);
+	}
 
+        if (bridge->b_int_status & BRIDGE_IRR_PCI_GRP) {
+	    bridge->b_int_rst_stat = BRIDGE_IRR_PCI_GRP_CLR;
+	    (void) bridge->b_wid_tflush;	/* flushbus */
+        }
+	rv = badaddr_val((void *) (((uint64_t)cfg) ^ 4), 4, valp);
 	/*
 	 * The xbridge doesn't set master timeout in b_int_status
 	 * here.  Fortunately it's in error_interrupt_view.
 	 */
-	if (is_xbridge(bridge))
+	if (is_xbridge(bridge)) {
 	    if (bridge->b_err_int_view & BRIDGE_ISR_PCI_MST_TIMEOUT) {
 		bridge->b_int_rst_stat = BRIDGE_IRR_MULTI_CLR;
 		rv = 1;		/* unoccupied slot */
 	    }
+	}
+        bridge->b_int_enable = b_old_enable;
+	bridge->b_wid_tflush;		/* wait until Bridge PIO complete */
+
+    	return(rv);
+}
 
-    bridge->b_int_enable = old_enable;
-    bridge->b_wid_tflush;		/* wait until Bridge PIO complete */
 
-    return rv;
+/*
+ * pcibr_probe_slot: read a config space word
+ * while trapping any errors; return zero if
+ * all went OK, or nonzero if there was an error.
+ * The value read, if any, is passed back
+ * through the valp parameter.
+ */
+static int
+pcibr_probe_slot(bridge_t *bridge,
+		 cfg_p cfg,
+		 unsigned *valp)
+{
+    if ( is_pic(bridge) )
+	return(pcibr_probe_slot_pic(bridge, cfg, valp));
+    else
+	return(pcibr_probe_slot_non_pic(bridge, cfg, valp));
 }
 
+
 void
 pcibr_device_info_free(devfs_handle_t pcibr_vhdl, pciio_slot_t slot)
 {
@@ -1632,10 +2060,13 @@
     pcibr_info_t	pcibr_info;
     pciio_function_t	func;
     pcibr_soft_slot_t	slotp = &pcibr_soft->bs_slot[slot];
+    bridge_t           *bridge = pcibr_soft->bs_base; 
+    cfg_p               cfgw;
     int			nfunc = slotp->bss_ninfo;
     int                 bar;
     int                 devio_index;
     int                 s;
+    unsigned            cmd_reg;
 
 
     for (func = 0; func < nfunc; func++) {
@@ -1646,10 +2077,19 @@
 
         s = pcibr_lock(pcibr_soft);
 
+        /* Disable memory and I/O BARs */
+	cfgw = pcibr_func_config_addr(bridge, 0, slot, func, 0);
+	cmd_reg = do_pcibr_config_get(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_COMMAND, 4);
+	cmd_reg &= (PCI_CMD_MEM_SPACE | PCI_CMD_IO_SPACE);
+	do_pcibr_config_set(IS_PIC_SOFT(pcibr_soft), cfgw, PCI_CFG_COMMAND, 4, cmd_reg);
+
         for (bar = 0; bar < PCI_CFG_BASE_ADDRS; bar++) {
             if (pcibr_info->f_window[bar].w_space == PCIIO_SPACE_NONE)
                 continue;
 
+            /* Free the PCI bus space */
+            pciibr_bus_addr_free(pcibr_soft, &pcibr_info->f_window[bar]);
+
             /* Get index of the DevIO(x) register used to access this BAR */
             devio_index = pcibr_info->f_window[bar].w_devio_index;
 
@@ -1664,6 +2104,11 @@
             }
         }
 
+        /* Free the Expansion ROM PCI bus space */
+	if(pcibr_info->f_rbase && pcibr_info->f_rsize) {
+            pciibr_bus_addr_free(pcibr_soft, &pcibr_info->f_rwindow);
+        }
+
         pcibr_unlock(pcibr_soft, s);
 
 	slotp->bss_infos[func] = 0;
@@ -1690,3 +2135,68 @@
     slotp->bss_cmd_shadow = 0;
 
 }
+
+
+iopaddr_t
+pcibr_bus_addr_alloc(pcibr_soft_t pcibr_soft, pciio_win_info_t win_info_p,
+                     pciio_space_t space, int start, int size, int align)
+{
+    pciio_win_map_t win_map_p;
+
+    switch (space) {
+
+        case PCIIO_SPACE_IO:
+            win_map_p = &pcibr_soft->bs_io_win_map;
+            break;
+
+        case PCIIO_SPACE_MEM:
+            win_map_p = &pcibr_soft->bs_swin_map;
+            break;
+
+        case PCIIO_SPACE_MEM32:
+            win_map_p = &pcibr_soft->bs_mem_win_map;
+            break;
+
+        default:
+            return 0;
+
+    }
+    return pciio_device_win_alloc(win_map_p,
+				  win_info_p
+				  ? &win_info_p->w_win_alloc
+				  : NULL,
+				  start, size, align);
+}
+
+
+void
+pciibr_bus_addr_free(pcibr_soft_t pcibr_soft, pciio_win_info_t win_info_p)
+{
+	pciio_device_win_free(&win_info_p->w_win_alloc);
+}
+
+/*
+ * given a vertex_hdl to the pcibr_vhdl, return the brick's bus number
+ * associated with that vertex_hdl.  The true mapping happens from the
+ * io_brick_tab[] array defined in ml/SN/iograph.c
+ */
+int
+pcibr_widget_to_bus(devfs_handle_t pcibr_vhdl) 
+{
+    pcibr_soft_t	pcibr_soft = pcibr_soft_get(pcibr_vhdl);
+    xwidgetnum_t	widget = pcibr_soft->bs_xid;
+    int			bricktype = pcibr_soft->bs_bricktype;
+    int			bus = pcibr_soft->bs_busnum;
+    
+    /* 
+     * For PIC there are 2 busses per widget and pcibr_soft->bs_busnum
+     * will be 0 or 1.  For [X]BRIDGE there is 1 bus per widget and 
+     * pcibr_soft->bs_busnum will always be zero.  So we add bs_busnum
+     * to what io_brick_map_widget returns to get the bus number.
+     */
+    if ((bus += io_brick_map_widget(bricktype, widget)) > 0) {
+	return bus;
+    } else {
+	return 0;
+    }
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/pciio.c linux-2.4.21-pre6/arch/ia64/sn/io/sn2/pciio.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/pciio.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn2/pciio.c	2003-03-26 23:49:29.000000000 +0000
@@ -0,0 +1,1877 @@
+/* $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) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#define	USRPCI	0
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/xtalk/xbow.h>	/* Must be before iograph.h to get MAX_PORT_NUM */
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/hcl_util.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/pci/bridge.h>
+#include <asm/sn/ioerror_handling.h>
+#include <asm/sn/pci/pciio.h>
+#include <asm/sn/pci/pciio_private.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/io.h>
+#include <asm/sn/pci/pci_bus_cvlink.h>
+#include <asm/sn/ate_utils.h>
+#include <asm/sn/simulator.h>
+
+#ifdef __ia64
+#define rmallocmap atemapalloc
+#define rmfreemap atemapfree
+#define rmfree atefree
+#define rmalloc atealloc
+#endif
+
+#define DEBUG_PCIIO
+#undef DEBUG_PCIIO	/* turn this on for yet more console output */
+
+
+#define GET_NEW(ptr)	(ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL))
+#define DO_DEL(ptr)	(kfree(ptr))
+
+char                    pciio_info_fingerprint[] = "pciio_info";
+
+cdl_p                   pciio_registry = NULL;
+
+int
+badaddr_val(volatile void *addr, int len, volatile void *ptr)
+{
+	int ret = 0;
+	volatile void *new_addr;
+
+	switch (len) {
+		case 4:
+			new_addr = (void *) addr;
+			ret = ia64_sn_probe_io_slot((long)new_addr, len, (void *)ptr);
+			break;
+		default:
+			printk(KERN_WARNING "badaddr_val given len %x but supports len of 4 only\n", len);
+	}
+
+	if (ret < 0)
+		panic("badaddr_val: unexpected status (%d) in probing", ret);
+	return(ret);
+
+}
+
+
+nasid_t
+get_console_nasid(void)
+{
+	extern nasid_t console_nasid;
+	extern nasid_t master_baseio_nasid;
+
+	if (console_nasid < 0) {
+		console_nasid = ia64_sn_get_console_nasid();
+		if (console_nasid < 0) {
+// ZZZ What do we do if we don't get a console nasid on the hardware????
+			if (IS_RUNNING_ON_SIMULATOR() )
+				console_nasid = master_baseio_nasid;
+		}
+	} 
+	return console_nasid;
+}
+
+nasid_t
+get_master_baseio_nasid(void)
+{
+	extern nasid_t master_baseio_nasid;
+	extern char master_baseio_wid;
+
+	if (master_baseio_nasid < 0) {
+		nasid_t tmp;
+
+		master_baseio_nasid = ia64_sn_get_master_baseio_nasid();
+
+		if ( master_baseio_nasid >= 0 ) {
+        		master_baseio_wid = WIDGETID_GET(KL_CONFIG_CH_CONS_INFO(master_baseio_nasid)->memory_base);
+		}
+	} 
+	return master_baseio_nasid;
+}
+
+int
+hub_dma_enabled(devfs_handle_t xconn_vhdl)
+{
+	return(0);
+}
+
+int
+hub_error_devenable(devfs_handle_t xconn_vhdl, int devnum, int error_code)
+{
+	return(0);
+}
+
+void
+ioerror_dump(char *name, int error_code, int error_mode, ioerror_t *ioerror)
+{
+}
+
+/******
+ ****** end hack defines ......
+ ******/
+
+
+
+
+/* =====================================================================
+ *    PCI Generic Bus Provider
+ * Implement PCI provider operations.  The pciio* layer provides a
+ * platform-independent interface for PCI devices.  This layer
+ * switches among the possible implementations of a PCI adapter.
+ */
+
+/* =====================================================================
+ *    Provider Function Location SHORTCUT
+ *
+ * On platforms with only one possible PCI provider, macros can be
+ * set up at the top that cause the table lookups and indirections to
+ * completely disappear.
+ */
+
+
+/* =====================================================================
+ *    Function Table of Contents
+ */
+
+#if !defined(DEV_FUNC)
+static pciio_provider_t *pciio_to_provider_fns(devfs_handle_t dev);
+#endif
+
+pciio_piomap_t          pciio_piomap_alloc(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, size_t, unsigned);
+void                    pciio_piomap_free(pciio_piomap_t);
+caddr_t                 pciio_piomap_addr(pciio_piomap_t, iopaddr_t, size_t);
+
+void                    pciio_piomap_done(pciio_piomap_t);
+caddr_t                 pciio_piotrans_addr(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, unsigned);
+caddr_t			pciio_pio_addr(devfs_handle_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, pciio_piomap_t *, unsigned);
+
+iopaddr_t               pciio_piospace_alloc(devfs_handle_t, device_desc_t, pciio_space_t, size_t, size_t);
+void                    pciio_piospace_free(devfs_handle_t, pciio_space_t, iopaddr_t, size_t);
+
+pciio_dmamap_t          pciio_dmamap_alloc(devfs_handle_t, device_desc_t, size_t, unsigned);
+void                    pciio_dmamap_free(pciio_dmamap_t);
+iopaddr_t               pciio_dmamap_addr(pciio_dmamap_t, paddr_t, size_t);
+alenlist_t              pciio_dmamap_list(pciio_dmamap_t, alenlist_t, unsigned);
+void                    pciio_dmamap_done(pciio_dmamap_t);
+iopaddr_t               pciio_dmatrans_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, unsigned);
+alenlist_t              pciio_dmatrans_list(devfs_handle_t, device_desc_t, alenlist_t, unsigned);
+void			pciio_dmamap_drain(pciio_dmamap_t);
+void			pciio_dmaaddr_drain(devfs_handle_t, paddr_t, size_t);
+void			pciio_dmalist_drain(devfs_handle_t, alenlist_t);
+iopaddr_t               pciio_dma_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, pciio_dmamap_t *, unsigned);
+
+pciio_intr_t            pciio_intr_alloc(devfs_handle_t, device_desc_t, pciio_intr_line_t, devfs_handle_t);
+void                    pciio_intr_free(pciio_intr_t);
+int                     pciio_intr_connect(pciio_intr_t, intr_func_t, intr_arg_t);
+void                    pciio_intr_disconnect(pciio_intr_t);
+devfs_handle_t            pciio_intr_cpu_get(pciio_intr_t);
+
+void			pciio_slot_func_to_name(char *, pciio_slot_t, pciio_function_t);
+
+void                    pciio_provider_startup(devfs_handle_t);
+void                    pciio_provider_shutdown(devfs_handle_t);
+
+pciio_endian_t          pciio_endian_set(devfs_handle_t, pciio_endian_t, pciio_endian_t);
+pciio_priority_t        pciio_priority_set(devfs_handle_t, pciio_priority_t);
+devfs_handle_t            pciio_intr_dev_get(pciio_intr_t);
+
+devfs_handle_t            pciio_pio_dev_get(pciio_piomap_t);
+pciio_slot_t            pciio_pio_slot_get(pciio_piomap_t);
+pciio_space_t           pciio_pio_space_get(pciio_piomap_t);
+iopaddr_t               pciio_pio_pciaddr_get(pciio_piomap_t);
+ulong                   pciio_pio_mapsz_get(pciio_piomap_t);
+caddr_t                 pciio_pio_kvaddr_get(pciio_piomap_t);
+
+devfs_handle_t            pciio_dma_dev_get(pciio_dmamap_t);
+pciio_slot_t            pciio_dma_slot_get(pciio_dmamap_t);
+
+pciio_info_t            pciio_info_chk(devfs_handle_t);
+pciio_info_t            pciio_info_get(devfs_handle_t);
+void                    pciio_info_set(devfs_handle_t, pciio_info_t);
+devfs_handle_t            pciio_info_dev_get(pciio_info_t);
+pciio_slot_t            pciio_info_slot_get(pciio_info_t);
+pciio_function_t        pciio_info_function_get(pciio_info_t);
+pciio_vendor_id_t       pciio_info_vendor_id_get(pciio_info_t);
+pciio_device_id_t       pciio_info_device_id_get(pciio_info_t);
+devfs_handle_t            pciio_info_master_get(pciio_info_t);
+arbitrary_info_t        pciio_info_mfast_get(pciio_info_t);
+pciio_provider_t       *pciio_info_pops_get(pciio_info_t);
+error_handler_f	       *pciio_info_efunc_get(pciio_info_t);
+error_handler_arg_t    *pciio_info_einfo_get(pciio_info_t);
+pciio_space_t		pciio_info_bar_space_get(pciio_info_t, int);
+iopaddr_t		pciio_info_bar_base_get(pciio_info_t, int);
+size_t			pciio_info_bar_size_get(pciio_info_t, int);
+iopaddr_t		pciio_info_rom_base_get(pciio_info_t);
+size_t			pciio_info_rom_size_get(pciio_info_t);
+
+void                    pciio_init(void);
+int                     pciio_attach(devfs_handle_t);
+
+void                    pciio_provider_register(devfs_handle_t, pciio_provider_t *pciio_fns);
+void                    pciio_provider_unregister(devfs_handle_t);
+pciio_provider_t       *pciio_provider_fns_get(devfs_handle_t);
+
+int                     pciio_driver_register(pciio_vendor_id_t, pciio_device_id_t, char *driver_prefix, unsigned);
+void                    pciio_driver_unregister(char *driver_prefix);
+
+devfs_handle_t            pciio_device_register(devfs_handle_t, devfs_handle_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t);
+
+void			pciio_device_unregister(devfs_handle_t);
+pciio_info_t		pciio_device_info_new(pciio_info_t, devfs_handle_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t);
+void			pciio_device_info_free(pciio_info_t);
+devfs_handle_t		pciio_device_info_register(devfs_handle_t, pciio_info_t);
+void			pciio_device_info_unregister(devfs_handle_t, pciio_info_t);
+int                     pciio_device_attach(devfs_handle_t, int);
+int			pciio_device_detach(devfs_handle_t, int);
+void                    pciio_error_register(devfs_handle_t, error_handler_f *, error_handler_arg_t);
+
+int                     pciio_reset(devfs_handle_t);
+int                     pciio_write_gather_flush(devfs_handle_t);
+int                     pciio_slot_inuse(devfs_handle_t);
+
+/* =====================================================================
+ *    Provider Function Location
+ *
+ *      If there is more than one possible provider for
+ *      this platform, we need to examine the master
+ *      vertex of the current vertex for a provider
+ *      function structure, and indirect through the
+ *      appropriately named member.
+ */
+
+#if !defined(DEV_FUNC)
+
+static pciio_provider_t *
+pciio_to_provider_fns(devfs_handle_t dev)
+{
+    pciio_info_t            card_info;
+    pciio_provider_t       *provider_fns;
+
+    /*
+     * We're called with two types of vertices, one is
+     * the bridge vertex (ends with "pci") and the other is the
+     * pci slot vertex (ends with "pci/[0-8]").  For the first type
+     * we need to get the provider from the PFUNCS label.  For
+     * the second we get it from fastinfo/c_pops.
+     */
+    provider_fns = pciio_provider_fns_get(dev);
+    if (provider_fns == NULL) {
+	card_info = pciio_info_get(dev);
+	if (card_info != NULL) {
+		provider_fns = pciio_info_pops_get(card_info);
+	}
+    }
+
+    if (provider_fns == NULL)
+#if defined(SUPPORT_PRINTING_V_FORMAT)
+	PRINT_PANIC("%v: provider_fns == NULL", dev);
+#else
+	PRINT_PANIC("0x%p: provider_fns == NULL", (void *)dev);
+#endif
+
+    return provider_fns;
+
+}
+
+#define DEV_FUNC(dev,func)	pciio_to_provider_fns(dev)->func
+#define CAST_PIOMAP(x)		((pciio_piomap_t)(x))
+#define CAST_DMAMAP(x)		((pciio_dmamap_t)(x))
+#define CAST_INTR(x)		((pciio_intr_t)(x))
+#endif
+
+/*
+ * Many functions are not passed their vertex
+ * information directly; rather, they must
+ * dive through a resource map. These macros
+ * are available to coordinate this detail.
+ */
+#define PIOMAP_FUNC(map,func)		DEV_FUNC((map)->pp_dev,func)
+#define DMAMAP_FUNC(map,func)		DEV_FUNC((map)->pd_dev,func)
+#define INTR_FUNC(intr_hdl,func)	DEV_FUNC((intr_hdl)->pi_dev,func)
+
+/* =====================================================================
+ *          PIO MANAGEMENT
+ *
+ *      For mapping system virtual address space to
+ *      pciio space on a specified card
+ */
+
+pciio_piomap_t
+pciio_piomap_alloc(devfs_handle_t dev,	/* set up mapping for this device */
+		   device_desc_t dev_desc,	/* device descriptor */
+		   pciio_space_t space,	/* CFG, MEM, IO, or a device-decoded window */
+		   iopaddr_t addr,	/* lowest address (or offset in window) */
+		   size_t byte_count,	/* size of region containing our mappings */
+		   size_t byte_count_max,	/* maximum size of a mapping */
+		   unsigned flags)
+{					/* defined in sys/pio.h */
+    return (pciio_piomap_t) DEV_FUNC(dev, piomap_alloc)
+	(dev, dev_desc, space, addr, byte_count, byte_count_max, flags);
+}
+
+void
+pciio_piomap_free(pciio_piomap_t pciio_piomap)
+{
+    PIOMAP_FUNC(pciio_piomap, piomap_free)
+	(CAST_PIOMAP(pciio_piomap));
+}
+
+caddr_t
+pciio_piomap_addr(pciio_piomap_t pciio_piomap,	/* mapping resources */
+		  iopaddr_t pciio_addr,	/* map for this pciio address */
+		  size_t byte_count)
+{					/* map this many bytes */
+    pciio_piomap->pp_kvaddr = PIOMAP_FUNC(pciio_piomap, piomap_addr)
+	(CAST_PIOMAP(pciio_piomap), pciio_addr, byte_count);
+
+    return pciio_piomap->pp_kvaddr;
+}
+
+void
+pciio_piomap_done(pciio_piomap_t pciio_piomap)
+{
+    PIOMAP_FUNC(pciio_piomap, piomap_done)
+	(CAST_PIOMAP(pciio_piomap));
+}
+
+caddr_t
+pciio_piotrans_addr(devfs_handle_t dev,	/* translate for this device */
+		    device_desc_t dev_desc,	/* device descriptor */
+		    pciio_space_t space,	/* CFG, MEM, IO, or a device-decoded window */
+		    iopaddr_t addr,	/* starting address (or offset in window) */
+		    size_t byte_count,	/* map this many bytes */
+		    unsigned flags)
+{					/* (currently unused) */
+    return DEV_FUNC(dev, piotrans_addr)
+	(dev, dev_desc, space, addr, byte_count, flags);
+}
+
+caddr_t
+pciio_pio_addr(devfs_handle_t dev,	/* translate for this device */
+	       device_desc_t dev_desc,	/* device descriptor */
+	       pciio_space_t space,	/* CFG, MEM, IO, or a device-decoded window */
+	       iopaddr_t addr,		/* starting address (or offset in window) */
+	       size_t byte_count,	/* map this many bytes */
+	       pciio_piomap_t *mapp,	/* where to return the map pointer */
+	       unsigned flags)
+{					/* PIO flags */
+    pciio_piomap_t          map = 0;
+    int			    errfree = 0;
+    caddr_t                 res;
+
+    if (mapp) {
+	map = *mapp;			/* possible pre-allocated map */
+	*mapp = 0;			/* record "no map used" */
+    }
+
+    res = pciio_piotrans_addr
+	(dev, dev_desc, space, addr, byte_count, flags);
+    if (res)
+	return res;			/* pciio_piotrans worked */
+
+    if (!map) {
+	map = pciio_piomap_alloc
+	    (dev, dev_desc, space, addr, byte_count, byte_count, flags);
+	if (!map)
+	    return res;			/* pciio_piomap_alloc failed */
+	errfree = 1;
+    }
+
+    res = pciio_piomap_addr
+	(map, addr, byte_count);
+    if (!res) {
+	if (errfree)
+	    pciio_piomap_free(map);
+	return res;			/* pciio_piomap_addr failed */
+    }
+    if (mapp)
+	*mapp = map;			/* pass back map used */
+
+    return res;				/* pciio_piomap_addr succeeded */
+}
+
+iopaddr_t
+pciio_piospace_alloc(devfs_handle_t dev,	/* Device requiring space */
+		     device_desc_t dev_desc,	/* Device descriptor */
+		     pciio_space_t space,	/* MEM32/MEM64/IO */
+		     size_t byte_count,	/* Size of mapping */
+		     size_t align)
+{					/* Alignment needed */
+    if (align < NBPP)
+	align = NBPP;
+    return DEV_FUNC(dev, piospace_alloc)
+	(dev, dev_desc, space, byte_count, align);
+}
+
+void
+pciio_piospace_free(devfs_handle_t dev,	/* Device freeing space */
+		    pciio_space_t space,	/* Type of space        */
+		    iopaddr_t pciaddr,	/* starting address */
+		    size_t byte_count)
+{					/* Range of address   */
+    DEV_FUNC(dev, piospace_free)
+	(dev, space, pciaddr, byte_count);
+}
+
+/* =====================================================================
+ *          DMA MANAGEMENT
+ *
+ *      For mapping from pci space to system
+ *      physical space.
+ */
+
+pciio_dmamap_t
+pciio_dmamap_alloc(devfs_handle_t dev,	/* set up mappings for this device */
+		   device_desc_t dev_desc,	/* device descriptor */
+		   size_t byte_count_max,	/* max size of a mapping */
+		   unsigned flags)
+{					/* defined in dma.h */
+    return (pciio_dmamap_t) DEV_FUNC(dev, dmamap_alloc)
+	(dev, dev_desc, byte_count_max, flags);
+}
+
+void
+pciio_dmamap_free(pciio_dmamap_t pciio_dmamap)
+{
+    DMAMAP_FUNC(pciio_dmamap, dmamap_free)
+	(CAST_DMAMAP(pciio_dmamap));
+}
+
+iopaddr_t
+pciio_dmamap_addr(pciio_dmamap_t pciio_dmamap,	/* use these mapping resources */
+		  paddr_t paddr,	/* map for this address */
+		  size_t byte_count)
+{					/* map this many bytes */
+    return DMAMAP_FUNC(pciio_dmamap, dmamap_addr)
+	(CAST_DMAMAP(pciio_dmamap), paddr, byte_count);
+}
+
+alenlist_t
+pciio_dmamap_list(pciio_dmamap_t pciio_dmamap,	/* use these mapping resources */
+		  alenlist_t alenlist,	/* map this Address/Length List */
+		  unsigned flags)
+{
+    return DMAMAP_FUNC(pciio_dmamap, dmamap_list)
+	(CAST_DMAMAP(pciio_dmamap), alenlist, flags);
+}
+
+void
+pciio_dmamap_done(pciio_dmamap_t pciio_dmamap)
+{
+    DMAMAP_FUNC(pciio_dmamap, dmamap_done)
+	(CAST_DMAMAP(pciio_dmamap));
+}
+
+iopaddr_t
+pciio_dmatrans_addr(devfs_handle_t dev,	/* translate for this device */
+		    device_desc_t dev_desc,	/* device descriptor */
+		    paddr_t paddr,	/* system physical address */
+		    size_t byte_count,	/* length */
+		    unsigned flags)
+{					/* defined in dma.h */
+    return DEV_FUNC(dev, dmatrans_addr)
+	(dev, dev_desc, paddr, byte_count, flags);
+}
+
+alenlist_t
+pciio_dmatrans_list(devfs_handle_t dev,	/* translate for this device */
+		    device_desc_t dev_desc,	/* device descriptor */
+		    alenlist_t palenlist,	/* system address/length list */
+		    unsigned flags)
+{					/* defined in dma.h */
+    return DEV_FUNC(dev, dmatrans_list)
+	(dev, dev_desc, palenlist, flags);
+}
+
+iopaddr_t
+pciio_dma_addr(devfs_handle_t dev,	/* translate for this device */
+	       device_desc_t dev_desc,	/* device descriptor */
+	       paddr_t paddr,		/* system physical address */
+	       size_t byte_count,	/* length */
+	       pciio_dmamap_t *mapp,	/* map to use, then map we used */
+	       unsigned flags)
+{					/* PIO flags */
+    pciio_dmamap_t          map = 0;
+    int			    errfree = 0;
+    iopaddr_t               res;
+
+    if (mapp) {
+	map = *mapp;			/* possible pre-allocated map */
+	*mapp = 0;			/* record "no map used" */
+    }
+
+    res = pciio_dmatrans_addr
+	(dev, dev_desc, paddr, byte_count, flags);
+    if (res)
+	return res;			/* pciio_dmatrans worked */
+
+    if (!map) {
+	map = pciio_dmamap_alloc
+	    (dev, dev_desc, byte_count, flags);
+	if (!map)
+	    return res;			/* pciio_dmamap_alloc failed */
+	errfree = 1;
+    }
+
+    res = pciio_dmamap_addr
+	(map, paddr, byte_count);
+    if (!res) {
+	if (errfree)
+	    pciio_dmamap_free(map);
+	return res;			/* pciio_dmamap_addr failed */
+    }
+    if (mapp)
+	*mapp = map;			/* pass back map used */
+
+    return res;				/* pciio_dmamap_addr succeeded */
+}
+
+void
+pciio_dmamap_drain(pciio_dmamap_t map)
+{
+    DMAMAP_FUNC(map, dmamap_drain)
+	(CAST_DMAMAP(map));
+}
+
+void
+pciio_dmaaddr_drain(devfs_handle_t dev, paddr_t addr, size_t size)
+{
+    DEV_FUNC(dev, dmaaddr_drain)
+	(dev, addr, size);
+}
+
+void
+pciio_dmalist_drain(devfs_handle_t dev, alenlist_t list)
+{
+    DEV_FUNC(dev, dmalist_drain)
+	(dev, list);
+}
+
+/* =====================================================================
+ *          INTERRUPT MANAGEMENT
+ *
+ *      Allow crosstalk devices to establish interrupts
+ */
+
+/*
+ * Allocate resources required for an interrupt as specified in intr_desc.
+ * Return resource handle in intr_hdl.
+ */
+pciio_intr_t
+pciio_intr_alloc(devfs_handle_t dev,	/* which Crosstalk device */
+		 device_desc_t dev_desc,	/* device descriptor */
+		 pciio_intr_line_t lines,	/* INTR line(s) to attach */
+		 devfs_handle_t owner_dev)
+{					/* owner of this interrupt */
+    return (pciio_intr_t) DEV_FUNC(dev, intr_alloc)
+	(dev, dev_desc, lines, owner_dev);
+}
+
+/*
+ * Free resources consumed by intr_alloc.
+ */
+void
+pciio_intr_free(pciio_intr_t intr_hdl)
+{
+    INTR_FUNC(intr_hdl, intr_free)
+	(CAST_INTR(intr_hdl));
+}
+
+/*
+ * Associate resources allocated with a previous pciio_intr_alloc call with the
+ * described handler, arg, name, etc.
+ *
+ * Returns 0 on success, returns <0 on failure.
+ */
+int
+pciio_intr_connect(pciio_intr_t intr_hdl,
+		intr_func_t intr_func, intr_arg_t intr_arg)	/* pciio intr resource handle */
+{
+    return INTR_FUNC(intr_hdl, intr_connect)
+	(CAST_INTR(intr_hdl), intr_func, intr_arg);
+}
+
+/*
+ * Disassociate handler with the specified interrupt.
+ */
+void
+pciio_intr_disconnect(pciio_intr_t intr_hdl)
+{
+    INTR_FUNC(intr_hdl, intr_disconnect)
+	(CAST_INTR(intr_hdl));
+}
+
+/*
+ * Return a hwgraph vertex that represents the CPU currently
+ * targeted by an interrupt.
+ */
+devfs_handle_t
+pciio_intr_cpu_get(pciio_intr_t intr_hdl)
+{
+    return INTR_FUNC(intr_hdl, intr_cpu_get)
+	(CAST_INTR(intr_hdl));
+}
+
+void
+pciio_slot_func_to_name(char		       *name,
+			pciio_slot_t		slot,
+			pciio_function_t	func)
+{
+    /*
+     * standard connection points:
+     *
+     * PCIIO_SLOT_NONE:	.../pci/direct
+     * PCIIO_FUNC_NONE: .../pci/<SLOT>			ie. .../pci/3
+     * multifunction:   .../pci/<SLOT><FUNC>		ie. .../pci/3c
+     */
+
+    if (slot == PCIIO_SLOT_NONE)
+	sprintf(name, EDGE_LBL_DIRECT);
+    else if (func == PCIIO_FUNC_NONE)
+	sprintf(name, "%d", slot);
+    else
+	sprintf(name, "%d%c", slot, 'a'+func);
+}
+
+/*
+ * pciio_cardinfo_get
+ *
+ * Get the pciio info structure corresponding to the
+ * specified PCI "slot" (we like it when the same index
+ * number is used for the PCI IDSEL, the REQ/GNT pair,
+ * and the interrupt line being used for INTA. We like
+ * it so much we call it the slot number).
+ */
+static pciio_info_t
+pciio_cardinfo_get(
+		      devfs_handle_t pciio_vhdl,
+		      pciio_slot_t pci_slot)
+{
+    char                    namebuf[16];
+    pciio_info_t	    info = 0;
+    devfs_handle_t	    conn;
+
+    pciio_slot_func_to_name(namebuf, pci_slot, PCIIO_FUNC_NONE);
+    if (GRAPH_SUCCESS ==
+	hwgraph_traverse(pciio_vhdl, namebuf, &conn)) {
+	info = pciio_info_chk(conn);
+	hwgraph_vertex_unref(conn);
+    }
+
+    return info;
+}
+
+
+/*
+ * pciio_error_handler:
+ * dispatch an error to the appropriate
+ * pciio connection point, or process
+ * it as a generic pci error.
+ * Yes, the first parameter is the
+ * provider vertex at the middle of
+ * the bus; we get to the pciio connect
+ * point using the ioerror widgetdev field.
+ *
+ * This function is called by the
+ * specific PCI provider, after it has figured
+ * out where on the PCI bus (including which slot,
+ * if it can tell) the error came from.
+ */
+/*ARGSUSED */
+int
+pciio_error_handler(
+		       devfs_handle_t pciio_vhdl,
+		       int error_code,
+		       ioerror_mode_t mode,
+		       ioerror_t *ioerror)
+{
+    pciio_info_t            pciio_info;
+    devfs_handle_t            pconn_vhdl;
+#if USRPCI
+    devfs_handle_t            usrpci_v;
+#endif
+    pciio_slot_t            slot;
+
+    int                     retval;
+#ifdef EHE_ENABLE
+    error_state_t	    e_state;
+#endif /* EHE_ENABLE */
+
+#if DEBUG && ERROR_DEBUG
+    printk("%v: pciio_error_handler\n", pciio_vhdl);
+#endif
+
+    IOERR_PRINTF(printk(KERN_NOTICE "%v: PCI Bus Error: Error code: %d Error mode: %d\n",
+			 pciio_vhdl, error_code, mode));
+
+    /* If there is an error handler sitting on
+     * the "no-slot" connection point, give it
+     * first crack at the error. NOTE: it is
+     * quite possible that this function may
+     * do further refining of the ioerror.
+     */
+    pciio_info = pciio_cardinfo_get(pciio_vhdl, PCIIO_SLOT_NONE);
+    if (pciio_info && pciio_info->c_efunc) {
+	pconn_vhdl = pciio_info_dev_get(pciio_info);
+
+#ifdef EHE_ENABLE
+	e_state = error_state_get(pciio_vhdl);
+
+	if (e_state == ERROR_STATE_ACTION)
+	    (void)error_state_set(pciio_vhdl, ERROR_STATE_NONE);
+
+	if (error_state_set(pconn_vhdl,e_state) == ERROR_RETURN_CODE_CANNOT_SET_STATE)
+	    return(IOERROR_UNHANDLED);
+#endif 
+
+	retval = pciio_info->c_efunc
+	    (pciio_info->c_einfo, error_code, mode, ioerror);
+	if (retval != IOERROR_UNHANDLED)
+	    return retval;
+    }
+
+    /* Is the error associated with a particular slot?
+     */
+    if (IOERROR_FIELDVALID(ioerror, widgetdev)) {
+	short widgetdev;
+	/*
+	 * NOTE : 
+	 * widgetdev is a 4byte value encoded as slot in the higher order
+	 * 2 bytes and function in the lower order 2 bytes.
+	 */
+	IOERROR_GETVALUE(widgetdev, ioerror, widgetdev);
+	slot = pciio_widgetdev_slot_get(widgetdev);
+
+	/* If this slot has an error handler,
+	 * deliver the error to it.
+	 */
+	pciio_info = pciio_cardinfo_get(pciio_vhdl, slot);
+	if (pciio_info != NULL) {
+	    if (pciio_info->c_efunc != NULL) {
+
+		pconn_vhdl = pciio_info_dev_get(pciio_info);
+
+#ifdef EHE_ENABLE
+		e_state = error_state_get(pciio_vhdl);
+
+		if (e_state == ERROR_STATE_ACTION)
+		    (void)error_state_set(pciio_vhdl, ERROR_STATE_NONE);
+
+		if (error_state_set(pconn_vhdl,e_state) ==
+		    ERROR_RETURN_CODE_CANNOT_SET_STATE)
+		    return(IOERROR_UNHANDLED);
+#endif /* EHE_ENABLE */
+
+		retval = pciio_info->c_efunc
+		    (pciio_info->c_einfo, error_code, mode, ioerror);
+		if (retval != IOERROR_UNHANDLED)
+		    return retval;
+	    }
+
+#if USRPCI
+	    /* If the USRPCI driver is available and
+	     * knows about this connection point,
+	     * deliver the error to it.
+	     *
+	     * OK to use pconn_vhdl here, even though we
+	     * have already UNREF'd it, since we know that
+	     * it is not going away.
+	     */
+	    pconn_vhdl = pciio_info_dev_get(pciio_info);
+	    if (GRAPH_SUCCESS == hwgraph_traverse(pconn_vhdl, EDGE_LBL_USRPCI, &usrpci_v)) {
+		iopaddr_t busaddr;
+		IOERROR_GETVALUE(busaddr, ioerror, busaddr);
+		retval = usrpci_error_handler (usrpci_v, error_code, busaddr);
+		hwgraph_vertex_unref(usrpci_v);
+		if (retval != IOERROR_UNHANDLED) {
+		    /*
+		     * This unref is not needed.  If this code is called often enough,
+		     * the system will crash, due to vertex reference count reaching 0,
+		     * causing vertex to be unallocated.  -jeremy
+		     * hwgraph_vertex_unref(pconn_vhdl);
+		     */
+		    return retval;
+		}
+	    }
+#endif
+	}
+    }
+
+    return (mode == MODE_DEVPROBE)
+	? IOERROR_HANDLED	/* probes are OK */
+	: IOERROR_UNHANDLED;	/* otherwise, foo! */
+}
+
+/* =====================================================================
+ *          CONFIGURATION MANAGEMENT
+ */
+
+/*
+ * Startup a crosstalk provider
+ */
+void
+pciio_provider_startup(devfs_handle_t pciio_provider)
+{
+    DEV_FUNC(pciio_provider, provider_startup)
+	(pciio_provider);
+}
+
+/*
+ * Shutdown a crosstalk provider
+ */
+void
+pciio_provider_shutdown(devfs_handle_t pciio_provider)
+{
+    DEV_FUNC(pciio_provider, provider_shutdown)
+	(pciio_provider);
+}
+
+/*
+ * Specify endianness constraints.  The driver tells us what the device
+ * does and how it would like to see things in memory.  We reply with
+ * how things will actually appear in memory.
+ */
+pciio_endian_t
+pciio_endian_set(devfs_handle_t dev,
+		 pciio_endian_t device_end,
+		 pciio_endian_t desired_end)
+{
+    ASSERT((device_end == PCIDMA_ENDIAN_BIG) || (device_end == PCIDMA_ENDIAN_LITTLE));
+    ASSERT((desired_end == PCIDMA_ENDIAN_BIG) || (desired_end == PCIDMA_ENDIAN_LITTLE));
+
+#if DEBUG
+#if defined(SUPPORT_PRINTING_V_FORMAT)
+    printk(KERN_ALERT  "%v: pciio_endian_set is going away.\n"
+	    "\tplease use PCIIO_BYTE_STREAM or PCIIO_WORD_VALUES in your\n"
+	    "\tpciio_dmamap_alloc and pciio_dmatrans calls instead.\n",
+	    dev);
+#else
+    printk(KERN_ALERT  "0x%x: pciio_endian_set is going away.\n"
+	    "\tplease use PCIIO_BYTE_STREAM or PCIIO_WORD_VALUES in your\n"
+	    "\tpciio_dmamap_alloc and pciio_dmatrans calls instead.\n",
+	    dev);
+#endif
+#endif
+
+    return DEV_FUNC(dev, endian_set)
+	(dev, device_end, desired_end);
+}
+
+/*
+ * Specify PCI arbitration priority.
+ */
+pciio_priority_t
+pciio_priority_set(devfs_handle_t dev,
+		   pciio_priority_t device_prio)
+{
+    ASSERT((device_prio == PCI_PRIO_HIGH) || (device_prio == PCI_PRIO_LOW));
+
+    return DEV_FUNC(dev, priority_set)
+	(dev, device_prio);
+}
+
+/*
+ * Read value of configuration register
+ */
+uint64_t
+pciio_config_get(devfs_handle_t	dev,
+		 unsigned	reg,
+		 unsigned	size)
+{
+    uint64_t	value = 0;
+    unsigned	shift = 0;
+
+    /* handle accesses that cross words here,
+     * since that's common code between all
+     * possible providers.
+     */
+    while (size > 0) {
+	unsigned	biw = 4 - (reg&3);
+	if (biw > size)
+	    biw = size;
+
+	value |= DEV_FUNC(dev, config_get)
+	    (dev, reg, biw) << shift;
+
+	shift += 8*biw;
+	reg += biw;
+	size -= biw;
+    }
+    return value;
+}
+
+/*
+ * Change value of configuration register
+ */
+void
+pciio_config_set(devfs_handle_t	dev,
+		 unsigned	reg,
+		 unsigned	size,
+		 uint64_t	value)
+{
+    /* handle accesses that cross words here,
+     * since that's common code between all
+     * possible providers.
+     */
+    while (size > 0) {
+	unsigned	biw = 4 - (reg&3);
+	if (biw > size)
+	    biw = size;
+	    
+	DEV_FUNC(dev, config_set)
+	    (dev, reg, biw, value);
+	reg += biw;
+	size -= biw;
+	value >>= biw * 8;
+    }
+}
+
+/* =====================================================================
+ *          GENERIC PCI SUPPORT FUNCTIONS
+ */
+
+/*
+ * Issue a hardware reset to a card.
+ */
+int
+pciio_reset(devfs_handle_t dev)
+{
+    return DEV_FUNC(dev, reset) (dev);
+}
+
+/*
+ * flush write gather buffers
+ */
+int
+pciio_write_gather_flush(devfs_handle_t dev)
+{
+    return DEV_FUNC(dev, write_gather_flush) (dev);
+}
+
+devfs_handle_t
+pciio_intr_dev_get(pciio_intr_t pciio_intr)
+{
+    return (pciio_intr->pi_dev);
+}
+
+/****** Generic crosstalk pio interfaces ******/
+devfs_handle_t
+pciio_pio_dev_get(pciio_piomap_t pciio_piomap)
+{
+    return (pciio_piomap->pp_dev);
+}
+
+pciio_slot_t
+pciio_pio_slot_get(pciio_piomap_t pciio_piomap)
+{
+    return (pciio_piomap->pp_slot);
+}
+
+pciio_space_t
+pciio_pio_space_get(pciio_piomap_t pciio_piomap)
+{
+    return (pciio_piomap->pp_space);
+}
+
+iopaddr_t
+pciio_pio_pciaddr_get(pciio_piomap_t pciio_piomap)
+{
+    return (pciio_piomap->pp_pciaddr);
+}
+
+ulong
+pciio_pio_mapsz_get(pciio_piomap_t pciio_piomap)
+{
+    return (pciio_piomap->pp_mapsz);
+}
+
+caddr_t
+pciio_pio_kvaddr_get(pciio_piomap_t pciio_piomap)
+{
+    return (pciio_piomap->pp_kvaddr);
+}
+
+/****** Generic crosstalk dma interfaces ******/
+devfs_handle_t
+pciio_dma_dev_get(pciio_dmamap_t pciio_dmamap)
+{
+    return (pciio_dmamap->pd_dev);
+}
+
+pciio_slot_t
+pciio_dma_slot_get(pciio_dmamap_t pciio_dmamap)
+{
+    return (pciio_dmamap->pd_slot);
+}
+
+/****** Generic pci slot information interfaces ******/
+
+pciio_info_t
+pciio_info_chk(devfs_handle_t pciio)
+{
+    arbitrary_info_t        ainfo = 0;
+
+    hwgraph_info_get_LBL(pciio, INFO_LBL_PCIIO, &ainfo);
+    return (pciio_info_t) ainfo;
+}
+
+pciio_info_t
+pciio_info_get(devfs_handle_t pciio)
+{
+    pciio_info_t            pciio_info;
+
+    pciio_info = (pciio_info_t) hwgraph_fastinfo_get(pciio);
+
+#ifdef DEBUG_PCIIO
+    {
+	int pos;
+	char dname[256];
+	pos = devfs_generate_path(pciio, dname, 256);
+	printk("%s : path= %s\n", __FUNCTION__, &dname[pos]);
+    }
+#endif /* DEBUG_PCIIO */
+
+    if ((pciio_info != NULL) &&
+	(pciio_info->c_fingerprint != pciio_info_fingerprint)
+	&& (pciio_info->c_fingerprint != NULL)) {
+
+	return((pciio_info_t)-1); /* Should panic .. */
+    }
+	
+
+    return pciio_info;
+}
+
+void
+pciio_info_set(devfs_handle_t pciio, pciio_info_t pciio_info)
+{
+    if (pciio_info != NULL)
+	pciio_info->c_fingerprint = pciio_info_fingerprint;
+    hwgraph_fastinfo_set(pciio, (arbitrary_info_t) pciio_info);
+
+    /* Also, mark this vertex as a PCI slot
+     * and use the pciio_info, so pciio_info_chk
+     * can work (and be fairly efficient).
+     */
+    hwgraph_info_add_LBL(pciio, INFO_LBL_PCIIO,
+			 (arbitrary_info_t) pciio_info);
+}
+
+devfs_handle_t
+pciio_info_dev_get(pciio_info_t pciio_info)
+{
+    return (pciio_info->c_vertex);
+}
+
+pciio_slot_t
+pciio_info_slot_get(pciio_info_t pciio_info)
+{
+    return (pciio_info->c_slot);
+}
+
+pciio_function_t
+pciio_info_function_get(pciio_info_t pciio_info)
+{
+    return (pciio_info->c_func);
+}
+
+pciio_vendor_id_t
+pciio_info_vendor_id_get(pciio_info_t pciio_info)
+{
+    return (pciio_info->c_vendor);
+}
+
+pciio_device_id_t
+pciio_info_device_id_get(pciio_info_t pciio_info)
+{
+    return (pciio_info->c_device);
+}
+
+devfs_handle_t
+pciio_info_master_get(pciio_info_t pciio_info)
+{
+    return (pciio_info->c_master);
+}
+
+arbitrary_info_t
+pciio_info_mfast_get(pciio_info_t pciio_info)
+{
+    return (pciio_info->c_mfast);
+}
+
+pciio_provider_t       *
+pciio_info_pops_get(pciio_info_t pciio_info)
+{
+    return (pciio_info->c_pops);
+}
+
+error_handler_f	       *
+pciio_info_efunc_get(pciio_info_t pciio_info)
+{
+    return (pciio_info->c_efunc);
+}
+
+error_handler_arg_t    *
+pciio_info_einfo_get(pciio_info_t pciio_info)
+{
+    return (pciio_info->c_einfo);
+}
+
+pciio_space_t
+pciio_info_bar_space_get(pciio_info_t info, int win)
+{
+    return info->c_window[win].w_space;
+}
+
+iopaddr_t
+pciio_info_bar_base_get(pciio_info_t info, int win)
+{
+    return info->c_window[win].w_base;
+}
+
+size_t
+pciio_info_bar_size_get(pciio_info_t info, int win)
+{
+    return info->c_window[win].w_size;
+}
+
+iopaddr_t
+pciio_info_rom_base_get(pciio_info_t info)
+{
+    return info->c_rbase;
+}
+
+size_t
+pciio_info_rom_size_get(pciio_info_t info)
+{
+    return info->c_rsize;
+}
+
+
+/* =====================================================================
+ *          GENERIC PCI INITIALIZATION FUNCTIONS
+ */
+
+/*
+ *    pciioinit: called once during device driver
+ *      initializtion if this driver is configured into
+ *      the system.
+ */
+void
+pciio_init(void)
+{
+    cdl_p                   cp;
+
+#if DEBUG && ATTACH_DEBUG
+    printf("pciio_init\n");
+#endif
+    /* Allocate the registry.
+     * We might already have one.
+     * If we don't, go get one.
+     * MPness: someone might have
+     * set one up for us while we
+     * were not looking; use an atomic
+     * compare-and-swap to commit to
+     * using the new registry if and
+     * only if nobody else did first.
+     * If someone did get there first,
+     * toss the one we allocated back
+     * into the pool.
+     */
+    if (pciio_registry == NULL) {
+	cp = cdl_new(EDGE_LBL_PCI, "vendor", "device");
+	if (!compare_and_swap_ptr((void **) &pciio_registry, NULL, (void *) cp)) {
+	    cdl_del(cp);
+	}
+    }
+    ASSERT(pciio_registry != NULL);
+}
+
+/*
+ *    pciioattach: called for each vertex in the graph
+ *      that is a PCI provider.
+ */
+/*ARGSUSED */
+int
+pciio_attach(devfs_handle_t pciio)
+{
+#if DEBUG && ATTACH_DEBUG
+#if defined(SUPPORT_PRINTING_V_FORMAT)
+    printk("%v: pciio_attach\n", pciio);
+#else
+    printk("0x%x: pciio_attach\n", pciio);
+#endif
+#endif
+    return 0;
+}
+
+/*
+ * Associate a set of pciio_provider functions with a vertex.
+ */
+void
+pciio_provider_register(devfs_handle_t provider, pciio_provider_t *pciio_fns)
+{
+    hwgraph_info_add_LBL(provider, INFO_LBL_PFUNCS, (arbitrary_info_t) pciio_fns);
+}
+
+/*
+ * Disassociate a set of pciio_provider functions with a vertex.
+ */
+void
+pciio_provider_unregister(devfs_handle_t provider)
+{
+    arbitrary_info_t        ainfo;
+
+    hwgraph_info_remove_LBL(provider, INFO_LBL_PFUNCS, (long *) &ainfo);
+}
+
+/*
+ * Obtain a pointer to the pciio_provider functions for a specified Crosstalk
+ * provider.
+ */
+pciio_provider_t       *
+pciio_provider_fns_get(devfs_handle_t provider)
+{
+    arbitrary_info_t        ainfo = 0;
+
+    (void) hwgraph_info_get_LBL(provider, INFO_LBL_PFUNCS, &ainfo);
+    return (pciio_provider_t *) ainfo;
+}
+
+/*ARGSUSED4 */
+int
+pciio_driver_register(
+			 pciio_vendor_id_t vendor_id,
+			 pciio_device_id_t device_id,
+			 char *driver_prefix,
+			 unsigned flags)
+{
+    /* a driver's init routine might call
+     * pciio_driver_register before the
+     * system calls pciio_init; so we
+     * make the init call ourselves here.
+     */
+    if (pciio_registry == NULL)
+	pciio_init();
+
+    return cdl_add_driver(pciio_registry,
+			  vendor_id, device_id,
+			  driver_prefix, flags, NULL);
+}
+
+/*
+ * Remove an initialization function.
+ */
+void
+pciio_driver_unregister(
+			   char *driver_prefix)
+{
+    /* before a driver calls unregister,
+     * it must have called register; so
+     * we can assume we have a registry here.
+     */
+    ASSERT(pciio_registry != NULL);
+
+    cdl_del_driver(pciio_registry, driver_prefix, NULL);
+}
+
+/* 
+ * Set the slot status for a device supported by the 
+ * driver being registered.
+ */
+void
+pciio_driver_reg_callback(
+                           devfs_handle_t pconn_vhdl,
+			   int key1,
+			   int key2,
+                           int error)
+{
+}
+
+/* 
+ * Set the slot status for a device supported by the 
+ * driver being unregistered.
+ */
+void
+pciio_driver_unreg_callback(
+                           devfs_handle_t pconn_vhdl,
+			   int key1,
+			   int key2,
+                           int error)
+{
+}
+
+/*
+ * Call some function with each vertex that
+ * might be one of this driver's attach points.
+ */
+void
+pciio_iterate(char *driver_prefix,
+	      pciio_iter_f * func)
+{
+    /* a driver's init routine might call
+     * pciio_iterate before the
+     * system calls pciio_init; so we
+     * make the init call ourselves here.
+     */
+    if (pciio_registry == NULL)
+	pciio_init();
+
+    ASSERT(pciio_registry != NULL);
+
+    cdl_iterate(pciio_registry, driver_prefix, (cdl_iter_f *) func);
+}
+
+devfs_handle_t
+pciio_device_register(
+		devfs_handle_t connectpt,	/* vertex for /hw/.../pciio/%d */
+		devfs_handle_t master,	/* card's master ASIC (PCI provider) */
+		pciio_slot_t slot,	/* card's slot */
+		pciio_function_t func,	/* card's func */
+		pciio_vendor_id_t vendor_id,
+		pciio_device_id_t device_id)
+{
+    return pciio_device_info_register
+	(connectpt, pciio_device_info_new (NULL, master, slot, func,
+					   vendor_id, device_id));
+}
+
+void
+pciio_device_unregister(devfs_handle_t pconn)
+{
+    DEV_FUNC(pconn,device_unregister)(pconn);
+}
+
+pciio_info_t
+pciio_device_info_new(
+		pciio_info_t pciio_info,
+		devfs_handle_t master,
+		pciio_slot_t slot,
+		pciio_function_t func,
+		pciio_vendor_id_t vendor_id,
+		pciio_device_id_t device_id)
+{
+    if (!pciio_info)
+	GET_NEW(pciio_info);
+    ASSERT(pciio_info != NULL);
+
+    pciio_info->c_slot = slot;
+    pciio_info->c_func = func;
+    pciio_info->c_vendor = vendor_id;
+    pciio_info->c_device = device_id;
+    pciio_info->c_master = master;
+    pciio_info->c_mfast = hwgraph_fastinfo_get(master);
+    pciio_info->c_pops = pciio_provider_fns_get(master);
+    pciio_info->c_efunc = 0;
+    pciio_info->c_einfo = 0;
+
+    return pciio_info;
+}
+
+void
+pciio_device_info_free(pciio_info_t pciio_info)
+{
+    /* NOTE : pciio_info is a structure within the pcibr_info
+     *	      and not a pointer to memory allocated on the heap !!
+     */
+    BZERO((char *)pciio_info,sizeof(pciio_info));
+}
+
+devfs_handle_t
+pciio_device_info_register(
+		devfs_handle_t connectpt,		/* vertex at center of bus */
+		pciio_info_t pciio_info)	/* details about the connectpt */
+{
+    char		name[32];
+    devfs_handle_t	pconn;
+    int device_master_set(devfs_handle_t, devfs_handle_t);
+
+    pciio_slot_func_to_name(name,
+			    pciio_info->c_slot,
+			    pciio_info->c_func);
+
+    if (GRAPH_SUCCESS !=
+	hwgraph_path_add(connectpt, name, &pconn))
+	return pconn;
+
+    pciio_info->c_vertex = pconn;
+    pciio_info_set(pconn, pciio_info);
+#ifdef DEBUG_PCIIO
+    {
+	int pos;
+	char dname[256];
+	pos = devfs_generate_path(pconn, dname, 256);
+	printk("%s : pconn path= %s \n", __FUNCTION__, &dname[pos]);
+    }
+#endif /* DEBUG_PCIIO */
+
+    /*
+     * create link to our pci provider
+     */
+
+    device_master_set(pconn, pciio_info->c_master);
+
+#if USRPCI
+    /*
+     * Call into usrpci provider to let it initialize for
+     * the given slot.
+     */
+    if (pciio_info->c_slot != PCIIO_SLOT_NONE)
+	usrpci_device_register(pconn, pciio_info->c_master, pciio_info->c_slot);
+#endif
+
+    return pconn;
+}
+
+void
+pciio_device_info_unregister(devfs_handle_t connectpt,
+			     pciio_info_t pciio_info)
+{
+    char		name[32];
+    devfs_handle_t	pconn;
+
+    if (!pciio_info)
+	return;
+
+    pciio_slot_func_to_name(name,
+			    pciio_info->c_slot,
+			    pciio_info->c_func);
+
+    hwgraph_edge_remove(connectpt,name,&pconn);
+    pciio_info_set(pconn,0);
+
+    /* Remove the link to our pci provider */
+    hwgraph_edge_remove(pconn, EDGE_LBL_MASTER, NULL);
+
+
+    hwgraph_vertex_unref(pconn);
+    hwgraph_vertex_destroy(pconn);
+    
+}
+/* Add the pci card inventory information to the hwgraph
+ */
+static void
+pciio_device_inventory_add(devfs_handle_t pconn_vhdl)
+{
+    pciio_info_t	pciio_info = pciio_info_get(pconn_vhdl);
+
+    ASSERT(pciio_info);
+    ASSERT(pciio_info->c_vertex == pconn_vhdl);
+
+    /* Donot add inventory  for non-existent devices */
+    if ((pciio_info->c_vendor == PCIIO_VENDOR_ID_NONE)	||
+	(pciio_info->c_device == PCIIO_DEVICE_ID_NONE))
+	return;
+    device_inventory_add(pconn_vhdl,INV_IOBD,INV_PCIADAP,
+			 pciio_info->c_vendor,pciio_info->c_device,
+			 pciio_info->c_slot);
+}
+
+/*ARGSUSED */
+int
+pciio_device_attach(devfs_handle_t pconn,
+		    int          drv_flags)
+{
+    pciio_info_t            pciio_info;
+    pciio_vendor_id_t       vendor_id;
+    pciio_device_id_t       device_id;
+
+
+    pciio_device_inventory_add(pconn);
+    pciio_info = pciio_info_get(pconn);
+
+    vendor_id = pciio_info->c_vendor;
+    device_id = pciio_info->c_device;
+
+    /* we don't start attaching things until
+     * all the driver init routines (including
+     * pciio_init) have been called; so we
+     * can assume here that we have a registry.
+     */
+    ASSERT(pciio_registry != NULL);
+
+    return(cdl_add_connpt(pciio_registry, vendor_id, device_id, pconn, drv_flags));
+}
+
+int
+pciio_device_detach(devfs_handle_t pconn,
+		    int          drv_flags)
+{
+    pciio_info_t            pciio_info;
+    pciio_vendor_id_t       vendor_id;
+    pciio_device_id_t       device_id;
+
+    pciio_info = pciio_info_get(pconn);
+
+    vendor_id = pciio_info->c_vendor;
+    device_id = pciio_info->c_device;
+
+    /* we don't start attaching things until
+     * all the driver init routines (including
+     * pciio_init) have been called; so we
+     * can assume here that we have a registry.
+     */
+    ASSERT(pciio_registry != NULL);
+
+    return(cdl_del_connpt(pciio_registry, vendor_id, device_id,
+		          pconn, drv_flags));
+
+}
+
+/* SN2 */
+/*
+ * Allocate (if necessary) and initialize a PCI window mapping structure.
+ */
+pciio_win_map_t
+pciio_device_win_map_new(pciio_win_map_t win_map,
+			 size_t region_size,
+			 size_t page_size)
+{
+	ASSERT((page_size & (page_size - 1)) == 0);
+	ASSERT((region_size & (page_size - 1)) == 0);
+
+	if (win_map == NULL)
+		NEW(win_map);
+
+	/*
+	 * The map array tracks the free ``pages'' in the region.  The worst
+	 * case scenario is when every other page in the region is free --
+	 * e.i. maximum fragmentation.  This leads to (max pages + 1) / 2 + 1
+	 * map entries.  The first "+1" handles the divide by 2 rounding; the
+	 * second handles the need for an end marker sentinel.
+	 */
+	win_map->wm_map = rmallocmap((region_size / page_size + 1) / 2 + 1);
+	win_map->wm_page_size = page_size;
+	ASSERT(win_map->wm_map != NULL);
+
+	return win_map;
+}
+
+/*
+ * Free resources associated with a PCI window mapping structure.
+ */
+extern void
+pciio_device_win_map_free(pciio_win_map_t win_map)
+{
+	rmfreemap(win_map->wm_map);
+	bzero(win_map, sizeof *win_map);
+}
+
+/*
+ * Populate window map with specified free range.
+ */
+void
+pciio_device_win_populate(pciio_win_map_t win_map,
+                          iopaddr_t ioaddr,
+                          size_t size)
+{
+	ASSERT((size & (win_map->wm_page_size - 1)) == 0);
+	ASSERT((ioaddr & (win_map->wm_page_size - 1)) == 0);
+
+	rmfree(win_map->wm_map,
+	       size / win_map->wm_page_size,
+	       (unsigned long)ioaddr / win_map->wm_page_size);
+	       
+}
+/*
+ * Allocate space from the specified PCI window mapping resource.  On
+ * success record information about the allocation in the supplied window
+ * allocation cookie (if non-NULL) and return the address of the allocated
+ * window.  On failure return NULL.
+ *
+ * The "size" parameter is usually from a PCI device's Base Address Register
+ * (BAR) decoder.  As such, the allocation must be aligned to be a multiple of
+ * that.  The "align" parameter acts as a ``minimum alignment'' allocation
+ * constraint.  The alignment contraint reflects system or device addressing
+ * restrictions such as the inability to share higher level ``windows''
+ * between devices, etc.  The returned PCI address allocation will be a
+ * multiple of the alignment constraint both in alignment and size.  Thus, the
+ * returned PCI address block is aligned to the maximum of the requested size
+ * and alignment.
+ */
+iopaddr_t
+pciio_device_win_alloc(pciio_win_map_t win_map,
+		       pciio_win_alloc_t win_alloc,
+		       size_t start, size_t size, size_t align)
+{
+	unsigned long base;
+
+#ifdef PIC_LATER
+	ASSERT((size & (size - 1)) == 0);
+	ASSERT((align & (align - 1)) == 0);
+
+	/*
+	 * Convert size and alignment to pages.  If size is greated than the
+	 * requested alignment, we bump the alignment up to size; otherwise
+	 * convert the size into a multiple of the alignment request.
+	 */
+	size = (size + win_map->wm_page_size - 1) / win_map->wm_page_size;
+	align = align / win_map->wm_page_size;
+	if (size > align)
+		align = size;
+	else
+		size = (size + align - 1) & ~(align - 1);
+
+	/* XXXX */
+	base = rmalloc_align(win_map->wm_map, size, align, VM_NOSLEEP);
+	if (base == RMALLOC_FAIL)
+		return((iopaddr_t)NULL);
+#else
+    int                 index_page, index_page_align;
+    int                 align_pages, size_pages;
+    int                 alloc_pages, free_pages;
+    int                 addr_align;
+
+    /* Convert PCI bus alignment from bytes to pages */
+    align_pages = align / win_map->wm_page_size;
+
+    /* Convert PCI request from bytes to pages */
+    size_pages = (size / win_map->wm_page_size) +
+                  ((size % win_map->wm_page_size) ? 1 : 0);
+
+    /* Align address with the larger of the size or the requested slot align */
+    if (size_pages > align_pages)
+        align_pages = size_pages;
+  
+    /*
+     * Avoid wasting space by aligning - 1; this will prevent crossing
+     * another alignment boundary.
+     */
+    alloc_pages = size_pages + (align_pages - 1);
+
+    /* Allocate PCI bus space in pages */
+    index_page = (int) rmalloc(win_map->wm_map,
+                               (size_t) alloc_pages);
+
+    /* Error if no PCI bus address space available */
+    if (!index_page)
+        return 0;
+
+    /* PCI bus address index starts at 0 */
+    index_page--;
+
+    /* Align the page offset as requested */
+    index_page_align = (index_page + (align_pages - 1)) -
+                       ((index_page + (align_pages - 1)) % align_pages);
+
+    free_pages = (align_pages - 1) - (index_page_align - index_page);
+
+    /* Free unused PCI bus pages adjusting the index to start at 1 */
+    rmfree(win_map->wm_map, 
+           free_pages,
+           (index_page_align + 1) + size_pages);
+
+    /* Return aligned PCI bus space in bytes */ 
+    addr_align = (index_page_align * win_map->wm_page_size); 
+    base = index_page;
+    size = alloc_pages - free_pages;
+#endif	/* PIC_LATER */
+
+	/*
+	 * If a window allocation cookie has been supplied, use it to keep
+	 * track of all the allocated space assigned to this window.
+	 */
+	if (win_alloc) {
+		win_alloc->wa_map = win_map;
+		win_alloc->wa_base = base;
+		win_alloc->wa_pages = size;
+	}
+
+	return base * win_map->wm_page_size;
+}
+
+/*
+ * Free the specified window allocation back into the PCI window mapping
+ * resource.  As noted above, we keep page addresses offset by 1 ...
+ */
+void
+pciio_device_win_free(pciio_win_alloc_t win_alloc)
+{
+	if (win_alloc->wa_pages)
+		rmfree(win_alloc->wa_map->wm_map,
+		       win_alloc->wa_pages,
+		       win_alloc->wa_base);
+}
+
+/*
+ * pciio_error_register:
+ * arrange for a function to be called with
+ * a specified first parameter plus other
+ * information when an error is encountered
+ * and traced to the pci slot corresponding
+ * to the connection point pconn.
+ *
+ * may also be called with a null function
+ * pointer to "unregister" the error handler.
+ *
+ * NOTE: subsequent calls silently overwrite
+ * previous data for this vertex. We assume that
+ * cooperating drivers, well, cooperate ...
+ */
+void
+pciio_error_register(devfs_handle_t pconn,
+		     error_handler_f *efunc,
+		     error_handler_arg_t einfo)
+{
+    pciio_info_t            pciio_info;
+
+    pciio_info = pciio_info_get(pconn);
+    ASSERT(pciio_info != NULL);
+    pciio_info->c_efunc = efunc;
+    pciio_info->c_einfo = einfo;
+}
+
+/*
+ * Check if any device has been found in this slot, and return
+ * true or false
+ * vhdl is the vertex for the slot
+ */
+int
+pciio_slot_inuse(devfs_handle_t pconn_vhdl)
+{
+    pciio_info_t            pciio_info = pciio_info_get(pconn_vhdl);
+
+    ASSERT(pciio_info);
+    ASSERT(pciio_info->c_vertex == pconn_vhdl);
+    if (pciio_info->c_vendor) {
+	/*
+	 * Non-zero value for vendor indicate
+	 * a board being found in this slot.
+	 */
+	return 1;
+    }
+    return 0;
+}
+
+int
+pciio_dma_enabled(devfs_handle_t pconn_vhdl)
+{
+	return DEV_FUNC(pconn_vhdl, dma_enabled)(pconn_vhdl);
+}
+
+int
+pciio_info_type1_get(pciio_info_t pci_info)
+{
+	return(0);
+}
+
+
+/*
+ * These are complementary Linux interfaces that takes in a pci_dev * as the 
+ * first arguement instead of devfs_handle_t.
+ */
+iopaddr_t               snia_pciio_dmatrans_addr(struct pci_dev *, device_desc_t, paddr_t, size_t, unsigned);
+pciio_dmamap_t          snia_pciio_dmamap_alloc(struct pci_dev *, device_desc_t, size_t, unsigned);
+void                    snia_pciio_dmamap_free(pciio_dmamap_t);
+iopaddr_t               snia_pciio_dmamap_addr(pciio_dmamap_t, paddr_t, size_t);
+void                    snia_pciio_dmamap_done(pciio_dmamap_t);
+pciio_endian_t          snia_pciio_endian_set(struct pci_dev *pci_dev, pciio_endian_t device_end,
+					      pciio_endian_t desired_end);
+
+#include <linux/module.h>
+EXPORT_SYMBOL(snia_pciio_dmatrans_addr);
+EXPORT_SYMBOL(snia_pciio_dmamap_alloc);
+EXPORT_SYMBOL(snia_pciio_dmamap_free);
+EXPORT_SYMBOL(snia_pciio_dmamap_addr);
+EXPORT_SYMBOL(snia_pciio_dmamap_done);
+EXPORT_SYMBOL(snia_pciio_endian_set);
+
+int
+snia_pcibr_rrb_alloc(struct pci_dev *pci_dev,
+	int *count_vchan0,
+	int *count_vchan1)
+{
+	devfs_handle_t dev = PCIDEV_VERTEX(pci_dev);
+
+	return pcibr_rrb_alloc(dev, count_vchan0, count_vchan1);
+}
+EXPORT_SYMBOL(snia_pcibr_rrb_alloc);
+
+pciio_endian_t
+snia_pciio_endian_set(struct pci_dev *pci_dev,
+	pciio_endian_t device_end,
+	pciio_endian_t desired_end)
+{
+	devfs_handle_t dev = PCIDEV_VERTEX(pci_dev);
+	
+	return DEV_FUNC(dev, endian_set)
+		(dev, device_end, desired_end);
+}
+
+iopaddr_t
+snia_pciio_dmatrans_addr(struct pci_dev *pci_dev, /* translate for this device */
+                    device_desc_t dev_desc,     /* device descriptor */
+                    paddr_t paddr,      /* system physical address */
+                    size_t byte_count,  /* length */
+                    unsigned flags)
+{                                       /* defined in dma.h */
+
+    devfs_handle_t dev = PCIDEV_VERTEX(pci_dev);
+
+    /*
+     * If the device is not a PIC, we always want the PCIIO_BYTE_STREAM to be 
+     * set.  Otherwise, it must not be set.  This applies to SN1 and SN2.
+     */
+    return DEV_FUNC(dev, dmatrans_addr)
+        (dev, dev_desc, paddr, byte_count, (IS_PIC_DEVICE(pci_dev)) ? (flags & ~PCIIO_BYTE_STREAM) : flags | PCIIO_BYTE_STREAM);
+}
+
+pciio_dmamap_t
+snia_pciio_dmamap_alloc(struct pci_dev *pci_dev,  /* set up mappings for this device */
+                   device_desc_t dev_desc,      /* device descriptor */
+                   size_t byte_count_max,       /* max size of a mapping */
+                   unsigned flags)
+{                                       /* defined in dma.h */
+
+    devfs_handle_t dev = PCIDEV_VERTEX(pci_dev);
+
+    /*
+     * If the device is not a PIC, we always want the PCIIO_BYTE_STREAM to be
+     * set.  Otherwise, it must not be set.  This applies to SN1 and SN2.
+     */
+    return (pciio_dmamap_t) DEV_FUNC(dev, dmamap_alloc)
+        (dev, dev_desc, byte_count_max, (IS_PIC_DEVICE(pci_dev)) ? (flags & ~PCIIO_BYTE_STREAM) : flags | PCIIO_BYTE_STREAM);
+}
+
+void
+snia_pciio_dmamap_free(pciio_dmamap_t pciio_dmamap)
+{
+    DMAMAP_FUNC(pciio_dmamap, dmamap_free)
+        (CAST_DMAMAP(pciio_dmamap));
+}
+
+iopaddr_t
+snia_pciio_dmamap_addr(pciio_dmamap_t pciio_dmamap,  /* use these mapping resources */
+                  paddr_t paddr,        /* map for this address */
+                  size_t byte_count)
+{                                       /* map this many bytes */
+    return DMAMAP_FUNC(pciio_dmamap, dmamap_addr)
+        (CAST_DMAMAP(pciio_dmamap), paddr, byte_count);
+}
+
+void
+snia_pciio_dmamap_done(pciio_dmamap_t pciio_dmamap)
+{
+    DMAMAP_FUNC(pciio_dmamap, dmamap_done)
+        (CAST_DMAMAP(pciio_dmamap));
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/pic.c linux-2.4.21-pre6/arch/ia64/sn/io/sn2/pic.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/pic.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn2/pic.c	2003-03-26 23:49:39.000000000 +0000
@@ -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.
+ *
+ * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/sn_cpuid.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/arch.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/xtalk/xwidget.h>
+#include <asm/sn/pci/bridge.h>
+#include <asm/sn/pci/pciio.h>
+#include <asm/sn/pci/pcibr.h>
+#include <asm/sn/pci/pcibr_private.h>
+#include <asm/sn/pci/pci_defs.h>
+#include <asm/sn/prio.h>
+#include <asm/sn/xtalk/xbow.h>
+#include <asm/sn/ioc3.h>
+#include <asm/sn/eeprom.h>
+#include <asm/sn/io.h>
+#include <asm/sn/sn_private.h>
+
+
+#define PCI_BUS_NO_1 1
+
+int pic_devflag = D_MP;
+
+extern int pcibr_attach2(devfs_handle_t, bridge_t *, devfs_handle_t, int, pcibr_soft_t *);
+extern void pcibr_driver_reg_callback(devfs_handle_t, int, int, int);
+extern void pcibr_driver_unreg_callback(devfs_handle_t, int, int, int);
+
+
+void
+pic_init(void)
+{
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INIT, NULL, "pic_init()\n"));	
+
+	xwidget_driver_register(PIC_WIDGET_PART_NUM_BUS0,
+			    PIC_WIDGET_MFGR_NUM,
+			    "pic_",
+			    0);
+}
+
+int
+pic_attach(devfs_handle_t conn_v)
+{
+	int		rc;
+	bridge_t	*bridge0, *bridge1 = (bridge_t *)0;
+	devfs_handle_t	pcibr_vhdl0, pcibr_vhdl1 = (devfs_handle_t)0;
+	pcibr_soft_t	bus0_soft, bus1_soft = (pcibr_soft_t)0;
+
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, conn_v, "pic_attach()\n"));
+
+	bridge0 = (bridge_t *) xtalk_piotrans_addr(conn_v, NULL,
+	                        0, sizeof(bridge_t), 0);
+#ifdef	PCI_BUS_NO_1
+	bridge1 = (bridge_t *)((char *)bridge0 + PIC_BUS1_OFFSET);
+#endif
+
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, conn_v,
+		    "pic_attach: bridge0=0x%x, bridge1=0x%x\n", 
+		    bridge0, bridge1));
+
+	/*
+	 * Create the vertex for the PCI buses, which we
+	 * will also use to hold the pcibr_soft and
+	 * which will be the "master" vertex for all the
+	 * pciio connection points we will hang off it.
+	 * This needs to happen before we call nic_bridge_vertex_info
+	 * as we are some of the *_vmc functions need access to the edges.
+	 *
+	 * Opening this vertex will provide access to
+	 * the Bridge registers themselves.
+	 */
+	/* FIXME: what should the hwgraph path look like ? */
+	rc = hwgraph_path_add(conn_v, EDGE_LBL_PCIX_0, &pcibr_vhdl0);
+	ASSERT(rc == GRAPH_SUCCESS);
+#ifdef	PCI_BUS_NO_1
+	rc = hwgraph_path_add(conn_v, EDGE_LBL_PCIX_1, &pcibr_vhdl1);
+	ASSERT(rc == GRAPH_SUCCESS);
+#endif
+
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, conn_v,
+		    "pic_attach: pcibr_vhdl0=%v, pcibr_vhdl1=%v\n",
+		    pcibr_vhdl0, pcibr_vhdl1));
+
+	/* register pci provider array */
+	pciio_provider_register(pcibr_vhdl0, &pci_pic_provider);
+#ifdef	PCI_BUS_NO_1
+	pciio_provider_register(pcibr_vhdl1, &pci_pic_provider);
+#endif
+
+	pciio_provider_startup(pcibr_vhdl0);
+#ifdef	PCI_BUS_NO_1
+	pciio_provider_startup(pcibr_vhdl1);
+#endif
+
+	pcibr_attach2(conn_v, bridge0, pcibr_vhdl0, 0, &bus0_soft);
+#ifdef	PCI_BUS_NO_1
+	pcibr_attach2(conn_v, bridge1, pcibr_vhdl1, 1, &bus1_soft);
+#endif
+
+	/* save a pointer to the PIC's other bus's soft struct */
+#ifdef	PCI_BUS_NO_1
+        bus0_soft->bs_peers_soft = bus1_soft;
+        bus1_soft->bs_peers_soft = bus0_soft;
+#else
+        bus0_soft->bs_peers_soft = (pcibr_soft_t)0;
+#endif
+
+	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, conn_v,
+		    "pic_attach: bus0_soft=0x%x, bus1_soft=0x%x\n",
+		    bus0_soft, bus1_soft));
+
+	return 0;
+}
+
+/*
+ * pci provider functions
+ *
+ * mostly in pcibr.c but if any are needed here then
+ * this might be a way to get them here.
+ */
+pciio_provider_t        pci_pic_provider =
+{
+    (pciio_piomap_alloc_f *) pcibr_piomap_alloc,
+    (pciio_piomap_free_f *) pcibr_piomap_free,
+    (pciio_piomap_addr_f *) pcibr_piomap_addr,
+    (pciio_piomap_done_f *) pcibr_piomap_done,
+    (pciio_piotrans_addr_f *) pcibr_piotrans_addr,
+    (pciio_piospace_alloc_f *) pcibr_piospace_alloc,
+    (pciio_piospace_free_f *) pcibr_piospace_free,
+
+    (pciio_dmamap_alloc_f *) pcibr_dmamap_alloc,
+    (pciio_dmamap_free_f *) pcibr_dmamap_free,
+    (pciio_dmamap_addr_f *) pcibr_dmamap_addr,
+    (pciio_dmamap_list_f *) pcibr_dmamap_list,
+    (pciio_dmamap_done_f *) pcibr_dmamap_done,
+    (pciio_dmatrans_addr_f *) pcibr_dmatrans_addr,
+    (pciio_dmatrans_list_f *) pcibr_dmatrans_list,
+    (pciio_dmamap_drain_f *) pcibr_dmamap_drain,
+    (pciio_dmaaddr_drain_f *) pcibr_dmaaddr_drain,
+    (pciio_dmalist_drain_f *) pcibr_dmalist_drain,
+
+    (pciio_intr_alloc_f *) pcibr_intr_alloc,
+    (pciio_intr_free_f *) pcibr_intr_free,
+    (pciio_intr_connect_f *) pcibr_intr_connect,
+    (pciio_intr_disconnect_f *) pcibr_intr_disconnect,
+    (pciio_intr_cpu_get_f *) pcibr_intr_cpu_get,
+
+    (pciio_provider_startup_f *) pcibr_provider_startup,
+    (pciio_provider_shutdown_f *) pcibr_provider_shutdown,
+    (pciio_reset_f *) pcibr_reset,
+    (pciio_write_gather_flush_f *) pcibr_write_gather_flush,
+    (pciio_endian_set_f *) pcibr_endian_set,
+    (pciio_priority_set_f *) pcibr_priority_set,
+    (pciio_config_get_f *) pcibr_config_get,
+    (pciio_config_set_f *) pcibr_config_set,
+    (pciio_error_devenable_f *) 0,
+    (pciio_error_extract_f *) 0,
+    (pciio_driver_reg_callback_f *) pcibr_driver_reg_callback,
+    (pciio_driver_unreg_callback_f *) pcibr_driver_unreg_callback,
+    (pciio_device_unregister_f 	*) pcibr_device_unregister,
+    (pciio_dma_enabled_f		*) pcibr_dma_enabled,
+};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/sgi_io_init.c linux-2.4.21-pre6/arch/ia64/sn/io/sn2/sgi_io_init.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/sgi_io_init.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn2/sgi_io_init.c	2003-03-26 23:48:57.000000000 +0000
@@ -0,0 +1,230 @@
+/* $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) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#include <linux/types.h>
+#include <linux/config.h>
+#include <linux/slab.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/io.h>
+#include <asm/sn/sn_cpuid.h>
+#include <asm/sn/klconfig.h>
+#include <asm/sn/sn_private.h>
+#include <asm/sn/pci/pciba.h>
+#include <linux/smp.h>
+
+extern void mlreset(void);
+extern int init_hcl(void);
+extern void klgraph_hack_init(void);
+extern void hubspc_init(void);
+extern void pciio_init(void);
+extern void pcibr_init(void);
+extern void xtalk_init(void);
+extern void xbow_init(void);
+extern void xbmon_init(void);
+extern void pciiox_init(void);
+extern void pic_init(void);
+extern void usrpci_init(void);
+extern void ioc3_init(void);
+extern void initialize_io(void);
+extern void klhwg_add_all_modules(devfs_handle_t);
+extern void klhwg_add_all_nodes(devfs_handle_t);
+
+void sn_mp_setup(void);
+extern devfs_handle_t hwgraph_root;
+extern void io_module_init(void);
+extern void pci_bus_cvlink_init(void);
+extern void temp_hack(void);
+
+extern int pci_bus_to_hcl_cvlink(void);
+
+/* #define DEBUG_IO_INIT 1 */
+#ifdef DEBUG_IO_INIT
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif /* DEBUG_IO_INIT */
+
+/*
+ * per_hub_init
+ *
+ * 	This code is executed once for each Hub chip.
+ */
+static void
+per_hub_init(cnodeid_t cnode)
+{
+	nasid_t		nasid;
+	nodepda_t	*npdap;
+	ii_icmr_u_t	ii_icmr;
+	ii_ibcr_u_t	ii_ibcr;
+
+	nasid = COMPACT_TO_NASID_NODEID(cnode);
+
+	ASSERT(nasid != INVALID_NASID);
+	ASSERT(NASID_TO_COMPACT_NODEID(nasid) == cnode);
+
+	npdap = NODEPDA(cnode);
+
+#ifdef BRINGUP2
+#if 0
+	while ((REMOTE_HUB_L(nasid, IIO_IFDR)) != 0x2d2d)
+		REMOTE_HUB_S(nasid, IIO_IFDR, 0xadad);
+#endif
+	printk("IIO_IFDR = 0x%x\n", REMOTE_HUB_L(nasid, IIO_IFDR));
+	REMOTE_HUB_S(nasid, IIO_IWEIM, 0x8000);
+#endif
+	/*
+	 * Set the total number of CRBs that can be used.
+	 */
+	ii_icmr.ii_icmr_regval= 0x0;
+	ii_icmr.ii_icmr_fld_s.i_c_cnt = 0xF;
+	REMOTE_HUB_S(nasid, IIO_ICMR, ii_icmr.ii_icmr_regval);
+
+	/*
+	 * Set the number of CRBs that both of the BTEs combined
+	 * can use minus 1.
+	 */
+	ii_ibcr.ii_ibcr_regval= 0x0;
+	ii_ibcr.ii_ibcr_fld_s.i_count = 0x8;
+	REMOTE_HUB_S(nasid, IIO_IBCR, ii_ibcr.ii_ibcr_regval);
+
+	/*
+	 * Set CRB timeout to be 10ms.
+	 */
+#ifdef BRINGUP2
+	REMOTE_HUB_S(nasid, IIO_ICTP, 0xffffff );
+	REMOTE_HUB_S(nasid, IIO_ICTO, 0xff);
+	REMOTE_HUB_S(nasid, IIO_IDBSS, 0x504);
+	REMOTE_HUB_S(nasid, SH_DEBUG_SELECT, 0x0002DF6D74CF2C70);
+#endif
+
+	/* Initialize error interrupts for this hub. */
+	hub_error_init(cnode);
+}
+
+/*
+ * This routine is responsible for the setup of all the IRIX hwgraph style
+ * stuff that's been pulled into linux.  It's called by sn_pci_find_bios which
+ * is called just before the generic Linux PCI layer does its probing (by 
+ * platform_pci_fixup aka sn_pci_fixup).
+ *
+ * It is very IMPORTANT that this call is only made by the Master CPU!
+ *
+ */
+
+void
+sgi_master_io_infr_init(void)
+{
+	int cnode;
+
+	/*
+	 * Do any early init stuff .. einit_tbl[] etc.
+	 */
+	init_hcl(); /* Sets up the hwgraph compatibility layer with devfs */
+
+	/*
+	 * initialize the Linux PCI to xwidget vertexes ..
+	 */
+	pci_bus_cvlink_init();
+
+#ifdef BRINGUP
+	/*
+	 * Hack to provide statically initialzed klgraph entries.
+	 */
+	DBG("--> sgi_master_io_infr_init: calling klgraph_hack_init()\n");
+	klgraph_hack_init();
+#endif /* BRINGUP */
+
+	/*
+	 * This is the Master CPU.  Emulate mlsetup and main.c in Irix.
+	 */
+	mlreset();
+
+	/*
+	 * allowboot() is called by kern/os/main.c in main()
+	 * Emulate allowboot() ...
+	 *   per_cpu_init() - only need per_hub_init()
+	 *   cpu_io_setup() - Nothing to do.
+	 * 
+	 */
+	sn_mp_setup();
+
+	for (cnode = 0; cnode < numnodes; cnode++) {
+		per_hub_init(cnode);
+	}
+
+	/* We can do headless hub cnodes here .. */
+
+	/*
+	 * io_init[] stuff.
+	 *
+	 * Get SGI IO Infrastructure drivers to init and register with 
+	 * each other etc.
+	 */
+
+	hubspc_init();
+	pciio_init();
+	pcibr_init();
+	pic_init();
+	xtalk_init();
+	xbow_init();
+	xbmon_init();
+	pciiox_init();
+	usrpci_init();
+	ioc3_init();
+
+	/*
+	 *
+	 * Our IO Infrastructure drivers are in place .. 
+	 * Initialize the whole IO Infrastructure .. xwidget/device probes.
+	 *
+	 */
+	initialize_io();
+	pci_bus_to_hcl_cvlink();
+
+#ifdef CONFIG_PCIBA
+	DBG("--> sgi_master_io_infr_init: calling pciba_init()\n");
+#ifndef BRINGUP2
+ 	pciba_init();
+#endif
+#endif
+}
+
+/*
+ * One-time setup for MP SN.
+ * Allocate per-node data, slurp prom klconfig information and
+ * convert it to hwgraph information.
+ */
+void
+sn_mp_setup(void)
+{
+	cpuid_t		cpu;
+
+	for (cpu = 0; cpu < smp_num_cpus; cpu++) {
+		/* Skip holes in CPU space */
+		if (cpu_enabled(cpu)) {
+			init_platform_pda(cpu);
+		}
+	}
+
+	/*
+	 * Initialize platform-dependent vertices in the hwgraph:
+	 *	module
+	 *	node
+	 *	cpu
+	 *	memory
+	 *	slot
+	 *	hub
+	 *	router
+	 *	xbow
+	 */
+
+	io_module_init(); /* Use to be called module_init() .. */
+	klhwg_add_all_modules(hwgraph_root);
+	klhwg_add_all_nodes(hwgraph_root);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/shub.c linux-2.4.21-pre6/arch/ia64/sn/io/sn2/shub.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/shub.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn2/shub.c	2003-03-26 23:48:58.000000000 +0000
@@ -0,0 +1,233 @@
+/* $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) 1992-1997, 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ */
+
+#ident  "$Revision: 1.167 $"
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <asm/smp.h>
+#include <asm/irq.h>
+#include <asm/hw_irq.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/io.h>
+#include <asm/sn/sn_private.h>
+#include <asm/sn/klconfig.h>
+#include <asm/sn/sn_cpuid.h>
+#include <asm/sn/pci/pciio.h>
+#include <asm/sn/pci/pcibr.h>
+#include <asm/sn/xtalk/xtalk.h>
+#include <asm/sn/pci/pcibr_private.h>
+#include <asm/sn/intr.h>
+#include <asm/sn/sn2/shub_mmr_t.h>
+#include <asm/sal.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/sndrv.h>
+
+/*
+ * Shub WAR for Xbridge Little Endian problem:
+ *	Xbridge has to run in BIG ENDIAN even with Shub.
+ */
+
+
+/*
+ * io_sh_swapper: Turn on Shub byte swapping.
+ *	All data destined to and from Shub to XIO are byte-swapped.
+ */
+void
+io_sh_swapper(nasid_t nasid, int onoff)
+{
+    ii_iwc_u_t      ii_iwc;
+
+    ii_iwc.ii_iwc_regval = REMOTE_HUB_L(nasid, IIO_IWC);
+
+    ii_iwc.ii_iwc_fld_s.i_dma_byte_swap = onoff;
+    REMOTE_HUB_S(nasid, IIO_IWC, ii_iwc.ii_iwc_regval);
+    ii_iwc.ii_iwc_regval = REMOTE_HUB_L(nasid, IIO_IWC);
+
+}
+
+/*
+ * io_get_sh_swapper: Return current Swap mode.
+ *	1 = Swap on, 0 = Swap off.
+ */
+int
+io_get_sh_swapper(nasid_t nasid)
+{
+    ii_iwc_u_t      ii_iwc;
+
+    ii_iwc.ii_iwc_regval = REMOTE_HUB_L(nasid, IIO_IWC);
+    return(ii_iwc.ii_iwc_fld_s.i_dma_byte_swap);
+
+}
+
+#define SHUB_NUM_ECF_REGISTERS 8
+
+static uint32_t	shub_perf_counts[SHUB_NUM_ECF_REGISTERS];
+
+static shubreg_t shub_perf_counts_regs[SHUB_NUM_ECF_REGISTERS] = {
+	SH_PERFORMANCE_COUNTER0,
+	SH_PERFORMANCE_COUNTER1,
+	SH_PERFORMANCE_COUNTER2,
+	SH_PERFORMANCE_COUNTER3,
+	SH_PERFORMANCE_COUNTER4,
+	SH_PERFORMANCE_COUNTER5,
+	SH_PERFORMANCE_COUNTER6,
+	SH_PERFORMANCE_COUNTER7
+};
+
+static inline void
+shub_mmr_write(cnodeid_t cnode, shubreg_t reg, uint64_t val)
+{
+	int		   nasid = cnodeid_to_nasid(cnode);
+	volatile uint64_t *addr = (uint64_t *)(GLOBAL_MMR_ADDR(nasid, reg));
+
+	*addr = val;
+	__ia64_mf_a();
+}
+
+static inline void
+shub_mmr_write32(cnodeid_t cnode, shubreg_t reg, uint32_t val)
+{
+	int		   nasid = cnodeid_to_nasid(cnode);
+	volatile uint32_t *addr = (uint32_t *)(GLOBAL_MMR_ADDR(nasid, reg));
+
+	*addr = val;
+	__ia64_mf_a();
+}
+
+static inline uint64_t
+shub_mmr_read(cnodeid_t cnode, shubreg_t reg)
+{
+	int		  nasid = cnodeid_to_nasid(cnode);
+	volatile uint64_t val;
+
+	val = *(uint64_t *)(GLOBAL_MMR_ADDR(nasid, reg));
+	__ia64_mf_a();
+
+	return val;
+}
+
+static inline uint32_t
+shub_mmr_read32(cnodeid_t cnode, shubreg_t reg)
+{
+	int		  nasid = cnodeid_to_nasid(cnode);
+	volatile uint32_t val;
+
+	val = *(uint32_t *)(GLOBAL_MMR_ADDR(nasid, reg));
+	__ia64_mf_a();
+
+	return val;
+}
+
+static int
+reset_shub_stats(cnodeid_t cnode)
+{
+	int i;
+
+	for (i=0; i < SHUB_NUM_ECF_REGISTERS; i++) {
+		shub_perf_counts[i] = 0;
+		shub_mmr_write32(cnode, shub_perf_counts_regs[i], 0);
+	}
+	return 0;
+}
+
+static int
+configure_shub_stats(cnodeid_t cnode, unsigned long arg)
+{
+	uint64_t	*p = (uint64_t *)arg;
+	uint64_t	i;
+	uint64_t	regcnt;
+	uint64_t	regval[2];
+
+	if (copy_from_user((void *)&regcnt, p, sizeof(regcnt)))
+	    return -EFAULT;
+
+	for (p++, i=0; i < regcnt; i++, p += 2) {
+		if (copy_from_user((void *)regval, (void *)p, sizeof(regval)))
+		    return -EFAULT;
+		if (regval[0] & 0x7) {
+		    printk("Error: configure_shub_stats: unaligned address 0x%016lx\n", regval[0]);
+		    return -EINVAL;
+		}
+		shub_mmr_write(cnode, (shubreg_t)regval[0], regval[1]);
+	}
+	return 0;
+}
+
+static int
+capture_shub_stats(cnodeid_t cnode, uint32_t *counts)
+{
+	int 		i;
+
+	for (i=0; i < SHUB_NUM_ECF_REGISTERS; i++) {
+		counts[i] = shub_mmr_read32(cnode, shub_perf_counts_regs[i]);
+	}
+	return 0;
+}
+
+static int
+shubstats_ioctl(struct inode *inode, struct file *file,
+        unsigned int cmd, unsigned long arg)
+{
+        cnodeid_t       cnode;
+        uint64_t        longarg;
+        devfs_handle_t  d;
+	int		nasid;
+
+        if ((d = devfs_get_handle_from_inode(inode)) == NULL)
+                return -ENODEV;
+        cnode = (cnodeid_t)hwgraph_fastinfo_get(d);
+
+        switch (cmd) {
+	case SNDRV_SHUB_CONFIGURE:
+		return configure_shub_stats(cnode, arg);
+		break;
+
+	case SNDRV_SHUB_RESETSTATS:
+		reset_shub_stats(cnode);
+		break;
+
+	case SNDRV_SHUB_INFOSIZE:
+		longarg = sizeof(shub_perf_counts);
+		if (copy_to_user((void *)arg, &longarg, sizeof(longarg))) {
+		    return -EFAULT;
+		}
+		break;
+
+	case SNDRV_SHUB_GETSTATS:
+		capture_shub_stats(cnode, shub_perf_counts);
+		if (copy_to_user((void *)arg, shub_perf_counts,
+				       	sizeof(shub_perf_counts))) {
+		    return -EFAULT;
+		}
+		break;
+
+	case SNDRV_SHUB_GETNASID:
+		nasid = cnodeid_to_nasid(cnode);
+		if (copy_to_user((void *)arg, &nasid,
+				       	sizeof(nasid))) {
+		    return -EFAULT;
+		}
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+struct file_operations shub_mon_fops = {
+	        ioctl:          shubstats_ioctl,
+};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/shub_intr.c linux-2.4.21-pre6/arch/ia64/sn/io/sn2/shub_intr.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/shub_intr.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn2/shub_intr.c	2003-03-26 23:48:58.000000000 +0000
@@ -25,21 +25,13 @@
 #include <asm/sn/intr.h>
 #include <asm/sn/xtalk/xtalkaddrs.h>
 #include <asm/sn/klconfig.h>
+#include <asm/sn/sn2/shub_mmr.h>
 #include <asm/sn/sn_cpuid.h>
 
-extern void hub_device_desc_update(device_desc_t, ilvl_t, cpuid_t);
-
 /* ARGSUSED */
 void
 hub_intr_init(devfs_handle_t hubv)
 {
-	extern void sn_cpei_handler(int, void *, struct pt_regs *);
-	extern void sn_init_cpei_timer(void);
-
-	if (request_irq(SGI_SHUB_ERROR_VECTOR, sn_cpei_handler, 0, "SN hub error", NULL) ) {
-		printk("hub_intr_init: Couldn't register SGI_SHUB_ERROR_VECTOR = %x\n",SGI_SHUB_ERROR_VECTOR);
-	}
-	sn_init_cpei_timer();
 }
 
 xwidgetnum_t
@@ -82,11 +74,9 @@
 	cnode = cpuid_to_cnodeid(cpu);
 
 	if (slice) {
-		xtalk_addr = SH_II_INT1 | GLOBAL_MMR_SPACE |
-			((unsigned long)nasid << 36) | (1UL << 47);
+		xtalk_addr = SH_II_INT1 | ((unsigned long)nasid << 36) | (1UL << 47);
 	} else {
-		xtalk_addr = SH_II_INT0 | GLOBAL_MMR_SPACE |
-			((unsigned long)nasid << 36) | (1UL << 47);
+		xtalk_addr = SH_II_INT0 | ((unsigned long)nasid << 36) | (1UL << 47);
 	}
 
 	intr_hdl = snia_kmem_alloc_node(sizeof(struct hub_intr_s), KM_NOSLEEP, cnode);
@@ -107,7 +97,6 @@
 	intr_hdl->i_bit = vector;
 	intr_hdl->i_flags |= HUB_INTR_IS_ALLOCED;
 
-	hub_device_desc_update(dev_desc, intr_swlevel, cpu);
 	return(intr_hdl);
 }
 
@@ -150,6 +139,8 @@
 
 int
 hub_intr_connect(hub_intr_t intr_hdl,
+		intr_func_t intr_func,          /* xtalk intr handler */
+		void *intr_arg,                 /* arg to intr handler */
 		xtalk_intr_setfunc_t setfunc,
 		void *setfunc_arg)
 {
@@ -160,7 +151,6 @@
 	ASSERT(intr_hdl->i_flags & HUB_INTR_IS_ALLOCED);
 
 	rv = intr_connect_level(cpu, vector, intr_hdl->i_swlevel, NULL);
-
 	if (rv < 0) {
 		return rv;
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/shuberror.c linux-2.4.21-pre6/arch/ia64/sn/io/sn2/shuberror.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/shuberror.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn2/shuberror.c	2003-03-26 23:49:39.000000000 +0000
@@ -10,6 +10,8 @@
 
 #include <linux/types.h>
 #include <linux/slab.h>
+#include <linux/irq.h>
+#include <asm/irq.h>
 #include <asm/smp.h>
 #include <asm/sn/sgi.h>
 #include <asm/sn/io.h>
@@ -34,12 +36,18 @@
 extern void hubii_eint_handler (int irq, void *arg, struct pt_regs *ep);
 int hubiio_crb_error_handler(devfs_handle_t hub_v, hubinfo_t hinfo);
 int hubiio_prb_error_handler(devfs_handle_t hub_v, hubinfo_t hinfo);
-extern void bte_crb_error_handler(devfs_handle_t hub_v, int btenum, int crbnum, ioerror_t *ioe);
+extern void bte_crb_error_handler(devfs_handle_t hub_v, int btenum, int crbnum, ioerror_t *ioe, int bteop);
 
 extern int maxcpus;
 
 #define HUB_ERROR_PERIOD        (120 * HZ)      /* 2 minutes */
 
+#ifdef BUS_INT_WAR
+void sn_add_polled_interrupt(int irq, int interval);
+void sn_delete_polled_interrupt(int irq);
+extern int bus_int_war_ide_irq;
+#endif
+
 
 void
 hub_error_clear(nasid_t nasid)
@@ -118,9 +126,7 @@
     hubinfo_t		hinfo; 
     cpuid_t		intr_cpu;
     devfs_handle_t 	hub_v;
-    ii_ilcsr_u_t	ilcsr;
     int bit_pos_to_irq(int bit);
-    int synergy_intr_connect(int bit, int cpuid);
 
 
     hub_v = (devfs_handle_t)cnodeid_to_vertex(cnode);
@@ -130,17 +136,6 @@
     ASSERT(hinfo);
     ASSERT(hinfo->h_cnodeid == cnode);
 
-    ilcsr.ii_ilcsr_regval = REMOTE_HUB_L(hinfo->h_nasid, IIO_ILCSR);
-
-    if ((ilcsr.ii_ilcsr_fld_s.i_llp_stat & 0x2) == 0) {
-	/* 
-	 * HUB II link is not up. 
-	 * Just disable LLP, and don't connect any interrupts.
-	 */
-	ilcsr.ii_ilcsr_fld_s.i_llp_en = 0;
-	REMOTE_HUB_S(hinfo->h_nasid, IIO_ILCSR, ilcsr.ii_ilcsr_regval);
-	return;
-    }
     /* Select a possible interrupt target where there is a free interrupt
      * bit and also reserve the interrupt bit for this IO error interrupt
      */
@@ -152,7 +147,11 @@
     }
 	
     rv = intr_connect_level(intr_cpu, bit, 0, NULL);
-    request_irq(bit + (intr_cpu << 8), hubii_eint_handler, 0, "SN hub error", (void *)hub_v);
+    request_irq(bit + (intr_cpu << 8), hubii_eint_handler, 0, "SN_hub_error", (void *)hub_v);
+    irq_desc(bit + (intr_cpu << 8))->status |= SN2_IRQ_PER_HUB;
+#ifdef BUS_INT_WAR                                              
+    sn_add_polled_interrupt(bit + (intr_cpu << 8), (0.01 * HZ));
+#endif
     ASSERT_ALWAYS(rv >= 0);
     hubio_eint.ii_iidsr_regval = 0;
     hubio_eint.ii_iidsr_fld_s.i_enable = 1;
@@ -257,15 +256,16 @@
 void
 hubiio_crb_free(hubinfo_t hinfo, int crbnum)
 {
-	ii_icrb0_a_u_t         icrba;
+	ii_icrb0_b_u_t         icrbb;
 
 	/*
 	* The hardware does NOT clear the mark bit, so it must get cleared
 	* here to be sure the error is not processed twice.
 	*/
-	icrba.ii_icrb0_a_regval = REMOTE_HUB_L(hinfo->h_nasid, IIO_ICRB_A(crbnum));
-	icrba.a_valid   = 0;
-	REMOTE_HUB_S(hinfo->h_nasid, IIO_ICRB_A(crbnum), icrba.ii_icrb0_a_regval);
+	icrbb.ii_icrb0_b_regval = REMOTE_HUB_L(hinfo->h_nasid, IIO_ICRB_B(crbnum));
+	icrbb.b_mark   = 0;
+	REMOTE_HUB_S(hinfo->h_nasid, IIO_ICRB_B(crbnum), icrbb.ii_icrb0_b_regval);
+
 	/*
 	* Deallocate the register.
 	*/
@@ -325,9 +325,11 @@
 	ii_icrb0_b_u_t		icrbb;		/* II CRB Register B */
 	ii_icrb0_c_u_t		icrbc;		/* II CRB Register C */
 	ii_icrb0_d_u_t		icrbd;		/* II CRB Register D */
+	ii_icrb0_e_u_t		icrbe;		/* II CRB Register D */
 	int		i;
 	int		num_errors = 0;	/* Num of errors handled */
 	ioerror_t	ioerror;
+	int		rc;
 
 	nasid = hinfo->h_nasid;
 	cnode = NASID_TO_COMPACT_NODEID(nasid);
@@ -337,16 +339,24 @@
 	 * in any of the CRBs marked.
 	 */
 	for (i = 0; i < IIO_NUM_CRBS; i++) {
+		/* Check this crb entry to see if it is in error. */
+		icrbb.ii_icrb0_b_regval = REMOTE_HUB_L(nasid, IIO_ICRB_B(i));
+
+		if (icrbb.b_mark == 0) {
+			continue;
+		}
+
 		icrba.ii_icrb0_a_regval = REMOTE_HUB_L(nasid, IIO_ICRB_A(i));
 
 		IOERROR_INIT(&ioerror);
 
 		/* read other CRB error registers. */
-		icrbb.ii_icrb0_b_regval = REMOTE_HUB_L(nasid, IIO_ICRB_B(i));
 		icrbc.ii_icrb0_c_regval = REMOTE_HUB_L(nasid, IIO_ICRB_C(i));
 		icrbd.ii_icrb0_d_regval = REMOTE_HUB_L(nasid, IIO_ICRB_D(i));
+		icrbe.ii_icrb0_e_regval = REMOTE_HUB_L(nasid, IIO_ICRB_E(i));
 
 		IOERROR_SETVALUE(&ioerror,errortype,icrbb.b_ecode);
+
 		/* Check if this error is due to BTE operation,
 		* and handle it separately.
 		*/
@@ -363,8 +373,15 @@
 			else /* b_initiator bit 2 gives BTE number */
 				bte_num = (icrbb.b_initiator & 0x4) >> 2;
 
+			/* >>> bte_crb_error_handler needs to be 
+			 * broken into two parts.  The first should
+			 * cleanup the CRB.  The second should wait
+			 * until all bte related CRB's are complete
+			 * and then do the error reset.
+			 */
 			bte_crb_error_handler(hub_v, bte_num,
-					i, &ioerror);
+					      i, &ioerror,
+					      icrbd.d_bteop);
 			hubiio_crb_free(hinfo, i);
 			num_errors++;
 			continue;
@@ -401,13 +418,144 @@
 			 */
 			IOERROR_SETVALUE(&ioerror,widgetdev,
 					 TNUM_TO_WIDGET_DEV(icrba.a_tnum));
+			/*
+			* The encoding of TNUM (see comments above) is
+			* different for PIC. So we'll save TNUM here and
+			* deal with the differences later when we can
+			* determine if we're using a Bridge or the PIC.
+			*
+			* XXX:  We may be able to remove saving the widgetdev
+			* above and just sort it out of TNUM later.
+			*/
+			IOERROR_SETVALUE(&ioerror, tnum, icrba.a_tnum);
+
+		}
+
+		if (icrbb.b_error) {
+		/* 
+		 * CRB 'i' has some error. Identify the type of error,
+		 * and try to handle it.
+		 */
+		switch(icrbb.b_ecode) {
+		case IIO_ICRB_ECODE_PERR:
+		case IIO_ICRB_ECODE_WERR:
+		case IIO_ICRB_ECODE_AERR:
+		case IIO_ICRB_ECODE_PWERR:
+
+			printk("%s on hub cnodeid: %d",
+				hubiio_crb_errors[icrbb.b_ecode], cnode);
+			/*
+			 * Any sort of write error is mostly due
+			 * bad programming (Note it's not a timeout.)
+			 * So, invoke hub_iio_error_handler with
+			 * appropriate information.
+			 */
+			IOERROR_SETVALUE(&ioerror,errortype,icrbb.b_ecode);
+
+			rc = hub_ioerror_handler(
+					hub_v, 
+					DMA_WRITE_ERROR, 
+					MODE_DEVERROR, 
+					&ioerror);
+
+                        if (rc == IOERROR_HANDLED) {
+                                rc = hub_ioerror_handler(
+                                        hub_v,
+                                        DMA_WRITE_ERROR,
+                                        MODE_DEVREENABLE,
+                                        &ioerror);
+                                ASSERT(rc == IOERROR_HANDLED);
+                        }else {
+
+				panic("Unable to handle %s on hub %d",
+					hubiio_crb_errors[icrbb.b_ecode],
+					cnode);
+				/*NOTREACHED*/
+			}
+			/* Go to Next error */
+			hubiio_crb_free(hinfo, i);
+			continue;
+
+		case IIO_ICRB_ECODE_PRERR:
+
+                case IIO_ICRB_ECODE_TOUT:
+                case IIO_ICRB_ECODE_XTERR:
+
+		case IIO_ICRB_ECODE_DERR:
+			panic("Fatal %s on hub : %d",
+				hubiio_crb_errors[icrbb.b_ecode], cnode);
+			/*NOTREACHED*/
+		
+		default:
+			panic("Fatal error (code : %d) on hub : %d",
+				cnode);
+			/*NOTREACHED*/
+
+		}
+		} 	/* if (icrbb.b_error) */	
 
+		/*
+		 * Error is not indicated via the errcode field 
+		 * Check other error indications in this register.
+		 */
+		
+		if (icrbb.b_xerr) {
+			panic("Xtalk Packet with error bit set to hub %d",
+				cnode);
+			/*NOTREACHED*/
+		}
+
+		if (icrbb.b_lnetuce) {
+			panic("Uncorrectable data error detected on data "
+				" from Craylink to node %d",
+				cnode);
+			/*NOTREACHED*/
 		}
 
 	}
 	return	num_errors;
 }
 
+/*
+ * hubii_check_widget_disabled
+ *
+ *	Check if PIO access to the specified widget is disabled due
+ *	to any II errors that are currently set.
+ *
+ *	The specific error bits checked are:
+ *		IPRBx register: SPUR_RD (51)
+ *				SPUR_WR (50)
+ *				RD_TO (49)
+ *				ERROR (48)
+ *
+ *		WSTAT register: CRAZY (32)
+ */
+
+int
+hubii_check_widget_disabled(nasid_t nasid, int wnum)
+{
+	iprb_t		iprb;
+	ii_wstat_u_t	wstat;
+
+	iprb.iprb_regval = REMOTE_HUB_L(nasid, IIO_IOPRB(wnum));
+	if (iprb.iprb_regval & (IIO_PRB_SPUR_RD | IIO_PRB_SPUR_WR |
+		IIO_PRB_RD_TO | IIO_PRB_ERROR)) {
+#ifdef DEBUG
+	    printk(KERN_WARNING "II error, IPRB%x=0x%lx\n", wnum, iprb.iprb_regval);
+#endif
+	    return(1);
+	}
+
+	wstat.ii_wstat_regval = REMOTE_HUB_L(nasid, IIO_WSTAT);
+	if (wstat.ii_wstat_regval & IIO_WSTAT_ECRAZY) {
+#ifdef DEBUG
+	    printk(KERN_WARNING "II error, WSTAT=0x%lx\n", wstat.ii_wstat_regval);
+#endif
+	    return(1);
+	}
+	return(0);
+}
+
 /*ARGSUSED*/
 /*
  * hubii_prb_handler
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/shubio.c linux-2.4.21-pre6/arch/ia64/sn/io/sn2/shubio.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/shubio.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn2/shubio.c	2003-03-26 23:49:35.000000000 +0000
@@ -0,0 +1,510 @@
+/* $Id: shubio.c,v 1.1 2002/02/28 17:31:25 marcelo 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) 1992 - 1997, 2000,2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <asm/smp.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/io.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/sn_private.h>
+#include <asm/sn/klconfig.h>
+#include <asm/sn/sn_cpuid.h>
+#include <asm/sn/pci/pciio.h>
+#include <asm/sn/pci/pcibr.h>
+#include <asm/sn/xtalk/xtalk.h>
+#include <asm/sn/pci/pcibr_private.h>
+#include <asm/sn/intr.h>
+#include <asm/sn/ioerror_handling.h>
+#include <asm/sn/ioerror.h>
+#include <asm/sn/sn2/shubio.h>
+
+
+error_state_t error_state_get(devfs_handle_t v);
+error_return_code_t error_state_set(devfs_handle_t v,error_state_t new_state);
+
+
+/*
+ * Get the xtalk provider function pointer for the
+ * specified hub.
+ */
+
+/*ARGSUSED*/
+int
+hub_xp_error_handler(
+	devfs_handle_t 	hub_v, 
+	nasid_t		nasid, 
+	int		error_code, 
+	ioerror_mode_t	mode, 
+	ioerror_t	*ioerror)
+{
+	/*REFERENCED*/
+	hubreg_t	iio_imem;
+	devfs_handle_t	xswitch;
+	error_state_t	e_state;
+	cnodeid_t	cnode;
+
+	/*
+	 * Before walking down to the next level, check if
+	 * the I/O link is up. If it's been disabled by the 
+	 * hub ii for some reason, we can't even touch the
+	 * widget registers.
+	 */
+	iio_imem = REMOTE_HUB_L(nasid, IIO_IMEM);
+
+	if (!(iio_imem & (IIO_IMEM_B0ESD|IIO_IMEM_W0ESD))){
+		/* 
+		 * IIO_IMEM_B0ESD getting set, indicates II shutdown
+		 * on HUB0 parts.. Hopefully that's not true for 
+		 * Hub1 parts..
+		 *
+		 *
+		 * If either one of them is shut down, can't
+		 * go any further.
+		 */
+		return IOERROR_XTALKLEVEL;
+	}
+
+	/* Get the error state of the hub */
+	e_state = error_state_get(hub_v);
+
+	cnode = NASID_TO_COMPACT_NODEID(nasid);
+
+	xswitch = NODEPDA(cnode)->basew_xc;
+
+	/* Set the error state of the crosstalk device to that of
+	 * hub.
+	 */
+	if (error_state_set(xswitch , e_state) == 
+	    ERROR_RETURN_CODE_CANNOT_SET_STATE)
+		return(IOERROR_UNHANDLED);
+
+	/* Clean the error state of the hub if we are in the action handling
+	 * phase.
+	 */
+	if (e_state == ERROR_STATE_ACTION)
+		(void)error_state_set(hub_v, ERROR_STATE_NONE);
+	/* hand the error off to the switch or the directly
+	 * connected crosstalk device.
+	 */
+	return  xtalk_error_handler(xswitch,
+				    error_code, mode, ioerror);
+
+}
+
+/* 
+ * Check if the widget in error has been enabled for PIO accesses
+ */
+int
+is_widget_pio_enabled(ioerror_t *ioerror)
+{
+	cnodeid_t	src_node;
+	nasid_t		src_nasid;
+	hubreg_t	ii_iowa;
+	xwidgetnum_t	widget;
+	iopaddr_t	p;
+
+	/* Get the node where the PIO error occurred */
+	IOERROR_GETVALUE(p,ioerror, srcnode);
+	src_node = p;
+	if (src_node == CNODEID_NONE)
+		return(0);
+
+	/* Get the nasid for the cnode */
+	src_nasid = COMPACT_TO_NASID_NODEID(src_node);
+	if (src_nasid == INVALID_NASID)
+		return(0);
+
+	/* Read the Outbound widget access register for this hub */
+	ii_iowa = REMOTE_HUB_L(src_nasid, IIO_IOWA);
+	IOERROR_GETVALUE(p,ioerror, widgetnum);
+	widget = p;
+
+	/* Check if the PIOs to the widget with PIO error have been
+	 * enabled.
+	 */
+	if (ii_iowa & IIO_IOWA_WIDGET(widget))
+		return(1);
+
+	return(0);
+}
+
+/*
+ * Hub IO error handling.
+ *
+ *	Gets invoked for different types of errors found at the hub. 
+ *	Typically this includes situations from bus error or due to 
+ *	an error interrupt (mostly generated at the hub).
+ */
+int
+hub_ioerror_handler(
+	devfs_handle_t 	hub_v, 
+	int		error_code,
+	int		mode,
+	struct io_error_s	*ioerror)
+{
+	hubinfo_t 	hinfo; 		/* Hub info pointer */
+	nasid_t		nasid;
+	int		retval = 0;
+	/*REFERENCED*/
+	iopaddr_t 	p;
+
+	IOERROR_DUMP("hub_ioerror_handler", error_code, mode, ioerror);
+
+	hubinfo_get(hub_v, &hinfo);
+
+	if (!hinfo){
+		/* Print an error message and return */
+		goto end;
+	}
+	nasid = hinfo->h_nasid;
+
+	switch(error_code) {
+
+	case PIO_READ_ERROR:
+		/* 
+		 * Cpu got a bus error while accessing IO space.
+		 * hubaddr field in ioerror structure should have
+		 * the IO address that caused access error.
+		 */
+
+		/*
+		 * Identify if  the physical address in hub_error_data
+		 * corresponds to small/large window, and accordingly,
+		 * get the xtalk address.
+		 */
+
+		/*
+		 * Evaluate the widget number and the widget address that
+		 * caused the error. Use 'vaddr' if it's there.
+		 * This is typically true either during probing
+		 * or a kernel driver getting into trouble. 
+		 * Otherwise, use paddr to figure out widget details
+		 * This is typically true for user mode bus errors while
+		 * accessing I/O space.
+		 */
+		 IOERROR_GETVALUE(p,ioerror,vaddr);
+		 if (p){
+		    /* 
+		     * If neither in small window nor in large window range,
+		     * outright reject it.
+		     */
+		    IOERROR_GETVALUE(p,ioerror,vaddr);
+		    if (NODE_SWIN_ADDR(nasid, (paddr_t)p)){
+			iopaddr_t	hubaddr;
+			xwidgetnum_t	widgetnum;
+			iopaddr_t	xtalkaddr;
+
+			IOERROR_GETVALUE(p,ioerror,hubaddr);
+			hubaddr = p;
+			widgetnum = SWIN_WIDGETNUM(hubaddr);
+			xtalkaddr = SWIN_WIDGETADDR(hubaddr);
+			/* 
+			 * differentiate local register vs IO space access
+			 */
+			IOERROR_SETVALUE(ioerror,widgetnum,widgetnum);
+			IOERROR_SETVALUE(ioerror,xtalkaddr,xtalkaddr);
+
+
+		    } else if (NODE_BWIN_ADDR(nasid, (paddr_t)p)){
+			/* 
+			 * Address corresponds to large window space. 
+			 * Convert it to xtalk address.
+			 */
+			int		bigwin;
+			hub_piomap_t    bw_piomap;
+			xtalk_piomap_t	xt_pmap = NULL;
+			iopaddr_t	hubaddr;
+			xwidgetnum_t	widgetnum;
+			iopaddr_t	xtalkaddr;
+
+			IOERROR_GETVALUE(p,ioerror,hubaddr);
+			hubaddr = p;
+
+			/*
+			 * Have to loop to find the correct xtalk_piomap 
+			 * because the're not allocated on a one-to-one
+			 * basis to the window number.
+			 */
+			for (bigwin=0; bigwin < HUB_NUM_BIG_WINDOW; bigwin++) {
+				bw_piomap = hubinfo_bwin_piomap_get(hinfo,
+								    bigwin);
+
+				if (bw_piomap->hpio_bigwin_num ==
+				    (BWIN_WINDOWNUM(hubaddr) - 1)) {
+					xt_pmap = hub_piomap_xt_piomap(bw_piomap);
+					break;
+				}
+			}
+
+			ASSERT(xt_pmap);
+
+			widgetnum = xtalk_pio_target_get(xt_pmap);
+			xtalkaddr = xtalk_pio_xtalk_addr_get(xt_pmap) + BWIN_WIDGETADDR(hubaddr);
+
+			IOERROR_SETVALUE(ioerror,widgetnum,widgetnum);
+			IOERROR_SETVALUE(ioerror,xtalkaddr,xtalkaddr);
+
+			/* 
+			 * Make sure that widgetnum doesnot map to hub 
+			 * register widget number, as we never use
+			 * big window to access hub registers. 
+			 */
+			ASSERT(widgetnum != HUB_REGISTER_WIDGET);
+		    }
+		} else if (IOERROR_FIELDVALID(ioerror,hubaddr)) {
+			iopaddr_t	hubaddr;
+			xwidgetnum_t	widgetnum;
+			iopaddr_t	xtalkaddr;
+
+			IOERROR_GETVALUE(p,ioerror,hubaddr);
+			hubaddr = p;
+			if (BWIN_WINDOWNUM(hubaddr)){
+				int 	window = BWIN_WINDOWNUM(hubaddr) - 1;
+				hubreg_t itte;
+				itte = (hubreg_t)HUB_L(IIO_ITTE_GET(nasid, window));
+				widgetnum =  (itte >> IIO_ITTE_WIDGET_SHIFT) & 
+						IIO_ITTE_WIDGET_MASK;
+				xtalkaddr = (((itte >> IIO_ITTE_OFFSET_SHIFT) &
+					IIO_ITTE_OFFSET_MASK) << 
+					     BWIN_SIZE_BITS) +
+					BWIN_WIDGETADDR(hubaddr);
+			} else {
+				widgetnum = SWIN_WIDGETNUM(hubaddr);
+				xtalkaddr = SWIN_WIDGETADDR(hubaddr);
+			}
+			IOERROR_SETVALUE(ioerror,widgetnum,widgetnum);
+			IOERROR_SETVALUE(ioerror,xtalkaddr,xtalkaddr);
+		} else {
+			IOERROR_DUMP("hub_ioerror_handler", error_code, 
+						mode, ioerror);
+			IOERR_PRINTF(printk(
+				"hub_ioerror_handler: Invalid address passed"));
+
+			return IOERROR_INVALIDADDR;
+		}
+
+
+		IOERROR_GETVALUE(p,ioerror,widgetnum);
+		if ((p) == HUB_REGISTER_WIDGET) {
+			/* 
+			 * Error in accessing Hub local register
+			 * This should happen mostly in SABLE mode..
+			 */
+			retval = 0;
+		} else {
+			/* Make sure that the outbound widget access for this
+			 * widget is enabled.
+			 */
+			if (!is_widget_pio_enabled(ioerror)) {
+				if (error_state_get(hub_v) == 
+				    ERROR_STATE_ACTION)
+					ioerror_dump("No outbound widget"
+						     " access - ", 
+						     error_code, mode, ioerror);
+				return(IOERROR_HANDLED);
+			}
+		  
+
+			retval = hub_xp_error_handler(
+				hub_v, nasid, error_code, mode, ioerror);
+
+		}
+
+		IOERR_PRINTF(printk(
+			"hub_ioerror_handler:PIO_READ_ERROR return: %d",
+				retval));
+
+		break;
+
+	case PIO_WRITE_ERROR:
+		/*
+		 * This hub received an interrupt indicating a widget 
+		 * attached to this hub got a timeout. 
+		 * widgetnum field should be filled to indicate the
+		 * widget that caused error.
+		 *
+		 * NOTE: This hub may have nothing to do with this error.
+		 * We are here since the widget attached to the xbow 
+		 * gets its PIOs through this hub.
+		 *
+		 * There is nothing that can be done at this level. 
+		 * Just invoke the xtalk error handling mechanism.
+		 */
+		IOERROR_GETVALUE(p,ioerror,widgetnum);
+		if ((p) == HUB_REGISTER_WIDGET) {
+		} else {
+			/* Make sure that the outbound widget access for this
+			 * widget is enabled.
+			 */
+
+			if (!is_widget_pio_enabled(ioerror)) {
+				if (error_state_get(hub_v) == 
+				    ERROR_STATE_ACTION)
+					ioerror_dump("No outbound widget"
+						     " access - ", 
+						     error_code, mode, ioerror);
+				return(IOERROR_HANDLED);
+			}
+		  
+			retval = hub_xp_error_handler(
+				hub_v, nasid, error_code, mode, ioerror);
+		}
+		break;
+	
+	case DMA_READ_ERROR:
+		/* 
+		 * DMA Read error always ends up generating an interrupt
+		 * at the widget level, and never at the hub level. So,
+		 * we don't expect to come here any time
+		 */
+		ASSERT(0);
+		retval = IOERROR_UNHANDLED;
+		break;
+
+	case DMA_WRITE_ERROR:
+		/*
+		 * DMA Write error is generated when a write by an I/O 
+		 * device could not be completed. Problem is, device is
+		 * totally unaware of this problem, and would continue
+		 * writing to system memory. So, hub has a way to send
+		 * an error interrupt on the first error, and bitbucket
+		 * all further write transactions.
+		 * Coming here indicates that hub detected one such error,
+		 * and we need to handle it.
+		 *
+		 * Hub interrupt handler would have extracted physaddr, 
+		 * widgetnum, and widgetdevice from the CRB 
+		 *
+		 * There is nothing special to do here, since gathering
+		 * data from crb's is done elsewhere. Just pass the 
+		 * error to xtalk layer.
+		 */
+		retval = hub_xp_error_handler(hub_v, nasid, error_code, mode,
+					      ioerror);
+		break;
+	
+	default:
+		ASSERT(0);
+		return IOERROR_BADERRORCODE;
+	
+	}
+	
+	/*
+	 * If error was not handled, we may need to take certain action
+	 * based on the error code.
+	 * For e.g. in case of PIO_READ_ERROR, we may need to release the
+	 * PIO Read entry table (they are sticky after errors).
+	 * Similarly other cases. 
+	 *
+	 * Further Action TBD 
+	 */
+end:	
+	if (retval == IOERROR_HWGRAPH_LOOKUP) {
+		/*
+		 * If we get errors very early, we can't traverse
+		 * the path using hardware graph. 
+		 * To handle this situation, we need a functions
+		 * which don't depend on the hardware graph vertex to 
+		 * handle errors. This break the modularity of the
+		 * existing code. Instead we print out the reason for
+		 * not handling error, and return. On return, all the
+		 * info collected would be dumped. This should provide 
+		 * sufficient info to analyse the error.
+		 */
+		printk("Unable to handle IO error: hardware graph not setup\n");
+	}
+
+	return retval;
+}
+
+#define L_BITSMINOR 18
+#define L_MAXMAJ 0x1ff
+#define emajor(x) (int )(((unsigned )(x)>>L_BITSMINOR) & L_MAXMAJ)
+#define dev_is_vertex(dev) (emajor((dev_t)(dev)) == 0)
+
+#define INFO_LBL_ERROR_STATE    "error_state"
+
+#define v_error_state_get(v,s)                                          \
+(hwgraph_info_get_LBL(v,INFO_LBL_ERROR_STATE, (arbitrary_info_t *)&s))
+
+#define v_error_state_set(v,s,replace)                                  \
+(replace ?                                                              \
+hwgraph_info_replace_LBL(v,INFO_LBL_ERROR_STATE,(arbitrary_info_t)s,0) :\
+hwgraph_info_add_LBL(v,INFO_LBL_ERROR_STATE, (arbitrary_info_t)s))
+
+
+#define v_error_state_clear(v)                                          \
+(hwgraph_info_remove_LBL(v,INFO_LBL_ERROR_STATE,0))
+
+/*
+ * error_state_get
+ *              Get the state of the vertex.
+ *              Returns ERROR_STATE_INVALID on failure
+ *                      current state otherwise
+ */
+error_state_t
+error_state_get(devfs_handle_t v)
+{
+        error_state_t   s;
+
+        /* Check if we have a valid hwgraph vertex */
+        if (!dev_is_vertex(v))
+                return(ERROR_STATE_NONE);
+
+        /* Get the labelled info hanging off the vertex which corresponds
+         * to the state.
+         */
+        if (v_error_state_get(v, s) != GRAPH_SUCCESS) {
+                return(ERROR_STATE_NONE);
+        }
+        return(s);
+}
+
+
+/*
+ * error_state_set
+ *              Set the state of the vertex
+ *              Returns ERROR_RETURN_CODE_CANNOT_SET_STATE on failure
+ *                      ERROR_RETURN_CODE_SUCCESS otherwise
+ */
+error_return_code_t
+error_state_set(devfs_handle_t v,error_state_t new_state)
+{
+        error_state_t   old_state;
+        boolean_t       replace = B_TRUE;
+
+        /* Check if we have a valid hwgraph vertex */
+        if (!dev_is_vertex(v))
+                return(ERROR_RETURN_CODE_GENERAL_FAILURE);
+
+
+        /* This means that the error state needs to be cleaned */
+        if (new_state == ERROR_STATE_NONE) {
+                /* Make sure that we have an error state */
+                if (v_error_state_get(v,old_state) == GRAPH_SUCCESS)
+                        v_error_state_clear(v);
+                return(ERROR_RETURN_CODE_SUCCESS);
+        }
+
+        /* Check if the state information has been set at least once
+         * for this vertex.
+         */
+        if (v_error_state_get(v,old_state) != GRAPH_SUCCESS)
+                replace = B_FALSE;
+
+        if (v_error_state_set(v,new_state,replace) != GRAPH_SUCCESS) {
+                return(ERROR_RETURN_CODE_CANNOT_SET_STATE);
+        }
+        return(ERROR_RETURN_CODE_SUCCESS);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/xbow.c linux-2.4.21-pre6/arch/ia64/sn/io/sn2/xbow.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/xbow.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn2/xbow.c	2003-03-26 23:49:09.000000000 +0000
@@ -0,0 +1,1642 @@
+/* $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) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/intr.h>
+#include <asm/sn/sn2/sn_private.h>
+#include <asm/sn/sn2/shubio.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/hack.h>
+#include <asm/sn/pci/bridge.h>
+#include <asm/sn/xtalk/xtalk_private.h>
+#include <asm/sn/simulator.h>
+
+/* #define DEBUG		1 */
+/* #define XBOW_DEBUG	1 */
+/* #define DEBUG_ERROR	1 */
+
+
+/*
+ * Files needed to get the device driver entry points
+ */
+
+#include <asm/sn/xtalk/xbow.h>
+#include <asm/sn/xtalk/xtalk.h>
+#include <asm/sn/xtalk/xswitch.h>
+#include <asm/sn/xtalk/xwidget.h>
+
+#include <asm/sn/prio.h>
+#include <asm/sn/hcl_util.h>
+
+
+#define NEW(ptr)	(ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL))
+#define DEL(ptr)	(kfree(ptr))
+
+int                     xbow_devflag = D_MP;
+
+/*
+ * This file supports the Xbow chip.  Main functions: initializtion,
+ * error handling, and GBR.
+ */
+
+/*
+ * each vertex corresponding to an xbow chip
+ * has a "fastinfo" pointer pointing at one
+ * of these things.
+ */
+typedef struct xbow_soft_s *xbow_soft_t;
+
+struct xbow_soft_s {
+    devfs_handle_t            conn;	/* our connection point */
+    devfs_handle_t            vhdl;	/* xbow's private vertex */
+    devfs_handle_t            busv;	/* the xswitch vertex */
+    xbow_t                 *base;	/* PIO pointer to crossbow chip */
+    char                   *name;	/* hwgraph name */
+
+    xbow_perf_t             xbow_perfcnt[XBOW_PERF_COUNTERS];
+    xbow_perf_link_t        xbow_perflink[MAX_XBOW_PORTS];
+    xbow_link_status_t      xbow_link_status[MAX_XBOW_PORTS];
+    spinlock_t              xbow_perf_lock;
+    int                     link_monitor;
+    widget_cfg_t	   *wpio[MAX_XBOW_PORTS];	/* cached PIO pointer */
+
+    /* Bandwidth allocation state. Bandwidth values are for the
+     * destination port since contention happens there.
+     * Implicit mapping from xbow ports (8..f) -> (0..7) array indices.
+     */
+    spinlock_t		    xbow_bw_alloc_lock;		/* bw allocation lock */
+    unsigned long long	    bw_hiwm[MAX_XBOW_PORTS];	/* hiwater mark values */
+    unsigned long long      bw_cur_used[MAX_XBOW_PORTS]; /* bw used currently */
+};
+
+#define xbow_soft_set(v,i)	hwgraph_fastinfo_set((v), (arbitrary_info_t)(i))
+#define xbow_soft_get(v)	((xbow_soft_t)hwgraph_fastinfo_get((v)))
+
+/*
+ * Function Table of Contents
+ */
+
+void                    xbow_mlreset(xbow_t *);
+void                    xbow_init(void);
+int                     xbow_attach(devfs_handle_t);
+
+int                     xbow_open(devfs_handle_t *, int, int, cred_t *);
+int                     xbow_close(devfs_handle_t, int, int, cred_t *);
+
+int                     xbow_map(devfs_handle_t, vhandl_t *, off_t, size_t, uint);
+int                     xbow_unmap(devfs_handle_t, vhandl_t *);
+int                     xbow_ioctl(devfs_handle_t, int, void *, int, struct cred *, int *);
+
+int                     xbow_widget_present(xbow_t *, int);
+static int              xbow_link_alive(xbow_t *, int);
+devfs_handle_t            xbow_widget_lookup(devfs_handle_t, int);
+
+void                    xbow_intr_preset(void *, int, xwidgetnum_t, iopaddr_t, xtalk_intr_vector_t);
+
+
+
+void                    xbow_update_perf_counters(devfs_handle_t);
+xbow_perf_link_t       *xbow_get_perf_counters(devfs_handle_t);
+int                     xbow_enable_perf_counter(devfs_handle_t, int, int, int);
+xbow_link_status_t     *xbow_get_llp_status(devfs_handle_t);
+void                    xbow_update_llp_status(devfs_handle_t);
+
+int                     xbow_disable_llp_monitor(devfs_handle_t);
+int                     xbow_enable_llp_monitor(devfs_handle_t);
+int                     xbow_prio_bw_alloc(devfs_handle_t, xwidgetnum_t, xwidgetnum_t,
+                                unsigned long long, unsigned long long);
+static void		xbow_setwidint(xtalk_intr_t);
+void                    idbg_xbowregs(int64_t);
+
+xswitch_reset_link_f    xbow_reset_link;
+
+xswitch_provider_t      xbow_provider =
+{
+    xbow_reset_link,
+};
+
+/*
+ *    xbow_mlreset: called at mlreset time if the
+ *      platform specific code determines that there is
+ *      a crossbow in a critical path that must be
+ *      functional before the driver would normally get
+ *      the device properly set up.
+ *
+ *      what do we need to do, that the boot prom can
+ *      not be counted on to have already done, that is
+ *      generic across all platforms using crossbows?
+ */
+/*ARGSUSED */
+void
+xbow_mlreset(xbow_t * xbow)
+{
+}
+
+/*
+ *    xbow_init: called with the rest of the device
+ *      driver XXX_init routines. This platform *might*
+ *      have a Crossbow chip, or even several, but it
+ *      might have none. Register with the crosstalk
+ *      generic provider so when we encounter the chip
+ *      the right magic happens.
+ */
+void
+xbow_init(void)
+{
+
+#if DEBUG && ATTACH_DEBUG
+    printk("xbow_init\n");
+#endif
+
+    xwidget_driver_register(PXBOW_WIDGET_PART_NUM,
+			    0, /* XXBOW_WIDGET_MFGR_NUM, */
+			    "xbow_",
+			    CDL_PRI_HI);	/* attach before friends */
+
+
+    xwidget_driver_register(XXBOW_WIDGET_PART_NUM,
+			    0, /* XXBOW_WIDGET_MFGR_NUM, */
+			    "xbow_",
+			    CDL_PRI_HI);	/* attach before friends */
+
+    xwidget_driver_register(XBOW_WIDGET_PART_NUM,
+			    XBOW_WIDGET_MFGR_NUM,
+			    "xbow_",
+			    CDL_PRI_HI);	/* attach before friends */
+}
+
+#ifdef XBRIDGE_REGS_SIM
+/*    xbow_set_simulated_regs: sets xbow regs as needed
+ *	for powering through the boot
+ */
+void
+xbow_set_simulated_regs(xbow_t *xbow, int port)
+{
+    /*
+     * turn on link
+     */
+    xbow->xb_link(port).link_status = (1<<31);
+    /*
+     * and give it a live widget too
+     */
+    xbow->xb_link(port).link_aux_status = XB_AUX_STAT_PRESENT;
+    /*
+     * zero the link control reg
+     */
+    xbow->xb_link(port).link_control = 0x0;
+}
+#endif /* XBRIDGE_REGS_SIM */
+
+/*
+ *    xbow_attach: the crosstalk provider has
+ *      determined that there is a crossbow widget
+ *      present, and has handed us the connection
+ *      point for that vertex.
+ *
+ *      We not only add our own vertex, but add
+ *      some "xtalk switch" data to the switch
+ *      vertex (at the connect point's parent) if
+ *      it does not have any.
+ */
+
+/*ARGSUSED */
+int
+xbow_attach(devfs_handle_t conn)
+{
+    /*REFERENCED */
+    devfs_handle_t            vhdl;
+    devfs_handle_t            busv;
+    xbow_t                 *xbow;
+    xbow_soft_t             soft;
+    int                     port;
+    xswitch_info_t          info;
+    xtalk_intr_t            intr_hdl;
+    char                    devnm[MAXDEVNAME], *s;
+    xbowreg_t               id;
+    int                     rev;
+    int			    i;
+    int			    xbow_num;
+    static void xbow_errintr_handler(int, void *, struct pt_regs *);
+
+	
+#if DEBUG && ATTACH_DEBUG
+#if defined(SUPPORT_PRINTING_V_FORMAT)
+    printk("%v: xbow_attach\n", conn);
+#else
+    printk("0x%x: xbow_attach\n", conn);
+#endif
+#endif
+
+    /*
+     * Get a PIO pointer to the base of the crossbow
+     * chip.
+     */
+#ifdef XBRIDGE_REGS_SIM
+    printk("xbow_attach: XBRIDGE_REGS_SIM FIXME: allocating %ld bytes for xbow_s\n", sizeof(xbow_t));
+    xbow = (xbow_t *) kmalloc(sizeof(xbow_t), GFP_KERNEL);
+    /*
+     * turn on ports e and f like in a real live ibrick
+     */
+    xbow_set_simulated_regs(xbow, 0xe);
+    xbow_set_simulated_regs(xbow, 0xf);
+#else
+    xbow = (xbow_t *) xtalk_piotrans_addr(conn, 0, 0, sizeof(xbow_t), 0);
+#endif /* XBRIDGE_REGS_SIM */
+
+    /*
+     * Locate the "switch" vertex: it is the parent
+     * of our connection point.
+     */
+    busv = hwgraph_connectpt_get(conn);
+#if DEBUG && ATTACH_DEBUG
+    printk("xbow_attach: Bus Vertex 0x%p, conn 0x%p, xbow register 0x%p wid= 0x%x\n", busv, conn, xbow, *(volatile u32 *)xbow);
+#endif
+
+    ASSERT(busv != GRAPH_VERTEX_NONE);
+
+    /*
+     * Create our private vertex, and connect our
+     * driver information to it. This makes it possible
+     * for diagnostic drivers to open the crossbow
+     * vertex for access to registers.
+     */
+
+    /*
+     * We need to teach xbow drivers to provide the right set of
+     * file ops.
+     */
+    vhdl = NULL;
+    vhdl = hwgraph_register(conn, EDGE_LBL_XBOW,
+                        0, DEVFS_FL_AUTO_DEVNUM,
+                        0, 0,
+                        S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0,
+                        /* &hcl_fops */ (void *)&vhdl, NULL);
+    if (!vhdl) {
+        printk(KERN_WARNING "xbow_attach: Unable to create char device for xbow conn %p\n",
+                (void *)conn);
+    }
+
+    /*
+     * Allocate the soft state structure and attach
+     * it to the xbow's vertex
+     */
+    NEW(soft);
+    soft->conn = conn;
+    soft->vhdl = vhdl;
+    soft->busv = busv;
+    soft->base = xbow;
+    /* does the universe really need another macro?  */
+    /* xbow_soft_set(vhdl, (arbitrary_info_t) soft); */
+    hwgraph_fastinfo_set(vhdl, (arbitrary_info_t) soft);
+
+#define XBOW_NUM_SUFFIX_FORMAT	"[xbow# %d]"
+
+    /* Add xbow number as a suffix to the hwgraph name of the xbow.
+     * This is helpful while looking at the error/warning messages.
+     */
+    xbow_num = 0;
+
+    /*
+     * get the name of this xbow vertex and keep the info.
+     * This is needed during errors and interupts, but as
+     * long as we have it, we can use it elsewhere.
+     */
+    s = dev_to_name(vhdl, devnm, MAXDEVNAME);
+    soft->name = kmalloc(strlen(s) + strlen(XBOW_NUM_SUFFIX_FORMAT) + 1, 
+			    GFP_KERNEL);
+    sprintf(soft->name,"%s"XBOW_NUM_SUFFIX_FORMAT, s,xbow_num);
+
+#ifdef XBRIDGE_REGS_SIM
+    /* my o200/ibrick has id=0x2d002049, but XXBOW_WIDGET_PART_NUM is defined
+     * as 0xd000, so I'm using that for the partnum bitfield.
+     */
+    printk("xbow_attach: XBRIDGE_REGS_SIM FIXME: need xb_wid_id value!!\n");
+    id = 0x2d000049;
+#else
+    id = xbow->xb_wid_id;
+#endif /* XBRIDGE_REGS_SIM */
+    rev = XWIDGET_PART_REV_NUM(id);
+
+    mutex_spinlock_init(&soft->xbow_perf_lock);
+    soft->xbow_perfcnt[0].xp_perf_reg = &xbow->xb_perf_ctr_a;
+    soft->xbow_perfcnt[1].xp_perf_reg = &xbow->xb_perf_ctr_b;
+
+    /* Initialization for GBR bw allocation */
+    mutex_spinlock_init(&soft->xbow_bw_alloc_lock);
+
+#define	XBOW_8_BIT_PORT_BW_MAX		(400 * 1000 * 1000)	/* 400 MB/s */
+#define XBOW_16_BIT_PORT_BW_MAX		(800 * 1000 * 1000)	/* 800 MB/s */
+
+    /* Set bandwidth hiwatermark and current values */
+    for (i = 0; i < MAX_XBOW_PORTS; i++) {
+	soft->bw_hiwm[i] = XBOW_16_BIT_PORT_BW_MAX;	/* for now */
+	soft->bw_cur_used[i] = 0;
+    }
+
+     /*
+      * attach the crossbow error interrupt.
+      */
+     intr_hdl = xtalk_intr_alloc(conn, (device_desc_t)0, vhdl);
+     ASSERT(intr_hdl != NULL);
+ 
+     xtalk_intr_connect(intr_hdl,
+                        (intr_func_t) xbow_errintr_handler,
+                        (intr_arg_t) soft,
+                        (xtalk_intr_setfunc_t) xbow_setwidint,
+                        (void *) xbow);
+
+#ifdef BUS_INT_WAR_NOT_YET
+     request_irq(CPU_VECTOR_TO_IRQ(((hub_intr_t)intr_hdl)->i_cpuid,
+			((hub_intr_t)intr_hdl)->i_bit),
+			(intr_func_t)xbow_errintr_handler, 0, "XBOW error",
+			(intr_arg_t) soft);
+
+    {
+	void sn_add_polled_interrupt(int, int);
+        sn_add_polled_interrupt(CPU_VECTOR_TO_IRQ(((hub_intr_t)intr_hdl)->i_cpuid,
+                                ((hub_intr_t)intr_hdl)->i_bit), 5000);
+    }
+#endif
+
+ 
+    /*
+     * Enable xbow error interrupts
+     */
+    xbow->xb_wid_control = (XB_WID_CTRL_REG_ACC_IE | XB_WID_CTRL_XTALK_IE);
+
+    /*
+     * take a census of the widgets present,
+     * leaving notes at the switch vertex.
+     */
+    info = xswitch_info_new(busv);
+
+    for (port = MAX_PORT_NUM - MAX_XBOW_PORTS;
+	 port < MAX_PORT_NUM; ++port) {
+	if (!xbow_link_alive(xbow, port)) {
+#if DEBUG && XBOW_DEBUG
+	    printk(KERN_INFO "0x%p link %d is not alive\n",
+		    (void *)busv, port);
+#endif
+	    continue;
+	}
+	if (!xbow_widget_present(xbow, port)) {
+#if DEBUG && XBOW_DEBUG
+	    printk(KERN_INFO "0x%p link %d is alive but no widget is present\n", (void *)busv, port);
+#endif
+	    continue;
+	}
+#if DEBUG && XBOW_DEBUG
+	printk(KERN_INFO "0x%p link %d has a widget\n",
+		(void *)busv, port);
+#endif
+
+	xswitch_info_link_is_ok(info, port);
+	/*
+	 * Turn some error interrupts on
+	 * and turn others off. The PROM has
+	 * some things turned on we don't
+	 * want to see (bandwidth allocation
+	 * errors for instance); so if it
+	 * is not listed here, it is not on.
+	 */
+	xbow->xb_link(port).link_control =
+	    ( (xbow->xb_link(port).link_control
+	/*
+	 * Turn off these bits; they are non-fatal,
+	 * but we might want to save some statistics
+	 * on the frequency of these errors.
+	 * XXX FIXME XXX
+	 */
+	    & ~XB_CTRL_RCV_CNT_OFLOW_IE
+	    & ~XB_CTRL_XMT_CNT_OFLOW_IE
+	    & ~XB_CTRL_BNDWDTH_ALLOC_IE
+	    & ~XB_CTRL_RCV_IE)
+	/*
+	 * These are the ones we want to turn on.
+	 */
+	    | (XB_CTRL_ILLEGAL_DST_IE
+	    | XB_CTRL_OALLOC_IBUF_IE
+	    | XB_CTRL_XMT_MAX_RTRY_IE
+	    | XB_CTRL_MAXREQ_TOUT_IE
+	    | XB_CTRL_XMT_RTRY_IE
+	    | XB_CTRL_SRC_TOUT_IE) );
+    }
+
+    xswitch_provider_register(busv, &xbow_provider);
+
+    return 0;				/* attach successful */
+}
+
+/*ARGSUSED */
+int
+xbow_open(devfs_handle_t *devp, int oflag, int otyp, cred_t *credp)
+{
+    return 0;
+}
+
+/*ARGSUSED */
+int
+xbow_close(devfs_handle_t dev, int oflag, int otyp, cred_t *crp)
+{
+    return 0;
+}
+
+/*ARGSUSED */
+int
+xbow_map(devfs_handle_t dev, vhandl_t *vt, off_t off, size_t len, uint prot)
+{
+    devfs_handle_t            vhdl = dev_to_vhdl(dev);
+    xbow_soft_t             soft = xbow_soft_get(vhdl);
+    int                     error;
+
+    ASSERT(soft);
+    len = ctob(btoc(len));
+    /* XXX- this ignores the offset!!! */
+    error = v_mapphys(vt, (void *) soft->base, len);
+    return error;
+}
+
+/*ARGSUSED */
+int
+xbow_unmap(devfs_handle_t dev, vhandl_t *vt)
+{
+    return 0;
+}
+
+/* This contains special-case code for grio. There are plans to make
+ * this general sometime in the future, but till then this should
+ * be good enough.
+ */
+xwidgetnum_t
+xbow_widget_num_get(devfs_handle_t dev)
+{
+	devfs_handle_t	tdev;
+	char		devname[MAXDEVNAME];
+	xwidget_info_t	xwidget_info;
+	int		i;
+
+	vertex_to_name(dev, devname, MAXDEVNAME);
+
+	/* If this is a pci controller vertex, traverse up using
+	 * the ".." links to get to the widget.
+	 */
+	if (strstr(devname, EDGE_LBL_PCI) &&
+			strstr(devname, EDGE_LBL_CONTROLLER)) {
+		tdev = dev;
+		for (i=0; i< 2; i++) {
+			if (hwgraph_edge_get(tdev,
+				HWGRAPH_EDGELBL_DOTDOT, &tdev) !=
+					GRAPH_SUCCESS)
+				return XWIDGET_NONE;
+		}
+
+		if ((xwidget_info = xwidget_info_chk(tdev)) != NULL) {
+			return (xwidget_info_id_get(xwidget_info));
+		} else {
+			return XWIDGET_NONE;
+		}
+	}
+
+	return XWIDGET_NONE;
+}
+
+int
+xbow_ioctl(devfs_handle_t dev,
+	   int cmd,
+	   void *arg,
+	   int flag,
+	   struct cred *cr,
+	   int *rvalp)
+{
+    devfs_handle_t            vhdl;
+    int                     error = 0;
+
+#if defined (DEBUG)
+    int                     rc;
+    devfs_handle_t            conn;
+    struct xwidget_info_s  *xwidget_info;
+    xbow_soft_t             xbow_soft;
+#endif
+    *rvalp = 0;
+
+    vhdl = dev_to_vhdl(dev);
+#if defined (DEBUG)
+    xbow_soft = xbow_soft_get(vhdl);
+    conn = xbow_soft->conn;
+
+    xwidget_info = xwidget_info_get(conn);
+    ASSERT_ALWAYS(xwidget_info != NULL);
+
+    rc = xwidget_hwid_is_xswitch(&xwidget_info->w_hwid);
+    ASSERT_ALWAYS(rc != 0);
+#endif
+    switch (cmd) {
+
+    case XBOWIOC_LLP_ERROR_ENABLE:
+	if ((error = xbow_enable_llp_monitor(vhdl)) != 0)
+	    error = EINVAL;
+
+	break;
+
+    case XBOWIOC_LLP_ERROR_DISABLE:
+
+	if ((error = xbow_disable_llp_monitor(vhdl)) != 0)
+	    error = EINVAL;
+
+	break;
+
+    default:
+	break;
+
+    }
+    return error;
+}
+
+/*
+ * xbow_widget_present: See if a device is present
+ * on the specified port of this crossbow.
+ */
+int
+xbow_widget_present(xbow_t *xbow, int port)
+{
+	if ( IS_RUNNING_ON_SIMULATOR() ) {
+		if ( (port == 14) || (port == 15) ) {
+			return 1;
+		}
+		else {
+			return 0;
+		}
+	}
+	else {
+		/* WAR: port 0xf on PIC is missing present bit */
+		if (XBOW_WAR_ENABLED(PV854827, xbow->xb_wid_id) &&
+					IS_PIC_XBOW(xbow->xb_wid_id) && port==0xf) {
+			return 1;
+		}
+		return xbow->xb_link(port).link_aux_status & XB_AUX_STAT_PRESENT;
+	}
+}
+
+static int
+xbow_link_alive(xbow_t * xbow, int port)
+{
+    xbwX_stat_t             xbow_linkstat;
+
+    xbow_linkstat.linkstatus = xbow->xb_link(port).link_status;
+    return (xbow_linkstat.link_alive);
+}
+
+/*
+ * xbow_widget_lookup
+ *      Lookup the edges connected to the xbow specified, and
+ *      retrieve the handle corresponding to the widgetnum
+ *      specified.
+ *      If not found, return 0.
+ */
+devfs_handle_t
+xbow_widget_lookup(devfs_handle_t vhdl,
+		   int widgetnum)
+{
+    xswitch_info_t          xswitch_info;
+    devfs_handle_t            conn;
+
+    xswitch_info = xswitch_info_get(vhdl);
+    conn = xswitch_info_vhdl_get(xswitch_info, widgetnum);
+    return conn;
+}
+
+/*
+ * xbow_setwidint: called when xtalk
+ * is establishing or migrating our
+ * interrupt service.
+ */
+static void
+xbow_setwidint(xtalk_intr_t intr)
+{
+    xwidgetnum_t            targ = xtalk_intr_target_get(intr);
+    iopaddr_t               addr = xtalk_intr_addr_get(intr);
+    xtalk_intr_vector_t     vect = xtalk_intr_vector_get(intr);
+    xbow_t                 *xbow = (xbow_t *) xtalk_intr_sfarg_get(intr);
+
+    xbow_intr_preset((void *) xbow, 0, targ, addr, vect);
+}
+
+/*
+ * xbow_intr_preset: called during mlreset time
+ * if the platform specific code needs to route
+ * an xbow interrupt before the xtalk infrastructure
+ * is available for use.
+ *
+ * Also called from xbow_setwidint, so we don't
+ * replicate the guts of the routine.
+ *
+ * XXX- probably should be renamed xbow_wid_intr_set or
+ * something to reduce confusion.
+ */
+/*ARGSUSED3 */
+void
+xbow_intr_preset(void *which_widget,
+		 int which_widget_intr,
+		 xwidgetnum_t targ,
+		 iopaddr_t addr,
+		 xtalk_intr_vector_t vect)
+{
+    xbow_t                 *xbow = (xbow_t *) which_widget;
+
+    xbow->xb_wid_int_upper = ((0xFF000000 & (vect << 24)) |
+			      (0x000F0000 & (targ << 16)) |
+			      XTALK_ADDR_TO_UPPER(addr));
+    xbow->xb_wid_int_lower = XTALK_ADDR_TO_LOWER(addr);
+
+#ifdef BRINGUP2
+printk("xbow_intr_preset: xb_wid_int_upper 0x%lx xb_wid_int_lower 0x%lx\n",
+	(long)(((0xFF000000 & (vect << 24)) | (0x000F0000 & (targ << 16)) |XTALK_ADDR_TO_UPPER(addr))), (long)XTALK_ADDR_TO_LOWER(addr));
+#endif
+}
+
+#define	XEM_ADD_STR(s)		printk("%s", (s))
+#define	XEM_ADD_NVAR(n,v)	printk("\t%20s: 0x%llx\n", (n), ((unsigned long long)v))
+#define	XEM_ADD_VAR(v)		XEM_ADD_NVAR(#v,(v))
+#define XEM_ADD_IOEF(p,n)	if (IOERROR_FIELDVALID(ioe,n)) {	\
+				    IOERROR_GETVALUE(p,ioe,n);		\
+				    XEM_ADD_NVAR("ioe." #n, p);		\
+				}
+
+#ifdef LATER
+static void
+xem_add_ioe(ioerror_t *ioe)
+{
+    union tmp {
+	ushort stmp;
+	unsigned long long lltmp;
+	cpuid_t cputmp;
+	cnodeid_t cntmp;
+	iopaddr_t iotmp;
+	caddr_t catmp;
+	paddr_t patmp;
+    } tmp;
+
+    XEM_ADD_IOEF(tmp.stmp, errortype);
+    XEM_ADD_IOEF(tmp.stmp, widgetnum);
+    XEM_ADD_IOEF(tmp.stmp, widgetdev);
+    XEM_ADD_IOEF(tmp.cputmp, srccpu);
+    XEM_ADD_IOEF(tmp.cntmp, srcnode);
+    XEM_ADD_IOEF(tmp.cntmp, errnode);
+    XEM_ADD_IOEF(tmp.iotmp, sysioaddr);
+    XEM_ADD_IOEF(tmp.iotmp, xtalkaddr);
+    XEM_ADD_IOEF(tmp.iotmp, busspace);
+    XEM_ADD_IOEF(tmp.iotmp, busaddr);
+    XEM_ADD_IOEF(tmp.catmp, vaddr);
+    XEM_ADD_IOEF(tmp.patmp, memaddr);
+    XEM_ADD_IOEF(tmp.catmp, epc);
+    XEM_ADD_IOEF(tmp.catmp, ef);
+    XEM_ADD_IOEF(tmp.stmp, tnum);
+}
+
+#define XEM_ADD_IOE()   (xem_add_ioe(ioe))
+#endif	/* LATER */
+
+int                     xbow_xmit_retry_errors = 0;
+
+int
+xbow_xmit_retry_error(xbow_soft_t soft,
+		      int port)
+{
+    xswitch_info_t          info;
+    devfs_handle_t            vhdl;
+    widget_cfg_t           *wid;
+    widgetreg_t             id;
+    int                     part;
+    int                     mfgr;
+
+    wid = soft->wpio[port - BASE_XBOW_PORT];
+    if (wid == NULL) {
+	/* If we can't track down a PIO
+	 * pointer to our widget yet,
+	 * leave our caller knowing that
+	 * we are interested in this
+	 * interrupt if it occurs in
+	 * the future.
+	 */
+	info = xswitch_info_get(soft->busv);
+	if (!info)
+	    return 1;
+	vhdl = xswitch_info_vhdl_get(info, port);
+	if (vhdl == GRAPH_VERTEX_NONE)
+	    return 1;
+	wid = (widget_cfg_t *) xtalk_piotrans_addr
+	    (vhdl, 0, 0, sizeof *wid, 0);
+	if (!wid)
+	    return 1;
+	soft->wpio[port - BASE_XBOW_PORT] = wid;
+    }
+    id = wid->w_id;
+    part = XWIDGET_PART_NUM(id);
+    mfgr = XWIDGET_MFG_NUM(id);
+
+    /* If this thing is not a Bridge,
+     * do not activate the WAR, and
+     * tell our caller we do not need
+     * to be called again.
+     */
+    if ((part != BRIDGE_WIDGET_PART_NUM) ||
+	(mfgr != BRIDGE_WIDGET_MFGR_NUM)) {
+		/* FIXME: add Xbridge to the WAR.
+		 * Shouldn't hurt anything.  Later need to
+		 * check if we can remove this.
+                 */
+    		if ((part != XBRIDGE_WIDGET_PART_NUM) ||
+		    (mfgr != XBRIDGE_WIDGET_MFGR_NUM))
+			return 0;
+    }
+
+    /* count how many times we
+     * have picked up after
+     * LLP Transmit problems.
+     */
+    xbow_xmit_retry_errors++;
+
+    /* rewrite the control register
+     * to fix things up.
+     */
+    wid->w_control = wid->w_control;
+    wid->w_control;
+
+    return 1;
+}
+
+/*
+ * xbow_errintr_handler will be called if the xbow
+ * sends an interrupt request to report an error.
+ */
+static void
+xbow_errintr_handler(int irq, void *arg, struct pt_regs *ep)
+{
+    ioerror_t               ioe[1];
+    xbow_soft_t             soft = (xbow_soft_t) arg;
+    xbow_t                 *xbow = soft->base;
+    xbowreg_t               wid_control;
+    xbowreg_t               wid_stat;
+    xbowreg_t               wid_err_cmdword;
+    xbowreg_t               wid_err_upper;
+    xbowreg_t               wid_err_lower;
+    w_err_cmd_word_u        wid_err;
+    unsigned long long      wid_err_addr;
+
+    int                     fatal = 0;
+    int                     dump_ioe = 0;
+    static int xbow_error_handler(void *, int, ioerror_mode_t, ioerror_t *);
+
+    wid_control = xbow->xb_wid_control;
+    wid_stat = xbow->xb_wid_stat_clr;
+    wid_err_cmdword = xbow->xb_wid_err_cmdword;
+    wid_err_upper = xbow->xb_wid_err_upper;
+    wid_err_lower = xbow->xb_wid_err_lower;
+    xbow->xb_wid_err_cmdword = 0;
+
+    wid_err_addr = wid_err_lower | (((iopaddr_t) wid_err_upper & WIDGET_ERR_UPPER_ADDR_ONLY) << 32);
+
+    if (wid_stat & XB_WID_STAT_LINK_INTR_MASK) {
+	int                     port;
+
+	wid_err.r = wid_err_cmdword;
+
+	for (port = MAX_PORT_NUM - MAX_XBOW_PORTS;
+	     port < MAX_PORT_NUM; port++) {
+	    if (wid_stat & XB_WID_STAT_LINK_INTR(port)) {
+		xb_linkregs_t          *link = &(xbow->xb_link(port));
+		xbowreg_t               link_control = link->link_control;
+		xbowreg_t               link_status = link->link_status_clr;
+		xbowreg_t               link_aux_status = link->link_aux_status;
+		xbowreg_t               link_pend;
+
+		link_pend = link_status & link_control &
+		    (XB_STAT_ILLEGAL_DST_ERR
+		     | XB_STAT_OALLOC_IBUF_ERR
+		     | XB_STAT_RCV_CNT_OFLOW_ERR
+		     | XB_STAT_XMT_CNT_OFLOW_ERR
+		     | XB_STAT_XMT_MAX_RTRY_ERR
+		     | XB_STAT_RCV_ERR
+		     | XB_STAT_XMT_RTRY_ERR
+		     | XB_STAT_MAXREQ_TOUT_ERR
+		     | XB_STAT_SRC_TOUT_ERR
+		    );
+
+		if (link_pend & XB_STAT_ILLEGAL_DST_ERR) {
+		    if (wid_err.f.sidn == port) {
+			IOERROR_INIT(ioe);
+			IOERROR_SETVALUE(ioe, widgetnum, port);
+			IOERROR_SETVALUE(ioe, xtalkaddr, wid_err_addr);
+			if (IOERROR_HANDLED ==
+			    xbow_error_handler(soft,
+					       IOECODE_DMA,
+					       MODE_DEVERROR,
+					       ioe)) {
+			    link_pend &= ~XB_STAT_ILLEGAL_DST_ERR;
+			} else {
+			    dump_ioe++;
+			}
+		    }
+		}
+		/* Xbow/Bridge WAR:
+		 * if the bridge signals an LLP Transmitter Retry,
+		 * rewrite its control register.
+		 * If someone else triggers this interrupt,
+		 * ignore (and disable) the interrupt.
+		 */
+		if (link_pend & XB_STAT_XMT_RTRY_ERR) {
+		    if (!xbow_xmit_retry_error(soft, port)) {
+			link_control &= ~XB_CTRL_XMT_RTRY_IE;
+			link->link_control = link_control;
+			link->link_control;	/* stall until written */
+		    }
+		    link_pend &= ~XB_STAT_XMT_RTRY_ERR;
+		}
+		if (link_pend) {
+		    devfs_handle_t	xwidget_vhdl;
+		    char		*xwidget_name;
+		    
+		    /* Get the widget name corresponding to the current
+		     * xbow link.
+		     */
+		    xwidget_vhdl = xbow_widget_lookup(soft->busv,port);
+		    xwidget_name = xwidget_name_get(xwidget_vhdl);
+
+		    printk("%s port %X[%s] XIO Bus Error",
+			    soft->name, port, xwidget_name);
+		    if (link_status & XB_STAT_MULTI_ERR)
+			XEM_ADD_STR("\tMultiple Errors\n");
+		    if (link_status & XB_STAT_ILLEGAL_DST_ERR)
+			XEM_ADD_STR("\tInvalid Packet Destination\n");
+		    if (link_status & XB_STAT_OALLOC_IBUF_ERR)
+			XEM_ADD_STR("\tInput Overallocation Error\n");
+		    if (link_status & XB_STAT_RCV_CNT_OFLOW_ERR)
+			XEM_ADD_STR("\tLLP receive error counter overflow\n");
+		    if (link_status & XB_STAT_XMT_CNT_OFLOW_ERR)
+			XEM_ADD_STR("\tLLP transmit retry counter overflow\n");
+		    if (link_status & XB_STAT_XMT_MAX_RTRY_ERR)
+			XEM_ADD_STR("\tLLP Max Transmitter Retry\n");
+		    if (link_status & XB_STAT_RCV_ERR)
+			XEM_ADD_STR("\tLLP Receiver error\n");
+		    if (link_status & XB_STAT_XMT_RTRY_ERR)
+			XEM_ADD_STR("\tLLP Transmitter Retry\n");
+		    if (link_status & XB_STAT_MAXREQ_TOUT_ERR)
+			XEM_ADD_STR("\tMaximum Request Timeout\n");
+		    if (link_status & XB_STAT_SRC_TOUT_ERR)
+			XEM_ADD_STR("\tSource Timeout Error\n");
+
+		    {
+			int                     other_port;
+
+			for (other_port = 8; other_port < 16; ++other_port) {
+			    if (link_aux_status & (1 << other_port)) {
+				/* XXX- need to go to "other_port"
+				 * and clean up after the timeout?
+				 */
+				XEM_ADD_VAR(other_port);
+			    }
+			}
+		    }
+
+#if !DEBUG
+		    if (kdebug) {
+#endif
+			XEM_ADD_VAR(link_control);
+			XEM_ADD_VAR(link_status);
+			XEM_ADD_VAR(link_aux_status);
+
+#ifdef LATER
+			if (dump_ioe) {
+			    XEM_ADD_IOE();
+			    dump_ioe = 0;
+			}
+#endif
+#if !DEBUG
+		    }
+#endif
+		    fatal++;
+		}
+	    }
+	}
+    }
+    if (wid_stat & wid_control & XB_WID_STAT_WIDGET0_INTR) {
+	/* we have a "widget zero" problem */
+
+	if (wid_stat & (XB_WID_STAT_MULTI_ERR
+			| XB_WID_STAT_XTALK_ERR
+			| XB_WID_STAT_REG_ACC_ERR)) {
+
+	    printk("%s Port 0 XIO Bus Error",
+		    soft->name);
+	    if (wid_stat & XB_WID_STAT_MULTI_ERR)
+		XEM_ADD_STR("\tMultiple Error\n");
+	    if (wid_stat & XB_WID_STAT_XTALK_ERR)
+		XEM_ADD_STR("\tXIO Error\n");
+	    if (wid_stat & XB_WID_STAT_REG_ACC_ERR)
+		XEM_ADD_STR("\tRegister Access Error\n");
+
+	    fatal++;
+	}
+    }
+    if (fatal) {
+	XEM_ADD_VAR(wid_stat);
+	XEM_ADD_VAR(wid_control);
+	XEM_ADD_VAR(wid_err_cmdword);
+	XEM_ADD_VAR(wid_err_upper);
+	XEM_ADD_VAR(wid_err_lower);
+	XEM_ADD_VAR(wid_err_addr);
+	PRINT_PANIC("XIO Bus Error");
+    }
+}
+
+/*
+ * XBOW ERROR Handling routines.
+ * These get invoked as part of walking down the error handling path
+ * from hub/heart towards the I/O device that caused the error.
+ */
+
+/*
+ * xbow_error_handler
+ *      XBow error handling dispatch routine.
+ *      This is the primary interface used by external world to invoke
+ *      in case of an error related to a xbow.
+ *      Only functionality in this layer is to identify the widget handle
+ *      given the widgetnum. Otherwise, xbow does not gathers any error
+ *      data.
+ */
+static int
+xbow_error_handler(
+		      void *einfo,
+		      int error_code,
+		      ioerror_mode_t mode,
+		      ioerror_t *ioerror)
+{
+    int                     retval = IOERROR_WIDGETLEVEL;
+
+    xbow_soft_t             soft = (xbow_soft_t) einfo;
+    int                     port;
+    devfs_handle_t          conn;
+    devfs_handle_t          busv;
+
+    xbow_t                 *xbow = soft->base;
+    xbowreg_t               wid_stat;
+    xbowreg_t               wid_err_cmdword;
+    xbowreg_t               wid_err_upper;
+    xbowreg_t               wid_err_lower;
+    unsigned long long      wid_err_addr;
+
+    xb_linkregs_t          *link;
+    xbowreg_t               link_control;
+    xbowreg_t               link_status;
+    xbowreg_t               link_aux_status;
+
+    ASSERT(soft != 0);
+    busv = soft->busv;
+
+#if DEBUG && ERROR_DEBUG
+    printk("%s: xbow_error_handler\n", soft->name, busv);
+#endif
+
+    IOERROR_GETVALUE(port, ioerror, widgetnum);
+
+    if (port == 0) {
+	/* error during access to xbow:
+	 * do NOT attempt to access xbow regs.
+	 */
+	if (mode == MODE_DEVPROBE)
+	    return IOERROR_HANDLED;
+
+	if (error_code & IOECODE_DMA) {
+	    printk(KERN_ALERT
+		    "DMA error blamed on Crossbow at %s\n"
+		    "\tbut Crosbow never initiates DMA!",
+		    soft->name);
+	}
+	if (error_code & IOECODE_PIO) {
+	    iopaddr_t tmp;
+	    IOERROR_GETVALUE(tmp, ioerror, xtalkaddr);
+	    printk(KERN_ALERT "PIO Error on XIO Bus %s\n"
+		    "\tattempting to access XIO controller\n"
+		    "\twith offset 0x%lx",
+		    soft->name, tmp);
+	}
+	/* caller will dump contents of ioerror
+	 * in DEBUG and kdebug kernels.
+	 */
+
+	return retval;
+    }
+    /*
+     * error not on port zero:
+     * safe to read xbow registers.
+     */
+    wid_stat = xbow->xb_wid_stat;
+    wid_err_cmdword = xbow->xb_wid_err_cmdword;
+    wid_err_upper = xbow->xb_wid_err_upper;
+    wid_err_lower = xbow->xb_wid_err_lower;
+
+    wid_err_addr =
+	wid_err_lower
+	| (((iopaddr_t) wid_err_upper
+	    & WIDGET_ERR_UPPER_ADDR_ONLY)
+	   << 32);
+
+    if ((port < BASE_XBOW_PORT) ||
+	(port >= MAX_PORT_NUM)) {
+
+	if (mode == MODE_DEVPROBE)
+	    return IOERROR_HANDLED;
+
+	if (error_code & IOECODE_DMA) {
+	    printk(KERN_ALERT
+		    "DMA error blamed on XIO port at %s/%d\n"
+		    "\tbut Crossbow does not support that port",
+		    soft->name, port);
+	}
+	if (error_code & IOECODE_PIO) {
+	    iopaddr_t tmp;
+	    IOERROR_GETVALUE(tmp, ioerror, xtalkaddr);
+	    printk(KERN_ALERT
+		    "PIO Error on XIO Bus %s\n"
+		    "\tattempting to access XIO port %d\n"
+		    "\t(which Crossbow does not support)"
+		    "\twith offset 0x%lx",
+		    soft->name, port, tmp);
+	}
+#if !DEBUG
+	if (kdebug) {
+#endif
+	    XEM_ADD_STR("Raw status values for Crossbow:\n");
+	    XEM_ADD_VAR(wid_stat);
+	    XEM_ADD_VAR(wid_err_cmdword);
+	    XEM_ADD_VAR(wid_err_upper);
+	    XEM_ADD_VAR(wid_err_lower);
+	    XEM_ADD_VAR(wid_err_addr);
+#if !DEBUG
+	}
+#endif
+
+	/* caller will dump contents of ioerror
+	 * in DEBUG and kdebug kernels.
+	 */
+
+	return retval;
+    }
+    /* access to valid port:
+     * ok to check port status.
+     */
+
+    link = &(xbow->xb_link(port));
+    link_control = link->link_control;
+    link_status = link->link_status;
+    link_aux_status = link->link_aux_status;
+
+    /* Check that there is something present
+     * in that XIO port.
+     */
+    /* WAR: PIC widget 0xf is missing prescense bit */
+    if (XBOW_WAR_ENABLED(PV854827, xbow->xb_wid_id) &&
+		IS_PIC_XBOW(xbow->xb_wid_id) && (port==0xf))
+		;
+    else
+    if (!(link_aux_status & XB_AUX_STAT_PRESENT)) {
+	/* nobody connected. */
+	if (mode == MODE_DEVPROBE)
+	    return IOERROR_HANDLED;
+
+	if (error_code & IOECODE_DMA) {
+	    printk(KERN_ALERT
+		    "DMA error blamed on XIO port at %s/%d\n"
+		    "\tbut there is no device connected there.",
+		    soft->name, port);
+	}
+	if (error_code & IOECODE_PIO) {
+	    iopaddr_t tmp;
+	    IOERROR_GETVALUE(tmp, ioerror, xtalkaddr);
+	    printk(KERN_ALERT
+		    "PIO Error on XIO Bus %s\n"
+		    "\tattempting to access XIO port %d\n"
+		    "\t(which has no device connected)"
+		    "\twith offset 0x%lx",
+		    soft->name, port, tmp);
+	}
+#if !DEBUG
+	if (kdebug) {
+#endif
+	    XEM_ADD_STR("Raw status values for Crossbow:\n");
+	    XEM_ADD_VAR(wid_stat);
+	    XEM_ADD_VAR(wid_err_cmdword);
+	    XEM_ADD_VAR(wid_err_upper);
+	    XEM_ADD_VAR(wid_err_lower);
+	    XEM_ADD_VAR(wid_err_addr);
+	    XEM_ADD_VAR(port);
+	    XEM_ADD_VAR(link_control);
+	    XEM_ADD_VAR(link_status);
+	    XEM_ADD_VAR(link_aux_status);
+#if !DEBUG
+	}
+#endif
+	return retval;
+
+    }
+    /* Check that the link is alive.
+     */
+    if (!(link_status & XB_STAT_LINKALIVE)) {
+	iopaddr_t tmp;
+	/* nobody connected. */
+	if (mode == MODE_DEVPROBE)
+	    return IOERROR_HANDLED;
+
+	printk(KERN_ALERT
+		"%s%sError on XIO Bus %s port %d",
+		(error_code & IOECODE_DMA) ? "DMA " : "",
+		(error_code & IOECODE_PIO) ? "PIO " : "",
+		soft->name, port);
+
+	IOERROR_GETVALUE(tmp, ioerror, xtalkaddr);
+	if ((error_code & IOECODE_PIO) &&
+	    (IOERROR_FIELDVALID(ioerror, xtalkaddr))) {
+		printk("\tAccess attempted to offset 0x%lx\n", tmp);
+	}
+	if (link_aux_status & XB_AUX_LINKFAIL_RST_BAD)
+	    XEM_ADD_STR("\tLink never came out of reset\n");
+	else
+	    XEM_ADD_STR("\tLink failed while transferring data\n");
+
+    }
+    /* get the connection point for the widget
+     * involved in this error; if it exists and
+     * is not our connectpoint, cycle back through
+     * xtalk_error_handler to deliver control to
+     * the proper handler (or to report a generic
+     * crosstalk error).
+     *
+     * If the downstream handler won't handle
+     * the problem, we let our upstream caller
+     * deal with it, after (in DEBUG and kdebug
+     * kernels) dumping the xbow state for this
+     * port.
+     */
+    conn = xbow_widget_lookup(busv, port);
+    if ((conn != GRAPH_VERTEX_NONE) &&
+	(conn != soft->conn)) {
+	retval = xtalk_error_handler(conn, error_code, mode, ioerror);
+	if (retval == IOERROR_HANDLED)
+	    return IOERROR_HANDLED;
+    }
+    if (mode == MODE_DEVPROBE)
+	return IOERROR_HANDLED;
+
+    if (retval == IOERROR_UNHANDLED) {
+	iopaddr_t tmp;
+	retval = IOERROR_PANIC;
+
+	printk(KERN_ALERT
+		"%s%sError on XIO Bus %s port %d",
+		(error_code & IOECODE_DMA) ? "DMA " : "",
+		(error_code & IOECODE_PIO) ? "PIO " : "",
+		soft->name, port);
+
+	IOERROR_GETVALUE(tmp, ioerror, xtalkaddr);
+	if ((error_code & IOECODE_PIO) &&
+	    (IOERROR_FIELDVALID(ioerror, xtalkaddr))) {
+	    printk("\tAccess attempted to offset 0x%lx\n", tmp);
+	}
+    }
+
+#if !DEBUG
+    if (kdebug) {
+#endif
+	XEM_ADD_STR("Raw status values for Crossbow:\n");
+	XEM_ADD_VAR(wid_stat);
+	XEM_ADD_VAR(wid_err_cmdword);
+	XEM_ADD_VAR(wid_err_upper);
+	XEM_ADD_VAR(wid_err_lower);
+	XEM_ADD_VAR(wid_err_addr);
+	XEM_ADD_VAR(port);
+	XEM_ADD_VAR(link_control);
+	XEM_ADD_VAR(link_status);
+	XEM_ADD_VAR(link_aux_status);
+#if !DEBUG
+    }
+#endif
+    /* caller will dump raw ioerror data
+     * in DEBUG and kdebug kernels.
+     */
+
+    return retval;
+}
+
+void
+xbow_update_perf_counters(devfs_handle_t vhdl)
+{
+    xbow_soft_t             xbow_soft = xbow_soft_get(vhdl);
+    xbow_perf_t            *xbow_perf = xbow_soft->xbow_perfcnt;
+    xbow_perf_link_t       *xbow_plink = xbow_soft->xbow_perflink;
+    xbow_perfcount_t        perf_reg;
+    unsigned long           s;
+    int                     link, i;
+
+    for (i = 0; i < XBOW_PERF_COUNTERS; i++, xbow_perf++) {
+	if (xbow_perf->xp_mode == XBOW_MONITOR_NONE)
+	    continue;
+
+	s = mutex_spinlock(&xbow_soft->xbow_perf_lock);
+
+	perf_reg.xb_counter_val = *(xbowreg_t *) xbow_perf->xp_perf_reg;
+
+	link = perf_reg.xb_perf.link_select;
+
+	(xbow_plink + link)->xlp_cumulative[xbow_perf->xp_curmode] +=
+	    ((perf_reg.xb_perf.count - xbow_perf->xp_current) & XBOW_COUNTER_MASK);
+	xbow_perf->xp_current = perf_reg.xb_perf.count;
+
+	mutex_spinunlock(&xbow_soft->xbow_perf_lock, s);
+    }
+}
+
+xbow_perf_link_t       *
+xbow_get_perf_counters(devfs_handle_t vhdl)
+{
+    xbow_soft_t             xbow_soft = xbow_soft_get(vhdl);
+    xbow_perf_link_t       *xbow_perf_link = xbow_soft->xbow_perflink;
+
+    return xbow_perf_link;
+}
+
+int
+xbow_enable_perf_counter(devfs_handle_t vhdl, int link, int mode, int counter)
+{
+    xbow_soft_t             xbow_soft = xbow_soft_get(vhdl);
+    xbow_perf_t            *xbow_perf = xbow_soft->xbow_perfcnt;
+    xbow_linkctrl_t         xbow_link_ctrl;
+    xbow_t                 *xbow = xbow_soft->base;
+    xbow_perfcount_t        perf_reg;
+    unsigned long           s;
+    int                     i;
+
+    link -= BASE_XBOW_PORT;
+    if ((link < 0) || (link >= MAX_XBOW_PORTS))
+	return -1;
+
+    if ((mode < XBOW_MONITOR_NONE) || (mode > XBOW_MONITOR_DEST_LINK))
+	return -1;
+
+    if ((counter < 0) || (counter >= XBOW_PERF_COUNTERS))
+	return -1;
+
+    s = mutex_spinlock(&xbow_soft->xbow_perf_lock);
+
+    if ((xbow_perf + counter)->xp_mode && mode) {
+	mutex_spinunlock(&xbow_soft->xbow_perf_lock, s);
+	return -1;
+    }
+    for (i = 0; i < XBOW_PERF_COUNTERS; i++) {
+	if (i == counter)
+	    continue;
+	if (((xbow_perf + i)->xp_link == link) &&
+	    ((xbow_perf + i)->xp_mode)) {
+	    mutex_spinunlock(&xbow_soft->xbow_perf_lock, s);
+	    return -1;
+	}
+    }
+    xbow_perf += counter;
+
+    xbow_perf->xp_curlink = xbow_perf->xp_link = link;
+    xbow_perf->xp_curmode = xbow_perf->xp_mode = mode;
+
+    xbow_link_ctrl.xbl_ctrlword = xbow->xb_link_raw[link].link_control;
+    xbow_link_ctrl.xb_linkcontrol.perf_mode = mode;
+    xbow->xb_link_raw[link].link_control = xbow_link_ctrl.xbl_ctrlword;
+
+    perf_reg.xb_counter_val = *(xbowreg_t *) xbow_perf->xp_perf_reg;
+    perf_reg.xb_perf.link_select = link;
+    *(xbowreg_t *) xbow_perf->xp_perf_reg = perf_reg.xb_counter_val;
+    xbow_perf->xp_current = perf_reg.xb_perf.count;
+
+    mutex_spinunlock(&xbow_soft->xbow_perf_lock, s);
+    return 0;
+}
+
+xbow_link_status_t     *
+xbow_get_llp_status(devfs_handle_t vhdl)
+{
+    xbow_soft_t             xbow_soft = xbow_soft_get(vhdl);
+    xbow_link_status_t     *xbow_llp_status = xbow_soft->xbow_link_status;
+
+    return xbow_llp_status;
+}
+
+void
+xbow_update_llp_status(devfs_handle_t vhdl)
+{
+    xbow_soft_t             xbow_soft = xbow_soft_get(vhdl);
+    xbow_link_status_t     *xbow_llp_status = xbow_soft->xbow_link_status;
+    xbow_t                 *xbow;
+    xbwX_stat_t             lnk_sts;
+    xbow_aux_link_status_t  aux_sts;
+    int                     link;
+    devfs_handle_t	    xwidget_vhdl;
+    char		   *xwidget_name;	
+
+    xbow = (xbow_t *) xbow_soft->base;
+    for (link = 0; link < MAX_XBOW_PORTS; link++, xbow_llp_status++) {
+	/* Get the widget name corresponding the current link.
+	 * Note : 0 <= link < MAX_XBOW_PORTS(8).
+	 * 	  BASE_XBOW_PORT(0x8) <= xwidget number < MAX_PORT_NUM (0x10)
+	 */
+	xwidget_vhdl = xbow_widget_lookup(xbow_soft->busv,link+BASE_XBOW_PORT);
+	xwidget_name = xwidget_name_get(xwidget_vhdl);
+	aux_sts.aux_linkstatus
+	    = xbow->xb_link_raw[link].link_aux_status;
+	lnk_sts.linkstatus = xbow->xb_link_raw[link].link_status_clr;
+
+	if (lnk_sts.link_alive == 0)
+	    continue;
+
+	xbow_llp_status->rx_err_count +=
+	    aux_sts.xb_aux_linkstatus.rx_err_cnt;
+
+	xbow_llp_status->tx_retry_count +=
+	    aux_sts.xb_aux_linkstatus.tx_retry_cnt;
+
+	if (lnk_sts.linkstatus & ~(XB_STAT_RCV_ERR | XB_STAT_XMT_RTRY_ERR | XB_STAT_LINKALIVE)) {
+#ifdef	LATER
+	    printk(KERN_WARNING  "link %d[%s]: bad status 0x%x\n",
+		    link, xwidget_name, lnk_sts.linkstatus);
+#endif
+	}
+    }
+}
+
+int
+xbow_disable_llp_monitor(devfs_handle_t vhdl)
+{
+    xbow_soft_t             xbow_soft = xbow_soft_get(vhdl);
+    int                     port;
+
+    for (port = 0; port < MAX_XBOW_PORTS; port++) {
+	xbow_soft->xbow_link_status[port].rx_err_count = 0;
+	xbow_soft->xbow_link_status[port].tx_retry_count = 0;
+    }
+
+    xbow_soft->link_monitor = 0;
+    return 0;
+}
+
+int
+xbow_enable_llp_monitor(devfs_handle_t vhdl)
+{
+    xbow_soft_t             xbow_soft = xbow_soft_get(vhdl);
+
+    xbow_soft->link_monitor = 1;
+    return 0;
+}
+
+
+int
+xbow_reset_link(devfs_handle_t xconn_vhdl)
+{
+    xwidget_info_t          widget_info;
+    xwidgetnum_t            port;
+    xbow_t                 *xbow;
+    xbowreg_t               ctrl;
+    xbwX_stat_t             stat;
+    unsigned                itick;
+    unsigned                dtick;
+    static int              ticks_per_ms = 0;
+
+    if (!ticks_per_ms) {
+	itick = get_timestamp();
+	us_delay(1000);
+	ticks_per_ms = get_timestamp() - itick;
+    }
+    widget_info = xwidget_info_get(xconn_vhdl);
+    port = xwidget_info_id_get(widget_info);
+
+#ifdef XBOW_K1PTR			/* defined if we only have one xbow ... */
+    xbow = XBOW_K1PTR;
+#else
+    {
+	devfs_handle_t            xbow_vhdl;
+	xbow_soft_t             xbow_soft;
+
+	hwgraph_traverse(xconn_vhdl, ".master/xtalk/0/xbow", &xbow_vhdl);
+	xbow_soft = xbow_soft_get(xbow_vhdl);
+	xbow = xbow_soft->base;
+    }
+#endif
+
+    /*
+     * This requires three PIOs (reset the link, check for the
+     * reset, restore the control register for the link) plus
+     * 10us to wait for the reset. We allow up to 1ms for the
+     * widget to come out of reset before giving up and
+     * returning a failure.
+     */
+    ctrl = xbow->xb_link(port).link_control;
+    xbow->xb_link(port).link_reset = 0;
+    itick = get_timestamp();
+    while (1) {
+	stat.linkstatus = xbow->xb_link(port).link_status;
+	if (stat.link_alive)
+	    break;
+	dtick = get_timestamp() - itick;
+	if (dtick > ticks_per_ms) {
+	    return -1;			/* never came out of reset */
+	}
+	DELAY(2);			/* don't beat on link_status */
+    }
+    xbow->xb_link(port).link_control = ctrl;
+    return 0;
+}
+
+/*
+ * Dump xbow registers.
+ * input parameter is either a pointer to
+ * the xbow chip or the vertex handle for
+ * an xbow vertex.
+ */
+void
+idbg_xbowregs(int64_t regs)
+{
+    xbow_t                 *xbow;
+    int                     i;
+    xb_linkregs_t          *link;
+
+    xbow = (xbow_t *) regs;
+
+#ifdef LATER
+    qprintf("Printing xbow registers starting at 0x%x\n", xbow);
+    qprintf("wid %x status %x erruppr %x errlower %x control %x timeout %x\n",
+	    xbow->xb_wid_id, xbow->xb_wid_stat, xbow->xb_wid_err_upper,
+	    xbow->xb_wid_err_lower, xbow->xb_wid_control,
+	    xbow->xb_wid_req_timeout);
+    qprintf("intr uppr %x lower %x errcmd %x llp ctrl %x arb_reload %x\n",
+	    xbow->xb_wid_int_upper, xbow->xb_wid_int_lower,
+	    xbow->xb_wid_err_cmdword, xbow->xb_wid_llp,
+	    xbow->xb_wid_arb_reload);
+#endif
+
+    for (i = 8; i <= 0xf; i++) {
+	link = &xbow->xb_link(i);
+#ifdef LATER
+	qprintf("Link %d registers\n", i);
+	qprintf("\tctrl %x stat %x arbuppr %x arblowr %x auxstat %x\n",
+		link->link_control, link->link_status,
+		link->link_arb_upper, link->link_arb_lower,
+		link->link_aux_status);
+#endif
+    }
+}
+
+
+#define XBOW_ARB_RELOAD_TICKS		25
+					/* granularity: 4 MB/s, max: 124 MB/s */
+#define GRANULARITY			((100 * 1000000) / XBOW_ARB_RELOAD_TICKS)
+
+#define XBOW_BYTES_TO_GBR(BYTES_per_s)	(int) (BYTES_per_s / GRANULARITY)
+
+#define XBOW_GBR_TO_BYTES(cnt)		(bandwidth_t) ((cnt) * GRANULARITY)
+
+#define CEILING_BYTES_TO_GBR(gbr, bytes_per_sec)	\
+			((XBOW_GBR_TO_BYTES(gbr) < bytes_per_sec) ? gbr+1 : gbr)
+
+#define XBOW_ARB_GBR_MAX		31
+
+#define ABS(x)				((x > 0) ? (x) : (-1 * x))
+					/* absolute value */
+
+int
+xbow_bytes_to_gbr(bandwidth_t old_bytes_per_sec, bandwidth_t bytes_per_sec)
+{
+    int                     gbr_granted;
+    int                     new_total_gbr;
+    int                     change_gbr;
+    bandwidth_t             new_total_bw;
+
+#ifdef GRIO_DEBUG
+    printk("xbow_bytes_to_gbr: old_bytes_per_sec %lld bytes_per_sec %lld\n",
+		old_bytes_per_sec, bytes_per_sec);
+#endif	/* GRIO_DEBUG */
+
+    gbr_granted = CEILING_BYTES_TO_GBR((XBOW_BYTES_TO_GBR(old_bytes_per_sec)),
+			old_bytes_per_sec);
+    new_total_bw = old_bytes_per_sec + bytes_per_sec;
+    new_total_gbr = CEILING_BYTES_TO_GBR((XBOW_BYTES_TO_GBR(new_total_bw)),
+			new_total_bw);
+
+    change_gbr = new_total_gbr - gbr_granted;
+
+#ifdef GRIO_DEBUG
+    printk("xbow_bytes_to_gbr: gbr_granted %d new_total_gbr %d change_gbr %d\n",
+		gbr_granted, new_total_gbr, change_gbr);
+#endif	/* GRIO_DEBUG */
+
+    return (change_gbr);
+}
+
+/* Conversion from GBR to bytes */
+bandwidth_t
+xbow_gbr_to_bytes(int gbr)
+{
+    return (XBOW_GBR_TO_BYTES(gbr));
+}
+
+/* Given the vhdl for the desired xbow, the src and dest. widget ids
+ * and the req_bw value, this xbow driver entry point accesses the
+ * xbow registers and allocates the desired bandwidth if available.
+ *
+ * If bandwidth allocation is successful, return success else return failure.
+ */
+int
+xbow_prio_bw_alloc(devfs_handle_t vhdl,
+		xwidgetnum_t src_wid,
+		xwidgetnum_t dest_wid,
+		unsigned long long old_alloc_bw,
+		unsigned long long req_bw)
+{
+    xbow_soft_t             soft = xbow_soft_get(vhdl);
+    volatile xbowreg_t     *xreg;
+    xbowreg_t               mask;
+    unsigned long           s;
+    int                     error = 0;
+    bandwidth_t             old_bw_BYTES, req_bw_BYTES;
+    xbowreg_t               old_xreg;
+    int                     old_bw_GBR, req_bw_GBR, new_bw_GBR;
+
+#ifdef GRIO_DEBUG
+    printk("xbow_prio_bw_alloc: vhdl %d src_wid %d dest_wid %d req_bw %lld\n",
+		(int) vhdl, (int) src_wid, (int) dest_wid, req_bw);
+#endif
+
+    ASSERT(XBOW_WIDGET_IS_VALID(src_wid));
+    ASSERT(XBOW_WIDGET_IS_VALID(dest_wid));
+
+    s = mutex_spinlock(&soft->xbow_bw_alloc_lock);
+
+    /* Get pointer to the correct register */
+    xreg = XBOW_PRIO_ARBREG_PTR(soft->base, dest_wid, src_wid);
+
+    /* Get mask for GBR count value */
+    mask = XB_ARB_GBR_MSK << XB_ARB_GBR_SHFT(src_wid);
+
+    req_bw_GBR = xbow_bytes_to_gbr(old_alloc_bw, req_bw);
+    req_bw_BYTES = (req_bw_GBR < 0) ? (-1 * xbow_gbr_to_bytes(ABS(req_bw_GBR)))
+		: xbow_gbr_to_bytes(req_bw_GBR);
+
+#ifdef GRIO_DEBUG
+    printk("req_bw %lld req_bw_BYTES %lld req_bw_GBR %d\n",
+		req_bw, req_bw_BYTES, req_bw_GBR);
+#endif	/* GRIO_DEBUG */
+
+    old_bw_BYTES = soft->bw_cur_used[(int) dest_wid - MAX_XBOW_PORTS];
+    old_xreg = *xreg;
+    old_bw_GBR = (((*xreg) & mask) >> XB_ARB_GBR_SHFT(src_wid));
+
+#ifdef GRIO_DEBUG
+    ASSERT(XBOW_BYTES_TO_GBR(old_bw_BYTES) == old_bw_GBR);
+
+    printk("old_bw_BYTES %lld old_bw_GBR %d\n", old_bw_BYTES, old_bw_GBR);
+
+    printk("req_bw_BYTES %lld old_bw_BYTES %lld soft->bw_hiwm %lld\n",
+		req_bw_BYTES, old_bw_BYTES,
+		soft->bw_hiwm[(int) dest_wid - MAX_XBOW_PORTS]);
+	   
+#endif				/* GRIO_DEBUG */
+
+    /* Accept the request only if we don't exceed the destination
+     * port HIWATER_MARK *AND* the max. link GBR arbitration count
+     */
+    if (((old_bw_BYTES + req_bw_BYTES) <=
+		soft->bw_hiwm[(int) dest_wid - MAX_XBOW_PORTS]) &&
+		(req_bw_GBR + old_bw_GBR <= XBOW_ARB_GBR_MAX)) {
+
+	new_bw_GBR = (old_bw_GBR + req_bw_GBR);
+
+	/* Set this in the xbow link register */
+	*xreg = (old_xreg & ~mask) | \
+	    (new_bw_GBR << XB_ARB_GBR_SHFT(src_wid) & mask);
+
+	soft->bw_cur_used[(int) dest_wid - MAX_XBOW_PORTS] =
+			xbow_gbr_to_bytes(new_bw_GBR);
+    } else {
+	error = 1;
+    }
+
+    mutex_spinunlock(&soft->xbow_bw_alloc_lock, s);
+
+    return (error);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/sn2/xtalk.c linux-2.4.21-pre6/arch/ia64/sn/io/sn2/xtalk.c
--- linux-2.4.20/arch/ia64/sn/io/sn2/xtalk.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/sn2/xtalk.c	2003-03-26 23:49:39.000000000 +0000
@@ -0,0 +1,1087 @@
+/* $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) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <asm/sn/sgi.h>
+#include <asm/sn/driver.h>
+#include <asm/sn/io.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/labelcl.h>
+#include <asm/sn/hcl_util.h>
+#include <asm/sn/xtalk/xtalk.h>
+#include <asm/sn/xtalk/xswitch.h>
+#include <asm/sn/xtalk/xwidget.h>
+#include <asm/sn/xtalk/xtalk_private.h>
+
+/*
+ * Implement crosstalk provider operations.  The xtalk* layer provides a
+ * platform-independent interface for crosstalk devices.  This layer
+ * switches among the possible implementations of a crosstalk adapter.
+ *
+ * On platforms with only one possible xtalk provider, macros can be
+ * set up at the top that cause the table lookups and indirections to
+ * completely disappear.
+ */
+
+#define	NEW(ptr)	(ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL))
+#define	DEL(ptr)	(kfree(ptr))
+
+char                    widget_info_fingerprint[] = "widget_info";
+
+cdl_p                   xtalk_registry = NULL;
+
+#define	DEV_FUNC(dev,func)	hub_##func
+#define	CAST_PIOMAP(x)		((hub_piomap_t)(x))
+#define	CAST_DMAMAP(x)		((hub_dmamap_t)(x))
+#define	CAST_INTR(x)		((hub_intr_t)(x))
+
+/* =====================================================================
+ *            Function Table of Contents
+ */
+xtalk_piomap_t          xtalk_piomap_alloc(devfs_handle_t, device_desc_t, iopaddr_t, size_t, size_t, unsigned);
+void                    xtalk_piomap_free(xtalk_piomap_t);
+caddr_t                 xtalk_piomap_addr(xtalk_piomap_t, iopaddr_t, size_t);
+void                    xtalk_piomap_done(xtalk_piomap_t);
+caddr_t                 xtalk_piotrans_addr(devfs_handle_t, device_desc_t, iopaddr_t, size_t, unsigned);
+caddr_t                 xtalk_pio_addr(devfs_handle_t, device_desc_t, iopaddr_t, size_t, xtalk_piomap_t *, unsigned);
+void                    xtalk_set_early_piotrans_addr(xtalk_early_piotrans_addr_f *);
+caddr_t                 xtalk_early_piotrans_addr(xwidget_part_num_t, xwidget_mfg_num_t, int, iopaddr_t, size_t, unsigned);
+static caddr_t          null_xtalk_early_piotrans_addr(xwidget_part_num_t, xwidget_mfg_num_t, int, iopaddr_t, size_t, unsigned);
+xtalk_dmamap_t          xtalk_dmamap_alloc(devfs_handle_t, device_desc_t, size_t, unsigned);
+void                    xtalk_dmamap_free(xtalk_dmamap_t);
+iopaddr_t               xtalk_dmamap_addr(xtalk_dmamap_t, paddr_t, size_t);
+alenlist_t              xtalk_dmamap_list(xtalk_dmamap_t, alenlist_t, unsigned);
+void                    xtalk_dmamap_done(xtalk_dmamap_t);
+iopaddr_t               xtalk_dmatrans_addr(devfs_handle_t, device_desc_t, paddr_t, size_t, unsigned);
+alenlist_t              xtalk_dmatrans_list(devfs_handle_t, device_desc_t, alenlist_t, unsigned);
+void			xtalk_dmamap_drain(xtalk_dmamap_t);
+void			xtalk_dmaaddr_drain(devfs_handle_t, iopaddr_t, size_t);
+void			xtalk_dmalist_drain(devfs_handle_t, alenlist_t);
+xtalk_intr_t            xtalk_intr_alloc(devfs_handle_t, device_desc_t, devfs_handle_t);
+xtalk_intr_t            xtalk_intr_alloc_nothd(devfs_handle_t, device_desc_t, devfs_handle_t);
+void                    xtalk_intr_free(xtalk_intr_t);
+int                     xtalk_intr_connect(xtalk_intr_t, intr_func_t, intr_arg_t, xtalk_intr_setfunc_t, void *);
+void                    xtalk_intr_disconnect(xtalk_intr_t);
+devfs_handle_t            xtalk_intr_cpu_get(xtalk_intr_t);
+int                     xtalk_error_handler(devfs_handle_t, int, ioerror_mode_t, ioerror_t *);
+int                     xtalk_error_devenable(devfs_handle_t, int, int);
+void                    xtalk_provider_startup(devfs_handle_t);
+void                    xtalk_provider_shutdown(devfs_handle_t);
+devfs_handle_t            xtalk_intr_dev_get(xtalk_intr_t);
+xwidgetnum_t            xtalk_intr_target_get(xtalk_intr_t);
+xtalk_intr_vector_t     xtalk_intr_vector_get(xtalk_intr_t);
+iopaddr_t               xtalk_intr_addr_get(struct xtalk_intr_s *);
+void                   *xtalk_intr_sfarg_get(xtalk_intr_t);
+devfs_handle_t            xtalk_pio_dev_get(xtalk_piomap_t);
+xwidgetnum_t            xtalk_pio_target_get(xtalk_piomap_t);
+iopaddr_t               xtalk_pio_xtalk_addr_get(xtalk_piomap_t);
+ulong                   xtalk_pio_mapsz_get(xtalk_piomap_t);
+caddr_t                 xtalk_pio_kvaddr_get(xtalk_piomap_t);
+devfs_handle_t            xtalk_dma_dev_get(xtalk_dmamap_t);
+xwidgetnum_t            xtalk_dma_target_get(xtalk_dmamap_t);
+xwidget_info_t          xwidget_info_chk(devfs_handle_t);
+xwidget_info_t          xwidget_info_get(devfs_handle_t);
+void                    xwidget_info_set(devfs_handle_t, xwidget_info_t);
+devfs_handle_t            xwidget_info_dev_get(xwidget_info_t);
+xwidgetnum_t            xwidget_info_id_get(xwidget_info_t);
+devfs_handle_t            xwidget_info_master_get(xwidget_info_t);
+xwidgetnum_t            xwidget_info_masterid_get(xwidget_info_t);
+xwidget_part_num_t      xwidget_info_part_num_get(xwidget_info_t);
+xwidget_mfg_num_t       xwidget_info_mfg_num_get(xwidget_info_t);
+char 			*xwidget_info_name_get(xwidget_info_t);
+void                    xtalk_init(void);
+void                    xtalk_provider_register(devfs_handle_t, xtalk_provider_t *);
+void                    xtalk_provider_unregister(devfs_handle_t);
+xtalk_provider_t       *xtalk_provider_fns_get(devfs_handle_t);
+int                     xwidget_driver_register(xwidget_part_num_t, 
+						xwidget_mfg_num_t, 
+						char *, unsigned);
+void                    xwidget_driver_unregister(char *);
+int                     xwidget_register(xwidget_hwid_t, devfs_handle_t, 
+					 xwidgetnum_t, devfs_handle_t, 
+					 xwidgetnum_t, async_attach_t);
+int			xwidget_unregister(devfs_handle_t);
+void                    xwidget_reset(devfs_handle_t);
+char			*xwidget_name_get(devfs_handle_t);
+#if !defined(DEV_FUNC)
+/*
+ * There is more than one possible provider
+ * for this platform. We need to examine the
+ * master vertex of the current vertex for
+ * a provider function structure, and indirect
+ * through the appropriately named member.
+ */
+#define	DEV_FUNC(dev,func)	xwidget_to_provider_fns(dev)->func
+#define	CAST_PIOMAP(x)		((xtalk_piomap_t)(x))
+#define	CAST_DMAMAP(x)		((xtalk_dmamap_t)(x))
+#define	CAST_INTR(x)		((xtalk_intr_t)(x))
+
+static xtalk_provider_t *
+xwidget_to_provider_fns(devfs_handle_t xconn)
+{
+    xwidget_info_t          widget_info;
+    xtalk_provider_t       *provider_fns;
+
+    widget_info = xwidget_info_get(xconn);
+    ASSERT(widget_info != NULL);
+
+    provider_fns = xwidget_info_pops_get(widget_info);
+    ASSERT(provider_fns != NULL);
+
+    return (provider_fns);
+}
+#endif
+
+/*
+ * Many functions are not passed their vertex
+ * information directly; rather, they must
+ * dive through a resource map. These macros
+ * are available to coordinate this detail.
+ */
+#define	PIOMAP_FUNC(map,func)	DEV_FUNC(map->xp_dev,func)
+#define	DMAMAP_FUNC(map,func)	DEV_FUNC(map->xd_dev,func)
+#define	INTR_FUNC(intr,func)	DEV_FUNC(intr_hdl->xi_dev,func)
+
+/* =====================================================================
+ *                    PIO MANAGEMENT
+ *
+ *      For mapping system virtual address space to
+ *      xtalk space on a specified widget
+ */
+
+xtalk_piomap_t
+xtalk_piomap_alloc(devfs_handle_t dev,	/* set up mapping for this device */
+		   device_desc_t dev_desc,	/* device descriptor */
+		   iopaddr_t xtalk_addr,	/* map for this xtalk_addr range */
+		   size_t byte_count,
+		   size_t byte_count_max,	/* maximum size of a mapping */
+		   unsigned flags)
+{				/* defined in sys/pio.h */
+    return (xtalk_piomap_t) DEV_FUNC(dev, piomap_alloc)
+	(dev, dev_desc, xtalk_addr, byte_count, byte_count_max, flags);
+}
+
+
+void
+xtalk_piomap_free(xtalk_piomap_t xtalk_piomap)
+{
+    PIOMAP_FUNC(xtalk_piomap, piomap_free)
+	(CAST_PIOMAP(xtalk_piomap));
+}
+
+
+caddr_t
+xtalk_piomap_addr(xtalk_piomap_t xtalk_piomap,	/* mapping resources */
+		  iopaddr_t xtalk_addr,		/* map for this xtalk address */
+		  size_t byte_count)
+{				/* map this many bytes */
+    return PIOMAP_FUNC(xtalk_piomap, piomap_addr)
+	(CAST_PIOMAP(xtalk_piomap), xtalk_addr, byte_count);
+}
+
+
+void
+xtalk_piomap_done(xtalk_piomap_t xtalk_piomap)
+{
+    PIOMAP_FUNC(xtalk_piomap, piomap_done)
+	(CAST_PIOMAP(xtalk_piomap));
+}
+
+
+caddr_t
+xtalk_piotrans_addr(devfs_handle_t dev,	/* translate for this device */
+		    device_desc_t dev_desc,	/* device descriptor */
+		    iopaddr_t xtalk_addr,	/* Crosstalk address */
+		    size_t byte_count,	/* map this many bytes */
+		    unsigned flags)
+{				/* (currently unused) */
+    return DEV_FUNC(dev, piotrans_addr)
+	(dev, dev_desc, xtalk_addr, byte_count, flags);
+}
+
+caddr_t
+xtalk_pio_addr(devfs_handle_t dev,	/* translate for this device */
+	       device_desc_t dev_desc,	/* device descriptor */
+	       iopaddr_t addr,		/* starting address (or offset in window) */
+	       size_t byte_count,	/* map this many bytes */
+	       xtalk_piomap_t *mapp,	/* where to return the map pointer */
+	       unsigned flags)
+{					/* PIO flags */
+    xtalk_piomap_t          map = 0;
+    caddr_t                 res;
+
+    if (mapp)
+	*mapp = 0;			/* record "no map used" */
+
+    res = xtalk_piotrans_addr
+	(dev, dev_desc, addr, byte_count, flags);
+    if (res)
+	return res;			/* xtalk_piotrans worked */
+
+    map = xtalk_piomap_alloc
+	(dev, dev_desc, addr, byte_count, byte_count, flags);
+    if (!map)
+	return res;			/* xtalk_piomap_alloc failed */
+
+    res = xtalk_piomap_addr
+	(map, addr, byte_count);
+    if (!res) {
+	xtalk_piomap_free(map);
+	return res;			/* xtalk_piomap_addr failed */
+    }
+    if (mapp)
+	*mapp = map;			/* pass back map used */
+
+    return res;				/* xtalk_piomap_addr succeeded */
+}
+
+/* =====================================================================
+ *            EARLY PIOTRANS SUPPORT
+ *
+ *      There are places where drivers (mgras, for instance)
+ *      need to get PIO translations before the infrastructure
+ *      is extended to them (setting up textports, for
+ *      instance). These drivers should call
+ *      xtalk_early_piotrans_addr with their xtalk ID
+ *      information, a sequence number (so we can use the second
+ *      mgras for instance), and the usual piotrans parameters.
+ *
+ *      Machine specific code should provide an implementation
+ *      of early_piotrans_addr, and present a pointer to this
+ *      function to xtalk_set_early_piotrans_addr so it can be
+ *      used by clients without the clients having to know what
+ *      platform or what xtalk provider is in use.
+ */
+
+static xtalk_early_piotrans_addr_f null_xtalk_early_piotrans_addr;
+
+xtalk_early_piotrans_addr_f *impl_early_piotrans_addr = null_xtalk_early_piotrans_addr;
+
+/* xtalk_set_early_piotrans_addr:
+ * specify the early_piotrans_addr implementation function.
+ */
+void
+xtalk_set_early_piotrans_addr(xtalk_early_piotrans_addr_f *impl)
+{
+    impl_early_piotrans_addr = impl;
+}
+
+/* xtalk_early_piotrans_addr:
+ * figure out a PIO address for the "nth" crosstalk widget that
+ * matches the specified part and mfgr number. Returns NULL if
+ * there is no such widget, or if the requested mapping can not
+ * be constructed.
+ * Limitations on which crosstalk slots (and busses) are
+ * checked, and definitions of the ordering of the search across
+ * the crosstalk slots, are defined by the platform.
+ */
+caddr_t
+xtalk_early_piotrans_addr(xwidget_part_num_t part_num,
+			  xwidget_mfg_num_t mfg_num,
+			  int which,
+			  iopaddr_t xtalk_addr,
+			  size_t byte_count,
+			  unsigned flags)
+{
+    return impl_early_piotrans_addr
+	(part_num, mfg_num, which, xtalk_addr, byte_count, flags);
+}
+
+/* null_xtalk_early_piotrans_addr:
+ * used as the early_piotrans_addr implementation until and
+ * unless a real implementation is provided. In DEBUG kernels,
+ * we want to know who is calling before the implementation is
+ * registered; in non-DEBUG kernels, return NULL representing
+ * lack of mapping support.
+ */
+/*ARGSUSED */
+static caddr_t
+null_xtalk_early_piotrans_addr(xwidget_part_num_t part_num,
+			       xwidget_mfg_num_t mfg_num,
+			       int which,
+			       iopaddr_t xtalk_addr,
+			       size_t byte_count,
+			       unsigned flags)
+{
+#if DEBUG
+    PRINT_PANIC("null_xtalk_early_piotrans_addr");
+#endif
+    return NULL;
+}
+
+/* =====================================================================
+ *                    DMA MANAGEMENT
+ *
+ *      For mapping from crosstalk space to system
+ *      physical space.
+ */
+
+xtalk_dmamap_t
+xtalk_dmamap_alloc(devfs_handle_t dev,	/* set up mappings for this device */
+		   device_desc_t dev_desc,	/* device descriptor */
+		   size_t byte_count_max,	/* max size of a mapping */
+		   unsigned flags)
+{				/* defined in dma.h */
+    return (xtalk_dmamap_t) DEV_FUNC(dev, dmamap_alloc)
+	(dev, dev_desc, byte_count_max, flags);
+}
+
+
+void
+xtalk_dmamap_free(xtalk_dmamap_t xtalk_dmamap)
+{
+    DMAMAP_FUNC(xtalk_dmamap, dmamap_free)
+	(CAST_DMAMAP(xtalk_dmamap));
+}
+
+
+iopaddr_t
+xtalk_dmamap_addr(xtalk_dmamap_t xtalk_dmamap,	/* use these mapping resources */
+		  paddr_t paddr,	/* map for this address */
+		  size_t byte_count)
+{				/* map this many bytes */
+    return DMAMAP_FUNC(xtalk_dmamap, dmamap_addr)
+	(CAST_DMAMAP(xtalk_dmamap), paddr, byte_count);
+}
+
+
+alenlist_t
+xtalk_dmamap_list(xtalk_dmamap_t xtalk_dmamap,	/* use these mapping resources */
+		  alenlist_t alenlist,	/* map this Address/Length List */
+		  unsigned flags)
+{
+    return DMAMAP_FUNC(xtalk_dmamap, dmamap_list)
+	(CAST_DMAMAP(xtalk_dmamap), alenlist, flags);
+}
+
+
+void
+xtalk_dmamap_done(xtalk_dmamap_t xtalk_dmamap)
+{
+    DMAMAP_FUNC(xtalk_dmamap, dmamap_done)
+	(CAST_DMAMAP(xtalk_dmamap));
+}
+
+
+iopaddr_t
+xtalk_dmatrans_addr(devfs_handle_t dev,	/* translate for this device */
+		    device_desc_t dev_desc,	/* device descriptor */
+		    paddr_t paddr,	/* system physical address */
+		    size_t byte_count,	/* length */
+		    unsigned flags)
+{				/* defined in dma.h */
+    return DEV_FUNC(dev, dmatrans_addr)
+	(dev, dev_desc, paddr, byte_count, flags);
+}
+
+
+alenlist_t
+xtalk_dmatrans_list(devfs_handle_t dev,	/* translate for this device */
+		    device_desc_t dev_desc,	/* device descriptor */
+		    alenlist_t palenlist,	/* system address/length list */
+		    unsigned flags)
+{				/* defined in dma.h */
+    return DEV_FUNC(dev, dmatrans_list)
+	(dev, dev_desc, palenlist, flags);
+}
+
+void
+xtalk_dmamap_drain(xtalk_dmamap_t map)
+{
+    DMAMAP_FUNC(map, dmamap_drain)
+	(CAST_DMAMAP(map));
+}
+
+void
+xtalk_dmaaddr_drain(devfs_handle_t dev, paddr_t addr, size_t size)
+{
+    DEV_FUNC(dev, dmaaddr_drain)
+	(dev, addr, size);
+}
+
+void
+xtalk_dmalist_drain(devfs_handle_t dev, alenlist_t list)
+{
+    DEV_FUNC(dev, dmalist_drain)
+	(dev, list);
+}
+
+/* =====================================================================
+ *                    INTERRUPT MANAGEMENT
+ *
+ *      Allow crosstalk devices to establish interrupts
+ */
+
+/*
+ * Allocate resources required for an interrupt as specified in intr_desc.
+ * Return resource handle in intr_hdl.
+ */
+xtalk_intr_t
+xtalk_intr_alloc(devfs_handle_t dev,	/* which Crosstalk device */
+		 device_desc_t dev_desc,	/* device descriptor */
+		 devfs_handle_t owner_dev)
+{				/* owner of this interrupt */
+    return (xtalk_intr_t) DEV_FUNC(dev, intr_alloc)
+	(dev, dev_desc, owner_dev);
+}
+
+/*
+ * Allocate resources required for an interrupt as specified in dev_desc.
+ * Unconditionally setup resources to be non-threaded.
+ * Return resource handle in intr_hdl.
+ */
+xtalk_intr_t
+xtalk_intr_alloc_nothd(devfs_handle_t dev,	/* which Crosstalk device */
+		 	device_desc_t dev_desc,	/* device descriptor */
+		 	devfs_handle_t owner_dev)	/* owner of this interrupt */
+{
+    return (xtalk_intr_t) DEV_FUNC(dev, intr_alloc_nothd)
+	(dev, dev_desc, owner_dev);
+}
+
+/*
+ * Free resources consumed by intr_alloc.
+ */
+void
+xtalk_intr_free(xtalk_intr_t intr_hdl)
+{
+    INTR_FUNC(intr_hdl, intr_free)
+	(CAST_INTR(intr_hdl));
+}
+
+
+/*
+ * Associate resources allocated with a previous xtalk_intr_alloc call with the
+ * described handler, arg, name, etc.
+ *
+ * Returns 0 on success, returns <0 on failure.
+ */
+int
+xtalk_intr_connect(xtalk_intr_t intr_hdl,	/* xtalk intr resource handle */
+		   intr_func_t intr_func,       /* xtalk intr handler */
+		   intr_arg_t intr_arg,         /* arg to intr handler */
+		   xtalk_intr_setfunc_t setfunc,	/* func to set intr hw */
+		   void *setfunc_arg)	/* arg to setfunc */
+{
+    return INTR_FUNC(intr_hdl, intr_connect)
+	(CAST_INTR(intr_hdl), intr_func, intr_arg, setfunc, setfunc_arg);
+}
+
+
+/*
+ * Disassociate handler with the specified interrupt.
+ */
+void
+xtalk_intr_disconnect(xtalk_intr_t intr_hdl)
+{
+    INTR_FUNC(intr_hdl, intr_disconnect)
+	(CAST_INTR(intr_hdl));
+}
+
+
+/*
+ * Return a hwgraph vertex that represents the CPU currently
+ * targeted by an interrupt.
+ */
+devfs_handle_t
+xtalk_intr_cpu_get(xtalk_intr_t intr_hdl)
+{
+    return INTR_FUNC(intr_hdl, intr_cpu_get)
+	(CAST_INTR(intr_hdl));
+}
+
+
+/*
+ * =====================================================================
+ *                      ERROR MANAGEMENT
+ */
+
+/*
+ * xtalk_error_handler:
+ * pass this error on to the handler registered
+ * at the specified xtalk connecdtion point,
+ * or complain about it here if there is no handler.
+ *
+ * This routine plays two roles during error delivery
+ * to most widgets: first, the external agent (heart,
+ * hub, or whatever) calls in with the error and the
+ * connect point representing the crosstalk switch,
+ * or whatever crosstalk device is directly connected
+ * to the agent.
+ *
+ * If there is a switch, it will generally look at the
+ * widget number stashed in the ioerror structure; and,
+ * if the error came from some widget other than the
+ * switch, it will call back into xtalk_error_handler
+ * with the connection point of the offending port.
+ */
+int
+xtalk_error_handler(
+		       devfs_handle_t xconn,
+		       int error_code,
+		       ioerror_mode_t mode,
+		       ioerror_t *ioerror)
+{
+    xwidget_info_t          xwidget_info;
+
+    xwidget_info = xwidget_info_get(xconn);
+    /* Make sure that xwidget_info is a valid pointer before derefencing it.
+     * We could come in here during very early initialization. 
+     */
+    if (xwidget_info && xwidget_info->w_efunc)
+	return xwidget_info->w_efunc
+	    (xwidget_info->w_einfo,
+	     error_code, mode, ioerror);
+    /*
+     * no error handler registered for
+     * the offending port. it's not clear
+     * what needs to be done, but reporting
+     * it would be a good thing, unless it
+     * is a mode that requires nothing.
+     */
+    if ((mode == MODE_DEVPROBE) || (mode == MODE_DEVUSERERROR) ||
+	(mode == MODE_DEVREENABLE))
+	return IOERROR_HANDLED;
+
+#if defined(SUPPORT_PRINTING_V_FORMAT)
+    printk(KERN_WARNING "Xbow at %v encountered Fatal error", xconn);
+#else
+    printk(KERN_WARNING "Xbow at 0x%p encountered Fatal error", xconn);
+#endif
+    ioerror_dump("xtalk", error_code, mode, ioerror);
+
+    return IOERROR_UNHANDLED;
+}
+
+int
+xtalk_error_devenable(devfs_handle_t xconn_vhdl, int devnum, int error_code)
+{
+    return DEV_FUNC(xconn_vhdl, error_devenable) (xconn_vhdl, devnum, error_code);
+}
+
+
+/* =====================================================================
+ *                    CONFIGURATION MANAGEMENT
+ */
+
+/*
+ * Startup a crosstalk provider
+ */
+void
+xtalk_provider_startup(devfs_handle_t xtalk_provider)
+{
+    DEV_FUNC(xtalk_provider, provider_startup)
+	(xtalk_provider);
+}
+
+
+/*
+ * Shutdown a crosstalk provider
+ */
+void
+xtalk_provider_shutdown(devfs_handle_t xtalk_provider)
+{
+    DEV_FUNC(xtalk_provider, provider_shutdown)
+	(xtalk_provider);
+}
+
+/* 
+ * Enable a device on a xtalk widget 
+ */
+void
+xtalk_widgetdev_enable(devfs_handle_t xconn_vhdl, int devnum)
+{
+    DEV_FUNC(xconn_vhdl, widgetdev_enable) (xconn_vhdl, devnum);
+}
+
+/* 
+ * Shutdown a device on a xtalk widget 
+ */
+void
+xtalk_widgetdev_shutdown(devfs_handle_t xconn_vhdl, int devnum)
+{
+    DEV_FUNC(xconn_vhdl, widgetdev_shutdown) (xconn_vhdl, devnum);
+}
+
+int
+xtalk_dma_enabled(devfs_handle_t xconn_vhdl)
+{
+    return DEV_FUNC(xconn_vhdl, dma_enabled) (xconn_vhdl);
+}
+/*
+ * Generic crosstalk functions, for use with all crosstalk providers
+ * and all crosstalk devices.
+ */
+
+/****** Generic crosstalk interrupt interfaces ******/
+devfs_handle_t
+xtalk_intr_dev_get(xtalk_intr_t xtalk_intr)
+{
+    return (xtalk_intr->xi_dev);
+}
+
+xwidgetnum_t
+xtalk_intr_target_get(xtalk_intr_t xtalk_intr)
+{
+    return (xtalk_intr->xi_target);
+}
+
+xtalk_intr_vector_t
+xtalk_intr_vector_get(xtalk_intr_t xtalk_intr)
+{
+    return (xtalk_intr->xi_vector);
+}
+
+iopaddr_t
+xtalk_intr_addr_get(struct xtalk_intr_s *xtalk_intr)
+{
+    return (xtalk_intr->xi_addr);
+}
+
+void                   *
+xtalk_intr_sfarg_get(xtalk_intr_t xtalk_intr)
+{
+    return (xtalk_intr->xi_sfarg);
+}
+
+/****** Generic crosstalk pio interfaces ******/
+devfs_handle_t
+xtalk_pio_dev_get(xtalk_piomap_t xtalk_piomap)
+{
+    return (xtalk_piomap->xp_dev);
+}
+
+xwidgetnum_t
+xtalk_pio_target_get(xtalk_piomap_t xtalk_piomap)
+{
+    return (xtalk_piomap->xp_target);
+}
+
+iopaddr_t
+xtalk_pio_xtalk_addr_get(xtalk_piomap_t xtalk_piomap)
+{
+    return (xtalk_piomap->xp_xtalk_addr);
+}
+
+ulong
+xtalk_pio_mapsz_get(xtalk_piomap_t xtalk_piomap)
+{
+    return (xtalk_piomap->xp_mapsz);
+}
+
+caddr_t
+xtalk_pio_kvaddr_get(xtalk_piomap_t xtalk_piomap)
+{
+    return (xtalk_piomap->xp_kvaddr);
+}
+
+
+/****** Generic crosstalk dma interfaces ******/
+devfs_handle_t
+xtalk_dma_dev_get(xtalk_dmamap_t xtalk_dmamap)
+{
+    return (xtalk_dmamap->xd_dev);
+}
+
+xwidgetnum_t
+xtalk_dma_target_get(xtalk_dmamap_t xtalk_dmamap)
+{
+    return (xtalk_dmamap->xd_target);
+}
+
+
+/****** Generic crosstalk widget information interfaces ******/
+
+/* xwidget_info_chk:
+ * check to see if this vertex is a widget;
+ * if so, return its widget_info (if any).
+ * if not, return NULL.
+ */
+xwidget_info_t
+xwidget_info_chk(devfs_handle_t xwidget)
+{
+    arbitrary_info_t        ainfo = 0;
+
+    hwgraph_info_get_LBL(xwidget, INFO_LBL_XWIDGET, &ainfo);
+    return (xwidget_info_t) ainfo;
+}
+
+
+xwidget_info_t
+xwidget_info_get(devfs_handle_t xwidget)
+{
+    xwidget_info_t          widget_info;
+
+    widget_info = (xwidget_info_t)
+	hwgraph_fastinfo_get(xwidget);
+
+#ifdef	LATER
+    if ((widget_info != NULL) &&
+	(widget_info->w_fingerprint != widget_info_fingerprint))
+#ifdef SUPPORT_PRINTING_V_FORMAT
+	PRINT_PANIC("%v bad xwidget_info", xwidget);
+#else
+	PRINT_PANIC("%x bad xwidget_info", xwidget);
+#endif
+#endif	/* LATER */
+
+    return (widget_info);
+}
+
+void
+xwidget_info_set(devfs_handle_t xwidget, xwidget_info_t widget_info)
+{
+    if (widget_info != NULL)
+	widget_info->w_fingerprint = widget_info_fingerprint;
+
+    hwgraph_fastinfo_set(xwidget, (arbitrary_info_t) widget_info);
+
+    /* Also, mark this vertex as an xwidget,
+     * and use the widget_info, so xwidget_info_chk
+     * can work (and be fairly efficient).
+     */
+    hwgraph_info_add_LBL(xwidget, INFO_LBL_XWIDGET,
+			 (arbitrary_info_t) widget_info);
+}
+
+devfs_handle_t
+xwidget_info_dev_get(xwidget_info_t xwidget_info)
+{
+    if (xwidget_info == NULL)
+	panic("null xwidget_info");
+    return (xwidget_info->w_vertex);
+}
+
+xwidgetnum_t
+xwidget_info_id_get(xwidget_info_t xwidget_info)
+{
+    if (xwidget_info == NULL)
+	panic("null xwidget_info");
+    return (xwidget_info->w_id);
+}
+
+
+devfs_handle_t
+xwidget_info_master_get(xwidget_info_t xwidget_info)
+{
+    if (xwidget_info == NULL)
+	panic("null xwidget_info");
+    return (xwidget_info->w_master);
+}
+
+xwidgetnum_t
+xwidget_info_masterid_get(xwidget_info_t xwidget_info)
+{
+    if (xwidget_info == NULL)
+	panic("null xwidget_info");
+    return (xwidget_info->w_masterid);
+}
+
+xwidget_part_num_t
+xwidget_info_part_num_get(xwidget_info_t xwidget_info)
+{
+    if (xwidget_info == NULL)
+	panic("null xwidget_info");
+    return (xwidget_info->w_hwid.part_num);
+}
+
+xwidget_mfg_num_t
+xwidget_info_mfg_num_get(xwidget_info_t xwidget_info)
+{
+    if (xwidget_info == NULL)
+	panic("null xwidget_info");
+    return (xwidget_info->w_hwid.mfg_num);
+}
+/* Extract the widget name from the widget information
+ * for the xtalk widget.
+ */
+char *
+xwidget_info_name_get(xwidget_info_t xwidget_info)
+{
+    if (xwidget_info == NULL)
+	panic("null xwidget info");
+    return(xwidget_info->w_name);
+}
+/****** Generic crosstalk initialization interfaces ******/
+
+/*
+ * One-time initialization needed for systems that support crosstalk.
+ */
+void
+xtalk_init(void)
+{
+    cdl_p                   cp;
+
+#if DEBUG && ATTACH_DEBUG
+    printf("xtalk_init\n");
+#endif
+    /* Allocate the registry.
+     * We might already have one.
+     * If we don't, go get one.
+     * MPness: someone might have
+     * set one up for us while we
+     * were not looking; use an atomic
+     * compare-and-swap to commit to
+     * using the new registry if and
+     * only if nobody else did first.
+     * If someone did get there first,
+     * toss the one we allocated back
+     * into the pool.
+     */
+    if (xtalk_registry == NULL) {
+	cp = cdl_new(EDGE_LBL_XIO, "part", "mfgr");
+	if (!compare_and_swap_ptr((void **) &xtalk_registry, NULL, (void *) cp)) {
+	    cdl_del(cp);
+	}
+    }
+    ASSERT(xtalk_registry != NULL);
+}
+
+/*
+ * Associate a set of xtalk_provider functions with a vertex.
+ */
+void
+xtalk_provider_register(devfs_handle_t provider, xtalk_provider_t *xtalk_fns)
+{
+    hwgraph_fastinfo_set(provider, (arbitrary_info_t) xtalk_fns);
+}
+
+/*
+ * Disassociate a set of xtalk_provider functions with a vertex.
+ */
+void
+xtalk_provider_unregister(devfs_handle_t provider)
+{
+    hwgraph_fastinfo_set(provider, (arbitrary_info_t)NULL);
+}
+
+/*
+ * Obtain a pointer to the xtalk_provider functions for a specified Crosstalk
+ * provider.
+ */
+xtalk_provider_t       *
+xtalk_provider_fns_get(devfs_handle_t provider)
+{
+    return ((xtalk_provider_t *) hwgraph_fastinfo_get(provider));
+}
+
+/*
+ * Announce a driver for a particular crosstalk part.
+ * Returns 0 on success or -1 on failure.  Failure occurs if the
+ * specified hardware already has a driver.
+ */
+/*ARGSUSED4 */
+int
+xwidget_driver_register(xwidget_part_num_t part_num,
+			xwidget_mfg_num_t mfg_num,
+			char *driver_prefix,
+			unsigned flags)
+{
+    /* a driver's init routine could call
+     * xwidget_driver_register before the
+     * system calls xtalk_init; so, we
+     * make the call here.
+     */
+    if (xtalk_registry == NULL)
+	xtalk_init();
+
+    return cdl_add_driver(xtalk_registry,
+			  part_num, mfg_num,
+			  driver_prefix, flags, NULL);
+}
+
+/*
+ * Inform xtalk infrastructure that a driver is no longer available for
+ * handling any widgets.
+ */
+void
+xwidget_driver_unregister(char *driver_prefix)
+{
+    /* before a driver calls unregister,
+     * it must have called registger; so we
+     * can assume we have a registry here.
+     */
+    ASSERT(xtalk_registry != NULL);
+
+    cdl_del_driver(xtalk_registry, driver_prefix, NULL);
+}
+
+/*
+ * Call some function with each vertex that
+ * might be one of this driver's attach points.
+ */
+void
+xtalk_iterate(char *driver_prefix,
+	      xtalk_iter_f *func)
+{
+    ASSERT(xtalk_registry != NULL);
+
+    cdl_iterate(xtalk_registry, driver_prefix, (cdl_iter_f *)func);
+}
+
+/*
+ * xwidget_register:
+ *	Register a xtalk device (xwidget) by doing the following.
+ *      -allocate and initialize xwidget_info data
+ *      -allocate a hwgraph vertex with name based on widget number (id)
+ *      -look up the widget's initialization function and call it,
+ *      or remember the vertex for later initialization.
+ *
+ */
+int
+xwidget_register(xwidget_hwid_t hwid,		/* widget's hardware ID */
+		 devfs_handle_t 	widget,		/* widget to initialize */
+		 xwidgetnum_t 	id,		/* widget's target id (0..f) */
+		 devfs_handle_t 	master,		/* widget's master vertex */
+		 xwidgetnum_t 	targetid,	/* master's target id (9/a) */
+		 async_attach_t aa)
+{			
+    xwidget_info_t          widget_info;
+    char		    *s,devnm[MAXDEVNAME];
+
+    /* Allocate widget_info and associate it with widget vertex */
+    NEW(widget_info);
+
+    /* Initialize widget_info */
+    widget_info->w_vertex = widget;
+    widget_info->w_id = id;
+    widget_info->w_master = master;
+    widget_info->w_masterid = targetid;
+    widget_info->w_hwid = *hwid;	/* structure copy */
+    widget_info->w_efunc = 0;
+    widget_info->w_einfo = 0;
+    /*
+     * get the name of this xwidget vertex and keep the info.
+     * This is needed during errors and interupts, but as
+     * long as we have it, we can use it elsewhere.
+     */
+    s = dev_to_name(widget,devnm,MAXDEVNAME);
+    widget_info->w_name = kmalloc(strlen(s) + 1, GFP_KERNEL);
+    strcpy(widget_info->w_name,s);
+    
+    xwidget_info_set(widget, widget_info);
+
+    device_master_set(widget, master);
+
+    /* All the driver init routines (including
+     * xtalk_init) are called before we get into
+     * attaching devices, so we can assume we
+     * have a registry here.
+     */
+    ASSERT(xtalk_registry != NULL);
+
+    /* 
+     * Add pointer to async attach info -- tear down will be done when
+     * the particular descendant is done with the info.
+     */
+    if (aa)
+	    async_attach_add_info(widget, aa);
+
+    return cdl_add_connpt(xtalk_registry, hwid->part_num, hwid->mfg_num,
+                          widget, 0);
+}
+
+/*
+ * xwidget_unregister :
+ *	Unregister the xtalk device and detach all its hwgraph namespace.
+ */
+int
+xwidget_unregister(devfs_handle_t widget)
+{
+    xwidget_info_t	widget_info;
+    xwidget_hwid_t	hwid;
+
+    /* Make sure that we have valid widget information initialized */
+    if (!(widget_info = xwidget_info_get(widget)))
+	return(1);
+
+    /* Remove the inventory information associated
+     * with the widget.
+     */
+    hwgraph_inventory_remove(widget, -1, -1, -1, -1, -1);
+    
+    hwid = &(widget_info->w_hwid);
+
+    cdl_del_connpt(xtalk_registry, hwid->part_num, hwid->mfg_num,
+                   widget, 0);
+
+    /* Clean out the xwidget information */
+    (void)kfree(widget_info->w_name);
+    BZERO((void *)widget_info, sizeof(widget_info));
+    DEL(widget_info);
+    
+    return(0);
+}
+
+void
+xwidget_error_register(devfs_handle_t xwidget,
+		       error_handler_f *efunc,
+		       error_handler_arg_t einfo)
+{
+    xwidget_info_t          xwidget_info;
+
+    xwidget_info = xwidget_info_get(xwidget);
+    ASSERT(xwidget_info != NULL);
+    xwidget_info->w_efunc = efunc;
+    xwidget_info->w_einfo = einfo;
+}
+
+/*
+ * Issue a link reset to a widget.
+ */
+void
+xwidget_reset(devfs_handle_t xwidget)
+{
+    xswitch_reset_link(xwidget);
+
+}
+
+
+void
+xwidget_gfx_reset(devfs_handle_t xwidget)
+{
+    xwidget_info_t info;
+
+    xswitch_reset_link(xwidget);
+    info = xwidget_info_get(xwidget);
+#ifdef LATER
+    ASSERT_ALWAYS(info != NULL);
+#endif
+
+    /*
+     * Enable this for other architectures once we add widget_reset to the
+     * xtalk provider interface.
+     */
+    DEV_FUNC(xtalk_provider, widget_reset)
+	(xwidget_info_master_get(info), xwidget_info_id_get(info));
+}
+
+#define ANON_XWIDGET_NAME	"No Name"	/* Default Widget Name */
+
+/* Get the canonical hwgraph  name of xtalk widget */
+char *
+xwidget_name_get(devfs_handle_t xwidget_vhdl)
+{
+	xwidget_info_t  info;
+
+	/* If we have a bogus widget handle then return
+	 * a default anonymous widget name.
+	 */
+	if (xwidget_vhdl == GRAPH_VERTEX_NONE)
+	    return(ANON_XWIDGET_NAME);
+	/* Read the widget name stored in the widget info
+	 * for the widget setup during widget initialization.
+	 */
+	info = xwidget_info_get(xwidget_vhdl);
+	ASSERT(info != NULL);
+	return(xwidget_info_name_get(info));
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/stubs.c linux-2.4.21-pre6/arch/ia64/sn/io/stubs.c
--- linux-2.4.20/arch/ia64/sn/io/stubs.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/stubs.c	2003-03-26 23:49:53.000000000 +0000
@@ -28,8 +28,8 @@
 
 int pcibr_prefetch_enable_rev, pcibr_wg_enable_rev;
 int default_intr_pri;
-int force_fire_and_forget;
-int ignore_conveyor_override;
+int force_fire_and_forget = 1;
+int ignore_conveyor_override = 0;
 
 devfs_handle_t dummy_vrtx;	/* Needed for cpuid_to_vertex() in hack.h */
 
@@ -53,36 +53,6 @@
 	return(0);
 }
 
-char *
-nic_bridge_vertex_info(devfs_handle_t v, nic_data_t mcr)
-{
-	FIXME("nic_bridge_vertex_info : returns NULL");
-	return((char *)0);
-}
-
-void *
-snia_kmem_alloc_node(register size_t size, register int flags, cnodeid_t node)
-{
-        /* Allocates on node 'node' */
-	FIXME("snia_kmem_alloc_node : use kmalloc");
-	return(kmalloc(size, GFP_KERNEL));
-}
-
-void *
-snia_kmem_zalloc_node(register size_t size, register int flags, cnodeid_t node)
-{
-	FIXME("snia_kmem_zalloc_node : use kmalloc");
-	return(kmalloc(size, GFP_KERNEL));
-}
-
-void
-snia_kmem_free(void *where, int size)
-{
-	FIXME("snia_kmem_free : use kfree");
-	return(kfree(where));
-}
-
-
 void *
 snia_kmem_zone_alloc(register zone_t *zone, int flags)
 {
@@ -115,13 +85,6 @@
 		return(0);
 }
 
-void *
-swap_ptr(void **loc, void *new)
-{
-	FIXME("swap_ptr : returns null");
-	return((void *)0);
-}
-
 /* For ml/SN/SN1/slots.c */
 /* ARGSUSED */
 slotid_t get_widget_slotnum(int xbow, int widget)
@@ -153,10 +116,8 @@
 char *
 nic_vertex_info_get(devfs_handle_t v)
 {
-
 	FIXME("nic_vertex_info_get\n");
 	return(NULL);
-
 }
 
 int
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/io/xswitch.c linux-2.4.21-pre6/arch/ia64/sn/io/xswitch.c
--- linux-2.4.20/arch/ia64/sn/io/xswitch.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/io/xswitch.c	2003-03-26 23:49:15.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (c) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 
 #include <linux/types.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/kernel/Makefile linux-2.4.21-pre6/arch/ia64/sn/kernel/Makefile
--- linux-2.4.20/arch/ia64/sn/kernel/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/kernel/Makefile	2003-03-26 23:49:18.000000000 +0000
@@ -1,4 +1,4 @@
-# arch/ia64/sn/Makefile
+# arch/ia64/sn/kernel/Makefile
 #
 # Copyright (C) 1999,2001-2002 Silicon Graphics, Inc.  All Rights Reserved.
 #
@@ -40,9 +40,7 @@
 
 O_TARGET        = sn.o
 
-ifeq ($(CONFIG_MODULES),y)
-export-objs = sn_ksyms.o
-endif
+export-objs = sn_ksyms.o iomv.o
 
 subdir-$(CONFIG_IA64_SGI_SN1)	= sn1
 subdir-$(CONFIG_IA64_SGI_SN2)	= sn2
@@ -51,12 +49,12 @@
 obj-$(CONFIG_IA64_SGI_SN1)      += irq.o mca.o
 obj-$(CONFIG_IA64_SGI_SN2)      += irq.o mca.o
 
-obj-$(CONFIG_IA64_SGI_SN1)      += sn1/sn1.a  
-obj-$(CONFIG_IA64_SGI_SN2)      += sn2/sn2.a  
+obj-$(CONFIG_IA64_SGI_SN1)      += sn1/sn1.o  
+obj-$(CONFIG_IA64_SGI_SN2)      += sn2/sn2.o  
 
 obj-$(CONFIG_IA64_SGI_AUTOTEST) += llsc4.o misctest.o
 obj-$(CONFIG_IA64_GENERIC)      += machvec.o
 obj-$(CONFIG_MODULES)           += sn_ksyms.o
-
+obj-$(CONFIG_IA64_SGI_SN_BRT)	+= bte_regr_test.o
 
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/kernel/bte.c linux-2.4.21-pre6/arch/ia64/sn/kernel/bte.c
--- linux-2.4.20/arch/ia64/sn/kernel/bte.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/kernel/bte.c	2003-03-26 23:48:57.000000000 +0000
@@ -1,16 +1,46 @@
 /*
- * 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-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify it 
+ * under the terms of version 2 of the GNU General Public License 
+ * as published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope that it would be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
+ * 
+ * Further, this software is distributed without any warranty that it is 
+ * free of the rightful claim of any third person regarding infringement 
+ * or the like.  Any license provided herein, whether implied or 
+ * otherwise, applies only to this software file.  Patent licenses, if 
+ * any, provided herein do not apply to combinations of this program with 
+ * other software, or any other product whatsoever.
  * 
- * Copyright (c) 2001-2002 Silicon Graphics, Inc.  All rights reserved.
+ * You should have received a copy of the GNU General Public 
+ * License along with this program; if not, write the Free Software 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ * 
+ * Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, 
+ * Mountain View, CA  94043, or:
+ * 
+ * http://www.sgi.com 
+ * 
+ * For further information regarding this notice, see: 
+ * 
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan
  */
 
+#include <linux/config.h>
 #include <asm/sn/nodepda.h>
 #include <asm/sn/addrs.h>
 #include <asm/sn/arch.h>
 #include <asm/sn/sn_cpuid.h>
 #include <asm/sn/pda.h>
+#ifdef CONFIG_IA64_SGI_SN2
+#include <asm/sn/sn2/shubio.h>
+#endif
 #include <asm/nodedata.h>
 
 #include <linux/bootmem.h>
@@ -22,29 +52,20 @@
 int bte_offsets[] = { IIO_IBLS0, IIO_IBLS1 };
 
 /*
- * bte_init_node(nodepda, cnode, cmdline_p)
+ * bte_init_node(nodepda, cnode)
  *
  * Initialize the nodepda structure with BTE base addresses and
  * spinlocks.
  *
+ * NOTE: The kernel parameter btetest will cause the initialization
+ * code to reserve blocks of physically contiguous memory to be
+ * used by the bte test module.
  */
 void
-bte_init_node(nodepda_t * mynodepda, cnodeid_t cnode, char **cmdline_p)
+bte_init_node(nodepda_t * mynodepda, cnodeid_t cnode)
 {
-	int bteTestMode = 0;
-	int cmdoffset = 0;
 	int i;
 
-#ifdef ZZZ
-	if (!cmdoffset) {
-		for (;cmdline_p[cmdoffset]; cmdoffset++) {
-			if (strstr(cmdline_p[cmdoffset], "btetest")) {
-				bteTestMode = 1;
-				break;
-			}
-		}
-	}
-#endif
 
 	/*
 	 * Indicate that all the block transfer engines on this node
@@ -53,32 +74,76 @@
 	for (i = 0; i < BTES_PER_NODE; i++) {
 #ifdef CONFIG_IA64_SGI_SN2
 		/* >>> Don't know why the 0x1800000L is here.  Robin */
-		mynodepda->node_bte_info[i].bte_base_addr =
+		mynodepda->bte_if[i].bte_base_addr =
 		    (char *)LOCAL_MMR_ADDR(bte_offsets[i] | 0x1800000L);
+
 #elif CONFIG_IA64_SGI_SN1
-		mynodepda->node_bte_info[i].bte_base_addr =
+		mynodepda->bte_if[i].bte_base_addr =
 		    (char *)LOCAL_HUB_ADDR(bte_offsets[i]);
 #else
 #error BTE Not defined for this hardware platform.
 #endif
 
+		/*
+		 * Initialize the notification and spinlock
+		 * so the first transfer can occur.
+		 */
+		mynodepda->bte_if[i].most_rcnt_na =
+		    &(mynodepda->bte_if[i].notify);
+		mynodepda->bte_if[i].notify = 0L;
 #ifdef CONFIG_IA64_SGI_BTE_LOCKING
-		/* Initialize the notification and spinlock */
-		/* so the first transfer can occur. */
-		mynodepda->node_bte_info[i].mostRecentNotification =
-		    &(mynodepda->node_bte_info[i].notify);
-		mynodepda->node_bte_info[i].notify = 0L;
-		spin_lock_init(&mynodepda->node_bte_info[i].spinlock);
+		spin_lock_init(&mynodepda->bte_if[i].spinlock);
 #endif				/* CONFIG_IA64_SGI_BTE_LOCKING */
 
-		if (bteTestMode) {
-			mynodepda->node_bte_info[i].bteTestBuf =
-				alloc_bootmem_node(NODE_DATA(cnode),
-						   BTE_MAX_XFER);
-		}
+		mynodepda->bte_if[i].bte_test_buf =
+			alloc_bootmem_node(NODE_DATA(cnode), BTE_MAX_XFER);
+	}
+
+}
+
+
+/*
+ * bte_reset_nasid(nasid_t)
+ *
+ * Does a soft reset of the BTEs on the specified nasid.
+ * This is followed by a one-line transfer from each of the
+ * virtual interfaces.
+ */
+void
+bte_reset_nasid(nasid_t n)
+{
+	ii_ibcr_u_t	ibcr;
+
+	ibcr.ii_ibcr_regval  = REMOTE_HUB_L(n, IIO_IBCR);
+	ibcr.ii_ibcr_fld_s.i_soft_reset = 1;
+	REMOTE_HUB_S(n, IIO_IBCR, ibcr.ii_ibcr_regval);
+
+	/* One line transfer on virtual interface 0 */
+	REMOTE_HUB_S(n, IIO_IBLS_0, IBLS_BUSY | 1);
+	REMOTE_HUB_S(n, IIO_IBSA_0, TO_PHYS(__pa(&nodepda->bte_cleanup)));
+	REMOTE_HUB_S(n, IIO_IBDA_0,
+		     TO_PHYS(__pa(&nodepda->bte_cleanup[4*L1_CACHE_BYTES])));
+	REMOTE_HUB_S(n, IIO_IBNA_0,
+		     TO_PHYS(__pa(&nodepda->bte_cleanup[4*L1_CACHE_BYTES])));
+	REMOTE_HUB_S(n, IIO_IBCT_0, BTE_NOTIFY);
+	while (REMOTE_HUB_L(n, IIO_IBLS0)) {
+		/* >>> Need some way out in case of hang... */
+	}
+
+	/* One line transfer on virtual interface 1 */
+	REMOTE_HUB_S(n, IIO_IBLS_1, IBLS_BUSY | 1);
+	REMOTE_HUB_S(n, IIO_IBSA_1, TO_PHYS(__pa(nodepda->bte_cleanup)));
+	REMOTE_HUB_S(n, IIO_IBDA_1,
+		     TO_PHYS(__pa(nodepda->bte_cleanup[4 * L1_CACHE_BYTES])));
+	REMOTE_HUB_S(n, IIO_IBNA_1,
+		     TO_PHYS(__pa(nodepda->bte_cleanup[5 * L1_CACHE_BYTES])));
+	REMOTE_HUB_S(n, IIO_IBCT_1, BTE_NOTIFY);
+	while (REMOTE_HUB_L(n, IIO_IBLS1)) {
+		/* >>> Need some way out in case of hang... */
 	}
 }
 
+
 /*
  * bte_init_cpu()
  *
@@ -91,11 +156,11 @@
 {
 	/* Called by setup.c as each cpu is being added to the nodepda */
 	if (local_node_data->active_cpu_count & 0x1) {
-		pda.cpubte[0] = &(nodepda->node_bte_info[0]);
-		pda.cpubte[1] = &(nodepda->node_bte_info[1]);
+		pda.cpu_bte_if[0] = &(nodepda->bte_if[0]);
+		pda.cpu_bte_if[1] = &(nodepda->bte_if[1]);
 	} else {
-		pda.cpubte[0] = &(nodepda->node_bte_info[1]);
-		pda.cpubte[1] = &(nodepda->node_bte_info[0]);
+		pda.cpu_bte_if[0] = &(nodepda->bte_if[1]);
+		pda.cpu_bte_if[1] = &(nodepda->bte_if[0]);
 	}
 }
 
@@ -112,14 +177,12 @@
  *   len - number of bytes to transfer from source to dest.
  *   mode - hardware defined.  See reference information
  *          for IBCT0/1 in the SGI documentation.
- *   bteBlock - kernel virtual address of a temporary
- *              buffer used during unaligned transfers.
  *
  * NOTE: If the source, dest, and len are all cache line aligned,
  * then it would be _FAR_ preferrable to use bte_copy instead.
  */
 bte_result_t
-bte_unaligned_copy(u64 src, u64 dest, u64 len, u64 mode, char *bteBlock)
+bte_unaligned_copy(u64 src, u64 dest, u64 len, u64 mode)
 {
 	int destFirstCacheOffset;
 	u64 headBteSource;
@@ -132,11 +195,19 @@
 	u64 footBcopyDest;
 	u64 footBcopyLen;
 	bte_result_t rv;
+	char *bteBlock;
 
 	if (len == 0) {
 		return (BTE_SUCCESS);
 	}
 
+#ifdef CONFIG_IA64_SGI_BTE_LOCKING
+#error bte_unaligned_copy() assumes single BTE selection in bte_copy().
+#else
+	/* temporary buffer used during unaligned transfers */
+	bteBlock = pda.cpu_bte_if[0]->bte_test_buf;
+#endif
+
 	headBcopySrcOffset = src & L1_CACHE_MASK;
 	destFirstCacheOffset = dest & L1_CACHE_MASK;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/kernel/bte_regr_test.c linux-2.4.21-pre6/arch/ia64/sn/kernel/bte_regr_test.c
--- linux-2.4.20/arch/ia64/sn/kernel/bte_regr_test.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/kernel/bte_regr_test.c	2003-03-26 23:49:55.000000000 +0000
@@ -0,0 +1,1062 @@
+/*
+ *
+ *
+ * Copyright (c) 2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify it 
+ * under the terms of version 2 of the GNU General Public License 
+ * as published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope that it would be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
+ * 
+ * Further, this software is distributed without any warranty that it is 
+ * free of the rightful claim of any third person regarding infringement 
+ * or the like.  Any license provided herein, whether implied or 
+ * otherwise, applies only to this software file.  Patent licenses, if 
+ * any, provided herein do not apply to combinations of this program with 
+ * other software, or any other product whatsoever.
+ * 
+ * You should have received a copy of the GNU General Public 
+ * License along with this program; if not, write the Free Software 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ * 
+ * Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, 
+ * Mountain View, CA  94043, or:
+ * 
+ * http://www.sgi.com 
+ * 
+ * For further information regarding this notice, see: 
+ * 
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan
+ */
+
+
+/***********************************************************************
+ * Block Transfer Engine regression tests.
+ *
+ *	The following set of tests can be used to test for regressions.
+ *	It is implemented as a loadable module.
+ *
+ *	To enable the tests, the kernel must be booted with the
+ *	"btetest" command line flag.  If the tests are compiled into the
+ *	kernel, additional values may be passed with
+ *	"bte_test=t,v,ht,tn,tx,ti,ta,tc"
+ *	where:
+ *	    t = Bitmask of tests to run.
+ *	    v = Level of verbosity.
+ *	    ht = Number of seconds to try to force a notification hang.
+ *          hu = Number of uSecs to wait until warning of hang.
+ *	    tn = Min number of lines to rate test with (2 raised to).
+ *	    tx = Max number of lines to rate test with (2 raised to).
+ *	    ti = Number of iterations per timing.
+ *          ta = Aternate through cpus on each pass.
+ *	    tc = Use/Don't Use memcopy
+ *
+ *	When loaded as a module, each of those values has a seperate
+ *	parameter.  Just do a modinfo bte_test.o to get those names
+ *	and valid ranges.
+ *
+ *	Tests are performed in the following order.
+ *
+ *	Standard Transfer Test - Just transfers a block of initialized
+ *	data to a cleared block and ensures that memory before and after
+ *	is untouched, but that the body has all the correct values.
+ *
+ *	Transfer Rate Test - Data is transfered from node to node
+ *	to ensure every node is able to BTE data.  Timings are created
+ *	for each node.
+ *
+ *	Notification Hang Test - Attempts to force the Notification
+ *	hang problem to arise.  A hang occurs when the BTE fails
+ *	to invalidate a processors cache line for the notification
+ *	word, resulting in the processor not seeing the updated
+ *	value.
+ *
+ *	Invalid Transfer Test - In this test, we attempt to transfer
+ *	data from a valid address to a nasid which does not exist.
+ *
+ **********************************************************************/
+
+
+#define BTE_TIME 1		/* Needed to ensure bte_copy records
+				 * timings */
+// #define BTE_DEBUG
+// #define BTE_DEBUG_VERBOSE
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <asm/sn/nodepda.h>
+#include <asm/processor.h>
+
+#include <asm/sn/bte_copy.h>
+
+
+/***********************************************************************
+ * Local defines, structs, and typedefs.
+ *
+ **********************************************************************/
+
+
+/*
+ * The following struct defines standard transfers to use while
+ * testing.
+ */
+typedef struct brt_xfer_entry_s {
+	int source_offset;
+	int dest_offset;
+	int length;
+} brt_xfer_entry_t;
+
+/*
+ * BRT_TEST_BLOCK_SIZE needs to accomodate the largest transfer that
+ * is found in brt_xfer_tests.
+ */
+#define BRT_TEST_BLOCK_SIZE 1024
+
+/* Flags for selecting tests to run. */
+#define TEST_REGRESSION		0x00000001	/* Standard Transfer */
+#define TEST_TIME		0x00000002	/* Timed Transfer */
+#define TEST_NOTIFY		0x00000004	/* Notification Hang */
+#define TEST_NONODE		0x00000008	/* Invalid Nasid Xfer */
+
+
+/***********************************************************************
+ * Global variables.
+ * 
+ **********************************************************************/
+
+
+/*
+ * bte_setup_time - Time it takes for bte_copy to get locks
+ * 		    acquired and values into SHUB registers to start the
+ * 		    xfer.
+ *
+ * bte_transfer_time - Time where hardware is doing the xfer.
+ *
+ * bte_tear_down_time - Time to unlock and return.
+ *
+ * bte_execute_time - Time from first call until return.
+ */
+volatile static u64 bte_setup_time;
+volatile static u64 bte_transfer_time;
+volatile static u64 bte_tear_down_time;
+volatile static u64 bte_execute_time;
+
+/* Tests to run during standard transfer tests. */
+static brt_xfer_entry_t brt_xfer_tests[] = {
+	{0, 0, 2 * L1_CACHE_BYTES},	/* The ideal case. */
+
+	{0, 0, 35},		/* Symetrical aligned test. */
+	{L1_CACHE_BYTES, L1_CACHE_BYTES, 35},
+	{0, 0, L1_CACHE_BYTES + 35},
+	{L1_CACHE_BYTES, L1_CACHE_BYTES, L1_CACHE_BYTES + 35},
+	{0, 0, (2 * L1_CACHE_BYTES) + 35},
+	{L1_CACHE_BYTES, L1_CACHE_BYTES, (2 * L1_CACHE_BYTES) + 35},
+	{0, 0, (4 * L1_CACHE_BYTES) + 35},
+	{L1_CACHE_BYTES, L1_CACHE_BYTES, (4 * L1_CACHE_BYTES) + 35},
+
+	{(0 + 25), (0 + 25), 35},	/* Symetrical unaligned test. */
+	{(L1_CACHE_BYTES + 25), (L1_CACHE_BYTES + 25), 35},
+	{(0 + 25), (0 + 25), L1_CACHE_BYTES + 35},
+	{(L1_CACHE_BYTES + 25), (L1_CACHE_BYTES + 25),
+	 (L1_CACHE_BYTES + 25) + 35},
+	{(0 + 25), (0 + 25), (2 * L1_CACHE_BYTES) + 35},
+	{(L1_CACHE_BYTES + 25), (L1_CACHE_BYTES + 25),
+	 (2 * L1_CACHE_BYTES) + 35},
+	{(0 + 25), (0 + 25), (4 * L1_CACHE_BYTES) + 35},
+	{(L1_CACHE_BYTES + 25), (L1_CACHE_BYTES + 25),
+	 (4 * L1_CACHE_BYTES) + 35},
+
+	{(0 + 25), (0 + 26), 35},	/* Asymetrical unaligned test. */
+	{(L1_CACHE_BYTES + 25), (L1_CACHE_BYTES + 26), 35},
+	{(0 + 25), (0 + 26), L1_CACHE_BYTES + 35},
+	{(L1_CACHE_BYTES + 25), (L1_CACHE_BYTES + 26),
+	 (L1_CACHE_BYTES + 25) + 35},
+	{(0 + 25), (0 + 26), (2 * L1_CACHE_BYTES) + 35},
+	{(L1_CACHE_BYTES + 25), (L1_CACHE_BYTES + 26),
+	 (2 * L1_CACHE_BYTES) + 35},
+	{(0 + 25), (0 + 26), (4 * L1_CACHE_BYTES) + 35},
+	{(L1_CACHE_BYTES + 25), (L1_CACHE_BYTES + 26),
+	 (4 * L1_CACHE_BYTES) + 35},
+
+	{0, 0, 0}		/* Terminator */
+};
+
+static atomic_t brt_thread_cnt;	/* Threads in test. */
+volatile static int brt_exit_flag;	/* Flag termination of hang test */
+
+/* command line/module parameters */
+static int selected_tests = 0;
+static int verbose = 0;
+static int hang_timeout = 10;
+static int hang_usec = 12;
+static int tm_min_lines = 1;
+static int tm_max_lines = 3;
+static int tm_iterations = 1;
+static int tm_alternate = 0;
+static int tm_memcpy = 1;
+static int ix_iterations = 1000;
+static int ix_srcnasid = -1;
+
+
+/***********************************************************************
+ * Local Function Prototypes.
+ * 
+ **********************************************************************/
+
+
+static int __init brt_test_init(void);
+static void __exit brt_test_exit(void);
+
+/* Standard Transfer Test related functions. */
+static int brt_tst_std_xfer(void);
+static int brt_std_xfer(char *, char *, int, int, int, int);
+static void brt_hex_dump(char *, int);
+
+/* Timed Transfer Test related functions. */
+static int brt_tst_time_xfers(void);
+static void brt_time_xfer(int, int, int);
+
+/* Notification Hang Test related functions. */
+static int brt_tst_notify_hang(void);
+static int brt_notify_thrd(void *);
+
+/* Transfers to Invalid Nasid Test related functions. */
+static int brt_tst_invalid_xfers(void);
+
+#if !defined(MODULE)
+/* Kernel command line handler. */
+static int __init brt_setup(char *);
+#endif				/* !defined(MODULE) */
+
+
+/***********************************************************************
+ * Module Load/Unload.
+ * 
+ **********************************************************************/
+
+
+#define brt_marker() \
+	printk("**************************************************" \
+	       "**********************.\n"); \
+	printk("\n"); \
+	printk("**************************************************" \
+	       "**********************.\n"); \
+	printk("\n"); \
+	printk("**************************************************" \
+	       "**********************.\n"); \
+	printk("\n");
+
+
+static int __init
+brt_test_init(void)
+{
+	int some_tests_removed;
+
+	if (numnodes < 2) {
+		printk("These tests are best run on multinode "
+		       "systems.\n");
+	}
+
+	if (!pda.cpu_bte_if[0]->bte_test_buf) {
+		some_tests_removed = 0;
+
+		/* Timed Transfers go node-to-node. */
+		if (selected_tests & TEST_TIME) {
+			some_tests_removed = 1;
+			selected_tests &= ~(TEST_TIME);
+		}
+
+		/* Notification Hang runs on all cpus simultaneously */
+		if (selected_tests & TEST_NOTIFY) {
+			some_tests_removed = 1;
+			selected_tests &= ~(TEST_NOTIFY);
+		}
+
+		/* Invalid Tests */
+		if (selected_tests & TEST_NONODE) {
+			some_tests_removed = 1;
+			selected_tests &= ~(TEST_NONODE);
+		}
+
+		if (some_tests_removed) {
+			printk("Test Buffers were not allocated.\n");
+			printk("Please reboot the system and supply "
+			       "the \"btetest\" kernel flag\n");
+			printk("Some tests were removed.\n");
+		}
+	}
+
+	brt_marker();
+
+	printk("brt_test(): Starting.\n");
+
+	if (selected_tests & TEST_REGRESSION) {
+		if (brt_tst_std_xfer()) {
+			printk("Standard Transfers had errors.\n");
+		}
+
+	}
+
+	if (selected_tests & TEST_TIME) {
+		if (tm_min_lines < 0) {
+			tm_min_lines = 0;
+		}
+		if (tm_max_lines < 0) {
+			tm_max_lines = 0;
+		}
+
+		if (tm_max_lines > BTE_LEN_MASK) {
+			tm_max_lines = BTE_LEN_MASK;
+		}
+		if (tm_min_lines > tm_max_lines) {
+			tm_min_lines = tm_max_lines;
+		}
+
+		if (brt_tst_time_xfers()) {
+			printk("Timed transfers had errors.\n");
+		}
+
+	}
+
+	if (selected_tests & TEST_NOTIFY) {
+		if (hang_usec < 8) {
+			hang_usec = 8;
+		}
+		if (hang_usec > 256) {
+			hang_usec = 256;
+		}
+
+		if (brt_tst_notify_hang()) {
+			printk("Notification Hang test had errors.\n");
+		}
+	}
+
+	if (selected_tests & TEST_NONODE) {
+		if (brt_tst_invalid_xfers()) {
+			printk("Invalid Nasid test had errors.\n");
+		}
+	}
+
+	return (1);		/* Prevent module load. */
+}
+
+
+static void __exit
+brt_test_exit(void)
+{
+}
+
+
+/***********************************************************************
+ * Standard Transfer Test.
+ *	
+ *	This test has a table of transfers defined above.  For each
+ *	transfer, it calls bte_unaligned_copy.  It compares the actual
+ *	result with the expected result.  If they differ, it prints out
+ *	information about the transfer and hex dumps the actual block
+ *
+ **********************************************************************/
+
+
+/*
+ * Allocate the needed buffers and then initiate each xfer specified
+ * by brt_xfer_tests.
+ */
+static int
+brt_tst_std_xfer(void)
+{
+	char *block_1;
+	char *block_2;
+	int iteration = 0;
+	brt_xfer_entry_t *cur_test;
+	int cpu;
+	int err_cnt;
+
+	block_1 = kmalloc(BRT_TEST_BLOCK_SIZE, GFP_KERNEL);
+	ASSERT(!((u64) block_1 & L1_CACHE_MASK));
+	block_2 = kmalloc(BRT_TEST_BLOCK_SIZE, GFP_KERNEL);
+	ASSERT(!((u64) block_2 & L1_CACHE_MASK));
+
+	cur_test = brt_xfer_tests;
+
+	err_cnt = 0;
+	while (cur_test->length) {
+		for (cpu = 0; cpu < smp_num_cpus; cpu++) {
+			set_cpus_allowed(current, (1UL << cpu));
+
+			if (verbose > 1) {
+				printk("Cpu %d Transfering %d from "
+				       "%d to %d.\n",
+				       smp_processor_id(),
+				       cur_test->length,
+				       cur_test->source_offset,
+				       cur_test->dest_offset);
+			}
+
+			err_cnt += brt_std_xfer(block_1, block_2,
+						cur_test->source_offset,
+						cur_test->dest_offset,
+						cur_test->length,
+						++iteration);
+
+		}
+		cur_test++;
+	}
+
+	kfree(block_2);
+	kfree(block_1);
+
+	return ((err_cnt ? 1 : 0));
+}
+
+
+/*
+ * Perform a single transfer and ensure the result matches
+ * the expected.  Returns the number of differences found.
+ *
+ * Testing is performed by setting the source buffer to a
+ * known value, and zeroing out the destination.
+ *
+ * After the copy, if the destination has only the known
+ * source values at the correct place, we know we had a
+ * good transfer.
+ *
+ */
+static int
+brt_std_xfer(char *src, char *dst,
+	     int src_offset, int dst_offset, int len,
+	     int magic)
+{
+	int i, ret;
+	int err_cnt = 0;
+
+	if (verbose > 3) {
+		printk("brt_test(src=0x%lx, dst=0x%lx, src_offset=%d, "
+		       "dst_offset=%d, len=%d, magic=%d\n",
+		       (u64) src, (u64) dst, src_offset,
+		       dst_offset, len, magic);
+	}
+
+	memset(src, ((magic + 1) & 0xff), BRT_TEST_BLOCK_SIZE);
+	memset((src + src_offset), magic, len);
+	if (verbose > 8) {
+		printk("Before transfer: Source is\n");
+		brt_hex_dump(src, BRT_TEST_BLOCK_SIZE);
+	}
+	memset(dst, 0, BRT_TEST_BLOCK_SIZE);
+	if (verbose > 8) {
+		printk("Before transfer: dest is\n");
+		brt_hex_dump(dst, BRT_TEST_BLOCK_SIZE);
+	}
+
+	ret = BTE_UNALIGNED_COPY(__pa(src + src_offset),
+				 __pa(dst + dst_offset),
+				 len, BTE_NOTIFY);
+	if (ret != BTE_SUCCESS) {
+		printk("brt_test: BTE_UNALIGNED_COPY() error: %d\n", ret);
+		return (1);
+	}
+
+	/* Check head */
+	for (i = 0; i < dst_offset; i++) {
+		if ((dst[i] & 0xff) != 0) {
+			err_cnt++;
+		}
+	}
+	/* Check body */
+	for (i = 0; i < len; i++) {
+		if ((dst[dst_offset + i] & 0xff) != (magic & 0xff)) {
+			err_cnt++;
+		}
+	}
+	/* Check foot */
+	for (i = (dst_offset + len); i < BRT_TEST_BLOCK_SIZE; i++) {
+		if ((dst[i] & 0xff) != 0) {
+			err_cnt++;
+		}
+	}
+
+	if ((verbose > 3) || err_cnt) {
+		printk("brt_test: %d errors during basic "
+		       "transfer test.\n", err_cnt);
+		brt_hex_dump(dst, BRT_TEST_BLOCK_SIZE);
+	}
+
+	return (err_cnt);
+}
+
+
+/*
+ * Dump a block of data to console as hex.
+ */
+static void
+brt_hex_dump(char *block_to_dump, int block_len)
+{
+	int i;
+	char fmt_line[128];
+	char *fmt_eol = fmt_line;
+
+	for (i = 0; i < block_len; i++) {
+		if (!(i % 16)) {
+			if (i > 0) {
+				printk("%s\n", fmt_line);
+			}
+			sprintf(fmt_line, "0x%lx %05d ",
+				__pa(&block_to_dump[i]), i);
+			fmt_eol = fmt_line;
+		}
+		while (*fmt_eol++) {	/* empty */
+		};
+		fmt_eol--;
+		sprintf(fmt_eol, "%s%02x",
+			(!(i % 4) ? " " : ""), (block_to_dump[i] & 0xff));
+	}
+	printk("%s\n", fmt_line);
+}
+
+
+/***********************************************************************
+ * Transfer Rate Test.
+ * 
+ *	This test migrates to each cpu one at a time.  This is done to
+ *	get a complete view of how each of the bte engines is performing
+ *	and help ensure that each virtual interface is being used.
+ *	NOTE: All virtual interfaces will not necessarily be used.
+ *
+ *	Now that we have migrated to the desired cpu, we transfer from
+ *	our node to all the other nodes (including ourself).  We
+ *	accomplish this with both a memcpy and a bte_copy.  Timings
+ *	for both are printed.
+ *
+ **********************************************************************/
+
+
+#define NSEC(x) ((x) * (1000000000UL / local_cpu_data->itc_freq))
+
+
+/*
+ * Migrate to each cpu. When on the desired cpu, time transfers to
+ * each node by calling brt_time_xfer.
+ */
+static int
+brt_tst_time_xfers(void)
+{
+	int tst_cpu;
+	int dest_node;
+	int xfer_lines;
+	int i;
+
+	if (tm_memcpy) {
+		printk("Cpu,Src,Dst,Lines,Stup,Transfr,Fin,Execute,"
+		       "Overall,Memcpy\n");
+	} else {
+		printk("Cpu,Src,Dst,Lines,Stup,Transfr,Fin,Execute,"
+		       "Overall\n");
+	}
+
+	if (tm_alternate) {
+		/* Now transfer from this node to all the others. */
+		for (dest_node = 0; dest_node < numnodes; dest_node++) {
+			for (xfer_lines = tm_min_lines;
+			     xfer_lines <= tm_max_lines;) {
+
+				for (i = 0; i < tm_iterations; i++) {
+					for (tst_cpu = 0;
+					     tst_cpu < smp_num_cpus;
+					     tst_cpu++) {
+						/* Move to the desired CPU. */
+						set_cpus_allowed(current,
+						    (1UL << tst_cpu));
+
+						brt_time_xfer(dest_node,
+							      1,
+							      xfer_lines);
+
+					}
+				}
+				/* Handle a min of 0 */
+				if (xfer_lines < 1) {
+					xfer_lines = 1;
+				} else {
+					xfer_lines *= 2;
+				}
+			}
+		}
+	} else {
+		for (tst_cpu = 0; tst_cpu < smp_num_cpus; tst_cpu++) {
+			/* Move to the desired CPU. */
+			set_cpus_allowed(current, (1UL << tst_cpu));
+
+			/* Now transfer from this node to all the others. */
+			for (dest_node = 0; dest_node < numnodes;
+			     dest_node++) {
+				for (xfer_lines = tm_min_lines;
+				     xfer_lines <= tm_max_lines;) {
+
+					brt_time_xfer(dest_node,
+						      tm_iterations,
+						      xfer_lines);
+
+					/* Handle a min of 0 */
+					if (xfer_lines < 1) {
+						xfer_lines = 1;
+					} else {
+						xfer_lines *= 2;
+					}
+				}
+			}
+		}
+	}
+	return (0);
+}
+
+
+/*
+ * Transfer the bte_test_buffer from our node to the specified
+ * destination and print out timing results.
+ */
+static void
+brt_time_xfer(int dest_node, int iterations, int xfer_lines)
+{
+	int iteration;
+	char *src, *dst;
+	u64 xfer_len, src_phys, dst_phys;
+	u64 itc_before, itc_after, mem_intvl, bte_intvl;
+
+
+	xfer_len = xfer_lines * L1_CACHE_BYTES;
+
+	src = nodepda->bte_if[0].bte_test_buf;
+	src_phys = __pa(src);
+	dst = NODEPDA(dest_node)->bte_if[1].bte_test_buf;
+	dst_phys = __pa(dst);
+	mem_intvl = 0;
+
+	for (iteration = 0; iteration < iterations; iteration++) {
+		if (tm_memcpy) {
+			itc_before = ia64_get_itc();
+			memcpy(dst, src, xfer_len);
+			itc_after = ia64_get_itc();
+			mem_intvl = itc_after - itc_before;
+		}
+
+		itc_before = ia64_get_itc();
+		bte_copy(src_phys, dst_phys, xfer_len, BTE_NOTIFY, NULL);
+		itc_after = ia64_get_itc();
+		bte_intvl = itc_after - itc_before;
+
+		if (tm_memcpy) {
+			printk("%3d,%3d,%3d,%5d,%4ld,%7ld,%3ld,"
+			       "%7ld,%7ld,%7ld\n",
+			       smp_processor_id(), NASID_GET(src),
+			       NASID_GET(dst), xfer_lines,
+			       NSEC(bte_setup_time),
+			       NSEC(bte_transfer_time),
+			       NSEC(bte_tear_down_time),
+			       NSEC(bte_execute_time), NSEC(bte_intvl),
+			       NSEC(mem_intvl));
+		} else {
+			printk("%3d,%3d,%3d,%5d,%4ld,%7ld,%3ld,"
+			       "%7ld,%7ld\n",
+			       smp_processor_id(), NASID_GET(src),
+			       NASID_GET(dst), xfer_lines,
+			       NSEC(bte_setup_time),
+			       NSEC(bte_transfer_time),
+			       NSEC(bte_tear_down_time),
+			       NSEC(bte_execute_time), NSEC(bte_intvl));
+		}
+	}
+
+}
+
+
+/***********************************************************************
+ * Notification Hang Test. -- NOTE: Has never actually caused a hang.
+ *
+ *	The next set of code checks to see if the Notification Hang
+ *	occurs.  It does this by starting one thread per cpu, pinning
+ *	the thread to its assigned cpu.  After it is pinned, we lock
+ *	the associated bte.  Source, Dest, and Notification are
+ *	assigned.
+ *
+ *	Inside of a loop, we set the length and trigger the
+ *	transfer. We use the ITC to determine when the transfer should
+ *	complete. Whenever the IBLS_BUSY bit is cleared, the transfer
+ *	has completed. We occasionally call schedule (Since all CPUs
+ *	have a pinned process The machine will be doing nothing but
+ *	out tranfers) and loop.
+ *
+ *	If twice max normal time has passed without seeing the
+ *	notification, we check the Length/Status register to see if
+ *	IBLS_BUSY is still asserted and length is zero.  This is an
+ *	indication of the hang.
+ *
+ **********************************************************************/
+
+
+/*
+ * Launch one thread per cpu.  When all threads are started, sleep
+ * the specified timeout and then notify the other threads that it
+ * is time to exit.
+ */
+static int
+brt_tst_notify_hang(void)
+{
+	int tst_cpu;
+
+	printk("Waiting %d seconds to complete test.\n", hang_timeout);
+
+	atomic_set(&brt_thread_cnt, 0);
+	brt_exit_flag = 0;
+
+	for (tst_cpu = 0; tst_cpu < smp_num_cpus; tst_cpu++) {
+		if ((kernel_thread(brt_notify_thrd,
+				   (void *)(long)tst_cpu, 0)) < 0) {
+			printk("Failed to start thread.\n");
+		}
+	}
+
+	set_current_state(TASK_INTERRUPTIBLE);
+	schedule_timeout(hang_timeout * HZ);
+	set_current_state(TASK_RUNNING);
+
+	printk("Flagging an exit.\n");
+	brt_exit_flag = 1;
+
+	while (atomic_read(&brt_thread_cnt)) {
+		/* Wait until everyone else is done. */
+		schedule();
+	}
+
+	printk("All threads have exited.\n");
+	return (0);
+}
+
+
+/*
+ * One of these threads is started per cpu.  Each thread is responsible
+ * for loading that cpu's bte interface and then writing to the
+ * test buffer.  The transfers are set in a round-robin fashion.
+ * The end result is that each test buffer is being written into
+ * by the previous node and both cpu's at the same time as the
+ * local bte is transferring it to the next node.
+ */
+static int
+brt_notify_thrd(void *__bind_cpu)
+{
+	int bind_cpu = (long int)__bind_cpu;
+	int cpu = cpu_logical_map(bind_cpu);
+	nodepda_t *nxt_node;
+	long tmout_itc_intvls;
+	long tmout;
+	long passes;
+	long good_xfer_cnt;
+	u64 src_phys, dst_phys;
+	int i;
+	volatile char *src_buf;
+	u64 *notify;
+
+	atomic_inc(&brt_thread_cnt);
+	daemonize();
+	set_user_nice(current, 19);
+	sigfillset(&current->blocked);
+
+	/* Migrate to the right CPU */
+	set_cpus_allowed(current, 1UL << cpu);
+
+	/* Calculate the uSec timeout itc offset. */
+	tmout_itc_intvls = local_cpu_data->cyc_per_usec * hang_usec;
+
+	if (local_cnodeid() == (numnodes - 1)) {
+		nxt_node = NODEPDA(0);
+	} else {
+		nxt_node = NODEPDA(local_cnodeid() + 1);
+	}
+
+	src_buf = nodepda->bte_if[0].bte_test_buf;
+	src_phys = __pa(src_buf);
+	dst_phys = __pa(nxt_node->bte_if[0].bte_test_buf);
+
+	notify = kmalloc(L1_CACHE_BYTES, GFP_KERNEL);
+	ASSERT(!((u64) notify & L1_CACHE_MASK));
+
+	printk("BTE Hang %d xfer 0x%lx -> 0x%lx, Notify=0x%lx\n",
+	       smp_processor_id(), src_phys, dst_phys, (u64) notify);
+
+	passes = 0;
+	good_xfer_cnt = 0;
+
+	/* Loop until signalled to exit. */
+	while (!brt_exit_flag) {
+		/*
+		 * A hang will prevent further transfers.
+		 * NOTE: Sometimes, it appears like a hang occurred and
+		 * then transfers begin again.  This just means that
+		 * there is NUMA congestion and the hang_usec param
+		 * should be increased.
+		 */
+		if (!(*notify & IBLS_BUSY)) {
+			if ((bte_copy(src_phys,
+				      dst_phys,
+				      4UL * L1_CACHE_BYTES,
+				      BTE_NOTIFY,
+				      (void *)notify)) != BTE_SUCCESS) {
+				printk("<0>Cpu %d Could not "
+				       "allocate a bte.\n",
+				       smp_processor_id());
+				continue;
+			}
+
+			tmout = ia64_get_itc() + tmout_itc_intvls;
+
+			while ((*notify & IBLS_BUSY) &&
+			       (ia64_get_itc() < tmout)) {
+
+
+				/* Push data out with the processor. */
+				for (i = 0; i < (4 * L1_CACHE_BYTES);
+				     i += L1_CACHE_BYTES) {
+					src_buf[i] = (passes % 128);
+				}
+			};
+
+			if (*notify & IBLS_BUSY) {
+				printk("<0>Cpu %d BTE appears to have "
+				       "hung.\n", smp_processor_id());
+			} else {
+				good_xfer_cnt++;
+			}
+		}
+
+		/* Every x passes, take a little break. */
+		if (!(++passes % 40)) {
+			passes = 0;
+			schedule_timeout(0.01 * HZ);
+		}
+	}
+
+	kfree(notify);
+
+	printk("Cpu %d had %ld good passes\n",
+	       smp_processor_id(), good_xfer_cnt);
+
+	atomic_dec(&brt_thread_cnt);
+	return (0);
+}
+
+
+/***********************************************************************
+ * Invalid Transfer Test.
+ * 
+ *	Just transfer from the local node to a nasid which does not
+ *	exist.
+ *
+ *	>>> Potential Problem: on SN1, HUB interrupt doesn't always
+ *	occurr.
+ *
+ **********************************************************************/
+
+
+/*
+ * Locate a nasid which doesn't exist.  Perform a bte_copy from that
+ * node to our local node.
+ */
+static int
+brt_tst_invalid_xfers(void)
+{
+	int i;
+	int free_nasid = -1;
+	int cpu;
+	int error_cnt;
+
+	u64 ret_code;
+
+	if (ix_srcnasid != -1) {
+		free_nasid = ix_srcnasid;
+	} else {
+		/* Only looking for nasids from C-Nodes. */
+		for (i = 0; i < PLAT_MAX_NODE_NUMBER; i += 2) {
+			if (local_node_data->physical_node_map[i] == -1) {
+				free_nasid = i;
+				break;
+			}
+		}
+	}
+
+	if (free_nasid == -1) {
+		printk("tst_invalid_xfers: No free nodes found. "
+		       "Exiting.\n");
+		return (0);
+	}
+
+	printk("tst_invalid_xfers: Using source nasid of %d\n",
+	       free_nasid);
+
+	error_cnt = 0;
+
+	for (i = 0; i < ix_iterations; i++) {
+		if (verbose >= 1) {
+			printk("-------------------------------"
+			       "-------------------------------"
+			       "--------------\n");
+		}
+		if ((verbose >= 1) || !(i % 10)) {
+			printk("  Loop %d\n", i);
+		}
+
+		for (cpu = 0; cpu < smp_num_cpus; cpu++) {
+			set_cpus_allowed(current, (1UL << cpu));
+
+			if (verbose > 1) {
+				printk("Testing with CPU %d\n",
+				       smp_processor_id());
+			}
+
+			/* >>> Need a better means of calculating a
+			 * remote addr. */
+			ret_code = bte_copy(TO_NODE(free_nasid, 0),
+					    __pa(nodepda->bte_if[0].
+						 bte_test_buf),
+					    4 * L1_CACHE_BYTES,
+					    BTE_NOTIFY,
+					    NULL);
+			error_cnt += (ret_code ? 1 : 0);
+		}
+	}
+
+	ret_code = ((error_cnt != (ix_iterations * smp_num_cpus)) ?
+		    1 : 0);
+	return (ret_code);
+}
+
+
+/***********************************************************************
+ * Kernel command line handler.
+ * 
+ **********************************************************************/
+
+
+#if !defined(MODULE)
+static int __init
+brt_setup(char *str)
+{
+	int cur_val;
+
+	if (get_option(&str, &cur_val)) {
+		selected_tests = cur_val;
+	}
+	if (get_option(&str, &cur_val)) {
+		verbose = cur_val;
+	}
+	if (get_option(&str, &cur_val)) {
+		hang_timeout = cur_val;
+	}
+	if (get_option(&str, &cur_val)) {
+		hang_usec = cur_val;
+	}
+	if (get_option(&str, &cur_val)) {
+		tm_min_lines = cur_val;
+	}
+	if (get_option(&str, &cur_val)) {
+		tm_max_lines = cur_val;
+	}
+	if (get_option(&str, &cur_val)) {
+		tm_iterations = cur_val;
+	}
+	if (get_option(&str, &cur_val)) {
+		tm_alternate = cur_val;
+	}
+	if (get_option(&str, &cur_val)) {
+		tm_memcpy = cur_val;
+	}
+	if (get_option(&str, &cur_val)) {
+		ix_iterations = cur_val;
+	}
+	if (get_option(&str, &cur_val)) {
+		ix_srcnasid = cur_val;
+	}
+
+	return (1);
+}
+#endif				/* !defined(MODULE) */
+
+
+/***********************************************************************
+ * Module parameters.
+ *	
+ *	The two supported cases are loadable module parms and kernel
+ *	command line support.
+ *	
+ *	The loadable module options are specified below in the
+ *	MODULE_PARM macros and have associated descriptions.
+ *	
+ *	The kernel command line option is btetest=x[,y[,z]] etc.  The
+ *	individual setting order is constant.  NOTE: The btetest flag
+ *	is checked for in the bte_init_node function.
+ *	
+ **********************************************************************/
+
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Silicon Graphics, Inc.");
+MODULE_DESCRIPTION("Test the Block Transfer Engine(BTE) "
+		   "present on SGI machines.");
+
+MODULE_PARM(selected_tests, "1i");
+MODULE_PARM_DESC(selected_tests, "Bitmask of tests to run.");
+
+MODULE_PARM(verbose, "1i");
+MODULE_PARM_DESC(verbose,
+		 "How much information should be "
+		 "printed during the tests.");
+
+MODULE_PARM(hang_timeout, "1i");
+MODULE_PARM_DESC(hang_timeout,
+		 "Number of seconds to wait for the Bte "
+		 "Notification Failure.");
+
+MODULE_PARM(hang_usec, "1i");
+MODULE_PARM_DESC(hang_usec,
+		 "Number of micro-seconds to wait for the 4-line Bte "
+		 "transfer to complete.");
+
+MODULE_PARM(tm_min_lines, "1i");
+MODULE_PARM_DESC(tm_min_lines, "Minimum number of cache lines"
+		 " to time with.");
+
+MODULE_PARM(tm_max_lines, "1i");
+MODULE_PARM_DESC(tm_max_lines, "Maximum number of cache lines"
+		 " to time with.");
+
+MODULE_PARM(tm_iterations, "1i");
+MODULE_PARM_DESC(tm_iterations, "Rerun each timed transfer this "
+		 "many times.");
+
+MODULE_PARM(tm_alternate, "1i");
+MODULE_PARM_DESC(tm_alternate, "Cycle across cpus between each "
+		 "iteration");
+
+MODULE_PARM(tm_memcpy, "1i");
+MODULE_PARM_DESC(tm_memcpy, "Use memcpy as a comparison to BTE");
+
+MODULE_PARM(ix_iterations, "1i");
+MODULE_PARM_DESC(ix_iterations, "Rerun each transfer from an "
+		 "invalid nasid this many times.");
+
+MODULE_PARM(ix_srcnasid, "1i");
+MODULE_PARM_DESC(ix_srcnasid, "Nasid to attempt xfer from.");
+
+
+#if !defined(MODULE)
+__setup("btetest=", brt_setup);
+#endif				/* !defined(MODULE) */
+
+
+module_init(brt_test_init);
+module_exit(brt_test_exit);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/kernel/iomv.c linux-2.4.21-pre6/arch/ia64/sn/kernel/iomv.c
--- linux-2.4.20/arch/ia64/sn/kernel/iomv.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/kernel/iomv.c	2003-03-26 23:49:34.000000000 +0000
@@ -7,15 +7,7 @@
  */
 
 #include <asm/io.h>
-
-#if 1	/* ##jh */
-#ifdef CONFIG_IA64_SGI_SN1
-#define mmiob sn1_mmiob
-#else
-#define mmiob sn2_mmiob
-#endif
-extern void mmiob(void);
-#endif /* ##jh */
+#include <linux/module.h>
 
 extern void * sn_io_addr(unsigned long port); /* defined in sn[12]/iomv.c */
 
@@ -83,7 +75,6 @@
 	volatile unsigned char *addr = sn_io_addr(port);
 
 	*addr = val;
-	mmiob();
 }
 
 /**
@@ -99,7 +90,6 @@
 	volatile unsigned short *addr = sn_io_addr(port);
 
 	*addr = val;
-	mmiob();
 }
 
 /**
@@ -115,5 +105,11 @@
 	volatile unsigned int *addr = sn_io_addr(port);
 
 	*addr = val;
-	mmiob();
 }
+
+EXPORT_SYMBOL(sn_inb);
+EXPORT_SYMBOL(sn_inw);
+EXPORT_SYMBOL(sn_inl);
+EXPORT_SYMBOL(sn_outb);
+EXPORT_SYMBOL(sn_outw);
+EXPORT_SYMBOL(sn_outl);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/kernel/irq.c linux-2.4.21-pre6/arch/ia64/sn/kernel/irq.c
--- linux-2.4.20/arch/ia64/sn/kernel/irq.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/kernel/irq.c	2003-03-26 23:49:00.000000000 +0000
@@ -226,12 +226,6 @@
 	return (CPU_VECTOR_TO_IRQ(smp_processor_id(), vector));
 }
 
-int
-sn_valid_irq(u8 irq) {
-
-	return( ((irq & 0xff) < NR_IRQS) && ((irq >> 8) < NR_CPUS) );
-}
-
 void *kmalloc(size_t, int);
 
 void
@@ -240,7 +234,7 @@
 	int i;
 	irq_desc_t *base_desc = _irq_desc;
 
-	for (i=IA64_FIRST_DEVICE_VECTOR; i<NR_IRQS; i++) {
+	for (i=IA64_FIRST_DEVICE_VECTOR; i<NR_IVECS; i++) {
 		if (base_desc[i].handler == &no_irq_type) {
 			base_desc[i].handler = &irq_type_sn;
 		}
@@ -254,21 +248,14 @@
 
 	for (i=0; i < NR_CPUS; i++) {
 		p =  page_address(alloc_pages_node(local_cnodeid(), GFP_KERNEL,
-			get_order(sizeof(struct irq_desc) * NR_IRQS) ) );
+			get_order(sizeof(struct irq_desc) * NR_IVECS) ) );
 		ASSERT(p);
-		memcpy(p, base_desc, sizeof(struct irq_desc) * NR_IRQS);
+		memcpy(p, base_desc, sizeof(struct irq_desc) * NR_IVECS);
 		_sn_irq_desc[i] = p;
 	}
 }
 
 
-#if !defined(CONFIG_IA64_SGI_SN)
-void
-sn_pci_fixup(void)
-{
-}
-#endif
-
 int
 bit_pos_to_irq(int bit) {
 #define BIT_TO_IRQ 64
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/kernel/mca.c linux-2.4.21-pre6/arch/ia64/sn/kernel/mca.c
--- linux-2.4.20/arch/ia64/sn/kernel/mca.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/kernel/mca.c	2003-03-26 23:49:20.000000000 +0000
@@ -34,199 +34,80 @@
  */
 
 #include <linux/types.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/threads.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/smp_lock.h>
-#include <linux/kdb.h>
-
-#include <asm/machvec.h>
-#include <asm/page.h>
-#include <asm/ptrace.h>
-#include <asm/system.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <asm/mca.h>
 #include <asm/sal.h>
 #include <asm/sn/sn_sal.h>
-#include <asm/mca.h>
-#include <asm/sn/mca.h>
 
-#include <asm/irq.h>
-#include <asm/hw_irq.h>
-#include <asm/acpi-ext.h>
-#include <asm/smp.h>
-#include <asm/sn/sn_cpuid.h>
-
-static char *shub_mmr_names[] = {
-	"sh_event_occurred",
-	"sh_first_error",
-	"sh_event_overflow",
-
-/* PI */
-	"sh_pi_first_error",
-	"sh_pi_error_summary",
-	"sh_pi_error_overflow",
-
-/* PI HW */
-	"sh_pi_error_detail_1",
-	"sh_pi_error_detail_2",
-	"sh_pi_hw_time_stamp",
-
-/* PI UCE */
-	"sh_pi_uncorrected_detail_1",
-	"sh_pi_uncorrected_detail_2",
-	"sh_pi_uncorrected_detail_3",
-	"sh_pi_uncorrected_detail_4",
-	"sh_pi_uncor_time_stamp",
-
-/* PI CE */
-	"sh_pi_corrected_detail_1",
-	"sh_pi_corrected_detail_2",
-	"sh_pi_corrected_detail_3",
-	"sh_pi_corrected_detail_4",
-	"sh_pi_cor_time_stamp",
-
-/* MD */
-	"sh_mem_error_summary",
-	"sh_mem_error_overflow",
-/* MD HW */
-	"sh_misc_err_hdr_upper",
-	"sh_misc_err_hdr_lower",
-	"sh_md_dqlp_mmr_xperr_val",
-	"sh_md_dqlp_mmr_yperr_val",
-	"sh_md_dqrp_mmr_xperr_val",
-	"sh_md_dqrp_mmr_yperr_val",
-	"sh_md_hw_time_stamp",
-
-/* MD UCE */
-	"sh_dir_uc_err_hdr_lower",
-	"sh_dir_uc_err_hdr_upper",
-	"sh_md_dqlp_mmr_xuerr1",
-	"sh_md_dqlp_mmr_xuerr2",
-	"sh_md_dqlp_mmr_yuerr1",
-	"sh_md_dqlp_mmr_yuerr2",
-	"sh_md_dqrp_mmr_xuerr1",
-	"sh_md_dqrp_mmr_xuerr2",
-	"sh_md_dqrp_mmr_yuerr1",
-	"sh_md_dqrp_mmr_yuerr2",
-	"sh_md_uncor_time_stamp",
-
-/* MD CE */
-	"sh_dir_cor_err_hdr_lower",
-	"sh_dir_cor_err_hdr_upper",
-	"sh_md_dqlp_mmr_xcerr1",
-	"sh_md_dqlp_mmr_xcerr2",
-	"sh_md_dqlp_mmr_ycerr1",
-	"sh_md_dqlp_mmr_ycerr2",
-	"sh_md_dqrp_mmr_xcerr1",
-	"sh_md_dqrp_mmr_xcerr2",
-	"sh_md_dqrp_mmr_ycerr1",
-	"sh_md_dqrp_mmr_ycerr2",
-	"sh_md_cor_time_stamp",
-
-/* MD CE, UCE */
-	"sh_md_dqls_mmr_xamopw_err",
-	"sh_md_dqrs_mmr_yamopw_err",
-
-/* XN */
-	"sh_xn_error_summary",
-	"sh_xn_first_error",
-	"sh_xn_error_overflow",
-
-/* XN HW */
-	"sh_xniilb_error_summary",
-	"sh_xniilb_first_error",
-	"sh_xniilb_error_overflow",
-	"sh_xniilb_error_detail_1",
-	"sh_xniilb_error_detail_2",
-	"sh_xniilb_error_detail_3",
-
-	"sh_ni0_error_summary_1",
-	"sh_ni0_first_error_1",
-	"sh_ni0_error_overflow_1",
-
-	"sh_ni0_error_summary_2",
-	"sh_ni0_first_error_2",
-	"sh_ni0_error_overflow_2",
-	"sh_ni0_error_detail_1",
-	"sh_ni0_error_detail_2",
-	"sh_ni0_error_detail_3",
-
-	"sh_ni1_error_summary_1",
-	"sh_ni1_first_error_1",
-	"sh_ni1_error_overflow_1",
-
-	"sh_ni1_error_summary_2",
-	"sh_ni1_first_error_2",
-	"sh_ni1_error_overflow_2",
-
-	"sh_ni1_error_detail_1",
-	"sh_ni1_error_detail_2",
-	"sh_ni1_error_detail_3",
-
-	"sh_xn_hw_time_stamp",
-
-/* XN HW & UCE & SBE */
-	"sh_xnpi_error_summary",
-	"sh_xnpi_first_error",
-	"sh_xnpi_error_overflow",
-	"sh_xnpi_error_detail_1",
-
-	"sh_xnmd_error_summary",
-	"sh_xnmd_first_error",
-	"sh_xnmd_error_overflow",
-	"sh_xnmd_ecc_err_report",
-	"sh_xnmd_error_detail_1",
-
-/* XN UCE */
-	"sh_xn_uncorrected_detail_1",
-	"sh_xn_uncorrected_detail_2",
-	"sh_xn_uncorrected_detail_3",
-	"sh_xn_uncorrected_detail_4",
-	"sh_xn_uncor_time_stamp",
-
-/* XN CE */
-	"sh_xn_corrected_detail_1",
-	"sh_xn_corrected_detail_2",
-	"sh_xn_corrected_detail_3",
-	"sh_xn_corrected_detail_4",
-	"sh_xn_cor_time_stamp",
-
-/* LB HW */
-	"sh_lb_error_summary",
-	"sh_lb_first_error",
-	"sh_lb_error_overflow",
-	"sh_lb_error_detail_1",
-	"sh_lb_error_detail_2",
-	"sh_lb_error_detail_3",
-	"sh_lb_error_detail_4",
-	"sh_lb_error_detail_5",
-	"sh_junk_error_status",
-};
 
-void 
-sal_log_plat_print(int header_len, int sect_len, u8 *p_data, prfunc_t prfunc) 
+
+/*
+ * Interval for calling SAL to poll for errors that do NOT cause error
+ * interrupts. SAL will raise a CPEI if any errors are present that
+ * need to be logged.
+ */
+#define CPEI_INTERVAL	(5*HZ)
+
+
+struct timer_list sn_cpei_timer;
+void sn_init_cpei_timer(void);
+
+
+/*
+ * print_hook
+ *
+ * This function is the callback routine that SAL calls to log error
+ * info for platform errors. 
+ */
+static int
+print_hook(const char *fmt, ...)
 {
-	sal_log_plat_info_t *sh_info = (sal_log_plat_info_t *) p_data;
-	u64 *mmr_val = (u64 *)&(sh_info->shub_state);
-	char **mmr_name = shub_mmr_names;
-	int mmr_count = sizeof(sal_log_shub_state_t)>>3;
-
-	while(mmr_count) {
-		if(*mmr_val) {
-			prfunc("%-40s: %#016lx\n",*mmr_name, *mmr_val);
-		}
-		mmr_name++;
-		mmr_val++;
-		mmr_count--;
+	static int	newline=1;
+	char		buf[400], *p;
+	va_list		args;
+	int		len=0;
+
+
+	va_start(args, fmt);
+	if (newline) {
+		strcpy(buf, "+ ");
+		len += 2;
 	}
+	len += vsnprintf(buf+len, sizeof(buf)-len, fmt, args);
 
+	/* Prefix each line with "+ " to be consistent with mca.c. */
+	p = buf;
+	while ((p=strchr(p, '\n')) && *++p != '\0') {
+		memmove(p+2, p, 1+strlen(p));
+		strncpy(p, "+ ", 2);
+		len += 2;
+	}
+	newline = (p != 0);
+
+	va_end(args);
+	printk("%s", buf);
+	return len;
 }
 
-sn_cpei_handler(int irq, void *devid, struct pt_regs *regs)
+
+
+/*
+ * ia64_sn2_platform_plat_specific_err_print
+ *
+ * Called by the MCA handler to log platform-specific errors.
+ */
+void
+ia64_sn2_platform_plat_specific_err_print(int header_len, int sect_len, u8 *p_data, prfunc_t prfunc)
 {
-	struct ia64_sal_retval isrv;
+	ia64_sn_plat_specific_err_print(print_hook, p_data - sect_len);
+}
+
 
+
+static void
+sn_cpei_handler(int irq, void *devid, struct pt_regs *regs)
+{
 	/*
 	 * this function's sole purpose is to call SAL when we receive
 	 * a CE interrupt from SHUB or when the timer routine decides
@@ -234,46 +115,45 @@
 	 */
 
 	/* CALL SAL_LOG_CE */
-	SAL_CALL(isrv, SN_SAL_LOG_CE, irq, 0, 0, 0, 0, 0, 0);
-}
 
-#include <linux/timer.h>
+	ia64_sn_plat_cpei_handler();
+}
 
-#define CPEI_INTERVAL   (HZ/100)
-struct timer_list sn_cpei_timer;
-void sn_init_cpei_timer(void);
 
-void
+static void
 sn_cpei_timer_handler(unsigned long dummy) {
-        sn_cpei_handler(-1, NULL, NULL);
-        del_timer(&sn_cpei_timer);
-        sn_cpei_timer.expires = jiffies + CPEI_INTERVAL;
+	sn_cpei_handler(-1, NULL, NULL);
+	del_timer(&sn_cpei_timer);
+	sn_cpei_timer.expires = jiffies + CPEI_INTERVAL;
         add_timer(&sn_cpei_timer);
 }
 
 void
 sn_init_cpei_timer() {
-        sn_cpei_timer.expires = jiffies + CPEI_INTERVAL;
+	sn_cpei_timer.expires = jiffies + CPEI_INTERVAL;
         sn_cpei_timer.function = sn_cpei_timer_handler;
         add_timer(&sn_cpei_timer);
 }
 
+
+
+
 #ifdef ajmtestceintr
 
 struct timer_list sn_ce_timer;
 
 void
 sn_ce_timer_handler(long dummy) {
-        unsigned long *pi_ce_error_inject_reg = 0xc00000092fffff00;
+	unsigned long *pi_ce_error_inject_reg = 0xc00000092fffff00;
 
-        *pi_ce_error_inject_reg = 0x0000000000000100;
-        del_timer(&sn_ce_timer);
-        sn_ce_timer.expires = jiffies + CPEI_INTERVAL;
+	*pi_ce_error_inject_reg = 0x0000000000000100;
+	del_timer(&sn_ce_timer);
+	sn_ce_timer.expires = jiffies + CPEI_INTERVAL;
         add_timer(&sn_ce_timer);
 }
 
 sn_init_ce_timer() {
-        sn_ce_timer.expires = jiffies + CPEI_INTERVAL;
+	sn_ce_timer.expires = jiffies + CPEI_INTERVAL;
         sn_ce_timer.function = sn_ce_timer_handler;
         add_timer(&sn_ce_timer);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/kernel/misctest.c linux-2.4.21-pre6/arch/ia64/sn/kernel/misctest.c
--- linux-2.4.20/arch/ia64/sn/kernel/misctest.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/kernel/misctest.c	2003-03-26 23:49:19.000000000 +0000
@@ -4,119 +4,368 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/interrupt.h>
 #include <asm/sn/sn_sal.h>
 #include <asm/sn/sn_cpuid.h>
 #include <asm/processor.h>
 #include <asm/pgtable.h>
-
+#include <asm/page.h>
+#include <asm/timex.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/sn/intr.h>
+#include <asm/hw_irq.h>
+#include <asm/sn/leds.h>
 
 extern	int autotest_enabled;
-int	mcatest=0;
-
+long	mcatest=0, debug0, debug1, debug2, debug3;
 
+#define HDELAY(t)	(IS_RUNNING_ON_SIMULATOR() ? udelay(1) : udelay(t))
 
 /* 
  * mcatest
- *	1 = expected MCA
- *	2 = unexpected MCA
- *	3 = expected MCA + unexpected MCA
- *	4 = INIT
- *	5 = speculative load to garbage memory address
- *	6 = speculative load with ld8.s (needs poison hack in PROM)
- *	7 = speculative load from mis-predicted branch (needs poison hack in PROM)
+ *	mactest contains a decimal number (RPTT) where
+ *		R - flag, if non zero, run forever
+ *
+ *		P - identifies when to run the test
+ *		    0 execute test at cpu 0 early init
+ *		    1 execute test at cpu 0 idle
+ *		    2 execute test at last (highest numbered) cpu idle
+ *		    3 execute test on all cpus at idle
+ *
+ *		TT- identifies test to run
+ *		    01 = MCA via dup TLB dropin
+ *		    02 = MCA via garbage address
+ *		    03 = lfetch via garbage address
+ *		    05 = INIT self
+ *		    06 = INIT other cpu
+ *		    07 = INIT non-existent cpu
+ *		    10 = IPI stress test. Target cpu 0
+ *		    11 = IPI stress test. Target all cpus
+ *		    12 = TLB stress test
+ *		    13 = Park cpu (spinloop)
+ *		    14 = One shot TLB test with tlb spinlock
+ *		    15 = One shot TLB test
+ *		    16 = One shot TLB test sync'ed with RTC
+ *		    20 = set led to the cpuid & spin.
+ *		    21 = Try mixed cache/uncached refs & see what happens
+ *		    22 = Call SAL reboot
+ *		    23 = Call PAL halt
  */
 static int __init set_mcatest(char *str)
 {
-	get_option(&str, &mcatest);
+	int	val;
+	get_option(&str, &val);
+	mcatest = val;
 	return 1;
 }
-
 __setup("mcatest=", set_mcatest);
 
+static int __init set_debug0(char *str)
+{
+	int	val;
+	get_option(&str, &val);
+	debug0 = val;
+	return 1;
+}
+__setup("debug0=", set_debug0);
+
+static int __init set_debug1(char *str)
+{
+	int	val;
+	get_option(&str, &val);
+	debug1 = val;
+	return 1;
+}
+__setup("debug1=", set_debug1);
+
+static int __init set_debug2(char *str)
+{
+	int	val;
+	get_option(&str, &val);
+	debug2 = val;
+	return 1;
+}
+__setup("debug2=", set_debug2);
+
+static int __init set_debug3(char *str)
+{
+	int	val;
+	get_option(&str, &val);
+	debug3 = val;
+	return 1;
+}
+__setup("debug3=", set_debug3);
+
+static volatile int	go;
+
+static void
+do_sync(int pos) {
+	if (pos != 3)
+		return;
+	else if (smp_processor_id() == 0)
+		go = 1;
+	else
+		while (!go);
+}
+
+static void
+sgi_mcatest_bkpt(void)
+{
+}
+
+
+/*
+ * Optional test
+ *	pos - 0 called from early init
+ *	pos - called when cpu about to go idle (fully initialized
+ */
 void
-sgi_mcatest(void)
+sgi_mcatest(int pos)
 {
-	if (mcatest == 1 || mcatest == 3) {
-		long	*p, result, adrs[] = {0xc0000a000f021004UL, 0xc0000a000f026004UL, 0x800000000, 0x500000, 0};
-		long	size[] = {1,2,4,8};
-		int	r, i, j;
-		p = (long*)0xc000000000000000UL;
-		ia64_fc(p);
-		*p = 0x0123456789abcdefL;
-		for (i=0; i<5; i++) {
-			for (j=0; j<4; j++) {
-				printk("Probing 0x%lx, size %ld\n", adrs[i], size[j]);
-				result = -1;
-				r = ia64_sn_probe_io_slot (adrs[i], size[j], &result);
-				printk("    status %d, val 0x%lx\n", r, result); 
+	long	spos, test, repeat;
+	int	cpu, curcpu, i, n;
+
+	//if (IS_RUNNING_ON_SIMULATOR()) mcatest=1323;
+	repeat = mcatest/1000;
+	spos = (mcatest/100)%10;
+	test = mcatest % 100;
+	curcpu = smp_processor_id();
+
+	if ( mcatest == 0 || !((pos == 0 && spos == 0) ||
+		(pos == 1 && spos == 3) ||
+	        (pos == 1 && spos == 1 && curcpu == 0) ||
+	        (pos == 1 && spos == 2 && curcpu == smp_num_cpus-1)))
+		return;
+	     
+again:
+	if (test == 1 || test == 2 || test == 3) {
+		void zzzmca(int);
+		printk("CPU %d: About to cause unexpected MCA\n", curcpu);
+		HDELAY(100000);
+		sgi_mcatest_bkpt();
+		do_sync(spos);
+
+		zzzmca(test-1);
+	
+		HDELAY(100000);
+	}
+
+	if (test == 4) {
+		long    result, adrs[] = {0xe0021000009821e0UL, 0xc0003f3000000000UL, 0xc0000081101c0000UL, 0xc00000180e021004UL,  0xc00000180e022004UL, 0xc00000180e023004UL };
+		long    size[] = {1,2,4,8};
+		int     r, i, j, k;
+
+		for (k=0; k<2; k++) {
+			for (i=0; i<6; i++) {
+				for (j=0; j<4; j++) {
+					printk("Probing 0x%lx, size %ld\n", adrs[i], size[j]);
+					result = -1;
+					r = ia64_sn_probe_io_slot (adrs[i], size[j], &result);
+					printk("    status %d, val 0x%lx\n", r, result);
+					udelay(100000);
+				}
 			}
 		}
+
 	}
-	if (mcatest == 2 || mcatest == 3) {
-		void zzzmca(int, int, int);
-		printk("About to cause unexpected MCA\n");
-		zzzmca(mcatest, 0x32dead, 0x33dead);
-	}
-	if (mcatest == 4) {
-		long	*p;
-		int	delivery_mode = 5;
-		printk("About to try to cause an INIT on cpu 0\n");
-		p = (long*)((0xc0000a0000000000LL | ((long)get_nasid())<<33) | 0x1800080);
-		*p = (delivery_mode << 8);
-		udelay(10000);
-		printk("Returned from INIT\n");
-	}
-	if (mcatest == 5) {
-		int zzzspec(long);
-		int	i;
-		long	psr, dcr, res, val, addr=0xff00000000UL;
-
-		dcr = ia64_get_dcr();
-		for (i=0; i<5; i++) {
-			printk("Default DCR: 0x%lx\n", ia64_get_dcr());
-			printk("zzzspec: 0x%x\n", zzzspec(addr));
-			ia64_set_dcr(0);
-			printk("New     DCR: 0x%lx\n", ia64_get_dcr());
-			printk("zzzspec: 0x%x\n", zzzspec(addr));
-			ia64_set_dcr(dcr);
-			res = ia64_sn_probe_io_slot(0xff00000000UL, 8, &val);
-			printk("zzzspec: probe %ld, 0x%lx\n", res, val);
-			psr = ia64_clear_ic();
-			ia64_itc(0x2, 0xe00000ff00000000UL,
-			          pte_val(mk_pte_phys(0xff00000000UL,
-				  __pgprot(__DIRTY_BITS|_PAGE_PL_0|_PAGE_AR_RW))), _PAGE_SIZE_256M);
-			ia64_set_psr(psr);
-			ia64_srlz_i ();
-		}
 
+	if (test == 5) {
+		cpu =  curcpu;
+		printk("CPU %d: About to send INIT to self (cpu %d)\n", curcpu, cpu);
+		HDELAY(100000);
+		sgi_mcatest_bkpt();
+		do_sync(spos);
+
+		platform_send_ipi(cpu, 0, IA64_IPI_DM_INIT, 0);
+		
+		HDELAY(100000);
+		printk("CPU %d: Returned from INIT\n", curcpu);
+	}
+
+	if (test == 6) {
+		cpu =  curcpu ^ 1;
+		printk("CPU %d: About to send INIT to other cpu (cpu %d)\n", curcpu, cpu);
+		HDELAY(100000);
+		sgi_mcatest_bkpt();
+		do_sync(spos);
+
+		platform_send_ipi(cpu, 0, IA64_IPI_DM_INIT, 0);
+
+		HDELAY(100000);
+		printk("CPU %d: Done\n", curcpu);
+	}
+
+	if (test == 7) {
+		printk("CPU %d: About to send INIT to non-existent cpu\n", curcpu);
+		HDELAY(100000);
+		sgi_mcatest_bkpt();
+		do_sync(spos);
+
+		sn_send_IPI_phys(0xffff, 0, IA64_IPI_DM_INIT);
+
+		HDELAY(100000);
+		printk("CPU %d: Done\n", curcpu);
 	}
-	if (mcatest == 6) {
-		int zzzspec(long);
-		int	i;
-		long	dcr, addr=0xe000000008000000UL;
-
-		dcr = ia64_get_dcr();
-		for (i=0; i<5; i++) {
-			printk("zzzspec: 0x%x\n", zzzspec(addr));
-			ia64_set_dcr(0);
-		}
-		ia64_set_dcr(dcr);
-	}
-	if (mcatest == 7) {
-		int zzzspec2(long, long);
-		int	i;
-		long	addr=0xe000000008000000UL;
-		long	addr2=0xe000000007000000UL;
-
-		for (i=0; i<5; i++) {
-			printk("zzzspec2\n");
-			zzzspec2(addr, addr2);
+
+	if (test == 10) {
+		n = IS_RUNNING_ON_SIMULATOR() ? 10 : 10000000;
+		cpu = 0;
+		printk("CPU %d: IPI stress test. Target cpu 0\n", curcpu);
+		HDELAY(100000);
+		sgi_mcatest_bkpt();
+		do_sync(spos);
+
+		for (i=0; i<n; i++)
+			platform_send_ipi(cpu, IA64_IPI_RESCHEDULE, IA64_IPI_DM_INT, 0);
+
+		HDELAY(100000);
+		printk("CPU %d: Done\n", curcpu);
+	}
+
+	if (test == 11) {
+		n = IS_RUNNING_ON_SIMULATOR() ? 100 : 10000000;
+		printk("CPU %d: IPI stress test. Target all cpus\n", curcpu);
+		HDELAY(100000);
+		sgi_mcatest_bkpt();
+		do_sync(spos);
+
+		for (i=0; i<n; i++)
+			for (cpu=0; cpu<smp_num_cpus; cpu++)
+				if (smp_num_cpus > 2 && cpu != curcpu)
+					platform_send_ipi(cpu, IA64_IPI_RESCHEDULE, IA64_IPI_DM_INT, 0);
+
+		HDELAY(100000);
+		printk("CPU %d: Done\n", curcpu);
+	}
+
+	if (test == 12) {
+		long adr = 0xe002200000000000UL;
+		n = IS_RUNNING_ON_SIMULATOR() ? 1000 : 100000;
+		printk("CPU %d: TLB flush stress test\n", curcpu);
+		HDELAY(100000);
+		sgi_mcatest_bkpt();
+		do_sync(spos);
+
+		for (i=0; i<n; i++)
+			platform_global_tlb_purge(adr, adr+25*PAGE_SIZE, 14);
+
+		HDELAY(100000);
+		printk("CPU %d: Done\n", curcpu);
+	}
+	
+	if (test == 13) {
+		printk("CPU %d: Park cpu in spinloop\n", curcpu);
+		while(1);
+	}
+	if (test == 14 || test == 15 || test == 16 || test == 17) {
+		long adr = 0xe002200000000000UL;
+		static int inited=0;
+		if (inited == 0) {
+			if (debug0 == 0) debug0 = 1;
+			repeat = 1;
+			do_sync(spos);
+			if (curcpu >= smp_num_cpus-2) {
+				printk("Parking cpu %d\n", curcpu);
+				local_irq_disable();
+				while(1);
+			} else {
+				printk("Waiting cpu %d\n", curcpu);
+				HDELAY(1000000);
+			}
+			HDELAY(1000000);
+			inited = 1;
+		}
+		if (test == 16 || test == 17) {
+			unsigned long t, shift, mask;
+			mask =  (smp_num_cpus > 16) ? 0x1f : 0xf;
+			shift = 25-debug1;
+			do {
+				t = get_cycles();
+				if (IS_RUNNING_ON_SIMULATOR())
+					t = (t>>8);
+				else
+					t = (t>>shift);
+				t = t & mask;
+			} while (t == curcpu);
+			do {
+				t = get_cycles();
+				if (IS_RUNNING_ON_SIMULATOR())
+					t = (t>>8);
+				else
+					t = (t>>shift);
+				t = t & mask;
+			} while (t != curcpu);
+		}
+		if(debug3) printk("CPU %d: One TLB start\n", curcpu);
+		if (test != 17) platform_global_tlb_purge(adr, adr+PAGE_SIZE*debug0, 14);
+		if(debug3) printk("CPU %d: One TLB flush done\n", curcpu);
+	}
+	if (test == 20) {
+		local_irq_disable();
+		set_led_bits(smp_processor_id(), 0xff);
+		while(1);
+	}
+	if (test == 21) {
+		extern long ia64_mca_stack[];
+		int		i, n;
+		volatile long	*p, *up;
+		p = (volatile long*)__imva(ia64_mca_stack);
+		up = (volatile long*)(__pa(p) | __IA64_UNCACHED_OFFSET);
+
+		if(!IS_RUNNING_ON_SIMULATOR()) printk("ZZZ get data in cache\n");
+		for (n=0, i=0; i<100; i++)
+			n += *(p+i);
+		if(!IS_RUNNING_ON_SIMULATOR()) printk("ZZZ Make uncached refs to same data\n");
+		for (n=0, i=0; i<100; i++)
+			n += *(up+i);
+		if(!IS_RUNNING_ON_SIMULATOR()) printk("ZZZ dirty the data via cached refs\n");
+		for (n=0, i=0; i<100; i++)
+			*(p+i) = i;
+		if(!IS_RUNNING_ON_SIMULATOR()) printk("ZZZ Make uncached refs to same data\n");
+		for (n=0, i=0; i<100; i++)
+			n += *(up+i);
+		if(!IS_RUNNING_ON_SIMULATOR()) printk("ZZZ Flushing cache\n");
+		for (n=0, i=0; i<100; i++)
+			ia64_fc((void*)(p+i));
+		printk("ZZZ done\n");
+	}
+	if (test == 21) {
+		int i;
+		volatile long tb, t[10];
+		for (i=0; i<10; i++) {
+			tb = debug3+ia64_get_itc();
+			sgi_mcatest_bkpt();
+			t[i] = ia64_get_itc() - tb;
+		}
+		for (i=0; i<10; i++) {
+			printk("ZZZ NULL  0x%lx\n", t[i]);
+		}
+		for (i=0; i<10; i++) {
+			tb = debug3+ia64_get_itc();
+			ia64_pal_call_static(PAL_MC_DRAIN, 0, 0, 0, 0);
+			t[i] = ia64_get_itc() - tb;
 		}
+		for (i=0; i<10; i++) {
+			printk("ZZZ DRAIN 0x%lx\n", t[i]);
+		}
+	}
+	if (test == 22) {
+		extern void machine_restart(char*);
+		printk("ZZZ machine_restart\n");
+		machine_restart(0);
 	}
+	if (test == 23) {
+		printk("ZZZ ia64_pal_halt_light\n");
+		ia64_pal_halt_light();
+	}
+	if (repeat)
+		goto again;
+
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/kernel/setup.c linux-2.4.21-pre6/arch/ia64/sn/kernel/setup.c
--- linux-2.4.20/arch/ia64/sn/kernel/setup.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/kernel/setup.c	2003-03-26 23:49:54.000000000 +0000
@@ -47,14 +47,14 @@
 #include <linux/bootmem.h>
 #include <linux/mmzone.h>
 #include <linux/interrupt.h>
+#include <linux/acpi.h>
+#include <linux/compiler.h>
+#include <linux/sched.h>
 
 #include <asm/io.h>
 #include <asm/sal.h>
 #include <asm/machvec.h>
 #include <asm/system.h>
-#ifdef CONFIG_IA64_MCA
-#include <asm/acpi-ext.h>
-#endif
 #include <asm/processor.h>
 #include <asm/sn/sgi.h>
 #include <asm/sn/io.h>
@@ -68,15 +68,21 @@
 #include <asm/sn/leds.h>
 #include <asm/sn/bte.h>
 #include <asm/sn/clksupport.h>
+#include <asm/sn/sn_sal.h>
 
 #ifdef CONFIG_IA64_SGI_SN2
 #include <asm/sn/sn2/shub.h>
 #endif
 
-extern void bte_init_node (nodepda_t *, cnodeid_t, char **);
+extern void bte_init_node (nodepda_t *, cnodeid_t);
 extern void bte_init_cpu (void);
 
-long sn_rtc_cycles_per_second;   
+unsigned long sn_rtc_cycles_per_second;   
+unsigned long sn_rtc_usec_per_cyc;
+
+partid_t sn_partid = -1;
+char sn_system_serial_number_string[128];
+u64 sn_partition_serial_number;
 
 /*
  * This is the address of the RRegs in the HSpace of the global
@@ -137,7 +143,7 @@
  * virt_to_page() (asm-ia64/page.h), among other things.
  */
 unsigned long
-sn_map_nr (unsigned long addr)
+sn_map_nr (void *addr)
 {
 	return MAP_NR_DISCONTIG(addr);
 }
@@ -149,10 +155,43 @@
  * for bringup, it's only called if %BRINGUP and %CONFIG_IA64_EARLY_PRINTK
  * are turned on.  See start_kernel() in init/main.c.
  */
-#if defined(CONFIG_IA64_EARLY_PRINTK) && defined(CONFIG_IA64_SGI_SN)
+#if defined(CONFIG_IA64_EARLY_PRINTK)
+
 void __init
 early_sn_setup(void)
 {
+	void ia64_sal_handler_init (void *entry_point, void *gpval);
+	efi_system_table_t			*efi_systab;
+	efi_config_table_t 			*config_tables;
+	struct ia64_sal_systab			*sal_systab;
+	struct ia64_sal_desc_entry_point	*ep;
+	char					*p;
+	int					i;
+
+	/*
+	 * Parse enough of the SAL tables to locate the SAL entry point. Since, console
+	 * IO on SN2 is done via SAL calls, early_printk wont work without this.
+	 *
+	 * This code duplicates some of the ACPI table parsing that is in efi.c & sal.c.
+	 * Any changes to those file may have to be made hereas well.
+	 */
+	efi_systab = (efi_system_table_t*)__va(ia64_boot_param->efi_systab);
+	config_tables = __va(efi_systab->tables);
+	for (i = 0; i < efi_systab->nr_tables; i++) {
+		if (efi_guidcmp(config_tables[i].guid, SAL_SYSTEM_TABLE_GUID) == 0) {
+			sal_systab = __va(config_tables[i].table);
+			p = (char*)(sal_systab+1);
+			for (i = 0; i < sal_systab->entry_count; i++) {
+				if (*p == SAL_DESC_ENTRY_POINT) {
+					ep = (struct ia64_sal_desc_entry_point *) p;
+					ia64_sal_handler_init(__va(ep->sal_proc), __va(ep->gp));
+					break;
+				}
+				p += SAL_DESC_SIZE(*p);
+			}
+		}
+	}
+
 	if ( IS_RUNNING_ON_SIMULATOR() ) {
 #if defined(CONFIG_IA64_SGI_SN1)
 		master_node_bedrock_address = (u64)REMOTE_HSPEC_ADDR(get_nasid(), 0);
@@ -162,18 +201,10 @@
 		printk(KERN_DEBUG "early_sn_setup: setting master_node_bedrock_address to 0x%lx\n", master_node_bedrock_address);
 	}
 }
-#endif /* CONFIG_IA64_EARLY_PRINTK && CONFIG_IA64_SGI_SN */
+#endif /* CONFIG_IA64_SGI_SN1 */
 
-#ifdef NOT_YET_CONFIG_IA64_MCA
-extern void ia64_mca_cpe_int_handler (int cpe_irq, void *arg, struct pt_regs *ptregs);
-static struct irqaction mca_cpe_irqaction = { 
-	handler:    ia64_mca_cpe_int_handler,
-	flags:      SA_INTERRUPT,
-	name:       "cpe_hndlr"
-};
-#endif
 #ifdef CONFIG_IA64_MCA
-extern int platform_irq_list[];
+extern int platform_intr_list[];
 #endif
 
 extern nasid_t master_nasid;
@@ -191,22 +222,56 @@
 {
 	long status, ticks_per_sec, drift;
 	int i;
+	int major = sn_sal_rev_major(), minor = sn_sal_rev_minor();
+
+	printk("SGI SAL version %x.%02x\n", major, minor);
+
+	/*
+	 * Confirm the SAL we're running on is recent enough...
+	 */
+	if ((major < SN_SAL_MIN_MAJOR) || (major == SN_SAL_MIN_MAJOR &&
+					   minor < SN_SAL_MIN_MINOR)) {
+		printk(KERN_ERR "This kernel needs SGI SAL version >= "
+		       "%x.%02x\n", SN_SAL_MIN_MAJOR, SN_SAL_MIN_MINOR);
+		panic("PROM version too old\n");
+	}
+
+#ifdef CONFIG_IA64_SGI_SN2
+	{
+		extern void io_sh_swapper(int, int);
+		io_sh_swapper(get_nasid(), 0);
+	}
+#endif
 
 	master_nasid = get_nasid();
 	(void)get_console_nasid();
+#ifndef CONFIG_IA64_SGI_SN1
+	{
+		extern nasid_t get_master_baseio_nasid(void);
+		(void)get_master_baseio_nasid();
+	}
+#endif
 
 	status = ia64_sal_freq_base(SAL_FREQ_BASE_REALTIME_CLOCK, &ticks_per_sec, &drift);
-	if (status != 0 || ticks_per_sec < 100000)
-		printk(KERN_WARNING "unable to determine platform RTC clock frequency\n");
+	if (status != 0 || ticks_per_sec < 100000) {
+		printk(KERN_WARNING "unable to determine platform RTC clock frequency, guessing.\n");
+		/* PROM gives wrong value for clock freq. so guess */
+		sn_rtc_cycles_per_second = 1000000000000UL/30000UL;
+	}
 	else
 		sn_rtc_cycles_per_second = ticks_per_sec;
+
+#ifdef CONFIG_IA64_SGI_SN1
+	/* PROM has wrong value on SN1 */
+	sn_rtc_cycles_per_second = 990177;
+#endif
+	sn_rtc_usec_per_cyc = ((1000000UL<<IA64_USEC_PER_CYC_SHIFT)
+			       + sn_rtc_cycles_per_second/2) / sn_rtc_cycles_per_second;
 		
 	for (i=0;i<NR_CPUS;i++)
 		_sn_irq_desc[i] = _irq_desc;
 
-#ifdef CONFIG_IA64_MCA
-	platform_irq_list[ACPI20_ENTRY_PIS_CPEI] = IA64_PCE_VECTOR;
-#endif
+	platform_intr_list[ACPI_INTERRUPT_CPEI] = IA64_PCE_VECTOR;
 
 
 	if ( IS_RUNNING_ON_SIMULATOR() )
@@ -296,7 +361,7 @@
 	 */
 	for (cnode = 0; cnode < numnodes; cnode++) {
 		init_platform_nodepda(nodepdaindr[cnode], cnode);
-		bte_init_node (nodepdaindr[cnode], cnode, cmdline_p);
+		bte_init_node (nodepdaindr[cnode], cnode);
 	}
 }
 
@@ -331,9 +396,16 @@
 	cnode = nasid_to_cnodeid(nasid);
 	slice = cpu_physical_id_to_slice(cpuphyid);
 
+	printk("CPU %d: nasid %d, slice %d, cnode %d\n",
+			smp_processor_id(), nasid, slice, cnode);
+
+	memset(&pda, 0, sizeof(pda));
 	pda.p_nodepda = nodepdaindr[cnode];
-	pda.led_address = (long*) (LED0 + (slice<<LED_CPU_SHIFT));
-	pda.led_state = 0;
+	pda.led_address = (typeof(pda.led_address)) (LED0 + (slice<<LED_CPU_SHIFT));
+#ifdef LED_WAR
+	pda.led_address = (typeof(pda.led_address)) (LED0 + (slice<<(LED_CPU_SHIFT-1))); /* temp til L1 firmware fixed */
+#endif
+	pda.led_state = LED_ALWAYS_SET;
 	pda.hb_count = HZ/2;
 	pda.hb_state = 0;
 	pda.idle_flag = 0;
@@ -359,9 +431,35 @@
 		irqpdaindr[cpuid] = alloc_bootmem_node(NODE_DATA(cpuid_to_cnodeid(cpuid)),sizeof(irqpda_t));
 	else
 		irqpdaindr[cpuid] = page_address(alloc_pages_node(local_cnodeid(), GFP_KERNEL, get_order(sizeof(irqpda_t))));
+
 	memset(irqpdaindr[cpuid], 0, sizeof(irqpda_t));
 	pda.p_irqpda = irqpdaindr[cpuid];
-	pda.pio_write_status_addr = (volatile unsigned long *)LOCAL_MMR_ADDR((slice < 2 ? SH_PIO_WRITE_STATUS_0 : SH_PIO_WRITE_STATUS_1 ) );
+
+	pda.pio_write_status_addr = (volatile unsigned long *)
+			LOCAL_MMR_ADDR((slice < 2 ? SH_PIO_WRITE_STATUS_0 : SH_PIO_WRITE_STATUS_1 ) );
+	pda.mem_write_status_addr = (volatile u64 *)
+			LOCAL_MMR_ADDR((slice < 2 ? SH_MEMORY_WRITE_STATUS_0 : SH_MEMORY_WRITE_STATUS_1 ) );
+
+	if (nodepda->node_first_cpu == cpuid) {
+		int	buddy_nasid;
+		buddy_nasid = cnodeid_to_nasid(local_cnodeid() == numnodes-1 ? 0 : local_cnodeid()+ 1);
+		pda.pio_shub_war_cam_addr = (volatile unsigned long*)GLOBAL_MMR_ADDR(nasid, SH_PI_CAM_CONTROL);
+	}
+
+#ifdef BRINGUP2
+	/*
+	 * Zero out the counters used for counting MCAs
+	 *   ZZZZZ temp
+	 */
+	{
+		long	*p;
+		p = (long*)LOCAL_MMR_ADDR(SH_XN_IILB_LB_CMP_ENABLE0);
+		*p = 0;
+		p = (long*)LOCAL_MMR_ADDR(SH_XN_IILB_LB_CMP_ENABLE1);
+		*p = 0;
+	}
+
+#endif
 #endif
 
 #ifdef CONFIG_IA64_SGI_SN1
@@ -401,7 +499,6 @@
 	return cpu;
 }
 
-#if 0 /* ##jh */
 /**
  * get_cycles - return a non-decreasing timestamp
  *
@@ -412,4 +509,186 @@
 {
 	return GET_RTC_COUNTER();
 }
+
+/**
+ * gettimeoffset - number of usecs elapsed since &xtime was last updated
+ *
+ * This function is used by do_gettimeofday() to determine the number
+ * of usecs that have elapsed since the last update to &xtime.  On SN
+ * this is accomplished using the RTC built in to each Hub chip; each
+ * is guaranteed to be synchronized by the PROM, so a local read will
+ * suffice (get_cycles() does this for us).  A snapshot of the RTC value
+ * is taken on every timer interrupt and this function more or less
+ * subtracts that snapshot value from the current value.
+ *
+ * Note that if a lot of processing was done during the last timer
+ * interrupt then &xtime may be some number of jiffies out of date.
+ * This function must account for that.
+ */
+unsigned long
+gettimeoffset(void)
+{
+	unsigned long current_rtc_val, local_last_rtc_val;
+	unsigned long usec;
+
+	local_last_rtc_val = last_rtc_val;
+	current_rtc_val = get_cycles();
+	usec = last_itc_lost_usec;
+
+	/* If the RTC has wrapped around, compensate */
+	if (unlikely(current_rtc_val < local_last_rtc_val)) {
+		printk(KERN_NOTICE "RTC wrapped cpu:%d current:0x%lx last:0x%lx\n",
+				smp_processor_id(), current_rtc_val,
+				local_last_rtc_val);
+		current_rtc_val += RTC_MASK;
+	}
+
+	usec += ((current_rtc_val - local_last_rtc_val)*sn_rtc_usec_per_cyc) >> 
+		IA64_USEC_PER_CYC_SHIFT;
+
+	/*
+	 * usec is the number of microseconds into the current clock interval. Every
+	 * clock tick, xtime is advanced by "tick" microseconds. If "usec"
+	 * is allowed to get larger than "tick", the time value returned by gettimeofday
+	 * will go backward.
+	 */
+	if (usec >= tick)
+		usec = tick-1;
+
+	return usec;
+}
+
+#ifdef II_PRTE_TLB_WAR
+long iiprt_lock[16*64] __cacheline_aligned; /* allow for NASIDs up to 64 */
+#endif
+
+#ifdef BUS_INT_WAR
+
+#include <asm/hw_irq.h>
+#include <asm/sn/pda.h>
+
+void ia64_handle_irq (ia64_vector vector, struct pt_regs *regs);
+
+static spinlock_t irq_lock = SPIN_LOCK_UNLOCKED;
+
+#define IRQCPU(irq)	((irq)>>8)
+
+void
+sn_add_polled_interrupt(int irq, int interval)
+{
+	unsigned long flags, irq_cnt;
+	sn_poll_entry_t	*irq_list;
+
+	irq_list = pdacpu(IRQCPU(irq)).pda_poll_entries;;
+
+	spin_lock_irqsave(&irq_lock, flags);
+	irq_cnt = pdacpu(IRQCPU(irq)).pda_poll_entry_count;
+	irq_list[irq_cnt].irq = irq;
+	irq_list[irq_cnt].interval = interval;
+	irq_list[irq_cnt].tick = interval;
+	pdacpu(IRQCPU(irq)).pda_poll_entry_count++;
+	spin_unlock_irqrestore(&irq_lock, flags);
+
+
+}
+
+void
+sn_delete_polled_interrupt(int irq)
+{
+	unsigned long flags, i, irq_cnt;
+	sn_poll_entry_t	*irq_list;
+
+	irq_list = pdacpu(IRQCPU(irq)).pda_poll_entries;
+
+	spin_lock_irqsave(&irq_lock, flags);
+	irq_cnt = pdacpu(IRQCPU(irq)).pda_poll_entry_count;
+	for (i=0; i<irq_cnt; i++) {
+		if (irq_list[i].irq == irq) {
+			irq_list[i] = irq_list[irq_cnt-1];
+			pdacpu(IRQCPU(irq)).pda_poll_entry_count--;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&irq_lock, flags);
+}
+
+long sn_int_poll_ticks=50;
+
+void
+sn_irq_poll(int cpu, int reason) 
+{
+	unsigned long flags, i;
+	sn_poll_entry_t	*irq_list;
+
+
+#ifdef CONFIG_SHUB_1_0_SPECIFIC
+	ia64_handle_irq(IA64_IPI_VECTOR, 0);
+#else
+	if (sn_int_poll_ticks == 0)
+		return;
+#endif
+	irq_list = pda.pda_poll_entries;
+
+	for (i=0; i<pda.pda_poll_entry_count; i++, irq_list++) {
+		if (--irq_list->tick <= 0) {
+#ifdef CONFIG_SHUB_1_0_SPECIFIC
+			irq_list->tick = irq_list->interval;
+#else
+			irq_list->tick = sn_int_poll_ticks;
+#endif
+			local_irq_save(flags);
+			ia64_handle_irq(irq_to_vector(irq_list->irq), 0);
+			local_irq_restore(flags);
+		}
+	}
+}	
+
+#define PROCFILENAME	"sn_int_poll_ticks"
+
+static struct proc_dir_entry *proc_op;
+
+
+static int
+read_proc(char *buffer, char **start, off_t off, int count, int *eof, void *data)
+{
+	int len = 0;
+
+	len += sprintf(buffer + len, "Poll hack: interval %ld ticks\n", sn_int_poll_ticks);
+
+	if (len <= off+count) *eof = 1;
+	*start = buffer + off;
+	len   -= off;
+	if (len>count) len = count;
+	if (len<0) len = 0;
+	return len;
+}
+
+static int
+write_proc (struct file *file, const char *userbuf, unsigned long count, void *data)
+{
+       extern long atoi(char *);
+       char        buf[80];
+
+       if (copy_from_user(buf, userbuf, count < sizeof(buf) ? count : sizeof(buf)))
+           return -EFAULT;
+
+       sn_int_poll_ticks = atoi(buf);
+
+       return count;
+}
+
+
+int __init
+sn_poll_init(void)
+{
+	if ((proc_op = create_proc_entry(PROCFILENAME, 0644, NULL)) == NULL) {
+		printk("%s: unable to create proc entry", PROCFILENAME);
+		return -1;
+	}
+	proc_op->read_proc = read_proc;
+	proc_op->write_proc = write_proc;
+	return 0;
+}
+
+module_init(sn_poll_init);
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/kernel/sn1/Makefile linux-2.4.21-pre6/arch/ia64/sn/kernel/sn1/Makefile
--- linux-2.4.20/arch/ia64/sn/kernel/sn1/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/kernel/sn1/Makefile	2003-03-26 23:49:00.000000000 +0000
@@ -1,5 +1,5 @@
 #
-# ia64/platform/sn/sn1/Makefile
+# arch/ia64/sn/kernel/sn1/Makefile
 #
 # Copyright (C) 1999,2001-2002 Silicon Graphics, Inc. All rights reserved.
 #
@@ -40,12 +40,8 @@
 .S.o:
 	$(CC) $(AFLAGS) $(AFLAGS_KERNEL) -c -o $*.o $<
 
-all: sn1.a
-
-O_TARGET        = sn1.a
+O_TARGET        = sn1.o
 
 obj-y          = cache.o error.o iomv.o synergy.o sn1_smp.o
 
-clean::
-
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/kernel/sn1/sn1_smp.c linux-2.4.21-pre6/arch/ia64/sn/kernel/sn1/sn1_smp.c
--- linux-2.4.20/arch/ia64/sn/kernel/sn1/sn1_smp.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/kernel/sn1/sn1_smp.c	2003-03-26 23:49:09.000000000 +0000
@@ -59,11 +59,16 @@
  * to other cpus for flushing TLB ranges.
  */
 typedef struct {
-	unsigned long	start;
-	unsigned long	end;
-	unsigned long	nbits;
-	unsigned int	rid;
-	atomic_t	unfinished_count;
+	union {
+		struct {
+			unsigned long	start;
+			unsigned long	end;
+			unsigned long	nbits;
+			unsigned int	rid;
+			atomic_t	unfinished_count;
+		} ptc;
+		char pad[SMP_CACHE_BYTES];
+	};
 } ptc_params_t;
 
 #define NUMPTC	512
@@ -149,11 +154,11 @@
 		return;
 
 	do {
-		start = ptcParams->start;
+		start = ptcParams->ptc.start;
 		saved_rid = (unsigned int) ia64_get_rr(start);
-		end = ptcParams->end;
-		nbits = ptcParams->nbits;
-		rid = ptcParams->rid;
+		end = ptcParams->ptc.end;
+		nbits = ptcParams->ptc.nbits;
+		rid = ptcParams->ptc.rid;
 
 		if (saved_rid != rid) {
 			ia64_set_rr(start, (unsigned long)rid);
@@ -167,7 +172,7 @@
 
 		ia64_srlz_i();
 
-		result = atomic_dec(&ptcParams->unfinished_count);
+		result = atomic_dec(&ptcParams->ptc.unfinished_count);
 #ifdef PTCDEBUG
 		{
 		    int i = ptcParams-&ptcParamArray[0];
@@ -256,7 +261,7 @@
 		/* check the current pointer to the beginning */
 		ptr = params;
 		while(--ptr >= &ptcParamArray[0]) {
-			if (atomic_read(&ptr->unfinished_count) == 0)
+			if (atomic_read(&ptr->ptc.unfinished_count) == 0)
 				break;
 			++backlog;
 		}
@@ -265,7 +270,7 @@
 			/* check the end of the array */
 			ptr = &ptcParamArray[NUMPTC];
 			while (--ptr > params) {
-				if (atomic_read(&ptr->unfinished_count) == 0)
+				if (atomic_read(&ptr->ptc.unfinished_count) == 0)
 					break;
 				++backlog;
 			}
@@ -275,12 +280,12 @@
 #endif	/* PTCDEBUG */
 
 	/* wait for the next entry to clear...should be rare */
-	if (atomic_read(&next->unfinished_count) > 0) {
+	if (atomic_read(&next->ptc.unfinished_count) > 0) {
 #ifdef PTCDEBUG
 		ptcParamsAllBusy++;
 
-		if (atomic_read(&nextnext->unfinished_count) == 0) {
-		    if (atomic_read(&next->unfinished_count) > 0) {
+		if (atomic_read(&nextnext->ptc.unfinished_count) == 0) {
+		    if (atomic_read(&next->ptc.unfinished_count) > 0) {
 			panic("\nnonzero next zero nextnext %lx %lx\n",
 			    (long)next, (long)nextnext);
 		    }
@@ -293,16 +298,16 @@
 		local_irq_restore(irqflags);
 
 		/* now we know it's not this cpu, so just wait */
-		while (atomic_read(&next->unfinished_count) > 0) {
+		while (atomic_read(&next->ptc.unfinished_count) > 0) {
 			barrier();
 		}
 	}
 
-	params->start = start;
-	params->end = end;
-	params->nbits = nbits;
-	params->rid = (unsigned int) ia64_get_rr(start);
-	atomic_set(&params->unfinished_count, smp_num_cpus);
+	params->ptc.start = start;
+	params->ptc.end = end;
+	params->ptc.nbits = nbits;
+	params->ptc.rid = (unsigned int) ia64_get_rr(start);
+	atomic_set(&params->ptc.unfinished_count, smp_num_cpus);
 
 	/* The atomic_set above can hit memory *after* the update
 	 * to ptcParamsEmpty below, which opens a timing window
@@ -335,13 +340,11 @@
 	 * shouldn't be using user TLB entries.  To change this to wait
 	 * for all the flushes to complete, enable the following code.
 	 */
-#ifdef SN1_SYNCHRONOUS_GLOBAL_TLB_PURGE
+#if defined(SN1_SYNCHRONOUS_GLOBAL_TLB_PURGE) || defined(BUS_INT_WAR)
 	/* this code is not tested */
 	/* wait for the flush to complete */
-	while (atomic_read(&params.unfinished_count) > 1)
+	while (atomic_read(&params->ptc.unfinished_count) > 0)
 		barrier();
-
-	atomic_set(&params->unfinished_count, 0);
 #endif
 }
 
@@ -369,18 +372,17 @@
 
 	static int 	off[4] = {0x1800080, 0x1800088, 0x1a00080, 0x1a00088};
 
+#ifdef BUS_INT_WAR
+	if (vector != ap_wakeup_vector) {
+		return;
+	}
+#endif
+
 	nasid = cpu_physical_id_to_nasid(physid);
         slice = cpu_physical_id_to_slice(physid);
 
 	p = (long*)(0xc0000a0000000000LL | (nasid<<33) | off[slice]);
 
-#if defined(ZZZBRINGUP)
-	{
-	static int count=0;
-	if (count++ < 10) printk("ZZ sendIPI 0x%x vec %d, nasid 0x%lx, slice %ld, adr 0x%lx\n",
-		smp_processor_id(), vector, nasid, slice, (long)p);
-	}
-#endif
 	mb();
 	*p = (delivery_mode << 8) | (vector & 0xff);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/kernel/sn1/synergy.c linux-2.4.21-pre6/arch/ia64/sn/kernel/sn1/synergy.c
--- linux-2.4.20/arch/ia64/sn/kernel/sn1/synergy.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/kernel/sn1/synergy.c	2003-03-26 23:49:18.000000000 +0000
@@ -240,6 +240,7 @@
 	synergy_perf_t	*p;
 	int		checked = 0;
 	int		err = 0;
+	unsigned long	flags;
 
 	/* bit 45 is enable */
 	modesel |= (1UL << 45);
@@ -279,7 +280,7 @@
 			memset(p, 0, sizeof(synergy_perf_t));
 			p->modesel = modesel;
 
-			spin_lock_irq(&npdap->synergy_perf_lock);
+			spin_lock_irqsave(&npdap->synergy_perf_lock, flags);
 			if (npdap->synergy_perf_data == NULL) {
 				/* circular list */
 				p->next = p;
@@ -290,7 +291,7 @@
 				p->next = npdap->synergy_perf_data->next;
 				npdap->synergy_perf_data->next = p;
 			}
-			spin_unlock_irq(&npdap->synergy_perf_lock);
+			spin_unlock_irqrestore(&npdap->synergy_perf_lock, flags);
 		}
 	}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/kernel/sn2/Makefile linux-2.4.21-pre6/arch/ia64/sn/kernel/sn2/Makefile
--- linux-2.4.20/arch/ia64/sn/kernel/sn2/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/kernel/sn2/Makefile	2003-03-26 23:49:54.000000000 +0000
@@ -1,5 +1,5 @@
 #
-# ia64/platform/sn/sn1/Makefile
+# arch/ia64/sn/kernel/sn2/Makefile
 #
 # Copyright (C) 1999,2001-2002 Silicon Graphics, Inc. All rights reserved.
 #
@@ -40,12 +40,8 @@
 .S.o:
 	$(CC) $(AFLAGS) $(AFLAGS_KERNEL) -c -o $*.o $<
 
-all: sn2.a
+O_TARGET        = sn2.o
 
-O_TARGET        = sn2.a
-
-obj-y          = cache.o iomv.o sn2_smp.o
-
-clean::
+obj-y          = cache.o iomv.o ptc_deadlock.o sn2_smp.o sn_proc_fs.o
 
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/kernel/sn2/iomv.c linux-2.4.21-pre6/arch/ia64/sn/kernel/sn2/iomv.c
--- linux-2.4.20/arch/ia64/sn/kernel/sn2/iomv.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/kernel/sn2/iomv.c	2003-03-26 23:49:35.000000000 +0000
@@ -56,10 +56,13 @@
  * a chipset register to ensure ordering.
  *
  * On SN2, we wait for the PIO_WRITE_STATUS SHub register to clear.
+ * See PV 871084 for details about the WAR about zero value.
+ *
  */
 void
 sn2_mmiob (void)
 {
-	while ( !((volatile unsigned long) (*pda.pio_write_status_addr)) & 0x8000000000000000)
-		udelay(5);
+	while ((((volatile unsigned long) (*pda.pio_write_status_addr)) & SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT_MASK) != 
+				SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT_MASK)
+		udelay(1);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/kernel/sn2/ptc_deadlock.S linux-2.4.21-pre6/arch/ia64/sn/kernel/sn2/ptc_deadlock.S
--- linux-2.4.20/arch/ia64/sn/kernel/sn2/ptc_deadlock.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/kernel/sn2/ptc_deadlock.S	2003-03-26 23:49:15.000000000 +0000
@@ -0,0 +1,80 @@
+/* 
+ * 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-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#include <asm/sn/sn2/shub_mmr.h>
+
+#define ZEROVAL		0x3f		// "zero" value for outstanding PIO requests
+#define DEADLOCKBIT	SH_PIO_WRITE_STATUS_0_WRITE_DEADLOCK_SHFT
+#define WRITECOUNT	SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT_SHFT
+#define ALIAS_OFFSET	(SH_PIO_WRITE_STATUS_0_ALIAS-SH_PIO_WRITE_STATUS_0)
+
+
+	.global	sn2_ptc_deadlock_recovery_core
+	.proc  	sn2_ptc_deadlock_recovery_core
+
+sn2_ptc_deadlock_recovery_core:
+	.regstk 5,0,0,0
+
+	ptc0  	 = in0
+	data0 	 = in1
+	ptc1  	 = in2
+	data1 	 = in3
+	piowc 	 = in4
+	piowcphy = r30
+	psrsave  = r2
+	zeroval  = r3
+	scr1	 = r16
+	scr2	 = r17
+
+
+	extr.u	piowcphy=piowc,0,61;;	// Convert piowc to uncached physical address
+	dep	piowcphy=-1,piowcphy,63,1
+
+	mov	zeroval=ZEROVAL		// "zero" value for PIO write count
+
+1:
+	add	scr2=ALIAS_OFFSET,piowc	// Address of WRITE_STATUS alias register 
+	mov	scr1=7;;		// Clear DEADLOCK, WRITE_ERROR, MULTI_WRITE_ERROR
+	st8.rel	[scr2]=scr1;;
+
+5:	ld8.acq	scr1=[piowc];;		// Wait for PIOs to complete.
+	extr.u	scr2=scr1,WRITECOUNT,7;;// PIO count
+	cmp.ne	p6,p0=zeroval,scr2
+(p6)	br.cond.sptk 5b
+	
+
+
+	////////////// BEGIN PHYSICAL MODE ////////////////////
+	mov psrsave=psr			// Disable IC (no PMIs)
+	rsm psr.i | psr.dt | psr.ic;;
+	srlz.i;;
+
+	st8.rel [ptc0]=data0		// Write PTC0 & wait for completion.
+
+5:	ld8.acq	scr1=[piowcphy];;	// Wait for PIOs to complete.
+	extr.u	scr2=scr1,WRITECOUNT,7;;// PIO count
+	cmp.ne	p6,p0=zeroval,scr2
+(p6)	br.cond.sptk 5b;;
+
+	tbit.nz	p6,p7=scr1,DEADLOCKBIT;;// Test for DEADLOCK
+	
+(p7)	st8.rel [ptc1]=data1;;		// Now write PTC1.
+
+	mov psr.l=psrsave;;		// Reenable IC
+	srlz.i;;
+	////////////// END   PHYSICAL MODE ////////////////////
+
+(p6)	br.cond.spnt 1b;;		// Repeat if DEADLOCK occurred.
+
+5:	ld8.acq	scr1=[piowc];;		// Wait for PIOs to complete.
+	extr.u	scr2=scr1,WRITECOUNT,7;;// PIO count
+	cmp.ne	p6,p0=zeroval,scr2
+(p6)	br.cond.sptk 5b
+	
+	br.ret.sptk	rp
+	.endp sn2_ptc_deadlock_recovery_core
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/kernel/sn2/sn2_smp.c linux-2.4.21-pre6/arch/ia64/sn/kernel/sn2/sn2_smp.c
--- linux-2.4.20/arch/ia64/sn/kernel/sn2/sn2_smp.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/kernel/sn2/sn2_smp.c	2003-03-26 23:49:00.000000000 +0000
@@ -46,6 +46,7 @@
 #include <asm/irq.h>
 #include <asm/sal.h>
 #include <asm/system.h>
+#include <asm/delay.h>
 #include <asm/io.h>
 #include <asm/smp.h>
 #include <asm/hw_irq.h>
@@ -53,6 +54,322 @@
 #include <asm/sn/sn_cpuid.h>
 #include <asm/sn/addrs.h>
 #include <asm/sn/sn2/shub_mmr.h>
+#include <asm/sn/nodepda.h>
+#include <asm/sn/rw_mmr.h>
+
+void sn2_ptc_deadlock_recovery(unsigned long data0, unsigned long data1);
+
+
+static spinlock_t sn2_global_ptc_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED;
+
+static unsigned long sn2_ptc_deadlock_count;
+
+
+static inline unsigned long
+wait_piowc(void)
+{
+	volatile unsigned long *piows;
+	unsigned long	ws;
+
+	piows = pda.pio_write_status_addr;
+	do {
+		__asm__ __volatile__ ("mf.a" ::: "memory");
+	} while (((ws = *piows) & SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT_MASK) != 
+			SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT_MASK);
+	return ws;
+}
+
+static long use_tlb_hack;
+static volatile unsigned long zz[1024] __attribute__((__aligned__(128)));
+static inline long
+get_itc(void)
+{
+        long ret;                                                                                                           
+        __asm__ __volatile__ ("mov %0=ar.itc" : "=r"(ret));
+        return ret+1;
+}                                                                                                                           
+
+
+
+#ifdef PTCG_WAR
+/*
+ * The following structure is used to pass params thru smp_call_function
+ * to other cpus for flushing TLB ranges.
+ */
+typedef struct {
+	unsigned long	start;
+	unsigned long	end;
+	unsigned long	nbits;
+	unsigned int	rid;
+	atomic_t	unfinished_count;
+	char		fill[96];
+} ptc_params_t;
+
+#define NUMPTC	512
+
+static ptc_params_t	ptcParamArray[NUMPTC] __attribute__((__aligned__(128)));
+
+/* use separate cache lines on ptcParamsNextByCpu to avoid false sharing */
+static ptc_params_t	*ptcParamsNextByCpu[NR_CPUS*16] __attribute__((__aligned__(128)));
+static volatile ptc_params_t	*ptcParamsEmpty __cacheline_aligned;
+
+/*REFERENCED*/
+static spinlock_t ptcParamsLock __cacheline_aligned = SPIN_LOCK_UNLOCKED;
+
+static int ptcInit = 0;
+#ifdef PTCDEBUG
+static int ptcParamsAllBusy = 0;		/* debugging/statistics */
+static int ptcCountBacklog = 0;
+static int ptcBacklog[NUMPTC+1];
+static char ptcParamsCounts[NR_CPUS][NUMPTC] __attribute__((__aligned__(128)));
+static char ptcParamsResults[NR_CPUS][NUMPTC] __attribute__((__aligned__(128)));
+#endif
+
+/*
+ * Make smp_send_flush_tlbsmp_send_flush_tlb() a weak reference,
+ * so that we get a clean compile with the ia64 patch without the
+ * actual SN1 specific code in arch/ia64/kernel/smp.c.
+ */
+extern void smp_send_flush_tlb (void) __attribute((weak));
+
+
+/**
+ * sn1_ptc_l_range - purge local translation cache
+ * @start: start of virtual address range
+ * @end: end of virtual address range
+ * @nbits: specifies number of bytes to purge per instruction (num = 1<<(nbits & 0xfc))
+ *
+ * Purges the range specified from the local processor's translation cache
+ * (as opposed to the translation registers).  Note that more than the specified
+ * range *may* be cleared from the cache by some processors.
+ *
+ * This is probably not good enough, but I don't want to try to make it better 
+ * until I get some statistics on a running system. At a minimum, we should only 
+ * send IPIs to 1 processor in each TLB domain & have it issue a ptc.g on it's 
+ * own FSB. Also, we only have to serialize per FSB, not globally.
+ *
+ * More likely, we will have to do some work to reduce the frequency of calls to
+ * this routine.
+ */
+static inline void
+sn1_ptc_l_range(unsigned long start, unsigned long end, unsigned long nbits)
+{
+	do {
+		__asm__ __volatile__ ("ptc.l %0,%1" :: "r"(start), "r"(nbits<<2) : "memory");
+		start += (1UL << nbits);
+	} while (start < end);
+	ia64_srlz_d();
+}
+
+/**
+ * sn1_received_flush_tlb - cpu tlb flush routine
+ *
+ * Flushes the TLB of a given processor.
+ */
+void
+sn1_received_flush_tlb(void)
+{
+	unsigned long	start, end, nbits;
+	unsigned int	rid, saved_rid;
+	int		cpu = smp_processor_id();
+	int		result;
+	ptc_params_t	*ptcParams;
+
+	ptcParams = ptcParamsNextByCpu[cpu*16];
+	if (ptcParams == ptcParamsEmpty)
+		return;
+
+	do {
+		start = ptcParams->start;
+		saved_rid = (unsigned int) ia64_get_rr(start);
+		end = ptcParams->end;
+		nbits = ptcParams->nbits;
+		rid = ptcParams->rid;
+
+		if (saved_rid != rid) {
+			ia64_set_rr(start, (unsigned long)rid);
+			ia64_srlz_d();
+		}
+
+		sn1_ptc_l_range(start, end, nbits);
+
+		if (saved_rid != rid) 
+			ia64_set_rr(start, (unsigned long)saved_rid);
+
+		ia64_srlz_i();
+
+		result = atomic_dec(&ptcParams->unfinished_count);
+#ifdef PTCDEBUG
+		{
+		    int i = ptcParams-&ptcParamArray[0];
+		    ptcParamsResults[cpu][i] = (char) result;
+		    ptcParamsCounts[cpu][i]++;
+		}
+#endif /* PTCDEBUG */
+
+		if (++ptcParams == &ptcParamArray[NUMPTC])
+			ptcParams = &ptcParamArray[0];
+
+	} while (ptcParams != ptcParamsEmpty);
+
+	ptcParamsNextByCpu[cpu*16] = ptcParams;
+}
+
+/**
+ * sn1_global_tlb_purge - flush a translation cache range on all processors
+ * @start: start of virtual address range to flush
+ * @end: end of virtual address range
+ * @nbits: specifies number of bytes to purge per instruction (num = 1<<(nbits & 0xfc))
+ *
+ * Flushes the translation cache of all processors from @start to @end.
+ */
+void
+sn1_global_tlb_purge (unsigned long start, unsigned long end, unsigned long nbits)
+{
+	ptc_params_t	*params;
+	ptc_params_t	*next;
+	unsigned long	irqflags;
+#ifdef PTCDEBUG
+	ptc_params_t	*nextnext;
+	int		backlog = 0;
+#endif
+
+	if (smp_num_cpus == 1) {
+		sn1_ptc_l_range(start, end, nbits);
+		return;
+	}
+
+	if (in_interrupt()) {
+		/*
+		 *  If at interrupt level and cannot get spinlock, 
+		 *  then do something useful by flushing own tlbflush queue
+		 *  so as to avoid a possible deadlock.
+		 */
+		while (!spin_trylock(&ptcParamsLock)) {
+			local_irq_save(irqflags);
+			sn1_received_flush_tlb();
+			local_irq_restore(irqflags);
+			udelay(10);	/* take it easier on the bus */	
+		}
+	} else {
+		spin_lock(&ptcParamsLock);
+	}
+
+	if (!ptcInit) {
+		int cpu;
+		ptcInit = 1;
+		memset(ptcParamArray, 0, sizeof(ptcParamArray));
+		ptcParamsEmpty = &ptcParamArray[0];
+		for (cpu=0; cpu<NR_CPUS; cpu++)
+			ptcParamsNextByCpu[cpu*16] = &ptcParamArray[0];
+
+#ifdef PTCDEBUG
+		memset(ptcBacklog, 0, sizeof(ptcBacklog));
+		memset(ptcParamsCounts, 0, sizeof(ptcParamsCounts));
+		memset(ptcParamsResults, 0, sizeof(ptcParamsResults));
+#endif	/* PTCDEBUG */
+	}
+
+	params = (ptc_params_t *) ptcParamsEmpty;
+	next = (ptc_params_t *) ptcParamsEmpty + 1;
+	if (next == &ptcParamArray[NUMPTC])
+		next = &ptcParamArray[0];
+
+#ifdef PTCDEBUG
+	nextnext = next + 1;
+	if (nextnext == &ptcParamArray[NUMPTC])
+		nextnext = &ptcParamArray[0];
+
+	if (ptcCountBacklog) {
+		/* quick count of backlog */
+		ptc_params_t *ptr;
+
+		/* check the current pointer to the beginning */
+		ptr = params;
+		while(--ptr >= &ptcParamArray[0]) {
+			if (atomic_read(&ptr->unfinished_count) == 0)
+				break;
+			++backlog;
+		}
+
+		if (backlog) {
+			/* check the end of the array */
+			ptr = &ptcParamArray[NUMPTC];
+			while (--ptr > params) {
+				if (atomic_read(&ptr->unfinished_count) == 0)
+					break;
+				++backlog;
+			}
+		}
+		ptcBacklog[backlog]++;
+	}
+#endif	/* PTCDEBUG */
+
+	/* wait for the next entry to clear...should be rare */
+	if (atomic_read(&next->unfinished_count) > 0) {
+#ifdef PTCDEBUG
+		ptcParamsAllBusy++;
+
+		if (atomic_read(&nextnext->unfinished_count) == 0) {
+		    if (atomic_read(&next->unfinished_count) > 0) {
+			panic("\nnonzero next zero nextnext %lx %lx\n",
+			    (long)next, (long)nextnext);
+		    }
+		}
+#endif
+
+		/* it could be this cpu that is behind */
+		local_irq_save(irqflags);
+		sn1_received_flush_tlb();
+		local_irq_restore(irqflags);
+
+		/* now we know it's not this cpu, so just wait */
+		while (atomic_read(&next->unfinished_count) > 0) {
+			barrier();
+		}
+	}
+
+	params->start = start;
+	params->end = end;
+	params->nbits = nbits;
+	params->rid = (unsigned int) ia64_get_rr(start);
+	atomic_set(&params->unfinished_count, smp_num_cpus);
+
+	/* The atomic_set above can hit memory *after* the update
+	 * to ptcParamsEmpty below, which opens a timing window
+	 * that other cpus can squeeze into!
+	 */
+	mb();
+
+	/* everything is ready to process:
+	 *	-- global lock is held
+	 *	-- new entry + 1 is free
+	 *	-- new entry is set up
+	 * so now:
+	 *	-- update the global next pointer
+	 *	-- unlock the global lock
+	 *	-- send IPI to notify other cpus
+	 *	-- process the data ourselves
+	 */
+	ptcParamsEmpty = next;
+	spin_unlock(&ptcParamsLock);
+	smp_send_flush_tlb();
+
+	local_irq_save(irqflags);
+	sn1_received_flush_tlb();
+	local_irq_restore(irqflags);
+
+	/* 
+	 * Since IPIs are polled event (for now), we need to wait til the
+	 * TLB flush has started.
+	 * wait for the flush to complete 
+	 */ 
+	while (atomic_read(&params->unfinished_count) > 0)
+		barrier();
+}
+
+#endif /* PTCG_WAR */
+
 
 /**
  * sn2_global_tlb_purge - globally purge translation cache of virtual address range
@@ -63,42 +380,116 @@
  * Purges the translation caches of all processors of the given virtual address
  * range.
  */
+
 void
 sn2_global_tlb_purge (unsigned long start, unsigned long end, unsigned long nbits)
 {
-	int		cnode, nasid;
-	volatile long	*ptc0, *ptc1, *piows;
-	unsigned long	ws, next, data0, data1;
-
-	piows = (long*)LOCAL_MMR_ADDR(get_slice() ? SH_PIO_WRITE_STATUS_1 : SH_PIO_WRITE_STATUS_0);
+	int			cnode, mycnode, nasid;
+	volatile unsigned	long	*ptc0, *ptc1;
+	unsigned long		flags=0, data0, data1;
+	long 		        zzbase, zztime, zztime2;
+
+	/*
+	 * Special case 1 cpu & 1 node. Use local purges.
+	 */
+#ifdef PTCG_WAR
+	sn1_global_tlb_purge(start, end, nbits);
+	return;
+#endif /* PTCG_WAR */
+		
 	data0 = (1UL<<SH_PTC_0_A_SHFT) |
 		(nbits<<SH_PTC_0_PS_SHFT) |
 		((ia64_get_rr(start)>>8)<<SH_PTC_0_RID_SHFT) |
 		(1UL<<SH_PTC_0_START_SHFT);
 
-	ptc0 = (long*)GLOBAL_MMR_ADDR(0, SH_PTC_0);
-	ptc1 = (long*)GLOBAL_MMR_ADDR(0, SH_PTC_1);
+	ptc0 = (long*)GLOBAL_MMR_PHYS_ADDR(0, SH_PTC_0);
+	ptc1 = (long*)GLOBAL_MMR_PHYS_ADDR(0, SH_PTC_1);
+
+	mycnode = local_cnodeid();
+
+	/* 
+	 * For now, we dont want to spin uninterruptibly waiting
+	 * for the lock. Makes hangs hard to debug.
+	 */
+	zzbase = smp_processor_id()*16;
+	zz[zzbase+0] += 0x0000ffff00000001UL;
+
+	local_irq_save(flags);
+	zztime = get_itc();     
+	spin_lock(&sn2_global_ptc_lock);
+	zz[zzbase+0] += 0xffff000000000000UL;
+	zztime2 = get_itc();     
+
 	do {
-		*(piows+1) = -1;	/* use alias address to clear bits*/
-		next = start;
-		do {
-			for (cnode = 0; cnode < numnodes; cnode++) {
+		data1 = start | (1UL<<SH_PTC_1_START_SHFT);
+		for (cnode = 0; cnode < numnodes; cnode++) {
+			if (is_headless_node(cnode))
+				continue;
+			if (cnode == mycnode) {
+				asm volatile ("ptc.ga %0,%1;;srlz.i;;" :: "r"(start), "r"(nbits<<2) : "memory");
+			} else {
 				nasid = cnodeid_to_nasid(cnode);
 				ptc0 = CHANGE_NASID(nasid, ptc0);
 				ptc1 = CHANGE_NASID(nasid, ptc1);
-				data1 = next | (1UL<<SH_PTC_1_START_SHFT);
-				*ptc0 = data0;
-				*ptc1 = data1;
+				pio_atomic_phys_write_mmrs(ptc0, data0, ptc1, data1);
 			}
-			next += (1UL << nbits);
-		} while (next < end);
+		}
 
-		while ((ws = *piows) & SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT_MASK)
-			;
+		if (wait_piowc() & SH_PIO_WRITE_STATUS_0_WRITE_DEADLOCK_MASK) {
+			zz[zzbase+1]++;
+			sn2_ptc_deadlock_recovery(data0, data1);
+		}
 
-	} while (ws & SH_PIO_WRITE_STATUS_0_WRITE_DEADLOCK_MASK);
+		start += (1UL << nbits);
+
+	} while (start < end);
+
+	zz[zzbase+0] -= 0xffffffff00000000UL;   
+	zztime2 = get_itc() - zztime2;    
+	spin_unlock_irqrestore(&sn2_global_ptc_lock, flags);
+
+	zztime = get_itc() - zztime;    
+
+	zz[zzbase+6] += zztime;                                                                                             
+	if (zztime > zz[zzbase+7])
+	       zz[zzbase+7] = zztime; 
+
+	zz[zzbase+8] += zztime2;                                                                                             
+	if (zztime2 > zz[zzbase+9])
+	       zz[zzbase+9] = zztime2; 
 
-	
+}
+
+/*
+ * sn2_ptc_deadlock_recovery
+ *
+ * Recover from PTC deadlocks conditions. Recovery requires stepping thru each 
+ * TLB flush transaction.  The recovery sequence is somewhat tricky & is
+ * coded in assembly language.
+ */
+void
+sn2_ptc_deadlock_recovery(unsigned long data0, unsigned long data1)
+{
+	extern void sn2_ptc_deadlock_recovery_core(long*, long, long*, long, long*);
+	int	cnode, mycnode, nasid;
+	long	*ptc0, *ptc1, *piows;
+
+	sn2_ptc_deadlock_count++;
+
+	ptc0 = (long*)GLOBAL_MMR_PHYS_ADDR(0, SH_PTC_0);
+	ptc1 = (long*)GLOBAL_MMR_PHYS_ADDR(0, SH_PTC_1);
+	piows = (long*)pda.pio_write_status_addr;
+
+	mycnode = local_cnodeid();
+
+	for (cnode = 0; cnode < numnodes; cnode++) {
+		if (is_headless_node(cnode) || cnode == mycnode)
+			continue;
+		nasid = cnodeid_to_nasid(cnode);
+		ptc0 = CHANGE_NASID(nasid, ptc0);
+		ptc1 = CHANGE_NASID(nasid, ptc1);
+		sn2_ptc_deadlock_recovery_core(ptc0, data0, ptc1, data1, piows);
+	}
 }
 
 /**
@@ -121,28 +512,32 @@
 sn_send_IPI_phys(long physid, int vector, int delivery_mode)
 {
 	long		nasid, slice;
-	long		*p, val;
+	long		val;
+	volatile long	*p;
+
+#if defined(BUS_INT_WAR) && defined(CONFIG_SHUB_1_0_SPECIFIC)
+	if (vector != ap_wakeup_vector && delivery_mode == IA64_IPI_DM_INT) {
+		return;
+	}
+#endif
 
 	nasid = cpu_physical_id_to_nasid(physid);
         slice = cpu_physical_id_to_slice(physid);
 
-	p = (long*)GLOBAL_MMR_ADDR(nasid, SH_IPI_INT);
+	p = (long*)GLOBAL_MMR_PHYS_ADDR(nasid, SH_IPI_INT);
 	val =   (1UL<<SH_IPI_INT_SEND_SHFT) | 
 		(physid<<SH_IPI_INT_PID_SHFT) | 
 	        ((long)delivery_mode<<SH_IPI_INT_TYPE_SHFT) | 
 		((long)vector<<SH_IPI_INT_IDX_SHFT) |
 		(0x000feeUL<<SH_IPI_INT_BASE_SHFT);
 
-#if defined(BRINGUP)
-	{
-	static int count=0;
-	if (count++ < 10) printk("ZZ sendIPI 0x%x vec %d, nasid 0x%lx, slice %ld, adr 0x%lx, val 0x%lx\n",
-		smp_processor_id(), vector, nasid, slice, (long)p, val);
-	}
-#endif
 	mb();
-	*p = val;
-	
+	pio_phys_write_mmr(p, val);
+
+#ifndef CONFIG_SHUB_1_0_SPECIFIC
+	/* doesnt work on shub 1.0 */
+	wait_piowc();
+#endif
 }
 
 /**
@@ -172,13 +567,131 @@
 }
 
 
-/**
- * init_sn2_smp_config - initialize SN2 smp configuration
- *
- * currently a NOP.
- */
-void __init
-init_sn2_smp_config(void)
+
+/* ----------------------------------------------------------------------------------------------- */
+
+#include <linux/proc_fs.h>
+
+
+static struct proc_dir_entry *ptcg_stats;
+
+static int
+ptcg_read_proc(char *buffer, char **start, off_t off, int count, int *eof, void *data)
+{
+	long cpu, *p, cnt;
+	int len = 0;
+
+	p = (long*)LOCAL_MMR_ADDR(SH_DIAG_MSG_DATA7L);
+	len += sprintf(buffer + len, "PTCG Stats (option 0x%lx)\n", use_tlb_hack);
+
+	len += sprintf(buffer + len, "%-14s", "CPU");
+	for (cpu=0; cpu<smp_num_cpus; cpu++)
+		len += sprintf(buffer + len, "%10ld", cpu);
+	len += sprintf(buffer + len, "\n");
+
+	len += sprintf(buffer + len, "%-14s", "flushes");
+	for (cpu=0; cpu<smp_num_cpus; cpu++)
+		len += sprintf(buffer + len, "%10ld", zz[cpu*16+0]&0xffffffff);
+	len += sprintf(buffer + len, "\n");
+
+	len += sprintf(buffer + len, "%-14s", "deadlocks");
+	for (cpu=0; cpu<smp_num_cpus; cpu++)
+		len += sprintf(buffer + len, "%10ld", zz[cpu*16+1]);
+	len += sprintf(buffer + len, "\n");
+
+	len += sprintf(buffer + len, "%-14s", "aver-us");
+	for (cpu=0; cpu<smp_num_cpus; cpu++) {
+		cnt = zz[cpu*16+0]&0xffffffff;
+		len += sprintf(buffer + len, "%10ld", cnt ? zz[cpu*16+6]/(cnt)/cpu_data(cpu)->cyc_per_usec : 0);
+	}
+	len += sprintf(buffer + len, "\n");
+
+	len += sprintf(buffer + len, "%-14s", "max-us");
+	for (cpu=0; cpu<smp_num_cpus; cpu++)
+		len += sprintf(buffer + len, "%10ld", zz[cpu*16+7]/cpu_data(cpu)->cyc_per_usec);
+	len += sprintf(buffer + len, "\n");
+
+	len += sprintf(buffer + len, "%-14s", "iaver-us");
+	for (cpu=0; cpu<smp_num_cpus; cpu++) {
+		cnt = zz[cpu*16+0]&0xffffffff;
+		len += sprintf(buffer + len, "%10ld", cnt ? zz[cpu*16+8]/(cnt)/cpu_data(cpu)->cyc_per_usec : 0);
+	}
+	len += sprintf(buffer + len, "\n");
+
+	len += sprintf(buffer + len, "%-14s", "imax-us");
+	for (cpu=0; cpu<smp_num_cpus; cpu++)
+		len += sprintf(buffer + len, "%10ld", zz[cpu*16+9]/cpu_data(cpu)->cyc_per_usec);
+	len += sprintf(buffer + len, "\n");
+
+	len += sprintf(buffer + len, "%-14s", "long-piowc");
+	for (cpu=0; cpu<smp_num_cpus; cpu++)
+		len += sprintf(buffer + len, "%10ld", zz[cpu*16+9]);
+	len += sprintf(buffer + len, "\n");
+
+        len += sprintf(buffer + len, "%-14s", "ipi-rp-error");
+        for (cpu=0; cpu<smp_num_cpus; cpu++) {
+                p = (long*)GLOBAL_MMR_ADDR(cpuid_to_nasid(cpu), SH_XN_IILB_LB_CMP_ENABLE0);
+                len += sprintf(buffer + len, "%10ld", *p);
+        }
+	len += sprintf(buffer + len, "\n");
+
+        len += sprintf(buffer + len, "%-14s", "lb-cb-error");
+        for (cpu=0; cpu<smp_num_cpus; cpu++) {
+                p = (long*)GLOBAL_MMR_ADDR(cpuid_to_nasid(cpu), SH_XN_IILB_LB_CMP_ENABLE1);
+                len += sprintf(buffer + len, "%10ld", *p);
+        }
+        len += sprintf(buffer + len, "\n");
+
+
+	if (len <= off+count) *eof = 1;
+	*start = buffer + off;
+	len   -= off;
+	if (len>count) len = count;
+	if (len<0) len = 0;
+	return len;
+}
+
+
+static int
+ptcg_write_proc (struct file *file, const char *userbuf, unsigned long count, void *data)
 {
+	extern long atoi(char *);
+	char		buf[80];
+	long		val;
+	long		cpu;
+	long		*p;
+
+	if (copy_from_user(buf, userbuf, count < sizeof(buf) ? count : sizeof(buf)))
+		return -EFAULT;
+
+	val = atoi(buf);
+	if (val&4) val |= 1;
+	use_tlb_hack = val;
+
+	memset((void*)zz, 0, sizeof(zz));
+
+	for (cpu=0; cpu<smp_num_cpus; cpu++) {
+		p = (long*)GLOBAL_MMR_ADDR(cpuid_to_nasid(cpu), SH_XN_IILB_LB_CMP_ENABLE0);
+		*p = 0;
+		p = (long*)GLOBAL_MMR_ADDR(cpuid_to_nasid(cpu), SH_XN_IILB_LB_CMP_ENABLE1);
+		*p = 0;
+	}
+	return count;
+}
+
+	
 
+static int
+sn2_ptcg_stats_init(void)
+{
+	if ((ptcg_stats = create_proc_entry("ptcg_stats", 0644, NULL)) == NULL) {
+		printk("unable to create proc entry for ptcg_stats");
+		return -1;
+	}
+	ptcg_stats->read_proc = ptcg_read_proc;
+	ptcg_stats->write_proc = ptcg_write_proc;
+	return 0;
 }
+
+#include <linux/module.h>
+module_init(sn2_ptcg_stats_init);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/kernel/sn2/sn_proc_fs.c linux-2.4.21-pre6/arch/ia64/sn/kernel/sn2/sn_proc_fs.c
--- linux-2.4.20/arch/ia64/sn/kernel/sn2/sn_proc_fs.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/kernel/sn2/sn_proc_fs.c	2003-03-26 23:49:08.000000000 +0000
@@ -0,0 +1,99 @@
+/*
+ *
+ * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify it 
+ * under the terms of version 2 of the GNU General Public License 
+ * as published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope that it would be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
+ * 
+ * Further, this software is distributed without any warranty that it is 
+ * free of the rightful claim of any third person regarding infringement 
+ * or the like.  Any license provided herein, whether implied or 
+ * otherwise, applies only to this software file.  Patent licenses, if 
+ * any, provided herein do not apply to combinations of this program with 
+ * other software, or any other product whatsoever.
+ * 
+ * You should have received a copy of the GNU General Public 
+ * License along with this program; if not, write the Free Software 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ * 
+ * Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, 
+ * Mountain View, CA  94043, or:
+ * 
+ * http://www.sgi.com 
+ * 
+ * For further information regarding this notice, see: 
+ * 
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan
+ */
+#include <linux/config.h>
+
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#include <asm/sn/sn_sal.h>
+
+
+static int partition_id_read_proc(char *page, char **start, off_t off,
+		int count, int *eof, void *data) {
+
+	return sprintf(page, "%d\n", sn_local_partid());
+}
+
+struct proc_dir_entry * sgi_proc_dir = NULL;
+
+void
+register_sn_partition_id(void) {
+	struct proc_dir_entry *entry;
+
+	if (!sgi_proc_dir) {
+		sgi_proc_dir = proc_mkdir("sgi_sn", 0);
+	}
+	entry = create_proc_entry("partition_id", 0444, sgi_proc_dir);
+	if (entry) {
+		entry->nlink = 1;
+		entry->data = 0;
+		entry->read_proc = partition_id_read_proc;
+		entry->write_proc = NULL;
+	}
+}
+
+static int
+system_serial_number_read_proc(char *page, char **start, off_t off,
+		int count, int *eof, void *data) {
+	return sprintf(page, "%s\n", sn_system_serial_number());
+}
+
+static int
+licenseID_read_proc(char *page, char **start, off_t off,
+		int count, int *eof, void *data) {
+	return sprintf(page, "0x%lx\n",sn_partition_serial_number_val());
+}
+
+void
+register_sn_serial_numbers(void) {
+	struct proc_dir_entry *entry;
+
+	if (!sgi_proc_dir) {
+		sgi_proc_dir = proc_mkdir("sgi_sn", 0);
+	}
+	entry = create_proc_entry("system_serial_number", 0444, sgi_proc_dir);
+	if (entry) {
+		entry->nlink = 1;
+		entry->data = 0;
+		entry->read_proc = system_serial_number_read_proc;
+		entry->write_proc = NULL;
+	}
+	entry = create_proc_entry("licenseID", 0444, sgi_proc_dir);
+	if (entry) {
+		entry->nlink = 1;
+		entry->data = 0;
+		entry->read_proc = licenseID_read_proc;
+		entry->write_proc = NULL;
+	}
+}
+
+#endif /* CONFIG_PROC_FS */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/kernel/sn_asm.S linux-2.4.21-pre6/arch/ia64/sn/kernel/sn_asm.S
--- linux-2.4.20/arch/ia64/sn/kernel/sn_asm.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/kernel/sn_asm.S	2003-03-26 23:48:59.000000000 +0000
@@ -1,6 +1,33 @@
-
 /*
- * Copyright (c) 2000-2001 Silicon Graphics, Inc.  All rights reserved.
+ * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify it 
+ * under the terms of version 2 of the GNU General Public License 
+ * as published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope that it would be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
+ * 
+ * Further, this software is distributed without any warranty that it is 
+ * free of the rightful claim of any third person regarding infringement 
+ * or the like.  Any license provided herein, whether implied or 
+ * otherwise, applies only to this software file.  Patent licenses, if 
+ * any, provided herein do not apply to combinations of this program with 
+ * other software, or any other product whatsoever.
+ * 
+ * You should have received a copy of the GNU General Public 
+ * License along with this program; if not, write the Free Software 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ * 
+ * Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, 
+ * Mountain View, CA  94043, or:
+ * 
+ * http://www.sgi.com 
+ * 
+ * For further information regarding this notice, see: 
+ * 
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan
  */
 
 #include <linux/config.h>
@@ -8,9 +35,10 @@
 
 // Testing only.
 // Routine will cause MCAs
-//   zzzmsa(n)
+//   zzzmca(n)
 //      n=0 MCA via duplicate TLB dropin
-//      n=0 MCA via read of garbage address
+//      n=1 MCA via read of garbage address
+//      n=2 MCA via lfetch read of garbage address
 //
 
 #define ITIR(key, ps)           ((key<<8) | (ps<<2))
@@ -45,20 +73,30 @@
 
                         rsm      0x2000;;
                         srlz.d;
-                        mov      r11      = 1
+                        mov      r11      = 5
                         mov      r3       = ITIR(0,TLB_PAGESIZE);;
                         mov      cr.itir  = r3
                         mov      r10      = 0;;
                         itr.d    dtr[r11] = r10;;
-                        mov      r11      = 2
+                        mov      r11      = 6
 
                         itr.d    dtr[r11] = r10;;
                         br      9f
 
-1:                      movl    r8=0xfe00000048;;
-                        ld8     r9=[r8];;
+1:
+			cmp.eq	p6,p7=1,r32
+#ifdef CONFIG_IA64_SGI_SN1
+                        movl    r8=0xe00000fe00000048;;
+#else
+                        movl    r8=0xe0007fb000000048;;
+#endif
+                 (p6)   ld8     r9=[r8]
+                 (p7)   lfetch.fault.nt2  [r8]
+			;;
                         mf
+			;;
                         mf.a
+			;;
                         srlz.d
 
 9:                      mov     ar.pfs=loc4
@@ -66,83 +104,4 @@
 
                         .endp   zzzmca
 
-                        .global zzzspec
-                        .proc   zzzspec
-zzzspec:
-			mov	r8=r32
-			movl	r9=0xe000000000000000
-			movl	r10=0x4000;;
-			ld8.s	r16=[r8];;
-			ld8.s	r17=[r9];;
-			add	r8=r8,r10;;
-			ld8.s	r18=[r8];;
-			add	r8=r8,r10;;
-			ld8.s	r19=[r8];;
-			add	r8=r8,r10;;
-			ld8.s	r20=[r8];;
-			mov	r8=r0
-			tnat.nz	p6,p0=r16
-			tnat.nz	p7,p0=r17
-			tnat.nz	p8,p0=r18
-			tnat.nz	p9,p0=r19
-			tnat.nz	p10,p0=r20;;
-		(p6)	dep	r8=-1,r8,0,1;;
-		(p7)	dep	r8=-1,r8,1,1;;
-		(p8)	dep	r8=-1,r8,2,1;;
-		(p9)	dep	r8=-1,r8,3,1;;
-		(p10)	dep	r8=-1,r8,4,1;;
-                        br.ret.sptk     rp
-                        .endp   zzzspec
-
-                        .global zzzspec2
-                        .proc   zzzspec2
-zzzspec2:
-			cmp.eq	p6,p7=r2,r2
-			movl	r16=0xc0000a0001000020
-			;;
-			mf
-			;;
-			ld8	r9=[r16]
-		(p6)	br.spnt	1f
-			ld8	r10=[r32]
-			;;
-		1:	mf.a
-			mf
-
-			ld8	r9=[r16];;
-			cmp.ne	p6,p7=r9,r16
-		(p6)	br.spnt	1f
-			ld8	r10=[r32]
-			;;
-		1:	mf.a
-			mf
-
-			ld8	r9=[r33];;
-			cmp.ne	p6,p7=r9,r33
-		(p6)	br.spnt	1f
-			ld8	r10=[r32]
-			;;
-		1:	mf.a
-			mf
-
-			tpa	r23=r32
-			add	r20=512,r33
-			add	r21=1024,r33;;
-			ld8	r9=[r20]
-			ld8	r10=[r21];;
-			nop.i	0
-			{ .mib
-			nop.m 0
-			cmp.ne	p6,p7=r10,r33
-		(p6)	br.spnt	1f
-			}
-			ld8	r10=[r32]
-			;;
-		1:	mf.a
-			mf
-			br.ret.sptk     rp
-
-                        .endp   zzzspec
-
 #endif
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/kernel/sn_ksyms.c linux-2.4.21-pre6/arch/ia64/sn/kernel/sn_ksyms.c
--- linux-2.4.20/arch/ia64/sn/kernel/sn_ksyms.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/kernel/sn_ksyms.c	2003-03-26 23:49:55.000000000 +0000
@@ -44,6 +44,7 @@
 EXPORT_SYMBOL(hwgraph_edge_add);
 EXPORT_SYMBOL(pciio_info_master_get);
 EXPORT_SYMBOL(pciio_info_get);
+
 #ifdef CONFIG_IA64_SGI_SN_DEBUG
 EXPORT_SYMBOL(__pa_debug);
 EXPORT_SYMBOL(__va_debug);
@@ -52,5 +53,30 @@
 /* Support IPIs for loaded modules. */
 EXPORT_SYMBOL(sn_send_IPI_phys);
 
+/* symbols referenced by partitioning modules */
+#include <asm/sn/bte_copy.h>
+EXPORT_SYMBOL(bte_unaligned_copy);
+#include <asm/sal.h>
+EXPORT_SYMBOL(ia64_sal);
+
+#ifdef CONFIG_IA64_SGI_SN2
+#include <asm/sn/sn_sal.h>
+EXPORT_SYMBOL(sal_lock);
+EXPORT_SYMBOL(sn_partid);
+EXPORT_SYMBOL(sn_local_partid);
+EXPORT_SYMBOL(sn_system_serial_number_string);
+EXPORT_SYMBOL(sn_partition_serial_number);
+#endif
+
+/* added by tduffy 04.08.01 to fix depmod issues */
 #include <linux/mmzone.h>
 
+#ifdef BUS_INT_WAR
+extern void sn_add_polled_interrupt(int, int);
+extern void sn_delete_polled_interrupt(int);
+EXPORT_SYMBOL(sn_add_polled_interrupt);
+EXPORT_SYMBOL(sn_delete_polled_interrupt);
+#endif
+
+extern nasid_t master_nasid;
+EXPORT_SYMBOL(master_nasid);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/kernel/sv.c linux-2.4.21-pre6/arch/ia64/sn/kernel/sv.c
--- linux-2.4.20/arch/ia64/sn/kernel/sv.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/kernel/sv.c	2003-03-26 23:49:39.000000000 +0000
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2000-2001 Silicon Graphics, Inc.  All rights reserved
+ * Copyright (C) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This implemenation of synchronization variables is heavily based on
  * one done by Steve Lord <lord@sgi.com>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/sn/tools/make_textsym linux-2.4.21-pre6/arch/ia64/sn/tools/make_textsym
--- linux-2.4.20/arch/ia64/sn/tools/make_textsym	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/sn/tools/make_textsym	2003-03-26 23:48:57.000000000 +0000
@@ -44,7 +44,7 @@
 
 [ -f $VMLINUX ] || help
 
-$OBJDUMP -t $LINUX | sort > $TMPSYM
+$OBJDUMP -t $LINUX | egrep -v '__ks' | sort > $TMPSYM
 SN1=`egrep "dig_setup|Synergy_da_indr" $TMPSYM|wc -l`
 
 # Dataprefix and textprefix correspond to the VGLOBAL_BASE and VPERNODE_BASE.
@@ -58,74 +58,74 @@
 # pipe everything thru sort
 echo "TEXTSYM V1.0"
 (cat <<END 
-GLOBAL | ${textprefix}00400000 | CODE | VEC_VHPT_Translation_0000
-GLOBAL | ${textprefix}00400400 | CODE | VEC_ITLB_0400
-GLOBAL | ${textprefix}00400800 | CODE | VEC_DTLB_0800
-GLOBAL | ${textprefix}00400c00 | CODE | VEC_Alt_ITLB_0c00
-GLOBAL | ${textprefix}00401000 | CODE | VEC_Alt_DTLB_1000
-GLOBAL | ${textprefix}00401400 | CODE | VEC_Data_nested_TLB_1400
-GLOBAL | ${textprefix}00401800 | CODE | VEC_Instruction_Key_Miss_1800
-GLOBAL | ${textprefix}00401c00 | CODE | VEC_Data_Key_Miss_1c00
-GLOBAL | ${textprefix}00402000 | CODE | VEC_Dirty-bit_2000
-GLOBAL | ${textprefix}00402400 | CODE | VEC_Instruction_Access-bit_2400
-GLOBAL | ${textprefix}00402800 | CODE | VEC_Data_Access-bit_2800
-GLOBAL | ${textprefix}00402c00 | CODE | VEC_Break_instruction_2c00
-GLOBAL | ${textprefix}00403000 | CODE | VEC_External_Interrupt_3000
-GLOBAL | ${textprefix}00403400 | CODE | VEC_Reserved_3400
-GLOBAL | ${textprefix}00403800 | CODE | VEC_Reserved_3800
-GLOBAL | ${textprefix}00403c00 | CODE | VEC_Reserved_3c00
-GLOBAL | ${textprefix}00404000 | CODE | VEC_Reserved_4000
-GLOBAL | ${textprefix}00404400 | CODE | VEC_Reserved_4400
-GLOBAL | ${textprefix}00404800 | CODE | VEC_Reserved_4800
-GLOBAL | ${textprefix}00404c00 | CODE | VEC_Reserved_4c00
-GLOBAL | ${textprefix}00405000 | CODE | VEC_Page_Not_Present_5000
-GLOBAL | ${textprefix}00405100 | CODE | VEC_Key_Permission_5100
-GLOBAL | ${textprefix}00405200 | CODE | VEC_Instruction_Access_Rights_5200
-GLOBAL | ${textprefix}00405300 | CODE | VEC_Data_Access_Rights_5300
-GLOBAL | ${textprefix}00405400 | CODE | VEC_General_Exception_5400
-GLOBAL | ${textprefix}00405500 | CODE | VEC_Disabled_FP-Register_5500
-GLOBAL | ${textprefix}00405600 | CODE | VEC_Nat_Consumption_5600
-GLOBAL | ${textprefix}00405700 | CODE | VEC_Speculation_5700
-GLOBAL | ${textprefix}00405800 | CODE | VEC_Reserved_5800
-GLOBAL | ${textprefix}00405900 | CODE | VEC_Debug_5900
-GLOBAL | ${textprefix}00405a00 | CODE | VEC_Unaligned_Reference_5a00
-GLOBAL | ${textprefix}00405b00 | CODE | VEC_Unsupported_Data_Reference_5b00
-GLOBAL | ${textprefix}00405c00 | CODE | VEC_Floating-Point_Fault_5c00
-GLOBAL | ${textprefix}00405d00 | CODE | VEC_Floating_Point_Trap_5d00
-GLOBAL | ${textprefix}00405e00 | CODE | VEC_Lower_Privilege_Tranfer_Trap_5e00
-GLOBAL | ${textprefix}00405f00 | CODE | VEC_Taken_Branch_Trap_5f00
-GLOBAL | ${textprefix}00406000 | CODE | VEC_Single_Step_Trap_6000
-GLOBAL | ${textprefix}00406100 | CODE | VEC_Reserved_6100
-GLOBAL | ${textprefix}00406200 | CODE | VEC_Reserved_6200
-GLOBAL | ${textprefix}00406300 | CODE | VEC_Reserved_6300
-GLOBAL | ${textprefix}00406400 | CODE | VEC_Reserved_6400
-GLOBAL | ${textprefix}00406500 | CODE | VEC_Reserved_6500
-GLOBAL | ${textprefix}00406600 | CODE | VEC_Reserved_6600
-GLOBAL | ${textprefix}00406700 | CODE | VEC_Reserved_6700
-GLOBAL | ${textprefix}00406800 | CODE | VEC_Reserved_6800
-GLOBAL | ${textprefix}00406900 | CODE | VEC_IA-32_Exeception_6900
-GLOBAL | ${textprefix}00406a00 | CODE | VEC_IA-32_Intercept_6a00
-GLOBAL | ${textprefix}00406b00 | CODE | VEC_IA-32_Interrupt_6b00
-GLOBAL | ${textprefix}00406c00 | CODE | VEC_Reserved_6c00
-GLOBAL | ${textprefix}00406d00 | CODE | VEC_Reserved_6d00
-GLOBAL | ${textprefix}00406e00 | CODE | VEC_Reserved_6e00
-GLOBAL | ${textprefix}00406f00 | CODE | VEC_Reserved_6f00
-GLOBAL | ${textprefix}00407000 | CODE | VEC_Reserved_7000
-GLOBAL | ${textprefix}00407100 | CODE | VEC_Reserved_7100
-GLOBAL | ${textprefix}00407200 | CODE | VEC_Reserved_7200
-GLOBAL | ${textprefix}00407300 | CODE | VEC_Reserved_7300
-GLOBAL | ${textprefix}00407400 | CODE | VEC_Reserved_7400
-GLOBAL | ${textprefix}00407500 | CODE | VEC_Reserved_7500
-GLOBAL | ${textprefix}00407600 | CODE | VEC_Reserved_7600
-GLOBAL | ${textprefix}00407700 | CODE | VEC_Reserved_7700
-GLOBAL | ${textprefix}00407800 | CODE | VEC_Reserved_7800
-GLOBAL | ${textprefix}00407900 | CODE | VEC_Reserved_7900
-GLOBAL | ${textprefix}00407a00 | CODE | VEC_Reserved_7a00
-GLOBAL | ${textprefix}00407b00 | CODE | VEC_Reserved_7b00
-GLOBAL | ${textprefix}00407c00 | CODE | VEC_Reserved_7c00
-GLOBAL | ${textprefix}00407d00 | CODE | VEC_Reserved_7d00
-GLOBAL | ${textprefix}00407e00 | CODE | VEC_Reserved_7e00
-GLOBAL | ${textprefix}00407f00 | CODE | VEC_Reserved_7f00
+GLOBAL | ${textprefix}00000000 | CODE | VEC_VHPT_Translation_0000
+GLOBAL | ${textprefix}00000400 | CODE | VEC_ITLB_0400
+GLOBAL | ${textprefix}00000800 | CODE | VEC_DTLB_0800
+GLOBAL | ${textprefix}00000c00 | CODE | VEC_Alt_ITLB_0c00
+GLOBAL | ${textprefix}00001000 | CODE | VEC_Alt_DTLB_1000
+GLOBAL | ${textprefix}00001400 | CODE | VEC_Data_nested_TLB_1400
+GLOBAL | ${textprefix}00001800 | CODE | VEC_Instruction_Key_Miss_1800
+GLOBAL | ${textprefix}00001c00 | CODE | VEC_Data_Key_Miss_1c00
+GLOBAL | ${textprefix}00002000 | CODE | VEC_Dirty-bit_2000
+GLOBAL | ${textprefix}00002400 | CODE | VEC_Instruction_Access-bit_2400
+GLOBAL | ${textprefix}00002800 | CODE | VEC_Data_Access-bit_2800
+GLOBAL | ${textprefix}00002c00 | CODE | VEC_Break_instruction_2c00
+GLOBAL | ${textprefix}00003000 | CODE | VEC_External_Interrupt_3000
+GLOBAL | ${textprefix}00003400 | CODE | VEC_Reserved_3400
+GLOBAL | ${textprefix}00003800 | CODE | VEC_Reserved_3800
+GLOBAL | ${textprefix}00003c00 | CODE | VEC_Reserved_3c00
+GLOBAL | ${textprefix}00004000 | CODE | VEC_Reserved_4000
+GLOBAL | ${textprefix}00004400 | CODE | VEC_Reserved_4400
+GLOBAL | ${textprefix}00004800 | CODE | VEC_Reserved_4800
+GLOBAL | ${textprefix}00004c00 | CODE | VEC_Reserved_4c00
+GLOBAL | ${textprefix}00005000 | CODE | VEC_Page_Not_Present_5000
+GLOBAL | ${textprefix}00005100 | CODE | VEC_Key_Permission_5100
+GLOBAL | ${textprefix}00005200 | CODE | VEC_Instruction_Access_Rights_5200
+GLOBAL | ${textprefix}00005300 | CODE | VEC_Data_Access_Rights_5300
+GLOBAL | ${textprefix}00005400 | CODE | VEC_General_Exception_5400
+GLOBAL | ${textprefix}00005500 | CODE | VEC_Disabled_FP-Register_5500
+GLOBAL | ${textprefix}00005600 | CODE | VEC_Nat_Consumption_5600
+GLOBAL | ${textprefix}00005700 | CODE | VEC_Speculation_5700
+GLOBAL | ${textprefix}00005800 | CODE | VEC_Reserved_5800
+GLOBAL | ${textprefix}00005900 | CODE | VEC_Debug_5900
+GLOBAL | ${textprefix}00005a00 | CODE | VEC_Unaligned_Reference_5a00
+GLOBAL | ${textprefix}00005b00 | CODE | VEC_Unsupported_Data_Reference_5b00
+GLOBAL | ${textprefix}00005c00 | CODE | VEC_Floating-Point_Fault_5c00
+GLOBAL | ${textprefix}00005d00 | CODE | VEC_Floating_Point_Trap_5d00
+GLOBAL | ${textprefix}00005e00 | CODE | VEC_Lower_Privilege_Tranfer_Trap_5e00
+GLOBAL | ${textprefix}00005f00 | CODE | VEC_Taken_Branch_Trap_5f00
+GLOBAL | ${textprefix}00006000 | CODE | VEC_Single_Step_Trap_6000
+GLOBAL | ${textprefix}00006100 | CODE | VEC_Reserved_6100
+GLOBAL | ${textprefix}00006200 | CODE | VEC_Reserved_6200
+GLOBAL | ${textprefix}00006300 | CODE | VEC_Reserved_6300
+GLOBAL | ${textprefix}00006400 | CODE | VEC_Reserved_6400
+GLOBAL | ${textprefix}00006500 | CODE | VEC_Reserved_6500
+GLOBAL | ${textprefix}00006600 | CODE | VEC_Reserved_6600
+GLOBAL | ${textprefix}00006700 | CODE | VEC_Reserved_6700
+GLOBAL | ${textprefix}00006800 | CODE | VEC_Reserved_6800
+GLOBAL | ${textprefix}00006900 | CODE | VEC_IA-32_Exeception_6900
+GLOBAL | ${textprefix}00006a00 | CODE | VEC_IA-32_Intercept_6a00
+GLOBAL | ${textprefix}00006b00 | CODE | VEC_IA-32_Interrupt_6b00
+GLOBAL | ${textprefix}00006c00 | CODE | VEC_Reserved_6c00
+GLOBAL | ${textprefix}00006d00 | CODE | VEC_Reserved_6d00
+GLOBAL | ${textprefix}00006e00 | CODE | VEC_Reserved_6e00
+GLOBAL | ${textprefix}00006f00 | CODE | VEC_Reserved_6f00
+GLOBAL | ${textprefix}00007000 | CODE | VEC_Reserved_7000
+GLOBAL | ${textprefix}00007100 | CODE | VEC_Reserved_7100
+GLOBAL | ${textprefix}00007200 | CODE | VEC_Reserved_7200
+GLOBAL | ${textprefix}00007300 | CODE | VEC_Reserved_7300
+GLOBAL | ${textprefix}00007400 | CODE | VEC_Reserved_7400
+GLOBAL | ${textprefix}00007500 | CODE | VEC_Reserved_7500
+GLOBAL | ${textprefix}00007600 | CODE | VEC_Reserved_7600
+GLOBAL | ${textprefix}00007700 | CODE | VEC_Reserved_7700
+GLOBAL | ${textprefix}00007800 | CODE | VEC_Reserved_7800
+GLOBAL | ${textprefix}00007900 | CODE | VEC_Reserved_7900
+GLOBAL | ${textprefix}00007a00 | CODE | VEC_Reserved_7a00
+GLOBAL | ${textprefix}00007b00 | CODE | VEC_Reserved_7b00
+GLOBAL | ${textprefix}00007c00 | CODE | VEC_Reserved_7c00
+GLOBAL | ${textprefix}00007d00 | CODE | VEC_Reserved_7d00
+GLOBAL | ${textprefix}00007e00 | CODE | VEC_Reserved_7e00
+GLOBAL | ${textprefix}00007f00 | CODE | VEC_Reserved_7f00
 END
 
 
@@ -157,10 +157,10 @@
 	print $0
 	if (sn1 != 0) {
 		/* 32 bits of sn1 physical addrs, */
-		print substr($0,1,9) substr($0,18,18) "Phy_" substr($0,36)
+		print substr($0,1,9) "04" substr($0,20,16) "Phy_" substr($0,36)
 	} else {
 		/* 38 bits of sn2 physical addrs, need addr space bits */
-		print substr($0,1,9) "30" substr($0,18,18) "Phy_" substr($0,36)
+		print substr($0,1,9) "3004" substr($0,20,16) "Phy_" substr($0,36)
 	}
 
 } ' | sort -k3
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ia64/vmlinux.lds.S linux-2.4.21-pre6/arch/ia64/vmlinux.lds.S
--- linux-2.4.20/arch/ia64/vmlinux.lds.S	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/ia64/vmlinux.lds.S	2003-03-26 23:49:24.000000000 +0000
@@ -13,6 +13,8 @@
   /DISCARD/ : {
 	*(.text.exit)
 	*(.data.exit)
+	*(*.text.exit)
+	*(*.data.exit)
 	*(.exitcall.exit)
 	*(.IA_64.unwind.text.exit)
 	*(.IA_64.unwind_info.text.exit)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/amiga/config.c linux-2.4.21-pre6/arch/m68k/amiga/config.c
--- linux-2.4.20/arch/m68k/amiga/config.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/m68k/amiga/config.c	2003-03-26 23:48:58.000000000 +0000
@@ -21,6 +21,7 @@
 #include <linux/rtc.h>
 #include <linux/init.h>
 #include <linux/vt_kern.h>
+#include <linux/delay.h>
 #ifdef CONFIG_ZORRO
 #include <linux/zorro.h>
 #endif
@@ -95,6 +96,7 @@
 static void a2000_gettod (int *, int *, int *, int *, int *, int *);
 static int amiga_hwclk (int, struct rtc_time *);
 static int amiga_set_clock_mmss (unsigned long);
+static unsigned int amiga_get_ss (void);
 extern void amiga_mksound( unsigned int count, unsigned int ticks );
 #ifdef CONFIG_AMIGA_FLOPPY
 extern void amiga_floppy_setup(char *, int *);
@@ -428,6 +430,7 @@
 
   mach_hwclk           = amiga_hwclk;
   mach_set_clock_mmss  = amiga_set_clock_mmss;
+  mach_get_ss          = amiga_get_ss; 
 #ifdef CONFIG_AMIGA_FLOPPY
   mach_floppy_setup    = amiga_floppy_setup;
 #endif
@@ -574,135 +577,145 @@
 static void a3000_gettod (int *yearp, int *monp, int *dayp,
 			  int *hourp, int *minp, int *secp)
 {
-	volatile struct tod3000 *tod = TOD_3000;
+	tod_3000.cntrl1 = TOD3000_CNTRL1_HOLD;
 
-	tod->cntrl1 = TOD3000_CNTRL1_HOLD;
+	*secp  = tod_3000.second1 * 10 + tod_3000.second2;
+	*minp  = tod_3000.minute1 * 10 + tod_3000.minute2;
+	*hourp = tod_3000.hour1   * 10 + tod_3000.hour2;
+	*dayp  = tod_3000.day1    * 10 + tod_3000.day2;
+	*monp  = tod_3000.month1  * 10 + tod_3000.month2;
+	*yearp = tod_3000.year1   * 10 + tod_3000.year2;
 
-	*secp  = tod->second1 * 10 + tod->second2;
-	*minp  = tod->minute1 * 10 + tod->minute2;
-	*hourp = tod->hour1   * 10 + tod->hour2;
-	*dayp  = tod->day1    * 10 + tod->day2;
-	*monp  = tod->month1  * 10 + tod->month2;
-	*yearp = tod->year1   * 10 + tod->year2;
-
-	tod->cntrl1 = TOD3000_CNTRL1_FREE;
+	tod_3000.cntrl1 = TOD3000_CNTRL1_FREE;
 }
 
 static void a2000_gettod (int *yearp, int *monp, int *dayp,
 			  int *hourp, int *minp, int *secp)
 {
-	volatile struct tod2000 *tod = TOD_2000;
+	int cnt = 5;
 
-	tod->cntrl1 = TOD2000_CNTRL1_HOLD;
+	tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD;
+	
+	while ((tod_2000.cntrl1 & TOD2000_CNTRL1_BUSY) && cnt--)
+	{
+	        tod_2000.cntrl1 &= ~TOD2000_CNTRL1_HOLD;
+	        udelay(70);
+	        tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD;
+	}
 
-	while (tod->cntrl1 & TOD2000_CNTRL1_BUSY)
-		;
+	if (!cnt)
+		printk(KERN_INFO "gettod: timed out waiting for RTC (0x%x)\n", tod_2000.cntrl1);
 
-	*secp  = tod->second1     * 10 + tod->second2;
-	*minp  = tod->minute1     * 10 + tod->minute2;
-	*hourp = (tod->hour1 & 3) * 10 + tod->hour2;
-	*dayp  = tod->day1        * 10 + tod->day2;
-	*monp  = tod->month1      * 10 + tod->month2;
-	*yearp = tod->year1       * 10 + tod->year2;
+	*secp  = tod_2000.second1     * 10 + tod_2000.second2;
+	*minp  = tod_2000.minute1     * 10 + tod_2000.minute2;
+	*hourp = (tod_2000.hour1 & 3) * 10 + tod_2000.hour2;
+	*dayp  = tod_2000.day1        * 10 + tod_2000.day2;
+	*monp  = tod_2000.month1      * 10 + tod_2000.month2;
+	*yearp = tod_2000.year1       * 10 + tod_2000.year2;
 
-	if (!(tod->cntrl3 & TOD2000_CNTRL3_24HMODE)){
-		if (!(tod->hour1 & TOD2000_HOUR1_PM) && *hourp == 12)
+	if (!(tod_2000.cntrl3 & TOD2000_CNTRL3_24HMODE)){
+		if (!(tod_2000.hour1 & TOD2000_HOUR1_PM) && *hourp == 12)
 			*hourp = 0;
-		else if ((tod->hour1 & TOD2000_HOUR1_PM) && *hourp != 12)
+		else if ((tod_2000.hour1 & TOD2000_HOUR1_PM) && *hourp != 12)
 			*hourp += 12;
 	}
 
-	tod->cntrl1 &= ~TOD2000_CNTRL1_HOLD;
+	tod_2000.cntrl1 &= ~TOD2000_CNTRL1_HOLD;
 }
 
 static int amiga_hwclk(int op, struct rtc_time *t)
 {
 	if (AMIGAHW_PRESENT(A3000_CLK)) {
-		volatile struct tod3000 *tod = TOD_3000;
-
-		tod->cntrl1 = TOD3000_CNTRL1_HOLD;
+		tod_3000.cntrl1 = TOD3000_CNTRL1_HOLD;
 
 		if (!op) { /* read */
-			t->tm_sec  = tod->second1 * 10 + tod->second2;
-			t->tm_min  = tod->minute1 * 10 + tod->minute2;
-			t->tm_hour = tod->hour1   * 10 + tod->hour2;
-			t->tm_mday = tod->day1    * 10 + tod->day2;
-			t->tm_wday = tod->weekday;
-			t->tm_mon  = tod->month1  * 10 + tod->month2 - 1;
-			t->tm_year = tod->year1   * 10 + tod->year2;
+			t->tm_sec  = tod_3000.second1 * 10 + tod_3000.second2;
+			t->tm_min  = tod_3000.minute1 * 10 + tod_3000.minute2;
+			t->tm_hour = tod_3000.hour1   * 10 + tod_3000.hour2;
+			t->tm_mday = tod_3000.day1    * 10 + tod_3000.day2;
+			t->tm_wday = tod_3000.weekday;
+			t->tm_mon  = tod_3000.month1  * 10 + tod_3000.month2 - 1;
+			t->tm_year = tod_3000.year1   * 10 + tod_3000.year2;
 			if (t->tm_year <= 69)
 				t->tm_year += 100;
 		} else {
-			tod->second1 = t->tm_sec / 10;
-			tod->second2 = t->tm_sec % 10;
-			tod->minute1 = t->tm_min / 10;
-			tod->minute2 = t->tm_min % 10;
-			tod->hour1   = t->tm_hour / 10;
-			tod->hour2   = t->tm_hour % 10;
-			tod->day1    = t->tm_mday / 10;
-			tod->day2    = t->tm_mday % 10;
+			tod_3000.second1 = t->tm_sec / 10;
+			tod_3000.second2 = t->tm_sec % 10;
+			tod_3000.minute1 = t->tm_min / 10;
+			tod_3000.minute2 = t->tm_min % 10;
+			tod_3000.hour1   = t->tm_hour / 10;
+			tod_3000.hour2   = t->tm_hour % 10;
+			tod_3000.day1    = t->tm_mday / 10;
+			tod_3000.day2    = t->tm_mday % 10;
 			if (t->tm_wday != -1)
-				tod->weekday = t->tm_wday;
-			tod->month1  = (t->tm_mon + 1) / 10;
-			tod->month2  = (t->tm_mon + 1) % 10;
+				tod_3000.weekday = t->tm_wday;
+			tod_3000.month1  = (t->tm_mon + 1) / 10;
+			tod_3000.month2  = (t->tm_mon + 1) % 10;
 			if (t->tm_year >= 100)
 				t->tm_year -= 100;
-			tod->year1   = t->tm_year / 10;
-			tod->year2   = t->tm_year % 10;
+			tod_3000.year1   = t->tm_year / 10;
+			tod_3000.year2   = t->tm_year % 10;
 		}
 
-		tod->cntrl1 = TOD3000_CNTRL1_FREE;
+		tod_3000.cntrl1 = TOD3000_CNTRL1_FREE;
 	} else /* if (AMIGAHW_PRESENT(A2000_CLK)) */ {
-		volatile struct tod2000 *tod = TOD_2000;
+		int cnt = 5;
 
-		tod->cntrl1 = TOD2000_CNTRL1_HOLD;
-	    
-		while (tod->cntrl1 & TOD2000_CNTRL1_BUSY)
-			;
+		tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD;
+		
+		while ((tod_2000.cntrl1 & TOD2000_CNTRL1_BUSY) && cnt--)
+		{
+			tod_2000.cntrl1 &= ~TOD2000_CNTRL1_HOLD;
+			udelay(70);
+			tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD;
+		}
+
+		if (!cnt)
+			printk(KERN_INFO "hwclk: timed out waiting for RTC (0x%x)\n", tod_2000.cntrl1);
 
 		if (!op) { /* read */
-			t->tm_sec  = tod->second1     * 10 + tod->second2;
-			t->tm_min  = tod->minute1     * 10 + tod->minute2;
-			t->tm_hour = (tod->hour1 & 3) * 10 + tod->hour2;
-			t->tm_mday = tod->day1        * 10 + tod->day2;
-			t->tm_wday = tod->weekday;
-			t->tm_mon  = tod->month1      * 10 + tod->month2 - 1;
-			t->tm_year = tod->year1       * 10 + tod->year2;
+			t->tm_sec  = tod_2000.second1     * 10 + tod_2000.second2;
+			t->tm_min  = tod_2000.minute1     * 10 + tod_2000.minute2;
+			t->tm_hour = (tod_2000.hour1 & 3) * 10 + tod_2000.hour2;
+			t->tm_mday = tod_2000.day1        * 10 + tod_2000.day2;
+			t->tm_wday = tod_2000.weekday;
+			t->tm_mon  = tod_2000.month1      * 10 + tod_2000.month2 - 1;
+			t->tm_year = tod_2000.year1       * 10 + tod_2000.year2;
 			if (t->tm_year <= 69)
 				t->tm_year += 100;
 
-			if (!(tod->cntrl3 & TOD2000_CNTRL3_24HMODE)){
-				if (!(tod->hour1 & TOD2000_HOUR1_PM) && t->tm_hour == 12)
+			if (!(tod_2000.cntrl3 & TOD2000_CNTRL3_24HMODE)){
+				if (!(tod_2000.hour1 & TOD2000_HOUR1_PM) && t->tm_hour == 12)
 					t->tm_hour = 0;
-				else if ((tod->hour1 & TOD2000_HOUR1_PM) && t->tm_hour != 12)
+				else if ((tod_2000.hour1 & TOD2000_HOUR1_PM) && t->tm_hour != 12)
 					t->tm_hour += 12;
 			}
 		} else {
-			tod->second1 = t->tm_sec / 10;
-			tod->second2 = t->tm_sec % 10;
-			tod->minute1 = t->tm_min / 10;
-			tod->minute2 = t->tm_min % 10;
-			if (tod->cntrl3 & TOD2000_CNTRL3_24HMODE)
-				tod->hour1 = t->tm_hour / 10;
+			tod_2000.second1 = t->tm_sec / 10;
+			tod_2000.second2 = t->tm_sec % 10;
+			tod_2000.minute1 = t->tm_min / 10;
+			tod_2000.minute2 = t->tm_min % 10;
+			if (tod_2000.cntrl3 & TOD2000_CNTRL3_24HMODE)
+				tod_2000.hour1 = t->tm_hour / 10;
 			else if (t->tm_hour >= 12)
-				tod->hour1 = TOD2000_HOUR1_PM +
+				tod_2000.hour1 = TOD2000_HOUR1_PM +
 					(t->tm_hour - 12) / 10;
 			else
-				tod->hour1 = t->tm_hour / 10;
-			tod->hour2   = t->tm_hour % 10;
-			tod->day1    = t->tm_mday / 10;
-			tod->day2    = t->tm_mday % 10;
+				tod_2000.hour1 = t->tm_hour / 10;
+			tod_2000.hour2   = t->tm_hour % 10;
+			tod_2000.day1    = t->tm_mday / 10;
+			tod_2000.day2    = t->tm_mday % 10;
 			if (t->tm_wday != -1)
-				tod->weekday = t->tm_wday;
-			tod->month1  = (t->tm_mon + 1) / 10;
-			tod->month2  = (t->tm_mon + 1) % 10;
+				tod_2000.weekday = t->tm_wday;
+			tod_2000.month1  = (t->tm_mon + 1) / 10;
+			tod_2000.month2  = (t->tm_mon + 1) % 10;
 			if (t->tm_year >= 100)
 				t->tm_year -= 100;
-			tod->year1   = t->tm_year / 10;
-			tod->year2   = t->tm_year % 10;
+			tod_2000.year1   = t->tm_year / 10;
+			tod_2000.year2   = t->tm_year % 10;
 		}
 
-		tod->cntrl1 &= ~TOD2000_CNTRL1_HOLD;
+		tod_2000.cntrl1 &= ~TOD2000_CNTRL1_HOLD;
 	}
 
 	return 0;
@@ -713,35 +726,54 @@
 	short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
 
 	if (AMIGAHW_PRESENT(A3000_CLK)) {
-		volatile struct tod3000 *tod = TOD_3000;
-
-		tod->cntrl1 = TOD3000_CNTRL1_HOLD;
+		tod_3000.cntrl1 = TOD3000_CNTRL1_HOLD;
 
-		tod->second1 = real_seconds / 10;
-		tod->second2 = real_seconds % 10;
-		tod->minute1 = real_minutes / 10;
-		tod->minute2 = real_minutes % 10;
+		tod_3000.second1 = real_seconds / 10;
+		tod_3000.second2 = real_seconds % 10;
+		tod_3000.minute1 = real_minutes / 10;
+		tod_3000.minute2 = real_minutes % 10;
 		
-		tod->cntrl1 = TOD3000_CNTRL1_FREE;
+		tod_3000.cntrl1 = TOD3000_CNTRL1_FREE;
 	} else /* if (AMIGAHW_PRESENT(A2000_CLK)) */ {
-		volatile struct tod2000 *tod = TOD_2000;
+		int cnt = 5;
 
-		tod->cntrl1 = TOD2000_CNTRL1_HOLD;
-	    
-		while (tod->cntrl1 & TOD2000_CNTRL1_BUSY)
-			;
-
-		tod->second1 = real_seconds / 10;
-		tod->second2 = real_seconds % 10;
-		tod->minute1 = real_minutes / 10;
-		tod->minute2 = real_minutes % 10;
+		tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD;
+		
+		while ((tod_2000.cntrl1 & TOD2000_CNTRL1_BUSY) && cnt--)
+		{
+			tod_2000.cntrl1 &= ~TOD2000_CNTRL1_HOLD;
+			udelay(70);
+			tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD;
+		}
 
-		tod->cntrl1 &= ~TOD2000_CNTRL1_HOLD;
+		if (!cnt)
+			printk(KERN_INFO "set_clock_mmss: timed out waiting for RTC (0x%x)\n", tod_2000.cntrl1);
+
+		tod_2000.second1 = real_seconds / 10;
+		tod_2000.second2 = real_seconds % 10;
+		tod_2000.minute1 = real_minutes / 10;
+		tod_2000.minute2 = real_minutes % 10;
+
+		tod_2000.cntrl1 &= ~TOD2000_CNTRL1_HOLD;
 	}
 
 	return 0;
 }
 
+static unsigned int amiga_get_ss( void )
+{
+	unsigned int s;
+
+	if (AMIGAHW_PRESENT(A3000_CLK)) {
+		tod_3000.cntrl1 = TOD3000_CNTRL1_HOLD;
+		s = tod_3000.second1 * 10 + tod_3000.second2;
+		tod_3000.cntrl1 = TOD3000_CNTRL1_FREE;
+	} else /* if (AMIGAHW_PRESENT(A2000_CLK)) */ { 
+		s = tod_2000.second1 * 10 + tod_2000.second2;
+	}
+	return s;
+}
+
 static NORET_TYPE void amiga_reset( void )
     ATTRIB_NORET;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/apollo/config.c linux-2.4.21-pre6/arch/m68k/apollo/config.c
--- linux-2.4.20/arch/m68k/apollo/config.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/m68k/apollo/config.c	2003-03-26 23:49:25.000000000 +0000
@@ -51,7 +51,6 @@
 static void dn_timer_int(int irq,void *, struct pt_regs *);
 static void (*sched_timer_handler)(int, void *, struct pt_regs *)=NULL;
 static void dn_get_model(char *model);
-static int dn_cpuctrl=0xff00;
 static const char *apollo_models[] = {
 	"DN3000 (Otter)",
 	"DN3010 (Otter)",
@@ -313,6 +312,8 @@
 }
 
 #ifdef CONFIG_HEARTBEAT
+static int dn_cpuctrl=0xff00;
+
 static void dn_heartbeat(int on) {
 
 	if(on) { 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/apollo/dma.c linux-2.4.21-pre6/arch/m68k/apollo/dma.c
--- linux-2.4.20/arch/m68k/apollo/dma.c	2000-01-28 16:04:58.000000000 +0000
+++ linux-2.4.21-pre6/arch/m68k/apollo/dma.c	2003-03-26 23:49:20.000000000 +0000
@@ -10,6 +10,7 @@
 #include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/apollodma.h>
+#include <asm/io.h>
 
 /* note only works for 16 Bit 1 page DMA's */
 
@@ -27,7 +28,7 @@
 #if 0
 		printk("phys_addr: %x, page_aligned_addr: %x, start_map_addr: %x\n",phys_addr,page_aligned_addr,start_map_addr+i);
 #endif
-		outw(start_map_addr+i, xlat_map_entry);
+		out_be16(xlat_map_entry, start_map_addr+i);
 	}
 
 	next_free_xlat_entry+=2;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/atari/stram.c linux-2.4.21-pre6/arch/m68k/atari/stram.c
--- linux-2.4.20/arch/m68k/atari/stram.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/m68k/atari/stram.c	2003-03-26 23:49:51.000000000 +0000
@@ -146,7 +146,7 @@
 
 /* The following two numbers define the maximum fraction of ST-RAM in total
  * memory, below that the kernel would automatically use ST-RAM as swap
- * space. This decision can be overriden with stram_swap= */
+ * space. This decision can be overridden with stram_swap= */
 #define MAX_STRAM_FRACTION_NOM		1
 #define MAX_STRAM_FRACTION_DENOM	3
 
@@ -347,7 +347,7 @@
 		/*
 		 * If the whole ST-RAM is used for swapping, there are no allocatable
 		 * dma pages left. But unfortunately, some shared parts of the kernel
-		 * (particularily the SCSI mid-level) call __get_dma_pages()
+		 * (particularly the SCSI mid-level) call __get_dma_pages()
 		 * unconditionally :-( These calls then fail, and scsi.c even doesn't
 		 * check for NULL return values and just crashes. The quick fix for
 		 * this (instead of doing much clean up work in the SCSI code) is to
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/bvme6000/rtc.c linux-2.4.21-pre6/arch/m68k/bvme6000/rtc.c
--- linux-2.4.20/arch/m68k/bvme6000/rtc.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/m68k/bvme6000/rtc.c	2003-03-26 23:48:59.000000000 +0000
@@ -179,7 +179,6 @@
 		return -ENODEV;
 
 	printk(KERN_INFO "DP8570A Real Time Clock Driver v%s\n", RTC_VERSION);
-	misc_register(&rtc_dev);
-	return 0;
+	return misc_register(&rtc_dev);
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/config.in linux-2.4.21-pre6/arch/m68k/config.in
--- linux-2.4.20/arch/m68k/config.in	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/m68k/config.in	2003-03-26 23:49:50.000000000 +0000
@@ -111,7 +111,9 @@
    bool 'Support for ST-RAM as swap space' CONFIG_STRAM_SWAP
    bool 'ST-RAM statistics in /proc' CONFIG_STRAM_PROC
 fi
-if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_ATARI" = "y" -o "$CONFIG_Q40" = "y" ]; then
+if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_APOLLO" = "y" -o \
+     "$CONFIG_ATARI" = "y" -o "$CONFIG_MAC" = "y" -o \
+     "$CONFIG_Q40" = "y" ]; then
    bool 'Use power LED as a heartbeat' CONFIG_HEARTBEAT
 else
   if [ "$CONFIG_HP300" = "y" ]; then
@@ -502,7 +504,7 @@
      "$CONFIG_SUN3X_ZS" = "y" -o "$CONFIG_SERIAL" = "y" -o \
      "$CONFIG_MVME147_SCC" -o "$CONFIG_SERIAL167" = "y" -o \
      "$CONFIG_MVME162_SCC" -o "$CONFIG_BVME6000_SCC" = "y" -o \
-     "$CONFIG_DN_SERIAL" -o ]; then
+     "$CONFIG_DN_SERIAL" ]; then
    bool 'Support for serial port console' CONFIG_SERIAL_CONSOLE
 fi
 bool 'Support for user serial device modules' CONFIG_USERIAL
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/ifpsp060/fskeleton.S linux-2.4.21-pre6/arch/m68k/ifpsp060/fskeleton.S
--- linux-2.4.20/arch/m68k/ifpsp060/fskeleton.S	1996-09-25 07:47:39.000000000 +0000
+++ linux-2.4.21-pre6/arch/m68k/ifpsp060/fskeleton.S	2003-03-26 23:49:27.000000000 +0000
@@ -302,7 +302,6 @@
 
 | The size of this section MUST be 128 bytes!!!
 
-	.global	_FP_CALL_TOP
 _FP_CALL_TOP:
 	.long	_060_real_bsun		- _FP_CALL_TOP
 	.long	_060_real_snan		- _FP_CALL_TOP
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/ifpsp060/iskeleton.S linux-2.4.21-pre6/arch/m68k/ifpsp060/iskeleton.S
--- linux-2.4.20/arch/m68k/ifpsp060/iskeleton.S	1999-01-19 18:58:26.000000000 +0000
+++ linux-2.4.21-pre6/arch/m68k/ifpsp060/iskeleton.S	2003-03-26 23:49:06.000000000 +0000
@@ -270,7 +270,6 @@
 
 | The size of this section MUST be 128 bytes!!!
 
-	.global	_I_CALL_TOP
 _I_CALL_TOP:
 	.long	_060_real_chk		- _I_CALL_TOP
 	.long	_060_real_divbyzero	- _I_CALL_TOP
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/kernel/entry.S linux-2.4.21-pre6/arch/m68k/kernel/entry.S
--- linux-2.4.20/arch/m68k/kernel/entry.S	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/m68k/kernel/entry.S	2003-03-26 23:48:58.000000000 +0000
@@ -240,13 +240,10 @@
 2:
 	RESTORE_ALL
 1:
-#if 1
-	bfextu  %sp@(PT_SR){#5,#3},%d0	| Check for nested interrupt.
-#if MAX_NOINT_IPL > 0
-	cmpiw	#MAX_NOINT_IPL,%d0
-#endif
-	jhi	2b
-#endif
+	moveq	#(~ALLOWINT>>8)&0xff,%d0
+	andb	%sp@(PT_SR),%d0
+	jne	2b
+
 	/* check if we need to do software interrupts */
 	tstl	SYMBOL_NAME(irq_stat)	| softirq_pending ?
 	jeq	SYMBOL_NAME(ret_from_exception)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/kernel/head.S linux-2.4.21-pre6/arch/m68k/kernel/head.S
--- linux-2.4.20/arch/m68k/kernel/head.S	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/m68k/kernel/head.S	2003-03-26 23:49:38.000000000 +0000
@@ -130,7 +130,7 @@
  *
  * mmu_engage
  * ----------
- *	Thanks to a small helping routine enabling the mmu got quiet simple
+ *	Thanks to a small helping routine enabling the mmu got quite simple
  * and there is only one way left. mmu_engage makes a complete a new mapping
  * that only includes the absolute necessary to be able to jump to the final
  * postion and to restore the original mapping.
@@ -190,7 +190,7 @@
  *
  * options
  * -------
- *	There are many options availble in a build of this file.  I've
+ *	There are many options available in a build of this file.  I've
  * taken the time to describe them here to save you the time of searching
  * for them and trying to understand what they mean.
  *
@@ -1202,7 +1202,7 @@
  *
  * Map the kernel (that's already done),
  * Map the I/O (on most machines that's the
- * 0x5000.0000 ... 0x5200.0000 range,
+ * 0x5000.0000 ... 0x5300.0000 range,
  * Map the video frame buffer using as few pages
  * as absolutely (this requirement mostly stems from
  * the fact that when the frame buffer is at
@@ -1246,10 +1246,11 @@
 	andl	L(mac_videobase),%d0
 
 	mmu_map		#VIDEOMEMBASE,%d0,#VIDEOMEMSIZE,%d3
-	mmu_map_eq	#0x40800000,#0x02000000,%d3	/* rom ? */
-	mmu_map_eq	#0x50000000,#0x02000000,%d3
-	mmu_map_eq	#0x60000000,#0x00400000,%d3
-	mmu_map_eq	#0x9c000000,#0x00400000,%d3
+	/* The ROM starts at 4000 0000		    	*/
+	mmu_map_eq	#0x40000000,#0x02000000,%d3
+	/* IO devices                               	*/
+	mmu_map_eq	#0x50000000,#0x03000000,%d3
+	/* NuBus slot space				*/
 	mmu_map_tt	#1,#0xf8000000,#0x08000000,%d3
 
 	jbra	L(mmu_init_done)
@@ -1461,6 +1462,9 @@
 	andl	L(mac_videobase),%d0
 	addl	#VIDEOMEMBASE,%d0
 	movel	%d0,L(mac_videobase)
+#ifdef MAC_SERIAL_DEBUG
+	orl	#0x50000000,L(mac_sccbase)
+#endif		
 1:
 #endif
 
@@ -3048,10 +3052,6 @@
 #ifdef CONFIG_MAC
 	is_not_mac(5f)
 
-#ifdef CONSOLE
-	console_putc	%d0
-#endif /* CONSOLE */
-
 #ifdef MAC_SERIAL_DEBUG
 
 #ifdef MAC_USE_SCC_A
@@ -3446,6 +3446,10 @@
 	putn	%pc@(L(cputype))
 	putc	'\n'
 
+#ifdef MAC_SERIAL_DEBUG
+	putn	%pc@(L(mac_sccbase))
+	putc	'\n'
+#endif	
 #  if defined(MMU_PRINT)
 	jbsr	mmu_print_machine_cpu_types
 #  endif /* MMU_PRINT */
@@ -3622,7 +3626,7 @@
 	movel	%a0@(Lconsole_struct_num_columns),%d1
 	cmpl	%d1,%d0
 	jcs	1f
-	putc	'\n'	/* recursion is OK! */
+	console_putc	#'\n'	/* recursion is OK! */
 1:
 	movel	%a0@(Lconsole_struct_cur_row),%d1
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/kernel/m68k_ksyms.c linux-2.4.21-pre6/arch/m68k/kernel/m68k_ksyms.c
--- linux-2.4.20/arch/m68k/kernel/m68k_ksyms.c	2001-01-04 21:00:55.000000000 +0000
+++ linux-2.4.21-pre6/arch/m68k/kernel/m68k_ksyms.c	2003-03-26 23:49:53.000000000 +0000
@@ -26,7 +26,7 @@
 extern char m68k_debug_device[];
 
 extern void dump_thread(struct pt_regs *, struct user *);
-extern int dump_fpu(elf_fpregset_t *);
+extern int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu);
 
 /* platform dependent support */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/kernel/process.c linux-2.4.21-pre6/arch/m68k/kernel/process.c
--- linux-2.4.20/arch/m68k/kernel/process.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/m68k/kernel/process.c	2003-03-26 23:49:39.000000000 +0000
@@ -124,7 +124,7 @@
 /*
  * Create a kernel thread
  */
-int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 {
 	int pid;
 	mm_segment_t fs;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/kernel/signal.c linux-2.4.21-pre6/arch/m68k/kernel/signal.c
--- linux-2.4.20/arch/m68k/kernel/signal.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/m68k/kernel/signal.c	2003-03-26 23:49:09.000000000 +0000
@@ -16,7 +16,7 @@
  * 1997-12-01  Modified for POSIX.1b signals by Andreas Schwab
  *
  * mathemu support by Roman Zippel
- *  (Note: fpstate in the signal context is completly ignored for the emulator
+ *  (Note: fpstate in the signal context is completely ignored for the emulator
  *         and the internal floating point format is put on stack)
  */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/kernel/time.c linux-2.4.21-pre6/arch/m68k/kernel/time.c
--- linux-2.4.20/arch/m68k/kernel/time.c	2001-01-04 21:00:55.000000000 +0000
+++ linux-2.4.21-pre6/arch/m68k/kernel/time.c	2003-03-26 23:49:19.000000000 +0000
@@ -55,28 +55,11 @@
  */
 static void timer_interrupt(int irq, void *dummy, struct pt_regs * regs)
 {
-	/* last time the cmos clock got updated */
-	static long last_rtc_update=0;
-
 	do_timer(regs);
 
 	if (!user_mode(regs))
 		do_profile(regs->pc);
 
-	/*
-	 * If we have an externally synchronized Linux clock, then update
-	 * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
-	 * called as close as possible to 500 ms before the new second starts.
-	 */
-	if ((time_status & STA_UNSYNC) == 0 &&
-	    xtime.tv_sec > last_rtc_update + 660 &&
-	    xtime.tv_usec >= 500000 - ((unsigned) tick) / 2 &&
-	    xtime.tv_usec <= 500000 + ((unsigned) tick) / 2) {
-	  if (set_rtc_mmss(xtime.tv_sec) == 0)
-	    last_rtc_update = xtime.tv_sec;
-	  else
-	    last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
-	}
 #ifdef CONFIG_HEARTBEAT
 	/* use power LED as a heartbeat instead -- much more useful
 	   for debugging -- based on the version for PReP by Cort */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/kernel/traps.c linux-2.4.21-pre6/arch/m68k/kernel/traps.c
--- linux-2.4.20/arch/m68k/kernel/traps.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/m68k/kernel/traps.c	2003-03-26 23:49:39.000000000 +0000
@@ -302,7 +302,7 @@
 	return res;
 }
 
-/* after an exception in a writeback the stack frame coresponding
+/* after an exception in a writeback the stack frame corresponding
  * to that exception is discarded, set a few bits in the old frame 
  * to simulate what it should look like
  */
@@ -332,7 +332,7 @@
 			fp->un.fmt7.wb2s = 0;
 	}
 
-	/* do the 2nd wb only if the first one was succesful (except for a kernel wb) */
+	/* do the 2nd wb only if the first one was successful (except for a kernel wb) */
 	if (fp->un.fmt7.wb3s & WBV_040 && (!res || fp->un.fmt7.wb3s & 4)) {
 		res = do_040writeback1(fp->un.fmt7.wb3s, fp->un.fmt7.wb3a,
 				       fp->un.fmt7.wb3d);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/mac/baboon.c linux-2.4.21-pre6/arch/m68k/mac/baboon.c
--- linux-2.4.20/arch/m68k/mac/baboon.c	2000-12-04 01:48:19.000000000 +0000
+++ linux-2.4.21-pre6/arch/m68k/mac/baboon.c	2003-03-26 23:49:08.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * Baboon Custom IC Managment
+ * Baboon Custom IC Management
  *
  * The Baboon custom IC controls the IDE, PCMCIA and media bay on the
  * PowerBook 190. It multiplexes multiple interrupt sources onto the
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/mac/config.c linux-2.4.21-pre6/arch/m68k/mac/config.c
--- linux-2.4.20/arch/m68k/mac/config.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/m68k/mac/config.c	2003-03-26 23:49:34.000000000 +0000
@@ -104,7 +104,7 @@
 
 void mac_bang(int irq, void *vector, struct pt_regs *p)
 {
-	printk("Resetting ...\n");
+	printk(KERN_INFO "Resetting ...\n");
 	mac_reset();
 }
 
@@ -205,7 +205,7 @@
 void __init config_mac(void)
 {
 	if (!MACH_IS_MAC) {
-	  printk("ERROR: no Mac, but config_mac() called!! \n");
+	  printk(KERN_ERR "ERROR: no Mac, but config_mac() called!! \n");
 	}
 
 #ifdef CONFIG_VT
@@ -370,13 +370,14 @@
 	 */	 
 	 
 	{	MAC_MODEL_Q605, "Quadra 605", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE,   MAC_SCC_QUADRA,	MAC_ETHER_NONE,		MAC_NUBUS},
+	{	MAC_MODEL_Q605_ACC, "Quadra 605", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE,   MAC_SCC_QUADRA,	MAC_ETHER_NONE,		MAC_NUBUS},
 	{	MAC_MODEL_Q610, "Quadra 610", MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE,   MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
 	{	MAC_MODEL_Q630, "Quadra 630", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_QUADRA, MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
  	{	MAC_MODEL_Q650, "Quadra 650", MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE,   MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
 	/*	The Q700 does have a NS Sonic */
-	{	MAC_MODEL_Q700, "Quadra 700", MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE,   MAC_SCC_QUADRA2,	MAC_ETHER_SONIC,	MAC_NUBUS},
+	{	MAC_MODEL_Q700, "Quadra 700", MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE,   MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
 	{	MAC_MODEL_Q800, "Quadra 800", MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE,   MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
-	{	MAC_MODEL_Q840, "Quadra 840AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_II,	MAC_ETHER_MACE,		MAC_NUBUS},
+	{	MAC_MODEL_Q840, "Quadra 840AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_PSC,	MAC_ETHER_MACE,		MAC_NUBUS},
 	{	MAC_MODEL_Q900, "Quadra 900", MAC_ADB_IOP, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE,   MAC_SCC_IOP,	MAC_ETHER_SONIC,	MAC_NUBUS},
 	{	MAC_MODEL_Q950, "Quadra 950", MAC_ADB_IOP, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE,   MAC_SCC_IOP,	MAC_ETHER_SONIC,	MAC_NUBUS},
 
@@ -389,8 +390,8 @@
 	{	MAC_MODEL_P475F, "Performa 475", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE,   MAC_SCC_II,	MAC_ETHER_NONE, MAC_NUBUS},
 	{	MAC_MODEL_P520,  "Performa 520", MAC_ADB_CUDA, MAC_VIA_IIci,   MAC_SCSI_OLD,    MAC_IDE_NONE,   MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
 	{	MAC_MODEL_P550,  "Performa 550", MAC_ADB_CUDA, MAC_VIA_IIci,   MAC_SCSI_OLD,    MAC_IDE_NONE,   MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
-	{	MAC_MODEL_P575,  "Performa 575", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE,   MAC_SCC_II,	MAC_ETHER_NONE, MAC_NUBUS},
 	/* These have the comm slot, and therefore the possibility of SONIC ethernet */
+	{	MAC_MODEL_P575,  "Performa 575", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE,   MAC_SCC_II,	MAC_ETHER_SONIC, MAC_NUBUS},
 	{	MAC_MODEL_P588,  "Performa 588", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_QUADRA, MAC_SCC_II,	MAC_ETHER_SONIC, MAC_NUBUS},
 	{	MAC_MODEL_TV,    "TV",           MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_OLD,	MAC_IDE_NONE,   MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
 	{	MAC_MODEL_P600,  "Performa 600", MAC_ADB_IISI, MAC_VIA_IIci,   MAC_SCSI_OLD,	MAC_IDE_NONE,   MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
@@ -402,7 +403,7 @@
 	/* The C610 may or may not have SONIC.  We probe to make sure */
 	{	MAC_MODEL_C610, "Centris 610",   MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
 	{	MAC_MODEL_C650, "Centris 650",   MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
-	{	MAC_MODEL_C660, "Centris 660AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_MACE,		MAC_NUBUS},
+	{	MAC_MODEL_C660, "Centris 660AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_PSC,	MAC_ETHER_MACE,		MAC_NUBUS},
 
 	/*
 	 * The PowerBooks all the same "Combo" custom IC for SCSI and SCC
@@ -455,7 +456,7 @@
 		/* no bootinfo model id -> NetBSD booter was used! */
 		/* XXX FIXME: breaks for model > 31 */
 		model=(mac_bi_data.cpuid>>2)&63;
-		printk ("No bootinfo model ID, using cpuid instead (hey, use Penguin!)\n");
+		printk (KERN_WARNING "No bootinfo model ID, using cpuid instead (hey, use Penguin!)\n");
 	}
 
 	macintosh_config = mac_data_table; 
@@ -473,22 +474,22 @@
 	iop_preinit();
 	mac_debug_init();
 
-	printk ("Detected Macintosh model: %d \n", model);
+	printk (KERN_INFO "Detected Macintosh model: %d \n", model);
 
 	/*
 	 * Report booter data:
 	 */
-	printk (" Penguin bootinfo data:\n");
-	printk (" Video: addr 0x%lx row 0x%lx depth %lx dimensions %ld x %ld\n", 
+	printk (KERN_DEBUG " Penguin bootinfo data:\n");
+	printk (KERN_DEBUG " Video: addr 0x%lx row 0x%lx depth %lx dimensions %ld x %ld\n", 
 		mac_bi_data.videoaddr, mac_bi_data.videorow, 
 		mac_bi_data.videodepth, mac_bi_data.dimensions & 0xFFFF, 
 		mac_bi_data.dimensions >> 16); 
-	printk (" Videological 0x%lx phys. 0x%lx, SCC at 0x%lx \n",
+	printk (KERN_DEBUG " Videological 0x%lx phys. 0x%lx, SCC at 0x%lx \n",
 		mac_bi_data.videological, mac_orig_videoaddr, 
 		mac_bi_data.sccbase); 
-	printk (" Boottime: 0x%lx GMTBias: 0x%lx \n",
+	printk (KERN_DEBUG " Boottime: 0x%lx GMTBias: 0x%lx \n",
 		mac_bi_data.boottime, mac_bi_data.gmtbias); 
-	printk (" Machine ID: %ld CPUid: 0x%lx memory size: 0x%lx \n",
+	printk (KERN_DEBUG " Machine ID: %ld CPUid: 0x%lx memory size: 0x%lx \n",
 		mac_bi_data.id, mac_bi_data.cpuid, mac_bi_data.memsize); 
 #if 0
 	printk ("Ramdisk: addr 0x%lx size 0x%lx\n", 
@@ -511,7 +512,7 @@
 	    MACHW_SET(MAC_SCSI_96_2);
 	  break;
 	default:
-	  printk("config.c: wtf: unknown scsi, using 53c80\n");
+	  printk(KERN_WARNING "config.c: wtf: unknown scsi, using 53c80\n");
 	  MACHW_SET(MAC_SCSI_80);
 	  break;
 
@@ -525,7 +526,7 @@
 
 void mac_report_hardware(void)
 {
-	printk("Apple Macintosh %s\n", macintosh_config->name);
+	printk(KERN_INFO "Apple Macintosh %s\n", macintosh_config->name);
 }
 
 static void mac_get_model(char *str)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/mac/iop.c linux-2.4.21-pre6/arch/m68k/mac/iop.c
--- linux-2.4.20/arch/m68k/mac/iop.c	2001-06-12 02:15:27.000000000 +0000
+++ linux-2.4.21-pre6/arch/m68k/mac/iop.c	2003-03-26 23:49:30.000000000 +0000
@@ -28,7 +28,7 @@
  *		  globally-visible functions take an IOP number instead of an
  *		  an actual base address.
  * 990610 (jmt) - Finished the message passing framework and it seems to work.
- *		  Sending _definately_ works; my adb-bus.c mods can send
+ *		  Sending _definitely_ works; my adb-bus.c mods can send
  *		  messages and receive the MSG_COMPLETED status back from the
  *		  IOP. The trick now is figuring out the message formats.
  * 990611 (jmt) - More cleanups. Fixed problem where unclaimed messages on a
@@ -236,7 +236,7 @@
 
 /*
  * This is called by the startup code before anything else. Its purpose
- * is to find and initalize the IOPs early in the boot sequence, so that
+ * is to find and initialize the IOPs early in the boot sequence, so that
  * the serial IOP can be placed into bypass mode _before_ we try to
  * initialize the serial console.
  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/mac/macints.c linux-2.4.21-pre6/arch/m68k/mac/macints.c
--- linux-2.4.20/arch/m68k/mac/macints.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/m68k/mac/macints.c	2003-03-26 23:49:53.000000000 +0000
@@ -30,7 +30,7 @@
  *		  - slot 0: SCSI interrupt
  *		  - slot 1: Sound interrupt
  *
- * Levels 3-6 vary by machine type. For VIA or RBV Macintohes:
+ * Levels 3-6 vary by machine type. For VIA or RBV Macintoshes:
  *
  *	3	- unused (?)
  *
@@ -494,7 +494,7 @@
  * Add an interrupt service routine to an interrupt source.
  * Returns 0 on success.
  *
- * FIXME: You can register interrupts on nonexistant source (ie PSC4 on a
+ * FIXME: You can register interrupts on nonexistent source (ie PSC4 on a
  *        non-PSC machine). We should return -EINVAL in those cases.
  */
  
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/mac/via.c linux-2.4.21-pre6/arch/m68k/mac/via.c
--- linux-2.4.20/arch/m68k/mac/via.c	2001-06-12 02:15:27.000000000 +0000
+++ linux-2.4.21-pre6/arch/m68k/mac/via.c	2003-03-26 23:49:30.000000000 +0000
@@ -137,15 +137,15 @@
 			panic("UNKNOWN VIA TYPE");
 	}
 
-	printk("VIA1 at %p is a 6522 or clone\n", via1);
+	printk(KERN_INFO "VIA1 at %p is a 6522 or clone\n", via1);
 
-	printk("VIA2 at %p is ", via2);
+	printk(KERN_INFO "VIA2 at %p is ", via2);
 	if (rbv_present) {
-		printk("an RBV\n");
+		printk(KERN_INFO "an RBV\n");
 	} else if (oss_present) {
-		printk("an OSS\n");
+		printk(KERN_INFO "an OSS\n");
 	} else {
-		printk("a 6522 or clone\n");
+		printk(KERN_INFO "a 6522 or clone\n");
 	}
 
 #ifdef DEBUG_VIA
@@ -291,22 +291,22 @@
 
 void via_debug_dump(void)
 {
-	printk("VIA1: DDRA = 0x%02X DDRB = 0x%02X ACR = 0x%02X\n",
+	printk(KERN_DEBUG "VIA1: DDRA = 0x%02X DDRB = 0x%02X ACR = 0x%02X\n",
 		(uint) via1[vDirA], (uint) via1[vDirB], (uint) via1[vACR]);
-	printk("         PCR = 0x%02X  IFR = 0x%02X IER = 0x%02X\n",
+	printk(KERN_DEBUG "         PCR = 0x%02X  IFR = 0x%02X IER = 0x%02X\n",
 		(uint) via1[vPCR], (uint) via1[vIFR], (uint) via1[vIER]);
 	if (oss_present) {
-		printk("VIA2: <OSS>\n");
+		printk(KERN_DEBUG "VIA2: <OSS>\n");
 	} else if (rbv_present) {
-		printk("VIA2:  IFR = 0x%02X  IER = 0x%02X\n",
+		printk(KERN_DEBUG "VIA2:  IFR = 0x%02X  IER = 0x%02X\n",
 			(uint) via2[rIFR], (uint) via2[rIER]);
-		printk("      SIFR = 0x%02X SIER = 0x%02X\n",
+		printk(KERN_DEBUG "      SIFR = 0x%02X SIER = 0x%02X\n",
 			(uint) via2[rSIFR], (uint) via2[rSIER]);
 	} else {
-		printk("VIA2: DDRA = 0x%02X DDRB = 0x%02X ACR = 0x%02X\n",
+		printk(KERN_DEBUG "VIA2: DDRA = 0x%02X DDRB = 0x%02X ACR = 0x%02X\n",
 			(uint) via2[vDirA], (uint) via2[vDirB],
 			(uint) via2[vACR]);
-		printk("         PCR = 0x%02X  IFR = 0x%02X IER = 0x%02X\n",
+		printk(KERN_DEBUG "         PCR = 0x%02X  IFR = 0x%02X IER = 0x%02X\n",
 			(uint) via2[vPCR],
 			(uint) via2[vIFR], (uint) via2[vIER]);
 	}
@@ -374,7 +374,10 @@
 
 	if (!rbv_present) {
 		/* set the line to be an output on non-RBV machines */
-		via2[vDirB] |= 0x02;
+		if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
+		   (macintosh_config->adb_type != MAC_ADB_PB2)) {
+			via2[vDirB] |= 0x02;
+		}
 	}
 
 	/* this seems to be an ADB bit on PMU machines */
@@ -390,8 +393,23 @@
 		via2[rSIER] = 0x7F;
 		via2[rSIER] = nubus_active | 0x80;
 	} else {
-		via2[vBufA] = 0xFF;
-		via2[vDirA] = ~nubus_active;
+		/* These are ADB bits on PMU */
+		if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
+		   (macintosh_config->adb_type != MAC_ADB_PB2)) {
+			switch(macintosh_config->ident)
+			{
+				case MAC_MODEL_II:
+				case MAC_MODEL_IIX:
+				case MAC_MODEL_IICX:
+				case MAC_MODEL_SE30:
+					via2[vBufA] |= 0x3F;
+					via2[vDirA] = ~nubus_active | 0xc0;
+					break;
+				default:
+					via2[vBufA] = 0xFF;
+					via2[vDirA] = ~nubus_active;
+			}
+		}
 	}
 }
 
@@ -481,7 +499,7 @@
 	int irq_bit	= 1 << irq_idx;
 
 #ifdef DEBUG_IRQUSE
-	printk("via_irq_enable(%d)\n", irq);
+	printk(KERN_DEBUG "via_irq_enable(%d)\n", irq);
 #endif
 
 	if (irq_src == 1) {
@@ -508,7 +526,21 @@
 			via2[rSIER] = IER_SET_BIT(irq_idx);
 		} else {
 			/* Make sure the bit is an input, to enable the irq */
-			via2[vDirA] &= ~irq_bit;
+			/* But not on PowerBooks, that's ADB... */
+			if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
+			   (macintosh_config->adb_type != MAC_ADB_PB2)) {
+			   	switch(macintosh_config->ident)
+				{
+					case MAC_MODEL_II:
+					case MAC_MODEL_IIX:
+					case MAC_MODEL_IICX:
+					case MAC_MODEL_SE30:
+						via2[vDirA] &= (~irq_bit | 0xc0);
+						break;
+					default:
+						via2[vDirA] &= ~irq_bit;
+				}
+			}
 		}
 		nubus_active |= irq_bit;
 	}
@@ -520,7 +552,7 @@
 	int irq_bit	= 1 << irq_idx;
 
 #ifdef DEBUG_IRQUSE
-	printk("via_irq_disable(%d)\n", irq);
+	printk(KERN_DEBUG "via_irq_disable(%d)\n", irq);
 #endif
 
 	if (irq_src == 1) {
@@ -533,7 +565,11 @@
 			via2[rSIER] = IER_CLR_BIT(irq_idx);
 		} else {
 			/* disable the nubus irq by changing dir to output */
-			via2[vDirA] |= irq_bit;
+			/* except on PMU */
+			if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
+			   (macintosh_config->adb_type != MAC_ADB_PB2)) {
+				via2[vDirA] |= irq_bit;
+			}
 		}
 		nubus_active &= ~irq_bit;
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/math-emu/fp_arith.c linux-2.4.21-pre6/arch/m68k/math-emu/fp_arith.c
--- linux-2.4.20/arch/m68k/math-emu/fp_arith.c	1999-08-15 18:47:29.000000000 +0000
+++ linux-2.4.21-pre6/arch/m68k/math-emu/fp_arith.c	2003-03-26 23:49:19.000000000 +0000
@@ -113,7 +113,7 @@
 	return dest;
 }
 
-/* fp_fsub: Implementes the kernel of the FSUB, FSSUB, and FDSUB
+/* fp_fsub: Implements the kernel of the FSUB, FSSUB, and FDSUB
    instructions.
 
    Remember that the arguments are in assembler-syntax order! */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/mm/Makefile linux-2.4.21-pre6/arch/m68k/mm/Makefile
--- linux-2.4.20/arch/m68k/mm/Makefile	2000-12-29 22:07:20.000000000 +0000
+++ linux-2.4.21-pre6/arch/m68k/mm/Makefile	2003-03-26 23:49:09.000000000 +0000
@@ -14,7 +14,7 @@
 ifndef CONFIG_SUN3
 obj-y		+= kmap.o memory.o motorola.o
 else
-obj-y		+= sun3mmu.o
+obj-y		+= sun3kmap.o sun3mmu.o
 endif
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/mm/memory.c linux-2.4.21-pre6/arch/m68k/mm/memory.c
--- linux-2.4.20/arch/m68k/mm/memory.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/m68k/mm/memory.c	2003-03-26 23:49:50.000000000 +0000
@@ -434,46 +434,51 @@
 #endif
 
 /* invalidate page in both caches */
-#define	clear040(paddr)					\
-	__asm__ __volatile__ ("nop\n\t"			\
-			      ".chip 68040\n\t"		\
-			      "cinvp %%bc,(%0)\n\t"	\
-			      ".chip 68k"		\
-			      : : "a" (paddr))
+static inline void clear040(unsigned long paddr)
+{
+	asm volatile (
+		"nop\n\t"
+		".chip 68040\n\t"
+		"cinvp %%bc,(%0)\n\t"
+		".chip 68k"
+		: : "a" (paddr));
+}
 
 /* invalidate page in i-cache */
-#define	cleari040(paddr)				\
-	__asm__ __volatile__ ("nop\n\t"			\
-			      ".chip 68040\n\t"		\
-			      "cinvp %%ic,(%0)\n\t"	\
-			      ".chip 68k"		\
-			      : : "a" (paddr))
+static inline void cleari040(unsigned long paddr)
+{
+	asm volatile (
+		"nop\n\t"
+		".chip 68040\n\t"
+		"cinvp %%ic,(%0)\n\t"
+		".chip 68k"
+		: : "a" (paddr));
+}
 
 /* push page in both caches */
-#define	push040(paddr)					\
-	__asm__ __volatile__ ("nop\n\t"			\
-			      ".chip 68040\n\t"		\
-			      "cpushp %%bc,(%0)\n\t"	\
-			      ".chip 68k"		\
-			      : : "a" (paddr))
+/* RZ: cpush %bc DOES invalidate %ic, regardless of DPI */
+static inline void push040(unsigned long paddr)
+{
+	asm volatile (
+		"nop\n\t"
+		".chip 68040\n\t"
+		"cpushp %%bc,(%0)\n\t"
+		".chip 68k"
+		: : "a" (paddr));
+}
 
 /* push and invalidate page in both caches, must disable ints
  * to avoid invalidating valid data */
-#define	pushcl040(paddr)			\
-	do { unsigned long flags;               \
-             save_flags(flags);                 \
-	     cli();                             \
-             push040(paddr);			\
-	     if (CPU_IS_060) clear040(paddr);	\
-	     restore_flags(flags);              \
-	} while(0)
-
-/* push page in both caches, invalidate in i-cache */
-/* RZ: cpush %bc DOES invalidate %ic, regardless of DPI */
-#define	pushcli040(paddr)			\
-	do { push040(paddr);			\
-	} while(0)
+static inline void pushcl040(unsigned long paddr)
+{
+	unsigned long flags;
 
+	local_irq_save(flags);
+	push040(paddr);
+	if (CPU_IS_060)
+		clear040(paddr);
+	local_irq_restore(flags);
+}
 
 /*
  * 040: Hit every page containing an address in the range paddr..paddr+len-1.
@@ -567,7 +572,7 @@
 	paddr &= PAGE_MASK;
 
 	do {
-	    pushcli040(paddr);
+	    push040(paddr);
 	    paddr += tmp;
 	} while ((len -= tmp) > 0);
     }
@@ -593,12 +598,6 @@
 }
 
 
-#undef clear040
-#undef cleari040
-#undef push040
-#undef pushcl040
-#undef pushcli040
-
 #ifndef CONFIG_SINGLE_MEMORY_CHUNK
 int mm_end_of_chunk (unsigned long addr, int len)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/mm/sun3kmap.c linux-2.4.21-pre6/arch/m68k/mm/sun3kmap.c
--- linux-2.4.20/arch/m68k/mm/sun3kmap.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/m68k/mm/sun3kmap.c	2003-03-26 23:48:57.000000000 +0000
@@ -0,0 +1,156 @@
+/*
+ * linux/arch/m68k/mm/sun3kmap.c
+ *
+ * Copyright (C) 2002 Sam Creasey <sammy@sammy.net>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+#include <asm/sun3mmu.h>
+
+#undef SUN3_KMAP_DEBUG
+
+#ifdef SUN3_KMAP_DEBUG
+extern void print_pte_vaddr(unsigned long vaddr);
+#endif
+
+extern void mmu_emu_map_pmeg (int context, int vaddr);
+
+static inline void do_page_mapin(unsigned long phys, unsigned long virt, 
+				 unsigned long type)
+{
+	unsigned long pte;
+	pte_t ptep;
+
+	ptep = mk_pte_phys(phys, PAGE_KERNEL);
+	pte = pte_val(ptep);
+	pte |= type;
+
+	sun3_put_pte(virt, pte);
+
+#ifdef SUN3_KMAP_DEBUG
+	print_pte_vaddr(virt);
+#endif
+
+}
+
+static inline void do_pmeg_mapin(unsigned long phys, unsigned long virt, 
+				 unsigned long type, int pages)
+{
+
+	if(sun3_get_segmap(virt & ~SUN3_PMEG_MASK) == SUN3_INVALID_PMEG) 
+		mmu_emu_map_pmeg(sun3_get_context(), virt);
+
+	while(pages) {
+		do_page_mapin(phys, virt, type);
+		phys += PAGE_SIZE;
+		virt += PAGE_SIZE;
+		pages--;
+	}
+}
+
+void *sun3_ioremap(unsigned long phys, unsigned long size, 
+		   unsigned long type)
+{
+	struct vm_struct *area;
+	unsigned long offset, virt, ret;
+	int pages;
+
+	if(!size)
+		return NULL;
+
+	/* page align */
+	offset = phys & (PAGE_SIZE-1);
+	phys &= ~(PAGE_SIZE-1);
+
+	size += offset;
+	size = PAGE_ALIGN(size);
+	if((area = get_vm_area(size, VM_IOREMAP)) == NULL)
+		return NULL;
+
+#ifdef SUN3_KMAP_DEBUG
+	printk("ioremap: got virt %p size %lx(%lx)\n", 
+	       area->addr, size, area->size);
+#endif
+
+	pages = size / PAGE_SIZE;
+	virt = (unsigned long)area->addr;
+	ret = virt + offset;
+
+	while(pages) {
+		int seg_pages;
+
+		seg_pages = (SUN3_PMEG_SIZE - (virt & SUN3_PMEG_MASK)) / PAGE_SIZE;
+		if(seg_pages > pages)
+			seg_pages = pages;
+		
+		do_pmeg_mapin(phys, virt, type, seg_pages);
+
+		pages -= seg_pages;
+		phys += seg_pages * PAGE_SIZE;
+		virt += seg_pages * PAGE_SIZE;
+	}
+		
+	return (void *)ret;
+
+}
+ 
+ 
+void *__ioremap(unsigned long phys, unsigned long size, int cache)
+{
+	
+	return sun3_ioremap(phys, size, SUN3_PAGE_TYPE_IO);
+	
+}
+
+void iounmap(void *addr)
+{
+	vfree((void *)(PAGE_MASK & (unsigned long)addr));	
+}
+
+/* sun3_map_test(addr, val) -- Reads a byte from addr, storing to val,
+ * trapping the potential read fault.  Returns 0 if the access faulted,
+ * 1 on success.
+ *  
+ * This function is primarily used to check addresses on the VME bus.
+ *
+ * Mucking with the page fault handler seems a little hackish to me, but
+ * SunOS, NetBSD, and Mach all implemented this check in such a manner, 
+ * so I figure we're allowed.
+ */
+int sun3_map_test(unsigned long addr, char *val)
+{
+	int ret = 0;
+
+	__asm__ __volatile__
+		(".globl _sun3_map_test_start\n"
+		 "_sun3_map_test_start:\n"
+		 "1: moveb (%2), (%0)\n"
+		 "   moveq #1, %1\n"
+		 "2:\n"
+		 ".section .fixup,\"ax\"\n"
+		 ".even\n"
+		 "3: moveq #0, %1\n"
+		 "   jmp 2b\n"
+		 ".previous\n"
+		 ".section __ex_table,\"a\"\n"
+		 ".align 4\n"
+		 ".long 1b,3b\n"
+		 ".previous\n"
+		 ".globl _sun3_map_test_end\n"
+		 "_sun3_map_test_end:\n"
+		 : "=a"(val), "=r"(ret)
+		 : "a"(addr));
+	
+	return ret;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/mm/sun3mmu.c linux-2.4.21-pre6/arch/m68k/mm/sun3mmu.c
--- linux-2.4.20/arch/m68k/mm/sun3mmu.c	2000-12-29 22:07:20.000000000 +0000
+++ linux-2.4.21-pre6/arch/m68k/mm/sun3mmu.c	2003-03-26 23:49:19.000000000 +0000
@@ -96,13 +96,12 @@
 	}
 
 	mmu_emu_init(bootmem_end);
-	
+
 	current->mm = NULL;
 
 	/* memory sizing is a hack stolen from motorola.c..  hope it works for us */
-	zones_size[1] = ((unsigned long)high_memory - PAGE_OFFSET) >> PAGE_SHIFT;
-	zones_size[0] = zones_size[1]/2;
-	zones_size[1] -= zones_size[0];
+	zones_size[0] = ((unsigned long)high_memory - PAGE_OFFSET) >> PAGE_SHIFT;
+	zones_size[1] = 0;
 	
 	free_area_init(zones_size);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/mvme16x/rtc.c linux-2.4.21-pre6/arch/m68k/mvme16x/rtc.c
--- linux-2.4.20/arch/m68k/mvme16x/rtc.c	2001-06-12 02:15:27.000000000 +0000
+++ linux-2.4.21-pre6/arch/m68k/mvme16x/rtc.c	2003-03-26 23:49:39.000000000 +0000
@@ -168,7 +168,6 @@
 		return -ENODEV;
 
 	printk(KERN_INFO "MK48T08 Real Time Clock Driver v%s\n", RTC_VERSION);
-	misc_register(&rtc_dev);
-	return 0;
+	return misc_register(&rtc_dev);
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/q40/q40ints.c linux-2.4.21-pre6/arch/m68k/q40/q40ints.c
--- linux-2.4.20/arch/m68k/q40/q40ints.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/m68k/q40/q40ints.c	2003-03-26 23:49:25.000000000 +0000
@@ -7,7 +7,7 @@
  * License.  See the file COPYING in the main directory of this archive
  * for more details.
  *
- * .. used to be losely based on bvme6000ints.c
+ * .. used to be loosely based on bvme6000ints.c
  *
  */
 
@@ -271,7 +271,7 @@
 #if 0
 static struct IRQ_TABLE iirqs[]={
   {Q40_IRQ_FRAME_MASK,Q40_IRQ_FRAME},
-  Q40_{IRQ_KEYB_MASK,Q40_IRQ_KEYBOARD},
+  {Q40_IRQ_KEYB_MASK,Q40_IRQ_KEYBOARD},
   {0,0}};
 #endif
 static struct IRQ_TABLE eirqs[]={
@@ -438,7 +438,7 @@
 {
   /* disable ISA iqs : only do something if the driver has been
    * verified to be Q40 "compatible" - right now IDE, NE2K
-   * Any driver should not attempt to sleep accross disable_irq !!
+   * Any driver should not attempt to sleep across disable_irq !!
    */
 
   if ( irq>=5 && irq<=15 ) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/sun3/Makefile linux-2.4.21-pre6/arch/m68k/sun3/Makefile
--- linux-2.4.20/arch/m68k/sun3/Makefile	2001-06-12 02:15:27.000000000 +0000
+++ linux-2.4.21-pre6/arch/m68k/sun3/Makefile	2003-03-26 23:48:57.000000000 +0000
@@ -14,9 +14,9 @@
 
 export-objs	:= sun3_ksyms.o
 
-obj-y	:= sun3_ksyms.o sun3ints.o sun3dvma.o sbus.o
+obj-y	:= sun3_ksyms.o sun3ints.o sun3dvma.o sbus.o idprom.o
 
-obj-$(CONFIG_SUN3) += config.o idprom.o mmu_emu.o leds.o dvma.o \
+obj-$(CONFIG_SUN3) += config.o mmu_emu.o leds.o dvma.o \
 			intersil.o
 
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/sun3/idprom.c linux-2.4.21-pre6/arch/m68k/sun3/idprom.c
--- linux-2.4.20/arch/m68k/sun3/idprom.c	1999-09-08 18:20:42.000000000 +0000
+++ linux-2.4.21-pre6/arch/m68k/sun3/idprom.c	2003-03-26 23:49:26.000000000 +0000
@@ -31,8 +31,8 @@
 { "Sun 3/60", (SM_SUN3 | SM_3_60) },
 { "Sun 3/E", (SM_SUN3 | SM_3_E) },
 /* Now, Sun3x's */
-{ "Sun 3/460 Series", (SM_SUN3 | SM_3_460) },
-{ "Sun 3/80", (SM_SUN3 | SM_3_80) },
+{ "Sun 3/460 Series", (SM_SUN3X | SM_3_460) },
+{ "Sun 3/80", (SM_SUN3X | SM_3_80) },
 /* Then, Sun4's */
 //{ "Sun 4/100 Series", (SM_SUN4 | SM_4_110) },
 //{ "Sun 4/200 Series", (SM_SUN4 | SM_4_260) },
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/sun3/mmu_emu.c linux-2.4.21-pre6/arch/m68k/sun3/mmu_emu.c
--- linux-2.4.20/arch/m68k/sun3/mmu_emu.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/m68k/sun3/mmu_emu.c	2003-03-26 23:49:02.000000000 +0000
@@ -178,7 +178,6 @@
 			pmeg_alloc[sun3_get_segmap(seg)] = 2;
 		}
 	}
-
 	
 	dvma_init();
 	
@@ -277,7 +276,7 @@
 //todo: better allocation scheme? but is extra complexity worthwhile?
 //todo: only clear old entries if necessary? how to tell?
 
-static inline void mmu_emu_map_pmeg (int context, int vaddr)
+inline void mmu_emu_map_pmeg (int context, int vaddr)
 {
 	static unsigned char curr_pmeg = 128;
 	int i;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/sun3/sun3dvma.c linux-2.4.21-pre6/arch/m68k/sun3/sun3dvma.c
--- linux-2.4.20/arch/m68k/sun3/sun3dvma.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/m68k/sun3/sun3dvma.c	2003-03-26 23:49:10.000000000 +0000
@@ -97,7 +97,7 @@
 	printk("end of hole listing...\n");
 	
 }
-#endif DVMA_DEBUG
+#endif /* DVMA_DEBUG */
 
 static inline int refill(void)
 {
@@ -317,8 +317,14 @@
 
 void dvma_unmap(void *baddr)
 {
-
-	free_baddr((unsigned long)baddr);
+	unsigned long addr;
+	
+	addr = (unsigned long)baddr;
+	/* check if this is a vme mapping */
+	if(!(addr & 0x00f00000))
+		addr |= 0xf00000;
+	
+	free_baddr(addr);
 	
 	return;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/sun3/sun3ints.c linux-2.4.21-pre6/arch/m68k/sun3/sun3ints.c
--- linux-2.4.20/arch/m68k/sun3/sun3ints.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/m68k/sun3/sun3ints.c	2003-03-26 23:49:39.000000000 +0000
@@ -17,6 +17,7 @@
 #include <asm/sun3ints.h>
 
 extern void sun3_leds (unsigned char);
+static void sun3_inthandle(int irq, void *dev_id, struct pt_regs *fp);
 
 void sun3_disable_interrupts(void)
 {
@@ -62,11 +63,6 @@
 	*sun3_intreg |=  (1<<irq);
 }
 
-int sun3_get_irq_list(char *buf)
-{
-	return 0;
-}
-
 static void sun3_int7(int irq, void *dev_id, struct pt_regs *fp)
 {
 	sun3_do_irq(irq,fp);
@@ -93,13 +89,39 @@
 
 /* handle requested ints, excepting 5 and 7, which always do the same
    thing */
+void (*sun3_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = {
+	sun3_inthandle, sun3_inthandle, sun3_inthandle, sun3_inthandle,
+	sun3_inthandle, sun3_int5, sun3_inthandle, sun3_int7
+};
+
+static const char *dev_names[SYS_IRQS] = { NULL, NULL, NULL, NULL,
+				     NULL, "timer", NULL, "int7 handler" };
 static void *dev_ids[SYS_IRQS];
 static void (*sun3_inthandler[SYS_IRQS])(int, void *, struct pt_regs *) = {
 	NULL, NULL, NULL, NULL, NULL, sun3_int5, NULL, sun3_int7
 };
-static void (*sun3_vechandler[192])(int, void *, struct pt_regs *);
-static void *vec_ids[192];
-static const char *vec_names[192];
+
+static void (*sun3_vechandler[SUN3_INT_VECS])(int, void *, struct pt_regs *);
+static void *vec_ids[SUN3_INT_VECS];
+static const char *vec_names[SUN3_INT_VECS];
+static int vec_ints[SUN3_INT_VECS];
+
+
+int sun3_get_irq_list(char *buf)
+{
+	int i, len = 0;
+
+	for(i = 0; i < (SUN3_INT_VECS-1); i++) {
+		if(sun3_vechandler[i] != NULL) {
+			len += sprintf(buf+len, "vec %3d: %10u %s\n", i+64,
+				       vec_ints[i],
+				       (vec_names[i]) ? vec_names[i] :
+				       "sun3_vechandler");
+		}
+	}
+
+	return 0;
+}
 
 static void sun3_inthandle(int irq, void *dev_id, struct pt_regs *fp)
 {
@@ -117,14 +139,6 @@
 //	intersil_clear();
 }
 
-void (*sun3_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = {
-	sun3_inthandle, sun3_inthandle, sun3_inthandle, sun3_inthandle,
-	sun3_inthandle, sun3_int5, sun3_inthandle, sun3_int7
-};
-
-static const char *dev_names[SYS_IRQS] = { NULL, NULL, NULL, NULL,
-					   NULL, "timer", NULL, NULL };
-
 void sun3_init_IRQ(void)
 {
 	int i;
@@ -175,6 +189,7 @@
 			sun3_vechandler[vec] = handler;
 			vec_ids[vec] = dev_id;
 			vec_names[vec] = devname;
+			vec_ints[vec] = 0;
 			
 			return 0;
 		}
@@ -221,7 +236,8 @@
 		vec = irq - 64;
 		if(sun3_vechandler[vec] == NULL) 
 			panic ("bad interrupt vector %d received\n",irq);
-			
+
+		vec_ints[vec]++;
 		sun3_vechandler[vec](irq, vec_ids[vec], regs);
 		return;
 	} else {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/sun3x/config.c linux-2.4.21-pre6/arch/m68k/sun3x/config.c
--- linux-2.4.20/arch/m68k/sun3x/config.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/m68k/sun3x/config.c	2003-03-26 23:48:58.000000000 +0000
@@ -17,12 +17,14 @@
 #include <asm/sun3xprom.h>
 #include <asm/sun3ints.h>
 #include <asm/setup.h>
+#include <asm/oplib.h>
 
 #include "time.h"
 
 volatile char *clock_va;
 extern volatile unsigned char *sun3_intreg;
 
+extern void sun3_get_model(char *model);
 
 int __init sun3x_keyb_init(void)
 {
@@ -44,10 +46,16 @@
 
 }
 
-/* should probably detect types of these eventually. */
-static void sun3x_get_model(char *model)
+static int sun3x_get_hardware_list(char *buffer)
 {
-	sprintf(model, "Sun3x");
+
+	int len = 0;
+
+	len += sprintf(buffer + len, "PROM Revision:\t%s\n",
+		       romvec->pv_monid);
+
+	return len;
+
 }
 
 /*
@@ -81,7 +89,8 @@
 
 	mach_gettod          = sun3x_gettod;
 	mach_hwclk           = sun3x_hwclk;
-	mach_get_model       = sun3x_get_model;
+	mach_get_model       = sun3_get_model;
+	mach_get_hardware_list = sun3x_get_hardware_list;
 
 	sun3_intreg = (unsigned char *)SUN3X_INTREG;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/m68k/sun3x/prom.c linux-2.4.21-pre6/arch/m68k/sun3x/prom.c
--- linux-2.4.20/arch/m68k/sun3x/prom.c	2002-11-28 23:53:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/m68k/sun3x/prom.c	2003-03-26 23:49:34.000000000 +0000
@@ -26,8 +26,6 @@
 int (*sun3x_mayput)(int);
 void (*sun3x_prom_reboot)(void);
 e_vector sun3x_prom_abort;
-struct idprom *idprom;
-static struct idprom idprom_buffer;
 struct linux_romvec *romvec;
 
 /* prom vector table */
@@ -107,8 +105,6 @@
 void sun3x_prom_init(void)
 {
     /* Read the vector table */
-	int i;
-
 
     sun3x_putchar = *(void (**)(int)) (SUN3X_P_PUTCHAR);
     sun3x_getchar = *(int (**)(void)) (SUN3X_P_GETCHAR);
@@ -118,12 +114,9 @@
     sun3x_prom_abort = *(e_vector *)  (SUN3X_P_ABORT);
     romvec = (struct linux_romvec *)SUN3X_PROM_BASE;
 
-    /* make a copy of the idprom structure */
-    for(i = 0; i < sizeof(struct idprom); i++) 
-	    ((unsigned char *)(&idprom_buffer))[i] = ((unsigned char *)SUN3X_IDPROM)[i];
-    idprom = &idprom_buffer;
+    idprom_init();
 
-    if((idprom->id_machtype & SM_ARCH_MASK) != SM_SUN3X) {
+    if(!((idprom->id_machtype & SM_ARCH_MASK) == SM_SUN3X)) {
 	    printk("Warning: machine reports strange type %02x\n",
 		   idprom->id_machtype);
 	    printk("Pretending it's a 3/80, but very afraid...\n");
@@ -163,3 +156,19 @@
 {
 	sun3x_halt();
 }
+
+/* Get the idprom and stuff it into buffer 'idbuf'.  Returns the
+ * format type.  'num_bytes' is the number of bytes that your idbuf
+ * has space for.  Returns 0xff on error.
+ */
+unsigned char
+prom_get_idprom(char *idbuf, int num_bytes)
+{
+        int i;
+
+	/* make a copy of the idprom structure */
+	for(i = 0; i < num_bytes; i++) 
+		idbuf[i] = ((char *)SUN3X_IDPROM)[i];
+
+        return idbuf[0];
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/mips/kernel/process.c linux-2.4.21-pre6/arch/mips/kernel/process.c
--- linux-2.4.20/arch/mips/kernel/process.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-pre6/arch/mips/kernel/process.c	2003-03-26 23:49:30.000000000 +0000
@@ -152,7 +152,7 @@
 /*
  * Create a kernel thread
  */
-int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 {
 	long retval;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/mips64/kernel/process.c linux-2.4.21-pre6/arch/mips64/kernel/process.c
--- linux-2.4.20/arch/mips64/kernel/process.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-pre6/arch/mips64/kernel/process.c	2003-03-26 23:49:20.000000000 +0000
@@ -151,7 +151,7 @@
 /*
  * Create a kernel thread
  */
-int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
+int arch_kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
 {
 	int retval;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/Makefile linux-2.4.21-pre6/arch/parisc/Makefile
--- linux-2.4.20/arch/parisc/Makefile	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-pre6/arch/parisc/Makefile	2003-03-26 23:49:27.000000000 +0000
@@ -91,14 +91,6 @@
 SUBDIRS := $(SUBDIRS) arch/parisc/math-emu
 DRIVERS := $(DRIVERS) arch/parisc/math-emu/math.o
 
-ifdef CONFIG_KWDB
-SUBDIRS := $(SUBDIRS) arch/parisc/kdb
-DRIVERS := $(DRIVERS) arch/parisc/kdb/kdb.o
-
-arch/parisc/kdb: dummy
-	$(MAKE) linuxsubdirs SUBDIRS=arch/parisc/kdb
-endif
-
 arch/parisc/kernel: dummy
 	$(MAKE) linuxsubdirs SUBDIRS=arch/parisc/kernel
 
@@ -106,6 +98,21 @@
 	$(MAKE) linuxsubdirs SUBDIRS=arch/parisc/mm
 
 palo: vmlinux
+	@if [ $$(palo -f /dev/null >/dev/null 2>&1 ; echo $$?) != 2 ]; then \
+		echo 'ERROR: Please install palo first (apt-get install palo)';\
+		echo 'or build it from source and install it somewhere in your $$PATH';\
+		false; \
+	fi
+	@if [ ! -f ./palo.conf ]; then \
+		cp arch/parisc/defpalo.conf palo.conf; \
+		echo 'A generic palo config file (./palo.conf) has been created for you.'; \
+		echo 'You should check it and re-run "make palo".'; \
+		echo 'WARNING: the "lifimage" file is now placed in this directory by default!'; \
+		false; \
+	fi
+	palo -f ./palo.conf
+
+oldpalo: vmlinux
 	export TOPDIR=`pwd`; \
 	unset STRIP LDFLAGS CPP CPPFLAGS AFLAGS CFLAGS CC LD; cd ../palo && make lifimage
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/defconfig linux-2.4.21-pre6/arch/parisc/defconfig
--- linux-2.4.20/arch/parisc/defconfig	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-pre6/arch/parisc/defconfig	2003-03-26 23:48:59.000000000 +0000
@@ -32,7 +32,6 @@
 #
 # CONFIG_SMP is not set
 CONFIG_CHASSIS_LCD_LED=y
-# CONFIG_KWDB is not set
 CONFIG_IOMMU_CCIO=y
 CONFIG_GSC=y
 CONFIG_GSC_LASI=y
@@ -87,7 +86,9 @@
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_NBD is not set
 CONFIG_BLK_DEV_RAM=y
@@ -138,6 +139,11 @@
 #
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -155,6 +161,11 @@
 # CONFIG_NET_SCHED is not set
 
 #
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
 # ATA/IDE/MFM/RLL support
 #
 CONFIG_IDE=y
@@ -171,6 +182,7 @@
 # CONFIG_BLK_DEV_HD is not set
 # CONFIG_BLK_DEV_IDEDISK is not set
 # CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_IDEDISK_STROKE is not set
 # CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
 # CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
 # CONFIG_BLK_DEV_IDEDISK_IBM is not set
@@ -185,6 +197,7 @@
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
 # CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
 
 #
 # IDE chipset support/bugfixes
@@ -196,12 +209,15 @@
 CONFIG_BLK_DEV_IDEPCI=y
 # CONFIG_IDEPCI_SHARE_IRQ is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
-CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
 # CONFIG_IDEDMA_PCI_AUTO is not set
+# CONFIG_IDEDMA_ONLYDISK is not set
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_PCI_WIP is not set
+# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
+CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_AEC62XX_TUNING is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
@@ -209,6 +225,7 @@
 # CONFIG_BLK_DEV_AMD74XX is not set
 # CONFIG_AMD74XX_OVERRIDE is not set
 # CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_CMD680 is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5530 is not set
 # CONFIG_BLK_DEV_HPT34X is not set
@@ -296,9 +313,13 @@
 CONFIG_53C700_USE_CONSISTENT=y
 # CONFIG_SCSI_NCR53C7xx is not set
 # CONFIG_SCSI_SYM53C8XX_2 is not set
-# CONFIG_SCSI_NCR53C8XX is not set
-CONFIG_SCSI_SYM53C8XX=y
+# CONFIG_ASK_ZALON is not set
+# CONFIG_ASK_NCR53C8XX is not set
+# CONFIG_ASK_SYM53C8XX is not set
 CONFIG_SCSI_ZALON=y
+CONFIG_ASK_ZALON=y
+CONFIG_SCSI_SYM53C8XX=y
+CONFIG_ASK_SYM53C8XX=y
 CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
 CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
 CONFIG_SCSI_NCR53C8XX_SYNC=20
@@ -366,6 +387,7 @@
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
 CONFIG_TULIP=y
+# CONFIG_TC35815 is not set
 # CONFIG_TULIP_MWI is not set
 # CONFIG_TULIP_MMIO is not set
 # CONFIG_DE4X5 is not set
@@ -403,6 +425,7 @@
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
@@ -473,6 +496,7 @@
 CONFIG_PSMOUSE=y
 # CONFIG_82C710_MOUSE is not set
 # CONFIG_PC110_PAD is not set
+# CONFIG_MK712_MOUSE is not set
 
 #
 # Joysticks
@@ -515,7 +539,6 @@
 #
 # CONFIG_WATCHDOG is not set
 CONFIG_GENRTC=y
-# CONFIG_INTEL_RNG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -585,7 +608,7 @@
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 # CONFIG_TMPFS is not set
-# CONFIG_RAMFS is not set
+CONFIG_RAMFS=y
 CONFIG_ISO9660_FS=y
 CONFIG_JOLIET=y
 # CONFIG_ZISOFS is not set
@@ -697,6 +720,7 @@
 # CONFIG_FB_RIVA is not set
 # CONFIG_FB_CLGEN is not set
 # CONFIG_FB_PM2 is not set
+# CONFIG_FB_PM3 is not set
 # CONFIG_FB_CYBER2000 is not set
 CONFIG_FB_STI=y
 # CONFIG_FB_MATROX is not set
@@ -704,6 +728,7 @@
 # CONFIG_FB_RADEON is not set
 # CONFIG_FB_ATY128 is not set
 # CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
 # CONFIG_FB_3DFX is not set
 # CONFIG_FB_VOODOO1 is not set
 # CONFIG_FB_TRIDENT is not set
@@ -759,106 +784,6 @@
 # CONFIG_USB is not set
 
 #
-# USB Controllers
-#
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-# CONFIG_USB_OHCI is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_BLUETOOTH is not set
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-
-#
-# USB Human Interface Devices (HID)
-#
-# CONFIG_USB_HID is not set
-# CONFIG_USB_HIDDEV is not set
-# CONFIG_USB_KBD is not set
-# CONFIG_USB_MOUSE is not set
-# CONFIG_USB_WACOM is not set
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
-
-#
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
-#
-# CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IPAQ is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_KLSI is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
-
-#
-# USB Miscellaneous drivers
-#
-# CONFIG_USB_RIO500 is not set
-
-#
 # Kernel hacking
 #
 CONFIG_MAGIC_SYSRQ=y
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/Makefile linux-2.4.21-pre6/arch/parisc/kernel/Makefile
--- linux-2.4.20/arch/parisc/kernel/Makefile	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-pre6/arch/parisc/kernel/Makefile	2003-03-26 23:49:25.000000000 +0000
@@ -24,7 +24,7 @@
 		pa7300lc.o syscall.o entry.o sys_parisc.o firmware.o \
 		ptrace.o hardware.o inventory.o drivers.o semaphore.o \
 		signal.o hpmc.o real2.o parisc_ksyms.o unaligned.o \
-		processor.o power.o
+		processor.o power.o pdc_chassis.o
 
 export-objs	:= parisc_ksyms.o superio.o keyboard.o
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/ccio-dma.c linux-2.4.21-pre6/arch/parisc/kernel/ccio-dma.c
--- linux-2.4.20/arch/parisc/kernel/ccio-dma.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-pre6/arch/parisc/kernel/ccio-dma.c	2003-03-26 23:49:09.000000000 +0000
@@ -609,8 +609,6 @@
 		return 0;
 	}
 
-	dev->dma_mask = mask;   /* save it */
-
 	/* only support 32-bit devices (ie PCI/GSC) */
 	return (int)(mask == 0xffffffffUL);
 }
@@ -1441,7 +1439,7 @@
 	result = request_resource(&iomem_resource, res);
 	if (result < 0) {
 		printk(KERN_ERR 
-		       "%s: failed to claim CCIO bus address space (%p,%p)\n", 
+		       "%s: failed to claim CCIO bus address space (%lx,%lx)\n", 
 		       __FILE__, res->start, res->end);
 	}
 }
@@ -1486,7 +1484,7 @@
 int ccio_allocate_resource(const struct parisc_device *dev,
 		struct resource *res, unsigned long size,
 		unsigned long min, unsigned long max, unsigned long align,
-		void (*alignf)(void *, struct resource *, unsigned long),
+		void (*alignf)(void *, struct resource *, unsigned long, unsigned long),
 		void *alignf_data)
 {
 	struct ioc *ioc = ccio_get_iommu(dev);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/ccio-rm-dma.c linux-2.4.21-pre6/arch/parisc/kernel/ccio-rm-dma.c
--- linux-2.4.20/arch/parisc/kernel/ccio-rm-dma.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-pre6/arch/parisc/kernel/ccio-rm-dma.c	2003-03-26 23:49:19.000000000 +0000
@@ -74,8 +74,6 @@
 		return(0);
 	}
 
-	dev->dma_mask = mask;   /* save it */
-
 	/* only support 32-bit devices (ie PCI/GSC) */
 	return((int) (mask >= 0xffffffffUL));
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/drivers.c linux-2.4.21-pre6/arch/parisc/kernel/drivers.c
--- linux-2.4.20/arch/parisc/kernel/drivers.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-pre6/arch/parisc/kernel/drivers.c	2003-03-26 23:49:25.000000000 +0000
@@ -461,6 +461,7 @@
 #define BC_PORT_MASK 0x8
 #define BC_LOWER_PORT 0x8
 
+
 #define BUS_CONVERTER(dev) \
         ((dev->id.hw_type == HPHW_IOA) || (dev->id.hw_type == HPHW_BCPORT))
 
@@ -473,14 +474,29 @@
 	        __raw_readl((unsigned long)&((struct bc_module *)dev->hpa)->io_io_low) << 16 : \
 	        __raw_readl((unsigned long)&((struct bc_module *)dev->hpa)->io_io_low))
 
-static void walk_native_bus(unsigned long addr, struct parisc_device *parent);
+#define READ_IO_IO_HIGH(dev) \
+	(dev->id.hw_type == HPHW_IOA ? \
+	        __raw_readl((unsigned long)&((struct bc_module *)dev->hpa)->io_io_high) << 16 : \
+	        __raw_readl((unsigned long)&((struct bc_module *)dev->hpa)->io_io_high))
+
+
+static void walk_native_bus(unsigned long io_io_low, unsigned long io_io_high, 
+			    struct parisc_device *parent);
+
+#define FLEX_MASK (unsigned long)0xfffffffffffc0000
+
+
 void walk_lower_bus(struct parisc_device *dev)
 {
+	unsigned long io_io_low, io_io_high;
 
 	if(!BUS_CONVERTER(dev) || IS_LOWER_PORT(dev))
 		return;
 
-	walk_native_bus((unsigned long)(signed int)READ_IO_IO_LOW(dev), dev);
+	io_io_low = ((unsigned long)(signed int)READ_IO_IO_LOW(dev) + ~FLEX_MASK) & FLEX_MASK;
+	io_io_high = ((unsigned long)(signed int)READ_IO_IO_HIGH(dev) + ~FLEX_MASK) & FLEX_MASK;
+
+	walk_native_bus(io_io_low, io_io_high, dev);
 }
 
 #define MAX_NATIVE_DEVICES 64
@@ -488,7 +504,9 @@
 
 /**
  * walk_native_bus -- Probe a bus for devices
- * @addr: Base address of this bus.
+ * @io_io_low: Base address of this bus.
+ * @io_io_high: Last address of this bus.
+ * @parent: The parent bus device.
  * 
  * A native bus (eg Runway or GSC) may have up to 64 devices on it,
  * spaced at intervals of 0x1000 bytes.  PDC may not inform us of these
@@ -496,28 +514,32 @@
  * devices which are not physically connected (such as extra serial &
  * keyboard ports).  This problem is not yet solved.
  */
-static void walk_native_bus(unsigned long addr, struct parisc_device *parent)
+static void walk_native_bus(unsigned long io_io_low, unsigned long io_io_high,
+			    struct parisc_device *parent)
 {
-	int i;
+	int i, devices_found = 0;
+	unsigned long hpa = io_io_low;
 	struct hardware_path path;
 
 	get_node_path(parent, &path);
-	for (i = 0; i < MAX_NATIVE_DEVICES; i++) {
-		unsigned long hpa = (addr + i * NATIVE_DEVICE_OFFSET);
-		struct parisc_device *dev;
-
-		/* Was the device already added by Firmware? */
-		dev = find_device_by_addr(hpa);
-		if (!dev) {
-			path.mod = i;
-			dev = alloc_pa_dev(hpa, &path);
-			if (!dev)
-				continue;
-
-			register_parisc_device(dev);
+	do {
+		for (i = 0; i < MAX_NATIVE_DEVICES; i++, hpa += NATIVE_DEVICE_OFFSET) {
+			struct parisc_device *dev;
+
+			/* Was the device already added by Firmware? */
+			dev = find_device_by_addr(hpa);
+			if (!dev) {
+				path.mod = i;
+				dev = alloc_pa_dev(hpa, &path);
+				if (!dev)
+					continue;
+
+				register_parisc_device(dev);
+				devices_found++;
+			}
+			walk_lower_bus(dev);
 		}
-		walk_lower_bus(dev);
-	}
+	} while (!devices_found && hpa < io_io_high);
 }
 
 #define CENTRAL_BUS_ADDR (unsigned long) 0xfffffffffff80000
@@ -530,7 +552,9 @@
  */
 void walk_central_bus(void)
 {
-	walk_native_bus(CENTRAL_BUS_ADDR, &root);
+	walk_native_bus(CENTRAL_BUS_ADDR, 
+			CENTRAL_BUS_ADDR + (MAX_NATIVE_DEVICES * NATIVE_DEVICE_OFFSET),
+			&root);
 }
 
 void fixup_child_irqs(struct parisc_device *parent, int base,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/entry.S linux-2.4.21-pre6/arch/parisc/kernel/entry.S
--- linux-2.4.20/arch/parisc/kernel/entry.S	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-pre6/arch/parisc/kernel/entry.S	2003-03-26 23:49:18.000000000 +0000
@@ -759,32 +759,30 @@
 
 	.import do_softirq,code
 intr_do_softirq:
-	bl      do_softirq,%r2
 #ifdef __LP64__
 	ldo	-16(%r30),%r29		/* Reference param save area */
-#else
-	nop
 #endif
-	b       intr_check_resched
-	nop
+	ldil	L%intr_check_resched, %r2
+	b	do_softirq
+	ldo	R%intr_check_resched(%r2), %r2
 
 	.import schedule,code
 intr_do_resched:
 	/* Only do reschedule if we are returning to user space */
 	LDREG   PT_IASQ0(%r16), %r20
-	CMPIB= 0,%r20,intr_restore /* backward */
+	CMPIB= 0,%r20,intr_check_sig /* backward */
 	nop
 	LDREG   PT_IASQ1(%r16), %r20
-	CMPIB= 0,%r20,intr_restore /* backward */
+	CMPIB= 0,%r20,intr_check_sig /* backward */
 	nop
 
 #ifdef __LP64__
 	ldo	-16(%r30),%r29		/* Reference param save area */
 #endif
 
-	ldil	L%intr_return, %r2
+	ldil	L%intr_check_sig, %r2
 	b	schedule
-	ldo	R%intr_return(%r2), %r2	/* return to intr_return, not here */
+	ldo	R%intr_check_sig(%r2), %r2
 
 
 	.import do_signal,code
@@ -799,15 +797,14 @@
 
 	copy	%r0, %r24			/* unsigned long in_syscall */
 	copy	%r16, %r25			/* struct pt_regs *regs */
-	ssm     PSW_SM_I, %r0
+	copy	%r0, %r26			/* sigset_t *oldset = NULL */
 #ifdef __LP64__
 	ldo	-16(%r30),%r29			/* Reference param save area */
 #endif
-	bl	do_signal,%r2
-	copy	%r0, %r26			/* sigset_t *oldset = NULL */
+	ldil	L%intr_restore, %r2
+	b	do_signal
+	ldo	R%intr_restore(%r2), %r2
 
-	b	intr_restore
-	nop
 
 	/*
 	 * External interrupts.
@@ -852,7 +849,7 @@
 	ldo	-16(%r30),%r29	/* Reference param save area */
 #endif
 	b	do_cpu_irq_mask
-	ldo	R%intr_return(%r2), %r2	/* return to intr_return, not here */
+	ldo	R%intr_return(%r2), %r2
 
 
 
@@ -925,19 +922,16 @@
 	loadgp
 
 	copy		%r29, %r25	/* arg1 is pt_regs */
-#ifdef CONFIG_KWDB
-	copy		%r29, %r3	/* KWDB - update frame pointer (gr3) */
-#endif
 
 #ifdef __LP64__
 	ldo		-16(%r30),%r29	/* Reference param save area */
 #endif
 
-	ldil		L%intr_return, %r2
+	ldil		L%intr_restore, %r2
 	copy		%r25, %r16	/* save pt_regs */
 
 	b		handle_interruption
-	ldo		R%intr_return(%r2), %r2	/* return to intr_return */
+	ldo		R%intr_restore(%r2), %r2
 
 
 	/*
@@ -1319,9 +1313,9 @@
 
 	/* Get rid of prot bits and convert to page addr for idtlbt */
 
-	extrd,s         pte,35,4,t0
+	extrd,s         pte,35,4,t1
 	depdi		0,63,12,pte	/* clear lower 12 bits */
-        addi,=          1,t0,0 
+        addi,=          1,t1,0 
         extrd,u,*tr     pte,56,25,pte 
 	extrd,s		pte,56,25,pte	/* bit 31:8 >> 8  */ 
 	idtlbt          pte,prot
@@ -1389,9 +1383,9 @@
 
 	/* Get rid of prot bits and convert to page addr for idtlbt */
 
-        extrd,s         pte,35,4,t0
+        extrd,s         pte,35,4,t1
         depdi           0,63,12,pte     /* clear lower 12 bits */
-        addi,=          1,t0,0
+        addi,=          1,t1,0
         extrd,u,*tr     pte,56,25,pte
         extrd,s         pte,56,25,pte   /* bit 31:8 >> 8  */
         idtlbt          pte,prot
@@ -1642,9 +1636,9 @@
 
 	/* Get rid of prot bits and convert to page addr for iitlbt */
 
-        extrd,s         pte,35,4,t0 
+        extrd,s         pte,35,4,t1 
         depdi           0,63,12,pte     /* clear lower 12 bits */
-        addi,=          1,t0,0
+        addi,=          1,t1,0
         extrd,u,*tr     pte,56,25,pte 
         extrd,s         pte,56,25,pte   /* bit 31:8 >> 8  */
 	iitlbt          pte,prot
@@ -1860,9 +1854,9 @@
 	extrd,u,*= 	pte,_PAGE_GATEWAY_BIT+32,1,r0
 	depdi		0,11,2,prot	/* If Gateway, Set PL2 to 0 */
 
-        extrd,s         pte,35,4,t0 
+        extrd,s         pte,35,4,t1 
         depdi           0,63,12,pte     /* clear lower 12 bits */
-        addi,=          1,t0,0
+        addi,=          1,t1,0
         extrd,u,*tr     pte,56,25,pte 
         extrd,s         pte,56,25,pte   /* bit 31:8 >> 8  */
         idtlbt          pte,prot
@@ -2358,9 +2352,9 @@
 	STREG	%r2,TASK_PT_IAOQ0(%r1)
 	ldo	4(%r2),%r2
 	STREG	%r2,TASK_PT_IAOQ1(%r1)
-	copy	%r25,%r16
+
 	b	intr_restore
-	nop
+	copy	%r25,%r16
 
 	.import do_softirq,code
 syscall_do_softirq:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/firmware.c linux-2.4.21-pre6/arch/parisc/kernel/firmware.c
--- linux-2.4.20/arch/parisc/kernel/firmware.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-pre6/arch/parisc/kernel/firmware.c	2003-03-26 23:49:54.000000000 +0000
@@ -1,4 +1,4 @@
-/* arch/parisc/kernel/pdc.c  - safe pdc access routines
+/* arch/parisc/kernel/firmware.c  - safe pdc access routines
  *
  * Copyright 1999 SuSE GmbH Nuernberg (Philipp Rumpf, prumpf@tux.org)
  * portions Copyright 1999 The Puffin Group, (Alex deVries, David Kennedy)
@@ -177,6 +177,45 @@
 }
 
 /**
+ * pdc_pat_chassis_send_log - Sends a PDC PAT CHASSIS log message.
+ * @retval: -1 on error, 0 on success. Other value are PDC errors
+ *
+ * Must be correctly formatted or expect system crash
+ */
+#ifdef __LP64__
+int pdc_pat_chassis_send_log(unsigned long state, unsigned long data)
+{
+	if (!is_pdc_pat())
+		return -1;
+		
+	int retval = 0;
+	
+	spin_lock_irq(&pdc_lock);
+	retval = mem_pdc_call(PDC_PAT_CHASSIS_LOG, PDC_PAT_CHASSIS_WRITE_LOG, __pa(&state), __pa(&data));
+	spin_unlock_irq(&pdc_lock);
+	
+	return retval;
+}
+#endif
+
+/**
+ * pdc_chassis_disp - Updates display
+ * @retval: -1 on error, 0 on success
+ *
+ * Works on old PDC only (E class, others?)
+ */
+int pdc_chassis_disp(unsigned long disp)
+{
+	int retval = 0;
+
+	spin_lock_irq(&pdc_lock);
+	retval = mem_pdc_call(PDC_CHASSIS, PDC_CHASSIS_DISP, disp);
+	spin_unlock_irq(&pdc_lock);
+
+	return retval;
+}
+
+/**
  * pdc_coproc_cfg - To identify coprocessors attached to the processor.
  * @pdc_coproc_info: Return buffer address.
  *
@@ -507,12 +546,11 @@
 
 /* BCJ-XXXX series boxes. E.G. "9000/785/C3000" */
 #define IS_SPROCKETS() (strlen(boot_cpu_data.pdc.sys_model_name) == 14 && \
-	strncmp(boot_cpu_data.pdc.sys_model_name, "9000/785", 9) == 0)
+	strncmp(boot_cpu_data.pdc.sys_model_name, "9000/785", 8) == 0)
 
 	retval = mem_pdc_call(PDC_INITIATOR, PDC_GET_INITIATOR, 
 			      __pa(pdc_result), __pa(hwpath));
 
-
 	if (retval >= PDC_OK) {
 		*scsi_id = (unsigned char) pdc_result[0];
 
@@ -534,10 +572,12 @@
 		** pdc_result[3]	PDC suggested SCSI rate
 		*/
 
+		/*
+		** XXX REVISIT: Doesn't look like PAT PDC does the same.
+		** Problem is A500 also exports 50-pin SE SCSI port.
+		*/
 		if (IS_SPROCKETS()) {
 			/*
-			** Revisit: PAT PDC do the same thing?
-			** A500 also exports 50-pin SE SCSI.
 			**	0 == 8-bit
 			**	1 == 16-bit
 			*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/head64.S linux-2.4.21-pre6/arch/parisc/kernel/head64.S
--- linux-2.4.20/arch/parisc/kernel/head64.S	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-pre6/arch/parisc/kernel/head64.S	2003-03-26 23:49:38.000000000 +0000
@@ -24,7 +24,7 @@
 #include <asm/pdc.h>		/* for PDC_PSW defines */
 
 
-	.level 2.0
+	.level 2.0w
 
 	.section	.initcall.init
 	.align		4
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/ioctl32.c linux-2.4.21-pre6/arch/parisc/kernel/ioctl32.c
--- linux-2.4.20/arch/parisc/kernel/ioctl32.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-pre6/arch/parisc/kernel/ioctl32.c	2003-03-26 23:49:38.000000000 +0000
@@ -2986,6 +2986,9 @@
 COMPATIBLE_IOCTL(BLKFRASET)
 COMPATIBLE_IOCTL(BLKSECTSET)
 COMPATIBLE_IOCTL(BLKSSZGET)
+COMPATIBLE_IOCTL(BLKBSZGET)
+COMPATIBLE_IOCTL(BLKBSZSET)
+COMPATIBLE_IOCTL(BLKGETSIZE64)
 
 /* RAID */
 COMPATIBLE_IOCTL(RAID_VERSION)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/irq.c linux-2.4.21-pre6/arch/parisc/kernel/irq.c
--- linux-2.4.20/arch/parisc/kernel/irq.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-pre6/arch/parisc/kernel/irq.c	2003-03-26 23:49:30.000000000 +0000
@@ -201,7 +201,7 @@
 {
 #ifdef CONFIG_PROC_FS
 	char *p = buf;
-	unsigned int regnr;
+	unsigned int regnr = 0;
 
 	p += sprintf(p, "     ");
 #ifdef CONFIG_SMP
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/lba_pci.c linux-2.4.21-pre6/arch/parisc/kernel/lba_pci.c
--- linux-2.4.20/arch/parisc/kernel/lba_pci.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-pre6/arch/parisc/kernel/lba_pci.c	2003-03-26 23:49:50.000000000 +0000
@@ -735,47 +735,11 @@
 		bus->resource[0] = &(ldev->hba.io_space);
 		bus->resource[1] = &(ldev->hba.lmmio_space);
 	} else {
-		/* KLUGE ALERT!
-		** PCI-PCI Bridge resource munging.
-		** This hack should go away in the near future.
-		** It's based on the Alpha port.
-		*/
-		int i;
-		u16 cmd;
-
-		for (i = 0; i < 4; i++) {
-			bus->resource[i] =
-				&bus->self->resource[PCI_BRIDGE_RESOURCES+i];
-			bus->resource[i]->name = bus->name;
-		}
-#if 0
-		bus->resource[0]->flags |= pci_bridge_check_io(bus->self);
-#else
-		bus->resource[0]->flags |= IORESOURCE_IO;
-#endif
-		bus->resource[1]->flags |= IORESOURCE_MEM;
-		bus->resource[2]->flags = 0;	/* Don't support prefetchable */
-		bus->resource[3]->flags = 0;	/* not used */
-
-		/* 
-		** If the PPB is enabled (ie already configured) then
-		** just read those values.
-		*/
-		(void) lba_cfg_read16(bus->self, PCI_COMMAND, &cmd);
-		if (cmd & (PCI_COMMAND_MEMORY | PCI_COMMAND_IO)) {
-			pci_read_bridge_bases(bus);
-		} else {
-			/* Not configured.
-			** For now, propogate HBA limits to the bus;
-			**	PCI will adjust them later.
-			*/
-			bus->resource[0]->end = ldev->hba.io_space.end;
-			bus->resource[1]->end = ldev->hba.lmmio_space.end;
-		}
+		pci_read_bridge_bases(bus);
 
-		/* Turn off downstream PF memory address range by default */
-		bus->resource[2]->start = 1024*1024;
-		bus->resource[2]->end = bus->resource[2]->start - 1;
+		/* Turn off downstream PreFetchable Memory range by default */
+		bus->resource[2]->start = 0;
+		bus->resource[2]->end = 0;
 	}
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/led.c linux-2.4.21-pre6/arch/parisc/kernel/led.c
--- linux-2.4.20/arch/parisc/kernel/led.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-pre6/arch/parisc/kernel/led.c	2003-03-26 23:49:24.000000000 +0000
@@ -352,7 +352,8 @@
 static unsigned long led_net_rx_counter, led_net_tx_counter;
 
 static void led_get_net_stats(int addvalue)
-{
+{ 
+#ifdef CONFIG_NET
 	static unsigned long rx_total_last, tx_total_last;
 	unsigned long rx_total, tx_total;
 	struct net_device *dev;
@@ -383,6 +384,7 @@
         
 	rx_total_last += rx_total;
         tx_total_last += tx_total;
+#endif
 }
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/parisc_ksyms.c linux-2.4.21-pre6/arch/parisc/kernel/parisc_ksyms.c
--- linux-2.4.20/arch/parisc/kernel/parisc_ksyms.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-pre6/arch/parisc/kernel/parisc_ksyms.c	2003-03-26 23:49:55.000000000 +0000
@@ -232,3 +232,11 @@
 EXPORT_SYMBOL_NOVERS($$dyncall);
 #endif
 
+#ifdef CONFIG_SMP
+#ifdef CONFIG_DEBUG_SPINLOCK
+#include <asm/spinlock.h>
+EXPORT_SYMBOL(spin_lock);
+EXPORT_SYMBOL(spin_unlock);
+EXPORT_SYMBOL(spin_trylock);
+#endif
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/pci.c linux-2.4.21-pre6/arch/parisc/kernel/pci.c
--- linux-2.4.20/arch/parisc/kernel/pci.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-pre6/arch/parisc/kernel/pci.c	2003-03-26 23:48:57.000000000 +0000
@@ -306,13 +306,13 @@
 		   (32) for primary and secondary buses. */
 		pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 32);
 
-		/* Read bridge control */
+		/* Read bridge control - force SERR/PERR on */
 		pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &bus->bridge_ctl);
+		bus->bridge_ctl |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR;
+		pci_write_config_word(dev, PCI_BRIDGE_CONTROL, bus->bridge_ctl);
 	}
 
-	/* Set FBB bit for now. Disable ISA IO forwarding. Enable PERR/SERR */
-	bus->bridge_ctl |= PCI_BRIDGE_CTL_FAST_BACK | 
-			   PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR;
+	bus->bridge_ctl |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR;
 }
 
 
@@ -390,7 +390,7 @@
 */
 void __devinit
 pcibios_align_resource(void *data, struct resource *res,
-		       unsigned long size, unsigned long alignment)
+			unsigned long size, unsigned long alignment)
 {
 	unsigned long mask, align;
 
@@ -407,7 +407,7 @@
 	align = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM;
 
 	/* Align to largest of MIN or input size */
-	mask = MAX(size, align) - 1;
+	mask = MAX(alignment, align) - 1;
 	res->start += mask;
 	res->start &= ~mask;
 
@@ -420,7 +420,7 @@
 
 
 int __devinit
-pcibios_enable_device(struct pci_dev *dev)
+pcibios_enable_device(struct pci_dev *dev, int mask)
 {
 	u16 cmd;
 	int idx;
@@ -438,6 +438,11 @@
 	*/
         for (idx=0; idx<DEVICE_COUNT_RESOURCE; idx++) {
 		struct resource *r = &dev->resource[idx];
+
+                /* only setup requested resources */
+		if (!(mask & (1<<idx)))
+			continue;
+
 		if (r->flags & IORESOURCE_IO)
 			cmd |= PCI_COMMAND_IO;
 		if (r->flags & IORESOURCE_MEM)
@@ -454,9 +459,11 @@
 	*/
 	cmd |= (PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
 
+#if 0
 	/* If bridge/bus controller has FBB enabled, child must too. */
 	if (dev->bus->bridge_ctl & PCI_BRIDGE_CTL_FAST_BACK)
 		cmd |= PCI_COMMAND_FAST_BACK;
+#endif
 
 	DBGC("PCIBIOS: Enabling device %s cmd 0x%04x\n", dev->slot_name, cmd);
 	pci_write_config_word(dev, PCI_COMMAND, cmd);
@@ -478,6 +485,19 @@
 #endif
 }
 
+static void __devinit
+pcibios_enable_ppb(struct pci_bus *bus)
+{
+	struct list_head *list;
+
+	/* find a leaf of the PCI bus tree. */
+        list_for_each(list, &bus->children)
+		pcibios_enable_ppb(pci_bus_b(list));
+
+	if (bus->self && (bus->self->class >> 8) == PCI_CLASS_BRIDGE_PCI)
+		pdev_enable_device(bus->self);
+}
+
 
 /*
 ** Mostly copied from drivers/pci/setup-bus.c:pci_assign_unassigned_resources()
@@ -486,16 +506,13 @@
 pcibios_assign_unassigned_resources(struct pci_bus *bus)
 {
 	/* from drivers/pci/setup-bus.c */
-	extern void pbus_assign_resources(struct pci_bus *bus, struct pbus_set_ranges_data *ranges);
+	extern void pbus_size_bridges(struct pci_bus *bus);
+	extern void pbus_assign_resources(struct pci_bus *bus);
 
-	struct pbus_set_ranges_data ranges;
+	pbus_size_bridges(bus);
+	pbus_assign_resources(bus);
 
-	ranges.io_end = ranges.io_start
-				= bus->resource[0]->start + PCIBIOS_MIN_IO;
-	ranges.mem_end = ranges.mem_start
-				= bus->resource[1]->start + PCIBIOS_MIN_MEM;
-	ranges.found_vga = 0;
-	pbus_assign_resources(bus, &ranges);
+	pcibios_enable_ppb(bus);
 }
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/pdc_chassis.c linux-2.4.21-pre6/arch/parisc/kernel/pdc_chassis.c
--- linux-2.4.20/arch/parisc/kernel/pdc_chassis.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/parisc/kernel/pdc_chassis.c	2003-03-26 23:48:58.000000000 +0000
@@ -0,0 +1,205 @@
+/*
+ *		arch/parisc/kernel/pdc_chassis.c
+ *
+ * 		Copyright (C) 2002 Laurent Canet <canetl@esiee.fr>
+ *		Copyright (C) 2002 Thibaut Varene <varenet@esiee.fr>
+ *
+ *
+ *		This program is free software; you can redistribute it and/or modify
+ *		it under the terms of the GNU General Public License as published by
+ *		the Free Software Foundation; either version 2, or (at your option)
+ *		any later version.
+ *      
+ *		This program is distributed in the hope that it will be useful,
+ *		but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *		GNU General Public License for more details.
+ *      
+ *		You should have received a copy of the GNU General Public License
+ *		along with this program; if not, write to the Free Software
+ *		Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#undef PDC_CHASSIS_DEBUG
+#ifdef PDC_CHASSIS_DEBUG
+#define DPRINTK(fmt, args...)	printk(fmt, ## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/reboot.h>
+#include <linux/notifier.h>
+
+#include <asm/pdc_chassis.h>
+#include <asm/processor.h>
+
+static int pdc_chassis_old = 0;	
+
+
+/** 
+ * pdc_chassis_checkold() - Checks for old PDC_CHASSIS compatibility
+ * @pdc_chassis_old: 1 if old pdc chassis style
+ * 
+ * Currently, only E class and A180 are known to work with this.
+ * Inspired by Christoph Plattner
+ */
+
+static void __init pdc_chassis_checkold(void)
+{
+	switch(CPU_HVERSION) {
+		case 0x480:		/* E25 */
+		case 0x481:		/* E35 */
+		case 0x482:		/* E45 */
+		case 0x483:		/* E55 */
+		case 0x516:		/* A180 */
+			pdc_chassis_old = 1;
+			break;
+
+		default:
+			break;
+	}
+	DPRINTK(KERN_DEBUG "%s: pdc_chassis_checkold(); pdc_chassis_old = %d\n", __FILE__, pdc_chassis_old);
+}
+
+
+/**
+ * pdc_chassis_panic_event() - Called by the panic handler.
+ *
+ * As soon as a panic occurs, we should inform the PDC.
+ */
+
+static int pdc_chassis_panic_event(struct notifier_block *this,
+		        unsigned long event, void *ptr)
+{
+	pdc_chassis_send_status(PDC_CHASSIS_DIRECT_PANIC);
+		return NOTIFY_DONE;
+}   
+
+
+static struct notifier_block pdc_chassis_panic_block = {
+	notifier_call: pdc_chassis_panic_event,
+	priority: INT_MAX,
+};
+
+
+/**
+ * parisc_reboot_event() - Called by the reboot handler.
+ *
+ * As soon as a reboot occurs, we should inform the PDC.
+ */
+
+static int pdc_chassis_reboot_event(struct notifier_block *this,
+		        unsigned long event, void *ptr)
+{
+	pdc_chassis_send_status(PDC_CHASSIS_DIRECT_SHUTDOWN);
+		return NOTIFY_DONE;
+}   
+
+
+static struct notifier_block pdc_chassis_reboot_block = {
+	notifier_call: pdc_chassis_reboot_event,
+	priority: INT_MAX,
+};
+
+
+/**
+ * parisc_pdc_chassis_init() - Called at boot time.
+ */
+
+void __init parisc_pdc_chassis_init(void)
+{
+	DPRINTK(KERN_DEBUG "%s: parisc_pdc_chassis_init()\n", __FILE__);
+
+	/* initialize panic notifier chain */
+	notifier_chain_register(&panic_notifier_list, &pdc_chassis_panic_block);
+
+	/* initialize reboot notifier chain */
+	register_reboot_notifier(&pdc_chassis_reboot_block);
+
+	/* Check for old LED Panel */
+	pdc_chassis_checkold();
+}
+
+
+/** 
+ * pdc_chassis_send_status() - Sends a predefined message to the chassis,
+ * and changes the front panel LEDs according to the new system state
+ * @retval: PDC call return value.
+ *
+ * Only machines with 64 bits PDC PAT and E-class are supported atm.
+ * 
+ * returns 0 if no error, -1 if no supported PDC is present or invalid message,
+ * else returns the appropriate PDC error code.
+ * 
+ * For a list of predefined messages, see asm-parisc/pdc_chassis.h
+ */
+
+int pdc_chassis_send_status(int message)
+{
+	/* Maybe we should do that in an other way ? */
+	int retval = 0;
+
+	DPRINTK(KERN_DEBUG "%s: pdc_chassis_send_status(%d)\n", __FILE__, message);
+
+#ifdef __LP64__	/* pdc_pat_chassis_send_log is defined only when #ifdef __LP64__ */
+	if (is_pdc_pat()) {
+		switch(message) {
+			case PDC_CHASSIS_DIRECT_BSTART:
+				retval = pdc_pat_chassis_send_log(PDC_CHASSIS_PMSG_BSTART, PDC_CHASSIS_LSTATE_RUN_NORMAL);
+				break;
+			
+			case PDC_CHASSIS_DIRECT_BCOMPLETE:
+				retval = pdc_pat_chassis_send_log(PDC_CHASSIS_PMSG_BCOMPLETE, PDC_CHASSIS_LSTATE_RUN_NORMAL);
+				break;
+			
+			case PDC_CHASSIS_DIRECT_SHUTDOWN:
+				retval = pdc_pat_chassis_send_log(PDC_CHASSIS_PMSG_SHUTDOWN, PDC_CHASSIS_LSTATE_NONOS);
+				break;
+			
+			case PDC_CHASSIS_DIRECT_PANIC:
+				retval = pdc_pat_chassis_send_log(PDC_CHASSIS_PMSG_PANIC, PDC_CHASSIS_LSTATE_RUN_CRASHREC);
+				break;
+		
+			case PDC_CHASSIS_DIRECT_LPMC:
+				retval = pdc_pat_chassis_send_log(PDC_CHASSIS_PMSG_LPMC, PDC_CHASSIS_LSTATE_RUN_SYSINT);
+				break;
+
+			case PDC_CHASSIS_DIRECT_HPMC:
+				retval = pdc_pat_chassis_send_log(PDC_CHASSIS_PMSG_HPMC, PDC_CHASSIS_LSTATE_RUN_NCRIT);
+				break;
+
+			default:
+				retval = -1;
+		}
+	} else retval = -1;
+#else
+	if (pdc_chassis_old) {
+		switch (message) {
+			case PDC_CHASSIS_DIRECT_BSTART:
+			case PDC_CHASSIS_DIRECT_BCOMPLETE:
+				retval = pdc_chassis_disp(PDC_CHASSIS_DISP_DATA(OSTAT_RUN));
+				break;
+							
+			case PDC_CHASSIS_DIRECT_SHUTDOWN:
+				retval = pdc_chassis_disp(PDC_CHASSIS_DISP_DATA(OSTAT_SHUT));
+				break;
+			
+			case PDC_CHASSIS_DIRECT_HPMC:
+			case PDC_CHASSIS_DIRECT_PANIC:
+				retval = pdc_chassis_disp(PDC_CHASSIS_DISP_DATA(OSTAT_FLT));
+				break;
+		
+			case PDC_CHASSIS_DIRECT_LPMC:
+				retval = pdc_chassis_disp(PDC_CHASSIS_DISP_DATA(OSTAT_WARN));
+				break;
+
+			default:
+				retval = -1;
+		}
+	} else retval = -1;
+#endif
+		
+	return retval;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/pdc_cons.c linux-2.4.21-pre6/arch/parisc/kernel/pdc_cons.c
--- linux-2.4.20/arch/parisc/kernel/pdc_cons.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-pre6/arch/parisc/kernel/pdc_cons.c	2003-03-26 23:49:19.000000000 +0000
@@ -51,33 +51,33 @@
 	return 0;
 }
 
-#ifdef CONFIG_PDC_CONSOLE
+#if defined(CONFIG_PDC_CONSOLE) || defined(CONFIG_SERIAL_MUX)
+#define PDC_CONSOLE_DEVICE pdc_console_device
 static kdev_t pdc_console_device (struct console *c)
 {
-        return MKDEV(PDCCONS_MAJOR, 0);
+        return MKDEV(MUX_MAJOR, 0);
 }
-#endif
-
-#ifdef CONFIG_PDC_CONSOLE
-#define PDC_CONSOLE_DEVICE pdc_console_device
-#else
+#else 
 #define PDC_CONSOLE_DEVICE NULL
 #endif
 
 static struct console pdc_cons = {
 	name:		"ttyB",
 	write:		pdc_console_write,
- 	device:		PDC_CONSOLE_DEVICE,
+#warning UPSTREAM 2.4.19 removed the next 4 lines but we did not
+	read:		NULL,
+	device:		PDC_CONSOLE_DEVICE,
+	unblank:	NULL,
 	setup:		pdc_console_setup,
 	flags:		CON_BOOT|CON_PRINTBUFFER|CON_ENABLED,
 	index:		-1,
 };
 
 static int pdc_console_initialized;
-
 extern unsigned long con_start;	/* kernel/printk.c */
 extern unsigned long log_end;	/* kernel/printk.c */
-  
+
+
 static void pdc_console_init_force(void)
 {
 	if (pdc_console_initialized)
@@ -94,7 +94,7 @@
 
 void pdc_console_init(void)
 {
-#if defined(EARLY_BOOTUP_DEBUG) || defined(CONFIG_PDC_CONSOLE)
+#if defined(EARLY_BOOTUP_DEBUG) || defined(CONFIG_PDC_CONSOLE) || defined(CONFIG_SERIAL_MUX)
 	pdc_console_init_force();
 #endif
 #ifdef EARLY_BOOTUP_DEBUG
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/power.c linux-2.4.21-pre6/arch/parisc/kernel/power.c
--- linux-2.4.20/arch/parisc/kernel/power.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-pre6/arch/parisc/kernel/power.c	2003-03-26 23:49:10.000000000 +0000
@@ -44,15 +44,12 @@
 #include <linux/reboot.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
-#include <linux/proc_fs.h>
-#include <linux/ctype.h>
 
 #include <asm/gsc.h>
 #include <asm/pdc.h>
 #include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/led.h>
-#include <asm/led.h>
 #include <asm/uaccess.h>
 
 
@@ -144,11 +141,7 @@
 DECLARE_TASKLET_DISABLED(power_tasklet, NULL, 0);
 
 /* soft power switch enabled/disabled */
-#ifdef CONFIG_PROC_FS
-static int pwrsw_enabled = 1;
-#else
-#define pwrsw_enabled (1)
-#endif
+int pwrsw_enabled = 1;
 
 /*
  * On gecko style machines (e.g. 712/xx and 715/xx) 
@@ -209,90 +202,6 @@
 
 
 
-/* 
- * /proc filesystem support 
- */
-
-#ifdef CONFIG_SYSCTL
-static int power_proc_read(char *page, char **start, off_t off, int count, 
-	int *eof, void *data)
-{
-	char *out = page;
-	int len;
-
-	out += sprintf(out, "Software power switch support: ");
-	out += sprintf(out, pwrsw_enabled ? "enabled (1)" : "disabled (0)" );
-	out += sprintf(out, "\n");
-
-	len = out - page - off;
-	if (len < count) {
-		*eof = 1;
-		if (len <= 0) return 0;
-	} else {
-		len = count;
-	}
-	*start = page + off;
-	return len;
-}
-
-static int power_proc_write(struct file *file, const char *buf, 
-	unsigned long count, void *data)
-{
-	char *cur, lbuf[count];
-
-	if (!capable(CAP_SYS_ADMIN))
-		return -EACCES;
-
-	memset(lbuf, 0, count);
-
-	copy_from_user(lbuf, buf, count);
-	cur = lbuf;
-
-	/* skip initial spaces */
-	while (*cur && isspace(*cur))
-		cur++;
-
-	switch (*cur) {
-	case '0':	pwrsw_enabled = 0;
-			break;
-	case '1':	pwrsw_enabled = 1;
-			break;
-	default:	printk(KERN_CRIT "/proc/" SYSCTL_FILENAME 
-					": Parse error: only '0' or '1' allowed!\n");
-			return -EINVAL;
-	} /* switch() */
-
-	return count;
-}
-
-static struct proc_dir_entry *ent;
-
-static void __init power_create_procfs(void)
-{
-	if (!power_tasklet.func)
-		return;
-	
-	ent = create_proc_entry(SYSCTL_FILENAME, S_IFREG|S_IRUGO|S_IWUSR, 0);
-	if (!ent) return;
-	
-	ent->nlink = 1;
-	ent->read_proc = power_proc_read;
-	ent->write_proc = power_proc_write;
-	ent->owner = THIS_MODULE;
-}
-
-static void __exit power_remove_procfs(void)
-{
-	remove_proc_entry(SYSCTL_FILENAME, NULL);
-}
-
-#else
-#define power_create_procfs()	do { } while (0)
-#define power_remove_procfs()	do { } while (0)
-#endif	/* CONFIG_SYSCTL */
-
-
-
 /* parisc_panic_event() is called by the panic handler.
  * As soon as a panic occurs, our tasklets above will not be
  * executed any longer. This function then re-enables the 
@@ -346,7 +255,6 @@
 	/* Register a call for panic conditions. */
 	notifier_chain_register(&panic_notifier_list, &parisc_panic_block);
 
-	power_create_procfs();
 	tasklet_enable(&power_tasklet);
 
 	return 0;
@@ -359,7 +267,6 @@
 
 	tasklet_disable(&power_tasklet);
 	notifier_chain_unregister(&panic_notifier_list, &parisc_panic_block);
-	power_remove_procfs();
 	power_tasklet.func = NULL;
 	pdc_soft_power_button(0);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/process.c linux-2.4.21-pre6/arch/parisc/kernel/process.c
--- linux-2.4.20/arch/parisc/kernel/process.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-pre6/arch/parisc/kernel/process.c	2003-03-26 23:49:55.000000000 +0000
@@ -36,6 +36,7 @@
 #include <asm/io.h>
 #include <asm/gsc.h>
 #include <asm/processor.h>
+#include <asm/pdc_chassis.h>
 
 int hlt_counter;
 
@@ -118,6 +119,9 @@
 	/* "Normal" system reset */
 	pdc_do_reset();
 
+	/* set up a new led state on systems shipped with a LED State panel */
+	pdc_chassis_send_status(PDC_CHASSIS_DIRECT_SHUTDOWN);
+	
 	/* Nope...box should reset with just CMD_RESET now */
 	gsc_writel(CMD_RESET, COMMAND_GLOBAL);
 
@@ -150,6 +154,8 @@
 	 * following call will immediately power off. */
 	pdc_soft_power_button(0);
 
+	pdc_chassis_send_status(PDC_CHASSIS_DIRECT_SHUTDOWN);
+	
 	/* It seems we have no way to power the system off via
 	 * software. The user has to press the button himself. */
 
@@ -163,7 +169,7 @@
  */
 
 extern pid_t __kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
-pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
+pid_t arch_kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
 {
 
 	/*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/processor.c linux-2.4.21-pre6/arch/parisc/kernel/processor.c
--- linux-2.4.20/arch/parisc/kernel/processor.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-pre6/arch/parisc/kernel/processor.c	2003-03-26 23:49:08.000000000 +0000
@@ -1,4 +1,4 @@
-/*    $Id: processor.c,v 1.13 2002/07/04 19:33:01 grundler Exp $
+/*    $Id: processor.c,v 1.14 2002/09/13 06:46:28 grundler Exp $
  *
  *    Initial setup-routines for HP 9000 based hardware.
  *
@@ -77,6 +77,8 @@
 	unsigned long txn_addr;
 	unsigned long cpuid;
 	struct cpuinfo_parisc *p;
+	extern struct irq_region_ops cpu_irq_ops; /* arch/parisc...irq.c */
+	extern struct irqaction cpu_irq_actions[]; /* arch/parisc...irq.c */
 
 #ifndef CONFIG_SMP
 	if (boot_cpu_data.cpu_count > 0) {
@@ -167,12 +169,24 @@
 	**	p->state = STATE_RENDEZVOUS;
 	*/
 
-	/*
-	** itimer and ipi IRQ handlers are statically initialized in
-	** arch/parisc/kernel/irq.c. ie Don't need to register them.
-	*/
-	p->region = irq_region[IRQ_FROM_REGION(CPU_IRQ_REGION)];
+#if 0
+	/* CPU 0 IRQ table is statically allocated/initialized */
+	if (cpuid) {
+		struct irqaction actions[];
+
+		/*
+		** itimer and ipi IRQ handlers are statically initialized in
+		** arch/parisc/kernel/irq.c. ie Don't need to register them.
+		*/
+		actions = kmalloc(sizeof(struct irqaction)*MAX_CPU_IRQ, GFP_ATOMIC);
+		if (!actions) {
+			/* not getting it's own table, share with monarch */
+			actions = cpu_irq_actions[0];
+		}
 
+		cpu_irq_actions[cpuid] = actions;
+	}
+#endif
 	return 0;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/sba_iommu.c linux-2.4.21-pre6/arch/parisc/kernel/sba_iommu.c
--- linux-2.4.20/arch/parisc/kernel/sba_iommu.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-pre6/arch/parisc/kernel/sba_iommu.c	2003-03-26 23:49:18.000000000 +0000
@@ -812,10 +812,8 @@
 		return(0);
 	}
 
-	dev->dma_mask = mask;	/* save it */
-
 	/* only support 32-bit PCI devices - no DAC support (yet) */
-	return((int) (mask == 0xffffffff));
+	return((int) (mask == 0xffffffffUL));
 }
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/setup.c linux-2.4.21-pre6/arch/parisc/kernel/setup.c
--- linux-2.4.20/arch/parisc/kernel/setup.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-pre6/arch/parisc/kernel/setup.c	2003-03-26 23:49:55.000000000 +0000
@@ -41,6 +41,7 @@
 #include <asm/processor.h>
 #include <asm/pdc.h>
 #include <asm/led.h>
+#include <asm/pdc_chassis.h>
 #include <asm/machdep.h>	/* for pa7300lc_init() proto */
 
 #define COMMAND_LINE_SIZE 1024
@@ -283,6 +284,11 @@
 	parisc_init_resources();
 	do_device_inventory();                  /* probe for hardware */
 
+	parisc_pdc_chassis_init();
+
+	/* set up a new led state on systems shipped LED State panel */
+	pdc_chassis_send_status(PDC_CHASSIS_DIRECT_BSTART);
+	
 	processor_init();
 	printk(KERN_INFO "CPU(s): %d x %s at %d.%06d MHz\n",
 			boot_cpu_data.cpu_count,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/sys_parisc32.c linux-2.4.21-pre6/arch/parisc/kernel/sys_parisc32.c
--- linux-2.4.20/arch/parisc/kernel/sys_parisc32.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-pre6/arch/parisc/kernel/sys_parisc32.c	2003-03-26 23:49:24.000000000 +0000
@@ -2759,20 +2759,9 @@
 
 asmlinkage long sys32_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
-	switch (cmd) {
-		case F_GETLK64:
-			cmd = F_GETLK;
-			break;
-		case F_SETLK64:
-			cmd = F_SETLK;
-			break;
-		case F_SETLKW64:
-			cmd = F_SETLKW;
-			break;
-		default:
-			break;
-	}
-	return sys_fcntl(fd, cmd, arg);
+	if (cmd >= F_GETLK64 && cmd <= F_SETLKW64)
+		return sys_fcntl(fd, cmd + F_GETLK - F_GETLK64, arg);
+	return sys32_fcntl(fd, cmd, arg);
 }
 
 asmlinkage int sys32_pread(int fd, void *buf, size_t count, unsigned int high, unsigned int low)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/syscall.S linux-2.4.21-pre6/arch/parisc/kernel/syscall.S
--- linux-2.4.20/arch/parisc/kernel/syscall.S	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-pre6/arch/parisc/kernel/syscall.S	2003-03-26 23:49:55.000000000 +0000
@@ -593,11 +593,18 @@
 	ENTRY_DIFF(ftruncate64)	/* 200 */
 	ENTRY_SAME(getdents64)
 	ENTRY_DIFF(fcntl64)
-	ENTRY_SAME(ni_syscall)		/* attrctl */
-	ENTRY_SAME(ni_syscall)		/* acl_get */
-	ENTRY_SAME(ni_syscall)		/* acl_set */
-	ENTRY_SAME(gettid)
+#ifdef CONFIG_XFS_FS
+	ENTRY_SAME(attrctl)
+	ENTRY_SAME(acl_get)
+	ENTRY_SAME(acl_set)            /* 205 */
+#else
+	ENTRY_SAME(ni_syscall)
+	ENTRY_SAME(ni_syscall)
+	ENTRY_SAME(ni_syscall)	       /* 205 */
+#endif
+	ENTRY_SAME(gettid)             
 	ENTRY_SAME(readahead)          
+	ENTRY_SAME(tkill)
 
 .end
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/traps.c linux-2.4.21-pre6/arch/parisc/kernel/traps.c
--- linux-2.4.20/arch/parisc/kernel/traps.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-pre6/arch/parisc/kernel/traps.c	2003-03-26 23:49:39.000000000 +0000
@@ -18,6 +18,7 @@
 #include <linux/ptrace.h>
 #include <linux/timer.h>
 #include <linux/mm.h>
+#include <linux/module.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/spinlock.h>
@@ -34,17 +35,10 @@
 #include <asm/atomic.h>
 #include <asm/smp.h>
 #include <asm/pdc.h>
+#include <asm/pdc_chassis.h>
 
 #include "../math-emu/math-emu.h"	/* for handle_fpe() */
 
-#ifdef CONFIG_KWDB
-#include <kdb/break.h>		/* for BI2_KGDB_GDB */
-#include <kdb/kgdb_types.h>	/* for __() */
-#include <kdb/save_state.h>	/* for struct save_state */
-#include <kdb/kgdb_machine.h>	/* for pt_regs_to_ssp and ssp_to_pt_regs */
-#include <kdb/trap.h>		/* for I_BRK_INST */
-#endif /* CONFIG_KWDB */
-
 #define PRINT_USER_FAULTS /* (turn this on if you want user faults to be */
 			  /*  dumped to the console via printk)          */
 
@@ -66,6 +60,99 @@
 #define RFMT "%08lx"
 #endif
 
+static int kstack_depth_to_print = 24;
+extern struct module *module_list;
+extern struct module kernel_module;
+
+static inline int kernel_text_address(unsigned long addr)
+{
+#ifdef CONFIG_MODULES
+	int retval = 0;
+	struct module *mod;
+#endif
+	extern char _stext, _etext;
+
+	if (addr >= (unsigned long) &_stext &&
+	    addr <= (unsigned long) &_etext)
+		return 1;
+
+#ifdef CONFIG_MODULES
+	for (mod = module_list; mod != &kernel_module; mod = mod->next) {
+		/* mod_bound tests for addr being inside the vmalloc'ed
+		 * module area. Of course it'd be better to test only
+		 * for the .text subset... */
+		if (mod_bound(addr, 0, mod)) {
+			retval = 1;
+			break;
+		}
+	}
+	return retval;
+#endif
+}
+
+
+void show_trace(unsigned long * stack)
+{
+	unsigned long *startstack;
+	unsigned long addr;
+	int i;
+
+	startstack = (unsigned long *)((unsigned long)stack & ~(THREAD_SIZE - 1));
+	i = 1;
+	printk("Kernel addresses on the stack:\n");
+	while (stack >= startstack) {
+		addr = *stack--;
+		if (kernel_text_address(addr)) {
+			printk(" [<" RFMT ">] ", addr);
+			if ((i & 0x03) == 0)
+				printk("\n");
+			i++;
+		}
+	}
+	printk("\n");
+}
+
+void show_trace_task(struct task_struct *tsk)
+{
+	show_trace((unsigned long *)tsk->thread.regs.ksp);
+}
+
+void show_stack(unsigned long * sp)
+{
+	unsigned long *stack;
+	int i;
+
+	/*
+	 * debugging aid: "show_stack(NULL);" prints the
+	 * back trace for this cpu.
+	 */
+	if (sp==NULL)
+		sp = (unsigned long*)&sp;
+
+	stack = sp;
+	printk("\n" KERN_CRIT "Stack Dump:\n");
+	printk(KERN_CRIT " " RFMT ":  ", (unsigned long) stack);
+	for (i=0; i < kstack_depth_to_print; i++) {
+		if (((long) stack & (THREAD_SIZE-1)) == 0)
+			break;
+		if (i && ((i & 0x03) == 0))
+			printk("\n" KERN_CRIT " " RFMT ":  ",
+				(unsigned long) stack);
+		printk(RFMT " ", *stack--);
+	}
+	printk("\n" KERN_CRIT "\n");
+	show_trace(sp);
+}
+
+/*
+ * The architecture-independent backtrace generator
+ */
+void dump_stack(void)
+{
+	show_stack(0);
+}
+
+
 void show_regs(struct pt_regs *regs)
 {
 	int i;
@@ -121,84 +208,6 @@
 }
 
 
-static void dump_stack(unsigned long from, unsigned long to, int istackflag)
-{
-	unsigned int *fromptr;
-	unsigned int *toptr;
-
-	fromptr = (unsigned int *)from;
-	toptr = (unsigned int *)to;
-
-	printk("\n");
-	printk(KERN_CRIT "Dumping %sStack from 0x%p to 0x%p:\n",
-			istackflag ? "Interrupt " : "",
-			fromptr, toptr);
-
-	while (fromptr < toptr) {
-		printk(KERN_CRIT "%04lx %08x %08x %08x %08x %08x %08x %08x %08x\n",
-		    ((unsigned long)fromptr) & 0xffff,
-		    fromptr[0], fromptr[1], fromptr[2], fromptr[3],
-		    fromptr[4], fromptr[5], fromptr[6], fromptr[7]);
-		fromptr += 8;
-	}
-}
-
-
-void show_stack(struct pt_regs *regs)
-{
-#if 1
-	/* If regs->sr[7] == 0, we are on a kernel stack */
-	if (regs->sr[7] == 0) {
-
-		unsigned long sp = regs->gr[30];
-		unsigned long cr30;
-		unsigned long cr31;
-		unsigned long stack_start;
-		struct pt_regs *int_regs;
-
-		cr30 = mfctl(30);
-		cr31 = mfctl(31);
-		stack_start = sp & ~(ISTACK_SIZE - 1);
-		if (stack_start == cr31) {
-		    /*
-		     * We are on the interrupt stack, get the stack
-		     * pointer from the first pt_regs structure on
-		     * the interrupt stack, so we can dump the task
-		     * stack first.
-		     */
-
-		    int_regs = (struct pt_regs *)cr31;
-		    sp = int_regs->gr[30];
-		    stack_start = sp & ~(INIT_TASK_SIZE - 1);
-		    if (stack_start != cr30) {
-			printk(KERN_CRIT "WARNING! Interrupt-Stack pointer and cr30 do not correspond!\n");
-			printk(KERN_CRIT "Dumping virtual address stack instead\n");
-			dump_stack((unsigned long)__va(stack_start), (unsigned long)__va(sp), 0);
-		    } else {
-			dump_stack(stack_start, sp, 0);
-		    };
-
-		    printk("\n\n" KERN_DEBUG "Registers at Interrupt:\n");
-		    show_regs(int_regs);
-
-		    /* Now dump the interrupt stack */
-
-		    sp = regs->gr[30];
-		    stack_start = sp & ~(ISTACK_SIZE - 1);
-		    dump_stack(stack_start,sp,1);
-		}
-		else
-		{
-		    /* Stack Dump! */
-		    printk(KERN_CRIT "WARNING! Stack pointer and cr30 do not correspond!\n");
-		    printk(KERN_CRIT "Dumping virtual address stack instead\n");
-		    dump_stack((unsigned long)__va(stack_start), (unsigned long)__va(sp), 0);
-		}
-	}
-#endif
-}
-
-
 void die_if_kernel(char *str, struct pt_regs *regs, long err)
 {
 	if (user_mode(regs)) {
@@ -260,9 +269,6 @@
 void handle_break(unsigned iir, struct pt_regs *regs)
 {
 	struct siginfo si;
-#ifdef CONFIG_KWDB
-	struct save_state ssp;
-#endif /* CONFIG_KWDB */   
 
 	switch(iir) {
 	case 0x00:
@@ -285,26 +291,6 @@
 		handle_gdb_break(regs, TRAP_BRKPT);
 		break;
 
-#ifdef CONFIG_KWDB
-	case KGDB_BREAK_INSN:
-		mtctl(0, 15);
-		pt_regs_to_ssp(regs, &ssp);
-		kgdb_trap(I_BRK_INST, &ssp, 1);
-		ssp_to_pt_regs(&ssp, regs);
-		break;
-
-	case KGDB_INIT_BREAK_INSN:
-		mtctl(0, 15);
-		pt_regs_to_ssp(regs, &ssp);
-		kgdb_trap(I_BRK_INST, &ssp, 1);
-		ssp_to_pt_regs(&ssp, regs);
-
-		/* Advance pcoq to skip break */
-		regs->iaoq[0] = regs->iaoq[1];
-		regs->iaoq[1] += 4;
-		break;
-#endif /* CONFIG_KWDB */
-
 	default:
 #ifdef PRINT_USER_FAULTS
 		printk(KERN_DEBUG "break %#08x: pid=%d command='%s'\n",
@@ -335,20 +321,6 @@
 void (*cpu_lpmc) (int code, struct pt_regs *regs) = default_trap;
 
 
-#ifdef CONFIG_KWDB
-int debug_call (void)
-{
-    printk (KERN_DEBUG "Debug call.\n");
-    return 0;
-}
-
-int debug_call_leaf (void)
-{
-    return 0;
-}
-#endif /* CONFIG_KWDB */
-
-
 void transfer_pim_to_trap_frame(struct pt_regs *regs)
 {
     register int i;
@@ -425,7 +397,7 @@
 
 
 /*
- * This routine handles page faults.  It determines the address,
+ * This routine handles various exception codes.  It determines the address,
  * and the problem, and then passes it off to one of the appropriate
  * routines.
  */
@@ -444,10 +416,20 @@
 	if (!console_drivers)
 		pdc_console_restart();
 
-	if (code == 1)
-	    transfer_pim_to_trap_frame(regs);
 
-	show_stack(regs);
+	/* Not all switch paths will gutter the processor... */
+	switch(code){
+
+	case 1:
+		transfer_pim_to_trap_frame(regs);
+		break;
+	    
+	default:
+		/* Fall through */
+		break;
+	}
+
+	show_stack((unsigned long *)regs->gr[30]);
 
 	printk("\n");
 	printk(KERN_CRIT "%s: Code=%d regs=%p (Addr=" RFMT ")\n",
@@ -461,32 +443,34 @@
 	 * system will shut down immediately right here. */
 	pdc_soft_power_button(0);
 	
+	/* Gutter the processor... */
 	for(;;)
 	    ;
 }
 
+
 void handle_interruption(int code, struct pt_regs *regs)
 {
 	unsigned long fault_address = 0;
 	unsigned long fault_space = 0;
 	struct siginfo si;
-#ifdef CONFIG_KWDB
-	struct save_state ssp;
-#endif /* CONFIG_KWDB */   
-
-	if (code == 1)
-	    pdc_console_restart();  /* switch back to pdc if HPMC */
-	else
-	    sti();
 
-#if 0
-	printk(KERN_CRIT "Interruption # %d\n", code);
-#endif
+	/* HACK! jsm is going to fix this.
+	 * entry.S will manage I-bit - only enable I-bit if it was
+	 * enabled before we took the "trap".
+	 */
+	if (code != 1)
+		local_irq_enable();
 
 	switch(code) {
 
 	case  1:
 		/* High-priority machine check (HPMC) */
+		pdc_console_restart();  /* switch back to pdc if HPMC */
+
+		/* set up a new led state on systems shipped with a LED State panel */
+		pdc_chassis_send_status(PDC_CHASSIS_DIRECT_HPMC);
+
 		parisc_terminate("High Priority Machine Check (HPMC)",
 				regs, code, 0);
 		/* NOT REACHED */
@@ -506,6 +490,9 @@
 
 	case  5:
 		/* Low-priority machine check */
+
+		pdc_chassis_send_status(PDC_CHASSIS_DIRECT_LPMC);
+
 		flush_all_caches();
 		cpu_lpmc(5, regs);
 		return;
@@ -554,6 +541,7 @@
 
 		die_if_kernel("Privileged register usage", regs, code);
 		si.si_code = ILL_PRVREG;
+		/* Fall thru */
 	give_sigill:
 		si.si_signo = SIGILL;
 		si.si_errno = 0;
@@ -561,17 +549,47 @@
 		force_sig_info(SIGILL, &si, current);
 		return;
 
+	case 12:
+		/* Overflow Trap, let the userland signal handler do the cleanup */
+		si.si_signo = SIGFPE;
+		si.si_code = FPE_INTOVF;
+		si.si_addr = (void *) regs->iaoq[0];
+		force_sig_info(SIGFPE, &si, current);
+		return;
+	
+	case 13:
+		/* Conditional Trap 
+		   The condition succees in an instruction which traps on condition  */
+		si.si_signo = SIGFPE;
+		/* Set to zero, and let the userspace app figure it out from
+		   the insn pointed to by si_addr */
+		si.si_code = 0;
+		si.si_addr = (void *) regs->iaoq[0];
+		force_sig_info(SIGFPE, &si, current);
+		return;
+
 	case 14:
 		/* Assist Exception Trap, i.e. floating point exception. */
 		die_if_kernel("Floating point exception", regs, 0); /* quiet */
 		handle_fpe(regs);
 		return;
 
+	case 15: 
+		/* Data TLB miss fault/Data page fault */	
+		/* Fall thru */
+	case 16:
+		/* Non-access instruction TLB miss fault */
+		/* The instruction TLB entry needed for the target address of the FIC
+		   is absent, and hardware can't find it, so we get to cleanup */
+		/* Fall thru */
 	case 17:
 		/* Non-access data TLB miss fault/Non-access data page fault */
 		/* TODO: Still need to add slow path emulation code here */
+		/* TODO: Understand what is meant by the TODO listed 
+		   above this one. (Carlos) */
 		fault_address = regs->ior;
-		parisc_terminate("Non access data tlb fault!",regs,code,fault_address);
+		fault_space = regs->isr;
+		break;
 
 	case 18:
 		/* PCXS only -- later cpu's split this into types 26,27 & 28 */
@@ -581,9 +599,8 @@
 			return;
 		}
 		/* Fall Through */
-
-	case 15: /* Data TLB miss fault/Data page fault */
-	case 26: /* PCXL: Data memory access rights trap */
+	case 26: 
+		/* PCXL: Data memory access rights trap */
 		fault_address = regs->ior;
 		fault_space   = regs->isr;
 		break;
@@ -599,7 +616,6 @@
 
 	case 25:
 		/* Taken branch trap */
-#ifndef CONFIG_KWDB
 		regs->gr[0] &= ~PSW_T;
 		if (regs->iasq[0])
 			handle_gdb_break(regs, TRAP_BRANCH);
@@ -607,14 +623,6 @@
 		 * run.
 		 */
 		return;
-#else
-		/* Kernel debugger: */
-		mtctl(0, 15);
-		pt_regs_to_ssp(regs, &ssp);
-		kgdb_trap(I_TAKEN_BR, &ssp, 1);
-		ssp_to_pt_regs(&ssp, regs);
-		break;
-#endif /* CONFIG_KWDB */
 
 	case  7:  
 		/* Instruction access rights */
@@ -648,7 +656,6 @@
 			up_read(&current->mm->mmap_sem);
 		}
 		/* Fall Through */
-
 	case 27: 
 		/* Data memory protection ID trap */
 		die_if_kernel("Protection id trap", regs, code);
@@ -682,6 +689,9 @@
 			force_sig_info(SIGBUS, &si, current);
 			return;
 		}
+		
+		pdc_chassis_send_status(PDC_CHASSIS_DIRECT_PANIC);
+
 		parisc_terminate("Unexpected interruption", regs, code, 0);
 		/* NOT REACHED */
 	}
@@ -710,24 +720,17 @@
 	     * The kernel should never fault on its own address space.
 	     */
 
-	    if (fault_space == 0)
-		    parisc_terminate("Kernel Fault", regs, code, fault_address);
+	    if (fault_space == 0) {
+		pdc_chassis_send_status(PDC_CHASSIS_DIRECT_PANIC);
+		parisc_terminate("Kernel Fault", regs, code, fault_address);
+		/** NOT REACHED **/
+	    }
 	}
 
-#ifdef CONFIG_KWDB
-	debug_call_leaf ();
-#endif /* CONFIG_KWDB */
-
 	do_page_fault(regs, code, fault_address);
 }
 
 
-void show_trace_task(struct task_struct *tsk)
-{
-    	BUG();
-}
-
-
 
 int __init check_ivt(void *iva)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/kernel/unaligned.c linux-2.4.21-pre6/arch/parisc/kernel/unaligned.c
--- linux-2.4.20/arch/parisc/kernel/unaligned.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-pre6/arch/parisc/kernel/unaligned.c	2003-03-26 23:49:10.000000000 +0000
@@ -1,4 +1,4 @@
-/*    $Id: unaligned.c,v 1.9 2001/10/04 03:31:08 tausq Exp $
+/*    $Id: unaligned.c,v 1.10 2002/09/22 02:21:05 tausq Exp $
  *
  *    Unaligned memory access handler
  *
@@ -108,7 +108,7 @@
 #define OPCODE_STW_L    OPCODE4(0x1A)
 #define OPCODE_STW_L2   OPCODE4(0x1B)
 
-
+int unaligned_enabled = 1;
 
 void die_if_kernel (char *str, struct pt_regs *regs, long err);
 
@@ -281,6 +281,9 @@
 		}
 	}
 
+	if (!unaligned_enabled)
+		goto force_sigbus;
+
 	/* TODO: make this cleaner... */
 	switch (regs->iir & OPCODE1_MASK)
 	{
@@ -368,7 +371,7 @@
 	{
 		printk(KERN_CRIT "Unaligned handler failed, ret = %d\n", ret);
 		die_if_kernel("Unaligned data reference", regs, 28);
-
+force_sigbus:
 		/* couldn't handle it ... */
 		si.si_signo = SIGBUS;
 		si.si_errno = 0;
@@ -432,3 +435,4 @@
 
 	return (int)(regs->ior & align_mask);
 }
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/lib/Makefile linux-2.4.21-pre6/arch/parisc/lib/Makefile
--- linux-2.4.20/arch/parisc/lib/Makefile	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-pre6/arch/parisc/lib/Makefile	2003-03-26 23:49:40.000000000 +0000
@@ -6,4 +6,6 @@
 L_TARGET = lib.a
 obj-y	:= lusercopy.o bitops.o checksum.o io.o memset.o
 
+obj-$(CONFIG_SMP) += locks.o
+
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/lib/locks.c linux-2.4.21-pre6/arch/parisc/lib/locks.c
--- linux-2.4.20/arch/parisc/lib/locks.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/parisc/lib/locks.c	2003-03-26 23:49:49.000000000 +0000
@@ -0,0 +1,68 @@
+/*
+ * debugging spinlocks for parisc
+ * 
+ * Adapted from the ppc version
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+#ifdef CONFIG_DEBUG_SPINLOCK
+
+#undef INIT_STUCK
+#define INIT_STUCK 200000000 /*0xffffffff*/
+
+#define __spin_trylock(x) (__ldcw(&(x)->lock) != 0)
+
+void spin_lock(spinlock_t *lock)
+{
+	int cpu = smp_processor_id();
+	unsigned int stuck = INIT_STUCK;
+	while (!__spin_trylock(lock)) {
+		while ((unsigned volatile long)lock->lock == 0) {
+			if (!--stuck) {
+				printk("spin_lock(%p) CPU#%d NIP %p"
+				       " holder: cpu %ld pc %08lX\n",
+				       lock, cpu, __builtin_return_address(0),
+				       lock->owner_cpu,lock->owner_pc);
+				stuck = INIT_STUCK;
+				/* steal the lock */
+				/*xchg_u32((void *)&lock->lock,0);*/
+			}
+		}
+	}
+	lock->owner_pc = (unsigned long)__builtin_return_address(0);
+	lock->owner_cpu = cpu;
+}
+
+int spin_trylock(spinlock_t *lock)
+{
+	if (!__spin_trylock(lock))
+		return 0;
+	lock->owner_cpu = smp_processor_id(); 
+	lock->owner_pc = (unsigned long)__builtin_return_address(0);
+	return 1;
+}
+
+void spin_unlock(spinlock_t *lp)
+{
+  	if ( lp->lock )
+		printk("spin_unlock(%p): no lock cpu %d curr PC %p %s/%d\n",
+		       lp, smp_processor_id(), __builtin_return_address(0),
+		       current->comm, current->pid);
+	if ( lp->owner_cpu != smp_processor_id() )
+		printk("spin_unlock(%p): cpu %d trying clear of cpu %d pc %lx val %x\n",
+		      lp, smp_processor_id(), (int)lp->owner_cpu,
+		      lp->owner_pc,lp->lock);
+	lp->owner_pc = lp->owner_cpu = 0;
+	wmb();
+	lp->lock = 1;
+}
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/mm/fault.c linux-2.4.21-pre6/arch/parisc/mm/fault.c
--- linux-2.4.20/arch/parisc/mm/fault.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-pre6/arch/parisc/mm/fault.c	2003-03-26 23:49:54.000000000 +0000
@@ -257,7 +257,8 @@
 	}
 
 	parisc_terminate("Bad Address (null pointer deref?)", regs, code, address);
-
+	/* NOT REACHED! */
+	
   out_of_memory:
 	up_read(&mm->mmap_sem);
 	printk(KERN_CRIT "VM: killing process %s\n", current->comm);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/mm/init.c linux-2.4.21-pre6/arch/parisc/mm/init.c
--- linux-2.4.20/arch/parisc/mm/init.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-pre6/arch/parisc/mm/init.c	2003-03-26 23:49:38.000000000 +0000
@@ -21,6 +21,7 @@
 
 #include <asm/pgalloc.h>
 #include <asm/tlb.h>
+#include <asm/pdc_chassis.h>
 
 mmu_gather_t mmu_gathers[NR_CPUS];
 
@@ -409,6 +410,9 @@
 	}
 
 	printk("%luk freed\n", (unsigned long)(&__init_end - &__init_begin) >> 10);
+
+	/* set up a new led state on systems shipped LED State panel */
+	pdc_chassis_send_status(PDC_CHASSIS_DIRECT_BCOMPLETE);
 }
 
 /*
@@ -574,13 +578,8 @@
 			for (tmp2 = start_pte; tmp2 < PTRS_PER_PTE; tmp2++,pg_table++) {
 				pte_t pte;
 
-#if !defined(CONFIG_KWDB) && !defined(CONFIG_STI_CONSOLE)
+#if !defined(CONFIG_STI_CONSOLE)
 #warning STI console should explicitly allocate executable pages but does not
-/* KWDB needs to write kernel text when setting break points.
-**
-** The right thing to do seems like KWDB modify only the pte which
-** has a break point on it...otherwise we might mask worse bugs.
-*/
 				/*
 				 * Map the fault vector writable so we can
 				 * write the HPMC checksum.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/vmlinux.lds linux-2.4.21-pre6/arch/parisc/vmlinux.lds
--- linux-2.4.20/arch/parisc/vmlinux.lds	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-pre6/arch/parisc/vmlinux.lds	2003-03-26 23:49:15.000000000 +0000
@@ -14,12 +14,12 @@
 	*(.gnu.warning)
 	} = 0
 
+  _etext = .;			/* End of text section */
+  
   . = ALIGN(16);
   .rodata : { *(.rodata) *(.rodata.*) }
   .kstrtab : { *(.kstrtab) }
 
-  _etext = .;			/* End of text section */
-  
   .data BLOCK(8192) : {			/* Data without special */
 	data_start = .;
 	*(.data)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/parisc/vmlinux64.lds linux-2.4.21-pre6/arch/parisc/vmlinux64.lds
--- linux-2.4.20/arch/parisc/vmlinux64.lds	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-pre6/arch/parisc/vmlinux64.lds	2003-03-26 23:49:09.000000000 +0000
@@ -15,12 +15,12 @@
 	*(.gnu.warning)
 	} = 0
 
+  _etext = .;			/* End of text section */
+
   . = ALIGN(16);
   .rodata : { *(.rodata) }
   .kstrtab : { *(.kstrtab) }
 
-  _etext = .;			/* End of text section */
-  
   .data BLOCK(8192) : {			/* Data without special */
 	data_start = .;
 	*(.data)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/8260_io/Makefile linux-2.4.21-pre6/arch/ppc/8260_io/Makefile
--- linux-2.4.20/arch/ppc/8260_io/Makefile	2001-05-22 00:04:46.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/8260_io/Makefile	2003-03-26 23:49:50.000000000 +0000
@@ -1,5 +1,3 @@
-# BK Id: SCCS/s.Makefile 1.3 05/17/01 18:14:19 cort
-#
 #
 # Makefile for the linux MPC8xx ppc-specific parts of comm processor
 #
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/8260_io/commproc.c linux-2.4.21-pre6/arch/ppc/8260_io/commproc.c
--- linux-2.4.20/arch/ppc/8260_io/commproc.c	2001-11-03 01:43:54.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/8260_io/commproc.c	2003-03-26 23:48:57.000000000 +0000
@@ -1,8 +1,4 @@
 /*
- * BK Id: SCCS/s.commproc.c 1.10 10/16/01 16:21:52 trini
- */
-
-/*
  * General Purpose functions for the global management of the
  * 8260 Communication Processor Module.
  * Copyright (c) 1999 Dan Malek (dmalek@jlc.net)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/8260_io/enet.c linux-2.4.21-pre6/arch/ppc/8260_io/enet.c
--- linux-2.4.20/arch/ppc/8260_io/enet.c	2001-10-08 18:40:13.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/8260_io/enet.c	2003-03-26 23:48:57.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.enet.c 1.9 09/14/01 18:01:16 trini
- */
-/*
  * Ethernet driver for Motorola MPC8260.
  * Copyright (c) 1999 Dan Malek (dmalek@jlc.net)
  * Copyright (c) 2000 MontaVista Software Inc. (source@mvista.com)
@@ -810,7 +807,7 @@
 
 	/* Install our interrupt handler.
 	*/
-	request_8xxirq(SIU_INT_ENET, scc_enet_interrupt, 0, "enet", dev);
+	request_irq(SIU_INT_ENET, scc_enet_interrupt, 0, "enet", dev);
 
 	/* Set GSMR_H to enable all normal operating modes.
 	 * Set GSMR_L to enable Ethernet to MC68160.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/8260_io/fcc_enet.c linux-2.4.21-pre6/arch/ppc/8260_io/fcc_enet.c
--- linux-2.4.20/arch/ppc/8260_io/fcc_enet.c	2001-05-22 00:04:46.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/8260_io/fcc_enet.c	2003-03-26 23:49:35.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.fcc_enet.c 1.7 05/17/01 18:14:20 cort
- */
-/*
  * Fast Ethernet Controller (FCC) driver for Motorola MPC8260.
  * Copyright (c) 2000 MontaVista Software, Inc.   Dan Malek (dmalek@jlc.net)
  *
@@ -1442,8 +1439,8 @@
 
 	/* Install our interrupt handler.
 	*/
-	if (request_8xxirq(fip->fc_interrupt, fcc_enet_interrupt, 0,
-							"fenet", dev) < 0)
+	if (request_irq(fip->fc_interrupt, fcc_enet_interrupt, 0, "fenet",
+				dev) < 0)
 		printk("Can't get FCC IRQ %d\n", fip->fc_interrupt);
 
 	/* Set GFMR to enable Ethernet operating mode.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/8260_io/uart.c linux-2.4.21-pre6/arch/ppc/8260_io/uart.c
--- linux-2.4.20/arch/ppc/8260_io/uart.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/8260_io/uart.c	2003-03-26 23:49:00.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.uart.c 1.13 12/29/01 14:50:03 trini
- */
-/*
  *  UART driver for MPC8260 CPM SCC or SMC
  *  Copyright (c) 1999 Dan Malek (dmalek@jlc.net)
  *  Copyright (c) 2000 MontaVista Software, Inc. (source@mvista.com)
@@ -2594,7 +2591,8 @@
 
 			/* Install interrupt handler.
 			*/
-			request_8xxirq(state->irq, rs_8xx_interrupt, 0, "uart", info);
+			request_irq(state->irq, rs_8xx_interrupt, 0, "uart",
+					info);
 
 			/* Set up the baud rate generator.
 			*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/8xx_io/Makefile linux-2.4.21-pre6/arch/ppc/8xx_io/Makefile
--- linux-2.4.20/arch/ppc/8xx_io/Makefile	2001-09-08 19:39:33.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/8xx_io/Makefile	2003-03-26 23:49:35.000000000 +0000
@@ -1,5 +1,3 @@
-# BK Id: SCCS/s.Makefile 1.6 08/30/01 09:33:48 trini
-#
 #
 # Makefile for the linux MPC8xx ppc-specific parts of comm processor
 #
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/8xx_io/commproc.c linux-2.4.21-pre6/arch/ppc/8xx_io/commproc.c
--- linux-2.4.20/arch/ppc/8xx_io/commproc.c	2001-11-03 01:43:54.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/8xx_io/commproc.c	2003-03-26 23:49:40.000000000 +0000
@@ -1,8 +1,4 @@
 /*
- * BK Id: SCCS/s.commproc.c 1.15 10/16/01 16:21:52 trini
- */
-
-/*
  * General Purpose functions for the global management of the
  * Communication Processor Module.
  * Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
@@ -31,7 +27,7 @@
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
-#include <asm/irq.h>
+#include <linux/irq.h>
 #include <asm/mpc8xx.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
@@ -47,14 +43,65 @@
 cpm8xx_t	*cpmp;		/* Pointer to comm processor space */
 
 /* CPM interrupt vector functions.
-*/
+ *
+ * The cpm_vecs structure is only needed to support the cpm_install_handler()
+ * mechanism of installing CPM interrupt handlers.
+ */
 struct	cpm_action {
 	void	(*handler)(void *, struct pt_regs * regs);
 	void	*dev_id;
 };
 static	struct	cpm_action cpm_vecs[CPMVEC_NR];
 static	void	cpm_interrupt(int irq, void * dev, struct pt_regs * regs);
-static	void	cpm_error_interrupt(void *, struct pt_regs * regs);
+static	void	cpm_error_interrupt(int irq, void *, struct pt_regs * regs);
+
+/* Define a table of names to identify CPM interrupt handlers in
+ * /proc/interrupts.
+ */
+const char *cpm_int_name[] =
+	{ "error",	"PC4",		"PC5",		"SMC2",
+	  "SMC1",	"SPI",		"PC6",		"Timer 4",
+	  "",		"PC7",		"PC8",		"PC9",
+	  "Timer 3",	"",		"PC10",		"PC11",
+	  "I2C",	"RISC Timer",	"Timer 2",	"",
+	  "IDMA2",	"IDMA1",	"SDMA error",	"PC12",
+	  "PC13",	"Timer 1",	"PC14",		"SCC4",
+	  "SCC3",	"SCC2",		"SCC1",		"PC15"
+	};
+
+static void
+cpm_mask_irq(unsigned int irq)
+{
+	int cpm_vec = irq - CPM_IRQ_OFFSET;
+
+	((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr &= ~(1 << cpm_vec);
+}
+
+static void
+cpm_unmask_irq(unsigned int irq)
+{
+	int cpm_vec = irq - CPM_IRQ_OFFSET;
+
+	((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr |= (1 << cpm_vec);
+}
+
+static void
+cpm_eoi(unsigned int irq)
+{
+	int cpm_vec = irq - CPM_IRQ_OFFSET;
+
+	((immap_t *)IMAP_ADDR)->im_cpic.cpic_cisr = (1 << cpm_vec);
+}
+
+struct hw_interrupt_type cpm_pic = {
+	" CPM      ",
+	NULL,
+	NULL,
+	cpm_unmask_irq,
+	cpm_mask_irq,
+	NULL,
+	cpm_eoi
+};
 
 void
 m8xx_cpm_reset(uint host_page_addr)
@@ -118,6 +165,8 @@
 void
 cpm_interrupt_init(void)
 {
+	int i;
+
 	/* Initialize the CPM interrupt controller.
 	*/
 	((immap_t *)IMAP_ADDR)->im_cpic.cpic_cicr =
@@ -125,41 +174,54 @@
 		((CPM_INTERRUPT/2) << 13) | CICR_HP_MASK;
 	((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr = 0;
 
+        /* install the CPM interrupt controller routines for the CPM
+         * interrupt vectors
+         */
+        for ( i = CPM_IRQ_OFFSET ; i < CPM_IRQ_OFFSET + NR_CPM_INTS ; i++ )
+                irq_desc[i].handler = &cpm_pic;
+
 	/* Set our interrupt handler with the core CPU.
 	*/
-	if (request_8xxirq(CPM_INTERRUPT, cpm_interrupt, 0, "cpm", NULL) != 0)
+	if (request_irq(CPM_INTERRUPT, cpm_interrupt, 0, "CPM cascade",
+				NULL) != 0)
 		panic("Could not allocate CPM IRQ!");
 
 	/* Install our own error handler.
 	*/
-	cpm_install_handler(CPMVEC_ERROR, cpm_error_interrupt, NULL);
+	if (request_irq(CPM_IRQ_OFFSET + CPMVEC_ERROR, cpm_error_interrupt,
+				0, cpm_int_name[CPMVEC_ERROR], NULL) != 0)
+		panic("Could not allocate CPM error IRQ!");
+
 	((immap_t *)IMAP_ADDR)->im_cpic.cpic_cicr |= CICR_IEN;
 }
 
-/* CPM interrupt controller interrupt.
-*/
-static	void
-cpm_interrupt(int irq, void * dev, struct pt_regs * regs)
+/*
+ * Get the CPM interrupt vector.
+ */
+int
+cpm_get_irq(struct pt_regs *regs)
 {
-	uint	vec;
+	int cpm_vec;
 
 	/* Get the vector by setting the ACK bit and then reading
 	 * the register.
 	 */
 	((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr = 1;
-	vec = ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr;
-	vec >>= 11;
+	cpm_vec = ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr;
+	cpm_vec >>= 11;
 
-	if (cpm_vecs[vec].handler != 0)
-		(*cpm_vecs[vec].handler)(cpm_vecs[vec].dev_id, regs);
-	else
-		((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr &= ~(1 << vec);
+	return cpm_vec;
+}
 
-	/* After servicing the interrupt, we have to remove the status
-	 * indicator.
+/* CPM interrupt controller cascade interrupt.
+*/
+static	void
+cpm_interrupt(int irq, void * dev, struct pt_regs * regs)
+{
+	/* This interrupt handler never actually gets called.  It is
+	 * installed only to unmask the CPM cascade interrupt in the SIU
+	 * and to make the CPM cascade interrupt visible in /proc/interrupts.
 	 */
-	((immap_t *)IMAP_ADDR)->im_cpic.cpic_cisr = (1 << vec);
-	
 }
 
 /* The CPM can generate the error interrupt when there is a race condition
@@ -168,40 +230,69 @@
  * tests in the interrupt handler.
  */
 static	void
-cpm_error_interrupt(void *dev, struct pt_regs *regs)
+cpm_error_interrupt(int irq, void *dev, struct pt_regs *regs)
 {
 }
 
+/* A helper function to translate the handler prototype required by
+ * request_irq() to the handler prototype required by cpm_install_handler().
+ */
+static void
+cpm_handler_helper(int irq, void *dev_id, struct pt_regs *regs)
+{
+	int cpm_vec = irq - CPM_IRQ_OFFSET;
+
+	(*cpm_vecs[cpm_vec].handler)(dev_id, regs);
+}
+
 /* Install a CPM interrupt handler.
-*/
+ * This routine accepts a CPM interrupt vector in the range 0 to 31.
+ * This routine is retained for backward compatibility.  Rather than using
+ * this routine to install a CPM interrupt handler, you can now use
+ * request_irq() with an IRQ in the range CPM_IRQ_OFFSET to
+ * CPM_IRQ_OFFSET + NR_CPM_INTS - 1 (16 to 47).
+ *
+ * Notice that the prototype of the interrupt handler function must be
+ * different depending on whether you install the handler with
+ * request_irq() or cpm_install_handler().
+ */
 void
-cpm_install_handler(int vec, void (*handler)(void *, struct pt_regs *regs),
+cpm_install_handler(int cpm_vec, void (*handler)(void *, struct pt_regs *regs),
 		    void *dev_id)
 {
+	int err;
 
 	/* If null handler, assume we are trying to free the IRQ.
 	*/
 	if (!handler) {
-		cpm_free_handler(vec);
+		free_irq(CPM_IRQ_OFFSET + cpm_vec, dev_id);
 		return;
 	}
 
-	if (cpm_vecs[vec].handler != 0)
-		printk("CPM interrupt %x replacing %x\n",
-			(uint)handler, (uint)cpm_vecs[vec].handler);
-	cpm_vecs[vec].handler = handler;
-	cpm_vecs[vec].dev_id = dev_id;
-	((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr |= (1 << vec);
+	if (cpm_vecs[cpm_vec].handler != 0)
+		printk(KERN_INFO "CPM interrupt %x replacing %x\n",
+			(uint)handler, (uint)cpm_vecs[cpm_vec].handler);
+	cpm_vecs[cpm_vec].handler = handler;
+	cpm_vecs[cpm_vec].dev_id = dev_id;
+
+	if ((err = request_irq(CPM_IRQ_OFFSET + cpm_vec, cpm_handler_helper,
+					0, cpm_int_name[cpm_vec], dev_id)))
+		printk(KERN_ERR "request_irq() returned %d for CPM vector %d\n",
+				err, cpm_vec);
 }
 
 /* Free a CPM interrupt handler.
-*/
+ * This routine accepts a CPM interrupt vector in the range 0 to 31.
+ * This routine is retained for backward compatibility.
+ */
 void
-cpm_free_handler(int vec)
+cpm_free_handler(int cpm_vec)
 {
-	cpm_vecs[vec].handler = NULL;
-	cpm_vecs[vec].dev_id = NULL;
-	((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr &= ~(1 << vec);
+	request_irq(CPM_IRQ_OFFSET + cpm_vec, NULL, 0, 0,
+		cpm_vecs[cpm_vec].dev_id);
+
+	cpm_vecs[cpm_vec].handler = NULL;
+	cpm_vecs[cpm_vec].dev_id = NULL;
 }
 
 /* Allocate some memory from the dual ported ram.  We may want to
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/8xx_io/enet.c linux-2.4.21-pre6/arch/ppc/8xx_io/enet.c
--- linux-2.4.20/arch/ppc/8xx_io/enet.c	2001-10-17 21:37:01.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/8xx_io/enet.c	2003-03-26 23:49:20.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.enet.c 1.17 10/11/01 11:55:47 trini
- */
-/*
  * Ethernet driver for Motorola MPC8xx.
  * Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
  *
@@ -48,6 +45,7 @@
 #include <asm/bitops.h>
 #include <asm/uaccess.h>
 #include <asm/commproc.h>
+#include <asm/irq.h>
 
 /*
  *				Theory of Operation
@@ -147,7 +145,6 @@
 static int scc_enet_open(struct net_device *dev);
 static int scc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev);
 static int scc_enet_rx(struct net_device *dev);
-static void scc_enet_interrupt(void *dev_id, struct pt_regs *regs);
 static int scc_enet_close(struct net_device *dev);
 static struct net_device_stats *scc_enet_get_stats(struct net_device *dev);
 static void set_multicast_list(struct net_device *dev);
@@ -303,7 +300,7 @@
  * This is called from the CPM handler, not the MPC core interrupt.
  */
 static void
-scc_enet_interrupt(void *dev_id, struct pt_regs *regs)
+scc_enet_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct	net_device *dev = dev_id;
 	volatile struct	scc_enet_private *cep;
@@ -880,7 +877,9 @@
 
 	/* Install our interrupt handler.
 	*/
-	cpm_install_handler(CPMVEC_ENET, scc_enet_interrupt, dev);
+	if ((request_irq(CPM_IRQ_OFFSET + CPMVEC_ENET, scc_enet_interrupt,
+			0, cpm_int_name[CPMVEC_ENET], dev)) != 0)
+		panic("Could not allocate SCC ethernet IRQ!");
 
 	/* Set GSMR_H to enable all normal operating modes.
 	 * Set GSMR_L to enable Ethernet to MC68160.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/8xx_io/fec.c linux-2.4.21-pre6/arch/ppc/8xx_io/fec.c
--- linux-2.4.20/arch/ppc/8xx_io/fec.c	2002-11-28 23:53:10.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/8xx_io/fec.c	2003-03-26 23:49:30.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Fast Ethernet Controller (FEC) driver for Motorola MPC8xx.
  * Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
  *
@@ -1365,11 +1362,7 @@
 /* This interrupt occurs when the PHY detects a link change.
 */
 static void
-#ifdef CONFIG_RPXCLASSIC
-mii_link_interrupt(void *dev_id)
-#else
 mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs)
-#endif
 {
 #ifdef	CONFIG_USE_MDIO
 	struct	net_device *dev = dev_id;
@@ -1815,7 +1808,7 @@
 	bdp->cbd_sc |= BD_SC_WRAP;
 
 	/* Install our interrupt handler. */
-	if (request_8xxirq(FEC_INTERRUPT, fec_enet_interrupt, 0, "fec", dev) != 0)
+	if (request_irq(FEC_INTERRUPT, fec_enet_interrupt, 0, "fec", dev) != 0)
 		panic("Could not allocate FEC IRQ!");
 
 #ifdef CONFIG_RPXCLASSIC
@@ -1825,7 +1818,9 @@
 	immap->im_ioport.iop_pcdir &= ~0x0001;
 	immap->im_ioport.iop_pcso  &= ~0x0001;
 	immap->im_ioport.iop_pcint |=  0x0001;
-	cpm_install_handler(CPMVEC_PIO_PC15, mii_link_interrupt, dev);
+	if (request_irq(CPM_IRQ_OFFSET + CPMVEC_PIO_PC15, mii_link_interrupt,
+			0, cpm_int_name[CPMVEC_PIO_PC15], dev) != 0)
+		panic("Could not allocate Port C FEC IRQ!");
 
 	/* Make LEDS reflect Link status.
 	*/
@@ -1836,7 +1831,7 @@
 	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_siel |=
 		(0x80000000 >> PHY_INTERRUPT);
 
-	if (request_8xxirq(PHY_INTERRUPT, mii_link_interrupt, 0, "mii", dev) != 0)
+	if (request_irq(PHY_INTERRUPT, mii_link_interrupt, 0, "mii", dev) != 0)
 		panic("Could not allocate MII IRQ!");
 #endif
 
@@ -1906,9 +1901,9 @@
 	fep->phy_id_done = 0;
 	fep->phy_addr = 0;
 	mii_queue(dev, mk_mii_read(MII_REG_PHYIR1), mii_discover_phy, 0);
-#endif	/* CONFIG_USE_MDIO */
 
 	fep->old_status = 0;
+#endif	/* CONFIG_USE_MDIO */
 
 	return 0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/8xx_io/uart.c linux-2.4.21-pre6/arch/ppc/8xx_io/uart.c
--- linux-2.4.20/arch/ppc/8xx_io/uart.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/8xx_io/uart.c	2003-03-26 23:49:50.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.uart.c 1.23 12/29/01 14:50:03 trini
- */
-/*
  *  UART driver for MPC860 CPM SCC or SMC
  *  Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
  *
@@ -44,15 +41,13 @@
 #include <asm/8xx_immap.h>
 #include <asm/mpc8xx.h>
 #include <asm/commproc.h>
+#include <asm/irq.h>
+#include <asm/kgdb.h>
 #ifdef CONFIG_MAGIC_SYSRQ
 #include <linux/sysrq.h>
 #endif
 
-#ifdef CONFIG_KGDB
-extern void breakpoint(void);
-extern void set_debug_traps(void);
-extern int  kgdb_output_string (const char* s, unsigned int count);
-#endif
+extern int kgdb_output_string (const char* s, unsigned int count);
 
 #ifdef CONFIG_SERIAL_CONSOLE
 #include <linux/console.h>
@@ -134,6 +129,18 @@
 #define smc_scc_num	hub6
 #define NUM_IS_SCC	((int)0x00010000)
 #define PORT_NUM(P)	((P) & 0x0000ffff)
+#define PORT_IS_SCC(P)	((P) & NUM_IS_SCC)
+
+/* The serial port to use for KGDB. */
+#ifdef CONFIG_KGDB_TTYS1
+#define KGDB_SER_IDX	1	/* SCC1/SMC1 */
+#elif CONFIG_KGDB_TTYS2
+#define KGDB_SER_IDX	2	/* SCC2/SMC2 */
+#elif CONFIG_KGDB_TTYS3
+#define KGDB_SER_IDX	3	/* SCC4/SMC4 (future?) */
+#else				/* Unset, or ttyS0, use SCC1/SMC1 */
+#define KGDB_SER_IDX	0
+#endif
 
 /* Processors other than the 860 only get SMCs configured by default.
  * Either they don't have SCCs or they are allocated somewhere else.
@@ -277,7 +284,7 @@
 	
 	save_flags(flags); cli();
 	idx = PORT_NUM(info->state->smc_scc_num);
-	if (info->state->smc_scc_num & NUM_IS_SCC) {
+	if (PORT_IS_SCC(info->state->smc_scc_num)) {
 		sccp = &cpmp->cp_scc[idx];
 		sccp->scc_sccm &= ~UART_SCCM_TX;
 	}
@@ -301,7 +308,7 @@
 	
 	idx = PORT_NUM(info->state->smc_scc_num);
 	save_flags(flags); cli();
-	if (info->state->smc_scc_num & NUM_IS_SCC) {
+	if (PORT_IS_SCC(info->state->smc_scc_num)) {
 		sccp = &cpmp->cp_scc[idx];
 		sccp->scc_sccm |= UART_SCCM_TX;
 	}
@@ -390,6 +397,14 @@
 		cp = (unsigned char *)__va(bdp->cbd_bufaddr);
 		status = bdp->cbd_sc;
 
+#ifdef CONFIG_KGDB
+		if (info->state->smc_scc_num == KGDB_SER_IDX) {
+			if (*cp == 0x03 || *cp == '$')
+				breakpoint();
+			return;
+		}
+#endif
+
 		/* Check to see if there is room in the tty buffer for
 		 * the characters in our BD buffer.  If not, we exit
 		 * now, leaving the BD with the characters.  We'll pick
@@ -615,7 +630,7 @@
 /*
  * This is the serial driver's interrupt routine for a single port
  */
-static void rs_8xx_interrupt(void *dev_id, struct pt_regs *regs)
+static void rs_8xx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	u_char	events;
 	int	idx;
@@ -626,7 +641,7 @@
 	info = (ser_info_t *)dev_id;
 
 	idx = PORT_NUM(info->state->smc_scc_num);
-	if (info->state->smc_scc_num & NUM_IS_SCC) {
+	if (PORT_IS_SCC(info->state->smc_scc_num)) {
 		sccp = &cpmp->cp_scc[idx];
 		events = sccp->scc_scce;
 		if (events & SMCM_BRKE)
@@ -772,7 +787,7 @@
 	change_speed(info);
 	
 	idx = PORT_NUM(info->state->smc_scc_num);
-	if (info->state->smc_scc_num & NUM_IS_SCC) {
+	if (PORT_IS_SCC(info->state->smc_scc_num)) {
 		sccp = &cpmp->cp_scc[idx];
 		scup = (scc_uart_t *)&cpmp->cp_dparam[state->port];
 		scup->scc_genscc.scc_mrblr = RX_BUF_SIZE;
@@ -836,7 +851,7 @@
 	save_flags(flags); cli(); /* Disable interrupts */
 
 	idx = PORT_NUM(state->smc_scc_num);
-	if (state->smc_scc_num & NUM_IS_SCC) {
+	if (PORT_IS_SCC(state->smc_scc_num)) {
 		sccp = &cpmp->cp_scc[idx];
 		sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
 #ifdef CONFIG_SERIAL_CONSOLE
@@ -991,7 +1006,7 @@
 	 */
 	bits++;
 	idx = PORT_NUM(state->smc_scc_num);
-	if (state->smc_scc_num & NUM_IS_SCC) {
+	if (PORT_IS_SCC(state->smc_scc_num)) {
 		sccp = &cpmp->cp_scc[idx];
 		new_mode = (sbits << 12) | scval;
 		prev_mode = sccp->scc_pmsr;
@@ -1059,7 +1074,7 @@
 	ser_info_t *info = (ser_info_t *)tty->driver_data;
 	volatile cbd_t *bdp;
 
-#ifdef CONFIG_KGDB
+#ifdef CONFIG_KGDB_CONSOLE
         /* Try to let stub handle output. Returns true if it did. */ 
         if (kgdb_output_string(buf, count))
             return ret;
@@ -1390,7 +1405,7 @@
 	cp = cpmp;
 
 	idx = PORT_NUM(info->state->smc_scc_num);
-	if (info->state->smc_scc_num & NUM_IS_SCC)
+	if (PORT_IS_SCC(info->state->smc_scc_num))
 		chan = scc_chan_map[idx];
 	else
 		chan = smc_chan_map[idx];
@@ -1407,7 +1422,7 @@
 	cp = cpmp;
 
 	idx = PORT_NUM(info->state->smc_scc_num);
-	if (info->state->smc_scc_num & NUM_IS_SCC)
+	if (PORT_IS_SCC(info->state->smc_scc_num))
 		chan = scc_chan_map[idx];
 	else
 		chan = smc_chan_map[idx];
@@ -1712,7 +1727,7 @@
 	info->read_status_mask &= ~BD_SC_EMPTY;
 	if (info->flags & ASYNC_INITIALIZED) {
 		idx = PORT_NUM(info->state->smc_scc_num);
-		if (info->state->smc_scc_num & NUM_IS_SCC) {
+		if (PORT_IS_SCC(info->state->smc_scc_num)) {
 			sccp = &cpmp->cp_scc[idx];
 			sccp->scc_sccm &= ~UART_SCCM_RX;
 			sccp->scc_gsmrl &= ~SCC_GSMRL_ENR;
@@ -1903,7 +1918,7 @@
 	 */
 	if ((filp->f_flags & O_NONBLOCK) ||
 	    (tty->flags & (1 << TTY_IO_ERROR)) ||
-	    !(info->state->smc_scc_num & NUM_IS_SCC)) {
+	    !(PORT_IS_SCC(info->state->smc_scc_num))) {
 		if (info->flags & ASYNC_CALLOUT_ACTIVE)
 			return -EBUSY;
 		info->flags |= ASYNC_NORMAL_ACTIVE;
@@ -2081,7 +2096,7 @@
 
 	ret = sprintf(buf, "%d: uart:%s port:%X irq:%d",
 		      state->line,
-		      (state->smc_scc_num & NUM_IS_SCC) ? "SCC" : "SMC",
+		      (PORT_IS_SCC(state->smc_scc_num)) ? "SCC" : "SMC",
 		      (unsigned int)(state->port), state->irq);
 
 	if (!state->port || (state->type == PORT_UNKNOWN)) {
@@ -2302,7 +2317,7 @@
 static void serial_console_write(struct console *c, const char *s,
 				unsigned count)
 {
-#ifdef CONFIG_KGDB
+#ifdef CONFIG_KGDB_CONSOLE
 	/* Try to let stub handle output. Returns true if it did. */ 
 	if (kgdb_output_string(s, count))
 		return;
@@ -2319,14 +2334,7 @@
 }
 #endif
 
-#ifdef CONFIG_KGDB
-void
-putDebugChar(char ch)
-{
-	my_console_write(0, &ch, 1);
-}
-#endif
-
+#if defined(CONFIG_KGDB) || defined(CONFIG_XMON)
 /*
  * Receive character from the serial port.  This only works well
  * before the port is initialized for real use.
@@ -2399,6 +2407,7 @@
 
 	return((int)c);
 }
+#endif /* CONFIG_KGDB || CONFIG_XMON */
 
 #ifdef CONFIG_XMON
 int
@@ -2418,7 +2427,13 @@
 static char kgdb_buf[RX_BUF_SIZE], *kgdp;
 static int kgdb_chars;
 
-unsigned char
+void
+putDebugChar(char ch)
+{
+	my_console_write(0, &ch, 1);
+}
+
+char
 getDebugChar(void)
 {
 	if (kgdb_chars <= 0) {
@@ -2430,9 +2445,18 @@
 	return(*kgdp++);
 }
 
-void kgdb_interruptible(int state)
+void kgdb_interruptible(int yes)
 {
+	volatile smc_t	*smcp;
+
+	smcp = &cpmp->cp_smc[KGDB_SER_IDX];
+
+	if (yes == 1)
+		smcp->smc_smcm |= SMCM_RX;
+	else
+		smcp->smc_smcm &= ~SMCM_RX;
 }
+
 void kgdb_map_scc(void)
 {
 	struct		serial_state *ser;
@@ -2459,7 +2483,7 @@
 	/* Allocate space for an input FIFO, plus a few bytes for output.
 	 * Allocate bytes to maintain word alignment.
 	 */
-	mem_addr = (uint)(&cpmp->cp_dpmem[0x1000]);
+	mem_addr = (uint)(&cpmp->cp_dpmem[0xa00]);
 
 	/* Set the physical address of the host memory buffers in
 	 * the buffer descriptors.
@@ -2489,7 +2513,7 @@
 	return kmem_start;
 }
 
-#endif
+#endif /* CONFIG_SERIAL_CONSOLE */
 
 /* Index in baud rate table of the default console baud rate.
 */
@@ -2646,7 +2670,7 @@
 		state->icount.overrun = state->icount.brk = 0;
 		printk(KERN_INFO "ttyS%02d at 0x%04x is a %s\n",
 		       i, (unsigned int)(state->port),
-		       (state->smc_scc_num & NUM_IS_SCC) ? "SCC" : "SMC");
+		       PORT_IS_SCC(state->smc_scc_num) ? "SCC" : "SMC");
 #ifdef CONFIG_SERIAL_CONSOLE
 		/* If we just printed the message on the console port, and
 		 * we are about to initialize it for general use, we have
@@ -2698,7 +2722,7 @@
 			bdp->cbd_sc = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT;
 
 			idx = PORT_NUM(info->state->smc_scc_num);
-			if (info->state->smc_scc_num & NUM_IS_SCC) {
+			if (PORT_IS_SCC(info->state->smc_scc_num)) {
 				scp = &cp->cp_scc[idx];
 				sup = (scc_uart_t *)&cp->cp_dparam[state->port];
 				sup->scc_genscc.scc_rbase = dp_addr;
@@ -2731,7 +2755,7 @@
 			bdp->cbd_bufaddr = __pa(mem_addr);
 			bdp->cbd_sc = (BD_SC_WRAP | BD_SC_INTRPT);
 
-			if (info->state->smc_scc_num & NUM_IS_SCC) {
+			if (PORT_IS_SCC(info->state->smc_scc_num)) {
 				sup->scc_genscc.scc_tbase = dp_addr;
 
 				/* Set up the uart parameters in the
@@ -2874,7 +2898,8 @@
 
 			/* Install interrupt handler.
 			*/
-			cpm_install_handler(state->irq, rs_8xx_interrupt, info);
+			if ((request_irq(CPM_IRQ_OFFSET + state->irq, rs_8xx_interrupt, 0, cpm_int_name[state->irq], info)) != 0)
+				panic("Could not allocate UART IRQ!");
 
 			/* Set up the baud rate generator.
 			*/
@@ -2919,7 +2944,7 @@
 	cp = cpmp;	/* Get pointer to Communication Processor */
 
 	idx = PORT_NUM(ser->smc_scc_num);
-	if (ser->smc_scc_num & NUM_IS_SCC) {
+	if (PORT_IS_SCC(ser->smc_scc_num)) {
 		scp = &cp->cp_scc[idx];
 		sup = (scc_uart_t *)&cp->cp_dparam[ser->port];
 	}
@@ -2957,7 +2982,7 @@
 
 	/* Set up the uart parameters in the parameter ram.
 	*/
-	if (ser->smc_scc_num & NUM_IS_SCC) {
+	if (PORT_IS_SCC(ser->smc_scc_num)) {
 
 		sup->scc_genscc.scc_rbase = dp_addr;
 		sup->scc_genscc.scc_tbase = dp_addr + sizeof(cbd_t);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/Makefile linux-2.4.21-pre6/arch/ppc/Makefile
--- linux-2.4.20/arch/ppc/Makefile	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/Makefile	2003-03-26 23:48:59.000000000 +0000
@@ -1,4 +1,3 @@
-# BK Id: %F% %I% %G% %U% %#%
 #
 # This file is included by the global makefile so that you can add your own
 # architecture-specific flags and dependencies. Remember to do have actions
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/amiga/Makefile linux-2.4.21-pre6/arch/ppc/amiga/Makefile
--- linux-2.4.20/arch/ppc/amiga/Makefile	2001-05-22 00:04:46.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/amiga/Makefile	2003-03-26 23:49:34.000000000 +0000
@@ -1,5 +1,3 @@
-# BK Id: SCCS/s.Makefile 1.5 05/21/01 00:48:24 cort
-#
 #
 # Makefile for Linux arch/m68k/amiga source directory
 #
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/amiga/amiga_ksyms.c linux-2.4.21-pre6/arch/ppc/amiga/amiga_ksyms.c
--- linux-2.4.20/arch/ppc/amiga/amiga_ksyms.c	2001-05-22 00:04:46.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/amiga/amiga_ksyms.c	2003-03-26 23:49:00.000000000 +0000
@@ -1,4 +1 @@
-/*
- * BK Id: SCCS/s.amiga_ksyms.c 1.5 05/17/01 18:14:20 cort
- */
 #include "../../m68k/amiga/amiga_ksyms.c"
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/amiga/amiints.c linux-2.4.21-pre6/arch/ppc/amiga/amiints.c
--- linux-2.4.20/arch/ppc/amiga/amiints.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/amiga/amiints.c	2003-03-26 23:49:05.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * linux/arch/m68k/amiga/amiints.c -- Amiga Linux interrupt handling code
  *
  * This file is subject to the terms and conditions of the GNU General Public
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/amiga/amisound.c linux-2.4.21-pre6/arch/ppc/amiga/amisound.c
--- linux-2.4.20/arch/ppc/amiga/amisound.c	2001-05-22 00:04:46.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/amiga/amisound.c	2003-03-26 23:49:20.000000000 +0000
@@ -1,4 +1 @@
-/*
- * BK Id: SCCS/s.amisound.c 1.5 05/17/01 18:14:20 cort
- */
 #include "../../m68k/amiga/amisound.c"
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/amiga/bootinfo.c linux-2.4.21-pre6/arch/ppc/amiga/bootinfo.c
--- linux-2.4.20/arch/ppc/amiga/bootinfo.c	2001-05-22 00:04:46.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/amiga/bootinfo.c	2003-03-26 23:49:50.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.bootinfo.c 1.5 05/17/01 18:14:20 cort
- */
-/*
  *  linux/arch/ppc/amiga/bootinfo.c
  *
  *  Extracted from arch/m68k/kernel/setup.c.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/amiga/chipram.c linux-2.4.21-pre6/arch/ppc/amiga/chipram.c
--- linux-2.4.20/arch/ppc/amiga/chipram.c	2001-05-22 00:04:46.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/amiga/chipram.c	2003-03-26 23:49:51.000000000 +0000
@@ -1,4 +1 @@
-/*
- * BK Id: SCCS/s.chipram.c 1.7 05/21/01 00:49:49 cort
- */
 #include "../../m68k/amiga/chipram.c"
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/amiga/cia.c linux-2.4.21-pre6/arch/ppc/amiga/cia.c
--- linux-2.4.20/arch/ppc/amiga/cia.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/amiga/cia.c	2003-03-26 23:49:18.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  linux/arch/m68k/amiga/cia.c - CIA support
  *
  *  Copyright (C) 1996 Roman Zippel
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/amiga/config.c linux-2.4.21-pre6/arch/ppc/amiga/config.c
--- linux-2.4.20/arch/ppc/amiga/config.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/amiga/config.c	2003-03-26 23:49:24.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #define m68k_debug_device debug_device
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/amiga/ints.c linux-2.4.21-pre6/arch/ppc/amiga/ints.c
--- linux-2.4.20/arch/ppc/amiga/ints.c	2001-05-22 00:04:46.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/amiga/ints.c	2003-03-26 23:48:59.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.ints.c 1.5 05/17/01 18:14:20 cort
- */
-/*
  *  linux/arch/ppc/amiga/ints.c
  *
  *  Linux/m68k general interrupt handling code from arch/m68k/kernel/ints.c
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/amiga/pcmcia.c linux-2.4.21-pre6/arch/ppc/amiga/pcmcia.c
--- linux-2.4.20/arch/ppc/amiga/pcmcia.c	2001-05-22 00:04:46.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/amiga/pcmcia.c	2003-03-26 23:49:20.000000000 +0000
@@ -1,4 +1 @@
-/*
- * BK Id: SCCS/s.pcmcia.c 1.5 05/17/01 18:14:20 cort
- */
 #include "../../m68k/amiga/pcmcia.c"
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/amiga/time.c linux-2.4.21-pre6/arch/ppc/amiga/time.c
--- linux-2.4.20/arch/ppc/amiga/time.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/amiga/time.c	2003-03-26 23:49:38.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #include <linux/config.h> /* CONFIG_HEARTBEAT */
 #include <linux/errno.h>
 #include <linux/sched.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/Makefile linux-2.4.21-pre6/arch/ppc/boot/Makefile
--- linux-2.4.20/arch/ppc/boot/Makefile	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/Makefile	2003-03-26 23:48:59.000000000 +0000
@@ -31,6 +31,7 @@
 subdir-$(CONFIG_ALL_PPC)	:= chrp pmac prep
 tools-$(CONFIG_ALL_PPC)		:= addnote mknote hack-coff mkprep
 tools-$(CONFIG_4xx)		:= mktree
+tools-$(CONFIG_LOPEC)		:= mkbugboot mkprep
 tools-$(CONFIG_SPRUCE)		:= mktree
 
 # These are dirs we don't want to go into on BOOT_TARGETS.  We have them for
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/chrp/Makefile linux-2.4.21-pre6/arch/ppc/boot/chrp/Makefile
--- linux-2.4.20/arch/ppc/boot/chrp/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/chrp/Makefile	2003-03-26 23:49:50.000000000 +0000
@@ -1,4 +1,3 @@
-# BK Id: SCCS/s.Makefile 1.15 01/11/02 10:46:06 trini
 #
 # Makefile for making ELF bootable images for booting on CHRP
 # using Open Firmware.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/chrp/main.c linux-2.4.21-pre6/arch/ppc/boot/chrp/main.c
--- linux-2.4.20/arch/ppc/boot/chrp/main.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/chrp/main.c	2003-03-26 23:48:58.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.main.c 1.16 01/12/02 10:36:33 trini
- */
-/*
  * Copyright (C) Paul Mackerras 1997.
  *
  * This program is free software; you can redistribute it and/or
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/chrp/misc.S linux-2.4.21-pre6/arch/ppc/boot/chrp/misc.S
--- linux-2.4.20/arch/ppc/boot/chrp/misc.S	2001-05-24 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/chrp/misc.S	2003-03-26 23:48:58.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.misc.S 1.6 05/18/01 15:16:59 cort
- */
-/*
  * Copyright (C) Paul Mackerras 1997.
  *
  * This program is free software; you can redistribute it and/or
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/chrp/start.c linux-2.4.21-pre6/arch/ppc/boot/chrp/start.c
--- linux-2.4.20/arch/ppc/boot/chrp/start.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/chrp/start.c	2003-03-26 23:48:57.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.start.c 1.8 07/25/01 18:13:07 trini
- */
-/*
  * Copyright (C) Paul Mackerras 1997.
  *
  * This program is free software; you can redistribute it and/or
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/common/crt0.S linux-2.4.21-pre6/arch/ppc/boot/common/crt0.S
--- linux-2.4.20/arch/ppc/boot/common/crt0.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/common/crt0.S	2003-03-26 23:49:50.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.crt0.S 1.14 01/11/02 10:46:07 trini
- */
 /*    Copyright (c) 1997 Paul Mackerras <paulus@cs.anu.edu.au>
  *      Initial Power Macintosh COFF version.
  *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/common/dummy.c linux-2.4.21-pre6/arch/ppc/boot/common/dummy.c
--- linux-2.4.20/arch/ppc/boot/common/dummy.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/common/dummy.c	2003-03-26 23:49:34.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 int main(void)
 {
 	return 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/common/misc-common.c linux-2.4.21-pre6/arch/ppc/boot/common/misc-common.c
--- linux-2.4.20/arch/ppc/boot/common/misc-common.c	2001-08-28 13:58:33.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/common/misc-common.c	2003-03-26 23:49:38.000000000 +0000
@@ -8,27 +8,10 @@
  *
  * Derived from arch/ppc/boot/prep/misc.c
  *
- * Copyright 2000-2001 MontaVista Software Inc.
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- *
- * THIS  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.
- *
- * 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.
+ * 2000-2001 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
  */
 
 #include <stdarg.h>	/* for va_ bits */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/common/misc-simple.c linux-2.4.21-pre6/arch/ppc/boot/common/misc-simple.c
--- linux-2.4.20/arch/ppc/boot/common/misc-simple.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/common/misc-simple.c	2003-03-26 23:49:51.000000000 +0000
@@ -10,12 +10,10 @@
  * Author: Matt Porter <mporter@mvista.com>
  * Derived from arch/ppc/boot/prep/misc.c
  *
- * Copyright 2001 MontaVista Software Inc.
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
+ * 2001 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
  */
 
 #include <linux/types.h>
@@ -27,6 +25,7 @@
 #include <asm/mmu.h>
 #include <asm/bootinfo.h>
 
+#include "mpc10x.h"
 #include "nonstdio.h"
 #include "zlib.h"
 
@@ -44,6 +43,12 @@
 #define HAS_KEYB 0
 #endif
 
+/* Will / Can the user give input? */
+#if (defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_VGA_CONSOLE)) \
+	&& !defined(CONFIG_GEMINI)
+#define INTERACTIVE_CONSOLE	1
+#endif
+
 char *avail_ram;
 char *end_avail;
 char *zimage_start;
@@ -64,21 +69,42 @@
 extern unsigned long start;
 
 extern int CRT_tstc(void);
+extern unsigned long mpc10x_get_mem_size(int map);
 extern unsigned long serial_init(int chan, void *ignored);
 extern void serial_close(unsigned long com_port);
 extern void gunzip(void *, int, unsigned char *, int *);
 extern void serial_fixups(void);
 
+/* Allow decompress_kernel to be hooked into.  This is the default. */
+void * __attribute__ ((weak))
+load_kernel(unsigned long load_addr, int num_words, unsigned long cksum,
+		void *bp)
+{
+	return decompress_kernel(load_addr, num_words, cksum, bp);
+}
+
 struct bi_record *
 decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum)
 {
+#ifdef INTERACTIVE_CONSOLE
 	int timer = 0;
-	char *cp, ch;
-	struct bi_record *rec, *birecs;
+	char ch;
+#endif
+	char *cp;
+	struct bi_record *rec;
+	unsigned long rec_loc, initrd_loc, TotalMemory = 0;
 
 	serial_fixups();
 	com_port = serial_init(0, NULL);
 
+#ifdef CONFIG_LOPEC
+	/*
+	 * This should work on any board with an MPC10X which is properly
+	 * initalized.
+	 */
+	TotalMemory = mpc10x_get_mem_size(MPC10X_MEM_MAP_B);
+#endif
+
 	/* assume the chunk below 8M is free */
 	end_avail = (char *)0x00800000;
 
@@ -148,8 +174,7 @@
 	memcpy (cmd_line, cmd_preset, sizeof(cmd_preset));
 	while ( *cp ) putc(*cp++);
 
-#if (defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_VGA_CONSOLE)) \
-	&& !defined(CONFIG_GEMINI)
+#ifdef INTERACTIVE_CONSOLE
 	/*
 	 * If they have a console, allow them to edit the command line.
 	 * Otherwise, don't bother wasting the five seconds.
@@ -189,14 +214,40 @@
 	/*
 	 * Create bi_recs for cmd_line and initrds
 	 */
-	rec = (struct bi_record *)_ALIGN((unsigned long)(zimage_size) +
+	rec_loc = _ALIGN((unsigned long)(zimage_size) +
 			(1 << 20) - 1, (1 << 20));
-	birecs = rec;
+	rec = (struct bi_record *)rec_loc;
 
+	/* We need to make sure that the initrd and bi_recs do not
+	 * overlap. */
+	if ( initrd_size ) {
+		initrd_loc = (unsigned long)(&__ramdisk_begin);
+		/* If the bi_recs are in the middle of the current
+		 * initrd, move the initrd to the next MB
+		 * boundary. */
+		if ((rec_loc > initrd_loc) &&
+				((initrd_loc + initrd_size) > rec_loc)) {
+			initrd_loc = _ALIGN((unsigned long)(zimage_size)
+					+ (2 << 20) - 1, (2 << 20));
+		 	memmove((void *)initrd_loc, &__ramdisk_begin,
+				 initrd_size);
+	         	puts("initrd moved:  "); puthex(initrd_loc);
+		 	puts(" "); puthex(initrd_loc + initrd_size);
+		 	puts("\n");
+		}
+	}
+ 
 	rec->tag = BI_FIRST;
 	rec->size = sizeof(struct bi_record);
 	rec = (struct bi_record *)((unsigned long)rec + rec->size);
 
+	if ( TotalMemory ) {
+		rec->tag = BI_MEMSIZE;
+		rec->data[0] = TotalMemory;
+		rec->size = sizeof(struct bi_record) + sizeof(unsigned long);
+		rec = (struct bi_record *)((unsigned long)rec + rec->size);
+	}
+
 	rec->tag = BI_CMD_LINE;
 	memcpy( (char *)rec->data, cmd_line, strlen(cmd_line)+1);
 	rec->size = sizeof(struct bi_record) + strlen(cmd_line) + 1;
@@ -204,7 +255,7 @@
 
 	if ( initrd_size ) {
 		rec->tag = BI_INITRD;
-		rec->data[0] = (unsigned long)(&__ramdisk_begin);
+		rec->data[0] = initrd_loc;
 		rec->data[1] = initrd_size;
 		rec->size = sizeof(struct bi_record) + 2 *
 			sizeof(unsigned long);
@@ -218,5 +269,5 @@
 	puts("Now booting the kernel\n");
 	serial_close(com_port);
 
-	return birecs;
+	return (struct bi_record *)rec_loc;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/common/mpc10x_memory.c linux-2.4.21-pre6/arch/ppc/boot/common/mpc10x_memory.c
--- linux-2.4.20/arch/ppc/boot/common/mpc10x_memory.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/common/mpc10x_memory.c	2003-03-26 23:49:27.000000000 +0000
@@ -0,0 +1,113 @@
+/*
+ * arch/ppc/boot/common/mpc10x_common.c
+ * 
+ * A routine to find out how much memory the machine has.
+ *
+ * Based on:
+ * arch/ppc/kernel/mpc10x_common.c
+ *
+ * Author: Mark A. Greer
+ *         mgreer@mvista.com
+ *
+ * Copyright 2001-2002 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/pci.h>
+#include <asm/types.h>
+#include <asm/io.h>
+#include "mpc10x.h"
+
+/*
+ * *** WARNING - A BAT MUST be set to access the PCI config addr/data regs ***
+ */
+
+
+/*
+ * PCI config space macros, similar to indirect_xxx and early_xxx macros.
+ * We assume bus 0.
+ */
+#define MPC10X_CFG_read(val, addr, type, op)	*val = op((type)(addr))
+#define MPC10X_CFG_write(val, addr, type, op)	op((type *)(addr), (val))
+
+#define MPC10X_PCI_OP(rw, size, type, op, mask)			 	\
+static void								\
+mpc10x_##rw##_config_##size(unsigned int *cfg_addr, 			\
+		unsigned int *cfg_data, int devfn, int offset,		\
+		type val)						\
+{									\
+	out_be32(cfg_addr, 						\
+		 ((offset & 0xfc) << 24) | (devfn << 16)		\
+		 | (0 << 8) | 0x80);					\
+	MPC10X_CFG_##rw(val, cfg_data + (offset & mask), type, op);	\
+	return;    					 		\
+}
+
+MPC10X_PCI_OP(read, byte,  u8 *, in_8, 3)
+MPC10X_PCI_OP(read, dword, u32 *, in_le32, 0)
+
+/*
+ * Read the memory controller registers to determine the amount of memory in
+ * the system.  This assumes that the firmware has correctly set up the memory
+ * controller registers.
+ */
+unsigned long
+mpc10x_get_mem_size(unsigned int mem_map)
+{
+	unsigned int *config_addr, *config_data, val;
+	unsigned long start, end, total, offset;
+	int i;
+	unsigned char bank_enables;
+
+	switch (mem_map) {
+		case MPC10X_MEM_MAP_A:
+			config_addr = (unsigned int *)MPC10X_MAPA_CNFG_ADDR;
+			config_data = (unsigned int *)MPC10X_MAPA_CNFG_DATA;
+			break;
+		case MPC10X_MEM_MAP_B:
+			config_addr = (unsigned int *)MPC10X_MAPB_CNFG_ADDR;
+			config_data = (unsigned int *)MPC10X_MAPB_CNFG_DATA;
+			break;
+		default:
+			return 0;
+	}
+
+	mpc10x_read_config_byte(config_addr, config_data, PCI_DEVFN(0,0),
+			MPC10X_MCTLR_MEM_BANK_ENABLES, &bank_enables);
+
+	total = 0;
+
+	for (i = 0; i < 8; i++) {
+		if (bank_enables & (1 << i)) {
+			offset = MPC10X_MCTLR_MEM_START_1 + ((i > 3) ? 4 : 0);
+			mpc10x_read_config_dword(config_addr, config_data,
+					PCI_DEVFN(0,0), offset, &val);
+			start = (val >> ((i & 3) << 3)) & 0xff;
+
+			offset = MPC10X_MCTLR_EXT_MEM_START_1 + ((i>3) ? 4 : 0);
+			mpc10x_read_config_dword(config_addr, config_data,
+					PCI_DEVFN(0,0), offset, &val);
+			val = (val >> ((i & 3) << 3)) & 0x03;
+			start = (val << 28) | (start << 20);
+
+			offset = MPC10X_MCTLR_MEM_END_1 + ((i > 3) ? 4 : 0);
+			mpc10x_read_config_dword(config_addr, config_data,
+					PCI_DEVFN(0,0), offset, &val);
+			end = (val >> ((i & 3) << 3)) & 0xff;
+
+			offset = MPC10X_MCTLR_EXT_MEM_END_1 + ((i > 3) ? 4 : 0);
+			mpc10x_read_config_dword(config_addr, config_data,
+					PCI_DEVFN(0,0), offset, &val);
+			val = (val >> ((i & 3) << 3)) & 0x03;
+			end = (val << 28) | (end << 20) | 0xfffff;
+
+			total += (end - start + 1);
+		}
+	}
+
+	return total;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/common/ns16550.c linux-2.4.21-pre6/arch/ppc/boot/common/ns16550.c
--- linux-2.4.20/arch/ppc/boot/common/ns16550.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/common/ns16550.c	2003-03-26 23:49:34.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.ns16550.c 1.16 03/13/02 09:17:06 trini
- */
-/*
  * COM1 NS16550 support
  */
 
@@ -98,8 +95,3 @@
 {
 	return ((inb(com_port + (UART_LSR << shift)) & UART_LSR_DR) != 0);
 }
-
-void
-serial_close(unsigned long com_port)
-{
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/common/ofcommon.c linux-2.4.21-pre6/arch/ppc/boot/common/ofcommon.c
--- linux-2.4.20/arch/ppc/boot/common/ofcommon.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/common/ofcommon.c	2003-03-26 23:49:34.000000000 +0000
@@ -1,6 +1,4 @@
 /*
- * BK Id: SCCS/s.ofcommon.c 1.2 01/11/02 10:46:07 trini
- *
  * Copyright (C) Paul Mackerras 1997.
  *
  * This program is free software; you can redistribute it and/or
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/common/relocate.S linux-2.4.21-pre6/arch/ppc/boot/common/relocate.S
--- linux-2.4.20/arch/ppc/boot/common/relocate.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/common/relocate.S	2003-03-26 23:49:50.000000000 +0000
@@ -9,12 +9,10 @@
  *	   trini@mvista.com
  * Derived from arch/ppc/boot/prep/head.S (Cort Dougan, many others).
  *
- * Copyright 2001 MontaVista Software Inc.
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
+ * 2001 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
  */
 
 #include <linux/config.h>
@@ -191,7 +189,7 @@
 	mr	r4,r7		/* Program length */
 	mr	r5,r6		/* Checksum */
 	mr	r6,r11		/* Residual data */
-	bl	decompress_kernel
+	bl	load_kernel
 
 	/*
 	 * Make sure the kernel knows we don't have things set  in
@@ -201,10 +199,10 @@
 	li	r6,0
 
 	/*
-	 * Start at the begining.
+	 * Start at the beginning of real code (the first
+	 * three instructions are 'nop' since we 
+	 * sometimes overwrite them).
 	 */
-	li	r9,0x0000
-	mtlr	r9
-	blr
+	ba	0x000c
 
 	.comm	.stack,4096*2,4
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/common/serial_stub.c linux-2.4.21-pre6/arch/ppc/boot/common/serial_stub.c
--- linux-2.4.20/arch/ppc/boot/common/serial_stub.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/common/serial_stub.c	2003-03-26 23:49:24.000000000 +0000
@@ -0,0 +1,28 @@
+/*
+ * arch/ppc/boot/common/serial_stub.c
+ *
+ * This is a few stub routines to make the boot code cleaner looking when
+ * there is no serial port support doesn't need to be closed, for example.
+ *
+ * Author: Tom Rini <trini@mvista.com>
+ *
+ * 2003 (c) MontaVista, Software, Inc.  This file is licensed under the terms
+ * of the GNU General Public License version 2.  This program is licensed "as
+ * is" without any warranty of any kind, whether express or implied.
+ */
+
+void __attribute__ ((weak))
+serial_fixups(void)
+{
+}
+
+unsigned long __attribute__ ((weak))
+serial_init(int chan, void *ignored)
+{
+	return 0;
+}
+
+void __attribute__ ((weak))
+serial_close(unsigned long com_port)
+{
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/common/string.S linux-2.4.21-pre6/arch/ppc/boot/common/string.S
--- linux-2.4.20/arch/ppc/boot/common/string.S	2001-05-24 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/common/string.S	2003-03-26 23:49:49.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.string.S 1.8 05/18/01 06:20:29 patch
- */
-/*
  * String handling functions for PowerPC.
  *
  * Copyright (C) 1996 Paul Mackerras.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/common/util.S linux-2.4.21-pre6/arch/ppc/boot/common/util.S
--- linux-2.4.20/arch/ppc/boot/common/util.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/common/util.S	2003-03-26 23:49:07.000000000 +0000
@@ -14,12 +14,10 @@
  *	   trini@mvista.com
  * Derived from arch/ppc/boot/prep/head.S (Cort Dougan, many others).
  *
- * Copyright 2001 MontaVista Software Inc.
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
+ * 2001-2003 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
  */
 
 #include <asm/processor.h>
@@ -100,7 +98,7 @@
 	isync
 	mfspr	r8,L2CR
 	rlwinm	r8,r8,0,1,31
-	oris	r8,r8,0x0020
+	oris	r8,r8,L2CR_L2I@h
 	sync
 	isync
 	mtspr	L2CR,r8
@@ -108,11 +106,25 @@
 	isync
 
 	/* Wait for the invalidation to complete */
-1:	mfspr	r8,L2CR
-	rlwinm.	r9,r8,0,31,31
+	mfspr   r8,PVR
+	srwi    r8,r8,16
+	cmpli	cr0,r8,0x8000			/* 7450 */
+	cmpli	cr1,r8,0x8001			/* 7455 */
+	cmpli	cr2,r8,0x8002			/* 7457 */
+	cror	4*cr0+eq,4*cr0+eq,4*cr1+eq	/* Now test if any are true. */
+	cror	4*cr0+eq,4*cr0+eq,4*cr2+eq
+	bne     2f
+
+1:	mfspr	r8,L2CR		/* On 745x, poll L2I bit (bit 10) */
+	rlwinm.	r9,r8,0,10,10
 	bne	1b
+	b	3f
+
+2:      mfspr   r8,L2CR		/* On 75x & 74[01]0, poll L2IP bit (bit 31) */
+	rlwinm. r9,r8,0,31,31
+	bne     2b
 
-	rlwinm	r8,r8,0,11,9		/* Turn off L2I bit */
+3:	rlwinm	r8,r8,0,11,9	/* Turn off L2I bit */
 	sync
 	isync
 	mtspr	L2CR,r8
@@ -120,6 +132,33 @@
 	isync
 	blr
 
+	.globl	_setup_L3CR
+_setup_L3CR:
+	/* Invalidate/disable L3 cache */
+	sync
+	isync
+	mfspr	r8,L3CR
+	rlwinm	r8,r8,0,1,31
+	ori	r8,r8,L3CR_L3I@l
+	sync
+	isync
+	mtspr	L3CR,r8
+	sync
+	isync
+
+	/* Wait for the invalidation to complete */
+1:	mfspr	r8,L3CR
+	rlwinm.	r9,r8,0,21,21
+	bne	1b
+
+	rlwinm	r8,r8,0,22,20		/* Turn off L3I bit */
+	sync
+	isync
+	mtspr	L3CR,r8
+	sync
+	isync
+	blr
+
 
 /*
  * Delay for a number of microseconds
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/include/mpc10x.h linux-2.4.21-pre6/arch/ppc/boot/include/mpc10x.h
--- linux-2.4.20/arch/ppc/boot/include/mpc10x.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/include/mpc10x.h	2003-03-26 23:49:07.000000000 +0000
@@ -0,0 +1,67 @@
+/*
+ * arch/ppc/boot/include/mpc10.h
+ *
+ * Common defines for the Motorola SPS MPC106/8240/107 Host bridge/Mem
+ * ctrl/EPIC/etc.
+ *
+ * Author: Tom Rini <trini@mvista.com>
+ *
+ * This is a heavily stripped down version of:
+ * include/asm-ppc/mpc10x.h
+ *
+ * Author: Mark A. Greer
+ *         mgreer@mvista.com
+ *
+ * Copyright 2001-2002 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+#ifndef __BOOT_MPC10X_H__
+#define __BOOT_MPC10X_H__
+
+/*
+ * The values here don't completely map everything but should work in most
+ * cases.
+ *
+ * MAP A (PReP Map)
+ *   Processor: 0x80000000 - 0x807fffff -> PCI I/O: 0x00000000 - 0x007fffff
+ *   Processor: 0xc0000000 - 0xdfffffff -> PCI MEM: 0x00000000 - 0x1fffffff
+ *   PCI MEM:   0x80000000 -> Processor System Memory: 0x00000000
+ *   EUMB mapped to: ioremap_base - 0x00100000 (ioremap_base - 1 MB)
+ *
+ * MAP B (CHRP Map)
+ *   Processor: 0xfe000000 - 0xfebfffff -> PCI I/O: 0x00000000 - 0x00bfffff
+ *   Processor: 0x80000000 - 0xbfffffff -> PCI MEM: 0x80000000 - 0xbfffffff
+ *   PCI MEM:   0x00000000 -> Processor System Memory: 0x00000000
+ *   EUMB mapped to: ioremap_base - 0x00100000 (ioremap_base - 1 MB)
+ */
+
+/* Define the type of map to use */
+#define	MPC10X_MEM_MAP_A		1
+#define	MPC10X_MEM_MAP_B		2
+
+/* Map A (PReP Map) Defines */
+#define	MPC10X_MAPA_CNFG_ADDR		0x80000cf8
+#define	MPC10X_MAPA_CNFG_DATA		0x80000cfc
+
+/* Map B (CHRP Map) Defines */
+#define	MPC10X_MAPB_CNFG_ADDR		0xfec00000
+#define	MPC10X_MAPB_CNFG_DATA		0xfee00000
+
+/* Define offsets for the memory controller registers in the config space */
+#define MPC10X_MCTLR_MEM_START_1	0x80	/* Banks 0-3 */
+#define MPC10X_MCTLR_MEM_START_2	0x84	/* Banks 4-7 */
+#define MPC10X_MCTLR_EXT_MEM_START_1	0x88	/* Banks 0-3 */
+#define MPC10X_MCTLR_EXT_MEM_START_2	0x8c	/* Banks 4-7 */
+
+#define MPC10X_MCTLR_MEM_END_1		0x90	/* Banks 0-3 */
+#define MPC10X_MCTLR_MEM_END_2i		0x94	/* Banks 4-7 */
+#define MPC10X_MCTLR_EXT_MEM_END_1	0x98	/* Banks 0-3 */
+#define MPC10X_MCTLR_EXT_MEM_END_2	0x9c	/* Banks 4-7 */
+
+#define MPC10X_MCTLR_MEM_BANK_ENABLES	0xa0
+
+#endif	/* __BOOT_MPC10X_H__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/include/nonstdio.h linux-2.4.21-pre6/arch/ppc/boot/include/nonstdio.h
--- linux-2.4.20/arch/ppc/boot/include/nonstdio.h	2001-08-28 13:58:33.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/include/nonstdio.h	2003-03-26 23:49:29.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.nonstdio.h 1.9 07/25/01 18:13:07 trini
- */
-/*
  * Copyright (C) Paul Mackerras 1997.
  *
  * This program is free software; you can redistribute it and/or
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/include/rs6000.h linux-2.4.21-pre6/arch/ppc/boot/include/rs6000.h
--- linux-2.4.20/arch/ppc/boot/include/rs6000.h	2001-05-24 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/include/rs6000.h	2003-03-26 23:49:40.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.rs6000.h 1.7 05/18/01 15:17:23 cort
- */
 /* IBM RS/6000 "XCOFF" file definitions for BFD.
    Copyright (C) 1990, 1991 Free Software Foundation, Inc.
    FIXME: Can someone provide a transliteration of this name into ASCII?
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/include/zlib.h linux-2.4.21-pre6/arch/ppc/boot/include/zlib.h
--- linux-2.4.20/arch/ppc/boot/include/zlib.h	2001-05-24 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/include/zlib.h	2003-03-26 23:49:09.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.zlib.h 1.8 05/18/01 15:17:23 cort
- */
-/*
  * This file is derived from zlib.h and zconf.h from the zlib-0.95
  * distribution by Jean-loup Gailly and Mark Adler, with some additions
  * by Paul Mackerras to aid in implementing Deflate compression and
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/lib/Makefile linux-2.4.21-pre6/arch/ppc/boot/lib/Makefile
--- linux-2.4.20/arch/ppc/boot/lib/Makefile	2001-05-24 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/lib/Makefile	2003-03-26 23:49:20.000000000 +0000
@@ -2,8 +2,10 @@
 # Makefile for some libs needed by zImage.
 #
 
+USE_STANDARD_AS_RULE	:= true
+
 L_TARGET := zlib.a
 
-obj-y := zlib.o
+obj-y := zlib.o div64.o
 
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/lib/div64.S linux-2.4.21-pre6/arch/ppc/boot/lib/div64.S
--- linux-2.4.20/arch/ppc/boot/lib/div64.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/lib/div64.S	2003-03-26 23:49:25.000000000 +0000
@@ -0,0 +1,58 @@
+/*
+ * Divide a 64-bit unsigned number by a 32-bit unsigned number.
+ * This routine assumes that the top 32 bits of the dividend are
+ * non-zero to start with.
+ * On entry, r3 points to the dividend, which get overwritten with
+ * the 64-bit quotient, and r4 contains the divisor.
+ * On exit, r3 contains the remainder.
+ *
+ * Copyright (C) 2002 Paul Mackerras, IBM Corp.
+ *
+ * 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 <asm/ppc_asm.h>
+#include <asm/processor.h>
+
+_GLOBAL(__div64_32)
+	lwz	r5,0(r3)	# get the dividend into r5/r6
+	lwz	r6,4(r3)
+	cmplw	r5,r4
+	li	r7,0
+	li	r8,0
+	blt	1f
+	divwu	r7,r5,r4	# if dividend.hi >= divisor,
+	mullw	r0,r7,r4	# quotient.hi = dividend.hi / divisor
+	subf.	r5,r0,r5	# dividend.hi %= divisor
+	beq	3f
+1:	mr	r11,r5		# here dividend.hi != 0
+	andis.	r0,r5,0xc000
+	bne	2f
+	cntlzw	r0,r5		# we are shifting the dividend right
+	li	r10,-1		# to make it < 2^32, and shifting
+	srw	r10,r10,r0	# the divisor right the same amount,
+	add	r9,r4,r10	# rounding up (so the estimate cannot
+	andc	r11,r6,r10	# ever be too large, only too small)
+	andc	r9,r9,r10
+	or	r11,r5,r11
+	rotlw	r9,r9,r0
+	rotlw	r11,r11,r0
+	divwu	r11,r11,r9	# then we divide the shifted quantities
+2:	mullw	r10,r11,r4	# to get an estimate of the quotient,
+	mulhwu	r9,r11,r4	# multiply the estimate by the divisor,
+	subfc	r6,r10,r6	# take the product from the divisor,
+	add	r8,r8,r11	# and add the estimate to the accumulated
+	subfe.	r5,r9,r5	# quotient
+	bne	1b
+3:	cmplw	r6,r4
+	blt	4f
+	divwu	r0,r6,r4	# perform the remaining 32-bit division
+	mullw	r10,r0,r4	# and get the remainder
+	add	r8,r8,r0
+	subf	r6,r10,r6
+4:	stw	r7,0(r3)	# return the quotient in *r3
+	stw	r8,4(r3)
+	mr	r3,r6		# return the remainder in r3
+	blr
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/lib/zlib.c linux-2.4.21-pre6/arch/ppc/boot/lib/zlib.c
--- linux-2.4.20/arch/ppc/boot/lib/zlib.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/lib/zlib.c	2003-03-26 23:49:21.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.zlib.c 1.9 12/05/01 16:19:42 mporter
- */
-/*
  * This file is derived from various .h and .c files from the zlib-0.95
  * distribution by Jean-loup Gailly and Mark Adler, with some additions
  * by Paul Mackerras to aid in implementing Deflate compression and
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/pmac/Makefile linux-2.4.21-pre6/arch/ppc/boot/pmac/Makefile
--- linux-2.4.20/arch/ppc/boot/pmac/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/pmac/Makefile	2003-03-26 23:49:25.000000000 +0000
@@ -1,4 +1,3 @@
-# BK Id: SCCS/s.Makefile 1.19 01/16/02 11:08:07 trini
 #
 # Makefile for making XCOFF bootable images for booting on PowerMacs
 # using Open Firmware.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/pmac/chrpmain.c linux-2.4.21-pre6/arch/ppc/boot/pmac/chrpmain.c
--- linux-2.4.20/arch/ppc/boot/pmac/chrpmain.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/pmac/chrpmain.c	2003-03-26 23:48:57.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.chrpmain.c 1.18 01/11/02 10:46:07 trini
- */
-/*
  * Copyright (C) Paul Mackerras 1997.
  *
  * This program is free software; you can redistribute it and/or
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/pmac/coffmain.c linux-2.4.21-pre6/arch/ppc/boot/pmac/coffmain.c
--- linux-2.4.20/arch/ppc/boot/pmac/coffmain.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/pmac/coffmain.c	2003-03-26 23:49:40.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.coffmain.c 1.15 01/11/02 10:46:07 trini
- */
-/*
  * Copyright (C) Paul Mackerras 1997.
  *
  * This program is free software; you can redistribute it and/or
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/pmac/misc.S linux-2.4.21-pre6/arch/ppc/boot/pmac/misc.S
--- linux-2.4.20/arch/ppc/boot/pmac/misc.S	2001-05-24 22:02:07.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/pmac/misc.S	2003-03-26 23:49:40.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.misc.S 1.6 05/18/01 15:17:15 cort
- */
-/*
  * Copyright (C) Paul Mackerras 1997.
  *
  * This program is free software; you can redistribute it and/or
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/pmac/start.c linux-2.4.21-pre6/arch/ppc/boot/pmac/start.c
--- linux-2.4.20/arch/ppc/boot/pmac/start.c	2001-08-28 13:58:33.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/pmac/start.c	2003-03-26 23:49:25.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.start.c 1.10 07/25/01 18:13:07 trini
- */
-/*
  * Copyright (C) Paul Mackerras 1997.
  *
  * This program is free software; you can redistribute it and/or
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/prep/Makefile linux-2.4.21-pre6/arch/ppc/boot/prep/Makefile
--- linux-2.4.20/arch/ppc/boot/prep/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/prep/Makefile	2003-03-26 23:49:54.000000000 +0000
@@ -1,4 +1,3 @@
-# BK Id: SCCS/s.Makefile 1.30 01/26/02 12:27:41 trini
 #
 # arch/ppc/boot/Makefile
 #
@@ -25,7 +24,8 @@
 LD_ARGS				= -T ../ld.script -Ttext 0x00800000 -Bstatic
 obj-y				:= head.o ../simple/legacy.o misc.o of1275.o \
 					../common/util.o ../common/string.o \
-					../common/misc-common.o
+					../common/misc-common.o \
+					../common/serial_stub.o
 OBJCOPY_ARGS			= -O elf32-powerpc
 LIBS 				= ../lib/zlib.a
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/prep/head.S linux-2.4.21-pre6/arch/ppc/boot/prep/head.S
--- linux-2.4.20/arch/ppc/boot/prep/head.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/prep/head.S	2003-03-26 23:49:08.000000000 +0000
@@ -1,7 +1,3 @@
-/*
- * BK Id: SCCS/s.head.S 1.13 01/11/02 10:46:07 trini
- */
-
 #include <asm/ppc_asm.h>
 #include <asm/processor.h>
 #include <asm/cache.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/prep/iso_font.h linux-2.4.21-pre6/arch/ppc/boot/prep/iso_font.h
--- linux-2.4.20/arch/ppc/boot/prep/iso_font.h	2001-05-24 22:02:07.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/prep/iso_font.h	2003-03-26 23:49:35.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.iso_font.h 1.6 05/18/01 15:16:42 cort
- */
 static const unsigned char font[] = {
 /* 0x00 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 /* 0x01 */ 0x00,0x00,0x7E,0x81,0xA5,0x81,0x81,0xBD,0x99,0x81,0x81,0x7E,0x00,0x00,0x00,0x00,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/prep/kbd.c linux-2.4.21-pre6/arch/ppc/boot/prep/kbd.c
--- linux-2.4.20/arch/ppc/boot/prep/kbd.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/prep/kbd.c	2003-03-26 23:48:59.000000000 +0000
@@ -1,7 +1,3 @@
-/*
- * BK Id: SCCS/s.kbd.c 1.9 01/11/02 10:46:07 trini
- */
-
 #include <linux/keyboard.h>
 
 #include "defkeymap.c"	/* yeah I know it's bad -- Cort */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/prep/misc.c linux-2.4.21-pre6/arch/ppc/boot/prep/misc.c
--- linux-2.4.20/arch/ppc/boot/prep/misc.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/prep/misc.c	2003-03-26 23:49:07.000000000 +0000
@@ -1,6 +1,4 @@
 /*
- * BK Id: SCCS/s.misc.c 1.25 01/26/02 12:27:41 trini
- *
  * arch/ppc/boot/prep/misc.c
  *
  * Adapted for PowerPC by Gary Thomas
@@ -23,6 +21,16 @@
 #include "nonstdio.h"
 #include "zlib.h"
 
+#ifdef CONFIG_CMDLINE
+#define CMDLINE CONFIG_CMDLINE
+#else
+#define CMDLINE ""
+#endif
+
+#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_VGA_CONSOLE)
+#define INTERACTIVE_CONSOLE	1
+#endif
+
 /*
  * Please send me load/board info and such data for hardware not
  * listed here so I can keep track since things are getting tricky
@@ -38,11 +46,6 @@
 extern char __ramdisk_begin, __ramdisk_end;
 extern char _end[];
 
-#ifdef CONFIG_CMDLINE
-#define CMDLINE CONFIG_CMDLINE
-#else
-#define CMDLINE ""
-#endif
 char cmd_preset[] = CMDLINE;
 char cmd_buf[256];
 char *cmd_line = cmd_buf;
@@ -56,9 +59,7 @@
 char *zimage_start;
 int zimage_size;
 
-#if defined(CONFIG_SERIAL_CONSOLE)
 unsigned long com_port;
-#endif /* CONFIG_SERIAL_CONSOLE */
 #ifdef CONFIG_VGA_CONSOLE
 char *vidmem = (char *)0xC00B8000;
 int lines = 25, cols = 80;
@@ -122,9 +123,12 @@
 decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum,
 		  RESIDUAL *residual, void *OFW_interface)
 {
+#ifdef INTERACTIVE_CONSOLE
 	int timer = 0;
+	char ch;
+#endif
 	extern unsigned long start;
-	char *cp, ch;
+	char *cp;
 	unsigned long TotalMemory;
 	int dev_handle;
 	int mem_info[2];
@@ -135,9 +139,7 @@
 	unsigned int pci_viddid, pci_did, tulip_pci_base, tulip_base;
 
 	serial_fixups();
-#if defined(CONFIG_SERIAL_CONSOLE)
 	com_port = serial_init(0, NULL);
-#endif /* CONFIG_SERIAL_CONSOLE */
 #if defined(CONFIG_VGA_CONSOLE)
 	vga_init((unsigned char *)0xC0000000);
 #endif /* CONFIG_VGA_CONSOLE */
@@ -304,6 +306,11 @@
 	memcpy (cmd_line, cmd_preset, sizeof(cmd_preset));
 	while ( *cp )
 		putc(*cp++);
+#ifdef INTERACTIVE_CONSOLE
+	/*
+	 * If they have a console, allow them to edit the command line.
+	 * Otherwise, don't bother wasting the five seconds.
+	 */
 	while (timer++ < 5*1000) {
 		if (tstc()) {
 			while ((ch = getc()) != '\n' && ch != '\r') {
@@ -328,6 +335,7 @@
 		}
 		udelay(1000);  /* 1 msec */
 	}
+#endif
 	*cp = 0;
 	puts("\nUncompressing Linux...");
 
@@ -343,9 +351,31 @@
 
 	{
 		struct bi_record *rec;
-		
-		rec = (struct bi_record *)_ALIGN((unsigned long)(zimage_size) +
+		unsigned long initrd_loc;
+		unsigned long rec_loc = _ALIGN((unsigned long)(zimage_size) +
 				(1 << 20) - 1, (1 << 20));
+		
+		rec = (struct bi_record *)rec_loc;
+
+		/* We need to make sure that the initrd and bi_recs do not
+		 * overlap. */
+		if ( initrd_size ) {
+			initrd_loc = (unsigned long)(&__ramdisk_begin);
+			/* If the bi_recs are in the middle of the current
+			 * initrd, move the initrd to the next MB
+			 * boundary. */
+			if ((rec_loc > initrd_loc) &&
+					((initrd_loc + initrd_size)
+					 > rec_loc)) {
+				initrd_loc = _ALIGN((unsigned long)(zimage_size)
+						+ (2 << 20) - 1, (2 << 20));
+			 	memmove((void *)initrd_loc, &__ramdisk_begin,
+					 initrd_size);
+		         	puts("initrd moved:  "); puthex(initrd_loc);
+			 	puts(" "); puthex(initrd_loc + initrd_size);
+			 	puts("\n");
+			}
+		}
 
 		rec->tag = BI_FIRST;
 		rec->size = sizeof(struct bi_record);
@@ -370,7 +400,7 @@
 
 		if ( initrd_size ) {
 			rec->tag = BI_INITRD;
-			rec->data[0] = (unsigned long)(&__ramdisk_begin);
+			rec->data[0] = initrd_loc;
 			rec->data[1] = initrd_size;
 			rec->size = sizeof(struct bi_record) + 2 *
 				sizeof(unsigned long);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/prep/of1275.c linux-2.4.21-pre6/arch/ppc/boot/prep/of1275.c
--- linux-2.4.20/arch/ppc/boot/prep/of1275.c	2001-05-24 22:02:07.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/prep/of1275.c	2003-03-26 23:49:34.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.of1275.c 1.6 05/18/01 15:16:42 cort
- */
 /* Open Firmware Client Interface */
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/prep/of1275.h linux-2.4.21-pre6/arch/ppc/boot/prep/of1275.h
--- linux-2.4.20/arch/ppc/boot/prep/of1275.h	2001-05-24 22:02:07.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/prep/of1275.h	2003-03-26 23:49:20.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.of1275.h 1.6 05/18/01 15:16:42 cort
- */
 /* 6.3.2.1 Client interface */
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/prep/vreset.c linux-2.4.21-pre6/arch/ppc/boot/prep/vreset.c
--- linux-2.4.20/arch/ppc/boot/prep/vreset.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/prep/vreset.c	2003-03-26 23:48:57.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.vreset.c 1.13 01/11/02 10:46:08 trini
- */
-/*
  * vreset.c
  *
  * Initialize the VGA control registers to 80x25 text mode.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/simple/Makefile linux-2.4.21-pre6/arch/ppc/boot/simple/Makefile
--- linux-2.4.20/arch/ppc/boot/simple/Makefile	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/simple/Makefile	2003-03-26 23:48:58.000000000 +0000
@@ -3,7 +3,10 @@
 #
 # Author: Tom Rini <trini@mvista.com>
 #
-# Copyright 2001-2002 MontaVista Software Inc.
+# 2001-2002 (c) MontaVista, Software, Inc.  This file is licensed under
+# the terms of the GNU General Public License version 2.  This program
+# is licensed "as is" without any warranty of any kind, whether express
+# or implied.
 #
 # Notes:
 # (1) For machine targets which produce more than one image, define
@@ -13,11 +16,6 @@
 # the machine name you want in the image, and you can optionally set
 # ENTRYPOINT which the image should be loaded at.  The optimal setting
 # for ENTRYPOINT is the link address.
-#
-# 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.
 
 USE_STANDARD_AS_RULE		:= true
 
@@ -33,19 +31,25 @@
 ifeq ($(CONFIG_GEMINI),y)
 ZIMAGE				:= zImage-SMON
 ZIMAGEINITRD			:= zImage.initrd-SMON
-EXTRA				:= direct.o
 TFTPIMAGE			:= /tftpboot/zImage.gemini
 endif
+ifeq ($(CONFIG_LOPEC),y)
+ZIMAGE				:= zImage-PPLUS
+ZIMAGEINITRD			:= zImage.initrd-PPLUS
+EXTRA				:= ../common/mpc10x_memory.o
+TFTPIMAGE			:= /tftpboot/zImage.pplus
+ZNETBOOT			:= zImage.pplus
+ZNETBOOTRD			:= zImage.initrd.pplus
+endif
+
 ifeq ($(CONFIG_PAL4),y)
 ZIMAGE				:= zImage-PAL4
 ZIMAGEINITRD			:= zImage.initrd-PAL4
-EXTRA				:= direct.o
 TFTPIMAGE			:= /tftpboot/zImage.pal4
 endif
 ifeq ($(CONFIG_SPRUCE),y)
 ZIMAGE				:= zImage-TREE
 ZIMAGEINITRD			:= zImage.initrd-TREE
-EXTRA				:= direct.o
 ENTRYPOINT			:= 0x00800000
 MISC				:= misc-spruce.o
 END				:= spruce
@@ -68,7 +72,8 @@
 # head.o and ../common/relocate.o must be at the start.
 obj-y				:= head.o ../common/relocate.o $(EXTRA) \
 				$(MISC) ../common/misc-common.o \
-				../common/string.o ../common/util.o
+				../common/string.o ../common/util.o \
+				../common/serial_stub.o
 obj-$(CONFIG_4xx)		+= embed_config.o
 obj-$(CONFIG_8xx)		+= embed_config.o
 obj-$(CONFIG_8260)		+= embed_config.o
@@ -86,6 +91,7 @@
 LIBS				:= ../lib/zlib.a
 
 # Tools
+MKBUGBOOT			:= ../utils/mkbugboot
 MKPREP				:= ../utils/mkprep
 MKTREE				:= ../utils/mktree
 
@@ -142,6 +148,14 @@
 zImage.initrd-PAL4: zvmlinux.initrd
 	cp zvmlinux.initrd ../images/zImage.initrd.pal4
 
+zImage-PPLUS: zvmlinux $(MKPREP) $(MKBUGBOOT)
+	$(MKPREP) -pbp zvmlinux ../images/zImage.pplus
+	$(MKBUGBOOT) zvmlinux ../images/zImage.bugboot
+
+zImage.initrd-PPLUS: zvmlinux.initrd $(MKPREP) $(MKBUGBOOT)
+	$(MKPREP) -pbp zvmlinux.initrd ../images/zImage.initrd.pplus
+	$(MKBUGBOOT) zvmlinux.initrd ../images/zImage.initrd.bugboot
+
 zImage-SMON: zvmlinux
 	dd if=zvmlinux of=../images/zImage.gemini skip=64 bs=1k
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/simple/direct.S linux-2.4.21-pre6/arch/ppc/boot/simple/direct.S
--- linux-2.4.20/arch/ppc/boot/simple/direct.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/simple/direct.S	1970-01-01 00:00:00.000000000 +0000
@@ -1,15 +0,0 @@
-/*
- * arch/ppc/boot/simple/direct.S
- *
- * Author: Tom Rini <trini@mvista.com>
- *
- * This is an empty function for machines which use SERIAL_IO_MEM
- * and don't need ISA_io set to anything but 0, or perform any other
- * serial fixups.
- */
-
-	.text
-
-	.globl serial_fixups
-serial_fixups:
-	blr
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/simple/embed_config.c linux-2.4.21-pre6/arch/ppc/boot/simple/embed_config.c
--- linux-2.4.20/arch/ppc/boot/simple/embed_config.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/simple/embed_config.c	2003-03-26 23:49:53.000000000 +0000
@@ -1,7 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
-
 /* Board specific functions for those embedded 8xx boards that do
  * not have boot monitor support for board information.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/simple/head.S linux-2.4.21-pre6/arch/ppc/boot/simple/head.S
--- linux-2.4.20/arch/ppc/boot/simple/head.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/simple/head.S	2003-03-26 23:49:25.000000000 +0000
@@ -7,12 +7,10 @@
  *	   trini@mvista.com
  * Derived from arch/ppc/boot/prep/head.S (Cort Dougan, many others).
  *
- * Copyright 2001 MontaVista Software Inc.
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
+ * 2001-2003 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
  */
 
 #include <linux/config.h>
@@ -75,6 +73,17 @@
 	bl	disable_6xx_l1cache
 #if defined(CONFIG_FORCE) || defined(CONFIG_K2) || defined(CONFIG_EV64260)
 	bl	_setup_L2CR
+
+	/* If 745x, turn off L3CR as well */
+	mfspr	r8,PVR
+	srwi	r8,r8,16
+
+	cmpli	cr0,r8,0x8000			/* 7450 */
+	cmpli	cr1,r8,0x8001			/* 7455 */
+	cmpli	cr2,r8,0x8002			/* 7457 */
+	cror	4*cr0+eq,4*cr0+eq,4*cr1+eq	/* Now test if any are true. */
+	cror	4*cr0+eq,4*cr0+eq,4*cr2+eq
+	beql	_setup_L3CR
 #endif
 #endif
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/simple/iic.c linux-2.4.21-pre6/arch/ppc/boot/simple/iic.c
--- linux-2.4.20/arch/ppc/boot/simple/iic.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/simple/iic.c	2003-03-26 23:49:09.000000000 +0000
@@ -1,7 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
-
 /* Minimal support functions to read configuration from IIC EEPROMS
  * on MPC8xx boards.  Originally written for RPGC RPX-Lite.
  * Dan Malek (dmalek@jlc.net).
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/simple/m8260_tty.c linux-2.4.21-pre6/arch/ppc/boot/simple/m8260_tty.c
--- linux-2.4.20/arch/ppc/boot/simple/m8260_tty.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/simple/m8260_tty.c	2003-03-26 23:49:50.000000000 +0000
@@ -1,8 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
-
-
 /* Minimal serial functions needed to send messages out the serial
  * port on SMC1.
  */
@@ -316,8 +311,3 @@
 
 	return(!(rbdf->cbd_sc & BD_SC_EMPTY));
 }
-
-void
-serial_close(unsigned long com_port)
-{
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/simple/m8xx_tty.c linux-2.4.21-pre6/arch/ppc/boot/simple/m8xx_tty.c
--- linux-2.4.20/arch/ppc/boot/simple/m8xx_tty.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/simple/m8xx_tty.c	2003-03-26 23:49:29.000000000 +0000
@@ -1,8 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
-
-
 /* Minimal serial functions needed to send messages out the serial
  * port on the MBX console.
  *
@@ -293,8 +288,3 @@
 
 	return(!(rbdf->cbd_sc & BD_SC_EMPTY));
 }
-
-void
-serial_close(unsigned long com_port)
-{
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/simple/misc-embedded.c linux-2.4.21-pre6/arch/ppc/boot/simple/misc-embedded.c
--- linux-2.4.20/arch/ppc/boot/simple/misc-embedded.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/simple/misc-embedded.c	2003-03-26 23:49:30.000000000 +0000
@@ -1,6 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- *
  * Originally adapted by Gary Thomas.  Much additional work by
  * Cort Dougan <cort@fsmlabs.com>.  On top of that still more work by
  * Dan Malek <dmalek@jlc.net>.
@@ -28,6 +26,10 @@
 #include "nonstdio.h"
 #include "zlib.h"
 
+#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_VGA_CONSOLE)
+#define INTERACTIVE_CONSOLE	1
+#endif
+
 /* The linker tells us where the image is. */
 extern char __image_begin, __image_end;
 extern char __ramdisk_begin, __ramdisk_end;
@@ -77,19 +79,22 @@
 extern void embed_config(bd_t **bp);
 
 unsigned long
-decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, bd_t *bp)
+load_kernel(unsigned long load_addr, int num_words, unsigned long cksum,
+		bd_t *bp)
 {
-	char *cp, ch;
-	int timer = 0, zimage_size;
+#ifdef INTERACTIVE_CONSOLE
+	int timer = 0;
+	char ch;
+#endif
+	char *cp;
+	int zimage_size;
 	unsigned long initrd_size;
 
 	/* First, capture the embedded board information.  Then
 	 * initialize the serial console port.
 	 */
 	embed_config(&bp);
-#ifdef CONFIG_SERIAL_CONSOLE
 	com_port = serial_init(0, bp);
-#endif
 
 	/* copy board data */
 	if (bp)
@@ -172,7 +177,7 @@
 #endif
 	while ( *cp )
 		putc(*cp++);
-#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_VGA_CONSOLE)
+#ifdef INTERACTIVE_CONSOLE
 	/*
 	 * If they have a console, allow them to edit the command line.
 	 * Otherwise, don't bother wasting the five seconds.
@@ -209,9 +214,30 @@
 	puts("done.\n");
 	{
 		struct bi_record *rec;
+		unsigned long initrd_loc;
+		unsigned long rec_loc = _ALIGN((unsigned long)(zimage_size) +
+				(1 << 20) - 1, (1 << 20));
+		rec = (struct bi_record *)rec_loc;
 
-		rec = (struct bi_record *)_ALIGN((unsigned long)zimage_size +
-				(1 << 20) - 1,(1 << 20));
+		/* We need to make sure that the initrd and bi_recs do not
+		 * overlap. */
+		if ( initrd_size ) {
+			initrd_loc = (unsigned long)(&__ramdisk_begin);
+			/* If the bi_recs are in the middle of the current
+			 * initrd, move the initrd to the next MB
+			 * boundary. */
+			if ((rec_loc > initrd_loc) &&
+					((initrd_loc + initrd_size)
+					 > rec_loc)) {
+				initrd_loc = _ALIGN((unsigned long)(zimage_size)
+						+ (2 << 20) - 1, (2 << 20));
+			 	memmove((void *)initrd_loc, &__ramdisk_begin,
+					 initrd_size);
+		         	puts("initrd moved:  "); puthex(initrd_loc);
+			 	puts(" "); puthex(initrd_loc + initrd_size);
+			 	puts("\n");
+			}
+		}
 
 		rec->tag = BI_FIRST;
 		rec->size = sizeof(struct bi_record);
@@ -224,7 +250,7 @@
 
 		if ( initrd_size ) {
 			rec->tag = BI_INITRD;
-			rec->data[0] = (unsigned long)(&__ramdisk_begin);
+			rec->data[0] = initrd_loc;
 			rec->data[1] = initrd_size;
 			rec->size = sizeof(struct bi_record) + 2 *
 				sizeof(unsigned long);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/simple/misc-spruce.c linux-2.4.21-pre6/arch/ppc/boot/simple/misc-spruce.c
--- linux-2.4.20/arch/ppc/boot/simple/misc-spruce.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/simple/misc-spruce.c	2003-03-26 23:49:34.000000000 +0000
@@ -8,27 +8,10 @@
  *
  * Derived from arch/ppc/boot/prep/misc.c
  *
- * Copyright 2000-2001 MontaVista Software Inc.
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- *
- * THIS  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.
- *
- * 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.
+ * 2000-2001 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
  */
 
 #include <linux/types.h>
@@ -43,6 +26,16 @@
 
 #include "zlib.h"
 
+#ifdef CONFIG_CMDLINE
+#define CMDLINE CONFIG_CMDLINE
+#else
+#define CMDLINE ""
+#endif
+
+#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_VGA_CONSOLE)
+#define INTERACTIVE_CONSOLE	1
+#endif
+
 /* Define some important locations of the Spruce. */
 #define SPRUCE_PCI_CONFIG_ADDR	0xfec00000
 #define SPRUCE_PCI_CONFIG_DATA	0xfec00004
@@ -58,11 +51,6 @@
 extern char __ramdisk_begin, __ramdisk_end;
 extern char _end[];
 
-#ifdef CONFIG_CMDLINE
-#define CMDLINE CONFIG_CMDLINE
-#else
-#define CMDLINE ""
-#endif
 char cmd_preset[] = CMDLINE;
 char cmd_buf[256];
 char *cmd_line = cmd_buf;
@@ -164,11 +152,13 @@
 #define MEM_B2EA	0x60
 
 unsigned long
-decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum)
+load_kernel(unsigned long load_addr, int num_words, unsigned long cksum)
 {
+#ifdef INTERACTIVE_CONSOLE
 	int timer = 0;
-	char *cp, ch;
-
+	char ch;
+#endif
+	char *cp;
 	int loop;
 	int csr0;
 	int csr_id;
@@ -189,10 +179,8 @@
 	unsigned char header_type;
 	unsigned int bar0;
 
-#ifdef CONFIG_SERIAL_CONSOLE
 	/* Initialize the serial console port */
 	com_port = serial_init(0, NULL);
-#endif
 
 	/*
 	 * Gah, these firmware guys need to learn that hardware
@@ -367,7 +355,13 @@
 	puts("\nLinux/PPC load: ");
 	cp = cmd_line;
 	memcpy (cmd_line, cmd_preset, sizeof(cmd_preset));
-	while ( *cp ) putc(*cp++);
+	while ( *cp )
+		putc(*cp++);
+#ifdef INTERACTIVE_CONSOLE
+	/*
+	 * If they have a console, allow them to edit the command line.
+	 * Otherwise, don't bother wasting the five seconds.
+	 */
 	while (timer++ < 5*1000) {
 		if (tstc()) {
 			while ((ch = getc()) != '\n' && ch != '\r') {
@@ -385,6 +379,7 @@
 		}
 		udelay(1000);  /* 1 msec */
 	}
+#endif
 	*cp = 0;
 	puts("\n");
 
@@ -396,9 +391,30 @@
 
 	{
 		struct bi_record *rec;
-
-		rec = (struct bi_record *)_ALIGN((ulong)zimage_size +
-							(1<<20)-1,(1<<20));
+		unsigned long initrd_loc;
+		unsigned long rec_loc = _ALIGN((unsigned long)(zimage_size) +
+				(1 << 20) - 1, (1 << 20));
+		rec = (struct bi_record *)rec_loc;
+  
+		/* We need to make sure that the initrd and bi_recs do not
+		 * overlap. */
+		if ( initrd_size ) {
+			initrd_loc = (unsigned long)(&__ramdisk_begin);
+			/* If the bi_recs are in the middle of the current
+			 * initrd, move the initrd to the next MB
+			 * boundary. */
+			if ((rec_loc > initrd_loc) &&
+					((initrd_loc + initrd_size)
+					 > rec_loc)) {
+				initrd_loc = _ALIGN((unsigned long)(zimage_size)
+						+ (2 << 20) - 1, (2 << 20));
+			 	memmove((void *)initrd_loc, &__ramdisk_begin,
+					 initrd_size);
+		         	puts("initrd moved:  "); puthex(initrd_loc);
+			 	puts(" "); puthex(initrd_loc + initrd_size);
+			 	puts("\n");
+			}
+		}
 
 		rec->tag = BI_FIRST;
         	rec->size = sizeof(struct bi_record);
@@ -421,7 +437,7 @@
 
 		if ( initrd_size ) {
 			rec->tag = BI_INITRD;
-			rec->data[0] = (unsigned long)(&__ramdisk_begin);
+			rec->data[0] = initrd_loc;
 			rec->data[1] = initrd_size;
 			rec->size = sizeof(struct bi_record) + 2 *
 				sizeof(unsigned long);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/utils/Makefile linux-2.4.21-pre6/arch/ppc/boot/utils/Makefile
--- linux-2.4.20/arch/ppc/boot/utils/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/utils/Makefile	2003-03-26 23:49:24.000000000 +0000
@@ -10,7 +10,7 @@
 all: dummy
 
 # Simple programs with 1 file and no extra CFLAGS
-UTILS = addnote hack-coff mkprep mknote mktree
+UTILS = addnote hack-coff mkbugboot mkprep mknote mktree
 
 $(UTILS):
 	$(HOSTCC) $(HOSTCFLAGS) -o $@ $@.c
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/utils/addnote.c linux-2.4.21-pre6/arch/ppc/boot/utils/addnote.c
--- linux-2.4.20/arch/ppc/boot/utils/addnote.c	2001-05-24 22:02:07.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/utils/addnote.c	2003-03-26 23:49:55.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.addnote.c 1.7 05/18/01 15:17:23 cort
- */
-/*
  * Program to hack in a PT_NOTE program header entry in an ELF file.
  * This is needed for OF on RS/6000s to load an image correctly.
  * Note that OF needs a program header entry for the note, not an
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/utils/hack-coff.c linux-2.4.21-pre6/arch/ppc/boot/utils/hack-coff.c
--- linux-2.4.20/arch/ppc/boot/utils/hack-coff.c	2001-05-24 22:02:07.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/utils/hack-coff.c	2003-03-26 23:49:19.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.hack-coff.c 1.8 05/18/01 06:20:29 patch
- */
-/*
  * hack-coff.c - hack the header of an xcoff file to fill in
  * a few fields needed by the Open Firmware xcoff loader on
  * Power Macs but not initialized by objcopy.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/utils/mkbugboot.c linux-2.4.21-pre6/arch/ppc/boot/utils/mkbugboot.c
--- linux-2.4.20/arch/ppc/boot/utils/mkbugboot.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/utils/mkbugboot.c	2003-03-26 23:49:55.000000000 +0000
@@ -0,0 +1,191 @@
+/*
+ * arch/ppc/pp3boot/mkbugboot.c
+ * 
+ * Makes a Motorola PPCBUG ROM bootable image which can be flashed 
+ * into one of the FLASH banks on a Motorola PowerPlus board. 
+ *
+ * Author: Matt Porter <mporter@mvista.com>
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#define ELF_HEADER_SIZE	65536
+
+#include <unistd.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#ifdef __i386__
+#define cpu_to_be32(x) le32_to_cpu(x)
+#define cpu_to_be16(x) le16_to_cpu(x)
+#else
+#define cpu_to_be32(x) (x)
+#define cpu_to_be16(x) (x)
+#endif
+
+#define cpu_to_le32(x) le32_to_cpu((x))
+unsigned long le32_to_cpu(unsigned long x)
+{
+     	return (((x & 0x000000ffU) << 24) |
+		((x & 0x0000ff00U) <<  8) |
+		((x & 0x00ff0000U) >>  8) |
+		((x & 0xff000000U) >> 24));
+}
+
+#define cpu_to_le16(x) le16_to_cpu((x))
+unsigned short le16_to_cpu(unsigned short x)
+{
+	return (((x & 0x00ff) << 8) |
+		((x & 0xff00) >> 8));
+}
+
+/* size of read buffer */
+#define SIZE 0x1000
+
+#ifndef __sun__
+/* typedef long int32_t; */
+typedef unsigned long uint32_t;
+typedef unsigned short uint16_t;
+typedef unsigned char uint8_t;
+#endif
+
+/* PPCBUG ROM boot header */
+typedef struct bug_boot_header {
+  uint8_t	magic_word[4];		/* "BOOT" */
+  uint32_t	entry_offset;		/* Offset from top of header to code */
+  uint32_t	routine_length;		/* Length of code */
+  uint8_t	routine_name[8];	/* Name of the boot code */
+} bug_boot_header_t;
+
+#define HEADER_SIZE	sizeof(bug_boot_header_t)
+
+uint32_t copy_image(int32_t in_fd, int32_t out_fd)
+{
+  uint8_t buf[SIZE];
+  int n;
+  uint32_t image_size = 0;
+  uint8_t zero = 0;
+
+  lseek(in_fd, ELF_HEADER_SIZE, SEEK_SET);
+
+  /* Copy an image while recording its size */
+  while ( (n = read(in_fd, buf, SIZE)) > 0 )
+    {
+    image_size = image_size + n;
+    write(out_fd, buf, n);
+    }
+
+  /* BUG romboot requires that our size is divisible by 2 */
+  /* align image to 2 byte boundary */
+  if (image_size % 2)
+    {
+    image_size++;
+    write(out_fd, &zero, 1);
+    }
+
+  return image_size;
+}
+
+void write_bugboot_header(int32_t out_fd, uint32_t boot_size)
+{
+  uint8_t header_block[HEADER_SIZE];
+  bug_boot_header_t *bbh = (bug_boot_header_t *)&header_block[0];
+  
+  memset(header_block, 0, HEADER_SIZE);
+
+  /* Fill in the PPCBUG ROM boot header */
+  strncpy(bbh->magic_word, "BOOT", 4);		/* PPCBUG magic word */
+  bbh->entry_offset = cpu_to_be32(HEADER_SIZE);	/* Entry address */
+  bbh->routine_length= cpu_to_be32(HEADER_SIZE+boot_size+2);	/* Routine length */
+  strncpy(bbh->routine_name, "LINUXROM", 8);		/* Routine name   */
+
+  /* Output the header and bootloader to the file */
+  write(out_fd, header_block, HEADER_SIZE);
+}
+
+uint16_t calc_checksum(int32_t bug_fd)
+{
+  uint32_t checksum_var = 0;
+  uint8_t buf[2];
+  int n;
+
+  /* Checksum loop */
+  while ( (n = read(bug_fd, buf, 2) ) )
+  {
+    checksum_var = checksum_var + *(uint16_t *)buf;
+
+    /* If we carry out, mask it and add one to the checksum */
+    if (checksum_var >> 16)
+      checksum_var = (checksum_var & 0x0000ffff) + 1;
+  }
+
+  return checksum_var;
+}
+
+int main(int argc, char *argv[])
+{
+  int32_t image_fd, bugboot_fd;
+  int argptr = 1;
+  uint32_t kernel_size = 0;
+  uint16_t checksum = 0;
+  uint8_t bugbootname[256];
+
+  if ( (argc != 3) )
+  {
+    fprintf(stderr, "usage: %s <kernel_image> <bugboot>\n",argv[0]);
+    exit(-1);
+  }
+
+  /* Get file args */
+  
+  /* kernel image file */
+    if ((image_fd = open( argv[argptr] , 0)) < 0)
+      exit(-1);
+  argptr++;
+
+  /* bugboot file */
+  if ( !strcmp( argv[argptr], "-" ) )
+    bugboot_fd = 1;			/* stdout */
+  else
+    if ((bugboot_fd = creat( argv[argptr] , 0755)) < 0)
+      exit(-1);
+    else
+      strcpy(bugbootname, argv[argptr]);
+  argptr++;
+
+  /* Set file position after ROM header block where zImage will be written */
+  lseek(bugboot_fd, HEADER_SIZE, SEEK_SET);
+
+  /* Copy kernel image into bugboot image */
+  kernel_size = copy_image(image_fd, bugboot_fd);
+  close(image_fd);
+
+  /* Set file position to beginning where header/romboot will be written */
+  lseek(bugboot_fd, 0, SEEK_SET);
+
+  /* Write out BUG header/romboot */
+  write_bugboot_header(bugboot_fd, kernel_size);
+
+  /* Close bugboot file */
+  close(bugboot_fd);
+
+  /* Reopen it as read/write */
+  bugboot_fd = open(bugbootname, O_RDWR);
+
+  /* Calculate checksum */
+  checksum = calc_checksum(bugboot_fd);  
+
+  /* Write out the calculated checksum */
+  write(bugboot_fd, &checksum, 2);
+
+  return 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/utils/mknote.c linux-2.4.21-pre6/arch/ppc/boot/utils/mknote.c
--- linux-2.4.20/arch/ppc/boot/utils/mknote.c	2001-05-24 22:02:07.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/utils/mknote.c	2003-03-26 23:49:55.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.mknote.c 1.7 05/18/01 15:17:23 cort
- */
-/*
  * Copyright (C) Cort Dougan 1999.
  *
  * This program is free software; you can redistribute it and/or
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/utils/mkprep.c linux-2.4.21-pre6/arch/ppc/boot/utils/mkprep.c
--- linux-2.4.20/arch/ppc/boot/utils/mkprep.c	2001-05-24 22:02:07.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/utils/mkprep.c	2003-03-26 23:49:50.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.mkprep.c 1.7 05/18/01 06:20:29 patch
- */
-/*
  * Makes a prep bootable image which can be dd'd onto
  * a disk device to make a bootdisk.  Will take
  * as input a elf executable, strip off the header
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/boot/utils/mktree.c linux-2.4.21-pre6/arch/ppc/boot/utils/mktree.c
--- linux-2.4.20/arch/ppc/boot/utils/mktree.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/boot/utils/mktree.c	2003-03-26 23:49:08.000000000 +0000
@@ -1,6 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- * 
  * Makes a tree bootable image for IBM Evaluation boards.
  * Basically, just take a zImage, skip the ELF header, and stuff
  * a 32 byte header on the front.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/config.in linux-2.4.21-pre6/arch/ppc/config.in
--- linux-2.4.20/arch/ppc/config.in	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/config.in	2003-03-26 23:49:40.000000000 +0000
@@ -1,4 +1,3 @@
-# BK Id: %F% %I% %G% %U% %#%
 #
 # For a description of the syntax of this configuration file,
 # see Documentation/kbuild/config-language.txt.
@@ -58,9 +57,12 @@
 fi
 
 if [ "$CONFIG_4xx" = "y" ]; then
-    choice 'Machine Type'			\
+  choice 'Machine Type'			\
 	"Oak			CONFIG_OAK 	\
 	 Walnut			CONFIG_WALNUT"	Oak
+  if [ "$CONFIG_WALNUT" = "y" ]; then
+    define_bool CONFIG_IBM405_ERR77 y
+  fi
 fi
 
 if [ "$CONFIG_8xx" = "y" ]; then
@@ -99,10 +101,20 @@
 	"CHRP/PowerMac/PReP	CONFIG_ALL_PPC		\
   	 Amiga-APUS		CONFIG_APUS		\
 	 IBM-Spruce		CONFIG_SPRUCE		\
+	 Motorola-LoPEC		CONFIG_LOPEC		\
 	 SBS-Palomar4		CONFIG_PAL4		\
 	 Synergy-Gemini        	CONFIG_GEMINI"		CHRP/PowerMac/PReP
 fi
 
+if [ "$CONFIG_SPRUCE" = "y" ]; then
+  define_bool CONFIG_GEN550 y
+fi
+
+if [ "$CONFIG_LOPEC" = "y" ]; then
+  define_bool CONFIG_EPIC_SERIAL_MODE y
+  define_bool CONFIG_GEN550 y
+fi
+
 if [ "$CONFIG_PPC_STD_MMU" != "y" ]; then
   define_bool CONFIG_ALL_PPC n
 fi
@@ -199,9 +211,12 @@
 if [ "$CONFIG_ALL_PPC" = "y" ]; then
   bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE
   bool 'Support for RTAS (RunTime Abstraction Services) in /proc' CONFIG_PPC_RTAS
-  bool 'Support for early boot text console (BootX or OpenFirmware only)' CONFIG_BOOTX_TEXT
   bool 'Support for PReP Residual Data' CONFIG_PREP_RESIDUAL
   dep_bool '  Support for reading of PReP Residual Data in /proc' CONFIG_PROC_PREPRESIDUAL $CONFIG_PREP_RESIDUAL
+  define_bool CONFIG_PPCBUG_NVRAM y
+fi
+if [ "$CONFIG_LOPEC" = "y" ]; then
+  bool 'Enable reading PPCBUG NVRAM during boot' CONFIG_PPCBUG_NVRAM
 fi
 
 bool 'Default bootloader kernel arguments' CONFIG_CMDLINE_BOOL
@@ -414,14 +429,38 @@
   fi
   bool '  Wait queue debugging' CONFIG_DEBUG_WAITQ
   bool '  Include kgdb kernel debugger' CONFIG_KGDB
+  if [ "$CONFIG_KGDB" = "y" ]; then
+    choice '    Serial Port'		\
+	"ttyS0	CONFIG_KGDB_TTYS0	\
+	 ttyS1	CONFIG_KGDB_TTYS1	\
+	 ttyS2	CONFIG_KGDB_TTYS2	\
+	 ttyS3	CONFIG_KGDB_TTYS3"	ttyS1
+  fi
+  if [ "$CONFIG_8xx" = "y" ]; then
+    dep_bool '    Enable serial console thru kgdb port' CONFIG_KGDB_CONSOLE $CONFIG_KGDB
+  fi
   bool '  Include xmon kernel debugger' CONFIG_XMON
   bool '  Include BDI-2000 user context switcher' CONFIG_BDI_SWITCH
+  # CONFIG_KGDB is much more useful with -g enbaled.  This makes the
+  # following look a little odd.
   if [ "$CONFIG_KGDB" = "y" -o "$CONFIG_XMON" = "y" \
 	-o "$CONFIG_BDI_SWITCH" = "y" ]; then
-    bool '    Add any additional compile options' CONFIG_MORE_COMPILE_OPTIONS
+    bool '  Add any additional compile options' CONFIG_MORE_COMPILE_OPTIONS
     if [ "$CONFIG_MORE_COMPILE_OPTIONS" = "y" ]; then
       string '    Additional compile arguments' CONFIG_COMPILE_OPTIONS "-g -ggdb"
+    else
+      if [ "$CONFIG_KGDB" = "y" ]; then
+        define_bool CONFIG_MORE_COMPILE_OPTIONS y
+	define_string CONFIG_COMPILE_OPTIONS "-g"
+      fi
     fi
   fi
 fi
+
+if [ "$CONFIG_ALL_PPC" = "y" ]; then
+  bool 'Support for early boot text console (BootX or OpenFirmware only)' CONFIG_BOOTX_TEXT
+fi
+if [ "$CONFIG_GEN550" = "y" ]; then
+  bool 'Support for early boot texts over serial port' CONFIG_SERIAL_TEXT_DEBUG
+fi
 endmenu
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/IVMS8_defconfig linux-2.4.21-pre6/arch/ppc/configs/IVMS8_defconfig
--- linux-2.4.20/arch/ppc/configs/IVMS8_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/configs/IVMS8_defconfig	2003-03-26 23:49:07.000000000 +0000
@@ -194,21 +194,13 @@
 CONFIG_BLK_DEV_IDEDISK=y
 CONFIG_IDEDISK_MULTI_MODE=y
 # CONFIG_IDEDISK_STROKE is not set
-# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
-# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
-# CONFIG_BLK_DEV_IDEDISK_IBM is not set
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
 # CONFIG_BLK_DEV_IDECS is not set
 CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
 # CONFIG_BLK_DEV_IDESCSI is not set
 # CONFIG_IDE_TASK_IOCTL is not set
+# CONFIG_IDE_TASKFILE_IO is not set
 
 #
 # IDE chipset support/bugfixes
@@ -277,6 +269,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -384,6 +377,8 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/SM850_defconfig linux-2.4.21-pre6/arch/ppc/configs/SM850_defconfig
--- linux-2.4.20/arch/ppc/configs/SM850_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/configs/SM850_defconfig	2003-03-26 23:49:30.000000000 +0000
@@ -233,6 +233,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -340,6 +341,8 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/SPD823TS_defconfig linux-2.4.21-pre6/arch/ppc/configs/SPD823TS_defconfig
--- linux-2.4.20/arch/ppc/configs/SPD823TS_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/configs/SPD823TS_defconfig	2003-03-26 23:49:55.000000000 +0000
@@ -232,6 +232,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -339,6 +340,8 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/TQM823L_defconfig linux-2.4.21-pre6/arch/ppc/configs/TQM823L_defconfig
--- linux-2.4.20/arch/ppc/configs/TQM823L_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/configs/TQM823L_defconfig	2003-03-26 23:49:15.000000000 +0000
@@ -233,6 +233,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -340,6 +341,8 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/TQM850L_defconfig linux-2.4.21-pre6/arch/ppc/configs/TQM850L_defconfig
--- linux-2.4.20/arch/ppc/configs/TQM850L_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/configs/TQM850L_defconfig	2003-03-26 23:49:40.000000000 +0000
@@ -233,6 +233,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -340,6 +341,8 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/TQM860L_defconfig linux-2.4.21-pre6/arch/ppc/configs/TQM860L_defconfig
--- linux-2.4.20/arch/ppc/configs/TQM860L_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/configs/TQM860L_defconfig	2003-03-26 23:49:25.000000000 +0000
@@ -195,21 +195,13 @@
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
 # CONFIG_IDEDISK_STROKE is not set
-# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
-# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
-# CONFIG_BLK_DEV_IDEDISK_IBM is not set
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
 # CONFIG_BLK_DEV_IDECS is not set
 # CONFIG_BLK_DEV_IDECD is not set
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
 # CONFIG_BLK_DEV_IDESCSI is not set
 # CONFIG_IDE_TASK_IOCTL is not set
+# CONFIG_IDE_TASKFILE_IO is not set
 
 #
 # IDE chipset support/bugfixes
@@ -278,6 +270,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -385,6 +378,8 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/apus_defconfig linux-2.4.21-pre6/arch/ppc/configs/apus_defconfig
--- linux-2.4.20/arch/ppc/configs/apus_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/configs/apus_defconfig	2003-03-26 23:49:51.000000000 +0000
@@ -265,21 +265,13 @@
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
 # CONFIG_IDEDISK_STROKE is not set
-# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
-# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
-# CONFIG_BLK_DEV_IDEDISK_IBM is not set
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
 # CONFIG_BLK_DEV_IDECS is not set
 CONFIG_BLK_DEV_IDECD=y
 CONFIG_BLK_DEV_IDETAPE=m
 CONFIG_BLK_DEV_IDEFLOPPY=y
 CONFIG_BLK_DEV_IDESCSI=m
 # CONFIG_IDE_TASK_IOCTL is not set
+# CONFIG_IDE_TASKFILE_IO is not set
 
 #
 # IDE chipset support/bugfixes
@@ -287,7 +279,6 @@
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
 # CONFIG_BLK_DEV_IDEPCI is not set
 CONFIG_BLK_DEV_GAYLE=y
 CONFIG_BLK_DEV_IDEDOUBLER=y
@@ -295,7 +286,7 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
 # CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
+CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
@@ -374,6 +365,7 @@
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
 CONFIG_A3000_SCSI=y
 CONFIG_A4000T_SCSI=y
@@ -444,6 +436,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -600,6 +593,7 @@
 CONFIG_PRINTER=m
 # CONFIG_LP_CONSOLE is not set
 # CONFIG_PPDEV is not set
+# CONFIG_TIPAR is not set
 
 #
 # I2C support
@@ -660,6 +654,8 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -855,6 +851,7 @@
 CONFIG_SOUND_TRACEINIT=y
 CONFIG_SOUND_DMAP=y
 # CONFIG_SOUND_AD1816 is not set
+# CONFIG_SOUND_AD1889 is not set
 # CONFIG_SOUND_SGALAXY is not set
 # CONFIG_SOUND_ADLIB is not set
 # CONFIG_SOUND_ACI_MIXER is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/briq_defconfig linux-2.4.21-pre6/arch/ppc/configs/briq_defconfig
--- linux-2.4.20/arch/ppc/configs/briq_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/configs/briq_defconfig	2003-03-26 23:49:50.000000000 +0000
@@ -236,21 +236,13 @@
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
 # CONFIG_IDEDISK_STROKE is not set
-# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
-# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
-# CONFIG_BLK_DEV_IDEDISK_IBM is not set
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
 # CONFIG_BLK_DEV_IDECS is not set
 CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_IDETAPE is not set
 CONFIG_BLK_DEV_IDEFLOPPY=y
 CONFIG_BLK_DEV_IDESCSI=y
 # CONFIG_IDE_TASK_IOCTL is not set
+# CONFIG_IDE_TASKFILE_IO is not set
 
 #
 # IDE chipset support/bugfixes
@@ -258,8 +250,8 @@
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
 CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_BLK_DEV_GENERIC=y
 CONFIG_IDEPCI_SHARE_IRQ=y
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
@@ -268,28 +260,30 @@
 # CONFIG_IDEDMA_ONLYDISK is not set
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_PCI_WIP is not set
-# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set
-# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
 CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_AEC62XX is not set
-# CONFIG_AEC62XX_TUNING is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
 # CONFIG_WDC_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD74XX is not set
 # CONFIG_AMD74XX_OVERRIDE is not set
 # CONFIG_BLK_DEV_CMD64X is not set
-# CONFIG_BLK_DEV_CMD680 is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5530 is not set
 # CONFIG_BLK_DEV_HPT34X is not set
 # CONFIG_HPT34X_AUTODMA is not set
 # CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_NFORCE is not set
 # CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_PDC202XX is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
 # CONFIG_PDC202XX_BURST is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
 # CONFIG_PDC202XX_FORCE is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
 # CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
 # CONFIG_BLK_DEV_SIS5513 is not set
 # CONFIG_BLK_DEV_SLC90E66 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
@@ -379,6 +373,7 @@
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
 # CONFIG_SCSI_MESH is not set
 # CONFIG_SCSI_MAC53C94 is not set
@@ -465,6 +460,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -556,7 +552,6 @@
 # CONFIG_SERIAL_NONSTANDARD is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
-CONFIG_BRIQ_PANEL=y
 
 #
 # I2C support
@@ -599,6 +594,8 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 CONFIG_NVRAM=y
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/bseip_defconfig linux-2.4.21-pre6/arch/ppc/configs/bseip_defconfig
--- linux-2.4.20/arch/ppc/configs/bseip_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/configs/bseip_defconfig	2003-03-26 23:49:18.000000000 +0000
@@ -232,6 +232,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -339,6 +340,8 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/common_defconfig linux-2.4.21-pre6/arch/ppc/configs/common_defconfig
--- linux-2.4.20/arch/ppc/configs/common_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/configs/common_defconfig	2003-03-26 23:49:21.000000000 +0000
@@ -242,21 +242,13 @@
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
 # CONFIG_IDEDISK_STROKE is not set
-# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
-# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
-# CONFIG_BLK_DEV_IDEDISK_IBM is not set
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
 # CONFIG_BLK_DEV_IDECS is not set
 CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_IDETAPE is not set
 CONFIG_BLK_DEV_IDEFLOPPY=y
 CONFIG_BLK_DEV_IDESCSI=y
 # CONFIG_IDE_TASK_IOCTL is not set
+CONFIG_IDE_TASKFILE_IO=y
 
 #
 # IDE chipset support/bugfixes
@@ -264,8 +256,8 @@
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
 CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_BLK_DEV_GENERIC=y
 CONFIG_IDEPCI_SHARE_IRQ=y
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
@@ -274,28 +266,30 @@
 # CONFIG_IDEDMA_ONLYDISK is not set
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_PCI_WIP is not set
-# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set
-# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
 CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_AEC62XX is not set
-# CONFIG_AEC62XX_TUNING is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
 # CONFIG_WDC_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD74XX is not set
 # CONFIG_AMD74XX_OVERRIDE is not set
 CONFIG_BLK_DEV_CMD64X=y
-# CONFIG_BLK_DEV_CMD680 is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5530 is not set
 # CONFIG_BLK_DEV_HPT34X is not set
 # CONFIG_HPT34X_AUTODMA is not set
 # CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_NFORCE is not set
 # CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_PDC202XX is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
 # CONFIG_PDC202XX_BURST is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
 # CONFIG_PDC202XX_FORCE is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
 # CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
 # CONFIG_BLK_DEV_SIS5513 is not set
 # CONFIG_BLK_DEV_SLC90E66 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
@@ -396,6 +390,7 @@
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
 CONFIG_SCSI_MESH=y
 CONFIG_SCSI_MESH_SYNC_RATE=5
@@ -487,6 +482,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -647,7 +643,6 @@
 # CONFIG_SERIAL_NONSTANDARD is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
-# CONFIG_BRIQ_PANEL is not set
 
 #
 # I2C support
@@ -712,6 +707,8 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 CONFIG_NVRAM=y
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -880,6 +877,8 @@
 CONFIG_SOUND=m
 CONFIG_DMASOUND_PMAC=m
 CONFIG_DMASOUND=m
+CONFIG_I2C=m
+CONFIG_I2C_KEYWEST=m
 # CONFIG_SOUND_ALI5455 is not set
 # CONFIG_SOUND_BT878 is not set
 # CONFIG_SOUND_CMPCI is not set
@@ -915,7 +914,6 @@
 #
 CONFIG_USB_DEVICEFS=y
 # CONFIG_USB_BANDWIDTH is not set
-# CONFIG_USB_LONG_TIMEOUT is not set
 
 #
 # USB Host Controller Drivers
@@ -953,6 +951,7 @@
 # CONFIG_USB_HIDDEV is not set
 # CONFIG_USB_AIPTEK is not set
 # CONFIG_USB_WACOM is not set
+# CONFIG_USB_POWERMATE is not set
 
 #
 # USB Imaging devices
@@ -1006,6 +1005,7 @@
 # CONFIG_USB_SERIAL_KEYSPAN is not set
 # CONFIG_USB_SERIAL_MCT_U232 is not set
 # CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
 # CONFIG_USB_SERIAL_PL2303 is not set
 # CONFIG_USB_SERIAL_CYBERJACK is not set
 # CONFIG_USB_SERIAL_XIRCOM is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/est8260_defconfig linux-2.4.21-pre6/arch/ppc/configs/est8260_defconfig
--- linux-2.4.20/arch/ppc/configs/est8260_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/configs/est8260_defconfig	2003-03-26 23:49:39.000000000 +0000
@@ -215,6 +215,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -323,6 +324,8 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/gemini_defconfig linux-2.4.21-pre6/arch/ppc/configs/gemini_defconfig
--- linux-2.4.20/arch/ppc/configs/gemini_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/configs/gemini_defconfig	2003-03-26 23:49:34.000000000 +0000
@@ -257,6 +257,7 @@
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
 
 #
@@ -310,6 +311,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -420,6 +422,8 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/ibmchrp_defconfig linux-2.4.21-pre6/arch/ppc/configs/ibmchrp_defconfig
--- linux-2.4.20/arch/ppc/configs/ibmchrp_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/configs/ibmchrp_defconfig	2003-03-26 23:49:35.000000000 +0000
@@ -298,6 +298,7 @@
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
 # CONFIG_SCSI_MESH is not set
 # CONFIG_SCSI_MAC53C94 is not set
@@ -384,6 +385,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -520,7 +522,6 @@
 # CONFIG_SERIAL_NONSTANDARD is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
-# CONFIG_BRIQ_PANEL is not set
 
 #
 # I2C support
@@ -580,6 +581,8 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 CONFIG_NVRAM=y
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/mbx_defconfig linux-2.4.21-pre6/arch/ppc/configs/mbx_defconfig
--- linux-2.4.20/arch/ppc/configs/mbx_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/configs/mbx_defconfig	2003-03-26 23:48:57.000000000 +0000
@@ -229,6 +229,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -335,6 +336,8 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/oak_defconfig linux-2.4.21-pre6/arch/ppc/configs/oak_defconfig
--- linux-2.4.20/arch/ppc/configs/oak_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/configs/oak_defconfig	2003-03-26 23:49:00.000000000 +0000
@@ -215,6 +215,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -322,6 +323,8 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/pal4_defconfig linux-2.4.21-pre6/arch/ppc/configs/pal4_defconfig
--- linux-2.4.20/arch/ppc/configs/pal4_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/configs/pal4_defconfig	2003-03-26 23:49:38.000000000 +0000
@@ -309,6 +309,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -433,6 +434,8 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/pmac_defconfig linux-2.4.21-pre6/arch/ppc/configs/pmac_defconfig
--- linux-2.4.20/arch/ppc/configs/pmac_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/configs/pmac_defconfig	2003-03-26 23:49:20.000000000 +0000
@@ -245,21 +245,13 @@
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
 # CONFIG_IDEDISK_STROKE is not set
-# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
-# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
-# CONFIG_BLK_DEV_IDEDISK_IBM is not set
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
 CONFIG_BLK_DEV_IDECS=m
 CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_IDETAPE is not set
 CONFIG_BLK_DEV_IDEFLOPPY=y
 CONFIG_BLK_DEV_IDESCSI=y
 # CONFIG_IDE_TASK_IOCTL is not set
+# CONFIG_IDE_TASKFILE_IO is not set
 
 #
 # IDE chipset support/bugfixes
@@ -267,8 +259,8 @@
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
 CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_BLK_DEV_GENERIC=y
 CONFIG_IDEPCI_SHARE_IRQ=y
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
@@ -277,28 +269,30 @@
 # CONFIG_IDEDMA_ONLYDISK is not set
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_PCI_WIP is not set
-# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set
-# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
 CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_AEC62XX is not set
-# CONFIG_AEC62XX_TUNING is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
 # CONFIG_WDC_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD74XX is not set
 # CONFIG_AMD74XX_OVERRIDE is not set
 CONFIG_BLK_DEV_CMD64X=y
-# CONFIG_BLK_DEV_CMD680 is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5530 is not set
 # CONFIG_BLK_DEV_HPT34X is not set
 # CONFIG_HPT34X_AUTODMA is not set
 # CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_NFORCE is not set
 # CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_PDC202XX is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
 # CONFIG_PDC202XX_BURST is not set
+CONFIG_BLK_DEV_PDC202XX_NEW=m
 # CONFIG_PDC202XX_FORCE is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
 # CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
 # CONFIG_BLK_DEV_SIS5513 is not set
 # CONFIG_BLK_DEV_SLC90E66 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
@@ -313,6 +307,7 @@
 CONFIG_IDEDMA_AUTO=y
 # CONFIG_IDEDMA_IVB is not set
 # CONFIG_DMA_NONPCI is not set
+CONFIG_BLK_DEV_PDC202XX=y
 CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
@@ -399,6 +394,7 @@
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
 CONFIG_SCSI_MESH=y
 CONFIG_SCSI_MESH_SYNC_RATE=5
@@ -516,6 +512,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -748,7 +745,6 @@
 # CONFIG_SERIAL_NONSTANDARD is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
-# CONFIG_BRIQ_PANEL is not set
 
 #
 # I2C support
@@ -813,6 +809,8 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 CONFIG_NVRAM=y
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -988,6 +986,8 @@
 CONFIG_SOUND=m
 CONFIG_DMASOUND_PMAC=m
 CONFIG_DMASOUND=m
+CONFIG_I2C=m
+CONFIG_I2C_KEYWEST=m
 # CONFIG_SOUND_ALI5455 is not set
 # CONFIG_SOUND_BT878 is not set
 # CONFIG_SOUND_CMPCI is not set
@@ -1023,7 +1023,6 @@
 #
 CONFIG_USB_DEVICEFS=y
 # CONFIG_USB_BANDWIDTH is not set
-# CONFIG_USB_LONG_TIMEOUT is not set
 
 #
 # USB Host Controller Drivers
@@ -1061,6 +1060,7 @@
 # CONFIG_USB_HIDDEV is not set
 # CONFIG_USB_AIPTEK is not set
 # CONFIG_USB_WACOM is not set
+# CONFIG_USB_POWERMATE is not set
 
 #
 # USB Imaging devices
@@ -1114,6 +1114,7 @@
 # CONFIG_USB_SERIAL_KEYSPAN is not set
 # CONFIG_USB_SERIAL_MCT_U232 is not set
 # CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
 # CONFIG_USB_SERIAL_PL2303 is not set
 # CONFIG_USB_SERIAL_CYBERJACK is not set
 # CONFIG_USB_SERIAL_XIRCOM is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/power3_defconfig linux-2.4.21-pre6/arch/ppc/configs/power3_defconfig
--- linux-2.4.20/arch/ppc/configs/power3_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/configs/power3_defconfig	2003-03-26 23:49:18.000000000 +0000
@@ -259,6 +259,7 @@
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
 # CONFIG_SCSI_MESH is not set
 # CONFIG_SCSI_MAC53C94 is not set
@@ -345,6 +346,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -486,7 +488,7 @@
 CONFIG_PRINTER=m
 # CONFIG_LP_CONSOLE is not set
 # CONFIG_PPDEV is not set
-# CONFIG_BRIQ_PANEL is not set
+# CONFIG_TIPAR is not set
 
 #
 # I2C support
@@ -496,6 +498,8 @@
 # CONFIG_I2C_PHILIPSPAR is not set
 # CONFIG_I2C_ELV is not set
 # CONFIG_I2C_VELLEMAN is not set
+# CONFIG_SCx200_I2C is not set
+# CONFIG_SCx200_ACB is not set
 CONFIG_I2C_ALGOPCF=y
 # CONFIG_I2C_ELEKTOR is not set
 # CONFIG_I2C_KEYWEST is not set
@@ -552,6 +556,8 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 CONFIG_NVRAM=y
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -730,6 +736,7 @@
 CONFIG_SOUND_TRACEINIT=y
 # CONFIG_SOUND_DMAP is not set
 # CONFIG_SOUND_AD1816 is not set
+# CONFIG_SOUND_AD1889 is not set
 # CONFIG_SOUND_SGALAXY is not set
 # CONFIG_SOUND_ADLIB is not set
 # CONFIG_SOUND_ACI_MIXER is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/rpxcllf_defconfig linux-2.4.21-pre6/arch/ppc/configs/rpxcllf_defconfig
--- linux-2.4.20/arch/ppc/configs/rpxcllf_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/configs/rpxcllf_defconfig	2003-03-26 23:49:20.000000000 +0000
@@ -14,7 +14,9 @@
 #
 # Loadable module support
 #
-# CONFIG_MODULES is not set
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
 
 #
 # Platform support
@@ -67,8 +69,16 @@
 CONFIG_BINFMT_ELF=y
 CONFIG_KERNEL_ELF=y
 # CONFIG_BINFMT_MISC is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
+CONFIG_HOTPLUG=y
+
+#
+# PCMCIA/CardBus support
+#
+CONFIG_PCMCIA=m
+# CONFIG_TCIC is not set
+# CONFIG_I82092 is not set
+# CONFIG_I82365 is not set
+CONFIG_PCMCIA_M8XX=m
 
 #
 # Parallel port support
@@ -232,6 +242,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -243,7 +254,21 @@
 #
 # Wireless LAN (non-hamradio)
 #
-# CONFIG_NET_RADIO is not set
+CONFIG_NET_RADIO=y
+# CONFIG_STRIP is not set
+# CONFIG_WAVELAN is not set
+# CONFIG_ARLAN is not set
+# CONFIG_AIRONET4500 is not set
+# CONFIG_AIRONET4500_NONCS is not set
+# CONFIG_AIRONET4500_PROC is not set
+CONFIG_HERMES=m
+
+#
+# Wireless Pcmcia cards support
+#
+CONFIG_PCMCIA_HERMES=m
+# CONFIG_AIRO_CS is not set
+CONFIG_NET_WIRELESS=y
 
 #
 # Token Ring devices
@@ -259,6 +284,11 @@
 # CONFIG_WAN is not set
 
 #
+# PCMCIA network device support
+#
+# CONFIG_NET_PCMCIA is not set
+
+#
 # Amateur Radio support
 #
 # CONFIG_HAMRADIO is not set
@@ -339,6 +369,8 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -353,6 +385,12 @@
 # CONFIG_DRM is not set
 
 #
+# PCMCIA character devices
+#
+# CONFIG_PCMCIA_SERIAL_CS is not set
+# CONFIG_SYNCLINK_CS is not set
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/rpxlite_defconfig linux-2.4.21-pre6/arch/ppc/configs/rpxlite_defconfig
--- linux-2.4.20/arch/ppc/configs/rpxlite_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/configs/rpxlite_defconfig	2003-03-26 23:49:16.000000000 +0000
@@ -14,7 +14,9 @@
 #
 # Loadable module support
 #
-# CONFIG_MODULES is not set
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
 
 #
 # Platform support
@@ -67,8 +69,16 @@
 CONFIG_BINFMT_ELF=y
 CONFIG_KERNEL_ELF=y
 # CONFIG_BINFMT_MISC is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
+CONFIG_HOTPLUG=y
+
+#
+# PCMCIA/CardBus support
+#
+CONFIG_PCMCIA=m
+# CONFIG_TCIC is not set
+# CONFIG_I82092 is not set
+# CONFIG_I82365 is not set
+CONFIG_PCMCIA_M8XX=m
 
 #
 # Parallel port support
@@ -232,6 +242,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -243,7 +254,21 @@
 #
 # Wireless LAN (non-hamradio)
 #
-# CONFIG_NET_RADIO is not set
+CONFIG_NET_RADIO=y
+# CONFIG_STRIP is not set
+# CONFIG_WAVELAN is not set
+# CONFIG_ARLAN is not set
+# CONFIG_AIRONET4500 is not set
+# CONFIG_AIRONET4500_NONCS is not set
+# CONFIG_AIRONET4500_PROC is not set
+CONFIG_HERMES=m
+
+#
+# Wireless Pcmcia cards support
+#
+CONFIG_PCMCIA_HERMES=m
+# CONFIG_AIRO_CS is not set
+CONFIG_NET_WIRELESS=y
 
 #
 # Token Ring devices
@@ -259,6 +284,11 @@
 # CONFIG_WAN is not set
 
 #
+# PCMCIA network device support
+#
+# CONFIG_NET_PCMCIA is not set
+
+#
 # Amateur Radio support
 #
 # CONFIG_HAMRADIO is not set
@@ -339,6 +369,8 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -353,6 +385,12 @@
 # CONFIG_DRM is not set
 
 #
+# PCMCIA character devices
+#
+# CONFIG_PCMCIA_SERIAL_CS is not set
+# CONFIG_SYNCLINK_CS is not set
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/spruce_defconfig linux-2.4.21-pre6/arch/ppc/configs/spruce_defconfig
--- linux-2.4.20/arch/ppc/configs/spruce_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/configs/spruce_defconfig	2003-03-26 23:49:18.000000000 +0000
@@ -260,6 +260,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -373,6 +374,8 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/configs/walnut_defconfig linux-2.4.21-pre6/arch/ppc/configs/walnut_defconfig
--- linux-2.4.20/arch/ppc/configs/walnut_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/configs/walnut_defconfig	2003-03-26 23:49:53.000000000 +0000
@@ -215,6 +215,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -326,6 +327,8 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/defconfig linux-2.4.21-pre6/arch/ppc/defconfig
--- linux-2.4.20/arch/ppc/defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/defconfig	2003-03-26 23:49:20.000000000 +0000
@@ -242,21 +242,13 @@
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
 # CONFIG_IDEDISK_STROKE is not set
-# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
-# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
-# CONFIG_BLK_DEV_IDEDISK_IBM is not set
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
 # CONFIG_BLK_DEV_IDECS is not set
 CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_IDETAPE is not set
 CONFIG_BLK_DEV_IDEFLOPPY=y
 CONFIG_BLK_DEV_IDESCSI=y
 # CONFIG_IDE_TASK_IOCTL is not set
+# CONFIG_IDE_TASKFILE_IO is not set
 
 #
 # IDE chipset support/bugfixes
@@ -264,8 +256,8 @@
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
 CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_BLK_DEV_GENERIC=y
 CONFIG_IDEPCI_SHARE_IRQ=y
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
@@ -274,28 +266,30 @@
 # CONFIG_IDEDMA_ONLYDISK is not set
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_PCI_WIP is not set
-# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set
-# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
 CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_AEC62XX is not set
-# CONFIG_AEC62XX_TUNING is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
 # CONFIG_WDC_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD74XX is not set
 # CONFIG_AMD74XX_OVERRIDE is not set
 CONFIG_BLK_DEV_CMD64X=y
-# CONFIG_BLK_DEV_CMD680 is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5530 is not set
 # CONFIG_BLK_DEV_HPT34X is not set
 # CONFIG_HPT34X_AUTODMA is not set
 # CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_NFORCE is not set
 # CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_PDC202XX is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
 # CONFIG_PDC202XX_BURST is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
 # CONFIG_PDC202XX_FORCE is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
 # CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
 # CONFIG_BLK_DEV_SIS5513 is not set
 # CONFIG_BLK_DEV_SLC90E66 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
@@ -396,6 +390,7 @@
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
 CONFIG_SCSI_MESH=y
 CONFIG_SCSI_MESH_SYNC_RATE=5
@@ -487,6 +482,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -647,7 +643,6 @@
 # CONFIG_SERIAL_NONSTANDARD is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
-# CONFIG_BRIQ_PANEL is not set
 
 #
 # I2C support
@@ -712,6 +707,8 @@
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 CONFIG_NVRAM=y
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -880,6 +877,8 @@
 CONFIG_SOUND=m
 CONFIG_DMASOUND_PMAC=m
 CONFIG_DMASOUND=m
+CONFIG_I2C=m
+CONFIG_I2C_KEYWEST=m
 # CONFIG_SOUND_ALI5455 is not set
 # CONFIG_SOUND_BT878 is not set
 # CONFIG_SOUND_CMPCI is not set
@@ -915,7 +914,6 @@
 #
 CONFIG_USB_DEVICEFS=y
 # CONFIG_USB_BANDWIDTH is not set
-# CONFIG_USB_LONG_TIMEOUT is not set
 
 #
 # USB Host Controller Drivers
@@ -953,6 +951,7 @@
 # CONFIG_USB_HIDDEV is not set
 # CONFIG_USB_AIPTEK is not set
 # CONFIG_USB_WACOM is not set
+# CONFIG_USB_POWERMATE is not set
 
 #
 # USB Imaging devices
@@ -1006,6 +1005,7 @@
 # CONFIG_USB_SERIAL_KEYSPAN is not set
 # CONFIG_USB_SERIAL_MCT_U232 is not set
 # CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
 # CONFIG_USB_SERIAL_PL2303 is not set
 # CONFIG_USB_SERIAL_CYBERJACK is not set
 # CONFIG_USB_SERIAL_XIRCOM is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/Makefile linux-2.4.21-pre6/arch/ppc/kernel/Makefile
--- linux-2.4.20/arch/ppc/kernel/Makefile	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/Makefile	2003-03-26 23:49:54.000000000 +0000
@@ -1,5 +1,3 @@
-# BK Id: %F% %I% %G% %U% %#%
-#
 #
 # Makefile for the linux kernel.
 #
@@ -43,8 +41,13 @@
 obj-$(CONFIG_PCI)		+= pci.o 
 obj-$(CONFIG_PCI)		+= pci-dma.o
 obj-$(CONFIG_KGDB)		+= ppc-stub.o
+obj-$(CONFIG_PPCBUG_NVRAM)	+= prep_nvram.o
 obj-$(CONFIG_SMP)		+= smp.o
 obj-$(CONFIG_TAU)		+= temp.o
+ifeq ($(CONFIG_SERIAL)$(CONFIG_GEN550),yy)
+obj-$(CONFIG_KGDB)		+= gen550_kgdb.o gen550_dbg.o
+obj-$(CONFIG_SERIAL_TEXT_DEBUG)	+= gen550_dbg.o
+endif
 obj-$(CONFIG_4xx)		+= ppc4xx_pic.o
 obj-$(CONFIG_8xx)		+= m8xx_setup.o ppc8xx_pic.o
 ifeq ($(CONFIG_8xx),y)
@@ -55,8 +58,10 @@
 endif
 obj-$(CONFIG_MBX)		+= i8259.o
 obj-$(CONFIG_ALL_PPC)		+= prom_init.o prom.o open_pic.o \
-					indirect_pci.o i8259.o prep_nvram.o
+					indirect_pci.o i8259.o
 obj-$(CONFIG_GEMINI)		+= open_pic.o
+obj-$(CONFIG_LOPEC)		+= mpc10x_common.o indirect_pci.o pci_auto.o \
+					open_pic.o i8259.o todc_time.o
 obj-$(CONFIG_PAL4)		+= indirect_pci.o pci_auto.o todc_time.o
 obj-$(CONFIG_SPRUCE)		+= indirect_pci.o pci_auto.o todc_time.o
 obj-$(CONFIG_8260)		+= m8260_setup.o ppc8260_pic.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/align.c linux-2.4.21-pre6/arch/ppc/kernel/align.c
--- linux-2.4.20/arch/ppc/kernel/align.c	2001-05-22 00:04:46.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/align.c	2003-03-26 23:48:57.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.align.c 1.5 05/17/01 18:14:21 cort
- */
-/*
  * align.c - handle alignment exceptions for the Power PC.
  *
  * Copyright (c) 1996 Paul Mackerras <paulus@cs.anu.edu.au>
@@ -28,7 +25,7 @@
 #define	OPCD(inst)	(((inst) & 0xFC000000) >> 26)
 #define	RS(inst)	(((inst) & 0x03E00000) >> 21)
 #define	RA(inst)	(((inst) & 0x001F0000) >> 16)
-#define	IS_DFORM(code)	((code) >= 32 && (code) <= 47)
+#define	IS_XFORM(code)	((code) == 31)
 #endif
 
 #define INVALID	{ 0, 0 }
@@ -64,9 +61,9 @@
 	{ 4, ST+F+S },		/* 00 0 1010: stfs */
 	{ 8, ST+F },		/* 00 0 1011: stfd */
 	INVALID,		/* 00 0 1100 */
-	INVALID,		/* 00 0 1101 */
+	INVALID,		/* 00 0 1101: ld/ldu/lwa */
 	INVALID,		/* 00 0 1110 */
-	INVALID,		/* 00 0 1111 */
+	INVALID,		/* 00 0 1111: std/stdu */
 	{ 4, LD+U },		/* 00 1 0000: lwzu */
 	INVALID,		/* 00 1 0001 */
 	{ 4, ST+U },		/* 00 1 0010: stwu */
@@ -83,12 +80,12 @@
 	INVALID,		/* 00 1 1101 */
 	INVALID,		/* 00 1 1110 */
 	INVALID,		/* 00 1 1111 */
-	INVALID,		/* 01 0 0000 */
+	INVALID,		/* 01 0 0000: ldx */
 	INVALID,		/* 01 0 0001 */
-	INVALID,		/* 01 0 0010 */
+	INVALID,		/* 01 0 0010: stdx */
 	INVALID,		/* 01 0 0011 */
 	INVALID,		/* 01 0 0100 */
-	INVALID,		/* 01 0 0101: lwax?? */
+	INVALID,		/* 01 0 0101: lwax */
 	INVALID,		/* 01 0 0110 */
 	INVALID,		/* 01 0 0111 */
 	{ 0, LD+HARD },		/* 01 0 1000: lswx */
@@ -99,12 +96,12 @@
 	INVALID,		/* 01 0 1101 */
 	INVALID,		/* 01 0 1110 */
 	INVALID,		/* 01 0 1111 */
-	INVALID,		/* 01 1 0000 */
+	INVALID,		/* 01 1 0000: ldux */
 	INVALID,		/* 01 1 0001 */
-	INVALID,		/* 01 1 0010 */
+	INVALID,		/* 01 1 0010: stdux */
 	INVALID,		/* 01 1 0011 */
 	INVALID,		/* 01 1 0100 */
-	INVALID,		/* 01 1 0101: lwaux?? */
+	INVALID,		/* 01 1 0101: lwaux */
 	INVALID,		/* 01 1 0110 */
 	INVALID,		/* 01 1 0111 */
 	INVALID,		/* 01 1 1000 */
@@ -160,9 +157,9 @@
 	{ 4, ST+F+S },		/* 11 0 1010: stfsx */
 	{ 8, ST+F },		/* 11 0 1011: stfdx */
 	INVALID,		/* 11 0 1100 */
-	INVALID,		/* 11 0 1101 */
+	INVALID,		/* 11 0 1101: lmd */
 	INVALID,		/* 11 0 1110 */
-	INVALID,		/* 11 0 1111 */
+	INVALID,		/* 11 0 1111: stmd */
 	{ 4, LD+U },		/* 11 1 0000: lwzux */
 	INVALID,		/* 11 1 0001 */
 	{ 4, ST+U },		/* 11 1 0010: stwux */
@@ -212,7 +209,7 @@
 	reg = RS(instr);
 	areg = RA(instr);
 
-	if (IS_DFORM(opcode)) {
+	if (!IS_XFORM(opcode)) {
 		f1 = 0;
 		f2 = (instr & 0x04000000) >> 26;
 		f3 = (instr & 0x78000000) >> 27;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/bitops.c linux-2.4.21-pre6/arch/ppc/kernel/bitops.c
--- linux-2.4.20/arch/ppc/kernel/bitops.c	2001-05-22 00:04:46.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/bitops.c	2003-03-26 23:49:02.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.bitops.c 1.7 05/17/01 18:14:21 cort
- */
-/*
  * Copyright (C) 1996 Paul Mackerras.
  */
 
@@ -21,8 +18,9 @@
 	
 	__asm__ __volatile__(SMP_WMB "\n\
 1:	lwarx	%0,0,%3 \n\
-	or	%0,%0,%2 \n\
-	stwcx.	%0,0,%3 \n\
+	or	%0,%0,%2 \n"
+	PPC405_ERR77(0,%3)
+"	stwcx.	%0,0,%3 \n\
 	bne	1b"
 	SMP_MB
 	: "=&r" (old), "=m" (*p)
@@ -38,8 +36,9 @@
 
 	__asm__ __volatile__(SMP_WMB "\n\
 1:	lwarx	%0,0,%3 \n\
-	andc	%0,%0,%2 \n\
-	stwcx.	%0,0,%3 \n\
+	andc	%0,%0,%2 \n"
+	PPC405_ERR77(0,%3)
+"	stwcx.	%0,0,%3 \n\
 	bne	1b"
 	SMP_MB
 	: "=&r" (old), "=m" (*p)
@@ -55,8 +54,9 @@
 
 	__asm__ __volatile__(SMP_WMB "\n\
 1:	lwarx	%0,0,%3 \n\
-	xor	%0,%0,%2 \n\
-	stwcx.	%0,0,%3 \n\
+	xor	%0,%0,%2 \n"
+	PPC405_ERR77(0,%3)
+"	stwcx.	%0,0,%3 \n\
 	bne	1b"
 	SMP_MB
 	: "=&r" (old), "=m" (*p)
@@ -72,8 +72,9 @@
 
 	__asm__ __volatile__(SMP_WMB "\n\
 1:	lwarx	%0,0,%4 \n\
-	or	%1,%0,%3 \n\
-	stwcx.	%1,0,%4 \n\
+	or	%1,%0,%3 \n"
+	PPC405_ERR77(0,%4)
+"	stwcx.	%1,0,%4 \n\
 	bne	1b"
 	SMP_MB
 	: "=&r" (old), "=&r" (t), "=m" (*p)
@@ -91,8 +92,9 @@
 
 	__asm__ __volatile__(SMP_WMB "\n\
 1:	lwarx	%0,0,%4 \n\
-	andc	%1,%0,%3 \n\
-	stwcx.	%1,0,%4 \n\
+	andc	%1,%0,%3 \n"
+	PPC405_ERR77(0,%4)
+"	stwcx.	%1,0,%4 \n\
 	bne	1b"
 	SMP_MB
 	: "=&r" (old), "=&r" (t), "=m" (*p)
@@ -110,8 +112,9 @@
 
 	__asm__ __volatile__(SMP_WMB "\n\
 1:	lwarx	%0,0,%4 \n\
-	xor	%1,%0,%3 \n\
-	stwcx.	%1,0,%4 \n\
+	xor	%1,%0,%3 \n"
+	PPC405_ERR77(0,%4)
+"	stwcx.	%1,0,%4 \n\
 	bne	1b"
 	SMP_MB
 	: "=&r" (old), "=&r" (t), "=m" (*p)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/btext.c linux-2.4.21-pre6/arch/ppc/kernel/btext.c
--- linux-2.4.20/arch/ppc/kernel/btext.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/btext.c	2003-03-26 23:48:58.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Procedures for drawing on the screen early on in the boot process.
  *
  * Benjamin Herrenschmidt <benh@kernel.crashing.org>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/checks.c linux-2.4.21-pre6/arch/ppc/kernel/checks.c
--- linux-2.4.20/arch/ppc/kernel/checks.c	2001-05-22 00:04:46.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/checks.c	2003-03-26 23:49:54.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.checks.c 1.6 05/17/01 18:14:21 cort
- */
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/cputable.c linux-2.4.21-pre6/arch/ppc/kernel/cputable.c
--- linux-2.4.20/arch/ppc/kernel/cputable.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/cputable.c	2003-03-26 23:49:39.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/kernel/cputable.c
  *
  *  Copyright (C) 2001 Ben. Herrenschmidt (benh@kernel.crashing.org)
@@ -38,7 +35,7 @@
 
 #define CLASSIC_PPC (!defined(CONFIG_8xx) && 	 \
 		     !defined(CONFIG_4xx) && !defined(CONFIG_POWER3) &&  \
-		     !defined(CONFIG_POWER4) && !defined(CONFIG_PPC_ISERIES))
+		     !defined(CONFIG_POWER4))
 
 /* This table only contains "desktop" CPUs, it need to be filled with embedded
  * ones as well...
@@ -144,7 +141,16 @@
 	32, 32,
 	__setup_cpu_750cx
     },
-    {	/* 750FX (All revs for now) */
+    {	/* 750FX rev 2.0 must disable HID0[DPM] */
+    	0xffffffff, 0x70000200, "750FX",
+    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB |
+	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP |
+	CPU_FTR_NO_DPM,
+	COMMON_PPC,
+	32, 32,
+	__setup_cpu_750
+    },
+    {	/* 750FX (All revs except 2.0) */
     	0xffff0000, 0x70000000, "750FX",
     	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB |
 	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_CAN_NAP |
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/entry.S linux-2.4.21-pre6/arch/ppc/kernel/entry.S
--- linux-2.4.20/arch/ppc/kernel/entry.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/entry.S	2003-03-26 23:49:25.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.entry.S 1.26 01/25/02 15:15:24 benh
- */
-/*
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
  *  Rewritten by Cort Dougan (cort@fsmlabs.com) for PReP
@@ -166,7 +163,6 @@
 	.globl	ret_from_syscall_2
 ret_from_syscall_2:
 	stw	r3,RESULT(r1)	/* Save result */	
-	stw	r3,GPR0(r1)	/* temporary gross hack to make strace work */
 	li	r10,-_LAST_ERRNO
 	cmpl	0,r3,r10
 	blt	60f
@@ -314,6 +310,7 @@
 	SYNC			/* Some chip revs have problems here... */
 	mtmsr	r0		/* Update machine state */
 
+	PPC405_ERR77(0,r1)
 	stwcx.	r0,0,r1		/* to clear the reservation */
 
 	/* if returning to user mode, set new sprg2 and save kernel SP */
@@ -377,6 +374,7 @@
 	lwz	r4,GPR4(r1)
 	lwz	r1,GPR1(r1)
 	SYNC
+	PPC405_ERR77_SYNC
 	RFI
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/find_name.c linux-2.4.21-pre6/arch/ppc/kernel/find_name.c
--- linux-2.4.20/arch/ppc/kernel/find_name.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/find_name.c	2003-03-26 23:49:49.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.find_name.c 1.5 05/17/01 18:14:21 cort
- */
 #include <stdio.h>
 #include <asm/page.h>
 #include <sys/mman.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/galaxy_pci.c linux-2.4.21-pre6/arch/ppc/kernel/galaxy_pci.c
--- linux-2.4.20/arch/ppc/kernel/galaxy_pci.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/galaxy_pci.c	2003-03-26 23:49:39.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *
  *    Copyright (c) 2000 Grant Erickson <grant@borg.umn.edu>
  *    All rights reserved.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/gen550_dbg.c linux-2.4.21-pre6/arch/ppc/kernel/gen550_dbg.c
--- linux-2.4.20/arch/ppc/kernel/gen550_dbg.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/gen550_dbg.c	2003-03-26 23:49:08.000000000 +0000
@@ -0,0 +1,153 @@
+/*
+ * arch/ppc/kernel/gen550_dbg.c
+ *
+ * A library of polled 16550 serial routines.  These are intended to
+ * be used to support progress messages, xmon, kgdb, etc. on a
+ * variety of platforms.
+ *
+ * Adapted from lots of code ripped from the arch/ppc/boot/ polled
+ * 16550 support.
+ *
+ * Matt Porter <mporter@mvista.com>
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/serialP.h>
+#include <linux/serial_reg.h>
+#include <asm/serial.h>
+#include <asm/io.h>
+
+#define SERIAL_BAUD	9600
+
+extern struct serial_state rs_table[];
+
+static void (*serial_outb)(unsigned long, unsigned char);
+static unsigned long (*serial_inb)(unsigned long);
+
+static int shift;
+
+unsigned long direct_inb(unsigned long addr)
+{
+	return readb(addr);
+}
+
+void direct_outb(unsigned long addr, unsigned char val)
+{
+	writeb(val, addr);
+}
+
+unsigned long io_inb(unsigned long port)
+{
+	return inb(port);
+}
+
+void io_outb(unsigned long port, unsigned char val)
+{
+	outb(val, port);
+}
+
+unsigned long serial_init(int chan, void *ignored)
+{
+	unsigned long com_port;
+
+	/* We need to find out which type io we're expecting.  If it's
+	 * 'SERIAL_IO_PORT', we get an offset from the isa_io_base.
+	 * If it's 'SERIAL_IO_MEM', we can the exact location.  -- Tom */
+	switch (rs_table[chan].io_type) {
+		case SERIAL_IO_PORT:
+			com_port = rs_table[chan].port;
+			serial_outb = io_outb;
+			serial_inb = io_inb;
+			break;
+		case SERIAL_IO_MEM:
+			com_port = (unsigned long)rs_table[chan].iomem_base;
+			serial_outb = direct_outb;
+			serial_inb = direct_inb;
+			break;
+		default:
+			/* We can't deal with it. */
+			return -1;
+	}
+
+	/* How far apart the registers are. */
+	shift = rs_table[chan].iomem_reg_shift;
+	
+	/* Access baud rate */
+	serial_outb(com_port + (UART_LCR << shift), 0x80);
+
+	/* Input clock. */
+	serial_outb(com_port + (UART_DLL << shift),
+			(rs_table[chan].baud_base / SERIAL_BAUD) & 0xFF);
+	serial_outb(com_port + (UART_DLM << shift),
+			(rs_table[chan].baud_base / SERIAL_BAUD) >> 8);
+	/* 8 data, 1 stop, no parity */
+	serial_outb(com_port + (UART_LCR << shift), 0x03);
+	/* RTS/DTR */
+	serial_outb(com_port + (UART_MCR << shift), 0x03);
+
+	/* Clear & enable FIFOs */
+	serial_outb(com_port + (UART_FCR << shift), 0x07);
+
+	return (com_port);
+}
+
+void
+serial_putc(unsigned long com_port, unsigned char c)
+{
+	while ((serial_inb(com_port + (UART_LSR << shift)) & UART_LSR_THRE) == 0)
+		;
+	serial_outb(com_port, c);
+}
+
+unsigned char
+serial_getc(unsigned long com_port)
+{
+	while ((serial_inb(com_port + (UART_LSR << shift)) & UART_LSR_DR) == 0)
+		;
+	return serial_inb(com_port);
+}
+
+int
+serial_tstc(unsigned long com_port)
+{
+	return ((serial_inb(com_port + (UART_LSR << shift)) & UART_LSR_DR) != 0);
+}
+
+void
+serial_close(unsigned long com_port)
+{
+}
+
+void
+gen550_init(int i, struct serial_struct *serial_req)
+{
+	rs_table[i].io_type = serial_req->io_type;
+	rs_table[i].iomem_base = serial_req->iomem_base;
+	rs_table[i].iomem_reg_shift = serial_req->iomem_reg_shift;
+}
+
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+void
+gen550_progress(char *s, unsigned short hex)
+{
+	volatile unsigned int progress_debugport;
+	volatile char c;
+
+	progress_debugport = serial_init(0, NULL);
+
+	serial_putc(progress_debugport, '\r');
+
+	while ((c = *s++) != 0)
+		serial_putc(progress_debugport, c);
+
+	serial_putc(progress_debugport, '\n');
+	serial_putc(progress_debugport, '\r');
+}
+#endif /* CONFIG_SERIAL_TEXT_DEBUG */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/gen550_kgdb.c linux-2.4.21-pre6/arch/ppc/kernel/gen550_kgdb.c
--- linux-2.4.20/arch/ppc/kernel/gen550_kgdb.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/gen550_kgdb.c	2003-03-26 23:49:30.000000000 +0000
@@ -0,0 +1,84 @@
+/*
+ * arch/ppc/kernel/gen550_kgdb.c
+ *
+ * Generic 16550 kgdb support intended to be useful on a variety
+ * of platforms.  To enable this support, it is necessary to set
+ * the CONFIG_GEN550 option.  Any virtual mapping of the serial
+ * port(s) to be used can be accomplished by setting
+ * ppc_md.early_serial_map to a platform-specific mapping function.
+ *
+ * Adapted from ppc4xx_kgdb.c. 
+ *
+ * Matt Porter <mporter@mvista.com>
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#include <asm/machdep.h>
+
+extern unsigned long serial_init(int, void *);
+extern unsigned long serial_getc(unsigned long);
+extern unsigned long serial_putc(unsigned long, unsigned char);
+
+#if defined(CONFIG_KGDB_TTYS0)
+#define KGDB_PORT 0
+#elif defined(CONFIG_KGDB_TTYS1)
+#define KGDB_PORT 1
+#elif defined(CONFIG_KGDB_TTYS2)
+#define KGDB_PORT 2
+#elif defined(CONFIG_KGDB_TTYS3)
+#define KGDB_PORT 3
+#else
+#error "invalid kgdb_tty port"
+#endif
+
+static volatile unsigned int kgdb_debugport;
+
+void putDebugChar(unsigned char c)
+{
+	if (kgdb_debugport == 0)
+		kgdb_debugport = serial_init(KGDB_PORT, NULL);
+
+	serial_putc(kgdb_debugport, c);
+}
+
+int getDebugChar(void)
+{
+	if (kgdb_debugport == 0)
+		kgdb_debugport = serial_init(KGDB_PORT, NULL);
+
+	return(serial_getc(kgdb_debugport));
+}
+
+void kgdb_interruptible(int enable)
+{
+	return;
+}
+
+void putDebugString(char* str)
+{
+	while (*str != '\0') {
+		putDebugChar(*str);
+		str++;
+	}
+	putDebugChar('\r');
+	return;
+}
+
+void
+kgdb_map_scc(void)
+{
+	printk("kgdb init\n");
+	if (ppc_md.early_serial_map)
+		ppc_md.early_serial_map();
+	kgdb_debugport = serial_init(KGDB_PORT, NULL);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/head.S linux-2.4.21-pre6/arch/ppc/kernel/head.S
--- linux-2.4.20/arch/ppc/kernel/head.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/head.S	2003-03-26 23:48:58.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
  *
@@ -853,11 +850,11 @@
 	RFI
 
 /*
- * Disable FP for the task which had the FPU previously,
+ * This task wants to use the FPU now.
+ * On UP, disable FP for the task which had the FPU previously,
  * and save its floating-point registers in its thread_struct.
- * Enables the FPU for use in the kernel on return.
- * On SMP we know the fpu is free, since we give it up every
- * switch.  -- Cort
+ * Load up this task's FP registers from its thread_struct,
+ * enable the FPU for the current task and return to the task.
  */
 load_up_fpu:
 	mfmsr	r5
@@ -874,14 +871,13 @@
  * to another.  Instead we call giveup_fpu in switch_to.
  */
 #ifndef CONFIG_SMP
-	lis	r6,0                    /* get __pa constant */
-	tophys(r6,r6)
+	tophys(r6,0)			/* get __pa constant */
 	addis	r3,r6,last_task_used_math@ha
 	lwz	r4,last_task_used_math@l(r3)
 	cmpi	0,r4,0
 	beq	1f
 	add	r4,r4,r6
-	addi	r4,r4,THREAD	        /* want THREAD of last_task_used_math */
+	addi	r4,r4,THREAD		/* want last_task_used_math->thread */
 	SAVE_32FPRS(0, r4)
 	mffs	fr0
 	stfd	fr0,THREAD_FPSCR-4(r4)
@@ -894,8 +890,10 @@
 1:
 #endif /* CONFIG_SMP */
 	/* enable use of FP after return */
-	ori	r23,r23,MSR_FP|MSR_FE0|MSR_FE1
 	mfspr	r5,SPRG3		/* current task's THREAD (phys) */
+	lwz	r4,THREAD_FPEXC_MODE(r5)
+	ori	r23,r23,MSR_FP		/* enable FP for current */
+	or	r23,r23,r4
 	lfd	fr0,THREAD_FPSCR-4(r5)
 	mtfsf	0xff,fr0
 	REST_32FPRS(0, r5)
@@ -1077,7 +1075,7 @@
 	ori	r5,r5,MSR_FP
 	SYNC
 	mtmsr	r5			/* enable use of fpu now */
-	SYNC
+	SYNC_601
 	isync
 	cmpi	0,r3,0
 	beqlr-				/* if no previous owner, done */
@@ -1348,12 +1346,14 @@
 	blr
 _GLOBAL(__setup_cpu_7400)
 	mflr	r4
+	bl	setup_7400_workarounds
 	bl	setup_common_caches
 	bl	setup_750_7400_hid0
 	mtlr	r4
 	blr
 _GLOBAL(__setup_cpu_7410)
 	mflr	r4
+	bl	setup_7410_workarounds
 	bl	setup_common_caches
 	bl	setup_750_7400_hid0
 	li	r3,0
@@ -1414,6 +1414,47 @@
 	isync
 	blr
 
+/* 7400 <= rev 2.7 and 7410 rev = 1.0 suffer from some
+ * erratas we work around here.
+ * Moto MPC710CE.pdf describes them, those are errata
+ * #3, #4 and #5
+ * Note that we assume the firmware didn't choose to
+ * apply other workarounds (there are other ones documented
+ * in the .pdf). It appear that Apple firmware only works
+ * around #3 and with the same fix we use. We may want to
+ * check if the CPU is using 60x bus mode in which case
+ * the workaround for errata #4 is useless. Also, we may
+ * want to explicitely clear HID0_NOPDST as this is not
+ * needed once we have applied workaround #5 (though it's
+ * not set by Apple's firmware at least).
+ */
+setup_7400_workarounds:
+	mfpvr	r3
+	rlwinm	r3,r3,0,20,31
+	cmpwi	0,r3,0x0207
+	ble	1f
+	blr
+setup_7410_workarounds:
+	mfpvr	r3
+	rlwinm	r3,r3,0,20,31
+	cmpwi	0,r3,0x0100
+	bnelr
+1:
+	mfspr	r11,SPRN_MSSSR0
+	/* Errata #3: Set L1OPQ_SIZE to 0x10 */
+	rlwinm	r11,r11,0,9,6
+	oris	r11,r11,0x0100
+	/* Errata #4: Set L2MQ_SIZE to 1 (check for MPX mode first ?) */
+	oris	r11,r11,0x0002
+	/* Errata #5: Set DRLT_SIZE to 0x01 */
+	rlwinm	r11,r11,0,5,2
+	oris	r11,r11,0x0800
+	sync
+	mtspr	SPRN_MSSSR0,r11
+	sync
+	isync
+	blr
+	
 /* 740/750/7400/7410
  * Enable Store Gathering (SGE), Address Brodcast (ABE),
  * Branch History Table (BHTE), Branch Target ICache (BTIC)
@@ -1423,7 +1464,9 @@
 setup_750_7400_hid0:
 	mfspr	r11,HID0
 	ori	r11,r11,HID0_SGE | HID0_ABE | HID0_BHTE | HID0_BTIC
+BEGIN_FTR_SECTION
 	oris	r11,r11,HID0_DPM@h	/* enable dynamic power mgmt */
+END_FTR_SECTION_IFCLR(CPU_FTR_NO_DPM)
 	li	r3,HID0_SPD
 	andc	r11,r11,r3		/* clear SPD: enable speculative */
  	li	r3,0
@@ -1439,6 +1482,18 @@
  * (waiting for confirmation)
  */
 setup_750cx:
+	mfspr	r10, SPRN_HID1
+	rlwinm	r10,r10,4,28,31
+	cmpi	cr0,r10,7
+	cmpi	cr1,r10,9
+	cmpi	cr2,r10,11
+	cror	4*cr0+eq,4*cr0+eq,4*cr1+eq
+	cror	4*cr0+eq,4*cr0+eq,4*cr2+eq
+	bnelr
+	lwz	r6,CPU_SPEC_FEATURES(r5)
+	li	r7,CPU_FTR_CAN_NAP
+	andc	r6,r6,r7
+	stw	r6,CPU_SPEC_FEATURES(r5)
 	blr
 
 /* 750fx specific
@@ -1476,7 +1531,9 @@
 	/* All of the bits we have to set.....
 	 */
 	ori	r11,r11,HID0_SGE | HID0_FOLD | HID0_BHTE | HID0_BTIC | HID0_LRSTK
+BEGIN_FTR_SECTION
 	oris	r11,r11,HID0_DPM@h	/* enable dynamic power mgmt */
+END_FTR_SECTION_IFCLR(CPU_FTR_NO_DPM)
 
 	/* All of the bits we have to clear....
 	 */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/head_4xx.S linux-2.4.21-pre6/arch/ppc/kernel/head_4xx.S
--- linux-2.4.20/arch/ppc/kernel/head_4xx.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/head_4xx.S	2003-03-26 23:49:35.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.head_4xx.S 1.6 05/21/01 11:50:00 paulus
- */
-/*
  *    Copyright (c) 1995-1996 Gary Thomas <gdt@linuxppc.org>
  *      Initial PowerPC version.
  *    Copyright (c) 1996 Cort Dougan <cort@cs.nmt.edu>
@@ -70,6 +67,14 @@
 	.text
 _GLOBAL(_stext)
 _GLOBAL(_start)
+
+	/* To accomodate some SMP systems that overwrite the first few
+	 * locations before cpu 0 starts, the bootloader starts us at 0xc.
+	 */
+	nop
+	nop
+	nop
+
 	## Save residual data, init RAM disk, and command line parameters
 	
 	mr	r31,r3
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/head_8xx.S linux-2.4.21-pre6/arch/ppc/kernel/head_8xx.S
--- linux-2.4.20/arch/ppc/kernel/head_8xx.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/head_8xx.S	2003-03-26 23:49:35.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/kernel/except_8xx.S
  *
  *  PowerPC version 
@@ -82,6 +79,12 @@
 
 	.globl	__start
 __start:
+	/* To accomodate some SMP systems that overwrite the first few
+	 * locations before cpu 0 starts, the bootloader starts us at 0xc.
+	 */
+	nop
+	nop
+	nop
 	mr	r31,r3			/* save parameters */
 	mr	r30,r4
 	mr	r29,r5
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/i8259.c linux-2.4.21-pre6/arch/ppc/kernel/i8259.c
--- linux-2.4.20/arch/ppc/kernel/i8259.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/i8259.c	2003-03-26 23:49:35.000000000 +0000
@@ -1,7 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
-
 #include <linux/stddef.h>
 #include <linux/init.h>
 #include <linux/irq.h>
@@ -21,17 +17,37 @@
 
 int i8259_pic_irq_offset;
 
-/* Acknowledge the irq using the PCI host bridge's interrupt acknowledge
- * feature. (Polling is somehow broken on some IBM and Motorola PReP boxes.)
+/*
+ * Acknowledge the IRQ using either the PCI host bridge's interrupt
+ * acknowledge feature or poll.  How i8259_init() is called determines
+ * which is called.  It should be noted that polling is broken on some
+ * IBM and Motorola PReP boxes so we must use the int-ack feature on them.
  */
-int i8259_irq(struct pt_regs *regs)
+int
+i8259_irq(struct pt_regs *regs)
 {
 	int irq;
 
-	spin_lock/*_irqsave*/(&i8259_lock/*, flags*/);
+	spin_lock(&i8259_lock);
 
-	irq = *pci_intack;
-	if (irq==7) {
+	/* Either int-ack or poll for the IRQ */
+	if (pci_intack)
+		irq = *pci_intack;
+	else {
+		/* Perform an interrupt acknowledge cycle on controller 1. */
+		outb(0x0C, 0x20);		/* prepare for poll */
+		irq = inb(0x20) & 7;
+		if (irq == 2 ) {
+			/*
+			 * Interrupt is cascaded so perform interrupt
+			 * acknowledge on controller 2.
+			 */
+			outb(0x0C, 0xA0);	/* prepare for poll */
+			irq = (inb(0xA0) & 7) + 8;
+		}
+	}
+
+	if (irq == 7) {
 		/*
 		 * This may be a spurious interrupt.
 		 *
@@ -39,47 +55,13 @@
 		 * significant bit is not set then there is no valid
 		 * interrupt.
 		 */
-		if(~inb(0x20)&0x80) {
+		if (!pci_intack)
+			outb(0x0B, 0x20);	/* ISR register */
+		if(~inb(0x20) & 0x80)
 			irq = -1;
-		}
 	}
-	spin_unlock/*_irqrestore*/(&i8259_lock/*, flags*/);
-	return irq;
-}
 
-/* Poke the 8259's directly using poll commands. */
-int i8259_poll(struct pt_regs *regs)
-{
-	int irq;
-
-	spin_lock/*_irqsave*/(&i8259_lock/*, flags*/);
-	/*
-	 * Perform an interrupt acknowledge cycle on controller 1
-	 */
-	outb(0x0C, 0x20); /* prepare for poll */
-	irq = inb(0x20) & 7;
-	if (irq == 2) {
-		/*
-		 * Interrupt is cascaded so perform interrupt
-		 * acknowledge on controller 2
-		 */
-		outb(0x0C, 0xA0); /* prepare for poll */
-		irq = (inb(0xA0) & 7) + 8;
-	} else if (irq==7) {
-		/*
-		 * This may be a spurious interrupt
-		 *
-		 * Read the interrupt status register. If the most
-		 * significant bit is not set then there is no valid
-		 * interrupt
-		 */
-		outb(0x0b, 0x20);
-		if(~inb(0x20)&0x80) {
-			spin_unlock/*_irqrestore*/(&i8259_lock/*, flags*/);
-			return -1;
-		}
-	}
-	spin_unlock/*_irqrestore*/(&i8259_lock/*, flags*/);
+	spin_unlock(&i8259_lock);
 	return irq;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/idle.c linux-2.4.21-pre6/arch/ppc/kernel/idle.c
--- linux-2.4.20/arch/ppc/kernel/idle.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/idle.c	2003-03-26 23:48:58.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Idle daemon for PowerPC.  Idle daemon will handle any action
  * that needs to be taken when the system becomes idle.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/idle_6xx.S linux-2.4.21-pre6/arch/ppc/kernel/idle_6xx.S
--- linux-2.4.20/arch/ppc/kernel/idle_6xx.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/idle_6xx.S	2003-03-26 23:49:40.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  This file contains the power_save function for 6xx & 7xxx CPUs
  *  rewritten in assembler
  *
@@ -107,13 +104,23 @@
 	andis.	r0,r3,HID0_NAP@h
 	beq	2f
 BEGIN_FTR_SECTION
-	/* Disable L2 prefetch on some 745x */
+	/* Disable L2 prefetch on some 745x and try to ensure
+	 * L2 prefetch engines are idle. As explained by errata
+	 * text, we can't be sure they are, we just hope very hard
+	 * that well be enough (sic !). At least I noticed Apple
+	 * doesn't even bother doing the dcbf's here...
+	 */
 	mfspr	r4,SPRN_MSSCR0
 	rlwinm	r4,r4,0,0,29
 	sync
 	mtspr	SPRN_MSSCR0,r4
 	sync
 	isync
+	lis	r4,KERNELBASE@h
+	dcbf	0,r4
+	dcbf	0,r4
+	dcbf	0,r4
+	dcbf	0,r4
 END_FTR_SECTION_IFSET(CPU_FTR_NAP_DISABLE_L2_PR)
 #ifdef DEBUG
 	lis	r6,nap_enter_count@ha
@@ -142,7 +149,9 @@
 END_FTR_SECTION_IFSET(CPU_FTR_CAN_DOZE)
 	andc	r4,r4,r5
 	or	r4,r4,r3
-	oris	r4,r4,HID0_DPM@h	/* that should be done once for all ... */
+BEGIN_FTR_SECTION
+	oris	r4,r4,HID0_DPM@h	/* that should be done once for all  */
+END_FTR_SECTION_IFCLR(CPU_FTR_NO_DPM)
 	mtspr	SPRN_HID0,r4
 BEGIN_FTR_SECTION
 	DSSALL
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/indirect_pci.c linux-2.4.21-pre6/arch/ppc/kernel/indirect_pci.c
--- linux-2.4.20/arch/ppc/kernel/indirect_pci.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/indirect_pci.c	2003-03-26 23:49:07.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Support for indirect PCI bridges.
  *
  * Copyright (C) 1998 Gabriel Paubert.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/irq.c linux-2.4.21-pre6/arch/ppc/kernel/irq.c
--- linux-2.4.20/arch/ppc/kernel/irq.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/irq.c	2003-03-26 23:49:20.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/kernel/irq.c
  *
  *  Derived from arch/i386/kernel/irq.c
@@ -177,15 +174,6 @@
 	return 0;
 }
 
-#if (defined(CONFIG_8xx) || defined(CONFIG_8260))
-/* Name change so we can catch standard drivers that potentially mess up
- * the internal interrupt controller on 8xx and 8260.  Just bear with me,
- * I don't like this either and I am searching a better solution.  For
- * now, this is what I need. -- Dan
- */
-#define request_irq	request_8xxirq
-#endif
-
 void free_irq(unsigned int irq, void* dev_id)
 {
 	irq_desc_t *desc;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/m8260_setup.c linux-2.4.21-pre6/arch/ppc/kernel/m8260_setup.c
--- linux-2.4.20/arch/ppc/kernel/m8260_setup.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/m8260_setup.c	2003-03-26 23:49:39.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  linux/arch/ppc/kernel/setup.c
  *
  *  Copyright (C) 1995  Linus Torvalds
@@ -269,11 +266,3 @@
 	ppc_md.ppc_kbd_sysrq_xlate	= NULL;
 }
 
-/* Mainly for ksyms.
-*/
-int
-request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
-		       unsigned long flag, const char *naem, void *dev)
-{
-	panic("request IRQ\n");
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/m8xx_setup.c linux-2.4.21-pre6/arch/ppc/kernel/m8xx_setup.c
--- linux-2.4.20/arch/ppc/kernel/m8xx_setup.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/m8xx_setup.c	2003-03-26 23:49:34.000000000 +0000
@@ -1,6 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- *
  *  linux/arch/ppc/kernel/setup.c
  *
  *  Copyright (C) 1995  Linus Torvalds
@@ -48,6 +46,8 @@
 
 #include "ppc8xx_pic.h"
 
+extern int i8259_pic_irq_offset; /* defined in arch/ppc/kernel/i8259.c */
+
 static int m8xx_set_rtc_time(unsigned long time);
 static unsigned long m8xx_get_rtc_time(void);
 void m8xx_calibrate_decr(void);
@@ -63,9 +63,9 @@
 m8xx_setup_arch(void)
 {
 	int	cpm_page;
-	
+
 	cpm_page = (int) alloc_bootmem_pages(PAGE_SIZE);
-	
+
 	/* Reset the Communication Processor Module.
 	*/
 	m8xx_cpm_reset(cpm_page);
@@ -73,10 +73,10 @@
 #ifdef notdef
 	ROOT_DEV = to_kdev_t(0x0301); /* hda1 */
 #endif
-	
+
 #ifdef CONFIG_BLK_DEV_INITRD
 #if 0
-	ROOT_DEV = to_kdev_t(0x0200); /* floppy */  
+	ROOT_DEV = to_kdev_t(0x0200); /* floppy */
 	rd_prompt = 1;
 	rd_doload = 1;
 	rd_image_start = 0;
@@ -106,6 +106,9 @@
 	xmon(0);
 #endif
 	machine_restart(NULL);
+
+	/* not reached */
+	for (;;);
 }
 
 /* A place holder for time base interrupts, if they are ever enabled. */
@@ -178,7 +181,8 @@
 				((mk_int_int_mask(DEC_INTERRUPT) << 8) |
 					 (TBSCR_TBF | TBSCR_TBE));
 
-	if (request_8xxirq(DEC_INTERRUPT, timebase_interrupt, 0, "tbint", NULL) != 0)
+	if (request_irq(DEC_INTERRUPT, timebase_interrupt, 0, "tbint",
+				NULL) != 0)
 		panic("Could not allocate timer IRQ!");
 }
 
@@ -218,7 +222,7 @@
 	__asm__("mtmsr %0" : : "r" (msr) );
 
 	dummy = ((immap_t *)IMAP_ADDR)->im_clkrst.res[0];
-	printk("Restart failed\n"); 
+	printk("Restart failed\n");
 	while(1);
 }
 
@@ -241,9 +245,9 @@
 	bd_t	*bp;
 
 	bp = (bd_t *)__res;
-			
-	seq_printf(m, "clock\t\t: %ldMHz\n"
-		   "bus clock\t: %ldMHz\n",
+
+	seq_printf(m, "clock\t\t: %dMHz\n"
+		   "bus clock\t: %dMHz\n",
 		   bp->bi_intfreq / 1000000,
 		   bp->bi_busfreq / 1000000);
 
@@ -262,23 +266,26 @@
 	int i;
 	void cpm_interrupt_init(void);
 
-        for ( i = 0 ; i < NR_SIU_INTS ; i++ )
-                irq_desc[i].handler = &ppc8xx_pic;
-	
-	/* We could probably incorporate the CPM into the multilevel
-	 * interrupt structure.
-	 */
+	for (i = SIU_IRQ_OFFSET ; i < SIU_IRQ_OFFSET + NR_SIU_INTS ; i++)
+		irq_desc[i].handler = &ppc8xx_pic;
+
 	cpm_interrupt_init();
-        unmask_irq(CPM_INTERRUPT);
 
 #if defined(CONFIG_PCI)
-        for ( i = NR_SIU_INTS ; i < (NR_SIU_INTS + NR_8259_INTS) ; i++ )
-                irq_desc[i].handler = &i8259_pic;
-        i8259_pic.irq_offset = NR_SIU_INTS;
-        i8259_init();
-        request_8xxirq(ISA_BRIDGE_INT, mbx_i8259_action, 0, "8259 cascade", NULL);
-        enable_irq(ISA_BRIDGE_INT);
-#endif
+	for (i = I8259_IRQ_OFFSET ; i < I8259_IRQ_OFFSET + NR_8259_INTS ; i++)
+		irq_desc[i].handler = &i8259_pic;
+
+	i8259_pic_irq_offset = I8259_IRQ_OFFSET;
+	i8259_init(0);
+
+	/* The i8259 cascade interrupt must be level sensitive. */
+	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_siel &= 
+		~(0x80000000 >> ISA_BRIDGE_INT);
+
+	if (request_irq(ISA_BRIDGE_INT, mbx_i8259_action, 0, "i8259 cascade",
+				NULL) != 0)
+		panic("Could not allocate 8259 IRQ!");
+#endif	/* CONFIG_PCI */
 }
 
 /* -------------------------------------------------------------------- */
@@ -297,7 +304,7 @@
 {
 	bd_t	*binfo;
 	extern unsigned char __res[];
-	
+
 	binfo = (bd_t *)__res;
 
 	return binfo->bi_memsize;
@@ -348,7 +355,7 @@
 
 	if ( r3 )
 		memcpy( (void *)__res,(void *)(r3+KERNELBASE), sizeof(bd_t) );
-	
+
 #ifdef CONFIG_PCI
 	m8xx_setup_pci_ptrs();
 #endif
@@ -363,7 +370,7 @@
 #endif /* CONFIG_BLK_DEV_INITRD */
 	/* take care of cmd line */
 	if ( r6 )
-	{	
+	{
 		*(char *)(r7+KERNELBASE) = 0;
 		strcpy(cmd_line, (char *)(r6+KERNELBASE));
 	}
@@ -397,5 +404,5 @@
 
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
 	m8xx_ide_init();
-#endif		
+#endif
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/misc.S linux-2.4.21-pre6/arch/ppc/kernel/misc.S
--- linux-2.4.20/arch/ppc/kernel/misc.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/misc.S	2003-03-26 23:49:29.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * This file contains miscellaneous low-level functions.
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
  *
@@ -364,6 +361,7 @@
 10:	lwarx	r7,0,r9
 	cmpi	0,r7,0
 	bne-	10b
+	/* No 405 Erratum 77 fix needed here, because 4xx can't do SMP */
 	stwcx.	r8,0,r9
 	bne-	10b
 #endif /* CONFIG_SMP */
@@ -651,6 +649,7 @@
 _GLOBAL(xchg_u32)
 	mr	r5,r3		/* Save pointer */
 10:	lwarx	r3,0,r5		/* Fetch old value & reserve */
+	PPC405_ERR77(0,r5)
 	stwcx.	r4,0,r5		/* Update with new value */
 	bne-	10b		/* Retry if "reservation" (i.e. lock) lost */
 	blr
@@ -662,12 +661,14 @@
 _GLOBAL(atomic_clear_mask)
 10:	lwarx	r5,0,r4
 	andc	r5,r5,r3
+	PPC405_ERR77(0,r4)
 	stwcx.	r5,0,r4
 	bne-	10b
 	blr
 _GLOBAL(atomic_set_mask)
 10:	lwarx	r5,0,r4
 	or	r5,r5,r3
+	PPC405_ERR77(0,r4)
 	stwcx.	r5,0,r4
 	bne-	10b
 	blr
@@ -898,9 +899,9 @@
 
 /*
  * Create a kernel thread
- *   kernel_thread(fn, arg, flags)
+ *   arch_kernel_thread(fn, arg, flags)
  */
-_GLOBAL(kernel_thread)
+_GLOBAL(arch_kernel_thread)
 	mr	r6,r3		/* function */
 	ori	r3,r5,CLONE_VM	/* flags */
 	li	r0,__NR_clone
@@ -1062,10 +1063,10 @@
 	.long sys_newlstat
 	.long sys_newfstat
 	.long sys_uname
-	.long sys_iopl		/* 110 */
+	.long sys_ni_syscall	/* 110 old iopl syscall */
 	.long sys_vhangup
 	.long sys_ni_syscall	/* old 'idle' syscall */
-	.long sys_vm86
+	.long sys_ni_syscall	/* old vm86 syscall */
 	.long sys_wait4
 	.long sys_swapoff	/* 115 */
 	.long sys_sysinfo
@@ -1075,7 +1076,7 @@
 	.long sys_clone		/* 120 */
 	.long sys_setdomainname
 	.long sys_newuname
-	.long sys_modify_ldt
+	.long sys_ni_syscall	/* old modify_ldt syscall */
 	.long sys_adjtimex
 	.long sys_mprotect	/* 125 */
 	.long sys_sigprocmask
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/mk_defs.c linux-2.4.21-pre6/arch/ppc/kernel/mk_defs.c
--- linux-2.4.20/arch/ppc/kernel/mk_defs.c	2001-08-28 13:58:33.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/mk_defs.c	2003-03-26 23:49:40.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.mk_defs.c 1.11 08/19/01 22:43:23 paulus
- */
-/*
  * This program is used to generate definitions needed by
  * assembly language modules.
  *
@@ -52,6 +49,7 @@
 	DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
 	DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
 	DEFINE(NEED_RESCHED, offsetof(struct task_struct, need_resched));
+	DEFINE(THREAD_FPEXC_MODE, offsetof(struct thread_struct, fpexc_mode));
 	DEFINE(THREAD_FPR0, offsetof(struct thread_struct, fpr[0]));
 	DEFINE(THREAD_FPSCR, offsetof(struct thread_struct, fpscr));
 #ifdef CONFIG_ALTIVEC
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/mpc10x_common.c linux-2.4.21-pre6/arch/ppc/kernel/mpc10x_common.c
--- linux-2.4.20/arch/ppc/kernel/mpc10x_common.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/mpc10x_common.c	2003-03-26 23:49:40.000000000 +0000
@@ -0,0 +1,402 @@
+
+/*
+ * arch/ppc/kernel/mpc10x_common.c
+ * 
+ * Common routines for the Motorola SPS MPC106, MPC107 and MPC8240 Host bridge,
+ * Mem ctlr, EPIC, etc.
+ *
+ * Author: Mark A. Greer
+ *         mgreer@mvista.com
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+/*
+ * *** WARNING - A BAT MUST be set to access the PCI config addr/data regs ***
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <asm/open_pic.h>
+#include <asm/mpc10x.h>
+
+
+/* Set resources to match bridge memory map */
+void __init
+mpc10x_bridge_set_resources(int map, struct pci_controller *hose)
+{
+
+	switch (map) {
+		case MPC10X_MEM_MAP_A:
+			pci_init_resource(&hose->io_resource,
+					0x00000000,
+					0x3f7fffff,
+					IORESOURCE_IO,
+					"PCI host bridge");
+
+			pci_init_resource (&hose->mem_resources[0],
+					0xc0000000,
+					0xfeffffff,
+					IORESOURCE_MEM,
+					"PCI host bridge");
+			break;
+		case MPC10X_MEM_MAP_B:
+			pci_init_resource(&hose->io_resource,
+					0x00000000,
+					0x00bfffff,
+					IORESOURCE_IO,
+					"PCI host bridge");
+
+			pci_init_resource (&hose->mem_resources[0],
+					0x80000000,
+					0xfcffffff,
+					IORESOURCE_MEM,
+					"PCI host bridge");
+			break;
+		default:
+			printk("mpc10x_bridge_set_resources: "
+					"Invalid map specified\n");
+			if (ppc_md.progress)
+				ppc_md.progress("mpc10x:exit1", 0x100);
+	}
+}
+/*
+ * Do some initialization and put the EUMB registers at the specified address
+ * (also map the EPIC registers into virtual space--OpenPIC_Addr will be set).
+ *
+ * The EPIC is not on the 106, only the 8240 and 107.
+ */
+int __init
+mpc10x_bridge_init(struct pci_controller *hose,
+		   uint current_map,
+		   uint new_map,
+		   uint phys_eumb_base)
+{
+	int	host_bridge, picr1, picr1_bit;
+	ulong	pci_config_addr, pci_config_data;
+	u_char	pir, byte;
+
+	if (ppc_md.progress) ppc_md.progress("mpc10x:enter", 0x100);
+
+	/* Set up for current map so we can get at config regs */
+	switch (current_map) {
+		case MPC10X_MEM_MAP_A:
+			setup_indirect_pci(hose,
+					   MPC10X_MAPA_CNFG_ADDR,
+					   MPC10X_MAPA_CNFG_DATA);
+			break;
+		case MPC10X_MEM_MAP_B:
+			setup_indirect_pci(hose,
+					   MPC10X_MAPB_CNFG_ADDR,
+					   MPC10X_MAPB_CNFG_DATA);
+			break;
+		default:
+			printk("mpc10x_bridge_init: %s\n",
+				"Invalid current map specified");
+			if (ppc_md.progress)
+				ppc_md.progress("mpc10x:exit1", 0x100);
+			return -1;
+	}
+
+	/* Make sure its a supported bridge */
+	early_read_config_dword(hose,
+			        0,
+			        PCI_DEVFN(0,0),
+			        PCI_VENDOR_ID,
+			        &host_bridge);
+
+	switch (host_bridge) {
+		case MPC10X_BRIDGE_106:
+		case MPC10X_BRIDGE_8240:
+		case MPC10X_BRIDGE_107:
+		case MPC10X_BRIDGE_8245:
+			break;
+		default:
+			if (ppc_md.progress)
+				ppc_md.progress("mpc10x:exit2", 0x100);
+			return -1;
+	}
+
+	switch (new_map) {
+		case MPC10X_MEM_MAP_A:
+			MPC10X_SETUP_HOSE(hose, A);
+			pci_config_addr = MPC10X_MAPA_CNFG_ADDR;
+			pci_config_data = MPC10X_MAPA_CNFG_DATA;
+			picr1_bit = MPC10X_CFG_PICR1_ADDR_MAP_A;
+			break;
+		case MPC10X_MEM_MAP_B:
+			MPC10X_SETUP_HOSE(hose, B);
+			pci_config_addr = MPC10X_MAPB_CNFG_ADDR;
+			pci_config_data = MPC10X_MAPB_CNFG_DATA;
+			picr1_bit = MPC10X_CFG_PICR1_ADDR_MAP_B;
+			break;
+		default:
+			printk("mpc10x_bridge_init: %s\n",
+				"Invalid new map specified");
+			if (ppc_md.progress)
+				ppc_md.progress("mpc10x:exit3", 0x100);
+			return -1;
+	}
+
+	/* Make bridge use the 'new_map', if not already usng it */
+	if (current_map != new_map) {
+		early_read_config_dword(hose,
+					0,
+					PCI_DEVFN(0,0),
+					MPC10X_CFG_PICR1_REG,
+					&picr1);
+
+		picr1 = (picr1 & ~MPC10X_CFG_PICR1_ADDR_MAP_MASK) |
+			 picr1_bit;
+
+		early_write_config_dword(hose,
+					 0,
+					 PCI_DEVFN(0,0),
+					 MPC10X_CFG_PICR1_REG,
+					 picr1);
+
+		asm volatile("sync");
+
+		/* Undo old mappings & map in new cfg data/addr regs */
+		iounmap((void *)hose->cfg_addr);
+		iounmap((void *)hose->cfg_data);
+
+		setup_indirect_pci(hose,
+				   pci_config_addr,
+				   pci_config_data);
+	}
+
+	/* Setup resources to match map */
+	mpc10x_bridge_set_resources(new_map, hose);
+
+	/*
+	 * Want processor accesses of 0xFDxxxxxx to be mapped
+	 * to PCI memory space at 0x00000000.  Do not want
+	 * host bridge to respond to PCI memory accesses of
+	 * 0xFDxxxxxx.  Do not want host bridge to respond
+	 * to PCI memory addresses 0xFD000000-0xFDFFFFFF;
+	 * want processor accesses from 0x000A0000-0x000BFFFF
+	 * to be forwarded to system memory.
+	 *
+	 * Only valid if not in agent mode and using MAP B.
+	 */
+	if (new_map == MPC10X_MEM_MAP_B) {
+		early_read_config_byte(hose,
+				       0,
+				       PCI_DEVFN(0,0),
+				       MPC10X_CFG_MAPB_OPTIONS_REG,
+				       &byte);
+
+		byte &= ~(MPC10X_CFG_MAPB_OPTIONS_PFAE  |
+			  MPC10X_CFG_MAPB_OPTIONS_PCICH |
+			  MPC10X_CFG_MAPB_OPTIONS_PROCCH);
+
+		if (host_bridge != MPC10X_BRIDGE_106) {
+			byte |= MPC10X_CFG_MAPB_OPTIONS_CFAE;
+		}
+
+		early_write_config_byte(hose,
+					0,
+					PCI_DEVFN(0,0),
+					MPC10X_CFG_MAPB_OPTIONS_REG,
+					byte);
+	}
+
+	if (host_bridge != MPC10X_BRIDGE_106) {
+		early_read_config_byte(hose,
+				       0,
+				       PCI_DEVFN(0,0),
+				       MPC10X_CFG_PIR_REG,
+				       &pir);
+
+		if (pir != MPC10X_CFG_PIR_HOST_BRIDGE) {
+			printk("Host bridge in Agent mode\n");
+			/* Read or Set LMBAR & PCSRBAR? */
+		}
+		       
+		/* Set base addr of the 8240/107 EUMB.  */
+		early_write_config_dword(hose,
+					 0,
+					 PCI_DEVFN(0,0),
+					 MPC10X_CFG_EUMBBAR,
+					 phys_eumb_base);
+
+		/* Map EPIC register part of EUMB into vitual memory */
+		OpenPIC_Addr = 
+			ioremap(phys_eumb_base + MPC10X_EUMB_EPIC_OFFSET,
+				MPC10X_EUMB_EPIC_SIZE);
+	}
+
+#ifdef CONFIG_MPC10X_STORE_GATHERING
+	mpc10x_enable_store_gathering(hose);
+#else
+	mpc10x_disable_store_gathering(hose);
+#endif
+
+	if (ppc_md.progress) ppc_md.progress("mpc10x:exit", 0x100);
+	return 0;
+}
+
+/*
+ * Need to make our own PCI config space access macros because
+ * mpc10x_get_mem_size() is called before the data structures are set up for
+ * the 'early_xxx' and 'indirect_xxx' routines to work.
+ * Assumes bus 0.
+ */
+#define MPC10X_CFG_read(val, addr, type, op)	*val = op((type)(addr))
+#define MPC10X_CFG_write(val, addr, type, op)	op((type *)(addr), (val))
+
+#define MPC10X_PCI_OP(rw, size, type, op, mask)			 	\
+static void								\
+mpc10x_##rw##_config_##size(uint *cfg_addr, uint *cfg_data, int devfn, int offset, type val) \
+{									\
+	out_be32(cfg_addr, 						\
+		 ((offset & 0xfc) << 24) | (devfn << 16)		\
+		 | (0 << 8) | 0x80);					\
+	MPC10X_CFG_##rw(val, cfg_data + (offset & mask), type, op);	\
+	return;    					 		\
+}
+
+MPC10X_PCI_OP(read,  byte,  u8 *, in_8, 3)
+MPC10X_PCI_OP(read,  dword, u32 *, in_le32, 0)
+#if 0	/* Not used */
+MPC10X_PCI_OP(write, byte,  u8, out_8, 3)
+MPC10X_PCI_OP(read,  word,  u16 *, in_le16, 2)
+MPC10X_PCI_OP(write, word,  u16, out_le16, 2)
+MPC10X_PCI_OP(write, dword, u32, out_le32, 0)
+#endif
+
+/*
+ * Read the memory controller registers to determine the amount of memory in
+ * the system.  This assumes that the firmware has correctly set up the memory
+ * controller registers.
+ */
+unsigned long __init
+mpc10x_get_mem_size(uint mem_map)
+{
+	uint			*config_addr, *config_data, val;
+	ulong			start, end, total, offset;
+	int			i;
+	u_char			bank_enables;
+
+	switch (mem_map) {
+		case MPC10X_MEM_MAP_A:
+			config_addr = (uint *)MPC10X_MAPA_CNFG_ADDR;
+			config_data = (uint *)MPC10X_MAPA_CNFG_DATA;
+			break;
+		case MPC10X_MEM_MAP_B:
+			config_addr = (uint *)MPC10X_MAPB_CNFG_ADDR;
+			config_data = (uint *)MPC10X_MAPB_CNFG_DATA;
+			break;
+		default:
+			return 0;
+	}
+
+	mpc10x_read_config_byte(config_addr,
+				config_data,
+				PCI_DEVFN(0,0),
+			        MPC10X_MCTLR_MEM_BANK_ENABLES,
+			        &bank_enables);
+
+	total = 0;
+
+	for (i=0; i<8; i++) {
+		if (bank_enables & (1 << i)) {
+			offset = MPC10X_MCTLR_MEM_START_1 + ((i > 3) ? 4 : 0);
+			mpc10x_read_config_dword(config_addr,
+						 config_data,
+						 PCI_DEVFN(0,0),
+						 offset,
+						 &val);
+			start = (val >> ((i & 3) << 3)) & 0xff;
+
+			offset = MPC10X_MCTLR_EXT_MEM_START_1 + ((i>3) ? 4 : 0);
+			mpc10x_read_config_dword(config_addr,
+						 config_data,
+						 PCI_DEVFN(0,0),
+						 offset,
+						 &val);
+			val = (val >> ((i & 3) << 3)) & 0x03;
+			start = (val << 28) | (start << 20);
+
+			offset = MPC10X_MCTLR_MEM_END_1 + ((i > 3) ? 4 : 0);
+			mpc10x_read_config_dword(config_addr,
+						 config_data,
+						 PCI_DEVFN(0,0),
+						 offset,
+						 &val);
+			end = (val >> ((i & 3) << 3)) & 0xff;
+
+			offset = MPC10X_MCTLR_EXT_MEM_END_1 + ((i > 3) ? 4 : 0);
+			mpc10x_read_config_dword(config_addr,
+						 config_data,
+						 PCI_DEVFN(0,0),
+						 offset,
+						 &val);
+			val = (val >> ((i & 3) << 3)) & 0x03;
+			end = (val << 28) | (end << 20) | 0xfffff;
+
+			total += (end - start + 1);
+		}
+	}
+
+	return total;
+}
+
+int __init
+mpc10x_enable_store_gathering(struct pci_controller *hose)
+{
+	uint picr1;
+
+	early_read_config_dword(hose,
+				0,
+				PCI_DEVFN(0,0),
+			        MPC10X_CFG_PICR1_REG,
+			        &picr1);
+
+	picr1 |= MPC10X_CFG_PICR1_ST_GATH_EN;
+
+	early_write_config_dword(hose,
+				0,
+				PCI_DEVFN(0,0),
+				MPC10X_CFG_PICR1_REG,
+				picr1);
+
+	return 0;
+}
+
+int __init
+mpc10x_disable_store_gathering(struct pci_controller *hose)
+{
+	uint picr1;
+
+	early_read_config_dword(hose,
+				0,
+				PCI_DEVFN(0,0),
+			        MPC10X_CFG_PICR1_REG,
+			        &picr1);
+
+	picr1 &= ~MPC10X_CFG_PICR1_ST_GATH_EN;
+
+	early_write_config_dword(hose,
+				0,
+				PCI_DEVFN(0,0),
+				MPC10X_CFG_PICR1_REG,
+				picr1);
+
+	return 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/open_pic.c linux-2.4.21-pre6/arch/ppc/kernel/open_pic.c
--- linux-2.4.20/arch/ppc/kernel/open_pic.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/open_pic.c	2003-03-26 23:49:40.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/kernel/open_pic.c -- OpenPIC Interrupt Handling
  *
  *  Copyright (C) 1997 Geert Uytterhoeven
@@ -30,6 +27,11 @@
 
 void* OpenPIC_Addr;
 static volatile struct OpenPIC *OpenPIC = NULL;
+/*
+ * We define OpenPIC_InitSenses table thusly:
+ * bit 0x1: sense, 0 for edge and 1 for level.
+ * bit 0x2: polarity, 0 for negative, 1 for positive.
+ */
 u_int OpenPIC_NumInitSenses __initdata = 0;
 u_char *OpenPIC_InitSenses __initdata = NULL;
 extern int use_of_interrupt_tree;
@@ -38,7 +40,8 @@
 static u_int NumSources;
 static int open_pic_irq_offset;
 static volatile OpenPIC_Source *ISR[NR_IRQS];
-static volatile unsigned char* chrp_int_ack_special;
+static int openpic_cascade_irq = -1;
+static int (*openpic_cascade_fn)(struct pt_regs *);
 
 /* Global Operations */
 static void openpic_disable_8259_pass_through(void);
@@ -247,6 +250,31 @@
 }
 #endif /* CONFIG_SMP */
 
+#ifdef CONFIG_EPIC_SERIAL_MODE
+static void __init openpic_eicr_set_clk(u_int clkval)
+{
+	openpic_writefield(&OpenPIC->Global.Global_Configuration1,
+			OPENPIC_EICR_S_CLK_MASK, (clkval << 28));
+}
+
+static void __init openpic_enable_sie(void)
+{
+	openpic_setfield(&OpenPIC->Global.Global_Configuration1,
+			OPENPIC_EICR_SIE);
+}
+#endif
+
+#if defined(CONFIG_EPIC_SERIAL_MODE) || defined(CONFIG_PMAC_PBOOK)
+static void openpic_reset(void)
+{
+	openpic_setfield(&OpenPIC->Global.Global_Configuration0,
+			 OPENPIC_CONFIG_RESET);
+	while (openpic_readfield(&OpenPIC->Global.Global_Configuration0,
+				 OPENPIC_CONFIG_RESET))
+		mb();
+}
+#endif
+
 void __init openpic_set_sources(int first_irq, int num_irqs, void *first_ISR)
 {
 	volatile OpenPIC_Source *src = first_ISR;
@@ -261,8 +289,14 @@
 		ISR[i] = src;
 }
 
-void __init openpic_init(int main_pic, int offset, unsigned char* chrp_ack,
-			 int programmer_switch_irq)
+/*
+ * The `offset' parameter defines where the interrupts handled by the
+ * OpenPIC start in the space of interrupt numbers that the kernel knows
+ * about.  In other words, the OpenPIC's IRQ0 is numbered `offset' in the
+ * kernel's interrupt numbering scheme.
+ * We assume there is only one OpenPIC.
+ */
+void __init openpic_init(int offset)
 {
 	u_int t, i;
 	u_int timerfreq;
@@ -274,6 +308,12 @@
 	}
 	OpenPIC = (volatile struct OpenPIC *)OpenPIC_Addr;
 
+#ifdef CONFIG_EPIC_SERIAL_MODE
+	/* Have to start from ground zero.
+	*/
+	openpic_reset();
+#endif
+
 	if (ppc_md.progress) ppc_md.progress("openpic: enter", 0x122);
 
 	t = openpic_read(&OpenPIC->Global.Feature_Reporting0);
@@ -305,11 +345,7 @@
 		printk("OpenPIC timer frequency is %d.%06d MHz\n",
 		       timerfreq / 1000000, timerfreq % 1000000);
 
-	if (!main_pic)
-		return;
-
 	open_pic_irq_offset = offset;
-	chrp_int_ack_special = (volatile unsigned char*)chrp_ack;
 
 	/* Initialize timer interrupts */
 	if ( ppc_md.progress ) ppc_md.progress("openpic: timer",0x3ba);
@@ -333,19 +369,13 @@
 #endif
 
 	/* Initialize external interrupts */
-	if (ppc_md.progress) ppc_md.progress("openpic ext",0x3bc);
+	if (ppc_md.progress) ppc_md.progress("openpic: external",0x3bc);
 
 	openpic_set_priority(0xf);
 
-	/* SIOint (8259 cascade) is special */
-	if (offset) {
-		openpic_initirq(0, 8, offset, 1, 1);
-		openpic_mapirq(0, 1<<0, 0);
-	}
-
-	/* Init all external sources */
-	for (i = 1; i < NumSources; i++) {
-		int pri, sense;
+	/* Init all external sources, including possibly the cascade. */
+	for (i = 0; i < NumSources; i++) {
+		int sense;
 
 		if (ISR[i] == 0)
 			continue;
@@ -353,13 +383,15 @@
 		/* the bootloader may have left it enabled (bad !) */
 		openpic_disable_irq(i+offset);
 
-		pri = (i == programmer_switch_irq)? 9: 8;
-		sense = (i < OpenPIC_NumInitSenses)? OpenPIC_InitSenses[i]: 1;
-		if (sense)
+		sense = (i < OpenPIC_NumInitSenses)? OpenPIC_InitSenses[i]: \
+				(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE);
+
+		if (sense & IRQ_SENSE_MASK)
 			irq_desc[i+offset].status = IRQ_LEVEL;
 
-		/* Enabled, Priority 8 or 9 */
-		openpic_initirq(i, pri, i+offset, !sense, sense);
+		/* Enabled, Priority 8 */
+		openpic_initirq(i, 8, i+offset, (sense & IRQ_POLARITY_MASK),
+				(sense & IRQ_SENSE_MASK));
 		/* Processor 0 */
 		openpic_mapirq(i, 1<<0, 0);
 	}
@@ -372,25 +404,14 @@
 	if (ppc_md.progress) ppc_md.progress("openpic: spurious",0x3bd);
 	openpic_set_spurious(OPENPIC_VEC_SPURIOUS+offset);
 
-	/* Initialize the cascade */
-	if (offset) {
-		if (request_irq(offset, no_action, SA_INTERRUPT,
-				"82c59 cascade", NULL))
-			printk("Unable to get OpenPIC IRQ 0 for cascade\n");
-	}
-	openpic_set_priority(0);
 	openpic_disable_8259_pass_through();
+#ifdef CONFIG_EPIC_SERIAL_MODE
+	openpic_eicr_set_clk(7);	/* Slowest value until we know better */
+	openpic_enable_sie();
+#endif
+	openpic_set_priority(0);
 
-	if (ppc_md.progress) ppc_md.progress("openpic exit",0x222);
-}
-
-static void openpic_reset(void)
-{
-	openpic_setfield(&OpenPIC->Global.Global_Configuration0,
-			 OPENPIC_CONFIG_RESET);
-	while (openpic_readfield(&OpenPIC->Global.Global_Configuration0,
-				 OPENPIC_CONFIG_RESET))
-		mb();
+	if (ppc_md.progress) ppc_md.progress("openpic: exit",0x222);
 }
 
 #ifdef notused
@@ -614,6 +635,21 @@
 		      physmask(cpumask));
 }
 
+/*
+ * Initalize the interrupt source which will generate an NMI.
+ * This raises the interrupt's priority from 8 to 9.
+ *
+ * irq: The logical IRQ which generates an NMI.
+ */
+void __init
+openpic_init_nmi_irq(u_int irq)
+{
+	check_arg_irq(irq);
+	openpic_safe_writefield(&ISR[irq - open_pic_irq_offset]->Vector_Priority,
+				OPENPIC_PRIORITY_MASK,
+				9 << OPENPIC_PRIORITY_SHIFT);
+}
+
 
 /*
  *
@@ -621,6 +657,19 @@
  *
  */
 
+/*
+ * Hookup a cascade to the OpenPIC.
+ */
+void __init
+openpic_hookup_cascade(u_int irq, char *name,
+	int (*cascade_fn)(struct pt_regs *))
+{
+	openpic_cascade_irq = irq;
+	openpic_cascade_fn = cascade_fn;
+	if (request_irq(irq, no_action, SA_INTERRUPT, name, NULL))
+		printk("Unable to get OpenPIC IRQ %d for cascade\n",
+				irq - open_pic_irq_offset);
+}
 
 /*
  *  Enable/disable an external interrupt source
@@ -762,32 +811,25 @@
 
 #endif /* CONFIG_SMP */
 
-/* This one may be merged with PReP and CHRP */
 int
 openpic_get_irq(struct pt_regs *regs)
 {
-/*
- * Clean up needed. -VAL
- */
 	int irq = openpic_irq();
 
-	/* Management of the cascade should be moved out of here */
-
-	/* Yep - because openpic !=> i8259, for one thing. -VAL */
-        if (open_pic_irq_offset && irq == open_pic_irq_offset)
-        {
-                /*
-                 * This magic address generates a PCI IACK cycle.
-                 */
-		if ( chrp_int_ack_special )
-			irq = *chrp_int_ack_special;
-#ifndef CONFIG_GEMINI
-		else
-			irq = i8259_poll(regs);
-#endif
-		openpic_eoi();
-        }
-	if (irq == OPENPIC_VEC_SPURIOUS + open_pic_irq_offset)
+	/*
+	 * Check for the cascade interrupt and call the cascaded
+	 * interrupt controller function (usually i8259_irq) if so.
+	 * This should move to irq.c eventually.  -- paulus
+	 */
+	if (irq == openpic_cascade_irq && openpic_cascade_fn != NULL) {
+		int cirq = openpic_cascade_fn(regs);
+
+		/* Allow for the cascade being shared with other devices */
+		if (cirq != -1) {
+			irq = cirq;
+			openpic_eoi();
+		}
+        } else if (irq == OPENPIC_VEC_SPURIOUS + open_pic_irq_offset)
 		irq = -1;
 	return irq;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/open_pic_defs.h linux-2.4.21-pre6/arch/ppc/kernel/open_pic_defs.h
--- linux-2.4.20/arch/ppc/kernel/open_pic_defs.h	2001-08-28 13:58:33.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/open_pic_defs.h	2003-03-26 23:49:50.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.open_pic_defs.h 1.8 08/20/01 22:33:28 paulus
- */
-/*
  *  linux/openpic.h -- OpenPIC definitions
  *
  *  Copyright (C) 1997 Geert Uytterhoeven
@@ -209,6 +206,14 @@
 #define OPENPIC_CONFIG_BASE_MASK		0x000fffff
 
     /*
+     *  Global Configuration Register 1
+     *  This is the EICR on EPICs.
+     */
+
+#define OPENPIC_EICR_S_CLK_MASK			0x70000000
+#define OPENPIC_EICR_SIE			0x08000000
+
+    /*
      *  Vendor Identification Register
      */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/pci-dma.c linux-2.4.21-pre6/arch/ppc/kernel/pci-dma.c
--- linux-2.4.20/arch/ppc/kernel/pci-dma.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/pci-dma.c	2003-03-26 23:49:09.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.pci-dma.c 1.5 05/17/01 18:14:21 cort
- */
-/*
  * Copyright (C) 2000   Ani Joshi <ajoshi@unixbox.com>
  *
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/pci.c linux-2.4.21-pre6/arch/ppc/kernel/pci.c
--- linux-2.4.20/arch/ppc/kernel/pci.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/pci.c	2003-03-26 23:49:35.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Common pmac/prep/chrp pci routines. -- Cort
  */
 
@@ -39,8 +36,13 @@
 
 void pcibios_make_OF_bus_map(void);
 
+static int pci_relocate_bridge_resource(struct pci_bus *bus, int i);
+static int probe_resource(struct pci_bus *parent, struct resource *pr,
+			  struct resource *res, struct resource **conflict);
+static void update_bridge_base(struct pci_bus *bus, int i);
 static void pcibios_fixup_resources(struct pci_dev* dev);
 static void fixup_broken_pcnet32(struct pci_dev* dev);
+static int reparent_resources(struct resource *parent, struct resource *res);
 static void fixup_rev1_53c810(struct pci_dev* dev);
 static void fixup_cpc710_pci64(struct pci_dev* dev);
 #ifdef CONFIG_ALL_PPC
@@ -107,7 +109,7 @@
 
 void
 pcibios_update_resource(struct pci_dev *dev, struct resource *root,
-			     struct resource *res, int resource)
+			struct resource *res, int resource)
 {
 	u32 new, check;
 	int reg;
@@ -115,6 +117,7 @@
 	unsigned long io_offset;
 	
 	new = res->start;
+	res->flags &= ~IORESOURCE_UNSET;
 	if (hose && res->flags & IORESOURCE_IO) {
 		io_offset = (unsigned long)hose->io_base_virt - isa_io_base;
 		new -= io_offset;
@@ -139,6 +142,9 @@
 		       "%s/%d (%08x != %08x)\n", dev->slot_name, resource,
 		       new, check);
 	}
+	printk(KERN_INFO "PCI: moved device %s resource %d (%lx) to %x\n",
+	       dev->slot_name, resource, res->flags,
+	       new & ~PCI_REGION_FLAG_MASK);
 }
 
 static void
@@ -154,13 +160,14 @@
 	}
 	for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
 		struct resource *res = dev->resource + i;
-		if (!res->start || !res->flags)
+		if (!res->flags)
 			continue;
-		if (res->end == 0xffffffff) {
+		if (!res->start || res->end == 0xffffffff) {
 			DBG("PCI:%s Resource %d [%08lx-%08lx] is unassigned\n",
 			    dev->slot_name, i, res->start, res->end);
 			res->end -= res->start;
 			res->start = 0;
+			res->flags |= IORESOURCE_UNSET;
 			continue;
 		}
 		offset = 0;
@@ -304,7 +311,8 @@
 	for (ln = bus_list->next; ln != bus_list; ln=ln->next) {
 		bus = pci_bus_b(ln);
 		for (i = 0; i < 4; ++i) {
-			if ((res = bus->resource[i]) == NULL || !res->flags)
+			if ((res = bus->resource[i]) == NULL || !res->flags
+			    || res->start > res->end)
 				continue;
 			if (bus->parent == NULL)
 				pr = (res->flags & IORESOURCE_IO)?
@@ -319,18 +327,238 @@
 					continue;
 				}
 			}
-			
-			if (pr && request_resource(pr, res) == 0)
-				continue;
+
+			DBG("PCI: bridge rsrc %lx..%lx (%lx), parent %p\n",
+			    res->start, res->end, res->flags, pr);
+			if (pr) {
+				if (request_resource(pr, res) == 0)
+					continue;
+				/*
+				 * Must be a conflict with an existing entry.
+				 * Move that entry (or entries) under the
+				 * bridge resource and try again.
+				 */
+				if (reparent_resources(pr, res) == 0)
+					continue;
+			}
 			printk(KERN_ERR "PCI: Cannot allocate resource region "
 			       "%d of PCI bridge %d\n", i, bus->number);
-			DBG("PCI: resource is %lx..%lx (%lx), parent %p\n",
-			    res->start, res->end, res->flags, pr);
+			if (pci_relocate_bridge_resource(bus, i))
+				bus->resource[i] = NULL;
 		}
 		pcibios_allocate_bus_resources(&bus->children);
 	}
 }
 
+/*
+ * Reparent resource children of pr that conflict with res
+ * under res, and make res replace those children.
+ */
+static int __init
+reparent_resources(struct resource *parent, struct resource *res)
+{
+	struct resource *p, **pp;
+	struct resource **firstpp = NULL;
+
+	for (pp = &parent->child; (p = *pp) != NULL; pp = &p->sibling) {
+		if (p->end < res->start)
+			continue;
+		if (res->end < p->start)
+			break;
+		if (p->start < res->start || p->end > res->end)
+			return -1;	/* not completely contained */
+		if (firstpp == NULL)
+			firstpp = pp;
+	}
+	if (firstpp == NULL)
+		return -1;	/* didn't find any conflicting entries? */
+	res->parent = parent;
+	res->child = *firstpp;
+	res->sibling = *pp;
+	*firstpp = res;
+	*pp = NULL;
+	for (p = res->child; p != NULL; p = p->sibling) {
+		p->parent = res;
+		DBG(KERN_INFO "PCI: reparented %s [%lx..%lx] under %s\n",
+		    p->name, p->start, p->end, res->name);
+	}
+	return 0;
+}
+
+/*
+ * A bridge has been allocated a range which is outside the range
+ * of its parent bridge, so it needs to be moved.
+ */
+static int __init
+pci_relocate_bridge_resource(struct pci_bus *bus, int i)
+{
+	struct resource *res, *pr, *conflict;
+	unsigned long try, size;
+	int j;
+	struct pci_bus *parent = bus->parent;
+
+	if (parent == NULL) {
+		/* shouldn't ever happen */
+		printk(KERN_ERR "PCI: can't move host bridge resource\n");
+		return -1;
+	}
+	res = bus->resource[i];
+	pr = NULL;
+	for (j = 0; j < 4; j++) {
+		struct resource *r = parent->resource[j];
+		if (!r)
+			continue;
+		if ((res->flags ^ r->flags) & (IORESOURCE_IO | IORESOURCE_MEM))
+			continue;
+		if (!((res->flags ^ r->flags) & IORESOURCE_PREFETCH)) {
+			pr = r;
+			break;
+		}
+		if (res->flags & IORESOURCE_PREFETCH)
+			pr = r;
+	}
+	if (pr == NULL)
+		return -1;
+	size = res->end - res->start;
+	if (pr->start > pr->end || size > pr->end - pr->start)
+		return -1;
+	try = pr->end + 1;
+	for (;;) {
+		try &= ~0xfffUL;
+		if (res->flags & IORESOURCE_MEM)
+			try &= ~0xfffffUL;
+		res->start = try - size - 1;
+		res->end = try - 1;
+		if (try <= size || res->start < pr->start)
+			return -1;
+		if (probe_resource(bus->parent, pr, res, &conflict) == 0)
+			break;
+		if (conflict->start <= pr->start + size)
+			return -1;
+		try = conflict->start;
+	}
+	if (request_resource(pr, res)) {
+		DBG(KERN_ERR "PCI: huh? couldn't move to %lx..%lx\n",
+		    res->start, res->end);
+		return -1;		/* "can't happen" */
+	}
+	update_bridge_base(bus, i);
+	printk(KERN_INFO "PCI: bridge %d resource %d moved to %lx..%lx\n",
+	       bus->number, i, res->start, res->end);
+	return 0;
+}
+
+static int __init
+probe_resource(struct pci_bus *parent, struct resource *pr,
+	       struct resource *res, struct resource **conflict)
+{
+	struct pci_bus *bus;
+	struct pci_dev *dev;
+	struct resource *r;
+	struct list_head *ln;
+	int i;
+
+	for (r = pr->child; r != NULL; r = r->sibling) {
+		if (r->end >= res->start && res->end >= r->start) {
+			*conflict = r;
+			return 1;
+		}
+	}
+	for (ln = parent->children.next; ln != &parent->children;
+	     ln = ln->next) {
+		bus = pci_bus_b(ln);
+		for (i = 0; i < 4; ++i) {
+			if ((r = bus->resource[i]) == NULL)
+				continue;
+			if (!r->flags || r->start > r->end || r == res)
+				continue;
+			if (pci_find_parent_resource(bus->self, r) != pr)
+				continue;
+			if (r->end >= res->start && res->end >= r->start) {
+				*conflict = r;
+				return 1;
+			}
+		}
+	}
+	for (ln = parent->devices.next; ln != &parent->devices; ln=ln->next) {
+		dev = pci_dev_b(ln);
+		for (i = 0; i < 6; ++i) {
+			r = &dev->resource[i];
+			if (!r->flags || (r->flags & IORESOURCE_UNSET))
+				continue;
+			if (pci_find_parent_resource(bus->self, r) != pr)
+				continue;
+			if (r->end >= res->start && res->end >= r->start) {
+				*conflict = r;
+				return 1;
+			}
+		}
+	}
+	return 0;
+}
+
+static void __init
+update_bridge_base(struct pci_bus *bus, int i)
+{
+	struct resource *res = bus->resource[i];
+	u8 io_base_lo, io_limit_lo;
+	u16 mem_base, mem_limit;
+	u16 cmd;
+	unsigned long start, end, off;
+	struct pci_dev *dev = bus->self;
+	struct pci_controller *hose = dev->sysdata;
+
+	if (!hose) {
+		printk("update_bridge_base: no hose?\n");
+		return;
+	}
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+	pci_write_config_word(dev, PCI_COMMAND,
+			      cmd & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY));
+	if (res->flags & IORESOURCE_IO) {
+		u16 bu;
+		off = (unsigned long) hose->io_base_virt - isa_io_base;
+		start = res->start - off;
+		end = res->end - off;
+		pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo);
+		pci_read_config_byte(dev, PCI_IO_LIMIT, &io_limit_lo);
+		pci_read_config_word(dev, PCI_IO_BASE_UPPER16, &bu);
+		io_limit_lo &= PCI_IO_RANGE_TYPE_MASK;
+		if (io_base_lo == PCI_IO_RANGE_TYPE_16 && end > 0xffff) {
+			printk(KERN_ERR "bridge only supports 16-bit I/O!\n");
+			goto out;
+		}
+		io_base_lo |= (start >> 8) & PCI_IO_RANGE_MASK;
+		io_limit_lo |= (end >> 8) & PCI_IO_RANGE_MASK;
+		pci_write_config_word(dev, PCI_IO_BASE_UPPER16, start >> 16);
+		pci_write_config_word(dev, PCI_IO_LIMIT_UPPER16, end >> 16);
+		pci_write_config_byte(dev, PCI_IO_BASE, io_base_lo);
+		pci_write_config_byte(dev, PCI_IO_LIMIT, io_limit_lo);
+
+	} else if ((res->flags & (IORESOURCE_MEM | IORESOURCE_PREFETCH))
+		   == IORESOURCE_MEM) {
+		off = hose->pci_mem_offset;
+		mem_base = ((res->start - off) >> 16) & PCI_MEMORY_RANGE_MASK;
+		mem_limit = ((res->end - off) >> 16) & PCI_MEMORY_RANGE_MASK;
+		pci_write_config_word(dev, PCI_MEMORY_BASE, mem_base);
+		pci_write_config_word(dev, PCI_MEMORY_LIMIT, mem_limit);
+
+	} else if ((res->flags & (IORESOURCE_MEM | IORESOURCE_PREFETCH))
+		   == (IORESOURCE_MEM | IORESOURCE_PREFETCH)) {
+		off = hose->pci_mem_offset;
+		mem_base = ((res->start - off) >> 16) & PCI_PREF_RANGE_MASK;
+		mem_limit = ((res->end - off) >> 16) & PCI_PREF_RANGE_MASK;
+		pci_write_config_word(dev, PCI_PREF_MEMORY_BASE, mem_base);
+		pci_write_config_word(dev, PCI_PREF_MEMORY_LIMIT, mem_limit);
+
+	} else {
+		DBG(KERN_ERR "PCI: ugh, bridge %s res %d has flags=%lx\n",
+		    dev->slot_name, i, res->flags);
+	}
+ out:
+	pci_write_config_word(dev, PCI_COMMAND, cmd);
+}
+
 static inline void alloc_resource(struct pci_dev *dev, int idx)
 {
 	struct resource *pr, *r = &dev->resource[idx];
@@ -345,6 +573,7 @@
 			DBG("PCI:  parent is %p: %08lx-%08lx (f=%lx)\n",
 			    pr, pr->start, pr->end, pr->flags);
 		/* We'll assign a new address later */
+		r->flags |= IORESOURCE_UNSET;
 		r->end -= r->start;
 		r->start = 0;
 	}
@@ -364,8 +593,8 @@
 			r = &dev->resource[idx];
 			if (r->parent)		/* Already allocated */
 				continue;
-			if (!r->start)		/* Not assigned at all */
-				continue;
+			if (!r->flags || (r->flags & IORESOURCE_UNSET))
+				continue;	/* Not assigned at all */
 			if (r->flags & IORESOURCE_IO)
 				disabled = !(command & PCI_COMMAND_IO);
 			else
@@ -411,7 +640,7 @@
 			 * or because we have decided the old address was
 			 * unusable for some reason.
 			 */
-			if (!r->start && r->end &&
+			if ((r->flags & IORESOURCE_UNSET) && r->end &&
 			    (!ppc_md.pcibios_enable_device_hook ||
 			     !ppc_md.pcibios_enable_device_hook(dev, 1)))
 				pci_assign_resource(dev, idx);
@@ -437,9 +666,9 @@
 
 	pci_read_config_word(dev, PCI_COMMAND, &cmd);
 	old_cmd = cmd;
-	for(idx=0; idx<6; idx++) {
+	for (idx=0; idx<6; idx++) {
 		r = &dev->resource[idx];
-		if (!r->start && r->end) {
+		if (r->flags & IORESOURCE_UNSET) {
 			printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name);
 			return -EINVAL;
 		}
@@ -490,7 +719,7 @@
 	bus_range = (int *) get_property(node, "bus-range", &len);
 	if (bus_range == NULL || len < 2 * sizeof(int)) {
 		printk(KERN_WARNING "Can't get bus-range for %s\n",
-			       node->full_name);
+		       node->full_name);
 		return;
 	}
 	pci_to_OF_bus_map[pci_bus] = bus_range[0];
@@ -717,8 +946,9 @@
 	int rlen = 0;
 	int memno = 0;
 	struct resource *res;
-	int np, na = prom_n_addr_cells(dev);
-	np = na + 5;
+	int na = prom_n_addr_cells(dev);
+	int np = na + 5;
+	unsigned int size;
 
 	/* First we try to merge ranges to fix a problem with some pmacs
 	 * that can have more than 3 ranges, fortunately using contiguous
@@ -754,12 +984,16 @@
 	ranges = (unsigned int *) get_property(dev, "ranges", &rlen);
 	while ((rlen -= np * sizeof(unsigned int)) >= 0) {
 		res = NULL;
+		size = ranges[na+4];
 		switch (ranges[0] >> 24) {
 		case 1:		/* I/O space */
 			if (ranges[2] != 0)
 				break;
 			hose->io_base_phys = ranges[na+2];
-			hose->io_base_virt = ioremap(ranges[na+2], ranges[na+4]);
+			/* limit I/O to 16MB */
+			if (size > 0x01000000)
+				size = 0x01000000;
+			hose->io_base_virt = ioremap(ranges[na+2], size);
 			if (primary)
 				isa_io_base = (unsigned long) hose->io_base_virt;
 			res = &hose->io_resource;
@@ -788,7 +1022,7 @@
 		}
 		if (res != NULL) {
 			res->name = dev->full_name;
-			res->end = res->start + ranges[na+4] - 1;
+			res->end = res->start + size - 1;
 			res->parent = NULL;
 			res->sibling = NULL;
 			res->child = NULL;
@@ -894,7 +1128,8 @@
 		struct pci_dev *dev = pci_dev_b(ln);
 		u16 class = dev->class >> 8;
 
-		if (class == PCI_CLASS_DISPLAY_VGA || class == PCI_CLASS_NOT_DEFINED_VGA)
+		if (class == PCI_CLASS_DISPLAY_VGA ||
+		    class == PCI_CLASS_NOT_DEFINED_VGA)
 			*found_vga = 1;
 		if (class >> 8 == PCI_BASE_CLASS_BRIDGE && dev->subordinate)
 			rc |= check_for_io_childs(dev->subordinate, res, found_vga);
@@ -905,7 +1140,8 @@
 			struct resource *r;
 			unsigned long r_size;
 
-			if (dev->class >> 8 == PCI_CLASS_BRIDGE_PCI && i >= PCI_BRIDGE_RESOURCES)
+			if (dev->class >> 8 == PCI_CLASS_BRIDGE_PCI
+			    && i >= PCI_BRIDGE_RESOURCES)
 				continue;
 			r = &dev->resource[i];
 			r_size = r->end - r->start;
@@ -931,30 +1167,45 @@
 do_fixup_p2p_level(struct pci_bus *bus)
 {
 	struct list_head *ln;
-	int i;
+	int i, parent_io;
 	int has_vga = 0;
+
+	for (parent_io=0; parent_io<4; parent_io++)
+		if (bus->resource[parent_io]->flags & IORESOURCE_IO)
+			break;
+	if (parent_io >= 4)
+		return;
 	
 	for (ln=bus->children.next; ln != &bus->children; ln=ln->next) {
 		struct pci_bus *b = pci_bus_b(ln);
 		struct pci_dev *d = b->self;
 		struct pci_controller* hose = (struct pci_controller *)d->sysdata;
 		struct resource *res = b->resource[0];
+		struct resource tmp_res;
 		unsigned long max;
 		int found_vga = 0;
 
-		res->end = 0;
-		res->start = 0x1000;
+		memset(&tmp_res, 0, sizeof(tmp_res));
+		tmp_res.start = bus->resource[parent_io]->start;
+
+		/* We don't let low addresses go through that closed P2P bridge, well,
+		 * that may not be necessary but I feel safer that way
+		 */
+		if (tmp_res.start == 0)
+			tmp_res.start = 0x1000;
 		
-		if (!list_empty(&b->devices) && res && res->flags == 0 && res != bus->resource[0] &&
+		if (!list_empty(&b->devices) && res && res->flags == 0 &&
+		    res != bus->resource[parent_io] &&
 		    (d->class >> 8) == PCI_CLASS_BRIDGE_PCI &&
-		    check_for_io_childs(b, res, &found_vga)) {
+		    check_for_io_childs(b, &tmp_res, &found_vga)) {
 			u8 io_base_lo;
 
 			printk(KERN_INFO "Fixing up IO bus %s\n", b->name);
 
 			if (found_vga) {
 				if (has_vga) {
-					printk(KERN_WARNING "Skipping VGA, already active on bus segment\n");
+					printk(KERN_WARNING "Skipping VGA, already active"
+					    " on bus segment\n");
 					found_vga = 0;
 				} else
 					has_vga = 1;
@@ -962,10 +1213,13 @@
 			pci_read_config_byte(d, PCI_IO_BASE, &io_base_lo);
 
 			if ((io_base_lo & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32)
-				max = ((unsigned long) hose->io_base_virt - isa_io_base) + 0xffffffff;
+				max = ((unsigned long) hose->io_base_virt
+					- isa_io_base) + 0xffffffff;
 			else
-				max = ((unsigned long) hose->io_base_virt - isa_io_base) + 0xffff;
-			
+				max = ((unsigned long) hose->io_base_virt
+					- isa_io_base) + 0xffff;
+
+			*res = tmp_res;
 			res->flags = IORESOURCE_IO;
 			res->name = b->name;
 			
@@ -976,10 +1230,12 @@
 					continue;
 				if ((r->flags & IORESOURCE_IO) == 0)
 					continue;
-				DBG("Trying to allocate from %08lx, size %08lx from parent res %d: %08lx -> %08lx\n",
+				DBG("Trying to allocate from %08lx, size %08lx from parent"
+				    " res %d: %08lx -> %08lx\n",
 					res->start, res->end, i, r->start, r->end);
 				
-				if (allocate_resource(r, res, res->end + 1, res->start, max, res->end + 1, NULL, NULL) < 0) {
+				if (allocate_resource(r, res, res->end + 1, res->start, max,
+				    res->end + 1, NULL, NULL) < 0) {
 					DBG("Failed !\n");
 					continue;
 				}
@@ -1191,7 +1447,7 @@
 			continue;
 			
 		r = &dev->resource[idx];
-		if (!r->start && r->end) {
+		if (r->flags & IORESOURCE_UNSET) {
 			printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name);
 			return -EINVAL;
 		}
@@ -1298,51 +1554,41 @@
 {
 	struct pci_controller *hose = (struct pci_controller *) dev->sysdata;
 	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
-	unsigned long io_offset = 0;
-	int i, res_bit;
+	unsigned long size = vma->vm_end - vma->vm_start;
+	unsigned long base;
+	struct resource *res;
+	int i;
+	int ret = -EINVAL;
 
 	if (hose == 0)
 		return -EINVAL;		/* should never happen */
+	if (offset + size <= offset)
+		return -EINVAL;
 
-	/* If memory, add on the PCI bridge address offset */
 	if (mmap_state == pci_mmap_mem) {
+		/* PCI memory space */
+		base = hose->pci_mem_offset;
+		for (i = 0; i < 3; ++i) {
+			res = &hose->mem_resources[i];
+			if (offset >= res->start - base
+			    && offset + size - 1 <= res->end - base) {
+				ret = 0;
+				break;
+			}
+		}
 		offset += hose->pci_mem_offset;
-		res_bit = IORESOURCE_MEM;
 	} else {
-		io_offset = (unsigned long)hose->io_base_virt - isa_io_base;
-		offset += io_offset;
-		res_bit = IORESOURCE_IO;
+		/* PCI I/O space */
+		base = (unsigned long)hose->io_base_virt - isa_io_base;
+		res = &hose->io_resource;
+		if (offset >= res->start - base
+		    && offset + size - 1 <= res->end - base)
+			ret = 0;
+		offset += hose->io_base_phys;
 	}
 
-	/*
-	 * Check that the offset requested corresponds to one of the
-	 * resources of the device.
-	 */
-	for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
-		struct resource *rp = &dev->resource[i];
-		int flags = rp->flags;
-
-		/* treat ROM as memory (should be already) */
-		if (i == PCI_ROM_RESOURCE)
-			flags |= IORESOURCE_MEM;
-
-		/* Active and same type? */
-		if ((flags & res_bit) == 0)
-			continue;
-
-		/* In the range of this resource? */
-		if (offset < (rp->start & PAGE_MASK) || offset > rp->end)
-			continue;
-
-		/* found it! construct the final physical address */
-		if (mmap_state == pci_mmap_io)
-			offset += hose->io_base_phys - io_offset;
-
-		vma->vm_pgoff = offset >> PAGE_SHIFT;
-		return 0;
-	}
-
-	return -EINVAL;
+	vma->vm_pgoff = offset >> PAGE_SHIFT;
+	return ret;
 }
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/pci.h linux-2.4.21-pre6/arch/ppc/kernel/pci.h
--- linux-2.4.20/arch/ppc/kernel/pci.h	2001-08-12 19:43:26.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/pci.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,27 +0,0 @@
-/*
- * BK Id: SCCS/s.pci.h 1.10 08/08/01 16:35:43 paulus
- */
-
-#ifndef __PPC_KERNEL_PCI_H__
-#define __PPC_KERNEL_PCI_H__
-
-/* Configure those in your xxx_init() or xxx_setup_arch() function */
-extern unsigned long isa_io_base;
-extern unsigned long isa_mem_base;
-extern unsigned long pci_dram_offset;
-
-/* Set this to 1 if you want the kernel to re-assign all PCI
- * bus numbers
- */
-extern int pci_assign_all_busses;
-
-
-extern struct pci_controller* pcibios_alloc_controller(void);
-extern struct pci_controller* pci_find_hose_for_OF_device(
-			struct device_node* node);
-
-extern void setup_indirect_pci(struct pci_controller* hose,
-			u32 cfg_addr, u32 cfg_data);
-extern void setup_grackle(struct pci_controller *hose);
-
-#endif /* __PPC_KERNEL_PCI_H__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/pci_auto.c linux-2.4.21-pre6/arch/ppc/kernel/pci_auto.c
--- linux-2.4.20/arch/ppc/kernel/pci_auto.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/pci_auto.c	2003-03-26 23:49:09.000000000 +0000
@@ -5,12 +5,10 @@
  *
  * Author: Matt Porter <mporter@mvista.com>
  *
- * Copyright 2001 MontaVista Software Inc.
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
+ * 2001 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
  */
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/ppc-stub.c linux-2.4.21-pre6/arch/ppc/kernel/ppc-stub.c
--- linux-2.4.20/arch/ppc/kernel/ppc-stub.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/ppc-stub.c	2003-03-26 23:49:54.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.ppc-stub.c 1.6 05/17/01 18:14:21 cort
- */
-/*
  * ppc-stub.c:  KGDB support for the Linux kernel.
  *
  * adapted from arch/sparc/kernel/sparc-stub.c for the PowerPC
@@ -137,6 +134,9 @@
 /* struct tt_entry kgdb_savettable[256]; */
 /* typedef void (*trapfunc_t)(void); */
 
+static void kgdb_fault_handler(struct pt_regs *regs);
+static void handle_exception (struct pt_regs *regs);
+
 #if 0
 /* Install an exception handler for kgdb */
 static void exceptionHandler(int tnum, unsigned int *tfunc)
@@ -185,7 +185,7 @@
  * return 0.
  */
 static unsigned char *
-mem2hex(char *mem, char *buf, int count)
+mem2hex(const char *mem, char *buf, int count)
 {
 	unsigned char ch;
 
@@ -347,18 +347,6 @@
 	flush_instruction_cache();
 }
 
-static inline int get_msr(void)
-{
-	int msr;
-	asm volatile("mfmsr %0" : "=r" (msr):);
-	return msr;
-}
-
-static inline void set_msr(int msr)
-{
-	asm volatile("mtmsr %0" : : "r" (msr));
-}
-
 /* Set up exception handlers for tracing and breakpoints
  * [could be called kgdb_init()]
  */
@@ -498,8 +486,8 @@
 
 	kgdb_interruptible(0);
 	lock_kernel();
-	msr = get_msr();
-	set_msr(msr & ~MSR_EE);	/* disable interrupts */
+	msr = mfmsr();
+	mtmsr(msr & ~MSR_EE);	/* disable interrupts */
 
 	if (regs->nip == (unsigned long)breakinst) {
 		/* Skip over breakpoint trap insn */
@@ -521,7 +509,7 @@
 	*ptr++ = hexchars[PC_REGNUM >> 4];
 	*ptr++ = hexchars[PC_REGNUM & 0xf];
 	*ptr++ = ':';
-	ptr = mem2hex((char *)&regs->nip, ptr, 4);
+	ptr = mem2hex((char *)regs->nip, ptr, 4);
 	*ptr++ = ';';
 	*ptr++ = hexchars[SP_REGNUM >> 4];
 	*ptr++ = hexchars[SP_REGNUM & 0xf];
@@ -685,7 +673,7 @@
  * some location may have changed something that is in the instruction cache.
  */
 			kgdb_flush_cache_all();
-			set_msr(msr);
+			mtmsr(msr);
 			kgdb_interruptible(1);
 			unlock_kernel();
 			kgdb_active = 0;
@@ -694,9 +682,6 @@
 		case 's':
 			kgdb_flush_cache_all();
 			regs->msr |= MSR_SE;
-#if 0
-			set_msr(msr | MSR_SE);
-#endif
 			unlock_kernel();
 			kgdb_active = 0;
 			return;
@@ -727,13 +712,15 @@
 		return;
 	}
 
-	asm("	.globl breakinst
-	     breakinst: .long 0x7d821008
-            ");
+	asm("	.globl breakinst	\n\
+	     breakinst: .long 0x7d821008");
 }
 
-/* Output string in GDB O-packet format if GDB has connected. If nothing
-   output, returns 0 (caller must then handle output). */
+#ifdef CONFIG_KGDB_CONSOLE 
+/* 
+ * Output string in GDB O-packet format if GDB has connected. If nothing
+ * output, returns 0 (caller must then handle output) 
+ */
 int
 kgdb_output_string (const char* s, unsigned int count)
 {
@@ -750,15 +737,5 @@
 	putpacket(buffer);
 
         return 1;
- }
-
-#ifndef CONFIG_8xx
-
-/* I don't know why other platforms don't need this.  The function for
- * the 8xx is found in arch/ppc/8xx_io/uart.c.  -- Dan
- */
-void
-kgdb_map_scc(void)
-{
 }
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/ppc4xx_pic.c linux-2.4.21-pre6/arch/ppc/kernel/ppc4xx_pic.c
--- linux-2.4.20/arch/ppc/kernel/ppc4xx_pic.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/ppc4xx_pic.c	2003-03-26 23:48:57.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.ppc4xx_pic.c 1.5 05/17/01 18:14:21 cort
- */
-/*
  *
  *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/ppc8260_pic.c linux-2.4.21-pre6/arch/ppc/kernel/ppc8260_pic.c
--- linux-2.4.20/arch/ppc/kernel/ppc8260_pic.c	2002-02-25 19:37:55.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/ppc8260_pic.c	2003-03-26 23:49:40.000000000 +0000
@@ -1,7 +1,3 @@
-/*
- * BK Id: SCCS/s.ppc8260_pic.c 1.5 05/17/01 18:14:21 cort
- */
-
 #include <linux/stddef.h>
 #include <linux/init.h>
 #include <linux/sched.h>
@@ -112,7 +108,7 @@
 	0
 };
 
-
+/* Return an interrupt vector or -1 if no interrupt is pending. */
 int
 m8260_get_irq(struct pt_regs *regs)
 {
@@ -124,11 +120,9 @@
         bits = immr->im_intctl.ic_sivec;
         irq = bits >> 26;
 
-	if (irq == 0)
-		return(-1);
-#if 0
-        irq += ppc8260_pic.irq_offset;
-#endif
+	if (irq == 0)	/* 0 --> no irq is pending */
+		irq = -1;
+
 	return irq;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/ppc8260_pic.h linux-2.4.21-pre6/arch/ppc/kernel/ppc8260_pic.h
--- linux-2.4.20/arch/ppc/kernel/ppc8260_pic.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/ppc8260_pic.h	2003-03-26 23:49:54.000000000 +0000
@@ -1,7 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
-
 #ifndef _PPC_KERNEL_PPC8260_H
 #define _PPC_KERNEL_PPC8260_H
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/ppc8xx_pic.c linux-2.4.21-pre6/arch/ppc/kernel/ppc8xx_pic.c
--- linux-2.4.20/arch/ppc/kernel/ppc8xx_pic.c	2002-02-25 19:37:55.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/ppc8xx_pic.c	2003-03-26 23:49:25.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.ppc8xx_pic.c 1.13 12/01/01 17:19:48 trini
- */
 #include <linux/config.h>
 #include <linux/stddef.h>
 #include <linux/init.h>
@@ -11,6 +8,8 @@
 #include <asm/mpc8xx.h>
 #include "ppc8xx_pic.h"
 
+extern int cpm_get_irq(struct pt_regs *regs);
+
 /* The 8xx internal interrupt controller.  It is usually
  * the only interrupt controller.  Some boards, like the MBX and
  * Sandpoint have the 8259 as a secondary controller.  Depending
@@ -83,36 +82,6 @@
 	0
 };
 
-#if 0
-void
-m8xx_do_IRQ(struct pt_regs *regs,
-	   int            cpu)
-{
-	int irq;
-        unsigned long bits = 0;
-
-        /* For MPC8xx, read the SIVEC register and shift the bits down
-         * to get the irq number.         */
-        bits = ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec;
-        irq = bits >> 26;
-#if 0
-        irq += ppc8xx_pic.irq_offset;
-#endif
-        bits = 1UL << irq;
-
-	if (irq < 0) {
-		printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
-		       irq, regs->nip);
-		ppc_spurious_interrupts++;
-	}
-	else {
-                ppc_irq_dispatch_handler( regs, irq );
-	}
-
-}
-#endif
-
-
 /*
  * We either return a valid interrupt or -1 if there is nothing pending
  */
@@ -130,70 +99,31 @@
 	 * When we read the sivec without an interrupt to process, we will 
 	 * get back SIU_LEVEL7.  In this case, return -1
 	 */
-	if (irq == SIU_LEVEL7)
-		return -1;
+        if (irq == CPM_INTERRUPT)
+        	irq = CPM_IRQ_OFFSET + cpm_get_irq(regs);
+#if defined(CONFIG_PCI)
+	else if (irq == ISA_BRIDGE_INT) {
+		int isa_irq;
+
+		if ((isa_irq = i8259_poll(regs)) >= 0)
+			irq = I8259_IRQ_OFFSET + isa_irq;
+	}
+#endif	/* CONFIG_PCI */
+	else if (irq == SIU_LEVEL7)
+		irq = -1;
 
 	return irq;
 }
 
-/* The MBX is the only 8xx board that uses the 8259.
-*/
-#if defined(CONFIG_MBX) && defined(CONFIG_PCI)
-void mbx_i8259_action(int cpl, void *dev_id, struct pt_regs *regs)
-{
-	int bits, irq;
-
-	/* A bug in the QSpan chip causes it to give us 0xff always
-	 * when doing a character read.  So read 32 bits and shift.
-	 * This doesn't seem to return useful values anyway, but
-	 * read it to make sure things are acked.
-	 * -- Cort
-	 */
-	irq = (inl(0x508) >> 24)&0xff;
-	if ( irq != 0xff ) printk("iack %d\n", irq);
-	
-	outb(0x0C, 0x20);
-	irq = inb(0x20) & 7;
-	if (irq == 2)
-	{
-		outb(0x0C, 0xA0);
-		irq = inb(0xA0);
-		irq = (irq&7) + 8;
-	}
-	bits = 1UL << irq;
-	irq += i8259_pic.irq_offset;
-	ppc_irq_dispatch_handler( regs, irq );
-}
-#endif
-
-/* Only the MBX uses the external 8259.  This allows us to catch standard
- * drivers that may mess up the internal interrupt controllers, and also
- * allow them to run without modification on the MBX.
+#if defined(CONFIG_PCI)
+/* Handler for the MPC8xx SIU cascade interrupt for the 8259 interrupt
+ * controller
  */
-int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
-	unsigned long irqflags, const char * devname, void *dev_id)
+void mbx_i8259_action(int irq, void *dev_id, struct pt_regs *regs)
 {
-
-#if defined(CONFIG_MBX) && defined(CONFIG_PCI)
-	irq += i8259_pic.irq_offset;
-	return (request_8xxirq(irq, handler, irqflags, devname, dev_id));
-#else
-	/*
-	 * Handle other "well-known" interrupts, but panic on unknown ones.
+	/* This interrupt handler never actually gets called.  It is
+	 * installed only to unmask the 8259 cascade interrupt in the SIU
+	 * and to make the 8259 cascade interrupt visible in /proc/interrupts.
 	 */
-	switch (irq) {
-#ifdef	IDE0_INTERRUPT
-		case IDE0_INTERRUPT:	/* IDE0 */
-			return (request_8xxirq(irq, handler, irqflags, devname,
-						dev_id));
-#endif
-#ifdef	IDE1_INTERRUPT
-		case IDE1_INTERRUPT:	/* IDE1 */
-			return (request_8xxirq(irq, handler, irqflags, devname,
-						dev_id));
-#endif
-	default:			/* unknown IRQ -> panic */
-		panic("request_irq");
-	}
-#endif
 }
+#endif	/* CONFIG_PCI */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/ppc8xx_pic.h linux-2.4.21-pre6/arch/ppc/kernel/ppc8xx_pic.h
--- linux-2.4.20/arch/ppc/kernel/ppc8xx_pic.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/ppc8xx_pic.h	2003-03-26 23:49:34.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #ifndef _PPC_KERNEL_PPC8xx_H
 #define _PPC_KERNEL_PPC8xx_H
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/ppc_htab.c linux-2.4.21-pre6/arch/ppc/kernel/ppc_htab.c
--- linux-2.4.20/arch/ppc/kernel/ppc_htab.c	2001-11-03 01:43:54.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/ppc_htab.c	2003-03-26 23:48:59.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.ppc_htab.c 1.19 10/16/01 15:58:42 trini
- */
-/*
  * PowerPC hash table management proc entry.  Will show information
  * about the current hash table and will allow changes to it.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/ppc_ksyms.c linux-2.4.21-pre6/arch/ppc/kernel/ppc_ksyms.c
--- linux-2.4.20/arch/ppc/kernel/ppc_ksyms.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/ppc_ksyms.c	2003-03-26 23:49:54.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/threads.h>
@@ -58,7 +55,6 @@
 /* Tell string.h we don't want memcpy etc. as cpp defines */
 #define EXPORT_SYMTAB_STROPS
 
-extern void ppc_generic_ide_fix_driveid(struct hd_driveid *id);
 extern void transfer_to_handler(void);
 extern void syscall_trace(void);
 extern void do_IRQ(struct pt_regs *regs);
@@ -170,7 +166,6 @@
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) \
 	|| defined(CONFIG_USB_STORAGE) || defined(CONFIG_USB_STORAGE_MODULE)
 EXPORT_SYMBOL(ppc_ide_md);
-EXPORT_SYMBOL(ppc_generic_ide_fix_driveid);
 #endif
 
 #ifdef CONFIG_PCI
@@ -343,11 +338,15 @@
 
 #ifdef  CONFIG_8xx
 EXPORT_SYMBOL(__res);
-EXPORT_SYMBOL(request_8xxirq);
 EXPORT_SYMBOL(cpm_install_handler);
 EXPORT_SYMBOL(cpm_free_handler);
+EXPORT_SYMBOL(m8xx_cpm_hostalloc);
 #endif /* CONFIG_8xx */
 
+/* Those should really be inline */
+EXPORT_SYMBOL(atomic_clear_mask);
+EXPORT_SYMBOL(atomic_set_mask);
+
 EXPORT_SYMBOL(ret_to_user_hook);
 EXPORT_SYMBOL(next_mmu_context);
 EXPORT_SYMBOL(set_context);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/prep_nvram.c linux-2.4.21-pre6/arch/ppc/kernel/prep_nvram.c
--- linux-2.4.20/arch/ppc/kernel/prep_nvram.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/prep_nvram.c	2003-03-26 23:49:38.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/platforms/prep_nvram.c
  *
  *  Copyright (C) 1998  Corey Minyard
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/process.c linux-2.4.21-pre6/arch/ppc/kernel/process.c
--- linux-2.4.20/arch/ppc/kernel/process.c	2001-11-26 13:29:17.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/process.c	2003-03-26 23:49:38.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.process.c 1.34 11/23/01 16:38:29 paulus
- */
-/*
  *  linux/arch/ppc/kernel/process.c
  *
  *  Derived from "arch/i386/kernel/process.c"
@@ -34,6 +31,7 @@
 #include <linux/user.h>
 #include <linux/elf.h>
 #include <linux/init.h>
+#include <linux/prctl.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
@@ -400,13 +398,53 @@
 		last_task_used_math = 0;
 	if (last_task_used_altivec == current)
 		last_task_used_altivec = 0;
+	memset(current->thread.fpr, 0, sizeof(current->thread.fpr));
 	current->thread.fpscr = 0;
+#ifdef CONFIG_ALTIVEC
+	memset(current->thread.vr, 0, sizeof(current->thread.vr));
+	memset(&current->thread.vscr, 0, sizeof(current->thread.vscr));
+	current->thread.vrsave = 0;
+#endif /* CONFIG_ALTIVEC */
+}
+
+/*
+ * Support for the PR_GET/SET_FPEXC prctl() calls.
+ */
+static inline unsigned int __unpack_fe01(unsigned int msr_bits)
+{
+	return ((msr_bits & MSR_FE0) >> 10) | ((msr_bits & MSR_FE1) >> 8);
+}
+
+static inline unsigned int __pack_fe01(unsigned int fpmode)
+{
+	return ((fpmode << 10) & MSR_FE0) | ((fpmode << 8) & MSR_FE1);
+}
+
+int set_fpexc_mode(struct task_struct *tsk, unsigned int val)
+{
+	struct pt_regs *regs = tsk->thread.regs;
+
+	if (val > PR_FP_EXC_PRECISE)
+		return -EINVAL;
+	tsk->thread.fpexc_mode = __pack_fe01(val);
+	if (regs != NULL && (regs->msr & MSR_FP) != 0)
+		regs->msr = (regs->msr & ~(MSR_FE0|MSR_FE1))
+			| tsk->thread.fpexc_mode;
+	return 0;
+}
+
+int get_fpexc_mode(struct task_struct *tsk, unsigned long adr)
+{
+	unsigned int val;
+
+	val = __unpack_fe01(tsk->thread.fpexc_mode);
+	return put_user(val, (unsigned int *) adr);
 }
 
 int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6,
 	      struct pt_regs *regs)
 {
-	return do_fork(p1, regs->gpr[1], regs, 0);
+	return do_fork(p1, p2, regs, 0);
 }
 
 int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6,
@@ -452,6 +490,8 @@
 	int cnt = 0;
 	unsigned long i;
 
+	if (sp == NULL)
+		asm("mr %0,1" : "=r" (sp));
 	printk("Call backtrace: ");
 	while (sp) {
 		if (__get_user( i, &sp[1] ))
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/prom.c linux-2.4.21-pre6/arch/ppc/kernel/prom.c
--- linux-2.4.20/arch/ppc/kernel/prom.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/prom.c	2003-03-26 23:49:00.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Procedures for interfacing to the Open Firmware PROM on
  * Power Macintosh computers.
  *
@@ -506,6 +503,38 @@
 }
 
 static unsigned long __init
+map_addr(struct device_node *np, unsigned long space, unsigned long addr)
+{
+	int na;
+	unsigned int *ranges;
+	int rlen = 0;
+	unsigned int type;
+
+	type = (space >> 24) & 3;
+	if (type == 0)
+		return addr;
+
+	while ((np = np->parent) != NULL) {
+		if (strcmp(np->type, "pci") != 0)
+			continue;
+		/* PCI bridge: map the address through the ranges property */
+		na = prom_n_addr_cells(np);
+		ranges = (unsigned int *) get_property(np, "ranges", &rlen);
+		while ((rlen -= (na + 5) * sizeof(unsigned int)) >= 0) {
+			if (((ranges[0] >> 24) & 3) == type
+			    && ranges[2] <= addr
+			    && addr - ranges[2] < ranges[na+4]) {
+				/* ok, this matches, translate it */
+				addr += ranges[na+2] - ranges[2];
+				break;
+			}
+			ranges += na + 5;
+		}
+	}
+	return addr;
+}
+
+static unsigned long __init
 interpret_pci_props(struct device_node *np, unsigned long mem_start,
 		    int naddrc, int nsizec)
 {
@@ -519,9 +548,9 @@
 		i = 0;
 		adr = (struct address_range *) mem_start;
 		while ((l -= sizeof(struct pci_reg_property)) >= 0) {
-			/* XXX assumes PCI addresses mapped 1-1 to physical */
 			adr[i].space = pci_addrs[i].addr.a_hi;
-			adr[i].address = pci_addrs[i].addr.a_lo;
+			adr[i].address = map_addr(np, pci_addrs[i].addr.a_hi,
+						  pci_addrs[i].addr.a_lo);
 			adr[i].size = pci_addrs[i].size_lo;
 			++i;
 		}
@@ -758,8 +787,15 @@
 	for (np = allnodes; np != 0; np = np->allnext) {
 		for (j = 0; j < np->n_intrs; j++) {
 			i = np->intrs[j].line;
-			if (i >= off && i < max)
-				senses[i-off] = np->intrs[j].sense;
+			if (i >= off && i < max) {
+				if (np->intrs[j].sense == 1) {
+					senses[i-off] = (IRQ_SENSE_LEVEL |
+							IRQ_POLARITY_NEGATIVE);
+				} else {
+					senses[i-off] = (IRQ_SENSE_EDGE |
+							IRQ_POLARITY_POSITIVE);
+				}
+			}
 		}
 	}
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/prom_init.c linux-2.4.21-pre6/arch/ppc/kernel/prom_init.c
--- linux-2.4.20/arch/ppc/kernel/prom_init.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/prom_init.c	2003-03-26 23:49:54.000000000 +0000
@@ -266,7 +266,7 @@
 {
 	phandle node;
 	ihandle ih;
-	int i;
+	int i, j;
 	char type[16], *path;
 	static unsigned char default_colors[] = {
 		0x00, 0x00, 0x00,
@@ -325,26 +325,26 @@
 			break;
 	}
 
-try_again:
 	/*
 	 * Open the first display and set its colormap.
 	 */
-	if (prom_num_displays > 0) {
-		path = prom_display_paths[0];
+	for (j=0; j<prom_num_displays; j++) {
+		path = prom_display_paths[j];
 		prom_print("opening display ");
 		prom_print(path);
 		ih = call_prom("open", 1, 1, path);
 		if (ih == 0 || ih == (ihandle) -1) {
 			prom_print("... failed\n");
-			for (i=1; i<prom_num_displays; i++) {
+			for (i=j+1; i<prom_num_displays; i++) {
 				prom_display_paths[i-1] = prom_display_paths[i];
 				prom_display_nodes[i-1] = prom_display_nodes[i];
 			}
-			if (--prom_num_displays > 0)
-				prom_disp_node = prom_display_nodes[0];
-			else
+			if (--prom_num_displays > 0) {
+				prom_disp_node = prom_display_nodes[j];
+				j--;
+			} else
 				prom_disp_node = NULL;
-			goto try_again;
+			continue;
 		} else {
 			prom_print("... ok\n");
 			/*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/ptrace.c linux-2.4.21-pre6/arch/ppc/kernel/ptrace.c
--- linux-2.4.20/arch/ppc/kernel/ptrace.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/ptrace.c	2003-03-26 23:49:19.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.ptrace.c 1.14 01/17/02 23:05:50 paulus
- */
-/*
  *  linux/arch/ppc/kernel/ptrace.c
  *
  *  PowerPC version
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/qspan_pci.c linux-2.4.21-pre6/arch/ppc/kernel/qspan_pci.c
--- linux-2.4.20/arch/ppc/kernel/qspan_pci.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/qspan_pci.c	2003-03-26 23:49:18.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * QSpan pci routines.
  * Most 8xx boards use the QSpan PCI bridge.  The config address register
  * is located 0x500 from the base of the bridge control/status registers.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/semaphore.c linux-2.4.21-pre6/arch/ppc/kernel/semaphore.c
--- linux-2.4.20/arch/ppc/kernel/semaphore.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/semaphore.c	2003-03-26 23:49:51.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.semaphore.c 1.12 05/17/01 18:14:22 cort
- */
-/*
  * PowerPC-specific semaphore code.
  *
  * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu>
@@ -39,6 +36,7 @@
 "	srawi	%1,%0,31\n"
 "	andc	%1,%0,%1\n"
 "	add	%1,%1,%4\n"
+	PPC405_ERR77(0,%3)
 "	stwcx.	%1,0,%3\n"
 "	bne	1b"
 	: "=&r" (old_count), "=&r" (tmp), "=m" (sem->count)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/setup.c linux-2.4.21-pre6/arch/ppc/kernel/setup.c
--- linux-2.4.20/arch/ppc/kernel/setup.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/setup.c	2003-03-26 23:49:30.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Common prep/pmac/chrp boot and setup code.
  */
 
@@ -35,6 +32,7 @@
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/pmac_feature.h>
+#include <asm/kgdb.h>
 
 extern void platform_init(unsigned long r3, unsigned long r4,
 		unsigned long r5, unsigned long r6, unsigned long r7);
@@ -478,6 +476,12 @@
 		case BI_MEMSIZE:
 			boot_mem_size = data[0];
 			break;
+		case BI_BOARD_INFO:
+			/* data is typically a bd_t */
+			if (ppc_md.board_info)
+				ppc_md.board_info((void *)data,
+					rec->size - sizeof(struct bi_record));
+			break;
 		}
 		rec = (struct bi_record *)((ulong)rec + rec->size);
 	}
@@ -562,7 +566,14 @@
 #if defined(CONFIG_KGDB)
 	kgdb_map_scc();
 	set_debug_traps();
-	breakpoint();
+	if (strstr(cmd_line, "nokgdb"))
+		printk("kgdb default breakpoint deactivated on command line\n");
+	else {
+		if (ppc_md.progress)
+			ppc_md.progress("setup_arch: kgdb breakpoint", 0x4000);
+		printk("kgdb default breakpoint activated\n");
+		breakpoint();
+	}
 #endif
 
 	/*
@@ -603,101 +614,3 @@
 	/* this is for modules since _machine can be a define -- Cort */
 	ppc_md.ppc_machine = _machine;
 }
-
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) \
-	|| defined(CONFIG_USB_STORAGE) || defined(CONFIG_USB_STORAGE_MODULE)
-/* Convert the shorts/longs in hd_driveid from little to big endian;
- * chars are endian independant, of course, but strings need to be flipped.
- * (Despite what it says in drivers/block/ide.h, they come up as little
- * endian...)
- *
- * Changes to linux/hdreg.h may require changes here. */
-void ppc_generic_ide_fix_driveid(struct hd_driveid *id)
-{
-        int i;
-	unsigned short *stringcast;
-
-	id->config         = __le16_to_cpu(id->config);
-	id->cyls           = __le16_to_cpu(id->cyls);
-	id->reserved2      = __le16_to_cpu(id->reserved2);
-	id->heads          = __le16_to_cpu(id->heads);
-	id->track_bytes    = __le16_to_cpu(id->track_bytes);
-	id->sector_bytes   = __le16_to_cpu(id->sector_bytes);
-	id->sectors        = __le16_to_cpu(id->sectors);
-	id->vendor0        = __le16_to_cpu(id->vendor0);
-	id->vendor1        = __le16_to_cpu(id->vendor1);
-	id->vendor2        = __le16_to_cpu(id->vendor2);
-	stringcast = (unsigned short *)&id->serial_no[0];
-	for (i = 0; i < (20/2); i++)
-	        stringcast[i] = __le16_to_cpu(stringcast[i]);
-	id->buf_type       = __le16_to_cpu(id->buf_type);
-	id->buf_size       = __le16_to_cpu(id->buf_size);
-	id->ecc_bytes      = __le16_to_cpu(id->ecc_bytes);
-	stringcast = (unsigned short *)&id->fw_rev[0];
-	for (i = 0; i < (8/2); i++)
-	        stringcast[i] = __le16_to_cpu(stringcast[i]);
-	stringcast = (unsigned short *)&id->model[0];
-	for (i = 0; i < (40/2); i++)
-	        stringcast[i] = __le16_to_cpu(stringcast[i]);
-	id->dword_io       = __le16_to_cpu(id->dword_io);
-	id->reserved50     = __le16_to_cpu(id->reserved50);
-	id->field_valid    = __le16_to_cpu(id->field_valid);
-	id->cur_cyls       = __le16_to_cpu(id->cur_cyls);
-	id->cur_heads      = __le16_to_cpu(id->cur_heads);
-	id->cur_sectors    = __le16_to_cpu(id->cur_sectors);
-	id->cur_capacity0  = __le16_to_cpu(id->cur_capacity0);
-	id->cur_capacity1  = __le16_to_cpu(id->cur_capacity1);
-	id->lba_capacity   = __le32_to_cpu(id->lba_capacity);
-	id->dma_1word      = __le16_to_cpu(id->dma_1word);
-	id->dma_mword      = __le16_to_cpu(id->dma_mword);
-	id->eide_pio_modes = __le16_to_cpu(id->eide_pio_modes);
-	id->eide_dma_min   = __le16_to_cpu(id->eide_dma_min);
-	id->eide_dma_time  = __le16_to_cpu(id->eide_dma_time);
-	id->eide_pio       = __le16_to_cpu(id->eide_pio);
-	id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy);
-	for (i = 0; i < 2; i++)
-		id->words69_70[i] = __le16_to_cpu(id->words69_70[i]);
-        for (i = 0; i < 4; i++)
-                id->words71_74[i] = __le16_to_cpu(id->words71_74[i]);
-	id->queue_depth	   = __le16_to_cpu(id->queue_depth);
-	for (i = 0; i < 4; i++)
-		id->words76_79[i] = __le16_to_cpu(id->words76_79[i]);
-	id->major_rev_num  = __le16_to_cpu(id->major_rev_num);
-	id->minor_rev_num  = __le16_to_cpu(id->minor_rev_num);
-	id->command_set_1  = __le16_to_cpu(id->command_set_1);
-	id->command_set_2  = __le16_to_cpu(id->command_set_2);
-	id->cfsse          = __le16_to_cpu(id->cfsse);
-	id->cfs_enable_1   = __le16_to_cpu(id->cfs_enable_1);
-	id->cfs_enable_2   = __le16_to_cpu(id->cfs_enable_2);
-	id->csf_default    = __le16_to_cpu(id->csf_default);
-	id->dma_ultra      = __le16_to_cpu(id->dma_ultra);
-	id->word89         = __le16_to_cpu(id->word89);
-	id->word90         = __le16_to_cpu(id->word90);
-	id->CurAPMvalues   = __le16_to_cpu(id->CurAPMvalues);
-	id->word92         = __le16_to_cpu(id->word92);
-	id->hw_config      = __le16_to_cpu(id->hw_config);
-	id->acoustic       = __le16_to_cpu(id->acoustic);
-	for (i = 0; i < 5; i++)
-		id->words95_99[i]  = __le16_to_cpu(id->words95_99[i]);
-	id->lba_capacity_2 = __le64_to_cpu(id->lba_capacity_2);
-	for (i = 0; i < 22; i++)
-		id->words104_125[i]   = __le16_to_cpu(id->words104_125[i]);
-	id->last_lun       = __le16_to_cpu(id->last_lun);
-	id->word127        = __le16_to_cpu(id->word127);
-	id->dlf            = __le16_to_cpu(id->dlf);
-	id->csfo           = __le16_to_cpu(id->csfo);
-	for (i = 0; i < 26; i++)
-		id->words130_155[i] = __le16_to_cpu(id->words130_155[i]);
-	id->word156        = __le16_to_cpu(id->word156);
-	for (i = 0; i < 3; i++)
-		id->words157_159[i] = __le16_to_cpu(id->words157_159[i]);
-	id->cfa_power      = __le16_to_cpu(id->cfa_power);
-	for (i = 0; i < 14; i++)
-		id->words161_175[i] = __le16_to_cpu(id->words161_175[i]);
-	for (i = 0; i < 31; i++)
-		id->words176_205[i] = __le16_to_cpu(id->words176_205[i]);
-	for (i = 0; i < 48; i++)
-		id->words206_254[i] = __le16_to_cpu(id->words206_254[i]);
-	id->integrity_word  = __le16_to_cpu(id->integrity_word);
-}
-#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/signal.c linux-2.4.21-pre6/arch/ppc/kernel/signal.c
--- linux-2.4.20/arch/ppc/kernel/signal.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/signal.c	2003-03-26 23:49:35.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  linux/arch/ppc/kernel/signal.c
  *
  *  PowerPC version 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/smp.c linux-2.4.21-pre6/arch/ppc/kernel/smp.c
--- linux-2.4.20/arch/ppc/kernel/smp.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/smp.c	2003-03-26 23:49:30.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.smp.c 1.40 03/28/02 16:54:23 hozer
- */
-/*
  * Smp support for ppc.
  *
  * Written by Cort Dougan (cort@cs.nmt.edu) borrowing a great
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/softemu8xx.c linux-2.4.21-pre6/arch/ppc/kernel/softemu8xx.c
--- linux-2.4.20/arch/ppc/kernel/softemu8xx.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/softemu8xx.c	2003-03-26 23:49:39.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.softemu8xx.c 1.8 05/17/01 18:14:22 cort
- */
-/*
  * Software emulation of some PPC instructions for the 8xx core.
  *
  * Copyright (C) 1998 Dan Malek (dmalek@jlc.net)
@@ -35,6 +32,11 @@
 #include <asm/io.h>
 #include <asm/processor.h>
 
+extern void
+print_8xx_pte(struct mm_struct *mm, unsigned long addr);
+extern int
+get_8xx_pte(struct mm_struct *mm, unsigned long addr);
+
 /* Eventually we may need a look-up table, but this works for now.
 */
 #define LFS	48
@@ -117,7 +119,7 @@
 	default:
 		retval = 1;
 		printk("Bad emulation %s/%d\n"
-		       " NIP: %08x instruction: %08x opcode: %x "
+		       " NIP: %08lx instruction: %08x opcode: %x "
 		       "A: %x B: %x C: %x code: %x rc: %x\n",
 		       current->comm,current->pid,
 		       regs->nip,
@@ -128,13 +130,12 @@
 		       (instword>>1)&0x3ff,
 		       instword&1);
 		{
-			int pa;
+			unsigned long pa;
 			print_8xx_pte(current->mm,regs->nip);
-			pa = get_8xx_pte(current->mm,regs->nip) & PAGE_MASK;
-			pa |= (regs->nip & ~PAGE_MASK);
-			pa = __va(pa);
-			printk("Kernel VA for NIP %x ", pa);
-			print_8xx_pte(current->mm,pa);
+			pa = (get_8xx_pte(current->mm,regs->nip) & PAGE_MASK)
+				| (regs->nip & ~PAGE_MASK);
+			printk("Kernel VA for NIP 0x%p ", __va(pa));
+			print_8xx_pte(current->mm, (unsigned long)__va(pa));
 		}
 		
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/syscalls.c linux-2.4.21-pre6/arch/ppc/kernel/syscalls.c
--- linux-2.4.20/arch/ppc/kernel/syscalls.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/syscalls.c	2003-03-26 23:49:54.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.syscalls.c 1.13 03/13/02 09:12:22 trini
- */
-/*
  * linux/arch/ppc/kernel/sys_ppc.c
  *
  *  PowerPC version 
@@ -54,24 +51,6 @@
 	return -EIO;
 }
 
-int sys_iopl(int a1, int a2, int a3, int a4)
-{
-	printk(KERN_ERR "sys_iopl(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
-	return (-ENOSYS);
-}
-
-int sys_vm86(int a1, int a2, int a3, int a4)
-{
-	printk(KERN_ERR "sys_vm86(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
-	return (-ENOSYS);
-}
-
-int sys_modify_ldt(int a1, int a2, int a3, int a4)
-{
-	printk(KERN_ERR "sys_modify_ldt(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
-	return (-ENOSYS);
-}
-
 /*
  * sys_ipc() is the de-multiplexer for the SysV IPC calls..
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/time.c linux-2.4.21-pre6/arch/ppc/kernel/time.c
--- linux-2.4.20/arch/ppc/kernel/time.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/time.c	2003-03-26 23:49:18.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Common time routines among all ppc machines.
  *
  * Written by Cort Dougan (cort@cs.nmt.edu) to merge
@@ -186,7 +183,7 @@
 		 * We should have an rtc call that only sets the minutes and
 		 * seconds like on Intel to avoid problems with non UTC clocks.
 		 */
-		if ( (time_status & STA_UNSYNC) == 0 &&
+		if ( ppc_md.set_rtc_time && (time_status & STA_UNSYNC) == 0 &&
 		     xtime.tv_sec - last_rtc_update >= 659 &&
 		     abs(xtime.tv_usec - (1000000-1000000/HZ)) < 500000/HZ &&
 		     jiffies - wall_jiffies == 1) {
@@ -197,8 +194,6 @@
 				last_rtc_update += 60;
 		}
 		write_unlock(&xtime_lock);
-		
-
 	}
 	if (!disarm_decr[cpu])
 		set_dec(next_dec);
@@ -295,13 +290,11 @@
 	write_unlock_irqrestore(&xtime_lock, flags);
 }
 
-
+/* This function is only called on the boot processor */
 void __init time_init(void)
 {
 	time_t sec, old_sec;
 	unsigned old_stamp, stamp, elapsed;
-	/* This function is only called on the boot processor */
-	unsigned long flags;
 
         if (ppc_md.time_init != NULL)
                 time_offset = ppc_md.time_init();
@@ -318,32 +311,33 @@
 	/* Now that the decrementer is calibrated, it can be used in case the 
 	 * clock is stuck, but the fact that we have to handle the 601
 	 * makes things more complex. Repeatedly read the RTC until the
-	 * next second boundary to try to achieve some precision...
+	 * next second boundary to try to achieve some precision.  If there
+	 * is no RTC, we still need to set tb_last_stamp and
+	 * last_jiffy_stamp(cpu 0) to the current stamp.
 	 */
+	stamp = get_native_tbl();
 	if (ppc_md.get_rtc_time) {
-		stamp = get_native_tbl();
 		sec = ppc_md.get_rtc_time();
 		elapsed = 0;
 		do {
 			old_stamp = stamp; 
 			old_sec = sec;
 			stamp = get_native_tbl();
-			if (__USE_RTC() && stamp < old_stamp) old_stamp -= 1000000000;
+			if (__USE_RTC() && stamp < old_stamp)
+				old_stamp -= 1000000000;
 			elapsed += stamp - old_stamp;
 			sec = ppc_md.get_rtc_time();
 		} while ( sec == old_sec && elapsed < 2*HZ*tb_ticks_per_jiffy);
-		if (sec==old_sec) {
+		if (sec == old_sec)
 			printk("Warning: real time clock seems stuck!\n");
-		}
-		write_lock_irqsave(&xtime_lock, flags);
 		xtime.tv_sec = sec;
-		last_jiffy_stamp(0) = tb_last_stamp = stamp;
 		xtime.tv_usec = 0;
 		/* No update now, we just read the time from the RTC ! */
 		last_rtc_update = xtime.tv_sec;
-		write_unlock_irqrestore(&xtime_lock, flags);
 	}
 
+	last_jiffy_stamp(0) = tb_last_stamp = stamp;
+
 	/* Not exact, but the timer interrupt takes care of this */
 	set_dec(tb_ticks_per_jiffy);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/todc_time.c linux-2.4.21-pre6/arch/ppc/kernel/todc_time.c
--- linux-2.4.20/arch/ppc/kernel/todc_time.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/todc_time.c	2003-03-26 23:48:59.000000000 +0000
@@ -7,12 +7,10 @@
  * Author: Mark A. Greer
  *         mgreer@mvista.com
  *
- * Copyright 2001 MontaVista Software Inc.
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
+ * 2001 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
  */
 #include <linux/errno.h>
 #include <linux/init.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/kernel/traps.c linux-2.4.21-pre6/arch/ppc/kernel/traps.c
--- linux-2.4.20/arch/ppc/kernel/traps.c	2001-11-03 01:43:54.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/kernel/traps.c	2003-03-26 23:49:16.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.traps.c 1.22 10/11/01 10:33:09 paulus
- */
-/*
  *  linux/arch/ppc/kernel/traps.c
  *
  *  Copyright (C) 1995-1996  Gary Thomas (gdt@linuxppc.org)
@@ -38,6 +35,9 @@
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/processor.h>
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#endif
 
 extern int fix_alignment(struct pt_regs *);
 extern void bad_page_fault(struct pt_regs *, unsigned long, int sig);
@@ -66,6 +66,13 @@
 int (*debugger_iabr_match)(struct pt_regs *regs);
 int (*debugger_dabr_match)(struct pt_regs *regs);
 void (*debugger_fault_handler)(struct pt_regs *regs);
+#else
+#define debugger(regs)			do { } while (0)
+#define debugger_bpt(regs)		0
+#define debugger_sstep(regs)		0
+#define debugger_iabr_match(regs)	0
+#define debugger_dabr_match(regs)	0
+#define debugger_fault_handler		((void (*)(struct pt_regs *))0)
 #endif
 #endif
 
@@ -74,15 +81,19 @@
  */
 
 
-spinlock_t oops_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
 
 void die(const char * str, struct pt_regs * fp, long err)
 {
 	console_verbose();
-	spin_lock_irq(&oops_lock);
+	spin_lock_irq(&die_lock);
+#ifdef CONFIG_PMAC_BACKLIGHT
+	set_backlight_enable(1);
+	set_backlight_level(BACKLIGHT_MAX);
+#endif
 	printk("Oops: %s, sig: %ld\n", str, err);
 	show_regs(fp);
-	spin_unlock_irq(&oops_lock);
+	spin_unlock_irq(&die_lock);
 	/* do_exit() should take care of panic'ing from an interrupt
 	 * context so we don't handle it here
 	 */
@@ -90,54 +101,37 @@
 }
 
 void
-_exception(int signr, struct pt_regs *regs)
+_exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
 {
-	if (!user_mode(regs))
-	{
-#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+	siginfo_t info;
+
+	if (!user_mode(regs)) {
 		debugger(regs);
-#endif
 		die("Exception in kernel mode", regs, signr);
 	}
-	force_sig(signr, current);
+	info.si_signo = signr;
+	info.si_errno = 0;
+	info.si_code = code;
+	info.si_addr = (void *) addr;
+	force_sig_info(signr, &info, current);
 }
 
-void
-MachineCheckException(struct pt_regs *regs)
+/*
+ * I/O accesses can cause machine checks on powermacs.
+ * Check if the NIP corresponds to the address of a sync
+ * instruction for which there is an entry in the exception
+ * table.
+ * Note that the 601 only takes a machine check on TEA
+ * (transfer error ack) signal assertion, and does not
+ * set any of the top 16 bits of SRR1.
+ *  -- paulus.
+ */
+static inline int check_io_access(struct pt_regs *regs)
 {
 #ifdef CONFIG_ALL_PPC
 	unsigned long fixup;
-#endif /* CONFIG_ALL_PPC */
 	unsigned long msr = regs->msr;
 
-	if (user_mode(regs)) {
-		_exception(SIGSEGV, regs);	
-		return;
-	}
-
-#if defined(CONFIG_8xx) && defined(CONFIG_PCI)
-	/* the qspan pci read routines can cause machine checks -- Cort */
-	bad_page_fault(regs, regs->dar, SIGBUS);
-	return;
-#endif
-#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
-	if (debugger_fault_handler) {
-		debugger_fault_handler(regs);
-		return;
-	}
-#endif
-
-#ifdef CONFIG_ALL_PPC
-	/*
-	 * I/O accesses can cause machine checks on powermacs.
-	 * Check if the NIP corresponds to the address of a sync
-	 * instruction for which there is an entry in the exception
-	 * table.
-	 * Note that the 601 only takes a machine check on TEA
-	 * (transfer error ack) signal assertion, and does not
-	 * set of the top 16 bits of SRR1.
-	 *  -- paulus.
-	 */
 	if (((msr & 0xffff0000) == 0 || (msr & (0x80000 | 0x40000)))
 	    && (fixup = search_exception_table(regs->nip)) != 0) {
 		/*
@@ -163,18 +157,72 @@
 			       (*nip & 0x100)? "OUT to": "IN from",
 			       regs->gpr[rb] - _IO_BASE, nip);
 			regs->nip = fixup;
-			return;
+			return 1;
 		}
 	}
 #endif /* CONFIG_ALL_PPC */
+	return 0;
+}
+
+#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
+/* On 4xx, the reason for the machine check or program exception
+   is in the ESR. */
+#define get_reason(regs)	mfspr(SPRN_ESR);
+#define REASON_FP		0
+#define REASON_ILLEGAL		ESR_PIL
+#define REASON_PRIVILEGED	ESR_PPR
+#define REASON_TRAP		ESR_PTR
+
+#else
+/* On non-4xx, the reason for the machine check or program
+   exception is in the MSR. */
+#define get_reason(regs)	((regs)->msr)
+#define REASON_FP		0x100000
+#define REASON_ILLEGAL		0x80000
+#define REASON_PRIVILEGED	0x40000
+#define REASON_TRAP		0x20000
+#endif
+
+void
+MachineCheckException(struct pt_regs *regs)
+{
+	unsigned long reason = get_reason(regs);
+
+	if (user_mode(regs)) {
+		_exception(SIGBUS, regs, BUS_ADRERR, regs->nip);
+		return;
+	}
+
+#if defined(CONFIG_8xx) && defined(CONFIG_PCI)
+	/* the qspan pci read routines can cause machine checks -- Cort */
+	bad_page_fault(regs, regs->dar, SIGBUS);
+	return;
+#endif
+	if (debugger_fault_handler) {
+		debugger_fault_handler(regs);
+		return;
+	}
+	if (check_io_access(regs))
+		return;
+
+#ifdef CONFIG_4xx
+	if (reason & ESR_IMCP) {
+		printk("Instruction");
+		mtspr(SPRN_ESR, reason & ~ESR_IMCP);
+	} else
+		printk("Data");
+	printk(" machine check in kernel mode.\n");
+
+#else /* CONFIG_4xx */
 	printk("Machine check in kernel mode.\n");
-	printk("Caused by (from SRR1=%lx): ", msr);
-	switch (msr & 0xF0000) {
+	printk("Caused by (from SRR1=%lx): ", reason);
+	switch (reason & 0x601F0000) {
 	case 0x80000:
 		printk("Machine check signal\n");
 		break;
 	case 0:		/* for 601 */
 	case 0x40000:
+	case 0x140000:	/* 7450 MSS error and TEA */
 		printk("Transfer error ack signal\n");
 		break;
 	case 0x20000:
@@ -183,26 +231,32 @@
 	case 0x10000:
 		printk("Address parity error signal\n");
 		break;
+	case 0x20000000:
+		printk("L1 Data Cache error\n");
+		break;
+	case 0x40000000:
+		printk("L1 Instruction Cache error\n");
+		break;
+	case 0x00100000:
+		printk("L2 data cache parity error\n");
+		break;
 	default:
 		printk("Unknown values in msr\n");
 	}
-#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
+#endif /* CONFIG_4xx */
+
 	debugger(regs);
-#endif
 	die("machine check", regs, SIGBUS);
 }
 
 void
 SMIException(struct pt_regs *regs)
 {
-#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
-	{
-		debugger(regs);
-		return;
-	}
-#endif
+	debugger(regs);
+#if !(defined(CONFIG_XMON) || defined(CONFIG_KGDB))
 	show_regs(regs);
 	panic("System Management Interrupt");
+#endif
 }
 
 void
@@ -210,23 +264,21 @@
 {
 	printk("Bad trap at PC: %lx, SR: %lx, vector=%lx    %s\n",
 	       regs->nip, regs->msr, regs->trap, print_tainted());
-	_exception(SIGTRAP, regs);	
+	_exception(SIGTRAP, regs, 0, 0);
 }
 
 void
 InstructionBreakpoint(struct pt_regs *regs)
 {
-#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
 	if (debugger_iabr_match(regs))
 		return;
-#endif
-	_exception(SIGTRAP, regs);
+	_exception(SIGTRAP, regs, TRAP_BRKPT, 0);
 }
 
 void
 RunModeException(struct pt_regs *regs)
 {
-	_exception(SIGTRAP, regs);	
+	_exception(SIGTRAP, regs, 0, 0);
 }
 
 /* Illegal instruction emulation support.  Originally written to
@@ -245,16 +297,16 @@
 static int
 emulate_instruction(struct pt_regs *regs)
 {
-	uint    instword;
-	uint    rd;
-	uint    retval;
+	u32 instword;
+	u32 rd;
+	int retval;
 
-	retval = EINVAL;
+	retval = -EINVAL;
 
 	if (!user_mode(regs))
 		return retval;
 
-	if (get_user(instword, (uint *)(regs->nip)))
+	if (get_user(instword, (u32 *)(regs->nip)))
 		return -EFAULT;
 
 	/* Emulate the mfspr rD, PVR.
@@ -263,60 +315,71 @@
 		rd = (instword >> 21) & 0x1f;
 		regs->gpr[rd] = mfspr(PVR);
 		retval = 0;
-	}
-	if (retval == 0)
 		regs->nip += 4;
-	return(retval);
+	}
+	return retval;
 }
 
 void
 ProgramCheckException(struct pt_regs *regs)
 {
-#if defined(CONFIG_4xx)
-	unsigned int esr = mfspr(SPRN_ESR);
+	unsigned int reason = get_reason(regs);
+	extern int do_mathemu(struct pt_regs *regs);
 
-	if (esr & ESR_PTR) {
-#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
-		if (debugger_bpt(regs))
-			return;
-#endif
-		_exception(SIGTRAP, regs);
-	} else {
-		_exception(SIGILL, regs);
-	}
-#else
-	if (regs->msr & 0x100000) {
+#ifdef CONFIG_MATH_EMULATION
+	if ((reason & REASON_ILLEGAL) && do_mathemu(regs) == 0)
+		return;
+#endif /* CONFIG_MATH_EMULATION */
+
+	if (reason & REASON_FP) {
 		/* IEEE FP exception */
-		_exception(SIGFPE, regs);
-	} else if (regs->msr & 0x20000) {
+		int code = 0;
+		u32 fpscr;
+
+		if (regs->msr & MSR_FP)
+			giveup_fpu(current);
+		fpscr = current->thread.fpscr;
+		fpscr &= fpscr << 22;	/* mask summary bits with enables */
+		if (fpscr & FPSCR_VX)
+			code = FPE_FLTINV;
+		else if (fpscr & FPSCR_OX)
+			code = FPE_FLTOVF;
+		else if (fpscr & FPSCR_UX)
+			code = FPE_FLTUND;
+		else if (fpscr & FPSCR_ZX)
+			code = FPE_FLTDIV;
+		else if (fpscr & FPSCR_XX)
+			code = FPE_FLTRES;
+		_exception(SIGFPE, regs, code, regs->nip);
+		return;
+	}
+
+	if (reason & REASON_TRAP) {
 		/* trap exception */
-#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
 		if (debugger_bpt(regs))
 			return;
-#endif
-		_exception(SIGTRAP, regs);
-	} else {
+		_exception(SIGTRAP, regs, TRAP_BRKPT, 0);
+		return;
+	}
+
+	if (reason & REASON_PRIVILEGED) {
 		/* Try to emulate it if we should. */
-		int errcode;
-		if ((errcode = emulate_instruction(regs))) {
-			if (errcode == -EFAULT)
-				_exception(SIGBUS, regs);
-			else
-				_exception(SIGILL, regs);
-		}
+		if (emulate_instruction(regs) == 0)
+			return;
+		_exception(SIGILL, regs, ILL_PRVOPC, regs->nip);
+		return;
 	}
-#endif
+
+	_exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
 }
 
 void
 SingleStepException(struct pt_regs *regs)
 {
 	regs->msr &= ~MSR_SE;  /* Turn off 'trace' bit */
-#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
 	if (debugger_sstep(regs))
 		return;
-#endif
-	_exception(SIGTRAP, regs);	
+	_exception(SIGTRAP, regs, TRAP_TRACE, 0);
 }
 
 void
@@ -332,12 +395,12 @@
 	if (fixed == -EFAULT) {
 		/* fixed == -EFAULT means the operand address was bad */
 		if (user_mode(regs))
-			force_sig(SIGSEGV, current);
+			_exception(SIGSEGV, regs, SEGV_ACCERR, regs->dar);
 		else
 			bad_page_fault(regs, regs->dar, SIGSEGV);
 		return;
 	}
-	_exception(SIGBUS, regs);	
+	_exception(SIGBUS, regs, BUS_ADRALN, regs->dar);
 }
 
 void
@@ -345,9 +408,7 @@
 {
 	printk(KERN_CRIT "Kernel stack overflow in process %p, r1=%lx\n",
 	       current, regs->gpr[1]);
-#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
 	debugger(regs);
-#endif
 	show_regs(regs);
 	panic("kernel stack overflow");
 }
@@ -365,29 +426,29 @@
 SoftwareEmulation(struct pt_regs *regs)
 {
 	extern int do_mathemu(struct pt_regs *);
+	extern int Soft_emulate_8xx(struct pt_regs *);
 	int errcode;
 
 	if (!user_mode(regs)) {
-#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
 		debugger(regs);
-#endif
 		die("Kernel Mode Software FPU Emulation", regs, SIGFPE);
 	}
 
 #ifdef CONFIG_MATH_EMULATION
-	if ((errcode = do_mathemu(regs))) {
+	errcode = do_mathemu(regs);
 #else
-	if ((errcode = Soft_emulate_8xx(regs))) {
+	errcode = Soft_emulate_8xx(regs);
 #endif
+	if (errcode) {
 		if (errcode > 0)
-			_exception(SIGFPE, regs);
+			_exception(SIGFPE, regs, 0, 0);
 		else if (errcode == -EFAULT)
-			_exception(SIGSEGV, regs);
+			_exception(SIGSEGV, regs, 0, 0);
 		else
-			_exception(SIGILL, regs);
+			_exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
 	}
 }
-#endif
+#endif /* CONFIG_8xx */
 
 #if !defined(CONFIG_TAU_INT)
 void
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/lib/Makefile linux-2.4.21-pre6/arch/ppc/lib/Makefile
--- linux-2.4.20/arch/ppc/lib/Makefile	2001-11-16 18:10:08.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/lib/Makefile	2003-03-26 23:48:59.000000000 +0000
@@ -1,5 +1,3 @@
-# BK Id: SCCS/s.Makefile 1.10 11/08/01 07:57:40 paulus
-#
 #
 # Makefile for ppc-specific library files..
 #
@@ -10,7 +8,7 @@
 
 export-objs		:= dec_and_lock.o
 
-obj-y			:= checksum.o string.o strcase.o dec_and_lock.o
+obj-y			:= checksum.o string.o strcase.o dec_and_lock.o div64.o
 
 obj-$(CONFIG_SMP)	+= locks.o
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/lib/checksum.S linux-2.4.21-pre6/arch/ppc/lib/checksum.S
--- linux-2.4.20/arch/ppc/lib/checksum.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/lib/checksum.S	2003-03-26 23:49:20.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * This file contains assembly-language implementations
  * of IP-style 1's complement checksum routines.
  *	
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/lib/div64.S linux-2.4.21-pre6/arch/ppc/lib/div64.S
--- linux-2.4.20/arch/ppc/lib/div64.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/lib/div64.S	2003-03-26 23:48:57.000000000 +0000
@@ -0,0 +1,58 @@
+/*
+ * Divide a 64-bit unsigned number by a 32-bit unsigned number.
+ * This routine assumes that the top 32 bits of the dividend are
+ * non-zero to start with.
+ * On entry, r3 points to the dividend, which get overwritten with
+ * the 64-bit quotient, and r4 contains the divisor.
+ * On exit, r3 contains the remainder.
+ *
+ * Copyright (C) 2002 Paul Mackerras, IBM Corp.
+ *
+ * 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 <asm/ppc_asm.h>
+#include <asm/processor.h>
+
+_GLOBAL(__div64_32)
+	lwz	r5,0(r3)	# get the dividend into r5/r6
+	lwz	r6,4(r3)
+	cmplw	r5,r4
+	li	r7,0
+	li	r8,0
+	blt	1f
+	divwu	r7,r5,r4	# if dividend.hi >= divisor,
+	mullw	r0,r7,r4	# quotient.hi = dividend.hi / divisor
+	subf.	r5,r0,r5	# dividend.hi %= divisor
+	beq	3f
+1:	mr	r11,r5		# here dividend.hi != 0
+	andis.	r0,r5,0xc000
+	bne	2f
+	cntlzw	r0,r5		# we are shifting the dividend right
+	li	r10,-1		# to make it < 2^32, and shifting
+	srw	r10,r10,r0	# the divisor right the same amount,
+	add	r9,r4,r10	# rounding up (so the estimate cannot
+	andc	r11,r6,r10	# ever be too large, only too small)
+	andc	r9,r9,r10
+	or	r11,r5,r11
+	rotlw	r9,r9,r0
+	rotlw	r11,r11,r0
+	divwu	r11,r11,r9	# then we divide the shifted quantities
+2:	mullw	r10,r11,r4	# to get an estimate of the quotient,
+	mulhwu	r9,r11,r4	# multiply the estimate by the divisor,
+	subfc	r6,r10,r6	# take the product from the divisor,
+	add	r8,r8,r11	# and add the estimate to the accumulated
+	subfe.	r5,r9,r5	# quotient
+	bne	1b
+3:	cmplw	r6,r4
+	blt	4f
+	divwu	r0,r6,r4	# perform the remaining 32-bit division
+	mullw	r10,r0,r4	# and get the remainder
+	add	r8,r8,r0
+	subf	r6,r10,r6
+4:	stw	r7,0(r3)	# return the quotient in *r3
+	stw	r8,4(r3)
+	mr	r3,r6		# return the remainder in r3
+	blr
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/lib/locks.c linux-2.4.21-pre6/arch/ppc/lib/locks.c
--- linux-2.4.20/arch/ppc/lib/locks.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/lib/locks.c	2003-03-26 23:49:18.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Locks for smp ppc 
  * 
  * Written by Cort Dougan (cort@cs.nmt.edu)
@@ -35,8 +32,9 @@
 	__asm__ __volatile__ ("\n\
 1:	lwarx	%0,0,%1\n\
 	cmpwi	0,%0,0\n\
-	bne	2f\n\
-	stwcx.	%2,0,%1\n\
+	bne	2f\n"
+	PPC405_ERR77(0,%1)
+"	stwcx.	%2,0,%1\n\
 	bne-	1b\n\
 	isync\n\
 2:"
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/lib/strcase.c linux-2.4.21-pre6/arch/ppc/lib/strcase.c
--- linux-2.4.20/arch/ppc/lib/strcase.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/lib/strcase.c	2003-03-26 23:49:55.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.strcase.c 1.5 05/17/01 18:14:22 cort
- */
 #include <linux/ctype.h>
 
 int strcasecmp(const char *s1, const char *s2)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/lib/string.S linux-2.4.21-pre6/arch/ppc/lib/string.S
--- linux-2.4.20/arch/ppc/lib/string.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/lib/string.S	2003-03-26 23:49:40.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * String handling functions for PowerPC.
  *
  * Copyright (C) 1996 Paul Mackerras.
@@ -445,23 +442,23 @@
 
 #if !defined(CONFIG_8xx)
 	/* Here we decide how far ahead to prefetch the source */
-#if MAX_L1_COPY_PREFETCH > 1
+#if MAX_COPY_PREFETCH > 1
 	/* Heuristically, for large transfers we prefetch
-	   MAX_L1_COPY_PREFETCH cachelines ahead.  For small transfers
+	   MAX_COPY_PREFETCH cachelines ahead.  For small transfers
 	   we prefetch 1 cacheline ahead. */
-	cmpwi	r0,MAX_L1_COPY_PREFETCH
+	cmpwi	r0,MAX_COPY_PREFETCH
 	li	r7,1
 	li	r3,4
 	ble	111f
-	li	r7,MAX_L1_COPY_PREFETCH
+	li	r7,MAX_COPY_PREFETCH
 111:	mtctr	r7
 112:	dcbt	r3,r4
 	addi	r3,r3,CACHELINE_BYTES
 	bdnz	112b
-#else /* MAX_L1_COPY_PREFETCH == 1 */
+#else /* MAX_COPY_PREFETCH == 1 */
 	li	r3,CACHELINE_BYTES + 4
 	dcbt	r11,r4
-#endif /* MAX_L1_COPY_PREFETCH */
+#endif /* MAX_COPY_PREFETCH */
 #endif /* CONFIG_8xx */
 
 	mtctr	r0
@@ -517,18 +514,18 @@
 	blr
 
 /* read fault, initial single-byte copy */
-100:	li	r4,0
+100:	li	r9,0
 	b	90f
 /* write fault, initial single-byte copy */
-101:	li	r4,1
+101:	li	r9,1
 90:	subf	r5,r8,r5
 	li	r3,0
 	b	99f
 /* read fault, initial word copy */
-102:	li	r4,0
+102:	li	r9,0
 	b	91f
 /* write fault, initial word copy */
-103:	li	r4,1
+103:	li	r9,1
 91:	li	r3,2
 	b	99f
 
@@ -552,38 +549,47 @@
 #endif
 
 /* read fault in cacheline loop */
-104:	li	r4,0
+104:	li	r9,0
 	b	92f
 /* fault on dcbz (effectively a write fault) */
 /* or write fault in cacheline loop */
-105:	li	r4,1
+105:	li	r9,1
 92:	li	r3,LG_CACHELINE_BYTES
 	b	99f
 /* read fault in final word loop */
-108:	li	r4,0
+108:	li	r9,0
 	b	93f
 /* write fault in final word loop */
-109:	li	r4,1
+109:	li	r9,1
 93:	andi.	r5,r5,3
 	li	r3,2
 	b	99f
 /* read fault in final byte loop */
-110:	li	r4,0
+110:	li	r9,0
 	b	94f
 /* write fault in final byte loop */
-111:	li	r4,1
+111:	li	r9,1
 94:	li	r5,0
 	li	r3,0
 /*
  * At this stage the number of bytes not copied is
- * r5 + (ctr << r3), and r4 is 0 for read or 1 for write.
+ * r5 + (ctr << r3), and r9 is 0 for read or 1 for write.
  */
 99:	mfctr	r0
 	slw	r3,r0,r3
-	add	r3,r3,r5
-	cmpwi	0,r4,0
+	add.	r3,r3,r5
+	beq	120f			/* shouldn't happen */
+	cmpwi	0,r9,0
 	bne	120f
-/* for read fault, clear out the destination: r3 bytes starting at 4(r6) */
+/* for a read fault, first try to continue the copy one byte at a time */
+	mtctr	r3
+130:	lbz	r0,4(r4)
+131:	stb	r0,4(r6)
+	addi	r4,r4,1
+	addi	r6,r6,1
+	bdnz	130b
+/* then clear out the destination: r3 bytes starting at 4(r6) */
+132:	mfctr	r3
 	srwi.	r0,r3,2
 	li	r9,0
 	mtctr	r0
@@ -604,6 +610,8 @@
 	.long	31b,109b
 	.long	40b,110b
 	.long	41b,111b
+	.long	130b,132b
+	.long	131b,120b
 	.long	112b,120b
 	.long	114b,120b
 	.text
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/Makefile linux-2.4.21-pre6/arch/ppc/math-emu/Makefile
--- linux-2.4.20/arch/ppc/math-emu/Makefile	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/Makefile	2003-03-26 23:49:51.000000000 +0000
@@ -1,5 +1,3 @@
-# BK Id: SCCS/s.Makefile 1.3 05/17/01 18:14:22 cort
-#
 #
 #
 #
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/double.h linux-2.4.21-pre6/arch/ppc/math-emu/double.h
--- linux-2.4.20/arch/ppc/math-emu/double.h	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/double.h	2003-03-26 23:49:40.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.double.h 1.5 05/17/01 18:14:22 cort
- */
-/*
  * Definitions for IEEE Double Precision
  */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fabs.c linux-2.4.21-pre6/arch/ppc/math-emu/fabs.c
--- linux-2.4.20/arch/ppc/math-emu/fabs.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/fabs.c	2003-03-26 23:49:10.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fabs.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fadd.c linux-2.4.21-pre6/arch/ppc/math-emu/fadd.c
--- linux-2.4.20/arch/ppc/math-emu/fadd.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/fadd.c	2003-03-26 23:49:29.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fadd.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fadds.c linux-2.4.21-pre6/arch/ppc/math-emu/fadds.c
--- linux-2.4.20/arch/ppc/math-emu/fadds.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/fadds.c	2003-03-26 23:48:59.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fadds.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fcmpo.c linux-2.4.21-pre6/arch/ppc/math-emu/fcmpo.c
--- linux-2.4.20/arch/ppc/math-emu/fcmpo.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/fcmpo.c	2003-03-26 23:49:35.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fcmpo.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fcmpu.c linux-2.4.21-pre6/arch/ppc/math-emu/fcmpu.c
--- linux-2.4.20/arch/ppc/math-emu/fcmpu.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/fcmpu.c	2003-03-26 23:49:09.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fcmpu.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fctiw.c linux-2.4.21-pre6/arch/ppc/math-emu/fctiw.c
--- linux-2.4.20/arch/ppc/math-emu/fctiw.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/fctiw.c	2003-03-26 23:49:40.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fctiw.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fctiwz.c linux-2.4.21-pre6/arch/ppc/math-emu/fctiwz.c
--- linux-2.4.20/arch/ppc/math-emu/fctiwz.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/fctiwz.c	2003-03-26 23:48:59.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fctiwz.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fdiv.c linux-2.4.21-pre6/arch/ppc/math-emu/fdiv.c
--- linux-2.4.20/arch/ppc/math-emu/fdiv.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/fdiv.c	2003-03-26 23:49:30.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fdiv.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fdivs.c linux-2.4.21-pre6/arch/ppc/math-emu/fdivs.c
--- linux-2.4.20/arch/ppc/math-emu/fdivs.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/fdivs.c	2003-03-26 23:49:39.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fdivs.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fmadd.c linux-2.4.21-pre6/arch/ppc/math-emu/fmadd.c
--- linux-2.4.20/arch/ppc/math-emu/fmadd.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/fmadd.c	2003-03-26 23:49:54.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fmadd.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fmadds.c linux-2.4.21-pre6/arch/ppc/math-emu/fmadds.c
--- linux-2.4.20/arch/ppc/math-emu/fmadds.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/fmadds.c	2003-03-26 23:49:20.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fmadds.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fmr.c linux-2.4.21-pre6/arch/ppc/math-emu/fmr.c
--- linux-2.4.20/arch/ppc/math-emu/fmr.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/fmr.c	2003-03-26 23:49:06.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fmr.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fmsub.c linux-2.4.21-pre6/arch/ppc/math-emu/fmsub.c
--- linux-2.4.20/arch/ppc/math-emu/fmsub.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/fmsub.c	2003-03-26 23:49:55.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fmsub.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fmsubs.c linux-2.4.21-pre6/arch/ppc/math-emu/fmsubs.c
--- linux-2.4.20/arch/ppc/math-emu/fmsubs.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/fmsubs.c	2003-03-26 23:49:53.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fmsubs.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fmul.c linux-2.4.21-pre6/arch/ppc/math-emu/fmul.c
--- linux-2.4.20/arch/ppc/math-emu/fmul.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/fmul.c	2003-03-26 23:49:25.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fmul.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fmuls.c linux-2.4.21-pre6/arch/ppc/math-emu/fmuls.c
--- linux-2.4.20/arch/ppc/math-emu/fmuls.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/fmuls.c	2003-03-26 23:49:21.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fmuls.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fnabs.c linux-2.4.21-pre6/arch/ppc/math-emu/fnabs.c
--- linux-2.4.20/arch/ppc/math-emu/fnabs.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/fnabs.c	2003-03-26 23:49:49.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fnabs.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fneg.c linux-2.4.21-pre6/arch/ppc/math-emu/fneg.c
--- linux-2.4.20/arch/ppc/math-emu/fneg.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/fneg.c	2003-03-26 23:49:40.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fneg.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fnmadd.c linux-2.4.21-pre6/arch/ppc/math-emu/fnmadd.c
--- linux-2.4.20/arch/ppc/math-emu/fnmadd.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/fnmadd.c	2003-03-26 23:49:51.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fnmadd.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fnmadds.c linux-2.4.21-pre6/arch/ppc/math-emu/fnmadds.c
--- linux-2.4.20/arch/ppc/math-emu/fnmadds.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/fnmadds.c	2003-03-26 23:49:25.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fnmadds.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fnmsub.c linux-2.4.21-pre6/arch/ppc/math-emu/fnmsub.c
--- linux-2.4.20/arch/ppc/math-emu/fnmsub.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/fnmsub.c	2003-03-26 23:49:39.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fnmsub.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fnmsubs.c linux-2.4.21-pre6/arch/ppc/math-emu/fnmsubs.c
--- linux-2.4.20/arch/ppc/math-emu/fnmsubs.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/fnmsubs.c	2003-03-26 23:48:57.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fnmsubs.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fres.c linux-2.4.21-pre6/arch/ppc/math-emu/fres.c
--- linux-2.4.20/arch/ppc/math-emu/fres.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/fres.c	2003-03-26 23:48:58.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fres.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/frsp.c linux-2.4.21-pre6/arch/ppc/math-emu/frsp.c
--- linux-2.4.20/arch/ppc/math-emu/frsp.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/frsp.c	2003-03-26 23:49:08.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.frsp.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/frsqrte.c linux-2.4.21-pre6/arch/ppc/math-emu/frsqrte.c
--- linux-2.4.20/arch/ppc/math-emu/frsqrte.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/frsqrte.c	2003-03-26 23:49:34.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.frsqrte.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fsel.c linux-2.4.21-pre6/arch/ppc/math-emu/fsel.c
--- linux-2.4.20/arch/ppc/math-emu/fsel.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/fsel.c	2003-03-26 23:49:08.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fsel.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fsqrt.c linux-2.4.21-pre6/arch/ppc/math-emu/fsqrt.c
--- linux-2.4.20/arch/ppc/math-emu/fsqrt.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/fsqrt.c	2003-03-26 23:49:07.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fsqrt.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fsqrts.c linux-2.4.21-pre6/arch/ppc/math-emu/fsqrts.c
--- linux-2.4.20/arch/ppc/math-emu/fsqrts.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/fsqrts.c	2003-03-26 23:48:57.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fsqrts.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fsub.c linux-2.4.21-pre6/arch/ppc/math-emu/fsub.c
--- linux-2.4.20/arch/ppc/math-emu/fsub.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/fsub.c	2003-03-26 23:49:55.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fsub.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/fsubs.c linux-2.4.21-pre6/arch/ppc/math-emu/fsubs.c
--- linux-2.4.20/arch/ppc/math-emu/fsubs.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/fsubs.c	2003-03-26 23:49:40.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fsubs.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/lfd.c linux-2.4.21-pre6/arch/ppc/math-emu/lfd.c
--- linux-2.4.20/arch/ppc/math-emu/lfd.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/lfd.c	2003-03-26 23:49:16.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.lfd.c 1.6 05/17/01 18:14:23 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/lfs.c linux-2.4.21-pre6/arch/ppc/math-emu/lfs.c
--- linux-2.4.20/arch/ppc/math-emu/lfs.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/lfs.c	2003-03-26 23:49:56.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.lfs.c 1.6 05/17/01 18:14:23 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/math.c linux-2.4.21-pre6/arch/ppc/math-emu/math.c
--- linux-2.4.20/arch/ppc/math-emu/math.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/math.c	2003-03-26 23:49:29.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.math.c 1.6 05/17/01 18:14:23 cort
- */
-/*
  * arch/ppc/math-emu/math.c
  *
  * Copyright (C) 1999  Eddie C. Dost  (ecd@atecom.com)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/mcrfs.c linux-2.4.21-pre6/arch/ppc/math-emu/mcrfs.c
--- linux-2.4.20/arch/ppc/math-emu/mcrfs.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/mcrfs.c	2003-03-26 23:49:19.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.mcrfs.c 1.6 05/17/01 18:14:23 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/mffs.c linux-2.4.21-pre6/arch/ppc/math-emu/mffs.c
--- linux-2.4.20/arch/ppc/math-emu/mffs.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/mffs.c	2003-03-26 23:49:55.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.mffs.c 1.6 05/17/01 18:14:23 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/mtfsb0.c linux-2.4.21-pre6/arch/ppc/math-emu/mtfsb0.c
--- linux-2.4.20/arch/ppc/math-emu/mtfsb0.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/mtfsb0.c	2003-03-26 23:49:00.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.mtfsb0.c 1.6 05/17/01 18:14:23 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/mtfsb1.c linux-2.4.21-pre6/arch/ppc/math-emu/mtfsb1.c
--- linux-2.4.20/arch/ppc/math-emu/mtfsb1.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/mtfsb1.c	2003-03-26 23:49:50.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.mtfsb1.c 1.6 05/17/01 18:14:23 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/mtfsf.c linux-2.4.21-pre6/arch/ppc/math-emu/mtfsf.c
--- linux-2.4.20/arch/ppc/math-emu/mtfsf.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/mtfsf.c	2003-03-26 23:48:57.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.mtfsf.c 1.6 05/17/01 18:14:23 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/mtfsfi.c linux-2.4.21-pre6/arch/ppc/math-emu/mtfsfi.c
--- linux-2.4.20/arch/ppc/math-emu/mtfsfi.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/mtfsfi.c	2003-03-26 23:49:55.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.mtfsfi.c 1.6 05/17/01 18:14:23 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/op-1.h linux-2.4.21-pre6/arch/ppc/math-emu/op-1.h
--- linux-2.4.20/arch/ppc/math-emu/op-1.h	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/op-1.h	2003-03-26 23:49:29.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.op-1.h 1.5 05/17/01 18:14:23 cort
- */
-/*
  * Basic one-word fraction declaration and manipulation.
  */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/op-2.h linux-2.4.21-pre6/arch/ppc/math-emu/op-2.h
--- linux-2.4.20/arch/ppc/math-emu/op-2.h	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/op-2.h	2003-03-26 23:48:57.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.op-2.h 1.5 05/17/01 18:14:23 cort
- */
-/*
  * Basic two-word fraction declaration and manipulation.
  */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/op-4.h linux-2.4.21-pre6/arch/ppc/math-emu/op-4.h
--- linux-2.4.20/arch/ppc/math-emu/op-4.h	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/op-4.h	2003-03-26 23:49:34.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.op-4.h 1.5 05/17/01 18:14:23 cort
- */
-/*
  * Basic four-word fraction declaration and manipulation.
  *
  * When adding quadword support for 32 bit machines, we need
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/op-common.h linux-2.4.21-pre6/arch/ppc/math-emu/op-common.h
--- linux-2.4.20/arch/ppc/math-emu/op-common.h	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/op-common.h	2003-03-26 23:49:53.000000000 +0000
@@ -1,7 +1,3 @@
-/*
- * BK Id: SCCS/s.op-common.h 1.5 05/17/01 18:14:23 cort
- */
-
 #define _FP_DECL(wc, X)			\
   _FP_I_TYPE X##_c, X##_s, X##_e;	\
   _FP_FRAC_DECL_##wc(X)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/sfp-machine.h linux-2.4.21-pre6/arch/ppc/math-emu/sfp-machine.h
--- linux-2.4.20/arch/ppc/math-emu/sfp-machine.h	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/sfp-machine.h	2003-03-26 23:49:18.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.sfp-machine.h 1.5 05/17/01 18:14:23 cort
- */
 /* Machine-dependent software floating-point definitions.  PPC version.
    Copyright (C) 1997 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/single.h linux-2.4.21-pre6/arch/ppc/math-emu/single.h
--- linux-2.4.20/arch/ppc/math-emu/single.h	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/single.h	2003-03-26 23:48:58.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.single.h 1.5 05/17/01 18:14:23 cort
- */
-/*
  * Definitions for IEEE Single Precision
  */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/soft-fp.h linux-2.4.21-pre6/arch/ppc/math-emu/soft-fp.h
--- linux-2.4.20/arch/ppc/math-emu/soft-fp.h	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/soft-fp.h	2003-03-26 23:49:18.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.soft-fp.h 1.5 05/17/01 18:14:23 cort
- */
 #ifndef SOFT_FP_H
 #define SOFT_FP_H
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/stfd.c linux-2.4.21-pre6/arch/ppc/math-emu/stfd.c
--- linux-2.4.20/arch/ppc/math-emu/stfd.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/stfd.c	2003-03-26 23:49:40.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.stfd.c 1.6 05/17/01 18:14:23 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/stfiwx.c linux-2.4.21-pre6/arch/ppc/math-emu/stfiwx.c
--- linux-2.4.20/arch/ppc/math-emu/stfiwx.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/stfiwx.c	2003-03-26 23:49:20.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.stfiwx.c 1.6 05/17/01 18:14:23 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/stfs.c linux-2.4.21-pre6/arch/ppc/math-emu/stfs.c
--- linux-2.4.20/arch/ppc/math-emu/stfs.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/stfs.c	2003-03-26 23:49:18.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.stfs.c 1.6 05/17/01 18:14:23 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/types.c linux-2.4.21-pre6/arch/ppc/math-emu/types.c
--- linux-2.4.20/arch/ppc/math-emu/types.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/types.c	2003-03-26 23:48:57.000000000 +0000
@@ -1,7 +1,3 @@
-/*
- * BK Id: SCCS/s.types.c 1.5 05/17/01 18:14:23 cort
- */
-
 #include "soft-fp.h"
 #include "double.h"
 #include "single.h"
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/math-emu/udivmodti4.c linux-2.4.21-pre6/arch/ppc/math-emu/udivmodti4.c
--- linux-2.4.20/arch/ppc/math-emu/udivmodti4.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/math-emu/udivmodti4.c	2003-03-26 23:49:35.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.udivmodti4.c 1.5 05/17/01 18:14:23 cort
- */
 /* This has so very few changes over libgcc2's __udivmoddi4 it isn't funny.  */
 
 #include "soft-fp.h"
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/mm/4xx_mmu.c linux-2.4.21-pre6/arch/ppc/mm/4xx_mmu.c
--- linux-2.4.20/arch/ppc/mm/4xx_mmu.c	2001-11-03 01:43:54.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/mm/4xx_mmu.c	2003-03-26 23:48:57.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * This file contains the routines for initializing the MMU
  * on the 4xx series of chips.
  *  -- paulus
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/mm/4xx_tlb.c linux-2.4.21-pre6/arch/ppc/mm/4xx_tlb.c
--- linux-2.4.20/arch/ppc/mm/4xx_tlb.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/mm/4xx_tlb.c	2003-03-26 23:49:49.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.4xx_tlb.c 1.5 05/17/01 18:14:23 cort
- */
-/*
  *
  *    Copyright (c) 1998-1999 TiVo, Inc.
  *      Original implementation.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/mm/4xx_tlb.h linux-2.4.21-pre6/arch/ppc/mm/4xx_tlb.h
--- linux-2.4.20/arch/ppc/mm/4xx_tlb.h	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/mm/4xx_tlb.h	2003-03-26 23:49:38.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.4xx_tlb.h 1.5 05/17/01 18:14:23 cort
- */
-/*
  *
  *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/mm/Makefile linux-2.4.21-pre6/arch/ppc/mm/Makefile
--- linux-2.4.20/arch/ppc/mm/Makefile	2001-08-28 13:58:33.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/mm/Makefile	2003-03-26 23:49:19.000000000 +0000
@@ -1,5 +1,3 @@
-# BK Id: SCCS/s.Makefile 1.8 08/16/01 17:25:47 paulus
-#
 #
 # Makefile for the linux ppc-specific parts of the memory manager.
 #
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/mm/cachemap.c linux-2.4.21-pre6/arch/ppc/mm/cachemap.c
--- linux-2.4.20/arch/ppc/mm/cachemap.c	2001-11-03 01:43:54.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/mm/cachemap.c	2003-03-26 23:49:37.000000000 +0000
@@ -1,6 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- *
  *  PowerPC version derived from arch/arm/mm/consistent.c
  *    Copyright (C) 2001 Dan Malek (dmalek@jlc.net)
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/mm/extable.c linux-2.4.21-pre6/arch/ppc/mm/extable.c
--- linux-2.4.20/arch/ppc/mm/extable.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/mm/extable.c	2003-03-26 23:49:54.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.extable.c 1.5 05/17/01 18:14:23 cort
- */
-/*
  * linux/arch/ppc/mm/extable.c
  *
  * from linux/arch/i386/mm/extable.c
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/mm/fault.c linux-2.4.21-pre6/arch/ppc/mm/fault.c
--- linux-2.4.20/arch/ppc/mm/fault.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/mm/fault.c	2003-03-26 23:49:21.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.fault.c 1.15 09/24/01 16:35:10 paulus
- */
-/*
  *  arch/ppc/mm/fault.c
  *
  *  PowerPC version 
@@ -56,6 +53,41 @@
 void do_page_fault(struct pt_regs *, unsigned long, unsigned long);
 
 /*
+ * Check whether the instruction at regs->nip is a store using
+ * an update addressing form which will update r1.
+ */
+static int store_updates_sp(struct pt_regs *regs)
+{
+	unsigned int inst;
+
+	if (get_user(inst, (unsigned int *)regs->nip))
+		return 0;
+	/* check for 1 in the rA field */
+	if (((inst >> 16) & 0x1f) != 1)
+		return 0;
+	/* check major opcode */
+	switch (inst >> 26) {
+	case 37:	/* stwu */
+	case 39:	/* stbu */
+	case 45:	/* sthu */
+	case 53:	/* stfsu */
+	case 55:	/* stfdu */
+		return 1;
+	case 31:
+		/* check minor opcode */
+		switch ((inst >> 1) & 0x3ff) {
+		case 183:	/* stwux */
+		case 247:	/* stbux */
+		case 439:	/* sthux */
+		case 695:	/* stfsux */
+		case 759:	/* stfdux */
+			return 1;
+		}
+	}
+	return 0;
+}
+
+/*
  * For 600- and 800-family processors, the error_code parameter is DSISR
  * for a data fault, SRR1 for an instruction fault. For 400-family processors
  * the error_code parameter is ESR for a data fault, 0 for an instruction
@@ -111,6 +143,40 @@
 		goto good_area;
 	if (!(vma->vm_flags & VM_GROWSDOWN))
 		goto bad_area;
+	if (!is_write)
+                goto bad_area;
+
+	/*
+	 * N.B. The rs6000/xcoff ABI allows programs to access up to
+	 * a few hundred bytes below the stack pointer.
+	 * The kernel signal delivery code writes up to about 1.5kB
+	 * below the stack pointer (r1) before decrementing it.
+	 * The exec code can write slightly over 640kB to the stack
+	 * before setting the user r1.  Thus we allow the stack to
+	 * expand to 1MB without further checks.
+	 */
+	if (address + 0x100000 < vma->vm_end) {
+		/* get user regs even if this fault is in kernel mode */
+		struct pt_regs *uregs = current->thread.regs;
+		if (uregs == NULL)
+			goto bad_area;
+
+		/*
+		 * A user-mode access to an address a long way below
+		 * the stack pointer is only valid if the instruction
+		 * is one which would update the stack pointer to the
+		 * address accessed if the instruction completed,
+		 * i.e. either stwu rs,n(r1) or stwux rs,r1,rb
+		 * (or the byte, halfword, float or double forms).
+		 *
+		 * If we don't check this then any write to the area
+		 * between the last mapped region and the stack will
+		 * expand the stack rather than segfaulting.
+		 */
+		if (address + 2048 < uregs->gpr[1]
+		    && (!user_mode(regs) || !store_updates_sp(regs)))
+			goto bad_area;
+	}
 	if (expand_stack(vma, address))
 		goto bad_area;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/mm/hashtable.S linux-2.4.21-pre6/arch/ppc/mm/hashtable.S
--- linux-2.4.20/arch/ppc/mm/hashtable.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/mm/hashtable.S	2003-03-26 23:49:53.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/kernel/hashtable.S
  *
  *  $Id: hashtable.S,v 1.6 1999/10/08 01:56:15 paulus Exp $
@@ -27,7 +24,6 @@
  */
 
 #include <linux/config.h>
-#include <asm/ppc_asm.h>
 #include <asm/processor.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
@@ -335,25 +331,6 @@
 	ori	r8,r8,_PAGE_COHERENT	/* set M (coherence required) */
 #endif
 
-#ifdef CONFIG_POWER4
-	/*
-	 * XXX hack hack hack - translate 32-bit "physical" addresses
-	 * in the linux page tables to 42-bit real addresses in such
-	 * a fashion that we can get at the I/O we need to access.
-	 *	-- paulus
-	 */
-	cmpwi	r8,0
-	rlwinm	r0,r8,16,16,30
-	bge	57f
-	cmplwi	r0,0xfe00
-	li	r0,0x3fd
-	bne	56f
-	li	r0,0x3ff
-56:	sldi	r0,r0,32
-	or	r8,r8,r0
-57:
-#endif
-
 	/* Construct the high word of the PPC-style PTE (r5) */
 #ifndef CONFIG_PPC64BRIDGE
 	rlwinm	r5,r3,7,1,24		/* put VSID in 0x7fffff80 bits */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/mm/init.c linux-2.4.21-pre6/arch/ppc/mm/init.c
--- linux-2.4.20/arch/ppc/mm/init.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/mm/init.c	2003-03-26 23:49:18.000000000 +0000
@@ -1,8 +1,5 @@
 /*
- * BK Id: SCCS/s.init.c 1.43 03/12/02 12:13:51 paulus
- */
-/*
- *  PowerPC version 
+ *  PowerPC version
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
  *
  *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
@@ -51,10 +48,12 @@
 
 mmu_gather_t mmu_gathers[NR_CPUS];
 
-void *end_of_DRAM;
 unsigned long total_memory;
 unsigned long total_lowmem;
 
+unsigned long ppc_memstart;
+unsigned long ppc_memoffset = PAGE_OFFSET;
+
 int mem_init_done;
 int init_bootmem_done;
 int boot_mapsize;
@@ -181,13 +180,13 @@
 				iscur = 1;
 				printk("current");
 			}
-			
+
 			if ( p == last_task_used_math )
 			{
 				if ( iscur )
 					printk(",");
 				printk("last math");
-			}			
+			}
 #endif /* CONFIG_SMP */
 			printk("\n");
 		}
@@ -312,8 +311,7 @@
 	if (__max_memory && total_memory > __max_memory)
 		total_memory = __max_memory;
 	total_lowmem = total_memory;
-	adjust_total_lowmem();	
-	end_of_DRAM = __va(total_lowmem);
+	adjust_total_lowmem();
 	set_phys_avail(total_lowmem);
 
 	/* Initialize the MMU hardware */
@@ -396,8 +394,11 @@
 	}
 	start = PAGE_ALIGN(start);
 
-	boot_mapsize = init_bootmem(start >> PAGE_SHIFT,
-				    total_lowmem >> PAGE_SHIFT);
+	min_low_pfn = start >> PAGE_SHIFT;
+	max_low_pfn = (PPC_MEMSTART + total_lowmem) >> PAGE_SHIFT;
+	boot_mapsize = init_bootmem_node(&contig_page_data, min_low_pfn,
+					 PPC_MEMSTART >> PAGE_SHIFT,
+					 max_low_pfn);
 
 	/* remove the bootmem bitmap from the available memory */
 	mem_pieces_remove(&phys_avail, start, boot_mapsize, 1);
@@ -450,12 +451,10 @@
 
 	highmem_mapnr = total_lowmem >> PAGE_SHIFT;
 	highmem_start_page = mem_map + highmem_mapnr;
-	max_mapnr = total_memory >> PAGE_SHIFT;
-#else
-	max_mapnr = max_low_pfn;
 #endif /* CONFIG_HIGHMEM */
+	max_mapnr = total_memory >> PAGE_SHIFT;
 
-	high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
+	high_memory = (void *) __va(PPC_MEMSTART + total_lowmem);
 	num_physpages = max_mapnr;	/* RAM is assumed contiguous */
 
 	totalram_pages += free_all_bootmem();
@@ -485,7 +484,7 @@
 		     addr += PAGE_SIZE)
 			SetPageReserved(virt_to_page(addr));
 
-	for (addr = PAGE_OFFSET; addr < (unsigned long)end_of_DRAM;
+	for (addr = PAGE_OFFSET; addr < (unsigned long)high_memory;
 	     addr += PAGE_SIZE) {
 		if (!PageReserved(virt_to_page(addr)))
 			continue;
@@ -544,7 +543,7 @@
 	 * physical memory.
 	 */
 
-	phys_avail.regions[0].address = 0;
+	phys_avail.regions[0].address = PPC_MEMSTART;
 	phys_avail.regions[0].size = total_memory;
 	phys_avail.n_regions = 1;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/mm/mem_pieces.c linux-2.4.21-pre6/arch/ppc/mm/mem_pieces.c
--- linux-2.4.20/arch/ppc/mm/mem_pieces.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/mm/mem_pieces.c	2003-03-26 23:48:58.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.mem_pieces.c 1.5 05/17/01 18:14:23 cort
- */
-/*
  *    Copyright (c) 1996 Paul Mackerras <paulus@cs.anu.edu.au>
  *      Changes to accomodate Power Macintoshes.
  *    Cort Dougan <cort@cs.nmt.edu>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/mm/mem_pieces.h linux-2.4.21-pre6/arch/ppc/mm/mem_pieces.h
--- linux-2.4.20/arch/ppc/mm/mem_pieces.h	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/mm/mem_pieces.h	2003-03-26 23:48:57.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.mem_pieces.h 1.5 05/17/01 18:14:23 cort
- */
-/*
  *    Copyright (c) 1996 Paul Mackerras <paulus@cs.anu.edu.au>
  *      Changes to accomodate Power Macintoshes.
  *    Cort Dougan <cort@cs.nmt.edu>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/mm/mmu_context.c linux-2.4.21-pre6/arch/ppc/mm/mmu_context.c
--- linux-2.4.20/arch/ppc/mm/mmu_context.c	2001-10-02 16:12:44.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/mm/mmu_context.c	2003-03-26 23:49:40.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * This file contains the routines for handling the MMU on those
  * PowerPC implementations where the MMU substantially follows the
  * architecture specification.  This includes the 6xx, 7xx, 7xxx,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/mm/mmu_decl.h linux-2.4.21-pre6/arch/ppc/mm/mmu_decl.h
--- linux-2.4.20/arch/ppc/mm/mmu_decl.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/mm/mmu_decl.h	2003-03-26 23:49:39.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Declarations of procedures and variables shared between files
  * in arch/ppc/mm/.
  * 
@@ -34,19 +31,14 @@
 extern void reserve_phys_mem(unsigned long start, unsigned long size);
 
 extern int __map_without_bats;
-extern void *end_of_DRAM;
 extern unsigned long ioremap_base;
 extern unsigned long ioremap_bot;
 extern unsigned int rtas_data, rtas_size;
 
 extern unsigned long total_memory;
 extern unsigned long total_lowmem;
-extern unsigned long ram_phys_base;
 extern int mem_init_done;
 
-extern PTE *Hash, *Hash_end;
-extern unsigned long Hash_size, Hash_mask;
-
 /* ...and now those things that may be slightly different between processor
  * architectures.  -- Dan
  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/mm/pgtable.c linux-2.4.21-pre6/arch/ppc/mm/pgtable.c
--- linux-2.4.20/arch/ppc/mm/pgtable.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/mm/pgtable.c	2003-03-26 23:49:10.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * This file contains the routines setting up the linux page tables.
  *  -- paulus
  * 
@@ -32,11 +29,10 @@
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
 #include <asm/io.h>
+#include <asm/machdep.h>
 
 #include "mmu_decl.h"
 
-unsigned long ram_phys_base;
-
 unsigned long ioremap_base;
 unsigned long ioremap_bot;
 int io_bat_index;
@@ -71,7 +67,6 @@
 #define p_mapped_by_bats(x)	(0UL)
 #endif /* HAVE_BATS */
 
-#ifndef CONFIG_PPC_ISERIES
 void *
 ioremap(unsigned long addr, unsigned long size)
 {
@@ -171,7 +166,6 @@
 	if (addr > high_memory && (unsigned long) addr < ioremap_bot)
 		vfree((void *) (PAGE_MASK & (unsigned long) addr));
 }
-#endif /* CONFIG_PPC_ISERIES */
 
 int
 map_page(unsigned long va, unsigned long pa, int flags)
@@ -203,7 +197,7 @@
 #ifdef HAVE_BATS
 	unsigned long bat_max = 0x10000000;
 	unsigned long align;
-	unsigned long ram = total_lowmem;
+	unsigned long ram;
 	int is601 = 0;
 	
 	/* 601s have smaller BATs */
@@ -212,10 +206,20 @@
 		is601 = 1;
 	}
 
+	/* adjust BAT block size to max_low_mem */
+	if (max_low_mem < bat_max)
+		bat_max = max_low_mem;
+
+	/* adjust lowmem size to max_low_mem */
+	if (max_low_mem < total_lowmem)
+		ram = max_low_mem;
+	else
+		ram = total_lowmem;
+
 	/* Make sure we don't map a block larger than the
 	   smallest alignment of the physical address. */
-	/* alignment of ram_phys_base */
-	align = ~(ram_phys_base-1) & ram_phys_base;
+	/* alignment of PPC_MEMSTART */
+	align = ~(PPC_MEMSTART-1) & PPC_MEMSTART;
 	/* set BAT block size to MIN(max_size, align) */
 	if (align && align < bat_max)
 		bat_max = align;
@@ -232,8 +236,9 @@
 		ram -= __bat3;
 	}
 
-	printk(KERN_INFO "Memory BAT mapping: BAT2=%ldMb, BAT3=%ldMb, residual: %ldMb\n",
-		__bat2 >> 20, __bat3 >> 20, ram >> 20);
+	printk(KERN_INFO "Memory BAT mapping: BAT2=%ldMb, BAT3=%ldMb,"
+			" residual: %ldMb\n", __bat2 >> 20, __bat3 >> 20,
+			(total_lowmem - (__bat2 - __bat3)) >> 20);
 
 	/* On SMP, we limit the lowmem to the area mapped with BATs.
 	 * We also assume nobody will do SMP with 601s
@@ -247,8 +252,9 @@
 	if (total_lowmem > max_low_mem) {
 		total_lowmem = max_low_mem;
 #ifndef CONFIG_HIGHMEM
-		printk(KERN_INFO "Warning, memory limited to %ld Mb, use CONFIG_HIGHMEM"
-			" to reach %ld Mb\n", max_low_mem >> 20, total_lowmem >> 20);
+		printk(KERN_INFO "Warning, memory limited to %ld Mb, use "
+				"CONFIG_HIGHMEM to reach %ld Mb\n",
+				max_low_mem >> 20, total_memory >> 20);
 		total_memory = total_lowmem;
 #endif /* CONFIG_HIGHMEM */
 	}
@@ -267,7 +273,7 @@
 #endif /* HAVE_BATS */
 
 	v = KERNELBASE;
-	p = ram_phys_base;
+	p = PPC_MEMSTART;
 	for (s = 0; s < total_lowmem; s += PAGE_SIZE) {
 		/* On the MPC8xx, we want the page shared so we
 		 * don't get ASID compares on kernel space.
@@ -290,6 +296,8 @@
 		v += PAGE_SIZE;
 		p += PAGE_SIZE;
 	}
+	if (ppc_md.progress)
+		ppc_md.progress("MMU:mapin_ram done", 0x401);
 }
 
 /* is x a power of 2? */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/mm/ppc_mmu.c linux-2.4.21-pre6/arch/ppc/mm/ppc_mmu.c
--- linux-2.4.20/arch/ppc/mm/ppc_mmu.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/mm/ppc_mmu.c	2003-03-26 23:49:08.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * This file contains the routines for handling the MMU on those
  * PowerPC implementations where the MMU substantially follows the
  * architecture specification.  This includes the 6xx, 7xx, 7xxx,
@@ -91,11 +88,11 @@
 	unsigned long tot, done;
 	
 	tot = total_lowmem;
-	setbat(2, KERNELBASE, ram_phys_base, bat2, _PAGE_KERNEL);
+	setbat(2, KERNELBASE, PPC_MEMSTART, bat2, _PAGE_KERNEL);
 	done = (unsigned long)bat_addrs[2].limit - KERNELBASE + 1;
 	if ((done < tot) && !bat_addrs[3].limit && bat3) {
 		tot -= done;
-		setbat(3, KERNELBASE+done, ram_phys_base+done, bat3, 
+		setbat(3, KERNELBASE+done, PPC_MEMSTART+done, bat3, 
 		       _PAGE_KERNEL);
 	}
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/mm/tlb.c linux-2.4.21-pre6/arch/ppc/mm/tlb.c
--- linux-2.4.20/arch/ppc/mm/tlb.c	2001-08-28 13:58:33.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/mm/tlb.c	2003-03-26 23:49:50.000000000 +0000
@@ -1,10 +1,7 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * This file contains the routines for TLB flushing.
  * On machines where the MMU uses a hash table to store virtual to
- * physical translations, these routines flush entries from the the
+ * physical translations, these routines flush entries from the 
  * hash table also.
  *  -- paulus
  * 
@@ -30,7 +27,7 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/init.h>
-
+#include <asm/mmu.h>
 #include "mmu_decl.h"
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/Makefile linux-2.4.21-pre6/arch/ppc/platforms/Makefile
--- linux-2.4.20/arch/ppc/platforms/Makefile	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/Makefile	2003-03-26 23:49:56.000000000 +0000
@@ -1,5 +1,3 @@
-# BK Id: SCCS/s.Makefile 1.57 09/24/01 07:45:31 trini
-#
 #
 # Makefile for the linux kernel.
 #
@@ -46,6 +44,7 @@
 obj-$(CONFIG_PPC_RTAS)		+= error_log.o proc_rtas.o
 obj-$(CONFIG_PREP_RESIDUAL)	+= residual.o
 obj-$(CONFIG_GEMINI)		+= gemini_pci.o gemini_setup.o gemini_prom.o
+obj-$(CONFIG_LOPEC)		+= lopec_setup.o lopec_pci.o
 obj-$(CONFIG_PAL4)		+= pal4_setup.o pal4_pci.o cpc700_pic.o
 obj-$(CONFIG_SPRUCE)		+= spruce_setup.o spruce_pci.o cpc700_pic.o
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/apus_pci.c linux-2.4.21-pre6/arch/ppc/platforms/apus_pci.c
--- linux-2.4.20/arch/ppc/platforms/apus_pci.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/apus_pci.c	2003-03-26 23:49:54.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Copyright (C) Michel Dänzer <michdaen@iiic.ethz.ch>
  *
  * APUS PCI routines.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/apus_pci.h linux-2.4.21-pre6/arch/ppc/platforms/apus_pci.h
--- linux-2.4.20/arch/ppc/platforms/apus_pci.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/apus_pci.h	2003-03-26 23:49:27.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Phase5 CybervisionPPC (TVP4020) definitions for the Permedia2 framebuffer
  * driver.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/apus_setup.c linux-2.4.21-pre6/arch/ppc/platforms/apus_setup.c
--- linux-2.4.20/arch/ppc/platforms/apus_setup.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/apus_setup.c	2003-03-26 23:49:40.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/platforms/apus_setup.c
  *
  *  Copyright (C) 1998, 1999  Jesper Skov
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/bseip.h linux-2.4.21-pre6/arch/ppc/platforms/bseip.h
--- linux-2.4.20/arch/ppc/platforms/bseip.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/bseip.h	2003-03-26 23:48:59.000000000 +0000
@@ -1,8 +1,4 @@
 /*
- * BK Id: SCCS/s.bseip.h 1.10 08/17/01 15:23:17 paulus
- */
-
-/*
  * A collection of structures, addresses, and values associated with
  * the Bright Star Engineering ip-Engine board.  Copied from the MBX stuff.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/chrp_pci.c linux-2.4.21-pre6/arch/ppc/platforms/chrp_pci.c
--- linux-2.4.20/arch/ppc/platforms/chrp_pci.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/chrp_pci.c	2003-03-26 23:49:55.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * CHRP pci routines.
  */
 
@@ -26,12 +23,15 @@
 #include <asm/open_pic.h>
 
 /* LongTrail */
-unsigned long gg2_pci_config_base;
+unsigned long gg2_pci_config_base __chrpdata;
 
 #define pci_config_addr(dev, offset) \
-(gg2_pci_config_base | ((dev->bus->number)<<16) | ((dev->devfn)<<8) | (offset))
+(gg2_pci_config_base + ((dev->bus->number<<16) | (dev->devfn<<8) | offset))
+
+volatile struct Hydra *Hydra __chrpdata = NULL;
 
-volatile struct Hydra *Hydra = NULL;
+/* BriQ */
+extern int chrp_is_briq;
 
 /*
  * The VLSI Golden Gate II has only 512K of PCI configuration space, so we
@@ -66,7 +66,7 @@
 GG2_PCI_OP(write, word, u16, out_le16)
 GG2_PCI_OP(write, dword, u32, out_le32)
 
-static struct pci_ops gg2_pci_ops =
+static struct pci_ops gg2_pci_ops __chrpdata =
 {
 	gg2_read_config_byte,
 	gg2_read_config_word,
@@ -101,7 +101,7 @@
 PYTHON_PCI_OP(write, word, u16, out_le16, 2)
 PYTHON_PCI_OP(write, dword, u32, out_le32, 0)
 
-static struct pci_ops python_pci_ops =
+static struct pci_ops python_pci_ops __chrpdata =
 {
 	python_read_config_byte,
 	python_read_config_word,
@@ -148,7 +148,7 @@
 RTAS_PCI_WRITE_OP(word, u16, 2)
 RTAS_PCI_WRITE_OP(dword, u32, 4)
 
-static struct pci_ops rtas_pci_ops =
+static struct pci_ops rtas_pci_ops __chrpdata =
 {
 	rtas_read_config_byte,
 	rtas_read_config_word,
@@ -194,6 +194,71 @@
 	}
 }
 
+/* W83C553 IDE Interrupt Routing Control Register */
+#define W83C553_IDEIRCR                0x43
+
+/* SL82C105 IDE Control/Status Register */
+#define SL82C105_IDECSR                0x40
+
+static void __init
+longtrail_pcibios_fixup(void)
+{
+       struct pci_dev *w83c553, *sl82c105;
+       u8 progif;
+
+       chrp_pcibios_fixup();
+
+       /*
+        *  Open Firmware may have left the SL82C105 IDE interface in the
+        *  W83C553 PCI/ISA bridge in legacy mode
+        */
+       if ((w83c553 = pci_find_device(PCI_VENDOR_ID_WINBOND,
+                                      PCI_DEVICE_ID_WINBOND_83C553, 0)) &&
+           (sl82c105 = pci_find_device(PCI_VENDOR_ID_WINBOND,
+                                       PCI_DEVICE_ID_WINBOND_82C105,
+                                       w83c553)) &&
+           (sl82c105->class & 5) != 5) {
+               printk("W83C553: Switching SL82C105 IDE to PCI native mode\n");
+               /* Enable W83C553 legacy interrupt internal routing to INTC#, */
+               /* which is connected to HYDRA_INT_EXT5 */
+               pci_write_config_byte(w83c553, W83C553_IDEIRCR, 0x00);
+               /* Enable SL82C105 PCI native IDE mode */
+               pci_read_config_byte(sl82c105, PCI_CLASS_PROG, &progif);
+               pci_write_config_byte(sl82c105, PCI_CLASS_PROG, progif | 0x05);
+               sl82c105->class |= 0x05;
+               /* Enable SL82C105 legacy interrupts & both channels */
+               pci_write_config_word(sl82c105, SL82C105_IDECSR, 0x0833);
+       }
+}
+
+static void __init
+briq_pcibios_fixup(void)
+{
+       struct pci_dev *w83c553, *sl82c105;
+       u8 progif;
+
+       chrp_pcibios_fixup();
+
+       /*
+        *  Open Firmware may have left the SL82C105 IDE interface in the
+        *  W83C553 PCI/ISA bridge in legacy mode
+        */
+       if ((w83c553 = pci_find_device(PCI_VENDOR_ID_WINBOND,
+                                      PCI_DEVICE_ID_WINBOND_83C553, 0)) &&
+           (sl82c105 = pci_find_device(PCI_VENDOR_ID_WINBOND,
+                                       PCI_DEVICE_ID_WINBOND_82C105,
+                                       w83c553)) &&
+           (sl82c105->class & 5) != 5) {
+               printk("W83C553: Switching SL82C105 IDE to PCI native mode\n");
+               /* Enable SL82C105 PCI native IDE mode */
+               pci_read_config_byte(sl82c105, PCI_CLASS_PROG, &progif);
+               pci_write_config_byte(sl82c105, PCI_CLASS_PROG, progif | 0x05);
+               sl82c105->class |= 0x05;
+               /* Disable SL82C105 second port */
+               pci_write_config_word(sl82c105, SL82C105_IDECSR, 0x0003);
+       }
+}
+
 #define PRG_CL_RESET_VALID 0x00010000
 
 static void __init
@@ -318,5 +383,10 @@
 		}
 	}
 
-	ppc_md.pcibios_fixup = chrp_pcibios_fixup;
+       if (is_longtrail)
+               ppc_md.pcibios_fixup = longtrail_pcibios_fixup;
+       else if (chrp_is_briq)
+               ppc_md.pcibios_fixup = briq_pcibios_fixup;
+       else
+               ppc_md.pcibios_fixup = chrp_pcibios_fixup;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/chrp_setup.c linux-2.4.21-pre6/arch/ppc/platforms/chrp_setup.c
--- linux-2.4.20/arch/ppc/platforms/chrp_setup.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/chrp_setup.c	2003-03-26 23:49:20.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/platforms/setup.c
  *
  *  Copyright (C) 1995  Linus Torvalds
@@ -56,6 +53,11 @@
 #include <asm/i8259.h>
 #include <asm/open_pic.h>
 
+#ifdef CONFIG_SERIAL
+#include <linux/serial.h>
+#include <linux/serialP.h>
+#endif
+
 unsigned long chrp_get_rtc_time(void);
 int chrp_set_rtc_time(unsigned long nowtime);
 void chrp_calibrate_decr(void);
@@ -81,13 +83,11 @@
 
 extern kdev_t boot_dev;
 
-extern PTE *Hash, *Hash_end;
-extern unsigned long Hash_size, Hash_mask;
-extern int probingmem;
 extern unsigned long loops_per_jiffy;
-static int max_width;
-static int is_briq;
-unsigned int* briq_SPOR; /* To be replaced by RTAS when available */
+
+static int max_width __chrpdata;
+int chrp_is_briq __chrpdata;
+unsigned int* briq_SPOR __chrpdata; /* To be replaced by RTAS when available */
 
 #ifdef CONFIG_SMP
 extern struct smp_ops_t chrp_smp_ops;
@@ -411,8 +411,6 @@
 chrp_init_irq_openpic(unsigned long intack)
 {
 	int i;
-	unsigned char* chrp_int_ack_special = 0;
-	int nmi_irq = -1;
 	unsigned char init_senses[NR_IRQS - NUM_8259_INTERRUPTS];
 
 	chrp_find_openpic();
@@ -421,12 +419,14 @@
 	OpenPIC_InitSenses = init_senses;
 	OpenPIC_NumInitSenses = NR_IRQS - NUM_8259_INTERRUPTS;
 
-	if (intack)
-		chrp_int_ack_special = (unsigned char *) ioremap(intack, 1);
-	openpic_init(1, NUM_8259_INTERRUPTS, chrp_int_ack_special, nmi_irq);
+	openpic_init(NUM_8259_INTERRUPTS);
+	/* We have a cascade on OpenPIC IRQ 0, Linux IRQ 16 */
+	openpic_hookup_cascade(NUM_8259_INTERRUPTS, "82c59 cascade",
+			       i8259_irq);
+
 	for (i = 0; i < NUM_8259_INTERRUPTS; i++)
 		irq_desc[i].handler = &i8259_pic;
-	i8259_init(0);
+	i8259_init(intack);
 }
 
 static void __init
@@ -492,7 +492,7 @@
 chrp_init2(void)
 {
  
-	if (is_briq)
+	if (chrp_is_briq)
 		briq_SPOR = (unsigned int *)ioremap(0xff0000e8, 4);
 #ifdef CONFIG_NVRAM  
 /* Fix me: currently, a lot of pmac_nvram routines are marked __pmac, and
@@ -500,7 +500,7 @@
  * Among others, it cracks on briQ.
  * Please implement a CHRP specific version. --BenH
  */
-	if (!is_briq)
+	if (!chrp_is_briq)
 		pmac_nvram_init();
 #endif
 	/* This is to be replaced by RTAS when available */
@@ -532,46 +532,6 @@
 #endif /* CONFIG_VT && (CONFIG_ADB_KEYBOARD || CONFIG_INPUT) */
 }
 
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-/*
- * IDE stuff.
- */
-
-static int __chrp
-chrp_ide_check_region(ide_ioreg_t from, unsigned int extent)
-{
-        return check_region(from, extent);
-}
-
-static void __chrp
-chrp_ide_request_region(ide_ioreg_t from,
-			unsigned int extent,
-			const char *name)
-{
-        request_region(from, extent, name);
-}
-
-static void __chrp
-chrp_ide_release_region(ide_ioreg_t from,
-			unsigned int extent)
-{
-        release_region(from, extent);
-}
-
-static void __chrp
-chrp_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
-{
-	ide_ioreg_t reg = data_port;
-	int i;
-
-	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
-		hw->io_ports[i] = reg;
-		reg += 1;
-	}
-	hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
-}
-#endif
-
 void __init
 chrp_init(unsigned long r3, unsigned long r4, unsigned long r5,
 	  unsigned long r6, unsigned long r7)
@@ -595,7 +555,15 @@
 
 	/* Check if it's a briq */
 	machine = get_property(root, "model", NULL);
-	is_briq = machine && strncmp(machine, "TotalImpact,BRIQ-1", 18) == 0;
+	chrp_is_briq = machine && strncmp(machine, "TotalImpact,BRIQ-1", 18) == 0;
+#ifdef CONFIG_SERIAL
+	if (chrp_is_briq) {
+		/* briQ has a different serial clock */
+		extern struct serial_state rs_table[];
+		rs_table[0].baud_base = (7372800 / 16);
+		rs_table[1].baud_base = (7372800 / 16);
+	}
+#endif /* CONFIG_SERIAL */	
 
 	ppc_md.setup_arch     = chrp_setup_arch;
 	ppc_md.show_percpuinfo = of_show_percpuinfo;
@@ -606,7 +574,7 @@
 
 	ppc_md.init           = chrp_init2;
 
-	ppc_md.restart        = is_briq ? briq_restart : chrp_restart;
+	ppc_md.restart        = chrp_is_briq ? briq_restart : chrp_restart;
 	ppc_md.power_off      = chrp_power_off;
 	ppc_md.halt           = chrp_halt;
 
@@ -623,8 +591,10 @@
 	ppc_md.kbd_getkeycode    = pckbd_getkeycode;
 	ppc_md.kbd_translate     = pckbd_translate;
 	ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
-	ppc_md.kbd_leds          = pckbd_leds;
-	ppc_md.kbd_init_hw       = pckbd_init_hw;
+	if (!chrp_is_briq) {
+		ppc_md.kbd_leds          = pckbd_leds;
+		ppc_md.kbd_init_hw       = pckbd_init_hw;
+	}
 #ifdef CONFIG_MAGIC_SYSRQ
 	ppc_md.ppc_kbd_sysrq_xlate	 = pckbd_sysrq_xlate;
 	SYSRQ_KEY = 0x54;
@@ -657,10 +627,6 @@
 #endif /* CONFIG_SMP */
 
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-        ppc_ide_md.ide_check_region = chrp_ide_check_region;
-        ppc_ide_md.ide_request_region = chrp_ide_request_region;
-        ppc_ide_md.ide_release_region = chrp_ide_release_region;
-        ppc_ide_md.ide_init_hwif = chrp_ide_init_hwif_ports;
 #endif
 
 	/*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/chrp_smp.c linux-2.4.21-pre6/arch/ppc/platforms/chrp_smp.c
--- linux-2.4.20/arch/ppc/platforms/chrp_smp.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/chrp_smp.c	2003-03-26 23:49:29.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Smp support for CHRP machines.
  *
  * Written by Cort Dougan (cort@cs.nmt.edu) borrowing a great
@@ -125,37 +122,9 @@
 
 	if (OpenPIC_Addr)
 		do_openpic_setup_cpu();
-}
-
-#ifdef CONFIG_POWER4
-static void __chrp
-smp_xics_message_pass(int target, int msg, unsigned long data, int wait)
-{
-	/* for now, only do reschedule messages
-	   since we only have one IPI */
-	if (msg != PPC_MSG_RESCHEDULE)
-		return;
-	for (i = 0; i < smp_num_cpus; ++i) {
-		if (target == MSG_ALL || target == i
-		    || (target == MSG_ALL_BUT_SELF
-			&& i != smp_processor_id()))
-			xics_cause_IPI(i);
-	}
-}
 
-static int __chrp
-smp_xics_probe(void)
-{
-	return smp_chrp_cpu_nr;
-}
-
-static void __chrp
-smp_xics_setup_cpu(int cpu_nr)
-{
-	if (cpu_nr > 0)
-		xics_setup_cpu();
+	spread_heartbeat();
 }
-#endif /* CONFIG_POWER4 */
 
 /* CHRP with openpic */
 struct smp_ops_t chrp_smp_ops __chrpdata = {
@@ -164,13 +133,3 @@
 	smp_chrp_kick_cpu,
 	smp_chrp_setup_cpu,
 };
-
-#ifdef CONFIG_POWER4
-/* CHRP with new XICS interrupt controller */
-struct smp_ops_t xics_smp_ops __chrpdata = {
-	smp_xics_message_pass,
-	smp_xics_probe,
-	smp_chrp_kick_cpu,
-	smp_xics_setup_cpu,
-};
-#endif /* CONFIG_POWER4 */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/chrp_time.c linux-2.4.21-pre6/arch/ppc/platforms/chrp_time.c
--- linux-2.4.20/arch/ppc/platforms/chrp_time.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/chrp_time.c	2003-03-26 23:48:59.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/platforms/chrp_time.c
  *
  *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/cpc700.h linux-2.4.21-pre6/arch/ppc/platforms/cpc700.h
--- linux-2.4.20/arch/ppc/platforms/cpc700.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/cpc700.h	2003-03-26 23:49:19.000000000 +0000
@@ -6,27 +6,10 @@
  * Author: Mark A. Greer
  *         mgreer@mvista.com
  *
- * Copyright 2000-2002 MontaVista Software Inc.
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- *
- * THIS  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.
- *
- * 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.
+ * 2000-2002 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
  */
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/cpc700_pic.c linux-2.4.21-pre6/arch/ppc/platforms/cpc700_pic.c
--- linux-2.4.20/arch/ppc/platforms/cpc700_pic.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/cpc700_pic.c	2003-03-26 23:49:18.000000000 +0000
@@ -8,27 +8,10 @@
  *          mporter@mvista.com
  *          jpeters@mvista.com
  *
- * Copyright 2001-2002 MontaVista Software Inc.
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- *
- * THIS  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.
- *
- * 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.
+ * 2001-2002 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
  */
 
 #include <linux/stddef.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/error_log.c linux-2.4.21-pre6/arch/ppc/platforms/error_log.c
--- linux-2.4.20/arch/ppc/platforms/error_log.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/error_log.c	2003-03-26 23:49:50.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.error_log.c 1.6 05/17/01 18:14:21 cort
- */
-/*
  *  arch/ppc/kernel/error_log.c
  *  
  *  Copyright (c) 2000 Tilmann Bitterberg
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/error_log.h linux-2.4.21-pre6/arch/ppc/platforms/error_log.h
--- linux-2.4.20/arch/ppc/platforms/error_log.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/error_log.h	2003-03-26 23:49:50.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.error_log.h 1.5 05/17/01 18:14:21 cort
- */
 #ifndef __ERROR_LOG_H__
 #define __ERROR_LOG_H__
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/est8260.h linux-2.4.21-pre6/arch/ppc/platforms/est8260.h
--- linux-2.4.20/arch/ppc/platforms/est8260.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/est8260.h	2003-03-26 23:49:50.000000000 +0000
@@ -1,7 +1,3 @@
-/*
- * BK Id: SCCS/s.est8260.h 1.5 05/17/01 18:14:24 cort
- */
-
 /* Board information for the EST8260, which should be generic for
  * all 8260 boards.  The IMMR is now given to us so the hard define
  * will soon be removed.  All of the clock values are computed from
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/fads.h linux-2.4.21-pre6/arch/ppc/platforms/fads.h
--- linux-2.4.20/arch/ppc/platforms/fads.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/fads.h	2003-03-26 23:48:58.000000000 +0000
@@ -1,8 +1,4 @@
 /*
- * BK Id: SCCS/s.fads.h 1.14 10/26/01 10:14:09 trini
- */
-
-/*
  * A collection of structures, addresses, and values associated with
  * the Motorola 860T FADS board.  Copied from the MBX stuff.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/gemini.h linux-2.4.21-pre6/arch/ppc/platforms/gemini.h
--- linux-2.4.20/arch/ppc/platforms/gemini.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/gemini.h	2003-03-26 23:49:35.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/platforms/gemini.h
  *
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/gemini_pci.c linux-2.4.21-pre6/arch/ppc/platforms/gemini_pci.c
--- linux-2.4.20/arch/ppc/platforms/gemini_pci.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/gemini_pci.c	2003-03-26 23:49:24.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/pci.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/gemini_prom.S linux-2.4.21-pre6/arch/ppc/platforms/gemini_prom.S
--- linux-2.4.20/arch/ppc/platforms/gemini_prom.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/gemini_prom.S	2003-03-26 23:48:59.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/kernel/gemini_prom.S
  *
  *  Not really prom support code (yet), but sort of anti-prom code.  The current
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/gemini_serial.h linux-2.4.21-pre6/arch/ppc/platforms/gemini_serial.h
--- linux-2.4.20/arch/ppc/platforms/gemini_serial.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/gemini_serial.h	2003-03-26 23:49:30.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #ifdef __KERNEL__
 #ifndef __ASMPPC_GEMINI_SERIAL_H
 #define __ASMPPC_GEMINI_SERIAL_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/gemini_setup.c linux-2.4.21-pre6/arch/ppc/platforms/gemini_setup.c
--- linux-2.4.20/arch/ppc/platforms/gemini_setup.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/gemini_setup.c	2003-03-26 23:49:39.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/platforms/setup.c
  *
  *  Copyright (C) 1995 Linus Torvalds
@@ -118,13 +115,14 @@
 }
 
 static u_char gemini_openpic_initsenses[] = {
-	1,
-	1,
-	1,
-	1,
-	0,
-	0,
-	1, /* remainder are level-triggered */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* IRQ 0 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* IRQ 1 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* IRQ 2 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* IRQ 3 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* IRQ 4 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* IRQ 5 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* IRQ 6 */
+	/* remainder are level-triggered */
 };
 
 #define GEMINI_MPIC_ADDR (0xfcfc0000)
@@ -330,7 +328,7 @@
 void __init gemini_init_IRQ(void)
 {
 	/* gemini has no 8259 */
-	openpic_init(1, 0, 0, -1);
+	openpic_init(0);
 }
 
 #define gemini_rtc_read(x)       (readb(GEMINI_RTC+(x)))
@@ -374,7 +372,7 @@
 		year = gemini_rtc_read(M48T35_RTC_YEAR);
 	} while( sec != gemini_rtc_read(M48T35_RTC_SECONDS));
 #ifdef DEBUG_RTC
-	printk("get rtc: sec=%x, min=%x, hour=%x, day=%x, mon=%x, year=%x\n", 
+	printk("get rtc: sec=%x, min=%x, hour=%x, day=%x, mon=%x, year=%x\n",
 	       sec, min, hour, day, mon, year);
 #endif
 
@@ -390,7 +388,7 @@
 	if ((year += 1900) < 1970)
 		year += 100;
 #ifdef DEBUG_RTC
-	printk("get rtc: sec=%x, min=%x, hour=%x, day=%x, mon=%x, year=%x\n", 
+	printk("get rtc: sec=%x, min=%x, hour=%x, day=%x, mon=%x, year=%x\n",
 	       sec, min, hour, day, mon, year);
 #endif
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/ivms8.h linux-2.4.21-pre6/arch/ppc/platforms/ivms8.h
--- linux-2.4.20/arch/ppc/platforms/ivms8.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/ivms8.h	2003-03-26 23:49:38.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.ivms8.h 1.8 10/26/01 10:14:09 trini
- */
-/*
  * Speech Design Integrated Voicemail board specific definitions
  * - IVMS8  (small,  8 channels)
  * - IVML24 (large, 24 channels)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/lopec_pci.c linux-2.4.21-pre6/arch/ppc/platforms/lopec_pci.c
--- linux-2.4.20/arch/ppc/platforms/lopec_pci.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/lopec_pci.c	2003-03-26 23:49:19.000000000 +0000
@@ -0,0 +1,108 @@
+/*
+ * arch/ppc/platforms/lopec_pci.c
+ * 
+ * PCI setup routines for the Motorola LoPEC.
+ *
+ * Author: Dan Cox
+ *         danc@mvista.com (or, alternately, source@mvista.com)
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+
+#include <asm/machdep.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/pci-bridge.h>
+#include <asm/open_pic.h>
+#include <asm/mpc10x.h>
+
+static inline int __init
+lopec_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+	int irq;
+	static char pci_irq_table[][4] = {
+		{16, 0, 0, 0}, /* ID 11 - Winbond */
+		{22, 0, 0, 0}, /* ID 12 - SCSI */
+		{0, 0, 0, 0}, /* ID 13 - nothing */
+		{17, 0, 0, 0}, /* ID 14 - 82559 Ethernet */
+		{27, 0, 0, 0}, /* ID 15 - USB */
+		{23, 0, 0, 0}, /* ID 16 - PMC slot 1 */
+		{24, 0, 0, 0}, /* ID 17 - PMC slot 2 */
+		{25, 0, 0, 0}, /* ID 18 - PCI slot */
+		{0, 0, 0, 0}, /* ID 19 - nothing */
+		{0, 0, 0, 0}, /* ID 20 - nothing */
+		{0, 0, 0, 0}, /* ID 21 - nothing */
+		{0, 0, 0, 0}, /* ID 22 - nothing */
+		{0, 0, 0, 0}, /* ID 23 - nothing */
+		{0, 0, 0, 0}, /* ID 24 - PMC slot 1b */
+		{0, 0, 0, 0}, /* ID 25 - nothing */
+		{0, 0, 0, 0}  /* ID 26 - PMC Slot 2b */
+	};
+	const long min_idsel = 11, max_idsel = 26, irqs_per_slot = 4;
+
+	irq = PCI_IRQ_TABLE_LOOKUP;
+	if (!irq)
+		return 0;
+
+	return irq;
+}
+
+void __init
+lopec_setup_winbond_83553(struct pci_controller *hose)
+{
+	int devfn;
+
+	devfn = PCI_DEVFN(11,0);
+
+	/* IDE interrupt routing (primary 14, secondary 15) */
+	early_write_config_byte(hose, 0, devfn, 0x43, 0xef);
+	/* PCI interrupt routing */
+	early_write_config_word(hose, 0, devfn, 0x44, 0x0000);
+
+	/* ISA-PCI address decoder */
+	early_write_config_byte(hose, 0, devfn, 0x48, 0xf0);
+
+	/* RTC, kb, not used in PPC */
+	early_write_config_byte(hose, 0, devfn, 0x4d, 0x00);
+	early_write_config_byte(hose, 0, devfn, 0x4e, 0x04);
+	devfn = PCI_DEVFN(11, 1);
+	early_write_config_byte(hose, 0, devfn, 0x09, 0x8f);
+	early_write_config_dword(hose, 0, devfn, 0x40, 0x00ff0011);
+}
+
+void __init
+lopec_find_bridges(void)
+{
+	struct pci_controller *hose;
+
+	hose = pcibios_alloc_controller();
+	if (!hose)
+		return;
+
+	hose->first_busno = 0;
+	hose->last_busno = 0xff;
+
+	if (mpc10x_bridge_init(hose,
+			       MPC10X_MEM_MAP_B,
+			       MPC10X_MEM_MAP_B,
+			       MPC10X_MAPB_EUMB_BASE) == 0) {
+
+		hose->mem_resources[0].end = 0xffffffff;
+		lopec_setup_winbond_83553(hose);
+		hose->last_busno = pciauto_bus_scan(hose, hose->first_busno);
+		ppc_md.pci_swizzle = common_swizzle;
+		ppc_md.pci_map_irq = lopec_map_irq;
+	}
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/lopec_serial.h linux-2.4.21-pre6/arch/ppc/platforms/lopec_serial.h
--- linux-2.4.20/arch/ppc/platforms/lopec_serial.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/lopec_serial.h	2003-03-26 23:48:58.000000000 +0000
@@ -0,0 +1,45 @@
+/*
+ * include/asm-ppc/lopec_serial.h
+ *
+ * Definitions for Motorola LoPEC board.
+ *
+ * Author: Dan Cox
+ *         danc@mvista.com (or, alternately, source@mvista.com)
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __PLATFORMS_LOPEC_SERIAL_H__
+#define __PLATFORMS_LOPEC_SERIAL_H__
+
+#define RS_TABLE_SIZE	3
+
+#define BASE_BAUD	(1843200 / 16)
+#define UART0_INT	29
+#define UART1_INT	20
+#define UART2_INT	21
+
+#define UART0_PORT	0xFFE10000
+#define UART1_PORT	0xFFE11000
+#define UART2_PORT	0xFFE12000
+#define UART0_IO_BASE	(u8 *) UART0_PORT
+#define UART1_IO_BASE	(u8 *) UART1_PORT
+#define UART2_IO_BASE	(u8 *) UART2_PORT
+
+#define STD_UART_OP(num)					\
+	{ 0, BASE_BAUD, UART##num##_PORT, UART##num##_INT,	\
+		(ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST),		\
+		iomem_base: UART##num##_IO_BASE,		\
+		io_type: SERIAL_IO_MEM },
+
+#define SERIAL_PORT_DFNS 	\
+		STD_UART_OP(0)	\
+		STD_UART_OP(1)	\
+		STD_UART_OP(2)
+
+#endif /* __PLATFORMS_LOPEC_SERIAL_H__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/lopec_setup.c linux-2.4.21-pre6/arch/ppc/platforms/lopec_setup.c
--- linux-2.4.20/arch/ppc/platforms/lopec_setup.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/lopec_setup.c	2003-03-26 23:49:25.000000000 +0000
@@ -0,0 +1,449 @@
+/*
+ * arch/ppc/platforms/lopec_setup.c
+ * 
+ * Setup routines for the Motorola LoPEC.
+ *
+ * Author: Dan Cox
+ *         danc@mvista.com
+ *
+ * Copyright 2001-2002 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/time.h>
+#include <linux/types.h>
+#include <linux/major.h>
+#include <linux/kdev_t.h>
+#include <linux/ide.h>
+#include <linux/irq.h>
+#include <linux/seq_file.h>
+#include <linux/console.h>
+#include <linux/serial.h>
+#include <linux/serialP.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/machdep.h>
+#include <asm/page.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/time.h>
+#include <asm/delay.h>
+#include <asm/irq.h>
+#include <asm/open_pic.h>
+#include <asm/i8259.h>
+#include <asm/pci-bridge.h>
+#include <asm/todc.h>
+#include <asm/bootinfo.h>
+#include <asm/mpc10x.h>
+#include <asm/keyboard.h>
+#include <asm/prep_nvram.h>
+#include <asm/serial.h>
+  
+extern char saved_command_line[];
+extern void lopec_find_bridges(void);
+
+extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int pckbd_getkeycode(unsigned int scancode);
+extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+			   char raw_mode);
+extern char pckbd_unexpected_up(unsigned char keycode);
+extern void pckbd_leds(unsigned char leds);
+extern void pckbd_init_hw(void);
+extern unsigned char pckbd_sysrq_xlate[128];
+extern void gen550_progress(char *, unsigned short);
+extern void gen550_init(int, struct serial_struct *);
+
+/*
+ * Define all of the IRQ senses and polarities.  Taken from the
+ * LoPEC Programmer's Reference Guide */
+static u_char lopec_openpic_initsenses[17] __initdata = {
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* IRQ 0 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* IRQ 1 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* IRQ 2 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* IRQ 3 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* IRQ 4 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* IRQ 5 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* IRQ 6 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* IRQ 7 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* IRQ 8 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* IRQ 9 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* IRQ 10 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* IRQ 11 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* IRQ 12 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* IRQ 13 */
+	(IRQ_SENSE_EDGE | IRQ_POLARITY_NEGATIVE),	/* IRQ 14 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE)	/* IRQ 15 */
+};
+
+static int
+lopec_show_cpuinfo(struct seq_file *m)
+{
+	seq_printf(m, "machine\t\t: Motorola LoPEC\n");
+	return 0;
+}
+
+static u32
+lopec_irq_cannonicalize(u32 irq)
+{
+	if (irq == 2)
+		return 9;
+	else
+		return irq;
+}
+
+static void
+lopec_restart(char *cmd)
+{
+#define LOPEC_SYSSTAT1 0xffe00000
+	/* force a hard reset, if possible */
+	unsigned char reg = *((unsigned char *) LOPEC_SYSSTAT1);
+	reg |= 0x80;
+	*((unsigned char *) LOPEC_SYSSTAT1) = reg;
+
+	__cli();
+	while(1);
+#undef LOPEC_SYSSTAT1
+}
+
+static void
+lopec_halt(void)
+{
+	__cli();
+	while(1);
+}
+
+static void
+lopec_power_off(void)
+{
+	lopec_halt();
+}
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+int lopec_ide_ports_known = 0;
+static ide_ioreg_t lopec_ide_regbase[MAX_HWIFS];
+static ide_ioreg_t lopec_ide_ctl_regbase[MAX_HWIFS];
+static ide_ioreg_t lopec_idedma_regbase;
+
+static void
+lopec_ide_probe(void)
+{
+	struct pci_dev *dev = pci_find_device(PCI_VENDOR_ID_WINBOND,
+					      PCI_DEVICE_ID_WINBOND_82C105,
+					      NULL);
+	lopec_ide_ports_known = 1;
+
+	if (dev) {
+		lopec_ide_regbase[0] = dev->resource[0].start;
+		lopec_ide_regbase[1] = dev->resource[2].start;
+		lopec_ide_ctl_regbase[0] = dev->resource[1].start;
+		lopec_ide_ctl_regbase[1] = dev->resource[3].start;
+		lopec_idedma_regbase = dev->resource[4].start;
+	}
+}
+
+static int
+lopec_ide_default_irq(ide_ioreg_t base)
+{
+	if (lopec_ide_ports_known == 0)
+		lopec_ide_probe();
+
+	if (base == lopec_ide_regbase[0])
+		return 14;
+	else if (base == lopec_ide_regbase[1])
+		return 15;
+	else
+		return 0;
+}
+
+static ide_ioreg_t
+lopec_ide_default_io_base(int index)
+{
+	if (lopec_ide_ports_known == 0)
+		lopec_ide_probe();
+	return lopec_ide_regbase[index];
+}
+
+static void __init
+lopec_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data,
+			  ide_ioreg_t ctl, int *irq)
+{
+	ide_ioreg_t reg = data;
+	uint alt_status_base;
+	int i;
+
+	for(i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
+		hw->io_ports[i] = reg++;
+
+	if (data == lopec_ide_regbase[0]) {
+		alt_status_base = lopec_ide_ctl_regbase[0] + 2;
+		hw->irq = 14;
+	}
+	else if (data == lopec_ide_regbase[1]) {
+		alt_status_base = lopec_ide_ctl_regbase[1] + 2;
+		hw->irq = 15;
+	}
+	else {
+		alt_status_base = 0;
+		hw->irq = 0;
+	}
+
+	if (ctl)
+		hw->io_ports[IDE_CONTROL_OFFSET] = ctl;
+	else
+		hw->io_ports[IDE_CONTROL_OFFSET] = alt_status_base;
+
+	if (irq != NULL)
+		*irq = hw->irq;
+
+}
+#endif /* BLK_DEV_IDE */
+
+static void __init
+lopec_init_IRQ(void)
+{
+	int i;
+
+	OpenPIC_InitSenses = lopec_openpic_initsenses;
+	OpenPIC_NumInitSenses = sizeof(lopec_openpic_initsenses);
+
+	/*
+	 * We need to tell openpic_set_sources where things actually are.
+	 * mpc10x_common will setup OpenPIC_Addr at ioremap(EUMB phys base +
+	 * EPIC offset (0x40000));  The EPIC IRQ Register Address Map -
+	 * Interrupt Source Configuration Registers gives these numbers
+	 * as offsets starting at 0x50200, we need to adjust occordinly.
+	 */
+	/* Map serial interrupts 0-15 */
+	openpic_set_sources(0, 16, OpenPIC_Addr + 0x10200);
+	/* Skip reserved space and map i2c and DMA Ch[01] */
+	openpic_set_sources(16, 3, OpenPIC_Addr + 0x11020);
+	/* Skip reserved space and map Message Unit Interrupt (I2O) */
+	openpic_set_sources(19, 1, OpenPIC_Addr + 0x110C0);
+
+	openpic_init(NUM_8259_INTERRUPTS);
+	/* We have a cascade on OpenPIC IRQ 0, Linux IRQ 16 */
+	openpic_hookup_cascade(NUM_8259_INTERRUPTS, "82c59 cascade",
+			&i8259_irq);
+
+	/* Map i8259 interrupts */
+	for(i = 0; i < NUM_8259_INTERRUPTS; i++)
+		irq_desc[i].handler = &i8259_pic;
+
+	i8259_init(0);
+}
+
+static void __init
+lopec_init2(void)
+{
+	outb(0x00, 0x4d0);
+	outb(0xc0, 0x4d1);
+
+	request_region(0x00, 0x20, "dma1");
+	request_region(0x20, 0x20, "pic1");
+	request_region(0x40, 0x20, "timer");
+	request_region(0x80, 0x10, "dma page reg");
+	request_region(0xa0, 0x20, "pic2");
+	request_region(0xc0, 0x20, "dma2");
+}
+
+static void __init
+lopec_map_io(void)
+{
+	io_block_mapping(0xf0000000, 0xf0000000, 0x10000000, _PAGE_IO);
+	io_block_mapping(0xb0000000, 0xb0000000, 0x10000000, _PAGE_IO);
+}
+
+static void __init
+lopec_set_bat(void)
+{
+	unsigned long batu, batl;
+
+	__asm__ __volatile__(
+		"lis %0,0xf800\n \
+                 ori %1,%0,0x002a\n \
+                 ori %0,%0,0x0ffe\n \
+                 mtspr 0x21e,%0\n \
+                 mtspr 0x21f,%1\n \
+                 isync\n \
+                 sync "
+		: "=r" (batu), "=r" (batl));
+}
+
+static unsigned long __init
+lopec_find_end_of_memory(void)
+{
+	return boot_mem_size;
+}
+
+TODC_ALLOC();
+
+#ifdef CONFIG_SERIAL
+static void __init
+lopec_early_serial_map(void)
+{
+	struct serial_struct serial_req;
+
+	memset(&serial_req, 0, sizeof(serial_req));
+
+	/* Setup ioremapped serial port access */
+	serial_req.line = 0;
+	serial_req.baud_base = BASE_BAUD;
+	serial_req.irq = UART0_INT;
+	serial_req.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
+	serial_req.io_type = SERIAL_IO_MEM;
+	serial_req.iomem_base = ioremap(UART0_PORT, 8);
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+	/* Configure debug serial access */
+	gen550_init(0, &serial_req);
+#endif
+
+	if (early_serial_setup(&serial_req) != 0)
+		printk("Early serial init of port 0 failed\n");
+
+	/* Assume early_serial_setup() doesn't modify serial_req */
+	serial_req.line = 1;
+	serial_req.port = 1;
+	serial_req.irq = UART1_INT; 
+	serial_req.iomem_base = ioremap(UART1_PORT, 8);
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+	/* Configure debug serial access */
+	gen550_init(1, &serial_req);
+#endif
+
+	if (early_serial_setup(&serial_req) != 0)
+		printk("Early serial init of port 1 failed\n");
+
+	serial_req.line = 2;
+	serial_req.port = 2;
+	serial_req.irq = UART2_INT; 
+	serial_req.iomem_base = ioremap(UART2_PORT, 8);
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+	/* Configure debug serial access */
+	gen550_init(2, &serial_req);
+#endif
+
+	if (early_serial_setup(&serial_req) != 0)
+		printk("Early serial init of port 2 failed\n");
+}
+#endif
+
+static void __init
+lopec_setup_arch(void)
+{
+
+	TODC_INIT(TODC_TYPE_MK48T37, 0, 0,
+		  ioremap(0xffe80000, 0x8000), 8);
+
+	loops_per_jiffy = 100000000/HZ;
+
+	lopec_find_bridges();
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (initrd_start)
+		ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
+	else
+#elif defined(CONFIG_ROOT_NFS)
+        	ROOT_DEV = to_kdev_t(0x00ff);
+#elif defined(CONFIG_BLK_DEV_IDE)
+	        ROOT_DEV = to_kdev_t(0x0301);
+#else
+        	ROOT_DEV = to_kdev_t(0x0801);
+#endif
+
+#ifdef CONFIG_DUMMY_CONSOLE
+	conswitchp = &dummy_con;
+#endif
+
+#ifdef CONFIG_SERIAL
+	lopec_early_serial_map();
+#endif
+
+#ifdef CONFIG_PPCBUG_NVRAM
+	/* Read in NVRAM data */ 
+	init_prep_nvram();
+
+	/* if no bootargs, look in NVRAM */
+	if ( cmd_line[0] == '\0' ) {
+		char *bootargs;
+		 bootargs = prep_nvram_get_var("bootargs");
+		 if (bootargs != NULL) {
+			 strcpy(cmd_line, bootargs);
+			 /* again.. */
+			 strcpy(saved_command_line, cmd_line);
+		}
+	}
+#endif
+}
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+	      unsigned long r6, unsigned long r7)
+{
+	parse_bootinfo(find_bootinfo());
+	lopec_set_bat();
+
+	isa_io_base = MPC10X_MAPB_ISA_IO_BASE;
+	isa_mem_base = MPC10X_MAPB_ISA_MEM_BASE;
+	pci_dram_offset = MPC10X_MAPB_DRAM_OFFSET;
+	ISA_DMA_THRESHOLD = 0x00ffffff;
+	DMA_MODE_READ = 0x44;
+	DMA_MODE_WRITE = 0x48;
+
+	ppc_md.setup_arch = lopec_setup_arch;
+	ppc_md.show_cpuinfo = lopec_show_cpuinfo;
+	ppc_md.irq_cannonicalize = lopec_irq_cannonicalize;
+	ppc_md.init_IRQ = lopec_init_IRQ;
+	ppc_md.get_irq = openpic_get_irq;
+	ppc_md.init = lopec_init2;
+
+	ppc_md.restart = lopec_restart;
+	ppc_md.power_off = lopec_power_off;
+	ppc_md.halt = lopec_halt;
+
+	ppc_md.find_end_of_memory = lopec_find_end_of_memory;
+	ppc_md.setup_io_mappings = lopec_map_io;
+
+#ifdef CONFIG_VT
+	ppc_md.kbd_setkeycode = pckbd_setkeycode;
+	ppc_md.kbd_getkeycode = pckbd_getkeycode;
+	ppc_md.kbd_translate = pckbd_translate;
+	ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
+#ifdef CONFIG_MAGIC_SYSRQ
+	ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate;
+	SYSRQ_KEY = 0x54;
+#endif /* CONFIG_MAGIC_SYSRQ */
+#endif /* CONFIG_VT */
+
+	ppc_md.time_init = todc_time_init;
+	ppc_md.set_rtc_time = todc_set_rtc_time;
+	ppc_md.get_rtc_time = todc_get_rtc_time;
+	ppc_md.calibrate_decr = todc_calibrate_decr;
+
+	ppc_md.nvram_read_val = todc_direct_read_val;
+	ppc_md.nvram_write_val = todc_direct_write_val;
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_ID_MODULE)
+	ppc_ide_md.default_irq = lopec_ide_default_irq;
+	ppc_ide_md.default_io_base = lopec_ide_default_io_base;
+	ppc_ide_md.ide_init_hwif = lopec_ide_init_hwif_ports;
+#endif
+#ifdef CONFIG_SERIAL
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+	ppc_md.progress = gen550_progress;
+#endif
+	ppc_md.early_serial_map = lopec_early_serial_map;
+#endif
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/mbx.h linux-2.4.21-pre6/arch/ppc/platforms/mbx.h
--- linux-2.4.20/arch/ppc/platforms/mbx.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/mbx.h	2003-03-26 23:49:50.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.mbx.h 1.11 08/17/01 15:23:17 paulus
- */
-/*
  * A collection of structures, addresses, and values associated with
  * the Motorola MBX boards.  This was originally created for the
  * MBX860, and probably needs revisions for other boards (like the 821).
@@ -92,7 +89,11 @@
 
 /* The MBX uses the 8259.
 */
+#ifdef CONFIG_PCI
 #define NR_8259_INTS	16
+#else
+#define NR_8259_INTS	0
+#endif
 
 #endif
 #endif /* __KERNEL__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/oak.h linux-2.4.21-pre6/arch/ppc/platforms/oak.h
--- linux-2.4.20/arch/ppc/platforms/oak.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/oak.h	2003-03-26 23:49:51.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.oak.h 1.12 10/11/01 13:05:07 trini
- */
-/*
  *
  *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/oak_setup.c linux-2.4.21-pre6/arch/ppc/platforms/oak_setup.c
--- linux-2.4.20/arch/ppc/platforms/oak_setup.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/oak_setup.c	2003-03-26 23:49:19.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *
  *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/oak_setup.h linux-2.4.21-pre6/arch/ppc/platforms/oak_setup.h
--- linux-2.4.20/arch/ppc/platforms/oak_setup.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/oak_setup.h	2003-03-26 23:49:30.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.oak_setup.h 1.5 05/17/01 18:14:21 cort
- */
-/*
  *
  *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/pal4.h linux-2.4.21-pre6/arch/ppc/platforms/pal4.h
--- linux-2.4.20/arch/ppc/platforms/pal4.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/pal4.h	2003-03-26 23:49:51.000000000 +0000
@@ -5,12 +5,10 @@
  *
  * Author: Dan Cox
  *
- * Copyright 2002 MontaVista Software Inc.
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
+ * 2002 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
  */
 
 #ifndef __PPC_PLATFORMS_PAL4_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/pal4_pci.c linux-2.4.21-pre6/arch/ppc/platforms/pal4_pci.c
--- linux-2.4.20/arch/ppc/platforms/pal4_pci.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/pal4_pci.c	2003-03-26 23:49:25.000000000 +0000
@@ -5,12 +5,10 @@
  *
  * Author: Dan Cox 
  *
- * Copyright 2002 MontaVista Software Inc.
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
+ * 2002 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
  */
 
 #include <linux/kernel.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/pal4_serial.h linux-2.4.21-pre6/arch/ppc/platforms/pal4_serial.h
--- linux-2.4.20/arch/ppc/platforms/pal4_serial.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/pal4_serial.h	2003-03-26 23:48:59.000000000 +0000
@@ -5,12 +5,10 @@
  *
  * Author: Dan Cox
  *
- * Copyright 2002 MontaVista Software Inc.
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
+ * 2002 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
  */
 
 #ifndef __PPC_PAL4_SERIAL_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/pal4_setup.c linux-2.4.21-pre6/arch/ppc/platforms/pal4_setup.c
--- linux-2.4.20/arch/ppc/platforms/pal4_setup.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/pal4_setup.c	2003-03-26 23:49:10.000000000 +0000
@@ -5,12 +5,10 @@
  *
  * Author: Dan Cox
  *
- * Copyright 2002 MontaVista Software Inc.
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
+ * 2002 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
  */
 
 #include <linux/config.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/pmac_backlight.c linux-2.4.21-pre6/arch/ppc/platforms/pmac_backlight.c
--- linux-2.4.20/arch/ppc/platforms/pmac_backlight.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/pmac_backlight.c	2003-03-26 23:49:38.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.pmac_backlight.c 1.10 12/01/01 20:09:06 benh
- */
-/*
  * Miscellaneous procedures for dealing with the PowerMac hardware.
  * Contains support for the backlight.
  * 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/pmac_feature.c linux-2.4.21-pre6/arch/ppc/platforms/pmac_feature.c
--- linux-2.4.20/arch/ppc/platforms/pmac_feature.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/pmac_feature.c	2003-03-26 23:49:18.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/platform/pmac_feature.c
  *
  *  Copyright (C) 1996-2002 Paul Mackerras (paulus@cs.anu.edu.au)
@@ -17,6 +14,8 @@
  *   - Replace mdelay with some schedule loop if possible
  *   - Shorten some obfuscated delays on some routines (like modem
  *     power)
+ *   - Refcount some clocks (see darwin)
+ *   - Split split split...
  *
  */
 #include <linux/config.h>
@@ -79,7 +78,8 @@
 	macio_gatwick,
 	macio_paddington,
 	macio_keylargo,
-	macio_pangea
+	macio_pangea,
+	macio_intrepid,
 };
 
 static const char* macio_names[] __pmacdata = 
@@ -92,7 +92,8 @@
 	"Gatwick",
 	"Paddington",
 	"Keylargo",
-	"Pangea"
+	"Pangea",
+	"Intrepid"
 };
 
 static struct macio_chip
@@ -538,7 +539,7 @@
 	return 0;
 }
 
-static u32 save_fcr[5] __pmacdata;
+static u32 save_fcr[6] __pmacdata;
 static u32 save_mbcr __pmacdata;
 static u32 save_gpio_levels[2] __pmacdata;
 static u8 save_gpio_extint[KEYLARGO_GPIO_EXTINT_CNT] __pmacdata;
@@ -814,8 +815,96 @@
 }
 
 static int __pmac
+pangea_modem_enable(struct device_node* node, int param, int value)
+{
+	struct macio_chip*	macio;
+	u8			gpio;
+	unsigned long		flags;
+	
+	/* Hack for internal USB modem */
+	if (node == NULL) {	
+		if (macio_chips[0].type != macio_pangea &&
+		    macio_chips[0].type != macio_intrepid)
+			return -ENODEV;
+		node = macio_chips[0].of_node;
+	}
+	macio = macio_find(node, 0);
+	if (!macio)
+		return -ENODEV;
+	gpio = MACIO_IN8(KL_GPIO_MODEM_RESET);
+	gpio |= KEYLARGO_GPIO_OUTPUT_ENABLE;
+	gpio &= ~KEYLARGO_GPIO_OUTOUT_DATA;
+	
+	if (!value) {
+		LOCK(flags);
+		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
+		UNLOCK(flags);
+		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
+		mdelay(250);
+	}
+    	LOCK(flags);
+	if (value) {
+		MACIO_OUT8(KL_GPIO_MODEM_POWER,
+			KEYLARGO_GPIO_OUTPUT_ENABLE);
+    		UNLOCK(flags);
+	    	(void)MACIO_IN32(KEYLARGO_FCR2);
+		mdelay(250);
+	} else {
+		MACIO_OUT8(KL_GPIO_MODEM_POWER,
+			KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA);
+    		UNLOCK(flags);
+	}
+	if (value) {
+		LOCK(flags);
+		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
+		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
+	    	UNLOCK(flags); mdelay(250); LOCK(flags);
+		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
+		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
+	    	UNLOCK(flags); mdelay(250); LOCK(flags);
+		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
+		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
+	    	UNLOCK(flags); mdelay(250);
+	}
+	return 0;
+}
+
+static int __pmac
+core99_ata100_enable(struct device_node* node, int value)
+{
+	unsigned long flags;
+	struct pci_dev *pdev = NULL;
+	u8 pbus, pid;
+
+    	if (uninorth_rev < 0x24)
+    		return -ENODEV;
+
+	LOCK(flags);
+	if (value)
+		UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_ATA100);
+	else
+		UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_ATA100);
+	(void)UN_IN(UNI_N_CLOCK_CNTL);
+	UNLOCK(flags);
+	udelay(20);
+
+	if (value) {
+		if (pci_device_from_OF_node(node, &pbus, &pid) == 0)
+			pdev = pci_find_slot(pbus, pid);
+		if (pdev == NULL)
+			return 0;
+		pci_enable_device(pdev);
+		pci_set_master(pdev);
+	}
+    	return 0;
+}
+
+static int __pmac
 core99_ide_enable(struct device_node* node, int param, int value)
 {
+	/* Bus ID 0 to 2 are KeyLargo based IDE, busID 3 is U2
+	 * based ata-100
+	 */
 	switch(param) {
 	    case 0:
 		return simple_feature_tweak(node, macio_unknown,
@@ -826,6 +915,8 @@
 	    case 2:
 		return simple_feature_tweak(node, macio_unknown,
 			KEYLARGO_FCR1, KL1_UIDE_ENABLE, value);
+	    case 3:
+	    	return core99_ata100_enable(node, value);
 	    default:
 	    	return -ENODEV;
 	}
@@ -873,7 +964,8 @@
 	struct macio_chip* macio;
 	
 	macio = &macio_chips[0];
-	if (macio->type != macio_keylargo && macio->type != macio_pangea)
+	if (macio->type != macio_keylargo && macio->type != macio_pangea &&
+	    macio->type != macio_intrepid)
 		return -ENODEV;
 
 	LOCK(flags);
@@ -1010,40 +1102,14 @@
 static int __pmac
 core99_reset_cpu(struct device_node* node, int param, int value)
 {
-	const int reset_lines[] = {	KL_GPIO_RESET_CPU0,
-					KL_GPIO_RESET_CPU1,
-					KL_GPIO_RESET_CPU2,
-					KL_GPIO_RESET_CPU3 };
-	int reset_io;
-	unsigned long flags;
-	struct macio_chip* macio;
-	
-	macio = &macio_chips[0];
-	if (macio->type != macio_keylargo && macio->type != macio_pangea)
-		return -ENODEV;
-	if (param > 3 || param < 0)
-		return -ENODEV;
-
-	reset_io = reset_lines[param];
-	
-	LOCK(flags);
-	MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE);
-	(void)MACIO_IN8(reset_io);
-	udelay(1);
-	MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA);
-	(void)MACIO_IN8(reset_io);
-	UNLOCK(flags);
-
-	return 0;
-}
-
-static int __pmac
-rackmac_reset_cpu(struct device_node* node, int param, int value)
-{
-	int reset_io;
+	unsigned int reset_io = 0;
 	unsigned long flags;
 	struct macio_chip* macio;
 	struct device_node* np;
+	const int dflt_reset_lines[] = {	KL_GPIO_RESET_CPU0,
+						KL_GPIO_RESET_CPU1,
+						KL_GPIO_RESET_CPU2,
+						KL_GPIO_RESET_CPU3 };
 	
 	macio = &macio_chips[0];
 	if (macio->type != macio_keylargo)
@@ -1062,14 +1128,14 @@
 			break;
 		}
 	}
-	if (np == NULL)
-		return -ENODEV;
+	if (np == NULL || reset_io == 0)
+		reset_io = dflt_reset_lines[param];
 	
 	LOCK(flags);
 	MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE);
 	(void)MACIO_IN8(reset_io);
 	udelay(1);
-	MACIO_OUT8(reset_io, 0);
+	MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTOUT_DATA | KEYLARGO_GPIO_OUTPUT_ENABLE);
 	(void)MACIO_IN8(reset_io);
 	UNLOCK(flags);
 
@@ -1087,15 +1153,19 @@
 	u32 reg;
 	
 	macio = &macio_chips[0];
-	if (macio->type != macio_keylargo && macio->type != macio_pangea)
+	if (macio->type != macio_keylargo && macio->type != macio_pangea &&
+	    macio->type != macio_intrepid)
 		return -ENODEV;
-	
+
+	/* XXX Fix handling of 3rd USB controller in Intrepid, move the
+	 * port connect stuff (KL4_*) to the sleep code eventually
+	 */
 	prop = (char *)get_property(node, "AAPL,clock-id", NULL);
 	if (!prop)
 		return -ENODEV;
-	if (strncmp(prop, "usb0u048", strlen("usb0u048")) == 0)
+	if (strncmp(prop, "usb0u048", 8) == 0)
 		number = 0;
-	else if (strncmp(prop, "usb1u148", strlen("usb1u148")) == 0)
+	else if (strncmp(prop, "usb1u148", 8) == 0)
 		number = 2;
 	else
 		return -ENODEV;
@@ -1166,7 +1236,8 @@
 	struct macio_chip* macio;
 
 	macio = &macio_chips[0];
-	if (macio->type != macio_keylargo && macio->type != macio_pangea)
+	if (macio->type != macio_keylargo && macio->type != macio_pangea &&
+	    macio->type != macio_intrepid)
 		return -ENODEV;
 	if (!(macio->flags & MACIO_FLAG_FW_SUPPORTED))
 		return -ENODEV;
@@ -1195,7 +1266,8 @@
 	if ((pmac_mb.board_flags & PMAC_MB_HAS_FW_POWER) == 0)
 	    	return -ENODEV;
 	macio = &macio_chips[0];
-	if (macio->type != macio_keylargo && macio->type != macio_pangea)
+	if (macio->type != macio_keylargo && macio->type != macio_pangea &&
+	    macio->type != macio_intrepid)
 		return -ENODEV;
 	if (!(macio->flags & MACIO_FLAG_FW_SUPPORTED))
 		return -ENODEV;
@@ -1234,23 +1306,24 @@
 }
 
 static void __pmac
-keylargo_shutdown(struct macio_chip* macio, int restart)
+keylargo_shutdown(struct macio_chip* macio, int sleep_mode)
 {
 	u32 temp;
 
-	mdelay(1);
-	MACIO_BIS(KEYLARGO_FCR0, KL0_USB_REF_SUSPEND);
-	(void)MACIO_IN32(KEYLARGO_FCR0);
-	mdelay(100);
+	if (sleep_mode) {
+		mdelay(1);
+		MACIO_BIS(KEYLARGO_FCR0, KL0_USB_REF_SUSPEND);
+		(void)MACIO_IN32(KEYLARGO_FCR0);
+		mdelay(1);
+	}
 
 	MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE |
 				KL0_SCC_CELL_ENABLE |
 		      		KL0_IRDA_ENABLE | KL0_IRDA_CLK32_ENABLE |
 		      		KL0_IRDA_CLK19_ENABLE);
-
-	(void)MACIO_IN32(KEYLARGO_FCR0); udelay(10);
+	
 	MACIO_BIC(KEYLARGO_MBCR, KL_MBCR_MB0_DEV_MASK);
-	(void)MACIO_IN32(KEYLARGO_MBCR); udelay(10);
+	MACIO_BIS(KEYLARGO_MBCR, KL_MBCR_MB0_IDE_ENABLE);
 
 	MACIO_BIC(KEYLARGO_FCR1,
 		KL1_AUDIO_SEL_22MCLK | KL1_AUDIO_CLK_ENABLE_BIT |
@@ -1261,27 +1334,33 @@
 		KL1_EIDE0_ENABLE | KL1_EIDE0_RESET_N |
 		KL1_EIDE1_ENABLE | KL1_EIDE1_RESET_N |
 		KL1_UIDE_ENABLE);
-	(void)MACIO_IN32(KEYLARGO_FCR1); udelay(10);
 
 	MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
- 	udelay(10);
  	MACIO_BIC(KEYLARGO_FCR2, KL2_IOBUS_ENABLE);
- 	udelay(10);
+
 	temp = MACIO_IN32(KEYLARGO_FCR3);
-	if (macio->rev >= 2)
-		temp |= (KL3_SHUTDOWN_PLL2X | KL3_SHUTDOWN_PLL_TOTAL);
-		
+	if (macio->rev >= 2) {
+		temp |= KL3_SHUTDOWN_PLL2X;
+		if (sleep_mode)
+			temp |= KL3_SHUTDOWN_PLL_TOTAL;
+	}
+	
 	temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 |
-		KL3_SHUTDOWN_PLLKW35 | KL3_SHUTDOWN_PLLKW12;
+		KL3_SHUTDOWN_PLLKW35;
+	if (sleep_mode)
+		temp |= KL3_SHUTDOWN_PLLKW12;
 	temp &= ~(KL3_CLK66_ENABLE | KL3_CLK49_ENABLE | KL3_CLK45_ENABLE
-		| KL3_CLK31_ENABLE | KL3_TIMER_CLK18_ENABLE | KL3_I2S1_CLK18_ENABLE
-		| KL3_I2S0_CLK18_ENABLE | KL3_VIA_CLK16_ENABLE);
+		| KL3_CLK31_ENABLE | KL3_I2S1_CLK18_ENABLE | KL3_I2S0_CLK18_ENABLE);
+	if (sleep_mode)
+		temp &= ~(KL3_TIMER_CLK18_ENABLE | KL3_VIA_CLK16_ENABLE);
 	MACIO_OUT32(KEYLARGO_FCR3, temp);
-	(void)MACIO_IN32(KEYLARGO_FCR3); udelay(10);
+
+	/* Flush posted writes & wait a bit */
+	(void)MACIO_IN32(KEYLARGO_FCR0); mdelay(1);
 }
 
 static void __pmac
-pangea_shutdown(struct macio_chip* macio, int restart)
+pangea_shutdown(struct macio_chip* macio, int sleep_mode)
 {
 	u32 temp;
 
@@ -1289,10 +1368,6 @@
 				KL0_SCC_CELL_ENABLE |
 				KL0_USB0_CELL_ENABLE | KL0_USB1_CELL_ENABLE);
 
-	(void)MACIO_IN32(KEYLARGO_FCR0); udelay(10);
-	MACIO_BIC(KEYLARGO_MBCR, KL_MBCR_MB0_DEV_MASK);
-	(void)MACIO_IN32(KEYLARGO_MBCR); udelay(10);
-
 	MACIO_BIC(KEYLARGO_FCR1,
 		KL1_AUDIO_SEL_22MCLK | KL1_AUDIO_CLK_ENABLE_BIT |
 		KL1_AUDIO_CLK_OUT_ENABLE | KL1_AUDIO_CELL_ENABLE |
@@ -1300,18 +1375,54 @@
 		KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE |
 		KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE |
 		KL1_UIDE_ENABLE);
-	(void)MACIO_IN32(KEYLARGO_FCR1); udelay(10);
+	if (pmac_mb.board_flags & PMAC_MB_MOBILE)
+		MACIO_BIC(KEYLARGO_FCR1, KL1_UIDE_RESET_N);
 
 	MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
- 	udelay(10);
+ 	
 	temp = MACIO_IN32(KEYLARGO_FCR3);
 	temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 |
 		KL3_SHUTDOWN_PLLKW35;
-	temp &= ~(KL3_CLK49_ENABLE | KL3_CLK45_ENABLE
-		| KL3_CLK31_ENABLE | KL3_TIMER_CLK18_ENABLE | KL3_I2S1_CLK18_ENABLE
-		| KL3_I2S0_CLK18_ENABLE | KL3_VIA_CLK16_ENABLE);
+	temp &= ~(KL3_CLK49_ENABLE | KL3_CLK45_ENABLE | KL3_CLK31_ENABLE
+		| KL3_I2S0_CLK18_ENABLE | KL3_I2S1_CLK18_ENABLE);
+	if (sleep_mode)
+		temp &= ~(KL3_VIA_CLK16_ENABLE | KL3_TIMER_CLK18_ENABLE);
 	MACIO_OUT32(KEYLARGO_FCR3, temp);
-	(void)MACIO_IN32(KEYLARGO_FCR3); udelay(10);
+
+	/* Flush posted writes & wait a bit */
+	(void)MACIO_IN32(KEYLARGO_FCR0); mdelay(1);
+}
+
+static void __pmac
+intrepid_shutdown(struct macio_chip* macio, int sleep_mode)
+{
+	u32 temp;
+
+	MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE |
+				KL0_SCC_CELL_ENABLE |
+				KL0_USB0_CELL_ENABLE | KL0_USB1_CELL_ENABLE);
+
+	MACIO_BIC(KEYLARGO_FCR1,
+		KL1_USB2_CELL_ENABLE |
+		KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT |
+		KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE |
+		KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE);
+	if (pmac_mb.board_flags & PMAC_MB_MOBILE)
+		MACIO_BIC(KEYLARGO_FCR1, KL1_UIDE_RESET_N);
+
+	MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
+ 	
+	temp = MACIO_IN32(KEYLARGO_FCR3);
+	temp |= KL3_IT_SHUTDOWN_PLL1 | KL3_IT_SHUTDOWN_PLL2 |
+		KL3_IT_SHUTDOWN_PLL3;
+	temp &= ~(KL3_CLK49_ENABLE | KL3_CLK45_ENABLE |
+		  KL3_I2S1_CLK18_ENABLE | KL3_I2S0_CLK18_ENABLE);
+	if (sleep_mode)
+		temp &= ~(KL3_TIMER_CLK18_ENABLE | KL3_IT_VIA_CLK32_ENABLE);
+	MACIO_OUT32(KEYLARGO_FCR3, temp);
+
+	/* Flush posted writes & wait a bit */
+	(void)MACIO_IN32(KEYLARGO_FCR0); mdelay(1);
 }
 
 static int __pmac
@@ -1321,7 +1432,8 @@
 	int i;
 
 	macio = &macio_chips[0];
-	if (macio->type != macio_keylargo && macio->type != macio_pangea)
+	if (macio->type != macio_keylargo && macio->type != macio_pangea &&
+	    macio->type != macio_intrepid)
 		return -ENODEV;
 	
 	/* We power off the wireless slot in case it was not done
@@ -1337,7 +1449,11 @@
 	}
 
 	/* We make sure int. modem is off (in case driver lost it) */
-	core99_modem_enable(macio->of_node, 0, 0);
+	if (macio->type == macio_keylargo)
+		core99_modem_enable(macio->of_node, 0, 0);
+	else
+		pangea_modem_enable(macio->of_node, 0, 0);
+
 	/* We make sure the sound is off as well */
 	core99_sound_chip_enable(macio->of_node, 0, 0);
 	 
@@ -1354,12 +1470,15 @@
 		save_gpio_normal[i] = MACIO_IN8(KEYLARGO_GPIO_0+i);
 
 	/* Save the FCRs */
-	save_mbcr = MACIO_IN32(KEYLARGO_MBCR);
+	if (macio->type == macio_keylargo)
+		save_mbcr = MACIO_IN32(KEYLARGO_MBCR);
 	save_fcr[0] = MACIO_IN32(KEYLARGO_FCR0);
 	save_fcr[1] = MACIO_IN32(KEYLARGO_FCR1);
 	save_fcr[2] = MACIO_IN32(KEYLARGO_FCR2);
 	save_fcr[3] = MACIO_IN32(KEYLARGO_FCR3);
 	save_fcr[4] = MACIO_IN32(KEYLARGO_FCR4);
+	if (macio->type == macio_pangea || macio->type == macio_intrepid)
+		save_fcr[5] = MACIO_IN32(KEYLARGO_FCR5);
 
 	/* Save state & config of DBDMA channels */
 	dbdma_save(macio, save_dbdma);
@@ -1368,9 +1487,11 @@
 	 * Turn off as much as we can
 	 */
 	if (macio->type == macio_pangea)
-		pangea_shutdown(macio, 0);
+		pangea_shutdown(macio, 1);
+	else if (macio->type == macio_intrepid)
+		intrepid_shutdown(macio, 1);
 	else if (macio->type == macio_keylargo)
-		keylargo_shutdown(macio, 0);
+		keylargo_shutdown(macio, 1);
 	
 	/* 
 	 * Put the host bridge to sleep
@@ -1400,7 +1521,8 @@
 	int i;
 
 	macio = &macio_chips[0];
-	if (macio->type != macio_keylargo && macio->type != macio_pangea)
+	if (macio->type != macio_keylargo && macio->type != macio_pangea &&
+	    macio->type != macio_intrepid)
 		return -ENODEV;
 
 	/*
@@ -1414,9 +1536,11 @@
 	/*
 	 * Restore KeyLargo
 	 */
-	 
-	MACIO_OUT32(KEYLARGO_MBCR, save_mbcr);
-	(void)MACIO_IN32(KEYLARGO_MBCR); udelay(10);
+
+	if (macio->type == macio_keylargo) {
+		MACIO_OUT32(KEYLARGO_MBCR, save_mbcr);
+		(void)MACIO_IN32(KEYLARGO_MBCR); udelay(10);
+	}
 	MACIO_OUT32(KEYLARGO_FCR0, save_fcr[0]);
 	(void)MACIO_IN32(KEYLARGO_FCR0); udelay(10);
 	MACIO_OUT32(KEYLARGO_FCR1, save_fcr[1]);
@@ -1427,6 +1551,10 @@
 	(void)MACIO_IN32(KEYLARGO_FCR3); udelay(10);
 	MACIO_OUT32(KEYLARGO_FCR4, save_fcr[4]);
 	(void)MACIO_IN32(KEYLARGO_FCR4); udelay(10);
+	if (macio->type == macio_pangea || macio->type == macio_intrepid) {
+		MACIO_OUT32(KEYLARGO_FCR5, save_fcr[5]);
+		(void)MACIO_IN32(KEYLARGO_FCR5); udelay(10);
+	}
 
 	dbdma_restore(macio, save_dbdma);
 
@@ -1477,61 +1605,6 @@
 }
 
 static int __pmac
-pangea_modem_enable(struct device_node* node, int param, int value)
-{
-	struct macio_chip*	macio;
-	u8			gpio;
-	unsigned long		flags;
-	
-	/* Hack for internal USB modem */
-	if (node == NULL) {	
-		if (macio_chips[0].type != macio_pangea)
-			return -ENODEV;
-		node = macio_chips[0].of_node;
-	}
-	macio = macio_find(node, 0);
-	if (!macio)
-		return -ENODEV;
-	gpio = MACIO_IN8(KL_GPIO_MODEM_RESET);
-	gpio |= KEYLARGO_GPIO_OUTPUT_ENABLE;
-	gpio &= ~KEYLARGO_GPIO_OUTOUT_DATA;
-	
-	if (!value) {
-		LOCK(flags);
-		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
-		UNLOCK(flags);
-		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-		mdelay(250);
-	}
-    	LOCK(flags);
-	if (value) {
-		MACIO_OUT8(KL_GPIO_MODEM_POWER,
-			KEYLARGO_GPIO_OUTPUT_ENABLE);
-    		UNLOCK(flags);
-	    	(void)MACIO_IN32(KEYLARGO_FCR2);
-		mdelay(250);
-	} else {
-		MACIO_OUT8(KL_GPIO_MODEM_POWER,
-			KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA);
-    		UNLOCK(flags);
-	}
-	if (value) {
-		LOCK(flags);
-		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
-		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-	    	UNLOCK(flags); mdelay(250); LOCK(flags);
-		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
-		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-	    	UNLOCK(flags); mdelay(250); LOCK(flags);
-		MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
-		(void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-	    	UNLOCK(flags); mdelay(250);
-	}
-	return 0;
-}
-
-
-static int __pmac
 generic_get_mb_info(struct device_node* node, int param, int value)
 {
 	switch(param) {
@@ -1547,7 +1620,6 @@
 	return 0;
 }
 
-
 /* 
  * Table definitions
  */
@@ -1657,7 +1729,7 @@
 	{ PMAC_FTR_1394_CABLE_POWER,	core99_firewire_cable_power },
 	{ PMAC_FTR_SLEEP_STATE,		core99_sleep_state },
 #ifdef CONFIG_SMP
-	{ PMAC_FTR_RESET_CPU,		rackmac_reset_cpu },
+	{ PMAC_FTR_RESET_CPU,		core99_reset_cpu },
 #endif /* CONFIG_SMP */
 	{ PMAC_FTR_READ_GPIO,		core99_read_gpio },
 	{ PMAC_FTR_WRITE_GPIO,		core99_write_gpio },
@@ -1683,6 +1755,26 @@
 	{ PMAC_FTR_WRITE_GPIO,		core99_write_gpio },
 	{ 0, NULL }
 };
+
+/* Intrepid features
+ */
+static struct feature_table_entry intrepid_features[]  __pmacdata = {
+	{ PMAC_FTR_SCC_ENABLE,		core99_scc_enable },
+	{ PMAC_FTR_MODEM_ENABLE,	pangea_modem_enable },
+	{ PMAC_FTR_IDE_ENABLE,		core99_ide_enable },
+	{ PMAC_FTR_IDE_RESET,		core99_ide_reset },
+	{ PMAC_FTR_GMAC_ENABLE,		core99_gmac_enable },
+	{ PMAC_FTR_GMAC_PHY_RESET,	core99_gmac_phy_reset },
+	{ PMAC_FTR_SOUND_CHIP_ENABLE,	core99_sound_chip_enable },
+	{ PMAC_FTR_AIRPORT_ENABLE,	core99_airport_enable },
+	{ PMAC_FTR_USB_ENABLE,		core99_usb_enable },
+	{ PMAC_FTR_1394_ENABLE,		core99_firewire_enable },
+	{ PMAC_FTR_1394_CABLE_POWER,	core99_firewire_cable_power },
+	{ PMAC_FTR_SLEEP_STATE,		core99_sleep_state },
+	{ PMAC_FTR_READ_GPIO,		core99_read_gpio },
+	{ PMAC_FTR_WRITE_GPIO,		core99_write_gpio },
+	{ 0, NULL }
+};
 	
 static struct pmac_mb_def pmac_mb_defs[] __pmacdata = {
 	/* Warning: ordering is important as some models may claim
@@ -1714,11 +1806,11 @@
 	},
 	{	"AAPL,3400/2400",		"PowerBook 3400",
 		PMAC_TYPE_HOOPER,		ohare_features,
-		PMAC_MB_CAN_SLEEP
+		PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE
 	},
 	{	"AAPL,3500",			"PowerBook 3500",
 		PMAC_TYPE_KANGA,		ohare_features,
-		PMAC_MB_CAN_SLEEP
+		PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE
 	},
 	{	"AAPL,Gossamer",		"PowerMac G3 (Gossamer)",
 		PMAC_TYPE_GOSSAMER,		heathrow_desktop_features,
@@ -1730,11 +1822,11 @@
 	},
 	{	"AAPL,PowerBook1998",		"PowerBook Wallstreet",
 		PMAC_TYPE_WALLSTREET,		heathrow_laptop_features,
-		PMAC_MB_CAN_SLEEP
+		PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE
 	},
 	{	"PowerBook1,1",			"PowerBook 101 (Lombard)",
 		PMAC_TYPE_101_PBOOK,		paddington_features,
-		PMAC_MB_CAN_SLEEP
+		PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE
 	},
 	{	"iMac,1",			"iMac (first generation)",
 		PMAC_TYPE_ORIG_IMAC,		paddington_features,
@@ -1746,15 +1838,15 @@
 	},
 	{	"PowerBook4,3",			"iBook 2 rev. 2",
 		PMAC_TYPE_IBOOK2,		pangea_features,
-		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
+		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
 	},
 	{	"PowerBook4,2",			"iBook 2",
 		PMAC_TYPE_IBOOK2,		pangea_features,
-		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
+		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
 	},
 	{	"PowerBook4,1",			"iBook 2",
 		PMAC_TYPE_IBOOK2,		pangea_features,
-		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
+		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
 	},
 	{	"PowerMac4,4",			"eMac",
 		PMAC_TYPE_EMAC,			core99_features,
@@ -1774,7 +1866,7 @@
 	},
 	{	"PowerBook2,1",			"iBook (first generation)",
 		PMAC_TYPE_ORIG_IBOOK,		core99_features,
-		PMAC_MB_CAN_SLEEP | PMAC_MB_OLD_CORE99
+		PMAC_MB_CAN_SLEEP | PMAC_MB_OLD_CORE99 | PMAC_MB_MOBILE
 	},
 	{	"PowerMac3,1",			"PowerMac G4 AGP Graphics",
 		PMAC_TYPE_SAWTOOTH,		core99_features,
@@ -1798,7 +1890,7 @@
 	},
 	{	"PowerBook2,2",			"iBook FireWire",
 		PMAC_TYPE_FW_IBOOK,		core99_features,
-		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_OLD_CORE99
+		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_OLD_CORE99 | PMAC_MB_MOBILE
 	},
 	{	"PowerMac5,1",			"PowerMac G4 Cube",
 		PMAC_TYPE_CUBE,			core99_features,
@@ -1814,19 +1906,23 @@
 	},
 	{	"PowerBook3,1",			"PowerBook Pismo",
 		PMAC_TYPE_PISMO,		core99_features,
-		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_OLD_CORE99
+		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_OLD_CORE99 | PMAC_MB_MOBILE
 	},
 	{	"PowerBook3,2",			"PowerBook Titanium",
 		PMAC_TYPE_TITANIUM,		core99_features,
-		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
+		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
 	},
 	{	"PowerBook3,3",			"PowerBook Titanium II",
 		PMAC_TYPE_TITANIUM2,		core99_features,
-		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
+		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
 	},
 	{	"PowerBook3,4",			"PowerBook Titanium III",
 		PMAC_TYPE_TITANIUM3,		core99_features,
-		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER
+		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
+	},
+	{	"PowerBook3,5",			"PowerBook Titanium IV",
+		PMAC_TYPE_TITANIUM4,		core99_features,
+		PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
 	},
 	{	"RackMac1,1",			"XServe",
 		PMAC_TYPE_RACKMAC,		rackmac_features,
@@ -1931,6 +2027,11 @@
 		pmac_mb.model_name = "Unknown Pangea-based";
 	    	pmac_mb.features = pangea_features;
 		break;
+	    case macio_intrepid:
+		pmac_mb.model_id = PMAC_TYPE_UNKNOWN_PANGEA;
+		pmac_mb.model_name = "Unknown Pangea-based";
+	    	pmac_mb.features = intrepid_features;
+	    	break;
 	    default:
 	    	return -ENODEV;
 	}
@@ -1977,6 +2078,12 @@
 	 * NAP mode
 	 */
 	powersave_lowspeed = 1;
+
+	/* Check for "mobile" machine */
+	if (model && (strncmp(model, "PowerBook", 9) == 0
+		   || strncmp(model, "iBook", 5) == 0))
+		pmac_mb.board_flags |= PMAC_MB_MOBILE;
+	
 	
 	printk(KERN_INFO "PowerMac motherboard: %s\n", pmac_mb.model_name);
 	return 0;
@@ -2060,6 +2167,8 @@
 		u32* did = (u32 *)get_property(node, "device-id", NULL);
 		if (*did == 0x00000025)
 			type = macio_pangea;
+		if (*did == 0x0000003e)
+			type = macio_intrepid;
 	}
 	macio_chips[i].of_node	= node;
 	macio_chips[i].type	= type;
@@ -2154,7 +2263,8 @@
 	}
 
 	if (macio_chips[0].type == macio_keylargo ||
-	    macio_chips[0].type == macio_pangea) {
+	    macio_chips[0].type == macio_pangea ||
+	    macio_chips[0].type == macio_intrepid) {
 		/* Enable GMAC for now for PCI probing. It will be disabled
 		 * later on after PCI probe
 		 */
@@ -2185,6 +2295,17 @@
 			np = np->next;
 		}
 		
+		/* Enable ATA-100 before PCI probe. */
+		np = find_devices("ata-6");
+		while(np) {
+			if (np->parent
+			    && device_is_compatible(np->parent, "uni-north")
+			    && device_is_compatible(np, "kauai-ata")) {
+				core99_ata100_enable(np, 1);
+			}
+			np = np->next;
+		}
+		
 		/* Switch airport off */
 		np = find_devices("radio");
 		while(np) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/pmac_nvram.c linux-2.4.21-pre6/arch/ppc/platforms/pmac_nvram.c
--- linux-2.4.20/arch/ppc/platforms/pmac_nvram.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/pmac_nvram.c	2003-03-26 23:49:34.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.pmac_nvram.c 1.17 12/01/01 20:09:06 benh
- */
-/*
  * Miscellaneous procedures for dealing with the PowerMac hardware.
  */
 #include <linux/config.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/pmac_pci.c linux-2.4.21-pre6/arch/ppc/platforms/pmac_pci.c
--- linux-2.4.20/arch/ppc/platforms/pmac_pci.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/pmac_pci.c	2003-03-26 23:49:39.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Support for PCI bridges found on Power Macintoshes.
  * At present the "bandit" and "chaos" bridges are supported.
  * Fortunately you access configuration space in the same
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/pmac_pic.c linux-2.4.21-pre6/arch/ppc/platforms/pmac_pic.c
--- linux-2.4.20/arch/ppc/platforms/pmac_pic.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/pmac_pic.c	2003-03-26 23:49:54.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.pmac_pic.c 1.24 12/19/01 10:53:01 paulus
- */
 #include <linux/config.h>
 #include <linux/stddef.h>
 #include <linux/init.h>
@@ -358,26 +355,28 @@
 		printk("PowerMac using OpenPIC irq controller\n");
 		if (irqctrler->n_addrs > 0)
 		{
-			int nmi_irq = -1;
 			unsigned char senses[NR_IRQS];
-#ifdef CONFIG_XMON
-			struct device_node* pswitch;
 
-			pswitch = find_devices("programmer-switch");
-			if (pswitch && pswitch->n_intrs)
-				nmi_irq = pswitch->intrs[0].line;
-#endif /* CONFIG_XMON */
 			prom_get_irq_senses(senses, 0, NR_IRQS);
 			OpenPIC_InitSenses = senses;
 			OpenPIC_NumInitSenses = NR_IRQS;
 			ppc_md.get_irq = openpic_get_irq;
 			OpenPIC_Addr = ioremap(irqctrler->addrs[0].address,
 					       irqctrler->addrs[0].size);
-			openpic_init(1, 0, 0, nmi_irq);
+			openpic_init(0);
 #ifdef CONFIG_XMON
-			if (nmi_irq >= 0)
-				request_irq(nmi_irq, xmon_irq, 0,
-					    "NMI - XMON", 0);
+			{
+				struct device_node* pswitch;
+				int nmi_irq;
+
+				pswitch = find_devices("programmer-switch");
+				if (pswitch && pswitch->n_intrs) {
+					nmi_irq = pswitch->intrs[0].line;
+					openpic_init_nmi_irq(nmi_irq);
+					request_irq(nmi_irq, xmon_irq, 0,
+							"NMI - XMON", 0);
+				}
+			}
 #endif	/* CONFIG_XMON */
 			return;
 		}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/pmac_pic.h linux-2.4.21-pre6/arch/ppc/platforms/pmac_pic.h
--- linux-2.4.20/arch/ppc/platforms/pmac_pic.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/pmac_pic.h	2003-03-26 23:48:57.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #ifndef __PPC_PLATFORMS_PMAC_PIC_H
 #define __PPC_PLATFORMS_PMAC_PIC_H
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/pmac_setup.c linux-2.4.21-pre6/arch/ppc/platforms/pmac_setup.c
--- linux-2.4.20/arch/ppc/platforms/pmac_setup.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/pmac_setup.c	2003-03-26 23:49:07.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/platforms/setup.c
  *
  *  PowerPC version 
@@ -86,7 +83,6 @@
 extern void pmac_calibrate_decr(void);
 extern void pmac_pcibios_fixup(void);
 extern void pmac_find_bridges(void);
-extern int pmac_ide_check_base(ide_ioreg_t base);
 extern ide_ioreg_t pmac_ide_get_base(int index);
 extern void pmac_ide_init_hwif_ports(hw_regs_t *hw,
 	ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq);
@@ -709,64 +705,6 @@
 }
 
 
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-/*
- * IDE stuff.
- */
-static int __pmac
-pmac_ide_check_region(ide_ioreg_t from, unsigned int extent)
-{
-#ifdef CONFIG_BLK_DEV_IDE_PMAC
-	if (pmac_ide_check_base(from) >= 0)
-		return 0;
-#endif
-	return check_region(from, extent);
-}
-
-static void __pmac
-pmac_ide_request_region(ide_ioreg_t from,
-			unsigned int extent,
-			const char *name)
-{
-#ifdef CONFIG_BLK_DEV_IDE_PMAC
-	if (pmac_ide_check_base(from) >= 0)
-		return;
-#endif
-	request_region(from, extent, name);
-}
-
-static void __pmac
-pmac_ide_release_region(ide_ioreg_t from,
-			unsigned int extent)
-{
-#ifdef CONFIG_BLK_DEV_IDE_PMAC
-	if (pmac_ide_check_base(from) >= 0)
-		return;
-#endif
-	release_region(from, extent);
-}
-
-#ifndef CONFIG_BLK_DEV_IDE_PMAC
-/*
- * This is only used if we have a PCI IDE controller, not
- * for the IDE controller in the ohare/paddington/heathrow/keylargo.
- */
-static void __pmac
-pmac_ide_pci_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port,
-		ide_ioreg_t ctrl_port, int *irq)
-{
-	ide_ioreg_t reg = data_port;
-	int i;
-
-	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
-		hw->io_ports[i] = reg;
-		reg += 1;
-	}
-	hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
-}
-#endif /* CONFIG_BLK_DEV_IDE_PMAC */
-#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */
-
 /*
  * Read in a property describing some pieces of memory.
  */
@@ -926,14 +864,9 @@
 	select_adb_keyboard();
 
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-        ppc_ide_md.ide_check_region	= pmac_ide_check_region;
-        ppc_ide_md.ide_request_region	= pmac_ide_request_region;
-        ppc_ide_md.ide_release_region	= pmac_ide_release_region;
 #ifdef CONFIG_BLK_DEV_IDE_PMAC
         ppc_ide_md.ide_init_hwif	= pmac_ide_init_hwif_ports;
         ppc_ide_md.default_io_base	= pmac_ide_get_base;
-#else /* CONFIG_BLK_DEV_IDE_PMAC */
-        ppc_ide_md.ide_init_hwif	= pmac_ide_pci_init_hwif_ports;
 #endif /* CONFIG_BLK_DEV_IDE_PMAC */
 #endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/pmac_sleep.S linux-2.4.21-pre6/arch/ppc/platforms/pmac_sleep.S
--- linux-2.4.20/arch/ppc/platforms/pmac_sleep.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/pmac_sleep.S	2003-03-26 23:49:06.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * This file contains sleep low-level functions for PowerBook G3.
  *    Copyright (C) 1999 Benjamin Herrenschmidt (benh@kernel.crashing.org)
  *    and Paul Mackerras (paulus@samba.org).
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/pmac_smp.c linux-2.4.21-pre6/arch/ppc/platforms/pmac_smp.c
--- linux-2.4.20/arch/ppc/platforms/pmac_smp.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/pmac_smp.c	2003-03-26 23:49:39.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * SMP support for power macintosh.
  *
  * We support both the old "powersurge" SMP architecture
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/pmac_time.c linux-2.4.21-pre6/arch/ppc/platforms/pmac_time.c
--- linux-2.4.20/arch/ppc/platforms/pmac_time.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/pmac_time.c	2003-03-26 23:49:20.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Support for periodic interrupts (100 per second) and for getting
  * the current time from the RTC on Power Macintoshes.
  *
@@ -206,7 +203,7 @@
 	printk(KERN_INFO "via_calibrate_decr: ticks per jiffy = %u (%u ticks)\n",
 	       tb_ticks_per_jiffy, dstart - dend);
 
-	iounmap(via);
+	iounmap((void *)via);
 	
 	return 1;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/prep_pci.c linux-2.4.21-pre6/arch/ppc/platforms/prep_pci.c
--- linux-2.4.20/arch/ppc/platforms/prep_pci.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/prep_pci.c	2003-03-26 23:49:55.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.prep_pci.c 1.33 12/20/01 15:36:12 trini
- */
-/*
  * PReP pci functions.
  * Originally by Gary Thomas
  * rewritten and updated by Cort Dougan (cort@cs.nmt.edu)
@@ -29,6 +26,8 @@
 
 #define MAX_DEVNR 22
 
+extern void (*setup_ibm_pci)(char *irq_lo, char *irq_hi);
+
 /* Which PCI interrupt line does a given device [slot] use? */
 /* Note: This really should be two dimensional based in slot/pin used */
 static unsigned char *Motherboard_map;
@@ -665,22 +664,22 @@
 #define	MPIC_HAWK_ID		0x48030000
 #define	MOT_PROC2_BIT		0x800
 
-static u_char mvme2600_openpic_initsenses[] __initdata = {
-    1,	/* MVME2600_INT_SIO */
-    0,	/* MVME2600_INT_FALCN_ECC_ERR */
-    1,	/* MVME2600_INT_PCI_ETHERNET */
-    1,	/* MVME2600_INT_PCI_SCSI */
-    1,	/* MVME2600_INT_PCI_GRAPHICS */
-    1,	/* MVME2600_INT_PCI_VME0 */
-    1,	/* MVME2600_INT_PCI_VME1 */
-    1,	/* MVME2600_INT_PCI_VME2 */
-    1,	/* MVME2600_INT_PCI_VME3 */
-    1,	/* MVME2600_INT_PCI_INTA */
-    1,	/* MVME2600_INT_PCI_INTB */
-    1,	/* MVME2600_INT_PCI_INTC */
-    1,	/* MVME2600_INT_PCI_INTD */
-    1,	/* MVME2600_INT_LM_SIG0 */
-    1,	/* MVME2600_INT_LM_SIG1 */
+static u_char prep_openpic_initsenses[] __initdata = {
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* MVME2600_INT_SIO */
+    (IRQ_SENSE_EDGE  | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_FALCN_ECC_ERR */
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_ETHERNET */
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_SCSI */
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_GRAPHICS */
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_VME0 */
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_VME1 */
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_VME2 */
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_VME3 */
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_INTA */
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_INTB */
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_INTC */
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_INTD */
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_LM_SIG0 */
+    (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_LM_SIG1 */
 };
 
 #define MOT_RAVEN_PRESENT	0x1
@@ -737,8 +736,8 @@
 	/* Map the Raven MPIC registers to virtual memory. */
 	OpenPIC_Addr = ioremap(pci_membase+0xC0000000, 0x22000);
 
-	OpenPIC_InitSenses = mvme2600_openpic_initsenses;
-	OpenPIC_NumInitSenses = sizeof(mvme2600_openpic_initsenses);
+	OpenPIC_InitSenses = prep_openpic_initsenses;
+	OpenPIC_NumInitSenses = sizeof(prep_openpic_initsenses);
 
 	ppc_md.get_irq = openpic_get_irq;
 	
@@ -806,29 +805,51 @@
 void __init
 ibm_prep_init(void)
 {
-	u32 addr;
 #ifdef CONFIG_PREP_RESIDUAL
+	u32 addr, real_addr, len;
 	PPC_DEVICE *mpic;
-#endif
-
-	if (inb(0x0852) == 0xd5) {
-		/* This is for the 43p-140 */
-		early_read_config_dword(0, 0, PCI_DEVFN(13, 0),
-					PCI_BASE_ADDRESS_0, &addr);
-		if (addr != 0xffffffff
-		    && !(addr & PCI_BASE_ADDRESS_SPACE_IO)
-		    && (addr &= PCI_BASE_ADDRESS_MEM_MASK) != 0) {
-			addr += PREP_ISA_MEM_BASE;
-			OpenPIC_Addr = ioremap(addr, 0x40000);
-			ppc_md.get_irq = openpic_get_irq;
-		}
-	}
+	PnP_TAG_PACKET *pkt;
 
-#ifdef CONFIG_PREP_RESIDUAL
+	/* Use the PReP residual data to determine if an OpenPIC is
+	 * present.  If so, get the large vendor packet which will
+	 * tell us the base address and length in memory.
+	 * If we are successful, ioremap the memory area and set
+	 * OpenPIC_Addr (this indicates that the OpenPIC was found).
+	 */
 	mpic = residual_find_device(-1, NULL, SystemPeripheral,
-				    ProgrammableInterruptController, MPIC, 0);
-	if (mpic != NULL)
-		printk("mpic = %p\n", mpic);
+			    ProgrammableInterruptController, MPIC, 0);
+	if (!mpic)
+		return;
+
+	pkt = PnP_find_large_vendor_packet(res->DevicePnPHeap +
+			mpic->AllocatedOffset, 9, 0);
+
+	if (!pkt)
+		return;
+
+#define p pkt->L4_Pack.L4_Data.L4_PPCPack
+	if (!((p.PPCData[0] == 2) && (p.PPCData[1] == 32)))
+		return; /* not a 32-bit memory address */
+
+	real_addr = ld_le32((unsigned int *) (p.PPCData + 4));
+	if (real_addr == 0xffffffff)
+		return;
+
+	/* Adjust address to be as seen by CPU */
+	addr = real_addr + PREP_ISA_MEM_BASE;
+
+	len = ld_le32((unsigned int *) (p.PPCData + 12));
+	if (!len)
+		return;
+#undef p
+	OpenPIC_Addr = ioremap(addr, len);
+	ppc_md.get_irq = openpic_get_irq;
+
+	OpenPIC_InitSenses = prep_openpic_initsenses;
+	OpenPIC_NumInitSenses = sizeof(prep_openpic_initsenses);
+
+	printk(KERN_INFO "MPIC at 0x%08x (0x%08x), length 0x%08x "
+	       "mapped to 0x%p\n", addr, real_addr, len, OpenPIC_Addr);
 #endif
 }
 
@@ -849,6 +870,47 @@
 }
 
 void __init
+prep_sandalfoot_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi)
+{
+	Motherboard_map_name = "IBM 6015/7020 (Sandalfoot/Sandalbow)";
+	Motherboard_map = ibm6015_pci_IRQ_map;
+	Motherboard_routes = ibm6015_pci_IRQ_routes;
+	*irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */
+	*irq_edge_mask_hi = 0xA0; /* irq's 13, 15 level-triggered */
+}
+
+void __init
+prep_thinkpad_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi)
+{
+	Motherboard_map_name = "IBM Thinkpad 850/860";
+	Motherboard_map = Nobis_pci_IRQ_map;
+	Motherboard_routes = Nobis_pci_IRQ_routes;
+	*irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */
+	*irq_edge_mask_hi = 0xA0; /* irq's 13, 15 level-triggered */
+}
+
+void __init
+prep_carolina_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi)
+{
+	Motherboard_map_name = "IBM 7248, PowerSeries 830/850 (Carolina)";
+	Motherboard_map = ibm8xx_pci_IRQ_map;
+	Motherboard_routes = ibm8xx_pci_IRQ_routes;
+	*irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */
+	*irq_edge_mask_hi = 0xA4; /* irq's 10, 13, 15 level-triggered */
+}
+
+void __init
+prep_tiger1_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi)
+{
+	Motherboard_map_name = "IBM 43P-140 (Tiger1)";
+	Motherboard_map = ibm43p_pci_IRQ_map;
+	Motherboard_routes = ibm43p_pci_IRQ_routes;
+	Motherboard_non0 = ibm43p_pci_map_non0;
+	*irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */
+	*irq_edge_mask_hi = 0xA0; /* irq's 13, 15 level-triggered */
+}
+
+void __init
 prep_route_pci_interrupts(void)
 {
 	unsigned char *ibc_pirq = (unsigned char *)0x80800860;
@@ -917,52 +979,12 @@
 			outb( (irq_mode >> 8) & 0xff, 0x4d1 );
 		}
 	} else if ( _prep_type == _PREP_IBM ) {
-		unsigned char planar_id = inb(0x0852);
 		unsigned char irq_edge_mask_lo, irq_edge_mask_hi;
 
-		printk("IBM ID: %08x\n", planar_id);
-		switch(planar_id) {
-		case 0xff:
-			Motherboard_map_name = "IBM Thinkpad 850/860";
-			Motherboard_map = Nobis_pci_IRQ_map;
-			Motherboard_routes = Nobis_pci_IRQ_routes;
-			irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */
-			irq_edge_mask_hi = 0xA0; /* irq's 13, 15 level-triggered */
-			break;
-		case 0xfc:
-			Motherboard_map_name = "IBM 6015/7020 (Sandalfoot/Sandalbow)";
-			Motherboard_map = ibm6015_pci_IRQ_map;
-			Motherboard_routes = ibm6015_pci_IRQ_routes;
-			irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */
-			irq_edge_mask_hi = 0xA0; /* irq's 13, 15 level-triggered */
-			break;
-		case 0xd5:
-			Motherboard_map_name = "IBM 43P-140 (Tiger1)";
-			Motherboard_map = ibm43p_pci_IRQ_map;
-			Motherboard_routes = ibm43p_pci_IRQ_routes;
-			Motherboard_non0 = ibm43p_pci_map_non0;
-			irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */
-			irq_edge_mask_hi = 0xA0; /* irq's 13, 15 level-triggered */
-			break;
-		default:
-			printk(KERN_ERR "Unknown IBM motherboard! Defaulting to Carolina.\n");
-		case 0xf0: /* PowerSeries 830/850 */
-		case 0xf1: /* PowerSeries 830/850 */
-		case 0xf2: /* PowerSeries 830/850 */
-		case 0xf4: /* 7248-43P */
-		case 0xf5: /* 7248-43P */
-		case 0xf6: /* 7248-43P */
-		case 0xf7: /* 7248-43P (missing from Carolina Tech Spec) */
-			Motherboard_map_name = "IBM PS830/PS850/7248 (Carolina)";
-			Motherboard_map = ibm8xx_pci_IRQ_map;
-			Motherboard_routes = ibm8xx_pci_IRQ_routes;
-			irq_edge_mask_lo = 0x00; /* irq's 0-7 all edge-triggered */
-			irq_edge_mask_hi = 0xA4; /* irq's 10, 13, 15 level-triggered */
-			break;
-		}
+		setup_ibm_pci(&irq_edge_mask_lo, &irq_edge_mask_hi);
 
-		outb(inb(0x04d0)|irq_edge_mask_lo, 0x04d0); /* primary 8259 */
-		outb(inb(0x04d1)|irq_edge_mask_hi, 0x04d1); /* cascaded 8259 */
+		outb(inb(0x04d0)|irq_edge_mask_lo, 0x4d0); /* primary 8259 */
+		outb(inb(0x04d1)|irq_edge_mask_hi, 0x4d1); /* cascaded 8259 */
 	} else {
 		printk("No known machine pci routing!\n");
 		return;
@@ -1121,7 +1143,6 @@
         struct pci_dev *dev;
         extern unsigned char *Motherboard_map;
         extern unsigned char *Motherboard_routes;
-        unsigned char i;
 
 	prep_route_pci_interrupts();
 
@@ -1152,7 +1173,7 @@
 		 */
 		unsigned char d = PCI_SLOT(dev->devfn);
 		dev->irq = Motherboard_routes[Motherboard_map[d]];
-
+#if 0
 		for ( i = 0 ; i <= 5 ; i++ ) {
 			/*
 			 * Relocate PCI I/O resources if necessary so the
@@ -1175,6 +1196,7 @@
 					| 0x01000000;
 		        }
 		}
+#endif
 #if 0
 		/*
 		 * If we have residual data and if it knows about this
@@ -1235,13 +1257,14 @@
 	hose->pci_mem_offset = PREP_ISA_MEM_BASE;
 	hose->io_base_phys = PREP_ISA_IO_BASE;
 	hose->io_base_virt = (void *)0x80000000; /* see prep_map_io() */
-	prep_init_resource(&hose->io_resource, 0, 0x0fffffff, IORESOURCE_IO);
+	prep_init_resource(&hose->io_resource, 0, 0x007fffff, IORESOURCE_IO);
 	prep_init_resource(&hose->mem_resources[0], 0xc0000000, 0xfeffffff,
 			   IORESOURCE_MEM);
-	
+	hose->ops = &prep_pci_ops;
+
 	printk("PReP architecture\n");
-	{
 #ifdef CONFIG_PREP_RESIDUAL	  
+	{
 		PPC_DEVICE *hostbridge;
 
 		hostbridge = residual_find_device(PROCESSORDEVICE, NULL,
@@ -1257,12 +1280,12 @@
 				setup_indirect_pci(hose, 
 					ld_le32((unsigned *) (p.PPCData)),
 					ld_le32((unsigned *) (p.PPCData+8)));
+#undef p
 			} else
 				setup_indirect_pci(hose, 0x80000cf8, 0x80000cfc);
-		} else
-#endif /* CONFIG_PREP_RESIDUAL */
-			hose->ops = &prep_pci_ops;
+		}
 	}
+#endif /* CONFIG_PREP_RESIDUAL */
 
 	ppc_md.pcibios_fixup = prep_pcibios_fixup;
 	ppc_md.pcibios_after_init = prep_pcibios_after_init;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/prep_setup.c linux-2.4.21-pre6/arch/ppc/platforms/prep_setup.c
--- linux-2.4.20/arch/ppc/platforms/prep_setup.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/prep_setup.c	2003-03-26 23:49:54.000000000 +0000
@@ -1,8 +1,5 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
- *  linux/arch/ppc/kernel/setup.c
+ *  arch/ppc/platforms/setup.c
  *
  *  Copyright (C) 1995  Linus Torvalds
  *  Adapted from 'alpha' version by Gary Thomas
@@ -59,11 +56,8 @@
 #include <asm/time.h>
 #include <asm/i8259.h>
 #include <asm/open_pic.h>
-
-#if defined(CONFIG_SOUND) || defined(CONFIG_SOUND_MODULE)
-#include <../drivers/sound/sound_config.h>
-#include <../drivers/sound/dev_table.h>
-#endif
+#include <asm/pci-bridge.h>
+#include <asm/bootinfo.h>
 
 unsigned char ucSystemType;
 unsigned char ucBoardRev;
@@ -96,60 +90,335 @@
 
 int _prep_type;
 
+extern void prep_sandalfoot_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi);
+extern void prep_thinkpad_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi);
+extern void prep_carolina_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi);
+extern void prep_tiger1_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi);
+
+
 #define cached_21	(((char *)(ppc_cached_irq_mask))[3])
 #define cached_A1	(((char *)(ppc_cached_irq_mask))[2])
 
 /* for the mac fs */
 kdev_t boot_dev;
-/* used in nasty hack for sound - see prep_setup_arch() -- Cort */
+
+#ifdef CONFIG_SOUND_CS4232 
 long ppc_cs4232_dma, ppc_cs4232_dma2;
+#endif
 
 extern PTE *Hash, *Hash_end;
 extern unsigned long Hash_size, Hash_mask;
 extern int probingmem;
 extern unsigned long loops_per_jiffy;
 
-#ifdef CONFIG_SOUND_MODULE
+#ifdef CONFIG_SOUND_CS4232 
 EXPORT_SYMBOL(ppc_cs4232_dma);
 EXPORT_SYMBOL(ppc_cs4232_dma2);
 #endif
 
-static int __prep
-prep_show_cpuinfo(struct seq_file *m)
+/* useful ISA ports */
+#define PREP_SYSCTL	0x81c
+/* present in the IBM reference design; possibly identical in Mot boxes: */
+#define PREP_IBM_SIMM_ID	0x803 /* SIMM size: 32 or 8 MiB */
+#define PREP_IBM_SIMM_PRESENCE	0x804
+#define PREP_IBM_EQUIPMENT	0x80c
+#define PREP_IBM_L2INFO	0x80d
+#define PREP_IBM_PM1	0x82a /* power management register 1 */
+#define PREP_IBM_PLANAR	0x852 /* planar ID - identifies the motherboard */
+
+/* Equipment Present Register masks: */
+#define PREP_IBM_EQUIPMENT_RESERVED	0x80
+#define PREP_IBM_EQUIPMENT_SCSIFUSE	0x40
+#define PREP_IBM_EQUIPMENT_L2_COPYBACK	0x08
+#define PREP_IBM_EQUIPMENT_L2_256	0x04
+#define PREP_IBM_EQUIPMENT_CPU	0x02
+#define PREP_IBM_EQUIPMENT_L2	0x01
+
+/* planar ID values: */
+/* Sandalfoot/Sandalbow (6015/7020) */
+#define PREP_IBM_SANDALFOOT	0xfc
+/* Woodfield, Thinkpad 850/860 (6042/7249) */
+#define PREP_IBM_THINKPAD	0xff /* planar ID unimplemented */
+/* PowerSeries 830/850 (6050/6070) */
+#define PREP_IBM_CAROLINA_IDE_0	0xf0
+#define PREP_IBM_CAROLINA_IDE_1	0xf1
+#define PREP_IBM_CAROLINA_IDE_2	0xf2
+/* 7248-43P */
+#define PREP_IBM_CAROLINA_SCSI_0	0xf4
+#define PREP_IBM_CAROLINA_SCSI_1	0xf5
+#define PREP_IBM_CAROLINA_SCSI_2	0xf6
+#define PREP_IBM_CAROLINA_SCSI_3	0xf7 /* missing from Carolina Tech Spec */
+/* Tiger1 (7043-140) */
+#define PREP_IBM_TIGER1_133		0xd1
+#define PREP_IBM_TIGER1_166		0xd2
+#define PREP_IBM_TIGER1_180		0xd3
+#define PREP_IBM_TIGER1_xxx		0xd4 /* unknown, but probably exists */
+#define PREP_IBM_TIGER1_333		0xd5 /* missing from Tiger Tech Spec */
+
+/* setup_ibm_pci:
+ * 	set Motherboard_map_name, Motherboard_map, Motherboard_routes.
+ * 	return 8259 edge/level masks.
+ */
+void (*setup_ibm_pci)(char *irq_lo, char *irq_hi);
+
+extern char *Motherboard_map_name; /* for use in *_cpuinfo */
+
+/*
+ * As found in the PReP reference implementation.
+ * Used by Thinkpad, Sandalfoot (6015/7020), and all Motorola PReP.
+ */
+static void __init
+prep_gen_enable_l2(void)
+{
+	outb(inb(PREP_SYSCTL) | 0x3, PREP_SYSCTL);
+}
+
+/* Used by Carolina and Tiger1 */
+static void __init
+prep_carolina_enable_l2(void)
+{
+	outb(inb(PREP_SYSCTL) | 0xc0, PREP_SYSCTL);
+}
+
+/* cpuinfo code common to all IBM PReP */
+static void __prep
+prep_ibm_cpuinfo(struct seq_file *m)
 {
-	extern char *Motherboard_map_name;
-	int cachew;
+	unsigned int equip_reg = inb(PREP_IBM_EQUIPMENT);
+
+	seq_printf(m, "machine\t\t: PReP %s\n", Motherboard_map_name);
+
+	seq_printf(m, "upgrade cpu\t: ");
+	if (equip_reg & PREP_IBM_EQUIPMENT_CPU) {
+		seq_printf(m, "not ");
+	}
+	seq_printf(m, "present\n");
+
+	/* print info about the SCSI fuse */
+	seq_printf(m, "scsi fuse\t: ");
+	if (equip_reg & PREP_IBM_EQUIPMENT_SCSIFUSE) 
+		seq_printf(m, "ok");
+	else
+		seq_printf(m, "bad");
+	seq_printf(m, "\n");
+
 #ifdef CONFIG_PREP_RESIDUAL
-	int i;
+	/* print info about SIMMs */
+	if (res->ResidualLength != 0) {
+		int i;
+		seq_printf(m, "simms\t\t: ");
+		for (i = 0; (res->ActualNumMemories) && (i < MAX_MEMS); i++) {
+			if (res->Memories[i].SIMMSize != 0)
+				seq_printf(m, "%d:%ldMiB ", i,
+					(res->Memories[i].SIMMSize > 1024) ? 
+					res->Memories[i].SIMMSize>>20 : 
+					res->Memories[i].SIMMSize);
+		}
+		seq_printf(m, "\n");
+	}
 #endif
+}
 
-	seq_printf(m, "machine\t\t: PReP %s\n", Motherboard_map_name);
+static int __prep
+prep_sandalfoot_cpuinfo(struct seq_file *m)
+{
+	unsigned int equip_reg = inb(PREP_IBM_EQUIPMENT);
 
-	switch ( _prep_type ) {
-	case _PREP_IBM:
-		cachew = inw(0x80c);
-		if (cachew & (1<<6))
-			seq_printf(m, "Upgrade CPU\n");
-		seq_printf(m, "L2\t\t: ");
-		if (cachew & (1<<7)) {
-			seq_printf(m, "not present\n");
-			goto no_l2;
+	prep_ibm_cpuinfo(m);
+
+	/* report amount and type of L2 cache present */
+	seq_printf(m, "L2 cache\t: ");
+	if (equip_reg & PREP_IBM_EQUIPMENT_L2) {
+		seq_printf(m, "not present");
+	} else {
+		if (equip_reg & PREP_IBM_EQUIPMENT_L2_256)
+			seq_printf(m, "256KiB");
+		else
+			seq_printf(m, "unknown size");
+
+		if (equip_reg & PREP_IBM_EQUIPMENT_L2_COPYBACK)
+			seq_printf(m, ", copy-back");
+		else
+			seq_printf(m, ", write-through");
+	}
+	seq_printf(m, "\n");
+
+	return 0;
+}
+
+static int __prep
+prep_thinkpad_cpuinfo(struct seq_file *m)
+{
+	unsigned int equip_reg = inb(PREP_IBM_EQUIPMENT);
+	char *cpubus_speed, *pci_speed;
+
+	prep_ibm_cpuinfo(m);
+
+	/* report amount and type of L2 cache present */
+	seq_printf(m, "l2 cache\t: ");
+	if ((equip_reg & 0x1) == 0) {
+		switch ((equip_reg & 0xc) >> 2) {
+			case 0x0:
+				seq_printf(m, "128KiB look-aside 2-way write-through\n");
+				break;
+			case 0x1:
+				seq_printf(m, "512KiB look-aside direct-mapped write-back\n");
+				break;
+			case 0x2:
+				seq_printf(m, "256KiB look-aside 2-way write-through\n");
+				break;
+			case 0x3:
+				seq_printf(m, "256KiB look-aside direct-mapped write-back\n");
+				break;
 		}
-		seq_printf(m, "%sKb,", (cachew & (1 << 10))? "512" : "256");
-		seq_printf(m, "%ssync\n", (cachew & (1 << 15))? "" : "a");
-		break;
-	case _PREP_Motorola:
-		cachew = *((unsigned char *)CACHECRBA);
-		seq_printf(m, "L2\t\t: ");
-		switch (cachew & L2CACHE_MASK) {
+	} else {
+		seq_printf(m, "not present\n");
+	}
+
+	/* report bus speeds because we can */
+	if ((equip_reg & 0x80) == 0) {
+		switch ((equip_reg & 0x30) >> 4) {
+			case 0x1:
+				cpubus_speed = "50";
+				pci_speed = "25";
+				break;
+			case 0x3:
+				cpubus_speed = "66";
+				pci_speed = "33";
+				break;
+			default:
+				cpubus_speed = "unknown";
+				pci_speed = "unknown";
+				break;
+		}
+	} else {
+		switch ((equip_reg & 0x30) >> 4) {
+			case 0x1:
+				cpubus_speed = "25";
+				pci_speed = "25";
+				break;
+			case 0x2:
+				cpubus_speed = "60";
+				pci_speed = "30";
+				break;
+			case 0x3:
+				cpubus_speed = "33";
+				pci_speed = "33";
+				break;
+			default:
+				cpubus_speed = "unknown";
+				pci_speed = "unknown";
+				break;
+		}
+	}
+	seq_printf(m, "60x bus\t\t: %sMHz\n", cpubus_speed);
+	seq_printf(m, "pci bus\t\t: %sMHz\n", pci_speed);
+
+	return 0;
+}
+
+static int __prep
+prep_carolina_cpuinfo(struct seq_file *m)
+{
+	unsigned int equip_reg = inb(PREP_IBM_EQUIPMENT);
+
+	prep_ibm_cpuinfo(m);
+
+	/* report amount and type of L2 cache present */
+	seq_printf(m, "l2 cache\t: ");
+	if ((equip_reg & 0x1) == 0) {
+		unsigned int l2_reg = inb(PREP_IBM_L2INFO);
+
+		/* L2 size */
+		switch ((l2_reg & 0x60) >> 5) {
+			case 0:
+				seq_printf(m, "256KiB");
+				break;
+			case 1:
+				seq_printf(m, "512KiB");
+				break;
+			default:
+				seq_printf(m, "unknown size");
+				break;
+		}
+
+		/* L2 type */
+		if ((l2_reg & 0x3) == 0)
+			seq_printf(m, ", async");
+		else if ((l2_reg & 0x3) == 1)
+			seq_printf(m, ", sync");
+		else
+			seq_printf(m, ", unknown type");
+
+		seq_printf(m, "\n");
+	} else {
+		seq_printf(m, "not present\n");
+	}
+
+	return 0;
+}
+
+static int __prep
+prep_tiger1_cpuinfo(struct seq_file *m)
+{
+	unsigned int l2_reg = inb(PREP_IBM_L2INFO);
+
+	prep_ibm_cpuinfo(m);
+
+	/* report amount and type of L2 cache present */
+	seq_printf(m, "l2 cache\t: ");
+	if ((l2_reg & 0xf) == 0xf) {
+		seq_printf(m, "not present\n");
+	} else {
+		if (l2_reg & 0x8)
+			seq_printf(m, "async, ");
+		else
+			seq_printf(m, "sync burst, ");
+		
+		if (l2_reg & 0x4)
+			seq_printf(m, "parity, ");
+		else
+			seq_printf(m, "no parity, ");
+		
+		switch (l2_reg & 0x3) {
+			case 0x0:
+				seq_printf(m, "256KiB\n");
+				break;
+			case 0x1:
+				seq_printf(m, "512KiB\n");
+				break;
+			case 0x2:
+				seq_printf(m, "1MiB\n");
+				break;
+			default:
+				seq_printf(m, "unknown size\n");
+				break;
+		}
+	}
+
+	return 0;
+}
+
+
+/* Used by all Motorola PReP */
+static int __prep
+prep_mot_cpuinfo(struct seq_file *m)
+{
+	unsigned int cachew = *((unsigned char *)CACHECRBA);
+
+	seq_printf(m, "machine\t\t: PReP %s\n", Motherboard_map_name);
+
+	/* report amount and type of L2 cache present */
+	seq_printf(m, "l2 cache\t: ");
+	switch (cachew & L2CACHE_MASK) {
 		case L2CACHE_512KB:
-			seq_printf(m, "512Kb");
+			seq_printf(m, "512KiB");
 			break;
 		case L2CACHE_256KB:
-			seq_printf(m, "256Kb");
+			seq_printf(m, "256KiB");
 			break;
 		case L2CACHE_1MB:
-			seq_printf(m, "1MB");
+			seq_printf(m, "1MiB");
 			break;
 		case L2CACHE_NONE:
 			seq_printf(m, "none\n");
@@ -157,32 +426,29 @@
 			break;
 		default:
 			seq_printf(m, "%x\n", cachew);
-		}
-		
-		seq_printf(m, ", parity %s",
-			   (cachew & L2CACHE_PARITY)? "enabled" : "disabled");
+	}
 
-		seq_printf(m, " SRAM:");
-		
-		switch ( ((cachew & 0xf0) >> 4) & ~(0x3) ) {
-		case 1: seq_printf(m, "synchronous,parity,flow-through\n");
-			break;
-		case 2: seq_printf(m, "asynchronous,no parity\n");
-			break;
-		case 3: seq_printf(m, "asynchronous,parity\n");
-			break;
-		default:seq_printf(m, "synchronous,pipelined,no parity\n");
-			break;
-		}
-		break;
-	default:
-		break;
+	seq_printf(m, ", parity %s",
+			(cachew & L2CACHE_PARITY)? "enabled" : "disabled");
+
+	seq_printf(m, " SRAM:");
+
+	switch ( ((cachew & 0xf0) >> 4) & ~(0x3) ) {
+		case 1: seq_printf(m, "synchronous, parity, flow-through\n");
+				break;
+		case 2: seq_printf(m, "asynchronous, no parity\n");
+				break;
+		case 3: seq_printf(m, "asynchronous, parity\n");
+				break;
+		default:seq_printf(m, "synchronous, pipelined, no parity\n");
+				break;
 	}
 
 no_l2:
 #ifdef CONFIG_PREP_RESIDUAL
+	/* print info about SIMMs */
 	if (res->ResidualLength != 0) {
-		/* print info about SIMMs */
+		int i;
 		seq_printf(m, "simms\t\t: ");
 		for (i = 0; (res->ActualNumMemories) && (i < MAX_MEMS); i++) {
 			if (res->Memories[i].SIMMSize != 0)
@@ -198,6 +464,107 @@
 	return 0;
 }
 
+static void __prep
+prep_restart(char *cmd)
+{
+#define PREP_SP92	0x92	/* Special Port 92 */
+	__cli(); /* no interrupts */
+
+	/* set exception prefix high - to the prom */
+	_nmask_and_or_msr(0, MSR_IP);
+
+	/* make sure bit 0 (reset) is a 0 */
+	outb( inb(PREP_SP92) & ~1L , PREP_SP92);
+	/* signal a reset to system control port A - soft reset */
+	outb( inb(PREP_SP92) | 1 , PREP_SP92);
+
+	while ( 1 ) ;
+	/* not reached */
+#undef PREP_SP92
+}
+
+static void __prep
+prep_halt(void)
+{
+	__cli(); /* no interrupts */
+
+	/* set exception prefix high - to the prom */
+	_nmask_and_or_msr(0, MSR_IP);
+
+	while ( 1 ) ;
+	/* not reached */
+}
+
+/* Carrera is the power manager in the Thinkpads. Unfortunately not much is
+ * known about it, so we can't power down.
+ */
+static void __prep
+prep_carrera_poweroff(void)
+{
+	prep_halt();
+}
+
+/*
+ * On most IBM PReP's, power management is handled by a Signetics 87c750
+ * behind the Utah component on the ISA bus. To access the 750 you must write
+ * a series of nibbles to port 0x82a (decoded by the Utah). This is described
+ * somewhat in the IBM Carolina Technical Specification.
+ * -Hollis
+ */
+static void __prep
+utah_sig87c750_setbit(unsigned int bytenum, unsigned int bitnum, int value)
+{
+	/*
+	 * byte1: 0 0 0 1 0  d  a5 a4
+	 * byte2: 0 0 0 1 a3 a2 a1 a0
+	 *
+	 * d = the bit's value, enabled or disabled
+	 * (a5 a4 a3) = the byte number, minus 20
+	 * (a2 a1 a0) = the bit number
+	 *
+	 * example: set the 5th bit of byte 21 (21.5)
+	 *     a5 a4 a3 = 001 (byte 1)
+	 *     a2 a1 a0 = 101 (bit 5)
+	 *
+	 *     byte1 = 0001 0100 (0x14)
+	 *     byte2 = 0001 1101 (0x1d)
+	 */
+	unsigned char byte1=0x10, byte2=0x10;
+
+	/* the 750's '20.0' is accessed as '0.0' through Utah (which adds 20) */
+	bytenum -= 20;
+
+	byte1 |= (!!value) << 2;		/* set d */
+	byte1 |= (bytenum >> 1) & 0x3;	/* set a5, a4 */
+
+	byte2 |= (bytenum & 0x1) << 3;	/* set a3 */
+	byte2 |= bitnum & 0x7;			/* set a2, a1, a0 */
+
+	outb(byte1, PREP_IBM_PM1);	/* first nibble */
+	mb();
+	udelay(100);				/* important: let controller recover */
+
+	outb(byte2, PREP_IBM_PM1);	/* second nibble */
+	mb();
+	udelay(100);				/* important: let controller recover */
+}
+
+static void __prep
+prep_sig750_poweroff(void)
+{
+	/* tweak the power manager found in most IBM PRePs (except Thinkpads) */
+	unsigned long flags;
+	__cli();
+	/* set exception prefix high - to the prom */
+	save_flags( flags );
+	restore_flags( flags|MSR_IP );
+
+	utah_sig87c750_setbit(21, 5, 1); /* set bit 21.5, "PMEXEC_OFF" */
+
+	while (1) ;
+	/* not reached */
+}
+
 static int __prep
 prep_show_percpuinfo(struct seq_file *m, int i)
 {
@@ -216,14 +583,120 @@
 	return 0;
 }
 
+#ifdef CONFIG_SOUND_CS4232 
+static long __init masktoint(unsigned int i)
+{
+	int t = -1;
+	while (i >> ++t)
+		;
+	return (t-1);
+}
+
+/*
+ * ppc_cs4232_dma and ppc_cs4232_dma2 are used in include/asm/dma.h
+ * to distinguish sound dma-channels from others. This is because 
+ * blocksize on 16 bit dma-channels 5,6,7 is 128k, but
+ * the cs4232.c uses 64k like on 8 bit dma-channels 0,1,2,3
+ */
+
+static void __init prep_init_sound(void)
+{
+	PPC_DEVICE *audiodevice = NULL;
+
+	/*
+	 * Get the needed resource informations from residual data.
+	 * 
+	 */
+#ifdef CONFIG_PREP_RESIDUAL
+	audiodevice = residual_find_device(~0, NULL, MultimediaController,
+			AudioController, -1, 0);
+	if (audiodevice != NULL) {
+		PnP_TAG_PACKET *pkt;
+
+		pkt = PnP_find_packet((unsigned char *)&res->DevicePnPHeap[audiodevice->AllocatedOffset],
+				S5_Packet, 0);
+		if (pkt != NULL)
+			ppc_cs4232_dma = masktoint(pkt->S5_Pack.DMAMask);
+		pkt = PnP_find_packet((unsigned char*)&res->DevicePnPHeap[audiodevice->AllocatedOffset],
+				S5_Packet, 1);
+		if (pkt != NULL)
+			ppc_cs4232_dma2 = masktoint(pkt->S5_Pack.DMAMask);
+	}
+#endif
+
+	/*
+	 * These are the PReP specs' defaults for the cs4231.  We use these
+	 * as fallback incase we don't have residual data.
+	 * At least the IBM Thinkpad 850 with IDE DMA Channels at 6 and 7 
+	 * will use the other values.
+	 */
+	if (audiodevice == NULL) {
+		switch (_prep_type) {
+		case _PREP_IBM:
+			ppc_cs4232_dma = 1;
+			ppc_cs4232_dma2 = -1;
+			break;
+		default: 
+			ppc_cs4232_dma = 6;
+			ppc_cs4232_dma2 = 7;
+		}
+	}
+
+	/*
+	 * Find a way to push these informations to the cs4232 driver
+	 * Give it out with printk, when not in cmd_line?
+	 * Append it to  cmd_line and saved_command_line?
+	 * Format is cs4232=io,irq,dma,dma2
+	 */
+}
+#endif /* CONFIG_SOUND_CS4232 */
+
+/*
+ * Fill out screen_info according to the residual data. This allows us to use
+ * at least vesafb.
+ */
+static void __init
+prep_init_vesa(void)
+{
+#if defined(CONFIG_PREP_RESIDUAL) && \
+	(defined(CONFIG_FB_VGA16) || defined(CONFIG_FB_VGA_16_MODULE) || \
+	 defined(CONFIG_FB_VESA))
+	PPC_DEVICE *vgadev;
+
+	vgadev = residual_find_device(~0, NULL, DisplayController, SVGAController,
+									-1, 0);
+	if (vgadev != NULL) {
+		PnP_TAG_PACKET *pkt;
+
+		pkt = PnP_find_large_vendor_packet(
+				(unsigned char *)&res->DevicePnPHeap[vgadev->AllocatedOffset],
+				0x04, 0); /* 0x04 = Display Tag */
+		if (pkt != NULL) {
+			unsigned char *ptr = (unsigned char *)pkt;
+
+			if (ptr[4]) {
+				/* graphics mode */
+				screen_info.orig_video_isVGA = VIDEO_TYPE_VLFB;
+
+				screen_info.lfb_depth = ptr[4] * 8;
+
+				screen_info.lfb_width = swab16(*(short *)(ptr+6));
+				screen_info.lfb_height = swab16(*(short *)(ptr+8));
+				screen_info.lfb_linelength = swab16(*(short *)(ptr+10));
+
+				screen_info.lfb_base = swab32(*(long *)(ptr+12));
+				screen_info.lfb_size = swab32(*(long *)(ptr+20)) / 65536;
+			}
+		}
+	}
+#endif /* CONFIG_PREP_RESIDUAL */
+}
+
 static void __init
 prep_setup_arch(void)
 {
 	unsigned char reg;
-#if 0 /* unused?? */
-	unsigned char ucMothMemType;
-	unsigned char ucEquipPres1;
-#endif
+	int is_ide=0;
 
 	/* init to some ~sane value until calibrate_delay() runs */
 	loops_per_jiffy = 50000000;
@@ -238,17 +711,64 @@
 	outb(reg, SIO_CONFIG_RD);
 	outb(reg, SIO_CONFIG_RD);	/* Have to write twice to change! */
 
-	/* we should determine this according to what we find! -- Cort */
 	switch ( _prep_type )
 	{
 	case _PREP_IBM:
-		/* Enable L2.  Assume we don't need to flush -- Cort*/
-		*(unsigned char *)(0x8000081c) |= 3;
-		ROOT_DEV = to_kdev_t(0x0301); /* hda1 */
+		reg = inb(PREP_IBM_PLANAR);
+		printk(KERN_INFO "IBM planar ID: %08x", reg);
+		switch (reg) {
+			case PREP_IBM_SANDALFOOT:
+				prep_gen_enable_l2();
+				setup_ibm_pci = prep_sandalfoot_setup_pci;
+				ppc_md.power_off = prep_sig750_poweroff;
+				ppc_md.show_cpuinfo = prep_sandalfoot_cpuinfo;
+				break;
+			case PREP_IBM_THINKPAD:
+				prep_gen_enable_l2();
+				setup_ibm_pci = prep_thinkpad_setup_pci;
+				ppc_md.power_off = prep_carrera_poweroff;
+				ppc_md.show_cpuinfo = prep_thinkpad_cpuinfo;
+				break;
+			default:
+				printk(" -- unknown! Assuming Carolina");
+			case PREP_IBM_CAROLINA_IDE_0:
+			case PREP_IBM_CAROLINA_IDE_1:
+			case PREP_IBM_CAROLINA_IDE_2:
+				is_ide = 1;
+			case PREP_IBM_CAROLINA_SCSI_0:
+			case PREP_IBM_CAROLINA_SCSI_1:
+			case PREP_IBM_CAROLINA_SCSI_2:
+			case PREP_IBM_CAROLINA_SCSI_3:
+				prep_carolina_enable_l2();
+				setup_ibm_pci = prep_carolina_setup_pci;
+				ppc_md.power_off = prep_sig750_poweroff;
+				ppc_md.show_cpuinfo = prep_carolina_cpuinfo;
+				break;
+			case PREP_IBM_TIGER1_133:
+			case PREP_IBM_TIGER1_166:
+			case PREP_IBM_TIGER1_180:
+			case PREP_IBM_TIGER1_xxx:
+			case PREP_IBM_TIGER1_333:
+				prep_carolina_enable_l2();
+				setup_ibm_pci = prep_tiger1_setup_pci;
+				ppc_md.power_off = prep_sig750_poweroff;
+				ppc_md.show_cpuinfo = prep_tiger1_cpuinfo;
+				break;
+		}
+		printk("\n");
+
+		/* default root device */
+		if (is_ide)
+			ROOT_DEV = to_kdev_t(0x0303); /* hda3 */
+		else
+			ROOT_DEV = to_kdev_t(0x0803); /* sda3 */
+
 		break;
 	case _PREP_Motorola:
-		/* Enable L2.  Assume we don't need to flush -- Cort*/
-		*(unsigned char *)(0x8000081c) |= 3;
+		prep_gen_enable_l2();
+		ppc_md.power_off = prep_halt;
+		ppc_md.show_cpuinfo = prep_mot_cpuinfo;
+
 #ifdef CONFIG_BLK_DEV_INITRD
 		if (initrd_start)
 			ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); /* /dev/ram */
@@ -276,46 +796,11 @@
 		}
 	}
 
-#ifdef CONFIG_SOUND_CS4232
-	/*
-	 * setup proper values for the cs4232 driver so we don't have
-	 * to recompile for the motorola or ibm workstations sound systems.
-	 * This is a really nasty hack, but unless we change the driver
-	 * it's the only way to support both addrs from one binary.
-	 * -- Cort
-	 */
-	if ( _machine == _MACH_prep )
-	{
-		extern struct card_info snd_installed_cards[];
-		struct card_info *snd_ptr;
-
-		for ( snd_ptr = snd_installed_cards; 
-			snd_ptr < &snd_installed_cards[num_sound_cards];
-			snd_ptr++ )
-		{
-			if ( snd_ptr->card_type == SNDCARD_CS4232 )
-			{
-				if ( _prep_type == _PREP_Motorola )
-				{
-					snd_ptr->config.io_base = 0x830;
-					snd_ptr->config.irq = 10;
-					snd_ptr->config.dma = ppc_cs4232_dma = 6;
-					snd_ptr->config.dma2 = ppc_cs4232_dma2 = 7;
-				}
-				if ( _prep_type == _PREP_IBM )
-				{
-					snd_ptr->config.io_base = 0x530;
-					snd_ptr->config.irq = 5;
-					snd_ptr->config.dma = ppc_cs4232_dma = 1;
-					/* this is wrong - but leave it for now */
-					snd_ptr->config.dma2 = ppc_cs4232_dma2 = 7;
-				}
-			}
-		}
-	}
-#endif /* CONFIG_SOUND_CS4232 */	
+#ifdef CONFIG_SOUND_CS4232 
+	prep_init_sound();
+#endif /* CONFIG_SOUND_CS4232 */
 
-	/*print_residual_device_info();*/
+	prep_init_vesa();
 
 	switch (_prep_type) {
 	case _PREP_Motorola:
@@ -327,9 +812,8 @@
 	}
 
 #ifdef CONFIG_VGA_CONSOLE
-	/* remap the VGA memory */
+	/* vgacon.c needs to know where we mapped IO memory in io_block_mapping() */
 	vgacon_remap_base = 0xf0000000;
-	/*vgacon_remap_base = ioremap(0xc0000000, 0xba000);*/
 	conswitchp = &vga_con;
 #elif defined(CONFIG_DUMMY_CONSOLE)
 	conswitchp = &dummy_con;
@@ -502,108 +986,6 @@
 	tb_to_us = mulhwu_scale_factor(freq, 1000000);
 }
 
-static void __prep
-prep_restart(char *cmd)
-{
-#define PREP_SP92	0x92	/* Special Port 92 */
-	__cli(); /* no interrupts */
-
-	/* set exception prefix high - to the prom */
-	_nmask_and_or_msr(0, MSR_IP);
-
-	/* make sure bit 0 (reset) is a 0 */
-	outb( inb(PREP_SP92) & ~1L , PREP_SP92);
-	/* signal a reset to system control port A - soft reset */
-	outb( inb(PREP_SP92) | 1 , PREP_SP92);
-
-	while ( 1 ) ;
-	/* not reached */
-#undef PREP_SP92
-}
-
-static void __prep
-prep_halt(void)
-{
-	__cli(); /* no interrupts */
-
-	/* set exception prefix high - to the prom */
-	_nmask_and_or_msr(0, MSR_IP);
-
-	while ( 1 ) ;
-	/* not reached */
-}
-
-/*
- * On IBM PReP's, power management is handled by a Signetics 87c750 behind the
- * Utah component on the ISA bus. To access the 750 you must write a series of
- * nibbles to port 0x82a (decoded by the Utah). This is described somewhat in
- * the IBM Carolina Technical Specification.
- * -Hollis
- */
-static void __prep
-utah_sig87c750_setbit(unsigned int bytenum, unsigned int bitnum, int value)
-{
-	/*
-	 * byte1: 0 0 0 1 0  d  a5 a4
-	 * byte2: 0 0 0 1 a3 a2 a1 a0
-	 *
-	 * d = the bit's value, enabled or disabled
-	 * (a5 a4 a3) = the byte number, minus 20
-	 * (a2 a1 a0) = the bit number
-	 *
-	 * example: set the 5th bit of byte 21 (21.5)
-	 *     a5 a4 a3 = 001 (byte 1)
-	 *     a2 a1 a0 = 101 (bit 5)
-	 *
-	 *     byte1 = 0001 0100 (0x14)
-	 *     byte2 = 0001 1101 (0x1d)
-	 */
-	unsigned char byte1=0x10, byte2=0x10;
-	const unsigned int pm_reg_1=0x82a; /* ISA address */
-
-	/* the 750's '20.0' is accessed as '0.0' through Utah (which adds 20) */
-	bytenum -= 20;
-
-	byte1 |= (!!value) << 2;		/* set d */
-	byte1 |= (bytenum >> 1) & 0x3;	/* set a5, a4 */
-
-	byte2 |= (bytenum & 0x1) << 3;	/* set a3 */
-	byte2 |= bitnum & 0x7;			/* set a2, a1, a0 */
-
-	outb(byte1, pm_reg_1);		/* first nibble */
-	mb();
-	udelay(100);				/* important: let controller recover */
-
-	outb(byte2, pm_reg_1);		/* second nibble */
-	mb();
-	udelay(100);				/* important: let controller recover */
-}
-
-static void __prep
-prep_power_off(void)
-{
-	if ( _prep_type == _PREP_IBM) {
-		/* tested on:
-		 * 		Carolina's: 7248-43P, 6070 (PowerSeries 850)
-		 * should work on:
-		 * 		Carolina: 6050 (PowerSeries 830)
-		 * 		7043-140 (Tiger 1)
-		 */
-		unsigned long flags;
-		__cli();
-		/* set exception prefix high - to the prom */
-		save_flags( flags );
-		restore_flags( flags|MSR_IP );
-
-		utah_sig87c750_setbit(21, 5, 1); /* set bit 21.5, "PMEXEC_OFF" */
-
-		while ( 1 ) ;
-		/* not reached */
-	} else {
-		prep_halt();
-	}
-}
-
 static unsigned int __prep
 prep_irq_cannonicalize(u_int irq)
 {
@@ -621,12 +1003,28 @@
 prep_init_IRQ(void)
 {
 	int i;
+	unsigned int pci_viddid, pci_did;
 
-	if (OpenPIC_Addr != NULL)
-		openpic_init(1, NUM_8259_INTERRUPTS, 0, -1);
-	for ( i = 0 ; i < NUM_8259_INTERRUPTS ; i++ )
+	if (OpenPIC_Addr != NULL) {
+		openpic_init(NUM_8259_INTERRUPTS);
+		/* We have a cascade on OpenPIC IRQ 0, Linux IRQ 16 */
+		openpic_hookup_cascade(NUM_8259_INTERRUPTS, "82c59 cascade",
+				       i8259_irq);
+	}
+	for (i = 0; i < NUM_8259_INTERRUPTS; i++)
 		irq_desc[i].handler = &i8259_pic;
-	i8259_init(0xbffffff0); /* PCI interrupt ack address for MPC105 and 106 */
+	 /* If we have a Raven PCI bridge or a Hawk PCI bridge / Memory
+	  * controller, we poll (as they have a different int-ack address). */
+	early_read_config_dword(0, 0, 0, PCI_VENDOR_ID, &pci_viddid);
+	pci_did = (pci_viddid & 0xffff0000) >> 16;
+	if (((pci_viddid & 0xffff) == PCI_VENDOR_ID_MOTOROLA)
+			&& ((pci_did == PCI_DEVICE_ID_MOTOROLA_RAVEN)
+				|| (pci_did == PCI_DEVICE_ID_MOTOROLA_HAWK)))
+		i8259_init(0);
+	else
+		/* PCI interrupt ack address given in section 6.1.8 of the
+		 * PReP specification. */
+		i8259_init(0xbffffff0);
 }
 
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
@@ -659,46 +1057,6 @@
 			return 0;
 	}
 }
-
-static int __prep
-prep_ide_check_region(ide_ioreg_t from, unsigned int extent)
-{
-	return check_region(from, extent);
-}
-
-static void __prep
-prep_ide_request_region(ide_ioreg_t from,
-			unsigned int extent,
-			const char *name)
-{
-	request_region(from, extent, name);
-}
-
-static void __prep
-prep_ide_release_region(ide_ioreg_t from,
-			unsigned int extent)
-{
-	release_region(from, extent);
-}
-
-static void __init
-prep_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
-{
-	ide_ioreg_t reg = data_port;
-	int i;
-
-	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
-		hw->io_ports[i] = reg;
-		reg += 1;
-	}
-	if (ctrl_port) {
-		hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
-	} else {
-		hw->io_ports[IDE_CONTROL_OFFSET] = hw->io_ports[IDE_DATA_OFFSET] + 0x206;
-	}
-	if (irq != NULL)
-		*irq = 0;
-}
 #endif
 
 #ifdef CONFIG_SMP
@@ -722,7 +1080,7 @@
 {
 	*(unsigned long *)KERNELBASE = nr;
 	asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory");
-	printk("CPU1 reset, waiting\n");
+	printk("CPU1 released, waiting\n");
 }
 
 static void __init
@@ -741,34 +1099,12 @@
 #endif /* CONFIG_SMP */
 
 /*
- * This finds the amount of physical ram and does necessary
- * setup for prep.  This is pretty architecture specific so
- * this will likely stay separate from the pmac.
- * -- Cort
+ * What ever boots us must pass in the ammount of memory.
  */
 static unsigned long __init
 prep_find_end_of_memory(void)
 {
-	unsigned long total = 0;
-	extern unsigned int boot_mem_size;
-
-#ifdef CONFIG_PREP_RESIDUAL	
-	total = res->TotalMemory;
-#endif	
-
-	if (total == 0 && boot_mem_size != 0)
-		total = boot_mem_size;
-	else if (total == 0) {
-		/*
-		 * I need a way to probe the amount of memory if the residual
-		 * data doesn't contain it. -- Cort
-		 */
-		total = 0x02000000;
-		printk(KERN_INFO "Ramsize from residual data was 0"
-			 " -- defaulting to %ldM\n", total>>20);
-	}
-
-	return (total);
+	return boot_mem_size;
 }
 
 /*
@@ -789,8 +1125,6 @@
 #ifdef CONFIG_NVRAM
 	request_region(PREP_NVRAM_AS0, 0x8, "nvram");
 #endif
-	request_region(0x20,0x20,"pic1");
-	request_region(0xa0,0x20,"pic2");
 	request_region(0x00,0x20,"dma1");
 	request_region(0x40,0x20,"timer");
 	request_region(0x80,0x10,"dma page reg");
@@ -818,14 +1152,12 @@
 
 	/* figure out what kind of prep workstation we are */
 #ifdef CONFIG_PREP_RESIDUAL	
-	if ( res->ResidualLength != 0 )
-	{
+	if ( res->ResidualLength != 0 ) {
 		if ( !strncmp(res->VitalProductData.PrintableModel,"IBM",3) )
 			_prep_type = _PREP_IBM;
 		else
 			_prep_type = _PREP_Motorola;
-	}
-	else /* assume motorola if no residual (netboot?) */
+	} else /* assume motorola if no residual (netboot?) */
 #endif
 	{
 		_prep_type = _PREP_Motorola;
@@ -833,7 +1165,7 @@
 
 	ppc_md.setup_arch     = prep_setup_arch;
 	ppc_md.show_percpuinfo = prep_show_percpuinfo;
-	ppc_md.show_cpuinfo   = prep_show_cpuinfo;
+	ppc_md.show_cpuinfo   = NULL; /* set in prep_setup_arch() */
 	ppc_md.irq_cannonicalize = prep_irq_cannonicalize;
 	ppc_md.init_IRQ       = prep_init_IRQ;
 	/* this gets changed later on if we have an OpenPIC -- Cort */
@@ -841,7 +1173,7 @@
 	ppc_md.init           = prep_init2;
 
 	ppc_md.restart        = prep_restart;
-	ppc_md.power_off      = prep_power_off;
+	ppc_md.power_off      = NULL; /* set in prep_setup_arch() */
 	ppc_md.halt           = prep_halt;
 
 	ppc_md.nvram_read_val = prep_nvram_read_val;
@@ -865,10 +1197,6 @@
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
 	ppc_ide_md.default_irq = prep_ide_default_irq;
 	ppc_ide_md.default_io_base = prep_ide_default_io_base;
-	ppc_ide_md.ide_check_region = prep_ide_check_region;
-	ppc_ide_md.ide_request_region = prep_ide_request_region;
-	ppc_ide_md.ide_release_region = prep_ide_release_region;
-	ppc_ide_md.ide_init_hwif = prep_ide_init_hwif_ports;
 #endif
 
 #ifdef CONFIG_VT
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/prep_time.c linux-2.4.21-pre6/arch/ppc/platforms/prep_time.c
--- linux-2.4.20/arch/ppc/platforms/prep_time.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/prep_time.c	2003-03-26 23:49:39.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/platforms/prep_time.c
  *
  *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/proc_rtas.c linux-2.4.21-pre6/arch/ppc/platforms/proc_rtas.c
--- linux-2.4.20/arch/ppc/platforms/proc_rtas.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/proc_rtas.c	2003-03-26 23:49:55.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.proc_rtas.c 1.5 05/17/01 18:14:22 cort
- */
-/*
  *   arch/ppc/kernel/proc_rtas.c
  *   Copyright (C) 2000 Tilmann Bitterberg
  *   (tilmann@bitterberg.de)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/residual.c linux-2.4.21-pre6/arch/ppc/platforms/residual.c
--- linux-2.4.20/arch/ppc/platforms/residual.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/residual.c	2003-03-26 23:49:10.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.residual.c 1.15 02/05/02 18:08:35 trini
- */
-/*
  * Code to deal with the PReP residual data.
  *
  * Written by: Cort Dougan (cort@cs.nmt.edu)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/rpxclassic.h linux-2.4.21-pre6/arch/ppc/platforms/rpxclassic.h
--- linux-2.4.20/arch/ppc/platforms/rpxclassic.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/rpxclassic.h	2003-03-26 23:49:08.000000000 +0000
@@ -1,8 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-
-/*
  * A collection of structures, addresses, and values associated with
  * the RPCG RPX-Classic board.  Copied from the RPX-Lite stuff.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/rpxhiox.h linux-2.4.21-pre6/arch/ppc/platforms/rpxhiox.h
--- linux-2.4.20/arch/ppc/platforms/rpxhiox.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/rpxhiox.h	2003-03-26 23:49:54.000000000 +0000
@@ -1,8 +1,4 @@
 /*
- * BK Id: SCCS/s.rpxhiox.h 1.3 05/17/01 18:14:25 cort
- */
-
-/*
  * The Embedded Planet HIOX expansion card definitions.
  * There were a few different versions of these cards, but only
  * the one that escaped real production is defined here.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/rpxlite.h linux-2.4.21-pre6/arch/ppc/platforms/rpxlite.h
--- linux-2.4.20/arch/ppc/platforms/rpxlite.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/rpxlite.h	2003-03-26 23:49:05.000000000 +0000
@@ -1,8 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-
-/*
  * A collection of structures, addresses, and values associated with
  * the RPCG RPX-Lite board.  Copied from the MBX stuff.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/spd8xx.h linux-2.4.21-pre6/arch/ppc/platforms/spd8xx.h
--- linux-2.4.20/arch/ppc/platforms/spd8xx.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/spd8xx.h	2003-03-26 23:49:05.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.spd8xx.h 1.8 10/27/01 13:39:41 trini
- */
-/*
  * Speech Design SPD8xxTS board specific definitions
  * 
  * Copyright (c) 2000,2001 Wolfgang Denk (wd@denx.de)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/spruce.h linux-2.4.21-pre6/arch/ppc/platforms/spruce.h
--- linux-2.4.20/arch/ppc/platforms/spruce.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/spruce.h	2003-03-26 23:48:58.000000000 +0000
@@ -7,27 +7,10 @@
  *          mporter@mvista.com
  *          jpeters@mvista.com
  *
- * Copyright 2001 MontaVista Software Inc.
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- *
- * THIS  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.
- *
- * 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.
+ * 2001 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
  */
 
 #ifdef __KERNEL__
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/spruce_pci.c linux-2.4.21-pre6/arch/ppc/platforms/spruce_pci.c
--- linux-2.4.20/arch/ppc/platforms/spruce_pci.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/spruce_pci.c	2003-03-26 23:49:00.000000000 +0000
@@ -6,27 +6,10 @@
  * Author: Johnnie Peters
  *         jpeters@mvista.com
  *
- * Copyright 2000 MontaVista Software Inc.
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- *
- * THIS  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.
- *
- * 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.
+ * 2000 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
  */
 
 #include <linux/kernel.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/spruce_setup.c linux-2.4.21-pre6/arch/ppc/platforms/spruce_setup.c
--- linux-2.4.20/arch/ppc/platforms/spruce_setup.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/spruce_setup.c	2003-03-26 23:49:54.000000000 +0000
@@ -6,27 +6,10 @@
  * Authors: Johnnie Peters <jpeters@mvista.com>
  *          Matt Porter <mporter@mvista.com>
  *
- * Copyright 2001-2002 MontaVista Software Inc.
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- *
- * THIS  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.
- *
- * 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.
+ * 2001-2002 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
  */
 
 #include <linux/config.h>
@@ -73,6 +56,9 @@
 extern unsigned char pckbd_sysrq_xlate[128];
 extern char cmd_line[];
 
+extern void gen550_progress(char *, unsigned short);
+extern void gen550_init(int, struct serial_struct *);
+
 /*
  * CPC700 PIC interrupt programming table
  *
@@ -128,14 +114,56 @@
 	return 0;
 }
 
-TODC_ALLOC();
-
+#ifdef CONFIG_SERIAL
 static void __init
-spruce_setup_arch(void)
+spruce_early_serial_map(void)
 {
 	u32 baud_base;
 	struct serial_struct serial_req;
 
+	if (SPRUCE_UARTCLK_IS_33M(readb(SPRUCE_FPGA_REG_A)))
+		baud_base = SPRUCE_BAUD_33M;
+	else
+		baud_base = SPRUCE_BAUD_30M;
+
+	/* Setup serial port access */
+	memset(&serial_req, 0, sizeof(serial_req));
+	serial_req.baud_base = baud_base;
+	serial_req.line = 0;
+	serial_req.port = 0;
+	serial_req.irq = 3;
+	serial_req.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
+	serial_req.io_type = SERIAL_IO_MEM;
+	serial_req.iomem_base = (u_char *)UART0_IO_BASE;
+	serial_req.iomem_reg_shift = 0;
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+	gen550_init(0, &serial_req);
+#endif
+
+	if (early_serial_setup(&serial_req) != 0)
+		printk("Early serial init of port 0 failed\n");
+
+	/* Assume early_serial_setup() doesn't modify serial_req */
+	serial_req.line = 1;
+	serial_req.port = 1;
+	serial_req.irq = 4;
+	serial_req.iomem_base = (u_char *)UART1_IO_BASE;
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+	gen550_init(1, &serial_req);
+#endif
+
+	if (early_serial_setup(&serial_req) != 0)
+		printk("Early serial init of port 1 failed\n");
+}
+#endif
+
+TODC_ALLOC();
+
+static void __init
+spruce_setup_arch(void)
+{
 	/* Setup TODC access */
 	TODC_INIT(TODC_TYPE_DS1643, 0, 0, SPRUCE_RTC_BASE_ADDR, 8);
 
@@ -160,35 +188,9 @@
 	conswitchp = &dummy_con;
 #endif
 
-	if (SPRUCE_UARTCLK_IS_33M(readb(SPRUCE_FPGA_REG_A)))	
-		baud_base = SPRUCE_BAUD_33M;
-	else
-		baud_base = SPRUCE_BAUD_30M;
-
-	/* Setup serial port access */
-	memset(&serial_req, 0, sizeof(serial_req));
-	serial_req.baud_base = baud_base;
-	serial_req.line = 0;
-	serial_req.port = 0;
-	serial_req.irq = 3;
-	serial_req.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
-	serial_req.io_type = SERIAL_IO_MEM;
-	serial_req.iomem_base = UART0_IO_BASE;
-	serial_req.iomem_reg_shift = 0;
-
-	if (early_serial_setup(&serial_req) != 0) {
-		printk("Early serial init of port 0 failed\n");
-	}
-
-	/* Assume early_serial_setup() doesn't modify serial_req */
-	serial_req.line = 1;
-	serial_req.port = 1;
-	serial_req.irq = 4; 
-	serial_req.iomem_base = UART1_IO_BASE;
-
-	if (early_serial_setup(&serial_req) != 0) {
-		printk("Early serial init of port 1 failed\n");
-	}
+#ifdef CONFIG_SERIAL
+	spruce_early_serial_map();
+#endif
 
 	/* Identify the system */
 	printk("System Identification: IBM Spruce\n");
@@ -202,15 +204,12 @@
 
 	/* SRR0 has system reset vector, SRR1 has default MSR value */
 	/* rfi restores MSR from SRR1 and sets the PC to the SRR0 value */
-	__asm__ __volatile__
-	("\n\
-	lis	3,0xfff0
-	ori	3,3,0x0100
-	mtspr	26,3
-	li	3,0
-	mtspr	27,3
-	rfi
-	");
+	asm volatile("	lis	3,0xfff0	\n\
+			ori	3,3,0x0100	\n\
+			mtspr	26,3		\n\
+			li	3,0		\n\
+			mtspr	27,3		\n\
+			rfi");
 	for(;;);
 }
 
@@ -249,10 +248,10 @@
 	__raw_writel(0x03000000, 0xff50000c);
 	eieio();
 
-	asm volatile("	lis	7,0xff88	\n
-			ori	7,7,0x8		\n
-			lswi	6,7,0x8		\n
-			mr	%0,6		\n"
+	asm volatile("	lis	7,0xff88	\n\
+			ori	7,7,0x8		\n\
+			lswi	6,7,0x8		\n\
+			mr	%0,6"
 			: "=r" (kbd_status) :: "6", "7");
 
 	__raw_writel(0x00000000, 0xff50000c);
@@ -271,9 +270,9 @@
 	__raw_writel(0x03000000, 0xff50000c);
 	eieio();
 
-	asm volatile("	lis	7,0xff88	\n
-			lswi	6,7,0x8		\n
-			mr	%0,6		\n"
+	asm volatile("	lis	7,0xff88	\n\
+			lswi	6,7,0x8		\n\
+			mr	%0,6"
 			: "=r" (kbd_data) :: "6", "7");
 
 	__raw_writel(0x00000000, 0xff50000c);
@@ -282,6 +281,26 @@
 	return (unsigned char)(kbd_data >> 24);
 }
 
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+/*
+ * Set BAT 3 to map 0xf8000000 to end of physical memory space 1-to-1.
+ */
+static __inline__ void
+spruce_set_bat(void)
+{
+	unsigned long	bat3u, bat3l;
+
+	asm volatile("  lis	%0,0xf800	\n\
+			ori	%1,%0,0x002a	\n\
+			ori	%0,%0,0x0ffe	\n\
+			mtspr	0x21e,%0	\n\
+			mtspr	0x21f,%1	\n\
+			isync			\n\
+			sync "
+			: "=r" (bat3u), "=r" (bat3l));
+}
+#endif
+
 void __init
 platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
 	      unsigned long r6, unsigned long r7)
@@ -311,6 +330,17 @@
 	ppc_md.nvram_read_val = todc_direct_read_val;
 	ppc_md.nvram_write_val = todc_direct_write_val;
 
+#if defined(CONFIG_SERIAL) && (defined(CONFIG_SERIAL_TEXT_DEBUG) \
+		|| defined(CONFIG_KGDB))
+	spruce_set_bat();
+	spruce_early_serial_map();
+
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+	ppc_md.progress = gen550_progress;
+#endif /* CONFIG_SERIAL_TEXT_DEBUG */
+	ppc_md.early_serial_map = spruce_early_serial_map;
+#endif
+
 #ifdef CONFIG_VT
 	/* Spruce has a PS2 style keyboard */
 	ppc_md.kbd_setkeycode = pckbd_setkeycode;
@@ -320,7 +350,7 @@
 	ppc_md.kbd_leds = pckbd_leds;
 	ppc_md.kbd_init_hw = pckbd_init_hw;
 #ifdef CONFIG_MAGIC_SYSRQ
-	ppc_md.kbd_sysrq_xlate = pckbd_sysrq_xlate;
+	ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate;
 	SYSRQ_KEY = 0x54;
 #endif
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/tqm8xx.h linux-2.4.21-pre6/arch/ppc/platforms/tqm8xx.h
--- linux-2.4.20/arch/ppc/platforms/tqm8xx.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/tqm8xx.h	2003-03-26 23:49:27.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.tqm8xx.h 1.8 08/30/01 09:01:04 trini
- */
-/*
  * TQM8xx(L) board specific definitions
  * 
  * Copyright (c) 1999,2000,2001 Wolfgang Denk (wd@denx.de)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/walnut.c linux-2.4.21-pre6/arch/ppc/platforms/walnut.c
--- linux-2.4.20/arch/ppc/platforms/walnut.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/walnut.c	2003-03-26 23:49:34.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.walnut_setup.c 1.10 11/13/01 21:26:07 paulus
- */
-/*
  *
  *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/platforms/walnut.h linux-2.4.21-pre6/arch/ppc/platforms/walnut.h
--- linux-2.4.20/arch/ppc/platforms/walnut.h	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/platforms/walnut.h	2003-03-26 23:48:59.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.walnut_setup.h 1.5 05/17/01 18:14:22 cort
- */
-/*
  *
  *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/xmon/Makefile linux-2.4.21-pre6/arch/ppc/xmon/Makefile
--- linux-2.4.20/arch/ppc/xmon/Makefile	2001-07-02 21:34:57.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/xmon/Makefile	2003-03-26 23:49:07.000000000 +0000
@@ -1,4 +1,3 @@
-# BK Id: SCCS/s.Makefile 1.6 06/27/01 14:49:58 trini
 #
 # Makefile for xmon
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/xmon/adb.c linux-2.4.21-pre6/arch/ppc/xmon/adb.c
--- linux-2.4.20/arch/ppc/xmon/adb.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/xmon/adb.c	2003-03-26 23:49:38.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.adb.c 1.5 05/17/01 18:14:23 cort
- */
-/*
  * Copyright (C) 1996 Paul Mackerras.
  */
 #include "nonstdio.h"
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/xmon/ansidecl.h linux-2.4.21-pre6/arch/ppc/xmon/ansidecl.h
--- linux-2.4.20/arch/ppc/xmon/ansidecl.h	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/xmon/ansidecl.h	2003-03-26 23:49:37.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.ansidecl.h 1.5 05/17/01 18:14:23 cort
- */
 /* ANSI and traditional C compatability macros
    Copyright 1991, 1992 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/xmon/nonstdio.h linux-2.4.21-pre6/arch/ppc/xmon/nonstdio.h
--- linux-2.4.20/arch/ppc/xmon/nonstdio.h	2002-02-25 19:37:55.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/xmon/nonstdio.h	2003-03-26 23:49:40.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.nonstdio.h 1.8 12/01/01 20:09:07 benh
- */
 typedef int	FILE;
 extern FILE *xmon_stdin, *xmon_stdout;
 #define EOF	(-1)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/xmon/ppc-dis.c linux-2.4.21-pre6/arch/ppc/xmon/ppc-dis.c
--- linux-2.4.20/arch/ppc/xmon/ppc-dis.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/xmon/ppc-dis.c	2003-03-26 23:49:54.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.ppc-dis.c 1.5 05/17/01 18:14:23 cort
- */
 /* ppc-dis.c -- Disassemble PowerPC instructions
    Copyright 1994 Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/xmon/ppc-opc.c linux-2.4.21-pre6/arch/ppc/xmon/ppc-opc.c
--- linux-2.4.20/arch/ppc/xmon/ppc-opc.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/xmon/ppc-opc.c	2003-03-26 23:48:58.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.ppc-opc.c 1.5 05/17/01 18:14:23 cort
- */
 /* ppc-opc.c -- PowerPC opcode list
    Copyright 1994 Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/xmon/ppc.h linux-2.4.21-pre6/arch/ppc/xmon/ppc.h
--- linux-2.4.20/arch/ppc/xmon/ppc.h	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/xmon/ppc.h	2003-03-26 23:49:31.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.ppc.h 1.5 05/17/01 18:14:23 cort
- */
 /* ppc.h -- Header file for PowerPC opcode table
    Copyright 1994 Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/xmon/privinst.h linux-2.4.21-pre6/arch/ppc/xmon/privinst.h
--- linux-2.4.20/arch/ppc/xmon/privinst.h	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/xmon/privinst.h	2003-03-26 23:49:30.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.privinst.h 1.5 05/17/01 18:14:23 cort
- */
-/*
  * Copyright (C) 1996 Paul Mackerras.
  */
 #include <linux/config.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/xmon/setjmp.c linux-2.4.21-pre6/arch/ppc/xmon/setjmp.c
--- linux-2.4.20/arch/ppc/xmon/setjmp.c	2001-05-22 00:04:47.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/xmon/setjmp.c	2003-03-26 23:49:53.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.setjmp.c 1.5 05/17/01 18:14:23 cort
- */
-/*
  * Copyright (C) 1996 Paul Mackerras.
  *
  * NB this file must be compiled with -O2.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/xmon/start.c linux-2.4.21-pre6/arch/ppc/xmon/start.c
--- linux-2.4.20/arch/ppc/xmon/start.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/xmon/start.c	2003-03-26 23:48:58.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.start.c 1.20 04/09/02 21:01:58 paulus
- */
-/*
  * Copyright (C) 1996 Paul Mackerras.
  */
 #include <linux/config.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/xmon/start_8xx.c linux-2.4.21-pre6/arch/ppc/xmon/start_8xx.c
--- linux-2.4.20/arch/ppc/xmon/start_8xx.c	2001-10-08 18:40:13.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/xmon/start_8xx.c	2003-03-26 23:49:20.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.start_8xx.c 1.10 09/14/01 18:01:17 trini
- */
-/*
  * Copyright (C) 1996 Paul Mackerras.
  * Copyright (C) 2000 Dan Malek.
  * Quick hack of Paul's code to make XMON work on 8xx processors.  Lots
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/xmon/subr_prf.c linux-2.4.21-pre6/arch/ppc/xmon/subr_prf.c
--- linux-2.4.20/arch/ppc/xmon/subr_prf.c	2002-02-25 19:37:55.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/xmon/subr_prf.c	2003-03-26 23:49:00.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.subr_prf.c 1.8 12/01/01 20:09:07 benh
- */
-/*
  * Written by Cort Dougan to replace the version originally used
  * by Paul Mackerras, which came from NetBSD and thus had copyright
  * conflicts with Linux.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc/xmon/xmon.c linux-2.4.21-pre6/arch/ppc/xmon/xmon.c
--- linux-2.4.20/arch/ppc/xmon/xmon.c	2002-02-25 19:37:55.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc/xmon/xmon.c	2003-03-26 23:48:57.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.xmon.c 1.18 12/01/01 20:09:07 benh
- */
-/*
  * Routines providing a simple monitor for use on the PowerMac.
  *
  * Copyright (C) 1996 Paul Mackerras.
@@ -14,6 +11,8 @@
 #include <asm/string.h>
 #include <asm/prom.h>
 #include <asm/bitops.h>
+#include <asm/mmu.h>
+
 #include "nonstdio.h"
 #include "privinst.h"
 
@@ -921,15 +920,22 @@
 }
 #endif
 
+#ifndef CONFIG_PPC_STD_MMU
+static void
+dump_hash_table()
+{
+	printf("This CPU doesn't have a hash table.\n");
+}
+#else
+
 #ifndef CONFIG_PPC64BRIDGE
 static void
 dump_hash_table_seg(unsigned seg, unsigned start, unsigned end)
 {
-	extern void *Hash;
-	extern unsigned long Hash_size;
-	unsigned *htab = Hash;
-	unsigned hsize = Hash_size;
-	unsigned v, hmask, va, last_va;
+	void *htab = Hash;
+	unsigned long hsize = Hash_size;
+	unsigned long hmask;
+	unsigned v, va, last_va;
 	int found, last_found, i;
 	unsigned *hg, w1, last_w2, last_va0;
 
@@ -984,11 +990,10 @@
 static void
 dump_hash_table_seg(unsigned seg, unsigned start, unsigned end)
 {
-	extern void *Hash;
-	extern unsigned long Hash_size;
-	unsigned *htab = Hash;
-	unsigned hsize = Hash_size;
-	unsigned v, hmask, va, last_va;
+	void *htab = Hash;
+	unsigned long hsize = Hash_size;
+	unsigned long hmask;
+	unsigned v, va, last_va;
 	int found, last_found, i;
 	unsigned *hg, w1, last_w2, last_va0;
 
@@ -1050,6 +1055,8 @@
 	int seg;
 	unsigned seg_start, seg_end;
 
+	if (Hash == NULL)
+		return;
 	hash_ctx = 0;
 	hash_start = 0;
 	hash_end = 0xfffff000;
@@ -1067,6 +1074,7 @@
 		seg_start = seg_end + 0x1000;
 	}
 }
+#endif /* CONFIG_PPC_STD_MMU */
 
 /*
  * Stuff for reading and writing memory safely
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/boot/Makefile linux-2.4.21-pre6/arch/ppc64/boot/Makefile
--- linux-2.4.20/arch/ppc64/boot/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/boot/Makefile	2003-03-26 23:49:39.000000000 +0000
@@ -24,7 +24,7 @@
 #CROSS32_COMPILE = /usr/local/ppc/bin/powerpc-linux-
 
 BOOTCC = $(CROSS32_COMPILE)gcc
-BOOTCFLAGS = $(HOSTCFLAGS) -I$(HPATH)
+BOOTCFLAGS = $(HOSTCFLAGS) -fno-builtin -I$(HPATH)
 BOOTLD = $(CROSS32_COMPILE)ld
 BOOTAS = $(CROSS32_COMPILE)as
 BOOTAFLAGS = -D__ASSEMBLY__ $(HOSTCFLAGS) -I$(HPATH)
@@ -40,7 +40,6 @@
 LD_ARGS = -Ttext 0x00400000 -e _start
 
 OBJS = crt0.o string.o prom.o zImage.o zlib.o imagesize.o
-#LIBS = $(TOPDIR)/lib/lib.a
 LIBS =
 
 ifeq ($(CONFIG_SMP),y)
@@ -93,6 +92,8 @@
 	ls -l $(TOPDIR)/vmlinux | awk '{printf "/* generated -- do not edit! */\nunsigned long vmlinux_filesize = %d;\n", $$5}' > imagesize.c
 	$(CROSS_COMPILE)nm -n $(TOPDIR)/vmlinux | tail -1 | awk '{printf "unsigned long vmlinux_memsize = 0x%s;\n", substr($$1,8)}' >> imagesize.c
 
+zImage.o: $(TOPDIR)/vmlinux
+
 vmlinux .config System.map: % : $(TOPDIR)/%
 	gzip -cvf9 $(TOPDIR)/$@ > kernel-$@.gz
 	$(OBJCOPY) zImage.o \
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/boot/README linux-2.4.21-pre6/arch/ppc64/boot/README
--- linux-2.4.20/arch/ppc64/boot/README	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/boot/README	2003-03-26 23:48:59.000000000 +0000
@@ -0,0 +1,10 @@
+
+To extract the kernel vmlinux, System.map or .config from the zImage binary:
+
+objcopy -j .kernel:vmlinux -O binary zImage vmlinux.gz
+objcopy -j .kernel:System.map -O binary zImage System.map.gz
+objcopy -j .kernel:.config -O binary zImage config.gz
+
+
+	Peter
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/boot/addRamDisk.c linux-2.4.21-pre6/arch/ppc64/boot/addRamDisk.c
--- linux-2.4.20/arch/ppc64/boot/addRamDisk.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/boot/addRamDisk.c	2003-03-26 23:49:07.000000000 +0000
@@ -154,9 +154,8 @@
   
 	/* Process the Sysmap file to determine where _end is */
 	sysmapPages = sysmapLen / 4096;
-	for (i=0; i<sysmapPages; ++i) {
-		get4k(sysmap, inbuf);
-	}
+	/* read the whole file line by line, expect that it doesnt fail */
+	while ( fgets(inbuf, 4096, sysmap) )  ;
 	/* search for _end in the last page of the system map */
 	ptr_end = strstr(inbuf, " _end");
 	if (!ptr_end) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/boot/addSystemMap.c linux-2.4.21-pre6/arch/ppc64/boot/addSystemMap.c
--- linux-2.4.20/arch/ppc64/boot/addSystemMap.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/boot/addSystemMap.c	2003-03-26 23:49:53.000000000 +0000
@@ -146,10 +146,8 @@
   /* Process the Sysmap file to determine the true end of the kernel */
 	sysmapPages = sysmapLen / 4096;
 	printf("System map pages to copy = %ld\n", sysmapPages);
-	for (i=0; i<sysmapPages; ++i)
-	{
-		get4k(sysmap, inbuf);
-	}
+	/* read the whole file line by line, expect that it doesnt fail */
+	while ( fgets(inbuf, 4096, sysmap) )  ;
 	/* search for _end in the last page of the system map */
 	ptr_end = strstr(inbuf, " _end");
 	if (!ptr_end)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/boot/zImage.c linux-2.4.21-pre6/arch/ppc64/boot/zImage.c
--- linux-2.4.20/arch/ppc64/boot/zImage.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/boot/zImage.c	2003-03-26 23:49:54.000000000 +0000
@@ -12,11 +12,14 @@
 #include "ppc32-types.h"
 #include "zlib.h"
 #include <linux/elf.h>
+#include <linux/version.h>
 #include <asm/processor.h>
 #include <asm/page.h>
 #include <asm/bootinfo.h>
 
 void memmove(void *dst, void *im, int len);
+void *memcpy(void *dest, const void *src, size_t n);
+size_t strlen(const char *s);
 
 extern void *finddevice(const char *);
 extern int getprop(void *, const char *, void *, int);
@@ -88,6 +91,8 @@
 	kernel_entry_t kernel_entry;
 	Elf64_Ehdr *elf64;
 	Elf64_Phdr *elf64ph;
+	/* tell userland tools about uname -r */
+	unsigned char this_uts[] = "Linux version " UTS_RELEASE;
 
 	prom = (int (*)(void *)) promptr;
 	chosen_handle = finddevice("/chosen");
@@ -100,6 +105,7 @@
 		exit();
 
 	printf("zImage starting: loaded at 0x%x\n\r", (unsigned)&_start);
+	printf("%s\n\r", this_uts);
 
 #if 0
 	sysmap.size = (unsigned long)(_sysmap_end - _sysmap_start);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/config.in linux-2.4.21-pre6/arch/ppc64/config.in
--- linux-2.4.20/arch/ppc64/config.in	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/config.in	2003-03-26 23:49:19.000000000 +0000
@@ -38,6 +38,7 @@
 else
 bool 'MsChunks Physical to Absolute address translation support' CONFIG_MSCHUNKS
 tristate 'Firmware flash interface' CONFIG_RTAS_FLASH
+tristate 'Scanlog Dump interface' CONFIG_SCANLOG
 fi
 
 
@@ -228,6 +229,8 @@
 source drivers/usb/Config.in
 fi
 
+source lib/Config.in
+
 mainmenu_option next_comment
 comment 'Kernel hacking'
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/configs/pSeries_defconfig linux-2.4.21-pre6/arch/ppc64/configs/pSeries_defconfig
--- linux-2.4.20/arch/ppc64/configs/pSeries_defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/configs/pSeries_defconfig	2003-03-26 23:49:26.000000000 +0000
@@ -26,6 +26,7 @@
 # CONFIG_HMT is not set
 # CONFIG_MSCHUNKS is not set
 CONFIG_RTAS_FLASH=m
+CONFIG_SCANLOG=m
 
 #
 # Loadable module support
@@ -42,6 +43,7 @@
 # CONFIG_MCA is not set
 # CONFIG_EISA is not set
 CONFIG_PCI=y
+# CONFIG_PCMCIA is not set
 CONFIG_NET=y
 CONFIG_SYSCTL=y
 CONFIG_SYSVIPC=y
@@ -52,7 +54,6 @@
 # CONFIG_BINFMT_MISC is not set
 CONFIG_PCI_NAMES=y
 # CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
 
 #
 # Parallel port support
@@ -61,20 +62,7 @@
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_FB=y
 CONFIG_PROC_DEVICETREE=y
-
-CONFIG_CMDLINE_BOOL=n
-CONFIG_CMDLINE="console=ttyS0,9600 console=tty0 root=/dev/sda2"
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
+# CONFIG_CMDLINE_BOOL is not set
 
 #
 # Block devices
@@ -92,6 +80,7 @@
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_STATS is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -178,15 +167,6 @@
 # CONFIG_BLK_DEV_IDEDISK is not set
 # CONFIG_IDEDISK_MULTI_MODE is not set
 # CONFIG_IDEDISK_STROKE is not set
-# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
-# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
-# CONFIG_BLK_DEV_IDEDISK_IBM is not set
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
 # CONFIG_BLK_DEV_IDECS is not set
 CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_IDETAPE is not set
@@ -200,8 +180,8 @@
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
 CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_BLK_DEV_GENERIC is not set
 # CONFIG_IDEPCI_SHARE_IRQ is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
@@ -210,28 +190,31 @@
 # CONFIG_IDEDMA_ONLYDISK is not set
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_PCI_WIP is not set
-# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set
-# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
 CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_AEC62XX is not set
-# CONFIG_AEC62XX_TUNING is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
 # CONFIG_WDC_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD74XX is not set
 # CONFIG_AMD74XX_OVERRIDE is not set
 # CONFIG_BLK_DEV_CMD64X is not set
-# CONFIG_BLK_DEV_CMD680 is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5530 is not set
 # CONFIG_BLK_DEV_HPT34X is not set
 # CONFIG_HPT34X_AUTODMA is not set
 # CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_NFORCE is not set
 # CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_PDC202XX is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
 # CONFIG_PDC202XX_BURST is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
 # CONFIG_PDC202XX_FORCE is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
 # CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
 # CONFIG_BLK_DEV_SIS5513 is not set
 # CONFIG_BLK_DEV_SLC90E66 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
@@ -245,6 +228,7 @@
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
+# CONFIG_BLK_DEV_ATARAID_SII is not set
 
 #
 # SCSI support
@@ -325,6 +309,7 @@
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
 
 #
@@ -367,15 +352,16 @@
 # CONFIG_NET_ISA is not set
 CONFIG_NET_PCI=y
 CONFIG_PCNET32=y
+# CONFIG_AMD8111_ETH is not set
 # CONFIG_ADAPTEC_STARFIRE is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
 # CONFIG_TULIP is not set
-# CONFIG_TC35815 is not set
 # CONFIG_DE4X5 is not set
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
-CONFIG_EEPRO100=y
+# CONFIG_EEPRO100 is not set
+CONFIG_E100=y
 # CONFIG_LNE390 is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
@@ -387,11 +373,13 @@
 # CONFIG_8139TOO_PIO is not set
 # CONFIG_8139TOO_TUNE_TWISTER is not set
 # CONFIG_8139TOO_8129 is not set
-# CONFIG_8139_NEW_RX_RESET is not set
+# CONFIG_8139_OLD_RX_RESET is not set
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
+# CONFIG_SUNDANCE_MMIO is not set
 # CONFIG_TLAN is not set
+# CONFIG_TC35815 is not set
 # CONFIG_VIA_RHINE is not set
 # CONFIG_VIA_RHINE_MMIO is not set
 # CONFIG_WINBOND_840 is not set
@@ -401,12 +389,14 @@
 # Ethernet (1000 Mbit)
 #
 CONFIG_ACENIC=y
-# CONFIG_ACENIC_OMIT_TIGON_I is not set
+CONFIG_ACENIC_OMIT_TIGON_I=y
 # CONFIG_DL2K is not set
+CONFIG_E1000=y
 # CONFIG_MYRI_SBUS is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -443,11 +433,6 @@
 # CONFIG_HAMRADIO is not set
 
 #
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
-
-#
 # ISDN subsystem
 #
 # CONFIG_ISDN is not set
@@ -558,14 +543,20 @@
 # Input core support is needed for joysticks
 #
 # CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
-# CONFIG_RTC is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
@@ -590,6 +581,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BEFS_DEBUG is not set
 # CONFIG_BFS_FS is not set
 CONFIG_EXT3_FS=y
 CONFIG_JBD=y
@@ -607,9 +600,10 @@
 CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
 # CONFIG_ZISOFS is not set
-# CONFIG_MINIX_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS 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
@@ -639,6 +633,7 @@
 # CONFIG_ROOT_NFS is not set
 CONFIG_NFSD=y
 CONFIG_NFSD_V3=y
+# CONFIG_NFSD_TCP is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
@@ -654,7 +649,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -712,21 +706,29 @@
 # CONFIG_SOUND is not set
 
 #
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
 # USB support
 #
 # CONFIG_USB is not set
 
 #
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
+
+#
 # Kernel hacking
 #
 CONFIG_MAGIC_SYSRQ=y
 # CONFIG_KGDB is not set
-# CONFIG_XMON is not set
-CONFIG_KDB=y
-# CONFIG_KDB_OFF is not set
+CONFIG_XMON=y
+# CONFIG_KDB is not set
+# CONFIG_KDB is not set
 # CONFIG_KALLSYMS is not set
 CONFIG_PPCDBG=y
-
-CONFIG_DUMP=y
-CONFIG_DUMP_COMPRESS_RLE=y
-CONFIG_DUMP_COMPRESS_GZIP=y
+# CONFIG_DUMP is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/defconfig linux-2.4.21-pre6/arch/ppc64/defconfig
--- linux-2.4.20/arch/ppc64/defconfig	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/defconfig	2003-03-26 23:49:35.000000000 +0000
@@ -26,6 +26,7 @@
 # CONFIG_HMT is not set
 # CONFIG_MSCHUNKS is not set
 CONFIG_RTAS_FLASH=m
+CONFIG_SCANLOG=m
 
 #
 # Loadable module support
@@ -42,6 +43,7 @@
 # CONFIG_MCA is not set
 # CONFIG_EISA is not set
 CONFIG_PCI=y
+# CONFIG_PCMCIA is not set
 CONFIG_NET=y
 CONFIG_SYSCTL=y
 CONFIG_SYSVIPC=y
@@ -52,7 +54,6 @@
 # CONFIG_BINFMT_MISC is not set
 CONFIG_PCI_NAMES=y
 # CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
 
 #
 # Parallel port support
@@ -61,20 +62,7 @@
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_FB=y
 CONFIG_PROC_DEVICETREE=y
-
-CONFIG_CMDLINE_BOOL=n
-CONFIG_CMDLINE="console=ttyS0,9600 console=tty0 root=/dev/sda2"
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Plug and Play configuration
-#
-# CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
+# CONFIG_CMDLINE_BOOL is not set
 
 #
 # Block devices
@@ -92,6 +80,7 @@
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_STATS is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -178,15 +167,6 @@
 # CONFIG_BLK_DEV_IDEDISK is not set
 # CONFIG_IDEDISK_MULTI_MODE is not set
 # CONFIG_IDEDISK_STROKE is not set
-# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
-# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
-# CONFIG_BLK_DEV_IDEDISK_IBM is not set
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
 # CONFIG_BLK_DEV_IDECS is not set
 CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_IDETAPE is not set
@@ -200,8 +180,8 @@
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
 CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_BLK_DEV_GENERIC is not set
 # CONFIG_IDEPCI_SHARE_IRQ is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
@@ -210,28 +190,31 @@
 # CONFIG_IDEDMA_ONLYDISK is not set
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_PCI_WIP is not set
-# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set
-# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
 CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_AEC62XX is not set
-# CONFIG_AEC62XX_TUNING is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
 # CONFIG_WDC_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD74XX is not set
 # CONFIG_AMD74XX_OVERRIDE is not set
 # CONFIG_BLK_DEV_CMD64X is not set
-# CONFIG_BLK_DEV_CMD680 is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5530 is not set
 # CONFIG_BLK_DEV_HPT34X is not set
 # CONFIG_HPT34X_AUTODMA is not set
 # CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_NFORCE is not set
 # CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_PDC202XX is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
 # CONFIG_PDC202XX_BURST is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
 # CONFIG_PDC202XX_FORCE is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
 # CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
 # CONFIG_BLK_DEV_SIS5513 is not set
 # CONFIG_BLK_DEV_SLC90E66 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
@@ -245,6 +228,7 @@
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
+# CONFIG_BLK_DEV_ATARAID_SII is not set
 
 #
 # SCSI support
@@ -325,6 +309,7 @@
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
 
 #
@@ -367,15 +352,16 @@
 # CONFIG_NET_ISA is not set
 CONFIG_NET_PCI=y
 CONFIG_PCNET32=y
+# CONFIG_AMD8111_ETH is not set
 # CONFIG_ADAPTEC_STARFIRE is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
 # CONFIG_TULIP is not set
-# CONFIG_TC35815 is not set
 # CONFIG_DE4X5 is not set
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
-CONFIG_EEPRO100=y
+# CONFIG_EEPRO100 is not set
+CONFIG_E100=y
 # CONFIG_LNE390 is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
@@ -387,11 +373,13 @@
 # CONFIG_8139TOO_PIO is not set
 # CONFIG_8139TOO_TUNE_TWISTER is not set
 # CONFIG_8139TOO_8129 is not set
-# CONFIG_8139_NEW_RX_RESET is not set
+# CONFIG_8139_OLD_RX_RESET is not set
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
+# CONFIG_SUNDANCE_MMIO is not set
 # CONFIG_TLAN is not set
+# CONFIG_TC35815 is not set
 # CONFIG_VIA_RHINE is not set
 # CONFIG_VIA_RHINE_MMIO is not set
 # CONFIG_WINBOND_840 is not set
@@ -403,10 +391,12 @@
 CONFIG_ACENIC=y
 CONFIG_ACENIC_OMIT_TIGON_I=y
 # CONFIG_DL2K is not set
+CONFIG_E1000=y
 # CONFIG_MYRI_SBUS is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
@@ -443,11 +433,6 @@
 # CONFIG_HAMRADIO is not set
 
 #
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
-
-#
 # ISDN subsystem
 #
 # CONFIG_ISDN is not set
@@ -558,14 +543,20 @@
 # Input core support is needed for joysticks
 #
 # CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
-# CONFIG_RTC is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
@@ -590,6 +581,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BEFS_DEBUG is not set
 # CONFIG_BFS_FS is not set
 CONFIG_EXT3_FS=y
 CONFIG_JBD=y
@@ -607,9 +600,10 @@
 CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
 # CONFIG_ZISOFS is not set
-# CONFIG_MINIX_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS 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
@@ -639,6 +633,7 @@
 # CONFIG_ROOT_NFS is not set
 CONFIG_NFSD=y
 CONFIG_NFSD_V3=y
+# CONFIG_NFSD_TCP is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
@@ -654,7 +649,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -712,21 +706,29 @@
 # CONFIG_SOUND is not set
 
 #
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
 # USB support
 #
 # CONFIG_USB is not set
 
 #
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
+
+#
 # Kernel hacking
 #
 CONFIG_MAGIC_SYSRQ=y
 # CONFIG_KGDB is not set
-# CONFIG_XMON is not set
-CONFIG_KDB=y
-# CONFIG_KDB_OFF is not set
+CONFIG_XMON=y
+# CONFIG_KDB is not set
+# CONFIG_KDB is not set
 # CONFIG_KALLSYMS is not set
 CONFIG_PPCDBG=y
-
-CONFIG_DUMP=y
-CONFIG_DUMP_COMPRESS_RLE=y
-CONFIG_DUMP_COMPRESS_GZIP=y
+# CONFIG_DUMP is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/ItLpQueue.c linux-2.4.21-pre6/arch/ppc64/kernel/ItLpQueue.c
--- linux-2.4.20/arch/ppc64/kernel/ItLpQueue.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/ItLpQueue.c	2003-03-26 23:48:58.000000000 +0000
@@ -13,6 +13,8 @@
 #include <linux/sched.h>
 #include <asm/system.h>
 #include <asm/paca.h>
+#include <linux/random.h>
+#include <asm/time.h>
 #include <asm/iSeries/ItLpQueue.h>
 #include <asm/iSeries/HvLpEvent.h>
 #include <asm/iSeries/HvCallEvent.h>
@@ -166,5 +168,12 @@
 
 	get_paca()->lpEvent_count += numIntsProcessed;
 
+	/* Use LPEvents as a source of randomness.  Since there
+	 * Isn't an LPEvent Randomness call, pretend these are
+	 * mouse events (which is fair since we don't have mice
+	 * on the iSeries)
+	 */
+	add_mouse_randomness(get_tb());
+
 	return numIntsProcessed;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/Makefile linux-2.4.21-pre6/arch/ppc64/kernel/Makefile
--- linux-2.4.20/arch/ppc64/kernel/Makefile	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/Makefile	2003-03-26 23:49:31.000000000 +0000
@@ -42,6 +42,8 @@
 
 obj-$(CONFIG_RTAS_FLASH) += rtas_flash.o
 
+obj-$(CONFIG_SCANLOG) += scanlog.o
+
 obj-$(CONFIG_KGDB) += ppc-stub.o
 
 obj-$(CONFIG_SMP) += smp.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/bitops.c linux-2.4.21-pre6/arch/ppc64/kernel/bitops.c
--- linux-2.4.20/arch/ppc64/kernel/bitops.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/bitops.c	2003-03-26 23:49:39.000000000 +0000
@@ -39,7 +39,7 @@
  * 64 bit long layout as shown above.  Got that?  Good.
  */
 
-unsigned long find_next_zero_bit(void * addr, unsigned long size,
+unsigned long find_next_zero_bit(unsigned long* addr, unsigned long size,
 				 unsigned long offset)
 {
 	unsigned long *p = ((unsigned long *) addr) + (offset >> 6);
@@ -79,6 +79,99 @@
 	return result + ffz(tmp);
 }
 
+unsigned long find_next_bit(unsigned long *addr, unsigned long size, unsigned long offset)
+{
+        unsigned long *p = addr + (offset >> 6);
+        unsigned long result = offset & ~63UL;
+        unsigned long tmp;
+
+        if (offset >= size)
+                return size;
+        size -= result;
+        offset &= 63UL;
+        if (offset) {
+                tmp = *(p++);
+                tmp &= (~0UL << offset);
+                if (size < 64)
+                        goto found_first;
+                if (tmp)
+                        goto found_middle;
+                size -= 64;
+                result += 64;
+        }
+        while (size & ~63UL) {
+                if ((tmp = *(p++)))
+                        goto found_middle;
+                result += 64;
+                size -= 64;
+        }
+        if (!size)
+                return result;
+        tmp = *p;
+
+found_first:
+        tmp &= (~0UL >> (64 - size));
+        if (tmp == 0UL)        /* Are any bits set? */
+                return result + size; /* Nope. */
+found_middle:
+        return result + __ffs(tmp);
+}
+
+static __inline__ unsigned int ext2_ilog2(unsigned int x)
+{
+        int lz;
+
+        asm("cntlzw %0,%1" : "=r" (lz) : "r" (x));
+        return 31 - lz;
+}
+
+static __inline__ unsigned int ext2_ffz(unsigned int x)
+{
+        u32  tempRC;
+        if ((x = ~x) == 0)
+                return 32;
+        tempRC = ext2_ilog2(x & -x);
+        return tempRC;
+}
+
+unsigned long find_next_zero_le_bit(unsigned long *addr, unsigned long size, unsigned long
+ offset)
+{
+        unsigned int *p = ((unsigned int *) addr) + (offset >> 5);
+        unsigned int result = offset & ~31;
+        unsigned int tmp;
+
+        if (offset >= size)
+                return size;
+        size -= result;
+        offset &= 31;
+        if (offset) {
+                tmp = cpu_to_le32p(p++);
+                tmp |= ~0U >> (32-offset); /* bug or feature ? */
+                if (size < 32)
+                        goto found_first;
+                if (tmp != ~0)
+                        goto found_middle;
+                size -= 32;
+                result += 32;
+        }
+        while (size >= 32) {
+                if ((tmp = cpu_to_le32p(p++)) != ~0)
+                        goto found_middle;
+                result += 32;
+                size -= 32;
+        }
+        if (!size)
+                return result;
+        tmp = cpu_to_le32p(p);
+found_first:
+        tmp |= ~0 << size;
+        if (tmp == ~0)          /* Are any bits zero? */
+                return result + size; /* Nope. */
+found_middle:
+        return result + ext2_ffz(tmp);
+}
+
 void BUG_OUTLINE(char* file, unsigned line) 
 {
 	udbg_printf("BUG - kernel BUG at %s:%d! \n", __FILE__, __LINE__);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/chrp_setup.c linux-2.4.21-pre6/arch/ppc64/kernel/chrp_setup.c
--- linux-2.4.20/arch/ppc64/kernel/chrp_setup.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/chrp_setup.c	2003-03-26 23:49:50.000000000 +0000
@@ -161,11 +161,12 @@
 
 	fwnmi_init();
 
+#ifndef CONFIG_PPC_ISERIES
 	/* Find and initialize PCI host bridges */
 	/* iSeries needs to be done much later. */
- 	#ifndef CONFIG_PPC_ISERIES
-		find_and_init_phbs();
- 	#endif
+	eeh_init();
+	find_and_init_phbs();
+#endif
 
 	/* Find the Open PIC if present */
 	root = find_path_device("/");
@@ -256,7 +257,7 @@
 #endif /* CONFIG_BLK_DEV_INITRD */
 #endif
 
-	ppc_md.ppc_machine = naca->platform;
+	ppc_md.ppc_machine = systemcfg->platform;
 
 	ppc_md.setup_arch     = chrp_setup_arch;
 	ppc_md.setup_residual = NULL;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/eeh.c linux-2.4.21-pre6/arch/ppc64/kernel/eeh.c
--- linux-2.4.20/arch/ppc64/kernel/eeh.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/eeh.c	2003-03-26 23:49:30.000000000 +0000
@@ -43,25 +43,25 @@
 static int ibm_set_slot_reset;
 static int ibm_read_slot_reset_state;
 
-int eeh_implemented;
+static int eeh_implemented;
 #define EEH_MAX_OPTS 4096
 static char *eeh_opts;
 static int eeh_opts_last;
-static int eeh_check_opts_config(struct pci_dev *dev, int default_state);
 
-
-unsigned long eeh_token(unsigned long phb, unsigned long bus, unsigned long devfn, unsigned long offset)
-{
-	if (phb > 0xff)
-		panic("eeh_token: phb 0x%lx is too large\n", phb);
-	if (offset & 0x0fffffff00000000)
-		panic("eeh_token: offset 0x%lx is out of range\n", offset);
-	return ((IO_UNMAPPED_REGION_ID << 60) | (phb << 48UL) | ((bus & 0xff) << 40UL) | (devfn << 32UL) | (offset & 0xffffffff));
-}
-
-int eeh_get_state(unsigned long ea)
-{
-	return 0;
+pte_t *find_linux_pte(pgd_t *pgdir, unsigned long va);	/* from htab.c */
+static int eeh_check_opts_config(struct device_node *dn,
+				 int class_code, int vendor_id, int device_id,
+				 int default_state);
+
+unsigned long eeh_token_to_phys(unsigned long token)
+{
+	if (REGION_ID(token) == EEH_REGION_ID) {
+		unsigned long vaddr = IO_TOKEN_TO_ADDR(token);
+		pte_t *ptep = find_linux_pte(ioremap_mm.pgd, vaddr);
+		unsigned long pa = pte_pagenr(*ptep) << PAGE_SHIFT;
+		return pa | (vaddr & (PAGE_SIZE-1));
+	} else
+		return token;
 }
 
 /* Check for an eeh failure at the given token address.
@@ -73,47 +73,152 @@
  */
 unsigned long eeh_check_failure(void *token, unsigned long val)
 {
-	unsigned long config_addr = (unsigned long)token >> 24;	/* PPBBDDRR */
-	unsigned long phbidx = (config_addr >> 24) & 0xff;
-	struct pci_controller *phb;
+	unsigned long addr;
+	struct pci_dev *dev;
+	struct device_node *dn;
 	unsigned long ret, rets[2];
 
-	config_addr &= 0xffff00;  /* 00BBDD00 */
+	/* IO BAR access could get us here...or if we manually force EEH
+	 * operation on even if the hardware won't support it.
+	 */
+	if (!eeh_implemented || ibm_read_slot_reset_state == RTAS_UNKNOWN_SERVICE)
+		return val;
 
-	if (phbidx >= global_phb_number) {
-		panic("EEH: checking token %p phb index of %ld is greater than max of %d\n", token, phbidx, global_phb_number-1);
+	/* Finding the phys addr + pci device is quite expensive.
+	 * However, the RTAS call is MUCH slower.... :(
+	 */
+	addr = eeh_token_to_phys((unsigned long)token);
+	dev = pci_find_dev_by_addr(addr);
+	if (!dev) {
+		printk("EEH: no pci dev found for addr=0x%lx\n", addr);
+		return val;
+	}
+	dn = pci_device_to_OF_node(dev);
+	if (!dn) {
+		printk("EEH: no pci dn found for addr=0x%lx\n", addr);
+		return val;
 	}
-	phb = phbtab[phbidx];
 
-	ret = rtas_call(ibm_read_slot_reset_state, 3, 3, rets,
-			config_addr, BUID_HI(phb->buid), BUID_LO(phb->buid));
-	if (ret == 0 && rets[1] == 1 && rets[0] >= 2) {
-		struct pci_dev *dev;
-		int bus = ((unsigned long)token >> 40) & 0xffff; /* include PHB# in bus */
-		int devfn = (config_addr >> 8) & 0xff;
-
-		dev = pci_find_slot(bus, devfn);
-		if (dev) {
-			udbg_printf("EEH:  MMIO failure (%ld) on device:\n  %s %s\n",
-			      rets[0], dev->slot_name, dev->name);
-			printk("EEH:  MMIO failure (%ld) on device:\n  %s %s\n",
-			      rets[0], dev->slot_name, dev->name);
-			PPCDBG_ENTER_DEBUGGER();
+	/* Access to IO BARs might get this far and still not want checking. */
+	if (!(dn->eeh_mode & EEH_MODE_SUPPORTED) || dn->eeh_mode & EEH_MODE_NOCHECK)
+		return val;
+
+
+	/* Now test for an EEH failure.  This is VERY expensive.
+	 * Note that the eeh_config_addr may be a parent device
+	 * in the case of a device behind a bridge, or it may be
+	 * function zero of a multi-function device.
+	 * In any case they must share a common PHB.
+	 */
+	if (dn->eeh_config_addr) {
+		ret = rtas_call(ibm_read_slot_reset_state, 3, 3, rets,
+				dn->eeh_config_addr, BUID_HI(dn->phb->buid), BUID_LO(dn->phb->buid));
+		if (ret == 0 && rets[1] == 1 && rets[0] >= 2) {
 			panic("EEH:  MMIO failure (%ld) on device:\n  %s %s\n",
 			      rets[0], dev->slot_name, dev->name);
-		} else {
-			udbg_printf("EEH:  MMIO failure (%ld) on device buid %lx, config_addr %lx\n", rets[0], phb->buid, config_addr);
-			printk("EEH:  MMIO failure (%ld) on device buid %lx, config_addr %lx\n", rets[0], phb->buid, config_addr);
-			PPCDBG_ENTER_DEBUGGER();
-			panic("EEH:  MMIO failure (%ld) on device buid %lx, config_addr %lx\n", rets[0], phb->buid, config_addr);
 		}
 	}
 	eeh_false_positives++;
 	return val;	/* good case */
+
 }
 
+struct eeh_early_enable_info {
+	unsigned int buid_hi;
+	unsigned int buid_lo;
+	int adapters_enabled;
+};
+
+/* Enable eeh for the given device node. */
+static void *early_enable_eeh(struct device_node *dn, void *data)
+{
+	struct eeh_early_enable_info *info = data;
+	long ret;
+	char *status = get_property(dn, "status", 0);
+	u32 *class_code = (u32 *)get_property(dn, "class-code", 0);
+	u32 *vendor_id =(u32 *) get_property(dn, "vendor-id", 0);
+	u32 *device_id = (u32 *)get_property(dn, "device-id", 0);
+	u32 *regs;
+	int enable;
+
+	if (status && strcmp(status, "ok") != 0)
+		return NULL;	/* ignore devices with bad status */
+
+	/* Weed out PHBs or other bad nodes. */
+	if (!class_code || !vendor_id || !device_id)
+		return NULL;
+
+	/* Ignore known PHBs and EADs bridges */
+	if (*vendor_id == PCI_VENDOR_ID_IBM &&
+	    (*device_id == 0x0102 || *device_id == 0x008b ||
+	     *device_id == 0x0188 || *device_id == 0x0302))
+		return NULL;
+
+	/* Now decide if we are going to "Disable" EEH checking
+	 * for this device.  We still run with the EEH hardware active,
+	 * but we won't be checking for ff's.  This means a driver
+	 * could return bad data (very bad!), an interrupt handler could
+	 * hang waiting on status bits that won't change, etc.
+	 * But there are a few cases like display devices that make sense.
+	 */
+	enable = 1;	/* i.e. we will do checking */
+	if ((*class_code >> 16) == PCI_BASE_CLASS_DISPLAY)
+		enable = 0;
+
+	if (!eeh_check_opts_config(dn, *class_code, *vendor_id, *device_id, enable)) {
+		if (enable) {
+			printk(KERN_INFO "EEH: %s user requested to run without EEH.\n", dn->full_name);
+			enable = 0;
+		}
+	}
+
+	if (!enable)
+		dn->eeh_mode = EEH_MODE_NOCHECK;
+
+	/* This device may already have an EEH parent. */
+	if (dn->parent && (dn->parent->eeh_mode & EEH_MODE_SUPPORTED)) {
+		/* Parent supports EEH. */
+		dn->eeh_mode |= EEH_MODE_SUPPORTED;
+		dn->eeh_config_addr = dn->parent->eeh_config_addr;
+		return NULL;
+	}
+
+	/* Ok..see if this device supports EEH. */
+	regs = (u32 *)get_property(dn, "reg", 0);
+	if (regs) {
+		/* First register entry is addr (00BBSS00)  */
+		/* Try to enable eeh */
+		ret = rtas_call(ibm_set_eeh_option, 4, 1, NULL,
+				regs[0], info->buid_hi, info->buid_lo,
+				EEH_ENABLE);
+		if (ret == 0) {
+			info->adapters_enabled++;
+			dn->eeh_mode |= EEH_MODE_SUPPORTED;
+			dn->eeh_config_addr = regs[0];
+		}
+	}
+	return NULL; 
+}
+
+/*
+ * Initialize eeh by trying to enable it for all of the adapters in the system.
+ * As a side effect we can determine here if eeh is supported at all.
+ * Note that we leave EEH on so failed config cycles won't cause a machine
+ * check.  If a user turns off EEH for a particular adapter they are really
+ * telling Linux to ignore errors.
+ *
+ * We should probably distinguish between "ignore errors" and "turn EEH off"
+ * but for now disabling EEH for adapters is mostly to work around drivers that
+ * directly access mmio space (without using the macros).
+ *
+ * The eeh-force-off/on option does literally what it says, so if Linux must
+ * avoid enabling EEH this must be done.
+ */
 void eeh_init(void)
 {
+	struct device_node *phb;
+	struct eeh_early_enable_info info;
+
 	extern char cmd_line[];	/* Very early cmd line parse.  Cheap, but works. */
 	char *eeh_force_off = strstr(cmd_line, "eeh-force-off");
 	char *eeh_force_on = strstr(cmd_line, "eeh-force-on");
@@ -121,64 +226,51 @@
 	ibm_set_eeh_option = rtas_token("ibm,set-eeh-option");
 	ibm_set_slot_reset = rtas_token("ibm,set-slot-reset");
 	ibm_read_slot_reset_state = rtas_token("ibm,read-slot-reset-state");
-	if (ibm_set_eeh_option != RTAS_UNKNOWN_SERVICE && naca->platform == PLATFORM_PSERIES_LPAR)
+
+	/* Allow user to force eeh mode on or off -- even if the hardware
+	 * doesn't exist.  This allows driver writers to at least test use
+	 * of I/O macros even if we can't actually test for EEH failure.
+	 */
+	if (eeh_force_on > eeh_force_off)
 		eeh_implemented = 1;
+	else if (ibm_set_eeh_option == RTAS_UNKNOWN_SERVICE)
+		return;
 
 	if (eeh_force_off > eeh_force_on) {
 		/* User is forcing EEH off.  Be noisy if it is implemented. */
 		if (eeh_implemented)
-			printk("EEH: WARNING: PCI Enhanced I/O Error Handling is user disabled\n");
+			printk(KERN_WARNING "EEH: WARNING: PCI Enhanced I/O Error Handling is user disabled\n");
 		eeh_implemented = 0;
 		return;
 	}
 
-	if (eeh_force_on > eeh_force_off)
-		eeh_implemented = 1;	/* User is forcing it on. */
 
-	if (eeh_implemented)
-		printk("EEH: PCI Enhanced I/O Error Handling Enabled\n");
+	/* Enable EEH for all adapters.  Note that eeh requires buid's */
+	info.adapters_enabled = 0;
+	for (phb = find_devices("pci"); phb; phb = phb->next) {
+		int len;
+		int *buid_vals = (int *) get_property(phb, "ibm,fw-phb-id", &len);
+		if (!buid_vals)
+			continue;
+		if (len == sizeof(int)) {
+			info.buid_lo = buid_vals[0];
+			info.buid_hi = 0;
+		} else if (len == sizeof(int)*2) {
+			info.buid_hi = buid_vals[0];
+			info.buid_lo = buid_vals[1];
+		} else {
+			printk("EEH: odd ibm,fw-phb-id len returned: %d\n", len);
+			continue;
+		}
+		traverse_pci_devices(phb, early_enable_eeh, NULL, &info);
+	}
+	if (info.adapters_enabled) {
+		printk(KERN_INFO "EEH: PCI Enhanced I/O Error Handling Enabled\n");
+		eeh_implemented = 1;
+	}
 }
 
 
-/* Given a PCI device check if eeh should be configured or not.
- * This may look at firmware properties and/or kernel cmdline options.
- */
-int is_eeh_configured(struct pci_dev *dev)
-{
-	struct device_node *dn = pci_device_to_OF_node(dev);
-	struct pci_controller *phb = PCI_GET_PHB_PTR(dev);
-	unsigned long ret, rets[2];
-	int eeh_capable;
-	int default_state = 1;	/* default enable EEH if we can. */
-
-	if (dn == NULL || phb == NULL || !eeh_implemented)
-		return 0;
-
-	/* Hack: turn off eeh for display class devices by default.
-	 * This fixes matrox accel framebuffer.
-	 */
-	if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY)
-		default_state = 0;
-
-	/* Ignore known PHBs and EADs bridges */
-	if (dev->vendor == PCI_VENDOR_ID_IBM &&
-	    (dev->device == 0x0102 || dev->device == 0x008b))
-		default_state = 0;
-
-	if (!eeh_check_opts_config(dev, default_state)) {
-		if (default_state)
-			printk("EEH: %s %s user requested to run without EEH.\n", dev->slot_name, dev->name);
-		return 0;
-	}
-
-	ret = rtas_call(ibm_read_slot_reset_state, 3, 3, rets,
-			CONFIG_ADDR(dn->busno, dn->devfn),
-			BUID_HI(phb->buid), BUID_LO(phb->buid));
-	eeh_capable = (ret == 0 && rets[1] == 1);
-	printk("EEH: %s %s is%s EEH capable.\n", dev->slot_name, dev->name, eeh_capable ? "" : " not");
-	return eeh_capable;
-}
-
 int eeh_set_option(struct pci_dev *dev, int option)
 {
 	struct device_node *dn = pci_device_to_OF_node(dev);
@@ -193,6 +285,30 @@
 }
 
 
+/* If EEH is implemented, find the PCI device using given phys addr
+ * and check to see if eeh failure checking is disabled.
+ * Remap the addr (trivially) to the EEH region if not.
+ * For addresses not known to PCI the vaddr is simply returned unchanged.
+ */
+void *eeh_ioremap(unsigned long addr, void *vaddr)
+{
+	struct pci_dev *dev;
+	struct device_node *dn;
+
+	if (!eeh_implemented)
+		return vaddr;
+	dev = pci_find_dev_by_addr(addr);
+	if (!dev)
+		return vaddr;
+	dn = pci_device_to_OF_node(dev);
+	if (!dn)
+		return vaddr;
+	if (dn->eeh_mode & EEH_MODE_NOCHECK)
+		return vaddr;
+
+	return (void *)IO_ADDR_TO_TOKEN(vaddr);
+}
+
 static int eeh_proc_falsepositive_read(char *page, char **start, off_t off,
 			 int count, int *eof, void *data)
 {
@@ -223,28 +339,24 @@
  * This lets the user specify stupid combinations of options,
  * but at least the result should be very predictable.
  */
-static int eeh_check_opts_config(struct pci_dev *dev, int default_state)
+static int eeh_check_opts_config(struct device_node *dn,
+				 int class_code, int vendor_id, int device_id,
+				 int default_state)
 {
-	struct device_node *dn = pci_device_to_OF_node(dev);
-	struct pci_controller *phb = PCI_GET_PHB_PTR(dev);
-	char devname[32], classname[32], phbname[32];
+	char devname[32], classname[32];
 	char *strs[8], *s;
 	int nstrs, i;
 	int ret = default_state;
 
-	if (dn == NULL || phb == NULL)
-		return 0;
 	/* Build list of strings to match */
 	nstrs = 0;
 	s = (char *)get_property(dn, "ibm,loc-code", 0);
 	if (s)
 		strs[nstrs++] = s;
-	sprintf(devname, "dev%04x:%04x", dev->vendor, dev->device);
+	sprintf(devname, "dev%04x:%04x", vendor_id, device_id);
 	strs[nstrs++] = devname;
-	sprintf(classname, "class%04x", dev->class);
+	sprintf(classname, "class%04x", class_code);
 	strs[nstrs++] = classname;
-	sprintf(phbname, "pci@%lx", phb->buid);
-	strs[nstrs++] = phbname;
 	strs[nstrs++] = "";	/* yes, this matches the empty string */
 
 	/* Now see if any string matches the eeh_opts list.
@@ -276,7 +388,6 @@
  *
  *	dev#:#    vendor:device id in hex (e.g. dev1022:2000)
  *	class#    class id in hex (e.g. class0200)
- *	pci@buid  all devices under phb (e.g. pci@fef00000)
  *
  * If no location code is specified all devices are assumed
  * so eeh-off means eeh by default is off.
@@ -284,13 +395,11 @@
 
 /* This is implemented as a null separated list of strings.
  * Each string looks like this:  "+X" or "-X"
- * where X is a loc code, dev, class or pci string (as shown above)
+ * where X is a loc code, vendor:device, class (as shown above)
  * or empty which is used to indicate all.
  *
- * We interpret this option string list during the buswalk
- * so that it will literally behave left-to-right even if
- * some combinations don't make sense.  Give the user exactly
- * what they want! :)
+ * We interpret this option string list so that it will literally
+ * behave left-to-right even if some combinations don't make sense.
  */
 
 static int __init eeh_parm(char *str, int state)
@@ -318,7 +427,7 @@
 		if (*cur) {
 			int curlen = curend-cur;
 			if (eeh_opts_last + curlen > EEH_MAX_OPTS-2) {
-				printk("EEH: sorry...too many eeh cmd line options\n");
+				printk(KERN_INFO "EEH: sorry...too many eeh cmd line options\n");
 				return 1;
 			}
 			eeh_opts[eeh_opts_last++] = state ? '+' : '-';
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/entry.S linux-2.4.21-pre6/arch/ppc64/kernel/entry.S
--- linux-2.4.20/arch/ppc64/kernel/entry.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/entry.S	2003-03-26 23:49:07.000000000 +0000
@@ -52,12 +52,12 @@
 	andc	r11,r11,r10
 	std	r11,_CCR(r1)
 #ifdef SHOW_SYSCALLS
-#ifdef SHOW_SYSCALLS_TASK
+# ifdef SHOW_SYSCALLS_TASK
 	LOADBASE(r31,show_syscalls_task)
 	ld	r31,show_syscalls_task@l(r31)
 	cmp	0,r13,r31
 	bne	1f
-#endif
+# endif /* SHOW_SYSCALLS_TASK */
 	LOADADDR(r3,7f)
 	ld	r4,GPR0(r1)
 	ld	r5,GPR3(r1)
@@ -115,16 +115,16 @@
 _GLOBAL(ret_from_syscall_1)
 20:	std	r3,RESULT(r1)	/* Save result */
 #ifdef SHOW_SYSCALLS
-#ifdef SHOW_SYSCALLS_TASK
+# ifdef SHOW_SYSCALLS_TASK
 	cmp	0,r13,r31
 	bne	91f
-#endif
+# endif /* SHOW_SYSCALLS_TASK */
 	mr	r4,r3
 	LOADADDR(r3,79f)
 	bl	.printk
 	ld	r3,RESULT(r1)
 91:
-#endif
+#endif /* SHOW_SYSCALLS */
 	li	r10,-_LAST_ERRNO
 	cmpl	0,r3,r10
 	blt	30f
@@ -177,7 +177,6 @@
 	blrl			/* Call handler */
 _GLOBAL(ret_from_syscall_2)
 58:	std	r3,RESULT(r1)	/* Save result */	
-	std	r3,GPR0(r1)	/* temporary gross hack to make strace work */
 	li	r10,-_LAST_ERRNO
 	cmpl	0,r3,r10
 	blt	60f
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/head.S linux-2.4.21-pre6/arch/ppc64/kernel/head.S
--- linux-2.4.20/arch/ppc64/kernel/head.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/head.S	2003-03-26 23:48:57.000000000 +0000
@@ -49,8 +49,9 @@
  * 0x0100 - 0x2fff : pSeries Interrupt prologs
  * 0x3000 - 0x3fff : Interrupt support
  * 0x4000 - 0x4fff : NACA
- * 0x5000 - 0x5fff : Initial segment table
+ * 0x5000 - 0x5fff : SystemCfg
  * 0x6000          : iSeries and common interrupt prologs
+ * 0x9000 - 0x9fff : Initial segment table
  */
 
 /*
@@ -80,6 +81,12 @@
 _stext:
 _STATIC(__start)
 	b .__start_initialization_pSeries
+	.long  0x0
+
+	. = 0x8
+	.globl	__zero
+__zero:
+	.llong	0
 
 	/* At offset 0x20, there is a pointer to iSeries LPAR data.
 	 * This is required by the hypervisor */
@@ -373,21 +380,14 @@
 	.llong 0x0
 	.llong paca
 
-	/*
-	 * Space for the initial segment table
-	 * For LPAR, the hypervisor must fill in at least one entry
-	 * before we get control (with relocate on)
-	 */
 	. = 0x5000
 	.globl __end_naca
-	.globl __start_stab
+	.globl __start_systemcfg
 __end_naca:
-__start_stab:
-
-
+__start_systemcfg:
 	. = 0x6000
-	.globl __end_stab
-__end_stab:
+	.globl __end_systemcfg
+__end_systemcfg:
 
 	/*
 	 * The iSeries LPAR map is at this fixed address
@@ -400,7 +400,7 @@
 
 	.llong	1		/* # ESIDs to be mapped by hypervisor         */
 	.llong	1		/* # memory ranges to be mapped by hypervisor */
-	.llong	5		/* Page # of segment table within load area   */
+	.llong	STAB0_PAGE	/* Page # of segment table within load area   */
 	.llong	0		/* Reserved */
 	.llong  0		/* Reserved */
 	.llong  0		/* Reserved */
@@ -527,6 +527,20 @@
 MachineCheck_FWNMI:
 	EXCEPTION_PROLOG_PSERIES(0x200, MachineCheck_common)
 
+	/*
+	 * Space for the initial segment table
+	 * For LPAR, the hypervisor must fill in at least one entry
+	 * before we get control (with relocate on)
+	 */
+	. = STAB0_PHYS_ADDR
+	.globl __start_stab
+__start_stab:
+
+	. = (STAB0_PHYS_ADDR + PAGE_SIZE)
+	.globl __end_stab
+__end_stab:
+
+
 /*** Common interrupt handlers ***/
 
 	STD_EXCEPTION_COMMON( 0x100, SystemReset, .SystemResetException )
@@ -801,6 +815,7 @@
 	b	fast_exception_return
 	
 _GLOBAL(PerformanceMonitorException)
+	sync
 	mfspr	r7,SPRG3
 	lbz	r8,PACAPROFMODE(r7)
 	cmpi	0,r8,PMC_STATE_PROFILE_KERN
@@ -809,6 +824,8 @@
 	beq 	6f
 	cmpi	0,r8,PMC_STATE_TRACE_USER
 	beq 	9f
+	cmpi	0,r8,PMC_STATE_TIMESLICE
+	beq 	10f
 	blr
 
 	/* PMC Profile Kernel */
@@ -879,6 +896,13 @@
 	addi	r10,r13,THREAD+THREAD_PMC1
 	addi	r7,r13,THREAD+THREAD_PMCC1
 #endif
+	b	7f
+
+	/* PMC Timeslice */
+10:	addi	r10,r7,PACAPMC1
+	addi	r7,r7,PACAPMCC1
+	b	7f
+
 	/* Accumulate counter values for kernel traces */
 7:	ld	r9,0(r7)
 	mfspr   r8,PMC1	
@@ -914,27 +938,27 @@
 	std	r9,56(r7)
 
 	/* Reset all counters for kernel traces */
-	lwz	r9,0(r10)
+	ld	r9,0(r10)
 	mtspr	PMC1,r9
-	lwz	r9,4(r10)
+	ld	r9,8(r10)
 	mtspr	PMC2,r9
-	lwz	r9,8(r10)
+	ld	r9,16(r10)
 	mtspr	PMC3,r9
-	lwz	r9,12(r10)
+	ld	r9,24(r10)
 	mtspr	PMC4,r9
-	lwz	r9,16(r10)
+	ld	r9,32(r10)
 	mtspr	PMC5,r9
-	lwz	r9,20(r10)
+	ld	r9,40(r10)
 	mtspr	PMC6,r9
-	lwz	r9,24(r10)
+	ld	r9,48(r10)
 	mtspr	PMC7,r9
-	lwz	r9,28(r10)
+	ld	r9,56(r10)
 	mtspr	PMC8,r9
-	lwz	r9,32(r10)
+	ld	r9,64(r10)
 	mtspr	MMCR0,r9
-	lwz	r9,36(r10)
+	ld	r9,72(r10)
 	mtspr	MMCR1,r9
-	lwz	r9,40(r10)
+	ld	r9,80(r10)
 	mtspr	MMCRA,r9
 	blr
 
@@ -1016,6 +1040,13 @@
 #ifdef CONFIG_XMON
 	bl	.xmon
 #endif
+#ifdef CONFIG_KDB
+	/*	    kdb(KDB_REASON_FAULT,regs->trap,regs); */
+	li      r3,1   /* reason_call, regs considered invalid*/
+	li      r4,0x200  /* trap */
+	li      r5,0      /* pointers to regs.*/
+	bl	.kdb
+#endif
 1:	b	1b
 2:
 	/* (((ea >> 28) & 0x1fff) << 15) | (ea >> 60) */
@@ -1363,14 +1394,19 @@
 	addi	r2,r2,0x4000
 	addi	r2,r2,0x4000
 
+	LOADADDR(r9,systemcfg)
+	SET_REG_TO_CONST(r4, KERNELBASE+0x5000)
+	std	r4,0(r9)		/* set the systemcfg pointer */
+
 	LOADADDR(r9,naca)
-	SET_REG_TO_CONST(r4, KERNELBASE)
-	addi	r4,r4,0x4000
+	SET_REG_TO_CONST(r4, KERNELBASE+0x4000)
 	std	r4,0(r9)		/* set the naca pointer */
 
+#if 1 /* DRENG:PPPBBB:TIA This looks like dead code to me -Peter */
 	/* Get the pointer to the segment table */
 	ld	r6,PACA(r4)             /* Get the base paca pointer       */
 	ld	r4,PACASTABVIRT(r6)
+#endif
 
 	bl      .iSeries_fixup_klimit
 
@@ -1398,13 +1434,18 @@
 	/* Relocate the TOC from a virt addr to a real addr */
 	sub	r2,r2,r3
 
+	/* setup the systemcfg pointer which is needed by prom_init       */
+	LOADADDR(r9,systemcfg)
+	sub	r9,r9,r3                /* addr of the variable systemcfg */
+	SET_REG_TO_CONST(r4, KERNELBASE+0x5000)
+	sub	r4,r4,r3
+	std	r4,0(r9)		/* set the value of systemcfg     */
+
 	/* setup the naca pointer which is needed by prom_init            */
 	LOADADDR(r9,naca)
 	sub	r9,r9,r3                /* addr of the variable naca      */
-
-	SET_REG_TO_CONST(r4, KERNELBASE)
+	SET_REG_TO_CONST(r4, KERNELBASE+0x4000)
 	sub	r4,r4,r3
-	addi	r4,r4,0x4000
 	std	r4,0(r9)		/* set the value of naca          */
 
 	/* DRENG / PPPBBB Fix the following comment!!! -Peter */
@@ -1526,11 +1567,13 @@
 copy_to_here:
 
 /*
+ * load_up_fpu(unused, unused, tsk)
  * Disable FP for the task which had the FPU previously,
  * and save its floating-point registers in its thread_struct.
  * Enables the FPU for use in the kernel on return.
  * On SMP we know the fpu is free, since we give it up every
- * switch.  -- Cort
+ * switch (ie, no lazy save of the FP registers).
+ * On entry: r13 == 'current' && last_task_used_math != 'current'
  */
 _STATIC(load_up_fpu)
 	mfmsr	r5                      /* grab the current MSR */
@@ -1548,26 +1591,30 @@
 	ld	r4,last_task_used_math@l(r3)
 	cmpi	0,r4,0
 	beq	1f
-	addi	r4,r4,THREAD	       /* want THREAD of last_task_used_math */
+	/* Save FP state to last_task_used_math's THREAD struct */
+	addi	r4,r4,THREAD
 	SAVE_32FPRS(0, r4)
 	mffs	fr0
-	stfd	fr0,THREAD_FPSCR-4(r4)
+	stfd	fr0,THREAD_FPSCR(r4)
+	/* Disable FP for last_task_used_math */
 	ld	r5,PT_REGS(r4)
 	ld	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
 	li	r20,MSR_FP|MSR_FE0|MSR_FE1
-	andc	r4,r4,r20		/* disable FP for previous task */
+	andc	r4,r4,r20
 	std	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
 1:
 #endif /* CONFIG_SMP */
 	/* enable use of FP after return */
-	ori	r23,r23,MSR_FP|MSR_FE0|MSR_FE1
-	addi	r5,r13,THREAD		/* Get THREAD */
-	lfd	fr0,THREAD_FPSCR-4(r5)
+	addi	r5,r13,THREAD
+	ld	r4,THREAD_FPEXC_MODE(r5)
+	ori	r23,r23,MSR_FP
+	or	r23,r23,r4
+	lfd	fr0,THREAD_FPSCR(r5)
 	mtfsf	0xff,fr0
 	REST_32FPRS(0, r5)
 #ifndef CONFIG_SMP
-	subi	r4,r5,THREAD		/* Back to 'current' */
-	std	r4,last_task_used_math@l(r3)
+	/* Update last_task_used_math to 'current' */
+	std	r13,last_task_used_math@l(r3)
 #endif /* CONFIG_SMP */
 	/* restore registers and return */
 	b	fast_exception_return
@@ -1606,7 +1653,12 @@
 	cmpi	0,r5,0
 	SAVE_32FPRS(0, r3)
 	mffs	fr0
-	stfd	fr0,THREAD_FPSCR-4(r3)
+	stfd	fr0,THREAD_FPSCR(r3)
+#if 0 /* PPPBBB: enable code below if we run with FE0/1 = 0,0 as default */
+	clrrdi	r4,r13,60		/* r4 <- 0xC000000000000000 */
+	lfd	fr0,__zero@l(r4)
+	mtfsf	0xff,fr0
+#endif
 	beq	1f
 	ld	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
 	li	r3,MSR_FP|MSR_FE0|MSR_FE1
@@ -1677,8 +1729,8 @@
 	sc				/* HvCall_setASR */
 #else
 	/* set the ASR */
-	addi	r3,0,0x4000     /* r3 = ptr to naca */
-	lhz   	r3,PLATFORM(r3) /* r3 = platform flags */
+	li	r3,0x5000	/* r3 = ptr to systemcfg  */
+	lwz   	r3,PLATFORM(r3) /* r3 = platform flags */
 	cmpldi 	r3,PLATFORM_PSERIES_LPAR
 	bne   	98f
 	mfspr	r3,PVR
@@ -1753,6 +1805,12 @@
 	bl	.reloc_offset
 	mr	r26,r3
 
+	/* setup the systemcfg pointer which is needed by *tab_initialize  */
+	LOADADDR(r6,systemcfg)
+	sub	r6,r6,r26                /* addr of the variable systemcfg */
+	li	r27,0x5000
+	std	r27,0(r6)	 	 /* set the value of systemcfg     */
+
 	/* setup the naca pointer which is needed by *tab_initialize       */
 	LOADADDR(r6,naca)
 	sub	r6,r6,r26                /* addr of the variable naca      */
@@ -1819,8 +1877,8 @@
 	ori	r4,r3,1			/* turn on valid bit                */
 
 	/* set the ASR */
-	addi	r3,0,0x4000     /* r3 = ptr to naca */
-	lhz   	r3,PLATFORM(r3) /* r3 = platform flags */
+	li	r3,0x5000	/* r3 = ptr to systemcfg */
+	lwz   	r3,PLATFORM(r3) /* r3 = platform flags */
 	cmpldi 	r3,PLATFORM_PSERIES_LPAR
 	bne   	98f
 	mfspr	r3,PVR
@@ -1840,8 +1898,8 @@
 	bl	.stab_initialize
 	bl	.htab_initialize
 
-	addi  r3,0,0x4000     /* r3 = ptr to naca */
-	lhz   r3,PLATFORM(r3) /* r3 = platform flags */
+	li	r3,0x5000	/* r3 = ptr to systemcfg */
+	lwz	r3,PLATFORM(r3) /* r3 = platform flags */
 	cmpldi r3,PLATFORM_PSERIES
 	bne    98f
 	LOADADDR(r6,_SDR1)		/* Only if NOT LPAR */
@@ -1891,11 +1949,14 @@
 	addi    r2,r2,0x4000
 	addi    r2,r2,0x4000
 
+	/* setup the systemcfg pointer                                       */
+	LOADADDR(r9,systemcfg)
+	SET_REG_TO_CONST(r8, KERNELBASE+0x5000)
+	std	r8,0(r9)
+
 	/* setup the naca pointer                                         */
 	LOADADDR(r9,naca)
-
-	SET_REG_TO_CONST(r8, KERNELBASE)
-	addi	r8,r8,0x4000
+	SET_REG_TO_CONST(r8, KERNELBASE+0x4000)
 	std	r8,0(r9)		/* set the value of the naca ptr  */
 
 	LOADADDR(r4,naca)               /* Get naca ptr address           */
@@ -2046,7 +2107,7 @@
 hardware_int_paca0:
 	.space	8*4096
 
-/* 1 page segment table per cpu (max 48, cpu0 allocated at 0x5000) */
+/* 1 page segment table per cpu (max 48, cpu0 allocated at STAB0_PHYS_ADDR) */
 	.globl	stab_array
 stab_array:
         .space	4096 * (48 - 1)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/htab.c linux-2.4.21-pre6/arch/ppc64/kernel/htab.c
--- linux-2.4.20/arch/ppc64/kernel/htab.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/htab.c	2003-03-26 23:49:50.000000000 +0000
@@ -73,10 +73,17 @@
 static long hpte_remove(unsigned long hpte_group);
 static long rpa_lpar_hpte_remove(unsigned long hpte_group);
 static long iSeries_hpte_remove(unsigned long hpte_group);
+inline unsigned long get_lock_slot(unsigned long vpn);
 
 static spinlock_t pSeries_tlbie_lock = SPIN_LOCK_UNLOCKED;
 static spinlock_t pSeries_lpar_tlbie_lock = SPIN_LOCK_UNLOCKED;
-spinlock_t hash_table_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
+
+#define LOCK_SPLIT
+#ifdef LOCK_SPLIT
+hash_table_lock_t hash_table_lock[128] __cacheline_aligned_in_smp = { [0 ... 31] = {SPIN_LOCK_UNLOCKED}};
+#else
+hash_table_lock_t hash_table_lock[1] __cacheline_aligned_in_smp = { [0] = {SPIN_LOCK_UNLOCKED}};
+#endif
 
 #define KB (1024)
 #define MB (1024*KB)
@@ -115,7 +122,7 @@
 {
 	unsigned long table, htab_size_bytes;
 	unsigned long pteg_count;
-	unsigned long mode_rw, mask;
+	unsigned long mode_rw, mask, lock_shift;
 
 #if 0
 	/* Can't really do the call below since it calls the normal RTAS
@@ -141,7 +148,15 @@
 	htab_data.htab_num_ptegs = pteg_count;
 	htab_data.htab_hash_mask = pteg_count - 1;
 
-	if(naca->platform == PLATFORM_PSERIES) {
+	/* 
+	 * Calculate the number of bits to shift the pteg selector such that we
+	 * use the high order 8 bits to select a page table lock.
+	 */
+	asm ("cntlzd %0,%1" : "=r" (lock_shift) : 
+	     "r" (htab_data.htab_hash_mask));
+	htab_data.htab_lock_shift = (64 - lock_shift) - 8;
+
+	if(systemcfg->platform == PLATFORM_PSERIES) {
 		/* Find storage for the HPT.  Must be contiguous in
 		 * the absolute address space.
 		 */
@@ -167,16 +182,16 @@
 	mask = pteg_count-1;
 
 	/* XXX we currently map kernel text rw, should fix this */
-	if ((naca->platform & PLATFORM_PSERIES) &&
-	   cpu_has_largepage() && (naca->physicalMemorySize > 256*MB)) {
+	if ((systemcfg->platform & PLATFORM_PSERIES) &&
+	   cpu_has_largepage() && (systemcfg->physicalMemorySize > 256*MB)) {
 		create_pte_mapping((unsigned long)KERNELBASE, 
 				   KERNELBASE + 256*MB, mode_rw, mask, 0);
 		create_pte_mapping((unsigned long)KERNELBASE + 256*MB, 
-				   KERNELBASE + (naca->physicalMemorySize), 
+				   KERNELBASE + (systemcfg->physicalMemorySize), 
 				   mode_rw, mask, 1);
 	} else {
 		create_pte_mapping((unsigned long)KERNELBASE, 
-				   KERNELBASE+(naca->physicalMemorySize), 
+				   KERNELBASE+(systemcfg->physicalMemorySize), 
 				   mode_rw, mask, 0);
 	}
 #if 0
@@ -220,7 +235,7 @@
 	}
 	local_hpte.dw0.dw0.v = 1;
 
-	if (naca->platform == PLATFORM_PSERIES) {
+	if (systemcfg->platform == PLATFORM_PSERIES) {
 		hptep  = htab + ((hash & hash_mask)*HPTES_PER_GROUP);
 
 		for (i = 0; i < 8; ++i, ++hptep) {
@@ -229,7 +244,7 @@
 				return;
 			}
 		}
-	} else if (naca->platform == PLATFORM_PSERIES_LPAR) {
+	} else if (systemcfg->platform == PLATFORM_PSERIES_LPAR) {
 		slot = ((hash & hash_mask)*HPTES_PER_GROUP);
 		
 		/* Set CEC cookie to 0                   */
@@ -242,12 +257,8 @@
 		lpar_rc =  plpar_pte_enter(flags, slot, local_hpte.dw0.dword0,
 					   local_hpte.dw1.dword1, 
 					   &dummy1, &dummy2);
-		if (lpar_rc != H_Success) {
-			ppc64_terminate_msg(0x21, "hpte enter");
-			loop_forever();
-		}
 		return;
-	} else if (naca->platform == PLATFORM_ISERIES_LPAR) {
+	} else if (systemcfg->platform == PLATFORM_ISERIES_LPAR) {
 		slot = HvCallHpt_findValid(&rhpte, vpn);
 		if (slot < 0) {
 			/* Must find space in primary group */
@@ -305,18 +316,19 @@
 {
 	unsigned long va, vpn;
 	unsigned long newpp, prpn;
-	unsigned long hpteflags;
+	unsigned long hpteflags, lock_slot;
 	long slot;
 	pte_t old_pte, new_pte;
 
 	/* Search the Linux page table for a match with va */
 	va = (vsid << 28) | (ea & 0x0fffffff);
 	vpn = va >> PAGE_SHIFT;
+	lock_slot = get_lock_slot(vpn); 
 
 	/* Acquire the hash table lock to guarantee that the linux
 	 * pte we fetch will not change
 	 */
-	spin_lock( &hash_table_lock );
+	spin_lock(&hash_table_lock[lock_slot].lock);
 	
 	/* 
 	 * Check the user's access rights to the page.  If access should be
@@ -324,7 +336,7 @@
 	 */
 	access |= _PAGE_PRESENT;
 	if (unlikely(access & ~(pte_val(*ptep)))) {
-		spin_unlock( &hash_table_lock );
+		spin_unlock(&hash_table_lock[lock_slot].lock);
 		return 1;
 	}
 
@@ -401,7 +413,7 @@
 		*ptep = new_pte;
 	}
 
-	spin_unlock(&hash_table_lock);
+	spin_unlock(&hash_table_lock[lock_slot].lock);
 
 	return 0;
 }
@@ -435,22 +447,21 @@
 		mm = &init_mm;
 		vsid = get_kernel_vsid(ea);
 		break;
-	case IO_UNMAPPED_REGION_ID:
-		udbg_printf("EEH Error ea = 0x%lx\n", ea);
-		PPCDBG_ENTER_DEBUGGER();
-		panic("EEH Error ea = 0x%lx\n", ea);
-		break;
+	case EEH_REGION_ID:
+		/*
+		 * Should only be hit if there is an access to MMIO space
+		 * which is protected by EEH.
+		 * Send the problem up to do_page_fault 
+		 */
 	case KERNEL_REGION_ID:
 		/*
-		 * As htab_initialize is now, we shouldn't ever get here since
-		 * we're bolting the entire 0xC0... region.
+		 * Should never get here - entire 0xC0... region is bolted.
+		 * Send the problem up to do_page_fault 
 		 */
-		udbg_printf("Little faulted on kernel address 0x%lx\n", ea);
-		PPCDBG_ENTER_DEBUGGER();
-		panic("Little faulted on kernel address 0x%lx\n", ea);
-		break;
 	default:
-		/* Not a valid range, send the problem up to do_page_fault */
+		/* Not a valid range
+		 * Send the problem up to do_page_fault 
+		 */
 		return 1;
 		break;
 	}
@@ -483,7 +494,7 @@
 
 void flush_hash_page(unsigned long context, unsigned long ea, pte_t *ptep)
 {
-	unsigned long vsid, vpn, va, hash, secondary, slot, flags;
+	unsigned long vsid, vpn, va, hash, secondary, slot, flags, lock_slot;
 	unsigned long large = 0, local = 0;
 	pte_t pte;
 
@@ -497,9 +508,11 @@
 		vpn = va >> LARGE_PAGE_SHIFT;
 	else
 		vpn = va >> PAGE_SHIFT;
+
+	lock_slot = get_lock_slot(vpn); 
 	hash = hpt_hash(vpn, large);
 
-	spin_lock_irqsave( &hash_table_lock, flags);
+	spin_lock_irqsave(&hash_table_lock[lock_slot].lock, flags);
 
 	pte = __pte(pte_update(ptep, _PAGE_HPTEFLAGS, 0));
 	secondary = (pte_val(pte) & _PAGE_SECONDARY) >> 15;
@@ -511,7 +524,7 @@
 		ppc_md.hpte_invalidate(slot, secondary, va, large, local);
 	}
 
-	spin_unlock_irqrestore( &hash_table_lock, flags );
+	spin_unlock_irqrestore(&hash_table_lock[lock_slot].lock, flags);
 }
 
 long plpar_pte_enter(unsigned long flags,
@@ -567,6 +580,26 @@
 }
 
 /*
+ * Calculate which hash_table_lock to use, based on the pteg being used.
+ *
+ * Given a VPN, use the high order 8 bits to select one of 2^7 locks.  The
+ * highest order bit is used to indicate primary vs. secondary group.  If the
+ * secondary is selected, complement the lock select bits.  This results in
+ * both the primary and secondary groups being covered under the same lock.
+ */
+inline unsigned long get_lock_slot(unsigned long vpn)
+{
+	unsigned long lock_slot;
+#ifdef LOCK_SPLIT
+	lock_slot = (hpt_hash(vpn,0) >> htab_data.htab_lock_shift) & 0xff;
+	if(lock_slot & 0x80) lock_slot = (~lock_slot) & 0x7f;
+#else
+	lock_slot = 0;
+#endif
+	return(lock_slot);
+}
+
+/*
  * Functions used to retrieve word 0 of a given page table entry.
  *
  * Input : slot : PTE index within the page table of the entry to retrieve 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/iSeries_VpdInfo.c linux-2.4.21-pre6/arch/ppc64/kernel/iSeries_VpdInfo.c
--- linux-2.4.20/arch/ppc64/kernel/iSeries_VpdInfo.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/iSeries_VpdInfo.c	2003-03-26 23:49:08.000000000 +0000
@@ -164,7 +164,8 @@
 	/* Parse Slot label until we find the one requrested         */
 	/*************************************************************/
 	while (SlotMapLen > 0) {
-		if (SlotMapPtr->AgentId == DevNode->AgentId ) {
+		if ((SlotMapPtr->AgentId == DevNode->AgentId) && 
+		    (SlotMapPtr->SecondaryAgentId == 0x10   ) ) {
 			/*******************************************************/
 			/* If Phb wasn't found, grab the entry first one found.*/ 
 			/*******************************************************/
@@ -300,7 +301,7 @@
 		printk("PCI: Bus VPD Buffer zero length.\n");
 		return;
 	}
-	//printk("PCI: BusVpdPtr: %p, %d\n",BusVpdPtr, BusVpdLen);
+	//printk("PCI: DevNode:0x%p BusVpdPtr:0x%p Length:%d\n",DevNode, BusVpdPtr, BusVpdLen);
 	/*************************************************************/
 	/* Make sure this is what I think it is                      */
 	/*************************************************************/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/iSeries_pci.c linux-2.4.21-pre6/arch/ppc64/kernel/iSeries_pci.c
--- linux-2.4.20/arch/ppc64/kernel/iSeries_pci.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/iSeries_pci.c	2003-03-26 23:49:07.000000000 +0000
@@ -4,7 +4,7 @@
  * Copyright (C) 2001 Allan Trautman, IBM Corporation
  *
  * iSeries specific routines for PCI.
- * /
+ * 
  * Based on code from pci.c and iSeries_pci.c 32bit
  *
  * This program is free software; you can redistribute it and/or modify
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/iSeries_setup.c linux-2.4.21-pre6/arch/ppc64/kernel/iSeries_setup.c
--- linux-2.4.20/arch/ppc64/kernel/iSeries_setup.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/iSeries_setup.c	2003-03-26 23:49:54.000000000 +0000
@@ -1,6 +1,4 @@
 /*
- * 
- *
  *    Copyright (c) 2000 Mike Corrigan <mikejc@us.ibm.com>
  *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
  *
@@ -431,7 +429,7 @@
 	u32 chunkBit;
 	u64 map;
 	struct MemoryBlock mb[32];
-	unsigned long numMemoryBlocks, curBlock;
+	unsigned long numMemoryBlocks, curBlock, lock_shift;
 
 	/* Chunk size on iSeries is 256K bytes */
 	totalChunks = (u32)HvLpConfig_getMsChunks();
@@ -492,7 +490,15 @@
 	num_ptegs = hptSizePages * (PAGE_SIZE/(sizeof(HPTE)*HPTES_PER_GROUP));
 	htab_data.htab_num_ptegs = num_ptegs;
 	htab_data.htab_hash_mask = num_ptegs - 1;
+	naca->pftSize = __ilog2(num_ptegs << 7);
 	
+	/* 
+	 * Calculate the number of bits to shift the pteg selector such that we
+	 * use the high order 8 bits to select a page table lock.
+	 */
+	asm ("cntlzd %0,%1" : "=r" (lock_shift) : "r" (htab_data.htab_hash_mask));
+	htab_data.htab_lock_shift = (64 - lock_shift) - 8;
+
 	/* The actual hashed page table is in the hypervisor, we have no direct access */
 	htab_data.htab = NULL;
 
@@ -550,15 +556,15 @@
 	 * which should be equal to 
 	 *   nextPhysChunk
 	 */
-	naca->physicalMemorySize = chunk_to_addr(nextPhysChunk);
+	systemcfg->physicalMemorySize = chunk_to_addr(nextPhysChunk);
 
 	/* Bolt kernel mappings for all of memory */
-	iSeries_bolt_kernel( 0, naca->physicalMemorySize );
+	iSeries_bolt_kernel(0, systemcfg->physicalMemorySize);
 
 	lmb_init();
-	lmb_add( 0, naca->physicalMemorySize );
+	lmb_add(0, systemcfg->physicalMemorySize);
 	lmb_analyze();	/* ?? */
-	lmb_reserve( 0, __pa(klimit));
+	lmb_reserve(0, __pa(klimit));
 
 	/* 
 	 * Hardcode to GP size.  I am not sure where to get this info. DRENG
@@ -576,26 +582,24 @@
 	unsigned i,n;
 	unsigned procIx = get_paca()->xLpPaca.xDynHvPhysicalProcIndex;
 
-	naca->iCacheL1LineSize = xIoHriProcessorVpd[procIx].xInstCacheOperandSize;
-	naca->dCacheL1LineSize = xIoHriProcessorVpd[procIx].xDataCacheOperandSize;
-	naca->iCacheL1LinesPerPage = PAGE_SIZE / naca->iCacheL1LineSize;
-	naca->dCacheL1LinesPerPage = PAGE_SIZE / naca->dCacheL1LineSize;
-	i = naca->iCacheL1LineSize;
+	systemcfg->iCacheL1Size = xIoHriProcessorVpd[procIx].xInstCacheSize * 1024;
+	systemcfg->iCacheL1LineSize = xIoHriProcessorVpd[procIx].xInstCacheOperandSize;
+	systemcfg->dCacheL1Size = xIoHriProcessorVpd[procIx].xDataL1CacheSizeKB * 1024;
+	systemcfg->dCacheL1LineSize = xIoHriProcessorVpd[procIx].xDataCacheOperandSize;
+	naca->iCacheL1LinesPerPage = PAGE_SIZE / systemcfg->iCacheL1LineSize;
+	naca->dCacheL1LinesPerPage = PAGE_SIZE / systemcfg->dCacheL1LineSize;
+
+	i = systemcfg->iCacheL1LineSize;
 	n = 0;
 	while ((i=(i/2))) ++n;
 	naca->iCacheL1LogLineSize = n;
-	i = naca->dCacheL1LineSize;
+	i = systemcfg->dCacheL1LineSize;
 	n = 0;
 	while ((i=(i/2))) ++n;
 	naca->dCacheL1LogLineSize = n;
 
-	printk( "D-cache line size = %d  (log = %d)\n",
-			(unsigned)naca->dCacheL1LineSize,
-			(unsigned)naca->dCacheL1LogLineSize );
-	printk( "I-cache line size = %d  (log = %d)\n",
-			(unsigned)naca->iCacheL1LineSize,
-			(unsigned)naca->iCacheL1LogLineSize );
-	
+	printk( "D-cache line size = %d\n", (unsigned)systemcfg->dCacheL1LineSize);
+	printk( "I-cache line size = %d\n", (unsigned)systemcfg->iCacheL1LineSize);
 }
 
 /*
@@ -637,6 +641,12 @@
 	void *	eventStack;
 	unsigned procIx = get_paca()->xLpPaca.xDynHvPhysicalProcIndex;
 
+        /* Add an eye catcher and the systemcfg layout version number */
+        strcpy(systemcfg->eye_catcher, "SYSTEMCFG:PPC64");
+        systemcfg->version.major = SYSTEMCFG_MAJOR;
+        systemcfg->version.minor = SYSTEMCFG_MINOR;
+
+
 	/* Setup the Lp Event Queue */
 
 	/* Allocate a page for the Event Stack
@@ -685,8 +695,8 @@
 	printk("Time base frequency = %lu.%02lu\n",
 			tbFreqMhz,
 			tbFreqMhzHundreths );
-	printk("Processor version = %x\n",
-			xIoHriProcessorVpd[procIx].xPVR );
+	systemcfg->processor = xIoHriProcessorVpd[procIx].xPVR;
+	printk("Processor version = %x\n", systemcfg->processor);
 
 }
 
@@ -715,9 +725,9 @@
 	seq_printf(m,"time base\t: %lu.%02luMHz\n",
 		tbFreqMhz, tbFreqMhzHundreths );
 	seq_printf(m,"i-cache\t\t: %d\n",
-		naca->iCacheL1LineSize);
+		systemcfg->iCacheL1LineSize);
 	seq_printf(m,"d-cache\t\t: %d\n",
-		naca->dCacheL1LineSize);
+		systemcfg->dCacheL1LineSize);
 
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/idle.c linux-2.4.21-pre6/arch/ppc64/kernel/idle.c
--- linux-2.4.20/arch/ppc64/kernel/idle.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/idle.c	2003-03-26 23:49:26.000000000 +0000
@@ -34,36 +34,28 @@
 #include <asm/iSeries/HvCall.h>
 #include <asm/iSeries/ItLpQueue.h>
 
-unsigned long maxYieldTime = 0;
-unsigned long minYieldTime = 0xffffffffffffffffUL;
-
 #ifdef CONFIG_PPC_ISERIES
 static void yield_shared_processor(void)
 {
 	struct paca_struct *lpaca = get_paca();
 	unsigned long tb;
-	unsigned long yieldTime;
 
 	HvCall_setEnabledInterrupts( HvCall_MaskIPI |
 				     HvCall_MaskLpEvent |
 				     HvCall_MaskLpProd |
 				     HvCall_MaskTimeout );
 
-	tb = get_tb();
-	/* Compute future tb value when yield should expire */
-	HvCall_yieldProcessor( HvCall_YieldTimed, tb+tb_ticks_per_jiffy );
-
-	yieldTime = get_tb() - tb;
-	if ( yieldTime > maxYieldTime )
-		maxYieldTime = yieldTime;
-
-	if ( yieldTime < minYieldTime )
-		minYieldTime = yieldTime;
-	
-	/* The decrementer stops during the yield.  Force a fake decrementer
-	 * here and let the timer_interrupt code sort out the actual time.
-	 */
-	lpaca->xLpPaca.xIntDword.xFields.xDecrInt = 1;
+	if ( ! ItLpQueue_isLpIntPending( paca->lpQueuePtr ) ) {
+	  tb = get_tb();
+	  /* Compute future tb value when yield should expire */
+	  HvCall_yieldProcessor( HvCall_YieldTimed, tb+tb_ticks_per_jiffy );
+	  
+	  /* The decrementer stops during the yield.  Force a fake decrementer
+	   * here and let the timer_interrupt code sort out the actual time.
+	   */
+	  lpaca->xLpPaca.xIntDword.xFields.xDecrInt = 1;
+	}
+	  
 	process_iSeries_events();
 }
 #endif /* CONFIG_PPC_ISERIES */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/ioctl32.c linux-2.4.21-pre6/arch/ppc64/kernel/ioctl32.c
--- linux-2.4.20/arch/ppc64/kernel/ioctl32.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/ioctl32.c	2003-03-26 23:49:40.000000000 +0000
@@ -838,6 +838,34 @@
 	return err ? -EFAULT : 0;
 }
 
+struct hd_big_geometry32 {
+	u8 heads;
+	u8 sectors;
+	u32 cylinders;
+	u32 start;
+};
+
+static int hdio_getgeo_big(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	struct hd_big_geometry geo;
+	int err;
+	
+	set_fs (KERNEL_DS);
+	err = sys_ioctl(fd, HDIO_GETGEO_BIG, (unsigned long)&geo);
+	set_fs (old_fs);
+	if (err)
+		return err;
+	else {
+		struct hd_big_geometry32 *user_geo = (struct hd_big_geometry32 *)arg;
+		err = __put_user (geo.heads, &(user_geo->heads));
+		err |= __put_user (geo.sectors, &(user_geo->sectors));
+		err |= __put_user (geo.cylinders, &(user_geo->cylinders));
+		err |= __put_user (geo.start, &(user_geo->start));
+	}
+	return err ? -EFAULT : 0;
+}
+
 
 static int hdio_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
@@ -3706,6 +3734,39 @@
 	return ((0 == ret) ? 0 : -EFAULT);
 }	
 
+/* Fix sizeof(sizeof()) breakage */
+#define BLKELVGET_32	_IOR(0x12,106,int)
+#define BLKELVSET_32	_IOW(0x12,107,int)
+#define BLKBSZGET_32	_IOR(0x12,112,int)
+#define BLKBSZSET_32	_IOW(0x12,113,int)
+#define BLKGETSIZE64_32	_IOR(0x12,114,int)
+
+static int do_blkelvget(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	return sys_ioctl(fd, BLKELVGET, arg);
+}
+
+static int do_blkelvset(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	return sys_ioctl(fd, BLKELVSET, arg);
+}
+
+static int do_blkbszget(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	return sys_ioctl(fd, BLKBSZGET, arg);
+}
+
+static int do_blkbszset(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	return sys_ioctl(fd, BLKBSZSET, arg);
+}
+
+static int do_blkgetsize64(unsigned int fd, unsigned int cmd,
+			   unsigned long arg)
+{
+	return sys_ioctl(fd, BLKGETSIZE64, arg);
+}
+
 struct ioctl_trans {
 	unsigned long cmd;
 	unsigned long handler;
@@ -4417,6 +4478,8 @@
 HANDLE_IOCTL(SIOCRTMSG, ret_einval),
 HANDLE_IOCTL(SIOCGSTAMP, do_siocgstamp),
 HANDLE_IOCTL(HDIO_GETGEO, hdio_getgeo),
+HANDLE_IOCTL(HDIO_GETGEO_BIG, hdio_getgeo_big),
+HANDLE_IOCTL(HDIO_GETGEO_BIG_RAW, hdio_getgeo_big),
 HANDLE_IOCTL(BLKRAGET, w_long),
 HANDLE_IOCTL(BLKGETSIZE, w_long),
 HANDLE_IOCTL(0x1260, broken_blkgetsize),
@@ -4534,6 +4597,14 @@
 HANDLE_IOCTL(USBDEVFS_REAPURB32, do_usbdevfs_reapurb),
 HANDLE_IOCTL(USBDEVFS_REAPURBNDELAY32, do_usbdevfs_reapurb),
 HANDLE_IOCTL(USBDEVFS_DISCSIGNAL32, do_usbdevfs_discsignal),
+/* take care of sizeof(sizeof()) breakage */
+/* elevator */
+HANDLE_IOCTL(BLKELVGET_32, do_blkelvget),
+HANDLE_IOCTL(BLKELVSET_32, do_blkelvset),
+/* block stuff */
+HANDLE_IOCTL(BLKBSZGET_32, do_blkbszget),
+HANDLE_IOCTL(BLKBSZSET_32, do_blkbszset),
+HANDLE_IOCTL(BLKGETSIZE64_32, do_blkgetsize64),
 };
 
 unsigned long ioctl32_hash_table[1024];
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/misc.S linux-2.4.21-pre6/arch/ppc64/kernel/misc.S
--- linux-2.4.20/arch/ppc64/kernel/misc.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/misc.S	2003-03-26 23:49:25.000000000 +0000
@@ -165,12 +165,14 @@
  */
 	LOADADDR(r10,naca)		/* Get Naca address */
 	ld	r10,0(r10)
-	lhz	r7,DCACHEL1LINESIZE(r10)	/* Get cache line size */
+	LOADADDR(r11,systemcfg)		/* Get systemcfg address */
+	ld	r11,0(r11)
+	lwz	r7,DCACHEL1LINESIZE(r11)	/* Get cache line size */
 	addi	r5,r7,-1
 	andc	r6,r3,r5		/* round low to line bdy */
 	subf	r8,r6,r4		/* compute length */
 	add	r8,r8,r5		/* ensure we get enough */
-	lhz	r9,DCACHEL1LOGLINESIZE(r10)	/* Get log-2 of cache line size */
+	lwz	r9,DCACHEL1LOGLINESIZE(r10)	/* Get log-2 of cache line size */
 	srw.	r8,r8,r9		/* compute line count */
 	beqlr				/* nothing to do? */
 	mtctr	r8
@@ -181,12 +183,12 @@
 
 /* Now invalidate the instruction cache */
 	
-	lhz	r7,ICACHEL1LINESIZE(r10)	/* Get Icache line size */
+	lwz	r7,ICACHEL1LINESIZE(r11)	/* Get Icache line size */
 	addi	r5,r7,-1
 	andc	r6,r3,r5		/* round low to line bdy */
 	subf	r8,r6,r4		/* compute length */
 	add	r8,r8,r5
-	lhz	r9,ICACHEL1LOGLINESIZE(r10)	/* Get log-2 of Icache line size */
+	lwz	r9,ICACHEL1LOGLINESIZE(r10)	/* Get log-2 of Icache line size */
 	srw.	r8,r8,r9		/* compute line count */
 	beqlr				/* nothing to do? */
 	mtctr	r8
@@ -212,12 +214,14 @@
  */
 	LOADADDR(r10,naca)		/* Get Naca address */
 	ld	r10,0(r10)
-	lhz	r7,DCACHEL1LINESIZE(r10)	/* Get dcache line size */
+	LOADADDR(r11,systemcfg)		/* Get systemcfg address */
+	ld	r11,0(r11)
+	lwz	r7,DCACHEL1LINESIZE(r11)	/* Get dcache line size */
 	addi	r5,r7,-1
 	andc	r6,r3,r5		/* round low to line bdy */
 	subf	r8,r6,r4		/* compute length */
 	add	r8,r8,r5		/* ensure we get enough */
-	lhz	r9,DCACHEL1LOGLINESIZE(r10)	/* Get log-2 of dcache line size */
+	lwz	r9,DCACHEL1LOGLINESIZE(r10)	/* Get log-2 of dcache line size */
 	srw.	r8,r8,r9		/* compute line count */
 	beqlr				/* nothing to do? */
 	mtctr	r8
@@ -244,9 +248,11 @@
 /* Flush the dcache */
 	LOADADDR(r7,naca)
 	ld	r7,0(r7)
+	LOADADDR(r8,systemcfg)			/* Get systemcfg address */
+	ld	r8,0(r8)
 	clrrdi	r3,r3,12           	    /* Page align */
-	lhz	r4,DCACHEL1LINESPERPAGE(r7)	/* Get # dcache lines per page */
-	lhz	r5,DCACHEL1LINESIZE(r7)		/* Get dcache line size */
+	lwz	r4,DCACHEL1LINESPERPAGE(r7)	/* Get # dcache lines per page */
+	lwz	r5,DCACHEL1LINESIZE(r8)		/* Get dcache line size */
 	mr	r6,r3
 	mtctr	r4
 0:	dcbst	0,r6
@@ -256,8 +262,8 @@
 
 /* Now invalidate the icache */	
 
-	lhz	r4,ICACHEL1LINESPERPAGE(r7)	/* Get # icache lines per page */
-	lhz	r5,ICACHEL1LINESIZE(r7)		/* Get icache line size */
+	lwz	r4,ICACHEL1LINESPERPAGE(r7)	/* Get # icache lines per page */
+	lwz	r5,ICACHEL1LINESIZE(r8)		/* Get icache line size */
 	mtctr	r4
 1:	icbi	0,r3
 	add	r3,r3,r5
@@ -266,24 +272,6 @@
 	blr
 	
 /*
- * Copy a whole page.  Assumes a 4096B page size.
- */
-_GLOBAL(copy_page)
-	clrrdi	r3,r3,12           	    /* Page align */
-	clrrdi	r4,r4,12           	    /* Page align */
-	li	r5,256
-	mtctr	r5
-	addi	r3,r3,-8
-	addi	r4,r4,-8
-
-1:      ld 	r6,8(r4)
-        ldu	r7,16(r4)
-	std     r6,8(r3) 
-	stdu    r7,16(r3) 
-	bdnz+	1b
-	blr  
-
-/*
  * I/O string operations
  *
  * insb(port, buf, len)
@@ -474,28 +462,28 @@
 	blr
 
 _GLOBAL(cvt_fd)
-	lfd	0,-4(r5)	/* load up fpscr value */
+	lfd	0,0(r5)		/* load up fpscr value */
 	mtfsf	0xff,0
 	lfs	0,0(r3)
 	stfd	0,0(r4)
 	mffs	0		/* save new fpscr value */
-	stfd	0,-4(r5)
+	stfd	0,0(r5)
 	blr
 
 _GLOBAL(cvt_df)
-	lfd	0,-4(r5)	/* load up fpscr value */
+	lfd	0,0(r5)		/* load up fpscr value */
 	mtfsf	0xff,0
 	lfd	0,0(r3)
 	stfs	0,0(r4)
 	mffs	0		/* save new fpscr value */
-	stfd	0,-4(r5)
+	stfd	0,0(r5)
 	blr
 
 /*
  * Create a kernel thread
- *   kernel_thread(fn, arg, flags)
+ *   arch_kernel_thread(fn, arg, flags)
  */
-_GLOBAL(kernel_thread)
+_GLOBAL(arch_kernel_thread)
 	mr	r6,r3		/* function */
 	ori	r3,r5,CLONE_VM	/* flags */
 	li	r0,__NR_clone
@@ -535,8 +523,8 @@
 	.llong .sys32_execve
 	.llong .sys_chdir
 	.llong .sys32_time
-	.llong .sys32_mknod
-	.llong .sys32_chmod		/* 15 */
+	.llong .sys_mknod
+	.llong .sys_chmod		/* 15 */
 	.llong .sys_lchown
 	.llong .sys_ni_syscall			/* old break syscall holder */
 	.llong .sys32_stat
@@ -603,7 +591,7 @@
 	.llong .sys32_settimeofday
 	.llong .sys32_getgroups	        /* 80 */
 	.llong .sys32_setgroups
-	.llong .ppc32_select
+	.llong .sys_ni_syscall		/* old select syscall */
 	.llong .sys_symlink
 	.llong .sys32_lstat
 	.llong .sys32_readlink	        /* 85 */
@@ -622,7 +610,7 @@
 	.llong .sys_ni_syscall			/* old profil syscall holder */
 	.llong .sys32_statfs
 	.llong .sys32_fstatfs	/* 100 */
-	.llong .sys32_ioperm
+	.llong .sys_ioperm
 	.llong .sys32_socketcall
 	.llong .sys32_syslog
 	.llong .sys32_setitimer
@@ -631,10 +619,10 @@
 	.llong .sys32_newlstat
 	.llong .sys32_newfstat
 	.llong .sys_uname
-	.llong .sys32_iopl		/* 110 */
+	.llong .sys_ni_syscall		/* 110 old iopl syscall */
 	.llong .sys_vhangup
 	.llong .sys_ni_syscall	/* old 'idle' syscall */
-	.llong .sys32_vm86
+	.llong .sys_ni_syscall		/* old vm86 syscall */
 	.llong .sys32_wait4
 	.llong .sys_swapoff	/* 115 */
 	.llong .sys32_sysinfo
@@ -644,7 +632,7 @@
 	.llong .sys32_clone		/* 120 */
 	.llong .sys32_setdomainname
 	.llong .ppc64_newuname
-	.llong .sys32_modify_ldt
+	.llong .sys_ni_syscall		/* old modify_ldt syscall */
 	.llong .sys32_adjtimex
 	.llong .sys_mprotect	/* 125 */
 	.llong .sys32_sigprocmask
@@ -712,8 +700,8 @@
 	.llong .sys_ni_syscall		/* streams2 */
 	.llong .sys32_vfork
 	.llong .sys32_getrlimit	        /* 190 */
-	.llong .sys_ni_syscall		/* 191 */	/* Unused */
-	.llong .sys_ni_syscall		/* 192 - reserved - mmap2 */
+	.llong .sys32_readahead
+	.llong .ppc32_mmap2
 	.llong .sys32_truncate64	/* 193 - truncate64 */
 	.llong .sys32_ftruncate64	/* 194 - ftruncate64 */
 	.llong .sys_stat64      	/* 195 - stat64 */
@@ -729,24 +717,7 @@
 	.llong .sys_madvise		/* 205 */
 	.llong .sys_mincore		/* 206 */
 	.llong .sys_gettid		/* 207 */
-#if 0 /* Reserved syscalls */
-	.llong .sys_tkill		/* 208 */
-	.llong .sys_setxattr
-	.llong .sys_lsetxattr	/* 210 */
-	.llong .sys_fsetxattr
-	.llong .sys_getxattr
-	.llong .sys_lgetxattr
-	.llong .sys_fgetxattr
-	.llong .sys_listxattr	/* 215 */
-	.llong .sys_llistxattr
-	.llong .sys_flistxattr
-	.llong .sys_removexattr
-	.llong .sys_lremovexattr
-	.llong .sys_fremovexattr	/* 220 */
-	.llong .sys_futex
-#endif
-	.llong .sys_perfmonctl   /* Put this here for now ... */
-	.rept NR_syscalls-222
+	.rept NR_syscalls-208
 		.llong .sys_ni_syscall
 	.endr
 #endif
@@ -774,7 +745,7 @@
 	.llong .sys_lseek
 	.llong .sys_getpid	/* 20 */
 	.llong .sys_mount
-	.llong .sys_oldumount
+	.llong .sys_ni_syscall		/* old umount syscall */
 	.llong .sys_setuid
 	.llong .sys_getuid
 	.llong .ppc64_sys_stime		/* 25 */
@@ -811,7 +782,7 @@
 	.llong .sys_ni_syscall			/* old mpx syscall holder */
 	.llong .sys_setpgid
 	.llong .sys_ni_syscall			/* old ulimit syscall holder */
-	.llong .sys_olduname
+	.llong .sys_ni_syscall		/* old uname syscall */
 	.llong .sys_umask		/* 60 */
 	.llong .sys_chroot
 	.llong .sys_ustat
@@ -828,20 +799,20 @@
 	.llong .sys_sigpending
 	.llong .sys_sethostname
 	.llong .sys_setrlimit	/* 75 */
-	.llong .sys_old_getrlimit
+	.llong .sys_ni_syscall		/* old getrlimit syscall */
 	.llong .sys_getrusage
 	.llong .sys_gettimeofday
 	.llong .sys_settimeofday
 	.llong .sys_getgroups	/* 80 */
 	.llong .sys_setgroups
-	.llong .sys_select
+	.llong .sys_ni_syscall		/* old select syscall */
 	.llong .sys_symlink
 	.llong .sys_lstat
 	.llong .sys_readlink	/* 85 */
 	.llong .sys_uselib
 	.llong .sys_swapon
 	.llong .sys_reboot
-	.llong .old_readdir
+	.llong .sys_ni_syscall		/* old readdir syscall */
 	.llong .sys_mmap	/* 90 */
 	.llong .sys_munmap
 	.llong .sys_truncate
@@ -862,10 +833,10 @@
 	.llong .sys_newlstat
 	.llong .sys_newfstat
 	.llong .sys_uname
-	.llong .sys_iopl		/* 110 */
+	.llong .sys_ni_syscall		/* 110 old iopl syscall */
 	.llong .sys_vhangup
 	.llong .sys_ni_syscall	/* old 'idle' syscall */
-	.llong .sys_vm86
+	.llong .sys_ni_syscall		/* old vm86 syscall */
 	.llong .sys_wait4
 	.llong .sys_swapoff	/* 115 */
 	.llong .sys_sysinfo
@@ -875,7 +846,7 @@
 	.llong .sys_clone		/* 120 */
 	.llong .sys_setdomainname
 	.llong .ppc64_newuname
-	.llong .sys_modify_ldt
+	.llong .sys_ni_syscall		/* old modify_ldt syscall */
 	.llong .sys_adjtimex
 	.llong .sys_mprotect	/* 125 */
 	.llong .sys_sigprocmask
@@ -943,7 +914,7 @@
 	.llong .sys_ni_syscall		/* streams2 */
 	.llong .sys_vfork
 	.llong .sys_getrlimit	        /* 190 */
-	.llong .sys_ni_syscall		/* 191 */	/* Unused */
+	.llong .sys_readahead
 	.llong .sys_ni_syscall		/* 192 - reserved - mmap2 */
 	.llong .sys_ni_syscall		/* 193 - reserved - truncate64 */
 	.llong .sys_ni_syscall		/* 194 - reserved - ftruncate64 */
@@ -960,23 +931,6 @@
 	.llong .sys_madvise		/* 205 */
 	.llong .sys_mincore		/* 206 */
 	.llong .sys_gettid		/* 207 */
-#if 0 /* Reserved syscalls */
-	.llong .sys_tkill		/* 208 */
-	.llong .sys_setxattr
-	.llong .sys_lsetxattr	/* 210 */
-	.llong .sys_fsetxattr
-	.llong .sys_getxattr
-	.llong .sys_lgetxattr
-	.llong .sys_fgetxattr
-	.llong .sys_listxattr	/* 215 */
-	.llong .sys_llistxattr
-	.llong .sys_flistxattr
-	.llong .sys_removexattr
-	.llong .sys_lremovexattr
-	.llong .sys_fremovexattr	/* 220 */
-	.llong .sys_futex
-#endif
-	.llong .sys_perfmonctl   /* Put this here for now ... */
-	.rept NR_syscalls-222
+	.rept NR_syscalls-208
 	.llong .sys_ni_syscall
 	.endr
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/mk_defs.c linux-2.4.21-pre6/arch/ppc64/kernel/mk_defs.c
--- linux-2.4.20/arch/ppc64/kernel/mk_defs.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/mk_defs.c	2003-03-26 23:49:55.000000000 +0000
@@ -39,7 +39,7 @@
 #include <asm/rtas.h>
 
 #define DEFINE(sym, val) \
-	        asm volatile("\n#define\t" #sym "\t%0" : : "i" (val))
+	asm volatile("\n#define\t" #sym "\t%0" : : "i" (val))
 
 int
 main(void)
@@ -50,29 +50,28 @@
 	DEFINE(TASK_STRUCT_SIZE, sizeof(struct task_struct));
 	DEFINE(KSP, offsetof(struct thread_struct, ksp));
 
-        DEFINE(PACA, offsetof(struct naca_struct, paca));
-        DEFINE(PACA_SIZE, sizeof(struct paca_struct));
-
-        DEFINE(DCACHEL1LINESIZE, offsetof(struct naca_struct, dCacheL1LineSize));
-        DEFINE(DCACHEL1LOGLINESIZE, offsetof(struct naca_struct, dCacheL1LogLineSize));
-        DEFINE(DCACHEL1LINESPERPAGE, offsetof(struct naca_struct, dCacheL1LinesPerPage));
-
-        DEFINE(ICACHEL1LINESIZE, offsetof(struct naca_struct, iCacheL1LineSize));
-        DEFINE(ICACHEL1LOGLINESIZE, offsetof(struct naca_struct, iCacheL1LogLineSize));
-        DEFINE(ICACHEL1LINESPERPAGE, offsetof(struct naca_struct, iCacheL1LinesPerPage));
+	DEFINE(PACA, offsetof(struct naca_struct, paca));
 	DEFINE(SLBSIZE, offsetof(struct naca_struct, slb_size));
-	DEFINE(PLATFORM, offsetof(struct naca_struct, platform));
-
-        DEFINE(PACAPACAINDEX, offsetof(struct paca_struct, xPacaIndex));
-        DEFINE(PACAPROCSTART, offsetof(struct paca_struct, xProcStart));
-        DEFINE(PACAKSAVE, offsetof(struct paca_struct, xKsave));
+	DEFINE(DCACHEL1LOGLINESIZE, offsetof(struct naca_struct, dCacheL1LogLineSize));
+	DEFINE(DCACHEL1LINESPERPAGE, offsetof(struct naca_struct, dCacheL1LinesPerPage));
+	DEFINE(ICACHEL1LOGLINESIZE, offsetof(struct naca_struct, iCacheL1LogLineSize));
+	DEFINE(ICACHEL1LINESPERPAGE, offsetof(struct naca_struct, iCacheL1LinesPerPage));
+
+	DEFINE(DCACHEL1LINESIZE, offsetof(struct systemcfg, dCacheL1LineSize));
+	DEFINE(ICACHEL1LINESIZE, offsetof(struct systemcfg, iCacheL1LineSize));
+	DEFINE(PLATFORM, offsetof(struct systemcfg, platform));
+
+	DEFINE(PACA_SIZE, sizeof(struct paca_struct));
+	DEFINE(PACAPACAINDEX, offsetof(struct paca_struct, xPacaIndex));
+	DEFINE(PACAPROCSTART, offsetof(struct paca_struct, xProcStart));
+	DEFINE(PACAKSAVE, offsetof(struct paca_struct, xKsave));
 	DEFINE(PACACURRENT, offsetof(struct paca_struct, xCurrent));
-        DEFINE(PACASAVEDMSR, offsetof(struct paca_struct, xSavedMsr));
-        DEFINE(PACASTABREAL, offsetof(struct paca_struct, xStab_data.real));
-        DEFINE(PACASTABVIRT, offsetof(struct paca_struct, xStab_data.virt));
+	DEFINE(PACASAVEDMSR, offsetof(struct paca_struct, xSavedMsr));
+	DEFINE(PACASTABREAL, offsetof(struct paca_struct, xStab_data.real));
+	DEFINE(PACASTABVIRT, offsetof(struct paca_struct, xStab_data.virt));
 	DEFINE(PACASTABRR, offsetof(struct paca_struct, xStab_data.next_round_robin));
-        DEFINE(PACAR1, offsetof(struct paca_struct, xR1));
-        DEFINE(PACALPQUEUE, offsetof(struct paca_struct, lpQueuePtr));
+	DEFINE(PACAR1, offsetof(struct paca_struct, xR1));
+	DEFINE(PACALPQUEUE, offsetof(struct paca_struct, lpQueuePtr));
 	DEFINE(PACATOC, offsetof(struct paca_struct, xTOC));
 	DEFINE(PACAEXCSP, offsetof(struct paca_struct, exception_sp));
 	DEFINE(PACAHRDWINTSTACK, offsetof(struct paca_struct, xHrdIntStack));
@@ -107,18 +106,18 @@
 	DEFINE(PACAPMCC8, offsetof(struct paca_struct, pmcc[7]));
 
 	DEFINE(PACALPPACA, offsetof(struct paca_struct, xLpPaca));
-        DEFINE(LPPACA, offsetof(struct paca_struct, xLpPaca));
-        DEFINE(PACAREGSAV, offsetof(struct paca_struct, xRegSav));
-        DEFINE(PACAEXC, offsetof(struct paca_struct, exception_stack));
-        DEFINE(PACAGUARD, offsetof(struct paca_struct, guard));
-        DEFINE(LPPACASRR0, offsetof(struct ItLpPaca, xSavedSrr0));
-        DEFINE(LPPACASRR1, offsetof(struct ItLpPaca, xSavedSrr1));
+	DEFINE(LPPACA, offsetof(struct paca_struct, xLpPaca));
+	DEFINE(PACAREGSAV, offsetof(struct paca_struct, xRegSav));
+	DEFINE(PACAEXC, offsetof(struct paca_struct, exception_stack));
+	DEFINE(PACAGUARD, offsetof(struct paca_struct, guard));
+	DEFINE(LPPACASRR0, offsetof(struct ItLpPaca, xSavedSrr0));
+	DEFINE(LPPACASRR1, offsetof(struct ItLpPaca, xSavedSrr1));
 	DEFINE(LPPACAANYINT, offsetof(struct ItLpPaca, xIntDword.xAnyInt));
 	DEFINE(LPPACADECRINT, offsetof(struct ItLpPaca, xIntDword.xFields.xDecrInt));
 	DEFINE(LPPACAPDCINT, offsetof(struct ItLpPaca, xIntDword.xFields.xPdcInt));
-        DEFINE(LPQCUREVENTPTR, offsetof(struct ItLpQueue, xSlicCurEventPtr));
-        DEFINE(LPQOVERFLOW, offsetof(struct ItLpQueue, xPlicOverflowIntPending));
-        DEFINE(LPEVENTFLAGS, offsetof(struct HvLpEvent, xFlags));
+	DEFINE(LPQCUREVENTPTR, offsetof(struct ItLpQueue, xSlicCurEventPtr));
+	DEFINE(LPQOVERFLOW, offsetof(struct ItLpQueue, xPlicOverflowIntPending));
+	DEFINE(LPEVENTFLAGS, offsetof(struct HvLpEvent, xFlags));
 	DEFINE(PROMENTRY, offsetof(struct prom_t, entry));
 
 	DEFINE(RTASBASE, offsetof(struct rtas_t, base));
@@ -131,18 +130,25 @@
 	DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
 	DEFINE(NEED_RESCHED, offsetof(struct task_struct, need_resched));
 	DEFINE(THREAD_FPR0, offsetof(struct thread_struct, fpr[0]));
+	DEFINE(THREAD_FPEXC_MODE, offsetof(struct thread_struct, fpexc_mode));
 	DEFINE(THREAD_FPSCR, offsetof(struct thread_struct, fpscr));
 	DEFINE(THREAD_FLAGS, offsetof(struct thread_struct, flags));
 	DEFINE(PPC_FLAG_32BIT, PPC_FLAG_32BIT);
-	/* Interrupt register frame */
+	/*
+	 * Interrupt register frame
+	 */
 	DEFINE(TASK_UNION_SIZE, sizeof(union task_union));
 	DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD);
-        /* 288 = # of volatile regs, int & fp, for leaf routines */
-        /* which do not stack a frame.  See the PPC64 ABI.       */
-        DEFINE(INT_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 288);
-	/* Create extra stack space for SRR0 and SRR1 when calling prom/rtas. */
-        DEFINE(PROM_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16 + 288);
-        DEFINE(RTAS_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16 + 288);
+	/*
+	 * 288 = # of volatile regs, int & fp, for leaf routines
+	 * which do not stack a frame.  See the PPC64 ABI.
+	 */
+	DEFINE(INT_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 288);
+	/*
+	 * Create extra stack space for SRR0 and SRR1 when calling prom/rtas.
+	 */
+	DEFINE(PROM_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16 + 288);
+	DEFINE(RTAS_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16 + 288);
 	DEFINE(GPR0, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[0]));
 	DEFINE(GPR1, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[1]));
 	DEFINE(GPR2, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[2]));
@@ -157,7 +163,8 @@
 	DEFINE(GPR21, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[21]));
 	DEFINE(GPR22, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[22]));
 	DEFINE(GPR23, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[23]));
-	/* Note: these symbols include _ because they overlap with special
+	/*
+	 * Note: these symbols include _ because they overlap with special
 	 * register names
 	 */
 	DEFINE(_NIP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, nip));
@@ -173,7 +180,9 @@
 	DEFINE(TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap));
 	DEFINE(SOFTE, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, softe));
 
-	/* These _only_ to be used with {PROM,RTAS}_FRAME_SIZE!!! */
+	/*
+	 * These _only_ to be used with {PROM,RTAS}_FRAME_SIZE!!!
+	 */
 	DEFINE(_SRR0, STACK_FRAME_OVERHEAD+sizeof(struct pt_regs));
 	DEFINE(_SRR1, STACK_FRAME_OVERHEAD+sizeof(struct pt_regs)+8);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/nvram.c linux-2.4.21-pre6/arch/ppc64/kernel/nvram.c
--- linux-2.4.20/arch/ppc64/kernel/nvram.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/nvram.c	2003-03-26 23:48:59.000000000 +0000
@@ -99,11 +99,11 @@
 }
 
 struct file_operations nvram_fops = {
-	owner:		THIS_MODULE,
-	llseek:		nvram_llseek,
-	read:		read_nvram,
-	write:		write_nvram,
-	ioctl:		nvram_ioctl,
+	.owner =	THIS_MODULE,
+	.llseek =	nvram_llseek,
+	.read =		read_nvram,
+	.write =	write_nvram,
+	.ioctl =	nvram_ioctl,
 };
 
 static struct miscdevice nvram_dev = {
@@ -126,8 +126,7 @@
 	nvram_store = rtas_token("nvram-store");
 	printk(KERN_INFO "PPC64 nvram contains %d bytes\n", rtas_nvram_size);
 
-	misc_register(&nvram_dev);
-	return 0;
+	return misc_register(&nvram_dev);
 }
 
 void __exit nvram_cleanup(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/pSeries_pci.c linux-2.4.21-pre6/arch/ppc64/kernel/pSeries_pci.c
--- linux-2.4.20/arch/ppc64/kernel/pSeries_pci.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/pSeries_pci.c	2003-03-26 23:49:19.000000000 +0000
@@ -1,7 +1,7 @@
 /*
  * pSeries_pci.c
  *
- * pSeries_pcibios_init(void)opyright (C) 2001 Dave Engebretsen, IBM Corporation
+ * Copyright (C) 2001 Dave Engebretsen, IBM Corporation
  *
  * pSeries specific routines for PCI.
  * 
@@ -39,7 +39,6 @@
 #include <asm/ppcdebug.h>
 #include <asm/naca.h>
 #include <asm/pci_dma.h>
-#include <asm/eeh.h>
 
 #include "xics.h"
 #include "open_pic.h"
@@ -78,6 +77,8 @@
 	 \
 	if (dn == NULL) { \
 		ret = -2; \
+	} else if (dn->status) { \
+		ret = -1; \
 	} else { \
 		addr = (dn->busno << 16) | (dn->devfn << 8) | offset; \
 		buid = dn->phb->buid; \
@@ -109,6 +110,8 @@
 	 \
 	if (dn == NULL) { \
 		ret = -2; \
+	} else if (dn->status) { \
+		ret = -1; \
 	} else { \
 		buid = dn->phb->buid; \
 		addr = (dn->busno << 16) | (dn->devfn << 8) | offset; \
@@ -252,8 +255,6 @@
 	ibm_read_pci_config = rtas_token("ibm,read-pci-config");
 	ibm_write_pci_config = rtas_token("ibm,write-pci-config");
 
-	eeh_init();
-
 	if (naca->interrupt_controller == IC_OPEN_PIC) {
 		opprop = (unsigned int *)get_property(find_path_device("/"),
 				"platform-open-pic", NULL);
@@ -352,24 +353,15 @@
 				res = &phb->io_resource;
 				res->name = Pci_Node->full_name;
 				res->flags = IORESOURCE_IO;
-				if (is_eeh_implemented()) {
-					if (!isa_io_base && has_isa) {
-						/* map a page for ISA ports.  Not EEH protected. */
-						isa_io_base = (unsigned long)__ioremap(phb->io_base_phys, PAGE_SIZE, _PAGE_NO_CACHE);
-					}
-					res->start = phb->io_base_virt = eeh_token(index, 0, 0, 0);
-					res->end = eeh_token(index, 0xff, 0xff, 0xffffffff);
-				} else {
-					phb->io_base_virt = ioremap(phb->io_base_phys, range.size);
-					if (!pci_io_base) {
-						pci_io_base = (unsigned long)phb->io_base_virt;
-						if (has_isa)
-							isa_io_base = pci_io_base;
-					}
-					res->start = ((((unsigned long) range.child_addr.a_mid) << 32) | (range.child_addr.a_lo));
-					res->start += (unsigned long)phb->io_base_virt;
-					res->end =   res->start + range.size - 1;
+				phb->io_base_virt = __ioremap(phb->io_base_phys, range.size, _PAGE_NO_CACHE);
+				if (!pci_io_base) {
+					pci_io_base = (unsigned long)phb->io_base_virt;
+					if (has_isa)
+						isa_io_base = pci_io_base;
 				}
+				res->start = ((((unsigned long) range.child_addr.a_mid) << 32) | (range.child_addr.a_lo));
+				res->start += (unsigned long)phb->io_base_virt - pci_io_base;
+				res->end =   res->start + range.size - 1;
 				res->parent = NULL;
 				res->sibling = NULL;
 				res->child = NULL;
@@ -393,13 +385,8 @@
 					++memno;
 					res->name = Pci_Node->full_name;
 					res->flags = IORESOURCE_MEM;
-					if (is_eeh_implemented()) {
-						res->start = eeh_token(index, 0, 0, 0);
-						res->end =   eeh_token(index, 0xff, 0xff, 0xffffffff);
-					} else {
-						res->start = range.parent_addr;
-						res->end =   range.parent_addr + range.size - 1;
-					}
+					res->start = range.parent_addr;
+					res->end =   range.parent_addr + range.size - 1;
 					res->parent = NULL;
 					res->sibling = NULL;
 					res->child = NULL;
@@ -433,6 +420,7 @@
 	struct pci_controller *phb;
 	unsigned int *ui_ptr = NULL, len;
 	struct reg_property64 reg_struct;
+	struct property *of_prop;
 	int *bus_range;
 	int *buid_vals;
 
@@ -517,7 +505,7 @@
 	        phb = pci_alloc_pci_controller("PHB SW",phb_type_speedwagon);
 		if (phb == NULL) return NULL;
 
-		if (naca->platform == PLATFORM_PSERIES) {
+		if (systemcfg->platform == PLATFORM_PSERIES) {
 			phb->cfg_addr = (volatile unsigned long *) 
 			  ioremap(reg_struct.address + 0x140, PAGE_SIZE);
 			phb->cfg_data = (char*)(phb->cfg_addr - 0x02); /* minus is correct */
@@ -545,6 +533,21 @@
 		return NULL;
 	}
 
+	/* Add a linux,phbnum property to the device tree so user code
+	 * can translate bus numbers.
+	 */
+	of_prop = (struct property *) alloc_bootmem(sizeof(struct property) +
+						    sizeof(phb->global_number));
+	if (of_prop) {
+		memset(of_prop, 0, sizeof(struct property));
+		of_prop->name = "linux,phbnum";
+		of_prop->length = sizeof(phb->global_number);
+		of_prop->value = (unsigned char *)&of_prop[1];
+		memcpy(of_prop->value, &phb->global_number,
+		       sizeof(phb->global_number));
+		prom_add_property(dev, of_prop);
+	}
+
 	bus_range = (int *) get_property(dev, "bus-range", &len);
 	if (bus_range == NULL || len < 2 * sizeof(int)) {
 		PPCDBG(PPCDBG_PHBINIT, "Can't get bus-range for %s\n", dev->full_name);
@@ -600,7 +603,6 @@
  	int i;
  	struct pci_controller *phb = PCI_GET_PHB_PTR(dev);
 	struct device_node *dn;
-	unsigned long eeh_disable_bit;
 
 	/* Add IBM loc code (slot) as a prefix to the device names for service */
 	dn = pci_device_to_OF_node(dev);
@@ -617,20 +619,6 @@
 		}
 	}
 
-	if (is_eeh_implemented()) {
-		if (is_eeh_configured(dev)) {
-			eeh_disable_bit = 0;
-			if (eeh_set_option(dev, EEH_ENABLE) != 0) {
-				printk("PCI: failed to enable EEH for %s %s\n", dev->slot_name, dev->name);
-				eeh_disable_bit = EEH_TOKEN_DISABLED;
-			}
-		} else {
-			/* Assume device is by default EEH_DISABLE'd */
-			printk("PCI: eeh NOT configured for %s %s\n", dev->slot_name, dev->name);
-			eeh_disable_bit = EEH_TOKEN_DISABLED;
-		}
-	}
-
 	PPCDBG(PPCDBG_PHBINIT, "fixup_resources:\n"); 
 	PPCDBG(PPCDBG_PHBINIT, "\tphb                 = 0x%016LX\n", phb); 
 	PPCDBG(PPCDBG_PHBINIT, "\tphb->pci_io_offset  = 0x%016LX\n", phb->pci_io_offset); 
@@ -661,19 +649,9 @@
 
 
 		if (dev->resource[i].flags & IORESOURCE_IO) {
-			if (is_eeh_implemented()) {
-				unsigned int busno = dev->bus ? dev->bus->number : 0;
-				unsigned long size = dev->resource[i].end - dev->resource[i].start;
-				unsigned long addr = (unsigned long)__ioremap(dev->resource[i].start + phb->io_base_phys, size, _PAGE_NO_CACHE);
-				if (!addr)
-					panic("fixup_resources: io ioremap failed!\n");
-				dev->resource[i].start = eeh_token(phb->global_number, busno, dev->devfn, addr) | eeh_disable_bit;
-				dev->resource[i].end = dev->resource[i].start + size;
-			} else {
-				unsigned long offset = (unsigned long)phb->io_base_virt;
-				dev->resource[i].start += offset;
-				dev->resource[i].end += offset;
-			}
+			unsigned long offset = (unsigned long)phb->io_base_virt - pci_io_base;
+			dev->resource[i].start += offset;
+			dev->resource[i].end += offset;
 			PPCDBG(PPCDBG_PHBINIT, "\t\t-> now [%lx .. %lx]\n",
 			       dev->resource[i].start, dev->resource[i].end);
 		} else if (dev->resource[i].flags & IORESOURCE_MEM) {
@@ -681,18 +659,8 @@
 				/* Bogus.  Probably an unused bridge. */
 				dev->resource[i].end = 0;
 			} else {
-				if (is_eeh_implemented()) {
-					unsigned int busno = dev->bus ? dev->bus->number : 0;
-					unsigned long size = dev->resource[i].end - dev->resource[i].start;
-					unsigned long addr = (unsigned long)__ioremap(dev->resource[i].start + phb->pci_mem_offset, size, _PAGE_NO_CACHE);
-					if (!addr)
-						panic("fixup_resources: mem ioremap failed!\n");
-					dev->resource[i].start = eeh_token(phb->global_number, busno, dev->devfn, addr) | eeh_disable_bit;
-					dev->resource[i].end = dev->resource[i].start + size;
-				} else {
-					dev->resource[i].start += phb->pci_mem_offset;
-					dev->resource[i].end += phb->pci_mem_offset;
-				}
+				dev->resource[i].start += phb->pci_mem_offset;
+				dev->resource[i].end += phb->pci_mem_offset;
 			}
 			PPCDBG(PPCDBG_PHBINIT, "\t\t-> now [%lx..%lx]\n",
 			       dev->resource[i].start, dev->resource[i].end);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/pacaData.c linux-2.4.21-pre6/arch/ppc64/kernel/pacaData.c
--- linux-2.4.20/arch/ppc64/kernel/pacaData.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/pacaData.c	2003-03-26 23:49:40.000000000 +0000
@@ -12,6 +12,8 @@
 #include <stddef.h>
 #include <linux/config.h>
 #include <linux/threads.h>
+#include <asm/page.h>
+#include <asm/mmu.h>
 #include <asm/processor.h>
 #include <asm/ptrace.h>
 
@@ -20,6 +22,7 @@
 #include <asm/paca.h>
 
 struct naca_struct *naca;
+struct systemcfg *systemcfg;
 
 /* The Paca is an array with one entry per processor.  Each contains an 
  * ItLpPaca, which contains the information shared between the 
@@ -65,9 +68,9 @@
 
 struct paca_struct paca[MAX_PACAS] __page_aligned = {
 #ifdef CONFIG_PPC_ISERIES
-	PACAINITDATA( 0, 1, &xItLpQueue, 0, 0xc000000000005000),
+	PACAINITDATA( 0, 1, &xItLpQueue, 0, STAB0_VIRT_ADDR),
 #else
-	PACAINITDATA( 0, 1, 0, 0x5000, 0xc000000000005000),
+	PACAINITDATA( 0, 1, 0, STAB0_PHYS_ADDR, STAB0_VIRT_ADDR),
 #endif
 	PACAINITDATA( 1, 0, 0, 0, 0),
 	PACAINITDATA( 2, 0, 0, 0, 0),
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/pci.c linux-2.4.21-pre6/arch/ppc64/kernel/pci.c
--- linux-2.4.20/arch/ppc64/kernel/pci.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/pci.c	2003-03-26 23:49:40.000000000 +0000
@@ -1,6 +1,4 @@
 /*
- * 
- *
  * Port for PPC64 David Engebretsen, IBM Corp.
  *   Contains common pci routines for ppc64 platform, pSeries and iSeries brands. 
  * 
@@ -33,7 +31,6 @@
 #include <asm/naca.h>
 #include <asm/pci_dma.h>
 #include <asm/machdep.h>
-#include <asm/eeh.h>
 
 #include "pci.h"
 
@@ -123,12 +120,48 @@
 }
 
 
+/* Given an mmio phys address, find a pci device that implements
+ * this address.  This is of course expensive, but only used
+ * for device initialization or error paths.
+ * For io BARs it is assumed the pci_io_base has already been added
+ * into addr.
+ *
+ * Bridges are ignored although they could be used to optimize the search.
+ */
+struct pci_dev *pci_find_dev_by_addr(unsigned long addr)
+{
+	struct pci_dev *dev;
+	int i;
+	unsigned long ioaddr;
+
+	ioaddr = (addr > _IO_BASE) ? addr - _IO_BASE : 0;
+
+	pci_for_each_dev(dev) {
+		if ((dev->class >> 8) == PCI_BASE_CLASS_BRIDGE)
+			continue;
+		for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+			unsigned long start = pci_resource_start(dev,i);
+			unsigned long end = pci_resource_end(dev,i);
+			unsigned int flags = pci_resource_flags(dev,i);
+			if (start == 0 || ~start == 0 ||
+			    end == 0 || ~end == 0)
+				continue;
+			if ((flags & IORESOURCE_IO) &&
+			    (ioaddr >= start && ioaddr <= end))
+				return dev;
+			else if ((flags & IORESOURCE_MEM) &&
+				 (addr >= start && addr <= end))
+				return dev;
+		}
+	}
+	return NULL;
+}
+
 void pcibios_fixup_pbus_ranges(struct pci_bus *pbus,
 				struct pbus_set_ranges_data *pranges)
 {
 }
 
-
 void
 pcibios_update_resource(struct pci_dev *dev, struct resource *root,
 			     struct resource *res, int resource)
@@ -182,6 +215,7 @@
 void
 pcibios_align_resource(void *data, struct resource *res, unsigned long size,
 		       unsigned long align)
+
 {
 	struct pci_dev *dev = data;
 
@@ -200,7 +234,6 @@
 	}
 }
 
-
 /*
  *  Handle resources of PCI devices.  If the world were perfect, we could
  *  just allocate all the resource regions and do nothing more.  It isn't.
@@ -409,8 +442,10 @@
                 return NULL;
         }
         memset(hose, 0, sizeof(struct pci_controller));
-        if(strlen(model) < 8) strcpy(hose->what,model);
-        else                  memcpy(hose->what,model,7);
+        if(strlen(model) < 8)
+		strcpy(hose->what,model);
+        else
+		memcpy(hose->what,model,7);
         hose->type = controller_type;
         hose->global_number = global_phb_number;
 	phbtab[global_phb_number++] = hose;
@@ -469,7 +504,7 @@
 			next_busno = hose->last_busno+1;
 	}
 	pci_bus_count = next_busno;
-		
+
 	/* Call machine dependant fixup */
 	if (ppc_md.pcibios_fixup) {
 		ppc_md.pcibios_fixup();
@@ -549,21 +584,15 @@
 				/* Transparent resource -- don't try to "fix" it. */
 				continue;
 			}
-			if (is_eeh_implemented()) {
-				if (res->flags & (IORESOURCE_IO|IORESOURCE_MEM)) {
-					res->start = eeh_token(phb->global_number, bus->number, 0, 0);
-					res->end = eeh_token(phb->global_number, bus->number, 0xff, 0xffffffff);
-				}
-			} else {
-				if (res->flags & IORESOURCE_IO) {
-					res->start += (unsigned long)phb->io_base_virt;
-					res->end += (unsigned long)phb->io_base_virt;
-				} else if (phb->pci_mem_offset
-					   && (res->flags & IORESOURCE_MEM)) {
-					if (res->start < phb->pci_mem_offset) {
-						res->start += phb->pci_mem_offset;
-						res->end += phb->pci_mem_offset;
-					}
+			if (res->flags & IORESOURCE_IO) {
+				unsigned long offset = (unsigned long)phb->io_base_virt - pci_io_base;
+				res->start += offset;
+				res->end += offset;
+			} else if (phb->pci_mem_offset
+				   && (res->flags & IORESOURCE_MEM)) {
+				if (res->start < phb->pci_mem_offset) {
+					res->start += phb->pci_mem_offset;
+					res->end += phb->pci_mem_offset;
 				}
 			}
 		}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/pci.h linux-2.4.21-pre6/arch/ppc64/kernel/pci.h
--- linux-2.4.20/arch/ppc64/kernel/pci.h	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/pci.h	2003-03-26 23:49:49.000000000 +0000
@@ -56,6 +56,7 @@
 void *traverse_pci_devices(struct device_node *start, traverse_func pre, traverse_func post, void *data);
 void *traverse_all_pci_devices(traverse_func pre);
 
+struct pci_dev *pci_find_dev_by_addr(unsigned long addr);
 void pci_devs_phb_init(void);
 void pci_fix_bus_sysdata(void);
 struct device_node *fetch_dev_dn(struct pci_dev *dev);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/pci_dma.c linux-2.4.21-pre6/arch/ppc64/kernel/pci_dma.c
--- linux-2.4.20/arch/ppc64/kernel/pci_dma.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/pci_dma.c	2003-03-26 23:49:30.000000000 +0000
@@ -146,7 +146,7 @@
 		dev = ppc64_isabridge_dev;
 	if (!dev)
 		return NULL;
-	if (naca->platform == PLATFORM_ISERIES_LPAR) {
+	if (systemcfg->platform == PLATFORM_ISERIES_LPAR) {
  		return ISERIES_DEVNODE(dev)->DevTceTable;
 	} else {
 		return PCI_GET_DN(dev)->tce_table;
@@ -735,7 +735,7 @@
 	struct pci_dev *dev;
 	struct device_node *dn, *mydn;
 
-	if (naca->platform == PLATFORM_PSERIES_LPAR) {
+	if (systemcfg->platform == PLATFORM_PSERIES_LPAR) {
 		create_tce_tables_for_busesLP(&pci_root_buses);
 	}
 	else {
@@ -776,7 +776,7 @@
  	/* - Tce Table Share between buses,                              */
  	/* - Tce Table per logical slot.                                 */
 	/*****************************************************************/
-	if(naca->platform == PLATFORM_ISERIES_LPAR) {
+	if(systemcfg->platform == PLATFORM_ISERIES_LPAR) {
 
 		struct iSeries_Device_Node* DevNode = (struct iSeries_Device_Node*)token;
 		getTceTableParmsiSeries(DevNode,newTceTable);
@@ -800,7 +800,7 @@
 
 		dn = (struct device_node *)token;
 		phb = dn->phb;
-		if (naca->platform == PLATFORM_PSERIES)
+		if (systemcfg->platform == PLATFORM_PSERIES)
 			getTceTableParmsPSeries(phb, dn, newTceTable);
 		else
 			getTceTableParmsPSeriesLP(phb, dn, newTceTable);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/pci_dn.c linux-2.4.21-pre6/arch/ppc64/kernel/pci_dn.c
--- linux-2.4.20/arch/ppc64/kernel/pci_dn.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/pci_dn.c	2003-03-26 23:48:59.000000000 +0000
@@ -50,6 +50,7 @@
 	struct pci_controller *phb = (struct pci_controller *)data;
 	u32 *regs;
 	char *device_type = get_property(dn, "device_type", 0);
+	char *status = get_property(dn, "status", 0);
 
 	dn->phb = phb;
 	if (device_type && strcmp(device_type, "pci") == 0 && get_property(dn, "class-code", 0) == 0) {
@@ -65,6 +66,11 @@
 			dn->devfn = (regs[0] >> 8) & 0xff;
 		}
 	}
+	if (status && strcmp(status, "ok") != 0) {
+		char *name = get_property(dn, "name", 0);
+		printk(KERN_ERR "PCI: %04x:%02x.%x %s (%s) has bad status from firmware! (%s)", dn->busno, PCI_SLOT(dn->devfn), PCI_FUNC(dn->devfn), name ? name : "<no name>", device_type ? device_type : "<unknown type>", status);
+		dn->status = 1;
+	}
 	return NULL;
 }
 
@@ -75,9 +81,11 @@
 static void * __init
 write_OF_bars(struct device_node *dn, void *data)
 {
+#ifdef CONFIG_PPC_PSERIES
 	int i;
 	u32 oldbar, newbar, newbartest;
 	u8  config_offset;
+#endif
 	char *name = get_property(dn, "name", 0);
 	char *device_type = get_property(dn, "device_type", 0);
 	char devname[128];
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/perfmon.c linux-2.4.21-pre6/arch/ppc64/kernel/perfmon.c
--- linux-2.4.20/arch/ppc64/kernel/perfmon.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/perfmon.c	2003-03-26 23:48:57.000000000 +0000
@@ -1,5 +1,11 @@
 /*
- * This file contains the code to configure and utilize the ppc64 pmc hardware
+ * Code to configure and utilize the ppc64 pmc hardware.  Generally, the
+ * following functions are supported:
+ *    1. Kernel profile based on decrementer ticks
+ *    2. Kernel profile based on PMC execution cycles
+ *    3. Trace based on arbitrary PMC counter
+ *    4. Timeslice data capture of arbitrary collections of PMCs
+ *
  * Copyright (C) 2002 David Engebretsen <engebret@us.ibm.com>
  */
 
@@ -14,24 +20,60 @@
 #include <asm/uaccess.h>
 #include <asm/naca.h>
 #include <asm/perfmon.h>
+#include <asm/iSeries/HvCall.h>
+#include <asm/hvcall.h>
 
 extern char _stext[], _etext[], _end[];
-struct perfmon_base_struct perfmon_base = {0, 0, 0, 0, 0, PMC_STATE_INITIAL};
+struct perfmon_base_struct perfmon_base = {0, 0, 0, 0, 0, 0, 0, PMC_STATE_INITIAL};
 
 int alloc_perf_buffer(int size);
 int free_perf_buffer(void);
 int clear_buffers(void);
 void pmc_stop(void *data);
+void pmc_clear(void *data);
 void pmc_start(void *data);
 void pmc_touch_bolted(void *data);
 void dump_pmc_struct(struct perfmon_struct *perfdata);
 void dump_hardware_pmc_struct(void *perfdata);
-int  decr_profile(struct perfmon_struct *perfdata);
+int  decr_profile(void *data);
 int  pmc_profile(struct perfmon_struct *perfdata);
 int  pmc_set_general(struct perfmon_struct *perfdata);
 int  pmc_set_user_general(struct perfmon_struct *perfdata);
 void pmc_configure(void *data);
+int pmc_timeslice_enable(struct perfmon_struct *perfdata);
+int pmc_timeslice_disable(struct perfmon_struct *perfdata);
+int pmc_timeslice_set(struct perfmon_struct *perfdata);
+void pmc_dump_timeslice(struct perfmon_struct *perfdata);
+void pmc_trace_rec_type(unsigned long type);
+void pmc_timeslice_data_collect(void *data);
+int pmc_timeslice_tick(void);
+int perfmon_buffer_ctl(void *data);
+int perfmon_dump_ctl(void *data);
+int perfmon_profile_ctl(void *data);
+int perfmon_trace_ctl(void *data);
+int perfmon_timeslice_ctl(void *data);
+
+#define PMC_MAX_CPUS     48
+#define PMC_MAX_COUNTERS 8
+#define PMC_SLICES_STAR  64
+#define PMC_SLICES_GP    28
+#define PMC_SLICES_MAX   64
+#define PMC_TICK_FACTOR  10
 
+int pmc_timeslice_enabled = 0, pmc_timeslice_top = 0;
+int pmc_tick_count[PMC_MAX_CPUS], pmc_timeslice[PMC_MAX_CPUS];
+
+unsigned long pmc_timeslice_data[PMC_SLICES_MAX*PMC_MAX_COUNTERS*PMC_MAX_CPUS];
+
+/*
+ * DRENG: todo:
+ * add api to add config entries (entry, values), and bump pmc_timeslice_top
+ *   value
+ * add api to get data from kernel (entry, values)
+ */
+unsigned long pmc_timeslice_config[PMC_SLICES_MAX * 5];
+
+static spinlock_t pmc_lock = SPIN_LOCK_UNLOCKED;
 asmlinkage int
 sys_perfmonctl (int cmd, void *data) 
 { 
@@ -42,37 +84,35 @@
 	pdata = kmalloc(sizeof(struct perfmon_struct), GFP_USER);
 	err = __copy_from_user(pdata, data, sizeof(struct perfmon_struct));
 	switch(cmd) {
-	case PMC_OP_ALLOC:
-		alloc_perf_buffer(0); 
+	case PMC_CMD_BUFFER:
+		perfmon_buffer_ctl(data); 
 		break;
-	case PMC_OP_FREE:
-		free_perf_buffer(); 
-		break;
-	case PMC_OP_CLEAR:
-		clear_buffers();
+	case PMC_CMD_DUMP:
+		perfmon_dump_ctl(data); 
 		break;
-	case PMC_OP_DUMP:
-		dump_pmc_struct(pdata);
-		copy_to_user(data, pdata, sizeof(struct perfmon_struct));
+	case PMC_CMD_DECR_PROFILE: /* NIA time sampling */
+		decr_profile(data); 
 		break;
-	case PMC_OP_DUMP_HARDWARE:
-		dump_hardware_pmc_struct(pdata);
-		smp_call_function(dump_hardware_pmc_struct, (void *)pdata, 0, 1);
+	case PMC_CMD_PROFILE:
+		perfmon_profile_ctl(pdata); 
 		break;
-	case PMC_OP_DECR_PROFILE: /* NIA time sampling */
-		decr_profile(pdata); 
+	case PMC_CMD_TRACE:
+		perfmon_trace_ctl(pdata); 
 		break;
-	case PMC_OP_PMC_PROFILE:
-		pmc_profile(pdata); 
+	case PMC_CMD_TIMESLICE:
+		perfmon_timeslice_ctl(pdata); 
 		break;
-	case PMC_OP_SET:
-		pmc_set_general(pdata); 
+#if 0
+	case PMC_OP_TIMESLICE:
+		pmc_enable_timeslice(pdata); 
 		break;
-	case PMC_OP_SET_USER:
-		pmc_set_user_general(pdata); 
+	case PMC_OP_DUMP_TIMESLICE:
+		pmc_dump_timeslice(pdata); 
+		smp_call_function(pmc_dump_timeslice, (void *)pdata, 0, 1);
 		break;
+#endif
 	default:
-		printk("Perfmon: Unknown operation\n");
+		printk("Perfmon: Unknown command\n");
 		break;
 	}
 
@@ -80,6 +120,30 @@
 	return 0;
 }
 
+int perfmon_buffer_ctl(void *data) {
+	struct perfmon_struct *pdata;
+	int err;
+
+	pdata = kmalloc(sizeof(struct perfmon_struct), GFP_USER);
+	err = __copy_from_user(pdata, data, sizeof(struct perfmon_struct));
+
+	switch(pdata->header.subcmd) {
+	case PMC_SUBCMD_BUFFER_ALLOC:
+		alloc_perf_buffer(0); 
+		break;
+	case PMC_SUBCMD_BUFFER_FREE:
+		free_perf_buffer(); 
+		break;
+	case PMC_SUBCMD_BUFFER_CLEAR:
+		clear_buffers();
+		break;
+	default:
+		return(-1); 
+	}
+
+	return(0); 
+}
+
 int alloc_perf_buffer(int size) 
 {
 	int i;
@@ -92,6 +156,9 @@
 		perfmon_base.trace_length = 1024*1024*16;
 		perfmon_base.trace_buffer = (unsigned long)btmalloc(perfmon_base.trace_length);
 
+		perfmon_base.timeslice_length = PMC_SLICES_MAX*PMC_MAX_COUNTERS*PMC_MAX_CPUS;
+		perfmon_base.timeslice_buffer = (unsigned long)pmc_timeslice_data;
+
 		if(perfmon_base.profile_buffer && perfmon_base.trace_buffer) {
 			memset((char *)perfmon_base.profile_buffer, 0, perfmon_base.profile_length);
 			printk("Profile buffer created at address 0x%lx of length 0x%lx\n",
@@ -145,6 +212,8 @@
 
 int clear_buffers() 
 {
+	int i, j;
+
 	if(perfmon_base.state == PMC_STATE_INITIAL) {
 		printk("Perfmon: clear buffer failed - no buffer was allocated.\n"); 
 		return -1;
@@ -152,17 +221,29 @@
 
 	printk("Perfmon: clear buffer\n");
 	
-	/* Stop counters on all processors -- blocking */
+	/* Stop counters on all [PMC_MAX_CPUS]processors -- blocking */
 	pmc_stop(NULL); 
 	smp_call_function(pmc_stop, (void *)NULL, 0, 1);
 	
 	/* Clear the buffers */
 	memset((char *)perfmon_base.profile_buffer, 0, perfmon_base.profile_length);
 	memset((char *)perfmon_base.trace_buffer, 0, perfmon_base.trace_length);
+	memset((char *)perfmon_base.timeslice_buffer, 0, perfmon_base.timeslice_length);
 	
 	/* Reset the trace buffer point */
 	perfmon_base.trace_end = 0;
 	
+	for (i=0; i<MAX_PACAS; ++i) {
+		for(j=0; j<8; j++) {
+			paca[i].pmcc[j] = 0;
+		}
+	}
+#if 0
+	/* Reset the timeslice data */
+	for(i=0; i<(PMC_MAX_CPUS*PMC_MAX_COUNTERS*PMC_SLICES_MAX); i++) {
+		pmc_timeslice_data[i] = 0;
+	}
+#endif
 	/* Restart counters on all processors -- blocking */
 	pmc_start(NULL); 
 	smp_call_function(pmc_start, (void *)NULL, 0, 1);
@@ -173,13 +254,22 @@
 void pmc_stop(void *data) 
 {
 	/* Freeze all counters, leave everything else alone */
-	mtspr( MMCR0, mfspr( MMCR0 ) | 0x80000000 );
+	mtspr(MMCR0, mfspr( MMCR0 ) | 0x80000000);
+}
+
+void pmc_clear(void *data) 
+{
+	mtspr(PMC1, 0); mtspr(PMC2, 0);
+	mtspr(PMC3, 0); mtspr(PMC4, 0);
+	mtspr(PMC5, 0); mtspr(PMC6, 0);
+	mtspr(PMC7, 0); mtspr(PMC8, 0);
+	mtspr(MMCR0, 0); mtspr(MMCR1, 0); mtspr(MMCRA, 0);
 }
 
 void pmc_start(void *data) 
 {
 	/* Free all counters, leave everything else alone */
-	mtspr( MMCR0, mfspr( MMCR0 ) & 0x7fffffff );
+	mtspr(MMCR0, mfspr( MMCR0 ) & 0x7fffffff);
 }
 
 void pmc_touch_bolted(void *data) 
@@ -190,6 +280,27 @@
 	touch = *((int *)(perfmon_base.profile_buffer));
 }
 
+int perfmon_dump_ctl(void *data) {
+	struct perfmon_struct *pdata;
+	int err;
+
+	pdata = kmalloc(sizeof(struct perfmon_struct), GFP_USER);
+	err = __copy_from_user(pdata, data, sizeof(struct perfmon_struct));
+
+	switch(pdata->header.subcmd) {
+	case PMC_SUBCMD_DUMP_COUNTERS:
+		dump_pmc_struct(pdata);
+		// copy_to_user(data, pdata, sizeof(struct perfmon_struct));
+		break;
+	case PMC_SUBCMD_DUMP_HARDWARE:
+		dump_hardware_pmc_struct(pdata);
+		smp_call_function(dump_hardware_pmc_struct, (void *)pdata, 0, 1);
+		break;
+	}
+
+	return(0); 
+}
+
 void dump_pmc_struct(struct perfmon_struct *perfdata) 
 {
 	unsigned int cpu = perfdata->vdata.pmc_info.cpu, i;
@@ -226,7 +337,7 @@
 	       cpu, (u32) mfspr(MMCR0),(u32) mfspr(MMCR1),(u32) mfspr(MMCRA));
 }
 
-int decr_profile(struct perfmon_struct *perfdata) 
+int decr_profile(void *data)
 {
 	int i;
 
@@ -251,12 +362,79 @@
 	return 0;
 }
 
+int perfmon_profile_ctl(void *data) {
+	struct perfmon_struct *pdata;
+	int err;
+
+	pdata = kmalloc(sizeof(struct perfmon_struct), GFP_USER);
+	err = __copy_from_user(pdata, data, sizeof(struct perfmon_struct));
+
+	switch(pdata->header.subcmd) {
+	case PMC_SUBCMD_PROFILE_CYCLE:
+		pmc_profile(pdata); 
+		break;
+	default:
+		return(-1);
+	}
+
+	return(0); 
+}
+
+int perfmon_trace_ctl(void *data) {
+	struct perfmon_struct *pdata;
+	int err;
+
+	pdata = kmalloc(sizeof(struct perfmon_struct), GFP_USER);
+	err = __copy_from_user(pdata, data, sizeof(struct perfmon_struct));
+
+	pmc_set_general(pdata); 
+
+#if 0
+        /* Reimplement at some point ... */
+	pmc_set_user_general(pdata); 
+#endif
+	return(0); 
+}
+
+int perfmon_timeslice_ctl(void *data) {
+	struct perfmon_struct *pdata;
+	int err;
+
+	pdata = kmalloc(sizeof(struct perfmon_struct), GFP_USER);
+	err = __copy_from_user(pdata, data, sizeof(struct perfmon_struct));
+
+	switch(pdata->header.subcmd) {
+	case PMC_SUBCMD_TIMESLICE_ENABLE:
+		pmc_timeslice_enable(pdata); 
+		break;
+	case PMC_SUBCMD_TIMESLICE_DISABLE:
+		pmc_timeslice_disable(pdata); 
+		break;
+	case PMC_SUBCMD_TIMESLICE_SET:
+		pmc_timeslice_set(pdata); 
+		break;
+	default:
+		return(-1);
+	}
+
+	return(0); 
+}
+/*
+ * pmc_profile
+ *
+ * Profile the kernel based on cycle counts.  This is made a special case of the more 
+ * general trace functions because it is high use.  Benefits of special casing this
+ * include a buffer of sufficient size to profile the entire kernel is available, and CPI
+ * can be collected along with the profile.
+ */
 int pmc_profile(struct perfmon_struct *perfdata) 
 {
 	struct pmc_struct *pdata = &(perfdata->vdata.pmc);
 	int i;
 
-	printk("Perfmon: NIA PMC profile and CPI\n");
+	printk("Perfmon: NIA PMC profile\n");
+
+	pmc_timeslice_disable(NULL); // fixme
 
 	if(perfmon_base.state == PMC_STATE_INITIAL) {
 		printk("Perfmon: failed - no buffer was allocated.\n"); 
@@ -272,15 +450,33 @@
 	}
 	perfmon_base.state = PMC_STATE_PROFILE_KERN; 
 
-	pdata->pmc[0] = 0x7f000000;
-	for(i = 1; i < 8; i++) 
-		pdata->pmc[i] = 0x0;
-	pdata->pmc[8] = 0x26000000 | (0x01 << (31 - 25) | (0x1));
-	pdata->pmc[9] = (0x3 << (31-4)); /* Instr completed */
-	pdata->pmc[10] = 0x00000000 | (0x1 << (31 - 30));
+	if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p)) {
+		for(i = 0; i < 8; i++) 
+			pdata->pmc[i] = 0x0;
+		pdata->pmc[1] = 0x7f000000;
+		/* Freeze in problem state, exception enable, freeze on event, */
+		/*   enable counter negative condition, PMC1, PMC2             */
+		pdata->pmc[8] = 0x2600cd0e;
+		pdata->pmc[9] = 0x4a5675ac;
+
+		/* Freeze while in wait state */
+		pdata->pmc[10] = 0x00022002;
+	} else {
+		pdata->pmc[0] = 0x7f000000;
+		for(i = 1; i < 8; i++) 
+			pdata->pmc[i] = 0x0;
+		pdata->pmc[8] = 0x26000000 | (0x01 << (31 - 25) | (0x1));
+		pdata->pmc[9] = (0x3 << (31-4)); /* Instr completed */
+
+		/* Freeze while in wait state */
+		pdata->pmc[10] = 0x00000000 | (0x1 << (31 - 30));
+	}
+
+	pmc_configure_hardware();
 
 	mb();
 
+	pmc_trace_rec_type(perfdata->header.vdata.type);
 	pmc_configure((void *)perfdata);
 	smp_call_function(pmc_configure, (void *)perfdata, 0, 0);
 
@@ -308,6 +504,7 @@
 	perfmon_base.state = PMC_STATE_TRACE_KERN; 
 	mb();
 
+	pmc_trace_rec_type(perfdata->header.vdata.type);
 	pmc_configure((void *)perfdata);
 	smp_call_function(pmc_configure, (void *)perfdata, 0, 0);
 
@@ -316,8 +513,10 @@
 
 int pmc_set_user_general(struct perfmon_struct *perfdata) 
 {
+#if 0
 	struct pmc_struct *pdata = &(perfdata->vdata.pmc);
-	int pid = perfdata->header.pid;
+#endif
+	int pid = perfdata->header.vdata.pid;
 	struct task_struct *task;
 	int i;
 
@@ -357,38 +556,49 @@
 	perfmon_base.state = PMC_STATE_TRACE_USER; 
 	mb();
 
+	pmc_trace_rec_type(perfdata->header.vdata.type);
 	pmc_configure((void *)perfdata);
 	smp_call_function(pmc_configure, (void *)perfdata, 0, 0);
 
 	return 0;
 }
 
+void pmc_trace_rec_type(unsigned long type)
+{
+	unsigned long cmd_rec;
+
+	cmd_rec = 0xFFUL << 56;
+	cmd_rec |= type;
+	*((unsigned long *)(perfmon_base.trace_buffer + 
+			    perfmon_base.trace_end)) = cmd_rec;
+	perfmon_base.trace_end += 8;
+	if(perfmon_base.trace_end >= perfmon_base.trace_length)
+		perfmon_base.trace_end = 0;
+}
+
 void pmc_configure(void *data)
 {
 	struct paca_struct *lpaca = get_paca();
 	struct perfmon_struct *perfdata = (struct perfmon_struct *)data;
 	struct pmc_struct *pdata = &(perfdata->vdata.pmc);
-	unsigned long cmd_rec, i;
+	unsigned long i;
 
 	/* Indicate to hypervisor that we are using the PMCs */
-	if(naca->platform == PLATFORM_ISERIES_LPAR)
+	if(systemcfg->platform == PLATFORM_ISERIES_LPAR)
 		lpaca->xLpPacaPtr->xPMCRegsInUse = 1;
 
 	/* Freeze all counters */
-	mtspr( MMCR0, 0x80000000 ); mtspr( MMCR1, 0x00000000 );
-
-	cmd_rec = 0xFFUL << 56;
-	cmd_rec |= perfdata->header.type;
-	*((unsigned long *)(perfmon_base.trace_buffer + perfmon_base.trace_end)) = cmd_rec;
-	perfmon_base.trace_end += 8;
+	mtspr(MMCR0, 0x80000000); mtspr(MMCR1, 0x00000000);
 
 	/* Clear all the PMCs */
-	mtspr( PMC1, 0 ); mtspr( PMC2, 0 ); mtspr( PMC3, 0 );
-	mtspr( PMC4, 0 ); mtspr( PMC5, 0 ); mtspr( PMC6, 0 );
-	mtspr( PMC7, 0 ); mtspr( PMC8, 0 );
+	mtspr(PMC1, 0); mtspr(PMC2, 0); mtspr(PMC3, 0); mtspr(PMC4, 0); 
+	mtspr(PMC5, 0); mtspr(PMC6, 0); mtspr(PMC7, 0); mtspr(PMC8, 0);
 
-	for(i = 0; i < 11; i++)
+	/* Set the PMCs to the new values */
+	for(i = 0; i < 11; i++) {
 		lpaca->pmc[i]  = pdata->pmc[i];
+		printk("pmc_configure: 0x%lx\n", pdata->pmc[i]);
+	}
 
 	mtspr(PMC1, lpaca->pmc[0]); mtspr(PMC2, lpaca->pmc[1]);
 	mtspr(PMC3, lpaca->pmc[2]); mtspr(PMC4, lpaca->pmc[3]);
@@ -398,7 +608,203 @@
 
 	mb();
 	
-	/* Start all counters */
-	mtspr( MMCR0, lpaca->pmc[8]);
+	/* Start all counters - MMCR0 contains the PMC enable control bit */
+	mtspr(MMCR0, lpaca->pmc[8]);
+}
+
+/* Increment the timeslice counters for the current timeslice */ 
+void pmc_timeslice_data_collect(void *data) {
+	struct paca_struct *lpaca = get_paca();
+	int i, cpu = smp_processor_id(); 
+	int slice_rec = cpu*PMC_MAX_COUNTERS*PMC_SLICES_MAX +
+		        pmc_timeslice[cpu]*PMC_MAX_COUNTERS;
+
+	/* First get any cumulative data that may have accrued */
+	for(i=0; i<8; i++) {
+		pmc_timeslice_data[slice_rec + i] += lpaca->pmcc[i];
+		lpaca->pmcc[i] = 0;
+		lpaca->pmc[i]  = 0;
+	}
+
+	/* Next get current hardware values */
+	pmc_timeslice_data[slice_rec + 0] += ((u32)mfspr(PMC1));
+	pmc_timeslice_data[slice_rec + 1] += ((u32)mfspr(PMC2));
+	pmc_timeslice_data[slice_rec + 2] += ((u32)mfspr(PMC3));
+	pmc_timeslice_data[slice_rec + 3] += ((u32)mfspr(PMC4));
+	pmc_timeslice_data[slice_rec + 4] += ((u32)mfspr(PMC5));
+	pmc_timeslice_data[slice_rec + 5] += ((u32)mfspr(PMC6));
+	pmc_timeslice_data[slice_rec + 6] += ((u32)mfspr(PMC7));
+	pmc_timeslice_data[slice_rec + 7] += ((u32)mfspr(PMC8));
+}
+
+/* Handle a timeslice tick.  Each processor executes independantly */
+int pmc_timeslice_tick() {
+	int i;
+	struct perfmon_struct perfdata;
+	unsigned int cpu = smp_processor_id();
+
+	/* Switch timeslice every decrementer, reduced by some factor */
+	pmc_tick_count[cpu]++;
+	if(!pmc_timeslice_enabled || pmc_tick_count[cpu] < PMC_TICK_FACTOR) 
+		return 0;
+	pmc_tick_count[cpu] = 0;
+
+	/* Stop counters and collect current state */
+	pmc_stop(NULL); 
+	pmc_timeslice_data_collect(NULL); 
+
+	/* Move on to the next timeslice */
+	pmc_timeslice[cpu]++; 
+	if(pmc_timeslice[cpu] >= pmc_timeslice_top) pmc_timeslice[cpu] = 0;
+
+	/* Set up the counters to reflect the new data to collect */
+	for(i = 0; i < 8; i++) {
+		perfdata.vdata.pmc.pmc[i] = 0;
+	}
+	for(i = 0; i < 3; i++) {
+		perfdata.vdata.pmc.pmc[i+8] = 
+			pmc_timeslice_config[pmc_timeslice[cpu]*5+i];
+	}
+	mb();
+
+	/* Configure the new counters */
+	pmc_configure((void *)&perfdata);
+
+	return 0;
+}
+
+int pmc_timeslice_set(struct perfmon_struct *perfdata) 
+{
+	int slice; 
+
+	printk("Perfmon: Timeslice set\n");
+
+	slice = perfdata->header.vdata.slice;
+	if(slice >= PMC_SLICES_MAX) {
+		printk("Perfmon: invalid timeslice specified %d\n", slice);
+		return(-1); 
+	}
+
+	if(slice > pmc_timeslice_top) pmc_timeslice_top = slice;
+
+	pmc_timeslice_config[slice * 5 + 0] = perfdata->vdata.pmc.pmc[0];
+	pmc_timeslice_config[slice * 5 + 1] = perfdata->vdata.pmc.pmc[1];
+	pmc_timeslice_config[slice * 5 + 2] = perfdata->vdata.pmc.pmc[2];
+	pmc_timeslice_config[slice * 5 + 3] = perfdata->vdata.pmc.pmc[3];
+	pmc_timeslice_config[slice * 5 + 4] = perfdata->vdata.pmc.pmc[4];
 }
 
+int pmc_timeslice_enable(struct perfmon_struct *perfdata) 
+{
+	int i, j;
+
+	printk("Perfmon: Timeslice mode\n");
+
+	if(perfmon_base.state == PMC_STATE_INITIAL) {
+		printk("Perfmon: failed - no buffer was allocated.\n"); 
+		return -1;
+	}
+
+	pmc_timeslice_disable(NULL); // fixme
+	mb();
+
+	for (i=0; i<MAX_PACAS; ++i) {
+		paca[i].prof_mode = PMC_STATE_TIMESLICE;
+	}
+	perfmon_base.state = PMC_STATE_TIMESLICE; 
+
+	pmc_configure_hardware(); 
+
+	for(i=0; i<PMC_MAX_CPUS; i++) {
+		pmc_tick_count[i] = 0;
+		pmc_timeslice[i]  = 0;
+	}
+
+	/* Stop counters on all processors -- blocking */
+	pmc_stop(NULL); 
+	smp_call_function(pmc_stop, (void *)NULL, 0, 1);
+
+	/* Clear out the PMC counters, cumulative and current */
+	for (i=0; i<MAX_PACAS; ++i) {
+		paca[i].prof_mode = PMC_STATE_TIMESLICE;
+		for(j=0; j<8; j++) {
+			paca[i].pmcc[j] = 0;
+		}
+		for(j=0; j<11; j++) {
+			paca[i].pmc[j] = 0;
+		}
+	}	
+
+	memset((char *)perfmon_base.timeslice_buffer, 
+	       0, perfmon_base.timeslice_length);
+
+	pmc_trace_rec_type(PMC_TYPE_TIMESLICE);
+
+	/* Clear counters on all processors -- blocking */
+	pmc_clear(NULL); 
+	smp_call_function(pmc_clear, (void *)NULL, 0, 1);
+
+	mb();
+
+	pmc_timeslice_enabled  = 1;
+
+	/* 
+	 * We do not actually setup the PMC hardware here.  That occurs
+	 * after the first timeslice tick occurs. Close enough.
+	 */
+	return 0;
+}
+
+int pmc_timeslice_disable(struct perfmon_struct *perfdata) 
+{
+	pmc_timeslice_enabled = 0;
+}
+
+void pmc_dump_timeslice(struct perfmon_struct *perfdata) 
+{
+	unsigned long rec, i, j, idx;
+	int cpu = smp_processor_id(); 
+
+	spin_lock(&pmc_lock);
+
+	pmc_trace_rec_type(PMC_TYPE_TIMESLICE_DUMP); /* DRENG put cpu num in */
+	for(i=0; i<pmc_timeslice_top; i++) {
+		for(j=0; j<8; j++) {
+			idx = cpu*PMC_MAX_COUNTERS*PMC_SLICES_MAX +
+				i*PMC_MAX_COUNTERS + j;
+			rec = pmc_timeslice_data[idx];
+			*((unsigned long *)(perfmon_base.trace_buffer + 
+					    perfmon_base.trace_end)) = rec;
+			perfmon_base.trace_end += 8;
+			if(perfmon_base.trace_end >= perfmon_base.trace_length)
+				perfmon_base.trace_end = 0;
+		}
+	}
+	spin_unlock(&pmc_lock);
+}
+
+long plpar_perfmon(int mode)
+{
+        return plpar_hcall_norets(H_PERFMON, mode, 0); 
+}
+
+void pmc_configure_hardware() {
+	/* 
+	 * Debug bus enabled is required on GP for timeslice mode.
+	 * Flood enabled is required on GP for PMC cycle profile mode
+	 *   iSeries SP sets this by default.  pSeries requires the OS to enable.
+	 */
+	if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p)) {
+		/* Set up the debug bus to pmc mode - a feature of GP */
+		switch(systemcfg->platform) {
+		case PLATFORM_ISERIES_LPAR:
+			HvCall_setDebugBus(1);
+			break;
+		case PLATFORM_PSERIES_LPAR:
+			plpar_perfmon(1);
+			break;
+		case PLATFORM_PSERIES:
+			mtspr(HID0, mfspr(HID0) | 0x0000080000000000);
+		} 
+	} 
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/pmc.c linux-2.4.21-pre6/arch/ppc64/kernel/pmc.c
--- linux-2.4.20/arch/ppc64/kernel/pmc.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/pmc.c	2003-03-26 23:48:57.000000000 +0000
@@ -73,7 +73,8 @@
 struct mm_struct btmalloc_mm = {pgd             : bolted_dir,
                                 page_table_lock : SPIN_LOCK_UNLOCKED};
 
-extern spinlock_t hash_table_lock;
+extern spinlock_t hash_table_lock[];
+extern inline unsigned long get_lock_slot(unsigned long vpn);
 
 char *
 ppc64_pmc_stab(int file)
@@ -211,15 +212,14 @@
 	pgd_t *pgdp;
 	pmd_t *pmdp;
 	pte_t *ptep, pte;
-	unsigned long ea_base, ea, hpteflags;
+	unsigned long ea_base, ea, hpteflags, lock_slot;
 	struct vm_struct *area;
-	unsigned long pa, pg_count, page, vsid, slot, va, arpn, vpn;
+	unsigned long pa, pg_count, page, vsid, slot, va, rpn, vpn;
   
 	size = PAGE_ALIGN(size);
 	if (!size || (size >> PAGE_SHIFT) > num_physpages) return NULL;
 
 	spin_lock(&btmalloc_mm.page_table_lock);
-	spin_lock(&hash_table_lock);
 
 	/* Get a virtual address region in the bolted space */
 	area = get_btm_area(size, 0);
@@ -236,10 +236,12 @@
 		pa = get_free_page(GFP_KERNEL) - PAGE_OFFSET; 
 		ea = ea_base + (page * PAGE_SIZE);
 		vsid = get_kernel_vsid(ea);
-		va = ( vsid << 28 ) | ( pa & 0xfffffff );
+		va = ( vsid << 28 ) | ( ea & 0xfffffff );
 		vpn = va >> PAGE_SHIFT;
-		arpn = ((unsigned long)__v2a(ea)) >> PAGE_SHIFT;
+		lock_slot = get_lock_slot(vpn); 
+		rpn = pa >> PAGE_SHIFT;
 
+		spin_lock(&hash_table_lock[lock_slot].lock);
 		/* Get a pointer to the linux page table entry for this page
 		 * allocating pmd or pte pages along the way as needed.  Note
 		 * that the pmd & pte pages are not themselfs bolted.
@@ -257,13 +259,16 @@
 		pte_val(pte) &= ~_PAGE_HPTEFLAGS;
 		pte_val(pte) |= _PAGE_HASHPTE;
 
-		slot = ppc_md.hpte_insert(vpn, arpn, hpteflags, 1, 0);  
+		slot = ppc_md.hpte_insert(vpn, rpn, hpteflags, 1, 0);  
 
 		pte_val(pte) |= ((slot<<12) & 
 				 (_PAGE_GROUP_IX | _PAGE_SECONDARY));
+
+		*ptep = pte;
+
+		spin_unlock(&hash_table_lock[lock_slot].lock);
 	}
 
-	spin_unlock(&hash_table_lock);
 	spin_unlock(&btmalloc_mm.page_table_lock);
 	return (void*)ea_base;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/ppc_ksyms.c linux-2.4.21-pre6/arch/ppc64/kernel/ppc_ksyms.c
--- linux-2.4.20/arch/ppc64/kernel/ppc_ksyms.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/ppc_ksyms.c	2003-03-26 23:49:55.000000000 +0000
@@ -106,6 +106,7 @@
 EXPORT_SYMBOL(pci_dram_offset);
 
 EXPORT_SYMBOL(find_next_zero_bit);
+EXPORT_SYMBOL(find_next_zero_le_bit);
 
 EXPORT_SYMBOL(strcpy);
 EXPORT_SYMBOL(strncpy);
@@ -124,6 +125,7 @@
 EXPORT_SYMBOL(__down_interruptible);
 EXPORT_SYMBOL(__up);
 EXPORT_SYMBOL(naca);
+EXPORT_SYMBOL(systemcfg);
 EXPORT_SYMBOL(__down);
 
 /* EXPORT_SYMBOL(csum_partial); already in net/netsyms.c */
@@ -252,6 +254,8 @@
 EXPORT_SYMBOL(rtas_firmware_flash_list);
 EXPORT_SYMBOL(rtas_token);
 EXPORT_SYMBOL(rtas_call);
+EXPORT_SYMBOL(rtas_data_buf);
+EXPORT_SYMBOL(rtas_data_buf_lock);
 #endif
 
 #ifndef CONFIG_PPC_ISERIES
@@ -269,10 +273,6 @@
 
 EXPORT_SYMBOL(abs);
 
-#ifdef CONFIG_VT
-EXPORT_SYMBOL(screen_info);
-#endif
-
 EXPORT_SYMBOL(timer_interrupt);
 EXPORT_SYMBOL(irq_desc);
 void ppc_irq_dispatch_handler(struct pt_regs *, int);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/proc_pmc.c linux-2.4.21-pre6/arch/ppc64/kernel/proc_pmc.c
--- linux-2.4.20/arch/ppc64/kernel/proc_pmc.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/proc_pmc.c	2003-03-26 23:49:31.000000000 +0000
@@ -110,6 +110,9 @@
 static ssize_t read_trace(struct file *file, char *buf, size_t count, loff_t *ppos);
 static ssize_t write_trace(struct file * file, const char * buf,
 			     size_t count, loff_t *ppos);
+static ssize_t read_timeslice(struct file *file, char *buf, size_t count, loff_t *ppos);
+static ssize_t write_timeslice(struct file * file, const char * buf,
+			     size_t count, loff_t *ppos);
 
 static struct file_operations proc_profile_operations = {
 	read:		read_profile,
@@ -121,6 +124,11 @@
 	write:		write_trace,
 };
 
+static struct file_operations proc_timeslice_operations = {
+	read:		read_timeslice,
+	write:		write_timeslice,
+};
+
 extern struct perfmon_base_struct perfmon_base;
 
 void proc_ppc64_init(void)
@@ -144,7 +152,15 @@
 	ent = create_proc_entry("naca", S_IFREG|S_IRUGO, proc_ppc64_root);
 	if ( ent ) {
 		ent->nlink = 1;
-		ent->data = 0;
+		ent->data = naca;
+		ent->size = 4096;
+		ent->proc_fops = &nacamap_fops;
+	}
+	
+	ent = create_proc_entry("systemcfg", S_IFREG|S_IRUGO, proc_ppc64_root);
+	if ( ent ) {
+		ent->nlink = 1;
+		ent->data = systemcfg;
 		ent->size = 4096;
 		ent->proc_fops = &nacamap_fops;
 	}
@@ -152,7 +168,7 @@
 	/* /proc/ppc64/paca/XX -- raw paca contents.  Only readable to root */
 	ent = proc_mkdir("paca", proc_ppc64_root);
 	if (ent) {
-		for (i = 0; i < naca->processorCount; i++)
+		for (i = 0; i < systemcfg->processorCount; i++)
 			proc_ppc64_create_paca(i, ent);
 	}
 
@@ -165,14 +181,14 @@
 	proc_ppc64_pmc_root = proc_mkdir("pmc", proc_ppc64_root);
 
 	proc_ppc64_pmc_system_root = proc_mkdir("system", proc_ppc64_pmc_root);
-	for (i = 0; i < naca->processorCount; i++) {
+	for (i = 0; i < systemcfg->processorCount; i++) {
 		sprintf(buf, "cpu%ld", i); 
 		proc_ppc64_pmc_cpu_root[i] = proc_mkdir(buf, proc_ppc64_pmc_root);
 	}
 
 
 	/* Create directories for the software counters. */
-	for (i = 0; i < naca->processorCount; i++) {
+	for (i = 0; i < systemcfg->processorCount; i++) {
 		ent = create_proc_entry("stab", S_IRUGO | S_IWUSR, 
 					proc_ppc64_pmc_cpu_root[i]);
 		if (ent) {
@@ -224,8 +240,14 @@
 		/* ent->size = (1+prof_len) * sizeof(unsigned int); */
 	}
 
+	ent = create_proc_entry("timeslice", S_IWUSR | S_IRUGO, proc_ppc64_pmc_system_root);
+	if (ent) {
+		ent->nlink = 1;
+		ent->proc_fops = &proc_timeslice_operations;
+	}
+
 	/* Create directories for the hardware counters. */
-	for (i = 0; i < naca->processorCount; i++) {
+	for (i = 0; i < systemcfg->processorCount; i++) {
 		ent = create_proc_entry("hardware", S_IRUGO | S_IWUSR, 
 					proc_ppc64_pmc_cpu_root[i]);
 		if (ent) {
@@ -299,7 +321,7 @@
 	   (unsigned long) proc_ppc64_pmc_system_root) {
 		return(-1); 
 	} else {
-		for (i = 0; i < naca->processorCount; i++) {
+		for (i = 0; i < systemcfg->processorCount; i++) {
 			if ((unsigned long)data ==
 			   (unsigned long)proc_ppc64_pmc_cpu_root[i]) {
 				return(i); 
@@ -417,20 +439,24 @@
 	return read;
 }
 
+static ssize_t write_profile(struct file * file, const char * buf,
+			     size_t count, loff_t *ppos)
+{
+}
+
 static ssize_t read_trace(struct file *file, char *buf,
 			    size_t count, loff_t *ppos)
 {
 	unsigned long p = *ppos;
 	ssize_t read;
 	char * pnt;
-	unsigned int sample_step = 4;
 
 	if (p >= (perfmon_base.trace_length)) return 0;
 	if (count > (perfmon_base.trace_length) - p)
 		count = (perfmon_base.trace_length) - p;
 	read = 0;
 
-	pnt = (char *)(perfmon_base.trace_buffer) + p; //  - sizeof(unsigned int);
+	pnt = (char *)(perfmon_base.trace_buffer) + p;
 	copy_to_user(buf,(void *)pnt,count);
 	read += count;
 	*ppos += read;
@@ -442,8 +468,28 @@
 {
 }
 
-static ssize_t write_profile(struct file * file, const char * buf,
-			     size_t count, loff_t *ppos)
+static ssize_t read_timeslice(struct file *file, char *buf,
+			      size_t count, loff_t *ppos)
+{
+	unsigned long p = *ppos;
+	ssize_t read;
+	char * pnt;
+	unsigned int sample_step = 4;
+
+	if (p >= (perfmon_base.timeslice_length)) return 0;
+	if (count > (perfmon_base.timeslice_length) - p)
+		count = (perfmon_base.timeslice_length) - p;
+	read = 0;
+
+	pnt = (char *)(perfmon_base.timeslice_buffer) + p;
+	copy_to_user(buf,(void *)pnt,count);
+	read += count;
+	*ppos += read;
+	return read;
+}
+
+static ssize_t write_timeslice(struct file * file, const char * buf,
+			       size_t count, loff_t *ppos)
 {
 }
 
@@ -545,7 +591,7 @@
 			(unsigned long)xItLpQueue.xLpIntCountByType[i] );
 	}
 	len += sprintf( page+len, "\n  events processed by processor:\n" );
-	for (i=0; i<naca->processorCount; ++i) {
+	for (i=0; i<systemcfg->processorCount; ++i) {
 		len += sprintf( page+len, "    CPU%02d  %10u\n",
 			i, paca[i].lpEvent_count );
 	}
@@ -978,45 +1024,33 @@
 static ssize_t nacamap_read( struct file *file, char *buf, size_t nbytes, loff_t *ppos)
 {
 	unsigned pos = *ppos;
-	unsigned size;
-	char * fromaddr;
 	struct proc_dir_entry *dp;
 
 	dp = file->f_dentry->d_inode->u.generic_ip;
 
-	size = dp->size;
-	if ( pos >= size )
+	if ( pos >= dp->size )
 		return 0;
-	if ( nbytes >= size )
-		nbytes = size;
-	if ( pos + nbytes > size )
-		nbytes = size - pos;
-	fromaddr = (char *)(KERNELBASE + 0x4000 + pos);
+	if ( nbytes >= dp->size )
+		nbytes = dp->size;
+	if ( pos + nbytes > dp->size )
+		nbytes = dp->size - pos;
 
-	copy_to_user( buf, fromaddr, nbytes );
+	copy_to_user( buf, (char *)dp->data + pos, nbytes );
 	*ppos = pos + nbytes;
 	return nbytes;
 }
 
 static int nacamap_mmap( struct file *file, struct vm_area_struct *vma )
 {
-	unsigned long pa;
-	long size;
-	long fsize;
 	struct proc_dir_entry *dp;
 
 	dp = file->f_dentry->d_inode->u.generic_ip;
 
-	pa = 0x4000;
-	fsize = 4096;
-
 	vma->vm_flags |= VM_SHM | VM_LOCKED;
 
-	size = vma->vm_end - vma->vm_start;
-	if ( size != 4096 )
+	if ((vma->vm_end - vma->vm_start) > dp->size)
 		return -EINVAL;
 
-	remap_page_range( vma->vm_start, pa, 4096, vma->vm_page_prot );
+	remap_page_range( vma->vm_start, __pa(dp->data), dp->size, vma->vm_page_prot );
 	return 0;
 }
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/process.c linux-2.4.21-pre6/arch/ppc64/kernel/process.c
--- linux-2.4.20/arch/ppc64/kernel/process.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/process.c	2003-03-26 23:49:10.000000000 +0000
@@ -241,6 +241,7 @@
 	}
 	memcpy(&p->thread.fpr, &current->thread.fpr, sizeof(p->thread.fpr));
 	p->thread.fpscr = current->thread.fpscr;
+	p->thread.fpexc_mode = current->thread.fpexc_mode;
 
 	return 0;
 }
@@ -278,6 +279,32 @@
 	current->thread.fpscr = 0;
 }
 
+# define PR_FP_EXC_DISABLED     0       /* FP exceptions disabled */
+# define PR_FP_EXC_NONRECOV     1       /* async non-recoverable exc. mode */
+# define PR_FP_EXC_ASYNC        2       /* async recoverable exception mode */
+# define PR_FP_EXC_PRECISE      3       /* precise exception mode */
+
+int set_fpexc_mode(struct task_struct *tsk, unsigned int val)
+{
+	struct pt_regs *regs = tsk->thread.regs;
+
+	if (val > PR_FP_EXC_PRECISE)
+		return -EINVAL;
+	tsk->thread.fpexc_mode = __pack_fe01(val);
+	if (regs != NULL && (regs->msr & MSR_FP) != 0)
+		regs->msr = (regs->msr & ~(MSR_FE0|MSR_FE1))
+			| tsk->thread.fpexc_mode;
+	return 0;
+}
+
+int get_fpexc_mode(struct task_struct *tsk, unsigned long adr)
+{
+	unsigned int val;
+
+	val = __unpack_fe01(tsk->thread.fpexc_mode);
+	return put_user(val, (unsigned int *) adr);
+}
+
 int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6,
 	      struct pt_regs *regs)
 {
@@ -337,13 +364,13 @@
 
 void initialize_paca_hardware_interrupt_stack(void)
 {
-	extern struct naca_struct *naca;
+	extern struct systemcfg *systemcfg;
 
 	int i;
 	unsigned long stack;
 	unsigned long end_of_stack =0;
 
-	for (i=1; i < naca->processorCount; i++) {
+	for (i=1; i < systemcfg->processorCount; i++) {
 		/* Carve out storage for the hardware interrupt stack */
 		stack = __get_free_pages(GFP_KERNEL, get_order(8*PAGE_SIZE));
 
@@ -366,7 +393,7 @@
 	if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p))
 		return;
 
-	for (i=0; i < naca->processorCount; i++) {
+	for (i=0; i < systemcfg->processorCount; i++) {
 		/* set page at the top of stack to be protected - prevent overflow */
 		end_of_stack = paca[i].xHrdIntStack - (8*PAGE_SIZE - STACK_FRAME_OVERHEAD);
 		ppc_md.hpte_updateboltedpp(PP_RXRX,end_of_stack);
@@ -461,6 +488,10 @@
 			return 0;
 		if (count > 0) {
 			ip = *(unsigned long *)(sp + 16);
+			/*
+			 * XXX we mask the upper 32 bits until procps
+			 * gets fixed.
+			 */
 			if (ip < first_sched || ip >= last_sched)
 				return (ip & 0xFFFFFFFF);
 		}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/prom.c linux-2.4.21-pre6/arch/ppc64/kernel/prom.c
--- linux-2.4.20/arch/ppc64/kernel/prom.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/prom.c	2003-03-26 23:49:54.000000000 +0000
@@ -342,6 +342,7 @@
         unsigned long offset = reloc_offset();
 	struct prom_t *_prom = PTRRELOC(&prom);
         struct naca_struct *_naca = RELOC(naca);
+        struct systemcfg *_systemcfg = RELOC(systemcfg);
 
 	/* NOTE: _naca->debug_switch is already initialized. */
 #ifdef DEBUG_PROM
@@ -362,7 +363,7 @@
 			 * d-cache and i-cache sizes... -Peter
 			 */
 			if ( num_cpus == 1 ) {
-				u32 size, lsize, sets;
+				u32 size, lsize;
 
 				call_prom(RELOC("getprop"), 4, 1, node,
 					  RELOC("d-cache-size"),
@@ -372,35 +373,25 @@
 					  RELOC("d-cache-line-size"),
 					  &lsize, sizeof(lsize));
 
-				call_prom(RELOC("getprop"), 4, 1, node,
-					  RELOC("d-cache-sets"),
-					  &sets, sizeof(sets));
-
-				_naca->dCacheL1Size         = size;
-				_naca->dCacheL1LineSize     = lsize;
-				_naca->dCacheL1LogLineSize  = __ilog2(lsize);
+				_systemcfg->dCacheL1Size = size;
+				_systemcfg->dCacheL1LineSize = lsize;
+				_naca->dCacheL1LogLineSize = __ilog2(lsize);
 				_naca->dCacheL1LinesPerPage = PAGE_SIZE/lsize;
-				_naca->dCacheL1Assoc = size / lsize / sets;
 
 				call_prom(RELOC("getprop"), 4, 1, node,
-					  RELOC("i-cache-line-size"),
+					  RELOC("i-cache-size"),
 					  &size, sizeof(size));
 
 				call_prom(RELOC("getprop"), 4, 1, node,
 					  RELOC("i-cache-line-size"),
 					  &lsize, sizeof(lsize));
 
-				call_prom(RELOC("getprop"), 4, 1, node,
-					  RELOC("i-cache-sets"),
-					  &sets, sizeof(sets));
-
-				_naca->iCacheL1Size         = size;
-				_naca->iCacheL1LineSize     = lsize;
-				_naca->iCacheL1LogLineSize  = __ilog2(lsize);
+				_systemcfg->iCacheL1Size = size;
+				_systemcfg->iCacheL1LineSize = lsize;
+				_naca->iCacheL1LogLineSize = __ilog2(lsize);
 				_naca->iCacheL1LinesPerPage = PAGE_SIZE/lsize;
-				_naca->iCacheL1Assoc = size / lsize / sets;
 
-				if (_naca->platform == PLATFORM_PSERIES_LPAR) {
+				if (_systemcfg->platform == PLATFORM_PSERIES_LPAR) {
 					u32 pft_size[2];
 					call_prom(RELOC("getprop"), 4, 1, node, 
 						  RELOC("ibm,pft-size"),
@@ -470,17 +461,17 @@
 	}
 
 	/* We gotta have at least 1 cpu... */
-        if ( (_naca->processorCount = num_cpus) < 1 )
+        if ( (_systemcfg->processorCount = num_cpus) < 1 )
                 PROM_BUG();
 
-	_naca->physicalMemorySize = lmb_phys_mem_size();
+	_systemcfg->physicalMemorySize = lmb_phys_mem_size();
 
-	if (_naca->platform == PLATFORM_PSERIES) {
+	if (_systemcfg->platform == PLATFORM_PSERIES) {
 		unsigned long rnd_mem_size, pteg_count;
 
 		/* round mem_size up to next power of 2 */
-		rnd_mem_size = 1UL << __ilog2(_naca->physicalMemorySize);
-		if (rnd_mem_size < _naca->physicalMemorySize)
+		rnd_mem_size = 1UL << __ilog2(_systemcfg->physicalMemorySize);
+		if (rnd_mem_size < _systemcfg->physicalMemorySize)
 			rnd_mem_size <<= 1;
 
 		/* # pages / 2 */
@@ -501,58 +492,43 @@
 	 */
 	_naca->slb_size = 64;
 
-	/* Add an eye catcher and the naca layout version number */
-	strcpy(_naca->eye_catcher, RELOC("PPC64"));
-	_naca->version     = 1;
-	_naca->processor   = _get_PVR() >> 16;
+	/* Add an eye catcher and the systemcfg layout version number */
+	strcpy(_systemcfg->eye_catcher, RELOC("SYSTEMCFG:PPC64"));
+	_systemcfg->version.major = SYSTEMCFG_MAJOR;
+	_systemcfg->version.minor = SYSTEMCFG_MINOR;
+	_systemcfg->processor = _get_PVR();
 
 #ifdef DEBUG_PROM
-        prom_print(RELOC("naca->processorCount       = 0x"));
-        prom_print_hex(_naca->processorCount);
+        prom_print(RELOC("systemcfg->processorCount       = 0x"));
+        prom_print_hex(_systemcfg->processorCount);
         prom_print_nl();
 
-        prom_print(RELOC("naca->physicalMemorySize   = 0x"));
-        prom_print_hex(_naca->physicalMemorySize);
+        prom_print(RELOC("systemcfg->physicalMemorySize   = 0x"));
+        prom_print_hex(_systemcfg->physicalMemorySize);
         prom_print_nl();
 
-        prom_print(RELOC("naca->pftSize              = 0x"));
+        prom_print(RELOC("naca->pftSize                   = 0x"));
         prom_print_hex(_naca->pftSize);
         prom_print_nl();
 
-        prom_print(RELOC("naca->dCacheL1LineSize     = 0x"));
-        prom_print_hex(_naca->dCacheL1LineSize);
-        prom_print_nl();
-
-        prom_print(RELOC("naca->dCacheL1LogLineSize  = 0x"));
-        prom_print_hex(_naca->dCacheL1LogLineSize);
-        prom_print_nl();
-
-        prom_print(RELOC("naca->dCacheL1LinesPerPage = 0x"));
-        prom_print_hex(_naca->dCacheL1LinesPerPage);
-        prom_print_nl();
-
-        prom_print(RELOC("naca->iCacheL1LineSize     = 0x"));
-        prom_print_hex(_naca->iCacheL1LineSize);
-        prom_print_nl();
-
-        prom_print(RELOC("naca->iCacheL1LogLineSize  = 0x"));
-        prom_print_hex(_naca->iCacheL1LogLineSize);
+        prom_print(RELOC("systemcfg->dCacheL1LineSize     = 0x"));
+        prom_print_hex(_systemcfg->dCacheL1LineSize);
         prom_print_nl();
 
-        prom_print(RELOC("naca->iCacheL1LinesPerPage = 0x"));
-        prom_print_hex(_naca->iCacheL1LinesPerPage);
+        prom_print(RELOC("systemcfg->iCacheL1LineSize     = 0x"));
+        prom_print_hex(_systemcfg->iCacheL1LineSize);
         prom_print_nl();
 
-        prom_print(RELOC("naca->serialPortAddr       = 0x"));
+        prom_print(RELOC("naca->serialPortAddr            = 0x"));
         prom_print_hex(_naca->serialPortAddr);
         prom_print_nl();
 
-        prom_print(RELOC("naca->interrupt_controller = 0x"));
+        prom_print(RELOC("naca->interrupt_controller      = 0x"));
         prom_print_hex(_naca->interrupt_controller);
         prom_print_nl();
 
-        prom_print(RELOC("naca->platform             = 0x"));
-        prom_print_hex(_naca->platform);
+        prom_print(RELOC("systemcfg->platform             = 0x"));
+        prom_print_hex(_systemcfg->platform);
         prom_print_nl();
 
 	prom_print(RELOC("prom_initialize_naca: end...\n"));
@@ -655,7 +631,7 @@
 	unsigned long offset = reloc_offset();
 	struct prom_t *_prom = PTRRELOC(&prom);
 	struct rtas_t *_rtas = PTRRELOC(&rtas);
-	struct naca_struct *_naca = RELOC(naca);
+	struct systemcfg *_systemcfg = RELOC(systemcfg);
 	ihandle prom_rtas;
         u32 getprop_rval;
 
@@ -672,7 +648,7 @@
 				  RELOC("ibm,hypertas-functions"), 
 				  hypertas_funcs, 
 				  sizeof(hypertas_funcs))) > 0) {
-			_naca->platform = PLATFORM_PSERIES_LPAR;
+			_systemcfg->platform = PLATFORM_PSERIES_LPAR;
 		}
 
 		call_prom(RELOC("getprop"), 
@@ -689,7 +665,7 @@
 			 * of physical memory (or within the RMO region) because RTAS
 			 * runs in 32-bit mode and relocate off.
 			 */
-			if ( _naca->platform == PLATFORM_PSERIES_LPAR ) {
+			if ( _systemcfg->platform == PLATFORM_PSERIES_LPAR ) {
 				struct lmb *_lmb  = PTRRELOC(&lmb);
 				rtas_region = min(_lmb->rmo_size, RTAS_INSTANTIATE_MAX);
 			}
@@ -1083,12 +1059,12 @@
         unsigned long *spinloop     = __v2a(&__secondary_hold_spinloop);
         unsigned long *acknowledge  = __v2a(&__secondary_hold_acknowledge);
         unsigned long secondary_hold = (unsigned long)__v2a(*PTRRELOC((unsigned long *)__secondary_hold));
-        struct naca_struct *_naca = RELOC(naca);
+        struct systemcfg *_systemcfg = RELOC(systemcfg);
 	struct paca_struct *_xPaca = PTRRELOC(&paca[0]);
 	struct prom_t *_prom = PTRRELOC(&prom);
 
 	/* Initially, we must have one active CPU. */
-	_naca->processorCount = 1;
+	_systemcfg->processorCount = 1;
 
 #ifdef DEBUG_PROM
 	prom_print(RELOC("prom_hold_cpus: start...\n"));
@@ -1206,7 +1182,7 @@
 		if (*acknowledge == cpuid) {
 			prom_print(RELOC("ok\n"));
 			/* Set the number of active processors. */
-			_naca->processorCount++;
+			_systemcfg->processorCount++;
 		} else {
 			prom_print(RELOC("failed: "));
 			prom_print_hex(*acknowledge);
@@ -1220,8 +1196,8 @@
 	    __is_processor(PV_SSTAR)) {
 		prom_print(RELOC("    starting secondary threads\n"));
 
-		for (i=0; i < _naca->processorCount ;i++) {
-			unsigned long threadid = _naca->processorCount*2-1-i;
+		for (i=0; i < _systemcfg->processorCount ;i++) {
+			unsigned long threadid = _systemcfg->processorCount*2-1-i;
 			
 			if (i == 0) {
 				unsigned long pir = _get_PIR();
@@ -1247,7 +1223,7 @@
 #endif
 			_xPaca[threadid].xHwProcNum = _xPaca[i].xHwProcNum+1;
 		}
-		_naca->processorCount *= 2;
+		_systemcfg->processorCount *= 2;
 	} else {
 		prom_print(RELOC("Processor is not HMT capable\n"));
 	}
@@ -1381,13 +1357,14 @@
 	char *p, *d;
  	unsigned long phys;
         u32 getprop_rval;
-        struct naca_struct   *_naca = RELOC(naca);
+        struct naca_struct *_naca = RELOC(naca);
+        struct systemcfg *_systemcfg = RELOC(systemcfg);
 	struct paca_struct *_xPaca = PTRRELOC(&paca[0]);
 	struct prom_t *_prom = PTRRELOC(&prom);
 	char *_cmd_line = PTRRELOC(&cmd_line[0]);
 
 	/* Default machine type. */
-	_naca->platform = PLATFORM_PSERIES;
+	_systemcfg->platform = PLATFORM_PSERIES;
 	/* Reset klimit to take into account the embedded system map */
 	if (RELOC(embedded_sysmap_end))
 		RELOC(klimit) = __va(PAGE_ALIGN(RELOC(embedded_sysmap_end)));
@@ -1475,6 +1452,8 @@
 			    sizeof(cmd_line)-1);
 	if (sz > 0)
 		_cmd_line[sz] = '\0';
+        if (sz <=1 )
+                strcpy(_cmd_line,RELOC(CONFIG_CMDLINE));
 
 	prom_parse_cmd_line(_cmd_line);
 
@@ -1544,6 +1523,8 @@
 
 	mem = prom_bi_rec_reserve(mem);
 
+	mem = check_display(mem);
+
 	prom_instantiate_rtas();
         
         /* Initialize some system info into the Naca early... */
@@ -1553,11 +1534,9 @@
          * following, regardless of whether we have an SMP
          * kernel or not.
          */
-        if ( _naca->processorCount > 1 )
+        if (_systemcfg->processorCount > 1)
 	        prom_hold_cpus(mem);
 
-	mem = check_display(mem);
-
 #ifdef DEBUG_PROM
 	prom_print(RELOC("copying OF device tree...\n"));
 #endif
@@ -1567,7 +1546,7 @@
 
 	lmb_reserve(0, __pa(RELOC(klimit)));
 
-	if (_naca->platform == PLATFORM_PSERIES)
+	if (_systemcfg->platform == PLATFORM_PSERIES)
 		prom_initialize_tce_table();
 
  	if ((long) call_prom(RELOC("getprop"), 4, 1,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/ptrace.c linux-2.4.21-pre6/arch/ppc64/kernel/ptrace.c
--- linux-2.4.20/arch/ppc64/kernel/ptrace.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/ptrace.c	2003-03-26 23:49:40.000000000 +0000
@@ -252,50 +252,68 @@
 		break;
 
 	case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */
-		u64 tmp;
-		u64 cntr;
-
-		ret = 0; 
-		for (cntr=0; cntr<32 && ret==0; ++cntr) {
-			tmp = ((u64*)child->thread.regs)[cntr];
-			ret = put_user(tmp, (u64*)(data+cntr));
+		int i;
+		unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
+		unsigned long *tmp = (unsigned long *)addr;
+
+		for (i = 0; i < 32; i++) {
+			ret = put_user(*reg, tmp);
+			if (ret)
+				break;
+			reg++;
+			tmp++;
 		}
 		break;
 	}
 
 	case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */
-		u64 cntr;
-
-		ret = 0; 
-		for (cntr=0; cntr<32 && ret==0; ++cntr)
-			ret = put_reg(child, cntr, *(u64*)(data+cntr));
+		int i;
+		unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
+		unsigned long *tmp = (unsigned long *)addr;
+
+		for (i = 0; i < 32; i++) {
+			ret = get_user(*reg, tmp);
+			if (ret)
+				break;
+			reg++;
+			tmp++;
+		}
 		break;
 	}
 
 	case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */
-		u64 tmp;
-		u64 cntr;
+		int i;
+		unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
+		unsigned long *tmp = (unsigned long *)addr;
 
-		ret = -EIO;
 		if (child->thread.regs->msr & MSR_FP)
 			giveup_fpu(child);
-		ret = 0; 
-		for (cntr=0; cntr<32 && ret==0; ++cntr) {
-			tmp = ((u64*)child->thread.fpr)[cntr];
-			ret = put_user(tmp, (u64*)(data+cntr));
+
+		for (i = 0; i < 32; i++) {
+			ret = put_user(*reg, tmp);
+			if (ret)
+				break;
+			reg++;
+			tmp++;
 		}
 		break;
 	}
 
 	case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */
-		u64 cntr;
+		int i;
+		unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
+		unsigned long *tmp = (unsigned long *)addr;
 
-		ret = -EIO;
 		if (child->thread.regs->msr & MSR_FP)
 			giveup_fpu(child);
-		for (cntr=0; cntr<32; ++cntr)
-			((u64*)child->thread.fpr)[cntr] = *(u64*)(data+cntr);
-		ret = 0; 
+
+		for (i = 0; i < 32; i++) {
+			ret = get_user(*reg, tmp);
+			if (ret)
+				break;
+			reg++;
+			tmp++;
+		}
 		break;
 	}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/ptrace32.c linux-2.4.21-pre6/arch/ppc64/kernel/ptrace32.c
--- linux-2.4.20/arch/ppc64/kernel/ptrace32.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/ptrace32.c	2003-03-26 23:49:50.000000000 +0000
@@ -228,9 +228,9 @@
 			if (child->thread.regs->msr & MSR_FP)
 				giveup_fpu(child);
 		        if (numReg == PT_FPSCR) 
-			        tmp_reg_value = ((unsigned int *)child->thread.fpscr);
+			        tmp_reg_value = ((unsigned long *)child->thread.fpscr);
 		        else 
-			        tmp_reg_value = ((unsigned long int *)child->thread.fpr)[numReg - PT_FPR0];
+			        tmp_reg_value = ((unsigned long *)child->thread.fpr)[numReg - PT_FPR0];
 		} else { /* register within PT_REGS struct */
 		    tmp_reg_value = get_reg(child, numReg);
 		} 
@@ -395,6 +395,74 @@
 		ret = ptrace_detach(child, data);
 		break;
 
+	case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */
+		int i;
+		unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
+		unsigned int *tmp = (unsigned int *)addr;
+
+		for (i = 0; i < 32; i++) {
+			ret = put_user(*reg, tmp);
+			if (ret)
+				break;
+			reg++;
+			tmp++;
+		}
+		break;
+	}
+
+	case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */
+		int i;
+		unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
+		unsigned int *tmp = (unsigned int *)addr;
+
+		for (i = 0; i < 32; i++) {
+			ret = get_user(*reg, tmp);
+			if (ret)
+				break;
+			reg++;
+			tmp++;
+		}
+		break;
+	}
+
+	case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */
+		int i;
+		unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
+		unsigned int *tmp = (unsigned int *)addr;
+
+		if (child->thread.regs->msr & MSR_FP)
+			giveup_fpu(child);
+
+		for (i = 0; i < 32; i++) {
+			ret = put_user(*reg, tmp);
+			if (ret)
+				break;
+			reg++;
+			tmp++;
+		}
+		break;
+	}
+
+	case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */
+		int i;
+		unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
+		unsigned int *tmp = (unsigned int *)addr;
+
+		if (child->thread.regs->msr & MSR_FP)
+			giveup_fpu(child);
+
+		for (i = 0; i < 32; i++) {
+			ret = get_user(*reg, tmp);
+			if (ret)
+				break;
+			reg++;
+			tmp++;
+		}
+		break;
+	}
+
+
+
 	default:
 		ret = -EIO;
 		break;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/rtas-proc.c linux-2.4.21-pre6/arch/ppc64/kernel/rtas-proc.c
--- linux-2.4.20/arch/ppc64/kernel/rtas-proc.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/rtas-proc.c	2003-03-26 23:49:30.000000000 +0000
@@ -162,26 +162,26 @@
 		size_t count, loff_t *ppos);
 
 struct file_operations ppc_rtas_poweron_operations = {
-	read:		ppc_rtas_poweron_read,
-	write:		ppc_rtas_poweron_write
+	.read =		ppc_rtas_poweron_read,
+	.write =	ppc_rtas_poweron_write
 };
 struct file_operations ppc_rtas_progress_operations = {
-	read:		ppc_rtas_progress_read,
-	write:		ppc_rtas_progress_write
+	.read =		ppc_rtas_progress_read,
+	.write =	ppc_rtas_progress_write
 };
 
 struct file_operations ppc_rtas_clock_operations = {
-	read:		ppc_rtas_clock_read,
-	write:		ppc_rtas_clock_write
+	.read =		ppc_rtas_clock_read,
+	.write =	ppc_rtas_clock_write
 };
 
 struct file_operations ppc_rtas_tone_freq_operations = {
-	read:		ppc_rtas_tone_freq_read,
-	write:		ppc_rtas_tone_freq_write
+	.read =		ppc_rtas_tone_freq_read,
+	.write =	ppc_rtas_tone_freq_write
 };
 struct file_operations ppc_rtas_tone_volume_operations = {
-	read:		ppc_rtas_tone_volume_read,
-	write:		ppc_rtas_tone_volume_write
+	.read =		ppc_rtas_tone_volume_read,
+	.write =	ppc_rtas_tone_volume_write
 };
 
 int ppc_rtas_find_all_sensors (void);
@@ -200,7 +200,7 @@
 	struct proc_dir_entry *entry;
 
 	rtas_node = find_devices("rtas");
-	if ((rtas_node == 0) || (naca->platform == PLATFORM_ISERIES_LPAR)) {
+	if ((rtas_node == 0) || (systemcfg->platform == PLATFORM_ISERIES_LPAR)) {
 		return;
 	}
 	
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/rtas.c linux-2.4.21-pre6/arch/ppc64/kernel/rtas.c
--- linux-2.4.20/arch/ppc64/kernel/rtas.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/rtas.c	2003-03-26 23:49:39.000000000 +0000
@@ -53,11 +53,14 @@
  */
 
 struct rtas_t rtas = { 
-	lock: SPIN_LOCK_UNLOCKED
+	.lock = SPIN_LOCK_UNLOCKED
 };
 
 extern unsigned long reloc_offset(void);
 
+spinlock_t rtas_data_buf_lock = SPIN_LOCK_UNLOCKED;
+char rtas_data_buf[RTAS_DATA_BUF_SIZE];
+
 void
 phys_call_rtas(int token, int nargs, int nret, ...)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/rtasd.c linux-2.4.21-pre6/arch/ppc64/kernel/rtasd.c
--- linux-2.4.20/arch/ppc64/kernel/rtasd.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/rtasd.c	2003-03-26 23:49:06.000000000 +0000
@@ -113,10 +113,10 @@
 }
 
 struct file_operations proc_rtas_log_operations = {
-	read:		rtas_log_read,
-	poll:		rtas_log_poll,
-	open:		rtas_log_open,
-	release:	rtas_log_release,
+	.read =		rtas_log_read,
+	.poll =		rtas_log_poll,
+	.open =		rtas_log_open,
+	.release =	rtas_log_release,
 };
 
 
@@ -623,25 +623,27 @@
 }
 
 #define MAX_LOG_DEBUG 10
+#define MAX_LOG_DEBUG_LEN 900
 /* Print log debug data.  This appears after the location code.
  * We limit the number of debug logs in case the data is somehow corrupt.
  */
 static void printk_log_debug(char *buf)
 {
-	unsigned char *p = (unsigned char *)_ALIGN((unsigned long)buf, 8);
+	unsigned char *p = (unsigned char *)_ALIGN((unsigned long)buf, 4);
 	int len, n, logged;
 
 	logged = 0;
-	while ((logged < MAX_LOG_DEBUG) && (len = ((p[0] << 8) | p[1])) != 2) {
-		/* len includes 2-byte length thus len == 2 is the end */
-		printk("RTAS: Log Debug: ");
-		if (len >= 4)	/* next 2 bytes are an ascii code */
-			printk("%c%c ", p[2], p[3]);
+	while ((logged < MAX_LOG_DEBUG) && (len = ((p[0] << 8) | p[1])) >= 4) {
+		if (len > MAX_LOG_DEBUG_LEN)
+			len = MAX_LOG_DEBUG_LEN;	/* bound it */
+		printk("RTAS: Log Debug: %c%c ", p[2], p[3]);
 		for (n=4; n < len; n++)
 			printk("%02x", p[n]);
 		printk("\n");
-		p += len;
+		p = (unsigned char *)_ALIGN((unsigned long)p+len, 4);
 		logged++;
+		if (len == MAX_LOG_DEBUG_LEN)
+			return;	/* no point continuing */
 	}
 	if (logged == 0)
 		printk("RTAS: no log debug data present\n");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/rtc.c linux-2.4.21-pre6/arch/ppc64/kernel/rtc.c
--- linux-2.4.20/arch/ppc64/kernel/rtc.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/rtc.c	2003-03-26 23:49:55.000000000 +0000
@@ -178,12 +178,12 @@
  *	The various file operations we support.
  */
 static struct file_operations rtc_fops = {
-	owner:		THIS_MODULE,
-	llseek:		rtc_llseek,
-	read:		rtc_read,
-	ioctl:		rtc_ioctl,
-	open:		rtc_open,
-	release:	rtc_release,
+	.owner =	THIS_MODULE,
+	.llseek =	rtc_llseek,
+	.read =		rtc_read,
+	.ioctl =	rtc_ioctl,
+	.open =		rtc_open,
+	.release =	rtc_release,
 };
 
 static struct miscdevice rtc_dev=
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/scanlog.c linux-2.4.21-pre6/arch/ppc64/kernel/scanlog.c
--- linux-2.4.20/arch/ppc64/kernel/scanlog.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/scanlog.c	2003-03-26 23:49:09.000000000 +0000
@@ -0,0 +1,234 @@
+/*
+ *  c 2001 PPC 64 Team, IBM Corp
+ *
+ *      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.
+ *
+ * scan-log-data driver for PPC64  Todd Inglett <tinglett@vnet.ibm.com>
+ *
+ * When ppc64 hardware fails the service processor dumps internal state
+ * of the system.  After a reboot the operating system can access a dump
+ * of this data using this driver.  A dump exists if the device-tree
+ * /chosen/ibm,scan-log-data property exists.
+ *
+ * This driver exports /proc/ppc64/scan-log-dump which can be read.
+ * The driver supports only sequential reads.
+ *
+ * The driver looks at a write to the driver for the single word "reset".
+ * If given, the driver will reset the scanlog so the platform can free it.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <asm/rtas.h>
+#include <asm/prom.h>
+
+#define MODULE_VERSION "1.0"
+#define MODULE_NAME "scanlog"
+
+/* Status returns from ibm,scan-log-dump */
+#define SCANLOG_COMPLETE 0
+#define SCANLOG_HWERROR -1
+#define SCANLOG_CONTINUE 1
+
+#define DEBUG(A...) do { if (scanlog_debug) printk(KERN_ERR "scanlog: " A); } while (0)
+
+static int scanlog_debug;
+static unsigned int ibm_scan_log_dump;			/* RTAS token */
+static struct proc_dir_entry *proc_ppc64_scan_log_dump;	/* The proc file */
+
+
+static ssize_t scanlog_read(struct file *file, char *buf,
+			    size_t count, loff_t *ppos)
+{
+	struct proc_dir_entry *dp = file->f_dentry->d_inode->u.generic_ip;
+	unsigned int *data = (unsigned int *)dp->data;
+	unsigned long status;
+	unsigned long len, off;
+	unsigned int wait_time;
+
+	if (!data) {
+		printk(KERN_ERR "scanlog: read failed no data\n");
+		return -EIO;
+	}
+
+	if (count > RTAS_DATA_BUF_SIZE)
+		count = RTAS_DATA_BUF_SIZE;
+
+	if (count < 1024) {
+		/* This is the min supported by this RTAS call.  Rather
+		 * than do all the buffering we insist the user code handle
+		 * larger reads.  As long as cp works... :)
+		 */
+		printk(KERN_ERR "scanlog: cannot perform a small read (%ld)\n", count);
+		return -EINVAL;
+	}
+
+	if (verify_area(VERIFY_WRITE, buf, count))
+		return -EFAULT;
+
+	for (;;) {
+		wait_time = HZ/2;	/* default wait if no data */
+		spin_lock(&rtas_data_buf_lock);
+		memcpy(rtas_data_buf, data, RTAS_DATA_BUF_SIZE);
+		status = rtas_call(ibm_scan_log_dump, 2, 1, NULL,
+				   __pa(rtas_data_buf), count);
+		memcpy(data, rtas_data_buf, RTAS_DATA_BUF_SIZE);
+		spin_unlock(&rtas_data_buf_lock);
+
+		DEBUG("status=%ld, data[0]=%x, data[1]=%x, data[2]=%x\n",
+		      status, data[0], data[1], data[2]);
+		switch (status) {
+		    case SCANLOG_COMPLETE:
+			DEBUG("hit eof\n");
+			return 0;
+		    case SCANLOG_HWERROR:
+			DEBUG("hardware error reading scan log data\n");
+			return -EIO;
+		    case SCANLOG_CONTINUE:
+			/* We may or may not have data yet */
+			len = data[1];
+			off = data[2];
+			if (len > 0) {
+				if (copy_to_user(buf, ((char *)data)+off, len))
+					return -EFAULT;
+				return len;
+			}
+			/* Break to sleep default time */
+			break;
+		    default:
+			if (status > 9900 && status <= 9905) {
+				/* No data.  RTAS is hinting at a delay required
+				 * between 1-100000 milliseconds
+				 */
+				int ms = 1;
+				for (; status > 9900; status--)
+					ms = ms * 10;
+				/* Use microseconds for reasonable accuracy */
+				ms *= 1000;
+				wait_time = ms / (1000000/HZ); /* round down is fine */
+				/* Fall through to sleep */
+			} else {
+				printk(KERN_ERR "scanlog: unknown error from rtas: %ld\n", status);
+				return -EIO;
+			}
+		}
+		/* Apparently no data yet.  Wait and try again. */
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(wait_time);
+	}
+	/*NOTREACHED*/
+}
+
+static ssize_t scanlog_write(struct file * file, const char * buf,
+			     size_t count, loff_t *ppos)
+{
+	unsigned long status;
+
+	if (buf) {
+		if (strncmp(buf, "reset", 5) == 0) {
+			DEBUG("reset scanlog\n");
+			status = rtas_call(ibm_scan_log_dump, 2, 1, NULL, NULL, 0);
+			DEBUG("rtas returns %ld\n", status);
+		} else if (strncmp(buf, "debugon", 7) == 0) {
+			printk(KERN_ERR "scanlog: debug on\n");
+			scanlog_debug = 1;
+		} else if (strncmp(buf, "debugoff", 8) == 0) {
+			printk(KERN_ERR "scanlog: debug off\n");
+			scanlog_debug = 0;
+		}
+	}
+	return count;
+}
+
+static int scanlog_open(struct inode * inode, struct file * file)
+{
+	struct proc_dir_entry *dp = file->f_dentry->d_inode->u.generic_ip;
+	unsigned int *data = (unsigned int *)dp->data;
+
+	if (!data) {
+		printk(KERN_ERR "scanlog: open failed no data\n");
+		return -EIO;
+	}
+	if (data[0] != 0) {
+		/* This imperfect test stops a second copy of the
+		 * data (or a reset while data is being copied)
+		 */
+		return -EBUSY;
+	}
+
+	data[0] = 0;	/* re-init so we restart the scan */
+
+	return 0;
+}
+
+static int scanlog_release(struct inode * inode, struct file * file)
+{
+	struct proc_dir_entry *dp = file->f_dentry->d_inode->u.generic_ip;
+	unsigned int *data = (unsigned int *)dp->data;
+
+	if (!data) {
+		printk(KERN_ERR "scanlog: release failed no data\n");
+		return -EIO;
+	}
+	data[0] = 0;
+
+	return 0;
+}
+
+struct file_operations scanlog_fops = {
+	owner:		THIS_MODULE,
+	read:		scanlog_read,
+	write:		scanlog_write,
+	open:		scanlog_open,
+	release:	scanlog_release,
+};
+
+int __init scanlog_init(void)
+{
+	struct proc_dir_entry *ent;
+
+	ibm_scan_log_dump = rtas_token("ibm,scan-log-dump");
+	if (ibm_scan_log_dump == RTAS_UNKNOWN_SERVICE) {
+		printk(KERN_ERR "scan-log-dump not implemented on this system\n");
+		return -EIO;
+	}
+
+	ent = create_proc_entry("ppc64/scan-log-dump", S_IRUSR, NULL);
+	if (ent) {
+		ent->proc_fops = &scanlog_fops;
+		/* Ideally we could allocate a buffer < 4G */
+		ent->data = kmalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL);
+		if (!ent->data) {
+			printk(KERN_ERR "Failed to allocate a buffer\n");
+			remove_proc_entry("scan-log-dump", ent->parent);
+			return -ENOMEM;
+		}
+		((unsigned int *)ent->data)[0] = 0;
+	} else {
+		printk(KERN_ERR "Failed to create ppc64/scan-log-dump proc entry\n");
+		return -EIO;
+	}
+	proc_ppc64_scan_log_dump = ent;
+
+	return 0;
+}
+
+void __exit scanlog_cleanup(void)
+{
+	if (proc_ppc64_scan_log_dump) {
+		if (proc_ppc64_scan_log_dump->data)
+		    kfree(proc_ppc64_scan_log_dump->data);
+		remove_proc_entry("scan-log-dump", proc_ppc64_scan_log_dump->parent);
+	}
+}
+
+module_init(scanlog_init);
+module_exit(scanlog_cleanup);
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/setup.c linux-2.4.21-pre6/arch/ppc64/kernel/setup.c
--- linux-2.4.20/arch/ppc64/kernel/setup.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/setup.c	2003-03-26 23:49:20.000000000 +0000
@@ -37,12 +37,15 @@
 #include <asm/paca.h>
 #include <asm/ppcdebug.h>
 #include <asm/time.h>
+#ifdef CONFIG_KDB
+#include <linux/kdb.h>
+#endif
 
 extern unsigned long klimit;
 /* extern void *stab; */
 extern HTAB htab_data;
 extern unsigned long loops_per_jiffy;
-extern int preferred_console;	/* from kernel/printk.c */
+extern int blk_nohighio;
 
 extern unsigned long embedded_sysmap_start;
 extern unsigned long embedded_sysmap_end;
@@ -89,26 +92,6 @@
 struct machdep_calls ppc_md;
 
 /*
- * Perhaps we can put the pmac screen_info[] here
- * on pmac as well so we don't need the ifdef's.
- * Until we get multiple-console support in here
- * that is.  -- Cort
- * Maybe tie it to serial consoles, since this is really what
- * these processors use on existing boards.  -- Dan
- */ 
-struct screen_info screen_info = {
-	0, 25,			/* orig-x, orig-y */
-	0,			/* unused */
-	0,			/* orig-video-page */
-	0,			/* orig-video-mode */
-	80,			/* orig-video-cols */
-	0,0,0,			/* ega_ax, ega_bx, ega_cx */
-	25,			/* orig-video-lines */
-	1,			/* orig-video-isVGA */
-	16			/* orig-video-points */
-};
-
-/*
  * These are used in binfmt_elf.c to put aux entries on the stack
  * for each elf executable being started.
  */
@@ -116,7 +99,7 @@
 int icache_bsize;
 int ucache_bsize;
 
-static struct console udbg_console = {
+struct console udbg_console = {
 	name:	"udbg",
 	write:	udbg_console_write,
 	flags:	CON_PRINTBUFFER,
@@ -135,9 +118,9 @@
 
 	/* pSeries systems are identified in prom.c via OF. */
 	if ( itLpNaca.xLparInstalled == 1 )
-		naca->platform = PLATFORM_ISERIES_LPAR;
+		systemcfg->platform = PLATFORM_ISERIES_LPAR;
 	
-	switch (naca->platform) {
+	switch (systemcfg->platform) {
 	case PLATFORM_ISERIES_LPAR:
 		iSeries_init_early();
 		break;
@@ -161,38 +144,36 @@
 #endif
 	}
 
-	if (naca->platform & PLATFORM_PSERIES) {
+	if (systemcfg->platform & PLATFORM_PSERIES) {
 		register_console(&udbg_console);
-		preferred_console = -1;
+		udbg_printf("---- start early boot console ----\n");
 	}
 
 	printk("Starting Linux PPC64 %s\n", UTS_RELEASE);
 
 	printk("-----------------------------------------------------\n");
-	printk("naca                       = 0x%p\n", naca);
-	printk("naca->processorCount       = 0x%x\n", naca->processorCount);
-	printk("naca->physicalMemorySize   = 0x%lx\n", naca->physicalMemorySize);
-	printk("naca->dCacheL1LineSize     = 0x%x\n", naca->dCacheL1LineSize);
-	printk("naca->dCacheL1LogLineSize  = 0x%x\n", naca->dCacheL1LogLineSize);
-	printk("naca->dCacheL1LinesPerPage = 0x%x\n", naca->dCacheL1LinesPerPage);
-	printk("naca->iCacheL1LineSize     = 0x%x\n", naca->iCacheL1LineSize);
-	printk("naca->iCacheL1LogLineSize  = 0x%x\n", naca->iCacheL1LogLineSize);
-	printk("naca->iCacheL1LinesPerPage = 0x%x\n", naca->iCacheL1LinesPerPage);
-	printk("naca->pftSize              = 0x%lx\n", naca->pftSize);
-	printk("naca->debug_switch         = 0x%lx\n", naca->debug_switch);
-	printk("naca->interrupt_controller = 0x%lx\n", naca->interrupt_controller);
-	printk("htab_data.htab             = 0x%p\n", htab_data.htab);
-	printk("htab_data.num_ptegs        = 0x%lx\n", htab_data.htab_num_ptegs);
+	printk("naca                          = 0x%p\n", naca);
+	printk("naca->pftSize                 = 0x%lx\n", naca->pftSize);
+	printk("naca->paca                    = 0x%lx\n\n", naca->paca);
+	printk("systemcfg                     = 0x%p\n", systemcfg);
+	printk("systemcfg->platform           = 0x%x\n", systemcfg->platform);
+	printk("systemcfg->processor          = 0x%x\n", systemcfg->processor);
+	printk("systemcfg->processorCount     = 0x%lx\n", systemcfg->processorCount);
+	printk("systemcfg->physicalMemorySize = 0x%lx\n", systemcfg->physicalMemorySize);
+	printk("systemcfg->dCacheL1LineSize   = 0x%x\n", systemcfg->dCacheL1LineSize);
+	printk("systemcfg->iCacheL1LineSize   = 0x%x\n", systemcfg->iCacheL1LineSize);
+	printk("htab_data.htab                = 0x%p\n", htab_data.htab);
+	printk("htab_data.num_ptegs           = 0x%lx\n", htab_data.htab_num_ptegs);
 	printk("-----------------------------------------------------\n");
 
-	if (naca->platform & PLATFORM_PSERIES) {
+	if (systemcfg->platform & PLATFORM_PSERIES) {
 		finish_device_tree();
 		chrp_init(r3, r4, r5, r6, r7);
 	}
 
 	mm_init_ppc64();
 
-	switch (naca->platform) {
+	switch (systemcfg->platform) {
 	    case PLATFORM_ISERIES_LPAR:
 		iSeries_init();
 		break;
@@ -206,14 +187,13 @@
 
 /* This is called just before console_init().
  * It will be obsolete when Linux gets real early console support (2.5?)
- * We need to hack preferred_console to retain the correct behavior
  */
 void setup_before_console_init(void)
 {
-	if (naca->platform & PLATFORM_PSERIES) {
-		int save = preferred_console;
+	if (systemcfg->platform & PLATFORM_PSERIES) {
 		unregister_console(&udbg_console);
-		preferred_console = save;
+		udbg_console.next = NULL;
+		udbg_printf("---- end early boot console ----\n");
 	}
 }
 
@@ -298,7 +278,7 @@
 	 * Assume here that all clock rates are the same in a
 	 * smp system.  -- Cort
 	 */
-	if (naca->platform != PLATFORM_ISERIES_LPAR) {
+	if (systemcfg->platform != PLATFORM_ISERIES_LPAR) {
 		struct device_node *cpu_node;
 		int *fp;
 
@@ -333,18 +313,18 @@
 {
 }
 struct seq_operations cpuinfo_op = {
-	start:	c_start,
-	next:	c_next,
-	stop:	c_stop,
-	show:	show_cpuinfo,
+	.start =c_start,
+	.next =	c_next,
+	.stop =	c_stop,
+	.show =	show_cpuinfo,
 };
 
 /*
- * Fetch the cmd_line from open firmware. */
+ * Fetch the cmd_line from open firmware. 
+ */
 void parse_cmd_line(unsigned long r3, unsigned long r4, unsigned long r5,
 		  unsigned long r6, unsigned long r7)
 {
-	struct device_node *chosen;
 	char *p;
 
 #ifdef CONFIG_BLK_DEV_INITRD
@@ -356,6 +336,40 @@
 	}
 #endif
 
+	/* Hack -- add console=ttySn,9600 if necessary */
+	if(strstr(cmd_line, "console=") == NULL) {
+		struct device_node *prom_stdout = find_path_device(of_stdout_device);
+		u32 *reg;
+		int i;
+		char *name, *val = NULL;
+		printk("of_stdout_device %s\n", of_stdout_device);
+		if (prom_stdout) {
+			name = (char *)get_property(prom_stdout, "name", NULL);
+			if (name) {
+				if (strcmp(name, "serial") == 0) {
+					reg = (u32 *)get_property(prom_stdout, "reg", &i);
+					if (i > 8) {
+						switch (reg[1]) {
+						    case 0x3f8: val = "ttyS0,9600"; break; 
+						    case 0x2f8: val = "ttyS1,9600"; break; 
+						    case 0x898: val = "ttyS2,9600"; break; 
+						    case 0x890: val = "ttyS3,9600"; break; 
+						}
+					}
+				} else if (strcmp(name, "vty") == 0) {
+					/* pSeries LPAR virtual console */
+					val = "hvc0";
+				}
+				if (val) {
+					i = strlen(cmd_line);
+					sprintf(cmd_line + i, " AUTOCONSOLE console=%s", val);
+					printk("console= not found, add console=%s\ncmd_line is now %s\n",
+					       val, cmd_line);
+				}
+			}
+		}
+	}	
+
 	/* Look for mem= option on command line */
 	if (strstr(cmd_line, "mem=")) {
 		char *q;
@@ -457,6 +471,7 @@
 }	
 
 extern void (*calibrate_delay)(void);
+extern void sort_exception_table(void);
 
 /*
  * Called into from start_kernel, after lock_kernel has been called.
@@ -469,6 +484,8 @@
 	extern char _etext[], _edata[];
 	extern void do_init_bootmem(void);
 
+	blk_nohighio = 1;
+
 	calibrate_delay = ppc64_calibrate_delay;
 
 	ppc64_boot_msg(0x12, "Setup Arch");
@@ -494,8 +511,8 @@
 	 * Systems with OF can look in the properties on the cpu node(s)
 	 * for a possibly more accurate value.
 	 */
-	dcache_bsize = naca->dCacheL1LineSize; 
-	icache_bsize = naca->iCacheL1LineSize; 
+	dcache_bsize = systemcfg->dCacheL1LineSize; 
+	icache_bsize = systemcfg->iCacheL1LineSize; 
 
 	/* reboot on panic */
 	panic_timeout = 180;
@@ -515,106 +532,10 @@
 	ppc_md.setup_arch();
 
 	paging_init();
+	sort_exception_table();
 	ppc64_boot_msg(0x15, "Setup Done");
 }
 
-#ifdef CONFIG_IDE
-
-/* Convert the shorts/longs in hd_driveid from little to big endian;
- * chars are endian independant, of course, but strings need to be flipped.
- * (Despite what it says in drivers/block/ide.h, they come up as little
- * endian...)
- *
- * Changes to linux/hdreg.h may require changes here. */
-void ppc64_ide_fix_driveid(struct hd_driveid *id)
-{
-        int i;
-	unsigned short *stringcast;
-
-	id->config         = __le16_to_cpu(id->config);
-	id->cyls           = __le16_to_cpu(id->cyls);
-	id->reserved2      = __le16_to_cpu(id->reserved2);
-	id->heads          = __le16_to_cpu(id->heads);
-	id->track_bytes    = __le16_to_cpu(id->track_bytes);
-	id->sector_bytes   = __le16_to_cpu(id->sector_bytes);
-	id->sectors        = __le16_to_cpu(id->sectors);
-	id->vendor0        = __le16_to_cpu(id->vendor0);
-	id->vendor1        = __le16_to_cpu(id->vendor1);
-	id->vendor2        = __le16_to_cpu(id->vendor2);
-	stringcast = (unsigned short *)&id->serial_no[0];
-	for (i = 0; i < (20/2); i++)
-	        stringcast[i] = __le16_to_cpu(stringcast[i]);
-	id->buf_type       = __le16_to_cpu(id->buf_type);
-	id->buf_size       = __le16_to_cpu(id->buf_size);
-	id->ecc_bytes      = __le16_to_cpu(id->ecc_bytes);
-	stringcast = (unsigned short *)&id->fw_rev[0];
-	for (i = 0; i < (8/2); i++)
-	        stringcast[i] = __le16_to_cpu(stringcast[i]);
-	stringcast = (unsigned short *)&id->model[0];
-	for (i = 0; i < (40/2); i++)
-	        stringcast[i] = __le16_to_cpu(stringcast[i]);
-	id->dword_io       = __le16_to_cpu(id->dword_io);
-	id->reserved50     = __le16_to_cpu(id->reserved50);
-	id->field_valid    = __le16_to_cpu(id->field_valid);
-	id->cur_cyls       = __le16_to_cpu(id->cur_cyls);
-	id->cur_heads      = __le16_to_cpu(id->cur_heads);
-	id->cur_sectors    = __le16_to_cpu(id->cur_sectors);
-	id->cur_capacity0  = __le16_to_cpu(id->cur_capacity0);
-	id->cur_capacity1  = __le16_to_cpu(id->cur_capacity1);
-	id->lba_capacity   = __le32_to_cpu(id->lba_capacity);
-	id->dma_1word      = __le16_to_cpu(id->dma_1word);
-	id->dma_mword      = __le16_to_cpu(id->dma_mword);
-	id->eide_pio_modes = __le16_to_cpu(id->eide_pio_modes);
-	id->eide_dma_min   = __le16_to_cpu(id->eide_dma_min);
-	id->eide_dma_time  = __le16_to_cpu(id->eide_dma_time);
-	id->eide_pio       = __le16_to_cpu(id->eide_pio);
-	id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy);
-	for (i = 0; i < 2; i++)
-		id->words69_70[i] = __le16_to_cpu(id->words69_70[i]);
-        for (i = 0; i < 4; i++)
-                id->words71_74[i] = __le16_to_cpu(id->words71_74[i]);
-	id->queue_depth	   = __le16_to_cpu(id->queue_depth);
-	for (i = 0; i < 4; i++)
-		id->words76_79[i] = __le16_to_cpu(id->words76_79[i]);
-	id->major_rev_num  = __le16_to_cpu(id->major_rev_num);
-	id->minor_rev_num  = __le16_to_cpu(id->minor_rev_num);
-	id->command_set_1  = __le16_to_cpu(id->command_set_1);
-	id->command_set_2  = __le16_to_cpu(id->command_set_2);
-	id->cfsse          = __le16_to_cpu(id->cfsse);
-	id->cfs_enable_1   = __le16_to_cpu(id->cfs_enable_1);
-	id->cfs_enable_2   = __le16_to_cpu(id->cfs_enable_2);
-	id->csf_default    = __le16_to_cpu(id->csf_default);
-	id->dma_ultra      = __le16_to_cpu(id->dma_ultra);
-	id->word89         = __le16_to_cpu(id->word89);
-	id->word90         = __le16_to_cpu(id->word90);
-	id->CurAPMvalues   = __le16_to_cpu(id->CurAPMvalues);
-	id->word92         = __le16_to_cpu(id->word92);
-	id->hw_config      = __le16_to_cpu(id->hw_config);
-	id->acoustic       = __le16_to_cpu(id->acoustic);
-	for (i = 0; i < 5; i++)
-		id->words95_99[i]  = __le16_to_cpu(id->words95_99[i]);
-	id->lba_capacity_2 = __le64_to_cpu(id->lba_capacity_2);
-	for (i = 0; i < 21; i++)
-		id->words104_125[i]  = __le16_to_cpu(id->words104_125[i]);
-	id->last_lun       = __le16_to_cpu(id->last_lun);
-	id->word127        = __le16_to_cpu(id->word127);
-	id->dlf            = __le16_to_cpu(id->dlf);
-	id->csfo           = __le16_to_cpu(id->csfo);
-	for (i = 0; i < 26; i++)
-		id->words130_155[i] = __le16_to_cpu(id->words130_155[i]);
-	id->word156        = __le16_to_cpu(id->word156);
-	for (i = 0; i < 3; i++)
-		id->words157_159[i] = __le16_to_cpu(id->words157_159[i]);
-	id->cfa_power=__le16_to_cpu(id->cfa_power);
-	for (i = 0; i < 15; i++)
-		id->words161_175[i] = __le16_to_cpu(id->words161_175[i]);
-	for (i = 0; i < 29; i++)
-		id->words176_205[i] = __le16_to_cpu(id->words176_205[i]);
-	for (i = 0; i < 48; i++)
-		id->words206_254[i] = __le16_to_cpu(id->words206_254[i]);
-	id->integrity_word=__le16_to_cpu(id->integrity_word);
-}
-#endif
 
 /* ToDo: do something useful if ppc_md is not yet setup. */
 #define PPC64_LINUX_FUNCTION 0x0f000000
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/signal.c linux-2.4.21-pre6/arch/ppc64/kernel/signal.c
--- linux-2.4.20/arch/ppc64/kernel/signal.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/signal.c	2003-03-26 23:49:54.000000000 +0000
@@ -43,24 +43,44 @@
 #endif
 
 #define GP_REGS_SIZE	MIN(sizeof(elf_gregset_t), sizeof(struct pt_regs))
+#define FP_REGS_SIZE	sizeof(elf_fpregset_t)
 
-/* 
- * These are the flags in the MSR that the user is allowed to change
- * by modifying the saved value of the MSR on the stack.  SE and BE
- * should not be in this list since gdb may want to change these.  I.e,
- * you should be able to step out of a signal handler to see what
- * instruction executes next after the signal handler completes.
- * Alternately, if you stepped into a signal handler, you should be
- * able to continue 'til the next breakpoint from within the signal
- * handler, even if the handler returns.
+#define TRAMP_TRACEBACK	3
+#define TRAMP_SIZE	6
+
+/*
+ * When we have signals to deliver, we set up on the user stack,
+ * going down from the original stack pointer:
+ *	1) a sigframe/rt_sigframe struct which contains the sigcontext/ucontext	
+ *	2) a gap of __SIGNAL_FRAMESIZE bytes which acts as a dummy caller
+ *	   frame for the signal handler.
  */
-#define MSR_USERCHANGE	(MSR_FE0 | MSR_FE1)
 
-int do_signal(sigset_t *oldset, struct pt_regs *regs);
+struct sigframe {
+	/* sys_sigreturn requires the sigcontext be the first field */
+	struct sigcontext sc;
+	unsigned int tramp[TRAMP_SIZE];
+	/* 64 bit ABI allows for 288 bytes below sp before decrementing it. */
+	char abigap[288];
+};
+
+struct rt_sigframe {
+	/* sys_rt_sigreturn requires the ucontext be the first field */
+	struct ucontext uc;
+	unsigned long _unused[2];
+	unsigned int tramp[TRAMP_SIZE];
+	struct siginfo *pinfo;
+	void *puc;
+	struct siginfo info;
+	/* 64 bit ABI allows for 288 bytes below sp before decrementing it. */
+	char abigap[288];
+};
+
 extern long sys_wait4(pid_t pid, unsigned int *stat_addr,
 		     int options, /*unsigned long*/ struct rusage *ru);
 
-int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
+int
+copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
 {
 	if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
 		return -EFAULT;
@@ -95,18 +115,16 @@
 	}
 }
 
+int do_signal(sigset_t *oldset, struct pt_regs *regs);
+
 /*
  * Atomically swap in the new signal mask, and wait for a signal.
  */
-long sys_sigsuspend(old_sigset_t mask, int p2, int p3, int p4, int p6, int p7,
+asmlinkage long
+sys_sigsuspend(old_sigset_t mask, int p2, int p3, int p4, int p6, int p7,
 	       struct pt_regs *regs)
 {
 	sigset_t saveset;
-  
-        PPCDBG(PPCDBG_SYS64X, "sys_sigsuspend - running - pid=%ld current=%lx comm=%s \n",
-                current->pid, current, current->comm);
-
-
 
 	mask &= _BLOCKABLE;
 	spin_lock_irq(&current->sigmask_lock);
@@ -115,7 +133,9 @@
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
 
-	regs->gpr[3] = -EINTR;
+	regs->result = -EINTR;
+	regs->gpr[3] = EINTR;
+	regs->ccr |= 0x10000000;
 	while (1) {
 		current->state = TASK_INTERRUPTIBLE;
 		schedule();
@@ -132,16 +152,13 @@
 	}
 }
 
-long sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, int p3, int p4, int p6,
+asmlinkage long
+sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, int p3, int p4, int p6,
 		  int p7, struct pt_regs *regs)
 {
 	sigset_t saveset, newset;
 
-  
-        PPCDBG(PPCDBG_SYS64X, "sys_rt_sigsuspend - running - pid=%ld current=%lx comm=%s \n",
-                current->pid, current, current->comm);
-	
-  /* XXX: Don't preclude handling different sized sigset_t's.  */
+	/* XXX: Don't preclude handling different sized sigset_t's.  */
 	if (sigsetsize != sizeof(sigset_t))
 		return -EINVAL;
 
@@ -155,7 +172,9 @@
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
 
-	regs->gpr[3] = -EINTR;
+	regs->result = -EINTR;
+	regs->gpr[3] = EINTR;
+	regs->ccr |= 0x10000000;
 	while (1) {
 		current->state = TASK_INTERRUPTIBLE;
 		schedule();
@@ -164,31 +183,24 @@
 	}
 }
 
-
-
-asmlinkage long sys_sigaltstack(const stack_t *uss, stack_t *uoss)
+asmlinkage long
+sys_sigaltstack(const stack_t *uss, stack_t *uoss, unsigned long r5,
+		unsigned long r6, unsigned long r7, unsigned long r8,
+		struct pt_regs *regs)
 {
-  struct pt_regs *regs = (struct pt_regs *) &uss;
-  
-  PPCDBG(PPCDBG_SYS64X, "sys_sigaltstack - running - pid=%ld current=%lx comm=%s \n",
-          current->pid, current, current->comm);
-
-  return do_sigaltstack(uss, uoss, regs->gpr[1]);
+        return do_sigaltstack(uss, uoss, regs->gpr[1]);
 }
 
-long sys_sigaction(int sig, const struct old_sigaction *act,
+asmlinkage long
+sys_sigaction(int sig, const struct old_sigaction *act,
 	      struct old_sigaction *oact)
 {
 	struct k_sigaction new_ka, old_ka;
 	int ret;
 
-        PPCDBG(PPCDBG_SYS64X, "sys_sigaction - running - pid=%ld current=%lx comm=%s \n",
-                current->pid, current, current->comm);
-
- 
-
 	if (act) {
 		old_sigset_t mask;
+
 		if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
 		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
 		    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
@@ -199,7 +211,6 @@
 	}
 
 	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
-
 	if (!ret && oact) {
 		if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
 		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
@@ -209,193 +220,212 @@
 		__put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
 	}
 
-
- 
-
 	return ret;
 }
 
 /*
- * When we have signals to deliver, we set up on the
- * user stack, going down from the original stack pointer:
- *	a sigregs struct
- *	one or more sigcontext structs
- *	a gap of __SIGNAL_FRAMESIZE bytes
- *
- * Each of these things must be a multiple of 16 bytes in size.
- *
- * XXX ultimately we will have to stack up a siginfo and ucontext
- * for each rt signal.
+ * Set up the sigcontext for the signal frame.
  */
-struct sigregs {
-	elf_gregset_t	gp_regs;
-	double		fp_regs[ELF_NFPREG];
-	unsigned int	tramp[2];
-	/* 64 bit API allows for 288 bytes below sp before 
-	   decrementing it. */
-	int		abigap[72];
-};
 
+static int
+setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
+		 int signr, sigset_t *set, unsigned long handler)
+{
+	int err = 0;
+
+	if (regs->msr & MSR_FP)
+		giveup_fpu(current);
+
+	current->thread.saved_msr = regs->msr & ~(MSR_FP | MSR_FE0 | MSR_FE1);
+	regs->msr = current->thread.saved_msr | current->thread.fpexc_mode;
+	current->thread.saved_softe = regs->softe;
+
+	err |= __put_user(&sc->gp_regs, &sc->regs);
+	err |= __copy_to_user(&sc->gp_regs, regs, GP_REGS_SIZE);
+	err |= __copy_to_user(&sc->fp_regs, &current->thread.fpr, FP_REGS_SIZE);
+	err |= __put_user(signr, &sc->signal);
+	err |= __put_user(handler, &sc->handler);
+	if (set != NULL)
+		err |=  __put_user(set->sig[0], &sc->oldmask);
 
+	regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1);
+	current->thread.fpscr = 0;
 
-struct rt_sigframe
+	return err;
+}
+
+/*
+ * Restore the sigcontext from the signal frame.
+ */
+
+static int
+restore_sigcontext(struct pt_regs *regs, sigset_t *set, struct sigcontext *sc)
 {
-	unsigned long	_unused[2];
-	struct siginfo *pinfo;
-	void *puc;
-	struct siginfo info;
-	struct ucontext uc;
-};
+	unsigned int err = 0;
 
+	if (regs->msr & MSR_FP)
+		giveup_fpu(current);
+
+	err |= __copy_from_user(regs, &sc->gp_regs, GP_REGS_SIZE);
+	err |= __copy_from_user(&current->thread.fpr, &sc->fp_regs, FP_REGS_SIZE);
+	current->thread.fpexc_mode = regs->msr & (MSR_FE0 | MSR_FE1);
+	if (set != NULL)
+		err |=  __get_user(set->sig[0], &sc->oldmask);
+
+	/* Don't allow the signal handler to change these modulo FE{0,1} */
+	regs->msr = current->thread.saved_msr & ~(MSR_FP | MSR_FE0 | MSR_FE1);
+	regs->softe = current->thread.saved_softe;
+
+	return err;
+}
 
 /*
- *  When we have rt signals to deliver, we set up on the
- *  user stack, going down from the original stack pointer:
- *	   a sigregs struct
- *	   one rt_sigframe struct (siginfo + ucontext)
- *	   a gap of __SIGNAL_FRAMESIZE bytes
- *
- *  Each of these things must be a multiple of 16 bytes in size.
- *
+ * Allocate space for the signal frame
  */
+static inline void *
+get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
+{
+        unsigned long newsp;
 
-int sys_rt_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5,
-		     unsigned long r6, unsigned long r7, unsigned long r8,
-		     struct pt_regs *regs)
-{
-	struct rt_sigframe *rt_sf;
-	struct sigcontext_struct sigctx;
-	struct sigregs *sr;
-	int ret;
-	elf_gregset_t saved_regs;  /* an array of ELF_NGREG unsigned longs */
+        /* Default to using normal stack */
+        newsp = regs->gpr[1];
+
+	if (ka->sa.sa_flags & SA_ONSTACK) {
+		if (! on_sig_stack(regs->gpr[1]))
+			newsp = (current->sas_ss_sp + current->sas_ss_size);
+	}
+
+        return (void *)((newsp - frame_size) & -8ul);
+}
+
+static int
+setup_trampoline(unsigned int syscall, unsigned int *tramp)
+{
+	int i, err = 0;
+
+	/* addi r1, r1, __SIGNAL_FRAMESIZE  # Pop the dummy stackframe */
+	err |= __put_user(0x38210000UL | (__SIGNAL_FRAMESIZE & 0xffff), &tramp[0]);
+	/* li r0, __NR_[rt_]sigreturn| */
+	err |= __put_user(0x38000000UL | (syscall & 0xffff), &tramp[1]);
+	/* sc */
+	err |= __put_user(0x44000002UL, &tramp[2]);
+
+	/* Minimal traceback info */
+	for (i=TRAMP_TRACEBACK; i < TRAMP_SIZE ;i++)
+		err |= __put_user(0, &tramp[i]);
+
+	if (!err)
+		flush_icache_range((unsigned long) &tramp[0],
+			   (unsigned long) &tramp[TRAMP_SIZE]);
+
+	return err;
+}
+
+
+asmlinkage int
+sys_rt_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5,
+		 unsigned long r6, unsigned long r7, unsigned long r8,
+		 struct pt_regs *regs)
+{
+	struct ucontext *uc = (struct ucontext *)regs->gpr[1];
 	sigset_t set;
 	stack_t st;
-	unsigned long prevsp;
 
-	rt_sf = (struct rt_sigframe *)(regs->gpr[1] + __SIGNAL_FRAMESIZE);
-	if (copy_from_user(&sigctx, &rt_sf->uc.uc_mcontext, sizeof(sigctx))
-	    || copy_from_user(&set, &rt_sf->uc.uc_sigmask, sizeof(set))
-	    || copy_from_user(&st, &rt_sf->uc.uc_stack, sizeof(st)))
+	if (verify_area(VERIFY_READ, uc, sizeof(*uc)))
 		goto badframe;
+
+	if (__copy_from_user(&set, &uc->uc_sigmask, sizeof(set)))
+		goto badframe;
+
 	sigdelsetmask(&set, ~_BLOCKABLE);
 	spin_lock_irq(&current->sigmask_lock);
 	current->blocked = set;
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
 
-	rt_sf++;			/* Look at next rt_sigframe */
-	if (rt_sf == (struct rt_sigframe *)(sigctx.regs)) {
-		/* Last stacked signal - restore registers -
-		 * sigctx is initialized to point to the 
-		 * preamble frame (where registers are stored) 
-		 * see handle_signal()
-		 */
-		sr = (struct sigregs *) sigctx.regs;
-		if (regs->msr & MSR_FP )
-			giveup_fpu(current);
-		if (copy_from_user(saved_regs, &sr->gp_regs,
-				   sizeof(sr->gp_regs)))
-			goto badframe;
-		saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE)
-			| (saved_regs[PT_MSR] & MSR_USERCHANGE);
-		saved_regs[PT_SOFTE] = regs->softe;
-		memcpy(regs, saved_regs, GP_REGS_SIZE);
-		if (copy_from_user(current->thread.fpr, &sr->fp_regs,
-				   sizeof(sr->fp_regs)))
-			goto badframe;
-		/* This function sets back the stack flags into
-		   the current task structure.  */
-		sys_sigaltstack(&st, NULL);
-
-		ret = regs->result;
-	} else {
-		/* More signals to go */
-		/* Set up registers for next signal handler */
-		regs->gpr[1] = (unsigned long)rt_sf - __SIGNAL_FRAMESIZE;
-		if (copy_from_user(&sigctx, &rt_sf->uc.uc_mcontext, sizeof(sigctx)))
-			goto badframe;
-		sr = (struct sigregs *) sigctx.regs;
-		regs->gpr[3] = ret = sigctx.signal;
-		/* Get the siginfo   */
-		get_user(regs->gpr[4], (unsigned long *)&rt_sf->pinfo);
-		/* Get the ucontext */
-		get_user(regs->gpr[5], (unsigned long *)&rt_sf->puc);
-		regs->gpr[6] = (unsigned long) rt_sf;
-
-		regs->link = (unsigned long) &sr->tramp;
-		regs->nip = sigctx.handler;
-		if (get_user(prevsp, &sr->gp_regs[PT_R1])
-		    || put_user(prevsp, (unsigned long *) regs->gpr[1]))
-			goto badframe;
-	}
-	return ret;
+	if (restore_sigcontext(regs, NULL, &uc->uc_mcontext))
+		goto badframe;
+
+	if (__copy_from_user(&st, &uc->uc_stack, sizeof(st)))
+		goto badframe;
+
+	/* This function sets back the stack flags into
+	   the current task structure.  */
+	sys_sigaltstack(&st, NULL, 0, 0, 0, 0, regs);
+
+	return regs->result;
 
 badframe:
 	do_exit(SIGSEGV);
 }
 
 static void
-setup_rt_frame(struct pt_regs *regs, struct sigregs *frame,
-	       signed long newsp)
+setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info,
+		sigset_t *set, struct pt_regs *regs)
 {
-	struct rt_sigframe *rt_sf = (struct rt_sigframe *) newsp;
 	/* Handler is *really* a pointer to the function descriptor for
 	 * the signal routine.  The first entry in the function
 	 * descriptor is the entry address of signal and the second
 	 * entry is the TOC value we need to use.
 	 */
-        struct funct_descr_entry {
-                     unsigned long entry;
-                     unsigned long toc;
-	};
-  
-	struct funct_descr_entry * funct_desc_ptr;
-	unsigned long temp_ptr;
+	func_descr_t *funct_desc_ptr;
+	struct rt_sigframe *frame;
+	unsigned long newsp;
+	int err = 0;
 
-	/* Set up preamble frame */
-	if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
-		goto badframe;
-	if (regs->msr & MSR_FP)
-		giveup_fpu(current);
-	if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE)
-	    || __copy_to_user(&frame->fp_regs, current->thread.fpr,
-			      ELF_NFPREG * sizeof(double))
-	    || __put_user(0x38000000UL + __NR_rt_sigreturn, &frame->tramp[0])	/* li r0, __NR_rt_sigreturn */
-	    || __put_user(0x44000002UL, &frame->tramp[1]))	/* sc */
-		goto badframe;
-	flush_icache_range((unsigned long) &frame->tramp[0],
-			   (unsigned long) &frame->tramp[2]);
-
-	/* Retrieve rt_sigframe from stack and
-	   set up registers for signal handler
-	*/
-	newsp -= __SIGNAL_FRAMESIZE;
-
-        if ( get_user(temp_ptr, &rt_sf->uc.uc_mcontext.handler)) {
-		goto badframe;
-	}
+	frame = get_sigframe(ka, regs, sizeof(*frame));
 
-        funct_desc_ptr = ( struct funct_descr_entry *) temp_ptr;
-        
-	if (put_user(regs->gpr[1], (unsigned long *)newsp)
-	    || get_user(regs->nip, &funct_desc_ptr->entry)
-            || get_user(regs->gpr[2], &funct_desc_ptr->toc)
-	    || get_user(regs->gpr[3], &rt_sf->uc.uc_mcontext.signal)
-	    || get_user(regs->gpr[4], (unsigned long *)&rt_sf->pinfo)
-	    || get_user(regs->gpr[5], (unsigned long *)&rt_sf->puc))
-		goto badframe;
+	if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
+		goto give_sigsegv;
 
+	err |= __put_user(&frame->info, &frame->pinfo);
+	err |= __put_user(&frame->uc, &frame->puc);
+	err |= copy_siginfo_to_user(&frame->info, info);
+	if (err)
+		goto give_sigsegv;
+
+	/* Create the ucontext.  */
+	err |= __put_user(0, &frame->uc.uc_flags);
+	err |= __put_user(0, &frame->uc.uc_link);
+	err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
+	err |= __put_user(sas_ss_flags(regs->gpr[1]),
+			  &frame->uc.uc_stack.ss_flags);
+	err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+	err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, signr, NULL,
+				(unsigned long)ka->sa.sa_handler);
+	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+	if (err)
+		goto give_sigsegv;
+
+	/* Set up to return from userspace. */
+	err |= setup_trampoline(__NR_rt_sigreturn, &frame->tramp[0]);
+	if (err)
+		goto give_sigsegv;
+
+	funct_desc_ptr = (func_descr_t *) ka->sa.sa_handler;
+
+	/* Allocate a dummy caller frame for the signal handler. */
+	newsp = (unsigned long)frame - __SIGNAL_FRAMESIZE;
+	err |= put_user(0, (unsigned long *)newsp);
+
+	/* Set up "regs" so we "return" to the signal handler. */
+	err |= get_user(regs->nip, &funct_desc_ptr->entry);
+	regs->link = (unsigned long) &frame->tramp[0];
 	regs->gpr[1] = newsp;
-	regs->gpr[6] = (unsigned long) rt_sf;
-	regs->link = (unsigned long) frame->tramp;
+	err |= get_user(regs->gpr[2], &funct_desc_ptr->toc);
+	regs->gpr[3] = signr;
+	err |= get_user(regs->gpr[4], (unsigned long *)&frame->pinfo);
+	err |= get_user(regs->gpr[5], (unsigned long *)&frame->puc);
+	regs->gpr[6] = (unsigned long) frame;
+	if (err)
+		goto give_sigsegv;
 
-	
 	return;
 
-badframe:
+give_sigsegv:
 #if DEBUG_SIG
-	printk("badframe in setup_rt_frame, regs=%p frame=%p newsp=%lx\n",
-	       regs, frame, newsp);
+	printk("badframe in setup_rt_frame, regs=%p frame=%p, newsp=0x%lx\n",
+		regs, frame, newsp);
 #endif
 	do_exit(SIGSEGV);
 }
@@ -403,131 +433,79 @@
 /*
  * Do a signal return; undo the signal stack.
  */
-long sys_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5,
-		   unsigned long r6, unsigned long r7, unsigned long r8,
-		   struct pt_regs *regs)
-{
-	struct sigcontext_struct *sc, sigctx;
-	struct sigregs *sr;
-	long ret;
-	elf_gregset_t saved_regs;  /* an array of ELF_NGREG unsigned longs */
+asmlinkage long
+sys_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5,
+	      unsigned long r6, unsigned long r7, unsigned long r8,
+	      struct pt_regs *regs)
+{
+	struct sigcontext *sc = (struct sigcontext *)regs->gpr[1];
 	sigset_t set;
-	unsigned long prevsp;
 
-        sc = (struct sigcontext_struct *)(regs->gpr[1] + __SIGNAL_FRAMESIZE);
-	if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
+	if (verify_area(VERIFY_READ, sc, sizeof(*sc)))
+		goto badframe;
+
+	if (restore_sigcontext(regs, &set, sc))
 		goto badframe;
 
-	set.sig[0] = sigctx.oldmask;
-#if _NSIG_WORDS > 1
-	set.sig[1] = sigctx._unused[3];
-#endif
 	sigdelsetmask(&set, ~_BLOCKABLE);
 	spin_lock_irq(&current->sigmask_lock);
 	current->blocked = set;
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
 
-	sc++;			/* Look at next sigcontext */
-	if (sc == (struct sigcontext_struct *)(sigctx.regs)) {
-		/* Last stacked signal - restore registers */
-		sr = (struct sigregs *) sigctx.regs;
-		if (regs->msr & MSR_FP )
-			giveup_fpu(current);
-		if (copy_from_user(saved_regs, &sr->gp_regs,
-				   sizeof(sr->gp_regs)))
-			goto badframe;
-		saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE)
-			| (saved_regs[PT_MSR] & MSR_USERCHANGE);
-		saved_regs[PT_SOFTE] = regs->softe;
-		memcpy(regs, saved_regs, GP_REGS_SIZE);
-
-		if (copy_from_user(current->thread.fpr, &sr->fp_regs,
-				   sizeof(sr->fp_regs)))
-			goto badframe;
-
-		ret = regs->result;
-
-	} else {
-		/* More signals to go */
-		regs->gpr[1] = (unsigned long)sc - __SIGNAL_FRAMESIZE;
-		if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
-			goto badframe;
-		sr = (struct sigregs *) sigctx.regs;
-		regs->gpr[3] = ret = sigctx.signal;
-		regs->gpr[4] = (unsigned long) sc;
-		regs->link = (unsigned long) &sr->tramp;
-		regs->nip = sigctx.handler;
-
-		if (get_user(prevsp, &sr->gp_regs[PT_R1])
-		    || put_user(prevsp, (unsigned long *) regs->gpr[1]))
-			goto badframe;
-	}
-	return ret;
+	return regs->result;
 
 badframe:
 	do_exit(SIGSEGV);
 }	
 
-/*
- * Set up a signal frame.
- */
+
 static void
-setup_frame(struct pt_regs *regs, struct sigregs *frame,
-            unsigned long newsp)
+setup_frame(int signr, struct k_sigaction *ka, sigset_t *set,
+	    struct pt_regs *regs)
 {
-
 	/* Handler is *really* a pointer to the function descriptor for
 	 * the signal routine.  The first entry in the function
 	 * descriptor is the entry address of signal and the second
 	 * entry is the TOC value we need to use.
 	 */
-	struct funct_descr_entry {
-		unsigned long entry;
-		unsigned long toc;
-	};
-  
-	struct funct_descr_entry * funct_desc_ptr;
-	unsigned long temp_ptr;
+	func_descr_t *funct_desc_ptr;
+	struct sigframe *frame;
+	unsigned long newsp;
+	int err = 0;
+
+	frame = get_sigframe(ka, regs, sizeof(*frame));
 
-	struct sigcontext_struct *sc = (struct sigcontext_struct *) newsp;
-  
 	if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
 		goto badframe;
-	if (regs->msr & MSR_FP)
-		giveup_fpu(current);
-	if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE)
-	    || __copy_to_user(&frame->fp_regs, current->thread.fpr,
-			      ELF_NFPREG * sizeof(double))
-	    || __put_user(0x38000000UL + __NR_sigreturn, &frame->tramp[0])    /* li r0, __NR_sigreturn */
-	    || __put_user(0x44000002UL, &frame->tramp[1]))   /* sc */
-		goto badframe;
-	flush_icache_range((unsigned long) &frame->tramp[0],
-			   (unsigned long) &frame->tramp[2]);
 
-	newsp -= __SIGNAL_FRAMESIZE;
-	if ( get_user(temp_ptr, &sc->handler))
-		goto badframe;
-  
-	funct_desc_ptr = ( struct funct_descr_entry *) temp_ptr;
+	err |= setup_sigcontext(&frame->sc, regs, signr, set,
+				(unsigned long)ka->sa.sa_handler);
 
-	if (put_user(regs->gpr[1], (unsigned long *)newsp)
-	    || get_user(regs->nip, & funct_desc_ptr ->entry)
-	    || get_user(regs->gpr[2],& funct_desc_ptr->toc)
-	    || get_user(regs->gpr[3], &sc->signal))
+	/* Set up to return from userspace. */
+	err |= setup_trampoline(__NR_sigreturn, &frame->tramp[0]);
+	if (err)
 		goto badframe;
-	regs->gpr[1] = newsp;
-	regs->gpr[4] = (unsigned long) sc;
-	regs->link = (unsigned long) frame->tramp;
 
+	funct_desc_ptr = (func_descr_t *) ka->sa.sa_handler;
 
-	PPCDBG(PPCDBG_SIGNAL, "setup_frame - returning - regs->gpr[1]=%lx, regs->gpr[4]=%lx, regs->link=%lx \n",
-	       regs->gpr[1], regs->gpr[4], regs->link);
+	/* Allocate a dummy caller frame for the signal handler. */
+	newsp = (unsigned long)frame - __SIGNAL_FRAMESIZE;
+	err |= put_user(0, (unsigned long *)newsp);
+
+	/* Set up "regs" so we "return" to the signal handler. */
+	err |= get_user(regs->nip, &funct_desc_ptr->entry);
+	regs->link = (unsigned long) &frame->tramp[0];
+	regs->gpr[1] = newsp;
+	err |= get_user(regs->gpr[2], &funct_desc_ptr->toc);
+	regs->gpr[3] = signr;
+	regs->gpr[4] = (unsigned long) &frame->sc;
+	if (err)
+		goto badframe;
 
 	return;
 
- badframe:
-	PPCDBG(PPCDBG_SIGNAL, "setup_frame - badframe in setup_frame, regs=%p frame=%p newsp=%lx\n", regs, frame, newsp);  PPCDBG_ENTER_DEBUGGER();
+badframe:
 #if DEBUG_SIG
 	printk("badframe in setup_frame, regs=%p frame=%p newsp=%lx\n",
 	       regs, frame, newsp);
@@ -540,61 +518,20 @@
  */
 static void
 handle_signal(unsigned long sig, struct k_sigaction *ka,
-	      siginfo_t *info, sigset_t *oldset, struct pt_regs * regs,
-	      unsigned long *newspp, unsigned long frame)
+	      siginfo_t *info, sigset_t *oldset, struct pt_regs *regs)
 {
-	struct sigcontext_struct *sc;
-        struct rt_sigframe *rt_sf;
-
-	if (regs->trap == 0x0C00 /* System Call! */
+	/* Are we from a system call? */
+	if (regs->trap == 0x0C00
 	    && ((int)regs->result == -ERESTARTNOHAND ||
 		((int)regs->result == -ERESTARTSYS &&
 		 !(ka->sa.sa_flags & SA_RESTART))))
 		regs->result = -EINTR;
-        /* Set up Signal Frame */
-     
-	if (ka->sa.sa_flags & SA_SIGINFO) {
-		/* Put a Real Time Context onto stack */
-		*newspp -= sizeof(*rt_sf);
-		rt_sf = (struct rt_sigframe *) *newspp;
-		if (verify_area(VERIFY_WRITE, rt_sf, sizeof(*rt_sf)))
-			goto badframe;
-                
-
-		if (__put_user((unsigned long) ka->sa.sa_handler, &rt_sf->uc.uc_mcontext.handler)
-		    || __put_user(&rt_sf->info, &rt_sf->pinfo)
-		    || __put_user(&rt_sf->uc, &rt_sf->puc)
-		    /* Put the siginfo */
-		    || __copy_to_user(&rt_sf->info, info, sizeof(*info))
-		    /* Create the ucontext */
-		    || __put_user(0, &rt_sf->uc.uc_flags)
-		    || __put_user(0, &rt_sf->uc.uc_link)
-		    || __put_user(current->sas_ss_sp, &rt_sf->uc.uc_stack.ss_sp)
-		    || __put_user(sas_ss_flags(regs->gpr[1]), 
-				  &rt_sf->uc.uc_stack.ss_flags)
-		    || __put_user(current->sas_ss_size, &rt_sf->uc.uc_stack.ss_size)
-		    || __copy_to_user(&rt_sf->uc.uc_sigmask, oldset, sizeof(*oldset))
-		    /* mcontext.regs points to preamble register frame */
-		    || __put_user((struct pt_regs *)frame, &rt_sf->uc.uc_mcontext.regs)
-		    || __put_user(sig, &rt_sf->uc.uc_mcontext.signal))
-			goto badframe;
-               
-	} else {
-	        /* Put another sigcontext on the stack */
-                *newspp -= sizeof(*sc);
-        	sc = (struct sigcontext_struct *) *newspp;
-        	if (verify_area(VERIFY_WRITE, sc, sizeof(*sc)))
-	        	goto badframe;
-
-        	if (__put_user((unsigned long) ka->sa.sa_handler, &sc->handler)
-	           || __put_user(oldset->sig[0], &sc->oldmask)
-#if _NSIG_WORDS > 1
-	           || __put_user(oldset->sig[1], &sc->_unused[3])
-#endif
-	           || __put_user((struct pt_regs *)frame, &sc->regs)
-	           || __put_user(sig, &sc->signal))
-	        	goto badframe;
-	}
+
+	/* Set up Signal Frame */
+	if (ka->sa.sa_flags & SA_SIGINFO)
+		setup_rt_frame(sig, ka, info, oldset, regs);
+	else
+		setup_frame(sig, ka, oldset, regs);
 
 	if (ka->sa.sa_flags & SA_ONESHOT)
 		ka->sa.sa_handler = SIG_DFL;
@@ -606,49 +543,18 @@
 		recalc_sigpending(current);
 		spin_unlock_irq(&current->sigmask_lock);
 	}
-	return;
-
-badframe:
-#if DEBUG_SIG
-	printk("badframe in handle_signal, regs=%p frame=%lx newsp=%lx\n",
-	       regs, frame, *newspp);
-	printk("sc=%p sig=%d ka=%p info=%p oldset=%p\n", sc, sig, ka, info, oldset);
-#endif
-	do_exit(SIGSEGV);
 }
 
-/*
- * Note that 'init' is a special process: it doesn't get signals it doesn't
- * want to handle. Thus you cannot kill init even with a SIGKILL even by
- * mistake.
- */
-extern int do_signal32(sigset_t *oldset, struct pt_regs *regs);
-int do_signal(sigset_t *oldset, struct pt_regs *regs)
+static int
+get_signal_to_deliver(siginfo_t *info, struct pt_regs *regs)
 {
-	siginfo_t info;
-	struct k_sigaction *ka;
-	unsigned long frame, newsp;
-
-	/*
-	 * If the current thread is 32 bit - invoke the
-	 * 32 bit signal handling code
-	 */
-	if (current->thread.flags & PPC_FLAG_32BIT)
-		return do_signal32(oldset, regs);
-
-        if (!oldset)
-		oldset = &current->blocked;
-
-	newsp = frame = 0;
-
 	for (;;) {
 		unsigned long signr;
+		struct k_sigaction *ka;
 
-                PPCDBG(PPCDBG_SIGNAL, "do_signal - (pre) dequeueing signal - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
 		spin_lock_irq(&current->sigmask_lock);
-		signr = dequeue_signal(&current->blocked, &info);
+		signr = dequeue_signal(&current->blocked, info);
 		spin_unlock_irq(&current->sigmask_lock);
-                PPCDBG(PPCDBG_SIGNAL, "do_signal - (aft) dequeueing signal - signal=%lx - pid=%ld current=%lx comm=%s \n", signr, current->pid, current, current->comm);
 
 		if (!signr)
 			break;
@@ -661,7 +567,8 @@
 			schedule();
 
 			/* We're back.  Did the debugger cancel the sig?  */
-			if (!(signr = current->exit_code))
+			signr = current->exit_code;
+			if (signr == 0)
 				continue;
 			current->exit_code = 0;
 
@@ -670,28 +577,24 @@
 				continue;
 
 			/* Update the siginfo structure.  Is this good?  */
-			if (signr != info.si_signo) {
-				info.si_signo = signr;
-				info.si_errno = 0;
-				info.si_code = SI_USER;
-				info.si_pid = current->p_pptr->pid;
-				info.si_uid = current->p_pptr->uid;
+			if (signr != info->si_signo) {
+				info->si_signo = signr;
+				info->si_errno = 0;
+				info->si_code = SI_USER;
+				info->si_pid = current->p_pptr->pid;
+				info->si_uid = current->p_pptr->uid;
 			}
 
 			/* If the (new) signal is now blocked, requeue it.  */
 			if (sigismember(&current->blocked, signr)) {
-				send_sig_info(signr, &info, current);
+				send_sig_info(signr, info, current);
 				continue;
 			}
 		}
 
 		ka = &current->sig->action[signr-1];
 
-  
-                PPCDBG(PPCDBG_SIGNAL, "do_signal - ka=%p, action handler=%lx \n", ka, ka->sa.sa_handler);
-
 		if (ka->sa.sa_handler == SIG_IGN) {
-                        PPCDBG(PPCDBG_SIGNAL, "do_signal - into SIG_IGN logic \n");
 			if (signr != SIGCHLD)
 				continue;
 			/* Check for SIGCHLD: it's special.  */
@@ -702,7 +605,6 @@
 
 		if (ka->sa.sa_handler == SIG_DFL) {
 			int exit_code = signr;
-                        PPCDBG(PPCDBG_SIGNAL, "do_signal - into SIG_DFL logic \n");
 
 			/* Init gets no signals it doesn't want.  */
 			if (current->pid == 1)
@@ -736,48 +638,58 @@
 				/* FALLTHRU */
 
 			default:
-				sig_exit(signr, exit_code, &info);
+				sig_exit(signr, exit_code, info);
 				/* NOTREACHED */
 			}
 		}
+		return signr;
+	}
+	return 0;
+}
 
-		if ( (ka->sa.sa_flags & SA_ONSTACK)
-		     && (! on_sig_stack(regs->gpr[1])))
-			newsp = (current->sas_ss_sp + current->sas_ss_size);
-		else
-			newsp = regs->gpr[1];
-		newsp = frame = newsp - sizeof(struct sigregs);
+/*
+ * Note that 'init' is a special process: it doesn't get signals it doesn't
+ * want to handle. Thus you cannot kill init even with a SIGKILL even by
+ * mistake.
+ */
+extern int do_signal32(sigset_t *oldset, struct pt_regs *regs);
+
+int
+do_signal(sigset_t *oldset, struct pt_regs *regs)
+{
+	siginfo_t info;
+	int signr;
+
+	/*
+	 * If the current thread is 32 bit - invoke the
+	 * 32 bit signal handling code
+	 */
+	if (current->thread.flags & PPC_FLAG_32BIT)
+		return do_signal32(oldset, regs);
+
+        if (!oldset)
+		oldset = &current->blocked;
+
+	signr = get_signal_to_deliver(&info, regs);
+	if (signr > 0) {
+		struct k_sigaction *ka = &current->sig->action[signr-1];
 
 		/* Whee!  Actually deliver the signal.  */
-  
-                PPCDBG(PPCDBG_SIGNAL, "do_signal - GOING TO RUN SIGNAL HANDLER - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-		handle_signal(signr, ka, &info, oldset, regs, &newsp, frame);
-                PPCDBG(PPCDBG_SIGNAL, "do_signal - after running signal handler - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-                break;
+		handle_signal(signr, ka, &info, oldset, regs);
+		return 1;
 	}
 
 	if (regs->trap == 0x0C00 /* System Call! */ &&
 	    ((int)regs->result == -ERESTARTNOHAND ||
 	     (int)regs->result == -ERESTARTSYS ||
 	     (int)regs->result == -ERESTARTNOINTR)) {
-                PPCDBG(PPCDBG_SIGNAL, "do_signal - going to back up & retry system call \n");
 		regs->gpr[3] = regs->orig_gpr3;
 		regs->nip -= 4;		/* Back up & retry system call */
 		regs->result = 0;
 	}
 
-	if (newsp == frame)
-          {
-             PPCDBG(PPCDBG_SIGNAL, "do_signal - returning w/ no signal delivered \n");
-             return 0;		/* no signals delivered */
-           }
-  
-     
-
-        if (ka->sa.sa_flags & SA_SIGINFO)
-             setup_rt_frame(regs, (struct sigregs *) frame, newsp);
-        else        
-	    setup_frame(regs, (struct sigregs *) frame, newsp);
-        PPCDBG(PPCDBG_SIGNAL, "do_signal - returning a signal was delivered \n");
-	return 1;
+	return 0;
 }
+
+
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/signal32.c linux-2.4.21-pre6/arch/ppc64/kernel/signal32.c
--- linux-2.4.20/arch/ppc64/kernel/signal32.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/signal32.c	2003-03-26 23:49:08.000000000 +0000
@@ -71,34 +71,41 @@
 };
 
 struct sigregs32 {
-    /***********************************************************************/
-    /* the gp_regs array is 32 bit representation of the pt_regs structure */
-    /*  that was stored on the kernle stack during the system call that    */
-    /*  was interrupted for the signal.                                    */
-    /*                                                                     */
-    /* Note that the entire pt_regs regs structure will fit in the gp_regs */
-    /*   structure because the ELF_NREG value is 48 for PPC and the pt_regs*/
-    /*   structure contains 44 registers                                   */
-    /*                                                                     */ 
-    /***********************************************************************/ 
+	/*
+	 * the gp_regs array is 32 bit representation of the pt_regs
+	 * structure that was stored on the kernle stack during the
+	 * system call that was interrupted for the signal.
+	 *
+	 * Note that the entire pt_regs regs structure will fit in
+	 * the gp_regs structure because the ELF_NREG value is 48 for
+	 * PPC and the pt_regs structure contains 44 registers
+	 */
 	elf_gregset_t32	gp_regs;
 	double		fp_regs[ELF_NFPREG];
 	unsigned int	tramp[2];
-	/* Programs using the rs6000/xcoff abi can save up to 19 gp regs
-	   and 18 fp regs below sp before decrementing it. */
+	/*
+	 * Programs using the rs6000/xcoff abi can save up to 19 gp
+	 * regs and 18 fp regs below sp before decrementing it.
+	 */
 	int		abigap[56];
 };
 
 
 struct rt_sigframe_32 {
-	/* Unused space at start of frame to allow for storing of stack pointers */
+	/*
+	 * Unused space at start of frame to allow for storing of
+	 * stack pointers
+	 */
 	unsigned long _unused;
-	/* This is a 32 bit pointer in user address space 
+	/*
+	 * This is a 32 bit pointer in user address space 
 	 *     it is a pointer to the siginfo stucture in the rt stack frame 
 	 */
 	u32 pinfo;
-	/* This is a 32 bit pointer in user address space */
-	/*     it is a pointer to the user context in the rt stack frame  */
+	/*
+	 * This is a 32 bit pointer in user address space
+	 * it is a pointer to the user context in the rt stack frame
+	 */
 	u32 puc;
 	struct siginfo32  info;
 	struct ucontext32 uc;
@@ -138,12 +145,9 @@
 	PPCDBG(PPCDBG_SYS32, "sys32_sigaction - entered - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
 
 	if (sig < 0)
-	{
 		sig = -sig;
-	}
 
-	if (act)
-	{
+	if (act) {
 		old_sigset_t32 mask;
 
 		ret = get_user((long)new_ka.sa.sa_handler, &act->sa_handler);
@@ -214,15 +218,18 @@
 	
 	PPCDBG(PPCDBG_SYS32, "sys32_sigprocmask - entered - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
 	
-	if (set && get_user (s, set)) return -EFAULT;
+	if (set && get_user(s, set))
+		return -EFAULT;
 	set_fs (KERNEL_DS);
 	ret = sys_sigprocmask((int)how, set ? &s : NULL, oset ? &s : NULL);
 	set_fs (old_fs);
-	if (ret) return ret;
-	if (oset && put_user (s, oset)) return -EFAULT;
 	
 	PPCDBG(PPCDBG_SYS32, "sys32_sigprocmask - exited - pid=%ld current=%lx comm=%s\n", current->pid, current, current->comm);
 
+	if (ret)
+		return ret;
+	if (oset && put_user (s, oset))
+		return -EFAULT;
 	return 0;
 }
 
@@ -247,21 +254,24 @@
 		     unsigned long r6, unsigned long r7, unsigned long r8,
 		     struct pt_regs *regs)
 {
-	struct sigcontext32_struct *sc, sigctx;
+	struct sigcontext32 *sc, sigctx;
 	struct sigregs32 *sr;
 	int ret;
 	elf_gregset_t32 saved_regs;  /* an array of ELF_NGREG unsigned ints (32 bits) */
 	sigset_t set;
 	unsigned int prevsp;
+	int i;
 
 	PPCDBG(PPCDBG_SIGNAL, "sys32_sigreturn - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
 
-	sc = (struct sigcontext32_struct *)(regs->gpr[1] + __SIGNAL_FRAMESIZE32);
+	sc = (struct sigcontext32 *)(regs->gpr[1] + __SIGNAL_FRAMESIZE32);
 	if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
 		goto badframe;
 
-	/* Note that PPC32 puts the upper 32 bits of the sigmask in the  */
-	/*   unused part of the signal stackframe                        */
+	/*
+	 * Note that PPC32 puts the upper 32 bits of the sigmask in the
+	 * unused part of the signal stackframe
+	 */
 	set.sig[0] = sigctx.oldmask + ((long)(sigctx._unused[3])<< 32);
 	sigdelsetmask(&set, ~_BLOCKABLE);
 	spin_lock_irq(&current->sigmask_lock);
@@ -272,77 +282,50 @@
 	sc++;			/* Look at next sigcontext */
 	/* If the next sigcontext is actually the sigregs (frame)  */
 	/*   - then no more sigcontexts on the user stack          */  
-	if (sc == (struct sigcontext32_struct*)(u64)sigctx.regs)
+	if (sc == (struct sigcontext32*)(u64)sigctx.regs)
 	{
 		/* Last stacked signal - restore registers */
 		sr = (struct sigregs32*)(u64)sigctx.regs;
 		if (regs->msr & MSR_FP )
 			giveup_fpu(current);
-		/* copy the 32 bit register values off the user stack */
-		/*   into the 32 bit register area                    */
+		/* 
+		 * Copy the 32 bit register values off the user stack
+		 * into the 32 bit register area
+		 */
 		if (copy_from_user(saved_regs, &sr->gp_regs,sizeof(sr->gp_regs)))
 			goto badframe;
-		/**********************************************************************/
-		/* The saved reg structure in the frame is an elf_grepset_t32, it is  */
-		/*   a 32 bit register save of the registers in the pt_regs structure */
-		/*   that was stored on the kernel stack during the system call       */
-		/*   when the system call was interrupted for the signal. Only 32 bits*/
-		/*   are saved because the sigcontext contains a pointer to the regs  */
-		/*   and the sig context address is passed as a pointer to the signal */
-		/*   handler.                                                         */
-		/*                                                                    */
-		/* The entries in the elf_grepset have the same index as the elements */
-		/*   in the pt_regs structure.                                        */
-		/*                                                                    */
-		/**********************************************************************/
-
+		/*
+		 * The saved reg structure in the frame is an elf_grepset_t32,
+		 * it is a 32 bit register save of the registers in the
+		 * pt_regs structure that was stored on the kernel stack
+		 * during the system call when the system call was interrupted
+		 * for the signal. Only 32 bits are saved because the
+		 * sigcontext contains a pointer to the regs and the sig
+		 * context address is passed as a pointer to the signal
+		 * handler.  
+		 *
+		 * The entries in the elf_grepset have the same index as the
+		 * elements in the pt_regs structure.
+		 */
 		saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE)
 			| (saved_regs[PT_MSR] & MSR_USERCHANGE);
-		regs->gpr[0] = (u64)(saved_regs[0]) & 0xFFFFFFFF;
-		regs->gpr[1] = (u64)(saved_regs[1]) & 0xFFFFFFFF;
-		/**********************************************************************/
-		/* Register 2 is the kernel toc - should be reset on any calls into   */
-		/*  the kernel                                                        */
-		/**********************************************************************/
-		regs->gpr[2] = (u64)(saved_regs[2]) & 0xFFFFFFFF;
-
-		regs->gpr[3] = (u64)(saved_regs[3]) & 0xFFFFFFFF;
-		regs->gpr[4] = (u64)(saved_regs[4]) & 0xFFFFFFFF;
-		regs->gpr[5] = (u64)(saved_regs[5]) & 0xFFFFFFFF;
-		regs->gpr[6] = (u64)(saved_regs[6]) & 0xFFFFFFFF;
-		regs->gpr[7] = (u64)(saved_regs[7]) & 0xFFFFFFFF;
-		regs->gpr[8] = (u64)(saved_regs[8]) & 0xFFFFFFFF;
-		regs->gpr[9] = (u64)(saved_regs[9]) & 0xFFFFFFFF;
-		regs->gpr[10] = (u64)(saved_regs[10]) & 0xFFFFFFFF;
-		regs->gpr[11] = (u64)(saved_regs[11]) & 0xFFFFFFFF;
-		regs->gpr[12] = (u64)(saved_regs[12]) & 0xFFFFFFFF;
-		regs->gpr[13] = (u64)(saved_regs[13]) & 0xFFFFFFFF;
-		regs->gpr[14] = (u64)(saved_regs[14]) & 0xFFFFFFFF;
-		regs->gpr[15] = (u64)(saved_regs[15]) & 0xFFFFFFFF;
-		regs->gpr[16] = (u64)(saved_regs[16]) & 0xFFFFFFFF;
-		regs->gpr[17] = (u64)(saved_regs[17]) & 0xFFFFFFFF;
-		regs->gpr[18] = (u64)(saved_regs[18]) & 0xFFFFFFFF;
-		regs->gpr[19] = (u64)(saved_regs[19]) & 0xFFFFFFFF;
-		regs->gpr[20] = (u64)(saved_regs[20]) & 0xFFFFFFFF;
-		regs->gpr[21] = (u64)(saved_regs[21]) & 0xFFFFFFFF;
-		regs->gpr[22] = (u64)(saved_regs[22]) & 0xFFFFFFFF;
-		regs->gpr[23] = (u64)(saved_regs[23]) & 0xFFFFFFFF;
-		regs->gpr[24] = (u64)(saved_regs[24]) & 0xFFFFFFFF;
-		regs->gpr[25] = (u64)(saved_regs[25]) & 0xFFFFFFFF;
-		regs->gpr[26] = (u64)(saved_regs[26]) & 0xFFFFFFFF;
-		regs->gpr[27] = (u64)(saved_regs[27]) & 0xFFFFFFFF;
-		regs->gpr[28] = (u64)(saved_regs[28]) & 0xFFFFFFFF;
-		regs->gpr[29] = (u64)(saved_regs[29]) & 0xFFFFFFFF;
-		regs->gpr[30] = (u64)(saved_regs[30]) & 0xFFFFFFFF;
-		regs->gpr[31] = (u64)(saved_regs[31]) & 0xFFFFFFFF;
-		/****************************************************/
-		/*  restore the non gpr registers                   */
-		/****************************************************/
+		/*
+		 * Register 2 is the kernel toc - should be reset on
+		 * any calls into the kernel 
+		 */
+		for (i = 0; i < 32; i++)
+			regs->gpr[i] = (u64)(saved_regs[i]) & 0xFFFFFFFF;
+
+		/*
+		 *  restore the non gpr registers 
+		 */
 		regs->msr = (u64)(saved_regs[PT_MSR]) & 0xFFFFFFFF;
-		/* Insure that the interrupt mode is 64 bit, during 32 bit execution.
-		 * (This is necessary because we only saved lower 32 bits of msr.)
+		/*
+		 * Insure that the interrupt mode is 64 bit, during 32 bit
+		 * execution. (This is necessary because we only saved
+		 * lower 32 bits of msr.)
 		 */
-		regs->msr = regs->msr | MSR_ISF;  /* When this thread is interrupted it should run in 64 bit mode. */
+		regs->msr = regs->msr | MSR_ISF;
 
 		regs->nip = (u64)(saved_regs[PT_NIP]) & 0xFFFFFFFF;
 		regs->orig_gpr3 = (u64)(saved_regs[PT_ORIG_R3]) & 0xFFFFFFFF; 
@@ -378,6 +361,7 @@
 		if (get_user(prevsp, &sr->gp_regs[PT_R1])
 		    || put_user(prevsp, (unsigned int*) regs->gpr[1]))
 			goto badframe;
+		current->thread.fpscr = 0;
 	}
   
 	PPCDBG(PPCDBG_SIGNAL, "sys32_sigreturn - normal exit returning %ld - pid=%ld current=%lx comm=%s \n", ret, current->pid, current, current->comm);
@@ -395,97 +379,51 @@
 setup_frame32(struct pt_regs *regs, struct sigregs32 *frame,
             unsigned int newsp)
 {
-	struct sigcontext32_struct *sc = (struct sigcontext32_struct *)(u64)newsp;
+	struct sigcontext32 *sc = (struct sigcontext32 *)(u64)newsp;
+	int i;
 
 	if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
 		goto badframe;
 	if (regs->msr & MSR_FP)
 		giveup_fpu(current);
 
-	/***************************************************************/
-	/*                                                             */ 
-	/* Copy the register contents for the pt_regs structure on the */
-	/*   kernel stack to the elf_gregset_t32 structure on the user */
-	/*   stack. This is a copy of 64 bit register values to 32 bit */
-	/*   register values. The high order 32 bits of the 64 bit     */
-	/*   registers are not needed since a 32 bit application is    */
-	/*   running and the saved registers are the contents of the   */
-	/*   user registers at the time of a system call.              */
-	/*                                                             */
-	/* The values saved on the user stack will be restored into    */
-	/*  the registers during the signal return processing          */
-	/*                                                             */
-	/* Note the +1 is needed in order to get the lower 32 bits     */
-	/*  of 64 bit register                                         */
-	/***************************************************************/
-	if (__copy_to_user(&frame->gp_regs[0], (u32*)(&regs->gpr[0])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[1], (u32*)(&regs->gpr[1])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[2], (u32*)(&regs->gpr[2])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[3], (u32*)(&regs->gpr[3])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[4], (u32*)(&regs->gpr[4])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[5], (u32*)(&regs->gpr[5])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[6], (u32*)(&regs->gpr[6])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[7], (u32*)(&regs->gpr[7])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[8], (u32*)(&regs->gpr[8])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[9], (u32*)(&regs->gpr[9])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[10], (u32*)(&regs->gpr[10])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[11], (u32*)(&regs->gpr[11])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[12], (u32*)(&regs->gpr[12])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[13], (u32*)(&regs->gpr[13])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[14], (u32*)(&regs->gpr[14])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[15], (u32*)(&regs->gpr[15])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[16], (u32*)(&regs->gpr[16])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[17], (u32*)(&regs->gpr[17])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[18], (u32*)(&regs->gpr[18])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[19], (u32*)(&regs->gpr[19])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[20], (u32*)(&regs->gpr[20])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[21], (u32*)(&regs->gpr[21])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[22], (u32*)(&regs->gpr[22])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[23], (u32*)(&regs->gpr[23])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[24], (u32*)(&regs->gpr[24])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[25], (u32*)(&regs->gpr[25])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[26], (u32*)(&regs->gpr[26])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[27], (u32*)(&regs->gpr[27])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[28], (u32*)(&regs->gpr[28])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[29], (u32*)(&regs->gpr[29])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[30], (u32*)(&regs->gpr[30])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[31], (u32*)(&regs->gpr[31])+1, sizeof(u32))) 
-		goto badframe;
-
-  /*****************************************************************************/
-  /* Copy the non gpr registers to the user stack                              */
-  /*****************************************************************************/
-
-	if (__copy_to_user(&frame->gp_regs[PT_NIP], (u32*)(&regs->gpr[PT_NIP])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[PT_MSR], (u32*)(&regs->gpr[PT_MSR])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[PT_ORIG_R3], (u32*)(&regs->gpr[PT_ORIG_R3])+1,
-			      sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[PT_CTR], (u32*)(&regs->gpr[PT_CTR])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[PT_LNK], (u32*)(&regs->gpr[PT_LNK])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[PT_XER], (u32*)(&regs->gpr[PT_XER])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[PT_CCR], (u32*)(&regs->gpr[PT_CCR])+1, sizeof(u32))
-# if 0
-	    || __copy_to_user(&frame->gp_regs[PT_MQ], (u32*)(&regs->gpr[PT_MQ])+1, sizeof(u32))
-#endif
-	    || __copy_to_user(&frame->gp_regs[PT_RESULT], (u32*)(&regs->gpr[PT_RESULT])+1,
-			      sizeof(u32)))
-		goto badframe;
-
+	/*
+	 * Copy the register contents for the pt_regs structure on the
+	 *   kernel stack to the elf_gregset_t32 structure on the user
+	 *   stack. This is a copy of 64 bit register values to 32 bit
+	 *   register values. The high order 32 bits of the 64 bit
+	 *   registers are not needed since a 32 bit application is
+	 *   running and the saved registers are the contents of the
+	 *   user registers at the time of a system call.
+	 * 
+	 * The values saved on the user stack will be restored into
+	 *  the registers during the signal return processing
+	 *
+	 * Note the +1 is needed in order to get the lower 32 bits
+	 * of 64 bit register
+	 */
+	for (i = 0; i < sizeof(struct pt_regs32)/sizeof(u32); i++) {
+		if (__copy_to_user(&frame->gp_regs[i], (u32*)(&regs->gpr[i])+1, sizeof(u32)))
+			goto badframe;
+	}
 
-	/*****************************************************************************/
-	/* Now copy the floating point registers onto the user stack                 */
-	/*                                                                           */
-	/* Also set up so on the completion of the signal handler, the sys_sigreturn */
-	/*   will get control to reset the stack                                     */
-	/*****************************************************************************/
+	/*
+	 * Now copy the floating point registers onto the user stack 
+	 *
+	 * Also set up so on the completion of the signal handler, the
+	 * sys_sigreturn will get control to reset the stack
+	 */
 	if (__copy_to_user(&frame->fp_regs, current->thread.fpr,
 			   ELF_NFPREG * sizeof(double))
-	    || __put_user(0x38000000U + __NR_sigreturn, &frame->tramp[0])    /* li r0, __NR_sigreturn */
-	    || __put_user(0x44000002U, &frame->tramp[1]))   /* sc */
+	    /* li r0, __NR_sigreturn */
+	    || __put_user(0x38000000U + __NR_sigreturn, &frame->tramp[0])
+	    /* sc */
+	    || __put_user(0x44000002U, &frame->tramp[1]))
 		goto badframe;
 
 	flush_icache_range((unsigned long) &frame->tramp[0],
 			   (unsigned long) &frame->tramp[2]);
+	current->thread.fpscr = 0;      /* turn off all fp exceptions */
 
 	newsp -= __SIGNAL_FRAMESIZE32;
 	if (put_user(regs->gpr[1], (u32*)(u64)newsp)
@@ -494,12 +432,12 @@
 		goto badframe;
 
 	regs->gpr[1] = newsp & 0xFFFFFFFF;
-	/**************************************************************/
-	/* first parameter to the signal handler is the signal number */
-	/*  - the value is in gpr3                                    */  
-	/* second parameter to the signal handler is the sigcontext   */
-	/*   - set the value into gpr4                                */ 
-	/**************************************************************/
+	/*
+	 * first parameter to the signal handler is the signal number
+	 *  - the value is in gpr3
+	 * second parameter to the signal handler is the sigcontext
+	 *   - set the value into gpr4
+	 */
 	regs->gpr[4] = (unsigned long) sc;
 	regs->link = (unsigned long) frame->tramp;
 	return;
@@ -514,40 +452,40 @@
 }
 
 
-/****************************************************************************/
-/*  Start of RT signal support                                              */
-/*                                                                          */
-/*     sigset_t is 64 bits for rt signals                                   */
-/*                                                                          */
-/*  System Calls                                                            */
-/*       sigaction                sys32_rt_sigaction                        */
-/*       sigpending               sys32_rt_sigpending                       */
-/*       sigprocmask              sys32_rt_sigprocmask                      */
-/*       sigreturn                sys32_rt_sigreturn                        */
-/*       sigtimedwait             sys32_rt_sigtimedwait                     */
-/*       sigqueueinfo             sys32_rt_sigqueueinfo                     */
-/*       sigsuspend               sys32_rt_sigsuspend                       */ 
-/*                                                                          */
-/*  Other routines                                                          */
-/*        setup_rt_frame32                                                  */
-/*        siginfo64to32                                                     */
-/*        siginfo32to64                                                     */
-/*                                                                          */
-/*                                                                          */
-/****************************************************************************/
+/*
+ *  Start of RT signal support
+ *
+ *     sigset_t is 64 bits for rt signals
+ *
+ *  System Calls
+ *       sigaction                sys32_rt_sigaction
+ *       sigpending               sys32_rt_sigpending
+ *       sigprocmask              sys32_rt_sigprocmask
+ *       sigreturn                sys32_rt_sigreturn
+ *       sigtimedwait             sys32_rt_sigtimedwait
+ *       sigqueueinfo             sys32_rt_sigqueueinfo
+ *       sigsuspend               sys32_rt_sigsuspend
+ *
+ *  Other routines
+ *        setup_rt_frame32
+ *        copy_siginfo_to_user32
+ *        siginfo32to64
+ */
 
 
-// This code executes after the rt signal handler in 32 bit mode has completed and 
-//  returned  
+/*
+ * This code executes after the rt signal handler in 32 bit mode has
+ * completed and returned  
+ */
 long sys32_rt_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5,
 			unsigned long r6, unsigned long r7, unsigned long r8,
 			struct pt_regs * regs)
 {
 	struct rt_sigframe_32 *rt_stack_frame;
-	struct sigcontext32_struct sigctx;
+	struct sigcontext32 sigctx;
 	struct sigregs32 *signalregs;
  
-	int ret;
+	int i, ret;
 	elf_gregset_t32 saved_regs;   /* an array of 32 bit register values */
 	sigset_t signal_set; 
 	stack_t stack;
@@ -560,12 +498,11 @@
 	if (copy_from_user(&sigctx, &rt_stack_frame->uc.uc_mcontext,sizeof(sigctx))
 	    || copy_from_user(&signal_set, &rt_stack_frame->uc.uc_sigmask,sizeof(signal_set))
 	    || copy_from_user(&stack,&rt_stack_frame->uc.uc_stack,sizeof(stack)))
-	{
 		/* unable to copy from user storage */
 		goto badframe;
-	}
 
-	/* Unblock the signal that was processed 
+	/*
+	 * Unblock the signal that was processed 
 	 *   After a signal handler runs - 
 	 *     if the signal is blockable - the signal will be unblocked  
 	 *       ( sigkill and sigstop are not blockable)
@@ -582,76 +519,39 @@
 	 */
 	rt_stack_frame ++;
 
-	if (rt_stack_frame == (struct rt_sigframe_32 *)(u64)(sigctx.regs))
-	{
+	if (rt_stack_frame == (struct rt_sigframe_32 *)(u64)(sigctx.regs)) {
 		signalregs = (struct sigregs32 *) (u64)sigctx.regs;
 		/* If currently owning the floating point - give them up */
 		if (regs->msr & MSR_FP)
-		{
 			giveup_fpu(current);
-		}
+
 		if (copy_from_user(saved_regs,&signalregs->gp_regs,sizeof(signalregs->gp_regs))) 
-		{
 			goto badframe;
-		}
-		/**********************************************************************/
-		/* The saved reg structure in the frame is an elf_grepset_t32, it is  */
-		/*   a 32 bit register save of the registers in the pt_regs structure */
-		/*   that was stored on the kernel stack during the system call       */
-		/*   when the system call was interrupted for the signal. Only 32 bits*/
-		/*   are saved because the sigcontext contains a pointer to the regs  */
-		/*   and the sig context address is passed as a pointer to the signal */
-		/*   handler.                                                         */
-		/*                                                                    */
-		/* The entries in the elf_grepset have the same index as the elements */
-		/*   in the pt_regs structure.                                        */
-		/*                                                                    */
-		/**********************************************************************/
 
+		/*
+		 * The saved reg structure in the frame is an elf_grepset_t32,
+		 * it is a 32 bit register save of the registers in the
+		 * pt_regs structure that was stored on the kernel stack
+		 * during the system call when the system call was interrupted
+		 * for the signal. Only 32 bits are saved because the
+		 * sigcontext contains a pointer to the regs and the sig
+		 * context address is passed as a pointer to the signal handler
+		 *
+		 * The entries in the elf_grepset have the same index as
+		 * the elements in the pt_regs structure.
+		 */
 		saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE)
 			| (saved_regs[PT_MSR] & MSR_USERCHANGE);
-		regs->gpr[0] = (u64)(saved_regs[0]) & 0xFFFFFFFF;
-		regs->gpr[1] = (u64)(saved_regs[1]) & 0xFFFFFFFF;
-		/**********************************************************************/
-		/* Register 2 is the kernel toc - should be reset on any calls into   */
-		/*  the kernel                                                        */
-		/**********************************************************************/
-		regs->gpr[2] = (u64)(saved_regs[2]) & 0xFFFFFFFF;
- 
-		regs->gpr[3] = (u64)(saved_regs[3]) & 0xFFFFFFFF;
-		regs->gpr[4] = (u64)(saved_regs[4]) & 0xFFFFFFFF;
-		regs->gpr[5] = (u64)(saved_regs[5]) & 0xFFFFFFFF;
-		regs->gpr[6] = (u64)(saved_regs[6]) & 0xFFFFFFFF;
-		regs->gpr[7] = (u64)(saved_regs[7]) & 0xFFFFFFFF;
-		regs->gpr[8] = (u64)(saved_regs[8]) & 0xFFFFFFFF;
-		regs->gpr[9] = (u64)(saved_regs[9]) & 0xFFFFFFFF;
-		regs->gpr[10] = (u64)(saved_regs[10]) & 0xFFFFFFFF;
-		regs->gpr[11] = (u64)(saved_regs[11]) & 0xFFFFFFFF;
-		regs->gpr[12] = (u64)(saved_regs[12]) & 0xFFFFFFFF;
-		regs->gpr[13] = (u64)(saved_regs[13]) & 0xFFFFFFFF;
-		regs->gpr[14] = (u64)(saved_regs[14]) & 0xFFFFFFFF;
-		regs->gpr[15] = (u64)(saved_regs[15]) & 0xFFFFFFFF;
-		regs->gpr[16] = (u64)(saved_regs[16]) & 0xFFFFFFFF;
-		regs->gpr[17] = (u64)(saved_regs[17]) & 0xFFFFFFFF;
-		regs->gpr[18] = (u64)(saved_regs[18]) & 0xFFFFFFFF;
-		regs->gpr[19] = (u64)(saved_regs[19]) & 0xFFFFFFFF;
-		regs->gpr[20] = (u64)(saved_regs[20]) & 0xFFFFFFFF;
-		regs->gpr[21] = (u64)(saved_regs[21]) & 0xFFFFFFFF;
-		regs->gpr[22] = (u64)(saved_regs[22]) & 0xFFFFFFFF;
-		regs->gpr[23] = (u64)(saved_regs[23]) & 0xFFFFFFFF;
-		regs->gpr[24] = (u64)(saved_regs[24]) & 0xFFFFFFFF;
-		regs->gpr[25] = (u64)(saved_regs[25]) & 0xFFFFFFFF;
-		regs->gpr[26] = (u64)(saved_regs[26]) & 0xFFFFFFFF;
-		regs->gpr[27] = (u64)(saved_regs[27]) & 0xFFFFFFFF;
-		regs->gpr[28] = (u64)(saved_regs[28]) & 0xFFFFFFFF;
-		regs->gpr[29] = (u64)(saved_regs[29]) & 0xFFFFFFFF;
-		regs->gpr[30] = (u64)(saved_regs[30]) & 0xFFFFFFFF;
-		regs->gpr[31] = (u64)(saved_regs[31]) & 0xFFFFFFFF;
-		/****************************************************/
-		/*  restore the non gpr registers                   */
-		/****************************************************/
+		/*
+		 * Register 2 is the kernel toc - should be reset on any
+		 * calls into the kernel
+		 */
+		for (i = 0; i < 32; i++)
+			regs->gpr[i] = (u64)(saved_regs[i]) & 0xFFFFFFFF;
+		/*
+		 * restore the non gpr registers
+		 */
 		regs->msr = (u64)(saved_regs[PT_MSR]) & 0xFFFFFFFF;
-
 		regs->nip = (u64)(saved_regs[PT_NIP]) & 0xFFFFFFFF;
 		regs->orig_gpr3 = (u64)(saved_regs[PT_ORIG_R3]) & 0xFFFFFFFF; 
 		regs->ctr = (u64)(saved_regs[PT_CTR]) & 0xFFFFFFFF; 
@@ -659,14 +559,18 @@
 		regs->xer = (u64)(saved_regs[PT_XER]) & 0xFFFFFFFF; 
 		regs->ccr = (u64)(saved_regs[PT_CCR]) & 0xFFFFFFFF;
 		/* regs->softe is left unchanged (like MSR.EE) */
-		/******************************************************/
-		/* the DAR and the DSISR are only relevant during a   */
-		/*   data or instruction storage interrupt. The value */
-		/*   will be set to zero.                             */
-		/******************************************************/
+		/*
+		 * the DAR and the DSISR are only relevant during a
+		 *   data or instruction storage interrupt. The value
+		 *   will be set to zero.
+		 */
 		regs->dar = 0; 
 		regs->dsisr = 0;
 		regs->result = (u64)(saved_regs[PT_RESULT]) & 0xFFFFFFFF;
+
+		if (copy_from_user(current->thread.fpr, &signalregs->fp_regs, sizeof(signalregs->fp_regs))) 
+			goto badframe;
+
 		ret = regs->result;
 	}
 	else  /* more signals to go  */
@@ -696,6 +600,7 @@
 		{
 			goto badframe;
 		}
+		current->thread.fpscr = 0;
 
 	}
 
@@ -772,10 +677,12 @@
 extern asmlinkage long sys_rt_sigprocmask(int how, sigset_t *set, sigset_t *oset,
 					  size_t sigsetsize);
 
-/* Note: it is necessary to treat how as an unsigned int, 
- * with the corresponding cast to a signed int to insure that the 
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
+/*
+ * Note: it is necessary to treat how as an unsigned int, with the
+ * corresponding cast to a signed int to insure that the proper
+ * conversion (sign extension) between the register representation
+ * of a signed int (msr in 32-bit mode) and the register representation
+ * of a signed int (msr in 64-bit mode) is performed.
  */
 asmlinkage long sys32_rt_sigprocmask(u32 how, sigset32_t *set, sigset32_t *oset, size_t sigsetsize)
 {
@@ -802,7 +709,8 @@
 	ret = sys_rt_sigprocmask((int)how, set ? &s : NULL, oset ? &s : NULL,
 				 sigsetsize); 
 	set_fs (old_fs);
-	if (ret) return ret;
+	if (ret)
+		return ret;
 	if (oset) {
 		switch (_NSIG_WORDS) {
 		case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3];
@@ -853,7 +761,7 @@
 	memset (d, 0, sizeof(siginfo_t32));
 	d->si_signo = s->si_signo;
 	d->si_errno = s->si_errno;
-	d->si_code = s->si_code;
+	d->si_code = s->si_code & 0xffff;
 	if (s->si_signo >= SIGRTMIN) {
 		d->si_pid = s->si_pid;
 		d->si_uid = s->si_uid;
@@ -871,7 +779,7 @@
 	case SIGBUS:
 	case SIGFPE:
 	case SIGILL:
-		d->si_addr = (long)(s->si_addr);
+		d->si_addr = (unsigned int)(s->si_addr);
         break;
 	case SIGPOLL:
 		d->si_band = s->si_band;
@@ -917,12 +825,10 @@
 	}
 	set_fs (KERNEL_DS);
 	if (uts) 
-	{
 		ret = sys_rt_sigtimedwait(&s, &info, &t, sigsetsize);
-	} else {
-		ret = sys_rt_sigtimedwait(&s, &info, (struct timespec *)uts, sigsetsize);
-	}
-	
+	else
+		ret = sys_rt_sigtimedwait(&s, &info, (struct timespec *)uts,
+				sigsetsize);
 	set_fs (old_fs);
 	if (ret >= 0 && uinfo) {
 		if (copy_to_user (uinfo, siginfo64to32(&info32, &info),
@@ -974,10 +880,12 @@
 
 extern asmlinkage long sys_rt_sigqueueinfo(int pid, int sig, siginfo_t *uinfo);
 
-/* Note: it is necessary to treat pid and sig as unsigned ints,
- * with the corresponding cast to a signed int to insure that the 
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
+/*
+ * Note: it is necessary to treat pid and sig as unsigned ints, with the
+ * corresponding cast to a signed int to insure that the proper conversion
+ * (sign extension) between the register representation of a signed int
+ * (msr in 32-bit mode) and the register representation of a signed int
+ * (msr in 64-bit mode) is performed.
  */
 asmlinkage long sys32_rt_sigqueueinfo(u32 pid, u32 sig, siginfo_t32 *uinfo)
 {
@@ -1012,9 +920,11 @@
 	if (copy_from_user(&s32, unewset, sizeof(s32)))
 		return -EFAULT;
 
-	/* Swap the 2 words of the 64-bit sigset_t (they are stored in the "wrong" endian in 32-bit user storage). */
-	switch (_NSIG_WORDS) 
-	{
+	/*
+	 * Swap the 2 words of the 64-bit sigset_t (they are stored
+	 * in the "wrong" endian in 32-bit user storage).
+	 */
+	switch (_NSIG_WORDS) {
 		case 4: newset.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32);
 		case 3: newset.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32);
 		case 2: newset.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32);
@@ -1029,22 +939,26 @@
 	recalc_sigpending(current);
 	spin_unlock_irq(&current->sigmask_lock);
 
-	regs->gpr[3] = -EINTR;
+	regs->result = -EINTR;
+	regs->gpr[3] = EINTR;
+	regs->ccr |= 0x10000000;
 	while (1) {
 		current->state = TASK_INTERRUPTIBLE;
 		schedule();
 		if (do_signal(&saveset, regs))
+			/*
+			 * If a signal handler needs to be called,
+			 * do_signal() has set R3 to the signal number (the
+			 * first argument of the signal handler), so don't
+			 * overwrite that with EINTR !
+			 * In the other cases, do_signal() doesn't touch 
+			 * R3, so it's still set to -EINTR (see above).
+			 */
 			return regs->gpr[3];
 	}
 }
 
 
-
-
-
-
-
-
 /*
  * Set up a rt signal frame.
  */
@@ -1054,87 +968,40 @@
 {
 	unsigned int copyreg4,copyreg5;
 	struct rt_sigframe_32 * rt_sf = (struct rt_sigframe_32 *) (u64)newsp;
-
+	int i;
   
 	if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
 		goto badframe;
 	if (regs->msr & MSR_FP)
 		giveup_fpu(current);
-	/***************************************************************/
-	/*                                                             */ 
-	/* Copy the register contents for the pt_regs structure on the */
-	/*   kernel stack to the elf_gregset_t32 structure on the user */
-	/*   stack. This is a copy of 64 bit register values to 32 bit */
-	/*   register values. The high order 32 bits of the 64 bit     */
-	/*   registers are not needed since a 32 bit application is    */
-	/*   running and the saved registers are the contents of the   */
-	/*   user registers at the time of a system call.              */
-	/*                                                             */
-	/* The values saved on the user stack will be restored into    */
-	/*  the registers during the signal return processing          */
-	/*                                                             */
-	/* Note the +1 is needed in order to get the lower 32 bits     */
-	/*  of 64 bit register                                         */
-	/***************************************************************/
-	if (__copy_to_user(&frame->gp_regs[0], (u32*)(&regs->gpr[0])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[1], (u32*)(&regs->gpr[1])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[2], (u32*)(&regs->gpr[2])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[3], (u32*)(&regs->gpr[3])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[4], (u32*)(&regs->gpr[4])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[5], (u32*)(&regs->gpr[5])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[6], (u32*)(&regs->gpr[6])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[7], (u32*)(&regs->gpr[7])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[8], (u32*)(&regs->gpr[8])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[9], (u32*)(&regs->gpr[9])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[10], (u32*)(&regs->gpr[10])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[11], (u32*)(&regs->gpr[11])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[12], (u32*)(&regs->gpr[12])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[13], (u32*)(&regs->gpr[13])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[14], (u32*)(&regs->gpr[14])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[15], (u32*)(&regs->gpr[15])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[16], (u32*)(&regs->gpr[16])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[17], (u32*)(&regs->gpr[17])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[18], (u32*)(&regs->gpr[18])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[19], (u32*)(&regs->gpr[19])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[20], (u32*)(&regs->gpr[20])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[21], (u32*)(&regs->gpr[21])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[22], (u32*)(&regs->gpr[22])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[23], (u32*)(&regs->gpr[23])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[24], (u32*)(&regs->gpr[24])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[25], (u32*)(&regs->gpr[25])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[26], (u32*)(&regs->gpr[26])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[27], (u32*)(&regs->gpr[27])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[28], (u32*)(&regs->gpr[28])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[29], (u32*)(&regs->gpr[29])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[30], (u32*)(&regs->gpr[30])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[31], (u32*)(&regs->gpr[31])+1, sizeof(u32))) 
-		goto badframe;
 
-	/*****************************************************************************/
-	/* Copy the non gpr registers to the user stack                              */
-	/*****************************************************************************/
-
-	if (__copy_to_user(&frame->gp_regs[PT_NIP], (u32*)(&regs->gpr[PT_NIP])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[PT_MSR], (u32*)(&regs->gpr[PT_MSR])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[PT_ORIG_R3], (u32*)(&regs->gpr[PT_ORIG_R3])+1,
-			      sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[PT_CTR], (u32*)(&regs->gpr[PT_CTR])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[PT_LNK], (u32*)(&regs->gpr[PT_LNK])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[PT_XER], (u32*)(&regs->gpr[PT_XER])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[PT_CCR], (u32*)(&regs->gpr[PT_CCR])+1, sizeof(u32))
-	    || __copy_to_user(&frame->gp_regs[PT_RESULT], (u32*)(&regs->gpr[PT_RESULT])+1,
-			      sizeof(u32)))
-		goto badframe;
-
-
-	/*****************************************************************************/
-	/* Now copy the floating point registers onto the user stack                 */
-	/*                                                                           */
-	/* Also set up so on the completion of the signal handler, the sys_sigreturn */
-	/*   will get control to reset the stack                                     */
-	/*****************************************************************************/
+	/*
+	 * Copy the register contents for the pt_regs structure on the
+	 *   kernel stack to the elf_gregset_t32 structure on the user
+	 *   stack. This is a copy of 64 bit register values to 32 bit
+	 *   register values. The high order 32 bits of the 64 bit
+	 *   registers are not needed since a 32 bit application is
+	 *   running and the saved registers are the contents of the
+	 *   user registers at the time of a system call.
+	 *
+	 * The values saved on the user stack will be restored into
+	 *  the registers during the signal return processing.
+	 *
+	 * Note the +1 is needed in order to get the lower 32 bits
+	 * of 64 bit register
+	 */
+	for (i = 0; i < sizeof(struct pt_regs32)/sizeof(u32); i++) {
+		if (__copy_to_user(&frame->gp_regs[i], (u32*)(&regs->gpr[i])+1, sizeof(u32)))
+			goto badframe;
+	}
 
 
+	/*
+	 * Now copy the floating point registers onto the user stack
+	 *
+	 * Also set up so on the completion of the signal handler, the
+	 * sys_sigreturn will get control to reset the stack
+	 */
 	if (__copy_to_user(&frame->fp_regs, current->thread.fpr,
 			   ELF_NFPREG * sizeof(double))
 	    || __put_user(0x38000000U + __NR_rt_sigreturn, &frame->tramp[0])    /* li r0, __NR_rt_sigreturn */
@@ -1143,10 +1010,11 @@
 
 	flush_icache_range((unsigned long) &frame->tramp[0],
 			   (unsigned long) &frame->tramp[2]);
-
+	current->thread.fpscr = 0;	/* turn off all fp exceptions */
   
-	/* Retrieve rt_sigframe from stack and
-	   set up registers for signal handler
+	/*
+	 * Retrieve rt_sigframe from stack and
+	 * set up registers for signal handler
 	*/
 	newsp -= __SIGNAL_FRAMESIZE32;
       
@@ -1160,17 +1028,12 @@
 
 	regs->gpr[4] = copyreg4;
 	regs->gpr[5] = copyreg5;
-
-   
 	regs->gpr[1] = newsp;
 	regs->gpr[6] = (unsigned long) rt_sf;
-
-
 	regs->link = (unsigned long) frame->tramp;
 
 	return;
 
-
  badframe:
 	udbg_printf("setup_frame32 - badframe in setup_frame, regs=%p frame=%p newsp=%lx\n", regs, frame, newsp);  PPCDBG_ENTER_DEBUGGER();
 #if DEBUG_SIG
@@ -1189,7 +1052,7 @@
 	      siginfo_t *info, sigset_t *oldset, struct pt_regs * regs,
 	      unsigned int *newspp, unsigned int frame)
 {
-	struct sigcontext32_struct *sc;
+	struct sigcontext32 *sc;
 	struct rt_sigframe_32 *rt_stack_frame;
 	siginfo_t32 siginfo32bit;
 
@@ -1231,14 +1094,15 @@
 			goto badframe; 
 		}
 	} else {
-		/* Put another sigcontext on the stack */
+		/* Put a sigcontext on the stack */
 		*newspp -= sizeof(*sc);
-		sc = (struct sigcontext32_struct *)(u64)*newspp;
+		sc = (struct sigcontext32 *)(u64)*newspp;
 		if (verify_area(VERIFY_WRITE, sc, sizeof(*sc)))
 			goto badframe;
-
-		/* Note the upper 32 bits of the signal mask are stored in the */
-		/*   unused part of the signal stack frame                     */  
+		/*
+		 * Note the upper 32 bits of the signal mask are stored
+		 * in the unused part of the signal stack frame
+		 */
 		if (__put_user((u32)(u64)ka->sa.sa_handler, &sc->handler)
 		    || __put_user(oldset->sig[0], &sc->oldmask)
 		    || __put_user((oldset->sig[0] >> 32), &sc->_unused[3])
@@ -1270,15 +1134,12 @@
 }
 
 
-/****************************************************************************/
-/*  Start Alternate signal stack support                                    */
-/*                                                                          */
-/*                                                                          */
-/*                                                                          */
-/*  System Calls                                                            */
-/*       sigaltatck               sys32_sigaltstack                         */
-/*                                                                          */
-/****************************************************************************/
+/*
+ *  Start Alternate signal stack support
+ *
+ *  System Calls
+ *       sigaltatck               sys32_sigaltstack
+ */
 
 
 asmlinkage int sys32_sigaltstack(u32 newstack, u32 oldstack, int p3, int p4, int p6,
@@ -1289,8 +1150,10 @@
 	mm_segment_t old_fs;
 	unsigned long sp;
 
-	/* set sp to the user stack on entry to the system call                  */
-	/*   the system call router sets R9 to the saved registers               */
+	/*
+	 * set sp to the user stack on entry to the system call
+	 * the system call router sets R9 to the saved registers
+	 */
 	sp = regs->gpr[1];
 
 	/*  Put new stack info in local 64 bit stack struct                      */ 
@@ -1314,15 +1177,14 @@
 
 
 
-/****************************************************************************/
-/*  Start of do_signal32 routine                                            */
-/*                                                                          */
-/*   This routine gets control when a pemding signal needs to be processed  */
-/*     in the 32 bit target thread -                                        */
-/*                                                                          */
-/*   It handles both rt and non-rt signals                                  */
-/*                                                                          */
-/****************************************************************************/
+/*
+ *  Start of do_signal32 routine
+ *
+ *   This routine gets control when a pending signal needs to be processed
+ *     in the 32 bit target thread -
+ *
+ *   It handles both rt and non-rt signals
+ */
 
 /*
  * Note that 'init' is a special process: it doesn't get signals it doesn't
@@ -1445,9 +1307,8 @@
 
 		if ( (ka->sa.sa_flags & SA_ONSTACK)
 		     && (! on_sig_stack(regs->gpr[1])))
-		{
 			newsp = (current->sas_ss_sp + current->sas_ss_size);
-		} else
+		else
 			newsp = regs->gpr[1];
 		newsp = frame = newsp - sizeof(struct sigregs32);
 
@@ -1466,15 +1327,12 @@
 	}
 
 	if (newsp == frame)
-	{
 		return 0;		/* no signals delivered */
-	}
-	// Invoke correct stack setup routine 
+
+	/* Invoke correct stack setup routine */
 	if (ka->sa.sa_flags & SA_SIGINFO) 
 		setup_rt_frame32(regs, (struct sigregs32*)(u64)frame, newsp);
 	else
 		setup_frame32(regs, (struct sigregs32*)(u64)frame, newsp);
-
 	return 1;
-
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/smp.c linux-2.4.21-pre6/arch/ppc64/kernel/smp.c
--- linux-2.4.20/arch/ppc64/kernel/smp.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/smp.c	2003-03-26 23:49:50.000000000 +0000
@@ -224,7 +224,7 @@
 	ppc_md.smp_kick_cpu     = smp_iSeries_kick_cpu;
 	ppc_md.smp_setup_cpu    = smp_iSeries_setup_cpu;
 
-	naca->processorCount	= smp_iSeries_numProcs();
+	systemcfg->processorCount	= smp_iSeries_numProcs();
 }
 
 
@@ -255,10 +255,10 @@
 static int
 smp_chrp_probe(void)
 {
-	if (naca->processorCount > 1)
+	if (systemcfg->processorCount > 1)
 		openpic_request_IPIs();
 
-	return naca->processorCount;
+	return systemcfg->processorCount;
 }
 
 static void
@@ -299,11 +299,11 @@
 	static atomic_t ready = ATOMIC_INIT(1);
 	static volatile int frozen = 0;
 
-	if (naca->platform == PLATFORM_PSERIES_LPAR) {
+	if (systemcfg->platform == PLATFORM_PSERIES_LPAR) {
 		/* timebases already synced under the hypervisor. */
 		paca[cpu_nr].next_jiffy_update_tb = tb_last_stamp = get_tb();
 		if (cpu_nr == 0) {
-			naca->tb_orig_stamp = tb_last_stamp;
+			systemcfg->tb_orig_stamp = tb_last_stamp;
 			/* Should update naca->stamp_xsec.
 			 * For now we leave it which means the time can be some
 			 * number of msecs off until someone does a settimeofday()
@@ -330,7 +330,7 @@
 			mb();
 			frozen = 0;
 			tb_last_stamp = get_tb();
-			naca->tb_orig_stamp = tb_last_stamp;
+			systemcfg->tb_orig_stamp = tb_last_stamp;
 			smp_tb_synchronized = 1;
 		} else {
 			atomic_inc(&ready);
@@ -371,7 +371,7 @@
 static int
 smp_xics_probe(void)
 {
-	return naca->processorCount;
+	return systemcfg->processorCount;
 }
 
 /* This is called very early */
@@ -621,7 +621,7 @@
 		if(i != 0) {
 		        /*
 			 * Processor 0's segment table is statically 
-			 * initialized to real address 0x5000.  The
+			 * initialized to real address STAB0_PHYS_ADDR.  The
 			 * Other processor's tables are created and
 			 * initialized here.
 			 */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/sys32.S linux-2.4.21-pre6/arch/ppc64/kernel/sys32.S
--- linux-2.4.20/arch/ppc64/kernel/sys32.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/sys32.S	2003-03-26 23:49:09.000000000 +0000
@@ -19,8 +19,6 @@
 #include <asm/errno.h>
 #include <asm/processor.h>
 
-/* NOTE: call as jump breaks return stack, we have to avoid that */
-
 	.text
 
 _GLOBAL(sys32_mmap)
@@ -32,14 +30,6 @@
 	extsw		r4,r4		/* sign extend off_t offset parm */
 	b		.sys_lseek
 
-_GLOBAL(sys32_chmod)
-/* Ken Aaker.. hmmm maybe I don't need to do anything here */
-	b		.sys_chmod
-
-_GLOBAL(sys32_mknod)
-/* Ken Aaker.. hmmm maybe I don't need to do anything here */
-	b		.sys_mknod
-
 _GLOBAL(sys32_sendto)
 	clrldi		r7, r7, 32	/* struct sockaddr *addr parm */
 	clrldi		r8, r8, 32	/* int addr_len parm */
@@ -58,10 +48,10 @@
 	extsw		r4,r4		/* sign extend long data parm */
 	b		.sys_bdflush
 
-_GLOBAL(sys32_mmap2)
+_GLOBAL(ppc32_mmap2)
 	clrldi		r7, r7, 32	/* unsigned long fd parm */
-	extsw		r8, r8		/* off_t offset */
-	b		.sys_mmap
+	clrldi		r8, r8, 32	/* unsigned long pgoff */
+	b		.sys32_mmap2
 
 _GLOBAL(sys32_socketcall)	/* r3=call, r4=args */
 	cmpwi		r3, 1
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/sys_ppc32.c linux-2.4.21-pre6/arch/ppc64/kernel/sys_ppc32.c
--- linux-2.4.20/arch/ppc64/kernel/sys_ppc32.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/sys_ppc32.c	2003-03-26 23:49:09.000000000 +0000
@@ -69,17 +69,6 @@
 extern unsigned long wall_jiffies;
 #define USEC_PER_SEC (1000000)
 
-/* 
- * These are the flags in the MSR that the user is allowed to change
- * by modifying the saved value of the MSR on the stack.  SE and BE
- * should not be in this list since gdb may want to change these.  I.e,
- * you should be able to step out of a signal handler to see what
- * instruction executes next after the signal handler completes.
- * Alternately, if you stepped into a signal handler, you should be
- * able to continue 'til the next breakpoint from within the signal
- * handler, even if the handler returns.
- */
-#define MSR_USERCHANGE	(MSR_FE0 | MSR_FE1)
 
 extern asmlinkage long sys_utime(char * filename, struct utimbuf * times);
 
@@ -135,10 +124,10 @@
 	 */
 	if (!count)
 		return 0;
-	if(verify_area(VERIFY_READ, vector, sizeof(struct iovec32)*count))
-		return -EFAULT;
 	if (count > UIO_MAXIOV)
 		return -EINVAL;
+	if(verify_area(VERIFY_READ, vector, sizeof(struct iovec32)*count))
+		return -EFAULT;
 	if (count > UIO_FASTIOV) {
 		iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
 		if (!iov)
@@ -546,7 +535,6 @@
 	u32		d_ino;
 	u32		d_offset;
 	unsigned short	d_namlen;
-  /* unsigned char	d_type; */
 	char		d_name[1];
 };
 
@@ -639,7 +627,6 @@
 	buf->previous = dirent;
 	put_user(ino, &dirent->d_ino);
 	put_user(reclen, &dirent->d_reclen);
-	/* put_user(d_type, &dirent->d_type); */
 	copy_to_user(dirent->d_name, name, namlen);
 	put_user(0, dirent->d_name + namlen);
 	((char *) dirent) += reclen;
@@ -837,7 +824,7 @@
 		put_user(usec, &tvp->tv_usec);
 	}
 
-  if (ret < 0)
+	if (ret < 0)
 		goto out;
 	if (!ret) {
 		ret = -ERESTARTNOHAND;
@@ -2448,8 +2435,10 @@
 struct msgbuf32 { s32 mtype; char mtext[1]; };
 
 struct semid_ds32 {
-	struct ipc_perm sem_perm;
+	struct ipc_perm32 sem_perm;
+	unsigned int _pad0;
 	__kernel_time_t32 sem_otime;
+	unsigned int _pad1;
 	__kernel_time_t32 sem_ctime;
 	u32 sem_base;
 	u32 sem_pending;
@@ -2459,7 +2448,7 @@
 };
 
 struct semid64_ds32 {
-	struct ipc64_perm sem_perm;
+	struct ipc64_perm32 sem_perm;
 	unsigned int __unused1;
 	__kernel_time_t32 sem_otime;
 	unsigned int __unused2;
@@ -2471,7 +2460,7 @@
 
 struct msqid_ds32
 {
-	struct ipc_perm msg_perm;
+	struct ipc_perm32 msg_perm;
 	u32 msg_first;
 	u32 msg_last;
 	__kernel_time_t32 msg_stime;
@@ -2487,7 +2476,7 @@
 };
 
 struct msqid64_ds32 {
-	struct ipc64_perm msg_perm;
+	struct ipc64_perm32 msg_perm;
 	unsigned int __unused1;
 	__kernel_time_t32 msg_stime;
 	unsigned int __unused2;
@@ -2504,7 +2493,7 @@
 };
 
 struct shmid_ds32 {
-	struct ipc_perm shm_perm;
+	struct ipc_perm32 shm_perm;
 	int shm_segsz;
 	__kernel_time_t32 shm_atime;
 	__kernel_time_t32 shm_dtime;
@@ -2518,7 +2507,7 @@
 };
 
 struct shmid64_ds32 {
-	struct ipc64_perm shm_perm;
+	struct ipc64_perm32 shm_perm;
 	unsigned int __unused1;
 	__kernel_time_t32 shm_atime;
 	unsigned int __unused2;
@@ -2584,7 +2573,7 @@
 			err = sys_semctl(first, second, third, fourth);
 			set_fs(old_fs);
 			err2 = copy_to_user(&usp->sem_perm, &s64.sem_perm,
-					    sizeof(struct ipc64_perm));
+					    sizeof(struct ipc64_perm32));
 			err2 |= __put_user(s64.sem_otime, &usp->sem_otime);
 			err2 |= __put_user(s64.sem_ctime, &usp->sem_ctime);
 			err2 |= __put_user(s64.sem_nsems, &usp->sem_nsems);
@@ -2601,7 +2590,7 @@
 			err = sys_semctl(first, second, third, fourth);
 			set_fs(old_fs);
 			err2 = copy_to_user(&usp->sem_perm, &s.sem_perm,
-					    sizeof(struct ipc_perm));
+					    sizeof(struct ipc_perm32));
 			err2 |= __put_user(s.sem_otime, &usp->sem_otime);
 			err2 |= __put_user(s.sem_ctime, &usp->sem_ctime);
 			err2 |= __put_user(s.sem_nsems, &usp->sem_nsems);
@@ -2652,11 +2641,15 @@
 			set_fs(old_fs);
 		}
 		break;
+	default:
+		err = -EINVAL;
 	}
 out:
 	return err;
 }
 
+#define MAXBUF (64*1024)
+
 static int 
 do_sys32_msgsnd(int first, int second, int third, void *uptr)
 {
@@ -2665,14 +2658,14 @@
 	mm_segment_t old_fs;
 	int err;
 
-	if (second < 0)
+	if (second < 0 || (second >= MAXBUF-sizeof(struct msgbuf)))
 		return -EINVAL;
 
-	p = kmalloc(second + sizeof(struct msgbuf) + 4, GFP_USER);
+	p = kmalloc(second + sizeof(struct msgbuf), GFP_USER);
 	if (!p)
 		return -ENOMEM;
 	err = get_user(p->mtype, &up->mtype);
-	err |= __copy_from_user(p->mtext, &up->mtext, second);
+	err |= copy_from_user(p->mtext, &up->mtext, second);
 	if (err) {
 		err = -EFAULT;
 		goto out;
@@ -2695,35 +2688,35 @@
 	mm_segment_t old_fs;
 	int err;
 
-	if (second < 0)
+	if (second < 0 || (second >= MAXBUF-sizeof(struct msgbuf)))
 		return -EINVAL;
 
 	if (!version) {
-		struct ipc_kludge *uipck = (struct ipc_kludge *)uptr;
-		struct ipc_kludge ipck;
+		struct ipc_kludge_32 *uipck = (struct ipc_kludge_32 *)uptr;
+		struct ipc_kludge_32 ipck;
 
 		err = -EINVAL;
 		if (!uptr)
 			goto out;
 		err = -EFAULT;
-		if (copy_from_user(&ipck, uipck, sizeof(struct ipc_kludge)))
+		if (copy_from_user(&ipck, uipck, sizeof(struct ipc_kludge_32)))
 			goto out;
 		uptr = (void *)A(ipck.msgp);
 		msgtyp = ipck.msgtyp;
 	}
 	err = -ENOMEM;
-	p = kmalloc(second + sizeof (struct msgbuf) + 4, GFP_USER);
+	p = kmalloc(second + sizeof (struct msgbuf), GFP_USER);
 	if (!p)
 		goto out;
 	old_fs = get_fs();
 	set_fs(KERNEL_DS);
-	err = sys_msgrcv(first, p, second + 4, msgtyp, third);
+	err = sys_msgrcv(first, p, second, msgtyp, third);
 	set_fs(old_fs);
 	if (err < 0)
 		goto free_then_out;
 	up = (struct msgbuf32 *)uptr;
 	if (put_user(p->mtype, &up->mtype) ||
-	    __copy_to_user(&up->mtext, p->mtext, err))
+	    copy_to_user(&up->mtext, p->mtext, err))
 		err = -EFAULT;
 free_then_out:
 	kfree(p);
@@ -2751,7 +2744,7 @@
 			struct msqid64_ds32 *up = (struct msqid64_ds32 *)uptr;
 
 			err2 = copy_from_user(&m64.msg_perm, &up->msg_perm,
-					      sizeof(struct ipc64_perm));
+					      sizeof(struct ipc64_perm32));
 			err2 |= __get_user(m64.msg_qbytes, &up->msg_qbytes);
 			if (err2) {
 				err = -EFAULT;
@@ -2767,7 +2760,7 @@
 			struct msqid_ds32 *up = (struct msqid_ds32 *)uptr;
 
 			err2 = copy_from_user(&m.msg_perm, &up->msg_perm,
-					      sizeof(struct ipc_perm));
+					      sizeof(struct ipc_perm32));
 			err2 |= __get_user(m.msg_qbytes, &up->msg_qbytes);
 			if (err2) {
 				err = -EFAULT;
@@ -2793,7 +2786,7 @@
 			set_fs(old_fs);
 
 			err2 = copy_to_user(&up->msg_perm, &m64.msg_perm,
-					    sizeof(struct ipc64_perm));
+					    sizeof(struct ipc64_perm32));
  			err2 |= __put_user(m64.msg_stime, &up->msg_stime);
 			err2 |= __put_user(m64.msg_rtime, &up->msg_rtime);
 			err2 |= __put_user(m64.msg_ctime, &up->msg_ctime);
@@ -2814,7 +2807,7 @@
 			set_fs(old_fs);
 
 			err2 = copy_to_user(&up->msg_perm, &m.msg_perm,
-					    sizeof(struct ipc_perm));
+					    sizeof(struct ipc_perm32));
  			err2 |= __put_user(m.msg_stime, &up->msg_stime);
 			err2 |= __put_user(m.msg_rtime, &up->msg_rtime);
 			err2 |= __put_user(m.msg_ctime, &up->msg_ctime);
@@ -2850,7 +2843,7 @@
 static int
 do_sys32_shmctl(int first, int second, void *uptr)
 {
-	int err = -EFAULT, err2;
+	int err = -EINVAL, err2;
 	mm_segment_t old_fs;
 
 	switch (second & (~IPC_64)) {
@@ -2908,7 +2901,7 @@
 				break;
 
 			err2 = copy_to_user(&up->shm_perm, &s64.shm_perm,
-					    sizeof(struct ipc64_perm));
+					    sizeof(struct ipc64_perm32));
 			err2 |= __put_user(s64.shm_atime, &up->shm_atime);
 			err2 |= __put_user(s64.shm_dtime, &up->shm_dtime);
 			err2 |= __put_user(s64.shm_ctime, &up->shm_ctime);
@@ -2930,7 +2923,7 @@
 				break;
 
 			err2 = copy_to_user(&up->shm_perm, &s.shm_perm,
-					    sizeof(struct ipc_perm));
+					    sizeof(struct ipc_perm32));
 			err2 |= __put_user (s.shm_atime, &up->shm_atime);
 			err2 |= __put_user (s.shm_dtime, &up->shm_dtime);
 			err2 |= __put_user (s.shm_ctime, &up->shm_ctime);
@@ -4241,32 +4234,6 @@
 }
 
 
-extern asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on);
-
-/* Note: it is necessary to treat on as an unsigned int,
- * with the corresponding cast to a signed int to insure that the 
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage long sys32_ioperm(unsigned long from, unsigned long num, u32 on)
-{
-	return sys_ioperm(from, num, (int)on);
-}
-
-
-extern asmlinkage int sys_iopl(int a1, int a2, int a3, int a4);
-
-/* Note: it is necessary to treat a1, a2, a3, and a4 as unsigned ints,
- * with the corresponding cast to a signed int to insure that the 
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage int sys32_iopl(u32 a1, u32 a2, u32 a3, u32 a4)
-{
-	return sys_iopl((int)a1, (int)a2, (int)a3, (int)a4);
-}
-
-
 extern asmlinkage long sys_kill(int pid, int sig);
 
 /* Note: it is necessary to treat pid and sig as unsigned ints,
@@ -4306,19 +4273,6 @@
 }
 
 
-extern asmlinkage int sys_modify_ldt(int a1, int a2, int a3, int a4);
-
-/* Note: it is necessary to treat a1, a2, a3, and a4 as unsigned ints,
- * with the corresponding cast to a signed int to insure that the 
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage int sys32_modify_ldt(u32 a1, u32 a2, u32 a3, u32 a4)
-{
-	return sys_modify_ldt((int)a1, (int)a2, (int)a3, (int)a4);
-}
-
-
 extern asmlinkage long sys_msync(unsigned long start, size_t len, int flags);
 
 /* Note: it is necessary to treat flags as an unsigned int,
@@ -4344,19 +4298,36 @@
 	return sys_nice((int)increment);
 }
 
-
-extern asmlinkage long sys_open(const char * filename, int flags, int mode);
-
-/* Note: it is necessary to treat flags and mode as unsigned ints,
- * with the corresponding cast to a signed int to insure that the 
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
+/*
+ * This is just a version for 32-bit applications which does
+ * not force O_LARGEFILE on.
  */
-asmlinkage long sys32_open(const char * filename, int flags, int mode)
+long sys32_open(const char * filename, int flags, int mode)
 {
-	return sys_open(filename, (int)flags, (int)mode);
-}
+	char * tmp;
+	int fd, error;
+
+	tmp = getname(filename);
+	fd = PTR_ERR(tmp);
+	if (!IS_ERR(tmp)) {
+		fd = get_unused_fd();
+		if (fd >= 0) {
+			struct file * f = filp_open(tmp, flags, mode);
+			error = PTR_ERR(f);
+			if (IS_ERR(f))
+				goto out_error;
+			fd_install(fd, f);
+		}
+out:
+		putname(tmp);
+	}
+	return fd;
 
+out_error:
+	put_unused_fd(fd);
+	fd = error;
+	goto out;
+}
 
 extern asmlinkage long sys_readlink(const char * path, char * buf, int bufsiz);
 
@@ -4604,23 +4575,6 @@
 	return sys_vfork((int)p1, (int)p2, (int)p3, (int)p4, (int)p5, (int)p6, regs);
 }
 
-
-extern asmlinkage int sys_vm86(int a1, int a2, int a3, int a4);
-
-/* Note: it is necessary to treat a1, a2, a3, and a4 as unsigned ints,
- * with the corresponding cast to a signed int to insure that the 
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage int sys32_vm86(u32 a1, u32 a2, u32 a3, u32 a4)
-{
-	return sys_vm86((int)a1, (int)a2, (int)a3, (int)a4);
-}
-
-
-
-
-
 extern asmlinkage ssize_t sys_pread(unsigned int fd, char * buf,
 				    size_t count, loff_t pos);
 
@@ -4641,6 +4595,12 @@
 	return sys_pwrite(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo));
 }
 
+extern ssize_t sys_readahead(int fd, loff_t offset, size_t count);
+
+ssize_t32 sys32_readahead(int fd, u32 r4, u32 offhi, u32 offlo, u32 count)
+{
+        return sys_readahead(fd, ((loff_t)offhi << 32) | offlo, AA(count));
+}
 
 extern asmlinkage long sys_truncate(const char * path, unsigned long length);
 extern asmlinkage long sys_ftruncate(unsigned int fd, unsigned long length);
@@ -4737,3 +4697,15 @@
 
 	return secs;
 }
+
+extern unsigned long sys_mmap(unsigned long addr, size_t len,
+			      unsigned long prot, unsigned long flags,
+			      unsigned long fd, off_t offset);
+
+unsigned long sys32_mmap2(unsigned long addr, size_t len,
+			  unsigned long prot, unsigned long flags,
+			  unsigned long fd, unsigned long pgoff)
+{
+	/* This should remain 12 even if PAGE_SIZE changes */
+	return sys_mmap(addr, len, prot, flags, fd, pgoff << 12);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/syscalls.c linux-2.4.21-pre6/arch/ppc64/kernel/syscalls.c
--- linux-2.4.20/arch/ppc64/kernel/syscalls.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/syscalls.c	2003-03-26 23:49:40.000000000 +0000
@@ -54,28 +54,9 @@
 
 asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
 {
-	printk(KERN_ERR "sys_ioperm()\n");
 	return -EIO;
 }
 
-int sys_iopl(int a1, int a2, int a3, int a4)
-{
-	printk(KERN_ERR "sys_iopl(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
-	return (-ENOSYS);
-}
-
-int sys_vm86(int a1, int a2, int a3, int a4)
-{
-	printk(KERN_ERR "sys_vm86(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
-	return (-ENOSYS);
-}
-
-int sys_modify_ldt(int a1, int a2, int a3, int a4)
-{
-	printk(KERN_ERR "sys_modify_ldt(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
-	return (-ENOSYS);
-}
-
 /*
  * sys_ipc() is the de-multiplexer for the SysV IPC calls..
  *
@@ -125,7 +106,7 @@
 						(struct ipc_kludge *) ptr,
 						sizeof (tmp))))
 				break;
-			ret = sys_msgrcv (first, (struct msgbuf *)(unsigned long)tmp.msgp,
+			ret = sys_msgrcv (first, (struct msgbuf *)tmp.msgp,
 						second, tmp.msgtyp, third);
 			break;
 		}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/time.c linux-2.4.21-pre6/arch/ppc64/kernel/time.c
--- linux-2.4.20/arch/ppc64/kernel/time.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/time.c	2003-03-26 23:49:20.000000000 +0000
@@ -212,9 +212,9 @@
 				tb_ticks_per_jiffy = new_tb_ticks_per_jiffy;
 				tb_ticks_per_sec   = new_tb_ticks_per_sec;
 				div128_by_32( XSEC_PER_SEC, 0, tb_ticks_per_sec, &divres );
-				naca->tb_ticks_per_sec = tb_ticks_per_sec;
+				systemcfg->tb_ticks_per_sec = tb_ticks_per_sec;
 				tb_to_xs = divres.result_low;
-				naca->tb_to_xs = tb_to_xs;
+				systemcfg->tb_to_xs = tb_to_xs;
 			}
 			else {
 				printk( "Titan recalibrate: FAILED (difference > 4 percent)\n"
@@ -258,6 +258,8 @@
 	if ((!user_mode(regs)) && (prof_buffer))
 		ppc_do_profile(instruction_pointer(regs));
 
+	pmc_timeslice_tick(); /* Hack this in for now */
+
 	lpaca->xLpPaca.xIntDword.xFields.xDecrInt = 0;
 
 	while (lpaca->next_jiffy_update_tb <= (cur_tb = get_tb())) {
@@ -306,9 +308,9 @@
 	unsigned long temp_tb_to_xs, temp_stamp_xsec;
 	unsigned long tb_count_1, tb_count_2;
 	unsigned long always_zero;
-	struct naca_struct *gtdp;
+	struct systemcfg *gtdp;
 	
-	gtdp = (struct naca_struct *)0xC000000000004000;
+	gtdp = systemcfg;
 	/* 
 	 * The following loop guarantees that we see a consistent view of the
 	 * tb_to_xs and stamp_xsec variables.  These two variables can change
@@ -412,23 +414,23 @@
 	time_maxerror = NTP_PHASE_LIMIT;
 	time_esterror = NTP_PHASE_LIMIT;
 
-	delta_xsec = mulhdu( (tb_last_stamp-naca->tb_orig_stamp), naca->tb_to_xs );
+	delta_xsec = mulhdu( (tb_last_stamp-systemcfg->tb_orig_stamp), systemcfg->tb_to_xs );
 	new_xsec = (new_usec * XSEC_PER_SEC) / USEC_PER_SEC;
 	new_xsec += new_sec * XSEC_PER_SEC;
 	if ( new_xsec > delta_xsec ) {
-		naca->stamp_xsec = new_xsec - delta_xsec;
+		systemcfg->stamp_xsec = new_xsec - delta_xsec;
 	}
 	else {
 		/* This is only for the case where the user is setting the time
 		 * way back to a time such that the boot time would have been
 		 * before 1970 ... eg. we booted ten days ago, and we are
 		 * setting the time to Jan 5, 1970 */
-		naca->stamp_xsec = new_xsec;
-		naca->tb_orig_stamp = tb_last_stamp;
+		systemcfg->stamp_xsec = new_xsec;
+		systemcfg->tb_orig_stamp = tb_last_stamp;
 	}
 
-	naca->tz_minuteswest = sys_tz.tz_minuteswest;
-	naca->tz_dsttime = sys_tz.tz_dsttime;
+	systemcfg->tz_minuteswest = sys_tz.tz_minuteswest;
+	systemcfg->tz_dsttime = sys_tz.tz_dsttime;
 
 	write_unlock_irqrestore(&xtime_lock, flags);
 }
@@ -498,11 +500,11 @@
 	xtime.tv_sec = mktime(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
 			      tm.tm_hour, tm.tm_min, tm.tm_sec);
 	tb_last_stamp = get_tb();
-	naca->tb_orig_stamp = tb_last_stamp;
-	naca->tb_update_count = 0;
-	naca->tb_ticks_per_sec = tb_ticks_per_sec;
-	naca->stamp_xsec = xtime.tv_sec * XSEC_PER_SEC;
-	naca->tb_to_xs = tb_to_xs;
+	systemcfg->tb_orig_stamp = tb_last_stamp;
+	systemcfg->tb_update_count = 0;
+	systemcfg->tb_ticks_per_sec = tb_ticks_per_sec;
+	systemcfg->stamp_xsec = xtime.tv_sec * XSEC_PER_SEC;
+	systemcfg->tb_to_xs = tb_to_xs;
 
 	xtime_sync_interval = tb_ticks_per_sec - (tb_ticks_per_sec/8);
 	next_xtime_sync_tb = tb_last_stamp + xtime_sync_interval;
@@ -614,14 +616,14 @@
 	 * tb_to_xs) and so guarantees that the current time remains the same
 	 *
 	 */ 
-	tb_ticks = get_tb() - naca->tb_orig_stamp;
+	tb_ticks = get_tb() - systemcfg->tb_orig_stamp;
 	div128_by_32( 1024*1024, 0, new_tb_ticks_per_sec, &divres );
 	new_tb_to_xs = divres.result_low;
 	new_xsec = mulhdu( tb_ticks, new_tb_to_xs );
 
 	write_lock_irqsave( &xtime_lock, flags );
-	old_xsec = mulhdu( tb_ticks, naca->tb_to_xs );
-	new_stamp_xsec = naca->stamp_xsec + old_xsec - new_xsec;
+	old_xsec = mulhdu( tb_ticks, systemcfg->tb_to_xs );
+	new_stamp_xsec = systemcfg->stamp_xsec + old_xsec - new_xsec;
 
 	/*
 	 * tb_update_count is used to allow the problem state gettimeofday code
@@ -632,12 +634,12 @@
 	 * tb_to_xs and stamp_xsec values are consistent.  If not, then it
 	 * loops back and reads them again until this criteria is met.
 	 */
-	++(naca->tb_update_count);
+	++(systemcfg->tb_update_count);
 	wmb();
-	naca->tb_to_xs = new_tb_to_xs;
-	naca->stamp_xsec = new_stamp_xsec;
+	systemcfg->tb_to_xs = new_tb_to_xs;
+	systemcfg->stamp_xsec = new_stamp_xsec;
 	wmb();
-	++(naca->tb_update_count);
+	++(systemcfg->tb_update_count);
 
 	write_unlock_irqrestore( &xtime_lock, flags );
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/traps.c linux-2.4.21-pre6/arch/ppc64/kernel/traps.c
--- linux-2.4.20/arch/ppc64/kernel/traps.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/traps.c	2003-03-26 23:49:26.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- *  linux/arch/ppc/kernel/traps.c
+ *  linux/arch/ppc64/kernel/traps.c
  *
  *  Copyright (C) 1995-1996  Gary Thomas (gdt@linuxppc.org)
  *
@@ -81,7 +81,7 @@
 int (*debugger_bpt)(struct pt_regs *regs);
 int (*debugger_sstep)(struct pt_regs *regs);
 int (*debugger_iabr_match)(struct pt_regs *regs);
-int (*debugger_dabr_match)(struct pt_regs *regs);
+int (*debugger_dabr_match)(struct pt_regs *regs) = kdb;
 /* - only defined during (xmon) mread */
 void (*debugger_fault_handler)(struct pt_regs *regs);
 #endif /* kdb */
@@ -94,8 +94,8 @@
  * Trap & Exception support
  */
 
-void
-_exception(int signr, struct pt_regs *regs)
+static void
+_exception(int signr, siginfo_t *info, struct pt_regs *regs)
 {
 	if (!user_mode(regs))
 	{
@@ -104,7 +104,8 @@
 		debugger(regs);
 #endif
 #if defined(CONFIG_KDB)
-		kdb(KDB_REASON_OOPS, 0, (kdb_eframe_t) regs);
+		if (kdb(KDB_REASON_BREAK, 0, (kdb_eframe_t) regs))
+		    return;
 #endif
 		print_backtrace((unsigned long *)regs->gpr[1]);
 		panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
@@ -115,7 +116,7 @@
 			debugger(regs);
 #endif
 	}
-	force_sig(signr, current);
+	force_sig_info(signr, info, current);
 }
 
 /* Get the error information for errors coming through the
@@ -155,35 +156,47 @@
 SystemResetException(struct pt_regs *regs)
 {
 	char *msg = "System Reset in kernel mode.\n";
-	udbg_printf(msg); printk(msg);
+	printk(msg);
 	if (fwnmi_active) {
 		unsigned long *r3 = __va(regs->gpr[3]); /* for FWNMI debug */
-		struct rtas_error_log *errlog;
-
-		msg = "FWNMI is active with save area at %016lx\n";
-		udbg_printf(msg, r3); printk(msg, r3);
-		errlog = FWNMI_get_errinfo(regs);
+		printk("FWNMI is active with save area at %p\n", r3);
+		FWNMI_release_errinfo();
 	}
 #if defined(CONFIG_XMON)
 	xmon(regs);
 	udbg_printf("leaving xmon...\n");
 #endif
 #if defined(CONFIG_KDB)
-	kdb(KDB_REASON_ENTER, regs->trap, (kdb_eframe_t) regs);
-	udbg_printf("leaving kdb...\n");
+	{
+		int cpu = smp_processor_id();
+		static int reset_cpu = -1;
+		static spinlock_t reset_lock = SPIN_LOCK_UNLOCKED;
+
+		/* Give kdb some help serializing the reset */
+		spin_lock(&reset_lock);
+		if (reset_cpu == -1) {
+			reset_cpu = cpu;
+			spin_unlock(&reset_lock);
+			kdb(KDB_REASON_ENTER, regs->trap, (kdb_eframe_t) regs);
+			reset_cpu = -1;
+		} else {
+			spin_unlock(&reset_lock);
+			/* Let kdb catch this cpu with an IPI.
+			 * Ideally we need a way to enter kdb w/o it becoming
+			 * confused so we can precisely capture reset state.
+			 */
+			return;
+		}
+	}
 #endif
-
-/*
-allow system to resume after reset.
-	for(;;);
-*/
-
 }
 
 
 void
 MachineCheckException(struct pt_regs *regs)
 {
+	siginfo_t info;
+
 	if (fwnmi_active) {
 		struct rtas_error_log *errhdr = FWNMI_get_errinfo(regs);
 		if (errhdr) {
@@ -191,18 +204,14 @@
 		}
 		FWNMI_release_errinfo();
 	}
-	if ( !user_mode(regs) )
-	{
+
+	if ( !user_mode(regs) ) {
 #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
 		if (debugger_fault_handler) {
 			debugger_fault_handler(regs);
 			return;
 		}
 #endif
-#ifdef CONFIG_KDB
-		if (kdb(KDB_REASON_FAULT, 0, regs))
-			return;
-#endif
 		printk("Machine check in kernel mode.\n");
 		printk("Caused by (from SRR1=%lx): ", regs->msr);
 		show_regs(regs);
@@ -216,7 +225,17 @@
 		print_backtrace((unsigned long *)regs->gpr[1]);
 		panic("machine check");
 	}
-	_exception(SIGSEGV, regs);	
+	
+	/*
+	 * XXX we should check RI bit on exception exit and kill the
+	 * task if it was cleared
+	 */
+	info.si_signo = SIGBUS;
+	info.si_errno = 0;
+	info.si_code = BUS_ADRERR;
+	info.si_addr = (void *)regs->nip;
+	_exception(SIGSEGV, &info, regs);
+
 }
 
 void
@@ -242,33 +261,98 @@
 void
 UnknownException(struct pt_regs *regs)
 {
+	siginfo_t info;
+
 	printk("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
 	       regs->nip, regs->msr, regs->trap);
-	_exception(SIGTRAP, regs);	
+
+	info.si_signo = SIGTRAP;
+	info.si_errno = 0;
+	info.si_code = 0;
+	info.si_addr = 0;
+	_exception(SIGTRAP, &info, regs);	
 }
 
 void
 InstructionBreakpointException(struct pt_regs *regs)
 {
+	siginfo_t info;
+	
 #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
 	if (debugger_iabr_match(regs))
 		return;
 #endif
 #ifdef CONFIG_KDB
 	if (kdb(KDB_REASON_BREAK, 0, regs))
-		return ;
+		return;
 #endif
-	_exception(SIGTRAP, regs);
+
+	info.si_signo = SIGTRAP;
+	info.si_errno = 0;
+	info.si_code = TRAP_BRKPT;
+	info.si_addr = (void *)regs->nip;
+	_exception(SIGTRAP, &info, regs);
+}
+
+static void
+parse_fpe(siginfo_t *info, struct pt_regs *regs)
+{
+	unsigned long fpscr;
+
+	if (regs->msr & MSR_FP)
+		giveup_fpu(current);
+
+	fpscr = current->thread.fpscr;
+
+	/* Invalid operation */
+	if ((fpscr & FPSCR_VE) && (fpscr & FPSCR_VX))
+		info->si_code = FPE_FLTINV;
+
+	/* Overflow */
+	else if ((fpscr & FPSCR_OE) && (fpscr & FPSCR_OX))
+		info->si_code = FPE_FLTOVF;
+
+	/* Underflow */
+	else if ((fpscr & FPSCR_UE) && (fpscr & FPSCR_UX))
+		info->si_code = FPE_FLTUND;
+
+	/* Divide by zero */
+	else if ((fpscr & FPSCR_ZE) && (fpscr & FPSCR_ZX))
+		info->si_code = FPE_FLTDIV;
+
+	/* Inexact result */
+	else if ((fpscr & FPSCR_XE) && (fpscr & FPSCR_XX))
+		info->si_code = FPE_FLTRES;
+
+	else
+		info->si_code = 0;
+
+	info->si_signo = SIGFPE;
+	info->si_errno = 0;
+	info->si_addr = (void *)regs->nip;
+	_exception(SIGFPE, info, regs);
 }
 
 void
 ProgramCheckException(struct pt_regs *regs)
 {
+	siginfo_t info;
+
 	if (regs->msr & 0x100000) {
 		/* IEEE FP exception */
-		_exception(SIGFPE, regs);
+
+		parse_fpe(&info, regs);
+	} else if (regs->msr & 0x40000) {
+		/* Privileged instruction */
+
+		info.si_signo = SIGILL;
+		info.si_errno = 0;
+		info.si_code = ILL_PRVOPC;
+		info.si_addr = (void *)regs->nip;
+		_exception(SIGILL, &info, regs);
 	} else if (regs->msr & 0x20000) {
 		/* trap exception */
+
 #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
 		if (debugger_bpt(regs))
 			return;
@@ -277,16 +361,29 @@
 		if (kdb(KDB_REASON_BREAK, 0, regs))
 			return;
 #endif
-		_exception(SIGTRAP, regs);
+		info.si_signo = SIGTRAP;
+		info.si_errno = 0;
+		info.si_code = TRAP_BRKPT;
+		info.si_addr = (void *)regs->nip;
+		_exception(SIGTRAP, &info, regs);
 	} else {
-		_exception(SIGILL, regs);
+		/* Illegal instruction */
+
+		info.si_signo = SIGILL;
+		info.si_errno = 0;
+		info.si_code = ILL_ILLTRP;
+		info.si_addr = (void *)regs->nip;
+		_exception(SIGILL, &info, regs);
 	}
 }
 
 void
 SingleStepException(struct pt_regs *regs)
 {
+	siginfo_t info;
+
 	regs->msr &= ~MSR_SE;  /* Turn off 'trace' bit */
+
 #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
 	if (debugger_sstep(regs))
 		return;
@@ -295,13 +392,19 @@
 	if (kdb(KDB_REASON_DEBUG, 0, regs))
 		return;
 #endif
-	_exception(SIGTRAP, regs);	
+
+	info.si_signo = SIGTRAP;
+	info.si_errno = 0;
+	info.si_code = TRAP_TRACE;
+	info.si_addr = (void *)regs->nip;
+	_exception(SIGTRAP, &info, regs);	
 }
 
 void
 AlignmentException(struct pt_regs *regs)
 {
 	int fixed;
+	siginfo_t info;
 
 	fixed = fix_alignment(regs);
 	if (fixed == 1) {
@@ -311,15 +414,28 @@
 		regs->nip += 4;	/* skip over emulated instruction */
 		return;
 	}
+	
+	/* Operand address was bad */
 	if (fixed == -EFAULT) {
-		/* fixed == -EFAULT means the operand address was bad */
-		if (user_mode(regs))
-			force_sig(SIGSEGV, current);
-		else
+		if (user_mode(regs)) {
+			info.si_signo = SIGSEGV;
+			info.si_errno = 0;
+			info.si_code = SEGV_MAPERR;
+			info.si_addr = (void *)regs->dar;
+			force_sig_info(SIGSEGV, &info, current);
+		} else {
+			/* Search exception table */
 			bad_page_fault(regs, regs->dar);
+		}
+
 		return;
 	}
-	_exception(SIGBUS, regs);	
+
+	info.si_signo = SIGBUS;
+	info.si_errno = 0;
+	info.si_code = BUS_ADRALN;
+	info.si_addr = (void *)regs->nip;
+	_exception(SIGBUS, &info, regs);
 }
 
 void __init trap_init(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/udbg.c linux-2.4.21-pre6/arch/ppc64/kernel/udbg.c
--- linux-2.4.20/arch/ppc64/kernel/udbg.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/udbg.c	2003-03-26 23:49:25.000000000 +0000
@@ -82,7 +82,7 @@
 				/* wait for idle */;
 			udbg_comport->thr = '\r'; eieio();
 		}
-	} else if (naca->platform == PLATFORM_ISERIES_LPAR) {
+	} else if (systemcfg->platform == PLATFORM_ISERIES_LPAR) {
 		/* ToDo: switch this via ppc_md */
 		printk("%c", c);
 	}
@@ -119,8 +119,6 @@
 		if (s && *s != '\0') {
 			while ((c = *s++) != '\0')
 				ppc_md.udbg_putc(c);
-		} else {
-			udbg_puts("NULL");
 		}
 	} else {
 		printk("%s", s);
@@ -138,8 +136,7 @@
 		while ( (( c = *s++ ) != '\0') && (remain-- > 0)) {
 			ppc_md.udbg_putc(c);
 		}
-	} else
-		udbg_puts("NULL");
+	}
 	return n - remain;
 }
 
@@ -182,7 +179,7 @@
 void
 udbg_printSP(const char *s)
 {
-	if (naca->platform == PLATFORM_PSERIES) {
+	if (systemcfg->platform == PLATFORM_PSERIES) {
 		unsigned long sp;
 		asm("mr %0,1" : "=r" (sp) :);
 		if (s)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/kernel/xics.c linux-2.4.21-pre6/arch/ppc64/kernel/xics.c
--- linux-2.4.20/arch/ppc64/kernel/xics.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/kernel/xics.c	2003-03-26 23:49:20.000000000 +0000
@@ -88,6 +88,7 @@
 /* RTAS service tokens */
 int ibm_get_xive;
 int ibm_set_xive;
+int ibm_int_on;
 int ibm_int_off;
 
 struct xics_interrupt_node {
@@ -159,6 +160,14 @@
 		       irq, call_status, status);
 		return;
 	}
+	/* Now unmask the interrupt (often a no-op) */
+	call_status = rtas_call(ibm_int_on, 1, 1, (unsigned long*)&status, 
+				irq);
+	if( call_status != 0 ) {
+		printk("xics_disable_irq on: irq=%x: rtas_call failed, retn=%lx\n",
+		       irq, call_status);
+		return;
+	}
 }
 
 void
@@ -289,6 +298,7 @@
 
 	ibm_get_xive = rtas_token("ibm,get-xive");
 	ibm_set_xive = rtas_token("ibm,set-xive");
+	ibm_int_on  = rtas_token("ibm,int-on");
 	ibm_int_off = rtas_token("ibm,int-off");
 
 	np = find_type_devices("PowerPC-External-Interrupt-Presentation");
@@ -362,9 +372,9 @@
 		xics_irq_8259_cascade = virt_irq_create_mapping(xics_irq_8259_cascade_real);
 	}
 
-	if (naca->platform == PLATFORM_PSERIES) {
+	if (systemcfg->platform == PLATFORM_PSERIES) {
 #ifdef CONFIG_SMP
-		for (i = 0; i < naca->processorCount; ++i) {
+		for (i = 0; i < systemcfg->processorCount; ++i) {
 			xics_info.per_cpu[i] =
 			  __ioremap((ulong)inodes[get_hard_smp_processor_id(i)].addr, 
 				  (ulong)inodes[get_hard_smp_processor_id(i)].size, _PAGE_NO_CACHE);
@@ -376,7 +386,7 @@
 	/* actually iSeries does not use any of xics...but it has link dependencies
 	 * for now, except this new one...
 	 */
-	} else if (naca->platform == PLATFORM_PSERIES_LPAR) {
+	} else if (systemcfg->platform == PLATFORM_PSERIES_LPAR) {
 		ops = &pSeriesLP_ops;
 #endif
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/lib/Makefile linux-2.4.21-pre6/arch/ppc64/lib/Makefile
--- linux-2.4.20/arch/ppc64/lib/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/lib/Makefile	2003-03-26 23:49:55.000000000 +0000
@@ -6,6 +6,9 @@
 
 O_TARGET = lib.o
 
-obj-y           := checksum.o dec_and_lock.o string.o strcase.o
+export-objs     := dec_and_lock.o
+
+obj-y           := checksum.o dec_and_lock.o string.o strcase.o copypage.o \
+		   memcpy.o copyuser.o
 
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/lib/copypage.S linux-2.4.21-pre6/arch/ppc64/lib/copypage.S
--- linux-2.4.20/arch/ppc64/lib/copypage.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/lib/copypage.S	2003-03-26 23:49:07.000000000 +0000
@@ -0,0 +1,121 @@
+/*
+ * arch/ppc64/lib/copypage.S
+ *
+ * Copyright (C) 2002 Paul Mackerras, IBM Corp.
+ *
+ * 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 <asm/processor.h>
+#include <asm/ppc_asm.tmpl>
+
+_GLOBAL(copy_page)
+	std	r31,-8(1)
+	std	r30,-16(1)
+	std	r29,-24(1)
+	std	r28,-32(1)
+	std	r27,-40(1)
+	std	r26,-48(1)
+	std	r25,-56(1)
+	std	r24,-64(1)
+	std	r23,-72(1)
+	std	r22,-80(1)
+	std	r21,-88(1)
+	std	r20,-96(1)
+	li	r5,4096/32 - 1
+	addi	r3,r3,-8
+	li	r12,5
+0:	addi	r5,r5,-24
+	mtctr	r12
+	ld	r22,640(4)
+	ld	r21,512(4)
+	ld	r20,384(4)
+	ld	r11,256(4)
+	ld	r9,128(4)
+	ld	r7,0(4)
+	ld	r25,648(4)
+	ld	r24,520(4)
+	ld	r23,392(4)
+	ld	r10,264(4)
+	ld	r8,136(4)
+	ldu	r6,8(4)
+	cmpwi	r5,24
+1:	std	r22,648(3)
+	std	r21,520(3)
+	std	r20,392(3)
+	std	r11,264(3)
+	std	r9,136(3)
+	std	r7,8(3)
+	ld	r28,648(4)
+	ld	r27,520(4)
+	ld	r26,392(4)
+	ld	r31,264(4)
+	ld	r30,136(4)
+	ld	r29,8(4)
+	std	r25,656(3)
+	std	r24,528(3)
+	std	r23,400(3)
+	std	r10,272(3)
+	std	r8,144(3)
+	std	r6,16(3)
+	ld	r22,656(4)
+	ld	r21,528(4)
+	ld	r20,400(4)
+	ld	r11,272(4)
+	ld	r9,144(4)
+	ld	r7,16(4)
+	std	r28,664(3)
+	std	r27,536(3)
+	std	r26,408(3)
+	std	r31,280(3)
+	std	r30,152(3)
+	stdu	r29,24(3)
+	ld	r25,664(4)
+	ld	r24,536(4)
+	ld	r23,408(4)
+	ld	r10,280(4)
+	ld	r8,152(4)
+	ldu	r6,24(4)
+	bdnz	1b
+	std	r22,648(3)
+	std	r21,520(3)
+	std	r20,392(3)
+	std	r11,264(3)
+	std	r9,136(3)
+	std	r7,8(3)
+	addi	r4,r4,640
+	addi	r3,r3,648
+	bge	0b
+	mtctr	r5
+	ld	r7,0(4)
+	ld	r8,8(4)
+	ldu	r9,16(4)
+3:	ld	r10,8(4)
+	std	r7,8(3)
+	ld	r7,16(4)
+	std	r8,16(3)
+	ld	r8,24(4)
+	std	r9,24(3)
+	ldu	r9,32(4)
+	stdu	r10,32(3)
+	bdnz	3b
+4:	ld	r10,8(4)
+	std	r7,8(3)
+	std	r8,16(3)
+	std	r9,24(3)
+	std	r10,32(3)
+9:	ld	r20,-96(1)
+	ld	r21,-88(1)
+	ld	r22,-80(1)
+	ld	r23,-72(1)
+	ld	r24,-64(1)
+	ld	r25,-56(1)
+	ld	r26,-48(1)
+	ld	r27,-40(1)
+	ld	r28,-32(1)
+	ld	r29,-24(1)
+	ld	r30,-16(1)
+	ld	r31,-8(1)
+	blr
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/lib/copyuser.S linux-2.4.21-pre6/arch/ppc64/lib/copyuser.S
--- linux-2.4.20/arch/ppc64/lib/copyuser.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/lib/copyuser.S	2003-03-26 23:49:35.000000000 +0000
@@ -0,0 +1,564 @@
+/*
+ * arch/ppc64/lib/copyuser.S
+ *
+ * Copyright (C) 2002 Paul Mackerras, IBM Corp.
+ *
+ * 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 <asm/processor.h>
+#include <asm/ppc_asm.tmpl>
+
+	.align	7
+_GLOBAL(__copy_tofrom_user)
+	/* first check for a whole page copy on a page boundary */
+	cmpldi	cr1,r5,16
+	cmpdi	cr6,r5,4096
+	or	r0,r3,r4
+	neg	r6,r3		/* LS 3 bits = # bytes to 8-byte dest bdry */
+	andi.	r0,r0,4095
+	std	r3,-24(r1)
+	crand	cr0*4+2,cr0*4+2,cr6*4+2
+	std	r4,-16(r1)
+	std	r5,-8(r1)
+	dcbt	0,r4
+	beq	.Lcopy_page
+	andi.	r6,r6,7
+	mtcrf	0x01,r5
+	blt	cr1,.Lshort_copy
+	bne	.Ldst_unaligned
+.Ldst_aligned:
+	andi.	r0,r4,7
+	addi	r3,r3,-16
+	bne	.Lsrc_unaligned
+	srdi	r7,r5,4
+20:	ld	r9,0(r4)
+	addi	r4,r4,-8
+	mtctr	r7
+	andi.	r5,r5,7
+	bf	cr7*4+0,22f
+	addi	r3,r3,8
+	addi	r4,r4,8
+	mr	r8,r9
+	blt	cr1,72f
+21:	ld	r9,8(r4)
+70:	std	r8,8(r3)
+22:	ldu	r8,16(r4)
+71:	stdu	r9,16(r3)
+	bdnz	21b
+72:	std	r8,8(r3)
+	beq+	3f
+	addi	r3,r3,16
+23:	ld	r9,8(r4)
+.Ldo_tail:
+	bf	cr7*4+1,1f
+	rotldi	r9,r9,32
+73:	stw	r9,0(r3)
+	addi	r3,r3,4
+1:	bf	cr7*4+2,2f
+	rotldi	r9,r9,16
+74:	sth	r9,0(r3)
+	addi	r3,r3,2
+2:	bf	cr7*4+3,3f
+	rotldi	r9,r9,8
+75:	stb	r9,0(r3)
+3:	li	r3,0
+	blr
+
+.Lsrc_unaligned:
+	srdi	r6,r5,3
+	addi	r5,r5,-16
+	subf	r4,r0,r4
+	srdi	r7,r5,4
+	sldi	r10,r0,3
+	cmpldi	cr6,r6,3
+	andi.	r5,r5,7
+	mtctr	r7
+	subfic	r11,r10,64
+	add	r5,r5,r0
+	bt	cr7*4+0,28f
+
+24:	ld	r9,0(r4)	/* 3+2n loads, 2+2n stores */
+25:	ld	r0,8(r4)
+	sld	r6,r9,r10
+26:	ldu	r9,16(r4)
+	srd	r7,r0,r11
+	sld	r8,r0,r10
+	or	r7,r7,r6
+	blt	cr6,79f
+27:	ld	r0,8(r4)
+	b	2f
+
+28:	ld	r0,0(r4)	/* 4+2n loads, 3+2n stores */
+29:	ldu	r9,8(r4)
+	sld	r8,r0,r10
+	addi	r3,r3,-8
+	blt	cr6,5f
+30:	ld	r0,8(r4)
+	srd	r12,r9,r11
+	sld	r6,r9,r10
+31:	ldu	r9,16(r4)
+	or	r12,r8,r12
+	srd	r7,r0,r11
+	sld	r8,r0,r10
+	addi	r3,r3,16
+	beq	cr6,78f
+
+1:	or	r7,r7,r6
+32:	ld	r0,8(r4)
+76:	std	r12,8(r3)
+2:	srd	r12,r9,r11
+	sld	r6,r9,r10
+33:	ldu	r9,16(r4)
+	or	r12,r8,r12
+77:	stdu	r7,16(r3)
+	srd	r7,r0,r11
+	sld	r8,r0,r10
+	bdnz	1b
+
+78:	std	r12,8(r3)
+	or	r7,r7,r6
+79:	std	r7,16(r3)
+5:	srd	r12,r9,r11
+	or	r12,r8,r12
+80:	std	r12,24(r3)
+	bne	6f
+	li	r3,0
+	blr
+6:	cmpwi	cr1,r5,8
+	addi	r3,r3,32
+	sld	r9,r9,r10
+	blt	cr1,.Ldo_tail
+34:	ld	r0,8(r4)
+	srd	r7,r0,r11
+	or	r9,r7,r9
+	b	.Ldo_tail
+
+.Ldst_unaligned:
+	mtcrf	0x01,r6		/* put #bytes to 8B bdry into cr7 */
+	subf	r5,r6,r5
+	li	r7,0
+	cmpldi	r1,r5,16
+	bf	cr7*4+3,1f
+35:	lbz	r0,0(r4)
+81:	stb	r0,0(r3)
+	addi	r7,r7,1
+1:	bf	cr7*4+2,2f
+36:	lhzx	r0,r7,r4
+82:	sthx	r0,r7,r3
+	addi	r7,r7,2
+2:	bf	cr7*4+1,3f
+37:	lwzx	r0,r7,r4
+83:	stwx	r0,r7,r3
+3:	mtcrf	0x01,r5
+	add	r4,r6,r4
+	add	r3,r6,r3
+	b	.Ldst_aligned
+
+.Lshort_copy:
+	bf	cr7*4+0,1f
+38:	lwz	r0,0(r4)
+39:	lwz	r9,4(r4)
+	addi	r4,r4,8
+84:	stw	r0,0(r3)
+85:	stw	r9,4(r3)
+	addi	r3,r3,8
+1:	bf	cr7*4+1,2f
+40:	lwz	r0,0(r4)
+	addi	r4,r4,4
+86:	stw	r0,0(r3)
+	addi	r3,r3,4
+2:	bf	cr7*4+2,3f
+41:	lhz	r0,0(r4)
+	addi	r4,r4,2
+87:	sth	r0,0(r3)
+	addi	r3,r3,2
+3:	bf	cr7*4+3,4f
+42:	lbz	r0,0(r4)
+88:	stb	r0,0(r3)
+4:	li	r3,0
+	blr
+
+/*
+ * exception handlers follow
+ * we have to return the number of bytes not copied
+ * for an exception on a load, we set the rest of the destination to 0
+ */
+
+136:
+137:
+	add	r3,r3,r7
+	b	1f
+130:
+131:
+	addi	r3,r3,8
+120:
+122:
+124:
+125:
+126:
+127:
+128:
+129:
+133:
+	addi	r3,r3,8
+121:
+132:
+	addi	r3,r3,8
+123:
+134:
+135:
+138:
+139:
+140:
+141:
+142:
+
+/*
+ * here we have had a fault on a load and r3 points to the first
+ * unmodified byte of the destination
+ */
+1:	ld	r6,-24(r1)
+	ld	r4,-16(r1)
+	ld	r5,-8(r1)
+	subf	r6,r6,r3
+	add	r4,r4,r6
+	subf	r5,r6,r5	/* #bytes left to go */
+
+/*
+ * first see if we can copy any more bytes before hitting another exception
+ */
+	mtctr	r5
+43:	lbz	r0,0(r4)
+	addi	r4,r4,1
+89:	stb	r0,0(r3)
+	addi	r3,r3,1
+	bdnz	43b
+	li	r3,0		/* huh? all copied successfully this time? */
+	blr
+
+/*
+ * here we have trapped again, need to clear ctr bytes starting at r3
+ */
+143:	mfctr	r5
+	li	r0,0
+	mr	r4,r3
+	mr	r3,r5		/* return the number of bytes not copied */
+1:	andi.	r9,r4,7
+	beq	3f
+90:	stb	r0,0(r4)
+	addic.	r5,r5,-1
+	addi	r4,r4,1
+	bne	1b
+	blr
+3:	cmpldi	cr1,r5,8
+	srdi	r9,r5,3
+	andi.	r5,r5,7
+	blt	cr1,93f
+	mtctr	r9
+91:	std	r0,0(r4)
+	addi	r4,r4,8
+	bdnz	91b
+93:	beqlr
+	mtctr	r5	
+92:	stb	r0,0(r4)
+	addi	r4,r4,1
+	bdnz	92b
+	blr
+
+/*
+ * exception handlers for stores: we just need to work
+ * out how many bytes weren't copied
+ */
+182:
+183:
+	add	r3,r3,r7
+	b	1f
+180:
+	addi	r3,r3,8
+171:
+177:
+	addi	r3,r3,8
+170:
+172:
+176:
+178:
+	addi	r3,r3,4
+185:
+	addi	r3,r3,4
+173:
+174:
+175:
+179:
+181:
+184:
+186:
+187:
+188:
+189:	
+1:
+	ld	r6,-24(r1)
+	ld	r5,-8(r1)
+	add	r6,r6,r5
+	subf	r3,r3,r6	/* #bytes not copied */
+190:
+191:
+192:
+	blr			/* #bytes not copied in r3 */
+
+	.section __ex_table,"a"
+	.align	3
+	.llong	20b,120b
+	.llong	21b,121b
+	.llong	70b,170b
+	.llong	22b,122b
+	.llong	71b,171b
+	.llong	72b,172b
+	.llong	23b,123b
+	.llong	73b,173b
+	.llong	74b,174b
+	.llong	75b,175b
+	.llong	24b,124b
+	.llong	25b,125b
+	.llong	26b,126b
+	.llong	27b,127b
+	.llong	28b,128b
+	.llong	29b,129b
+	.llong	30b,130b
+	.llong	31b,131b
+	.llong	32b,132b
+	.llong	76b,176b
+	.llong	33b,133b
+	.llong	77b,177b
+	.llong	78b,178b
+	.llong	79b,179b
+	.llong	80b,180b
+	.llong	34b,134b
+	.llong	35b,135b
+	.llong	81b,181b
+	.llong	36b,136b
+	.llong	82b,182b
+	.llong	37b,137b
+	.llong	83b,183b
+	.llong	38b,138b
+	.llong	39b,139b
+	.llong	84b,184b
+	.llong	85b,185b
+	.llong	40b,140b
+	.llong	86b,186b
+	.llong	41b,141b
+	.llong	87b,187b
+	.llong	42b,142b
+	.llong	88b,188b
+	.llong	43b,143b
+	.llong	89b,189b
+	.llong	90b,190b
+	.llong	91b,191b
+	.llong	92b,192b
+	
+	.text
+
+/*
+ * Routine to copy a whole page of data, optimized for POWER4.
+ * On POWER4 it is more than 50% faster than the simple loop
+ * above (following the .Ldst_aligned label) but it runs slightly
+ * slower on POWER3.
+ */
+.Lcopy_page:
+	std	r31,-32(1)
+	std	r30,-40(1)
+	std	r29,-48(1)
+	std	r28,-56(1)
+	std	r27,-64(1)
+	std	r26,-72(1)
+	std	r25,-80(1)
+	std	r24,-88(1)
+	std	r23,-96(1)
+	std	r22,-104(1)
+	std	r21,-112(1)
+	std	r20,-120(1)
+	li	r5,4096/32 - 1
+	addi	r3,r3,-8
+	li	r0,5
+0:	addi	r5,r5,-24
+	mtctr	r0
+20:	ld	r22,640(4)
+21:	ld	r21,512(4)
+22:	ld	r20,384(4)
+23:	ld	r11,256(4)
+24:	ld	r9,128(4)
+25:	ld	r7,0(4)
+26:	ld	r25,648(4)
+27:	ld	r24,520(4)
+28:	ld	r23,392(4)
+29:	ld	r10,264(4)
+30:	ld	r8,136(4)
+31:	ldu	r6,8(4)
+	cmpwi	r5,24
+1:
+32:	std	r22,648(3)
+33:	std	r21,520(3)
+34:	std	r20,392(3)
+35:	std	r11,264(3)
+36:	std	r9,136(3)
+37:	std	r7,8(3)
+38:	ld	r28,648(4)
+39:	ld	r27,520(4)
+40:	ld	r26,392(4)
+41:	ld	r31,264(4)
+42:	ld	r30,136(4)
+43:	ld	r29,8(4)
+44:	std	r25,656(3)
+45:	std	r24,528(3)
+46:	std	r23,400(3)
+47:	std	r10,272(3)
+48:	std	r8,144(3)
+49:	std	r6,16(3)
+50:	ld	r22,656(4)
+51:	ld	r21,528(4)
+52:	ld	r20,400(4)
+53:	ld	r11,272(4)
+54:	ld	r9,144(4)
+55:	ld	r7,16(4)
+56:	std	r28,664(3)
+57:	std	r27,536(3)
+58:	std	r26,408(3)
+59:	std	r31,280(3)
+60:	std	r30,152(3)
+61:	stdu	r29,24(3)
+62:	ld	r25,664(4)
+63:	ld	r24,536(4)
+64:	ld	r23,408(4)
+65:	ld	r10,280(4)
+66:	ld	r8,152(4)
+67:	ldu	r6,24(4)
+	bdnz	1b
+68:	std	r22,648(3)
+69:	std	r21,520(3)
+70:	std	r20,392(3)
+71:	std	r11,264(3)
+72:	std	r9,136(3)
+73:	std	r7,8(3)
+74:	addi	r4,r4,640
+75:	addi	r3,r3,648
+	bge	0b
+	mtctr	r5
+76:	ld	r7,0(4)
+77:	ld	r8,8(4)
+78:	ldu	r9,16(4)
+3:
+79:	ld	r10,8(4)
+80:	std	r7,8(3)
+81:	ld	r7,16(4)
+82:	std	r8,16(3)
+83:	ld	r8,24(4)
+84:	std	r9,24(3)
+85:	ldu	r9,32(4)
+86:	stdu	r10,32(3)
+	bdnz	3b
+4:
+87:	ld	r10,8(4)
+88:	std	r7,8(3)
+89:	std	r8,16(3)
+90:	std	r9,24(3)
+91:	std	r10,32(3)
+9:	ld	r20,-120(1)
+	ld	r21,-112(1)
+	ld	r22,-104(1)
+	ld	r23,-96(1)
+	ld	r24,-88(1)
+	ld	r25,-80(1)
+	ld	r26,-72(1)
+	ld	r27,-64(1)
+	ld	r28,-56(1)
+	ld	r29,-48(1)
+	ld	r30,-40(1)
+	ld	r31,-32(1)
+	li	r3,0
+	blr
+
+/*
+ * on an exception, reset to the beginning and jump back into the
+ * standard __copy_tofrom_user
+ */
+100:	ld	r3,-24(r1)
+	ld	r4,-24(r1)
+	li	r5,4096
+	b	.Ldst_aligned
+
+	.section __ex_table,"a"
+	.align	3
+	.llong	20b,100b
+	.llong	21b,100b
+	.llong	22b,100b
+	.llong	23b,100b
+	.llong	24b,100b
+	.llong	25b,100b
+	.llong	26b,100b
+	.llong	27b,100b
+	.llong	28b,100b
+	.llong	29b,100b
+	.llong	30b,100b
+	.llong	31b,100b
+	.llong	32b,100b
+	.llong	33b,100b
+	.llong	34b,100b
+	.llong	35b,100b
+	.llong	36b,100b
+	.llong	37b,100b
+	.llong	38b,100b
+	.llong	39b,100b
+	.llong	40b,100b
+	.llong	41b,100b
+	.llong	42b,100b
+	.llong	43b,100b
+	.llong	44b,100b
+	.llong	45b,100b
+	.llong	46b,100b
+	.llong	47b,100b
+	.llong	48b,100b
+	.llong	49b,100b
+	.llong	50b,100b
+	.llong	51b,100b
+	.llong	52b,100b
+	.llong	53b,100b
+	.llong	54b,100b
+	.llong	55b,100b
+	.llong	56b,100b
+	.llong	57b,100b
+	.llong	58b,100b
+	.llong	59b,100b
+	.llong	60b,100b
+	.llong	61b,100b
+	.llong	62b,100b
+	.llong	63b,100b
+	.llong	64b,100b
+	.llong	65b,100b
+	.llong	66b,100b
+	.llong	67b,100b
+	.llong	68b,100b
+	.llong	69b,100b
+	.llong	70b,100b
+	.llong	71b,100b
+	.llong	72b,100b
+	.llong	73b,100b
+	.llong	74b,100b
+	.llong	75b,100b
+	.llong	76b,100b
+	.llong	77b,100b
+	.llong	78b,100b
+	.llong	79b,100b
+	.llong	80b,100b
+	.llong	81b,100b
+	.llong	82b,100b
+	.llong	83b,100b
+	.llong	84b,100b
+	.llong	85b,100b
+	.llong	86b,100b
+	.llong	87b,100b
+	.llong	88b,100b
+	.llong	89b,100b
+	.llong	90b,100b
+	.llong	91b,100b
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/lib/dec_and_lock.c linux-2.4.21-pre6/arch/ppc64/lib/dec_and_lock.c
--- linux-2.4.20/arch/ppc64/lib/dec_and_lock.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/lib/dec_and_lock.c	2003-03-26 23:48:57.000000000 +0000
@@ -7,32 +7,48 @@
  * 2 of the License, or (at your option) any later version.
  */
 
+#include <linux/module.h>
 #include <linux/spinlock.h>
-#include <asm/system.h>
 #include <asm/atomic.h>
+#include <asm/system.h>
 
+/*
+ * This is an implementation of the notion of "decrement a
+ * reference count, and return locked if it decremented to zero".
+ *
+ * This implementation can be used on any architecture that
+ * has a cmpxchg, and where atomic->value is an int holding
+ * the value of the atomic (i.e. the high bits aren't used
+ * for a lock or anything like that).
+ *
+ * N.B. ATOMIC_DEC_AND_LOCK gets defined in include/linux/spinlock.h
+ * if spinlocks are empty and thus atomic_dec_and_lock is defined
+ * to be atomic_dec_and_test - in that case we don't need it
+ * defined here as well.
+ */
+
+#ifndef ATOMIC_DEC_AND_LOCK
 int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
 {
 	int counter;
 	int newcount;
 
-repeat:
-	counter = atomic_read(atomic);
-	newcount = counter-1;
-
-	if (!newcount)
-		goto slow_path;
+	for (;;) {
+		counter = atomic_read(atomic);
+		newcount = counter - 1;
+		if (!newcount)
+			break;		/* do it the slow way */
+
+		newcount = cmpxchg(&atomic->counter, counter, newcount);
+		if (newcount == counter)
+			return 0;
+	}
 
-	newcount = cmpxchg(&atomic->counter, counter, newcount);
-
-	if (newcount != counter)
-		goto repeat;
-	return 0;
-
-slow_path:
 	spin_lock(lock);
 	if (atomic_dec_and_test(atomic))
 		return 1;
 	spin_unlock(lock);
 	return 0;
 }
+
+#endif /* ATOMIC_DEC_AND_LOCK */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/lib/memcpy.S linux-2.4.21-pre6/arch/ppc64/lib/memcpy.S
--- linux-2.4.20/arch/ppc64/lib/memcpy.S	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/lib/memcpy.S	2003-03-26 23:49:34.000000000 +0000
@@ -0,0 +1,172 @@
+/*
+ * arch/ppc64/lib/memcpy.S
+ *
+ * Copyright (C) 2002 Paul Mackerras, IBM Corp.
+ *
+ * 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 <asm/processor.h>
+#include <asm/ppc_asm.tmpl>
+
+	.align	7
+_GLOBAL(memcpy)
+	mtcrf	0x01,r5
+	cmpldi	cr1,r5,16
+	neg	r6,r3		# LS 3 bits = # bytes to 8-byte dest bdry
+	andi.	r6,r6,7
+	dcbt	0,r4
+	blt	cr1,.Lshort_copy
+	bne	.Ldst_unaligned
+.Ldst_aligned:
+	andi.	r0,r4,7
+	addi	r3,r3,-16
+	bne	.Lsrc_unaligned
+	srdi	r7,r5,4
+	ld	r9,0(r4)
+	addi	r4,r4,-8
+	mtctr	r7
+	andi.	r5,r5,7
+	bf	cr7*4+0,2f
+	addi	r3,r3,8
+	addi	r4,r4,8
+	mr	r8,r9
+	blt	cr1,3f
+1:	ld	r9,8(r4)
+	std	r8,8(r3)
+2:	ldu	r8,16(r4)
+	stdu	r9,16(r3)
+	bdnz	1b
+3:	std	r8,8(r3)
+	beqlr
+	addi	r3,r3,16
+	ld	r9,8(r4)
+.Ldo_tail:
+	bf	cr7*4+1,1f
+	rotldi	r9,r9,32
+	stw	r9,0(r3)
+	addi	r3,r3,4
+1:	bf	cr7*4+2,2f
+	rotldi	r9,r9,16
+	sth	r9,0(r3)
+	addi	r3,r3,2
+2:	bf	cr7*4+3,3f
+	rotldi	r9,r9,8
+	stb	r9,0(r3)
+3:	blr
+
+.Lsrc_unaligned:
+	srdi	r6,r5,3
+	addi	r5,r5,-16
+	subf	r4,r0,r4
+	srdi	r7,r5,4
+	sldi	r10,r0,3
+	cmpdi	cr6,r6,3
+	andi.	r5,r5,7
+	mtctr	r7
+	subfic	r11,r10,64
+	add	r5,r5,r0
+
+	bt	cr7*4+0,0f
+
+	ld	r9,0(r4)	# 3+2n loads, 2+2n stores
+	ld	r0,8(r4)
+	sld	r6,r9,r10
+	ldu	r9,16(r4)
+	srd	r7,r0,r11
+	sld	r8,r0,r10
+	or	r7,r7,r6
+	blt	cr6,4f
+	ld	r0,8(r4)
+	# s1<< in r8, d0=(s0<<|s1>>) in r7, s3 in r0, s2 in r9, nix in r6 & r12
+	b	2f
+
+0:	ld	r0,0(r4)	# 4+2n loads, 3+2n stores
+	ldu	r9,8(r4)
+	sld	r8,r0,r10
+	addi	r3,r3,-8
+	blt	cr6,5f
+	ld	r0,8(r4)
+	srd	r12,r9,r11
+	sld	r6,r9,r10
+	ldu	r9,16(r4)
+	or	r12,r8,r12
+	srd	r7,r0,r11
+	sld	r8,r0,r10
+	addi	r3,r3,16
+	beq	cr6,3f
+
+	# d0=(s0<<|s1>>) in r12, s1<< in r6, s2>> in r7, s2<< in r8, s3 in r9
+1:	or	r7,r7,r6
+	ld	r0,8(r4)
+	std	r12,8(r3)
+2:	srd	r12,r9,r11
+	sld	r6,r9,r10
+	ldu	r9,16(r4)
+	or	r12,r8,r12
+	stdu	r7,16(r3)
+	srd	r7,r0,r11
+	sld	r8,r0,r10
+	bdnz	1b
+
+3:	std	r12,8(r3)
+	or	r7,r7,r6
+4:	std	r7,16(r3)
+5:	srd	r12,r9,r11
+	or	r12,r8,r12
+	std	r12,24(r3)
+	beqlr
+	cmpwi	cr1,r5,8
+	addi	r3,r3,32
+	sld	r9,r9,r10
+	ble	cr1,.Ldo_tail
+	ld	r0,8(r4)
+	srd	r7,r0,r11
+	or	r9,r7,r9
+	b	.Ldo_tail
+
+.Ldst_unaligned:
+	mtcrf	0x01,r6		# put #bytes to 8B bdry into cr7
+	subf	r5,r6,r5
+	li	r7,0
+	cmpldi	r1,r5,16
+	bf	cr7*4+3,1f
+	lbz	r0,0(r4)
+	stb	r0,0(r3)
+	addi	r7,r7,1
+1:	bf	cr7*4+2,2f
+	lhzx	r0,r7,r4
+	sthx	r0,r7,r3
+	addi	r7,r7,2
+2:	bf	cr7*4+1,3f
+	lwzx	r0,r7,r4
+	stwx	r0,r7,r3
+3:	mtcrf	0x01,r5
+	add	r4,r6,r4
+	add	r3,r6,r3
+	b	.Ldst_aligned
+
+.Lshort_copy:
+	bf	cr7*4+0,1f
+	lwz	r0,0(r4)
+	lwz	r9,4(r4)
+	addi	r4,r4,8
+	stw	r0,0(r3)
+	stw	r9,4(r3)
+	addi	r3,r3,8
+1:	bf	cr7*4+1,2f
+	lwz	r0,0(r4)
+	addi	r4,r4,4
+	stw	r0,0(r3)
+	addi	r3,r3,4
+2:	bf	cr7*4+2,3f
+	lhz	r0,0(r4)
+	addi	r4,r4,2
+	sth	r0,0(r3)
+	addi	r3,r3,2
+3:	bf	cr7*4+3,4f
+	lbz	r0,0(r4)
+	stb	r0,0(r3)
+4:	blr
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/lib/string.S linux-2.4.21-pre6/arch/ppc64/lib/string.S
--- linux-2.4.20/arch/ppc64/lib/string.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/lib/string.S	2003-03-26 23:49:20.000000000 +0000
@@ -12,61 +12,6 @@
 #include <asm/processor.h>
 #include <asm/errno.h>
 
-#define CACHE_LINE_SIZE		128
-#define LG_CACHE_LINE_SIZE	7
-#define MAX_COPY_PREFETCH	1
-
-#define COPY_16_BYTES		\
-	lwz	r7,4(r4);	\
-	lwz	r8,8(r4);	\
-	lwz	r9,12(r4);	\
-	lwzu	r10,16(r4);	\
-	stw	r7,4(r6);	\
-	stw	r8,8(r6);	\
-	stw	r9,12(r6);	\
-	stwu	r10,16(r6)
-
-#define COPY_16_BYTES_WITHEX(n)	\
-8 ## n ## 0:			\
-	lwz	r7,4(r4);	\
-8 ## n ## 1:			\
-	lwz	r8,8(r4);	\
-8 ## n ## 2:			\
-	lwz	r9,12(r4);	\
-8 ## n ## 3:			\
-	lwzu	r10,16(r4);	\
-8 ## n ## 4:			\
-	stw	r7,4(r6);	\
-8 ## n ## 5:			\
-	stw	r8,8(r6);	\
-8 ## n ## 6:			\
-	stw	r9,12(r6);	\
-8 ## n ## 7:			\
-	stwu	r10,16(r6)
-
-#define COPY_16_BYTES_EXCODE(n)			\
-9 ## n ## 0:					\
-	addi	r5,r5,-(16 * n);		\
-	b	104f;				\
-9 ## n ## 1:					\
-	addi	r5,r5,-(16 * n);		\
-	b	105f;				\
-.section __ex_table,"a";			\
-	.align	3;				\
-	.llong	8 ## n ## 0b,9 ## n ## 0b;	\
-	.llong	8 ## n ## 1b,9 ## n ## 0b;	\
-	.llong	8 ## n ## 2b,9 ## n ## 0b;	\
-	.llong	8 ## n ## 3b,9 ## n ## 0b;	\
-	.llong	8 ## n ## 4b,9 ## n ## 1b;	\
-	.llong	8 ## n ## 5b,9 ## n ## 1b;	\
-	.llong	8 ## n ## 6b,9 ## n ## 1b;	\
-	.llong	8 ## n ## 7b,9 ## n ## 1b;	\
-.text
-
-CACHELINE_BYTES = CACHE_LINE_SIZE
-LG_CACHELINE_BYTES = LG_CACHE_LINE_SIZE
-CACHELINE_MASK = (CACHE_LINE_SIZE-1)
-
 _GLOBAL(strcpy)
 	addi	r5,r3,-1
 	addi	r4,r4,-1
@@ -120,54 +65,6 @@
 	subf	r3,r3,r4
 	blr
 
-/*
- * Use dcbz on the complete cache lines in the destination
- * to set them to zero.  This requires that the destination
- * area is cacheable.  -- paulus
- */
-_GLOBAL(cacheable_memzero)
-	mr	r5,r4
-	li	r4,0
-	addi	r6,r3,-4
-	cmplwi	0,r5,4
-	blt	7f
-	stwu	r4,4(r6)
-	beqlr
-	andi.	r0,r6,3
-	add	r5,r0,r5
-	subf	r6,r0,r6
-	clrlwi	r7,r6,32-LG_CACHELINE_BYTES
-	add	r8,r7,r5
-	srwi	r9,r8,LG_CACHELINE_BYTES
-	addic.	r9,r9,-1	/* total number of complete cachelines */
-	ble	2f
-	xori	r0,r7,CACHELINE_MASK & ~3
-	srwi.	r0,r0,2
-	beq	3f
-	mtctr	r0
-4:	stwu	r4,4(r6)
-	bdnz	4b
-3:	mtctr	r9
-	li	r7,4
-10:	dcbz	r7,r6
-	addi	r6,r6,CACHELINE_BYTES
-	bdnz	10b
-	clrlwi	r5,r8,32-LG_CACHELINE_BYTES
-	addi	r5,r5,4
-2:	srwi	r0,r5,2
-	mtctr	r0
-	bdz	6f
-1:	stwu	r4,4(r6)
-	bdnz	1b
-6:	andi.	r5,r5,3
-7:	cmpwi	0,r5,0
-	beqlr
-	mtctr	r5
-	addi	r6,r6,3
-8:	stbu	r4,1(r6)
-	bdnz	8b
-	blr
-
 _GLOBAL(memset)
 	rlwimi	r4,r4,8,16,23
 	rlwimi	r4,r4,16,0,15
@@ -196,48 +93,7 @@
 _GLOBAL(memmove)
 	cmplw	0,r3,r4
 	bgt	.backwards_memcpy
-	/* fall through */
-
-_GLOBAL(memcpy)
-	srwi.	r7,r5,3
-	addi	r6,r3,-4
-	addi	r4,r4,-4
-	beq	2f			/* if less than 8 bytes to do */
-	andi.	r0,r6,3			/* get dest word aligned */
-	mtctr	r7
-	bne	5f
-1:	lwz	r7,4(r4)
-	lwzu	r8,8(r4)
-	stw	r7,4(r6)
-	stwu	r8,8(r6)
-	bdnz	1b
-	andi.	r5,r5,7
-2:	cmplwi	0,r5,4
-	blt	3f
-	lwzu	r0,4(r4)
-	addi	r5,r5,-4
-	stwu	r0,4(r6)
-3:	cmpwi	0,r5,0
-	beqlr
-	mtctr	r5
-	addi	r4,r4,3
-	addi	r6,r6,3
-4:	lbzu	r0,1(r4)
-	stbu	r0,1(r6)
-	bdnz	4b
-	blr
-5:	subfic	r0,r0,4
-	mtctr	r0
-6:	lbz	r7,4(r4)
-	addi	r4,r4,1
-	stb	r7,4(r6)
-	addi	r6,r6,1
-	bdnz	6b
-	subf	r5,r0,r5
-	rlwinm.	r7,r5,32-3,3,31
-	beq	2b
-	mtctr	r7
-	b	1b
+	b	.memcpy
 
 _GLOBAL(backwards_memcpy)
 	rlwinm.	r7,r5,32-3,3,31		/* r0 = r5 >> 3 */
@@ -301,195 +157,6 @@
 2:	li	r3,0
 	blr
 
-_GLOBAL(__copy_tofrom_user)
-	addi	r4,r4,-4
-	addi	r6,r3,-4
-	neg	r0,r3
-	andi.	r0,r0,CACHELINE_MASK	/* # bytes to start of cache line */
-	beq	58f
-
-	cmplw	0,r5,r0			/* is this more than total to do? */
-	blt	63f			/* if not much to do */
-	andi.	r8,r0,3			/* get it word-aligned first */
-	mtctr	r8
-	beq+	61f
-70:	lbz	r9,4(r4)		/* do some bytes */
-71:	stb	r9,4(r6)
-	addi	r4,r4,1
-	addi	r6,r6,1
-	bdnz	70b
-61:	subf	r5,r0,r5
-	srwi.	r0,r0,2
-	mtctr	r0
-	beq	58f
-72:	lwzu	r9,4(r4)		/* do some words */
-73:	stwu	r9,4(r6)
-	bdnz	72b
-
-58:	srwi.	r0,r5,LG_CACHELINE_BYTES /* # complete cachelines */
-	clrlwi	r5,r5,32-LG_CACHELINE_BYTES
-	li	r11,4
-	beq	63f
-
-	/* Here we decide how far ahead to prefetch the source */
-#if MAX_COPY_PREFETCH > 1
-	/* Heuristically, for large transfers we prefetch
-	   MAX_COPY_PREFETCH cachelines ahead.  For small transfers
-	   we prefetch 1 cacheline ahead. */
-	cmpwi	r0,MAX_COPY_PREFETCH
-	li	r7,1
-	li	r3,4
-	ble	111f
-	li	r7,MAX_COPY_PREFETCH
-111:	mtctr	r7
-112:	dcbt	r3,r4
-	addi	r3,r3,CACHELINE_BYTES
-	bdnz	112b
-#else /* MAX_COPY_PREFETCH == 1 */
-	li	r3,CACHELINE_BYTES + 4
-	dcbt	r11,r4
-#endif /* MAX_COPY_PREFETCH */
-
-	mtctr	r0
-	dcbt	r3,r4
-53:
-54:	dcbz	r11,r6
-/* had to move these to keep extable in order */
-	.section __ex_table,"a"
-	.align	3
-	.llong	70b,100f
-	.llong	71b,101f
-	.llong	72b,102f
-	.llong	73b,103f
-	.llong	54b,105f
-	.text
-/* the main body of the cacheline loop */
-	COPY_16_BYTES_WITHEX(0)
-#if CACHE_LINE_SIZE >= 32
-	COPY_16_BYTES_WITHEX(1)
-#if CACHE_LINE_SIZE >= 64
-	COPY_16_BYTES_WITHEX(2)
-	COPY_16_BYTES_WITHEX(3)
-#if CACHE_LINE_SIZE >= 128
-	COPY_16_BYTES_WITHEX(4)
-	COPY_16_BYTES_WITHEX(5)
-	COPY_16_BYTES_WITHEX(6)
-	COPY_16_BYTES_WITHEX(7)
-#endif
-#endif
-#endif
-	bdnz	53b
-
-63:	srwi.	r0,r5,2
-	mtctr	r0
-	beq	64f
-30:	lwzu	r0,4(r4)
-31:	stwu	r0,4(r6)
-	bdnz	30b
-
-64:	andi.	r0,r5,3
-	mtctr	r0
-	beq+	65f
-40:	lbz	r0,4(r4)
-41:	stb	r0,4(r6)
-	addi	r4,r4,1
-	addi	r6,r6,1
-	bdnz	40b
-65:	li	r3,0
-	blr
-
-/* read fault, initial single-byte copy */
-100:	li	r4,0
-	b	90f
-/* write fault, initial single-byte copy */
-101:	li	r4,1
-90:	subf	r5,r8,r5
-	li	r3,0
-	b	99f
-/* read fault, initial word copy */
-102:	li	r4,0
-	b	91f
-/* write fault, initial word copy */
-103:	li	r4,1
-91:	li	r3,2
-	b	99f
-
-/*
- * this stuff handles faults in the cacheline loop and branches to either
- * 104f (if in read part) or 105f (if in write part), after updating r5
- */
-	COPY_16_BYTES_EXCODE(0)
-#if CACHE_LINE_SIZE >= 32
-	COPY_16_BYTES_EXCODE(1)
-#if CACHE_LINE_SIZE >= 64
-	COPY_16_BYTES_EXCODE(2)
-	COPY_16_BYTES_EXCODE(3)
-#if CACHE_LINE_SIZE >= 128
-	COPY_16_BYTES_EXCODE(4)
-	COPY_16_BYTES_EXCODE(5)
-	COPY_16_BYTES_EXCODE(6)
-	COPY_16_BYTES_EXCODE(7)
-#endif
-#endif
-#endif
-
-/* read fault in cacheline loop */
-104:	li	r4,0
-	b	92f
-/* fault on dcbz (effectively a write fault) */
-/* or write fault in cacheline loop */
-105:	li	r4,1
-92:	li	r3,LG_CACHELINE_BYTES
-	b	99f
-/* read fault in final word loop */
-108:	li	r4,0
-	b	93f
-/* write fault in final word loop */
-109:	li	r4,1
-93:	andi.	r5,r5,3
-	li	r3,2
-	b	99f
-/* read fault in final byte loop */
-110:	li	r4,0
-	b	94f
-/* write fault in final byte loop */
-111:	li	r4,1
-94:	li	r5,0
-	li	r3,0
-/*
- * At this stage the number of bytes not copied is
- * r5 + (ctr << r3), and r4 is 0 for read or 1 for write.
- */
-99:	mfctr	r0
-	slw	r3,r0,r3
-	add	r3,r3,r5
-	cmpwi	0,r4,0
-	bne	120f
-/* for read fault, clear out the destination: r3 bytes starting at 4(r6) */
-	srwi.	r0,r3,2
-	li	r9,0
-	mtctr	r0
-	beq	113f
-112:	stwu	r9,4(r6)
-	bdnz	112b
-113:	andi.	r0,r3,3
-	mtctr	r0
-	beq	120f
-114:	stb	r9,4(r6)
-	addi	r6,r6,1
-	bdnz	114b
-120:	blr
-
-	.section __ex_table,"a"
-	.align	3
-	.llong	30b,108b
-	.llong	31b,109b
-	.llong	40b,110b
-	.llong	41b,111b
-	.llong	112b,120b
-	.llong	114b,120b
-	.text
-
 _GLOBAL(__clear_user)
 	addi	r6,r3,-4
 	li	r3,0
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/mm/extable.c linux-2.4.21-pre6/arch/ppc64/mm/extable.c
--- linux-2.4.20/arch/ppc64/mm/extable.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/mm/extable.c	2003-03-26 23:49:35.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * linux/arch/ppc/mm/extable.c
+ * linux/arch/ppc64/mm/extable.c
  *
  * from linux/arch/i386/mm/extable.c
  *
@@ -9,54 +9,95 @@
  *      2 of the License, or (at your option) any later version.
  */
 
+#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[];
-extern const struct exception_table_entry __stop___ex_table[];
+extern struct exception_table_entry __start___ex_table[];
+extern struct exception_table_entry __stop___ex_table[];
+
+/*
+ * The exception table needs to be sorted because we use the macros
+ * which put things into the exception table in a variety of segments
+ * as well as the init segment and the main kernel text segment.
+ */
+static inline void
+sort_ex_table(struct exception_table_entry *start,
+	      struct exception_table_entry *finish)
+{
+	struct exception_table_entry el, *p, *q;
+
+	/* insertion sort */
+	for (p = start + 1; p < finish; ++p) {
+		/* start .. p-1 is sorted */
+		if (p[0].insn < p[-1].insn) {
+			/* move element p down to its right place */
+			el = *p;
+			q = p;
+			do {
+				/* el comes before q[-1], move q[-1] up one */
+				q[0] = q[-1];
+				--q;
+			} while (q > start && el.insn < q[-1].insn);
+			*q = el;
+		}
+	}
+}
+
+void
+sort_exception_table(void)
+{
+	sort_ex_table(__start___ex_table, __stop___ex_table);
+}
 
 static inline unsigned long
 search_one_table(const struct exception_table_entry *first,
 		 const struct exception_table_entry *last,
 		 unsigned long value)
 {
-        while (first <= last) {
+	while (first <= last) {
 		const struct exception_table_entry *mid;
 		long diff;
 
 		mid = (last - first) / 2 + first;
 		diff = mid->insn - value;
-                if (diff == 0)
-                        return mid->fixup;
-                else if (diff < 0)
-                        first = mid+1;
-                else
-                        last = mid-1;
-        }
-        return 0;
+		if (diff == 0)
+			return mid->fixup;
+		else if (diff < 0)
+			first = mid+1;
+		else
+			last = mid-1;
+	}
+	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;
+			break;
 	}
+	spin_unlock_irqrestore(&modlist_lock, flags);
+	return ret;
 #endif
-
-	return 0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/mm/fault.c linux-2.4.21-pre6/arch/ppc64/mm/fault.c
--- linux-2.4.20/arch/ppc64/mm/fault.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/mm/fault.c	2003-03-26 23:49:30.000000000 +0000
@@ -84,17 +84,30 @@
 
 #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
 	if (debugger_fault_handler && (regs->trap == 0x300 ||
-				regs->trap == 0x380)) {
+				       regs->trap == 0x380)) {
 		debugger_fault_handler(regs);
 		return;
 	}
+#endif /* CONFIG_XMON || CONFIG_KGDB */
+
+	/* On an SLB miss we can only check for a valid exception entry */
+	if (regs->trap == 0x380) {
+		bad_page_fault(regs, address);
+		return;
+	}
 
+#if defined(CONFIG_XMON) || defined(CONFIG_KGDB) || defined(CONFIG_KDB)
 	if (error_code & 0x00400000) {
 		/* DABR match */
+#if defined(CONFIG_KDB)
+	    if (kdb(KDB_REASON_BREAK,regs->trap,regs))
+			return;
+#else
 		if (debugger_dabr_match(regs))
 			return;
+#endif
 	}
-#endif /* CONFIG_XMON || CONFIG_KGDB */
+#endif /* CONFIG_XMON || CONFIG_KGDB || CONFIG_KDB */
 
 	if (in_interrupt() || mm == NULL) {
 		bad_page_fault(regs, address);
@@ -136,6 +149,7 @@
 			goto bad_area;
 	}
 
+ survive:
 	/*
 	 * If for any reason at all we couldn't handle the fault,
 	 * make sure we exit gracefully rather than endlessly redo
@@ -189,6 +203,11 @@
  */
 out_of_memory:
 	up_read(&mm->mmap_sem);
+	if (current->pid == 1) {
+		yield();
+		down_read(&mm->mmap_sem);
+		goto survive;
+	}
 	printk("VM: killing process %s\n", current->comm);
 	if (user_mode(regs))
 		do_exit(SIGKILL);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/mm/init.c linux-2.4.21-pre6/arch/ppc64/mm/init.c
--- linux-2.4.20/arch/ppc64/mm/init.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/mm/init.c	2003-03-26 23:49:09.000000000 +0000
@@ -82,11 +82,6 @@
 extern char _stext[], etext[];
 extern struct task_struct *current_set[NR_CPUS];
 
-void mm_init_ppc64(void);
-
-unsigned long *pmac_find_end_of_memory(void);
-extern unsigned long *find_end_of_memory(void);
-
 extern pgd_t ioremap_dir[];
 pgd_t * ioremap_pgd = (pgd_t *)&ioremap_dir;
 
@@ -171,12 +166,10 @@
 #ifdef CONFIG_PPC_ISERIES
 	return (void*)addr;
 #else
-	if(mem_init_done && (addr >> 60UL)) {
-		if (IS_EEH_TOKEN_DISABLED(addr))
-			return IO_TOKEN_TO_ADDR(addr);
-		return (void*)addr; /* already mapped address or EEH token. */
-	}
-	return __ioremap(addr, size, _PAGE_NO_CACHE);
+	void *ret = __ioremap(addr, size, _PAGE_NO_CACHE);
+	if(mem_init_done)
+		return eeh_ioremap(addr, ret);	/* may remap the addr */
+	return ret;
 #endif
 }
 
@@ -272,6 +265,14 @@
 	}
 }
 
+#ifndef CONFIG_PPC_ISERIES
+int
+io_remap_page_range(unsigned long from, unsigned long to, unsigned long size, pgprot_t prot)
+{
+	return remap_page_range(from, eeh_token_to_phys(to), size, prot);
+}
+#endif
+
 void
 local_flush_tlb_all(void)
 {
@@ -284,6 +285,8 @@
 void
 local_flush_tlb_mm(struct mm_struct *mm)
 {
+	spin_lock(&mm->page_table_lock);
+
 	if ( mm->map_count ) {
 		struct vm_area_struct *mp;
 		for ( mp = mm->mmap; mp != NULL; mp = mp->vm_next )
@@ -294,6 +297,8 @@
 		 * when an address space (represented by an mm_struct)
 		 * is being destroyed. */
 		local_flush_tlb_range( mm, USER_START, USER_END );
+
+	spin_unlock(&mm->page_table_lock);
 }
 
 /*
@@ -446,12 +451,12 @@
 	 * The range of contexts [FIRST_USER_CONTEXT, NUM_USER_CONTEXT)
 	 * are stored on a stack/queue for easy allocation and deallocation.
 	 */
-        mmu_context_queue.lock = SPIN_LOCK_UNLOCKED;
-        mmu_context_queue.head = 0;
-        mmu_context_queue.tail = NUM_USER_CONTEXT-1;
-        mmu_context_queue.size = NUM_USER_CONTEXT;
+	mmu_context_queue.lock = SPIN_LOCK_UNLOCKED;
+	mmu_context_queue.head = 0;
+	mmu_context_queue.tail = NUM_USER_CONTEXT-1;
+	mmu_context_queue.size = NUM_USER_CONTEXT;
 	for(index=0; index < NUM_USER_CONTEXT ;index++) {
-                mmu_context_queue.elements[index] = index+FIRST_USER_CONTEXT;
+		mmu_context_queue.elements[index] = index+FIRST_USER_CONTEXT;
 	}
 
 	/* Setup guard pages for the Paca's */
@@ -491,7 +496,7 @@
 
 	PPCDBG(PPCDBG_MMINIT, "\tstart               = 0x%lx\n", start);
 	PPCDBG(PPCDBG_MMINIT, "\tbootmap_pages       = 0x%lx\n", bootmap_pages);
-	PPCDBG(PPCDBG_MMINIT, "\tphysicalMemorySize  = 0x%lx\n", naca->physicalMemorySize);
+	PPCDBG(PPCDBG_MMINIT, "\tphysicalMemorySize  = 0x%lx\n", systemcfg->physicalMemorySize);
 
 	boot_mapsize = init_bootmem(start >> PAGE_SHIFT, total_pages);
 	PPCDBG(PPCDBG_MMINIT, "\tboot_mapsize        = 0x%lx\n", boot_mapsize);
@@ -585,7 +590,7 @@
 			datapages++;
 	}
 
-        printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%08lx,%08lx]\n",
+	printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%08lx,%08lx]\n",
 	       (unsigned long)nr_free_pages()<< (PAGE_SHIFT-10),
 	       codepages<< (PAGE_SHIFT-10), datapages<< (PAGE_SHIFT-10),
 	       initpages<< (PAGE_SHIFT-10),
@@ -622,6 +627,7 @@
 void clear_user_page(void *page, unsigned long vaddr)
 {
 	clear_page(page);
+	__flush_dcache_icache(page);
 }
 
 void copy_user_page(void *vto, void *vfrom, unsigned long vaddr)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/vmlinux.lds linux-2.4.21-pre6/arch/ppc64/vmlinux.lds
--- linux-2.4.20/arch/ppc64/vmlinux.lds	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/vmlinux.lds	2003-03-26 23:48:59.000000000 +0000
@@ -1,4 +1,4 @@
-OUTPUT_ARCH(powerpc)
+OUTPUT_ARCH(powerpc:common64)
 SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib);
 /* Do we need any of these for elf?
    __DYNAMIC = 0;    */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/xmon/start.c linux-2.4.21-pre6/arch/ppc64/xmon/start.c
--- linux-2.4.20/arch/ppc64/xmon/start.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/xmon/start.c	2003-03-26 23:48:59.000000000 +0000
@@ -59,9 +59,9 @@
 }
 static struct sysrq_key_op sysrq_xmon_op = 
 {
-	handler:	sysrq_handle_xmon,
-	help_msg:	"xmon",
-	action_msg:	"Entering xmon\n",
+	.handler =	sysrq_handle_xmon,
+	.help_msg =	"xmon",
+	.action_msg =	"Entering xmon\n",
 };
 
 void
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/ppc64/xmon/xmon.c linux-2.4.21-pre6/arch/ppc64/xmon/xmon.c
--- linux-2.4.20/arch/ppc64/xmon/xmon.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/ppc64/xmon/xmon.c	2003-03-26 23:49:20.000000000 +0000
@@ -14,6 +14,7 @@
 #include <linux/smp.h>
 #include <linux/mm.h>
 #include <linux/reboot.h>
+#include <linux/delay.h>
 #include <asm/ptrace.h>
 #include <asm/string.h>
 #include <asm/prom.h>
@@ -48,11 +49,6 @@
 #define setjmp xmon_setjmp
 #define longjmp xmon_longjmp
 
-#define memlist_entry list_entry
-#define memlist_next(x) ((x)->next)
-#define memlist_prev(x) ((x)->prev)
-
-
 /* Max number of stack frames we are willing to produce on a backtrace. */
 #define MAXFRAMECOUNT 50
 
@@ -119,15 +115,12 @@
 static void cpu_cmd(void);
 #endif /* CONFIG_SMP */
 static void csum(void);
+static void bootcmds(void);
 static void mem_translate(void);
 static void mem_check(void);
 static void mem_find_real(void);
 static void mem_find_vsid(void);
-static void mem_check_pagetable_vsids (void);
 
-static void mem_map_check_slab(void);
-static void mem_map_lock_pages(void);
-static void mem_check_dup_rpn (void);
 static void debug_trace(void);
 
 extern int print_insn_big_powerpc(FILE *, unsigned long, unsigned long);
@@ -144,6 +137,14 @@
 
 #define GETWORD(v)	(((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
 
+#define isxdigit(c)	(('0' <= (c) && (c) <= '9') \
+			 || ('a' <= (c) && (c) <= 'f') \
+			 || ('A' <= (c) && (c) <= 'F'))
+#define isalnum(c)	(('0' <= (c) && (c) <= '9') \
+			 || ('a' <= (c) && (c) <= 'z') \
+			 || ('A' <= (c) && (c) <= 'Z'))
+#define isspace(c)	(c == ' ' || c == '\t' || c == 10 || c == 13 || c == 0)
+
 static char *help_string = "\
 Commands:\n\
   b	show breakpoints\n\
@@ -173,14 +174,14 @@
   t	print backtrace\n\
   T	Enable/Disable PPCDBG flags\n\
   x	exit monitor\n\
-  z	reboot\n\
-  Z	halt\n\
 ";
 
 static int xmon_trace[NR_CPUS];
 #define SSTEP	1		/* stepping because of 's' command */
 #define BRSTEP	2		/* stepping over breakpoint */
 
+static struct pt_regs *xmon_regs[NR_CPUS];
+
 /*
  * Stuff for reading and writing memory safely
  */
@@ -292,7 +293,6 @@
 			std	29,232(%0)\n\
 			std	30,240(%0)\n\
 			std	31,248(%0)" : : "b" (&regs));
-		printf("xmon called\n");
 		/* Fetch the link reg for this stack frame.
 		 NOTE: the prev printf fills in the lr. */
 		regs.nip = regs.link = ((unsigned long *)(regs.gpr[1]))[2];
@@ -306,6 +306,7 @@
 
 	msr = get_msr();
 	set_msrd(msr & ~MSR_EE);	/* disable interrupts */
+	xmon_regs[smp_processor_id()] = excp;
 	excprint(excp);
 #ifdef CONFIG_SMP
 	if (test_and_set_bit(smp_processor_id(), &cpus_in_xmon))
@@ -325,14 +326,15 @@
 	cmd = cmds(excp);
 	if (cmd == 's') {
 		xmon_trace[smp_processor_id()] = SSTEP;
-		excp->msr |= 0x400;
+		excp->msr |= MSR_SE;
 	} else if (at_breakpoint(excp->nip)) {
 		xmon_trace[smp_processor_id()] = BRSTEP;
-		excp->msr |= 0x400;
+		excp->msr |= MSR_SE;
 	} else {
 		xmon_trace[smp_processor_id()] = 0;
 		insert_bpts();
 	}
+	xmon_regs[smp_processor_id()] = 0;
 #ifdef CONFIG_SMP
 	clear_bit(0, &got_xmon);
 	clear_bit(smp_processor_id(), &cpus_in_xmon);
@@ -340,85 +342,6 @@
 	set_msrd(msr);		/* restore interrupt enable */
 }
 
-/* Code can call this to get a backtrace and continue. */
-void
-xmon_backtrace(const char *fmt, ...)
-{
-	va_list ap;
-	struct pt_regs regs;
-
-
-	/* Ok, grab regs as they are now.
-	 This won't do a particularily good job because the
-	 prologue has already been executed.
-	 ToDo: We could reach back into the callers save
-	 area to do a better job of representing the
-	 caller's state.
-	 */
-	asm volatile ("std	0,0(%0)\n\
-	    std	1,8(%0)\n\
-	    std	2,16(%0)\n\
-	    std	3,24(%0)\n\
-	    std	4,32(%0)\n\
-	    std	5,40(%0)\n\
-	    std	6,48(%0)\n\
-	    std	7,56(%0)\n\
-	    std	8,64(%0)\n\
-	    std	9,72(%0)\n\
-	    std	10,80(%0)\n\
-	    std	11,88(%0)\n\
-	    std	12,96(%0)\n\
-	    std	13,104(%0)\n\
-	    std	14,112(%0)\n\
-	    std	15,120(%0)\n\
-	    std	16,128(%0)\n\
-	    std	17,136(%0)\n\
-	    std	18,144(%0)\n\
-	    std	19,152(%0)\n\
-	    std	20,160(%0)\n\
-	    std	21,168(%0)\n\
-	    std	22,176(%0)\n\
-	    std	23,184(%0)\n\
-	    std	24,192(%0)\n\
-	    std	25,200(%0)\n\
-	    std	26,208(%0)\n\
-	    std	27,216(%0)\n\
-	    std	28,224(%0)\n\
-	    std	29,232(%0)\n\
-	    std	30,240(%0)\n\
-	    std	31,248(%0)" : : "b" (&regs));
-	/* Fetch the link reg for this stack frame.
-	 NOTE: the prev printf fills in the lr. */
-	regs.nip = regs.link = ((unsigned long *)(regs.gpr[1]))[2];
-	regs.msr = get_msr();
-	regs.ctr = get_ctr();
-	regs.xer = get_xer();
-	regs.ccr = get_cr();
-	regs.trap = 0;
-
-	va_start(ap, fmt);
-	xmon_vfprintf(stdout, fmt, ap);
-	xmon_putc('\n', stdout);
-	va_end(ap);
-	take_input("\n");
-	backtrace(&regs);
-}
-
-/* Call this to poll for ^C during busy operations.
- * Returns true if the user has hit ^C.
- */
-int
-xmon_interrupted(void)
-{
-	int ret = xmon_read_poll();
-	if (ret == 3) {
-		printf("\n^C interrupted.\n");
-		return 1;
-	}
-	return 0;
-}
-
-
 void
 xmon_irq(int irq, void *d, struct pt_regs *regs)
 {
@@ -443,7 +366,7 @@
 		remove_bpts();
 		excprint(regs);
 		xmon_trace[smp_processor_id()] = BRSTEP;
-		regs->msr |= 0x400;
+		regs->msr |= MSR_SE;
 	} else {
 		printf("Stopped at breakpoint %x (%lx %s)\n", (bp - bpts)+1, bp->address, bp->funcname);
 		xmon(regs);
@@ -473,7 +396,7 @@
 		remove_bpts();
 		excprint(regs);
 		xmon_trace[smp_processor_id()] = BRSTEP;
-		regs->msr |= 0x400;
+		regs->msr |= MSR_SE;
 	} else {
 		dabr.instr = regs->nip;
 		xmon(regs);
@@ -489,7 +412,7 @@
 		remove_bpts();
 		excprint(regs);
 		xmon_trace[smp_processor_id()] = BRSTEP;
-		regs->msr |= 0x400;
+		regs->msr |= MSR_SE;
 	} else {
 		xmon(regs);
 	}
@@ -519,7 +442,7 @@
 	int i;
 	struct bpt *bp;
 
-	if (naca->platform != PLATFORM_PSERIES)
+	if (systemcfg->platform != PLATFORM_PSERIES)
 		return;
 	bp = bpts;
 	for (i = 0; i < NBPTS; ++i, ++bp) {
@@ -550,7 +473,7 @@
 	struct bpt *bp;
 	unsigned instr;
 
-	if (naca->platform != PLATFORM_PSERIES)
+	if (systemcfg->platform != PLATFORM_PSERIES)
 		return;
 	if (!__is_processor(PV_POWER4) && !__is_processor(PV_POWER4p)) {
 		set_dabr(0);
@@ -597,14 +520,6 @@
 			cmd = inchar();
 		}
 		switch (cmd) {
-		case 'z':
-			printf("Rebooting machine now...");
-			machine_restart(NULL);
-			break;
-		case 'Z':
-			printf("Halting machine now...");
-			machine_halt();
-			break;
 		case 'm':
 			cmd = inchar();
 			switch (cmd) {
@@ -625,27 +540,15 @@
 			case 'c':
 				mem_check();
 				break;
-			case 'j':
-				mem_map_check_slab();
-				break;
 			case 'f':
 				mem_find_real();
 				break;
 			case 'e':
 				mem_find_vsid();
 				break;
-			case 'r':
-				mem_check_dup_rpn();
-				break;           
 			case 'i':
 				show_mem();
 				break;
-			case 'o':
-				mem_check_pagetable_vsids ();
-				break;
-			case 'q':
-				mem_map_lock_pages() ;
-				break;
 			default:
 				termch = cmd;
 				memex();
@@ -700,6 +603,8 @@
 			cpu_cmd();
 			break;
 #endif /* CONFIG_SMP */
+		case 'z':
+			bootcmds();
 		case 'T':
 			debug_trace();
 			break;
@@ -718,6 +623,19 @@
 	}
 }
 
+static void bootcmds(void)
+{
+	int cmd;
+
+	cmd = inchar();
+	if (cmd == 'r')
+		ppc_md.restart(NULL);
+	else if (cmd == 'h')
+		ppc_md.halt();
+	else if (cmd == 'p')
+		ppc_md.power_off();
+}
+
 #ifdef CONFIG_SMP
 static void cpu_cmd(void)
 {
@@ -739,7 +657,7 @@
 		printf("cpus stopped:");
 		for (cpu = 0; cpu < NR_CPUS; ++cpu) {
 			if (test_bit(cpu, &cpus_in_xmon)) {
-				printf(" %d", cpu);
+				printf(" %x", cpu);
 				if (cpu == smp_processor_id())
 					printf("*", cpu);
 			}
@@ -870,6 +788,7 @@
 		break;
 	case 'i':	/* bi - hardware instr breakpoint */
 		if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p)) {
+			printf("Not implemented on POWER4\n");
 			break;
 		}
 		iabr.address = 0;
@@ -972,7 +891,9 @@
 	case 0x100:	ret = "(System Reset)"; break; 
 	case 0x200:	ret = "(Machine Check)"; break; 
 	case 0x300:	ret = "(Data Access)"; break; 
+	case 0x380:	ret = "(Data SLB Access)"; break;
 	case 0x400:	ret = "(Instruction Access)"; break; 
+	case 0x480:	ret = "(Instruction SLB Access)"; break;
 	case 0x500:	ret = "(Hardware Interrupt)"; break; 
 	case 0x600:	ret = "(Alignment)"; break; 
 	case 0x700:	ret = "(Program Check)"; break; 
@@ -1120,7 +1041,7 @@
 	printf("    sp: %lx\n", fp->gpr[1]);
 	printf("   msr: %lx\n", fp->msr);
 
-	if (fp->trap == 0x300 || fp->trap == 0x600) {
+	if (fp->trap == 0x300 || fp->trap == 0x380 || fp->trap == 0x600) {
 		printf("   dar: %lx\n", fp->dar);
 		printf(" dsisr: %lx\n", fp->dsisr);
 	}
@@ -1296,34 +1217,6 @@
 	scannl();
 }
 
-#if 0
-static void
-openforth()
-{
-	int c;
-	char *p;
-	char cmd[1024];
-	int args[5];
-	extern int (*prom_entry)(int *);
-
-	p = cmd;
-	c = skipbl();
-	while (c != '\n') {
-		*p++ = c;
-		c = inchar();
-	}
-	*p = 0;
-	args[0] = (int) "interpret";
-	args[1] = 1;
-	args[2] = 1;
-	args[3] = (int) cmd;
-	(*prom_entry)(args);
-	printf("\n");
-	if (args[4] != 0)
-		printf("error %x\n", args[4]);
-}
-#endif
-
 #ifndef CONFIG_PPC64BRIDGE
 static void
 dump_hash_table_seg(unsigned seg, unsigned start, unsigned end)
@@ -1538,7 +1431,18 @@
 static void
 handle_fault(struct pt_regs *regs)
 {
-	fault_type = regs->trap == 0x200? 0: regs->trap == 0x300? 1: 2;
+	switch (regs->trap) {
+	case 0x200:
+		fault_type = 0;
+		break;
+	case 0x300:
+	case 0x380:
+		fault_type = 1;
+		break;
+	default:
+		fault_type = 2;
+	}
+
 	longjmp(bus_error_jmp, 1);
 }
 
@@ -2011,6 +1915,16 @@
 	return c;
 }
 
+#define N_PTREGS	44
+static char *regnames[N_PTREGS] = {
+	"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+	"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+	"r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+	"r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
+	"pc", "msr", "or3", "ctr", "lr", "xer", "ccr", "mq",
+	"trap", "dar", "dsisr", "res"
+};
+
 int
 scanhex(vp)
 unsigned long *vp;
@@ -2019,6 +1933,36 @@
 	unsigned long v;
 
 	c = skipbl();
+	if (c == '%') {
+		/* parse register name */
+		char regname[8];
+		int i;
+
+		for (i = 0; i < sizeof(regname) - 1; ++i) {
+			c = inchar();
+			if (!isalnum(c)) {
+				termch = c;
+				break;
+			}
+			regname[i] = c;
+		}
+		regname[i] = 0;
+		for (i = 0; i < N_PTREGS; ++i) {
+			if (strcmp(regnames[i], regname) == 0) {
+				unsigned long *rp = (unsigned long *)
+					xmon_regs[smp_processor_id()];
+				if (rp == NULL) {
+					printf("regs not available\n");
+					return 0;
+				}
+				*vp = rp[i];
+				return 1;
+			}
+		}
+		printf("invalid register name '%%%s'\n", regname);
+		return 0;
+	}
+
 	d = hexdigit(c);
 	if( d == EOF ){
 		termch = c;
@@ -2440,249 +2384,6 @@
 	printf("\nDone -------------------\n");
 }
 
-void mem_map_check_slab()
-{
-	int i, slab_count;
-
-	i = max_mapnr;
-	slab_count = 0;
-	
-	while (i-- > 0)  {
-		if (PageSlab(mem_map+i)){
-			printf(" slab entry - mem_map entry =%p  \n", mem_map+i);
-			slab_count ++;
-		}
-	}
-
-	printf(" count of pages for slab = %d \n", slab_count);
-}
-
-void mem_map_lock_pages()
-{
-	int i, lock_count;
-
-	i = max_mapnr;
-	lock_count = 0;
-	
-	while (i-- > 0)  {
-		if (PageLocked(mem_map+i)){
-			printf(" locked entry - mem_map entry =%p  \n", mem_map+i);
-			lock_count ++;
-		}
-	}
-
-	printf(" count of locked pages = %d \n", lock_count); 
-}
-
-void mem_check_dup_rpn ()
-{
-	unsigned long htab_size_bytes;
-	unsigned long htab_end;
-	unsigned long last_rpn;
-	HPTE *hpte1, *hpte2;
-	int dup_count;
-	struct task_struct *p;
-	unsigned long kernel_vsid_c0,kernel_vsid_c1,kernel_vsid_c2,kernel_vsid_c3;
-	unsigned long kernel_vsid_c4,kernel_vsid_c5,kernel_vsid_d,kernel_vsid_e;
-	unsigned long kernel_vsid_f;
-	unsigned long vsid0,vsid1,vsidB,vsid2;
-
-	htab_size_bytes = htab_data.htab_num_ptegs * 128; // 128B / PTEG
-	htab_end = (unsigned long)htab_data.htab + htab_size_bytes;
-	// last_rpn = (naca->physicalMemorySize-1) >> PAGE_SHIFT;
-	last_rpn = 0xfffff;
-
-	printf("\nHardware Page Table Check\n-------------------\n");
-	printf("htab base      : %.16lx\n", htab_data.htab);
-	printf("htab size      : %.16lx\n", htab_size_bytes);
-
-
-	for(hpte1 = htab_data.htab; hpte1 < (HPTE *)htab_end; hpte1++) {
-		if ( hpte1->dw0.dw0.v != 0 ) {
-			if ( hpte1->dw1.dw1.rpn <= last_rpn ) {
-				dup_count = 0;
-				for(hpte2 = hpte1+1; hpte2 < (HPTE *)htab_end; hpte2++) {
-					if ( hpte2->dw0.dw0.v != 0 ) {
-						if(hpte1->dw1.dw1.rpn == hpte2->dw1.dw1.rpn) {
-							dup_count++;
-						}
-					}
-				}
-				if(dup_count > 5) {
-					printf(" Duplicate rpn: %.13lx \n", (hpte1->dw1.dw1.rpn));
-					printf("    mem map array entry %p count = %d \n",
-					       (mem_map+(hpte1->dw1.dw1.rpn)), (mem_map+(hpte1->dw1.dw1.rpn))->count);
-					for(hpte2 = hpte1+1; hpte2 < (HPTE *)htab_end; hpte2++) {
-						if ( hpte2->dw0.dw0.v != 0 ) {
-							if(hpte1->dw1.dw1.rpn == hpte2->dw1.dw1.rpn) {
-								printf("   hpte2: %16.16lx  *hpte2: %16.16lx %16.16lx\n",
-								       hpte2, hpte2->dw0.dword0, hpte2->dw1.dword1);
-							}
-						}
-					}
-				}
-			} else {
-				printf(" Bogus rpn: %.13lx \n", (hpte1->dw1.dw1.rpn));
-				printf("   hpte: %16.16lx  *hpte: %16.16lx %16.16lx\n",
-				       hpte1, hpte1->dw0.dword0, hpte1->dw1.dword1);
-			}
-		}
-		if (xmon_interrupted())
-			return;
-	}                                                                     
-
-
-
-	// print the kernel vsids
-	kernel_vsid_c0 =  get_kernel_vsid(0xC000000000000000);
-	kernel_vsid_c1 =  get_kernel_vsid(0xC000000010000000);
-	kernel_vsid_c2 =  get_kernel_vsid(0xC000000020000000);
-	kernel_vsid_c3 =  get_kernel_vsid(0xC000000030000000);
-	kernel_vsid_c4 =  get_kernel_vsid(0xC000000040000000);
-	kernel_vsid_c5 =  get_kernel_vsid(0xC000000050000000);
-	kernel_vsid_d  =  get_kernel_vsid(0xD000000000000000);
-	kernel_vsid_e  =  get_kernel_vsid(0xE000000000000000);
-	kernel_vsid_f  =  get_kernel_vsid(0xF000000000000000);
-
-	printf(" kernel vsid -  seg c0  = %lx\n",  kernel_vsid_c0 );
-	printf(" kernel vsid -  seg c1  = %lx\n",  kernel_vsid_c1 );
-	printf(" kernel vsid -  seg c2  = %lx\n",  kernel_vsid_c2 );
-	printf(" kernel vsid -  seg c3  = %lx\n",  kernel_vsid_c3 );
-	printf(" kernel vsid -  seg c4  = %lx\n",  kernel_vsid_c4 );
-	printf(" kernel vsid -  seg c5  = %lx\n",  kernel_vsid_c5 );
-	printf(" kernel vsid -  seg d   = %lx\n",  kernel_vsid_d );
-	printf(" kernel vsid -  seg e   = %lx\n",  kernel_vsid_e );
-	printf(" kernel vsid -  seg f   = %lx\n",  kernel_vsid_f );
-
-
-  // print a list of valid vsids for the tasks
-	read_lock(&tasklist_lock);
-	for_each_task(p)
-		if(p->mm) {
-			struct mm_struct *mm = p->mm; 
-			printf(" task = %p  mm =  %lx  pgd   %lx\n", 
-			       p, mm, mm->pgd);
-			vsid0 = get_vsid( mm->context, 0 );
-			vsid1 = get_vsid( mm->context, 0x10000000 );
-			vsid2 = get_vsid( mm->context, 0x20000000 );
-			vsidB = get_vsid( mm->context, 0xB0000000 );
-			printf("            context = %lx  vsid seg 0  = %lx\n",  mm->context, vsid0 );
-			printf("                           vsid seg 1  = %lx\n",  vsid1 );
-			printf("                           vsid seg 2  = %lx\n",  vsid2 );
-			printf("                           vsid seg 2  = %lx\n",  vsidB );
-	  
-			printf("\n");
-		};
-	read_unlock(&tasklist_lock);
-
-	printf("\nDone -------------------\n");
-}
-
-
-
-void mem_check_pagetable_vsids ()
-{
-	unsigned long htab_size_bytes;
-	unsigned long htab_end;
-	unsigned long last_rpn;
-	struct task_struct *p;
-	unsigned long valid_table_count,invalid_table_count,bogus_rpn_count;
-	int found;
-	unsigned long user_address_table_count,kernel_page_table_count;
-	unsigned long pt_vsid;
-	HPTE *hpte1;
-
-
-	htab_size_bytes = htab_data.htab_num_ptegs * 128; // 128B / PTEG
-	htab_end = (unsigned long)htab_data.htab + htab_size_bytes;
-	// last_rpn = (naca->physicalMemorySize-1) >> PAGE_SHIFT;
-	last_rpn = 0xfffff;
-
-	printf("\nHardware Page Table Check\n-------------------\n");
-	printf("htab base      : %.16lx\n", htab_data.htab);
-	printf("htab size      : %.16lx\n", htab_size_bytes);
-
-	valid_table_count = 0;
-	invalid_table_count = 0;
-	bogus_rpn_count = 0;
-	user_address_table_count = 0;
-	kernel_page_table_count = 0;
-	for(hpte1 = htab_data.htab; hpte1 < (HPTE *)htab_end; hpte1++) {
-		if ( hpte1->dw0.dw0.v != 0 ) {
-			valid_table_count++;
-			if ( hpte1->dw1.dw1.rpn <= last_rpn ) {
-				pt_vsid =  (hpte1->dw0.dw0.avpn) >> 5;
-				if ((pt_vsid == get_kernel_vsid(0xC000000000000000)) |
-				    (pt_vsid == get_kernel_vsid(0xC000000010000000)) |
-				    (pt_vsid == get_kernel_vsid(0xC000000020000000)) |
-				    (pt_vsid == get_kernel_vsid(0xC000000030000000)) |
-				    (pt_vsid == get_kernel_vsid(0xC000000040000000)) |
-				    (pt_vsid == get_kernel_vsid(0xC000000050000000)) |
-				    (pt_vsid == get_kernel_vsid(0xD000000000000000)) |
-				    (pt_vsid == get_kernel_vsid(0xE000000000000000)) |
-				    (pt_vsid == get_kernel_vsid(0xF000000000000000)) ) {
-					kernel_page_table_count ++;
-				} else {
-					read_lock(&tasklist_lock);
-					found = 0;
-					for_each_task(p) {
-						if(p->mm && (found == 0)) {
-							struct mm_struct *mm = p->mm; 
-	     
-							if ((pt_vsid == get_vsid( mm->context, 0 )) |
-							    (pt_vsid == get_vsid( mm->context, 0x10000000 )) |
-							    (pt_vsid == get_vsid( mm->context, 0x20000000 )) |
-							    (pt_vsid == get_vsid( mm->context, 0x30000000 )) |
-							    (pt_vsid == get_vsid( mm->context, 0x40000000 )) |
-							    (pt_vsid == get_vsid( mm->context, 0x50000000 )) |
-							    (pt_vsid == get_vsid( mm->context, 0x60000000 )) |
-							    (pt_vsid == get_vsid( mm->context, 0x70000000 )) |
-							    (pt_vsid == get_vsid( mm->context, 0x80000000 )) |
-							    (pt_vsid == get_vsid( mm->context, 0x90000000 )) |
-							    (pt_vsid == get_vsid( mm->context, 0xA0000000 )) |
-							    (pt_vsid == get_vsid( mm->context, 0xB0000000 ))) {
-								user_address_table_count ++;
-								found = 1;
-							}
-						}
-					}
-					read_unlock(&tasklist_lock);
-					if (found == 0)
-					{
-						printf(" vsid not found vsid = %lx, hpte = %p  \n", 
-						       pt_vsid,hpte1);
-						printf("    rpn in entry = %lx \n", hpte1->dw1.dw1.rpn);
-						printf("    mem map address = %lx  \n", mem_map + (hpte1->dw1.dw1.rpn));
-           
-					} else //  found
-					{
-					}
-
-				}  // good rpn
-       
-			} else {
-				bogus_rpn_count ++;
-			}
-		} else {
-			invalid_table_count++;
-		}
-	}                                                                     
-
-
-	printf(" page table valid counts - valid entries = %lx  invalid entries =  %lx \n",
-	       valid_table_count, invalid_table_count);
-
-	printf("  bogus rpn entries ( probably io) = %lx \n", bogus_rpn_count);
-
- 
-  
-	printf(" page table counts - kernel entries = %lx  user entries =  %lx \n",
-	       kernel_page_table_count, user_address_table_count); 
-
-	printf("\nDone -------------------\n");
-
-}
-
 static void debug_trace(void) {
         unsigned long val, cmd, on;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/s390/kernel/debug.c linux-2.4.21-pre6/arch/s390/kernel/debug.c
--- linux-2.4.20/arch/s390/kernel/debug.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/s390/kernel/debug.c	2003-03-26 23:49:07.000000000 +0000
@@ -459,9 +459,9 @@
 		size = MIN((len - count), (size - entry_offset));
 
 		if(size){
-			if ((rc = copy_to_user(user_buf + count, 
-					p_info->temp_buf + entry_offset, size)))
-			return rc;
+			if (copy_to_user(user_buf + count, 
+					p_info->temp_buf + entry_offset, size))
+				return -EFAULT;
 		}
 		count += size;
 		entry_offset = 0;
@@ -744,8 +744,10 @@
                         id->name, new_level, 0, DEBUG_MAX_LEVEL);
         } else {
                 id->level = new_level;
+#ifdef DEBUG
                 printk(KERN_INFO 
 			"debug: %s: new level %i\n",id->name,id->level);
+#endif
         }
 	spin_unlock_irqrestore(&id->lock,flags);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/s390/kernel/entry.S linux-2.4.21-pre6/arch/s390/kernel/entry.S
--- linux-2.4.20/arch/s390/kernel/entry.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/s390/kernel/entry.S	2003-03-26 23:49:09.000000000 +0000
@@ -556,7 +556,7 @@
         .long  sys_madvise
 	.long  sys_getdents64		 /* 220 */
         .long  sys_fcntl64 
-	.long  sys_ni_syscall
+	.long  sys_readahead
 	.long  sys_ni_syscall
 	.long  sys_ni_syscall		 /* 224 - reserved for setxattr  */
 	.long  sys_ni_syscall            /* 225 - reserved for lsetxattr */
@@ -599,13 +599,14 @@
         tm      __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
         bnz     BASED(pgm_per)           # got per exception -> special case
 	SAVE_ALL __LC_PGM_OLD_PSW,1
+        l       %r3,__LC_PGM_ILC         # load program interruption code
+	la	%r8,0x7f
         l       %r7,BASED(.Ljump_table)
-        lh      %r8,__LC_PGM_INT_CODE
+	nr	%r8,%r3
         sll     %r8,2
 	GET_CURRENT
         l       %r7,0(%r8,%r7)		 # load address of handler routine
         la      %r2,SP_PTREGS(%r15)	 # address of register-save area
-        l       %r3,__LC_PGM_ILC         # load program interruption code
 	la      %r14,BASED(sysc_return)
 	br      %r7			 # branch to interrupt-handler
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/s390/kernel/head.S linux-2.4.21-pre6/arch/s390/kernel/head.S
--- linux-2.4.20/arch/s390/kernel/head.S	2001-11-09 21:58:02.000000000 +0000
+++ linux-2.4.21-pre6/arch/s390/kernel/head.S	2003-03-26 23:49:19.000000000 +0000
@@ -466,6 +466,18 @@
         mvc   __LC_IPLDEV(4),IPL_DEVICE-PARMAREA(%r12)
 	
 #
+# clear bss memory
+#
+        l     %r2,.Lbss_bgn-.LPG1(%r13) # start of bss
+        l     %r3,.Lbss_end-.LPG1(%r13) # end of bss
+        sr    %r3,%r2                   # length of bss
+        sr    %r4,%r4                   #
+        sr    %r5,%r5                   # set src,length and pad to zero
+        sr    %r0,%r0                   #
+        mvcle %r2,%r4,0                 # clear mem
+        jo    .-4                       # branch back, if not finish
+
+#
 # find memory chunks.
 #
 	mvc   __LC_PGM_NEW_PSW(8),.Lpcmem-.LPG1(%r13)
@@ -513,15 +525,29 @@
 #
         stidp  __LC_CPUID               # store cpuid
 	tm     __LC_CPUID,0xff          # running under VM ?
-	bno    .Lnovm-.LPG1(%r13)
+	bno    .Lchkpfix-.LPG1(%r13)
         oi     3(%r12),1                # set VM flag
-.Lnovm:
+#
+# we are running under VM, find out if we have PFIX
+#
+        mvc    __LC_PGM_NEW_PSW(8),.Lpcpfix-.LPG1(%r13)
+	lhi    %r0,0x4000
+	slr    %r2,%r2
+	.long  0x83200098		# diag 2,0,x'0098' - lock page
+	lhi    %r2,4
+	.long  0x83200098		# diag 2,0,x'0098' - unlock page
+	oi     3(%r12),128              # set PFIX flag
+.Lchkpfix:
         lh     %r0,__LC_CPUID+4         # get cpu version
         chi    %r0,0x7490               # running on a P/390 ?
         bne    .Lnop390-.LPG1(%r13)
         oi     3(%r12),4                # set P/390 flag
 .Lnop390:
-
+	chi    %r0,0x2084		# new stidp format?
+	bne    .Loldfmt-.LPG1(%r13)
+	oi     3(%r12),64		# set new stidp flag
+.Loldfmt:	
+		
 #
 # find out if we have an IEEE fpu
 #
@@ -576,9 +602,12 @@
 .Lpcfpu:.long  0x00080000,0x80000000 + .Lchkfpu
 .Lpccsp:.long  0x00080000,0x80000000 + .Lchkcsp
 .Lpcmvpg:.long 0x00080000,0x80000000 + .Lchkmvpg
+.Lpcpfix:.long 0x00080000,0x80000000 + .Lchkpfix
 .Lmemsize:.long memory_size
 .Lmchunk:.long memory_chunk
 .Lmflags:.long machine_flags
+.Lbss_bgn:  .long  __bss_start
+.Lbss_end:  .long  _end
 
 	.org PARMAREA-64
 .Lduct:	.long 0,0,0,0,0,0,0,0
@@ -620,17 +649,6 @@
         ahi   %r15,-96
         xc    0(4,%r15),0(%r15)         # set backchain to zero
 
-#
-# clear bss memory
-#
-        l     %r2,.Lbss_bgn-.LPG2(%r13) # start of bss
-        l     %r3,.Lbss_end-.LPG2(%r13) # end of bss
-        sr    %r3,%r2                   # length of bss
-        sr    %r4,%r4                   #
-        sr    %r5,%r5                   # set src,length and pad to zero
-        sr    %r0,%r0                   #
-        mvcle %r2,%r4,0                 # clear mem
-        jo    .-4                       # branch back, if not finish
 # check control registers
         stctl  %c0,%c15,0(%r15)
 	oi     2(%r15),0x20             # enable sigp external interrupts
@@ -651,7 +669,5 @@
 .Ldw:	    .long  0x000a0000,0x00000000
 .Linittu:   .long  init_task_union
 .Lstart:    .long  start_kernel
-.Lbss_bgn:  .long  __bss_start
-.Lbss_end:  .long  _end
-.Laregs:    .long  0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0
+.Laregs:    .long  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/s390/kernel/process.c linux-2.4.21-pre6/arch/s390/kernel/process.c
--- linux-2.4.20/arch/s390/kernel/process.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/s390/kernel/process.c	2003-03-26 23:49:19.000000000 +0000
@@ -105,7 +105,7 @@
 		show_trace((unsigned long *) regs->gprs[15]);
 }
 
-int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 {
         int clone_arg = flags | CLONE_VM;
         int retval;
@@ -181,6 +181,8 @@
         /* save fprs, if used in last task */
 	save_fp_regs(&p->thread.fp_regs);
         p->thread.user_seg = __pa((unsigned long) p->mm->pgd) | _SEGMENT_TABLE;
+	/* start process with ar4 pointing to the correct address space */
+	p->thread.ar4 = get_fs().ar4;
         /* Don't copy debug registers */
         memset(&p->thread.per_info,0,sizeof(p->thread.per_info));
         return 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/s390/kernel/s390_ksyms.c linux-2.4.21-pre6/arch/s390/kernel/s390_ksyms.c
--- linux-2.4.20/arch/s390/kernel/s390_ksyms.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/s390/kernel/s390_ksyms.c	2003-03-26 23:49:00.000000000 +0000
@@ -60,4 +60,5 @@
 EXPORT_SYMBOL(csum_fold);
 EXPORT_SYMBOL(console_mode);
 EXPORT_SYMBOL(console_device);
+EXPORT_SYMBOL(pfix_table);
 EXPORT_SYMBOL_NOVERS(do_call_softirq);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/s390/kernel/setup.c linux-2.4.21-pre6/arch/s390/kernel/setup.c
--- linux-2.4.20/arch/s390/kernel/setup.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/s390/kernel/setup.c	2003-03-26 23:49:06.000000000 +0000
@@ -56,6 +56,8 @@
 unsigned long cpu_initialized = 0;
 volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */
 
+void* *pfix_table=NULL;
+
 /*
  * Setup options
  */
@@ -317,6 +319,10 @@
 	printk((MACHINE_IS_VM) ?
 	       "We are running under VM (31 bit mode)\n" :
 	       "We are running native (31 bit mode)\n");
+	if (MACHINE_IS_VM)
+		printk((MACHINE_HAS_PFIX) ?
+		       "This machine has PFIX support\n" :
+		       "This machine has no PFIX support\n");
 	printk((MACHINE_HAS_IEEE) ?
 	       "This machine has an IEEE fpu\n" :
 	       "This machine has no IEEE fpu\n");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/s390/kernel/signal.c linux-2.4.21-pre6/arch/s390/kernel/signal.c
--- linux-2.4.20/arch/s390/kernel/signal.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/s390/kernel/signal.c	2003-03-26 23:49:19.000000000 +0000
@@ -544,7 +544,7 @@
 				continue;
 
 			switch (signr) {
-			case SIGCONT: case SIGCHLD: case SIGWINCH:
+			case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG:
 				continue;
 
 			case SIGTSTP: case SIGTTIN: case SIGTTOU:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/s390/kernel/time.c linux-2.4.21-pre6/arch/s390/kernel/time.c
--- linux-2.4.20/arch/s390/kernel/time.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/s390/kernel/time.c	2003-03-26 23:48:58.000000000 +0000
@@ -182,13 +182,13 @@
 {
 	unsigned long cr0;
 
+	S390_lowcore.jiffy_timer = (__u64) jiffies * CLK_TICKS_PER_JIFFY;
+	S390_lowcore.jiffy_timer += init_timer_cc + CLK_TICKS_PER_JIFFY;
+	asm volatile ("SCKC %0" : : "m" (S390_lowcore.jiffy_timer));
         /* allow clock comparator timer interrupt */
         asm volatile ("STCTL 0,0,%0" : "=m" (cr0) : : "memory");
         cr0 |= 0x800;
         asm volatile ("LCTL 0,0,%0" : : "m" (cr0) : "memory");
-	S390_lowcore.jiffy_timer = (__u64) jiffies * CLK_TICKS_PER_JIFFY;
-	S390_lowcore.jiffy_timer += init_timer_cc + CLK_TICKS_PER_JIFFY;
-	asm volatile ("SCKC %0" : : "m" (S390_lowcore.jiffy_timer));
 }
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/s390/lib/uaccess.S linux-2.4.21-pre6/arch/s390/lib/uaccess.S
--- linux-2.4.20/arch/s390/lib/uaccess.S	2002-02-25 19:37:56.000000000 +0000
+++ linux-2.4.21-pre6/arch/s390/lib/uaccess.S	2003-03-26 23:49:08.000000000 +0000
@@ -1,9 +1,9 @@
 /*
  *  arch/s390/lib/uaccess.S
- *    fixup routines for copy_{from|to}_user functions.
+ *    __copy_{from|to}_user functions.
  *
  *  s390
- *    Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Copyright (C) 2000,2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
  *    Authors(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
  *
  *  These functions have standard call interface
@@ -19,23 +19,26 @@
 	sacf	512
 0:	mvcle	%r2,%r4,0
 	jo	0b
-	sacf	0
+1:	sacf	0
 	lr	%r2,%r5
 	br	%r14
-1:	l	%r1,__LC_PGM_OLD_PSW+4
-        sll	%r4,1
-        srl	%r4,1
-2:      lhi	%r3,-4096
-        sll	%r3,1
-        srl	%r3,1
-        n	%r3,__LC_TRANS_EXC_ADDR
-        sr	%r3,%r4
-        bm	4(%r1)
-3:      mvcle	%r2,%r4,0
-        b	4(%r1)
+2:	lhi	%r1,-4096
+	lr	%r3,%r4
+	slr	%r3,%r1      # %r3 = %r4 + 4096
+	nr	%r3,%r1      # %r3 = (%r4 + 4096) & -4096
+	slr	%r3,%r4      # %r3 = #bytes to next user page boundary
+	clr	%r5,%r3      # copy crosses next page boundary ?
+	jnh	1b           # no, this page fauled
+	# The page after the current user page might have faulted.
+	# We cant't find out which page because the program check handler
+	# might have callled schedule, destroying all lowcore information.
+	# We retry with the shortened length.
+3:	mvcle	%r2,%r4,0
+	jo	3b
+	j	1b
         .section __ex_table,"a"
-	.long	0b,1b
-	.long	3b,2b
+	.long	0b,2b
+	.long	3b,1b
         .previous
 
         .align 4
@@ -46,23 +49,26 @@
 	sacf	512
 0:	mvcle	%r4,%r2,0
 	jo	0b
-	sacf	0
+1:	sacf	0
 	lr	%r2,%r3
 	br	%r14
-1:	l	%r1,__LC_PGM_OLD_PSW+4
-        sll	%r4,1
-        srl	%r4,1
-2:      lhi	%r5,-4096
-        sll	%r5,1
-        srl	%r5,1
-        n	%r5,__LC_TRANS_EXC_ADDR
-        sr	%r5,%r4
-        bm	4(%r1)
-3:      mvcle	%r4,%r2,0
-        b	4(%r1)
+2:	lhi	%r1,-4096
+	lr	%r5,%r4
+	slr	%r5,%r1      # %r5 = %r4 + 4096
+	nr	%r5,%r1      # %r5 = (%r4 + 4096) & -4096
+	slr	%r5,%r4      # %r5 = #bytes to next user page boundary
+	clr	%r3,%r5      # copy crosses next page boundary ?
+	jnh	1b           # no, the current page fauled
+	# The page after the current user page might have faulted.
+	# We cant't find out which page because the program check handler
+	# might have callled schedule, destroying all lowcore information.
+	# We retry with the shortened length.
+3:	mvcle	%r4,%r2,0
+	jo	3b
+	j	1b
         .section __ex_table,"a"
-	.long   0b,1b
-        .long	3b,2b
+	.long	0b,2b
+	.long	3b,1b
         .previous
 
         .align 4
@@ -76,22 +82,27 @@
 	sacf	512
 0:	mvcle	%r4,%r2,0
 	jo	0b
-	sacf	0
-	lr	%r2,%r3
+1:	sacf	0
 	br	%r14
-1:	l	%r1,__LC_PGM_OLD_PSW+4
-        sll	%r4,1
-        srl	%r4,1
-2:      lhi	%r5,-4096
-        sll	%r5,1
-        srl	%r5,1
-        n	%r5,__LC_TRANS_EXC_ADDR
-        sr	%r5,%r4
-        bm	4(%r1)
-3:      mvcle	%r4,%r2,0
-        b	4(%r1)
+2:	lr	%r2,%r5
+	lhi	%r1,-4096
+	slr	%r5,%r1      # %r5 = %r4 + 4096
+	nr	%r5,%r1      # %r5 = (%r4 + 4096) & -4096
+	slr	%r5,%r4      # %r5 = #bytes to next user page boundary
+	clr	%r2,%r5      # copy crosses next page boundary ?
+	jnh	1b           # no, the current page fauled
+	# The page after the current user page might have faulted.
+	# We cant't find out which page because the program check handler
+	# might have callled schedule, destroying all lowcore information.
+	# We retry with the shortened length.
+	slr	%r2,%r5
+3:	mvcle	%r4,%r2,0
+	jo	3b
+	j	1b
+4:	alr	%r2,%r5
+	j	1b
         .section __ex_table,"a"
-	.long   0b,1b
-        .long	3b,2b
+	.long	0b,2b
+        .long	3b,4b
         .previous
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/s390/mm/init.c linux-2.4.21-pre6/arch/s390/mm/init.c
--- linux-2.4.20/arch/s390/mm/init.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/s390/mm/init.c	2003-03-26 23:49:09.000000000 +0000
@@ -40,6 +40,7 @@
 mmu_gather_t mmu_gathers[NR_CPUS];
 
 static unsigned long totalram_pages;
+extern unsigned long memory_size;
 
 pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE)));
 char  empty_zero_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
@@ -153,6 +154,11 @@
                         if (address >= end_mem)
                                 pte_clear(&pte);
                         set_pte(pg_table, pte);
+			if (address < memory_size) /* do not set storage
+						      key outside the storage
+						      or die */
+				set_access_key(pte); /* switch to our
+							access key */
                         address += PAGE_SIZE;
                 }
         }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/s390x/kernel/debug.c linux-2.4.21-pre6/arch/s390x/kernel/debug.c
--- linux-2.4.20/arch/s390x/kernel/debug.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/s390x/kernel/debug.c	2003-03-26 23:49:07.000000000 +0000
@@ -459,9 +459,9 @@
 		size = MIN((len - count), (size - entry_offset));
 
 		if(size){
-			if ((rc = copy_to_user(user_buf + count, 
-					p_info->temp_buf + entry_offset, size)))
-			return rc;
+			if (copy_to_user(user_buf + count, 
+					p_info->temp_buf + entry_offset, size))
+				return -EFAULT;
 		}
 		count += size;
 		entry_offset = 0;
@@ -744,8 +744,10 @@
                         id->name, new_level, 0, DEBUG_MAX_LEVEL);
         } else {
                 id->level = new_level;
+#ifdef DEBUG
                 printk(KERN_INFO 
 			"debug: %s: new level %i\n",id->name,id->level);
+#endif
         }
 	spin_unlock_irqrestore(&id->lock,flags);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/s390x/kernel/entry.S linux-2.4.21-pre6/arch/s390x/kernel/entry.S
--- linux-2.4.20/arch/s390x/kernel/entry.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/s390x/kernel/entry.S	2003-03-26 23:49:19.000000000 +0000
@@ -589,7 +589,7 @@
         .long  SYSCALL(sys_madvise,sys32_madvise_wrapper)
 	.long  SYSCALL(sys_getdents64,sys32_getdents64_wrapper)/* 220 */
 	.long  SYSCALL(sys_ni_syscall,sys32_fcntl64_wrapper)
-	.long  SYSCALL(sys_ni_syscall,sys_ni_syscall)
+	.long  SYSCALL(sys_readahead,sys_ni_syscall)
 	.long  SYSCALL(sys_ni_syscall,sys_ni_syscall)
 	.long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 224 - reserved for setxattr  */
 	.long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 225 - reserved for lsetxattr */
@@ -631,13 +631,14 @@
         tm      __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
         jnz     pgm_per                  # got per exception -> special case
 	SAVE_ALL __LC_PGM_OLD_PSW,1
-	llgh    %r8,__LC_PGM_INT_CODE
+	lgf     %r3,__LC_PGM_ILC	 # load program interruption code
+	lghi	%r8,0x7f
+	ngr	%r8,%r3
         sll     %r8,3
 	GET_CURRENT
         larl    %r1,pgm_check_table
         lg      %r1,0(%r8,%r1)		 # load address of handler routine
         la      %r2,SP_PTREGS(%r15)	 # address of register-save area
-	lgf     %r3,__LC_PGM_ILC	 # load program interruption code
 	larl	%r14,sysc_return
         br      %r1			 # branch to interrupt-handler
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/s390x/kernel/head.S linux-2.4.21-pre6/arch/s390x/kernel/head.S
--- linux-2.4.20/arch/s390x/kernel/head.S	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/s390x/kernel/head.S	2003-03-26 23:49:07.000000000 +0000
@@ -467,10 +467,21 @@
 	larl  %r12,_pstart               # pointer to parameter area
 					 # move IPL device to lowcore
         mvc   __LC_IPLDEV(4),IPL_DEVICE+4-PARMAREA(%r12)
+
+#
+# clear bss memory
+#
+	larl  %r2,__bss_start           # start of bss segment
+        larl  %r3,_end                  # end of bss segment
+        sgr   %r3,%r2                   # length of bss
+        sgr   %r4,%r4                   #
+        sgr   %r5,%r5                   # set src,length and pad to zero
+        mvcle %r2,%r4,0                 # clear mem
+        jo    .-4                       # branch back, if not finish
+
 					 # set program check new psw mask
 	mvc   __LC_PGM_NEW_PSW(8),.Lpcmsk-.LPG1(%r13)
 
-
 #
 # find memory chunks.
 #
@@ -537,11 +548,26 @@
 	tm     __LC_CPUID,0xff          # running under VM ?
 	bno    0f-.LPG1(%r13)
         oi     7(%r12),1                # set VM flag
+#
+# we are running under VM, find out if we have PFIX
+#
+	la     %r1,0f-.LPG1(%r13)       # set program check address
+	stg    %r1,__LC_PGM_NEW_PSW+8
+        lghi   %r0,0x4000
+	lghi   %r2,0
+	.long  0x83200098               # diag 2,0,x'0098' - lock page
+	lghi   %r2,4
+	.long  0x83200098               # diag 2,0,x'0098' - unlock page
+	oi     7(%r12),128              # set PFIX flag
 0:      lh     %r0,__LC_CPUID+4         # get cpu version
         chi    %r0,0x7490               # running on a P/390 ?
         bne    1f-.LPG1(%r13)
         oi     7(%r12),4                # set P/390 flag
 1:
+	chi    %r0,0x2084		# new stidp format?
+	bne    2f-.LPG1(%r13)
+	oi     7(%r12),64		# set new stidp flag
+2:	
 
 #
 # find out if we have the MVPG instruction
@@ -631,16 +657,7 @@
         stg   %r15,__LC_KERNEL_STACK    # set end of kernel stack
         aghi  %r15,-160
         xc    0(8,%r15),0(%r15)         # set backchain to zero
-#
-# clear bss memory
-#
-	larl  %r2,__bss_start           # start of bss segment
-        larl  %r3,_end                  # end of bss segment
-        sgr   %r3,%r2                   # length of bss
-        sgr   %r4,%r4                   #
-        sgr   %r5,%r5                   # set src,length and pad to zero
-        mvcle %r2,%r4,0                 # clear mem
-        jo    .-4                       # branch back, if not finish
+
 # check control registers
         stctg  %c0,%c15,0(%r15)
 	oi     6(%r15),0x20             # enable sigp external interrupts
@@ -658,5 +675,5 @@
 #
             .align 8
 .Ldw:       .quad  0x0002000180000000,0x0000000000000000
-.Laregs:    .long  0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0
+.Laregs:    .long  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/s390x/kernel/process.c linux-2.4.21-pre6/arch/s390x/kernel/process.c
--- linux-2.4.20/arch/s390x/kernel/process.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/s390x/kernel/process.c	2003-03-26 23:49:09.000000000 +0000
@@ -102,7 +102,7 @@
 		show_trace((unsigned long *) regs->gprs[15]);
 }
 
-int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 {
         int clone_arg = flags | CLONE_VM;
         int retval;
@@ -178,6 +178,8 @@
         /* save fprs, if used in last task */
 	save_fp_regs(&p->thread.fp_regs);
         p->thread.user_seg = __pa((unsigned long) p->mm->pgd) | _REGION_TABLE;
+	/* start new process with ar4 pointing to the correct address space */
+	p->thread.ar4 = get_fs().ar4;
         /* Don't copy debug registers */
         memset(&p->thread.per_info,0,sizeof(p->thread.per_info));
         return 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/s390x/kernel/s390_ksyms.c linux-2.4.21-pre6/arch/s390x/kernel/s390_ksyms.c
--- linux-2.4.20/arch/s390x/kernel/s390_ksyms.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/s390x/kernel/s390_ksyms.c	2003-03-26 23:49:20.000000000 +0000
@@ -70,4 +70,5 @@
 EXPORT_SYMBOL(kernel_thread);
 EXPORT_SYMBOL(console_mode);
 EXPORT_SYMBOL(console_device);
+EXPORT_SYMBOL(pfix_table);
 EXPORT_SYMBOL_NOVERS(do_call_softirq);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/s390x/kernel/setup.c linux-2.4.21-pre6/arch/s390x/kernel/setup.c
--- linux-2.4.20/arch/s390x/kernel/setup.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/s390x/kernel/setup.c	2003-03-26 23:49:29.000000000 +0000
@@ -56,6 +56,8 @@
 unsigned long cpu_initialized = 0;
 volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */
 
+void* *pfix_table=NULL;
+
 /*
  * Setup options
  */
@@ -317,6 +319,10 @@
 	printk((MACHINE_IS_VM) ?
 	       "We are running under VM (64 bit mode)\n" :
 	       "We are running native (64 bit mode)\n");
+	if (MACHINE_IS_VM)
+		printk((MACHINE_HAS_PFIX) ?
+		       "This machine has PFIX support\n" :
+		       "This machine has no PFIX support\n");
 
         ROOT_DEV = to_kdev_t(0x0100);
         memory_start = (unsigned long) &_end;    /* fixit if use $CODELO etc*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/s390x/kernel/signal.c linux-2.4.21-pre6/arch/s390x/kernel/signal.c
--- linux-2.4.20/arch/s390x/kernel/signal.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/s390x/kernel/signal.c	2003-03-26 23:49:49.000000000 +0000
@@ -548,7 +548,7 @@
 				continue;
 
 			switch (signr) {
-			case SIGCONT: case SIGCHLD: case SIGWINCH:
+			case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG:
 				continue;
 
 			case SIGTSTP: case SIGTTIN: case SIGTTOU:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/s390x/kernel/smp.c linux-2.4.21-pre6/arch/s390x/kernel/smp.c
--- linux-2.4.20/arch/s390x/kernel/smp.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/s390x/kernel/smp.c	2003-03-26 23:49:39.000000000 +0000
@@ -224,10 +224,6 @@
  */
 void smp_send_stop(void)
 {
-        int i;
-        u32 dummy;
-        unsigned long low_core_addr;
-
         /* write magic number to zero page (absolute 0) */
         get_cpu_lowcore(smp_processor_id())->panic_magic = __PANIC_MAGIC;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/s390x/kernel/time.c linux-2.4.21-pre6/arch/s390x/kernel/time.c
--- linux-2.4.20/arch/s390x/kernel/time.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/s390x/kernel/time.c	2003-03-26 23:49:20.000000000 +0000
@@ -155,13 +155,13 @@
 {
 	unsigned long cr0;
 
+	S390_lowcore.jiffy_timer = (__u64) jiffies * CLK_TICKS_PER_JIFFY;
+	S390_lowcore.jiffy_timer += init_timer_cc + CLK_TICKS_PER_JIFFY;
+	asm volatile ("SCKC %0" : : "m" (S390_lowcore.jiffy_timer));
         /* allow clock comparator timer interrupt */
         asm volatile ("STCTG 0,0,%0" : "=m" (cr0) : : "memory");
         cr0 |= 0x800;
         asm volatile ("LCTLG 0,0,%0" : : "m" (cr0) : "memory");
-	S390_lowcore.jiffy_timer = (__u64) jiffies * CLK_TICKS_PER_JIFFY;
-	S390_lowcore.jiffy_timer += init_timer_cc + CLK_TICKS_PER_JIFFY;
-	asm volatile ("SCKC %0" : : "m" (S390_lowcore.jiffy_timer));
 }
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/s390x/lib/uaccess.S linux-2.4.21-pre6/arch/s390x/lib/uaccess.S
--- linux-2.4.20/arch/s390x/lib/uaccess.S	2002-02-25 19:37:56.000000000 +0000
+++ linux-2.4.21-pre6/arch/s390x/lib/uaccess.S	2003-03-26 23:49:51.000000000 +0000
@@ -1,9 +1,9 @@
 /*
  *  arch/s390x/lib/uaccess.S
- *    fixup routines for copy_{from|to}_user functions.
+ *    __copy_{from|to}_user functions.
  *
- *  S390
- *    Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *  s390
+ *    Copyright (C) 2000,2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
  *    Authors(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
  *
  *  These functions have standard call interface
@@ -19,20 +19,26 @@
 	sacf	512
 0:	mvcle	%r2,%r4,0
 	jo	0b
-	sacf	0
+1:	sacf	0
 	lgr	%r2,%r5
 	br	%r14
-1:	lg	%r1,__LC_PGM_OLD_PSW+8
-2:	lghi	%r3,-4096
-        ng	%r3,__LC_TRANS_EXC_ADDR
-        sgr	%r3,%r4
-        bm	4(%r1)
-3:      mvcle	%r2,%r4,0
-        b	4(%r1)
+2:	lghi	%r1,-4096
+	lgr	%r3,%r4
+	slgr	%r3,%r1      # %r3 = %r4 + 4096
+	ngr	%r3,%r1      # %r3 = (%r4 + 4096) & -4096
+	slgr	%r3,%r4      # %r3 = #bytes to next user page boundary
+	clgr	%r5,%r3      # copy crosses next page boundary ?
+	jnh	1b           # no, this page fauled
+	# The page after the current user page might have faulted.
+	# We cant't find out which page because the program check handler
+	# might have callled schedule, destroying all lowcore information.
+	# We retry with the shortened length.
+3:	mvcle	%r2,%r4,0
+	jo	3b
+	j	1b
         .section __ex_table,"a"
-        .align	8
-	.quad	0b,1b
-	.quad	3b,2b
+	.quad	0b,2b
+	.quad	3b,1b
         .previous
 
         .align 4
@@ -43,20 +49,26 @@
 	sacf	512
 0:	mvcle	%r4,%r2,0
 	jo	0b
-	sacf	0
+1:	sacf	0
 	lgr	%r2,%r3
 	br	%r14
-1:	lg	%r1,__LC_PGM_OLD_PSW+8
-2:      lghi	%r5,-4096
-        ng	%r5,__LC_TRANS_EXC_ADDR
-        sgr	%r5,%r4
-        bm	4(%r1)
-3:      mvcle	%r4,%r2,0
-        b	4(%r1)
+2:	lghi	%r1,-4096
+	lgr	%r5,%r4
+	slgr	%r5,%r1      # %r5 = %r4 + 4096
+	ngr	%r5,%r1      # %r5 = (%r4 + 4096) & -4096
+	slgr	%r5,%r4      # %r5 = #bytes to next user page boundary
+	clgr	%r3,%r5      # copy crosses next page boundary ?
+	jnh	1b           # no, the current page fauled
+	# The page after the current user page might have faulted.
+	# We cant't find out which page because the program check handler
+	# might have callled schedule, destroying all lowcore information.
+	# We retry with the shortened length.
+3:	mvcle	%r4,%r2,0
+	jo	3b
+	j	1b
         .section __ex_table,"a"
-        .align	8
-        .quad	0b,1b
-        .quad	3b,2b
+	.quad	0b,2b
+	.quad	3b,1b
         .previous
 
         .align 4
@@ -70,18 +82,26 @@
 	sacf	512
 0:	mvcle	%r4,%r2,0
 	jo	0b
-	sacf	0
-	lgr	%r2,%r5
+1:	sacf	0
 	br	%r14
-1:	lg	%r1,__LC_PGM_OLD_PSW+8
-2:      lghi	%r5,-4096
-        ng	%r5,__LC_TRANS_EXC_ADDR
-        sgr	%r5,%r4
-        bm	4(%r1)
-3:      mvcle	%r4,%r2,0
-        b	4(%r1)
+2:	lgr	%r2,%r5
+	lghi	%r1,-4096
+	slgr	%r5,%r1      # %r5 = %r4 + 4096
+	ngr	%r5,%r1      # %r5 = (%r4 + 4096) & -4096
+	slgr	%r5,%r4      # %r5 = #bytes to next user page boundary
+	clgr	%r2,%r5      # copy crosses next page boundary ?
+	jnh	1b           # no, the current page fauled
+	# The page after the current user page might have faulted.
+	# We cant't find out which page because the program check handler
+	# might have callled schedule, destroying all lowcore information.
+	# We retry with the shortened length.
+	slgr	%r2,%r5
+3:	mvcle	%r4,%r2,0
+	jo	3b
+	j	1b
+4:	algr	%r2,%r5
+	j	1b
         .section __ex_table,"a"
-        .align	8
-        .quad	0b,1b
-        .quad	3b,2b
+	.quad	0b,2b
+        .quad	3b,4b
         .previous
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/s390x/mm/init.c linux-2.4.21-pre6/arch/s390x/mm/init.c
--- linux-2.4.20/arch/s390x/mm/init.c	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/s390x/mm/init.c	2003-03-26 23:49:25.000000000 +0000
@@ -40,6 +40,7 @@
 mmu_gather_t mmu_gathers[NR_CPUS];
 
 static unsigned long totalram_pages;
+extern unsigned long memory_size;
 
 pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE)));
 char  empty_zero_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
@@ -233,6 +234,11 @@
                                         continue;
                                 }
                                 set_pte(pt_dir, pte);
+				if (address < memory_size ) /* do not set storage
+							       key outside the storage
+							       or die */
+					set_access_key(pte); /* switch to our
+								access key */
                                 address += PAGE_SIZE;
                         }
                 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sh/config.in linux-2.4.21-pre6/arch/sh/config.in
--- linux-2.4.20/arch/sh/config.in	2002-11-28 23:53:11.000000000 +0000
+++ linux-2.4.21-pre6/arch/sh/config.in	2003-03-26 23:49:39.000000000 +0000
@@ -189,7 +189,7 @@
    if [ "$CONFIG_PCI_GODIRECT" = "y" -o "$CONFIG_PCI_GOANY" = "y" ]; then
       define_bool CONFIG_PCI_DIRECT y
    fi
-   bool 'Cache and PCI noncoherent' CONFIG_SH_PCIDMA_NONCOHERENT n
+   bool 'Cache and PCI noncoherent' CONFIG_SH_PCIDMA_NONCOHERENT
 fi
 
 source drivers/pci/Config.in
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sh/kernel/irq_intc2.c linux-2.4.21-pre6/arch/sh/kernel/irq_intc2.c
--- linux-2.4.20/arch/sh/kernel/irq_intc2.c	2001-09-08 19:29:09.000000000 +0000
+++ linux-2.4.21-pre6/arch/sh/kernel/irq_intc2.c	2003-03-26 23:49:50.000000000 +0000
@@ -107,7 +107,7 @@
 	}
 
 	disable_irq_nosync(irq);
-	/* Fill the the data we need */
+	/* Fill the data we need */
 	intc2_data[offset].addr=addr;
 	intc2_data[offset].mask=1<<pos;
 		
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sh/kernel/process.c linux-2.4.21-pre6/arch/sh/kernel/process.c
--- linux-2.4.20/arch/sh/kernel/process.c	2001-10-15 20:36:48.000000000 +0000
+++ linux-2.4.21-pre6/arch/sh/kernel/process.c	2003-03-26 23:49:50.000000000 +0000
@@ -118,7 +118,7 @@
  * This is the mechanism for creating a new kernel thread.
  *
  */
-int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 {	/* Don't use this in BL=1(cli).  Or else, CPU resets! */
 	register unsigned long __sc0 __asm__ ("r0");
 	register unsigned long __sc3 __asm__ ("r3") = __NR_clone;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc/config.in linux-2.4.21-pre6/arch/sparc/config.in
--- linux-2.4.20/arch/sparc/config.in	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/sparc/config.in	2003-03-26 23:49:00.000000000 +0000
@@ -264,7 +264,15 @@
 mainmenu_option next_comment
 comment 'Kernel hacking'
 
-bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+bool 'Kernel debugging' CONFIG_DEBUG_KERNEL
+if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then
+   bool '  Debug high memory support' CONFIG_DEBUG_HIGHMEM
+   bool '  Debug memory allocations' CONFIG_DEBUG_SLAB
+   bool '  Memory mapped I/O debugging' CONFIG_DEBUG_IOVIRT
+   bool '  Magic SysRq key' CONFIG_MAGIC_SYSRQ
+   bool '  Spinlock debugging' CONFIG_DEBUG_SPINLOCK
+fi
+
 endmenu
 
 source lib/Config.in
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc/kernel/apc.c linux-2.4.21-pre6/arch/sparc/kernel/apc.c
--- linux-2.4.20/arch/sparc/kernel/apc.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/sparc/kernel/apc.c	2003-03-26 23:49:40.000000000 +0000
@@ -22,7 +22,6 @@
 /* Debugging
  * 
  * #define APC_DEBUG_LED
- * #define APC_NO_IDLE
  */
 
 #define APC_MINOR	MISC_DYNAMIC_MINOR
@@ -31,10 +30,27 @@
 
 volatile static u8 *regs; 
 static int apc_regsize;
+static int apc_no_idle __initdata = 0;
 
 #define apc_readb(offs)			(sbus_readb(regs+offs))
 #define apc_writeb(val, offs) 	(sbus_writeb(val, regs+offs))
 
+/* Specify "apc=noidle" on the kernel command line to 
+ * disable APC CPU standby support.  Certain prototype
+ * systems (SPARCstation-Fox) do not play well with APC
+ * CPU idle, so disable this if your system has APC and 
+ * crashes randomly.
+ */
+static int __init apc_setup(char *str) 
+{
+	if(!strncmp(str, "noidle", strlen("noidle"))) {
+		apc_no_idle = 1;
+		return 1;
+	}
+	return 0;
+}
+__setup("apc=", apc_setup);
+
 /* 
  * CPU idle callback function
  * See .../arch/sparc/kernel/process.c
@@ -127,6 +143,7 @@
 	struct sbus_bus *sbus = NULL;
 	struct sbus_dev *sdev = NULL;
 	int iTmp = 0;
+
 	for_each_sbus(sbus) {
 		for_each_sbusdev(sdev, sbus) {
 			if (!strcmp(sdev->prom_name, APC_OBPNAME)) {
@@ -155,12 +172,12 @@
 		return -ENODEV;
 	}
 
-#ifndef APC_NO_IDLE	
 	/* Assign power management IDLE handler */
-	pm_idle = apc_swift_idle;	
-#endif
+	if(!apc_no_idle)
+		pm_idle = apc_swift_idle;	
 
-	printk(KERN_INFO "%s: power management initialized\n", APC_DEVNAME);
+	printk(KERN_INFO "%s: power management initialized%s\n", 
+		APC_DEVNAME, apc_no_idle ? " (CPU idle disabled)" : "");
 	return 0;
 }
 
@@ -169,3 +186,4 @@
  * initialized, so we install ourselves thusly:
  */
 __initcall(apc_probe);
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc/kernel/entry.S linux-2.4.21-pre6/arch/sparc/kernel/entry.S
--- linux-2.4.20/arch/sparc/kernel/entry.S	2001-11-13 17:16:05.000000000 +0000
+++ linux-2.4.21-pre6/arch/sparc/kernel/entry.S	2003-03-26 23:49:35.000000000 +0000
@@ -1794,6 +1794,15 @@
 	retl
 	 nop
 
+	.globl	C_LABEL(ndelay)
+C_LABEL(ndelay):
+	save	%sp, -REGWIN_SZ, %sp
+	mov	%i0, %o0
+	call	.umul
+	 mov	5, %o1
+	ba	delay_continue
+	 nop
+
 	.globl	C_LABEL(udelay)
 C_LABEL(udelay):
 	save	%sp, -REGWIN_SZ, %sp
@@ -1801,6 +1810,7 @@
 	sethi	%hi(0x10c6), %o1
 	call	.umul
 	 or	%o1, %lo(0x10c6), %o1
+delay_continue:
 #ifndef CONFIG_SMP
 	sethi	%hi(C_LABEL(loops_per_jiffy)), %o3
 	call	.umul
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc/kernel/ioport.c linux-2.4.21-pre6/arch/sparc/kernel/ioport.c
--- linux-2.4.20/arch/sparc/kernel/ioport.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/sparc/kernel/ioport.c	2003-03-26 23:49:55.000000000 +0000
@@ -221,19 +221,7 @@
 		pa += PAGE_SIZE;
 	}
 
-	/*
-	 * XXX Playing with implementation details here.
-	 * On sparc64 Ebus has resources with precise boundaries.
-	 * We share drivers with sparc64. Too clever drivers use
-	 * start of a resource instead of a base address.
-	 *
-	 * XXX-2 This may be not valid anymore, clean when
-	 * interface to sbus_ioremap() is resolved.
-	 */
-	res->start += offset;
-	res->end = res->start + sz - 1;		/* not strictly necessary.. */
-
-	return (void *) res->start;
+	return (void *) (res->start + offset);
 }
 
 /*
@@ -244,7 +232,7 @@
 	unsigned long plen;
 
 	plen = res->end - res->start + 1;
-	plen = (plen + PAGE_SIZE-1) & PAGE_MASK;
+	if ((plen & (PAGE_SIZE-1)) != 0) BUG();
 	while (plen != 0) {
 		plen -= PAGE_SIZE;
 		(*_sparc_unmapioaddr)(res->start + plen);
@@ -515,7 +503,7 @@
 	mmu_inval_dma_area(va, len_total);
 
 #if 1
-/* P3 */ printk("pci_alloc_consistent: kva %lx uncva %lx phys %lx size %x\n",
+/* P3 */ printk("pci_alloc_consistent: kva %lx uncva %lx phys %lx size %lx\n",
   (long)va, (long)res->start, (long)virt_to_phys(va), len_total);
 #endif
 	{
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc/kernel/irq.c linux-2.4.21-pre6/arch/sparc/kernel/irq.c
--- linux-2.4.20/arch/sparc/kernel/irq.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/sparc/kernel/irq.c	2003-03-26 23:48:59.000000000 +0000
@@ -72,7 +72,7 @@
     prom_halt();
 }
 
-void (*init_timers)(void (*)(int, void *,struct pt_regs *)) =
+void (*sparc_init_timers)(void (*)(int, void *,struct pt_regs *)) =
     (void (*)(void (*)(int, void *,struct pt_regs *))) irq_panic;
 
 /*
@@ -92,7 +92,7 @@
 struct irqaction static_irqaction[MAX_STATIC_ALLOC];
 int static_irq_count;
 
-struct irqaction *irq_action[NR_IRQS+1] = {
+struct irqaction *irq_action[NR_IRQS] = {
 	  NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL,
 	  NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL
 };
@@ -110,7 +110,7 @@
 		
 		return sun4d_get_irq_list(buf);
 	}
-	for (i = 0 ; i < (NR_IRQS+1) ; i++) {
+	for (i = 0 ; i < NR_IRQS ; i++) {
 	        action = *(i + irq_action);
 		if (!action) 
 		        continue;
@@ -147,7 +147,7 @@
 		
 		return sun4d_free_irq(irq, dev_id);
 	}
-	cpu_irq = irq & NR_IRQS;
+	cpu_irq = irq & (NR_IRQS - 1);
 	action = *(cpu_irq + irq_action);
         if (cpu_irq > 14) {  /* 14 irq levels on the sparc */
                 printk("Trying to free bogus IRQ %d\n", irq);
@@ -382,7 +382,7 @@
 	struct irqaction * action;
 	unsigned int cpu_irq;
 	
-	cpu_irq = irq & NR_IRQS;
+	cpu_irq = irq & (NR_IRQS - 1);
 	action = *(cpu_irq + irq_action);
 
         printk("IO device interrupt, irq = %d\n", irq);
@@ -392,7 +392,7 @@
 		printk("Expecting: ");
         	for (i = 0; i < 16; i++)
                 	if (action->handler)
-                        	prom_printf("[%s:%d:0x%x] ", action->name,
+				printk("[%s:%d:0x%x] ", action->name,
 				    (int) i, (unsigned int) action->handler);
 	}
         printk("AIEEE\n");
@@ -461,7 +461,7 @@
 	extern struct tt_entry trapbase_cpu1, trapbase_cpu2, trapbase_cpu3;
 #endif
 	
-	cpu_irq = irq & NR_IRQS;
+	cpu_irq = irq & (NR_IRQS - 1);
 	if(cpu_irq > 14)
 		return -EINVAL;
 	if(!handler)
@@ -551,7 +551,7 @@
 					     unsigned long, const char *, void *);
 		return sun4d_request_irq(irq, handler, irqflags, devname, dev_id);
 	}
-	cpu_irq = irq & NR_IRQS;
+	cpu_irq = irq & (NR_IRQS - 1);
 	if(cpu_irq > 14)
 		return -EINVAL;
 
@@ -636,7 +636,7 @@
 	extern void sun4c_init_IRQ( void );
 	extern void sun4m_init_IRQ( void );
 	extern void sun4d_init_IRQ( void );
-    
+
 	switch(sparc_cpu_model) {
 	case sun4c:
 	case sun4:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc/kernel/process.c linux-2.4.21-pre6/arch/sparc/kernel/process.c
--- linux-2.4.20/arch/sparc/kernel/process.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/sparc/kernel/process.c	2003-03-26 23:49:08.000000000 +0000
@@ -676,7 +676,7 @@
  * a system call from a "real" process, but the process memory space will
  * not be free'd until both the parent and the child have exited.
  */
-pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+pid_t arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 {
 	long retval;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc/kernel/signal.c linux-2.4.21-pre6/arch/sparc/kernel/signal.c
--- linux-2.4.20/arch/sparc/kernel/signal.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/sparc/kernel/signal.c	2003-03-26 23:49:50.000000000 +0000
@@ -1241,7 +1241,7 @@
 			if (current->pid == 1)
 				continue;
 			switch (signr) {
-			case SIGCONT: case SIGCHLD: case SIGWINCH:
+			case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG:
 				continue;
 
 			case SIGTSTP: case SIGTTIN: case SIGTTOU:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc/kernel/sparc_ksyms.c linux-2.4.21-pre6/arch/sparc/kernel/sparc_ksyms.c
--- linux-2.4.20/arch/sparc/kernel/sparc_ksyms.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/sparc/kernel/sparc_ksyms.c	2003-03-26 23:49:05.000000000 +0000
@@ -151,6 +151,7 @@
 #endif
 
 EXPORT_SYMBOL(udelay);
+EXPORT_SYMBOL(ndelay);
 EXPORT_SYMBOL(mostek_lock);
 EXPORT_SYMBOL(mstk48t02_regs);
 #if CONFIG_SUN_AUXIO
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc/kernel/sun4c_irq.c linux-2.4.21-pre6/arch/sparc/kernel/sun4c_irq.c
--- linux-2.4.20/arch/sparc/kernel/sun4c_irq.c	2001-04-27 05:17:26.000000000 +0000
+++ linux-2.4.21-pre6/arch/sparc/kernel/sun4c_irq.c	2003-03-26 23:49:00.000000000 +0000
@@ -34,6 +34,7 @@
 #include <asm/sun4paddr.h>
 #include <asm/idprom.h>
 #include <asm/machines.h>
+#include <asm/sbus.h>
 
 #if 0
 static struct resource sun4c_timer_eb = { "sun4c_timer" };
@@ -51,13 +52,24 @@
  */
 unsigned char *interrupt_enable = 0;
 
+static int sun4c_pil_map[] = { 0, 1, 2, 3, 5, 7, 8, 9 };
+
+unsigned int sun4c_sbint_to_irq(struct sbus_dev *sdev, unsigned int sbint)
+{
+	if (sbint >= sizeof(sun4c_pil_map)) {
+		printk(KERN_ERR "%s: bogus SBINT %d\n", sdev->prom_name, sbint);
+		BUG();
+	}
+	return sun4c_pil_map[sbint];
+}
+
 static void sun4c_disable_irq(unsigned int irq_nr)
 {
 	unsigned long flags;
 	unsigned char current_mask, new_mask;
     
 	save_and_cli(flags);
-	irq_nr &= NR_IRQS;
+	irq_nr &= (NR_IRQS - 1);
 	current_mask = *interrupt_enable;
 	switch(irq_nr) {
 	case 1:
@@ -86,7 +98,7 @@
 	unsigned char current_mask, new_mask;
     
 	save_and_cli(flags);
-	irq_nr &= NR_IRQS;
+	irq_nr &= (NR_IRQS - 1);
 	current_mask = *interrupt_enable;
 	switch(irq_nr) {
 	case 1:
@@ -213,6 +225,7 @@
 		    int_regs[0].reg_size, "sun4c_intr");
 	}
 
+	BTFIXUPSET_CALL(sbint_to_irq, sun4c_sbint_to_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(enable_irq, sun4c_enable_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(disable_irq, sun4c_disable_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(enable_pil_irq, sun4c_enable_irq, BTFIXUPCALL_NORM);
@@ -221,7 +234,7 @@
 	BTFIXUPSET_CALL(clear_profile_irq, sun4c_clear_profile_irq, BTFIXUPCALL_NOP);
 	BTFIXUPSET_CALL(load_profile_irq, sun4c_load_profile_irq, BTFIXUPCALL_NOP);
 	BTFIXUPSET_CALL(__irq_itoa, sun4m_irq_itoa, BTFIXUPCALL_NORM);
-	init_timers = sun4c_init_timers;
+	sparc_init_timers = sun4c_init_timers;
 #ifdef CONFIG_SMP
 	BTFIXUPSET_CALL(set_cpu_int, sun4c_nop, BTFIXUPCALL_NOP);
 	BTFIXUPSET_CALL(clear_cpu_int, sun4c_nop, BTFIXUPCALL_NOP);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc/kernel/sun4d_irq.c linux-2.4.21-pre6/arch/sparc/kernel/sun4d_irq.c
--- linux-2.4.20/arch/sparc/kernel/sun4d_irq.c	2001-07-20 01:11:13.000000000 +0000
+++ linux-2.4.21-pre6/arch/sparc/kernel/sun4d_irq.c	2003-03-26 23:48:57.000000000 +0000
@@ -251,6 +251,15 @@
 		return irq;
 }
 
+unsigned int sun4d_sbint_to_irq(struct sbus_dev *sdev, unsigned int sbint)
+{
+	if (sbint >= sizeof(sbus_to_pil)) {
+		printk(KERN_ERR "%s: bogus SBINT %d\n", sdev->prom_name, sbint);
+		BUG();
+	}
+	return sun4d_build_irq(sdev, sbus_to_pil[sbint]);
+}
+
 int sun4d_request_irq(unsigned int irq,
 		void (*handler)(int, void *, struct pt_regs *),
 		unsigned long irqflags, const char * devname, void *dev_id)
@@ -540,13 +549,14 @@
 {
 	__cli();
 
+	BTFIXUPSET_CALL(sbint_to_irq, sun4d_sbint_to_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(enable_irq, sun4d_enable_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(disable_irq, sun4d_disable_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(clear_clock_irq, sun4d_clear_clock_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(clear_profile_irq, sun4d_clear_profile_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(load_profile_irq, sun4d_load_profile_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(__irq_itoa, sun4d_irq_itoa, BTFIXUPCALL_NORM);
-	init_timers = sun4d_init_timers;
+	sparc_init_timers = sun4d_init_timers;
 #ifdef CONFIG_SMP
 	BTFIXUPSET_CALL(set_cpu_int, sun4d_set_cpu_int, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(clear_cpu_int, sun4d_clear_ipi, BTFIXUPCALL_NOP);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc/kernel/sun4m_irq.c linux-2.4.21-pre6/arch/sparc/kernel/sun4m_irq.c
--- linux-2.4.20/arch/sparc/kernel/sun4m_irq.c	2001-04-27 05:17:26.000000000 +0000
+++ linux-2.4.21-pre6/arch/sparc/kernel/sun4m_irq.c	2003-03-26 23:49:39.000000000 +0000
@@ -36,6 +36,7 @@
 #include <asm/smp.h>
 #include <asm/irq.h>
 #include <asm/io.h>
+#include <asm/sbus.h>
 
 static unsigned long dummy;
 
@@ -77,6 +78,17 @@
 	SUN4M_INT_SBUS(6)				  /* 14 irq 13 */
 };
 
+static int sun4m_pil_map[] = { 0, 2, 3, 5, 7, 9, 11, 13 };
+
+unsigned int sun4m_sbint_to_irq(struct sbus_dev *sdev, unsigned int sbint) 
+{
+	if (sbint >= sizeof(sun4m_pil_map)) {
+		printk(KERN_ERR "%s: bogus SBINT %d\n", sdev->prom_name, sbint);
+		BUG();
+	}
+	return sun4m_pil_map[sbint] | 0x30;
+}
+
 inline unsigned long sun4m_get_irqmask(unsigned int irq)
 {
 	unsigned long mask;
@@ -366,6 +378,7 @@
 				&sun4m_interrupts->undirected_target;
 		sun4m_interrupts->undirected_target = 0;
 	}
+	BTFIXUPSET_CALL(sbint_to_irq, sun4m_sbint_to_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(enable_irq, sun4m_enable_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(disable_irq, sun4m_disable_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(enable_pil_irq, sun4m_enable_pil_irq, BTFIXUPCALL_NORM);
@@ -374,7 +387,7 @@
 	BTFIXUPSET_CALL(clear_profile_irq, sun4m_clear_profile_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(load_profile_irq, sun4m_load_profile_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(__irq_itoa, sun4m_irq_itoa, BTFIXUPCALL_NORM);
-	init_timers = sun4m_init_timers;
+	sparc_init_timers = sun4m_init_timers;
 #ifdef CONFIG_SMP
 	BTFIXUPSET_CALL(set_cpu_int, sun4m_send_ipi, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(clear_cpu_int, sun4m_clear_ipi, BTFIXUPCALL_NORM);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc/kernel/systbls.S linux-2.4.21-pre6/arch/sparc/kernel/systbls.S
--- linux-2.4.20/arch/sparc/kernel/systbls.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/sparc/kernel/systbls.S	2003-03-26 23:49:39.000000000 +0000
@@ -51,11 +51,11 @@
 /*150*/	.long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_getdents64
 /*155*/	.long sys_fcntl64, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_oldumount
 /*160*/	.long sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_nis_syscall
-/*165*/	.long sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall
-/*170*/	.long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents
-/*175*/	.long sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*180*/	.long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_sigpending, sys_query_module
-/*185*/	.long sys_setpgid, sys_nis_syscall, sys_tkill, sys_nis_syscall, sys_newuname
+/*165*/	.long sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_setxattr
+/*170*/	.long sys_lsetxattr, sys_fsetxattr, sys_getxattr, sys_lgetxattr, sys_getdents
+/*175*/	.long sys_setsid, sys_fchdir, sys_fgetxattr, sys_listxattr, sys_llistxattr
+/*180*/	.long sys_flistxattr, sys_removexattr, sys_lremovexattr, sys_sigpending, sys_query_module
+/*185*/	.long sys_setpgid, sys_fremovexattr, sys_tkill, sys_nis_syscall, sys_newuname
 /*190*/	.long sys_init_module, sys_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
 /*195*/	.long sys_nis_syscall, sys_nis_syscall, sys_getppid, sparc_sigaction, sys_sgetmask
 /*200*/	.long sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, old_readdir
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc/kernel/time.c linux-2.4.21-pre6/arch/sparc/kernel/time.c
--- linux-2.4.20/arch/sparc/kernel/time.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/sparc/kernel/time.c	2003-03-26 23:48:58.000000000 +0000
@@ -379,7 +379,7 @@
 	else
 		clock_probe();
 
-	init_timers(timer_interrupt);
+	sparc_init_timers(timer_interrupt);
 	
 #ifdef CONFIG_SUN4
 	if(idprom->id_machtype == (SM_SUN4 | SM_4_330)) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc/mm/fault.c linux-2.4.21-pre6/arch/sparc/mm/fault.c
--- linux-2.4.20/arch/sparc/mm/fault.c	2001-12-21 17:41:53.000000000 +0000
+++ linux-2.4.21-pre6/arch/sparc/mm/fault.c	2003-03-26 23:49:25.000000000 +0000
@@ -139,7 +139,7 @@
 {
 	if((unsigned long) address < PAGE_SIZE) {
 		printk(KERN_ALERT "Unable to handle kernel NULL "
-		       "pointer dereference");
+		       "pointer dereference\n");
 	} else {
 		printk(KERN_ALERT "Unable to handle kernel paging request "
 		       "at virtual address %08lx\n", address);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc/mm/iommu.c linux-2.4.21-pre6/arch/sparc/mm/iommu.c
--- linux-2.4.20/arch/sparc/mm/iommu.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/sparc/mm/iommu.c	2003-03-26 23:49:35.000000000 +0000
@@ -188,7 +188,7 @@
 {
 	unsigned long page, oldpage = 0;
 
-	while(sz >= 0) {
+	while(sz != 0) {
 		sz--;
 		page = ((unsigned long) sg[sz].address) & PAGE_MASK;
 		if (oldpage == page)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc/mm/sun4c.c linux-2.4.21-pre6/arch/sparc/mm/sun4c.c
--- linux-2.4.20/arch/sparc/mm/sun4c.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/sparc/mm/sun4c.c	2003-03-26 23:49:18.000000000 +0000
@@ -290,7 +290,7 @@
 		switch (idprom->id_machtype) {
 
 		case (SM_SUN4|SM_4_110):
-			sun4c_vacinfo.type = NONE;
+			sun4c_vacinfo.type = VAC_NONE;
 			sun4c_vacinfo.num_bytes = 0;
 			sun4c_vacinfo.linesize = 0;
 			sun4c_vacinfo.do_hwflushes = 0;
@@ -299,21 +299,21 @@
 			break;
 
 		case (SM_SUN4|SM_4_260):
-			sun4c_vacinfo.type = WRITE_BACK;
+			sun4c_vacinfo.type = VAC_WRITE_BACK;
 			sun4c_vacinfo.num_bytes = 128 * 1024;
 			sun4c_vacinfo.linesize = 16;
 			sun4c_vacinfo.do_hwflushes = 0;
 			break;
 
 		case (SM_SUN4|SM_4_330):
-			sun4c_vacinfo.type = WRITE_THROUGH;
+			sun4c_vacinfo.type = VAC_WRITE_THROUGH;
 			sun4c_vacinfo.num_bytes = 128 * 1024;
 			sun4c_vacinfo.linesize = 16;
 			sun4c_vacinfo.do_hwflushes = 0;
 			break;
 
 		case (SM_SUN4|SM_4_470):
-			sun4c_vacinfo.type = WRITE_BACK;
+			sun4c_vacinfo.type = VAC_WRITE_BACK;
 			sun4c_vacinfo.num_bytes = 128 * 1024;
 			sun4c_vacinfo.linesize = 32;
 			sun4c_vacinfo.do_hwflushes = 0;
@@ -324,7 +324,7 @@
 			prom_halt();
 		};
 	} else {
-		sun4c_vacinfo.type = WRITE_THROUGH;
+		sun4c_vacinfo.type = VAC_WRITE_THROUGH;
 
 		if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
 		    (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
@@ -386,7 +386,7 @@
 		daddr = &(dst);		\
 		iaddr = &(src);		\
 		*daddr = *iaddr;	\
-	} while (0);
+	} while (0)
 
 static void __init patch_kernel_fault_handler(void)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc/prom/printf.c linux-2.4.21-pre6/arch/sparc/prom/printf.c
--- linux-2.4.20/arch/sparc/prom/printf.c	2000-02-09 02:23:13.000000000 +0000
+++ linux-2.4.21-pre6/arch/sparc/prom/printf.c	2003-03-26 23:49:07.000000000 +0000
@@ -1,11 +1,15 @@
-/* $Id: printf.c,v 1.7 2000/02/08 20:24:23 davem Exp $
+/*
  * printf.c:  Internal prom library printf facility.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-
-/* This routine is internal to the prom library, no one else should know
- * about or use it!  It's simple and smelly anyway....
+ * Copyright (c) 2002 Pete Zaitcev (zaitcev@yahoo.com)
+ *
+ * We used to warn all over the code: DO NOT USE prom_printf(),
+ * and yet people do. Anton's banking code was outputing banks
+ * with prom_printf for most of the 2.4 lifetime. Since an effective
+ * stick is not available, we deployed a carrot: an early printk
+ * through PROM by means of -p boot option. This ought to fix it.
+ * USE printk; if you need, deploy -p.
  */
 
 #include <linux/kernel.h>
@@ -16,23 +20,27 @@
 static char ppbuf[1024];
 
 void
+prom_write(const char *buf, unsigned int n)
+{
+	char ch;
+
+	while (n != 0) {
+		--n;
+		if ((ch = *buf++) == '\n')
+			prom_putchar('\r');
+		prom_putchar(ch);
+	}
+}
+
+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);
-	}
+	i = vsnprintf(ppbuf, sizeof(ppbuf), fmt, args);
 	va_end(args);
-	return;
+
+	prom_write(ppbuf, i);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/Makefile linux-2.4.21-pre6/arch/sparc64/Makefile
--- linux-2.4.20/arch/sparc64/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/sparc64/Makefile	2003-03-26 23:49:55.000000000 +0000
@@ -17,6 +17,7 @@
 NEW_GCC := $(shell if $(CC) -m64 -mcmodel=medlow -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo y; else echo n; fi; )
 NEW_GAS := $(shell if $(LD) -V 2>&1 | grep 'elf64_sparc' > /dev/null; then echo y; else echo n; fi)
 UNDECLARED_REGS := $(shell if $(CC) -c -x assembler /dev/null -Wa,--help | grep undeclared-regs > /dev/null; then echo y; else echo n; fi; )
+INLINE_LIMIT := $(shell if $(CC) -m64 -finline-limit=100000 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo y; else echo n; fi; )
 
 export NEW_GCC
 
@@ -48,6 +49,10 @@
   AFLAGS += -m64 -mcpu=ultrasparc $(CC_UNDECL)
 endif
 
+ifeq ($(INLINE_LIMIT),y)
+  CFLAGS := $(CFLAGS) -finline-limit=100000
+endif
+
 ifeq ($(CONFIG_MCOUNT),y)
   CFLAGS := $(subst -fomit-frame-pointer,,$(CFLAGS))
   CFLAGS := $(CFLAGS) -pg
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/defconfig linux-2.4.21-pre6/arch/sparc64/defconfig
--- linux-2.4.20/arch/sparc64/defconfig	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/sparc64/defconfig	2003-03-26 23:49:25.000000000 +0000
@@ -269,15 +269,6 @@
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
 # CONFIG_IDEDISK_STROKE is not set
-# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
-# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
-# CONFIG_BLK_DEV_IDEDISK_IBM is not set
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
 # CONFIG_BLK_DEV_IDECS is not set
 CONFIG_BLK_DEV_IDECD=y
 CONFIG_BLK_DEV_IDETAPE=m
@@ -291,8 +282,8 @@
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
 CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_BLK_DEV_GENERIC=y
 # CONFIG_IDEPCI_SHARE_IRQ is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
@@ -301,40 +292,45 @@
 # CONFIG_IDEDMA_ONLYDISK is not set
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_PCI_WIP is not set
-# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set
-# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
 CONFIG_BLK_DEV_ADMA=y
-# CONFIG_BLK_DEV_AEC62XX is not set
-# CONFIG_AEC62XX_TUNING is not set
+CONFIG_BLK_DEV_AEC62XX=m
 CONFIG_BLK_DEV_ALI15X3=y
 # CONFIG_WDC_ALI15X3 is not set
-# CONFIG_BLK_DEV_AMD74XX is not set
+CONFIG_BLK_DEV_AMD74XX=m
 # CONFIG_AMD74XX_OVERRIDE is not set
 CONFIG_BLK_DEV_CMD64X=y
-# CONFIG_BLK_DEV_CMD680 is not set
-# CONFIG_BLK_DEV_CY82C693 is not set
-# CONFIG_BLK_DEV_CS5530 is not set
-# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+CONFIG_BLK_DEV_CY82C693=m
+CONFIG_BLK_DEV_CS5530=m
+CONFIG_BLK_DEV_HPT34X=m
 # CONFIG_HPT34X_AUTODMA is not set
-# CONFIG_BLK_DEV_HPT366 is not set
+CONFIG_BLK_DEV_HPT366=m
+CONFIG_BLK_DEV_PIIX=m
+CONFIG_BLK_DEV_NFORCE=m
 CONFIG_BLK_DEV_NS87415=y
-# CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_PDC202XX is not set
+CONFIG_BLK_DEV_OPTI621=m
+CONFIG_BLK_DEV_PDC202XX_OLD=m
 # CONFIG_PDC202XX_BURST is not set
+CONFIG_BLK_DEV_PDC202XX_NEW=m
 # CONFIG_PDC202XX_FORCE is not set
-# CONFIG_BLK_DEV_SVWKS is not set
-# CONFIG_BLK_DEV_SIS5513 is not set
-# CONFIG_BLK_DEV_SLC90E66 is not set
-# CONFIG_BLK_DEV_TRM290 is not set
-# CONFIG_BLK_DEV_VIA82CXXX is not set
+CONFIG_BLK_DEV_RZ1000=m
+CONFIG_BLK_DEV_SC1200=m
+CONFIG_BLK_DEV_SVWKS=m
+CONFIG_BLK_DEV_SIIMAGE=m
+CONFIG_BLK_DEV_SIS5513=m
+CONFIG_BLK_DEV_SLC90E66=m
+CONFIG_BLK_DEV_TRM290=m
+CONFIG_BLK_DEV_VIA82CXXX=m
 # CONFIG_IDE_CHIPSETS is not set
 CONFIG_IDEDMA_AUTO=y
 # CONFIG_IDEDMA_IVB is not set
 # CONFIG_DMA_NONPCI is not set
+CONFIG_BLK_DEV_PDC202XX=y
 CONFIG_BLK_DEV_IDE_MODES=y
 CONFIG_BLK_DEV_ATARAID=m
 CONFIG_BLK_DEV_ATARAID_PDC=m
 CONFIG_BLK_DEV_ATARAID_HPT=m
+# CONFIG_BLK_DEV_ATARAID_SII is not set
 
 #
 # SCSI support
@@ -405,6 +401,7 @@
 #
 CONFIG_FUSION=m
 # CONFIG_FUSION_BOOT is not set
+CONFIG_FUSION_MAX_SGE=40
 CONFIG_FUSION_ISENSE=m
 CONFIG_FUSION_CTL=m
 CONFIG_FUSION_LAN=m
@@ -466,6 +463,7 @@
 # CONFIG_ELMC is not set
 # CONFIG_ELMC_II is not set
 CONFIG_VORTEX=m
+CONFIG_TYPHOON=m
 # CONFIG_LANCE is not set
 # CONFIG_NET_VENDOR_SMC is not set
 # CONFIG_NET_VENDOR_RACAL is not set
@@ -473,6 +471,7 @@
 # CONFIG_NET_ISA is not set
 CONFIG_NET_PCI=y
 CONFIG_PCNET32=m
+# CONFIG_AMD8111_ETH is not set
 CONFIG_ADAPTEC_STARFIRE=m
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
@@ -483,6 +482,7 @@
 CONFIG_DGRS=m
 # CONFIG_DM9102 is not set
 CONFIG_EEPRO100=m
+# CONFIG_EEPRO100_PIO is not set
 CONFIG_E100=m
 # CONFIG_LNE390 is not set
 CONFIG_FEALNX=m
@@ -518,6 +518,7 @@
 CONFIG_NS83820=m
 # CONFIG_HAMACHI is not set
 CONFIG_YELLOWFIN=m
+# CONFIG_R8169 is not set
 CONFIG_SK98LIN=m
 CONFIG_TIGON3=m
 CONFIG_FDDI=y
@@ -760,7 +761,6 @@
 #
 CONFIG_USB_DEVICEFS=y
 # CONFIG_USB_BANDWIDTH is not set
-# CONFIG_USB_LONG_TIMEOUT is not set
 
 #
 # USB Host Controller Drivers
@@ -775,7 +775,10 @@
 #
 # CONFIG_USB_AUDIO is not set
 # CONFIG_USB_EMI26 is not set
-CONFIG_USB_BLUETOOTH=m
+
+#
+#   USB Bluetooth can only be used with disabled Bluetooth subsystem
+#
 CONFIG_USB_MIDI=m
 CONFIG_USB_STORAGE=m
 # CONFIG_USB_STORAGE_DEBUG is not set
@@ -798,6 +801,7 @@
 # CONFIG_USB_HIDDEV is not set
 CONFIG_USB_AIPTEK=m
 CONFIG_USB_WACOM=m
+CONFIG_USB_POWERMATE=m
 
 #
 # USB Imaging devices
@@ -812,6 +816,7 @@
 # USB Multimedia devices
 #
 CONFIG_USB_IBMCAM=m
+CONFIG_USB_KONICAWC=m
 CONFIG_USB_OV511=m
 CONFIG_USB_PWC=m
 CONFIG_USB_SE401=m
@@ -865,6 +870,7 @@
 # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
 CONFIG_USB_SERIAL_MCT_U232=m
 CONFIG_USB_SERIAL_KLSI=m
+CONFIG_USB_SERIAL_KOBIL_SCT=m
 CONFIG_USB_SERIAL_PL2303=m
 CONFIG_USB_SERIAL_CYBERJACK=m
 CONFIG_USB_SERIAL_XIRCOM=m
@@ -885,9 +891,11 @@
 CONFIG_BLUEZ=m
 CONFIG_BLUEZ_L2CAP=m
 CONFIG_BLUEZ_SCO=m
+CONFIG_BLUEZ_RFCOMM=m
+CONFIG_BLUEZ_RFCOMM_TTY=y
 CONFIG_BLUEZ_BNEP=m
-CONFIG_BNEP_MC_FILTER=y
-CONFIG_BNEP_PROTO_FILTER=y
+CONFIG_BLUEZ_BNEP_MC_FILTER=y
+CONFIG_BLUEZ_BNEP_PROTO_FILTER=y
 
 #
 # Bluetooth device drivers
@@ -896,9 +904,12 @@
 CONFIG_BLUEZ_USB_ZERO_PACKET=y
 CONFIG_BLUEZ_HCIUART=m
 CONFIG_BLUEZ_HCIUART_H4=y
+CONFIG_BLUEZ_HCIUART_BCSP=y
+CONFIG_BLUEZ_HCIUART_BCSP_TXCRC=y
 # CONFIG_BLUEZ_HCIDTL1 is not set
 # CONFIG_BLUEZ_HCIBT3C is not set
 # CONFIG_BLUEZ_HCIBLUECARD is not set
+# CONFIG_BLUEZ_HCIBTUART is not set
 CONFIG_BLUEZ_HCIVHCI=m
 
 #
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/kernel/Makefile linux-2.4.21-pre6/arch/sparc64/kernel/Makefile
--- linux-2.4.20/arch/sparc64/kernel/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/sparc64/kernel/Makefile	2003-03-26 23:49:10.000000000 +0000
@@ -54,9 +54,12 @@
 	fi
 	@echo "/* Automatically generated. Do not edit. */" > asm_offsets.h
 	@echo "#ifndef __ASM_OFFSETS_H__" >> asm_offsets.h
-	@echo -e "#define __ASM_OFFSETS_H__\n" >> asm_offsets.h
-	@echo -e "#include <linux/config.h>\n" >> asm_offsets.h
-	@echo -e "#ifndef CONFIG_SMP\n" >> asm_offsets.h
+	@echo "#define __ASM_OFFSETS_H__" >> asm_offsets.h
+	@echo >> asm_offsets.h
+	@echo "#include <linux/config.h>" >> asm_offsets.h
+	@echo >> asm_offsets.h
+	@echo "#ifndef CONFIG_SMP" >> asm_offsets.h
+	@echo >> asm_offsets.h
 	@echo "#include <linux/config.h>" > tmp.c
 	@echo "#undef CONFIG_SMP" >> tmp.c
 	@echo "#include <linux/sched.h>" >> tmp.c
@@ -86,8 +89,10 @@
 	$(HOSTCC) -o check_asm check_asm.c
 	./check_asm >> asm_offsets.h
 	@rm -f check_asm check_asm.c
-	@echo -e "\n#else /* CONFIG_SMP */\n" >> asm_offsets.h
-	@echo -e "#ifndef CONFIG_DEBUG_SPINLOCK\n" >>asm_offsets.h
+	@echo >> asm_offsets.h
+	@echo "#else /* CONFIG_SMP */" >> asm_offsets.h
+	@echo "#ifndef CONFIG_DEBUG_SPINLOCK" >>asm_offsets.h
+	@echo >> asm_offsets.h
 	@echo "#include <linux/config.h>" > tmp.c
 	@echo "#undef CONFIG_SMP" >> tmp.c
 	@echo "#define CONFIG_SMP 1" >> tmp.c
@@ -119,7 +124,9 @@
 	$(HOSTCC) -o check_asm check_asm.c
 	./check_asm >> asm_offsets.h
 	@rm -f check_asm check_asm.c
-	@echo -e "\n#else /* CONFIG_DEBUG_SPINLOCK */\n" >> asm_offsets.h
+	@echo >> asm_offsets.h
+	@echo "#else /* CONFIG_DEBUG_SPINLOCK */" >> asm_offsets.h
+	@echo >> asm_offsets.h
 	@echo "#include <linux/sched.h>" > tmp.c
 	$(CPP) $(CPPFLAGS) -P -DCONFIG_DEBUG_SPINLOCK tmp.c -o tmp.i
 	@echo "/* Automatically generated. Do not edit. */" > check_asm_data.c
@@ -148,8 +155,10 @@
 	$(HOSTCC) -o check_asm check_asm.c
 	./check_asm >> asm_offsets.h
 	@rm -f check_asm check_asm.c
-	@echo -e "#endif /* CONFIG_DEBUG_SPINLOCK */\n" >> asm_offsets.h
-	@echo -e "#endif /* CONFIG_SMP */\n" >> asm_offsets.h
+	@echo "#endif /* CONFIG_DEBUG_SPINLOCK */" >> asm_offsets.h
+	@echo >> asm_offsets.h
+	@echo "#endif /* CONFIG_SMP */" >> asm_offsets.h
+	@echo >> asm_offsets.h
 	@echo "#endif /* __ASM_OFFSETS_H__ */" >> asm_offsets.h
 	@if test -r $(HPATH)/asm/asm_offsets.h; then \
 	  if cmp -s asm_offsets.h $(HPATH)/asm/asm_offsets.h; then \
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/kernel/entry.S linux-2.4.21-pre6/arch/sparc64/kernel/entry.S
--- linux-2.4.20/arch/sparc64/kernel/entry.S	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/sparc64/kernel/entry.S	2003-03-26 23:48:57.000000000 +0000
@@ -1843,7 +1843,7 @@
 	sub	%o1, %g7, %o1
 	mulx	%o3, %o1, %o1
 	brz,pt	%o2, 1f
-	 srlx	%o1, 32, %o1
+	 srlx	%o1, 30, %o1
 	sethi	%hi(10000), %g2
 	or	%g2, %lo(10000), %g2
 	add	%o1, %g2, %o1
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/kernel/head.S linux-2.4.21-pre6/arch/sparc64/kernel/head.S
--- linux-2.4.20/arch/sparc64/kernel/head.S	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/sparc64/kernel/head.S	2003-03-26 23:49:29.000000000 +0000
@@ -673,7 +673,9 @@
 #endif
 
 	/* Kill PROM timer */
-	wr	%g0, 0, %tick_cmpr
+	sethi	%hi(0x80000000), %g1
+	sllx	%g1, 32, %g1
+	wr	%g1, 0, %tick_cmpr
 
 	BRANCH_IF_ANY_CHEETAH(g1,g5,1f)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/kernel/ioctl32.c linux-2.4.21-pre6/arch/sparc64/kernel/ioctl32.c
--- linux-2.4.20/arch/sparc64/kernel/ioctl32.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/sparc64/kernel/ioctl32.c	2003-03-26 23:49:54.000000000 +0000
@@ -37,6 +37,7 @@
 #include <linux/cdrom.h>
 #include <linux/loop.h>
 #include <linux/auto_fs.h>
+#include <linux/auto_fs4.h>
 #include <linux/devfs_fs.h>
 #include <linux/tty.h>
 #include <linux/vt_kern.h>
@@ -95,9 +96,11 @@
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci.h>
+#include <net/bluetooth/rfcomm.h>
 
 #include <linux/usb.h>
 #include <linux/usbdevice_fs.h>
+#include <linux/usb_scanner_ioctl.h>
 #include <linux/nbd.h>
 #include <linux/random.h>
 #include <linux/filter.h>
@@ -3217,6 +3220,175 @@
 }
 #endif
 
+#if defined(CONFIG_IEEE1394) || defined(CONFIG_IEEE1394_MODULE)
+#include "../../../drivers/ieee1394/ieee1394-ioctl.h"
+#include "../../../drivers/ieee1394/amdtp.h"
+#include "../../../drivers/ieee1394/dv1394.h"
+#include "../../../drivers/ieee1394/video1394.h"
+
+#define DV1394_IOC32_INIT	_IOW('#', 0x06, struct dv1394_init32)
+#define DV1394_IOC32_GET_STATUS	_IOR('#', 0x0c, struct dv1394_status32)
+
+struct dv1394_init32 {
+	u32 api_version;
+	u32 channel;
+	u32 n_frames;
+	u32 format;
+	u32 cip_n;
+	u32 cip_d;
+	u32 syt_offset;
+};
+
+struct dv1394_status32 {
+	struct dv1394_init32 init;
+	s32 active_frame;
+	u32 first_clear_frame;
+	u32 n_clear_frames;
+	u32 dropped_frames;
+};
+
+static int handle_dv1394_init(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct dv1394_init32 dv32;
+	struct dv1394_init dv;
+	mm_segment_t old_fs;
+	int ret;
+
+	if (copy_from_user(&dv32, (void *)arg, sizeof(dv32)))
+		return -EFAULT;
+
+	dv.api_version = dv32.api_version;
+	dv.channel = dv32.channel;
+	dv.n_frames = dv32.n_frames;
+	dv.format = dv32.format;
+	dv.cip_n = (unsigned long)dv32.cip_n;
+	dv.cip_d = (unsigned long)dv32.cip_d;
+	dv.syt_offset = dv32.syt_offset;
+
+        old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_ioctl(fd, DV1394_IOC_INIT, (unsigned long) &dv);
+	set_fs(old_fs);
+
+	return ret;
+}
+
+static int handle_dv1394_get_status(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct dv1394_status32 dv32;
+	struct dv1394_status dv;
+	mm_segment_t old_fs;
+	int ret;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_ioctl(fd, DV1394_IOC_GET_STATUS, (unsigned long) &dv);
+	set_fs(old_fs);
+
+	if (!ret) {
+		dv32.init.api_version = dv.init.api_version;
+		dv32.init.channel = dv.init.channel;
+		dv32.init.n_frames = dv.init.n_frames;
+		dv32.init.format = dv.init.format;
+		dv32.init.cip_n = (u32)dv.init.cip_n;
+		dv32.init.cip_d = (u32)dv.init.cip_d;
+		dv32.init.syt_offset = dv.init.syt_offset;
+		dv32.active_frame = dv.active_frame;
+		dv32.first_clear_frame = dv.first_clear_frame;
+		dv32.n_clear_frames = dv.n_clear_frames;
+		dv32.dropped_frames = dv.dropped_frames;
+
+		if (copy_to_user((struct dv1394_status32 *)arg, &dv32, sizeof(dv32)))
+			ret = -EFAULT;
+	}
+
+	return ret;
+}
+
+#define VIDEO1394_IOC32_LISTEN_QUEUE_BUFFER	\
+	_IOW ('#', 0x12, struct video1394_wait32)
+#define VIDEO1394_IOC32_LISTEN_WAIT_BUFFER	\
+	_IOWR('#', 0x13, struct video1394_wait32)
+#define VIDEO1394_IOC32_TALK_WAIT_BUFFER	\
+        _IOW ('#', 0x17, struct video1394_wait32)
+#define VIDEO1394_IOC32_LISTEN_POLL_BUFFER	\
+        _IOWR('#', 0x18, struct video1394_wait32)
+
+struct video1394_wait32 {
+	u32 channel;
+	u32 buffer;
+        struct timeval32 filltime;
+};
+
+static int video1394_wr_wait32(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct video1394_wait32 wait32;
+	struct video1394_wait wait;
+	mm_segment_t old_fs;
+	int ret;
+
+	if (copy_from_user(&wait32, (void *)arg, sizeof(wait32)))
+		return -EFAULT;
+
+	wait.channel = wait32.channel;
+	wait.buffer = wait32.buffer;
+	wait.filltime.tv_sec = (time_t)wait32.filltime.tv_sec;
+	wait.filltime.tv_usec = (suseconds_t)wait32.filltime.tv_usec;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	if (cmd == VIDEO1394_IOC32_LISTEN_WAIT_BUFFER)
+		ret = sys_ioctl(fd, VIDEO1394_IOC_LISTEN_WAIT_BUFFER, (unsigned long) &wait);
+	else
+		ret = sys_ioctl(fd, VIDEO1394_IOC_LISTEN_POLL_BUFFER, (unsigned long) &wait);
+	set_fs(old_fs);
+
+	if (!ret) {
+		wait32.channel = wait.channel;
+		wait32.buffer = wait.buffer;
+		wait32.filltime.tv_sec = (int)wait.filltime.tv_sec;
+		wait32.filltime.tv_usec = (int)wait.filltime.tv_usec;
+
+		if (copy_to_user((struct video1394_wait32 *)arg, &wait32, sizeof(wait32)))
+			ret = -EFAULT;
+	}
+
+	return ret;
+}
+
+static int video1394_w_wait32(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct video1394_wait32 wait32;
+	struct video1394_wait wait;
+	mm_segment_t old_fs;
+	int ret;
+
+	if (copy_from_user(&wait32, (void *)arg, sizeof(wait32)))
+		return -EFAULT;
+
+	wait.channel = wait32.channel;
+	wait.buffer = wait32.buffer;
+	wait.filltime.tv_sec = (time_t)wait32.filltime.tv_sec;
+	wait.filltime.tv_usec = (suseconds_t)wait32.filltime.tv_usec;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	if (cmd == VIDEO1394_IOC32_LISTEN_QUEUE_BUFFER)
+		ret = sys_ioctl(fd, VIDEO1394_IOC_LISTEN_QUEUE_BUFFER, (unsigned long) &wait);
+	else
+		ret = sys_ioctl(fd, VIDEO1394_IOC_TALK_WAIT_BUFFER, (unsigned long) &wait);
+	set_fs(old_fs);
+
+	return ret;
+}
+
+static int video1394_queue_buf32(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	return -EFAULT;
+}
+
+#endif /* CONFIG_IEEE1394 */
+
 #if defined(CONFIG_DRM_NEW) || defined(CONFIG_DRM_NEW_MODULE)
 /* This really belongs in include/linux/drm.h -DaveM */
 #include "../../../drivers/char/drm/drm.h"
@@ -4286,6 +4458,15 @@
 	return sys_ioctl(fd, BLKGETSIZE64, arg);
 }
 
+/* Bluetooth ioctls */
+#define HCIUARTSETPROTO	_IOW('U', 200, int)
+#define HCIUARTGETPROTO	_IOR('U', 201, int)
+
+#define BNEPCONNADD	_IOW('B', 200, int)
+#define BNEPCONNDEL	_IOW('B', 201, int)
+#define BNEPGETCONNLIST	_IOR('B', 210, int)
+#define BNEPGETCONNINFO	_IOR('B', 211, int)
+
 struct ioctl_trans {
 	unsigned int cmd;
 	unsigned int handler;
@@ -4307,6 +4488,7 @@
 COMPATIBLE_IOCTL(TCSETAW)
 COMPATIBLE_IOCTL(TCSETAF)
 COMPATIBLE_IOCTL(TCSBRK)
+COMPATIBLE_IOCTL(TCSBRKP)
 COMPATIBLE_IOCTL(TCXONC)
 COMPATIBLE_IOCTL(TCFLSH)
 COMPATIBLE_IOCTL(TCGETS)
@@ -4870,6 +5052,7 @@
 COMPATIBLE_IOCTL(AUTOFS_IOC_CATATONIC)
 COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOVER)
 COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE)
+COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE_MULTI)
 /* DEVFS */
 COMPATIBLE_IOCTL(DEVFSDIOC_GET_PROTO_REV)
 COMPATIBLE_IOCTL(DEVFSDIOC_SET_EVENT_MASK)
@@ -4987,6 +5170,21 @@
 COMPATIBLE_IOCTL(HCISETACLMTU)
 COMPATIBLE_IOCTL(HCISETSCOMTU)
 COMPATIBLE_IOCTL(HCIINQUIRY)
+COMPATIBLE_IOCTL(HCIUARTSETPROTO)
+COMPATIBLE_IOCTL(HCIUARTGETPROTO)
+COMPATIBLE_IOCTL(RFCOMMCREATEDEV)
+COMPATIBLE_IOCTL(RFCOMMRELEASEDEV)
+COMPATIBLE_IOCTL(RFCOMMGETDEVLIST)
+COMPATIBLE_IOCTL(RFCOMMGETDEVINFO)
+COMPATIBLE_IOCTL(RFCOMMSTEALDLC)
+COMPATIBLE_IOCTL(BNEPCONNADD)
+COMPATIBLE_IOCTL(BNEPCONNDEL)
+COMPATIBLE_IOCTL(BNEPGETCONNLIST)
+COMPATIBLE_IOCTL(BNEPGETCONNINFO)
+/* Scanner */
+COMPATIBLE_IOCTL(SCANNER_IOCTL_VENDOR)
+COMPATIBLE_IOCTL(SCANNER_IOCTL_PRODUCT)
+COMPATIBLE_IOCTL(SCANNER_IOCTL_CTRLMSG)
 /* Misc. */
 COMPATIBLE_IOCTL(0x41545900)		/* ATYIO_CLKR */
 COMPATIBLE_IOCTL(0x41545901)		/* ATYIO_CLKW */
@@ -5023,7 +5221,33 @@
 COMPATIBLE_IOCTL(NBD_PRINT_DEBUG)
 COMPATIBLE_IOCTL(NBD_SET_SIZE_BLOCKS)
 COMPATIBLE_IOCTL(NBD_DISCONNECT)
+/* Linux-1394 */
+#if defined(CONFIG_IEEE1394) || defined(CONFIG_IEEE1394_MODULE)
+COMPATIBLE_IOCTL(AMDTP_IOC_CHANNEL)
+COMPATIBLE_IOCTL(AMDTP_IOC_PLUG)
+COMPATIBLE_IOCTL(AMDTP_IOC_PING)
+COMPATIBLE_IOCTL(AMDTP_IOC_ZAP)
+COMPATIBLE_IOCTL(DV1394_IOC_SHUTDOWN)
+COMPATIBLE_IOCTL(DV1394_IOC_SUBMIT_FRAMES)
+COMPATIBLE_IOCTL(DV1394_IOC_WAIT_FRAMES)
+COMPATIBLE_IOCTL(DV1394_IOC_RECEIVE_FRAMES)
+COMPATIBLE_IOCTL(DV1394_IOC_START_RECEIVE)
+COMPATIBLE_IOCTL(VIDEO1394_IOC_LISTEN_CHANNEL)
+COMPATIBLE_IOCTL(VIDEO1394_IOC_UNLISTEN_CHANNEL)
+COMPATIBLE_IOCTL(VIDEO1394_IOC_TALK_CHANNEL)
+COMPATIBLE_IOCTL(VIDEO1394_IOC_UNTALK_CHANNEL)
+#endif
+
 /* And these ioctls need translation */
+#if defined(CONFIG_IEEE1394) || defined(CONFIG_IEEE1394_MODULE)
+HANDLE_IOCTL(DV1394_IOC32_INIT, handle_dv1394_init)
+HANDLE_IOCTL(DV1394_IOC32_GET_STATUS, handle_dv1394_get_status)
+HANDLE_IOCTL(VIDEO1394_IOC32_LISTEN_QUEUE_BUFFER, video1394_w_wait32)
+HANDLE_IOCTL(VIDEO1394_IOC32_LISTEN_WAIT_BUFFER, video1394_wr_wait32)
+HANDLE_IOCTL(VIDEO1394_IOC_TALK_QUEUE_BUFFER, video1394_queue_buf32)
+HANDLE_IOCTL(VIDEO1394_IOC32_TALK_WAIT_BUFFER, video1394_w_wait32)
+HANDLE_IOCTL(VIDEO1394_IOC32_LISTEN_POLL_BUFFER, video1394_wr_wait32)
+#endif
 HANDLE_IOCTL(MEMREADOOB32, mtd_rw_oob)
 HANDLE_IOCTL(MEMWRITEOOB32, mtd_rw_oob)
 #ifdef CONFIG_NET
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/kernel/irq.c linux-2.4.21-pre6/arch/sparc64/kernel/irq.c
--- linux-2.4.20/arch/sparc64/kernel/irq.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/sparc64/kernel/irq.c	2003-03-26 23:49:29.000000000 +0000
@@ -803,12 +803,8 @@
 	 */
 	{
 		unsigned long clr_mask = 1 << irq;
-		unsigned long tick_mask;
+		unsigned long tick_mask = tick_ops->softint_mask;
 
-		if (SPARC64_USE_STICK)
-			tick_mask = (1UL << 16);
-		else
-			tick_mask = (1UL << 0);
 		if ((irq == 14) && (get_softint() & tick_mask)) {
 			irq = 0;
 			clr_mask = tick_mask;
@@ -1025,113 +1021,6 @@
 	return 0;
 }
 
-/* This is gets the master TICK_INT timer going. */
-void init_timers(void (*cfunc)(int, void *, struct pt_regs *),
-		 unsigned long *clock)
-{
-	unsigned long pstate;
-	extern unsigned long timer_tick_offset;
-	int node, err;
-#ifdef CONFIG_SMP
-	extern void smp_tick_init(void);
-#endif
-
-	if (!SPARC64_USE_STICK) {
-		node = linux_cpus[0].prom_node;
-		*clock = prom_getint(node, "clock-frequency");
-	} else {
-		node = prom_root_node;
-		*clock = prom_getint(node, "stick-frequency");
-	}
-	timer_tick_offset = *clock / HZ;
-#ifdef CONFIG_SMP
-	smp_tick_init();
-#endif
-
-	/* Register IRQ handler. */
-	err = request_irq(build_irq(0, 0, 0UL, 0UL), cfunc, SA_STATIC_ALLOC,
-			  "timer", NULL);
-
-	if(err) {
-		prom_printf("Serious problem, cannot register TICK_INT\n");
-		prom_halt();
-	}
-
-	/* Guarentee that the following sequences execute
-	 * uninterrupted.
-	 */
-	__asm__ __volatile__("rdpr	%%pstate, %0\n\t"
-			     "wrpr	%0, %1, %%pstate"
-			     : "=r" (pstate)
-			     : "i" (PSTATE_IE));
-
-	/* Set things up so user can access tick register for profiling
-	 * purposes.  Also workaround BB_ERRATA_1 by doing a dummy
-	 * read back of %tick after writing it.
-	 */
-	__asm__ __volatile__(
-	"	sethi	%%hi(0x80000000), %%g1\n"
-	"	ba,pt	%%xcc, 1f\n"
-	"	 sllx	%%g1, 32, %%g1\n"
-	"	.align	64\n"
-	"1:	rd	%%tick, %%g2\n"
-	"	add	%%g2, 6, %%g2\n"
-	"	andn	%%g2, %%g1, %%g2\n"
-	"	wrpr	%%g2, 0, %%tick\n"
-	"	rdpr	%%tick, %%g0"
-	: /* no outputs */
-	: /* no inputs */
-	: "g1", "g2");
-
-	/* Workaround for Spitfire Errata (#54 I think??), I discovered
-	 * this via Sun BugID 4008234, mentioned in Solaris-2.5.1 patch
-	 * number 103640.
-	 *
-	 * On Blackbird writes to %tick_cmpr can fail, the
-	 * workaround seems to be to execute the wr instruction
-	 * at the start of an I-cache line, and perform a dummy
-	 * read back from %tick_cmpr right after writing to it. -DaveM
-	 */
-	if (!SPARC64_USE_STICK) {
-	__asm__ __volatile__(
-	"	rd	%%tick, %%g1\n"
-	"	ba,pt	%%xcc, 1f\n"
-	"	 add	%%g1, %0, %%g1\n"
-	"	.align	64\n"
-	"1:	wr	%%g1, 0x0, %%tick_cmpr\n"
-	"	rd	%%tick_cmpr, %%g0"
-	: /* no outputs */
-	: "r" (timer_tick_offset)
-	: "g1");
-	} else {
-	/* Let the user get at STICK too. */
-	__asm__ __volatile__(
-	"	sethi	%%hi(0x80000000), %%g1\n"
-	"	sllx	%%g1, 32, %%g1\n"
-	"	rd	%%asr24, %%g2\n"
-	"	andn	%%g2, %%g1, %%g2\n"
-	"	wr	%%g2, 0, %%asr24"
-	: /* no outputs */
-	: /* no inputs */
-	: "g1", "g2");
-
-	__asm__ __volatile__(
-	"	rd	%%asr24, %%g1\n"
-	"	add	%%g1, %0, %%g1\n"
-	"	wr	%%g1, 0x0, %%asr25"
-	: /* no outputs */
-	: "r" (timer_tick_offset)
-	: "g1");
-	}
-
-	/* Restore PSTATE_IE. */
-	__asm__ __volatile__("wrpr	%0, 0x0, %%pstate"
-			     : /* no outputs */
-			     : "r" (pstate));
-
-	sti();
-}
-
 #ifdef CONFIG_SMP
 static int retarget_one_irq(struct irqaction *p, int goal_cpu)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/kernel/process.c linux-2.4.21-pre6/arch/sparc64/kernel/process.c
--- linux-2.4.20/arch/sparc64/kernel/process.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/sparc64/kernel/process.c	2003-03-26 23:49:34.000000000 +0000
@@ -673,7 +673,7 @@
  * a system call from a "real" process, but the process memory space will
  * not be free'd until both the parent and the child have exited.
  */
-pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+pid_t arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 {
 	long retval;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/kernel/signal.c linux-2.4.21-pre6/arch/sparc64/kernel/signal.c
--- linux-2.4.20/arch/sparc64/kernel/signal.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/sparc64/kernel/signal.c	2003-03-26 23:48:58.000000000 +0000
@@ -219,7 +219,7 @@
 	err |= __put_user(regs->u_regs[UREG_G4], &((*grp)[MC_G4]));
 	err |= __put_user(regs->u_regs[UREG_G5], &((*grp)[MC_G5]));
 	err |= __put_user(regs->u_regs[UREG_G6], &((*grp)[MC_G6]));
-	err |= __put_user(regs->u_regs[UREG_G6], &((*grp)[MC_G7]));
+	err |= __put_user(regs->u_regs[UREG_G7], &((*grp)[MC_G7]));
 	err |= __put_user(regs->u_regs[UREG_I0], &((*grp)[MC_O0]));
 	err |= __put_user(regs->u_regs[UREG_I1], &((*grp)[MC_O1]));
 	err |= __put_user(regs->u_regs[UREG_I2], &((*grp)[MC_O2]));
@@ -438,8 +438,8 @@
 	err |= copy_from_user(regs->u_regs, sf->regs.u_regs, sizeof(regs->u_regs));
 
 	/* User can only change condition codes in %tstate. */
-	regs->tstate &= ~(TSTATE_ICC);
-	regs->tstate |= (tstate & TSTATE_ICC);
+	regs->tstate &= ~(TSTATE_ICC | TSTATE_XCC);
+	regs->tstate |= (tstate & (TSTATE_ICC | TSTATE_XCC));
 
 	err |= __get_user(fpu_save, &sf->fpu_save);
 	if (fpu_save)
@@ -783,7 +783,7 @@
 			if (current->pid == 1)
 				continue;
 			switch (signr) {
-			case SIGCONT: case SIGCHLD: case SIGWINCH:
+			case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG:
 				continue;
 
 			case SIGTSTP: case SIGTTIN: case SIGTTOU:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/kernel/signal32.c linux-2.4.21-pre6/arch/sparc64/kernel/signal32.c
--- linux-2.4.20/arch/sparc64/kernel/signal32.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/sparc64/kernel/signal32.c	2003-03-26 23:48:57.000000000 +0000
@@ -1444,7 +1444,7 @@
 			if (current->pid == 1)
 				continue;
 			switch (signr) {
-			case SIGCONT: case SIGCHLD: case SIGWINCH:
+			case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG:
 				continue;
 
 			case SIGTSTP: case SIGTTIN: case SIGTTOU:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/kernel/smp.c linux-2.4.21-pre6/arch/sparc64/kernel/smp.c
--- linux-2.4.20/arch/sparc64/kernel/smp.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/sparc64/kernel/smp.c	2003-03-26 23:48:57.000000000 +0000
@@ -18,6 +18,7 @@
 #include <linux/fs.h>
 #include <linux/seq_file.h>
 #include <linux/cache.h>
+#include <linux/timer.h>
 
 #include <asm/head.h>
 #include <asm/ptrace.h>
@@ -137,7 +138,6 @@
 void __init smp_callin(void)
 {
 	int cpuid = hard_smp_processor_id();
-	unsigned long pstate;
 	extern int bigkernel;
 	extern unsigned long kern_locked_tte_data;
 
@@ -155,50 +155,6 @@
 
 	cpu_probe();
 
-	/* Guarentee that the following sequences execute
-	 * uninterrupted.
-	 */
-	__asm__ __volatile__("rdpr	%%pstate, %0\n\t"
-			     "wrpr	%0, %1, %%pstate"
-			     : "=r" (pstate)
-			     : "i" (PSTATE_IE));
-
-	/* Set things up so user can access tick register for profiling
-	 * purposes.  Also workaround BB_ERRATA_1 by doing a dummy
-	 * read back of %tick after writing it.
-	 */
-	__asm__ __volatile__(
-		"sethi	%%hi(0x80000000), %%g1\n\t"
-		"ba,pt	%%xcc, 1f\n\t"
-		"sllx	%%g1, 32, %%g1\n\t"
-		".align	64\n"
-	"1:	rd	%%tick, %%g2\n\t"
-		"add	%%g2, 6, %%g2\n\t"
-		"andn	%%g2, %%g1, %%g2\n\t"
-		"wrpr	%%g2, 0, %%tick\n\t"
-		"rdpr	%%tick, %%g0"
-	: /* no outputs */
-	: /* no inputs */
-	: "g1", "g2");
-
-	if (SPARC64_USE_STICK) {
-		/* Let the user get at STICK too. */
-		__asm__ __volatile__(
-			"sethi	%%hi(0x80000000), %%g1\n\t"
-			"sllx	%%g1, 32, %%g1\n\t"
-			"rd	%%asr24, %%g2\n\t"
-			"andn	%%g2, %%g1, %%g2\n\t"
-			"wr	%%g2, 0, %%asr24"
-		: /* no outputs */
-		: /* no inputs */
-		: "g1", "g2");
-	}
-
-	/* Restore PSTATE_IE. */
-	__asm__ __volatile__("wrpr	%0, 0x0, %%pstate"
-			     : /* no outputs */
-			     : "r" (pstate));
-
 	smp_setup_percpu_timer();
 
 	__sti();
@@ -242,6 +198,158 @@
 	panic("SMP bolixed\n");
 }
 
+static unsigned long current_tick_offset;
+
+/* This tick register synchronization scheme is taken entirely from
+ * the ia64 port, see arch/ia64/kernel/smpboot.c for details and credit.
+ *
+ * The only change I've made is to rework it so that the master
+ * initiates the synchonization instead of the slave. -DaveM
+ */
+
+#define MASTER	0
+#define SLAVE	(SMP_CACHE_BYTES/sizeof(unsigned long))
+
+#define NUM_ROUNDS	64	/* magic value */
+#define NUM_ITERS	5	/* likewise */
+
+static spinlock_t itc_sync_lock = SPIN_LOCK_UNLOCKED;
+static unsigned long go[SLAVE + 1];
+
+#define DEBUG_TICK_SYNC	0
+
+static inline long get_delta (long *rt, long *master)
+{
+	unsigned long best_t0 = 0, best_t1 = ~0UL, best_tm = 0;
+	unsigned long tcenter, t0, t1, tm;
+	unsigned long i;
+
+	for (i = 0; i < NUM_ITERS; i++) {
+		t0 = tick_ops->get_tick();
+		go[MASTER] = 1;
+		membar("#StoreLoad");
+		while (!(tm = go[SLAVE]))
+			membar("#LoadLoad");
+		go[SLAVE] = 0;
+		membar("#StoreStore");
+		t1 = tick_ops->get_tick();
+
+		if (t1 - t0 < best_t1 - best_t0)
+			best_t0 = t0, best_t1 = t1, best_tm = tm;
+	}
+
+	*rt = best_t1 - best_t0;
+	*master = best_tm - best_t0;
+
+	/* average best_t0 and best_t1 without overflow: */
+	tcenter = (best_t0/2 + best_t1/2);
+	if (best_t0 % 2 + best_t1 % 2 == 2)
+		tcenter++;
+	return tcenter - best_tm;
+}
+
+void smp_synchronize_tick_client(void)
+{
+	long i, delta, adj, adjust_latency = 0, done = 0;
+	unsigned long flags, rt, master_time_stamp, bound;
+#if DEBUG_TICK_SYNC
+	struct {
+		long rt;	/* roundtrip time */
+		long master;	/* master's timestamp */
+		long diff;	/* difference between midpoint and master's timestamp */
+		long lat;	/* estimate of itc adjustment latency */
+	} t[NUM_ROUNDS];
+#endif
+
+	go[MASTER] = 1;
+
+	while (go[MASTER])
+		membar("#LoadLoad");
+
+	local_irq_save(flags);
+	{
+		for (i = 0; i < NUM_ROUNDS; i++) {
+			delta = get_delta(&rt, &master_time_stamp);
+			if (delta == 0) {
+				done = 1;	/* let's lock on to this... */
+				bound = rt;
+			}
+
+			if (!done) {
+				if (i > 0) {
+					adjust_latency += -delta;
+					adj = -delta + adjust_latency/4;
+				} else
+					adj = -delta;
+
+				tick_ops->add_tick(adj, current_tick_offset);
+			}
+#if DEBUG_TICK_SYNC
+			t[i].rt = rt;
+			t[i].master = master_time_stamp;
+			t[i].diff = delta;
+			t[i].lat = adjust_latency/4;
+#endif
+		}
+	}
+	local_irq_restore(flags);
+
+#if DEBUG_TICK_SYNC
+	for (i = 0; i < NUM_ROUNDS; i++)
+		printk("rt=%5ld master=%5ld diff=%5ld adjlat=%5ld\n",
+		       t[i].rt, t[i].master, t[i].diff, t[i].lat);
+#endif
+
+	printk(KERN_INFO "CPU %d: synchronized TICK with master CPU (last diff %ld cycles,"
+	       "maxerr %lu cycles)\n", smp_processor_id(), delta, rt);
+}
+
+static void smp_start_sync_tick_client(int cpu);
+
+static void smp_synchronize_one_tick(int cpu)
+{
+	unsigned long flags, i;
+
+	go[MASTER] = 0;
+
+	smp_start_sync_tick_client(cpu);
+
+	/* wait for client to be ready */
+	while (!go[MASTER])
+		membar("#LoadLoad");
+
+	/* now let the client proceed into his loop */
+	go[MASTER] = 0;
+	membar("#StoreLoad");
+
+	spin_lock_irqsave(&itc_sync_lock, flags);
+	{
+		for (i = 0; i < NUM_ROUNDS*NUM_ITERS; i++) {
+			while (!go[MASTER])
+				membar("#LoadLoad");
+			go[MASTER] = 0;
+			membar("#StoreStore");
+			go[SLAVE] = tick_ops->get_tick();
+			membar("#StoreLoad");
+		}
+	}
+	spin_unlock_irqrestore(&itc_sync_lock, flags);
+}
+
+static void smp_synchronize_tick(void)
+{
+	int cpu = smp_processor_id();
+	int i;
+
+	for (i = 0; i < NR_CPUS; i++) {
+		if (cpu_present_map & (1UL << i)) {
+			if (i == cpu)
+				continue;
+			smp_synchronize_one_tick(i);
+		}
+	}
+}
+
 extern struct prom_cpuinfo linux_cpus[64];
 
 extern unsigned long sparc64_cpu_startup;
@@ -340,6 +448,8 @@
 	}
 	smp_processors_ready = 1;
 	membar("#StoreStore | #StoreLoad");
+
+	smp_synchronize_tick();
 }
 
 static void spitfire_xcall_helper(u64 data0, u64 data1, u64 data2, u64 pstate, unsigned long cpu)
@@ -542,6 +652,15 @@
 	}
 }
 
+extern unsigned long xcall_sync_tick;
+
+static void smp_start_sync_tick_client(int cpu)
+{
+	smp_cross_call_masked(&xcall_sync_tick,
+			      0, 0, 0,
+			      (1UL << cpu));
+}
+
 /* Send cross call to all processors except self. */
 #define smp_cross_call(func, ctx, data1, data2) \
 	smp_cross_call_masked(func, ctx, data1, data2, cpu_present_map)
@@ -987,8 +1106,6 @@
 
 extern void sparc64_do_profile(unsigned long pc, unsigned long o7);
 
-static unsigned long current_tick_offset;
-
 #define prof_multiplier(__cpu)		cpu_data[(__cpu)].multiplier
 #define prof_counter(__cpu)		cpu_data[(__cpu)].counter
 
@@ -1002,12 +1119,7 @@
 	 * Check for level 14 softint.
 	 */
 	{
-		unsigned long tick_mask;
-
-		if (SPARC64_USE_STICK)
-			tick_mask = (1UL << 16);
-		else
-			tick_mask = (1UL << 0);
+		unsigned long tick_mask = tick_ops->softint_mask;
 
 		if (!(get_softint() & tick_mask)) {
 			extern void handler_irq(int, struct pt_regs *);
@@ -1022,17 +1134,17 @@
 		if (!user)
 			sparc64_do_profile(regs->tpc, regs->u_regs[UREG_RETPC]);
 		if (!--prof_counter(cpu)) {
-			if (cpu == boot_cpu_id) {
-				irq_enter(cpu, 0);
+			irq_enter(cpu, 0);
 
+			if (cpu == boot_cpu_id) {
 				kstat.irqs[cpu][0]++;
 				timer_tick_interrupt(regs);
-
-				irq_exit(cpu, 0);
 			}
 
 			update_process_times(user);
 
+			irq_exit(cpu, 0);
+
 			prof_counter(cpu) = prof_multiplier(cpu);
 		}
 
@@ -1044,47 +1156,14 @@
 				     : "=r" (pstate)
 				     : "i" (PSTATE_IE));
 
-		/* Workaround for Spitfire Errata (#54 I think??), I discovered
-		 * this via Sun BugID 4008234, mentioned in Solaris-2.5.1 patch
-		 * number 103640.
-		 *
-		 * On Blackbird writes to %tick_cmpr can fail, the
-		 * workaround seems to be to execute the wr instruction
-		 * at the start of an I-cache line, and perform a dummy
-		 * read back from %tick_cmpr right after writing to it. -DaveM
-		 *
-		 * Just to be anal we add a workaround for Spitfire
-		 * Errata 50 by preventing pipeline bypasses on the
-		 * final read of the %tick register into a compare
-		 * instruction.  The Errata 50 description states
-		 * that %tick is not prone to this bug, but I am not
-		 * taking any chances.
-		 */
-		if (!SPARC64_USE_STICK) {
-		__asm__ __volatile__("rd	%%tick_cmpr, %0\n\t"
-				     "ba,pt	%%xcc, 1f\n\t"
-				     " add	%0, %2, %0\n\t"
-				     ".align	64\n"
-				  "1: wr	%0, 0x0, %%tick_cmpr\n\t"
-				     "rd	%%tick_cmpr, %%g0\n\t"
-				     "rd	%%tick, %1\n\t"
-				     "mov	%1, %1"
-				     : "=&r" (compare), "=r" (tick)
-				     : "r" (current_tick_offset));
-		} else {
-		__asm__ __volatile__("rd	%%asr25, %0\n\t"
-				     "add	%0, %2, %0\n\t"
-				     "wr	%0, 0x0, %%asr25\n\t"
-				     "rd	%%asr24, %1\n\t"
-				     : "=&r" (compare), "=r" (tick)
-				     : "r" (current_tick_offset));
-		}
+		compare = tick_ops->add_compare(current_tick_offset);
+		tick = tick_ops->get_tick();
 
 		/* Restore PSTATE_IE. */
 		__asm__ __volatile__("wrpr	%0, 0x0, %%pstate"
 				     : /* no outputs */
 				     : "r" (pstate));
-	} while (tick >= compare);
+	} while (time_after_eq(tick, compare));
 }
 
 static void __init smp_setup_percpu_timer(void)
@@ -1102,35 +1181,7 @@
 			     : "=r" (pstate)
 			     : "i" (PSTATE_IE));
 
-	/* Workaround for Spitfire Errata (#54 I think??), I discovered
-	 * this via Sun BugID 4008234, mentioned in Solaris-2.5.1 patch
-	 * number 103640.
-	 *
-	 * On Blackbird writes to %tick_cmpr can fail, the
-	 * workaround seems to be to execute the wr instruction
-	 * at the start of an I-cache line, and perform a dummy
-	 * read back from %tick_cmpr right after writing to it. -DaveM
-	 */
-	if (!SPARC64_USE_STICK) {
-	__asm__ __volatile__(
-		"rd	%%tick, %%g1\n\t"
-		"ba,pt	%%xcc, 1f\n\t"
-		" add	%%g1, %0, %%g1\n\t"
-		".align	64\n"
-	"1:	wr	%%g1, 0x0, %%tick_cmpr\n\t"
-		"rd	%%tick_cmpr, %%g0"
-	: /* no outputs */
-	: "r" (current_tick_offset)
-	: "g1");
-	} else {
-	__asm__ __volatile__(
-		"rd	%%asr24, %%g1\n\t"
-		"add	%%g1, %0, %%g1\n\t"
-		"wr	%%g1, 0x0, %%asr25"
-	: /* no outputs */
-	: "r" (current_tick_offset)
-	: "g1");
-	}
+	tick_ops->init_tick(current_tick_offset);
 
 	/* Restore PSTATE_IE. */
 	__asm__ __volatile__("wrpr	%0, 0x0, %%pstate"
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/kernel/sparc64_ksyms.c linux-2.4.21-pre6/arch/sparc64/kernel/sparc64_ksyms.c
--- linux-2.4.20/arch/sparc64/kernel/sparc64_ksyms.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/sparc64/kernel/sparc64_ksyms.c	2003-03-26 23:49:20.000000000 +0000
@@ -60,7 +60,6 @@
 
 extern unsigned prom_cpu_nodes[64];
 extern void die_if_kernel(char *str, struct pt_regs *regs);
-extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 void _sigpause_common (unsigned int set, struct pt_regs *);
 extern void *__bzero(void *, size_t);
 extern void *__bzero_noasi(void *, size_t);
@@ -195,6 +194,7 @@
 EXPORT_SYMBOL(get_fb_unmapped_area);
 EXPORT_SYMBOL(flush_icache_range);
 EXPORT_SYMBOL(flush_dcache_page);
+EXPORT_SYMBOL(__flush_dcache_range);
 
 EXPORT_SYMBOL(mostek_lock);
 EXPORT_SYMBOL(mstk48t02_regs);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/kernel/sys_sparc32.c linux-2.4.21-pre6/arch/sparc64/kernel/sys_sparc32.c
--- linux-2.4.20/arch/sparc64/kernel/sys_sparc32.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/sparc64/kernel/sys_sparc32.c	2003-03-26 23:49:49.000000000 +0000
@@ -50,6 +50,7 @@
 #include <linux/icmpv6.h>
 #include <linux/sysctl.h>
 #include <linux/dnotify.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
 
 #include <asm/types.h>
 #include <asm/ipc.h>
@@ -1150,7 +1151,7 @@
 	/* VERIFY_WRITE actually means a read, as we write to user space */
 	if ((retval + (type == VERIFY_WRITE)) > 0)
 		dnotify_parent(file->f_dentry,
-			(type == VERIFY_WRITE) ? DN_MODIFY : DN_ACCESS);
+			(type == VERIFY_WRITE) ? DN_ACCESS : DN_MODIFY);
 
 	return retval;
 }
@@ -2618,10 +2619,28 @@
 		__get_user(kcmsg32->cmsg_type, &ucmsg->cmsg_type);
 
 		clen64 = kcmsg32->cmsg_len;
-		copy_from_user(CMSG32_DATA(kcmsg32), CMSG_DATA(ucmsg),
-			       clen64 - CMSG_ALIGN(sizeof(*ucmsg)));
-		clen32 = ((clen64 - CMSG_ALIGN(sizeof(*ucmsg))) +
-			  CMSG32_ALIGN(sizeof(struct cmsghdr32)));
+		if (kcmsg32->cmsg_level == SOL_SOCKET &&
+			kcmsg32->cmsg_type == SO_TIMESTAMP) {
+			struct timeval tv;
+			struct timeval32 *tv32;
+
+			if (clen64 != CMSG_LEN(sizeof(struct timeval))) {
+				kfree(workbuf);
+				goto fail;
+			}
+
+			copy_from_user(&tv, CMSG_DATA(ucmsg), sizeof(tv));
+			tv32 = (struct timeval32 *)CMSG32_DATA(kcmsg32);
+			tv32->tv_sec = tv.tv_sec;
+			tv32->tv_usec = tv.tv_usec;
+			clen32 = sizeof(*tv32) +
+				  CMSG32_ALIGN(sizeof(struct cmsghdr32));
+		} else {
+			copy_from_user(CMSG32_DATA(kcmsg32), CMSG_DATA(ucmsg),
+				       clen64 - CMSG_ALIGN(sizeof(*ucmsg)));
+			clen32 = ((clen64 - CMSG_ALIGN(sizeof(*ucmsg))) +
+				  CMSG32_ALIGN(sizeof(struct cmsghdr32)));
+		}
 		kcmsg32->cmsg_len = clen32;
 
 		ucmsg = (struct cmsghdr *) (((char *)ucmsg) + CMSG_ALIGN(clen64));
@@ -2777,6 +2796,78 @@
 extern asmlinkage int sys_setsockopt(int fd, int level, int optname,
 				     char *optval, int optlen);
 
+static int do_netfilter_replace(int fd, int level, int optname,
+				char *optval, int optlen)
+{
+	struct ipt_replace32 {
+		char name[IPT_TABLE_MAXNAMELEN];
+		__u32 valid_hooks;
+		__u32 num_entries;
+		__u32 size;
+		__u32 hook_entry[NF_IP_NUMHOOKS];
+		__u32 underflow[NF_IP_NUMHOOKS];
+		__u32 num_counters;
+		__u32 counters;
+		struct ipt_entry entries[0];
+	} *repl32 = (struct ipt_replace32 *)optval;
+	struct ipt_replace *krepl;
+	struct ipt_counters *counters32;
+	__u32 origsize;
+	unsigned int kreplsize, kcountersize;
+	mm_segment_t old_fs;
+	int ret;
+
+	if (optlen < sizeof(repl32))
+		return -EINVAL;
+
+	if (copy_from_user(&origsize,
+			&repl32->size,
+			sizeof(origsize)))
+		return -EFAULT;
+
+	kreplsize = sizeof(*krepl) + origsize;
+	kcountersize = krepl->num_counters * sizeof(struct ipt_counters);
+
+	/* Hack: Causes ipchains to give correct error msg --RR */
+	if (optlen != kreplsize)
+		return -ENOPROTOOPT;
+
+	krepl = (struct ipt_replace *)kmalloc(kreplsize, GFP_KERNEL);
+	if (krepl == NULL)
+		return -ENOMEM;
+
+	if (copy_from_user(krepl, optval, kreplsize)) {
+		kfree(krepl);
+		return -EFAULT;
+	}
+
+	counters32 = (struct ipt_counters *)AA(
+		((struct ipt_replace32 *)krepl)->counters);
+
+	kcountersize = krepl->num_counters * sizeof(struct ipt_counters);
+	krepl->counters = (struct ipt_counters *)kmalloc(
+					kcountersize, GFP_KERNEL);
+	if (krepl->counters == NULL) {
+		kfree(krepl);
+		return -ENOMEM;
+	}
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_setsockopt(fd, level, optname,
+			     (char *)krepl, kreplsize);
+	set_fs(old_fs);
+
+	if (ret == 0 &&
+		copy_to_user(counters32, krepl->counters, kcountersize))
+			ret = -EFAULT;
+
+	kfree(krepl->counters);
+	kfree(krepl);
+
+	return ret;
+}
+
 static int do_set_attach_filter(int fd, int level, int optname,
 				char *optval, int optlen)
 {
@@ -2870,6 +2961,9 @@
 asmlinkage int sys32_setsockopt(int fd, int level, int optname,
 				char *optval, int optlen)
 {
+	if (optname == IPT_SO_SET_REPLACE)
+		return do_netfilter_replace(fd, level, optname,
+					    optval, optlen);
 	if (optname == SO_ATTACH_FILTER)
 		return do_set_attach_filter(fd, level, optname,
 					    optval, optlen);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/kernel/systbls.S linux-2.4.21-pre6/arch/sparc64/kernel/systbls.S
--- linux-2.4.20/arch/sparc64/kernel/systbls.S	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/sparc64/kernel/systbls.S	2003-03-26 23:49:34.000000000 +0000
@@ -52,11 +52,11 @@
 /*150*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_getdents64
 	.word sys32_fcntl64, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys_oldumount
 /*160*/	.word sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_nis_syscall
-	.word sys32_quotactl, sys_nis_syscall, sys32_mount, sys_ustat, sys_nis_syscall
-/*170*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getdents
-	.word sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*180*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_sigpending, sys32_query_module
-	.word sys_setpgid, sys_nis_syscall, sys_tkill, sys_nis_syscall, sparc64_newuname
+	.word sys32_quotactl, sys_nis_syscall, sys32_mount, sys_ustat, sys_setxattr
+/*170*/	.word sys_lsetxattr, sys_fsetxattr, sys_getxattr, sys_lgetxattr, sys32_getdents
+	.word sys_setsid, sys_fchdir, sys_fgetxattr, sys_listxattr, sys_llistxattr
+/*180*/	.word sys_flistxattr, sys_removexattr, sys_lremovexattr, sys32_sigpending, sys32_query_module
+	.word sys_setpgid, sys_fremovexattr, sys_tkill, sys_nis_syscall, sparc64_newuname
 /*190*/	.word sys32_init_module, sparc64_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
 	.word sys_nis_syscall, sys_nis_syscall, sys_getppid, sys32_sigaction, sys_sgetmask
 /*200*/	.word sys_ssetmask, sys_sigsuspend, sys32_newlstat, sys_uselib, old32_readdir
@@ -111,11 +111,11 @@
 /*150*/	.word sys_getsockname, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_getdents64
 	.word sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_oldumount
 /*160*/	.word sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_utrap_install
-	.word sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall
-/*170*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents
-	.word sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*180*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_query_module
-	.word sys_setpgid, sys_nis_syscall, sys_tkill, sys_nis_syscall, sparc64_newuname
+	.word sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_setxattr
+/*170*/	.word sys_lsetxattr, sys_fsetxattr, sys_getxattr, sys_lgetxattr, sys_getdents
+	.word sys_setsid, sys_fchdir, sys_fgetxattr, sys_listxattr, sys_llistxattr
+/*180*/	.word sys_flistxattr, sys_removexattr, sys_lremovexattr, sys_nis_syscall, sys_query_module
+	.word sys_setpgid, sys_fremovexattr, sys_tkill, sys_nis_syscall, sparc64_newuname
 /*190*/	.word sys_init_module, sparc64_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
 	.word sys_nis_syscall, sys_nis_syscall, sys_getppid, sys_nis_syscall, sys_sgetmask
 /*200*/	.word sys_ssetmask, sys_nis_syscall, sys_newlstat, sys_uselib, sys_nis_syscall
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/kernel/time.c linux-2.4.21-pre6/arch/sparc64/kernel/time.c
--- linux-2.4.20/arch/sparc64/kernel/time.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/sparc64/kernel/time.c	2003-03-26 23:49:39.000000000 +0000
@@ -22,6 +22,7 @@
 #include <linux/ioport.h>
 #include <linux/mc146818rtc.h>
 #include <linux/delay.h>
+#include <linux/timer.h>
 
 #include <asm/oplib.h>
 #include <asm/mostek.h>
@@ -34,6 +35,7 @@
 #include <asm/ebus.h>
 #include <asm/isa.h>
 #include <asm/starfire.h>
+#include <asm/smp.h>
 
 extern rwlock_t xtime_lock;
 
@@ -49,6 +51,352 @@
 
 static int set_rtc_mmss(unsigned long);
 
+struct sparc64_tick_ops *tick_ops;
+
+#define TICK_PRIV_BIT	(1UL << 63)
+
+static void tick_disable_protection(void)
+{
+	/* Set things up so user can access tick register for profiling
+	 * purposes.  Also workaround BB_ERRATA_1 by doing a dummy
+	 * read back of %tick after writing it.
+	 */
+	__asm__ __volatile__(
+	"	ba,pt	%%xcc, 1f\n"
+	"	 nop\n"
+	"	.align	64\n"
+	"1:	rd	%%tick, %%g2\n"
+	"	add	%%g2, 6, %%g2\n"
+	"	andn	%%g2, %0, %%g2\n"
+	"	wrpr	%%g2, 0, %%tick\n"
+	"	rdpr	%%tick, %%g0"
+	: /* no outputs */
+	: "r" (TICK_PRIV_BIT)
+	: "g2");
+}
+
+static void tick_init_tick(unsigned long offset)
+{
+	tick_disable_protection();
+
+	__asm__ __volatile__(
+	"	rd	%%tick, %%g1\n"
+	"	andn	%%g1, %1, %%g1\n"
+	"	ba,pt	%%xcc, 1f\n"
+	"	 add	%%g1, %0, %%g1\n"
+	"	.align	64\n"
+	"1:	wr	%%g1, 0x0, %%tick_cmpr\n"
+	"	rd	%%tick_cmpr, %%g0"
+	: /* no outputs */
+	: "r" (offset), "r" (TICK_PRIV_BIT)
+	: "g1");
+}
+
+static unsigned long tick_get_tick(void)
+{
+	unsigned long ret;
+
+	__asm__ __volatile__("rd	%%tick, %0\n\t"
+			     "mov	%0, %0"
+			     : "=r" (ret));
+
+	return ret & ~TICK_PRIV_BIT;
+}
+
+static unsigned long tick_get_compare(void)
+{
+	unsigned long ret;
+
+	__asm__ __volatile__("rd	%%tick_cmpr, %0\n\t"
+			     "mov	%0, %0"
+			     : "=r" (ret));
+
+	return ret;
+}
+
+static unsigned long tick_add_compare(unsigned long adj)
+{
+	unsigned long new_compare;
+
+	/* Workaround for Spitfire Errata (#54 I think??), I discovered
+	 * this via Sun BugID 4008234, mentioned in Solaris-2.5.1 patch
+	 * number 103640.
+	 *
+	 * On Blackbird writes to %tick_cmpr can fail, the
+	 * workaround seems to be to execute the wr instruction
+	 * at the start of an I-cache line, and perform a dummy
+	 * read back from %tick_cmpr right after writing to it. -DaveM
+	 */
+	__asm__ __volatile__("rd	%%tick_cmpr, %0\n\t"
+			     "ba,pt	%%xcc, 1f\n\t"
+			     " add	%0, %1, %0\n\t"
+			     ".align	64\n"
+			     "1:\n\t"
+			     "wr	%0, 0, %%tick_cmpr\n\t"
+			     "rd	%%tick_cmpr, %%g0"
+			     : "=&r" (new_compare)
+			     : "r" (adj));
+
+	return new_compare;
+}
+
+static unsigned long tick_add_tick(unsigned long adj, unsigned long offset)
+{
+	unsigned long new_tick, tmp;
+
+	/* Also need to handle Blackbird bug here too. */
+	__asm__ __volatile__("rd	%%tick, %0\n\t"
+			     "add	%0, %2, %0\n\t"
+			     "wrpr	%0, 0, %%tick\n\t"
+			     "andn	%0, %4, %1\n\t"
+			     "ba,pt	%%xcc, 1f\n\t"
+			     " add	%1, %3, %1\n\t"
+			     ".align	64\n"
+			     "1:\n\t"
+			     "wr	%1, 0, %%tick_cmpr\n\t"
+			     "rd	%%tick_cmpr, %%g0"
+			     : "=&r" (new_tick), "=&r" (tmp)
+			     : "r" (adj), "r" (offset), "r" (TICK_PRIV_BIT));
+
+	return new_tick;
+}
+
+static struct sparc64_tick_ops tick_operations = {
+	.init_tick	=	tick_init_tick,
+	.get_tick	=	tick_get_tick,
+	.get_compare	=	tick_get_compare,
+	.add_tick	=	tick_add_tick,
+	.add_compare	=	tick_add_compare,
+	.softint_mask	=	1UL << 0,
+};
+
+static void stick_init_tick(unsigned long offset)
+{
+	tick_disable_protection();
+
+	/* Let the user get at STICK too. */
+	__asm__ __volatile__(
+	"	rd	%%asr24, %%g2\n"
+	"	andn	%%g2, %0, %%g2\n"
+	"	wr	%%g2, 0, %%asr24"
+	: /* no outputs */
+	: "r" (TICK_PRIV_BIT)
+	: "g1", "g2");
+
+	__asm__ __volatile__(
+	"	rd	%%asr24, %%g1\n"
+	"	andn	%%g1, %1, %%g1\n"
+	"	add	%%g1, %0, %%g1\n"
+	"	wr	%%g1, 0x0, %%asr25"
+	: /* no outputs */
+	: "r" (offset), "r" (TICK_PRIV_BIT)
+	: "g1");
+}
+
+static unsigned long stick_get_tick(void)
+{
+	unsigned long ret;
+
+	__asm__ __volatile__("rd	%%asr24, %0"
+			     : "=r" (ret));
+
+	return ret & ~TICK_PRIV_BIT;
+}
+
+static unsigned long stick_get_compare(void)
+{
+	unsigned long ret;
+
+	__asm__ __volatile__("rd	%%asr25, %0"
+			     : "=r" (ret));
+
+	return ret;
+}
+
+static unsigned long stick_add_tick(unsigned long adj, unsigned long offset)
+{
+	unsigned long new_tick, tmp;
+
+	__asm__ __volatile__("rd	%%asr24, %0\n\t"
+			     "add	%0, %2, %0\n\t"
+			     "wr	%0, 0, %%asr24\n\t"
+			     "andn	%0, %4, %1\n\t"
+			     "add	%1, %3, %1\n\t"
+			     "wr	%1, 0, %%asr25"
+			     : "=&r" (new_tick), "=&r" (tmp)
+			     : "r" (adj), "r" (offset), "r" (TICK_PRIV_BIT));
+
+	return new_tick;
+}
+
+static unsigned long stick_add_compare(unsigned long adj)
+{
+	unsigned long new_compare;
+
+	__asm__ __volatile__("rd	%%asr25, %0\n\t"
+			     "add	%0, %1, %0\n\t"
+			     "wr	%0, 0, %%asr25"
+			     : "=&r" (new_compare)
+			     : "r" (adj));
+
+	return new_compare;
+}
+
+static struct sparc64_tick_ops stick_operations = {
+	.init_tick	=	stick_init_tick,
+	.get_tick	=	stick_get_tick,
+	.get_compare	=	stick_get_compare,
+	.add_tick	=	stick_add_tick,
+	.add_compare	=	stick_add_compare,
+	.softint_mask	=	1UL << 16,
+};
+
+/* On Hummingbird the STICK/STICK_CMPR register is implemented
+ * in I/O space.  There are two 64-bit registers each, the
+ * first holds the low 32-bits of the value and the second holds
+ * the high 32-bits.
+ *
+ * Since STICK is constantly updating, we have to access it carefully.
+ *
+ * The sequence we use to read is:
+ * 1) read low
+ * 2) read high
+ * 3) read low again, if it rolled over increment high by 1
+ *
+ * Writing STICK safely is also tricky:
+ * 1) write low to zero
+ * 2) write high
+ * 3) write low
+ */
+#define HBIRD_STICKCMP_ADDR	0x1fe0000f060UL
+#define HBIRD_STICK_ADDR	0x1fe0000f070UL
+
+static unsigned long __hbird_read_stick(void)
+{
+	unsigned long ret, tmp1, tmp2, tmp3;
+	unsigned long addr = HBIRD_STICK_ADDR;
+
+	__asm__ __volatile__("ldxa	[%1] %5, %2\n\t"
+			     "add	%1, 0x8, %1\n\t"
+			     "ldxa	[%1] %5, %3\n\t"
+			     "sub	%1, 0x8, %1\n\t"
+			     "ldxa	[%1] %5, %4\n\t"
+			     "cmp	%4, %2\n\t"
+			     "blu,a,pn	%%xcc, 1f\n\t"
+			     " add	%3, 1, %3\n"
+			     "1:\n\t"
+			     "sllx	%3, 32, %3\n\t"
+			     "or	%3, %4, %0\n\t"
+			     : "=&r" (ret), "=&r" (addr),
+			       "=&r" (tmp1), "=&r" (tmp2), "=&r" (tmp3)
+			     : "i" (ASI_PHYS_BYPASS_EC_E), "1" (addr));
+
+	return ret;
+}
+
+static unsigned long __hbird_read_compare(void)
+{
+	unsigned long low, high;
+	unsigned long addr = HBIRD_STICKCMP_ADDR;
+
+	__asm__ __volatile__("ldxa	[%2] %3, %0\n\t"
+			     "add	%2, 0x8, %2\n\t"
+			     "ldxa	[%2] %3, %1"
+			     : "=&r" (low), "=&r" (high), "=&r" (addr)
+			     : "i" (ASI_PHYS_BYPASS_EC_E), "2" (addr));
+
+	return (high << 32UL) | low;
+}
+
+static void __hbird_write_stick(unsigned long val)
+{
+	unsigned long low = (val & 0xffffffffUL);
+	unsigned long high = (val >> 32UL);
+	unsigned long addr = HBIRD_STICK_ADDR;
+
+	__asm__ __volatile__("stxa	%%g0, [%0] %4\n\t"
+			     "add	%0, 0x8, %0\n\t"
+			     "stxa	%3, [%0] %4\n\t"
+			     "sub	%0, 0x8, %0\n\t"
+			     "stxa	%2, [%0] %4"
+			     : "=&r" (addr)
+			     : "0" (addr), "r" (low), "r" (high),
+			       "i" (ASI_PHYS_BYPASS_EC_E));
+}
+
+static void __hbird_write_compare(unsigned long val)
+{
+	unsigned long low = (val & 0xffffffffUL);
+	unsigned long high = (val >> 32UL);
+	unsigned long addr = HBIRD_STICKCMP_ADDR + 0x8UL;
+
+	__asm__ __volatile__("stxa	%3, [%0] %4\n\t"
+			     "sub	%0, 0x8, %0\n\t"
+			     "stxa	%2, [%0] %4"
+			     : "=&r" (addr)
+			     : "0" (addr), "r" (low), "r" (high),
+			       "i" (ASI_PHYS_BYPASS_EC_E));
+}
+
+static void hbtick_init_tick(unsigned long offset)
+{
+	unsigned long val;
+
+	tick_disable_protection();
+
+	/* XXX This seems to be necessary to 'jumpstart' Hummingbird
+	 * XXX into actually sending STICK interrupts.  I think because
+	 * XXX of how we store %tick_cmpr in head.S this somehow resets the
+	 * XXX {TICK + STICK} interrupt mux.  -DaveM
+	 */
+	__hbird_write_stick(__hbird_read_stick());
+
+	val = __hbird_read_stick() & ~TICK_PRIV_BIT;
+	__hbird_write_compare(val + offset);
+}
+
+static unsigned long hbtick_get_tick(void)
+{
+	return __hbird_read_stick() & ~TICK_PRIV_BIT;
+}
+
+static unsigned long hbtick_get_compare(void)
+{
+	return __hbird_read_compare();
+}
+
+static unsigned long hbtick_add_tick(unsigned long adj, unsigned long offset)
+{
+	unsigned long val;
+
+	val = __hbird_read_stick() + adj;
+	__hbird_write_stick(val);
+
+	val &= ~TICK_PRIV_BIT;
+	__hbird_write_compare(val + offset);
+
+	return val;
+}
+
+static unsigned long hbtick_add_compare(unsigned long adj)
+{
+	unsigned long val = __hbird_read_compare() + adj;
+
+	val &= ~TICK_PRIV_BIT;
+	__hbird_write_compare(val);
+
+	return val;
+}
+
+static struct sparc64_tick_ops hbtick_operations = {
+	.init_tick	=	hbtick_init_tick,
+	.get_tick	=	hbtick_get_tick,
+	.get_compare	=	hbtick_get_compare,
+	.add_tick	=	hbtick_add_tick,
+	.add_compare	=	hbtick_add_compare,
+	.softint_mask	=	1UL << 0,
+};
+
 /* timer_interrupt() needs to keep up the real-time clock,
  * as well as call the "do_timer()" routine every clocktick
  *
@@ -129,49 +477,14 @@
 				     : "=r" (pstate)
 				     : "i" (PSTATE_IE));
 
-		/* Workaround for Spitfire Errata (#54 I think??), I discovered
-		 * this via Sun BugID 4008234, mentioned in Solaris-2.5.1 patch
-		 * number 103640.
-		 *
-		 * On Blackbird writes to %tick_cmpr can fail, the
-		 * workaround seems to be to execute the wr instruction
-		 * at the start of an I-cache line, and perform a dummy
-		 * read back from %tick_cmpr right after writing to it. -DaveM
-		 *
-		 * Just to be anal we add a workaround for Spitfire
-		 * Errata 50 by preventing pipeline bypasses on the
-		 * final read of the %tick register into a compare
-		 * instruction.  The Errata 50 description states
-		 * that %tick is not prone to this bug, but I am not
-		 * taking any chances.
-		 */
-		if (!SPARC64_USE_STICK) {
-		__asm__ __volatile__(
-		"	rd	%%tick_cmpr, %0\n"
-		"	ba,pt	%%xcc, 1f\n"
-		"	 add	%0, %2, %0\n"
-		"	.align	64\n"
-		"1: 	wr	%0, 0, %%tick_cmpr\n"
-		"	rd	%%tick_cmpr, %%g0\n"
-		"	rd	%%tick, %1\n"
-		"	mov	%1, %1"
-			: "=&r" (timer_tick_compare), "=r" (ticks)
-			: "r" (timer_tick_offset));
-		} else {
-		__asm__ __volatile__(
-		"	rd	%%asr25, %0\n"
-		"	add	%0, %2, %0\n"
-		"	wr	%0, 0, %%asr25\n"
-		"	rd	%%asr24, %1"
-			: "=&r" (timer_tick_compare), "=r" (ticks)
-			: "r" (timer_tick_offset));
-		}
+		timer_tick_compare = tick_ops->add_compare(timer_tick_offset);
+		ticks = tick_ops->get_tick();
 
 		/* Restore PSTATE_IE. */
 		__asm__ __volatile__("wrpr	%0, 0x0, %%pstate"
 				     : /* no outputs */
 				     : "r" (pstate));
-	} while (ticks >= timer_tick_compare);
+	} while (time_after_eq(ticks, timer_tick_compare));
 
 	timer_check_rtc();
 
@@ -188,19 +501,7 @@
 	/*
 	 * Only keep timer_tick_offset uptodate, but don't set TICK_CMPR.
 	 */
-	if (!SPARC64_USE_STICK) {
-	__asm__ __volatile__(
-	"	rd	%%tick_cmpr, %0\n"
-	"	add	%0, %1, %0"
-		: "=&r" (timer_tick_compare)
-		: "r" (timer_tick_offset));
-	} else {
-	__asm__ __volatile__(
-	"	rd	%%asr25, %0\n"
-	"	add	%0, %1, %0"
-		: "=&r" (timer_tick_compare)
-		: "r" (timer_tick_offset));
-	}
+	timer_tick_compare = tick_ops->get_compare() + timer_tick_offset;
 
 	timer_check_rtc();
 
@@ -611,43 +912,90 @@
 	__restore_flags(flags);
 }
 
-extern void init_timers(void (*func)(int, void *, struct pt_regs *),
-			unsigned long *);
+/* This is gets the master TICK_INT timer going. */
+static unsigned long sparc64_init_timers(void (*cfunc)(int, void *, struct pt_regs *))
+{
+	unsigned long pstate, clock;
+	int node, err;
+#ifdef CONFIG_SMP
+	extern void smp_tick_init(void);
+#endif
+
+	if (tlb_type == spitfire) {
+		unsigned long ver, manuf, impl;
+
+		__asm__ __volatile__ ("rdpr %%ver, %0"
+				      : "=&r" (ver));
+		manuf = ((ver >> 48) & 0xffff);
+		impl = ((ver >> 32) & 0xffff);
+		if (manuf == 0x17 && impl == 0x13) {
+			/* Hummingbird, aka Ultra-IIe */
+			tick_ops = &hbtick_operations;
+			node = prom_root_node;
+			clock = prom_getint(node, "stick-frequency");
+		} else {
+			tick_ops = &tick_operations;
+			node = linux_cpus[0].prom_node;
+			clock = prom_getint(node, "clock-frequency");
+		}
+	} else {
+		tick_ops = &stick_operations;
+		node = prom_root_node;
+		clock = prom_getint(node, "stick-frequency");
+	}
+	timer_tick_offset = clock / HZ;
+
+#ifdef CONFIG_SMP
+	smp_tick_init();
+#endif
+
+	/* Register IRQ handler. */
+	err = request_irq(build_irq(0, 0, 0UL, 0UL), cfunc, SA_STATIC_ALLOC,
+			  "timer", NULL);
+
+	if(err) {
+		prom_printf("Serious problem, cannot register TICK_INT\n");
+		prom_halt();
+	}
+
+	/* Guarentee that the following sequences execute
+	 * uninterrupted.
+	 */
+	__asm__ __volatile__("rdpr	%%pstate, %0\n\t"
+			     "wrpr	%0, %1, %%pstate"
+			     : "=r" (pstate)
+			     : "i" (PSTATE_IE));
+
+	tick_ops->init_tick(timer_tick_offset);
 
+	/* Restore PSTATE_IE. */
+	__asm__ __volatile__("wrpr	%0, 0x0, %%pstate"
+			     : /* no outputs */
+			     : "r" (pstate));
+
+	sti();
+
+	return clock;
+}
+
+/* The quotient formula is taken from the IA64 port. */
 void __init time_init(void)
 {
-	/* clock_probe() is now done at end of [se]bus_init on sparc64
-	 * so that sbus, fhc and ebus bus information is probed and
-	 * available.
-	 */
-	unsigned long clock;
+	unsigned long clock = sparc64_init_timers(timer_interrupt);
 
-	init_timers(timer_interrupt, &clock);
-	timer_ticks_per_usec_quotient = ((1UL<<32) / (clock / 1000020));
+	timer_ticks_per_usec_quotient =
+		(((1000000UL << 30) +
+		  (clock / 2)) / clock);
 }
 
 static __inline__ unsigned long do_gettimeoffset(void)
 {
-	unsigned long ticks;
+	unsigned long ticks = tick_ops->get_tick();
 
-	if (!SPARC64_USE_STICK) {
-	__asm__ __volatile__(
-	"	rd	%%tick, %%g1\n"
-	"	add	%1, %%g1, %0\n"
-	"	sub	%0, %2, %0\n"
-		: "=r" (ticks)
-		: "r" (timer_tick_offset), "r" (timer_tick_compare)
-		: "g1", "g2");
-	} else {
-	__asm__ __volatile__("rd	%%asr24, %%g1\n\t"
-			     "add	%1, %%g1, %0\n\t"
-			     "sub	%0, %2, %0\n\t"
-			     : "=&r" (ticks)
-			     : "r" (timer_tick_offset), "r" (timer_tick_compare)
-			     : "g1");
-	}
+	ticks += timer_tick_offset;
+	ticks -= timer_tick_compare;
 
-	return (ticks * timer_ticks_per_usec_quotient) >> 32UL;
+	return (ticks * timer_ticks_per_usec_quotient) >> 30UL;
 }
 
 void do_settimeofday(struct timeval *tv)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/kernel/trampoline.S linux-2.4.21-pre6/arch/sparc64/kernel/trampoline.S
--- linux-2.4.20/arch/sparc64/kernel/trampoline.S	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/sparc64/kernel/trampoline.S	2003-03-26 23:49:29.000000000 +0000
@@ -85,7 +85,10 @@
 
 startup_continue:
 	wrpr		%g0, 15, %pil
-	wr		%g0, 0, %tick_cmpr
+
+	sethi		%hi(0x80000000), %g2
+	sllx		%g2, 32, %g2
+	wr		%g2, 0, %tick_cmpr
 
 	/* Call OBP by hand to lock KERNBASE into i/d tlbs. */
 	mov		%o0, %l0
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/mm/ultra.S linux-2.4.21-pre6/arch/sparc64/mm/ultra.S
--- linux-2.4.20/arch/sparc64/mm/ultra.S	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/sparc64/mm/ultra.S	2003-03-26 23:49:50.000000000 +0000
@@ -524,6 +524,24 @@
 	nop
 	nop
 
+	/* This runs in a very controlled environment, so we do
+	 * not need to worry about BH races etc.
+	 */
+	.globl		xcall_sync_tick
+xcall_sync_tick:
+	rdpr		%pstate, %g2
+	wrpr		%g2, PSTATE_IG | PSTATE_AG, %pstate
+	rdpr		%pil, %g2
+	wrpr		%g0, 15, %pil
+	sethi		%hi(109f), %g7
+	b,pt		%xcc, etrap_irq
+109:	 or		%g7, %lo(109b), %g7
+	call		smp_synchronize_tick_client
+	 nop
+	clr		%l6
+	b		rtrap_xcall
+	 ldx		[%sp + PTREGS_OFF + PT_V9_TSTATE], %l1
+
 	/* NOTE: This is SPECIAL!!  We do etrap/rtrap however
 	 *       we choose to deal with the "BH's run with
 	 *       %pil==15" problem (described in asm/pil.h)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/sparc64/solaris/ioctl.c linux-2.4.21-pre6/arch/sparc64/solaris/ioctl.c
--- linux-2.4.20/arch/sparc64/solaris/ioctl.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/arch/sparc64/solaris/ioctl.c	2003-03-26 23:49:40.000000000 +0000
@@ -367,6 +367,7 @@
 	case 106: /* SI_GETINTRANSIT */
 	case 107: /* SI_TCL_LINK */
 	case 108: /* SI_TCL_UNLINK */
+		;
 	}
 	return TNOTSUPPORT;
 }
@@ -454,6 +455,7 @@
 	case 145: /* TI_GETPEERNAME */
 	case 146: /* TI_SETMYNAME */
 	case 147: /* TI_SETPEERNAME */
+		;
 	}
 	return TNOTSUPPORT;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/Makefile linux-2.4.21-pre6/arch/x86_64/Makefile
--- linux-2.4.20/arch/x86_64/Makefile	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/Makefile	2003-03-26 23:49:25.000000000 +0000
@@ -19,7 +19,7 @@
 # 20010105  Andi Kleen, add IA32 compiler.
 #           ....and later removed it again....
 #
-# $Id: Makefile,v 1.31 2002/03/22 15:56:07 ak Exp $
+# $Id: Makefile,v 1.32 2003/03/03 16:06:43 ak Exp $
 
 #
 # early bootup linking needs 32bit. You can either use real 32bit tools
@@ -47,6 +47,9 @@
 # needed for earlier gcc 3.1
 CFLAGS += -fno-strength-reduce
 #CFLAGS += -g
+ifneq ($(CONFIG_X86_REMOTE_DEBUG),y)
+CFLAGS += -fno-asynchronous-unwind-tables
+endif
 
 # prevent gcc from keeping the stack 16 byte aligned (FIXME)
 #CFLAGS += -mpreferred-stack-boundary=2
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/boot/bootsect.S linux-2.4.21-pre6/arch/x86_64/boot/bootsect.S
--- linux-2.4.20/arch/x86_64/boot/bootsect.S	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/boot/bootsect.S	2003-03-26 23:49:50.000000000 +0000
@@ -395,9 +395,9 @@
 # NOTE: Doesn't save %ax or %dx; do it yourself if you need to.
 
 kill_motor:
-	movw	$0x3f2, %dx
-	xorb	%al, %al
-	outb	%al, %dx
+	xorw	%ax, %ax		# reset FDC
+	xorb	%dl, %dl
+	int	$0x13
 	ret
 
 sectors:	.word 0
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/boot/compressed/misc.c linux-2.4.21-pre6/arch/x86_64/boot/compressed/misc.c
--- linux-2.4.20/arch/x86_64/boot/compressed/misc.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/boot/compressed/misc.c	2003-03-26 23:49:20.000000000 +0000
@@ -279,7 +279,7 @@
 	puts(x);
 	puts("\n\n -- System halted");
 
-	while(1);	/* Halt */
+	while(1);
 }
 
 void setup_normal_output_buffer(void)
@@ -332,76 +332,6 @@
 	}
 }
 
-void check_cpu(void)
-{
-	int res = 0;
-	asm volatile( " \n\
-	movl $3,%%edx		# at least 386 \n\
-	pushfl			# push EFLAGS \n\
-	popl %%eax		# get EFLAGS \n\
-	movl %%eax,%%ecx		# save original EFLAGS \n\
-	xorl $0x40000,%%eax	# flip AC bit in EFLAGS \n\
-	pushl %%eax		# copy to EFLAGS \n\
-	popfl			# set EFLAGS \n\
-	pushfl			# get new EFLAGS \n\
-	popl %%eax		# put it in eax \n\
-	xorl %%ecx,%%eax		# change in flags \n\
-	andl $0x40000,%%eax	# check if AC bit changed \n\
-	je 1f \n\
-\n\
-	movl $4,%%edx		# at least 486 \n\
-	movl %%ecx,%%eax \n\
-	xorl $0x200000,%%eax	# check ID flag \n\
-	pushl %%eax \n\
-	popfl			# if we are on a straight 486DX, SX, or \n\
-	pushfl			# 487SX we can't change it \n\
-	popl %%eax \n\
-	xorl %%ecx,%%eax \n\
-	pushl %%ecx		# restore original EFLAGS \n\
-	popfl \n\
-	andl $0x200000,%%eax \n\
-	je 1f \n\
-\n\
-	/* get vendor info */ \n\
-#	xorl %%eax,%%eax			# call CPUID with 0 -> return vendor ID \n\
-#	cpuid \n\
-#	movl $5, %%edx \n\
-#	cmpl $0x41757468,%%ebx		# check thats amd \n\
-#	jne 1f \n\
-\n\
-	mov $0x80000000,%%eax		# Is extended cpuid supported?\n\
-	cpuid\n\
-	test $0x80000000,%%eax\n\
-	movl $5, %%edx \n\
-	jz 1f\n\
-\n\
-	movl $0x80000001,%%eax \n\
-	cpuid \n\
-	andl $0x20000000,%%edx \n\
-	movl $6, %%edx \n\
-	jz 1f \n\
-\n\
-	movl $7, %%edx \n\
-1:" : "=d" (res) : : "eax", "ebx", "ecx" );
-
-	switch (res) {
-	case 3: puts( "386" );
-		break;
-	case 4: puts( "486" );
-		break;
-	case 5: puts( "no extended cpuid" );
-		break;
-	case 6: puts( "non-64bit 586+" );
-		break;
-	case 7: puts( "64bit" );
-		break;
-	default:puts( "internal error" );
-		break;
-	}
-	if (res !=7)
-		error( "Sorry, your CPU is not capable of running 64-bit kernel." );
-}
-
 int decompress_kernel(struct moveparams *mv, void *rmode)
 {
 	real_mode = rmode;
@@ -421,8 +351,6 @@
 	else setup_output_buffer_if_we_run_high(mv);
 
 	makecrc();
-	puts("Checking CPU type...");
-	check_cpu();
 	puts(".\nDecompressing Linux...");
 	gunzip();
 	puts("done.\nBooting the kernel.\n");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/boot/setup.S linux-2.4.21-pre6/arch/x86_64/boot/setup.S
--- linux-2.4.20/arch/x86_64/boot/setup.S	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/boot/setup.S	2003-03-26 23:49:50.000000000 +0000
@@ -42,6 +42,7 @@
  * if CX/DX have been changed in the e801 call and if so use AX/BX .
  * Michael Miller, April 2001 <michaelm@mjmm.org>
  *
+ * Added long mode checking and SSE force. March 2003, Andi Kleen.		
  */
 
 #include <linux/config.h>
@@ -197,10 +198,10 @@
 prtsp2:	call	prtspc		# Print double space
 prtspc:	movb	$0x20, %al	# Print single space (note: fall-thru)
 
-# Part of above routine, this one just prints ascii al
-prtchr:	pushw	%ax
+prtchr:	
+	pushw	%ax
 	pushw	%cx
-	xorb	%bh, %bh
+	movw	$0007,%bx
 	movw	$0x01, %cx
 	movb	$0x0e, %ah
 	int	$0x10
@@ -277,6 +278,75 @@
 loader_panic_mess: .string "Wrong loader, giving up..."
 
 loader_ok:
+	/* check for long mode. */
+	/* we have to do this before the VESA setup, otherwise the user
+	   can't see the error message. */
+	
+	pushw	%ds
+	movw	%cs,%ax
+	movw	%ax,%ds
+	
+	/* minimum CPUID flags for x86-64 */
+	/* see http://www.x86-64.org/lists/discuss/msg02971.html */		
+#define SSE_MASK ((1<<25)|(1<<26))
+#define REQUIRED_MASK1 ((1<<0)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<8)|(1<<11)| \
+					   (1<<13)|(1<<15)|(1<<24)|(1<<29))
+
+	pushfl				/* standard way to check for cpuid */
+	popl	%eax
+	movl	%eax,%ebx
+	xorl	$0x200000,%eax
+	pushl	%eax
+	popfl
+	pushfl
+	popl	%eax
+	cmpl	%eax,%ebx
+	jz	no_longmode		/* cpu has no cpuid */
+	movl	$0x80000000,%eax
+	cpuid
+	cmpl	$0x80000001,%eax
+	jb	no_longmode		/* no extended cpuid */
+	xor	%di,%di
+	cmpl	$0x68747541,%ebx	/* AuthenticAMD */
+	jnz	noamd
+	cmpl	$0x69746e65,%edx
+	jnz	noamd
+	cmpl	$0x444d4163,%ecx
+	jnz	noamd
+	mov	$1,%di			/* cpu is from AMD */
+noamd:		
+	movl	$0x80000001,%eax		
+	cpuid
+	andl	$REQUIRED_MASK1,%edx
+	xorl	$REQUIRED_MASK1,%edx
+	jnz	no_longmode
+sse_test:		
+	movl	$1,%eax
+	cpuid
+	andl	$SSE_MASK,%edx
+	cmpl	$SSE_MASK,%edx
+	je	sse_ok
+	test	%di,%di
+	jz	no_longmode	/* only try to force SSE on AMD */ 
+	movl	$0xc0010015,%ecx	/* HWCR */
+	rdmsr
+	btr	$15,%eax	/* enable SSE */
+	wrmsr
+	xor	%di,%di		/* don't loop */
+	jmp	sse_test	/* try again */	
+no_longmode:
+	call	beep
+	lea	long_mode_panic,%si
+	call	prtstr
+no_longmode_loop:		
+	jmp	no_longmode_loop
+long_mode_panic:
+	.string "Your CPU does not support long mode. Use a 32bit distribution."
+	.byte 0
+	
+sse_ok:
+	popw	%ds
+	
 # Get memory size (extended mem, kB)
 
 	xorl	%eax, %eax
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/config.in linux-2.4.21-pre6/arch/x86_64/config.in
--- linux-2.4.20/arch/x86_64/config.in	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/config.in	2003-03-26 23:49:50.000000000 +0000
@@ -95,6 +95,7 @@
    source drivers/hotplug/Config.in
 else
    define_bool CONFIG_PCMCIA n
+   define_bool CONFIG_HOTPLUG_PCI n
 fi
 
 bool 'System V IPC' CONFIG_SYSVIPC
@@ -199,9 +200,8 @@
 source drivers/input/Config.in
 source drivers/char/Config.in
 
-source net/bluetooth/Config.in
 
-source drivers/misc/Config.in
+#source drivers/misc/Config.in
 
 source drivers/media/Config.in
 
@@ -230,6 +230,8 @@
 
 source drivers/usb/Config.in
 
+source net/bluetooth/Config.in
+
 mainmenu_option next_comment
 comment 'Kernel hacking'
 
@@ -241,7 +243,10 @@
    bool '  Spinlock debugging' CONFIG_DEBUG_SPINLOCK
    bool '  Additional run-time checks' CONFIG_CHECKING
    bool '  Debug __init statements' CONFIG_INIT_DEBUG
+   bool '  IOMMU debugging' CONFIG_IOMMU_DEBUG
    bool '  IOMMU leak tracing' CONFIG_IOMMU_LEAK
    bool '  Probalistic stack overflow check' CONFIG_DEBUG_STACKOVERFLOW
 fi
 endmenu
+
+source lib/Config.in
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/defconfig linux-2.4.21-pre6/arch/x86_64/defconfig
--- linux-2.4.20/arch/x86_64/defconfig	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/defconfig	2003-03-26 23:49:35.000000000 +0000
@@ -42,8 +42,7 @@
 CONFIG_MTRR=y
 # CONFIG_SMP is not set
 CONFIG_HPET_TIMER=y
-# CONFIG_GART_IOMMU is not set
-CONFIG_DUMMY_IOMMU=y
+CONFIG_GART_IOMMU=y
 CONFIG_X86_UP_IOAPIC=y
 CONFIG_MCE=y
 # CONFIG_K8_NUMA is not set
@@ -57,6 +56,7 @@
 # CONFIG_PCI_NAMES is not set
 # CONFIG_HOTPLUG is not set
 # CONFIG_PCMCIA is not set
+# CONFIG_HOTPLUG_PCI is not set
 CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
@@ -195,15 +195,6 @@
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
 # CONFIG_IDEDISK_STROKE is not set
-# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
-# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
-# CONFIG_BLK_DEV_IDEDISK_IBM is not set
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
 # CONFIG_BLK_DEV_IDECS is not set
 CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_IDETAPE is not set
@@ -217,8 +208,8 @@
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_BLK_DEV_RZ1000 is not set
 CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_BLK_DEV_GENERIC=y
 # CONFIG_IDEPCI_SHARE_IRQ is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
@@ -227,30 +218,31 @@
 # CONFIG_IDEDMA_ONLYDISK is not set
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_PCI_WIP is not set
-# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set
-# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
 CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_AEC62XX is not set
-# CONFIG_AEC62XX_TUNING is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
 # CONFIG_WDC_ALI15X3 is not set
 CONFIG_BLK_DEV_AMD74XX=y
 # CONFIG_AMD74XX_OVERRIDE is not set
 # CONFIG_BLK_DEV_CMD64X is not set
-# CONFIG_BLK_DEV_CMD680 is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5530 is not set
 # CONFIG_BLK_DEV_HPT34X is not set
 # CONFIG_HPT34X_AUTODMA is not set
 # CONFIG_BLK_DEV_HPT366 is not set
 # CONFIG_BLK_DEV_PIIX is not set
-# CONFIG_PIIX_TUNING is not set
+# CONFIG_BLK_DEV_NFORCE is not set
 # CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_OPTI621 is not set
-# CONFIG_BLK_DEV_PDC202XX is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
 # CONFIG_PDC202XX_BURST is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
 # CONFIG_PDC202XX_FORCE is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
 # CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
 # CONFIG_BLK_DEV_SIS5513 is not set
 # CONFIG_BLK_DEV_SLC90E66 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
@@ -263,6 +255,7 @@
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
+# CONFIG_BLK_DEV_ATARAID_SII is not set
 
 #
 # SCSI support
@@ -302,10 +295,8 @@
 CONFIG_AIC7XXX_RESET_DELAY_MS=15000
 # CONFIG_AIC7XXX_PROBE_EISA_VL is not set
 # CONFIG_AIC7XXX_BUILD_FIRMWARE is not set
-# CONFIG_SCSI_DPT_I2O 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_CPQFCTS is not set
@@ -333,13 +324,11 @@
 # CONFIG_SCSI_QLOGIC_ISP is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
-# CONFIG_SCSI_SEAGATE is not set
-# CONFIG_SCSI_SIM710 is not set
 # CONFIG_SCSI_SYM53C416 is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_ULTRASTOR is not set
+# CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
 
 #
@@ -388,6 +377,7 @@
 # CONFIG_ELMC is not set
 # CONFIG_ELMC_II is not set
 CONFIG_VORTEX=y
+# CONFIG_TYPHOON is not set
 # CONFIG_LANCE is not set
 # CONFIG_NET_VENDOR_SMC is not set
 # CONFIG_NET_VENDOR_RACAL is not set
@@ -406,6 +396,7 @@
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
 # CONFIG_SK98LIN is not set
 CONFIG_TIGON3=y
 # CONFIG_FDDI is not set
@@ -496,13 +487,20 @@
 # Input core support is needed for joysticks
 #
 # CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
 # CONFIG_AMD_RNG is not set
 # CONFIG_INTEL_RNG is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -514,6 +512,7 @@
 #
 # CONFIG_FTAPE is not set
 CONFIG_AGP=y
+CONFIG_AGP_AMD_8151=y
 CONFIG_AGP_INTEL=y
 CONFIG_AGP_I810=y
 CONFIG_AGP_VIA=y
@@ -525,15 +524,6 @@
 # CONFIG_MWAVE is not set
 
 #
-# Bluetooth support
-#
-# CONFIG_BLUEZ is not set
-
-#
-# Misc devices
-#
-
-#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -592,6 +582,7 @@
 # CONFIG_UDF_RW is not set
 # CONFIG_UFS_FS is not set
 # CONFIG_UFS_FS_WRITE is not set
+CONFIG_SIMICSFS=y
 
 #
 # Network File Systems
@@ -603,7 +594,7 @@
 # CONFIG_ROOT_NFS is not set
 CONFIG_NFSD=y
 CONFIG_NFSD_V3=y
-# CONFIG_NFSD_TCP is not set
+CONFIG_NFSD_TCP=y
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
@@ -692,6 +683,11 @@
 # CONFIG_USB is not set
 
 #
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
 # Kernel hacking
 #
 CONFIG_DEBUG_KERNEL=y
@@ -700,5 +696,12 @@
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_CHECKING is not set
 # CONFIG_INIT_DEBUG is not set
-# CONFIG_IOMMU_LEAK is not set
-CONFIG_DEBUG_STACKOVERFLOW=y
+# CONFIG_IOMMU_DEBUG is not set
+CONFIG_IOMMU_LEAK=y
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+
+#
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/ia32/fpu32.c linux-2.4.21-pre6/arch/x86_64/ia32/fpu32.c
--- linux-2.4.20/arch/x86_64/ia32/fpu32.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/ia32/fpu32.c	2003-03-26 23:49:07.000000000 +0000
@@ -2,7 +2,7 @@
  * Copyright 2002 Andi Kleen, SuSE Labs.
  * FXSAVE<->i387 conversion support. Based on code by Gareth Hughes.
  * This is used for ptrace, signals and coredumps in 32bit emulation.
- * $Id: fpu32.c,v 1.1 2002/03/21 14:16:32 ak Exp $
+ * $Id: fpu32.c,v 1.7 2003/03/14 16:06:35 ak Exp $
  */ 
 
 #include <linux/sched.h>
@@ -77,17 +77,20 @@
 	struct _fpxreg *to;
 	struct _fpreg *from;
 	int i;
-	int err; 
-	__u32 v;
+	int err = 0; 
+	u32 v;
 
-	err = __get_user(fxsave->cwd, (u16 *)&buf->cw); 
-	err |= __get_user(fxsave->swd, (u16 *)&buf->sw);
-	err |= __get_user(fxsave->twd, (u16 *)&buf->tag);
+#define G(num,val) err |= __get_user(val, num + (u32 *)buf)
+	G(0, fxsave->cwd);
+	G(1, fxsave->swd);
+	G(2, fxsave->twd);
 	fxsave->twd = twd_i387_to_fxsr(fxsave->twd);
-	err |= __get_user(fxsave->rip, &buf->ipoff); 
-	err |= __get_user(fxsave->rdp, &buf->dataoff); 
-	err |= __get_user(v, &buf->cssel); 
-	fxsave->fop = v >> 16;
+	G(3, fxsave->rip);
+	G(4, v);
+	fxsave->fop = v>>16;	/* cs ignored */
+	G(5, fxsave->rdp);
+	/* 6: ds ignored */
+#undef G
 	if (err) 
 		return -1; 
 
@@ -109,21 +112,29 @@
 	struct _fpreg *to;
 	struct _fpxreg *from;
 	int i;
-	u32 ds; 
-	int err; 
+	u16 cs,ds; 
+	int err = 0; 
 
-	err = __put_user((unsigned long)fxsave->cwd | 0xffff0000, &buf->cw);
-	err |= __put_user((unsigned long)fxsave->swd | 0xffff0000, &buf->sw);
-	err |= __put_user((u32)fxsave->rip, &buf->ipoff); 
-	err |= __put_user((u32)(regs->cs | ((u32)fxsave->fop << 16)), 
-			  &buf->cssel); 
-	err |= __put_user((u32)twd_fxsr_to_i387(fxsave), &buf->tag); 
-	err |= __put_user((u32)fxsave->rdp, &buf->dataoff); 
-	if (tsk == current) 
-		asm("movl %%ds,%0 " : "=r" (ds)); 
-	else /* ptrace. task has stopped. */
+	if (tsk == current) {
+		/* should be actually ds/cs at fpu exception time,
+		   but that information is not available in 64bit mode. */
+		asm("movw %%ds,%0 " : "=r" (ds)); 
+		asm("movw %%cs,%0 " : "=r" (cs)); 		
+	} else { /* ptrace. task has stopped. */
 		ds = tsk->thread.ds;
-	err |= __put_user(ds, &buf->datasel); 
+		cs = regs->cs;
+	} 
+
+#define P(num,val) err |= __put_user(val, num + (u32 *)buf)
+	P(0, (u32)fxsave->cwd | 0xffff0000);
+	P(1, (u32)fxsave->swd | 0xffff0000);
+	P(2, twd_fxsr_to_i387(fxsave));
+	P(3, (u32)fxsave->rip);
+	P(4,  cs | ((u32)fxsave->fop) << 16); 
+	P(5, fxsave->rdp);
+	P(6, 0xffff0000 | ds);
+#undef P
+
 	if (err) 
 		return -1; 
 
@@ -144,8 +155,8 @@
 				     &buf->_fxsr_env[0],
 				     sizeof(struct i387_fxsave_struct)))
 			return -1;
-	} 
 	tsk->thread.i387.fxsave.mxcsr &= 0xffbf;
+	}
 	return convert_fxsr_from_user(&tsk->thread.i387.fxsave, buf);
 }  
 
@@ -156,12 +167,11 @@
 {
 	int err = 0;
 
-	if (!tsk->used_math) 
-		return 0;
-	tsk->used_math = 0; 
-	unlazy_fpu(tsk);
+	init_fpu(tsk);
 	if (convert_fxsr_to_user(buf, &tsk->thread.i387.fxsave, regs, tsk))
 		return -1;
+	if (fsave) 
+		return 0;
 	err |= __put_user(tsk->thread.i387.fxsave.swd, &buf->status);
 	if (fsave) 
 		return err ? -1 : 1; 	
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/ia32/ia32_binfmt.c linux-2.4.21-pre6/arch/x86_64/ia32/ia32_binfmt.c
--- linux-2.4.20/arch/x86_64/ia32/ia32_binfmt.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/ia32/ia32_binfmt.c	2003-03-26 23:48:59.000000000 +0000
@@ -25,7 +25,9 @@
 
 #define IA32_EMULATOR 1
 
-#define IA32_PAGE_OFFSET 0xFFFFF000
+#define ELF_NAME "elf/i386"
+
+#define IA32_PAGE_OFFSET 0xFFFFe000
 #define IA32_STACK_TOP IA32_PAGE_OFFSET
 #define ELF_ET_DYN_BASE		(IA32_PAGE_OFFSET/3 + 0x1000000)
 
@@ -163,11 +165,13 @@
 #define ELF_PLAT_INIT(r)		elf32_init(r)
 #define setup_arg_pages(bprm)		ia32_setup_arg_pages(bprm)
 
+extern void load_gs_index(unsigned);
+
 #undef start_thread
 #define start_thread(regs,new_rip,new_rsp) do { \
-	__asm__("movl %0,%%fs": :"r" (0)); \
-	__asm__("movl %0,%%es; movl %0,%%ds": :"r" (__USER32_DS)); \
-	wrmsrl(MSR_KERNEL_GS_BASE, 0); \
+	asm volatile("movl %0,%%fs": :"r" (0)); \
+	load_gs_index(0);	\
+	asm volatile("movl %0,%%es; movl %0,%%ds": :"r" (__USER32_DS)); \
 	(regs)->rip = (new_rip); \
 	(regs)->rsp = (new_rsp); \
 	(regs)->eflags = 0x200; \
@@ -203,6 +207,8 @@
 	regs->rax = 0;
 	regs->rbx = 0; 
 	regs->rbp = 0; 
+	regs->r8 = regs->r9 = regs->r10 = regs->r11 = regs->r12 = regs->r13 =
+		regs->r14 = regs->r15 = 0;	
 	me->thread.fs = 0; 
 	me->thread.gs = 0;
 	me->thread.fsindex = 0; 
@@ -237,7 +243,7 @@
 		mpnt->vm_mm = current->mm;
 		mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p;
 		mpnt->vm_end = IA32_STACK_TOP;
-		mpnt->vm_page_prot = PAGE_COPY;
+		mpnt->vm_page_prot = PAGE_COPY_EXEC;
 		mpnt->vm_flags = VM_STACK_FLAGS;
 		mpnt->vm_ops = NULL;
 		mpnt->vm_pgoff = 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/ia32/ia32_ioctl.c linux-2.4.21-pre6/arch/x86_64/ia32/ia32_ioctl.c
--- linux-2.4.20/arch/x86_64/ia32/ia32_ioctl.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/ia32/ia32_ioctl.c	2003-03-26 23:49:24.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: ia32_ioctl.c,v 1.24 2002/09/17 15:23:41 ak Exp $
+/* $Id: ia32_ioctl.c,v 1.30 2003/03/12 06:03:23 ak Exp $
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
  *
  * Copyright (C) 1997-2000  Jakub Jelinek  (jakub@redhat.com)
@@ -38,6 +38,7 @@
 #include <linux/cdrom.h>
 #include <linux/loop.h>
 #include <linux/auto_fs.h>
+#include <linux/auto_fs4.h>
 #include <linux/devfs_fs.h>
 #include <linux/tty.h>
 #include <linux/vt_kern.h>
@@ -56,6 +57,10 @@
 #include <linux/module.h>
 #include <linux/serial.h>
 #include <linux/reiserfs_fs.h>
+#include <linux/if_tun.h>
+#include <linux/ctype.h>
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/rfcomm.h>
 #if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE)
 /* Ugh. This header really is not clean */
 #define min min
@@ -74,9 +79,14 @@
 #include <asm/ia32.h>
 #include <asm/uaccess.h>
 #include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/if_bonding.h>
+#include <linux/watchdog.h>
+
 #include <asm/module.h>
 #include <asm/ioctl32.h>
 #include <linux/soundcard.h>
+#include <linux/lp.h>
 
 #include <linux/atm.h>
 #include <linux/atmarp.h>
@@ -89,6 +99,19 @@
 #include <linux/atm_tcp.h>
 #include <linux/sonet.h>
 #include <linux/atm_suni.h>
+#include <linux/mtd/mtd.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci.h>
+
+#include <linux/usb.h>
+#include <linux/usbdevice_fs.h>
+#include <linux/nbd.h>
+#include <linux/random.h>
+#include <linux/filter.h>
+
+#include <asm/mtrr.h>
+
 
 #define A(__x) ((void *)(unsigned long)(__x))
 #define AA(__x)	A(__x)
@@ -442,6 +465,7 @@
         __kernel_caddr_t32  ifcbuf;
 };
 
+#ifdef CONFIG_NET
 static int dev_ifname32(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
 	struct net_device *dev;
@@ -457,10 +481,12 @@
 
 	strncpy(ifr32.ifr_name, dev->name, sizeof(ifr32.ifr_name)-1);
 	ifr32.ifr_name[sizeof(ifr32.ifr_name)-1] = 0; 
+	dev_put(dev);
 	
 	err = copy_to_user((struct ifreq32 *)arg, &ifr32, sizeof(struct ifreq32));
 	return (err ? -EFAULT : 0);
 }
+#endif
 
 static int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
@@ -557,9 +583,25 @@
 	}
 	switch (ethcmd) {
 	case ETHTOOL_GDRVINFO:	len = sizeof(struct ethtool_drvinfo); break;
+	case ETHTOOL_GMSGLVL:
+	case ETHTOOL_SMSGLVL:
+	case ETHTOOL_GLINK:
+	case ETHTOOL_NWAY_RST:  len = sizeof(struct ethtool_value); break;
+	case ETHTOOL_GREGS: {
+		struct ethtool_regs *regaddr = (struct ethtool_regs *)A(data);
+		/* darned variable size arguments */
+		if (get_user(len, (u32 *)&regaddr->len)) {
+			err = -EFAULT;
+			goto out;
+		}
+		len += sizeof(struct ethtool_regs);
+		break;
+	}
 	case ETHTOOL_GSET:
-	case ETHTOOL_SSET:
-	default:		len = sizeof(struct ethtool_cmd); break;
+	case ETHTOOL_SSET:      len = sizeof(struct ethtool_cmd); break;
+	default:
+               err = -EOPNOTSUPP;
+               goto out;
 	}
 
 	if (copy_from_user(ifr.ifr_data, (char *)A(data), len)) {
@@ -585,6 +627,91 @@
 	return err;
 }
 
+
+static int bond_ioctl(unsigned long fd, unsigned int cmd, unsigned long arg)
+{
+	struct ifreq ifr;
+	mm_segment_t old_fs;
+	int err, len;
+	u32 data;
+	
+	if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
+		return -EFAULT;
+	ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL);
+	if (!ifr.ifr_data)
+		return -EAGAIN;
+
+	switch (cmd) {
+	case SIOCBONDENSLAVE:
+	case SIOCBONDRELEASE:
+	case SIOCBONDSETHWADDR:
+	case SIOCBONDCHANGEACTIVE:
+		len = IFNAMSIZ * sizeof(char);
+		break;
+	case SIOCBONDSLAVEINFOQUERY:
+		len = sizeof(struct ifslave);
+		break;
+	case SIOCBONDINFOQUERY:
+		len = sizeof(struct ifbond);
+		break;
+	default:
+		err = -EINVAL;
+		goto out;
+	};
+
+	__get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data));
+	if (copy_from_user(ifr.ifr_data, (char *)A(data), len)) {
+		err = -EFAULT;
+		goto out;
+	}
+
+	old_fs = get_fs();
+	set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, cmd, (unsigned long)&ifr);
+	set_fs (old_fs);
+	if (!err) {
+		len = copy_to_user((char *)A(data), ifr.ifr_data, len);
+		if (len)
+			err = -EFAULT;
+	}
+
+out:
+	free_page((unsigned long)ifr.ifr_data);
+	return err;
+}
+
+static __inline__ void *alloc_user_space(long len)
+{
+	struct pt_regs *regs = (void *)current->thread.rsp0 - sizeof(struct pt_regs); 
+	return (void *)regs->rsp - len; 
+}
+
+static int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct ifreq *u_ifreq64;
+	struct ifreq32 *u_ifreq32 = (struct ifreq32 *) arg;
+	char tmp_buf[IFNAMSIZ];
+	void *data64;
+	u32 data32;
+
+	if (copy_from_user(&tmp_buf[0], &(u_ifreq32->ifr_ifrn.ifrn_name[0]),
+			   IFNAMSIZ))
+		return -EFAULT;
+	if (__get_user(data32, &u_ifreq32->ifr_ifru.ifru_data))
+		return -EFAULT;
+	data64 = (void *) A(data32);
+
+	u_ifreq64 = alloc_user_space(sizeof(*u_ifreq64));
+
+	/* Don't check these user accesses, just let that get trapped
+	 * in the ioctl handler instead.
+	 */
+	copy_to_user(&u_ifreq64->ifr_ifrn.ifrn_name[0], &tmp_buf[0], IFNAMSIZ);
+	__put_user(data64, &u_ifreq64->ifr_ifru.ifru_data);
+
+	return sys_ioctl(fd, cmd, (unsigned long) u_ifreq64);
+}
+
 static int dev_ifsioc(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
 	struct ifreq ifr;
@@ -603,15 +730,6 @@
 		if (err)
 			return -EFAULT;
 		break;
-	case SIOCGPPPSTATS:
-	case SIOCGPPPCSTATS:
-	case SIOCGPPPVER:
-		if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
-			return -EFAULT;
-		ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL);
-		if (!ifr.ifr_data)
-			return -EAGAIN;
-		break;
 	default:
 		if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
 			return -EFAULT;
@@ -637,27 +755,6 @@
 			if (copy_to_user((struct ifreq32 *)arg, &ifr, sizeof(struct ifreq32)))
 				return -EFAULT;
 			break;
-		case SIOCGPPPSTATS:
-		case SIOCGPPPCSTATS:
-		case SIOCGPPPVER:
-		{
-			u32 data;
-			int len;
-
-			__get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data));
-			if(cmd == SIOCGPPPVER)
-				len = strlen((char *)ifr.ifr_data) + 1;
-			else if(cmd == SIOCGPPPCSTATS)
-				len = sizeof(struct ppp_comp_stats);
-			else
-				len = sizeof(struct ppp_stats);
-
-			len = copy_to_user((char *)A(data), ifr.ifr_data, len);
-			free_page((unsigned long)ifr.ifr_data);
-			if(len)
-				return -EFAULT;
-			break;
-		}
 		case SIOCGIFMAP:
 			err = copy_to_user((struct ifreq32 *)arg, &ifr, sizeof(ifr.ifr_name));
 			err |= __put_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_start));
@@ -670,14 +767,6 @@
 				err = -EFAULT;
 			break;
 		}
-	} else {
-		switch (cmd) {
-		case SIOCGPPPSTATS:
-		case SIOCGPPPCSTATS:
-		case SIOCGPPPVER:
-			free_page((unsigned long)ifr.ifr_data);
-			break;
-		}
 	}
 	return err;
 }
@@ -716,11 +805,6 @@
 
 extern struct socket *sockfd_lookup(int fd, int *err);
 
-extern __inline__ void sockfd_put(struct socket *sock)
-{
-	fput(sock->file);
-}
-
 static int routing_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
 	int ret;
@@ -769,9 +853,6 @@
 	ret = sys_ioctl (fd, cmd, (long) r);
 	set_fs (old_fs);
 
-	if (mysock)
-		sockfd_put(mysock);
-
 	return ret;
 }
 
@@ -798,14 +879,6 @@
 	return err ? -EFAULT : 0;
 }
 
-struct  fbcmap32 {
-	int             index;          /* first element (0 origin) */
-	int             count;
-	u32		red;
-	u32		green;
-	u32		blue;
-};
-
 struct fb_fix_screeninfo32 {
 	char			id[16];
         __kernel_caddr_t32	smem_start;
@@ -889,7 +962,7 @@
 		break;
 	default:
 		do {
-			static int count = 0;
+			static int count;
 			if (++count <= 20)
 				printk("%s: Unknown fb ioctl cmd fd(%d) "
 				       "cmd(%08x) arg(%08lx)\n",
@@ -1268,6 +1341,269 @@
 	return err;
 }
 
+
+typedef struct sg_io_hdr32 {
+	s32 interface_id;	/* [i] 'S' for SCSI generic (required) */
+	s32 dxfer_direction;	/* [i] data transfer direction  */
+	u8  cmd_len;		/* [i] SCSI command length ( <= 16 bytes) */
+	u8  mx_sb_len;		/* [i] max length to write to sbp */
+	u16 iovec_count;	/* [i] 0 implies no scatter gather */
+	u32 dxfer_len;		/* [i] byte count of data transfer */
+	u32 dxferp;		/* [i], [*io] points to data transfer memory
+					      or scatter gather list */
+	u32 cmdp;		/* [i], [*i] points to command to perform */
+	u32 sbp;		/* [i], [*o] points to sense_buffer memory */
+	u32 timeout;		/* [i] MAX_UINT->no timeout (unit: millisec) */
+	u32 flags;		/* [i] 0 -> default, see SG_FLAG... */
+	s32 pack_id;		/* [i->o] unused internally (normally) */
+	u32 usr_ptr;		/* [i->o] unused internally */
+	u8  status;		/* [o] scsi status */
+	u8  masked_status;	/* [o] shifted, masked scsi status */
+	u8  msg_status;		/* [o] messaging level data (optional) */
+	u8  sb_len_wr;		/* [o] byte count actually written to sbp */
+	u16 host_status;	/* [o] errors from host adapter */
+	u16 driver_status;	/* [o] errors from software driver */
+	s32 resid;		/* [o] dxfer_len - actual_transferred */
+	u32 duration;		/* [o] time taken by cmd (unit: millisec) */
+	u32 info;		/* [o] auxiliary information */
+} sg_io_hdr32_t;  /* 64 bytes long (on sparc32) */
+
+typedef struct sg_iovec32 {
+	u32 iov_base;
+	u32 iov_len;
+} sg_iovec32_t;
+
+static int alloc_sg_iovec(sg_io_hdr_t *sgp, u32 uptr32)
+{
+	sg_iovec32_t *uiov = (sg_iovec32_t *) A(uptr32);
+	sg_iovec_t *kiov;
+	int i;
+
+	sgp->dxferp = kmalloc(sgp->iovec_count *
+			      sizeof(sg_iovec_t), GFP_KERNEL);
+	if (!sgp->dxferp)
+		return -ENOMEM;
+	memset(sgp->dxferp, 0,
+	       sgp->iovec_count * sizeof(sg_iovec_t));
+
+	kiov = (sg_iovec_t *) sgp->dxferp;
+	for (i = 0; i < sgp->iovec_count; i++) {
+		u32 iov_base32;
+		if (__get_user(iov_base32, &uiov->iov_base) ||
+		    __get_user(kiov->iov_len, &uiov->iov_len))
+			return -EFAULT;
+
+		kiov->iov_base = kmalloc(kiov->iov_len, GFP_KERNEL);
+		if (!kiov->iov_base)
+			return -ENOMEM;
+		if (copy_from_user(kiov->iov_base,
+				   (void *) A(iov_base32),
+				   kiov->iov_len))
+			return -EFAULT;
+
+		uiov++;
+		kiov++;
+	}
+
+	return 0;
+}
+
+static int copy_back_sg_iovec(sg_io_hdr_t *sgp, u32 uptr32)
+{
+	sg_iovec32_t *uiov = (sg_iovec32_t *) A(uptr32);
+	sg_iovec_t *kiov = (sg_iovec_t *) sgp->dxferp;
+	int i;
+
+	for (i = 0; i < sgp->iovec_count; i++) {
+		u32 iov_base32;
+
+		if (__get_user(iov_base32, &uiov->iov_base))
+			return -EFAULT;
+
+		if (copy_to_user((void *) A(iov_base32),
+				 kiov->iov_base,
+				 kiov->iov_len))
+			return -EFAULT;
+
+		uiov++;
+		kiov++;
+	}
+
+	return 0;
+}
+
+static void free_sg_iovec(sg_io_hdr_t *sgp)
+{
+	sg_iovec_t *kiov = (sg_iovec_t *) sgp->dxferp;
+	int i;
+
+	for (i = 0; i < sgp->iovec_count; i++) {
+		if (kiov->iov_base) {
+			kfree(kiov->iov_base);
+			kiov->iov_base = NULL;
+		}
+		kiov++;
+	}
+	kfree(sgp->dxferp);
+	sgp->dxferp = NULL;
+}
+
+static int sg_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	sg_io_hdr32_t *sg_io32;
+	sg_io_hdr_t sg_io64;
+	u32 dxferp32, cmdp32, sbp32;
+	mm_segment_t old_fs;
+	int err = 0;
+
+	sg_io32 = (sg_io_hdr32_t *)arg;
+	err = __get_user(sg_io64.interface_id, &sg_io32->interface_id);
+	err |= __get_user(sg_io64.dxfer_direction, &sg_io32->dxfer_direction);
+	err |= __get_user(sg_io64.cmd_len, &sg_io32->cmd_len);
+	err |= __get_user(sg_io64.mx_sb_len, &sg_io32->mx_sb_len);
+	err |= __get_user(sg_io64.iovec_count, &sg_io32->iovec_count);
+	err |= __get_user(sg_io64.dxfer_len, &sg_io32->dxfer_len);
+	err |= __get_user(sg_io64.timeout, &sg_io32->timeout);
+	err |= __get_user(sg_io64.flags, &sg_io32->flags);
+	err |= __get_user(sg_io64.pack_id, &sg_io32->pack_id);
+
+	sg_io64.dxferp = NULL;
+	sg_io64.cmdp = NULL;
+	sg_io64.sbp = NULL;
+
+	err |= __get_user(cmdp32, &sg_io32->cmdp);
+	sg_io64.cmdp = kmalloc(sg_io64.cmd_len, GFP_KERNEL);
+	if (!sg_io64.cmdp) {
+		err = -ENOMEM;
+		goto out;
+	}
+	if (copy_from_user(sg_io64.cmdp,
+			   (void *) A(cmdp32),
+			   sg_io64.cmd_len)) {
+		err = -EFAULT;
+		goto out;
+	}
+
+	err |= __get_user(sbp32, &sg_io32->sbp);
+	sg_io64.sbp = kmalloc(sg_io64.mx_sb_len, GFP_KERNEL);
+	if (!sg_io64.sbp) {
+		err = -ENOMEM;
+		goto out;
+	}
+	if (copy_from_user(sg_io64.sbp,
+			   (void *) A(sbp32),
+			   sg_io64.mx_sb_len)) {
+		err = -EFAULT;
+		goto out;
+	}
+
+	err |= __get_user(dxferp32, &sg_io32->dxferp);
+	if (sg_io64.iovec_count) {
+		int ret;
+
+		if ((ret = alloc_sg_iovec(&sg_io64, dxferp32))) {
+			err = ret;
+			goto out;
+		}
+	} else {
+		sg_io64.dxferp = kmalloc(sg_io64.dxfer_len, GFP_KERNEL);
+		if (!sg_io64.dxferp) {
+			err = -ENOMEM;
+			goto out;
+		}
+		if (copy_from_user(sg_io64.dxferp,
+				   (void *) A(dxferp32),
+				   sg_io64.dxfer_len)) {
+			err = -EFAULT;
+			goto out;
+		}
+	}
+
+	/* Unused internally, do not even bother to copy it over. */
+	sg_io64.usr_ptr = NULL;
+
+	if (err)
+		return -EFAULT;
+
+	old_fs = get_fs();
+	set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, cmd, (unsigned long) &sg_io64);
+	set_fs (old_fs);
+
+	if (err < 0)
+		goto out;
+
+	err = __put_user(sg_io64.pack_id, &sg_io32->pack_id);
+	err |= __put_user(sg_io64.status, &sg_io32->status);
+	err |= __put_user(sg_io64.masked_status, &sg_io32->masked_status);
+	err |= __put_user(sg_io64.msg_status, &sg_io32->msg_status);
+	err |= __put_user(sg_io64.sb_len_wr, &sg_io32->sb_len_wr);
+	err |= __put_user(sg_io64.host_status, &sg_io32->host_status);
+	err |= __put_user(sg_io64.driver_status, &sg_io32->driver_status);
+	err |= __put_user(sg_io64.resid, &sg_io32->resid);
+	err |= __put_user(sg_io64.duration, &sg_io32->duration);
+	err |= __put_user(sg_io64.info, &sg_io32->info);
+	err |= copy_to_user((void *)A(sbp32), sg_io64.sbp, sg_io64.mx_sb_len);
+	if (sg_io64.dxferp) {
+		if (sg_io64.iovec_count)
+			err |= copy_back_sg_iovec(&sg_io64, dxferp32);
+		else
+			err |= copy_to_user((void *)A(dxferp32),
+					    sg_io64.dxferp,
+					    sg_io64.dxfer_len);
+	}
+	if (err)
+		err = -EFAULT;
+
+out:
+	if (sg_io64.cmdp)
+		kfree(sg_io64.cmdp);
+	if (sg_io64.sbp)
+		kfree(sg_io64.sbp);
+	if (sg_io64.dxferp) {
+		if (sg_io64.iovec_count) {
+			free_sg_iovec(&sg_io64);
+		} else {
+			kfree(sg_io64.dxferp);
+		}
+	}
+	return err;
+}
+
+struct sock_fprog32 {
+	__u16	len;
+	__u32	filter;
+};
+
+#define PPPIOCSPASS32	_IOW('t', 71, struct sock_fprog32)
+#define PPPIOCSACTIVE32	_IOW('t', 70, struct sock_fprog32)
+
+static int ppp_sock_fprog_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct sock_fprog32 *u_fprog32 = (struct sock_fprog32 *) arg;
+	struct sock_fprog *u_fprog64 = alloc_user_space(sizeof(struct sock_fprog));
+	void *fptr64;
+	u32 fptr32;
+	u16 flen;
+
+	if (get_user(flen, &u_fprog32->len) ||
+	    get_user(fptr32, &u_fprog32->filter))
+		return -EFAULT;
+
+	fptr64 = (void *) A(fptr32);
+
+	if (put_user(flen, &u_fprog64->len) ||
+	    put_user(fptr64, &u_fprog64->filter))
+		return -EFAULT;
+
+	if (cmd == PPPIOCSPASS32)
+		cmd = PPPIOCSPASS;
+	else
+		cmd = PPPIOCSACTIVE;
+
+	return sys_ioctl(fd, cmd, (unsigned long) u_fprog64);
+}
+
 struct ppp_option_data32 {
 	__kernel_caddr_t32	ptr;
 	__u32			length;
@@ -1314,7 +1650,7 @@
 		break;
 	default:
 		do {
-			static int count = 0;
+			static int count;
 			if (++count <= 20)
 				printk("ppp_ioctl: Unknown cmd fd(%d) "
 				       "cmd(%08x) arg(%08x)\n",
@@ -1424,7 +1760,7 @@
 		break;
 	default:
 		do {
-			static int count = 0;
+			static int count;
 			if (++count <= 20)
 				printk("mt_ioctl: Unknown cmd fd(%d) "
 				       "cmd(%08x) arg(%08x)\n",
@@ -1542,7 +1878,7 @@
 		break;
 	default:
 		do {
-			static int count = 0;
+			static int count;
 			if (++count <= 20)
 				printk("cdrom_ioctl: Unknown cmd fd(%d) "
 				       "cmd(%08x) arg(%08x)\n",
@@ -1629,7 +1965,7 @@
 		}
 		break;
 	default: {
-		static int count = 0;
+		static int count;
 		if (++count <= 20)
 			printk("%s: Unknown loop ioctl cmd, fd(%d) "
 			       "cmd(%08x) arg(%08lx)\n",
@@ -2443,602 +2779,63 @@
 }
 #endif
 
-#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
-/* This really belongs in include/linux/drm.h -DaveM */
-#include "../../../drivers/char/drm/drm.h"
-
-typedef struct drm32_version {
-	int    version_major;	  /* Major version			    */
-	int    version_minor;	  /* Minor version			    */
-	int    version_patchlevel;/* Patch level			    */
-	int    name_len;	  /* Length of name buffer		    */
-	u32    name;		  /* Name of driver			    */
-	int    date_len;	  /* Length of date buffer		    */
-	u32    date;		  /* User-space buffer to hold date	    */
-	int    desc_len;	  /* Length of desc buffer		    */
-	u32    desc;		  /* User-space buffer to hold desc	    */
-} drm32_version_t;
-#define DRM32_IOCTL_VERSION    DRM_IOWR(0x00, drm32_version_t)
-
-static int drm32_version(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	drm32_version_t *uversion = (drm32_version_t *)arg;
-	char *name_ptr, *date_ptr, *desc_ptr;
-	u32 tmp1, tmp2, tmp3;
-	drm_version_t kversion;
-	mm_segment_t old_fs;
-	int ret;
-
-	memset(&kversion, 0, sizeof(kversion));
-	if (get_user(kversion.name_len, &uversion->name_len) ||
-	    get_user(kversion.date_len, &uversion->date_len) ||
-	    get_user(kversion.desc_len, &uversion->desc_len) ||
-	    get_user(tmp1, &uversion->name) ||
-	    get_user(tmp2, &uversion->date) ||
-	    get_user(tmp3, &uversion->desc))
-		return -EFAULT;
+static int ret_einval(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	return -EINVAL;
+}
 
-	name_ptr = (char *) A(tmp1);
-	date_ptr = (char *) A(tmp2);
-	desc_ptr = (char *) A(tmp3);
-
-	ret = -ENOMEM;
-	if (kversion.name_len && name_ptr) {
-		kversion.name = kmalloc(kversion.name_len, GFP_KERNEL);
-		if (!kversion.name)
-			goto out;
-	}
-	if (kversion.date_len && date_ptr) {
-		kversion.date = kmalloc(kversion.date_len, GFP_KERNEL);
-		if (!kversion.date)
-			goto out;
-	}
-	if (kversion.desc_len && desc_ptr) {
-		kversion.desc = kmalloc(kversion.desc_len, GFP_KERNEL);
-		if (!kversion.desc)
-			goto out;
-	}
+static int broken_blkgetsize(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	/* The mkswap binary hard codes it to Intel value :-((( */
+	return w_long(fd, BLKGETSIZE, arg);
+}
 
-        old_fs = get_fs();
-	set_fs(KERNEL_DS);
-        ret = sys_ioctl (fd, DRM_IOCTL_VERSION, (unsigned long)&kversion);
-        set_fs(old_fs);
+struct blkpg_ioctl_arg32 {
+	int op;
+	int flags;
+	int datalen;
+	u32 data;
+};
 
-	if (!ret) {
-		if ((kversion.name &&
-		     copy_to_user(name_ptr, kversion.name, kversion.name_len)) ||
-		    (kversion.date &&
-		     copy_to_user(date_ptr, kversion.date, kversion.date_len)) ||
-		    (kversion.desc &&
-		     copy_to_user(desc_ptr, kversion.desc, kversion.desc_len)))
-			ret = -EFAULT;
-		if (put_user(kversion.version_major, &uversion->version_major) ||
-		    put_user(kversion.version_minor, &uversion->version_minor) ||
-		    put_user(kversion.version_patchlevel, &uversion->version_patchlevel) ||
-		    put_user(kversion.name_len, &uversion->name_len) ||
-		    put_user(kversion.date_len, &uversion->date_len) ||
-		    put_user(kversion.desc_len, &uversion->desc_len))
-			ret = -EFAULT;
-	}
+static int blkpg_ioctl_trans(unsigned int fd, unsigned int cmd, struct blkpg_ioctl_arg32 *arg)
+{
+	struct blkpg_ioctl_arg a;
+	struct blkpg_partition p;
+	int err;
+	mm_segment_t old_fs = get_fs();
 
-out:
-	if (kversion.name)
-		kfree(kversion.name);
-	if (kversion.date)
-		kfree(kversion.date);
-	if (kversion.desc)
-		kfree(kversion.desc);
-	return ret;
+	err = get_user(a.op, &arg->op);
+	err |= __get_user(a.flags, &arg->flags);
+	err |= __get_user(a.datalen, &arg->datalen);
+	err |= __get_user((long)a.data, &arg->data);
+	if (err) return err;
+	switch (a.op) {
+	case BLKPG_ADD_PARTITION:
+	case BLKPG_DEL_PARTITION:
+		if (a.datalen < sizeof(struct blkpg_partition))
+			return -EINVAL;
+                if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition)))
+			return -EFAULT;
+		a.data = &p;
+		set_fs (KERNEL_DS);
+		err = sys_ioctl(fd, cmd, (unsigned long)&a);
+		set_fs (old_fs);
+	default:
+		return -EINVAL;
+	}                                        
+	return err;
 }
 
-typedef struct drm32_unique {
-	int	unique_len;	  /* Length of unique			    */
-	u32	unique;		  /* Unique name for driver instantiation   */
-} drm32_unique_t;
-#define DRM32_IOCTL_GET_UNIQUE DRM_IOWR(0x01, drm32_unique_t)
-#define DRM32_IOCTL_SET_UNIQUE DRM_IOW( 0x10, drm32_unique_t)
-
-static int drm32_getsetunique(unsigned int fd, unsigned int cmd, unsigned long arg)
+static int ioc_settimeout(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
-	drm32_unique_t *uarg = (drm32_unique_t *)arg;
-	drm_unique_t karg;
-	mm_segment_t old_fs;
-	char *uptr;
-	u32 tmp;
-	int ret;
+	return rw_long(fd, AUTOFS_IOC_SETTIMEOUT, arg);
+}
 
-	if (get_user(karg.unique_len, &uarg->unique_len))
-		return -EFAULT;
-	karg.unique = NULL;
-
-	if (get_user(tmp, &uarg->unique))
-		return -EFAULT;
-
-	uptr = (char *) A(tmp);
-
-	if (uptr) {
-		karg.unique = kmalloc(karg.unique_len, GFP_KERNEL);
-		if (!karg.unique)
-			return -ENOMEM;
-		if (cmd == DRM32_IOCTL_SET_UNIQUE &&
-		    copy_from_user(karg.unique, uptr, karg.unique_len)) {
-			kfree(karg.unique);
-			return -EFAULT;
-		}
-	}
-
-	old_fs = get_fs();
-	set_fs(KERNEL_DS);
-	if (cmd == DRM32_IOCTL_GET_UNIQUE)
-		ret = sys_ioctl (fd, DRM_IOCTL_GET_UNIQUE, (unsigned long)&karg);
-	else
-		ret = sys_ioctl (fd, DRM_IOCTL_SET_UNIQUE, (unsigned long)&karg);
-        set_fs(old_fs);
-
-	if (!ret) {
-		if (cmd == DRM32_IOCTL_GET_UNIQUE &&
-		    uptr != NULL &&
-		    copy_to_user(uptr, karg.unique, karg.unique_len))
-			ret = -EFAULT;
-		if (put_user(karg.unique_len, &uarg->unique_len))
-			ret = -EFAULT;
-	}
-
-	if (karg.unique != NULL)
-		kfree(karg.unique);
-
-	return ret;
-}
-
-typedef struct drm32_map {
-	u32		offset;	 /* Requested physical address (0 for SAREA)*/
-	u32		size;	 /* Requested physical size (bytes)	    */
-	drm_map_type_t	type;	 /* Type of memory to map		    */
-	drm_map_flags_t flags;	 /* Flags				    */
-	u32		handle;  /* User-space: "Handle" to pass to mmap    */
-				 /* Kernel-space: kernel-virtual address    */
-	int		mtrr;	 /* MTRR slot used			    */
-				 /* Private data			    */
-} drm32_map_t;
-#define DRM32_IOCTL_ADD_MAP    DRM_IOWR(0x15, drm32_map_t)
-
-static int drm32_addmap(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	drm32_map_t *uarg = (drm32_map_t *) arg;
-	drm_map_t karg;
-	mm_segment_t old_fs;
-	u32 tmp;
-	int ret;
-
-	ret  = get_user(karg.offset, &uarg->offset);
-	ret |= get_user(karg.size, &uarg->size);
-	ret |= get_user(karg.type, &uarg->type);
-	ret |= get_user(karg.flags, &uarg->flags);
-	ret |= get_user(tmp, &uarg->handle);
-	ret |= get_user(karg.mtrr, &uarg->mtrr);
-	if (ret)
-		return -EFAULT;
-
-	karg.handle = (void *) A(tmp);
-
-	old_fs = get_fs();
-	set_fs(KERNEL_DS);
-	ret = sys_ioctl(fd, DRM_IOCTL_ADD_MAP, (unsigned long) &karg);
-	set_fs(old_fs);
-
-	if (!ret) {
-		ret  = put_user(karg.offset, &uarg->offset);
-		ret |= put_user(karg.size, &uarg->size);
-		ret |= put_user(karg.type, &uarg->type);
-		ret |= put_user(karg.flags, &uarg->flags);
-		tmp = (u32) (long)karg.handle;
-		ret |= put_user(tmp, &uarg->handle);
-		ret |= put_user(karg.mtrr, &uarg->mtrr);
-		if (ret)
-			ret = -EFAULT;
-	}
-
-	return ret;
-}
-
-typedef struct drm32_buf_info {
-	int	       count;	/* Entries in list			     */
-	u32	       list;    /* (drm_buf_desc_t *) */ 
-} drm32_buf_info_t;
-#define DRM32_IOCTL_INFO_BUFS  DRM_IOWR(0x18, drm32_buf_info_t)
-
-static int drm32_info_bufs(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	drm32_buf_info_t *uarg = (drm32_buf_info_t *)arg;
-	drm_buf_desc_t *ulist;
-	drm_buf_info_t karg;
-	mm_segment_t old_fs;
-	int orig_count, ret;
-	u32 tmp;
-
-	if (get_user(karg.count, &uarg->count) ||
-	    get_user(tmp, &uarg->list))
-		return -EFAULT;
-
-	ulist = (drm_buf_desc_t *) A(tmp);
-
-	orig_count = karg.count;
-
-	karg.list = kmalloc(karg.count * sizeof(drm_buf_desc_t), GFP_KERNEL);
-	if (!karg.list)
-		return -EFAULT;
-
-	old_fs = get_fs();
-	set_fs(KERNEL_DS);
-	ret = sys_ioctl(fd, DRM_IOCTL_INFO_BUFS, (unsigned long) &karg);
-	set_fs(old_fs);
-
-	if (!ret) {
-		if (karg.count <= orig_count &&
-		    (copy_to_user(ulist, karg.list,
-				  karg.count * sizeof(drm_buf_desc_t))))
-			ret = -EFAULT;
-		if (put_user(karg.count, &uarg->count))
-			ret = -EFAULT;
-	}
-
-	kfree(karg.list);
-
-	return ret;
-}
-
-typedef struct drm32_buf_free {
-	int	       count;
-	u32	       list;	/* (int *) */
-} drm32_buf_free_t;
-#define DRM32_IOCTL_FREE_BUFS  DRM_IOW( 0x1a, drm32_buf_free_t)
-
-static int drm32_free_bufs(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	drm32_buf_free_t *uarg = (drm32_buf_free_t *)arg;
-	drm_buf_free_t karg;
-	mm_segment_t old_fs;
-	int *ulist;
-	int ret;
-	u32 tmp;
-
-	if (get_user(karg.count, &uarg->count) ||
-	    get_user(tmp, &uarg->list))
-		return -EFAULT;
-
-	ulist = (int *) A(tmp);
-
-	karg.list = kmalloc(karg.count * sizeof(int), GFP_KERNEL);
-	if (!karg.list)
-		return -ENOMEM;
-
-	ret = -EFAULT;
-	if (copy_from_user(karg.list, ulist, (karg.count * sizeof(int))))
-		goto out;
-
-	old_fs = get_fs();
-	set_fs(KERNEL_DS);
-	ret = sys_ioctl(fd, DRM_IOCTL_FREE_BUFS, (unsigned long) &karg);
-	set_fs(old_fs);
-
-out:
-	kfree(karg.list);
-
-	return ret;
-}
-
-typedef struct drm32_buf_pub {
-	int		  idx;	       /* Index into master buflist	     */
-	int		  total;       /* Buffer size			     */
-	int		  used;	       /* Amount of buffer in use (for DMA)  */
-	u32		  address;     /* Address of buffer (void *)	     */
-} drm32_buf_pub_t;
-
-typedef struct drm32_buf_map {
-	int	      count;	/* Length of buflist			    */
-	u32	      virtual;	/* Mmaped area in user-virtual (void *)	    */
-	u32 	      list;	/* Buffer information (drm_buf_pub_t *)	    */
-} drm32_buf_map_t;
-#define DRM32_IOCTL_MAP_BUFS   DRM_IOWR(0x19, drm32_buf_map_t)
-
-static int drm32_map_bufs(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	drm32_buf_map_t *uarg = (drm32_buf_map_t *)arg;
-	drm32_buf_pub_t *ulist;
-	drm_buf_map_t karg;
-	mm_segment_t old_fs;
-	int orig_count, ret, i;
-	u32 tmp1, tmp2;
-
-	if (get_user(karg.count, &uarg->count) ||
-	    get_user(tmp1, &uarg->virtual) ||
-	    get_user(tmp2, &uarg->list))
-		return -EFAULT;
-
-	karg.virtual = (void *) A(tmp1);
-	ulist = (drm32_buf_pub_t *) A(tmp2);
-
-	orig_count = karg.count;
-
-	karg.list = kmalloc(karg.count * sizeof(drm_buf_pub_t), GFP_KERNEL);
-	if (!karg.list)
-		return -ENOMEM;
-
-	ret = -EFAULT;
-	for (i = 0; i < karg.count; i++) {
-		if (get_user(karg.list[i].idx, &ulist[i].idx) ||
-		    get_user(karg.list[i].total, &ulist[i].total) ||
-		    get_user(karg.list[i].used, &ulist[i].used) ||
-		    get_user(tmp1, &ulist[i].address))
-			goto out;
-
-		karg.list[i].address = (void *) A(tmp1);
-	}
-
-	old_fs = get_fs();
-	set_fs(KERNEL_DS);
-	ret = sys_ioctl(fd, DRM_IOCTL_MAP_BUFS, (unsigned long) &karg);
-	set_fs(old_fs);
-
-	if (!ret) {
-		for (i = 0; i < orig_count; i++) {
-			tmp1 = (u32) (long) karg.list[i].address;
-			if (put_user(karg.list[i].idx, &ulist[i].idx) ||
-			    put_user(karg.list[i].total, &ulist[i].total) ||
-			    put_user(karg.list[i].used, &ulist[i].used) ||
-			    put_user(tmp1, &ulist[i].address)) {
-				ret = -EFAULT;
-				goto out;
-			}
-		}
-		if (put_user(karg.count, &uarg->count))
-			ret = -EFAULT;
-	}
-
-out:
-	kfree(karg.list);
-	return ret;
-}
-
-typedef struct drm32_dma {
-				/* Indices here refer to the offset into
-				   buflist in drm_buf_get_t.  */
-	int		context;	  /* Context handle		    */
-	int		send_count;	  /* Number of buffers to send	    */
-	u32		send_indices;	  /* List of handles to buffers (int *) */
-	u32		send_sizes;	  /* Lengths of data to send (int *) */
-	drm_dma_flags_t flags;		  /* Flags			    */
-	int		request_count;	  /* Number of buffers requested    */
-	int		request_size;	  /* Desired size for buffers	    */
-	u32		request_indices;  /* Buffer information (int *)	    */
-	u32		request_sizes;    /* (int *) */
-	int		granted_count;	  /* Number of buffers granted	    */
-} drm32_dma_t;
-#define DRM32_IOCTL_DMA	     DRM_IOWR(0x29, drm32_dma_t)
-
-/* RED PEN	The DRM layer blindly dereferences the send/request
- * 		indice/size arrays even though they are userland
- * 		pointers.  -DaveM
- */
-static int drm32_dma(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	drm32_dma_t *uarg = (drm32_dma_t *) arg;
-	int *u_si, *u_ss, *u_ri, *u_rs;
-	drm_dma_t karg;
-	mm_segment_t old_fs;
-	int ret;
-	u32 tmp1, tmp2, tmp3, tmp4;
-
-	karg.send_indices = karg.send_sizes = NULL;
-	karg.request_indices = karg.request_sizes = NULL;
-
-	if (get_user(karg.context, &uarg->context) ||
-	    get_user(karg.send_count, &uarg->send_count) ||
-	    get_user(tmp1, &uarg->send_indices) ||
-	    get_user(tmp2, &uarg->send_sizes) ||
-	    get_user(karg.flags, &uarg->flags) ||
-	    get_user(karg.request_count, &uarg->request_count) ||
-	    get_user(karg.request_size, &uarg->request_size) ||
-	    get_user(tmp3, &uarg->request_indices) ||
-	    get_user(tmp4, &uarg->request_sizes) ||
-	    get_user(karg.granted_count, &uarg->granted_count))
-		return -EFAULT;
-
-	u_si = (int *) A(tmp1);
-	u_ss = (int *) A(tmp2);
-	u_ri = (int *) A(tmp3);
-	u_rs = (int *) A(tmp4);
-
-	if (karg.send_count) {
-		karg.send_indices = kmalloc(karg.send_count * sizeof(int), GFP_KERNEL);
-		karg.send_sizes = kmalloc(karg.send_count * sizeof(int), GFP_KERNEL);
-
-		ret = -ENOMEM;
-		if (!karg.send_indices || !karg.send_sizes)
-			goto out;
-
-		ret = -EFAULT;
-		if (copy_from_user(karg.send_indices, u_si,
-				   (karg.send_count * sizeof(int))) ||
-		    copy_from_user(karg.send_sizes, u_ss,
-				   (karg.send_count * sizeof(int))))
-			goto out;
-	}
-
-	if (karg.request_count) {
-		karg.request_indices = kmalloc(karg.request_count * sizeof(int), GFP_KERNEL);
-		karg.request_sizes = kmalloc(karg.request_count * sizeof(int), GFP_KERNEL);
-
-		ret = -ENOMEM;
-		if (!karg.request_indices || !karg.request_sizes)
-			goto out;
-
-		ret = -EFAULT;
-		if (copy_from_user(karg.request_indices, u_ri,
-				   (karg.request_count * sizeof(int))) ||
-		    copy_from_user(karg.request_sizes, u_rs,
-				   (karg.request_count * sizeof(int))))
-			goto out;
-	}
-
-	old_fs = get_fs();
-	set_fs(KERNEL_DS);
-	ret = sys_ioctl(fd, DRM_IOCTL_DMA, (unsigned long) &karg);
-	set_fs(old_fs);
-
-	if (!ret) {
-		if (put_user(karg.context, &uarg->context) ||
-		    put_user(karg.send_count, &uarg->send_count) ||
-		    put_user(karg.flags, &uarg->flags) ||
-		    put_user(karg.request_count, &uarg->request_count) ||
-		    put_user(karg.request_size, &uarg->request_size) ||
-		    put_user(karg.granted_count, &uarg->granted_count))
-			ret = -EFAULT;
-
-		if (karg.send_count) {
-			if (copy_to_user(u_si, karg.send_indices,
-					 (karg.send_count * sizeof(int))) ||
-			    copy_to_user(u_ss, karg.send_sizes,
-					 (karg.send_count * sizeof(int))))
-				ret = -EFAULT;
-		}
-		if (karg.request_count) {
-			if (copy_to_user(u_ri, karg.request_indices,
-					 (karg.request_count * sizeof(int))) ||
-			    copy_to_user(u_rs, karg.request_sizes,
-					 (karg.request_count * sizeof(int))))
-				ret = -EFAULT;
-		}
-	}
-
-out:
-	if (karg.send_indices)
-		kfree(karg.send_indices);
-	if (karg.send_sizes)
-		kfree(karg.send_sizes);
-	if (karg.request_indices)
-		kfree(karg.request_indices);
-	if (karg.request_sizes)
-		kfree(karg.request_sizes);
-
-	return ret;
-}
-
-typedef struct drm32_ctx_res {
-	int		count;
-	u32		contexts; /* (drm_ctx_t *) */
-} drm32_ctx_res_t;
-#define DRM32_IOCTL_RES_CTX    DRM_IOWR(0x26, drm32_ctx_res_t)
-
-static int drm32_res_ctx(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	drm32_ctx_res_t *uarg = (drm32_ctx_res_t *) arg;
-	drm_ctx_t *ulist;
-	drm_ctx_res_t karg;
-	mm_segment_t old_fs;
-	int orig_count, ret;
-	u32 tmp;
-
-	karg.contexts = NULL;
-	if (get_user(karg.count, &uarg->count) ||
-	    get_user(tmp, &uarg->contexts))
-		return -EFAULT;
-
-	ulist = (drm_ctx_t *) A(tmp);
-
-	orig_count = karg.count;
-	if (karg.count && ulist) {
-		karg.contexts = kmalloc((karg.count * sizeof(drm_ctx_t)), GFP_KERNEL);
-		if (!karg.contexts)
-			return -ENOMEM;
-		if (copy_from_user(karg.contexts, ulist,
-				   (karg.count * sizeof(drm_ctx_t)))) {
-			kfree(karg.contexts);
-			return -EFAULT;
-		}
-	}
-
-	old_fs = get_fs();
-	set_fs(KERNEL_DS);
-	ret = sys_ioctl(fd, DRM_IOCTL_RES_CTX, (unsigned long) &karg);
-	set_fs(old_fs);
-
-	if (!ret) {
-		if (orig_count) {
-			if (copy_to_user(ulist, karg.contexts,
-					 (orig_count * sizeof(drm_ctx_t))))
-				ret = -EFAULT;
-		}
-		if (put_user(karg.count, &uarg->count))
-			ret = -EFAULT;
-	}
-
-	if (karg.contexts)
-		kfree(karg.contexts);
-
-	return ret;
-}
-
-#endif
-
-static int ret_einval(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	return -EINVAL;
-}
-
-static int broken_blkgetsize(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	/* The mkswap binary hard codes it to Intel value :-((( */
-	return w_long(fd, BLKGETSIZE, arg);
-}
-
-struct blkpg_ioctl_arg32 {
-	int op;
-	int flags;
-	int datalen;
-	u32 data;
-};
-                                
-static int blkpg_ioctl_trans(unsigned int fd, unsigned int cmd, struct blkpg_ioctl_arg32 *arg)
-{
-	struct blkpg_ioctl_arg a;
-	struct blkpg_partition p;
-	int err;
-	mm_segment_t old_fs = get_fs();
-	
-	err = get_user(a.op, &arg->op);
-	err |= __get_user(a.flags, &arg->flags);
-	err |= __get_user(a.datalen, &arg->datalen);
-	err |= __get_user((long)a.data, &arg->data);
-	if (err) return err;
-	switch (a.op) {
-	case BLKPG_ADD_PARTITION:
-	case BLKPG_DEL_PARTITION:
-		if (a.datalen < sizeof(struct blkpg_partition))
-			return -EINVAL;
-                if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition)))
-			return -EFAULT;
-		a.data = &p;
-		set_fs (KERNEL_DS);
-		err = sys_ioctl(fd, cmd, (unsigned long)&a);
-		set_fs (old_fs);
-	default:
-		return -EINVAL;
-	}                                        
-	return err;
-}
-
-static int ioc_settimeout(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-	return rw_long(fd, AUTOFS_IOC_SETTIMEOUT, arg);
-}
-
-/* SuSE extension */ 
-#ifndef TIOCGDEV
-#define TIOCGDEV       _IOR('T',0x32, unsigned int)
-#endif
-static int tiocgdev(unsigned fd, unsigned cmd,  unsigned int *ptr) 
-{ 
+#ifndef TIOCGDEV
+#define TIOCGDEV       _IOR('T',0x32, unsigned int)
+#endif
+static int tiocgdev(unsigned fd, unsigned cmd,  unsigned int *ptr) 
+{ 
 
 	struct file *file = fget(fd);
 	struct tty_struct *real_tty;
@@ -3144,6 +2941,14 @@
 	return err;	
 }
 
+/* Bluetooth ioctls */
+#define HCIUARTSETPROTO        _IOW('U', 200, int)
+#define HCIUARTGETPROTO        _IOR('U', 201, int)
+
+#define BNEPCONNADD    _IOW('B', 200, int)
+#define BNEPCONNDEL    _IOW('B', 201, int)
+#define BNEPGETCONNLIST        _IOR('B', 210, int)
+#define BNEPGETCONNINFO        _IOR('B', 211, int)
 
 #define REISERFS_IOC_UNPACK32               _IOW(0xCD,1,int)
 
@@ -3230,6 +3035,579 @@
 	return sys_ioctl(fd,cmd,arg); 
 } 
 
+/* Fix sizeof(sizeof()) breakage */
+#define BLKELVGET_32   _IOR(0x12,106,int)
+#define BLKELVSET_32   _IOW(0x12,107,int)
+#define BLKBSZGET_32   _IOR(0x12,112,int)
+#define BLKBSZSET_32   _IOW(0x12,113,int)
+#define BLKGETSIZE64_32        _IOR(0x12,114,int)
+
+static int do_blkelvget(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+       return sys_ioctl(fd, BLKELVGET, arg);
+}
+
+static int do_blkelvset(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+       return sys_ioctl(fd, BLKELVSET, arg);
+}
+
+static int do_blkbszget(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+       return sys_ioctl(fd, BLKBSZGET, arg);
+}
+
+static int do_blkbszset(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+       return sys_ioctl(fd, BLKBSZSET, arg);
+}
+
+static int do_blkgetsize64(unsigned int fd, unsigned int cmd,
+                          unsigned long arg)
+{
+       return sys_ioctl(fd, BLKGETSIZE64, arg);
+}
+
+/* Bluetooth ioctls */
+#define HCIUARTSETPROTO        _IOW('U', 200, int)
+#define HCIUARTGETPROTO        _IOR('U', 201, int)
+
+#define BNEPCONNADD    _IOW('B', 200, int)
+#define BNEPCONNDEL    _IOW('B', 201, int)
+#define BNEPGETCONNLIST        _IOR('B', 210, int)
+#define BNEPGETCONNINFO        _IOR('B', 211, int)
+
+struct usbdevfs_ctrltransfer32 {
+	__u8 requesttype;
+	__u8 request;
+	__u16 value;
+	__u16 index;
+	__u16 length;
+	__u32 timeout;  /* in milliseconds */
+	__u32 data;
+};
+
+#define USBDEVFS_CONTROL32           _IOWR('U', 0, struct usbdevfs_ctrltransfer32)
+
+static int do_usbdevfs_control(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct usbdevfs_ctrltransfer kctrl;
+	struct usbdevfs_ctrltransfer32 *uctrl;
+	mm_segment_t old_fs;
+	__u32 udata;
+	void *uptr, *kptr;
+	int err;
+
+	uctrl = (struct usbdevfs_ctrltransfer32 *) arg;
+
+	if (copy_from_user(&kctrl, uctrl,
+			   (sizeof(struct usbdevfs_ctrltransfer) -
+			    sizeof(void *))))
+		return -EFAULT;
+
+	if (get_user(udata, &uctrl->data))
+		return -EFAULT;
+	uptr = (void *) A(udata);
+
+	/* In usbdevice_fs, it limits the control buffer to a page,
+	 * for simplicity so do we.
+	 */
+	if (!uptr || kctrl.length > PAGE_SIZE)
+		return -EINVAL;
+
+	kptr = (void *)__get_free_page(GFP_KERNEL);
+
+	if ((kctrl.requesttype & 0x80) == 0) {
+		err = -EFAULT;
+		if (copy_from_user(kptr, uptr, kctrl.length))
+			goto out;
+	}
+
+	kctrl.data = kptr;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, USBDEVFS_CONTROL, (unsigned long)&kctrl);
+	set_fs(old_fs);
+
+	if (err >= 0 &&
+	    ((kctrl.requesttype & 0x80) != 0)) {
+		if (copy_to_user(uptr, kptr, kctrl.length))
+			err = -EFAULT;
+	}
+
+out:
+	free_page((unsigned long) kptr);
+	return err;
+}
+
+struct usbdevfs_bulktransfer32 {
+	unsigned int ep;
+	unsigned int len;
+	unsigned int timeout; /* in milliseconds */
+	__u32 data;
+};
+
+#define USBDEVFS_BULK32              _IOWR('U', 2, struct usbdevfs_bulktransfer32)
+
+static int do_usbdevfs_bulk(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct usbdevfs_bulktransfer kbulk;
+	struct usbdevfs_bulktransfer32 *ubulk;
+	mm_segment_t old_fs;
+	__u32 udata;
+	void *uptr, *kptr;
+	int err;
+
+	ubulk = (struct usbdevfs_bulktransfer32 *) arg;
+
+	if (get_user(kbulk.ep, &ubulk->ep) ||
+	    get_user(kbulk.len, &ubulk->len) ||
+	    get_user(kbulk.timeout, &ubulk->timeout) ||
+	    get_user(udata, &ubulk->data))
+		return -EFAULT;
+
+	uptr = (void *) A(udata);
+
+	/* In usbdevice_fs, it limits the control buffer to a page,
+	 * for simplicity so do we.
+	 */
+	if (!uptr || kbulk.len > PAGE_SIZE)
+		return -EINVAL;
+
+	kptr = (void *) __get_free_page(GFP_KERNEL);
+
+	if ((kbulk.ep & 0x80) == 0) {
+		err = -EFAULT;
+		if (copy_from_user(kptr, uptr, kbulk.len))
+			goto out;
+	}
+
+	kbulk.data = kptr;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, USBDEVFS_BULK, (unsigned long) &kbulk);
+	set_fs(old_fs);
+
+	if (err >= 0 &&
+	    ((kbulk.ep & 0x80) != 0)) {
+		if (copy_to_user(uptr, kptr, kbulk.len))
+			err = -EFAULT;
+	}
+
+out:
+	free_page((unsigned long) kptr);
+	return err;
+}
+
+/* This needs more work before we can enable it.  Unfortunately
+ * because of the fancy asynchronous way URB status/error is written
+ * back to userspace, we'll need to fiddle with USB devio internals
+ * and/or reimplement entirely the frontend of it ourselves. -DaveM
+ *
+ * The issue is:
+ *
+ *	When an URB is submitted via usbdevicefs it is put onto an
+ *	asynchronous queue.  When the URB completes, it may be reaped
+ *	via another ioctl.  During this reaping the status is written
+ *	back to userspace along with the length of the transfer.
+ *
+ *	We must translate into 64-bit kernel types so we pass in a kernel
+ *	space copy of the usbdevfs_urb structure.  This would mean that we
+ *	must do something to deal with the async entry reaping.  First we
+ *	have to deal somehow with this transitory memory we've allocated.
+ *	This is problematic since there are many call sites from which the
+ *	async entries can be destroyed (and thus when we'd need to free up
+ *	this kernel memory).  One of which is the close() op of usbdevicefs.
+ *	To handle that we'd need to make our own file_operations struct which
+ *	overrides usbdevicefs's release op with our own which runs usbdevicefs's
+ *	real release op then frees up the kernel memory.
+ *
+ *	But how to keep track of these kernel buffers?  We'd need to either
+ *	keep track of them in some table _or_ know about usbdevicefs internals
+ *	(ie. the exact layout of it's file private, which is actually defined
+ *	in linux/usbdevice_fs.h, the layout of the async queues are private to
+ *	devio.c)
+ *
+ * There is one possible other solution I considered, also involving knowledge
+ * of usbdevicefs internals:
+ *
+ *	After an URB is submitted, we "fix up" the address back to the user
+ *	space one.  This would work if the status/length fields written back
+ *	by the async URB completion lines up perfectly in the 32-bit type with
+ *	the 64-bit kernel type.  Unfortunately, it does not because the iso
+ *	frame descriptors, at the end of the struct, can be written back.
+ *
+ * I think we'll just need to simply duplicate the devio URB engine here.
+ */
+#if 0
+struct usbdevfs_urb32 {
+	__u8 type;
+	__u8 endpoint;
+	__s32 status;
+	__u32 flags;
+	__u32 buffer;
+	__s32 buffer_length;
+	__s32 actual_length;
+	__s32 start_frame;
+	__s32 number_of_packets;
+	__s32 error_count;
+	__u32 signr;
+	__u32 usercontext; /* unused */
+	struct usbdevfs_iso_packet_desc iso_frame_desc[0];
+};
+
+#define USBDEVFS_SUBMITURB32       _IOR('U', 10, struct usbdevfs_urb32)
+
+static int get_urb32(struct usbdevfs_urb *kurb,
+		     struct usbdevfs_urb32 *uurb)
+{
+	if (get_user(kurb->type, &uurb->type) ||
+	    __get_user(kurb->endpoint, &uurb->endpoint) ||
+	    __get_user(kurb->status, &uurb->status) ||
+	    __get_user(kurb->flags, &uurb->flags) ||
+	    __get_user(kurb->buffer_length, &uurb->buffer_length) ||
+	    __get_user(kurb->actual_length, &uurb->actual_length) ||
+	    __get_user(kurb->start_frame, &uurb->start_frame) ||
+	    __get_user(kurb->number_of_packets, &uurb->number_of_packets) ||
+	    __get_user(kurb->error_count, &uurb->error_count) ||
+	    __get_user(kurb->signr, &uurb->signr))
+		return -EFAULT;
+
+	kurb->usercontext = 0; /* unused currently */
+
+	return 0;
+}
+
+/* Just put back the values which usbdevfs actually changes. */
+static int put_urb32(struct usbdevfs_urb *kurb,
+		     struct usbdevfs_urb32 *uurb)
+{
+	if (put_user(kurb->status, &uurb->status) ||
+	    __put_user(kurb->actual_length, &uurb->actual_length) ||
+	    __put_user(kurb->error_count, &uurb->error_count))
+		return -EFAULT;
+
+	if (kurb->number_of_packets != 0) {
+		int i;
+
+		for (i = 0; i < kurb->number_of_packets; i++) {
+			if (__put_user(kurb->iso_frame_desc[i].actual_length,
+				       &uurb->iso_frame_desc[i].actual_length) ||
+			    __put_user(kurb->iso_frame_desc[i].status,
+				       &uurb->iso_frame_desc[i].status))
+				return -EFAULT;
+		}
+	}
+
+	return 0;
+}
+
+static int get_urb32_isoframes(struct usbdevfs_urb *kurb,
+			       struct usbdevfs_urb32 *uurb)
+{
+	unsigned int totlen;
+	int i;
+
+	if (kurb->type != USBDEVFS_URB_TYPE_ISO) {
+		kurb->number_of_packets = 0;
+		return 0;
+	}
+
+	if (kurb->number_of_packets < 1 ||
+	    kurb->number_of_packets > 128)
+		return -EINVAL;
+
+	if (copy_from_user(&kurb->iso_frame_desc[0],
+			   &uurb->iso_frame_desc[0],
+			   sizeof(struct usbdevfs_iso_packet_desc) *
+			   kurb->number_of_packets))
+		return -EFAULT;
+
+	totlen = 0;
+	for (i = 0; i < kurb->number_of_packets; i++) {
+		unsigned int this_len;
+
+		this_len = kurb->iso_frame_desc[i].length;
+		if (this_len > 1023)
+			return -EINVAL;
+
+		totlen += this_len;
+	}
+
+	if (totlen > 32768)
+		return -EINVAL;
+
+	kurb->buffer_length = totlen;
+
+	return 0;
+}
+
+static int do_usbdevfs_urb(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct usbdevfs_urb *kurb;
+	struct usbdevfs_urb32 *uurb;
+	mm_segment_t old_fs;
+	__u32 udata;
+	void *uptr, *kptr;
+	unsigned int buflen;
+	int err;
+
+	uurb = (struct usbdevfs_urb32 *) arg;
+
+	err = -ENOMEM;
+	kurb = kmalloc(sizeof(struct usbdevfs_urb) +
+		       (sizeof(struct usbdevfs_iso_packet_desc) * 128),
+		       GFP_KERNEL);
+	if (!kurb)
+		goto out;
+
+	err = -EFAULT;
+	if (get_urb32(kurb, uurb))
+		goto out;
+
+	err = get_urb32_isoframes(kurb, uurb);
+	if (err)
+		goto out;
+
+	err = -EFAULT;
+	if (__get_user(udata, &uurb->buffer))
+		goto out;
+	uptr = (void *) A(udata);
+
+	err = -ENOMEM;
+	buflen = kurb->buffer_length;
+	kptr = kmalloc(buflen, GFP_KERNEL);
+	if (!kptr)
+		goto out;
+
+	kurb->buffer = kptr;
+
+	err = -EFAULT;
+	if (copy_from_user(kptr, uptr, buflen))
+		goto out_kptr;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, USBDEVFS_SUBMITURB, (unsigned long) kurb);
+	set_fs(old_fs);
+
+	if (err >= 0) {
+		/* XXX Shit, this doesn't work for async URBs :-( XXX */
+		if (put_urb32(kurb, uurb)) {
+			err = -EFAULT;
+		} else if ((kurb->endpoint & USB_DIR_IN) != 0) {
+			if (copy_to_user(uptr, kptr, buflen))
+				err = -EFAULT;
+		}
+	}
+
+out_kptr:
+	kfree(kptr);
+
+out:
+	kfree(kurb);
+	return err;
+}
+#endif
+
+#define USBDEVFS_REAPURB32         _IOW('U', 12, u32)
+#define USBDEVFS_REAPURBNDELAY32   _IOW('U', 13, u32)
+
+static int do_usbdevfs_reapurb(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs;
+	void *kptr;
+	int err;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd,
+			(cmd == USBDEVFS_REAPURB32 ?
+			 USBDEVFS_REAPURB :
+			 USBDEVFS_REAPURBNDELAY),
+			(unsigned long) &kptr);
+	set_fs(old_fs);
+
+	if (err >= 0 &&
+	    put_user(((u32)(long)kptr), (u32 *) A(arg)))
+		err = -EFAULT;
+
+	return err;
+}
+
+struct usbdevfs_disconnectsignal32 {
+	unsigned int signr;
+	u32 context;
+};
+
+#define USBDEVFS_DISCSIGNAL32      _IOR('U', 14, struct usbdevfs_disconnectsignal32)
+
+static int do_usbdevfs_discsignal(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct usbdevfs_disconnectsignal kdis;
+	struct usbdevfs_disconnectsignal32 *udis;
+	mm_segment_t old_fs;
+	u32 uctx;
+	int err;
+
+	udis = (struct usbdevfs_disconnectsignal32 *) arg;
+
+	if (get_user(kdis.signr, &udis->signr) ||
+	    __get_user(uctx, &udis->context))
+		return -EFAULT;
+
+	kdis.context = (void *) (long)uctx;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, USBDEVFS_DISCSIGNAL, (unsigned long) &kdis);
+	set_fs(old_fs);
+
+	return err;
+}
+
+struct mtd_oob_buf32 {
+	u32 start;
+	u32 length;
+	u32 ptr;	/* unsigned char* */
+};
+
+#define MEMWRITEOOB32 	_IOWR('M',3,struct mtd_oob_buf32)
+#define MEMREADOOB32 	_IOWR('M',4,struct mtd_oob_buf32)
+
+static int mtd_rw_oob(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t 			old_fs 	= get_fs();
+	struct mtd_oob_buf32	*uarg 	= (struct mtd_oob_buf32 *)arg;
+	struct mtd_oob_buf		karg;
+	u32 tmp;
+	char *ptr;
+	int ret;
+
+	if (get_user(karg.start, &uarg->start) 		||
+	    get_user(karg.length, &uarg->length)	||
+	    get_user(tmp, &uarg->ptr))
+		return -EFAULT;
+
+	ptr = (char *)A(tmp);
+	if (0 >= karg.length) 
+		return -EINVAL;
+
+	karg.ptr = kmalloc(karg.length, GFP_KERNEL);
+	if (NULL == karg.ptr)
+		return -ENOMEM;
+
+	if (copy_from_user(karg.ptr, ptr, karg.length)) {
+		kfree(karg.ptr);
+		return -EFAULT;
+	}
+
+	set_fs(KERNEL_DS);
+	if (MEMREADOOB32 == cmd) 
+		ret = sys_ioctl(fd, MEMREADOOB, (unsigned long)&karg);
+	else if (MEMWRITEOOB32 == cmd)
+		ret = sys_ioctl(fd, MEMWRITEOOB, (unsigned long)&karg);
+	else
+		ret = -EINVAL;
+	set_fs(old_fs);
+
+	if (0 == ret && cmd == MEMREADOOB32) {
+		ret = copy_to_user(ptr, karg.ptr, karg.length);
+		ret |= put_user(karg.start, &uarg->start);
+		ret |= put_user(karg.length, &uarg->length);
+	}
+
+	kfree(karg.ptr);
+	return ((0 == ret) ? 0 : -EFAULT);
+}	
+
+/* /proc/mtrr ioctls */
+
+
+struct mtrr_sentry32
+{
+    unsigned int base;    /*  Base address     */
+    unsigned int size;    /*  Size of region   */
+    unsigned int type;     /*  Type of region   */
+};
+
+struct mtrr_gentry32
+{
+    unsigned int regnum;   /*  Register number  */
+    unsigned int base;    /*  Base address     */
+    unsigned int size;    /*  Size of region   */
+    unsigned int type;     /*  Type of region   */
+};
+
+#define	MTRR_IOCTL_BASE	'M'
+
+#define MTRRIOC32_ADD_ENTRY        _IOW(MTRR_IOCTL_BASE,  0, struct mtrr_sentry32)
+#define MTRRIOC32_SET_ENTRY        _IOW(MTRR_IOCTL_BASE,  1, struct mtrr_sentry32)
+#define MTRRIOC32_DEL_ENTRY        _IOW(MTRR_IOCTL_BASE,  2, struct mtrr_sentry32)
+#define MTRRIOC32_GET_ENTRY        _IOWR(MTRR_IOCTL_BASE, 3, struct mtrr_gentry32)
+#define MTRRIOC32_KILL_ENTRY       _IOW(MTRR_IOCTL_BASE,  4, struct mtrr_sentry32)
+#define MTRRIOC32_ADD_PAGE_ENTRY   _IOW(MTRR_IOCTL_BASE,  5, struct mtrr_sentry32)
+#define MTRRIOC32_SET_PAGE_ENTRY   _IOW(MTRR_IOCTL_BASE,  6, struct mtrr_sentry32)
+#define MTRRIOC32_DEL_PAGE_ENTRY   _IOW(MTRR_IOCTL_BASE,  7, struct mtrr_sentry32)
+#define MTRRIOC32_GET_PAGE_ENTRY   _IOWR(MTRR_IOCTL_BASE, 8, struct mtrr_gentry32)
+#define MTRRIOC32_KILL_PAGE_ENTRY  _IOW(MTRR_IOCTL_BASE,  9, struct mtrr_sentry32)
+
+
+static int mtrr_ioctl32(unsigned int fd, unsigned int cmd, unsigned long arg)
+{ 
+	struct mtrr_gentry g;
+	struct mtrr_sentry s;
+	int get = 0, err = 0; 
+	struct mtrr_gentry32 *g32 = (struct mtrr_gentry32 *)arg; 
+	mm_segment_t oldfs = get_fs(); 
+
+	switch (cmd) { 
+#define SET(x) case MTRRIOC32_ ## x ## _ENTRY: cmd = MTRRIOC_ ## x ## _ENTRY; break 
+#define GET(x) case MTRRIOC32_ ## x ## _ENTRY: cmd = MTRRIOC_ ## x ## _ENTRY; get=1; break
+		SET(ADD);
+		SET(SET); 
+		SET(DEL);
+		GET(GET); 
+		SET(KILL);
+		SET(ADD_PAGE); 
+		SET(SET_PAGE); 
+		SET(DEL_PAGE); 
+		GET(GET_PAGE); 
+		SET(KILL_PAGE); 
+	} 
+	
+	if (get) { 
+		err = get_user(g.regnum, &g32->regnum);
+		err |= get_user(g.base, &g32->base);
+		err |= get_user(g.size, &g32->size);
+		err |= get_user(g.type, &g32->type); 
+
+		arg = (unsigned long)&g; 
+	} else { 
+		struct mtrr_sentry32 *s32 = (struct mtrr_sentry32 *)arg;
+		err = get_user(s.base, &s32->base);
+		err |= get_user(s.size, &s32->size);
+		err |= get_user(s.type, &s32->type);
+
+		arg = (unsigned long)&s; 
+	} 
+	if (err) return err;
+	
+	set_fs(KERNEL_DS); 
+	err = sys_ioctl(fd, cmd, arg); 
+	set_fs(oldfs); 
+		
+	if (!err && get) { 
+		err = put_user(g.base, &g32->base);
+		err |= put_user(g.size, &g32->size);
+		err |= put_user(g.regnum, &g32->regnum);
+		err |= put_user(g.type, &g32->type); 
+	} 
+	return err;
+} 
+
 struct ioctl_trans {
 	unsigned long cmd;
 	int (*handler)(unsigned int, unsigned int, unsigned long, struct file * filp);
@@ -3260,7 +3638,6 @@
 COMPATIBLE_IOCTL(TCSETSW)
 COMPATIBLE_IOCTL(TCSETSF)
 COMPATIBLE_IOCTL(TIOCLINUX)
-HANDLE_IOCTL(TIOCGDEV, tiocgdev)
 /* Little t */
 COMPATIBLE_IOCTL(TIOCGETD)
 COMPATIBLE_IOCTL(TIOCSETD)
@@ -3285,6 +3662,7 @@
 COMPATIBLE_IOCTL(TIOCGPTN)
 COMPATIBLE_IOCTL(TIOCSPTLCK)
 COMPATIBLE_IOCTL(TIOCSERGETLSR)
+/* Big F */
 COMPATIBLE_IOCTL(FBIOGET_VSCREENINFO)
 COMPATIBLE_IOCTL(FBIOPUT_VSCREENINFO)
 COMPATIBLE_IOCTL(FBIOPAN_DISPLAY)
@@ -3344,7 +3722,6 @@
 COMPATIBLE_IOCTL(BLKFRASET)
 COMPATIBLE_IOCTL(BLKSECTSET)
 COMPATIBLE_IOCTL(BLKSSZGET)
-
 /* RAID */
 COMPATIBLE_IOCTL(RAID_VERSION)
 COMPATIBLE_IOCTL(GET_ARRAY_INFO)
@@ -3365,7 +3742,6 @@
 COMPATIBLE_IOCTL(STOP_ARRAY)
 COMPATIBLE_IOCTL(STOP_ARRAY_RO)
 COMPATIBLE_IOCTL(RESTART_ARRAY_RW)
-
 /* Big K */
 COMPATIBLE_IOCTL(PIO_FONT)
 COMPATIBLE_IOCTL(GIO_FONT)
@@ -3387,6 +3763,7 @@
 COMPATIBLE_IOCTL(KDSKBSENT)
 COMPATIBLE_IOCTL(KDGKBDIACR)
 COMPATIBLE_IOCTL(KDSKBDIACR)
+COMPATIBLE_IOCTL(KDKBDREP)
 COMPATIBLE_IOCTL(KDGKBLED)
 COMPATIBLE_IOCTL(KDSKBLED)
 COMPATIBLE_IOCTL(KDGETLED)
@@ -3406,6 +3783,14 @@
 COMPATIBLE_IOCTL(SCSI_IOCTL_TAGGED_DISABLE)
 COMPATIBLE_IOCTL(SCSI_IOCTL_GET_BUS_NUMBER)
 COMPATIBLE_IOCTL(SCSI_IOCTL_SEND_COMMAND)
+COMPATIBLE_IOCTL(SCSI_IOCTL_PROBE_HOST)
+COMPATIBLE_IOCTL(SCSI_IOCTL_GET_PCI)
+/* Big T */
+COMPATIBLE_IOCTL(TUNSETNOCSUM)
+COMPATIBLE_IOCTL(TUNSETDEBUG)
+COMPATIBLE_IOCTL(TUNSETIFF)
+COMPATIBLE_IOCTL(TUNSETPERSIST)
+COMPATIBLE_IOCTL(TUNSETOWNER)
 /* Big V */
 COMPATIBLE_IOCTL(VT_SETMODE)
 COMPATIBLE_IOCTL(VT_GETMODE)
@@ -3419,7 +3804,8 @@
 COMPATIBLE_IOCTL(VT_RESIZEX)
 COMPATIBLE_IOCTL(VT_LOCKSWITCH)
 COMPATIBLE_IOCTL(VT_UNLOCKSWITCH)
-/* Little v, the video4linux ioctls */
+/* Little v */
+/* Little v, the video4linux ioctls (conflict?) */
 COMPATIBLE_IOCTL(VIDIOCGCAP)
 COMPATIBLE_IOCTL(VIDIOCGCHAN)
 COMPATIBLE_IOCTL(VIDIOCSCHAN)
@@ -3459,11 +3845,6 @@
 COMPATIBLE_IOCTL(RTC_SET_TIME)
 COMPATIBLE_IOCTL(RTC_WKALM_SET)
 COMPATIBLE_IOCTL(RTC_WKALM_RD)
-HANDLE_IOCTL(RTC_IRQP_READ,  rtc32_ioctl)
-HANDLE_IOCTL(RTC_IRQP_READ32,rtc32_ioctl)
-HANDLE_IOCTL(RTC_IRQP_SET32, rtc32_ioctl)
-HANDLE_IOCTL(RTC_EPOCH_READ32, rtc32_ioctl)
-HANDLE_IOCTL(RTC_EPOCH_SET32, rtc32_ioctl)
 /* Little m */
 COMPATIBLE_IOCTL(MTIOCTOP)
 /* Socket level stuff */
@@ -3485,6 +3866,11 @@
 COMPATIBLE_IOCTL(SIOCDRARP)
 COMPATIBLE_IOCTL(SIOCADDDLCI)
 COMPATIBLE_IOCTL(SIOCDELDLCI)
+COMPATIBLE_IOCTL(SIOCGMIIPHY)
+COMPATIBLE_IOCTL(SIOCGMIIREG)
+COMPATIBLE_IOCTL(SIOCSMIIREG)
+COMPATIBLE_IOCTL(SIOCGIFVLAN)
+COMPATIBLE_IOCTL(SIOCSIFVLAN)
 /* SG stuff */
 COMPATIBLE_IOCTL(SG_SET_TIMEOUT)
 COMPATIBLE_IOCTL(SG_GET_TIMEOUT)
@@ -3506,7 +3892,6 @@
 COMPATIBLE_IOCTL(SG_GET_VERSION_NUM)
 COMPATIBLE_IOCTL(SG_NEXT_CMD_LEN)
 COMPATIBLE_IOCTL(SG_SCSI_RESET)
-COMPATIBLE_IOCTL(SG_IO)
 COMPATIBLE_IOCTL(SG_GET_REQUEST_TABLE)
 COMPATIBLE_IOCTL(SG_SET_KEEP_ORPHAN)
 COMPATIBLE_IOCTL(SG_GET_KEEP_ORPHAN)
@@ -3524,10 +3909,14 @@
 COMPATIBLE_IOCTL(PPPIOCGXASYNCMAP)
 COMPATIBLE_IOCTL(PPPIOCSXASYNCMAP)
 COMPATIBLE_IOCTL(PPPIOCXFERUNIT)
+/* PPPIOCSCOMPRESS is translated */
 COMPATIBLE_IOCTL(PPPIOCGNPMODE)
 COMPATIBLE_IOCTL(PPPIOCSNPMODE)
 COMPATIBLE_IOCTL(PPPIOCGDEBUG)
 COMPATIBLE_IOCTL(PPPIOCSDEBUG)
+/* PPPIOCSPASS is translated */
+/* PPPIOCSACTIVE is translated */
+/* PPPIOCGIDLE is translated */
 COMPATIBLE_IOCTL(PPPIOCNEWUNIT)
 COMPATIBLE_IOCTL(PPPIOCATTACH)
 COMPATIBLE_IOCTL(PPPIOCDETACH)
@@ -3537,8 +3926,10 @@
 COMPATIBLE_IOCTL(PPPIOCATTCHAN)
 COMPATIBLE_IOCTL(PPPIOCGCHAN)
 /* PPPOX */
-COMPATIBLE_IOCTL(PPPOEIOCSFWD);
-COMPATIBLE_IOCTL(PPPOEIOCDFWD);
+COMPATIBLE_IOCTL(PPPOEIOCSFWD)
+COMPATIBLE_IOCTL(PPPOEIOCDFWD)
+/* LP */
+COMPATIBLE_IOCTL(LPGETSTATUS)
 /* CDROM stuff */
 COMPATIBLE_IOCTL(CDROMPAUSE)
 COMPATIBLE_IOCTL(CDROMRESUME)
@@ -3570,9 +3961,15 @@
 COMPATIBLE_IOCTL(CDROM_LOCKDOOR)
 COMPATIBLE_IOCTL(CDROM_DEBUG)
 COMPATIBLE_IOCTL(CDROM_GET_CAPABILITY)
+/* DVD ioctls */
+COMPATIBLE_IOCTL(DVD_READ_STRUCT)
+COMPATIBLE_IOCTL(DVD_WRITE_STRUCT)
+COMPATIBLE_IOCTL(DVD_AUTH)
 /* Big L */
 COMPATIBLE_IOCTL(LOOP_SET_FD)
 COMPATIBLE_IOCTL(LOOP_CLR_FD)
+/* Big A */
+/* sparc only */
 /* Big Q for sound/OSS */
 COMPATIBLE_IOCTL(SNDCTL_SEQ_RESET)
 COMPATIBLE_IOCTL(SNDCTL_SEQ_SYNC)
@@ -3731,6 +4128,7 @@
 COMPATIBLE_IOCTL(AUTOFS_IOC_CATATONIC)
 COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOVER)
 COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE)
+COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE_MULTI)
 /* DEVFS */
 COMPATIBLE_IOCTL(DEVFSDIOC_GET_PROTO_REV)
 COMPATIBLE_IOCTL(DEVFSDIOC_SET_EVENT_MASK)
@@ -3776,64 +4174,79 @@
 COMPATIBLE_IOCTL(LV_BMAP)
 COMPATIBLE_IOCTL(LV_SNAPSHOT_USE_RATE)
 #endif /* LVM */
-#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
-COMPATIBLE_IOCTL(DRM_IOCTL_GET_MAGIC)
-COMPATIBLE_IOCTL(DRM_IOCTL_IRQ_BUSID)
-COMPATIBLE_IOCTL(DRM_IOCTL_AUTH_MAGIC)
-COMPATIBLE_IOCTL(DRM_IOCTL_BLOCK)
-COMPATIBLE_IOCTL(DRM_IOCTL_UNBLOCK)
-COMPATIBLE_IOCTL(DRM_IOCTL_CONTROL)
-COMPATIBLE_IOCTL(DRM_IOCTL_ADD_BUFS)
-COMPATIBLE_IOCTL(DRM_IOCTL_MARK_BUFS)
-COMPATIBLE_IOCTL(DRM_IOCTL_ADD_CTX)
-COMPATIBLE_IOCTL(DRM_IOCTL_RM_CTX)
-COMPATIBLE_IOCTL(DRM_IOCTL_MOD_CTX)
-COMPATIBLE_IOCTL(DRM_IOCTL_GET_CTX)
-COMPATIBLE_IOCTL(DRM_IOCTL_SWITCH_CTX)
-COMPATIBLE_IOCTL(DRM_IOCTL_NEW_CTX)
-COMPATIBLE_IOCTL(DRM_IOCTL_ADD_DRAW)
-COMPATIBLE_IOCTL(DRM_IOCTL_RM_DRAW)
-COMPATIBLE_IOCTL(DRM_IOCTL_LOCK)
-COMPATIBLE_IOCTL(DRM_IOCTL_UNLOCK)
-COMPATIBLE_IOCTL(DRM_IOCTL_FINISH)
-#endif /* DRM */
 #ifdef CONFIG_AUTOFS_FS
-COMPATIBLE_IOCTL(AUTOFS_IOC_READY);
-COMPATIBLE_IOCTL(AUTOFS_IOC_FAIL);
-COMPATIBLE_IOCTL(AUTOFS_IOC_CATATONIC);
-COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOVER);
-COMPATIBLE_IOCTL(AUTOFS_IOC_SETTIMEOUT);
-COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE);
+COMPATIBLE_IOCTL(AUTOFS_IOC_READY)
+COMPATIBLE_IOCTL(AUTOFS_IOC_FAIL)
+COMPATIBLE_IOCTL(AUTOFS_IOC_CATATONIC)
+COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOVER)
+COMPATIBLE_IOCTL(AUTOFS_IOC_SETTIMEOUT)
+COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE)
 #endif
 #ifdef CONFIG_RTC
-COMPATIBLE_IOCTL(RTC_AIE_ON);
-COMPATIBLE_IOCTL(RTC_AIE_OFF);
-COMPATIBLE_IOCTL(RTC_UIE_ON);
-COMPATIBLE_IOCTL(RTC_UIE_OFF);
-COMPATIBLE_IOCTL(RTC_PIE_ON);
-COMPATIBLE_IOCTL(RTC_PIE_OFF);
-COMPATIBLE_IOCTL(RTC_WIE_ON);
-COMPATIBLE_IOCTL(RTC_WIE_OFF);
-COMPATIBLE_IOCTL(RTC_ALM_SET);
-COMPATIBLE_IOCTL(RTC_ALM_READ);
-COMPATIBLE_IOCTL(RTC_RD_TIME);
-COMPATIBLE_IOCTL(RTC_SET_TIME);
-COMPATIBLE_IOCTL(RTC_IRQP_READ);
-COMPATIBLE_IOCTL(RTC_IRQP_SET);
-COMPATIBLE_IOCTL(RTC_EPOCH_READ);
-COMPATIBLE_IOCTL(RTC_EPOCH_SET);
-COMPATIBLE_IOCTL(RTC_WKALM_SET);
-COMPATIBLE_IOCTL(RTC_WKALM_RD);
+COMPATIBLE_IOCTL(RTC_AIE_ON)
+COMPATIBLE_IOCTL(RTC_AIE_OFF)
+COMPATIBLE_IOCTL(RTC_UIE_ON)
+COMPATIBLE_IOCTL(RTC_UIE_OFF)
+COMPATIBLE_IOCTL(RTC_PIE_ON)
+COMPATIBLE_IOCTL(RTC_PIE_OFF)
+COMPATIBLE_IOCTL(RTC_WIE_ON)
+COMPATIBLE_IOCTL(RTC_WIE_OFF)
+COMPATIBLE_IOCTL(RTC_ALM_SET)
+COMPATIBLE_IOCTL(RTC_ALM_READ)
+COMPATIBLE_IOCTL(RTC_RD_TIME)
+COMPATIBLE_IOCTL(RTC_SET_TIME)
+COMPATIBLE_IOCTL(RTC_WKALM_SET)
+COMPATIBLE_IOCTL(RTC_WKALM_RD)
 #endif
-HANDLE_IOCTL(REISERFS_IOC_UNPACK32, reiserfs_ioctl32);
-HANDLE_IOCTL(VFAT_IOCTL_READDIR_BOTH32, vfat_ioctl32);
-HANDLE_IOCTL(VFAT_IOCTL_READDIR_SHORT32, vfat_ioctl32);
-/* serial driver */ 
-HANDLE_IOCTL(TIOCGSERIAL, serial_struct_ioctl);
-HANDLE_IOCTL(TIOCSSERIAL, serial_struct_ioctl);
-/* elevator */
-COMPATIBLE_IOCTL(BLKELVGET)
-COMPATIBLE_IOCTL(BLKELVSET)
+/* Big W */
+/* WIOC_GETSUPPORT not yet implemented -E */
+COMPATIBLE_IOCTL(WDIOC_GETSTATUS)
+COMPATIBLE_IOCTL(WDIOC_GETBOOTSTATUS)
+COMPATIBLE_IOCTL(WDIOC_GETTEMP)
+COMPATIBLE_IOCTL(WDIOC_SETOPTIONS)
+COMPATIBLE_IOCTL(WDIOC_KEEPALIVE)
+#if 0 /* sparc only ? */
+COMPATIBLE_IOCTL(WIOCSTART)
+COMPATIBLE_IOCTL(WIOCSTOP)
+COMPATIBLE_IOCTL(WIOCGSTAT)
+#endif
+/* Big R */
+COMPATIBLE_IOCTL(RNDGETENTCNT)
+COMPATIBLE_IOCTL(RNDADDTOENTCNT)
+COMPATIBLE_IOCTL(RNDGETPOOL)
+COMPATIBLE_IOCTL(RNDADDENTROPY)
+COMPATIBLE_IOCTL(RNDZAPENTCNT)
+COMPATIBLE_IOCTL(RNDCLEARPOOL)
+/* Bluetooth ioctls */
+COMPATIBLE_IOCTL(HCIDEVUP)
+COMPATIBLE_IOCTL(HCIDEVDOWN)
+COMPATIBLE_IOCTL(HCIDEVRESET)
+COMPATIBLE_IOCTL(HCIDEVRESTAT)
+COMPATIBLE_IOCTL(HCIGETDEVLIST)
+COMPATIBLE_IOCTL(HCIGETDEVINFO)
+COMPATIBLE_IOCTL(HCIGETCONNLIST)
+COMPATIBLE_IOCTL(HCIGETCONNINFO)
+COMPATIBLE_IOCTL(HCISETRAW)
+COMPATIBLE_IOCTL(HCISETSCAN)
+COMPATIBLE_IOCTL(HCISETAUTH)
+COMPATIBLE_IOCTL(HCISETENCRYPT)
+COMPATIBLE_IOCTL(HCISETPTYPE)
+COMPATIBLE_IOCTL(HCISETLINKPOL)
+COMPATIBLE_IOCTL(HCISETLINKMODE)
+COMPATIBLE_IOCTL(HCISETACLMTU)
+COMPATIBLE_IOCTL(HCISETSCOMTU)
+COMPATIBLE_IOCTL(HCIINQUIRY)
+COMPATIBLE_IOCTL(HCIUARTSETPROTO)
+COMPATIBLE_IOCTL(HCIUARTGETPROTO)
+COMPATIBLE_IOCTL(RFCOMMCREATEDEV)
+COMPATIBLE_IOCTL(RFCOMMRELEASEDEV)
+COMPATIBLE_IOCTL(RFCOMMGETDEVLIST)
+COMPATIBLE_IOCTL(RFCOMMGETDEVINFO)
+COMPATIBLE_IOCTL(RFCOMMSTEALDLC)
+COMPATIBLE_IOCTL(BNEPCONNADD)
+COMPATIBLE_IOCTL(BNEPCONNDEL)
+COMPATIBLE_IOCTL(BNEPGETCONNLIST)
+COMPATIBLE_IOCTL(BNEPGETCONNINFO)
 /* Misc. */
 COMPATIBLE_IOCTL(0x41545900)		/* ATYIO_CLKR */
 COMPATIBLE_IOCTL(0x41545901)		/* ATYIO_CLKW */
@@ -3841,8 +4254,46 @@
 COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_IO)
 COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_MEM)
 COMPATIBLE_IOCTL(PCIIOC_WRITE_COMBINE)
+COMPATIBLE_IOCTL(0x4B50);   /* KDGHWCLK - not in the kernel, but don't complain */
+COMPATIBLE_IOCTL(0x4B51);   /* KDSHWCLK - not in the kernel, but don't complain */
+/* USB */
+COMPATIBLE_IOCTL(USBDEVFS_RESETEP)
+COMPATIBLE_IOCTL(USBDEVFS_SETINTERFACE)
+COMPATIBLE_IOCTL(USBDEVFS_SETCONFIGURATION)
+COMPATIBLE_IOCTL(USBDEVFS_GETDRIVER)
+COMPATIBLE_IOCTL(USBDEVFS_DISCARDURB)
+COMPATIBLE_IOCTL(USBDEVFS_CLAIMINTERFACE)
+COMPATIBLE_IOCTL(USBDEVFS_RELEASEINTERFACE)
+COMPATIBLE_IOCTL(USBDEVFS_CONNECTINFO)
+COMPATIBLE_IOCTL(USBDEVFS_HUB_PORTINFO)
+COMPATIBLE_IOCTL(USBDEVFS_RESET)
+COMPATIBLE_IOCTL(USBDEVFS_CLEAR_HALT)
+/* MTD */
+COMPATIBLE_IOCTL(MEMGETINFO)
+COMPATIBLE_IOCTL(MEMERASE)
+COMPATIBLE_IOCTL(MEMLOCK)
+COMPATIBLE_IOCTL(MEMUNLOCK)
+COMPATIBLE_IOCTL(MEMGETREGIONCOUNT)
+COMPATIBLE_IOCTL(MEMGETREGIONINFO)
+/* NBD */
+COMPATIBLE_IOCTL(NBD_SET_SOCK)
+COMPATIBLE_IOCTL(NBD_SET_BLKSIZE)
+COMPATIBLE_IOCTL(NBD_SET_SIZE)
+COMPATIBLE_IOCTL(NBD_DO_IT)
+COMPATIBLE_IOCTL(NBD_CLEAR_SOCK)
+COMPATIBLE_IOCTL(NBD_CLEAR_QUE)
+COMPATIBLE_IOCTL(NBD_PRINT_DEBUG)
+COMPATIBLE_IOCTL(NBD_SET_SIZE_BLOCKS)
+COMPATIBLE_IOCTL(NBD_DISCONNECT)
 /* And these ioctls need translation */
+HANDLE_IOCTL(TIOCGDEV, tiocgdev)
+HANDLE_IOCTL(TIOCGSERIAL, serial_struct_ioctl)
+HANDLE_IOCTL(TIOCSSERIAL, serial_struct_ioctl)
+HANDLE_IOCTL(MEMREADOOB32, mtd_rw_oob)
+HANDLE_IOCTL(MEMWRITEOOB32, mtd_rw_oob)
+#ifdef CONFIG_NET
 HANDLE_IOCTL(SIOCGIFNAME, dev_ifname32)
+#endif
 HANDLE_IOCTL(SIOCGIFCONF, dev_ifconf)
 HANDLE_IOCTL(SIOCGIFFLAGS, dev_ifsioc)
 HANDLE_IOCTL(SIOCSIFFLAGS, dev_ifsioc)
@@ -3869,14 +4320,26 @@
 HANDLE_IOCTL(SIOCSIFNETMASK, dev_ifsioc)
 HANDLE_IOCTL(SIOCSIFPFLAGS, dev_ifsioc)
 HANDLE_IOCTL(SIOCGIFPFLAGS, dev_ifsioc)
-HANDLE_IOCTL(SIOCGPPPSTATS, dev_ifsioc)
-HANDLE_IOCTL(SIOCGPPPCSTATS, dev_ifsioc)
-HANDLE_IOCTL(SIOCGPPPVER, dev_ifsioc)
 HANDLE_IOCTL(SIOCGIFTXQLEN, dev_ifsioc)
 HANDLE_IOCTL(SIOCSIFTXQLEN, dev_ifsioc)
 HANDLE_IOCTL(SIOCETHTOOL, ethtool_ioctl)
+HANDLE_IOCTL(SIOCBONDENSLAVE, bond_ioctl)
+HANDLE_IOCTL(SIOCBONDRELEASE, bond_ioctl)
+HANDLE_IOCTL(SIOCBONDSETHWADDR, bond_ioctl)
+HANDLE_IOCTL(SIOCBONDSLAVEINFOQUERY, bond_ioctl)
+HANDLE_IOCTL(SIOCBONDINFOQUERY, bond_ioctl)
+HANDLE_IOCTL(SIOCBONDCHANGEACTIVE, bond_ioctl)
 HANDLE_IOCTL(SIOCADDRT, routing_ioctl)
 HANDLE_IOCTL(SIOCDELRT, routing_ioctl)
+/* realtime device */
+HANDLE_IOCTL(RTC_IRQP_READ,  rtc32_ioctl)
+HANDLE_IOCTL(RTC_IRQP_READ32,rtc32_ioctl)
+HANDLE_IOCTL(RTC_IRQP_SET32, rtc32_ioctl)
+HANDLE_IOCTL(RTC_EPOCH_READ32, rtc32_ioctl)
+HANDLE_IOCTL(RTC_EPOCH_SET32, rtc32_ioctl)
+HANDLE_IOCTL(REISERFS_IOC_UNPACK32, reiserfs_ioctl32)
+HANDLE_IOCTL(VFAT_IOCTL_READDIR_BOTH32, vfat_ioctl32)
+HANDLE_IOCTL(VFAT_IOCTL_READDIR_SHORT32, vfat_ioctl32)
 /* Raw devices */
 HANDLE_IOCTL(RAW_SETBIND, raw_ioctl)
 /* Note SIOCRTMSG is no longer, so this is safe and * the user would have seen just an -EINVAL anyways. */
@@ -3888,6 +4351,7 @@
 HANDLE_IOCTL(0x1260, broken_blkgetsize)
 HANDLE_IOCTL(BLKFRAGET, w_long)
 HANDLE_IOCTL(BLKSECTGET, w_long)
+HANDLE_IOCTL(FBIOGET_FSCREENINFO, fb_ioctl_trans)
 HANDLE_IOCTL(BLKPG, blkpg_ioctl_trans)
 HANDLE_IOCTL(FBIOGETCMAP, fb_ioctl_trans)
 HANDLE_IOCTL(FBIOPUTCMAP, fb_ioctl_trans)
@@ -3907,8 +4371,11 @@
 HANDLE_IOCTL(FDPOLLDRVSTAT32, fd_ioctl_trans)
 HANDLE_IOCTL(FDGETFDCSTAT32, fd_ioctl_trans)
 HANDLE_IOCTL(FDWERRORGET32, fd_ioctl_trans)
+HANDLE_IOCTL(SG_IO,sg_ioctl_trans)
 HANDLE_IOCTL(PPPIOCGIDLE32, ppp_ioctl_trans)
 HANDLE_IOCTL(PPPIOCSCOMPRESS32, ppp_ioctl_trans)
+HANDLE_IOCTL(PPPIOCSPASS32, ppp_sock_fprog_ioctl_trans)
+HANDLE_IOCTL(PPPIOCSACTIVE32, ppp_sock_fprog_ioctl_trans)
 HANDLE_IOCTL(MTIOCGET32, mt_ioctl_trans)
 HANDLE_IOCTL(MTIOCPOS32, mt_ioctl_trans)
 HANDLE_IOCTL(MTIOCGETCONFIG32, mt_ioctl_trans)
@@ -3982,20 +4449,37 @@
 HANDLE_IOCTL(LV_STATUS_BYINDEX, do_lvm_ioctl)
 HANDLE_IOCTL(PV_CHANGE, do_lvm_ioctl)
 HANDLE_IOCTL(PV_STATUS, do_lvm_ioctl)
+HANDLE_IOCTL(VG_CREATE_OLD, do_lvm_ioctl)
+HANDLE_IOCTL(LV_STATUS_BYDEV, do_lvm_ioctl)
 #endif /* LVM */
-#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
-HANDLE_IOCTL(DRM32_IOCTL_VERSION, drm32_version);
-HANDLE_IOCTL(DRM32_IOCTL_GET_UNIQUE, drm32_getsetunique);
-HANDLE_IOCTL(DRM32_IOCTL_SET_UNIQUE, drm32_getsetunique);
-HANDLE_IOCTL(DRM32_IOCTL_ADD_MAP, drm32_addmap);
-HANDLE_IOCTL(DRM32_IOCTL_INFO_BUFS, drm32_info_bufs);
-HANDLE_IOCTL(DRM32_IOCTL_FREE_BUFS, drm32_free_bufs);
-HANDLE_IOCTL(DRM32_IOCTL_MAP_BUFS, drm32_map_bufs);
-HANDLE_IOCTL(DRM32_IOCTL_DMA, drm32_dma);
-HANDLE_IOCTL(DRM32_IOCTL_RES_CTX, drm32_res_ctx);
-#endif /* DRM */
-HANDLE_IOCTL(VFAT_IOCTL_READDIR_BOTH32, vfat_ioctl32);
-HANDLE_IOCTL(VFAT_IOCTL_READDIR_SHORT32, vfat_ioctl32);
+/* VFAT */
+HANDLE_IOCTL(VFAT_IOCTL_READDIR_BOTH32, vfat_ioctl32)
+HANDLE_IOCTL(VFAT_IOCTL_READDIR_SHORT32, vfat_ioctl32)
+HANDLE_IOCTL(USBDEVFS_CONTROL32, do_usbdevfs_control)
+HANDLE_IOCTL(USBDEVFS_BULK32, do_usbdevfs_bulk)
+/*HANDLE_IOCTL(USBDEVFS_SUBMITURB32, do_usbdevfs_urb)*/
+HANDLE_IOCTL(USBDEVFS_REAPURB32, do_usbdevfs_reapurb)
+HANDLE_IOCTL(USBDEVFS_REAPURBNDELAY32, do_usbdevfs_reapurb)
+HANDLE_IOCTL(USBDEVFS_DISCSIGNAL32, do_usbdevfs_discsignal)
+/* take care of sizeof(sizeof()) breakage */
+/* elevator */
+HANDLE_IOCTL(BLKELVGET_32, do_blkelvget)
+HANDLE_IOCTL(BLKELVSET_32, do_blkelvset)
+/* block stuff */
+HANDLE_IOCTL(BLKBSZGET_32, do_blkbszget)
+HANDLE_IOCTL(BLKBSZSET_32, do_blkbszset)
+HANDLE_IOCTL(BLKGETSIZE64_32, do_blkgetsize64)
+/* mtrr */
+HANDLE_IOCTL(MTRRIOC32_ADD_ENTRY, mtrr_ioctl32)
+HANDLE_IOCTL(MTRRIOC32_SET_ENTRY, mtrr_ioctl32)
+HANDLE_IOCTL(MTRRIOC32_DEL_ENTRY, mtrr_ioctl32)
+HANDLE_IOCTL(MTRRIOC32_GET_ENTRY, mtrr_ioctl32)
+HANDLE_IOCTL(MTRRIOC32_KILL_ENTRY, mtrr_ioctl32)
+HANDLE_IOCTL(MTRRIOC32_ADD_PAGE_ENTRY, mtrr_ioctl32)
+HANDLE_IOCTL(MTRRIOC32_SET_PAGE_ENTRY, mtrr_ioctl32)
+HANDLE_IOCTL(MTRRIOC32_DEL_PAGE_ENTRY, mtrr_ioctl32)
+HANDLE_IOCTL(MTRRIOC32_GET_PAGE_ENTRY, mtrr_ioctl32)
+HANDLE_IOCTL(MTRRIOC32_KILL_PAGE_ENTRY, mtrr_ioctl32)
 IOCTL_TABLE_END
 
 #define IOCTL_HASHSIZE 256
@@ -4099,7 +4583,7 @@
 /* Problem: 
    This function cannot unregister duplicate ioctls, because they are not
    unique.
-   When they happen we need to extend the prototype to pass handler too. */
+   When they happen we need to extend the prototype to pass the handler too. */
 
 int unregister_ioctl32_conversion(unsigned int cmd)
 {
@@ -4150,10 +4634,10 @@
 EXPORT_SYMBOL(register_ioctl32_conversion); 
 EXPORT_SYMBOL(unregister_ioctl32_conversion); 
 
-asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+asmlinkage long sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
 	struct file * filp;
-	int error = -EBADF;
+	long error = -EBADF;
 	int (*handler)(unsigned int, unsigned int, unsigned long, struct file * filp);
 	struct ioctl_trans *t;
 
@@ -4173,13 +4657,35 @@
 	if (t) {
 		handler = t->handler;
 		error = handler(fd, cmd, arg, filp);
+	} else if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) {
+		error = siocdevprivate_ioctl(fd, cmd, arg);
 	} else {
-		static int count = 0;
-		if (++count <= 50)
-			printk("sys32_ioctl(%s:%d): Unknown cmd fd(%d) "
-			       "cmd(%08x) arg(%08x)\n",
+		static int count;
+		if (++count <= 50) { 
+			char buf[10];
+			char *path = (char *)__get_free_page(GFP_KERNEL), *fn = "?"; 
+
+			/* find the name of the device. */
+			if (path) {
+				struct file *f = fget(fd); 
+				if (f) {
+					fn = d_path(f->f_dentry, f->f_vfsmnt, 
+						    path, PAGE_SIZE);
+					fput(f);
+				}
+			}
+
+			sprintf(buf,"'%c'", (cmd>>24) & 0x3f); 
+			if (!isprint(buf[1]))
+			    sprintf(buf, "%02x", buf[1]);
+			printk("ioctl32(%s:%d): Unknown cmd fd(%d) "
+			       "cmd(%08x){%s} arg(%08x) on %s\n",
 			       current->comm, current->pid,
-			       (int)fd, (unsigned int)cmd, (unsigned int)arg);
+			       (int)fd, (unsigned int)cmd, buf, (unsigned int)arg,
+			       fn);
+			if (path) 
+				free_page((unsigned long)path); 
+		}
 		error = -EINVAL;
 	}
 out:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/ia32/ia32_signal.c linux-2.4.21-pre6/arch/x86_64/ia32/ia32_signal.c
--- linux-2.4.20/arch/x86_64/ia32/ia32_signal.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/ia32/ia32_signal.c	2003-03-26 23:49:34.000000000 +0000
@@ -7,7 +7,7 @@
  *  2000-06-20  Pentium III FXSR, SSE support by Gareth Hughes
  *  2000-12-*   x86-64 compatibility mode signal handling by Andi Kleen
  * 
- *  $Id: ia32_signal.c,v 1.22 2002/07/29 10:34:03 ak Exp $
+ *  $Id: ia32_signal.c,v 1.31 2003/03/12 08:22:12 ak Exp $
  */
 
 #include <linux/sched.h>
@@ -33,6 +33,7 @@
 #include <asm/fpu32.h>
 
 #define ptr_to_u32(x) ((u32)(u64)(x))	/* avoid gcc warning */ 
+#define u32_to_ptr(x) ((void *)(u64)(x))
 
 #define DEBUG_SIG 0
 
@@ -45,9 +46,16 @@
 {
 	if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
 		return -EFAULT;
-	if (from->si_code < 0)
-		return __copy_to_user(to, from, sizeof(siginfo_t));
-	else {
+	if (from->si_code < 0) { 
+		/* the only field that's different is the alignment
+		   of the pointer in sigval_t. Move that 4 bytes down including
+		   padding. */
+		memmove(&((siginfo_t32 *)&from)->si_int,
+			&from->si_int, 
+			sizeof(siginfo_t) - offsetof(siginfo_t, si_int));
+		/* last 4 bytes stay the same */
+		return __copy_to_user(to, from, sizeof(siginfo_t32));
+	} else {
 		int err;
 
 		/* If you change siginfo_t structure, please be sure
@@ -57,7 +65,7 @@
 		   3 ints plus the relevant union member.  */
 		err = __put_user(from->si_signo, &to->si_signo);
 		err |= __put_user(from->si_errno, &to->si_errno);
-		err |= __put_user((short)from->si_code, &to->si_code);
+		err |= __put_user(from->si_code, &to->si_code);
 		/* First 32bits of unions are always present.  */
 		err |= __put_user(from->si_pid, &to->si_pid);
 		switch (from->si_code >> 16) {
@@ -76,7 +84,7 @@
 	}
 }
 
-asmlinkage int
+asmlinkage long
 sys32_sigsuspend(int history0, int history1, old_sigset_t mask, struct pt_regs regs)
 {
 	sigset_t saveset;
@@ -97,27 +105,32 @@
 	}
 }
 
-asmlinkage int
+asmlinkage long
 sys32_sigaltstack(const stack_ia32_t *uss_ptr, stack_ia32_t *uoss_ptr, 
 				  struct pt_regs regs)
 {
 	stack_t uss,uoss; 
 	int ret;
 	mm_segment_t seg; 
+	if (uss_ptr) {
+		u32 val32;
+		memset(&uss, 0, sizeof(stack_t));
 	if (!access_ok(VERIFY_READ,uss_ptr,sizeof(stack_ia32_t)) ||
-	    __get_user(ptr_to_u32(uss.ss_sp), &uss_ptr->ss_sp) ||
-	    __get_user((u32)uss.ss_flags, &uss_ptr->ss_flags) ||
-	    __get_user((u32)uss.ss_size, &uss_ptr->ss_size))
+		    __get_user(val32, &uss_ptr->ss_sp) ||
+		    __get_user(uss.ss_flags, &uss_ptr->ss_flags) ||
+		    __get_user(uss.ss_size, &uss_ptr->ss_size))
 		return -EFAULT;
+		uss.ss_sp = u32_to_ptr(val32);	
+	}
 	seg = get_fs(); 
 	set_fs(KERNEL_DS); 
-	ret = do_sigaltstack(&uss, &uoss, regs.rsp);
+	ret = do_sigaltstack(uss_ptr ? &uss : NULL, &uoss, regs.rsp);
 	set_fs(seg); 
 	if (ret >= 0 && uoss_ptr)  {
-		if (!access_ok(VERIFY_WRITE,uss_ptr,sizeof(stack_ia32_t)) ||
-		    __put_user(ptr_to_u32(uss.ss_sp), &uss_ptr->ss_sp) ||
-		    __put_user((u32)uss.ss_flags, &uss_ptr->ss_flags) ||
-		    __put_user((u32)uss.ss_size, &uss_ptr->ss_size))
+		if (!access_ok(VERIFY_WRITE,uoss_ptr,sizeof(stack_ia32_t)) ||
+		    __put_user(ptr_to_u32(uoss.ss_sp), &uoss_ptr->ss_sp) ||
+		    __put_user((u32)uoss.ss_flags, &uoss_ptr->ss_flags) ||
+		    __put_user((u32)uoss.ss_size, &uoss_ptr->ss_size))
 			ret = -EFAULT;
 	} 	
 	return ret;	
@@ -173,31 +186,29 @@
 	  if (pre != cur) loadsegment(seg,pre); }
 
 	/* Reload fs and gs if they have changed in the signal handler.
-	   This does not handle long fs/gs base changes in the handler, but 
-	   does not clobber them at least in the normal case. */ 
+	   This does not handle long gs base changes in the handler, but 
+	   does not clobber it at least in the normal case. */ 
 	
 	{
 		unsigned short gs; 
+		unsigned int curgs;
 		err |= __get_user(gs, &sc->gs);
-		load_gs_index(gs); 
+		asm volatile("movl %%gs,%0" : "=r" (curgs)); 		
+		if (gs != curgs) 
+			load_gs_index(gs | 3); 
 	} 
-	RELOAD_SEG(fs,0);
-	RELOAD_SEG(ds,0);
-	RELOAD_SEG(es,0);
+	RELOAD_SEG(fs,3);
+	RELOAD_SEG(ds,3);
+	RELOAD_SEG(es,3);
 
 	COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
 	COPY(dx); COPY(cx); COPY(ip);
 	/* Don't touch extended registers */ 
 
-#if 1	/* not ready for this yet */ 
 	err |= __get_user(regs->cs, &sc->cs); 
-	regs->cs |= 2; 	
+	regs->cs |= 3; 	
 	err |= __get_user(regs->ss, &sc->ss); 
-	regs->ss |= 2; 
-#else
-	regs->cs = __USER32_CS;
-	regs->ss = __USER32_DS; 
-#endif
+	regs->ss |= 3; 
 	
 	{
 		unsigned int tmpflags;
@@ -213,7 +224,7 @@
 		buf = (struct _fpstate_ia32 *) (u64)tmp;
 		if (buf) {
 			if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
-				goto badframe;
+				return 1;
 			err |= restore_i387_ia32(current, buf, 0);
 		}
 	}
@@ -224,12 +235,9 @@
 		*peax = tmp;
 	}
 	return err;
-
-badframe:
-	return 1;
 }
 
-asmlinkage int sys32_sigreturn(struct pt_regs regs)
+asmlinkage long sys32_sigreturn(struct pt_regs regs)
 {
 	struct sigframe *frame = (struct sigframe *)(regs.rsp - 8);
 	sigset_t set;
@@ -258,7 +266,7 @@
 	return 0;
 }	
 
-asmlinkage int sys32_rt_sigreturn(struct pt_regs regs)
+asmlinkage long sys32_rt_sigreturn(struct pt_regs regs)
 {
 	struct rt_sigframe *frame = (struct rt_sigframe *)(regs.rsp - 4);
 	sigset_t set;
@@ -336,8 +344,12 @@
 	tmp = save_i387_ia32(current, fpstate, regs, 0);
 	if (tmp < 0)
 	  err = -EFAULT;
-	else
+	else { 
+		/* trigger finit in signal handler */
+		current->used_math = 0;
+		stts();
 	  err |= __put_user((u32)(u64)(tmp ? fpstate : NULL), &sc->fpstate);
+	} 
 
 	/* non-iBCS2 extensions.. */
 	err |= __put_user(mask, &sc->oldmask);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/ia32/ia32entry.S linux-2.4.21-pre6/arch/x86_64/ia32/ia32entry.S
--- linux-2.4.20/arch/x86_64/ia32/ia32entry.S	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/ia32/ia32entry.S	2003-03-26 23:49:19.000000000 +0000
@@ -3,7 +3,7 @@
  * 		
  * Copyright 2000,2001 Andi Kleen, SuSE Labs.
  * 
- * $Id: ia32entry.S,v 1.36 2002/09/12 12:55:05 ak Exp $ 		
+ * $Id: ia32entry.S,v 1.39 2003/01/14 14:29:59 ak Exp $ 		
  */		 
 
 #include <asm/calling.h>
@@ -86,6 +86,7 @@
 		
 ia32_badsys:
 	movq $-ENOSYS,RAX-ARGOFFSET(%rsp)
+	movq $0,ORIG_RAX-ARGOFFSET(%rsp)
 	jmp int_ret_from_sys_call
 
 ni_syscall:
@@ -133,7 +134,7 @@
 	.quad stub32_fork
 	.quad sys_read
 	.quad sys_write
-	.quad sys_open		/* 5 */
+	.quad sys32_open		/* 5 */
 	.quad sys_close
 	.quad sys32_waitpid
 	.quad sys_creat
@@ -176,7 +177,7 @@
 	.quad sys_brk		/* 45 */
 	.quad sys_setgid16
 	.quad sys_getgid16
-	.quad ni_syscall	/* signal */
+	.quad sys_signal
 	.quad sys_geteuid16
 	.quad sys_getegid16	/* 50 */
 	.quad sys_acct
@@ -241,7 +242,7 @@
 	.quad stub32_iopl		/* 110 */
 	.quad sys_vhangup
 	.quad ni_syscall	/* old "idle" system call */
-	.quad ni_syscall	/* vm86old */ 
+	.quad sys32_vm86_warning	/* vm86old */ 
 	.quad sys32_wait4
 	.quad sys_swapoff		/* 115 */
 	.quad sys32_sysinfo
@@ -251,7 +252,7 @@
 	.quad stub32_clone		/* 120 */
 	.quad sys_setdomainname
 	.quad sys_uname
-	.quad sys_modify_ldt
+	.quad sys32_modify_ldt
 	.quad sys32_adjtimex
 	.quad sys32_mprotect		/* 125 */
 	.quad sys32_sigprocmask
@@ -294,7 +295,7 @@
 	.quad sys_mremap
 	.quad sys_setresuid16
 	.quad sys_getresuid16	/* 165 */
-	.quad ni_syscall	/* vm86 */ 
+	.quad sys32_vm86_warning	/* vm86 */ 
 	.quad quiet_ni_syscall	/* query_module */
 	.quad sys_poll
 	.quad sys32_nfsservctl
@@ -354,34 +355,23 @@
 	.quad sys_ni_syscall    /* security */
 	.quad sys_gettid	
 	.quad sys_readahead	/* 225 */ 
-	.quad sys_setxattr
-	.quad sys_lsetxattr
-	.quad sys_fsetxattr
-	.quad sys_getxattr
-	.quad sys_lgetxattr	/* 230 */
-	.quad sys_fgetxattr
-	.quad sys_listxattr
-	.quad sys_llistxattr
-	.quad sys_flistxattr
-	.quad sys_removexattr	/* 235 */
-	.quad sys_lremovexattr
-	.quad sys_fremovexattr
-	.quad sys_tkill		/* 238 */ 
-	.quad sys_ni_syscall	/* sendfile64 */
-	.quad sys_ni_syscall	/* futex */
-	.quad sys_ni_syscall	/* sched_setaffinity */
-	.quad sys_ni_syscall	/* sched_getaffinity */
-	.quad sys_ni_syscall	/* set_threadarea */
-	.quad sys_ni_syscall	/* get_threadarea */
-	.quad sys_ni_syscall	/* io_setup */
-	.quad sys_ni_syscall	/* io_destroy */
-	.quad sys_ni_syscall	/* io_getevents */
-	.quad sys_ni_syscall	/* io_submit */
-	.quad sys_ni_syscall	/* io_cancel */
-	.quad sys_ni_syscall	/* alloc_hugepages */
-	.quad sys_ni_syscall	/* free_hugepages */
-	.quad sys_ni_syscall	/* exit_group */
-
+	.quad quiet_ni_syscall  /* xattr syscalls 226-237 */
+	.quad quiet_ni_syscall
+	.quad quiet_ni_syscall
+	.quad quiet_ni_syscall
+	.quad quiet_ni_syscall  /* 230 */
+	.quad quiet_ni_syscall  
+	.quad quiet_ni_syscall  
+	.quad quiet_ni_syscall  
+	.quad quiet_ni_syscall  
+	.quad quiet_ni_syscall  /* 235 */
+	.quad quiet_ni_syscall  
+	.quad quiet_ni_syscall  /* fremovexattr - 237 */
+	.quad sys_tkill
+	.quad quiet_ni_syscall  /* sendfile64 - 2.5 only */
+	.quad quiet_ni_syscall  /* futex */
+	.quad quiet_ni_syscall  /* sched_setaffinity */
+	.quad quiet_ni_syscall  /* sched_getaffinity */	
 ia32_syscall_end:		
 	.rept IA32_NR_syscalls-(ia32_syscall_end-ia32_sys_call_table)/8
 		.quad ni_syscall
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/ia32/ipc32.c linux-2.4.21-pre6/arch/x86_64/ia32/ipc32.c
--- linux-2.4.20/arch/x86_64/ia32/ipc32.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/ia32/ipc32.c	2003-03-26 23:49:39.000000000 +0000
@@ -227,22 +227,25 @@
 		set_fs(old_fs);
 
 		if (version == IPC_64) {
-			struct semid64_ds32 *usp64 = (struct semid64_ds32 *) A(pad);
-
-			if (!access_ok(VERIFY_WRITE, usp64, sizeof(*usp64))) {
-				err = -EFAULT;
-				break;
-			}
-			err2 = __put_user(s.sem_perm.key, &usp64->sem_perm.key);
-			err2 |= __put_user(s.sem_perm.uid, &usp64->sem_perm.uid);
-			err2 |= __put_user(s.sem_perm.gid, &usp64->sem_perm.gid);
-			err2 |= __put_user(s.sem_perm.cuid, &usp64->sem_perm.cuid);
-			err2 |= __put_user(s.sem_perm.cgid, &usp64->sem_perm.cgid);
-			err2 |= __put_user(s.sem_perm.mode, &usp64->sem_perm.mode);
-			err2 |= __put_user(s.sem_perm.seq, &usp64->sem_perm.seq);
-			err2 |= __put_user(s.sem_otime, &usp64->sem_otime);
-			err2 |= __put_user(s.sem_ctime, &usp64->sem_ctime);
-			err2 |= __put_user(s.sem_nsems, &usp64->sem_nsems);
+			/* This works, but the equivalent __put_user code 
+			   does not. Why? */
+			struct semid64_ds32 u64; 
+			memset(&u64, 0, sizeof(u64));
+#define C(x) u64.x = s.x
+			C(sem_perm.key);
+			C(sem_perm.uid);
+			C(sem_perm.gid);
+			C(sem_perm.cuid);
+			C(sem_perm.cgid);
+			C(sem_perm.mode);
+			C(sem_perm.seq);
+			C(sem_otime);
+			C(sem_ctime);
+			C(sem_nsems);
+#undef C
+			err2 = copy_to_user((void *)A(pad), &u64, sizeof(struct semid64_ds32));
+			if (err2) 
+				err2 = -EFAULT;
 		} else {
 			struct semid_ds32 *usp32 = (struct semid_ds32 *) A(pad);
 
@@ -264,6 +267,9 @@
 		if (err2)
 		    err = -EFAULT;
 		break;
+	default:
+		err = -EINVAL;
+		break;
 	}
 	return err;
 }
@@ -284,7 +290,7 @@
 	if (!p)
 		return -ENOMEM;
 	err = get_user(p->mtype, &up->mtype);
-	err |= copy_from_user(p->mtext, &up->mtext, second);
+	err |= (copy_from_user(p->mtext, &up->mtext, second) ? -EFAULT : 0);
 	if (err)
 		goto out;
 	old_fs = get_fs();
@@ -604,6 +610,10 @@
 			err = -EFAULT;
 		break;
 
+	default:
+		err = -EINVAL;
+		break;
+
 	}
 	return err;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/ia32/ptrace32.c linux-2.4.21-pre6/arch/x86_64/ia32/ptrace32.c
--- linux-2.4.20/arch/x86_64/ia32/ptrace32.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/ia32/ptrace32.c	2003-03-26 23:49:54.000000000 +0000
@@ -8,7 +8,7 @@
  * This allows to access 64bit processes too; but there is no way to see the extended 
  * register contents.
  *
- * $Id: ptrace32.c,v 1.13 2002/07/18 13:44:12 ak Exp $
+ * $Id: ptrace32.c,v 1.16 2003/03/14 16:06:35 ak Exp $
  */ 
 
 #include <linux/kernel.h>
@@ -73,8 +73,16 @@
 		stack[offsetof(struct pt_regs, eflags)/8] = val & 0x44dd5; 
 		break;
 
-	case offsetof(struct user32, u_debugreg[0]) ... offsetof(struct user32, u_debugreg[6]):
-		child->thread.debugreg[(regno-offsetof(struct user32, u_debugreg[0]))/4] = val; 
+	case offsetof(struct user32, u_debugreg[4]): 
+	case offsetof(struct user32, u_debugreg[5]):
+		return -EIO;
+
+	case offsetof(struct user32, u_debugreg[0]) ...
+	     offsetof(struct user32, u_debugreg[3]):
+	case offsetof(struct user32, u_debugreg[6]):
+		child->thread.debugreg
+			[(regno-offsetof(struct user32, u_debugreg[0]))/4] 
+			= val; 
 		break; 
 
 	case offsetof(struct user32, u_debugreg[7]):
@@ -277,7 +285,6 @@
 			ret = -EIO;
 			break;
 		}
-		empty_fpu(child); 
 		ret = 0; 
 		for ( i = 0; i <= 16*4; i += sizeof(u32) ) {
 			ret |= __get_user(tmp, (u32 *) (unsigned long) data);
@@ -287,33 +294,47 @@
 		break;
 	}
 
-	case PTRACE_SETFPREGS:
-		empty_fpu(child); 
+	case PTRACE_GETFPREGS:
+		ret = -EIO; 
+		if (!access_ok(VERIFY_READ, (void *)(u64)data, 
+			       sizeof(struct user_i387_struct)))
+			break;
 		save_i387_ia32(child, (void *)(u64)data, childregs, 1);
 		ret = 0; 
 		break;
 
-	case PTRACE_GETFPREGS:
-		empty_fpu(child); 
-		restore_i387_ia32(child, (void *)(u64)data, 1);
+	case PTRACE_SETFPREGS:
+		ret = -EIO;
+		if (!access_ok(VERIFY_WRITE, (void *)(u64)data, 
+			       sizeof(struct user_i387_struct)))
+			break;
 		ret = 0;
+		/* don't check EFAULT to be bug-to-bug compatible to i386 */
+		restore_i387_ia32(child, (void *)(u64)data, 1);
 		break;
 
 	case PTRACE_GETFPXREGS: { 
 		struct user32_fxsr_struct *u = (void *)(u64)data; 
-		empty_fpu(child); 
-		ret = copy_to_user(u, &child->thread.i387.fxsave, sizeof(*u));
-		ret |= __put_user(childregs->cs, &u->fcs);
-		ret |= __put_user(child->thread.ds, &u->fos); 
-		if (ret) 
+		init_fpu(child); 
+		ret = -EIO;
+		if (!access_ok(VERIFY_WRITE, u, sizeof(*u)))
+			break;
 			ret = -EFAULT;
+		if (__copy_to_user(u, &child->thread.i387.fxsave, sizeof(*u)))
+			break;
+		ret = __put_user(childregs->cs, &u->fcs);
+		ret |= __put_user(child->thread.ds, &u->fos); 
 		break; 
 	} 
 	case PTRACE_SETFPXREGS: { 
 		struct user32_fxsr_struct *u = (void *)(u64)data; 
-		empty_fpu(child); 
-		/* no error checking to be bug to bug compatible with i386 */ 
-		copy_from_user(&child->thread.i387.fxsave, u, sizeof(*u));
+		unlazy_fpu(child);
+		ret = -EIO;
+		if (!access_ok(VERIFY_READ, u, sizeof(*u)))
+			break;
+		/* no checking to be bug-to-bug compatible with i386 */
+		__copy_from_user(&child->thread.i387.fxsave, u, sizeof(*u));
+		child->used_math = 1;
 	        child->thread.i387.fxsave.mxcsr &= 0xffbf;
 		ret = 0; 
 		break; 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/ia32/socket32.c linux-2.4.21-pre6/arch/x86_64/ia32/socket32.c
--- linux-2.4.20/arch/x86_64/ia32/socket32.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/ia32/socket32.c	2003-03-26 23:49:09.000000000 +0000
@@ -362,7 +362,7 @@
 	kmsg->msg_control = (void *) orig_cmsg_uptr;
 }
 
-asmlinkage int sys32_sendmsg(int fd, struct msghdr32 *user_msg, unsigned user_flags)
+asmlinkage long sys32_sendmsg(int fd, struct msghdr32 *user_msg, unsigned user_flags)
 {
 	struct socket *sock;
 	char address[MAX_SOCK_ADDR];
@@ -407,7 +407,7 @@
 	return err;
 }
 
-asmlinkage int sys32_recvmsg(int fd, struct msghdr32 *user_msg, unsigned int user_flags)
+asmlinkage long sys32_recvmsg(int fd, struct msghdr32 *user_msg, unsigned int user_flags)
 {
 	struct iovec iovstack[UIO_FASTIOV];
 	struct msghdr kern_msg;
@@ -561,7 +561,7 @@
 	return ret;
 }
 
-asmlinkage int sys32_setsockopt(int fd, int level, int optname,
+asmlinkage long sys32_setsockopt(int fd, int level, int optname,
 				char *optval, int optlen)
 {
 	if (optname == SO_ATTACH_FILTER)
@@ -664,7 +664,7 @@
 			ret = sys_shutdown(a0,a1);
 			break;
 		case SYS_SETSOCKOPT:
-			ret = sys_setsockopt(a0, a1, a[2], (char *)A(a[3]),
+			ret = sys32_setsockopt(a0, a1, a[2], (char *)A(a[3]),
 					      a[4]);
 			break;
 		case SYS_GETSOCKOPT:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/ia32/sys_ia32.c linux-2.4.21-pre6/arch/x86_64/ia32/sys_ia32.c
--- linux-2.4.20/arch/x86_64/ia32/sys_ia32.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/ia32/sys_ia32.c	2003-03-26 23:49:54.000000000 +0000
@@ -9,13 +9,14 @@
  * Copyright (C) 1997 		David S. Miller (davem@caip.rutgers.edu)
  * Copyright (C) 2000		Hewlett-Packard Co.
  * Copyright (C) 2000		David Mosberger-Tang <davidm@hpl.hp.com>
- * Copyright (C) 2000,2001	Andi Kleen, SuSE Labs (x86-64 port) 
+ * Copyright (C) 2000,2001,2002	Andi Kleen, SuSE Labs (x86-64 port) 
  *
  * These routines maintain argument size conversion between 32bit and 64bit
  * environment. In 2.5 most of this should be moved to a generic directory. 
  *
  * This file assumes that there is a hole at the end of user address space.
- * $Id: sys_ia32.c,v 1.42 2002/09/17 15:23:41 ak Exp $
+ *
+ * $Id: sys_ia32.c,v 1.53 2003/03/12 09:45:06 ak Exp $
  */
 
 #include <linux/config.h>
@@ -61,6 +62,7 @@
 #include <asm/semaphore.h>
 #include <asm/ipc.h>
 #include <asm/atomic.h>
+#include <asm/ldt.h>
 
 #include <net/scm.h>
 #include <net/sock.h>
@@ -225,7 +227,33 @@
 	return ret;
 }
 
+/* Don't set O_LARGEFILE implicitely. */
+asmlinkage long sys32_open(const char * filename, int flags, int mode)
+{
+	char * tmp;
+	int fd, error;
+
+	tmp = getname(filename);
+	fd = PTR_ERR(tmp);
+	if (!IS_ERR(tmp)) {
+		fd = get_unused_fd();
+		if (fd >= 0) {
+			struct file *f = filp_open(tmp, flags, mode);
+			error = PTR_ERR(f);
+			if (IS_ERR(f))
+				goto out_error;
+			fd_install(fd, f);
+		}
+out:
+		putname(tmp);
+	}
+	return fd;
 
+out_error:
+	put_unused_fd(fd);
+	fd = error;
+	goto out;
+}
 
 /*
  * Linux/i386 didn't use to be able to handle more than
@@ -242,7 +270,7 @@
 	unsigned int offset;
 };
 
-asmlinkage __u32
+asmlinkage long
 sys32_mmap(struct mmap_arg_struct *arg)
 {
 	struct mmap_arg_struct a;
@@ -261,22 +289,16 @@
 		if (!file)
 			return -EBADF;
 	}
+	
 	if (a.prot & PROT_READ) 
 		a.prot |= PROT_EXEC; 
 
-	a.flags |= MAP_32BIT;
-
 	mm = current->mm; 
 	down_write(&mm->mmap_sem); 
 	retval = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags, a.offset>>PAGE_SHIFT);
 	if (file)
 		fput(file);
 
-	/* Should not happen */
-	if (retval >= 0xFFFFFFFF && (long)retval > 0) { 
-		do_munmap(mm, retval, a.len); 
-		retval = -ENOMEM; 
-	} 
 	up_write(&mm->mmap_sem); 
 
 	return retval;
@@ -284,7 +306,7 @@
 
 extern asmlinkage long sys_mprotect(unsigned long start,size_t len,unsigned long prot);
 
-asmlinkage int sys32_mprotect(unsigned long start, size_t len, unsigned long prot)
+asmlinkage long sys32_mprotect(unsigned long start, size_t len, unsigned long prot)
 {
 	if (prot & PROT_READ) 
 		prot |= PROT_EXEC; 
@@ -503,7 +525,7 @@
     struct timeval32 it_value;
 };
 
-static inline long
+static long
 get_tv32(struct timeval *o, struct timeval32 *i)
 {
 	int err = -EFAULT; 
@@ -514,7 +536,7 @@
 	return err; 
 }
 
-static inline long
+static long
 put_tv32(struct timeval32 *o, struct timeval *i)
 {
 	int err = -EFAULT;
@@ -525,7 +547,7 @@
 	return err; 
 }
 
-static inline long
+static long
 get_it32(struct itimerval *o, struct itimerval32 *i)
 {
 	int err = -EFAULT; 
@@ -538,7 +560,7 @@
 	return err;
 }
 
-static inline long
+static long
 put_it32(struct itimerval32 *o, struct itimerval *i)
 {
 	int err = -EFAULT;
@@ -589,7 +611,8 @@
 	return 0;
 
 }
-asmlinkage unsigned long 
+
+asmlinkage long 
 sys32_alarm(unsigned int seconds)
 {
 	struct itimerval it_new, it_old;
@@ -912,21 +935,23 @@
 asmlinkage long
 sys32_nanosleep(struct timespec32 *rqtp, struct timespec32 *rmtp)
 {
-	struct timespec t;
+	struct timespec t, tout;
 	int ret;
 	mm_segment_t old_fs = get_fs ();
 	
+	if (rqtp) { 
 	if (verify_area(VERIFY_READ, rqtp, sizeof(struct timespec32)) ||
 	    __get_user (t.tv_sec, &rqtp->tv_sec) ||
 	    __get_user (t.tv_nsec, &rqtp->tv_nsec))
 		return -EFAULT;
+	}
 	set_fs (KERNEL_DS);
-	ret = sys_nanosleep(&t, rmtp ? &t : NULL);
+	ret = sys_nanosleep(rqtp ? &t : NULL, rmtp ? &tout : NULL);
 	set_fs (old_fs);
 	if (rmtp && ret == -EINTR) {
 		if (verify_area(VERIFY_WRITE, rmtp, sizeof(struct timespec32)) ||
-		    __put_user (t.tv_sec, &rmtp->tv_sec) ||
-	    	    __put_user (t.tv_nsec, &rmtp->tv_nsec))
+		    __put_user (tout.tv_sec, &rmtp->tv_sec) ||
+	    	    __put_user (tout.tv_nsec, &rmtp->tv_nsec))
 			return -EFAULT;
 	}
 	return ret;
@@ -935,22 +960,27 @@
 asmlinkage ssize_t sys_readv(unsigned long,const struct iovec *,unsigned long);
 asmlinkage ssize_t sys_writev(unsigned long,const struct iovec *,unsigned long);
 
-struct iovec *
-get_iovec32(struct iovec32 *iov32, struct iovec *iov_buf, u32 count, int type)
+static struct iovec *
+get_iovec32(struct iovec32 *iov32, struct iovec *iov_buf, u32 count, int type, int *errp)
 {
 	int i;
 	u32 buf, len;
 	struct iovec *ivp, *iov;
+	unsigned long totlen; 
 
 	/* Get the "struct iovec" from user memory */
 
+	*errp = 0; 
 	if (!count)
 		return 0;
-	if(verify_area(VERIFY_READ, iov32, sizeof(struct iovec32)*count))
-		return(struct iovec *)0;
+	*errp = -EINVAL;
 	if (count > UIO_MAXIOV)
 		return(struct iovec *)0;
+	*errp = -EFAULT;
+	if(verify_area(VERIFY_READ, iov32, sizeof(struct iovec32)*count))
+		return(struct iovec *)0;
 	if (count > UIO_FASTIOV) {
+		*errp = -ENOMEM; 
 		iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
 		if (!iov)
 			return((struct iovec *)0);
@@ -958,24 +988,33 @@
 		iov = iov_buf;
 
 	ivp = iov;
+	totlen = 0;
 	for (i = 0; i < count; i++) {
-		if (__get_user(len, &iov32->iov_len) ||
-		    __get_user(buf, &iov32->iov_base)) {
-			if (iov != iov_buf)
-				kfree(iov);
-			return((struct iovec *)0);
-		}
-		if (verify_area(type, (void *)A(buf), len)) {
-			if (iov != iov_buf)
-				kfree(iov);
-			return((struct iovec *)0);
-		}
+		*errp = __get_user(len, &iov32->iov_len) |
+		  	__get_user(buf, &iov32->iov_base);	
+		if (*errp)
+			goto error;
+		*errp = verify_area(type, (void *)A(buf), len);
+		if (*errp) 
+			goto error;
+		/* SuS checks: */
+		*errp = -EINVAL; 
+		if ((int)len < 0)
+			goto error;
+		if ((totlen += len) >= 0x7fffffff)
+			goto error;			
 		ivp->iov_base = (void *)A(buf);
 		ivp->iov_len = (__kernel_size_t)len;
 		iov32++;
 		ivp++;
 	}
+	*errp = 0;
 	return(iov);
+
+error:
+	if (iov != iov_buf)
+		kfree(iov);
+	return NULL;
 }
 
 asmlinkage long
@@ -986,8 +1025,8 @@
 	int ret;
 	mm_segment_t old_fs = get_fs();
 
-	if ((iov = get_iovec32(vector, iovstack, count, VERIFY_WRITE)) == (struct iovec *)0)
-		return -EFAULT;
+	if ((iov = get_iovec32(vector, iovstack, count, VERIFY_WRITE, &ret)) == NULL)
+		return ret;
 	set_fs(KERNEL_DS);
 	ret = sys_readv(fd, iov, count);
 	set_fs(old_fs);
@@ -1004,8 +1043,8 @@
 	int ret;
 	mm_segment_t old_fs = get_fs();
 
-	if ((iov = get_iovec32(vector, iovstack, count, VERIFY_READ)) == (struct iovec *)0)
-		return -EFAULT;
+	if ((iov = get_iovec32(vector, iovstack, count, VERIFY_READ, &ret)) == NULL)
+		return ret;
 	set_fs(KERNEL_DS);
 	ret = sys_writev(fd, iov, count);
 	set_fs(old_fs);
@@ -1092,7 +1131,7 @@
 
 /*
  * sys_time() can be implemented in user-level using
- * sys_gettimeofday().  IA64 did this but i386 Linux did not
+ * sys_gettimeofday().  x86-64 did this but i386 Linux did not
  * so we have to implement this system call here.
  */
 asmlinkage long sys32_time(int * tloc)
@@ -1354,7 +1393,7 @@
 	return ret; 
 }
 
-int sys32_ni_syscall(int call)
+asmlinkage long sys32_ni_syscall(int call)
 { 
 	printk(KERN_INFO "IA32 syscall %d from %s not implemented\n", call,
 	       current->comm);
@@ -1572,8 +1611,8 @@
 	if (s->si_signo >= SIGRTMIN) {
 		d->si_pid = s->si_pid;
 		d->si_uid = s->si_uid;
-		/* XXX: Ouch, how to find this out??? */
-		d->si_int = s->si_int;
+		memcpy(&d->si_int, &s->si_int, 
+		       sizeof(siginfo_t) - offsetof(siginfo_t,si_int));
 	} else switch (s->si_signo) {
 	/* XXX: What about POSIX1.b timers */
 	case SIGCHLD:
@@ -1610,8 +1649,9 @@
 	if (s->si_signo >= SIGRTMIN) {
 		d->si_pid = s->si_pid;
 		d->si_uid = s->si_uid;
-		/* XXX: Ouch, how to find this out??? */
-		d->si_int = s->si_int;
+		memcpy(&d->si_int,
+		       &s->si_int,
+		       sizeof(siginfo_t) - offsetof(siginfo_t, si_int)); 
 	} else switch (s->si_signo) {
 	/* XXX: What about POSIX1.b timers */
 	case SIGCHLD:
@@ -1812,7 +1852,7 @@
 
 
 /* warning: next two assume little endian */ 
-asmlinkage ssize_t32
+asmlinkage long
 sys32_pread(unsigned int fd, char *ubuf, __kernel_size_t32 count,
 	    u32 poslo, u32 poshi)
 {
@@ -1820,7 +1860,7 @@
 			 ((loff_t)AA(poshi) << 32) | AA(poslo));
 }
 
-asmlinkage ssize_t32
+asmlinkage long
 sys32_pwrite(unsigned int fd, char *ubuf, __kernel_size_t32 count,
 	     u32 poslo, u32 poshi)
 {
@@ -1867,6 +1907,30 @@
 	return ret;
 }
 
+extern long sys_modify_ldt(int,void*,unsigned long);
+
+asmlinkage long sys32_modify_ldt(int func, void *ptr, unsigned long bytecount)
+{
+        long ret;
+        if (func == 0x1 || func == 0x11) { 
+				struct modify_ldt_ldt_s info;
+                mm_segment_t old_fs = get_fs();
+                if (bytecount != sizeof(struct modify_ldt_ldt_s))
+                        return -EINVAL;
+                if (copy_from_user(&info, ptr, sizeof(struct modify_ldt_ldt_s)))
+                        return -EFAULT;
+                /* lm bit was undefined in the 32bit ABI and programs
+                   give it random values. Force it to zero here. */
+                info.lm = 0; 
+                set_fs(KERNEL_DS);
+                ret = sys_modify_ldt(func, &info, bytecount);
+                set_fs(old_fs);
+        }  else { 
+                ret = sys_modify_ldt(func, ptr, bytecount); 
+        }
+        return ret;
+}
+
 /* Handle adjtimex compatability. */
 
 struct timex32 {
@@ -1943,41 +2007,33 @@
 	return ret;
 }
 
-
-/* common code for old and new mmaps */
-static inline long do_mmap2(
-	unsigned long addr, unsigned long len,
+asmlinkage long sys32_mmap2(unsigned long addr, unsigned long len,
 	unsigned long prot, unsigned long flags,
 	unsigned long fd, unsigned long pgoff)
 {
-	int error = -EBADF;
+	struct mm_struct *mm = current->mm;
+	unsigned long error;
 	struct file * file = NULL;
 
 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 	if (!(flags & MAP_ANONYMOUS)) {
 		file = fget(fd);
 		if (!file)
-			goto out;
+			return -EBADF;
 	}
 
-	down_write(&current->mm->mmap_sem);
-	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-	up_write(&current->mm->mmap_sem);
+	if (prot & PROT_READ)
+		prot |= PROT_EXEC;
+
+	down_write(&mm->mmap_sem);
+	error = do_mmap_pgoff(file, addr, len, prot, flags|MAP_32BIT, pgoff);
+	up_write(&mm->mmap_sem);
 
 	if (file)
 		fput(file);
-out:
 	return error;
 }
 
-asmlinkage long sys32_mmap2(unsigned long addr, unsigned long len,
-	unsigned long prot, unsigned long flags,
-	unsigned long fd, unsigned long pgoff)
-{
-	return do_mmap2(addr, len, prot, flags, fd, pgoff);
-}
-
-
 asmlinkage long sys32_olduname(struct oldold_utsname * name)
 {
 	int error;
@@ -2024,7 +2080,7 @@
 
 extern int sys_ustat(dev_t, struct ustat *);
 
-int sys32_ustat(dev_t dev, struct ustat32 *u32p)
+asmlinkage long sys32_ustat(dev_t dev, struct ustat32 *u32p)
 {
 	struct ustat u;
 	mm_segment_t seg;
@@ -2067,21 +2123,26 @@
 	return cnt; 
 } 
 
-int sys32_execve(char *name, u32 argv, u32 envp, struct pt_regs regs)
+asmlinkage long sys32_execve(char *name, u32 argv, u32 envp, struct pt_regs regs)
 { 
 	mm_segment_t oldseg; 
-	char **buf; 
-	int na,ne;
+	char **buf = NULL; 
+	int na = 0,ne = 0;
 	int ret;
-	unsigned sz; 
+	unsigned sz = 0; 
 	
+	if (argv) {
 	na = nargs(argv, NULL); 
 	if (na < 0) 
 		return -EFAULT; 
+	} 	
+	if (envp) { 
 	ne = nargs(envp, NULL); 
 	if (ne < 0) 
 		return -EFAULT; 
+	}
 
+	if (argv || envp) { 
 	sz = (na+ne)*sizeof(void *); 
 	if (sz > PAGE_SIZE) 
 		buf = vmalloc(sz); 
@@ -2089,14 +2150,19 @@
 		buf = kmalloc(sz, GFP_KERNEL); 
 	if (!buf)
 		return -ENOMEM; 
+	} 
 	
+	if (argv) { 
 	ret = nargs(argv, buf);
 	if (ret < 0)
 		goto free;
+	}
 
+	if (envp) { 
 	ret = nargs(envp, buf + na); 
 	if (ret < 0)
 		goto free; 
+	}
 
 	name = getname(name); 
 	ret = PTR_ERR(name); 
@@ -2105,7 +2171,7 @@
 
 	oldseg = get_fs(); 
 	set_fs(KERNEL_DS);
-	ret = do_execve(name, buf, buf+na, &regs);  
+	ret = do_execve(name, argv ? buf : NULL, envp ? buf+na : NULL, &regs);  
 	set_fs(oldseg); 
 
 	if (ret == 0)
@@ -2114,19 +2180,21 @@
 	putname(name);
  
 free:
+	if (argv || envp) { 
 	if (sz > PAGE_SIZE)
 		vfree(buf); 
 	else
 		kfree(buf);
+	}
 	return ret; 
 } 
 
-asmlinkage int sys32_fork(struct pt_regs regs)
+asmlinkage long sys32_fork(struct pt_regs regs)
 {
 	return do_fork(SIGCHLD, regs.rsp, &regs, 0);
 }
 
-asmlinkage int sys32_clone(unsigned int clone_flags, unsigned int newsp, struct pt_regs regs)
+asmlinkage long sys32_clone(unsigned int clone_flags, unsigned int newsp, struct pt_regs regs)
 {
 	if (!newsp)
 		newsp = regs.rsp;
@@ -2143,7 +2211,7 @@
  * do not have enough call-clobbered registers to hold all
  * the information you need.
  */
-asmlinkage int sys32_vfork(struct pt_regs regs)
+asmlinkage long sys32_vfork(struct pt_regs regs)
 {
 	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.rsp, &regs, 0);
 }
@@ -2154,14 +2222,14 @@
 
 extern off_t sys_lseek (unsigned int fd, off_t offset, unsigned int origin);
 
-int sys32_lseek (unsigned int fd, int offset, unsigned int whence)
+asmlinkage long sys32_lseek (unsigned int fd, int offset, unsigned int whence)
 {
 	return sys_lseek(fd, offset, whence);
 }
 
 extern int sys_kill(pid_t pid, int sig); 
 
-int sys32_kill(int pid, int sig)
+asmlinkage long sys32_kill(int pid, int sig)
 {
 	return sys_kill(pid, sig);
 }
@@ -2306,54 +2374,6 @@
 	return err;
 }
 
-static int nfs_uud32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
-{
-	u32 uaddr;
-	int i;
-	int err;
-
-	memset(karg, 0, sizeof(*karg));
-	if(get_user(karg->ca_version, &arg32->ca32_version))
-		return -EFAULT;
-	karg->ca_umap.ug_ident = (char *)get_free_page(GFP_USER);
-	if(!karg->ca_umap.ug_ident)
-		return -ENOMEM;
-	err = get_user(uaddr, &arg32->ca32_umap.ug32_ident);
-	if(strncpy_from_user(karg->ca_umap.ug_ident,
-			     (char *)A(uaddr), PAGE_SIZE) <= 0)
-		return -EFAULT;
-	err |= __get_user(karg->ca_umap.ug_uidbase,
-		      &arg32->ca32_umap.ug32_uidbase);
-	err |= __get_user(karg->ca_umap.ug_uidlen,
-		      &arg32->ca32_umap.ug32_uidlen);
-	err |= __get_user(uaddr, &arg32->ca32_umap.ug32_udimap);
-	if (err)
-		return -EFAULT;
-	karg->ca_umap.ug_udimap = kmalloc((sizeof(uid_t) * karg->ca_umap.ug_uidlen),
-					  GFP_USER);
-	if(!karg->ca_umap.ug_udimap)
-		return -ENOMEM;
-	for(i = 0; i < karg->ca_umap.ug_uidlen; i++)
-		err |= __get_user(karg->ca_umap.ug_udimap[i],
-			      &(((__kernel_uid_t32 *)A(uaddr))[i]));
-	err |= __get_user(karg->ca_umap.ug_gidbase,
-		      &arg32->ca32_umap.ug32_gidbase);
-	err |= __get_user(karg->ca_umap.ug_uidlen,
-		      &arg32->ca32_umap.ug32_gidlen);
-	err |= __get_user(uaddr, &arg32->ca32_umap.ug32_gdimap);
-	if (err)
-		return -EFAULT;
-	karg->ca_umap.ug_gdimap = kmalloc((sizeof(gid_t) * karg->ca_umap.ug_uidlen),
-					  GFP_USER);
-	if(!karg->ca_umap.ug_gdimap)
-		return -ENOMEM;
-	for(i = 0; i < karg->ca_umap.ug_gidlen; i++)
-		err |= __get_user(karg->ca_umap.ug_gdimap[i],
-			      &(((__kernel_gid_t32 *)A(uaddr))[i]));
-
-	return err;
-}
-
 static int nfs_getfh32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
 {
 	int err;
@@ -2411,7 +2431,7 @@
 	return copy_to_user(res32, kres, sizeof(*res32));
 }
 
-int asmlinkage sys32_nfsservctl(int cmd, struct nfsctl_arg32 *arg32, union nfsctl_res32 *res32)
+long asmlinkage sys32_nfsservctl(int cmd, struct nfsctl_arg32 *arg32, union nfsctl_res32 *res32)
 {
 	struct nfsctl_arg *karg = NULL;
 	union nfsctl_res *kres = NULL;
@@ -2442,10 +2462,6 @@
 	case NFSCTL_UNEXPORT:
 		err = nfs_exp32_trans(karg, arg32);
 		break;
-	/* This one is unimplemented, be we're ready for it. */
-	case NFSCTL_UGIDUPDATE:
-		err = nfs_uud32_trans(karg, arg32);
-		break;
 	case NFSCTL_GETFH:
 		err = nfs_getfh32_trans(karg, arg32);
 		break;
@@ -2492,13 +2508,13 @@
 }
 #else /* !NFSD */
 extern asmlinkage long sys_ni_syscall(void);
-int asmlinkage sys32_nfsservctl(int cmd, void *notused, void *notused2)
+long asmlinkage sys32_nfsservctl(int cmd, void *notused, void *notused2)
 {
 	return sys_ni_syscall();
 }
 #endif
 
-int sys32_module_warning(void)
+long sys32_module_warning(void)
 { 
 	static long warn_time = -(60*HZ); 
 	if (time_before(warn_time + 60*HZ,jiffies) && strcmp(current->comm,"klogd")) { 
@@ -2509,15 +2525,27 @@
 	return -ENOSYS ;
 } 
 
+long sys32_vm86_warning(void)
+{ 
+	static long warn_time = -(60*HZ); 
+	if (time_before(warn_time + 60*HZ,jiffies)) { 
+		printk(KERN_INFO "%s: vm86 mode not supported on 64 bit kernel\n",
+		       current->comm);
+		warn_time = jiffies;
+	} 
+	return -ENOSYS ;
+} 
+
+/* This only triggers an i686 uname */
 struct exec_domain ia32_exec_domain = { 
-	name: "linux/x86",
+	name: "linux/uname-i686",
 	pers_low: PER_LINUX32,
 	pers_high: PER_LINUX32,
 };      
 
 static int __init ia32_init (void)
 {
-	printk("IA32 emulation $Id: sys_ia32.c,v 1.42 2002/09/17 15:23:41 ak Exp $\n");  
+	printk("IA32 emulation $Id: sys_ia32.c,v 1.53 2003/03/12 09:45:06 ak Exp $\n");  
 	ia32_exec_domain.signal_map = default_exec_domain.signal_map;
 	ia32_exec_domain.signal_invmap = default_exec_domain.signal_invmap;
 	register_exec_domain(&ia32_exec_domain);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/acpitable.c linux-2.4.21-pre6/arch/x86_64/kernel/acpitable.c
--- linux-2.4.20/arch/x86_64/kernel/acpitable.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/kernel/acpitable.c	2003-03-26 23:49:50.000000000 +0000
@@ -282,9 +282,9 @@
 		return -1;
 	}
 
-	hpet.address = hpet_tbl->addr.addrl | ((long) hpet_tbl->addr.addrh << 32);
+	hpet_address = hpet_tbl->addr.addrl | ((long) hpet_tbl->addr.addrh << 32);
 
-	printk(KERN_INFO "acpi: HPET id: %#x base: %#lx\n", hpet_tbl->id, hpet.address);
+	printk(KERN_INFO "acpi: HPET id: %#x base: %#lx\n", hpet_tbl->id, hpet_address);
 
 	return 0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/aperture.c linux-2.4.21-pre6/arch/x86_64/kernel/aperture.c
--- linux-2.4.20/arch/x86_64/kernel/aperture.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/kernel/aperture.c	2003-03-26 23:49:54.000000000 +0000
@@ -8,7 +8,7 @@
  * the bootmem allocator can allocate 32+MB. 
  * 
  * Copyright 2002 Andi Kleen, SuSE Labs.
- * $Id: aperture.c,v 1.2 2002/09/19 19:25:32 ak Exp $
+ * $Id: aperture.c,v 1.4 2002/11/28 06:05:58 ak Exp $
  */
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -47,10 +47,9 @@
 	aper_size = (32 * 1024 * 1024) << fallback_aper_order; 
 
 	/* 
-         * Aperture has to be naturally aligned it seems. This means an
-	 * 2GB aperture won't have much changes to succeed in the lower 4GB of 
-	 * memory. Unfortunately we cannot move it up because that would make
-	 * the IOMMU useless.
+         * Aperture has to be naturally aligned. This means an 2GB aperture won't 
+         * have much chances to find a place in the lower 4GB of memory. Unfortunately 
+         * we cannot move it up because that would make the IOMMU useless.
 	 */
 	p = __alloc_bootmem_node(nd0, aper_size, aper_size, 0); 
 	if (!p || __pa(p)+aper_size > 0xffffffff) {
@@ -105,7 +104,8 @@
 	if (!fix && !fallback_aper_force) 
 		return; 
 
-	printk("Your BIOS is broken and doesn't leave a aperture memory hole\n");
+	printk("Your BIOS doesn't leave a aperture memory hole\n");
+	printk("Please enable the IOMMU option in the BIOS setup\n"); 
 	aper_alloc = allocate_aperture(); 
 	if (!aper_alloc) 
 		return; 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/apic.c linux-2.4.21-pre6/arch/x86_64/kernel/apic.c
--- linux-2.4.20/arch/x86_64/kernel/apic.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/kernel/apic.c	2003-03-26 23:48:57.000000000 +0000
@@ -31,6 +31,10 @@
 #include <asm/pgalloc.h>
 #include <asm/timex.h>
 
+int apic_disabled;
+
+extern spinlock_t i8253_lock;
+
 /* Using APIC to generate smp_local_timer_interrupt? */
 int using_apic_timer = 0;
 
@@ -373,10 +377,10 @@
 	value = apic_read(APIC_LVT0) & APIC_LVT_MASKED;
 	if (!smp_processor_id() && (pic_mode || !value)) {
 		value = APIC_DM_EXTINT;
-		printk("enabled ExtINT on CPU#%d\n", smp_processor_id());
+		Dprintk("enabled ExtINT on CPU#%d\n", smp_processor_id());
 	} else {
 		value = APIC_DM_EXTINT | APIC_LVT_MASKED;
-		printk("masked ExtINT on CPU#%d\n", smp_processor_id());
+		Dprintk("masked ExtINT on CPU#%d\n", smp_processor_id());
 	}
 	apic_write_around(APIC_LVT0, value);
 
@@ -396,7 +400,7 @@
 		if (maxlvt > 3)			/* Due to the Pentium erratum 3AP. */
 			apic_write(APIC_ESR, 0);
 		value = apic_read(APIC_ESR);
-		printk("ESR value before enabling vector: %08x\n", value);
+		Dprintk("ESR value before enabling vector: %08x\n", value);
 
 		value = ERROR_APIC_VECTOR;	/* enables sending errors */
 		apic_write_around(APIC_LVTERR, value);
@@ -406,7 +410,7 @@
 		if (maxlvt > 3)
 			apic_write(APIC_ESR, 0);
 		value = apic_read(APIC_ESR);
-		printk("ESR value after enabling vector: %08x\n", value);
+		Dprintk("ESR value after enabling vector: %08x\n", value);
 	} else {
 		if (esr_disable)
 			/*
@@ -415,9 +419,9 @@
 			 * ESR disabled - we can't do anything useful with the
 			 * errors anyway - mbligh
 			 */
-			printk("Leaving ESR disabled.\n");
+			Dprintk("Leaving ESR disabled.\n");
 		else
-			printk("No ESR for 82489DX.\n");
+			Dprintk("No ESR for 82489DX.\n");
 	}
 
 	if (nmi_watchdog == NMI_LOCAL_APIC)
@@ -766,12 +770,13 @@
 	 * Wait for timer IRQ slice:
 	 */
 
-	if (hpet.address) {
+	if (hpet_address) {
 		int trigger = hpet_readl(HPET_T0_CMP);
 		while (hpet_readl(HPET_COUNTER) >= trigger);
 		while (hpet_readl(HPET_COUNTER) <  trigger);
 	} else {
 		int c1, c2;
+		spin_lock(&i8253_lock);
 		outb_p(0x00, 0x43);
 		c2 = inb_p(0x40);
 		c2 |= inb_p(0x40) << 8;
@@ -781,6 +786,7 @@
 			c2 = inb_p(0x40);
 			c2 |= inb_p(0x40) << 8;
 		} while (c2 - c1 < 300);
+		spin_unlock(&i8253_lock);
 	}
 
 	__setup_APIC_LVTT(clocks);
@@ -1018,6 +1024,7 @@
 		printk(KERN_INFO "spurious APIC interrupt on CPU#%d, %ld skipped.\n",
 		       smp_processor_id(), skipped);
 		last_warning = jiffies;
+		skipped = 0;
 	} else {
 		skipped++;
 	}
@@ -1058,8 +1065,10 @@
  */
 int __init APIC_init_uniprocessor (void)
 {
-	if (!smp_found_config && !cpu_has_apic)
+	if (!smp_found_config && !cpu_has_apic) { 
+		apic_disabled = 1;
 		return -1;
+	} 
 
 	/*
 	 * Complain if the BIOS pretends there is one.
@@ -1067,6 +1076,7 @@
 	if (!cpu_has_apic && APIC_INTEGRATED(apic_version[boot_cpu_id])) {
 		printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n",
 			boot_cpu_id);
+		apic_disabled = 1;
 		return -1;
 	}
 
@@ -1084,9 +1094,10 @@
 	if (nmi_watchdog == NMI_LOCAL_APIC)
 		check_nmi_watchdog();
 #ifdef CONFIG_X86_IO_APIC
-	if (smp_found_config)
-		if (!skip_ioapic_setup && nr_ioapics)
+	if (smp_found_config && !skip_ioapic_setup && nr_ioapics)
 			setup_IO_APIC();
+	else
+		nr_ioapics = 0;
 #endif
 	setup_APIC_clocks();
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/bluesmoke.c linux-2.4.21-pre6/arch/x86_64/kernel/bluesmoke.c
--- linux-2.4.20/arch/x86_64/kernel/bluesmoke.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/kernel/bluesmoke.c	2003-03-26 23:49:52.000000000 +0000
@@ -1,6 +1,6 @@
 /* 
  * Machine check handler.
- * K8 parts Copyright 2002 Andi Kleen, SuSE Labs.
+ * K8 parts Copyright 2002,2003 Andi Kleen, SuSE Labs.
  * Rest from unknown author(s). 
  */
 #include <linux/init.h>
@@ -15,14 +15,23 @@
 #include <linux/pci.h>
 #include <linux/timer.h>
 
-static int mce_disabled __initdata = 1;
+static int mce_disabled __initdata;
+static unsigned long mce_cpus; 
 
 /*
  *	Machine Check Handler For PII/PIII/K7
  */
 
 static int banks;
-static unsigned long ignored_banks, disabled_banks =  (1UL << 4); 
+static unsigned long ignored_banks, disabled_banks;
+
+/* Machine Check on everything dubious. This is a good setting
+   for device driver testing. */
+#define K8_DRIVER_DEBUG ((1<<13)-1)
+/* Report RAM errors and Hyper Transport Problems, but ignore Device
+   aborts and GART errors. */
+#define K8_NORMAL_OP    0xff
+static u32 k8_nb_flags __initdata = K8_NORMAL_OP;
 
 static void generic_machine_check(struct pt_regs * regs, long error_code)
 {
@@ -96,7 +105,7 @@
 
 void do_machine_check(struct pt_regs * regs, long error_code)
 {
-	notify_die(DIE_NMI, "machine check", regs, error_code);
+	notify_die(DIE_NMI, "machine check", regs, error_code, 255, SIGKILL);
 	machine_check_vector(regs, error_code);
 }
 
@@ -116,14 +125,48 @@
 	return NULL;
 }
 
+static void check_k8_nb(void)
+{
+	struct pci_dev *nb;
+	nb = find_k8_nb(); 
+	if (nb == NULL)
+		return;
+
+	u32 statuslow, statushigh;
+	pci_read_config_dword(nb, 0x48, &statuslow);
+	pci_read_config_dword(nb, 0x4c, &statushigh);
+	if (!(statushigh & (1<<31)))
+		return;
+	printk(KERN_ERR "Northbridge status %08x%08x\n",
+	       statushigh,statuslow); 
+	if (statuslow & 0x10) 
+		printk(KERN_ERR "GART error %d\n", statuslow & 0xf); 
+	if (statushigh & (1<<31))
+		printk(KERN_ERR "Lost an northbridge error\n"); 
+	if (statushigh & (1<<25))
+		printk(KERN_EMERG "NB status: unrecoverable\n"); 
+	if (statushigh & (1<<26)) { 
+		u32 addrhigh, addrlow; 
+		pci_read_config_dword(nb, 0x54, &addrhigh); 
+		pci_read_config_dword(nb, 0x50, &addrlow); 
+		printk(KERN_ERR "NB error address %08x%08x\n", addrhigh,addrlow); 
+	}
+	if (statushigh & (1<<29))
+		printk(KERN_EMERG "Error uncorrected\n"); 
+	statushigh &= ~(1<<31); 
+	pci_write_config_dword(nb, 0x4c, statushigh); 		
+}
+
 static void k8_machine_check(struct pt_regs * regs, long error_code)
 { 
 	u64 status, nbstatus;
-	struct pci_dev *nb;
 
 	rdmsrl(MSR_IA32_MCG_STATUS, status); 
-	if ((status & (1<<2)) == 0) 
+	if ((status & (1<<2)) == 0) { 
+		if (!regs) 
+			check_k8_nb();
 		return; 
+	}
 	if (status & 1)
 		printk(KERN_EMERG "MCG_STATUS: unrecoverable\n"); 
 
@@ -141,28 +184,7 @@
 	if (nbstatus & (1UL<57))
 		printk(KERN_EMERG "Unrecoverable condition\n"); 
 		
-	nb = find_k8_nb(); 
-	if (nb != NULL) { 
-		u32 statuslow, statushigh;
-		pci_read_config_dword(nb, 0x48, &statuslow);
-		pci_read_config_dword(nb, 0x4c, &statushigh);
-		printk(KERN_EMERG "Northbridge status %08x%08x\n",
-		       statushigh,statuslow); 
-		if (statuslow & 0x10) 
-			printk(KERN_EMERG "GART error %d\n", statuslow & 0xf); 
-		if (statushigh & (1<<31))
-			printk(KERN_EMERG "Lost an northbridge error\n"); 
-		if (statushigh & (1<<25))
-			printk(KERN_EMERG "NB status: unrecoverable\n"); 
-		if (statushigh & (1<<26)) { 
-			u32 addrhigh, addrlow; 
-			pci_read_config_dword(nb, 0x54, &addrhigh); 
-			pci_read_config_dword(nb, 0x50, &addrlow); 
-			printk(KERN_EMERG "NB error address %08x%08x\n", addrhigh,addrlow); 
-		}
-		statushigh &= ~(1<<31); 
-		pci_write_config_dword(nb, 0x4c, statushigh); 		
-	} 
+	check_k8_nb();
 
 	if (nbstatus & (1UL<<58)) { 
 		u64 adr;
@@ -183,33 +205,38 @@
 static struct timer_list mcheck_timer;
 int mcheck_interval = 30*HZ; 
 
+#ifndef CONFIG_SMP 
 static void mcheck_timer_handler(unsigned long data)
 {
 	k8_machine_check(NULL,0);
-	BUG_ON(timer_pending(&mcheck_timer));
 	mcheck_timer.expires = jiffies + mcheck_interval;
 	add_timer(&mcheck_timer);
 }
+#else
 
-#ifdef CONFIG_SMP 
 /* SMP needs a process context trampoline because smp_call_function cannot be 
-   called from interrupt context */
+   called from interrupt context. */
+
+static void mcheck_timer_other(void *data)
+{ 
+	k8_machine_check(NULL, 0); 
+} 
+
 static void mcheck_timer_dist(void *data)
 { 
-	/* preempt disabled on preemptive kernel */	
-	if (!data) 
-		smp_call_function((void (*)(void *))mcheck_timer_handler,(void*)1,0,0);
-	mcheck_timer_handler(0); 	
+	smp_call_function(mcheck_timer_other,0,0,0);
+	k8_machine_check(NULL, 0); 
+	mcheck_timer.expires = jiffies + mcheck_interval;
+	add_timer(&mcheck_timer);
 } 
 
-static void mcheck_timer_trampoline(unsigned long data)
+static void mcheck_timer_handler(unsigned long data)
 { 
 	static struct tq_struct mcheck_task = { 
 		routine: mcheck_timer_dist
 	}; 
 	schedule_task(&mcheck_task); 
 } 
-#define mcheck_timer_handler mcheck_timer_trampoline
 #endif 
 
 static int nok8 __initdata; 
@@ -235,17 +262,19 @@
 
 	nb = find_k8_nb(); 
 	if (nb != NULL) {
-		u32 reg;
+		u32 reg, reg2;
 		pci_read_config_dword(nb, 0x40, &reg); 
-		pci_write_config_dword(nb, 0x40, reg|(1<<11)|(1<<10)|(1<<9)|(1<<8)); 
-		printk(KERN_INFO "Machine Check Reporting for K8 Northbridge %d enabled\n",
-		       nb->devfn);
+		pci_write_config_dword(nb, 0x40, k8_nb_flags);
+		pci_read_config_dword(nb, 0x44, &reg2);
+		pci_write_config_dword(nb, 0x44, reg2); 
+		printk(KERN_INFO "Machine Check for K8 Northbridge %d enabled (%x,%x)\n",
+		       nb->devfn, reg, reg2);
 		ignored_banks |= (1UL<<4); 
 	} 
 
 	set_in_cr4(X86_CR4_MCE);	   	
 
-	if (mcheck_interval) { 
+	if (mcheck_interval && (smp_processor_id() == 0)) { 
 		init_timer(&mcheck_timer); 
 		mcheck_timer.function = (void (*)(unsigned long))mcheck_timer_handler; 
 		mcheck_timer.expires = jiffies + mcheck_interval; 
@@ -308,6 +337,9 @@
 
 void __init mcheck_init(struct cpuinfo_x86 *c)
 {
+	if (test_and_set_bit(smp_processor_id(), &mce_cpus))
+		return; 
+
 	if(mce_disabled==1)
 		return;
 		
@@ -333,9 +365,10 @@
 
 
 /* mce=off disable machine check
-   mcenok8 disable k8 specific features
+   mce=nok8 disable k8 specific features
    mce=disable<NUMBER> disable bank NUMBER
    mce=enable<NUMBER> enable bank number
+   mce=device	Enable device driver test reporting in NB
    mce=NUMBER mcheck timer interval number seconds. 
    Can be also comma separated in a single mce= */
 static int __init mcheck_enable(char *str)
@@ -352,8 +385,8 @@
 			disabled_banks |= ~(1<<simple_strtol(p+7,NULL,0));
 		else if (!strcmp(p,"nok8"))
 			nok8 = 1;
-		else
-			return -1;			
+		else if (!strcmp(p,"device"))
+			k8_nb_flags = K8_DRIVER_DEBUG;
 	}
 	return 0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/e820.c linux-2.4.21-pre6/arch/x86_64/kernel/e820.c
--- linux-2.4.20/arch/x86_64/kernel/e820.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/kernel/e820.c	2003-03-26 23:49:26.000000000 +0000
@@ -1,7 +1,7 @@
 /* 
  * Handle the memory map.
  * The functions here do the job until bootmem takes over.
- * $Id: e820.c,v 1.4 2002/09/19 19:25:32 ak Exp $
+ * $Id: e820.c,v 1.6 2002/10/15 09:35:16 ak Exp $
  */
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -122,27 +122,51 @@
 }
 
 /*
+ * end_pfn only includes RAM, while end_pfn_map includes all e820 entries.
+ * The direct mapping extends to end_pfn_map, so that we can directly access
+ * ACPI and other tables without having to play with fixmaps.
+ */ 
+unsigned long end_pfn_map; 
+
+/* 
+ * Last pfn which the user wants to use.
+ */
+unsigned long end_user_pfn = MAXMEM>>PAGE_SHIFT;  
+
+/*
  * Find the highest page frame number we have available
  */
+
 void __init e820_end_of_ram(void)
 {
 	int i;
 	end_pfn = 0;
+	
 	for (i = 0; i < e820.nr_map; i++) {
 		struct e820entry *ei = &e820.map[i]; 
 		unsigned long start, end;
 
-		/* count all types of areas for now to map ACPI easily */
 		start = round_up(ei->addr, PAGE_SIZE); 
 		end = round_down(ei->addr + ei->size, PAGE_SIZE); 
 		if (start >= end)
 			continue;
+		if (ei->type == E820_RAM) { 
 		if (end > end_pfn<<PAGE_SHIFT)
 			end_pfn = end>>PAGE_SHIFT;
+		} else { 
+			if (end > end_pfn_map<<PAGE_SHIFT) 
+				end_pfn_map = end>>PAGE_SHIFT;
+		} 
 	}
 
-	if (end_pfn > MAXMEM >> PAGE_SHIFT)
-		end_pfn = MAXMEM >> PAGE_SHIFT;
+	if (end_pfn > end_pfn_map) 
+		end_pfn_map = end_pfn;
+	if (end_pfn_map > MAXMEM>>PAGE_SHIFT)
+		end_pfn_map = MAXMEM>>PAGE_SHIFT;
+	if (end_pfn > end_user_pfn)
+		end_pfn = end_user_pfn;
+	if (end_pfn > end_pfn_map) 
+		end_pfn = end_pfn_map; 
 }
 
 /* 
@@ -481,7 +505,6 @@
 {
 	char c = ' ', *to = command_line, *from = COMMAND_LINE;
 	int len = 0;
-	int usermem = 0;
 
 	/* Save unparsed command line copy for /proc/cmdline */
 	memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE);
@@ -492,44 +515,23 @@
 			goto next;
 
 		/*
-		 * "mem=XXX[kKmM]" defines a memory region from HIGH_MEM
-		 * to <mem>, overriding the bios size.
-		 * "mem=XXX[KkmM]@XXX[KkmM]" defines a memory region from
-		 * <start> to <start>+<mem>, overriding the bios size.
+		 * mem=XXX[kKmM] limits kernel memory to XXX+1MB
+		 *
+		 * It would be more logical to count from 0 instead of from
+		 * HIGH_MEMORY, but we keep that for now for i386 compatibility. -AK
 		 */
 		if (!memcmp(from, "mem=", 4)) {
-			if (to != command_line)
-				to--;
-			else if (!memcmp(from+4, "exactmap", 8)) {
-				from += 8+4;
-				e820.nr_map = 0;
-				usermem = 1;
-			} else {
-				/* If the user specifies memory size, we
-				 * blow away any automatically generated
-				 * size
-				 */
-				unsigned long long start_at, mem_size;
- 
-				if (usermem == 0) {
-					/* first time in: zap the whitelist
-					 * and reinitialize it with the
-					 * standard low-memory region.
+			/* 
+			 * No support for custom mapping like i386.
+			 * The reason is that we need to read the e820 map
+			 * anyways to handle the ACPI mappings in the 
+			 * direct map.
+			 * Also on x86-64 there should be always a good e820
+			 * map. This is only an upper limit, you cannot force
+			 * usage of memory not in e820.
 					 */
-					e820.nr_map = 0;
-					usermem = 1;
-					add_memory_region(0, LOWMEMSIZE(), E820_RAM);
-				}
-				mem_size = memparse(from+4, &from);
-				if (*from == '@')
-					start_at = memparse(from+1, &from);
-				else {
-					start_at = HIGH_MEMORY;
-					mem_size -= HIGH_MEMORY;
-					usermem=0;
-				}
-				add_memory_region(start_at, mem_size, E820_RAM);
-			}
+			end_user_pfn = memparse(from+4, &from) + HIGH_MEMORY;
+			end_user_pfn >>= PAGE_SHIFT;
 		}
 #ifdef CONFIG_GART_IOMMU 
 		else if (!memcmp(from,"iommu=",6)) { 
@@ -547,8 +549,4 @@
 	}
 	*to = '\0';
 	*cmdline_p = command_line;
-	if (usermem) {
-		printk(KERN_INFO "user-defined physical RAM map:\n");
-		e820_print_map("user");
-	}
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/entry.S linux-2.4.21-pre6/arch/x86_64/kernel/entry.S
--- linux-2.4.20/arch/x86_64/kernel/entry.S	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/kernel/entry.S	2003-03-26 23:49:53.000000000 +0000
@@ -5,7 +5,7 @@
  *  Copyright (C) 2000, 2001, 2002  Andi Kleen SuSE Labs
  *  Copyright (C) 2000  Pavel Machek <pavel@suse.cz>
  * 
- *  $Id: entry.S,v 1.81 2002/09/12 12:55:25 ak Exp $		
+ *  $Id: entry.S,v 1.93 2003/02/20 12:52:08 ak Exp $		
  */
 
 /*
@@ -34,6 +34,7 @@
 #include <asm/offset.h>
 #include <asm/msr.h>
 #include <asm/unistd.h>
+#include <asm/hw_irq.h>
 
 	.code64
 
@@ -85,6 +86,7 @@
 2:
 	movq %rsp,%rdi	
 	call syscall_trace
+	GET_CURRENT(%rcx)
 	jmp 1b
 
 /*
@@ -187,6 +189,7 @@
 	jmp ret_from_sys_call
 		
 badsys:
+	movq $0,ORIG_RAX-ARGOFFSET(%rsp)
 	movq $-ENOSYS,RAX-ARGOFFSET(%rsp)
 	jmp ret_from_sys_call
 
@@ -227,6 +230,7 @@
 	je   retint_restore_args_swapgs
 	sti
 	call schedule
+	# RED-PEN: can we lose signals here?
 	jmp  intret_signal_test
 	
 /* 
@@ -307,8 +311,13 @@
 	je   1f
 	swapgs
 1:	cld
+#ifdef CONFIG_KGDB
+	SAVE_ALL
+	movq %rsp,%rdi
+#else			
 	SAVE_ARGS
 	leaq -ARGOFFSET(%rsp),%rdi	# arg1 for handler
+#endif	
 	addl $1,PDAREF(pda_irqcount)	# XXX: should be merged with irq.c irqcount
 	movq PDAREF(pda_irqstackptr),%rax
 	cmoveq %rax,%rsp
@@ -369,6 +378,48 @@
 	cli
 	jmp retint_with_reschedule
 		
+/* IF:off, stack contains irq number on origrax */ 	
+	.macro IRQ_ENTER	
+	cld
+	pushq %rdi
+	pushq %rsi
+	pushq %rdx
+	pushq %rcx
+	pushq %rax
+	pushq %r8
+	pushq %r9
+	pushq %r10
+	pushq %r11
+	leaq -48(%rsp),%rdi
+	testl $3,136(%rdi)
+	je 1f
+	swapgs
+1:	addl $1,%gs:pda_irqcount
+	movq %gs:pda_irqstackptr,%rax
+	cmoveq %rax,%rsp
+	pushq %rdi
+	.endm	
+
+	.macro BUILD_SMP_INTERRUPT x,v
+ENTRY(\x)
+	push $\v-256
+	IRQ_ENTER
+	call smp_\x
+	jmp ret_from_intr
+	.endm
+
+#ifdef CONFIG_SMP				
+	BUILD_SMP_INTERRUPT reschedule_interrupt,RESCHEDULE_VECTOR
+	BUILD_SMP_INTERRUPT invalidate_interrupt,INVALIDATE_TLB_VECTOR
+	BUILD_SMP_INTERRUPT call_function_interrupt,CALL_FUNCTION_VECTOR
+#endif
+#ifdef CONFIG_X86_LOCAL_APIC
+	BUILD_SMP_INTERRUPT apic_timer_interrupt,LOCAL_TIMER_VECTOR
+	BUILD_SMP_INTERRUPT error_interrupt,ERROR_APIC_VECTOR
+	BUILD_SMP_INTERRUPT spurious_interrupt,SPURIOUS_APIC_VECTOR
+#endif
+		
+		
 /*
  * Exception entry points.
  */ 		
@@ -407,8 +458,7 @@
 	je error_kernelspace
 	swapgs	
 	movl $1,%r15d	
-error_action:		
-	sti	
+error_action:
 	movq  %rdi,RDI(%rsp) 	
 	movq %rsp,%rdi
 	movq ORIG_RAX(%rsp),%rsi	/* get error code */ 
@@ -432,11 +482,15 @@
 	jmp retint_restore_args
 	
 error_reschedule:
+	cmpl $2,%r15d
+	je  error_restore_swapgs
 	sti
 	call schedule
 	jmp  error_test
 
 error_signal:	
+	cmpl $2,%r15d
+	je  error_restore_swapgs	
 	sti
 	xorq %rsi,%rsi
 	movq %rsp,%rdi
@@ -452,12 +506,38 @@
 	
 error_kernelspace:	
 	xorl %r15d,%r15d
+	/* There are two places in the kernel that can potentially fault with
+	   usergs. Handle them here. */	   
 	cmpq $iret_label,RIP(%rsp)
+	je   1f
+	cmpq $gs_change,RIP(%rsp)
 	jne  error_action
-	movl $1,%r15d
+1:	movl $2,%r15d
 	swapgs
 	jmp error_action
 
+	/* Reload gs selector with exception handling */
+	/* edi:	 new selector */ 
+ENTRY(load_gs_index)
+	pushf
+	cli
+	swapgs
+gs_change:	
+	movl %edi,%gs	
+2:	mfence
+	swapgs
+	popf
+	ret
+	
+	.section __ex_table,"a"
+	.align 8
+	.quad gs_change,bad_gs
+	.previous
+
+bad_gs:
+	xorl %eax,%eax
+	movl %eax,%gs
+	jmp 2b
 /*
  * Create a kernel thread.
  *
@@ -535,18 +615,6 @@
 	ret
 
 ENTRY(page_fault)
-#ifdef CONFIG_KDB
-	pushq %rcx
-	pushq %rdx
-	pushq %rax
-	movl  $473,%ecx
-	rdmsr
-	andl  $0xfffffffe,%eax		/* Disable last branch recording */
-	wrmsr
-	popq  %rax
-	popq  %rdx
-	popq  %rcx
-#endif	
 	errorentry do_page_fault
 
 ENTRY(coprocessor_error)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/head.S linux-2.4.21-pre6/arch/x86_64/kernel/head.S
--- linux-2.4.20/arch/x86_64/kernel/head.S	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/kernel/head.S	2003-03-26 23:49:40.000000000 +0000
@@ -6,7 +6,7 @@
  *  Copyright (C) 2000 Karsten Keil <kkeil@suse.de>
  *  Copyright (C) 2001,2002 Andi Kleen <ak@suse.de>
  *
- *  $Id: head.S,v 1.53 2002/07/18 09:49:42 ak Exp $
+ *  $Id: head.S,v 1.55 2003/02/11 12:29:15 ak Exp $
  */
 
 
@@ -76,13 +76,11 @@
 	/* Enable System Call */
 	btsl	$_EFER_SCE, %eax
 
-#if 0
 	/* No Execute supported? */	
 	btl	$20,%edi
 	jnc     1f
 	btsl	$_EFER_NX, %eax
 1:
-#endif
 	
 	/* Make changes effective */
 	wrmsr
@@ -118,7 +116,6 @@
 	jnz   second	
 	
 	/* Load new GDT with the 64bit segment using 32bit descriptor */
-	/* to avoid 32bit relocations we use fixed adresses here */
 	movl	$0x100F00, %eax
 	lgdt	(%eax)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/i387.c linux-2.4.21-pre6/arch/x86_64/kernel/i387.c
--- linux-2.4.20/arch/x86_64/kernel/i387.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/kernel/i387.c	2003-03-26 23:49:35.000000000 +0000
@@ -25,19 +25,16 @@
 
 extern int exception_trace;
 
-/*
- * The _current_ task is using the FPU for the first time
- * so initialize it and set the mxcsr to its default
- * value at reset if we support XMM instructions and then
- * remeber the current task has used the FPU.
- */
-void init_fpu(void)
+void init_fpu(struct task_struct *child)
 {
-	struct task_struct *me = current;
-	memset(&me->thread.i387.fxsave, 0, sizeof(struct i387_fxsave_struct));
-	me->thread.i387.fxsave.cwd = 0x37f;
-	me->thread.i387.fxsave.mxcsr = 0x1f80;
-	me->used_math = 1;
+	if (child->used_math) { 
+		unlazy_fpu(child);
+		return;
+	}
+	memset(&child->thread.i387.fxsave, 0, sizeof(struct i387_fxsave_struct));
+	child->thread.i387.fxsave.cwd = 0x37f;
+	child->thread.i387.fxsave.mxcsr = 0x1f80;
+	child->used_math = 1;
 }
 
 /*
@@ -81,7 +78,7 @@
 
 int get_fpregs(struct user_i387_struct *buf, struct task_struct *tsk)
 {
-	empty_fpu(tsk);
+	init_fpu(tsk);
 	return __copy_to_user((void *)buf, &tsk->thread.i387.fxsave,
 			       sizeof(struct user_i387_struct)) ? -EFAULT : 0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/i8259.c linux-2.4.21-pre6/arch/x86_64/kernel/i8259.c
--- linux-2.4.20/arch/x86_64/kernel/i8259.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/kernel/i8259.c	2003-03-26 23:48:57.000000000 +0000
@@ -40,8 +40,6 @@
  * interrupt-controller happy.
  */
 
-BUILD_COMMON_IRQ()
-
 #define BI(x,y) \
 	BUILD_IRQ(x##y)
 
@@ -77,24 +75,6 @@
 #undef BUILD_16_IRQS
 #undef BI
 
-
-/*
- * The following vectors are part of the Linux architecture, there
- * is no hardware IRQ pin equivalent for them, they are triggered
- * through the ICC by us (IPIs)
- */
-#ifdef CONFIG_SMP
-BUILD_SMP_INTERRUPT(reschedule_interrupt,RESCHEDULE_VECTOR);
-BUILD_SMP_INTERRUPT(invalidate_interrupt,INVALIDATE_TLB_VECTOR);
-BUILD_SMP_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR);
-#endif
-
-#ifdef CONFIG_X86_LOCAL_APIC
-BUILD_SMP_INTERRUPT(apic_timer_interrupt,LOCAL_TIMER_VECTOR);
-BUILD_SMP_INTERRUPT(error_interrupt,ERROR_APIC_VECTOR);
-BUILD_SMP_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR);
-#endif
-
 #define IRQ(x,y) \
 	IRQ##x##y##_interrupt
 
@@ -424,7 +404,7 @@
 	 */
 	for (i = 0; i < NR_IRQS; i++) {
 		int vector = FIRST_EXTERNAL_VECTOR + i;
-		if (vector != IA32_SYSCALL_VECTOR && vector != KDBENTER_VECTOR) {
+		if (vector != IA32_SYSCALL_VECTOR) {
 			set_intr_gate(vector, interrupt[i]);
 		}
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/io_apic.c linux-2.4.21-pre6/arch/x86_64/kernel/io_apic.c
--- linux-2.4.20/arch/x86_64/kernel/io_apic.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/kernel/io_apic.c	2003-03-26 23:49:25.000000000 +0000
@@ -728,8 +728,10 @@
 
 void __init UNEXPECTED_IO_APIC(void)
 {
+#if 0
 	printk(KERN_WARNING " WARNING: unexpected IO-APIC, please mail\n");
 	printk(KERN_WARNING "          to linux-smp@vger.kernel.org\n");
+#endif
 }
 
 void __init print_IO_APIC(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/ioport.c linux-2.4.21-pre6/arch/x86_64/kernel/ioport.c
--- linux-2.4.20/arch/x86_64/kernel/ioport.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/kernel/ioport.c	2003-03-26 23:49:34.000000000 +0000
@@ -53,7 +53,7 @@
 /*
  * this changes the io permissions bitmap in the current task.
  */
-asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on)
+asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on)
 {
 	struct thread_struct * t = &current->thread;
 	struct tss_struct * tss = init_tss + smp_processor_id();
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/ldt.c linux-2.4.21-pre6/arch/x86_64/kernel/ldt.c
--- linux-2.4.20/arch/x86_64/kernel/ldt.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/kernel/ldt.c	2003-03-26 23:49:54.000000000 +0000
@@ -85,11 +85,6 @@
 			goto out;
 	}
 
-	me->thread.fsindex = 0; 
-	me->thread.gsindex = 0; 
-	me->thread.gs = 0; 
-	me->thread.fs = 0; 
-
 	/*
 	 * the GDT index of the LDT is allocated dynamically, and is
 	 * limited by MAX_LDT_DESCRIPTORS.
@@ -142,10 +137,8 @@
 
 	/* Install the new entry ...  */
 install:
-	write_lock(&mm->context.ldtlock);
 	*lp	= entry_1;
 	*(lp+1)	= entry_2;
-	write_unlock(&mm->context.ldtlock);
 	error = 0;
 
 out_unlock:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/msr.c linux-2.4.21-pre6/arch/x86_64/kernel/msr.c
--- linux-2.4.20/arch/x86_64/kernel/msr.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/kernel/msr.c	2003-03-26 23:49:34.000000000 +0000
@@ -1,4 +1,4 @@
-#ident "$Id: msr.c,v 1.7 2002/02/14 10:20:47 ak Exp $"
+#ident "$Id: msr.c,v 1.8 2003/01/10 15:17:43 ak Exp $"
 /* ----------------------------------------------------------------------- *
  *   
  *   Copyright 2000 H. Peter Anvin - All Rights Reserved
@@ -55,7 +55,7 @@
 	       "	jmp 2b\n"
 	       ".previous\n"
 	       ".section __ex_table,\"a\"\n"
-	       "	.align 4\n"
+	       "	.align 8\n"
 	       "	.quad 1b,3b\n"
 	       ".previous"
 	       : "=&bDS" (err)
@@ -76,7 +76,7 @@
 	       "	jmp 2b\n"
 	       ".previous\n"
 	       ".section __ex_table,\"a\"\n"
-	       "	.align 4\n"
+	       "	.align 8\n"
 	       "	.quad 1b,3b\n"
 	       ".previous"
 	       : "=&bDS" (err), "=a" (*eax), "=d" (*edx)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/nmi.c linux-2.4.21-pre6/arch/x86_64/kernel/nmi.c
--- linux-2.4.20/arch/x86_64/kernel/nmi.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/kernel/nmi.c	2003-03-26 23:49:20.000000000 +0000
@@ -31,6 +31,8 @@
 static unsigned int nmi_hz = HZ;
 unsigned int nmi_perfctr_msr;	/* the MSR to reset in NMI handler */
 
+int nmi_watchdog_disabled; 
+
 #define K7_EVNTSEL_ENABLE	(1 << 22)
 #define K7_EVNTSEL_INT		(1 << 20)
 #define K7_EVNTSEL_OS		(1 << 17)
@@ -223,6 +225,7 @@
 	wrmsr(MSR_K7_EVNTSEL0, evntsel, 0);
 }
 
+#ifndef CONFIG_MK8
 static void __pminit setup_p6_watchdog(void)
 {
 	unsigned int evntsel;
@@ -274,6 +277,7 @@
 	wrmsr(MSR_P4_IQ_CCCR0, P4_NMI_IQ_CCCR0, 0);
 	return 1;
 }
+#endif
 
 void __pminit setup_apic_nmi_watchdog (void)
 {
@@ -285,6 +289,7 @@
 			return;	    
 		setup_k7_watchdog();
 		break;
+#ifndef CONFIG_MK8
 	case X86_VENDOR_INTEL:
 		switch (boot_cpu_data.x86) {
 		case 6:
@@ -298,6 +303,7 @@
 			return;
 		}
 		break;
+#endif
 	default:
 		return;
 	}
@@ -337,14 +343,17 @@
 		alert_counter[i] = 0;
 }
 
-void nmi_watchdog_tick (struct pt_regs * regs)
+void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason)
 {
 
 	/*
 	 * Since current-> is always on the stack, and we always switch
 	 * the stack NMI-atomically, it's safe to use smp_processor_id().
 	 */
-	int sum, cpu = smp_processor_id();
+	int sum, cpu = safe_smp_processor_id();
+
+	if (nmi_watchdog_disabled)
+		return;
 
 	sum = apic_timer_irqs[cpu];
 
@@ -355,6 +364,14 @@
 		 */
 		alert_counter[cpu]++;
 		if (alert_counter[cpu] == 5*nmi_hz) {
+
+
+			if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_BAD) { 
+				alert_counter[cpu] = 0; 
+				return;
+			} 
+
+
 			spin_lock(&nmi_print_lock);
 			/*
 			 * We are in trouble anyway, lets at least try
@@ -374,6 +391,7 @@
 		alert_counter[cpu] = 0;
 	}
 	if (nmi_perfctr_msr) {
+#ifndef CONFIG_MK8
 		if (nmi_perfctr_msr == MSR_P4_IQ_COUNTER0) {
 			/*
 			 * P4 quirks:
@@ -385,6 +403,7 @@
 			wrmsr(MSR_P4_IQ_CCCR0, P4_NMI_IQ_CCCR0, 0);
 			apic_write(APIC_LVTPC, APIC_DM_NMI);
 		}
+#endif
 		wrmsr(nmi_perfctr_msr, -(cpu_khz/nmi_hz*1000), -1);
 	}
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/pci-dma.c linux-2.4.21-pre6/arch/x86_64/kernel/pci-dma.c
--- linux-2.4.20/arch/x86_64/kernel/pci-dma.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/kernel/pci-dma.c	2003-03-26 23:49:35.000000000 +0000
@@ -37,16 +37,16 @@
  	 */
  	for (i = 0; i < nents; i++ ) {
 		struct scatterlist *s = &sg[i];
- 		if (s->address) {
+		int flush = (i == nents-1);
+		void *addr = s->address; 
+		if (addr) 
 			BUG_ON(s->page || s->offset); 
- 			s->dma_address = pci_map_single(hwdev, s->address, s->length, 
-							direction); 
- 		} else if (s->page) { 
-			s->dma_address = pci_map_page(hwdev, s->page, s->offset,
-						      s->length, direction); 
-		} else
+		else if (s->page)
+			addr = page_address(s->page) + s->offset; 
+		else
 			BUG(); 
-
+		s->dma_address = __pci_map_single(hwdev, addr, s->length,
+						  direction, flush); 
 		if (unlikely(s->dma_address == bad_dma_address))
 			goto error; 
  	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/pci-gart.c linux-2.4.21-pre6/arch/x86_64/kernel/pci-gart.c
--- linux-2.4.20/arch/x86_64/kernel/pci-gart.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/kernel/pci-gart.c	2003-03-26 23:48:59.000000000 +0000
@@ -8,7 +8,7 @@
  * See Documentation/DMA-mapping.txt for the interface specification.
  * 
  * Copyright 2002 Andi Kleen, SuSE Labs.
- * $Id: pci-gart.c,v 1.12 2002/09/19 19:25:32 ak Exp $
+ * $Id: pci-gart.c,v 1.20 2003/03/12 08:23:29 ak Exp $
  */
 
 /* 
@@ -19,9 +19,12 @@
 
 possible future tuning: 
  fast path for sg streaming mappings 
- more intelligent flush strategy - flush only a single NB?
+ more intelligent flush strategy - flush only a single NB? flush only when
+ gart area fills up and alloc_iommu wraps. 
+ don't flush on allocation - need to unmap the gart area first to avoid prefetches
+ by the CPU
  move boundary between IOMMU and AGP in GART dynamically
- could use exact fit in the gart in alloc_consistent, not order of two.
+  
 */ 
 
 #include <linux/config.h>
@@ -49,7 +52,11 @@
 
 int no_iommu; 
 static int no_agp; 
+#ifdef CONFIG_IOMMU_DEBUG
 int force_mmu = 1;
+#else
+int force_mmu = 0;
+#endif
 
 extern int fallback_aper_order;
 extern int fallback_aper_force;
@@ -58,11 +65,10 @@
 static spinlock_t iommu_bitmap_lock = SPIN_LOCK_UNLOCKED;
 static unsigned long *iommu_gart_bitmap; /* guarded by iommu_bitmap_lock */
 
-#define GPTE_MASK 0xfffffff000
 #define GPTE_VALID    1
 #define GPTE_COHERENT 2
-#define GPTE_ENCODE(x,flag) (((x) & 0xfffffff0) | ((x) >> 28) | GPTE_VALID | (flag))
-#define GPTE_DECODE(x) (((x) & 0xfffff000) | (((x) & 0xff0) << 28))
+#define GPTE_ENCODE(x) (((x) & 0xfffff000) | (((x) >> 32) << 4) | GPTE_VALID | GPTE_COHERENT)
+#define GPTE_DECODE(x) (((x) & 0xfffff000) | (((u64)(x) & 0xff0) << 28))
 
 #define for_all_nb(dev) \
 	pci_for_each_dev(dev) \
@@ -129,7 +135,7 @@
 {
 	void *memory;
 	int gfp = GFP_ATOMIC;
-	int order, i;
+	int i;
 	unsigned long iommu_page;
 
 	if (hwdev == NULL || hwdev->dma_mask < 0xffffffff || no_iommu)
@@ -139,15 +145,15 @@
 	 * First try to allocate continuous and use directly if already 
 	 * in lowmem. 
 	 */ 
-	order = get_order(size);
-	memory = (void *)__get_free_pages(gfp, order);
+	size = round_up(size, PAGE_SIZE); 
+	memory = (void *)__get_free_pages(gfp, get_order(size));
 	if (memory == NULL) {
 		return NULL; 
 	} else {
 		int high = (unsigned long)virt_to_bus(memory) + size
 			>= 0xffffffff;
 		int mmu = high;
-		if (force_mmu) 
+		if (force_mmu && !(gfp & GFP_DMA)) 
 			mmu = 1;
 		if (no_iommu) { 
 			if (high) goto error;
@@ -160,19 +166,21 @@
 		}
 	} 
 
-	iommu_page = alloc_iommu(1<<order);
+	size >>= PAGE_SHIFT;
+
+	iommu_page = alloc_iommu(size);
 	if (iommu_page == -1)
 		goto error; 
 
    	/* Fill in the GATT, allocating pages as needed. */
-	for (i = 0; i < 1<<order; i++) { 
+	for (i = 0; i < size; i++) { 
 		unsigned long phys_mem; 
 		void *mem = memory + i*PAGE_SIZE;
 		if (i > 0) 
 			atomic_inc(&virt_to_page(mem)->count); 
 		phys_mem = virt_to_phys(mem); 
-		BUG_ON(phys_mem & ~PTE_MASK); 
-		iommu_gatt_base[iommu_page + i] = GPTE_ENCODE(phys_mem,GPTE_COHERENT); 
+		BUG_ON(phys_mem & ~PHYSICAL_PAGE_MASK); 
+		iommu_gatt_base[iommu_page + i] = GPTE_ENCODE(phys_mem); 
 	} 
 
 	flush_gart();
@@ -180,7 +188,7 @@
 	return memory; 
 	
  error:
-	free_pages((unsigned long)memory, order); 
+	free_pages((unsigned long)memory, get_order(size)); 
 	return NULL; 
 }
 
@@ -192,30 +200,32 @@
 			 void *vaddr, dma_addr_t bus)
 {
 	u64 pte;
-	int order = get_order(size);
 	unsigned long iommu_page;
 	int i;
 
+	size = round_up(size, PAGE_SIZE); 
 	if (bus < iommu_bus_base || bus > iommu_bus_base + iommu_size) { 
-		free_pages((unsigned long)vaddr, order); 		
+		free_pages((unsigned long)vaddr, get_order(size)); 		
 		return;
 	} 
+	size >>= PAGE_SHIFT;
 	iommu_page = (bus - iommu_bus_base) / PAGE_SIZE;
-	for (i = 0; i < 1<<order; i++) {
+	for (i = 0; i < size; i++) {
 		pte = iommu_gatt_base[iommu_page + i];
 		BUG_ON((pte & GPTE_VALID) == 0); 
 		iommu_gatt_base[iommu_page + i] = 0; 		
 		free_page((unsigned long) __va(GPTE_DECODE(pte)));
 	} 
 	flush_gart(); 
-	free_iommu(iommu_page, 1<<order);
+	free_iommu(iommu_page, size);
 }
 
 #ifdef CONFIG_IOMMU_LEAK
 /* Debugging aid for drivers that don't free their IOMMU tables */
 static void **iommu_leak_tab; 
 static int leak_trace;
-int iommu_leak_dumppages = 20; 
+int iommu_leak_pages = 20; 
+extern unsigned long printk_address(unsigned long);
 void dump_leak(void)
 {
 	int i;
@@ -223,10 +233,13 @@
 	if (dump || !iommu_leak_tab) return;
 	dump = 1;
 	show_stack(NULL);
-	printk("Dumping %d pages from end of IOMMU:\n", iommu_leak_dumppages); 
-	for (i = 0; i < iommu_leak_dumppages; i++) 
-		printk("[%lu: %lx] ",
-		       iommu_pages-i,(unsigned long) iommu_leak_tab[iommu_pages-i]); 
+	/* Very crude. dump some from the end of the table too */ 
+	printk("Dumping %d pages from end of IOMMU:\n", iommu_leak_pages); 
+	for (i = 0; i < iommu_leak_pages; i+=2) {
+		printk("%lu: ", iommu_pages-i);
+		printk_address((unsigned long) iommu_leak_tab[iommu_pages-i]);
+		printk("%c", (i+1)%2 == 0 ? '\n' : ' '); 
+	} 
 	printk("\n");
 }
 #endif
@@ -274,7 +287,8 @@
 	return mmu; 
 }
 
-dma_addr_t pci_map_single(struct pci_dev *dev, void *addr, size_t size,int dir)
+dma_addr_t __pci_map_single(struct pci_dev *dev, void *addr, size_t size,
+			    int dir, int flush)
 { 
 	unsigned long iommu_page;
 	unsigned long phys_mem, bus;
@@ -286,7 +300,7 @@
 	if (!need_iommu(dev, phys_mem, size))
 		return phys_mem; 
 
-	npages = round_up(size, PAGE_SIZE) >> PAGE_SHIFT;
+	npages = round_up(size + ((u64)addr & ~PAGE_MASK), PAGE_SIZE) >> PAGE_SHIFT;
 
 	iommu_page = alloc_iommu(npages); 
 	if (iommu_page == -1) {
@@ -296,13 +310,18 @@
 
 	phys_mem &= PAGE_MASK;
 	for (i = 0; i < npages; i++, phys_mem += PAGE_SIZE) {
-		BUG_ON(phys_mem & ~PTE_MASK); 
+		BUG_ON(phys_mem & ~PHYSICAL_PAGE_MASK); 
 		
 		/* 
 		 * Set coherent mapping here to avoid needing to flush
 		 * the caches on mapping.
 		 */
-		iommu_gatt_base[iommu_page + i] = GPTE_ENCODE(phys_mem, GPTE_COHERENT);
+		iommu_gatt_base[iommu_page + i] = GPTE_ENCODE(phys_mem);
+
+#ifdef CONFIG_IOMMU_DEBUG
+		/* paranoia check */
+		BUG_ON(GPTE_DECODE(iommu_gatt_base[iommu_page+i]) != phys_mem); 
+#endif
 
 #ifdef CONFIG_IOMMU_LEAK
 		/* XXX need eventually caller of pci_map_sg */
@@ -310,6 +329,7 @@
 			iommu_leak_tab[iommu_page + i] = __builtin_return_address(0); 
 #endif
 	}
+	if (flush)
 	flush_gart(); 
 
 	bus = iommu_bus_base + iommu_page*PAGE_SIZE; 
@@ -328,7 +348,7 @@
 	    dma_addr > iommu_bus_base + iommu_size)
 		return;
 	iommu_page = (dma_addr - iommu_bus_base)>>PAGE_SHIFT;	
-	npages = round_up(size, PAGE_SIZE) >> PAGE_SHIFT;
+	npages = round_up(size + (dma_addr & ~PAGE_MASK), PAGE_SIZE) >> PAGE_SHIFT;
 	for (i = 0; i < npages; i++) { 
 		iommu_gatt_base[iommu_page + i] = 0; 
 #ifdef CONFIG_IOMMU_LEAK
@@ -340,7 +360,7 @@
 	free_iommu(iommu_page, npages);
 }
 
-EXPORT_SYMBOL(pci_map_single);
+EXPORT_SYMBOL(__pci_map_single);
 EXPORT_SYMBOL(pci_unmap_single);
 
 static __init unsigned long check_iommu_size(unsigned long aper, u64 aper_size)
@@ -523,6 +543,8 @@
    off   don't use the IOMMU
    leak  turn on simple iommu leak tracing (only when CONFIG_IOMMU_LEAK is on)
    memaper[=order] allocate an own aperture over RAM with size 32MB^order.
+   noforce don't force IOMMU usage. Should be fastest.
+   force  Force IOMMU and turn on unmap debugging.
 */
 __init int iommu_setup(char *opt) 
 { 
@@ -545,8 +567,13 @@
 			    fallback_aper_order = arg;
 	    } 
 #ifdef CONFIG_IOMMU_LEAK
-	    if (!memcmp(p,"leak", 4))
+	    if (!memcmp(p,"leak", 4)) { 
 		    leak_trace = 1;
+		    p += 4; 
+		    if (*p == '=') ++p;
+		    if (isdigit(*p) && get_option(&p, &arg))
+			    iommu_leak_pages = arg;
+	    } else
 #endif
 	    if (isdigit(*p) && get_option(&p, &arg)) 
 		    iommu_size = arg;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/pci-x86_64.c linux-2.4.21-pre6/arch/x86_64/kernel/pci-x86_64.c
--- linux-2.4.20/arch/x86_64/kernel/pci-x86_64.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/kernel/pci-x86_64.c	2003-03-26 23:49:50.000000000 +0000
@@ -136,8 +136,7 @@
  * which might have be mirrored at 0x0100-0x03ff..
  */
 void
-pcibios_align_resource(void *data, struct resource *res, unsigned long size,
-		       unsigned long align)
+pcibios_align_resource(void *data, struct resource *res, unsigned long size, unsigned long align)
 {
 	if (res->flags & IORESOURCE_IO) {
 		unsigned long start = res->start;
@@ -313,9 +312,9 @@
 	pci_read_config_word(dev, PCI_COMMAND, &cmd);
 	old_cmd = cmd;
 	for(idx=0; idx<6; idx++) {
+		r = &dev->resource[idx];
 		if (!(mask & (1<<idx)))
 			continue;
-		r = &dev->resource[idx];
 		if (!r->start && r->end) {
 			printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name);
 			return -EINVAL;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/pci-x86_64.h linux-2.4.21-pre6/arch/x86_64/kernel/pci-x86_64.h
--- linux-2.4.20/arch/x86_64/kernel/pci-x86_64.h	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/kernel/pci-x86_64.h	2003-03-26 23:48:59.000000000 +0000
@@ -29,7 +29,7 @@
 extern unsigned int pcibios_max_latency;
 
 void pcibios_resource_survey(void);
-int pcibios_enable_resources(struct pci_dev *, int);
+int pcibios_enable_resources(struct pci_dev *, int mask);
 
 /* pci-pc.c */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/process.c linux-2.4.21-pre6/arch/x86_64/kernel/process.c
--- linux-2.4.20/arch/x86_64/kernel/process.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/kernel/process.c	2003-03-26 23:49:30.000000000 +0000
@@ -9,7 +9,7 @@
  *  X86-64 port
  *	Andi Kleen.
  * 
- *  $Id: process.c,v 1.57 2002/09/12 12:56:36 ak Exp $
+ *  $Id: process.c,v 1.63 2003/02/19 13:23:19 ak Exp $
  */
 
 /*
@@ -242,7 +242,6 @@
 	 * Stop all CPUs and turn off local APICs and the IO-APIC, so
 	 * other OSs see a clean IRQ state.
 	 */
-	if (notify_die(DIE_STOP,"cpustop",0,0) != NOTIFY_BAD)
 		smp_send_stop();
 	disable_IO_APIC();
 #endif
@@ -275,6 +274,8 @@
 		pm_power_off();
 }
 
+extern int printk_address(unsigned long); 
+
 /* Prints also some state that isn't saved in the pt_regs */ 
 void show_regs(struct pt_regs * regs)
 {
@@ -284,8 +285,9 @@
 
 	printk("\n");
 	printk("Pid: %d, comm: %.20s %s\n", current->pid, current->comm, print_tainted());
-	printk("RIP: %04lx:[<%016lx>]\n", regs->cs & 0xffff, regs->rip);
-	printk("RSP: %04lx:%016lx  EFLAGS: %08lx\n", regs->ss, regs->rsp, regs->eflags);
+	printk("RIP: %04lx:", regs->cs & 0xffff);
+	printk_address(regs->rip); 
+	printk("\nRSP: %04lx:%016lx  EFLAGS: %08lx\n", regs->ss, regs->rsp, regs->eflags);
 	printk("RAX: %016lx RBX: %016lx RCX: %016lx\n",
 	       regs->rax, regs->rbx, regs->rcx);
 	printk("RDX: %016lx RSI: %016lx RDI: %016lx\n",
@@ -316,6 +318,8 @@
 	       fs,fsindex,gs,gsindex,shadowgs); 
 	printk("CS:  %04x DS: %04x ES: %04x CR0: %016lx\n", cs, ds, es, cr0); 
 	printk("CR2: %016lx CR3: %016lx CR4: %016lx\n", cr2, cr3, cr4);
+
+	show_trace(&regs->rsp);
 }
 
 /*
@@ -336,37 +340,6 @@
 }
 
 /* 
- * Reloading %gs is a bit complicated because the kernel relies on it 
- * This includes the exception handlers, so we cannot take any exceptions
- * while doing this. Check the new gs value manually for validity and only
- * then load it. This needs locking again parallel CPUs that share the same
- * LDT. This has to be done in the context switch iff %gs changes.
- */
-void load_gs_index(unsigned gs)
-{
-	struct mm_struct *mm = current->mm;
-	int access; 
-	/* paranoia: */
-	if ((gs & 3) != 2) gs = 0;
-	if (mm) 
-		read_lock(&mm->context.ldtlock); 
-	asm volatile("pushf\n\t" 
-		     "cli\n\t"
-		     "swapgs\n\t"
-		     /* cannot take any exception until the next swapgs */
-		     "lar %1,%0\n\t"
-		     "jnz 1f\n\t"
-		     "movl %1,%%eax\n\t"
-		     "movl %%eax,%%gs\n\t"
-		     "jmp 2f\n\t"
-		     "1: movl %2,%%gs\n\t"
-		     "2: swapgs\n\t"
-		     "popf" : "=g" (access) : "g" (gs), "r" (0) : "rax"); 
-	if (mm)
-		read_unlock(&mm->context.ldtlock);
-}
-	
-/*
  * Free current thread data structures etc..
  */
 void exit_thread(void)
@@ -486,10 +459,6 @@
 /*
  *	switch_to(x,y) should switch tasks from x to y.
  *
- * We fsave/fwait so that an exception goes off at the right time
- * (as a call from the fsave or fwait in effect) rather than to
- * the wrong process. 
- * 
  * This could still be optimized: 
  * - fold all the options into a flag word and test it with a single test.
  * - could test fs/gs bitsliced
@@ -520,29 +489,37 @@
 
 	/* 
 	 * Switch FS and GS.
-	 * XXX Check if this is safe on SMP (!= -> |)
 	 */
 	{ 
-		unsigned int fsindex;
-
+		unsigned fsindex;
 		asm volatile("movl %%fs,%0" : "=g" (fsindex)); 
-		if (unlikely(fsindex != next->fsindex)) /* or likely? */
+		/* segment register != 0 always requires a reload. 
+		   also reload when it has changed. 
+		   when prev process used 64bit base always reload
+		   to avoid an information leak. */
+		if (unlikely((fsindex | next->fsindex) || prev->fs)) {
 			loadsegment(fs, next->fsindex);
-		if (unlikely(fsindex != prev->fsindex))
+			/* check if the user use a selector != 0
+			 * if yes clear 64bit base, since overloaded base
+			 * is allways mapped to the Null selector
+			 */
+			if (fsindex)
 			prev->fs = 0; 
-		if ((fsindex != prev->fsindex) || (prev->fs != next->fs))
+		}
+		/* when next process has a 64bit base use it */
+		if (next->fs) 
 			wrmsrl(MSR_FS_BASE, next->fs); 
 		prev->fsindex = fsindex;
 	}
 	{
-		unsigned int gsindex;
-
+		unsigned gsindex;
 		asm volatile("movl %%gs,%0" : "=g" (gsindex)); 
-		if (unlikely(gsindex != next->gsindex))
-			load_gs_index(next->gs); 
-		if (unlikely(gsindex != prev->gsindex)) 
+		if (unlikely((gsindex | next->gsindex) || prev->gs)) {
+			load_gs_index(next->gsindex);
+			if (gsindex)
 			prev->gs = 0;				
-		if (gsindex != prev->gsindex || prev->gs != next->gs)
+		}
+		if (next->gs)
 			wrmsrl(MSR_KERNEL_GS_BASE, next->gs); 
 		prev->gsindex = gsindex;
 	}
@@ -695,16 +672,18 @@
 	case ARCH_SET_GS:
 		if (addr >= TASK_SIZE) 
 			return -EPERM; 
-		asm volatile("movw %%gs,%0" : "=g" (current->thread.gsindex)); 
+		asm volatile("movl %0,%%gs" :: "r" (0)); 
+		current->thread.gsindex = 0;
 		current->thread.gs = addr;
 		ret = checking_wrmsrl(MSR_KERNEL_GS_BASE, addr); 
 		break;
 	case ARCH_SET_FS:
 		/* Not strictly needed for fs, but do it for symmetry
-		   with gs */
+		   with gs. */
 		if (addr >= TASK_SIZE)
 			return -EPERM; 
-		asm volatile("movw %%fs,%0" : "=g" (current->thread.fsindex)); 
+		asm volatile("movl %0,%%fs" :: "r" (0)); 
+		current->thread.fsindex = 0;
 		current->thread.fs = addr;
 		ret = checking_wrmsrl(MSR_FS_BASE, addr); 
 		break;
@@ -726,4 +705,3 @@
 	} 
 	return ret;	
 } 
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/ptrace.c linux-2.4.21-pre6/arch/x86_64/kernel/ptrace.c
--- linux-2.4.20/arch/x86_64/kernel/ptrace.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/kernel/ptrace.c	2003-03-26 23:49:20.000000000 +0000
@@ -90,6 +90,8 @@
 	unsigned long regno, unsigned long value)
 {
 	unsigned long tmp; 
+	if (child->thread.flags & THREAD_IA32)
+		value &= 0xffffffff;
 	switch (regno) {
 		case offsetof(struct user_regs_struct,fs):
 			if (value && (value & 3) != 3)
@@ -144,6 +146,7 @@
 
 static unsigned long getreg(struct task_struct *child, unsigned long regno)
 {
+	unsigned long val; 
 	switch (regno) {
 		case offsetof(struct user_regs_struct, fs):
 			return child->thread.fsindex;
@@ -159,7 +162,10 @@
 			return child->thread.gs;
 		default:
 			regno = regno - sizeof(struct pt_regs);
-			return get_stack_long(child, regno);
+			val = get_stack_long(child, regno);
+			if (child->thread.flags & THREAD_IA32) 
+				val &= 0xffffffff;
+			return val;
 	}
 
 }
@@ -228,8 +234,8 @@
 		unsigned long tmp;
 
 		ret = -EIO;
-		if ((addr & 3) || addr < 0 || 
-		    addr > sizeof(struct user) - 3)
+		if ((addr & 7) || addr < 0 || 
+		    addr > sizeof(struct user) - 7)
 			break;
 
 		tmp = 0;  /* Default return condition */
@@ -238,7 +244,7 @@
 		if(addr >= (long) &dummy->u_debugreg[0] &&
 		   addr <= (long) &dummy->u_debugreg[7]){
 			addr -= (long) &dummy->u_debugreg[0];
-			addr = addr >> 2;
+			addr = addr >> 3;
 			tmp = child->thread.debugreg[addr];
 		}
 		ret = put_user(tmp,(unsigned long *) data);
@@ -256,8 +262,8 @@
 
 	case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
 		ret = -EIO;
-		if ((addr & 3) || addr < 0 || 
-		    addr > sizeof(struct user) - 3)
+		if ((addr & 7) || addr < 0 || 
+		    addr > sizeof(struct user) - 7)
 			break;
 
 		if (addr < sizeof(struct user_regs_struct)) {
@@ -278,6 +284,11 @@
 			  if(addr < (long) &dummy->u_debugreg[4] &&
 			     ((unsigned long) data) >= TASK_SIZE-3) break;
 			  
+			  if (addr == (long) &dummy->u_debugreg[6]) { 
+				  if (data >> 32) 
+					  goto out_tsk;
+			  }
+
 			  if(addr == (long) &dummy->u_debugreg[7]) {
 				  data &= ~DR_CONTROL_RESERVED;
 				  for(i=0; i<4; i++)
@@ -286,7 +297,7 @@
 			  }
 
 			  addr -= (long) &dummy->u_debugreg;
-			  addr = addr >> 2;
+			  addr = addr >> 3;
 			  child->thread.debugreg[addr] = data;
 			  ret = 0;
 		  }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/setup.c linux-2.4.21-pre6/arch/x86_64/kernel/setup.c
--- linux-2.4.20/arch/x86_64/kernel/setup.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/kernel/setup.c	2003-03-26 23:49:14.000000000 +0000
@@ -76,8 +76,6 @@
 extern int root_mountflags;
 extern char _text, _etext, _edata, _end;
 
-static int disable_x86_fxsr __initdata = 0;
-
 char command_line[COMMAND_LINE_SIZE];
 char saved_command_line[COMMAND_LINE_SIZE];
 
@@ -328,18 +326,6 @@
 	num_mappedpages = end_pfn;
 }
 
-#ifndef CONFIG_X86_TSC
-static int tsc_disable __initdata = 0;
-
-static int __init tsc_setup(char *str)
-{
-	tsc_disable = 1;
-	return 1;
-}
-
-__setup("notsc", tsc_setup);
-#endif
-
 static int __init get_model_name(struct cpuinfo_x86 *c)
 {
 	unsigned int *v;
@@ -362,7 +348,6 @@
 
 	n = cpuid_eax(0x80000000);
 
-
 	if (n >= 0x80000005) {
 		if (n >= 0x80000006) 
 			cpuid(0x80000006, &eax_2, &ebx_2, &ecx_2, &dummy); 
@@ -376,16 +361,17 @@
 			printk(KERN_INFO "CPU: L2 Cache: %dK (%d bytes/line/%d way)\n",
 			       ecx_2>>16, ecx_2&0xFF, (ecx_2>>12)&0xf);
 			c->x86_cache_size = ecx_2 >> 16;
-		}		
-		printk(KERN_INFO "CPU: DTLB L1 %d 4K %d 2MB L2: %d 4K %d 2MB\n",
-		       (ebx>>16)&0xff, (eax>>16)&0xff, 
-		       (ebx_2>>16)&0xfff, (eax_2>>16)&0xfff);
-		printk(KERN_INFO "CPU: ITLB L1 %d 4K %d 2MB L2: %d 4K %d 2MB\n",
-		       ebx&0xff, (eax)&0xff, 
-		       (ebx_2)&0xfff, (eax_2)&0xfff);		
 		c->x86_tlbsize = ((ebx>>16)&0xff) + ((ebx_2>>16)&0xfff) + 
 			(ebx&0xff) + ((ebx_2)&0xfff);
 	}
+		if (n >= 0x80000007)
+			cpuid(0x80000007, &dummy, &dummy, &dummy, &c->x86_power); 
+		if (n >= 0x80000008) {
+			cpuid(0x80000008, &eax, &dummy, &dummy, &dummy); 
+			c->x86_virt_bits = (eax >> 8) & 0xff;
+			c->x86_phys_bits = eax & 0xff;
+		}
+	}
 }
 
 static int __init init_amd(struct cpuinfo_x86 *c)
@@ -427,15 +413,6 @@
 	char *model_names[16];
 };
 
-int __init x86_fxsr_setup(char * s)
-{
-	disable_x86_fxsr = 1;
-	return 1;
-}
-__setup("nofxsr", x86_fxsr_setup);
-
-
-
 /*
  * This does the hard work of actually picking apart the CPU stuff...
  */
@@ -468,11 +445,11 @@
 		cpuid(0x00000001, &tfms, &misc, &junk,
 		      &c->x86_capability[0]);
 		c->x86 = (tfms >> 8) & 15;
-		if (c->x86 == 0xf)
-			c->x86 += (tfms >> 20) & 0xff;
 		c->x86_model = (tfms >> 4) & 15;
-		if (c->x86_model == 0xf)
+		if (c->x86 == 0xf) { /* extended */
+			c->x86 += (tfms >> 20) & 0xff;
 			c->x86_model += ((tfms >> 16) & 0xF) << 4; 
+		}
 		c->x86_mask = tfms & 15;
 		if (c->x86_capability[0] & (1<<19)) 
 			c->x86_clflush_size = ((misc >> 8) & 0xff) * 8;
@@ -525,18 +502,6 @@
 	 * we do "generic changes."
 	 */
 
-	/* TSC disabled? */
-#ifndef CONFIG_X86_TSC
-	if ( tsc_disable )
-		clear_bit(X86_FEATURE_TSC, &c->x86_capability);
-#endif
-
-	/* FXSR disabled? */
-	if (disable_x86_fxsr) {
-		clear_bit(X86_FEATURE_FXSR, &c->x86_capability);
-		clear_bit(X86_FEATURE_XMM, &c->x86_capability);
-	}
-
 	/*
 	 * On SMP, boot_cpu_data holds the common feature set between
 	 * all CPUs; so make sure that we indicate which features are
@@ -606,6 +571,12 @@
 		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 	};
+	static char *x86_power_flags[] = { 
+		"ts",	/* temperature sensor */
+		"fid",  /* frequency id control */
+		"vid",  /* voltage id control */
+		"ttp",  /* thermal trip */
+	};
 
 #ifdef CONFIG_SMP
 	if (!(cpu_online_map & (1<<(c-cpu_data))))
@@ -659,7 +630,22 @@
 		seq_printf(m, "TLB size\t: %d 4K pages\n", c->x86_tlbsize);
 	seq_printf(m, "clflush size\t: %d\n", c->x86_clflush_size);
 
-	seq_printf(m, "\n"); 
+	seq_printf(m, "address sizes\t: %u bits physical, %u bits virtual\n", 
+		   c->x86_phys_bits, c->x86_virt_bits);
+
+	seq_printf(m, "power management:");
+	{
+		int i;
+		for (i = 0; i < 32; i++) 
+			if (c->x86_power & (1 << i)) {
+				if (i < ARRAY_SIZE(x86_power_flags))
+					seq_printf(m, " %s", x86_power_flags[i]);
+				else
+					seq_printf(m, " [%d]", i);
+			}
+	}
+
+	seq_printf(m, "\n\n"); 
 	return 0;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/setup64.c linux-2.4.21-pre6/arch/x86_64/kernel/setup64.c
--- linux-2.4.20/arch/x86_64/kernel/setup64.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/kernel/setup64.c	2003-03-26 23:49:54.000000000 +0000
@@ -3,7 +3,7 @@
  * Copyright (C) 1995  Linus Torvalds
  * Copyright 2001, 2002 SuSE Labs / Andi Kleen.
  * See setup.c for older changelog.
- * $Id: setup64.c,v 1.15 2002/09/05 15:25:43 ak Exp $
+ * $Id: setup64.c,v 1.19 2003/02/21 19:37:21 ak Exp $
  */ 
 #include <linux/config.h>
 #include <linux/init.h>
@@ -31,18 +31,17 @@
 struct desc_ptr gdt_descr = { 0 /* filled in */, (unsigned long) gdt_table }; 
 struct desc_ptr idt_descr = { 256 * 16, (unsigned long) idt_table }; 
 
-unsigned long __supported_pte_mask = ~_PAGE_NX; 
+unsigned long __supported_pte_mask = ~0UL; 
 static int do_not_nx = 1; 
 
 char boot_cpu_stack[IRQSTACKSIZE] __cacheline_aligned;
 
-
 static int __init nonx_setup(char *str)
 {
-	if (strstr(str,"off")) { 
+	if (!strncmp(str,"off",3)) { 
 		__supported_pte_mask &= ~_PAGE_NX; 
 		do_not_nx = 1; 
-	} else if (strstr(str, "on")) { 
+	} else if (!strncmp(str, "on",3)) { 
 		do_not_nx = 0; 
 		__supported_pte_mask |= _PAGE_NX; 
 	} 
@@ -108,10 +107,10 @@
 
 	/* CPU 0 is initialised in head64.c */
 	if (nr != 0) {
-		estacks = (char *)__get_free_pages(GFP_ATOMIC, 0); 
+		pda_init(nr);
+		estacks = (char *)__get_free_pages(GFP_ATOMIC, EXCEPTION_STK_ORDER); 
 		if (!estacks)
 			panic("Can't allocate exception stacks for CPU %d\n",nr);
-		pda_init(nr);  
 	} else 
 		estacks = boot_exception_stacks; 
 
@@ -145,12 +144,10 @@
 	wrmsrl(MSR_CSTAR, ia32_cstar_target); 
 #endif
 
-	if (!do_not_nx) { 
 		rdmsrl(MSR_EFER, efer); 
-		if (!(efer & EFER_NX)) { 
+	if (!(efer & EFER_NX) || do_not_nx) { 
 			__supported_pte_mask &= ~_PAGE_NX; 
 		} 
-	}
 
 	t->io_map_base = INVALID_IO_BITMAP_OFFSET;	
 	memset(t->io_bitmap, 0xff, sizeof(t->io_bitmap));
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/signal.c linux-2.4.21-pre6/arch/x86_64/kernel/signal.c
--- linux-2.4.20/arch/x86_64/kernel/signal.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/kernel/signal.c	2003-03-26 23:49:07.000000000 +0000
@@ -8,7 +8,7 @@
  *  2000-06-20  Pentium III FXSR, SSE support by Gareth Hughes
  *  2000-2001   x86-64 support by Andi Kleen
  * 
- *  $Id: signal.c,v 1.35 2002/07/29 10:34:03 ak Exp $
+ *  $Id: signal.c,v 1.42 2003/02/24 21:06:02 ak Exp $
  */
 
 #include <linux/sched.h>
@@ -29,6 +29,7 @@
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 #include <asm/i387.h>
+#include <asm/proto.h>
 
 #define DEBUG_SIG 0
 
@@ -63,8 +64,6 @@
 		/* First 32bits of unions are always present.  */
 		err |= __put_user(from->si_pid, &to->si_pid);
 		switch (from->si_code >> 16) {
-		case __SI_FAULT >> 16:
-			break;
 		case __SI_CHLD >> 16:
 			err |= __put_user(from->si_utime, &to->si_utime);
 			err |= __put_user(from->si_stime, &to->si_stime);
@@ -139,13 +138,7 @@
 	if ((regs->x >> 48)  != 0 && (regs->x >> 48) != 0xffff) \
 				regs->x = 0; 
 
-	{ 
-		unsigned int seg; 
-		err |= __get_user(seg, &sc->gs); 
-		load_gs_index(seg); 
-		err |= __get_user(seg, &sc->fs);
-		loadsegment(fs,seg);
-	}
+	/* fs and gs are ignored because we cannot handle the 64bit base easily */ 
 
 	COPY(rdi); COPY(rsi); COPY(rbp); COPY_CANON(rsp); COPY(rbx);
 	COPY(rdx); COPY(rcx); COPY_CANON(rip);
@@ -232,10 +225,8 @@
 	struct task_struct *me = current;
 
 	tmp = 0;
-	__asm__("movl %%gs,%0" : "=r"(tmp): "0"(tmp));
-	err |= __put_user(tmp, (unsigned int *)&sc->gs);
-	__asm__("movl %%fs,%0" : "=r"(tmp): "0"(tmp));
-	err |= __put_user(tmp, (unsigned int *)&sc->fs);
+	err |= __put_user(0, &sc->gs);
+	err |= __put_user(0, &sc->fs);
 
 	err |= __put_user(regs->rdi, &sc->rdi);
 	err |= __put_user(regs->rsi, &sc->rsi);
@@ -264,12 +255,6 @@
 	return err;
 }
 
-/*
- * Determine which stack to use..
- */
-#define round_down(p, r) ((void *)  ((unsigned long)((p) - (r) + 1) & ~((r)-1)))
-
-
 static void * 
 get_stack(struct k_sigaction *ka, struct pt_regs *regs, unsigned long size)
 {
@@ -279,34 +264,35 @@
 	rsp = regs->rsp - 128;
 
 	/* This is the X/Open sanctioned signal stack switching.  */
+	/* may need to subtract redzone there too */
 	if (ka->sa.sa_flags & SA_ONSTACK) {
-		if (! sas_ss_flags(rsp) == 0)
+		if (sas_ss_flags(rsp) == 0)
 			rsp = current->sas_ss_sp + current->sas_ss_size;
 	}
 
-	return round_down(rsp - size, 16); 	
+	return (void *)round_down(rsp - size, 16); 	
 }
 
 static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 			   sigset_t *set, struct pt_regs * regs)
 {
-	struct rt_sigframe *frame = NULL;
-	struct _fpstate *fp = NULL; 
+	struct rt_sigframe *frame;
+	struct _fpstate *fp; 
 	int err = 0;
 
 	if (current->used_math) {
 		fp = get_stack(ka, regs, sizeof(struct _fpstate)); 
-		frame = round_down((char *)fp - sizeof(struct rt_sigframe), 16) - 8;
+		frame = (void *)round_down((unsigned long)fp - sizeof(struct rt_sigframe), 16) - 8;
 
 		if (!access_ok(VERIFY_WRITE, fp, sizeof(struct _fpstate))) { 
 			goto give_sigsegv;
 		}
 		if (save_i387(fp) < 0) 
 			err |= -1; 
-	}
-
-	if (!frame)
+	} else {
 		frame = get_stack(ka, regs, sizeof(struct rt_sigframe)) - 8;
+		fp = NULL;
+	}
 
 	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) {
 		goto give_sigsegv;
@@ -400,7 +386,7 @@
 #endif
 
 	/* Are we from a system call? */
-	if (regs->orig_rax >= 0) {
+	if ((long)regs->orig_rax >= 0) {
 		/* If so, check system call restarting.. */
 		switch (regs->rax) {
 			case -ERESTARTNOHAND:
@@ -563,8 +549,8 @@
 		 * have been cleared if the watchpoint triggered
 		 * inside the kernel.
 		 */
-		__asm__("movq %0,%%db7"	: : "r" (current->thread.debugreg[7]));
-
+		if (current->thread.debugreg[7])
+			asm volatile("movq %0,%%db7" :: "r" (current->thread.debugreg[7]));
 		/* Whee!  Actually deliver the signal.  */
 		handle_signal(signr, ka, &info, oldset, regs);
 		return 1;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/smp.c linux-2.4.21-pre6/arch/x86_64/kernel/smp.c
--- linux-2.4.20/arch/x86_64/kernel/smp.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/kernel/smp.c	2003-03-26 23:49:25.000000000 +0000
@@ -3,6 +3,7 @@
  *
  *	(c) 1995 Alan Cox, Building #3 <alan@redhat.com>
  *	(c) 1998-99, 2000 Ingo Molnar <mingo@redhat.com>
+ *	(c) 2002,2003 Andi Kleen, SuSE Labs.
  *
  *	This code is released under the GNU General Public License version 2 or
  *	later.
@@ -114,8 +115,6 @@
 static inline unsigned int __prepare_ICR (unsigned int shortcut, int vector)
 {
 	unsigned int icr =  APIC_DM_FIXED | shortcut | vector | APIC_DEST_LOGICAL;
-	if (vector == KDB_VECTOR) 
-		icr = (icr & (~APIC_VECTOR_MASK)) | APIC_DM_NMI; 		
 	return icr;
 }
 
@@ -411,11 +410,6 @@
 	do_flush_tlb_all_local();
 }
 
-void smp_kdb_stop(void)
-{
-	send_IPI_allbutself(KDB_VECTOR);
-} 
-
 /*
  * this function sends a 'reschedule' IPI to another CPU.
  * it goes straight through and wastes no time serializing
@@ -553,3 +547,25 @@
 	}
 }
 
+/* Slow. Should be only used for debugging. */
+int slow_smp_processor_id(void)
+{ 
+	int stack_location;
+	unsigned long sp = (unsigned long)&stack_location; 
+	int offset = 0, cpu;
+
+	for (offset = 0; (cpu_online_map >> offset); offset = cpu + 1) { 
+		cpu = ffz(~(cpu_online_map >> offset));
+
+		if (sp >= (u64)cpu_pda[cpu].irqstackptr - IRQSTACKSIZE && 
+		    sp <= (u64)cpu_pda[cpu].irqstackptr)
+			return cpu;
+
+		unsigned long estack = init_tss[cpu].ist[0] - EXCEPTION_STKSZ;
+		if (sp >= estack && sp <= estack+(1<<(PAGE_SHIFT+EXCEPTION_STK_ORDER)))
+			return cpu;			
+	}
+
+	return stack_smp_processor_id();
+} 
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/smpboot.c linux-2.4.21-pre6/arch/x86_64/kernel/smpboot.c
--- linux-2.4.20/arch/x86_64/kernel/smpboot.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/kernel/smpboot.c	2003-03-26 23:49:52.000000000 +0000
@@ -76,6 +76,8 @@
 /* Set when the idlers are all forked */
 int smp_threads_ready;
 
+extern void time_init_smp(void);
+
 /*
  * Setup routine for controlling SMP activation
  *
@@ -236,12 +238,16 @@
 		 */
 		atomic_inc(&tsc_count_start);
 
+		sync_core();
 		rdtscll(tsc_values[smp_processor_id()]);
+
 		/*
 		 * We clear the TSC in the last loop:
 		 */
-		if (i == NR_LOOPS-1)
+
+		if (i == NR_LOOPS-1) {
 			write_tsc(0, 0);
+		}
 
 		/*
 		 * Wait for all APs to leave the synchronization point:
@@ -302,6 +308,7 @@
 		atomic_inc(&tsc_count_start);
 		while (atomic_read(&tsc_count_start) != smp_num_cpus) mb();
 
+		sync_core();
 		rdtscll(tsc_values[smp_processor_id()]);
 		if (i == NR_LOOPS-1)
 			write_tsc(0, 0);
@@ -403,8 +410,6 @@
 	 */
  	smp_store_cpu_info(cpuid);
 
-	notify_die(DIE_CPUINIT, "cpuinit", NULL, 0);
-
 	/*
 	 * Allow the master to continue.
 	 */
@@ -772,7 +777,7 @@
 static __init void smp_tune_scheduling (void)
 {
 	unsigned long cachesize;       /* kB   */
-	unsigned long bandwidth = 350; /* MB/s */
+	unsigned long bandwidth = 2000; /* MB/s */
 	/*
 	 * Rough estimation for SMP scheduling, this is the number of
 	 * cycles it takes for a fully memory-limited process to flush
@@ -801,6 +806,8 @@
 		cacheflush_time = (cpu_khz>>10) * (cachesize<<10) / bandwidth;
 	}
 
+	cacheflush_time *= 10;  /* Add an NUMA factor */
+
 	printk("per-CPU timeslice cutoff: %ld.%02ld usecs.\n",
 		(long)cacheflush_time/(cpu_khz/1000),
 		((long)cacheflush_time*100/(cpu_khz/1000)) % 100);
@@ -888,6 +895,7 @@
 		io_apic_irqs = 0;
 		cpu_online_map = phys_cpu_present_map = 1;
 		smp_num_cpus = 1;
+		apic_disabled = 1;
 		goto smp_done;
 	}
 
@@ -902,6 +910,7 @@
 		io_apic_irqs = 0;
 		cpu_online_map = phys_cpu_present_map = 1;
 		smp_num_cpus = 1;
+		apic_disabled = 1;
 		goto smp_done;
 	}
 
@@ -989,6 +998,8 @@
 	 */
 	if (!skip_ioapic_setup && nr_ioapics)
 		setup_IO_APIC();
+	else
+		nr_ioapics = 0;
 
 	/*
 	 * Set up all local APIC timers in the system:
@@ -1003,4 +1014,5 @@
 
 smp_done:
 	zap_low_mappings();
+	time_init_smp();
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/sys_x86_64.c linux-2.4.21-pre6/arch/x86_64/kernel/sys_x86_64.c
--- linux-2.4.20/arch/x86_64/kernel/sys_x86_64.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/kernel/sys_x86_64.c	2003-03-26 23:48:59.000000000 +0000
@@ -65,23 +65,34 @@
 	return error;
 }
 
+
 unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags)
 {
 	struct vm_area_struct *vma;
 	unsigned long end = TASK_SIZE;
 
-	if (current->thread.flags & THREAD_IA32)
-		flags |= MAP_32BIT; 
-	if (flags & MAP_32BIT)
-		end = 0xffffffff-1;
-	if (len > end)
-		return -ENOMEM;
-	if (!addr) { 
-		addr = TASK_UNMAPPED_64;
-		if (flags & MAP_32BIT) {
+	if (current->thread.flags & THREAD_IA32) {
+		if (!addr) 
 			addr = TASK_UNMAPPED_32;
+		end = 0xffff0000;
+	} else if (flags & MAP_32BIT) { 
+		/* This is usually used needed to map code in small
+		   model: it needs to be in the first 31bit. Limit it
+		   to that.  This means we need to move the unmapped
+		   base down for this case.  This may give conflicts
+		   with the heap, but we assume that malloc falls back
+		   to mmap. Give it 1GB of playground for now. -AK */ 
+		if (!addr) 
+			addr = 0x40000000; 
+		end = 0x80000000;		
+	} else { 
+		if (!addr) 
+			addr = TASK_UNMAPPED_64; 
+		end = TASK_SIZE; 
 		}
-	} 
+
+	if (len > end)
+		return -ENOMEM;
 	addr = PAGE_ALIGN(addr);
 
 	for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/syscall.c linux-2.4.21-pre6/arch/x86_64/kernel/syscall.c
--- linux-2.4.20/arch/x86_64/kernel/syscall.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/kernel/syscall.c	2003-03-26 23:49:25.000000000 +0000
@@ -3,6 +3,7 @@
 #include <linux/linkage.h>
 #include <linux/sys.h>
 #include <linux/cache.h>
+#include <linux/config.h>
 
 #define __NO_STUBS
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/time.c linux-2.4.21-pre6/arch/x86_64/kernel/time.c
--- linux-2.4.20/arch/x86_64/kernel/time.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/kernel/time.c	2003-03-26 23:49:54.000000000 +0000
@@ -12,8 +12,6 @@
  *
  */
 
-#define HPET_BIOS_SUPPORT_WORKING
-
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
@@ -26,39 +24,47 @@
 
 extern rwlock_t xtime_lock;
 spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t i8253_lock = SPIN_LOCK_UNLOCKED;
 
 unsigned int cpu_khz;					/* TSC clocks / usec, not used here */
+unsigned long hpet_address;
 unsigned long hpet_period;				/* fsecs / HPET clock */
-unsigned long hpet_tick;				/* HPET clocks / interrupt */
-int hpet_report_lost_ticks;				/* command line option */
+unsigned int hpet_tick;					/* HPET clocks / interrupt */
+unsigned long vxtime_hz = 1193182;
+int report_lost_ticks;					/* command line option */
 
-struct hpet_data __hpet __section_hpet;			/* address, quotient, trigger, hz */
+struct vxtime_data __vxtime __section_vxtime;		/* data for vsyscall */
 
 volatile unsigned long __jiffies __section_jiffies;
 unsigned long __wall_jiffies __section_wall_jiffies;
 struct timeval __xtime __section_xtime;
 struct timezone __sys_tz __section_sys_tz;
 
+static inline void rdtscll_sync(unsigned long *tsc)
+{
+	sync_core();
+	rdtscll(*tsc);
+}
+
 /*
  * do_gettimeoffset() returns microseconds since last timer interrupt was
- * triggered by hardware. A memory read of HPET is slower than a register read
- * of TSC, but much more reliable. It's also synchronized to the timer
- * interrupt. Note that do_gettimeoffset() may return more than hpet_tick, if a
- * timer interrupt has happened already, but hpet.trigger wasn't updated yet.
- * This is not a problem, because jiffies hasn't updated either. They are bound
- * together by xtime_lock.
+ * triggered by hardware. 
  */
 
-static spinlock_t time_offset_lock = SPIN_LOCK_UNLOCKED;
-static unsigned long timeoffset = 0;
-
-inline unsigned int do_gettimeoffset(void)
+static unsigned int do_gettimeoffset_tsc(void)
 {
 	unsigned long t;
-	rdtscll(t);	
-	return (t  - hpet.last_tsc) * (1000000L / HZ) / hpet.ticks + hpet.offset;
+	rdtscll_sync(&t);	
+	return ((t  - vxtime.last_tsc) * vxtime.tsc_quot) >> 32;
 }
 
+static unsigned int do_gettimeoffset_hpet(void)
+{
+	return ((hpet_readl(HPET_COUNTER) - vxtime.last) * vxtime.quot) >> 32;
+}
+
+unsigned int (*do_gettimeoffset)(void) = do_gettimeoffset_tsc;
+
 /*
  * This version of gettimeofday() has microsecond resolution and better than
  * microsecond precision, as we're using at least a 10 MHz (usually 14.31818
@@ -67,21 +73,20 @@
 
 void do_gettimeofday(struct timeval *tv)
 {
-	unsigned long flags, t;
+	unsigned long sequence;
  	unsigned int sec, usec;
 
-	read_lock_irqsave(&xtime_lock, flags);
-	spin_lock(&time_offset_lock);
+	do { 
+		sequence = __vxtime_sequence[1];
+		rmb();
 
 	sec = xtime.tv_sec;
-	usec = xtime.tv_usec;
+	usec = xtime.tv_usec
+		+ (jiffies - wall_jiffies) * tick
+			+ do_gettimeoffset();
 
-	t = (jiffies - wall_jiffies) * (1000000L / HZ) + do_gettimeoffset();
-	if (t > timeoffset) timeoffset = t;
-	usec += timeoffset;
-
-	spin_unlock(&time_offset_lock);
-	read_unlock_irqrestore(&xtime_lock, flags);
+		rmb(); 
+	} while (sequence != __vxtime_sequence[0]);
 
 	tv->tv_sec = sec + usec / 1000000;
 	tv->tv_usec = usec % 1000000;
@@ -98,8 +103,8 @@
 	write_lock_irq(&xtime_lock);
 	vxtime_lock();
 
-	tv->tv_usec -= do_gettimeoffset() +
-		(jiffies - wall_jiffies) * tick;
+	tv->tv_usec -= (jiffies - wall_jiffies) * tick
+			+ do_gettimeoffset();
 
 	while (tv->tv_usec < 0) {
 		tv->tv_usec += 1000000;
@@ -201,15 +206,55 @@
 	vxtime_lock();
 
 	{
-		unsigned long t;
+		long tsc;
+		int delay, offset = 0;
+
+		if (hpet_address) {
+
+			offset = hpet_readl(HPET_T0_CMP) - hpet_tick;
+			delay = hpet_readl(HPET_COUNTER) - offset;
+
+		} else {
+
+			spin_lock(&i8253_lock);
+			outb_p(0x00, 0x43);
+			delay = inb_p(0x40);
+			delay |= inb(0x40) << 8;
+			spin_unlock(&i8253_lock);
+			delay = LATCH - 1 - delay;
+		}
+
+		rdtscll_sync(&tsc);
+
+		if (vxtime.mode == VXTIME_HPET) {
+
+			if (offset - vxtime.last > hpet_tick) {
+				if (report_lost_ticks)
+					printk(KERN_WARNING "time.c: Lost %d timer tick(s)! (rip %016lx)\n",
+						(offset - vxtime.last) / hpet_tick - 1, regs->rip);
+				jiffies += (offset - vxtime.last) / hpet_tick - 1;
+			}
+
+			vxtime.last = offset;
+
+		} else {
+
+			offset = (((tsc - vxtime.last_tsc) * vxtime.tsc_quot) >> 32) - tick;
+
+			if (offset > tick) {
+				if (report_lost_ticks)
+					printk(KERN_WARNING "time.c: lost %ld tick(s) (rip %016lx)\n",
+						 offset / tick, regs->rip);
+				jiffies += offset / tick;
+				offset %= tick;
+			}
 
-		rdtscll(t);
-		hpet.offset = (t  - hpet.last_tsc) * (1000000L / HZ) / hpet.ticks + hpet.offset - 1000000L / HZ;
-		if (hpet.offset >= 1000000L / HZ)
-			hpet.offset = 0;
-		hpet.ticks = min_t(long, max_t(long, (t  - hpet.last_tsc) * (1000000L / HZ) / (1000000L / HZ - hpet.offset),
-				cpu_khz * 1000/HZ * 15 / 16), cpu_khz * 1000/HZ * 16 / 15); 
-		hpet.last_tsc = t;
+			vxtime.last_tsc = tsc - vxtime.quot * delay / vxtime.tsc_quot;
+
+			if ((((tsc - vxtime.last_tsc) * vxtime.tsc_quot) >> 32) < offset)
+				vxtime.last_tsc = tsc - (((long)offset << 32) / vxtime.tsc_quot) - 1;
+
+		}
 	}
 
 /*
@@ -318,6 +363,7 @@
 	do {
 		__cli();
 		hpet_now = hpet_readl(HPET_COUNTER);
+		sync_core();
 		rdtscl(tsc_now);
 		__restore_flags(flags);
 	} while ((tsc_now - tsc_start) < TICK_COUNT && (hpet_now - hpet_start) < TICK_COUNT);
@@ -337,12 +383,10 @@
 static unsigned int __init pit_calibrate_tsc(void)
 {
 	unsigned long start, end;
-	unsigned long flags;
 
 	outb((inb(0x61) & ~0x02) | 0x01, 0x61);
 
-	__save_flags(flags);
-	__cli();
+	spin_lock_irq(&i8253_lock);
 
 	outb(0xb0, 0x43);
 	outb((1193182 / (1000 / 50)) & 0xff, 0x42);
@@ -352,7 +396,7 @@
 	while ((inb(0x61) & 0x20) == 0);
 	rdtscll(end);
 
-	__restore_flags(flags);
+	spin_unlock_irq(&i8253_lock);
 
 	return (end - start) / 50;
 }
@@ -361,9 +405,9 @@
 {
 	unsigned int cfg, id;
 
-	if (!hpet.address)
+	if (!hpet_address)
 		return -1;
-	set_fixmap_nocache(FIX_HPET_BASE, hpet.address);
+	set_fixmap_nocache(FIX_HPET_BASE, hpet_address);
 
 /*
  * Read the period, compute tick and quotient.
@@ -411,35 +455,106 @@
 
 void __init pit_init(void)
 {
+	spin_lock_irq(&i8253_lock);
 	outb_p(0x34, 0x43);		/* binary, mode 2, LSB/MSB, ch 0 */
 	outb_p(LATCH & 0xff, 0x40);	/* LSB */
 	outb_p(LATCH >> 8, 0x40);	/* MSB */
+	spin_unlock_irq(&i8253_lock);
 }
 
-int __init time_setup(char *str)
+static int __init time_setup(char *str)
 {
-	hpet_report_lost_ticks = 1;
+	report_lost_ticks = 1;
 	return 1;
 }
 
+/* Only used on SMP */
+static int notsc __initdata = 0; 
+
+static int __init notsc_setup(char *str)
+{ 
+#ifdef CONFIG_SMP
+	printk(KERN_INFO "notsc ignored on non SMP kernel\n"); 
+#endif
+	notsc = 1;
+	return 1;
+} 
+
 static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL};
 
 extern void __init config_acpi_tables(void);
 
 void __init time_init(void)
 {
+	char *timename;
+
+	config_acpi_tables();
+
+#ifdef HPET_HACK_ENABLE_DANGEROUS
+        if (!hpet_address) {
+		printk(KERN_WARNING "time.c: WARNING: Enabling HPET base manually!\n");
+                outl(0x800038a0, 0xcf8);
+                outl(0xff000001, 0xcfc);
+                outl(0x800038a0, 0xcf8);
+                hpet_address = inl(0xcfc) & 0xfffffffe;
+		printk(KERN_WARNING "time.c: WARNING: Enabled HPET at at %#lx.\n", hpet_address);
+        }
+#endif
+
+#ifndef CONFIG_HPET_TIMER
+        hpet_address = 0;
+#endif
+
+	write_lock(&xtime_lock);
 	xtime.tv_sec = get_cmos_time();
 	xtime.tv_usec = 0;
+	write_unlock(&xtime_lock);
 
-		printk(KERN_WARNING "time.c: HPET timer not found, precise timing unavailable.\n");
+	if (!hpet_init()) {
+                vxtime_hz = (1000000000000000L + hpet_period / 2) / hpet_period;
+                cpu_khz = hpet_calibrate_tsc();
+		timename = "HPET";
+	} else {
 		pit_init();
-		printk(KERN_INFO "time.c: Using 1.1931816 MHz PIT timer.\n");
-		setup_irq(0, &irq0);
 		cpu_khz = pit_calibrate_tsc();
-		printk(KERN_INFO "time.c: Detected %d.%03d MHz processor.\n",
+		timename = "PIT";
+	}
+
+	vxtime.mode = VXTIME_TSC;
+	vxtime.quot = (1000000L << 32) / vxtime_hz;
+	vxtime.tsc_quot = (1000L << 32) / cpu_khz;
+	rdtscll_sync(&vxtime.last_tsc);
+
+	setup_irq(0, &irq0);
+
+        printk(KERN_INFO "time.c: Detected %ld.%06ld MHz %s timer.\n",
+		vxtime_hz / 1000000, vxtime_hz % 1000000, timename);
+	printk(KERN_INFO "time.c: Detected %d.%03d MHz TSC timer.\n",
 			cpu_khz / 1000, cpu_khz % 1000);
-	hpet.ticks = cpu_khz * (1000 / HZ);
-	rdtscll(hpet.last_tsc);
 }
 
+void __init time_init_smp(void)
+{
+	char *timetype;
+
+	if (hpet_address) {
+		if (notsc) { 
+			timetype = "HPET";
+			vxtime.last = hpet_readl(HPET_T0_CMP) - hpet_tick;
+			vxtime.mode = VXTIME_HPET;
+			do_gettimeoffset = do_gettimeoffset_hpet;
+		} else {
+			timetype = "HPET/TSC";
+			vxtime.mode = VXTIME_TSC;
+			do_gettimeoffset = do_gettimeoffset_tsc;
+		}		
+	} else {
+			timetype = "PIT/TSC";
+			vxtime.mode = VXTIME_TSC;
+	}
+	printk(KERN_INFO "time.c: Using %s based timekeeping.\n", timetype);
+}
+
+__setup("notsc", notsc_setup);
 __setup("report_lost_ticks", time_setup);
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/traps.c linux-2.4.21-pre6/arch/x86_64/kernel/traps.c
--- linux-2.4.20/arch/x86_64/kernel/traps.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/kernel/traps.c	2003-03-26 23:49:09.000000000 +0000
@@ -7,7 +7,7 @@
  *  Pentium III FXSR, SSE support
  *	Gareth Hughes <gareth@valinux.com>, May 2000
  *
- *  $Id: traps.c,v 1.51 2002/09/12 12:57:46 ak Exp $
+ *  $Id: traps.c,v 1.62 2003/03/14 16:06:35 ak Exp $
  */
 
 /*
@@ -71,6 +71,12 @@
 asmlinkage void spurious_interrupt_bug(void);
 asmlinkage void call_debug(void);
 
+static inline void conditional_sti(struct pt_regs *regs)
+{
+	if (regs->eflags & X86_EFLAGS_IF)
+		__sti();
+}
+
 extern char iret_address[];
 
 struct notifier_block *die_chain;
@@ -95,7 +101,7 @@
 	} 
 	if (!strcmp(modname, "kernel"))
 		modname = delim = ""; 		
-        return printk("[%016lx%s%s%s%s%+ld]",
+        return printk("[<%016lx>]{%s%s%s%s%+ld}",
 		      address,delim,modname,delim,symname,address-symstart); 
 } 
 #else
@@ -143,7 +149,7 @@
 
 #endif
 
-static inline unsigned long *in_exception_stack(int cpu, unsigned long stack) 
+unsigned long *in_exception_stack(int cpu, unsigned long stack) 
 { 
 	int k;
 	for (k = 0; k < N_EXCEPTION_STACKS; k++) {
@@ -159,13 +165,12 @@
 {
 	unsigned long addr;
 	unsigned long *irqstack, *irqstack_end, *estack_end;
-	/* FIXME: should read the cpuid from the APIC; to still work with bogus %gs */
-	const int cpu = smp_processor_id();
+	const int cpu = safe_smp_processor_id();
 	int i;
 
 	printk("\nCall Trace: ");
 
-	i = 1;
+	i = 12;
 	estack_end = in_exception_stack(cpu, (unsigned long)stack); 
 	if (estack_end) { 
 		while (stack < estack_end) { 
@@ -243,7 +248,7 @@
 {
 	unsigned long *stack;
 	int i;
-	const int cpu = smp_processor_id();
+	const int cpu = safe_smp_processor_id();
 	unsigned long *irqstack_end = (unsigned long *) (cpu_pda[cpu].irqstackptr);
 	unsigned long *irqstack = (unsigned long *) (cpu_pda[cpu].irqstackptr - IRQSTACKSIZE);    
 
@@ -271,22 +276,12 @@
 	show_trace((unsigned long *)rsp);
 }
 
-void dump_stack(void)
-{
-	show_stack(0);
-} 
-
 void show_registers(struct pt_regs *regs)
 {
 	int i;
 	int in_kernel = 1;
 	unsigned long rsp;
-#ifdef CONFIG_SMP
-	/* For SMP should get the APIC id here, just to protect against corrupted GS */ 
-	const int cpu = smp_processor_id(); 
-#else
-	const int cpu = 0;
-#endif	
+	const int cpu = safe_smp_processor_id(); 
 	struct task_struct *cur = cpu_pda[cpu].pcurrent; 
 
 	rsp = (unsigned long) (&regs->rsp);
@@ -350,13 +345,12 @@
 void die(const char * str, struct pt_regs * regs, long err)
 {
 	int cpu;
-	struct die_args args = { regs, str, err };
 	console_verbose();
-	notifier_call_chain(&die_chain,  DIE_DIE, &args); 
 	bust_spinlocks(1);
 	handle_BUG(regs);		
 	printk(KERN_EMERG "%s: %04lx\n", str, err & 0xffff);
-	cpu = smp_processor_id(); 
+ 	notify_die(DIE_OOPS, (char *)str, regs, err, 255, SIGSEGV);
+	cpu = safe_smp_processor_id(); 
 	/* racy, but better than risking deadlock. */ 
 	__cli();
 	if (!spin_trylock(&die_lock)) { 
@@ -369,7 +363,6 @@
 	show_registers(regs);
 	bust_spinlocks(0);
 	spin_unlock_irq(&die_lock);
-	notify_die(DIE_OOPS, (char *)str, regs, err);
 	do_exit(SIGSEGV);
 }
 
@@ -391,10 +384,12 @@
 static void do_trap(int trapnr, int signr, char *str, 
 		    struct pt_regs * regs, long error_code, siginfo_t *info)
 {
+	conditional_sti(regs);
+
 #if defined(CONFIG_CHECKING) && defined(CONFIG_LOCAL_APIC)
 	{ 
 		unsigned long gs; 
-		struct x8664_pda *pda = cpu_pda + hard_smp_processor_id(); 
+		struct x8664_pda *pda = cpu_pda + safe_smp_processor_id(); 
 		rdmsrl(MSR_GS_BASE, gs); 
 		if (gs != (unsigned long)pda) { 
 			wrmsrl(MSR_GS_BASE, pda); 
@@ -407,7 +402,7 @@
 		struct task_struct *tsk = current;
 		tsk->thread.error_code = error_code;
 		tsk->thread.trap_no = trapnr;
-		if (exception_trace)
+		if (exception_trace && trapnr != 3)
 			printk("%s[%d] trap %s rip:%lx rsp:%lx error:%lx\n",
 			       tsk->comm, tsk->pid, str,
 			       regs->rip,regs->rsp,error_code); 
@@ -424,11 +419,6 @@
 		unsigned long fixup = search_exception_table(regs->rip);
 		if (fixup) {
 			extern int exception_trace; 
-			if (0 && exception_trace)
-	       printk(KERN_ERR
-	             "%s: fixed kernel exception at %lx err:%ld\n",
-	             current->comm, regs->rip, error_code);
-		
 			regs->rip = fixup;
 		} else	
 			die(str, regs, error_code);
@@ -439,6 +429,8 @@
 #define DO_ERROR(trapnr, signr, str, name) \
 asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
 { \
+	if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) == NOTIFY_BAD) \
+		return; \
 	do_trap(trapnr, signr, str, regs, error_code, NULL); \
 }
 
@@ -450,10 +442,13 @@
 	info.si_errno = 0; \
 	info.si_code = sicode; \
 	info.si_addr = (void *)siaddr; \
+	if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr)==NOTIFY_BAD) \
+		return; \
 	do_trap(trapnr, signr, str, regs, error_code, &info); \
 }
 
 DO_ERROR_INFO( 0, SIGFPE,  "divide error", divide_error, FPE_INTDIV, regs->rip)
+DO_ERROR( 3, SIGTRAP, "int3", int3); 
 DO_ERROR( 4, SIGSEGV, "overflow", overflow)
 DO_ERROR( 5, SIGSEGV, "bounds", bounds)
 DO_ERROR_INFO( 6, SIGILL,  "invalid operand", invalid_op, ILL_ILLOPN, regs->rip)
@@ -466,25 +461,25 @@
 DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, get_cr2())
 DO_ERROR(18, SIGSEGV, "reserved", reserved)
 
-asmlinkage void do_int3(struct pt_regs * regs, long error_code)
-{
-	if (notify_die(DIE_INT3, "int3", regs, error_code) == NOTIFY_BAD)
-		return;
-	do_trap(3, SIGTRAP, "int3", regs, error_code, NULL);
-}
-
 extern void dump_pagetable(unsigned long);
 
 asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
 {
+	conditional_sti(regs);
+
 #ifdef CONFIG_CHECKING
 	{ 
 		unsigned long gs; 
-		struct x8664_pda *pda = cpu_pda + stack_smp_processor_id(); 
+		struct x8664_pda *pda = cpu_pda + safe_smp_processor_id(); 
 		rdmsrl(MSR_GS_BASE, gs); 
 		if (gs != (unsigned long)pda) { 
 			wrmsrl(MSR_GS_BASE, pda); 
+			/* Avoid wakeup in printk in case this was triggered
+			   by the segment reloads in __switch_to. Otherwise
+			   the wake_up could deadlock on scheduler locks. */
+			oops_in_progress++;
 			printk("general protection handler: wrong gs %lx expected %p\n", gs, pda);
+			oops_in_progress--; 
 		}
 	}
 #endif
@@ -505,15 +500,11 @@
 		unsigned long fixup;
 		fixup = search_exception_table(regs->rip);
 		if (fixup) {
-			extern int exception_trace; 
-			if (exception_trace)
-				printk(KERN_ERR
-			       "%s: fixed kernel exception at %lx err:%ld\n",
-				       current->comm, regs->rip, error_code);
-
 			regs->rip = fixup;
 			return;
 		}
+		notify_die(DIE_GPF, "general protection fault", regs, error_code,
+			   13, SIGSEGV); 
 		die("general protection fault", regs, error_code);
 	}
 }
@@ -552,7 +543,7 @@
 {
 	unsigned char reason = inb(0x61);
 
-	++nmi_count(smp_processor_id());
+	++nmi_count(safe_smp_processor_id());
 	
 	if (!(reason & 0xc0)) {
 #if CONFIG_X86_LOCAL_APIC
@@ -561,16 +552,14 @@
 		 * so it must be the NMI watchdog.
 		 */
 		if (nmi_watchdog) {
-			nmi_watchdog_tick(regs);
+			nmi_watchdog_tick(regs, reason);
 			return;
 		}
 #endif
-		if (notify_die(DIE_NMI, "nmi", regs, reason) == NOTIFY_BAD)
-			return;
 		unknown_nmi_error(reason, regs);
 		return;
 	}
-	if (notify_die(DIE_NMI, "nmi", regs, reason) == NOTIFY_BAD)
+	if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_BAD)
 		return; 
 	if (reason & 0x80)
 		mem_parity_error(reason, regs);
@@ -593,10 +582,15 @@
 	struct task_struct *tsk = current;
 	siginfo_t info;
 
+	asm("movq %%db6,%0" : "=r" (condition));
+
+	conditional_sti(regs);
+
 #ifdef CONFIG_CHECKING
 	{ 
+		/* XXX: interaction with debugger - could destroy gs */
 		unsigned long gs; 
-		struct x8664_pda *pda = cpu_pda + stack_smp_processor_id(); 
+		struct x8664_pda *pda = cpu_pda + safe_smp_processor_id(); 
 		rdmsrl(MSR_GS_BASE, gs); 
 		if (gs != (unsigned long)pda) { 
 			wrmsrl(MSR_GS_BASE, pda); 
@@ -605,16 +599,6 @@
 	}
 #endif
 
-	asm("movq %%db6,%0" : "=r" (condition));
-
-	if (notify_die(DIE_DEBUG, "debug", regs, error_code) == NOTIFY_BAD)
-		return; 
-
-	/* If the user set TF, it's simplest to clear it right away. */
-	/* AK: dubious check, likely wrong */
-	if ((regs->cs & 3) == 0 && (regs->eflags & TF_MASK))
-		goto clear_TF;
-
 	/* Mask out spurious debug traps due to lazy DR7 setting */
 	if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
 		if (!tsk->thread.debugreg[7]) { 
@@ -647,14 +631,19 @@
 	info.si_signo = SIGTRAP;
 	info.si_errno = 0;
 	info.si_code = TRAP_BRKPT;
-	info.si_addr = ((regs->cs & 3) == 0) ? (void *)tsk->thread.rip : 
-	                                        (void *)regs->rip;
+	if ((regs->cs & 3) == 0) 
+		goto clear_dr7; 
+
+	info.si_addr = (void *)regs->rip;
 	force_sig_info(SIGTRAP, &info, tsk);	
 clear_dr7:
-	asm("movq %0,%%db7"::"r"(0UL));
+	asm volatile("movq %0,%%db7"::"r"(0UL));
+	notify_die(DIE_DEBUG, "debug", regs, error_code, 1, SIGTRAP);
 	return;
 
 clear_TF:
+	/* XXX: could cause spurious errors */
+	if (notify_die(DIE_DEBUG, "debug2", regs, error_code, 1, SIGTRAP) != NOTIFY_BAD)
 	regs->eflags &= ~TF_MASK;
 	return;
 }
@@ -721,6 +710,7 @@
 
 asmlinkage void do_coprocessor_error(struct pt_regs * regs, long error_code)
 {
+	conditional_sti(regs);
 	math_error((void *)regs->rip);
 }
 
@@ -780,6 +770,7 @@
 asmlinkage void do_simd_coprocessor_error(struct pt_regs * regs,
 					  long error_code)
 {
+	conditional_sti(regs);
 	simd_math_error((void *)regs->rip);
 }
 
@@ -800,7 +791,7 @@
 	clts();			/* Allow maths ops (or we recurse) */
 
 	if (!me->used_math)
-		init_fpu();        
+		init_fpu(me);
 	restore_fpu_checking(&me->thread.i387.fxsave);
 	me->flags |= PF_USEDFPU;	/* So we fxsave on switch_to() */
 }
@@ -812,7 +803,7 @@
 
 void do_call_debug(struct pt_regs *regs) 
 { 
-	notify_die(DIE_CALL, "debug call", regs, 0); 
+	notify_die(DIE_CALL, "debug call", regs, 0, 255, SIGINT); 
 } 
 
 #ifndef CONFIG_MCE
@@ -849,10 +840,6 @@
 	set_intr_gate(IA32_SYSCALL_VECTOR, ia32_syscall);
 #endif
 
-	set_intr_gate(KDB_VECTOR, call_debug);
-       
-	notify_die(DIE_TRAPINIT, "traps initialized", 0, 0); 
-	
 	/*
 	 * Should be a barrier for any external CPU state.
 	 */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/vsyscall.c linux-2.4.21-pre6/arch/x86_64/kernel/vsyscall.c
--- linux-2.4.20/arch/x86_64/kernel/vsyscall.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/kernel/vsyscall.c	2003-03-26 23:49:38.000000000 +0000
@@ -12,7 +12,7 @@
  *  vsyscalls. One vsyscall can reserve more than 1 slot to avoid
  *  jumping out of line if necessary.
  *
- *  $Id: vsyscall.c,v 1.19 2002/07/19 02:24:08 vojtech Exp $
+ *  $Id: vsyscall.c,v 1.26 2003/02/18 11:55:47 ak Exp $
  */
 
 /*
@@ -45,16 +45,15 @@
 #include <asm/errno.h>
 #include <asm/io.h>
 #include <asm/msr.h>
+#include <asm/unistd.h>
 
 #define __vsyscall(nr) __attribute__ ((unused,__section__(".vsyscall_" #nr)))
 
-long __vxtime_sequence[2] __section_vxtime_sequence;
-
-#undef USE_VSYSCALL
+#define force_inline inline __attribute__((always_inline))
 
-#ifdef USE_VSYSCALL
+long __vxtime_sequence[2] __section_vxtime_sequence;
 
-static inline void do_vgettimeofday(struct timeval * tv)
+static force_inline void do_vgettimeofday(struct timeval * tv)
 {
 	long sequence, t;
 	unsigned long sec, usec;
@@ -63,11 +62,22 @@
 		sequence = __vxtime_sequence[1];
 		rmb();
 
-		rdtscll(t);
 		sec = __xtime.tv_sec;
-		usec = __xtime.tv_usec +
-			(__jiffies - __wall_jiffies) * (1000000 / HZ) +
-			(t  - __hpet.last_tsc) * (1000000 / HZ) / __hpet.ticks + __hpet.offset;
+		usec = __xtime.tv_usec + (__jiffies - __wall_jiffies) * (1000000 / HZ);
+
+		switch (__vxtime.mode) {
+
+			case VXTIME_TSC:
+				sync_core();
+				rdtscll(t);
+				usec += (((t  - __vxtime.last_tsc) * __vxtime.tsc_quot) >> 32);
+				break;
+
+			case VXTIME_HPET:
+				usec += ((readl(fix_to_virt(VSYSCALL_HPET) + 0xf0) - __vxtime.last) * __vxtime.quot) >> 32;
+				break;
+
+		}
 
 		rmb();
 	} while (sequence != __vxtime_sequence[0]);
@@ -76,7 +86,8 @@
 	tv->tv_usec = usec % 1000000;
 }
 
-static inline void do_get_tz(struct timezone * tz)
+
+static force_inline void do_get_tz(struct timezone * tz)
 {
 	long sequence;
 
@@ -92,27 +103,15 @@
 
 static long __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz)
 {
-	if (tv) do_vgettimeofday(tv);
-	if (tz) do_get_tz(tz);
-	return 0;
-}
-
-#else
+	if (tv)
+			do_vgettimeofday(tv);
 
-#include <asm/unistd.h>
+	if (tz)
+		do_get_tz(tz);
 
-static long __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz)
-{
-	int r;
-	asm volatile("syscall"
-		     : "=a" (r)
-		     : "0" (__NR_gettimeofday), "D" (tv), "S" (tz)
-		     : "r11", "rcx","memory");
-	return r;
+	return 0;
 }
 
-#endif
-
 static time_t __vsyscall(1) vtime(time_t * tp)
 {
 	struct timeval tv;
@@ -131,19 +130,18 @@
 	return -ENOSYS;
 }
 
+extern char vsyscall_syscall[], __vsyscall_0[];
+
 static void __init map_vsyscall(void)
 {
-	extern char __vsyscall_0;
-	unsigned long physaddr_page0 = (unsigned long) &__vsyscall_0 - __START_KERNEL_map;
-
+	unsigned long physaddr_page0 = __pa_symbol(&__vsyscall_0);
 	__set_fixmap(VSYSCALL_FIRST_PAGE, physaddr_page0, PAGE_KERNEL_VSYSCALL);
-	if (hpet.address)
-		__set_fixmap(VSYSCALL_HPET, hpet.address, PAGE_KERNEL_VSYSCALL);
+	if (hpet_address)
+		__set_fixmap(VSYSCALL_HPET, hpet_address, PAGE_KERNEL_VSYSCALL);
 }
 
 static int __init vsyscall_init(void)
 {
-	printk("VSYSCALL: consistency checks...");
 	if ((unsigned long) &vgettimeofday != VSYSCALL_ADDR(__NR_vgettimeofday))
 		panic("vgettimeofday link addr broken");
 	if ((unsigned long) &vtime != VSYSCALL_ADDR(__NR_vtime))
@@ -151,10 +149,7 @@
 	if (VSYSCALL_ADDR(0) != __fix_to_virt(VSYSCALL_FIRST_PAGE))
 		panic("fixmap first vsyscall %lx should be %lx", __fix_to_virt(VSYSCALL_FIRST_PAGE),
 			VSYSCALL_ADDR(0));
-	printk("passed...mapping...");
 	map_vsyscall();
-	printk("done.\n");
-
 	return 0;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/kernel/x8664_ksyms.c linux-2.4.21-pre6/arch/x86_64/kernel/x8664_ksyms.c
--- linux-2.4.20/arch/x86_64/kernel/x8664_ksyms.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/kernel/x8664_ksyms.c	2003-03-26 23:49:49.000000000 +0000
@@ -220,3 +220,6 @@
 EXPORT_SYMBOL(plat_node_data);
 EXPORT_SYMBOL(fake_node);
 #endif
+
+extern void int_ret_from_sys_call(void);
+EXPORT_SYMBOL(int_ret_from_sys_call); 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/lib/clear_page.S linux-2.4.21-pre6/arch/x86_64/lib/clear_page.S
--- linux-2.4.20/arch/x86_64/lib/clear_page.S	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/lib/clear_page.S	2003-03-26 23:48:57.000000000 +0000
@@ -1,16 +1,18 @@
-	#include <linux/linkage.h>
 
 /*
  * Zero a page. 	
  * rdi	page
  */			
-ENTRY(clear_page)
+	.globl clear_page
+	.p2align 4
+clear_page:
 	xorl   %eax,%eax
-	movl   $4096/128,%ecx
-	movl   $128,%edx
-loop:
+	movl   $4096/64,%ecx
+	.p2align 4
+.Lloop:
+	decl	%ecx
 #define PUT(x) movq %rax,x*8(%rdi) 
-	PUT(0)
+	movq %rax,(%rdi)
 	PUT(1)
 	PUT(2)
 	PUT(3)
@@ -18,17 +20,8 @@
 	PUT(5)
 	PUT(6)
 	PUT(7)
-	PUT(8)
-	PUT(9)
-	PUT(10)
-	PUT(11)
-	PUT(12)
-	PUT(13)
-	PUT(14)
-	PUT(15)
-	addq    %rdx,%rdi
-	decl	%ecx
-	jnz	loop
-	sfence	
+	leaq	64(%rdi),%rdi
+	jnz	.Lloop
+	nop
 	ret
 	    	
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/lib/copy_page.S linux-2.4.21-pre6/arch/x86_64/lib/copy_page.S
--- linux-2.4.20/arch/x86_64/lib/copy_page.S	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/lib/copy_page.S	2003-03-26 23:48:57.000000000 +0000
@@ -1,70 +1,91 @@
-	#include <linux/linkage.h>
-	#include <linux/config.h>
-	#ifdef CONFIG_PREEMPT
-	#warning "check your fpu context saving!"
-	#endif
-
-/*
- * Copy a page. 
- *		
- * rdi destination page
- * rsi source page
- *		
- * src/dst must be aligned to 16 bytes.
- * 
- * Warning: in case of super lazy FP save this needs to be preempt_stop	
- */
+/* Written 2003 by Andi Kleen, based on a kernel by Evandro Menezes */
 	
+/* Don't use streaming store because it's better when the target
+   ends up in cache. */
+	    
+/* Could vary the prefetch distance based on SMP/UP */
+
 	.globl copy_page
-	.p2align
+	.p2align 4
 copy_page:
-	prefetchnta (%rsi) 
-	prefetchnta 64(%rsi)
-	    
-	movq %rsp,%rax
-	subq $16*4,%rsp
-	andq $~15,%rsp		
-	movdqa %xmm0,(%rsp) 
-	movdqa %xmm1,16(%rsp) 
-	movdqa %xmm2,32(%rsp) 
-	movdqa %xmm3,48(%rsp)
-	
-	movl   $(4096/128)-2,%ecx
-	movl   $128,%edx
-loop:
-	prefetchnta (%rsi) 
-	prefetchnta 64(%rsi) 
-loop_no_prefetch:	
-	movdqa (%rsi),%xmm0 	 			 
-	movdqa 16(%rsi),%xmm1
-	movdqa 32(%rsi),%xmm2 	 			 
-	movdqa 48(%rsi),%xmm3 	 			 
-	movntdq %xmm0,(%rdi)	 
-	movntdq %xmm1,16(%rdi)	 
-	movntdq %xmm2,32(%rdi)	 
-	movntdq %xmm3,48(%rdi)
-	
-	movdqa 64(%rsi),%xmm0 	 			 
-	movdqa 80(%rsi),%xmm1
-	movdqa 96(%rsi),%xmm2 	 			 
-	movdqa 112(%rsi),%xmm3 	 			 
-	movntdq %xmm0,64(%rdi)	 
-	movntdq %xmm1,80(%rdi)	 
-	movntdq %xmm2,96(%rdi)	 
-	movntdq %xmm3,112(%rdi)
+	prefetch (%rsi) 
+	prefetch 1*64(%rsi)
+	prefetch 2*64(%rsi)
+	prefetch 3*64(%rsi)
+	prefetch 4*64(%rsi)
+	prefetchw (%rdi) 
+	prefetchw 1*64(%rdi) 
+	prefetchw 2*64(%rdi) 
+	prefetchw 3*64(%rdi)
+	prefetchw 4*64(%rdi)
+
+	subq	$3*8,%rsp
+	movq	%rbx,(%rsp)
+	movq	%r12,1*8(%rsp)
+	movq	%r13,2*8(%rsp)
+			
+	movl	$(4096/64)-5,%ecx
+	.p2align 4
+.Loop64:	
+  	dec     %rcx
+
+	movq        (%rsi), %rax
+	movq      8 (%rsi), %rbx
+	movq     16 (%rsi), %rdx
+	movq     24 (%rsi), %r8
+	movq     32 (%rsi), %r9
+	movq     40 (%rsi), %r10
+	movq     48 (%rsi), %r11
+	movq     56 (%rsi), %r12
+
+	prefetch 5*64(%rsi)
+
+	movq     %rax,    (%rdi)
+	movq     %rbx,  8 (%rdi)
+	movq     %rdx, 16 (%rdi)
+	movq     %r8,  24 (%rdi)
+	movq     %r9,  32 (%rdi)
+	movq     %r10, 40 (%rdi)
+	movq     %r11, 48 (%rdi)
+	movq     %r12, 56 (%rdi)
 
-	addq   %rdx,%rdi	
-	addq   %rdx,%rsi
+	prefetchw 5*64(%rdi)
+
+	leaq    64 (%rsi), %rsi
+	leaq    64 (%rdi), %rdi
+
+	jnz     .Loop64
+
+	movl	$5,%ecx
+	.p2align 4
+.Loop2:	
 	decl   %ecx
-	jns    loop
-	cmpl   $-1,%ecx
-	je     loop_no_prefetch
-	
-	sfence
 
-	movdqa (%rsp),%xmm0
-	movdqa 16(%rsp),%xmm1
-	movdqa 32(%rsp),%xmm2
-	movdqa 48(%rsp),%xmm3
-	movq   %rax,%rsp
+	movq        (%rsi), %rax
+	movq      8 (%rsi), %rbx
+	movq     16 (%rsi), %rdx
+	movq     24 (%rsi), %r8
+	movq     32 (%rsi), %r9
+	movq     40 (%rsi), %r10
+	movq     48 (%rsi), %r11
+	movq     56 (%rsi), %r12
+
+	movq     %rax,    (%rdi)
+	movq     %rbx,  8 (%rdi)
+	movq     %rdx, 16 (%rdi)
+	movq     %r8,  24 (%rdi)
+	movq     %r9,  32 (%rdi)
+	movq     %r10, 40 (%rdi)
+	movq     %r11, 48 (%rdi)
+	movq     %r12, 56 (%rdi)
+	
+	leaq	64(%rdi),%rdi			
+	leaq	64(%rsi),%rsi			
+	
+	jnz	.Loop2		
+	
+	movq	(%rsp),%rbx
+	movq	1*8(%rsp),%r12
+	movq	2*8(%rsp),%r13
+	addq	$3*8,%rsp
 	ret
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/lib/copy_user.S linux-2.4.21-pre6/arch/x86_64/lib/copy_user.S
--- linux-2.4.20/arch/x86_64/lib/copy_user.S	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/lib/copy_user.S	2003-03-26 23:49:30.000000000 +0000
@@ -6,15 +6,12 @@
 
 #define FIX_ALIGNMENT 1
 
-#define movnti movq  /* write to cache for now */
-#define prefetch prefetcht2
-		
 	#include <asm/current.h>
 	#include <asm/offset.h>
 
 /* Standard copy_to_user with segment limit checking */		
 	.globl copy_to_user
-	.p2align 	
+	.p2align 4	
 copy_to_user:
 	GET_CURRENT(%rax)
 	movq %rdi,%rcx
@@ -26,7 +23,7 @@
 
 /* Standard copy_from_user with segment limit checking */	
 	.globl copy_from_user
-	.p2align 	
+	.p2align 4	
 copy_from_user:
 	GET_CURRENT(%rax)
 	movq %rsi,%rcx
@@ -60,6 +57,7 @@
  * eax uncopied bytes or 0 if successfull. 
  */
 	.globl copy_user_generic	
+	.p2align 4
 copy_user_generic:	
 	/* Put the first cacheline into cache. This should handle
 	   the small movements in ioctls etc., but not penalize the bigger
@@ -72,8 +70,8 @@
 	/* check for bad alignment of destination */
 	movl %edi,%ecx
 	andl $7,%ecx
-	jnz  bad_alignment
-after_bad_alignment:
+	jnz  .Lbad_alignment
+.Lafter_bad_alignment:
 #endif
 
 	movq %rdx,%rcx
@@ -81,133 +79,138 @@
 	movl $64,%ebx	
 	shrq $6,%rdx
 	decq %rdx
-	js   handle_tail
-	jz   loop_no_prefetch
-	
-loop:
-	prefetch 64(%rsi)
+	js   .Lhandle_tail
+	jz   .Lloop_no_prefetch
 	
-loop_no_prefetch:	
-s1:	movq (%rsi),%r11
-s2:	movq 1*8(%rsi),%r8
-s3:	movq 2*8(%rsi),%r9
-s4:	movq 3*8(%rsi),%r10
-d1:	movnti %r11,(%rdi)
-d2:	movnti %r8,1*8(%rdi)
-d3:	movnti %r9,2*8(%rdi)
-d4:	movnti %r10,3*8(%rdi)
+	.p2align 4
+.Lloop:
+	prefetch 64(%rsi)		/* prefetch distance too short */
+	
+.Lloop_no_prefetch:	
+.Ls1:	movq (%rsi),%r11
+.Ls2:	movq 1*8(%rsi),%r8
+.Ls3:	movq 2*8(%rsi),%r9
+.Ls4:	movq 3*8(%rsi),%r10
+.Ld1:	movq %r11,(%rdi)
+.Ld2:	movq %r8,1*8(%rdi)
+.Ld3:	movq %r9,2*8(%rdi)
+.Ld4:	movq %r10,3*8(%rdi)
 		
-s5:	movq 4*8(%rsi),%r11
-s6:	movq 5*8(%rsi),%r8
-s7:	movq 6*8(%rsi),%r9
-s8:	movq 7*8(%rsi),%r10
-d5:	movnti %r11,4*8(%rdi)
-d6:	movnti %r8,5*8(%rdi)
-d7:	movnti %r9,6*8(%rdi)
-d8:	movnti %r10,7*8(%rdi)
-
-	addq %rbx,%rsi	
-	addq %rbx,%rdi
+.Ls5:	movq 4*8(%rsi),%r11
+.Ls6:	movq 5*8(%rsi),%r8
+.Ls7:	movq 6*8(%rsi),%r9
+.Ls8:	movq 7*8(%rsi),%r10
+.Ld5:	movq %r11,4*8(%rdi)
+.Ld6:	movq %r8,5*8(%rdi)
+.Ld7:	movq %r9,6*8(%rdi)
+.Ld8:	movq %r10,7*8(%rdi)
 	
 	decq %rdx
-	jz   loop_no_prefetch
-	jns  loop
 
-handle_tail:
+	leaq 64(%rsi),%rsi
+	leaq 64(%rdi),%rdi
+	
+	jz   .Lloop_no_prefetch
+	jns  .Lloop
+
+	.p2align 4
+.Lhandle_tail:
 	movl %ecx,%edx
 	andl $63,%ecx
 	shrl $3,%ecx
-	jz   handle_7
+	jz   .Lhandle_7
 	movl $8,%ebx
-loop_8:
-s9:	movq (%rsi),%r8
-d9:	movq %r8,(%rdi)
-	addq %rbx,%rdi
-	addq %rbx,%rsi
+	.p2align 4
+.Lloop_8:
+.Ls9:	movq (%rsi),%r8
+.Ld9:	movq %r8,(%rdi)
 	decl %ecx
-	jnz loop_8
+	leaq 8(%rdi),%rdi
+	leaq 8(%rsi),%rsi
+	jnz .Lloop_8
 	
-handle_7:		
+.Lhandle_7:		
 	movl %edx,%ecx	
 	andl $7,%ecx
-	jz   ende
-loop_1:
-s10:	movb (%rsi),%bl
-d10:	movb %bl,(%rdi)
+	jz   .Lende
+	.p2align 4
+.Lloop_1:
+.Ls10:	movb (%rsi),%bl
+.Ld10:	movb %bl,(%rdi)
 	incq %rdi
 	incq %rsi
 	decl %ecx
-	jnz loop_1
+	jnz .Lloop_1
 			
-ende:
-	sfence
+.Lende:
 	popq %rbx
 	ret	
 
 #ifdef FIX_ALIGNMENT		  		
 	/* align destination */
-bad_alignment:
+	.p2align 4
+.Lbad_alignment:
 	movl $8,%r9d
 	subl %ecx,%r9d
 	movl %r9d,%ecx
 	subq %r9,%rdx
-	jz   small_align
-	js   small_align
-align_1:		
-s11:	movb (%rsi),%bl
-d11:	movb %bl,(%rdi)
+	jz   .Lsmall_align
+	js   .Lsmall_align
+.Lalign_1:		
+.Ls11:	movb (%rsi),%bl
+.Ld11:	movb %bl,(%rdi)
 	incq %rsi
 	incq %rdi
 	decl %ecx
-	jnz align_1
-	jmp after_bad_alignment
-small_align:
+	jnz .Lalign_1
+	jmp .Lafter_bad_alignment
+.Lsmall_align:
 	addq %r9,%rdx
-	jmp handle_7
+	jmp .Lhandle_7
 #endif
 	
 	/* table sorted by exception address */	
 	.section __ex_table,"a"
 	.align 8
-	.quad s1,s1e
-	.quad s2,s2e
-	.quad s3,s3e
-	.quad s4,s4e	
-	.quad d1,s1e
-	.quad d2,s2e
-	.quad d3,s3e
-	.quad d4,s4e
-	.quad s5,s5e
-	.quad s6,s6e
-	.quad s7,s7e
-	.quad s8,s8e	
-	.quad d5,s5e
-	.quad d6,s6e
-	.quad d7,s7e
-	.quad d8,s8e
-	.quad s9,e_quad
-	.quad d9,e_quad
-	.quad s10,e_byte
-	.quad d10,e_byte
+	.quad .Ls1,.Ls1e
+	.quad .Ls2,.Ls2e
+	.quad .Ls3,.Ls3e
+	.quad .Ls4,.Ls4e	
+	.quad .Ld1,.Ls1e
+	.quad .Ld2,.Ls2e
+	.quad .Ld3,.Ls3e
+	.quad .Ld4,.Ls4e
+	.quad .Ls5,.Ls5e
+	.quad .Ls6,.Ls6e
+	.quad .Ls7,.Ls7e
+	.quad .Ls8,.Ls8e	
+	.quad .Ld5,.Ls5e
+	.quad .Ld6,.Ls6e
+	.quad .Ld7,.Ls7e
+	.quad .Ld8,.Ls8e
+	.quad .Ls9,.Le_quad
+	.quad .Ld9,.Le_quad
+	.quad .Ls10,.Le_byte
+	.quad .Ld10,.Le_byte
 #ifdef FIX_ALIGNMENT	
-	.quad s11,e_byte
-	.quad d11,e_byte
+	.quad .Ls11,.Le_byte
+	.quad .Ld11,.Le_byte
 #endif
-	.quad e5,e_zero
+	.quad .Le5,.Le_zero
 	.previous
 
 	/* compute 64-offset for main loop. 8 bytes accuracy with error on the 
 	   pessimistic side. this is gross. it would be better to fix the 
 	   interface. */	
 	/* eax: zero, ebx: 64 */
-s1e: 	addl $8,%eax
-s2e: 	addl $8,%eax
-s3e: 	addl $8,%eax
-s4e: 	addl $8,%eax
-s5e: 	addl $8,%eax
-s6e: 	addl $8,%eax
-s7e: 	addl $8,%eax
-s8e: 	addl $8,%eax
+.Ls1e: 	addl $8,%eax
+.Ls2e: 	addl $8,%eax
+.Ls3e: 	addl $8,%eax
+.Ls4e: 	addl $8,%eax
+.Ls5e: 	addl $8,%eax
+.Ls6e: 	addl $8,%eax
+.Ls7e: 	addl $8,%eax
+.Ls8e: 	addl $8,%eax
 	addq %rbx,%rdi	/* +64 */
 	subq %rax,%rdi  /* correct destination with computed offset */
 
@@ -215,22 +218,22 @@
 	addq %rax,%rdx	/* add offset to loopcnt */
 	andl $63,%ecx	/* remaining bytes */
 	addq %rcx,%rdx	/* add them */
-	jmp zero_rest
+	jmp .Lzero_rest
 
 	/* exception on quad word loop in tail handling */
 	/* ecx:	loopcnt/8, %edx: length, rdi: correct */
-e_quad:
+.Le_quad:
 	shll $3,%ecx
 	andl $7,%edx
 	addl %ecx,%edx
 	/* edx: bytes to zero, rdi: dest, eax:zero */
-zero_rest:
+.Lzero_rest:
 	movq %rdx,%rcx
-e_byte:
+.Le_byte:
 	xorl %eax,%eax
-e5:	rep 
+.Le5:	rep 
 	stosb
 	/* when there is another exception while zeroing the rest just return */
-e_zero:		
+.Le_zero:		
 	movq %rdx,%rax
-	jmp ende
+	jmp .Lende
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/lib/csum-copy.S linux-2.4.21-pre6/arch/x86_64/lib/csum-copy.S
--- linux-2.4.20/arch/x86_64/lib/csum-copy.S	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/lib/csum-copy.S	2003-03-26 23:49:51.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2002 Andi Kleen
+ * Copyright 2002,2003 Andi Kleen, SuSE Labs.
  *	
  * 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
@@ -8,7 +8,6 @@
  	#include <linux/linkage.h>
 	#include <asm/errno.h>
 
-//	#define FIX_ALIGNMENT 1
 /*
  * Checksum copy with exception handling.
  * On exceptions src_err_ptr or dst_err_ptr is set to -EFAULT and the 
@@ -26,17 +25,14 @@
  * eax  64bit sum. undefined in case of exception.
  * 
  * Wrappers need to take care of valid exception sum and zeroing.		 
+ * They also should align source or destination to 8 bytes.
  */
 
-/* for now - should vary this based on direction */
- #define prefetch prefetcht2
- #define movnti   movq
-
 	.macro source
 10:
 	.section __ex_table,"a"
 	.align 8
-	.quad 10b,bad_source
+	.quad 10b,.Lbad_source
 	.previous
 	.endm
 		
@@ -44,57 +40,55 @@
 20:
 	.section __ex_table,"a"
 	.align 8
-	.quad 20b,bad_dest
+	.quad 20b,.Lbad_dest
 	.previous
 	.endm
 			
 	.globl csum_partial_copy_generic
-	.p2align
+	.p2align 4
 csum_partial_copy_generic:
-	prefetchnta (%rdi)
+	cmpl	 $3*64,%edx
+	jle	 1f
+
+	prefetch (%rdi)
+	prefetch 1*64(%rdi)
+	prefetch 2*64(%rdi)
+	prefetch 3*64(%rdi)
+	prefetch 4*64(%rdi)
+	prefetchw (%rsi)
+	prefetchw 1*64(%rsi)
+	prefetchw 2*64(%rsi)
+	prefetchw 3*64(%rsi)
+	prefetchw 4*64(%rsi)
+
+1:			
+	subq  $7*8,%rsp
+	movq  %rbx,2*8(%rsp)
+	movq  %r12,3*8(%rsp)
+	movq  %r14,4*8(%rsp)
+	movq  %r13,5*8(%rsp)
+	movq  %rbp,6*8(%rsp)
+
+	movq  %r8,(%rsp)
+	movq  %r9,1*8(%rsp)
 	
-	pushq %rbx
-	pushq %r12
-	pushq %r14
-	pushq %r15
-	movq %r8,%r14
-	movq %r9,%r15
 	movl  %ecx,%eax
 	movl  %edx,%ecx
 
-#ifdef FIX_ALIGNMENT
-	/* align source to 8 bytes */	
-	movl %edi,%r8d
-	andl $7,%r8d
-	jnz  bad_alignment	
-after_bad_alignment:
-#endif
-
-	movl  $64,%r10d
 	xorl  %r9d,%r9d
 	movq  %rcx,%r12
 
 	shrq  $6,%r12
-	/* loopcounter is maintained as one less to test efficiently for the
-	   previous to last iteration. This is needed to stop the prefetching. */
-	decq  %r12
-	js    handle_tail       /* < 64 */
-	jz    loop_no_prefetch  /* = 64 + X */ 
+	jz    .Lhandle_tail       /* < 64 */
+
+	clc
 	
 	/* main loop. clear in 64 byte blocks */
-	/* tries hard not to prefetch over the boundary */
-	/* r10:	64, r9: zero, r8: temp2, rbx: temp1, rax: sum, rcx: saved length */
+	/* r9: zero, r8: temp2, rbx: temp1, rax: sum, rcx: saved length */
 	/* r11:	temp3, rdx: temp4, r12 loopcnt */
-	.p2align
-loop:
-	/* Could prefetch more than one loop, but then it would be even
-	   trickier to avoid prefetching over the boundary. The hardware prefetch
-	   should take care of this anyways. The reason for this prefetch is
-	   just the non temporal hint to avoid cache pollution. Hopefully this
-	   will be handled properly by the hardware. */
-	prefetchnta 64(%rdi) 
-	
-loop_no_prefetch:
+	/* r10:	temp5, rbp: temp6, r14 temp7, r13 temp8 */
+	.p2align 4
+.Lloop:
 	source
 	movq  (%rdi),%rbx
 	source
@@ -104,175 +98,133 @@
 	source
 	movq  24(%rdi),%rdx
 
-	dest
-	movnti %rbx,(%rsi)
-	dest
-	movnti %r8,8(%rsi)
-	dest
-	movnti %r11,16(%rsi)
-	dest
-	movnti %rdx,24(%rsi)
+	source
+	movq  32(%rdi),%r10
+	source
+	movq  40(%rdi),%rbp
+	source
+	movq  48(%rdi),%r14
+	source
+	movq  56(%rdi),%r13
 		
-	addq  %rbx,%rax
+	prefetch 5*64(%rdi)
+						
+	adcq  %rbx,%rax
 	adcq  %r8,%rax
 	adcq  %r11,%rax
 	adcq  %rdx,%rax
+	adcq  %r10,%rax
+	adcq  %rbp,%rax
+	adcq  %r14,%rax
+	adcq  %r13,%rax
 
-	source
-	movq  32(%rdi),%rbx
-	source
-	movq  40(%rdi),%r8
-	source
-	movq  48(%rdi),%r11
-	source
-	movq  56(%rdi),%rdx
+	decl %r12d
 	
 	dest
-	movnti %rbx,32(%rsi)
+	movq %rbx,(%rsi)
 	dest
-	movnti %r8,40(%rsi)
+	movq %r8,8(%rsi)
 	dest
-	movnti %r11,48(%rsi)
+	movq %r11,16(%rsi)
 	dest
-	movnti %rdx,56(%rsi)
+	movq %rdx,24(%rsi)
 
-	adcq %rbx,%rax
-	adcq %r8,%rax
-	adcq %r11,%rax
-	adcq %rdx,%rax
+	dest
+	movq %r10,32(%rsi)
+	dest
+	movq %rbp,40(%rsi)
+	dest
+	movq %r14,48(%rsi)
+	dest
+	movq %r13,56(%rsi)
 	
-	adcq %r9,%rax	/* add in carry */
+	prefetchw 5*64(%rsi)
 	
-	addq %r10,%rdi		
-	addq %r10,%rsi
+	leaq 64(%rdi),%rdi
+	leaq 64(%rsi),%rsi
+
+	jnz   .Lloop
 
-	decq %r12
-	jz   loop_no_prefetch	/* previous to last iteration? */
-	jns  loop
+	adcq  %r9,%rax
 
 	/* do last upto 56 bytes */
-handle_tail:
+.Lhandle_tail:
 	/* ecx:	count */
 	movl %ecx,%r10d
 	andl $63,%ecx
 	shrl $3,%ecx
-	jz 	 fold
+	jz 	 .Lfold
 	clc
-	movl $8,%edx
-loop_8:	
+	.p2align 4
+.Lloop_8:	
 	source
 	movq (%rdi),%rbx
 	adcq %rbx,%rax
-	dest
-	movnti %rbx,(%rsi)
-	leaq (%rsi,%rdx),%rsi /* preserve carry */
-	leaq (%rdi,%rdx),%rdi
 	decl %ecx
-	jnz	loop_8
+	dest
+	movq %rbx,(%rsi)
+	leaq 8(%rsi),%rsi /* preserve carry */
+	leaq 8(%rdi),%rdi
+	jnz	.Lloop_8
 	adcq %r9,%rax	/* add in carry */
 
-fold:
+.Lfold:
+	/* reduce checksum to 32bits */
 	movl %eax,%ebx
 	shrq $32,%rax
-	addq %rbx,%rax
+	addl %ebx,%eax
+	adcl %r9d,%eax
 
 	/* do last upto 6 bytes */	
-handle_7:
+.Lhandle_7:
 	movl %r10d,%ecx
 	andl $7,%ecx
 	shrl $1,%ecx
-	jz   handle_1
+	jz   .Lhandle_1
 	movl $2,%edx
 	xorl %ebx,%ebx
 	clc  
-loop_1:	
+	.p2align 4
+.Lloop_1:	
 	source
 	movw (%rdi),%bx
-	adcq %rbx,%rax
+	adcl %ebx,%eax
 	dest
-	movw %bx,(%rsi)
-	addq %rdx,%rdi
-	addq %rdx,%rsi
 	decl %ecx
-	jnz loop_1
-	adcw %r9w,%ax	/* add in carry */
+	movw %bx,(%rsi)
+	leaq 2(%rdi),%rdi
+	leaq 2(%rsi),%rsi
+	jnz .Lloop_1
+	adcl %r9d,%eax	/* add in carry */
 	
 	/* handle last odd byte */
-handle_1:	
+.Lhandle_1:
 	testl $1,%r10d
-	jz    ende
+	jz    .Lende
 	xorl  %ebx,%ebx
 	source
 	movb (%rdi),%bl
 	dest
 	movb %bl,(%rsi)
-	addw %bx,%ax
-	adcw %r9w,%ax		/* carry */
+	addl %ebx,%eax
+	adcl %r9d,%eax		/* carry */
 			
-ende:		
-	sfence
-	popq %r15
-	popq %r14
-	popq %r12
-	popq %rbx
+.Lende:
+	movq 2*8(%rsp),%rbx
+	movq 3*8(%rsp),%r12
+	movq 4*8(%rsp),%r14
+	movq 5*8(%rsp),%r13
+	movq 6*8(%rsp),%rbp
+	addq $7*8,%rsp
 	ret
 
-#ifdef FIX_ALIGNMENT
-	/* align source to 8 bytes. */
-	/* r8d:	unalignedness, ecx len */
-bad_alignment:
-	testl $1,%edi
-	jnz   odd_source
-
-	/* compute distance to next aligned position */
-	movl $8,%r8d
-	xchgl %r8d,%ecx
-	subl %r8d,%ecx
-
-	/* handle unaligned part */
-	shrl $1,%ecx
-	xorl %ebx,%ebx	
-	movl $2,%r10d
-align_loop:
-	source
-	movw (%rdi),%bx
-	addq %rbx,%rax	/* carry cannot happen */
-	dest
-	movw %bx,(%rsi)
-	addq %r10,%rdi
-	addq %r10,%rsi
-	decl %ecx
-	jnz align_loop
-	jmp after_bad_alignment
-
-	/* weird case. need to swap the sum at the end because the spec requires
-	   16 bit words of the sum to be always paired. 
-	   handle it recursively because it should be rather rare. */
-odd_source:
-	/* copy odd byte */
-	xorl %ebx,%ebx
-	source
-	movb (%rdi),%bl
-	addl %ebx,%eax       /* add to old checksum */
-	adcl $0,%ecx
-	dest
-	movb %al,(%rsi)
-	
-	/* fix arguments */
-	movl %eax,%ecx
-	incq %rsi
-	incq %rdi
-	decq %rdx 
-	call csum_partial_copy_generic
-	bswap %eax        /* this should work, but check */
-	jmp ende
-#endif
-
 	/* Exception handlers. Very simple, zeroing is done in the wrappers */
-bad_source:
-	movl $-EFAULT,(%r14)
-	jmp  ende
-	
-bad_dest:
-	movl $-EFAULT,(%r15)
-	jmp ende
+.Lbad_source:
+	movq (%rsp),%rax
+	movl $-EFAULT,(%rax)
+	jmp  .Lende
+	
+.Lbad_dest:
+	movq 8(%rsp),%rax
+	movl $-EFAULT,(%rax)
+	jmp .Lende
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/lib/csum-partial.c linux-2.4.21-pre6/arch/x86_64/lib/csum-partial.c
--- linux-2.4.20/arch/x86_64/lib/csum-partial.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/lib/csum-partial.c	2003-03-26 23:49:54.000000000 +0000
@@ -7,35 +7,39 @@
  
 #include <linux/compiler.h>
 #include <linux/module.h>
+#include <asm/checksum.h>
 
-/* Better way for this sought */
-static inline unsigned short from64to16(unsigned long x)
+#define __force_inline inline __attribute__((always_inline))
+
+static inline unsigned short from32to16(unsigned a) 
 {
-	/* add up 32-bit words for 33 bits */
-	x = (x & 0xffffffff) + (x >> 32);
-	/* add up 16-bit and 17-bit words for 17+c bits */
-	x = (x & 0xffff) + (x >> 16);
-	/* add up 16-bit and 2-bit for 16+c bit */
-	x = (x & 0xffff) + (x >> 16);
-	/* add up carry.. */
-	x = (x & 0xffff) + (x >> 16);
-	return x;
+	unsigned short b = a >> 16; 
+	asm("addw %w2,%w0\n\t"
+	    "adcw $0,%w0\n" 
+	    : "=r" (b)
+	    : "0" (b), "r" (a));
+	return b;
 }
 
 /*
  * Do a 64-bit checksum on an arbitrary memory area.
  * Returns a 32bit checksum.
  *
- * This isn't a great routine, but it's not _horrible_ either. 
- * We rely on the compiler to unroll.
+ * This isn't as time critical as it used to be because many NICs
+ * do hardware checksumming these days.
+ * 
+ * Things tried and found to not make it faster:
+ * Manual Prefetching
+ * Unrolling to an 128 bytes inner loop.
+ * Using interleaving with more registers to break the carry chains.
  */
-static inline unsigned do_csum(const unsigned char * buff, int len)
+static __force_inline unsigned do_csum(const unsigned char *buff, unsigned len)
 {
-	int odd, count;
+	unsigned odd, count;
 	unsigned long result = 0;
 
-	if (len <= 0)
-		goto out;
+	if (unlikely(len == 0))
+		return result; 
 	odd = 1 & (unsigned long) buff;
 	if (unlikely(odd)) {
 		result = *buff << 8;
@@ -45,7 +49,7 @@
 	count = len >> 1;		/* nr of 16-bit words.. */
 	if (count) {
 		if (2 & (unsigned long) buff) {
-			result += *(unsigned short *) buff;
+			result += *(unsigned short *)buff;
 			count--;
 			len -= 2;
 			buff += 2;
@@ -59,18 +63,41 @@
 				buff += 4;
 			}
 			count >>= 1;	/* nr of 64-bit words.. */
-			if (count) {
+
+			/* main loop using 64byte blocks */
 				unsigned long zero = 0; 
-				do {
-					asm("  addq %1,%0\n"
-					    "  adcq %2,%0\n" 
+			unsigned count64 = count >> 3; 
+			while (count64) { 
+				asm("addq 0*8(%[src]),%[res]\n\t"
+				    "adcq 1*8(%[src]),%[res]\n\t"
+				    "adcq 2*8(%[src]),%[res]\n\t"
+				    "adcq 3*8(%[src]),%[res]\n\t"
+				    "adcq 4*8(%[src]),%[res]\n\t"
+				    "adcq 5*8(%[src]),%[res]\n\t"
+				    "adcq 6*8(%[src]),%[res]\n\t"
+				    "adcq 7*8(%[src]),%[res]\n\t"
+				    "adcq %[zero],%[res]"
+				    : [res] "=r" (result)
+				    : [src] "r" (buff), [zero] "r" (zero),
+				    "[res]" (result));
+				buff += 64;
+				count64--;
+			}
+
+			/* last upto 7 8byte blocks */
+			count %= 8; 
+			while (count) { 
+				asm("addq %1,%0\n\t"
+				    "adcq %2,%0\n" 
 					    : "=r" (result)
-					    : "m"  (*buff), "r" (zero),  "0" (result));
-					count--;
+				    : "m" (*(unsigned long *)buff), 
+				    "r" (zero),  "0" (result));
+				--count; 
 					buff += 8;
-				} while (count);
-				result = (result & 0xffffffff) + (result >> 32);
 			}
+			result = add32_with_carry(result>>32,
+						  result&0xffffffff); 
+
 			if (len & 4) {
 				result += *(unsigned int *) buff;
 				buff += 4;
@@ -83,10 +110,11 @@
 	}
 	if (len & 1)
 		result += *buff;
-	result = from64to16(result);
-	if (unlikely(odd))
-		return ((result >> 8) & 0xff) | ((result & 0xff) << 8);
-out:
+	result = add32_with_carry(result>>32, result & 0xffffffff); 
+	if (unlikely(odd)) { 
+		result = from32to16(result);
+		result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
+	}
 	return result;
 }
 
@@ -102,14 +130,9 @@
  *
  * it's best to have buff aligned on a 64-bit boundary
  */
-unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
+unsigned csum_partial(const unsigned char *buff, unsigned len, unsigned sum)
 {
-	unsigned result = do_csum(buff, len);
-
-	/* add in old sum, and carry.. */
-	asm("addl %1,%0\n\t"
-	    "adcl $0,%0" : "=r" (result) : "r" (sum), "0" (result)); 
-	return result;
+	return add32_with_carry(do_csum(buff, len), sum); 
 }
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/lib/csum-wrappers.c linux-2.4.21-pre6/arch/x86_64/lib/csum-wrappers.c
--- linux-2.4.20/arch/x86_64/lib/csum-wrappers.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/lib/csum-wrappers.c	2003-03-26 23:49:25.000000000 +0000
@@ -1,4 +1,4 @@
-/* Copyright 2002 Andi Kleen, SuSE Labs.
+/* Copyright 2002,2003 Andi Kleen, SuSE Labs.
  * Subject to the GNU Public License v.2
  * 
  * Wrappers of assembly checksum functions for x86-64.
@@ -7,18 +7,6 @@
 #include <asm/checksum.h>
 #include <linux/module.h>
 
-/* Better way for this sought */
-static inline unsigned from64to32(unsigned long x)
-{
-	/* add up 32-bit words for 33 bits */
-        x = (x & 0xffffffff) + (x >> 32);
-        /* add up 16-bit and 17-bit words for 17+c bits */
-        x = (x & 0xffff) + (x >> 16);
-        /* add up 16-bit and 2-bit for 16+c bit */
-        x = (x & 0xffff) + (x >> 16);
-        return x;
-}
-
 /** 
  * csum_partial_copy_from_user - Copy and checksum from user space. 
  * @src: source address (user space) 
@@ -36,14 +24,32 @@
 { 
 	*errp = 0;
 	if (likely(access_ok(VERIFY_READ,src, len))) { 
-		unsigned long sum; 
-		sum = csum_partial_copy_generic(src,dst,len,isum,errp,NULL);
+		/* Why 6, not 7? To handle odd addresses aligned we
+		   would need to do considerable complications to fix the
+		   checksum which is defined as an 16bit accumulator. The
+		   fix alignment code is primarily for performance
+		   compatibility with 32bit and that will handle odd
+		   addresses slowly too. */
+		if (unlikely((unsigned long)src & 6)) {			
+			while (((unsigned long)src & 6) && len >= 2) { 
+				__u16 val16;			
+				*errp = __get_user(val16, (__u16 *)src); 
+				if (*errp)
+					return isum;
+				*(__u16 *)dst = val16;
+				isum = add32_with_carry(isum, val16); 
+				src += 2; 
+				dst += 2; 
+				len -= 2;
+			}
+		}
+		isum = csum_partial_copy_generic(src,dst,len,isum,errp,NULL);
 		if (likely(*errp == 0)) 
-			return from64to32(sum); 
+			return isum;
 	} 
 	*errp = -EFAULT;
 	memset(dst,0,len); 
-	return 0;		
+	return isum;		
 } 
 
 EXPORT_SYMBOL(csum_partial_copy_from_user);
@@ -67,8 +73,22 @@
 		*errp = -EFAULT;
 		return 0; 
 	}
+
+	if (unlikely((unsigned long)dst & 6)) {
+		while (((unsigned long)dst & 6) && len >= 2) { 
+			__u16 val16 = *(__u16 *)src;
+			isum = add32_with_carry(isum, val16);
+			*errp = __put_user(val16, (__u16 *)dst);
+			if (*errp)
+				return isum;
+			src += 2; 
+			dst += 2; 
+			len -= 2;
+		}
+	}
+
 	*errp = 0;
-	return from64to32(csum_partial_copy_generic(src,dst,len,isum,NULL,errp)); 
+	return csum_partial_copy_generic(src,dst,len,isum,NULL,errp); 
 } 
 
 EXPORT_SYMBOL(csum_partial_copy_to_user);
@@ -85,11 +105,9 @@
 unsigned int 
 csum_partial_copy_nocheck(const char *src, char *dst, int len, unsigned int sum)
 { 
-	return from64to32(csum_partial_copy_generic(src,dst,len,sum,NULL,NULL));
+	return csum_partial_copy_generic(src,dst,len,sum,NULL,NULL);
 } 
 
-//EXPORT_SYMBOL(csum_partial_copy_nocheck);
-
 unsigned short csum_ipv6_magic(struct in6_addr *saddr, struct in6_addr *daddr,
 			       __u32 len, unsigned short proto, unsigned int sum) 
 {
@@ -103,7 +121,7 @@
 	    "  adcq $0,%[sum]\n"
 	    : [sum] "=r" (sum64) 
 	    : "[sum]" (rest),[saddr] "r" (saddr), [daddr] "r" (daddr));
-	return csum_fold(from64to32(sum64)); 
+	return csum_fold(add32_with_carry(sum64 & 0xffffffff, sum64>>32));
 }
 
 EXPORT_SYMBOL(csum_ipv6_magic);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/lib/delay.c linux-2.4.21-pre6/arch/x86_64/lib/delay.c
--- linux-2.4.20/arch/x86_64/lib/delay.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/lib/delay.c	2003-03-26 23:49:02.000000000 +0000
@@ -19,7 +19,6 @@
 
 void __delay(unsigned long loops)
 {
-#ifndef CONFIG_SIMNOW
 	unsigned long bclock, now;
 	
 	rdtscl(bclock);
@@ -29,7 +28,6 @@
 		rdtscl(now);
 	}
 	while((now-bclock) < loops);
-#endif
 }
 
 inline void __const_udelay(unsigned long xloops)
@@ -41,3 +39,9 @@
 {
 	__const_udelay(usecs * 0x000010c6);  /* 2**32 / 1000000 */
 }
+
+void __ndelay(unsigned long usecs)
+{
+       __const_udelay(usecs * 0x00005);  /* 2**32 / 1000000000 (rounded up) */
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/lib/memcpy.S linux-2.4.21-pre6/arch/x86_64/lib/memcpy.S
--- linux-2.4.20/arch/x86_64/lib/memcpy.S	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/lib/memcpy.S	2003-03-26 23:48:57.000000000 +0000
@@ -24,16 +24,16 @@
 #ifdef FIX_ALIGNMENT
 	movl %edi,%ecx
 	andl $7,%ecx
-	jnz  bad_alignment	
-after_bad_alignment:
+	jnz  .Lbad_alignment	
+.Lafter_bad_alignment:
 #endif
 
 	movq %rdx,%rcx
 	movl $64,%ebx
 	shrq $6,%rcx
-	jz handle_tail
+	jz .Lhandle_tail
 	
-loop_64:
+.Lloop_64:
 	movq (%rsi),%r11
 	movq 8(%rsi),%r8
 	movq 2*8(%rsi),%r9
@@ -55,35 +55,35 @@
 	addq %rbx,%rsi	
 	addq %rbx,%rdi
 	decl %ecx
-	jnz  loop_64
+	jnz  .Lloop_64
 
-handle_tail:
+.Lhandle_tail:
 	movl %edx,%ecx
 	andl $63,%ecx
 	shrl $3,%ecx
-	jz   handle_7
+	jz   .Lhandle_7
 	movl $8,%ebx
-loop_8: 
+.Lloop_8: 
 	movq (%rsi),%r8
 	movq %r8,(%rdi) 
 	addq %rbx,%rdi
 	addq %rbx,%rsi
 	decl %ecx
-	jnz  loop_8
+	jnz  .Lloop_8
 
-handle_7:
+.Lhandle_7:
 	movl %edx,%ecx
 	andl $7,%ecx
-	jz ende
-loop_1:
+	jz .Lende
+.Lloop_1:
 	movb (%rsi),%r8b
 	movb %r8b,(%rdi) 
 	incq %rdi
 	incq %rsi
 	decl %ecx
-	jnz loop_1
+	jnz .Lloop_1
 	
-ende: 	
+.Lende: 	
 	sfence
 	popq %rbx
 	ret
@@ -93,22 +93,22 @@
 	/* align destination */
 	/* This is simpleminded. For bigger blocks it may make sense to align
 	   src and dst to their aligned subset and handle the rest separately */
-bad_alignment:
+.Lbad_alignment:
 	movl $8,%r9d
 	subl %ecx,%r9d
 	movl %r9d,%ecx
 	subq %r9,%rdx
-	js   small_alignment
-	jz   small_alignment
-align_1:
+	js   .Lsmall_alignment
+	jz   .Lsmall_alignment
+.Lalign_1:
 	movb (%rsi),%r8b
 	movb %r8b,(%rdi) 
 	incq %rdi
 	incq %rsi
 	decl %ecx
-	jnz  align_1
-	jmp after_bad_alignment
-small_alignment:
+	jnz  .Lalign_1
+	jmp .Lafter_bad_alignment
+.Lsmall_alignment:
 	addq %r9,%rdx
-	jmp handle_7
+	jmp .Lhandle_7
 #endif	
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/lib/memset.S linux-2.4.21-pre6/arch/x86_64/lib/memset.S
--- linux-2.4.20/arch/x86_64/lib/memset.S	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/lib/memset.S	2003-03-26 23:49:50.000000000 +0000
@@ -25,15 +25,15 @@
 	/* align dst */
 	movl  %edi,%r9d
 	andl  $7,%r9d	
-	jnz  bad_alignment
-after_bad_alignment:
+	jnz  .Lbad_alignment
+.Lafter_bad_alignment:
 
 	movq %r11,%rcx
 	movl $64,%r8d
 	shrq $6,%rcx
-	jz	 handle_tail
+	jz	 .Lhandle_tail
 
-loop_64:	
+.Lloop_64:	
 	movq  %rax,(%rdi) 
 	movq  %rax,8(%rdi) 
 	movq  %rax,16(%rdi) 
@@ -44,41 +44,41 @@
 	movq  %rax,56(%rdi) 
 	addq    %r8,%rdi
 	decl   %ecx
-	jnz    loop_64
+	jnz    .Lloop_64
 
 	/* Handle tail in loops. The loops should be faster than hard
 	   to predict jump tables. */ 
-handle_tail:
+.Lhandle_tail:
 	movl	%r11d,%ecx
 	andl    $63&(~7),%ecx
-	jz 		handle_7
+	jz 		.Lhandle_7
 	shrl	$3,%ecx
-loop_8:
+.Lloop_8:
 	movq  %rax,(%rdi) 
 	addq    $8,%rdi
 	decl   %ecx
-	jnz    loop_8
+	jnz    .Lloop_8
 
-handle_7:
+.Lhandle_7:
 	movl	%r11d,%ecx
 	andl	$7,%ecx
-	jz      ende
-loop_1:
+	jz      .Lende
+.Lloop_1:
 	movb 	%al,(%rdi)
 	addq	$1,%rdi
 	decl    %ecx
-	jnz     loop_1
+	jnz     .Lloop_1
 	
-ende:	
+.Lende:	
 	movq	%r10,%rax
 	ret
 
-bad_alignment:
+.Lbad_alignment:
 	cmpq $7,%r11
-	jbe	handle_7
+	jbe	.Lhandle_7
 	movq %rax,(%rdi)	/* unaligned store */
 	movq $8,%r8
 	subq %r9,%r8 
 	addq %r8,%rdi
 	subq %r8,%r11
-	jmp after_bad_alignment
+	jmp .Lafter_bad_alignment
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/lib/usercopy.c linux-2.4.21-pre6/arch/x86_64/lib/usercopy.c
--- linux-2.4.20/arch/x86_64/lib/usercopy.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/lib/usercopy.c	2003-03-26 23:48:58.000000000 +0000
@@ -30,7 +30,7 @@
 		"	jmp 2b\n"					   \
 		".previous\n"						   \
 		".section __ex_table,\"a\"\n"				   \
-		"	.align 4\n"					   \
+		"	.align 8\n"					   \
 		"	.quad 0b,3b\n"					   \
 		".previous"						   \
 		: "=r"(res), "=c"(count), "=&a" (__d0), "=&S" (__d1),	   \
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/mm/fault.c linux-2.4.21-pre6/arch/x86_64/mm/fault.c
--- linux-2.4.20/arch/x86_64/mm/fault.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/mm/fault.c	2003-03-26 23:49:55.000000000 +0000
@@ -30,9 +30,6 @@
 #include <asm/proto.h>
 #include <asm/kdebug.h>
 
-spinlock_t pcrash_lock; 
-int crashing_cpu;
-
 extern spinlock_t console_lock, timerlist_lock;
 
 void bust_spinlocks(int yes)
@@ -60,29 +57,41 @@
 	}
 }
 
+static int bad_address(void *p) 
+{ 
+	unsigned long dummy;
+	return __get_user(dummy, (unsigned long *)p);
+} 
+
 void dump_pagetable(unsigned long address)
 {
-	static char *name[] = { "PML4", "PGD", "PDE", "PTE" }; 
-	int i, shift;
-	unsigned long page;
-
-	shift = 9+9+9+12;
-	address &= ~0xFFFF000000000000UL;
-	asm("movq %%cr3,%0" : "=r" (page)); 
-	for (i = 0; i < 4; i++) { 	
-		unsigned long *padr = (unsigned long *) __va(page); 
-		padr += (address >> shift) & 0x1FFU;
-		if (__get_user(page, padr)) { 
-			printk("%s: bad %p\n", name[i], padr); 
-			break;
-		}
-		printk("%s: %016lx ", name[i], page); 
-		if ((page & (1 | (1<<7))) != 1) /* Not present or 2MB page */
-			break;
-		page &= ~0xFFFUL;
-		shift -= (i == 0) ? 12 : 9;
-	} 
+	pml4_t *pml4;
+	asm("movq %%cr3,%0" : "=r" (pml4));
+
+	pml4 = __va((unsigned long)pml4 & PHYSICAL_PAGE_MASK); 
+	pml4 += pml4_index(address);
+	printk("PML4 %lx ", pml4_val(*pml4));
+	if (bad_address(pml4)) goto bad;
+	if (!pml4_present(*pml4)) goto ret; 
+
+	pgd_t *pgd = __pgd_offset_k((pgd_t *)pml4_page(*pml4), address); 
+	if (bad_address(pgd)) goto bad;
+	printk("PGD %lx ", pgd_val(*pgd)); 
+	if (!pgd_present(*pgd))	goto ret;
+
+	pmd_t *pmd = pmd_offset(pgd, address); 
+	if (bad_address(pmd)) goto bad;
+	printk("PMD %lx ", pmd_val(*pmd));
+	if (!pmd_present(*pmd))	goto ret;	 
+
+	pte_t *pte = pte_offset(pmd, address);
+	if (bad_address(pte)) goto bad;
+	printk("PTE %lx", pte_val(*pte)); 
+ret:
 	printk("\n");
+	return;
+bad:
+	printk("BAD\n");
 }
 
 int page_fault_trace; 
@@ -112,15 +121,18 @@
 	/* get the address */
 	__asm__("movq %%cr2,%0":"=r" (address));
 
+	if (regs->eflags & X86_EFLAGS_IF)
+		__sti();
+
 #ifdef CONFIG_CHECKING
 	if (page_fault_trace) 
-		printk("pfault %d rip:%lx rsp:%lx cs:%lu ss:%lu addr %lx error %lx\n",
-		       stack_smp_processor_id(), regs->rip,regs->rsp,regs->cs,
-			   regs->ss,address,error_code); 
+		printk("pagefault rip:%lx rsp:%lx cs:%lu ss:%lu address %lx error %lx\n",
+		       regs->rip,regs->rsp,regs->cs,regs->ss,address,error_code); 
+
 
 	{ 
 		unsigned long gs; 
-		struct x8664_pda *pda = cpu_pda + stack_smp_processor_id(); 
+		struct x8664_pda *pda = cpu_pda + safe_smp_processor_id(); 
 		rdmsrl(MSR_GS_BASE, gs); 
 		if (gs != (unsigned long)pda) { 
 			wrmsrl(MSR_GS_BASE, pda); 
@@ -217,14 +229,11 @@
 
 	/* User mode accesses just cause a SIGSEGV */
 	if (error_code & 4) {
-		if (exception_trace) {
-#if 1
-			dump_pagetable(address);
-#endif	
+		if (exception_trace) 
 			printk("%s[%d]: segfault at %016lx rip %016lx rsp %016lx error %lx\n",
 					current->comm, current->pid, address, regs->rip,
 					regs->rsp, error_code);
-		}
+	
 		tsk->thread.cr2 = address;
 		tsk->thread.error_code = error_code;
 		tsk->thread.trap_no = 14;
@@ -256,14 +265,6 @@
 	console_verbose();
 	bust_spinlocks(1); 
 
-	if (!in_interrupt()) { 
-		if (!spin_trylock(&pcrash_lock)) { 
-			if (crashing_cpu != smp_processor_id()) 
-				spin_lock(&pcrash_lock);  		    
-		} 
-		crashing_cpu = smp_processor_id();
-	} 
-
 	if (address < PAGE_SIZE)
 		printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
 	else
@@ -272,14 +273,7 @@
 	printk(" printing rip:\n");
 	printk("%016lx\n", regs->rip);
 	dump_pagetable(address);
-
 	die("Oops", regs, error_code);
-
-	if (!in_interrupt()) { 
-		crashing_cpu = -1;  /* small harmless window */ 
-		spin_unlock(&pcrash_lock);
-	}
-
 	bust_spinlocks(0); 
 	do_exit(SIGKILL);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/mm/init.c linux-2.4.21-pre6/arch/x86_64/mm/init.c
--- linux-2.4.20/arch/x86_64/mm/init.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/mm/init.c	2003-03-26 23:49:10.000000000 +0000
@@ -189,7 +189,7 @@
 	unsigned long pfn = table_end++, paddr; 
 	void *adr;
 
-	if (table_end >= end_pfn) 
+	if (table_end >= end_pfn_map) 
 		panic("alloc_low_page: ran out of page mappings"); 
 	for (i = 0; temp_mappings[i].allocated; i++) {
 		if (!temp_mappings[i].pmd) 
@@ -246,7 +246,8 @@
 					set_pmd(pmd,  __pmd(0)); 
 				break;
 			}
-			pe = _PAGE_PSE | _KERNPG_TABLE | _PAGE_GLOBAL | paddr;
+			pe = _PAGE_PSE | _KERNPG_TABLE | _PAGE_NX | _PAGE_GLOBAL | paddr;
+			pe &= __supported_pte_mask; 
 			set_pmd(pmd, __pmd(pe));
 		}
 		unmap_low_page(map);
@@ -264,7 +265,7 @@
 	unsigned long next; 
 	unsigned long pgds, pmds, tables; 
 
-	end = end_pfn << PAGE_SHIFT; 
+	end = end_pfn_map << PAGE_SHIFT; 
 
 	/* 
 	 * Find space for the kernel direct mapping tables.
@@ -494,7 +495,7 @@
 	return;
 }
 
-void reserve_bootmem_generic(unsigned long phys, unsigned len) 
+void __init reserve_bootmem_generic(unsigned long phys, unsigned len) 
 { 
 	/* Should check here against the e820 map to avoid double free */ 
 #ifdef CONFIG_DISCONTIGMEM
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/mm/ioremap.c linux-2.4.21-pre6/arch/x86_64/mm/ioremap.c
--- linux-2.4.20/arch/x86_64/mm/ioremap.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/mm/ioremap.c	2003-03-26 23:49:25.000000000 +0000
@@ -142,7 +142,7 @@
 	 */
 	offset = phys_addr & ~PAGE_MASK;
 	phys_addr &= PAGE_MASK;
-	size = PAGE_ALIGN(last_addr) - phys_addr;
+	size = PAGE_ALIGN(last_addr + 1) - phys_addr;
 
 	/*
 	 * Ok, go for it..
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/mm/k8topology.c linux-2.4.21-pre6/arch/x86_64/mm/k8topology.c
--- linux-2.4.20/arch/x86_64/mm/k8topology.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/mm/k8topology.c	2003-03-26 23:49:19.000000000 +0000
@@ -6,7 +6,7 @@
  * Instead the northbridge registers are read directly. 
  * 
  * Copyright 2002 Andi Kleen, SuSE Labs.
- * $Id: k8topology.c,v 1.3 2002/09/12 12:51:39 ak Exp $
+ * $Id: k8topology.c,v 1.5 2003/03/10 14:33:40 ak Exp $
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -23,7 +23,7 @@
 int memnode_shift;
 u8  memnodemap[NODEMAPSIZE];
 
-static int find_northbridge(void)
+static __init int find_northbridge(void)
 {
 	int num; 
 
@@ -53,7 +53,7 @@
 #define for_all_nodes(n) \
 	for (n=0; n<MAXNODE;n++) if (nodes[n].start!=nodes[n].end)
 
-static int compute_hash_shift(struct node *nodes, int numnodes, u64 maxmem)
+static __init int compute_hash_shift(struct node *nodes, int numnodes, u64 maxmem)
 {
 	int i; 
 	int shift = 24;
@@ -130,10 +130,8 @@
 
 		if (limit > end_pfn << PAGE_SHIFT) 
 			limit = end_pfn << PAGE_SHIFT; 
-		if (limit <= base) { 
-			printk(KERN_INFO "Node %d beyond memory map\n", nodeid);
+		if (limit <= base)
 			continue; 
-		} 
 			
 		base >>= 16;
 		base <<= 24; 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/mm/modutil.c linux-2.4.21-pre6/arch/x86_64/mm/modutil.c
--- linux-2.4.20/arch/x86_64/mm/modutil.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/mm/modutil.c	2003-03-26 23:49:19.000000000 +0000
@@ -10,11 +10,23 @@
  
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
+#include <linux/init.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
+#include <asm/proto.h>
 
-static struct vm_struct * modvmlist = NULL;
+extern char _text[], _end[]; 
+
+/* Kernel mapping to make the kernel alias visible to 
+   /proc/kcore and /dev/mem 
+
+   RED-PEN may want vsyscall mappings too 
+ */
+
+static struct vm_struct kernel_mapping = { 
+	.addr = (void *)KERNEL_TEXT_START, 
+}; 
 
 void module_unmap (void * addr)
 {
@@ -26,9 +38,11 @@
 		printk("Trying to unmap module with bad address (%p)\n", addr);
 		return;
 	}
-	for (p = &modvmlist ; (tmp = *p) ; p = &tmp->next) {
+	write_lock(&vmlist_lock); 
+	for (p = &vmlist ; (tmp = *p) ; p = &tmp->next) {
 		if (tmp->addr == addr) {
 			*p = tmp->next;
+			write_unlock(&vmlist_lock); 
 			vmfree_area_pages(VMALLOC_VMADDR(tmp->addr), tmp->size);
 			kfree(tmp);
 			return;
@@ -45,24 +59,55 @@
 	size = PAGE_ALIGN(size);
 	if (!size || size > MODULES_LEN) return NULL;
 		
+	area = (struct vm_struct *) kmalloc(sizeof(*area), GFP_KERNEL);
+	if (!area) return NULL; 
+
+	memset(area, 0, sizeof(struct vm_struct));
+
+	size = round_up(size, PAGE_SIZE); 
+
 	addr = (void *) MODULES_VADDR;
-	for (p = &modvmlist; (tmp = *p) ; p = &tmp->next) {
+	write_lock(&vmlist_lock); 
+	for (p = &vmlist; (tmp = *p) ; p = &tmp->next) {
+		void *next;
 		if (size + (unsigned long) addr < (unsigned long) tmp->addr)
 			break;
-		addr = (void *) (tmp->size + (unsigned long) tmp->addr);
+		next = (void *) (tmp->size + (unsigned long) tmp->addr);
+		if (next > addr)
+			addr = next;
+	}
+	if ((unsigned long) addr + size >= MODULES_END) { 
+		write_unlock(&vmlist_lock); 
+		kfree(area);
+		return NULL;
 	}
-	if ((unsigned long) addr + size >= MODULES_END) return NULL;
 	
-	area = (struct vm_struct *) kmalloc(sizeof(*area), GFP_KERNEL);
-	if (!area) return NULL;
-	area->size = size + PAGE_SIZE;
+	area->size = size;
 	area->addr = addr;
 	area->next = *p;
 	*p = area;
+	write_unlock(&vmlist_lock); 
 
-	if (vmalloc_area_pages(VMALLOC_VMADDR(addr), size, GFP_KERNEL, PAGE_KERNEL)) {
+	if (vmalloc_area_pages(VMALLOC_VMADDR(addr), size, GFP_KERNEL, PAGE_KERNEL_EXECUTABLE)) {
 		module_unmap(addr);
 		return NULL;
 	}
 	return addr;
 }
+
+static int __init mod_vmlist_init(void)
+{
+	struct vm_struct *vm, **base;
+	write_lock(&vmlist_lock); 
+	for (base = &vmlist, vm = *base; vm; base = &vm->next, vm = *base) { 
+		if (vm->addr > (void *)KERNEL_TEXT_START) 
+			break; 
+	}  
+	kernel_mapping.size = _end - _text;
+	kernel_mapping.next = vm; 
+	*base = &kernel_mapping; 
+	write_unlock(&vmlist_lock); 
+	return 0;
+} 
+
+__initcall(mod_vmlist_init);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/mm/numa.c linux-2.4.21-pre6/arch/x86_64/mm/numa.c
--- linux-2.4.20/arch/x86_64/mm/numa.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/mm/numa.c	2003-03-26 23:49:00.000000000 +0000
@@ -1,7 +1,7 @@
 /* 
  * Generic VM initialization for x86-64 NUMA setups.
  * Copyright 2002 Andi Kleen, SuSE Labs.
- * $Id: numa.c,v 1.4 2002/09/05 15:28:12 ak Exp $
+ * $Id: numa.c,v 1.5 2002/10/23 05:27:46 ak Exp $
  */ 
 #include <linux/kernel.h>
 #include <linux/mm.h>
@@ -185,7 +185,7 @@
 /* [numa=off] */
 static __init int numa_setup(char *opt) 
 { 
-	if (!strcmp(opt,"off"))
+	if (!strncmp(opt,"off",3))
 		numa_off = 1;
 	return 1;
 } 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/mm/pageattr.c linux-2.4.21-pre6/arch/x86_64/mm/pageattr.c
--- linux-2.4.20/arch/x86_64/mm/pageattr.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/mm/pageattr.c	2003-03-26 23:49:10.000000000 +0000
@@ -48,18 +48,17 @@
 {
 	struct cpuinfo_x86 *cpu = &cpu_data[smp_processor_id()]; 
 	wmb(); 
-	/* Disabled for now because there seem to be some problems with CLFLUSH */
 	if (0 && test_bit(X86_FEATURE_CLFLSH, &cpu->x86_capability)) { 
 		/* is this worth it? */ 
 		int i;
 		for (i = 0; i < PAGE_SIZE; i += cpu->x86_clflush_size) 
-			asm volatile("clflush %0" :: "m" (__pa(address) + i)); 
+			asm volatile("clflush %0" :: "m" (address + i)); 
 	} else
 		asm volatile("wbinvd":::"memory"); 
 	__flush_tlb_one(address);
 }
 
-/* no more special protections in this 2/4MB area - revert to a
+/* no more special protections in this 2MB area - revert to a
    large page again. */
 static inline void revert_page(struct page *kpte_page, unsigned long address)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/arch/x86_64/vmlinux.lds linux-2.4.21-pre6/arch/x86_64/vmlinux.lds
--- linux-2.4.20/arch/x86_64/vmlinux.lds	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/arch/x86_64/vmlinux.lds	2003-03-26 23:49:08.000000000 +0000
@@ -55,10 +55,10 @@
   .vxtime_sequence : AT ((LOADADDR(.vsyscall_0) + SIZEOF(.vsyscall_0) + 63) & ~(63)) { *(.vxtime_sequence) }
   vxtime_sequence = LOADADDR(.vxtime_sequence);
   . = ALIGN(16);
-  .hpet : AT ((LOADADDR(.vxtime_sequence) + SIZEOF(.vxtime_sequence) + 15) & ~(15)) { *(.hpet) }
-  hpet = LOADADDR(.hpet);
+  .vxtime : AT ((LOADADDR(.vxtime_sequence) + SIZEOF(.vxtime_sequence) + 15) & ~(15)) { *(.vxtime) }
+  vxtime = LOADADDR(.vxtime);
   . = ALIGN(16);
-  .wall_jiffies : AT ((LOADADDR(.hpet) + SIZEOF(.hpet) + 15) & ~(15)) { *(.wall_jiffies) }
+  .wall_jiffies : AT ((LOADADDR(.vxtime) + SIZEOF(.vxtime) + 15) & ~(15)) { *(.wall_jiffies) }
   wall_jiffies = LOADADDR(.wall_jiffies);
   . = ALIGN(16);
   .sys_tz : AT ((LOADADDR(.wall_jiffies) + SIZEOF(.wall_jiffies) + 15) & ~(15)) { *(.sys_tz) }
@@ -96,8 +96,10 @@
 
   /* Sections to be discarded */
   /DISCARD/ : {
+	*(.text.exit)
 	*(.data.exit)
 	*(.exitcall.exit)
+	*(.eh_frame)
 	}
 
   /* DWARF 2 */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/acpi/acpi_ksyms.c linux-2.4.21-pre6/drivers/acpi/acpi_ksyms.c
--- linux-2.4.20/drivers/acpi/acpi_ksyms.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/drivers/acpi/acpi_ksyms.c	2003-03-26 23:49:25.000000000 +0000
@@ -68,6 +68,7 @@
 EXPORT_SYMBOL(acpi_get_next_object);
 EXPORT_SYMBOL(acpi_evaluate_object);
 EXPORT_SYMBOL(acpi_get_table);
+EXPORT_SYMBOL(acpi_get_firmware_table);
 
 EXPORT_SYMBOL(acpi_install_notify_handler);
 EXPORT_SYMBOL(acpi_remove_notify_handler);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/atm/atmdev_init.c linux-2.4.21-pre6/drivers/atm/atmdev_init.c
--- linux-2.4.20/drivers/atm/atmdev_init.c	2001-11-13 17:19:41.000000000 +0000
+++ linux-2.4.21-pre6/drivers/atm/atmdev_init.c	2003-03-26 23:49:29.000000000 +0000
@@ -19,9 +19,6 @@
 #ifdef CONFIG_ATM_HORIZON
 extern int hrz_detect(void);
 #endif
-#ifdef CONFIG_ATM_IA
-extern int ia_detect(void);
-#endif
 #ifdef CONFIG_ATM_FORE200E
 extern int fore200e_detect(void);
 #endif
@@ -53,9 +50,6 @@
 #ifdef CONFIG_ATM_HORIZON
 	devs += hrz_detect();
 #endif
-#ifdef CONFIG_ATM_IA
-	devs += ia_detect();
-#endif
 #ifdef CONFIG_ATM_FORE200E
 	devs += fore200e_detect();
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/atm/fore200e.c linux-2.4.21-pre6/drivers/atm/fore200e.c
--- linux-2.4.20/drivers/atm/fore200e.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/drivers/atm/fore200e.c	2003-03-26 23:49:35.000000000 +0000
@@ -1135,7 +1135,7 @@
 	return;
     } 
 
-    skb->stamp = vcc->timestamp = xtime;
+    skb->stamp = xtime;
     
 #ifdef FORE200E_52BYTE_AAL0_SDU
     if (cell_header) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/atm/iphase.c linux-2.4.21-pre6/drivers/atm/iphase.c
--- linux-2.4.20/drivers/atm/iphase.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/atm/iphase.c	2003-03-26 23:49:54.000000000 +0000
@@ -1192,7 +1192,8 @@
 
 	/* Build the DLE structure */  
 	wr_ptr = iadev->rx_dle_q.write;  
-	wr_ptr->sys_pkt_addr = virt_to_bus(skb->data);	  
+	wr_ptr->sys_pkt_addr = pci_map_single(iadev->pci, skb->data,
+		len, PCI_DMA_FROMDEVICE);
 	wr_ptr->local_pkt_addr = buf_addr;  
 	wr_ptr->bytes = len;	/* We don't know this do we ?? */  
 	wr_ptr->mode = DMA_INT_ENABLE;  
@@ -1311,6 +1312,9 @@
           struct cpcs_trailer *trailer;
           u_short length;
           struct ia_vcc *ia_vcc;
+
+	  pci_unmap_single(iadev->pci, iadev->rx_dle_q.write->sys_pkt_addr,
+	  	len, PCI_DMA_FROMDEVICE);
           /* no VCC related housekeeping done as yet. lets see */  
           vcc = ATM_SKB(skb)->vcc;
 	  if (!vcc) {
@@ -1430,7 +1434,7 @@
 	IADEV *iadev;  
 	struct rx_buf_desc *buf_desc_ptr;  
 	unsigned long rx_pkt_start = 0;  
-	u32 *odle_addr, *dle_addr;  
+	void *dle_addr;  
 	struct abr_vc_table  *abr_vc_table; 
 	u16 *vc_table;  
 	u16 *reass_table;  
@@ -1441,25 +1445,14 @@
   
 	iadev = INPH_IA_DEV(dev);  
   //    spin_lock_init(&iadev->rx_lock); 
-	/* I need to initialize the DLEs somewhere. Lets see what I   
-		need to do for this, hmmm...  
-		- allocate memory for 256 DLEs. make sure that it starts  
-		on a 4k byte address boundary. Program the start address   
-		in Receive List address register.  ..... to do for TX also  
-	   To make sure that it is a 4k byte boundary - allocate 8k and find   
-		4k byte boundary within.  
-		( (addr + (4k-1)) & ~(4k-1) )  
-	*/   
   
-	/* allocate 8k bytes */  
-	odle_addr = kmalloc(2*sizeof(struct dle)*DLE_ENTRIES, GFP_KERNEL);  
-	if (!odle_addr)  
-	{  
-		printk(KERN_ERR DEV_LABEL "can't allocate DLEs\n");  
-		return -ENOMEM;
-	}  
-	/* find 4k byte boundary within the 8k allocated */  
-	dle_addr = (u32*)( ((u32)odle_addr+(4096-1)) & ~(4096-1) );  
+	/* Allocate 4k bytes - more aligned than needed (4k boundary) */
+	dle_addr = pci_alloc_consistent(iadev->pci, DLE_TOTAL_SIZE,
+					&iadev->rx_dle_dma);  
+	if (!dle_addr)  {  
+		printk(KERN_ERR DEV_LABEL "can't allocate DLEs\n");
+		goto err_out;
+	}
 	iadev->rx_dle_q.start = (struct dle*)dle_addr;  
 	iadev->rx_dle_q.read = iadev->rx_dle_q.start;  
 	iadev->rx_dle_q.write = iadev->rx_dle_q.start;  
@@ -1468,7 +1461,8 @@
 	DLE that can be used. */  
   
 	/* write the upper 20 bits of the start address to rx list address register */  
-	writel(virt_to_bus(dle_addr) & 0xfffff000, iadev->dma+IPHASE5575_RX_LIST_ADDR);  
+	writel(iadev->rx_dle_dma & 0xfffff000,
+	       iadev->dma + IPHASE5575_RX_LIST_ADDR);  
 	IF_INIT(printk("Tx Dle list addr: 0x%08x value: 0x%0x\n", 
                       (u32)(iadev->dma+IPHASE5575_TX_LIST_ADDR), 
                       *(u32*)(iadev->dma+IPHASE5575_TX_LIST_ADDR));  
@@ -1642,8 +1636,7 @@
 	{  
 		printk(KERN_ERR DEV_LABEL "itf %d couldn't get free page\n",
 		dev->number);  
-		kfree(odle_addr);
-		return -ENOMEM;  
+		goto err_free_dle;
 	}  
 	memset(iadev->rx_open, 0, 4*iadev->num_vc);  
         iadev->rxing = 1;
@@ -1651,6 +1644,12 @@
 	/* Mode Register */  
 	writew(R_ONLINE, iadev->reass_reg+MODE_REG);  
 	return 0;  
+
+err_free_dle:
+	pci_free_consistent(iadev->pci, DLE_TOTAL_SIZE, iadev->rx_dle_q.start,
+			    iadev->rx_dle_dma);  
+err_out:
+	return -ENOMEM;
 }  
   
 
@@ -1715,6 +1714,12 @@
             /* free the DMAed skb */ 
             skb = skb_dequeue(&iadev->tx_dma_q); 
             if (!skb) break;
+
+	    /* Revenge of the 2 dle (skb + trailer) used in ia_pkt_tx() */
+	    if (!((dle - iadev->tx_dle_q.start)%(2*sizeof(struct dle)))) {
+		pci_unmap_single(iadev->pci, dle->sys_pkt_addr, skb->len,
+				 PCI_DMA_TODEVICE);
+	    }
             vcc = ATM_SKB(skb)->vcc;
             if (!vcc) {
                   printk("tx_dle_intr: vcc is null\n");
@@ -1884,7 +1889,7 @@
                     return -EINVAL; 
                 }
                 if (vcc->qos.txtp.max_pcr > iadev->LineRate) {
-                   IF_CBR(printk("PCR is not availble\n");)
+                   IF_CBR(printk("PCR is not available\n");)
                    return -1;
                 }
                 vc->type = CBR;
@@ -1894,7 +1899,7 @@
                 }
        } 
 	else  
-           printk("iadev:  Non UBR, ABR and CBR traffic not supportedn"); 
+           printk("iadev:  Non UBR, ABR and CBR traffic not supported\n"); 
         
         iadev->testTable[vcc->vci]->vc_status |= VC_ACTIVE;
 	IF_EVENT(printk("ia open_tx returning \n");)  
@@ -1907,7 +1912,7 @@
 	IADEV *iadev;  
 	struct tx_buf_desc *buf_desc_ptr;
 	unsigned int tx_pkt_start;  
-	u32 *dle_addr;  
+	void *dle_addr;  
 	int i;  
 	u_short tcq_st_adr;  
 	u_short *tcq_start;  
@@ -1923,24 +1928,22 @@
  
 	IF_INIT(printk("Tx MASK REG: 0x%0x\n", 
                                 readw(iadev->seg_reg+SEG_MASK_REG));)  
-	/*---------- Initializing Transmit DLEs ----------*/  
-	/* allocating 8k memory for transmit DLEs */  
-	dle_addr = kmalloc(2*sizeof(struct dle)*DLE_ENTRIES, GFP_KERNEL);  
-	if (!dle_addr)  
-	{  
-		printk(KERN_ERR DEV_LABEL "can't allocate TX DLEs\n");  
-		return -ENOMEM;
-	}  
-  
-	/* find 4k byte boundary within the 8k allocated */  
-	dle_addr = (u32*)(((u32)dle_addr+(4096-1)) & ~(4096-1));  
+
+	/* Allocate 4k (boundary aligned) bytes */
+	dle_addr = pci_alloc_consistent(iadev->pci, DLE_TOTAL_SIZE,
+					&iadev->tx_dle_dma);  
+	if (!dle_addr)  {
+		printk(KERN_ERR DEV_LABEL "can't allocate DLEs\n");
+		goto err_out;
+	}
 	iadev->tx_dle_q.start = (struct dle*)dle_addr;  
 	iadev->tx_dle_q.read = iadev->tx_dle_q.start;  
 	iadev->tx_dle_q.write = iadev->tx_dle_q.start;  
 	iadev->tx_dle_q.end = (struct dle*)((u32)dle_addr+sizeof(struct dle)*DLE_ENTRIES);  
 
 	/* write the upper 20 bits of the start address to tx list address register */  
-	writel(virt_to_bus(dle_addr) & 0xfffff000, iadev->dma+IPHASE5575_TX_LIST_ADDR);  
+	writel(iadev->tx_dle_dma & 0xfffff000,
+	       iadev->dma + IPHASE5575_TX_LIST_ADDR);  
 	writew(0xffff, iadev->seg_reg+SEG_MASK_REG);  
 	writew(0, iadev->seg_reg+MODE_REG_0);  
 	writew(RESET_SEG, iadev->seg_reg+SEG_COMMAND_REG);  
@@ -1984,23 +1987,28 @@
 		buf_desc_ptr++;		  
 		tx_pkt_start += iadev->tx_buf_sz;  
 	}  
-        iadev->tx_buf = kmalloc(iadev->num_tx_desc*sizeof(caddr_t), GFP_KERNEL);
+        iadev->tx_buf = kmalloc(iadev->num_tx_desc*sizeof(struct cpcs_trailer_desc), GFP_KERNEL);
         if (!iadev->tx_buf) {
             printk(KERN_ERR DEV_LABEL " couldn't get mem\n");
-            return -EAGAIN;
+	    goto err_free_dle;
         }
        	for (i= 0; i< iadev->num_tx_desc; i++)
        	{
+	    struct cpcs_trailer *cpcs;
  
-       	    iadev->tx_buf[i] = kmalloc(sizeof(struct cpcs_trailer),
-                                                           GFP_KERNEL|GFP_DMA);
-            if(!iadev->tx_buf[i]) {                
+       	    cpcs = kmalloc(sizeof(*cpcs), GFP_KERNEL|GFP_DMA);
+            if(!cpcs) {                
 		printk(KERN_ERR DEV_LABEL " couldn't get freepage\n"); 
-         	return -EAGAIN;
+		goto err_free_tx_bufs;
             }
+	    iadev->tx_buf[i].cpcs = cpcs;
+	    iadev->tx_buf[i].dma_addr = pci_map_single(iadev->pci,
+		cpcs, sizeof(*cpcs), PCI_DMA_TODEVICE);
         }
         iadev->desc_tbl = kmalloc(iadev->num_tx_desc *
                                    sizeof(struct desc_tbl_t), GFP_KERNEL);
+        if(!iadev->desc_tbl)
+		goto err_free_all_tx_bufs;
   
 	/* Communication Queues base address */  
         i = TX_COMP_Q * iadev->memSize;
@@ -2128,7 +2136,7 @@
         iadev->testTable = kmalloc(sizeof(long)*iadev->num_vc, GFP_KERNEL); 
         if (!iadev->testTable) {
            printk("Get freepage  failed\n");
-           return -EAGAIN; 
+	   goto err_free_desc_tbl;
         }
 	for(i=0; i<iadev->num_vc; i++)  
 	{  
@@ -2137,7 +2145,7 @@
                 iadev->testTable[i] = kmalloc(sizeof(struct testTable_t),
 						GFP_KERNEL);
 		if (!iadev->testTable[i])
-			return -ENOMEM;
+			goto err_free_test_tables;
               	iadev->testTable[i]->lastTime = 0;
  		iadev->testTable[i]->fract = 0;
                 iadev->testTable[i]->vc_status = VC_UBR;
@@ -2193,7 +2201,30 @@
         iadev->tx_pkt_cnt = 0;
         iadev->rate_limit = iadev->LineRate / 3;
   
-	return 0;  
+	return 0;
+
+err_free_test_tables:
+	while (--i >= 0)
+		kfree(iadev->testTable[i]);
+	kfree(iadev->testTable);
+err_free_desc_tbl:
+	kfree(iadev->desc_tbl);
+err_free_all_tx_bufs:
+	i = iadev->num_tx_desc;
+err_free_tx_bufs:
+	while (--i >= 0) {
+		struct cpcs_trailer_desc *desc = iadev->tx_buf + i;
+
+		pci_unmap_single(iadev->pci, desc->dma_addr,
+			sizeof(*desc->cpcs), PCI_DMA_TODEVICE);
+		kfree(desc->cpcs);
+	}
+	kfree(iadev->tx_buf);
+err_free_dle:
+	pci_free_consistent(iadev->pci, DLE_TOTAL_SIZE, iadev->tx_dle_q.start,
+			    iadev->tx_dle_dma);  
+err_out:
+	return -ENOMEM;
 }   
    
 static void ia_int(int irq, void *dev_id, struct pt_regs *regs)  
@@ -2455,6 +2486,33 @@
 	return readl(INPH_IA_DEV(dev)->phy+addr);  
 }  
 
+static void ia_free_tx(IADEV *iadev)
+{
+	int i;
+
+	kfree(iadev->desc_tbl);
+	for (i = 0; i < iadev->num_vc; i++)
+		kfree(iadev->testTable[i]);
+	kfree(iadev->testTable);
+	for (i = 0; i < iadev->num_tx_desc; i++) {
+		struct cpcs_trailer_desc *desc = iadev->tx_buf + i;
+
+		pci_unmap_single(iadev->pci, desc->dma_addr,
+			sizeof(*desc->cpcs), PCI_DMA_TODEVICE);
+		kfree(desc->cpcs);
+	}
+	kfree(iadev->tx_buf);
+	pci_free_consistent(iadev->pci, DLE_TOTAL_SIZE, iadev->tx_dle_q.start,
+			    iadev->tx_dle_dma);  
+}
+
+static void ia_free_rx(IADEV *iadev)
+{
+	kfree(iadev->rx_open);
+	pci_free_consistent(iadev->pci, DLE_TOTAL_SIZE, iadev->rx_dle_q.start,
+			    iadev->rx_dle_dma);  
+}
+
 #if LINUX_VERSION_CODE >= 0x20312
 static int __init ia_start(struct atm_dev *dev)
 #else
@@ -2462,7 +2520,7 @@
 #endif  
 {  
 	IADEV *iadev;  
-	int error = 1;  
+	int error;  
 	unsigned char phy;  
 	u32 ctrl_reg;  
 	IF_EVENT(printk(">ia_start\n");)  
@@ -2470,7 +2528,8 @@
         if (request_irq(iadev->irq, &ia_int, SA_SHIRQ, DEV_LABEL, dev)) {  
                 printk(KERN_ERR DEV_LABEL "(itf %d): IRQ%d is already in use\n",  
                     dev->number, iadev->irq);  
-                return -EAGAIN;  
+		error = -EAGAIN;
+		goto err_out;
         }  
         /* @@@ should release IRQ on error */  
 	/* enabling memory + master */  
@@ -2480,8 +2539,8 @@
 	{  
                 printk(KERN_ERR DEV_LABEL "(itf %d): can't enable memory+"  
                     "master (0x%x)\n",dev->number, error);  
-                free_irq(iadev->irq, dev); 
-                return -EIO;  
+		error = -EIO;  
+		goto err_free_irq;
         }  
 	udelay(10);  
   
@@ -2515,15 +2574,11 @@
     
         ia_hw_type(iadev); 
 	error = tx_init(dev);  
-	if (error) {
-           free_irq(iadev->irq, dev);  
-           return error;
-        }  
+	if (error)
+		goto err_free_irq;
 	error = rx_init(dev);  
-	if (error) {
-          free_irq(iadev->irq, dev); 
-          return error;  
-        }
+	if (error)
+		goto err_free_tx;
   
 	ctrl_reg = readl(iadev->reg+IPHASE5575_BUS_CONTROL_REG);  
        	writel(ctrl_reg | CTRL_FE_RST, iadev->reg+IPHASE5575_BUS_CONTROL_REG);   
@@ -2538,33 +2593,36 @@
 
         if (iadev->phy_type &  FE_25MBIT_PHY) {
            ia_mb25_init(iadev);
-           return 0;
-        }
-        if (iadev->phy_type & (FE_DS3_PHY | FE_E3_PHY)) {
+        } else if (iadev->phy_type & (FE_DS3_PHY | FE_E3_PHY)) {
            ia_suni_pm7345_init(iadev);
-           return 0;
-        }
-
-	error = suni_init(dev);  
-	if (error) {
-          free_irq(iadev->irq, dev); 
-          return error;  
-        }
-
-        /* Enable interrupt on loss of signal SUNI_RSOP_CIE 0x10
-           SUNI_RSOP_CIE_LOSE - 0x04
-        */
-        ia_phy_put(dev, ia_phy_get(dev,0x10) | 0x04, 0x10);         
+        } else {
+		error = suni_init(dev);
+		if (error)
+			goto err_free_rx;
+		/* 
+		 * Enable interrupt on loss of signal
+		 * SUNI_RSOP_CIE - 0x10
+		 * SUNI_RSOP_CIE_LOSE - 0x04
+		 */
+		ia_phy_put(dev, ia_phy_get(dev, 0x10) | 0x04, 0x10);
 #ifndef MODULE
-	error = dev->phy->start(dev);  
-	if (error) {
-          free_irq(iadev->irq, dev);
-          return error;
-        }   
+		error = dev->phy->start(dev);
+		if (error)
+			goto err_free_rx;
 #endif
-        /* Get iadev->carrier_detect status */
-        IaFrontEndIntr(iadev);
-	return 0;  
+		/* Get iadev->carrier_detect status */
+		IaFrontEndIntr(iadev);
+	}
+	return 0;
+
+err_free_rx:
+	ia_free_rx(iadev);
+err_free_tx:
+	ia_free_tx(iadev);
+err_free_irq:
+	free_irq(iadev->irq, dev);  
+err_out:
+	return error;
 }  
   
 static void ia_close(struct atm_vcc *vcc)  
@@ -2873,10 +2931,10 @@
         struct tx_buf_desc *buf_desc_ptr;
         int desc;
         int comp_code;
-        unsigned int addr;
         int total_len, pad, last;
         struct cpcs_trailer *trailer;
         struct ia_vcc *iavcc;
+
         iadev = INPH_IA_DEV(vcc->dev);  
         iavcc = INPH_IA_VCC(vcc);
         if (!iavcc->txing) {
@@ -2961,13 +3019,9 @@
 	IF_TX(printk("ia packet len:%d padding:%d\n", total_len, pad);)  
  
 	/* Put the packet in a tx buffer */   
-	if (!iadev->tx_buf[desc-1])  
-		printk("couldn't get free page\n");  
-
+	trailer = iadev->tx_buf[desc-1].cpcs;
         IF_TX(printk("Sent: skb = 0x%x skb->data: 0x%x len: %d, desc: %d\n",
                   (u32)skb, (u32)skb->data, skb->len, desc);)
-        addr = virt_to_bus(skb->data);
-	trailer = (struct cpcs_trailer*)iadev->tx_buf[desc-1];  
 	trailer->control = 0; 
         /*big endian*/ 
 	trailer->length = ((skb->len & 0xff) << 8) | ((skb->len & 0xff00) >> 8);
@@ -2983,6 +3037,7 @@
 	buf_desc_ptr = (struct tx_buf_desc *)(iadev->seg_ram+TX_DESC_BASE);  
 	buf_desc_ptr += desc;	/* points to the corresponding entry */  
 	buf_desc_ptr->desc_mode = AAL5 | EOM_EN | APP_CRC32 | CMPL_INT;   
+	/* Huh ? p.115 of users guide describes this as a read-only register */
         writew(TRANSMIT_DONE, iadev->seg_reg+SEG_INTR_STATUS_REG);
 	buf_desc_ptr->vc_index = vcc->vci;
 	buf_desc_ptr->bytes = total_len;  
@@ -2993,7 +3048,8 @@
 	/* Build the DLE structure */  
 	wr_ptr = iadev->tx_dle_q.write;  
 	memset((caddr_t)wr_ptr, 0, sizeof(*wr_ptr));  
-	wr_ptr->sys_pkt_addr = addr;  
+	wr_ptr->sys_pkt_addr = pci_map_single(iadev->pci, skb->data,
+		skb->len, PCI_DMA_TODEVICE);
 	wr_ptr->local_pkt_addr = (buf_desc_ptr->buf_start_hi << 16) | 
                                                   buf_desc_ptr->buf_start_lo;  
 	/* wr_ptr->bytes = swap(total_len);	didn't seem to affect ?? */  
@@ -3011,7 +3067,7 @@
 		wr_ptr = iadev->tx_dle_q.start;  
         
         /* Build trailer dle */
-        wr_ptr->sys_pkt_addr = virt_to_bus(iadev->tx_buf[desc-1]);
+        wr_ptr->sys_pkt_addr = iadev->tx_buf[desc-1].dma_addr;
         wr_ptr->local_pkt_addr = ((buf_desc_ptr->buf_start_hi << 16) | 
           buf_desc_ptr->buf_start_lo) + total_len - sizeof(struct cpcs_trailer);
 
@@ -3163,135 +3219,130 @@
 };  
 	  
   
-#if LINUX_VERSION_CODE >= 0x20312
-int __init ia_detect(void)
-#else
-__initfunc(int ia_detect(void)) 
-#endif 
+static int __devinit ia_init_one(struct pci_dev *pdev,
+				 const struct pci_device_id *ent)
 {  
 	struct atm_dev *dev;  
 	IADEV *iadev;  
         unsigned long flags;
-        int index = 0;  
-	struct pci_dev *prev_dev;       
-	if (!pci_present()) {  
-		printk(KERN_ERR DEV_LABEL " driver but no PCI BIOS ?\n");  
-		return 0;  
-	}  
+	int ret;
+
 	iadev = kmalloc(sizeof(*iadev), GFP_KERNEL); 
-	if (!iadev) return -ENOMEM;  
-        memset((char*)iadev, 0, sizeof(*iadev));
-	prev_dev = NULL;  
-	while((iadev->pci = pci_find_device(PCI_VENDOR_ID_IPHASE,  
-		PCI_DEVICE_ID_IPHASE_5575,  prev_dev))) {  
-		IF_INIT(printk("ia detected at bus:%d dev: %d function:%d\n",
-                     iadev->pci->bus->number, PCI_SLOT(iadev->pci->devfn), 
-                                                 PCI_FUNC(iadev->pci->devfn));)  
-		if (pci_enable_device(iadev->pci)) break;
-		dev = atm_dev_register(DEV_LABEL, &ops, -1, NULL);
-		if (!dev) break;  
-		IF_INIT(printk(DEV_LABEL "registered at (itf :%d)\n", 
-                                                             dev->number);)  
-		INPH_IA_DEV(dev) = iadev; 
-                // TODO: multi_board using ia_boards logic in cleanup_module
-		ia_dev[index] = iadev;
-		_ia_dev[index] = dev;
-                IF_INIT(printk("dev_id = 0x%x iadev->LineRate = %d \n", 
-                                        (u32)dev, iadev->LineRate);)
-                iadev_count++;
-                spin_lock_init(&iadev->misc_lock);
-                spin_lock_irqsave(&iadev->misc_lock, flags); 
-		if (ia_init(dev) || ia_start(dev)) {  
-			atm_dev_deregister(dev);  
-                        IF_INIT(printk("IA register failed!\n");)
-                        ia_dev[index] = NULL;
-                        _ia_dev[index] = NULL;
-                        iadev_count--;
-                        spin_unlock_irqrestore(&iadev->misc_lock, flags); 
-			return -EINVAL;  
-		}  
-                spin_unlock_irqrestore(&iadev->misc_lock, flags);
-                IF_EVENT(printk("iadev_count = %d\n", iadev_count);)
-		prev_dev = iadev->pci;  
-		iadev->next_board = ia_boards;  
-		ia_boards = dev;  
-		iadev = kmalloc(sizeof(*iadev), GFP_KERNEL);  
-		if (!iadev) break;   
-                memset((char*)iadev, 0, sizeof(*iadev)); 
-		index++;  
-                dev = NULL;
-	}  
-	return index;  
-}  
-  
+	if (!iadev) {
+		ret = -ENOMEM;
+		goto err_out;
+	}
+	memset(iadev, 0, sizeof(*iadev));
+	iadev->pci = pdev;
 
-#ifdef MODULE  
-  
-int init_module(void)  
-{  
-	IF_EVENT(printk(">ia init_module\n");)  
-	if (!ia_detect()) {  
-		printk(KERN_ERR DEV_LABEL ": no adapter found\n");  
-		return -ENXIO;  
-	}  
-   	ia_timer.expires = jiffies + 3*HZ;
-   	add_timer(&ia_timer); 
-   
-	return 0;  
-}  
-  
-  
-void cleanup_module(void)  
-{  
-	struct atm_dev *dev;  
-	IADEV *iadev;  
-	unsigned short command;  
-        int i, j= 0;
- 
-	IF_EVENT(printk(">ia cleanup_module\n");)  
-	if (MOD_IN_USE)  
-		printk("ia: module in use\n");  
-        del_timer(&ia_timer);
-	while(ia_dev[j])  
-	{  
-		dev = ia_boards;  
-		iadev = INPH_IA_DEV(dev);  
-		ia_boards = iadev->next_board;  
-                
-        	/* disable interrupt of lost signal */
-        	ia_phy_put(dev, ia_phy_get(dev,0x10) & ~(0x4), 0x10); 
-        	udelay(1);
-
-      		/* De-register device */  
-      		atm_dev_deregister(dev);  
-		IF_EVENT(printk("iav deregistered at (itf:%d)\n", dev->number);)
-		for (i= 0; i< iadev->num_tx_desc; i++)
-                        kfree(iadev->tx_buf[i]);
-                kfree(iadev->tx_buf);
-      		/* Disable memory mapping and busmastering */  
-		if (pci_read_config_word(iadev->pci,  
-					     PCI_COMMAND, &command) != 0)  
-      		{  
-         		printk("ia: can't read PCI_COMMAND.\n");  
-      		}  
-      		command &= ~(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);  
-      		if (pci_write_config_word(iadev->pci,  
-					      PCI_COMMAND, command) != 0)  
-      		{  
-         		printk("ia: can't write PCI_COMMAND.\n");  
-      		}  
-      		free_irq(iadev->irq, dev);  
-      		iounmap((void *) iadev->base);  
-      		kfree(iadev);  
-                j++;
-	}  
-	/* and voila whatever we tried seems to work. I don't know if it will  
-		fix suni errors though. Really doubt that. */  
-        for (i = 0; i<8; i++) {
-               ia_dev[i] =  NULL;
-              _ia_dev[i] = NULL;
-        }
-}  
+	IF_INIT(printk("ia detected at bus:%d dev: %d function:%d\n",
+		pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));)
+	if (pci_enable_device(pdev)) {
+		ret = -ENODEV;
+		goto err_out_free_iadev;
+	}
+	dev = atm_dev_register(DEV_LABEL, &ops, -1, NULL);
+	if (!dev) {
+		ret = -ENOMEM;
+		goto err_out_disable_dev;
+	}
+	INPH_IA_DEV(dev) = iadev; 
+	IF_INIT(printk(DEV_LABEL "registered at (itf :%d)\n", dev->number);)
+	IF_INIT(printk("dev_id = 0x%x iadev->LineRate = %d \n", (u32)dev,
+		iadev->LineRate);)
+
+	ia_dev[iadev_count] = iadev;
+	_ia_dev[iadev_count] = dev;
+	iadev_count++;
+	spin_lock_init(&iadev->misc_lock);
+	/* First fixes first. I don't want to think about this now. */
+	spin_lock_irqsave(&iadev->misc_lock, flags); 
+	if (ia_init(dev) || ia_start(dev)) {  
+		IF_INIT(printk("IA register failed!\n");)
+		iadev_count--;
+		ia_dev[iadev_count] = NULL;
+		_ia_dev[iadev_count] = NULL;
+		spin_unlock_irqrestore(&iadev->misc_lock, flags); 
+		ret = -EINVAL;
+		goto err_out_deregister_dev;
+	}
+	spin_unlock_irqrestore(&iadev->misc_lock, flags); 
+	IF_EVENT(printk("iadev_count = %d\n", iadev_count);)
 
-#endif  
+	iadev->next_board = ia_boards;  
+	ia_boards = dev;  
+
+	pci_set_drvdata(pdev, dev);
+
+	return 0;
+
+err_out_deregister_dev:
+	atm_dev_deregister(dev);  
+err_out_disable_dev:
+	pci_disable_device(pdev);
+err_out_free_iadev:
+	kfree(iadev);
+err_out:
+	return ret;
+}
+
+static void __devexit ia_remove_one(struct pci_dev *pdev)
+{
+	struct atm_dev *dev = pci_get_drvdata(pdev);
+	IADEV *iadev = INPH_IA_DEV(dev);
+
+	ia_phy_put(dev, ia_phy_get(dev,0x10) & ~(0x4), 0x10); 
+	udelay(1);
+
+	/* De-register device */  
+      	free_irq(iadev->irq, dev);
+	iadev_count--;
+	ia_dev[iadev_count] = NULL;
+	_ia_dev[iadev_count] = NULL;
+	atm_dev_deregister(dev);
+	IF_EVENT(printk("iav deregistered at (itf:%d)\n", dev->number);)
+
+      	iounmap((void *) iadev->base);  
+	pci_disable_device(pdev);
+
+	ia_free_rx(iadev);
+	ia_free_tx(iadev);
+
+      	kfree(iadev);
+}
+
+static struct pci_device_id ia_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_IPHASE, 0x0008, PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_IPHASE, 0x0009, PCI_ANY_ID, PCI_ANY_ID, },
+	{ 0,}
+};
+MODULE_DEVICE_TABLE(pci, ia_pci_tbl);
+
+static struct pci_driver ia_driver = {
+	.name =         DEV_LABEL,
+	.id_table =     ia_pci_tbl,
+	.probe =        ia_init_one,
+	.remove =       ia_remove_one,
+};
+
+static int __init ia_init_module(void)
+{
+	int ret;
+
+	ret = pci_module_init(&ia_driver);
+	if (ret >= 0) {
+		ia_timer.expires = jiffies + 3*HZ;
+		add_timer(&ia_timer); 
+	}
+	return ret;
+}
+
+static void __exit ia_cleanup_module(void)
+{
+	pci_unregister_driver(&ia_driver);
+
+        del_timer(&ia_timer);
+}
 
+module_init(ia_init_module);
+module_exit(ia_cleanup_module);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/atm/iphase.h linux-2.4.21-pre6/drivers/atm/iphase.h
--- linux-2.4.20/drivers/atm/iphase.h	2001-02-04 18:05:29.000000000 +0000
+++ linux-2.4.21-pre6/drivers/atm/iphase.h	2003-03-26 23:49:16.000000000 +0000
@@ -200,7 +200,13 @@
 	u_short length;  
 	u_int	crc32;  
 };  
-  
+
+struct cpcs_trailer_desc
+{
+	struct cpcs_trailer *cpcs;
+	dma_addr_t dma_addr;
+};
+
 struct ia_vcc 
 { 
 	int rxing;	 
@@ -272,6 +278,7 @@
 #define DLE_ENTRIES 256  
 #define DMA_INT_ENABLE 0x0002	/* use for both Tx and Rx */  
 #define TX_DLE_PSI 0x0001  
+#define DLE_TOTAL_SIZE (sizeof(struct dle)*DLE_ENTRIES)
   
 /* Descriptor List Entries (DLE) */  
 struct dle 
@@ -1017,7 +1024,7 @@
         struct wait_queue     *close_wait;
         struct wait_queue     *timeout_wait;
 #endif
-	caddr_t *tx_buf;  
+	struct cpcs_trailer_desc *tx_buf;
         u16 num_tx_desc, tx_buf_sz, rate_limit;
         u32 tx_cell_cnt, tx_pkt_cnt;
         u32 MAIN_VC_TABLE_ADDR, EXT_VC_TABLE_ADDR, ABR_SCHED_TABLE_ADDR;
@@ -1063,7 +1070,9 @@
         struct desc_tbl_t *desc_tbl;
         u_short host_tcq_wr;
         struct testTable_t **testTable;
-} IADEV;  
+	dma_addr_t tx_dle_dma;
+	dma_addr_t rx_dle_dma;
+} IADEV;
   
   
 #define INPH_IA_DEV(d) ((IADEV *) (d)->dev_data)  
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/atm/nicstar.c linux-2.4.21-pre6/drivers/atm/nicstar.c
--- linux-2.4.20/drivers/atm/nicstar.c	2001-09-13 22:21:32.000000000 +0000
+++ linux-2.4.21-pre6/drivers/atm/nicstar.c	2003-03-26 23:49:18.000000000 +0000
@@ -1597,7 +1597,7 @@
          
 	 fill_tst(card, n, vc);
       }
-      else /* not CBR */
+      else if (vcc->qos.txtp.traffic_class == ATM_UBR)
       {
          vc->cbr_scd = 0x00000000;
 	 vc->scq = card->scq0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/atm/suni.c linux-2.4.21-pre6/drivers/atm/suni.c
--- linux-2.4.20/drivers/atm/suni.c	2001-11-13 17:19:41.000000000 +0000
+++ linux-2.4.21-pre6/drivers/atm/suni.c	2003-03-26 23:49:19.000000000 +0000
@@ -233,8 +233,6 @@
 	if (!(PRIV(dev) = kmalloc(sizeof(struct suni_priv),GFP_KERNEL)))
 		return -ENOMEM;
 
-	MOD_INC_USE_COUNT;
-
 	PRIV(dev)->dev = dev;
 	spin_lock_irqsave(&sunis_lock,flags);
 	first = !sunis;
@@ -280,7 +278,6 @@
 	spin_unlock_irqrestore(&sunis_lock,flags);
 	kfree(PRIV(dev));
 
-	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
@@ -293,7 +290,7 @@
 };
 
 
-int __init suni_init(struct atm_dev *dev)
+int suni_init(struct atm_dev *dev)
 {
 	unsigned char mri;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/block/Makefile linux-2.4.21-pre6/drivers/block/Makefile
--- linux-2.4.20/drivers/block/Makefile	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/drivers/block/Makefile	2003-03-26 23:49:53.000000000 +0000
@@ -10,7 +10,7 @@
 
 O_TARGET := block.o
 
-export-objs	:= ll_rw_blk.o blkpg.o loop.o DAC960.o genhd.o
+export-objs	:= ll_rw_blk.o blkpg.o loop.o DAC960.o genhd.o acsi.o
 
 obj-y	:= ll_rw_blk.o blkpg.o genhd.o elevator.o
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/block/amiflop.c linux-2.4.21-pre6/drivers/block/amiflop.c
--- linux-2.4.20/drivers/block/amiflop.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/drivers/block/amiflop.c	2003-03-26 23:49:35.000000000 +0000
@@ -333,7 +333,7 @@
 
 	get_fdc(drive);
 	save_flags (flags);
-	sti();
+	cli();
 
 	selected = -1;
 
@@ -431,7 +431,7 @@
 	motor_off_timer[drive].expires = jiffies + 3*HZ;
 	/* called this way it is always from interrupt */
 	motor_off_timer[drive].data = nr | 0x80000000;
-	add_timer(motor_off_timer + nr);
+	add_timer(motor_off_timer + drive);
 }
 
 static int fd_calibrate(int drive)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/block/cciss.c linux-2.4.21-pre6/drivers/block/cciss.c
--- linux-2.4.20/drivers/block/cciss.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/block/cciss.c	2003-03-26 23:49:55.000000000 +0000
@@ -1,6 +1,6 @@
 /*
- *    Disk Array driver for Compaq SMART2 Controllers
- *    Copyright 2000 Compaq Computer Corporation
+ *    Disk Array driver for HP SA 5xxx and 6xxx Controllers
+ *    Copyright 2000, 2002 Hewlett-Packard Development Company, L.P. 
  *
  *    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
@@ -16,7 +16,7 @@
  *    along with this program; if not, write to the Free Software
  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- *    Questions/Comments/Bugfixes to arrays@compaq.com
+ *    Questions/Comments/Bugfixes to Cciss-discuss@lists.sourceforge.net
  *
  */
 
@@ -44,12 +44,13 @@
 #include <linux/genhd.h>
 
 #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
-#define DRIVER_NAME "Compaq CISS Driver (v 2.4.5)"
-#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,4,5)
+#define DRIVER_NAME "HP CISS Driver (v 2.4.42)"
+#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,4,42)
 
 /* Embedded module documentation macros - see modules.h */
-MODULE_AUTHOR("Charles M. White III - Compaq Computer Corporation");
-MODULE_DESCRIPTION("Driver for Compaq Smart Array Controller 5300");
+MODULE_AUTHOR("Charles M. White III - Hewlett-Packard Company");
+MODULE_DESCRIPTION("Driver for HP SA5xxx SA6xxx Controllers version 2.4.42");
+MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400"); 
 MODULE_LICENSE("GPL");
 
 #include "cciss_cmd.h"
@@ -66,6 +67,12 @@
                         0x0E11, 0x4082, 0, 0, 0},
 	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB,
                         0x0E11, 0x4083, 0, 0, 0},
+	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC,
+                        0x0E11, 0x409A, 0, 0, 0},
+	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC,
+                        0x0E11, 0x409B, 0, 0, 0},
+	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC,
+                        0x0E11, 0x409C, 0, 0, 0},
 	{0,}
 };
 MODULE_DEVICE_TABLE(pci, cciss_pci_device_id);
@@ -77,15 +84,21 @@
  *  access = Address of the struct of function pointers 
  */
 static struct board_type products[] = {
-	{ 0x40700E11, "Smart Array 5300",	&SA5_access },
+	{ 0x40700E11, "Smart Array 5300", &SA5_access},
 	{ 0x40800E11, "Smart Array 5i", &SA5B_access},
 	{ 0x40820E11, "Smart Array 532", &SA5B_access},
 	{ 0x40830E11, "Smart Array 5312", &SA5B_access},
+	{ 0x409A0E11, "Smart Array 641", &SA5_access},
+	{ 0x409B0E11, "Smart Array 642", &SA5_access},
+	{ 0x409C0E11, "Smart Array 6400", &SA5_access},
 };
 
 /* How long to wait (in millesconds) for board to go into simple mode */
 #define MAX_CONFIG_WAIT 1000 
 
+/*define how many times we will try a command because of bus resets */
+#define MAX_CMD_RETRIES 3
+
 #define READ_AHEAD 	 128
 #define NR_CMDS		 128 /* #commands that can be outstanding */
 #define MAX_CTLR 8
@@ -104,6 +117,9 @@
 
 static int revalidate_logvol(kdev_t dev, int maxusage);
 static int frevalidate_logvol(kdev_t dev);
+static int deregister_disk(int ctlr, int logvol);
+static int register_new_disk(int cltr, int opened_vol, __u64 requested_lun);
+static int cciss_rescan_disk(int cltr, int logvol);
 
 static void cciss_getgeometry(int cntl_num);
 
@@ -130,6 +146,11 @@
 
 #include "cciss_scsi.c"		/* For SCSI tape support */
 
+#define ENG_GIG	1048576000
+#define ENG_GIG_FACTOR (ENG_GIG/512)
+#define	RAID_UNKNOWN 6
+static const char *raid_label[] = {"0","4","1(0+1)","5","5+1","ADG",
+				   "UNKNOWN"};
 /*
  * Report information about this controller.
  */
@@ -137,53 +158,67 @@
 static int cciss_proc_get_info(char *buffer, char **start, off_t offset, 
 		int length, int *eof, void *data)
 {
-        off_t pos = 0;
-        off_t len = 0;
-        int size, i, ctlr;
-        ctlr_info_t *h = (ctlr_info_t*)data;
-        drive_info_struct *drv;
-
-        ctlr = h->ctlr;
-        size = sprintf(buffer, "%s:  Compaq %s Controller\n"
-                "       Board ID: 0x%08lx\n"
-		"       Firmware Version: %c%c%c%c\n"
-                "       Memory Address: 0x%08lx\n"
-                "       IRQ: %d\n"
-                "       Logical drives: %d\n"
-                "       Current Q depth: %d\n"
-		"       Current # commands on controller %d\n"
-                "       Max Q depth since init: %d\n"
-		"       Max # commands on controller since init: %d\n"
-		"       Max SG entries since init: %d\n\n",
-                h->devname,
-                h->product_name,
-                (unsigned long)h->board_id,
-		h->firm_ver[0], h->firm_ver[1], h->firm_ver[2], h->firm_ver[3],
-                (unsigned long)h->vaddr,
-                (unsigned int)h->intr,
-                h->num_luns, 
-                h->Qdepth, h->commands_outstanding,
-		h->maxQsinceinit, h->max_outstanding, h->maxSG);
+	off_t pos = 0;
+	off_t len = 0;
+	int size, i, ctlr;
+	ctlr_info_t *h = (ctlr_info_t*)data;
+	drive_info_struct *drv;
+	unsigned long flags;
+	unsigned int vol_sz, vol_sz_frac;
 
-        pos += size; len += size;
+	spin_lock_irqsave(&io_request_lock, flags);
+	if (h->busy_configuring) {
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return -EBUSY;
+	}
+	h->busy_configuring = 1;
+	spin_unlock_irqrestore(&io_request_lock, flags);
+		
+	ctlr = h->ctlr;
+	size = sprintf(buffer, "%s: HP %s Controller\n"
+ 		"Board ID: 0x%08lx\n"
+		"Firmware Version: %c%c%c%c\n"
+ 		"IRQ: %d\n"
+ 		"Logical drives: %d\n"
+ 		"Current Q depth: %d\n"
+ 		"Current # commands on controller: %d\n"
+ 		"Max Q depth since init: %d\n"
+		"Max # commands on controller since init: %d\n"
+		"Max SG entries since init: %d\n\n",
+  		h->devname,
+  		h->product_name,
+  		(unsigned long)h->board_id,
+  		h->firm_ver[0], h->firm_ver[1], h->firm_ver[2], h->firm_ver[3],
+  		(unsigned int)h->intr,
+  		h->num_luns, 
+  		h->Qdepth, h->commands_outstanding,
+  		h->maxQsinceinit, h->max_outstanding, h->maxSG);
+  
+	pos += size; len += size;
 	cciss_proc_tape_report(ctlr, buffer, &pos, &len);
-	for(i=0; i<h->num_luns; i++) {
-                drv = &h->drv[i];
-                size = sprintf(buffer+len, "cciss/c%dd%d: blksz=%d nr_blocks=%d\n",
-                                ctlr, i, drv->block_size, drv->nr_blocks);
-                pos += size; len += size;
-        }
-
-	size = sprintf(buffer+len, "nr_allocs = %d\nnr_frees = %d\n",
-                        h->nr_allocs, h->nr_frees);
-        pos += size; len += size;
-
-        *eof = 1;
-        *start = buffer+offset;
-        len -= offset;
-        if (len>length)
-                len = length;
-        return len;
+	for(i=0; i<=h->highest_lun; i++) {
+		drv = &h->drv[i];
+		if (drv->nr_blocks == 0)
+			continue;
+		vol_sz = drv->nr_blocks/ENG_GIG_FACTOR; 
+		vol_sz_frac = (drv->nr_blocks%ENG_GIG_FACTOR)*100/ENG_GIG_FACTOR;
+
+		if (drv->raid_level > 5)
+			drv->raid_level = RAID_UNKNOWN;
+		size = sprintf(buffer+len, "cciss/c%dd%d:"
+				"\t%4d.%02dGB\tRAID %s\n",
+		       		 ctlr, i, vol_sz,vol_sz_frac,
+				 raid_label[drv->raid_level]);
+		pos += size, len += size;
+        }
+
+	*eof = 1;
+	*start = buffer+offset;
+	len -= offset;
+	if (len>length)
+		len = length;
+	h->busy_configuring = 0;
+	return len;
 }
 
 static int
@@ -197,16 +232,19 @@
 	int rc;
 #endif
 
-	if (count > sizeof(cmd)-1) return -EINVAL;
-	if (copy_from_user(cmd, buffer, count)) return -EFAULT;
+	if (count > sizeof(cmd)-1) 
+		return -EINVAL;
+	if (copy_from_user(cmd, buffer, count)) 
+		return -EFAULT;
 	cmd[count] = '\0';
-	len = strlen(cmd);	// safe???
+	len = strlen(cmd);	
 	if (cmd[len-1] == '\n')
 		cmd[--len] = '\0';
 #	ifdef CONFIG_CISS_SCSI_TAPE
 		if (strcmp("engage scsi", cmd)==0) {
 			rc = cciss_engage_scsi(h->ctlr);
-			if (rc != 0) return -rc;
+			if (rc != 0) 
+				return -rc;
 			return count;
 		}
 		/* might be nice to have "disengage" too, but it's not
@@ -225,8 +263,10 @@
 
 	if (proc_cciss == NULL) {
 		proc_cciss = proc_mkdir("cciss", proc_root_driver);
-		if (!proc_cciss)
+		if (!proc_cciss) {
+			printk("cciss:  proc_mkdir failed\n");
 			return;
+		}
 	}
 
 	pde = create_proc_read_entry(hba[i]->devname,
@@ -250,11 +290,10 @@
 	u64bit temp64;
 	dma_addr_t cmd_dma_handle, err_dma_handle;
 
-	if (!get_from_pool)
-	{
+	if (!get_from_pool) {
 		c = (CommandList_struct *) pci_alloc_consistent(
 			h->pdev, sizeof(CommandList_struct), &cmd_dma_handle); 
-        	if(c==NULL)
+        	if (c==NULL)
                  	return NULL;
 		memset(c, 0, sizeof(CommandList_struct));
 
@@ -310,8 +349,7 @@
 	int i;
 	u64bit temp64;
 
-	if( !got_from_pool)
-	{ 
+	if (!got_from_pool) { 
 		temp64.val32.lower = c->ErrDesc.Addr.lower;
 		temp64.val32.upper = c->ErrDesc.Addr.upper;
 		pci_free_consistent(h->pdev, sizeof(ErrorInfo_struct), 
@@ -336,24 +374,22 @@
 	
 	/* Loop through each real device */ 
 	hba[ctlr]->gendisk.nr_real = 0; 
-	for(i=0; i< NWD; i++)
-	{
+	for(i=0; i< NWD; i++) {
 		drv = &(hba[ctlr]->drv[i]);
-		if( !(drv->nr_blocks))
+		if (!(drv->nr_blocks))
 			continue;
 		hba[ctlr]->hd[i << NWD_SHIFT].nr_sects = 
 		hba[ctlr]->sizes[i << NWD_SHIFT] = drv->nr_blocks;
 
 		/* for each partition */ 
-		for(j=0; j<MAX_PART; j++)
-		{
+		for(j=0; j<MAX_PART; j++) {
 			hba[ctlr]->blocksizes[(i<<NWD_SHIFT) + j] = 1024; 
 
 			hba[ctlr]->hardsizes[ (i<<NWD_SHIFT) + j] = 
 				drv->block_size;
 		}
-		hba[ctlr]->gendisk.nr_real++;
 	}
+	hba[ctlr]->gendisk.nr_real = hba[ctlr]->highest_lun+1;
 }
 /*
  * Open.  Make sure the device is really there.
@@ -371,13 +407,23 @@
 		return -ENXIO;
 	/*
 	 * Root is allowed to open raw volume zero even if its not configured
-	 * so array config can still work. I don't think I really like this,
+	 * so array config can still work. Root is also allowed to open any
+	 * volume that has a LUN ID, so it can issue IOCTL to reread the
+	 * disk information.  I don't think I really like this.
 	 * but I'm already using way to many device nodes to claim another one
 	 * for "raw controller".
 	 */
 	if (hba[ctlr]->sizes[MINOR(inode->i_rdev)] == 0) { /* not online? */
-		if (MINOR(inode->i_rdev) != 0)	 /* not node 0? */
-			return -ENXIO;
+		if (MINOR(inode->i_rdev) != 0) {	 /* not node 0? */
+			/* if not node 0 make sure it is a partition = 0 */
+			if (MINOR(inode->i_rdev) & 0x0f) {
+				return -ENXIO;
+				/* if it is, make sure we have a LUN ID */
+			} else if (hba[ctlr]->drv[MINOR(inode->i_rdev)
+					>> NWD_SHIFT].LunID == 0) {
+				return -ENXIO;
+			}
+		}
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
 	}
@@ -419,8 +465,8 @@
 #endif /* CCISS_DEBUG */ 
 	
 	switch(cmd) {
-	case HDIO_GETGEO:
-	{
+	   case HDIO_GETGEO:
+	   {
 		struct hd_geometry driver_geo;
 		if (hba[ctlr]->drv[dsk].cylinders) {
 			driver_geo.heads = hba[ctlr]->drv[dsk].heads;
@@ -437,8 +483,8 @@
 		if (copy_to_user((void *) arg, &driver_geo,
 				sizeof( struct hd_geometry)))
 			return  -EFAULT;
-		return(0);
-	}
+		return 0;
+	   }
 	case HDIO_GETGEO_BIG:
 	{
 		struct hd_big_geometry driver_geo;
@@ -457,18 +503,14 @@
 		if (copy_to_user((void *) arg, &driver_geo,  
 				sizeof( struct hd_big_geometry)))
 			return  -EFAULT;
-		return(0);
-	}
-	case BLKGETSIZE:
-		put_user(hba[ctlr]->hd[MINOR(inode->i_rdev)].nr_sects, (unsigned long *)arg);
-		return 0;
-	case BLKGETSIZE64:
-		put_user((u64)hba[ctlr]->hd[MINOR(inode->i_rdev)].nr_sects << 9, (u64*)arg);
 		return 0;
+	}
 	case BLKRRPART:
-		if(!capable(CAP_SYS_ADMIN))
+		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
 		return revalidate_logvol(inode->i_rdev, 1);
+	case BLKGETSIZE:
+	case BLKGETSIZE64:
 	case BLKFLSBUF:
 	case BLKBSZSET:
 	case BLKBSZGET:
@@ -479,30 +521,32 @@
 	case BLKPG:
 	case BLKELVGET:
 	case BLKELVSET:
-		return( blk_ioctl(inode->i_rdev, cmd, arg));
+		return blk_ioctl(inode->i_rdev, cmd, arg);
 	case CCISS_GETPCIINFO:
 	{
 		cciss_pci_info_struct pciinfo;
 
-		if (!arg) return -EINVAL;
+		if (!arg) 
+			return -EINVAL;
 		pciinfo.bus = hba[ctlr]->pdev->bus->number;
 		pciinfo.dev_fn = hba[ctlr]->pdev->devfn;
 		pciinfo.board_id = hba[ctlr]->board_id;
 		if (copy_to_user((void *) arg, &pciinfo,  sizeof( cciss_pci_info_struct )))
 			return  -EFAULT;
-		return(0);
+		return 0;
 	}	
 	case CCISS_GETINTINFO:
 	{
 		cciss_coalint_struct intinfo;
 		ctlr_info_t *c = hba[ctlr];
 
-		if (!arg) return -EINVAL;
+		if (!arg) 
+			return -EINVAL;
 		intinfo.delay = readl(&c->cfgtable->HostWrite.CoalIntDelay);
 		intinfo.count = readl(&c->cfgtable->HostWrite.CoalIntCount);
 		if (copy_to_user((void *) arg, &intinfo, sizeof( cciss_coalint_struct )))
 			return -EFAULT;
-                return(0);
+                return 0;
         }
 	case CCISS_SETINTINFO:
         {
@@ -511,25 +555,21 @@
 		unsigned long flags;
 		int i;
 
-		if (!arg) return -EINVAL;	
-		if (!capable(CAP_SYS_ADMIN)) return -EPERM;
+		if (!arg) 
+			return -EINVAL;	
+		if (!capable(CAP_SYS_ADMIN)) 
+			return -EPERM;
 		if (copy_from_user(&intinfo, (void *) arg, sizeof( cciss_coalint_struct)))
 			return -EFAULT;
-		if ( (intinfo.delay == 0 ) && (intinfo.count == 0))
-
-		{
-//			printk("cciss_ioctl: delay and count cannot be 0\n");
-			return( -EINVAL);
+		if ( (intinfo.delay == 0 ) && (intinfo.count == 0)) {
+			return -EINVAL;
 		}
+
 		spin_lock_irqsave(&io_request_lock, flags);
 		/* Can only safely update if no commands outstanding */ 
-		if (c->commands_outstanding > 0 )
-		{
-//			printk("cciss_ioctl: cannot change coalasing "
-//				"%d commands outstanding on controller\n", 
-//					c->commands_outstanding);
+		if (c->commands_outstanding > 0 ) {
 			spin_unlock_irqrestore(&io_request_lock, flags);
-			return(-EINVAL);
+			return -EINVAL;
 		}
 		/* Update the field, and then ring the doorbell */ 
 		writel( intinfo.delay, 
@@ -538,8 +578,7 @@
                         &(c->cfgtable->HostWrite.CoalIntCount));
 		writel( CFGTBL_ChangeReq, c->vaddr + SA5_DOORBELL);
 
-		for(i=0;i<MAX_CONFIG_WAIT;i++)
-		{
+		for(i=0;i<MAX_CONFIG_WAIT;i++) {
 			if (!(readl(c->vaddr + SA5_DOORBELL) 
 					& CFGTBL_ChangeReq))
 				break;
@@ -548,8 +587,8 @@
 		}	
 		spin_unlock_irqrestore(&io_request_lock, flags);
 		if (i >= MAX_CONFIG_WAIT)
-			return( -EFAULT);
-                return(0);
+			return -EFAULT;
+                return 0;
         }
 	case CCISS_GETNODENAME:
         {
@@ -557,12 +596,13 @@
                 ctlr_info_t *c = hba[ctlr];
 		int i; 
 
-		if (!arg) return -EINVAL;
+		if (!arg) 
+			return -EINVAL;
 		for(i=0;i<16;i++)
 			NodeName[i] = readb(&c->cfgtable->ServerName[i]);
                 if (copy_to_user((void *) arg, NodeName, sizeof( NodeName_type)))
                 	return  -EFAULT;
-                return(0);
+                return 0;
         }
 	case CCISS_SETNODENAME:
 	{
@@ -571,8 +611,10 @@
 		unsigned long flags;
 		int i;
 
-		if (!arg) return -EINVAL;
-		if (!capable(CAP_SYS_ADMIN)) return -EPERM;
+		if (!arg) 
+			return -EINVAL;
+		if (!capable(CAP_SYS_ADMIN)) 
+			return -EPERM;
 		
 		if (copy_from_user(NodeName, (void *) arg, sizeof( NodeName_type)))
 			return -EFAULT;
@@ -585,8 +627,7 @@
 			
 		writel( CFGTBL_ChangeReq, c->vaddr + SA5_DOORBELL);
 
-		for(i=0;i<MAX_CONFIG_WAIT;i++)
-		{
+		for(i=0;i<MAX_CONFIG_WAIT;i++) {
 			if (!(readl(c->vaddr + SA5_DOORBELL) 
 					& CFGTBL_ChangeReq))
 				break;
@@ -595,8 +636,8 @@
 		}	
 		spin_unlock_irqrestore(&io_request_lock, flags);
 		if (i >= MAX_CONFIG_WAIT)
-			return( -EFAULT);
-                return(0);
+			return -EFAULT;
+                return 0;
         }
 
 	case CCISS_GETHEARTBEAT:
@@ -604,45 +645,68 @@
                 Heartbeat_type heartbeat;
                 ctlr_info_t *c = hba[ctlr];
 
-		if (!arg) return -EINVAL;
+		if (!arg) 
+			return -EINVAL;
                 heartbeat = readl(&c->cfgtable->HeartBeat);
                 if (copy_to_user((void *) arg, &heartbeat, sizeof( Heartbeat_type)))
                 	return -EFAULT;
-                return(0);
+                return 0;
         }
 	case CCISS_GETBUSTYPES:
         {
                 BusTypes_type BusTypes;
                 ctlr_info_t *c = hba[ctlr];
 
-		if (!arg) return -EINVAL;
+		if (!arg) 
+			return -EINVAL;
                 BusTypes = readl(&c->cfgtable->BusTypes);
                 if (copy_to_user((void *) arg, &BusTypes, sizeof( BusTypes_type) ))
                 	return  -EFAULT;
-                return(0);
+                return 0;
         }
 	case CCISS_GETFIRMVER:
         {
 		FirmwareVer_type firmware;
 
-		if (!arg) return -EINVAL;
+		if (!arg) 
+			return -EINVAL;
 		memcpy(firmware, hba[ctlr]->firm_ver, 4);
 
                 if (copy_to_user((void *) arg, firmware, sizeof( FirmwareVer_type)))
                 	return -EFAULT;
-                return(0);
+                return 0;
         }
         case CCISS_GETDRIVVER:
         {
 		DriverVer_type DriverVer = DRIVER_VERSION;
 
-                if (!arg) return -EINVAL;
+                if (!arg) 
+			return -EINVAL;
 
                 if (copy_to_user((void *) arg, &DriverVer, sizeof( DriverVer_type) ))
                 	return -EFAULT;
-                return(0);
+                return 0;
         }
+	case CCISS_RESCANDISK:
+	{
+		return cciss_rescan_disk(ctlr, dsk);
+	}
+	case CCISS_DEREGDISK:
+		return deregister_disk(ctlr,dsk);
+
+	case CCISS_REGNEWD:
+		return register_new_disk(ctlr, dsk, 0);
+	case CCISS_REGNEWDISK:
+	{
+		__u64 new_logvol;
 
+		if (!arg) 
+			return -EINVAL;
+		if (copy_from_user(&new_logvol, (void *) arg, 
+			sizeof( __u64)))
+			return -EFAULT;
+		return register_new_disk(ctlr, dsk, new_logvol);
+	}
 	case CCISS_GETLUNINFO:
 	{
 		LogvolInfo_struct luninfo;
@@ -656,14 +720,14 @@
   		start = (dsk << NWD_SHIFT);
 		for(i=1; i <MAX_PART; i++) {
 			int minor = start+i;
-			if(hba[ctlr]->sizes[minor] != 0)
+			if (hba[ctlr]->sizes[minor] != 0)
 				num_parts++;
 		}
 		luninfo.num_parts = num_parts;
 		if (copy_to_user((void *) arg, &luninfo,
 				sizeof( LogvolInfo_struct) ))
 			return -EFAULT;
-		return(0);
+		return 0;
 	}
 	case CCISS_PASSTHRU:
 	{
@@ -675,28 +739,28 @@
 		unsigned long flags;
 		DECLARE_COMPLETION(wait);
 
-		if (!arg) return -EINVAL;
+		if (!arg) 
+			return -EINVAL;
 	
-		if (!capable(CAP_SYS_RAWIO)) return -EPERM;
+		if (!capable(CAP_SYS_RAWIO)) 
+			return -EPERM;
 
 		if (copy_from_user(&iocommand, (void *) arg, sizeof( IOCTL_Command_struct) ))
 			return -EFAULT;
-		if((iocommand.buf_size < 1) && 
-				(iocommand.Request.Type.Direction != XFER_NONE))
-		{	
+		if ((iocommand.buf_size < 1) && 
+				(iocommand.Request.Type.Direction 
+				 	!= XFER_NONE)) {	
 			return -EINVAL;
 		} 
 		/* Check kmalloc limits */
-		if(iocommand.buf_size > 128000)
+		if (iocommand.buf_size > 128000)
 			return -EINVAL;
-		if(iocommand.buf_size > 0)
-		{
+		if (iocommand.buf_size > 0) {
 			buff =  kmalloc(iocommand.buf_size, GFP_KERNEL);
-			if( buff == NULL) 
-				return -EFAULT;
+			if (buff == NULL) 
+				return -ENOMEM;
 		}
-		if (iocommand.Request.Type.Direction == XFER_WRITE)
-		{
+		if (iocommand.Request.Type.Direction == XFER_WRITE) {
 			/* Copy the data into the buffer we created */ 
 			if (copy_from_user(buff, iocommand.buf, iocommand.buf_size))
 			{
@@ -704,40 +768,37 @@
 				return -EFAULT;
 			}
 		}
-		if ((c = cmd_alloc(h , 0)) == NULL)
-		{
+		if ((c = cmd_alloc(h , 0)) == NULL) {
 			kfree(buff);
 			return -ENOMEM;
 		}
-			// Fill in the command type 
+			/* Fill in the command type */
 		c->cmd_type = CMD_IOCTL_PEND;
-			// Fill in Command Header 
-		c->Header.ReplyQueue = 0;  // unused in simple mode
-		if( iocommand.buf_size > 0) 	// buffer to fill 
-		{
+			/* Fill in Command Header */
+		c->Header.ReplyQueue = 0;  /* unused in simple mode */
+		if (iocommand.buf_size > 0) { 	/* buffer to fill */
 			c->Header.SGList = 1;
 			c->Header.SGTotal= 1;
-		} else	// no buffers to fill  
-		{
+		} else	{  /* no buffers to fill  */
 			c->Header.SGList = 0;
                 	c->Header.SGTotal= 0;
 		}
 		c->Header.LUN = iocommand.LUN_info;
-		c->Header.Tag.lower = c->busaddr;  // use the kernel address the cmd block for tag
+		c->Header.Tag.lower = c->busaddr;  /* use the kernel address */
+						/* the cmd block for tag */
 		
-		// Fill in Request block 
+		/* Fill in Request block */
 		c->Request = iocommand.Request; 
 	
-		// Fill in the scatter gather information
-		if (iocommand.buf_size > 0 ) 
-		{
+		/* Fill in the scatter gather information */
+		if (iocommand.buf_size > 0 ) {
 			temp64.val = pci_map_single( h->pdev, buff,
                                         iocommand.buf_size, 
                                 PCI_DMA_BIDIRECTIONAL);	
 			c->SG[0].Addr.lower = temp64.val32.lower;
 			c->SG[0].Addr.upper = temp64.val32.upper;
 			c->SG[0].Len = iocommand.buf_size;
-			c->SG[0].Ext = 0;  // we are not chaining
+			c->SG[0].Ext = 0;  /* we are not chaining */
 		}
 		c->waiting = &wait;
 
@@ -758,18 +819,17 @@
 
 		/* Copy the error information out */ 
 		iocommand.error_info = *(c->err_info);
-		if ( copy_to_user((void *) arg, &iocommand, sizeof( IOCTL_Command_struct) ) )
-		{
+		if (copy_to_user((void *) arg, &iocommand, 
+				sizeof( IOCTL_Command_struct) ) ) {
 			kfree(buff);
 			cmd_free(h, c, 0);
-			return( -EFAULT);	
+			return( -EFAULT);
 		} 	
 
-		if (iocommand.Request.Type.Direction == XFER_READ)
-                {
+		if (iocommand.Request.Type.Direction == XFER_READ) {
                         /* Copy the data out of the buffer we created */
-                        if (copy_to_user(iocommand.buf, buff, iocommand.buf_size))
-			{
+                        if (copy_to_user(iocommand.buf, buff, 
+						iocommand.buf_size)) {
                         	kfree(buff);
 				cmd_free(h, c, 0);
 				return -EFAULT;
@@ -777,9 +837,149 @@
                 }
                 kfree(buff);
 		cmd_free(h, c, 0);
-                return(0);
+                return 0;
 	} 
+	case CCISS_BIG_PASSTHRU:
+	{
+		BIG_IOCTL_Command_struct iocommand;
+		ctlr_info_t *h = hba[ctlr];
+		CommandList_struct *c;
+		char 	*buff[MAXSGENTRIES] = {NULL,};
+		int	buff_size[MAXSGENTRIES] = {0,};
+		u64bit	temp64;
+		unsigned long flags;
+		BYTE sg_used = 0;
+		int status = 0;
+		int i;
+		DECLARE_COMPLETION(wait);
 
+		if (!arg) 
+			return -EINVAL;
+		
+		if (!capable(CAP_SYS_RAWIO)) 
+			return -EPERM;
+
+		if (copy_from_user(&iocommand, (void *) arg, sizeof( BIG_IOCTL_Command_struct) ))
+			return -EFAULT;
+		if ((iocommand.buf_size < 1) && 
+			(iocommand.Request.Type.Direction != XFER_NONE)) {
+			return -EINVAL;
+		} 
+		/* Check kmalloc limits  using all SGs */
+		if (iocommand.malloc_size > MAX_KMALLOC_SIZE)
+			return -EINVAL;
+		if (iocommand.buf_size > iocommand.malloc_size * MAXSGENTRIES)
+			return -EINVAL;
+		if (iocommand.buf_size > 0) {
+			__u32   size_left_alloc = iocommand.buf_size;
+			BYTE    *data_ptr = (BYTE *) iocommand.buf;
+			while (size_left_alloc > 0) {
+				buff_size[sg_used] = (size_left_alloc 
+							> iocommand.malloc_size)
+					? iocommand.malloc_size : size_left_alloc;
+				buff[sg_used] = kmalloc( buff_size[sg_used], 
+						GFP_KERNEL);
+				if (buff[sg_used] == NULL) {
+					status = -ENOMEM;
+					goto cleanup1;
+				}
+				if (iocommand.Request.Type.Direction == 
+						XFER_WRITE)
+				   /* Copy the data into the buffer created */
+				   if (copy_from_user(buff[sg_used], data_ptr, 
+						buff_size[sg_used])) {
+					status = -ENOMEM;
+					goto cleanup1;			
+				   }
+				size_left_alloc -= buff_size[sg_used];
+				data_ptr += buff_size[sg_used];
+				sg_used++;
+			}
+			
+		}
+		if ((c = cmd_alloc(h , 0)) == NULL) {
+			status = -ENOMEM;
+			goto cleanup1;	
+		}
+		/* Fill in the command type */
+		c->cmd_type = CMD_IOCTL_PEND;
+		/* Fill in Command Header */
+		c->Header.ReplyQueue = 0;  /* unused in simple mode */
+		
+		if (iocommand.buf_size > 0) { 	/* buffer to fill */
+			c->Header.SGList = sg_used;
+			c->Header.SGTotal= sg_used;
+		} else	{	/* no buffers to fill */
+			c->Header.SGList = 0;
+			c->Header.SGTotal= 0;
+		}
+		c->Header.LUN = iocommand.LUN_info;
+		c->Header.Tag.lower = c->busaddr;  /* use the kernel address */
+						/* the cmd block for tag */
+		
+	/* Fill in Request block */
+	c->Request = iocommand.Request; 
+	/* Fill in the scatter gather information */
+	if (iocommand.buf_size > 0 ) {
+		int i;
+		for(i=0; i< sg_used; i++) {
+			temp64.val = pci_map_single( h->pdev, buff[i], 
+					buff_size[i], 
+					PCI_DMA_BIDIRECTIONAL);
+
+			c->SG[i].Addr.lower = temp64.val32.lower;
+			c->SG[i].Addr.upper = temp64.val32.upper;
+			c->SG[i].Len = buff_size[i];
+			c->SG[i].Ext = 0;  /* we are not chaining */
+		}
+	}
+	c->waiting = &wait;
+	/* Put the request on the tail of the request queue */
+	spin_lock_irqsave(&io_request_lock, flags);
+	addQ(&h->reqQ, c);
+	h->Qdepth++;
+	start_io(h);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	wait_for_completion(&wait);
+	/* unlock the buffers from DMA */
+	for(i=0; i< sg_used; i++) {
+		temp64.val32.lower = c->SG[i].Addr.lower;
+		temp64.val32.upper = c->SG[i].Addr.upper;
+		pci_unmap_single( h->pdev, (dma_addr_t) temp64.val,
+				buff_size[i], PCI_DMA_BIDIRECTIONAL);
+	}
+	/* Copy the error information out */
+		iocommand.error_info = *(c->err_info);
+		if (copy_to_user((void *) arg, &iocommand, 
+					sizeof( IOCTL_Command_struct) ) ) {
+				cmd_free(h, c, 0);
+				status = -EFAULT;
+				goto cleanup1;
+		}
+		if (iocommand.Request.Type.Direction == XFER_READ) {
+		/* Copy the data out of the buffer we created */
+			BYTE *ptr = (BYTE  *) iocommand.buf;
+	        	for(i=0; i< sg_used; i++) {
+				if (copy_to_user(ptr, buff[i], buff_size[i])) {
+					cmd_free(h, c, 0);
+					status = -EFAULT;
+					goto cleanup1;
+
+				}
+				ptr += buff_size[i];
+			}
+		}
+		cmd_free(h, c, 0);
+		status = 0;
+		
+
+cleanup1:
+		for(i=0; i< sg_used; i++) {
+			if (buff[i] != NULL)
+				kfree(buff[i]);
+		}
+		return status;
+	}
 	default:
 		return -EBADRQC;
 	}
@@ -837,6 +1037,642 @@
 #endif /* CCISS_DEBUG */ 
 	return revalidate_logvol(dev, 0);
 }
+static int deregister_disk(int ctlr, int logvol)
+{
+	unsigned long flags;
+	struct gendisk *gdev = &(hba[ctlr]->gendisk);
+	ctlr_info_t  *h = hba[ctlr];
+	int start, max_p, i;
+
+	if (!capable(CAP_SYS_RAWIO))
+		return -EPERM;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	/* make sure logical volume is NOT is use */
+	if (h->drv[logvol].usage_count > 1 || h->busy_configuring) {
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return -EBUSY;
+	}
+	h->busy_configuring = 1;
+	spin_unlock_irqrestore(&io_request_lock, flags);
+
+	/* invalidate the devices and deregister the disk */
+	max_p = gdev->max_p;
+	start = logvol << gdev->minor_shift;
+	for (i=max_p-1; i>=0; i--) {
+		int minor = start+i;
+		/* printk("invalidating( %d %d)\n", ctlr, minor); */
+		invalidate_device(MKDEV(MAJOR_NR+ctlr, minor), 1);
+		/* so open will now fail */
+		h->sizes[minor] = 0;
+		/* so it will no longer appear in /proc/partitions */
+		gdev->part[minor].start_sect = 0;
+		gdev->part[minor].nr_sects = 0;
+	}
+	/* check to see if it was the last disk */
+	if (logvol == h->highest_lun) {
+		/* if so, find the new hightest lun */
+		int i, newhighest =-1;
+		for(i=0; i<h->highest_lun; i++) {
+			/* if the disk has size > 0, it is available */
+			if (h->sizes[i << gdev->minor_shift] != 0)
+				newhighest = i;
+		}
+		h->highest_lun = newhighest;
+
+	}
+	--h->num_luns;
+	gdev->nr_real = h->highest_lun+1;
+	/* zero out the disk size info */
+	h->drv[logvol].nr_blocks = 0;
+	h->drv[logvol].block_size = 0;
+	h->drv[logvol].cylinders = 0;
+	h->drv[logvol].LunID = 0;
+	h->busy_configuring = 0;
+	return 0;
+}
+static int sendcmd_withirq(__u8	cmd,
+	int	ctlr,
+	void	*buff,
+	size_t	size,
+	unsigned int use_unit_num,
+	unsigned int log_unit,
+	__u8	page_code )
+{
+	ctlr_info_t *h = hba[ctlr];
+	CommandList_struct *c;
+	u64bit	buff_dma_handle;
+	unsigned long flags;
+	int return_status = IO_OK;
+	DECLARE_COMPLETION(wait);
+
+	if ((c = cmd_alloc(h , 0)) == NULL)
+		return -ENOMEM;
+	c->cmd_type = CMD_IOCTL_PEND;
+	/* Fill in Command Header */
+	c->Header.ReplyQueue = 0;  /* unused in simple mode */
+	if (buff != NULL) { 	/* buffer to fill */
+		c->Header.SGList = 1;
+		c->Header.SGTotal= 1;
+	} else {
+		/* no buffers to fill */
+		c->Header.SGList = 0;
+		c->Header.SGTotal= 0;
+	}
+	c->Header.Tag.lower = c->busaddr;  /* tag is phys addr of cmd */
+	/* Fill in Request block */
+	switch (cmd) {
+		case  CISS_INQUIRY:
+			/* If the logical unit number is 0 then, this is going
+				to controller so It's a physical command
+				mode = 0 target = 0.
+				So we have nothing to write.
+				Otherwise
+				mode = 1  target = LUNID
+			*/
+			if (use_unit_num != 0) {
+				c->Header.LUN.LogDev.VolId =
+					hba[ctlr]->drv[log_unit].LunID;
+				c->Header.LUN.LogDev.Mode = 1;
+			}
+			if (page_code != 0) {
+				c->Request.CDB[1] = 0x01;
+				c->Request.CDB[2] = page_code;
+			}
+			c->Request.CDBLen = 6;
+			c->Request.Type.Type =  TYPE_CMD;
+			c->Request.Type.Attribute = ATTR_SIMPLE;
+			c->Request.Type.Direction = XFER_READ; /* Read */
+			c->Request.Timeout = 0; /* Don't time out */
+			c->Request.CDB[0] =  CISS_INQUIRY;
+			c->Request.CDB[4] = size  & 0xFF;
+		break;
+		case CISS_REPORT_LOG:
+			/* Talking to controller so It's a physical command
+				mode = 00 target = 0.
+				So we have nothing to write.
+			*/
+			c->Request.CDBLen = 12;
+			c->Request.Type.Type =  TYPE_CMD;
+			c->Request.Type.Attribute = ATTR_SIMPLE;
+			c->Request.Type.Direction = XFER_READ; /* Read */
+			c->Request.Timeout = 0; /* Don't time out */
+			c->Request.CDB[0] = CISS_REPORT_LOG;
+			c->Request.CDB[6] = (size >> 24) & 0xFF;  /* MSB */
+			c->Request.CDB[7] = (size >> 16) & 0xFF;
+			c->Request.CDB[8] = (size >> 8) & 0xFF;
+			c->Request.CDB[9] = size & 0xFF;
+		break;
+		case CCISS_READ_CAPACITY:
+			c->Header.LUN.LogDev.VolId=
+				hba[ctlr]->drv[log_unit].LunID;
+			c->Header.LUN.LogDev.Mode = 1;
+			c->Request.CDBLen = 10;
+			c->Request.Type.Type =  TYPE_CMD; /* It is a command. */
+			c->Request.Type.Attribute = ATTR_SIMPLE;
+			c->Request.Type.Direction = XFER_READ; /* Read */
+			c->Request.Timeout = 0; /* Don't time out */
+			c->Request.CDB[0] = CCISS_READ_CAPACITY;
+		break;
+		default:
+			printk(KERN_WARNING
+				"cciss:  Unknown Command 0x%x sent attempted\n",				cmd);
+			cmd_free(h, c, 1);
+			return IO_ERROR;
+	};
+
+	/* Fill in the scatter gather information */
+	if (size > 0) {
+		buff_dma_handle.val = (__u64) pci_map_single( h->pdev,
+			buff, size, PCI_DMA_BIDIRECTIONAL);
+		c->SG[0].Addr.lower = buff_dma_handle.val32.lower;
+		c->SG[0].Addr.upper = buff_dma_handle.val32.upper;
+		c->SG[0].Len = size;
+		c->SG[0].Ext = 0;  /* we are not chaining */
+	}
+
+resend_cmd2:
+	c->waiting = &wait;
+	/* Put the request on the tail of the queue and send it */
+	spin_lock_irqsave(&io_request_lock, flags);
+	addQ(&h->reqQ, c);
+	h->Qdepth++;
+	start_io(h);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+
+	wait_for_completion(&wait);
+
+
+	if (c->err_info->CommandStatus != 0) {
+		/* an error has occurred */
+		switch (c->err_info->CommandStatus) {
+			case CMD_TARGET_STATUS:
+				printk(KERN_WARNING "cciss: cmd %p has "
+					" completed with errors\n", c);
+				if (c->err_info->ScsiStatus) {
+					printk(KERN_WARNING "cciss: cmd %p "
+					"has SCSI Status = %x\n", c,
+						c->err_info->ScsiStatus);
+				}
+			break;
+			case CMD_DATA_UNDERRUN:
+			case CMD_DATA_OVERRUN:
+			/* expected for inquire and report lun commands */
+			break;
+			case CMD_INVALID:
+				printk(KERN_WARNING "cciss: cmd %p is "
+					"reported invalid\n", c);
+				return_status = IO_ERROR;
+			break;
+			case CMD_PROTOCOL_ERR:
+				printk(KERN_WARNING "cciss: cmd %p has "
+					"protocol error \n", c);
+				return_status = IO_ERROR;
+			break;
+			case CMD_HARDWARE_ERR:
+				printk(KERN_WARNING "cciss: cmd %p had "
+					" hardware error\n", c);
+				return_status = IO_ERROR;
+				break;
+			case CMD_CONNECTION_LOST:
+				printk(KERN_WARNING "cciss: cmd %p had "
+					"connection lost\n", c);
+				return_status = IO_ERROR;
+			break;
+			case CMD_ABORTED:
+				printk(KERN_WARNING "cciss: cmd %p was "
+					"aborted\n", c);
+				return_status = IO_ERROR;
+			break;
+			case CMD_ABORT_FAILED:
+				printk(KERN_WARNING "cciss: cmd %p reports "
+					"abort failed\n", c);
+				return_status = IO_ERROR;
+			break;
+			case CMD_UNSOLICITED_ABORT:
+				printk(KERN_WARNING "cciss: cmd %p aborted "
+					"do to an unsolicited abort\n", c);
+				if (c->retry_count < MAX_CMD_RETRIES) 
+				{ 
+					printk(KERN_WARNING "retrying cmd\n"); 
+					c->retry_count++; 
+					/* erase the old error */ 
+					/* information */ 
+					memset(c->err_info, 0, 
+						sizeof(ErrorInfo_struct)); 
+					return_status = IO_OK;
+					INIT_COMPLETION(wait);
+					goto resend_cmd2;
+					
+				}
+				return_status = IO_ERROR;
+			break;
+			default:
+				printk(KERN_WARNING "cciss: cmd %p returned "
+					"unknown status %x\n", c,
+						c->err_info->CommandStatus);
+				return_status = IO_ERROR;
+		}
+	}
+
+	/* unlock the buffers from DMA */
+	pci_unmap_single( h->pdev, (dma_addr_t) buff_dma_handle.val,
+			size, PCI_DMA_BIDIRECTIONAL);
+	cmd_free(h, c, 0);
+	return return_status;
+}
+static int register_new_disk(int ctlr, int opened_vol, __u64 requested_lun)
+{
+	struct gendisk *gdev = &(hba[ctlr]->gendisk);
+	ctlr_info_t  *h = hba[ctlr];
+	int start, max_p, i;
+	int num_luns;
+	int logvol;
+	int new_lun_found = 0;
+	int new_lun_index = 0;
+	int free_index_found = 0;
+	int free_index = 0;
+	ReportLunData_struct *ld_buff;
+	ReadCapdata_struct *size_buff;
+	InquiryData_struct *inq_buff;
+	int return_code;
+	int listlength = 0;
+	__u32 lunid = 0;
+	unsigned int block_size;
+	unsigned int total_size;
+	unsigned long flags;
+	int req_lunid = (int) (requested_lun & (__u64) 0xffffffff);
+
+	if (!capable(CAP_SYS_RAWIO))
+		return -EPERM;
+	/* if we have no space in our disk array left to add anything */
+	spin_lock_irqsave(&io_request_lock, flags);
+	if (h->num_luns >= CISS_MAX_LUN) {
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return -EINVAL;
+	}
+	if (h->busy_configuring) {
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return -EBUSY;
+	}
+	h->busy_configuring = 1;
+	spin_unlock_irqrestore(&io_request_lock, flags);
+
+	ld_buff = kmalloc(sizeof(ReportLunData_struct), GFP_KERNEL);
+	if (ld_buff == NULL) {
+		printk(KERN_ERR "cciss: out of memory\n");
+		h->busy_configuring = 0;
+		return -ENOMEM;
+	}
+	memset(ld_buff, 0, sizeof(ReportLunData_struct));
+	size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL);
+	if (size_buff == NULL) {
+		printk(KERN_ERR "cciss: out of memory\n");
+		kfree(ld_buff);
+		h->busy_configuring = 0;
+		return -ENOMEM;
+	}
+	inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL);
+	if (inq_buff == NULL) {
+		printk(KERN_ERR "cciss: out of memory\n");
+		kfree(ld_buff);
+		kfree(size_buff);
+		h->busy_configuring = 0;
+		return -ENOMEM;
+	}
+
+	return_code = sendcmd_withirq(CISS_REPORT_LOG, ctlr, ld_buff,
+			sizeof(ReportLunData_struct), 0, 0, 0 );
+
+	if (return_code == IO_OK) {
+		/* printk("LUN Data\n--------------------------\n"); */
+		listlength |= (0xff &
+			(unsigned int)(ld_buff->LUNListLength[0])) << 24;
+		listlength |= (0xff &
+			(unsigned int)(ld_buff->LUNListLength[1])) << 16;
+		listlength |= (0xff &
+			(unsigned int)(ld_buff->LUNListLength[2])) << 8;
+		listlength |= 0xff &
+			(unsigned int)(ld_buff->LUNListLength[3]);
+	} else {
+		/* reading number of logical volumes failed */
+		printk(KERN_WARNING "cciss: report logical volume"
+			" command failed\n");
+		listlength = 0;
+		h->busy_configuring = 0;
+		return -1;
+	}
+	num_luns = listlength / 8; /* 8 bytes pre entry */
+	if (num_luns > CISS_MAX_LUN)
+		num_luns = CISS_MAX_LUN;
+
+#ifdef CCISS_DEBUG
+	printk(KERN_DEBUG "Length = %x %x %x %x = %d\n", ld_buff->LUNListLength[0],
+		ld_buff->LUNListLength[1], ld_buff->LUNListLength[2],
+		ld_buff->LUNListLength[3],  num_luns);
+#endif
+	for(i=0; i<  num_luns; i++) {
+		int j;
+		int lunID_found = 0;
+
+		lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3])) << 24;
+		lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2])) << 16;
+		lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1])) << 8;
+		lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]);
+
+		/* check to see if this is a new lun */
+		for(j=0; j <= h->highest_lun; j++) {
+#ifdef CCISS_DEBUG
+			printk("Checking %d %x against %x\n", j,h->drv[j].LunID,
+						lunid);
+#endif /* CCISS_DEBUG */
+			if (h->drv[j].LunID == lunid) {
+				lunID_found = 1;
+				break;
+			}
+
+		}
+		if (lunID_found == 1)
+			continue;
+		else {	/* new lun found */
+			
+#ifdef CCISS_DEBUG
+			printk("new lun found at %d\n", i);
+#endif /* CCISS_DEBUG */
+			if (req_lunid)  /* we are looking for a specific lun */
+			{
+				if (lunid != req_lunid)
+				{
+#ifdef CCISS_DEBUG
+					printk("new lun %x is not %x\n",
+							lunid, req_lunid);
+#endif /* CCISS_DEBUG */
+					continue;
+				}
+			}
+			new_lun_index = i;
+			new_lun_found = 1;
+			break;
+		}
+	}
+	if (!new_lun_found) {
+		printk(KERN_DEBUG "cciss:  New Logical Volume not found\n");
+		h->busy_configuring = 0;
+		return -1;
+	}
+	/* Now find the free index 	*/
+	for(i=0; i <CISS_MAX_LUN; i++) {
+#ifdef CCISS_DEBUG
+		printk("Checking Index %d\n", i);
+#endif /* CCISS_DEBUG */
+		if (hba[ctlr]->drv[i].LunID == 0) {
+#ifdef CCISS_DEBUG
+			printk("free index found at %d\n", i);
+#endif /* CCISS_DEBUG */
+			free_index_found = 1;
+			free_index = i;
+			break;
+		}
+	}
+	if (!free_index_found) {
+		printk(KERN_WARNING "cciss: unable to find free slot for disk\n");
+		h->busy_configuring = 0;
+		return -1;
+	}
+
+	logvol = free_index;
+	hba[ctlr]->drv[logvol].LunID = lunid;
+		/* there could be gaps in lun numbers, track hightest */
+	if (hba[ctlr]->highest_lun < logvol)
+		hba[ctlr]->highest_lun = logvol;
+
+	memset(size_buff, 0, sizeof(ReadCapdata_struct));
+	return_code = sendcmd_withirq(CCISS_READ_CAPACITY, ctlr,
+			size_buff, sizeof(ReadCapdata_struct), 1,
+			logvol, 0 );
+	if (return_code == IO_OK) {
+		total_size = (0xff &
+			(unsigned int) size_buff->total_size[0]) << 24;
+		total_size |= (0xff &
+			(unsigned int) size_buff->total_size[1]) << 16;
+		total_size |= (0xff &
+			(unsigned int) size_buff->total_size[2]) << 8;
+		total_size |= (0xff &
+			(unsigned int) size_buff->total_size[3]);
+		total_size++; /* command returns highest block address */
+
+		block_size = (0xff &
+			(unsigned int) size_buff->block_size[0]) << 24;
+		block_size |= (0xff &
+			(unsigned int) size_buff->block_size[1]) << 16;
+		block_size |= (0xff &
+			(unsigned int) size_buff->block_size[2]) << 8;
+		block_size |= (0xff &
+			(unsigned int) size_buff->block_size[3]);
+	} else {
+		/* read capacity command failed */
+		printk(KERN_WARNING "cciss: read capacity failed\n");
+		total_size = 0;
+		block_size = BLOCK_SIZE;
+	}
+	printk(KERN_INFO "      blocks= %d block_size= %d\n",
+					total_size, block_size);
+	/* Execute the command to read the disk geometry */
+	memset(inq_buff, 0, sizeof(InquiryData_struct));
+	return_code = sendcmd_withirq(CISS_INQUIRY, ctlr, inq_buff,
+		sizeof(InquiryData_struct), 1, logvol ,0xC1 );
+	if (return_code == IO_OK) {
+		if (inq_buff->data_byte[8] == 0xFF) {
+			printk(KERN_WARNING
+			"cciss: reading geometry failed, "
+			"volume does not support reading geometry\n");
+
+			hba[ctlr]->drv[logvol].block_size = block_size;
+			hba[ctlr]->drv[logvol].nr_blocks = total_size;
+			hba[ctlr]->drv[logvol].heads = 255;
+			hba[ctlr]->drv[logvol].sectors = 32; /* secs/trk */
+			hba[ctlr]->drv[logvol].cylinders = total_size / 255 /32;
+			hba[ctlr]->drv[logvol].raid_level = RAID_UNKNOWN;
+		} else {
+			hba[ctlr]->drv[logvol].block_size = block_size;
+			hba[ctlr]->drv[logvol].nr_blocks = total_size;
+			hba[ctlr]->drv[logvol].heads = inq_buff->data_byte[6];
+			hba[ctlr]->drv[logvol].sectors = inq_buff->data_byte[7];
+			hba[ctlr]->drv[logvol].cylinders =
+				(inq_buff->data_byte[4] & 0xff) << 8;
+			hba[ctlr]->drv[logvol].cylinders +=
+				inq_buff->data_byte[5];
+			hba[ctlr]->drv[logvol].raid_level = 
+				inq_buff->data_byte[8];
+		}
+	} else {
+		/* Get geometry failed */
+		printk(KERN_WARNING "cciss: reading geometry failed, "
+			"continuing with default geometry\n");
+
+		hba[ctlr]->drv[logvol].block_size = block_size;
+		hba[ctlr]->drv[logvol].nr_blocks = total_size;
+		hba[ctlr]->drv[logvol].heads = 255;
+		hba[ctlr]->drv[logvol].sectors = 32; /* Sectors per track */
+		hba[ctlr]->drv[logvol].cylinders = total_size / 255 / 32;
+	}
+	if (hba[ctlr]->drv[logvol].raid_level > 5)
+		hba[ctlr]->drv[logvol].raid_level = RAID_UNKNOWN;
+	printk(KERN_INFO "      heads= %d, sectors= %d, cylinders= %d RAID %s\n\n",
+		hba[ctlr]->drv[logvol].heads,
+		hba[ctlr]->drv[logvol].sectors,
+		hba[ctlr]->drv[logvol].cylinders, 
+		raid_label[hba[ctlr]->drv[logvol].raid_level]);
+
+	/* special case for c?d0, which may be opened even when
+	   it does not "exist".  In that case, don't mess with usage count.
+	   Also, /dev/c1d1 could be used to re-add c0d0 so we can't just 
+	   check whether logvol == 0, must check logvol != opened_vol */
+	if (logvol != opened_vol)
+		hba[ctlr]->drv[logvol].usage_count = 0;
+
+	max_p = gdev->max_p;
+	start = logvol<< gdev->minor_shift;
+	hba[ctlr]->hd[start].nr_sects = total_size;
+	hba[ctlr]->sizes[start] = total_size;
+
+	for(i=max_p-1; i>=0; i--) {
+		int minor = start+i;
+		invalidate_device(MKDEV(MAJOR_NR + ctlr, minor), 1);
+		gdev->part[minor].start_sect = 0;
+		gdev->part[minor].nr_sects = 0;
+
+		/* reset the blocksize so we can read the partition table */
+		blksize_size[MAJOR_NR+ctlr][minor] = block_size;
+		hba[ctlr]->hardsizes[minor] = block_size;
+	}
+
+	++hba[ctlr]->num_luns;
+	gdev->nr_real = hba[ctlr]->highest_lun + 1;
+	/* setup partitions per disk */
+	grok_partitions(gdev, logvol, MAX_PART,
+			hba[ctlr]->drv[logvol].nr_blocks);
+	kfree(ld_buff);
+	kfree(size_buff);
+	kfree(inq_buff);
+	h->busy_configuring = 0;
+	return logvol;
+}
+
+static int cciss_rescan_disk(int ctlr, int logvol)
+{
+	struct gendisk *gdev = &(hba[ctlr]->gendisk);
+	int start, max_p, i;
+	ReadCapdata_struct *size_buff;
+	InquiryData_struct *inq_buff;
+	int return_code;
+	unsigned int block_size;
+	unsigned int total_size;
+
+	if (!capable(CAP_SYS_RAWIO))
+		return -EPERM;
+	if (hba[ctlr]->sizes[logvol << NWD_SHIFT] != 0) {
+		/* disk is possible on line, return just a warning */
+		return 1;
+	}
+	size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL);
+	if (size_buff == NULL) {
+		printk(KERN_ERR "cciss: out of memory\n");
+		return -1;
+	}
+	inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL);
+	if (inq_buff == NULL) {
+		printk(KERN_ERR "cciss: out of memory\n");
+		kfree(size_buff);
+		return -1;
+	}
+	memset(size_buff, 0, sizeof(ReadCapdata_struct));
+	return_code = sendcmd_withirq(CCISS_READ_CAPACITY, ctlr, size_buff,
+				sizeof( ReadCapdata_struct), 1, logvol, 0 );
+	if (return_code == IO_OK) {
+		total_size = (0xff &
+			(unsigned int)(size_buff->total_size[0])) << 24;
+		total_size |= (0xff &
+				(unsigned int)(size_buff->total_size[1])) << 16;
+		total_size |= (0xff &
+				(unsigned int)(size_buff->total_size[2])) << 8;
+		total_size |= (0xff & (unsigned int)
+				(size_buff->total_size[3]));
+		total_size++; /* command returns highest block address */
+
+		block_size = (0xff &
+				(unsigned int)(size_buff->block_size[0])) << 24;
+		block_size |= (0xff &
+				(unsigned int)(size_buff->block_size[1])) << 16;
+		block_size |= (0xff &
+				(unsigned int)(size_buff->block_size[2])) << 8;
+		block_size |= (0xff &
+				(unsigned int)(size_buff->block_size[3]));
+	} else { /* read capacity command failed */
+		printk(KERN_WARNING "cciss: read capacity failed\n");
+		total_size = block_size = 0;
+	}
+	printk(KERN_INFO "      blocks= %d block_size= %d\n",
+					total_size, block_size);
+	/* Execute the command to read the disk geometry */
+	memset(inq_buff, 0, sizeof(InquiryData_struct));
+	return_code = sendcmd_withirq(CISS_INQUIRY, ctlr, inq_buff,
+			sizeof(InquiryData_struct), 1, logvol ,0xC1 );
+	if (return_code == IO_OK) {
+		if (inq_buff->data_byte[8] == 0xFF) {
+			printk(KERN_WARNING "cciss: reading geometry failed, "
+				"volume does not support reading geometry\n");
+
+			hba[ctlr]->drv[logvol].nr_blocks = total_size;
+			hba[ctlr]->drv[logvol].heads = 255;
+			hba[ctlr]->drv[logvol].sectors = 32; /* Sectors/track */
+			hba[ctlr]->drv[logvol].cylinders = total_size / 255 /32;
+		} else {
+			hba[ctlr]->drv[logvol].nr_blocks = total_size;
+			hba[ctlr]->drv[logvol].heads = inq_buff->data_byte[6];
+			hba[ctlr]->drv[logvol].sectors = inq_buff->data_byte[7];
+			hba[ctlr]->drv[logvol].cylinders =
+				(inq_buff->data_byte[4] & 0xff) << 8;
+			hba[ctlr]->drv[logvol].cylinders +=
+				inq_buff->data_byte[5];
+		}
+	} else { /* Get geometry failed */
+		printk(KERN_WARNING "cciss: reading geometry failed, "
+				"continuing with default geometry\n");
+
+		hba[ctlr]->drv[logvol].nr_blocks = total_size;
+		hba[ctlr]->drv[logvol].heads = 255;
+		hba[ctlr]->drv[logvol].sectors = 32; /* Sectors / track */
+		hba[ctlr]->drv[logvol].cylinders = total_size / 255 /32;
+	}
+
+	printk(KERN_INFO "      heads= %d, sectors= %d, cylinders= %d \n\n", 
+		hba[ctlr]->drv[logvol].heads,
+		hba[ctlr]->drv[logvol].sectors,
+		hba[ctlr]->drv[logvol].cylinders);
+	max_p = gdev->max_p;
+	start = logvol<< gdev->minor_shift;
+	hba[ctlr]->hd[start].nr_sects = hba[ctlr]->sizes[start]= total_size;
+
+	for (i=max_p-1; i>=0; i--) {
+		int minor = start+i;
+		invalidate_device(MKDEV(MAJOR_NR + ctlr, minor), 1);
+		gdev->part[minor].start_sect = 0;
+		gdev->part[minor].nr_sects = 0;
+
+		/* reset the blocksize so we can read the partition table */
+		blksize_size[MAJOR_NR+ctlr][minor] = 1024;
+		hba[ctlr]->hardsizes[minor] = block_size;
+	}
+
+	/* setup partitions per disk */
+	grok_partitions(gdev, logvol, MAX_PART,
+			hba[ctlr]->drv[logvol].nr_blocks );
+
+	kfree(size_buff);
+	kfree(inq_buff);
+	return 0;
+}
 /*
  *   Wait polling for a command to complete.
  *   The memory mapped FIFO is polled for the completion.
@@ -844,20 +1680,21 @@
  */
 static unsigned long pollcomplete(int ctlr)
 {
-        unsigned long done;
-        int i;
+	unsigned long done;
+	int i;
 
-        /* Wait (up to 2 seconds) for a command to complete */
+	/* Wait (up to 20 seconds) for a command to complete */
 
-        for (i = 200000; i > 0; i--) {
-                done = hba[ctlr]->access.command_completed(hba[ctlr]);
-                if (done == FIFO_EMPTY) {
-                        udelay(10);     /* a short fixed delay */
-                } else
-                        return (done);
-        }
-        /* Invalid address to tell caller we ran out of time */
-        return 1;
+        for (i = 20 * HZ; i > 0; i--) {
+		done = hba[ctlr]->access.command_completed(hba[ctlr]);
+		if (done == FIFO_EMPTY) {
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			schedule_timeout(1);
+		} else
+			return done;
+	}
+	/* Invalid address to tell caller we ran out of time */
+	return 1;
 }
 /*
  * Send a command to the controller, and wait for it to complete.  
@@ -880,28 +1717,26 @@
 	unsigned long complete;
 	ctlr_info_t *info_p= hba[ctlr];
 	u64bit buff_dma_handle;
+	int status = IO_OK;
 
 	c = cmd_alloc(info_p, 1);
-	if (c == NULL)
-	{
+	if (c == NULL) {
 		printk(KERN_WARNING "cciss: unable to get memory");
-		return(IO_ERROR);
+		return IO_ERROR;
 	}
-	// Fill in Command Header 
-	c->Header.ReplyQueue = 0;  // unused in simple mode
-	if( buff != NULL) 	// buffer to fill 
-	{
+	/* Fill in Command Header */
+	c->Header.ReplyQueue = 0;  /* unused in simple mode */
+	if (buff != NULL) { 	/* buffer to fill */
 		c->Header.SGList = 1;
 		c->Header.SGTotal= 1;
-	} else	// no buffers to fill  
-	{
+	} else	{	/* no buffers to fill  */
 		c->Header.SGList = 0;
                 c->Header.SGTotal= 0;
 	}
-	c->Header.Tag.lower = c->busaddr;  // use the kernel address the cmd block for tag
-	// Fill in Request block 	
-	switch(cmd)
-	{
+	c->Header.Tag.lower = c->busaddr;  /* use the kernel address */
+					   /* the cmd block for tag */
+	/* Fill in Request block */
+	switch (cmd) {
 		case  CISS_INQUIRY:
 			/* If the logical unit number is 0 then, this is going
 				to controller so It's a physical command
@@ -912,29 +1747,27 @@
 				otherwise, if use_unit_num == 2,
 				mode = 0(periph dev addr) target = scsi3addr
 			*/
-			if(use_unit_num == 1)
-			{
+			if (use_unit_num == 1) {
 				c->Header.LUN.LogDev.VolId=
                                 	hba[ctlr]->drv[log_unit].LunID;
                         	c->Header.LUN.LogDev.Mode = 1;
 			}
-			else if (use_unit_num == 2)
-			{
+			else if (use_unit_num == 2) {
 				memcpy(c->Header.LUN.LunAddrBytes,scsi3addr,8);
-				c->Header.LUN.LogDev.Mode = 0; // phys dev addr
+				c->Header.LUN.LogDev.Mode = 0; 
+							/* phys dev addr */
 			}
 
 			/* are we trying to read a vital product page */
-			if(page_code != 0)
-			{
+			if (page_code != 0) {
 				c->Request.CDB[1] = 0x01;
 				c->Request.CDB[2] = page_code;
 			}
 			c->Request.CDBLen = 6;
-			c->Request.Type.Type =  TYPE_CMD; // It is a command. 
+			c->Request.Type.Type =  TYPE_CMD; /* It is a command. */
 			c->Request.Type.Attribute = ATTR_SIMPLE;  
-			c->Request.Type.Direction = XFER_READ; // Read 
-			c->Request.Timeout = 0; // Don't time out 
+			c->Request.Type.Direction = XFER_READ; /* Read */
+			c->Request.Timeout = 0; /* Don't time out */
 			c->Request.CDB[0] =  CISS_INQUIRY;
 			c->Request.CDB[4] = size  & 0xFF;  
 		break;
@@ -945,12 +1778,12 @@
                                 So we have nothing to write.
                         */
                         c->Request.CDBLen = 12;
-                        c->Request.Type.Type =  TYPE_CMD; // It is a command.
+                        c->Request.Type.Type =  TYPE_CMD; /* It is a command. */
                         c->Request.Type.Attribute = ATTR_SIMPLE; 
-                        c->Request.Type.Direction = XFER_READ; // Read
-                        c->Request.Timeout = 0; // Don't time out
+                        c->Request.Type.Direction = XFER_READ; /* Read */
+                        c->Request.Timeout = 0; /* Don't time out */
 			c->Request.CDB[0] = cmd;
-                        c->Request.CDB[6] = (size >> 24) & 0xFF;  //MSB
+                        c->Request.CDB[6] = (size >> 24) & 0xFF;  /* MSB */
                         c->Request.CDB[7] = (size >> 16) & 0xFF;
                         c->Request.CDB[8] = (size >> 8) & 0xFF;
                         c->Request.CDB[9] = size & 0xFF;
@@ -961,38 +1794,38 @@
 				hba[ctlr]->drv[log_unit].LunID;
 			c->Header.LUN.LogDev.Mode = 1;
 			c->Request.CDBLen = 10;
-                        c->Request.Type.Type =  TYPE_CMD; // It is a command.
+                        c->Request.Type.Type =  TYPE_CMD; /* It is a command. */
                         c->Request.Type.Attribute = ATTR_SIMPLE; 
-                        c->Request.Type.Direction = XFER_READ; // Read
-                        c->Request.Timeout = 0; // Don't time out
+                        c->Request.Type.Direction = XFER_READ; /* Read */
+                        c->Request.Timeout = 0; /* Don't time out */
                         c->Request.CDB[0] = CCISS_READ_CAPACITY;
 		break;
 		case CCISS_CACHE_FLUSH:
 			c->Request.CDBLen = 12;
-			c->Request.Type.Type =  TYPE_CMD; // It is a command.
+			c->Request.Type.Type =  TYPE_CMD; /* It is a command. */
 			c->Request.Type.Attribute = ATTR_SIMPLE;
-			c->Request.Type.Direction = XFER_WRITE; // No data
-			c->Request.Timeout = 0; // Don't time out
-			c->Request.CDB[0] = BMIC_WRITE;  // BMIC Passthru
+			c->Request.Type.Direction = XFER_WRITE; /* No data */
+			c->Request.Timeout = 0; /* Don't time out */
+			c->Request.CDB[0] = BMIC_WRITE;  /* BMIC Passthru */
 			c->Request.CDB[6] = BMIC_CACHE_FLUSH;
 		break;
 		default:
 			printk(KERN_WARNING
-				"cciss:  Unknown Command 0x%c sent attempted\n",
+				"cciss:  Unknown Command 0x%x sent attempted\n",
 				  cmd);
 			cmd_free(info_p, c, 1);
-			return(IO_ERROR);
+			return IO_ERROR;
 	};
-	// Fill in the scatter gather information
-	if (size > 0 ) 
-	{
+	/* Fill in the scatter gather information */
+	if (size > 0) {
 		buff_dma_handle.val = (__u64) pci_map_single( info_p->pdev, 
 			buff, size, PCI_DMA_BIDIRECTIONAL);
 		c->SG[0].Addr.lower = buff_dma_handle.val32.lower;
 		c->SG[0].Addr.upper = buff_dma_handle.val32.upper;
 		c->SG[0].Len = size;
-		c->SG[0].Ext = 0;  // we are not chaining
+		c->SG[0].Ext = 0;  /* we are not chaining */
 	}
+resend_cmd1:
 	/*
          * Disable interrupt
          */
@@ -1003,11 +1836,9 @@
 	
 	/* Make sure there is room in the command FIFO */
         /* Actually it should be completely empty at this time. */
-        for (i = 200000; i > 0; i--) 
-	{
+        for (i = 200000; i > 0; i--) {
 		/* if fifo isn't full go */
-                if (!(info_p->access.fifo_full(info_p))) 
-		{
+                if (!(info_p->access.fifo_full(info_p))) {
 			
                         break;
                 }
@@ -1025,13 +1856,9 @@
 	printk(KERN_DEBUG "cciss: command completed\n");
 #endif /* CCISS_DEBUG */
 
-	/* unlock the data buffer from DMA */
-	pci_unmap_single(info_p->pdev, (dma_addr_t) buff_dma_handle.val,
-                                size, PCI_DMA_BIDIRECTIONAL);
 	if (complete != 1) {
 		if ( (complete & CISS_ERROR_BIT)
-		     && (complete & ~CISS_ERROR_BIT) == c->busaddr)
-		     {
+		     && (complete & ~CISS_ERROR_BIT) == c->busaddr) {
 			/* if data overrun or underun on Report command 
 				ignore it 
 			*/
@@ -1042,41 +1869,64 @@
 					CMD_DATA_OVERRUN) || 
 				 (c->err_info->CommandStatus == 
 					CMD_DATA_UNDERRUN)
-			 	))
-			{
+			 	)) {
 				complete = c->busaddr;
-			} else
-			{
-				printk(KERN_WARNING "ciss ciss%d: sendcmd"
+			} else {
+				if (c->err_info->CommandStatus == 
+						CMD_UNSOLICITED_ABORT) {
+					printk(KERN_WARNING "cciss: "
+						"cmd %p aborted do "
+					"to an unsolicited abort \n", c); 
+					if (c->retry_count < MAX_CMD_RETRIES) {
+						printk(KERN_WARNING
+						   "retrying cmd\n");
+						c->retry_count++;
+						/* erase the old error */
+						/* information */
+						memset(c->err_info, 0, 
+						   sizeof(ErrorInfo_struct));
+						goto resend_cmd1;
+					} else {
+						printk(KERN_WARNING
+						   "retried to many times\n");
+						status = IO_ERROR;
+						goto cleanup1;
+					}
+				}
+				printk(KERN_WARNING "cciss cciss%d: sendcmd"
 				" Error %x \n", ctlr, 
 					c->err_info->CommandStatus); 
-				printk(KERN_WARNING "ciss ciss%d: sendcmd"
+				printk(KERN_WARNING "cciss cciss%d: sendcmd"
 				" offensive info\n"
 				"  size %x\n   num %x   value %x\n", ctlr,
 				  c->err_info->MoreErrInfo.Invalid_Cmd.offense_size,
 				  c->err_info->MoreErrInfo.Invalid_Cmd.offense_num,
 				  c->err_info->MoreErrInfo.Invalid_Cmd.offense_value);
-				cmd_free(info_p,c, 1);
-				return(IO_ERROR);
+				status = IO_ERROR;
+				goto cleanup1;
 			}
 		}
                 if (complete != c->busaddr) {
                         printk( KERN_WARNING "cciss cciss%d: SendCmd "
                       "Invalid command list address returned! (%lx)\n",
                                 ctlr, complete);
-                        cmd_free(info_p, c, 1);
-                        return (IO_ERROR);
+                        status = IO_ERROR;
+			goto cleanup1;
                 }
         } else {
                 printk( KERN_WARNING
                         "cciss cciss%d: SendCmd Timeout out, "
                         "No command list address returned!\n",
                         ctlr);
-                cmd_free(info_p, c, 1);
-                return (IO_ERROR);
+                status = IO_ERROR;
         }
+		
+cleanup1:	
+	/* unlock the data buffer from DMA */
+	pci_unmap_single(info_p->pdev, (dma_addr_t) buff_dma_handle.val,
+                                size, PCI_DMA_BIDIRECTIONAL);
 	cmd_free(info_p, c, 1);
-        return (IO_OK);
+        return status;
 } 
 /*
  * Map (physical) PCI mem into (virtual) kernel space
@@ -1127,11 +1977,9 @@
 {
 	CommandList_struct *c;
 	
-	while(( c = h->reqQ) != NULL )
-	{
+	while(( c = h->reqQ) != NULL ) {
 		/* can't do anything if fifo is full */
-		if ((h->access.fifo_full(h)))
-		{
+		if ((h->access.fifo_full(h))) {
 			printk(KERN_WARNING "cciss: fifo full \n");
 			return;
 		}
@@ -1151,8 +1999,7 @@
 {
 	struct buffer_head *xbh;
 	
-	while(bh)
-	{
+	while(bh) {
 		xbh = bh->b_reqnext; 
 		bh->b_reqnext = NULL; 
 		blk_finished_io(bh->b_size >> 9);
@@ -1160,39 +2007,44 @@
 		bh = xbh;
 	}
 } 
+/* This code assumes io_request_lock is already held */
+/* Zeros out the error record and then resends the command back */
+/* to the controller */ 
+static inline void resend_cciss_cmd( ctlr_info_t *h, CommandList_struct *c)
+{
+	/* erase the old error information */
+	memset(c->err_info, 0, sizeof(ErrorInfo_struct));
+
+	/* add it to software queue and then send it to the controller */
+	addQ(&(h->reqQ),c);
+	h->Qdepth++;
+	if (h->Qdepth > h->maxQsinceinit)
+		h->maxQsinceinit = h->Qdepth; 
+
+	start_io(h);
+}
 /* checks the status of the job and calls complete buffers to mark all 
  * buffers for the completed job. 
  */ 
-static inline void complete_command( CommandList_struct *cmd, int timeout)
+static inline void complete_command( ctlr_info_t *h, CommandList_struct *cmd, 
+		int timeout)
 {
 	int status = 1;
+	int retry_cmd = 0;
 	int i, ddir;
 	u64bit temp64;
 		
 	if (timeout)
 		status = 0; 
-	/* unmap the DMA mapping for all the scatter gather elements */
-	if (cmd->Request.Type.Direction == XFER_READ)
-		ddir = PCI_DMA_FROMDEVICE;
-	else
-		ddir = PCI_DMA_TODEVICE;
-	for(i=0; i<cmd->Header.SGList; i++)
-	{
-		temp64.val32.lower = cmd->SG[i].Addr.lower;
-		temp64.val32.upper = cmd->SG[i].Addr.upper;
-		pci_unmap_page(hba[cmd->ctlr]->pdev,
-			temp64.val, cmd->SG[i].Len, ddir);
-	}
 
-	if(cmd->err_info->CommandStatus != 0) 
-	{ /* an error has occurred */ 
-		switch(cmd->err_info->CommandStatus)
-		{
+	if (cmd->err_info->CommandStatus != 0) { 
+		/* an error has occurred */ 
+		switch (cmd->err_info->CommandStatus) {
 			unsigned char sense_key;
 			case CMD_TARGET_STATUS:
 				status = 0;
 			
-				if( cmd->err_info->ScsiStatus == 0x02) {
+				if (cmd->err_info->ScsiStatus == 0x02) {
 					printk(KERN_WARNING "cciss: cmd %p "
 						"has CHECK CONDITION,"
 						" sense key = 0x%x\n", cmd,
@@ -1200,10 +2052,9 @@
 					/* check the sense key */
 					sense_key = 0xf & 
 						cmd->err_info->SenseInfo[2];
-					/* no status or recovered error */
-					if ((sense_key == 0x0) ||
-						(sense_key == 0x1))
-							status = 1;
+					/* recovered error */
+					if ( sense_key == 0x1)
+						status = 1;
 				} else {
 					printk(KERN_WARNING "cciss: cmd %p "
 						"has SCSI Status 0x%x\n",
@@ -1251,8 +2102,18 @@
 				status=0;
 			break;
 			case CMD_UNSOLICITED_ABORT:
-				printk(KERN_WARNING "cciss: cmd %p aborted "
-					"do to an unsolicited abort\n", cmd);
+				printk(KERN_WARNING "cciss: cmd %p aborted do "
+					"to an unsolicited abort \n",
+				       	cmd);
+				if (cmd->retry_count < MAX_CMD_RETRIES) {
+					retry_cmd=1;
+					printk(KERN_WARNING
+						"retrying cmd\n");
+					cmd->retry_count++;
+				} else {
+					printk(KERN_WARNING
+					"retried to many times\n");
+				}
 				status=0;
 			break;
 			case CMD_TIMEOUT:
@@ -1267,12 +2128,29 @@
 				status=0;
 		}
 	}
+	/* We need to return this command */
+	if (retry_cmd) {
+		resend_cciss_cmd(h,cmd);
+		return;
+	}	
+	/* command did not need to be retried */
+	/* unmap the DMA mapping for all the scatter gather elements */
+	if (cmd->Request.Type.Direction == XFER_READ)
+		ddir = PCI_DMA_FROMDEVICE;
+	else
+		ddir = PCI_DMA_TODEVICE;
+	for(i=0; i<cmd->Header.SGList; i++) {
+		temp64.val32.lower = cmd->SG[i].Addr.lower;
+		temp64.val32.upper = cmd->SG[i].Addr.upper;
+		pci_unmap_page(hba[cmd->ctlr]->pdev,
+			temp64.val, cmd->SG[i].Len, ddir);
+	}
 	complete_buffers(cmd->rq->bh, status);
-
 #ifdef CCISS_DEBUG
 	printk("Done with %p\n", cmd->rq);
 #endif /* CCISS_DEBUG */ 
 	end_that_request_last(cmd->rq);
+	cmd_free(h,cmd,1);
 }
 
 
@@ -1289,7 +2167,7 @@
 static int cpq_back_merge_fn(request_queue_t *q, struct request *rq,
                              struct buffer_head *bh, int max_segments)
 {
-	if (blk_seg_merge_ok(rq->bhtail, bh))
+	if (blk_seg_merge_ok(rq->bhtail, bh))	
                 return 1;
         return cpq_new_segment(q, rq, max_segments);
 }
@@ -1347,8 +2225,7 @@
 	if (creq->nr_segments > MAXSGENTRIES)
                 BUG();
 
-        if (h->ctlr != MAJOR(creq->rq_dev)-MAJOR_NR )
-        {
+        if (h->ctlr != MAJOR(creq->rq_dev)-MAJOR_NR ) {
                 printk(KERN_WARNING "doreq cmd for %d, %x at %p\n",
                                 h->ctlr, creq->rq_dev, creq);
                 blkdev_dequeue_request(creq);
@@ -1370,34 +2247,33 @@
 	
 	/* fill in the request */ 
 	log_unit = MINOR(creq->rq_dev) >> NWD_SHIFT; 
-	c->Header.ReplyQueue = 0;  // unused in simple mode
-	c->Header.Tag.lower = c->busaddr;  // use the physical address the cmd block for tag
+	c->Header.ReplyQueue = 0;  /* unused in simple mode */
+	c->Header.Tag.lower = c->busaddr;  /* use the physical address */
+					/* the cmd block for tag */
 	c->Header.LUN.LogDev.VolId= hba[h->ctlr]->drv[log_unit].LunID;
 	c->Header.LUN.LogDev.Mode = 1;
-	c->Request.CDBLen = 10; // 12 byte commands not in FW yet;
-	c->Request.Type.Type =  TYPE_CMD; // It is a command. 
+	c->Request.CDBLen = 10; /* 12 byte commands not in FW yet. */
+	c->Request.Type.Type =  TYPE_CMD; /* It is a command.  */
 	c->Request.Type.Attribute = ATTR_SIMPLE; 
 	c->Request.Type.Direction = 
 		(creq->cmd == READ) ? XFER_READ: XFER_WRITE; 
-	c->Request.Timeout = 0; // Don't time out	
+	c->Request.Timeout = 0; /* Don't time out */
 	c->Request.CDB[0] = (creq->cmd == READ) ? CCISS_READ : CCISS_WRITE;
 	start_blk = hba[h->ctlr]->hd[MINOR(creq->rq_dev)].start_sect + creq->sector;
 #ifdef CCISS_DEBUG
 	if (bh == NULL)
 		panic("cciss: bh== NULL?");
-	printk(KERN_DEBUG "ciss: sector =%d nr_sectors=%d\n",(int) creq->sector,
+	printk(KERN_DEBUG "cciss: sector =%d nr_sectors=%d\n",(int) creq->sector,
 		(int) creq->nr_sectors);	
 #endif /* CCISS_DEBUG */
 	seg = 0;
 	lastdataend = ~0ULL;
-	while(bh)
-	{
+	while(bh) {
 		if (bh_phys(bh) == lastdataend)
-		{  // tack it on to the last segment 
+		{  /* tack it on to the last segment */
 			tmp_sg[seg-1].length +=bh->b_size;
 			lastdataend += bh->b_size;
-		} else
-		{
+		} else {
 			if (seg == MAXSGENTRIES)
 				BUG();
 			tmp_sg[seg].page = bh->b_page;
@@ -1420,10 +2296,10 @@
 			    tmp_sg[i].offset, tmp_sg[i].length, ddir);
 		c->SG[i].Addr.lower = temp64.val32.lower;
                 c->SG[i].Addr.upper = temp64.val32.upper;
-                c->SG[i].Ext = 0;  // we are not chaining
+                c->SG[i].Ext = 0;  /* we are not chaining */
 	}
 	/* track how many SG entries we are using */ 
-	if( seg > h->maxSG)
+	if (seg > h->maxSG)
 		h->maxSG = seg; 
 
 #ifdef CCISS_DEBUG
@@ -1432,11 +2308,11 @@
 
 	c->Header.SGList = c->Header.SGTotal = seg;
 	c->Request.CDB[1]= 0;
-	c->Request.CDB[2]= (start_blk >> 24) & 0xff;	//MSB
+	c->Request.CDB[2]= (start_blk >> 24) & 0xff;	/* MSB */
 	c->Request.CDB[3]= (start_blk >> 16) & 0xff;
 	c->Request.CDB[4]= (start_blk >>  8) & 0xff;
 	c->Request.CDB[5]= start_blk & 0xff;
-	c->Request.CDB[6]= 0; // (sect >> 24) & 0xff; MSB
+	c->Request.CDB[6]= 0; /* (sect >> 24) & 0xff; MSB */
 	c->Request.CDB[7]= (creq->nr_sectors >>  8) & 0xff; 
 	c->Request.CDB[8]= creq->nr_sectors & 0xff; 
 	c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0;
@@ -1445,7 +2321,7 @@
 
 	addQ(&(h->reqQ),c);
 	h->Qdepth++;
-	if(h->Qdepth > h->maxQsinceinit)
+	if (h->Qdepth > h->maxQsinceinit)
 		h->maxQsinceinit = h->Qdepth; 
 
 	goto next;
@@ -1463,7 +2339,7 @@
 
 
 	/* Is this interrupt for us? */
-	if ( h->access.intr_pending(h) == 0)
+	if (h->access.intr_pending(h) == 0)
 		return;
 
 	/*
@@ -1471,14 +2347,11 @@
 	 * we had better do something about it.
 	 */
 	spin_lock_irqsave(&io_request_lock, flags);
-	while( h->access.intr_pending(h))
-	{
-		while((a = h->access.command_completed(h)) != FIFO_EMPTY) 
-		{
+	while( h->access.intr_pending(h)) {
+		while((a = h->access.command_completed(h)) != FIFO_EMPTY) {
 			a1 = a;
 			a &= ~3;
-			if ((c = h->cmpQ) == NULL)
-			{  
+			if ((c = h->cmpQ) == NULL) {  
 				printk(KERN_WARNING "cciss: Completion of %08lx ignored\n", (unsigned long)a1);
 				continue;	
 			} 
@@ -1494,8 +2367,7 @@
 			 if (c->busaddr == a) {
 				removeQ(&h->cmpQ, c);
 				if (c->cmd_type == CMD_RWREQ) {
-					complete_command(c, 0);
-					cmd_free(h, c, 1);
+					complete_command(h, c, 0);
 				} else if (c->cmd_type == CMD_IOCTL_PEND) {
 					complete(c->waiting);
 				}
@@ -1557,7 +2429,7 @@
 static void release_io_mem(ctlr_info_t *c)
 {
 	/* if IO mem was not protected do nothing */
-	if( c->io_mem_addr == 0)
+	if (c->io_mem_addr == 0)
 		return;
 	release_region(c->io_mem_addr, c->io_mem_length);
 	c->io_mem_addr = 0;
@@ -1582,15 +2454,13 @@
 	for(i=0; i<6; i++)
 		addr[i] = pdev->resource[i].start;
 
-	if (pci_enable_device(pdev))
-	{
+	if (pci_enable_device(pdev)) {
 		printk(KERN_ERR "cciss: Unable to Enable PCI device\n");
-		return( -1);
+		return -1;
 	}
-	if (pci_set_dma_mask(pdev, CCISS_DMA_MASK ) != 0)
-	{
+	if (pci_set_dma_mask(pdev, CCISS_DMA_MASK ) != 0) {
 		printk(KERN_ERR "cciss:  Unable to set DMA mask\n");
-		return(-1);
+		return -1;
 	}
 	
 	(void) pci_read_config_word(pdev, PCI_COMMAND,&command);
@@ -1606,7 +2476,7 @@
 	/* check to see if controller has been disabled */
 	if (!(command & 0x02)) {
 		printk(KERN_WARNING "cciss: controller appears to be disabled\n");
-		return(-1);
+		return -1;
 	}
 	/* search for our IO range so we can protect it */
 	for (i=0; i<6; i++) {
@@ -1700,8 +2570,7 @@
 	if (  (readb(&c->cfgtable->Signature[0]) != 'C') ||
 	      (readb(&c->cfgtable->Signature[1]) != 'I') ||
 	      (readb(&c->cfgtable->Signature[2]) != 'S') ||
-	      (readb(&c->cfgtable->Signature[3]) != 'S') )
-	{
+	      (readb(&c->cfgtable->Signature[3]) != 'S') ) {
 		printk("Does not appear to be a valid CISS config table\n");
 		return -1;
 	}
@@ -1714,8 +2583,7 @@
 		&(c->cfgtable->HostWrite.TransportRequest));
 	writel( CFGTBL_ChangeReq, c->vaddr + SA5_DOORBELL);
 
-	for(i=0;i<MAX_CONFIG_WAIT;i++)
-	{
+	for(i=0;i<MAX_CONFIG_WAIT;i++) {
 		if (!(readl(c->vaddr + SA5_DOORBELL) & CFGTBL_ChangeReq))
 			break;
 		/* delay and try again */
@@ -1729,8 +2597,7 @@
 	print_cfg_table(c->cfgtable);	
 #endif /* CCISS_DEBUG */ 
 
-	if (!(readl(&(c->cfgtable->TransportActive)) & CFGTBL_Trans_Simple))
-	{
+	if (!(readl(&(c->cfgtable->TransportActive)) & CFGTBL_Trans_Simple)) {
 		printk(KERN_WARNING "cciss: unable to get board into"
 					" simple mode\n");
 		return -1;
@@ -1755,22 +2622,19 @@
 	int total_size; 
 
 	ld_buff = kmalloc(sizeof(ReportLunData_struct), GFP_KERNEL);
-	if (ld_buff == NULL)
-	{
+	if (ld_buff == NULL) {
 		printk(KERN_ERR "cciss: out of memory\n");
 		return;
 	}
 	memset(ld_buff, 0, sizeof(ReportLunData_struct));
 	size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL);
-        if (size_buff == NULL)
-        {
+        if (size_buff == NULL) {
                 printk(KERN_ERR "cciss: out of memory\n");
 		kfree(ld_buff);
                 return;
         }
 	inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL);
-        if (inq_buff == NULL)
-        {
+        if (inq_buff == NULL) {
                 printk(KERN_ERR "cciss: out of memory\n");
                 kfree(ld_buff);
 		kfree(size_buff);
@@ -1779,14 +2643,12 @@
 	/* Get the firmware version */ 
 	return_code = sendcmd(CISS_INQUIRY, cntl_num, inq_buff, 
 		sizeof(InquiryData_struct), 0, 0 ,0, NULL);
-	if (return_code == IO_OK)
-	{
+	if (return_code == IO_OK) {
 		hba[cntl_num]->firm_ver[0] = inq_buff->data_byte[32];
 		hba[cntl_num]->firm_ver[1] = inq_buff->data_byte[33];
 		hba[cntl_num]->firm_ver[2] = inq_buff->data_byte[34];
 		hba[cntl_num]->firm_ver[3] = inq_buff->data_byte[35];
-	} else /* send command failed */
-	{
+	} else  {	/* send command failed */
 		printk(KERN_WARNING "cciss: unable to determine firmware"
 			" version of controller\n");
 	}
@@ -1794,8 +2656,7 @@
 	return_code = sendcmd(CISS_REPORT_LOG, cntl_num, ld_buff, 
 			sizeof(ReportLunData_struct), 0, 0, 0, NULL);
 
-	if( return_code == IO_OK)
-	{
+	if (return_code == IO_OK) {
 #ifdef CCISS_DEBUG
 		printk("LUN Data\n--------------------------\n");
 #endif /* CCISS_DEBUG */ 
@@ -1804,16 +2665,14 @@
 		listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[1])) << 16;
 		listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[2])) << 8;	
 		listlength |= 0xff & (unsigned int)(ld_buff->LUNListLength[3]);
-	} else /* reading number of logical volumes failed */
-	{
+	} else { /* reading number of logical volumes failed */
 		printk(KERN_WARNING "cciss: report logical volume"
 			" command failed\n");
 		listlength = 0;
 	}
-	hba[cntl_num]->num_luns = listlength / 8; // 8 bytes pre entry
-	if (hba[cntl_num]->num_luns > CISS_MAX_LUN)
-	{
-		printk(KERN_ERR "ciss:  only %d number of logical volumes supported\n",
+	hba[cntl_num]->num_luns = listlength / 8; /* 8 bytes pre entry */
+	if (hba[cntl_num]->num_luns > CISS_MAX_LUN) {
+		printk(KERN_ERR "cciss:  only %d number of logical volumes supported\n",
 			CISS_MAX_LUN);
 		hba[cntl_num]->num_luns = CISS_MAX_LUN;
 	}
@@ -1822,8 +2681,9 @@
 		ld_buff->LUNListLength[1], ld_buff->LUNListLength[2],
 		ld_buff->LUNListLength[3],  hba[cntl_num]->num_luns);
 #endif /* CCISS_DEBUG */
-	for(i=0; i<  hba[cntl_num]->num_luns ; i++)
-	{
+
+	hba[cntl_num]->highest_lun = hba[cntl_num]->num_luns-1;
+	for(i=0; i<  hba[cntl_num]->num_luns; i++) {
 	  	lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3])) << 24;
         	lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2])) << 16;
         	lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1])) << 8;
@@ -1839,8 +2699,7 @@
 	  	memset(size_buff, 0, sizeof(ReadCapdata_struct));
 	  	return_code = sendcmd(CCISS_READ_CAPACITY, cntl_num, size_buff, 
 				sizeof( ReadCapdata_struct), 1, i, 0, NULL);
-	  	if (return_code == IO_OK)
-		{
+	  	if (return_code == IO_OK) {
 			total_size = (0xff & 
 				(unsigned int)(size_buff->total_size[0])) << 24;
 			total_size |= (0xff & 
@@ -1849,7 +2708,8 @@
 				(unsigned int)(size_buff->total_size[2])) << 8;
 			total_size |= (0xff & (unsigned int)
 				(size_buff->total_size[3])); 
-			total_size++; // command returns highest block address
+			total_size++; 	/* command returns highest */
+					/* block address */
 
 			block_size = (0xff & 
 				(unsigned int)(size_buff->block_size[0])) << 24;
@@ -1859,8 +2719,7 @@
 				(unsigned int)(size_buff->block_size[2])) << 8;
                 	block_size |= (0xff & 
 				(unsigned int)(size_buff->block_size[3]));
-		} else /* read capacity command failed */ 
-		{
+		} else {	/* read capacity command failed */ 
 			printk(KERN_WARNING "cciss: read capacity failed\n");
 			total_size = block_size = 0; 
 		}	
@@ -1871,18 +2730,18 @@
 		memset(inq_buff, 0, sizeof(InquiryData_struct));
 		return_code = sendcmd(CISS_INQUIRY, cntl_num, inq_buff,
 			sizeof(InquiryData_struct), 1, i, 0xC1, NULL );
-	  	if (return_code == IO_OK)
-		{
-			if(inq_buff->data_byte[8] == 0xFF)
-			{
+	  	if (return_code == IO_OK) {
+			if (inq_buff->data_byte[8] == 0xFF) {
 			   printk(KERN_WARNING "cciss: reading geometry failed, volume does not support reading geometry\n");
 
                            hba[cntl_num]->drv[i].block_size = block_size;
                            hba[cntl_num]->drv[i].nr_blocks = total_size;
                            hba[cntl_num]->drv[i].heads = 255;
-                           hba[cntl_num]->drv[i].sectors = 32; // Sectors per track
-                           hba[cntl_num]->drv[i].cylinders = total_size / 255 / 32;                	} else
-			{
+                           hba[cntl_num]->drv[i].sectors = 32; /* Sectors */
+			   					/* per track */
+                           hba[cntl_num]->drv[i].cylinders = total_size 
+				   				/ 255 / 32;
+			} else {
 
 		 	   hba[cntl_num]->drv[i].block_size = block_size;
                            hba[cntl_num]->drv[i].nr_blocks = total_size;
@@ -1894,23 +2753,27 @@
 					(inq_buff->data_byte[4] & 0xff) << 8;
 			   hba[cntl_num]->drv[i].cylinders += 
                                         inq_buff->data_byte[5];
+                           hba[cntl_num]->drv[i].raid_level = 
+					inq_buff->data_byte[8]; 
 			}
 		}
-		else /* Get geometry failed */
-		{
+		else {	/* Get geometry failed */
 			printk(KERN_WARNING "cciss: reading geometry failed, continuing with default geometry\n"); 
 
 			hba[cntl_num]->drv[i].block_size = block_size;
 			hba[cntl_num]->drv[i].nr_blocks = total_size;
 			hba[cntl_num]->drv[i].heads = 255;
-			hba[cntl_num]->drv[i].sectors = 32; // Sectors per track 
+			hba[cntl_num]->drv[i].sectors = 32; 	/* Sectors */
+								/* per track */
 			hba[cntl_num]->drv[i].cylinders = total_size / 255 / 32;
 		}
-		printk(KERN_INFO "      heads= %d, sectors= %d, cylinders= %d\n\n",
+		if (hba[cntl_num]->drv[i].raid_level > 5)
+			hba[cntl_num]->drv[i].raid_level = RAID_UNKNOWN;
+		printk(KERN_INFO "      heads= %d, sectors= %d, cylinders= %d RAID %s\n\n",
 			hba[cntl_num]->drv[i].heads, 
 			hba[cntl_num]->drv[i].sectors,
-			hba[cntl_num]->drv[i].cylinders);
-
+			hba[cntl_num]->drv[i].cylinders,
+			raid_label[hba[cntl_num]->drv[i].raid_level]); 
 	}
 	kfree(ld_buff);
 	kfree(size_buff);
@@ -1922,22 +2785,19 @@
 static int alloc_cciss_hba(void)
 {
 	int i;
-	for(i=0; i< MAX_CTLR; i++)
-	{
-		if (hba[i] == NULL)
-		{
+	for(i=0; i< MAX_CTLR; i++) {
+		if (hba[i] == NULL) {
 			hba[i] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL);
-			if(hba[i]==NULL)
-			{
+			if (hba[i]==NULL) {
 				printk(KERN_ERR "cciss: out of memory.\n");
-				return (-1);
+				return -1;
 			}
-			return (i);
+			return i;
 		}
 	}
 	printk(KERN_WARNING "cciss: This driver supports a maximum"
 		" of 8 controllers.\n");
-	return(-1);
+	return -1;
 }
 
 static void free_hba(int i)
@@ -1963,13 +2823,12 @@
 		pdev->device, pdev->bus->number, PCI_SLOT(pdev->devfn),
 			PCI_FUNC(pdev->devfn));
 	i = alloc_cciss_hba();
-	if( i < 0 ) 
-		return (-1);
+	if (i < 0 ) 
+		return -1;
 	memset(hba[i], 0, sizeof(ctlr_info_t));
-	if (cciss_pci_init(hba[i], pdev) != 0)
-	{
+	if (cciss_pci_init(hba[i], pdev) != 0) {
 		free_hba(i);
-		return (-1);
+		return -1;
 	}
 	sprintf(hba[i]->devname, "cciss%d", i);
 	hba[i]->ctlr = i;
@@ -1986,26 +2845,25 @@
 		return -ENODEV;
 	}
 		
-	if( register_blkdev(MAJOR_NR+i, hba[i]->devname, &cciss_fops))
-	{
+	if (register_blkdev(MAJOR_NR+i, hba[i]->devname, &cciss_fops)) {
 		printk(KERN_ERR "cciss:  Unable to get major number "
 			"%d for %s\n", MAJOR_NR+i, hba[i]->devname);
 		release_io_mem(hba[i]);
 		free_hba(i);
-		return(-1);
+		return -1;
 	}
 	/* make sure the board interrupts are off */
 	hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF);
-	if( request_irq(hba[i]->intr, do_cciss_intr, 
+	if (request_irq(hba[i]->intr, do_cciss_intr, 
 		SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, 
-			hba[i]->devname, hba[i]))
-	{
-		printk(KERN_ERR "ciss: Unable to get irq %d for %s\n",
+			hba[i]->devname, hba[i])) {
+
+		printk(KERN_ERR "cciss: Unable to get irq %d for %s\n",
 			hba[i]->intr, hba[i]->devname);
 		unregister_blkdev( MAJOR_NR+i, hba[i]->devname);
 		release_io_mem(hba[i]);
 		free_hba(i);
-		return(-1);
+		return -1;
 	}
 	hba[i]->cmd_pool_bits = (__u32*)kmalloc(
         	((NR_CMDS+31)/32)*sizeof(__u32), GFP_KERNEL);
@@ -2015,17 +2873,17 @@
 	hba[i]->errinfo_pool = (ErrorInfo_struct *)pci_alloc_consistent(
 		hba[i]->pdev, NR_CMDS * sizeof( ErrorInfo_struct), 
 		&(hba[i]->errinfo_pool_dhandle));
-	if((hba[i]->cmd_pool_bits == NULL) 
+	if ((hba[i]->cmd_pool_bits == NULL) 
 		|| (hba[i]->cmd_pool == NULL)
-		|| (hba[i]->errinfo_pool == NULL))
-        {
-		if(hba[i]->cmd_pool_bits)
+		|| (hba[i]->errinfo_pool == NULL)) {
+
+		if (hba[i]->cmd_pool_bits)
                 	kfree(hba[i]->cmd_pool_bits);
-                if(hba[i]->cmd_pool)
+                if (hba[i]->cmd_pool)
                 	pci_free_consistent(hba[i]->pdev,  
 				NR_CMDS * sizeof(CommandList_struct), 
 				hba[i]->cmd_pool, hba[i]->cmd_pool_dhandle);	
-		if(hba[i]->errinfo_pool)
+		if (hba[i]->errinfo_pool)
 			pci_free_consistent(hba[i]->pdev,
 				NR_CMDS * sizeof( ErrorInfo_struct),
 				hba[i]->errinfo_pool, 
@@ -2035,7 +2893,7 @@
 		release_io_mem(hba[i]);
 		free_hba(i);
                 printk( KERN_ERR "cciss: out of memory");
-		return(-1);
+		return -1;
 	}
 
 	/* Initialize the pdev driver private data. 
@@ -2082,7 +2940,8 @@
 	hba[i]->gendisk.max_p = MAX_PART;
 	hba[i]->gendisk.part = hba[i]->hd;
 	hba[i]->gendisk.sizes = hba[i]->sizes;
-	hba[i]->gendisk.nr_real = hba[i]->num_luns;
+	hba[i]->gendisk.nr_real = hba[i]->highest_lun+1;
+	hba[i]->gendisk.fops = &cciss_fops;
 
 	/* Get on the disk list */ 
 	add_gendisk(&(hba[i]->gendisk));
@@ -2096,7 +2955,7 @@
 
 	cciss_register_scsi(i, 1);  /* hook ourself into SCSI subsystem */
 
-	return(1);
+	return 1;
 }
 
 static void __devexit cciss_remove_one (struct pci_dev *pdev)
@@ -2106,15 +2965,13 @@
 	char flush_buf[4];
 	int return_code; 
 
-	if (pci_get_drvdata(pdev) == NULL)
-	{
+	if (pci_get_drvdata(pdev) == NULL) {
 		printk( KERN_ERR "cciss: Unable to remove device \n");
 		return;
 	}
 	tmp_ptr = pci_get_drvdata(pdev);
 	i = tmp_ptr->ctlr;
-	if (hba[i] == NULL) 
-	{
+	if (hba[i] == NULL) {
 		printk(KERN_ERR "cciss: device appears to "
 			"already be removed \n");
 		return;
@@ -2175,7 +3032,7 @@
 static int __init init_cciss_module(void)
 {
 
-	return ( cciss_init());
+	return cciss_init();
 }
 
 static void __exit cleanup_cciss_module(void)
@@ -2184,10 +3041,8 @@
 
 	pci_unregister_driver(&cciss_pci_driver);
 	/* double check that all controller entrys have been removed */
-	for (i=0; i< MAX_CTLR; i++) 
-	{
-		if (hba[i] != NULL)
-		{
+	for (i=0; i< MAX_CTLR; i++) {
+		if (hba[i] != NULL) {
 			printk(KERN_WARNING "cciss: had to remove"
 					" controller %d\n", i);
 			cciss_remove_one(hba[i]->pdev);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/block/cciss.h linux-2.4.21-pre6/drivers/block/cciss.h
--- linux-2.4.20/drivers/block/cciss.h	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/block/cciss.h	2003-03-26 23:48:57.000000000 +0000
@@ -27,13 +27,14 @@
 };
 typedef struct _drive_info_struct
 {
- 	__u32   LunID;	
-	int 	usage_count;
-	int 	nr_blocks;
-	int	block_size;
-	int 	heads;
-	int	sectors;
-	int 	cylinders;
+ 	__u32   	LunID;	
+	int 		usage_count;
+	unsigned int 	nr_blocks;
+	int		block_size;
+	int 		heads;
+	int		sectors;
+	int 		cylinders;
+	int 		raid_level;
 } drive_info_struct;
 
 struct ctlr_info 
@@ -55,6 +56,7 @@
 	int	commands_outstanding;
 	int 	max_outstanding; /* Debug */ 
 	int	num_luns;
+	int 	highest_lun;
 	int	usage_count;  /* number of opens all all minor devices */
 
 	// information about each logical volume
@@ -85,6 +87,7 @@
 	int              sizes[256];
 	int              blocksizes[256];
 	int              hardsizes[256];
+	int busy_configuring;
 #ifdef CONFIG_CISS_SCSI_TAPE
 	void *scsi_ctlr; /* ptr to structure containing scsi related stuff */
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/block/cciss_cmd.h linux-2.4.21-pre6/drivers/block/cciss_cmd.h
--- linux-2.4.20/drivers/block/cciss_cmd.h	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/drivers/block/cciss_cmd.h	2003-03-26 23:49:09.000000000 +0000
@@ -1,16 +1,17 @@
 #ifndef CCISS_CMD_H
 #define CCISS_CMD_H
-//###########################################################################
-//DEFINES
-//###########################################################################
+/* ########################################################################## */
+/* DEFINES                                                                    */
+/* ########################################################################## */
 #define CISS_VERSION "1.00"
 
-//general boundary defintions
-#define SENSEINFOBYTES          32//note that this value may vary between host implementations
+/* general boundary defintions */
+#define SENSEINFOBYTES          32	/* note that this value may vary */
+					/* between host implementations  */
 #define MAXSGENTRIES            31
 #define MAXREPLYQS              256
 
-//Command Status value
+/* Command Status value */
 #define CMD_SUCCESS             0x0000
 #define CMD_TARGET_STATUS       0x0001
 #define CMD_DATA_UNDERRUN       0x0002
@@ -25,30 +26,30 @@
 #define CMD_TIMEOUT             0x000B
 #define CMD_UNABORTABLE		0x000C
 
-//transfer direction
+/* transfer direction */
 #define XFER_NONE               0x00
 #define XFER_WRITE              0x01
 #define XFER_READ               0x02
 #define XFER_RSVD               0x03
 
-//task attribute
+/* task attribute */
 #define ATTR_UNTAGGED           0x00
 #define ATTR_SIMPLE             0x04
 #define ATTR_HEADOFQUEUE        0x05
 #define ATTR_ORDERED            0x06
 #define ATTR_ACA                0x07
 
-//cdb type
+/* cdb type */
 #define TYPE_CMD				0x00
 #define TYPE_MSG				0x01
 
-//config space register offsets
+/* config space register offsets */
 #define CFG_VENDORID            0x00
 #define CFG_DEVICEID            0x02
 #define CFG_I2OBAR              0x10
 #define CFG_MEM1BAR             0x14
 
-//i2o space register offsets
+/* i2o space register offsets */
 #define I2O_IBDB_SET            0x20
 #define I2O_IBDB_CLEAR          0x70
 #define I2O_INT_STATUS          0x30
@@ -56,7 +57,7 @@
 #define I2O_IBPOST_Q            0x40
 #define I2O_OBPOST_Q            0x44
 
-//Configuration Table
+/* Configuration Table */
 #define CFGTBL_ChangeReq        0x00000001l
 #define CFGTBL_AccCmds          0x00000001l
 
@@ -78,24 +79,24 @@
    __u64	val;
 } u64bit;
 
-// Type defs used in the following structs
-#define BYTE __u8
-#define WORD __u16
-#define HWORD __u16
-#define DWORD __u32
-#define QWORD vals32 
-
-//###########################################################################
-//STRUCTURES
-//###########################################################################
+/*  Type defs used in the following structs */
+typedef	__u8 BYTE;
+typedef	__u16 WORD;
+typedef __u16 HWORD;
+typedef	__u32 DWORD; 
+typedef vals32 QWORD; 
+
+/* ######################################################################### */
+/* STRUCTURES                                                                */
+/* ######################################################################### */
 #define CISS_MAX_LUN	16	
 #define CISS_MAX_PHYS_LUN	1024
-// SCSI-3 Cmmands 
+/* SCSI-3 Cmmands  */
 
 #pragma pack(1)	
 
 #define CISS_INQUIRY 0x12
-//Date returned
+/* Data returned */
 typedef struct _InquiryData_struct
 {
   BYTE data_byte[36];
@@ -103,7 +104,7 @@
 
 #define CISS_REPORT_LOG 0xc2    /* Report Logical LUNs */
 #define CISS_REPORT_PHYS 0xc3   /* Report Physical LUNs */
-// Data returned
+/*  Data returned */
 typedef struct _ReportLUNdata_struct
 {
   BYTE LUNListLength[4];
@@ -114,39 +115,39 @@
 #define CCISS_READ_CAPACITY 0x25 /* Read Capacity */ 
 typedef struct _ReadCapdata_struct
 {
-  BYTE total_size[4];	// Total size in blocks
-  BYTE block_size[4];	// Size of blocks in bytes
+  BYTE total_size[4];	/* Total size in blocks */
+  BYTE block_size[4];	/* Size of blocks in bytes */
 } ReadCapdata_struct;
 
-// 12 byte commands not implemented in firmware yet. 
-// #define CCISS_READ 	0xa8	// Read(12)
-// #define CCISS_WRITE	0xaa	// Write(12)
- #define CCISS_READ   0x28    // Read(10)
- #define CCISS_WRITE  0x2a    // Write(10)
+/* 12 byte commands not implemented in firmware yet.  */
+/* #define CCISS_READ 	0xa8	Read(12)	*/
+/* #define CCISS_WRITE	0xaa	Write(12) 	*/
+ #define CCISS_READ   0x28    /* Read(10) */
+ #define CCISS_WRITE  0x2a    /* Write(10) */
 
-// BMIC commands 
+/* BMIC commands */
 #define BMIC_READ 0x26
 #define BMIC_WRITE 0x27
 #define BMIC_CACHE_FLUSH 0xc2
-#define CCISS_CACHE_FLUSH 0x01	//C2 was already being used by CCISS
+#define CCISS_CACHE_FLUSH 0x01	/* 0xC2 was already being used by CCISS */
 
-//Command List Structure
+/* Command List Structure */
 typedef union _SCSI3Addr_struct {
    struct {
     BYTE Dev;
     BYTE Bus:6;
-    BYTE Mode:2;        // b00
+    BYTE Mode:2;        /* b00 */
   } PeripDev;
    struct {
     BYTE DevLSB;
     BYTE DevMSB:6;
-    BYTE Mode:2;        // b01
+    BYTE Mode:2;        /* b01 */
   } LogDev;
    struct {
     BYTE Dev:5;
     BYTE Bus:3;
     BYTE Targ:6;
-    BYTE Mode:2;        // b10
+    BYTE Mode:2;        /* b10 */
   } LogUnit;
 } SCSI3Addr_struct;
 
@@ -154,7 +155,7 @@
   DWORD             TargetId:24;
   DWORD             Bus:6;
   DWORD             Mode:2;
-  SCSI3Addr_struct  Target[2]; //2 level target device addr
+  SCSI3Addr_struct  Target[2]; /* 2 level target device addr */
 } PhysDevAddr_struct;
   
 typedef struct _LogDevAddr_struct {
@@ -205,8 +206,8 @@
   }Common_Info;
   struct{
     BYTE  Reserved[2];
-    BYTE  offense_size;//size of offending entry
-    BYTE  offense_num; //byte # of offense 0-base
+    BYTE  offense_size;	/* size of offending entry 	*/
+    BYTE  offense_num; 	/* byte # of offense 0-base 	*/
     DWORD offense_value;
   }Invalid_Cmd;
 }MoreErrInfo_struct;
@@ -240,12 +241,13 @@
   struct _CommandList_struct *next;
   struct request *	   rq;
   struct completion *waiting;
+  int	 retry_count;
 #ifdef CONFIG_CISS_SCSI_TAPE
   void * scsi_cmd;
 #endif
 } CommandList_struct;
 
-//Configuration Table Structure
+/* Configuration Table Structure */
 typedef struct _HostWrite_struct {
   DWORD TransportRequest;
   DWORD Reserved;
@@ -266,4 +268,4 @@
   DWORD            HeartBeat;
 } CfgTable_struct;
 #pragma pack()	 
-#endif // CCISS_CMD_H
+#endif /* CCISS_CMD_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/block/cciss_scsi.c linux-2.4.21-pre6/drivers/block/cciss_scsi.c
--- linux-2.4.20/drivers/block/cciss_scsi.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/block/cciss_scsi.c	2003-03-26 23:48:58.000000000 +0000
@@ -1,7 +1,7 @@
 /*
- *    Disk Array driver for Compaq SA53xx Controllers, SCSI Tape module
- *    Copyright 2001 Compaq Computer Corporation
- *
+ *    Disk Array driver for HP SA 5xxx and 6xxx Controllers, SCSI Tape module
+ *    Copyright 2001, 2002 Hewlett-Packard Development Company, L.P.
+ *    
  *    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
@@ -16,7 +16,7 @@
  *    along with this program; if not, write to the Free Software
  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- *    Questions/Comments/Bugfixes to arrays@compaq.com
+ *    Questions/Comments/Bugfixes to Cciss-discuss@lists.sourceforge.net 
  *
  *    Author: Stephen M. Cameron
  */
@@ -233,8 +233,8 @@
 		printk( "cciss: %d scsi commands are still outstanding.\n",
 			CMD_STACK_SIZE - stk->top);
 		// BUG();
-		printk("WE HAVE A BUG HERE!!! stk=%p\n",
-			stk);
+		printk("WE HAVE A BUG HERE!!! stk=0x%08x\n",
+			(unsigned int) stk);
 	}
 	size = sizeof(struct cciss_scsi_cmd_stack_elem_t) * CMD_STACK_SIZE;
 
@@ -896,7 +896,7 @@
 
 	memset(cp->Request.CDB, 0, sizeof(cp->Request.CDB));
 	memcpy(cp->Request.CDB, cdb, cdblen);
-	cp->Request.Timeout = 1000;		// guarantee completion.
+	cp->Request.Timeout = 0;	// No timeout
 	cp->Request.CDBLen = cdblen;
 	cp->Request.Type.Type = TYPE_CMD;
 	cp->Request.Type.Attribute = ATTR_SIMPLE;
@@ -1414,7 +1414,7 @@
 
 	// Fill in the request block...
 
-	cp->Request.Timeout = 1000; // guarantee completion
+	cp->Request.Timeout = 0; // No timeout 
 	memset(cp->Request.CDB, 0, sizeof(cp->Request.CDB));
 	if (cmd->cmd_len > sizeof(cp->Request.CDB)) BUG();
 	cp->Request.CDBLen = cmd->cmd_len;
@@ -1578,14 +1578,14 @@
 cciss_proc_tape_report(int ctlr, unsigned char *buffer, off_t *pos, off_t *len)
 {
 	int size;
-	unsigned long flags;
+	unsigned int flags;
 
 	*pos = *pos -1; *len = *len - 1; // cut off the last trailing newline
 
 	CPQ_TAPE_LOCK(ctlr, flags);
 	size = sprintf(buffer + *len,
-		"       Sequential access devices: %d\n\n",
-			ccissscsi[ctlr].ndevices);
+		"Sequential access devices: %d\n\n",
+		 ccissscsi[ctlr].ndevices);
 	CPQ_TAPE_UNLOCK(ctlr, flags);
 	*pos += size; *len += size;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/block/cciss_scsi.h linux-2.4.21-pre6/drivers/block/cciss_scsi.h
--- linux-2.4.20/drivers/block/cciss_scsi.h	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/drivers/block/cciss_scsi.h	2003-03-26 23:49:00.000000000 +0000
@@ -1,6 +1,6 @@
 /*
- *    Disk Array driver for Compaq SA53xx Controllers, SCSI Tape module
- *    Copyright 2001 Compaq Computer Corporation
+ *    Disk Array driver for HP SA 5xxx and 6xxx Controllers, SCSI Tape module
+ *    Copyright 2001, 2002 Hewlett-Packard Development Company, L.P.
  *
  *    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
@@ -16,7 +16,7 @@
  *    along with this program; if not, write to the Free Software
  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- *    Questions/Comments/Bugfixes to arrays@compaq.com
+ *    Questions/Comments/Bugfixes to Cciss-discuss@lists.sourceforge.net
  *
  */
 #ifdef CONFIG_CISS_SCSI_TAPE
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/block/cpqarray.c linux-2.4.21-pre6/drivers/block/cpqarray.c
--- linux-2.4.20/drivers/block/cpqarray.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/block/cpqarray.c	2003-03-26 23:49:08.000000000 +0000
@@ -16,7 +16,7 @@
  *    along with this program; if not, write to the Free Software
  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- *    Questions/Comments/Bugfixes to arrays@compaq.com
+ *    Questions/Comments/Bugfixes to Cpqarray-discuss@lists.sourceforge.net
  *
  */
 #include <linux/config.h>	/* CONFIG_PROC_FS */
@@ -41,13 +41,13 @@
 
 #define SMART2_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
 
-#define DRIVER_NAME "Compaq SMART2 Driver (v 2.4.21)"
-#define DRIVER_VERSION SMART2_DRIVER_VERSION(2,4,21)
+#define DRIVER_NAME "Compaq SMART2 Driver (v 2.4.25)"
+#define DRIVER_VERSION SMART2_DRIVER_VERSION(2,4,25)
 
 /* Embedded module documentation macros - see modules.h */
 /* Original author Chris Frantz - Compaq Computer Corporation */
 MODULE_AUTHOR("Compaq Computer Corporation");
-MODULE_DESCRIPTION("Driver for Compaq Smart2 Array Controllers version 2.4.21");
+MODULE_DESCRIPTION("Driver for Compaq Smart2 Array Controllers version 2.4.25");
 MODULE_LICENSE("GPL");
 
 #define MAJOR_NR COMPAQ_SMART2_MAJOR
@@ -162,6 +162,7 @@
 static int ida_release(struct inode *inode, struct file *filep);
 static int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg);
 static int ida_ctlr_ioctl(int ctlr, int dsk, ida_ioctl_t *io);
+static int ida_ctlr_big_ioctl( int ctlr, int dsk, ida_big_ioctl_t *io);
 
 static void do_ida_request(request_queue_t *q);
 static void start_io(ctlr_info_t *h);
@@ -279,8 +280,7 @@
 
 	for(i=0; i<=h->highest_lun; i++) {
 		drv = &h->drv[i];
-		if(drv->nr_blks != 0)
-		{
+		if(drv->nr_blks != 0) {
 		    	size = sprintf(buffer+len, "ida/c%dd%d: blksz=%d nr_blks=%d\n",
 				ctlr, i, drv->blk_size, drv->nr_blks);
 			pos += size; len += size;
@@ -293,7 +293,8 @@
 
 	c = h->reqQ;
 	size = sprintf(buffer+len, "reqQ = %p", c); pos += size; len += size;
-	if (c) c=c->next;
+	if (c) 
+		c=c->next;
 	while(c && c != h->reqQ) {
 		size = sprintf(buffer+len, "->%p", c);
 		pos += size; len += size;
@@ -302,7 +303,8 @@
 
 	c = h->cmpQ;
 	size = sprintf(buffer+len, "\ncmpQ = %p", c); pos += size; len += size;
-	if (c) c=c->next;
+	if (c) 
+		c=c->next;
 	while(c && c != h->cmpQ) {
 		size = sprintf(buffer+len, "->%p", c);
 		pos += size; len += size;
@@ -352,12 +354,12 @@
 	ctlr_info_t *tmp_ptr;
 	char buff[4]; 
 
-		if (pdev->driver_data == NULL)
+	tmp_ptr = pci_get_drvdata(pdev);
+	if (tmp_ptr == NULL)
 	{
 		printk( KERN_ERR "cpqarray: Unable to remove device \n");
 		return;
 	}
-	tmp_ptr = (ctlr_info_t *) pdev->driver_data;
 	i = tmp_ptr->ctlr;
 	if (hba[i] == NULL) 
 	{
@@ -369,13 +371,12 @@
 	/* sendcmd will turn off interrupt, and send the flush... 
 	 * To write all data in the battery backed cache to disks    */
 	memset(buff, 0 , 4);
-	if( sendcmd(FLUSH_CACHE, i, buff, 4, 0, 0, 0))
-	{
+	if( sendcmd(FLUSH_CACHE, i, buff, 4, 0, 0, 0)) {
 		printk(KERN_WARNING "Unable to flush cache on controller %d\n",
 			 i);	
 	}
 	free_irq(hba[i]->intr, hba[i]);
-	pdev->driver_data = NULL;
+	pci_set_drvdata(pdev, NULL);
 	/* remove it from the disk list */
 	del_gendisk(&(hba[i]->gendisk));
 
@@ -399,8 +400,7 @@
 {
 	char buff[4]; 
 
-	if (hba[i] == NULL) 
-	{
+	if (hba[i] == NULL) {
 		printk(KERN_ERR "cpqarray: device appears to "
 			"already be removed \n");
 		return;
@@ -409,8 +409,7 @@
 	/* sendcmd will turn off interrupt, and send the flush... 
 	 * To write all data in the battery backed cache to disks    
 	 * no data returned, but don't want to send NULL to sendcmd */	
-	if( sendcmd(FLUSH_CACHE, i, buff, 4, 0, 0, 0))
-	{
+	if( sendcmd(FLUSH_CACHE, i, buff, 4, 0, 0, 0)) {
 		printk(KERN_WARNING "Unable to flush cache on controller %d\n",
 			 i);	
 	}
@@ -488,15 +487,14 @@
 	memset(hba[i], 0, sizeof(ctlr_info_t));
 	/* fill in default block size */
 	for(j=0;j<256;j++)
-                hba[i]->hardsizes[j] = BLOCK_SIZE;
+                hba[i]->hardsizes[j] = hba[i]->drv[j].blk_size;
 
 	sprintf(hba[i]->devname, "ida%d", i);
         hba[i]->ctlr = i;
 	/* Initialize the pdev driver private data */
-	pdev->driver_data = hba[i];
+	pci_set_drvdata(pdev, hba[i]);
 
-	if (cpqarray_pci_init(hba[i], pdev) != 0)
-	{
+	if (cpqarray_pci_init(hba[i], pdev) != 0) {
 		release_io_mem(hba[i]);
 		free_hba(i);
 		return (-1);
@@ -510,8 +508,7 @@
 	
 	/* If this successful it should insure that we are the only */
 	/* instance of the driver */	
-	if (register_blkdev(MAJOR_NR+i, hba[i]->devname, &ida_fops)) 
-	{
+	if (register_blkdev(MAJOR_NR+i, hba[i]->devname, &ida_fops)) {
         	printk(KERN_ERR "cpqarray: Unable to get major number %d for ida\n",
                                 MAJOR_NR+i);
                 release_io_mem(hba[i]);
@@ -522,8 +519,8 @@
 	
 	hba[i]->access.set_intr_mask(hba[i], 0);
 	if (request_irq(hba[i]->intr, do_ida_intr,
-		SA_INTERRUPT|SA_SHIRQ, hba[i]->devname, hba[i])) 
-	{
+		SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, 
+				hba[i]->devname, hba[i])) {
 
 		printk(KERN_ERR "cpqarray: Unable to get irq %d for %s\n", 
 				hba[i]->intr, hba[i]->devname);
@@ -538,8 +535,7 @@
 	hba[i]->cmd_pool_bits = (__u32*)kmalloc(
 				((NR_CMDS+31)/32)*sizeof(__u32), GFP_KERNEL);
 		
-	if(hba[i]->cmd_pool_bits == NULL || hba[i]->cmd_pool == NULL)
-	{
+	if(hba[i]->cmd_pool_bits == NULL || hba[i]->cmd_pool == NULL) {
 		if(hba[i]->cmd_pool_bits)
 			kfree(hba[i]->cmd_pool_bits);
 		if(hba[i]->cmd_pool)
@@ -583,6 +579,7 @@
 	hba[i]->gendisk.part = hba[i]->hd;
 	hba[i]->gendisk.sizes = hba[i]->sizes;
 	hba[i]->gendisk.nr_real = hba[i]->highest_lun+1; 
+	hba[i]->gendisk.fops = &ida_fops;
 	
 		/* Get on the disk list */
 	add_gendisk(&(hba[i]->gendisk));
@@ -622,8 +619,7 @@
 	pci_register_driver(&cpqarray_pci_driver);
 	cpqarray_eisa_detect();
 
-	for(i=0; i< MAX_CTLR; i++)
-        {
+	for(i=0; i< MAX_CTLR; i++) {
 		if (hba[i] != NULL)
 			num_cntlrs_reg++;
 	}
@@ -634,13 +630,10 @@
 static int alloc_cpqarray_hba(void)
 {
 	int i;
-	for(i=0; i< MAX_CTLR; i++)
-	{
-		if (hba[i] == NULL)
-		{
+	for(i=0; i< MAX_CTLR; i++) {
+		if (hba[i] == NULL) {
 			hba[i] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL);
-			if(hba[i]==NULL)
-			{
+			if(hba[i]==NULL) {
 				printk(KERN_ERR "cpqarray: out of memory.\n");
 				return (-1);
 			}
@@ -674,8 +667,7 @@
 
 	pci_read_config_word(pdev, PCI_COMMAND, &command);
 	/* check to see if controller has been disabled */
-	if(!(command & 0x02))
-	{
+	if(!(command & 0x02)) {
 		printk(KERN_WARNING "cpqarray: controller appears to be disabled\n");
 		return(-1);
 	}
@@ -688,13 +680,11 @@
 	for(i=0; i<6; i++)
 		addr[i] = pci_resource_start(pdev, i);
 
-	if (pci_enable_device(pdev))
-	{
+	if (pci_enable_device(pdev)) {
 		printk(KERN_ERR "cpqarray: Unable to Enable PCI device\n");
 		return -1;
 	}
-	if (pci_set_dma_mask(pdev, CPQARRAY_DMA_MASK) != 0)
-	{
+	if (pci_set_dma_mask(pdev, CPQARRAY_DMA_MASK) != 0) {
 		printk(KERN_ERR "cpqarray: Unable to set DMA mask\n");
 		return -1;
 	}
@@ -719,18 +709,16 @@
 );
 
 	c->intr = irq;
-	for(i=0; i<6; i++)
-	{
-		if (pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE_IO)
-		{ /* IO space */  
+	for(i=0; i<6; i++) {
+		if (pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE_IO) { 
+			/* IO space */  
 			c->io_mem_addr = addr[i];
 			c->io_mem_length = pci_resource_end(pdev, i) 
 				- pci_resource_start(pdev, i) +1; 
 			// printk("IO Value found addr[%d] %lx %lx\n",
 			//		i, c->io_mem_addr, c->io_mem_length);
 			if(!request_region( c->io_mem_addr, c->io_mem_length,
-				"cpqarray"))
-			{
+				"cpqarray")) {
 				printk( KERN_WARNING "cpqarray I/O memory range already in use addr %lx length = %ld\n", c->io_mem_addr, c->io_mem_length);
 				c->io_mem_addr = 0;
 				c->io_mem_length = 0;
@@ -740,7 +728,8 @@
 	}	
 	c->paddr = 0;
 	for(i=0; i<6; i++)
-		if (!(pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE_IO)) {
+		if (!(pci_resource_flags(pdev, i) & 
+					PCI_BASE_ADDRESS_SPACE_IO)) {
 			c->paddr = pci_resource_start (pdev, i);
 			break;
 		}
@@ -843,8 +832,7 @@
 		hba[ctlr]->io_mem_length = 0x7FF;		
 		if(!request_region( hba[ctlr]->io_mem_addr, 
 					hba[ctlr]->io_mem_length, 
-				"cpqarray"))
-		{
+				"cpqarray")) {
 			printk( KERN_WARNING "cpqarray: I/0 range already in use addr = %lx length=%ld\n",
 			 hba[ctlr]->io_mem_addr, hba[ctlr]->io_mem_length);
 			free_hba(ctlr);
@@ -854,10 +842,14 @@
 		 * Read the config register to find our interrupt
 		 */
 		intr = inb(eisa[i]+0xCC0) >> 4;
-		if (intr & 1) intr = 11;
-		else if (intr & 2) intr = 10;
-		else if (intr & 4) intr = 14;
-		else if (intr & 8) intr = 15;
+		if (intr & 1) 
+			intr = 11;
+		else if (intr & 2) 
+			intr = 10;
+		else if (intr & 4) 
+			intr = 14;
+		else if (intr & 8) 
+			intr = 15;
 		
 		hba[ctlr]->intr = intr;
 		sprintf(hba[ctlr]->devname, "ida%d", ctlr);
@@ -894,19 +886,18 @@
 	if (ctlr > MAX_CTLR || hba[ctlr] == NULL)
 		return -ENXIO;
 
-	if (!suser() && hba[ctlr]->sizes[ MINOR(inode->i_rdev)] == 0)
-		return -ENXIO;
-
 	/*
 	 * Root is allowed to open raw volume zero even if its not configured
 	 * so array config can still work.  I don't think I really like this,
 	 * but I'm already using way to many device nodes to claim another one
 	 * for "raw controller".
 	 */
-	if (suser()
-		&& hba[ctlr]->sizes[ MINOR(inode->i_rdev)] == 0 
-		&& MINOR(inode->i_rdev) != 0)
-		return -ENXIO;
+	if (hba[ctlr]->sizes[MINOR(inode->i_rdev)] == 0) {
+		if (MINOR(inode->i_rdev) != 0)
+			return -ENXIO;
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+	}
 
 	hba[ctlr]->drv[dsk].usage_count++;
 	hba[ctlr]->usage_count++;
@@ -947,7 +938,8 @@
 static inline cmdlist_t *removeQ(cmdlist_t **Qptr, cmdlist_t *c)
 {
 	if (c && c->next != c) {
-		if (*Qptr == c) *Qptr = c->next;
+		if (*Qptr == c) 
+			*Qptr = c->next;
 		c->prev->next = c->next;
 		c->next->prev = c->prev;
 	} else {
@@ -985,8 +977,7 @@
 	if (creq->nr_segments > SG_MAX)
 		BUG();
 
-	if (h->ctlr != MAJOR(creq->rq_dev)-MAJOR_NR )
-	{
+	if (h->ctlr != MAJOR(creq->rq_dev)-MAJOR_NR ) {
 		printk(KERN_WARNING "doreq cmd for %d, %x at %p\n",
 				h->ctlr, creq->rq_dev, creq);
 		blkdev_dequeue_request(creq);
@@ -1036,8 +1027,7 @@
 		bh = bh->b_reqnext;
 	}
 	/* Now do all the DMA Mappings */
-	for( i=0; i < seg; i++)
-	{
+	for( i=0; i < seg; i++) {
 		c->req.sg[i].size = tmp_sg[i].length;
 		c->req.sg[i].addr = (__u32) pci_map_page(
                 		h->pci_dev, tmp_sg[i].page, tmp_sg[i].offset,
@@ -1131,7 +1121,8 @@
 				cmd->req.hdr.sg_cnt, cmd->req.hdr.rcode);
 		ok = 0;	
 	}
-	if (timeout) ok = 0;
+	if (timeout) 
+		ok = 0;
 	/* unmap the DMA mapping for all the scatter gather elements */
         for(i=0; i<cmd->req.hdr.sg_cnt; i++)
         {
@@ -1192,15 +1183,14 @@
                                  *  But rcode = 0.
                                  */
 
-				if((a1 & 0x03) && (c->req.hdr.rcode == 0))
-                                {
+				if((a1 & 0x03) && (c->req.hdr.rcode == 0)) {
                                 	c->req.hdr.rcode = RCODE_INVREQ;
                                 }
 				if (c->type == CMD_RWREQ) {
 					complete_command(c, 0);
 					cmd_free(h, c, 1);
 				} else if (c->type == CMD_IOCTL_PEND) {
-					c->type = CMD_IOCTL_DONE;
+					complete(c->waiting);
 				}
 				continue;
 			}
@@ -1238,8 +1228,6 @@
 	int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR;
 	int dsk  = MINOR(inode->i_rdev) >> NWD_SHIFT;
 	int error;
-	ida_ioctl_t *io = (ida_ioctl_t*)arg;
-	ida_ioctl_t my_io;
 
 	switch(cmd) {
 	case HDIO_GETGEO:
@@ -1286,26 +1274,50 @@
 	}
 
 	case IDAGETDRVINFO:
+	{
+
+		ida_ioctl_t *io = (ida_ioctl_t*)arg;
 		return copy_to_user(&io->c.drv,&hba[ctlr]->drv[dsk],sizeof(drv_info_t));
-	case BLKGETSIZE:
-		if (!arg) return -EINVAL;
-		return put_user(hba[ctlr]->hd[MINOR(inode->i_rdev)].nr_sects, 
-			(unsigned long *)arg);
-	case BLKGETSIZE64:
-		return put_user((u64)(hba[ctlr]->hd[MINOR(inode->i_rdev)].nr_sects) << 9, (u64*)arg);
+	}
 	case BLKRRPART:
 		return revalidate_logvol(inode->i_rdev, 1);
 	case IDAPASSTHRU:
-		if (!suser()) return -EPERM;
-		error = copy_from_user(&my_io, io, sizeof(my_io));
-		if (error) return error;
+	{
+
+		ida_ioctl_t *io = (ida_ioctl_t*)arg;
+		ida_ioctl_t my_io;
+
+		if (!capable(CAP_SYS_RAWIO)) 
+			return -EPERM;
+		if (copy_from_user(&my_io, io, sizeof(my_io)))
+			return -EFAULT;
 		error = ida_ctlr_ioctl(ctlr, dsk, &my_io);
-		if (error) return error;
-		if(copy_to_user(io, &my_io, sizeof(my_io)))
+		if (error)
+			return error;
+		if (copy_to_user(io, &my_io, sizeof(my_io)))
 			return -EFAULT;
-		return error;
+		return 0;
+	}
+	case IDABIGPASSTHRU:
+	{
+
+		ida_big_ioctl_t *io = (ida_big_ioctl_t*)arg;
+		ida_big_ioctl_t my_io;
+		
+		if (!capable(CAP_SYS_RAWIO))
+			return -EPERM;
+		if (copy_from_user(&my_io, io, sizeof(my_io)))
+			return -EFAULT;
+		error = ida_ctlr_big_ioctl(ctlr, dsk, &my_io);
+		if (error)
+			return error;
+		if (copy_to_user(io, &my_io, sizeof(my_io)))
+			return -EFAULT;
+		return 0;
+	}
 	case IDAGETCTLRSIG:
-		if (!arg) return -EINVAL;
+		if (!arg) 
+			return -EINVAL;
 		put_user(hba[ctlr]->ctlr_sig, (int*)arg);
 		return 0;
 	case IDAREVALIDATEVOLS:
@@ -1319,7 +1331,8 @@
 		
 		ida_pci_info_struct pciinfo;
 
-		if (!arg) return -EINVAL;
+		if (!arg) 
+			return -EINVAL;
 		pciinfo.bus = hba[ctlr]->pci_dev->bus->number;
 		pciinfo.dev_fn = hba[ctlr]->pci_dev->devfn;
 		pciinfo.board_id = hba[ctlr]->board_id;
@@ -1347,8 +1360,7 @@
 
 		/* count partitions 1 to 15 with sizes > 0 */
 		start = (dsk << NWD_SHIFT); 	
-		for(i=1; i <IDA_MAX_PART; i++)
-		{
+		for(i=1; i <IDA_MAX_PART; i++) {
 			int minor = start+i;
 			if(hba[ctlr]->sizes[minor] != 0)
 				num_parts++;
@@ -1360,6 +1372,8 @@
 		return(0);
 	}
 
+	case BLKGETSIZE:
+	case BLKGETSIZE64:
 	case BLKFLSBUF:
 	case BLKBSZSET:
 	case BLKBSZGET:
@@ -1394,6 +1408,7 @@
 	void *p = NULL;
 	unsigned long flags;
 	int error;
+	DECLARE_COMPLETION(wait);
 
 	if ((c = cmd_alloc(h, 0)) == NULL)
 		return -ENOMEM;
@@ -1411,8 +1426,7 @@
 	switch(io->cmd) {
 	case PASSTHRU_A:
 		p = kmalloc(io->sg[0].size, GFP_KERNEL);
-		if (!p) 
-		{ 
+		if (!p) { 
 			error = -ENOMEM; 
 			cmd_free(h, c, 0); 
 			return(error);
@@ -1431,11 +1445,11 @@
 		c->req.hdr.sg_cnt = 1;
 		break;
 	case IDA_READ:
+	case SENSE_SURF_STATUS:
 	case READ_FLASH_ROM:
 	case SENSE_CONTROLLER_PERFORMANCE:
 		p = kmalloc(io->sg[0].size, GFP_KERNEL);
-		if (!p) 
-		{ 
+		if (!p) { 
                         error = -ENOMEM; 
                         cmd_free(h, c, 0);
                         return(error);
@@ -1452,8 +1466,7 @@
 	case COLLECT_BUFFER:
 	case WRITE_FLASH_ROM:
 		p = kmalloc(io->sg[0].size, GFP_KERNEL);
-		if (!p) 
- 		{ 
+		if (!p) { 
                         error = -ENOMEM; 
                         cmd_free(h, c, 0);
                         return(error);
@@ -1474,7 +1487,9 @@
 			c->req.sg[0].size, PCI_DMA_BIDIRECTIONAL);
 		c->req.hdr.sg_cnt = 1;
 	}
-	
+
+	c->waiting = &wait;
+
 	/* Put the request on the tail of the request queue */
 	spin_lock_irqsave(&io_request_lock, flags);
 	addQ(&h->reqQ, c);
@@ -1483,8 +1498,7 @@
 	spin_unlock_irqrestore(&io_request_lock, flags);
 
 	/* Wait for completion */
-	while(c->type != CMD_IOCTL_DONE)
-		schedule();
+	wait_for_completion(&wait);
 
 	/* Unmap the DMA  */
 	pci_unmap_single(h->pci_dev, c->req.sg[0].addr, c->req.sg[0].size, 
@@ -1496,6 +1510,7 @@
                                 sizeof(ida_ioctl_t),
                                 PCI_DMA_BIDIRECTIONAL);
 	case IDA_READ:
+	case SENSE_SURF_STATUS:
 	case DIAG_PASS_THRU:
 	case SENSE_CONTROLLER_PERFORMANCE:
 	case READ_FLASH_ROM:
@@ -1520,6 +1535,175 @@
 }
 
 /*
+ * ida_ctlr_big_ioctl is for passing commands to the controller from userspace.
+ * The command block (io) has already been copied to kernel space for us,
+ *
+ * Only root may perform a controller passthru command, however I'm not doing
+ * any serious sanity checking on the arguments.  
+ */
+static int ida_ctlr_big_ioctl(int ctlr, int dsk, ida_big_ioctl_t *io)
+{
+	ctlr_info_t *h = hba[ctlr];
+	cmdlist_t *c;
+	__u8   *scsi_param = NULL;
+	__u8	*buff[SG_MAX] = {NULL,};
+	size_t	buff_size[SG_MAX];
+	__u8	sg_used = 0;
+	unsigned long flags;
+	int error = 0;
+	int i;
+	DECLARE_COMPLETION(wait);
+
+	/* Check kmalloc limits  using all SGs */
+	if( io->buff_malloc_size > IDA_MAX_KMALLOC_SIZE)
+		return -EINVAL;
+	if( io->buff_size > io->buff_malloc_size * SG_MAX)
+		return -EINVAL;
+	if ((c = cmd_alloc(h, 0)) == NULL)
+		return -ENOMEM;
+
+	c->ctlr = ctlr;
+	c->hdr.unit = (io->unit & UNITVALID) ? (io->unit & ~UNITVALID) : dsk;
+	c->hdr.size = sizeof(rblk_t) >> 2;
+	c->size += sizeof(rblk_t);
+
+	c->req.hdr.cmd = io->cmd;
+	c->req.hdr.blk = io->blk;
+	c->req.hdr.blk_cnt = io->blk_cnt;
+	c->type = CMD_IOCTL_PEND;
+
+	/* Pre submit processing */
+	/* for passthru_a the scsi command is in another record */
+	if (io->cmd == PASSTHRU_A) {
+
+		if (io->scsi_param == NULL)
+		{
+			error = -EINVAL;
+			cmd_free(h, c, 0);
+			return(error);
+		}
+		scsi_param = kmalloc(sizeof(scsi_param_t),  GFP_KERNEL);
+		if (scsi_param == NULL) {
+			error = -ENOMEM;
+			cmd_free(h, c, 0);
+			return(error);
+		}
+
+		/* copy the scsi command to get passed thru */ 	
+		if (copy_from_user(scsi_param, io->scsi_param, 
+					sizeof(scsi_param_t))) {	
+			kfree(scsi_param);
+			cmd_free(h, c, 0);
+			return -EFAULT;
+		}
+
+		/* with this command the scsi command is seperate */
+		c->req.hdr.blk = pci_map_single(h->pci_dev, scsi_param,
+				sizeof(scsi_param_t), PCI_DMA_BIDIRECTIONAL);
+	}
+
+	/* fill in the SG entries */
+	/* create buffers if we need to */ 
+	if(io->buff_size > 0) {
+		size_t size_left_alloc = io->buff_size;
+		__u8 *data_ptr = io->buff;
+
+		while(size_left_alloc > 0) {
+			buff_size[sg_used] = (size_left_alloc 
+					> io->buff_malloc_size)
+				? io->buff_malloc_size : size_left_alloc;
+			buff[sg_used] = kmalloc( buff_size[sg_used], 
+					GFP_KERNEL);
+			if (buff[sg_used] == NULL) {
+				error = -ENOMEM;
+				goto ida_alloc_cleanup;
+			}
+			if(io->xfer_type & IDA_XFER_WRITE) {
+				/* Copy the data into the buffer created */
+				if (copy_from_user(buff[sg_used], data_ptr,
+						buff_size[sg_used])) {
+					error = -EFAULT;
+					goto ida_alloc_cleanup;
+				}
+			}
+			/* put the data into the scatter gather list */
+			c->req.sg[sg_used].size = buff_size[sg_used];
+			c->req.sg[sg_used].addr = pci_map_single(h->pci_dev, 
+					buff[sg_used], buff_size[sg_used],
+					 PCI_DMA_BIDIRECTIONAL);
+			
+			size_left_alloc -= buff_size[sg_used];
+			data_ptr += buff_size[sg_used];
+			sg_used++;
+		}
+	}
+	c->req.hdr.sg_cnt = sg_used;
+
+	c->waiting = &wait;
+
+	/* Put the request on the tail of the request queue */
+	spin_lock_irqsave(&io_request_lock, flags);
+	addQ(&h->reqQ, c);
+	h->Qdepth++;
+	start_io(h);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+
+	/* Wait for completion */
+	wait_for_completion(&wait);
+	/* Unmap the DMA  */
+	for(i=0; i<c->req.hdr.sg_cnt; i++) {
+		pci_unmap_single(h->pci_dev, c->req.sg[i].addr, 
+				c->req.sg[i].size, PCI_DMA_BIDIRECTIONAL);
+	}
+
+	/* if we are reading data from the hardware copy it back to user */
+	if (io->xfer_type & IDA_XFER_READ) {
+		__u8	*data_ptr = io->buff;
+		int i;
+
+	    	for(i=0; i<c->req.hdr.sg_cnt; i++) {
+			if (copy_to_user(data_ptr, buff[i], buff_size[i])) { 
+				error = -EFAULT;
+				goto ida_alloc_cleanup;
+			}
+			data_ptr += buff_size[i];
+			
+		}
+
+	}
+
+	io->rcode = c->req.hdr.rcode;
+
+	if(scsi_param) {
+		pci_unmap_single(h->pci_dev, c->req.hdr.blk,
+			sizeof(scsi_param_t), PCI_DMA_BIDIRECTIONAL);
+		/* copy the scsi_params back to the user */ 
+		if( copy_to_user(io->scsi_param, scsi_param, 
+					sizeof(scsi_param_t))) {
+			error = -EFAULT;	
+		}
+		kfree(scsi_param);
+	}
+	cmd_free(h, c, 0);
+	return(error);
+	
+ida_alloc_cleanup:
+	if(scsi_param) {
+		pci_unmap_single(h->pci_dev, c->req.hdr.blk,
+			sizeof(scsi_param_t), PCI_DMA_BIDIRECTIONAL);
+		kfree(scsi_param);
+	}
+	for (i=0; i<sg_used; i++) {
+		if(buff[sg_used] != NULL) {	
+			pci_unmap_single(h->pci_dev, c->req.sg[i].addr, 
+				buff_size[sg_used], PCI_DMA_BIDIRECTIONAL);
+			kfree(buff[sg_used]);
+		}
+	}	
+	cmd_free(h, c, 0);
+	return(error);
+}
+/*
  * Commands are pre-allocated in a large block.  Here we use a simple bitmap
  * scheme to suballocte them to the driver.  Operations that are not time
  * critical (and can wait for kmalloc and possibly sleep) can pass in NULL
@@ -1720,7 +1904,7 @@
 	hba[ctlr]->gendisk.nr_real = 0;
 
 	for(i=0;i<256;i++)
-                hba[ctlr]->hardsizes[i] = BLOCK_SIZE;
+                hba[ctlr]->hardsizes[i] = 0;
 	/*
 	 * Tell the array controller not to give us any interrupts while
 	 * we check the new geometry.  Then turn interrupts back on when
@@ -1752,8 +1936,7 @@
 
 	spin_lock_irqsave(&io_request_lock, flags);
 	/* make sure logical volume is NOT is use */
-	if( h->drv[logvol].usage_count > 1)
-	{
+	if( h->drv[logvol].usage_count > 1) {
 		spin_unlock_irqrestore(&io_request_lock, flags);
                 return -EBUSY;
 	}
@@ -1763,21 +1946,21 @@
 	/* invalidate the devices and deregister the disk */ 
 	max_p = gdev->max_p;
 	start = logvol << gdev->minor_shift;
-	for (i=max_p-1; i>=0; i--)
-	{
+	for (i=max_p-1; i>=0; i--) {
 		int minor = start+i;
 		// printk("invalidating( %d %d)\n", ctlr, minor);
 		invalidate_device(MKDEV(MAJOR_NR+ctlr, minor), 1);
 		/* so open will now fail */
 		hba[ctlr]->sizes[minor] = 0;
+		/* so it will no longer appear in /proc/partitions */
+		gdev->part[minor].start_sect = 0;
+		gdev->part[minor].nr_sects = 0;
 	}
 	/* check to see if it was the last disk */
-	if (logvol == h->highest_lun)
-	{
+	if (logvol == h->highest_lun) {
 		/* if so, find the new hightest lun */
 		int i, newhighest =-1;
-		for(i=0; i<h->highest_lun; i++)
-		{
+		for(i=0; i<h->highest_lun; i++) {
 			/* if the disk has size > 0, it is available */
 			if (hba[ctlr]->sizes[i << gdev->minor_shift] != 0)
 				newhighest = i;
@@ -1789,7 +1972,8 @@
 	gdev->nr_real = h->highest_lun+1; 
 	/* zero out the disk size info */ 
 	h->drv[logvol].nr_blks = 0;
-	h->drv[logvol].blk_size = BLOCK_SIZE;
+	h->drv[logvol].cylinders = 0;
+	h->drv[logvol].blk_size = 0;
 	return(0);
 
 }
@@ -1806,6 +1990,7 @@
 	cmdlist_t *c;
 	unsigned long flags;
 	ctlr_info_t *info_p = hba[ctlr];
+	DECLARE_COMPLETION(wait);
 
 	c = cmd_alloc(info_p, 0);
 	if(!c)
@@ -1835,6 +2020,7 @@
 	c->req.sg[0].addr = (__u32) pci_map_single(info_p->pci_dev, 
 		buff, c->req.sg[0].size, PCI_DMA_BIDIRECTIONAL);
 
+	c->waiting = &wait;
 	/* Put the request on the tail of the request queue */
 	spin_lock_irqsave(&io_request_lock, flags);
 	addQ(&info_p->reqQ, c);
@@ -1843,8 +2029,7 @@
 	spin_unlock_irqrestore(&io_request_lock, flags);
 
 	/* Wait for completion */
-	while(c->type != CMD_IOCTL_DONE)
-		schedule();
+	wait_for_completion(&wait);
 
 	if (c->req.hdr.rcode & RCODE_FATAL) {
 		printk(KERN_WARNING "Fatal error on ida/c%dd%d\n",
@@ -1885,14 +2070,12 @@
 		return -EINVAL;
 
 	id_ldrive = (id_log_drv_t *)kmalloc(sizeof(id_log_drv_t), GFP_KERNEL);
-	if(id_ldrive == NULL)
-	{
+	if(id_ldrive == NULL) {
 		printk( KERN_ERR "cpqarray:  out of memory.\n");
 		return -1;
 	}
 	id_lstatus_buf = (sense_log_drv_stat_t *)kmalloc(sizeof(sense_log_drv_stat_t), GFP_KERNEL);
-	if(id_lstatus_buf == NULL)
-	{
+	if(id_lstatus_buf == NULL) {
 		kfree(id_ldrive);
 		printk( KERN_ERR "cpqarray:  out of memory.\n");
 		return -1;
@@ -1905,8 +2088,7 @@
 	 */
 	ret_code = sendcmd_withirq(SENSE_LOG_DRV_STAT,
 		ctlr, id_lstatus_buf, size, 0, 0, logvol);
-	if (ret_code == IO_ERROR) 
-	{
+	if (ret_code == IO_ERROR) {
 			/*
 			   If can't get logical drive status, set
 			   the logical drive map to 0, so the
@@ -1922,8 +2104,7 @@
 	/*
 		   Make sure the logical drive is configured
 	 */
-	if (id_lstatus_buf->status == LOG_NOT_CONF) 
-	{
+	if (id_lstatus_buf->status == LOG_NOT_CONF) {
 		printk(KERN_WARNING "cpqarray: c%dd%d array not configured\n",
 			ctlr, logvol); 
 		kfree(id_lstatus_buf);
@@ -1937,8 +2118,7 @@
 			   logical drive won't be set and
 			   idastubopen will return error. 
 			 */
-	if (ret_code == IO_ERROR) 
-	{
+	if (ret_code == IO_ERROR) {
 		printk(KERN_WARNING "cpqarray: c%dd%d unable to ID logical volume\n",
 			ctlr,logvol);
 		kfree(id_lstatus_buf);
@@ -1963,8 +2143,7 @@
 	max_p = gdev->max_p;
 	start = logvol<< gdev->minor_shift;
 	
-	for(i=max_p-1; i>=0; i--) 
-	{
+	for(i=max_p-1; i>=0; i--) {
 		int minor = start+i;
 		invalidate_device(MKDEV(MAJOR_NR + ctlr, minor), 1);
 		gdev->part[minor].start_sect = 0;
@@ -1972,6 +2151,7 @@
 	
 		/* reset the blocksize so we can read the partition table */
 		blksize_size[MAJOR_NR+ctlr][minor] = 1024;
+		hba[ctlr]->hardsizes[minor] = drv->blk_size;
 	}
 	++hba[ctlr]->log_drives;
 	gdev->nr_real = info_p->highest_lun + 1;
@@ -2075,8 +2255,7 @@
 	/* Command does not return anything, but idasend command needs a 
 		buffer */
 	id_ctlr_buf = (id_ctlr_t *)kmalloc(sizeof(id_ctlr_t), GFP_KERNEL);
-	if(id_ctlr_buf==NULL)
-	{
+	if(id_ctlr_buf==NULL) {
 		printk(KERN_WARNING "cpqarray: Out of memory. "
 			"Unable to start background processing.\n");
 		return;
@@ -2110,23 +2289,20 @@
 	info_p->log_drv_map = 0;	
 	
 	id_ldrive = (id_log_drv_t *)kmalloc(sizeof(id_log_drv_t), GFP_KERNEL);
-	if(id_ldrive == NULL)
-	{
+	if(id_ldrive == NULL) {
 		printk( KERN_ERR "cpqarray:  out of memory.\n");
 		return;
 	}
 
 	id_ctlr_buf = (id_ctlr_t *)kmalloc(sizeof(id_ctlr_t), GFP_KERNEL);
-	if(id_ctlr_buf == NULL)
-	{
+	if(id_ctlr_buf == NULL) {
 		kfree(id_ldrive);
 		printk( KERN_ERR "cpqarray:  out of memory.\n");
 		return;
 	}
 
 	id_lstatus_buf = (sense_log_drv_stat_t *)kmalloc(sizeof(sense_log_drv_stat_t), GFP_KERNEL);
-	if(id_lstatus_buf == NULL)
-	{
+	if(id_lstatus_buf == NULL) {
 		kfree(id_ctlr_buf);
 		kfree(id_ldrive);
 		printk( KERN_ERR "cpqarray:  out of memory.\n");
@@ -2134,8 +2310,7 @@
 	}
 
 	sense_config_buf = (config_t *)kmalloc(sizeof(config_t), GFP_KERNEL);
-	if(sense_config_buf == NULL)
-	{
+	if(sense_config_buf == NULL) {
 		kfree(id_lstatus_buf);
 		kfree(id_ctlr_buf);
 		kfree(id_ldrive);
@@ -2285,10 +2460,8 @@
 
         pci_unregister_driver(&cpqarray_pci_driver);
         /* double check that all controller entrys have been removed */
-        for (i=0; i< MAX_CTLR; i++)
-        {
-                if (hba[i] != NULL)
-                {
+        for (i=0; i< MAX_CTLR; i++) {
+                if (hba[i] != NULL) {
                         printk(KERN_WARNING "cpqarray: had to remove"
                                         " controller %d\n", i);
                         cpqarray_remove_one_eisa(i);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/block/elevator.c linux-2.4.21-pre6/drivers/block/elevator.c
--- linux-2.4.20/drivers/block/elevator.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/block/elevator.c	2003-03-26 23:49:51.000000000 +0000
@@ -83,21 +83,22 @@
 	struct list_head *entry = &q->queue_head;
 	unsigned int count = bh->b_size >> 9, ret = ELEVATOR_NO_MERGE;
 	struct request *__rq;
+	int backmerge_only = 0;
 
-	while ((entry = entry->prev) != head) {
+	while (!backmerge_only && (entry = entry->prev) != head) {
 		__rq = blkdev_entry_to_request(entry);
 
 		/*
 		 * we can't insert beyond a zero sequence point
 		 */
 		if (__rq->elevator_sequence <= 0)
-			break;
+			backmerge_only = 1;
 
 		if (__rq->waiting)
 			continue;
 		if (__rq->rq_dev != bh->b_rdev)
 			continue;
-		if (!*req && bh_rq_in_between(bh, __rq, &q->queue_head))
+		if (!*req && bh_rq_in_between(bh, __rq, &q->queue_head) && !backmerge_only)
 			*req = __rq;
 		if (__rq->cmd != rw)
 			continue;
@@ -107,7 +108,7 @@
 			ret = ELEVATOR_BACK_MERGE;
 			*req = __rq;
 			break;
-		} else if (__rq->sector - count == bh->b_rsector) {
+		} else if (__rq->sector - count == bh->b_rsector && !backmerge_only) {
 			ret = ELEVATOR_FRONT_MERGE;
 			__rq->elevator_sequence--;
 			*req = __rq;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/block/ida_cmd.h linux-2.4.21-pre6/drivers/block/ida_cmd.h
--- linux-2.4.20/drivers/block/ida_cmd.h	2001-11-03 01:45:42.000000000 +0000
+++ linux-2.4.21-pre6/drivers/block/ida_cmd.h	2003-03-26 23:49:21.000000000 +0000
@@ -82,7 +82,6 @@
 
 #define CMD_RWREQ	0x00
 #define CMD_IOCTL_PEND	0x01
-#define CMD_IOCTL_DONE	0x02
 
 typedef struct cmdlist {
 	chdr_t	hdr;
@@ -94,6 +93,7 @@
 	struct cmdlist *prev;
 	struct cmdlist *next;
 	struct request *rq;
+	struct completion *waiting;
 	int type;
 } cmdlist_t;
 	
@@ -318,6 +318,8 @@
 	__u8	reserved[510];
 } mp_delay_t;
 
+#define SENSE_SURF_STATUS	0x70
+
 #define PASSTHRU_A	0x91
 typedef struct {
 	__u8	target;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/block/ida_ioctl.h linux-2.4.21-pre6/drivers/block/ida_ioctl.h
--- linux-2.4.20/drivers/block/ida_ioctl.h	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/drivers/block/ida_ioctl.h	2003-03-26 23:49:38.000000000 +0000
@@ -34,6 +34,7 @@
 #define IDADEREGDISK		0x33333434
 #define IDAREGNEWDISK		0x34343535
 #define IDAGETLOGINFO		0x35353636
+#define IDABIGPASSTHRU          0x36363535
 
 typedef struct _ida_pci_info_struct
 {
@@ -94,4 +95,27 @@
 	} c;
 } ida_ioctl_t;
 
+#define IDA_MAX_KMALLOC_SIZE 128000
+
+/* transfer type of the commands */
+#define IDA_XFER_NONE	0x00
+#define IDA_XFER_READ	0x01
+#define IDA_XFER_WRITE	0x02
+#define IDA_XFER_BOTH	0x03
+
+typedef struct {
+	__u8	cmd;
+	__u8	rcode;
+	__u8	unit;
+	__u32	blk;
+	__u16	blk_cnt;
+
+	__u8	xfer_type;
+	__u8    *buff;
+	size_t	buff_size;
+	__u32	buff_malloc_size;
+	scsi_param_t *scsi_param; /* used only for PASSTHRU_A */
+
+} ida_big_ioctl_t;
+
 #endif /* IDA_IOCTL_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/block/ll_rw_blk.c linux-2.4.21-pre6/drivers/block/ll_rw_blk.c
--- linux-2.4.20/drivers/block/ll_rw_blk.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/block/ll_rw_blk.c	2003-03-26 23:49:07.000000000 +0000
@@ -394,7 +394,7 @@
 	unsigned long flags;
 	/* Several broken drivers assume that this function doesn't sleep,
 	 * this causes system hangs during boot.
-	 * As a temporary fix, make the the function non-blocking.
+	 * As a temporary fix, make the function non-blocking.
 	 */
 	spin_lock_irqsave(&io_request_lock, flags);
 	while (q->nr_requests < nr_requests) {
@@ -1413,12 +1413,6 @@
 #ifdef CONFIG_ISP16_CDI
 	isp16_init();
 #endif
-#if defined(CONFIG_IDE) && defined(CONFIG_BLK_DEV_IDE)
-	ide_init();		/* this MUST precede hd_init */
-#endif
-#if defined(CONFIG_IDE) && defined(CONFIG_BLK_DEV_HD)
-	hd_init();
-#endif
 #ifdef CONFIG_BLK_DEV_PS2
 	ps2esdi_init();
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/block/loop.c linux-2.4.21-pre6/drivers/block/loop.c
--- linux-2.4.20/drivers/block/loop.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/block/loop.c	2003-03-26 23:49:40.000000000 +0000
@@ -199,9 +199,9 @@
 		page = grab_cache_page(mapping, index);
 		if (!page)
 			goto fail;
+		kaddr = kmap(page);
 		if (aops->prepare_write(file, page, offset, offset+size))
 			goto unlock;
-		kaddr = page_address(page);
 		flush_dcache_page(page);
 		transfer_result = lo_do_transfer(lo, WRITE, kaddr + offset, data, size, IV);
 		if (transfer_result) {
@@ -216,6 +216,7 @@
 			goto unlock;
 		if (transfer_result)
 			goto unlock;
+		kunmap(page);
 		data += size;
 		len -= size;
 		offset = 0;
@@ -228,6 +229,7 @@
 	return 0;
 
 unlock:
+	kunmap(page);
 	UnlockPage(page);
 	page_cache_release(page);
 fail:
@@ -418,6 +420,7 @@
 			break;
 
 		run_task_queue(&tq_disk);
+		set_current_state(TASK_INTERRUPTIBLE);
 		schedule_timeout(HZ);
 	} while (1);
 	memset(bh, 0, sizeof(*bh));
@@ -437,6 +440,7 @@
 			break;
 
 		run_task_queue(&tq_disk);
+		set_current_state(TASK_INTERRUPTIBLE);
 		schedule_timeout(HZ);
 	} while (1);
 
@@ -563,6 +567,7 @@
 
 	daemonize();
 	exit_files(current);
+	reparent_to_init();
 
 	sprintf(current->comm, "loop%d", lo->lo_number);
 
@@ -571,9 +576,6 @@
 	flush_signals(current);
 	spin_unlock_irq(&current->sigmask_lock);
 
-	current->policy = SCHED_OTHER;
-	current->nice = -20;
-
 	spin_lock_irq(&lo->lo_lock);
 	lo->lo_state = Lo_bound;
 	atomic_inc(&lo->lo_pending);
@@ -645,7 +647,7 @@
 		lo_device = inode->i_rdev;
 		if (lo_device == dev) {
 			error = -EBUSY;
-			goto out;
+			goto out_putf;
 		}
 	} else if (S_ISREG(inode->i_mode)) {
 		struct address_space_operations *aops = inode->i_mapping->a_ops;
@@ -1014,11 +1016,6 @@
 		return -EIO;
 	}
 
-	devfs_handle = devfs_mk_dir(NULL, "loop", NULL);
-	devfs_register_series(devfs_handle, "%u", max_loop, DEVFS_FL_DEFAULT,
-			      MAJOR_NR, 0,
-			      S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP,
-			      &lo_fops, NULL);
 
 	loop_dev = kmalloc(max_loop * sizeof(struct loop_device), GFP_KERNEL);
 	if (!loop_dev)
@@ -1051,13 +1048,21 @@
 	for (i = 0; i < max_loop; i++)
 		register_disk(NULL, MKDEV(MAJOR_NR, i), 1, &lo_fops, 0);
 
+	devfs_handle = devfs_mk_dir(NULL, "loop", NULL);
+	devfs_register_series(devfs_handle, "%u", max_loop, DEVFS_FL_DEFAULT,
+			      MAJOR_NR, 0,
+			      S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP,
+			      &lo_fops, NULL);
+
 	printk(KERN_INFO "loop: loaded (max %d devices)\n", max_loop);
 	return 0;
 
-out_sizes:
-	kfree(loop_dev);
 out_blksizes:
 	kfree(loop_sizes);
+out_sizes:
+	kfree(loop_dev);
+	if (devfs_unregister_blkdev(MAJOR_NR, "loop"))
+		printk(KERN_WARNING "loop: cannot unregister blkdev\n");
 	printk(KERN_ERR "loop: ran out of memory\n");
 	return -ENOMEM;
 }
@@ -1067,7 +1072,6 @@
 	devfs_unregister(devfs_handle);
 	if (devfs_unregister_blkdev(MAJOR_NR, "loop"))
 		printk(KERN_WARNING "loop: cannot unregister blkdev\n");
-
 	kfree(loop_dev);
 	kfree(loop_sizes);
 	kfree(loop_blksizes);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/block/nbd.c linux-2.4.21-pre6/drivers/block/nbd.c
--- linux-2.4.20/drivers/block/nbd.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/drivers/block/nbd.c	2003-03-26 23:49:18.000000000 +0000
@@ -26,6 +26,8 @@
  *   reduce number of partial TCP segments sent. <steve@chygwyn.com>
  * 01-12-6 Fix deadlock condition by making queue locks independant of
  *   the transmit lock. <steve@chygwyn.com>
+ * 02-10-11 Allow hung xmit to be aborted via SIGKILL & various fixes.
+ *   <Paul.Clements@SteelEye.com> <James.Bottomley@SteelEye.com>
  *
  * possible FIXME: make set_sock / set_blksize / set_size / do_it one syscall
  * why not: would need verify_area and friends, would share yet another 
@@ -101,9 +103,12 @@
 	oldfs = get_fs();
 	set_fs(get_ds());
 
+	/* Allow interception of SIGKILL only
+	 * Don't allow other signals to interrupt the transmission */
 	spin_lock_irqsave(&current->sigmask_lock, flags);
 	oldset = current->blocked;
 	sigfillset(&current->blocked);
+	sigdelsetmask(&current->blocked, sigmask(SIGKILL));
 	recalc_sigpending(current);
 	spin_unlock_irqrestore(&current->sigmask_lock, flags);
 
@@ -126,6 +131,17 @@
 		else
 			result = sock_recvmsg(sock, &msg, size, 0);
 
+		if (signal_pending(current)) {
+			siginfo_t info;
+			spin_lock_irqsave(&current->sigmask_lock, flags);
+			printk(KERN_WARNING "NBD (pid %d: %s) got signal %d\n",
+				current->pid, current->comm, 
+				dequeue_signal(&current->blocked, &info));
+			spin_unlock_irqrestore(&current->sigmask_lock, flags);
+			result = -EINTR;
+			break;
+		}
+
 		if (result <= 0) {
 #ifdef PARANOIA
 			printk(KERN_ERR "NBD: %s - sock=%ld at buf=%ld, size=%d returned %d.\n",
@@ -150,7 +166,7 @@
 
 void nbd_send_req(struct nbd_device *lo, struct request *req)
 {
-	int result;
+	int result = -1;
 	struct nbd_request request;
 	unsigned long size = req->nr_sectors << 9;
 	struct socket *sock = lo->sock;
@@ -164,6 +180,10 @@
 
 	down(&lo->tx_lock);
 
+	if (!sock || !lo->sock) {
+		FAIL("Attempted sendmsg to closed socket\n");
+	}
+
 	result = nbd_xmit(1, sock, (char *) &request, sizeof(request), req->cmd == WRITE ? MSG_MORE : 0);
 	if (result <= 0)
 		FAIL("Sendmsg failed for control.");
@@ -345,10 +365,28 @@
 		spin_unlock_irq(&io_request_lock);
 
 		spin_lock(&lo->queue_lock);
+		if (!lo->file) {
+			spin_unlock(&lo->queue_lock);
+			printk(KERN_ERR "nbd: failed between accept and semaphore, file lost\n");
+			req->errors++;
+			nbd_end_request(req);
+			spin_lock_irq(&io_request_lock);
+			continue;
+		}
+
 		list_add_tail(&req->queue, &lo->queue_head);
 		spin_unlock(&lo->queue_lock);
 
 		nbd_send_req(lo, req);
+		if (req->errors) {
+			printk(KERN_ERR "nbd: nbd_send_req failed\n");
+			spin_lock(&lo->queue_lock);
+			list_del(&req->queue);
+			spin_unlock(&lo->queue_lock);
+			nbd_end_request(req);
+			spin_lock_irq(&io_request_lock);
+			continue;
+		}
 
 		spin_lock_irq(&io_request_lock);
 		continue;
@@ -397,12 +435,14 @@
 			printk(KERN_ERR "nbd: Some requests are in progress -> can not turn off.\n");
 			return -EBUSY;
 		}
-		spin_unlock(&lo->queue_lock);
 		file = lo->file;
-		if (!file)
+		if (!file) {
+			spin_unlock(&lo->queue_lock);
 			return -EINVAL;
+		}
 		lo->file = NULL;
 		lo->sock = NULL;
+		spin_unlock(&lo->queue_lock);
 		fput(file);
 		return 0;
 	case NBD_SET_SOCK:
@@ -443,6 +483,26 @@
 		if (!lo->file)
 			return -EINVAL;
 		nbd_do_it(lo);
+		/* on return tidy up in case we have a signal */
+		/* Forcibly shutdown the socket causing all listeners
+		 * to error
+		 *
+		 * FIXME: This code is duplicated from sys_shutdown, but
+		 * there should be a more generic interface rather than
+		 * calling socket ops directly here */
+		down(&lo->tx_lock);
+		printk(KERN_WARNING "nbd: shutting down socket\n");
+		lo->sock->ops->shutdown(lo->sock, SEND_SHUTDOWN|RCV_SHUTDOWN);
+		lo->sock = NULL;
+		up(&lo->tx_lock);
+		spin_lock(&lo->queue_lock);
+		file = lo->file;
+		lo->file = NULL;
+		spin_unlock(&lo->queue_lock);
+		nbd_clear_que(lo);
+		printk(KERN_WARNING "nbd: queue cleared\n");
+		if (file)
+			fput(file);
 		return lo->harderror;
 	case NBD_CLEAR_QUE:
 		nbd_clear_que(lo);
@@ -523,7 +583,7 @@
 		init_MUTEX(&nbd_dev[i].tx_lock);
 		nbd_blksizes[i] = 1024;
 		nbd_blksize_bits[i] = 10;
-		nbd_bytesizes[i] = 0x7ffffc00; /* 2GB */
+		nbd_bytesizes[i] = ((u64)0x7ffffc00) << 10; /* 2TB */
 		nbd_sizes[i] = nbd_bytesizes[i] >> BLOCK_SIZE_BITS;
 		register_disk(NULL, MKDEV(MAJOR_NR,i), 1, &nbd_fops,
 				nbd_bytesizes[i]>>9);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/block/umem.c linux-2.4.21-pre6/drivers/block/umem.c
--- linux-2.4.20/drivers/block/umem.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/block/umem.c	2003-03-26 23:49:50.000000000 +0000
@@ -1230,7 +1230,7 @@
 
         spin_lock_init(&card->lock);
 
-	dev->driver_data = card;
+	pci_set_drvdata(dev, card);
 
 	if (pci_write_cmd != 0x0F) 	/* If not Memory Write & Invalidate */
 		pci_write_cmd = 0x07;	/* then Memory Write command */
@@ -1290,7 +1290,7 @@
 */
 static void mm_pci_remove(struct pci_dev *dev)
 {
-	struct cardinfo *card = dev->driver_data;
+	struct cardinfo *card = pci_get_drvdata(dev);
 
 	tasklet_kill(&card->tasklet);
 	iounmap(card->csr_remap);
@@ -1314,6 +1314,9 @@
 static const struct pci_device_id __devinitdata mm_pci_ids[] = { {
 	vendor:		PCI_VENDOR_ID_MICRO_MEMORY,
 	device:		PCI_DEVICE_ID_MICRO_MEMORY_5415CN,
+	}, {
+	vendor:		PCI_VENDOR_ID_MICRO_MEMORY,
+	device:		PCI_DEVICE_ID_MICRO_MEMORY_5425CN,
 	}, { /* end: all zeroes */ }
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/bluetooth/Config.in linux-2.4.21-pre6/drivers/bluetooth/Config.in
--- linux-2.4.20/drivers/bluetooth/Config.in	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/bluetooth/Config.in	2003-03-26 23:48:58.000000000 +0000
@@ -1,3 +1,7 @@
+#
+# Bluetooth HCI device drivers configuration
+#
+
 mainmenu_option next_comment
 comment 'Bluetooth device drivers'
 
@@ -9,6 +13,8 @@
 dep_tristate 'HCI UART driver' CONFIG_BLUEZ_HCIUART $CONFIG_BLUEZ
 if [ "$CONFIG_BLUEZ_HCIUART" != "n" ]; then
    bool '  UART (H4) protocol support' CONFIG_BLUEZ_HCIUART_H4
+   bool '  BCSP protocol support' CONFIG_BLUEZ_HCIUART_BCSP
+   dep_bool '  Transmit CRC with every BCSP packet' CONFIG_BLUEZ_HCIUART_BCSP_TXCRC $CONFIG_BLUEZ_HCIUART_BCSP
 fi
 
 dep_tristate 'HCI DTL1 (PC Card) driver' CONFIG_BLUEZ_HCIDTL1 $CONFIG_PCMCIA $CONFIG_BLUEZ
@@ -17,6 +23,9 @@
 
 dep_tristate 'HCI BlueCard (PC Card) driver' CONFIG_BLUEZ_HCIBLUECARD $CONFIG_PCMCIA $CONFIG_BLUEZ
 
+dep_tristate 'HCI UART (PC Card) driver' CONFIG_BLUEZ_HCIBTUART $CONFIG_PCMCIA $CONFIG_BLUEZ
+
 dep_tristate 'HCI VHCI (Virtual HCI device) driver' CONFIG_BLUEZ_HCIVHCI $CONFIG_BLUEZ
 
 endmenu
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/bluetooth/Makefile linux-2.4.21-pre6/drivers/bluetooth/Makefile
--- linux-2.4.20/drivers/bluetooth/Makefile	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/bluetooth/Makefile	2003-03-26 23:49:55.000000000 +0000
@@ -1,5 +1,5 @@
 #
-# Makefile for Bluetooth HCI device drivers.
+# Makefile for the Linux Bluetooth HCI device drivers
 #
 
 O_TARGET	:= bluetooth.o
@@ -9,13 +9,15 @@
 obj-$(CONFIG_BLUEZ_HCIUSB)	+= hci_usb.o
 obj-$(CONFIG_BLUEZ_HCIVHCI)	+= hci_vhci.o
 
-obj-$(CONFIG_BLUEZ_HCIUART)	+= hci_uart.o
-uart-y				:= hci_ldisc.o
-uart-$(CONFIG_BLUEZ_HCIUART_H4)	+= hci_h4.o
+obj-$(CONFIG_BLUEZ_HCIUART)		+= hci_uart.o
+uart-y					:= hci_ldisc.o
+uart-$(CONFIG_BLUEZ_HCIUART_H4)		+= hci_h4.o
+uart-$(CONFIG_BLUEZ_HCIUART_BCSP)	+= hci_bcsp.o
 
 obj-$(CONFIG_BLUEZ_HCIDTL1)	+= dtl1_cs.o
 obj-$(CONFIG_BLUEZ_HCIBT3C)	+= bt3c_cs.o
 obj-$(CONFIG_BLUEZ_HCIBLUECARD)	+= bluecard_cs.o
+obj-$(CONFIG_BLUEZ_HCIBTUART)	+= btuart_cs.o
 
 include $(TOPDIR)/Rules.make
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/bluetooth/btuart_cs.c linux-2.4.21-pre6/drivers/bluetooth/btuart_cs.c
--- linux-2.4.20/drivers/bluetooth/btuart_cs.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/bluetooth/btuart_cs.c	2003-03-26 23:49:39.000000000 +0000
@@ -0,0 +1,906 @@
+/*
+ *
+ *  Driver for Bluetooth PCMCIA cards with HCI UART interface
+ *
+ *  Copyright (C) 2001-2002  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation;
+ *
+ *  Software distributed under the License is distributed on an "AS
+ *  IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ *  implied. See the License for the specific language governing
+ *  rights and limitations under the License.
+ *
+ *  The initial developer of the original code is David A. Hinds
+ *  <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+ *  are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/spinlock.h>
+
+#include <linux/skbuff.h>
+#include <linux/string.h>
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ciscode.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/cisreg.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+
+
+/* ======================== Module parameters ======================== */
+
+
+/* Bit map of interrupts to choose from */
+static u_int irq_mask = 0xffff;
+static int irq_list[4] = { -1 };
+
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+
+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
+MODULE_DESCRIPTION("BlueZ driver for Bluetooth PCMCIA cards with HCI UART interface");
+MODULE_LICENSE("GPL");
+
+
+
+/* ======================== Local structures ======================== */
+
+
+typedef struct btuart_info_t {
+	dev_link_t link;
+	dev_node_t node;
+
+	struct hci_dev hdev;
+
+	spinlock_t lock;	/* For serializing operations */
+
+	struct sk_buff_head txq;
+	unsigned long tx_state;
+
+	unsigned long rx_state;
+	unsigned long rx_count;
+	struct sk_buff *rx_skb;
+} btuart_info_t;
+
+
+void btuart_config(dev_link_t *link);
+void btuart_release(u_long arg);
+int btuart_event(event_t event, int priority, event_callback_args_t *args);
+
+static dev_info_t dev_info = "btuart_cs";
+
+dev_link_t *btuart_attach(void);
+void btuart_detach(dev_link_t *);
+
+static dev_link_t *dev_list = NULL;
+
+
+/* Maximum baud rate */
+#define SPEED_MAX  115200
+
+/* Default baud rate: 57600, 115200, 230400 or 460800 */
+#define DEFAULT_BAUD_RATE  115200
+
+
+/* Transmit states  */
+#define XMIT_SENDING	1
+#define XMIT_WAKEUP	2
+#define XMIT_WAITING	8
+
+/* Receiver states */
+#define RECV_WAIT_PACKET_TYPE	0
+#define RECV_WAIT_EVENT_HEADER	1
+#define RECV_WAIT_ACL_HEADER	2
+#define RECV_WAIT_SCO_HEADER	3
+#define RECV_WAIT_DATA		4
+
+
+
+/* ======================== Interrupt handling ======================== */
+
+
+static int btuart_write(unsigned int iobase, int fifo_size, __u8 *buf, int len)
+{
+	int actual = 0;
+
+	/* Tx FIFO should be empty */
+	if (!(inb(iobase + UART_LSR) & UART_LSR_THRE))
+		return 0;
+
+	/* Fill FIFO with current frame */
+	while ((fifo_size-- > 0) && (actual < len)) {
+		/* Transmit next byte */
+		outb(buf[actual], iobase + UART_TX);
+		actual++;
+	}
+
+	return actual;
+}
+
+
+static void btuart_write_wakeup(btuart_info_t *info)
+{
+	if (!info) {
+		printk(KERN_WARNING "btuart_cs: Call of write_wakeup for unknown device.\n");
+		return;
+	}
+
+	if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) {
+		set_bit(XMIT_WAKEUP, &(info->tx_state));
+		return;
+	}
+
+	do {
+		register unsigned int iobase = info->link.io.BasePort1;
+		register struct sk_buff *skb;
+		register int len;
+
+		clear_bit(XMIT_WAKEUP, &(info->tx_state));
+
+		if (!(info->link.state & DEV_PRESENT))
+			return;
+
+		if (!(skb = skb_dequeue(&(info->txq))))
+			break;
+
+		/* Send frame */
+		len = btuart_write(iobase, 16, skb->data, skb->len);
+		set_bit(XMIT_WAKEUP, &(info->tx_state));
+
+		if (len == skb->len) {
+			kfree_skb(skb);
+		} else {
+			skb_pull(skb, len);
+			skb_queue_head(&(info->txq), skb);
+		}
+
+		info->hdev.stat.byte_tx += len;
+
+	} while (test_bit(XMIT_WAKEUP, &(info->tx_state)));
+
+	clear_bit(XMIT_SENDING, &(info->tx_state));
+}
+
+
+static void btuart_receive(btuart_info_t *info)
+{
+	unsigned int iobase;
+	int boguscount = 0;
+
+	if (!info) {
+		printk(KERN_WARNING "btuart_cs: Call of receive for unknown device.\n");
+		return;
+	}
+
+	iobase = info->link.io.BasePort1;
+
+	do {
+		info->hdev.stat.byte_rx++;
+
+		/* Allocate packet */
+		if (info->rx_skb == NULL) {
+			info->rx_state = RECV_WAIT_PACKET_TYPE;
+			info->rx_count = 0;
+			if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
+				printk(KERN_WARNING "btuart_cs: Can't allocate mem for new packet.\n");
+				return;
+			}
+		}
+
+		if (info->rx_state == RECV_WAIT_PACKET_TYPE) {
+
+			info->rx_skb->dev = (void *)&(info->hdev);
+			info->rx_skb->pkt_type = inb(iobase + UART_RX);
+
+			switch (info->rx_skb->pkt_type) {
+
+			case HCI_EVENT_PKT:
+				info->rx_state = RECV_WAIT_EVENT_HEADER;
+				info->rx_count = HCI_EVENT_HDR_SIZE;
+				break;
+
+			case HCI_ACLDATA_PKT:
+				info->rx_state = RECV_WAIT_ACL_HEADER;
+				info->rx_count = HCI_ACL_HDR_SIZE;
+				break;
+
+			case HCI_SCODATA_PKT:
+				info->rx_state = RECV_WAIT_SCO_HEADER;
+				info->rx_count = HCI_SCO_HDR_SIZE;
+				break;
+
+			default:
+				/* Unknown packet */
+				printk(KERN_WARNING "btuart_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type);
+				info->hdev.stat.err_rx++;
+				clear_bit(HCI_RUNNING, &(info->hdev.flags));
+
+				kfree_skb(info->rx_skb);
+				info->rx_skb = NULL;
+				break;
+
+			}
+
+		} else {
+
+			*skb_put(info->rx_skb, 1) = inb(iobase + UART_RX);
+			info->rx_count--;
+
+			if (info->rx_count == 0) {
+
+				int dlen;
+				hci_event_hdr *eh;
+				hci_acl_hdr *ah;
+				hci_sco_hdr *sh;
+
+
+				switch (info->rx_state) {
+
+				case RECV_WAIT_EVENT_HEADER:
+					eh = (hci_event_hdr *)(info->rx_skb->data);
+					info->rx_state = RECV_WAIT_DATA;
+					info->rx_count = eh->plen;
+					break;
+
+				case RECV_WAIT_ACL_HEADER:
+					ah = (hci_acl_hdr *)(info->rx_skb->data);
+					dlen = __le16_to_cpu(ah->dlen);
+					info->rx_state = RECV_WAIT_DATA;
+					info->rx_count = dlen;
+					break;
+
+				case RECV_WAIT_SCO_HEADER:
+					sh = (hci_sco_hdr *)(info->rx_skb->data);
+					info->rx_state = RECV_WAIT_DATA;
+					info->rx_count = sh->dlen;
+					break;
+
+				case RECV_WAIT_DATA:
+					hci_recv_frame(info->rx_skb);
+					info->rx_skb = NULL;
+					break;
+
+				}
+
+			}
+
+		}
+
+		/* Make sure we don't stay here to long */
+		if (boguscount++ > 16)
+			break;
+
+	} while (inb(iobase + UART_LSR) & UART_LSR_DR);
+}
+
+
+void btuart_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
+{
+	btuart_info_t *info = dev_inst;
+	unsigned int iobase;
+	int boguscount = 0;
+	int iir, lsr;
+
+	if (!info) {
+		printk(KERN_WARNING "btuart_cs: Call of irq %d for unknown device.\n", irq);
+		return;
+	}
+
+	iobase = info->link.io.BasePort1;
+
+	spin_lock(&(info->lock));
+
+	iir = inb(iobase + UART_IIR) & UART_IIR_ID;
+	while (iir) {
+
+		/* Clear interrupt */
+		lsr = inb(iobase + UART_LSR);
+
+		switch (iir) {
+		case UART_IIR_RLSI:
+			printk(KERN_NOTICE "btuart_cs: RLSI\n");
+			break;
+		case UART_IIR_RDI:
+			/* Receive interrupt */
+			btuart_receive(info);
+			break;
+		case UART_IIR_THRI:
+			if (lsr & UART_LSR_THRE) {
+				/* Transmitter ready for data */
+				btuart_write_wakeup(info);
+			}
+			break;
+		default:
+			printk(KERN_NOTICE "btuart_cs: Unhandled IIR=%#x\n", iir);
+			break;
+		}
+
+		/* Make sure we don't stay here to long */
+		if (boguscount++ > 100)
+			break;
+
+		iir = inb(iobase + UART_IIR) & UART_IIR_ID;
+
+	}
+
+	spin_unlock(&(info->lock));
+}
+
+
+static void btuart_change_speed(btuart_info_t *info, unsigned int speed)
+{
+	unsigned long flags;
+	unsigned int iobase;
+	int fcr;		/* FIFO control reg */
+	int lcr;		/* Line control reg */
+	int divisor;
+
+	if (!info) {
+		printk(KERN_WARNING "btuart_cs: Call of change speed for unknown device.\n");
+		return;
+	}
+
+	iobase = info->link.io.BasePort1;
+
+	spin_lock_irqsave(&(info->lock), flags);
+
+	/* Turn off interrupts */
+	outb(0, iobase + UART_IER);
+
+	divisor = SPEED_MAX / speed;
+
+	fcr = UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT;
+
+	/* 
+	 * 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 (speed < 38400)
+		fcr |= UART_FCR_TRIGGER_1;
+	else
+		fcr |= UART_FCR_TRIGGER_14;
+
+	/* Bluetooth cards 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 */
+
+	/* Turn on interrups */
+	outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER);
+
+	spin_unlock_irqrestore(&(info->lock), flags);
+}
+
+
+
+/* ======================== HCI interface ======================== */
+
+
+static int btuart_hci_flush(struct hci_dev *hdev)
+{
+	btuart_info_t *info = (btuart_info_t *)(hdev->driver_data);
+
+	/* Drop TX queue */
+	skb_queue_purge(&(info->txq));
+
+	return 0;
+}
+
+
+static int btuart_hci_open(struct hci_dev *hdev)
+{
+	set_bit(HCI_RUNNING, &(hdev->flags));
+
+	return 0;
+}
+
+
+static int btuart_hci_close(struct hci_dev *hdev)
+{
+	if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
+		return 0;
+
+	btuart_hci_flush(hdev);
+
+	return 0;
+}
+
+
+static int btuart_hci_send_frame(struct sk_buff *skb)
+{
+	btuart_info_t *info;
+	struct hci_dev *hdev = (struct hci_dev *)(skb->dev);
+
+	if (!hdev) {
+		printk(KERN_WARNING "btuart_cs: Frame for unknown HCI device (hdev=NULL).");
+		return -ENODEV;
+	}
+
+	info = (btuart_info_t *)(hdev->driver_data);
+
+	switch (skb->pkt_type) {
+	case HCI_COMMAND_PKT:
+		hdev->stat.cmd_tx++;
+		break;
+	case HCI_ACLDATA_PKT:
+		hdev->stat.acl_tx++;
+		break;
+	case HCI_SCODATA_PKT:
+		hdev->stat.sco_tx++;
+		break;
+	};
+
+	/* Prepend skb with frame type */
+	memcpy(skb_push(skb, 1), &(skb->pkt_type), 1);
+	skb_queue_tail(&(info->txq), skb);
+
+	btuart_write_wakeup(info);
+
+	return 0;
+}
+
+
+static void btuart_hci_destruct(struct hci_dev *hdev)
+{
+}
+
+
+static int btuart_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
+{
+	return -ENOIOCTLCMD;
+}
+
+
+
+/* ======================== Card services HCI interaction ======================== */
+
+
+int btuart_open(btuart_info_t *info)
+{
+	unsigned long flags;
+	unsigned int iobase = info->link.io.BasePort1;
+	struct hci_dev *hdev;
+
+	spin_lock_init(&(info->lock));
+
+	skb_queue_head_init(&(info->txq));
+
+	info->rx_state = RECV_WAIT_PACKET_TYPE;
+	info->rx_count = 0;
+	info->rx_skb = NULL;
+
+	spin_lock_irqsave(&(info->lock), flags);
+
+	/* Reset UART */
+	outb(0, iobase + UART_MCR);
+
+	/* Turn off interrupts */
+	outb(0, iobase + UART_IER);
+
+	/* Initialize UART */
+	outb(UART_LCR_WLEN8, iobase + UART_LCR);	/* Reset DLAB */
+	outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase + UART_MCR);
+
+	/* Turn on interrupts */
+	// outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER);
+
+	spin_unlock_irqrestore(&(info->lock), flags);
+
+	btuart_change_speed(info, DEFAULT_BAUD_RATE);
+
+	/* Timeout before it is safe to send the first HCI packet */
+	set_current_state(TASK_INTERRUPTIBLE);
+	schedule_timeout(HZ);
+
+
+	/* Initialize and register HCI device */
+
+	hdev = &(info->hdev);
+
+	hdev->type = HCI_PCCARD;
+	hdev->driver_data = info;
+
+	hdev->open = btuart_hci_open;
+	hdev->close = btuart_hci_close;
+	hdev->flush = btuart_hci_flush;
+	hdev->send = btuart_hci_send_frame;
+	hdev->destruct = btuart_hci_destruct;
+	hdev->ioctl = btuart_hci_ioctl;
+
+	if (hci_register_dev(hdev) < 0) {
+		printk(KERN_WARNING "btuart_cs: Can't register HCI device %s.\n", hdev->name);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+
+int btuart_close(btuart_info_t *info)
+{
+	unsigned long flags;
+	unsigned int iobase = info->link.io.BasePort1;
+	struct hci_dev *hdev = &(info->hdev);
+
+	btuart_hci_close(hdev);
+
+	spin_lock_irqsave(&(info->lock), flags);
+
+	/* Reset UART */
+	outb(0, iobase + UART_MCR);
+
+	/* Turn off interrupts */
+	outb(0, iobase + UART_IER);
+
+	spin_unlock_irqrestore(&(info->lock), flags);
+
+	if (hci_unregister_dev(hdev) < 0)
+		printk(KERN_WARNING "btuart_cs: Can't unregister HCI device %s.\n", hdev->name);
+
+	return 0;
+}
+
+
+
+/* ======================== Card services ======================== */
+
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+	error_info_t err = { func, ret };
+
+	CardServices(ReportError, handle, &err);
+}
+
+
+dev_link_t *btuart_attach(void)
+{
+	btuart_info_t *info;
+	client_reg_t client_reg;
+	dev_link_t *link;
+	int i, ret;
+
+	/* Create new info device */
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return NULL;
+	memset(info, 0, sizeof(*info));
+
+	link = &info->link;
+	link->priv = info;
+
+	link->release.function = &btuart_release;
+	link->release.data = (u_long)link;
+	link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+	link->io.NumPorts1 = 8;
+	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | 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 = btuart_interrupt;
+	link->irq.Instance = info;
+
+	link->conf.Attributes = CONF_ENABLE_IRQ;
+	link->conf.Vcc = 50;
+	link->conf.IntType = INT_MEMORY_AND_IO;
+
+	/* Register with Card Services */
+	link->next = dev_list;
+	dev_list = link;
+	client_reg.dev_info = &dev_info;
+	client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+	client_reg.EventMask =
+		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+		CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+		CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+	client_reg.event_handler = &btuart_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);
+		btuart_detach(link);
+		return NULL;
+	}
+
+	return link;
+}
+
+
+void btuart_detach(dev_link_t *link)
+{
+	btuart_info_t *info = link->priv;
+	dev_link_t **linkp;
+	int ret;
+
+	/* 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)
+		btuart_release((u_long)link);
+
+	if (link->handle) {
+		ret = CardServices(DeregisterClient, link->handle);
+		if (ret != CS_SUCCESS)
+			cs_error(link->handle, DeregisterClient, ret);
+	}
+
+	/* Unlink device structure, free bits */
+	*linkp = link->next;
+
+	kfree(info);
+}
+
+
+static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
+{
+	int i;
+
+	i = CardServices(fn, handle, tuple);
+	if (i != CS_SUCCESS)
+		return CS_NO_MORE_ITEMS;
+
+	i = CardServices(GetTupleData, handle, tuple);
+	if (i != CS_SUCCESS)
+		return i;
+
+	return CardServices(ParseTuple, handle, tuple, parse);
+}
+
+
+#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
+#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c)
+
+void btuart_config(dev_link_t *link)
+{
+	static ioaddr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
+	client_handle_t handle = link->handle;
+	btuart_info_t *info = link->priv;
+	tuple_t tuple;
+	u_short buf[256];
+	cisparse_t parse;
+	cistpl_cftable_entry_t *cf = &parse.cftable_entry;
+	config_info_t config;
+	int i, j, try, last_ret, last_fn;
+
+	tuple.TupleData = (cisdata_t *)buf;
+	tuple.TupleOffset = 0;
+	tuple.TupleDataMax = 255;
+	tuple.Attributes = 0;
+
+	/* Get configuration register information */
+	tuple.DesiredTuple = CISTPL_CONFIG;
+	last_ret = first_tuple(handle, &tuple, &parse);
+	if (last_ret != CS_SUCCESS) {
+		last_fn = ParseTuple;
+		goto cs_failed;
+	}
+	link->conf.ConfigBase = parse.config.base;
+	link->conf.Present = parse.config.rmask[0];
+
+	/* Configure card */
+	link->state |= DEV_CONFIG;
+	i = CardServices(GetConfigurationInfo, handle, &config);
+	link->conf.Vcc = config.Vcc;
+
+	/* First pass: look for a config entry that looks normal. */
+	tuple.TupleData = (cisdata_t *) buf;
+	tuple.TupleOffset = 0;
+	tuple.TupleDataMax = 255;
+	tuple.Attributes = 0;
+	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+	/* Two tries: without IO aliases, then with aliases */
+	for (try = 0; try < 2; try++) {
+		i = first_tuple(handle, &tuple, &parse);
+		while (i != CS_NO_MORE_ITEMS) {
+			if (i != CS_SUCCESS)
+				goto next_entry;
+			if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
+				link->conf.Vpp1 = link->conf.Vpp2 = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+			if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && (cf->io.win[0].base != 0)) {
+				link->conf.ConfigIndex = cf->index;
+				link->io.BasePort1 = cf->io.win[0].base;
+				link->io.IOAddrLines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
+				i = CardServices(RequestIO, link->handle, &link->io);
+				if (i == CS_SUCCESS)
+					goto found_port;
+			}
+next_entry:
+			i = next_tuple(handle, &tuple, &parse);
+		}
+	}
+
+	/* Second pass: try to find an entry that isn't picky about
+	   its base address, then try to grab any standard serial port
+	   address, and finally try to get any free port. */
+	i = first_tuple(handle, &tuple, &parse);
+	while (i != CS_NO_MORE_ITEMS) {
+		if ((i == CS_SUCCESS) && (cf->io.nwin > 0)
+		    && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
+			link->conf.ConfigIndex = cf->index;
+			for (j = 0; j < 5; j++) {
+				link->io.BasePort1 = base[j];
+				link->io.IOAddrLines = base[j] ? 16 : 3;
+				i = CardServices(RequestIO, link->handle, &link->io);
+				if (i == CS_SUCCESS)
+					goto found_port;
+			}
+		}
+		i = next_tuple(handle, &tuple, &parse);
+	}
+
+found_port:
+	if (i != CS_SUCCESS) {
+		printk(KERN_NOTICE "btuart_cs: No usable port range found. Giving up.\n");
+		cs_error(link->handle, RequestIO, i);
+		goto failed;
+	}
+
+	i = CardServices(RequestIRQ, link->handle, &link->irq);
+	if (i != CS_SUCCESS) {
+		cs_error(link->handle, RequestIRQ, i);
+		link->irq.AssignedIRQ = 0;
+	}
+
+	i = CardServices(RequestConfiguration, link->handle, &link->conf);
+	if (i != CS_SUCCESS) {
+		cs_error(link->handle, RequestConfiguration, i);
+		goto failed;
+	}
+
+	MOD_INC_USE_COUNT;
+
+	if (btuart_open(info) != 0)
+		goto failed;
+
+	strcpy(info->node.dev_name, info->hdev.name);
+	link->dev = &info->node;
+	link->state &= ~DEV_CONFIG_PENDING;
+
+	return;
+
+cs_failed:
+	cs_error(link->handle, last_fn, last_ret);
+
+failed:
+	btuart_release((u_long) link);
+}
+
+
+void btuart_release(u_long arg)
+{
+	dev_link_t *link = (dev_link_t *)arg;
+	btuart_info_t *info = link->priv;
+
+	if (link->state & DEV_PRESENT)
+		btuart_close(info);
+
+	MOD_DEC_USE_COUNT;
+
+	link->dev = NULL;
+
+	CardServices(ReleaseConfiguration, link->handle);
+	CardServices(ReleaseIO, link->handle, &link->io);
+	CardServices(ReleaseIRQ, link->handle, &link->irq);
+
+	link->state &= ~DEV_CONFIG;
+}
+
+
+int btuart_event(event_t event, int priority, event_callback_args_t *args)
+{
+	dev_link_t *link = args->client_data;
+	btuart_info_t *info = link->priv;
+
+	switch (event) {
+	case CS_EVENT_CARD_REMOVAL:
+		link->state &= ~DEV_PRESENT;
+		if (link->state & DEV_CONFIG) {
+			btuart_close(info);
+			mod_timer(&link->release, jiffies + HZ / 20);
+		}
+		break;
+	case CS_EVENT_CARD_INSERTION:
+		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+		btuart_config(link);
+		break;
+	case CS_EVENT_PM_SUSPEND:
+		link->state |= DEV_SUSPEND;
+		/* Fall through... */
+	case CS_EVENT_RESET_PHYSICAL:
+		if (link->state & DEV_CONFIG)
+			CardServices(ReleaseConfiguration, link->handle);
+		break;
+	case CS_EVENT_PM_RESUME:
+		link->state &= ~DEV_SUSPEND;
+		/* Fall through... */
+	case CS_EVENT_CARD_RESET:
+		if (DEV_OK(link))
+			CardServices(RequestConfiguration, link->handle, &link->conf);
+		break;
+	}
+
+	return 0;
+}
+
+
+
+/* ======================== Module initialization ======================== */
+
+
+int __init init_btuart_cs(void)
+{
+	servinfo_t serv;
+	int err;
+
+	CardServices(GetCardServicesInfo, &serv);
+	if (serv.Revision != CS_RELEASE_CODE) {
+		printk(KERN_NOTICE "btuart_cs: Card Services release does not match!\n");
+		return -1;
+	}
+
+	err = register_pccard_driver(&dev_info, &btuart_attach, &btuart_detach);
+
+	return err;
+}
+
+
+void __exit exit_btuart_cs(void)
+{
+	unregister_pccard_driver(&dev_info);
+
+	while (dev_list != NULL)
+		btuart_detach(dev_list);
+}
+
+
+module_init(init_btuart_cs);
+module_exit(exit_btuart_cs);
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/bluetooth/hci_bcsp.c linux-2.4.21-pre6/drivers/bluetooth/hci_bcsp.c
--- linux-2.4.20/drivers/bluetooth/hci_bcsp.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/bluetooth/hci_bcsp.c	2003-03-26 23:49:25.000000000 +0000
@@ -0,0 +1,710 @@
+/* 
+   BlueCore Serial Protocol (BCSP) for Linux Bluetooth stack (BlueZ).
+   Copyright 2002 by Fabrizio Gennari <fabrizio.gennari@philips.com>
+
+   Based on
+       hci_h4.c  by Maxim Krasnyansky <maxk@qualcomm.com>
+       ABCSP     by Carl Orsborn <cjo@csr.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ * $Id: hci_bcsp.c,v 1.2 2002/09/26 05:05:14 maxk Exp $
+ */
+
+#define VERSION "0.1"
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/version.h>
+#include <linux/config.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/poll.h>
+
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/signal.h>
+#include <linux/ioctl.h>
+#include <linux/skbuff.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include "hci_uart.h"
+#include "hci_bcsp.h"
+
+#ifndef HCI_UART_DEBUG
+#undef  BT_DBG
+#define BT_DBG( A... )
+#undef  BT_DMP
+#define BT_DMP( A... )
+#endif
+
+/* ---- BCSP CRC calculation ---- */
+
+/* Table for calculating CRC for polynomial 0x1021, LSB processed first,
+initial value 0xffff, bits shifted in reverse order. */
+
+static const u16 crc_table[] = {
+	0x0000, 0x1081, 0x2102, 0x3183,
+	0x4204, 0x5285, 0x6306, 0x7387,
+	0x8408, 0x9489, 0xa50a, 0xb58b,
+	0xc60c, 0xd68d, 0xe70e, 0xf78f
+};
+
+/* Initialise the crc calculator */
+#define BCSP_CRC_INIT(x) x = 0xffff
+
+/*
+   Update crc with next data byte
+
+   Implementation note
+        The data byte is treated as two nibbles.  The crc is generated
+        in reverse, i.e., bits are fed into the register from the top.
+*/
+static void bcsp_crc_update(u16 *crc, u8 d)
+{
+	u16 reg = *crc;
+
+	reg = (reg >> 4) ^ crc_table[(reg ^ d) & 0x000f];
+	reg = (reg >> 4) ^ crc_table[(reg ^ (d >> 4)) & 0x000f];
+
+	*crc = reg;
+}
+
+/*
+   Get reverse of generated crc
+
+   Implementation note
+        The crc generator (bcsp_crc_init() and bcsp_crc_update())
+        creates a reversed crc, so it needs to be swapped back before
+        being passed on.
+*/
+static u16 bcsp_crc_reverse(u16 crc)
+{
+	u16 b, rev;
+
+	for (b = 0, rev = 0; b < 16; b++) {
+		rev = rev << 1;
+		rev |= (crc & 1);
+		crc = crc >> 1;
+	}
+	return (rev);
+}
+
+/* ---- BCSP core ---- */
+
+static void bcsp_slip_msgdelim(struct sk_buff *skb)
+{
+	const char pkt_delim = 0xc0;
+	memcpy(skb_put(skb, 1), &pkt_delim, 1);
+}
+
+static void bcsp_slip_one_byte(struct sk_buff *skb, u8 c)
+{
+	const char esc_c0[2] = { 0xdb, 0xdc };
+	const char esc_db[2] = { 0xdb, 0xdd };
+
+	switch (c) {
+	case 0xc0:
+		memcpy(skb_put(skb, 2), &esc_c0, 2);
+		break;
+	case 0xdb:
+		memcpy(skb_put(skb, 2), &esc_db, 2);
+		break;
+	default:
+		memcpy(skb_put(skb, 1), &c, 1);
+	}
+}
+
+static int bcsp_enqueue(struct hci_uart *hu, struct sk_buff *skb)
+{
+	struct bcsp_struct *bcsp = hu->priv;
+
+	if (skb->len > 0xFFF) {
+		BT_ERR("Packet too long");
+		kfree_skb(skb);
+		return 0;
+	}
+
+	switch (skb->pkt_type) {
+	case HCI_ACLDATA_PKT:
+	case HCI_COMMAND_PKT:
+		skb_queue_tail(&bcsp->rel, skb);
+		break;
+
+	case HCI_SCODATA_PKT:
+		skb_queue_tail(&bcsp->unrel, skb);
+		break;
+		
+	default:
+		BT_ERR("Unknown packet type");
+		kfree_skb(skb);
+		break;
+	}
+	return 0;
+}
+
+static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data,
+		int len, int pkt_type)
+{
+	struct sk_buff *nskb;
+	u8  hdr[4], chan;
+	int rel, i;
+
+#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
+	u16 BCSP_CRC_INIT(bcsp_txmsg_crc);
+#endif
+
+	switch (pkt_type) {
+	case HCI_ACLDATA_PKT:
+		chan = 6;	/* BCSP ACL channel */
+		rel = 1;	/* reliable channel */
+		break;
+	case HCI_COMMAND_PKT:
+		chan = 5;	/* BCSP cmd/evt channel */
+		rel = 1;	/* reliable channel */
+		break;
+	case HCI_SCODATA_PKT:
+		chan = 7;	/* BCSP SCO channel */
+		rel = 0;	/* unreliable channel */
+		break;
+	case BCSP_LE_PKT:
+		chan = 1;	/* BCSP LE channel */
+		rel = 0;	/* unreliable channel */
+		break;
+	case BCSP_ACK_PKT:
+		chan = 0;	/* BCSP internal channel */
+		rel = 0;	/* unreliable channel */
+		break;
+	default:
+		BT_ERR("Unknown packet type");
+		return NULL;
+	}
+
+	/* Max len of packet: (original len +4(bcsp hdr) +2(crc))*2
+	   (because bytes 0xc0 and 0xdb are escaped, worst case is
+	   when the packet is all made of 0xc0 and 0xdb :) )
+	   + 2 (0xc0 delimiters at start and end). */
+
+	nskb = alloc_skb((len + 6) * 2 + 2, GFP_ATOMIC);
+	if (!nskb)
+		return NULL;
+
+	nskb->pkt_type = pkt_type;
+
+	bcsp_slip_msgdelim(nskb);
+
+	hdr[0] = bcsp->rxseq_txack << 3;
+	bcsp->txack_req = 0;
+	BT_DBG("We request packet no %u to card", bcsp->rxseq_txack);
+
+	if (rel) {
+		hdr[0] |= 0x80 + bcsp->msgq_txseq;
+		BT_DBG("Sending packet with seqno %u", bcsp->msgq_txseq);
+		bcsp->msgq_txseq = ++(bcsp->msgq_txseq) & 0x07;
+	}
+#ifdef  CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
+	hdr[0] |= 0x40;
+#endif
+
+	hdr[1]  = (len << 4) & 0xFF;
+	hdr[1] |= chan;
+	hdr[2]  = len >> 4;
+	hdr[3]  = ~(hdr[0] + hdr[1] + hdr[2]);
+
+	/* Put BCSP header */
+	for (i = 0; i < 4; i++) {
+		bcsp_slip_one_byte(nskb, hdr[i]);
+#ifdef  CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
+		bcsp_crc_update(&bcsp_txmsg_crc, hdr[i]);
+#endif
+	}
+
+	/* Put payload */
+	for (i = 0; i < len; i++) {
+		bcsp_slip_one_byte(nskb, data[i]);
+#ifdef  CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
+		bcsp_crc_update(&bcsp_txmsg_crc, data[i]);
+#endif
+	}
+
+#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
+	/* Put CRC */
+	bcsp_txmsg_crc = bcsp_crc_reverse(bcsp_txmsg_crc);
+	bcsp_slip_one_byte(nskb, (u8) ((bcsp_txmsg_crc >> 8) & 0x00ff));
+	bcsp_slip_one_byte(nskb, (u8) (bcsp_txmsg_crc & 0x00ff));
+#endif
+
+	bcsp_slip_msgdelim(nskb);
+	return nskb;
+}
+
+/* This is a rewrite of pkt_avail in ABCSP */
+static struct sk_buff *bcsp_dequeue(struct hci_uart *hu)
+{
+	struct bcsp_struct *bcsp = (struct bcsp_struct *) hu->priv;
+	unsigned long flags;
+	struct sk_buff *skb;
+	
+	/* First of all, check for unreliable messages in the queue,
+	   since they have priority */
+
+	if ((skb = skb_dequeue(&bcsp->unrel)) != NULL) {
+		struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, skb->data, skb->len, skb->pkt_type);
+		if (nskb) {
+			kfree_skb(skb);
+			return nskb;
+		} else {
+			skb_queue_head(&bcsp->unrel, skb);
+			BT_ERR("Could not dequeue pkt because alloc_skb failed");
+		}
+	}
+
+	/* Now, try to send a reliable pkt. We can only send a
+	   reliable packet if the number of packets sent but not yet ack'ed
+	   is < than the winsize */
+
+	spin_lock_irqsave(&bcsp->unack.lock, flags);
+
+	if (bcsp->unack.qlen < BCSP_TXWINSIZE && (skb = skb_dequeue(&bcsp->rel)) != NULL) {
+		struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, skb->data, skb->len, skb->pkt_type);
+		if (nskb) {
+			__skb_queue_tail(&bcsp->unack, skb);
+			mod_timer(&bcsp->tbcsp, jiffies + HZ / 4);
+			spin_unlock_irqrestore(&bcsp->unack.lock, flags);
+			return nskb;
+		} else {
+			skb_queue_head(&bcsp->rel, skb);
+			BT_ERR("Could not dequeue pkt because alloc_skb failed");
+		}
+	}
+
+	spin_unlock_irqrestore(&bcsp->unack.lock, flags);
+
+
+	/* We could not send a reliable packet, either because there are
+	   none or because there are too many unack'ed pkts. Did we receive
+	   any packets we have not acknowledged yet ? */
+
+	if (bcsp->txack_req) {
+		/* if so, craft an empty ACK pkt and send it on BCSP unreliable
+		   channel 0 */
+		struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, NULL, 0, BCSP_ACK_PKT);
+		return nskb;
+	}
+
+	/* We have nothing to send */
+	return NULL;
+}
+
+static int bcsp_flush(struct hci_uart *hu)
+{
+	BT_DBG("hu %p", hu);
+	return 0;
+}
+
+/* Remove ack'ed packets */
+static void bcsp_pkt_cull(struct bcsp_struct *bcsp)
+{
+	unsigned long flags;
+	struct sk_buff *skb;
+	int i, pkts_to_be_removed;
+	u8 seqno;
+
+	spin_lock_irqsave(&bcsp->unack.lock, flags);
+
+	pkts_to_be_removed = bcsp->unack.qlen;
+	seqno = bcsp->msgq_txseq;
+
+	while (pkts_to_be_removed) {
+		if (bcsp->rxack == seqno)
+			break;
+		pkts_to_be_removed--;
+		seqno = (seqno - 1) & 0x07;
+	}
+
+	if (bcsp->rxack != seqno)
+		BT_ERR("Peer acked invalid packet");
+
+	BT_DBG("Removing %u pkts out of %u, up to seqno %u",
+	       pkts_to_be_removed, bcsp->unack.qlen, (seqno - 1) & 0x07);
+
+	for (i = 0, skb = ((struct sk_buff *) &bcsp->unack)->next; i < pkts_to_be_removed
+			&& skb != (struct sk_buff *) &bcsp->unack; i++) {
+		struct sk_buff *nskb;
+
+		nskb = skb->next;
+		__skb_unlink(skb, &bcsp->unack);
+		kfree_skb(skb);
+		skb = nskb;
+	}
+	if (bcsp->unack.qlen == 0)
+		del_timer(&bcsp->tbcsp);
+	spin_unlock_irqrestore(&bcsp->unack.lock, flags);
+
+	if (i != pkts_to_be_removed)
+		BT_ERR("Removed only %u out of %u pkts", i, pkts_to_be_removed);
+}
+
+/* Handle BCSP link-establishment packets. When we
+   detect a "sync" packet, symptom that the BT module has reset,
+   we do nothing :) (yet) */
+static void bcsp_handle_le_pkt(struct hci_uart *hu)
+{
+	struct bcsp_struct *bcsp = hu->priv;
+	u8 conf_pkt[4]     = { 0xad, 0xef, 0xac, 0xed };
+	u8 conf_rsp_pkt[4] = { 0xde, 0xad, 0xd0, 0xd0 };
+	u8 sync_pkt[4]     = { 0xda, 0xdc, 0xed, 0xed };
+
+	/* spot "conf" pkts and reply with a "conf rsp" pkt */
+	if (bcsp->rx_skb->data[1] >> 4 == 4 && bcsp->rx_skb->data[2] == 0 &&
+			!memcmp(&bcsp->rx_skb->data[4], conf_pkt, 4)) {
+		struct sk_buff *nskb = alloc_skb(4, GFP_ATOMIC);
+
+		BT_DBG("Found a LE conf pkt");
+		if (!nskb)
+			return;
+		memcpy(skb_put(nskb, 4), conf_rsp_pkt, 4);
+		nskb->pkt_type = BCSP_LE_PKT;
+
+		skb_queue_head(&bcsp->unrel, nskb);
+		hci_uart_tx_wakeup(hu);
+	}
+	/* Spot "sync" pkts. If we find one...disaster! */
+	else if (bcsp->rx_skb->data[1] >> 4 == 4 && bcsp->rx_skb->data[2] == 0 &&
+			!memcmp(&bcsp->rx_skb->data[4], sync_pkt, 4)) {
+		BT_ERR("Found a LE sync pkt, card has reset");
+	}
+}
+
+static inline void bcsp_unslip_one_byte(struct bcsp_struct *bcsp, unsigned char byte)
+{
+	const u8 c0 = 0xc0, db = 0xdb;
+
+	switch (bcsp->rx_esc_state) {
+	case BCSP_ESCSTATE_NOESC:
+		switch (byte) {
+		case 0xdb:
+			bcsp->rx_esc_state = BCSP_ESCSTATE_ESC;
+			break;
+		default:
+			memcpy(skb_put(bcsp->rx_skb, 1), &byte, 1);
+			if ((bcsp->rx_skb-> data[0] & 0x40) != 0 && 
+					bcsp->rx_state != BCSP_W4_CRC)
+				bcsp_crc_update(&bcsp->message_crc, byte);
+			bcsp->rx_count--;
+		}
+		break;
+
+	case BCSP_ESCSTATE_ESC:
+		switch (byte) {
+		case 0xdc:
+			memcpy(skb_put(bcsp->rx_skb, 1), &c0, 1);
+			if ((bcsp->rx_skb-> data[0] & 0x40) != 0 && 
+					bcsp->rx_state != BCSP_W4_CRC)
+				bcsp_crc_update(&bcsp-> message_crc, 0xc0);
+			bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC;
+			bcsp->rx_count--;
+			break;
+
+		case 0xdd:
+			memcpy(skb_put(bcsp->rx_skb, 1), &db, 1);
+			if ((bcsp->rx_skb-> data[0] & 0x40) != 0 && 
+					bcsp->rx_state != BCSP_W4_CRC) 
+				bcsp_crc_update(&bcsp-> message_crc, 0xdb);
+			bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC;
+			bcsp->rx_count--;
+			break;
+
+		default:
+			BT_ERR ("Invalid byte %02x after esc byte", byte);
+			kfree_skb(bcsp->rx_skb);
+			bcsp->rx_skb = NULL;
+			bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
+			bcsp->rx_count = 0;
+		}
+	}
+}
+
+static inline void bcsp_complete_rx_pkt(struct hci_uart *hu)
+{
+	struct bcsp_struct *bcsp = hu->priv;
+	int pass_up;
+
+	if (bcsp->rx_skb->data[0] & 0x80) {	/* reliable pkt */
+		BT_DBG("Received seqno %u from card", bcsp->rxseq_txack);
+		bcsp->rxseq_txack++;
+		bcsp->rxseq_txack %= 0x8;
+		bcsp->txack_req    = 1;
+
+		/* If needed, transmit an ack pkt */
+		hci_uart_tx_wakeup(hu);
+	}
+
+	bcsp->rxack = (bcsp->rx_skb->data[0] >> 3) & 0x07;
+	BT_DBG("Request for pkt %u from card", bcsp->rxack);
+
+	bcsp_pkt_cull(bcsp);
+	if ((bcsp->rx_skb->data[1] & 0x0f) == 6 &&
+			bcsp->rx_skb->data[0] & 0x80) {
+		bcsp->rx_skb->pkt_type = HCI_ACLDATA_PKT;
+		pass_up = 1;
+	} else if ((bcsp->rx_skb->data[1] & 0x0f) == 5 &&
+			bcsp->rx_skb->data[0] & 0x80) {
+		bcsp->rx_skb->pkt_type = HCI_EVENT_PKT;
+		pass_up = 1;
+	} else if ((bcsp->rx_skb->data[1] & 0x0f) == 7) {
+		bcsp->rx_skb->pkt_type = HCI_SCODATA_PKT;
+		pass_up = 1;
+	} else if ((bcsp->rx_skb->data[1] & 0x0f) == 1 &&
+			!(bcsp->rx_skb->data[0] & 0x80)) {
+		bcsp_handle_le_pkt(hu);
+		pass_up = 0;
+	} else
+		pass_up = 0;
+
+	if (!pass_up) {
+		if ((bcsp->rx_skb->data[1] & 0x0f) != 0 &&
+	    		(bcsp->rx_skb->data[1] & 0x0f) != 1) {
+			BT_ERR ("Packet for unknown channel (%u %s)",
+				bcsp->rx_skb->data[1] & 0x0f,
+				bcsp->rx_skb->data[0] & 0x80 ? 
+				"reliable" : "unreliable");
+		}
+		kfree_skb(bcsp->rx_skb);
+	} else {
+		/* Pull out BCSP hdr */
+		skb_pull(bcsp->rx_skb, 4);
+
+		hci_recv_frame(bcsp->rx_skb);
+	}
+	bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
+	bcsp->rx_skb = NULL;
+}
+
+/* Recv data */
+static int bcsp_recv(struct hci_uart *hu, void *data, int count)
+{
+	struct bcsp_struct *bcsp = hu->priv;
+	register unsigned char *ptr;
+
+	BT_DBG("hu %p count %d rx_state %ld rx_count %ld", 
+		hu, count, bcsp->rx_state, bcsp->rx_count);
+
+	ptr = data;
+	while (count) {
+		if (bcsp->rx_count) {
+			if (*ptr == 0xc0) {
+				BT_ERR("Short BCSP packet");
+				kfree_skb(bcsp->rx_skb);
+				bcsp->rx_state = BCSP_W4_PKT_START;
+				bcsp->rx_count = 0;
+			} else
+				bcsp_unslip_one_byte(bcsp, *ptr);
+
+			ptr++; count--;
+			continue;
+		}
+
+		switch (bcsp->rx_state) {
+		case BCSP_W4_BCSP_HDR:
+			if ((0xff & (u8) ~ (bcsp->rx_skb->data[0] + bcsp->rx_skb->data[1] +
+					bcsp->rx_skb->data[2])) != bcsp->rx_skb->data[3]) {
+				BT_ERR("Error in BCSP hdr checksum");
+				kfree_skb(bcsp->rx_skb);
+				bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
+				bcsp->rx_count = 0;
+				continue;
+			}
+			if (bcsp->rx_skb->data[0] & 0x80	/* reliable pkt */
+			    		&& (bcsp->rx_skb->data[0] & 0x07) != bcsp->rxseq_txack) {
+				BT_ERR ("Out-of-order packet arrived, got %u expected %u",
+					bcsp->rx_skb->data[0] & 0x07, bcsp->rxseq_txack);
+
+				kfree_skb(bcsp->rx_skb);
+				bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
+				bcsp->rx_count = 0;
+				continue;
+			}
+			bcsp->rx_state = BCSP_W4_DATA;
+			bcsp->rx_count = (bcsp->rx_skb->data[1] >> 4) + 
+					(bcsp->rx_skb->data[2] << 4);	/* May be 0 */
+			continue;
+
+		case BCSP_W4_DATA:
+			if (bcsp->rx_skb->data[0] & 0x40) {	/* pkt with crc */
+				bcsp->rx_state = BCSP_W4_CRC;
+				bcsp->rx_count = 2;
+			} else
+				bcsp_complete_rx_pkt(hu);
+			continue;
+
+		case BCSP_W4_CRC:
+			if (bcsp_crc_reverse(bcsp->message_crc) !=
+					(bcsp->rx_skb->data[bcsp->rx_skb->len - 2] << 8) +
+					bcsp->rx_skb->data[bcsp->rx_skb->len - 1]) {
+
+				BT_ERR ("Checksum failed: computed %04x received %04x",
+					bcsp_crc_reverse(bcsp->message_crc),
+				     	(bcsp->rx_skb-> data[bcsp->rx_skb->len - 2] << 8) +
+				     	bcsp->rx_skb->data[bcsp->rx_skb->len - 1]);
+
+				kfree_skb(bcsp->rx_skb);
+				bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
+				bcsp->rx_count = 0;
+				continue;
+			}
+			skb_trim(bcsp->rx_skb, bcsp->rx_skb->len - 2);
+			bcsp_complete_rx_pkt(hu);
+			continue;
+
+		case BCSP_W4_PKT_DELIMITER:
+			switch (*ptr) {
+			case 0xc0:
+				bcsp->rx_state = BCSP_W4_PKT_START;
+				break;
+			default:
+				/*BT_ERR("Ignoring byte %02x", *ptr);*/
+				break;
+			}
+			ptr++; count--;
+			break;
+
+		case BCSP_W4_PKT_START:
+			switch (*ptr) {
+			case 0xc0:
+				ptr++; count--;
+				break;
+
+			default:
+				bcsp->rx_state = BCSP_W4_BCSP_HDR;
+				bcsp->rx_count = 4;
+				bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC;
+				BCSP_CRC_INIT(bcsp->message_crc);
+				
+				/* Do not increment ptr or decrement count
+				 * Allocate packet. Max len of a BCSP pkt= 
+				 * 0xFFF (payload) +4 (header) +2 (crc) */
+
+				bcsp->rx_skb = bluez_skb_alloc(0x1005, GFP_ATOMIC);
+				if (!bcsp->rx_skb) {
+					BT_ERR("Can't allocate mem for new packet");
+					bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
+					bcsp->rx_count = 0;
+					return 0;
+				}
+				bcsp->rx_skb->dev = (void *) &hu->hdev;
+				break;
+			}
+			break;
+		}
+	}
+	return count;
+}
+
+	/* Arrange to retransmit all messages in the relq. */
+static void bcsp_timed_event(unsigned long arg)
+{
+	struct hci_uart *hu = (struct hci_uart *) arg;
+	struct bcsp_struct *bcsp = (struct bcsp_struct *) hu->priv;
+	struct sk_buff *skb;
+	unsigned long flags;
+
+	BT_ERR("Timeout, retransmitting %u pkts", bcsp->unack.qlen);
+	spin_lock_irqsave(&bcsp->unack.lock, flags);
+
+	while ((skb = __skb_dequeue_tail(&bcsp->unack)) != NULL) {
+		bcsp->msgq_txseq = (bcsp->msgq_txseq - 1) & 0x07;
+		skb_queue_head(&bcsp->rel, skb);
+	}
+
+	spin_unlock_irqrestore(&bcsp->unack.lock, flags);
+
+	hci_uart_tx_wakeup(hu);
+}
+
+static int bcsp_open(struct hci_uart *hu)
+{
+	struct bcsp_struct *bcsp;
+
+	BT_DBG("hu %p", hu);
+
+	bcsp = kmalloc(sizeof(*bcsp), GFP_ATOMIC);
+	if (!bcsp)
+		return -ENOMEM;
+	memset(bcsp, 0, sizeof(*bcsp));
+
+	hu->priv = bcsp;
+	skb_queue_head_init(&bcsp->unack);
+	skb_queue_head_init(&bcsp->rel);
+	skb_queue_head_init(&bcsp->unrel);
+
+	init_timer(&bcsp->tbcsp);
+	bcsp->tbcsp.function = bcsp_timed_event;
+	bcsp->tbcsp.data     = (u_long) hu;
+
+	bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
+
+	return 0;
+}
+
+static int bcsp_close(struct hci_uart *hu)
+{
+	struct bcsp_struct *bcsp = hu->priv;
+	hu->priv = NULL;
+
+	BT_DBG("hu %p", hu);
+
+	skb_queue_purge(&bcsp->unack);
+	skb_queue_purge(&bcsp->rel);
+	skb_queue_purge(&bcsp->unrel);
+	del_timer(&bcsp->tbcsp);
+
+	kfree(bcsp);
+	return 0;
+}
+
+static struct hci_uart_proto bcsp = {
+	id:      HCI_UART_BCSP,
+	open:    bcsp_open,
+	close:   bcsp_close,
+	enqueue: bcsp_enqueue,
+	dequeue: bcsp_dequeue,
+	recv:    bcsp_recv,
+	flush:   bcsp_flush
+};
+
+int bcsp_init(void)
+{
+	return hci_uart_register_proto(&bcsp);
+}
+
+int bcsp_deinit(void)
+{
+	return hci_uart_unregister_proto(&bcsp);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/bluetooth/hci_bcsp.h linux-2.4.21-pre6/drivers/bluetooth/hci_bcsp.h
--- linux-2.4.20/drivers/bluetooth/hci_bcsp.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/bluetooth/hci_bcsp.h	2003-03-26 23:49:50.000000000 +0000
@@ -0,0 +1,70 @@
+/* 
+   BlueCore Serial Protocol (BCSP) for Linux Bluetooth stack (BlueZ).
+   Copyright 2002 by Fabrizio Gennari <fabrizio.gennari@philips.com>
+
+   Based on
+       hci_h4.c  by Maxim Krasnyansky <maxk@qualcomm.com>
+       ABCSP     by Carl Orsborn <cjo@csr.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/* 
+ * $Id: hci_bcsp.h,v 1.2 2002/09/26 05:05:14 maxk Exp $
+ */
+
+#ifndef __HCI_BCSP_H__
+#define __HCI_BCSP_H__
+
+#define BCSP_TXWINSIZE  4
+
+#define BCSP_ACK_PKT    0x05
+#define BCSP_LE_PKT     0x06
+
+struct bcsp_struct {
+	struct sk_buff_head unack;	/* Unack'ed packets queue */
+	struct sk_buff_head rel;	/* Reliable packets queue */
+	struct sk_buff_head unrel;	/* Unreliable packets queue */
+
+	unsigned long rx_count;
+	struct  sk_buff *rx_skb;
+	u8      rxseq_txack;		/* rxseq == txack. */
+	u8      rxack;			/* Last packet sent by us that the peer ack'ed */
+	struct  timer_list tbcsp;
+	
+	enum {
+		BCSP_W4_PKT_DELIMITER,
+		BCSP_W4_PKT_START,
+		BCSP_W4_BCSP_HDR,
+		BCSP_W4_DATA,
+		BCSP_W4_CRC
+	} rx_state;
+
+	enum {
+		BCSP_ESCSTATE_NOESC,
+		BCSP_ESCSTATE_ESC
+	} rx_esc_state;
+
+	u16     message_crc;
+	u8      txack_req;		/* Do we need to send ack's to the peer? */
+
+	/* Reliable packet sequence number - used to assign seq to each rel pkt. */
+	u8      msgq_txseq;
+};
+
+#endif	/* __HCI_BCSP_H__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/bluetooth/hci_h4.c linux-2.4.21-pre6/drivers/bluetooth/hci_h4.c
--- linux-2.4.20/drivers/bluetooth/hci_h4.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/drivers/bluetooth/hci_h4.c	2003-03-26 23:49:50.000000000 +0000
@@ -25,15 +25,14 @@
 /*
  * BlueZ HCI UART(H4) protocol.
  *
- * $Id: hci_h4.c,v 1.2 2002/04/17 17:37:20 maxk Exp $    
+ * $Id: hci_h4.c,v 1.3 2002/09/09 01:17:32 maxk Exp $    
  */
-#define VERSION "1.1"
+#define VERSION "1.2"
 
 #include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/version.h>
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/sched.h>
@@ -64,63 +63,61 @@
 #endif
 
 /* Initialize protocol */
-static int h4_open(struct n_hci *n_hci)
+static int h4_open(struct hci_uart *hu)
 {
 	struct h4_struct *h4;
 	
-	BT_DBG("n_hci %p", n_hci);
+	BT_DBG("hu %p", hu);
 	
 	h4 = kmalloc(sizeof(*h4), GFP_ATOMIC);
 	if (!h4)
 		return -ENOMEM;
 	memset(h4, 0, sizeof(*h4));
 
-	n_hci->priv = h4;
+	skb_queue_head_init(&h4->txq);
+
+	hu->priv = h4;
 	return 0;
 }
 
 /* Flush protocol data */
-static int h4_flush(struct n_hci *n_hci)
+static int h4_flush(struct hci_uart *hu)
 {
-	BT_DBG("n_hci %p", n_hci);
+	struct h4_struct *h4 = hu->priv;
+
+	BT_DBG("hu %p", hu);
+	skb_queue_purge(&h4->txq);
 	return 0;
 }
 
 /* Close protocol */
-static int h4_close(struct n_hci *n_hci)
+static int h4_close(struct hci_uart *hu)
 {
-	struct h4_struct *h4 = n_hci->priv;
-	n_hci->priv = NULL;
+	struct h4_struct *h4 = hu->priv;
+	hu->priv = NULL;
 
-	BT_DBG("n_hci %p", n_hci);
+	BT_DBG("hu %p", hu);
 
+	skb_queue_purge(&h4->txq);
 	if (h4->rx_skb)
 		kfree_skb(h4->rx_skb);
 
+	hu->priv = NULL;
 	kfree(h4);
 	return 0;
 }
 
-/* Send data */
-static int h4_send(struct n_hci *n_hci, void *data, int len)
+/* Enqueue frame for transmittion (padding, crc, etc) */
+static int h4_enqueue(struct hci_uart *hu, struct sk_buff *skb)
 {
-	struct tty_struct *tty = n_hci->tty;
-	
-	BT_DBG("n_hci %p len %d", n_hci, len);
+	struct h4_struct *h4 = hu->priv;
 
-	/* Send frame to TTY driver */
-	tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
-	return tty->driver.write(tty, 0, data, len);
-}
-
-/* Init frame before queueing (padding, crc, etc) */
-static struct sk_buff* h4_preq(struct n_hci *n_hci, struct sk_buff *skb)
-{
-	BT_DBG("n_hci %p skb %p", n_hci, skb);
+	BT_DBG("hu %p skb %p", hu, skb);
 
 	/* Prepend skb with frame type */
 	memcpy(skb_push(skb, 1), &skb->pkt_type, 1);
-	return skb;
+	skb_queue_tail(&h4->txq, skb);
+	return 0;
 }
 
 static inline int h4_check_data_len(struct h4_struct *h4, int len)
@@ -132,7 +129,7 @@
 		BT_DMP(h4->rx_skb->data, h4->rx_skb->len);
 		hci_recv_frame(h4->rx_skb);
 	} else if (len > room) {
-		BT_ERR("Data length is to large");
+		BT_ERR("Data length is too large");
 		kfree_skb(h4->rx_skb);
 	} else {
 		h4->rx_state = H4_W4_DATA;
@@ -147,16 +144,17 @@
 }
 
 /* Recv data */
-static int h4_recv(struct n_hci *n_hci, void *data, int count)
+static int h4_recv(struct hci_uart *hu, void *data, int count)
 {
-	struct h4_struct *h4 = n_hci->priv;
+	struct h4_struct *h4 = hu->priv;
 	register char *ptr;
 	hci_event_hdr *eh;
 	hci_acl_hdr   *ah;
 	hci_sco_hdr   *sh;
 	register int len, type, dlen;
 
-	BT_DBG("n_hci %p count %d rx_state %ld rx_count %ld", n_hci, count, h4->rx_state, h4->rx_count);
+	BT_DBG("hu %p count %d rx_state %ld rx_count %ld", 
+			hu, count, h4->rx_state, h4->rx_count);
 
 	ptr = data;
 	while (count) {
@@ -204,7 +202,7 @@
 
 				h4_check_data_len(h4, sh->dlen);
 				continue;
-			};
+			}
 		}
 
 		/* H4_W4_PACKET_TYPE */
@@ -232,7 +230,7 @@
 
 		default:
 			BT_ERR("Unknown HCI packet type %2.2x", (__u8)*ptr);
-			n_hci->hdev.stat.err_rx++;
+			hu->hdev.stat.err_rx++;
 			ptr++; count--;
 			continue;
 		};
@@ -246,20 +244,26 @@
 			h4->rx_count = 0;
 			return 0;
 		}
-		h4->rx_skb->dev = (void *) &n_hci->hdev;
+		h4->rx_skb->dev = (void *) &hu->hdev;
 		h4->rx_skb->pkt_type = type;
 	}
 	return count;
 }
 
+static struct sk_buff *h4_dequeue(struct hci_uart *hu)
+{
+	struct h4_struct *h4 = hu->priv;
+	return skb_dequeue(&h4->txq);
+}
+
 static struct hci_uart_proto h4p = {
-	id:    HCI_UART_H4,
-	open:  h4_open,
-	close: h4_close,
-	send:  h4_send,
-	recv:  h4_recv,
-	preq:  h4_preq,
-	flush: h4_flush,
+	id:      HCI_UART_H4,
+	open:    h4_open,
+	close:   h4_close,
+	recv:    h4_recv,
+	enqueue: h4_enqueue,
+	dequeue: h4_dequeue,
+	flush:   h4_flush,
 };
 	      
 int h4_init(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/bluetooth/hci_h4.h linux-2.4.21-pre6/drivers/bluetooth/hci_h4.h
--- linux-2.4.20/drivers/bluetooth/hci_h4.h	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/drivers/bluetooth/hci_h4.h	2003-03-26 23:49:20.000000000 +0000
@@ -23,7 +23,7 @@
 */
 
 /*
- * $Id: hci_h4.h,v 1.1.1.1 2002/03/08 21:03:15 maxk Exp $
+ * $Id: hci_h4.h,v 1.2 2002/09/09 01:17:32 maxk Exp $
  */
 
 #ifdef __KERNEL__
@@ -31,6 +31,7 @@
 	unsigned long rx_state;
 	unsigned long rx_count;
 	struct sk_buff *rx_skb;
+	struct sk_buff_head txq;
 };
 
 /* H4 receiver States */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/bluetooth/hci_ldisc.c linux-2.4.21-pre6/drivers/bluetooth/hci_ldisc.c
--- linux-2.4.20/drivers/bluetooth/hci_ldisc.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/bluetooth/hci_ldisc.c	2003-03-26 23:49:25.000000000 +0000
@@ -25,14 +25,15 @@
 /*
  * BlueZ HCI UART driver.
  *
- * $Id: hci_ldisc.c,v 1.2 2002/04/17 17:37:20 maxk Exp $    
+ * $Id: hci_ldisc.c,v 1.5 2002/10/02 18:37:20 maxk Exp $    
  */
-#define VERSION "2.0"
+#define VERSION "2.1"
 
 #include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/version.h>
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/sched.h>
@@ -87,16 +88,86 @@
 	return 0;
 }
 
-static struct hci_uart_proto *n_hci_get_proto(unsigned int id)
+static struct hci_uart_proto *hci_uart_get_proto(unsigned int id)
 {
 	if (id >= HCI_UART_MAX_PROTO)
 		return NULL;
 	return hup[id];
 }
 
+static inline void hci_uart_tx_complete(struct hci_uart *hu, int pkt_type)
+{
+	struct hci_dev *hdev = &hu->hdev;
+	
+	/* Update HCI stat counters */
+	switch (pkt_type) {
+	case HCI_COMMAND_PKT:
+		hdev->stat.cmd_tx++;
+		break;
+
+	case HCI_ACLDATA_PKT:
+		hdev->stat.acl_tx++;
+		break;
+
+	case HCI_SCODATA_PKT:
+		hdev->stat.cmd_tx++;
+		break;
+	}
+}
+
+static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu)
+{
+	struct sk_buff *skb = hu->tx_skb;
+	if (!skb)
+		skb = hu->proto->dequeue(hu);
+	else
+		hu->tx_skb = NULL;
+	return skb;
+}
+
+int hci_uart_tx_wakeup(struct hci_uart *hu)
+{
+	struct tty_struct *tty = hu->tty;
+	struct hci_dev *hdev = &hu->hdev;
+	struct sk_buff *skb;
+	
+	if (test_and_set_bit(HCI_UART_SENDING, &hu->tx_state)) {
+		set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state);
+		return 0;
+	}
+
+	BT_DBG("");
+
+restart:
+	clear_bit(HCI_UART_TX_WAKEUP, &hu->tx_state);
+
+	while ((skb = hci_uart_dequeue(hu))) {
+		int len;
+	
+		set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+		len = tty->driver.write(tty, 0, skb->data, skb->len);
+		hdev->stat.byte_tx += len;
+
+		skb_pull(skb, len);
+		if (skb->len) {
+			hu->tx_skb = skb;
+			break;
+		}
+	
+		hci_uart_tx_complete(hu, skb->pkt_type);
+		kfree_skb(skb);
+	} 
+	
+	if (test_bit(HCI_UART_TX_WAKEUP, &hu->tx_state))
+		goto restart;
+
+	clear_bit(HCI_UART_SENDING, &hu->tx_state);
+	return 0;
+}
+
 /* ------- Interface to HCI layer ------ */
 /* Initialize device */
-static int n_hci_open(struct hci_dev *hdev)
+static int hci_uart_open(struct hci_dev *hdev)
 {
 	BT_DBG("%s %p", hdev->name, hdev);
 
@@ -107,15 +178,16 @@
 }
 
 /* Reset device */
-static int n_hci_flush(struct hci_dev *hdev)
+static int hci_uart_flush(struct hci_dev *hdev)
 {
-	struct n_hci *n_hci  = (struct n_hci *) hdev->driver_data;
-	struct tty_struct *tty = n_hci->tty;
+	struct hci_uart *hu  = (struct hci_uart *) hdev->driver_data;
+	struct tty_struct *tty = hu->tty;
 
 	BT_DBG("hdev %p tty %p", hdev, tty);
 
-	/* Drop TX queue */
-	skb_queue_purge(&n_hci->txq);
+	if (hu->tx_skb) {
+		kfree_skb(hu->tx_skb); hu->tx_skb = NULL;
+	}
 
 	/* Flush any pending characters in the driver and discipline. */
 	if (tty->ldisc.flush_buffer)
@@ -124,80 +196,30 @@
 	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
 
-	if (n_hci->proto->flush)
-		n_hci->proto->flush(n_hci);
+	if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
+		hu->proto->flush(hu);
 
 	return 0;
 }
 
 /* Close device */
-static int n_hci_close(struct hci_dev *hdev)
+static int hci_uart_close(struct hci_dev *hdev)
 {
 	BT_DBG("hdev %p", hdev);
 
 	if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
 		return 0;
 
-	n_hci_flush(hdev);
-	return 0;
-}
-
-static int n_hci_tx_wakeup(struct n_hci *n_hci)
-{
-	struct hci_dev *hdev = &n_hci->hdev;
-	
-	if (test_and_set_bit(N_HCI_SENDING, &n_hci->tx_state)) {
-		set_bit(N_HCI_TX_WAKEUP, &n_hci->tx_state);
-		return 0;
-	}
-
-	BT_DBG("");
-	do {
-		register struct sk_buff *skb;
-		register int len;
-
-		clear_bit(N_HCI_TX_WAKEUP, &n_hci->tx_state);
-
-		if (!(skb = skb_dequeue(&n_hci->txq)))
-			break;
-
-		len = n_hci->proto->send(n_hci, skb->data, skb->len);
-		n_hci->hdev.stat.byte_tx += len;
-
-		if (len == skb->len) {
-			/* Complete frame was sent */
-
-			switch (skb->pkt_type) {
-			case HCI_COMMAND_PKT:
-				hdev->stat.cmd_tx++;
-				break;
-
-			case HCI_ACLDATA_PKT:
-				hdev->stat.acl_tx++;
-				break;
-
-			case HCI_SCODATA_PKT:
-				hdev->stat.cmd_tx++;
-				break;
-			};
-
-			kfree_skb(skb);
-		} else {
-			/* Subtract sent part and requeue  */
-			skb_pull(skb, len);
-			skb_queue_head(&n_hci->txq, skb);
-		}
-	} while (test_bit(N_HCI_TX_WAKEUP, &n_hci->tx_state));
-	clear_bit(N_HCI_SENDING, &n_hci->tx_state);
+	hci_uart_flush(hdev);
 	return 0;
 }
 
 /* Send frames from HCI layer */
-static int n_hci_send_frame(struct sk_buff *skb)
+static int hci_uart_send_frame(struct sk_buff *skb)
 {
 	struct hci_dev* hdev = (struct hci_dev *) skb->dev;
 	struct tty_struct *tty;
-	struct n_hci *n_hci;
+	struct hci_uart *hu;
 
 	if (!hdev) {
 		BT_ERR("Frame for uknown device (hdev=NULL)");
@@ -207,66 +229,60 @@
 	if (!test_bit(HCI_RUNNING, &hdev->flags))
 		return -EBUSY;
 
-	n_hci = (struct n_hci *) hdev->driver_data;
-	tty = n_hci->tty;
+	hu = (struct hci_uart *) hdev->driver_data;
+	tty = hu->tty;
 
 	BT_DBG("%s: type %d len %d", hdev->name, skb->pkt_type, skb->len);
 
-	if (n_hci->proto->preq) {
-		skb = n_hci->proto->preq(n_hci, skb);
-		if (!skb)
-			return 0;
-	}
-	
-	skb_queue_tail(&n_hci->txq, skb);
-	n_hci_tx_wakeup(n_hci);
+	hu->proto->enqueue(hu, skb);
+
+	hci_uart_tx_wakeup(hu);
 	return 0;
 }
 
-static void n_hci_destruct(struct hci_dev *hdev)
+static void hci_uart_destruct(struct hci_dev *hdev)
 {
-	struct n_hci *n_hci;
+	struct hci_uart *hu;
 
 	if (!hdev) return;
 
 	BT_DBG("%s", hdev->name);
 
-	n_hci = (struct n_hci *) hdev->driver_data;
-	kfree(n_hci);
+	hu = (struct hci_uart *) hdev->driver_data;
+	kfree(hu);
 
 	MOD_DEC_USE_COUNT;
 }
 
 /* ------ LDISC part ------ */
-/* n_hci_tty_open
+/* hci_uart_tty_open
  * 
- *     Called when line discipline changed to N_HCI.
+ *     Called when line discipline changed to HCI_UART.
  *
  * Arguments:
  *     tty    pointer to tty info structure
  * Return Value:    
  *     0 if success, otherwise error code
  */
-static int n_hci_tty_open(struct tty_struct *tty)
+static int hci_uart_tty_open(struct tty_struct *tty)
 {
-	struct n_hci *n_hci = (void *)tty->disc_data;
+	struct hci_uart *hu = (void *) tty->disc_data;
 
 	BT_DBG("tty %p", tty);
 
-	if (n_hci)
+	if (hu)
 		return -EEXIST;
 
-	if (!(n_hci = kmalloc(sizeof(struct n_hci), GFP_KERNEL))) {
+	if (!(hu = kmalloc(sizeof(struct hci_uart), GFP_KERNEL))) {
 		BT_ERR("Can't allocate controll structure");
 		return -ENFILE;
 	}
-	memset(n_hci, 0, sizeof(struct n_hci));
+	memset(hu, 0, sizeof(struct hci_uart));
 
-	tty->disc_data = n_hci;
-	n_hci->tty = tty;
+	tty->disc_data = hu;
+	hu->tty = tty;
 
-	spin_lock_init(&n_hci->rx_lock);
-	skb_queue_head_init(&n_hci->txq);
+	spin_lock_init(&hu->rx_lock);
 
 	/* Flush any pending characters in the driver and line discipline */
 	if (tty->ldisc.flush_buffer)
@@ -279,34 +295,34 @@
 	return 0;
 }
 
-/* n_hci_tty_close()
+/* hci_uart_tty_close()
  *
  *    Called when the line discipline is changed to something
  *    else, the tty is closed, or the tty detects a hangup.
  */
-static void n_hci_tty_close(struct tty_struct *tty)
+static void hci_uart_tty_close(struct tty_struct *tty)
 {
-	struct n_hci *n_hci = (void *)tty->disc_data;
+	struct hci_uart *hu = (void *)tty->disc_data;
 
 	BT_DBG("tty %p", tty);
 
 	/* Detach from the tty */
 	tty->disc_data = NULL;
 
-	if (n_hci) {
-		struct hci_dev *hdev = &n_hci->hdev;
-		n_hci_close(hdev);
+	if (hu) {
+		struct hci_dev *hdev = &hu->hdev;
+		hci_uart_close(hdev);
 
-		if (test_and_clear_bit(N_HCI_PROTO_SET, &n_hci->flags)) {
-			n_hci->proto->close(n_hci);
+		if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) {
+			hu->proto->close(hu);
 			hci_unregister_dev(hdev);
 		}
-				
+
 		MOD_DEC_USE_COUNT;
 	}
 }
 
-/* n_hci_tty_wakeup()
+/* hci_uart_tty_wakeup()
  *
  *    Callback for transmit wakeup. Called when low level
  *    device driver can accept more send data.
@@ -314,24 +330,25 @@
  * Arguments:        tty    pointer to associated tty instance data
  * Return Value:    None
  */
-static void n_hci_tty_wakeup( struct tty_struct *tty )
+static void hci_uart_tty_wakeup(struct tty_struct *tty)
 {
-	struct n_hci *n_hci = (void *)tty->disc_data;
+	struct hci_uart *hu = (void *)tty->disc_data;
 
 	BT_DBG("");
 
-	if (!n_hci)
+	if (!hu)
 		return;
 
-	tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+	clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
 
-	if (tty != n_hci->tty)
+	if (tty != hu->tty)
 		return;
 
-	n_hci_tx_wakeup(n_hci);
+	if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
+		hci_uart_tx_wakeup(hu);
 }
 
-/* n_hci_tty_room()
+/* hci_uart_tty_room()
  * 
  *    Callback function from tty driver. Return the amount of 
  *    space left in the receiver's buffer to decide if remote
@@ -340,12 +357,12 @@
  * Arguments:        tty    pointer to associated tty instance data
  * Return Value:    number of bytes left in receive buffer
  */
-static int n_hci_tty_room (struct tty_struct *tty)
+static int hci_uart_tty_room (struct tty_struct *tty)
 {
 	return 65536;
 }
 
-/* n_hci_tty_receive()
+/* hci_uart_tty_receive()
  * 
  *     Called by tty low level driver when receive data is
  *     available.
@@ -357,42 +374,42 @@
  *     
  * Return Value:    None
  */
-static void n_hci_tty_receive(struct tty_struct *tty, const __u8 * data, char *flags, int count)
+static void hci_uart_tty_receive(struct tty_struct *tty, const __u8 *data, char *flags, int count)
 {
-	struct n_hci *n_hci = (void *)tty->disc_data;
+	struct hci_uart *hu = (void *)tty->disc_data;
 	
-	if (!n_hci || tty != n_hci->tty)
+	if (!hu || tty != hu->tty)
 		return;
 
-	if (!test_bit(N_HCI_PROTO_SET, &n_hci->flags))
+	if (!test_bit(HCI_UART_PROTO_SET, &hu->flags))
 		return;
 	
-	spin_lock(&n_hci->rx_lock);
-	n_hci->proto->recv(n_hci, (void *) data, count);
-	n_hci->hdev.stat.byte_rx += count;
-	spin_unlock(&n_hci->rx_lock);
+	spin_lock(&hu->rx_lock);
+	hu->proto->recv(hu, (void *) data, count);
+	hu->hdev.stat.byte_rx += count;
+	spin_unlock(&hu->rx_lock);
 
 	if (test_and_clear_bit(TTY_THROTTLED,&tty->flags) && tty->driver.unthrottle)
 		tty->driver.unthrottle(tty);
 }
 
-static int n_hci_register_dev(struct n_hci *n_hci)
+static int hci_uart_register_dev(struct hci_uart *hu)
 {
 	struct hci_dev *hdev;
 
 	BT_DBG("");
 
 	/* Initialize and register HCI device */
-	hdev = &n_hci->hdev;
+	hdev = &hu->hdev;
 
 	hdev->type = HCI_UART;
-	hdev->driver_data = n_hci;
+	hdev->driver_data = hu;
 
-	hdev->open  = n_hci_open;
-	hdev->close = n_hci_close;
-	hdev->flush = n_hci_flush;
-	hdev->send  = n_hci_send_frame;
-	hdev->destruct = n_hci_destruct;
+	hdev->open  = hci_uart_open;
+	hdev->close = hci_uart_close;
+	hdev->flush = hci_uart_flush;
+	hdev->send  = hci_uart_send_frame;
+	hdev->destruct = hci_uart_destruct;
 
 	if (hci_register_dev(hdev) < 0) {
 		BT_ERR("Can't register HCI device %s", hdev->name);
@@ -402,30 +419,30 @@
 	return 0;
 }
 
-static int n_hci_set_proto(struct n_hci *n_hci, int id)
+static int hci_uart_set_proto(struct hci_uart *hu, int id)
 {
 	struct hci_uart_proto *p;
 	int err;	
 	
-	p = n_hci_get_proto(id);
+	p = hci_uart_get_proto(id);
 	if (!p)
 		return -EPROTONOSUPPORT;
 
-	err = p->open(n_hci);
+	err = p->open(hu);
 	if (err)
 		return err;
 
-	n_hci->proto = p;
+	hu->proto = p;
 
-	err = n_hci_register_dev(n_hci);
+	err = hci_uart_register_dev(hu);
 	if (err) {
-		p->close(n_hci);
+		p->close(hu);
 		return err;
 	}
 	return 0;
 }
 
-/* n_hci_tty_ioctl()
+/* hci_uart_tty_ioctl()
  *
  *    Process IOCTL system call for the tty device.
  *
@@ -438,24 +455,24 @@
  *
  * Return Value:    Command dependent
  */
-static int n_hci_tty_ioctl(struct tty_struct *tty, struct file * file,
+static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file,
                             unsigned int cmd, unsigned long arg)
 {
-	struct n_hci *n_hci = (void *)tty->disc_data;
+	struct hci_uart *hu = (void *)tty->disc_data;
 	int err = 0;
 
 	BT_DBG("");
 
 	/* Verify the status of the device */
-	if (!n_hci)
+	if (!hu)
 		return -EBADF;
 
 	switch (cmd) {
 	case HCIUARTSETPROTO:
-		if (!test_and_set_bit(N_HCI_PROTO_SET, &n_hci->flags)) {
-			err = n_hci_set_proto(n_hci, arg);
+		if (!test_and_set_bit(HCI_UART_PROTO_SET, &hu->flags)) {
+			err = hci_uart_set_proto(hu, arg);
 			if (err) {
-				clear_bit(N_HCI_PROTO_SET, &n_hci->flags);
+				clear_bit(HCI_UART_PROTO_SET, &hu->flags);
 				return err;
 			}
 			tty->low_latency = 1;
@@ -463,8 +480,8 @@
 			return -EBUSY;
 
 	case HCIUARTGETPROTO:
-		if (test_bit(N_HCI_PROTO_SET, &n_hci->flags))
-			return n_hci->proto->id;
+		if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
+			return hu->proto->id;
 		return -EUNATCH;
 		
 	default:
@@ -478,15 +495,15 @@
 /*
  * We don't provide read/write/poll interface for user space.
  */
-static ssize_t n_hci_tty_read(struct tty_struct *tty, struct file *file, unsigned char *buf, size_t nr)
+static ssize_t hci_uart_tty_read(struct tty_struct *tty, struct file *file, unsigned char *buf, size_t nr)
 {
 	return 0;
 }
-static ssize_t n_hci_tty_write(struct tty_struct *tty, struct file *file, const unsigned char *data, size_t count)
+static ssize_t hci_uart_tty_write(struct tty_struct *tty, struct file *file, const unsigned char *data, size_t count)
 {
 	return 0;
 }
-static unsigned int n_hci_tty_poll(struct tty_struct *tty, struct file *filp, poll_table *wait)
+static unsigned int hci_uart_tty_poll(struct tty_struct *tty, struct file *filp, poll_table *wait)
 {
 	return 0;
 }
@@ -495,10 +512,14 @@
 int h4_init(void);
 int h4_deinit(void);
 #endif
+#ifdef CONFIG_BLUEZ_HCIUART_BCSP
+int bcsp_init(void);
+int bcsp_deinit(void);
+#endif
 
-int __init n_hci_init(void)
+int __init hci_uart_init(void)
 {
-	static struct tty_ldisc n_hci_ldisc;
+	static struct tty_ldisc hci_uart_ldisc;
 	int err;
 
 	BT_INFO("BlueZ HCI UART driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", 
@@ -507,20 +528,20 @@
 
 	/* Register the tty discipline */
 
-	memset(&n_hci_ldisc, 0, sizeof (n_hci_ldisc));
-	n_hci_ldisc.magic       = TTY_LDISC_MAGIC;
-	n_hci_ldisc.name        = "n_hci";
-	n_hci_ldisc.open        = n_hci_tty_open;
-	n_hci_ldisc.close       = n_hci_tty_close;
-	n_hci_ldisc.read        = n_hci_tty_read;
-	n_hci_ldisc.write       = n_hci_tty_write;
-	n_hci_ldisc.ioctl       = n_hci_tty_ioctl;
-	n_hci_ldisc.poll        = n_hci_tty_poll;
-	n_hci_ldisc.receive_room= n_hci_tty_room;
-	n_hci_ldisc.receive_buf = n_hci_tty_receive;
-	n_hci_ldisc.write_wakeup= n_hci_tty_wakeup;
+	memset(&hci_uart_ldisc, 0, sizeof (hci_uart_ldisc));
+	hci_uart_ldisc.magic       = TTY_LDISC_MAGIC;
+	hci_uart_ldisc.name        = "n_hci";
+	hci_uart_ldisc.open        = hci_uart_tty_open;
+	hci_uart_ldisc.close       = hci_uart_tty_close;
+	hci_uart_ldisc.read        = hci_uart_tty_read;
+	hci_uart_ldisc.write       = hci_uart_tty_write;
+	hci_uart_ldisc.ioctl       = hci_uart_tty_ioctl;
+	hci_uart_ldisc.poll        = hci_uart_tty_poll;
+	hci_uart_ldisc.receive_room= hci_uart_tty_room;
+	hci_uart_ldisc.receive_buf = hci_uart_tty_receive;
+	hci_uart_ldisc.write_wakeup= hci_uart_tty_wakeup;
 
-	if ((err = tty_register_ldisc(N_HCI, &n_hci_ldisc))) {
+	if ((err = tty_register_ldisc(N_HCI, &hci_uart_ldisc))) {
 		BT_ERR("Can't register HCI line discipline (%d)", err);
 		return err;
 	}
@@ -528,25 +549,31 @@
 #ifdef CONFIG_BLUEZ_HCIUART_H4
 	h4_init();
 #endif
+#ifdef CONFIG_BLUEZ_HCIUART_BCSP
+	bcsp_init();
+#endif
 	
 	return 0;
 }
 
-void n_hci_cleanup(void)
+void hci_uart_cleanup(void)
 {
 	int err;
 
 #ifdef CONFIG_BLUEZ_HCIUART_H4
 	h4_deinit();
 #endif
+#ifdef CONFIG_BLUEZ_HCIUART_BCSP
+	bcsp_deinit();
+#endif
 
 	/* Release tty registration of line discipline */
 	if ((err = tty_register_ldisc(N_HCI, NULL)))
 		BT_ERR("Can't unregister HCI line discipline (%d)", err);
 }
 
-module_init(n_hci_init);
-module_exit(n_hci_cleanup);
+module_init(hci_uart_init);
+module_exit(hci_uart_cleanup);
 
 MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
 MODULE_DESCRIPTION("BlueZ HCI UART driver ver " VERSION);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/bluetooth/hci_uart.h linux-2.4.21-pre6/drivers/bluetooth/hci_uart.h
--- linux-2.4.20/drivers/bluetooth/hci_uart.h	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/drivers/bluetooth/hci_uart.h	2003-03-26 23:49:40.000000000 +0000
@@ -23,10 +23,10 @@
 */
 
 /*
- * $Id: hci_uart.h,v 1.1.1.1 2002/03/08 21:03:15 maxk Exp $
+ * $Id: hci_uart.h,v 1.2 2002/09/09 01:17:32 maxk Exp $
  */
 
-#ifndef N_HCI
+#ifndef N_HCI 
 #define N_HCI	15
 #endif
 
@@ -42,19 +42,19 @@
 #define HCI_UART_NCSP	2
 
 #ifdef __KERNEL__
-struct n_hci;
+struct hci_uart;
 
 struct hci_uart_proto {
 	unsigned int id;
-	int (*open)(struct n_hci *n_hci);
-	int (*recv)(struct n_hci *n_hci, void *data, int len);
-	int (*send)(struct n_hci *n_hci, void *data, int len);
-	int (*close)(struct n_hci *n_hci);
-	int (*flush)(struct n_hci *n_hci);
-	struct sk_buff* (*preq)(struct n_hci *n_hci, struct sk_buff *skb);
+	int (*open)(struct hci_uart *hu);
+	int (*close)(struct hci_uart *hu);
+	int (*flush)(struct hci_uart *hu);
+	int (*recv)(struct hci_uart *hu, void *data, int len);
+	int (*enqueue)(struct hci_uart *hu, struct sk_buff *skb);
+	struct sk_buff *(*dequeue)(struct hci_uart *hu);
 };
 
-struct n_hci {
+struct hci_uart {
 	struct tty_struct  *tty;
 	struct hci_dev     hdev;
 	unsigned long      flags;
@@ -62,19 +62,20 @@
 	struct hci_uart_proto *proto;
 	void               *priv;
 	
-	struct sk_buff_head txq;
-	unsigned long       tx_state;
-	spinlock_t          rx_lock;
+	struct sk_buff     *tx_skb;
+	unsigned long      tx_state;
+	spinlock_t         rx_lock;
 };
 
-/* N_HCI flag bits */
-#define N_HCI_PROTO_SET		0x00
+/* HCI_UART flag bits */
+#define HCI_UART_PROTO_SET		0
 
 /* TX states  */
-#define N_HCI_SENDING		1
-#define N_HCI_TX_WAKEUP		2
+#define HCI_UART_SENDING		1
+#define HCI_UART_TX_WAKEUP		2
 
 int hci_uart_register_proto(struct hci_uart_proto *p);
 int hci_uart_unregister_proto(struct hci_uart_proto *p);
+int hci_uart_tx_wakeup(struct hci_uart *hu);
 
 #endif /* __KERNEL__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/bluetooth/hci_usb.c linux-2.4.21-pre6/drivers/bluetooth/hci_usb.c
--- linux-2.4.20/drivers/bluetooth/hci_usb.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/bluetooth/hci_usb.c	2003-03-26 23:49:30.000000000 +0000
@@ -214,7 +214,7 @@
 
 	err = hci_usb_enable_intr(husb);
 	if (!err) {
-		for (i = 0; i < HCI_MAX_BULK_TX; i++)
+		for (i = 0; i < HCI_MAX_BULK_RX; i++)
 			hci_usb_rx_submit(husb, NULL);
 	} else {
 		clear_bit(HCI_RUNNING, &hdev->flags);
@@ -389,7 +389,7 @@
 }
 
 /* Send frames from HCI layer */
-int hci_usb_send_frame(struct sk_buff *skb)
+static int hci_usb_send_frame(struct sk_buff *skb)
 {
 	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
 	struct hci_usb *husb;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/Config.in linux-2.4.21-pre6/drivers/char/Config.in
--- linux-2.4.20/drivers/char/Config.in	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/Config.in	2003-03-26 23:49:16.000000000 +0000
@@ -73,6 +73,14 @@
      tristate '    Stallion EasyIO or EC8/32 support' CONFIG_STALLION
      tristate '    Stallion EC8/64, ONboard, Brumby support' CONFIG_ISTALLION
    fi
+   if [ "$CONFIG_PARISC" = "y" ]; then
+     if [ "$CONFIG_PDC_CONSOLE" != "y" ]; then
+       bool '  Serial MUX support' CONFIG_SERIAL_MUX CONFIG_SERIAL_NONSTANDARD
+     fi
+     if [ "$CONFIG_SERIAL_MUX" != "y" ]; then
+       bool '  PDC software console support' CONFIG_PDC_CONSOLE CONFIG_SERIAL_NONSTANDARD
+     fi
+   fi
    if [ "$CONFIG_MIPS" = "y" ]; then
      bool '  TX3912/PR31700 serial port support' CONFIG_SERIAL_TX3912
      dep_bool '     Console on TX3912/PR31700 serial port' CONFIG_SERIAL_TX3912_CONSOLE $CONFIG_SERIAL_TX3912
@@ -147,6 +155,7 @@
       bool '  Support for console on line printer' CONFIG_LP_CONSOLE
    fi
    dep_tristate 'Support for user-space parallel port device drivers' CONFIG_PPDEV $CONFIG_PARPORT
+   dep_tristate 'Texas Instruments parallel link cable support' CONFIG_TIPAR $CONFIG_PARPORT
 fi
 
 if [ "$CONFIG_PPC64" ] ; then 
@@ -190,6 +199,12 @@
    fi
 fi
 
+tristate 'IPMI top-level message handler' CONFIG_IPMI_HANDLER
+dep_mbool '  Generate a panic event to all BMCs on a panic' CONFIG_IPMI_PANIC_EVENT $CONFIG_IPMI_HANDLER
+dep_tristate '  Device interface for IPMI' CONFIG_IPMI_DEVICE_INTERFACE $CONFIG_IPMI_HANDLER
+dep_tristate '  IPMI KCS handler' CONFIG_IPMI_KCS $CONFIG_IPMI_HANDLER
+dep_tristate '  IPMI Watchdog Timer' CONFIG_IPMI_WATCHDOG $CONFIG_IPMI_HANDLER
+
 mainmenu_option next_comment
 comment 'Watchdog Cards'
 bool 'Watchdog Timer Support'	CONFIG_WATCHDOG
@@ -216,6 +231,7 @@
    tristate '  Mixcom Watchdog' CONFIG_MIXCOMWD 
    tristate '  SBC-60XX Watchdog Timer' CONFIG_60XX_WDT
    dep_tristate '  SC1200 Watchdog Timer (EXPERIMENTAL)' CONFIG_SC1200_WDT $CONFIG_EXPERIMENTAL
+   tristate '  NatSemi SCx200 Watchdog' CONFIG_SCx200_WDT
    tristate '  Software Watchdog' CONFIG_SOFT_WATCHDOG
    tristate '  W83877F (EMACS) Watchdog Timer' CONFIG_W83877F_WDT
    tristate '  WDT Watchdog timer' CONFIG_WDT
@@ -239,6 +255,7 @@
    fi
    tristate 'NetWinder flash support' CONFIG_NWFLASH
 fi
+dep_tristate 'NatSemi SCx200 GPIO Support' CONFIG_SCx200_GPIO $CONFIG_SCx200
 
 if [ "$CONFIG_X86" = "y" -o "$CONFIG_X86_64" = "y" ]; then
    dep_tristate 'AMD 768 Random Number Generator support' CONFIG_AMD_RNG $CONFIG_PCI
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/Makefile linux-2.4.21-pre6/drivers/char/Makefile
--- linux-2.4.20/drivers/char/Makefile	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/Makefile	2003-03-26 23:49:54.000000000 +0000
@@ -24,7 +24,7 @@
 export-objs     :=	busmouse.o console.o keyboard.o sysrq.o \
 			misc.o pty.o random.o selection.o serial.o \
 			sonypi.o tty_io.o tty_ioctl.o generic_serial.o \
-			au1000_gpio.o hp_psaux.o nvram.o
+			au1000_gpio.o hp_psaux.o nvram.o scx200.o
 
 mod-subdirs	:=	joystick ftape drm drm-4.0 pcmcia
 
@@ -66,6 +66,20 @@
    SERIAL   =
 endif
 
+ifeq ($(ARCH),parisc)
+   ifdef CONFIG_GSC_PS2
+      KEYBD   = hp_psaux.o hp_keyb.o
+   else
+      KEYBD   =
+   endif
+   ifdef CONFIG_SERIAL_MUX
+      CONSOLE += mux.o
+   endif
+   ifdef CONFIG_PDC_CONSOLE
+      CONSOLE += pdc_console.o
+   endif
+endif
+
 ifdef CONFIG_Q40
   KEYBD += q40_keyb.o
   SERIAL = serial.o
@@ -204,6 +218,7 @@
 obj-$(CONFIG_ATIXL_BUSMOUSE) += atixlmouse.o
 obj-$(CONFIG_LOGIBUSMOUSE) += logibusmouse.o
 obj-$(CONFIG_PRINTER) += lp.o
+obj-$(CONFIG_TIPAR) += tipar.o
 
 ifeq ($(CONFIG_INPUT),y)
 obj-y += joystick/js.o
@@ -222,6 +237,7 @@
 obj-$(CONFIG_PC110_PAD) += pc110pad.o
 obj-$(CONFIG_MK712_MOUSE) += mk712.o
 obj-$(CONFIG_RTC) += rtc.o
+obj-$(CONFIG_GEN_RTC) += genrtc.o
 obj-$(CONFIG_EFI_RTC) += efirtc.o
 ifeq ($(CONFIG_PPC),)
   obj-$(CONFIG_NVRAM) += nvram.o
@@ -254,6 +270,7 @@
 obj-$(CONFIG_DZ) += dz.o
 obj-$(CONFIG_NWBUTTON) += nwbutton.o
 obj-$(CONFIG_NWFLASH) += nwflash.o
+obj-$(CONFIG_SCx200_GPIO) += scx200_gpio.o scx200.o
 
 # Only one watchdog can succeed. We probe the hardware watchdog
 # drivers first, then the softdog driver.  This means if your hardware
@@ -280,6 +297,7 @@
 #obj-$(CONFIG_ALIM1535_WDT) += alim1535d_wdt.o
 obj-$(CONFIG_INDYDOG) += indydog.o
 obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
+obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
 obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o
 obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o
 obj-$(CONFIG_AMD7XX_TCO) += amd7xx_tco.o
@@ -289,6 +307,11 @@
   obj-y += mwave/mwave.o
 endif
 
+subdir-$(CONFIG_IPMI_HANDLER) += ipmi
+ifeq ($(CONFIG_IPMI_HANDLER),y)
+  obj-y += ipmi/ipmi.o
+endif
+
 include $(TOPDIR)/Rules.make
 
 fastdep:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/agp/agp.h linux-2.4.21-pre6/drivers/char/agp/agp.h
--- linux-2.4.20/drivers/char/agp/agp.h	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/agp/agp.h	2003-03-26 23:49:34.000000000 +0000
@@ -87,6 +87,7 @@
 	u32 *gatt_table;
 	u32 *gatt_table_real;
 	unsigned long scratch_page;
+	unsigned long scratch_page_real;
 	unsigned long gart_bus_addr;
 	unsigned long gatt_bus_addr;
 	u32 mode;
@@ -99,7 +100,6 @@
 	int needs_scratch_page;
 	int aperture_size_idx;
 	int num_aperture_sizes;
-	int num_of_masks;
 	int capndx;
 	int cant_use_aperture;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/agp/agpgart_be.c linux-2.4.21-pre6/drivers/char/agp/agpgart_be.c
--- linux-2.4.20/drivers/char/agp/agpgart_be.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/agp/agpgart_be.c	2003-03-26 23:49:08.000000000 +0000
@@ -209,7 +209,6 @@
 	}
 	if (curr->page_count != 0) {
 		for (i = 0; i < curr->page_count; i++) {
-			curr->memory[i] &= ~(0x00000fff);
 			agp_bridge.agp_destroy_page((unsigned long)
 					 phys_to_virt(curr->memory[i]));
 		}
@@ -262,10 +261,7 @@
 			agp_free_memory(new);
 			return NULL;
 		}
-		new->memory[i] =
-		    agp_bridge.mask_memory(
-				   virt_to_phys((void *) new->memory[i]),
-						  type);
+		new->memory[i] = virt_to_phys((void *) new->memory[i]);
 		new->page_count++;
 	}
 
@@ -311,9 +307,6 @@
 
 int agp_copy_info(agp_kern_info * info)
 {
-	unsigned long page_mask = 0;
-	int i;
-
 	memset(info, 0, sizeof(agp_kern_info));
 	if (agp_bridge.type == NOT_SUPPORTED) {
 		info->chipset = agp_bridge.type;
@@ -329,11 +322,7 @@
 	info->max_memory = agp_bridge.max_memory_agp;
 	info->current_memory = atomic_read(&agp_bridge.current_memory_agp);
 	info->cant_use_aperture = agp_bridge.cant_use_aperture;
-
-	for(i = 0; i < agp_bridge.num_of_masks; i++)
-		page_mask |= agp_bridge.mask_memory(page_mask, i);
-
-	info->page_mask = ~page_mask;
+	info->page_mask = ~0UL;
 	return 0;
 }
 
@@ -731,7 +720,8 @@
 		mem->is_flushed = TRUE;
 	}
 	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
-		agp_bridge.gatt_table[j] = mem->memory[i];
+		agp_bridge.gatt_table[j] =
+			agp_bridge.mask_memory(mem->memory[i], mem->type);
 	}
 
 	agp_bridge.tlb_flush(mem);
@@ -976,7 +966,8 @@
    	CACHE_FLUSH();
 	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
 		OUTREG32(intel_i810_private.registers,
-			 I810_PTE_BASE + (j * 4), mem->memory[i]);
+			 I810_PTE_BASE + (j * 4),
+			 agp_bridge.mask_memory(mem->memory[i], mem->type));
 	}
 	CACHE_FLUSH();
 
@@ -1042,10 +1033,7 @@
 			agp_free_memory(new);
 			return NULL;
 		}
-		new->memory[0] =
-		    agp_bridge.mask_memory(
-				   virt_to_phys((void *) new->memory[0]),
-						  type);
+		new->memory[0] = virt_to_phys((void *) new->memory[0]);
 		new->page_count = 1;
 	   	new->num_scratch_pages = 1;
 	   	new->type = AGP_PHYS_MEMORY;
@@ -1079,7 +1067,6 @@
 	intel_i810_private.i810_dev = i810_dev;
 
 	agp_bridge.masks = intel_i810_masks;
-	agp_bridge.num_of_masks = 2;
 	agp_bridge.aperture_sizes = (void *) intel_i810_sizes;
 	agp_bridge.size_type = FIXED_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 2;
@@ -1282,7 +1269,8 @@
 	CACHE_FLUSH();
 
 	for (i = 0, j = pg_start; i < mem->page_count; i++, j++)
-		OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (j * 4),mem->memory[i]);
+		OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (j * 4),
+			 agp_bridge.mask_memory(mem->memory[i], mem->type));
 
 	CACHE_FLUSH();
 
@@ -1343,7 +1331,7 @@
 			return(NULL);
 		}
 
-		nw->memory[0] = agp_bridge.mask_memory(virt_to_phys((void *) nw->memory[0]),type);
+		nw->memory[0] = virt_to_phys((void *) nw->memory[0]);
 		nw->page_count = 1;
 		nw->num_scratch_pages = 1;
 		nw->type = AGP_PHYS_MEMORY;
@@ -1359,7 +1347,6 @@
 	intel_i830_private.i830_dev = i830_dev;
 
 	agp_bridge.masks = intel_i810_masks;
-	agp_bridge.num_of_masks = 3;
 	agp_bridge.aperture_sizes = (void *) intel_i830_sizes;
 	agp_bridge.size_type = FIXED_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 2;
@@ -1841,7 +1828,6 @@
 static int __init intel_generic_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = intel_generic_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) intel_generic_sizes;
 	agp_bridge.size_type = U16_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -1874,7 +1860,6 @@
 static int __init intel_815_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = intel_generic_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) intel_815_sizes;
 	agp_bridge.size_type = U8_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 2;
@@ -1907,7 +1892,6 @@
 static int __init intel_820_setup (struct pci_dev *pdev)
 {
        agp_bridge.masks = intel_generic_masks;
-       agp_bridge.num_of_masks = 1;
        agp_bridge.aperture_sizes = (void *) intel_8xx_sizes;
        agp_bridge.size_type = U8_APER_SIZE;
        agp_bridge.num_aperture_sizes = 7;
@@ -1940,7 +1924,6 @@
 static int __init intel_830mp_setup (struct pci_dev *pdev)
 {
        agp_bridge.masks = intel_generic_masks;
-       agp_bridge.num_of_masks = 1;
        agp_bridge.aperture_sizes = (void *) intel_830mp_sizes;
        agp_bridge.size_type = U8_APER_SIZE;
        agp_bridge.num_aperture_sizes = 4;
@@ -1972,7 +1955,6 @@
 static int __init intel_840_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = intel_generic_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) intel_8xx_sizes;
 	agp_bridge.size_type = U8_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -2005,7 +1987,6 @@
 static int __init intel_845_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = intel_generic_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) intel_8xx_sizes;
 	agp_bridge.size_type = U8_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -2038,7 +2019,6 @@
 static int __init intel_850_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = intel_generic_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) intel_8xx_sizes;
 	agp_bridge.size_type = U8_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -2071,7 +2051,6 @@
 static int __init intel_860_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = intel_generic_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) intel_8xx_sizes;
 	agp_bridge.size_type = U8_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -2191,7 +2170,6 @@
 static int __init via_generic_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = via_generic_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) via_generic_sizes;
 	agp_bridge.size_type = U8_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -2305,7 +2283,6 @@
 static int __init sis_generic_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = sis_generic_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) sis_generic_sizes;
 	agp_bridge.size_type = U8_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -2643,7 +2620,8 @@
 	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
 		addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr;
 		cur_gatt = GET_GATT(addr);
-		cur_gatt[GET_GATT_OFF(addr)] = mem->memory[i];
+		cur_gatt[GET_GATT_OFF(addr)] =
+			agp_bridge.mask_memory(mem->memory[i], mem->type);
 	}
 	agp_bridge.tlb_flush(mem);
 	return 0;
@@ -2689,7 +2667,6 @@
 static int __init amd_irongate_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = amd_irongate_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) amd_irongate_sizes;
 	agp_bridge.size_type = LVL2_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -2790,7 +2767,7 @@
 	}
 
 	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
-		addr = mem->memory[i];
+		addr = agp_bridge.mask_memory(mem->memory[i], mem->type);
 
 		tmp = addr;
 		BUG_ON(tmp & 0xffffff0000000ffc);
@@ -3155,7 +3132,6 @@
 static int __init amd_8151_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = amd_8151_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) amd_8151_sizes;
 	agp_bridge.size_type = U32_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -3393,7 +3369,6 @@
 static int __init ali_generic_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = ali_generic_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) ali_generic_sizes;
 	agp_bridge.size_type = U32_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -3807,7 +3782,8 @@
 	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
 		addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr;
 		cur_gatt = SVRWRKS_GET_GATT(addr);
-		cur_gatt[GET_GATT_OFF(addr)] = mem->memory[i];
+		cur_gatt[GET_GATT_OFF(addr)] =
+			agp_bridge.mask_memory(mem->memory[i], mem->type);
 	}
 	agp_bridge.tlb_flush(mem);
 	return 0;
@@ -3964,7 +3940,6 @@
 	serverworks_private.svrwrks_dev = pdev;
 
 	agp_bridge.masks = serverworks_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.aperture_sizes = (void *) serverworks_sizes;
 	agp_bridge.size_type = LVL2_APER_SIZE;
 	agp_bridge.num_aperture_sizes = 7;
@@ -4362,7 +4337,6 @@
 static int __init hp_zx1_setup (struct pci_dev *pdev)
 {
 	agp_bridge.masks = hp_zx1_masks;
-	agp_bridge.num_of_masks = 1;
 	agp_bridge.dev_private_data = NULL;
 	agp_bridge.size_type = FIXED_APER_SIZE;
 	agp_bridge.needs_scratch_page = FALSE;
@@ -4485,12 +4459,6 @@
 		"AMD",
 		"761",
 		amd_irongate_setup },
-	{ PCI_DEVICE_ID_AMD_762_0,
-		PCI_VENDOR_ID_AMD,
-		AMD_762,
-		"AMD",
-		"760MP",
-		amd_irongate_setup },
 	{ 0,
 		PCI_VENDOR_ID_AMD,
 		AMD_GENERIC,
@@ -4556,7 +4524,7 @@
 		 INTEL_I845_G,
 		 "Intel",
 		 "i845G",
-		 intel_830mp_setup },
+		 intel_845_setup },
 	{ PCI_DEVICE_ID_INTEL_840_0,
 		PCI_VENDOR_ID_INTEL,
 		INTEL_I840,
@@ -4714,6 +4682,18 @@
 		"Via",
 		"Apollo Pro KT266",
 		via_generic_setup },
+        { PCI_DEVICE_ID_VIA_8377_0,
+		PCI_VENDOR_ID_VIA,
+		VIA_APOLLO_KT400,
+		"Via",
+		"Apollo Pro KT400",
+		via_generic_setup },
+	{ PCI_DEVICE_ID_VIA_P4X333,
+		PCI_VENDOR_ID_VIA,
+		VIA_APOLLO_P4X400,
+		"Via",
+		"Apollo P4X400",
+		via_generic_setup },
 	{ 0,
 		PCI_VENDOR_ID_VIA,
 		VIA_GENERIC,
@@ -5077,17 +5057,17 @@
 	}
 
 	if (agp_bridge.needs_scratch_page == TRUE) {
-		agp_bridge.scratch_page = agp_bridge.agp_alloc_page();
+		unsigned long addr;
+		addr = agp_bridge.agp_alloc_page();
 
-		if (agp_bridge.scratch_page == 0) {
+		if (addr == 0) {
 			printk(KERN_ERR PFX "unable to get memory for "
 			       "scratch page.\n");
 			return -ENOMEM;
 		}
+		agp_bridge.scratch_page_real = virt_to_phys((void *) addr);
 		agp_bridge.scratch_page =
-		    virt_to_phys((void *) agp_bridge.scratch_page);
-		agp_bridge.scratch_page =
-		    agp_bridge.mask_memory(agp_bridge.scratch_page, 0);
+		    agp_bridge.mask_memory(agp_bridge.scratch_page_real, 0);
 	}
 
 	size_value = agp_bridge.fetch_size();
@@ -5129,9 +5109,8 @@
 
 err_out:
 	if (agp_bridge.needs_scratch_page == TRUE) {
-		agp_bridge.scratch_page &= ~(0x00000fff);
 		agp_bridge.agp_destroy_page((unsigned long)
-				 phys_to_virt(agp_bridge.scratch_page));
+				 phys_to_virt(agp_bridge.scratch_page_real));
 	}
 	if (got_gatt)
 		agp_bridge.free_gatt_table();
@@ -5149,9 +5128,8 @@
 	vfree(agp_bridge.key_list);
 
 	if (agp_bridge.needs_scratch_page == TRUE) {
-		agp_bridge.scratch_page &= ~(0x00000fff);
 		agp_bridge.agp_destroy_page((unsigned long)
-				 phys_to_virt(agp_bridge.scratch_page));
+				 phys_to_virt(agp_bridge.scratch_page_real));
 	}
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/amd768_rng.c linux-2.4.21-pre6/drivers/char/amd768_rng.c
--- linux-2.4.20/drivers/char/amd768_rng.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/amd768_rng.c	2003-03-26 23:49:08.000000000 +0000
@@ -1,11 +1,12 @@
 /*
- 	Hardware driver for the AMD 768 Random Number Generator (RNG)
+ 	Hardware driver for the AMD 768/8111 Random Number Generator (RNG)
 	(c) Copyright 2001 Red Hat Inc <alan@redhat.com>
- 
+	(c) Copyright 2002,2003 Andi Kleen, SuSE Labs
+
  	derived from
  
 	Hardware driver for Intel i810 Random Number Generator (RNG)
-	Copyright 2000,2001 Jeff Garzik <jgarzik@mandrakesoft.com>
+	Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>
 	Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>
 
 	Please read Documentation/i810_rng.txt for details on use.
@@ -238,13 +239,14 @@
  */
 static struct pci_device_id rng_pci_tbl[] __initdata = {
 	{ 0x1022, 0x7443, PCI_ANY_ID, PCI_ANY_ID, },
+	{ 0x1022, 0x746b, PCI_ANY_ID, PCI_ANY_ID, },
 	{ 0, },
 };
 MODULE_DEVICE_TABLE (pci, rng_pci_tbl);
 
 
-MODULE_AUTHOR("Alan Cox, Jeff Garzik, Philipp Rumpf, Matt Sottek");
-MODULE_DESCRIPTION("AMD 768 Random Number Generator (RNG) driver");
+MODULE_AUTHOR("Alan Cox, Jeff Garzik, Philipp Rumpf, Matt Sottek, Andi Kleen");
+MODULE_DESCRIPTION("AMD 768/8111 Random Number Generator (RNG) driver");
 MODULE_LICENSE("GPL");
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/cyclades.c linux-2.4.21-pre6/drivers/char/cyclades.c
--- linux-2.4.20/drivers/char/cyclades.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/cyclades.c	2003-03-26 23:49:18.000000000 +0000
@@ -4957,7 +4957,7 @@
   struct pci_dev	*pdev = NULL;
   unsigned char		cyy_rev_id;
   unsigned char         cy_pci_irq = 0;
-  uclong		cy_pci_phys0, cy_pci_phys1, cy_pci_phys2;
+  uclong		cy_pci_phys0, cy_pci_phys2;
   uclong		cy_pci_addr0, cy_pci_addr2;
   unsigned short        i,j,cy_pci_nchan, plx_ver;
   unsigned short        device_id,dev_index = 0;
@@ -4965,8 +4965,7 @@
   uclong		Ze_addr0[NR_CARDS], Ze_addr2[NR_CARDS], ZeIndex = 0;
   uclong		Ze_phys0[NR_CARDS], Ze_phys2[NR_CARDS];
   unsigned char         Ze_irq[NR_CARDS];
-  struct resource *resource;
-  unsigned long res_start, res_len;
+  struct pci_dev	*Ze_pdev[NR_CARDS];
 
         for (i = 0; i < NR_CARDS; i++) {
                 /* look for a Cyclades card by vendor and device id */
@@ -4988,7 +4987,6 @@
                 /* read PCI configuration area */
 		cy_pci_irq = pdev->irq;
 		cy_pci_phys0 = pci_resource_start(pdev, 0);
-		cy_pci_phys1 = pci_resource_start(pdev, 1);
 		cy_pci_phys2 = pci_resource_start(pdev, 2);
 		pci_read_config_byte(pdev, PCI_REVISION_ID, &cyy_rev_id);
 
@@ -5014,14 +5012,11 @@
 		/* Although we don't use this I/O region, we should
 		   request it from the kernel anyway, to avoid problems
 		   with other drivers accessing it. */
-		resource = request_region(cy_pci_phys1, CyPCI_Yctl, "Cyclom-Y");
-		if (resource == NULL) {
-		    printk(KERN_ERR "cyclades: failed to allocate IO "
-				    "resource at 0x%lx\n", cy_pci_phys1);
+		if (pci_request_regions(pdev, "Cyclom-Y") != 0) {
+		    printk(KERN_ERR "cyclades: failed to reserve PCI "
+				    "resources\n");
 		    continue;
 		}
-		res_start = cy_pci_phys1;
-		res_len = CyPCI_Yctl;
 
 #if defined(__alpha__)
                 if (device_id  == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */
@@ -5092,10 +5087,7 @@
                 cy_card[j].bus_index = 1;
                 cy_card[j].first_line = cy_next_channel;
                 cy_card[j].num_chips = cy_pci_nchan/4;
-		cy_card[j].resource = resource;
-		cy_card[j].res_start = res_start;
-		cy_card[j].res_len = res_len;
-		resource = NULL;	/* For next card */
+		cy_card[j].pdev = pdev;
 
                 /* enable interrupts in the PCI interface */
 		plx_ver = cy_readb(cy_pci_addr2 + CyPLX_VER) & 0x0f;
@@ -5175,16 +5167,13 @@
 		/* Although we don't use this I/O region, we should
 		   request it from the kernel anyway, to avoid problems
 		   with other drivers accessing it. */
-		resource = request_region(cy_pci_phys1, CyPCI_Zctl, 
-					  "Cyclades-Z");
-		if (resource == NULL) {
-		    printk(KERN_ERR "cyclades: failed to allocate IO "
-				    "resource at 0x%lx\n", cy_pci_phys1);
-		    continue;
-		}
-		res_start = cy_pci_phys1;
-		res_len = CyPCI_Zctl;
 
+		if (pci_request_regions(pdev, "Cyclades-Z") != 0) {
+			printk(KERN_ERR "cyclades: failed to reserve PCI "
+				    "resources\n");
+  			continue;
+  		}
+  
 		if (mailbox == ZE_V1) {
 		    cy_pci_addr2 = (ulong)ioremap(cy_pci_phys2, CyPCI_Ze_win);
 		    if (ZeIndex == NR_CARDS) {
@@ -5198,6 +5187,7 @@
 			Ze_addr0[ZeIndex] = cy_pci_addr0;
 			Ze_addr2[ZeIndex] = cy_pci_addr2;
 			Ze_irq[ZeIndex] = cy_pci_irq;
+			Ze_pdev[ZeIndex] = pdev;
 			ZeIndex++;
 		    }
 		    i--;
@@ -5282,10 +5272,7 @@
                 cy_card[j].bus_index = 1;
                 cy_card[j].first_line = cy_next_channel;
                 cy_card[j].num_chips = -1;
-		cy_card[j].resource = resource;
-		cy_card[j].res_start = res_start;
-		cy_card[j].res_len = res_len;
-		resource = NULL;	/* For next card */
+		cy_card[j].pdev = pdev;
 
                 /* print message */
 #ifdef CONFIG_CYZ_INTR
@@ -5313,12 +5300,14 @@
 	    cy_pci_addr0 = Ze_addr0[0];
 	    cy_pci_addr2 = Ze_addr2[0];
 	    cy_pci_irq = Ze_irq[0];
+	    pdev = Ze_pdev[0];
 	    for (j = 0 ; j < ZeIndex-1 ; j++) {
 		Ze_phys0[j] = Ze_phys0[j+1];
 		Ze_phys2[j] = Ze_phys2[j+1];
 		Ze_addr0[j] = Ze_addr0[j+1];
 		Ze_addr2[j] = Ze_addr2[j+1];
 		Ze_irq[j] = Ze_irq[j+1];
+		Ze_pdev[j] = Ze_pdev[j+1];
 	    }
 	    ZeIndex--;
 		mailbox = (uclong)cy_readl(&((struct RUNTIME_9060 *) 
@@ -5376,6 +5365,7 @@
                 cy_card[j].bus_index = 1;
                 cy_card[j].first_line = cy_next_channel;
                 cy_card[j].num_chips = -1;
+		cy_card[j].pdev = pdev;
 
                 /* print message */
 #ifdef CONFIG_CYZ_INTR
@@ -5812,10 +5802,8 @@
 #endif /* CONFIG_CYZ_INTR */
 	    )
 		free_irq(cy_card[i].irq, &cy_card[i]);
-	    if (cy_card[i].resource) {
-		cy_card[i].resource = NULL;
-		release_region(cy_card[i].res_start, cy_card[i].res_len);
-	    }
+	    if (cy_card[i].pdev)
+	    	pci_release_regions(cy_card[i].pdev);
         }
     }
     if (tmp_buf) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/drm/drm_agpsupport.h linux-2.4.21-pre6/drivers/char/drm/drm_agpsupport.h
--- linux-2.4.20/drivers/char/drm/drm_agpsupport.h	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/drm/drm_agpsupport.h	2003-03-26 23:48:57.000000000 +0000
@@ -279,8 +279,12 @@
 			break;
 		case VIA_APOLLO_KT133:	head->chipset = "VIA Apollo KT133";
 			break;
+		case VIA_APOLLO_KT400:  head->chipset = "VIA Apollo KT400";
+			break;
 		case VIA_APOLLO_PRO: 	head->chipset = "VIA Apollo Pro";
 			break;
+		case VIA_APOLLO_P4X400:	head->chipset = "VIA Apollo P4X400";
+			break;
 
 		case SIS_GENERIC:	head->chipset = "SiS";           break;
 		case AMD_GENERIC:	head->chipset = "AMD";           break;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/drm/drm_auth.h linux-2.4.21-pre6/drivers/char/drm/drm_auth.h
--- linux-2.4.20/drivers/char/drm/drm_auth.h	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/drm/drm_auth.h	2003-03-26 23:49:54.000000000 +0000
@@ -63,6 +63,7 @@
 	hash	     = DRM(hash_magic)(magic);
 	entry	     = DRM(alloc)(sizeof(*entry), DRM_MEM_MAGIC);
 	if (!entry) return -ENOMEM;
+	memset(entry, 0, sizeof(*entry));
 	entry->magic = magic;
 	entry->priv  = priv;
 	entry->next  = NULL;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/drm/drm_ioctl.h linux-2.4.21-pre6/drivers/char/drm/drm_ioctl.h
--- linux-2.4.20/drivers/char/drm/drm_ioctl.h	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/drm/drm_ioctl.h	2003-03-26 23:49:19.000000000 +0000
@@ -40,8 +40,20 @@
 	if (copy_from_user(&p, (drm_irq_busid_t *)arg, sizeof(p)))
 		return -EFAULT;
 	dev = pci_find_slot(p.busnum, PCI_DEVFN(p.devnum, p.funcnum));
-	if (dev) p.irq = dev->irq;
-	else	 p.irq = 0;
+	if (!dev) {
+		DRM_ERROR("pci_find_slot failed for %d:%d:%d\n",
+			  p.busnum, p.devnum, p.funcnum);
+		p.irq = 0;
+		goto out;
+	}			
+	if (pci_enable_device(dev) != 0) {
+		DRM_ERROR("pci_enable_device failed for %d:%d:%d\n",
+			  p.busnum, p.devnum, p.funcnum);
+		p.irq = 0;
+		goto out;
+	}		
+	p.irq = dev->irq;
+ out:
 	DRM_DEBUG("%d:%d:%d => IRQ %d\n",
 		  p.busnum, p.devnum, p.funcnum, p.irq);
 	if (copy_to_user((drm_irq_busid_t *)arg, &p, sizeof(p)))
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/drm/drm_lists.h linux-2.4.21-pre6/drivers/char/drm/drm_lists.h
--- linux-2.4.20/drivers/char/drm/drm_lists.h	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/drm/drm_lists.h	2003-03-26 23:49:20.000000000 +0000
@@ -41,7 +41,7 @@
 				    DRM_MEM_BUFLISTS);
 
 	if(!bl->bufs) return -ENOMEM;
-
+	memset(bl->bufs, 0, sizeof(*bl->bufs));
 	bl->count      = count;
 	bl->rp	       = bl->bufs;
 	bl->wp	       = bl->bufs;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/drm/drm_scatter.h linux-2.4.21-pre6/drivers/char/drm/drm_scatter.h
--- linux-2.4.20/drivers/char/drm/drm_scatter.h	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/drm/drm_scatter.h	2003-03-26 23:49:40.000000000 +0000
@@ -93,6 +93,8 @@
 		return -ENOMEM;
 	}
 
+	memset(entry->pagelist, 0, pages * sizeof(*entry->pagelist));
+
 	entry->busaddr = DRM(alloc)( pages * sizeof(*entry->busaddr),
 				     DRM_MEM_PAGES );
 	if ( !entry->busaddr ) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/drm/drm_vm.h linux-2.4.21-pre6/drivers/char/drm/drm_vm.h
--- linux-2.4.20/drivers/char/drm/drm_vm.h	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/drm/drm_vm.h	2003-03-26 23:49:38.000000000 +0000
@@ -406,7 +406,7 @@
 
 	if (!capable(CAP_SYS_ADMIN) && (map->flags & _DRM_READ_ONLY)) {
 		vma->vm_flags &= VM_MAYWRITE;
-#if defined(__i386__)
+#if defined(__i386__) || defined(__x86_64__)
 		pgprot_val(vma->vm_page_prot) &= ~_PAGE_RW;
 #else
 				/* Ye gads this is ugly.  With more thought
@@ -433,7 +433,7 @@
 	case _DRM_FRAME_BUFFER:
 	case _DRM_REGISTERS:
 		if (VM_OFFSET(vma) >= __pa(high_memory)) {
-#if defined(__i386__)
+#if defined(__i386__) || defined(__x86_64__)
 			if (boot_cpu_data.x86 > 3 && map->type != _DRM_AGP) {
 				pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
 				pgprot_val(vma->vm_page_prot) &= ~_PAGE_PWT;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/drm/mga_dma.c linux-2.4.21-pre6/drivers/char/drm/mga_dma.c
--- linux-2.4.20/drivers/char/drm/mga_dma.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/drm/mga_dma.c	2003-03-26 23:49:25.000000000 +0000
@@ -27,7 +27,7 @@
  * Authors:
  *    Rickard E. (Rik) Faith <faith@valinux.com>
  *    Jeff Hartmann <jhartmann@valinux.com>
- *    Keith Whitwell <keithw@valinux.com>
+ *    Keith Whitwell <keith@tungstengraphics.com>
  *
  * Rewritten by:
  *    Gareth Hughes <gareth@valinux.com>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/drm/mga_drm.h linux-2.4.21-pre6/drivers/char/drm/mga_drm.h
--- linux-2.4.20/drivers/char/drm/mga_drm.h	2001-08-08 16:42:15.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/drm/mga_drm.h	2003-03-26 23:49:09.000000000 +0000
@@ -26,7 +26,7 @@
  *
  * Authors:
  *    Jeff Hartmann <jhartmann@valinux.com>
- *    Keith Whitwell <keithw@valinux.com>
+ *    Keith Whitwell <keith@tungstengraphics.com>
  *
  * Rewritten by:
  *    Gareth Hughes <gareth@valinux.com>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/drm/mga_state.c linux-2.4.21-pre6/drivers/char/drm/mga_state.c
--- linux-2.4.20/drivers/char/drm/mga_state.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/drm/mga_state.c	2003-03-26 23:49:30.000000000 +0000
@@ -26,7 +26,7 @@
  *
  * Authors:
  *    Jeff Hartmann <jhartmann@valinux.com>
- *    Keith Whitwell <keithw@valinux.com>
+ *    Keith Whitwell <keith@tungstengraphics.com>
  *
  * Rewritten by:
  *    Gareth Hughes <gareth@valinux.com>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/drm/radeon.h linux-2.4.21-pre6/drivers/char/drm/radeon.h
--- linux-2.4.20/drivers/char/drm/radeon.h	2001-08-08 16:42:15.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/drm/radeon.h	2003-03-26 23:49:54.000000000 +0000
@@ -25,6 +25,7 @@
  *
  * Authors:
  *    Gareth Hughes <gareth@valinux.com>
+ *    Keith Whitwell <keith@tungstengraphics.com>
  */
 
 #ifndef __RADEON_H__
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/drm-4.0/agpsupport.c linux-2.4.21-pre6/drivers/char/drm-4.0/agpsupport.c
--- linux-2.4.20/drivers/char/drm-4.0/agpsupport.c	2002-02-25 19:37:57.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/drm-4.0/agpsupport.c	2003-03-26 23:49:53.000000000 +0000
@@ -275,6 +275,9 @@
 			break;
 		case VIA_APOLLO_KT133:	head->chipset = "VIA Apollo KT133"; 
 			break;
+		case VIA_APOLLO_KT400:  head->chipset = "VIA Apollo KT400";
+			break;
+		case VIA_APOLLO_P4X400:	head->chipset = "VIA Apollo P4X400";
 #endif
 
 		case VIA_APOLLO_PRO: 	head->chipset = "VIA Apollo Pro";
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/drm-4.0/i810_dma.c linux-2.4.21-pre6/drivers/char/drm-4.0/i810_dma.c
--- linux-2.4.20/drivers/char/drm-4.0/i810_dma.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/drm-4.0/i810_dma.c	2003-03-26 23:49:49.000000000 +0000
@@ -231,7 +231,7 @@
 #else
         	retcode = do_munmap(current->mm, 
 				    (unsigned long)buf_priv->virtual, 
-				    (size_t) buf->total);
+				    (size_t) buf->total, 1);
 #endif
    		up_write(&current->mm->mmap_sem);
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/efirtc.c linux-2.4.21-pre6/drivers/char/efirtc.c
--- linux-2.4.20/drivers/char/efirtc.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/efirtc.c	2003-03-26 23:49:50.000000000 +0000
@@ -40,7 +40,7 @@
 #include <asm/uaccess.h>
 #include <asm/system.h>
 
-#define EFI_RTC_VERSION		"0.3"
+#define EFI_RTC_VERSION		"0.4"
 
 #define EFI_ISDST (EFI_TIME_ADJUST_DAYLIGHT|EFI_TIME_IN_DAYLIGHT)
 /*
@@ -315,14 +315,14 @@
 	spin_unlock_irqrestore(&efi_rtc_lock,flags);
 
 	p += sprintf(p,
-		     "Time          : %u:%u:%u.%09u\n"
-		     "Date          : %u-%u-%u\n"
-		     "Daylight      : %u\n",
+		     "Time           : %u:%u:%u.%09u\n"
+		     "Date           : %u-%u-%u\n"
+		     "Daylight       : %u\n",
 		     eft.hour, eft.minute, eft.second, eft.nanosecond, 
 		     eft.year, eft.month, eft.day,
 		     eft.daylight);
 
-	if ( eft.timezone == EFI_UNSPECIFIED_TIMEZONE)
+	if (eft.timezone == EFI_UNSPECIFIED_TIMEZONE)
 		p += sprintf(p, "Timezone       : unspecified\n");
 	else
 		/* XXX fixme: convert to string? */
@@ -341,7 +341,7 @@
 		     enabled == 1 ? "yes" : "no",
 		     pending == 1 ? "yes" : "no");
 
-	if ( eft.timezone == EFI_UNSPECIFIED_TIMEZONE)
+	if (eft.timezone == EFI_UNSPECIFIED_TIMEZONE)
 		p += sprintf(p, "Timezone       : unspecified\n");
 	else
 		/* XXX fixme: convert to string? */
@@ -375,12 +375,25 @@
 static int __init 
 efi_rtc_init(void)
 {
-	printk(KERN_INFO "EFI Time Services Driver v%s\n", EFI_RTC_VERSION);
+	int ret;
+	struct proc_dir_entry *dir;
 
-	misc_register(&efi_rtc_dev);
+	printk(KERN_INFO "EFI Time Services Driver v%s\n", EFI_RTC_VERSION);
 
-	create_proc_read_entry ("driver/efirtc", 0, NULL, efi_rtc_read_proc, NULL);
+	ret = misc_register(&efi_rtc_dev);
+	if (ret) {
+		printk(KERN_ERR "efirtc: can't misc_register on minor=%d\n",
+				EFI_RTC_MINOR);
+		return ret;
+	}
 
+	dir = create_proc_read_entry ("driver/efirtc", 0, NULL,
+			              efi_rtc_read_proc, NULL);
+	if (dir == NULL) {
+		printk(KERN_ERR "efirtc: can't create /proc/driver/efirtc.\n");
+		misc_deregister(&efi_rtc_dev);
+		return -1;
+	}
 	return 0;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/epca.c linux-2.4.21-pre6/drivers/char/epca.c
--- linux-2.4.20/drivers/char/epca.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/epca.c	2003-03-26 23:49:40.000000000 +0000
@@ -2023,7 +2023,8 @@
 	    (*(ushort *)((ulong)memaddr + XEPORTS) < 3))
 		shrinkmem = 1;
 	if (bd->type < PCIXEM)
-		request_region((int)bd->port, 4, board_desc[bd->type]);
+		if (!request_region((int)bd->port, 4, board_desc[bd->type]))
+			return;		
 
 	memwinon(bd, 0);
 
@@ -2187,9 +2188,13 @@
 		if (!(ch->tmp_buf))
 		{
 			printk(KERN_ERR "POST FEP INIT : kmalloc failed for port 0x%x\n",i);
-
+			release_region((int)bd->port, 4);
+			while(i-- > 0)
+				kfree((ch--)->tmp_buf);
+			return;
 		}
-		memset((void *)ch->tmp_buf,0,ch->txbufsize);
+		else 
+			memset((void *)ch->tmp_buf,0,ch->txbufsize);
 	} /* End for each port */
 
 	printk(KERN_INFO 
@@ -3750,7 +3755,7 @@
 
 			case 5:
 				board.port = (unsigned char *)ints[index];
-				if (board.port <= 0)
+				if (ints[index] <= 0)
 				{
 					printk(KERN_ERR "<Error> - epca_setup: Invalid io port 0x%x\n", (unsigned int)board.port);
 					invalid_lilo_config = 1;
@@ -3762,7 +3767,7 @@
 
 			case 6:
 				board.membase = (unsigned char *)ints[index];
-				if (board.membase <= 0)
+				if (ints[index] <= 0)
 				{
 					printk(KERN_ERR "<Error> - epca_setup: Invalid memory base 0x%x\n",(unsigned int)board.membase);
 					invalid_lilo_config = 1;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/genrtc.c linux-2.4.21-pre6/drivers/char/genrtc.c
--- linux-2.4.20/drivers/char/genrtc.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/genrtc.c	2003-03-26 23:49:20.000000000 +0000
@@ -0,0 +1,533 @@
+/*
+ *	Real Time Clock interface for
+ *		- q40 and other m68k machines,
+ *		- HP PARISC machines
+ *		- PowerPC machines
+ *      emulate some RTC irq capabilities in software
+ *
+ *      Copyright (C) 1999 Richard Zidlicky
+ *
+ *	based on Paul Gortmaker's rtc.c device and
+ *           Sam Creasey Generic rtc driver
+ *
+ *	This driver allows use of the real time clock (built into
+ *	nearly all computers) from user space. It exports the /dev/rtc
+ *	interface supporting various ioctl() and also the /proc/dev/rtc
+ *	pseudo-file for status information.
+ *
+ *	The ioctls can be used to set the interrupt behaviour where
+ *	supported.
+ *
+ *	The /dev/rtc interface will block on reads until an interrupt
+ *	has been received. If a RTC interrupt has already happened,
+ *	it will output an unsigned long and then block. The output value
+ *	contains the interrupt status in the low byte and the number of
+ *	interrupts since the last read in the remaining high bytes. The
+ *	/dev/rtc interface can also be used with the select(2) call.
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ *
+
+ *      1.01 fix for 2.3.X                    rz@linux-m68k.org
+ *      1.02 merged with code from genrtc.c   rz@linux-m68k.org
+ *      1.03 make it more portable            zippel@linux-m68k.org
+ *      1.04 removed useless timer code       rz@linux-m68k.org
+ *      1.05 portable RTC_UIE emulation       rz@linux-m68k.org
+ *      1.06 set_rtc_time can return an error trini@kernel.crashing.org
+ *      1.07 ported to HP PARISC (hppa)	      Helge Deller <deller@gmx.de>
+ */
+
+#define RTC_VERSION	"1.07"
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/fcntl.h>
+
+#include <linux/rtc.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/rtc.h>
+
+/*
+ *	We sponge a minor off of the misc major. No need slurping
+ *	up another valuable major dev number for this. If you add
+ *	an ioctl, make sure you don't conflict with SPARC's RTC
+ *	ioctls.
+ */
+
+static DECLARE_WAIT_QUEUE_HEAD(gen_rtc_wait);
+
+/*
+ *	Bits in gen_rtc_status.
+ */
+
+#define RTC_IS_OPEN		0x01	/* means /dev/rtc is in use	*/
+
+static unsigned char gen_rtc_status;	/* bitmapped status byte.	*/
+static unsigned long gen_rtc_irq_data;	/* our output to the world	*/
+
+/* months start at 0 now */
+static unsigned char days_in_mo[] =
+{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+static int irq_active;
+
+#ifdef CONFIG_GEN_RTC_X
+struct tq_struct genrtc_task;
+static struct timer_list timer_task;
+
+static unsigned int oldsecs;
+static int lostint;
+static int tt_exp;
+
+static void gen_rtc_timer(unsigned long data);
+
+static volatile int stask_active;              /* schedule_task */
+static volatile int ttask_active;              /* timer_task */
+static int stop_rtc_timers;                    /* don't requeue tasks */
+static spinlock_t gen_rtc_lock = SPIN_LOCK_UNLOCKED;
+
+static void gen_rtc_interrupt(unsigned long arg);
+
+/*
+ * Routine to poll RTC seconds field for change as often as posible,
+ * after first RTC_UIE use timer to reduce polling
+ */
+static void genrtc_troutine(void *data)
+{
+	unsigned int tmp = get_rtc_ss();
+	
+	if (stop_rtc_timers) {
+		stask_active = 0;
+		return;
+	}
+
+	if (oldsecs != tmp){
+		oldsecs = tmp;
+
+		timer_task.function = gen_rtc_timer;
+		timer_task.expires = jiffies + HZ - (HZ/10);
+		tt_exp=timer_task.expires;
+		ttask_active=1;
+		stask_active=0;
+		add_timer(&timer_task);
+
+		gen_rtc_interrupt(0);
+	} else if (schedule_task(&genrtc_task) == 0)
+		stask_active = 0;
+}
+
+static void gen_rtc_timer(unsigned long data)
+{
+	lostint = get_rtc_ss() - oldsecs ;
+	if (lostint<0) 
+		lostint = 60 - lostint;
+	if (time_after(jiffies, tt_exp))
+		printk(KERN_INFO "genrtc: timer task delayed by %ld jiffies\n",
+		       jiffies-tt_exp);
+	ttask_active=0;
+	stask_active=1;
+	if ((schedule_task(&genrtc_task) == 0))
+		stask_active = 0;
+}
+
+/* 
+ * call gen_rtc_interrupt function to signal an RTC_UIE,
+ * arg is unused.
+ * Could be invoked either from a real interrupt handler or
+ * from some routine that periodically (eg 100HZ) monitors
+ * whether RTC_SECS changed
+ */
+static void gen_rtc_interrupt(unsigned long arg)
+{
+	/*  We store the status in the low byte and the number of
+	 *	interrupts received since the last read in the remainder
+	 *	of rtc_irq_data.  */
+
+	gen_rtc_irq_data += 0x100;
+	gen_rtc_irq_data &= ~0xff;
+	gen_rtc_irq_data |= RTC_UIE;
+
+	if (lostint){
+		printk("genrtc: system delaying clock ticks?\n");
+		/* increment count so that userspace knows something is wrong */
+		gen_rtc_irq_data += ((lostint-1)<<8);
+		lostint = 0;
+	}
+
+	wake_up_interruptible(&gen_rtc_wait);
+}
+
+/*
+ *	Now all the various file operations that we export.
+ */
+static ssize_t gen_rtc_read(struct file *file, char *buf,
+			size_t count, loff_t *ppos)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	unsigned long data;
+	ssize_t retval;
+
+	if (count != sizeof (unsigned int) && count != sizeof (unsigned long))
+		return -EINVAL;
+
+	if (file->f_flags & O_NONBLOCK && !gen_rtc_irq_data)
+		return -EAGAIN;
+
+	add_wait_queue(&gen_rtc_wait, &wait);
+	retval = -ERESTARTSYS;
+
+	while (1) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		data = xchg(&gen_rtc_irq_data, 0);
+		if (data)
+			break;
+		if (signal_pending(current))
+			goto out;
+		schedule();
+	}
+
+	/* first test allows optimizer to nuke this case for 32-bit machines */
+	if (sizeof (int) != sizeof (long) && count == sizeof (unsigned int)) {
+		unsigned int uidata = data;
+		retval = put_user(uidata, (unsigned long *)buf);
+	}
+	else {
+		retval = put_user(data, (unsigned long *)buf);
+	}
+	if (!retval)
+		retval = sizeof(unsigned long);
+ out:
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&gen_rtc_wait, &wait);
+
+	return retval;
+}
+
+static unsigned int gen_rtc_poll(struct file *file,
+				 struct poll_table_struct *wait)
+{
+	poll_wait(file, &gen_rtc_wait, wait);
+	if (gen_rtc_irq_data != 0)
+		return POLLIN | POLLRDNORM;
+	return 0;
+}
+
+#endif
+
+/*
+ * Used to disable/enable interrupts, only RTC_UIE supported
+ * We also clear out any old irq data after an ioctl() that
+ * meddles with the interrupt enable/disable bits.
+ */
+
+static inline void gen_clear_rtc_irq_bit(unsigned char bit)
+{
+#ifdef CONFIG_GEN_RTC_X
+	stop_rtc_timers = 1;
+	if (ttask_active){
+		del_timer_sync(&timer_task);
+		ttask_active = 0;
+	}
+	while (stask_active)
+		schedule();
+
+	spin_lock(&gen_rtc_lock);
+	irq_active = 0;
+	spin_unlock(&gen_rtc_lock);
+#endif
+}
+
+static inline int gen_set_rtc_irq_bit(unsigned char bit)
+{
+#ifdef CONFIG_GEN_RTC_X
+	spin_lock(&gen_rtc_lock);
+	if ( !irq_active ) {
+		irq_active = 1;
+		stop_rtc_timers = 0;
+		lostint = 0;
+		genrtc_task.routine = genrtc_troutine;
+		oldsecs = get_rtc_ss();
+		init_timer(&timer_task);
+
+		stask_active = 1;
+		if (schedule_task(&genrtc_task) == 0){
+			stask_active = 0;
+		}
+	}
+	spin_unlock(&gen_rtc_lock);
+	gen_rtc_irq_data = 0;
+	return 0;
+#else
+	return -EINVAL;
+#endif
+}
+
+static int gen_rtc_ioctl(struct inode *inode, struct file *file,
+			 unsigned int cmd, unsigned long arg)
+{
+	struct rtc_time wtime;
+	struct rtc_pll_info pll;
+
+	switch (cmd) {
+
+	case RTC_PLL_GET:
+	    if (get_rtc_pll(&pll))
+	 	    return -EINVAL;
+	    else
+		    return copy_to_user((void *)arg, &pll, sizeof pll) ? -EFAULT : 0;
+
+	case RTC_PLL_SET:
+		if (!capable(CAP_SYS_TIME))
+			return -EACCES;
+		if (copy_from_user(&pll, (struct rtc_pll_info*)arg,
+				   sizeof(pll)))
+			return -EFAULT;
+	    return set_rtc_pll(&pll);
+
+	case RTC_UIE_OFF:	/* disable ints from RTC updates.	*/
+		gen_clear_rtc_irq_bit(RTC_UIE);
+		return 0;
+
+	case RTC_UIE_ON:	/* enable ints for RTC updates.	*/
+	        return gen_set_rtc_irq_bit(RTC_UIE);
+
+	case RTC_RD_TIME:	/* Read the time/date from RTC	*/
+		/* this doesn't get week-day, who cares */
+		memset(&wtime, 0, sizeof(wtime));
+		get_rtc_time(&wtime);
+
+		return copy_to_user((void *)arg, &wtime, sizeof(wtime)) ? -EFAULT : 0;
+
+	case RTC_SET_TIME:	/* Set the RTC */
+	    {
+		int year;
+		unsigned char leap_yr;
+
+		if (!capable(CAP_SYS_TIME))
+			return -EACCES;
+
+		if (copy_from_user(&wtime, (struct rtc_time *)arg,
+				   sizeof(wtime)))
+			return -EFAULT;
+
+		year = wtime.tm_year + 1900;
+		leap_yr = ((!(year % 4) && (year % 100)) ||
+			   !(year % 400));
+
+		if ((wtime.tm_mon < 0 || wtime.tm_mon > 11) || (wtime.tm_mday < 1))
+			return -EINVAL;
+
+		if (wtime.tm_mday < 0 || wtime.tm_mday >
+		    (days_in_mo[wtime.tm_mon] + ((wtime.tm_mon == 1) && leap_yr)))
+			return -EINVAL;
+
+		if (wtime.tm_hour < 0 || wtime.tm_hour >= 24 ||
+		    wtime.tm_min < 0 || wtime.tm_min >= 60 ||
+		    wtime.tm_sec < 0 || wtime.tm_sec >= 60)
+			return -EINVAL;
+
+		return set_rtc_time(&wtime);
+	    }
+	}
+
+	return -EINVAL;
+}
+
+/*
+ *	We enforce only one user at a time here with the open/close.
+ *	Also clear the previous interrupt data on an open, and clean
+ *	up things on a close.
+ */
+
+static int gen_rtc_open(struct inode *inode, struct file *file)
+{
+	if (gen_rtc_status & RTC_IS_OPEN)
+		return -EBUSY;
+
+	MOD_INC_USE_COUNT;
+
+	gen_rtc_status |= RTC_IS_OPEN;
+	gen_rtc_irq_data = 0;
+	irq_active = 0;
+
+	return 0;
+}
+
+static int gen_rtc_release(struct inode *inode, struct file *file)
+{
+	/*
+	 * Turn off all interrupts once the device is no longer
+	 * in use and clear the data.
+	 */
+
+	gen_clear_rtc_irq_bit(RTC_PIE|RTC_AIE|RTC_UIE);
+
+	gen_rtc_status &= ~RTC_IS_OPEN;
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+static int gen_rtc_read_proc(char *page, char **start, off_t off,
+			     int count, int *eof, void *data);
+
+
+/*
+ *	The various file operations we support.
+ */
+
+static struct file_operations gen_rtc_fops = {
+	.owner		= THIS_MODULE,
+#ifdef CONFIG_GEN_RTC_X
+	.read		= gen_rtc_read,
+	.poll		= gen_rtc_poll,
+#endif
+	.ioctl		= gen_rtc_ioctl,
+	.open		= gen_rtc_open,
+	.release	= gen_rtc_release,
+};
+
+static struct miscdevice rtc_gen_dev =
+{
+	.minor		= RTC_MINOR,
+	.name		= "rtc",
+	.fops		= &gen_rtc_fops,
+};
+
+static int __init rtc_generic_init(void)
+{
+	int retval;
+
+	printk(KERN_INFO "Generic RTC Driver v%s\n", RTC_VERSION);
+
+	retval = misc_register(&rtc_gen_dev);
+	if(retval < 0)
+		return retval;
+
+#ifdef CONFIG_PROC_FS
+	if((create_proc_read_entry ("driver/rtc", 0, 0, gen_rtc_read_proc, NULL)) == NULL){
+		misc_deregister(&rtc_gen_dev);
+		return -ENOMEM;
+	}
+#endif
+
+	return 0;
+}
+
+static void __exit rtc_generic_exit(void)
+{
+	remove_proc_entry ("driver/rtc", NULL);
+	misc_deregister(&rtc_gen_dev);
+}
+
+module_init(rtc_generic_init);
+module_exit(rtc_generic_exit);
+EXPORT_NO_SYMBOLS;
+
+
+/*
+ *	Info exported via "/proc/rtc".
+ */
+
+#ifdef CONFIG_PROC_FS
+
+static int gen_rtc_proc_output(char *buf)
+{
+	char *p;
+	struct rtc_time tm;
+	unsigned int flags;
+	struct rtc_pll_info pll;
+
+	p = buf;
+
+	flags = get_rtc_time(&tm);
+
+	p += sprintf(p,
+		     "rtc_time\t: %02d:%02d:%02d\n"
+		     "rtc_date\t: %04d-%02d-%02d\n"
+		     "rtc_epoch\t: %04u\n",
+		     tm.tm_hour, tm.tm_min, tm.tm_sec,
+		     tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, 1900);
+
+	tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
+
+	p += sprintf(p, "alarm\t\t: ");
+	if (tm.tm_hour <= 24)
+		p += sprintf(p, "%02d:", tm.tm_hour);
+	else
+		p += sprintf(p, "**:");
+
+	if (tm.tm_min <= 59)
+		p += sprintf(p, "%02d:", tm.tm_min);
+	else
+		p += sprintf(p, "**:");
+
+	if (tm.tm_sec <= 59)
+		p += sprintf(p, "%02d\n", tm.tm_sec);
+	else
+		p += sprintf(p, "**\n");
+
+	p += sprintf(p,
+		     "DST_enable\t: %s\n"
+		     "BCD\t\t: %s\n"
+		     "24hr\t\t: %s\n"
+		     "square_wave\t: %s\n"
+		     "alarm_IRQ\t: %s\n"
+		     "update_IRQ\t: %s\n"
+		     "periodic_IRQ\t: %s\n"
+		     "periodic_freq\t: %ld\n"
+		     "batt_status\t: %s\n",
+		     (flags & RTC_DST_EN) ? "yes" : "no",
+		     (flags & RTC_DM_BINARY) ? "no" : "yes",
+		     (flags & RTC_24H) ? "yes" : "no",
+		     (flags & RTC_SQWE) ? "yes" : "no",
+		     (flags & RTC_AIE) ? "yes" : "no",
+		     irq_active ? "yes" : "no",
+		     (flags & RTC_PIE) ? "yes" : "no",
+		     0L /* freq */,
+		     (flags & RTC_BATT_BAD) ? "bad" : "okay");
+	if (!get_rtc_pll(&pll))
+	    p += sprintf(p,
+			 "PLL adjustment\t: %d\n"
+			 "PLL max +ve adjustment\t: %d\n"
+			 "PLL max -ve adjustment\t: %d\n"
+			 "PLL +ve adjustment factor\t: %d\n"
+			 "PLL -ve adjustment factor\t: %d\n"
+			 "PLL frequency\t: %ld\n",
+			 pll.pll_value,
+			 pll.pll_max,
+			 pll.pll_min,
+			 pll.pll_posmult,
+			 pll.pll_negmult,
+			 pll.pll_clock);
+	return p - buf;
+}
+
+static int gen_rtc_read_proc(char *page, char **start, off_t off,
+			     int count, int *eof, void *data)
+{
+	int len = gen_rtc_proc_output (page);
+        if (len <= off+count) *eof = 1;
+	*start = page + off;
+	len -= off;
+        if (len>count) len = count;
+        if (len<0) len = 0;
+	return len;
+}
+
+#endif /* CONFIG_PROC_FS */
+
+
+MODULE_AUTHOR("Richard Zidlicky");
+MODULE_LICENSE("GPL");
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/i810_rng.c linux-2.4.21-pre6/drivers/char/i810_rng.c
--- linux-2.4.20/drivers/char/i810_rng.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/i810_rng.c	2003-03-26 23:49:34.000000000 +0000
@@ -1,7 +1,7 @@
 /*
 
 	Hardware driver for Intel i810 Random Number Generator (RNG)
-	Copyright 2000,2001 Jeff Garzik <jgarzik@mandrakesoft.com>
+	Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>
 	Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>
 
 	Driver Web site:  http://sourceforge.net/projects/gkernel/
@@ -27,6 +27,7 @@
 #include <linux/miscdevice.h>
 #include <linux/smp_lock.h>
 #include <linux/mm.h>
+#include <linux/delay.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -243,8 +244,13 @@
 		if (filp->f_flags & O_NONBLOCK)
 			return ret ? : -EAGAIN;
 
-		current->state = TASK_INTERRUPTIBLE;
-		schedule_timeout(1);
+		if (current->need_resched)
+		{
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(1);
+		}
+		else
+			udelay(200);
 
 		if (signal_pending (current))
 			return ret ? : -ERESTARTSYS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/ipmi/Makefile linux-2.4.21-pre6/drivers/char/ipmi/Makefile
--- linux-2.4.20/drivers/char/ipmi/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/ipmi/Makefile	2003-03-26 23:49:19.000000000 +0000
@@ -0,0 +1,20 @@
+#
+# Makefile for the ipmi drivers.
+#
+
+O_TARGET	:= ipmi.o
+
+export-objs	:= ipmi_msghandler.o ipmi_watchdog.o
+
+list-multi := ipmi_kcs_drv.o
+ipmi_kcs_drv-objs := ipmi_kcs_sm.o ipmi_kcs_intf.o
+
+obj-$(CONFIG_IPMI_HANDLER) += ipmi_msghandler.o
+obj-$(CONFIG_IPMI_DEVICE_INTERFACE) += ipmi_devintf.o
+obj-$(CONFIG_IPMI_KCS) += ipmi_kcs_drv.o
+obj-$(CONFIG_IPMI_WATCHDOG) += ipmi_watchdog.o
+
+include $(TOPDIR)/Rules.make
+
+ipmi_kcs_drv.o:	$(ipmi_kcs_drv-objs)
+	$(LD) -r -o $@ $(ipmi_kcs_drv-objs) 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/ipmi/ipmi_devintf.c linux-2.4.21-pre6/drivers/char/ipmi/ipmi_devintf.c
--- linux-2.4.20/drivers/char/ipmi/ipmi_devintf.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/ipmi/ipmi_devintf.c	2003-03-26 23:48:59.000000000 +0000
@@ -0,0 +1,532 @@
+/*
+ * ipmi_devintf.c
+ *
+ * Linux device interface for the IPMI message handler.
+ *
+ * Author: MontaVista Software, Inc.
+ *         Corey Minyard <minyard@mvista.com>
+ *         source@mvista.com
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; either version 2 of the License, or (at your
+ *  option) any later version.
+ *
+ *
+ *  THIS 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.
+ *
+ *  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/errno.h>
+#include <asm/system.h>
+#include <linux/sched.h>
+#include <linux/poll.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/ipmi.h>
+#include <asm/semaphore.h>
+#include <linux/init.h>
+
+struct ipmi_file_private
+{
+	ipmi_user_t          user;
+	spinlock_t           recv_msg_lock;
+	struct list_head     recv_msgs;
+	struct file          *file;
+	struct fasync_struct *fasync_queue;
+	wait_queue_head_t    wait;
+	struct semaphore     recv_sem;
+};
+
+static void file_receive_handler(struct ipmi_recv_msg *msg,
+				 void                 *handler_data)
+{
+	struct ipmi_file_private *priv = handler_data;
+	int                      was_empty;
+	unsigned long            flags;
+
+	spin_lock_irqsave(&(priv->recv_msg_lock), flags);
+
+	was_empty = list_empty(&(priv->recv_msgs));
+	list_add_tail(&(msg->link), &(priv->recv_msgs));
+
+	if (was_empty) {
+		wake_up_interruptible(&priv->wait);
+		kill_fasync(&priv->fasync_queue, SIGIO, POLL_IN);
+	}
+
+	spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
+}
+
+static unsigned int ipmi_poll(struct file *file, poll_table *wait)
+{
+	struct ipmi_file_private *priv = file->private_data;
+	unsigned int             mask = 0;
+	unsigned long            flags;
+
+	spin_lock_irqsave(&priv->recv_msg_lock, flags);
+
+	poll_wait(file, &priv->wait, wait);
+
+	if (! list_empty(&(priv->recv_msgs)))
+		mask |= (POLLIN | POLLRDNORM);
+
+	spin_unlock_irqrestore(&priv->recv_msg_lock, flags);
+
+	return mask;
+}
+
+static int ipmi_fasync(int fd, struct file *file, int on)
+{
+	struct ipmi_file_private *priv = file->private_data;
+	int                      result;
+
+	result = fasync_helper(fd, file, on, &priv->fasync_queue);
+
+	return (result);
+}
+
+static struct ipmi_user_hndl ipmi_hndlrs =
+{
+	ipmi_recv_hndl : file_receive_handler
+};
+
+static int ipmi_open(struct inode *inode, struct file *file)
+{
+	int                      if_num = minor(inode->i_rdev);
+	int                      rv;
+	struct ipmi_file_private *priv;
+
+
+	priv = kmalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->file = file;
+
+	rv = ipmi_create_user(if_num,
+			      &ipmi_hndlrs,
+			      priv,
+			      &(priv->user));
+	if (rv) {
+		kfree(priv);
+		return rv;
+	}
+
+	file->private_data = priv;
+
+	spin_lock_init(&(priv->recv_msg_lock));
+	INIT_LIST_HEAD(&(priv->recv_msgs));
+	init_waitqueue_head(&priv->wait);
+	priv->fasync_queue = NULL;
+	sema_init(&(priv->recv_sem), 1);
+
+	return 0;
+}
+
+static int ipmi_release(struct inode *inode, struct file *file)
+{
+	struct ipmi_file_private *priv = file->private_data;
+	int                      rv;
+
+	rv = ipmi_destroy_user(priv->user);
+	if (rv)
+		return rv;
+
+	ipmi_fasync (-1, file, 0);
+
+	/* FIXME - free the messages in the list. */
+	kfree(priv);
+
+	return 0;
+}
+
+static int ipmi_ioctl(struct inode  *inode,
+		      struct file   *file,
+		      unsigned int  cmd,
+		      unsigned long data)
+{
+	int                      rv = -EINVAL;
+	struct ipmi_file_private *priv = file->private_data;
+
+	switch (cmd) 
+	{
+	case IPMICTL_SEND_COMMAND:
+	{
+		struct ipmi_req    req;
+		struct ipmi_addr   addr;
+		unsigned char msgdata[IPMI_MAX_MSG_LENGTH];
+
+		if (copy_from_user(&req, (void *) data, sizeof(req))) {
+			rv = -EFAULT;
+			break;
+		}
+
+		if (req.addr_len > sizeof(struct ipmi_addr))
+		{
+			rv = -EINVAL;
+			break;
+		}
+
+		if (copy_from_user(&addr, req.addr, req.addr_len)) {
+			rv = -EFAULT;
+			break;
+		}
+
+		rv = ipmi_validate_addr(&addr, req.addr_len);
+		if (rv)
+			break;
+
+		if (req.msg.data != NULL) {
+			if (req.msg.data_len > IPMI_MAX_MSG_LENGTH) {
+				rv = -EMSGSIZE;
+				break;
+			}
+
+			if (copy_from_user(&msgdata,
+					   req.msg.data,
+					   req.msg.data_len))
+			{
+				rv = -EFAULT;
+				break;
+			}
+		} else {
+			req.msg.data_len = 0;
+		}
+
+		req.msg.data = msgdata;
+
+		rv = ipmi_request(priv->user,
+				  &addr,
+				  req.msgid,
+				  &(req.msg),
+				  0);
+		break;
+	}
+
+	case IPMICTL_RECEIVE_MSG:
+	case IPMICTL_RECEIVE_MSG_TRUNC:
+	{
+		struct ipmi_recv      rsp;
+		int              addr_len;
+		struct list_head *entry;
+		struct ipmi_recv_msg  *msg;
+		unsigned long    flags;
+		
+
+		rv = 0;
+		if (copy_from_user(&rsp, (void *) data, sizeof(rsp))) {
+			rv = -EFAULT;
+			break;
+		}
+
+		/* We claim a semaphore because we don't want two
+                   users getting something from the queue at a time.
+                   Since we have to release the spinlock before we can
+                   copy the data to the user, it's possible another
+                   user will grab something from the queue, too.  Then
+                   the messages might get out of order if something
+                   fails and the message gets put back onto the
+                   queue.  This semaphore prevents that problem. */
+		down(&(priv->recv_sem));
+
+		/* Grab the message off the list. */
+		spin_lock_irqsave(&(priv->recv_msg_lock), flags);
+		if (list_empty(&(priv->recv_msgs))) {
+			spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
+			rv = -EAGAIN;
+			goto recv_err;
+		}
+		entry = priv->recv_msgs.next;
+		msg = list_entry(entry, struct ipmi_recv_msg, link);
+		list_del(entry);
+		spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
+
+		addr_len = ipmi_addr_length(msg->addr.addr_type);
+		if (rsp.addr_len < addr_len)
+		{
+			rv = -EINVAL;
+			goto recv_putback_on_err;
+		}
+
+		if (copy_to_user(rsp.addr, &(msg->addr), addr_len)) {
+			rv = -EFAULT;
+			goto recv_putback_on_err;
+		}
+		rsp.addr_len = addr_len;
+
+		rsp.recv_type = msg->recv_type;
+		rsp.msgid = msg->msgid;
+		rsp.msg.netfn = msg->msg.netfn;
+		rsp.msg.cmd = msg->msg.cmd;
+
+		if (msg->msg.data_len > 0) {
+			if (rsp.msg.data_len < msg->msg.data_len) {
+				rv = -EMSGSIZE;
+				if (cmd == IPMICTL_RECEIVE_MSG_TRUNC) {
+					msg->msg.data_len = rsp.msg.data_len;
+				} else {
+					goto recv_putback_on_err;
+				}
+			}
+
+			if (copy_to_user(rsp.msg.data,
+					 msg->msg.data,
+					 msg->msg.data_len))
+			{
+				rv = -EFAULT;
+				goto recv_putback_on_err;
+			}
+			rsp.msg.data_len = msg->msg.data_len;
+		} else {
+			rsp.msg.data_len = 0;
+		}
+
+		if (copy_to_user((void *) data, &rsp, sizeof(rsp))) {
+			rv = -EFAULT;
+			goto recv_putback_on_err;
+		}
+
+		up(&(priv->recv_sem));
+		ipmi_free_recv_msg(msg);
+		break;
+
+	recv_putback_on_err:
+		/* If we got an error, put the message back onto
+		   the head of the queue. */
+		spin_lock_irqsave(&(priv->recv_msg_lock), flags);
+		list_add(entry, &(priv->recv_msgs));
+		spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
+		up(&(priv->recv_sem));
+		break;
+
+	recv_err:
+		up(&(priv->recv_sem));
+		break;
+	}
+
+	case IPMICTL_REGISTER_FOR_CMD:
+	{
+		struct ipmi_cmdspec val;
+
+		if (copy_from_user(&val, (void *) data, sizeof(val))) {
+			rv = -EFAULT;
+			break;
+		}
+
+		rv = ipmi_register_for_cmd(priv->user, val.netfn, val.cmd);
+		break;
+	}
+
+	case IPMICTL_UNREGISTER_FOR_CMD:
+	{
+		struct ipmi_cmdspec   val;
+
+		if (copy_from_user(&val, (void *) data, sizeof(val))) {
+			rv = -EFAULT;
+			break;
+		}
+
+		rv = ipmi_unregister_for_cmd(priv->user, val.netfn, val.cmd);
+		break;
+	}
+
+	case IPMICTL_SET_GETS_EVENTS_CMD:
+	{
+		int val;
+
+		if (copy_from_user(&val, (void *) data, sizeof(val))) {
+			rv = -EFAULT;
+			break;
+		}
+
+		rv = ipmi_set_gets_events(priv->user, val);
+		break;
+	}
+
+	case IPMICTL_SET_MY_ADDRESS_CMD:
+	{
+		unsigned int val;
+
+		if (copy_from_user(&val, (void *) data, sizeof(val))) {
+			rv = -EFAULT;
+			break;
+		}
+
+		ipmi_set_my_address(priv->user, val);
+		rv = 0;
+		break;
+	}
+
+	case IPMICTL_GET_MY_ADDRESS_CMD:
+	{
+		unsigned int val;
+
+		val = ipmi_get_my_address(priv->user);
+
+		if (copy_to_user((void *) data, &val, sizeof(val))) {
+			rv = -EFAULT;
+			break;
+		}
+		rv = 0;
+		break;
+	}
+
+	case IPMICTL_SET_MY_LUN_CMD:
+	{
+		unsigned int val;
+
+		if (copy_from_user(&val, (void *) data, sizeof(val))) {
+			rv = -EFAULT;
+			break;
+		}
+
+		ipmi_set_my_LUN(priv->user, val);
+		rv = 0;
+		break;
+	}
+
+	case IPMICTL_GET_MY_LUN_CMD:
+	{
+		unsigned int val;
+
+		val = ipmi_get_my_LUN(priv->user);
+
+		if (copy_to_user((void *) data, &val, sizeof(val))) {
+			rv = -EFAULT;
+			break;
+		}
+		rv = 0;
+		break;
+	}
+
+	}
+  
+	return rv;
+}
+
+
+static struct file_operations ipmi_fops = {
+	owner:   THIS_MODULE,
+	ioctl:   ipmi_ioctl,
+	open:    ipmi_open,
+	release: ipmi_release,
+	fasync:  ipmi_fasync,
+	poll:    ipmi_poll
+};
+
+#define DEVICE_NAME     "ipmidev"
+
+static int ipmi_major = 0;
+MODULE_PARM(ipmi_major, "i");
+
+static devfs_handle_t devfs_handle;
+
+#define MAX_DEVICES 10
+static devfs_handle_t handles[MAX_DEVICES];
+
+static void ipmi_new_smi(int if_num)
+{
+	char name[2];
+
+	if (if_num > MAX_DEVICES)
+		return;
+
+	name[0] = if_num + '0';
+	name[1] = '\0';
+
+	handles[if_num] = devfs_register(devfs_handle, name, DEVFS_FL_NONE,
+					 ipmi_major, if_num,
+					 S_IFCHR | S_IRUSR | S_IWUSR,
+					 &ipmi_fops, NULL);
+}
+
+static void ipmi_smi_gone(int if_num)
+{
+	if (if_num > MAX_DEVICES)
+		return;
+
+	devfs_unregister(handles[if_num]);
+}
+
+static struct ipmi_smi_watcher smi_watcher =
+{
+	new_smi  : ipmi_new_smi,
+	smi_gone : ipmi_smi_gone
+};
+
+static __init int init_ipmi_devintf(void)
+{
+	int rv;
+
+	if (ipmi_major < 0)
+		return -EINVAL;
+
+	rv = register_chrdev(ipmi_major, DEVICE_NAME, &ipmi_fops);
+	if (rv < 0) {
+		printk(KERN_ERR "ipmi: can't get major %d\n", ipmi_major);
+		return rv;
+	}
+
+	if (ipmi_major == 0) {
+		ipmi_major = rv;
+	}
+
+	devfs_handle = devfs_mk_dir(NULL, DEVICE_NAME, NULL);
+
+	rv = ipmi_smi_watcher_register(&smi_watcher);
+	if (rv) {
+		unregister_chrdev(ipmi_major, DEVICE_NAME);
+		printk(KERN_WARNING "ipmi: can't register smi watcher");
+		return rv;
+	}
+
+	printk(KERN_INFO "ipmi: device interface at char major %d\n",
+	       ipmi_major);
+
+	return 0;
+}
+module_init(init_ipmi_devintf);
+
+static __exit void cleanup_ipmi(void)
+{
+	ipmi_smi_watcher_unregister(&smi_watcher);
+	devfs_unregister(devfs_handle);
+	unregister_chrdev(ipmi_major, DEVICE_NAME);
+}
+module_exit(cleanup_ipmi);
+#ifndef MODULE
+static __init int ipmi_setup (char *str)
+{
+	int x;
+
+	if (get_option (&str, &x)) {
+		/* ipmi=x sets the major number to x. */
+		ipmi_major = x;
+	} else if (!strcmp(str, "off")) {
+		ipmi_major = -1;
+	}
+
+	return 1;
+}
+#endif
+
+__setup("ipmi=", ipmi_setup);
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/ipmi/ipmi_kcs_intf.c linux-2.4.21-pre6/drivers/char/ipmi/ipmi_kcs_intf.c
--- linux-2.4.20/drivers/char/ipmi/ipmi_kcs_intf.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/ipmi/ipmi_kcs_intf.c	2003-03-26 23:49:19.000000000 +0000
@@ -0,0 +1,1243 @@
+/*
+ * ipmi_kcs_intf.c
+ *
+ * The interface to the IPMI driver for the KCS.
+ *
+ * Author: MontaVista Software, Inc.
+ *         Corey Minyard <minyard@mvista.com>
+ *         source@mvista.com
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; either version 2 of the License, or (at your
+ *  option) any later version.
+ *
+ *
+ *  THIS 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.
+ *
+ *  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 file holds the "policy" for the interface to the KCS state
+ * machine.  It does the configuration, handles timers and interrupts,
+ * and drives the real KCS state machine.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <asm/system.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/ioport.h>
+#ifdef CONFIG_HIGH_RES_TIMERS
+#include <linux/hrtime.h>
+#endif
+#include <linux/interrupt.h>
+#include <linux/ipmi_smi.h>
+#include <asm/io.h>
+#include "ipmi_kcs_sm.h"
+#include <linux/init.h>
+
+/* Measure times between events in the driver. */
+#undef DEBUG_TIMING
+
+#ifdef CONFIG_IPMI_KCS
+/* This forces a dependency to the config file for this option. */
+#endif
+
+enum kcs_intf_state {
+	KCS_NORMAL,
+	KCS_GETTING_FLAGS,
+	KCS_GETTING_EVENTS,
+	KCS_CLEARING_FLAGS,
+	KCS_CLEARING_FLAGS_THEN_SET_IRQ,
+	KCS_GETTING_MESSAGES,
+	KCS_ENABLE_INTERRUPTS1,
+	KCS_ENABLE_INTERRUPTS2
+	/* FIXME - add watchdog stuff. */
+};
+
+struct kcs_info
+{
+	ipmi_smi_t          intf;
+	struct kcs_data     *kcs_sm;
+	spinlock_t          kcs_lock;
+	spinlock_t          msg_lock;
+	struct list_head    xmit_msgs;
+	struct list_head    hp_xmit_msgs;
+	struct ipmi_smi_msg *curr_msg;
+	enum kcs_intf_state kcs_state;
+
+	/* Flags from the last GET_MSG_FLAGS command, used when an ATTN
+	   is set to hold the flags until we are done handling everything
+	   from the flags. */
+#define RECEIVE_MSG_AVAIL	0x01
+#define EVENT_MSG_BUFFER_FULL	0x02
+#define WDT_PRE_TIMEOUT_INT	0x08
+	unsigned char       msg_flags;
+
+	/* If set to true, this will request events the next time the
+	   state machine is idle. */
+	atomic_t            req_events;
+
+	/* If true, run the state machine to completion on every send
+	   call.  Generally used after a panic to make sure stuff goes
+	   out. */
+	int                 run_to_completion;
+
+	/* The I/O port of a KCS interface. */
+	int                 port;
+
+	/* zero if no irq; */
+	int                 irq;
+
+	/* The physical and remapped memory addresses of a KCS interface. */
+	unsigned long	    physaddr;
+	unsigned char	    *addr;
+
+	/* The timer for this kcs. */
+	struct timer_list   kcs_timer;
+
+	/* The time (in jiffies) the last timeout occurred at. */
+	unsigned long       last_timeout_jiffies;
+
+	/* Used to gracefully stop the timer without race conditions. */
+	volatile int        stop_operation;
+	volatile int        timer_stopped;
+
+	/* The driver will disable interrupts when it gets into a
+	   situation where it cannot handle messages due to lack of
+	   memory.  Once that situation clears up, it will re-enable
+	   interupts. */
+	int                 interrupt_disabled;
+};
+
+static void deliver_recv_msg(struct kcs_info *kcs_info, struct ipmi_smi_msg *msg)
+{
+	/* Deliver the message to the upper layer with the lock
+           released. */
+	spin_unlock(&(kcs_info->kcs_lock));
+	ipmi_smi_msg_received(kcs_info->intf, msg);
+	spin_lock(&(kcs_info->kcs_lock));
+}
+
+static void return_hosed_msg(struct kcs_info *kcs_info)
+{
+	struct ipmi_smi_msg *msg = kcs_info->curr_msg;
+
+	/* Make it a reponse */
+	msg->rsp[0] = msg->data[0] | 4;
+	msg->rsp[1] = msg->data[1];
+	msg->rsp[2] = 0xFF; /* Unknown error. */
+	msg->rsp_size = 3;
+			
+	kcs_info->curr_msg = NULL;
+	deliver_recv_msg(kcs_info, msg);
+}
+
+static enum kcs_result start_next_msg(struct kcs_info *kcs_info)
+{
+	int              rv;
+	struct list_head *entry = NULL;
+#ifdef DEBUG_TIMING
+	struct timeval t;
+#endif
+
+	/* No need to save flags, we aleady have interrupts off and we
+	   already hold the KCS lock. */
+	spin_lock(&(kcs_info->msg_lock));
+	
+	/* Pick the high priority queue first. */
+	if (! list_empty(&(kcs_info->hp_xmit_msgs))) {
+		entry = kcs_info->hp_xmit_msgs.next;
+	} else if (! list_empty(&(kcs_info->xmit_msgs))) {
+		entry = kcs_info->xmit_msgs.next;
+	}
+
+	if (!entry) {
+		kcs_info->curr_msg = NULL;
+		rv = KCS_SM_IDLE;
+	} else {
+		int err;
+
+		list_del(entry);
+		kcs_info->curr_msg = list_entry(entry,
+						struct ipmi_smi_msg,
+						link);
+#ifdef DEBUG_TIMING
+		do_gettimeofday(&t);
+		printk("**Start2: %d.%9.9d\n", t.tv_sec, t.tv_usec);
+#endif
+		err = start_kcs_transaction(kcs_info->kcs_sm,
+					   kcs_info->curr_msg->data,
+					   kcs_info->curr_msg->data_size);
+		if (err) {
+			return_hosed_msg(kcs_info);
+		}
+
+		rv = KCS_CALL_WITHOUT_DELAY;
+	}
+	spin_unlock(&(kcs_info->msg_lock));
+
+	return rv;
+}
+
+static void start_enable_irq(struct kcs_info *kcs_info)
+{
+	unsigned char msg[2];
+
+	/* If we are enabling interrupts, we have to tell the
+	   BMC to use them. */
+	msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
+	msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD;
+
+	start_kcs_transaction(kcs_info->kcs_sm, msg, 2);
+	kcs_info->kcs_state = KCS_ENABLE_INTERRUPTS1;
+}
+
+static void start_clear_flags(struct kcs_info *kcs_info)
+{
+	unsigned char msg[3];
+
+	/* Make sure the watchdog pre-timeout flag is not set at startup. */
+	msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
+	msg[1] = IPMI_CLEAR_MSG_FLAGS_CMD;
+	msg[2] = WDT_PRE_TIMEOUT_INT;
+
+	start_kcs_transaction(kcs_info->kcs_sm, msg, 3);
+	kcs_info->kcs_state = KCS_CLEARING_FLAGS;
+}
+
+/* When we have a situtaion where we run out of memory and cannot
+   allocate messages, we just leave them in the BMC and run the system
+   polled until we can allocate some memory.  Once we have some
+   memory, we will re-enable the interrupt. */
+static inline void disable_kcs_irq(struct kcs_info *kcs_info)
+{
+	if ((kcs_info->irq) && (!kcs_info->interrupt_disabled)) {
+		disable_irq_nosync(kcs_info->irq);
+		kcs_info->interrupt_disabled = 1;
+	}
+}
+
+static inline void enable_kcs_irq(struct kcs_info *kcs_info)
+{
+	if ((kcs_info->irq) && (kcs_info->interrupt_disabled)) {
+		enable_irq(kcs_info->irq);
+		kcs_info->interrupt_disabled = 0;
+	}
+}
+
+static void handle_flags(struct kcs_info *kcs_info)
+{
+	if (kcs_info->msg_flags & WDT_PRE_TIMEOUT_INT) {
+		/* Watchdog pre-timeout */
+		start_clear_flags(kcs_info);
+		kcs_info->msg_flags &= ~WDT_PRE_TIMEOUT_INT;
+		spin_unlock(&(kcs_info->kcs_lock));
+		ipmi_smi_watchdog_pretimeout(kcs_info->intf);
+		spin_lock(&(kcs_info->kcs_lock));
+	} else if (kcs_info->msg_flags & RECEIVE_MSG_AVAIL) {
+		/* Messages available. */
+		kcs_info->curr_msg = ipmi_alloc_smi_msg();
+		if (!kcs_info->curr_msg) {
+			disable_kcs_irq(kcs_info);
+			kcs_info->kcs_state = KCS_NORMAL;
+			return;
+		}
+		enable_kcs_irq(kcs_info);
+
+		kcs_info->curr_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
+		kcs_info->curr_msg->data[1] = IPMI_GET_MSG_CMD;
+		kcs_info->curr_msg->data_size = 2;
+
+		start_kcs_transaction(kcs_info->kcs_sm,
+				      kcs_info->curr_msg->data,
+				      kcs_info->curr_msg->data_size);
+		kcs_info->kcs_state = KCS_GETTING_MESSAGES;
+	} else if (kcs_info->msg_flags & EVENT_MSG_BUFFER_FULL) {
+		/* Events available. */
+		kcs_info->curr_msg = ipmi_alloc_smi_msg();
+		if (!kcs_info->curr_msg) {
+			disable_kcs_irq(kcs_info);
+			kcs_info->kcs_state = KCS_NORMAL;
+			return;
+		}
+		enable_kcs_irq(kcs_info);
+
+		kcs_info->curr_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
+		kcs_info->curr_msg->data[1] = IPMI_READ_EVENT_MSG_BUFFER_CMD;
+		kcs_info->curr_msg->data_size = 2;
+
+		start_kcs_transaction(kcs_info->kcs_sm,
+				      kcs_info->curr_msg->data,
+				      kcs_info->curr_msg->data_size);
+		kcs_info->kcs_state = KCS_GETTING_EVENTS;
+	} else {
+		kcs_info->kcs_state = KCS_NORMAL;
+	}
+}
+
+static void handle_transaction_done(struct kcs_info *kcs_info)
+{
+	struct ipmi_smi_msg *msg;
+#ifdef DEBUG_TIMING
+	struct timeval t;
+
+	do_gettimeofday(&t);
+	printk("**Done: %d.%9.9d\n", t.tv_sec, t.tv_usec);
+#endif
+	switch (kcs_info->kcs_state) {
+	case KCS_NORMAL:
+		kcs_info->curr_msg->rsp_size
+			= kcs_get_result(kcs_info->kcs_sm,
+					 kcs_info->curr_msg->rsp,
+					 IPMI_MAX_MSG_LENGTH);
+		
+		/* Do this here becase deliver_recv_msg() releases the
+		   lock, and a new message can be put in during the
+		   time the lock is released. */
+		msg = kcs_info->curr_msg;
+		kcs_info->curr_msg = NULL;
+		deliver_recv_msg(kcs_info, msg);
+		break;
+		
+	case KCS_GETTING_FLAGS:
+	{
+		unsigned char msg[4];
+		unsigned int  len;
+
+		/* We got the flags from the KCS, now handle them. */
+		len = kcs_get_result(kcs_info->kcs_sm, msg, 4);
+		if (msg[2] != 0) {
+			/* Error fetching flags, just give up for
+			   now. */
+			kcs_info->kcs_state = KCS_NORMAL;
+		} else if (len < 3) {
+			/* Hmm, no flags.  That's technically illegal, but
+			   don't use uninitialized data. */
+			kcs_info->kcs_state = KCS_NORMAL;
+		} else {
+			kcs_info->msg_flags = msg[3];
+			handle_flags(kcs_info);
+		}
+		break;
+	}
+
+	case KCS_CLEARING_FLAGS:
+	case KCS_CLEARING_FLAGS_THEN_SET_IRQ:
+	{
+		unsigned char msg[3];
+
+		/* We cleared the flags. */
+		kcs_get_result(kcs_info->kcs_sm, msg, 3);
+		if (msg[2] != 0) {
+			/* Error clearing flags */
+			printk(KERN_WARNING
+			       "ipmi_kcs: Error clearing flags: %2.2x\n",
+			       msg[2]);
+		}
+		if (kcs_info->kcs_state == KCS_CLEARING_FLAGS_THEN_SET_IRQ)
+			start_enable_irq(kcs_info);
+		else
+			kcs_info->kcs_state = KCS_NORMAL;
+		break;
+	}
+
+	case KCS_GETTING_EVENTS:
+	{
+		kcs_info->curr_msg->rsp_size
+			= kcs_get_result(kcs_info->kcs_sm,
+					 kcs_info->curr_msg->rsp,
+					 IPMI_MAX_MSG_LENGTH);
+
+		/* Do this here becase deliver_recv_msg() releases the
+		   lock, and a new message can be put in during the
+		   time the lock is released. */
+		msg = kcs_info->curr_msg;
+		kcs_info->curr_msg = NULL;
+		if (msg->rsp[2] != 0) {
+			/* Error getting event, probably done. */
+			msg->done(msg);
+
+			/* Take off the event flag. */
+			kcs_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
+		} else {
+			deliver_recv_msg(kcs_info, msg);
+		}
+		handle_flags(kcs_info);
+		break;
+	}
+
+	case KCS_GETTING_MESSAGES:
+	{
+		kcs_info->curr_msg->rsp_size
+			= kcs_get_result(kcs_info->kcs_sm,
+					 kcs_info->curr_msg->rsp,
+					 IPMI_MAX_MSG_LENGTH);
+
+		/* Do this here becase deliver_recv_msg() releases the
+		   lock, and a new message can be put in during the
+		   time the lock is released. */
+		msg = kcs_info->curr_msg;
+		kcs_info->curr_msg = NULL;
+		if (msg->rsp[2] != 0) {
+			/* Error getting event, probably done. */
+			msg->done(msg);
+
+			/* Take off the msg flag. */
+			kcs_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
+		} else {
+			deliver_recv_msg(kcs_info, msg);
+		}
+		handle_flags(kcs_info);
+		break;
+	}
+
+	case KCS_ENABLE_INTERRUPTS1:
+	{
+		unsigned char msg[4];
+
+		/* We got the flags from the KCS, now handle them. */
+		kcs_get_result(kcs_info->kcs_sm, msg, 4);
+		if (msg[2] != 0) {
+			printk(KERN_WARNING
+			       "ipmi_kcs: Could not enable interrupts"
+			       ", failed get, using polled mode.\n");
+			kcs_info->kcs_state = KCS_NORMAL;
+		} else {
+			msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
+			msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD;
+			msg[2] = msg[3] | 1; /* enable msg queue int */
+			start_kcs_transaction(kcs_info->kcs_sm, msg,3);
+			kcs_info->kcs_state = KCS_ENABLE_INTERRUPTS2;
+		}
+		break;
+	}
+
+	case KCS_ENABLE_INTERRUPTS2:
+	{
+		unsigned char msg[4];
+
+		/* We got the flags from the KCS, now handle them. */
+		kcs_get_result(kcs_info->kcs_sm, msg, 4);
+		if (msg[2] != 0) {
+			printk(KERN_WARNING
+			       "ipmi_kcs: Could not enable interrupts"
+			       ", failed set, using polled mode.\n");
+		}
+		kcs_info->kcs_state = KCS_NORMAL;
+		break;
+	}
+	}
+}
+
+/* Called on timeouts and events.  Timeouts should pass the elapsed
+   time, interrupts should pass in zero. */
+static enum kcs_result kcs_event_handler(struct kcs_info *kcs_info, int time)
+{
+	enum kcs_result kcs_result;
+
+ restart:
+	/* There used to be a loop here that waited a little while
+	   (around 25us) before giving up.  That turned out to be
+	   pointless, the minimum delays I was seeing were in the 300us
+	   range, which is far too long to wait in an interrupt.  So
+	   we just run until the state machine tells us something
+	   happened or it needs a delay. */
+	kcs_result = kcs_event(kcs_info->kcs_sm, time);
+	time = 0;
+	while (kcs_result == KCS_CALL_WITHOUT_DELAY)
+	{
+		kcs_result = kcs_event(kcs_info->kcs_sm, 0);
+	}
+
+	if (kcs_result == KCS_TRANSACTION_COMPLETE)
+	{
+		handle_transaction_done(kcs_info);
+		kcs_result = kcs_event(kcs_info->kcs_sm, 0);
+	}
+	else if (kcs_result == KCS_SM_HOSED)
+	{
+		if (kcs_info->curr_msg != NULL) {
+			/* If we were handling a user message, format
+                           a response to send to the upper layer to
+                           tell it about the error. */
+			return_hosed_msg(kcs_info);
+		}
+		kcs_result = kcs_event(kcs_info->kcs_sm, 0);
+		kcs_info->kcs_state = KCS_NORMAL;
+	}
+
+	/* We prefer handling attn over new messages. */
+	if (kcs_result == KCS_ATTN)
+	{
+		unsigned char msg[2];
+
+		/* Got a attn, send down a get message flags to see
+                   what's causing it.  It would be better to handle
+                   this in the upper layer, but due to the way
+                   interrupts work with the KCS, that's not really
+                   possible. */
+		msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
+		msg[1] = IPMI_GET_MSG_FLAGS_CMD;
+
+		start_kcs_transaction(kcs_info->kcs_sm, msg, 2);
+		kcs_info->kcs_state = KCS_GETTING_FLAGS;
+		goto restart;
+	}
+
+	/* If we are currently idle, try to start the next message. */
+	if (kcs_result == KCS_SM_IDLE) {
+		kcs_result = start_next_msg(kcs_info);
+		if (kcs_result != KCS_SM_IDLE)
+			goto restart;
+        }
+
+	if ((kcs_result == KCS_SM_IDLE)
+	    && (atomic_read(&kcs_info->req_events)))
+	{
+		/* We are idle and the upper layer requested that I fetch
+		   events, so do so. */
+		unsigned char msg[2];
+
+		atomic_set(&kcs_info->req_events, 0);
+		msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
+		msg[1] = IPMI_GET_MSG_FLAGS_CMD;
+
+		start_kcs_transaction(kcs_info->kcs_sm, msg, 2);
+		kcs_info->kcs_state = KCS_GETTING_FLAGS;
+		goto restart;
+	}
+
+	return kcs_result;
+}
+
+static void sender(void                *send_info,
+		   struct ipmi_smi_msg *msg,
+		   int                 priority)
+{
+	struct kcs_info *kcs_info = (struct kcs_info *) send_info;
+	enum kcs_result result;
+	unsigned long   flags;
+#ifdef DEBUG_TIMING
+	struct timeval t;
+#endif
+
+	spin_lock_irqsave(&(kcs_info->msg_lock), flags);
+#ifdef DEBUG_TIMING
+	do_gettimeofday(&t);
+	printk("**Enqueue: %d.%9.9d\n", t.tv_sec, t.tv_usec);
+#endif
+
+	if (kcs_info->run_to_completion) {
+		/* If we are running to completion, then throw it in
+		   the list and run transactions until everything is
+		   clear.  Priority doesn't matter here. */
+		list_add_tail(&(msg->link), &(kcs_info->xmit_msgs));
+
+		/* We have to release the msg lock and claim the kcs
+		   lock in this case, because of race conditions. */
+		spin_unlock_irqrestore(&(kcs_info->msg_lock), flags);
+
+		spin_lock_irqsave(&(kcs_info->kcs_lock), flags);
+		result = kcs_event_handler(kcs_info, 0);
+		while (result != KCS_SM_IDLE) {
+			udelay(500);
+			result = kcs_event_handler(kcs_info, 500);
+		}
+		spin_unlock_irqrestore(&(kcs_info->kcs_lock), flags);
+		return;
+	} else {
+		if (priority > 0) {
+			list_add_tail(&(msg->link), &(kcs_info->hp_xmit_msgs));
+		} else {
+			list_add_tail(&(msg->link), &(kcs_info->xmit_msgs));
+		}
+	}
+	spin_unlock_irqrestore(&(kcs_info->msg_lock), flags);
+
+	spin_lock_irqsave(&(kcs_info->kcs_lock), flags);
+	if ((kcs_info->kcs_state == KCS_NORMAL)
+	    && (kcs_info->curr_msg == NULL))
+	{
+		start_next_msg(kcs_info);
+	}
+	spin_unlock_irqrestore(&(kcs_info->kcs_lock), flags);
+}
+
+static void set_run_to_completion(void *send_info, int i_run_to_completion)
+{
+	struct kcs_info *kcs_info = (struct kcs_info *) send_info;
+	enum kcs_result result;
+	unsigned long   flags;
+
+	spin_lock_irqsave(&(kcs_info->kcs_lock), flags);
+
+	kcs_info->run_to_completion = i_run_to_completion;
+	if (i_run_to_completion) {
+		result = kcs_event_handler(kcs_info, 0);
+		while (result != KCS_SM_IDLE) {
+			udelay(500);
+			result = kcs_event_handler(kcs_info, 500);
+		}
+	}
+
+	spin_unlock_irqrestore(&(kcs_info->kcs_lock), flags);
+}
+
+static void request_events(void *send_info)
+{
+	struct kcs_info *kcs_info = (struct kcs_info *) send_info;
+
+	atomic_set(&kcs_info->req_events, 1);
+}
+
+static int new_user(void *send_info)
+{
+	if (!try_inc_mod_count(THIS_MODULE))
+		return -EBUSY;
+	return 0;
+}
+
+static void user_left(void *send_info)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+/* Call every 10 ms. */
+#define KCS_TIMEOUT_TIME_USEC	10000
+#define KCS_USEC_PER_JIFFY	(1000000/HZ)
+#define KCS_TIMEOUT_JIFFIES	(KCS_TIMEOUT_TIME_USEC/KCS_USEC_PER_JIFFY)
+#define KCS_SHORT_TIMEOUT_USEC  500 /* .5ms when the SM request a
+                                       short timeout */
+static int initialized = 0;
+
+static void kcs_timeout(unsigned long data)
+{
+	struct kcs_info *kcs_info = (struct kcs_info *) data;
+	enum kcs_result kcs_result;
+	unsigned long   flags;
+	unsigned long   jiffies_now;
+	unsigned long   time_diff;
+#ifdef DEBUG_TIMING
+	struct timeval t;
+#endif
+
+	if (kcs_info->stop_operation) {
+		kcs_info->timer_stopped = 1;
+		return;
+	}
+
+	spin_lock_irqsave(&(kcs_info->kcs_lock), flags);
+#ifdef DEBUG_TIMING
+	do_gettimeofday(&t);
+	printk("**Timer: %d.%9.9d\n", t.tv_sec, t.tv_usec);
+#endif
+	jiffies_now = jiffies;
+	time_diff = ((jiffies_now - kcs_info->last_timeout_jiffies)
+		     * KCS_USEC_PER_JIFFY);
+	kcs_result = kcs_event_handler(kcs_info, time_diff);
+
+	spin_unlock_irqrestore(&(kcs_info->kcs_lock), flags);
+
+	kcs_info->last_timeout_jiffies = jiffies_now;
+
+	if ((kcs_info->irq) && (! kcs_info->interrupt_disabled)) {
+		/* Running with interrupts, only do long timeouts. */
+		kcs_info->kcs_timer.expires = jiffies + KCS_TIMEOUT_JIFFIES;
+		goto do_add_timer;
+	}
+
+	/* If the state machine asks for a short delay, then shorten
+           the timer timeout. */
+#ifdef CONFIG_HIGH_RES_TIMERS
+	if (kcs_result == KCS_CALL_WITH_DELAY) {
+		kcs_info->kcs_timer.sub_expires
+			+= usec_to_arch_cycles(KCS_SHORT_TIMEOUT_USEC);
+		while (kcs_info->kcs_timer.sub_expires >= cycles_per_jiffies) {
+			kcs_info->kcs_timer.expires++;
+			kcs_info->kcs_timer.sub_expires -= cycles_per_jiffies;
+		}
+	} else {
+		kcs_info->kcs_timer.expires = jiffies + KCS_TIMEOUT_JIFFIES;
+	}
+#else
+	/* If requested, take the shortest delay possible */
+	if (kcs_result == KCS_CALL_WITH_DELAY) {
+		kcs_info->kcs_timer.expires = jiffies + 1;
+	} else {
+		kcs_info->kcs_timer.expires = jiffies + KCS_TIMEOUT_JIFFIES;
+	}
+#endif
+
+ do_add_timer:
+	add_timer(&(kcs_info->kcs_timer));
+}
+
+static void kcs_irq_handler(int irq, void *data, struct pt_regs *regs)
+{
+	struct kcs_info *kcs_info = (struct kcs_info *) data;
+	unsigned long   flags;
+#ifdef DEBUG_TIMING
+	struct timeval t;
+#endif
+
+	spin_lock_irqsave(&(kcs_info->kcs_lock), flags);
+	if (kcs_info->stop_operation)
+		goto out;
+
+#ifdef DEBUG_TIMING
+	do_gettimeofday(&t);
+	printk("**Interrupt: %d.%9.9d\n", t.tv_sec, t.tv_usec);
+#endif
+	kcs_event_handler(kcs_info, 0);
+ out:
+	spin_unlock_irqrestore(&(kcs_info->kcs_lock), flags);
+}
+
+static struct ipmi_smi_handlers handlers =
+{
+	sender:		       sender,
+	request_events:        request_events,
+	new_user:	       new_user,
+	user_left:	       user_left,
+	set_run_to_completion: set_run_to_completion
+};
+
+static unsigned char ipmi_kcs_dev_rev;
+static unsigned char ipmi_kcs_fw_rev_major;
+static unsigned char ipmi_kcs_fw_rev_minor;
+static unsigned char ipmi_version_major;
+static unsigned char ipmi_version_minor;
+
+extern int kcs_dbg;
+static int ipmi_kcs_detect_hardware(unsigned int port,
+				    unsigned char *addr,
+				    struct kcs_data *data)
+{
+	unsigned char   msg[2];
+	unsigned char   resp[IPMI_MAX_MSG_LENGTH];
+	unsigned long   resp_len;
+	enum kcs_result kcs_result;
+
+	/* It's impossible for the KCS status register to be all 1's,
+	   (assuming a properly functioning, self-initialized BMC)
+	   but that's what you get from reading a bogus address, so we
+	   test that first. */
+
+	if (port) {
+		if (inb(port+1) == 0xff) return -ENODEV; 
+	} else { 
+		if (readb(addr+1) == 0xff) return -ENODEV; 
+	}
+
+	/* Do a Get Device ID command, since it comes back with some
+	   useful info. */
+	msg[0] = IPMI_NETFN_APP_REQUEST << 2;
+	msg[1] = IPMI_GET_DEVICE_ID_CMD;
+	start_kcs_transaction(data, msg, 2);
+	
+	kcs_result = kcs_event(data, 0);
+	for (;;)
+	{
+		if (kcs_result == KCS_CALL_WITH_DELAY) {
+			udelay(100);
+			kcs_result = kcs_event(data, 100);
+		}
+		else if (kcs_result == KCS_CALL_WITHOUT_DELAY)
+		{
+			kcs_result = kcs_event(data, 0);
+		}
+		else
+			break;
+	}
+	if (kcs_result == KCS_SM_HOSED) {
+		/* We couldn't get the state machine to run, so whatever's at
+		   the port is probably not an IPMI KCS interface. */
+		return -ENODEV;
+	}
+	/* Otherwise, we got some data. */
+	resp_len = kcs_get_result(data, resp, IPMI_MAX_MSG_LENGTH);
+	if (resp_len < 6)
+		/* That's odd, it should be longer. */
+		return -EINVAL;
+	
+	if ((resp[1] != IPMI_GET_DEVICE_ID_CMD) || (resp[2] != 0))
+		/* That's odd, it shouldn't be able to fail. */
+		return -EINVAL;
+	
+	ipmi_kcs_dev_rev = resp[4] & 0xf;
+	ipmi_kcs_fw_rev_major = resp[5] & 0x7f;
+	ipmi_kcs_fw_rev_minor = resp[6];
+	ipmi_version_major = resp[7] & 0xf;
+	ipmi_version_minor = resp[7] >> 4;
+
+	return 0;
+}
+
+/* There can be 4 IO ports passed in (with or without IRQs), 4 addresses,
+   a default IO port, and 1 ACPI/SPMI address.  That sets KCS_MAX_DRIVERS */
+
+#define KCS_MAX_PARMS 4
+#define KCS_MAX_DRIVERS ((KCS_MAX_PARMS * 2) + 2)
+static struct kcs_info *kcs_infos[KCS_MAX_DRIVERS] =
+{ NULL, NULL, NULL, NULL };
+
+#define DEVICE_NAME "ipmi_kcs"
+
+#define DEFAULT_IO_PORT 0xca2
+
+static int kcs_trydefaults = 1;
+static unsigned long kcs_addrs[KCS_MAX_PARMS] = { 0, 0, 0, 0 };
+static int kcs_ports[KCS_MAX_PARMS] = { 0, 0, 0, 0 };
+static int kcs_irqs[KCS_MAX_PARMS] = { 0, 0, 0, 0 };
+
+MODULE_PARM(kcs_trydefaults, "i");
+MODULE_PARM(kcs_addrs, "1-4l");
+MODULE_PARM(kcs_irqs, "1-4i");
+MODULE_PARM(kcs_ports, "1-4i");
+
+/* Returns 0 if initialized, or negative on an error. */
+static int init_one_kcs(int kcs_port, 
+			int irq, 
+			unsigned long kcs_physaddr,
+			struct kcs_info **kcs)
+{
+	int		rv;
+	struct kcs_info *new_kcs;
+
+	/* Did anything get passed in at all?  Both == zero disables the
+	   driver. */
+
+	if (!(kcs_port || kcs_physaddr)) 
+		return -ENODEV;
+	
+	/* Only initialize a port OR a physical address on this call.
+	   Also, IRQs can go with either ports or addresses. */
+
+	if (kcs_port && kcs_physaddr)
+		return -EINVAL;
+
+	new_kcs = kmalloc(kcs_size(), GFP_KERNEL);
+	if (!new_kcs) {
+		printk(KERN_ERR "ipmi_kcs: out of memory\n");
+		return -ENOMEM;
+	}
+
+	/* So we know not to free it unless we have allocated one. */
+	new_kcs->kcs_sm = NULL;
+
+	new_kcs->addr = NULL;
+	new_kcs->physaddr = kcs_physaddr;
+	new_kcs->port = kcs_port;
+
+	if (kcs_port) {
+		if (request_region(kcs_port, 2, DEVICE_NAME) == NULL) {
+			kfree(new_kcs);
+			printk(KERN_ERR 
+			       "ipmi_kcs: can't reserve port @ 0x%4.4x\n",
+		       	       kcs_port);
+			return -EIO;
+		}
+	} else {
+		if (request_mem_region(kcs_physaddr, 2, DEVICE_NAME) == NULL) {
+			kfree(new_kcs);
+			printk(KERN_ERR 
+			       "ipmi_kcs: can't reserve memory @ 0x%lx\n",
+		       	       kcs_physaddr);
+			return -EIO;
+		}
+		if ((new_kcs->addr = ioremap(kcs_physaddr, 2)) == NULL) {
+			kfree(new_kcs);
+			printk(KERN_ERR 
+			       "ipmi_kcs: can't remap memory at 0x%lx\n",
+		       	       kcs_physaddr);
+			return -EIO;
+		}
+	}
+
+	new_kcs->kcs_sm = kmalloc(kcs_size(), GFP_KERNEL);
+	if (!new_kcs->kcs_sm) {
+		printk(KERN_ERR "ipmi_kcs: out of memory\n");
+		rv = -ENOMEM;
+		goto out_err;
+	}
+	init_kcs_data(new_kcs->kcs_sm, kcs_port, new_kcs->addr);
+	spin_lock_init(&(new_kcs->kcs_lock));
+	spin_lock_init(&(new_kcs->msg_lock));
+
+	rv = ipmi_kcs_detect_hardware(kcs_port, new_kcs->addr, new_kcs->kcs_sm);
+	if (rv) {
+		if (kcs_port) 
+			printk(KERN_ERR 
+			       "ipmi_kcs: No KCS @ port 0x%4.4x\n", 
+			       kcs_port);
+		else
+			printk(KERN_ERR 
+			       "ipmi_kcs: No KCS @ addr 0x%lx\n", 
+			       kcs_physaddr);
+		goto out_err;
+	}
+
+	if (irq != 0) {
+		rv = request_irq(irq,
+				 kcs_irq_handler,
+				 SA_INTERRUPT,
+				 DEVICE_NAME,
+				 new_kcs);
+		if (rv) {
+			printk(KERN_WARNING
+			       "ipmi_kcs: %s unable to claim interrupt %d,"
+			       " running polled\n",
+			       DEVICE_NAME, irq);
+			irq = 0;
+		}
+	}
+	new_kcs->irq = irq;
+
+	INIT_LIST_HEAD(&(new_kcs->xmit_msgs));
+	INIT_LIST_HEAD(&(new_kcs->hp_xmit_msgs));
+	new_kcs->curr_msg = NULL;
+	atomic_set(&new_kcs->req_events, 0);
+	new_kcs->run_to_completion = 0;
+
+	start_clear_flags(new_kcs);
+
+	if (irq) {
+		new_kcs->kcs_state = KCS_CLEARING_FLAGS_THEN_SET_IRQ;
+
+		printk(KERN_INFO 
+		       "ipmi_kcs: Acquiring BMC @ port=0x%x irq=%d\n",
+		       kcs_port, irq);
+
+	} else {
+		if (kcs_port)
+			printk(KERN_INFO 
+			       "ipmi_kcs: Acquiring BMC @ port=0x%x\n",
+		       	       kcs_port);
+		else
+			printk(KERN_INFO 
+			       "ipmi_kcs: Acquiring BMC @ addr=0x%lx\n",
+		       	       kcs_physaddr);
+	}
+
+	rv = ipmi_register_smi(&handlers,
+			       new_kcs,
+			       ipmi_version_major,
+			       ipmi_version_minor,
+			       &(new_kcs->intf));
+	if (rv) {
+		free_irq(irq, new_kcs);
+		printk(KERN_ERR 
+		       "ipmi_kcs: Unable to register device: error %d\n",
+		       rv);
+		goto out_err;
+	}
+
+	new_kcs->interrupt_disabled = 0;
+	new_kcs->timer_stopped = 0;
+	new_kcs->stop_operation = 0;
+
+	init_timer(&(new_kcs->kcs_timer));
+	new_kcs->kcs_timer.data = (long) new_kcs;
+	new_kcs->kcs_timer.function = kcs_timeout;
+	new_kcs->last_timeout_jiffies = jiffies;
+	new_kcs->kcs_timer.expires = jiffies + KCS_TIMEOUT_JIFFIES;
+	add_timer(&(new_kcs->kcs_timer));
+
+	*kcs = new_kcs;
+
+	return 0;
+
+ out_err:
+	if (kcs_port) 
+		release_region (kcs_port, 2);
+	if (new_kcs->addr) 
+		iounmap(new_kcs->addr);
+	if (kcs_physaddr) 
+		release_mem_region(kcs_physaddr, 2);
+	if (new_kcs->kcs_sm)
+		kfree(new_kcs->kcs_sm);
+	kfree(new_kcs);
+	return rv;
+}
+
+#ifdef CONFIG_ACPI
+
+/* Retrieve the base physical address from ACPI tables.  Originally
+   from Hewlett-Packard simple bmc.c, a GPL KCS driver. */
+
+#include <linux/acpi.h>
+/* A real hack, but everything's not there yet in 2.4. */
+#define COMPILER_DEPENDENT_UINT64 unsigned long
+#include <../drivers/acpi/include/acpi.h>
+#include <../drivers/acpi/include/actypes.h>
+
+struct SPMITable {
+	s8	Signature[4];
+	u32	Length;
+	u8	Revision;
+	u8	Checksum;
+	s8	OEMID[6];
+	s8	OEMTableID[8];
+	s8	OEMRevision[4];
+	s8	CreatorID[4];
+	s8	CreatorRevision[4];
+	s16	InterfaceType;
+	s16	SpecificationRevision;
+	u8	InterruptType;
+	u8	GPE;
+	s16	Reserved;
+	u64	GlobalSystemInterrupt;
+	u8	BaseAddress[12];
+	u8	UID[4];
+} __attribute__ ((packed));
+
+static unsigned long acpi_find_bmc(void)
+{
+	acpi_status       status;
+	acpi_table_header *spmi;
+	static unsigned long io_base = 0;
+
+	if (io_base != 0)
+		return io_base;
+
+	status = acpi_get_firmware_table("SPMI", 1,
+			ACPI_LOGICAL_ADDRESSING, &spmi);
+
+	if (status != AE_OK) {
+		printk(KERN_ERR "ipmi_kcs: SPMI table not found.\n");
+		return 0;
+	}
+
+	memcpy(&io_base, ((struct SPMITable *)spmi)->BaseAddress,
+			sizeof(io_base));
+	
+	return io_base;
+}
+#endif
+
+static __init int init_ipmi_kcs(void)
+{
+	int		rv = 0;
+	int		pos = 0;
+	int		i = 0;
+#ifdef CONFIG_ACPI
+	unsigned long	physaddr = 0;
+#endif
+
+	if (initialized)
+		return 0;
+	initialized = 1;
+
+	/* First do the "command-line" parameters */
+
+	for (i=0; i < KCS_MAX_PARMS; i++) {
+		rv = init_one_kcs(kcs_ports[i], 
+				  kcs_irqs[i], 
+				  0, 
+				  &(kcs_infos[pos]));
+		if (rv == 0)
+			pos++;
+
+		rv = init_one_kcs(0, 
+				  kcs_irqs[i], 
+				  kcs_addrs[i], 
+				  &(kcs_infos[pos]));
+		if (rv == 0)
+			pos++;
+	}
+
+	/* Only try the defaults if enabled and resources are available
+	   (because they weren't already specified above). */
+
+	if (kcs_trydefaults) {
+#ifdef CONFIG_ACPI
+		if ((physaddr = acpi_find_bmc())) {
+			if (!check_mem_region(physaddr, 2)) {
+				rv = init_one_kcs(0, 
+						  0, 
+						  physaddr, 
+						  &(kcs_infos[pos]));
+				if (rv == 0)
+					pos++;
+			}
+		}
+#endif
+		if (!check_region(DEFAULT_IO_PORT, 2)) {
+			rv = init_one_kcs(DEFAULT_IO_PORT, 
+					  0, 
+					  0, 
+					  &(kcs_infos[pos]));
+			if (rv == 0)
+				pos++;
+		}
+	}
+
+	if (kcs_infos[0] == NULL) {
+		printk("ipmi_kcs: Unable to find any KCS interfaces\n");
+		return -ENODEV;
+	} 
+
+	return 0;
+}
+module_init(init_ipmi_kcs);
+
+#ifdef MODULE
+void __exit cleanup_one_kcs(struct kcs_info *to_clean)
+{
+	int           rv;
+	unsigned long flags;
+
+	if (! to_clean)
+		return;
+
+	/* Tell the timer and interrupt handlers that we are shutting
+	   down. */
+	spin_lock_irqsave(&(to_clean->kcs_lock), flags);
+	spin_lock(&(to_clean->msg_lock));
+
+	to_clean->stop_operation = 1;
+
+	if (to_clean->irq != 0)
+		free_irq(to_clean->irq, to_clean);
+	if (to_clean->port) {
+		printk(KERN_INFO 
+		       "ipmi_kcs: Releasing BMC @ port=0x%x\n",
+		       to_clean->port);
+		release_region (to_clean->port, 2);
+	}
+	if (to_clean->addr) {
+		printk(KERN_INFO 
+		       "ipmi_kcs: Releasing BMC @ addr=0x%lx\n",
+		       to_clean->physaddr);
+		iounmap(to_clean->addr);
+		release_mem_region(to_clean->physaddr, 2);
+	}
+
+	spin_unlock(&(to_clean->msg_lock));
+	spin_unlock_irqrestore(&(to_clean->kcs_lock), flags);
+
+	/* Wait for the timer to stop.  This avoids problems with race
+	   conditions removing the timer here.  Hopefully this will be
+	   long enough to avoid problems with interrupts still
+	   running. */
+	schedule_timeout(2);
+	while (!to_clean->timer_stopped) {
+		schedule_timeout(1);
+	}
+
+	rv = ipmi_unregister_smi(to_clean->intf);
+	if (rv) {
+		printk(KERN_ERR 
+		       "ipmi_kcs: Unable to unregister device: errno=%d\n",
+		       rv);
+	}
+
+	initialized = 0;
+
+	kfree(to_clean->kcs_sm);
+	kfree(to_clean);
+}
+
+static __exit void cleanup_ipmi_kcs(void)
+{
+	int i;
+
+	if (!initialized)
+		return;
+
+	for (i=0; i<KCS_MAX_DRIVERS; i++) {
+		cleanup_one_kcs(kcs_infos[i]);
+	}
+}
+module_exit(cleanup_ipmi_kcs);
+#else
+
+/* Unfortunately, cmdline::get_options() only returns integers, not
+   longs.  Since we need ulongs (64-bit physical addresses) parse the 
+   comma-separated list manually.  Arguments can be one of these forms:
+   m0xaabbccddeeff	A physical memory address without an IRQ
+   m0xaabbccddeeff:cc	A physical memory address with an IRQ
+   p0xaabb		An IO port without an IRQ
+   p0xaabb:cc		An IO port with an IRQ
+   nodefaults		Suppress trying the default IO port or ACPI address 
+
+   For example, to pass one IO port with an IRQ, one address, and 
+   suppress the use of the default IO port and ACPI address,
+   use this option string: ipmi_kcs=p0xCA2:5,m0xFF5B0022,nodefaults
+
+   Remember, ipmi_kcs_setup() is passed the string after the equal sign. */
+
+static int __init ipmi_kcs_setup(char *str)
+{
+	unsigned long val;
+	char *cur, *colon;
+	int pos;
+
+	pos = 0;
+	
+	cur = strsep(&str, ",");
+	while ((cur) && (*cur) && (pos < KCS_MAX_PARMS)) {
+		switch (*cur) {
+		case 'n':
+			if (strcmp(cur, "nodefaults") == 0)
+				kcs_trydefaults = 0;
+			else
+				printk(KERN_INFO 
+				       "ipmi_kcs: bad parameter value %s\n",
+				       cur);
+			break;
+		
+		case 'm':
+		case 'p':
+			val = simple_strtoul(cur + 1,
+					     &colon,
+					     0);
+			if (*cur == 'p')
+				kcs_ports[pos] = val;
+			else
+				kcs_addrs[pos] = val;
+			if (*colon == ':') {
+				val = simple_strtoul(colon + 1,
+						     &colon,
+						     0);
+				kcs_irqs[pos] = val;
+			}
+			pos++;
+			break;
+
+		default:
+			printk(KERN_INFO 
+			       "ipmi_kcs: bad parameter value %s\n",
+			       cur);
+		}
+		cur = strsep(&str, ",");
+	}
+
+	return 1;
+}
+__setup("ipmi_kcs=", ipmi_kcs_setup);
+#endif
+
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/ipmi/ipmi_kcs_sm.c linux-2.4.21-pre6/drivers/char/ipmi/ipmi_kcs_sm.c
--- linux-2.4.20/drivers/char/ipmi/ipmi_kcs_sm.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/ipmi/ipmi_kcs_sm.c	2003-03-26 23:48:57.000000000 +0000
@@ -0,0 +1,485 @@
+/*
+ * ipmi_kcs_sm.c
+ *
+ * State machine for handling IPMI KCS interfaces.
+ *
+ * Author: MontaVista Software, Inc.
+ *         Corey Minyard <minyard@mvista.com>
+ *         source@mvista.com
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; either version 2 of the License, or (at your
+ *  option) any later version.
+ *
+ *
+ *  THIS 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.
+ *
+ *  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 state machine is taken from the state machine in the IPMI spec,
+ * pretty much verbatim.  If you have questions about the states, see
+ * that document.
+ */
+
+#include <asm/io.h>
+#include <asm/string.h>		/* Gets rid of memcpy warning */
+
+#include "ipmi_kcs_sm.h"
+
+/* Set this if you want a printout of why the state machine was hosed
+   when it gets hosed. */
+#define DEBUG_HOSED_REASON
+
+/* Print the state machine state on entry every time. */
+#undef DEBUG_STATE
+
+/* The states the KCS driver may be in. */
+enum kcs_states {
+	KCS_IDLE,		/* The KCS interface is currently
+                                   doing nothing. */
+	KCS_START_OP,		/* We are starting an operation.  The
+				   data is in the output buffer, but
+				   nothing has been done to the
+				   interface yet.  This was added to
+				   the state machine in the spec to
+				   wait for the initial IBF. */
+	KCS_WAIT_WRITE_START,	/* We have written a write cmd to the
+				   interface. */
+	KCS_WAIT_WRITE,		/* We are writing bytes to the
+                                   interface. */
+	KCS_WAIT_WRITE_END,	/* We have written the write end cmd
+                                   to the interface, and still need to
+                                   write the last byte. */
+	KCS_WAIT_READ,		/* We are waiting to read data from
+				   the interface. */
+	KCS_ERROR0,		/* State to transition to the error
+				   handler, this was added to the
+				   state machine in the spec to be
+				   sure IBF was there. */
+	KCS_ERROR1,		/* First stage error handler, wait for
+                                   the interface to respond. */
+	KCS_ERROR2,		/* The abort cmd has been written,
+				   wait for the interface to
+				   respond. */
+	KCS_ERROR3,		/* We wrote some data to the
+				   interface, wait for it to switch to
+				   read mode. */
+	KCS_HOSED		/* The hardware failed to follow the
+				   state machine. */
+};
+
+#define MAX_KCS_READ_SIZE 80
+#define MAX_KCS_WRITE_SIZE 80
+
+/* Timeouts in microseconds. */
+#define IBF_RETRY_TIMEOUT 1000000
+#define OBF_RETRY_TIMEOUT 1000000
+#define MAX_ERROR_RETRIES 10
+
+#define IPMI_ERR_MSG_TRUNCATED	0xc6
+#define IPMI_ERR_UNSPECIFIED	0xff
+
+struct kcs_data
+{
+	enum kcs_states state;
+	unsigned int    port;
+	unsigned char	*addr;
+	unsigned char   write_data[MAX_KCS_WRITE_SIZE];
+	int             write_pos;
+	int             write_count;
+	int             orig_write_count;
+	unsigned char   read_data[MAX_KCS_READ_SIZE];
+	int             read_pos;
+	int	        truncated;
+
+	unsigned int  error_retries;
+	long          ibf_timeout;
+	long          obf_timeout;
+};
+
+void init_kcs_data(struct kcs_data *kcs, unsigned int port, unsigned char *addr)
+{
+	kcs->state = KCS_IDLE;
+	kcs->port = port;
+	kcs->addr = addr;
+	kcs->write_pos = 0;
+	kcs->write_count = 0;
+	kcs->orig_write_count = 0;
+	kcs->read_pos = 0;
+	kcs->error_retries = 0;
+	kcs->truncated = 0;
+	kcs->ibf_timeout = IBF_RETRY_TIMEOUT;
+	kcs->obf_timeout = OBF_RETRY_TIMEOUT;
+}
+
+/* Remember, init_one_kcs() insured port and addr can't both be set */
+
+static inline unsigned char read_status(struct kcs_data *kcs)
+{
+        if (kcs->port)
+		return inb(kcs->port + 1);
+        else
+		return readb(kcs->addr + 1);
+}
+
+static inline unsigned char read_data(struct kcs_data *kcs)
+{
+        if (kcs->port)
+		return inb(kcs->port + 0);
+        else
+		return readb(kcs->addr + 0);
+}
+
+static inline void write_cmd(struct kcs_data *kcs, unsigned char data)
+{
+        if (kcs->port)
+		outb(data, kcs->port + 1);
+        else
+		writeb(data, kcs->addr + 1);
+}
+
+static inline void write_data(struct kcs_data *kcs, unsigned char data)
+{
+        if (kcs->port)
+		outb(data, kcs->port + 0);
+        else
+		writeb(data, kcs->addr + 0);
+}
+
+/* Control codes. */
+#define KCS_GET_STATUS_ABORT	0x60
+#define KCS_WRITE_START		0x61
+#define KCS_WRITE_END		0x62
+#define KCS_READ_BYTE		0x68
+
+/* Status bits. */
+#define GET_STATUS_STATE(status) (((status) >> 6) & 0x03)
+#define KCS_IDLE_STATE	0
+#define KCS_READ_STATE	1
+#define KCS_WRITE_STATE	2
+#define KCS_ERROR_STATE	3
+#define GET_STATUS_ATN(status) ((status) & 0x04)
+#define GET_STATUS_IBF(status) ((status) & 0x02)
+#define GET_STATUS_OBF(status) ((status) & 0x01)
+
+
+static inline void write_next_byte(struct kcs_data *kcs)
+{
+	write_data(kcs, kcs->write_data[kcs->write_pos]);
+	(kcs->write_pos)++;
+	(kcs->write_count)--;
+}
+
+static inline void start_error_recovery(struct kcs_data *kcs, char *reason)
+{
+	(kcs->error_retries)++;
+	if (kcs->error_retries > MAX_ERROR_RETRIES) {
+#ifdef DEBUG_HOSED_REASON
+		printk("ipmi_kcs_sm: kcs hosed: %s\n", reason);
+#endif
+		kcs->state = KCS_HOSED;
+	} else {
+		kcs->state = KCS_ERROR0;
+	}
+}
+
+static inline void read_next_byte(struct kcs_data *kcs)
+{
+	if (kcs->read_pos >= MAX_KCS_READ_SIZE) {
+		/* Throw the data away and mark it truncated. */
+		read_data(kcs);
+		kcs->truncated = 1;
+	} else {
+		kcs->read_data[kcs->read_pos] = read_data(kcs);
+		(kcs->read_pos)++;
+	}
+	write_data(kcs, KCS_READ_BYTE);
+}
+
+static inline int check_ibf(struct kcs_data *kcs,
+			    unsigned char   status,
+			    long            time)
+{
+	if (GET_STATUS_IBF(status)) {
+		kcs->ibf_timeout -= time;
+		if (kcs->ibf_timeout < 0) {
+			start_error_recovery(kcs, "IBF not ready in time");
+			kcs->ibf_timeout = IBF_RETRY_TIMEOUT;
+			return 1;
+		}
+		return 0;
+	}
+	kcs->ibf_timeout = IBF_RETRY_TIMEOUT;
+	return 1;
+}
+
+static inline int check_obf(struct kcs_data *kcs,
+			    unsigned char   status,
+			    long            time)
+{
+	if (! GET_STATUS_OBF(status)) {
+		kcs->obf_timeout -= time;
+		if (kcs->obf_timeout < 0) {
+		    start_error_recovery(kcs, "OBF not ready in time");
+		    return 1;
+		}
+		return 0;
+	}
+	kcs->obf_timeout = OBF_RETRY_TIMEOUT;
+	return 1;
+}
+
+static void clear_obf(struct kcs_data *kcs, unsigned char status)
+{
+	if (GET_STATUS_OBF(status))
+		read_data(kcs);
+}
+
+static void restart_kcs_transaction(struct kcs_data *kcs)
+{
+	kcs->write_count = kcs->orig_write_count;
+	kcs->write_pos = 0;
+	kcs->read_pos = 0;
+	kcs->state = KCS_WAIT_WRITE_START;
+	kcs->ibf_timeout = IBF_RETRY_TIMEOUT;
+	kcs->obf_timeout = OBF_RETRY_TIMEOUT;
+	write_cmd(kcs, KCS_WRITE_START);
+}
+
+int start_kcs_transaction(struct kcs_data *kcs, char *data, unsigned int size)
+{
+	if ((size < 2) || (size > MAX_KCS_WRITE_SIZE)) {
+		return -1;
+	}
+
+	if ((kcs->state != KCS_IDLE) && (kcs->state != KCS_HOSED)) {
+		return -2;
+	}
+
+	kcs->error_retries = 0;
+	memcpy(kcs->write_data, data, size);
+	kcs->write_count = size;
+	kcs->orig_write_count = size;
+	kcs->write_pos = 0;
+	kcs->read_pos = 0;
+	kcs->state = KCS_START_OP;
+	kcs->ibf_timeout = IBF_RETRY_TIMEOUT;
+	kcs->obf_timeout = OBF_RETRY_TIMEOUT;
+	return 0;
+}
+
+int kcs_get_result(struct kcs_data *kcs, unsigned char *data, int length)
+{
+	if (length < kcs->read_pos) {
+		kcs->read_pos = length;
+		kcs->truncated = 1;
+	}
+
+	memcpy(data, kcs->read_data, kcs->read_pos);
+
+	if ((length >= 3) && (kcs->read_pos < 3)) {
+		/* Guarantee that we return at least 3 bytes, with an
+		   error in the third byte if it is too short. */
+		data[2] = IPMI_ERR_UNSPECIFIED;
+		kcs->read_pos = 3;
+	}
+	if (kcs->truncated) {
+		/* Report a truncated error.  We might overwrite
+		   another error, but that's too bad, the user needs
+		   to know it was truncated. */
+		data[2] = IPMI_ERR_MSG_TRUNCATED;
+		kcs->truncated = 0;
+	}
+
+	return kcs->read_pos;
+}
+
+/* This implements the state machine defined in the IPMI manual, see
+   that for details on how this works.  Divide that flowchart into
+   sections delimited by "Wait for IBF" and this will become clear. */
+enum kcs_result kcs_event(struct kcs_data *kcs, long time)
+{
+	unsigned char status;
+	unsigned char state;
+
+	status = read_status(kcs);
+
+#ifdef DEBUG_STATE
+	printk("  State = %d, %x\n", kcs->state, status);
+#endif
+	/* All states wait for ibf, so just do it here. */
+	if (!check_ibf(kcs, status, time))
+		return KCS_CALL_WITH_DELAY;
+
+	/* Just about everything looks at the KCS state, so grab that, too. */
+	state = GET_STATUS_STATE(status);
+
+	switch (kcs->state) {
+	case KCS_IDLE:
+		/* If there's and interrupt source, turn it off. */
+		clear_obf(kcs, status);
+
+		if (GET_STATUS_ATN(status))
+			return KCS_ATTN;
+		else
+			return KCS_SM_IDLE;
+
+	case KCS_START_OP:
+		if (state != KCS_IDLE) {
+			start_error_recovery(kcs,
+					     "State machine not idle at start");
+			break;
+		}
+
+		clear_obf(kcs, status);
+		write_cmd(kcs, KCS_WRITE_START);
+		kcs->state = KCS_WAIT_WRITE_START;
+		break;
+
+	case KCS_WAIT_WRITE_START:
+		if (state != KCS_WRITE_STATE) {
+			start_error_recovery(
+				kcs,
+				"Not in write state at write start");
+			break;
+		}
+		read_data(kcs);
+		if (kcs->write_count == 1) {
+			write_cmd(kcs, KCS_WRITE_END);
+			kcs->state = KCS_WAIT_WRITE_END;
+		} else {
+			write_next_byte(kcs);
+			kcs->state = KCS_WAIT_WRITE;
+		}
+		break;
+
+	case KCS_WAIT_WRITE:
+		if (state != KCS_WRITE_STATE) {
+			start_error_recovery(kcs,
+					     "Not in write state for write");
+			break;
+		}
+		clear_obf(kcs, status);
+		if (kcs->write_count == 1) {
+			write_cmd(kcs, KCS_WRITE_END);
+			kcs->state = KCS_WAIT_WRITE_END;
+		} else {
+			write_next_byte(kcs);
+		}
+		break;
+		
+	case KCS_WAIT_WRITE_END:
+		if (state != KCS_WRITE_STATE) {
+			start_error_recovery(kcs,
+					     "Not in write state for write end");
+			break;
+		}
+		clear_obf(kcs, status);
+		write_next_byte(kcs);
+		kcs->state = KCS_WAIT_READ;
+		break;
+
+	case KCS_WAIT_READ:
+		if ((state != KCS_READ_STATE) && (state != KCS_IDLE_STATE)) {
+			start_error_recovery(
+				kcs,
+				"Not in read or idle in read state");
+			break;
+		}
+
+		if (state == KCS_READ_STATE) {
+			if (! check_obf(kcs, status, time))
+				return KCS_CALL_WITH_DELAY;
+			read_next_byte(kcs);
+		} else {
+			/* We don't implement this exactly like the state
+			   machine in the spec.  Some broken hardware
+			   does not write the final dummy byte to the
+			   read register.  Thus obf will never go high
+			   here.  We just go straight to idle, and we
+			   handle clearing out obf in idle state if it
+			   happens to come in. */
+			clear_obf(kcs, status);
+			kcs->orig_write_count = 0;
+			kcs->state = KCS_IDLE;
+			return KCS_TRANSACTION_COMPLETE;
+		}
+		break;
+
+	case KCS_ERROR0:
+		clear_obf(kcs, status);
+		write_cmd(kcs, KCS_GET_STATUS_ABORT);
+		kcs->state = KCS_ERROR1;
+		break;
+
+	case KCS_ERROR1:
+		clear_obf(kcs, status);
+		write_data(kcs, 0);
+		kcs->state = KCS_ERROR2;
+		break;
+		
+	case KCS_ERROR2:
+		if (state != KCS_READ_STATE) {
+			start_error_recovery(kcs,
+					     "Not in read state for error2");
+			break;
+		}
+		if (! check_obf(kcs, status, time))
+			return KCS_CALL_WITH_DELAY;
+
+		clear_obf(kcs, status);
+		write_data(kcs, KCS_READ_BYTE);
+		kcs->state = KCS_ERROR3;
+		break;
+		
+	case KCS_ERROR3:
+		if (state != KCS_IDLE_STATE) {
+			start_error_recovery(kcs,
+					     "Not in idle state for error3");
+			break;
+		}
+
+		if (! check_obf(kcs, status, time))
+			return KCS_CALL_WITH_DELAY;
+
+		clear_obf(kcs, status);
+		if (kcs->orig_write_count) {
+			restart_kcs_transaction(kcs);
+		} else {
+			kcs->state = KCS_IDLE;
+			return KCS_TRANSACTION_COMPLETE;
+		}
+		break;
+			
+	case KCS_HOSED:
+		return KCS_SM_HOSED;
+	}
+
+	if (kcs->state == KCS_HOSED) {
+		init_kcs_data(kcs, kcs->port, kcs->addr);
+		return KCS_SM_HOSED;
+	}
+
+	return KCS_CALL_WITHOUT_DELAY;
+}
+
+int kcs_size(void)
+{
+	return sizeof(struct kcs_data);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/ipmi/ipmi_kcs_sm.h linux-2.4.21-pre6/drivers/char/ipmi/ipmi_kcs_sm.h
--- linux-2.4.20/drivers/char/ipmi/ipmi_kcs_sm.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/ipmi/ipmi_kcs_sm.h	2003-03-26 23:49:08.000000000 +0000
@@ -0,0 +1,70 @@
+/*
+ * ipmi_kcs_sm.h
+ *
+ * State machine for handling IPMI KCS interfaces.
+ *
+ * Author: MontaVista Software, Inc.
+ *         Corey Minyard <minyard@mvista.com>
+ *         source@mvista.com
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; either version 2 of the License, or (at your
+ *  option) any later version.
+ *
+ *
+ *  THIS 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.
+ *
+ *  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.
+ */
+
+struct kcs_data;
+
+void init_kcs_data(struct kcs_data *kcs,
+		   unsigned int    port,
+		   unsigned char   *addr);
+
+/* Start a new transaction in the state machine.  This will return -2
+   if the state machine is not idle, -1 if the size is invalid (to
+   large or too small), or 0 if the transaction is successfully
+   completed. */
+int start_kcs_transaction(struct kcs_data *kcs, char *data, unsigned int size);
+
+/* Return the results after the transaction.  This will return -1 if
+   the buffer is too small, zero if no transaction is present, or the
+   actual length of the result data. */
+int kcs_get_result(struct kcs_data *kcs, unsigned char *data, int length);
+
+enum kcs_result
+{
+	KCS_CALL_WITHOUT_DELAY, /* Call the driver again immediately */
+	KCS_CALL_WITH_DELAY,	/* Delay some before calling again. */
+	KCS_TRANSACTION_COMPLETE, /* A transaction is finished. */
+	KCS_SM_IDLE,		/* The SM is in idle state. */
+	KCS_SM_HOSED,		/* The hardware violated the state machine. */
+	KCS_ATTN		/* The hardware is asserting attn and the
+				   state machine is idle. */
+};
+
+/* Call this periodically (for a polled interface) or upon receiving
+   an interrupt (for a interrupt-driven interface).  If interrupt
+   driven, you should probably poll this periodically when not in idle
+   state.  This should be called with the time that passed since the
+   last call, if it is significant.  Time is in microseconds. */
+enum kcs_result kcs_event(struct kcs_data *kcs, long time);
+
+/* Return the size of the KCS structure in bytes. */
+int kcs_size(void);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/ipmi/ipmi_msghandler.c linux-2.4.21-pre6/drivers/char/ipmi/ipmi_msghandler.c
--- linux-2.4.20/drivers/char/ipmi/ipmi_msghandler.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/ipmi/ipmi_msghandler.c	2003-03-26 23:49:15.000000000 +0000
@@ -0,0 +1,1982 @@
+/*
+ * ipmi_msghandler.c
+ *
+ * Incoming and outgoing message routing for an IPMI interface.
+ *
+ * Author: MontaVista Software, Inc.
+ *         Corey Minyard <minyard@mvista.com>
+ *         source@mvista.com
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; either version 2 of the License, or (at your
+ *  option) any later version.
+ *
+ *
+ *  THIS 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.
+ *
+ *  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/errno.h>
+#include <asm/system.h>
+#include <linux/sched.h>
+#include <linux/poll.h>
+#include <linux/spinlock.h>
+#include <linux/rwsem.h>
+#include <linux/slab.h>
+#include <linux/ipmi.h>
+#include <linux/ipmi_smi.h>
+#include <linux/notifier.h>
+#include <linux/init.h>
+
+struct ipmi_recv_msg *ipmi_alloc_recv_msg(void);
+static int ipmi_init_msghandler(void);
+
+static int initialized = 0;
+
+#define MAX_EVENTS_IN_QUEUE	25
+
+/* Don't let a message sit in a queue forever, always time it with at lest
+   the max message timer. */
+#define MAX_MSG_TIMEOUT		60000
+
+struct ipmi_user
+{
+	struct list_head link;
+
+	/* The upper layer that handles receive messages. */
+	struct ipmi_user_hndl *handler;
+	void             *handler_data;
+
+	/* The interface this user is bound to. */
+	ipmi_smi_t intf;
+
+	/* Does this interface receive IPMI events? */
+	int gets_events;
+};
+
+struct cmd_rcvr
+{
+	struct list_head link;
+
+	ipmi_user_t   user;
+	unsigned char netfn;
+	unsigned char cmd;
+};
+
+struct seq_table
+{
+	int                  inuse : 1;
+
+	unsigned long        timeout;
+	unsigned long        orig_timeout;
+	unsigned int         retries_left;
+
+	/* To verify on an incoming send message response that this is
+           the message that the response is for, we keep a sequence id
+           and increment it every time we send a message. */
+	long                 seqid;
+
+	/* This is held so we can properly respond to the message on a
+           timeout, and it is used to hold the temporary data for
+           retransmission, too. */
+	struct ipmi_recv_msg *recv_msg;
+};
+
+/* Store the information in a msgid (long) to allow us to find a
+   sequence table entry from the msgid. */
+#define STORE_SEQ_IN_MSGID(seq, seqid) (((seq&0xff)<<26) | (seqid&0x3ffffff))
+
+#define GET_SEQ_FROM_MSGID(msgid, seq, seqid) \
+	do {								\
+		seq = ((msgid >> 26) & 0x3f);				\
+		seqid = (msgid & 0x3fffff);				\
+        } while(0)
+
+#define NEXT_SEQID(seqid) (((seqid) + 1) & 0x3fffff)
+
+
+#define IPMI_IPMB_NUM_SEQ	64
+struct ipmi_smi
+{
+	/* The list of upper layers that are using me.  We read-lock
+           this when delivering messages to the upper layer to keep
+           the user from going away while we are processing the
+           message.  This means that you cannot add or delete a user
+           from the receive callback. */
+	rwlock_t                users_lock;
+	struct list_head        users;
+
+	/* The IPMI version of the BMC on the other end. */
+	unsigned char       version_major;
+	unsigned char       version_minor;
+
+	/* This is the lower-layer's sender routine. */
+	struct ipmi_smi_handlers *handlers;
+	void                     *send_info;
+
+	/* A table of sequence numbers for this interface.  We use the
+           sequence numbers for IPMB messages that go out of the
+           interface to match them up with their responses.  A routine
+           is called periodically to time the items in this list. */
+	spinlock_t       seq_lock;
+	struct seq_table seq_table[IPMI_IPMB_NUM_SEQ];
+	int curr_seq;
+
+	/* Messages that were delayed for some reason (out of memory,
+           for instance), will go in here to be processed later in a
+           periodic timer interrupt. */
+	spinlock_t       waiting_msgs_lock;
+	struct list_head waiting_msgs;
+
+	/* The list of command receivers that are registered for commands
+	   on this interface. */
+	rwlock_t	 cmd_rcvr_lock;
+	struct list_head cmd_rcvrs;
+
+	/* Events that were queues because no one was there to receive
+           them. */
+	spinlock_t       events_lock; /* For dealing with event stuff. */
+	struct list_head waiting_events;
+	unsigned int     waiting_events_count; /* How many events in queue? */
+
+	/* This will be non-null if someone registers to receive all
+	   IPMI commands (this is for interface emulation).  There
+	   may not be any things in the cmd_rcvrs list above when
+	   this is registered. */
+	ipmi_user_t all_cmd_rcvr;
+
+	/* My slave address.  This is initialized to IPMI_BMC_SLAVE_ADDR,
+	   but may be changed by the user. */
+	unsigned char my_address;
+
+	/* My LUN.  This should generally stay the SMS LUN, but just in
+	   case... */
+	unsigned char my_lun;
+};
+
+int
+ipmi_register_all_cmd_rcvr(ipmi_user_t user)
+{
+	int flags;
+	int rv = -EBUSY;
+
+	write_lock_irqsave(&(user->intf->users_lock), flags);
+	write_lock(&(user->intf->cmd_rcvr_lock));
+	if ((user->intf->all_cmd_rcvr == NULL)
+	    && (list_empty(&(user->intf->cmd_rcvrs))))
+	{
+		user->intf->all_cmd_rcvr = user;
+		rv = 0;
+	}
+	write_unlock(&(user->intf->cmd_rcvr_lock));
+	write_unlock_irqrestore(&(user->intf->users_lock), flags);
+	return rv;
+}
+
+int
+ipmi_unregister_all_cmd_rcvr(ipmi_user_t user)
+{
+	int flags;
+	int rv = -EINVAL;
+
+	write_lock_irqsave(&(user->intf->users_lock), flags);
+	write_lock(&(user->intf->cmd_rcvr_lock));
+	if (user->intf->all_cmd_rcvr == user)
+	{
+		user->intf->all_cmd_rcvr = NULL;
+		rv = 0;
+	}
+	write_unlock(&(user->intf->cmd_rcvr_lock));
+	write_unlock_irqrestore(&(user->intf->users_lock), flags);
+	return rv;
+}
+
+
+#define MAX_IPMI_INTERFACES 4
+static ipmi_smi_t ipmi_interfaces[MAX_IPMI_INTERFACES];
+
+/* Used to keep interfaces from going away while operations are
+   operating on interfaces.  Grab read if you are not modifying the
+   interfaces, write if you are. */
+static DECLARE_RWSEM(interfaces_sem);
+
+/* Directly protects the ipmi_interfaces data structure.  This is
+   claimed in the timer interrupt. */
+static spinlock_t interfaces_lock = SPIN_LOCK_UNLOCKED;
+
+/* List of watchers that want to know when smi's are added and
+   deleted. */
+static struct list_head smi_watchers = LIST_HEAD_INIT(smi_watchers);
+static DECLARE_RWSEM(smi_watchers_sem);
+
+int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher)
+{
+	int i;
+
+	down_read(&interfaces_sem);
+	down_write(&smi_watchers_sem);
+	list_add(&(watcher->link), &smi_watchers);
+	for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+		if (ipmi_interfaces[i] != NULL) {
+			watcher->new_smi(i);
+		}
+	}
+	up_write(&smi_watchers_sem);
+	up_read(&interfaces_sem);
+	return 0;
+}
+
+int ipmi_smi_watcher_unregister(struct ipmi_smi_watcher *watcher)
+{
+	down_write(&smi_watchers_sem);
+	list_del(&(watcher->link));
+	up_write(&smi_watchers_sem);
+	return 0;
+}
+
+int
+ipmi_addr_equal(struct ipmi_addr *addr1, struct ipmi_addr *addr2)
+{
+	if (addr1->addr_type != addr2->addr_type)
+		return 0;
+
+	if (addr1->channel != addr2->channel)
+		return 0;
+
+	if (addr1->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
+		struct ipmi_system_interface_addr *smi_addr1
+		    = (struct ipmi_system_interface_addr *) addr1;
+		struct ipmi_system_interface_addr *smi_addr2
+		    = (struct ipmi_system_interface_addr *) addr2;
+		return (smi_addr1->lun == smi_addr2->lun);
+	}
+
+	if ((addr1->addr_type == IPMI_IPMB_ADDR_TYPE)
+	    || (addr1->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
+	{
+		struct ipmi_ipmb_addr *ipmb_addr1
+		    = (struct ipmi_ipmb_addr *) addr1;
+		struct ipmi_ipmb_addr *ipmb_addr2
+		    = (struct ipmi_ipmb_addr *) addr2;
+
+		return ((ipmb_addr1->slave_addr == ipmb_addr2->slave_addr)
+			&& (ipmb_addr1->lun == ipmb_addr2->lun));
+	}
+
+	return 1;
+}
+
+int ipmi_validate_addr(struct ipmi_addr *addr, int len)
+{
+	if (len < sizeof(struct ipmi_system_interface_addr)) {
+		return -EINVAL;
+	}
+
+	if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
+		if (addr->channel != IPMI_BMC_CHANNEL)
+			return -EINVAL;
+		return 0;
+	}
+
+	if ((addr->channel == IPMI_BMC_CHANNEL)
+	    || (addr->channel >= IPMI_NUM_CHANNELS)
+	    || (addr->channel < 0))
+		return -EINVAL;
+
+	if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE)
+	    || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
+	{
+		if (len < sizeof(struct ipmi_ipmb_addr)) {
+			return -EINVAL;
+		}
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+unsigned int ipmi_addr_length(int addr_type)
+{
+	if (addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
+		return sizeof(struct ipmi_system_interface_addr);
+
+	if ((addr_type == IPMI_IPMB_ADDR_TYPE)
+	    || (addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
+	{
+		return sizeof(struct ipmi_ipmb_addr);
+	}
+
+	return 0;
+}
+
+static void deliver_response(struct ipmi_recv_msg *msg)
+{
+    msg->user->handler->ipmi_recv_hndl(msg, msg->user->handler_data);
+}
+
+/* Find the next sequence number not being used and add the given
+   message with the given timeout to the sequence table.  This must be
+   called with the interface's seq_lock held. */
+static int intf_next_seq(ipmi_smi_t           intf,
+			 struct ipmi_recv_msg *recv_msg,
+			 unsigned long        timeout,
+			 int                  retries,
+			 unsigned char        *seq,
+			 long                 *seqid)
+{
+	int          rv = 0;
+	unsigned int i;
+
+	for (i=intf->curr_seq;
+	     (i+1)%IPMI_IPMB_NUM_SEQ != intf->curr_seq;
+	     i=(i+1)%IPMI_IPMB_NUM_SEQ)
+	{
+		if (! intf->seq_table[i].inuse)
+			break;
+	}
+
+	if (! intf->seq_table[i].inuse) {
+		intf->seq_table[i].recv_msg = recv_msg;
+
+		/* Start with the maximum timeout, when the send response
+		   comes in we will start the real timer. */
+		intf->seq_table[i].timeout = MAX_MSG_TIMEOUT;
+		intf->seq_table[i].orig_timeout = timeout;
+		intf->seq_table[i].retries_left = retries;
+		intf->seq_table[i].inuse = 1;
+		intf->seq_table[i].seqid = NEXT_SEQID(intf->seq_table[i].seqid);
+		*seq = i;
+		*seqid = intf->seq_table[i].seqid;
+		intf->curr_seq = (i+1)%IPMI_IPMB_NUM_SEQ;
+	} else {
+		rv = -EAGAIN;
+	}
+	
+	return rv;
+}
+
+/* Return the receive message for the given sequence number and
+   release the sequence number so it can be reused.  Some other data
+   is passed in to be sure the message matches up correctly (to help
+   guard against message coming in after their timeout and the
+   sequence number being reused). */
+static int intf_find_seq(ipmi_smi_t           intf,
+			 unsigned char        seq,
+			 short                channel,
+			 unsigned char        cmd,
+			 unsigned char        netfn,
+			 struct ipmi_addr     *addr,
+			 struct ipmi_recv_msg **recv_msg)
+{
+	int           rv = -ENODEV;
+	unsigned long flags;
+
+	if (seq >= IPMI_IPMB_NUM_SEQ)
+		return -EINVAL;
+
+	spin_lock_irqsave(&(intf->seq_lock), flags);
+	if (intf->seq_table[seq].inuse) {
+		struct ipmi_recv_msg *msg = intf->seq_table[seq].recv_msg;
+
+		if ((msg->addr.channel == channel)
+		    && (msg->msg.cmd == cmd)
+		    && (msg->msg.netfn == netfn)
+		    && (ipmi_addr_equal(addr, &(msg->addr))))
+		{
+			*recv_msg = msg;
+			intf->seq_table[seq].inuse = 0;
+			rv = 0;
+		}
+	}
+	spin_unlock_irqrestore(&(intf->seq_lock), flags);
+
+	return rv;
+}
+
+
+/* Start the timer for a specific sequence table entry. */
+static int intf_start_seq_timer(ipmi_smi_t           intf,
+				long                 msgid)
+{
+	int           rv = -ENODEV;
+	unsigned long flags;
+	unsigned char seq;
+	unsigned long seqid;
+
+
+	GET_SEQ_FROM_MSGID(msgid, seq, seqid);
+
+	spin_lock_irqsave(&(intf->seq_lock), flags);
+	/* We do this verification because the user can be deleted
+           while a message is outstanding. */
+	if ((intf->seq_table[seq].inuse)
+	    && (intf->seq_table[seq].seqid == seqid))
+	{
+		struct seq_table *ent = &(intf->seq_table[seq]);
+		ent->timeout = ent->orig_timeout;
+	}
+	spin_unlock_irqrestore(&(intf->seq_lock), flags);
+
+	return rv;
+}
+
+
+int ipmi_create_user(unsigned int          if_num,
+		     struct ipmi_user_hndl *handler,
+		     void                  *handler_data,
+		     ipmi_user_t           *user)
+{
+	unsigned long flags;
+	ipmi_user_t   new_user;
+	int           rv = 0;
+
+	/* There is no module usecount here, because it's not
+           required.  Since this can only be used by and called from
+           other modules, they will implicitly use this module, and
+           thus this can't be removed unless the other modules are
+           removed. */
+
+	if (handler == NULL)
+		return -EINVAL;
+
+	/* Make sure the driver is actually initialized, this handles
+	   problems with initialization order. */
+	if (!initialized) {
+		rv = ipmi_init_msghandler();
+		if (rv)
+			return rv;
+
+		/* The init code doesn't return an error if it was turned
+		   off, but it won't initialize.  Check that. */
+		if (!initialized)
+			return -ENODEV;
+	}
+
+	new_user = kmalloc(sizeof(*new_user), GFP_KERNEL);
+	if (! new_user)
+		return -ENOMEM;
+
+	down_read(&interfaces_sem);
+	if ((if_num > MAX_IPMI_INTERFACES) || ipmi_interfaces[if_num] == NULL)
+	{
+		rv = -EINVAL;
+		goto out_unlock;
+	}
+
+	new_user->handler = handler;
+	new_user->handler_data = handler_data;
+	new_user->intf = ipmi_interfaces[if_num];
+	new_user->gets_events = 0;
+
+	rv = new_user->intf->handlers->new_user(new_user->intf->send_info);
+	if (rv)
+		goto out_unlock;
+
+	write_lock_irqsave(&(new_user->intf->users_lock), flags);
+	list_add_tail(&(new_user->link), &(new_user->intf->users));
+	write_unlock_irqrestore(&(new_user->intf->users_lock), flags);
+
+ out_unlock:	
+	if (rv) {
+		kfree(new_user);
+	} else {
+		*user = new_user;
+	}
+
+	up_read(&interfaces_sem);
+	return rv;
+}
+
+static int ipmi_destroy_user_nolock(ipmi_user_t user)
+{
+	int              rv = -ENODEV;
+	ipmi_user_t      t_user;
+	struct list_head *entry, *entry2;
+	int              i;
+	unsigned long    flags;
+
+	/* Find the user and delete them from the list. */
+	list_for_each(entry, &(user->intf->users)) {
+		t_user = list_entry(entry, struct ipmi_user, link);
+		if (t_user == user) {
+			list_del(entry);
+			rv = 0;
+			break;
+		}
+	}
+
+	if (rv) {
+		goto out_unlock;
+	}
+
+	/* Remove the user from the interfaces sequence table. */
+	spin_lock_irqsave(&(user->intf->seq_lock), flags);
+	for (i=0; i<IPMI_IPMB_NUM_SEQ; i++) {
+		if (user->intf->seq_table[i].inuse
+		    && (user->intf->seq_table[i].recv_msg->user == user))
+		{
+			user->intf->seq_table[i].inuse = 0;
+		}
+	}
+	spin_unlock_irqrestore(&(user->intf->seq_lock), flags);
+
+	/* Remove the user from the command receiver's table. */
+	write_lock_irqsave(&(user->intf->cmd_rcvr_lock), flags);
+	list_for_each_safe(entry, entry2, &(user->intf->cmd_rcvrs)) {
+		struct cmd_rcvr *rcvr;
+		rcvr = list_entry(entry, struct cmd_rcvr, link);
+		if (rcvr->user == user) {
+			list_del(entry);
+			kfree(rcvr);
+		}
+	}
+	write_unlock_irqrestore(&(user->intf->cmd_rcvr_lock), flags);
+
+	kfree(user);
+
+ out_unlock:
+
+	return rv;
+}
+
+int ipmi_destroy_user(ipmi_user_t user)
+{
+	int           rv;
+	ipmi_smi_t    intf = user->intf;
+	unsigned long flags;
+
+	down_read(&interfaces_sem);
+	write_lock_irqsave(&(intf->users_lock), flags);
+	rv = ipmi_destroy_user_nolock(user);
+	if (!rv)
+		intf->handlers->user_left(intf->send_info);
+		
+	write_unlock_irqrestore(&(intf->users_lock), flags);
+	up_read(&interfaces_sem);
+	return rv;
+}
+
+void ipmi_get_version(ipmi_user_t   user,
+		      unsigned char *major,
+		      unsigned char *minor)
+{
+	*major = user->intf->version_major;
+	*minor = user->intf->version_minor;
+}
+
+void ipmi_set_my_address(ipmi_user_t   user,
+			 unsigned char address)
+{
+	user->intf->my_address = address;
+}
+
+unsigned char ipmi_get_my_address(ipmi_user_t user)
+{
+	return user->intf->my_address;
+}
+
+void ipmi_set_my_LUN(ipmi_user_t   user,
+		     unsigned char LUN)
+{
+	user->intf->my_lun = LUN & 0x3;
+}
+
+unsigned char ipmi_get_my_LUN(ipmi_user_t user)
+{
+	return user->intf->my_lun;
+}
+
+int ipmi_set_gets_events(ipmi_user_t user, int val)
+{
+	unsigned long         flags;
+	struct list_head      *e, *e2;
+	struct ipmi_recv_msg  *msg;
+
+	read_lock(&(user->intf->users_lock));
+	spin_lock_irqsave(&(user->intf->events_lock), flags);
+	user->gets_events = val;
+
+	if (val) {
+		/* Deliver any queued events. */
+		list_for_each_safe(e, e2, &(user->intf->waiting_events)) {
+			msg = list_entry(e, struct ipmi_recv_msg, link);
+			list_del(e);
+			msg->user = user;
+			deliver_response(msg);
+		}
+	}
+	
+	spin_unlock_irqrestore(&(user->intf->events_lock), flags);
+	read_unlock(&(user->intf->users_lock));
+
+	return 0;
+}
+
+int ipmi_register_for_cmd(ipmi_user_t   user,
+			  unsigned char netfn,
+			  unsigned char cmd)
+{
+	struct list_head *entry;
+	unsigned long    flags;
+	struct cmd_rcvr  *rcvr;
+	int              rv = 0;
+
+
+	rcvr = kmalloc(sizeof(*rcvr), GFP_KERNEL);
+	if (! rcvr)
+		return -ENOMEM;
+
+	read_lock(&(user->intf->users_lock));
+	write_lock_irqsave(&(user->intf->cmd_rcvr_lock), flags);
+	if (user->intf->all_cmd_rcvr != NULL) {
+		rv = -EBUSY;
+		goto out_unlock;
+	}
+
+	/* Make sure the command/netfn is not already registered. */
+	list_for_each(entry, &(user->intf->cmd_rcvrs)) {
+		struct cmd_rcvr *cmp;
+		cmp = list_entry(entry, struct cmd_rcvr, link);
+		if ((cmp->netfn == netfn) && (cmp->cmd == cmd)) {
+			rv = -EBUSY;
+			break;
+		}
+	}
+
+	if (! rv) {
+		rcvr->cmd = cmd;
+		rcvr->netfn = netfn;
+		rcvr->user = user;
+		list_add_tail(&(rcvr->link), &(user->intf->cmd_rcvrs));
+	}
+ out_unlock:
+	write_unlock_irqrestore(&(user->intf->cmd_rcvr_lock), flags);
+	read_unlock(&(user->intf->users_lock));
+
+	if (rv)
+		kfree(rcvr);
+
+	return rv;
+}
+
+int ipmi_unregister_for_cmd(ipmi_user_t   user,
+			    unsigned char netfn,
+			    unsigned char cmd)
+{
+	struct list_head *entry;
+	unsigned long    flags;
+	struct cmd_rcvr  *rcvr;
+	int              rv = -ENOENT;
+
+	read_lock(&(user->intf->users_lock));
+	write_lock_irqsave(&(user->intf->cmd_rcvr_lock), flags);
+	/* Make sure the command/netfn is not already registered. */
+	list_for_each(entry, &(user->intf->cmd_rcvrs)) {
+		rcvr = list_entry(entry, struct cmd_rcvr, link);
+		if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) {
+			rv = 0;
+			list_del(entry);
+			kfree(rcvr);
+			break;
+		}
+	}
+	write_unlock_irqrestore(&(user->intf->cmd_rcvr_lock), flags);
+	read_unlock(&(user->intf->users_lock));
+
+	return rv;
+}
+
+static unsigned char
+ipmb_checksum(unsigned char *data, int size)
+{
+	unsigned char csum = 0;
+	
+	for (; size > 0; size--, data++)
+		csum += *data;
+
+	return -csum;
+}
+
+static inline void format_ipmb_msg(struct ipmi_smi_msg   *smi_msg,
+				   struct ipmi_msg       *msg,
+				   struct ipmi_ipmb_addr *ipmb_addr,
+				   long                  msgid,
+				   unsigned char         ipmb_seq,
+				   int                   broadcast,
+				   unsigned char         source_address,
+				   unsigned char         source_lun)
+{
+	int i = broadcast;
+
+	/* Format the IPMB header data. */
+	smi_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
+	smi_msg->data[1] = IPMI_SEND_MSG_CMD;
+	smi_msg->data[2] = ipmb_addr->channel;
+	if (broadcast)
+		smi_msg->data[3] = 0;
+	smi_msg->data[i+3] = ipmb_addr->slave_addr;
+	smi_msg->data[i+4] = (msg->netfn << 2) | (ipmb_addr->lun & 0x3);
+	smi_msg->data[i+5] = ipmb_checksum(&(smi_msg->data[i+3]), 2);
+	smi_msg->data[i+6] = source_address;
+	smi_msg->data[i+7] = (ipmb_seq << 2) | source_lun;
+	smi_msg->data[i+8] = msg->cmd;
+
+	/* Now tack on the data to the message. */
+	if (msg->data_len > 0)
+		memcpy(&(smi_msg->data[i+9]), msg->data,
+		       msg->data_len);
+	smi_msg->data_size = msg->data_len + 9;
+
+	/* Now calculate the checksum and tack it on. */
+	smi_msg->data[i+smi_msg->data_size]
+		= ipmb_checksum(&(smi_msg->data[i+6]),
+				smi_msg->data_size-6);
+
+	/* Add on the checksum size and the offset from the
+	   broadcast. */
+	smi_msg->data_size += 1 + i;
+
+	smi_msg->msgid = msgid;
+}
+
+/* Separate from ipmi_request so that the user does not have to be
+   supplied in certain circumstances (mainly at panic time).  If
+   messages are supplied, they will be freed, even if an error
+   occurs. */
+static inline int i_ipmi_request(ipmi_user_t          user,
+				 ipmi_smi_t           intf,
+				 struct ipmi_addr     *addr,
+				 long                 msgid,
+				 struct ipmi_msg      *msg,
+				 void                 *supplied_smi,
+				 struct ipmi_recv_msg *supplied_recv,
+				 int                  priority,
+				 unsigned char        source_address,
+				 unsigned char        source_lun)
+{
+	int                  rv = 0;
+	struct ipmi_smi_msg  *smi_msg;
+	struct ipmi_recv_msg *recv_msg;
+	unsigned long        flags;
+
+
+	if (supplied_recv) {
+		recv_msg = supplied_recv;
+	} else {
+		recv_msg = ipmi_alloc_recv_msg();
+		if (recv_msg == NULL) {
+			return -ENOMEM;
+		}
+	}
+
+	if (supplied_smi) {
+		smi_msg = (struct ipmi_smi_msg *) supplied_smi;
+	} else {
+		smi_msg = ipmi_alloc_smi_msg();
+		if (smi_msg == NULL) {
+			ipmi_free_recv_msg(recv_msg);
+			return -ENOMEM;
+		}
+	}
+
+	if (addr->channel > IPMI_NUM_CHANNELS) {
+	    rv = -EINVAL;
+	    goto out_err;
+	}
+
+	recv_msg->user = user;
+	recv_msg->msgid = msgid;
+	/* Store the message to send in the receive message so timeout
+	   responses can get the proper response data. */
+	recv_msg->msg = *msg;
+
+	if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
+		struct ipmi_system_interface_addr *smi_addr;
+
+
+		smi_addr = (struct ipmi_system_interface_addr *) addr;
+		if (smi_addr->lun > 3)
+			return -EINVAL;
+
+		memcpy(&recv_msg->addr, smi_addr, sizeof(*smi_addr));
+
+		if ((msg->netfn == IPMI_NETFN_APP_REQUEST)
+		    && ((msg->cmd == IPMI_SEND_MSG_CMD)
+			|| (msg->cmd == IPMI_GET_MSG_CMD)
+			|| (msg->cmd == IPMI_READ_EVENT_MSG_BUFFER_CMD)))
+		{
+			/* We don't let the user do these, since we manage
+			   the sequence numbers. */
+			rv = -EINVAL;
+			goto out_err;
+		}
+
+		if ((msg->data_len + 2) > IPMI_MAX_MSG_LENGTH) {
+			rv = -EMSGSIZE;
+			goto out_err;
+		}
+
+		smi_msg->data[0] = (msg->netfn << 2) | (smi_addr->lun & 0x3);
+		smi_msg->data[1] = msg->cmd;
+		smi_msg->msgid = msgid;
+		smi_msg->user_data = recv_msg;
+		if (msg->data_len > 0)
+			memcpy(&(smi_msg->data[2]), msg->data, msg->data_len);
+		smi_msg->data_size = msg->data_len + 2;
+	} else if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE)
+		   || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
+	{
+		struct ipmi_ipmb_addr *ipmb_addr;
+		unsigned char         ipmb_seq;
+		long                  seqid;
+		int                   broadcast;
+		int                   retries;
+
+		if (addr == NULL) {
+			rv = -EINVAL;
+			goto out_err;
+		}
+
+		if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE) {
+		    /* Broadcasts add a zero at the beginning of the
+		       message, but otherwise is the same as an IPMB
+		       address. */
+		    addr->addr_type = IPMI_IPMB_ADDR_TYPE;
+		    broadcast = 1;
+		    retries = 0; /* Don't retry broadcasts. */
+		} else {
+		    broadcast = 0;
+		    retries = 4;
+		}
+
+		/* 9 for the header and 1 for the checksum, plus
+                   possibly one for the broadcast. */
+		if ((msg->data_len + 10 + broadcast) > IPMI_MAX_MSG_LENGTH) {
+			rv = -EMSGSIZE;
+			goto out_err;
+		}
+
+		ipmb_addr = (struct ipmi_ipmb_addr *) addr;
+		if (ipmb_addr->lun > 3) {
+			rv = -EINVAL;
+			goto out_err;
+		}
+
+		memcpy(&recv_msg->addr, ipmb_addr, sizeof(*ipmb_addr));
+
+		if (recv_msg->msg.netfn & 0x1) {
+			/* It's a response, so use the user's sequence
+                           from msgid. */
+			format_ipmb_msg(smi_msg, msg, ipmb_addr, msgid,
+					msgid, broadcast,
+					source_address, source_lun);
+		} else {
+			/* It's a command, so get a sequence for it. */
+
+			spin_lock_irqsave(&(intf->seq_lock), flags);
+
+			/* Create a sequence number with a 1 second
+                           timeout and 4 retries. */
+			/* FIXME - magic number for the timeout. */
+			rv = intf_next_seq(intf,
+					   recv_msg,
+					   1000,
+					   retries,
+					   &ipmb_seq,
+					   &seqid);
+			if (rv) {
+				/* We have used up all the sequence numbers,
+				   probably, so abort. */
+				spin_unlock_irqrestore(&(intf->seq_lock),
+						       flags);
+				goto out_err;
+			}
+
+			/* Store the sequence number in the message,
+                           so that when the send message response
+                           comes back we can start the timer. */
+			format_ipmb_msg(smi_msg, msg, ipmb_addr,
+					STORE_SEQ_IN_MSGID(ipmb_seq, seqid),
+					ipmb_seq, broadcast,
+					source_address, source_lun);
+
+			/* Copy the message into the recv message data, so we
+			   can retransmit it later if necessary. */
+			memcpy(recv_msg->msg_data, smi_msg->data,
+			       smi_msg->data_size);
+			recv_msg->msg.data = recv_msg->msg_data;
+			recv_msg->msg.data_len = smi_msg->data_size;
+
+			/* We don't unlock until here, because we need
+                           to copy the completed message into the
+                           recv_msg before we release the lock.
+                           Otherwise, race conditions may bite us.  I
+                           know that's pretty paranoid, but I prefer
+                           to be correct. */
+			spin_unlock_irqrestore(&(intf->seq_lock), flags);
+		}
+	} else {
+	    /* Unknown address type. */
+	    rv = -EINVAL;
+	    goto out_err;
+	}
+
+#if DEBUG_MSGING
+	{
+	    int m;
+	    for (m=0; m<smi_msg->data_size; m++)
+		printk(" %2.2x", smi_msg->data[m]);
+	    printk("\n");
+	}
+#endif
+	intf->handlers->sender(intf->send_info, smi_msg, priority);
+
+	return 0;
+
+ out_err:
+	ipmi_free_smi_msg(smi_msg);
+	ipmi_free_recv_msg(recv_msg);
+	return rv;
+}
+
+int ipmi_request(ipmi_user_t      user,
+		 struct ipmi_addr *addr,
+		 long             msgid,
+		 struct ipmi_msg  *msg,
+		 int              priority)
+{
+	return i_ipmi_request(user,
+			      user->intf,
+			      addr,
+			      msgid,
+			      msg,
+			      NULL, NULL,
+			      priority,
+			      user->intf->my_address,
+			      user->intf->my_lun);
+}
+
+int ipmi_request_supply_msgs(ipmi_user_t          user,
+			     struct ipmi_addr     *addr,
+			     long                 msgid,
+			     struct ipmi_msg      *msg,
+			     void                 *supplied_smi,
+			     struct ipmi_recv_msg *supplied_recv,
+			     int                  priority)
+{
+	return i_ipmi_request(user,
+			      user->intf,
+			      addr,
+			      msgid,
+			      msg,
+			      supplied_smi,
+			      supplied_recv,
+			      priority,
+			      user->intf->my_address,
+			      user->intf->my_lun);
+}
+
+int ipmi_request_with_source(ipmi_user_t      user,
+			     struct ipmi_addr *addr,
+			     long             msgid,
+			     struct ipmi_msg  *msg,
+			     int              priority,
+			     unsigned char    source_address,
+			     unsigned char    source_lun)
+{
+	return i_ipmi_request(user,
+			      user->intf,
+			      addr,
+			      msgid,
+			      msg,
+			      NULL, NULL,
+			      priority,
+			      source_address,
+			      source_lun);
+}
+
+int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
+		      void		       *send_info,
+		      unsigned char            version_major,
+		      unsigned char            version_minor,
+		      ipmi_smi_t               *intf)
+{
+	int              i, j;
+	int              rv;
+	ipmi_smi_t       new_intf;
+	struct list_head *entry;
+	unsigned int     flags;
+
+
+	/* Make sure the driver is actually initialized, this handles
+	   problems with initialization order. */
+	if (!initialized) {
+		rv = ipmi_init_msghandler();
+		if (rv)
+			return rv;
+		/* The init code doesn't return an error if it was turned
+		   off, but it won't initialize.  Check that. */
+		if (!initialized)
+			return -ENODEV;
+	}
+
+	new_intf = kmalloc(sizeof(*new_intf), GFP_KERNEL);
+	if (!new_intf)
+		return -ENOMEM;
+
+	rv = -ENOMEM;
+
+	down_write(&interfaces_sem);
+	for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+		if (ipmi_interfaces[i] == NULL) {
+			new_intf->version_major = version_major;
+			new_intf->version_minor = version_minor;
+			new_intf->my_address = IPMI_BMC_SLAVE_ADDR;
+			new_intf->my_lun = 2;  /* the SMS LUN. */
+			rwlock_init(&(new_intf->users_lock));
+			INIT_LIST_HEAD(&(new_intf->users));
+			new_intf->handlers = handlers;
+			new_intf->send_info = send_info;
+			spin_lock_init(&(new_intf->seq_lock));
+			for (j=0; j<IPMI_IPMB_NUM_SEQ; j++) {
+				new_intf->seq_table[j].inuse = 0;
+				new_intf->seq_table[j].seqid = 0;
+			}
+			new_intf->curr_seq = 0;
+			spin_lock_init(&(new_intf->waiting_msgs_lock));
+			INIT_LIST_HEAD(&(new_intf->waiting_msgs));
+			spin_lock_init(&(new_intf->events_lock));
+			INIT_LIST_HEAD(&(new_intf->waiting_events));
+			new_intf->waiting_events_count = 0;
+			rwlock_init(&(new_intf->cmd_rcvr_lock));
+			INIT_LIST_HEAD(&(new_intf->cmd_rcvrs));
+			new_intf->all_cmd_rcvr = NULL;
+
+			spin_lock_irqsave(&interfaces_lock, flags);
+			ipmi_interfaces[i] = new_intf;
+			spin_unlock_irqrestore(&interfaces_lock, flags);
+
+			rv = 0;
+			*intf = new_intf;
+			break;
+		}
+	}
+
+	/* We convert to a read semaphore here.  It's possible the
+	   interface was removed between the calls, we have to recheck
+	   afterwards. */
+	up_write(&interfaces_sem);
+	down_read(&interfaces_sem);
+
+	if (ipmi_interfaces[i] != new_intf)
+		/* Well, it went away.  Just return. */
+		goto out;
+
+	if (rv == 0) {
+		/* Call all the watcher interfaces to tell them that a
+		   new interface is available. */
+		down_read(&smi_watchers_sem);
+		list_for_each(entry, &smi_watchers) {
+			struct ipmi_smi_watcher *w;
+			w = list_entry(entry, struct ipmi_smi_watcher, link);
+			w->new_smi(i);
+		}
+		up_read(&smi_watchers_sem);
+	}
+
+ out:
+	up_read(&interfaces_sem);
+
+	if (rv)
+		kfree(new_intf);
+
+	return rv;
+}
+
+static void free_recv_msg_list(struct list_head *q)
+{
+	struct list_head     *entry, *entry2;
+	struct ipmi_recv_msg *msg;
+
+	list_for_each_safe(entry, entry2, q) {
+		msg = list_entry(entry, struct ipmi_recv_msg, link);
+		list_del(entry);
+		ipmi_free_recv_msg(msg);
+	}
+}
+
+static void free_cmd_rcvr_list(struct list_head *q)
+{
+	struct list_head *entry, *entry2;
+	struct cmd_rcvr  *rcvr;
+
+	list_for_each_safe(entry, entry2, q) {
+		rcvr = list_entry(entry, struct cmd_rcvr, link);
+		list_del(entry);
+		kfree(rcvr);
+	}
+}
+
+static void clean_up_interface_data(ipmi_smi_t intf)
+{
+	int i;
+
+	free_recv_msg_list(&(intf->waiting_msgs));
+	free_recv_msg_list(&(intf->waiting_events));
+	free_cmd_rcvr_list(&(intf->cmd_rcvrs));
+
+	for (i=0; i<IPMI_IPMB_NUM_SEQ; i++) {
+		if ((intf->seq_table[i].inuse)
+		    && (intf->seq_table[i].recv_msg))
+		{
+			ipmi_free_recv_msg(intf->seq_table[i].recv_msg);
+		}	
+	}
+}
+
+int ipmi_unregister_smi(ipmi_smi_t intf)
+{
+	int              rv = -ENODEV;
+	int              i;
+	struct list_head *entry;
+	unsigned int     flags;
+
+	down_write(&interfaces_sem);
+	if (list_empty(&(intf->users)))
+	{
+		for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+			if (ipmi_interfaces[i] == intf) {
+				spin_lock_irqsave(&interfaces_lock, flags);
+				ipmi_interfaces[i] = NULL;
+				clean_up_interface_data(intf);
+				spin_unlock_irqrestore(&interfaces_lock,flags);
+				kfree(intf);
+				rv = 0;
+				goto out_call_watcher;
+			}
+		}
+	} else {
+		rv = -EBUSY;
+	}
+	up_write(&interfaces_sem);
+
+	return rv;
+
+ out_call_watcher:
+	/* Convert to a read semaphore so callbacks don't bite us. */
+	up_write(&interfaces_sem);
+	down_read(&interfaces_sem);
+
+	/* Call all the watcher interfaces to tell them that
+	   an interface is gone. */
+	down_read(&smi_watchers_sem);
+	list_for_each(entry, &smi_watchers) {
+		struct ipmi_smi_watcher *w;
+		w = list_entry(entry,
+			       struct ipmi_smi_watcher,
+			       link);
+		w->smi_gone(i);
+	}
+	up_read(&smi_watchers_sem);
+	up_read(&interfaces_sem);
+	return 0;
+}
+
+static int handle_get_msg_rsp(ipmi_smi_t          intf,
+			      struct ipmi_smi_msg *msg)
+{
+	struct ipmi_ipmb_addr ipmb_addr;
+	struct ipmi_recv_msg  *recv_msg;
+
+	
+	if (msg->rsp_size < 11)
+		/* Message not big enough, just ignore it. */
+		return 0;
+
+	if (msg->rsp[2] != 0)
+		/* An error getting the response, just ignore it. */
+		return 0;
+
+	ipmb_addr.addr_type = IPMI_IPMB_ADDR_TYPE;
+	ipmb_addr.slave_addr = msg->rsp[6];
+	ipmb_addr.channel = msg->rsp[3] & 0x0f;
+	ipmb_addr.lun = msg->rsp[7] & 3;
+
+	/* It's a response from a remote entity.  Look up the sequence
+	   number and handle the response. */
+	if (intf_find_seq(intf,
+			  msg->rsp[7] >> 2,
+			  msg->rsp[3] & 0x0f,
+			  msg->rsp[8],
+			  (msg->rsp[4] >> 2) & (~1),
+			  (struct ipmi_addr *) &(ipmb_addr),
+			  &recv_msg))
+	{
+		/* We were unable to find the sequence number,
+		   so just nuke the message. */
+		return 0;
+	}
+
+	memcpy(recv_msg->msg_data,
+	       &(msg->rsp[9]),
+	       msg->rsp_size - 9);
+	/* THe other fields matched, so no need to set them, except
+           for netfn, which needs to be the response that was
+           returned, not the request value. */
+	recv_msg->msg.netfn = msg->rsp[4] >> 2;
+	recv_msg->msg.data = recv_msg->msg_data;
+	recv_msg->msg.data_len = msg->rsp_size - 10;
+	recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
+	deliver_response(recv_msg);
+
+	return 0;
+}
+
+static int handle_get_msg_cmd(ipmi_smi_t          intf,
+			      struct ipmi_smi_msg *msg)
+{
+	struct list_head *entry;
+	struct cmd_rcvr       *rcvr;
+	int              rv = 0;
+	unsigned char    netfn;
+	unsigned char    cmd;
+	ipmi_user_t      user = NULL;
+	struct ipmi_ipmb_addr *ipmb_addr;
+	struct ipmi_recv_msg  *recv_msg;
+
+	if (msg->rsp_size < 10)
+		/* Message not big enough, just ignore it. */
+		return 0;
+
+	if (msg->rsp[2] != 0) {
+		/* An error getting the response, just ignore it. */
+		return 0;
+	}
+
+	netfn = msg->rsp[4] >> 2;
+	cmd = msg->rsp[8];
+
+	read_lock(&(intf->cmd_rcvr_lock));
+	
+	if (intf->all_cmd_rcvr) {
+		user = intf->all_cmd_rcvr;
+	} else {
+		/* Find the command/netfn. */
+		list_for_each(entry, &(intf->cmd_rcvrs)) {
+			rcvr = list_entry(entry, struct cmd_rcvr, link);
+			if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) {
+				user = rcvr->user;
+				break;
+			}
+		}
+	}
+	read_unlock(&(intf->cmd_rcvr_lock));
+
+	if (user == NULL) {
+		/* We didn't find a user, deliver an error response. */
+		msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
+		msg->data[1] = IPMI_SEND_MSG_CMD;
+		msg->data[2] = msg->rsp[3];
+		msg->data[3] = msg->rsp[6];
+                msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3);
+		msg->data[5] = ipmb_checksum(&(msg->data[3]), 2);
+		msg->data[6] = intf->my_address;
+                /* rqseq/lun */
+                msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3);
+		msg->data[8] = msg->rsp[8]; /* cmd */
+		msg->data[9] = IPMI_INVALID_CMD_COMPLETION_CODE;
+		msg->data[10] = ipmb_checksum(&(msg->data[6]), 4);
+		msg->data_size = 11;
+
+		intf->handlers->sender(intf->send_info, msg, 0);
+
+		rv = -1; /* We used the message, so return the value that
+			    causes it to not be freed or queued. */
+	} else {
+		/* Deliver the message to the user. */
+		recv_msg = ipmi_alloc_recv_msg();
+		if (! recv_msg) {
+			/* We couldn't allocate memory for the
+                           message, so requeue it for handling
+                           later. */
+			rv = 1;
+		} else {
+			ipmb_addr = (struct ipmi_ipmb_addr *) &recv_msg->addr;
+			ipmb_addr->addr_type = IPMI_IPMB_ADDR_TYPE;
+			ipmb_addr->slave_addr = msg->rsp[6];
+			ipmb_addr->lun = msg->rsp[7] & 3;
+			ipmb_addr->channel = msg->rsp[3];
+
+			recv_msg->user = user;
+			recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
+			recv_msg->msgid = msg->rsp[7] >> 2;
+			recv_msg->msg.netfn = msg->rsp[4] >> 2;
+			recv_msg->msg.cmd = msg->rsp[8];
+			recv_msg->msg.data = recv_msg->msg_data;
+			recv_msg->msg.data_len = msg->rsp_size - 10;
+			memcpy(recv_msg->msg_data,
+			       &(msg->rsp[9]),
+			       msg->rsp_size - 10);
+			deliver_response(recv_msg);
+		}
+	}
+
+	return rv;
+}
+
+static void copy_event_into_recv_msg(struct ipmi_recv_msg *recv_msg,
+				     struct ipmi_smi_msg  *msg)
+{
+	struct ipmi_system_interface_addr *smi_addr;
+	
+	recv_msg->msgid = 0;
+	smi_addr = (struct ipmi_system_interface_addr *) &(recv_msg->addr);
+	smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+	smi_addr->channel = IPMI_BMC_CHANNEL;
+	smi_addr->lun = msg->rsp[0] & 3;
+	recv_msg->recv_type = IPMI_ASYNC_EVENT_RECV_TYPE;
+	recv_msg->msg.netfn = msg->rsp[0] >> 2;
+	recv_msg->msg.cmd = msg->rsp[1];
+	memcpy(recv_msg->msg_data, &(msg->rsp[3]), msg->rsp_size - 3);
+	recv_msg->msg.data = recv_msg->msg_data;
+	recv_msg->msg.data_len = msg->rsp_size - 3;
+}
+
+/* This will be called with the intf->users_lock read-locked, so no need
+   to do that here. */
+static int handle_read_event_rsp(ipmi_smi_t          intf,
+				 struct ipmi_smi_msg *msg)
+{
+	struct ipmi_recv_msg *recv_msg;
+	struct list_head     msgs;
+	struct list_head     *entry, *entry2;
+	ipmi_user_t          user;
+	int                  rv = 0;
+	int                  deliver_count = 0;
+	unsigned long        flags;
+
+	if (msg->rsp_size < 19) {
+		/* Message is too small to be an IPMB event. */
+		return 0;
+	}
+
+	if (msg->rsp[2] != 0) {
+		/* An error getting the event, just ignore it. */
+		return 0;
+	}
+
+	INIT_LIST_HEAD(&msgs);
+
+	spin_lock_irqsave(&(intf->events_lock), flags);
+
+	/* Allocate and fill in one message for every user that is getting
+	   events. */
+	list_for_each(entry, &(intf->users)) {
+		user = list_entry(entry, struct ipmi_user, link);
+
+		if (! user->gets_events)
+			continue;
+
+		recv_msg = ipmi_alloc_recv_msg();
+		if (! recv_msg) {
+			list_for_each_safe(entry, entry2, &msgs) {
+				recv_msg = list_entry(entry,
+						      struct ipmi_recv_msg,
+						      link);
+				list_del(entry);
+				ipmi_free_recv_msg(recv_msg);
+			}
+			/* We couldn't allocate memory for the
+                           message, so requeue it for handling
+                           later. */
+			rv = 1;
+			goto out;
+		}
+
+		deliver_count++;
+
+		copy_event_into_recv_msg(recv_msg, msg);
+		recv_msg->user = user;
+		list_add_tail(&(recv_msg->link), &msgs);
+	}
+
+	if (deliver_count) {
+		/* Now deliver all the messages. */
+		list_for_each_safe(entry, entry2, &msgs) {
+			recv_msg = list_entry(entry,
+					      struct ipmi_recv_msg,
+					      link);
+			list_del(entry);
+			deliver_response(recv_msg);
+		}
+	} else if (intf->waiting_events_count < MAX_EVENTS_IN_QUEUE) {
+		/* No one to receive the message, put it in queue if there's
+		   not already too many things in the queue. */
+		recv_msg = ipmi_alloc_recv_msg();
+		if (! recv_msg) {
+			/* We couldn't allocate memory for the
+                           message, so requeue it for handling
+                           later. */
+			rv = 1;
+			goto out;
+		}
+
+		copy_event_into_recv_msg(recv_msg, msg);
+		list_add_tail(&(recv_msg->link), &(intf->waiting_events));
+	} else {
+		/* There's too many things in the queue, discard this
+		   message. */
+		printk(KERN_WARNING "ipmi: Event queue full, discarding an"
+		       " incoming event\n");
+	}
+
+ out:
+	spin_unlock_irqrestore(&(intf->events_lock), flags);
+
+	return rv;
+}
+
+static int handle_bmc_rsp(ipmi_smi_t          intf,
+			  struct ipmi_smi_msg *msg)
+{
+	struct ipmi_recv_msg *recv_msg;
+	int                  found = 0;
+	struct list_head     *entry;
+
+	recv_msg = (struct ipmi_recv_msg *) msg->user_data;
+
+	/* Make sure the user still exists. */
+	list_for_each(entry, &(intf->users)) {
+		if (list_entry(entry, struct ipmi_user, link)
+		    == recv_msg->user)
+		{
+			/* Found it, so we can deliver it */
+			found = 1;
+			break;
+		}
+	}
+
+	if (!found) {
+		/* The user for the message went away, so give up. */
+		ipmi_free_recv_msg(recv_msg);
+	} else {
+		struct ipmi_system_interface_addr *smi_addr;
+
+		recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
+		recv_msg->msgid = msg->msgid;
+		smi_addr = ((struct ipmi_system_interface_addr *)
+			    &(recv_msg->addr));
+		smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+		smi_addr->channel = IPMI_BMC_CHANNEL;
+		smi_addr->lun = msg->rsp[0] & 3;
+		recv_msg->msg.netfn = msg->rsp[0] >> 2;
+		recv_msg->msg.cmd = msg->rsp[1];
+		memcpy(recv_msg->msg_data,
+		       &(msg->rsp[2]),
+		       msg->rsp_size - 2);
+		recv_msg->msg.data = recv_msg->msg_data;
+		recv_msg->msg.data_len = msg->rsp_size - 2;
+		deliver_response(recv_msg);
+	}
+
+	return 0;
+}
+
+/* Handle a new message.  Return 1 if the message should be requeued,
+   0 if the message should be freed, or -1 if the message should not
+   be freed or requeued. */
+static int handle_new_recv_msg(ipmi_smi_t          intf,
+			       struct ipmi_smi_msg *msg)
+{
+	int requeue;
+
+	if (msg->rsp_size < 2) {
+		/* Message is too small to be correct. */
+		requeue = 0;
+	} else if (msg->rsp[1] == IPMI_GET_MSG_CMD) {
+#if DEBUG_MSGING
+		int m;
+		printk("Response:");
+		for (m=0; m<msg->rsp_size; m++)
+			printk(" %2.2x", msg->rsp[m]);
+		printk("\n");
+#endif
+		/* It's from the receive queue. */
+		if (msg->rsp[4] & 0x04) {
+			/* It's a response, so find the
+			   requesting message and send it up. */
+			requeue = handle_get_msg_rsp(intf, msg);
+		} else {
+			/* It's a command to the SMS from some other
+			   entity.  Handle that. */
+			requeue = handle_get_msg_cmd(intf, msg);
+		}
+	} else if (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD) {
+		/* It's an asyncronous event. */
+		requeue = handle_read_event_rsp(intf, msg);
+	} else {
+		/* It's a response from the local BMC. */
+		requeue = handle_bmc_rsp(intf, msg);
+	}
+
+	return requeue;
+}
+
+/* Handle a new message from the lower layer. */
+void ipmi_smi_msg_received(ipmi_smi_t          intf,
+			   struct ipmi_smi_msg *msg)
+{
+	unsigned long flags;
+	int           rv;
+
+
+	/* Lock the user lock so the user can't go away while we are
+	   working on it. */
+	read_lock(&(intf->users_lock));
+
+	if ((msg->data_size >= 2) && (msg->data[1] == IPMI_SEND_MSG_CMD)) {
+		/* This is the local response to a send, start the
+                   timer for these. */
+		intf_start_seq_timer(intf, msg->msgid);
+		ipmi_free_smi_msg(msg);
+		goto out_unlock;
+	}
+
+	/* To preserve message order, if the list is not empty, we
+           tack this message onto the end of the list. */
+	spin_lock_irqsave(&(intf->waiting_msgs_lock), flags);
+	if (!list_empty(&(intf->waiting_msgs))) {
+		list_add_tail(&(msg->link), &(intf->waiting_msgs));
+		spin_unlock(&(intf->waiting_msgs_lock));
+		goto out_unlock;
+	}
+	spin_unlock_irqrestore(&(intf->waiting_msgs_lock), flags);
+		
+	rv = handle_new_recv_msg(intf, msg);
+	if (rv > 0) {
+		/* Could not handle the message now, just add it to a
+                   list to handle later. */
+		spin_lock(&(intf->waiting_msgs_lock));
+		list_add_tail(&(msg->link), &(intf->waiting_msgs));
+		spin_unlock(&(intf->waiting_msgs_lock));
+	} else if (rv == 0) {
+		ipmi_free_smi_msg(msg);
+	}
+
+ out_unlock:
+	read_unlock(&(intf->users_lock));
+}
+
+void ipmi_smi_watchdog_pretimeout(ipmi_smi_t intf)
+{
+	struct list_head *entry;
+	ipmi_user_t      user;
+
+	read_lock(&(intf->users_lock));
+	list_for_each(entry, &(intf->users)) {
+		user = list_entry(entry, struct ipmi_user, link);
+
+		if (! user->handler->ipmi_watchdog_pretimeout)
+			continue;
+
+		user->handler->ipmi_watchdog_pretimeout(user->handler_data);
+	}
+	read_unlock(&(intf->users_lock));
+}
+
+static void
+handle_msg_timeout(struct ipmi_recv_msg *msg)
+{
+	msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
+	msg->msg_data[0] = IPMI_TIMEOUT_COMPLETION_CODE;
+	msg->msg.netfn |= 1; /* Convert to a response. */
+	msg->msg.data_len = 1;
+	msg->msg.data = msg->msg_data;
+	deliver_response(msg);
+}
+
+static void
+send_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg,
+		   struct ipmi_smi_msg *smi_msg,
+		   unsigned char seq, long seqid)
+{
+	if (!smi_msg)
+		smi_msg = ipmi_alloc_smi_msg();
+	if (!smi_msg)
+		/* If we can't allocate the message, then just return, we
+		   get 4 retries, so this should be ok. */
+		return;
+
+	memcpy(smi_msg->data, recv_msg->msg.data, recv_msg->msg.data_len);
+	smi_msg->data_size = recv_msg->msg.data_len;
+	smi_msg->msgid = STORE_SEQ_IN_MSGID(seq, seqid);
+		
+	/* Send the new message.  We send with a zero priority.  It
+	   timed out, I doubt time is that critical now, and high
+	   priority messages are really only for messages to the local
+	   MC, which don't get resent. */
+	intf->handlers->sender(intf->send_info, smi_msg, 0);
+
+#if DEBUG_MSGING
+	{
+		int m;
+		printk("Resend: ");
+		for (m=0; m<smi_msg->data_size; m++)
+			printk(" %2.2x", smi_msg->data[m]);
+		printk("\n");
+	}
+#endif
+}
+
+static void
+ipmi_timeout_handler(long timeout_period)
+{
+	ipmi_smi_t           intf;
+	struct list_head     timeouts;
+	struct ipmi_recv_msg *msg;
+	struct ipmi_smi_msg  *smi_msg;
+	unsigned long        flags;
+	struct list_head     *entry, *entry2;
+	int                  i, j;
+
+	INIT_LIST_HEAD(&timeouts);
+
+	spin_lock(&interfaces_lock);
+	for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+		intf = ipmi_interfaces[i];
+		if (intf == NULL)
+			continue;
+
+		read_lock(&(intf->users_lock));
+
+		/* See if any waiting messages need to be processed. */
+		spin_lock_irqsave(&(intf->waiting_msgs_lock), flags);
+		list_for_each_safe(entry, entry2, &(intf->waiting_msgs)) {
+			smi_msg = list_entry(entry, struct ipmi_smi_msg, link);
+			if (! handle_new_recv_msg(intf, smi_msg)) {
+				list_del(entry);
+				ipmi_free_smi_msg(smi_msg);
+			} else {
+				/* To preserve message order, quit if we
+				   can't handle a message. */
+				break;
+			}
+		}
+		spin_unlock_irqrestore(&(intf->waiting_msgs_lock), flags);
+
+		/* Go through the seq table and find any messages that
+		   have timed out, putting them in the timeouts
+		   list. */
+		spin_lock_irqsave(&(intf->seq_lock), flags);
+		for (j=0; j<IPMI_IPMB_NUM_SEQ; j++) {
+			struct seq_table *ent = &(intf->seq_table[j]);
+			if (!ent->inuse)
+				continue;
+
+			ent->timeout -= timeout_period;
+			if (ent->timeout > 0)
+				continue;
+
+			if (ent->retries_left == 0) {
+				/* The message has used all its retries. */
+				ent->inuse = 0;
+				msg = ent->recv_msg;
+				list_add_tail(&(msg->link), &timeouts);
+			} else {
+				/* More retries, send again. */
+
+				/* Start with the max timer, set to normal
+				   timer after the message is sent. */
+				ent->timeout = MAX_MSG_TIMEOUT;
+				ent->retries_left--;
+				send_from_recv_msg(intf, ent->recv_msg, NULL,
+						   j, ent->seqid);
+			}
+		}
+		spin_unlock_irqrestore(&(intf->seq_lock), flags);
+
+		list_for_each_safe(entry, entry2, &timeouts) {
+			msg = list_entry(entry, struct ipmi_recv_msg, link);
+			handle_msg_timeout(msg);
+		}
+
+		read_unlock(&(intf->users_lock));
+	}
+	spin_unlock(&interfaces_lock);
+}
+
+static void ipmi_request_event(void)
+{
+	ipmi_smi_t intf;
+	int        i;
+
+	spin_lock(&interfaces_lock);
+	for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+		intf = ipmi_interfaces[i];
+		if (intf == NULL)
+			continue;
+
+		intf->handlers->request_events(intf->send_info);
+	}
+	spin_unlock(&interfaces_lock);
+}
+
+static struct timer_list ipmi_timer;
+
+/* Call every 100 ms. */
+#define IPMI_TIMEOUT_TIME	100
+#define IPMI_TIMEOUT_JIFFIES	(IPMI_TIMEOUT_TIME/(1000/HZ))
+
+/* Request events from the queue every second.  Hopefully, in the
+   future, IPMI will add a way to know immediately if an event is
+   in the queue. */
+#define IPMI_REQUEST_EV_TIME	(1000 / (IPMI_TIMEOUT_TIME))
+
+static volatile int stop_operation = 0;
+static volatile int timer_stopped = 0;
+static unsigned int ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
+
+static void ipmi_timeout(unsigned long data)
+{
+	if (stop_operation) {
+		timer_stopped = 1;
+		return;
+	}
+
+	ticks_to_req_ev--;
+	if (ticks_to_req_ev == 0) {
+		ipmi_request_event();
+		ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
+	}
+
+	ipmi_timeout_handler(IPMI_TIMEOUT_TIME);
+
+	ipmi_timer.expires += IPMI_TIMEOUT_JIFFIES;
+	add_timer(&ipmi_timer);
+}
+
+
+/* FIXME - convert these to slabs. */
+static void free_smi_msg(struct ipmi_smi_msg *msg)
+{
+	kfree(msg);
+}
+
+struct ipmi_smi_msg *ipmi_alloc_smi_msg(void)
+{
+	struct ipmi_smi_msg *rv;
+	rv = kmalloc(sizeof(struct ipmi_smi_msg), GFP_ATOMIC);
+	if (rv)
+		rv->done = free_smi_msg;
+	return rv;
+}
+
+static void free_recv_msg(struct ipmi_recv_msg *msg)
+{
+	kfree(msg);
+}
+
+struct ipmi_recv_msg *ipmi_alloc_recv_msg(void)
+{
+	struct ipmi_recv_msg *rv;
+
+	rv = kmalloc(sizeof(struct ipmi_recv_msg), GFP_ATOMIC);
+	if (rv)
+		rv->done = free_recv_msg;
+	return rv;
+}
+
+#ifdef CONFIG_IPMI_PANIC_EVENT
+
+static void dummy_smi_done_handler(struct ipmi_smi_msg *msg)
+{
+}
+
+static void dummy_recv_done_handler(struct ipmi_recv_msg *msg)
+{
+}
+
+static void send_panic_events(void)
+{
+	struct ipmi_msg                   msg;
+	ipmi_smi_t                        intf;
+	unsigned char                     data[8];
+	int                               i;
+	struct ipmi_system_interface_addr addr;
+	struct ipmi_smi_msg               smi_msg;
+	struct ipmi_recv_msg              recv_msg;
+
+	addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+	addr.channel = IPMI_BMC_CHANNEL;
+
+	/* Fill in an event telling that we have failed. */
+	msg.netfn = 0x04; /* Sensor or Event. */
+	msg.cmd = 2; /* Platform event command. */
+	msg.data = data;
+	msg.data_len = 8;
+	data[0] = 0x21; /* Kernel generator ID, IPMI table 5-4 */
+	data[1] = 0x03; /* This is for IPMI 1.0. */
+	data[2] = 0x20; /* OS Critical Stop, IPMI table 36-3 */
+	data[4] = 0x6f; /* Sensor specific, IPMI table 36-1 */
+	data[5] = 0xa1; /* Runtime stop OEM bytes 2 & 3. */
+
+	/* These used to have the first three bytes of the panic string,
+	   but not only is that not terribly useful, it's not available
+	   any more. */
+	data[3] = 0;
+	data[6] = 0;
+	data[7] = 0;
+
+	smi_msg.done = dummy_smi_done_handler;
+	recv_msg.done = dummy_recv_done_handler;
+
+	/* For every registered interface, send the event. */
+	for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+		intf = ipmi_interfaces[i];
+		if (intf == NULL)
+			continue;
+
+		intf->handlers->set_run_to_completion(intf->send_info, 1);
+		i_ipmi_request(NULL,
+			       intf,
+			       (struct ipmi_addr *) &addr,
+			       0,
+			       &msg,
+			       &smi_msg,
+			       &recv_msg,
+			       0,
+			       intf->my_address,
+			       intf->my_lun);
+	}
+}
+#endif /* CONFIG_IPMI_PANIC_EVENT */
+
+static int has_paniced = 0;
+
+static int panic_event(struct notifier_block *this,
+		       unsigned long         event,
+                       void                  *ptr)
+{
+	int        i;
+	ipmi_smi_t intf;
+
+	if (has_paniced)
+		return NOTIFY_DONE;
+	has_paniced = 1;
+
+	/* For every registered interface, set it to run to completion. */
+	for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+		intf = ipmi_interfaces[i];
+		if (intf == NULL)
+			continue;
+
+		intf->handlers->set_run_to_completion(intf->send_info, 1);
+	}
+
+#ifdef CONFIG_IPMI_PANIC_EVENT
+	send_panic_events();
+#endif
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block panic_block = {
+	panic_event,
+	NULL,
+	200   /* priority: INT_MAX >= x >= 0 */
+};
+
+
+static __init int ipmi_init_msghandler(void)
+{
+	int i;
+
+	if (initialized)
+		return 0;
+
+	for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+		ipmi_interfaces[i] = NULL;
+	}
+
+	init_timer(&ipmi_timer);
+	ipmi_timer.data = 0;
+	ipmi_timer.function = ipmi_timeout;
+	ipmi_timer.expires = jiffies + IPMI_TIMEOUT_JIFFIES;
+	add_timer(&ipmi_timer);
+
+	notifier_chain_register(&panic_notifier_list, &panic_block);
+
+	initialized = 1;
+
+	printk(KERN_INFO "ipmi: message handler initialized\n");
+
+	return 0;
+}
+
+static __exit void cleanup_ipmi(void)
+{
+	if (!initialized)
+		return;
+
+	notifier_chain_unregister(&panic_notifier_list, &panic_block);
+
+	/* This can't be called if any interfaces exist, so no worry about
+	   shutting down the interfaces. */
+
+	/* Tell the timer to stop, then wait for it to stop.  This avoids
+	   problems with race conditions removing the timer here. */
+	stop_operation = 1;
+	while (!timer_stopped) {
+		schedule_timeout(1);
+	}
+
+	initialized = 0;
+}
+module_exit(cleanup_ipmi);
+
+module_init(ipmi_init_msghandler);
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(ipmi_alloc_recv_msg);
+EXPORT_SYMBOL(ipmi_create_user);
+EXPORT_SYMBOL(ipmi_destroy_user);
+EXPORT_SYMBOL(ipmi_get_version);
+EXPORT_SYMBOL(ipmi_request);
+EXPORT_SYMBOL(ipmi_request_supply_msgs);
+EXPORT_SYMBOL(ipmi_request_with_source);
+EXPORT_SYMBOL(ipmi_register_smi);
+EXPORT_SYMBOL(ipmi_unregister_smi);
+EXPORT_SYMBOL(ipmi_register_for_cmd);
+EXPORT_SYMBOL(ipmi_unregister_for_cmd);
+EXPORT_SYMBOL(ipmi_smi_msg_received);
+EXPORT_SYMBOL(ipmi_smi_watchdog_pretimeout);
+EXPORT_SYMBOL(ipmi_alloc_smi_msg);
+EXPORT_SYMBOL(ipmi_register_all_cmd_rcvr);
+EXPORT_SYMBOL(ipmi_unregister_all_cmd_rcvr);
+EXPORT_SYMBOL(ipmi_addr_length);
+EXPORT_SYMBOL(ipmi_validate_addr);
+EXPORT_SYMBOL(ipmi_set_gets_events);
+EXPORT_SYMBOL(ipmi_addr_equal);
+EXPORT_SYMBOL(ipmi_smi_watcher_register);
+EXPORT_SYMBOL(ipmi_smi_watcher_unregister);
+EXPORT_SYMBOL(ipmi_set_my_address);
+EXPORT_SYMBOL(ipmi_get_my_address);
+EXPORT_SYMBOL(ipmi_set_my_LUN);
+EXPORT_SYMBOL(ipmi_get_my_LUN);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/ipmi/ipmi_watchdog.c linux-2.4.21-pre6/drivers/char/ipmi/ipmi_watchdog.c
--- linux-2.4.20/drivers/char/ipmi/ipmi_watchdog.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/ipmi/ipmi_watchdog.c	2003-03-26 23:49:09.000000000 +0000
@@ -0,0 +1,1113 @@
+/*
+ * ipmi_watchdog.c
+ *
+ * A watchdog timer based upon the IPMI interface.
+ *
+ * Author: MontaVista Software, Inc.
+ *         Corey Minyard <minyard@mvista.com>
+ *         source@mvista.com
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; either version 2 of the License, or (at your
+ *  option) any later version.
+ *
+ *
+ *  THIS 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.
+ *
+ *  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/ipmi.h>
+#include <linux/ipmi_smi.h>
+#include <linux/watchdog.h>
+#include <linux/miscdevice.h>
+#include <linux/init.h>
+#include <linux/rwsem.h>
+#include <linux/errno.h>
+#include <asm/uaccess.h>
+#include <linux/notifier.h>
+#include <linux/nmi.h>
+#include <linux/reboot.h>
+#include <linux/wait.h>
+#include <linux/poll.h>
+#ifdef CONFIG_X86_LOCAL_APIC
+#include <asm/apic.h>
+#endif
+
+/*
+ * The IPMI command/response information for the watchdog timer.
+ */
+
+/* values for byte 1 of the set command, byte 2 of the get response. */
+#define WDOG_DONT_LOG		(1 << 7)
+#define WDOG_DONT_STOP_ON_SET	(1 << 6)
+#define WDOG_SET_TIMER_USE(byte, use) \
+	byte = ((byte) & 0xf8) | ((use) & 0x7)
+#define WDOG_GET_TIMER_USE(byte) ((byte) & 0x7)
+#define WDOG_TIMER_USE_BIOS_FRB2	1
+#define WDOG_TIMER_USE_BIOS_POST	2
+#define WDOG_TIMER_USE_OS_LOAD		3
+#define WDOG_TIMER_USE_SMS_OS		4
+#define WDOG_TIMER_USE_OEM		5
+
+/* values for byte 2 of the set command, byte 3 of the get response. */
+#define WDOG_SET_PRETIMEOUT_ACT(byte, use) \
+	byte = ((byte) & 0x8f) | (((use) & 0x7) << 4)
+#define WDOG_GET_PRETIMEOUT_ACT(byte) (((byte) >> 4) & 0x7)
+#define WDOG_PRETIMEOUT_NONE		0
+#define WDOG_PRETIMEOUT_SMI		1
+#define WDOG_PRETIMEOUT_NMI		2
+#define WDOG_PRETIMEOUT_MSG_INT		3
+
+/* Operations that can be performed on a pretimout. */
+#define WDOG_PREOP_NONE		0
+#define WDOG_PREOP_PANIC	1
+#define WDOG_PREOP_GIVE_DATA	2 /* Cause data to be available to
+                                     read.  Doesn't work in NMI
+                                     mode. */
+
+/* Actions to perform on a full timeout. */
+#define WDOG_SET_TIMEOUT_ACT(byte, use) \
+	byte = ((byte) & 0xf8) | ((use) & 0x7)
+#define WDOG_GET_TIMEOUT_ACT(byte) ((byte) & 0x7)
+#define WDOG_TIMEOUT_NONE		0
+#define WDOG_TIMEOUT_RESET		1
+#define WDOG_TIMEOUT_POWER_DOWN		2
+#define WDOG_TIMEOUT_POWER_CYCLE	3
+
+/* Byte 3 of the get command, byte 4 of the get response is the
+   pre-timeout in seconds. */
+
+/* Bits for setting byte 4 of the set command, byte 5 of the get response. */
+#define WDOG_EXPIRE_CLEAR_BIOS_FRB2	(1 << 1)
+#define WDOG_EXPIRE_CLEAR_BIOS_POST	(1 << 2)
+#define WDOG_EXPIRE_CLEAR_OS_LOAD	(1 << 3)
+#define WDOG_EXPIRE_CLEAR_SMS_OS	(1 << 4)
+#define WDOG_EXPIRE_CLEAR_OEM		(1 << 5)
+
+/* Setting/getting the watchdog timer value.  This is for bytes 5 and
+   6 (the timeout time) of the set command, and bytes 6 and 7 (the
+   timeout time) and 8 and 9 (the current countdown value) of the
+   response.  The timeout value is given in seconds (in the command it
+   is 100ms intervals). */
+#define WDOG_SET_TIMEOUT(byte1, byte2, val) \
+	(byte1) = (((val) * 10) & 0xff), (byte2) = (((val) * 10) >> 8)
+#define WDOG_GET_TIMEOUT(byte1, byte2) \
+	(((byte1) | ((byte2) << 8)) / 10)
+
+#define IPMI_WDOG_RESET_TIMER		0x22
+#define IPMI_WDOG_SET_TIMER		0x24
+#define IPMI_WDOG_GET_TIMER		0x25
+
+/* These are here until the real ones get into the watchdog.h interface. */
+#ifndef WDIOC_GETTIMEOUT
+#define	WDIOC_GETTIMEOUT        _IOW(WATCHDOG_IOCTL_BASE, 20, int)
+#endif
+#ifndef WDIOC_SET_PRETIMEOUT
+#define	WDIOC_SET_PRETIMEOUT     _IOW(WATCHDOG_IOCTL_BASE, 21, int)
+#endif
+#ifndef WDIOC_GET_PRETIMEOUT
+#define	WDIOC_GET_PRETIMEOUT     _IOW(WATCHDOG_IOCTL_BASE, 22, int)
+#endif
+
+static ipmi_user_t watchdog_user = NULL;
+
+/* Default the timeout to 10 seconds. */
+static int timeout = 10;
+
+/* The pre-timeout is disabled by default. */
+static int pretimeout = 0;
+
+/* Default action is to reset the board on a timeout. */
+static unsigned char action_val = WDOG_TIMEOUT_RESET;
+
+static char *action = "reset";
+
+static unsigned char preaction_val = WDOG_PRETIMEOUT_NONE;
+
+static char *preaction = "pre_none";
+
+static unsigned char preop_val = WDOG_PREOP_NONE;
+
+static char *preop = "preop_none";
+static spinlock_t ipmi_read_lock = SPIN_LOCK_UNLOCKED;
+static char data_to_read = 0;
+static DECLARE_WAIT_QUEUE_HEAD(read_q);
+static struct fasync_struct *fasync_q = NULL;
+static char pretimeout_since_last_heartbeat = 0;
+
+MODULE_PARM(timeout, "i");
+MODULE_PARM(pretimeout, "i");
+MODULE_PARM(action, "s");
+MODULE_PARM(preaction, "s");
+MODULE_PARM(preop, "s");
+
+/* Default state of the timer. */
+static unsigned char ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
+
+/* If shutting down via IPMI, we ignore the heartbeat. */
+static int ipmi_ignore_heartbeat = 0;
+
+/* Is someone using the watchdog?  Only one user is allowed. */
+static int ipmi_wdog_open = 0;
+
+/* If true, the driver will start running as soon as it is configured
+   and ready. */
+static int start_now = 0;
+
+/* If set to 1, the heartbeat command will set the state to reset and
+   start the timer.  The timer doesn't normally run when the driver is
+   first opened until the heartbeat is set the first time, this
+   variable is used to accomplish this. */
+static int ipmi_start_timer_on_heartbeat = 0;
+
+/* IPMI version of the BMC. */
+static unsigned char ipmi_version_major;
+static unsigned char ipmi_version_minor;
+
+
+static int ipmi_heartbeat(void);
+static void panic_halt_ipmi_heartbeat(void);
+
+
+/* We use a semaphore to make sure that only one thing can send a set
+   timeout at one time, because we only have one copy of the data.
+   The semaphore is claimed when the set_timeout is sent and freed
+   when both messages are free. */
+static atomic_t set_timeout_tofree = ATOMIC_INIT(0);
+static DECLARE_MUTEX(set_timeout_lock);
+static void set_timeout_free_smi(struct ipmi_smi_msg *msg)
+{
+    if (atomic_dec_and_test(&set_timeout_tofree))
+	    up(&set_timeout_lock);
+}
+static void set_timeout_free_recv(struct ipmi_recv_msg *msg)
+{
+    if (atomic_dec_and_test(&set_timeout_tofree))
+	    up(&set_timeout_lock);
+}
+static struct ipmi_smi_msg set_timeout_smi_msg =
+{
+	.done = set_timeout_free_smi
+};
+static struct ipmi_recv_msg set_timeout_recv_msg =
+{
+	.done = set_timeout_free_recv
+};
+ 
+static int i_ipmi_set_timeout(struct ipmi_smi_msg  *smi_msg,
+			      struct ipmi_recv_msg *recv_msg,
+			      int                  *send_heartbeat_now)
+{
+	struct ipmi_msg    msg;
+	unsigned char      data[6];
+	int                rv;
+	struct ipmi_system_interface_addr addr;
+
+
+	*send_heartbeat_now = 0;
+	data[0] = 0;
+	WDOG_SET_TIMER_USE(data[0], WDOG_TIMER_USE_SMS_OS);
+
+	if ((ipmi_version_major > 1)
+	    || ((ipmi_version_major == 1) && (ipmi_version_minor >= 5)))
+	{
+		/* This is an IPMI 1.5-only feature. */
+		data[0] |= WDOG_DONT_STOP_ON_SET;
+	} else if (ipmi_watchdog_state != WDOG_TIMEOUT_NONE) {
+		/* In ipmi 1.0, setting the timer stops the watchdog, we
+		   need to start it back up again. */
+		*send_heartbeat_now = 1;
+	}
+
+	data[1] = 0;
+	WDOG_SET_TIMEOUT_ACT(data[1], ipmi_watchdog_state);
+	if (pretimeout > 0) {
+	    WDOG_SET_PRETIMEOUT_ACT(data[1], preaction_val);
+	    data[2] = pretimeout;
+	} else {
+	    WDOG_SET_PRETIMEOUT_ACT(data[1], WDOG_PRETIMEOUT_NONE);
+	    data[2] = 0; /* No pretimeout. */
+	}
+	data[3] = 0;
+	WDOG_SET_TIMEOUT(data[4], data[5], timeout);
+
+	addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+	addr.channel = IPMI_BMC_CHANNEL;
+	addr.lun = 0;
+
+	msg.netfn = 0x06;
+	msg.cmd = IPMI_WDOG_SET_TIMER;
+	msg.data = data;
+	msg.data_len = sizeof(data);
+	rv = ipmi_request_supply_msgs(watchdog_user,
+				      (struct ipmi_addr *) &addr,
+				      0,
+				      &msg,
+				      smi_msg,
+				      recv_msg,
+				      1);
+	if (rv) {
+		printk(KERN_WARNING "IPMI Watchdog, set timeout error: %d\n",
+		       rv);
+	}
+
+	return rv;
+}
+
+static int ipmi_set_timeout(void)
+{
+	int send_heartbeat_now;
+	int rv;
+
+
+	/* We can only send one of these at a time. */
+	down(&set_timeout_lock);
+
+	atomic_set(&set_timeout_tofree, 2);
+
+	rv = i_ipmi_set_timeout(&set_timeout_smi_msg,
+				&set_timeout_recv_msg,
+				&send_heartbeat_now);
+	if (rv) {
+		up(&set_timeout_lock);
+	} else {
+		if (send_heartbeat_now)
+			rv = ipmi_heartbeat();
+	}
+
+	return rv;
+}
+
+static void dummy_smi_free(struct ipmi_smi_msg *msg)
+{
+}
+static void dummy_recv_free(struct ipmi_recv_msg *msg)
+{
+}
+static struct ipmi_smi_msg panic_halt_smi_msg =
+{
+	.done = dummy_smi_free
+};
+static struct ipmi_recv_msg panic_halt_recv_msg =
+{
+	.done = dummy_recv_free
+};
+
+/* Special call, doesn't claim any locks.  This is only to be called
+   at panic or halt time, in run-to-completion mode, when the caller
+   is the only CPU and the only thing that will be going IPMI
+   calls. */
+static void panic_halt_ipmi_set_timeout(void)
+{
+	int send_heartbeat_now;
+	int rv;
+
+	rv = i_ipmi_set_timeout(&panic_halt_smi_msg,
+				&panic_halt_recv_msg,
+				&send_heartbeat_now);
+	if (!rv) {
+		if (send_heartbeat_now)
+			panic_halt_ipmi_heartbeat();
+	}
+}
+
+/* Do a delayed shutdown, with the delay in milliseconds.  If power_off is
+   false, do a reset.  If power_off is true, do a power down.  This is
+   primarily for the IMB code's shutdown. */
+void ipmi_delayed_shutdown(long delay, int power_off)
+{
+	ipmi_ignore_heartbeat = 1;
+	if (power_off) 
+		ipmi_watchdog_state = WDOG_TIMEOUT_POWER_DOWN;
+	else
+		ipmi_watchdog_state = WDOG_TIMEOUT_RESET;
+	timeout = delay;
+	ipmi_set_timeout();
+}
+
+/* We use a semaphore to make sure that only one thing can send a
+   heartbeat at one time, because we only have one copy of the data.
+   The semaphore is claimed when the set_timeout is sent and freed
+   when both messages are free. */
+static atomic_t heartbeat_tofree = ATOMIC_INIT(0);
+static DECLARE_MUTEX(heartbeat_lock);
+static DECLARE_MUTEX_LOCKED(heartbeat_wait_lock);
+static void heartbeat_free_smi(struct ipmi_smi_msg *msg)
+{
+    if (atomic_dec_and_test(&heartbeat_tofree))
+	    up(&heartbeat_wait_lock);
+}
+static void heartbeat_free_recv(struct ipmi_recv_msg *msg)
+{
+    if (atomic_dec_and_test(&heartbeat_tofree))
+	    up(&heartbeat_wait_lock);
+}
+static struct ipmi_smi_msg heartbeat_smi_msg =
+{
+	.done = heartbeat_free_smi
+};
+static struct ipmi_recv_msg heartbeat_recv_msg =
+{
+	.done = heartbeat_free_recv
+};
+ 
+static struct ipmi_smi_msg panic_halt_heartbeat_smi_msg =
+{
+	.done = dummy_smi_free
+};
+static struct ipmi_recv_msg panic_halt_heartbeat_recv_msg =
+{
+	.done = dummy_recv_free
+};
+ 
+static int ipmi_heartbeat(void)
+{
+	struct ipmi_msg                   msg;
+	int                               rv;
+	struct ipmi_system_interface_addr addr;
+
+	if (ipmi_ignore_heartbeat) {
+		return 0;
+	}
+
+	if (ipmi_start_timer_on_heartbeat) {
+		ipmi_start_timer_on_heartbeat = 0;
+		ipmi_watchdog_state = action_val;
+		return ipmi_set_timeout();
+	}
+
+	if (pretimeout_since_last_heartbeat) {
+		/* A pretimeout occurred, make sure we set the timeout.
+		   We don't want to set the action, though, we want to
+		   leave that alone (thus it can't be combined with the
+		   above operation. */
+		pretimeout_since_last_heartbeat = 0;
+		return ipmi_set_timeout();
+	}
+
+	down(&heartbeat_lock);
+
+	atomic_set(&heartbeat_tofree, 2);
+
+	/* Don't reset the timer if we have the timer turned off, that
+           re-enables the watchdog. */
+	if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE) {
+		up(&heartbeat_lock);
+		return 0;
+	}
+
+	addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+	addr.channel = IPMI_BMC_CHANNEL;
+	addr.lun = 0;
+
+	msg.netfn = 0x06;
+	msg.cmd = IPMI_WDOG_RESET_TIMER;
+	msg.data = NULL;
+	msg.data_len = 0;
+	rv = ipmi_request_supply_msgs(watchdog_user,
+				      (struct ipmi_addr *) &addr,
+				      0,
+				      &msg,
+				      &heartbeat_smi_msg,
+				      &heartbeat_recv_msg,
+				      1);
+	if (rv) {
+		up(&heartbeat_lock);
+		printk(KERN_WARNING "IPMI Watchdog, heartbeat failure: %d\n",
+		       rv);
+		return rv;
+	}
+
+	/* Wait for the heartbeat to be sent. */
+	down(&heartbeat_wait_lock);
+
+	if (heartbeat_recv_msg.msg.data[0] != 0) {
+	    /* Got an error in the heartbeat response.  It was already
+	       reported in ipmi_wdog_msg_handler, but we should return
+	       an error here. */
+	    rv = -EINVAL;
+	}
+
+	up(&heartbeat_lock);
+
+	return rv;
+}
+
+static void panic_halt_ipmi_heartbeat(void)
+{
+	struct ipmi_msg                   msg;
+	struct ipmi_system_interface_addr addr;
+
+
+	/* Don't reset the timer if we have the timer turned off, that
+           re-enables the watchdog. */
+	if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE)
+		return;
+
+	addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+	addr.channel = IPMI_BMC_CHANNEL;
+	addr.lun = 0;
+
+	msg.netfn = 0x06;
+	msg.cmd = IPMI_WDOG_RESET_TIMER;
+	msg.data = NULL;
+	msg.data_len = 0;
+	ipmi_request_supply_msgs(watchdog_user,
+				 (struct ipmi_addr *) &addr,
+				 0,
+				 &msg,
+				 &panic_halt_heartbeat_smi_msg,
+				 &panic_halt_heartbeat_recv_msg,
+				 1);
+}
+
+static struct watchdog_info ident=
+{
+	0, /* WDIOF_SETTIMEOUT, */
+	1,
+	"IPMI"
+};
+
+static int ipmi_ioctl(struct inode *inode, struct file *file,
+		      unsigned int cmd, unsigned long arg)
+{
+	int i;
+	int val;
+
+	switch(cmd) {
+	case WDIOC_GETSUPPORT:
+		i = copy_to_user((void*)arg, &ident, sizeof(ident));
+		return i ? -EFAULT : 0;
+
+	case WDIOC_SETTIMEOUT:
+		i = copy_from_user(&val, (void *) arg, sizeof(int));
+		if (i)
+			return -EFAULT;
+		timeout = val;
+		return ipmi_set_timeout();
+
+	case WDIOC_GETTIMEOUT:
+		i = copy_to_user((void *) arg,
+				 &timeout,
+				 sizeof(timeout));
+		if (i)
+			return -EFAULT;
+		return 0;
+
+	case WDIOC_SET_PRETIMEOUT:
+		i = copy_from_user(&val, (void *) arg, sizeof(int));
+		if (i)
+			return -EFAULT;
+		pretimeout = val;
+		return ipmi_set_timeout();
+
+	case WDIOC_GET_PRETIMEOUT:
+		i = copy_to_user((void *) arg,
+				 &pretimeout,
+				 sizeof(pretimeout));
+		if (i)
+			return -EFAULT;
+		return 0;
+
+	case WDIOC_KEEPALIVE:
+		return ipmi_heartbeat();
+
+	case WDIOC_SETOPTIONS:
+		i = copy_from_user(&val, (void *) arg, sizeof(int));
+		if (i)
+			return -EFAULT;
+		if (val & WDIOS_DISABLECARD)
+		{
+			ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
+			ipmi_set_timeout();
+			ipmi_start_timer_on_heartbeat = 0;
+		}
+
+		if (val & WDIOS_ENABLECARD)
+		{
+			ipmi_watchdog_state = action_val;
+			ipmi_set_timeout();
+		}
+		return 0;
+
+	case WDIOC_GETSTATUS:
+		val = 0;
+		return copy_to_user((void *) arg, &val, sizeof(val));
+
+	default:
+		return -ENOIOCTLCMD;
+	}
+}
+
+static ssize_t ipmi_write(struct file *file,
+			  const char  *buf,
+			  size_t      len,
+			  loff_t      *ppos)
+{
+	int rv;
+
+	/*  Can't seek (pwrite) on this device  */
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	if (len) {
+		rv = ipmi_heartbeat();
+		if (rv)
+			return rv;
+		return 1;
+	}
+	return 0;
+}
+
+static ssize_t ipmi_read(struct file *file,
+			 char        *buf,
+			 size_t      count,
+			 loff_t      *ppos)
+{
+	int          rv = 0;
+	wait_queue_t wait;
+
+	/*  Can't seek (pread) on this device  */
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	if (count <= 0)
+		return 0;
+
+	/* Reading returns if the pretimeout has gone off, and it only does
+	   it once per pretimeout. */
+	spin_lock(&ipmi_read_lock);
+	if (!data_to_read) {
+		if (file->f_flags & O_NONBLOCK) {
+			rv = -EAGAIN;
+			goto out;
+		}
+		
+		init_waitqueue_entry(&wait, current);
+		add_wait_queue(&read_q, &wait);
+		while (!data_to_read) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			spin_unlock(&ipmi_read_lock);
+			schedule();
+			spin_lock(&ipmi_read_lock);
+		}
+		remove_wait_queue(&read_q, &wait);
+	    
+		if (signal_pending(current)) {
+			rv = -ERESTARTSYS;
+			goto out;
+		}
+	}
+	data_to_read = 0;
+
+ out:
+	spin_unlock(&ipmi_read_lock);
+
+	if (rv == 0) {
+		if (copy_to_user(buf, &data_to_read, 1))
+			rv = -EFAULT;
+		else
+			rv = 1;
+	}
+
+	return rv;
+}
+
+static int ipmi_open(struct inode *ino, struct file *filep)
+{
+        switch (minor(ino->i_rdev))
+        {
+                case WATCHDOG_MINOR:
+                    if (ipmi_wdog_open)
+                        return -EBUSY;
+
+                    ipmi_wdog_open = 1;
+
+		    /* Don't start the timer now, let it start on the
+		       first heartbeat. */
+		    ipmi_start_timer_on_heartbeat = 1;
+                    return(0);
+
+                default:
+                    return (-ENODEV);
+        }
+}
+
+static unsigned int ipmi_poll(struct file *file, poll_table *wait)
+{
+	unsigned int mask = 0;
+	
+	poll_wait(file, &read_q, wait);
+
+	spin_lock(&ipmi_read_lock);
+	if (data_to_read)
+		mask |= (POLLIN | POLLRDNORM);
+	spin_unlock(&ipmi_read_lock);
+
+	return mask;
+}
+
+static int ipmi_fasync(int fd, struct file *file, int on)
+{
+	int result;
+
+	result = fasync_helper(fd, file, on, &fasync_q);
+
+	return (result);
+}
+
+static int ipmi_close(struct inode *ino, struct file *filep)
+{
+	if (minor(ino->i_rdev)==WATCHDOG_MINOR)
+	{
+#ifndef CONFIG_WATCHDOG_NOWAYOUT	
+		ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
+		ipmi_set_timeout();
+#endif		
+	        ipmi_wdog_open = 0;
+	}
+
+	ipmi_fasync (-1, filep, 0);
+
+	return 0;
+}
+
+static struct file_operations ipmi_wdog_fops = {
+	.owner   = THIS_MODULE,
+	.read    = ipmi_read,
+	.poll    = ipmi_poll,
+	.write   = ipmi_write,
+	.ioctl   = ipmi_ioctl,
+	.open    = ipmi_open,
+	.release = ipmi_close,
+	.fasync  = ipmi_fasync,
+};
+
+static struct miscdevice ipmi_wdog_miscdev = {
+	WATCHDOG_MINOR,
+	"watchdog",
+	&ipmi_wdog_fops
+};
+
+static DECLARE_RWSEM(register_sem);
+
+static void ipmi_wdog_msg_handler(struct ipmi_recv_msg *msg,
+				  void                 *handler_data)
+{
+	if (msg->msg.data[0] != 0) {
+		printk(KERN_ERR "IPMI Watchdog response: Error %x on cmd %x\n",
+		       msg->msg.data[0],
+		       msg->msg.cmd);
+	}
+	
+	ipmi_free_recv_msg(msg);
+}
+
+static void ipmi_wdog_pretimeout_handler(void *handler_data)
+{
+	if (preaction_val != WDOG_PRETIMEOUT_NONE) {
+		if (preop_val == WDOG_PREOP_PANIC)
+			panic("Watchdog pre-timeout");
+		else if (preop_val == WDOG_PREOP_GIVE_DATA) {
+			spin_lock(&ipmi_read_lock);
+			data_to_read = 1;
+			wake_up_interruptible(&read_q);
+			kill_fasync(&fasync_q, SIGIO, POLL_IN);
+
+			/* On some machines, the heartbeat will give
+			   an error and not work unless we re-enable
+			   the timer.   So do so. */
+			pretimeout_since_last_heartbeat = 1;
+
+			spin_unlock(&ipmi_read_lock);
+		}
+	}
+}
+
+static struct ipmi_user_hndl ipmi_hndlrs =
+{
+	.ipmi_recv_hndl           = ipmi_wdog_msg_handler,
+	.ipmi_watchdog_pretimeout = ipmi_wdog_pretimeout_handler
+};
+
+static void ipmi_register_watchdog(int ipmi_intf)
+{
+	int rv = -EBUSY;
+
+	down_read(&register_sem);
+	if (watchdog_user)
+		goto out;
+
+	rv = ipmi_create_user(ipmi_intf, &ipmi_hndlrs, NULL, &watchdog_user);
+	if (rv < 0) {
+		printk("IPMI watchdog: Unable to register with ipmi\n");
+		goto out;
+	}
+
+	ipmi_get_version(watchdog_user,
+			 &ipmi_version_major,
+			 &ipmi_version_minor);
+
+	rv = misc_register(&ipmi_wdog_miscdev);
+	if (rv < 0) {
+		ipmi_destroy_user(watchdog_user);
+		watchdog_user = NULL;
+		printk("IPMI watchdog: Unable to register misc device\n");
+	}
+
+ out:
+	up_write(&register_sem);
+
+	if ((start_now) && (rv == 0)) {
+		/* Run from startup, so start the timer now. */
+		start_now = 0; /* Disable this function after first startup. */
+		ipmi_watchdog_state = action_val;
+		ipmi_set_timeout();
+		printk("Starting IPMI Watchdog now!\n");
+	}
+}
+
+#ifdef HAVE_NMI_HANDLER
+static int
+ipmi_nmi(void *dev_id, struct pt_regs *regs, int cpu, int handled)
+{
+	/* If no one else handled the NMI, we assume it was the IPMI
+           watchdog. */
+	if ((!handled) && (preop_val == WDOG_PREOP_PANIC))
+		panic("IPMI watchdog pre-timeout");
+	return NOTIFY_DONE;
+}
+
+static struct nmi_handler ipmi_nmi_handler =
+{
+	.dev_name = "ipmi_watchdog",
+	.dev_id   = NULL,
+	.handler  = ipmi_nmi,
+	.priority = 0, /* Call us last. */
+};
+#endif
+
+static int wdog_reboot_handler(struct notifier_block *this,
+			       unsigned long         code,
+			       void                  *unused)
+{
+	static int reboot_event_handled = 0;
+
+	if ((watchdog_user) && (!reboot_event_handled)) {
+		/* Make sure we only do this once. */
+		reboot_event_handled = 1;
+
+		if (code == SYS_DOWN || code == SYS_HALT) {
+			/* Disable the WDT if we are shutting down. */
+			ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
+			panic_halt_ipmi_set_timeout();
+		} else {
+			/* Set a long timer to let the reboot happens, but
+			   reboot if it hangs. */
+			timeout = 120;
+			pretimeout = 0;
+			ipmi_watchdog_state = WDOG_TIMEOUT_RESET;
+			panic_halt_ipmi_set_timeout();
+		}
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block wdog_reboot_notifier = {
+	wdog_reboot_handler,
+	NULL,
+	0
+};
+
+extern int panic_timeout; /* Why isn't this defined anywhere? */
+
+static int wdog_panic_handler(struct notifier_block *this,
+			      unsigned long         event,
+			      void                  *unused)
+{
+	static int panic_event_handled = 0;
+
+	/* On a panic, if we have a panic timeout, make sure that the thing
+	   reboots, even if it hangs during that panic. */
+	if (watchdog_user && !panic_event_handled && (panic_timeout > 0)) {
+		/* Make sure the panic doesn't hang, and make sure we
+		   do this only once. */
+		panic_event_handled = 1;
+	    
+		timeout = panic_timeout + 120;
+		if (timeout > 255)
+			timeout = 255;
+		pretimeout = 0;
+		ipmi_watchdog_state = WDOG_TIMEOUT_RESET;
+		panic_halt_ipmi_set_timeout();
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block wdog_panic_notifier = {
+	wdog_panic_handler,
+	NULL,
+	150   /* priority: INT_MAX >= x >= 0 */
+};
+
+
+static void ipmi_new_smi(int if_num)
+{
+	ipmi_register_watchdog(if_num);
+}
+
+static void ipmi_smi_gone(int if_num)
+{
+	/* This can never be called, because once the watchdog is
+	   registered, the interface can't go away until the watchdog
+	   is unregistered. */
+}
+
+static struct ipmi_smi_watcher smi_watcher =
+{
+	.new_smi  = ipmi_new_smi,
+	.smi_gone = ipmi_smi_gone
+};
+
+static int __init ipmi_wdog_init(void)
+{
+	int rv;
+
+	if (strcmp(action, "reset") == 0) {
+		action_val = WDOG_TIMEOUT_RESET;
+	} else if (strcmp(action, "none") == 0) {
+		action_val = WDOG_TIMEOUT_NONE;
+	} else if (strcmp(action, "power_cycle") == 0) {
+		action_val = WDOG_TIMEOUT_POWER_CYCLE;
+	} else if (strcmp(action, "power_off") == 0) {
+		action_val = WDOG_TIMEOUT_POWER_DOWN;
+	} else {
+		action_val = WDOG_TIMEOUT_RESET;
+		printk("ipmi_watchdog: Unknown action '%s', defaulting to"
+		       " reset\n", action);
+	}
+
+	if (strcmp(preaction, "pre_none") == 0) {
+		preaction_val = WDOG_PRETIMEOUT_NONE;
+	} else if (strcmp(preaction, "pre_smi") == 0) {
+		preaction_val = WDOG_PRETIMEOUT_SMI;
+#ifdef HAVE_NMI_HANDLER
+	} else if (strcmp(preaction, "pre_nmi") == 0) {
+		preaction_val = WDOG_PRETIMEOUT_NMI;
+#endif
+	} else if (strcmp(preaction, "pre_int") == 0) {
+		preaction_val = WDOG_PRETIMEOUT_MSG_INT;
+	} else {
+		action_val = WDOG_PRETIMEOUT_NONE;
+		printk("ipmi_watchdog: Unknown preaction '%s', defaulting to"
+		       " none\n", preaction);
+	}
+
+	if (strcmp(preop, "preop_none") == 0) {
+		preop_val = WDOG_PREOP_NONE;
+	} else if (strcmp(preop, "preop_panic") == 0) {
+		preop_val = WDOG_PREOP_PANIC;
+	} else if (strcmp(preop, "preop_give_data") == 0) {
+		preop_val = WDOG_PREOP_GIVE_DATA;
+	} else {
+		action_val = WDOG_PREOP_NONE;
+		printk("ipmi_watchdog: Unknown preop '%s', defaulting to"
+		       " none\n", preop);
+	}
+
+#ifdef HAVE_NMI_HANDLER
+	if (preaction_val == WDOG_PRETIMEOUT_NMI) {
+		if (preop_val == WDOG_PREOP_GIVE_DATA) {
+			printk(KERN_WARNING
+			       "ipmi_watchdog: Pretimeout op is to give data"
+			       " but NMI pretimeout is enabled, setting"
+			       " pretimeout op to none\n");
+			preop_val = WDOG_PREOP_NONE;
+		}
+#ifdef CONFIG_X86_LOCAL_APIC
+		if (nmi_watchdog == NMI_IO_APIC) {
+			printk(KERN_WARNING
+			       "ipmi_watchdog: nmi_watchdog is set to IO APIC"
+			       " mode (value is %d), that is incompatible"
+			       " with using NMI in the IPMI watchdog."
+			       " Disabling IPMI nmi pretimeout.\n",
+			       nmi_watchdog);
+			preaction_val = WDOG_PRETIMEOUT_NONE;
+		} else {
+#endif
+		rv = request_nmi(&ipmi_nmi_handler);
+		if (rv) {
+			printk(KERN_WARNING
+			       "ipmi_watchdog: Can't register nmi handler\n");
+			return rv;
+		}
+#ifdef CONFIG_X86_LOCAL_APIC
+		}
+#endif
+	}
+#endif
+
+	rv = ipmi_smi_watcher_register(&smi_watcher);
+	if (rv) {
+#ifdef HAVE_NMI_HANDLER
+		if (preaction_val == WDOG_PRETIMEOUT_NMI)
+			release_nmi(&ipmi_nmi_handler);
+#endif
+		printk(KERN_WARNING
+		       "ipmi_watchdog: can't register smi watcher\n");
+		return rv;
+	}
+
+	register_reboot_notifier(&wdog_reboot_notifier);
+	notifier_chain_register(&panic_notifier_list, &wdog_panic_notifier);
+
+	printk(KERN_INFO "IPMI watchdog by "
+	       "Corey Minyard (minyard@mvista.com)\n");
+
+	return 0;
+}
+
+#ifdef MODULE
+static void ipmi_unregister_watchdog(void)
+{
+	int rv;
+
+	down_write(&register_sem);
+
+#ifdef HAVE_NMI_HANDLER
+	if (preaction_val == WDOG_PRETIMEOUT_NMI)
+		release_nmi(&ipmi_nmi_handler);
+#endif
+
+	notifier_chain_unregister(&panic_notifier_list, &wdog_panic_notifier);
+	unregister_reboot_notifier(&wdog_reboot_notifier);
+
+	if (! watchdog_user)
+		goto out;
+
+	/* Make sure no one can call us any more. */
+	misc_deregister(&ipmi_wdog_miscdev);
+
+	/*  Disable the timer. */
+	ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
+	ipmi_set_timeout();
+
+	/* Wait to make sure the message makes it out.  The lower layer has
+	   pointers to our buffers, we want to make sure they are done before
+	   we release our memory. */
+	while (atomic_read(&set_timeout_tofree)) {
+		schedule_timeout(1);
+	}
+
+	/* Disconnect from IPMI. */
+	rv = ipmi_destroy_user(watchdog_user);
+	if (rv) {
+		printk(KERN_WARNING
+		       "IPMI Watchdog, error unlinking from IPMI: %d\n",
+		       rv);
+	}
+	watchdog_user = NULL;
+
+ out:
+	up_write(&register_sem);
+}
+
+static void __exit ipmi_wdog_exit(void)
+{
+	ipmi_smi_watcher_unregister(&smi_watcher);
+	ipmi_unregister_watchdog();
+}
+module_exit(ipmi_wdog_exit);
+#else
+static int __init ipmi_wdog_setup(char *str)
+{
+	int  val;
+	int  rv;
+	char *option;
+
+	rv = get_option(&str, &val);
+	if (rv == 0)
+		return 1;
+	if (val > 0)
+		timeout = val;
+	if (rv == 1)
+		return 1;
+
+	rv = get_option(&str, &val);
+	if (rv == 0)
+		return 1;
+	if (val >= 0)
+		pretimeout = val;
+	if (rv == 1)
+		return 1;
+
+	while ((option = strsep(&str, ",")) != NULL) {
+		if (strcmp(option, "reset") == 0) {
+			action = "reset";
+		}
+		else if (strcmp(option, "none") == 0) {
+			action = "none";
+		}
+		else if (strcmp(option, "power_cycle") == 0) {
+			action = "power_cycle";
+		}
+		else if (strcmp(option, "power_off") == 0) {
+			action = "power_off";
+		}
+		else if (strcmp(option, "pre_none") == 0) {
+			preaction = "pre_none";
+		}
+		else if (strcmp(option, "pre_smi") == 0) {
+			preaction = "pre_smi";
+		}
+#ifdef HAVE_NMI_HANDLER
+		else if (strcmp(option, "pre_nmi") == 0) {
+			preaction = "pre_nmi";
+		}
+#endif
+		else if (strcmp(option, "pre_int") == 0) {
+			preaction = "pre_int";
+		}
+		else if (strcmp(option, "start_now") == 0) {
+			start_now = 1;
+		}
+		else if (strcmp(option, "preop_none") == 0) {
+			preop = "preop_none";
+		}
+		else if (strcmp(option, "preop_panic") == 0) {
+			preop = "preop_panic";
+		}
+		else if (strcmp(option, "preop_none") == 0) {
+			preop = "preop_give_data";
+		} else {
+		    printk("Unknown IPMI watchdog option: '%s'\n", option);
+		}
+	}
+
+	return 1;
+}
+__setup("ipmi_wdog=", ipmi_wdog_setup);
+#endif
+
+EXPORT_SYMBOL(ipmi_delayed_shutdown);
+
+module_init(ipmi_wdog_init);
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/isicom.c linux-2.4.21-pre6/drivers/char/isicom.c
--- linux-2.4.20/drivers/char/isicom.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/isicom.c	2003-03-26 23:48:58.000000000 +0000
@@ -2016,7 +2016,7 @@
 	retval=misc_register(&isiloader_device);
 	if (retval<0) {
 		printk(KERN_ERR "ISICOM: Unable to register firmware loader driver.\n");
-		return -EIO;
+		return retval;
 	}
 	
 	if (!isicom_init()) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/joystick/iforce.c linux-2.4.21-pre6/drivers/char/joystick/iforce.c
--- linux-2.4.20/drivers/char/joystick/iforce.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/joystick/iforce.c	2003-03-26 23:49:07.000000000 +0000
@@ -93,6 +93,7 @@
 	BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A, BTN_B, BTN_C, BTN_DEAD, -1 };
 static signed short btn_wheel[] =    { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE,
 	BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A, BTN_B, BTN_C, -1 };
+static signed short btn_avb_tw[] =   { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, -1 };
 static signed short abs_joystick[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 };
 static signed short abs_wheel[] =    { ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, -1 };
 static signed short ff_iforce[] =    { FF_PERIODIC, FF_CONSTANT, FF_SPRING, FF_FRICTION,
@@ -106,11 +107,15 @@
 	signed short *abs;
 	signed short *ff;
 } iforce_device[] = {
+	{ 0x044f, 0xa01c, "Thrustmaster Motor Sport GT",		btn_wheel, abs_wheel, ff_iforce },
 	{ 0x046d, 0xc281, "Logitech WingMan Force",			btn_joystick, abs_joystick, ff_iforce },
 	{ 0x046d, 0xc291, "Logitech WingMan Formula Force",		btn_wheel, abs_wheel, ff_iforce },
 	{ 0x05ef, 0x020a, "AVB Top Shot Pegasus",			btn_joystick, abs_joystick, ff_iforce },
 	{ 0x05ef, 0x8884, "AVB Mag Turbo Force",			btn_wheel, abs_wheel, ff_iforce },
+	{ 0x05ef, 0x8888, "AVB Top Shot Force Feedback Racing Wheel",	btn_avb_tw, abs_wheel, ff_iforce },
+	{ 0x061c, 0xc084, "ACT LABS Force RS",                          btn_wheel, abs_wheel, ff_iforce },
 	{ 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback",	btn_wheel, abs_wheel, ff_iforce },
+	{ 0x06f8, 0x0004, "Guillemot Force Feedback Racing Wheel",	btn_wheel, abs_wheel, ff_iforce },
 	{ 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]",		btn_joystick, abs_joystick, ff_iforce }
 };
 
@@ -1061,11 +1066,15 @@
 }
 
 static struct usb_device_id iforce_usb_ids [] = {
+	{ USB_DEVICE(0x044f, 0xa01c) },		/* Thrustmaster Motor Sport GT */
 	{ USB_DEVICE(0x046d, 0xc281) },		/* Logitech WingMan Force */
 	{ USB_DEVICE(0x046d, 0xc291) },		/* Logitech WingMan Formula Force */
 	{ USB_DEVICE(0x05ef, 0x020a) },		/* AVB Top Shot Pegasus */
 	{ USB_DEVICE(0x05ef, 0x8884) },		/* AVB Mag Turbo Force */
+	{ USB_DEVICE(0x05ef, 0x8888) },		/* AVB Top Shot FFB Racing Wheel */
+	{ USB_DEVICE(0x061c, 0xc084) },         /* ACT LABS Force RS */
 	{ USB_DEVICE(0x06f8, 0x0001) },		/* Guillemot Race Leader Force Feedback */
+	{ USB_DEVICE(0x06f8, 0x0004) },		/* Guillemot Force Feedback Racing Wheel */
 	{ }					/* Terminating entry */
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/joystick/pcigame.c linux-2.4.21-pre6/drivers/char/joystick/pcigame.c
--- linux-2.4.20/drivers/char/joystick/pcigame.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/joystick/pcigame.c	2003-03-26 23:49:08.000000000 +0000
@@ -195,7 +195,7 @@
 
 int __init pcigame_init(void)
 {
-	pci_module_init(&pcigame_driver);
+	pci_register_driver(&pcigame_driver);
 	/* Needed by other modules */
 	return 0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/keyboard.c linux-2.4.21-pre6/drivers/char/keyboard.c
--- linux-2.4.20/drivers/char/keyboard.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/keyboard.c	2003-03-26 23:49:30.000000000 +0000
@@ -64,6 +64,7 @@
 void (*kbd_ledfunc)(unsigned int led);
 EXPORT_SYMBOL(handle_scancode);
 EXPORT_SYMBOL(kbd_ledfunc);
+EXPORT_SYMBOL(kbd_refresh_leds);
 
 extern void ctrl_alt_del(void);
 
@@ -94,6 +95,7 @@
 static struct tty_struct **ttytab;
 static struct kbd_struct * kbd = kbd_table;
 static struct tty_struct * tty;
+static unsigned char prev_scancode;
 
 void compute_shiftstate(void);
 
@@ -213,7 +215,17 @@
 	}
 	kbd = kbd_table + fg_console;
 	if ((raw_mode = (kbd->kbdmode == VC_RAW))) {
-		put_queue(scancode | up_flag);
+		/*
+		 *	The following is a workaround for hardware
+		 *	which sometimes send the key release event twice 
+		 */
+		unsigned char next_scancode = scancode|up_flag;
+		if (up_flag && next_scancode==prev_scancode) {
+			/* unexpected 2nd release event */
+		} else {
+			prev_scancode=next_scancode;
+			put_queue(next_scancode);
+		}
 		/* we do not return yet, because we want to maintain
 		   the key_down array, so that we have the correct
 		   values when finishing RAW mode or when changing VT's */
@@ -899,9 +911,9 @@
  * Aside from timing (which isn't really that important for
  * keyboard interrupts as they happen often), using the software
  * interrupt routines for this thing allows us to easily mask
- * this when we don't want any of the above to happen. Not yet
- * used, but this allows for easy and efficient race-condition
- * prevention later on.
+ * this when we don't want any of the above to happen.
+ * This allows for easy and efficient race-condition prevention
+ * for kbd_ledfunc => input_event(dev, EV_LED, ...) => ...
  */
 static void kbd_bh(unsigned long dummy)
 {
@@ -917,6 +929,18 @@
 EXPORT_SYMBOL(keyboard_tasklet);
 DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0);
 
+/*
+ * This allows a newly plugged keyboard to pick the LED state.
+ * We do it in this seemindly backwards fashion to ensure proper locking.
+ * Built-in keyboard does refresh on its own.
+ */
+void kbd_refresh_leds(void)
+{
+	tasklet_disable(&keyboard_tasklet);
+	if (ledstate != 0xff && kbd_ledfunc != NULL) kbd_ledfunc(ledstate);
+	tasklet_enable(&keyboard_tasklet);
+}
+
 typedef void (pm_kbd_func) (void);
 
 pm_callback pm_kbd_request_override = NULL;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/mux.c linux-2.4.21-pre6/drivers/char/mux.c
--- linux-2.4.20/drivers/char/mux.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/mux.c	2003-03-26 23:48:57.000000000 +0000
@@ -0,0 +1,638 @@
+/*
+** mux.c:
+**      MUX console for the NOVA and K-Class systems.
+**
+**	(c) Copyright 2002 Ryan Bradetich
+**	(c) Copyright 2002 Hewlett-Packard Company
+**
+** 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 used Christoph Plattner's pdc_console.c as a driver
+** template.
+**
+** This Driver currently only supports the console (port 0) on the MUX.
+** Additional work will be needed on this driver to enable the full
+** functionality of the MUX.
+**
+*/
+
+static char *mux_drv_version = "0.1";
+
+#include <linux/config.h>
+#include <linux/version.h>
+
+#undef SERIAL_PARANOIA_CHECK
+#define CONFIG_SERIAL_NOPAUSE_IO
+#define SERIAL_DO_RESTART
+
+#include <linux/module.h>
+#include <linux/serial.h>
+#include <linux/serialP.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_MAGIC_SYSRQ
+#include <linux/sysrq.h>
+static unsigned long break_pressed;
+#endif
+
+#ifdef CONFIG_GSC
+#include <asm/gsc.h>
+#endif
+
+static unsigned long hpa;
+
+#define MUX_OFFSET 0x800
+#define MUX_LINE_OFFSET 0x80
+
+#define MUX_FIFO_SIZE 255
+#define MUX_MIN_FREE_SIZE 32
+
+#define MUX_FIFO_DRAIN_DELAY 1
+#define MUX_POLL_DELAY (30 * HZ / 1000)
+
+#define IO_COMMAND_REG_OFFSET 0x30
+#define IO_STATUS_REG_OFFSET 0x34
+#define IO_DATA_REG_OFFSET 0x3c
+#define IO_DCOUNT_REG_OFFSET 0x40
+#define IO_UCOUNT_REG_OFFSET 0x44
+#define IO_FIFOS_REG_OFFSET 0x48
+
+#define MUX_EOFIFO(status) ((status & 0xF000) == 0xF000)
+#define MUX_STATUS(status) ((status & 0xF000) == 0x8000)
+#define MUX_BREAK(status) ((status & 0xF000) == 0x2000)
+
+static int mux_drv_refcount; /* = 0 */
+static struct tty_driver mux_drv_driver;
+static struct async_struct *mux_drv_info;
+static struct timer_list mux_drv_timer;
+
+#define NR_PORTS 1
+static struct tty_struct *mux_drv_table[NR_PORTS];
+static struct termios *mux_drv_termios[NR_PORTS];
+static struct termios *mux_drv_termios_locked[NR_PORTS];
+
+/**
+ * mux_read_fifo - Read chars from the mux fifo.
+ * @info: Ptr to the async structure.
+ *
+ * This reads all available data from the mux's fifo and pushes
+ * the data to the tty layer.
+ */
+static void
+mux_read_fifo(struct async_struct *info)
+{
+	int data;
+	struct tty_struct *tty = info->tty;
+
+	while(1) {
+		data = __raw_readl((unsigned long)info->iomem_base 
+				   + IO_DATA_REG_OFFSET);
+
+		if (MUX_STATUS(data))
+			continue;
+
+		if (MUX_EOFIFO(data))
+			break;
+
+		if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+			continue;
+
+		*tty->flip.char_buf_ptr = data & 0xffu;
+		*tty->flip.flag_buf_ptr = 0;
+
+#ifdef CONFIG_MAGIC_SYSRQ
+		if (MUX_BREAK(data) && !break_pressed) {
+ 			break_pressed = jiffies;
+			continue;
+		}
+
+		if(MUX_BREAK(data)) {
+			*tty->flip.flag_buf_ptr = TTY_BREAK;
+		}
+
+		if(break_pressed) {
+			if(time_before(jiffies, break_pressed + HZ * 5)) {
+				handle_sysrq(data & 0xffu, NULL, NULL, NULL);
+				break_pressed = 0;
+				continue; 
+			}
+			break_pressed = 0;
+		}
+#endif
+
+		tty->flip.flag_buf_ptr++;
+		tty->flip.char_buf_ptr++;
+		tty->flip.count++;
+	}
+
+	tty_flip_buffer_push(tty);
+}
+
+
+/**
+ * mux_drv_poll - Mux poll function.
+ * @unused: Unused variable
+ *
+ * This function periodically polls the Mux to check for new data.
+ */
+static void
+mux_drv_poll(unsigned long unused)
+{
+	struct async_struct *info = mux_drv_info;
+
+	if(info && info->tty && mux_drv_refcount) {
+		mux_read_fifo(info);
+		info->last_active = jiffies;
+	}
+
+	mod_timer(&mux_drv_timer, jiffies + MUX_POLL_DELAY);
+}
+
+/**
+ * mux_chars_in_buffer - Returns the number of chars present in the outbound fifo.
+ * @tty: Ptr to the tty structure.
+ *
+ * This function returns the number of chars sitting in the outbound fifo.
+ * [Note: This function is required for the normal_poll function in 
+ *  drivers/char/n_tty.c].
+ */
+static int
+mux_chars_in_buffer(struct tty_struct *tty)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	return __raw_readl((unsigned long)info->iomem_base 
+			   + IO_DCOUNT_REG_OFFSET);
+}
+
+/**
+ * mux_flush_buffer - Pause until the fifo is empty.
+ * @tty: Ptr to the tty structure.
+ *
+ * Since the mux fifo is self draining, this function just
+ * waits until the fifo has completely drained.
+ */
+static void
+mux_flush_buffer(struct tty_struct *tty)
+{
+	while(mux_chars_in_buffer(tty))
+		mdelay(MUX_FIFO_DRAIN_DELAY);
+}
+
+/**
+ * mux_write_room - How much room is left in the fifo.
+ * @tty: Ptr to the tty structure.
+ *
+ * This function returns how much room is in the fifo for
+ * writing.
+ */
+static int
+mux_write_room(struct tty_struct *tty)
+{
+	int room = mux_chars_in_buffer(tty);
+	if(room > MUX_FIFO_SIZE)
+		return 0;
+
+	return MUX_FIFO_SIZE - room;
+}
+
+/**
+ * mux_write - Write chars to the mux fifo.
+ * @tty: Ptr to the tty structure.
+ * @from_user: Is the buffer from user space?
+ * @buf: The buffer to write to the mux fifo.
+ * @count: The number of chars to write to the mux fifo.
+ *
+ * This function writes the data from buf to the mux fifo.
+ * [Note: we need the mux_flush_buffer() at the end of the 
+ * function, otherwise the system will wait for LONG_MAX
+ * if the fifo is not empty when the TCSETSW ioctl is called.]
+ */
+static int
+mux_write(struct tty_struct *tty, int from_user,
+	  const unsigned char *buf, int count)
+{
+	int size, len, ret = count;
+	char buffer[MUX_FIFO_SIZE], *buf_p;
+	unsigned long iomem_base = 
+		(unsigned long)((struct async_struct *)tty->driver_data)->iomem_base;
+
+	while (count) {
+		size = mux_write_room(tty);
+		len = (size < count) ? size : count;
+
+		if (from_user) {
+			copy_from_user(buffer, buf, len);
+			buf_p = buffer;
+		} else {
+			buf_p = (char *)buf;
+		}
+
+		count -= len;
+		buf += len;
+
+		if(size < MUX_MIN_FREE_SIZE)
+			mux_flush_buffer(tty);
+
+		while(len--) {
+			__raw_writel(*buf_p++, iomem_base + IO_DATA_REG_OFFSET);
+		}
+	}
+
+	mux_flush_buffer(tty);
+	return ret;
+}
+
+/**
+ * mux_break - Turn break handling on or off.
+ * @tty: Ptr to the tty structure.
+ * @break_state: break value.
+ *
+ * This function must be defined because the send_break() in
+ * drivers/char/tty_io.c requires it.  Currently the Serial Mux
+ * does nothing when this function is called.
+ */
+static void
+mux_break(struct tty_struct *tty, int break_state)
+{
+}
+
+/**
+ * get_serial_info - Return the serial structure to userspace.
+ * @info: Ptr to the async structure.
+ * @retinfo: Ptr to the users space buffer.
+ *
+ * Fill in this serial structure and return it to userspace.
+ */
+static int
+get_serial_info(struct async_struct *info,
+		struct serial_struct *retinfo)
+{
+	struct serial_struct tmp;
+
+	if (!retinfo)
+		return -EFAULT;
+
+	memset(&tmp, 0, sizeof(tmp));
+	tmp.line = info->line;
+	tmp.port = info->line;
+	tmp.flags = info->flags;
+	tmp.close_delay = info->close_delay;
+	return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
+}
+
+/**
+ * get_modem_info - Return the modem control and status signals to userspace.
+ * @info: Ptr to the async structure.
+ * @value: The return buffer.
+ *
+ * The Serial MUX driver always returns these values to userspace:
+ *      Data Terminal Ready, Carrier Detect, Clear To Send,
+ *      Request To Send.
+ *
+ */
+static int 
+get_modem_info(struct async_struct *info, unsigned int *value)
+{
+	unsigned int result = TIOCM_DTR|TIOCM_CAR|TIOCM_CTS|TIOCM_RTS;
+	return copy_to_user(value, &result, sizeof(int)) ? -EFAULT : 0;
+}
+
+/**
+ * get_lsr_info - Return line status register info to userspace.
+ * @info: Ptr to the async structure.
+ * @value: The return buffer.
+ *
+ * The Serial MUX driver always returns empty transmitter to userspace.
+ */
+static int 
+get_lsr_info(struct async_struct *info, unsigned int *value)
+{
+	unsigned int result = TIOCSER_TEMT;
+	return copy_to_user(value, &result, sizeof(int)) ? -EFAULT : 0;
+}
+
+/**
+ * mux_ioctl - Handle driver specific ioctl commands.
+ * @tty: Ptr to the tty structure.
+ * @file: Unused.
+ * @cmd: The ioctl number.
+ * @arg: The ioctl argument.
+ *
+ * This function handles ioctls specific to the Serial MUX driver,
+ * or ioctls that need driver specific information.
+ *
+ */
+static int
+mux_ioctl(struct tty_struct *tty, struct file *file,
+	  unsigned int cmd, unsigned long arg)
+{
+	struct async_struct *info = (struct async_struct *) tty->driver_data;
+
+	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+	    (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
+	    (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
+		if (tty->flags & (1 << TTY_IO_ERROR))
+			return -EIO;
+	}
+
+	switch (cmd) {
+	case TIOCMGET:
+		return get_modem_info(info, (unsigned int *) arg);
+
+	case TIOCMBIS:
+	case TIOCMBIC:
+	case TIOCMSET:
+		return 0;
+
+	case TIOCGSERIAL:
+		return get_serial_info(info, (struct serial_struct *) arg);
+
+	case TIOCSSERIAL:
+		return 0;
+
+	case TIOCSERCONFIG:
+		return 0;
+
+	case TIOCSERGETLSR:
+		return get_lsr_info(info, (unsigned int *) arg);
+
+	case TIOCSERGSTRUCT:
+		if (copy_to_user((struct async_struct *) arg,
+				 info, sizeof (struct async_struct)))
+			return -EFAULT;
+		return 0;
+
+	case TIOCMIWAIT:
+		return 0;
+
+	case TIOCGICOUNT:
+		return 0;
+
+	case TIOCSERGWILD:
+	case TIOCSERSWILD:
+		/* "setserial -W" is called in Debian boot */
+		printk("TIOCSER?WILD ioctl obsolete, ignored.\n");
+		return 0;
+
+	default:
+		return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+/**
+ * mux_close - Close the serial mux driver.
+ * @tty: Ptr to the tty structure.
+ * @filp: Unused.
+ * 
+ * This routine is called when the serial port gets closed.  First, we
+ * wait for the last remaining data to be sent.  Then, we unlink its
+ * async structure from the interrupt chain if necessary, and we free
+ * that IRQ if nothing is left in the chain.
+ */
+static void
+mux_close(struct tty_struct *tty, struct file *filp)
+{
+	struct async_struct *info = (struct async_struct *) tty->driver_data;
+
+	mux_drv_refcount--;
+	if (mux_drv_refcount > 0)
+		return;
+
+	info->flags |= ASYNC_CLOSING;
+
+	/*
+	 * Save the termios structure, since this port may have
+	 * separate termios for callout and dialin.
+	 */
+	if (info->flags & ASYNC_NORMAL_ACTIVE)
+		info->state->normal_termios = *tty->termios;
+	if (info->flags & ASYNC_CALLOUT_ACTIVE)
+		info->state->callout_termios = *tty->termios;
+
+	/*
+	 * At this point we stop accepting input.  To do this, we
+	 * disable the receive line status interrupts, and tell the
+	 * interrupt driver to stop checking the data ready bit in the
+	 * line status register.
+	 */
+
+	/* XXX CP: make mask for receive !!! */
+
+	if (tty->driver.flush_buffer)
+		tty->driver.flush_buffer(tty);
+	if (tty->ldisc.flush_buffer)
+		tty->ldisc.flush_buffer(tty);
+	tty->closing = 0;
+	info->event = 0;
+	info->tty = 0;
+	mux_drv_info = NULL;
+	if (info->blocked_open) {
+		if (info->close_delay) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(info->close_delay);
+		}
+		wake_up_interruptible(&info->open_wait);
+	}
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE |
+			 ASYNC_CLOSING);
+	wake_up_interruptible(&info->close_wait);
+	MOD_DEC_USE_COUNT;
+}
+
+/**
+ * get_async_struct - Get the async structure.
+ * @line: Minor number of the tty device.
+ * @ret_info: Ptr to the newly allocated async structure.
+ *
+ * Allocate and return an async structure for the specified
+ * tty device line.
+ */
+static int
+get_async_struct(int line, struct async_struct **ret_info)
+{
+	struct async_struct *info;
+
+	info = kmalloc(sizeof (struct async_struct), GFP_KERNEL);
+	if (!info) {
+		return -ENOMEM;
+	}
+	memset(info, 0, sizeof (struct async_struct));
+	init_waitqueue_head(&info->open_wait);
+	init_waitqueue_head(&info->close_wait);
+	init_waitqueue_head(&info->delta_msr_wait);
+	info->magic = SERIAL_MAGIC;
+	info->port = 0;
+	info->flags = 0;
+	info->io_type = 0;
+	info->iomem_base = (void *)(hpa + MUX_OFFSET);
+	info->iomem_reg_shift = 0;
+	info->xmit_fifo_size = MUX_FIFO_SIZE;
+	info->line = line;
+	info->tqueue.routine = NULL;
+	info->tqueue.data = info;
+	info->state = NULL;
+	*ret_info = info;
+	return 0;
+}
+
+/**
+ * mux_open - Open the serial mux driver.
+ * @tty: Ptr to the tty structure.
+ * @filp: Unused.
+ *
+ * This routine is called whenever a serial port is opened.  It
+ * enables interrupts for a serial port, linking in its async structure 
+ * into the IRQ chain.   It also performs the serial-specific
+ * initialization for the tty structure.
+ */
+static int
+mux_open(struct tty_struct *tty, struct file *filp)
+{
+	struct async_struct *info;
+	int retval, line;
+
+	MOD_INC_USE_COUNT;
+	line = MINOR(tty->device) - tty->driver.minor_start;
+	if ((line < 0) || (line >= NR_PORTS)) {
+		MOD_DEC_USE_COUNT;
+		return -ENODEV;
+	}
+	retval = get_async_struct(line, &info);
+	if (retval) {
+		MOD_DEC_USE_COUNT;
+		return retval;
+	}
+
+	tty->driver_data = info;
+	info->tty = tty;
+	mux_drv_info = info;
+	info->tty->low_latency = 0;
+	info->session = current->session;
+	info->pgrp = current->pgrp;
+	mux_drv_refcount++;
+	return 0;
+}
+
+/**
+ * mux_probe - Determine if the Serial Mux should claim this device.
+ * @dev: The parisc device.
+ *
+ * Deterimine if the Sserial Mux should claim this chip (return 0)
+ * or not (return 1).
+ */
+static int __init 
+mux_probe(struct parisc_device *dev)
+{
+	if(hpa) {
+		printk(KERN_INFO "Serial MUX driver already registered, skipping additonal MUXes for now.\n");
+		return 1;
+	}
+
+	init_timer(&mux_drv_timer);
+	mux_drv_timer.function = mux_drv_poll;
+	mod_timer(&mux_drv_timer, jiffies + MUX_POLL_DELAY);
+
+	hpa = dev->hpa;
+	printk(KERN_INFO "Serial MUX driver version %s at 0x%lx\n",
+	       mux_drv_version, hpa);
+
+	/* Initialize the tty_driver structure */
+
+	memset(&mux_drv_driver, 0, sizeof (struct tty_driver));
+	mux_drv_driver.magic = TTY_DRIVER_MAGIC;
+	mux_drv_driver.driver_name = "Serial MUX driver";
+#ifdef CONFIG_DEVFS_FS
+	mux_drv_driver.name = "ttb/%d";
+#else
+	mux_drv_driver.name = "ttyB";
+#endif
+	mux_drv_driver.major = MUX_MAJOR;
+	mux_drv_driver.minor_start = 0;
+	mux_drv_driver.num = NR_PORTS;
+	mux_drv_driver.type = TTY_DRIVER_TYPE_SERIAL;
+	mux_drv_driver.subtype = SERIAL_TYPE_NORMAL;
+	mux_drv_driver.init_termios = tty_std_termios;
+	mux_drv_driver.init_termios.c_cflag =
+	    B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	mux_drv_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+	mux_drv_driver.refcount = &mux_drv_refcount;
+	mux_drv_driver.table = mux_drv_table;
+	mux_drv_driver.termios = mux_drv_termios;
+	mux_drv_driver.termios_locked = mux_drv_termios_locked;
+
+	mux_drv_driver.open = mux_open;
+	mux_drv_driver.close = mux_close;
+	mux_drv_driver.write = mux_write;
+	mux_drv_driver.put_char = NULL;
+	mux_drv_driver.flush_chars = NULL;
+	mux_drv_driver.write_room = mux_write_room;
+	mux_drv_driver.chars_in_buffer = mux_chars_in_buffer;
+	mux_drv_driver.flush_buffer = mux_flush_buffer;
+	mux_drv_driver.ioctl = mux_ioctl;
+	mux_drv_driver.throttle = NULL;
+	mux_drv_driver.unthrottle = NULL;
+	mux_drv_driver.set_termios = NULL;
+	mux_drv_driver.stop = NULL;
+	mux_drv_driver.start = NULL;
+	mux_drv_driver.hangup = NULL;
+	mux_drv_driver.break_ctl = mux_break;
+	mux_drv_driver.send_xchar = NULL;
+	mux_drv_driver.wait_until_sent = NULL;
+	mux_drv_driver.read_proc = NULL;
+
+	if (tty_register_driver(&mux_drv_driver))
+		panic("Could not register the serial MUX driver\n");
+
+	return 0;
+}
+
+static struct parisc_device_id mux_tbl[] = {
+	{ HPHW_A_DIRECT, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0000D },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(parisc, mux_tbl);
+
+static struct parisc_driver mux_driver = {
+	name:		"Serial MUX driver",
+	id_table:	mux_tbl,
+	probe:		mux_probe,
+};
+
+/**
+ * mux_init - Serial MUX initalization procedure.
+ *
+ * Register the Serial MUX driver.
+ */
+static int __init mux_init(void) 
+{
+	return register_parisc_driver(&mux_driver);
+}
+
+/**
+ * mux_exit - Serial MUX cleanup procedure.
+ *
+ * Unregister the Serial MUX driver from the tty layer.
+ */
+static void __exit mux_exit(void)
+{
+	int status = tty_unregister_driver(&mux_drv_driver);
+	if(status) {
+		printk("MUX: failed to unregister the Serial MUX driver (%d)\n", status);
+	}
+}
+
+module_init(mux_init);
+module_exit(mux_exit);
+MODULE_DESCRIPTION("Serial MUX driver");
+MODULE_AUTHOR("Ryan Bradetich");
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/mwave/mwavedd.c linux-2.4.21-pre6/drivers/char/mwave/mwavedd.c
--- linux-2.4.20/drivers/char/mwave/mwavedd.c	2002-02-25 19:37:57.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/mwave/mwavedd.c	2003-03-26 23:49:20.000000000 +0000
@@ -500,7 +500,7 @@
 {
 	int i;
 	int retval = 0;
-	unsigned int resultMiscRegister;
+	int resultMiscRegister;
 	pMWAVE_DEVICE_DATA pDrvData = &mwave_s_mdd;
 
 	memset(&mwave_s_mdd, 0, sizeof(MWAVE_DEVICE_DATA));
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/n_r3964.c linux-2.4.21-pre6/drivers/char/n_r3964.c
--- linux-2.4.20/drivers/char/n_r3964.c	2001-09-13 22:21:32.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/n_r3964.c	2003-03-26 23:49:54.000000000 +0000
@@ -1364,7 +1364,7 @@
       pHeader->owner = pClient;
    }
 
-   copy_from_user (pHeader->data, data, count); /* We already verified this */
+   __copy_from_user(pHeader->data, data, count); /* We already verified this */
 
    if(pInfo->flags & R3964_DEBUG)
    {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/nvram.c linux-2.4.21-pre6/drivers/char/nvram.c
--- linux-2.4.20/drivers/char/nvram.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/nvram.c	2003-03-26 23:49:30.000000000 +0000
@@ -98,6 +98,8 @@
 #define RTC_PORT(x)		(TT_RTC_BAS + 2*(x))
 #define CHECK_DRIVER_INIT()	(MACH_IS_ATARI && ATARIHW_PRESENT(TT_CLK))
 
+#define NVRAM_BYTES		50
+
 /* On Ataris, the checksum is over all bytes except the checksum bytes
  * themselves; these are at the very end */
 #define ATARI_CKS_RANGE_START	0
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/pcmcia/serial_cs.c linux-2.4.21-pre6/drivers/char/pcmcia/serial_cs.c
--- linux-2.4.20/drivers/char/pcmcia/serial_cs.c	2001-12-21 17:41:54.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/pcmcia/serial_cs.c	2003-03-26 23:49:39.000000000 +0000
@@ -2,7 +2,7 @@
 
     A driver for PCMCIA serial devices
 
-    serial_cs.c 1.128 2001/10/18 12:18:35
+    serial_cs.c 1.138 2002/10/25 06:24:52
 
     The contents of this file are subject to the Mozilla Public
     License Version 1.1 (the "License"); you may not use this file
@@ -28,7 +28,7 @@
     and other provisions required by the GPL.  If you do not delete
     the provisions above, a recipient may use your version of this
     file under either the MPL or the GPL.
-    
+
 ======================================================================*/
 
 #include <linux/module.h>
@@ -69,14 +69,14 @@
 static int irq_list[4] = { -1 };
 MODULE_PARM(irq_list, "1-4i");
 
-/* Enable the speaker? */
-INT_MODULE_PARM(do_sound, 1);
+INT_MODULE_PARM(do_sound, 1);		/* Enable the speaker? */
+INT_MODULE_PARM(buggy_uart, 0);		/* Skip strict UART tests? */
 
 #ifdef PCMCIA_DEBUG
 INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
 static char *version =
-"serial_cs.c 1.128 2001/10/18 12:18:35 (David Hinds)";
+"serial_cs.c 1.138 2002/10/25 06:24:52 (David Hinds)";
 #else
 #define DEBUG(n, args...)
 #endif
@@ -95,6 +95,7 @@
     { MANFID_OMEGA, PRODID_OMEGA_QSP_100, 4 },
     { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232, 2 },
     { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D1, 2 },
+    { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D2, 2 },
     { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS232, 4 },
     { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS422, 2 },
     { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS422, 4 },
@@ -148,7 +149,7 @@
     client_reg_t client_reg;
     dev_link_t *link;
     int i, ret;
-    
+
     DEBUG(0, "serial_attach()\n");
 
     /* Create new serial device */
@@ -160,7 +161,7 @@
     link->release.function = &serial_release;
     link->release.data = (u_long)link;
     link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-    link->io.NumPorts1 = 8;
+    link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
     link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
     link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
     if (irq_list[0] == -1)
@@ -169,13 +170,12 @@
 	for (i = 0; i < 4; i++)
 	    link->irq.IRQInfo2 |= 1 << irq_list[i];
     link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.Vcc = 50;
     if (do_sound) {
 	link->conf.Attributes |= CONF_ENABLE_SPKR;
 	link->conf.Status = CCSR_AUDIO_ENA;
     }
     link->conf.IntType = INT_MEMORY_AND_IO;
-    
+
     /* Register with Card Services */
     link->next = dev_list;
     dev_list = link;
@@ -194,7 +194,7 @@
 	serial_detach(link);
 	return NULL;
     }
-    
+
     return link;
 } /* serial_attach */
 
@@ -214,7 +214,7 @@
     int ret;
 
     DEBUG(0, "serial_detach(0x%p)\n", link);
-    
+
     /* Locate device structure */
     for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
 	if (*linkp == link) break;
@@ -224,17 +224,17 @@
     del_timer(&link->release);
     if (link->state & DEV_CONFIG)
 	serial_release((u_long)link);
-    
+
     if (link->handle) {
 	ret = CardServices(DeregisterClient, link->handle);
 	if (ret != CS_SUCCESS)
 	    cs_error(link->handle, DeregisterClient, ret);
     }
-    
+
     /* Unlink device structure, free bits */
     *linkp = link->next;
     kfree(info);
-    
+
 } /* serial_detach */
 
 /*====================================================================*/
@@ -243,18 +243,20 @@
 {
     struct serial_struct serial;
     int line;
-    
+
     memset(&serial, 0, sizeof(serial));
     serial.port = port;
     serial.irq = irq;
     serial.flags = ASYNC_SKIP_TEST | ASYNC_SHARE_IRQ;
+    if (buggy_uart)
+	serial.flags |= ASYNC_BUGGY_UART;
     line = register_serial(&serial);
     if (line < 0) {
 	printk(KERN_NOTICE "serial_cs: register_serial() at 0x%04lx,"
 	       " irq %d failed\n", (u_long)serial.port, serial.irq);
 	return -1;
     }
-    
+
     info->line[info->ndev] = line;
     sprintf(info->node[info->ndev].dev_name, "ttyS%d", line);
     info->node[info->ndev].major = TTY_MAJOR;
@@ -262,7 +264,7 @@
     if (info->ndev > 0)
 	info->node[info->ndev-1].next = &info->node[info->ndev];
     info->ndev++;
-    
+
     return 0;
 }
 
@@ -313,7 +315,10 @@
 	    return setup_serial(info, port, config.AssignedIRQ);
     }
     link->conf.Vcc = config.Vcc;
-    
+
+    link->io.NumPorts1 = 8;
+    link->io.NumPorts2 = 0;
+
     /* First pass: look for a config entry that looks normal. */
     tuple.TupleData = (cisdata_t *)buf;
     tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
@@ -340,7 +345,7 @@
 	    i = next_tuple(handle, &tuple, &parse);
 	}
     }
-    
+
     /* Second pass: try to find an entry that isn't picky about
        its base address, then try to grab any standard serial port
        address, and finally try to get any free port. */
@@ -352,8 +357,7 @@
 	    for (j = 0; j < 5; j++) {
 		link->io.BasePort1 = base[j];
 		link->io.IOAddrLines = base[j] ? 16 : 3;
-		i = CardServices(RequestIO, link->handle,
-				 &link->io);
+		i = CardServices(RequestIO, link->handle, &link->io);
 		if (i == CS_SUCCESS) goto found_port;
 	    }
 	}
@@ -365,7 +369,7 @@
 	cs_error(link->handle, RequestIO, i);
 	return -1;
     }
-    
+
     i = CardServices(RequestIRQ, link->handle, &link->irq);
     if (i != CS_SUCCESS) {
 	cs_error(link->handle, RequestIRQ, i);
@@ -390,8 +394,12 @@
     u_char buf[256];
     cisparse_t parse;
     cistpl_cftable_entry_t *cf = &parse.cftable_entry;
+    config_info_t config;
     int i, base2 = 0;
 
+    CardServices(GetConfigurationInfo, handle, &config);
+    link->conf.Vcc = config.Vcc;
+
     tuple.TupleData = (cisdata_t *)buf;
     tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
     tuple.Attributes = 0;
@@ -433,12 +441,12 @@
 	    i = next_tuple(handle, &tuple, &parse);
 	}
     }
-    
+
     if (i != CS_SUCCESS) {
-	cs_error(link->handle, RequestIO, i);
-	return -1;
+	/* At worst, try to configure as a single port */
+	return simple_config(link);
     }
-    
+
     i = CardServices(RequestIRQ, link->handle, &link->irq);
     if (i != CS_SUCCESS) {
 	cs_error(link->handle, RequestIRQ, i);
@@ -454,14 +462,27 @@
 	cs_error(link->handle, RequestConfiguration, i);
 	return -1;
     }
-    
+
+    /* The Oxford Semiconductor OXCF950 cards are in fact single-port:
+       8 registers are for the UART, the others are extra registers */
+    if (info->manfid == MANFID_OXSEMI) {
+	if (cf->index == 1 || cf->index == 3) {
+	    setup_serial(info, base2, link->irq.AssignedIRQ);
+	    outb(12,link->io.BasePort1+1);
+	} else {
+	    setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ);
+	    outb(12,base2+1);
+	}
+	return 0;
+    }
+
     setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ);
     /* The Nokia cards are not really multiport cards */
     if (info->manfid == MANFID_NOKIA)
 	return 0;
     for (i = 0; i < info->multi-1; i++)
 	setup_serial(info, base2+(8*i), link->irq.AssignedIRQ);
-    
+
     return 0;
 }
 
@@ -487,7 +508,7 @@
     int i, last_ret, last_fn;
 
     DEBUG(0, "serial_config(0x%p)\n", link);
-    
+
     tuple.TupleData = (cisdata_t *)buf;
     tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
     tuple.Attributes = 0;
@@ -500,7 +521,7 @@
     }
     link->conf.ConfigBase = parse.config.base;
     link->conf.Present = parse.config.rmask[0];
-    
+
     /* Configure card */
     link->state |= DEV_CONFIG;
 
@@ -508,8 +529,8 @@
     tuple.DesiredTuple = CISTPL_LONGLINK_MFC;
     tuple.Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK;
     info->multi = (first_tuple(handle, &tuple, &parse) == CS_SUCCESS);
-    
-    /* Is this a multiport card? */
+
+    /* Scan list of known multiport card ID's */
     tuple.DesiredTuple = CISTPL_MANFID;
     if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) {
 	info->manfid = le16_to_cpu(buf[0]);
@@ -537,15 +558,15 @@
 		info->multi = 2;
 	}
     }
-    
+
     if (info->multi > 1)
 	multi_config(link);
     else
 	simple_config(link);
-    
+
     if (info->ndev == 0)
 	goto failed;
-    
+
     if (info->manfid == MANFID_IBM) {
 	conf_reg_t reg = { 0, CS_READ, 0x800, 0 };
 	CS_CHECK(AccessConfigurationRegister, link->handle, &reg);
@@ -562,6 +583,7 @@
     cs_error(link->handle, last_fn, last_ret);
 failed:
     serial_release((u_long)link);
+    link->state &= ~DEV_CONFIG_PENDING;
 
 } /* serial_config */
 
@@ -569,7 +591,7 @@
 
     After a card is removed, serial_release() will unregister the net
     device, and release the PCMCIA configuration.
-    
+
 ======================================================================*/
 
 void serial_release(u_long arg)
@@ -577,7 +599,7 @@
     dev_link_t *link = (dev_link_t *)arg;
     serial_info_t *info = link->priv;
     int i;
-    
+
     DEBUG(0, "serial_release(0x%p)\n", link);
 
     for (i = 0; i < info->ndev; i++) {
@@ -590,7 +612,7 @@
 	CardServices(ReleaseIO, link->handle, &link->io);
 	CardServices(ReleaseIRQ, link->handle, &link->irq);
     }
-    
+
     link->state &= ~DEV_CONFIG;
 
 } /* serial_release */
@@ -601,7 +623,7 @@
     stuff to run after an event is received.  A CARD_REMOVAL event
     also sets some flags to discourage the serial drivers from
     talking to the ports.
-    
+
 ======================================================================*/
 
 static int serial_event(event_t event, int priority,
@@ -609,9 +631,9 @@
 {
     dev_link_t *link = args->client_data;
     serial_info_t *info = link->priv;
-    
+
     DEBUG(1, "serial_event(0x%06x)\n", event);
-    
+
     switch (event) {
     case CS_EVENT_CARD_REMOVAL:
 	link->state &= ~DEV_PRESENT;
@@ -650,7 +672,7 @@
     if (serv.Revision != CS_RELEASE_CODE) {
 	printk(KERN_NOTICE "serial_cs: Card Services release "
 	       "does not match!\n");
-	return -1;
+	return -EINVAL;
     }
     register_pccard_driver(&dev_info, &serial_attach, &serial_detach);
     return 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/pdc_console.c linux-2.4.21-pre6/drivers/char/pdc_console.c
--- linux-2.4.20/drivers/char/pdc_console.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/pdc_console.c	2003-03-26 23:49:35.000000000 +0000
@@ -625,7 +625,7 @@
 #else
 	pdc_drv_driver.name = "ttyB";
 #endif
-	pdc_drv_driver.major = PDCCONS_MAJOR;
+	pdc_drv_driver.major = MUX_MAJOR;
 	pdc_drv_driver.minor_start = 0;
 	pdc_drv_driver.num = NR_PORTS;
 	pdc_drv_driver.type = TTY_DRIVER_TYPE_SERIAL;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/qtronix.c linux-2.4.21-pre6/drivers/char/qtronix.c
--- linux-2.4.20/drivers/char/qtronix.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/qtronix.c	2003-03-26 23:49:29.000000000 +0000
@@ -587,7 +587,12 @@
 
 static int __init psaux_init(void)
 {
-	misc_register(&psaux_mouse);
+	int retval;
+
+	retval = misc_register(&psaux_mouse);
+	if(retval < 0)
+		return retval;
+
 	queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
 	memset(queue, 0, sizeof(*queue));
 	queue->head = queue->tail = 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/random.c linux-2.4.21-pre6/drivers/char/random.c
--- linux-2.4.20/drivers/char/random.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/random.c	2003-03-26 23:49:00.000000000 +0000
@@ -2035,56 +2035,102 @@
 
 /* This should not be decreased so low that ISNs wrap too fast. */
 #define REKEY_INTERVAL	300
-#define HASH_BITS 24
+/*
+ * Bit layout of the tcp sequence numbers (before adding current time):
+ * bit 24-31: increased after every key exchange
+ * bit 0-23: hash(source,dest)
+ *
+ * The implementation is similar to the algorithm described
+ * in the Appendix of RFC 1185, except that
+ * - it uses a 1 MHz clock instead of a 250 kHz clock
+ * - it performs a rekey every 5 minutes, which is equivalent
+ * 	to a (source,dest) tulple dependent forward jump of the
+ * 	clock by 0..2^(HASH_BITS+1)
+ *
+ * Thus the average ISN wraparound time is 68 minutes instead of
+ * 4.55 hours.
+ *
+ * SMP cleanup and lock avoidance with poor man's RCU.
+ * 			Manfred Spraul <manfred@colorfullife.com>
+ * 		
+ */
+#define COUNT_BITS	8
+#define COUNT_MASK	( (1<<COUNT_BITS)-1)
+#define HASH_BITS	24
+#define HASH_MASK	( (1<<HASH_BITS)-1 )
+
+static struct keydata {
+	time_t rekey_time;
+	__u32	count;		// already shifted to the final position
+	__u32	secret[12];
+} ____cacheline_aligned ip_keydata[2];
+
+static spinlock_t ip_lock = SPIN_LOCK_UNLOCKED;
+static unsigned int ip_cnt;
+
+static struct keydata *__check_and_rekey(time_t time)
+{
+	struct keydata *keyptr;
+	spin_lock(&ip_lock);
+	keyptr = &ip_keydata[ip_cnt&1];
+	if (!keyptr->rekey_time || (time - keyptr->rekey_time) > REKEY_INTERVAL) {
+		keyptr = &ip_keydata[1^(ip_cnt&1)];
+		keyptr->rekey_time = time;
+		get_random_bytes(keyptr->secret, sizeof(keyptr->secret));
+		keyptr->count = (ip_cnt&COUNT_MASK)<<HASH_BITS;
+		mb();
+		ip_cnt++;
+	}
+	spin_unlock(&ip_lock);
+	return keyptr;
+}
+
+static inline struct keydata *check_and_rekey(time_t time)
+{
+	struct keydata *keyptr = &ip_keydata[ip_cnt&1];
+
+	rmb();
+	if (!keyptr->rekey_time || (time - keyptr->rekey_time) > REKEY_INTERVAL) {
+		keyptr = __check_and_rekey(time);
+	}
+
+	return keyptr;
+}
 
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 __u32 secure_tcpv6_sequence_number(__u32 *saddr, __u32 *daddr,
 				   __u16 sport, __u16 dport)
 {
-	static __u32	rekey_time;
-	static __u32	count;
-	static __u32	secret[12];
 	struct timeval 	tv;
 	__u32		seq;
+	__u32		hash[12];
+	struct keydata *keyptr;
 
-	/* The procedure is the same as for IPv4, but addresses are longer. */
+	/* The procedure is the same as for IPv4, but addresses are longer.
+	 * Thus we must use twothirdsMD4Transform.
+	 */
 
 	do_gettimeofday(&tv);	/* We need the usecs below... */
+	keyptr = check_and_rekey(tv.tv_sec);
 
-	if (!rekey_time || (tv.tv_sec - rekey_time) > REKEY_INTERVAL) {
-		rekey_time = tv.tv_sec;
-		/* First five words are overwritten below. */
-		get_random_bytes(&secret[5], sizeof(secret)-5*4);
-		count = (tv.tv_sec/REKEY_INTERVAL) << HASH_BITS;
-	}
-
-	memcpy(secret, saddr, 16);
-	secret[4]=(sport << 16) + dport;
-
-	seq = (twothirdsMD4Transform(daddr, secret) &
-	       ((1<<HASH_BITS)-1)) + count;
+	memcpy(hash, saddr, 16);
+	hash[4]=(sport << 16) + dport;
+	memcpy(&hash[5],keyptr->secret,sizeof(__u32)*7);
 
+	seq = twothirdsMD4Transform(daddr, hash) & HASH_MASK;
+	seq += keyptr->count;
 	seq += tv.tv_usec + tv.tv_sec*1000000;
+
 	return seq;
 }
 
 __u32 secure_ipv6_id(__u32 *daddr)
 {
-	static time_t	rekey_time;
-	static __u32	secret[12];
-	time_t		t;
+	struct keydata *keyptr;
 
-	/*
-	 * Pick a random secret every REKEY_INTERVAL seconds.
-	 */
-	t = CURRENT_TIME;
-	if (!rekey_time || (t - rekey_time) > REKEY_INTERVAL) {
-		rekey_time = t;
-		/* First word is overwritten below. */
-		get_random_bytes(secret, sizeof(secret));
-	}
+	keyptr = check_and_rekey(CURRENT_TIME);
 
-	return twothirdsMD4Transform(daddr, secret);
+	return halfMD4Transform(daddr, keyptr->secret);
 }
 
 #endif
@@ -2093,40 +2139,30 @@
 __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr,
 				 __u16 sport, __u16 dport)
 {
-	static __u32	rekey_time;
-	static __u32	count;
-	static __u32	secret[12];
 	struct timeval 	tv;
 	__u32		seq;
+	__u32	hash[4];
+	struct keydata *keyptr;
 
 	/*
 	 * Pick a random secret every REKEY_INTERVAL seconds.
 	 */
 	do_gettimeofday(&tv);	/* We need the usecs below... */
-
-	if (!rekey_time || (tv.tv_sec - rekey_time) > REKEY_INTERVAL) {
-		rekey_time = tv.tv_sec;
-		/* First three words are overwritten below. */
-		get_random_bytes(&secret[3], sizeof(secret)-12);
-		count = (tv.tv_sec/REKEY_INTERVAL) << HASH_BITS;
-	}
+	keyptr = check_and_rekey(tv.tv_sec);
 
 	/*
 	 *  Pick a unique starting offset for each TCP connection endpoints
 	 *  (saddr, daddr, sport, dport).
-	 *  Note that the words are placed into the first words to be
-	 *  mixed in with the halfMD4.  This is because the starting
-	 *  vector is also a random secret (at secret+8), and further
-	 *  hashing fixed data into it isn't going to improve anything,
-	 *  so we should get started with the variable data.
-	 */
-	secret[0]=saddr;
-	secret[1]=daddr;
-	secret[2]=(sport << 16) + dport;
-
-	seq = (halfMD4Transform(secret+8, secret) &
-	       ((1<<HASH_BITS)-1)) + count;
+	 *  Note that the words are placed into the starting vector, which is 
+	 *  then mixed with a partial MD4 over random data.
+	 */
+	hash[0]=saddr;
+	hash[1]=daddr;
+	hash[2]=(sport << 16) + dport;
+	hash[3]=keyptr->secret[11];
 
+	seq = halfMD4Transform(hash, keyptr->secret) & HASH_MASK;
+	seq += keyptr->count;
 	/*
 	 *	As close as possible to RFC 793, which
 	 *	suggests using a 250 kHz clock.
@@ -2148,31 +2184,22 @@
  */
 __u32 secure_ip_id(__u32 daddr)
 {
-	static time_t	rekey_time;
-	static __u32	secret[12];
-	time_t		t;
+	struct keydata *keyptr;
+	__u32 hash[4];
 
-	/*
-	 * Pick a random secret every REKEY_INTERVAL seconds.
-	 */
-	t = CURRENT_TIME;
-	if (!rekey_time || (t - rekey_time) > REKEY_INTERVAL) {
-		rekey_time = t;
-		/* First word is overwritten below. */
-		get_random_bytes(secret+1, sizeof(secret)-4);
-	}
+	keyptr = check_and_rekey(CURRENT_TIME);
 
 	/*
 	 *  Pick a unique starting offset for each IP destination.
-	 *  Note that the words are placed into the first words to be
-	 *  mixed in with the halfMD4.  This is because the starting
-	 *  vector is also a random secret (at secret+8), and further
-	 *  hashing fixed data into it isn't going to improve anything,
-	 *  so we should get started with the variable data.
+	 *  The dest ip address is placed in the starting vector,
+	 *  which is then hashed with random data.
 	 */
-	secret[0]=daddr;
+	hash[0] = daddr;
+	hash[1] = keyptr->secret[9];
+	hash[2] = keyptr->secret[10];
+	hash[3] = keyptr->secret[11];
 
-	return halfMD4Transform(secret+8, secret);
+	return halfMD4Transform(hash, keyptr->secret);
 }
 
 #ifdef CONFIG_SYN_COOKIES
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/raw.c linux-2.4.21-pre6/drivers/char/raw.c
--- linux-2.4.20/drivers/char/raw.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/raw.c	2003-03-26 23:49:00.000000000 +0000
@@ -170,7 +170,7 @@
 {
 	int minor = minor(inode->i_rdev), err; 
 	struct block_device *b; 
-	if (minor < 1 && minor > 255)
+	if (minor < 1 || minor > 255)
 		return -ENODEV;
 
 	b = raw_devices[minor].binding;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/rtc.c linux-2.4.21-pre6/drivers/char/rtc.c
--- linux-2.4.20/drivers/char/rtc.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/rtc.c	2003-03-26 23:49:30.000000000 +0000
@@ -74,6 +74,7 @@
 #include <asm/system.h>
 
 #ifdef __sparc__
+#include <linux/pci.h>
 #include <asm/ebus.h>
 #ifdef __sparc_v9__
 #include <asm/isa.h>
@@ -383,22 +384,18 @@
 		min = alm_tm.tm_min;
 		sec = alm_tm.tm_sec;
 
-		if (hrs >= 24)
-			hrs = 0xff;
-
-		if (min >= 60)
-			min = 0xff;
-
-		if (sec >= 60)
-			sec = 0xff;
-
 		spin_lock_irq(&rtc_lock);
 		if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) ||
 		    RTC_ALWAYS_BCD)
 		{
-			BIN_TO_BCD(sec);
-			BIN_TO_BCD(min);
-			BIN_TO_BCD(hrs);
+			if (sec < 60) BIN_TO_BCD(sec);
+			else sec = 0xff;
+
+			if (min < 60) BIN_TO_BCD(min);
+			else min = 0xff;
+
+			if (hrs < 24) BIN_TO_BCD(hrs);
+			else hrs = 0xff;
 		}
 		CMOS_WRITE(hrs, RTC_HOURS_ALARM);
 		CMOS_WRITE(min, RTC_MINUTES_ALARM);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/scx200.c linux-2.4.21-pre6/drivers/char/scx200.c
--- linux-2.4.20/drivers/char/scx200.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/scx200.c	2003-03-26 23:49:54.000000000 +0000
@@ -0,0 +1,128 @@
+/* linux/drivers/char/scx200.c 
+
+   Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
+
+   National Semiconductor SCx200 support. */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#include <linux/scx200.h>
+#include <linux/scx200.h>
+
+#define NAME "scx200"
+
+MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
+MODULE_DESCRIPTION("NatSemi SCx200 Driver");
+MODULE_LICENSE("GPL");
+
+unsigned scx200_gpio_base = 0;
+long scx200_gpio_shadow[2];
+
+spinlock_t scx200_gpio_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t scx200_gpio_config_lock = SPIN_LOCK_UNLOCKED;
+
+u32 scx200_gpio_configure(int index, u32 mask, u32 bits)
+{
+	u32 config, new_config;
+	unsigned long flags;
+
+	spin_lock_irqsave(&scx200_gpio_config_lock, flags);
+
+	outl(index, scx200_gpio_base + 0x20);
+	config = inl(scx200_gpio_base + 0x24);
+
+	new_config = (config & mask) | bits;
+	outl(new_config, scx200_gpio_base + 0x24);
+
+	spin_unlock_irqrestore(&scx200_gpio_config_lock, flags);
+
+	return config;
+}
+
+void scx200_gpio_dump(unsigned index)
+{
+	u32 config = scx200_gpio_configure(index, ~0, 0);
+	printk(KERN_DEBUG "GPIO%02u: 0x%08lx", index, (unsigned long)config);
+	
+	if (config & 1) 
+		printk(" OE"); /* output enabled */
+	else
+		printk(" TS"); /* tristate */
+	if (config & 2) 
+		printk(" PP"); /* push pull */
+	else
+		printk(" OD"); /* open drain */
+	if (config & 4) 
+		printk(" PUE"); /* pull up enabled */
+	else
+		printk(" PUD"); /* pull up disabled */
+	if (config & 8) 
+		printk(" LOCKED"); /* locked */
+	if (config & 16) 
+		printk(" LEVEL"); /* level input */
+	else
+		printk(" EDGE"); /* edge input */
+	if (config & 32) 
+		printk(" HI"); /* trigger on rising edge */
+	else
+		printk(" LO"); /* trigger on falling edge */
+	if (config & 64) 
+		printk(" DEBOUNCE"); /* debounce */
+	printk("\n");
+}
+
+int __init scx200_init(void)
+{
+	struct pci_dev *bridge;
+	int bank;
+	unsigned base;
+
+	printk(KERN_INFO NAME ": NatSemi SCx200 Driver\n");
+
+	if ((bridge = pci_find_device(PCI_VENDOR_ID_NS, 
+				      PCI_DEVICE_ID_NS_SCx200_BRIDGE,
+				      NULL)) == NULL)
+		return -ENODEV;
+
+	base = pci_resource_start(bridge, 0);
+	printk(KERN_INFO NAME ": GPIO base 0x%x\n", base);
+
+	if (request_region(base, SCx200_GPIO_SIZE, "NatSemi SCx200 GPIO") == 0) {
+		printk(KERN_ERR NAME ": can't allocate I/O for GPIOs\n");
+		return -EBUSY;
+	}
+
+	scx200_gpio_base = base;
+
+	/* read the current values driven on the GPIO signals */
+	for (bank = 0; bank < 2; ++bank)
+		scx200_gpio_shadow[bank] = inl(scx200_gpio_base + 0x10 * bank);
+
+	return 0;
+}
+
+void __exit scx200_cleanup(void)
+{
+	release_region(scx200_gpio_base, SCx200_GPIO_SIZE);
+}
+
+module_init(scx200_init);
+module_exit(scx200_cleanup);
+
+EXPORT_SYMBOL(scx200_gpio_base);
+EXPORT_SYMBOL(scx200_gpio_shadow);
+EXPORT_SYMBOL(scx200_gpio_lock);
+EXPORT_SYMBOL(scx200_gpio_configure);
+EXPORT_SYMBOL(scx200_gpio_dump);
+
+/*
+    Local variables:
+        compile-command: "make -k -C ../../.. SUBDIRS=arch/i386/kernel modules"
+        c-basic-offset: 8
+    End:
+*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/scx200_gpio.c linux-2.4.21-pre6/drivers/char/scx200_gpio.c
--- linux-2.4.20/drivers/char/scx200_gpio.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/scx200_gpio.c	2003-03-26 23:49:54.000000000 +0000
@@ -0,0 +1,154 @@
+/* linux/drivers/char/scx200_gpio.c 
+
+   National Semiconductor SCx200 GPIO driver.  Allows a user space
+   process to play with the GPIO pins.
+
+   Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com> */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#include <linux/scx200_gpio.h>
+
+#define NAME "scx200_gpio"
+
+MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
+MODULE_DESCRIPTION("NatSemi SCx200 GPIO Pin Driver");
+MODULE_LICENSE("GPL");
+
+static int major = 0;		/* default to dynamic major */
+MODULE_PARM(major, "i");
+MODULE_PARM_DESC(major, "Major device number");
+
+static ssize_t scx200_gpio_write(struct file *file, const char *data, 
+				 size_t len, loff_t *ppos)
+{
+	unsigned m = minor(file->f_dentry->d_inode->i_rdev);
+	size_t i;
+
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	for (i = 0; i < len; ++i) {
+		char c;
+		if (get_user(c, data+i))
+			return -EFAULT;
+		switch (c)
+		{
+		case '0': 
+			scx200_gpio_set(m, 0); 
+			break;
+		case '1': 
+			scx200_gpio_set(m, 1); 
+			break;
+		case 'O':
+			printk(KERN_INFO NAME ": GPIO%d output enabled\n", m);
+			scx200_gpio_configure(m, ~1, 1);
+			break;
+		case 'o':
+			printk(KERN_INFO NAME ": GPIO%d output disabled\n", m);
+			scx200_gpio_configure(m, ~1, 0);
+			break;
+		case 'T':
+			printk(KERN_INFO NAME ": GPIO%d output is push pull\n", m);
+			scx200_gpio_configure(m, ~2, 2);
+			break;
+		case 't':
+			printk(KERN_INFO NAME ": GPIO%d output is open drain\n", m);
+			scx200_gpio_configure(m, ~2, 0);
+			break;
+		case 'P':
+			printk(KERN_INFO NAME ": GPIO%d pull up enabled\n", m);
+			scx200_gpio_configure(m, ~4, 4);
+			break;
+		case 'p':
+			printk(KERN_INFO NAME ": GPIO%d pull up disabled\n", m);
+			scx200_gpio_configure(m, ~4, 0);
+			break;
+		}
+	}
+
+	return len;
+}
+
+static ssize_t scx200_gpio_read(struct file *file, char *buf,
+				size_t len, loff_t *ppos)
+{
+	unsigned m = minor(file->f_dentry->d_inode->i_rdev);
+	int value;
+
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	value = scx200_gpio_get(m);
+	if (put_user(value ? '1' : '0', buf))
+		return -EFAULT;
+	
+	return 1;
+}
+
+static int scx200_gpio_open(struct inode *inode, struct file *file)
+{
+	unsigned m = minor(inode->i_rdev);
+	if (m > 63)
+		return -EINVAL;
+	return 0;
+}
+
+static int scx200_gpio_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+
+static struct file_operations scx200_gpio_fops = {
+	.owner   = THIS_MODULE,
+	.write   = scx200_gpio_write,
+	.read    = scx200_gpio_read,
+	.open    = scx200_gpio_open,
+	.release = scx200_gpio_release,
+};
+
+static int __init scx200_gpio_init(void)
+{
+	int r;
+
+	printk(KERN_DEBUG NAME ": NatSemi SCx200 GPIO Driver\n");
+
+	if (!scx200_gpio_present()) {
+		printk(KERN_ERR NAME ": no SCx200 gpio pins available\n");
+		return -ENODEV;
+	}
+
+	r = register_chrdev(major, NAME, &scx200_gpio_fops);
+	if (r < 0) {
+		printk(KERN_ERR NAME ": unable to register character device\n");
+		return r;
+	}
+	if (!major) {
+		major = r;
+		printk(KERN_DEBUG NAME ": got dynamic major %d\n", major);
+	}
+
+	return 0;
+}
+
+static void __exit scx200_gpio_cleanup(void)
+{
+	unregister_chrdev(major, NAME);
+}
+
+module_init(scx200_gpio_init);
+module_exit(scx200_gpio_cleanup);
+
+/*
+    Local variables:
+        compile-command: "make -k -C ../.. SUBDIRS=drivers/char modules"
+        c-basic-offset: 8
+    End:
+*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/scx200_wdt.c linux-2.4.21-pre6/drivers/char/scx200_wdt.c
--- linux-2.4.20/drivers/char/scx200_wdt.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/scx200_wdt.c	2003-03-26 23:49:29.000000000 +0000
@@ -0,0 +1,277 @@
+/* linux/drivers/char/scx200_wdt.c 
+
+   National Semiconductor SCx200 Watchdog support
+
+   Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
+
+   Som code taken from:
+   National Semiconductor PC87307/PC97307 (ala SC1200) WDT driver
+   (c) Copyright 2002 Zwane Mwaikambo <zwane@commfireservices.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.
+
+   The author(s) of this software shall not be held liable for damages
+   of any nature resulting due to the use of this software. This
+   software is provided AS-IS with no warranties. */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/pci.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#include <linux/scx200.h>
+
+#define NAME "scx200_wdt"
+
+MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
+MODULE_DESCRIPTION("NatSemi SCx200 Watchdog Driver");
+MODULE_LICENSE("GPL");
+
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+#define CONFIG_WATCHDOG_NOWAYOUT 0
+#endif
+
+static int margin = 60;		/* in seconds */
+MODULE_PARM(margin, "i");
+MODULE_PARM_DESC(margin, "Watchdog margin in seconds");
+
+static int nowayout = CONFIG_WATCHDOG_NOWAYOUT;
+MODULE_PARM(nowayout, "i");
+MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
+
+static u16 wdto_restart;
+static struct semaphore open_semaphore;
+static unsigned expect_close;
+
+/* Bits of the WDCNFG register */
+#define W_ENABLE 0x00fa		/* Enable watchdog */
+#define W_DISABLE 0x0000	/* Disable watchdog */
+
+/* The scaling factor for the timer, this depends on the value of W_ENABLE */
+#define W_SCALE (32768/1024)
+
+static void scx200_wdt_ping(void)
+{
+	outw(wdto_restart, SCx200_CB_BASE + SCx200_WDT_WDTO);
+}
+
+static void scx200_wdt_update_margin(void)
+{
+	printk(KERN_INFO NAME ": timer margin %d seconds\n", margin);
+	wdto_restart = margin * W_SCALE;
+}
+
+static void scx200_wdt_enable(void)
+{
+	printk(KERN_DEBUG NAME ": enabling watchdog timer, wdto_restart = %d\n", 
+	       wdto_restart);
+
+	outw(0, SCx200_CB_BASE + SCx200_WDT_WDTO);
+	outb(SCx200_WDT_WDSTS_WDOVF, SCx200_CB_BASE + SCx200_WDT_WDSTS);
+	outw(W_ENABLE, SCx200_CB_BASE + SCx200_WDT_WDCNFG);
+
+	scx200_wdt_ping();
+}
+
+static void scx200_wdt_disable(void)
+{
+	printk(KERN_DEBUG NAME ": disabling watchdog timer\n");
+		
+	outw(0, SCx200_CB_BASE + SCx200_WDT_WDTO);
+	outb(SCx200_WDT_WDSTS_WDOVF, SCx200_CB_BASE + SCx200_WDT_WDSTS);
+	outw(W_DISABLE, SCx200_CB_BASE + SCx200_WDT_WDCNFG);
+}
+
+static int scx200_wdt_open(struct inode *inode, struct file *file)
+{
+        /* only allow one at a time */
+        if (down_trylock(&open_semaphore))
+                return -EBUSY;
+	scx200_wdt_enable();
+	expect_close = 0;
+
+	return 0;
+}
+
+static int scx200_wdt_release(struct inode *inode, struct file *file)
+{
+	if (!expect_close) {
+		printk(KERN_WARNING NAME ": watchdog device closed unexpectedly, will not disable the watchdog timer\n");
+	} else if (!nowayout) {
+		scx200_wdt_disable();
+	}
+        up(&open_semaphore);
+
+	return 0;
+}
+
+static int scx200_wdt_notify_sys(struct notifier_block *this, 
+				      unsigned long code, void *unused)
+{
+        if (code == SYS_HALT || code == SYS_POWER_OFF)
+		if (!nowayout)
+			scx200_wdt_disable();
+
+        return NOTIFY_DONE;
+}
+
+static struct notifier_block scx200_wdt_notifier =
+{
+        notifier_call: scx200_wdt_notify_sys
+};
+
+static ssize_t scx200_wdt_write(struct file *file, const char *data, 
+				     size_t len, loff_t *ppos)
+{
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	/* check for a magic close character */
+	if (len) 
+	{
+		size_t i;
+
+		scx200_wdt_ping();
+
+		expect_close = 0;
+		for (i = 0; i < len; ++i) {
+			char c;
+			if (get_user(c, data+i))
+				return -EFAULT;
+			if (c == 'V')
+				expect_close = 1;
+		}
+
+		return len;
+	}
+
+	return 0;
+}
+
+static int scx200_wdt_ioctl(struct inode *inode, struct file *file,
+	unsigned int cmd, unsigned long arg)
+{
+	static struct watchdog_info ident = {
+		.identity = "NatSemi SCx200 Watchdog",
+		.firmware_version = 1, 
+		.options = (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING),
+	};
+	int new_margin;
+	
+	switch (cmd) {
+	default:
+		return -ENOTTY;
+	case WDIOC_GETSUPPORT:
+		if(copy_to_user((struct watchdog_info *)arg, &ident, 
+				sizeof(ident)))
+			return -EFAULT;
+		return 0;
+	case WDIOC_GETSTATUS:
+	case WDIOC_GETBOOTSTATUS:
+		if (put_user(0, (int *)arg))
+			return -EFAULT;
+		return 0;
+	case WDIOC_KEEPALIVE:
+		scx200_wdt_ping();
+		return 0;
+	case WDIOC_SETTIMEOUT:
+		if (get_user(new_margin, (int *)arg))
+			return -EFAULT;
+		if (new_margin < 1)
+			return -EINVAL;
+		margin = new_margin;
+		scx200_wdt_update_margin();
+		scx200_wdt_ping();
+	case WDIOC_GETTIMEOUT:
+		if (put_user(margin, (int *)arg))
+			return -EFAULT;
+		return 0;
+	}
+}
+
+static struct file_operations scx200_wdt_fops = {
+	.owner	 = THIS_MODULE,
+	.write   = scx200_wdt_write,
+	.ioctl   = scx200_wdt_ioctl,
+	.open    = scx200_wdt_open,
+	.release = scx200_wdt_release,
+};
+
+static struct miscdevice scx200_wdt_miscdev = {
+	.minor = WATCHDOG_MINOR,
+	.name  = NAME,
+	.fops  = &scx200_wdt_fops,
+};
+
+static int __init scx200_wdt_init(void)
+{
+	int r;
+
+	printk(KERN_DEBUG NAME ": NatSemi SCx200 Watchdog Driver\n");
+
+	/* First check that this really is a NatSemi SCx200 CPU */
+	if ((pci_find_device(PCI_VENDOR_ID_NS, 
+			     PCI_DEVICE_ID_NS_SCx200_BRIDGE,
+			     NULL)) == NULL)
+		return -ENODEV;
+
+	/* More sanity checks, verify that the configuration block is there */
+	if (!scx200_cb_probe(SCx200_CB_BASE)) {
+		printk(KERN_WARNING NAME ": no configuration block found\n");
+		return -ENODEV;
+	}
+
+	if (!request_region(SCx200_CB_BASE + SCx200_WDT_OFFSET, 
+			    SCx200_WDT_SIZE, 
+			    "NatSemi SCx200 Watchdog")) {
+		printk(KERN_WARNING NAME ": watchdog I/O region busy\n");
+		return -EBUSY;
+	}
+
+	scx200_wdt_update_margin();
+	scx200_wdt_disable();
+
+	sema_init(&open_semaphore, 1);
+
+	r = misc_register(&scx200_wdt_miscdev);
+	if (r)
+		return r;
+
+	r = register_reboot_notifier(&scx200_wdt_notifier);
+        if (r) {
+                printk(KERN_ERR NAME ": unable to register reboot notifier");
+		misc_deregister(&scx200_wdt_miscdev);
+                return r;
+        }
+
+	return 0;
+}
+
+static void __exit scx200_wdt_cleanup(void)
+{
+        unregister_reboot_notifier(&scx200_wdt_notifier);
+	misc_deregister(&scx200_wdt_miscdev);
+	release_region(SCx200_CB_BASE + SCx200_WDT_OFFSET,
+		       SCx200_WDT_SIZE);
+}
+
+module_init(scx200_wdt_init);
+module_exit(scx200_wdt_cleanup);
+
+/*
+    Local variables:
+        compile-command: "make -k -C ../.. SUBDIRS=drivers/char modules"
+        c-basic-offset: 8
+    End:
+*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/serial.c linux-2.4.21-pre6/drivers/char/serial.c
--- linux-2.4.20/drivers/char/serial.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/serial.c	2003-03-26 23:49:25.000000000 +0000
@@ -842,10 +842,15 @@
 		if (status & UART_LSR_DR)
 			receive_chars(info, &status, regs);
 		check_modem_status(info);
+#ifdef CONFIG_MELAN
 		if ((status & UART_LSR_THRE) ||
 			/* for buggy ELAN processors */
 			((iir & UART_IIR_ID) == UART_IIR_THRI))
 			transmit_chars(info, 0);
+#else
+		if (status & UART_LSR_THRE)
+			transmit_chars(info, 0);
+#endif
 
 	next:
 		info = info->next_port;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/sonypi.c linux-2.4.21-pre6/drivers/char/sonypi.c
--- linux-2.4.20/drivers/char/sonypi.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/sonypi.c	2003-03-26 23:49:09.000000000 +0000
@@ -1,7 +1,9 @@
-/* 
+/*
  * Sony Programmable I/O Control Device driver for VAIO
  *
- * Copyright (C) 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
+ * Copyright (C) 2001-2003 Stelian Pop <stelian@popies.net>
+ *
+ * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
  *
  * Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
  *
@@ -31,12 +33,17 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
+#include <linux/input.h>
 #include <linux/pci.h>
 #include <linux/sched.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/miscdevice.h>
 #include <linux/poll.h>
 #include <linux/delay.h>
+#include <linux/wait.h>
+#include <linux/acpi.h>
+
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/system.h>
@@ -50,7 +57,8 @@
 static int fnkeyinit; /* = 0 */
 static int camera; /* = 0 */
 static int compat; /* = 0 */
-static int nojogdial; /* = 0 */
+static int useinput = 1;
+static unsigned long mask = 0xffffffff;
 
 /* Inits the queue */
 static inline void sonypi_initq(void) {
@@ -110,29 +118,14 @@
         return result;
 }
 
-static void sonypi_ecrset(u8 addr, u8 value) {
-
-	wait_on_command(1, inb_p(SONYPI_CST_IOPORT) & 3);
-	outb_p(0x81, SONYPI_CST_IOPORT);
-	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2);
-	outb_p(addr, SONYPI_DATA_IOPORT);
-	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2);
-	outb_p(value, SONYPI_DATA_IOPORT);
-	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2);
-}
-
-static u8 sonypi_ecrget(u8 addr) {
-
-	wait_on_command(1, inb_p(SONYPI_CST_IOPORT) & 3);
-	outb_p(0x80, SONYPI_CST_IOPORT);
-	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2);
-	outb_p(addr, SONYPI_DATA_IOPORT);
-	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2);
-	return inb_p(SONYPI_DATA_IOPORT);
-}
-
-static u16 sonypi_ecrget16(u8 addr) {
-	return sonypi_ecrget(addr) | (sonypi_ecrget(addr + 1) << 8);
+static int ec_read16(u8 addr, u16 *value) {
+	u8 val_lb, val_hb;
+	if (ec_read(addr, &val_lb))
+		return -1;
+	if (ec_read(addr + 1, &val_hb))
+		return -1;
+	*value = val_lb | (val_hb << 8);
+	return 0;
 }
 
 /* Initializes the device - this comes from the AML code in the ACPI bios */
@@ -159,9 +152,12 @@
 }
 
 static void __devinit sonypi_type2_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);
+	if (ec_write(SONYPI_SHIB, (sonypi_device.ioport1 & 0xFF00) >> 8))
+		printk(KERN_WARNING "ec_write failed\n");
+	if (ec_write(SONYPI_SLOB,  sonypi_device.ioport1 & 0x00FF))
+		printk(KERN_WARNING "ec_write failed\n");
+	if (ec_write(SONYPI_SIRQ,  sonypi_device.bits))
+		printk(KERN_WARNING "ec_write failed\n");
 	udelay(10);
 }
 
@@ -179,15 +175,18 @@
 }
 
 static void __devexit sonypi_type2_dis(void) {
-	sonypi_ecrset(SONYPI_SHIB, 0);
-	sonypi_ecrset(SONYPI_SLOB, 0);
-	sonypi_ecrset(SONYPI_SIRQ, 0);
+	if (ec_write(SONYPI_SHIB, 0))
+		printk(KERN_WARNING "ec_write failed\n");
+	if (ec_write(SONYPI_SLOB, 0))
+		printk(KERN_WARNING "ec_write failed\n");
+	if (ec_write(SONYPI_SIRQ, 0))
+		printk(KERN_WARNING "ec_write failed\n");
 }
 
 static u8 sonypi_call1(u8 dev) {
 	u8 v1, v2;
 
-	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2);
+	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
 	outb(dev, sonypi_device.ioport2);
 	v1 = inb_p(sonypi_device.ioport2);
 	v2 = inb_p(sonypi_device.ioport1);
@@ -197,9 +196,9 @@
 static u8 sonypi_call2(u8 dev, u8 fn) {
 	u8 v1;
 
-	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2);
+	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
 	outb(dev, sonypi_device.ioport2);
-	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2);
+	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
 	outb(fn, sonypi_device.ioport1);
 	v1 = inb_p(sonypi_device.ioport1);
 	return v1;
@@ -208,11 +207,11 @@
 static u8 sonypi_call3(u8 dev, u8 fn, u8 v) {
 	u8 v1;
 
-	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2);
+	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
 	outb(dev, sonypi_device.ioport2);
-	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2);
+	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
 	outb(fn, sonypi_device.ioport1);
-	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2);
+	wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
 	outb(v, sonypi_device.ioport1);
 	v1 = inb_p(sonypi_device.ioport1);
 	return v1;
@@ -234,7 +233,7 @@
 /* Set brightness, hue etc */
 static void sonypi_set(u8 fn, u8 v) {
 	
-	wait_on_command(0, sonypi_call3(0x90, fn, v));
+	wait_on_command(0, sonypi_call3(0x90, fn, v), ITERATIONS_SHORT);
 }
 
 /* Tests if the camera is ready */
@@ -308,85 +307,51 @@
 /* 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;
-	u8 sonypi_capture_ev, sonypi_bluetooth_ev;
-	u8 sonypi_pkey_ev;
-
-	if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2) {
-		sonypi_jogger_ev = SONYPI_TYPE2_JOGGER_EV;
-		sonypi_fnkey_ev = SONYPI_TYPE2_FNKEY_EV;
-		sonypi_capture_ev = SONYPI_TYPE2_CAPTURE_EV;
-		sonypi_bluetooth_ev = SONYPI_TYPE2_BLUETOOTH_EV;
-		sonypi_pkey_ev = nojogdial ? SONYPI_TYPE2_PKEY_EV 
-					   : SONYPI_TYPE1_PKEY_EV;
-	}
-	else {
-		sonypi_jogger_ev = SONYPI_TYPE1_JOGGER_EV;
-		sonypi_fnkey_ev = SONYPI_TYPE1_FNKEY_EV;
-		sonypi_capture_ev = SONYPI_TYPE1_CAPTURE_EV;
-		sonypi_bluetooth_ev = SONYPI_TYPE1_BLUETOOTH_EV;
-		sonypi_pkey_ev = SONYPI_TYPE1_PKEY_EV;
-	}
+	int i, j;
 
 	v1 = inb_p(sonypi_device.ioport1);
 	v2 = inb_p(sonypi_device.ioport2);
 
-	if ((v2 & sonypi_pkey_ev) == sonypi_pkey_ev) {
-		for (i = 0; sonypi_pkeyev[i].event; i++)
-			if (sonypi_pkeyev[i].data == v1) {
-				event = sonypi_pkeyev[i].event;
-				goto found;
-			}
-	}
-	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 ((v2 & SONYPI_BACK_EV) == SONYPI_BACK_EV) {
-		for (i = 0; sonypi_backev[i].event; i++)
-			if (sonypi_backev[i].data == v1) {
-				event = sonypi_backev[i].event;
-				goto found;
-			}
-	}
-	if ((v2 & SONYPI_LID_EV) == SONYPI_LID_EV) {
-		for (i = 0; sonypi_lidev[i].event; i++)
-			if (sonypi_lidev[i].data == v1) {
-				event = sonypi_lidev[i].event;
+	if (verbose > 1)
+		printk(KERN_INFO 
+		       "sonypi: event port1=0x%02x,port2=0x%02x\n", v1, v2);
+
+	for (i = 0; sonypi_eventtypes[i].model; i++) {
+		if (sonypi_device.model != sonypi_eventtypes[i].model)
+			continue;
+		if ((v2 & sonypi_eventtypes[i].data) != sonypi_eventtypes[i].data)
+			continue;
+		if (! (mask & sonypi_eventtypes[i].mask))
+			continue;
+		for (j = 0; sonypi_eventtypes[i].events[j].event; j++) {
+			if (v1 == sonypi_eventtypes[i].events[j].data) {
+				event = sonypi_eventtypes[i].events[j].event;
 				goto found;
 			}
+		}
 	}
+
 	if (verbose)
 		printk(KERN_WARNING 
 		       "sonypi: unknown event port1=0x%02x,port2=0x%02x\n",v1,v2);
 	return;
 
 found:
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+	if (useinput) {
+		struct input_dev *jog_dev = &sonypi_device.jog_dev;
+		if (event == SONYPI_EVENT_JOGDIAL_PRESSED)
+			input_report_key(jog_dev, BTN_MIDDLE, 1);
+		else if (event == SONYPI_EVENT_ANYBUTTON_RELEASED)
+			input_report_key(jog_dev, BTN_MIDDLE, 0);
+		else if ((event == SONYPI_EVENT_JOGDIAL_UP) ||
+			 (event == SONYPI_EVENT_JOGDIAL_UP_PRESSED))
+			input_report_rel(jog_dev, REL_WHEEL, 1);
+		else if ((event == SONYPI_EVENT_JOGDIAL_DOWN) ||
+			 (event == SONYPI_EVENT_JOGDIAL_DOWN_PRESSED))
+			input_report_rel(jog_dev, REL_WHEEL, -1);
+	}
+#endif /* CONFIG_INPUT || CONFIG_INPUT_MODULE */
 	sonypi_pushq(event);
 }
 
@@ -542,90 +507,140 @@
 	down(&sonypi_device.lock);
 	switch (cmd) {
 	case SONYPI_IOCGBRT:
-		val8 = sonypi_ecrget(0x96);
-		if (copy_to_user((u8 *)arg, &val8, sizeof(val8))) {
-			ret = -EFAULT;
-			goto out;
+		if (ec_read(SONYPI_LCD_LIGHT, &val8)) {
+			ret = -EIO;
+			break;
 		}
+		if (copy_to_user((u8 *)arg, &val8, sizeof(val8)))
+			ret = -EFAULT;
 		break;
 	case SONYPI_IOCSBRT:
 		if (copy_from_user(&val8, (u8 *)arg, sizeof(val8))) {
 			ret = -EFAULT;
-			goto out;
+			break;
 		}
-		sonypi_ecrset(0x96, val8);
+		if (ec_write(SONYPI_LCD_LIGHT, val8))
+			ret = -EIO;
 		break;
 	case SONYPI_IOCGBAT1CAP:
-		val16 = sonypi_ecrget16(0xb2);
-		if (copy_to_user((u16 *)arg, &val16, sizeof(val16))) {
-			ret = -EFAULT;
-			goto out;
+		if (ec_read16(SONYPI_BAT1_FULL, &val16)) {
+			ret = -EIO;
+			break;
 		}
+		if (copy_to_user((u16 *)arg, &val16, sizeof(val16)))
+			ret = -EFAULT;
 		break;
 	case SONYPI_IOCGBAT1REM:
-		val16 = sonypi_ecrget16(0xa2);
-		if (copy_to_user((u16 *)arg, &val16, sizeof(val16))) {
-			ret = -EFAULT;
-			goto out;
+		if (ec_read16(SONYPI_BAT1_FULL, &val16)) {
+			ret = -EIO;
+			break;
 		}
+		if (copy_to_user((u16 *)arg, &val16, sizeof(val16)))
+			ret = -EFAULT;
 		break;
 	case SONYPI_IOCGBAT2CAP:
-		val16 = sonypi_ecrget16(0xba);
-		if (copy_to_user((u16 *)arg, &val16, sizeof(val16))) {
-			ret = -EFAULT;
-			goto out;
+		if (ec_read16(SONYPI_BAT1_FULL, &val16)) {
+			ret = -EIO;
+			break;
 		}
+		if (copy_to_user((u16 *)arg, &val16, sizeof(val16)))
+			ret = -EFAULT;
 		break;
 	case SONYPI_IOCGBAT2REM:
-		val16 = sonypi_ecrget16(0xaa);
-		if (copy_to_user((u16 *)arg, &val16, sizeof(val16))) {
-			ret = -EFAULT;
-			goto out;
+		if (ec_read16(SONYPI_BAT1_FULL, &val16)) {
+			ret = -EIO;
+			break;
 		}
+		if (copy_to_user((u16 *)arg, &val16, sizeof(val16)))
+			ret = -EFAULT;
 		break;
 	case SONYPI_IOCGBATFLAGS:
-		val8 = sonypi_ecrget(0x81) & 0x07;
-		if (copy_to_user((u8 *)arg, &val8, sizeof(val8))) {
-			ret = -EFAULT;
-			goto out;
+		if (ec_read(SONYPI_BAT_FLAGS, &val8)) {
+			ret = -EIO;
+			break;
 		}
+		val8 &= 0x07;
+		if (copy_to_user((u8 *)arg, &val8, sizeof(val8)))
+			ret = -EFAULT;
 		break;
 	case SONYPI_IOCGBLUE:
 		val8 = sonypi_device.bluetooth_power;
-		if (copy_to_user((u8 *)arg, &val8, sizeof(val8))) {
+		if (copy_to_user((u8 *)arg, &val8, sizeof(val8)))
 			ret = -EFAULT;
-			goto out;
-		}
 		break;
 	case SONYPI_IOCSBLUE:
 		if (copy_from_user(&val8, (u8 *)arg, sizeof(val8))) {
 			ret = -EFAULT;
-			goto out;
+			break;
 		}
 		sonypi_setbluetoothpower(val8);
 		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,
+	.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
 };
 
+#ifdef CONFIG_PM
+static int sonypi_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) {
+	static int old_camera_power;
+
+	switch (rqst) {
+	case PM_SUSPEND:
+		sonypi_call2(0x81, 0); /* make sure we don't get any more events */
+		if (camera) {
+			old_camera_power = sonypi_device.camera_power;
+			sonypi_camera_off();
+		}
+		if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2)
+			sonypi_type2_dis();
+		else
+			sonypi_type1_dis();
+#ifndef CONFIG_ACPI
+		/* disable ACPI mode */
+		if (fnkeyinit)
+			outb(0xf1, 0xb2);
+#endif
+		break;
+	case PM_RESUME:
+#ifndef CONFIG_ACPI
+		/* Enable ACPI mode to get Fn key events */
+		if (fnkeyinit)
+			outb(0xf0, 0xb2);
+#endif
+		if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2)
+			sonypi_type2_srs();
+		else
+			sonypi_type1_srs();
+		sonypi_call1(0x82);
+		sonypi_call2(0x81, 0xff);
+		if (compat)
+			sonypi_call1(0x92); 
+		else
+			sonypi_call1(0x82);
+		if (camera && old_camera_power)
+			sonypi_camera_on();
+		break;
+	}
+	return 0;
+}
+#endif
+
 static int __devinit sonypi_probe(struct pci_dev *pcidev) {
 	int i, ret;
 	struct sonypi_ioport_list *ioport_list;
@@ -694,7 +709,7 @@
 		goto out3;
 	}
 
-#if !defined(CONFIG_ACPI)
+#ifndef CONFIG_ACPI
 	/* Enable ACPI mode to get Fn key events */
 	if (fnkeyinit)
 		outb(0xf0, 0xb2);
@@ -716,15 +731,16 @@
 	       SONYPI_DRIVER_MAJORVERSION,
 	       SONYPI_DRIVER_MINORVERSION);
 	printk(KERN_INFO "sonypi: detected %s model, "
-	       "verbose = %s, fnkeyinit = %s, camera = %s, "
-	       "compat = %s, nojogdial = %s\n",
+	       "verbose = %d, fnkeyinit = %s, camera = %s, "
+	       "compat = %s, mask = 0x%08lx, useinput = %s\n",
 	       (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE1) ?
 			"type1" : "type2",
-	       verbose ? "on" : "off",
+	       verbose,
 	       fnkeyinit ? "on" : "off",
 	       camera ? "on" : "off",
 	       compat ? "on" : "off",
-	       nojogdial ? "on" : "off");
+	       mask,
+	       useinput ? "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);
@@ -732,6 +748,29 @@
 		printk(KERN_INFO "sonypi: device allocated minor is %d\n",
 		       sonypi_misc_device.minor);
 
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+	if (useinput) {
+		/* Initialize the Input Drivers: */
+		sonypi_device.jog_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+		sonypi_device.jog_dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_MIDDLE);
+		sonypi_device.jog_dev.relbit[0] = BIT(REL_WHEEL);
+		sonypi_device.jog_dev.name = (char *) kmalloc(
+			sizeof(SONYPI_INPUTNAME), GFP_KERNEL);
+		sprintf(sonypi_device.jog_dev.name, SONYPI_INPUTNAME);
+		sonypi_device.jog_dev.idbus = BUS_ISA;
+		sonypi_device.jog_dev.idvendor = PCI_VENDOR_ID_SONY;
+	  
+		input_register_device(&sonypi_device.jog_dev);
+		printk(KERN_INFO "%s installed at input event device #%d.\n", 
+			sonypi_device.jog_dev.name,
+			sonypi_device.jog_dev.number);
+	}
+#endif /* CONFIG_INPUT || CONFIG_INPUT_MODULE */
+
+#ifdef CONFIG_PM
+	sonypi_device.pm = pm_register(PM_PCI_DEV, 0, sonypi_pm_callback);
+#endif
+
 	return 0;
 
 out3:
@@ -743,14 +782,27 @@
 }
 
 static void __devexit sonypi_remove(void) {
+
+#ifdef CONFIG_PM
+	pm_unregister(sonypi_device.pm);
+#endif
+
 	sonypi_call2(0x81, 0); /* make sure we don't get any more events */
+	
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+	if (useinput) {
+		input_unregister_device(&sonypi_device.jog_dev);
+		kfree(sonypi_device.jog_dev.name);
+	}
+#endif /* CONFIG_INPUT || CONFIG_INPUT_MODULE */
+
 	if (camera)
 		sonypi_camera_off();
 	if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2)
 		sonypi_type2_dis();
 	else
 		sonypi_type1_dis();
-#if !defined(CONFIG_ACPI)
+#ifndef CONFIG_ACPI
 	/* disable ACPI mode */
 	if (fnkeyinit)
 		outb(0xf1, 0xb2);
@@ -780,7 +832,7 @@
 
 #ifndef MODULE
 static int __init sonypi_setup(char *str)  {
-	int ints[7];
+	int ints[8];
 
 	str = get_options(str, ARRAY_SIZE(ints), ints);
 	if (ints[0] <= 0) 
@@ -800,7 +852,10 @@
 	compat = ints[5];
 	if (ints[0] == 5)
 		goto out;
-	nojogdial = ints[6];
+	mask = ints[6];
+	if (ints[0] == 6)
+		goto out;
+	useinput = ints[7];
 out:
 	return 1;
 }
@@ -812,7 +867,7 @@
 module_init(sonypi_init_module);
 module_exit(sonypi_cleanup_module);
 
-MODULE_AUTHOR("Stelian Pop <stelian.pop@fr.alcove.com>");
+MODULE_AUTHOR("Stelian Pop <stelian@popies.net>");
 MODULE_DESCRIPTION("Sony Programmable I/O Control Device driver");
 MODULE_LICENSE("GPL");
 
@@ -827,7 +882,9 @@
 MODULE_PARM_DESC(camera, "set this if you have a MotionEye camera (PictureBook series)");
 MODULE_PARM(compat,"i");
 MODULE_PARM_DESC(compat, "set this if you want to enable backward compatibility mode");
-MODULE_PARM(nojogdial, "i");
-MODULE_PARM_DESC(nojogdial, "set this if you have a Vaio without a jogdial (like the fx series)");
+MODULE_PARM(mask, "i");
+MODULE_PARM_DESC(mask, "set this to the mask of event you want to enable (see doc)");
+MODULE_PARM(useinput, "i");
+MODULE_PARM_DESC(useinput, "if you have a jogdial, set this if you would like it to use the modern Linux Input Driver system");
 
 EXPORT_SYMBOL(sonypi_camera_command);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/sonypi.h linux-2.4.21-pre6/drivers/char/sonypi.h
--- linux-2.4.20/drivers/char/sonypi.h	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/sonypi.h	2003-03-26 23:48:58.000000000 +0000
@@ -1,7 +1,9 @@
 /* 
  * Sony Programmable I/O Control Device driver for VAIO
  *
- * Copyright (C) 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
+ * Copyright (C) 2001-2003 Stelian Pop <stelian@popies.net>
+ *
+ * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
  *
  * Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
  *
@@ -35,10 +37,17 @@
 #ifdef __KERNEL__
 
 #define SONYPI_DRIVER_MAJORVERSION	 1
-#define SONYPI_DRIVER_MINORVERSION	13
+#define SONYPI_DRIVER_MINORVERSION	18
 
+#define SONYPI_DEVICE_MODEL_TYPE1	1
+#define SONYPI_DEVICE_MODEL_TYPE2	2
+
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/pci.h>
+#include <linux/input.h>
+#include <linux/pm.h>
+#include <linux/acpi.h>
 #include "linux/sonypi.h"
 
 /* type1 models use those */
@@ -54,6 +63,20 @@
 #define SONYPI_SHIB			0x9d
 #define SONYPI_TYPE2_REGION_SIZE	0x20
 
+/* battery / brightness addresses */
+#define SONYPI_BAT_FLAGS	0x81
+#define SONYPI_LCD_LIGHT	0x96
+#define SONYPI_BAT1_PCTRM	0xa0
+#define SONYPI_BAT1_LEFT	0xa2
+#define SONYPI_BAT1_MAXRT	0xa4
+#define SONYPI_BAT2_PCTRM	0xa8
+#define SONYPI_BAT2_LEFT	0xaa
+#define SONYPI_BAT2_MAXRT	0xac
+#define SONYPI_BAT1_MAXTK	0xb0
+#define SONYPI_BAT1_FULL	0xb2
+#define SONYPI_BAT2_MAXTK	0xb8
+#define SONYPI_BAT2_FULL	0xba
+
 /* ioports used for brightness and type2 events */
 #define SONYPI_DATA_IOPORT	0x62
 #define SONYPI_CST_IOPORT	0x66
@@ -131,34 +154,47 @@
 #define SONYPI_CAMERA_REVISION 			8
 #define SONYPI_CAMERA_ROMVERSION 		9
 
-/* key press event data (ioport2) */
-#define SONYPI_TYPE1_JOGGER_EV		0x10
-#define SONYPI_TYPE2_JOGGER_EV		0x08
-#define SONYPI_TYPE1_CAPTURE_EV		0x60
-#define SONYPI_TYPE2_CAPTURE_EV		0x08
-#define SONYPI_TYPE1_FNKEY_EV		0x20
-#define SONYPI_TYPE2_FNKEY_EV		0x08
-#define SONYPI_TYPE1_BLUETOOTH_EV	0x30
-#define SONYPI_TYPE2_BLUETOOTH_EV	0x08
-#define SONYPI_TYPE1_PKEY_EV		0x40
-#define SONYPI_TYPE2_PKEY_EV		0x08
-#define SONYPI_BACK_EV			0x08
-#define SONYPI_LID_EV			0x38
+/* Event masks */
+#define SONYPI_JOGGER_MASK			0x00000001
+#define SONYPI_CAPTURE_MASK			0x00000002
+#define SONYPI_FNKEY_MASK			0x00000004
+#define SONYPI_BLUETOOTH_MASK			0x00000008
+#define SONYPI_PKEY_MASK			0x00000010
+#define SONYPI_BACK_MASK			0x00000020
+#define SONYPI_HELP_MASK			0x00000040
+#define SONYPI_LID_MASK				0x00000080
+#define SONYPI_ZOOM_MASK			0x00000100
+#define SONYPI_THUMBPHRASE_MASK			0x00000200
+#define SONYPI_MEYE_MASK			0x00000400
+#define SONYPI_MEMORYSTICK_MASK			0x00000800
 
 struct sonypi_event {
 	u8	data;
 	u8	event;
 };
 
+/* The set of possible button release events */
+static struct sonypi_event sonypi_releaseev[] = {
+	{ 0x00, SONYPI_EVENT_ANYBUTTON_RELEASED },
+	{ 0, 0 }
+};
+
 /* 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 },
+	{ 0x1e, SONYPI_EVENT_JOGDIAL_FAST_UP },
+	{ 0x02, SONYPI_EVENT_JOGDIAL_FAST_DOWN },
+	{ 0x5e, SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED },
+	{ 0x42, SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED },
+	{ 0x1d, SONYPI_EVENT_JOGDIAL_VFAST_UP },
+	{ 0x03, SONYPI_EVENT_JOGDIAL_VFAST_DOWN },
+	{ 0x5d, SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED },
+	{ 0x43, SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED },
 	{ 0x40, SONYPI_EVENT_JOGDIAL_PRESSED },
-	{ 0x00, SONYPI_EVENT_JOGDIAL_RELEASED },
-	{ 0x00, 0x00 }
+	{ 0, 0 }
 };
 
 /* The set of possible capture button events */
@@ -166,8 +202,7 @@
 	{ 0x05, SONYPI_EVENT_CAPTURE_PARTIALPRESSED },
 	{ 0x07, SONYPI_EVENT_CAPTURE_PRESSED },
 	{ 0x01, SONYPI_EVENT_CAPTURE_PARTIALRELEASED },
-	{ 0x00, SONYPI_EVENT_CAPTURE_RELEASED },
-	{ 0x00, 0x00 }
+	{ 0, 0 }
 };
 
 /* The set of possible fnkeys events */
@@ -192,7 +227,8 @@
 	{ 0x33, SONYPI_EVENT_FNKEY_F },
 	{ 0x34, SONYPI_EVENT_FNKEY_S },
 	{ 0x35, SONYPI_EVENT_FNKEY_B },
-	{ 0x00, 0x00 }
+	{ 0x36, SONYPI_EVENT_FNKEY_ONLY },
+	{ 0, 0 }
 };
 
 /* The set of possible program key events */
@@ -200,7 +236,7 @@
 	{ 0x01, SONYPI_EVENT_PKEY_P1 },
 	{ 0x02, SONYPI_EVENT_PKEY_P2 },
 	{ 0x04, SONYPI_EVENT_PKEY_P3 },
-	{ 0x00, 0x00 }
+	{ 0, 0 }
 };
 
 /* The set of possible bluetooth events */
@@ -208,21 +244,84 @@
 	{ 0x55, SONYPI_EVENT_BLUETOOTH_PRESSED },
 	{ 0x59, SONYPI_EVENT_BLUETOOTH_ON },
 	{ 0x5a, SONYPI_EVENT_BLUETOOTH_OFF },
-	{ 0x00, 0x00 }
+	{ 0, 0 }
 };
 
 /* The set of possible back button events */
 static struct sonypi_event sonypi_backev[] = {
 	{ 0x20, SONYPI_EVENT_BACK_PRESSED },
+	{ 0, 0 }
+};
+
+/* The set of possible help button events */
+static struct sonypi_event sonypi_helpev[] = {
 	{ 0x3b, SONYPI_EVENT_HELP_PRESSED },
-	{ 0x00, 0x00 }
+	{ 0, 0 }
 };
 
+
 /* The set of possible lid events */
 static struct sonypi_event sonypi_lidev[] = {
 	{ 0x51, SONYPI_EVENT_LID_CLOSED },
 	{ 0x50, SONYPI_EVENT_LID_OPENED },
-	{ 0x00, 0x00 }
+	{ 0, 0 }
+};
+
+/* The set of possible zoom events */
+static struct sonypi_event sonypi_zoomev[] = {
+	{ 0x39, SONYPI_EVENT_ZOOM_PRESSED },
+	{ 0, 0 }
+};
+
+/* The set of possible thumbphrase events */
+static struct sonypi_event sonypi_thumbphraseev[] = {
+	{ 0x3a, SONYPI_EVENT_THUMBPHRASE_PRESSED },
+	{ 0, 0 }
+};
+
+/* The set of possible motioneye camera events */
+static struct sonypi_event sonypi_meyeev[] = {
+	{ 0x00, SONYPI_EVENT_MEYE_FACE },
+	{ 0x01, SONYPI_EVENT_MEYE_OPPOSITE },
+	{ 0, 0 }
+};
+
+/* The set of possible memorystick events */
+static struct sonypi_event sonypi_memorystickev[] = {
+	{ 0x53, SONYPI_EVENT_MEMORYSTICK_INSERT },
+	{ 0x54, SONYPI_EVENT_MEMORYSTICK_EJECT },
+	{ 0, 0 }
+};
+
+struct sonypi_eventtypes {
+	int			model;
+	u8			data;
+	unsigned long		mask;
+	struct sonypi_event *	events;
+} sonypi_eventtypes[] = {
+	{ SONYPI_DEVICE_MODEL_TYPE1, 0, 0xffffffff, sonypi_releaseev },
+	{ SONYPI_DEVICE_MODEL_TYPE1, 0x70, SONYPI_MEYE_MASK, sonypi_meyeev },
+	{ SONYPI_DEVICE_MODEL_TYPE1, 0x30, SONYPI_LID_MASK, sonypi_lidev },
+	{ SONYPI_DEVICE_MODEL_TYPE1, 0x60, SONYPI_CAPTURE_MASK, sonypi_captureev },
+	{ SONYPI_DEVICE_MODEL_TYPE1, 0x10, SONYPI_JOGGER_MASK, sonypi_joggerev },
+	{ SONYPI_DEVICE_MODEL_TYPE1, 0x20, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
+	{ SONYPI_DEVICE_MODEL_TYPE1, 0x30, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
+	{ SONYPI_DEVICE_MODEL_TYPE1, 0x40, SONYPI_PKEY_MASK, sonypi_pkeyev },
+
+	{ SONYPI_DEVICE_MODEL_TYPE2, 0, 0xffffffff, sonypi_releaseev },
+	{ SONYPI_DEVICE_MODEL_TYPE2, 0x38, SONYPI_LID_MASK, sonypi_lidev },
+	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_JOGGER_MASK, sonypi_joggerev },
+	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_CAPTURE_MASK, sonypi_captureev },
+	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
+	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
+	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev },
+	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_BACK_MASK, sonypi_backev },
+	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_HELP_MASK, sonypi_helpev },
+	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_ZOOM_MASK, sonypi_zoomev },
+	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev },
+	{ SONYPI_DEVICE_MODEL_TYPE2, 0x08, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
+
+	{ 0, 0, 0, 0 }
 };
 
 #define SONYPI_BUF_SIZE	128
@@ -236,8 +335,8 @@
 	unsigned char buf[SONYPI_BUF_SIZE];
 };
 
-#define SONYPI_DEVICE_MODEL_TYPE1	1
-#define SONYPI_DEVICE_MODEL_TYPE2	2
+/* The name of the Jog Dial for the input device drivers */
+#define SONYPI_INPUTNAME	"Sony VAIO Jog Dial"
 
 struct sonypi_device {
 	struct pci_dev *dev;
@@ -252,15 +351,56 @@
 	struct sonypi_queue queue;
 	int open_count;
 	int model;
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+	struct input_dev jog_dev;
+#endif
+#ifdef CONFIG_PM
+	struct pm_dev *pm;
+#endif
 };
 
-#define wait_on_command(quiet, command) { \
-	unsigned int n = 10000; \
+#define ITERATIONS_LONG		10000
+#define ITERATIONS_SHORT	10
+
+#define wait_on_command(quiet, command, iterations) { \
+	unsigned int n = iterations; \
 	while (--n && (command)) \
 		udelay(1); \
 	if (!n && (verbose || !quiet)) \
-		printk(KERN_WARNING "sonypi command failed at " __FILE__ " : %s (line %d)\n", __FUNCTION__, __LINE__); \
+		printk(KERN_WARNING "sonypi command failed at %s : %s (line %d)\n", __FILE__, __FUNCTION__, __LINE__); \
+}
+
+#ifdef CONFIG_ACPI
+#include <linux/acpi.h>
+#if (ACPI_CA_VERSION > 0x20021121)
+#define USE_ACPI
+#endif
+#endif /* CONFIG_ACPI */
+
+#ifndef USE_ACPI
+extern int verbose;
+
+static inline int ec_write(u8 addr, u8 value) {
+	wait_on_command(1, inb_p(SONYPI_CST_IOPORT) & 3, ITERATIONS_LONG);
+	outb_p(0x81, SONYPI_CST_IOPORT);
+	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG);
+	outb_p(addr, SONYPI_DATA_IOPORT);
+	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG);
+	outb_p(value, SONYPI_DATA_IOPORT);
+	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG);
+	return 0;
+}
+
+static inline int ec_read(u8 addr, u8 *value) {
+	wait_on_command(1, inb_p(SONYPI_CST_IOPORT) & 3, ITERATIONS_LONG);
+	outb_p(0x80, SONYPI_CST_IOPORT);
+	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG);
+	outb_p(addr, SONYPI_DATA_IOPORT);
+	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG);
+	*value = inb_p(SONYPI_DATA_IOPORT);
+	return 0;
 }
+#endif /* ! USE_ACPI */
 
 #endif /* __KERNEL__ */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/tipar.c linux-2.4.21-pre6/drivers/char/tipar.c
--- linux-2.4.20/drivers/char/tipar.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/tipar.c	2003-03-26 23:49:25.000000000 +0000
@@ -0,0 +1,538 @@
+/* Hey EMACS -*- linux-c -*-
+ *
+ * tipar - low level driver for handling a parallel link cable designed
+ * for Texas Instruments graphing calculators (http://lpg.ticalc.org).
+ *
+ * Copyright (C) 2000-2002, Romain Lievin <roms@lpg.ticalc.org>
+ * under the terms of the GNU General Public License.
+ *
+ * Various fixes & clean-up from the Linux Kernel Mailing List
+ * (Alan Cox, Richard B. Johnson, Christoph Hellwig).
+ */
+
+/* This driver should, in theory, work with any parallel port that has an
+ * appropriate low-level driver; all I/O is done through the parport
+ * abstraction layer.
+ *
+ * If this driver is built into the kernel, you can configure it using the
+ * kernel command-line.  For example:
+ *
+ *      tipar=timeout,delay       (set timeout and delay)
+ *
+ * If the driver is loaded as a module, similar functionality is available
+ * using module parameters.  The equivalent of the above commands would be:
+ *
+ *      # insmod tipar timeout=15 delay=10
+ */
+
+/* COMPATIBILITY WITH OLD KERNELS
+ *
+ * Usually, parallel cables were bound to ports at
+ * particular I/O addresses, as follows:
+ *
+ *      tipar0             0x378
+ *      tipar1             0x278
+ *      tipar2             0x3bc
+ *
+ *
+ * This driver, by default, binds tipar devices according to parport and
+ * the minor number.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/fcntl.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+#include <linux/devfs_fs_kernel.h>	/* DevFs support */
+#include <linux/parport.h>	/* Our code depend on parport */
+
+/*
+ * TI definitions
+ */
+#include <linux/ticable.h>
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "1.18"
+#define DRIVER_AUTHOR  "Romain Lievin <roms@lpg.ticalc.org>"
+#define DRIVER_DESC    "Device driver for TI/PC parallel link cables"
+#define DRIVER_LICENSE "GPL"
+
+#define VERSION(ver,rel,seq) (((ver)<<16) | ((rel)<<8) | (seq))
+#if LINUX_VERSION_CODE < VERSION(2,5,0)
+# define minor(x) MINOR(x)
+# define need_resched() (current->need_resched)
+#endif
+
+/* ----- global variables --------------------------------------------- */
+
+struct tipar_struct {
+	struct pardevice *dev;	/* Parport device entry */
+};
+
+#define PP_NO 3
+static struct tipar_struct table[PP_NO];
+
+static int delay = IO_DELAY;	/* inter-bit delay in microseconds */
+static int timeout = TIMAXTIME;	/* timeout in tenth of seconds     */
+
+static devfs_handle_t devfs_handle;
+static unsigned int tp_count;	/* tipar count */
+static unsigned long opened;	/* opened devices */
+
+/* --- macros for parport access -------------------------------------- */
+
+#define r_dtr(x)        (parport_read_data(table[(x)].dev->port))
+#define r_str(x)        (parport_read_status(table[(x)].dev->port))
+#define w_ctr(x,y)      (parport_write_control(table[(x)].dev->port, (y)))
+#define w_dtr(x,y)      (parport_write_data(table[(x)].dev->port, (y)))
+
+/* --- setting states on the D-bus with the right timing: ------------- */
+
+static inline void
+outbyte(int value, int minor)
+{
+	w_dtr(minor, value);
+}
+
+static inline int
+inbyte(int minor)
+{
+	return (r_str(minor));
+}
+
+static inline void
+init_ti_parallel(int minor)
+{
+	outbyte(3, minor);
+}
+
+/* ----- global defines ----------------------------------------------- */
+
+#define START(x) { x=jiffies+HZ/(timeout/10); }
+#define WAIT(x)  { \
+  if (time_before((x), jiffies)) return -1; \
+  if (need_resched()) schedule(); }
+
+/* ----- D-bus bit-banging functions ---------------------------------- */
+
+/* D-bus protocol (45kbit/s max):
+                    1                 0                      0
+       _______        ______|______    __________|________    __________
+Red  :        ________      |      ____          |        ____
+       _        ____________|________      ______|__________       _____
+White:  ________            |        ______      |          _______
+*/
+
+/* Try to transmit a byte on the specified port (-1 if error). */
+static int
+put_ti_parallel(int minor, unsigned char data)
+{
+	int bit;
+	unsigned long max;
+
+	for (bit = 0; bit < 8; bit++) {
+		if (data & 1) {
+			outbyte(2, minor);
+			START(max);
+			do {
+				WAIT(max);
+			} while (inbyte(minor) & 0x10);
+
+			outbyte(3, minor);
+			START(max);
+			do {
+				WAIT(max);
+			} while (!(inbyte(minor) & 0x10));
+		} else {
+			outbyte(1, minor);
+			START(max);
+			do {
+				WAIT(max);
+			} while (inbyte(minor) & 0x20);
+
+			outbyte(3, minor);
+			START(max);
+			do {
+				WAIT(max);
+			} while (!(inbyte(minor) & 0x20));
+		}
+
+		data >>= 1;
+		udelay(delay);
+
+		if (need_resched())
+			schedule();
+	}
+
+	return 0;
+}
+
+/* Receive a byte on the specified port or -1 if error. */
+static int
+get_ti_parallel(int minor)
+{
+	int bit;
+	unsigned char v, data = 0;
+	unsigned long max;
+
+	for (bit = 0; bit < 8; bit++) {
+		START(max);
+		do {
+			WAIT(max);
+		} while ((v = inbyte(minor) & 0x30) == 0x30);
+
+		if (v == 0x10) {
+			data = (data >> 1) | 0x80;
+			outbyte(1, minor);
+			START(max);
+			do {
+				WAIT(max);
+			} while (!(inbyte(minor) & 0x20));
+			outbyte(3, minor);
+		} else {
+			data = data >> 1;
+			outbyte(2, minor);
+			START(max);
+			do {
+				WAIT(max);
+			} while (!(inbyte(minor) & 0x10));
+			outbyte(3, minor);
+		}
+
+		udelay(delay);
+		if (need_resched())
+			schedule();
+	}
+
+	return (int) data;
+}
+
+/* Try to detect a parallel link cable on the specified port */
+static int
+probe_ti_parallel(int minor)
+{
+	int i;
+	int seq[] = { 0x00, 0x20, 0x10, 0x30 };
+
+	for (i = 3; i >= 0; i--) {
+		outbyte(3, minor);
+		outbyte(i, minor);
+		udelay(delay);
+		/*printk(KERN_DEBUG "Probing -> %i: 0x%02x 0x%02x\n", i, data & 0x30, seq[i]); */
+		if ((inbyte(minor) & 0x30) != seq[i]) {
+			outbyte(3, minor);
+			return -1;
+		}
+	}
+
+	outbyte(3, minor);
+	return 0;
+}
+
+/* ----- kernel module functions--------------------------------------- */
+
+static int
+tipar_open(struct inode *inode, struct file *file)
+{
+	unsigned int minor = minor(inode->i_rdev) - TIPAR_MINOR;
+
+	if (minor > tp_count - 1)
+		return -ENXIO;
+
+	if (test_and_set_bit(minor, &opened))
+		return -EBUSY;
+
+	parport_claim_or_block(table[minor].dev);
+	init_ti_parallel(minor);
+	parport_release(table[minor].dev);
+
+	return 0;
+}
+
+static int
+tipar_close(struct inode *inode, struct file *file)
+{
+	unsigned int minor = minor(inode->i_rdev) - TIPAR_MINOR;
+
+	if (minor > tp_count - 1)
+		return -ENXIO;
+
+	clear_bit(minor, &opened);
+
+	return 0;
+}
+
+static ssize_t
+tipar_write(struct file *file, const char *buf, size_t count, loff_t * ppos)
+{
+	unsigned int minor =
+	    minor(file->f_dentry->d_inode->i_rdev) - TIPAR_MINOR;
+	ssize_t n;
+
+	parport_claim_or_block(table[minor].dev);
+
+	for (n = 0; n < count; n++) {
+		unsigned char b;
+
+		if (get_user(b, buf + n)) {
+			n = -EFAULT;
+			goto out;
+		}
+
+		if (put_ti_parallel(minor, b) == -1) {
+			init_ti_parallel(minor);
+			n = -ETIMEDOUT;
+			goto out;
+		}
+	}
+      out:
+	parport_release(table[minor].dev);
+	return n;
+}
+
+static ssize_t
+tipar_read(struct file *file, char *buf, size_t count, loff_t * ppos)
+{
+	int b = 0;
+	unsigned int minor =
+	    minor(file->f_dentry->d_inode->i_rdev) - TIPAR_MINOR;
+	ssize_t retval = 0;
+	ssize_t n = 0;
+
+	if (count == 0)
+		return 0;
+
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	parport_claim_or_block(table[minor].dev);
+
+	while (n < count) {
+		b = get_ti_parallel(minor);
+		if (b == -1) {
+			init_ti_parallel(minor);
+			retval = -ETIMEDOUT;
+			goto out;
+		} else {
+			if (put_user(b, ((unsigned char *) buf) + n)) {
+				retval = -EFAULT;
+				break;
+			} else
+				retval = ++n;
+		}
+
+		/* Non-blocking mode : try again ! */
+		if (file->f_flags & O_NONBLOCK) {
+			retval = -EAGAIN;
+			goto out;
+		}
+
+		/* Signal pending, try again ! */
+		if (signal_pending(current)) {
+			retval = -ERESTARTSYS;
+			goto out;
+		}
+
+		if (need_resched())
+			schedule();
+	}
+
+      out:
+	parport_release(table[minor].dev);
+	return retval;
+}
+
+static int
+tipar_ioctl(struct inode *inode, struct file *file,
+	    unsigned int cmd, unsigned long arg)
+{
+	int retval = 0;
+
+	switch (cmd) {
+	case IOCTL_TIPAR_DELAY:
+	  delay = (int)arg;    //get_user(delay, &arg);
+	  break;
+	case IOCTL_TIPAR_TIMEOUT:
+	  timeout = (int)arg;  //get_user(timeout, &arg);
+	  break;
+	default:
+		retval = -ENOTTY;
+		break;
+	}
+
+	return retval;
+}
+
+/* ----- kernel module registering ------------------------------------ */
+
+static struct file_operations tipar_fops = {
+	owner:THIS_MODULE,
+	llseek:no_llseek,
+	read:tipar_read,
+	write:tipar_write,
+	ioctl:tipar_ioctl,
+	open:tipar_open,
+	release:tipar_close,
+};
+
+/* --- initialisation code ------------------------------------- */
+
+#ifndef MODULE
+/*      You must set these - there is no sane way to probe for this cable.
+ *      You can use 'tipar=timeout,delay' to set these now. */
+static int __init
+tipar_setup(char *str)
+{
+	int ints[2];
+
+	str = get_options(str, ARRAY_SIZE(ints), ints);
+
+	if (ints[0] > 0) {
+		timeout = ints[1];
+		if (ints[0] > 1) {
+			delay = ints[2];
+		}
+	}
+
+	return 1;
+}
+#endif
+
+/*
+ * Register our module into parport.
+ * Pass also 2 callbacks functions to parport: a pre-emptive function and an
+ * interrupt handler function (unused).
+ * Display a message such "tipar0: using parport0 (polling)".
+ */
+static int
+tipar_register(int nr, struct parport *port)
+{
+	char name[8];
+
+	/* Register our module into parport */
+	table[nr].dev = parport_register_device(port, "tipar",
+						NULL, NULL, NULL, 0,
+						(void *) &table[nr]);
+
+	if (table[nr].dev == NULL)
+		return 1;
+
+	/* Use devfs, tree: /dev/ticables/par/[0..2] */
+	sprintf(name, "%d", nr);
+	printk
+	    ("tipar: registering to devfs : major = %d, minor = %d, node = %s\n",
+	     TISER_MAJOR, (TIPAR_MINOR + nr), name);
+	devfs_register(devfs_handle, name, DEVFS_FL_DEFAULT, TIPAR_MAJOR,
+		       TIPAR_MINOR + nr, S_IFCHR | S_IRUGO | S_IWUGO,
+		       &tipar_fops, NULL);
+
+	/* Display informations */
+	printk(KERN_INFO "tipar%d: using %s (%s).\n", nr, port->name,
+	       (port->irq ==
+		PARPORT_IRQ_NONE) ? "polling" : "interrupt-driven");
+
+	if (probe_ti_parallel(nr) != -1)
+		printk("tipar%d: link cable found !\n", nr);
+	else
+		printk("tipar%d: link cable not found.\n", nr);
+
+	return 0;
+}
+
+static void
+tipar_attach(struct parport *port)
+{
+	if (tp_count == PP_NO) {
+		printk("tipar: ignoring parallel port (max. %d)\n", PP_NO);
+		return;
+	}
+
+	if (!tipar_register(tp_count, port))
+		tp_count++;
+}
+
+static void
+tipar_detach(struct parport *port)
+{
+	/* Nothing to do */
+}
+
+static struct parport_driver tipar_driver = {
+	"tipar",
+	tipar_attach,
+	tipar_detach,
+	NULL
+};
+
+int __init
+tipar_init_module(void)
+{
+	printk("tipar: parallel link cable driver, version %s\n",
+	       DRIVER_VERSION);
+
+	if (devfs_register_chrdev(TIPAR_MAJOR, "tipar", &tipar_fops)) {
+		printk("tipar: unable to get major %d\n", TIPAR_MAJOR);
+		return -EIO;
+	}
+
+	/* Use devfs with tree: /dev/ticables/par/[0..2] */
+	devfs_handle = devfs_mk_dir(NULL, "ticables/par", NULL);
+
+	if (parport_register_driver(&tipar_driver)) {
+		printk("tipar: unable to register with parport\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+void __exit
+tipar_cleanup_module(void)
+{
+	unsigned int i;
+
+	/* Unregistering module */
+	parport_unregister_driver(&tipar_driver);
+
+	devfs_unregister(devfs_handle);
+	devfs_unregister_chrdev(TIPAR_MAJOR, "tipar");
+
+	for (i = 0; i < PP_NO; i++) {
+		if (table[i].dev == NULL)
+			continue;
+		parport_unregister_device(table[i].dev);
+	}
+
+	printk("tipar: module unloaded !\n");
+}
+
+/* --------------------------------------------------------------------- */
+
+__setup("tipar=", tipar_setup);
+module_init(tipar_init_module);
+module_exit(tipar_cleanup_module);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
+
+EXPORT_NO_SYMBOLS;
+
+MODULE_PARM(timeout, "i");
+MODULE_PARM_DESC(timeout, "Timeout (default=1.5 seconds)");
+MODULE_PARM(delay, "i");
+MODULE_PARM_DESC(delay, "Inter-bit delay (default=10 microseconds)");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/char/wdt285.c linux-2.4.21-pre6/drivers/char/wdt285.c
--- linux-2.4.20/drivers/char/wdt285.c	2002-08-03 00:39:43.000000000 +0000
+++ linux-2.4.21-pre6/drivers/char/wdt285.c	2003-03-26 23:49:18.000000000 +0000
@@ -179,10 +179,15 @@
 
 static int __init footbridge_watchdog_init(void)
 {
+	int retval;
+
 	if (machine_is_netwinder())
 		return -ENODEV;
 
-	misc_register(&watchdog_miscdev);
+	retval = misc_register(&watchdog_miscdev);
+	if(retval < 0)
+		return retval;
+
 	printk("Footbridge Watchdog Timer: 0.01, timer margin: %d sec\n", 
 	       soft_margin);
 	if (machine_is_cats())
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/gsc/dino.c linux-2.4.21-pre6/drivers/gsc/dino.c
--- linux-2.4.20/drivers/gsc/dino.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/gsc/dino.c	2003-03-26 23:49:55.000000000 +0000
@@ -436,7 +436,7 @@
 	if (mask) {
 		if (--ilr_loop > 0)
 			goto ilr_again;
-		printk("Dino %lx: stuck interrupt %d\n", dino_dev->hba.base_addr, mask);
+		printk("Dino %lx: IRQ base %d, stuck IRQ lines? 0x%x\n", dino_dev->hba.base_addr, dino_dev->dino_region->data.irqbase, mask);
 	}
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/gsc/lasi.c linux-2.4.21-pre6/drivers/gsc/lasi.c
--- linux-2.4.20/drivers/gsc/lasi.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/gsc/lasi.c	2003-03-26 23:49:25.000000000 +0000
@@ -26,7 +26,7 @@
 #include <asm/gsc.h>
 #include <asm/hardware.h>
 #include <asm/led.h>
-
+#include <asm/pdc.h>
 #include "busdevice.h"
 
 
@@ -77,7 +77,10 @@
 
 	/* Resets */
 	/* gsc_writel(0xFFFFFFFF, lasi_base+0x2000);*/	/* Parallel */
-	gsc_writel(0xFFFFFFFF, lasi_base+0x4004);	/* Audio */
+
+	if(pdc_add_valid(lasi_base+0x4004) == PDC_OK)
+		gsc_writel(0xFFFFFFFF, lasi_base+0x4004);	/* Audio */
+
 	/* gsc_writel(0xFFFFFFFF, lasi_base+0x5000);*/	/* Serial */ 
 	/* gsc_writel(0xFFFFFFFF, lasi_base+0x6000);*/	/* SCSI */
 	gsc_writel(0xFFFFFFFF, lasi_base+0x7000);	/* LAN */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hil/hil_kbd.c linux-2.4.21-pre6/drivers/hil/hil_kbd.c
--- linux-2.4.20/drivers/hil/hil_kbd.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/hil/hil_kbd.c	2003-03-26 23:48:57.000000000 +0000
@@ -431,9 +431,9 @@
 
 
 struct serio_dev hil_kbd_serio_dev = {
-	connect:	hil_kbd_connect,
-	disconnect:	hil_kbd_disconnect,
-	interrupt:	hil_kbd_interrupt
+	.connect =	hil_kbd_connect,
+	.disconnect =	hil_kbd_disconnect,
+	.interrupt =	hil_kbd_interrupt
 };
 
 static int __init hil_kbd_init(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hil/hil_ptr.c linux-2.4.21-pre6/drivers/hil/hil_ptr.c
--- linux-2.4.20/drivers/hil/hil_ptr.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/hil/hil_ptr.c	2003-03-26 23:49:54.000000000 +0000
@@ -386,9 +386,9 @@
 
 
 struct serio_dev hil_ptr_serio_dev = {
-	connect: hil_ptr_connect,
-	disconnect: hil_ptr_disconnect,
-	interrupt: hil_ptr_interrupt
+	.connect =	hil_ptr_connect,
+	.disconnect =	hil_ptr_disconnect,
+	.interrupt =	hil_ptr_interrupt
 };
 
 static int __init hil_ptr_init(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hil/hilkbd.c linux-2.4.21-pre6/drivers/hil/hilkbd.c
--- linux-2.4.20/drivers/hil/hilkbd.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/hil/hilkbd.c	2003-03-26 23:49:40.000000000 +0000
@@ -348,9 +348,9 @@
 MODULE_DEVICE_TABLE(parisc, hil_tbl);
 
 static struct parisc_driver hil_driver = {
-	name:		"HIL",
-	id_table:	hil_tbl,
-	probe:		hil_init_chip,
+	.name =		"HIL",
+	.id_table =	hil_tbl,
+	.probe =	hil_init_chip,
 };
 #endif /* CONFIG_PARISC */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hil/hp_sdc.c linux-2.4.21-pre6/drivers/hil/hp_sdc.c
--- linux-2.4.20/drivers/hil/hp_sdc.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/hil/hp_sdc.c	2003-03-26 23:49:19.000000000 +0000
@@ -745,10 +745,10 @@
 
 static struct parisc_device_id hp_sdc_tbl[] = {
 	{
-		hw_type:	HPHW_FIO, 
-		hversion_rev:	HVERSION_REV_ANY_ID,
-		hversion:	HVERSION_ANY_ID,
-		sversion:	0x73, 
+		.hw_type =	HPHW_FIO, 
+		.hversion_rev =	HVERSION_REV_ANY_ID,
+		.hversion =	HVERSION_ANY_ID,
+		.sversion =	0x73, 
 	 },
 	{ 0, }
 };
@@ -758,9 +758,9 @@
 static int __init hp_sdc_init(struct parisc_device *d);
 
 static struct parisc_driver hp_sdc_driver = {
-	name:		"HP SDC",
-	id_table:	hp_sdc_tbl,
-	probe:		hp_sdc_init,
+	.name =		"HP SDC",
+	.id_table =	hp_sdc_tbl,
+	.probe =	hp_sdc_init,
 };
 
 static int __init hp_sdc_init(struct parisc_device *d)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hil/hp_sdc_rtc.c linux-2.4.21-pre6/drivers/hil/hp_sdc_rtc.c
--- linux-2.4.20/drivers/hil/hp_sdc_rtc.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/hil/hp_sdc_rtc.c	2003-03-26 23:49:39.000000000 +0000
@@ -674,20 +674,20 @@
 }
 
 static struct file_operations hp_sdc_rtc_fops = {
-        owner:          THIS_MODULE,
-        llseek:         hp_sdc_rtc_llseek,
-        read:           hp_sdc_rtc_read,
-        poll:           hp_sdc_rtc_poll,
-        ioctl:          hp_sdc_rtc_ioctl,
-        open:           hp_sdc_rtc_open,
-        release:        hp_sdc_rtc_release,
-        fasync:         hp_sdc_rtc_fasync,
+        .owner =	THIS_MODULE,
+        .llseek =	hp_sdc_rtc_llseek,
+        .read =		hp_sdc_rtc_read,
+        .poll =		hp_sdc_rtc_poll,
+        .ioctl =	hp_sdc_rtc_ioctl,
+        .open =		hp_sdc_rtc_open,
+        .release =	hp_sdc_rtc_release,
+        .fasync =	hp_sdc_rtc_fasync,
 };
 
 static struct miscdevice hp_sdc_rtc_dev = {
-        minor:		RTC_MINOR,
-        name:		"rtc",
-        fops:		&hp_sdc_rtc_fops
+        .minor =	RTC_MINOR,
+        .name =		"rtc",
+        .fops =		&hp_sdc_rtc_fops
 };
 
 static int __init hp_sdc_rtc_init(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hotplug/Makefile linux-2.4.21-pre6/drivers/hotplug/Makefile
--- linux-2.4.20/drivers/hotplug/Makefile	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/hotplug/Makefile	2003-03-26 23:49:09.000000000 +0000
@@ -29,9 +29,6 @@
 
 ifdef CONFIG_HOTPLUG_PCI_ACPI
   EXTRA_CFLAGS	+= -D_LINUX -I$(CURDIR)/../acpi
-  ifdef CONFIG_ACPI_DEBUG
-    EXTRA_CFLAGS += -DACPI_DEBUG -Wno-unused
-  endif
 endif
 
 acpiphp_objs		:=	acpiphp_core.o	\
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hotplug/acpiphp.h linux-2.4.21-pre6/drivers/hotplug/acpiphp.h
--- linux-2.4.20/drivers/hotplug/acpiphp.h	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/hotplug/acpiphp.h	2003-03-26 23:48:58.000000000 +0000
@@ -97,17 +97,17 @@
 
 #define dbg(format, arg...)					\
 	do {							\
-		if (debug)					\
-			printk (KERN_DEBUG "%s: " format "\n",	\
+		if (acpiphp_debug)				\
+			printk(KERN_DEBUG "%s: " format,	\
 				MY_NAME , ## arg); 		\
 	} while (0)
-#define err(format, arg...) printk (KERN_ERR "%s: " format "\n", MY_NAME , ## arg)
-#define info(format, arg...) printk (KERN_INFO "%s: " format "\n", MY_NAME , ## arg)
-#define warn(format, arg...) printk (KERN_WARNING "%s: " format "\n", MY_NAME , ## arg)
+#define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg)
+#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg)
 
 #define SLOT_MAGIC	0x67267322
 /* name size which is used for entries in pcihpfs */
-#define SLOT_NAME_SIZE	16		/* ACPIxxxx */
+#define SLOT_NAME_SIZE	32		/* ACPI{_SUN}-{BUS}:{DEV} */
 
 struct acpiphp_bridge;
 struct acpiphp_slot;
@@ -122,8 +122,6 @@
 	struct hotplug_slot	*hotplug_slot;
 	struct list_head	slot_list;
 
-	/* if there are multiple corresponding ACPI slot objects,
-	   this points to one of them */
 	struct acpiphp_slot	*acpi_slot;
 };
 
@@ -175,8 +173,6 @@
 	/* PCI-to-PCI bridge device */
 	struct pci_dev *pci_dev;
 
-	struct pci_ops *pci_ops;
-
 	/* ACPI 2.0 _HPP parameters */
 	struct hpp_param hpp;
 
@@ -200,7 +196,6 @@
 	struct acpiphp_bridge *bridge;	/* parent */
 	struct list_head funcs;		/* one slot may have different
 					   objects (i.e. for each function) */
-	struct acpiphp_func *func;	/* functions */
 	struct semaphore crit_sect;
 
 	u32		id;		/* slot id (serial #) for hotplug core */
@@ -213,7 +208,7 @@
 
 
 /**
- * struct acpiphp_func - PCI slot information
+ * struct acpiphp_func - PCI function information
  *
  * PCI function information for each object in ACPI namespace
  * typically 8 objects per slot (i.e. for each PCI function)
@@ -319,4 +314,7 @@
 extern void acpiphp_dump_resource (struct acpiphp_bridge *bridge); /* debug */
 extern void acpiphp_dump_func_resource (struct acpiphp_func *func); /* debug */
 
+/* variables */
+extern int acpiphp_debug;
+
 #endif /* _ACPIPHP_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hotplug/acpiphp_core.c linux-2.4.21-pre6/drivers/hotplug/acpiphp_core.c
--- linux-2.4.20/drivers/hotplug/acpiphp_core.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/hotplug/acpiphp_core.c	2003-03-26 23:49:54.000000000 +0000
@@ -50,12 +50,14 @@
 	#define MY_NAME	THIS_MODULE->name
 #endif
 
+static int debug;
+int acpiphp_debug;
+
 /* local variables */
-static int debug = 1;			/* XXX set to 0 after debug */
 static int num_slots;
 
-#define DRIVER_VERSION	"0.3"
-#define DRIVER_AUTHOR	"Greg Kroah-Hartman <gregkh@us.ibm.com>"
+#define DRIVER_VERSION	"0.4"
+#define DRIVER_AUTHOR	"Greg Kroah-Hartman <gregkh@us.ibm.com>, Takayoshi Kochi <t-kouchi@cq.jp.nec.com>"
 #define DRIVER_DESC	"ACPI Hot Plug PCI Controller Driver"
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
@@ -72,17 +74,21 @@
 static int get_attention_status	(struct hotplug_slot *slot, u8 *value);
 static int get_latch_status	(struct hotplug_slot *slot, u8 *value);
 static int get_adapter_status	(struct hotplug_slot *slot, u8 *value);
+static int get_max_bus_speed	(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value);
+static int get_cur_bus_speed	(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value);
 
 static struct hotplug_slot_ops acpi_hotplug_slot_ops = {
-	owner:			THIS_MODULE,
-	enable_slot:		enable_slot,
-	disable_slot:		disable_slot,
-	set_attention_status:	set_attention_status,
-	hardware_test:		hardware_test,
-	get_power_status:	get_power_status,
-	get_attention_status:	get_attention_status,
-	get_latch_status:	get_latch_status,
-	get_adapter_status:	get_adapter_status,
+	.owner			= THIS_MODULE,
+	.enable_slot		= enable_slot,
+	.disable_slot		= disable_slot,
+	.set_attention_status	= set_attention_status,
+	.hardware_test		= hardware_test,
+	.get_power_status	= get_power_status,
+	.get_attention_status	= get_attention_status,
+	.get_latch_status	= get_latch_status,
+	.get_adapter_status	= get_adapter_status,
+	.get_max_bus_speed	= get_max_bus_speed,
+	.get_cur_bus_speed	= get_cur_bus_speed,
 };
 
 
@@ -90,15 +96,15 @@
 static inline int slot_paranoia_check (struct slot *slot, const char *function)
 {
 	if (!slot) {
-		dbg("%s - slot == NULL", function);
+		dbg("%s - slot == NULL\n", function);
 		return -1;
 	}
 	if (slot->magic != SLOT_MAGIC) {
-		dbg("%s - bad magic number for slot", function);
+		dbg("%s - bad magic number for slot\n", function);
 		return -1;
 	}
 	if (!slot->hotplug_slot) {
-		dbg("%s - slot->hotplug_slot == NULL!", function);
+		dbg("%s - slot->hotplug_slot == NULL!\n", function);
 		return -1;
 	}
 	return 0;
@@ -106,16 +112,16 @@
 
 
 static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const char *function)
-{ 
+{
 	struct slot *slot;
 
 	if (!hotplug_slot) {
-		dbg("%s - hotplug_slot == NULL", function);
+		dbg("%s - hotplug_slot == NULL\n", function);
 		return NULL;
 	}
 
 	slot = (struct slot *)hotplug_slot->private;
-	if (slot_paranoia_check (slot, function))
+	if (slot_paranoia_check(slot, function))
                 return NULL;
 	return slot;
 }
@@ -130,16 +136,16 @@
  */
 static int enable_slot (struct hotplug_slot *hotplug_slot)
 {
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
 	int retval = 0;
-	
+
 	if (slot == NULL)
 		return -ENODEV;
 
-	dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
 	/* enable the specified slot */
-	retval = acpiphp_enable_slot (slot->acpi_slot);
+	retval = acpiphp_enable_slot(slot->acpi_slot);
 
 	return retval;
 }
@@ -154,16 +160,16 @@
  */
 static int disable_slot (struct hotplug_slot *hotplug_slot)
 {
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
 	int retval = 0;
 
 	if (slot == NULL)
 		return -ENODEV;
-	
-	dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
 	/* disable the specified slot */
-	retval = acpiphp_disable_slot (slot->acpi_slot);
+	retval = acpiphp_disable_slot(slot->acpi_slot);
 
 	return retval;
 }
@@ -180,8 +186,8 @@
 static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status)
 {
 	int retval = 0;
-	
-	dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
 	switch (status) {
 		case 0:
@@ -208,15 +214,15 @@
  */
 static int hardware_test (struct hotplug_slot *hotplug_slot, u32 value)
 {
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
 	int retval = 0;
-	
+
 	if (slot == NULL)
 		return -ENODEV;
-	
-	dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
 
-	err ("No hardware tests are defined for this driver");
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	err("No hardware tests are defined for this driver\n");
 	retval = -ENODEV;
 
 	return retval;
@@ -234,15 +240,15 @@
  */
 static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value)
 {
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
 	int retval = 0;
-	
+
 	if (slot == NULL)
 		return -ENODEV;
-	
-	dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
 
-	*value = acpiphp_get_power_status (slot->acpi_slot);
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	*value = acpiphp_get_power_status(slot->acpi_slot);
 
 	return retval;
 }
@@ -258,8 +264,8 @@
 static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value)
 {
 	int retval = 0;
-	
-	dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
 	*value = hotplug_slot->info->attention_status;
 
@@ -278,15 +284,15 @@
  */
 static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value)
 {
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
 	int retval = 0;
-	
+
 	if (slot == NULL)
 		return -ENODEV;
-	
-	dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
 
-	*value = acpiphp_get_latch_status (slot->acpi_slot);
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	*value = acpiphp_get_latch_status(slot->acpi_slot);
 
 	return retval;
 }
@@ -303,20 +309,48 @@
  */
 static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value)
 {
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
 	int retval = 0;
-	
+
 	if (slot == NULL)
 		return -ENODEV;
-	
-	dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
 
-	*value = acpiphp_get_adapter_status (slot->acpi_slot);
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	*value = acpiphp_get_adapter_status(slot->acpi_slot);
 
 	return retval;
 }
 
 
+/* return dummy value because ACPI doesn't provide any method... */
+static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
+{
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+
+	if (slot == NULL)
+		return -ENODEV;
+
+	*value = PCI_SPEED_UNKNOWN;
+
+	return 0;
+}
+
+
+/* return dummy value because ACPI doesn't provide any method... */
+static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
+{
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+
+	if (slot == NULL)
+		return -ENODEV;
+
+	*value = PCI_SPEED_UNKNOWN;
+
+	return 0;
+}
+
+
 static int init_acpi (void)
 {
 	int retval;
@@ -335,13 +369,6 @@
 }
 
 
-static void exit_acpi (void)
-{
-	/* deallocate internal data structures etc. */
-	acpiphp_glue_exit();
-}
-
-
 /**
  * make_slot_name - make a slot name that appears in pcihpfs
  * @slot: slot to name
@@ -349,7 +376,10 @@
  */
 static void make_slot_name (struct slot *slot)
 {
-	snprintf (slot->hotplug_slot->name, SLOT_NAME_SIZE, "ACPI%x", slot->acpi_slot->sun);
+	snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "ACPI%d-%02x:%02x",
+		 slot->acpi_slot->sun,
+		 slot->acpi_slot->bridge->bus,
+		 slot->acpi_slot->device);
 }
 
 /**
@@ -363,31 +393,31 @@
 	int i;
 
 	for (i = 0; i < num_slots; ++i) {
-		slot = kmalloc (sizeof (struct slot), GFP_KERNEL);
+		slot = kmalloc(sizeof(struct slot), GFP_KERNEL);
 		if (!slot)
 			return -ENOMEM;
 		memset(slot, 0, sizeof(struct slot));
 
-		slot->hotplug_slot = kmalloc (sizeof (struct hotplug_slot), GFP_KERNEL);
+		slot->hotplug_slot = kmalloc(sizeof(struct hotplug_slot), GFP_KERNEL);
 		if (!slot->hotplug_slot) {
-			kfree (slot);
+			kfree(slot);
 			return -ENOMEM;
 		}
-		memset(slot->hotplug_slot, 0, sizeof (struct hotplug_slot));
+		memset(slot->hotplug_slot, 0, sizeof(struct hotplug_slot));
 
-		slot->hotplug_slot->info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL);
+		slot->hotplug_slot->info = kmalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL);
 		if (!slot->hotplug_slot->info) {
-			kfree (slot->hotplug_slot);
-			kfree (slot);
+			kfree(slot->hotplug_slot);
+			kfree(slot);
 			return -ENOMEM;
 		}
-		memset(slot->hotplug_slot->info, 0, sizeof (struct hotplug_slot_info));
+		memset(slot->hotplug_slot->info, 0, sizeof(struct hotplug_slot_info));
 
-		slot->hotplug_slot->name = kmalloc (SLOT_NAME_SIZE, GFP_KERNEL);
+		slot->hotplug_slot->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL);
 		if (!slot->hotplug_slot->name) {
-			kfree (slot->hotplug_slot->info);
-			kfree (slot->hotplug_slot);
-			kfree (slot);
+			kfree(slot->hotplug_slot->info);
+			kfree(slot->hotplug_slot);
+			kfree(slot);
 			return -ENOMEM;
 		}
 
@@ -397,26 +427,27 @@
 		slot->hotplug_slot->private = slot;
 		slot->hotplug_slot->ops = &acpi_hotplug_slot_ops;
 
-		slot->acpi_slot = get_slot_from_id (i);
+		slot->acpi_slot = get_slot_from_id(i);
 		slot->hotplug_slot->info->power_status = acpiphp_get_power_status(slot->acpi_slot);
 		slot->hotplug_slot->info->attention_status = acpiphp_get_attention_status(slot->acpi_slot);
 		slot->hotplug_slot->info->latch_status = acpiphp_get_latch_status(slot->acpi_slot);
 		slot->hotplug_slot->info->adapter_status = acpiphp_get_adapter_status(slot->acpi_slot);
 
-		make_slot_name (slot);
+		make_slot_name(slot);
 
-		retval = pci_hp_register (slot->hotplug_slot);
+		retval = pci_hp_register(slot->hotplug_slot);
 		if (retval) {
-			err ("pci_hp_register failed with error %d", retval);
-			kfree (slot->hotplug_slot->info);
-			kfree (slot->hotplug_slot->name);
-			kfree (slot->hotplug_slot);
-			kfree (slot);
+			err("pci_hp_register failed with error %d\n", retval);
+			kfree(slot->hotplug_slot->info);
+			kfree(slot->hotplug_slot->name);
+			kfree(slot->hotplug_slot);
+			kfree(slot);
 			return retval;
 		}
 
 		/* add slot to our internal list */
-		list_add (&slot->slot_list, &slot_list);
+		list_add(&slot->slot_list, &slot_list);
+		info("Slot [%s] registered\n", slot->hotplug_slot->name);
 	}
 
 	return retval;
@@ -425,17 +456,17 @@
 
 static void cleanup_slots (void)
 {
-	struct list_head *tmp;
+	struct list_head *tmp, *n;
 	struct slot *slot;
 
-	list_for_each (tmp, &slot_list) {
-		slot = list_entry (tmp, struct slot, slot_list);
-		list_del (&slot->slot_list);
-		pci_hp_deregister (slot->hotplug_slot);
-		kfree (slot->hotplug_slot->info);
-		kfree (slot->hotplug_slot->name);
-		kfree (slot->hotplug_slot);
-		kfree (slot);
+	list_for_each_safe (tmp, n, &slot_list) {
+		slot = list_entry(tmp, struct slot, slot_list);
+		list_del(&slot->slot_list);
+		pci_hp_deregister(slot->hotplug_slot);
+		kfree(slot->hotplug_slot->info);
+		kfree(slot->hotplug_slot->name);
+		kfree(slot->hotplug_slot);
+		kfree(slot);
 	}
 
 	return;
@@ -446,6 +477,10 @@
 {
 	int retval;
 
+	info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
+
+	acpiphp_debug = debug;
+
 	/* read all the ACPI info from the system */
 	retval = init_acpi();
 	if (retval)
@@ -455,7 +490,6 @@
 	if (retval)
 		return retval;
 
-	info (DRIVER_DESC " version: " DRIVER_VERSION);
 	return 0;
 }
 
@@ -463,7 +497,8 @@
 static void __exit acpiphp_exit(void)
 {
 	cleanup_slots();
-	exit_acpi();
+	/* deallocate internal data structures etc. */
+	acpiphp_glue_exit();
 }
 
 module_init(acpiphp_init);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hotplug/acpiphp_glue.c linux-2.4.21-pre6/drivers/hotplug/acpiphp_glue.c
--- linux-2.4.20/drivers/hotplug/acpiphp_glue.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/hotplug/acpiphp_glue.c	2003-03-26 23:49:25.000000000 +0000
@@ -39,12 +39,10 @@
 
 static LIST_HEAD(bridge_list);
 
-static int debug = 1;			/* XXX set 0 after debug */
 #define MY_NAME "acpiphp_glue"
 
 static void handle_hotplug_event_bridge (acpi_handle, u32, void *);
 static void handle_hotplug_event_func (acpi_handle, u32, void *);
-static struct pci_ops *default_ops;
 
 /*
  * initialization & terminatation routines
@@ -90,8 +88,6 @@
 static acpi_status
 is_ejectable_slot (acpi_handle handle, u32 lvl,	void *context, void **rv)
 {
-	acpi_status status;
-	acpi_handle tmp;
 	int *count = (int *)context;
 
 	if (is_ejectable(handle)) {
@@ -157,7 +153,7 @@
 	for (slot = bridge->slots; slot; slot = slot->next)
 		if (slot->device == device) {
 			if (slot->sun != sun)
-				warn("sibling found, but _SUN doesn't match!");
+				warn("sibling found, but _SUN doesn't match!\n");
 			break;
 		}
 
@@ -181,7 +177,7 @@
 
 		bridge->nr_slots++;
 
-		dbg("found ACPI PCI Hotplug slot at PCI %02x:%02x Slot:%d",
+		dbg("found ACPI PCI Hotplug slot at PCI %02x:%02x Slot:%d\n",
 		    slot->bridge->bus, slot->device, slot->sun);
 	}
 
@@ -206,7 +202,7 @@
 					     newfunc);
 
 	if (ACPI_FAILURE(status)) {
-		err("failed to register interrupt notify handler");
+		err("failed to register interrupt notify handler\n");
 		return status;
 	}
 
@@ -306,21 +302,21 @@
 			switch (resource_type) {
 			case ACPI_MEMORY_RANGE:
 				if (cache_attribute == ACPI_PREFETCHABLE_MEMORY) {
-					dbg("resource type: prefetchable memory 0x%x - 0x%x", (u32)min_address_range, (u32)max_address_range);
+					dbg("resource type: prefetchable memory 0x%x - 0x%x\n", (u32)min_address_range, (u32)max_address_range);
 					res = acpiphp_make_resource(min_address_range,
 							    address_length);
 					if (!res) {
-						err("out of memory");
+						err("out of memory\n");
 						return;
 					}
 					res->next = bridge->p_mem_head;
 					bridge->p_mem_head = res;
 				} else {
-					dbg("resource type: memory 0x%x - 0x%x", (u32)min_address_range, (u32)max_address_range);
+					dbg("resource type: memory 0x%x - 0x%x\n", (u32)min_address_range, (u32)max_address_range);
 					res = acpiphp_make_resource(min_address_range,
 							    address_length);
 					if (!res) {
-						err("out of memory");
+						err("out of memory\n");
 						return;
 					}
 					res->next = bridge->mem_head;
@@ -328,22 +324,22 @@
 				}
 				break;
 			case ACPI_IO_RANGE:
-				dbg("resource type: io 0x%x - 0x%x", (u32)min_address_range, (u32)max_address_range);
+				dbg("resource type: io 0x%x - 0x%x\n", (u32)min_address_range, (u32)max_address_range);
 				res = acpiphp_make_resource(min_address_range,
 						    address_length);
 				if (!res) {
-					err("out of memory");
+					err("out of memory\n");
 					return;
 				}
 				res->next = bridge->io_head;
 				bridge->io_head = res;
 				break;
 			case ACPI_BUS_NUMBER_RANGE:
-				dbg("resource type: bus number %d - %d", (u32)min_address_range, (u32)max_address_range);
+				dbg("resource type: bus number %d - %d\n", (u32)min_address_range, (u32)max_address_range);
 				res = acpiphp_make_resource(min_address_range,
 						    address_length);
 				if (!res) {
-					err("out of memory");
+					err("out of memory\n");
 					return;
 				}
 				res->next = bridge->bus_head;
@@ -360,10 +356,9 @@
 	acpiphp_resource_sort_and_combine(&bridge->mem_head);
 	acpiphp_resource_sort_and_combine(&bridge->p_mem_head);
 	acpiphp_resource_sort_and_combine(&bridge->bus_head);
-#if 1
-	info("ACPI _CRS resource:");
+
+	dbg("ACPI _CRS resource:\n");
 	acpiphp_dump_resource(bridge);
-#endif
 }
 
 
@@ -372,7 +367,7 @@
 {
 	const struct list_head *l;
 
-	list_for_each(l, list) {
+	list_for_each (l, list) {
 		struct pci_bus *b = pci_bus_b(l);
 		if (b->number == bus)
 			return b;
@@ -386,7 +381,7 @@
 		}
 	}
 
-	return 0;
+	return NULL;
 }
 
 
@@ -397,7 +392,8 @@
 #if ACPI_CA_VERSION < 0x20020201
 	acpi_buffer buffer;
 #else
-	acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+	acpi_buffer buffer = { .length = ACPI_ALLOCATE_BUFFER,
+			       .pointer = NULL};
 #endif
 	acpi_object *package;
 	int i;
@@ -425,7 +421,7 @@
 #endif
 
 	if (ACPI_FAILURE(status)) {
-		dbg("_HPP evaluation failed");
+		dbg("_HPP evaluation failed\n");
 		return;
 	}
 
@@ -433,13 +429,13 @@
 
 	if (!package || package->type != ACPI_TYPE_PACKAGE ||
 	    package->package.count != 4 || !package->package.elements) {
-		err("invalid _HPP object; ignoring");
+		err("invalid _HPP object; ignoring\n");
 		goto err_exit;
 	}
 
 	for (i = 0; i < 4; i++) {
 		if (package->package.elements[i].type != ACPI_TYPE_INTEGER) {
-			err("invalid _HPP parameter type; ignoring");
+			err("invalid _HPP parameter type; ignoring\n");
 			goto err_exit;
 		}
 	}
@@ -449,7 +445,7 @@
 	bridge->hpp.enable_SERR = package->package.elements[2].integer.value;
 	bridge->hpp.enable_PERR = package->package.elements[3].integer.value;
 
-	dbg("_HPP parameter = (%02x, %02x, %02x, %02x)",
+	dbg("_HPP parameter = (%02x, %02x, %02x, %02x)\n",
 	    bridge->hpp.cache_line_size,
 	    bridge->hpp.latency_timer,
 	    bridge->hpp.enable_SERR,
@@ -484,15 +480,13 @@
 					     bridge);
 
 	if (ACPI_FAILURE(status)) {
-		err("failed to register interrupt notify handler");
+		err("failed to register interrupt notify handler\n");
 	}
 
 	list_add(&bridge->list, &bridge_list);
 
-#if 1
-	dbg("Bridge resource:");
+	dbg("Bridge resource:\n");
 	acpiphp_dump_resource(bridge);
-#endif
 }
 
 
@@ -503,7 +497,8 @@
 #if ACPI_CA_VERSION < 0x20020201
 	acpi_buffer buffer;
 #else
-	acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+	acpi_buffer buffer = { .length = ACPI_ALLOCATE_BUFFER,
+			       .pointer = NULL};
 #endif
 	struct acpiphp_bridge *bridge;
 
@@ -519,7 +514,6 @@
 	bridge->bus = bus;
 
 	bridge->pci_bus = find_pci_bus(&pci_root_buses, bus);
-	bridge->pci_ops = bridge->pci_bus->ops;
 
 	bridge->res_lock = SPIN_LOCK_UNLOCKED;
 
@@ -545,7 +539,7 @@
 #endif
 
 	if (ACPI_FAILURE(status)) {
-		err("failed to decode bridge resources");
+		err("failed to decode bridge resources\n");
 		kfree(bridge);
 		return;
 	}
@@ -565,17 +559,15 @@
 /* allocate and initialize PCI-to-PCI bridge data structure */
 static void add_p2p_bridge (acpi_handle *handle, int seg, int bus, int dev, int fn)
 {
-	acpi_status status;
 	struct acpiphp_bridge *bridge;
 	u8 tmp8;
 	u16 tmp16;
-	u32 tmp;
 	u64 base64, limit64;
 	u32 base, limit, base32u, limit32u;
 
 	bridge = kmalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
 	if (bridge == NULL) {
-		err("out of memory");
+		err("out of memory\n");
 		return;
 	}
 
@@ -587,18 +579,17 @@
 
 	bridge->pci_dev = pci_find_slot(bus, PCI_DEVFN(dev, fn));
 	if (!bridge->pci_dev) {
-		err("Can't get pci_dev");
+		err("Can't get pci_dev\n");
 		kfree(bridge);
 		return;
 	}
 
 	bridge->pci_bus = bridge->pci_dev->subordinate;
 	if (!bridge->pci_bus) {
-		err("This is not a PCI-to-PCI bridge!");
+		err("This is not a PCI-to-PCI bridge!\n");
 		kfree(bridge);
 		return;
 	}
-	bridge->pci_ops = bridge->pci_bus->ops;
 
 	bridge->res_lock = SPIN_LOCK_UNLOCKED;
 
@@ -621,10 +612,10 @@
 		limit = ((limit << 8) & 0xf000) + 0xfff;
 		bridge->io_head = acpiphp_make_resource((u64)base, limit - base + 1);
 		if (!bridge->io_head) {
-			err("out of memory");
+			err("out of memory\n");
 			return;
 		}
-		dbg("16bit I/O range: %04x-%04x",
+		dbg("16bit I/O range: %04x-%04x\n",
 		    (u32)bridge->io_head->base,
 		    (u32)(bridge->io_head->base + bridge->io_head->length - 1));
 		break;
@@ -635,18 +626,18 @@
 		limit = (((u32)tmp16 << 16) | ((limit << 8) & 0xf000)) + 0xfff;
 		bridge->io_head = acpiphp_make_resource((u64)base, limit - base + 1);
 		if (!bridge->io_head) {
-			err("out of memory");
+			err("out of memory\n");
 			return;
 		}
-		dbg("32bit I/O range: %08x-%08x",
+		dbg("32bit I/O range: %08x-%08x\n",
 		    (u32)bridge->io_head->base,
 		    (u32)(bridge->io_head->base + bridge->io_head->length - 1));
 		break;
 	case 0x0f:
-		dbg("I/O space unsupported");
+		dbg("I/O space unsupported\n");
 		break;
 	default:
-		warn("Unknown I/O range type");
+		warn("Unknown I/O range type\n");
 	}
 
 	/* Memory resources (mandatory for P2P bridge) */
@@ -656,10 +647,10 @@
 	limit = ((tmp16 & 0xfff0) << 16) | 0xfffff;
 	bridge->mem_head = acpiphp_make_resource((u64)base, limit - base + 1);
 	if (!bridge->mem_head) {
-		err("out of memory");
+		err("out of memory\n");
 		return;
 	}
-	dbg("32bit Memory range: %08x-%08x",
+	dbg("32bit Memory range: %08x-%08x\n",
 	    (u32)bridge->mem_head->base,
 	    (u32)(bridge->mem_head->base + bridge->mem_head->length-1));
 
@@ -675,10 +666,10 @@
 		limit = ((limit & 0xfff0) << 16) | 0xfffff;
 		bridge->p_mem_head = acpiphp_make_resource((u64)base, limit - base + 1);
 		if (!bridge->p_mem_head) {
-			err("out of memory");
+			err("out of memory\n");
 			return;
 		}
-		dbg("32bit Prefetchable memory range: %08x-%08x",
+		dbg("32bit Prefetchable memory range: %08x-%08x\n",
 		    (u32)bridge->p_mem_head->base,
 		    (u32)(bridge->p_mem_head->base + bridge->p_mem_head->length - 1));
 		break;
@@ -690,10 +681,10 @@
 
 		bridge->p_mem_head = acpiphp_make_resource(base64, limit64 - base64 + 1);
 		if (!bridge->p_mem_head) {
-			err("out of memory");
+			err("out of memory\n");
 			return;
 		}
-		dbg("64bit Prefetchable memory range: %08x%08x-%08x%08x",
+		dbg("64bit Prefetchable memory range: %08x%08x-%08x%08x\n",
 		    (u32)(bridge->p_mem_head->base >> 32),
 		    (u32)(bridge->p_mem_head->base & 0xffffffff),
 		    (u32)((bridge->p_mem_head->base + bridge->p_mem_head->length - 1) >> 32),
@@ -702,7 +693,7 @@
 	case 0x0f:
 		break;
 	default:
-		warn("Unknown prefetchale memory type");
+		warn("Unknown prefetchale memory type\n");
 	}
 
 	init_bridge_misc(bridge);
@@ -719,7 +710,6 @@
 	unsigned long tmp;
 	int seg, bus, device, function;
 	struct pci_dev *dev;
-	u32 val;
 
 	/* get PCI address */
 	seg = (*segbus >> 8) & 0xff;
@@ -731,7 +721,7 @@
 
 	status = acpi_evaluate_integer(handle, "_ADR", NULL, &tmp);
 	if (ACPI_FAILURE(status)) {
-		dbg("%s: _ADR evaluation failure", __FUNCTION__);
+		dbg("%s: _ADR evaluation failure\n", __FUNCTION__);
 		return AE_OK;
 	}
 
@@ -748,7 +738,7 @@
 
 	/* check if this bridge has ejectable slots */
 	if (detect_ejectable_slots(handle) > 0) {
-		dbg("found PCI-to-PCI bridge at PCI %02x:%02x.%d", bus, device, function);
+		dbg("found PCI-to-PCI bridge at PCI %s\n", dev->slot_name);
 		add_p2p_bridge(handle, seg, bus, device, function);
 	}
 
@@ -763,14 +753,13 @@
 	unsigned long tmp;
 	int seg, bus;
 	acpi_handle dummy_handle;
-	int sta = -1;
 
 	/* if the bridge doesn't have _STA, we assume it is always there */
 	status = acpi_get_handle(handle, "_STA", &dummy_handle);
 	if (ACPI_SUCCESS(status)) {
 		status = acpi_evaluate_integer(handle, "_STA", NULL, &tmp);
 		if (ACPI_FAILURE(status)) {
-			dbg("%s: _STA evaluation failure", __FUNCTION__);
+			dbg("%s: _STA evaluation failure\n", __FUNCTION__);
 			return 0;
 		}
 		if ((tmp & ACPI_STA_FUNCTIONING) == 0)
@@ -789,13 +778,13 @@
 	if (ACPI_SUCCESS(status)) {
 		bus = tmp;
 	} else {
-		warn("can't get bus number, assuming 0");
+		warn("can't get bus number, assuming 0\n");
 		bus = 0;
 	}
 
 	/* check if this bridge has ejectable slots */
 	if (detect_ejectable_slots(handle) > 0) {
-		dbg("found PCI host-bus bridge with hot-pluggable slots");
+		dbg("found PCI host-bus bridge with hot-pluggable slots\n");
 		add_host_bridge(handle, seg, bus);
 		return 0;
 	}
@@ -807,7 +796,7 @@
 				     find_p2p_bridge, &tmp, NULL);
 
 	if (ACPI_FAILURE(status))
-		warn("find_p2p_bridge faied (error code = 0x%x)",status);
+		warn("find_p2p_bridge faied (error code = 0x%x)\n",status);
 
 	return 0;
 }
@@ -820,21 +809,23 @@
 	acpi_status status;
 	acpi_device_info info;
 	char objname[5];
-	acpi_buffer buffer = { sizeof(objname), objname };
+	acpi_buffer buffer = { .length = sizeof(objname),
+			       .pointer = objname };
 
 	status = acpi_get_object_info(handle, &info);
 	if (ACPI_FAILURE(status)) {
-		dbg("%s: failed to get bridge information", __FUNCTION__);
+		dbg("%s: failed to get bridge information\n", __FUNCTION__);
 		return AE_OK;		/* continue */
 	}
 
 	info.hardware_id[sizeof(info.hardware_id)-1] = '\0';
 
-	/* TBD check _CID also */
-	if (strcmp(info.hardware_id, ACPI_PCI_HOST_HID) == 0) {
-
+	/* TBD use acpi_get_devices() API */
+	if (info.current_status &&
+	    (info.valid & ACPI_VALID_HID) &&
+	    strcmp(info.hardware_id, ACPI_PCI_HOST_HID) == 0) {
 		acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);
-		dbg("checking PCI-hotplug capable bridges under [%s]", objname);
+		dbg("checking PCI-hotplug capable bridges under [%s]\n", objname);
 		add_bridges(handle);
 	}
 	return AE_OK;
@@ -852,15 +843,15 @@
 	if (slot->flags & SLOT_POWEREDON)
 		goto err_exit;
 
-	list_for_each(l, &slot->funcs) {
+	list_for_each (l, &slot->funcs) {
 		func = list_entry(l, struct acpiphp_func, sibling);
 
 		if (func->flags & FUNC_HAS_PS0) {
-			dbg("%s: executing _PS0 on %02x:%02x.%d", __FUNCTION__,
-			    slot->bridge->bus, slot->device, func->function);
+			dbg("%s: executing _PS0 on %s\n", __FUNCTION__,
+			    func->pci_dev->slot_name);
 			status = acpi_evaluate_object(func->handle, "_PS0", NULL, NULL);
 			if (ACPI_FAILURE(status)) {
-				warn("%s: _PS0 failed", __FUNCTION__);
+				warn("%s: _PS0 failed\n", __FUNCTION__);
 				retval = -1;
 				goto err_exit;
 			}
@@ -890,27 +881,27 @@
 	if ((slot->flags & SLOT_POWEREDON) == 0)
 		goto err_exit;
 
-	list_for_each(l, &slot->funcs) {
+	list_for_each (l, &slot->funcs) {
 		func = list_entry(l, struct acpiphp_func, sibling);
 
 		if (func->flags & FUNC_HAS_PS3) {
-			dbg("%s: executing _PS3 on %02x:%02x.%d", __FUNCTION__,
-			    slot->bridge->bus, slot->device, func->function);
+			dbg("%s: executing _PS3 on %s\n", __FUNCTION__,
+			    func->pci_dev->slot_name);
 			status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL);
 			if (ACPI_FAILURE(status)) {
-				warn("%s: _PS3 failed", __FUNCTION__);
+				warn("%s: _PS3 failed\n", __FUNCTION__);
 				retval = -1;
 				goto err_exit;
 			}
 		}
 	}
 
-	list_for_each(l, &slot->funcs) {
+	list_for_each (l, &slot->funcs) {
 		func = list_entry(l, struct acpiphp_func, sibling);
 
 		if (func->flags & FUNC_HAS_EJ0) {
-			dbg("%s: executing _EJ0 on %02x:%02x.%d", __FUNCTION__,
-			    slot->bridge->bus, slot->device, func->function);
+			dbg("%s: executing _EJ0 on %s\n", __FUNCTION__,
+			    func->pci_dev->slot_name);
 
 			/* _EJ0 method take one argument */
 			arg_list.count = 1;
@@ -920,7 +911,7 @@
 
 			status = acpi_evaluate_object(func->handle, "_EJ0", &arg_list, NULL);
 			if (ACPI_FAILURE(status)) {
-				warn("%s: _EJ0 failed", __FUNCTION__);
+				warn("%s: _EJ0 failed\n", __FUNCTION__);
 				retval = -1;
 				goto err_exit;
 			}
@@ -946,7 +937,6 @@
  */
 static int enable_device (struct acpiphp_slot *slot)
 {
-	acpi_status status;
 	u8 bus;
 	struct pci_dev dev0, *dev;
 	struct pci_bus *child;
@@ -961,7 +951,7 @@
 	dev = pci_find_slot(slot->bridge->bus, PCI_DEVFN(slot->device, 0));
 	if (dev) {
 		/* This case shouldn't happen */
-		err("pci_dev structure already exists.");
+		err("pci_dev structure already exists.\n");
 		retval = -1;
 		goto err_exit;
 	}
@@ -981,7 +971,7 @@
 	dev = pci_scan_slot (&dev0);
 
 	if (!dev) {
-		err("No new device found");
+		err("No new device found\n");
 		retval = -1;
 		goto err_exit;
 	}
@@ -993,7 +983,7 @@
 	}
 
 	/* associate pci_dev to our representation */
-	list_for_each(l, &slot->funcs) {
+	list_for_each (l, &slot->funcs) {
 		func = list_entry(l, struct acpiphp_func, sibling);
 
 		func->pci_dev = pci_find_slot(slot->bridge->bus,
@@ -1010,10 +1000,8 @@
 
 	slot->flags |= SLOT_ENABLED;
 
-#if 1
-	dbg("Available resources:");
+	dbg("Available resources:\n");
 	acpiphp_dump_resource(slot->bridge);
-#endif
 
  err_exit:
 	return retval;
@@ -1028,20 +1016,19 @@
 	int retval = 0;
 	struct acpiphp_func *func;
 	struct list_head *l;
-	acpi_status status;
 
 	/* is this slot already disabled? */
 	if (!(slot->flags & SLOT_ENABLED))
 		goto err_exit;
 
-	list_for_each(l, &slot->funcs) {
+	list_for_each (l, &slot->funcs) {
 		func = list_entry(l, struct acpiphp_func, sibling);
 
 		if (func->pci_dev) {
 			if (acpiphp_unconfigure_function(func) == 0) {
 				func->pci_dev = NULL;
 			} else {
-				err("failed to unconfigure device");
+				err("failed to unconfigure device\n");
 				retval = -1;
 				goto err_exit;
 			}
@@ -1070,12 +1057,11 @@
 {
 	acpi_status status;
 	unsigned long sta = 0;
-	int fn;
 	u32 dvid;
 	struct list_head *l;
 	struct acpiphp_func *func;
 
-	list_for_each(l, &slot->funcs) {
+	list_for_each (l, &slot->funcs) {
 		func = list_entry(l, struct acpiphp_func, sibling);
 
 		if (func->flags & FUNC_HAS_STA) {
@@ -1083,11 +1069,9 @@
 			if (ACPI_SUCCESS(status) && sta)
 				break;
 		} else {
-			pci_read_config_dword_nodev(default_ops,
-						    slot->bridge->bus,
-						    slot->device,
-						    func->function,
-						    PCI_VENDOR_ID, &dvid);
+			pci_bus_read_config_dword(slot->bridge->pci_bus,
+					PCI_DEVFN(slot->device, func->function),
+					PCI_VENDOR_ID, &dvid);
 			if (dvid != 0xffffffff) {
 				sta = ACPI_STA_ALL;
 				break;
@@ -1106,7 +1090,7 @@
 /**
  * handle_hotplug_event_bridge - handle ACPI event on bridges
  *
- * @handle: Notify()'ed acpi_handle 
+ * @handle: Notify()'ed acpi_handle
  * @type: Notify code
  * @context: pointer to acpiphp_bridge structure
  *
@@ -1117,7 +1101,8 @@
 {
 	struct acpiphp_bridge *bridge;
 	char objname[64];
-	acpi_buffer buffer = { sizeof(objname), objname };
+	acpi_buffer buffer = { .length = sizeof(objname),
+			       .pointer = objname };
 
 	bridge = (struct acpiphp_bridge *)context;
 
@@ -1126,28 +1111,28 @@
 	switch (type) {
 	case ACPI_NOTIFY_BUS_CHECK:
 		/* bus re-enumerate */
-		dbg("%s: Bus check notify on %s", __FUNCTION__, objname);
+		dbg("%s: Bus check notify on %s\n", __FUNCTION__, objname);
 		acpiphp_check_bridge(bridge);
 		break;
 
 	case ACPI_NOTIFY_DEVICE_CHECK:
 		/* device check */
-		dbg("%s: Device check notify on %s", __FUNCTION__, objname);
+		dbg("%s: Device check notify on %s\n", __FUNCTION__, objname);
 		acpiphp_check_bridge(bridge);
 		break;
 
 	case ACPI_NOTIFY_DEVICE_WAKE:
 		/* wake event */
-		dbg("%s: Device wake notify on %s", __FUNCTION__, objname);
+		dbg("%s: Device wake notify on %s\n", __FUNCTION__, objname);
 		break;
 
 	case ACPI_NOTIFY_EJECT_REQUEST:
 		/* request device eject */
-		dbg("%s: Device eject notify on %s", __FUNCTION__, objname);
+		dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname);
 		break;
 
 	default:
-		warn("notify_handler: unknown event type 0x%x for %s", type, objname);
+		warn("notify_handler: unknown event type 0x%x for %s\n", type, objname);
 		break;
 	}
 }
@@ -1156,7 +1141,7 @@
 /**
  * handle_hotplug_event_func - handle ACPI event on functions (i.e. slots)
  *
- * @handle: Notify()'ed acpi_handle 
+ * @handle: Notify()'ed acpi_handle
  * @type: Notify code
  * @context: pointer to acpiphp_func structure
  *
@@ -1167,7 +1152,8 @@
 {
 	struct acpiphp_func *func;
 	char objname[64];
-	acpi_buffer buffer = { sizeof(objname), objname };
+	acpi_buffer buffer = { .length = sizeof(objname),
+			       .pointer = objname };
 
 	acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
 
@@ -1176,29 +1162,29 @@
 	switch (type) {
 	case ACPI_NOTIFY_BUS_CHECK:
 		/* bus re-enumerate */
-		dbg("%s: Bus check notify on %s", __FUNCTION__, objname);
+		dbg("%s: Bus check notify on %s\n", __FUNCTION__, objname);
 		acpiphp_enable_slot(func->slot);
 		break;
 
 	case ACPI_NOTIFY_DEVICE_CHECK:
 		/* device check : re-enumerate from parent bus */
-		dbg("%s: Device check notify on %s", __FUNCTION__, objname);
+		dbg("%s: Device check notify on %s\n", __FUNCTION__, objname);
 		acpiphp_check_bridge(func->slot->bridge);
 		break;
 
 	case ACPI_NOTIFY_DEVICE_WAKE:
 		/* wake event */
-		dbg("%s: Device wake notify on %s", __FUNCTION__, objname);
+		dbg("%s: Device wake notify on %s\n", __FUNCTION__, objname);
 		break;
 
 	case ACPI_NOTIFY_EJECT_REQUEST:
 		/* request device eject */
-		dbg("%s: Device eject notify on %s", __FUNCTION__, objname);
+		dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname);
 		acpiphp_disable_slot(func->slot);
 		break;
 
 	default:
-		warn("notify_handler: unknown event type 0x%x for %s", type, objname);
+		warn("notify_handler: unknown event type 0x%x for %s\n", type, objname);
 		break;
 	}
 }
@@ -1215,17 +1201,12 @@
 	if (list_empty(&pci_root_buses))
 		return -1;
 
-	/* set default pci_ops for configuration space operation */
-	default_ops = pci_bus_b(pci_root_buses.next)->ops;
-	if (!default_ops)
-		return -1;
-
 	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
 				     ACPI_UINT32_MAX, find_host_bridge,
 				     NULL, NULL);
 
 	if (ACPI_FAILURE(status)) {
-		err("%s: acpi_walk_namespace() failed", __FUNCTION__);
+		err("%s: acpi_walk_namespace() failed\n", __FUNCTION__);
 		return -1;
 	}
 
@@ -1240,19 +1221,19 @@
  */
 void acpiphp_glue_exit (void)
 {
-	struct list_head *node, *shead, *l, *n;
+	struct list_head *l1, *l2, *n1, *n2;
 	struct acpiphp_bridge *bridge;
 	struct acpiphp_slot *slot, *next;
 	struct acpiphp_func *func;
 	acpi_status status;
 
-	list_for_each(node, &bridge_list) {
-		bridge = (struct acpiphp_bridge *)node;
+	list_for_each_safe (l1, n1, &bridge_list) {
+		bridge = (struct acpiphp_bridge *)l1;
 		slot = bridge->slots;
 		while (slot) {
 			next = slot->next;
-			list_for_each_safe(l, n, &slot->funcs) {
-				func = list_entry(l, struct acpiphp_func, sibling);
+			list_for_each_safe (l2, n2, &slot->funcs) {
+				func = list_entry(l2, struct acpiphp_func, sibling);
 				acpiphp_free_resource(&func->io_head);
 				acpiphp_free_resource(&func->mem_head);
 				acpiphp_free_resource(&func->p_mem_head);
@@ -1261,7 +1242,7 @@
 								    ACPI_SYSTEM_NOTIFY,
 								    handle_hotplug_event_func);
 				if (ACPI_FAILURE(status))
-					err("failed to remove notify handler");
+					err("failed to remove notify handler\n");
 				kfree(func);
 			}
 			kfree(slot);
@@ -1270,7 +1251,7 @@
 		status = acpi_remove_notify_handler(bridge->handle, ACPI_SYSTEM_NOTIFY,
 						    handle_hotplug_event_bridge);
 		if (ACPI_FAILURE(status))
-			err("failed to remove notify handler");
+			err("failed to remove notify handler\n");
 
 		acpiphp_free_resource(&bridge->io_head);
 		acpiphp_free_resource(&bridge->mem_head);
@@ -1293,13 +1274,13 @@
 
 	num_slots = 0;
 
-	list_for_each(node, &bridge_list) {
+	list_for_each (node, &bridge_list) {
 		bridge = (struct acpiphp_bridge *)node;
-		dbg("Bus%d %dslot(s)", bridge->bus, bridge->nr_slots);
+		dbg("Bus%d %dslot(s)\n", bridge->bus, bridge->nr_slots);
 		num_slots += bridge->nr_slots;
 	}
 
-	dbg("Total %dslots", num_slots);
+	dbg("Total %dslots\n", num_slots);
 	return num_slots;
 }
 
@@ -1317,7 +1298,7 @@
 	struct acpiphp_slot *slot;
 	int retval = 0;
 
-	list_for_each(node, &bridge_list) {
+	list_for_each (node, &bridge_list) {
 		bridge = (struct acpiphp_bridge *)node;
 		for (slot = bridge->slots; slot; slot = slot->next) {
 			retval = fn(slot, data);
@@ -1338,7 +1319,7 @@
 	struct acpiphp_bridge *bridge;
 	struct acpiphp_slot *slot;
 
-	list_for_each(node, &bridge_list) {
+	list_for_each (node, &bridge_list) {
 		bridge = (struct acpiphp_bridge *)node;
 		for (slot = bridge->slots; slot; slot = slot->next)
 			if (slot->id == id)
@@ -1346,7 +1327,7 @@
 	}
 
 	/* should never happen! */
-	err("%s: no object for id %d",__FUNCTION__, id);
+	err("%s: no object for id %d\n",__FUNCTION__, id);
 	return 0;
 }
 
@@ -1357,7 +1338,6 @@
 int acpiphp_enable_slot (struct acpiphp_slot *slot)
 {
 	int retval;
-	int online = 0;
 
 	down(&slot->crit_sect);
 
@@ -1381,8 +1361,6 @@
  */
 int acpiphp_disable_slot (struct acpiphp_slot *slot)
 {
-	struct list_head *l;
-	struct acpiphp_func *func;
 	int retval = 0;
 
 	down(&slot->crit_sect);
@@ -1397,14 +1375,12 @@
 	if (retval)
 		goto err_exit;
 
-#if 1
 	acpiphp_resource_sort_and_combine(&slot->bridge->io_head);
 	acpiphp_resource_sort_and_combine(&slot->bridge->mem_head);
 	acpiphp_resource_sort_and_combine(&slot->bridge->p_mem_head);
 	acpiphp_resource_sort_and_combine(&slot->bridge->bus_head);
-	dbg("Available resources:");
+	dbg("Available resources:\n");
 	acpiphp_dump_resource(slot->bridge);
-#endif
 
  err_exit:
 	up(&slot->crit_sect);
@@ -1431,7 +1407,7 @@
 			if (sta != ACPI_STA_ALL) {
 				retval = acpiphp_disable_slot(slot);
 				if (retval) {
-					err("Error occured in enabling");
+					err("Error occured in enabling\n");
 					up(&slot->crit_sect);
 					goto err_exit;
 				}
@@ -1442,7 +1418,7 @@
 			if (sta == ACPI_STA_ALL) {
 				retval = acpiphp_enable_slot(slot);
 				if (retval) {
-					err("Error occured in enabling");
+					err("Error occured in enabling\n");
 					up(&slot->crit_sect);
 					goto err_exit;
 				}
@@ -1451,7 +1427,7 @@
 		}
 	}
 
-	dbg("%s: %d enabled, %d disabled", __FUNCTION__, enabled, disabled);
+	dbg("%s: %d enabled, %d disabled\n", __FUNCTION__, enabled, disabled);
 
  err_exit:
 	return retval;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hotplug/acpiphp_pci.c linux-2.4.21-pre6/drivers/hotplug/acpiphp_pci.c
--- linux-2.4.20/drivers/hotplug/acpiphp_pci.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/hotplug/acpiphp_pci.c	2003-03-26 23:49:34.000000000 +0000
@@ -37,16 +37,14 @@
 #include "pci_hotplug.h"
 #include "acpiphp.h"
 
-static int debug = 1;			/* XXX set 0 after debug */
 #define MY_NAME "acpiphp_pci"
 
 static void acpiphp_configure_irq (struct pci_dev *dev);
 
 
 /* allocate mem/pmem/io resource to a new function */
-static int alloc_resource (struct acpiphp_func *func)
+static int init_config_space (struct acpiphp_func *func)
 {
-	u64 base;
 	u32 bar, len;
 	u32 address[] = {
 		PCI_BASE_ADDRESS_0,
@@ -60,23 +58,22 @@
 	int count;
 	struct acpiphp_bridge *bridge;
 	struct pci_resource *res;
-	struct pci_ops *ops;
-	int bus, device, function;
+	struct pci_bus *bus;
+	int devfn;
 
 	bridge = func->slot->bridge;
-	bus = bridge->bus;
-	device = func->slot->device;
-	function = func->function;
-	ops = bridge->pci_ops;
+	bus = bridge->pci_bus;
+	devfn = PCI_DEVFN(func->slot->device, func->function);
 
 	for (count = 0; address[count]; count++) {	/* for 6 BARs */
-		pci_write_config_dword_nodev (ops, bus, device, function, address[count], 0xFFFFFFFF);
-		pci_read_config_dword_nodev(ops, bus, device, function, address[count], &bar);
+		pci_bus_write_config_dword(bus, devfn, address[count], 0xFFFFFFFF);
+		pci_bus_read_config_dword(bus, devfn, address[count], &bar);
 
 		if (!bar)	/* This BAR is not implemented */
 			continue;
 
-		dbg("Device %02x.%02x BAR %d wants %x", device, function, count, bar);
+		dbg("Device %02x.%d BAR %d wants %x\n", PCI_SLOT(devfn),
+				PCI_FUNC(devfn), count, bar);
 
 		if (bar & PCI_BASE_ADDRESS_SPACE_IO) {
 			/* This is IO */
@@ -84,7 +81,7 @@
 			len = bar & 0xFFFFFFFC;
 			len = ~len + 1;
 
-			dbg ("len in IO %x, BAR %d", len, count);
+			dbg("len in IO %x, BAR %d\n", len, count);
 
 			spin_lock(&bridge->res_lock);
 			res = acpiphp_get_io_resource(&bridge->io_head, len);
@@ -92,10 +89,10 @@
 
 			if (!res) {
 				err("cannot allocate requested io for %02x:%02x.%d len %x\n",
-				    bus, device, function, len);
+				    bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), len);
 				return -1;
 			}
-			pci_write_config_dword_nodev(ops, bus, device, function, address[count], (u32)res->base);
+			pci_bus_write_config_dword(bus, devfn, address[count], (u32)res->base);
 			res->next = func->io_head;
 			func->io_head = res;
 
@@ -107,7 +104,7 @@
 				len = bar & 0xFFFFFFF0;
 				len = ~len + 1;
 
-				dbg("len in PFMEM %x, BAR %d", len, count);
+				dbg("len in PFMEM %x, BAR %d\n", len, count);
 
 				spin_lock(&bridge->res_lock);
 				res = acpiphp_get_resource(&bridge->p_mem_head, len);
@@ -115,16 +112,16 @@
 
 				if (!res) {
 					err("cannot allocate requested pfmem for %02x:%02x.%d len %x\n",
-					    bus, device, function, len);
+					    bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), len);
 					return -1;
 				}
 
-				pci_write_config_dword_nodev(ops, bus, device, function, address[count], (u32)res->base);
+				pci_bus_write_config_dword(bus, devfn, address[count], (u32)res->base);
 
 				if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) {	/* takes up another dword */
-					dbg ("inside the pfmem 64 case, count %d", count);
+					dbg("inside the pfmem 64 case, count %d\n", count);
 					count += 1;
-					pci_write_config_dword_nodev(ops, bus, device, function, address[count], (u32)(res->base >> 32));
+					pci_bus_write_config_dword(bus, devfn, address[count], (u32)(res->base >> 32));
 				}
 
 				res->next = func->p_mem_head;
@@ -136,7 +133,7 @@
 				len = bar & 0xFFFFFFF0;
 				len = ~len + 1;
 
-				dbg("len in MEM %x, BAR %d", len, count);
+				dbg("len in MEM %x, BAR %d\n", len, count);
 
 				spin_lock(&bridge->res_lock);
 				res = acpiphp_get_resource(&bridge->mem_head, len);
@@ -144,17 +141,17 @@
 
 				if (!res) {
 					err("cannot allocate requested pfmem for %02x:%02x.%d len %x\n",
-					    bus, device, function, len);
+					    bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), len);
 					return -1;
 				}
 
-				pci_write_config_dword_nodev(ops, bus, device, function, address[count], (u32)res->base);
+				pci_bus_write_config_dword(bus, devfn, address[count], (u32)res->base);
 
 				if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) {
 					/* takes up another dword */
-					dbg ("inside mem 64 case, reg. mem, count %d", count);
+					dbg("inside mem 64 case, reg. mem, count %d\n", count);
 					count += 1;
-					pci_write_config_dword_nodev(ops, bus, device, function, address[count], (u32)(res->base >> 32));
+					pci_bus_write_config_dword(bus, devfn, address[count], (u32)(res->base >> 32));
 				}
 
 				res->next = func->mem_head;
@@ -165,7 +162,7 @@
 	}
 
 	/* disable expansion rom */
-	pci_write_config_dword_nodev(ops, bus, device, function, PCI_ROM_ADDRESS, 0x00000000);
+	pci_bus_write_config_dword(bus, devfn, PCI_ROM_ADDRESS, 0x00000000);
 
 	return 0;
 }
@@ -203,15 +200,16 @@
 	pci_proc_attach_device(dev);
 #endif
 	pci_announce_device_to_drivers(dev);
+	info("Device %s configured\n", dev->slot_name);
 
 	return 0;
 }
 
 
-static int is_pci_dev_in_use (struct pci_dev* dev) 
+static int is_pci_dev_in_use (struct pci_dev* dev)
 {
-	/* 
-	 * dev->driver will be set if the device is in use by a new-style 
+	/*
+	 * dev->driver will be set if the device is in use by a new-style
 	 * driver -- otherwise, check the device's regions to see if any
 	 * driver has claimed them
 	 */
@@ -253,13 +251,13 @@
 {
 	struct pci_dev *dev = wrapped_dev->dev;
 
-	dbg("attempting removal of driver for device %s", dev->slot_name);
+	dbg("attempting removal of driver for device %s\n", dev->slot_name);
 
 	/* Now, remove the Linux Driver Representation */
 	if (dev->driver) {
 		if (dev->driver->remove) {
 			dev->driver->remove(dev);
-			dbg("driver was properly removed");
+			dbg("driver was properly removed\n");
 		}
 		dev->driver = NULL;
 	}
@@ -276,6 +274,7 @@
 	/* Now, remove the Linux Representation */
 	if (dev) {
 		if (pci_hp_remove_device(dev) == 0) {
+			info("Device %s removed\n", dev->slot_name);
 			kfree(dev); /* Now, remove */
 		} else {
 			return -1; /* problems while freeing, abort visitation */
@@ -313,7 +312,7 @@
 /* detect_used_resource - subtract resource under dev from bridge */
 static int detect_used_resource (struct acpiphp_bridge *bridge, struct pci_dev *dev)
 {
-	u32 bar, len, pin;
+	u32 bar, len;
 	u64 base;
 	u32 address[] = {
 		PCI_BASE_ADDRESS_0,
@@ -327,7 +326,7 @@
 	int count;
 	struct pci_resource *res;
 
-	dbg("Device %s", dev->slot_name);
+	dbg("Device %s\n", dev->slot_name);
 
 	for (count = 0; address[count]; count++) {	/* for 6 BARs */
 		pci_read_config_dword(dev, address[count], &bar);
@@ -344,7 +343,7 @@
 			len &= 0xFFFFFFFC;
 			len = ~len + 1;
 
-			dbg("BAR[%d] %08x - %08x (IO)", count, (u32)base, (u32)base + len - 1);
+			dbg("BAR[%d] %08x - %08x (IO)\n", count, (u32)base, (u32)base + len - 1);
 
 			spin_lock(&bridge->res_lock);
 			res = acpiphp_get_resource_with_base(&bridge->io_head, base, len);
@@ -361,10 +360,10 @@
 				len = ~len + 1;
 
 				if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) {	/* takes up another dword */
-					dbg ("prefetch mem 64");
+					dbg("prefetch mem 64\n");
 					count += 1;
 				}
-				dbg("BAR[%d] %08x - %08x (PMEM)", count, (u32)base, (u32)base + len - 1);
+				dbg("BAR[%d] %08x - %08x (PMEM)\n", count, (u32)base, (u32)base + len - 1);
 				spin_lock(&bridge->res_lock);
 				res = acpiphp_get_resource_with_base(&bridge->p_mem_head, base, len);
 				spin_unlock(&bridge->res_lock);
@@ -378,10 +377,10 @@
 
 				if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) {
 					/* takes up another dword */
-					dbg ("mem 64");
+					dbg("mem 64\n");
 					count += 1;
 				}
-				dbg("BAR[%d] %08x - %08x (MEM)", count, (u32)base, (u32)base + len - 1);
+				dbg("BAR[%d] %08x - %08x (MEM)\n", count, (u32)base, (u32)base + len - 1);
 				spin_lock(&bridge->res_lock);
 				res = acpiphp_get_resource_with_base(&bridge->mem_head, base, len);
 				spin_unlock(&bridge->res_lock);
@@ -403,7 +402,7 @@
 	struct list_head *l;
 	struct pci_dev *dev;
 
-	list_for_each(l, &bus->devices) {
+	list_for_each (l, &bus->devices) {
 		dev = pci_dev_b(l);
 		detect_used_resource(bridge, dev);
 		/* XXX recursive call */
@@ -421,9 +420,6 @@
  */
 int acpiphp_detect_pci_resource (struct acpiphp_bridge *bridge)
 {
-	struct list_head *l;
-	struct pci_dev *dev;
-
 	detect_used_resource_bus(bridge, bridge->pci_bus);
 
 	return 0;
@@ -452,20 +448,19 @@
 	};
 	int count;
 	struct pci_resource *res;
-	struct pci_ops *ops;
 	struct pci_dev *dev;
 
 	dev = func->pci_dev;
-	dbg("Hot-pluggable device %s", dev->slot_name);
+	dbg("Hot-pluggable device %s\n", dev->slot_name);
 
 	for (count = 0; address[count]; count++) {	/* for 6 BARs */
-		pci_read_config_dword (dev, address[count], &bar);
+		pci_read_config_dword(dev, address[count], &bar);
 
 		if (!bar)	/* This BAR is not implemented */
 			continue;
 
-		pci_write_config_dword (dev, address[count], 0xFFFFFFFF);
-		pci_read_config_dword (dev, address[count], &len);
+		pci_write_config_dword(dev, address[count], 0xFFFFFFFF);
+		pci_read_config_dword(dev, address[count], &len);
 
 		if (len & PCI_BASE_ADDRESS_SPACE_IO) {
 			/* This is IO */
@@ -473,7 +468,7 @@
 			len &= 0xFFFFFFFC;
 			len = ~len + 1;
 
-			dbg("BAR[%d] %08x - %08x (IO)", count, (u32)base, (u32)base + len - 1);
+			dbg("BAR[%d] %08x - %08x (IO)\n", count, (u32)base, (u32)base + len - 1);
 
 			res = acpiphp_make_resource(base, len);
 			if (!res)
@@ -492,10 +487,10 @@
 				len = ~len + 1;
 
 				if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) {	/* takes up another dword */
-					dbg ("prefetch mem 64");
+					dbg("prefetch mem 64\n");
 					count += 1;
 				}
-				dbg("BAR[%d] %08x - %08x (PMEM)", count, (u32)base, (u32)base + len - 1);
+				dbg("BAR[%d] %08x - %08x (PMEM)\n", count, (u32)base, (u32)base + len - 1);
 				res = acpiphp_make_resource(base, len);
 				if (!res)
 					goto no_memory;
@@ -511,10 +506,10 @@
 
 				if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) {
 					/* takes up another dword */
-					dbg ("mem 64");
+					dbg("mem 64\n");
 					count += 1;
 				}
-				dbg("BAR[%d] %08x - %08x (MEM)", count, (u32)base, (u32)base + len - 1);
+				dbg("BAR[%d] %08x - %08x (MEM)\n", count, (u32)base, (u32)base + len - 1);
 				res = acpiphp_make_resource(base, len);
 				if (!res)
 					goto no_memory;
@@ -525,7 +520,7 @@
 			}
 		}
 
-		pci_write_config_dword (dev, address[count], bar);
+		pci_write_config_dword(dev, address[count], bar);
 	}
 #if 1
 	acpiphp_dump_func_resource(func);
@@ -534,7 +529,7 @@
 	return 0;
 
  no_memory:
-	err("out of memory");
+	err("out of memory\n");
 	acpiphp_free_resource(&func->io_head);
 	acpiphp_free_resource(&func->mem_head);
 	acpiphp_free_resource(&func->p_mem_head);
@@ -560,23 +555,22 @@
 	int retval = 0;
 	int is_multi = 0;
 
-	pci_read_config_byte_nodev(slot->bridge->pci_ops,
-				   slot->bridge->bus, slot->device, 0,
-				   PCI_HEADER_TYPE, &hdr);
+	pci_bus_read_config_byte(slot->bridge->pci_bus,
+					PCI_DEVFN(slot->device, 0),
+					PCI_HEADER_TYPE, &hdr);
 
 	if (hdr & 0x80)
 		is_multi = 1;
 
-	list_for_each(l, &slot->funcs) {
+	list_for_each (l, &slot->funcs) {
 		func = list_entry(l, struct acpiphp_func, sibling);
 		if (is_multi || func->function == 0) {
-			pci_read_config_dword_nodev(slot->bridge->pci_ops,
-						    slot->bridge->bus,
-						    slot->device,
-						    func->function,
+			pci_bus_read_config_dword(slot->bridge->pci_bus,
+						    PCI_DEVFN(slot->device,
+								func->function),
 						    PCI_VENDOR_ID, &dvid);
 			if (dvid != 0xffffffff) {
-				retval = alloc_resource(func);
+				retval = init_config_space(func);
 				if (retval)
 					break;
 			}
@@ -589,16 +583,16 @@
 
 /* for pci_visit_dev() */
 static struct pci_visit configure_functions = {
-	post_visit_pci_dev:	configure_pci_dev
+	.post_visit_pci_dev =	configure_pci_dev
 };
 
 static struct pci_visit unconfigure_functions_phase1 = {
-	post_visit_pci_dev:	unconfigure_pci_dev_driver
+	.post_visit_pci_dev =	unconfigure_pci_dev_driver
 };
 
 static struct pci_visit unconfigure_functions_phase2 = {
-	post_visit_pci_bus:	unconfigure_pci_bus,
-	post_visit_pci_dev:	unconfigure_pci_dev
+	.post_visit_pci_bus =	unconfigure_pci_bus,
+	.post_visit_pci_dev =	unconfigure_pci_dev
 };
 
 
@@ -647,7 +641,6 @@
 int acpiphp_unconfigure_function (struct acpiphp_func *func)
 {
 	struct acpiphp_bridge *bridge;
-	struct pci_resource *tmp;
 	struct pci_dev_wrapped wrapped_dev;
 	struct pci_bus_wrapped wrapped_bus;
 	int retval = 0;
@@ -686,45 +679,6 @@
 }
 
 
-/* XXX IA64 specific */
-#ifdef CONFIG_IA64
-static int ia64_get_irq(struct pci_dev *dev, int pin)
-{
-	extern int pci_pin_to_vector(int bus, int slot, int pci_pin);
-	int irq;
-
-	irq = pci_pin_to_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin);
-
-	if (irq < 0 && dev->bus->parent) {
-		/* go back to the bridge */
-		struct pci_dev *bridge = dev->bus->self;
-
-		if (bridge) {
-			/* allow for multiple bridges on an adapter */
-			do {
-				/* do the bridge swizzle... */
-				pin = (pin + PCI_SLOT(dev->devfn)) % 4;
-				irq = pci_pin_to_vector(bridge->bus->number,
-							PCI_SLOT(bridge->devfn),
-							   pin);
-			} while (irq < 0 && (bridge = bridge->bus->self));
-		}
-		if (irq >= 0)
-			printk(KERN_WARNING
-			       "PCI: using PPB(B%d,I%d,P%d) to get vector %02x\n",
-			       dev->bus->number, PCI_SLOT(dev->devfn),
-			       pin, irq);
-		else
-			printk(KERN_WARNING
-			       "PCI: Couldn't map irq for (B%d,I%d,P%d)\n",
-			       dev->bus->number, PCI_SLOT(dev->devfn), pin);
-	}
-
-	return irq;
-}
-#endif
-
-
 /*
  * acpiphp_configure_irq - configure PCI_INTERRUPT_PIN
  *
@@ -740,24 +694,10 @@
  */
 static void acpiphp_configure_irq (struct pci_dev *dev)
 {
-#if CONFIG_IA64		    /* XXX IA64 specific, need i386 version */
-	int bus, device, function, irq;
-	u8 tmp;
-
-	bus = dev->bus->number;
-	device = PCI_SLOT(dev->devfn);
-	function = PCI_FUNC(dev->devfn);
-
-	pci_read_config_byte (dev, PCI_INTERRUPT_PIN, &tmp);
-
-	if ((tmp > 0x00) && (tmp < 0x05)) {
-		irq = ia64_get_irq(dev, tmp - 1);
-		if (irq > 0) {
-			dev->irq = irq;
-			pci_write_config_byte (dev, PCI_INTERRUPT_LINE, irq);
-		} else {
-			err("Couldn't get IRQ for INT%c", 'A' + tmp - 1);
-		}
-	}
+#if CONFIG_IA64		    /* XXX IA64 specific */
+	extern void iosapic_fixup_pci_interrupt (struct pci_dev *dev);
+
+	iosapic_fixup_pci_interrupt(dev);
+	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
 #endif
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hotplug/acpiphp_res.c linux-2.4.21-pre6/drivers/hotplug/acpiphp_res.c
--- linux-2.4.20/drivers/hotplug/acpiphp_res.c	2002-11-28 23:53:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/hotplug/acpiphp_res.c	2003-03-26 23:49:35.000000000 +0000
@@ -59,8 +59,6 @@
 
 #define MY_NAME "acpiphp_res"
 
-/* local variables */
-static int debug = 0;
 
 /*
  * sort_by_size - sort nodes by their length, smallest first
@@ -275,7 +273,7 @@
 
 	for (max = *head;max; max = max->next) {
 
-		/* If not big enough we could probably just bail, 
+		/* If not big enough we could probably just bail,
 		   instead we'll continue to the next. */
 		if (max->length < size)
 			continue;
@@ -372,13 +370,13 @@
 		return NULL;
 
 	for (node = *head; node; node = node->next) {
-		dbg("%s: req_size =%x node=%p, base=%x, length=%x",
+		dbg("%s: req_size =%x node=%p, base=%x, length=%x\n",
 		    __FUNCTION__, size, node, (u32)node->base, node->length);
 		if (node->length < size)
 			continue;
 
 		if (node->base & (size - 1)) {
-			dbg("%s: not aligned", __FUNCTION__);
+			dbg("%s: not aligned\n", __FUNCTION__);
 			/* this one isn't base aligned properly
 			   so we'll make a new entry and split it up */
 			temp_qword = (node->base | (size-1)) + 1;
@@ -402,7 +400,7 @@
 
 		/* Don't need to check if too small since we already did */
 		if (node->length > size) {
-			dbg("%s: too big", __FUNCTION__);
+			dbg("%s: too big\n", __FUNCTION__);
 			/* this one is longer than we need
 			   so we'll make a new entry and split it up */
 			split_node = acpiphp_make_resource(node->base + size, node->length - size);
@@ -417,7 +415,7 @@
 			node->next = split_node;
 		}  /* End of too big on top end */
 
-		dbg("%s: got one!!!", __FUNCTION__);
+		dbg("%s: got one!!!\n", __FUNCTION__);
 		/* If we got here, then it is the right size
 		   Now take it out of the list */
 		if (*head == node) {
@@ -439,7 +437,7 @@
 /**
  * get_resource_with_base - get resource with specific base address
  *
- * this function 
+ * this function
  * returns the first node of "size" length located at specified base address.
  * If it finds a node larger than "size" it will split it up.
  *
@@ -460,7 +458,7 @@
 		return NULL;
 
 	for (node = *head; node; node = node->next) {
-		dbg(": 1st req_base=%x req_size =%x node=%p, base=%x, length=%x",
+		dbg(": 1st req_base=%x req_size =%x node=%p, base=%x, length=%x\n",
 		    (u32)base, size, node, (u32)node->base, node->length);
 		if (node->base > base)
 			continue;
@@ -469,7 +467,7 @@
 			continue;
 
 		if (node->base < base) {
-			dbg(": split 1");
+			dbg(": split 1\n");
 			/* this one isn't base aligned properly
 			   so we'll make a new entry and split it up */
 			temp_qword = base;
@@ -491,12 +489,12 @@
 			node->next = split_node;
 		}
 
-		dbg(": 2nd req_base=%x req_size =%x node=%p, base=%x, length=%x",
+		dbg(": 2nd req_base=%x req_size =%x node=%p, base=%x, length=%x\n",
 		    (u32)base, size, node, (u32)node->base, node->length);
 
 		/* Don't need to check if too small since we already did */
 		if (node->length > size) {
-			dbg(": split 2");
+			dbg(": split 2\n");
 			/* this one is longer than we need
 			   so we'll make a new entry and split it up */
 			split_node = acpiphp_make_resource(node->base + size, node->length - size);
@@ -511,7 +509,7 @@
 			node->next = split_node;
 		}  /* End of too big on top end */
 
-		dbg(": got one!!!");
+		dbg(": got one!!!\n");
 		/* If we got here, then it is the right size
 		   Now take it out of the list */
 		if (*head == node) {
@@ -549,13 +547,13 @@
 	if (!(*head))
 		return 1;
 
-	dbg("*head->next = %p",(*head)->next);
+	dbg("*head->next = %p\n",(*head)->next);
 
 	if (!(*head)->next)
 		return 0;	/* only one item on the list, already sorted! */
 
-	dbg("*head->base = 0x%x",(u32)(*head)->base);
-	dbg("*head->next->base = 0x%x", (u32)(*head)->next->base);
+	dbg("*head->base = 0x%x\n",(u32)(*head)->base);
+	dbg("*head->next->base = 0x%x\n", (u32)(*head)->next->base);
 	while (out_of_order) {
 		out_of_order = 0;
 
@@ -589,7 +587,7 @@
 	while (node1 && node1->next) {
 		if ((node1->base + node1->length) == node1->next->base) {
 			/* Combine */
-			dbg("8..");
+			dbg("8..\n");
 			node1->length += node1->next->length;
 			node2 = node1->next;
 			node1->next = node1->next->next;
@@ -670,39 +668,32 @@
 	cnt = 0;
 
 	while (p) {
-		info("[%02d] %08x - %08x",
-		     cnt++, (u32)p->base, (u32)p->base + p->length - 1);
+		dbg("[%02d] %08x - %08x\n",
+		    cnt++, (u32)p->base, (u32)p->base + p->length - 1);
 		p = p->next;
 	}
 }
 
 void acpiphp_dump_resource(struct acpiphp_bridge *bridge)
 {
-	info("I/O resource:");
+	dbg("I/O resource:\n");
 	dump_resource(bridge->io_head);
-	info("MEM resource:");
+	dbg("MEM resource:\n");
 	dump_resource(bridge->mem_head);
-	info("PMEM resource:");
+	dbg("PMEM resource:\n");
 	dump_resource(bridge->p_mem_head);
-	info("BUS resource:");
+	dbg("BUS resource:\n");
 	dump_resource(bridge->bus_head);
 }
 
 void acpiphp_dump_func_resource(struct acpiphp_func *func)
 {
-	info("I/O resource:");
+	dbg("I/O resource:\n");
 	dump_resource(func->io_head);
-	info("MEM resource:");
+	dbg("MEM resource:\n");
 	dump_resource(func->mem_head);
-	info("PMEM resource:");
+	dbg("PMEM resource:\n");
 	dump_resource(func->p_mem_head);
-	info("BUS resource:");
+	dbg("BUS resource:\n");
 	dump_resource(func->bus_head);
 }
-
-/*
-EXPORT_SYMBOL(acpiphp_get_io_resource);
-EXPORT_SYMBOL(acpiphp_get_max_resource);
-EXPORT_SYMBOL(acpiphp_get_resource);
-EXPORT_SYMBOL(acpiphp_resource_sort_and_combine);
-*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hotplug/pci_hotplug.h linux-2.4.21-pre6/drivers/hotplug/pci_hotplug.h
--- linux-2.4.20/drivers/hotplug/pci_hotplug.h	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/hotplug/pci_hotplug.h	2003-03-26 23:49:29.000000000 +0000
@@ -167,6 +167,18 @@
 				 struct pci_dev_wrapped *wrapped_dev,
 				 struct pci_bus_wrapped *wrapped_parent);
 
+int pci_bus_read_config_byte (struct pci_bus *bus, unsigned int devfn, int where, u8 *val);
+int pci_bus_read_config_word (struct pci_bus *bus, unsigned int devfn, int where, u16 *val);
+int pci_bus_read_config_dword (struct pci_bus *bus, unsigned int devfn, int where, u32 *val);
+int pci_bus_write_config_byte(struct pci_bus *bus, unsigned int devfn, int where, u8 val);
+int pci_bus_write_config_word(struct pci_bus *bus, unsigned int devfn, int where, u16 val);
+int pci_bus_write_config_dword(struct pci_bus *bus, unsigned int devfn, int where, u32 val);
+
+/*
+ * Compatibility functions.  Don't use these, use the
+ * pci_bus_*() functions above.
+ */
+
 extern int pci_read_config_byte_nodev	(struct pci_ops *ops, u8 bus, u8 device,
 					 u8 function, int where, u8 *val);
 extern int pci_read_config_word_nodev	(struct pci_ops *ops, u8 bus, u8 device,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/hotplug/pci_hotplug_util.c linux-2.4.21-pre6/drivers/hotplug/pci_hotplug_util.c
--- linux-2.4.20/drivers/hotplug/pci_hotplug_util.c	2001-11-09 22:01:22.000000000 +0000
+++ linux-2.4.21-pre6/drivers/hotplug/pci_hotplug_util.c	2003-03-26 23:49:50.000000000 +0000
@@ -50,78 +50,58 @@
 /* local variables */
 static int debug;
 
-
-static int build_dev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, struct pci_dev **pci_dev)
+static int build_dev (struct pci_bus *bus, unsigned int devfn, struct pci_dev **pci_dev)
 {
 	struct pci_dev *my_dev;
-	struct pci_bus *my_bus;
-
-	/* Some validity checks. */
-	if ((function > 7) ||
-	    (slot > 31) ||
-	    (pci_dev == NULL) ||
-	    (ops == NULL))
-		return -ENODEV;
 
 	my_dev = kmalloc (sizeof (struct pci_dev), GFP_KERNEL);
 	if (!my_dev)
 		return -ENOMEM;
-	my_bus = kmalloc (sizeof (struct pci_bus), GFP_KERNEL);
-	if (!my_bus) {
-		kfree (my_dev);
-		return -ENOMEM;
-	}
+
 	memset(my_dev, 0, sizeof(struct pci_dev));
-	memset(my_bus, 0, sizeof(struct pci_bus));
 
-	my_bus->number = bus;
-	my_bus->ops = ops;
-	my_dev->devfn = PCI_DEVFN(slot, function);
-	my_dev->bus = my_bus;
+	my_dev->devfn = devfn;
+	my_dev->bus = bus;
+	my_dev->sysdata = bus->sysdata;
 	*pci_dev = my_dev;
 	return 0;
 }
 
 /**
- * pci_read_config_byte_nodev - read a byte from a pci device
- * @ops: pointer to a &struct pci_ops that will be used to read from the pci device
- * @bus: the bus of the pci device to read from
- * @slot: the pci slot number of the pci device to read from
- * @function: the function of the pci device to read from
- * @where: the location on the pci address space to read from
+ * pci_bus_read_config_byte - read a byte from a pci device
+ * @bus: pointer to the parent bus of the pci device to read from
+ * @devfn: the device / function of the pci device to read from
+ * @where: the location in the pci address space to read from
  * @value: pointer to where to place the data read
  *
  * Like pci_read_config_byte() but works for pci devices that do not have a
  * pci_dev structure set up yet.
  * Returns 0 on success.
  */
-int pci_read_config_byte_nodev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, int where, u8 *value)
+int pci_bus_read_config_byte (struct pci_bus *bus, unsigned int devfn, int where, u8 *value)
 {
 	struct pci_dev *dev = NULL;
 	int result;
 
-	dbg("%p, %d, %d, %d, %d, %p\n", ops, bus, slot, function, where, value);
-	dev = pci_find_slot(bus, PCI_DEVFN(slot, function));
+	dbg("%p, %d, %d, %p\n", bus, devfn, where, value);
+	dev = pci_find_slot(bus->number, devfn);
 	if (dev) {
 		dbg("using native pci_dev\n");
 		return pci_read_config_byte (dev, where, value);
 	}
 	
-	result = build_dev (ops, bus, slot, function, &dev);
+	result = build_dev(bus, devfn, &dev);
 	if (result)
 		return result;
 	result = pci_read_config_byte(dev, where, value);
-	kfree (dev->bus);
 	kfree (dev);
 	return result;
 }
 
 /**
- * pci_read_config_word_nodev - read a word from a pci device
- * @ops: pointer to a &struct pci_ops that will be used to read from the pci device
- * @bus: the bus of the pci device to read from
- * @slot: the pci slot number of the pci device to read from
- * @function: the function of the pci device to read from
+ * pci_bus_read_config_word - read a word from a pci device
+ * @bus: pointer to the parent bus of the pci device to read from
+ * @devfn: the device / function of the pci device to read from
  * @where: the location on the pci address space to read from
  * @value: pointer to where to place the data read
  *
@@ -129,34 +109,30 @@
  * pci_dev structure set up yet. 
  * Returns 0 on success.
  */
-int pci_read_config_word_nodev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, int where, u16 *value)
+int pci_bus_read_config_word (struct pci_bus *bus, unsigned int devfn, int where, u16 *value)
 {
 	struct pci_dev *dev = NULL;
 	int result;
 
-	dbg("%p, %d, %d, %d, %d, %p\n", ops, bus, slot, function, where, value);
-	dev = pci_find_slot(bus, PCI_DEVFN(slot, function));
+	dbg("%p, %d, %d, %p\n", bus, devfn, where, value);
+	dev = pci_find_slot(bus->number, devfn);
 	if (dev) {
 		dbg("using native pci_dev\n");
 		return pci_read_config_word (dev, where, value);
 	}
 	
-	result = build_dev (ops, bus, slot, function, &dev);
+	result = build_dev(bus, devfn, &dev);
 	if (result)
 		return result;
 	result = pci_read_config_word(dev, where, value);
-	kfree (dev->bus);
 	kfree (dev);
 	return result;
 }
 
 /**
- * pci_read_config_dword_nodev - read a dword from a pci device
- * @ops: pointer to a &struct pci_ops that will be used to read from the pci
- * device
- * @bus: the bus of the pci device to read from
- * @slot: the pci slot number of the pci device to read from
- * @function: the function of the pci device to read from
+ * pci_bus_read_config_dword - read a dword from a pci device
+ * @bus: pointer to the parent bus of the pci device to read from
+ * @devfn: the device / function of the pci device to read from
  * @where: the location on the pci address space to read from
  * @value: pointer to where to place the data read
  *
@@ -164,34 +140,30 @@
  * pci_dev structure set up yet. 
  * Returns 0 on success.
  */
-int pci_read_config_dword_nodev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, int where, u32 *value)
+int pci_bus_read_config_dword (struct pci_bus *bus, unsigned int devfn, int where, u32 *value)
 {
 	struct pci_dev *dev = NULL;
 	int result;
 
-	dbg("%p, %d, %d, %d, %d, %p\n", ops, bus, slot, function, where, value);
-	dev = pci_find_slot(bus, PCI_DEVFN(slot, function));
+	dbg("%p, %d, %d, %p\n", bus, devfn, where, value);
+	dev = pci_find_slot(bus->number, devfn);
 	if (dev) {
 		dbg("using native pci_dev\n");
 		return pci_read_config_dword (dev, where, value);
 	}
 	
-	result = build_dev (ops, bus, slot, function, &dev);
+	result = build_dev(bus, devfn, &dev);
 	if (result)
 		return result;
 	result = pci_read_config_dword(dev, where, value);
-	kfree (dev->bus);
 	kfree (dev);
 	return result;
 }
 
 /**
- * pci_write_config_byte_nodev - write a byte to a pci device
- * @ops: pointer to a &struct pci_ops that will be used to write to the pci
- * device
- * @bus: the bus of the pci device to write to
- * @slot: the pci slot number of the pci device to write to
- * @function: the function of the pci device to write to
+ * pci_bus_write_config_byte - write a byte to a pci device
+ * @bus: pointer to the parent bus of the pci device to read from
+ * @devfn: the device / function of the pci device to read from
  * @where: the location on the pci address space to write to
  * @value: the value to write to the pci device
  *
@@ -199,34 +171,30 @@
  * pci_dev structure set up yet. 
  * Returns 0 on success.
  */
-int pci_write_config_byte_nodev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, int where, u8 value)
+int pci_bus_write_config_byte (struct pci_bus *bus, unsigned int devfn, int where, u8 value)
 {
 	struct pci_dev *dev = NULL;
 	int result;
 
-	dbg("%p, %d, %d, %d, %d, %d\n", ops, bus, slot, function, where, value);
-	dev = pci_find_slot(bus, PCI_DEVFN(slot, function));
+	dbg("%p, %d, %d, %d\n", bus, devfn, where, value);
+	dev = pci_find_slot(bus->number, devfn);
 	if (dev) {
 		dbg("using native pci_dev\n");
 		return pci_write_config_byte (dev, where, value);
 	}
 	
-	result = build_dev (ops, bus, slot, function, &dev);
+	result = build_dev(bus, devfn, &dev);
 	if (result)
 		return result;
 	result = pci_write_config_byte(dev, where, value);
-	kfree (dev->bus);
 	kfree (dev);
 	return result;
 }
 
 /**
- * pci_write_config_word_nodev - write a word to a pci device
- * @ops: pointer to a &struct pci_ops that will be used to write to the pci
- * device
- * @bus: the bus of the pci device to write to
- * @slot: the pci slot number of the pci device to write to
- * @function: the function of the pci device to write to
+ * pci_bus_write_config_word - write a word to a pci device
+ * @bus: pointer to the parent bus of the pci device to read from
+ * @devfn: the device / function of the pci device to read from
  * @where: the location on the pci address space to write to
  * @value: the value to write to the pci device
  *
@@ -234,34 +202,30 @@
  * pci_dev structure set up yet. 
  * Returns 0 on success.
  */
-int pci_write_config_word_nodev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, int where, u16 value)
+int pci_bus_write_config_word (struct pci_bus *bus, unsigned int devfn, int where, u16 value)
 {
 	struct pci_dev *dev = NULL;
 	int result;
 
-	dbg("%p, %d, %d, %d, %d, %d\n", ops, bus, slot, function, where, value);
-	dev = pci_find_slot(bus, PCI_DEVFN(slot, function));
+	dbg("%p, %d, %d, %d\n", bus, devfn, where, value);
+	dev = pci_find_slot(bus->number, devfn);
 	if (dev) {
 		dbg("using native pci_dev\n");
 		return pci_write_config_word (dev, where, value);
 	}
 	
-	result = build_dev (ops, bus, slot, function, &dev);
+	result = build_dev(bus, devfn, &dev);
 	if (result)
 		return result;
 	result = pci_write_config_word(dev, where, value);
-	kfree (dev->bus);
 	kfree (dev);
 	return result;
 }
 
 /**
- * pci_write_config_dword_nodev - write a dword to a pci device
- * @ops: pointer to a &struct pci_ops that will be used to write to the pci
- * device
- * @bus: the bus of the pci device to write to
- * @slot: the pci slot number of the pci device to write to
- * @function: the function of the pci device to write to
+ * pci_bus_write_config_dword - write a dword to a pci device
+ * @bus: pointer to the parent bus of the pci device to read from
+ * @devfn: the device / function of the pci device to read from
  * @where: the location on the pci address space to write to
  * @value: the value to write to the pci device
  *
@@ -269,23 +233,22 @@
  * pci_dev structure set up yet. 
  * Returns 0 on success.
  */
-int pci_write_config_dword_nodev (struct pci_ops *ops, u8 bus, u8 slot, u8 function, int where, u32 value)
+int pci_bus_write_config_dword (struct pci_bus *bus, unsigned int devfn, int where, u32 value)
 {
 	struct pci_dev *dev = NULL;
 	int result;
 
-	dbg("%p, %d, %d, %d, %d, %d\n", ops, bus, slot, function, where, value);
-	dev = pci_find_slot(bus, PCI_DEVFN(slot, function));
+	dbg("%p, %d, %d, %d\n", bus, devfn, where, value);
+	dev = pci_find_slot(bus->number, devfn);
 	if (dev) {
 		dbg("using native pci_dev\n");
 		return pci_write_config_dword (dev, where, value);
 	}
 	
-	result = build_dev (ops, bus, slot, function, &dev);
+	result = build_dev(bus, devfn, &dev);
 	if (result)
 		return result;
 	result = pci_write_config_dword(dev, where, value);
-	kfree (dev->bus);
 	kfree (dev);
 	return result;
 }
@@ -392,8 +355,98 @@
 	return result;
 }
 
+/* Compatibility wrapper functions */
+
+static struct pci_bus *alloc_bus(struct pci_ops *ops, u8 bus_nr)
+{
+	struct pci_bus *bus = kmalloc(sizeof(struct pci_bus), GFP_KERNEL);
+	if (!bus)
+		return NULL;
+	memset(bus, 0, sizeof(struct pci_bus));
+	bus->number = bus_nr;
+	bus->ops = ops;
+	return bus;
+}
+
+int pci_read_config_byte_nodev(struct pci_ops *ops, u8 bus_nr, u8 slot, u8 function, int where, u8 *value)
+{
+	int result;
+	struct pci_bus *bus = alloc_bus(ops, bus_nr);
+	if (!bus)
+		return -ENOMEM;
+	result = pci_bus_read_config_byte(bus, PCI_DEVFN(slot, function),
+						where, value);
+	kfree(bus);
+	return result;
+}
+
+int pci_read_config_word_nodev(struct pci_ops *ops, u8 bus_nr, u8 slot, u8 function, int where, u16 *value)
+{
+	int result;
+	struct pci_bus *bus = alloc_bus(ops, bus_nr);
+	if (!bus)
+		return -ENOMEM;
+	result = pci_bus_read_config_word(bus, PCI_DEVFN(slot, function),
+						where, value);
+	kfree(bus);
+	return result;
+}
+
+int pci_read_config_dword_nodev(struct pci_ops *ops, u8 bus_nr, u8 slot, u8 function, int where, u32 *value)
+{
+	int result;
+	struct pci_bus *bus = alloc_bus(ops, bus_nr);
+	if (!bus)
+		return -ENOMEM;
+	result = pci_bus_read_config_dword(bus, PCI_DEVFN(slot, function),
+						where, value);
+	kfree(bus);
+	return result;
+}
+
+int pci_write_config_byte_nodev(struct pci_ops *ops, u8 bus_nr, u8 slot, u8 function, int where, u8 value)
+{
+	int result;
+	struct pci_bus *bus = alloc_bus(ops, bus_nr);
+	if (!bus)
+		return -ENOMEM;
+	result = pci_bus_write_config_byte(bus, PCI_DEVFN(slot, function),
+						where, value);
+	kfree(bus);
+	return result;
+}
+
+int pci_write_config_word_nodev(struct pci_ops *ops, u8 bus_nr, u8 slot, u8 function, int where, u16 value)
+{
+	int result;
+	struct pci_bus *bus = alloc_bus(ops, bus_nr);
+	if (!bus)
+		return -ENOMEM;
+	result = pci_bus_write_config_word(bus, PCI_DEVFN(slot, function),
+						where, value);
+	kfree(bus);
+	return result;
+}
+
+int pci_write_config_dword_nodev(struct pci_ops *ops, u8 bus_nr, u8 slot, u8 function, int where, u32 value)
+{
+	int result;
+	struct pci_bus *bus = alloc_bus(ops, bus_nr);
+	if (!bus)
+		return -ENOMEM;
+	result = pci_bus_write_config_dword(bus, PCI_DEVFN(slot, function),
+						where, value);
+	kfree(bus);
+	return result;
+}
 
 EXPORT_SYMBOL(pci_visit_dev);
+EXPORT_SYMBOL(pci_bus_read_config_byte);
+EXPORT_SYMBOL(pci_bus_read_config_word);
+EXPORT_SYMBOL(pci_bus_read_config_dword);
+EXPORT_SYMBOL(pci_bus_write_config_byte);
+EXPORT_SYMBOL(pci_bus_write_config_word);
+EXPORT_SYMBOL(pci_bus_write_config_dword);
 EXPORT_SYMBOL(pci_read_config_byte_nodev);
 EXPORT_SYMBOL(pci_read_config_word_nodev);
 EXPORT_SYMBOL(pci_read_config_dword_nodev);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/i2c/Config.in linux-2.4.21-pre6/drivers/i2c/Config.in
--- linux-2.4.20/drivers/i2c/Config.in	2002-02-25 19:37:57.000000000 +0000
+++ linux-2.4.21-pre6/drivers/i2c/Config.in	2003-03-26 23:49:55.000000000 +0000
@@ -13,6 +13,12 @@
       dep_tristate '  Philips style parallel port adapter' CONFIG_I2C_PHILIPSPAR $CONFIG_I2C_ALGOBIT $CONFIG_PARPORT
       dep_tristate '  ELV adapter' CONFIG_I2C_ELV $CONFIG_I2C_ALGOBIT
       dep_tristate '  Velleman K9000 adapter' CONFIG_I2C_VELLEMAN $CONFIG_I2C_ALGOBIT
+      dep_tristate '  NatSemi SCx200 I2C using GPIO pins' CONFIG_SCx200_I2C $CONFIG_SCx200 $CONFIG_I2C_ALGOBIT
+      if [ "$CONFIG_SCx200_I2C" != "n" ]; then
+         int  '    GPIO pin used for SCL' CONFIG_SCx200_I2C_SCL 12
+         int  '    GPIO pin used for SDA' CONFIG_SCx200_I2C_SDA 13
+      fi
+      dep_tristate '  NatSemi SCx200 ACCESS.bus' CONFIG_SCx200_ACB $CONFIG_I2C
    fi
 
    dep_tristate 'I2C PCF 8584 interfaces' CONFIG_I2C_ALGOPCF $CONFIG_I2C
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/i2c/Makefile linux-2.4.21-pre6/drivers/i2c/Makefile
--- linux-2.4.20/drivers/i2c/Makefile	2002-02-25 19:37:57.000000000 +0000
+++ linux-2.4.21-pre6/drivers/i2c/Makefile	2003-03-26 23:48:58.000000000 +0000
@@ -18,6 +18,8 @@
 obj-$(CONFIG_ITE_I2C_ALGO)	+= i2c-algo-ite.o
 obj-$(CONFIG_ITE_I2C_ADAP)	+= i2c-adap-ite.o
 obj-$(CONFIG_I2C_PROC)		+= i2c-proc.o
+obj-$(CONFIG_SCx200_I2C)	+= scx200_i2c.o
+obj-$(CONFIG_SCx200_ACB)	+= scx200_acb.o
 obj-$(CONFIG_I2C_KEYWEST)	+= i2c-keywest.o
 
 # This is needed for automatic patch generation: sensors code starts here
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/i2c/i2c-proc.c linux-2.4.21-pre6/drivers/i2c/i2c-proc.c
--- linux-2.4.20/drivers/i2c/i2c-proc.c	2002-02-25 19:37:57.000000000 +0000
+++ linux-2.4.21-pre6/drivers/i2c/i2c-proc.c	2003-03-26 23:49:39.000000000 +0000
@@ -729,7 +729,7 @@
 			     ||
 			     ((address_data->
 			       ignore_range[i] ==
-			       SENSORS_ANY_I2C_BUS) & !is_isa))
+			       SENSORS_ANY_I2C_BUS) && !is_isa))
 			    && (addr >= address_data->ignore_range[i + 1])
 			    && (addr <= address_data->ignore_range[i + 2])) {
 #ifdef DEBUG
@@ -818,7 +818,7 @@
 		     i += 2) {
 			if (((adapter_id == address_data->probe[i]) ||
 			     ((address_data->
-			       probe[i] == SENSORS_ANY_I2C_BUS) & !is_isa))
+			       probe[i] == SENSORS_ANY_I2C_BUS) && !is_isa))
 			    && (addr == address_data->probe[i + 1])) {
 #ifdef DEBUG
 				printk
@@ -835,7 +835,7 @@
 			    ((adapter_id == address_data->probe_range[i])
 			     ||
 			     ((address_data->probe_range[i] ==
-			       SENSORS_ANY_I2C_BUS) & !is_isa))
+			       SENSORS_ANY_I2C_BUS) && !is_isa))
 			    && (addr >= address_data->probe_range[i + 1])
 			    && (addr <= address_data->probe_range[i + 2])) {
 				found = 1;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/i2c/scx200_acb.c linux-2.4.21-pre6/drivers/i2c/scx200_acb.c
--- linux-2.4.20/drivers/i2c/scx200_acb.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/i2c/scx200_acb.c	2003-03-26 23:49:51.000000000 +0000
@@ -0,0 +1,579 @@
+/*  linux/drivers/i2c/scx200_acb.c 
+
+    Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
+
+    National Semiconductor SCx200 ACCESS.bus support
+    
+    Based on i2c-keywest.c which is:
+        Copyright (c) 2001 Benjamin Herrenschmidt <benh@kernel.crashing.org>
+        Copyright (c) 2000 Philip Edelbrock <phil@stimpy.netroedge.com>
+    
+    This program is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.
+   
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    General Public License for more details.
+   
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/smp_lock.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+#include <linux/scx200.h>
+
+#define NAME "scx200_acb"
+
+MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
+MODULE_DESCRIPTION("NatSemi SCx200 ACCESS.bus Driver");
+MODULE_LICENSE("GPL");
+
+#define MAX_DEVICES 4
+static int base[MAX_DEVICES] = { 0x840 };
+MODULE_PARM(base, "1-4i");
+MODULE_PARM_DESC(base, "Base addresses for the ACCESS.bus controllers");
+
+#define DEBUG 0
+
+#if DEBUG
+#define DBG(x...) printk(KERN_DEBUG NAME ": " x)
+#else
+#define DBG(x...)
+#endif
+
+/* The hardware supports interrupt driven mode too, but I haven't
+   implemented that. */
+#define POLLED_MODE 1
+#define POLL_TIMEOUT (HZ)
+
+enum scx200_acb_state {
+	state_idle,
+	state_address,
+	state_command,
+	state_repeat_start,
+	state_quick,
+	state_read,
+	state_write,
+};
+
+static const char *scx200_acb_state_name[] = {
+	"idle",
+	"address",
+	"command",
+	"repeat_start",
+	"quick",
+	"read",
+	"write",
+};
+
+/* Physical interface */
+struct scx200_acb_iface
+{
+	struct scx200_acb_iface *next;
+	struct i2c_adapter adapter;
+	unsigned base;
+	struct semaphore sem;
+
+	/* State machine data */
+	enum scx200_acb_state state;
+	int result;
+	u8 address_byte;
+	u8 command;
+	u8 *ptr;
+	char needs_reset;
+	unsigned len;
+};
+
+/* Register Definitions */
+#define ACBSDA		(iface->base + 0)
+#define ACBST		(iface->base + 1)
+#define    ACBST_SDAST		0x40 /* SDA Status */
+#define    ACBST_BER		0x20 
+#define    ACBST_NEGACK		0x10 /* Negative Acknowledge */
+#define    ACBST_STASTR		0x08 /* Stall After Start */
+#define    ACBST_MASTER		0x02
+#define ACBCST		(iface->base + 2)
+#define    ACBCST_BB		0x02
+#define ACBCTL1		(iface->base + 3)
+#define    ACBCTL1_STASTRE	0x80
+#define    ACBCTL1_NMINTE	0x40
+#define	   ACBCTL1_ACK		0x10
+#define	   ACBCTL1_STOP		0x02
+#define	   ACBCTL1_START	0x01
+#define ACBADDR		(iface->base + 4)
+#define ACBCTL2		(iface->base + 5)
+#define    ACBCTL2_ENABLE	0x01
+
+/************************************************************************/
+
+static void scx200_acb_machine(struct scx200_acb_iface *iface, u8 status)
+{
+	const char *errmsg;
+
+	DBG("state %s, status = 0x%02x\n", 
+	    scx200_acb_state_name[iface->state], status);
+
+	if (status & ACBST_BER) {
+		errmsg = "bus error";
+		goto error;
+	}
+	if (!(status & ACBST_MASTER)) {
+		errmsg = "not master";
+		goto error;
+	}
+	if (status & ACBST_NEGACK)
+		goto negack;
+
+	switch (iface->state) {
+	case state_idle:
+		printk(KERN_WARNING NAME ": %s, interrupt in idle state\n", 
+		       iface->adapter.name);
+		break;
+
+	case state_address:
+		/* Do a pointer write first */
+		outb(iface->address_byte & ~1, ACBSDA);
+
+		iface->state = state_command;
+		break;
+
+	case state_command:
+		outb(iface->command, ACBSDA);
+
+		if (iface->address_byte & 1)
+			iface->state = state_repeat_start;
+		else
+			iface->state = state_write;
+		break;
+
+	case state_repeat_start:
+		outb(inb(ACBCTL1) | ACBCTL1_START, ACBCTL1);
+		/* fallthrough */
+		
+	case state_quick:
+		if (iface->address_byte & 1) {
+			if (iface->len == 1) 
+				outb(inb(ACBCTL1) | ACBCTL1_ACK, ACBCTL1);
+			else
+				outb(inb(ACBCTL1) & ~ACBCTL1_ACK, ACBCTL1);
+			outb(iface->address_byte, ACBSDA);
+
+			iface->state = state_read;
+		} else {
+			outb(iface->address_byte, ACBSDA);
+
+			iface->state = state_write;
+		}
+		break;
+
+	case state_read:
+		/* Set ACK if receiving the last byte */
+		if (iface->len == 1)
+			outb(inb(ACBCTL1) | ACBCTL1_ACK, ACBCTL1);
+		else
+			outb(inb(ACBCTL1) & ~ACBCTL1_ACK, ACBCTL1);
+
+		*iface->ptr++ = inb(ACBSDA);
+		--iface->len;
+
+		if (iface->len == 0) {
+			iface->result = 0;
+			iface->state = state_idle;
+			outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+		}
+
+		break;
+
+	case state_write:
+		if (iface->len == 0) {
+			iface->result = 0;
+			iface->state = state_idle;
+			outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+			break;
+		}
+		
+		outb(*iface->ptr++, ACBSDA);
+		--iface->len;
+		
+		break;
+	}
+
+	return;
+
+ negack:
+	DBG("negative acknowledge in state %s\n", 
+	    scx200_acb_state_name[iface->state]);
+
+	iface->state = state_idle;
+	iface->result = -ENXIO;
+
+	outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+	outb(ACBST_STASTR | ACBST_NEGACK, ACBST);
+	return;
+
+ error:
+	printk(KERN_ERR NAME ": %s, %s in state %s\n", iface->adapter.name, 
+	       errmsg, scx200_acb_state_name[iface->state]);
+
+	iface->state = state_idle;
+	iface->result = -EIO;
+	iface->needs_reset = 1;
+}
+
+static void scx200_acb_timeout(struct scx200_acb_iface *iface) 
+{
+	printk(KERN_ERR NAME ": %s, timeout in state %s\n", 
+	       iface->adapter.name, scx200_acb_state_name[iface->state]);
+
+	iface->state = state_idle;
+	iface->result = -EIO;
+	iface->needs_reset = 1;
+}
+
+#ifdef POLLED_MODE
+static void scx200_acb_poll(struct scx200_acb_iface *iface)
+{
+	u8 status = 0;
+	unsigned long timeout;
+
+	timeout = jiffies + POLL_TIMEOUT;
+	while (time_before(jiffies, timeout)) {
+		status = inb(ACBST);
+		if ((status & (ACBST_SDAST|ACBST_BER|ACBST_NEGACK)) != 0) {
+			scx200_acb_machine(iface, status);
+			return;
+		}
+		yield();
+	}
+
+	scx200_acb_timeout(iface);
+}
+#endif /* POLLED_MODE */
+
+static void scx200_acb_reset(struct scx200_acb_iface *iface)
+{
+	/* Disable the ACCESS.bus device and Configure the SCL
+           frequency: 16 clock cycles */
+	outb(0x70, ACBCTL2);
+	/* Polling mode */
+	outb(0, ACBCTL1);
+	/* Disable slave address */
+	outb(0, ACBADDR);
+	/* Enable the ACCESS.bus device */
+	outb(inb(ACBCTL2) | ACBCTL2_ENABLE, ACBCTL2);
+	/* Free STALL after START */
+	outb(inb(ACBCTL1) & ~(ACBCTL1_STASTRE | ACBCTL1_NMINTE), ACBCTL1);
+	/* Send a STOP */
+	outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+	/* Clear BER, NEGACK and STASTR bits */
+	outb(ACBST_BER | ACBST_NEGACK | ACBST_STASTR, ACBST);
+	/* Clear BB bit */
+	outb(inb(ACBCST) | ACBCST_BB, ACBCST);
+}
+
+static s32 scx200_acb_smbus_xfer(struct i2c_adapter *adapter,
+				u16 address, unsigned short flags,	
+				char rw, u8 command, int size, 
+				union i2c_smbus_data *data)
+{
+	struct scx200_acb_iface *iface = adapter->data;
+	int len;
+	u8 *buffer;
+	u16 cur_word;
+	int rc;
+
+	switch (size) {
+	case I2C_SMBUS_QUICK:
+	    	len = 0;
+	    	buffer = NULL;
+	    	break;
+	case I2C_SMBUS_BYTE:
+		if (rw == I2C_SMBUS_READ) {
+			len = 1;
+			buffer = &data->byte;
+		} else {
+			len = 1;
+			buffer = &command;
+		}
+	    	break;
+	case I2C_SMBUS_BYTE_DATA:
+	    	len = 1;
+	    	buffer = &data->byte;
+	    	break;
+	case I2C_SMBUS_WORD_DATA:
+		len = 2;
+	    	cur_word = cpu_to_le16(data->word);
+	    	buffer = (u8 *)&cur_word;
+		break;
+	case I2C_SMBUS_BLOCK_DATA:
+	    	len = data->block[0];
+	    	buffer = &data->block[1];
+		break;
+	default:
+	    	return -EINVAL;
+	}
+
+	DBG("size=%d, address=0x%x, command=0x%x, len=%d, read=%d\n",
+	    size, address, command, len, rw == I2C_SMBUS_READ);
+
+	if (!len && rw == I2C_SMBUS_READ) {
+		printk(KERN_WARNING NAME ": %s, zero length read\n", 
+		       adapter->name);
+		return -EINVAL;
+	}
+
+	if (len && !buffer) {
+		printk(KERN_WARNING NAME ": %s, nonzero length but no buffer\n", adapter->name);
+		return -EFAULT;
+	}
+
+	down(&iface->sem);
+
+	iface->address_byte = address<<1;
+	if (rw == I2C_SMBUS_READ)
+		iface->address_byte |= 1;
+	iface->command = command;
+	iface->ptr = buffer;
+	iface->len = len;
+	iface->result = -EINVAL;
+	iface->needs_reset = 0;
+
+	outb(inb(ACBCTL1) | ACBCTL1_START, ACBCTL1);
+
+	if (size == I2C_SMBUS_QUICK || size == I2C_SMBUS_BYTE)
+		iface->state = state_quick;
+	else
+		iface->state = state_address;
+
+#ifdef POLLED_MODE
+	while (iface->state != state_idle)
+		scx200_acb_poll(iface);
+#else /* POLLED_MODE */
+#error Interrupt driven mode not implemented
+#endif /* POLLED_MODE */	
+
+	if (iface->needs_reset)
+		scx200_acb_reset(iface);
+
+	rc = iface->result;
+
+	up(&iface->sem);
+
+	if (rc == 0 && size == I2C_SMBUS_WORD_DATA && rw == I2C_SMBUS_READ)
+	    	data->word = le16_to_cpu(cur_word);
+
+#if DEBUG
+	printk(KERN_DEBUG NAME ": transfer done, result: %d", rc);
+	if (buffer) {
+		int i;
+		printk(" data:");
+		for (i = 0; i < len; ++i)
+			printk(" %02x", buffer[i]);
+	}
+	printk("\n");
+#endif
+
+	return rc;
+}
+
+static u32 scx200_acb_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+	       I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+	       I2C_FUNC_SMBUS_BLOCK_DATA;
+}
+
+static int scx200_acb_reg(struct i2c_client *client)
+{
+	return 0;
+}
+
+static int scx200_acb_unreg(struct i2c_client *client)
+{
+	return 0;
+}
+
+static void scx200_acb_inc_use(struct i2c_adapter *adapter)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void scx200_acb_dec_use(struct i2c_adapter *adapter)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+/* For now, we only handle combined mode (smbus) */
+static struct i2c_algorithm scx200_acb_algorithm = {
+	name:		"NatSemi SCx200 ACCESS.bus",
+	id:		I2C_ALGO_SMBUS,
+	smbus_xfer:	scx200_acb_smbus_xfer,
+	functionality:	scx200_acb_func,
+};
+
+struct scx200_acb_iface *scx200_acb_list;
+
+int scx200_acb_probe(struct scx200_acb_iface *iface)
+{
+	u8 val;
+
+	/* Disable the ACCESS.bus device and Configure the SCL
+           frequency: 16 clock cycles */
+	outb(0x70, ACBCTL2);
+
+	if (inb(ACBCTL2) != 0x70) {
+		DBG("ACBCTL2 readback failed\n");
+		return -ENXIO;
+	}
+
+	outb(inb(ACBCTL1) | ACBCTL1_NMINTE, ACBCTL1);
+
+	val = inb(ACBCTL1);
+	if (val) {
+		DBG("disabled, but ACBCTL1=0x%02x\n", val);
+		return -ENXIO;
+	}
+
+	outb(inb(ACBCTL2) | ACBCTL2_ENABLE, ACBCTL2);
+
+	outb(inb(ACBCTL1) | ACBCTL1_NMINTE, ACBCTL1);
+
+	val = inb(ACBCTL1);
+	if ((val & ACBCTL1_NMINTE) != ACBCTL1_NMINTE) {
+		DBG("enabled, but NMINTE won't be set, ACBCTL1=0x%02x\n", val);
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+static int  __init scx200_acb_create(int base, int index)
+{
+	struct scx200_acb_iface *iface;
+	struct i2c_adapter *adapter;
+	int rc = 0;
+	char description[64];
+
+	iface = kmalloc(sizeof(*iface), GFP_KERNEL);
+	if (!iface) {
+		printk(KERN_ERR NAME ": can't allocate memory\n");
+		rc = -ENOMEM;
+		goto errout;
+	}
+
+	memset(iface, 0, sizeof(*iface));
+	adapter = &iface->adapter;
+	adapter->data = iface;
+	sprintf(adapter->name, "SCx200 ACB%d", index);
+	adapter->id = I2C_ALGO_SMBUS;
+	adapter->algo = &scx200_acb_algorithm;
+	adapter->inc_use = scx200_acb_inc_use;
+	adapter->dec_use = scx200_acb_dec_use;
+	adapter->client_register = scx200_acb_reg;
+	adapter->client_unregister = scx200_acb_unreg;
+
+	init_MUTEX(&iface->sem);
+
+	sprintf(description, "NatSemi SCx200 ACCESS.bus [%s]", adapter->name);
+	if (request_region(base, 8, description) == 0) {
+		printk(KERN_ERR NAME ": %s, can't allocate io 0x%x-0x%x\n", 
+		       adapter->name, base, base + 8-1);
+		rc = -EBUSY;
+		goto errout;
+	}
+	iface->base = base;
+
+	rc = scx200_acb_probe(iface);
+	if (rc) {
+		printk(KERN_WARNING NAME ": %s, probe failed\n", adapter->name);
+		goto errout;
+	}
+
+	scx200_acb_reset(iface);
+
+	if (i2c_add_adapter(adapter) < 0) {
+		printk(KERN_ERR NAME ": %s, failed to register\n", adapter->name);
+		rc = -ENODEV;
+		goto errout;
+	}
+
+	lock_kernel();
+	iface->next = scx200_acb_list;
+	scx200_acb_list = iface;
+	unlock_kernel();
+
+	return 0;
+
+ errout:
+	if (iface) {
+		if (iface->base)
+			release_region(iface->base, 8);
+		kfree(iface);
+	}
+	return rc;
+}
+
+static int __init scx200_acb_init(void)
+{
+	int i;
+	int rc;
+
+	printk(KERN_DEBUG NAME ": NatSemi SCx200 ACCESS.bus Driver\n");
+
+	/* Verify that this really is a SCx200 processor */
+	if (pci_find_device(PCI_VENDOR_ID_NS,
+			    PCI_DEVICE_ID_NS_SCx200_BRIDGE,
+			    NULL) == NULL)
+		return -ENODEV;
+
+	rc = -ENXIO;
+	for (i = 0; i < MAX_DEVICES; ++i) {
+		if (base[i] > 0)
+			rc = scx200_acb_create(base[i], i);
+	}
+	if (scx200_acb_list)
+		return 0;
+	return rc;
+}
+
+static void __exit scx200_acb_cleanup(void)
+{
+	struct scx200_acb_iface *iface;
+	lock_kernel();
+	while ((iface = scx200_acb_list) != NULL) {
+		scx200_acb_list = iface->next;
+		unlock_kernel();
+
+		i2c_del_adapter(&iface->adapter);
+		release_region(iface->base, 8);
+		kfree(iface);
+		lock_kernel();
+	}
+	unlock_kernel();
+}
+
+module_init(scx200_acb_init);
+module_exit(scx200_acb_cleanup);
+
+/*
+    Local variables:
+        compile-command: "make -k -C ../.. SUBDIRS=drivers/i2c modules"
+        c-basic-offset: 8
+    End:
+*/
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/i2c/scx200_i2c.c linux-2.4.21-pre6/drivers/i2c/scx200_i2c.c
--- linux-2.4.20/drivers/i2c/scx200_i2c.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/i2c/scx200_i2c.c	2003-03-26 23:49:39.000000000 +0000
@@ -0,0 +1,156 @@
+/* linux/drivers/i2c/scx200_i2c.c 
+
+   Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
+
+   National Semiconductor SCx200 I2C bus on GPIO pins
+
+   Based on i2c-velleman.c Copyright (C) 1995-96, 2000 Simon G. Vogl
+
+   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/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <asm/io.h>
+
+#include <linux/scx200_gpio.h>
+
+#define NAME "scx200_i2c"
+
+MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
+MODULE_DESCRIPTION("NatSemi SCx200 I2C Driver");
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(scl, "i");
+MODULE_PARM_DESC(scl, "GPIO line for SCL");
+MODULE_PARM(sda, "i");
+MODULE_PARM_DESC(sda, "GPIO line for SDA");
+
+static int scl = CONFIG_SCx200_I2C_SCL;
+static int sda = CONFIG_SCx200_I2C_SDA;
+
+static void scx200_i2c_setscl(void *data, int state)
+{
+	scx200_gpio_set(scl, state);
+}
+
+static void scx200_i2c_setsda(void *data, int state)
+{
+	scx200_gpio_set(sda, state);
+} 
+
+static int scx200_i2c_getscl(void *data)
+{
+	return scx200_gpio_get(scl);
+}
+
+static int scx200_i2c_getsda(void *data)
+{
+	return scx200_gpio_get(sda);
+}
+
+static int scx200_i2c_reg(struct i2c_client *client)
+{
+	return 0;
+}
+
+static int scx200_i2c_unreg(struct i2c_client *client)
+{
+	return 0;
+}
+
+static void scx200_i2c_inc_use(struct i2c_adapter *adap)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void scx200_i2c_dec_use(struct i2c_adapter *adap)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+/* ------------------------------------------------------------------------
+ * Encapsulate the above functions in the correct operations structure.
+ * This is only done when more than one hardware adapter is supported.
+ */
+
+static struct i2c_algo_bit_data scx200_i2c_data = {
+	NULL,
+	scx200_i2c_setsda,
+	scx200_i2c_setscl,
+	scx200_i2c_getsda,
+	scx200_i2c_getscl,
+	10, 10, 100,		/* waits, timeout */
+};
+
+static struct i2c_adapter scx200_i2c_ops = {
+	.name              = "NatSemi SCx200 I2C",
+	.id		   = I2C_HW_B_VELLE,
+	.algo_data	   = &scx200_i2c_data,
+	.inc_use	   = scx200_i2c_inc_use,
+	.dec_use	   = scx200_i2c_dec_use,
+	.client_register   = scx200_i2c_reg,
+	.client_unregister = scx200_i2c_unreg,
+};
+
+int scx200_i2c_init(void)
+{
+	printk(KERN_DEBUG NAME ": NatSemi SCx200 I2C Driver\n");
+
+	if (!scx200_gpio_present()) {
+		printk(KERN_ERR NAME ": no SCx200 gpio pins available\n");
+		return -ENODEV;
+	}
+
+	printk(KERN_DEBUG NAME ": SCL=GPIO%02u, SDA=GPIO%02u\n", 
+	       scl, sda);
+
+	if (scl == -1 || sda == -1 || scl == sda) {
+		printk(KERN_ERR NAME ": scl and sda must be specified\n");
+		return -EINVAL;
+	}
+
+	/* Configure GPIOs as open collector outputs */
+	scx200_gpio_configure(scl, ~2, 5);
+	scx200_gpio_configure(sda, ~2, 5);
+
+	if (i2c_bit_add_bus(&scx200_i2c_ops) < 0) {
+		printk(KERN_ERR NAME ": adapter %s registration failed\n", 
+		       scx200_i2c_ops.name);
+		return -ENODEV;
+	}
+	
+	return 0;
+}
+
+void scx200_i2c_cleanup(void)
+{
+	i2c_bit_del_bus(&scx200_i2c_ops);
+}
+
+module_init(scx200_i2c_init);
+module_exit(scx200_i2c_cleanup);
+
+/*
+    Local variables:
+        compile-command: "make -k -C ../.. SUBDIRS=drivers/i2c modules"
+        c-basic-offset: 8
+    End:
+*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/Config.in linux-2.4.21-pre6/drivers/ide/Config.in
--- linux-2.4.20/drivers/ide/Config.in	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/Config.in	2003-03-26 23:49:54.000000000 +0000
@@ -16,17 +16,6 @@
    dep_mbool '    Use multi-mode by default' CONFIG_IDEDISK_MULTI_MODE $CONFIG_BLK_DEV_IDEDISK
    dep_mbool '    Auto-Geometry Resizing support' CONFIG_IDEDISK_STROKE $CONFIG_BLK_DEV_IDEDISK
 
-   define_bool CONFIG_BLK_DEV_IDEDISK_VENDOR n
-   dep_mbool '    Fujitsu Vendor Specific' CONFIG_BLK_DEV_IDEDISK_FUJITSU $CONFIG_BLK_DEV_IDEDISK_VENDOR
-   dep_mbool '    IBM Vendor Specific' CONFIG_BLK_DEV_IDEDISK_IBM $CONFIG_BLK_DEV_IDEDISK_VENDOR
-   dep_mbool '    Maxtor Vendor Specific' CONFIG_BLK_DEV_IDEDISK_MAXTOR $CONFIG_BLK_DEV_IDEDISK_VENDOR
-   dep_mbool '    Quantum Vendor Specific' CONFIG_BLK_DEV_IDEDISK_QUANTUM $CONFIG_BLK_DEV_IDEDISK_VENDOR
-   dep_mbool '    Seagate Vendor Specific' CONFIG_BLK_DEV_IDEDISK_SEAGATE $CONFIG_BLK_DEV_IDEDISK_VENDOR
-   dep_mbool '    Western Digital Vendor Specific' CONFIG_BLK_DEV_IDEDISK_WD $CONFIG_BLK_DEV_IDEDISK_VENDOR
-
-   define_bool CONFIG_BLK_DEV_COMMERIAL n
-   dep_mbool '    TiVo Commerial Application Specific' CONFIG_BLK_DEV_TIVO $CONFIG_BLK_DEV_COMMERIAL
-
    dep_tristate '  PCMCIA IDE support' CONFIG_BLK_DEV_IDECS $CONFIG_BLK_DEV_IDE $CONFIG_PCMCIA
    dep_tristate '  Include IDE/ATAPI CDROM support' CONFIG_BLK_DEV_IDECD $CONFIG_BLK_DEV_IDE
    dep_tristate '  Include IDE/ATAPI TAPE support' CONFIG_BLK_DEV_IDETAPE $CONFIG_BLK_DEV_IDE
@@ -42,9 +31,9 @@
       dep_bool '    CMD640 enhanced support' CONFIG_BLK_DEV_CMD640_ENHANCED $CONFIG_BLK_DEV_CMD640
       dep_bool '  ISA-PNP EIDE support' CONFIG_BLK_DEV_ISAPNP $CONFIG_ISAPNP
       if [ "$CONFIG_PCI" = "y" ]; then
-	 dep_bool '  RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000 $CONFIG_X86
-	 bool '  Generic PCI IDE chipset support' CONFIG_BLK_DEV_IDEPCI
+	 bool '  PCI IDE chipset support' CONFIG_BLK_DEV_IDEPCI
 	 if [ "$CONFIG_BLK_DEV_IDEPCI" = "y" ]; then
+	    dep_bool '    Generic PCI IDE Chipset Support' CONFIG_BLK_DEV_GENERIC $CONFIG_BLK_DEV_IDEPCI
 	    bool '    Sharing PCI IDE interrupts support' CONFIG_IDEPCI_SHARE_IRQ
 	    bool '    Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA_PCI
 	    bool '    Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD
@@ -53,46 +42,42 @@
             dep_bool '    Enable DMA only for disks ' CONFIG_IDEDMA_ONLYDISK $CONFIG_IDEDMA_PCI_AUTO
 	    define_bool CONFIG_BLK_DEV_IDEDMA $CONFIG_BLK_DEV_IDEDMA_PCI
 	    dep_bool '      ATA Work(s) In Progress (EXPERIMENTAL)' CONFIG_IDEDMA_PCI_WIP $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL
-	    dep_bool '      Attempt to HACK around Chipsets that TIMEOUT (WIP)' CONFIG_BLK_DEV_IDEDMA_TIMEOUT $CONFIG_IDEDMA_PCI_WIP
-	    dep_bool '      Good-Bad DMA Model-Firmware (WIP)' CONFIG_IDEDMA_NEW_DRIVE_LISTINGS $CONFIG_IDEDMA_PCI_WIP
-#	    dep_bool '      Asynchronous DMA support (WIP) (EXPERIMENTAL)' CONFIG_BLK_DEV_ADMA $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_IDEDMA_PCI_WIP $CONFIG_EXPERIMENTAL
-	    define_bool CONFIG_BLK_DEV_ADMA $CONFIG_BLK_DEV_IDEDMA_PCI
-#	    dep_bool '      Tag Command Queue DMA support (WIP) (EXPERIMENTAL)' CONFIG_BLK_DEV_IDEDMA_TCQ $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_IDEDMA_PCI_WIP $CONFIG_EXPERIMENTAL
-
-	    dep_bool '    AEC62XX chipset support' CONFIG_BLK_DEV_AEC62XX $CONFIG_BLK_DEV_IDEDMA_PCI
-	    dep_mbool '      AEC62XX Tuning support' CONFIG_AEC62XX_TUNING $CONFIG_BLK_DEV_AEC62XX
-	    dep_bool '    ALI M15x3 chipset support' CONFIG_BLK_DEV_ALI15X3 $CONFIG_BLK_DEV_IDEDMA_PCI
-	    dep_mbool '      ALI M15x3 WDC support (DANGEROUS)' CONFIG_WDC_ALI15X3 $CONFIG_BLK_DEV_ALI15X3
-	    dep_bool '    AMD Viper support' CONFIG_BLK_DEV_AMD74XX $CONFIG_BLK_DEV_IDEDMA_PCI
-	    dep_mbool '      AMD Viper ATA-66 Override (WIP)' CONFIG_AMD74XX_OVERRIDE $CONFIG_BLK_DEV_AMD74XX $CONFIG_IDEDMA_PCI_WIP
-	    dep_bool '    CMD64X and CMD680 chipset support' CONFIG_BLK_DEV_CMD64X $CONFIG_BLK_DEV_IDEDMA_PCI
-	    dep_bool '    CMD680 chipset tuning support' CONFIG_BLK_DEV_CMD680 $CONFIG_BLK_DEV_CMD64X
-	    dep_bool '    CY82C693 chipset support' CONFIG_BLK_DEV_CY82C693 $CONFIG_BLK_DEV_IDEDMA_PCI
-	    dep_bool '    Cyrix CS5530 MediaGX chipset support' CONFIG_BLK_DEV_CS5530 $CONFIG_BLK_DEV_IDEDMA_PCI
-  	    dep_bool '    HPT34X chipset support' CONFIG_BLK_DEV_HPT34X $CONFIG_BLK_DEV_IDEDMA_PCI
-	    dep_mbool '      HPT34X AUTODMA support (WIP)' CONFIG_HPT34X_AUTODMA $CONFIG_BLK_DEV_HPT34X $CONFIG_IDEDMA_PCI_WIP
-	    dep_bool '    HPT366/368/370 chipset support' CONFIG_BLK_DEV_HPT366 $CONFIG_BLK_DEV_IDEDMA_PCI
-	    if [ "$CONFIG_X86" = "y" -o "$CONFIG_IA64" = "y" -o "$CONFIG_MIPS" = "y" ]; then
-	       dep_mbool '    Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX $CONFIG_BLK_DEV_IDEDMA_PCI
-	       dep_mbool '      PIIXn Tuning support' CONFIG_PIIX_TUNING $CONFIG_BLK_DEV_PIIX $CONFIG_IDEDMA_PCI_AUTO
-	    fi
+#	    dep_bool '      Good-Bad DMA Model-Firmware (WIP)' CONFIG_IDEDMA_NEW_DRIVE_LISTINGS $CONFIG_IDEDMA_PCI_WIP
+            define_bool CONFIG_BLK_DEV_ADMA $CONFIG_BLK_DEV_IDEDMA_PCI
+
+	    dep_tristate '    AEC62XX chipset support' CONFIG_BLK_DEV_AEC62XX $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    ALI M15x3 chipset support' CONFIG_BLK_DEV_ALI15X3 $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_mbool    '      ALI M15x3 WDC support (DANGEROUS)' CONFIG_WDC_ALI15X3 $CONFIG_BLK_DEV_ALI15X3
+	    dep_tristate '    AMD Viper support' CONFIG_BLK_DEV_AMD74XX $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_mbool    '      AMD Viper ATA-66 Override' CONFIG_AMD74XX_OVERRIDE $CONFIG_BLK_DEV_AMD74XX
+	    dep_tristate '    CMD64{3|6|8|9} chipset support' CONFIG_BLK_DEV_CMD64X $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    Compaq Triflex IDE support' CONFIG_BLK_DEV_TRIFLEX $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    CY82C693 chipset support' CONFIG_BLK_DEV_CY82C693 $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    Cyrix CS5530 MediaGX chipset support' CONFIG_BLK_DEV_CS5530 $CONFIG_BLK_DEV_IDEDMA_PCI
+  	    dep_tristate '    HPT34X chipset support' CONFIG_BLK_DEV_HPT34X $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_mbool    '      HPT34X AUTODMA support (WIP)' CONFIG_HPT34X_AUTODMA $CONFIG_BLK_DEV_HPT34X $CONFIG_IDEDMA_PCI_WIP
+	    dep_tristate '    HPT36X/37X chipset support' CONFIG_BLK_DEV_HPT366 $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX $CONFIG_BLK_DEV_IDEDMA_PCI
 	    if [ "$CONFIG_MIPS_ITE8172" = "y" -o "$CONFIG_MIPS_IVR" = "y" ]; then
 	       dep_mbool '    IT8172 IDE support' CONFIG_BLK_DEV_IT8172 $CONFIG_BLK_DEV_IDEDMA_PCI
-	       dep_mbool '      IT8172 IDE Tuning support' CONFIG_IT8172_TUNING $CONFIG_BLK_DEV_IT8172 $CONFIG_IDEDMA_PCI_AUTO
 	    fi
-	    dep_bool '    NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL
-	    dep_bool '    OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621 $CONFIG_EXPERIMENTAL
-#	    dep_mbool '   Pacific Digital A-DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC_ADMA $CONFIG_BLK_DEV_ADMA $CONFIG_IDEDMA_PCI_WIP $CONFIG_EXPERIMENTAL
-	    dep_bool '    PROMISE PDC202{46|62|65|67|68|69|70} support' CONFIG_BLK_DEV_PDC202XX $CONFIG_BLK_DEV_IDEDMA_PCI
-	    dep_bool '      Special UDMA Feature' CONFIG_PDC202XX_BURST $CONFIG_BLK_DEV_PDC202XX
-	    dep_bool '      Special FastTrak Feature' CONFIG_PDC202XX_FORCE $CONFIG_BLK_DEV_PDC202XX
-	    dep_bool '    ServerWorks OSB4/CSB5 chipsets support' CONFIG_BLK_DEV_SVWKS $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86
-	    dep_bool '    SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86
-	    dep_bool '    SLC90E66 chipset support' CONFIG_BLK_DEV_SLC90E66 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86
-	    dep_bool '    Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL
-	    dep_bool '    VIA82CXXX chipset support' CONFIG_BLK_DEV_VIA82CXXX $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    NS87415 chipset support' CONFIG_BLK_DEV_NS87415 $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621 $CONFIG_EXPERIMENTAL
+	    dep_tristate '    PROMISE PDC202{46|62|65|67} support' CONFIG_BLK_DEV_PDC202XX_OLD $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_bool     '      Special UDMA Feature' CONFIG_PDC202XX_BURST $CONFIG_BLK_DEV_PDC202XX_OLD $CONFI_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    PROMISE PDC202{68|69|70|71|75|76|77} support' CONFIG_BLK_DEV_PDC202XX_NEW $CONFIG_BLK_DEV_IDEDMA_PCI
+		# FIXME - probably wants to be one for old and for new
+	    dep_bool     '      Special FastTrak Feature' CONFIG_PDC202XX_FORCE $CONFIG_BLK_DEV_PDC202XX_NEW
+	    dep_tristate '    RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000 $CONFIG_X86
+	    dep_tristate '    SCx200 chipset support' CONFIG_BLK_DEV_SC1200 $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    ServerWorks OSB4/CSB5/CSB6 chipsets support' CONFIG_BLK_DEV_SVWKS $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    Silicon Image chipset support' CONFIG_BLK_DEV_SIIMAGE $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86
+	    dep_tristate '    SLC90E66 chipset support' CONFIG_BLK_DEV_SLC90E66 $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    Tekram TRM290 chipset support' CONFIG_BLK_DEV_TRM290 $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    VIA82CXXX chipset support' CONFIG_BLK_DEV_VIA82CXXX $CONFIG_BLK_DEV_IDEDMA_PCI
 	    if [ "$CONFIG_PPC" = "y" -o "$CONFIG_ARM" = "y" ]; then
-	       bool '    Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105
+	       dep_tristate '    Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105 $CONFIG_BLK_DEV_IDEPCI
 	    fi
          fi
       fi
@@ -149,14 +134,12 @@
       if [ "$CONFIG_IDE_CHIPSETS" = "y" ]; then
 	 comment 'Note: most of these also require special kernel boot parameters'
 	 bool '    Generic 4 drives/port support' CONFIG_BLK_DEV_4DRIVES
-	 bool '    ALI M14xx support' CONFIG_BLK_DEV_ALI14XX
-	 bool '    DTC-2278 support' CONFIG_BLK_DEV_DTC2278
-	 bool '    Holtek HT6560B support' CONFIG_BLK_DEV_HT6560B
-	 if [ "$CONFIG_BLK_DEV_IDEDISK" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
-	    bool '    PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030
-	 fi
-	 bool '    QDI QD65xx support' CONFIG_BLK_DEV_QD65XX
-	 bool '    UMC-8672 support' CONFIG_BLK_DEV_UMC8672
+	 dep_tristate '    ALI M14xx support' CONFIG_BLK_DEV_ALI14XX $CONFIG_BLK_DEV_IDE
+	 dep_tristate '    DTC-2278 support' CONFIG_BLK_DEV_DTC2278 $CONFIG_BLK_DEV_IDE
+	 dep_tristate '    Holtek HT6560B support' CONFIG_BLK_DEV_HT6560B $CONFIG_BLK_DEV_IDE
+	 dep_tristate '    PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030 $CONFIG_BLK_DEV_IDEDISK $CONFIG_EXPERIMENTAL
+	 dep_tristate '    QDI QD65xx support' CONFIG_BLK_DEV_QD65XX $CONFIG_BLK_DEV_IDE
+	 dep_tristate '    UMC-8672 support' CONFIG_BLK_DEV_UMC8672 $CONFIG_BLK_DEV_IDE
       fi
    fi
 else
@@ -184,7 +167,26 @@
   define_bool CONFIG_DMA_NONPCI n
 fi
 
-if [ "$CONFIG_IDE_CHIPSETS" = "y" -o \
+if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then
+   if [ "$CONFIG_BLK_DEV_PDC202XX_OLD" != "n" -o \
+        "$CONFIG_BLK_DEV_PDC202XX_NEW" != "n" ]; then
+      define_bool CONFIG_BLK_DEV_PDC202XX y
+   fi
+fi
+
+##if [ "$CONFIG_IDE_TASKFILE_IO" = "y" ]; then
+##  dep_mbool CONFIG_BLK_DEV_TF_DISK $CONFIG_BLK_DEV_IDEDISK
+##else
+##  dep_mbool CONFIG_BLK_DEV_NTF_DISK $CONFIG_BLK_DEV_IDEDISK
+##fi
+
+if [ "$CONFIG_BLK_DEV_4DRIVES" = "y" -o \
+     "$CONFIG_BLK_DEV_ALI14XX" != "n" -o \
+     "$CONFIG_BLK_DEV_DTC2278" != "n" -o \
+     "$CONFIG_BLK_DEV_HT6560B" != "n" -o \
+     "$CONFIG_BLK_DEV_PDC4030" != "n" -o \
+     "$CONFIG_BLK_DEV_QD65XX" != "n" -o \
+     "$CONFIG_BLK_DEV_UMC8672" != "n" -o \
      "$CONFIG_BLK_DEV_AEC62XX" = "y" -o \
      "$CONFIG_BLK_DEV_ALI15X3" = "y" -o \
      "$CONFIG_BLK_DEV_AMD74XX" = "y" -o \
@@ -195,16 +197,19 @@
      "$CONFIG_BLK_DEV_HPT34X" = "y" -o \
      "$CONFIG_BLK_DEV_HPT366" = "y" -o \
      "$CONFIG_BLK_DEV_IDE_PMAC" = "y" -o \
+     "$CONFIG_BLK_DEV_IT8172" = "y" -o \
+     "$CONFIG_BLK_DEV_MPC8xx_IDE" = "y" -o \
+     "$CONFIG_BLK_DEV_NFORCE" = "y" -o \
      "$CONFIG_BLK_DEV_OPTI621" = "y" -o \
      "$CONFIG_BLK_DEV_SVWKS" = "y" -o \
      "$CONFIG_BLK_DEV_PDC202XX" = "y" -o \
      "$CONFIG_BLK_DEV_PIIX" = "y" -o \
-     "$CONFIG_BLK_DEV_IT8172" = "y" -o \
+     "$CONFIG_BLK_DEV_SVWKS" = "y" -o \
+     "$CONFIG_BLK_DEV_SIIMAGE" = "y" -o \
      "$CONFIG_BLK_DEV_SIS5513" = "y" -o \
-     "$CONFIG_BLK_DEV_SLC90E66" = "y" -o \
      "$CONFIG_BLK_DEV_SL82C105" = "y" -o \
-     "$CONFIG_BLK_DEV_VIA82CXXX" = "y" -o \
-     "$CONFIG_BLK_DEV_MPC8xx_IDE" = "y" ]; then
+     "$CONFIG_BLK_DEV_SLC90E66" = "y" -o \
+     "$CONFIG_BLK_DEV_VIA82CXXX" = "y" ]; then
    define_bool CONFIG_BLK_DEV_IDE_MODES y
 else
    define_bool CONFIG_BLK_DEV_IDE_MODES n
@@ -213,5 +218,6 @@
 dep_tristate 'Support for IDE Raid controllers (EXPERIMENTAL)' CONFIG_BLK_DEV_ATARAID $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL
 dep_tristate '   Support Promise software RAID (Fasttrak(tm)) (EXPERIMENTAL)' CONFIG_BLK_DEV_ATARAID_PDC $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL $CONFIG_BLK_DEV_ATARAID
 dep_tristate '   Highpoint 370 software RAID (EXPERIMENTAL)' CONFIG_BLK_DEV_ATARAID_HPT $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL $CONFIG_BLK_DEV_ATARAID
+dep_tristate '   Silicon Image Medley software RAID (EXPERIMENTAL)' CONFIG_BLK_DEV_ATARAID_SII $CONFIG_BLK_DEV_IDE $CONFIG_EXPERIMENTAL $CONFIG_BLK_DEV_ATARAID
 
 endmenu
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/Makefile linux-2.4.21-pre6/drivers/ide/Makefile
--- linux-2.4.20/drivers/ide/Makefile	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/Makefile	2003-03-26 23:49:50.000000000 +0000
@@ -10,80 +10,50 @@
 
 O_TARGET := idedriver.o
 
-export-objs		:= ide.o ide-features.o ide-probe.o ide-taskfile.o ataraid.o
-list-multi		:= ide-mod.o ide-probe-mod.o
+export-objs := ide-iops.o ide-taskfile.o ide-proc.o ide.o ide-probe.o ide-dma.o ide-lib.o setup-pci.o ide-io.o
+
+all-subdirs	:= arm legacy pci ppc raid
+mod-subdirs	:= arm legacy pci ppc raid
 
 obj-y		:=
 obj-m		:=
 ide-obj-y	:=
 
-obj-$(CONFIG_BLK_DEV_HD)	+= hd.o
-obj-$(CONFIG_BLK_DEV_IDE)       += ide-mod.o ide-probe-mod.o
-obj-$(CONFIG_BLK_DEV_IDECS)     += ide-cs.o
-obj-$(CONFIG_BLK_DEV_IDEDISK)   += ide-disk.o
-obj-$(CONFIG_BLK_DEV_IDECD)     += ide-cd.o
-obj-$(CONFIG_BLK_DEV_IDETAPE)   += ide-tape.o
-obj-$(CONFIG_BLK_DEV_IDEFLOPPY) += ide-floppy.o
-
-obj-$(CONFIG_BLK_DEV_IT8172)    += it8172.o
-
-ide-obj-$(CONFIG_BLK_DEV_AEC62XX)	+= aec62xx.o
-ide-obj-$(CONFIG_BLK_DEV_ALI14XX)	+= ali14xx.o
-ide-obj-$(CONFIG_BLK_DEV_ALI15X3)	+= alim15x3.o
-ide-obj-$(CONFIG_BLK_DEV_AMD74XX)	+= amd74xx.o
-ide-obj-$(CONFIG_BLK_DEV_BUDDHA)	+= buddha.o
-ide-obj-$(CONFIG_BLK_DEV_CMD640)	+= cmd640.o
-ide-obj-$(CONFIG_BLK_DEV_CMD64X)	+= cmd64x.o
-ide-obj-$(CONFIG_BLK_DEV_CS5530)	+= cs5530.o
-ide-obj-$(CONFIG_BLK_DEV_CY82C693)	+= cy82c693.o
-ide-obj-$(CONFIG_BLK_DEV_DTC2278)	+= dtc2278.o
-ide-obj-$(CONFIG_BLK_DEV_FALCON_IDE)	+= falconide.o
-ide-obj-$(CONFIG_BLK_DEV_GAYLE)		+= gayle.o
-ide-obj-$(CONFIG_BLK_DEV_Q40IDE)	+= q40ide.o
-ide-obj-$(CONFIG_BLK_DEV_HPT34X)	+= hpt34x.o
-ide-obj-$(CONFIG_BLK_DEV_HPT366)	+= hpt366.o
-ide-obj-$(CONFIG_BLK_DEV_HT6560B)	+= ht6560b.o
-ide-obj-$(CONFIG_BLK_DEV_IDE_ICSIDE)	+= icside.o
-ide-obj-$(CONFIG_BLK_DEV_ADMA)		+= ide-adma.o
-ide-obj-$(CONFIG_BLK_DEV_IDEDMA_PCI)	+= ide-dma.o
-ide-obj-$(CONFIG_BLK_DEV_IDEPCI)	+= ide-pci.o
-ide-obj-$(CONFIG_BLK_DEV_ISAPNP)	+= ide-pnp.o
-ide-obj-$(CONFIG_BLK_DEV_IDE_PMAC)	+= ide-pmac.o
-ide-obj-$(CONFIG_BLK_DEV_IDE_SIBYTE)	+= ide-sibyte.o
-ide-obj-$(CONFIG_BLK_DEV_MAC_IDE)	+= macide.o
-ide-obj-$(CONFIG_BLK_DEV_NS87415)	+= ns87415.o
-ide-obj-$(CONFIG_BLK_DEV_OPTI621)	+= opti621.o
-ide-obj-$(CONFIG_BLK_DEV_SVWKS)		+= serverworks.o
-ide-obj-$(CONFIG_BLK_DEV_PDC202XX)	+= pdc202xx.o
-ide-obj-$(CONFIG_BLK_DEV_PDC4030)	+= pdc4030.o
-ide-obj-$(CONFIG_BLK_DEV_PDC_ADMA)	+= pdcadma.o
-ide-obj-$(CONFIG_BLK_DEV_PIIX)		+= piix.o
-ide-obj-$(CONFIG_BLK_DEV_QD65XX)	+= qd65xx.o
-ide-obj-$(CONFIG_BLK_DEV_IDE_RAPIDE)	+= rapide.o
-ide-obj-$(CONFIG_BLK_DEV_RZ1000)	+= rz1000.o
-ide-obj-$(CONFIG_BLK_DEV_SIS5513)	+= sis5513.o
-ide-obj-$(CONFIG_BLK_DEV_SLC90E66)	+= slc90e66.o
-ide-obj-$(CONFIG_BLK_DEV_SL82C105)	+= sl82c105.o
-ide-obj-$(CONFIG_BLK_DEV_TRM290)	+= trm290.o
-ide-obj-$(CONFIG_BLK_DEV_UMC8672)	+= umc8672.o
-ide-obj-$(CONFIG_BLK_DEV_VIA82CXXX)	+= via82cxxx.o
-ide-obj-$(CONFIG_BLK_DEV_MPC8xx_IDE)	+= ide-m8xx.o
-
-# The virtualised raid layers MUST come after the ide itself or bad stuff
-# will happen.
-obj-$(CONFIG_BLK_DEV_ATARAID)		+= ataraid.o
-obj-$(CONFIG_BLK_DEV_ATARAID_PDC)	+= pdcraid.o
-obj-$(CONFIG_BLK_DEV_ATARAID_HPT)	+= hptraid.o
+subdir-$(CONFIG_BLK_DEV_IDE) += legacy ppc arm raid pci
 
-ide-obj-$(CONFIG_PROC_FS)		+= ide-proc.o
+# First come modules that register themselves with the core
 
-ide-mod-objs		:= ide.o ide-features.o ide-taskfile.o $(ide-obj-y)
-ide-probe-mod-objs	:= ide-probe.o ide-geometry.o
+ifeq ($(CONFIG_BLK_DEV_IDE),y)
+  obj-y		+= pci/idedriver-pci.o
+endif
+
+# Core IDE code - must come before legacy
+
+obj-$(CONFIG_BLK_DEV_IDE)		+= ide-probe.o ide-geometry.o ide-iops.o ide-taskfile.o ide.o ide-lib.o ide-io.o
+obj-$(CONFIG_BLK_DEV_IDEDISK)		+= ide-disk.o
+obj-$(CONFIG_BLK_DEV_IDECD)		+= ide-cd.o
+obj-$(CONFIG_BLK_DEV_IDETAPE)		+= ide-tape.o
+obj-$(CONFIG_BLK_DEV_IDEFLOPPY)		+= ide-floppy.o
+
+obj-$(CONFIG_BLK_DEV_IDEPCI)		+= setup-pci.o
+obj-$(CONFIG_BLK_DEV_IDEDMA_PCI)	+= ide-dma.o
+obj-$(CONFIG_BLK_DEV_ISAPNP)		+= ide-pnp.o
 
-include $(TOPDIR)/Rules.make
 
-ide-mod.o: $(ide-mod-objs)
-	$(LD) -r -o $@ $(ide-mod-objs)
+ifeq ($(CONFIG_BLK_DEV_IDE),y)
+obj-$(CONFIG_PROC_FS)			+= ide-proc.o
+endif
 
-ide-probe-mod.o: $(ide-probe-mod-objs)
-	$(LD) -r -o $@ $(ide-probe-mod-objs)
+ifeq ($(CONFIG_BLK_DEV_IDE),y)
+  obj-y		+= legacy/idedriver-legacy.o
+  obj-y		+= ppc/idedriver-ppc.o
+  obj-y		+= arm/idedriver-arm.o
+endif
+
+
+ifeq ($(CONFIG_BLK_DEV_IDE),y)
+# RAID must be last of all
+  obj-y		+= raid/idedriver-raid.o
+endif
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/aec62xx.c linux-2.4.21-pre6/drivers/ide/aec62xx.c
--- linux-2.4.20/drivers/ide/aec62xx.c	2000-06-20 14:52:36.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/aec62xx.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,582 +0,0 @@
-/*
- * linux/drivers/ide/aec62xx.c		Version 0.09	June. 9, 2000
- *
- * Copyright (C) 1999-2000	Andre Hedrick (andre@linux-ide.org)
- * May be copied or modified under the terms of the GNU General Public License
- *
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include "ide_modes.h"
-
-#define DISPLAY_AEC62XX_TIMINGS
-
-#ifndef HIGH_4
-#define HIGH_4(H)		((H)=(H>>4))
-#endif
-#ifndef LOW_4
-#define LOW_4(L)		((L)=(L-((L>>4)<<4)))
-#endif
-#ifndef SPLIT_BYTE
-#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
-#endif
-#ifndef MAKE_WORD
-#define MAKE_WORD(W,HB,LB)	((W)=((HB<<8)+LB))
-#endif
-
-
-#if defined(DISPLAY_AEC62XX_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int aec62xx_get_info(char *, char **, off_t, int);
-extern int (*aec62xx_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-extern char *ide_media_verbose(ide_drive_t *);
-static struct pci_dev *bmide_dev;
-
-static int aec62xx_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-
-	u32 bibma = pci_resource_start(bmide_dev, 4);
-	u8 c0 = 0, c1 = 0;
-	u8 art = 0, uart = 0;
-
-	switch(bmide_dev->device) {
-		case PCI_DEVICE_ID_ARTOP_ATP850UF:
-			p += sprintf(p, "\n                                AEC6210 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_ARTOP_ATP860:
-			p += sprintf(p, "\n                                AEC6260 No Bios Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_ARTOP_ATP860R:
-			p += sprintf(p, "\n                                AEC6260 Chipset.\n");
-			break;
-		default:
-			p += sprintf(p, "\n                                AEC62?? Chipset.\n");
-			break;
-	}
-
-        /*
-         * at that point bibma+0x2 et bibma+0xa are byte registers
-         * to investigate:
-         */
-	c0 = inb_p((unsigned short)bibma + 0x02);
-	c1 = inb_p((unsigned short)bibma + 0x0a);
-
-	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
-	(void) pci_read_config_byte(bmide_dev, 0x4a, &art);
-	p += sprintf(p, "                %sabled                         %sabled\n",
-		(art&0x02)?" en":"dis",(art&0x04)?" en":"dis");
-	p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
-	p += sprintf(p, "DMA enabled:    %s              %s             %s               %s\n",
-		(c0&0x20)?"yes":"no ",(c0&0x40)?"yes":"no ",(c1&0x20)?"yes":"no ",(c1&0x40)?"yes":"no ");
-
-	switch(bmide_dev->device) {
-		case PCI_DEVICE_ID_ARTOP_ATP850UF:
-			(void) pci_read_config_byte(bmide_dev, 0x54, &art);
-			p += sprintf(p, "DMA Mode:       %s(%s)          %s(%s)         %s(%s)           %s(%s)\n",
-				(c0&0x20)?((art&0x03)?"UDMA":" DMA"):" PIO",
-				(art&0x02)?"2":(art&0x01)?"1":"0",
-				(c0&0x40)?((art&0x0c)?"UDMA":" DMA"):" PIO",
-				(art&0x08)?"2":(art&0x04)?"1":"0",
-				(c1&0x20)?((art&0x30)?"UDMA":" DMA"):" PIO",
-				(art&0x20)?"2":(art&0x10)?"1":"0",
-				(c1&0x40)?((art&0xc0)?"UDMA":" DMA"):" PIO",
-				(art&0x80)?"2":(art&0x40)?"1":"0");
-			(void) pci_read_config_byte(bmide_dev, 0x40, &art);
-			p += sprintf(p, "Active:         0x%02x", art);
-			(void) pci_read_config_byte(bmide_dev, 0x42, &art);
-			p += sprintf(p, "             0x%02x", art);
-			(void) pci_read_config_byte(bmide_dev, 0x44, &art);
-			p += sprintf(p, "            0x%02x", art);
-			(void) pci_read_config_byte(bmide_dev, 0x46, &art);
-			p += sprintf(p, "              0x%02x\n", art);
-			(void) pci_read_config_byte(bmide_dev, 0x41, &art);
-			p += sprintf(p, "Recovery:       0x%02x", art);
-			(void) pci_read_config_byte(bmide_dev, 0x43, &art);
-			p += sprintf(p, "             0x%02x", art);
-			(void) pci_read_config_byte(bmide_dev, 0x45, &art);
-			p += sprintf(p, "            0x%02x", art);
-			(void) pci_read_config_byte(bmide_dev, 0x47, &art);
-			p += sprintf(p, "              0x%02x\n", art);
-			break;
-		case PCI_DEVICE_ID_ARTOP_ATP860:
-		case PCI_DEVICE_ID_ARTOP_ATP860R:
-			(void) pci_read_config_byte(bmide_dev, 0x44, &art);
-			p += sprintf(p, "DMA Mode:       %s(%s)          %s(%s)",
-				(c0&0x20)?((art&0x07)?"UDMA":" DMA"):" PIO",
-				((art&0x06)==0x06)?"4":((art&0x05)==0x05)?"4":((art&0x04)==0x04)?"3":((art&0x03)==0x03)?"2":((art&0x02)==0x02)?"1":((art&0x01)==0x01)?"0":"?",
-				(c0&0x40)?((art&0x70)?"UDMA":" DMA"):" PIO",
-				((art&0x60)==0x60)?"4":((art&0x50)==0x50)?"4":((art&0x40)==0x40)?"3":((art&0x30)==0x30)?"2":((art&0x20)==0x20)?"1":((art&0x10)==0x10)?"0":"?");
-			(void) pci_read_config_byte(bmide_dev, 0x45, &art);
-			p += sprintf(p, "         %s(%s)           %s(%s)\n",
-				(c1&0x20)?((art&0x07)?"UDMA":" DMA"):" PIO",
-				((art&0x06)==0x06)?"4":((art&0x05)==0x05)?"4":((art&0x04)==0x04)?"3":((art&0x03)==0x03)?"2":((art&0x02)==0x02)?"1":((art&0x01)==0x01)?"0":"?",
-				(c1&0x40)?((art&0x70)?"UDMA":" DMA"):" PIO",
-				((art&0x60)==0x60)?"4":((art&0x50)==0x50)?"4":((art&0x40)==0x40)?"3":((art&0x30)==0x30)?"2":((art&0x20)==0x20)?"1":((art&0x10)==0x10)?"0":"?");
-			(void) pci_read_config_byte(bmide_dev, 0x40, &art);
-			p += sprintf(p, "Active:         0x%02x", HIGH_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x41, &art);
-			p += sprintf(p, "             0x%02x", HIGH_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x42, &art);
-			p += sprintf(p, "            0x%02x", HIGH_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x43, &art);
-			p += sprintf(p, "              0x%02x\n", HIGH_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x40, &art);
-			p += sprintf(p, "Recovery:       0x%02x", LOW_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x41, &art);
-			p += sprintf(p, "             0x%02x", LOW_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x42, &art);
-			p += sprintf(p, "            0x%02x", LOW_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x43, &art);
-			p += sprintf(p, "              0x%02x\n", LOW_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x49, &uart);
-			p += sprintf(p, "reg49h = 0x%02x ", uart);
-			(void) pci_read_config_byte(bmide_dev, 0x4a, &uart);
-			p += sprintf(p, "reg4ah = 0x%02x\n", uart);
-			break;
-		default:
-			break;
-	}
-
-	return p-buffer;/* => must be less than 4k! */
-}
-#endif	/* defined(DISPLAY_AEC62xx_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-byte aec62xx_proc = 0;
-
-#ifdef CONFIG_AEC62XX_TUNING
-
-struct chipset_bus_clock_list_entry {
-	byte		xfer_speed;
-
-	byte		chipset_settings_34;
-	byte		ultra_settings_34;
-
-	byte		chipset_settings_33;
-	byte		ultra_settings_33;
-};
-
-struct chipset_bus_clock_list_entry aec62xx_base [] = {
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	{	XFER_UDMA_4,	0x41,	0x04,	0x31,	0x05	},
-	{	XFER_UDMA_3,	0x41,	0x03,	0x31,	0x04	},
-	{	XFER_UDMA_2,	0x41,	0x02,	0x31,	0x03	},
-	{	XFER_UDMA_1,	0x41,	0x01,	0x31,	0x02	},
-	{	XFER_UDMA_0,	0x41,	0x01,	0x31,	0x01	},
-
-	{	XFER_MW_DMA_2,	0x41,	0x00,	0x31,	0x00	},
-	{	XFER_MW_DMA_1,	0x42,	0x00,	0x31,	0x00	},
-	{	XFER_MW_DMA_0,	0x7a,	0x00,	0x0a,	0x00	},
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-	{	XFER_PIO_4,	0x41,	0x00,	0x31,	0x00	},
-	{	XFER_PIO_3,	0x43,	0x00,	0x33,	0x00	},
-	{	XFER_PIO_2,	0x78,	0x00,	0x08,	0x00	},
-	{	XFER_PIO_1,	0x7a,	0x00,	0x0a,	0x00	},
-	{	XFER_PIO_0,	0x70,	0x00,	0x00,	0x00	},
-	{	0,		0x00,	0x00,	0x00,	0x00	}
-};
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-/*
- * TO DO: active tuning and correction of cards without a bios.
- */
-
-static byte pci_bus_clock_list (byte speed, struct chipset_bus_clock_list_entry * chipset_table)
-{
-	int bus_speed = system_bus_clock();
-
-	for ( ; chipset_table->xfer_speed ; chipset_table++)
-		if (chipset_table->xfer_speed == speed) {
-			return ((byte) ((bus_speed <= 33) ? chipset_table->chipset_settings_33 : chipset_table->chipset_settings_34));
-		}
-	return 0x00;
-}
-
-static byte pci_bus_clock_list_ultra (byte speed, struct chipset_bus_clock_list_entry * chipset_table)
-{
-	int bus_speed = system_bus_clock();
-
-	for ( ; chipset_table->xfer_speed ; chipset_table++)
-		if (chipset_table->xfer_speed == speed) {
-			return ((byte) ((bus_speed <= 33) ? chipset_table->ultra_settings_33 : chipset_table->ultra_settings_34));
-		}
-	return 0x00;
-}
-
-static int aec6210_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	int err			= 0;
-	unsigned short d_conf	= 0x0000;
-	byte ultra		= 0x00;
-	byte ultra_conf		= 0x00;
-	byte tmp0		= 0x00;
-	byte tmp1		= 0x00;
-	byte tmp2		= 0x00;
-	unsigned long flags;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-
-	pci_read_config_word(dev, 0x40|(2*drive->dn), &d_conf);
-	tmp0 = pci_bus_clock_list(speed, aec62xx_base);
-	SPLIT_BYTE(tmp0,tmp1,tmp2);
-	MAKE_WORD(d_conf,tmp1,tmp2);
-	pci_write_config_word(dev, 0x40|(2*drive->dn), d_conf);
-
-	tmp1 = 0x00;
-	tmp2 = 0x00;
-	pci_read_config_byte(dev, 0x54, &ultra);
-	tmp1 = ((0x00 << (2*drive->dn)) | (ultra & ~(3 << (2*drive->dn))));
-	ultra_conf = pci_bus_clock_list_ultra(speed, aec62xx_base);
-	tmp2 = ((ultra_conf << (2*drive->dn)) | (tmp1 & ~(3 << (2*drive->dn))));
-	pci_write_config_byte(dev, 0x54, tmp2);
-
-	__restore_flags(flags);	/* local CPU only */
-
-	err = ide_config_drive_speed(drive, speed);
-	return(err);
-}
-
-static int aec6260_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte unit		= (drive->select.b.unit & 0x01);
-	byte ultra_pci		= hwif->channel ? 0x45 : 0x44;
-	int err			= 0;
-	byte drive_conf		= 0x00;
-	byte ultra_conf		= 0x00;
-	byte ultra		= 0x00;
-	byte tmp1		= 0x00;
-	byte tmp2		= 0x00;
-	unsigned long flags;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-
-	pci_read_config_byte(dev, 0x40|drive->dn, &drive_conf);
-	drive_conf = pci_bus_clock_list(speed, aec62xx_base);
-	pci_write_config_byte(dev, 0x40|drive->dn, drive_conf);
-
-	pci_read_config_byte(dev, ultra_pci, &ultra);
-	tmp1 = ((0x00 << (4*unit)) | (ultra & ~(7 << (4*unit))));
-	ultra_conf = pci_bus_clock_list_ultra(speed, aec62xx_base);
-	tmp2 = ((ultra_conf << (4*unit)) | (tmp1 & ~(7 << (4*unit))));
-	pci_write_config_byte(dev, ultra_pci, tmp2);
-	__restore_flags(flags);	/* local CPU only */
-
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-
-	err = ide_config_drive_speed(drive, speed);
-	drive->current_speed = speed;
-	return(err);
-}
-
-
-static int aec62xx_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) {
-		return ((int) aec6210_tune_chipset(drive, speed));
-	} else {
-		return ((int) aec6260_tune_chipset(drive, speed));
-	}
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_aec6210_chipset_for_dma (ide_drive_t *drive, byte ultra)
-{
-	struct hd_driveid *id	= drive->id;
-	ide_hwif_t *hwif	= HWIF(drive);
-	byte unit		= (drive->select.b.unit & 0x01);
-	unsigned long dma_base	= hwif->dma_base;
-	byte speed		= -1;
-
-	if (drive->media != ide_disk)
-		return ((int) ide_dma_off_quietly);
-
-	if (((id->dma_ultra & 0x0010) ||
-	     (id->dma_ultra & 0x0008) ||
-	     (id->dma_ultra & 0x0004)) && (ultra)) {
-		speed = XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0002) && (ultra)) {
-		speed = XFER_UDMA_1;
-	} else if ((id->dma_ultra & 0x0001) && (ultra)) {
-		speed = XFER_UDMA_0;
-	} else if (id->dma_mword & 0x0004) {
-		speed = XFER_MW_DMA_2;
-	} else if (id->dma_mword & 0x0002) {
-		speed = XFER_MW_DMA_1;
-	} else if (id->dma_mword & 0x0001) {
-		speed = XFER_MW_DMA_0;
-	} else if (id->dma_1word & 0x0004) {
-		speed = XFER_SW_DMA_2;
-	} else if (id->dma_1word & 0x0002) {
-		speed = XFER_SW_DMA_1;
-	} else if (id->dma_1word & 0x0001) {
-		speed = XFER_SW_DMA_0;
-	} else {
- 		return ((int) ide_dma_off_quietly);
- 	}
-
-	outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
-	(void) aec6210_tune_chipset(drive, speed);
-
-	return ((int)	((id->dma_ultra >> 11) & 3) ? ide_dma_off :
-			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-			((id->dma_mword >> 8) & 7) ? ide_dma_on :
-			((id->dma_1word >> 8) & 7) ? ide_dma_on :
-						     ide_dma_off_quietly);
-}
-
-static int config_aec6260_chipset_for_dma (ide_drive_t *drive, byte ultra)
-{
-	struct hd_driveid *id	= drive->id;
-	ide_hwif_t *hwif	= HWIF(drive);
-	byte unit		= (drive->select.b.unit & 0x01);
-	unsigned long dma_base	= hwif->dma_base;
-	byte speed		= -1;
-	byte ultra66		= eighty_ninty_three(drive);
-
-	if (drive->media != ide_disk)
-		return ((int) ide_dma_off_quietly);
-
-	if ((id->dma_ultra & 0x0010) && (ultra) && (ultra66)) {
-		speed = XFER_UDMA_4;
-	} else if ((id->dma_ultra & 0x0008) && (ultra) && (ultra66)) {
-		speed = XFER_UDMA_3;
-	} else if ((id->dma_ultra & 0x0004) && (ultra)) {
-		speed = XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0002) && (ultra)) {
-		speed = XFER_UDMA_1;
-	} else if ((id->dma_ultra & 0x0001) && (ultra)) {
-		speed = XFER_UDMA_0;
-	} else if (id->dma_mword & 0x0004) {
-		speed = XFER_MW_DMA_2;
-	} else if (id->dma_mword & 0x0002) {
-		speed = XFER_MW_DMA_1;
-	} else if (id->dma_mword & 0x0001) {
-		speed = XFER_MW_DMA_0;
-	} else if (id->dma_1word & 0x0004) {
-		speed = XFER_SW_DMA_2;
-	} else if (id->dma_1word & 0x0002) {
-		speed = XFER_SW_DMA_1;
-	} else if (id->dma_1word & 0x0001) {
-		speed = XFER_SW_DMA_0;
-	} else {
-		return ((int) ide_dma_off_quietly);
-	}
-
-	outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
-	(void) aec6260_tune_chipset(drive, speed);
-
-	return ((int)	((id->dma_ultra >> 11) & 3) ? ide_dma_on :
-			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-			((id->dma_mword >> 8) & 7) ? ide_dma_on :
-			((id->dma_1word >> 8) & 7) ? ide_dma_on :
-						     ide_dma_off_quietly);
-}
-
-static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
-{
-	switch(HWIF(drive)->pci_dev->device) {	
-		case PCI_DEVICE_ID_ARTOP_ATP850UF:
-			return config_aec6210_chipset_for_dma(drive, ultra);
-		case PCI_DEVICE_ID_ARTOP_ATP860:
-		case PCI_DEVICE_ID_ARTOP_ATP860R:
-			return config_aec6260_chipset_for_dma(drive, ultra);
-		default:
-			return ((int) ide_dma_off_quietly);
-	}
-}
-
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-static void aec62xx_tune_drive (ide_drive_t *drive, byte pio)
-{
-	byte speed;
-	byte new_pio = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
-
-	switch(pio) {
-		case 5:		speed = new_pio; break;
-		case 4:		speed = XFER_PIO_4; break;
-		case 3:		speed = XFER_PIO_3; break;
-		case 2:		speed = XFER_PIO_2; break;
-		case 1:		speed = XFER_PIO_1; break;
-		default:	speed = XFER_PIO_0; break;
-	}
-
-	switch(HWIF(drive)->pci_dev->device) {
-		case PCI_DEVICE_ID_ARTOP_ATP850UF:
-			(void) aec6210_tune_chipset(drive, speed);
-		case PCI_DEVICE_ID_ARTOP_ATP860:
-		case PCI_DEVICE_ID_ARTOP_ATP860R:
-			(void) aec6260_tune_chipset(drive, speed);
-		default:
-			break;
-        }
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_drive_xfer_rate (ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-	ide_dma_action_t dma_func = ide_dma_on;
-
-	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x001F) {
-				/* Force if Capable UltraDMA */
-				dma_func = config_chipset_for_dma(drive, 1);
-				if ((id->field_valid & 2) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    (id->dma_1word & 0x0007)) {
-				/* Force if Capable regular DMA modes */
-				dma_func = config_chipset_for_dma(drive, 0);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			dma_func = config_chipset_for_dma(drive, 0);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-		aec62xx_tune_drive(drive, 5);
-	}
-	return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-/*
- * aec62xx_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
- */
-int aec62xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch (func) {
-		case ide_dma_check:
-			return config_drive_xfer_rate(drive);
-		case ide_dma_lostirq:
-		case ide_dma_timeout:
-			switch(HWIF(drive)->pci_dev->device) {
-				case PCI_DEVICE_ID_ARTOP_ATP860:
-				case PCI_DEVICE_ID_ARTOP_ATP860R:
-//					{
-//						int i = 0;
-//						byte reg49h = 0;
-//						pci_read_config_byte(HWIF(drive)->pci_dev, 0x49, &reg49h);
-//						for (i=0;i<256;i++)
-//							pci_write_config_byte(HWIF(drive)->pci_dev, 0x49, reg49h|0x10);
-//						pci_write_config_byte(HWIF(drive)->pci_dev, 0x49, reg49h & ~0x10);
-//					}
-//					return 0;
-				default:
-					break;
-			}
-		default:
-			break;
-	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-#endif /* CONFIG_AEC62XX_TUNING */
-
-unsigned int __init pci_init_aec62xx (struct pci_dev *dev, const char *name)
-{
-	if (dev->resource[PCI_ROM_RESOURCE].start) {
-		pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
-		printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
-	}
-
-#if defined(DISPLAY_AEC62XX_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!aec62xx_proc) {
-		aec62xx_proc = 1;
-		bmide_dev = dev;
-		aec62xx_display_info = &aec62xx_get_info;
-	}
-#endif /* DISPLAY_AEC62XX_TIMINGS && CONFIG_PROC_FS */
-
-	return dev->irq;
-}
-
-unsigned int __init ata66_aec62xx (ide_hwif_t *hwif)
-{
-	byte mask	= hwif->channel ? 0x02 : 0x01;
-	byte ata66	= 0;
-
-	pci_read_config_byte(hwif->pci_dev, 0x49, &ata66);
-	return ((ata66 & mask) ? 0 : 1);
-}
-
-void __init ide_init_aec62xx (ide_hwif_t *hwif)
-{
-#ifdef CONFIG_AEC62XX_TUNING
-	hwif->tuneproc = &aec62xx_tune_drive;
-	hwif->speedproc = &aec62xx_tune_chipset;
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (hwif->dma_base)
-		hwif->dmaproc = &aec62xx_dmaproc;
-#else /* !CONFIG_BLK_DEV_IDEDMA */
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-#endif /* CONFIG_AEC62XX_TUNING */
-}
-
-void __init ide_dmacapable_aec62xx (ide_hwif_t *hwif, unsigned long dmabase)
-{
-#ifdef CONFIG_AEC62XX_TUNING
-	unsigned long flags;
-	byte reg54h = 0;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-
-	pci_read_config_byte(hwif->pci_dev, 0x54, &reg54h);
-	pci_write_config_byte(hwif->pci_dev, 0x54, reg54h & ~(hwif->channel ? 0xF0 : 0x0F));
-
-	__restore_flags(flags);	/* local CPU only */
-#endif /* CONFIG_AEC62XX_TUNING */
-	ide_setup_dma(hwif, dmabase, 8);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ali14xx.c linux-2.4.21-pre6/drivers/ide/ali14xx.c
--- linux-2.4.20/drivers/ide/ali14xx.c	2001-07-15 23:22:23.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/ali14xx.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,226 +0,0 @@
-/*
- *  linux/drivers/ide/ali14xx.c		Version 0.03	Feb 09, 1996
- *
- *  Copyright (C) 1996  Linus Torvalds & author (see below)
- */
-
-/*
- * ALI M14xx chipset EIDE controller
- *
- * Works for ALI M1439/1443/1445/1487/1489 chipsets.
- *
- * Adapted from code developed by derekn@vw.ece.cmu.edu.  -ml
- * Derek's notes follow:
- *
- * I think the code should be pretty understandable,
- * but I'll be happy to (try to) answer questions.
- *
- * The critical part is in the setupDrive function.  The initRegisters
- * function doesn't seem to be necessary, but the DOS driver does it, so
- * I threw it in.
- *
- * I've only tested this on my system, which only has one disk.  I posted
- * it to comp.sys.linux.hardware, so maybe some other people will try it
- * out.
- *
- * Derek Noonburg  (derekn@ece.cmu.edu)
- * 95-sep-26
- *
- * Update 96-jul-13:
- *
- * I've since upgraded to two disks and a CD-ROM, with no trouble, and
- * I've also heard from several others who have used it successfully.
- * This driver appears to work with both the 1443/1445 and the 1487/1489
- * chipsets.  I've added support for PIO mode 4 for the 1487.  This
- * seems to work just fine on the 1443 also, although I'm not sure it's
- * advertised as supporting mode 4.  (I've been running a WDC AC21200 in
- * mode 4 for a while now with no trouble.)  -Derek
- */
-
-#undef REALLY_SLOW_IO           /* most systems can safely undef this */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-/* port addresses for auto-detection */
-#define ALI_NUM_PORTS 4
-static int ports[ALI_NUM_PORTS] __initdata = {0x074, 0x0f4, 0x034, 0x0e4};
-
-/* register initialization data */
-typedef struct { byte reg, data; } RegInitializer;
-
-static RegInitializer initData[] __initdata = {
-	{0x01, 0x0f}, {0x02, 0x00}, {0x03, 0x00}, {0x04, 0x00},
-	{0x05, 0x00}, {0x06, 0x00}, {0x07, 0x2b}, {0x0a, 0x0f},
-	{0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00}, {0x28, 0x00},
-	{0x29, 0x00}, {0x2a, 0x00}, {0x2f, 0x00}, {0x2b, 0x00},
-	{0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x30, 0x00},
-	{0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00}, {0x34, 0xff},
-	{0x35, 0x03}, {0x00, 0x00}
-};
-
-#define ALI_MAX_PIO 4
-
-/* timing parameter registers for each drive */
-static struct { byte reg1, reg2, reg3, reg4; } regTab[4] = {
-	{0x03, 0x26, 0x04, 0x27},     /* drive 0 */
-	{0x05, 0x28, 0x06, 0x29},     /* drive 1 */
-	{0x2b, 0x30, 0x2c, 0x31},     /* drive 2 */
-	{0x2d, 0x32, 0x2e, 0x33},     /* drive 3 */
-};
-
-static int basePort;	/* base port address */
-static int regPort;	/* port for register number */
-static int dataPort;	/* port for register data */
-static byte regOn;	/* output to base port to access registers */
-static byte regOff;	/* output to base port to close registers */
-
-/*------------------------------------------------------------------------*/
-
-/*
- * Read a controller register.
- */
-static inline byte inReg (byte reg)
-{
-	outb_p(reg, regPort);
-	return inb(dataPort);
-}
-
-/*
- * Write a controller register.
- */
-static void outReg (byte data, byte reg)
-{
-	outb_p(reg, regPort);
-	outb_p(data, dataPort);
-}
-
-/*
- * Set PIO mode for the specified drive.
- * This function computes timing parameters
- * and sets controller registers accordingly.
- */
-static void ali14xx_tune_drive (ide_drive_t *drive, byte pio)
-{
-	int driveNum;
-	int time1, time2;
-	byte param1, param2, param3, param4;
-	unsigned long flags;
-	ide_pio_data_t d;
-	int bus_speed = system_bus_clock();
-
-	pio = ide_get_best_pio_mode(drive, pio, ALI_MAX_PIO, &d);
-
-	/* calculate timing, according to PIO mode */
-	time1 = d.cycle_time;
-	time2 = ide_pio_timings[pio].active_time;
-	param3 = param1 = (time2 * bus_speed + 999) / 1000;
-	param4 = param2 = (time1 * bus_speed + 999) / 1000 - param1;
-	if (pio < 3) {
-		param3 += 8;
-		param4 += 8;
-	}
-	printk("%s: PIO mode%d, t1=%dns, t2=%dns, cycles = %d+%d, %d+%d\n",
-		drive->name, pio, time1, time2, param1, param2, param3, param4);
-
-	/* stuff timing parameters into controller registers */
-	driveNum = (HWIF(drive)->index << 1) + drive->select.b.unit;
-	save_flags(flags);	/* all CPUs */
-	cli();			/* all CPUs */
-	outb_p(regOn, basePort);
-	outReg(param1, regTab[driveNum].reg1);
-	outReg(param2, regTab[driveNum].reg2);
-	outReg(param3, regTab[driveNum].reg3);
-	outReg(param4, regTab[driveNum].reg4);
-	outb_p(regOff, basePort);
-	restore_flags(flags);	/* all CPUs */
-}
-
-/*
- * Auto-detect the IDE controller port.
- */
-static int __init findPort (void)
-{
-	int i;
-	byte t;
-	unsigned long flags;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-	for (i = 0; i < ALI_NUM_PORTS; ++i) {
-		basePort = ports[i];
-		regOff = inb(basePort);
-		for (regOn = 0x30; regOn <= 0x33; ++regOn) {
-			outb_p(regOn, basePort);
-			if (inb(basePort) == regOn) {
-				regPort = basePort + 4;
-				dataPort = basePort + 8;
-				t = inReg(0) & 0xf0;
-				outb_p(regOff, basePort);
-				__restore_flags(flags);	/* local CPU only */
-				if (t != 0x50)
-					return 0;
-				return 1;  /* success */
-			}
-		}
-		outb_p(regOff, basePort);
-	}
-	__restore_flags(flags);	/* local CPU only */
-	return 0;
-}
-
-/*
- * Initialize controller registers with default values.
- */
-static int __init initRegisters (void) {
-	RegInitializer *p;
-	byte t;
-	unsigned long flags;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-	outb_p(regOn, basePort);
-	for (p = initData; p->reg != 0; ++p)
-		outReg(p->data, p->reg);
-	outb_p(0x01, regPort);
-	t = inb(regPort) & 0x01;
-	outb_p(regOff, basePort);
-	__restore_flags(flags);	/* local CPU only */
-	return t;
-}
-
-void __init init_ali14xx (void)
-{
-	/* auto-detect IDE controller port */
-	if (!findPort()) {
-		printk("\nali14xx: not found");
-		return;
-	}
-
-	printk("\nali14xx: base= 0x%03x, regOn = 0x%02x", basePort, regOn);
-	ide_hwifs[0].chipset = ide_ali14xx;
-	ide_hwifs[1].chipset = ide_ali14xx;
-	ide_hwifs[0].tuneproc = &ali14xx_tune_drive;
-	ide_hwifs[1].tuneproc = &ali14xx_tune_drive;
-	ide_hwifs[0].mate = &ide_hwifs[1];
-	ide_hwifs[1].mate = &ide_hwifs[0];
-	ide_hwifs[1].channel = 1;
-
-	/* initialize controller registers */
-	if (!initRegisters()) {
-		printk("\nali14xx: Chip initialization failed");
-		return;
-	}
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/alim15x3.c linux-2.4.21-pre6/drivers/ide/alim15x3.c
--- linux-2.4.20/drivers/ide/alim15x3.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/alim15x3.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,705 +0,0 @@
-/*
- * linux/drivers/ide/alim15x3.c		Version 0.10	Jun. 9, 2000
- *
- *  Copyright (C) 1998-2000 Michel Aubry, Maintainer
- *  Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer
- *  Copyright (C) 1999-2000 CJ, cjtsai@ali.com.tw, Maintainer
- *
- *  Copyright (C) 1998-2000 Andre Hedrick (andre@linux-ide.org)
- *  May be copied or modified under the terms of the GNU General Public License
- *
- *  (U)DMA capable version of ali 1533/1543(C), 1535(D)
- *
- **********************************************************************
- *  9/7/99 --Parts from the above author are included and need to be
- *  converted into standard interface, once I finish the thought.
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-#define DISPLAY_ALI_TIMINGS
-
-#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int ali_get_info(char *buffer, char **addr, off_t offset, int count);
-extern int (*ali_display_info)(char *, char **, off_t, int);  /* ide-proc.c */
-static struct pci_dev *bmide_dev;
-
-char *fifo[4] = {
-	"FIFO Off",
-	"FIFO On ",
-	"DMA mode",
-	"PIO mode" };
-
-char *udmaT[8] = {
-	"1.5T",
-	"  2T",
-	"2.5T",
-	"  3T",
-	"3.5T",
-	"  4T",
-	"  6T",
-	"  8T"
-};
-
-char *channel_status[8] = {
-	"OK            ",
-	"busy          ",
-	"DRQ           ",
-	"DRQ busy      ",
-	"error         ",
-	"error busy    ",
-	"error DRQ     ",
-	"error DRQ busy"
-};
-
-static int ali_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	byte reg53h, reg5xh, reg5yh, reg5xh1, reg5yh1;
-	unsigned int bibma;
-	byte c0, c1;
-	byte rev, tmp;
-	char *p = buffer;
-	char *q;
-
-	/* fetch rev. */
-	pci_read_config_byte(bmide_dev, 0x08, &rev);
-	if (rev >= 0xc1)	/* M1543C or newer */
-		udmaT[7] = " ???";
-	else
-		fifo[3]  = "   ???  ";
-
-	/* first fetch bibma: */
-	pci_read_config_dword(bmide_dev, 0x20, &bibma);
-	bibma = (bibma & 0xfff0) ;
-	/*
-	 * at that point bibma+0x2 et bibma+0xa are byte
-	 * registers to investigate:
-	 */
-	c0 = inb((unsigned short)bibma + 0x02);
-	c1 = inb((unsigned short)bibma + 0x0a);
-
-	p += sprintf(p,
-		"\n                                Ali M15x3 Chipset.\n");
-	p += sprintf(p,
-		"                                ------------------\n");
-	pci_read_config_byte(bmide_dev, 0x78, &reg53h);
-	p += sprintf(p, "PCI Clock: %d.\n", reg53h);
-
-	pci_read_config_byte(bmide_dev, 0x53, &reg53h);
-	p += sprintf(p,
-		"CD_ROM FIFO:%s, CD_ROM DMA:%s\n",
-		(reg53h & 0x02) ? "Yes" : "No ",
-		(reg53h & 0x01) ? "Yes" : "No " );
-	pci_read_config_byte(bmide_dev, 0x74, &reg53h);
-	p += sprintf(p,
-		"FIFO Status: contains %d Words, runs%s%s\n\n",
-		(reg53h & 0x3f),
-		(reg53h & 0x40) ? " OVERWR" : "",
-		(reg53h & 0x80) ? " OVERRD." : "." );
-
-	p += sprintf(p,
-		"-------------------primary channel-------------------secondary channel---------\n\n");
-
-	pci_read_config_byte(bmide_dev, 0x09, &reg53h);
-	p += sprintf(p,
-		"channel status:       %s                               %s\n",
-		(reg53h & 0x20) ? "On " : "Off",
-		(reg53h & 0x10) ? "On " : "Off" );
-
-	p += sprintf(p,
-		"both channels togth:  %s                               %s\n",
-		(c0&0x80) ? "No " : "Yes",
-		(c1&0x80) ? "No " : "Yes" );
-
-	pci_read_config_byte(bmide_dev, 0x76, &reg53h);
-	p += sprintf(p,
-		"Channel state:        %s                    %s\n",
-		channel_status[reg53h & 0x07],
-		channel_status[(reg53h & 0x70) >> 4] );
-
-	pci_read_config_byte(bmide_dev, 0x58, &reg5xh);
-	pci_read_config_byte(bmide_dev, 0x5c, &reg5yh);
-	p += sprintf(p,
-		"Add. Setup Timing:    %dT                                %dT\n",
-		(reg5xh & 0x07) ? (reg5xh & 0x07) : 8,
-		(reg5yh & 0x07) ? (reg5yh & 0x07) : 8 );
-
-	pci_read_config_byte(bmide_dev, 0x59, &reg5xh);
-	pci_read_config_byte(bmide_dev, 0x5d, &reg5yh);
-	p += sprintf(p,
-		"Command Act. Count:   %dT                                %dT\n"
-		"Command Rec. Count:   %dT                               %dT\n\n",
-		(reg5xh & 0x70) ? ((reg5xh & 0x70) >> 4) : 8,
-		(reg5yh & 0x70) ? ((reg5yh & 0x70) >> 4) : 8, 
-		(reg5xh & 0x0f) ? (reg5xh & 0x0f) : 16,
-		(reg5yh & 0x0f) ? (reg5yh & 0x0f) : 16 );
-
-	p += sprintf(p,
-		"----------------drive0-----------drive1------------drive0-----------drive1------\n\n");
-	p += sprintf(p,
-		"DMA enabled:      %s              %s               %s              %s\n",
-		(c0&0x20) ? "Yes" : "No ",
-		(c0&0x40) ? "Yes" : "No ",
-		(c1&0x20) ? "Yes" : "No ",
-		(c1&0x40) ? "Yes" : "No " );
-
-	pci_read_config_byte(bmide_dev, 0x54, &reg5xh);
-	pci_read_config_byte(bmide_dev, 0x55, &reg5yh);
-	q = "FIFO threshold:   %2d Words         %2d Words          %2d Words         %2d Words\n";
-	if (rev < 0xc1) {
-		if ((rev == 0x20) && (pci_read_config_byte(bmide_dev, 0x4f, &tmp), (tmp &= 0x20))) {
-			p += sprintf(p, q, 8, 8, 8, 8);
-		} else {
-			p += sprintf(p, q,
-				(reg5xh & 0x03) + 12,
-				((reg5xh & 0x30)>>4) + 12,
-				(reg5yh & 0x03) + 12,
-				((reg5yh & 0x30)>>4) + 12 );
-		}
-	} else {
-		int t1 = (tmp = (reg5xh & 0x03)) ? (tmp << 3) : 4;
-		int t2 = (tmp = ((reg5xh & 0x30)>>4)) ? (tmp << 3) : 4;
-		int t3 = (tmp = (reg5yh & 0x03)) ? (tmp << 3) : 4;
-		int t4 = (tmp = ((reg5yh & 0x30)>>4)) ? (tmp << 3) : 4;
-		p += sprintf(p, q, t1, t2, t3, t4);
-	}
-
-#if 0
-	p += sprintf(p, 
-		"FIFO threshold:   %2d Words         %2d Words          %2d Words         %2d Words\n",
-		(reg5xh & 0x03) + 12,
-		((reg5xh & 0x30)>>4) + 12,
-		(reg5yh & 0x03) + 12,
-		((reg5yh & 0x30)>>4) + 12 );
-#endif
-
-	p += sprintf(p,
-		"FIFO mode:        %s         %s          %s         %s\n",
-		fifo[((reg5xh & 0x0c) >> 2)],
-		fifo[((reg5xh & 0xc0) >> 6)],
-		fifo[((reg5yh & 0x0c) >> 2)],
-		fifo[((reg5yh & 0xc0) >> 6)] );
-
-	pci_read_config_byte(bmide_dev, 0x5a, &reg5xh);
-	pci_read_config_byte(bmide_dev, 0x5b, &reg5xh1);
-	pci_read_config_byte(bmide_dev, 0x5e, &reg5yh);
-	pci_read_config_byte(bmide_dev, 0x5f, &reg5yh1);
-
-	p += sprintf(p,/*
-		"------------------drive0-----------drive1------------drive0-----------drive1------\n")*/
-		"Dt RW act. Cnt    %2dT              %2dT               %2dT              %2dT\n"
-		"Dt RW rec. Cnt    %2dT              %2dT               %2dT              %2dT\n\n",
-		(reg5xh & 0x70) ? ((reg5xh & 0x70) >> 4) : 8,
-		(reg5xh1 & 0x70) ? ((reg5xh1 & 0x70) >> 4) : 8,
-		(reg5yh & 0x70) ? ((reg5yh & 0x70) >> 4) : 8,
-		(reg5yh1 & 0x70) ? ((reg5yh1 & 0x70) >> 4) : 8,
-		(reg5xh & 0x0f) ? (reg5xh & 0x0f) : 16,
-		(reg5xh1 & 0x0f) ? (reg5xh1 & 0x0f) : 16,
-		(reg5yh & 0x0f) ? (reg5yh & 0x0f) : 16,
-		(reg5yh1 & 0x0f) ? (reg5yh1 & 0x0f) : 16 );
-
-	p += sprintf(p,
-		"-----------------------------------UDMA Timings--------------------------------\n\n");
-
-	pci_read_config_byte(bmide_dev, 0x56, &reg5xh);
-	pci_read_config_byte(bmide_dev, 0x57, &reg5yh);
-	p += sprintf(p,
-		"UDMA:             %s               %s                %s               %s\n"
-		"UDMA timings:     %s             %s              %s             %s\n\n",
-		(reg5xh & 0x08) ? "OK" : "No",
-		(reg5xh & 0x80) ? "OK" : "No",
-		(reg5yh & 0x08) ? "OK" : "No",
-		(reg5yh & 0x80) ? "OK" : "No",
-		udmaT[(reg5xh & 0x07)],
-		udmaT[(reg5xh & 0x70) >> 4],
-		udmaT[reg5yh & 0x07],
-		udmaT[(reg5yh & 0x70) >> 4] );
-
-	return p-buffer; /* => must be less than 4k! */
-}
-#endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-static byte m5229_revision;
-static byte chip_is_1543c_e;
-
-byte ali_proc = 0;
-static struct pci_dev *isa_dev;
-
-static void ali15x3_tune_drive (ide_drive_t *drive, byte pio)
-{
-	ide_pio_data_t d;
-	ide_hwif_t *hwif = HWIF(drive);
-	struct pci_dev *dev = hwif->pci_dev;
-	int s_time, a_time, c_time;
-	byte s_clc, a_clc, r_clc;
-	unsigned long flags;
-	int bus_speed = system_bus_clock();
-	int port = hwif->index ? 0x5c : 0x58;
-	int portFIFO = hwif->channel ? 0x55 : 0x54;
-	byte cd_dma_fifo = 0;
-
-	pio = ide_get_best_pio_mode(drive, pio, 5, &d);
-	s_time = ide_pio_timings[pio].setup_time;
-	a_time = ide_pio_timings[pio].active_time;
-	if ((s_clc = (s_time * bus_speed + 999) / 1000) >= 8)
-		s_clc = 0;
-	if ((a_clc = (a_time * bus_speed + 999) / 1000) >= 8)
-		a_clc = 0;
-	c_time = ide_pio_timings[pio].cycle_time;
-
-#if 0
-	if ((r_clc = ((c_time - s_time - a_time) * bus_speed + 999) / 1000) >= 16)
-		r_clc = 0;
-#endif
-
-	if (!(r_clc = (c_time * bus_speed + 999) / 1000 - a_clc - s_clc)) {
-		r_clc = 1;
-	} else {
-		if (r_clc >= 16)
-			r_clc = 0;
-	}
-	__save_flags(flags);
-	__cli();
-	
-	/* 
-	 * PIO mode => ATA FIFO on, ATAPI FIFO off
-	 */
-	pci_read_config_byte(dev, portFIFO, &cd_dma_fifo);
-	if (drive->media==ide_disk) {
-		if (hwif->index) {
-			pci_write_config_byte(dev, portFIFO, (cd_dma_fifo & 0x0F) | 0x50);
-		} else {
-			pci_write_config_byte(dev, portFIFO, (cd_dma_fifo & 0xF0) | 0x05);
-		}
-	} else {
-		if (hwif->index) {
-			pci_write_config_byte(dev, portFIFO, cd_dma_fifo & 0x0F);
-		} else {
-			pci_write_config_byte(dev, portFIFO, cd_dma_fifo & 0xF0);
-		}
-	}
-	
-	pci_write_config_byte(dev, port, s_clc);
-	pci_write_config_byte(dev, port+drive->select.b.unit+2, (a_clc << 4) | r_clc);
-	__restore_flags(flags);
-
-	/*
-	 * setup   active  rec
-	 * { 70,   165,    365 },   PIO Mode 0
-	 * { 50,   125,    208 },   PIO Mode 1
-	 * { 30,   100,    110 },   PIO Mode 2
-	 * { 30,   80,     70  },   PIO Mode 3 with IORDY
-	 * { 25,   70,     25  },   PIO Mode 4 with IORDY  ns
-	 * { 20,   50,     30  }    PIO Mode 5 with IORDY (nonstandard)
-	 */
-
-}
-
-static int ali15x3_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte unit		= (drive->select.b.unit & 0x01);
-	byte tmpbyte		= 0x00;
-	int m5229_udma		= hwif->channel? 0x57 : 0x56;
-	int err			= 0;
-
-	if (speed < XFER_UDMA_0) {
-		byte ultra_enable	= (unit) ? 0x7f : 0xf7;
-		/*
-		 * clear "ultra enable" bit
-		 */
-		pci_read_config_byte(dev, m5229_udma, &tmpbyte);
-		tmpbyte &= ultra_enable;
-		pci_write_config_byte(dev, m5229_udma, tmpbyte);
-	}
-
-	err = ide_config_drive_speed(drive, speed);
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (speed >= XFER_SW_DMA_0) {
-		unsigned long dma_base = hwif->dma_base;
-
-		outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
-	}
-
-	if (speed >= XFER_UDMA_0) {
-		pci_read_config_byte(dev, m5229_udma, &tmpbyte);
-		tmpbyte &= (0x0f << ((1-unit) << 2));
-		/*
-		 * enable ultra dma and set timing
-		 */
-		tmpbyte |= ((0x08 | ((4-speed)&0x07)) << (unit << 2));
-		pci_write_config_byte(dev, m5229_udma, tmpbyte);
-		if (speed >= XFER_UDMA_3) {
-			pci_read_config_byte(dev, 0x4b, &tmpbyte);
-			tmpbyte |= 1;
-			pci_write_config_byte(dev, 0x4b, tmpbyte);
-		}
-	}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-	drive->current_speed = speed;
-
-	return (err);
-}
-
-static void config_chipset_for_pio (ide_drive_t *drive)
-{
-	ali15x3_tune_drive(drive, 5);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_chipset_for_dma (ide_drive_t *drive, byte ultra33)
-{
-	struct hd_driveid *id	= drive->id;
-	byte speed		= 0x00;
-	byte ultra66		= eighty_ninty_three(drive);
-	byte ultra100		= (m5229_revision>=0xc4) ? 1 : 0;
-	int  rval;
-
-	if ((id->dma_ultra & 0x0020) && (ultra100) && (ultra66) && (ultra33)) {
-		speed = XFER_UDMA_5;
-	} else if ((id->dma_ultra & 0x0010) && (ultra66) && (ultra33)) {
-		speed = XFER_UDMA_4;
-	} else if ((id->dma_ultra & 0x0008) && (ultra66) && (ultra33)) {
-		speed = XFER_UDMA_3;
-	} else if ((id->dma_ultra & 0x0004) && (ultra33)) {
-		speed = XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0002) && (ultra33)) {
-		speed = XFER_UDMA_1;
-	} else if ((id->dma_ultra & 0x0001) && (ultra33)) {
-		speed = XFER_UDMA_0;
-	} else if (id->dma_mword & 0x0004) {
-		speed = XFER_MW_DMA_2;
-	} else if (id->dma_mword & 0x0002) {
-		speed = XFER_MW_DMA_1;
-	} else if (id->dma_mword & 0x0001) {
-		speed = XFER_MW_DMA_0;
-	} else if (id->dma_1word & 0x0004) {
-		speed = XFER_SW_DMA_2;
-	} else if (id->dma_1word & 0x0002) {
-		speed = XFER_SW_DMA_1;
-	} else if (id->dma_1word & 0x0001) {
-		speed = XFER_SW_DMA_0;
-	} else {
-		return ((int) ide_dma_off_quietly);
-	}
-
-	(void) ali15x3_tune_chipset(drive, speed);
-
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-
-	rval = (int)(	((id->dma_ultra >> 11) & 3) ? ide_dma_on :
-			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-			((id->dma_mword >> 8) & 7) ? ide_dma_on :
-			((id->dma_1word >> 8) & 7) ? ide_dma_on :
-						     ide_dma_off_quietly);
-
-	return rval;
-}
-
-static byte ali15x3_can_ultra (ide_drive_t *drive)
-{
-#ifndef CONFIG_WDC_ALI15X3
-	struct hd_driveid *id	= drive->id;
-#endif /* CONFIG_WDC_ALI15X3 */
-
-	if (m5229_revision <= 0x20) {
-		return 0;
-	} else if ((m5229_revision < 0xC2) &&
-#ifndef CONFIG_WDC_ALI15X3
-		   ((chip_is_1543c_e && strstr(id->model, "WDC ")) ||
-		    (drive->media!=ide_disk))) {
-#else /* CONFIG_WDC_ALI15X3 */
-		   (drive->media!=ide_disk)) {
-#endif /* CONFIG_WDC_ALI15X3 */
-		return 0;
-	} else {
-		return 1;
-	}
-}
-
-static int ali15x3_config_drive_for_dma(ide_drive_t *drive)
-{
-	struct hd_driveid *id		= drive->id;
-	ide_hwif_t *hwif		= HWIF(drive);
-	ide_dma_action_t dma_func	= ide_dma_on;
-	byte can_ultra_dma		= ali15x3_can_ultra(drive);
-
-	if ((m5229_revision<=0x20) && (drive->media!=ide_disk))
-		return hwif->dmaproc(ide_dma_off_quietly, drive);
-
-	if ((id != NULL) && ((id->capability & 1) != 0) && hwif->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if ((id->field_valid & 4) && (m5229_revision >= 0xC2)) {
-			if (id->dma_ultra & 0x003F) {
-				/* Force if Capable UltraDMA */
-				dma_func = config_chipset_for_dma(drive, can_ultra_dma);
-				if ((id->field_valid & 2) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    (id->dma_1word & 0x0007)) {
-				/* Force if Capable regular DMA modes */
-				dma_func = config_chipset_for_dma(drive, can_ultra_dma);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			dma_func = config_chipset_for_dma(drive, can_ultra_dma);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-		config_chipset_for_pio(drive);
-	}
-	return hwif->dmaproc(dma_func, drive);
-}
-
-static int ali15x3_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch(func) {
-		case ide_dma_check:
-			return ali15x3_config_drive_for_dma(drive);
-		case ide_dma_write:
-			if ((m5229_revision < 0xC2) && (drive->media != ide_disk))
-				return 1;	/* try PIO instead of DMA */
-			break;
-		default:
-			break;
-	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-unsigned int __init pci_init_ali15x3 (struct pci_dev *dev, const char *name)
-{
-	unsigned long fixdma_base = pci_resource_start(dev, 4);
-
-	pci_read_config_byte(dev, PCI_REVISION_ID, &m5229_revision);
-
-	isa_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
-
-	if (!fixdma_base) {
-		/*
-		 *
-		 */
-	} else {
-		/*
-		 * enable DMA capable bit, and "not" simplex only
-		 */
-		outb(inb(fixdma_base+2) & 0x60, fixdma_base+2);
-
-		if (inb(fixdma_base+2) & 0x80)
-			printk("%s: simplex device: DMA will fail!!\n", name);
-	}
-
-#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!ali_proc) {
-		ali_proc = 1;
-		bmide_dev = dev;
-		ali_display_info = &ali_get_info;
-	}
-#endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-	return 0;
-}
-
-/*
- * This checks if the controller and the cable are capable
- * of UDMA66 transfers. It doesn't check the drives.
- * But see note 2 below!
- */
-unsigned int __init ata66_ali15x3 (ide_hwif_t *hwif)
-{
-	struct pci_dev *dev	= hwif->pci_dev;
-	unsigned int ata66	= 0;
-	byte cable_80_pin[2]	= { 0, 0 };
-
-	unsigned long flags;
-	byte tmpbyte;
-
-	__save_flags(flags);
-	__cli();
-
-	if (m5229_revision >= 0xC2) {
-		/*
-		 * 1543C-B?, 1535, 1535D, 1553
-		 * Note 1: not all "motherboard" support this detection
-		 * Note 2: if no udma 66 device, the detection may "error".
-		 *         but in this case, we will not set the device to
-		 *         ultra 66, the detection result is not important
-		 */
-
-		/*
-		 * enable "Cable Detection", m5229, 0x4b, bit3
-		 */
-		pci_read_config_byte(dev, 0x4b, &tmpbyte);
-		pci_write_config_byte(dev, 0x4b, tmpbyte | 0x08);
-
-		/*
-		 * set south-bridge's enable bit, m1533, 0x79
-		 */
-		pci_read_config_byte(isa_dev, 0x79, &tmpbyte);
-		if (m5229_revision == 0xC2) {
-			/*
-			 * 1543C-B0 (m1533, 0x79, bit 2)
-			 */
-			pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x04);
-		} else if (m5229_revision >= 0xC3) {
-			/*
-			 * 1553/1535 (m1533, 0x79, bit 1)
-			 */
-			pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x02);
-		}
-		/*
-		 * Ultra66 cable detection (from Host View)
-		 * m5229, 0x4a, bit0: primary, bit1: secondary 80 pin
-		 */
-		pci_read_config_byte(dev, 0x4a, &tmpbyte);
-		/*
-		 * 0x4a, bit0 is 0 => primary channel
-		 * has 80-pin (from host view)
-		 */
-		if (!(tmpbyte & 0x01)) cable_80_pin[0] = 1;
-		/*
-		 * 0x4a, bit1 is 0 => secondary channel
-		 * has 80-pin (from host view)
-		 */
-		if (!(tmpbyte & 0x02)) cable_80_pin[1] = 1;
-		/*
-		 * Allow ata66 if cable of current channel has 80 pins
-		 */
-		ata66 = (hwif->channel)?cable_80_pin[1]:cable_80_pin[0];
-	} else {
-		/*
-		 * revision 0x20 (1543-E, 1543-F)
-		 * revision 0xC0, 0xC1 (1543C-C, 1543C-D, 1543C-E)
-		 * clear CD-ROM DMA write bit, m5229, 0x4b, bit 7
-		 */
-		pci_read_config_byte(dev, 0x4b, &tmpbyte);
-		/*
-		 * clear bit 7
-		 */
-		pci_write_config_byte(dev, 0x4b, tmpbyte & 0x7F);
-		/*
-		 * check m1533, 0x5e, bit 1~4 == 1001 => & 00011110 = 00010010
-		 */
-		pci_read_config_byte(isa_dev, 0x5e, &tmpbyte);
-		chip_is_1543c_e = ((tmpbyte & 0x1e) == 0x12) ? 1: 0;
-	}
-
-	/*
-	 * CD_ROM DMA on (m5229, 0x53, bit0)
-	 *      Enable this bit even if we want to use PIO
-	 * PIO FIFO off (m5229, 0x53, bit1)
-	 *      The hardware will use 0x54h and 0x55h to control PIO FIFO
-	 */
-	pci_read_config_byte(dev, 0x53, &tmpbyte);
-	tmpbyte = (tmpbyte & (~0x02)) | 0x01;
-
-	pci_write_config_byte(dev, 0x53, tmpbyte);
-
-	__restore_flags(flags);
-
-	return(ata66);
-}
-
-void __init ide_init_ali15x3 (ide_hwif_t *hwif)
-{
-#ifndef CONFIG_SPARC64
-	byte ideic, inmir;
-	byte irq_routing_table[] = { -1,  9, 3, 10, 4,  5, 7,  6,
-				      1, 11, 0, 12, 0, 14, 0, 15 };
-
-	hwif->irq = hwif->channel ? 15 : 14;
-
-	if (isa_dev) {
-		/*
-		 * read IDE interface control
-		 */
-		pci_read_config_byte(isa_dev, 0x58, &ideic);
-
-		/* bit0, bit1 */
-		ideic = ideic & 0x03;
-
-		/* get IRQ for IDE Controller */
-		if ((hwif->channel && ideic == 0x03) || (!hwif->channel && !ideic)) {
-			/*
-			 * get SIRQ1 routing table
-			 */
-			pci_read_config_byte(isa_dev, 0x44, &inmir);
-			inmir = inmir & 0x0f;
-			hwif->irq = irq_routing_table[inmir];
-		} else if (hwif->channel && !(ideic & 0x01)) {
-			/*
-			 * get SIRQ2 routing table
-			 */
-			pci_read_config_byte(isa_dev, 0x75, &inmir);
-			inmir = inmir & 0x0f;
-			hwif->irq = irq_routing_table[inmir];
-		}
-	}
-#endif /* CONFIG_SPARC64 */
-
-	hwif->tuneproc = &ali15x3_tune_drive;
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-	hwif->speedproc = &ali15x3_tune_chipset;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if ((hwif->dma_base) && (m5229_revision >= 0x20)) {
-		/*
-		 * M1543C or newer for DMAing
-		 */
-		hwif->dmaproc = &ali15x3_dmaproc;
-		hwif->autodma = 1;
-	}
-
-	if (noautodma)
-		hwif->autodma = 0;
-#else
-	hwif->autodma = 0;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-}
-
-void __init ide_dmacapable_ali15x3 (ide_hwif_t *hwif, unsigned long dmabase)
-{
-	if ((dmabase) && (m5229_revision < 0x20)) {
-		return;
-	}
-	ide_setup_dma(hwif, dmabase, 8);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/amd74xx.c linux-2.4.21-pre6/drivers/ide/amd74xx.c
--- linux-2.4.20/drivers/ide/amd74xx.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/amd74xx.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,513 +0,0 @@
-/*
- * linux/drivers/ide/amd74xx.c		Version 0.05	June 9, 2000
- *
- * Copyright (C) 1999-2000		Andre Hedrick <andre@linux-ide.org>
- * May be copied or modified under the terms of the GNU General Public License
- *
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include "ide_modes.h"
-
-#define DISPLAY_VIPER_TIMINGS
-
-#if defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int amd74xx_get_info(char *, char **, off_t, int);
-extern int (*amd74xx_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-extern char *ide_media_verbose(ide_drive_t *);
-static struct pci_dev *bmide_dev;
-
-static int amd74xx_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	u32 bibma = pci_resource_start(bmide_dev, 4);
-	u8 c0 = 0, c1 = 0;
-
-	/*
-	 * at that point bibma+0x2 et bibma+0xa are byte registers
-	 * to investigate:
-	 */
-	c0 = inb_p((unsigned short)bibma + 0x02);
-	c1 = inb_p((unsigned short)bibma + 0x0a);
-
-	p += sprintf(p, "\n                                AMD %04X VIPER Chipset.\n", bmide_dev->device);
-	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
-	p += sprintf(p, "                %sabled                         %sabled\n",
-			(c0&0x80) ? "dis" : " en",
-			(c1&0x80) ? "dis" : " en");
-	p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
-	p += sprintf(p, "DMA enabled:    %s              %s             %s               %s\n",
-			(c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ",
-			(c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " );
-	p += sprintf(p, "UDMA\n");
-	p += sprintf(p, "DMA\n");
-	p += sprintf(p, "PIO\n");
-
-	return p-buffer;	/* => must be less than 4k! */
-}
-#endif  /* defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-byte amd74xx_proc = 0;
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-static unsigned int amd74xx_swdma_check (struct pci_dev *dev)
-{
-	unsigned int class_rev;
-
-	if ((dev->device == PCI_DEVICE_ID_AMD_VIPER_7411) ||
-	    (dev->device == PCI_DEVICE_ID_AMD_VIPER_7441))
-		return 0;
-
-	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;
-	return ((int) (class_rev >= 7) ? 1 : 0);
-}
-
-static int amd74xx_swdma_error(ide_drive_t *drive)
-{
-	printk("%s: single-word DMA not support (revision < C4)\n", drive->name);
-	return 0;
-}
-
-/*
- * Here is where all the hard work goes to program the chipset.
- *
- */
-static int amd74xx_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	int err			= 0;
-	byte unit		= (drive->select.b.unit & 0x01);
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	unsigned long dma_base	= hwif->dma_base;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-	byte drive_pci		= 0x00;
-	byte drive_pci2		= 0x00;
-	byte ultra_timing	= 0x00;
-	byte dma_pio_timing	= 0x00;
-	byte pio_timing		= 0x00;
-
-        switch (drive->dn) {
-		case 0: drive_pci = 0x53; drive_pci2 = 0x4b; break;
-		case 1: drive_pci = 0x52; drive_pci2 = 0x4a; break;
-		case 2: drive_pci = 0x51; drive_pci2 = 0x49; break;
-		case 3: drive_pci = 0x50; drive_pci2 = 0x48; break;
-		default:
-                        return -1;
-        }
-
-	pci_read_config_byte(dev, drive_pci, &ultra_timing);
-	pci_read_config_byte(dev, drive_pci2, &dma_pio_timing);
-	pci_read_config_byte(dev, 0x4c, &pio_timing);
-
-#ifdef DEBUG
-	printk("%s:%d: Speed 0x%02x UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x\n",
-		drive->name, drive->dn, speed, ultra_timing, dma_pio_timing, pio_timing);
-#endif
-
-	ultra_timing	&= ~0xC7;
-	dma_pio_timing	&= ~0xFF;
-	pio_timing	&= ~(0x03 << drive->dn);
-
-#ifdef DEBUG
-	printk("%s: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x\n",
-		drive->name, ultra_timing, dma_pio_timing, pio_timing);
-#endif
-
-	switch(speed) {
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		case XFER_UDMA_7:
-		case XFER_UDMA_6:
-			speed = XFER_UDMA_5;
-		case XFER_UDMA_5:
-			ultra_timing |= 0x46;
-			dma_pio_timing |= 0x20;
-			break;
-		case XFER_UDMA_4:
-			ultra_timing |= 0x45;
-			dma_pio_timing |= 0x20;
-			break;
-		case XFER_UDMA_3:
-			ultra_timing |= 0x44;
-			dma_pio_timing |= 0x20;
-			break;
-		case XFER_UDMA_2:
-			ultra_timing |= 0x40;
-			dma_pio_timing |= 0x20;
-			break;
-		case XFER_UDMA_1:
-			ultra_timing |= 0x41;
-			dma_pio_timing |= 0x20;
-			break;
-		case XFER_UDMA_0:
-		ultra_timing |= 0x42;
-			dma_pio_timing |= 0x20;
-			break;
-		case XFER_MW_DMA_2:
-			dma_pio_timing |= 0x20;
-			break;
-		case XFER_MW_DMA_1:
-			dma_pio_timing |= 0x21;
-			break;
-		case XFER_MW_DMA_0:
-			dma_pio_timing |= 0x77;
-			break;
-		case XFER_SW_DMA_2:
-			if (!amd74xx_swdma_check(dev))
-				return amd74xx_swdma_error(drive);
-			dma_pio_timing |= 0x42;
-			break;
-		case XFER_SW_DMA_1:
-			if (!amd74xx_swdma_check(dev))
-				return amd74xx_swdma_error(drive);
-			dma_pio_timing |= 0x65;
-			break;
-		case XFER_SW_DMA_0:
-			if (!amd74xx_swdma_check(dev))
-				return amd74xx_swdma_error(drive);
-			dma_pio_timing |= 0xA8;
-			break;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-		case XFER_PIO_4:
-			dma_pio_timing |= 0x20;
-			break;
-		case XFER_PIO_3:
-			dma_pio_timing |= 0x22;
-			break;
-		case XFER_PIO_2:
-			dma_pio_timing |= 0x42;
-			break;
-		case XFER_PIO_1:
-			dma_pio_timing |= 0x65;
-			break;
-		case XFER_PIO_0:
-		default:
-			dma_pio_timing |= 0xA8;
-			break;
-        }
-
-	pio_timing |= (0x03 << drive->dn);
-
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	pci_write_config_byte(dev, drive_pci, ultra_timing);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-	pci_write_config_byte(dev, drive_pci2, dma_pio_timing);
-	pci_write_config_byte(dev, 0x4c, pio_timing);
-
-#ifdef DEBUG
-	printk("%s: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x\n",
-		drive->name, ultra_timing, dma_pio_timing, pio_timing);
-#endif
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (speed > XFER_PIO_4) {
-		outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
-	} else {
-		outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
-	}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-	err = ide_config_drive_speed(drive, speed);
-	drive->current_speed = speed;
-	return (err);
-}
-
-static void config_chipset_for_pio (ide_drive_t *drive)
-{
-	unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
-	unsigned short xfer_pio	= drive->id->eide_pio_modes;
-	byte			timing, speed, pio;
-
-	pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
-
-	if (xfer_pio> 4)
-		xfer_pio = 0;
-
-	if (drive->id->eide_pio_iordy > 0) {
-		for (xfer_pio = 5;
-			xfer_pio>0 &&
-			drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
-			xfer_pio--);
-	} else {
-		xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
-			   (drive->id->eide_pio_modes & 2) ? 0x04 :
-			   (drive->id->eide_pio_modes & 1) ? 0x03 :
-			   (drive->id->tPIO & 2) ? 0x02 :
-			   (drive->id->tPIO & 1) ? 0x01 : xfer_pio;
-	}
-
-	timing = (xfer_pio >= pio) ? xfer_pio : pio;
-
-	switch(timing) {
-		case 4: speed = XFER_PIO_4;break;
-		case 3: speed = XFER_PIO_3;break;
-		case 2: speed = XFER_PIO_2;break;
-		case 1: speed = XFER_PIO_1;break;
-		default:
-			speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW;
-			break;
-	}
-	(void) amd74xx_tune_chipset(drive, speed);
-	drive->current_speed = speed;
-}
-
-static void amd74xx_tune_drive (ide_drive_t *drive, byte pio)
-{
-	byte speed;
-	switch(pio) {
-		case 4:		speed = XFER_PIO_4;break;
-		case 3:		speed = XFER_PIO_3;break;
-		case 2:		speed = XFER_PIO_2;break;
-		case 1:		speed = XFER_PIO_1;break;
-		default:	speed = XFER_PIO_0;break;
-	}
-	(void) amd74xx_tune_chipset(drive, speed);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-/*
- * This allows the configuration of ide_pci chipset registers
- * for cards that learn about the drive's UDMA, DMA, PIO capabilities
- * after the drive is reported by the OS.
- */
-static int config_chipset_for_dma (ide_drive_t *drive)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	struct hd_driveid *id	= drive->id;
-	byte udma_66		= eighty_ninty_three(drive);
-	byte udma_100		= ((dev->device==PCI_DEVICE_ID_AMD_VIPER_7411)||
-				   (dev->device==PCI_DEVICE_ID_AMD_VIPER_7441)) ? 1 : 0;
-	byte speed		= 0x00;
-	int  rval;
-
-	if (udma_100)
-		udma_66 = eighty_ninty_three(drive);
-
-	if ((id->dma_ultra & 0x0020) && (udma_66) && (udma_100)) {
-		speed = XFER_UDMA_5;
-	} else if ((id->dma_ultra & 0x0010) && (udma_66)) {
-		speed = XFER_UDMA_4;
-	} else if ((id->dma_ultra & 0x0008) && (udma_66)) {
-		speed = XFER_UDMA_3;
-	} else if (id->dma_ultra & 0x0004) {
-		speed = XFER_UDMA_2;
-	} else if (id->dma_ultra & 0x0002) {
-		speed = XFER_UDMA_1;
-	} else if (id->dma_ultra & 0x0001) {
-		speed = XFER_UDMA_0;
-	} else if (id->dma_mword & 0x0004) {
-		speed = XFER_MW_DMA_2;
-	} else if (id->dma_mword & 0x0002) {
-		speed = XFER_MW_DMA_1;
-	} else if (id->dma_mword & 0x0001) {
-		speed = XFER_MW_DMA_0;
-	} else {
-		return ((int) ide_dma_off_quietly);
-	}
-
-	(void) amd74xx_tune_chipset(drive, speed);
-
-	rval = (int)(	((id->dma_ultra >> 11) & 7) ? ide_dma_on :
-			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-			((id->dma_mword >> 8) & 7) ? ide_dma_on :
-						     ide_dma_off_quietly);
-
-	return rval;
-}
-
-static int config_drive_xfer_rate (ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-	ide_dma_action_t dma_func = ide_dma_on;
-
-	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x003F) {
-				/* Force if Capable UltraDMA */
-				dma_func = config_chipset_for_dma(drive);
-				if ((id->field_valid & 2) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    ((id->dma_1word & 0x007) &&
-			     (amd74xx_swdma_check(HWIF(drive)->pci_dev)))) {
-				/* Force if Capable regular DMA modes */
-				dma_func = config_chipset_for_dma(drive);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-			
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			dma_func = config_chipset_for_dma(drive);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-
-		config_chipset_for_pio(drive);
-	}
-	return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-/*
- * amd74xx_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
- */
-
-int amd74xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch (func) {
-		case ide_dma_check:
-			return config_drive_xfer_rate(drive);
-		default:
-			break;
-	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-unsigned int __init pci_init_amd74xx (struct pci_dev *dev, const char *name)
-{
-	unsigned long fixdma_base = pci_resource_start(dev, 4);
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (!amd74xx_swdma_check(dev))
-		printk("%s: disabling single-word DMA support (revision < C4)\n", name);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-	if (!fixdma_base) {
-		/*
-		 *
-		 */
-	} else {
-		/*
-		 * enable DMA capable bit, and "not" simplex only
-		 */
-		outb(inb(fixdma_base+2) & 0x60, fixdma_base+2);
-
-		if (inb(fixdma_base+2) & 0x80)
-			printk("%s: simplex device: DMA will fail!!\n", name);
-	}
-#if defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!amd74xx_proc) {
-		amd74xx_proc = 1;
-		bmide_dev = dev;
-		amd74xx_display_info = &amd74xx_get_info;
-	}
-#endif /* DISPLAY_VIPER_TIMINGS && CONFIG_PROC_FS */
-
-	return 0;
-}
-
-unsigned int __init ata66_amd74xx (ide_hwif_t *hwif)
-{
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte cable_80_pin[2]	= { 0, 0 };
-	byte ata66		= 0;
-	byte tmpbyte;
-
-	/*
-	 * Ultra66 cable detection (from Host View)
-	 * 7411, 7441, 0x42, bit0: primary, bit2: secondary 80 pin
-	 */
-	pci_read_config_byte(dev, 0x42, &tmpbyte);
-
-	/*
-	 * 0x42, bit0 is 1 => primary channel
-	 * has 80-pin (from host view)
-	 */
-	if (tmpbyte & 0x01) cable_80_pin[0] = 1;
-
-	/*
-	 * 0x42, bit2 is 1 => secondary channel
-	 * has 80-pin (from host view)
-	 */
-	if (tmpbyte & 0x04) cable_80_pin[1] = 1;
-
-	switch(dev->device) {
-		case PCI_DEVICE_ID_AMD_VIPER_7441:
-		case PCI_DEVICE_ID_AMD_VIPER_7411:
-			ata66 = (hwif->channel) ?
-				cable_80_pin[1] :
-				cable_80_pin[0];
-		default:
-			break;
-	}
-#ifdef CONFIG_AMD74XX_OVERRIDE
-	return(1);
-#else
-	return (unsigned int) ata66;
-#endif /* CONFIG_AMD74XX_OVERRIDE */
-}
-
-void __init ide_init_amd74xx (ide_hwif_t *hwif)
-{
-	hwif->tuneproc = &amd74xx_tune_drive;
-	hwif->speedproc = &amd74xx_tune_chipset;
-
-#ifndef CONFIG_BLK_DEV_IDEDMA
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-	hwif->autodma = 0;
-	return;
-#else
-
-	if (hwif->dma_base) {
-		hwif->dmaproc = &amd74xx_dmaproc;
-		if (!noautodma)
-			hwif->autodma = 1;
-	} else {
-		hwif->autodma = 0;
-		hwif->drives[0].autotune = 1;
-		hwif->drives[1].autotune = 1;
-	}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-}
-
-void __init ide_dmacapable_amd74xx (ide_hwif_t *hwif, unsigned long dmabase)
-{
-	ide_setup_dma(hwif, dmabase, 8);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/arm/Makefile linux-2.4.21-pre6/drivers/ide/arm/Makefile
--- linux-2.4.20/drivers/ide/arm/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/arm/Makefile	2003-03-26 23:49:40.000000000 +0000
@@ -0,0 +1,12 @@
+
+O_TARGET := idedriver-arm.o
+
+obj-y		:=
+obj-m		:=
+
+obj-$(CONFIG_BLK_DEV_IDE_ICSIDE)	+= icside.o
+obj-$(CONFIG_BLK_DEV_IDE_RAPIDE)	+= rapide.o
+
+EXTRA_CFLAGS	:= -I../
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/arm/icside.c linux-2.4.21-pre6/drivers/ide/arm/icside.c
--- linux-2.4.20/drivers/ide/arm/icside.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/arm/icside.c	2003-03-26 23:49:02.000000000 +0000
@@ -0,0 +1,875 @@
+/*
+ * linux/drivers/ide/arm/icside.c
+ *
+ * Copyright (c) 1996,1997 Russell King.
+ *
+ * Changelog:
+ *  08-Jun-1996	RMK	Created
+ *  12-Sep-1997	RMK	Added interrupt enable/disable
+ *  17-Apr-1999	RMK	Added support for V6 EASI
+ *  22-May-1999	RMK	Added support for V6 DMA
+ */
+
+#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/errno.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+
+#include <asm/dma.h>
+#include <asm/ecard.h>
+#include <asm/io.h>
+
+#include "ide-noise.h"
+
+/*
+ * FIXME: We want to drop the the MACRO CRAP!
+ *
+ * ec->iops->in{b/w/l}
+ * ec->iops->in{b/w/l}_p
+ * ec->iops->out{b/w/l}
+ * ec->iops->out{b/w/l}_p
+ *
+ * the new core supports clean MMIO calls and other goodies
+ */
+
+/*
+ * Maximum number of interfaces per card
+ */
+#define MAX_IFS	2
+
+#define ICS_IDENT_OFFSET		0x8a0
+
+#define ICS_ARCIN_V5_INTRSTAT		0x000
+#define ICS_ARCIN_V5_INTROFFSET		0x001
+#define ICS_ARCIN_V5_IDEOFFSET		0xa00
+#define ICS_ARCIN_V5_IDEALTOFFSET	0xae0
+#define ICS_ARCIN_V5_IDESTEPPING	4
+
+#define ICS_ARCIN_V6_IDEOFFSET_1	0x800
+#define ICS_ARCIN_V6_INTROFFSET_1	0x880
+#define ICS_ARCIN_V6_INTRSTAT_1		0x8a4
+#define ICS_ARCIN_V6_IDEALTOFFSET_1	0x8e0
+#define ICS_ARCIN_V6_IDEOFFSET_2	0xc00
+#define ICS_ARCIN_V6_INTROFFSET_2	0xc80
+#define ICS_ARCIN_V6_INTRSTAT_2		0xca4
+#define ICS_ARCIN_V6_IDEALTOFFSET_2	0xce0
+#define ICS_ARCIN_V6_IDESTEPPING	4
+
+struct cardinfo {
+	unsigned int dataoffset;
+	unsigned int ctrloffset;
+	unsigned int stepping;
+};
+
+static struct cardinfo icside_cardinfo_v5 = {
+	ICS_ARCIN_V5_IDEOFFSET,
+	ICS_ARCIN_V5_IDEALTOFFSET,
+	ICS_ARCIN_V5_IDESTEPPING
+};
+
+static struct cardinfo icside_cardinfo_v6_1 = {
+	ICS_ARCIN_V6_IDEOFFSET_1,
+	ICS_ARCIN_V6_IDEALTOFFSET_1,
+	ICS_ARCIN_V6_IDESTEPPING
+};
+
+static struct cardinfo icside_cardinfo_v6_2 = {
+	ICS_ARCIN_V6_IDEOFFSET_2,
+	ICS_ARCIN_V6_IDEALTOFFSET_2,
+	ICS_ARCIN_V6_IDESTEPPING
+};
+
+static const card_ids icside_cids[] = {
+	{ MANU_ICS,  PROD_ICS_IDE  },
+	{ MANU_ICS2, PROD_ICS2_IDE },
+	{ 0xffff, 0xffff }
+};
+
+typedef enum {
+	ics_if_unknown,
+	ics_if_arcin_v5,
+	ics_if_arcin_v6
+} iftype_t;
+
+/* ---------------- Version 5 PCB Support Functions --------------------- */
+/* Prototype: icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
+ * Purpose  : enable interrupts from card
+ */
+static void icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
+{
+	unsigned int memc_port = (unsigned int)ec->irq_data;
+	outb(0, memc_port + ICS_ARCIN_V5_INTROFFSET);
+}
+
+/* Prototype: icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
+ * Purpose  : disable interrupts from card
+ */
+static void icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
+{
+	unsigned int memc_port = (unsigned int)ec->irq_data;
+	inb(memc_port + ICS_ARCIN_V5_INTROFFSET);
+}
+
+static const expansioncard_ops_t icside_ops_arcin_v5 = {
+	icside_irqenable_arcin_v5,
+	icside_irqdisable_arcin_v5,
+	NULL,
+	NULL,
+	NULL,
+	NULL
+};
+
+
+/* ---------------- Version 6 PCB Support Functions --------------------- */
+/* Prototype: icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
+ * Purpose  : enable interrupts from card
+ */
+static void icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
+{
+	unsigned int ide_base_port = (unsigned int)ec->irq_data;
+
+	outb(0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_1);
+	outb(0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_2);
+}
+
+/* Prototype: icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
+ * Purpose  : disable interrupts from card
+ */
+static void icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
+{
+	unsigned int ide_base_port = (unsigned int)ec->irq_data;
+
+	inb(ide_base_port + ICS_ARCIN_V6_INTROFFSET_1);
+	inb(ide_base_port + ICS_ARCIN_V6_INTROFFSET_2);
+}
+
+/* Prototype: icside_irqprobe(struct expansion_card *ec)
+ * Purpose  : detect an active interrupt from card
+ */
+static int icside_irqpending_arcin_v6(struct expansion_card *ec)
+{
+	unsigned int ide_base_port = (unsigned int)ec->irq_data;
+
+	return inb(ide_base_port + ICS_ARCIN_V6_INTRSTAT_1) & 1 ||
+	       inb(ide_base_port + ICS_ARCIN_V6_INTRSTAT_2) & 1;
+}
+
+static const expansioncard_ops_t icside_ops_arcin_v6 = {
+	icside_irqenable_arcin_v6,
+	icside_irqdisable_arcin_v6,
+	icside_irqpending_arcin_v6,
+	NULL,
+	NULL,
+	NULL
+};
+
+/* Prototype: icside_identifyif (struct expansion_card *ec)
+ * Purpose  : identify IDE interface type
+ * Notes    : checks the description string
+ */
+static iftype_t __init icside_identifyif (struct expansion_card *ec)
+{
+	unsigned int addr;
+	iftype_t iftype;
+	int id = 0;
+
+	iftype = ics_if_unknown;
+
+	addr = ecard_address (ec, ECARD_IOC, ECARD_FAST) + ICS_IDENT_OFFSET;
+
+	id = inb(addr) & 1;
+	id |= (inb(addr + 1) & 1) << 1;
+	id |= (inb(addr + 2) & 1) << 2;
+	id |= (inb(addr + 3) & 1) << 3;
+
+	switch (id) {
+	case 0: /* A3IN */
+		printk("icside: A3IN unsupported\n");
+		break;
+
+	case 1: /* A3USER */
+		printk("icside: A3USER unsupported\n");
+		break;
+
+	case 3:	/* ARCIN V6 */
+		printk(KERN_DEBUG "icside: detected ARCIN V6 in slot %d\n", ec->slot_no);
+		iftype = ics_if_arcin_v6;
+		break;
+
+	case 15:/* ARCIN V5 (no id) */
+		printk(KERN_DEBUG "icside: detected ARCIN V5 in slot %d\n", ec->slot_no);
+		iftype = ics_if_arcin_v5;
+		break;
+
+	default:/* we don't know - complain very loudly */
+		printk("icside: ***********************************\n");
+		printk("icside: *** UNKNOWN ICS INTERFACE id=%d ***\n", id);
+		printk("icside: ***********************************\n");
+		printk("icside: please report this to linux@arm.linux.org.uk\n");
+		printk("icside: defaulting to ARCIN V5\n");
+		iftype = ics_if_arcin_v5;
+		break;
+	}
+
+	return iftype;
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_ICS
+/*
+ * SG-DMA support.
+ *
+ * Similar to the BM-DMA, but we use the RiscPCs IOMD DMA controllers.
+ * There is only one DMA controller per card, which means that only
+ * one drive can be accessed at one time.  NOTE! We do not enforce that
+ * here, but we rely on the main IDE driver spotting that both
+ * interfaces use the same IRQ, which should guarantee this.
+ */
+#define NR_ENTRIES 256
+#define TABLE_SIZE (NR_ENTRIES * 8)
+
+static int ide_build_sglist(ide_hwif_t *hwif, struct request *rq)
+{
+	struct buffer_head *bh;
+	struct scatterlist *sg = hwif->sg_table;
+	int nents = 0;
+
+	if (rq->cmd == READ)
+		hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
+	else
+		hwif->sg_dma_direction = PCI_DMA_TODEVICE;
+	bh = rq->bh;
+	do {
+		unsigned char *virt_addr = bh->b_data;
+		unsigned int size = bh->b_size;
+
+		while ((bh = bh->b_reqnext) != NULL) {
+			if ((virt_addr + size) != (unsigned char *)bh->b_data)
+				break;
+			size += bh->b_size;
+		}
+		memset(&sg[nents], 0, sizeof(*sg));
+		sg[nents].address = virt_addr;
+		sg[nents].length = size;
+		nents++;
+	} while (bh != NULL);
+
+	return pci_map_sg(NULL, sg, nents, hwif->sg_dma_direction);
+}
+
+static int
+icside_build_dmatable(ide_drive_t *drive, int ddir)
+{
+	return HWIF(drive)->sg_nents = ide_build_sglist(HWIF(drive), HWGROUP(drive)->rq, ddir);
+}
+
+/* Teardown mappings after DMA has completed.  */
+static void icside_destroy_dmatable(ide_drive_t *drive)
+{
+	struct scatterlist *sg = HWIF(drive)->sg_table;
+	int nents = HWIF(drive)->sg_nents;
+
+	pci_unmap_sg(NULL, sg, nents, HWIF(drive)->sg_dma_direction);
+}
+
+static int
+icside_config_if(ide_drive_t *drive, int xfer_mode)
+{
+	int func = ide_dma_off;
+
+	switch (xfer_mode) {
+	case XFER_MW_DMA_2:
+		/*
+		 * The cycle time is limited to 250ns by the r/w
+		 * pulse width (90ns), however we should still
+		 * have a maximum burst transfer rate of 8MB/s.
+		 */
+		drive->drive_data = 250;
+		break;
+
+	case XFER_MW_DMA_1:
+		drive->drive_data = 250;
+		break;
+
+	case XFER_MW_DMA_0:
+		drive->drive_data = 480;
+		break;
+
+	default:
+		drive->drive_data = 0;
+		break;
+	}
+
+	if (!drive->init_speed)
+		drive->init_speed = (u8) xfer_mode;
+
+	if (drive->drive_data &&
+	    ide_config_drive_speed(drive, (u8) xfer_mode) == 0)
+		func = ide_dma_on;
+	else
+		drive->drive_data = 480;
+
+	printk("%s: %s selected (peak %dMB/s)\n", drive->name,
+		ide_xfer_verbose(xfer_mode), 2000 / drive->drive_data);
+
+	drive->current_speed = (u8) xfer_mode;
+
+	return func;
+}
+
+static int
+icside_set_speed(ide_drive_t *drive, u8 speed)
+{
+	return icside_config_if(drive, speed);
+}
+
+/*
+ * dma_intr() is the handler for disk read/write DMA interrupts
+ */
+static ide_startstop_t icside_dmaintr(ide_drive_t *drive)
+{
+	u8 dma_stat	= HWIF(drive)->ide_dma_end(drive);
+	/* get drive status */
+	u8 stat		= HWIF(drive)->INB(IDE_STATUS_REG);
+	int i;
+
+	if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
+		if (!dma_stat) {
+			struct request *rq = HWGROUP(drive)->rq;
+			rq = HWGROUP(drive)->rq;
+			for (i = rq->nr_sectors; i > 0;) {
+				i -= rq->current_nr_sectors;
+				DRIVER(drive)->end_request(drive, 1);
+			}
+			return ide_stopped;
+		}
+		printk("%s: dma_intr: bad DMA status (dma_stat=%x)\n", 
+		       drive->name, dma_stat);
+	}
+	return DRIVER(drive)->error(drive, "dma_intr", stat);
+}
+
+/*
+ * The following is a sick duplication from ide-dma.c ;(
+ *
+ * This should be defined in one place only.
+ */
+struct drive_list_entry {
+	char * id_model;
+	char * id_firmware;
+};
+
+static struct drive_list_entry drive_whitelist [] = {
+	{ "Micropolis 2112A",			"ALL"		},
+	{ "CONNER CTMA 4000",			"ALL"		},
+	{ "CONNER CTT8000-A",			"ALL"		},
+	{ "ST34342A",				"ALL"		},
+	{ NULL,					0		}
+};
+
+static struct drive_list_entry drive_blacklist [] = {
+	{ "WDC AC11000H",			"ALL"		},
+	{ "WDC AC22100H",			"ALL"		},
+	{ "WDC AC32500H",			"ALL"		},
+	{ "WDC AC33100H",			"ALL"		},
+	{ "WDC AC31600H",			"ALL"		},
+	{ "WDC AC32100H",			"24.09P07"	},
+	{ "WDC AC23200L",			"21.10N21"	},
+	{ "Compaq CRD-8241B",			"ALL"		},
+	{ "CRD-8400B",				"ALL"		},
+	{ "CRD-8480B",				"ALL"		},
+	{ "CRD-8480C",				"ALL"		},
+	{ "CRD-8482B",				"ALL"		},
+ 	{ "CRD-84",				"ALL"		},
+	{ "SanDisk SDP3B",			"ALL"		},
+	{ "SanDisk SDP3B-64",			"ALL"		},
+	{ "SANYO CD-ROM CRD",			"ALL"		},
+	{ "HITACHI CDR-8",			"ALL"		},
+	{ "HITACHI CDR-8335",			"ALL"		},
+	{ "HITACHI CDR-8435",			"ALL"		},
+	{ "Toshiba CD-ROM XM-6202B",		"ALL"		},
+	{ "CD-532E-A",				"ALL"		},
+	{ "E-IDE CD-ROM CR-840",		"ALL"		},
+	{ "CD-ROM Drive/F5A",			"ALL"		},
+	{ "RICOH CD-R/RW MP7083A",		"ALL"		},
+	{ "WPI CDD-820",			"ALL"		},
+	{ "SAMSUNG CD-ROM SC-148C",		"ALL"		},
+	{ "SAMSUNG CD-ROM SC-148F",		"ALL"		},
+	{ "SAMSUNG CD-ROM SC",			"ALL"		},
+	{ "SanDisk SDP3B-64",			"ALL"		},
+	{ "SAMSUNG CD-ROM SN-124",		"ALL"		},
+	{ "PLEXTOR CD-R PX-W8432T",		"ALL"		},
+	{ "ATAPI CD-ROM DRIVE 40X MAXIMUM",	"ALL"		},
+	{ "_NEC DV5800A",			"ALL"		},
+	{ NULL,					0		}
+};
+
+static int in_drive_list(struct hd_driveid *id, struct drive_list_entry * drive_table)
+{
+	for ( ; drive_table->id_model ; drive_table++)
+		if ((!strcmp(drive_table->id_model, id->model)) &&
+		    ((!strstr(drive_table->id_firmware, id->fw_rev)) ||
+		     (!strcmp(drive_table->id_firmware, "ALL"))))
+			return 1;
+	return 0;
+}
+
+/*
+ *  For both Blacklisted and Whitelisted drives.
+ *  This is setup to be called as an extern for future support
+ *  to other special driver code.
+ */
+int check_drive_good_lists (ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
+	return in_drive_list(id, drive_whitelist);
+}
+
+int check_drive_bad_lists (ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
+	int blacklist = in_drive_list(id, drive_blacklist);
+	if (blacklist)
+		printk("%s: Disabling DMA for %s\n", drive->name, id->model);
+	return(blacklist);
+}
+
+int icside_dma_check(ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
+	ide_hwif_t *hwif = HWIF(drive);
+	int autodma = hwif->autodma;
+	int xfer_mode = XFER_PIO_2;
+
+	if (!id || !(id->capability & 1) || !autodma)
+		return hwif->ide_dma_off_quietly(drive);
+
+	/*
+	 * Consult the list of known "bad" drives
+	 */
+	if (check_drive_bad_lists(drive))
+		return hwif->ide_dma_off(drive);
+
+	/*
+	 * Enable DMA on any drive that has multiword DMA
+	 */
+	if (id->field_valid & 2) {
+		if (id->dma_mword & 4) {
+			xfer_mode = XFER_MW_DMA_2;
+		} else if (id->dma_mword & 2) {
+			xfer_mode = XFER_MW_DMA_1;
+		} else if (id->dma_mword & 1) {
+			xfer_mode = XFER_MW_DMA_0;
+		}
+		goto out;
+	}
+
+	/*
+	 * Consult the list of known "good" drives
+	 */
+	if (check_drive_good_lists(drive)) {
+		if (id->eide_dma_time > 150)
+			goto out;
+		xfer_mode = XFER_MW_DMA_1;
+	}
+
+out:
+	if (icside_config_if(drive, xfer_mode))
+		return hwif->ide_dma_on(drive);
+	return hwif->ide_dma_off(drive);
+}
+
+int icside_dma_verbose(ide_drive_t *drive)
+{
+	printk(", DMA");
+	return 1;
+}
+
+int icside_dma_test_irq(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	return inb((unsigned long)hwif->hw.priv) & 1;
+}
+
+int icside_dma_host_off(ide_drive_t *drive)
+{
+	return 0;
+}
+
+int icside_dma_off_quietly(ide_drive_t *drive)
+{
+	drive->using_dma = 0;
+	return icside_dma_host_off(drive);
+}
+
+int icside_dma_off(ide_drive_t *drive)
+{
+	printk("%s: DMA disabled\n", drive->name);
+	return icside_dma_off_quietly(drive);
+}
+
+int icside_dma_host_on(ide_drive_t *drive)
+{
+	return 0;
+}
+
+int icside_dma_on(ide_drive_t *drive)
+{
+	drive->using_dma = 1;
+	return icside_dma_host_on(drive);
+}
+
+int icside_dma_begin(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+
+	enable_dma(hwif->hw.dma);
+	return 0;
+}
+
+int icside_dma_end(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+ 
+	drive->waiting_for_dma = 0;
+	disable_dma(hwif->hw.dma);
+	icside_destroy_dmatable(drive);
+	return get_dma_residue(hwif->hw.dma) != 0;
+}
+
+int icside_dma_count (ide_drive_t *drive)
+{
+        return icside_dma_begin(drive);
+}
+
+int icside_dma_read(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+//	ide_task_t *args	= HWGROUP(drive)->rq->special;
+	int count		= 0;
+	u8 lba48		= (drive->addressing == 1) ? 1 : 0;
+	task_ioreg_t command	= WIN_NOP;
+
+	count = icside_build_dmatable(drive, PCI_DMA_FROMDEVICE);
+	if (!count)
+		return 1;
+	disable_dma(hwif->hw.dma);
+
+	/* Route the DMA signals to
+	 * to the correct interface.
+	 */
+	HWIF(drive)->OUTB(hwif->select_data, hwif->config_data);
+
+	/* Select the correct timing
+	 * for this drive
+	 */
+	set_dma_speed(hwif->hw.dma, drive->drive_data);
+
+	set_dma_sg(hwif->hw.dma, HWIF(drive)->sg_table, count);
+	set_dma_mode(hwif->hw.dma, DMA_MODE_READ);
+
+	drive->waiting_for_dma = 1;
+	if (drive->media != ide_disk)
+		return 0;
+
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
+	ide_set_handler(drive, &icside_dmaintr, WAIT_CMD, NULL);
+	/*
+	 * FIX ME to use only ACB ide_task_t args Struct
+	 */
+#if 0
+	{
+		ide_task_t *args = HWGROUP(drive)->rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#else
+	command = (lba48) ? WIN_READDMA_EXT : WIN_READDMA;
+		if (HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE) {
+		ide_task_t *args = HWGROUP(drive)->rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#endif
+	/* issue cmd to drive */
+	HWIF(drive)->OUTB(command, IDE_COMMAND_REG);
+
+	return icside_dma_count(drive);
+}
+
+int icside_dma_write(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+//	ide_task_t *args	= HWGROUP(drive)->rq->special;
+	int count		= 0;
+	u8 lba48		= (drive->addressing == 1) ? 1 : 0;
+	task_ioreg_t command	= WIN_NOP;
+
+	count = icside_build_dmatable(drive, PCI_DMA_TODEVICE);
+	if (!count)
+		return 1;
+	disable_dma(hwif->hw.dma);
+
+	/* Route the DMA signals to
+	 * to the correct interface.
+	 */
+	HWIF(drive)->OUTB(hwif->select_data, hwif->config_data);
+
+	/* Select the correct timing
+	 * for this drive
+	 */
+	set_dma_speed(hwif->hw.dma, drive->drive_data);
+
+	set_dma_sg(hwif->hw.dma, HWIF(drive)->sg_table, count);
+	set_dma_mode(hwif->hw.dma, DMA_MODE_WRITE);
+
+	drive->waiting_for_dma = 1;
+	if (drive->media != ide_disk)
+		return 0;
+
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	ide_set_handler(drive, &icside_dmaintr, WAIT_CMD, NULL);
+	/*
+	 * FIX ME to use only ACB ide_task_t args Struct
+	 */
+#if 0
+	{
+		ide_task_t *args = HWGROUP(drive)->rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#else
+	command = (lba48) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
+	if (HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE) {
+		ide_task_t *args = HWGROUP(drive)->rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#endif
+	/* issue cmd to drive */
+	HWIF(drive)->OUTB(command, IDE_COMMAND_REG);
+
+	return icside_dma_count(drive);
+}
+
+static int
+icside_setup_dma(ide_hwif_t *hwif, int autodma)
+{
+	printk("    %s: SG-DMA", hwif->name);
+
+	hwif->sg_table = kmalloc(sizeof(struct scatterlist) * NR_ENTRIES,
+				 GFP_KERNEL);
+	if (!hwif->sg_table)
+		goto failed;
+
+	hwif->dmatable_cpu = NULL;
+	hwif->dmatable_dma = 0;
+	hwif->speedproc = icside_set_speed;
+	hwif->autodma = autodma;
+
+	hwif->ide_dma_check = icside_dma_check;
+	hwif->ide_dma_host_off = icside_dma_host_off;
+	hwif->ide_dma_off_quietly = icside_dma_off_quietly;
+	hwif->ide_dma_off = icside_dma_off;
+	hwif->ide_dma_host_on = icside_dma_host_on;
+	hwif->ide_dma_on = icside_dma_on;
+	hwif->ide_dma_read = icside_dma_read;
+	hwif->ide_dma_write = icside_dma_write;
+	hwif->ide_dma_count = icside_dma_count;
+	hwif->ide_dma_begin = icside_dma_begin;
+	hwif->ide_dma_end = icside_dma_end;
+	hwif->ide_dma_verbose = icside_dma_verbose;
+	hwif->ide_dma_bad_drive = check_drive_bad_lists;
+	hwif->ide_dma_good_drive = check_drive_good_lists;
+	hwif->ide_dma_test_irq = icside_dma_test_irq;
+
+	printk(" capable%s\n", autodma ?
+		", auto-enable" : "");
+
+	return 1;
+
+failed:
+	printk(" -- ERROR, unable to allocate DMA table\n");
+	return 0;
+}
+#endif
+
+static ide_hwif_t *
+icside_find_hwif(unsigned long dataport)
+{
+	ide_hwif_t *hwif;
+	int index;
+
+	for (index = 0; index < MAX_HWIFS; ++index) {
+		hwif = &ide_hwifs[index];
+		if (hwif->io_ports[IDE_DATA_OFFSET] == (ide_ioreg_t)dataport)
+			goto found;
+	}
+
+	for (index = 0; index < MAX_HWIFS; ++index) {
+		hwif = &ide_hwifs[index];
+		if (!hwif->io_ports[IDE_DATA_OFFSET])
+			goto found;
+	}
+
+	return NULL;
+found:
+	return hwif;
+}
+
+static ide_hwif_t *
+icside_setup(unsigned long base, struct cardinfo *info, int irq)
+{
+	unsigned long port = base + info->dataoffset;
+	ide_hwif_t *hwif;
+
+	hwif = icside_find_hwif(base);
+	if (hwif) {
+		int i;
+
+		memset(&hwif->hw, 0, sizeof(hw_regs_t));
+
+		for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+			hwif->hw.io_ports[i] = (ide_ioreg_t)port;
+			hwif->io_ports[i] = (ide_ioreg_t)port;
+			port += 1 << info->stepping;
+		}
+		hwif->hw.io_ports[IDE_CONTROL_OFFSET] = base + info->ctrloffset;
+		hwif->io_ports[IDE_CONTROL_OFFSET] = base + info->ctrloffset;
+		hwif->hw.irq  = irq;
+		hwif->irq     = irq;
+		hwif->hw.dma  = NO_DMA;
+		hwif->noprobe = 0;
+		hwif->chipset = ide_acorn;
+	}
+
+	return hwif;
+}
+
+static int __init icside_register_v5(struct expansion_card *ec, int autodma)
+{
+	unsigned long slot_port;
+	ide_hwif_t *hwif;
+
+	slot_port = ecard_address(ec, ECARD_MEMC, 0);
+
+	ec->irqaddr  = (unsigned char *)ioaddr(slot_port + ICS_ARCIN_V5_INTRSTAT);
+	ec->irqmask  = 1;
+	ec->irq_data = (void *)slot_port;
+	ec->ops      = (expansioncard_ops_t *)&icside_ops_arcin_v5;
+
+	/*
+	 * Be on the safe side - disable interrupts
+	 */
+	inb(slot_port + ICS_ARCIN_V5_INTROFFSET);
+
+	hwif = icside_setup(slot_port, &icside_cardinfo_v5, ec->irq);
+
+	return hwif ? 0 : -1;
+}
+
+static int __init icside_register_v6(struct expansion_card *ec, int autodma)
+{
+	unsigned long slot_port, port;
+	ide_hwif_t *hwif, *mate;
+	int sel = 0;
+
+	slot_port = ecard_address(ec, ECARD_IOC, ECARD_FAST);
+	port      = ecard_address(ec, ECARD_EASI, ECARD_FAST);
+
+	if (port == 0)
+		port = slot_port;
+	else
+		sel = 1 << 5;
+
+	outb(sel, slot_port);
+
+	ec->irq_data = (void *)port;
+	ec->ops      = (expansioncard_ops_t *)&icside_ops_arcin_v6;
+
+	/*
+	 * Be on the safe side - disable interrupts
+	 */
+	inb(port + ICS_ARCIN_V6_INTROFFSET_1);
+	inb(port + ICS_ARCIN_V6_INTROFFSET_2);
+
+	hwif = icside_setup(port, &icside_cardinfo_v6_1, ec->irq);
+	mate = icside_setup(port, &icside_cardinfo_v6_2, ec->irq);
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_ICS
+	if (ec->dma != NO_DMA) {
+		if (request_dma(ec->dma, hwif->name))
+			goto no_dma;
+
+		if (hwif) {
+			hwif->config_data = slot_port;
+			hwif->select_data = sel;
+			hwif->hw.dma  = ec->dma;
+			hwif->hw.priv = (void *)
+					(port + ICS_ARCIN_V6_INTRSTAT_1);
+			hwif->channel = 0;
+			icside_setup_dma(hwif, autodma);
+			hwif->drives[0].autodma = autodma;
+			hwif->drives[1].autodma = autodma;
+		}
+		if (mate) {
+			mate->config_data = slot_port;
+			mate->select_data = sel | 1;
+			mate->hw.dma  = ec->dma;
+			mate->hw.priv = (void *)
+					(port + ICS_ARCIN_V6_INTRSTAT_2);
+			mate->channel = 1;
+			icside_setup_dma(mate, autodma);
+			mate->drives[0].autodma = autodma;
+			mate->drives[1].autodma = autodma;
+		}
+	}
+no_dma:
+#endif
+	return hwif || mate ? 0 : -1;
+}
+
+int __init icside_init(void)
+{
+	int autodma = 0;
+
+#ifdef CONFIG_IDEDMA_ICS_AUTO
+	autodma = 1;
+#endif
+
+	ecard_startfind ();
+
+	do {
+		struct expansion_card *ec;
+		int result;
+
+		ec = ecard_find(0, icside_cids);
+		if (ec == NULL)
+			break;
+
+		ecard_claim(ec);
+
+		switch (icside_identifyif(ec)) {
+		case ics_if_arcin_v5:
+			result = icside_register_v5(ec, autodma);
+			break;
+
+		case ics_if_arcin_v6:
+			result = icside_register_v6(ec, autodma);
+			break;
+
+		default:
+			result = -1;
+			break;
+		}
+
+		if (result)
+			ecard_release(ec);
+	} while (1);
+
+	return 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/arm/rapide.c linux-2.4.21-pre6/drivers/ide/arm/rapide.c
--- linux-2.4.20/drivers/ide/arm/rapide.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/arm/rapide.c	2003-03-26 23:49:20.000000000 +0000
@@ -0,0 +1,94 @@
+/*
+ * linux/drivers/ide/arm/rapide.c
+ *
+ * Copyright (c) 1996-1998 Russell King.
+ *
+ * Changelog:
+ *  08-06-1996	RMK	Created
+ *  13-04-1998	RMK	Added manufacturer and product IDs
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/errno.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/ecard.h>
+
+static card_ids __init rapide_cids[] = {
+	{ MANU_YELLOWSTONE, PROD_YELLOWSTONE_RAPIDE32 },
+	{ 0xffff, 0xffff }
+};
+
+static struct expansion_card *ec[MAX_ECARDS];
+static int result[MAX_ECARDS];
+
+static inline int rapide_register(struct expansion_card *ec)
+{
+	unsigned long port = ecard_address (ec, ECARD_MEMC, 0);
+	hw_regs_t hw;
+
+	int i;
+
+	memset(&hw, 0, sizeof(hw));
+
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+		hw.io_ports[i] = (ide_ioreg_t)port;
+		port += 1 << 4;
+	}
+	hw.io_ports[IDE_CONTROL_OFFSET] = port + 0x206;
+	hw.irq = ec->irq;
+
+	return ide_register_hw(&hw, NULL);
+}
+
+int __init rapide_init(void)
+{
+	int i;
+
+	for (i = 0; i < MAX_ECARDS; i++)
+		ec[i] = NULL;
+
+	ecard_startfind();
+
+	for (i = 0; ; i++) {
+		if ((ec[i] = ecard_find(0, rapide_cids)) == NULL)
+			break;
+
+		ecard_claim(ec[i]);
+		result[i] = rapide_register(ec[i]);
+	}
+	for (i = 0; i < MAX_ECARDS; i++)
+		if (ec[i] && result[i] < 0) {
+			ecard_release(ec[i]);
+			ec[i] = NULL;
+	}
+	return 0;
+}
+
+#ifdef MODULE
+MODULE_LICENSE("GPL");
+
+int init_module (void)
+{
+	return rapide_init();
+}
+
+void cleanup_module (void)
+{
+	int i;
+
+	for (i = 0; i < MAX_ECARDS; i++)
+		if (ec[i]) {
+			unsigned long port;
+			port = ecard_address(ec[i], ECARD_MEMC, 0);
+
+			ide_unregister_port(port, ec[i]->irq, 16);
+			ecard_release(ec[i]);
+			ec[i] = NULL;
+		}
+}
+#endif
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ataraid.c linux-2.4.21-pre6/drivers/ide/ataraid.c
--- linux-2.4.20/drivers/ide/ataraid.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/ataraid.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,313 +0,0 @@
-/*
-   ataraid.c  Copyright (C) 2001 Red Hat, Inc. 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, or (at your option)
-   any later version.
-   
-   You should have received a copy of the GNU General Public License
-   (for example /usr/src/linux/COPYING); if not, write to the Free
-   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
-   
-   Authors: 	Arjan van de Ven <arjanv@redhat.com>
-   		
-   
-*/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <asm/semaphore.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/blkdev.h>
-#include <linux/blkpg.h>
-#include <linux/genhd.h>
-#include <linux/ioctl.h>
-#include <linux/kdev_t.h>
-#include <linux/swap.h>
-
-#include <linux/ide.h>
-#include <asm/uaccess.h>
-
-#include "ataraid.h"
-
-                                        
-static int ataraid_hardsect_size[256];
-static int ataraid_blksize_size[256];
-
-static struct raid_device_operations* ataraid_ops[16];
-
-static int ataraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
-static int ataraid_open(struct inode * inode, struct file * filp);
-static int ataraid_release(struct inode * inode, struct file * filp);
-static void ataraid_split_request(request_queue_t *q, int rw, struct buffer_head * bh);
-
-
-struct gendisk ataraid_gendisk;
-static int ataraid_gendisk_sizes[256];
-static int ataraid_readahead[256];
-
-static struct block_device_operations ataraid_fops = {
-	owner:			THIS_MODULE,
-	open:                   ataraid_open,
-	release:                ataraid_release,
-	ioctl:                  ataraid_ioctl,
-};
-                
-
-
-static DECLARE_MUTEX(ataraid_sem);
-
-/* Bitmap for the devices currently in use */
-static unsigned int ataraiduse;
-
-
-/* stub fops functions */
-
-static int ataraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)  
-{
-	int minor;
-	minor = MINOR(inode->i_rdev)>>SHIFT;
-	
-	if ((ataraid_ops[minor])&&(ataraid_ops[minor]->ioctl))
-		return (ataraid_ops[minor]->ioctl)(inode,file,cmd,arg);
-	return -EINVAL;
-}
-
-static int ataraid_open(struct inode * inode, struct file * filp)
-{
-	int minor;
-	minor = MINOR(inode->i_rdev)>>SHIFT;
-
-	if ((ataraid_ops[minor])&&(ataraid_ops[minor]->open))
-		return (ataraid_ops[minor]->open)(inode,filp);
-	return -EINVAL;
-}
-
-
-static int ataraid_release(struct inode * inode, struct file * filp)
-{
-	int minor;
-	minor = MINOR(inode->i_rdev)>>SHIFT;
-
-	if ((ataraid_ops[minor])&&(ataraid_ops[minor]->release))
-		return (ataraid_ops[minor]->release)(inode,filp);
-	return -EINVAL;
-}
-
-static int ataraid_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
-{
-	int minor;
-	int retval;
-	minor = MINOR(bh->b_rdev)>>SHIFT;
-
-	if ((ataraid_ops[minor])&&(ataraid_ops[minor]->make_request)) {
-		
-		retval= (ataraid_ops[minor]->make_request)(q,rw,bh);
-		if (retval == -1) {
-			ataraid_split_request(q,rw,bh);		
-			return 0;
-		} else
-			return retval;
-	}
-	return -EINVAL;
-}
-
-struct buffer_head *ataraid_get_bhead(void)
-{
-	void *ptr = NULL;
-	while (!ptr) {
-		ptr=kmalloc(sizeof(struct buffer_head),GFP_NOIO);
-		if (!ptr)
-			yield();
-	}
-	return ptr;
-}
-
-EXPORT_SYMBOL(ataraid_get_bhead);
-
-struct ataraid_bh_private *ataraid_get_private(void)
-{
-	void *ptr = NULL;
-	while (!ptr) {
-		ptr=kmalloc(sizeof(struct ataraid_bh_private),GFP_NOIO);
-		if (!ptr)
-			yield();
-	}
-	return ptr;
-}
-
-EXPORT_SYMBOL(ataraid_get_private);
-
-void ataraid_end_request(struct buffer_head *bh, int uptodate)
-{
-	struct ataraid_bh_private *private = bh->b_private;
-
-	if (private==NULL)
-		BUG();
-
-	if (atomic_dec_and_test(&private->count)) {
-		private->parent->b_end_io(private->parent,uptodate);
-		private->parent = NULL;
-		kfree(private);
-	}
-	kfree(bh);
-}
-
-EXPORT_SYMBOL(ataraid_end_request);
-
-static void ataraid_split_request(request_queue_t *q, int rw, struct buffer_head * bh)
-{
-	struct buffer_head *bh1,*bh2;
-	struct ataraid_bh_private *private;
-	bh1=ataraid_get_bhead();
-	bh2=ataraid_get_bhead();
-
-	/* If either of those ever fails we're doomed */
-	if ((!bh1)||(!bh2))
-		BUG();
-	private = ataraid_get_private();
-	if (private==NULL)
-		BUG();
-	
-	memcpy(bh1, bh, sizeof(*bh));
-	memcpy(bh2, bh, sizeof(*bh));
-	
-	bh1->b_end_io = ataraid_end_request;
-	bh2->b_end_io = ataraid_end_request;
-
-	bh2->b_rsector += bh->b_size >> 10;
-	bh1->b_size /= 2;
-	bh2->b_size /= 2;
-	private->parent = bh;
-
-	bh1->b_private = private;
-	bh2->b_private = private;
-	atomic_set(&private->count,2);
-
-	bh2->b_data +=  bh->b_size/2;
-
-	generic_make_request(rw,bh1);
-	generic_make_request(rw,bh2);
-}
-
-
-
-
-/* device register / release functions */
-
-
-int ataraid_get_device(struct raid_device_operations *fops)
-{
-	int bit;
-	down(&ataraid_sem);
-	if (ataraiduse==~0U) {
-		up(&ataraid_sem);
-		return -ENODEV;
-	}
-	bit=ffz(ataraiduse); 
-	ataraiduse |= 1<<bit;
-	ataraid_ops[bit] = fops;
-	up(&ataraid_sem);
-	return bit;
-}
-
-void ataraid_release_device(int device)
-{
-	down(&ataraid_sem);
-	
-	if ((ataraiduse & (1<<device))==0)
-		BUG();	/* device wasn't registered at all */
-	
-	ataraiduse &= ~(1<<device);
-	ataraid_ops[device] = NULL;
-	up(&ataraid_sem);
-}
-
-void ataraid_register_disk(int device,long size)
-{
-	register_disk(&ataraid_gendisk, MKDEV(ATAMAJOR,16*device),16,
-		&ataraid_fops,size);
-
-}
-
-static __init int ataraid_init(void) 
-{
-	int i;
-        for(i=0;i<256;i++)
-	{
-        	ataraid_hardsect_size[i] = 512;
-		ataraid_blksize_size[i] = 1024;  
-		ataraid_readahead[i] = 1023;
-	}
-	
-	if (blksize_size[ATAMAJOR]==NULL)
-		blksize_size[ATAMAJOR] = ataraid_blksize_size;
-	if (hardsect_size[ATAMAJOR]==NULL)
-		hardsect_size[ATAMAJOR] = ataraid_hardsect_size;
-	
-	
-	/* setup the gendisk structure */	
-	ataraid_gendisk.part = kmalloc(256 * sizeof(struct hd_struct),GFP_KERNEL);
-	if (ataraid_gendisk.part==NULL) {
-		printk(KERN_ERR "ataraid: Couldn't allocate memory, aborting \n");
-		return -1;
-	}
-	
-	memset(&ataraid_gendisk.part[0],0,256*sizeof(struct hd_struct));
-	
-	
-	ataraid_gendisk.major       = ATAMAJOR;
-	ataraid_gendisk.major_name  = "ataraid";
-	ataraid_gendisk.minor_shift = 4;
-	ataraid_gendisk.max_p	    = 15;
-	ataraid_gendisk.sizes	    = &ataraid_gendisk_sizes[0];
-	ataraid_gendisk.nr_real	    = 16;
-	ataraid_gendisk.fops        = &ataraid_fops;
-	
-	
-	add_gendisk(&ataraid_gendisk);
-			
-	if (register_blkdev(ATAMAJOR, "ataraid", &ataraid_fops)) {
-		printk(KERN_ERR "ataraid: Could not get major %d \n",ATAMAJOR);
-		return -1;
-	}
-	
-	                
-	
-	blk_queue_make_request(BLK_DEFAULT_QUEUE(ATAMAJOR),ataraid_make_request);
-                                                                                     	
-	return 0;                                                        	
-}
-
-
-static void __exit ataraid_exit(void)
-{
-	unregister_blkdev(ATAMAJOR, "ataraid");
-	hardsect_size[ATAMAJOR] = NULL;
-	blk_size[ATAMAJOR] = NULL;
-	blksize_size[ATAMAJOR] = NULL;                       
-	max_readahead[ATAMAJOR] = NULL;
-
-	del_gendisk(&ataraid_gendisk);
-        
-	if (ataraid_gendisk.part) {
-		kfree(ataraid_gendisk.part);
-		ataraid_gendisk.part = NULL;
-	}
-}
-
-module_init(ataraid_init);
-module_exit(ataraid_exit);
-
-
-
-EXPORT_SYMBOL(ataraid_get_device);
-EXPORT_SYMBOL(ataraid_release_device);
-EXPORT_SYMBOL(ataraid_gendisk);
-EXPORT_SYMBOL(ataraid_register_disk);
-MODULE_LICENSE("GPL");
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ataraid.h linux-2.4.21-pre6/drivers/ide/ataraid.h
--- linux-2.4.20/drivers/ide/ataraid.h	2001-10-08 20:32:28.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/ataraid.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,72 +0,0 @@
-/*
-   ataraid.h  Copyright (C) 2001 Red Hat, Inc. 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, or (at your option)
-   any later version.
-   
-   You should have received a copy of the GNU General Public License
-   (for example /usr/src/linux/COPYING); if not, write to the Free
-   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
-   
-   Authors: 	Arjan van de Ven <arjanv@redhat.com>
-   		
-   
-*/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <asm/semaphore.h>
-#include <linux/blkdev.h>
-#include <linux/blkpg.h>
-#include <linux/genhd.h>
-#include <linux/ioctl.h>
-
-#include <linux/ide.h>
-#include <asm/uaccess.h>
-
-#define ATAMAJOR 114
-#define SHIFT 4
-#define MINOR_MASK 15
-#define MAJOR_MASK 15
-
-                                        
-/* raid_device_operations is a light struct block_device_operations with an
-   added method for make_request */
-struct raid_device_operations {
-	int (*open) (struct inode *, struct file *);
-	int (*release) (struct inode *, struct file *);
-	int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long);
-	int (*make_request) (request_queue_t *q, int rw, struct buffer_head * bh);
-};
-
-
-struct geom {
-	unsigned char heads;
-	unsigned int cylinders;
-	unsigned char sectors;
-};
-
-/* structure for the splitting of bufferheads */
-
-struct ataraid_bh_private {
-	struct buffer_head *parent;
-	atomic_t count;
-};
-
-extern struct gendisk ataraid_gendisk;
-
-extern int ataraid_get_device(struct raid_device_operations *fops);
-extern void ataraid_release_device(int device);
-extern int get_blocksize(kdev_t dev);
-extern void ataraid_register_disk(int device,long size);
-extern struct buffer_head *ataraid_get_bhead(void);
-extern struct ataraid_bh_private *ataraid_get_private(void);
-extern void ataraid_end_request(struct buffer_head *bh, int uptodate);
-
-
-
-
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/buddha.c linux-2.4.21-pre6/drivers/ide/buddha.c
--- linux-2.4.20/drivers/ide/buddha.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/buddha.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,225 +0,0 @@
-/*
- *  linux/drivers/ide/buddha.c -- Amiga Buddha, Catweasel and X-Surf IDE Driver
- *
- *	Copyright (C) 1997, 2001 by Geert Uytterhoeven and others
- *
- *  This driver was written based on the specifications in README.buddha and
- *  the X-Surf info from Inside_XSurf.txt available at
- *  http://www.jschoenfeld.com
- *
- *  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.
- *
- *  TODO:
- *    - test it :-)
- *    - tune the timings using the speed-register
- */
-
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/zorro.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/amigahw.h>
-#include <asm/amigaints.h>
-
-
-    /*
-     *  The Buddha has 2 IDE interfaces, the Catweasel has 3, X-Surf has 2
-     */
-
-#define BUDDHA_NUM_HWIFS	2
-#define CATWEASEL_NUM_HWIFS	3
-#define XSURF_NUM_HWIFS         2
-
-    /*
-     *  Bases of the IDE interfaces (relative to the board address)
-     */
-
-#define BUDDHA_BASE1	0x800
-#define BUDDHA_BASE2	0xa00
-#define BUDDHA_BASE3	0xc00
-
-#define XSURF_BASE1     0xb000 /* 2.5" Interface */
-#define XSURF_BASE2     0xd000 /* 3.5" Interface */
-
-static u_int buddha_bases[CATWEASEL_NUM_HWIFS] __initdata = {
-    BUDDHA_BASE1, BUDDHA_BASE2, BUDDHA_BASE3
-};
-
-static u_int xsurf_bases[XSURF_NUM_HWIFS] __initdata = {
-     XSURF_BASE1, XSURF_BASE2
-};
-
-
-    /*
-     *  Offsets from one of the above bases
-     */
-
-#define BUDDHA_DATA	0x00
-#define BUDDHA_ERROR	0x06		/* see err-bits */
-#define BUDDHA_NSECTOR	0x0a		/* nr of sectors to read/write */
-#define BUDDHA_SECTOR	0x0e		/* starting sector */
-#define BUDDHA_LCYL	0x12		/* starting cylinder */
-#define BUDDHA_HCYL	0x16		/* high byte of starting cyl */
-#define BUDDHA_SELECT	0x1a		/* 101dhhhh , d=drive, hhhh=head */
-#define BUDDHA_STATUS	0x1e		/* see status-bits */
-#define BUDDHA_CONTROL	0x11a
-#define XSURF_CONTROL   -1              /* X-Surf has no CS1* (Control/AltStat) */
-
-static int buddha_offsets[IDE_NR_PORTS] __initdata = {
-    BUDDHA_DATA, BUDDHA_ERROR, BUDDHA_NSECTOR, BUDDHA_SECTOR, BUDDHA_LCYL,
-    BUDDHA_HCYL, BUDDHA_SELECT, BUDDHA_STATUS, BUDDHA_CONTROL, -1
-};
-
-static int xsurf_offsets[IDE_NR_PORTS] __initdata = {
-    BUDDHA_DATA, BUDDHA_ERROR, BUDDHA_NSECTOR, BUDDHA_SECTOR, BUDDHA_LCYL,
-    BUDDHA_HCYL, BUDDHA_SELECT, BUDDHA_STATUS, XSURF_CONTROL, -1
-};
-
-    /*
-     *  Other registers
-     */
-
-#define BUDDHA_IRQ1	0xf00		/* MSB = 1, Harddisk is source of */
-#define BUDDHA_IRQ2	0xf40		/* interrupt */
-#define BUDDHA_IRQ3	0xf80
-
-#define XSURF_IRQ1      0x7e
-#define XSURF_IRQ2      0x7e
-
-static int buddha_irqports[CATWEASEL_NUM_HWIFS] __initdata = {
-    BUDDHA_IRQ1, BUDDHA_IRQ2, BUDDHA_IRQ3
-};
-
-static int xsurf_irqports[XSURF_NUM_HWIFS] __initdata = {
-    XSURF_IRQ1, XSURF_IRQ2
-};
-
-#define BUDDHA_IRQ_MR	0xfc0		/* master interrupt enable */
-
-
-    /*
-     *  Board information
-     */
-
-typedef enum BuddhaType_Enum {
-    BOARD_BUDDHA, BOARD_CATWEASEL, BOARD_XSURF
-} BuddhaType;
-
-
-    /*
-     *  Check and acknowledge the interrupt status
-     */
-
-static int buddha_ack_intr(ide_hwif_t *hwif)
-{
-    unsigned char ch;
-
-    ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]);
-    if (!(ch & 0x80))
-	    return 0;
-    return 1;
-}
-
-static int xsurf_ack_intr(ide_hwif_t *hwif)
-{
-    unsigned char ch;
-
-    ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]);
-    /* X-Surf needs a 0 written to IRQ register to ensure ISA bit A11 stays at 0 */
-    z_writeb(0, hwif->io_ports[IDE_IRQ_OFFSET]); 
-    if (!(ch & 0x80))
-	    return 0;
-    return 1;
-}
-
-    /*
-     *  Probe for a Buddha or Catweasel IDE interface
-     */
-
-void __init buddha_init(void)
-{
-	hw_regs_t hw;
-	int i, index;
-
-	struct zorro_dev *z = NULL;
-	u_long buddha_board = 0;
-	BuddhaType type;
-	int buddha_num_hwifs;
-
-	while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
-		unsigned long board;
-		if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_BUDDHA) {
-			buddha_num_hwifs = BUDDHA_NUM_HWIFS;
-			type=BOARD_BUDDHA;
-		} else if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_CATWEASEL) {
-			buddha_num_hwifs = CATWEASEL_NUM_HWIFS;
-			type=BOARD_CATWEASEL;
-		} else if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF) {
-			buddha_num_hwifs = XSURF_NUM_HWIFS;
-			type=BOARD_XSURF;
-		} else 
-			continue;
-		
-		board = z->resource.start;
-		
-		if(type != BOARD_XSURF) {
-			if (!request_mem_region(board+BUDDHA_BASE1, 0x800, "IDE"))
-				continue;
-		} else {
-			if (!request_mem_region(board+XSURF_BASE1, 0x1000, "IDE"))
-				continue;
-			if (!request_mem_region(board+XSURF_BASE2, 0x1000, "IDE"))
-				goto fail_base2;
-			if (!request_mem_region(board+XSURF_IRQ1, 0x8, "IDE")) {
-				release_mem_region(board+XSURF_BASE2, 0x1000);
-fail_base2:
-				release_mem_region(board+XSURF_BASE1, 0x1000);
-				continue;
-			}
-		}	  
-		buddha_board = ZTWO_VADDR(board);
-		
-		/* write to BUDDHA_IRQ_MR to enable the board IRQ */
-		/* X-Surf doesn't have this.  IRQs are always on */
-		if (type != BOARD_XSURF)
-			z_writeb(0, buddha_board+BUDDHA_IRQ_MR);
-		
-		for(i=0;i<buddha_num_hwifs;i++) {
-			if(type != BOARD_XSURF) {
-				ide_setup_ports(&hw, (ide_ioreg_t)(buddha_board+buddha_bases[i]),
-						buddha_offsets, 0,
-						(ide_ioreg_t)(buddha_board+buddha_irqports[i]),
-						buddha_ack_intr, IRQ_AMIGA_PORTS);
-			} else {
-				ide_setup_ports(&hw, (ide_ioreg_t)(buddha_board+xsurf_bases[i]),
-						xsurf_offsets, 0,
-						(ide_ioreg_t)(buddha_board+xsurf_irqports[i]),
-						xsurf_ack_intr, IRQ_AMIGA_PORTS);
-			}	
-			
-			index = ide_register_hw(&hw, NULL);
-			if (index != -1) {
-				printk("ide%d: ", index);
-				switch(type) {
-				case BOARD_BUDDHA:
-					printk("Buddha");
-					break;
-				case BOARD_CATWEASEL:
-					printk("Catweasel");
-					break;
-				case BOARD_XSURF:
-					printk("X-Surf");
-					break;
-				}
-				printk(" IDE interface\n");	    
-			}		      
-		}
-	}
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/cmd640.c linux-2.4.21-pre6/drivers/ide/cmd640.c
--- linux-2.4.20/drivers/ide/cmd640.c	2001-02-17 00:02:36.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/cmd640.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,856 +0,0 @@
-/*
- *  linux/drivers/ide/cmd640.c		Version 1.02  Sep 01, 1996
- *
- *  Copyright (C) 1995-1996  Linus Torvalds & authors (see below)
- */
-
-/*
- *  Original authors:	abramov@cecmow.enet.dec.com (Igor Abramov)
- *  			mlord@pobox.com (Mark Lord)
- *
- *  See linux/MAINTAINERS for address of current maintainer.
- *
- *  This file provides support for the advanced features and bugs
- *  of IDE interfaces using the CMD Technologies 0640 IDE interface chip.
- *
- *  These chips are basically fucked by design, and getting this driver
- *  to work on every motherboard design that uses this screwed chip seems
- *  bloody well impossible.  However, we're still trying.
- *
- *  Version 0.97 worked for everybody.
- *
- *  User feedback is essential.  Many thanks to the beta test team:
- *
- *  A.Hartgers@stud.tue.nl, JZDQC@CUNYVM.CUNY.edu, abramov@cecmow.enet.dec.com,
- *  bardj@utopia.ppp.sn.no, bart@gaga.tue.nl, bbol001@cs.auckland.ac.nz,
- *  chrisc@dbass.demon.co.uk, dalecki@namu26.Num.Math.Uni-Goettingen.de,
- *  derekn@vw.ece.cmu.edu, florian@btp2x3.phy.uni-bayreuth.de,
- *  flynn@dei.unipd.it, gadio@netvision.net.il, godzilla@futuris.net,
- *  j@pobox.com, jkemp1@mises.uni-paderborn.de, jtoppe@hiwaay.net,
- *  kerouac@ssnet.com, meskes@informatik.rwth-aachen.de, hzoli@cs.elte.hu,
- *  peter@udgaard.isgtec.com, phil@tazenda.demon.co.uk, roadcapw@cfw.com,
- *  s0033las@sun10.vsz.bme.hu, schaffer@tam.cornell.edu, sjd@slip.net,
- *  steve@ei.org, ulrpeg@bigcomm.gun.de, ism@tardis.ed.ac.uk, mack@cray.com
- *  liug@mama.indstate.edu, and others.
- *
- *  Version 0.01	Initial version, hacked out of ide.c,
- *			and #include'd rather than compiled separately.
- *			This will get cleaned up in a subsequent release.
- *
- *  Version 0.02	Fixes for vlb initialization code, enable prefetch
- *			for versions 'B' and 'C' of chip by default,
- *			some code cleanup.
- *
- *  Version 0.03	Added reset of secondary interface,
- *			and black list for devices which are not compatible
- *			with prefetch mode. Separate function for setting
- *			prefetch is added, possibly it will be called some
- *			day from ioctl processing code.
- *
- *  Version 0.04	Now configs/compiles separate from ide.c
- *
- *  Version 0.05	Major rewrite of interface timing code.
- *			Added new function cmd640_set_mode to set PIO mode
- *			from ioctl call. New drives added to black list.
- *
- *  Version 0.06	More code cleanup. Prefetch is enabled only for
- *			detected hard drives, not included in prefetch
- *			black list.
- *
- *  Version 0.07	Changed to more conservative drive tuning policy.
- *			Unknown drives, which report PIO < 4 are set to
- *			(reported_PIO - 1) if it is supported, or to PIO0.
- *			List of known drives extended by info provided by
- *			CMD at their ftp site.
- *
- *  Version 0.08	Added autotune/noautotune support.
- *
- *  Version 0.09	Try to be smarter about 2nd port enabling.
- *  Version 0.10	Be nice and don't reset 2nd port.
- *  Version 0.11	Try to handle more weird situations.
- *
- *  Version 0.12	Lots of bug fixes from Laszlo Peter
- *			irq unmasking disabled for reliability.
- *			try to be even smarter about the second port.
- *			tidy up source code formatting.
- *  Version 0.13	permit irq unmasking again.
- *  Version 0.90	massive code cleanup, some bugs fixed.
- *			defaults all drives to PIO mode0, prefetch off.
- *			autotune is OFF by default, with compile time flag.
- *			prefetch can be turned OFF/ON using "hdparm -p8/-p9"
- *			 (requires hdparm-3.1 or newer)
- *  Version 0.91	first release to linux-kernel list.
- *  Version 0.92	move initial reg dump to separate callable function
- *			change "readahead" to "prefetch" to avoid confusion
- *  Version 0.95	respect original BIOS timings unless autotuning.
- *			tons of code cleanup and rearrangement.
- *			added CONFIG_BLK_DEV_CMD640_ENHANCED option
- *			prevent use of unmask when prefetch is on
- *  Version 0.96	prevent use of io_32bit when prefetch is off
- *  Version 0.97	fix VLB secondary interface for sjd@slip.net
- *			other minor tune-ups:  0.96 was very good.
- *  Version 0.98	ignore PCI version when disabled by BIOS
- *  Version 0.99	display setup/active/recovery clocks with PIO mode
- *  Version 1.00	Mmm.. cannot depend on PCMD_ENA in all systems
- *  Version 1.01	slow/fast devsel can be selected with "hdparm -p6/-p7"
- *			 ("fast" is necessary for 32bit I/O in some systems)
- *  Version 1.02	fix bug that resulted in slow "setup times"
- *			 (patch courtesy of Zoltan Hidvegi)
- */
-
-#undef REALLY_SLOW_IO		/* most systems can safely undef this */
-#define CMD640_PREFETCH_MASKS 1
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-/*
- * This flag is set in ide.c by the parameter:  ide0=cmd640_vlb
- */
-int cmd640_vlb = 0;
-
-/*
- * CMD640 specific registers definition.
- */
-
-#define VID		0x00
-#define DID		0x02
-#define PCMD		0x04
-#define   PCMD_ENA	0x01
-#define PSTTS		0x06
-#define REVID		0x08
-#define PROGIF		0x09
-#define SUBCL		0x0a
-#define BASCL		0x0b
-#define BaseA0		0x10
-#define BaseA1		0x14
-#define BaseA2		0x18
-#define BaseA3		0x1c
-#define INTLINE		0x3c
-#define INPINE		0x3d
-
-#define	CFR		0x50
-#define   CFR_DEVREV		0x03
-#define   CFR_IDE01INTR		0x04
-#define	  CFR_DEVID		0x18
-#define	  CFR_AT_VESA_078h	0x20
-#define	  CFR_DSA1		0x40
-#define	  CFR_DSA0		0x80
-
-#define CNTRL		0x51
-#define	  CNTRL_DIS_RA0		0x40
-#define   CNTRL_DIS_RA1		0x80
-#define	  CNTRL_ENA_2ND		0x08
-
-#define	CMDTIM		0x52
-#define	ARTTIM0		0x53
-#define	DRWTIM0		0x54
-#define ARTTIM1 	0x55
-#define DRWTIM1		0x56
-#define ARTTIM23	0x57
-#define   ARTTIM23_DIS_RA2	0x04
-#define   ARTTIM23_DIS_RA3	0x08
-#define DRWTIM23	0x58
-#define BRST		0x59
-
-/*
- * Registers and masks for easy access by drive index:
- */
-static byte prefetch_regs[4]  = {CNTRL, CNTRL, ARTTIM23, ARTTIM23};
-static byte prefetch_masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2, ARTTIM23_DIS_RA3};
-
-#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
-
-static byte arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23};
-static byte drwtim_regs[4] = {DRWTIM0, DRWTIM1, DRWTIM23, DRWTIM23};
-
-/*
- * Current cmd640 timing values for each drive.
- * The defaults for each are the slowest possible timings.
- */
-static byte setup_counts[4]    = {4, 4, 4, 4};     /* Address setup count (in clocks) */
-static byte active_counts[4]   = {16, 16, 16, 16}; /* Active count   (encoded) */
-static byte recovery_counts[4] = {16, 16, 16, 16}; /* Recovery count (encoded) */
-
-#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
-
-/*
- * These are initialized to point at the devices we control
- */
-static ide_hwif_t  *cmd_hwif0, *cmd_hwif1;
-static ide_drive_t *cmd_drives[4];
-
-/*
- * Interface to access cmd640x registers
- */
-static unsigned int cmd640_key;
-static void (*put_cmd640_reg)(unsigned short reg, byte val);
-static byte (*get_cmd640_reg)(unsigned short reg);
-
-/*
- * This is read from the CFR reg, and is used in several places.
- */
-static unsigned int cmd640_chip_version;
-
-/*
- * The CMD640x chip does not support DWORD config write cycles, but some
- * of the BIOSes use them to implement the config services.
- * Therefore, we must use direct IO instead.
- */
-
-/* PCI method 1 access */
-
-static void put_cmd640_reg_pci1 (unsigned short reg, byte val)
-{
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	outl_p((reg & 0xfc) | cmd640_key, 0xcf8);
-	outb_p(val, (reg & 3) | 0xcfc);
-	restore_flags(flags);
-}
-
-static byte get_cmd640_reg_pci1 (unsigned short reg)
-{
-	byte b;
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	outl_p((reg & 0xfc) | cmd640_key, 0xcf8);
-	b = inb_p((reg & 3) | 0xcfc);
-	restore_flags(flags);
-	return b;
-}
-
-/* PCI method 2 access (from CMD datasheet) */
-
-static void put_cmd640_reg_pci2 (unsigned short reg, byte val)
-{
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	outb_p(0x10, 0xcf8);
-	outb_p(val, cmd640_key + reg);
-	outb_p(0, 0xcf8);
-	restore_flags(flags);
-}
-
-static byte get_cmd640_reg_pci2 (unsigned short reg)
-{
-	byte b;
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	outb_p(0x10, 0xcf8);
-	b = inb_p(cmd640_key + reg);
-	outb_p(0, 0xcf8);
-	restore_flags(flags);
-	return b;
-}
-
-/* VLB access */
-
-static void put_cmd640_reg_vlb (unsigned short reg, byte val)
-{
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	outb_p(reg, cmd640_key);
-	outb_p(val, cmd640_key + 4);
-	restore_flags(flags);
-}
-
-static byte get_cmd640_reg_vlb (unsigned short reg)
-{
-	byte b;
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	outb_p(reg, cmd640_key);
-	b = inb_p(cmd640_key + 4);
-	restore_flags(flags);
-	return b;
-}
-
-static int __init match_pci_cmd640_device (void)
-{
-	const byte ven_dev[4] = {0x95, 0x10, 0x40, 0x06};
-	unsigned int i;
-	for (i = 0; i < 4; i++) {
-		if (get_cmd640_reg(i) != ven_dev[i])
-			return 0;
-	}
-#ifdef STUPIDLY_TRUST_BROKEN_PCMD_ENA_BIT
-	if ((get_cmd640_reg(PCMD) & PCMD_ENA) == 0) {
-		printk("ide: cmd640 on PCI disabled by BIOS\n");
-		return 0;
-	}
-#endif /* STUPIDLY_TRUST_BROKEN_PCMD_ENA_BIT */
-	return 1; /* success */
-}
-
-/*
- * Probe for CMD640x -- pci method 1
- */
-static int __init probe_for_cmd640_pci1 (void)
-{
-	get_cmd640_reg = get_cmd640_reg_pci1;
-	put_cmd640_reg = put_cmd640_reg_pci1;
-	for (cmd640_key = 0x80000000; cmd640_key <= 0x8000f800; cmd640_key += 0x800) {
-		if (match_pci_cmd640_device())
-			return 1; /* success */
-	}
-	return 0;
-}
-
-/*
- * Probe for CMD640x -- pci method 2
- */
-static int __init probe_for_cmd640_pci2 (void)
-{
-	get_cmd640_reg = get_cmd640_reg_pci2;
-	put_cmd640_reg = put_cmd640_reg_pci2;
-	for (cmd640_key = 0xc000; cmd640_key <= 0xcf00; cmd640_key += 0x100) {
-		if (match_pci_cmd640_device())
-			return 1; /* success */
-	}
-	return 0;
-}
-
-/*
- * Probe for CMD640x -- vlb
- */
-static int __init probe_for_cmd640_vlb (void)
-{
-	byte b;
-
-	get_cmd640_reg = get_cmd640_reg_vlb;
-	put_cmd640_reg = put_cmd640_reg_vlb;
-	cmd640_key = 0x178;
-	b = get_cmd640_reg(CFR);
-	if (b == 0xff || b == 0x00 || (b & CFR_AT_VESA_078h)) {
-		cmd640_key = 0x78;
-		b = get_cmd640_reg(CFR);
-		if (b == 0xff || b == 0x00 || !(b & CFR_AT_VESA_078h))
-			return 0;
-	}
-	return 1; /* success */
-}
-
-/*
- *  Returns 1 if an IDE interface/drive exists at 0x170,
- *  Returns 0 otherwise.
- */
-static int __init secondary_port_responding (void)
-{
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-
-	outb_p(0x0a, 0x170 + IDE_SELECT_OFFSET);	/* select drive0 */
-	udelay(100);
-	if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x0a) {
-		outb_p(0x1a, 0x170 + IDE_SELECT_OFFSET); /* select drive1 */
-		udelay(100);
-		if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x1a) {
-			restore_flags(flags);
-			return 0; /* nothing responded */
-		}
-	}
-	restore_flags(flags);
-	return 1; /* success */
-}
-
-#ifdef CMD640_DUMP_REGS
-/*
- * Dump out all cmd640 registers.  May be called from ide.c
- */
-void cmd640_dump_regs (void)
-{
-	unsigned int reg = cmd640_vlb ? 0x50 : 0x00;
-
-	/* Dump current state of chip registers */
-	printk("ide: cmd640 internal register dump:");
-	for (; reg <= 0x59; reg++) {
-		if (!(reg & 0x0f))
-			printk("\n%04x:", reg);
-		printk(" %02x", get_cmd640_reg(reg));
-	}
-	printk("\n");
-}
-#endif
-
-/*
- * Check whether prefetch is on for a drive,
- * and initialize the unmask flags for safe operation.
- */
-static void __init check_prefetch (unsigned int index)
-{
-	ide_drive_t *drive = cmd_drives[index];
-	byte b = get_cmd640_reg(prefetch_regs[index]);
-
-	if (b & prefetch_masks[index]) {	/* is prefetch off? */
-		drive->no_unmask = 0;
-		drive->no_io_32bit = 1;
-		drive->io_32bit = 0;
-	} else {
-#if CMD640_PREFETCH_MASKS
-		drive->no_unmask = 1;
-		drive->unmask = 0;
-#endif
-		drive->no_io_32bit = 0;
-	}
-}
-
-/*
- * Figure out which devices we control
- */
-static void __init setup_device_ptrs (void)
-{
-	unsigned int i;
-
-	cmd_hwif0 = &ide_hwifs[0]; /* default, if not found below */
-	cmd_hwif1 = &ide_hwifs[1]; /* default, if not found below */
-	for (i = 0; i < MAX_HWIFS; i++) {
-		ide_hwif_t *hwif = &ide_hwifs[i];
-		if (hwif->chipset == ide_unknown || hwif->chipset == ide_generic) {
-			if (hwif->io_ports[IDE_DATA_OFFSET] == 0x1f0)
-				cmd_hwif0 = hwif;
-			else if (hwif->io_ports[IDE_DATA_OFFSET] == 0x170)
-				cmd_hwif1 = hwif;
-		}
-	}
-	cmd_drives[0] = &cmd_hwif0->drives[0];
-	cmd_drives[1] = &cmd_hwif0->drives[1];
-	cmd_drives[2] = &cmd_hwif1->drives[0];
-	cmd_drives[3] = &cmd_hwif1->drives[1];
-}
-
-#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
-
-/*
- * Sets prefetch mode for a drive.
- */
-static void set_prefetch_mode (unsigned int index, int mode)
-{
-	ide_drive_t *drive = cmd_drives[index];
-	int reg = prefetch_regs[index];
-	byte b;
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	b = get_cmd640_reg(reg);
-	if (mode) {	/* want prefetch on? */
-#if CMD640_PREFETCH_MASKS
-		drive->no_unmask = 1;
-		drive->unmask = 0;
-#endif
-		drive->no_io_32bit = 0;
-		b &= ~prefetch_masks[index];	/* enable prefetch */
-	} else {
-		drive->no_unmask = 0;
-		drive->no_io_32bit = 1;
-		drive->io_32bit = 0;
-		b |= prefetch_masks[index];	/* disable prefetch */
-	}
-	put_cmd640_reg(reg, b);
-	restore_flags(flags);
-}
-
-/*
- * Dump out current drive clocks settings
- */
-static void display_clocks (unsigned int index)
-{
-	byte active_count, recovery_count;
-
-	active_count = active_counts[index];
-	if (active_count == 1)
-		++active_count;
-	recovery_count = recovery_counts[index];
-	if (active_count > 3 && recovery_count == 1)
-		++recovery_count;
-	if (cmd640_chip_version > 1)
-		recovery_count += 1;  /* cmd640b uses (count + 1)*/
-	printk(", clocks=%d/%d/%d\n", setup_counts[index], active_count, recovery_count);
-}
-
-/*
- * Pack active and recovery counts into single byte representation
- * used by controller
- */
-inline static byte pack_nibbles (byte upper, byte lower)
-{
-	return ((upper & 0x0f) << 4) | (lower & 0x0f);
-}
-
-/*
- * This routine retrieves the initial drive timings from the chipset.
- */
-static void __init retrieve_drive_counts (unsigned int index)
-{
-	byte b;
-
-	/*
-	 * Get the internal setup timing, and convert to clock count
-	 */
-	b = get_cmd640_reg(arttim_regs[index]) & ~0x3f;
-	switch (b) {
-		case 0x00: b = 4; break;
-		case 0x80: b = 3; break;
-		case 0x40: b = 2; break;
-		default:   b = 5; break;
-	}
-	setup_counts[index] = b;
-
-	/*
-	 * Get the active/recovery counts
-	 */
-	b = get_cmd640_reg(drwtim_regs[index]);
-	active_counts[index]   = (b >> 4)   ? (b >> 4)   : 0x10;
-	recovery_counts[index] = (b & 0x0f) ? (b & 0x0f) : 0x10;
-}
-
-
-/*
- * This routine writes the prepared setup/active/recovery counts
- * for a drive into the cmd640 chipset registers to active them.
- */
-static void program_drive_counts (unsigned int index)
-{
-	unsigned long flags;
-	byte setup_count    = setup_counts[index];
-	byte active_count   = active_counts[index];
-	byte recovery_count = recovery_counts[index];
-
-	/*
-	 * Set up address setup count and drive read/write timing registers.
-	 * Primary interface has individual count/timing registers for
-	 * each drive.  Secondary interface has one common set of registers,
-	 * so we merge the timings, using the slowest value for each timing.
-	 */
-	if (index > 1) {
-		unsigned int mate;
-		if (cmd_drives[mate = index ^ 1]->present) {
-			if (setup_count < setup_counts[mate])
-				setup_count = setup_counts[mate];
-			if (active_count < active_counts[mate])
-				active_count = active_counts[mate];
-			if (recovery_count < recovery_counts[mate])
-				recovery_count = recovery_counts[mate];
-		}
-	}
-
-	/*
-	 * Convert setup_count to internal chipset representation
-	 */
-	switch (setup_count) {
-		case 4:	 setup_count = 0x00; break;
-		case 3:	 setup_count = 0x80; break;
-		case 1:
-		case 2:	 setup_count = 0x40; break;
-		default: setup_count = 0xc0; /* case 5 */
-	}
-
-	/*
-	 * Now that everything is ready, program the new timings
-	 */
-	save_flags (flags);
-	cli();
-	/*
-	 * Program the address_setup clocks into ARTTIM reg,
-	 * and then the active/recovery counts into the DRWTIM reg
-	 * (this converts counts of 16 into counts of zero -- okay).
-	 */
-	setup_count |= get_cmd640_reg(arttim_regs[index]) & 0x3f;
-	put_cmd640_reg(arttim_regs[index], setup_count);
-	put_cmd640_reg(drwtim_regs[index], pack_nibbles(active_count, recovery_count));
-	restore_flags(flags);
-}
-
-/*
- * Set a specific pio_mode for a drive
- */
-static void cmd640_set_mode (unsigned int index, byte pio_mode, unsigned int cycle_time)
-{
-	int setup_time, active_time, recovery_time, clock_time;
-	byte setup_count, active_count, recovery_count, recovery_count2, cycle_count;
-	int bus_speed = system_bus_clock();
-
-	if (pio_mode > 5)
-		pio_mode = 5;
-	setup_time  = ide_pio_timings[pio_mode].setup_time;
-	active_time = ide_pio_timings[pio_mode].active_time;
-	recovery_time = cycle_time - (setup_time + active_time);
-	clock_time = 1000 / bus_speed;
-	cycle_count = (cycle_time + clock_time - 1) / clock_time;
-
-	setup_count = (setup_time + clock_time - 1) / clock_time;
-
-	active_count = (active_time + clock_time - 1) / clock_time;
-	if (active_count < 2)
-		active_count = 2; /* minimum allowed by cmd640 */
-
-	recovery_count = (recovery_time + clock_time - 1) / clock_time;
-	recovery_count2 = cycle_count - (setup_count + active_count);
-	if (recovery_count2 > recovery_count)
-		recovery_count = recovery_count2;
-	if (recovery_count < 2)
-		recovery_count = 2; /* minimum allowed by cmd640 */
-	if (recovery_count > 17) {
-		active_count += recovery_count - 17;
-		recovery_count = 17;
-	}
-	if (active_count > 16)
-		active_count = 16; /* maximum allowed by cmd640 */
-	if (cmd640_chip_version > 1)
-		recovery_count -= 1;  /* cmd640b uses (count + 1)*/
-	if (recovery_count > 16)
-		recovery_count = 16; /* maximum allowed by cmd640 */
-
-	setup_counts[index]    = setup_count;
-	active_counts[index]   = active_count;
-	recovery_counts[index] = recovery_count;
-
-	/*
-	 * In a perfect world, we might set the drive pio mode here
-	 * (using WIN_SETFEATURE) before continuing.
-	 *
-	 * But we do not, because:
-	 *	1) this is the wrong place to do it (proper is do_special() in ide.c)
-	 * 	2) in practice this is rarely, if ever, necessary
-	 */
-	program_drive_counts (index);
-}
-
-/*
- * Drive PIO mode selection:
- */
-static void cmd640_tune_drive (ide_drive_t *drive, byte mode_wanted)
-{
-	byte b;
-	ide_pio_data_t  d;
-	unsigned int index = 0;
-
-	while (drive != cmd_drives[index]) {
-		if (++index > 3) {
-			printk("%s: bad news in cmd640_tune_drive\n", drive->name);
-			return;
-		}
-	}
-	switch (mode_wanted) {
-		case 6: /* set fast-devsel off */
-		case 7: /* set fast-devsel on */
-			mode_wanted &= 1;
-			b = get_cmd640_reg(CNTRL) & ~0x27;
-			if (mode_wanted)
-				b |= 0x27;
-			put_cmd640_reg(CNTRL, b);
-			printk("%s: %sabled cmd640 fast host timing (devsel)\n", drive->name, mode_wanted ? "en" : "dis");
-			return;
-
-		case 8: /* set prefetch off */
-		case 9: /* set prefetch on */
-			mode_wanted &= 1;
-			set_prefetch_mode(index, mode_wanted);
-			printk("%s: %sabled cmd640 prefetch\n", drive->name, mode_wanted ? "en" : "dis");
-			return;
-	}
-
-	(void) ide_get_best_pio_mode (drive, mode_wanted, 5, &d);
-	cmd640_set_mode (index, d.pio_mode, d.cycle_time);
-
-	printk ("%s: selected cmd640 PIO mode%d (%dns)%s",
-		drive->name,
-		d.pio_mode,
-		d.cycle_time,
-		d.overridden ? " (overriding vendor mode)" : "");
-	display_clocks(index);
-	return;
-}
-
-#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
-
-/*
- * Probe for a cmd640 chipset, and initialize it if found.  Called from ide.c
- */
-int __init ide_probe_for_cmd640x (void)
-{
-#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
-	int second_port_toggled = 0;
-#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
-	int second_port_cmd640 = 0;
-	const char *bus_type, *port2;
-	unsigned int index;
-	byte b, cfr;
-
-	if (cmd640_vlb && probe_for_cmd640_vlb()) {
-		bus_type = "VLB";
-	} else {
-		cmd640_vlb = 0;
-		if (probe_for_cmd640_pci1())
-			bus_type = "PCI (type1)";
-		else if (probe_for_cmd640_pci2())
-			bus_type = "PCI (type2)";
-		else
-			return 0;
-	}
-	/*
-	 * Undocumented magic (there is no 0x5b reg in specs)
-	 */
-	put_cmd640_reg(0x5b, 0xbd);
-	if (get_cmd640_reg(0x5b) != 0xbd) {
-		printk("ide: cmd640 init failed: wrong value in reg 0x5b\n");
-		return 0;
-	}
-	put_cmd640_reg(0x5b, 0);
-
-#ifdef CMD640_DUMP_REGS
-	CMD640_DUMP_REGS;
-#endif
-
-	/*
-	 * Documented magic begins here
-	 */
-	cfr = get_cmd640_reg(CFR);
-	cmd640_chip_version = cfr & CFR_DEVREV;
-	if (cmd640_chip_version == 0) {
-		printk ("ide: bad cmd640 revision: %d\n", cmd640_chip_version);
-		return 0;
-	}
-
-	/*
-	 * Initialize data for primary port
-	 */
-	setup_device_ptrs ();
-	printk("%s: buggy cmd640%c interface on %s, config=0x%02x\n",
-	       cmd_hwif0->name, 'a' + cmd640_chip_version - 1, bus_type, cfr);
-	cmd_hwif0->chipset = ide_cmd640;
-#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
-	cmd_hwif0->tuneproc = &cmd640_tune_drive;
-#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
-
-	/*
-	 * Ensure compatibility by always using the slowest timings
-	 * for access to the drive's command register block,
-	 * and reset the prefetch burstsize to default (512 bytes).
-	 *
-	 * Maybe we need a way to NOT do these on *some* systems?
-	 */
-	put_cmd640_reg(CMDTIM, 0);
-	put_cmd640_reg(BRST, 0x40);
-
-	/*
-	 * Try to enable the secondary interface, if not already enabled
-	 */
-	if (cmd_hwif1->noprobe) {
-		port2 = "not probed";
-	} else {
-		b = get_cmd640_reg(CNTRL);
-		if (secondary_port_responding()) {
-			if ((b & CNTRL_ENA_2ND)) {
-				second_port_cmd640 = 1;
-				port2 = "okay";
-			} else if (cmd640_vlb) {
-				second_port_cmd640 = 1;
-				port2 = "alive";
-			} else
-				port2 = "not cmd640";
-		} else {
-			put_cmd640_reg(CNTRL, b ^ CNTRL_ENA_2ND); /* toggle the bit */
-			if (secondary_port_responding()) {
-				second_port_cmd640 = 1;
-#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
-				second_port_toggled = 1;
-#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
-				port2 = "enabled";
-			} else {
-				put_cmd640_reg(CNTRL, b); /* restore original setting */
-				port2 = "not responding";
-			}
-		}
-	}
-
-	/*
-	 * Initialize data for secondary cmd640 port, if enabled
-	 */
-	if (second_port_cmd640) {
-		cmd_hwif0->serialized = 1;
-		cmd_hwif1->serialized = 1;
-		cmd_hwif1->chipset = ide_cmd640;
-		cmd_hwif0->mate = cmd_hwif1;
-		cmd_hwif1->mate = cmd_hwif0;
-		cmd_hwif1->channel = 1;
-#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
-		cmd_hwif1->tuneproc = &cmd640_tune_drive;
-#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
-	}
-	printk("%s: %sserialized, secondary interface %s\n", cmd_hwif1->name,
-		cmd_hwif0->serialized ? "" : "not ", port2);
-
-	/*
-	 * Establish initial timings/prefetch for all drives.
-	 * Do not unnecessarily disturb any prior BIOS setup of these.
-	 */
-	for (index = 0; index < (2 + (second_port_cmd640 << 1)); index++) {
-		ide_drive_t *drive = cmd_drives[index];
-#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
-		if (drive->autotune || ((index > 1) && second_port_toggled)) {
-	 		/*
-	 		 * Reset timing to the slowest speed and turn off prefetch.
-			 * This way, the drive identify code has a better chance.
-			 */
-			setup_counts    [index] = 4;	/* max possible */
-			active_counts   [index] = 16;	/* max possible */
-			recovery_counts [index] = 16;	/* max possible */
-			program_drive_counts (index);
-			set_prefetch_mode (index, 0);
-			printk("cmd640: drive%d timings/prefetch cleared\n", index);
-		} else {
-			/*
-			 * Record timings/prefetch without changing them.
-			 * This preserves any prior BIOS setup.
-			 */
-			retrieve_drive_counts (index);
-			check_prefetch (index);
-			printk("cmd640: drive%d timings/prefetch(%s) preserved",
-				index, drive->no_io_32bit ? "off" : "on");
-			display_clocks(index);
-		}
-#else
-		/*
-		 * Set the drive unmask flags to match the prefetch setting
-		 */
-		check_prefetch (index);
-		printk("cmd640: drive%d timings/prefetch(%s) preserved\n",
-			index, drive->no_io_32bit ? "off" : "on");
-#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
-	}
-
-#ifdef CMD640_DUMP_REGS
-	CMD640_DUMP_REGS;
-#endif
-	return 1;
-}
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/cmd64x.c linux-2.4.21-pre6/drivers/ide/cmd64x.c
--- linux-2.4.20/drivers/ide/cmd64x.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/cmd64x.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,1163 +0,0 @@
-/* $Id: cmd64x.c,v 1.21 2000/01/30 23:23:16
- *
- * linux/drivers/ide/cmd64x.c		Version 1.22	June 9, 2000
- *
- * cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines.
- *           Note, this driver is not used at all on other systems because
- *           there the "BIOS" has done all of the following already.
- *           Due to massive hardware bugs, UltraDMA is only supported
- *           on the 646U2 and not on the 646U.
- *
- * Copyright (C) 1998       Eddie C. Dost  (ecd@skynet.be)
- * Copyright (C) 1998       David S. Miller (davem@redhat.com)
- * Copyright (C) 1999-2000  Andre Hedrick <andre@linux-ide.org>
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-#ifndef SPLIT_BYTE
-#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
-#endif
-
-#define CMD_DEBUG 0
-
-#if CMD_DEBUG
-#define cmdprintk(x...)	printk(##x)
-#else
-#define cmdprintk(x...)
-#endif
-
-/*
- * CMD64x specific registers definition.
- */
-
-#define CFR		0x50
-#define   CFR_INTR_CH0		0x02
-#define CNTRL		0x51
-#define	  CNTRL_DIS_RA0		0x40
-#define   CNTRL_DIS_RA1		0x80
-#define	  CNTRL_ENA_2ND		0x08
-
-#define	CMDTIM		0x52
-#define	ARTTIM0		0x53
-#define	DRWTIM0		0x54
-#define ARTTIM1 	0x55
-#define DRWTIM1		0x56
-#define ARTTIM23	0x57
-#define   ARTTIM23_DIS_RA2	0x04
-#define   ARTTIM23_DIS_RA3	0x08
-#define   ARTTIM23_INTR_CH1	0x10
-#define ARTTIM2		0x57
-#define ARTTIM3		0x57
-#define DRWTIM23	0x58
-#define DRWTIM2		0x58
-#define BRST		0x59
-#define DRWTIM3		0x5b
-
-#define BMIDECR0	0x70
-#define MRDMODE		0x71
-#define   MRDMODE_INTR_CH0	0x04
-#define   MRDMODE_INTR_CH1	0x08
-#define   MRDMODE_BLK_CH0	0x10
-#define   MRDMODE_BLK_CH1	0x20
-#define BMIDESR0	0x72
-#define UDIDETCR0	0x73
-#define DTPR0		0x74
-#define BMIDECR1	0x78
-#define BMIDECSR	0x79
-#define BMIDESR1	0x7A
-#define UDIDETCR1	0x7B
-#define DTPR1		0x7C
-
-#define DISPLAY_CMD64X_TIMINGS
-
-#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int cmd64x_get_info(char *, char **, off_t, int);
-static int cmd680_get_info(char *, char **, off_t, int);
-extern int (*cmd64x_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-extern char *ide_media_verbose(ide_drive_t *);
-static struct pci_dev *bmide_dev;
-
-static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	u8 reg53 = 0, reg54 = 0, reg55 = 0, reg56 = 0;	/* primary */
-	u8 reg57 = 0, reg58 = 0, reg5b;			/* secondary */
-	u8 reg72 = 0, reg73 = 0;			/* primary */
-	u8 reg7a = 0, reg7b = 0;			/* secondary */
-	u8 reg50 = 0, reg71 = 0;			/* extra */
-	u8 hi_byte = 0, lo_byte = 0;
-
-	switch(bmide_dev->device) {
-		case PCI_DEVICE_ID_CMD_649:
-			p += sprintf(p, "\n                                CMD649 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_CMD_648:
-			p += sprintf(p, "\n                                CMD648 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_CMD_646:
-			p += sprintf(p, "\n                                CMD646 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_CMD_643:
-			p += sprintf(p, "\n                                CMD643 Chipset.\n");
-			break;
-		default:
-			p += sprintf(p, "\n                                CMD64? Chipse.\n");
-			break;
-	}
-	(void) pci_read_config_byte(bmide_dev, CFR,       &reg50);
-	(void) pci_read_config_byte(bmide_dev, ARTTIM0,   &reg53);
-	(void) pci_read_config_byte(bmide_dev, DRWTIM0,   &reg54);
-	(void) pci_read_config_byte(bmide_dev, ARTTIM1,   &reg55);
-	(void) pci_read_config_byte(bmide_dev, DRWTIM1,   &reg56);
-	(void) pci_read_config_byte(bmide_dev, ARTTIM2,   &reg57);
-	(void) pci_read_config_byte(bmide_dev, DRWTIM2,   &reg58);
-	(void) pci_read_config_byte(bmide_dev, DRWTIM3,   &reg5b);
-	(void) pci_read_config_byte(bmide_dev, MRDMODE,   &reg71);
-	(void) pci_read_config_byte(bmide_dev, BMIDESR0,  &reg72);
-	(void) pci_read_config_byte(bmide_dev, UDIDETCR0, &reg73);
-	(void) pci_read_config_byte(bmide_dev, BMIDESR1,  &reg7a);
-	(void) pci_read_config_byte(bmide_dev, UDIDETCR1, &reg7b);
-
-	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
-	p += sprintf(p, "                %sabled                         %sabled\n",
-		(reg72&0x80)?"dis":" en",(reg7a&0x80)?"dis":" en");
-	p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
-	p += sprintf(p, "DMA enabled:    %s              %s             %s               %s\n",
-		(reg72&0x20)?"yes":"no ",(reg72&0x40)?"yes":"no ",(reg7a&0x20)?"yes":"no ",(reg7a&0x40)?"yes":"no ");
-	p += sprintf(p, "DMA Mode:       %s(%s)          %s(%s)         %s(%s)           %s(%s)\n",
-		(reg72&0x20)?((reg73&0x01)?"UDMA":" DMA"):" PIO",
-		(reg72&0x20)?(  ((reg73&0x30)==0x30)?(((reg73&0x35)==0x35)?"3":"0"):
-				((reg73&0x20)==0x20)?(((reg73&0x25)==0x25)?"3":"1"):
-				((reg73&0x10)==0x10)?(((reg73&0x15)==0x15)?"4":"2"):
-				((reg73&0x00)==0x00)?(((reg73&0x05)==0x05)?"5":"2"):"X"):"?",
-		(reg72&0x40)?((reg73&0x02)?"UDMA":" DMA"):" PIO",
-		(reg72&0x40)?(	((reg73&0xC0)==0xC0)?(((reg73&0xC5)==0xC5)?"3":"0"):
-				((reg73&0x80)==0x80)?(((reg73&0x85)==0x85)?"3":"1"):
-				((reg73&0x40)==0x40)?(((reg73&0x4A)==0x4A)?"4":"2"):
-				((reg73&0x00)==0x00)?(((reg73&0x0A)==0x0A)?"5":"2"):"X"):"?",
-		(reg7a&0x20)?((reg7b&0x01)?"UDMA":" DMA"):" PIO",
-		(reg7a&0x20)?(	((reg7b&0x30)==0x30)?(((reg7b&0x35)==0x35)?"3":"0"):
-				((reg7b&0x20)==0x20)?(((reg7b&0x25)==0x25)?"3":"1"):
-				((reg7b&0x10)==0x10)?(((reg7b&0x15)==0x15)?"4":"2"):
-				((reg7b&0x00)==0x00)?(((reg7b&0x05)==0x05)?"5":"2"):"X"):"?",
-		(reg7a&0x40)?((reg7b&0x02)?"UDMA":" DMA"):" PIO",
-		(reg7a&0x40)?(	((reg7b&0xC0)==0xC0)?(((reg7b&0xC5)==0xC5)?"3":"0"):
-				((reg7b&0x80)==0x80)?(((reg7b&0x85)==0x85)?"3":"1"):
-				((reg7b&0x40)==0x40)?(((reg7b&0x4A)==0x4A)?"4":"2"):
-				((reg7b&0x00)==0x00)?(((reg7b&0x0A)==0x0A)?"5":"2"):"X"):"?" );
-	p += sprintf(p, "PIO Mode:       %s                %s               %s                 %s\n",
-		"?", "?", "?", "?");
-	p += sprintf(p, "                %s                     %s\n",
-		(reg50 & CFR_INTR_CH0) ? "interrupting" : "polling     ",
-		(reg57 & ARTTIM23_INTR_CH1) ? "interrupting" : "polling");
-	p += sprintf(p, "                %s                          %s\n",
-		(reg71 & MRDMODE_INTR_CH0) ? "pending" : "clear  ",
-		(reg71 & MRDMODE_INTR_CH1) ? "pending" : "clear");
-	p += sprintf(p, "                %s                          %s\n",
-		(reg71 & MRDMODE_BLK_CH0) ? "blocked" : "enabled",
-		(reg71 & MRDMODE_BLK_CH1) ? "blocked" : "enabled");
-
-	SPLIT_BYTE(reg50, hi_byte, lo_byte);
-	p += sprintf(p, "CFR       = 0x%02x, HI = 0x%02x, LOW = 0x%02x\n", reg50, hi_byte, lo_byte);
-	SPLIT_BYTE(reg57, hi_byte, lo_byte);
-	p += sprintf(p, "ARTTIM23  = 0x%02x, HI = 0x%02x, LOW = 0x%02x\n", reg57, hi_byte, lo_byte);
-	SPLIT_BYTE(reg71, hi_byte, lo_byte);
-	p += sprintf(p, "MRDMODE   = 0x%02x, HI = 0x%02x, LOW = 0x%02x\n", reg71, hi_byte, lo_byte);
-
-	return p-buffer;	/* => must be less than 4k! */
-}
-
-static int cmd680_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	p += sprintf(p, "\n                                CMD680 Chipset.\n");
-	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
-	p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
-	p += sprintf(p, "PIO Mode:       %s                %s               %s                 %s\n",
-		"?", "?", "?", "?");
-	return p-buffer;	/* => must be less than 4k! */
-}
-
-#endif	/* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-byte cmd64x_proc = 0;
-byte cmd680_proc = 0;
-
-/*
- * Registers and masks for easy access by drive index:
- */
-#if 0
-static byte prefetch_regs[4]  = {CNTRL, CNTRL, ARTTIM23, ARTTIM23};
-static byte prefetch_masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2, ARTTIM23_DIS_RA3};
-#endif
-
-/*
- * This routine writes the prepared setup/active/recovery counts
- * for a drive into the cmd646 chipset registers to active them.
- */
-static void program_drive_counts (ide_drive_t *drive, int setup_count, int active_count, int recovery_count)
-{
-	unsigned long flags;
-	ide_drive_t *drives = HWIF(drive)->drives;
-	byte temp_b;
-	static const byte setup_counts[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0};
-	static const byte recovery_counts[] =
-		{15, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0};
-	static const byte arttim_regs[2][2] = {
-			{ ARTTIM0, ARTTIM1 },
-			{ ARTTIM23, ARTTIM23 }
-		};
-	static const byte drwtim_regs[2][2] = {
-			{ DRWTIM0, DRWTIM1 },
-			{ DRWTIM2, DRWTIM3 }
-		};
-	int channel = (int) HWIF(drive)->channel;
-	int slave = (drives != drive);  /* Is this really the best way to determine this?? */
-
-	cmdprintk("program_drive_count parameters = s(%d),a(%d),r(%d),p(%d)\n", setup_count,
-		active_count, recovery_count, drive->present);
-	/*
-	 * Set up address setup count registers.
-	 * Primary interface has individual count/timing registers for
-	 * each drive.  Secondary interface has one common set of registers,
-	 * for address setup so we merge these timings, using the slowest
-	 * value.
-	 */
-	if (channel) {
-		drive->drive_data = setup_count;
-		setup_count = IDE_MAX(drives[0].drive_data, drives[1].drive_data);
-		cmdprintk("Secondary interface, setup_count = %d\n", setup_count);
-	}
-
-	/*
-	 * Convert values to internal chipset representation
-	 */
-	setup_count = (setup_count > 5) ? 0xc0 : (int) setup_counts[setup_count];
-	active_count &= 0xf; /* Remember, max value is 16 */
-	recovery_count = (int) recovery_counts[recovery_count];
-
-	cmdprintk("Final values = %d,%d,%d\n", setup_count, active_count, recovery_count);
-
-	/*
-	 * Now that everything is ready, program the new timings
-	 */
-	__save_flags (flags);
-	__cli();
-	/*
-	 * Program the address_setup clocks into ARTTIM reg,
-	 * and then the active/recovery counts into the DRWTIM reg
-	 */
-	(void) pci_read_config_byte(HWIF(drive)->pci_dev, arttim_regs[channel][slave], &temp_b);
-	(void) pci_write_config_byte(HWIF(drive)->pci_dev, arttim_regs[channel][slave],
-		((byte) setup_count) | (temp_b & 0x3f));
-	(void) pci_write_config_byte(HWIF(drive)->pci_dev, drwtim_regs[channel][slave],
-		(byte) ((active_count << 4) | recovery_count));
-	cmdprintk ("Write %x to %x\n", ((byte) setup_count) | (temp_b & 0x3f), arttim_regs[channel][slave]);
-	cmdprintk ("Write %x to %x\n", (byte) ((active_count << 4) | recovery_count), drwtim_regs[channel][slave]);
-	__restore_flags(flags);
-}
-
-/*
- * Attempts to set the interface PIO mode.
- * The preferred method of selecting PIO modes (e.g. mode 4) is 
- * "echo 'piomode:4' > /proc/ide/hdx/settings".  Special cases are
- * 8: prefetch off, 9: prefetch on, 255: auto-select best mode.
- * Called with 255 at boot time.
- */
-static void cmd64x_tuneproc (ide_drive_t *drive, byte mode_wanted)
-{
-	int setup_time, active_time, recovery_time, clock_time, pio_mode, cycle_time;
-	byte recovery_count2, cycle_count;
-	int setup_count, active_count, recovery_count;
-	int bus_speed = system_bus_clock();
-	/*byte b;*/
-	ide_pio_data_t  d;
-
-	switch (mode_wanted) {
-		case 8: /* set prefetch off */
-		case 9: /* set prefetch on */
-			mode_wanted &= 1;
-			/*set_prefetch_mode(index, mode_wanted);*/
-			cmdprintk("%s: %sabled cmd640 prefetch\n", drive->name, mode_wanted ? "en" : "dis");
-			return;
-	}
-
-	mode_wanted = ide_get_best_pio_mode (drive, mode_wanted, 5, &d);
-	pio_mode = d.pio_mode;
-	cycle_time = d.cycle_time;
-
-	/*
-	 * I copied all this complicated stuff from cmd640.c and made a few minor changes.
-	 * For now I am just going to pray that it is correct.
-	 */
-	if (pio_mode > 5)
-		pio_mode = 5;
-	setup_time  = ide_pio_timings[pio_mode].setup_time;
-	active_time = ide_pio_timings[pio_mode].active_time;
-	recovery_time = cycle_time - (setup_time + active_time);
-	clock_time = 1000 / bus_speed;
-	cycle_count = (cycle_time + clock_time - 1) / clock_time;
-
-	setup_count = (setup_time + clock_time - 1) / clock_time;
-
-	active_count = (active_time + clock_time - 1) / clock_time;
-
-	recovery_count = (recovery_time + clock_time - 1) / clock_time;
-	recovery_count2 = cycle_count - (setup_count + active_count);
-	if (recovery_count2 > recovery_count)
-		recovery_count = recovery_count2;
-	if (recovery_count > 16) {
-		active_count += recovery_count - 16;
-		recovery_count = 16;
-	}
-	if (active_count > 16)
-		active_count = 16; /* maximum allowed by cmd646 */
-
-	/*
-	 * In a perfect world, we might set the drive pio mode here
-	 * (using WIN_SETFEATURE) before continuing.
-	 *
-	 * But we do not, because:
-	 *	1) this is the wrong place to do it (proper is do_special() in ide.c)
-	 * 	2) in practice this is rarely, if ever, necessary
-	 */
-	program_drive_counts (drive, setup_count, active_count, recovery_count);
-
-	cmdprintk("%s: selected cmd646 PIO mode%d : %d (%dns)%s, clocks=%d/%d/%d\n",
-		drive->name, pio_mode, mode_wanted, cycle_time,
-		d.overridden ? " (overriding vendor mode)" : "",
-		setup_count, active_count, recovery_count);
-}
-
-static byte cmd680_taskfile_timing (ide_hwif_t *hwif)
-{
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte addr_mask		= (hwif->channel) ? 0xB2 : 0xA2;
-	unsigned short		timing;
-
-	pci_read_config_word(dev, addr_mask, &timing);
-
-	switch (timing) {
-		case 0x10c1:	return 4;
-		case 0x10c3:	return 3;
-		case 0x1281:	return 2;
-		case 0x2283:	return 1;
-		case 0x328a:
-		default:	return 0;
-	}
-}
-
-static void cmd680_tuneproc (ide_drive_t *drive, byte mode_wanted)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte			drive_pci;
-	unsigned short		speedt;
-
-	switch (drive->dn) {
-		case 0: drive_pci = 0xA4; break;
-		case 1: drive_pci = 0xA6; break;
-		case 2: drive_pci = 0xB4; break;
-		case 3: drive_pci = 0xB6; break;
-		default: return;
-        }
-
-	pci_read_config_word(dev, drive_pci, &speedt);
-
-	/* cheat for now and use the docs */
-//	switch(cmd680_taskfile_timing(hwif)) {
-	switch(mode_wanted) {
-		case 4:		speedt = 0x10c1; break;
-		case 3:		speedt = 0x10C3; break;
-		case 2:		speedt = 0x1104; break;
-		case 1:		speedt = 0x2283; break;
-		case 0:
-		default:	speedt = 0x328A; break;
-	}
-	pci_write_config_word(dev, drive_pci, speedt);
-}
-
-static void config_cmd64x_chipset_for_pio (ide_drive_t *drive, byte set_speed)
-{
-	byte speed	= 0x00;
-	byte set_pio	= ide_get_best_pio_mode(drive, 4, 5, NULL);
-
-	cmd64x_tuneproc(drive, set_pio);
-	speed = XFER_PIO_0 + set_pio;
-	if (set_speed)
-		(void) ide_config_drive_speed(drive, speed);
-}
-
-static void config_cmd680_chipset_for_pio (ide_drive_t *drive, byte set_speed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	u8 unit			= (drive->select.b.unit & 0x01);
-	u8 addr_mask		= (hwif->channel) ? 0x84 : 0x80;
-	u8 speed		= 0x00;
-	u8 mode_pci		= 0x00;
-	u8 channel_timings	= cmd680_taskfile_timing(hwif);
-	u8 set_pio		= ide_get_best_pio_mode(drive, 4, 5, NULL);
-
-	pci_read_config_byte(dev, addr_mask, &mode_pci);
-	mode_pci &= ~((unit) ? 0x30 : 0x03);
-
-	/* WARNING PIO timing mess is going to happen b/w devices, argh */
-	if ((channel_timings != set_pio) && (set_pio > channel_timings))
-		set_pio = channel_timings;
-
-	cmd680_tuneproc(drive, set_pio);
-	speed = XFER_PIO_0 + set_pio;
-	if (set_speed) {
-		(void) ide_config_drive_speed(drive, speed);
-		drive->current_speed = speed;
-	}
-}
-
-static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed)
-{
-        if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_CMD_680) {
-		config_cmd680_chipset_for_pio(drive, set_speed);
-	} else {
-		config_cmd64x_chipset_for_pio(drive, set_speed);
-	}
-}
-
-static int cmd64x_tune_chipset (ide_drive_t *drive, byte speed)
-{
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	int err			= 0;
-
-	u8 unit			= (drive->select.b.unit & 0x01);
-	u8 pciU			= (hwif->channel) ? UDIDETCR1 : UDIDETCR0;
-	u8 pciD			= (hwif->channel) ? BMIDESR1 : BMIDESR0;
-	u8 regU			= 0;
-	u8 regD			= 0;
-
-	if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))	return 1;
-
-	(void) pci_read_config_byte(dev, pciD, &regD);
-	(void) pci_read_config_byte(dev, pciU, &regU);
-	regD &= ~(unit ? 0x40 : 0x20);
-	regU &= ~(unit ? 0xCA : 0x35);
-	(void) pci_write_config_byte(dev, pciD, regD);
-	(void) pci_write_config_byte(dev, pciU, regU);
-
-	(void) pci_read_config_byte(dev, pciD, &regD);
-	(void) pci_read_config_byte(dev, pciU, &regU);
-	switch(speed) {
-		case XFER_UDMA_5:	regU |= (unit ? 0x0A : 0x05); break;
-		case XFER_UDMA_4:	regU |= (unit ? 0x4A : 0x15); break;
-		case XFER_UDMA_3:	regU |= (unit ? 0x8A : 0x25); break;
-		case XFER_UDMA_2:	regU |= (unit ? 0x42 : 0x11); break;
-		case XFER_UDMA_1:	regU |= (unit ? 0x82 : 0x21); break;
-		case XFER_UDMA_0:	regU |= (unit ? 0xC2 : 0x31); break;
-		case XFER_MW_DMA_2:	regD |= (unit ? 0x40 : 0x10); break;
-		case XFER_MW_DMA_1:	regD |= (unit ? 0x80 : 0x20); break;
-		case XFER_MW_DMA_0:	regD |= (unit ? 0xC0 : 0x30); break;
-		case XFER_SW_DMA_2:	regD |= (unit ? 0x40 : 0x10); break;
-		case XFER_SW_DMA_1:	regD |= (unit ? 0x80 : 0x20); break;
-		case XFER_SW_DMA_0:	regD |= (unit ? 0xC0 : 0x30); break;
-#else
-	int err			= 0;
-
-		switch(speed) {
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-		case XFER_PIO_4:	cmd64x_tuneproc(drive, 4); break;
-		case XFER_PIO_3:	cmd64x_tuneproc(drive, 3); break;
-		case XFER_PIO_2:	cmd64x_tuneproc(drive, 2); break;
-		case XFER_PIO_1:	cmd64x_tuneproc(drive, 1); break;
-		case XFER_PIO_0:	cmd64x_tuneproc(drive, 0); break;
-
-		default:
-			return 1;
-	}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	(void) pci_write_config_byte(dev, pciU, regU);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-	err = ide_config_drive_speed(drive, speed);
-
-	drive->current_speed = speed;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	regD |= (unit ? 0x40 : 0x20);
-	(void) pci_write_config_byte(dev, pciD, regD);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-	return err;
-}
-
-static int cmd680_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	u8 addr_mask		= (hwif->channel) ? 0x84 : 0x80;
-	u8 unit			= (drive->select.b.unit & 0x01);
-	u8 dma_pci		= 0;
-	u8 udma_pci		= 0;
-	u8 mode_pci		= 0;
-	u8 scsc			= 0;
-	u16 ultra		= 0;
-	u16 multi		= 0;
-	int err			= 0;
-
-        pci_read_config_byte(dev, addr_mask, &mode_pci);
-	pci_read_config_byte(dev, 0x8A, &scsc);
-
-        switch (drive->dn) {
-		case 0: dma_pci = 0xA8; udma_pci = 0xAC; break;
-		case 1: dma_pci = 0xAA; udma_pci = 0xAE; break;
-		case 2: dma_pci = 0xB8; udma_pci = 0xBC; break;
-		case 3: dma_pci = 0xBA; udma_pci = 0xBE; break;
-		default: return 1;
-	}
-
-	pci_read_config_byte(dev, addr_mask, &mode_pci);
-	mode_pci &= ~((unit) ? 0x30 : 0x03);
-	pci_read_config_word(dev, dma_pci, &multi);
-	pci_read_config_word(dev, udma_pci, &ultra);
-
-	if ((speed == XFER_UDMA_6) && (scsc & 0x30) == 0x00) {
-		pci_write_config_byte(dev, 0x8A, scsc|0x01);
-		pci_read_config_byte(dev, 0x8A, &scsc);
-	}
-
-	switch(speed) {
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		case XFER_UDMA_6:
-			if ((scsc & 0x30) == 0x00)
-				goto speed_break;
-			multi = 0x10C1;
-			ultra &= ~0x3F;
-			ultra |= 0x01;
-			break;
-speed_break :
-			speed = XFER_UDMA_5;
-		case XFER_UDMA_5:
-			multi = 0x10C1;
-			ultra &= ~0x3F;
-			ultra |= (((scsc & 0x30) == 0x00) ? 0x01 : 0x02);
-			break;
-		case XFER_UDMA_4:
-			multi = 0x10C1;
-			ultra &= ~0x3F;
-			ultra |= (((scsc & 0x30) == 0x00) ? 0x02 : 0x03);
-			break;
-		case XFER_UDMA_3:
-			multi = 0x10C1;
-			ultra &= ~0x3F;
-			ultra |= (((scsc & 0x30) == 0x00) ? 0x04 : 0x05);
-			break;
-		case XFER_UDMA_2:
-			multi = 0x10C1;
-			ultra &= ~0x3F;
-			ultra |= (((scsc & 0x30) == 0x00) ? 0x05 : 0x07);
-			break;
-		case XFER_UDMA_1:
-			multi = 0x10C1;
-			ultra &= ~0x3F;
-			ultra |= (((scsc & 0x30) == 0x00) ? 0x07 : 0x0B);
-			break;
-		case XFER_UDMA_0:
-			multi = 0x10C1;
-			ultra &= ~0x3F;
-			ultra |= (((scsc & 0x30) == 0x00) ? 0x0C : 0x0F);
-			break;
-		case XFER_MW_DMA_2:
-			multi = 0x10C1;
-			break;
-		case XFER_MW_DMA_1:
-			multi = 0x10C2;
-			break;
-		case XFER_MW_DMA_0:
-			multi = 0x2208;
-			break;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-		case XFER_PIO_4:	cmd680_tuneproc(drive, 4); break;
-		case XFER_PIO_3:	cmd680_tuneproc(drive, 3); break;
-		case XFER_PIO_2:	cmd680_tuneproc(drive, 2); break;
-		case XFER_PIO_1:	cmd680_tuneproc(drive, 1); break;
-		case XFER_PIO_0:	cmd680_tuneproc(drive, 0); break;
-		default:
-			return 1;
-	}
-
-	
-	if (speed >= XFER_MW_DMA_0) 
-		config_cmd680_chipset_for_pio(drive, 0);
-
-	if (speed >= XFER_UDMA_0)
-		mode_pci |= ((unit) ? 0x30 : 0x03);
-	else if (speed >= XFER_MW_DMA_0)
-		mode_pci |= ((unit) ? 0x20 : 0x02);
-	else
-		mode_pci |= ((unit) ? 0x10 : 0x01);
-
-	pci_write_config_byte(dev, addr_mask, mode_pci);
-	pci_write_config_word(dev, dma_pci, multi);
-	pci_write_config_word(dev, udma_pci, ultra);
-
-	err = ide_config_drive_speed(drive, speed);
-	drive->current_speed = speed;
-	return err;
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_cmd64x_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66)
-{
-	struct hd_driveid *id	= drive->id;
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-
-	byte speed		= 0x00;
-	byte set_pio		= 0x00;
-	byte udma_33		= ((rev >= 0x05) || (ultra_66)) ? 1 : 0;
-	byte udma_66		= eighty_ninty_three(drive);
-	byte udma_100		= 0;
-	int rval;
-
-	switch(dev->device) {
-		case PCI_DEVICE_ID_CMD_649: udma_100 = 1; break;
-		case PCI_DEVICE_ID_CMD_648:
-		case PCI_DEVICE_ID_CMD_646:
-		case PCI_DEVICE_ID_CMD_643:
-		default:
-			break;
-	}
-
-	if (drive->media != ide_disk) {
-		cmdprintk("CMD64X: drive->media != ide_disk at double check, inital check failed!!\n");
-		return ((int) ide_dma_off);
-	}
-
-	/* UltraDMA only supported on PCI646U and PCI646U2,
-	 * which correspond to revisions 0x03, 0x05 and 0x07 respectively.
-	 * Actually, although the CMD tech support people won't
-	 * tell me the details, the 0x03 revision cannot support
-	 * UDMA correctly without hardware modifications, and even
-	 * then it only works with Quantum disks due to some
-	 * hold time assumptions in the 646U part which are fixed
-	 * in the 646U2.
-	 * So we only do UltraDMA on revision 0x05 and 0x07 chipsets.
-	 */
-	if ((id->dma_ultra & 0x0020) && (udma_100) && (udma_66) && (udma_33)) {
-		speed = XFER_UDMA_5;
-	} else if ((id->dma_ultra & 0x0010) && (udma_66) && (udma_33)) {
-		speed = XFER_UDMA_4;
-	} else if ((id->dma_ultra & 0x0008) && (udma_66) && (udma_33)) {
-		speed = XFER_UDMA_3;
-	} else if ((id->dma_ultra & 0x0004) && (udma_33)) {
-		speed = XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0002) && (udma_33)) {
-		speed = XFER_UDMA_1;
-	} else if ((id->dma_ultra & 0x0001) && (udma_33)) {
-		speed = XFER_UDMA_0;
-	} else if (id->dma_mword & 0x0004) {
-		speed = XFER_MW_DMA_2;
-	} else if (id->dma_mword & 0x0002) {
-		speed = XFER_MW_DMA_1;
-	} else if (id->dma_mword & 0x0001) {
-		speed = XFER_MW_DMA_0;
-	} else if (id->dma_1word & 0x0004) {
-		speed = XFER_SW_DMA_2;
-	} else if (id->dma_1word & 0x0002) {
-		speed = XFER_SW_DMA_1;
-	} else if (id->dma_1word & 0x0001) {
-		speed = XFER_SW_DMA_0;
-	} else {
-		set_pio = 1;
-	}
-
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-
-	config_chipset_for_pio(drive, set_pio);
-
-	if (set_pio)
-		return ((int) ide_dma_off_quietly);
-
-	if (cmd64x_tune_chipset(drive, speed))
-		return ((int) ide_dma_off);
-
-	rval = (int)(	((id->dma_ultra >> 11) & 7) ? ide_dma_on :
-			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-			((id->dma_mword >> 8) & 7) ? ide_dma_on :
-			((id->dma_1word >> 8) & 7) ? ide_dma_on :
-						     ide_dma_off_quietly);
-
-	return rval;
-}
-
-static int config_cmd680_chipset_for_dma (ide_drive_t *drive)
-{
-	struct hd_driveid *id	= drive->id;
-	byte udma_66		= eighty_ninty_three(drive);
-	byte speed		= 0x00;
-	byte set_pio		= 0x00;
-	int rval;
-
-	if ((id->dma_ultra & 0x0040) && (udma_66))	speed = XFER_UDMA_6;
-	else if ((id->dma_ultra & 0x0020) && (udma_66))	speed = XFER_UDMA_5;
-	else if ((id->dma_ultra & 0x0010) && (udma_66))	speed = XFER_UDMA_4;
-	else if ((id->dma_ultra & 0x0008) && (udma_66))	speed = XFER_UDMA_3;
-	else if (id->dma_ultra & 0x0004)		speed = XFER_UDMA_2;
-	else if (id->dma_ultra & 0x0002)		speed = XFER_UDMA_1;
-	else if (id->dma_ultra & 0x0001)		speed = XFER_UDMA_0;
-	else if (id->dma_mword & 0x0004)		speed = XFER_MW_DMA_2;
-	else if (id->dma_mword & 0x0002)		speed = XFER_MW_DMA_1;
-	else if (id->dma_mword & 0x0001)		speed = XFER_MW_DMA_0;
-	else {
-		set_pio = 1;
-	}
-
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-
-	config_chipset_for_pio(drive, set_pio);
-
-	if (set_pio)
-		return ((int) ide_dma_off_quietly);
-
-	if (cmd680_tune_chipset(drive, speed))
-		return ((int) ide_dma_off);
-
-	rval = (int)(	((id->dma_ultra >> 14) & 3) ? ide_dma_on :
-			((id->dma_ultra >> 11) & 7) ? ide_dma_on :
-			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-			((id->dma_mword >> 8) & 7) ? ide_dma_on :
-			((id->dma_1word >> 8) & 7) ? ide_dma_on :
-						     ide_dma_off_quietly);
-	return rval;
-}
-
-static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66)
-{
-	if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_CMD_680)
-		return (config_cmd680_chipset_for_dma(drive));
-	return (config_cmd64x_chipset_for_dma(drive, rev, ultra_66));
-}
-
-static int cmd64x_config_drive_for_dma (ide_drive_t *drive)
-{
-	struct hd_driveid *id	= drive->id;
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	unsigned int class_rev	= 0;
-	byte can_ultra_33	= 0;
-	byte can_ultra_66	= 0;
-	byte can_ultra_100	= 0;
-	byte can_ultra_133	= 0;
-	ide_dma_action_t dma_func = ide_dma_on;
-
-	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;	
-
-	switch(dev->device) {
-		case PCI_DEVICE_ID_CMD_680:
-			can_ultra_133 = 1;
-		case PCI_DEVICE_ID_CMD_649:
-			can_ultra_100 = 1;
-		case PCI_DEVICE_ID_CMD_648:
-			can_ultra_66  = 1;
-		case PCI_DEVICE_ID_CMD_643:
-			can_ultra_33  = 1;
-			break;
-		case PCI_DEVICE_ID_CMD_646:
-			can_ultra_33  = (class_rev >= 0x05) ? 1 : 0;
-			can_ultra_66  = 0;
-			can_ultra_100 = 0;
-			break;
-		default:
-			return hwif->dmaproc(ide_dma_off, drive);
-	}
-
-	if ((id != NULL) && ((id->capability & 1) != 0) &&
-	    hwif->autodma && (drive->media == ide_disk)) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if ((id->field_valid & 4) && (can_ultra_33)) {
-			if (id->dma_ultra & 0x007F) {
-				/* Force if Capable UltraDMA */
-				dma_func = config_chipset_for_dma(drive, class_rev, can_ultra_66);
-				if ((id->field_valid & 2) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    (id->dma_1word & 0x0007)) {
-				/* Force if Capable regular DMA modes */
-				dma_func = config_chipset_for_dma(drive, class_rev, 0);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			dma_func = config_chipset_for_dma(drive, class_rev, 0);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-		config_chipset_for_pio(drive, 1);
-	}
-	return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-static int cmd680_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch (func) {
-		case ide_dma_check:
-			return cmd64x_config_drive_for_dma(drive);
-		default:
-			break;
-	}
-	/* Other cases are done by generic IDE-DMA code. */
-        return ide_dmaproc(func, drive);
-}
-
-static int cmd64x_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	byte dma_stat		= 0;
-	byte dma_alt_stat	= 0;
-	byte mask		= (HWIF(drive)->channel) ? MRDMODE_INTR_CH1 : MRDMODE_INTR_CH0;
-	unsigned long dma_base	= HWIF(drive)->dma_base;
-	struct pci_dev *dev	= HWIF(drive)->pci_dev;
-	byte jack_slap		= ((dev->device == PCI_DEVICE_ID_CMD_648) || (dev->device == PCI_DEVICE_ID_CMD_649)) ? 1 : 0;
-
-	switch (func) {
-		case ide_dma_check:
-			return cmd64x_config_drive_for_dma(drive);
-		case ide_dma_end: /* returns 1 on error, 0 otherwise */
-			drive->waiting_for_dma = 0;
-			outb(inb(dma_base)&~1, dma_base);	/* stop DMA */
-			dma_stat = inb(dma_base+2);		/* get DMA status */
-			outb(dma_stat|6, dma_base+2);		/* clear the INTR & ERROR bits */
-			if (jack_slap) {
-				byte dma_intr	= 0;
-				byte dma_mask	= (HWIF(drive)->channel) ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0;
-				byte dma_reg	= (HWIF(drive)->channel) ? ARTTIM2 : CFR;
-				(void) pci_read_config_byte(dev, dma_reg, &dma_intr);
-				/*
-				 * DAMN BMIDE is not connected to PCI space!
-				 * Have to manually jack-slap that bitch!
-				 * To allow the PCI side to read incoming interrupts.
-				 */
-				(void) pci_write_config_byte(dev, dma_reg, dma_intr|dma_mask);	/* clear the INTR bit */
-			}
-			ide_destroy_dmatable(drive);		/* purge DMA mappings */
-			return (dma_stat & 7) != 4;		/* verify good DMA status */
-		case ide_dma_test_irq:	/* returns 1 if dma irq issued, 0 otherwise */
-			dma_stat = inb(dma_base+2);
-			(void) pci_read_config_byte(dev, MRDMODE, &dma_alt_stat);
-#ifdef DEBUG
-			printk("%s: dma_stat: 0x%02x dma_alt_stat: 0x%02x mask: 0x%02x\n", drive->name, dma_stat, dma_alt_stat, mask);
-#endif
-			if (!(dma_alt_stat & mask)) {
-				return 0;
-			}
-			return (dma_stat & 4) == 4;	/* return 1 if INTR asserted */
-		default:
-			break;
-	}
-	/* Other cases are done by generic IDE-DMA code. */
-	return ide_dmaproc(func, drive);
-}
-
-/*
- * ASUS P55T2P4D with CMD646 chipset revision 0x01 requires the old
- * event order for DMA transfers.
- */
-static int cmd646_1_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	unsigned long dma_base = hwif->dma_base;
-	byte dma_stat;
-
-	switch (func) {
-		case ide_dma_check:
-			return cmd64x_config_drive_for_dma(drive);
-		case ide_dma_end:
-			drive->waiting_for_dma = 0;
-			dma_stat = inb(dma_base+2);		/* get DMA status */
-			outb(inb(dma_base)&~1, dma_base);	/* stop DMA */
-			outb(dma_stat|6, dma_base+2);		/* clear the INTR & ERROR bits */
-			ide_destroy_dmatable(drive);		/* and free any DMA resources */
-			return (dma_stat & 7) != 4;		/* verify good DMA status */
-		default:
-			break;
-	}
-
-	/* Other cases are done by generic IDE-DMA code. */
-	return ide_dmaproc(func, drive);
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-static int cmd680_busproc (ide_drive_t * drive, int state)
-{
-#if 0
-	ide_hwif_t *hwif	= HWIF(drive);
-	u8 addr_mask		= (hwif->channel) ? 0xB0 : 0xA0;
-	u32 stat_config		= 0;
-
-        pci_read_config_dword(hwif->pci_dev, addr_mask, &stat_config);
-
-	if (!hwif)
-		return -EINVAL;
-
-	switch (state) {
-		case BUSSTATE_ON:
-			hwif->drives[0].failures = 0;
-			hwif->drives[1].failures = 0;
-			break;
-		case BUSSTATE_OFF:
-			hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
-			hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
-			break;
-		case BUSSTATE_TRISTATE:
-			hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
-			hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
-			break;
-		default:
-			return 0;
-	}
-	hwif->bus_state = state;
-#endif
-	return 0;
-}
-
-void cmd680_reset (ide_drive_t *drive)
-{
-#if 0
-	ide_hwif_t *hwif	= HWIF(drive);
-	u8 addr_mask		= (hwif->channel) ? 0xB0 : 0xA0;
-	byte reset		= 0;
-
-	pci_read_config_byte(hwif->pci_dev, addr_mask, &reset);
-	pci_write_config_byte(hwif->pci_dev, addr_mask, reset|0x03);
-#endif
-}
-
-unsigned int cmd680_pci_init (struct pci_dev *dev, const char *name)
-{
-	u8 tmpbyte	= 0;	
-	pci_write_config_byte(dev, 0x80, 0x00);
-	pci_write_config_byte(dev, 0x84, 0x00);
-	pci_read_config_byte(dev, 0x8A, &tmpbyte);
-	pci_write_config_byte(dev, 0x8A, tmpbyte|0x01);
-	pci_write_config_word(dev, 0xA2, 0x328A);
-	pci_write_config_dword(dev, 0xA4, 0x328A);
-	pci_write_config_dword(dev, 0xA8, 0x4392);
-	pci_write_config_dword(dev, 0xAC, 0x4009);
-	pci_write_config_word(dev, 0xB2, 0x328A);
-	pci_write_config_dword(dev, 0xB4, 0x328A);
-	pci_write_config_dword(dev, 0xB8, 0x4392);
-	pci_write_config_dword(dev, 0xBC, 0x4009);
-
-#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!cmd64x_proc) {
-		cmd64x_proc = 1;
-		bmide_dev = dev;
-		cmd64x_display_info = &cmd680_get_info;
-	}
-#endif /* DISPLAY_CMD64X_TIMINGS && CONFIG_PROC_FS */
-	return 0;
-}
-
-unsigned int cmd64x_pci_init (struct pci_dev *dev, const char *name)
-{
-	unsigned char mrdmode;
-	unsigned int class_rev;
-
-	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;
-
-#ifdef __i386__
-	if (dev->resource[PCI_ROM_RESOURCE].start) {
-		pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
-		printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
-	}
-#endif
-
-	switch(dev->device) {
-		case PCI_DEVICE_ID_CMD_643:
-			break;
-		case PCI_DEVICE_ID_CMD_646:
-			printk("%s: chipset revision 0x%02X, ", name, class_rev);
-			switch(class_rev) {
-				case 0x07:
-				case 0x05:
-					printk("UltraDMA Capable");
-					break;
-				case 0x03:
-					printk("MultiWord DMA Force Limited");
-					break;
-				case 0x01:
-				default:
-					printk("MultiWord DMA Limited, IRQ workaround enabled");
-					break;
-				}
-			printk("\n");
-                        break;
-		case PCI_DEVICE_ID_CMD_648:
-		case PCI_DEVICE_ID_CMD_649:
-			break;
-		default:
-			break;
-	}
-
-	/* Set a good latency timer and cache line size value. */
-	(void) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
-#ifdef __sparc_v9__
-	(void) pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x10);
-#endif
-
-
-	/* Setup interrupts. */
-	(void) pci_read_config_byte(dev, MRDMODE, &mrdmode);
-	mrdmode &= ~(0x30);
-	(void) pci_write_config_byte(dev, MRDMODE, mrdmode);
-
-	/* Use MEMORY READ LINE for reads.
-	 * NOTE: Although not mentioned in the PCI0646U specs,
-	 *       these bits are write only and won't be read
-	 *       back as set or not.  The PCI0646U2 specs clarify
-	 *       this point.
-	 */
-	(void) pci_write_config_byte(dev, MRDMODE, mrdmode | 0x02);
-
-	/* Set reasonable active/recovery/address-setup values. */
-	(void) pci_write_config_byte(dev, ARTTIM0,  0x40);
-	(void) pci_write_config_byte(dev, DRWTIM0,  0x3f);
-	(void) pci_write_config_byte(dev, ARTTIM1,  0x40);
-	(void) pci_write_config_byte(dev, DRWTIM1,  0x3f);
-#ifdef __i386__
-	(void) pci_write_config_byte(dev, ARTTIM23, 0x1c);
-#else
-	(void) pci_write_config_byte(dev, ARTTIM23, 0x5c);
-#endif
-	(void) pci_write_config_byte(dev, DRWTIM23, 0x3f);
-	(void) pci_write_config_byte(dev, DRWTIM3,  0x3f);
-#ifdef CONFIG_PPC
-	(void) pci_write_config_byte(dev, UDIDETCR0, 0xf0);
-#endif /* CONFIG_PPC */
-
-#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!cmd64x_proc) {
-		cmd64x_proc = 1;
-		bmide_dev = dev;
-		cmd64x_display_info = &cmd64x_get_info;
-	}
-#endif /* DISPLAY_CMD64X_TIMINGS && CONFIG_PROC_FS */
-
-	return 0;
-}
-
-unsigned int __init pci_init_cmd64x (struct pci_dev *dev, const char *name)
-{
-	if (dev->device == PCI_DEVICE_ID_CMD_680)
-		return cmd680_pci_init (dev, name);
-	return cmd64x_pci_init (dev, name);
-}
-
-unsigned int cmd680_ata66 (ide_hwif_t *hwif)
-{
-	byte ata66	= 0;
-	byte addr_mask	= (hwif->channel) ? 0xB0 : 0xA0;
-
-	pci_read_config_byte(hwif->pci_dev, addr_mask, &ata66);
-	return (ata66 & 0x01) ? 1 : 0;
-}
-
-unsigned int cmd64x_ata66 (ide_hwif_t *hwif)
-{
-	byte ata66 = 0;
-	byte mask = (hwif->channel) ? 0x02 : 0x01;
-
-	pci_read_config_byte(hwif->pci_dev, BMIDECSR, &ata66);
-	return (ata66 & mask) ? 1 : 0;
-}
-
-unsigned int __init ata66_cmd64x (ide_hwif_t *hwif)
-{
-	struct pci_dev *dev	= hwif->pci_dev;
-	if (dev->device == PCI_DEVICE_ID_CMD_680)
-		return cmd680_ata66(hwif);
-	return cmd64x_ata66(hwif);
-}
-
-void __init ide_init_cmd64x (ide_hwif_t *hwif)
-{
-	struct pci_dev *dev	= hwif->pci_dev;
-	unsigned int class_rev;
-
-	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;
-
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-
-	if (!hwif->dma_base)
-		return;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	switch(dev->device) {
-		case PCI_DEVICE_ID_CMD_680:
-			hwif->busproc	= &cmd680_busproc;
-			hwif->dmaproc	= &cmd680_dmaproc;
-			hwif->resetproc = &cmd680_reset;
-			hwif->speedproc	= &cmd680_tune_chipset;
-			hwif->tuneproc	= &cmd680_tuneproc;
-			break;
-		case PCI_DEVICE_ID_CMD_649:
-		case PCI_DEVICE_ID_CMD_648:
-		case PCI_DEVICE_ID_CMD_643:
-			hwif->dmaproc	= &cmd64x_dmaproc;
-			hwif->tuneproc	= &cmd64x_tuneproc;
-			hwif->speedproc = &cmd64x_tune_chipset;
-			break;
-		case PCI_DEVICE_ID_CMD_646:
-			hwif->chipset = ide_cmd646;
-			if (class_rev == 0x01) {
-				hwif->dmaproc = &cmd646_1_dmaproc;
-			} else {
-				hwif->dmaproc = &cmd64x_dmaproc;
-			}
-			hwif->tuneproc	= &cmd64x_tuneproc;
-			hwif->speedproc	= &cmd64x_tune_chipset;
-			break;
-		default:
-			break;
-	}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/cs5530.c linux-2.4.21-pre6/drivers/ide/cs5530.c
--- linux-2.4.20/drivers/ide/cs5530.c	2001-01-03 00:58:45.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/cs5530.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,374 +0,0 @@
-/*
- * linux/drivers/ide/cs5530.c		Version 0.6	Mar. 18, 2000
- *
- * Copyright (C) 2000			Andre Hedrick <andre@linux-ide.org>
- * Ditto of GNU General Public License.
- *
- * Copyright (C) 2000			Mark Lord <mlord@pobox.com>
- * May be copied or modified under the terms of the GNU General Public License
- *
- * Development of this chipset driver was funded
- * by the nice folks at National Semiconductor.
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include "ide_modes.h"
-
-#define DISPLAY_CS5530_TIMINGS
-
-#if defined(DISPLAY_CS5530_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int cs5530_get_info(char *, char **, off_t, int);
-extern int (*cs5530_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-extern char *ide_media_verbose(ide_drive_t *);
-static struct pci_dev *bmide_dev;
-
-static int cs5530_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	u32 bibma = pci_resource_start(bmide_dev, 4);
-	u8  c0 = 0, c1 = 0;
-
-	/*
-	 * at that point bibma+0x2 et bibma+0xa are byte registers
-	 * to investigate:
-	 */
-
-	c0 = inb_p((unsigned short)bibma + 0x02);
-	c1 = inb_p((unsigned short)bibma + 0x0a);
-
-	p += sprintf(p, "\n                                Cyrix 5530 Chipset.\n");
-	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
-	p += sprintf(p, "                %sabled                         %sabled\n",
-			(c0&0x80) ? "dis" : " en",
-			(c1&0x80) ? "dis" : " en");
-	p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
-	p += sprintf(p, "DMA enabled:    %s              %s             %s               %s\n",
-			(c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ",
-			(c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " );
-
-	p += sprintf(p, "UDMA\n");
-	p += sprintf(p, "DMA\n");
-	p += sprintf(p, "PIO\n");
-
-	return p-buffer;
-}
-#endif /* DISPLAY_CS5530_TIMINGS && CONFIG_PROC_FS */
-
-byte cs5530_proc = 0;
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-/*
- * Set a new transfer mode at the drive
- */
-int cs5530_set_xfer_mode (ide_drive_t *drive, byte mode)
-{
-	int error = 0;
-
-	printk("%s: cs5530_set_xfer_mode(%s)\n", drive->name, ide_xfer_verbose(mode));
-	error = ide_config_drive_speed(drive, mode);
-
-	return error;
-}
-
-/*
- * Here are the standard PIO mode 0-4 timings for each "format".
- * Format-0 uses fast data reg timings, with slower command reg timings.
- * Format-1 uses fast timings for all registers, but won't work with all drives.
- */
-static unsigned int cs5530_pio_timings[2][5] =
-	{{0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010},
-	 {0xd1329172, 0x71212171, 0x30200080, 0x20102010, 0x00100010}};
-
-/*
- * After chip reset, the PIO timings are set to 0x0000e132, which is not valid.
- */
-#define CS5530_BAD_PIO(timings) (((timings)&~0x80000000)==0x0000e132)
-#define CS5530_BASEREG(hwif)	(((hwif)->dma_base & ~0xf) + ((hwif)->channel ? 0x30 : 0x20))
-
-/*
- * cs5530_tuneproc() handles selection/setting of PIO modes
- * for both the chipset and drive.
- *
- * The ide_init_cs5530() routine guarantees that all drives
- * will have valid default PIO timings set up before we get here.
- */
-static void cs5530_tuneproc (ide_drive_t *drive, byte pio)	/* pio=255 means "autotune" */
-{
-	ide_hwif_t	*hwif = HWIF(drive);
-	unsigned int	format, basereg = CS5530_BASEREG(hwif);
-	static byte	modes[5] = {XFER_PIO_0, XFER_PIO_1, XFER_PIO_2, XFER_PIO_3, XFER_PIO_4};
-
-	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
-	if (!cs5530_set_xfer_mode(drive, modes[pio])) {
-		format = (inl(basereg+4) >> 31) & 1;
-		outl(cs5530_pio_timings[format][pio], basereg+(drive->select.b.unit<<3));
-	}
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-/*
- * cs5530_config_dma() handles selection/setting of DMA/UDMA modes
- * for both the chipset and drive.
- */
-static int cs5530_config_dma (ide_drive_t *drive)
-{
-	int			udma_ok = 1, mode = 0;
-	ide_hwif_t		*hwif = HWIF(drive);
-	int			unit = drive->select.b.unit;
-	ide_drive_t		*mate = &hwif->drives[unit^1];
-	struct hd_driveid	*id = drive->id;
-	unsigned int		basereg, reg, timings;
-
-
-	/*
-	 * Default to DMA-off in case we run into trouble here.
-	 */
-	(void)hwif->dmaproc(ide_dma_off_quietly, drive);	/* turn off DMA while we fiddle */
-	outb(inb(hwif->dma_base+2)&~(unit?0x40:0x20), hwif->dma_base+2); /* clear DMA_capable bit */
-
-	/*
-	 * The CS5530 specifies that two drives sharing a cable cannot
-	 * mix UDMA/MDMA.  It has to be one or the other, for the pair,
-	 * though different timings can still be chosen for each drive.
-	 * We could set the appropriate timing bits on the fly,
-	 * but that might be a bit confusing.  So, for now we statically
-	 * handle this requirement by looking at our mate drive to see
-	 * what it is capable of, before choosing a mode for our own drive.
-	 */
-	if (mate->present) {
-		struct hd_driveid *mateid = mate->id;
-		if (mateid && (mateid->capability & 1) && !hwif->dmaproc(ide_dma_bad_drive, mate)) {
-			if ((mateid->field_valid & 4) && (mateid->dma_ultra & 7))
-				udma_ok = 1;
-			else if ((mateid->field_valid & 2) && (mateid->dma_mword & 7))
-				udma_ok = 0;
-			else
-				udma_ok = 1;
-		}
-	}
-
-	/*
-	 * Now see what the current drive is capable of,
-	 * selecting UDMA only if the mate said it was ok.
-	 */
-	if (id && (id->capability & 1) && hwif->autodma && !hwif->dmaproc(ide_dma_bad_drive, drive)) {
-		if (udma_ok && (id->field_valid & 4) && (id->dma_ultra & 7)) {
-			if      (id->dma_ultra & 4)
-				mode = XFER_UDMA_2;
-			else if (id->dma_ultra & 2)
-				mode = XFER_UDMA_1;
-			else if (id->dma_ultra & 1)
-				mode = XFER_UDMA_0;
-		}
-		if (!mode && (id->field_valid & 2) && (id->dma_mword & 7)) {
-			if      (id->dma_mword & 4)
-				mode = XFER_MW_DMA_2;
-			else if (id->dma_mword & 2)
-				mode = XFER_MW_DMA_1;
-			else if (id->dma_mword & 1)
-				mode = XFER_MW_DMA_0;
-		}
-	}
-
-	/*
-	 * Tell the drive to switch to the new mode; abort on failure.
-	 */
-	if (!mode || cs5530_set_xfer_mode(drive, mode))
-		return 1;	/* failure */
-
-	/*
-	 * Now tune the chipset to match the drive:
-	 */
-	switch (mode) {
-		case XFER_UDMA_0:	timings = 0x00921250; break;
-		case XFER_UDMA_1:	timings = 0x00911140; break;
-		case XFER_UDMA_2:	timings = 0x00911030; break;
-		case XFER_MW_DMA_0:	timings = 0x00077771; break;
-		case XFER_MW_DMA_1:	timings = 0x00012121; break;
-		case XFER_MW_DMA_2:	timings = 0x00002020; break;
-		default:
-			printk("%s: cs5530_config_dma: huh? mode=%02x\n", drive->name, mode);
-			return 1;	/* failure */
-	}
-	basereg = CS5530_BASEREG(hwif);
-	reg = inl(basereg+4);			/* get drive0 config register */
-	timings |= reg & 0x80000000;		/* preserve PIO format bit */
-	if (unit == 0) {			/* are we configuring drive0? */
-		outl(timings, basereg+4);	/* write drive0 config register */
-	} else {
-		if (timings & 0x00100000)
-			reg |=  0x00100000;	/* enable UDMA timings for both drives */
-		else
-			reg &= ~0x00100000;	/* disable UDMA timings for both drives */
-		outl(reg,     basereg+4);	/* write drive0 config register */
-		outl(timings, basereg+12);	/* write drive1 config register */
-	}
-	outb(inb(hwif->dma_base+2)|(unit?0x40:0x20), hwif->dma_base+2);	/* set DMA_capable bit */
-
-	/*
-	 * Finally, turn DMA on in software, and exit.
-	 */
-	return hwif->dmaproc(ide_dma_on, drive);	/* success */
-}
-
-/*
- * This is a CS5530-specific wrapper for the standard ide_dmaproc().
- * We need it for our custom "ide_dma_check" function.
- * All other requests are forwarded to the standard ide_dmaproc().
- */
-int cs5530_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch (func) {
-		case ide_dma_check:
-			return cs5530_config_dma(drive);
-		default:
-			break;
-	}
-	/* Other cases are done by generic IDE-DMA code. */
-	return ide_dmaproc(func, drive);
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-/*
- * Initialize the cs5530 bridge for reliable IDE DMA operation.
- */
-unsigned int __init pci_init_cs5530 (struct pci_dev *dev, const char *name)
-{
-	struct pci_dev *master_0 = NULL, *cs5530_0 = NULL;
-	unsigned short pcicmd = 0;
-	unsigned long flags;
-
-#if defined(DISPLAY_CS5530_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!cs5530_proc) {
-		cs5530_proc = 1;
-		bmide_dev = dev;
-		cs5530_display_info = &cs5530_get_info;
-	}
-#endif /* DISPLAY_CS5530_TIMINGS && CONFIG_PROC_FS */
-
-	pci_for_each_dev (dev) {
-		if (dev->vendor == PCI_VENDOR_ID_CYRIX) {
-			switch (dev->device) {
-				case PCI_DEVICE_ID_CYRIX_PCI_MASTER:
-					master_0 = dev;
-					break;
-				case PCI_DEVICE_ID_CYRIX_5530_LEGACY:
-					cs5530_0 = dev;
-					break;
-			}
-		}
-	}
-	if (!master_0) {
-		printk("%s: unable to locate PCI MASTER function\n", name);
-		return 0;
-	}
-	if (!cs5530_0) {
-		printk("%s: unable to locate CS5530 LEGACY function\n", name);
-		return 0;
-	}
-
-	save_flags(flags);
-	cli();	/* all CPUs (there should only be one CPU with this chipset) */
-
-	/*
-	 * Enable BusMaster and MemoryWriteAndInvalidate for the cs5530:
-	 * -->  OR 0x14 into 16-bit PCI COMMAND reg of function 0 of the cs5530
-	 */
-	pci_read_config_word (cs5530_0, PCI_COMMAND, &pcicmd);
-	pci_write_config_word(cs5530_0, PCI_COMMAND, pcicmd | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE);
-
-	/*
-	 * Set PCI CacheLineSize to 16-bytes:
-	 * --> Write 0x04 into 8-bit PCI CACHELINESIZE reg of function 0 of the cs5530
-	 */
-	pci_write_config_byte(cs5530_0, PCI_CACHE_LINE_SIZE, 0x04);
-
-	/*
-	 * Disable trapping of UDMA register accesses (Win98 hack):
-	 * --> Write 0x5006 into 16-bit reg at offset 0xd0 of function 0 of the cs5530
-	 */
-	pci_write_config_word(cs5530_0, 0xd0, 0x5006);
-
-	/*
-	 * Bit-1 at 0x40 enables MemoryWriteAndInvalidate on internal X-bus:
-	 * The other settings are what is necessary to get the register
-	 * into a sane state for IDE DMA operation.
-	 */
-	pci_write_config_byte(master_0, 0x40, 0x1e);
-
-	/* 
-	 * Set max PCI burst size (16-bytes seems to work best):
-	 *	   16bytes: set bit-1 at 0x41 (reg value of 0x16)
-	 *	all others: clear bit-1 at 0x41, and do:
-	 *	  128bytes: OR 0x00 at 0x41
-	 *	  256bytes: OR 0x04 at 0x41
-	 *	  512bytes: OR 0x08 at 0x41
-	 *	 1024bytes: OR 0x0c at 0x41
-	 */
-	pci_write_config_byte(master_0, 0x41, 0x14);
-
-	/*
-	 * These settings are necessary to get the chip
-	 * into a sane state for IDE DMA operation.
-	 */
-	pci_write_config_byte(master_0, 0x42, 0x00);
-	pci_write_config_byte(master_0, 0x43, 0xc1);
-
-	restore_flags(flags);
-
-	return 0;
-}
-
-/*
- * This gets invoked by the IDE driver once for each channel,
- * and performs channel-specific pre-initialization before drive probing.
- */
-void __init ide_init_cs5530 (ide_hwif_t *hwif)
-{
-	if (hwif->mate)
-		hwif->serialized = hwif->mate->serialized = 1;
-	if (!hwif->dma_base) {
-		hwif->autodma = 0;
-	} else {
-		unsigned int basereg, d0_timings;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		hwif->dmaproc  = &cs5530_dmaproc;
-#else
-		hwif->autodma = 0;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-		hwif->tuneproc = &cs5530_tuneproc;
-		basereg = CS5530_BASEREG(hwif);
-		d0_timings = inl(basereg+0);
-		if (CS5530_BAD_PIO(d0_timings)) {	/* PIO timings not initialized? */
-			outl(cs5530_pio_timings[(d0_timings>>31)&1][0], basereg+0);
-			if (!hwif->drives[0].autotune)
-				hwif->drives[0].autotune = 1;	/* needs autotuning later */
-		}
-		if (CS5530_BAD_PIO(inl(basereg+8))) {	/* PIO timings not initialized? */
-			outl(cs5530_pio_timings[(d0_timings>>31)&1][0], basereg+8);
-			if (!hwif->drives[1].autotune)
-				hwif->drives[1].autotune = 1;	/* needs autotuning later */
-		}
-	}
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/cy82c693.c linux-2.4.21-pre6/drivers/ide/cy82c693.c
--- linux-2.4.20/drivers/ide/cy82c693.c	2001-05-20 00:43:06.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/cy82c693.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,449 +0,0 @@
-/*
- * linux/drivers/ide/cy82c693.c		Version 0.34	Dec. 13, 1999
- *
- *  Copyright (C) 1998-2000 Andreas S. Krebs (akrebs@altavista.net), Maintainer
- *  Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>, Integrater
- *
- * CYPRESS CY82C693 chipset IDE controller
- *
- * The CY82C693 chipset is used on Digital's PC-Alpha 164SX boards.
- * Writting the driver was quite simple, since most of the job is
- * done by the generic pci-ide support. 
- * The hard part was finding the CY82C693's datasheet on Cypress's
- * web page :-(. But Altavista solved this problem :-).
- *
- *
- * Notes:
- * - I recently got a 16.8G IBM DTTA, so I was able to test it with
- *   a large and fast disk - the results look great, so I'd say the
- *   driver is working fine :-)
- *   hdparm -t reports 8.17 MB/sec at about 6% CPU usage for the DTTA 
- * - this is my first linux driver, so there's probably a lot  of room 
- *   for optimizations and bug fixing, so feel free to do it.
- * - use idebus=xx parameter to set PCI bus speed - needed to calc
- *   timings for PIO modes (default will be 40)
- * - if using PIO mode it's a good idea to set the PIO mode and 
- *   32-bit I/O support (if possible), e.g. hdparm -p2 -c1 /dev/hda
- * - I had some problems with my IBM DHEA with PIO modes < 2
- *   (lost interrupts) ?????
- * - first tests with DMA look okay, they seem to work, but there is a
- *   problem with sound - the BusMaster IDE TimeOut should fixed this
- *
- *
- * History:
- * AMH@1999-08-24: v0.34 init_cy82c693_chip moved to pci_init_cy82c693
- * ASK@1999-01-23: v0.33 made a few minor code clean ups
- *                       removed DMA clock speed setting by default
- *                       added boot message
- * ASK@1998-11-01: v0.32 added support to set BusMaster IDE TimeOut
- *                       added support to set DMA Controller Clock Speed
- * ASK@1998-10-31: v0.31 fixed problem with setting to high DMA modes on some drive
- * ASK@1998-10-29: v0.3 added support to set DMA modes
- * ASK@1998-10-28: v0.2 added support to set PIO modes
- * ASK@1998-10-27: v0.1 first version - chipset detection
- *
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-/* the current version */
-#define CY82_VERSION	"CY82C693U driver v0.34 99-13-12 Andreas S. Krebs (akrebs@altavista.net)"
-
-/*
- *	The following are used to debug the driver.
- */
-#define	CY82C693_DEBUG_LOGS	0
-#define	CY82C693_DEBUG_INFO	0
-
-/* define CY82C693_SETDMA_CLOCK to set DMA Controller Clock Speed to ATCLK */
-#undef CY82C693_SETDMA_CLOCK
-
-/*
- * note: the value for busmaster timeout is tricky and i got it by trial and error !
- *       using a to low value will cause DMA timeouts and drop IDE performance
- *       using a to high value will cause audio playback to scatter
- *       if you know a better value or how to calc it, please let me know 
- */
-#define BUSMASTER_TIMEOUT	0x50	/* twice the value written in cy82c693ub datasheet */
-/*
- * the value above was tested on my machine and it seems to work okay
- */
-
-/* here are the offset definitions for the registers */
-#define CY82_IDE_CMDREG		0x04
-#define CY82_IDE_ADDRSETUP	0x48
-#define CY82_IDE_MASTER_IOR	0x4C	
-#define CY82_IDE_MASTER_IOW	0x4D	
-#define CY82_IDE_SLAVE_IOR	0x4E	
-#define CY82_IDE_SLAVE_IOW	0x4F
-#define CY82_IDE_MASTER_8BIT	0x50	
-#define CY82_IDE_SLAVE_8BIT	0x51	
-
-#define CY82_INDEX_PORT		0x22
-#define CY82_DATA_PORT		0x23
-
-#define CY82_INDEX_CTRLREG1	0x01
-#define CY82_INDEX_CHANNEL0	0x30
-#define CY82_INDEX_CHANNEL1	0x31
-#define CY82_INDEX_TIMEOUT	0x32
-
-/* the max PIO mode - from datasheet */
-#define CY82C693_MAX_PIO	4
-
-/* the min and max PCI bus speed in MHz - from datasheet */
-#define CY82C963_MIN_BUS_SPEED	25
-#define CY82C963_MAX_BUS_SPEED	33
-
-/* the struct for the PIO mode timings */
-typedef struct pio_clocks_s {
-        byte	address_time;		/* Address setup (clocks) */
-	byte	time_16r;		/* clocks for 16bit IOR (0xF0=Active/data, 0x0F=Recovery) */
-	byte	time_16w;		/* clocks for 16bit IOW (0xF0=Active/data, 0x0F=Recovery) */
-	byte	time_8;			/* clocks for 8bit (0xF0=Active/data, 0x0F=Recovery) */
-} pio_clocks_t;
-
-/*
- * calc clocks using bus_speed
- * returns (rounded up) time in bus clocks for time in ns
- */
-static int calc_clk (int time, int bus_speed)
-{
-	int clocks;
-
-	clocks = (time*bus_speed+999)/1000 -1;
-
-	if (clocks < 0)
-		clocks = 0;
-
-	if (clocks > 0x0F)
-		clocks = 0x0F;
-
-	return clocks;
-}
-
-/*
- * compute the values for the clock registers for PIO
- * mode and pci_clk [MHz] speed
- *
- * NOTE: for mode 0,1 and 2 drives 8-bit IDE command control registers are used
- *       for mode 3 and 4 drives 8 and 16-bit timings are the same
- *
- */ 
-static void compute_clocks (byte pio, pio_clocks_t *p_pclk)
-{
-	int clk1, clk2;
-	int bus_speed = system_bus_clock();	/* get speed of PCI bus */
-
-	/* we don't check against CY82C693's min and max speed,
-	 * so you can play with the idebus=xx parameter
-	 */
-
-	if (pio > CY82C693_MAX_PIO)
-		pio = CY82C693_MAX_PIO;
-
-	/* let's calc the address setup time clocks */
-	p_pclk->address_time = (byte)calc_clk(ide_pio_timings[pio].setup_time, bus_speed);
-
-	/* let's calc the active and recovery time clocks */
-	clk1 = calc_clk(ide_pio_timings[pio].active_time, bus_speed);
-
-	/* calc recovery timing */
-	clk2 =	ide_pio_timings[pio].cycle_time -
-		ide_pio_timings[pio].active_time -
-		ide_pio_timings[pio].setup_time;
-
-	clk2 = calc_clk(clk2, bus_speed);
-
-	clk1 = (clk1<<4)|clk2;	/* combine active and recovery clocks */
-
-	/* note: we use the same values for 16bit IOR and IOW
-         *	those are all the same, since I don't have other
-	 *	timings than those from ide_modes.h
-	 */
-
-	p_pclk->time_16r = (byte)clk1;
-	p_pclk->time_16w = (byte)clk1;
-
-	/* what are good values for 8bit ?? */
-	p_pclk->time_8 = (byte)clk1;
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-/*
- * set DMA mode a specific channel for CY82C693
- */
-static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
-{
-        byte index;
-	byte data;
-
-        if (mode>2)	/* make sure we set a valid mode */
-		mode = 2;
-			   
-	if (mode > drive->id->tDMA)  /* to be absolutly sure we have a valid mode */
-		mode = drive->id->tDMA;
-	
-        index = (HWIF(drive)->channel==0) ? CY82_INDEX_CHANNEL0 : CY82_INDEX_CHANNEL1;
-
-#if CY82C693_DEBUG_LOGS
-       	/* for debug let's show the previous values */
-
-	OUT_BYTE(index, CY82_INDEX_PORT);
-	data = IN_BYTE(CY82_DATA_PORT);
-
-	printk (KERN_INFO "%s (ch=%d, dev=%d): DMA mode is %d (single=%d)\n", drive->name, HWIF(drive)->channel, drive->select.b.unit, (data&0x3), ((data>>2)&1));
-#endif /* CY82C693_DEBUG_LOGS */
-
-	data = (byte)mode|(byte)(single<<2);
-
-	OUT_BYTE(index, CY82_INDEX_PORT);
-	OUT_BYTE(data, CY82_DATA_PORT);
-
-#if CY82C693_DEBUG_INFO
-	printk (KERN_INFO "%s (ch=%d, dev=%d): set DMA mode to %d (single=%d)\n", drive->name, HWIF(drive)->channel, drive->select.b.unit, mode, single);
-#endif /* CY82C693_DEBUG_INFO */
-
-	/* 
-	 * note: below we set the value for Bus Master IDE TimeOut Register
-	 * I'm not absolutly sure what this does, but it solved my problem
-	 * with IDE DMA and sound, so I now can play sound and work with
-	 * my IDE driver at the same time :-)
-	 *
-	 * If you know the correct (best) value for this register please
-	 * let me know - ASK
-	 */
-
-	data = BUSMASTER_TIMEOUT;
-	OUT_BYTE(CY82_INDEX_TIMEOUT, CY82_INDEX_PORT);
-	OUT_BYTE(data, CY82_DATA_PORT);
-
-#if CY82C693_DEBUG_INFO	
-	printk (KERN_INFO "%s: Set IDE Bus Master TimeOut Register to 0x%X\n", drive->name, data);
-#endif /* CY82C693_DEBUG_INFO */
-}
-
-/* 
- * used to set DMA mode for CY82C693 (single and multi modes)
- */
-static int cy82c693_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-	/*
-	 * if the function is dma on, set dma mode for drive everything
-	 * else is done by the defaul func
-	 */
-	if (func == ide_dma_on) {
-		struct hd_driveid *id = drive->id;
-
-#if CY82C693_DEBUG_INFO
-		printk (KERN_INFO "dma_on: %s\n", drive->name);
-#endif /* CY82C693_DEBUG_INFO */
-
-		if (id != NULL) {		
-                       /* Enable DMA on any drive that has DMA (multi or single) enabled */
-                       if (id->field_valid & 2) {       /* regular DMA */
-			       int mmode, smode;
-
-			       mmode = id->dma_mword & (id->dma_mword >> 8);
-			       smode = id->dma_1word & (id->dma_1word >> 8);
-			       		      
-		               if (mmode != 0)
-				     cy82c693_dma_enable(drive, (mmode >> 1), 0); /* enable multi */
-			       else if (smode != 0)
-				     cy82c693_dma_enable(drive, (smode >> 1), 1); /* enable single */
-			}
-		}
-	}
-        return ide_dmaproc(func, drive);
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-/*
- * tune ide drive - set PIO mode
- */
-static void cy82c693_tune_drive (ide_drive_t *drive, byte pio)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	struct pci_dev *dev = hwif->pci_dev;
-	pio_clocks_t pclk;
-	unsigned int addrCtrl;
-
-	/* select primary or secondary channel */
-	if (hwif->index > 0) {  /* drive is on the secondary channel */
-		dev = pci_find_slot(dev->bus->number, dev->devfn+1);
-		if (!dev) {
-			printk(KERN_ERR "%s: tune_drive: Cannot find secondary interface!\n", drive->name);
-			return;
-		}
-	}
-
-#if CY82C693_DEBUG_LOGS
-	/* for debug let's show the register values */
-	
-       	if (drive->select.b.unit == 0) {
-		/*
-		 * get master drive registers               	
-		 * address setup control register
-		 * is 32 bit !!!
-		 */ 
-	  	pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);                
-		addrCtrl &= 0x0F;
-
-		/* now let's get the remaining registers */
-		pci_read_config_byte(dev, CY82_IDE_MASTER_IOR, &pclk.time_16r);
-		pci_read_config_byte(dev, CY82_IDE_MASTER_IOW, &pclk.time_16w);
-		pci_read_config_byte(dev, CY82_IDE_MASTER_8BIT, &pclk.time_8);
-	} else {
-		/*
-		 * set slave drive registers
-		 * address setup control register
-		 * is 32 bit !!!
-		 */ 
-		pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
-
-		addrCtrl &= 0xF0;
-		addrCtrl >>= 4;
-
-		/* now let's get the remaining registers */
-		pci_read_config_byte(dev, CY82_IDE_SLAVE_IOR, &pclk.time_16r);
-		pci_read_config_byte(dev, CY82_IDE_SLAVE_IOW, &pclk.time_16w);
-		pci_read_config_byte(dev, CY82_IDE_SLAVE_8BIT, &pclk.time_8);
-	}
-
-	printk (KERN_INFO "%s (ch=%d, dev=%d): PIO timing is (addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n", drive->name, hwif->channel, drive->select.b.unit, addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
-#endif /* CY82C693_DEBUG_LOGS */
-
-        /* first let's calc the pio modes */
-	pio = ide_get_best_pio_mode(drive, pio, CY82C693_MAX_PIO, NULL);
-
-#if CY82C693_DEBUG_INFO
-	printk (KERN_INFO "%s: Selected PIO mode %d\n", drive->name, pio);
-#endif /* CY82C693_DEBUG_INFO */
-
-        compute_clocks(pio, &pclk);  /* let's calc the values for this PIO mode */
-
-	/* now let's write  the clocks registers */
-	if (drive->select.b.unit == 0) {
-		/*
-		 * set master drive
-		 * address setup control register
-		 * is 32 bit !!!
-		 */ 
-		pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
-		
-		addrCtrl &= (~0xF);
-		addrCtrl |= (unsigned int)pclk.address_time;
-		pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl);
-
-		/* now let's set the remaining registers */
-		pci_write_config_byte(dev, CY82_IDE_MASTER_IOR, pclk.time_16r);
-		pci_write_config_byte(dev, CY82_IDE_MASTER_IOW, pclk.time_16w);
-		pci_write_config_byte(dev, CY82_IDE_MASTER_8BIT, pclk.time_8);
-		
-		addrCtrl &= 0xF;
-	} else {
-		/*
-		 * set slave drive
-		 * address setup control register
-		 * is 32 bit !!!
-		 */ 
-		pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
-
-		addrCtrl &= (~0xF0);
-		addrCtrl |= ((unsigned int)pclk.address_time<<4);
-		pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl);
-
-		/* now let's set the remaining registers */
-		pci_write_config_byte(dev, CY82_IDE_SLAVE_IOR, pclk.time_16r);
-		pci_write_config_byte(dev, CY82_IDE_SLAVE_IOW, pclk.time_16w);
-		pci_write_config_byte(dev, CY82_IDE_SLAVE_8BIT, pclk.time_8);
-
-		addrCtrl >>= 4;
-		addrCtrl &= 0xF;
-	}	
-
-#if CY82C693_DEBUG_INFO
-	printk (KERN_INFO "%s (ch=%d, dev=%d): set PIO timing to (addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n", drive->name, hwif->channel, drive->select.b.unit, addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
-#endif /* CY82C693_DEBUG_INFO */
-}
-
-/*
- * this function is called during init and is used to setup the cy82c693 chip
- */
-/*
- * FIXME! "pci_init_cy82c693" really should replace
- * the "init_cy82c693_chip", it is the correct location to tinker/setup
- * the device prior to INIT.
- */
-
-unsigned int __init pci_init_cy82c693(struct pci_dev *dev, const char *name)
-{
-#ifdef CY82C693_SETDMA_CLOCK
-        byte data;
-#endif /* CY82C693_SETDMA_CLOCK */ 
-
-	/* write info about this verion of the driver */
-	printk (KERN_INFO CY82_VERSION "\n");
-
-#ifdef CY82C693_SETDMA_CLOCK
-       /* okay let's set the DMA clock speed */
-        
-        OUT_BYTE(CY82_INDEX_CTRLREG1, CY82_INDEX_PORT);
-        data = IN_BYTE(CY82_DATA_PORT);
-
-#if CY82C693_DEBUG_INFO
-	printk (KERN_INFO "%s: Peripheral Configuration Register: 0x%X\n", name, data);
-#endif /* CY82C693_DEBUG_INFO */
-
-        /*
-	 * for some reason sometimes the DMA controller
-	 * speed is set to ATCLK/2 ???? - we fix this here
-	 * 
-	 * note: i don't know what causes this strange behaviour,
-	 *       but even changing the dma speed doesn't solve it :-(
-	 *       the ide performance is still only half the normal speed 
-	 * 
-	 *       if anybody knows what goes wrong with my machine, please
-	 *       let me know - ASK
-         */
-
-	data |= 0x03;
-
-        OUT_BYTE(CY82_INDEX_CTRLREG1, CY82_INDEX_PORT);
-        OUT_BYTE(data, CY82_DATA_PORT);
-
-#if CY82C693_DEBUG_INFO
-	printk (KERN_INFO "%s: New Peripheral Configuration Register: 0x%X\n", name, data);
-#endif /* CY82C693_DEBUG_INFO */
-
-#endif /* CY82C693_SETDMA_CLOCK */
-	return 0;
-}
-
-/*
- * the init function - called for each ide channel once
- */
-void __init ide_init_cy82c693(ide_hwif_t *hwif)
-{
-	hwif->chipset = ide_cy82c693;
-	hwif->tuneproc = &cy82c693_tune_drive;
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-	hwif->autodma = 0;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (hwif->dma_base) {
-		hwif->dmaproc = &cy82c693_dmaproc;
-		if (!noautodma)
-			hwif->autodma = 1;
-	}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/dtc2278.c linux-2.4.21-pre6/drivers/ide/dtc2278.c
--- linux-2.4.20/drivers/ide/dtc2278.c	2000-04-14 05:54:26.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/dtc2278.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,134 +0,0 @@
-/*
- *  linux/drivers/ide/dtc2278.c		Version 0.02	Feb 10, 1996
- *
- *  Copyright (C) 1996  Linus Torvalds & author (see below)
- */
-
-#undef REALLY_SLOW_IO           /* most systems can safely undef this */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-/*
- * Changing this #undef to #define may solve start up problems in some systems.
- */
-#undef ALWAYS_SET_DTC2278_PIO_MODE
-
-/*
- * From: andy@cercle.cts.com (Dyan Wile)
- *
- * Below is a patch for DTC-2278 - alike software-programmable controllers
- * The code enables the secondary IDE controller and the PIO4 (3?) timings on
- * the primary (EIDE). You may probably have to enable the 32-bit support to
- * get the full speed. You better get the disk interrupts disabled ( hdparm -u0
- * /dev/hd.. ) for the drives connected to the EIDE interface. (I get my
- * filesystem  corrupted with -u1, but under heavy disk load only :-)
- *
- * This card is now forced to use the "serialize" feature,
- * and irq-unmasking is disallowed.  If io_32bit is enabled,
- * it must be done for BOTH drives on each interface.
- *
- * This code was written for the DTC2278E, but might work with any of these:
- *
- * DTC2278S has only a single IDE interface.
- * DTC2278D has two IDE interfaces and is otherwise identical to the S version.
- * DTC2278E also has serial ports and a printer port
- * DTC2278EB: has onboard BIOS, and "works like a charm" -- Kent Bradford <kent@theory.caltech.edu>
- *
- * There may be a fourth controller type. The S and D versions use the
- * Winbond chip, and I think the E version does also.
- *
- */
-
-static void sub22 (char b, char c)
-{
-	int i;
-
-	for(i = 0; i < 3; ++i) {
-		inb(0x3f6);
-		outb_p(b,0xb0);
-		inb(0x3f6);
-		outb_p(c,0xb4);
-		inb(0x3f6);
-		if(inb(0xb4) == c) {
-			outb_p(7,0xb0);
-			inb(0x3f6);
-			return;	/* success */
-		}
-	}
-}
-
-static void tune_dtc2278 (ide_drive_t *drive, byte pio)
-{
-	unsigned long flags;
-
-	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
-
-	if (pio >= 3) {
-		save_flags(flags);	/* all CPUs */
-		cli();			/* all CPUs */
-		/*
-		 * This enables PIO mode4 (3?) on the first interface
-		 */
-		sub22(1,0xc3);
-		sub22(0,0xa0);
-		restore_flags(flags);	/* all CPUs */
-	} else {
-		/* we don't know how to set it back again.. */
-	}
-
-	/*
-	 * 32bit I/O has to be enabled for *both* drives at the same time.
-	 */
-	drive->io_32bit = 1;
-	HWIF(drive)->drives[!drive->select.b.unit].io_32bit = 1;
-}
-
-void __init init_dtc2278 (void)
-{
-	unsigned long flags;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-	/*
-	 * This enables the second interface
-	 */
-	outb_p(4,0xb0);
-	inb(0x3f6);
-	outb_p(0x20,0xb4);
-	inb(0x3f6);
-#ifdef ALWAYS_SET_DTC2278_PIO_MODE
-	/*
-	 * This enables PIO mode4 (3?) on the first interface
-	 * and may solve start-up problems for some people.
-	 */
-	sub22(1,0xc3);
-	sub22(0,0xa0);
-#endif
-	__restore_flags(flags);	/* local CPU only */
-
-	ide_hwifs[0].serialized = 1;
-	ide_hwifs[1].serialized = 1;
-	ide_hwifs[0].chipset = ide_dtc2278;
-	ide_hwifs[1].chipset = ide_dtc2278;
-	ide_hwifs[0].tuneproc = &tune_dtc2278;
-	ide_hwifs[0].drives[0].no_unmask = 1;
-	ide_hwifs[0].drives[1].no_unmask = 1;
-	ide_hwifs[1].drives[0].no_unmask = 1;
-	ide_hwifs[1].drives[1].no_unmask = 1;
-	ide_hwifs[0].mate = &ide_hwifs[1];
-	ide_hwifs[1].mate = &ide_hwifs[0];
-	ide_hwifs[1].channel = 1;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/falconide.c linux-2.4.21-pre6/drivers/ide/falconide.c
--- linux-2.4.20/drivers/ide/falconide.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/falconide.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,68 +0,0 @@
-/*
- *  linux/drivers/ide/falconide.c -- Atari Falcon IDE Driver
- *
- *     Created 12 Jul 1997 by Geert Uytterhoeven
- *
- *  This file is subject to the terms and conditions of the GNU General Public
- *  License.  See the file COPYING in the main directory of this archive for
- *  more details.
- */
-
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/setup.h>
-#include <asm/atarihw.h>
-#include <asm/atariints.h>
-#include <asm/atari_stdma.h>
-
-
-    /*
-     *  Base of the IDE interface
-     */
-
-#define ATA_HD_BASE	0xfff00000
-
-    /*
-     *  Offsets from the above base
-     */
-
-#define ATA_HD_DATA	0x00
-#define ATA_HD_ERROR	0x05		/* see err-bits */
-#define ATA_HD_NSECTOR	0x09		/* nr of sectors to read/write */
-#define ATA_HD_SECTOR	0x0d		/* starting sector */
-#define ATA_HD_LCYL	0x11		/* starting cylinder */
-#define ATA_HD_HCYL	0x15		/* high byte of starting cyl */
-#define ATA_HD_SELECT	0x19		/* 101dhhhh , d=drive, hhhh=head */
-#define ATA_HD_STATUS	0x1d		/* see status-bits */
-#define ATA_HD_CONTROL	0x39
-
-static int falconide_offsets[IDE_NR_PORTS] __initdata = {
-    ATA_HD_DATA, ATA_HD_ERROR, ATA_HD_NSECTOR, ATA_HD_SECTOR, ATA_HD_LCYL,
-    ATA_HD_HCYL, ATA_HD_SELECT, ATA_HD_STATUS, ATA_HD_CONTROL, -1
-};
-
-
-    /*
-     *  Probe for a Falcon IDE interface
-     */
-
-void __init falconide_init(void)
-{
-    if (MACH_IS_ATARI && ATARIHW_PRESENT(IDE)) {
-	hw_regs_t hw;
-	int index;
-
-	ide_setup_ports(&hw, (ide_ioreg_t)ATA_HD_BASE, falconide_offsets,
-			0, 0, NULL, IRQ_MFP_IDE);
-	index = ide_register_hw(&hw, NULL);
-
-	if (index != -1)
-	    printk("ide%d: Falcon IDE interface\n", index);
-    }
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/gayle.c linux-2.4.21-pre6/drivers/ide/gayle.c
--- linux-2.4.20/drivers/ide/gayle.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/gayle.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,181 +0,0 @@
-/*
- *  linux/drivers/ide/gayle.c -- Amiga Gayle IDE Driver
- *
- *     Created 9 Jul 1997 by Geert Uytterhoeven
- *
- *  This file is subject to the terms and conditions of the GNU General Public
- *  License.  See the file COPYING in the main directory of this archive for
- *  more details.
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-#include <linux/zorro.h>
-
-#include <asm/setup.h>
-#include <asm/amigahw.h>
-#include <asm/amigaints.h>
-#include <asm/amigayle.h>
-
-
-    /*
-     *  Bases of the IDE interfaces
-     */
-
-#define GAYLE_BASE_4000	0xdd2020	/* A4000/A4000T */
-#define GAYLE_BASE_1200	0xda0000	/* A1200/A600 */
-
-    /*
-     *  Offsets from one of the above bases
-     */
-
-#define GAYLE_DATA	0x00
-#define GAYLE_ERROR	0x06		/* see err-bits */
-#define GAYLE_NSECTOR	0x0a		/* nr of sectors to read/write */
-#define GAYLE_SECTOR	0x0e		/* starting sector */
-#define GAYLE_LCYL	0x12		/* starting cylinder */
-#define GAYLE_HCYL	0x16		/* high byte of starting cyl */
-#define GAYLE_SELECT	0x1a		/* 101dhhhh , d=drive, hhhh=head */
-#define GAYLE_STATUS	0x1e		/* see status-bits */
-#define GAYLE_CONTROL	0x101a
-
-static int gayle_offsets[IDE_NR_PORTS] __initdata = {
-    GAYLE_DATA, GAYLE_ERROR, GAYLE_NSECTOR, GAYLE_SECTOR, GAYLE_LCYL,
-    GAYLE_HCYL, GAYLE_SELECT, GAYLE_STATUS, -1, -1
-};
-
-
-    /*
-     *  These are at different offsets from the base
-     */
-
-#define GAYLE_IRQ_4000	0xdd3020	/* MSB = 1, Harddisk is source of */
-#define GAYLE_IRQ_1200	0xda9000	/* interrupt */
-
-
-    /*
-     *  Offset of the secondary port for IDE doublers
-     *  Note that GAYLE_CONTROL is NOT available then!
-     */
-
-#define GAYLE_NEXT_PORT	0x1000
-
-#ifndef CONFIG_BLK_DEV_IDEDOUBLER
-#define GAYLE_NUM_HWIFS		1
-#define GAYLE_NUM_PROBE_HWIFS	GAYLE_NUM_HWIFS
-#define GAYLE_HAS_CONTROL_REG	1
-#define GAYLE_IDEREG_SIZE	0x2000
-#else /* CONFIG_BLK_DEV_IDEDOUBLER */
-#define GAYLE_NUM_HWIFS		2
-#define GAYLE_NUM_PROBE_HWIFS	(ide_doubler ? GAYLE_NUM_HWIFS : \
-					       GAYLE_NUM_HWIFS-1)
-#define GAYLE_HAS_CONTROL_REG	(!ide_doubler)
-#define GAYLE_IDEREG_SIZE	(ide_doubler ? 0x1000 : 0x2000)
-int ide_doubler = 0;	/* support IDE doublers? */
-#endif /* CONFIG_BLK_DEV_IDEDOUBLER */
-
-
-    /*
-     *  Check and acknowledge the interrupt status
-     */
-
-static int gayle_ack_intr_a4000(ide_hwif_t *hwif)
-{
-    unsigned char ch;
-
-    ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]);
-    if (!(ch & GAYLE_IRQ_IDE))
-	return 0;
-    return 1;
-}
-
-static int gayle_ack_intr_a1200(ide_hwif_t *hwif)
-{
-    unsigned char ch;
-
-    ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]);
-    if (!(ch & GAYLE_IRQ_IDE))
-	return 0;
-    (void)z_readb(hwif->io_ports[IDE_STATUS_OFFSET]);
-    z_writeb(0x7c, hwif->io_ports[IDE_IRQ_OFFSET]);
-    return 1;
-}
-
-    /*
-     *  Probe for a Gayle IDE interface (and optionally for an IDE doubler)
-     */
-
-void __init gayle_init(void)
-{
-    int a4000, i;
-
-    if (!MACH_IS_AMIGA)
-	return;
-
-    if (!(a4000 = AMIGAHW_PRESENT(A4000_IDE)) && !AMIGAHW_PRESENT(A1200_IDE))
-	return;
-
-    for (i = 0; i < GAYLE_NUM_PROBE_HWIFS; i++) {
-	ide_ioreg_t base, ctrlport, irqport;
-	ide_ack_intr_t *ack_intr;
-	hw_regs_t hw;
-	int index;
-	unsigned long phys_base, res_start, res_n;
-
-	if (a4000) {
-	    phys_base = GAYLE_BASE_4000;
-	    irqport = (ide_ioreg_t)ZTWO_VADDR(GAYLE_IRQ_4000);
-	    ack_intr = gayle_ack_intr_a4000;
-	} else {
-	    phys_base = GAYLE_BASE_1200;
-	    irqport = (ide_ioreg_t)ZTWO_VADDR(GAYLE_IRQ_1200);
-	    ack_intr = gayle_ack_intr_a1200;
-	}
-	phys_base += i*GAYLE_NEXT_PORT;
-
-	res_start = ((unsigned long)phys_base) & ~(GAYLE_NEXT_PORT-1);
-	res_n = GAYLE_IDEREG_SIZE;
-
-	if (!request_mem_region(res_start, res_n, "IDE"))
-	    continue;
-
-	base = (ide_ioreg_t)ZTWO_VADDR(phys_base);
-	ctrlport = GAYLE_HAS_CONTROL_REG ? (base + GAYLE_CONTROL) : 0;
-
-	ide_setup_ports(&hw, base, gayle_offsets,
-			ctrlport, irqport, ack_intr, IRQ_AMIGA_PORTS);
-
-	index = ide_register_hw(&hw, NULL);
-	if (index != -1) {
-	    switch (i) {
-		case 0:
-		    printk("ide%d: Gayle IDE interface (A%d style)\n", index,
-			   a4000 ? 4000 : 1200);
-		    break;
-#ifdef CONFIG_BLK_DEV_IDEDOUBLER
-		case 1:
-		    printk("ide%d: IDE doubler\n", index);
-		    break;
-#endif /* CONFIG_BLK_DEV_IDEDOUBLER */
-	    }
-	} else
-	    release_mem_region(res_start, res_n);
-
-#if 1 /* TESTING */
-	if (i == 1) {
-	    volatile u_short *addr = (u_short *)base;
-	    u_short data;
-	    printk("+++ Probing for IDE doubler... ");
-	    *addr = 0xffff;
-	    data = *addr;
-	    printk("probe returned 0x%02x (PLEASE REPORT THIS!!)\n", data);
-	}
-#endif /* TESTING */
-    }
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/hd.c linux-2.4.21-pre6/drivers/ide/hd.c
--- linux-2.4.20/drivers/ide/hd.c	2001-10-15 20:27:42.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/hd.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,918 +0,0 @@
-/*
- *  linux/drivers/ide/hd.c
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- */
-
-/*
- * This is the low-level hd interrupt support. It traverses the
- * request-list, using interrupts to jump between functions. As
- * all the functions are called within interrupts, we may not
- * sleep. Special care is recommended.
- * 
- *  modified by Drew Eckhardt to check nr of hd's from the CMOS.
- *
- *  Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
- *  in the early extended-partition checks and added DM partitions
- *
- *  IRQ-unmask, drive-id, multiple-mode, support for ">16 heads",
- *  and general streamlining by Mark Lord.
- *
- *  Removed 99% of above. Use Mark's ide driver for those options.
- *  This is now a lightweight ST-506 driver. (Paul Gortmaker)
- *
- *  Modified 1995 Russell King for ARM processor.
- *
- *  Bugfix: max_sectors must be <= 255 or the wheels tend to come
- *  off in a hurry once you queue things up - Paul G. 02/2001
- */
-  
-/* Uncomment the following if you want verbose error reports. */
-/* #define VERBOSE_ERRORS */
-  
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/fs.h>
-#include <linux/devfs_fs_kernel.h>
-#include <linux/kernel.h>
-#include <linux/hdreg.h>
-#include <linux/genhd.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/mc146818rtc.h> /* CMOS defines */
-#include <linux/init.h>
-#include <linux/blkpg.h>
-
-#define REALLY_SLOW_IO
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-
-#define MAJOR_NR HD_MAJOR
-#include <linux/blk.h>
-
-#ifdef __arm__
-#undef  HD_IRQ
-#endif
-#include <asm/irq.h>
-#ifdef __arm__
-#define HD_IRQ IRQ_HARDDISK
-#endif
-
-static int revalidate_hddisk(kdev_t, int);
-
-#define	HD_DELAY	0
-
-#define MAX_ERRORS     16	/* Max read/write errors/sector */
-#define RESET_FREQ      8	/* Reset controller every 8th retry */
-#define RECAL_FREQ      4	/* Recalibrate every 4th retry */
-#define MAX_HD		2
-
-#define STAT_OK		(READY_STAT|SEEK_STAT)
-#define OK_STATUS(s)	(((s)&(STAT_OK|(BUSY_STAT|WRERR_STAT|ERR_STAT)))==STAT_OK)
-
-static void recal_intr(void);
-static void bad_rw_intr(void);
-
-static char recalibrate[MAX_HD];
-static char special_op[MAX_HD];
-static int access_count[MAX_HD];
-static char busy[MAX_HD];
-static DECLARE_WAIT_QUEUE_HEAD(busy_wait);
-
-static int reset;
-static int hd_error;
-
-#define SUBSECTOR(block) (CURRENT->current_nr_sectors > 0)
-
-/*
- *  This struct defines the HD's and their types.
- */
-struct hd_i_struct {
-	unsigned int head,sect,cyl,wpcom,lzone,ctl;
-};
-	
-#ifdef HD_TYPE
-static struct hd_i_struct hd_info[] = { HD_TYPE };
-static int NR_HD = ((sizeof (hd_info))/(sizeof (struct hd_i_struct)));
-#else
-static struct hd_i_struct hd_info[MAX_HD];
-static int NR_HD;
-#endif
-
-static struct hd_struct hd[MAX_HD<<6];
-static int hd_sizes[MAX_HD<<6];
-static int hd_blocksizes[MAX_HD<<6];
-static int hd_hardsectsizes[MAX_HD<<6];
-static int hd_maxsect[MAX_HD<<6];
-
-static struct timer_list device_timer;
-
-#define SET_TIMER 							\
-	do {								\
-		mod_timer(&device_timer, jiffies + TIMEOUT_VALUE);	\
-	} while (0)
-
-#define CLEAR_TIMER del_timer(&device_timer);
-
-#undef SET_INTR
-
-#define SET_INTR(x) \
-if ((DEVICE_INTR = (x)) != NULL) \
-	SET_TIMER; \
-else \
-	CLEAR_TIMER;
-
-
-#if (HD_DELAY > 0)
-unsigned long last_req;
-
-unsigned long read_timer(void)
-{
-	unsigned long t, flags;
-	int i;
-
-	save_flags(flags);
-	cli();
-	t = jiffies * 11932;
-    	outb_p(0, 0x43);
-	i = inb_p(0x40);
-	i |= inb(0x40) << 8;
-	restore_flags(flags);
-	return(t - i);
-}
-#endif
-
-void __init hd_setup(char *str, int *ints)
-{
-	int hdind = 0;
-
-	if (ints[0] != 3)
-		return;
-	if (hd_info[0].head != 0)
-		hdind=1;
-	hd_info[hdind].head = ints[2];
-	hd_info[hdind].sect = ints[3];
-	hd_info[hdind].cyl = ints[1];
-	hd_info[hdind].wpcom = 0;
-	hd_info[hdind].lzone = ints[1];
-	hd_info[hdind].ctl = (ints[2] > 8 ? 8 : 0);
-	NR_HD = hdind+1;
-}
-
-static void dump_status (const char *msg, unsigned int stat)
-{
-	unsigned long flags;
-	char devc;
-
-	devc = !QUEUE_EMPTY ? 'a' + DEVICE_NR(CURRENT->rq_dev) : '?';
-	save_flags (flags);
-	sti();
-#ifdef VERBOSE_ERRORS
-	printk("hd%c: %s: status=0x%02x { ", devc, msg, stat & 0xff);
-	if (stat & BUSY_STAT)	printk("Busy ");
-	if (stat & READY_STAT)	printk("DriveReady ");
-	if (stat & WRERR_STAT)	printk("WriteFault ");
-	if (stat & SEEK_STAT)	printk("SeekComplete ");
-	if (stat & DRQ_STAT)	printk("DataRequest ");
-	if (stat & ECC_STAT)	printk("CorrectedError ");
-	if (stat & INDEX_STAT)	printk("Index ");
-	if (stat & ERR_STAT)	printk("Error ");
-	printk("}\n");
-	if ((stat & ERR_STAT) == 0) {
-		hd_error = 0;
-	} else {
-		hd_error = inb(HD_ERROR);
-		printk("hd%c: %s: error=0x%02x { ", devc, msg, hd_error & 0xff);
-		if (hd_error & BBD_ERR)		printk("BadSector ");
-		if (hd_error & ECC_ERR)		printk("UncorrectableError ");
-		if (hd_error & ID_ERR)		printk("SectorIdNotFound ");
-		if (hd_error & ABRT_ERR)	printk("DriveStatusError ");
-		if (hd_error & TRK0_ERR)	printk("TrackZeroNotFound ");
-		if (hd_error & MARK_ERR)	printk("AddrMarkNotFound ");
-		printk("}");
-		if (hd_error & (BBD_ERR|ECC_ERR|ID_ERR|MARK_ERR)) {
-			printk(", CHS=%d/%d/%d", (inb(HD_HCYL)<<8) + inb(HD_LCYL),
-				inb(HD_CURRENT) & 0xf, inb(HD_SECTOR));
-			if (!QUEUE_EMPTY)
-				printk(", sector=%ld", CURRENT->sector);
-		}
-		printk("\n");
-	}
-#else
-	printk("hd%c: %s: status=0x%02x.\n", devc, msg, stat & 0xff);
-	if ((stat & ERR_STAT) == 0) {
-		hd_error = 0;
-	} else {
-		hd_error = inb(HD_ERROR);
-		printk("hd%c: %s: error=0x%02x.\n", devc, msg, hd_error & 0xff);
-	}
-#endif	/* verbose errors */
-	restore_flags (flags);
-}
-
-void check_status(void)
-{
-	int i = inb_p(HD_STATUS);
-
-	if (!OK_STATUS(i)) {
-		dump_status("check_status", i);
-		bad_rw_intr();
-	}
-}
-
-static int controller_busy(void)
-{
-	int retries = 100000;
-	unsigned char status;
-
-	do {
-		status = inb_p(HD_STATUS);
-	} while ((status & BUSY_STAT) && --retries);
-	return status;
-}
-
-static int status_ok(void)
-{
-	unsigned char status = inb_p(HD_STATUS);
-
-	if (status & BUSY_STAT)
-		return 1;	/* Ancient, but does it make sense??? */
-	if (status & WRERR_STAT)
-		return 0;
-	if (!(status & READY_STAT))
-		return 0;
-	if (!(status & SEEK_STAT))
-		return 0;
-	return 1;
-}
-
-static int controller_ready(unsigned int drive, unsigned int head)
-{
-	int retry = 100;
-
-	do {
-		if (controller_busy() & BUSY_STAT)
-			return 0;
-		outb_p(0xA0 | (drive<<4) | head, HD_CURRENT);
-		if (status_ok())
-			return 1;
-	} while (--retry);
-	return 0;
-}
-
-static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
-		unsigned int head,unsigned int cyl,unsigned int cmd,
-		void (*intr_addr)(void))
-{
-	unsigned short port;
-
-#if (HD_DELAY > 0)
-	while (read_timer() - last_req < HD_DELAY)
-		/* nothing */;
-#endif
-	if (reset)
-		return;
-	if (!controller_ready(drive, head)) {
-		reset = 1;
-		return;
-	}
-	SET_INTR(intr_addr);
-	outb_p(hd_info[drive].ctl,HD_CMD);
-	port=HD_DATA;
-	outb_p(hd_info[drive].wpcom>>2,++port);
-	outb_p(nsect,++port);
-	outb_p(sect,++port);
-	outb_p(cyl,++port);
-	outb_p(cyl>>8,++port);
-	outb_p(0xA0|(drive<<4)|head,++port);
-	outb_p(cmd,++port);
-}
-
-static void hd_request (void);
-
-static int drive_busy(void)
-{
-	unsigned int i;
-	unsigned char c;
-
-	for (i = 0; i < 500000 ; i++) {
-		c = inb_p(HD_STATUS);
-		if ((c & (BUSY_STAT | READY_STAT | SEEK_STAT)) == STAT_OK)
-			return 0;
-	}
-	dump_status("reset timed out", c);
-	return 1;
-}
-
-static void reset_controller(void)
-{
-	int	i;
-
-	outb_p(4,HD_CMD);
-	for(i = 0; i < 1000; i++) barrier();
-	outb_p(hd_info[0].ctl & 0x0f,HD_CMD);
-	for(i = 0; i < 1000; i++) barrier();
-	if (drive_busy())
-		printk("hd: controller still busy\n");
-	else if ((hd_error = inb(HD_ERROR)) != 1)
-		printk("hd: controller reset failed: %02x\n",hd_error);
-}
-
-static void reset_hd(void)
-{
-	static int i;
-
-repeat:
-	if (reset) {
-		reset = 0;
-		i = -1;
-		reset_controller();
-	} else {
-		check_status();
-		if (reset)
-			goto repeat;
-	}
-	if (++i < NR_HD) {
-		special_op[i] = recalibrate[i] = 1;
-		hd_out(i,hd_info[i].sect,hd_info[i].sect,hd_info[i].head-1,
-			hd_info[i].cyl,WIN_SPECIFY,&reset_hd);
-		if (reset)
-			goto repeat;
-	} else
-		hd_request();
-}
-
-/*
- * Ok, don't know what to do with the unexpected interrupts: on some machines
- * doing a reset and a retry seems to result in an eternal loop. Right now I
- * ignore it, and just set the timeout.
- *
- * On laptops (and "green" PCs), an unexpected interrupt occurs whenever the
- * drive enters "idle", "standby", or "sleep" mode, so if the status looks
- * "good", we just ignore the interrupt completely.
- */
-void unexpected_hd_interrupt(void)
-{
-	unsigned int stat = inb_p(HD_STATUS);
-
-	if (stat & (BUSY_STAT|DRQ_STAT|ECC_STAT|ERR_STAT)) {
-		dump_status ("unexpected interrupt", stat);
-		SET_TIMER;
-	}
-}
-
-/*
- * bad_rw_intr() now tries to be a bit smarter and does things
- * according to the error returned by the controller.
- * -Mika Liljeberg (liljeber@cs.Helsinki.FI)
- */
-static void bad_rw_intr(void)
-{
-	int dev;
-
-	if (QUEUE_EMPTY)
-		return;
-	dev = DEVICE_NR(CURRENT->rq_dev);
-	if (++CURRENT->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) {
-		end_request(0);
-		special_op[dev] = recalibrate[dev] = 1;
-	} else if (CURRENT->errors % RESET_FREQ == 0)
-		reset = 1;
-	else if ((hd_error & TRK0_ERR) || CURRENT->errors % RECAL_FREQ == 0)
-		special_op[dev] = recalibrate[dev] = 1;
-	/* Otherwise just retry */
-}
-
-static inline int wait_DRQ(void)
-{
-	int retries = 100000, stat;
-
-	while (--retries > 0)
-		if ((stat = inb_p(HD_STATUS)) & DRQ_STAT)
-			return 0;
-	dump_status("wait_DRQ", stat);
-	return -1;
-}
-
-static void read_intr(void)
-{
-	int i, retries = 100000;
-
-	do {
-		i = (unsigned) inb_p(HD_STATUS);
-		if (i & BUSY_STAT)
-			continue;
-		if (!OK_STATUS(i))
-			break;
-		if (i & DRQ_STAT)
-			goto ok_to_read;
-	} while (--retries > 0);
-	dump_status("read_intr", i);
-	bad_rw_intr();
-	hd_request();
-	return;
-ok_to_read:
-	insw(HD_DATA,CURRENT->buffer,256);
-	CURRENT->sector++;
-	CURRENT->buffer += 512;
-	CURRENT->errors = 0;
-	i = --CURRENT->nr_sectors;
-	--CURRENT->current_nr_sectors;
-#ifdef DEBUG
-	printk("hd%c: read: sector %ld, remaining = %ld, buffer=0x%08lx\n",
-		dev+'a', CURRENT->sector, CURRENT->nr_sectors,
-		(unsigned long) CURRENT->buffer+512));
-#endif
-	if (CURRENT->current_nr_sectors <= 0)
-		end_request(1);
-	if (i > 0) {
-		SET_INTR(&read_intr);
-		return;
-	}
-	(void) inb_p(HD_STATUS);
-#if (HD_DELAY > 0)
-	last_req = read_timer();
-#endif
-	if (!QUEUE_EMPTY)
-		hd_request();
-	return;
-}
-
-static void write_intr(void)
-{
-	int i;
-	int retries = 100000;
-
-	do {
-		i = (unsigned) inb_p(HD_STATUS);
-		if (i & BUSY_STAT)
-			continue;
-		if (!OK_STATUS(i))
-			break;
-		if ((CURRENT->nr_sectors <= 1) || (i & DRQ_STAT))
-			goto ok_to_write;
-	} while (--retries > 0);
-	dump_status("write_intr", i);
-	bad_rw_intr();
-	hd_request();
-	return;
-ok_to_write:
-	CURRENT->sector++;
-	i = --CURRENT->nr_sectors;
-	--CURRENT->current_nr_sectors;
-	CURRENT->buffer += 512;
-	if (!i || (CURRENT->bh && !SUBSECTOR(i)))
-		end_request(1);
-	if (i > 0) {
-		SET_INTR(&write_intr);
-		outsw(HD_DATA,CURRENT->buffer,256);
-		sti();
-	} else {
-#if (HD_DELAY > 0)
-		last_req = read_timer();
-#endif
-		hd_request();
-	}
-	return;
-}
-
-static void recal_intr(void)
-{
-	check_status();
-#if (HD_DELAY > 0)
-	last_req = read_timer();
-#endif
-	hd_request();
-}
-
-/*
- * This is another of the error-routines I don't know what to do with. The
- * best idea seems to just set reset, and start all over again.
- */
-static void hd_times_out(unsigned long dummy)
-{
-	unsigned int dev;
-
-	DEVICE_INTR = NULL;
-	if (QUEUE_EMPTY)
-		return;
-	disable_irq(HD_IRQ);
-	sti();
-	reset = 1;
-	dev = DEVICE_NR(CURRENT->rq_dev);
-	printk("hd%c: timeout\n", dev+'a');
-	if (++CURRENT->errors >= MAX_ERRORS) {
-#ifdef DEBUG
-		printk("hd%c: too many errors\n", dev+'a');
-#endif
-		end_request(0);
-	}
-	cli();
-	hd_request();
-	enable_irq(HD_IRQ);
-}
-
-int do_special_op (unsigned int dev)
-{
-	if (recalibrate[dev]) {
-		recalibrate[dev] = 0;
-		hd_out(dev,hd_info[dev].sect,0,0,0,WIN_RESTORE,&recal_intr);
-		return reset;
-	}
-	if (hd_info[dev].head > 16) {
-		printk ("hd%c: cannot handle device with more than 16 heads - giving up\n", dev+'a');
-		end_request(0);
-	}
-	special_op[dev] = 0;
-	return 1;
-}
-
-/*
- * The driver enables interrupts as much as possible.  In order to do this,
- * (a) the device-interrupt is disabled before entering hd_request(),
- * and (b) the timeout-interrupt is disabled before the sti().
- *
- * Interrupts are still masked (by default) whenever we are exchanging
- * data/cmds with a drive, because some drives seem to have very poor
- * tolerance for latency during I/O. The IDE driver has support to unmask
- * interrupts for non-broken hardware, so use that driver if required.
- */
-static void hd_request(void)
-{
-	unsigned int dev, block, nsect, sec, track, head, cyl;
-
-	if (!QUEUE_EMPTY && CURRENT->rq_status == RQ_INACTIVE) return;
-	if (DEVICE_INTR)
-		return;
-repeat:
-	del_timer(&device_timer);
-	sti();
-	INIT_REQUEST;
-	if (reset) {
-		cli();
-		reset_hd();
-		return;
-	}
-	dev = MINOR(CURRENT->rq_dev);
-	block = CURRENT->sector;
-	nsect = CURRENT->nr_sectors;
-	if (dev >= (NR_HD<<6) || block >= hd[dev].nr_sects || ((block+nsect) > hd[dev].nr_sects)) {
-#ifdef DEBUG
-		if (dev >= (NR_HD<<6))
-			printk("hd: bad minor number: device=%s\n",
-			       kdevname(CURRENT->rq_dev));
-		else
-			printk("hd%c: bad access: block=%d, count=%d\n",
-				(MINOR(CURRENT->rq_dev)>>6)+'a', block, nsect);
-#endif
-		end_request(0);
-		goto repeat;
-	}
-	block += hd[dev].start_sect;
-	dev >>= 6;
-	if (special_op[dev]) {
-		if (do_special_op(dev))
-			goto repeat;
-		return;
-	}
-	sec   = block % hd_info[dev].sect + 1;
-	track = block / hd_info[dev].sect;
-	head  = track % hd_info[dev].head;
-	cyl   = track / hd_info[dev].head;
-#ifdef DEBUG
-	printk("hd%c: %sing: CHS=%d/%d/%d, sectors=%d, buffer=0x%08lx\n",
-		dev+'a', (CURRENT->cmd == READ)?"read":"writ",
-		cyl, head, sec, nsect, (unsigned long) CURRENT->buffer);
-#endif
-	if (CURRENT->cmd == READ) {
-		hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr);
-		if (reset)
-			goto repeat;
-		return;
-	}
-	if (CURRENT->cmd == WRITE) {
-		hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
-		if (reset)
-			goto repeat;
-		if (wait_DRQ()) {
-			bad_rw_intr();
-			goto repeat;
-		}
-		outsw(HD_DATA,CURRENT->buffer,256);
-		return;
-	}
-	panic("unknown hd-command");
-}
-
-static void do_hd_request (request_queue_t * q)
-{
-	disable_irq(HD_IRQ);
-	hd_request();
-	enable_irq(HD_IRQ);
-}
-
-static int hd_ioctl(struct inode * inode, struct file * file,
-	unsigned int cmd, unsigned long arg)
-{
-	struct hd_geometry *loc = (struct hd_geometry *) arg;
-	int dev;
-
-	if ((!inode) || !(inode->i_rdev))
-		return -EINVAL;
-	dev = DEVICE_NR(inode->i_rdev);
-	if (dev >= NR_HD)
-		return -EINVAL;
-	switch (cmd) {
-		case HDIO_GETGEO:
-		{
-			struct hd_geometry g; 
-			if (!loc)  return -EINVAL;
-			g.heads = hd_info[dev].head;
-			g.sectors = hd_info[dev].sect;
-			g.cylinders = hd_info[dev].cyl;
-			g.start = hd[MINOR(inode->i_rdev)].start_sect;
-			return copy_to_user(loc, &g, sizeof g) ? -EFAULT : 0; 
-		}
-
-         	case BLKGETSIZE:   /* Return device size */
-			return put_user(hd[MINOR(inode->i_rdev)].nr_sects, 
-					(unsigned long *) arg);
-         	case BLKGETSIZE64:
-			return put_user((u64)hd[MINOR(inode->i_rdev)].nr_sects << 9, 
-					(u64 *) arg);
-
-		case BLKRRPART: /* Re-read partition tables */
-			if (!capable(CAP_SYS_ADMIN))
-				return -EACCES;
-			return revalidate_hddisk(inode->i_rdev, 1);
-
-		case BLKROSET:
-		case BLKROGET:
-		case BLKRASET:
-		case BLKRAGET:
-		case BLKFLSBUF:
-		case BLKPG:
-			return blk_ioctl(inode->i_rdev, cmd, arg);
-
-		default:
-			return -EINVAL;
-	}
-}
-
-static int hd_open(struct inode * inode, struct file * filp)
-{
-	int target;
-	target =  DEVICE_NR(inode->i_rdev);
-
-	if (target >= NR_HD)
-		return -ENODEV;
-	while (busy[target])
-		sleep_on(&busy_wait);
-	access_count[target]++;
-	return 0;
-}
-
-/*
- * Releasing a block device means we sync() it, so that it can safely
- * be forgotten about...
- */
-static int hd_release(struct inode * inode, struct file * file)
-{
-        int target =  DEVICE_NR(inode->i_rdev);
-	access_count[target]--;
-	return 0;
-}
-
-extern struct block_device_operations hd_fops;
-
-static struct gendisk hd_gendisk = {
-	major:		MAJOR_NR,
-	major_name:	"hd",
-	minor_shift:	6,
-	max_p:		1 << 6,
-	part:		hd,
-	sizes:		hd_sizes,
-	fops:		&hd_fops,
-};
-	
-static void hd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	void (*handler)(void) = DEVICE_INTR;
-
-	DEVICE_INTR = NULL;
-	del_timer(&device_timer);
-	if (!handler)
-		handler = unexpected_hd_interrupt;
-	handler();
-	sti();
-}
-
-static struct block_device_operations hd_fops = {
-	open:		hd_open,
-	release:	hd_release,
-	ioctl:		hd_ioctl,
-};
-
-/*
- * This is the hard disk IRQ description. The SA_INTERRUPT in sa_flags
- * means we run the IRQ-handler with interrupts disabled:  this is bad for
- * interrupt latency, but anything else has led to problems on some
- * machines.
- *
- * We enable interrupts in some of the routines after making sure it's
- * safe.
- */
-static void __init hd_geninit(void)
-{
-	int drive;
-
-	for(drive=0; drive < (MAX_HD << 6); drive++) {
-		hd_blocksizes[drive] = 1024;
-		hd_hardsectsizes[drive] = 512;
-		hd_maxsect[drive]=255;
-	}
-	blksize_size[MAJOR_NR] = hd_blocksizes;
-	hardsect_size[MAJOR_NR] = hd_hardsectsizes;
-	max_sectors[MAJOR_NR] = hd_maxsect;
-
-#ifdef __i386__
-	if (!NR_HD) {
-		extern struct drive_info drive_info;
-		unsigned char *BIOS = (unsigned char *) &drive_info;
-		unsigned long flags;
-		int cmos_disks;
-
-		for (drive=0 ; drive<2 ; drive++) {
-			hd_info[drive].cyl = *(unsigned short *) BIOS;
-			hd_info[drive].head = *(2+BIOS);
-			hd_info[drive].wpcom = *(unsigned short *) (5+BIOS);
-			hd_info[drive].ctl = *(8+BIOS);
-			hd_info[drive].lzone = *(unsigned short *) (12+BIOS);
-			hd_info[drive].sect = *(14+BIOS);
-#ifdef does_not_work_for_everybody_with_scsi_but_helps_ibm_vp
-			if (hd_info[drive].cyl && NR_HD == drive)
-				NR_HD++;
-#endif
-			BIOS += 16;
-		}
-
-	/*
-		We query CMOS about hard disks : it could be that 
-		we have a SCSI/ESDI/etc controller that is BIOS
-		compatible with ST-506, and thus showing up in our
-		BIOS table, but not register compatible, and therefore
-		not present in CMOS.
-
-		Furthermore, we will assume that our ST-506 drives
-		<if any> are the primary drives in the system, and 
-		the ones reflected as drive 1 or 2.
-
-		The first drive is stored in the high nibble of CMOS
-		byte 0x12, the second in the low nibble.  This will be
-		either a 4 bit drive type or 0xf indicating use byte 0x19 
-		for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS.
-
-		Needless to say, a non-zero value means we have 
-		an AT controller hard disk for that drive.
-
-		Currently the rtc_lock is a bit academic since this
-		driver is non-modular, but someday... ?         Paul G.
-	*/
-
-		spin_lock_irqsave(&rtc_lock, flags);
-		cmos_disks = CMOS_READ(0x12);
-		spin_unlock_irqrestore(&rtc_lock, flags);
-
-		if (cmos_disks & 0xf0) {
-			if (cmos_disks & 0x0f)
-				NR_HD = 2;
-			else
-				NR_HD = 1;
-		}
-	}
-#endif /* __i386__ */
-#ifdef __arm__
-	if (!NR_HD) {
-		/* We don't know anything about the drive.  This means
-		 * that you *MUST* specify the drive parameters to the
-		 * kernel yourself.
-		 */
-		printk("hd: no drives specified - use hd=cyl,head,sectors"
-			" on kernel command line\n");
-	}
-#endif
-
-	for (drive=0 ; drive < NR_HD ; drive++) {
-		hd[drive<<6].nr_sects = hd_info[drive].head *
-			hd_info[drive].sect * hd_info[drive].cyl;
-		printk ("hd%c: %ldMB, CHS=%d/%d/%d\n", drive+'a',
-			hd[drive<<6].nr_sects / 2048, hd_info[drive].cyl,
-			hd_info[drive].head, hd_info[drive].sect);
-	}
-	if (!NR_HD)
-		return;
-
-	if (request_irq(HD_IRQ, hd_interrupt, SA_INTERRUPT, "hd", NULL)) {
-		printk("hd: unable to get IRQ%d for the hard disk driver\n",
-			HD_IRQ);
-		NR_HD = 0;
-		return;
-	}
-	request_region(HD_DATA, 8, "hd");
-	request_region(HD_CMD, 1, "hd(cmd)");
-
-	hd_gendisk.nr_real = NR_HD;
-
-	for(drive=0; drive < NR_HD; drive++)
-		register_disk(&hd_gendisk, MKDEV(MAJOR_NR,drive<<6), 1<<6,
-			&hd_fops, hd_info[drive].head * hd_info[drive].sect *
-			hd_info[drive].cyl);
-}
-
-int __init hd_init(void)
-{
-	if (devfs_register_blkdev(MAJOR_NR,"hd",&hd_fops)) {
-		printk("hd: unable to get major %d for hard disk\n",MAJOR_NR);
-		return -1;
-	}
-	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
-	read_ahead[MAJOR_NR] = 8;		/* 8 sector (4kB) read-ahead */
-	add_gendisk(&hd_gendisk);
-	init_timer(&device_timer);
-	device_timer.function = hd_times_out;
-	hd_geninit();
-	return 0;
-}
-
-#define DEVICE_BUSY busy[target]
-#define USAGE access_count[target]
-#define CAPACITY (hd_info[target].head*hd_info[target].sect*hd_info[target].cyl)
-/* We assume that the BIOS parameters do not change, so the disk capacity
-   will not change */
-#undef MAYBE_REINIT
-#define GENDISK_STRUCT hd_gendisk
-
-/*
- * This routine is called to flush all partitions and partition tables
- * for a changed disk, and then re-read the new partition table.
- * If we are revalidating a disk because of a media change, then we
- * enter with usage == 0.  If we are using an ioctl, we automatically have
- * usage == 1 (we need an open channel to use an ioctl :-), so this
- * is our limit.
- */
-static int revalidate_hddisk(kdev_t dev, int maxusage)
-{
-	int target;
-	struct gendisk * gdev;
-	int max_p;
-	int start;
-	int i;
-	long flags;
-
-	target = DEVICE_NR(dev);
-	gdev = &GENDISK_STRUCT;
-
-	save_flags(flags);
-	cli();
-	if (DEVICE_BUSY || USAGE > maxusage) {
-		restore_flags(flags);
-		return -EBUSY;
-	}
-	DEVICE_BUSY = 1;
-	restore_flags(flags);
-
-	max_p = gdev->max_p;
-	start = target << gdev->minor_shift;
-
-	for (i=max_p - 1; i >=0 ; i--) {
-		int minor = start + i;
-		invalidate_device(MKDEV(MAJOR_NR, minor), 1);
-		gdev->part[minor].start_sect = 0;
-		gdev->part[minor].nr_sects = 0;
-	}
-
-#ifdef MAYBE_REINIT
-	MAYBE_REINIT;
-#endif
-
-	grok_partitions(gdev, target, 1<<6, CAPACITY);
-
-	DEVICE_BUSY = 0;
-	wake_up(&busy_wait);
-	return 0;
-}
-
-static int parse_hd_setup (char *line) {
-	int ints[6];
-
-	(void) get_options(line, ARRAY_SIZE(ints), ints);
-	hd_setup(NULL, ints);
-
-	return 1;
-}
-__setup("hd=", parse_hd_setup);
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/hpt34x.c linux-2.4.21-pre6/drivers/ide/hpt34x.c
--- linux-2.4.20/drivers/ide/hpt34x.c	2001-05-20 00:43:06.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/hpt34x.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,437 +0,0 @@
-/*
- * linux/drivers/ide/hpt34x.c		Version 0.31	June. 9, 2000
- *
- * Copyright (C) 1998-2000	Andre Hedrick <andre@linux-ide.org>
- * May be copied or modified under the terms of the GNU General Public License
- *
- *
- * 00:12.0 Unknown mass storage controller:
- * Triones Technologies, Inc.
- * Unknown device 0003 (rev 01)
- *
- * hde: UDMA 2 (0x0000 0x0002) (0x0000 0x0010)
- * hdf: UDMA 2 (0x0002 0x0012) (0x0010 0x0030)
- * hde: DMA 2  (0x0000 0x0002) (0x0000 0x0010)
- * hdf: DMA 2  (0x0002 0x0012) (0x0010 0x0030)
- * hdg: DMA 1  (0x0012 0x0052) (0x0030 0x0070)
- * hdh: DMA 1  (0x0052 0x0252) (0x0070 0x00f0)
- *
- * ide-pci.c reference
- *
- * Since there are two cards that report almost identically,
- * the only discernable difference is the values reported in pcicmd.
- * Booting-BIOS card or HPT363 :: pcicmd == 0x07
- * Non-bootable card or HPT343 :: pcicmd == 0x05
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include "ide_modes.h"
-
-#ifndef SPLIT_BYTE
-#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
-#endif
-
-#define HPT343_DEBUG_DRIVE_INFO		0
-
-#undef DISPLAY_HPT34X_TIMINGS
-
-#if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int hpt34x_get_info(char *, char **, off_t, int);
-extern int (*hpt34x_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-extern char *ide_media_verbose(ide_drive_t *);
-static struct pci_dev *bmide_dev;
-
-static int hpt34x_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	u32 bibma = pci_resource_start(bmide_dev, 4);
-	u8  c0 = 0, c1 = 0;
-
-        /*
-         * at that point bibma+0x2 et bibma+0xa are byte registers
-         * to investigate:
-         */
-	c0 = inb_p((unsigned short)bibma + 0x02);
-	c1 = inb_p((unsigned short)bibma + 0x0a);
-
-	p += sprintf(p, "\n                                HPT34X Chipset.\n");
-	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
-	p += sprintf(p, "                %sabled                         %sabled\n",
-			(c0&0x80) ? "dis" : " en",
-			(c1&0x80) ? "dis" : " en");
-	p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
-	p += sprintf(p, "DMA enabled:    %s              %s             %s               %s\n",
-			(c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ",
-			(c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " );
-
-	p += sprintf(p, "UDMA\n");
-	p += sprintf(p, "DMA\n");
-	p += sprintf(p, "PIO\n");
-
-	return p-buffer;	/* => must be less than 4k! */
-}
-#endif  /* defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-byte hpt34x_proc = 0;
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-static void hpt34x_clear_chipset (ide_drive_t *drive)
-{
-	unsigned int reg1	= 0, tmp1 = 0;
-	unsigned int reg2	= 0, tmp2 = 0;
-
-	pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, &reg1);
-	pci_read_config_dword(HWIF(drive)->pci_dev, 0x48, &reg2);
-	tmp1 = ((0x00 << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn))));
-	tmp2 = (reg2 & ~(0x11 << drive->dn));
-	pci_write_config_dword(HWIF(drive)->pci_dev, 0x44, tmp1);
-	pci_write_config_dword(HWIF(drive)->pci_dev, 0x48, tmp2);
-}
-
-static int hpt34x_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	int			err;
-	byte			hi_speed, lo_speed;
-	unsigned int reg1	= 0, tmp1 = 0;
-	unsigned int reg2	= 0, tmp2 = 0;
-
-	SPLIT_BYTE(speed, hi_speed, lo_speed);
-
-	if (hi_speed & 7) {
-		hi_speed = (hi_speed & 4) ? 0x01 : 0x10;
-	} else {
-		lo_speed <<= 5;
-		lo_speed >>= 5;
-	}
-
-	pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, &reg1);
-	pci_read_config_dword(HWIF(drive)->pci_dev, 0x48, &reg2);
-	tmp1 = ((lo_speed << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn))));
-	tmp2 = ((hi_speed << drive->dn) | reg2);
-	err = ide_config_drive_speed(drive, speed);
-	pci_write_config_dword(HWIF(drive)->pci_dev, 0x44, tmp1);
-	pci_write_config_dword(HWIF(drive)->pci_dev, 0x48, tmp2);
-
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-
-#if HPT343_DEBUG_DRIVE_INFO
-	printk("%s: %s drive%d (0x%04x 0x%04x) (0x%04x 0x%04x)" \
-		" (0x%02x 0x%02x) 0x%04x\n",
-		drive->name, ide_xfer_verbose(speed),
-		drive->dn, reg1, tmp1, reg2, tmp2,
-		hi_speed, lo_speed, err);
-#endif /* HPT343_DEBUG_DRIVE_INFO */
-
-	drive->current_speed = speed;
-	return(err);
-}
-
-static void config_chipset_for_pio (ide_drive_t *drive)
-{
-	unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
-	unsigned short xfer_pio = drive->id->eide_pio_modes;
-
-	byte	timing, speed, pio;
-
-	pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
-
-	if (xfer_pio> 4)
-		xfer_pio = 0;
-
-	if (drive->id->eide_pio_iordy > 0) {
-		for (xfer_pio = 5;
-			xfer_pio>0 &&
-			drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
-			xfer_pio--);
-	} else {
-		xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
-			   (drive->id->eide_pio_modes & 2) ? 0x04 :
-			   (drive->id->eide_pio_modes & 1) ? 0x03 : xfer_pio;
-	}
-
-	timing = (xfer_pio >= pio) ? xfer_pio : pio;
-
-	switch(timing) {
-		case 4: speed = XFER_PIO_4;break;
-		case 3: speed = XFER_PIO_3;break;
-		case 2: speed = XFER_PIO_2;break;
-		case 1: speed = XFER_PIO_1;break;
-		default:
-			speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW;
-			break;
-		}
-	(void) hpt34x_tune_chipset(drive, speed);
-}
-
-static void hpt34x_tune_drive (ide_drive_t *drive, byte pio)
-{
-	byte speed;
-
-	switch(pio) {
-		case 4:		speed = XFER_PIO_4;break;
-		case 3:		speed = XFER_PIO_3;break;
-		case 2:		speed = XFER_PIO_2;break;
-		case 1:		speed = XFER_PIO_1;break;
-		default:	speed = XFER_PIO_0;break;
-	}
-	hpt34x_clear_chipset(drive);
-	(void) hpt34x_tune_chipset(drive, speed);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-/*
- * This allows the configuration of ide_pci chipset registers
- * for cards that learn about the drive's UDMA, DMA, PIO capabilities
- * after the drive is reported by the OS.  Initally for designed for
- * HPT343 UDMA chipset by HighPoint|Triones Technologies, Inc.
- */
-static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
-{
-	struct hd_driveid *id	= drive->id;
-	byte speed		= 0x00;
-
-	if (drive->media != ide_disk)
-		return ((int) ide_dma_off_quietly);
-
-	hpt34x_clear_chipset(drive);
-
-	if ((id->dma_ultra & 0x0010) && ultra) {
-		speed = XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0008) && ultra) {
-		speed = XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0004) && ultra) {
-		speed = XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0002) && ultra) {
-		speed = XFER_UDMA_1;
-	} else if ((id->dma_ultra & 0x0001) && ultra) {
-		speed = XFER_UDMA_0;
-	} else if (id->dma_mword & 0x0004) {
-		speed = XFER_MW_DMA_2;
-	} else if (id->dma_mword & 0x0002) {
-		speed = XFER_MW_DMA_1;
-	} else if (id->dma_mword & 0x0001) {
-		speed = XFER_MW_DMA_0;
-	} else if (id->dma_1word & 0x0004) {
-		speed = XFER_SW_DMA_2;
-	} else if (id->dma_1word & 0x0002) {
-		speed = XFER_SW_DMA_1;
-	} else if (id->dma_1word & 0x0001) {
-		speed = XFER_SW_DMA_0;
-        } else {
-		return ((int) ide_dma_off_quietly);
-	}
-
-	(void) hpt34x_tune_chipset(drive, speed);
-
-	return ((int)	((id->dma_ultra >> 11) & 3) ? ide_dma_off :
-			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-			((id->dma_mword >> 8) & 7) ? ide_dma_on :
-			((id->dma_1word >> 8) & 7) ? ide_dma_on :
-						     ide_dma_off_quietly);
-}
-
-static int config_drive_xfer_rate (ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-	ide_dma_action_t dma_func = ide_dma_on;
-
-	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x0007) {
-				/* Force if Capable UltraDMA */
-				dma_func = config_chipset_for_dma(drive, 1);
-				if ((id->field_valid & 2) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    (id->dma_1word & 0x0007)) {
-				/* Force if Capable regular DMA modes */
-				dma_func = config_chipset_for_dma(drive, 0);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			dma_func = config_chipset_for_dma(drive, 0);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-		config_chipset_for_pio(drive);
-	}
-
-#ifndef CONFIG_HPT34X_AUTODMA
-	if (dma_func == ide_dma_on)
-		dma_func = ide_dma_off;
-#endif /* CONFIG_HPT34X_AUTODMA */
-
-	return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-/*
- * hpt34x_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
- *
- * This is specific to the HPT343 UDMA bios-less chipset
- * and HPT345 UDMA bios chipset (stamped HPT363)
- * by HighPoint|Triones Technologies, Inc.
- */
-
-int hpt34x_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	unsigned long dma_base = hwif->dma_base;
-	unsigned int count, reading = 0;
-	byte dma_stat;
-
-	switch (func) {
-		case ide_dma_check:
-			return config_drive_xfer_rate(drive);
-		case ide_dma_read:
-			reading = 1 << 3;
-		case ide_dma_write:
-			if (!(count = ide_build_dmatable(drive, func)))
-				return 1;	/* try PIO instead of DMA */
-			outl(hwif->dmatable_dma, dma_base + 4); /* PRD table */
-			reading |= 0x01;
-			outb(reading, dma_base);		/* specify r/w */
-			outb(inb(dma_base+2)|6, dma_base+2);	/* clear INTR & ERROR flags */
-			drive->waiting_for_dma = 1;
-			if (drive->media != ide_disk)
-				return 0;
-			ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);	/* issue cmd to drive */
-			OUT_BYTE((reading == 9) ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
-			return 0;
-		case ide_dma_end:	/* returns 1 on error, 0 otherwise */
-			drive->waiting_for_dma = 0;
-			outb(inb(dma_base)&~1, dma_base);	/* stop DMA */
-			dma_stat = inb(dma_base+2);		/* get DMA status */
-			outb(dma_stat|6, dma_base+2);		/* clear the INTR & ERROR bits */
-			ide_destroy_dmatable(drive);		/* purge DMA mappings */
-			return (dma_stat & 7) != 4;		/* verify good DMA status */
-		default:
-			break;
-	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-/*
- * If the BIOS does not set the IO base addaress to XX00, 343 will fail.
- */
-#define	HPT34X_PCI_INIT_REG		0x80
-
-unsigned int __init pci_init_hpt34x (struct pci_dev *dev, const char *name)
-{
-	int i = 0;
-	unsigned long hpt34xIoBase = pci_resource_start(dev, 4);
-	unsigned short cmd;
-	unsigned long flags;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-
-	pci_write_config_byte(dev, HPT34X_PCI_INIT_REG, 0x00);
-	pci_read_config_word(dev, PCI_COMMAND, &cmd);
-
-	if (cmd & PCI_COMMAND_MEMORY) {
-		if (pci_resource_start(dev, PCI_ROM_RESOURCE)) {
-			pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
-			printk(KERN_INFO "HPT345: ROM enabled at 0x%08lx\n", dev->resource[PCI_ROM_RESOURCE].start);
-		}
-		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0);
-	} else {
-		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
-	}
-
-	pci_write_config_word(dev, PCI_COMMAND, cmd & ~PCI_COMMAND_IO);
-	dev->resource[0].start = (hpt34xIoBase + 0x20);
-	dev->resource[1].start = (hpt34xIoBase + 0x34);
-	dev->resource[2].start = (hpt34xIoBase + 0x28);
-	dev->resource[3].start = (hpt34xIoBase + 0x3c);
-	for(i=0; i<4; i++)
-		dev->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO;
-	/*
-	 * Since 20-23 can be assigned and are R/W, we correct them.
-	 */
-	pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, dev->resource[0].start);
-	pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, dev->resource[1].start);
-	pci_write_config_dword(dev, PCI_BASE_ADDRESS_2, dev->resource[2].start);
-	pci_write_config_dword(dev, PCI_BASE_ADDRESS_3, dev->resource[3].start);
-	pci_write_config_word(dev, PCI_COMMAND, cmd);
-
-	__restore_flags(flags);	/* local CPU only */
-
-#if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!hpt34x_proc) {
-		hpt34x_proc = 1;
-		bmide_dev = dev;
-		hpt34x_display_info = &hpt34x_get_info;
-	}
-#endif /* DISPLAY_HPT34X_TIMINGS && CONFIG_PROC_FS */
-
-	return dev->irq;
-}
-
-void __init ide_init_hpt34x (ide_hwif_t *hwif)
-{
-	hwif->tuneproc = &hpt34x_tune_drive;
-	hwif->speedproc = &hpt34x_tune_chipset;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (hwif->dma_base) {
-		unsigned short pcicmd = 0;
-
-		pci_read_config_word(hwif->pci_dev, PCI_COMMAND, &pcicmd);
-		if (!noautodma)
-			hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0;
-		else
-			hwif->autodma = 0;
-
-		hwif->dmaproc = &hpt34x_dmaproc;
-	} else {
-		hwif->drives[0].autotune = 1;
-		hwif->drives[1].autotune = 1;
-	}
-#else /* !CONFIG_BLK_DEV_IDEDMA */
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-	hwif->autodma = 0;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/hpt366.c linux-2.4.21-pre6/drivers/ide/hpt366.c
--- linux-2.4.20/drivers/ide/hpt366.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/hpt366.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,1233 +0,0 @@
-/*
- * linux/drivers/ide/hpt366.c		Version 0.22	20 Sep 2001
- *
- * Copyright (C) 1999-2000		Andre Hedrick <andre@linux-ide.org>
- * Portions Copyright (C) 2001	        Sun Microsystems, Inc.
- * May be copied or modified under the terms of the GNU General Public License
- *
- * Thanks to HighPoint Technologies for their assistance, and hardware.
- * Special Thanks to Jon Burchmore in SanDiego for the deep pockets, his
- * donation of an ABit BP6 mainboard, processor, and memory acellerated
- * development and support.
- *
- * Note that final HPT370 support was done by force extraction of GPL.
- *
- * - add function for getting/setting power status of drive
- * - the HPT370's state machine can get confused. reset it before each dma 
- *   xfer to prevent that from happening.
- * - reset state engine whenever we get an error.
- * - check for busmaster state at end of dma. 
- * - use new highpoint timings.
- * - detect bus speed using highpoint register.
- * - use pll if we don't have a clock table. added a 66MHz table that's
- *   just 2x the 33MHz table.
- * - removed turnaround. NOTE: we never want to switch between pll and
- *   pci clocks as the chip can glitch in those cases. the highpoint
- *   approved workaround slows everything down too much to be useful. in
- *   addition, we would have to serialize access to each chip.
- * 	Adrian Sun <a.sun@sun.com>
- *
- * add drive timings for 66MHz PCI bus,
- * fix ATA Cable signal detection, fix incorrect /proc info
- * add /proc display for per-drive PIO/DMA/UDMA mode and
- * per-channel ATA-33/66 Cable detect.
- * 	Duncan Laurie <void@sun.com>
- *
- * fixup /proc output for multiple controllers
- *	Tim Hockin <thockin@sun.com>
- *
- * On hpt366: 
- * Reset the hpt366 on error, reset on dma
- * Fix disabling Fast Interrupt hpt366.
- * 	Mike Waychison <crlf@sun.com>
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include "ide_modes.h"
-
-#define DISPLAY_HPT366_TIMINGS
-
-/* various tuning parameters */
-#define HPT_RESET_STATE_ENGINE
-/*#define HPT_DELAY_INTERRUPT*/
-/*#define HPT_SERIALIZE_IO*/
-
-#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-#endif  /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-extern char *ide_dmafunc_verbose(ide_dma_action_t dmafunc);
-
-const char *quirk_drives[] = {
-	"QUANTUM FIREBALLlct08 08",
-	"QUANTUM FIREBALLP KA6.4",
-	"QUANTUM FIREBALLP LM20.4",
-	"QUANTUM FIREBALLP LM20.5",
-        NULL
-};
-
-const char *bad_ata100_5[] = {
-	"IBM-DTLA-307075",
-	"IBM-DTLA-307060",
-	"IBM-DTLA-307045",
-	"IBM-DTLA-307030",
-	"IBM-DTLA-307020",
-	"IBM-DTLA-307015",
-	"IBM-DTLA-305040",
-	"IBM-DTLA-305030",
-	"IBM-DTLA-305020",
-	"IC35L010AVER07-0",
-	"IC35L020AVER07-0",
-	"IC35L030AVER07-0",
-	"IC35L040AVER07-0",
-	"IC35L060AVER07-0",
-	"WDC AC310200R",
-	NULL
-};
-
-const char *bad_ata66_4[] = {
-	"IBM-DTLA-307075",
-	"IBM-DTLA-307060",
-	"IBM-DTLA-307045",
-	"IBM-DTLA-307030",
-	"IBM-DTLA-307020",
-	"IBM-DTLA-307015",
-	"IBM-DTLA-305040",
-	"IBM-DTLA-305030",
-	"IBM-DTLA-305020",
-	"IC35L010AVER07-0",
-	"IC35L020AVER07-0",
-	"IC35L030AVER07-0",
-	"IC35L040AVER07-0",
-	"IC35L060AVER07-0",
-	"WDC AC310200R",
-	NULL
-};
-
-const char *bad_ata66_3[] = {
-	"WDC AC310200R",
-	NULL
-};
-
-const char *bad_ata33[] = {
-	"Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3", "Maxtor 90845U3", "Maxtor 90650U2",
-	"Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5", "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2",
-	"Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6", "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4",
-	"Maxtor 90510D4",
-	"Maxtor 90432D3", "Maxtor 90288D2", "Maxtor 90256D2",
-	"Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7", "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4",
-	"Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5", "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2",
-	NULL
-};
-
-struct chipset_bus_clock_list_entry {
-	byte		xfer_speed;
-	unsigned int	chipset_settings;
-};
-
-/* key for bus clock timings
- * bit
- * 0:3    data_high_time. inactive time of DIOW_/DIOR_ for PIO and MW
- *        DMA. cycles = value + 1
- * 4:8    data_low_time. active time of DIOW_/DIOR_ for PIO and MW
- *        DMA. cycles = value + 1
- * 9:12   cmd_high_time. inactive time of DIOW_/DIOR_ during task file
- *        register access.
- * 13:17  cmd_low_time. active time of DIOW_/DIOR_ during task file
- *        register access.
- * 18:21  udma_cycle_time. clock freq and clock cycles for UDMA xfer.
- *        during task file register access.
- * 22:24  pre_high_time. time to initialize 1st cycle for PIO and MW DMA
- *        xfer.
- * 25:27  cmd_pre_high_time. time to initialize 1st PIO cycle for task
- *        register access.
- * 28     UDMA enable
- * 29     DMA enable
- * 30     PIO_MST enable. if set, the chip is in bus master mode during
- *        PIO.
- * 31     FIFO enable.
- */
-struct chipset_bus_clock_list_entry forty_base [] = {
-
-	{	XFER_UDMA_4,    0x900fd943	},
-	{	XFER_UDMA_3,	0x900ad943	},
-	{	XFER_UDMA_2,	0x900bd943	},
-	{	XFER_UDMA_1,	0x9008d943	},
-	{	XFER_UDMA_0,	0x9008d943	},
-
-	{	XFER_MW_DMA_2,	0xa008d943	},
-	{	XFER_MW_DMA_1,	0xa010d955	},
-	{	XFER_MW_DMA_0,	0xa010d9fc	},
-
-	{	XFER_PIO_4,	0xc008d963	},
-	{	XFER_PIO_3,	0xc010d974	},
-	{	XFER_PIO_2,	0xc010d997	},
-	{	XFER_PIO_1,	0xc010d9c7	},
-	{	XFER_PIO_0,	0xc018d9d9	},
-	{	0,		0x0120d9d9	}
-};
-
-struct chipset_bus_clock_list_entry thirty_three_base [] = {
-
-	{	XFER_UDMA_4,	0x90c9a731	},
-	{	XFER_UDMA_3,	0x90cfa731	},
-	{	XFER_UDMA_2,	0x90caa731	},
-	{	XFER_UDMA_1,	0x90cba731	},
-	{	XFER_UDMA_0,	0x90c8a731	},
-
-	{	XFER_MW_DMA_2,	0xa0c8a731	},
-	{	XFER_MW_DMA_1,	0xa0c8a732	},	/* 0xa0c8a733 */
-	{	XFER_MW_DMA_0,	0xa0c8a797	},
-
-	{	XFER_PIO_4,	0xc0c8a731	},
-	{	XFER_PIO_3,	0xc0c8a742	},
-	{	XFER_PIO_2,	0xc0d0a753	},
-	{	XFER_PIO_1,	0xc0d0a7a3	},	/* 0xc0d0a793 */
-	{	XFER_PIO_0,	0xc0d0a7aa	},	/* 0xc0d0a7a7 */
-	{	0,		0x0120a7a7	}
-};
-
-struct chipset_bus_clock_list_entry twenty_five_base [] = {
-
-	{	XFER_UDMA_4,	0x90c98521	},
-	{	XFER_UDMA_3,	0x90cf8521	},
-	{	XFER_UDMA_2,	0x90cf8521	},
-	{	XFER_UDMA_1,	0x90cb8521	},
-	{	XFER_UDMA_0,	0x90cb8521	},
-
-	{	XFER_MW_DMA_2,	0xa0ca8521	},
-	{	XFER_MW_DMA_1,	0xa0ca8532	},
-	{	XFER_MW_DMA_0,	0xa0ca8575	},
-
-	{	XFER_PIO_4,	0xc0ca8521	},
-	{	XFER_PIO_3,	0xc0ca8532	},
-	{	XFER_PIO_2,	0xc0ca8542	},
-	{	XFER_PIO_1,	0xc0d08572	},
-	{	XFER_PIO_0,	0xc0d08585	},
-	{	0,		0x01208585	}
-};
-
-#if 1
-/* these are the current (4 sep 2001) timings from highpoint */
-struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = {
-        {       XFER_UDMA_5,    0x12446231      },
-        {       XFER_UDMA_4,    0x12446231      },
-        {       XFER_UDMA_3,    0x126c6231      },
-        {       XFER_UDMA_2,    0x12486231      },
-        {       XFER_UDMA_1,    0x124c6233      },
-        {       XFER_UDMA_0,    0x12506297      },
-
-        {       XFER_MW_DMA_2,  0x22406c31      },
-        {       XFER_MW_DMA_1,  0x22406c33      },
-        {       XFER_MW_DMA_0,  0x22406c97      },
-
-        {       XFER_PIO_4,     0x06414e31      },
-        {       XFER_PIO_3,     0x06414e42      },
-        {       XFER_PIO_2,     0x06414e53      },
-        {       XFER_PIO_1,     0x06814e93      },
-        {       XFER_PIO_0,     0x06814ea7      },
-        {       0,              0x06814ea7      }
-};
-
-/* 2x 33MHz timings */
-struct chipset_bus_clock_list_entry sixty_six_base_hpt370[] = {
-	{       XFER_UDMA_5,    0x1488e673       },
-	{       XFER_UDMA_4,    0x1488e673       },
-	{       XFER_UDMA_3,    0x1498e673       },
-	{       XFER_UDMA_2,    0x1490e673       },
-	{       XFER_UDMA_1,    0x1498e677       },
-	{       XFER_UDMA_0,    0x14a0e73f       },
-
-	{       XFER_MW_DMA_2,  0x2480fa73       },
-	{       XFER_MW_DMA_1,  0x2480fa77       }, 
-	{       XFER_MW_DMA_0,  0x2480fb3f       },
-
-	{       XFER_PIO_4,     0x0c82be73       },
-	{       XFER_PIO_3,     0x0c82be95       },
-	{       XFER_PIO_2,     0x0c82beb7       },
-	{       XFER_PIO_1,     0x0d02bf37       },
-	{       XFER_PIO_0,     0x0d02bf5f       },
-	{       0,              0x0d02bf5f       }
-};
-#else
-/* from highpoint documentation. these are old values */
-struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = {
-	{	XFER_UDMA_5,	0x16454e31	},
-	{	XFER_UDMA_4,	0x16454e31	},
-	{	XFER_UDMA_3,	0x166d4e31	},
-	{	XFER_UDMA_2,	0x16494e31	},
-	{	XFER_UDMA_1,	0x164d4e31	},
-	{	XFER_UDMA_0,	0x16514e31	},
-
-	{	XFER_MW_DMA_2,	0x26514e21	},
-	{	XFER_MW_DMA_1,	0x26514e33	},
-	{	XFER_MW_DMA_0,	0x26514e97	},
-
-	{	XFER_PIO_4,	0x06514e21	},
-	{	XFER_PIO_3,	0x06514e22	},
-	{	XFER_PIO_2,	0x06514e33	},
-	{	XFER_PIO_1,	0x06914e43	},
-	{	XFER_PIO_0,	0x06914e57	},
-	{	0,		0x06514e57	}
-};
-
-struct chipset_bus_clock_list_entry sixty_six_base_hpt370[] = {
-	{       XFER_UDMA_5,    0x14846231      },
-	{       XFER_UDMA_4,    0x14886231      },
-	{       XFER_UDMA_3,    0x148c6231      },
-	{       XFER_UDMA_2,    0x148c6231      },
-	{       XFER_UDMA_1,    0x14906231      },
-	{       XFER_UDMA_0,    0x14986231      },
-	
-	{       XFER_MW_DMA_2,  0x26514e21      },
-	{       XFER_MW_DMA_1,  0x26514e33      },
-	{       XFER_MW_DMA_0,  0x26514e97      },
-	
-	{       XFER_PIO_4,     0x06514e21      },
-	{       XFER_PIO_3,     0x06514e22      },
-	{       XFER_PIO_2,     0x06514e33      },
-	{       XFER_PIO_1,     0x06914e43      },
-	{       XFER_PIO_0,     0x06914e57      },
-	{       0,              0x06514e57      }
-};
-#endif
-
-struct chipset_bus_clock_list_entry fifty_base_hpt370[] = {
-	{       XFER_UDMA_5,    0x12848242      },
-	{       XFER_UDMA_4,    0x12ac8242      },
-	{       XFER_UDMA_3,    0x128c8242      },
-	{       XFER_UDMA_2,    0x120c8242      },
-	{       XFER_UDMA_1,    0x12148254      },
-	{       XFER_UDMA_0,    0x121882ea      },
-
-	{       XFER_MW_DMA_2,  0x22808242      },
-	{       XFER_MW_DMA_1,  0x22808254      },
-	{       XFER_MW_DMA_0,  0x228082ea      },
-
-	{       XFER_PIO_4,     0x0a81f442      },
-	{       XFER_PIO_3,     0x0a81f443      },
-	{       XFER_PIO_2,     0x0a81f454      },
-	{       XFER_PIO_1,     0x0ac1f465      },
-	{       XFER_PIO_0,     0x0ac1f48a      },
-	{       0,              0x0ac1f48a      }
-};
-
-#define HPT366_DEBUG_DRIVE_INFO		0
-#define HPT370_ALLOW_ATA100_5		1
-#define HPT366_ALLOW_ATA66_4		1
-#define HPT366_ALLOW_ATA66_3		1
-#define HPT366_MAX_DEVS			8
-
-#define F_LOW_PCI_33      0x23
-#define F_LOW_PCI_40      0x29
-#define F_LOW_PCI_50      0x2d
-#define F_LOW_PCI_66      0x42
-
-static struct pci_dev *hpt_devs[HPT366_MAX_DEVS];
-static int n_hpt_devs;
-
-static unsigned int pci_rev_check_hpt3xx(struct pci_dev *dev);
-static unsigned int pci_rev2_check_hpt3xx(struct pci_dev *dev);
-byte hpt366_proc = 0;
-byte hpt363_shared_irq;
-byte hpt363_shared_pin;
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
-static int hpt366_get_info(char *, char **, off_t, int);
-extern int (*hpt366_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-extern char *ide_media_verbose(ide_drive_t *);
-
-static int hpt366_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p	= buffer;
-	char *chipset_nums[] = {"366", "366", "368", "370", "370A"};
-	int i;
-
-	p += sprintf(p, "\n                             "
-		"HighPoint HPT366/368/370\n");
-	for (i = 0; i < n_hpt_devs; i++) {
-		struct pci_dev *dev = hpt_devs[i];
-		unsigned long iobase = dev->resource[4].start;
-		u32 class_rev;
-		u8 c0, c1;
-
-		pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-		class_rev &= 0xff;
-
-		p += sprintf(p, "\nController: %d\n", i);
-		p += sprintf(p, "Chipset: HPT%s\n", chipset_nums[class_rev]);
-		p += sprintf(p, "--------------- Primary Channel "
-				"--------------- Secondary Channel "
-				"--------------\n");
-
-		/* get the bus master status registers */
-		c0 = inb_p(iobase + 0x2);
-		c1 = inb_p(iobase + 0xa);
-		p += sprintf(p, "Enabled:        %s"
-				"                             %s\n",
-			(c0 & 0x80) ? "no" : "yes",
-			(c1 & 0x80) ? "no" : "yes");
-
-		if (pci_rev_check_hpt3xx(dev)) {
-			u8 cbl;
-			cbl = inb_p(iobase + 0x7b);
-			outb_p(cbl | 1, iobase + 0x7b);
-			outb_p(cbl & ~1, iobase + 0x7b);
-			cbl = inb_p(iobase + 0x7a);
-			p += sprintf(p, "Cable:          ATA-%d"
-					"                          ATA-%d\n",
-				(cbl & 0x02) ? 33 : 66,
-				(cbl & 0x01) ? 33 : 66);
-			p += sprintf(p, "\n");
-		}
-
-		p += sprintf(p, "--------------- drive0 --------- drive1 "
-				"------- drive0 ---------- drive1 -------\n");
-		p += sprintf(p, "DMA capable:    %s              %s" 
-				"            %s               %s\n",
-			(c0 & 0x20) ? "yes" : "no ", 
-			(c0 & 0x40) ? "yes" : "no ",
-			(c1 & 0x20) ? "yes" : "no ", 
-			(c1 & 0x40) ? "yes" : "no ");
-
-		{
-			u8 c2, c3;
-			/* older revs don't have these registers mapped 
-			 * into io space */
-			pci_read_config_byte(dev, 0x43, &c0);
-			pci_read_config_byte(dev, 0x47, &c1);
-			pci_read_config_byte(dev, 0x4b, &c2);
-			pci_read_config_byte(dev, 0x4f, &c3);
-
-			p += sprintf(p, "Mode:           %s             %s"
-					"           %s              %s\n",
-				(c0 & 0x10) ? "UDMA" : (c0 & 0x20) ? "DMA " : 
-					(c0 & 0x80) ? "PIO " : "off ",
-				(c1 & 0x10) ? "UDMA" : (c1 & 0x20) ? "DMA " :
-					(c1 & 0x80) ? "PIO " : "off ",
-				(c2 & 0x10) ? "UDMA" : (c2 & 0x20) ? "DMA " :
-					(c2 & 0x80) ? "PIO " : "off ",
-				(c3 & 0x10) ? "UDMA" : (c3 & 0x20) ? "DMA " :
-					(c3 & 0x80) ? "PIO " : "off ");
-		}
-	}
-	p += sprintf(p, "\n");
-	
-	return p-buffer;/* => must be less than 4k! */
-}
-#endif  /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-static unsigned int pci_rev_check_hpt3xx (struct pci_dev *dev)
-{
-	unsigned int class_rev;
-	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;
-	return ((int) (class_rev > 0x02) ? 1 : 0);
-}
-
-static unsigned int pci_rev2_check_hpt3xx (struct pci_dev *dev)
-{
-	unsigned int class_rev;
-	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;
-	return ((int) (class_rev > 0x01) ? 1 : 0);
-}
-
-static int check_in_drive_lists (ide_drive_t *drive, const char **list)
-{
-	struct hd_driveid *id = drive->id;
-
-	if (quirk_drives == list) {
-		while (*list) {
-			if (strstr(id->model, *list++)) {
-				return 1;
-			}
-		}
-	} else {
-		while (*list) {
-			if (!strcmp(*list++,id->model)) {
-				return 1;
-			}
-		}
-	}
-	return 0;
-}
-
-static unsigned int pci_bus_clock_list (byte speed, struct chipset_bus_clock_list_entry * chipset_table)
-{
-	for ( ; chipset_table->xfer_speed ; chipset_table++)
-		if (chipset_table->xfer_speed == speed) {
-			return chipset_table->chipset_settings;
-		}
-	return chipset_table->chipset_settings;
-}
-
-static void hpt366_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	byte regtime		= (drive->select.b.unit & 0x01) ? 0x44 : 0x40;
-	byte regfast		= (HWIF(drive)->channel) ? 0x55 : 0x51;
-			/*
-			 * since the channel is always 0 it does not matter.
-			 */
-
-	unsigned int reg1	= 0;
-	unsigned int reg2	= 0;
-	byte drive_fast		= 0;
-
-	/*
-	 * Disable the "fast interrupt" prediction. 
-	 */
-	pci_read_config_byte(HWIF(drive)->pci_dev, regfast, &drive_fast);
-	if (drive_fast & 0x02)
-		pci_write_config_byte(HWIF(drive)->pci_dev, regfast, drive_fast & ~0x20);
-
-	pci_read_config_dword(HWIF(drive)->pci_dev, regtime, &reg1);
-	/* detect bus speed by looking at control reg timing: */
-	switch((reg1 >> 8) & 7) {
-		case 5:
-			reg2 = pci_bus_clock_list(speed, forty_base);
-			break;
-		case 9:
-			reg2 = pci_bus_clock_list(speed, twenty_five_base);
-			break;
-		default:
-		case 7:
-			reg2 = pci_bus_clock_list(speed, thirty_three_base);
-			break;
-	}
-#if 0
-	/* this is a nice idea ... */
-	list_conf = pci_bus_clock_list(speed,
-				       (struct chipset_bus_clock_list_entry *)
-				       dev->sysdata);
-#endif
-	/*
-	 * Disable on-chip PIO FIFO/buffer (to avoid problems handling I/O errors later)
-	 */
-	if (speed >= XFER_MW_DMA_0) {
-		reg2 = (reg2 & ~0xc0000000) | (reg1 & 0xc0000000);
-	} else {
-		reg2 = (reg2 & ~0x30070000) | (reg1 & 0x30070000);
-	}	
-	reg2 &= ~0x80000000;
-
-	pci_write_config_dword(HWIF(drive)->pci_dev, regtime, reg2);
-}
-
-static void hpt370_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	byte regfast		= (HWIF(drive)->channel) ? 0x55 : 0x51;
-	unsigned int list_conf	= 0;
-	unsigned int drive_conf = 0;
-	unsigned int conf_mask	= (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
-	byte drive_pci		= 0x40 + (drive->dn * 4);
-	byte new_fast, drive_fast		= 0;
-	struct pci_dev *dev 	= HWIF(drive)->pci_dev;
-
-	/*
-	 * Disable the "fast interrupt" prediction.
-	 * don't holdoff on interrupts. (== 0x01 despite what the docs say) 
-	 */
-	pci_read_config_byte(dev, regfast, &drive_fast);
-	new_fast = drive_fast;
-	if (new_fast & 0x02)
-		new_fast &= ~0x02;
-
-#ifdef HPT_DELAY_INTERRUPT
-	if (new_fast & 0x01)
-		new_fast &= ~0x01;
-#else
-	if ((new_fast & 0x01) == 0)
-		new_fast |= 0x01;
-#endif
-	if (new_fast != drive_fast)
-		pci_write_config_byte(HWIF(drive)->pci_dev, regfast, new_fast);
-
-	list_conf = pci_bus_clock_list(speed, 
-				       (struct chipset_bus_clock_list_entry *)
-				       dev->sysdata);
-
-	pci_read_config_dword(dev, drive_pci, &drive_conf);
-	list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
-	
-	if (speed < XFER_MW_DMA_0) {
-		list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
-	}
-
-	pci_write_config_dword(dev, drive_pci, list_conf);
-}
-
-static int hpt3xx_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))
-		return -1;
-
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-
-	if (pci_rev_check_hpt3xx(HWIF(drive)->pci_dev)) {
-		hpt370_tune_chipset(drive, speed);
-        } else {
-                hpt366_tune_chipset(drive, speed);
-        }
-	drive->current_speed = speed;
-	return ((int) ide_config_drive_speed(drive, speed));
-}
-
-static void config_chipset_for_pio (ide_drive_t *drive)
-{
-	unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
-	unsigned short xfer_pio = drive->id->eide_pio_modes;
-	byte	timing, speed, pio;
-
-	pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
-
-	if (xfer_pio> 4)
-		xfer_pio = 0;
-
-	if (drive->id->eide_pio_iordy > 0) {
-		for (xfer_pio = 5;
-			xfer_pio>0 &&
-			drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
-			xfer_pio--);
-	} else {
-		xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
-			   (drive->id->eide_pio_modes & 2) ? 0x04 :
-			   (drive->id->eide_pio_modes & 1) ? 0x03 :
-			   (drive->id->tPIO & 2) ? 0x02 :
-			   (drive->id->tPIO & 1) ? 0x01 : xfer_pio;
-	}
-
-	timing = (xfer_pio >= pio) ? xfer_pio : pio;
-
-	switch(timing) {
-		case 4: speed = XFER_PIO_4;break;
-		case 3: speed = XFER_PIO_3;break;
-		case 2: speed = XFER_PIO_2;break;
-		case 1: speed = XFER_PIO_1;break;
-		default:
-			speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW;
-			break;
-	}
-	(void) hpt3xx_tune_chipset(drive, speed);
-}
-
-static void hpt3xx_tune_drive (ide_drive_t *drive, byte pio)
-{
-	byte speed;
-	switch(pio) {
-		case 4:		speed = XFER_PIO_4;break;
-		case 3:		speed = XFER_PIO_3;break;
-		case 2:		speed = XFER_PIO_2;break;
-		case 1:		speed = XFER_PIO_1;break;
-		default:	speed = XFER_PIO_0;break;
-	}
-	(void) hpt3xx_tune_chipset(drive, speed);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-/*
- * This allows the configuration of ide_pci chipset registers
- * for cards that learn about the drive's UDMA, DMA, PIO capabilities
- * after the drive is reported by the OS.  Initally for designed for
- * HPT366 UDMA chipset by HighPoint|Triones Technologies, Inc.
- *
- * check_in_drive_lists(drive, bad_ata66_4)
- * check_in_drive_lists(drive, bad_ata66_3)
- * check_in_drive_lists(drive, bad_ata33)
- *
- */
-static int config_chipset_for_dma (ide_drive_t *drive)
-{
-	struct hd_driveid *id	= drive->id;
-	byte speed		= 0x00;
-	byte ultra66		= eighty_ninty_three(drive);
-	int  rval;
-
-	if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))
-		return ((int) ide_dma_off_quietly);
-
-	if ((id->dma_ultra & 0x0020) &&
-	    (!check_in_drive_lists(drive, bad_ata100_5)) &&
-	    (HPT370_ALLOW_ATA100_5) &&
-	    (pci_rev_check_hpt3xx(HWIF(drive)->pci_dev)) &&
-	    (ultra66)) {
-		speed = XFER_UDMA_5;
-	} else if ((id->dma_ultra & 0x0010) &&
-		   (!check_in_drive_lists(drive, bad_ata66_4)) &&
-		   (HPT366_ALLOW_ATA66_4) &&
-		   (ultra66)) {
-		speed = XFER_UDMA_4;
-	} else if ((id->dma_ultra & 0x0008) &&
-		   (!check_in_drive_lists(drive, bad_ata66_3)) &&
-		   (HPT366_ALLOW_ATA66_3) &&
-		   (ultra66)) {
-		speed = XFER_UDMA_3;
-	} else if (id->dma_ultra && (!check_in_drive_lists(drive, bad_ata33))) {
-		if (id->dma_ultra & 0x0004) {
-			speed = XFER_UDMA_2;
-		} else if (id->dma_ultra & 0x0002) {
-			speed = XFER_UDMA_1;
-		} else if (id->dma_ultra & 0x0001) {
-			speed = XFER_UDMA_0;
-		}
-	} else if (id->dma_mword & 0x0004) {
-		speed = XFER_MW_DMA_2;
-	} else if (id->dma_mword & 0x0002) {
-		speed = XFER_MW_DMA_1;
-	} else if (id->dma_mword & 0x0001) {
-		speed = XFER_MW_DMA_0;
-	} else {
-		return ((int) ide_dma_off_quietly);
-	}
-
-	(void) hpt3xx_tune_chipset(drive, speed);
-
-	rval = (int)(	((id->dma_ultra >> 11) & 7) ? ide_dma_on :
-			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-			((id->dma_mword >> 8) & 7) ? ide_dma_on :
-						     ide_dma_off_quietly);
-	return rval;
-}
-
-int hpt3xx_quirkproc (ide_drive_t *drive)
-{
-	return ((int) check_in_drive_lists(drive, quirk_drives));
-}
-
-void hpt3xx_intrproc (ide_drive_t *drive)
-{
-	if (drive->quirk_list) {
-		/* drives in the quirk_list may not like intr setups/cleanups */
-	} else {
-		OUT_BYTE((drive)->ctl|2, HWIF(drive)->io_ports[IDE_CONTROL_OFFSET]);
-	}
-}
-
-void hpt3xx_maskproc (ide_drive_t *drive, int mask)
-{
-	if (drive->quirk_list) {
-		if (pci_rev_check_hpt3xx(HWIF(drive)->pci_dev)) {
-			byte reg5a = 0;
-			pci_read_config_byte(HWIF(drive)->pci_dev, 0x5a, &reg5a);
-			if (((reg5a & 0x10) >> 4) != mask)
-				pci_write_config_byte(HWIF(drive)->pci_dev, 0x5a, mask ? (reg5a | 0x10) : (reg5a & ~0x10));
-		} else {
-			if (mask) {
-				disable_irq(HWIF(drive)->irq);
-			} else {
-				enable_irq(HWIF(drive)->irq);
-			}
-		}
-	} else {
-		if (IDE_CONTROL_REG)
-			OUT_BYTE(mask ? (drive->ctl | 2) : (drive->ctl & ~2), IDE_CONTROL_REG);
-	}
-}
-
-static int config_drive_xfer_rate (ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-	ide_dma_action_t dma_func = ide_dma_on;
-
-	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x002F) {
-				/* Force if Capable UltraDMA */
-				dma_func = config_chipset_for_dma(drive);
-				if ((id->field_valid & 2) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if (id->dma_mword & 0x0007) {
-				/* Force if Capable regular DMA modes */
-				dma_func = config_chipset_for_dma(drive);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			dma_func = config_chipset_for_dma(drive);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-
-		config_chipset_for_pio(drive);
-	}
-	return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-/*
- * hpt366_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
- *
- * This is specific to the HPT366 UDMA bios chipset
- * by HighPoint|Triones Technologies, Inc.
- */
-int hpt366_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	byte reg50h = 0, reg52h = 0, reg5ah = 0, dma_stat = 0;
-	unsigned long dma_base = HWIF(drive)->dma_base;
-
-	switch (func) {
-		case ide_dma_check:
-			return config_drive_xfer_rate(drive);
-		case ide_dma_test_irq:	/* returns 1 if dma irq issued, 0 otherwise */
-			dma_stat = inb(dma_base+2);
-			return (dma_stat & 4) == 4;	/* return 1 if INTR asserted */
-		case ide_dma_lostirq:
-			pci_read_config_byte(HWIF(drive)->pci_dev, 0x50, &reg50h);
-			pci_read_config_byte(HWIF(drive)->pci_dev, 0x52, &reg52h);
-			pci_read_config_byte(HWIF(drive)->pci_dev, 0x5a, &reg5ah);
-			printk("%s: (%s)  reg50h=0x%02x, reg52h=0x%02x, reg5ah=0x%02x\n",
-				drive->name,
-				ide_dmafunc_verbose(func),
-				reg50h, reg52h, reg5ah);
-			if (reg5ah & 0x10)
-				pci_write_config_byte(HWIF(drive)->pci_dev, 0x5a, reg5ah & ~0x10);
-			/* fall through to a reset */
-#if 0
-		case ide_dma_begin:
-		case ide_dma_end:
-			/* reset the chips state over and over.. */
-			pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, 0x13);
-#endif
-			break;
-		case ide_dma_timeout:
-		default:
-			break;
-	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
-}
-
-int hpt370_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	unsigned long dma_base = hwif->dma_base;
-	byte regstate = hwif->channel ? 0x54 : 0x50;
-	byte reginfo = hwif->channel ? 0x56 : 0x52;
-	byte dma_stat;
-
-	switch (func) {
-		case ide_dma_check:
-			return config_drive_xfer_rate(drive);
-		case ide_dma_test_irq:	/* returns 1 if dma irq issued, 0 otherwise */
-			dma_stat = inb(dma_base+2);
-			return (dma_stat & 4) == 4;	/* return 1 if INTR asserted */
-
-		case ide_dma_end:
-			dma_stat = inb(dma_base + 2);
-			if (dma_stat & 0x01) {
-				udelay(20); /* wait a little */
-				dma_stat = inb(dma_base + 2);
-			}
-			if ((dma_stat & 0x01) == 0) 
-				break;
-
-			func = ide_dma_timeout;
-			/* fallthrough */
-
-		case ide_dma_timeout:
-		case ide_dma_lostirq:
-			pci_read_config_byte(hwif->pci_dev, reginfo, 
-					     &dma_stat); 
-			printk("%s: %d bytes in FIFO\n", drive->name, 
-			       dma_stat);
-			pci_write_config_byte(hwif->pci_dev, regstate, 0x37);
-			udelay(10);
-			dma_stat = inb(dma_base);
-			outb(dma_stat & ~0x1, dma_base); /* stop dma */
-			dma_stat = inb(dma_base + 2); 
-			outb(dma_stat | 0x6, dma_base+2); /* clear errors */
-			/* fallthrough */
-
-#ifdef HPT_RESET_STATE_ENGINE
-	        case ide_dma_begin:
-#endif
-			pci_write_config_byte(hwif->pci_dev, regstate, 0x37);
-			udelay(10);
-			break;
-
-		default:
-			break;
-	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-/*
- * Since SUN Cobalt is attempting to do this operation, I should disclose
- * this has been a long time ago Thu Jul 27 16:40:57 2000 was the patch date
- * HOTSWAP ATA Infrastructure.
- */
-void hpt3xx_reset (ide_drive_t *drive)
-{
-#if 0
-	unsigned long high_16	= pci_resource_start(HWIF(drive)->pci_dev, 4);
-	byte reset		= (HWIF(drive)->channel) ? 0x80 : 0x40;
-	byte reg59h		= 0;
-
-	pci_read_config_byte(HWIF(drive)->pci_dev, 0x59, &reg59h);
-	pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h|reset);
-	pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h);
-#endif
-}
-
-static int hpt3xx_tristate (ide_drive_t * drive, int state)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte reset		= (hwif->channel) ? 0x80 : 0x40;
-	byte state_reg		= (hwif->channel) ? 0x57 : 0x53;
-	byte reg59h		= 0;
-	byte regXXh		= 0;
-
-	if (!hwif)
-		return -EINVAL;
-
-//	hwif->bus_state = state;
-
-	pci_read_config_byte(dev, 0x59, &reg59h);
-	pci_read_config_byte(dev, state_reg, &regXXh);
-
-	if (state) {
-		(void) ide_do_reset(drive);
-		pci_write_config_byte(dev, state_reg, regXXh|0x80);
-		pci_write_config_byte(dev, 0x59, reg59h|reset);
-	} else {
-		pci_write_config_byte(dev, 0x59, reg59h & ~(reset));
-		pci_write_config_byte(dev, state_reg, regXXh & ~(0x80));
-		(void) ide_do_reset(drive);
-	}
-	return 0;
-}
-
-/* 
- * set/get power state for a drive.
- * turning the power off does the following things:
- *   1) soft-reset the drive
- *   2) tri-states the ide bus
- *
- * when we turn things back on, we need to re-initialize things.
- */
-#define TRISTATE_BIT  0x8000
-static int hpt370_busproc(ide_drive_t * drive, int state)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	byte tristate, resetmask, bus_reg;
-	u16 tri_reg;
-
-	if (!hwif)
-		return -EINVAL;
-
-	hwif->bus_state = state;
-
-	if (hwif->channel) { 
-		/* secondary channel */
-		tristate = 0x56;
-		resetmask = 0x80; 
-	} else { 
-		/* primary channel */
-		tristate = 0x52;
-		resetmask = 0x40;
-	}
-
-	/* grab status */
-	pci_read_config_word(hwif->pci_dev, tristate, &tri_reg);
-	pci_read_config_byte(hwif->pci_dev, 0x59, &bus_reg);
-
-	/* set the state. we don't set it if we don't need to do so.
-	 * make sure that the drive knows that it has failed if it's off */
-	switch (state) {
-	case BUSSTATE_ON:
-		hwif->drives[0].failures = 0;
-		hwif->drives[1].failures = 0;
-		if ((bus_reg & resetmask) == 0)
-			return 0;
-		tri_reg &= ~TRISTATE_BIT;
-		bus_reg &= ~resetmask;
-		break;
-	case BUSSTATE_OFF:
-		hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
-		hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
-		if ((tri_reg & TRISTATE_BIT) == 0 && (bus_reg & resetmask))
-			return 0;
-		tri_reg &= ~TRISTATE_BIT;
-		bus_reg |= resetmask;
-		break;
-	case BUSSTATE_TRISTATE:
-		hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
-		hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
-		if ((tri_reg & TRISTATE_BIT) && (bus_reg & resetmask))
-			return 0;
-		tri_reg |= TRISTATE_BIT;
-		bus_reg |= resetmask;
-		break;
-	}
-	pci_write_config_byte(hwif->pci_dev, 0x59, bus_reg);
-	pci_write_config_word(hwif->pci_dev, tristate, tri_reg);
-
-	return 0;
-}
-
-static void __init init_hpt370(struct pci_dev *dev)
-{
-	int adjust, i;
-	u16 freq;
-	u32 pll;
-	byte reg5bh;
-
-	/*
-	 * default to pci clock. make sure MA15/16 are set to output
-	 * to prevent drives having problems with 40-pin cables.
-	 */
-	pci_write_config_byte(dev, 0x5b, 0x23);
-
-	/*
-	 * set up the PLL. we need to adjust it so that it's stable. 
-	 * freq = Tpll * 192 / Tpci
-	 */
-	pci_read_config_word(dev, 0x78, &freq);
-	freq &= 0x1FF;
-	if (freq < 0x9c) {
-		pll = F_LOW_PCI_33;
-		dev->sysdata = (void *) thirty_three_base_hpt370;
-		printk("HPT370: using 33MHz PCI clock\n");
-	} else if (freq < 0xb0) {
-		pll = F_LOW_PCI_40;
-	} else if (freq < 0xc8) {
-		pll = F_LOW_PCI_50;
-		dev->sysdata = (void *) fifty_base_hpt370;
-		printk("HPT370: using 50MHz PCI clock\n");
-	} else {
-		pll = F_LOW_PCI_66;
-		dev->sysdata = (void *) sixty_six_base_hpt370;
-		printk("HPT370: using 66MHz PCI clock\n");
-	}
-	
-	/*
-	 * only try the pll if we don't have a table for the clock
-	 * speed that we're running at. NOTE: the internal PLL will
-	 * result in slow reads when using a 33MHz PCI clock. we also
-	 * don't like to use the PLL because it will cause glitches
-	 * on PRST/SRST when the HPT state engine gets reset.
-	 */
-	if (dev->sysdata) 
-		goto init_hpt370_done;
-	
-	/*
-	 * adjust PLL based upon PCI clock, enable it, and wait for
-	 * stabilization.
-	 */
-	adjust = 0;
-	freq = (pll < F_LOW_PCI_50) ? 2 : 4;
-	while (adjust++ < 6) {
-		pci_write_config_dword(dev, 0x5c, (freq + pll) << 16 |
-				       pll | 0x100);
-
-		/* wait for clock stabilization */
-		for (i = 0; i < 0x50000; i++) {
-			pci_read_config_byte(dev, 0x5b, &reg5bh);
-			if (reg5bh & 0x80) {
-				/* spin looking for the clock to destabilize */
-				for (i = 0; i < 0x1000; ++i) {
-					pci_read_config_byte(dev, 0x5b, 
-							     &reg5bh);
-					if ((reg5bh & 0x80) == 0)
-						goto pll_recal;
-				}
-				pci_read_config_dword(dev, 0x5c, &pll);
-				pci_write_config_dword(dev, 0x5c, 
-						       pll & ~0x100);
-				pci_write_config_byte(dev, 0x5b, 0x21);
-				dev->sysdata = (void *) fifty_base_hpt370;
-				printk("HPT370: using 50MHz internal PLL\n");
-				goto init_hpt370_done;
-			}
-		}
-pll_recal:
-		if (adjust & 1)
-			pll -= (adjust >> 1);
-		else
-			pll += (adjust >> 1);
-	} 
-
-init_hpt370_done:
-	/* reset state engine */
-	pci_write_config_byte(dev, 0x50, 0x37); 
-	pci_write_config_byte(dev, 0x54, 0x37); 
-	udelay(100);
-}
-
-unsigned int __init pci_init_hpt366 (struct pci_dev *dev, const char *name)
-{
-	byte test = 0;
-
-	if (dev->resource[PCI_ROM_RESOURCE].start)
-		pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
-
-	pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &test);
-	if (test != (L1_CACHE_BYTES / 4))
-		pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
-
-	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &test);
-	if (test != 0x78)
-		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
-
-	pci_read_config_byte(dev, PCI_MIN_GNT, &test);
-	if (test != 0x08)
-		pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
-
-	pci_read_config_byte(dev, PCI_MAX_LAT, &test);
-	if (test != 0x08)
-		pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
-
-	if (pci_rev_check_hpt3xx(dev)) {
-		init_hpt370(dev);
-		hpt_devs[n_hpt_devs++] = dev;
-	} else {
-		hpt_devs[n_hpt_devs++] = dev;
-	}
-	
-#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!hpt366_proc) {
-		hpt366_proc = 1;
-		hpt366_display_info = &hpt366_get_info;
-	}
-#endif /* DISPLAY_HPT366_TIMINGS && CONFIG_PROC_FS */
-
-	return dev->irq;
-}
-
-unsigned int __init ata66_hpt366 (ide_hwif_t *hwif)
-{
-	byte ata66	= 0;
-	byte regmask	= (hwif->channel) ? 0x01 : 0x02;
-
-	pci_read_config_byte(hwif->pci_dev, 0x5a, &ata66);
-#ifdef DEBUG
-	printk("HPT366: reg5ah=0x%02x ATA-%s Cable Port%d\n",
-		ata66, (ata66 & regmask) ? "33" : "66",
-		PCI_FUNC(hwif->pci_dev->devfn));
-#endif /* DEBUG */
-	return ((ata66 & regmask) ? 0 : 1);
-}
-
-void __init ide_init_hpt366 (ide_hwif_t *hwif)
-{
-	int hpt_rev;
-
-	hwif->tuneproc	= &hpt3xx_tune_drive;
-	hwif->speedproc	= &hpt3xx_tune_chipset;
-	hwif->quirkproc	= &hpt3xx_quirkproc;
-	hwif->intrproc	= &hpt3xx_intrproc;
-	hwif->maskproc	= &hpt3xx_maskproc;
-
-#ifdef HPT_SERIALIZE_IO
-	/* serialize access to this device */
-	if (hwif->mate)
-		hwif->serialized = hwif->mate->serialized = 1;
-#endif
-
-	hpt_rev = pci_rev_check_hpt3xx(hwif->pci_dev);
-	if (hpt_rev) {
-		/* set up ioctl for power status. note: power affects both
-		 * drives on each channel */
-		hwif->busproc   = &hpt370_busproc;
-	}
-
-	if (pci_rev2_check_hpt3xx(hwif->pci_dev)) {
-		/* do nothing now but will split device types */
-		hwif->resetproc = &hpt3xx_reset;
-/*
- * don't do until we can parse out the cobalt box argh ...
- *		hwif->busproc   = &hpt3xx_tristate;
- */
-	}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (hwif->dma_base) {
-		if (hpt_rev) {
-			byte reg5ah = 0;
-			pci_read_config_byte(hwif->pci_dev, 0x5a, &reg5ah);
-			if (reg5ah & 0x10)	/* interrupt force enable */
-				pci_write_config_byte(hwif->pci_dev, 0x5a, reg5ah & ~0x10);
-			hwif->dmaproc = &hpt370_dmaproc;
-		} else {
-			hwif->dmaproc = &hpt366_dmaproc;
-		}
-		if (!noautodma)
-			hwif->autodma = 1;
-		else
-			hwif->autodma = 0;
-	} else {
-		hwif->autodma = 0;
-		hwif->drives[0].autotune = 1;
-		hwif->drives[1].autotune = 1;
-	}
-#else /* !CONFIG_BLK_DEV_IDEDMA */
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-	hwif->autodma = 0;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-}
-
-void __init ide_dmacapable_hpt366 (ide_hwif_t *hwif, unsigned long dmabase)
-{
-	byte masterdma = 0, slavedma = 0;
-	byte dma_new = 0, dma_old = inb(dmabase+2);
-	byte primary	= hwif->channel ? 0x4b : 0x43;
-	byte secondary	= hwif->channel ? 0x4f : 0x47;
-	unsigned long flags;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-
-	dma_new = dma_old;
-	pci_read_config_byte(hwif->pci_dev, primary, &masterdma);
-	pci_read_config_byte(hwif->pci_dev, secondary, &slavedma);
-
-	if (masterdma & 0x30)	dma_new |= 0x20;
-	if (slavedma & 0x30)	dma_new |= 0x40;
-	if (dma_new != dma_old) outb(dma_new, dmabase+2);
-
-	__restore_flags(flags);	/* local CPU only */
-
-	ide_setup_dma(hwif, dmabase, 8);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/hptraid.c linux-2.4.21-pre6/drivers/ide/hptraid.c
--- linux-2.4.20/drivers/ide/hptraid.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/hptraid.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,436 +0,0 @@
-/*
-   hptraid.c  Copyright (C) 2001 Red Hat, Inc. 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, or (at your option)
-   any later version.
-   
-   You should have received a copy of the GNU General Public License
-   (for example /usr/src/linux/COPYING); if not, write to the Free
-   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
-   
-   Authors: 	Arjan van de Ven <arjanv@redhat.com>
-
-   Based on work
-   	Copyleft  (C) 2001 by Wilfried Weissmann <wweissmann@gmx.at>
-	Copyright (C) 1994-96 Marc ZYNGIER <zyngier@ufr-info-p7.ibp.fr>
-   Based on work done by Søren Schmidt for FreeBSD
-
-   
-*/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/kernel.h>
-#include <linux/blkdev.h>
-#include <linux/blkpg.h>
-#include <linux/genhd.h>
-#include <linux/ioctl.h>
-
-#include <linux/ide.h>
-#include <asm/uaccess.h>
-
-#include "ataraid.h"
-
-static int hptraid_open(struct inode * inode, struct file * filp);
-static int hptraid_release(struct inode * inode, struct file * filp);
-static int hptraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
-static int hptraid_make_request (request_queue_t *q, int rw, struct buffer_head * bh);
-
-
-
-struct hptdisk {
-	kdev_t	device;
-	unsigned long sectors;
-	struct block_device *bdev;
-};
-
-struct hptraid {
-	unsigned int stride;
-	unsigned int disks;
-	unsigned long sectors;
-	struct geom geom;
-	
-	struct hptdisk disk[8];
-	
-	unsigned long cutoff[8];
-	unsigned int cutoff_disks[8];	
-};
-
-static struct raid_device_operations hptraid_ops = {
-	open:                   hptraid_open,
-	release:                hptraid_release,
-	ioctl:			hptraid_ioctl,
-	make_request:		hptraid_make_request
-};
-
-static struct hptraid raid[16];
-
-static int hptraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-	unsigned int minor;
-	unsigned char val;
-	unsigned long sectors;
-	
-	if (!inode || !inode->i_rdev) 	
-		return -EINVAL;
-
-	minor = MINOR(inode->i_rdev)>>SHIFT;
-	
-	switch (cmd) {
-         	case BLKGETSIZE:   /* Return device size */
-			if (!arg)  return -EINVAL;
-			sectors = ataraid_gendisk.part[MINOR(inode->i_rdev)].nr_sects;
-			if (MINOR(inode->i_rdev)&15)
-				return put_user(sectors, (unsigned long *) arg);
-			return put_user(raid[minor].sectors , (unsigned long *) arg);
-			break;
-			
-
-		case HDIO_GETGEO:
-		{
-			struct hd_geometry *loc = (struct hd_geometry *) arg;
-			unsigned short bios_cyl;
-			
-			if (!loc) return -EINVAL;
-			val = 255;
-			if (put_user(val, (byte *) &loc->heads)) return -EFAULT;
-			val=63;
-			if (put_user(val, (byte *) &loc->sectors)) return -EFAULT;
-			bios_cyl = raid[minor].sectors/63/255;
-			if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT;
-			if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
-				(unsigned long *) &loc->start)) return -EFAULT;
-			return 0;
-		}
-
-		case HDIO_GETGEO_BIG:
-		{
-			struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
-			unsigned int bios_cyl;
-			if (!loc) return -EINVAL;
-			val = 255;
-			if (put_user(val, (byte *) &loc->heads)) return -EFAULT;
-			val = 63;
-			if (put_user(val, (byte *) &loc->sectors)) return -EFAULT;
-			bios_cyl = raid[minor].sectors/63/255;
-			if (put_user(bios_cyl, (unsigned int *) &loc->cylinders)) return -EFAULT;
-			if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
-				(unsigned long *) &loc->start)) return -EFAULT;
-			return 0;
-		}
-			
-		default:
-			return blk_ioctl(inode->i_rdev, cmd, arg);
-	};
-
-	return 0;
-}
-
-
-static int hptraid_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
-{
-	unsigned long rsect;
-	unsigned long rsect_left,rsect_accum = 0;
-	unsigned long block;
-	unsigned int disk=0,real_disk=0;
-	int i;
-	int device;
-	struct hptraid *thisraid;
-
-	rsect = bh->b_rsector;
-
-	/* Ok. We need to modify this sector number to a new disk + new sector number. 
-	 * If there are disks of different sizes, this gets tricky. 
-	 * Example with 3 disks (1Gb, 4Gb and 5 GB):
-	 * The first 3 Gb of the "RAID" are evenly spread over the 3 disks.
-	 * Then things get interesting. The next 2Gb (RAID view) are spread across disk 2 and 3
-	 * and the last 1Gb is disk 3 only.
-	 *
-	 * the way this is solved is like this: We have a list of "cutoff" points where everytime
-	 * a disk falls out of the "higher" count, we mark the max sector. So once we pass a cutoff
-	 * point, we have to divide by one less.
-	 */
-	
-	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
-	thisraid = &raid[device];
-	if (thisraid->stride==0)
-		thisraid->stride=1;
-
-	/* Partitions need adding of the start sector of the partition to the requested sector */
-	
-	rsect += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect;
-
-	/* Woops we need to split the request to avoid crossing a stride barrier */
-	if ((rsect/thisraid->stride) != ((rsect+(bh->b_size/512)-1)/thisraid->stride)) {
-		return -1;
-	}
-			
-	rsect_left = rsect;
-	
-	for (i=0;i<8;i++) {
-		if (thisraid->cutoff_disks[i]==0)
-			break;
-		if (rsect > thisraid->cutoff[i]) {
-			/* we're in the wrong area so far */
-			rsect_left -= thisraid->cutoff[i];
-			rsect_accum += thisraid->cutoff[i]/thisraid->cutoff_disks[i];
-		} else {
-			block = rsect_left / thisraid->stride;
-			disk = block % thisraid->cutoff_disks[i];
-			block = (block / thisraid->cutoff_disks[i]) * thisraid->stride;
-			rsect = rsect_accum + (rsect_left % thisraid->stride) + block;
-			break;
-		}
-	}
-	
-	for (i=0;i<8;i++) {
-		if ((disk==0) && (thisraid->disk[i].sectors > rsect_accum)) {
-			real_disk = i;
-			break;
-		}
-		if ((disk>0) && (thisraid->disk[i].sectors >= rsect_accum)) {
-			disk--;
-		}
-		
-	}
-	disk = real_disk;
-	
-	/* All but the first disk have a 10 sector offset */
-	if (i>0)
-		rsect+=10;
-		
-	
-	/*
-	 * The new BH_Lock semantics in ll_rw_blk.c guarantee that this
-	 * is the only IO operation happening on this bh.
-	 */
-	 
-	bh->b_rdev = thisraid->disk[disk].device;
-	bh->b_rsector = rsect;
-
-	/*
-	 * Let the main block layer submit the IO and resolve recursion:
-	 */
-	return 1;
-}
-
-
-#include "hptraid.h"
-
-static int read_disk_sb (int major, int minor, unsigned char *buffer,int bufsize)
-{
-	int ret = -EINVAL;
-	struct buffer_head *bh = NULL;
-	kdev_t dev = MKDEV(major,minor);
-	
-	if (blksize_size[major]==NULL)	 /* device doesn't exist */
-		return -EINVAL;
-	
-
-	/* Superblock is at 4096+412 bytes */
-	set_blocksize (dev, 4096);
-	bh = bread (dev, 1, 4096);
-
-	
-	if (bh) {
-		memcpy (buffer, bh->b_data, bufsize);
-	} else {
-		printk(KERN_ERR "hptraid: Error reading superblock.\n");
-		goto abort;
-	}
-	ret = 0;
-abort:
-	if (bh)
-		brelse (bh);
-	return ret;
-}
-
-static unsigned long maxsectors (int major,int minor)
-{
-	unsigned long lba = 0;
-	kdev_t dev;
-	ide_drive_t *ideinfo;
-	
-	dev = MKDEV(major,minor);
-	ideinfo = get_info_ptr (dev);
-	if (ideinfo==NULL)
-		return 0;
-	
-	
-	/* first sector of the last cluster */
-	if (ideinfo->head==0) 
-		return 0;
-	if (ideinfo->sect==0)
-		return 0;
-	lba = (ideinfo->capacity);
-
-	return lba;
-}
-
-static void __init probedisk(int major, int minor,int device)
-{
-	int i;
-        struct highpoint_raid_conf *prom;
-	static unsigned char block[4096];
-	struct block_device *bdev;
-	
-	if (maxsectors(major,minor)==0)
-		return;
-	
-        if (read_disk_sb(major,minor,(unsigned char*)&block,sizeof(block)))
-        	return;
-                                                                                                                 
-        prom = (struct highpoint_raid_conf*)&block[512];
-                
-        if (prom->magic!=  0x5a7816f0)
-        	return;
-        if (prom->type) {
-        	printk(KERN_INFO "hptraid: only RAID0 is supported currently\n");
-        	return;
-        }
-
-	i = prom->disk_number;
-	if (i<0)
-		return;
-	if (i>8) 
-		return;
-
-	bdev = bdget(MKDEV(major,minor));
-	if (bdev && blkdev_get(bdev,FMODE_READ|FMODE_WRITE,0,BDEV_RAW) == 0) {
-        	int j=0;
-        	struct gendisk *gd;
-		raid[device].disk[i].bdev = bdev;
-        	/* This is supposed to prevent others from stealing our underlying disks */
-		/* now blank the /proc/partitions table for the wrong partition table,
-		   so that scripts don't accidentally mount it and crash the kernel */
-		 /* XXX: the 0 is an utter hack  --hch */
-		gd=get_gendisk(MKDEV(major, 0));
-		if (gd!=NULL) {
-			for (j=1+(minor<<gd->minor_shift);j<((minor+1)<<gd->minor_shift);j++) 
-				gd->part[j].nr_sects=0;					
-		}
-        }
-	raid[device].disk[i].device = MKDEV(major,minor);
-	raid[device].disk[i].sectors = maxsectors(major,minor);
-	raid[device].stride = (1<<prom->raid0_shift);
-	raid[device].disks = prom->raid_disks;
-	raid[device].sectors = prom->total_secs;
-			
-}
-
-static void __init fill_cutoff(int device)
-{
-	int i,j;
-	unsigned long smallest;
-	unsigned long bar;
-	int count;
-	
-	bar = 0;
-	for (i=0;i<8;i++) {
-		smallest = ~0;
-		for (j=0;j<8;j++) 
-			if ((raid[device].disk[j].sectors < smallest) && (raid[device].disk[j].sectors>bar))
-				smallest = raid[device].disk[j].sectors;
-		count = 0;
-		for (j=0;j<8;j++) 
-			if (raid[device].disk[j].sectors >= smallest)
-				count++;
-		
-		smallest = smallest * count;		
-		bar = smallest;
-		raid[device].cutoff[i] = smallest;
-		raid[device].cutoff_disks[i] = count;
-		
-	}
-}
-
-
-static __init int hptraid_init_one(int device)
-{
-	int i,count;
-
-	probedisk(IDE0_MAJOR,  0, device);
-	probedisk(IDE0_MAJOR, 64, device);
-	probedisk(IDE1_MAJOR,  0, device);
-	probedisk(IDE1_MAJOR, 64, device);
-	probedisk(IDE2_MAJOR,  0, device);
-	probedisk(IDE2_MAJOR, 64, device);
-	probedisk(IDE3_MAJOR,  0, device);
-	probedisk(IDE3_MAJOR, 64, device);
-	probedisk(IDE4_MAJOR,  0, device);
-	probedisk(IDE4_MAJOR, 64, device);
-	probedisk(IDE5_MAJOR,  0, device);
-	probedisk(IDE5_MAJOR, 64, device);
-
-	fill_cutoff(device);
-	
-	/* Initialize the gendisk structure */
-	
-	ataraid_register_disk(device,raid[device].sectors);
-
-	count=0;
-	printk(KERN_INFO "Highpoint HPT370 Softwareraid driver for linux version 0.01\n");
-		
-	for (i=0;i<8;i++) {
-		if (raid[device].disk[i].device!=0) {
-			printk(KERN_INFO "Drive %i is %li Mb \n",
-				i,raid[device].disk[i].sectors/2048);
-			count++;
-		}
-	}
-	if (count) {
-		printk(KERN_INFO "Raid array consists of %i drives. \n",count);
-		return 0;
-	} else {
-		printk(KERN_INFO "No raid array found\n");
-		return -ENODEV;
-	}
-	
-}
-
-static __init int hptraid_init(void)
-{
-	int retval,device;
-	
-	device=ataraid_get_device(&hptraid_ops);
-	if (device<0)
-		return -ENODEV;
-	retval = hptraid_init_one(device);
-	if (retval)
-		ataraid_release_device(device);
-	return retval;
-}
-
-static void __exit hptraid_exit (void)
-{
-	int i,device;
-	for (device = 0; device<16; device++) {
-		for (i=0;i<8;i++)  {
-			struct block_device *bdev = raid[device].disk[i].bdev;
-			raid[device].disk[i].bdev = NULL;
-			if (bdev)
-				blkdev_put(bdev, BDEV_RAW);
-		}       
-		if (raid[device].sectors)
-			ataraid_release_device(device);
-	}
-}
-
-static int hptraid_open(struct inode * inode, struct file * filp) 
-{
-	MOD_INC_USE_COUNT;
-	return 0;
-}
-static int hptraid_release(struct inode * inode, struct file * filp)
-{	
-	MOD_DEC_USE_COUNT;
-	return 0;
-}
-
-module_init(hptraid_init);
-module_exit(hptraid_exit);
-MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/hptraid.h linux-2.4.21-pre6/drivers/ide/hptraid.h
--- linux-2.4.20/drivers/ide/hptraid.h	2001-10-11 16:43:29.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/hptraid.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,77 +0,0 @@
-/*-
- * Copyright (c) 2000,2001 Søren Schmidt <sos@FreeBSD.org>
- * 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, this list of conditions and the following disclaimer,
- *    without modification, immediately at the beginning of the file.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `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.
- *
- */
-                            
-struct highpoint_raid_conf
-{
-       int8_t  filler1[32];
-       u_int32_t       magic;
-#define HPT_MAGIC_OK   0x5a7816f0
-#define HPT_MAGIC_BAD  0x5a7816fd  
-
-       u_int32_t       magic_0;
-       u_int32_t       magic_1;
-       u_int32_t       order;  
-#define HPT_O_MIRROR   0x01  
-#define HPT_O_STRIPE   0x02
-#define HPT_O_OK       0x04
-
-       u_int8_t        raid_disks;
-       u_int8_t        raid0_shift; 
-       u_int8_t        type;
-#define HPT_T_RAID_0   0x00 
-#define HPT_T_RAID_1   0x01
-#define HPT_T_RAID_01_RAID_0   0x02
-#define HPT_T_SPAN             0x03
-#define HPT_T_RAID_3           0x04   
-#define HPT_T_RAID_5           0x05
-#define HPT_T_SINGLEDISK       0x06
-#define HPT_T_RAID_01_RAID_1   0x07
-
-       u_int8_t        disk_number;
-       u_int32_t       total_secs; 
-       u_int32_t       disk_mode;  
-       u_int32_t       boot_mode;
-       u_int8_t        boot_disk; 
-       u_int8_t        boot_protect;
-       u_int8_t        error_log_entries;
-       u_int8_t        error_log_index;  
-       struct
-       {
-               u_int32_t       timestamp;
-               u_int8_t        reason;   
-#define HPT_R_REMOVED          0xfe      
-#define HPT_R_BROKEN           0xff      
-
-               u_int8_t        disk;
-               u_int8_t        status;
-               u_int8_t        sectors;
-               u_int32_t       lba;
-       } errorlog[32];
-       u_int8_t        filler[60];
-};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ht6560b.c linux-2.4.21-pre6/drivers/ide/ht6560b.c
--- linux-2.4.20/drivers/ide/ht6560b.c	2000-04-14 05:54:26.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/ht6560b.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,343 +0,0 @@
-/*
- *  linux/drivers/ide/ht6560b.c		Version 0.07	Feb  1, 2000
- *
- *  Copyright (C) 1995-2000  Linus Torvalds & author (see below)
- */
-
-/*
- *
- *  Version 0.01        Initial version hacked out of ide.c
- *
- *  Version 0.02        Added support for PIO modes, auto-tune
- *
- *  Version 0.03        Some cleanups
- *
- *  Version 0.05        PIO mode cycle timings auto-tune using bus-speed
- *
- *  Version 0.06        Prefetch mode now defaults no OFF. To set
- *                      prefetch mode OFF/ON use "hdparm -p8/-p9".
- *                      Unmask irq is disabled when prefetch mode
- *                      is enabled.
- *
- *  Version 0.07        Trying to fix CD-ROM detection problem.
- *                      "Prefetch" mode bit OFF for ide disks and
- *                      ON for anything else.
- *
- *
- *  HT-6560B EIDE-controller support
- *  To activate controller support use kernel parameter "ide0=ht6560b".
- *  Use hdparm utility to enable PIO mode support.
- *
- *  Author:    Mikko Ala-Fossi            <maf@iki.fi>
- *             Jan Evert van Grootheest   <janevert@iae.nl>
- *
- *  Try:  http://www.maf.iki.fi/~maf/ht6560b/
- */
-
-#define HT6560B_VERSION "v0.07"
-
-#undef REALLY_SLOW_IO		/* most systems can safely undef this */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-/* #define DEBUG */  /* remove comments for DEBUG messages */
-
-/*
- * The special i/o-port that HT-6560B uses to configuration:
- *    bit0 (0x01): "1" selects secondary interface
- *    bit2 (0x04): "1" enables FIFO function
- *    bit5 (0x20): "1" enables prefetched data read function  (???)
- *
- * The special i/o-port that HT-6560A uses to configuration:
- *    bit0 (0x01): "1" selects secondary interface
- *    bit1 (0x02): "1" enables prefetched data read function
- *    bit2 (0x04): "0" enables multi-master system	      (?)
- *    bit3 (0x08): "1" 3 cycle time, "0" 2 cycle time	      (?)
- */
-#define HT_CONFIG_PORT	  0x3e6
-#define HT_CONFIG(drivea) (byte)(((drivea)->drive_data & 0xff00) >> 8)
-/*
- * FIFO + PREFETCH (both a/b-model)
- */
-#define HT_CONFIG_DEFAULT 0x1c /* no prefetch */
-/* #define HT_CONFIG_DEFAULT 0x3c */ /* with prefetch */
-#define HT_SECONDARY_IF	  0x01
-#define HT_PREFETCH_MODE  0x20
-
-/*
- * ht6560b Timing values:
- *
- * I reviewed some assembler source listings of htide drivers and found
- * out how they setup those cycle time interfacing values, as they at Holtek
- * call them. IDESETUP.COM that is supplied with the drivers figures out
- * optimal values and fetches those values to drivers. I found out that
- * they use IDE_SELECT_REG to fetch timings to the ide board right after
- * interface switching. After that it was quite easy to add code to
- * ht6560b.c.
- *
- * IDESETUP.COM gave me values 0x24, 0x45, 0xaa, 0xff that worked fine
- * for hda and hdc. But hdb needed higher values to work, so I guess
- * that sometimes it is necessary to give higher value than IDESETUP
- * gives.   [see cmd640.c for an extreme example of this. -ml]
- *
- * Perhaps I should explain something about these timing values:
- * The higher nibble of value is the Recovery Time  (rt) and the lower nibble
- * of the value is the Active Time  (at). Minimum value 2 is the fastest and
- * the maximum value 15 is the slowest. Default values should be 15 for both.
- * So 0x24 means 2 for rt and 4 for at. Each of the drives should have
- * both values, and IDESETUP gives automatically rt=15 st=15 for CDROMs or
- * similar. If value is too small there will be all sorts of failures.
- *
- * Timing byte consists of
- *	High nibble:  Recovery Cycle Time  (rt)
- *	     The valid values range from 2 to 15. The default is 15.
- *
- *	Low nibble:   Active Cycle Time	   (at)
- *	     The valid values range from 2 to 15. The default is 15.
- *
- * You can obtain optimized timing values by running Holtek IDESETUP.COM
- * for DOS. DOS drivers get their timing values from command line, where
- * the first value is the Recovery Time and the second value is the
- * Active Time for each drive. Smaller value gives higher speed.
- * In case of failures you should probably fall back to a higher value.
- */
-#define HT_TIMING(drivea) (byte)((drivea)->drive_data & 0x00ff)
-#define HT_TIMING_DEFAULT 0xff
-
-/*
- * This routine handles interface switching for the peculiar hardware design
- * on the F.G.I./Holtek HT-6560B VLB IDE interface.
- * The HT-6560B can only enable one IDE port at a time, and requires a
- * silly sequence (below) whenever we switch between primary and secondary.
- */
-
-/*
- * This routine is invoked from ide.c to prepare for access to a given drive.
- */
-static void ht6560b_selectproc (ide_drive_t *drive)
-{
-	unsigned long flags;
-	static byte current_select = 0;
-	static byte current_timing = 0;
-	byte select, timing;
-	
-	__save_flags (flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-	
-	select = HT_CONFIG(drive);
-	timing = HT_TIMING(drive);
-	
-	if (select != current_select || timing != current_timing) {
-		current_select = select;
-		current_timing = timing;
-		if (drive->media != ide_disk || !drive->present)
-			select |= HT_PREFETCH_MODE;
-		(void) inb(HT_CONFIG_PORT);
-		(void) inb(HT_CONFIG_PORT);
-		(void) inb(HT_CONFIG_PORT);
-		(void) inb(HT_CONFIG_PORT);
-		outb(select, HT_CONFIG_PORT);
-		/*
-		 * Set timing for this drive:
-		 */
-		outb(timing, IDE_SELECT_REG);
-		(void) inb(IDE_STATUS_REG);
-#ifdef DEBUG
-		printk("ht6560b: %s: select=%#x timing=%#x\n", drive->name, select, timing);
-#endif
-	}
-	__restore_flags (flags);	/* local CPU only */
-}
-
-/*
- * Autodetection and initialization of ht6560b
- */
-static int __init try_to_init_ht6560b(void)
-{
-	byte orig_value;
-	int i;
-	
-	/* Autodetect ht6560b */
-	if ((orig_value=inb(HT_CONFIG_PORT)) == 0xff)
-		return 0;
-	
-	for (i=3;i>0;i--) {
-		outb(0x00, HT_CONFIG_PORT);
-		if (!( (~inb(HT_CONFIG_PORT)) & 0x3f )) {
-			outb(orig_value, HT_CONFIG_PORT);
-			return 0;
-		}
-	}
-	outb(0x00, HT_CONFIG_PORT);
-	if ((~inb(HT_CONFIG_PORT))& 0x3f) {
-		outb(orig_value, HT_CONFIG_PORT);
-		return 0;
-	}
-	/*
-	 * Ht6560b autodetected
-	 */
-	outb(HT_CONFIG_DEFAULT, HT_CONFIG_PORT);
-	outb(HT_TIMING_DEFAULT, 0x1f6);  /* IDE_SELECT_REG */
-	(void) inb(0x1f7);               /* IDE_STATUS_REG */
-	
-	printk("\nht6560b " HT6560B_VERSION
-	       ": chipset detected and initialized"
-#ifdef DEBUG
-	       " with debug enabled"
-#endif
-		);
-	return 1;
-}
-
-static byte ht_pio2timings(ide_drive_t *drive, byte pio)
-{
-	int active_time, recovery_time;
-	int active_cycles, recovery_cycles;
-	ide_pio_data_t d;
-	int bus_speed = system_bus_clock();
-	
-        if (pio) {
-		pio = ide_get_best_pio_mode(drive, pio, 5, &d);
-		
-		/*
-		 *  Just like opti621.c we try to calculate the
-		 *  actual cycle time for recovery and activity
-		 *  according system bus speed.
-		 */
-		active_time = ide_pio_timings[pio].active_time;
-		recovery_time = d.cycle_time 
-			- active_time
-			- ide_pio_timings[pio].setup_time;
-		/*
-		 *  Cycle times should be Vesa bus cycles
-		 */
-		active_cycles   = (active_time   * bus_speed + 999) / 1000;
-		recovery_cycles = (recovery_time * bus_speed + 999) / 1000;
-		/*
-		 *  Upper and lower limits
-		 */
-		if (active_cycles   < 2)  active_cycles   = 2;
-		if (recovery_cycles < 2)  recovery_cycles = 2;
-		if (active_cycles   > 15) active_cycles   = 15;
-		if (recovery_cycles > 15) recovery_cycles = 0;  /* 0==16 */
-		
-#ifdef DEBUG
-		printk("ht6560b: drive %s setting pio=%d recovery=%d (%dns) active=%d (%dns)\n", drive->name, pio, recovery_cycles, recovery_time, active_cycles, active_time);
-#endif
-		
-		return (byte)((recovery_cycles << 4) | active_cycles);
-	} else {
-		
-#ifdef DEBUG
-		printk("ht6560b: drive %s setting pio=0\n", drive->name);
-#endif
-		
-		return HT_TIMING_DEFAULT;    /* default setting */
-	}
-}
-
-/*
- *  Enable/Disable so called prefetch mode
- */
-static void ht_set_prefetch(ide_drive_t *drive, byte state)
-{
-	unsigned long flags;
-	int t = HT_PREFETCH_MODE << 8;
-	
-	save_flags (flags);	/* all CPUs */
-	cli();		        /* all CPUs */
-	
-	/*
-	 *  Prefetch mode and unmask irq seems to conflict
-	 */
-	if (state) {
-		drive->drive_data |= t;   /* enable prefetch mode */
-		drive->no_unmask = 1;
-		drive->unmask = 0;
-	} else {
-		drive->drive_data &= ~t;  /* disable prefetch mode */
-		drive->no_unmask = 0;
-	}
-	
-	restore_flags (flags);	/* all CPUs */
-	
-#ifdef DEBUG
-	printk("ht6560b: drive %s prefetch mode %sabled\n", drive->name, (state ? "en" : "dis"));
-#endif
-}
-
-static void tune_ht6560b (ide_drive_t *drive, byte pio)
-{
-	unsigned long flags;
-	byte timing;
-	
-	switch (pio) {
-	case 8:         /* set prefetch off */
-	case 9:         /* set prefetch on */
-		ht_set_prefetch(drive, pio & 1);
-		return;
-	}
-	
-	timing = ht_pio2timings(drive, pio);
-	
-	save_flags (flags);	/* all CPUs */
-	cli();		        /* all CPUs */
-	
-	drive->drive_data &= 0xff00;
-	drive->drive_data |= timing;
-	
-	restore_flags (flags);	/* all CPUs */
-	
-#ifdef DEBUG
-	printk("ht6560b: drive %s tuned to pio mode %#x timing=%#x\n", drive->name, pio, timing);
-#endif
-}
-
-void __init init_ht6560b (void)
-{
-	int t;
-	
-	if (check_region(HT_CONFIG_PORT,1)) {
-		printk(KERN_ERR "ht6560b: PORT %#x ALREADY IN USE\n", HT_CONFIG_PORT);
-	} else {
-		if (try_to_init_ht6560b()) {
-			request_region(HT_CONFIG_PORT, 1, ide_hwifs[0].name);
-			ide_hwifs[0].chipset = ide_ht6560b;
-			ide_hwifs[1].chipset = ide_ht6560b;
-			ide_hwifs[0].selectproc = &ht6560b_selectproc;
-			ide_hwifs[1].selectproc = &ht6560b_selectproc;
-			ide_hwifs[0].tuneproc = &tune_ht6560b;
-			ide_hwifs[1].tuneproc = &tune_ht6560b;
-			ide_hwifs[0].serialized = 1;  /* is this needed? */
-			ide_hwifs[1].serialized = 1;  /* is this needed? */
-			ide_hwifs[0].mate = &ide_hwifs[1];
-			ide_hwifs[1].mate = &ide_hwifs[0];
-			ide_hwifs[1].channel = 1;
-			
-			/*
-			 * Setting default configurations for drives
-			 */
-			t = (HT_CONFIG_DEFAULT << 8);
-			t |= HT_TIMING_DEFAULT;
-			ide_hwifs[0].drives[0].drive_data = t;
-			ide_hwifs[0].drives[1].drive_data = t;
-			t |= (HT_SECONDARY_IF << 8);
-			ide_hwifs[1].drives[0].drive_data = t;
-			ide_hwifs[1].drives[1].drive_data = t;
-		} else
-			printk(KERN_ERR "ht6560b: not found\n");
-	}
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/icside.c linux-2.4.21-pre6/drivers/ide/icside.c
--- linux-2.4.20/drivers/ide/icside.c	2001-10-25 20:53:47.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/icside.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,766 +0,0 @@
-/*
- * linux/drivers/ide/icside.c
- *
- * Copyright (c) 1996,1997 Russell King.
- *
- * Changelog:
- *  08-Jun-1996	RMK	Created
- *  12-Sep-1997	RMK	Added interrupt enable/disable
- *  17-Apr-1999	RMK	Added support for V6 EASI
- *  22-May-1999	RMK	Added support for V6 DMA
- */
-
-#include <linux/config.h>
-#include <linux/string.h>
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/blkdev.h>
-#include <linux/errno.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-
-#include <asm/dma.h>
-#include <asm/ecard.h>
-#include <asm/io.h>
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-/*
- * Maximum number of interfaces per card
- */
-#define MAX_IFS	2
-
-#define ICS_IDENT_OFFSET		0x8a0
-
-#define ICS_ARCIN_V5_INTRSTAT		0x000
-#define ICS_ARCIN_V5_INTROFFSET		0x001
-#define ICS_ARCIN_V5_IDEOFFSET		0xa00
-#define ICS_ARCIN_V5_IDEALTOFFSET	0xae0
-#define ICS_ARCIN_V5_IDESTEPPING	4
-
-#define ICS_ARCIN_V6_IDEOFFSET_1	0x800
-#define ICS_ARCIN_V6_INTROFFSET_1	0x880
-#define ICS_ARCIN_V6_INTRSTAT_1		0x8a4
-#define ICS_ARCIN_V6_IDEALTOFFSET_1	0x8e0
-#define ICS_ARCIN_V6_IDEOFFSET_2	0xc00
-#define ICS_ARCIN_V6_INTROFFSET_2	0xc80
-#define ICS_ARCIN_V6_INTRSTAT_2		0xca4
-#define ICS_ARCIN_V6_IDEALTOFFSET_2	0xce0
-#define ICS_ARCIN_V6_IDESTEPPING	4
-
-struct cardinfo {
-	unsigned int dataoffset;
-	unsigned int ctrloffset;
-	unsigned int stepping;
-};
-
-static struct cardinfo icside_cardinfo_v5 = {
-	ICS_ARCIN_V5_IDEOFFSET,
-	ICS_ARCIN_V5_IDEALTOFFSET,
-	ICS_ARCIN_V5_IDESTEPPING
-};
-
-static struct cardinfo icside_cardinfo_v6_1 = {
-	ICS_ARCIN_V6_IDEOFFSET_1,
-	ICS_ARCIN_V6_IDEALTOFFSET_1,
-	ICS_ARCIN_V6_IDESTEPPING
-};
-
-static struct cardinfo icside_cardinfo_v6_2 = {
-	ICS_ARCIN_V6_IDEOFFSET_2,
-	ICS_ARCIN_V6_IDEALTOFFSET_2,
-	ICS_ARCIN_V6_IDESTEPPING
-};
-
-static const card_ids icside_cids[] = {
-	{ MANU_ICS,  PROD_ICS_IDE  },
-	{ MANU_ICS2, PROD_ICS2_IDE },
-	{ 0xffff, 0xffff }
-};
-
-typedef enum {
-	ics_if_unknown,
-	ics_if_arcin_v5,
-	ics_if_arcin_v6
-} iftype_t;
-
-/* ---------------- Version 5 PCB Support Functions --------------------- */
-/* Prototype: icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
- * Purpose  : enable interrupts from card
- */
-static void icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
-{
-	unsigned int memc_port = (unsigned int)ec->irq_data;
-	outb (0, memc_port + ICS_ARCIN_V5_INTROFFSET);
-}
-
-/* Prototype: icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
- * Purpose  : disable interrupts from card
- */
-static void icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
-{
-	unsigned int memc_port = (unsigned int)ec->irq_data;
-	inb (memc_port + ICS_ARCIN_V5_INTROFFSET);
-}
-
-static const expansioncard_ops_t icside_ops_arcin_v5 = {
-	icside_irqenable_arcin_v5,
-	icside_irqdisable_arcin_v5,
-	NULL,
-	NULL,
-	NULL,
-	NULL
-};
-
-
-/* ---------------- Version 6 PCB Support Functions --------------------- */
-/* Prototype: icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
- * Purpose  : enable interrupts from card
- */
-static void icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
-{
-	unsigned int ide_base_port = (unsigned int)ec->irq_data;
-
-	outb (0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_1);
-	outb (0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_2);
-}
-
-/* Prototype: icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
- * Purpose  : disable interrupts from card
- */
-static void icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
-{
-	unsigned int ide_base_port = (unsigned int)ec->irq_data;
-
-	inb (ide_base_port + ICS_ARCIN_V6_INTROFFSET_1);
-	inb (ide_base_port + ICS_ARCIN_V6_INTROFFSET_2);
-}
-
-/* Prototype: icside_irqprobe(struct expansion_card *ec)
- * Purpose  : detect an active interrupt from card
- */
-static int icside_irqpending_arcin_v6(struct expansion_card *ec)
-{
-	unsigned int ide_base_port = (unsigned int)ec->irq_data;
-
-	return inb(ide_base_port + ICS_ARCIN_V6_INTRSTAT_1) & 1 ||
-	       inb(ide_base_port + ICS_ARCIN_V6_INTRSTAT_2) & 1;
-}
-
-static const expansioncard_ops_t icside_ops_arcin_v6 = {
-	icside_irqenable_arcin_v6,
-	icside_irqdisable_arcin_v6,
-	icside_irqpending_arcin_v6,
-	NULL,
-	NULL,
-	NULL
-};
-
-/* Prototype: icside_identifyif (struct expansion_card *ec)
- * Purpose  : identify IDE interface type
- * Notes    : checks the description string
- */
-static iftype_t __init icside_identifyif (struct expansion_card *ec)
-{
-	unsigned int addr;
-	iftype_t iftype;
-	int id = 0;
-
-	iftype = ics_if_unknown;
-
-	addr = ecard_address (ec, ECARD_IOC, ECARD_FAST) + ICS_IDENT_OFFSET;
-
-	id = inb (addr) & 1;
-	id |= (inb (addr + 1) & 1) << 1;
-	id |= (inb (addr + 2) & 1) << 2;
-	id |= (inb (addr + 3) & 1) << 3;
-
-	switch (id) {
-	case 0: /* A3IN */
-		printk("icside: A3IN unsupported\n");
-		break;
-
-	case 1: /* A3USER */
-		printk("icside: A3USER unsupported\n");
-		break;
-
-	case 3:	/* ARCIN V6 */
-		printk(KERN_DEBUG "icside: detected ARCIN V6 in slot %d\n", ec->slot_no);
-		iftype = ics_if_arcin_v6;
-		break;
-
-	case 15:/* ARCIN V5 (no id) */
-		printk(KERN_DEBUG "icside: detected ARCIN V5 in slot %d\n", ec->slot_no);
-		iftype = ics_if_arcin_v5;
-		break;
-
-	default:/* we don't know - complain very loudly */
-		printk("icside: ***********************************\n");
-		printk("icside: *** UNKNOWN ICS INTERFACE id=%d ***\n", id);
-		printk("icside: ***********************************\n");
-		printk("icside: please report this to linux@arm.linux.org.uk\n");
-		printk("icside: defaulting to ARCIN V5\n");
-		iftype = ics_if_arcin_v5;
-		break;
-	}
-
-	return iftype;
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA_ICS
-/*
- * SG-DMA support.
- *
- * Similar to the BM-DMA, but we use the RiscPCs IOMD DMA controllers.
- * There is only one DMA controller per card, which means that only
- * one drive can be accessed at one time.  NOTE! We do not enforce that
- * here, but we rely on the main IDE driver spotting that both
- * interfaces use the same IRQ, which should guarantee this.
- */
-#define NR_ENTRIES 256
-#define TABLE_SIZE (NR_ENTRIES * 8)
-
-static int ide_build_sglist(ide_hwif_t *hwif, struct request *rq)
-{
-	struct buffer_head *bh;
-	struct scatterlist *sg = hwif->sg_table;
-	int nents = 0;
-
-	if (rq->cmd == READ)
-		hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
-	else
-		hwif->sg_dma_direction = PCI_DMA_TODEVICE;
-	bh = rq->bh;
-	do {
-		unsigned char *virt_addr = bh->b_data;
-		unsigned int size = bh->b_size;
-
-		while ((bh = bh->b_reqnext) != NULL) {
-			if ((virt_addr + size) != (unsigned char *)bh->b_data)
-				break;
-			size += bh->b_size;
-		}
-		memset(&sg[nents], 0, sizeof(*sg));
-		sg[nents].address = virt_addr;
-		sg[nents].length = size;
-		nents++;
-	} while (bh != NULL);
-
-	return pci_map_sg(NULL, sg, nents, hwif->sg_dma_direction);
-}
-
-static int
-icside_build_dmatable(ide_drive_t *drive, int reading)
-{
-	return HWIF(drive)->sg_nents = ide_build_sglist(HWIF(drive), HWGROUP(drive)->rq);
-}
-
-/* Teardown mappings after DMA has completed.  */
-static void icside_destroy_dmatable(ide_drive_t *drive)
-{
-	struct scatterlist *sg = HWIF(drive)->sg_table;
-	int nents = HWIF(drive)->sg_nents;
-
-	pci_unmap_sg(NULL, sg, nents, HWIF(drive)->sg_dma_direction);
-}
-
-static int
-icside_config_if(ide_drive_t *drive, int xfer_mode)
-{
-	int func = ide_dma_off;
-
-	switch (xfer_mode) {
-	case XFER_MW_DMA_2:
-		/*
-		 * The cycle time is limited to 250ns by the r/w
-		 * pulse width (90ns), however we should still
-		 * have a maximum burst transfer rate of 8MB/s.
-		 */
-		drive->drive_data = 250;
-		break;
-
-	case XFER_MW_DMA_1:
-		drive->drive_data = 250;
-		break;
-
-	case XFER_MW_DMA_0:
-		drive->drive_data = 480;
-		break;
-
-	default:
-		drive->drive_data = 0;
-		break;
-	}
-
-	if (!drive->init_speed)
-		drive->init_speed = (byte) xfer_mode;
-
-	if (drive->drive_data &&
-	    ide_config_drive_speed(drive, (byte) xfer_mode) == 0)
-		func = ide_dma_on;
-	else
-		drive->drive_data = 480;
-
-	printk("%s: %s selected (peak %dMB/s)\n", drive->name,
-		ide_xfer_verbose(xfer_mode), 2000 / drive->drive_data);
-
-	drive->current_speed = (byte) xfer_mode;
-
-	return func;
-}
-
-static int
-icside_set_speed(ide_drive_t *drive, byte speed)
-{
-	return icside_config_if(drive, speed);
-}
-
-/*
- * dma_intr() is the handler for disk read/write DMA interrupts
- */
-static ide_startstop_t icside_dmaintr(ide_drive_t *drive)
-{
-	int i;
-	byte stat, dma_stat;
-
-	dma_stat = HWIF(drive)->dmaproc(ide_dma_end, drive);
-	stat = GET_STAT();			/* get drive status */
-	if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
-		if (!dma_stat) {
-			struct request *rq = HWGROUP(drive)->rq;
-			rq = HWGROUP(drive)->rq;
-			for (i = rq->nr_sectors; i > 0;) {
-				i -= rq->current_nr_sectors;
-				ide_end_request(1, HWGROUP(drive));
-			}
-			return ide_stopped;
-		}
-		printk("%s: dma_intr: bad DMA status (dma_stat=%x)\n", 
-		       drive->name, dma_stat);
-	}
-	return ide_error(drive, "dma_intr", stat);
-}
-
-/*
- * The following is a sick duplication from ide-dma.c ;(
- *
- * This should be defined in one place only.
- */
-struct drive_list_entry {
-	char * id_model;
-	char * id_firmware;
-};
-
-static struct drive_list_entry drive_whitelist [] = {
-	{ "Micropolis 2112A",			"ALL"		},
-	{ "CONNER CTMA 4000",			"ALL"		},
-	{ "CONNER CTT8000-A",			"ALL"		},
-	{ "ST34342A",				"ALL"		},
-	{ NULL,					0		}
-};
-
-static struct drive_list_entry drive_blacklist [] = {
-	{ "WDC AC11000H",			"ALL"		},
-	{ "WDC AC22100H",			"ALL"		},
-	{ "WDC AC32500H",			"ALL"		},
-	{ "WDC AC33100H",			"ALL"		},
-	{ "WDC AC31600H",			"ALL"		},
-	{ "WDC AC32100H",			"24.09P07"	},
-	{ "WDC AC23200L",			"21.10N21"	},
-	{ "Compaq CRD-8241B",			"ALL"		},
-	{ "CRD-8400B",				"ALL"		},
-	{ "CRD-8480B",				"ALL"		},
-	{ "CRD-8480C",				"ALL"		},
-	{ "CRD-8482B",				"ALL"		},
- 	{ "CRD-84",				"ALL"		},
-	{ "SanDisk SDP3B",			"ALL"		},
-	{ "SanDisk SDP3B-64",			"ALL"		},
-	{ "SANYO CD-ROM CRD",			"ALL"		},
-	{ "HITACHI CDR-8",			"ALL"		},
-	{ "HITACHI CDR-8335",			"ALL"		},
-	{ "HITACHI CDR-8435",			"ALL"		},
-	{ "Toshiba CD-ROM XM-6202B",		"ALL"		},
-	{ "CD-532E-A",				"ALL"		},
-	{ "E-IDE CD-ROM CR-840",		"ALL"		},
-	{ "CD-ROM Drive/F5A",			"ALL"		},
-	{ "RICOH CD-R/RW MP7083A",		"ALL"		},
-	{ "WPI CDD-820",			"ALL"		},
-	{ "SAMSUNG CD-ROM SC-148C",		"ALL"		},
-	{ "SAMSUNG CD-ROM SC-148F",		"ALL"		},
-	{ "SAMSUNG CD-ROM SC",			"ALL"		},
-	{ "SanDisk SDP3B-64",			"ALL"		},
-	{ "SAMSUNG CD-ROM SN-124",		"ALL"		},
-	{ "PLEXTOR CD-R PX-W8432T",		"ALL"		},
-	{ "ATAPI CD-ROM DRIVE 40X MAXIMUM",	"ALL"		},
-	{ "_NEC DV5800A",			"ALL"		},
-	{ NULL,					0		}
-};
-
-static int in_drive_list(struct hd_driveid *id, struct drive_list_entry * drive_table)
-{
-	for ( ; drive_table->id_model ; drive_table++)
-		if ((!strcmp(drive_table->id_model, id->model)) &&
-		    ((!strstr(drive_table->id_firmware, id->fw_rev)) ||
-		     (!strcmp(drive_table->id_firmware, "ALL"))))
-			return 1;
-	return 0;
-}
-
-/*
- *  For both Blacklisted and Whitelisted drives.
- *  This is setup to be called as an extern for future support
- *  to other special driver code.
- */
-static int check_drive_lists(ide_drive_t *drive, int good_bad)
-{
-	struct hd_driveid *id = drive->id;
-
-	if (good_bad) {
-		return in_drive_list(id, drive_whitelist);
-	} else {
-		int blacklist = in_drive_list(id, drive_blacklist);
-		if (blacklist)
-			printk("%s: Disabling DMA for %s\n", drive->name, id->model);
-		return(blacklist);
-	}
-	return 0;
-}
-
-static int
-icside_dma_check(ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-	ide_hwif_t *hwif = HWIF(drive);
-	int autodma = hwif->autodma;
-	int xfer_mode = XFER_PIO_2;
-	int func = ide_dma_off_quietly;
-
-	if (!id || !(id->capability & 1) || !autodma)
-		goto out;
-
-	/*
-	 * Consult the list of known "bad" drives
-	 */
-	if (check_drive_lists(drive, 0)) {
-		func = ide_dma_off;
-		goto out;
-	}
-
-	/*
-	 * Enable DMA on any drive that has multiword DMA
-	 */
-	if (id->field_valid & 2) {
-		if (id->dma_mword & 4) {
-			xfer_mode = XFER_MW_DMA_2;
-			func = ide_dma_on;
-		} else if (id->dma_mword & 2) {
-			xfer_mode = XFER_MW_DMA_1;
-			func = ide_dma_on;
-		} else if (id->dma_mword & 1) {
-			xfer_mode = XFER_MW_DMA_0;
-			func = ide_dma_on;
-		}
-		goto out;
-	}
-
-	/*
-	 * Consult the list of known "good" drives
-	 */
-	if (check_drive_lists(drive, 1)) {
-		if (id->eide_dma_time > 150)
-			goto out;
-		xfer_mode = XFER_MW_DMA_1;
-		func = ide_dma_on;
-	}
-
-out:
-	func = icside_config_if(drive, xfer_mode);
-
-	return hwif->dmaproc(func, drive);
-}
-
-static int
-icside_dma_verbose(ide_drive_t *drive)
-{
-	printk(", DMA");
-	return 1;
-}
-
-static int
-icside_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	int count, reading = 0;
-
-	switch (func) {
-	case ide_dma_off:
-		printk("%s: DMA disabled\n", drive->name);
-		/*FALLTHROUGH*/
-
-	case ide_dma_off_quietly:
-	case ide_dma_on:
-		drive->using_dma = (func == ide_dma_on);
-		return 0;
-
-	case ide_dma_check:
-		return icside_dma_check(drive);
-
-	case ide_dma_read:
-		reading = 1;
-	case ide_dma_write:
-		count = icside_build_dmatable(drive, reading);
-		if (!count)
-			return 1;
-		disable_dma(hwif->hw.dma);
-
-		/* Route the DMA signals to
-		 * to the correct interface.
-		 */
-		outb(hwif->select_data, hwif->config_data);
-
-		/* Select the correct timing
-		 * for this drive
-		 */
-		set_dma_speed(hwif->hw.dma, drive->drive_data);
-
-		set_dma_sg(hwif->hw.dma, HWIF(drive)->sg_table, count);
-		set_dma_mode(hwif->hw.dma, reading ? DMA_MODE_READ
-			     : DMA_MODE_WRITE);
-
-		drive->waiting_for_dma = 1;
-		if (drive->media != ide_disk)
-			return 0;
-
-		ide_set_handler(drive, &icside_dmaintr, WAIT_CMD, NULL);
-		OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA,
-			 IDE_COMMAND_REG);
-
-	case ide_dma_begin:
-		enable_dma(hwif->hw.dma);
-		return 0;
-
-	case ide_dma_end:
-		drive->waiting_for_dma = 0;
-		disable_dma(hwif->hw.dma);
-		icside_destroy_dmatable(drive);
-		return get_dma_residue(hwif->hw.dma) != 0;
-
-	case ide_dma_test_irq:
-		return inb((unsigned long)hwif->hw.priv) & 1;
-
-	case ide_dma_bad_drive:
-	case ide_dma_good_drive:
-		return check_drive_lists(drive, (func == ide_dma_good_drive));
-
-	case ide_dma_verbose:
-		return icside_dma_verbose(drive);
-
-	case ide_dma_timeout:
-	default:
-		printk("icside_dmaproc: unsupported %s func: %d\n",
-			ide_dmafunc_verbose(func), func);
-	}
-	return 1;
-}
-
-static int
-icside_setup_dma(ide_hwif_t *hwif, int autodma)
-{
-	printk("    %s: SG-DMA", hwif->name);
-
-	hwif->sg_table = kmalloc(sizeof(struct scatterlist) * NR_ENTRIES,
-				 GFP_KERNEL);
-	if (!hwif->sg_table)
-		goto failed;
-
-	hwif->dmatable_cpu = NULL;
-	hwif->dmatable_dma = 0;
-	hwif->speedproc = icside_set_speed;
-	hwif->dmaproc = icside_dmaproc;
-	hwif->autodma = autodma;
-
-	printk(" capable%s\n", autodma ?
-		", auto-enable" : "");
-
-	return 1;
-
-failed:
-	printk(" -- ERROR, unable to allocate DMA table\n");
-	return 0;
-}
-#endif
-
-static ide_hwif_t *
-icside_find_hwif(unsigned long dataport)
-{
-	ide_hwif_t *hwif;
-	int index;
-
-	for (index = 0; index < MAX_HWIFS; ++index) {
-		hwif = &ide_hwifs[index];
-		if (hwif->io_ports[IDE_DATA_OFFSET] == (ide_ioreg_t)dataport)
-			goto found;
-	}
-
-	for (index = 0; index < MAX_HWIFS; ++index) {
-		hwif = &ide_hwifs[index];
-		if (!hwif->io_ports[IDE_DATA_OFFSET])
-			goto found;
-	}
-
-	return NULL;
-found:
-	return hwif;
-}
-
-static ide_hwif_t *
-icside_setup(unsigned long base, struct cardinfo *info, int irq)
-{
-	unsigned long port = base + info->dataoffset;
-	ide_hwif_t *hwif;
-
-	hwif = icside_find_hwif(base);
-	if (hwif) {
-		int i;
-
-		memset(&hwif->hw, 0, sizeof(hw_regs_t));
-
-		for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
-			hwif->hw.io_ports[i] = (ide_ioreg_t)port;
-			hwif->io_ports[i] = (ide_ioreg_t)port;
-			port += 1 << info->stepping;
-		}
-		hwif->hw.io_ports[IDE_CONTROL_OFFSET] = base + info->ctrloffset;
-		hwif->io_ports[IDE_CONTROL_OFFSET] = base + info->ctrloffset;
-		hwif->hw.irq  = irq;
-		hwif->irq     = irq;
-		hwif->hw.dma  = NO_DMA;
-		hwif->noprobe = 0;
-		hwif->chipset = ide_acorn;
-	}
-
-	return hwif;
-}
-
-static int __init icside_register_v5(struct expansion_card *ec, int autodma)
-{
-	unsigned long slot_port;
-	ide_hwif_t *hwif;
-
-	slot_port = ecard_address(ec, ECARD_MEMC, 0);
-
-	ec->irqaddr  = (unsigned char *)ioaddr(slot_port + ICS_ARCIN_V5_INTRSTAT);
-	ec->irqmask  = 1;
-	ec->irq_data = (void *)slot_port;
-	ec->ops      = (expansioncard_ops_t *)&icside_ops_arcin_v5;
-
-	/*
-	 * Be on the safe side - disable interrupts
-	 */
-	inb(slot_port + ICS_ARCIN_V5_INTROFFSET);
-
-	hwif = icside_setup(slot_port, &icside_cardinfo_v5, ec->irq);
-
-	return hwif ? 0 : -1;
-}
-
-static int __init icside_register_v6(struct expansion_card *ec, int autodma)
-{
-	unsigned long slot_port, port;
-	ide_hwif_t *hwif, *mate;
-	int sel = 0;
-
-	slot_port = ecard_address(ec, ECARD_IOC, ECARD_FAST);
-	port      = ecard_address(ec, ECARD_EASI, ECARD_FAST);
-
-	if (port == 0)
-		port = slot_port;
-	else
-		sel = 1 << 5;
-
-	outb(sel, slot_port);
-
-	ec->irq_data = (void *)port;
-	ec->ops      = (expansioncard_ops_t *)&icside_ops_arcin_v6;
-
-	/*
-	 * Be on the safe side - disable interrupts
-	 */
-	inb(port + ICS_ARCIN_V6_INTROFFSET_1);
-	inb(port + ICS_ARCIN_V6_INTROFFSET_2);
-
-	hwif = icside_setup(port, &icside_cardinfo_v6_1, ec->irq);
-	mate = icside_setup(port, &icside_cardinfo_v6_2, ec->irq);
-
-#ifdef CONFIG_BLK_DEV_IDEDMA_ICS
-	if (ec->dma != NO_DMA) {
-		if (request_dma(ec->dma, hwif->name))
-			goto no_dma;
-
-		if (hwif) {
-			hwif->config_data = slot_port;
-			hwif->select_data = sel;
-			hwif->hw.dma  = ec->dma;
-			hwif->hw.priv = (void *)
-					(port + ICS_ARCIN_V6_INTRSTAT_1);
-			hwif->channel = 0;
-			icside_setup_dma(hwif, autodma);
-		}
-		if (mate) {
-			mate->config_data = slot_port;
-			mate->select_data = sel | 1;
-			mate->hw.dma  = ec->dma;
-			mate->hw.priv = (void *)
-					(port + ICS_ARCIN_V6_INTRSTAT_2);
-			mate->channel = 1;
-			icside_setup_dma(mate, autodma);
-		}
-	}
-no_dma:
-#endif
-	return hwif || mate ? 0 : -1;
-}
-
-int __init icside_init(void)
-{
-	int autodma = 0;
-
-#ifdef CONFIG_IDEDMA_ICS_AUTO
-	autodma = 1;
-#endif
-
-	ecard_startfind ();
-
-	do {
-		struct expansion_card *ec;
-		int result;
-
-		ec = ecard_find(0, icside_cids);
-		if (ec == NULL)
-			break;
-
-		ecard_claim(ec);
-
-		switch (icside_identifyif(ec)) {
-		case ics_if_arcin_v5:
-			result = icside_register_v5(ec, autodma);
-			break;
-
-		case ics_if_arcin_v6:
-			result = icside_register_v6(ec, autodma);
-			break;
-
-		default:
-			result = -1;
-			break;
-		}
-
-		if (result)
-			ecard_release(ec);
-	} while (1);
-
-	return 0;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-adma.c linux-2.4.21-pre6/drivers/ide/ide-adma.c
--- linux-2.4.20/drivers/ide/ide-adma.c	2001-08-13 22:44:03.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/ide-adma.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,9 +0,0 @@
-/*
- *  linux/drivers/ide/ide-adma.c         Version 0.00	June 24, 2001
- *
- *  Copyright (c) 2001		Andre Hedrick <andre@linux-ide.org>
- *
- *  Asynchronous DMA -- TBA, this is a holding file.
- *
- */
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-cd.c linux-2.4.21-pre6/drivers/ide/ide-cd.c
--- linux-2.4.20/drivers/ide/ide-cd.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/ide-cd.c	2003-03-26 23:49:34.000000000 +0000
@@ -540,7 +540,124 @@
 }
 
 
-static void cdrom_end_request (int uptodate, ide_drive_t *drive)
+/*
+ * This is our end_request replacement function.
+ */
+static int ide_cdrom_end_request (ide_drive_t *drive, int uptodate)
+{
+	struct request *rq;
+	unsigned long flags;
+	int ret = 1;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	rq = HWGROUP(drive)->rq;
+
+	/*
+	 * decide whether to reenable DMA -- 3 is a random magic for now,
+	 * if we DMA timeout more than 3 times, just stay in PIO
+	 */
+	if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
+		drive->state = 0;
+		HWGROUP(drive)->hwif->ide_dma_on(drive);
+	}
+
+	if (!end_that_request_first(rq, uptodate, drive->name)) {
+		add_blkdev_randomness(MAJOR(rq->rq_dev));
+		blkdev_dequeue_request(rq);
+		HWGROUP(drive)->rq = NULL;
+		end_that_request_last(rq);
+		ret = 0;
+	}
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	return ret;
+}
+
+/*
+ * Error reporting, in human readable form (luxurious, but a memory hog).
+ */
+byte ide_cdrom_dump_status (ide_drive_t *drive, const char *msg, byte stat)
+{
+	unsigned long flags;
+
+	atapi_status_t status;
+	atapi_error_t error;
+
+	status.all = stat;
+	local_irq_set(flags);
+	printk("%s: %s: status=0x%02x", drive->name, msg, stat);
+#if FANCY_STATUS_DUMPS
+	printk(" { ");
+	if (status.b.bsy)
+		printk("Busy ");
+	else {
+		if (status.b.drdy)	printk("DriveReady ");
+		if (status.b.df)	printk("DeviceFault ");
+		if (status.b.dsc)	printk("SeekComplete ");
+		if (status.b.drq)	printk("DataRequest ");
+		if (status.b.corr)	printk("CorrectedError ");
+		if (status.b.idx)	printk("Index ");
+		if (status.b.check)	printk("Error ");
+	}
+	printk("}");
+#endif	/* FANCY_STATUS_DUMPS */
+	printk("\n");
+	if ((status.all & (status.b.bsy|status.b.check)) == status.b.check) {
+		error.all = HWIF(drive)->INB(IDE_ERROR_REG);
+		printk("%s: %s: error=0x%02x", drive->name, msg, error.all);
+#if FANCY_STATUS_DUMPS
+		if (error.b.ili)	printk("IllegalLengthIndication ");
+		if (error.b.eom)	printk("EndOfMedia ");
+		if (error.b.abrt)	printk("Aborted Command ");
+		if (error.b.mcr)	printk("MediaChangeRequested ");
+		if (error.b.sense_key)	printk("LastFailedSense 0x%02x ",
+						error.b.sense_key);
+#endif	/* FANCY_STATUS_DUMPS */
+		printk("\n");
+	}
+	local_irq_restore(flags);
+	return error.all;
+}
+
+/*
+ * ide_error() takes action based on the error returned by the drive.
+ */
+ide_startstop_t ide_cdrom_error (ide_drive_t *drive, const char *msg, byte stat)
+{
+	struct request *rq;
+	byte err;
+
+	err = ide_cdrom_dump_status(drive, msg, stat);
+	if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
+		return ide_stopped;
+	/* retry only "normal" I/O: */
+	if (rq->cmd == IDE_DRIVE_CMD || rq->cmd == IDE_DRIVE_TASK) {
+		rq->errors = 1;
+		ide_end_drive_cmd(drive, stat, err);
+		return ide_stopped;
+	}
+
+	if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) {
+		/* other bits are useless when BUSY */
+		rq->errors |= ERROR_RESET;
+	} else {
+		/* add decoding error stuff */
+	}
+	if (HWIF(drive)->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT))
+		/* force an abort */
+		HWIF(drive)->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);
+	if (rq->errors >= ERROR_MAX) {
+		DRIVER(drive)->end_request(drive, 0);
+	} else {
+		if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
+			++rq->errors;
+			return ide_do_reset(drive);
+		}
+		++rq->errors;
+	}
+	return ide_stopped;
+}
+
+static void cdrom_end_request (ide_drive_t *drive, int uptodate)
 {
 	struct request *rq = HWGROUP(drive)->rq;
 
@@ -550,11 +667,10 @@
 			(struct packet_command *) pc->sense,
 			(struct request_sense *) (pc->buffer - pc->c[4]));
 	}
-	if (rq->cmd == READ || rq->cmd == WRITE)
-		if (!rq->current_nr_sectors)
-			uptodate = 1;
+	if (blk_fs_request(rq) && !rq->current_nr_sectors)
+		uptodate = 1;
 
-	ide_end_request (uptodate, HWGROUP(drive));
+	ide_cdrom_end_request(drive, uptodate);
 }
 
 
@@ -568,14 +684,13 @@
 	struct packet_command *pc;
 	
 	/* Check for errors. */
-	stat = GET_STAT();
-	*stat_ret = stat;
+	*stat_ret = stat = HWIF(drive)->INB(IDE_STATUS_REG);
 
 	if (OK_STAT (stat, good_stat, BAD_R_STAT))
 		return 0;
 
 	/* Get the IDE error register. */
-	err = GET_ERR();
+	err = HWIF(drive)->INB(IDE_ERROR_REG);
 	sense_key = err >> 4;
 
 	if (rq == NULL) {
@@ -591,8 +706,8 @@
 
 		pc = (struct packet_command *) rq->buffer;
 		pc->stat = 1;
-		cdrom_end_request (1, drive);
-		*startstop = ide_error (drive, "request sense failure", stat);
+		cdrom_end_request(drive, 1);
+		*startstop = DRIVER(drive)->error(drive, "request sense failure", stat);
 		return 1;
 
 	} else if (rq->cmd == PACKET_COMMAND) {
@@ -628,11 +743,11 @@
 		}
 
 		pc->stat = 1;
-		cdrom_end_request (1, drive);
+		cdrom_end_request(drive, 1);
 
 		if ((stat & ERR_STAT) != 0)
 			cdrom_queue_request_sense(drive, wait, pc->sense, pc);
-	} else {
+	} else if (blk_fs_request(rq)) {
 		/* Handle errors from READ and WRITE requests. */
 
 		if (sense_key == NOT_READY) {
@@ -641,7 +756,7 @@
 
 			/* Fail the request. */
 			printk ("%s: tray open\n", drive->name);
-			cdrom_end_request (0, drive);
+			cdrom_end_request(drive, 0);
 		} else if (sense_key == UNIT_ATTENTION) {
 			/* Media change. */
 			cdrom_saw_media_change (drive);
@@ -650,21 +765,26 @@
 			   But be sure to give up if we've retried
 			   too many times. */
 			if (++rq->errors > ERROR_MAX)
-				cdrom_end_request (0, drive);
+				cdrom_end_request(drive, 0);
 		} else if (sense_key == ILLEGAL_REQUEST ||
 			   sense_key == DATA_PROTECT) {
 			/* No point in retrying after an illegal
 			   request or data protect error.*/
 			ide_dump_status (drive, "command error", stat);
-			cdrom_end_request (0, drive);
+			cdrom_end_request(drive, 0);
 		} else if ((err & ~ABRT_ERR) != 0) {
 			/* Go to the default handler
 			   for other errors. */
-			*startstop = ide_error (drive, "cdrom_decode_status", stat);
+			*startstop = DRIVER(drive)->error(drive, "cdrom_decode_status", stat);
 			return 1;
+		} else if (sense_key == MEDIUM_ERROR) {
+			/* No point in re-trying a zillion times on a bad 
+			 * sector...  If we got here the error is not correctable */
+			ide_dump_status (drive, "media error (bad sector)", stat);
+			cdrom_end_request(drive, 0);
 		} else if ((++rq->errors > ERROR_MAX)) {
 			/* We've racked up too many retries.  Abort. */
-			cdrom_end_request (0, drive);
+			cdrom_end_request(drive, 0);
 		}
 
 		/* If we got a CHECK_CONDITION status,
@@ -723,33 +843,35 @@
 
 	if (info->dma) {
 		if (info->cmd == READ) {
-			info->dma = !HWIF(drive)->dmaproc(ide_dma_read, drive);
+			info->dma = !HWIF(drive)->ide_dma_read(drive);
 		} else if (info->cmd == WRITE) {
-			info->dma = !HWIF(drive)->dmaproc(ide_dma_write, drive);
+			info->dma = !HWIF(drive)->ide_dma_write(drive);
 		} else {
 			printk("ide-cd: DMA set, but not allowed\n");
 		}
 	}
 
 	/* Set up the controller registers. */
-	OUT_BYTE (info->dma, IDE_FEATURE_REG);
-	OUT_BYTE (0, IDE_NSECTOR_REG);
-	OUT_BYTE (0, IDE_SECTOR_REG);
+	/* FIXME: for Virtual DMA we must check harder */
+	HWIF(drive)->OUTB(info->dma, IDE_FEATURE_REG);
+	HWIF(drive)->OUTB(0, IDE_IREASON_REG);
+	HWIF(drive)->OUTB(0, IDE_SECTOR_REG);
 
-	OUT_BYTE (xferlen & 0xff, IDE_LCYL_REG);
-	OUT_BYTE (xferlen >> 8  , IDE_HCYL_REG);
+	HWIF(drive)->OUTB(xferlen & 0xff, IDE_BCOUNTL_REG);
+	HWIF(drive)->OUTB(xferlen >> 8  , IDE_BCOUNTH_REG);
 	if (IDE_CONTROL_REG)
-		OUT_BYTE (drive->ctl, IDE_CONTROL_REG);
+		HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);
  
-	if (info->dma)
-		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
-
 	if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
+		if (HWGROUP(drive)->handler != NULL)
+			BUG();
 		ide_set_handler (drive, handler, WAIT_CMD, cdrom_timer_expiry);
-		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
+		/* packet command */
+		HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG);
 		return ide_started;
 	} else {
-		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
+		/* packet command */
+		HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG);
 		return (*handler) (drive);
 	}
 }
@@ -770,27 +892,37 @@
 	unsigned char *cmd_buf	= pc->c;
 	int cmd_len		= sizeof(pc->c);
 	unsigned int timeout	= pc->timeout;
+	struct cdrom_info *info = drive->driver_data;
 	ide_startstop_t startstop;
 
-	if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
+	if (CDROM_CONFIG_FLAGS(drive)->drq_interrupt) {
 		/* Here we should have been called after receiving an interrupt
 		   from the device.  DRQ should how be set. */
 		int stat_dum;
 
 		/* Check for errors. */
-		if (cdrom_decode_status (&startstop, drive, DRQ_STAT, &stat_dum))
+		if (cdrom_decode_status(&startstop, drive, DRQ_STAT, &stat_dum))
 			return startstop;
 	} else {
 		/* Otherwise, we must wait for DRQ to get set. */
-		if (ide_wait_stat (&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY))
+		if (ide_wait_stat(&startstop, drive, DRQ_STAT,
+				BUSY_STAT, WAIT_READY))
 			return startstop;
 	}
 
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
+
 	/* Arm the interrupt handler. */
-	ide_set_handler (drive, handler, timeout, cdrom_timer_expiry);
+	ide_set_handler(drive, handler, timeout, cdrom_timer_expiry);
 
 	/* Send the command to the device. */
-	atapi_output_bytes (drive, cmd_buf, cmd_len);
+	HWIF(drive)->atapi_output_bytes(drive, cmd_buf, cmd_len);
+
+	/* Start the DMA if need be */
+	if (info->dma)
+		(void) HWIF(drive)->ide_dma_begin(drive);
+
 	return ide_started;
 }
 
@@ -828,7 +960,7 @@
 	/* Read the data into the buffer. */
 	dest = info->buffer + info->nsectors_buffered * SECTOR_SIZE;
 	while (sectors_to_buffer > 0) {
-		atapi_input_bytes (drive, dest, SECTOR_SIZE);
+		HWIF(drive)->atapi_input_bytes(drive, dest, SECTOR_SIZE);
 		--sectors_to_buffer;
 		--sectors_to_transfer;
 		++info->nsectors_buffered;
@@ -838,7 +970,7 @@
 	/* Throw away any remaining data. */
 	while (sectors_to_transfer > 0) {
 		char dum[SECTOR_SIZE];
-		atapi_input_bytes (drive, dum, sizeof (dum));
+		HWIF(drive)->atapi_input_bytes(drive, dum, sizeof (dum));
 		--sectors_to_transfer;
 	}
 }
@@ -864,14 +996,14 @@
 		   and quit this request. */
 		while (len > 0) {
 			int dum = 0;
-			atapi_output_bytes (drive, &dum, sizeof (dum));
+			HWIF(drive)->atapi_output_bytes(drive, &dum, sizeof (dum));
 			len -= sizeof (dum);
 		}
 	} else  if (ireason == 1) {
 		/* Some drives (ASUS) seem to tell us that status
 		 * info is available. just get it and ignore.
 		 */
-		GET_STAT();
+		(void) HWIF(drive)->INB(IDE_STATUS_REG);
 		return 0;
 	} else {
 		/* Drive wants a command packet, or invalid ireason... */
@@ -879,7 +1011,7 @@
 			drive->name, ireason);
 	}
 
-	cdrom_end_request (0, drive);
+	cdrom_end_request(drive, 0);
 	return -1;
 }
 
@@ -891,6 +1023,7 @@
 	int stat;
 	int ireason, len, sectors_to_transfer, nskip;
 	struct cdrom_info *info = drive->driver_data;
+	u8 lowcyl = 0, highcyl = 0;
 	int i, dma = info->dma, dma_error = 0;
 	ide_startstop_t startstop;
 
@@ -899,8 +1032,8 @@
 	/* Check for errors. */
 	if (dma) {
 		info->dma = 0;
-		if ((dma_error = HWIF(drive)->dmaproc(ide_dma_end, drive)))
-			HWIF(drive)->dmaproc(ide_dma_off, drive);
+		if ((dma_error = HWIF(drive)->ide_dma_end(drive)))
+			HWIF(drive)->ide_dma_off(drive);
 	}
 
 	if (cdrom_decode_status (&startstop, drive, 0, &stat))
@@ -910,16 +1043,19 @@
 		if (!dma_error) {
 			for (i = rq->nr_sectors; i > 0;) {
 				i -= rq->current_nr_sectors;
-				ide_end_request(1, HWGROUP(drive));
+				ide_cdrom_end_request(drive, 1);
 			}
 			return ide_stopped;
 		} else
-			return ide_error (drive, "dma error", stat);
+			return DRIVER(drive)->error(drive, "dma error", stat);
 	}
 
 	/* Read the interrupt reason and the transfer length. */
-	ireason = IN_BYTE (IDE_NSECTOR_REG);
-	len = IN_BYTE (IDE_LCYL_REG) + 256 * IN_BYTE (IDE_HCYL_REG);
+	ireason = HWIF(drive)->INB(IDE_IREASON_REG);
+	lowcyl  = HWIF(drive)->INB(IDE_BCOUNTL_REG);
+	highcyl = HWIF(drive)->INB(IDE_BCOUNTH_REG);
+
+	len = lowcyl + (256 * highcyl);
 
 	/* If DRQ is clear, the command has completed. */
 	if ((stat & DRQ_STAT) == 0) {
@@ -928,9 +1064,9 @@
 		if (rq->current_nr_sectors > 0) {
 			printk ("%s: cdrom_read_intr: data underrun (%ld blocks)\n",
 				drive->name, rq->current_nr_sectors);
-			cdrom_end_request (0, drive);
+			cdrom_end_request(drive, 0);
 		} else
-			cdrom_end_request (1, drive);
+			cdrom_end_request(drive, 1);
 		return ide_stopped;
 	}
 
@@ -944,13 +1080,13 @@
 	if ((len % SECTOR_SIZE) != 0) {
 		printk ("%s: cdrom_read_intr: Bad transfer size %d\n",
 			drive->name, len);
-		if (CDROM_CONFIG_FLAGS (drive)->limit_nframes)
+		if (CDROM_CONFIG_FLAGS(drive)->limit_nframes)
 			printk ("  This drive is not supported by this version of the driver\n");
 		else {
 			printk ("  Trying to limit transfer sizes\n");
-			CDROM_CONFIG_FLAGS (drive)->limit_nframes = 1;
+			CDROM_CONFIG_FLAGS(drive)->limit_nframes = 1;
 		}
-		cdrom_end_request (0, drive);
+		cdrom_end_request(drive, 0);
 		return ide_stopped;
 	}
 
@@ -965,7 +1101,7 @@
 	while (nskip > 0) {
 		/* We need to throw away a sector. */
 		char dum[SECTOR_SIZE];
-		atapi_input_bytes (drive, dum, sizeof (dum));
+		HWIF(drive)->atapi_input_bytes(drive, dum, sizeof (dum));
 
 		--rq->current_nr_sectors;
 		--nskip;
@@ -979,7 +1115,7 @@
 		/* If we've filled the present buffer but there's another
 		   chained buffer after it, move on. */
 		if (rq->current_nr_sectors == 0 && rq->nr_sectors)
-			cdrom_end_request (1, drive);
+			cdrom_end_request(drive, 1);
 
 		/* If the buffers are full, cache the rest of the data in our
 		   internal buffer. */
@@ -996,7 +1132,7 @@
 			/* Read this_transfer sectors
 			   into the current buffer. */
 			while (this_transfer > 0) {
-				atapi_input_bytes(drive, rq->buffer, SECTOR_SIZE);
+				HWIF(drive)->atapi_input_bytes(drive, rq->buffer, SECTOR_SIZE);
 				rq->buffer += SECTOR_SIZE;
 				--rq->nr_sectors;
 				--rq->current_nr_sectors;
@@ -1007,8 +1143,10 @@
 		}
 	}
 
-	/* Done moving data!
-	   Wait for another interrupt. */
+	if (HWGROUP(drive)->handler != NULL)    /* paranoia check */
+		BUG();
+
+	/* Done moving data!  Wait for another interrupt. */
 	ide_set_handler(drive, &cdrom_read_intr, WAIT_CMD, NULL);
 	return ide_started;
 }
@@ -1031,7 +1169,7 @@
 	       rq->sector >= info->sector_buffered &&
 	       rq->sector < info->sector_buffered + info->nsectors_buffered) {
 		if (rq->current_nr_sectors == 0)
-			cdrom_end_request (1, drive);
+			cdrom_end_request(drive, 1);
 
 		memcpy (rq->buffer,
 			info->buffer +
@@ -1046,13 +1184,13 @@
 	/* If we've satisfied the current request,
 	   terminate it successfully. */
 	if (rq->nr_sectors == 0) {
-		cdrom_end_request (1, drive);
+		cdrom_end_request(drive, 1);
 		return -1;
 	}
 
 	/* Move on to the next buffer if needed. */
 	if (rq->current_nr_sectors == 0)
-		cdrom_end_request (1, drive);
+		cdrom_end_request(drive, 1);
 
 	/* If this condition does not hold, then the kluge i use to
 	   represent the number of sectors to skip at the start of a transfer
@@ -1060,9 +1198,9 @@
 	   paranoid and check. */
 	if (rq->current_nr_sectors < (rq->bh->b_size >> SECTOR_BITS) &&
 	    (rq->sector % SECTORS_PER_FRAME) != 0) {
-		printk ("%s: cdrom_read_from_buffer: buffer botch (%ld)\n",
+		printk("%s: cdrom_read_from_buffer: buffer botch (%ld)\n",
 			drive->name, rq->sector);
-		cdrom_end_request (0, drive);
+		cdrom_end_request(drive, 0);
 		return -1;
 	}
 
@@ -1101,7 +1239,7 @@
 			(rq->sector % CD_FRAMESIZE != 0)) {
 			printk ("%s: cdrom_start_read_continuation: buffer botch (%lu)\n",
 				drive->name, rq->current_nr_sectors);
-			cdrom_end_request (0, drive);
+			cdrom_end_request(drive, 0);
 			return ide_stopped;
 		}
 		sector -= nskip;
@@ -1147,7 +1285,7 @@
 		return startstop;
 	CDROM_CONFIG_FLAGS(drive)->seeking = 1;
 
-	if (retry && jiffies - info->start_seek > IDECD_SEEK_TIMER) {
+	if (retry && time_after(jiffies, info->start_seek + IDECD_SEEK_TIMER)) {
 		if (--retry == 0) {
 			/*
 			 * this condition is far too common, to bother
@@ -1189,7 +1327,7 @@
 	info->dma = 0;
 	info->cmd = 0;
 	info->start_seek = jiffies;
-	return cdrom_start_packet_command (drive, 0, cdrom_start_seek_continuation);
+	return cdrom_start_packet_command(drive, 0, cdrom_start_seek_continuation);
 }
 
 static inline int cdrom_merge_requests(struct request *rq, struct request *nxt)
@@ -1263,7 +1401,7 @@
 {
 	struct cdrom_info *info = drive->driver_data;
 	struct request *rq = HWGROUP(drive)->rq;
-	int minor = MINOR (rq->rq_dev);
+	int minor = MINOR(rq->rq_dev);
 
 	/* If the request is relative to a partition, fix it up to refer to the
 	   absolute address.  */
@@ -1313,14 +1451,18 @@
 	struct request *rq = HWGROUP(drive)->rq;
 	struct packet_command *pc = (struct packet_command *)rq->buffer;
 	ide_startstop_t startstop;
+	u8 lowcyl = 0, highcyl = 0;
 
 	/* Check for errors. */
-	if (cdrom_decode_status (&startstop, drive, 0, &stat))
+	if (cdrom_decode_status(&startstop, drive, 0, &stat))
 		return startstop;
 
 	/* Read the interrupt reason and the transfer length. */
-	ireason = IN_BYTE (IDE_NSECTOR_REG);
-	len = IN_BYTE (IDE_LCYL_REG) + 256 * IN_BYTE (IDE_HCYL_REG);
+	ireason = HWIF(drive)->INB(IDE_IREASON_REG);
+	lowcyl  = HWIF(drive)->INB(IDE_BCOUNTL_REG);
+	highcyl = HWIF(drive)->INB(IDE_BCOUNTH_REG);
+
+	len = lowcyl + (256 * highcyl);
 
 	/* If DRQ is clear, the command has completed.
 	   Complain if we still have data left to transfer. */
@@ -1337,7 +1479,7 @@
 		}
 
 		if (pc->buflen == 0)
-			cdrom_end_request (1, drive);
+			cdrom_end_request(drive, 1);
 		else {
 			/* Comment this out, because this always happens 
 			   right after a reset occurs, and it is annoying to 
@@ -1347,7 +1489,7 @@
 				drive->name, pc->buflen);
 			*/
 			pc->stat = 1;
-			cdrom_end_request (1, drive);
+			cdrom_end_request(drive, 1);
 		}
 		return ide_stopped;
 	}
@@ -1359,14 +1501,14 @@
 	/* The drive wants to be written to. */
 	if ((ireason & 3) == 0) {
 		/* Transfer the data. */
-		atapi_output_bytes (drive, pc->buffer, thislen);
+		HWIF(drive)->atapi_output_bytes(drive, pc->buffer, thislen);
 
 		/* If we haven't moved enough data to satisfy the drive,
 		   add some padding. */
 		while (len > thislen) {
 			int dum = 0;
-			atapi_output_bytes (drive, &dum, sizeof (dum));
-			len -= sizeof (dum);
+			HWIF(drive)->atapi_output_bytes(drive, &dum, sizeof(dum));
+			len -= sizeof(dum);
 		}
 
 		/* Keep count of how much data we've moved. */
@@ -1378,14 +1520,14 @@
 	else if ((ireason & 3) == 2) {
 
 		/* Transfer the data. */
-		atapi_input_bytes (drive, pc->buffer, thislen);
+		HWIF(drive)->atapi_input_bytes(drive, pc->buffer, thislen);
 
 		/* If we haven't moved enough data to satisfy the drive,
 		   add some padding. */
 		while (len > thislen) {
 			int dum = 0;
-			atapi_input_bytes (drive, &dum, sizeof (dum));
-			len -= sizeof (dum);
+			HWIF(drive)->atapi_input_bytes(drive, &dum, sizeof(dum));
+			len -= sizeof(dum);
 		}
 
 		/* Keep count of how much data we've moved. */
@@ -1398,8 +1540,11 @@
 		pc->stat = 1;
 	}
 
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+
 	/* Now we wait for another interrupt. */
-	ide_set_handler (drive, &cdrom_pc_intr, WAIT_CMD, cdrom_timer_expiry);
+	ide_set_handler(drive, &cdrom_pc_intr, WAIT_CMD, cdrom_timer_expiry);
 	return ide_started;
 }
 
@@ -1430,7 +1575,7 @@
 	len = pc->buflen;
 
 	/* Start sending the command to the drive. */
-	return cdrom_start_packet_command (drive, len, cdrom_do_pc_continuation);
+	return cdrom_start_packet_command(drive, len, cdrom_do_pc_continuation);
 }
 
 
@@ -1462,7 +1607,7 @@
 		ide_init_drive_cmd (&req);
 		req.cmd = PACKET_COMMAND;
 		req.buffer = (char *)pc;
-		ide_do_drive_cmd (drive, &req, ide_wait);
+		ide_do_drive_cmd(drive, &req, ide_wait);
 		/* FIXME: we should probably abort/retry or something 
 		 * in case of failure */
 		if (pc->stat != 0) {
@@ -1472,7 +1617,7 @@
 			struct request_sense *reqbuf = pc->sense;
 
 			if (reqbuf->sense_key == UNIT_ATTENTION)
-				cdrom_saw_media_change (drive);
+				cdrom_saw_media_change(drive);
 			else if (reqbuf->sense_key == NOT_READY &&
 				 reqbuf->asc == 4 && reqbuf->ascq != 4) {
 				/* The drive is in the process of loading
@@ -1513,7 +1658,7 @@
 		   and quit this request. */
 		while (len > 0) {
 			int dum = 0;
-			atapi_output_bytes(drive, &dum, sizeof(dum));
+			HWIF(drive)->atapi_output_bytes(drive, &dum, sizeof(dum));
 			len -= sizeof(dum);
 		}
 	} else {
@@ -1522,7 +1667,7 @@
 			drive->name, ireason);
 	}
 
-	cdrom_end_request(0, drive);
+	cdrom_end_request(drive, 0);
 	return 1;
 }
 
@@ -1531,6 +1676,7 @@
 	int stat, ireason, len, sectors_to_transfer, uptodate;
 	struct cdrom_info *info = drive->driver_data;
 	int i, dma_error = 0, dma = info->dma;
+	u8 lowcyl = 0, highcyl = 0;
 	ide_startstop_t startstop;
 
 	struct request *rq = HWGROUP(drive)->rq;
@@ -1538,9 +1684,9 @@
 	/* Check for errors. */
 	if (dma) {
 		info->dma = 0;
-		if ((dma_error = HWIF(drive)->dmaproc(ide_dma_end, drive))) {
+		if ((dma_error = HWIF(drive)->ide_dma_end(drive))) {
 			printk("ide-cd: write dma error\n");
-			HWIF(drive)->dmaproc(ide_dma_off, drive);
+			HWIF(drive)->ide_dma_off(drive);
 		}
 	}
 
@@ -1554,19 +1700,22 @@
 	 */
 	if (dma) {
 		if (dma_error)
-			return ide_error(drive, "dma error", stat);
+			return DRIVER(drive)->error(drive, "dma error", stat);
 
 		rq = HWGROUP(drive)->rq;
 		for (i = rq->nr_sectors; i > 0;) {
 			i -= rq->current_nr_sectors;
-			ide_end_request(1, HWGROUP(drive));
+			ide_cdrom_end_request(drive, 1);
 		}
 		return ide_stopped;
 	}
 
 	/* Read the interrupt reason and the transfer length. */
-	ireason = IN_BYTE(IDE_NSECTOR_REG);
-	len = IN_BYTE(IDE_LCYL_REG) + 256 * IN_BYTE(IDE_HCYL_REG);
+	ireason = HWIF(drive)->INB(IDE_IREASON_REG);
+	lowcyl  = HWIF(drive)->INB(IDE_BCOUNTL_REG);
+	highcyl = HWIF(drive)->INB(IDE_BCOUNTH_REG);
+
+	len = lowcyl + (256 * highcyl);
 
 	/* If DRQ is clear, the command has completed. */
 	if ((stat & DRQ_STAT) == 0) {
@@ -1579,7 +1728,7 @@
 			drive->name, rq->current_nr_sectors);
 			uptodate = 0;
 		}
-		cdrom_end_request(uptodate, drive);
+		cdrom_end_request(drive, uptodate);
 		return ide_stopped;
 	}
 
@@ -1607,7 +1756,7 @@
 		this_transfer = MIN(sectors_to_transfer,rq->current_nr_sectors);
 
 		while (this_transfer > 0) {
-			atapi_output_bytes(drive, rq->buffer, SECTOR_SIZE);
+			HWIF(drive)->atapi_output_bytes(drive, rq->buffer, SECTOR_SIZE);
 			rq->buffer += SECTOR_SIZE;
 			--rq->nr_sectors;
 			--rq->current_nr_sectors;
@@ -1620,9 +1769,12 @@
 		 * current buffer complete, move on
 		 */
 		if (rq->current_nr_sectors == 0 && rq->nr_sectors)
-			cdrom_end_request (1, drive);
+			cdrom_end_request(drive, 1);
 	}
 
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
+
 	/* re-arm handler */
 	ide_set_handler(drive, &cdrom_write_intr, 5 * WAIT_CMD, NULL);
 	return ide_started;
@@ -1662,7 +1814,7 @@
 	 * writes *must* be 2kB frame aligned
 	 */
 	if ((rq->nr_sectors & 3) || (rq->sector & 3)) {
-		cdrom_end_request(0, drive);
+		cdrom_end_request(drive, 0);
 		return ide_stopped;
 	}
 
@@ -1698,11 +1850,10 @@
 		case WRITE:
 		case READ: {
 			if (CDROM_CONFIG_FLAGS(drive)->seeking) {
-				unsigned long elpased = jiffies - info->start_seek;
-				int stat = GET_STAT();
+				int stat = HWIF(drive)->INB(IDE_STATUS_REG);
 
 				if ((stat & SEEK_STAT) != SEEK_STAT) {
-					if (elpased < IDECD_SEEK_TIMEOUT) {
+					if (time_before(jiffies, info->start_seek + IDECD_SEEK_TIMEOUT)) {
 						ide_stall_queue(drive, IDECD_SEEK_TIMER);
 						return ide_stopped;
 					}
@@ -1711,9 +1862,9 @@
 				CDROM_CONFIG_FLAGS(drive)->seeking = 0;
 			}
 			if (IDE_LARGE_SEEK(info->last_block, block, IDECD_SEEK_THRESHOLD) && drive->dsc_overlap)
-				action = cdrom_start_seek (drive, block);
+				action = cdrom_start_seek(drive, block);
 			else {
-				if (rq->cmd == READ)
+				if (rq_data_dir(rq) == READ)
 					action = cdrom_start_read(drive, block);
 				else
 					action = cdrom_start_write(drive, rq);
@@ -1728,13 +1879,13 @@
 		}
 
 		case RESET_DRIVE_COMMAND: {
-			cdrom_end_request(1, drive);
+			cdrom_end_request(drive, 1);
 			return ide_do_reset(drive);
 		}
 
 		default: {
 			printk("ide-cd: bad cmd %d\n", rq->cmd);
-			cdrom_end_request(0, drive);
+			cdrom_end_request(drive, 0);
 			return ide_stopped;
 		}
 	}
@@ -1836,7 +1987,7 @@
 		pc.sense = sense;
 		pc.c[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL;
 		pc.c[4] = lockflag ? 1 : 0;
-		stat = cdrom_queue_packet_command (drive, &pc);
+		stat = cdrom_queue_packet_command(drive, &pc);
 	}
 
 	/* If we got an illegal field error, the drive
@@ -1846,7 +1997,7 @@
 	    (sense->asc == 0x24 || sense->asc == 0x20)) {
 		printk ("%s: door locking not supported\n",
 			drive->name);
-		CDROM_CONFIG_FLAGS (drive)->no_doorlock = 1;
+		CDROM_CONFIG_FLAGS(drive)->no_doorlock = 1;
 		stat = 0;
 	}
 	
@@ -1855,7 +2006,7 @@
 		stat = 0;
 
 	if (stat == 0)
-		CDROM_STATE_FLAGS (drive)->door_locked = lockflag;
+		CDROM_STATE_FLAGS(drive)->door_locked = lockflag;
 
 	return stat;
 }
@@ -1880,7 +2031,7 @@
 
 	pc.c[0] = GPCMD_START_STOP_UNIT;
 	pc.c[4] = 0x02 + (ejectflag != 0);
-	return cdrom_queue_packet_command (drive, &pc);
+	return cdrom_queue_packet_command(drive, &pc);
 }
 
 static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity,
@@ -1929,7 +2080,7 @@
 	if (msf_flag)
 		pc.c[1] = 2;
 
-	return cdrom_queue_packet_command (drive, &pc);
+	return cdrom_queue_packet_command(drive, &pc);
 }
 
 
@@ -1969,9 +2120,9 @@
 	if (stat) return stat;
 
 #if ! STANDARD_ATAPI
-	if (CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd) {
-		toc->hdr.first_track = bcd2bin (toc->hdr.first_track);
-		toc->hdr.last_track  = bcd2bin (toc->hdr.last_track);
+	if (CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd) {
+		toc->hdr.first_track = bcd2bin(toc->hdr.first_track);
+		toc->hdr.last_track  = bcd2bin(toc->hdr.last_track);
 	}
 #endif  /* not STANDARD_ATAPI */
 
@@ -2009,7 +2160,7 @@
 			return stat;
 		}
 #if ! STANDARD_ATAPI
-		if (CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd) {
+		if (CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd) {
 			toc->hdr.first_track = bin2bcd(CDROM_LEADOUT);
 			toc->hdr.last_track = bin2bcd(CDROM_LEADOUT);
 		} else
@@ -2026,18 +2177,18 @@
 	toc->hdr.toc_length = ntohs (toc->hdr.toc_length);
 
 #if ! STANDARD_ATAPI
-	if (CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd) {
-		toc->hdr.first_track = bcd2bin (toc->hdr.first_track);
-		toc->hdr.last_track  = bcd2bin (toc->hdr.last_track);
+	if (CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd) {
+		toc->hdr.first_track = bcd2bin(toc->hdr.first_track);
+		toc->hdr.last_track  = bcd2bin(toc->hdr.last_track);
 	}
 #endif  /* not STANDARD_ATAPI */
 
 	for (i=0; i<=ntracks; i++) {
 #if ! STANDARD_ATAPI
-		if (CDROM_CONFIG_FLAGS (drive)->tocaddr_as_bcd) {
-			if (CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd)
-				toc->ent[i].track = bcd2bin (toc->ent[i].track);
-			msf_from_bcd (&toc->ent[i].addr.msf);
+		if (CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd) {
+			if (CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd)
+				toc->ent[i].track = bcd2bin(toc->ent[i].track);
+			msf_from_bcd(&toc->ent[i].addr.msf);
 		}
 #endif  /* not STANDARD_ATAPI */
 		toc->ent[i].addr.lba = msf_to_lba (toc->ent[i].addr.msf.minute,
@@ -2059,7 +2210,7 @@
 	}
 
 #if ! STANDARD_ATAPI
-	if (CDROM_CONFIG_FLAGS (drive)->tocaddr_as_bcd)
+	if (CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd)
 		msf_from_bcd (&ms_tmp.ent.addr.msf);
 #endif  /* not STANDARD_ATAPI */
 
@@ -2082,7 +2233,7 @@
 	drive->part[0].nr_sects = toc->capacity * SECTORS_PER_FRAME;
 
 	/* Remember that we've read this stuff. */
-	CDROM_STATE_FLAGS (drive)->toc_valid = 1;
+	CDROM_STATE_FLAGS(drive)->toc_valid = 1;
 
 	return 0;
 }
@@ -2308,7 +2459,7 @@
 		struct cdrom_tocentry *tocentry = (struct cdrom_tocentry*) arg;
 		struct atapi_toc_entry *toce;
 
-		stat = cdrom_get_toc_entry (drive, tocentry->cdte_track, &toce);
+		stat = cdrom_get_toc_entry(drive, tocentry->cdte_track, &toce);
 		if (stat) return stat;
 
 		tocentry->cdte_ctrl = toce->control;
@@ -2380,10 +2531,10 @@
 	struct request_sense sense;
 	int stat;
 
-	if ((stat = cdrom_select_speed (drive, speed, &sense)) < 0)
+	if ((stat = cdrom_select_speed(drive, speed, &sense)) < 0)
 		return stat;
 
-        cdi->speed = CDROM_STATE_FLAGS (drive)->current_speed;
+        cdi->speed = CDROM_STATE_FLAGS(drive)->current_speed;
         return 0;
 }
 
@@ -2476,8 +2627,8 @@
 	
 	if (slot_nr == CDSL_CURRENT) {
 		(void) cdrom_check_status(drive, NULL);
-		retval = CDROM_STATE_FLAGS (drive)->media_changed;
-		CDROM_STATE_FLAGS (drive)->media_changed = 0;
+		retval = CDROM_STATE_FLAGS(drive)->media_changed;
+		CDROM_STATE_FLAGS(drive)->media_changed = 0;
 		return retval;
 	} else {
 		return -EINVAL;
@@ -2535,30 +2686,30 @@
 	struct cdrom_device_info *devinfo = &info->devinfo;
 	int minor = (drive->select.b.unit) << PARTN_BITS;
 
-	devinfo->dev = MKDEV (HWIF(drive)->major, minor);
+	devinfo->dev = MKDEV(HWIF(drive)->major, minor);
 	devinfo->ops = &ide_cdrom_dops;
 	devinfo->mask = 0;
-	devinfo->speed = CDROM_STATE_FLAGS (drive)->current_speed;
+	devinfo->speed = CDROM_STATE_FLAGS(drive)->current_speed;
 	devinfo->capacity = nslots;
 	devinfo->handle = (void *) drive;
 	strcpy(devinfo->name, drive->name);
 	
 	/* set capability mask to match the probe. */
-	if (!CDROM_CONFIG_FLAGS (drive)->cd_r)
+	if (!CDROM_CONFIG_FLAGS(drive)->cd_r)
 		devinfo->mask |= CDC_CD_R;
-	if (!CDROM_CONFIG_FLAGS (drive)->cd_rw)
+	if (!CDROM_CONFIG_FLAGS(drive)->cd_rw)
 		devinfo->mask |= CDC_CD_RW;
-	if (!CDROM_CONFIG_FLAGS (drive)->dvd)
+	if (!CDROM_CONFIG_FLAGS(drive)->dvd)
 		devinfo->mask |= CDC_DVD;
-	if (!CDROM_CONFIG_FLAGS (drive)->dvd_r)
+	if (!CDROM_CONFIG_FLAGS(drive)->dvd_r)
 		devinfo->mask |= CDC_DVD_R;
-	if (!CDROM_CONFIG_FLAGS (drive)->dvd_ram)
+	if (!CDROM_CONFIG_FLAGS(drive)->dvd_ram)
 		devinfo->mask |= CDC_DVD_RAM;
-	if (!CDROM_CONFIG_FLAGS (drive)->is_changer)
+	if (!CDROM_CONFIG_FLAGS(drive)->is_changer)
 		devinfo->mask |= CDC_SELECT_DISC;
-	if (!CDROM_CONFIG_FLAGS (drive)->audio_play)
+	if (!CDROM_CONFIG_FLAGS(drive)->audio_play)
 		devinfo->mask |= CDC_PLAY_AUDIO;
-	if (!CDROM_CONFIG_FLAGS (drive)->close_tray)
+	if (!CDROM_CONFIG_FLAGS(drive)->close_tray)
 		devinfo->mask |= CDC_CLOSE_TRAY;
 
 	devinfo->de = devfs_register(drive->de, "cd", DEVFS_FL_DEFAULT,
@@ -2612,9 +2763,9 @@
 	struct atapi_capabilities_page cap;
 	int nslots = 1;
 
-	if (CDROM_CONFIG_FLAGS (drive)->nec260) {
-		CDROM_CONFIG_FLAGS (drive)->no_eject = 0;                       
-		CDROM_CONFIG_FLAGS (drive)->audio_play = 1;       
+	if (CDROM_CONFIG_FLAGS(drive)->nec260) {
+		CDROM_CONFIG_FLAGS(drive)->no_eject = 0;                       
+		CDROM_CONFIG_FLAGS(drive)->audio_play = 1;       
 		return nslots;
 	}
 
@@ -2622,38 +2773,38 @@
 		return 0;
 
 	if (cap.lock == 0)
-		CDROM_CONFIG_FLAGS (drive)->no_doorlock = 1;
+		CDROM_CONFIG_FLAGS(drive)->no_doorlock = 1;
 	if (cap.eject)
-		CDROM_CONFIG_FLAGS (drive)->no_eject = 0;
+		CDROM_CONFIG_FLAGS(drive)->no_eject = 0;
 	if (cap.cd_r_write)
-		CDROM_CONFIG_FLAGS (drive)->cd_r = 1;
+		CDROM_CONFIG_FLAGS(drive)->cd_r = 1;
 	if (cap.cd_rw_write)
-		CDROM_CONFIG_FLAGS (drive)->cd_rw = 1;
+		CDROM_CONFIG_FLAGS(drive)->cd_rw = 1;
 	if (cap.test_write)
-		CDROM_CONFIG_FLAGS (drive)->test_write = 1;
+		CDROM_CONFIG_FLAGS(drive)->test_write = 1;
 	if (cap.dvd_ram_read || cap.dvd_r_read || cap.dvd_rom)
-		CDROM_CONFIG_FLAGS (drive)->dvd = 1;
+		CDROM_CONFIG_FLAGS(drive)->dvd = 1;
 	if (cap.dvd_ram_write)
-		CDROM_CONFIG_FLAGS (drive)->dvd_ram = 1;
+		CDROM_CONFIG_FLAGS(drive)->dvd_ram = 1;
 	if (cap.dvd_r_write)
-		CDROM_CONFIG_FLAGS (drive)->dvd_r = 1;
+		CDROM_CONFIG_FLAGS(drive)->dvd_r = 1;
 	if (cap.audio_play)
-		CDROM_CONFIG_FLAGS (drive)->audio_play = 1;
+		CDROM_CONFIG_FLAGS(drive)->audio_play = 1;
 	if (cap.mechtype == mechtype_caddy || cap.mechtype == mechtype_popup)
-		CDROM_CONFIG_FLAGS (drive)->close_tray = 0;
+		CDROM_CONFIG_FLAGS(drive)->close_tray = 0;
 
 	/* Some drives used by Apple don't advertise audio play
 	 * but they do support reading TOC & audio datas
 	 */
-	if (strcmp (drive->id->model, "MATSHITADVD-ROM SR-8187") == 0 ||
-	    strcmp (drive->id->model, "MATSHITADVD-ROM SR-8186") == 0 ||
-	    strcmp (drive->id->model, "MATSHITADVD-ROM SR-8176") == 0 ||
-	    strcmp (drive->id->model, "MATSHITADVD-ROM SR-8174") == 0)
-		CDROM_CONFIG_FLAGS (drive)->audio_play = 1;
+	if (strcmp(drive->id->model, "MATSHITADVD-ROM SR-8187") == 0 ||
+	    strcmp(drive->id->model, "MATSHITADVD-ROM SR-8186") == 0 ||
+	    strcmp(drive->id->model, "MATSHITADVD-ROM SR-8176") == 0 ||
+	    strcmp(drive->id->model, "MATSHITADVD-ROM SR-8174") == 0)
+		CDROM_CONFIG_FLAGS(drive)->audio_play = 1;
 
 #if ! STANDARD_ATAPI
 	if (cdi->sanyo_slot > 0) {
-		CDROM_CONFIG_FLAGS (drive)->is_changer = 1;
+		CDROM_CONFIG_FLAGS(drive)->is_changer = 1;
 		nslots = 3;
 	}
 
@@ -2662,21 +2813,22 @@
 	if (cap.mechtype == mechtype_individual_changer ||
 	    cap.mechtype == mechtype_cartridge_changer) {
 		if ((nslots = cdrom_number_of_slots(cdi)) > 1) {
-			CDROM_CONFIG_FLAGS (drive)->is_changer = 1;
-			CDROM_CONFIG_FLAGS (drive)->supp_disc_present = 1;
+			CDROM_CONFIG_FLAGS(drive)->is_changer = 1;
+			CDROM_CONFIG_FLAGS(drive)->supp_disc_present = 1;
 		}
 	}
 
 	/* The ACER/AOpen 24X cdrom has the speed fields byte-swapped */
-	if (drive->id && !drive->id->model[0] && !strncmp(drive->id->fw_rev, "241N", 4)) {
-		CDROM_STATE_FLAGS (drive)->current_speed  = 
+	if (drive->id && !drive->id->model[0] &&
+	    !strncmp(drive->id->fw_rev, "241N", 4)) {
+		CDROM_STATE_FLAGS(drive)->current_speed  = 
 			(((unsigned int)cap.curspeed) + (176/2)) / 176;
-		CDROM_CONFIG_FLAGS (drive)->max_speed = 
+		CDROM_CONFIG_FLAGS(drive)->max_speed = 
 			(((unsigned int)cap.maxspeed) + (176/2)) / 176;
 	} else {
-		CDROM_STATE_FLAGS (drive)->current_speed  = 
+		CDROM_STATE_FLAGS(drive)->current_speed  = 
 			(ntohs(cap.curspeed) + (176/2)) / 176;
-		CDROM_CONFIG_FLAGS (drive)->max_speed = 
+		CDROM_CONFIG_FLAGS(drive)->max_speed = 
 			(ntohs(cap.maxspeed) + (176/2)) / 176;
 	}
 
@@ -2687,26 +2839,26 @@
 		printk(" %dX", CDROM_CONFIG_FLAGS(drive)->max_speed);
 	printk(" %s", CDROM_CONFIG_FLAGS(drive)->dvd ? "DVD-ROM" : "CD-ROM");
 
-	if (CDROM_CONFIG_FLAGS (drive)->dvd_r|CDROM_CONFIG_FLAGS (drive)->dvd_ram)
-        	printk (" DVD%s%s", 
-        	(CDROM_CONFIG_FLAGS (drive)->dvd_r)? "-R" : "", 
-        	(CDROM_CONFIG_FLAGS (drive)->dvd_ram)? "-RAM" : "");
-
-        if (CDROM_CONFIG_FLAGS (drive)->cd_r|CDROM_CONFIG_FLAGS (drive)->cd_rw) 
-        	printk (" CD%s%s", 
-        	(CDROM_CONFIG_FLAGS (drive)->cd_r)? "-R" : "", 
-        	(CDROM_CONFIG_FLAGS (drive)->cd_rw)? "/RW" : "");
+	if (CDROM_CONFIG_FLAGS(drive)->dvd_r|CDROM_CONFIG_FLAGS(drive)->dvd_ram)
+        	printk(" DVD%s%s", 
+        	(CDROM_CONFIG_FLAGS(drive)->dvd_r)? "-R" : "", 
+        	(CDROM_CONFIG_FLAGS(drive)->dvd_ram)? "-RAM" : "");
+
+        if (CDROM_CONFIG_FLAGS(drive)->cd_r|CDROM_CONFIG_FLAGS(drive)->cd_rw) 
+        	printk(" CD%s%s", 
+        	(CDROM_CONFIG_FLAGS(drive)->cd_r)? "-R" : "", 
+        	(CDROM_CONFIG_FLAGS(drive)->cd_rw)? "/RW" : "");
 
-        if (CDROM_CONFIG_FLAGS (drive)->is_changer) 
-        	printk (" changer w/%d slots", nslots);
+        if (CDROM_CONFIG_FLAGS(drive)->is_changer) 
+        	printk(" changer w/%d slots", nslots);
         else 	
-        	printk (" drive");
+        	printk(" drive");
 
-	printk (", %dkB Cache", be16_to_cpu(cap.buffer_size));
+	printk(", %dkB Cache", be16_to_cpu(cap.buffer_size));
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (drive->using_dma)
-		(void) HWIF(drive)->dmaproc(ide_dma_verbose, drive);
+		(void) HWIF(drive)->ide_dma_verbose(drive);
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 	printk("\n");
 
@@ -2741,42 +2893,42 @@
 	drive->special.all	= 0;
 	drive->ready_stat	= 0;
 
-	CDROM_STATE_FLAGS (drive)->media_changed = 1;
-	CDROM_STATE_FLAGS (drive)->toc_valid     = 0;
-	CDROM_STATE_FLAGS (drive)->door_locked   = 0;
+	CDROM_STATE_FLAGS(drive)->media_changed = 1;
+	CDROM_STATE_FLAGS(drive)->toc_valid     = 0;
+	CDROM_STATE_FLAGS(drive)->door_locked   = 0;
 
 #if NO_DOOR_LOCKING
-	CDROM_CONFIG_FLAGS (drive)->no_doorlock = 1;
+	CDROM_CONFIG_FLAGS(drive)->no_doorlock = 1;
 #else
-	CDROM_CONFIG_FLAGS (drive)->no_doorlock = 0;
+	CDROM_CONFIG_FLAGS(drive)->no_doorlock = 0;
 #endif
 
 	if (drive->id != NULL)
-		CDROM_CONFIG_FLAGS (drive)->drq_interrupt =
+		CDROM_CONFIG_FLAGS(drive)->drq_interrupt =
 			((drive->id->config & 0x0060) == 0x20);
 	else
-		CDROM_CONFIG_FLAGS (drive)->drq_interrupt = 0;
+		CDROM_CONFIG_FLAGS(drive)->drq_interrupt = 0;
 
-	CDROM_CONFIG_FLAGS (drive)->is_changer = 0;
-	CDROM_CONFIG_FLAGS (drive)->cd_r = 0;
-	CDROM_CONFIG_FLAGS (drive)->cd_rw = 0;
-	CDROM_CONFIG_FLAGS (drive)->test_write = 0;
-	CDROM_CONFIG_FLAGS (drive)->dvd = 0;
-	CDROM_CONFIG_FLAGS (drive)->dvd_r = 0;
-	CDROM_CONFIG_FLAGS (drive)->dvd_ram = 0;
-	CDROM_CONFIG_FLAGS (drive)->no_eject = 1;
-	CDROM_CONFIG_FLAGS (drive)->supp_disc_present = 0;
-	CDROM_CONFIG_FLAGS (drive)->audio_play = 0;
-	CDROM_CONFIG_FLAGS (drive)->close_tray = 1;
+	CDROM_CONFIG_FLAGS(drive)->is_changer = 0;
+	CDROM_CONFIG_FLAGS(drive)->cd_r = 0;
+	CDROM_CONFIG_FLAGS(drive)->cd_rw = 0;
+	CDROM_CONFIG_FLAGS(drive)->test_write = 0;
+	CDROM_CONFIG_FLAGS(drive)->dvd = 0;
+	CDROM_CONFIG_FLAGS(drive)->dvd_r = 0;
+	CDROM_CONFIG_FLAGS(drive)->dvd_ram = 0;
+	CDROM_CONFIG_FLAGS(drive)->no_eject = 1;
+	CDROM_CONFIG_FLAGS(drive)->supp_disc_present = 0;
+	CDROM_CONFIG_FLAGS(drive)->audio_play = 0;
+	CDROM_CONFIG_FLAGS(drive)->close_tray = 1;
 	
 	/* limit transfer size per interrupt. */
-	CDROM_CONFIG_FLAGS (drive)->limit_nframes = 0;
+	CDROM_CONFIG_FLAGS(drive)->limit_nframes = 0;
 	if (drive->id != NULL) {
 		/* a testament to the nice quality of Samsung drives... */
 		if (!strcmp(drive->id->model, "SAMSUNG CD-ROM SCR-2430"))
-			CDROM_CONFIG_FLAGS (drive)->limit_nframes = 1;
+			CDROM_CONFIG_FLAGS(drive)->limit_nframes = 1;
 		else if (!strcmp(drive->id->model, "SAMSUNG CD-ROM SCR-2432"))
-			CDROM_CONFIG_FLAGS (drive)->limit_nframes = 1;
+			CDROM_CONFIG_FLAGS(drive)->limit_nframes = 1;
 		/* the 3231 model does not support the SET_CD_SPEED command */
 		else if (!strcmp(drive->id->model, "SAMSUNG CD-ROM SCR-3231"))
 			cdi->mask |= CDC_SELECT_SPEED;
@@ -2787,11 +2939,11 @@
            ATAPI Rev 2.2+ standard support for CD changers is used */
 	cdi->sanyo_slot = 0;
 
-	CDROM_CONFIG_FLAGS (drive)->nec260 = 0;
-	CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd = 0;
-	CDROM_CONFIG_FLAGS (drive)->tocaddr_as_bcd = 0;
-	CDROM_CONFIG_FLAGS (drive)->playmsf_as_bcd = 0;
-	CDROM_CONFIG_FLAGS (drive)->subchan_as_bcd = 0;
+	CDROM_CONFIG_FLAGS(drive)->nec260 = 0;
+	CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd = 0;
+	CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd = 0;
+	CDROM_CONFIG_FLAGS(drive)->playmsf_as_bcd = 0;
+	CDROM_CONFIG_FLAGS(drive)->subchan_as_bcd = 0;
 
 	if (drive->id != NULL) {
 		if (strcmp (drive->id->model, "V003S0DS") == 0 &&
@@ -2799,36 +2951,36 @@
 		    drive->id->fw_rev[6] <= '2') {
 			/* Vertos 300.
 			   Some versions of this drive like to talk BCD. */
-			CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd = 1;
-			CDROM_CONFIG_FLAGS (drive)->tocaddr_as_bcd = 1;
-			CDROM_CONFIG_FLAGS (drive)->playmsf_as_bcd = 1;
-			CDROM_CONFIG_FLAGS (drive)->subchan_as_bcd = 1;
+			CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd = 1;
+			CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd = 1;
+			CDROM_CONFIG_FLAGS(drive)->playmsf_as_bcd = 1;
+			CDROM_CONFIG_FLAGS(drive)->subchan_as_bcd = 1;
 		}
 
 		else if (strcmp (drive->id->model, "V006E0DS") == 0 &&
 		    drive->id->fw_rev[4] == '1' &&
 		    drive->id->fw_rev[6] <= '2') {
 			/* Vertos 600 ESD. */
-			CDROM_CONFIG_FLAGS (drive)->toctracks_as_bcd = 1;
+			CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd = 1;
 		}
 
-		else if (strcmp (drive->id->model,
+		else if (strcmp(drive->id->model,
 				 "NEC CD-ROM DRIVE:260") == 0 &&
-			 strncmp (drive->id->fw_rev, "1.01", 4) == 0) { /* FIXME */
+			 strncmp(drive->id->fw_rev, "1.01", 4) == 0) { /* FIXME */
 			/* Old NEC260 (not R).
 			   This drive was released before the 1.2 version
 			   of the spec. */
-			CDROM_CONFIG_FLAGS (drive)->tocaddr_as_bcd = 1;
-			CDROM_CONFIG_FLAGS (drive)->playmsf_as_bcd = 1;
-			CDROM_CONFIG_FLAGS (drive)->subchan_as_bcd = 1;
-			CDROM_CONFIG_FLAGS (drive)->nec260         = 1;
+			CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd = 1;
+			CDROM_CONFIG_FLAGS(drive)->playmsf_as_bcd = 1;
+			CDROM_CONFIG_FLAGS(drive)->subchan_as_bcd = 1;
+			CDROM_CONFIG_FLAGS(drive)->nec260         = 1;
 		}
 
-		else if (strcmp (drive->id->model, "WEARNES CDD-120") == 0 &&
-			 strncmp (drive->id->fw_rev, "A1.1", 4) == 0) { /* FIXME */
+		else if (strcmp(drive->id->model, "WEARNES CDD-120") == 0 &&
+			 strncmp(drive->id->fw_rev, "A1.1", 4) == 0) { /* FIXME */
 			/* Wearnes */
-			CDROM_CONFIG_FLAGS (drive)->playmsf_as_bcd = 1;
-			CDROM_CONFIG_FLAGS (drive)->subchan_as_bcd = 1;
+			CDROM_CONFIG_FLAGS(drive)->playmsf_as_bcd = 1;
+			CDROM_CONFIG_FLAGS(drive)->subchan_as_bcd = 1;
 		}
 
                 /* Sanyo 3 CD changer uses a non-standard command
@@ -2857,7 +3009,16 @@
 	if (CDROM_CONFIG_FLAGS(drive)->dvd_ram)
 		set_device_ro(MKDEV(HWIF(drive)->major, minor), 0);
 
-	if (ide_cdrom_register (drive, nslots)) {
+#if 0
+	drive->dsc_overlap = (HWIF(drive)->no_dsc) ? 0 : 1;
+	if (HWIF(drive)->no_dsc) {
+		printk(KERN_INFO "ide-cd: %s: disabling DSC overlap\n",
+			drive->name);
+		drive->dsc_overlap = 0;
+	}
+#endif
+
+	if (ide_cdrom_register(drive, nslots)) {
 		printk ("%s: ide_cdrom_setup failed to register device with the cdrom driver.\n", drive->name);
 		info->devinfo.handle = NULL;
 		return 1;
@@ -2872,7 +3033,7 @@
 		     struct inode *inode, struct file *file,
 		     unsigned int cmd, unsigned long arg)
 {
-	return cdrom_ioctl (inode, file, cmd, arg);
+	return cdrom_ioctl(inode, file, cmd, arg);
 }
 
 static
@@ -2902,7 +3063,7 @@
 static
 int ide_cdrom_check_media_change (ide_drive_t *drive)
 {
-	return cdrom_media_changed(MKDEV (HWIF (drive)->major,
+	return cdrom_media_changed(MKDEV (HWIF(drive)->major,
 			(drive->select.b.unit) << PARTN_BITS));
 }
 
@@ -2950,22 +3111,26 @@
 	struct cdrom_info *info = drive->driver_data;
 	struct cdrom_device_info *devinfo = &info->devinfo;
 
-	if (ide_unregister_subdriver (drive))
+	if (ide_unregister_subdriver(drive)) {
+		printk("%s: %s: failed to ide_unregister_subdriver\n",
+			__FUNCTION__, drive->name);
 		return 1;
+	}
 	if (info->buffer != NULL)
 		kfree(info->buffer);
 	if (info->toc != NULL)
 		kfree(info->toc);
 	if (info->changer_info != NULL)
 		kfree(info->changer_info);
-	if (devinfo->handle == drive && unregister_cdrom (devinfo))
-		printk ("%s: ide_cdrom_cleanup failed to unregister device from the cdrom driver.\n", drive->name);
+	if (devinfo->handle == drive && unregister_cdrom(devinfo))
+		printk("%s: ide_cdrom_cleanup failed to unregister device from the cdrom driver.\n", drive->name);
 	kfree(info);
 	drive->driver_data = NULL;
 	return 0;
 }
 
-int ide_cdrom_reinit (ide_drive_t *drive);
+int ide_cdrom_init(void);
+int ide_cdrom_attach (ide_drive_t *drive);
 
 static ide_driver_t ide_cdrom_driver = {
 	name:			"ide-cdrom",
@@ -2976,9 +3141,13 @@
 	supports_dsc_overlap:	1,
 	cleanup:		ide_cdrom_cleanup,
 	standby:		NULL,
+	suspend:		NULL,
+	resume:			NULL,
 	flushcache:		NULL,
 	do_request:		ide_do_rw_cdrom,
-	end_request:		NULL,
+	end_request:		ide_cdrom_end_request,
+	sense:			ide_cdrom_dump_status,
+	error:			ide_cdrom_error,
 	ioctl:			ide_cdrom_ioctl,
 	open:			ide_cdrom_open,
 	release:		ide_cdrom_release,
@@ -2988,12 +3157,12 @@
 	capacity:		ide_cdrom_capacity,
 	special:		NULL,
 	proc:			NULL,
-	reinit:			ide_cdrom_reinit,
+	init:			ide_cdrom_init,
+	attach:			ide_cdrom_attach,
 	ata_prebuilder:		NULL,
 	atapi_prebuilder:	NULL,
 };
 
-int ide_cdrom_init(void);
 static ide_module_t ide_cdrom_module = {
 	IDE_DRIVER_MODULE,
 	ide_cdrom_init,
@@ -3007,35 +3176,46 @@
 MODULE_PARM(ignore, "s");
 MODULE_DESCRIPTION("ATAPI CD-ROM Driver");
 
-int ide_cdrom_reinit (ide_drive_t *drive)
+int ide_cdrom_attach (ide_drive_t *drive)
 {
 	struct cdrom_info *info;
 	int failed = 0;
 
+	if (drive->scsi) {
+		printk("ide-cd: passing drive %s to ide-scsi emulation.\n",
+			drive->name);
+		return 1;
+	}
+
 	MOD_INC_USE_COUNT;
 	info = (struct cdrom_info *) kmalloc (sizeof (struct cdrom_info), GFP_KERNEL);
 	if (info == NULL) {
-		printk ("%s: Can't allocate a cdrom structure\n", drive->name);
+		printk("%s: Can't allocate a cdrom structure\n", drive->name);
+		MOD_DEC_USE_COUNT;
 		return 1;
 	}
-	if (ide_register_subdriver (drive, &ide_cdrom_driver, IDE_SUBDRIVER_VERSION)) {
-		printk ("%s: Failed to register the driver with ide.c\n", drive->name);
-		kfree (info);
+	if (ide_register_subdriver(drive,
+			&ide_cdrom_driver, IDE_SUBDRIVER_VERSION)) {
+		printk(KERN_ERR "ide-cd: %s: Failed to register the driver "
+			"with ide.c\n", drive->name);
+		kfree(info);
+		MOD_DEC_USE_COUNT;
 		return 1;
 	}
-	memset (info, 0, sizeof (struct cdrom_info));
+	memset(info, 0, sizeof(struct cdrom_info));
 	drive->driver_data = info;
 	DRIVER(drive)->busy++;
-	if (ide_cdrom_setup (drive)) {
+	if (ide_cdrom_setup(drive)) {
 		DRIVER(drive)->busy--;
-		if (ide_cdrom_cleanup (drive))
-			printk ("%s: ide_cdrom_cleanup failed in ide_cdrom_init\n", drive->name);
+		if (ide_cdrom_cleanup(drive))
+			printk("%s: ide_cdrom_cleanup failed in "
+				"ide_cdrom_init\n", drive->name);
+		MOD_DEC_USE_COUNT;
 		return 1;
 	}
 	DRIVER(drive)->busy--;
 	failed--;
 
-	ide_register_module(&ide_cdrom_module);
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
@@ -3045,41 +3225,51 @@
 	ide_drive_t *drive;
 	int failed = 0;
 
-	while ((drive = ide_scan_devices (ide_cdrom, ide_cdrom_driver.name, &ide_cdrom_driver, failed)) != NULL)
-		if (ide_cdrom_cleanup (drive)) {
-			printk ("%s: cleanup_module() called while still busy\n", drive->name);
+	while ((drive = ide_scan_devices(ide_cdrom, ide_cdrom_driver.name,
+			&ide_cdrom_driver, failed)) != NULL)
+		if (ide_cdrom_cleanup(drive)) {
+			printk("%s: cleanup_module() called while still "
+				"busy\n", drive->name);
 			failed++;
 		}
-	ide_unregister_module (&ide_cdrom_module);
+	ide_unregister_module(&ide_cdrom_module);
 }
- 
+
 int ide_cdrom_init(void)
 {
+#ifdef CLASSIC_BUILTINS_METHOD
 	ide_drive_t *drive;
 	struct cdrom_info *info;
 	int failed = 0;
-
+#endif /* CLASSIC_BUILTINS_METHOD */
 	MOD_INC_USE_COUNT;
-	while ((drive = ide_scan_devices (ide_cdrom, ide_cdrom_driver.name, NULL, failed++)) != NULL) {
+#ifdef CLASSIC_BUILTINS_METHOD
+	while ((drive = ide_scan_devices(ide_cdrom,
+			ide_cdrom_driver.name, NULL, failed++)) != NULL) {
 		/* skip drives that we were told to ignore */
 		if (ignore != NULL) {
 			if (strstr(ignore, drive->name)) {
-				printk("ide-cd: ignoring drive %s\n", drive->name);
+				printk("ide-cd: ignoring drive %s\n",
+					drive->name);
 				continue;
 			}
 		}
 		if (drive->scsi) {
-			printk("ide-cd: passing drive %s to ide-scsi emulation.\n", drive->name);
+			printk("ide-cd: passing drive %s to ide-scsi "
+				"emulation.\n", drive->name);
 			continue;
 		}
 		info = (struct cdrom_info *) kmalloc (sizeof (struct cdrom_info), GFP_KERNEL);
 		if (info == NULL) {
-			printk ("%s: Can't allocate a cdrom structure\n", drive->name);
+			printk ("%s: Can't allocate a cdrom structure\n",
+				drive->name);
 			continue;
 		}
-		if (ide_register_subdriver (drive, &ide_cdrom_driver, IDE_SUBDRIVER_VERSION)) {
-			printk ("%s: Failed to register the driver with ide.c\n", drive->name);
-			kfree (info);
+		if (ide_register_subdriver(drive, 
+				&ide_cdrom_driver, IDE_SUBDRIVER_VERSION)) {
+			printk("%s: Failed to register the driver with "
+				"ide.c\n", drive->name);
+			kfree(info);
 			continue;
 		}
 		memset (info, 0, sizeof (struct cdrom_info));
@@ -3088,12 +3278,14 @@
 		if (ide_cdrom_setup (drive)) {
 			DRIVER(drive)->busy--;
 			if (ide_cdrom_cleanup (drive))
-				printk ("%s: ide_cdrom_cleanup failed in ide_cdrom_init\n", drive->name);
+				printk ("%s: ide_cdrom_cleanup failed in "
+					"ide_cdrom_init\n", drive->name);
 			continue;
 		}
 		DRIVER(drive)->busy--;
 		failed--;
 	}
+#endif /* CLASSIC_BUILTINS_METHOD */
 	ide_register_module(&ide_cdrom_module);
 	MOD_DEC_USE_COUNT;
 	return 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-cd.h linux-2.4.21-pre6/drivers/ide/ide-cd.h
--- linux-2.4.20/drivers/ide/ide-cd.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/ide-cd.h	2003-03-26 23:49:54.000000000 +0000
@@ -437,7 +437,7 @@
 
 	byte     curlba[3];
 	byte     nslots;
-	__u8 short slot_tablelen;
+	__u16	slot_tablelen;
 };
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-cs.c linux-2.4.21-pre6/drivers/ide/ide-cs.c
--- linux-2.4.20/drivers/ide/ide-cs.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/ide-cs.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,492 +0,0 @@
-/*======================================================================
-
-    A driver for PCMCIA IDE/ATA disk cards
-
-    ide_cs.c 1.26 1999/11/16 02:10:49
-
-    The contents of this file are subject to the Mozilla Public
-    License Version 1.1 (the "License"); you may not use this file
-    except in compliance with the License. You may obtain a copy of
-    the License at http://www.mozilla.org/MPL/
-
-    Software distributed under the License is distributed on an "AS
-    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
-    implied. See the License for the specific language governing
-    rights and limitations under the License.
-
-    The initial developer of the original code is David A. Hinds
-    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
-    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
-
-    Alternatively, the contents of this file may be used under the
-    terms of the GNU General Public License version 2 (the "GPL"), in which
-    case the provisions of the GPL are applicable instead of the
-    above.  If you wish to allow the use of your version of this file
-    only under the terms of the GPL and not to allow others to use
-    your version of this file under the MPL, indicate your decision
-    by deleting the provisions above and replace them with the notice
-    and other provisions required by the GPL.  If you do not delete
-    the provisions above, a recipient may use your version of this
-    file under either the MPL or the GPL.
-    
-======================================================================*/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/ioport.h>
-#include <linux/hdreg.h>
-#include <linux/major.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-#include <asm/system.h>
-
-#include <pcmcia/version.h>
-#include <pcmcia/cs_types.h>
-#include <pcmcia/cs.h>
-#include <pcmcia/cistpl.h>
-#include <pcmcia/ds.h>
-#include <pcmcia/cisreg.h>
-
-#ifdef PCMCIA_DEBUG
-static int pc_debug = PCMCIA_DEBUG;
-MODULE_PARM(pc_debug, "i");
-#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
-static char *version =
-"ide_cs.c 1.26 1999/11/16 02:10:49 (David Hinds)";
-#else
-#define DEBUG(n, args...)
-#endif
-
-/*====================================================================*/
-
-/* Parameters that can be set with 'insmod' */
-
-/* Bit map of interrupts to choose from */
-static u_int irq_mask = 0xdeb8;
-static int irq_list[4] = { -1 };
-
-MODULE_PARM(irq_mask, "i");
-MODULE_PARM(irq_list, "1-4i");
-
-MODULE_LICENSE("GPL");
-
-
-/*====================================================================*/
-
-static const char ide_major[] = {
-    IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR,
-#ifdef IDE4_MAJOR
-    IDE4_MAJOR, IDE5_MAJOR
-#endif
-};
-
-typedef struct ide_info_t {
-    dev_link_t	link;
-    int		ndev;
-    dev_node_t	node;
-    int		hd;
-} ide_info_t;
-
-static void ide_config(dev_link_t *link);
-static void ide_release(u_long arg);
-static int ide_event(event_t event, int priority,
-		     event_callback_args_t *args);
-
-static dev_info_t dev_info = "ide-cs";
-
-static dev_link_t *ide_attach(void);
-static void ide_detach(dev_link_t *);
-
-static dev_link_t *dev_list = NULL;
-
-/*====================================================================*/
-
-static void cs_error(client_handle_t handle, int func, int ret)
-{
-    error_info_t err = { func, ret };
-    CardServices(ReportError, handle, &err);
-}
-
-/*======================================================================
-
-    ide_attach() creates an "instance" of the driver, allocating
-    local data structures for one device.  The device is registered
-    with Card Services.
-
-======================================================================*/
-
-static dev_link_t *ide_attach(void)
-{
-    ide_info_t *info;
-    dev_link_t *link;
-    client_reg_t client_reg;
-    int i, ret;
-    
-    DEBUG(0, "ide_attach()\n");
-
-    /* Create new ide device */
-    info = kmalloc(sizeof(*info), GFP_KERNEL);
-    if (!info) return NULL;
-    memset(info, 0, sizeof(*info));
-    link = &info->link; link->priv = info;
-
-    link->release.function = &ide_release;
-    link->release.data = (u_long)link;
-    link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
-    link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
-    link->io.IOAddrLines = 3;
-    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
-    link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
-    if (irq_list[0] == -1)
-	link->irq.IRQInfo2 = irq_mask;
-    else
-	for (i = 0; i < 4; i++)
-	    link->irq.IRQInfo2 |= 1 << irq_list[i];
-    link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.Vcc = 50;
-    link->conf.IntType = INT_MEMORY_AND_IO;
-    
-    /* Register with Card Services */
-    link->next = dev_list;
-    dev_list = link;
-    client_reg.dev_info = &dev_info;
-    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
-    client_reg.EventMask =
-	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-    client_reg.event_handler = &ide_event;
-    client_reg.Version = 0x0210;
-    client_reg.event_callback_args.client_data = link;
-    ret = CardServices(RegisterClient, &link->handle, &client_reg);
-    if (ret != CS_SUCCESS) {
-	cs_error(link->handle, RegisterClient, ret);
-	ide_detach(link);
-	return NULL;
-    }
-    
-    return link;
-} /* ide_attach */
-
-/*======================================================================
-
-    This deletes a driver "instance".  The device is de-registered
-    with Card Services.  If it has been released, all local data
-    structures are freed.  Otherwise, the structures will be freed
-    when the device is released.
-
-======================================================================*/
-
-static void ide_detach(dev_link_t *link)
-{
-    dev_link_t **linkp;
-    int ret;
-
-    DEBUG(0, "ide_detach(0x%p)\n", link);
-    
-    /* Locate device structure */
-    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
-	if (*linkp == link) break;
-    if (*linkp == NULL)
-	return;
-
-    del_timer(&link->release);
-    if (link->state & DEV_CONFIG)
-	ide_release((u_long)link);
-    
-    if (link->handle) {
-	ret = CardServices(DeregisterClient, link->handle);
-	if (ret != CS_SUCCESS)
-	    cs_error(link->handle, DeregisterClient, ret);
-    }
-    
-    /* Unlink, free device structure */
-    *linkp = link->next;
-    kfree(link->priv);
-    
-} /* ide_detach */
-
-/*======================================================================
-
-    ide_config() is scheduled to run after a CARD_INSERTION event
-    is received, to configure the PCMCIA socket, and to make the
-    ide device available to the system.
-
-======================================================================*/
-
-#define CS_CHECK(fn, args...) \
-while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
-
-#define CFG_CHECK(fn, args...) \
-if (CardServices(fn, args) != 0) goto next_entry
-
-int idecs_register (int arg1, int arg2, int irq)
-{
-        hw_regs_t hw;
-        ide_init_hwif_ports(&hw, (ide_ioreg_t) arg1, (ide_ioreg_t) arg2, NULL);
-        hw.irq = irq;
-        hw.chipset = ide_pci; /* this enables IRQ sharing w/ PCI irqs */
-        return ide_register_hw(&hw, NULL);
-}
-
-void ide_config(dev_link_t *link)
-{
-    client_handle_t handle = link->handle;
-    ide_info_t *info = link->priv;
-    tuple_t tuple;
-    u_short buf[128];
-    cisparse_t parse;
-    config_info_t conf;
-    cistpl_cftable_entry_t *cfg = &parse.cftable_entry;
-    cistpl_cftable_entry_t dflt = { 0 };
-    int i, pass, last_ret, last_fn, hd=-1, io_base, ctl_base;
-
-    DEBUG(0, "ide_config(0x%p)\n", link);
-    
-    tuple.TupleData = (cisdata_t *)buf;
-    tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
-    tuple.Attributes = 0;
-    tuple.DesiredTuple = CISTPL_CONFIG;
-    CS_CHECK(GetFirstTuple, handle, &tuple);
-    CS_CHECK(GetTupleData, handle, &tuple);
-    CS_CHECK(ParseTuple, handle, &tuple, &parse);
-    link->conf.ConfigBase = parse.config.base;
-    link->conf.Present = parse.config.rmask[0];
-    
-    /* Configure card */
-    link->state |= DEV_CONFIG;
-
-    /* Not sure if this is right... look up the current Vcc */
-    CS_CHECK(GetConfigurationInfo, handle, &conf);
-    link->conf.Vcc = conf.Vcc;
-    
-    pass = io_base = ctl_base = 0;
-    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-    tuple.Attributes = 0;
-    CS_CHECK(GetFirstTuple, handle, &tuple);
-    while (1) {
-	CFG_CHECK(GetTupleData, handle, &tuple);
-	CFG_CHECK(ParseTuple, handle, &tuple, &parse);
-
-	/* Check for matching Vcc, unless we're desperate */
-	if (!pass) {
-	    if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
-		if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000)
-		    goto next_entry;
-	    } else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) {
-		if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM]/10000)
-		    goto next_entry;
-	    }
-	}
-	
-	if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
-	    link->conf.Vpp1 = link->conf.Vpp2 =
-		cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
-	else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM))
-	    link->conf.Vpp1 = link->conf.Vpp2 =
-		dflt.vpp1.param[CISTPL_POWER_VNOM]/10000;
-	
-	if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
-	    cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
-	    link->conf.ConfigIndex = cfg->index;
-	    link->io.BasePort1 = io->win[0].base;
-	    link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
-	    if (!(io->flags & CISTPL_IO_16BIT))
-		link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-	    if (io->nwin == 2) {
-		link->io.NumPorts1 = 8;
-		link->io.BasePort2 = io->win[1].base;
-		link->io.NumPorts2 = 1;
-		CFG_CHECK(RequestIO, link->handle, &link->io);
-		io_base = link->io.BasePort1;
-		ctl_base = link->io.BasePort2;
-	    } else if ((io->nwin == 1) && (io->win[0].len >= 16)) {
-		link->io.NumPorts1 = io->win[0].len;
-		link->io.NumPorts2 = 0;
-		CFG_CHECK(RequestIO, link->handle, &link->io);
-		io_base = link->io.BasePort1;
-		ctl_base = link->io.BasePort1+0x0e;
-	    } else goto next_entry;
-	    /* If we've got this far, we're done */
-	    break;
-	}
-	
-    next_entry:
-	if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
-	if (pass) {
-	    CS_CHECK(GetNextTuple, handle, &tuple);
-	} else if (CardServices(GetNextTuple, handle, &tuple) != 0) {
-	    CS_CHECK(GetFirstTuple, handle, &tuple);
-	    memset(&dflt, 0, sizeof(dflt));
-	    pass++;
-	}
-    }
-    
-    CS_CHECK(RequestIRQ, handle, &link->irq);
-    CS_CHECK(RequestConfiguration, handle, &link->conf);
-
-    /* deal with brain dead IDE resource management */
-    release_region(link->io.BasePort1, link->io.NumPorts1);
-    if (link->io.NumPorts2)
-	release_region(link->io.BasePort2, link->io.NumPorts2);
-
-    /* retry registration in case device is still spinning up */
-    for (i = 0; i < 10; i++) {
-	if (ctl_base)
-	    outb(0x02, ctl_base); /* Set nIEN = disable device interrupts */
-	hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ);
-	if (hd >= 0) break;
-	if (link->io.NumPorts1 == 0x20) {
-	    if (ctl_base)
-		outb(0x02, ctl_base+0x10);
-	    hd = idecs_register(io_base+0x10, ctl_base+0x10,
-			      link->irq.AssignedIRQ);
-	    if (hd >= 0) {
-		io_base += 0x10; ctl_base += 0x10;
-		break;
-	    }
-	}
-	__set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(HZ/10);
-    }
-    
-    if (hd < 0) {
-	printk(KERN_NOTICE "ide_cs: ide_register() at 0x%03x & 0x%03x"
-	       ", irq %u failed\n", io_base, ctl_base,
-	       link->irq.AssignedIRQ);
-	goto failed;
-    }
-
-    MOD_INC_USE_COUNT;
-    info->ndev = 1;
-    sprintf(info->node.dev_name, "hd%c", 'a'+(hd*2));
-    info->node.major = ide_major[hd];
-    info->node.minor = 0;
-    info->hd = hd;
-    link->dev = &info->node;
-    printk(KERN_INFO "ide_cs: %s: Vcc = %d.%d, Vpp = %d.%d\n",
-	   info->node.dev_name, link->conf.Vcc/10, link->conf.Vcc%10,
-	   link->conf.Vpp1/10, link->conf.Vpp1%10);
-
-    link->state &= ~DEV_CONFIG_PENDING;
-    return;
-    
-cs_failed:
-    cs_error(link->handle, last_fn, last_ret);
-failed:
-    ide_release((u_long)link);
-
-} /* ide_config */
-
-/*======================================================================
-
-    After a card is removed, ide_release() will unregister the net
-    device, and release the PCMCIA configuration.  If the device is
-    still open, this will be postponed until it is closed.
-    
-======================================================================*/
-
-void ide_release(u_long arg)
-{
-    dev_link_t *link = (dev_link_t *)arg;
-    ide_info_t *info = link->priv;
-    
-    DEBUG(0, "ide_release(0x%p)\n", link);
-
-    if (info->ndev) {
-	ide_unregister(info->hd);
-	MOD_DEC_USE_COUNT;
-    }
-
-    request_region(link->io.BasePort1, link->io.NumPorts1,"ide-cs");
-    if (link->io.NumPorts2)
-	request_region(link->io.BasePort2, link->io.NumPorts2,"ide-cs");
-    
-    info->ndev = 0;
-    link->dev = NULL;
-    
-    CardServices(ReleaseConfiguration, link->handle);
-    CardServices(ReleaseIO, link->handle, &link->io);
-    CardServices(ReleaseIRQ, link->handle, &link->irq);
-    
-    link->state &= ~DEV_CONFIG;
-
-} /* ide_release */
-
-/*======================================================================
-
-    The card status event handler.  Mostly, this schedules other
-    stuff to run after an event is received.  A CARD_REMOVAL event
-    also sets some flags to discourage the ide drivers from
-    talking to the ports.
-    
-======================================================================*/
-
-int ide_event(event_t event, int priority,
-	      event_callback_args_t *args)
-{
-    dev_link_t *link = args->client_data;
-
-    DEBUG(1, "ide_event(0x%06x)\n", event);
-    
-    switch (event) {
-    case CS_EVENT_CARD_REMOVAL:
-	link->state &= ~DEV_PRESENT;
-	if (link->state & DEV_CONFIG)
-	    mod_timer(&link->release, jiffies + HZ/20);
-	break;
-    case CS_EVENT_CARD_INSERTION:
-	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-	ide_config(link);
-	break;
-    case CS_EVENT_PM_SUSPEND:
-	link->state |= DEV_SUSPEND;
-	/* Fall through... */
-    case CS_EVENT_RESET_PHYSICAL:
-	if (link->state & DEV_CONFIG)
-	    CardServices(ReleaseConfiguration, link->handle);
-	break;
-    case CS_EVENT_PM_RESUME:
-	link->state &= ~DEV_SUSPEND;
-	/* Fall through... */
-    case CS_EVENT_CARD_RESET:
-	if (DEV_OK(link))
-	    CardServices(RequestConfiguration, link->handle, &link->conf);
-	break;
-    }
-    return 0;
-} /* ide_event */
-
-/*====================================================================*/
-
-static int __init init_ide_cs(void)
-{
-    servinfo_t serv;
-    DEBUG(0, "%s\n", version);
-    CardServices(GetCardServicesInfo, &serv);
-    if (serv.Revision != CS_RELEASE_CODE) {
-	printk(KERN_NOTICE "ide_cs: Card Services release "
-	       "does not match!\n");
-	return -1;
-    }
-    register_pccard_driver(&dev_info, &ide_attach, &ide_detach);
-    return 0;
-}
-
-static void __exit exit_ide_cs(void)
-{
-    DEBUG(0, "ide_cs: unloading\n");
-    unregister_pccard_driver(&dev_info);
-    while (dev_list != NULL)
-	ide_detach(dev_list);
-}
-
-module_init(init_ide_cs);
-module_exit(exit_ide_cs);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-disk.c linux-2.4.21-pre6/drivers/ide/ide-disk.c
--- linux-2.4.20/drivers/ide/ide-disk.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/ide-disk.c	2003-03-26 23:48:57.000000000 +0000
@@ -1,5 +1,9 @@
 /*
- *  linux/drivers/ide/ide-disk.c	Version 1.10	June 9, 2000
+ *  linux/drivers/ide/ide-disk.c	Version 1.16	April 7, 2002
+ *
+ *  Copyright (C) 1998-2002  Linux ATA Developemt
+ *				Andre Hedrick <andre@linux-ide.org>
+ *
  *
  *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
  */
@@ -29,10 +33,14 @@
  * Version 1.10		request queue changes, Ultra DMA 100
  * Version 1.11		added 48-bit lba
  * Version 1.12		adding taskfile io access method
- *			Highmem I/O support, Jens Axboe <axboe@suse.de>
+ * Version 1.13		added standby and flush-cache for notifier
+ * Version 1.14		added acoustic-wcache
+ * Version 1.15		convert all calls to ide_raw_taskfile
+ *				since args will return register content.
+ * Version 1.16		added suspend-resume-checkpower
  */
 
-#define IDEDISK_VERSION	"1.12"
+#define IDEDISK_VERSION	"1.16"
 
 #undef REALLY_SLOW_IO		/* most systems can safely undef this */
 
@@ -49,6 +57,9 @@
 #include <linux/genhd.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
+
+#define _IDE_DISK
+
 #include <linux/ide.h>
 
 #include <asm/byteorder.h>
@@ -56,48 +67,27 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
-#ifdef CONFIG_BLK_DEV_PDC4030
-#define IS_PDC4030_DRIVE (HWIF(drive)->chipset == ide_pdc4030)
-#else
-#define IS_PDC4030_DRIVE (0)	/* auto-NULLs out pdc4030 code */
-#endif
-
-#ifdef CONFIG_IDE_TASKFILE_IO
-#  undef __TASKFILE__IO /* define __TASKFILE__IO */
-#else /* CONFIG_IDE_TASKFILE_IO */
-#  undef __TASKFILE__IO
-#endif /* CONFIG_IDE_TASKFILE_IO */
+/* FIXME: soem day we shouldnt need to look in here! */
 
-#ifndef __TASKFILE__IO
-
-static void idedisk_bswap_data (void *buffer, int wcount)
-{
-	u16 *p = buffer;
-
-	while (wcount--) {
-		*p = *p << 8 | *p >> 8; p++;
-		*p = *p << 8 | *p >> 8; p++;
-	}
-}
+#include "legacy/pdc4030.h"
 
-static inline void idedisk_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
-{
-	ide_input_data(drive, buffer, wcount);
-	if (drive->bswap)
-		idedisk_bswap_data(buffer, wcount);
-}
+static int driver_blocked;
 
-static inline void idedisk_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+static inline u32 idedisk_read_24 (ide_drive_t *drive)
 {
-	if (drive->bswap) {
-		idedisk_bswap_data(buffer, wcount);
-		ide_output_data(drive, buffer, wcount);
-		idedisk_bswap_data(buffer, wcount);
-	} else
-		ide_output_data(drive, buffer, wcount);
+#if 0
+	return	(HWIF(drive)->INB(IDE_HCYL_REG)<<16) |
+		(HWIF(drive)->INB(IDE_LCYL_REG)<<8) |
+		 HWIF(drive)->INB(IDE_SECTOR_REG);
+#else
+	u8 hcyl = HWIF(drive)->INB(IDE_HCYL_REG);
+	u8 lcyl = HWIF(drive)->INB(IDE_LCYL_REG);
+	u8 sect = HWIF(drive)->INB(IDE_SECTOR_REG);
+	return (hcyl<<16)|(lcyl<<8)|sect;
+#endif
 }
 
-#endif /* __TASKFILE__IO */
+static int idedisk_end_request(ide_drive_t *drive, int uptodate);
 
 /*
  * lba_capacity_is_ok() performs a sanity check on the claimed "lba_capacity"
@@ -127,7 +117,7 @@
 	     || (id->cyls == 4092 && id->cur_cyls == 16383)) &&
 	    id->sectors == 63 &&
 	    (id->heads == 15 || id->heads == 16) &&
-	    id->lba_capacity >= 16383*63*id->heads)
+	    (id->lba_capacity >= 16383*63*id->heads))
 		return 1;
 
 	lba_sects   = id->lba_capacity;
@@ -149,31 +139,32 @@
 	return 0;	/* lba_capacity value may be bad */
 }
 
-#ifndef __TASKFILE__IO
+#ifndef CONFIG_IDE_TASKFILE_IO
 
 /*
  * read_intr() is the handler for disk read/multread interrupts
  */
 static ide_startstop_t read_intr (ide_drive_t *drive)
 {
-	byte stat;
-	int i;
-	unsigned int msect, nsect;
-	unsigned long flags;
+	ide_hwif_t *hwif	= HWIF(drive);
+	u32 i = 0, nsect	= 0, msect = drive->mult_count;
 	struct request *rq;
+	unsigned long flags;
+	u8 stat;
 	char *to;
 
 	/* new way for dealing with premature shared PCI interrupts */
-	if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) {
+	if (!OK_STAT(stat=hwif->INB(IDE_STATUS_REG),DATA_READY,BAD_R_STAT)) {
 		if (stat & (ERR_STAT|DRQ_STAT)) {
-			return ide_error(drive, "read_intr", stat);
+			return DRIVER(drive)->error(drive, "read_intr", stat);
 		}
 		/* no data yet, so wait for another interrupt */
+		if (HWGROUP(drive)->handler != NULL)
+			BUG();
 		ide_set_handler(drive, &read_intr, WAIT_CMD, NULL);
 		return ide_started;
 	}
-
-	msect = drive->mult_count;
+	
 read_next:
 	rq = HWGROUP(drive)->rq;
 	if (msect) {
@@ -183,22 +174,31 @@
 	} else
 		nsect = 1;
 	to = ide_map_buffer(rq, &flags);
-	idedisk_input_data(drive, to, nsect * SECTOR_WORDS);
+	taskfile_input_data(drive, to, nsect * SECTOR_WORDS);
+
 #ifdef DEBUG
 	printk("%s:  read: sectors(%ld-%ld), buffer=0x%08lx, remaining=%ld\n",
 		drive->name, rq->sector, rq->sector+nsect-1,
 		(unsigned long) rq->buffer+(nsect<<9), rq->nr_sectors-nsect);
 #endif
+
 	ide_unmap_buffer(to, &flags);
 	rq->sector += nsect;
 	rq->errors = 0;
 	i = (rq->nr_sectors -= nsect);
 	if (((long)(rq->current_nr_sectors -= nsect)) <= 0)
-		ide_end_request(1, HWGROUP(drive));
+		idedisk_end_request(drive, 1);
+	/*
+	 * Another BH Page walker and DATA INTERGRITY Questioned on ERROR.
+	 * If passed back up on multimode read, BAD DATA could be ACKED
+	 * to FILE SYSTEMS above ...
+	 */
 	if (i > 0) {
 		if (msect)
 			goto read_next;
-		ide_set_handler (drive, &read_intr, WAIT_CMD, NULL);
+		if (HWGROUP(drive)->handler != NULL)
+			BUG();
+		ide_set_handler(drive, &read_intr, WAIT_CMD, NULL);
                 return ide_started;
 	}
         return ide_stopped;
@@ -209,13 +209,16 @@
  */
 static ide_startstop_t write_intr (ide_drive_t *drive)
 {
-	byte stat;
-	int i;
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	struct request *rq = hwgroup->rq;
-
-	if (!OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) {
-		printk("%s: write_intr error1: nr_sectors=%ld, stat=0x%02x\n", drive->name, rq->nr_sectors, stat);
+	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct request *rq	= hwgroup->rq;
+	u32 i = 0;
+	u8 stat;
+
+	if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG),
+			DRIVE_READY, drive->bad_wstat)) {
+		printk("%s: write_intr error1: nr_sectors=%ld, stat=0x%02x\n",
+			drive->name, rq->nr_sectors, stat);
         } else {
 #ifdef DEBUG
 		printk("%s: write: sector %ld, buffer=0x%08lx, remaining=%ld\n",
@@ -228,20 +231,23 @@
 			i = --rq->nr_sectors;
 			--rq->current_nr_sectors;
 			if (((long)rq->current_nr_sectors) <= 0)
-				ide_end_request(1, hwgroup);
+				idedisk_end_request(drive, 1);
 			if (i > 0) {
 				unsigned long flags;
 				char *to = ide_map_buffer(rq, &flags);
-				idedisk_output_data (drive, to, SECTOR_WORDS);
+				taskfile_output_data(drive, to, SECTOR_WORDS);
 				ide_unmap_buffer(to, &flags);
-				ide_set_handler (drive, &write_intr, WAIT_CMD, NULL);
+				if (HWGROUP(drive)->handler != NULL)
+					BUG();
+				ide_set_handler(drive, &write_intr, WAIT_CMD, NULL);
                                 return ide_started;
 			}
                         return ide_stopped;
 		}
-		return ide_stopped;	/* the original code did this here (?) */
+		/* the original code did this here (?) */
+		return ide_stopped;
 	}
-	return ide_error(drive, "write_intr", stat);
+	return DRIVER(drive)->error(drive, "write_intr", stat);
 }
 
 /*
@@ -254,22 +260,27 @@
  * and IRQ context. The IRQ can happen any time after we've output the
  * full "mcount" number of sectors, so we must make sure we update the
  * state _before_ we output the final part of the data!
+ *
+ * The update and return to BH is a BLOCK Layer Fakey to get more data
+ * to satisfy the hardware atomic segment.  If the hardware atomic segment
+ * is shorter or smaller than the BH segment then we should be OKAY.
+ * This is only valid if we can rewind the rq->current_nr_sectors counter.
  */
 int ide_multwrite (ide_drive_t *drive, unsigned int mcount)
 {
- 	ide_hwgroup_t	*hwgroup= HWGROUP(drive);
- 	struct request	*rq = &hwgroup->wrq;
+ 	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
+ 	struct request *rq	= &hwgroup->wrq;
  
   	do {
   		char *buffer;
   		int nsect = rq->current_nr_sectors;
 		unsigned long flags;
-
+ 
 		if (nsect > mcount)
 			nsect = mcount;
 		mcount -= nsect;
-
 		buffer = ide_map_buffer(rq, &flags);
+
 		rq->sector += nsect;
 		rq->nr_sectors -= nsect;
 		rq->current_nr_sectors -= nsect;
@@ -285,6 +296,7 @@
 				rq->bh = bh;
 				rq->current_nr_sectors = bh->b_size >> 9;
 				rq->hard_cur_sectors = rq->current_nr_sectors;
+				rq->buffer             = bh->b_data;
 			}
 		}
 
@@ -292,7 +304,7 @@
 		 * Ok, we're all setup for the interrupt
 		 * re-entering us on the last transfer.
 		 */
-		idedisk_output_data(drive, buffer, nsect<<7);
+		taskfile_output_data(drive, buffer, nsect<<7);
 		ide_unmap_buffer(buffer, &flags);
 	} while (mcount);
 
@@ -304,12 +316,14 @@
  */
 static ide_startstop_t multwrite_intr (ide_drive_t *drive)
 {
-	byte stat;
-	int i;
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	struct request *rq = &hwgroup->wrq;
+	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct request *rq	= &hwgroup->wrq;
+	u32 i = 0;
+	u8 stat;
 
-	if (OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) {
+	if (OK_STAT(stat = hwif->INB(IDE_STATUS_REG),
+			DRIVE_READY, drive->bad_wstat)) {
 		if (stat & DRQ_STAT) {
 			/*
 			 *	The drive wants data. Remember rq is the copy
@@ -318,7 +332,9 @@
 			if (rq->nr_sectors) {
 				if (ide_multwrite(drive, drive->mult_count))
 					return ide_stopped;
-				ide_set_handler (drive, &multwrite_intr, WAIT_CMD, NULL);
+				if (HWGROUP(drive)->handler != NULL)
+					BUG();
+				ide_set_handler(drive, &multwrite_intr, WAIT_CMD, NULL);
 				return ide_started;
 			}
 		} else {
@@ -328,24 +344,19 @@
 			 */
 			if (!rq->nr_sectors) {	/* all done? */
 				rq = hwgroup->rq;
-				for (i = rq->nr_sectors; i > 0;){
+				for (i = rq->nr_sectors; i > 0;) {
 					i -= rq->current_nr_sectors;
-					ide_end_request(1, hwgroup);
+					idedisk_end_request(drive, 1);
 				}
 				return ide_stopped;
 			}
 		}
-		return ide_stopped;	/* the original code did this here (?) */
+		/* the original code did this here (?) */
+		return ide_stopped;
 	}
-	return ide_error(drive, "multwrite_intr", stat);
+	return DRIVER(drive)->error(drive, "multwrite_intr", stat);
 }
-#endif /* __TASKFILE__IO */
 
-#ifdef __TASKFILE__IO
-
-static ide_startstop_t chs_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block);
-static ide_startstop_t lba_28_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block);
-static ide_startstop_t lba_48_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long long block);
 
 /*
  * do_rw_disk() issues READ and WRITE commands to a disk,
@@ -354,230 +365,32 @@
  */
 static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
-	if (rq->cmd == READ)
-		goto good_command;
-	if (rq->cmd == WRITE)
-		goto good_command;
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 lba48		= (drive->addressing == 1) ? 1 : 0;
+	task_ioreg_t command	= WIN_NOP;
+	ata_nsector_t		nsectors;
 
-	printk(KERN_ERR "%s: bad command: %d\n", drive->name, rq->cmd);
-	ide_end_request(0, HWGROUP(drive));
-	return ide_stopped;
+	nsectors.all		= (u16) rq->nr_sectors;
 
-good_command:
+	if (driver_blocked)
+		panic("Request while ide driver is blocked?");
 
-#ifdef CONFIG_BLK_DEV_PDC4030
-	if (IS_PDC4030_DRIVE) {
-		extern ide_startstop_t promise_rw_disk(ide_drive_t *, struct request *, unsigned long);
+#if defined(CONFIG_BLK_DEV_PDC4030) || defined(CONFIG_BLK_DEV_PDC4030_MODULE)
+	if (IS_PDC4030_DRIVE)
 		return promise_rw_disk(drive, rq, block);
-	}
 #endif /* CONFIG_BLK_DEV_PDC4030 */
 
-	if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing))	/* 48-bit LBA */
-		return lba_48_rw_disk(drive, rq, (unsigned long long) block);
-	if (drive->select.b.lba)		/* 28-bit LBA */
-		return lba_28_rw_disk(drive, rq, (unsigned long) block);
-
-	/* 28-bit CHS : DIE DIE DIE piece of legacy crap!!! */
-	return chs_rw_disk(drive, rq, (unsigned long) block);
-}
-
-static task_ioreg_t get_command (ide_drive_t *drive, int cmd)
-{
-	int lba48bit = (drive->id->cfs_enable_2 & 0x0400) ? 1 : 0;
-
-#if 1
-	lba48bit = drive->addressing;
-#endif
-
-	if ((cmd == READ) && (drive->using_dma))
-		return (lba48bit) ? WIN_READDMA_EXT : WIN_READDMA;
-	else if ((cmd == READ) && (drive->mult_count))
-		return (lba48bit) ? WIN_MULTREAD_EXT : WIN_MULTREAD;
-	else if (cmd == READ)
-		return (lba48bit) ? WIN_READ_EXT : WIN_READ;
-	else if ((cmd == WRITE) && (drive->using_dma))
-		return (lba48bit) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
-	else if ((cmd == WRITE) && (drive->mult_count))
-		return (lba48bit) ? WIN_MULTWRITE_EXT : WIN_MULTWRITE;
-	else if (cmd == WRITE)
-		return (lba48bit) ? WIN_WRITE_EXT : WIN_WRITE;
-	else
-		return WIN_NOP;
-}
-
-static ide_startstop_t chs_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
-{
-	struct hd_drive_task_hdr	taskfile;
-	struct hd_drive_hob_hdr		hobfile;
-	ide_task_t			args;
-
-	task_ioreg_t command	= get_command(drive, rq->cmd);
-	unsigned int track	= (block / drive->sect);
-	unsigned int sect	= (block % drive->sect) + 1;
-	unsigned int head	= (track % drive->head);
-	unsigned int cyl	= (track / drive->head);
-
-	memset(&taskfile, 0, sizeof(task_struct_t));
-	memset(&hobfile, 0, sizeof(hob_struct_t));
-
-	taskfile.sector_count	= (rq->nr_sectors==256)?0x00:rq->nr_sectors;
-	taskfile.sector_number	= sect;
-	taskfile.low_cylinder	= cyl;
-	taskfile.high_cylinder	= (cyl>>8);
-	taskfile.device_head	= head;
-	taskfile.device_head	|= drive->select.all;
-	taskfile.command	= command;
-
-#ifdef DEBUG
-	printk("%s: %sing: ", drive->name, (rq->cmd==READ) ? "read" : "writ");
-	if (lba)	printk("LBAsect=%lld, ", block);
-	else		printk("CHS=%d/%d/%d, ", cyl, head, sect);
-	printk("sectors=%ld, ", rq->nr_sectors);
-	printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
-#endif
-
-	memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
-	memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr));
-	args.command_type	= ide_cmd_type_parser(&args);
-	args.prehandler		= ide_pre_handler_parser(&taskfile, &hobfile);
-	args.handler		= ide_handler_parser(&taskfile, &hobfile);
-	args.posthandler	= NULL;
-	args.rq			= (struct request *) rq;
-	args.block		= block;
-	rq->special		= NULL;
-	rq->special		= (ide_task_t *)&args;
-
-	return do_rw_taskfile(drive, &args);
-}
-
-static ide_startstop_t lba_28_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
-{
-	struct hd_drive_task_hdr	taskfile;
-	struct hd_drive_hob_hdr		hobfile;
-	ide_task_t			args;
-
-	task_ioreg_t command	= get_command(drive, rq->cmd);
-
-	memset(&taskfile, 0, sizeof(task_struct_t));
-	memset(&hobfile, 0, sizeof(hob_struct_t));
-
-	taskfile.sector_count	= (rq->nr_sectors==256)?0x00:rq->nr_sectors;
-	taskfile.sector_number	= block;
-	taskfile.low_cylinder	= (block>>=8);
-	taskfile.high_cylinder	= (block>>=8);
-	taskfile.device_head	= ((block>>8)&0x0f);
-	taskfile.device_head	|= drive->select.all;
-	taskfile.command	= command;
-
-
-#ifdef DEBUG
-	printk("%s: %sing: ", drive->name, (rq->cmd==READ) ? "read" : "writ");
-	if (lba)	printk("LBAsect=%lld, ", block);
-	else		printk("CHS=%d/%d/%d, ", cyl, head, sect);
-	printk("sectors=%ld, ", rq->nr_sectors);
-	printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
-#endif
-
-	memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
-	memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr));
-	args.command_type	= ide_cmd_type_parser(&args);
-	args.prehandler		= ide_pre_handler_parser(&taskfile, &hobfile);
-	args.handler		= ide_handler_parser(&taskfile, &hobfile);
-	args.posthandler	= NULL;
-	args.rq			= (struct request *) rq;
-	args.block		= block;
-	rq->special		= NULL;
-	rq->special		= (ide_task_t *)&args;
-
-	return do_rw_taskfile(drive, &args);
-}
-
-/*
- * 268435455  == 137439 MB or 28bit limit
- * 320173056  == 163929 MB or 48bit addressing
- * 1073741822 == 549756 MB or 48bit addressing fake drive
- */
-
-static ide_startstop_t lba_48_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long long block)
-{
-	struct hd_drive_task_hdr	taskfile;
-	struct hd_drive_hob_hdr		hobfile;
-	ide_task_t			args;
-
-	task_ioreg_t command	= get_command(drive, rq->cmd);
-
-	memset(&taskfile, 0, sizeof(task_struct_t));
-	memset(&hobfile, 0, sizeof(hob_struct_t));
-
-	taskfile.sector_count	= rq->nr_sectors;
-	hobfile.sector_count	= (rq->nr_sectors>>8);
-
-	if (rq->nr_sectors == 65536) {
-		taskfile.sector_count	= 0x00;
-		hobfile.sector_count	= 0x00;
-	}
-
-	taskfile.sector_number	= block;	/* low lba */
-	taskfile.low_cylinder	= (block>>=8);	/* mid lba */
-	taskfile.high_cylinder	= (block>>=8);	/* hi  lba */
-	hobfile.sector_number	= (block>>=8);	/* low lba */
-	hobfile.low_cylinder	= (block>>=8);	/* mid lba */
-	hobfile.high_cylinder	= (block>>=8);	/* hi  lba */
-	taskfile.device_head	= drive->select.all;
-	hobfile.device_head	= taskfile.device_head;
-	hobfile.control		= (drive->ctl|0x80);
-	taskfile.command	= command;
-
-#ifdef DEBUG
-	printk("%s: %sing: ", drive->name, (rq->cmd==READ) ? "read" : "writ");
-	if (lba)	printk("LBAsect=%lld, ", block);
-	else		printk("CHS=%d/%d/%d, ", cyl, head, sect);
-	printk("sectors=%ld, ", rq->nr_sectors);
-	printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
-#endif
-
-	memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
-	memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr));
-	args.command_type	= ide_cmd_type_parser(&args);
-	args.prehandler		= ide_pre_handler_parser(&taskfile, &hobfile);
-	args.handler		= ide_handler_parser(&taskfile, &hobfile);
-	args.posthandler	= NULL;
-	args.rq			= (struct request *) rq;
-	args.block		= block;
-	rq->special		= NULL;
-	rq->special		= (ide_task_t *)&args;
-
-	return do_rw_taskfile(drive, &args);
-}
-
-#else /* !__TASKFILE__IO */
-/*
- * do_rw_disk() issues READ and WRITE commands to a disk,
- * using LBA if supported, or CHS otherwise, to address sectors.
- * It also takes care of issuing special DRIVE_CMDs.
- */
-static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
-{
 	if (IDE_CONTROL_REG)
-		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
+		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
 
-#ifdef CONFIG_BLK_DEV_PDC4030
-	if (drive->select.b.lba || IS_PDC4030_DRIVE) {
-#else /* !CONFIG_BLK_DEV_PDC4030 */
 	if (drive->select.b.lba) {
-#endif /* CONFIG_BLK_DEV_PDC4030 */
-
-		if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing)) {
+		if (drive->addressing == 1) {
 			task_ioreg_t tasklets[10];
 
 			tasklets[0] = 0;
 			tasklets[1] = 0;
-			tasklets[2] = rq->nr_sectors;
-			tasklets[3] = (rq->nr_sectors>>8);
-			if (rq->nr_sectors == 65536) {
-				tasklets[2] = 0x00;
-				tasklets[3] = 0x00;
-			}
+			tasklets[2] = nsectors.b.low;
+			tasklets[3] = nsectors.b.high;
 			tasklets[4] = (task_ioreg_t) block;
 			tasklets[5] = (task_ioreg_t) (block>>8);
 			tasklets[6] = (task_ioreg_t) (block>>16);
@@ -587,7 +400,8 @@
 //			tasklets[8] = (task_ioreg_t) (block>>32);
 //			tasklets[9] = (task_ioreg_t) (block>>40);
 #ifdef DEBUG
-			printk("%s: %sing: LBAsect=%lu, sectors=%ld, buffer=0x%08lx, LBAsect=0x%012lx\n",
+			printk("%s: %sing: LBAsect=%lu, sectors=%ld, "
+				"buffer=0x%08lx, LBAsect=0x%012lx\n",
 				drive->name,
 				(rq->cmd==READ)?"read":"writ",
 				block,
@@ -599,87 +413,88 @@
 				tasklets[9], tasklets[8], tasklets[7],
 				tasklets[6], tasklets[5], tasklets[4]);
 #endif
-			OUT_BYTE(tasklets[1], IDE_FEATURE_REG);
-			OUT_BYTE(tasklets[3], IDE_NSECTOR_REG);
-			OUT_BYTE(tasklets[7], IDE_SECTOR_REG);
-			OUT_BYTE(tasklets[8], IDE_LCYL_REG);
-			OUT_BYTE(tasklets[9], IDE_HCYL_REG);
-
-			OUT_BYTE(tasklets[0], IDE_FEATURE_REG);
-			OUT_BYTE(tasklets[2], IDE_NSECTOR_REG);
-			OUT_BYTE(tasklets[4], IDE_SECTOR_REG);
-			OUT_BYTE(tasklets[5], IDE_LCYL_REG);
-			OUT_BYTE(tasklets[6], IDE_HCYL_REG);
-			OUT_BYTE(0x00|drive->select.all,IDE_SELECT_REG);
+			hwif->OUTB(tasklets[1], IDE_FEATURE_REG);
+			hwif->OUTB(tasklets[3], IDE_NSECTOR_REG);
+			hwif->OUTB(tasklets[7], IDE_SECTOR_REG);
+			hwif->OUTB(tasklets[8], IDE_LCYL_REG);
+			hwif->OUTB(tasklets[9], IDE_HCYL_REG);
+
+			hwif->OUTB(tasklets[0], IDE_FEATURE_REG);
+			hwif->OUTB(tasklets[2], IDE_NSECTOR_REG);
+			hwif->OUTB(tasklets[4], IDE_SECTOR_REG);
+			hwif->OUTB(tasklets[5], IDE_LCYL_REG);
+			hwif->OUTB(tasklets[6], IDE_HCYL_REG);
+			hwif->OUTB(0x00|drive->select.all,IDE_SELECT_REG);
 		} else {
 #ifdef DEBUG
-			printk("%s: %sing: LBAsect=%ld, sectors=%ld, buffer=0x%08lx\n",
+			printk("%s: %sing: LBAsect=%ld, sectors=%ld, "
+				"buffer=0x%08lx\n",
 				drive->name, (rq->cmd==READ)?"read":"writ",
-				block, rq->nr_sectors, (unsigned long) rq->buffer);
+				block, rq->nr_sectors,
+				(unsigned long) rq->buffer);
 #endif
-			OUT_BYTE(0x00, IDE_FEATURE_REG);
-			OUT_BYTE((rq->nr_sectors==256)?0x00:rq->nr_sectors,IDE_NSECTOR_REG);
-			OUT_BYTE(block,IDE_SECTOR_REG);
-			OUT_BYTE(block>>=8,IDE_LCYL_REG);
-			OUT_BYTE(block>>=8,IDE_HCYL_REG);
-			OUT_BYTE(((block>>8)&0x0f)|drive->select.all,IDE_SELECT_REG);
+			hwif->OUTB(0x00, IDE_FEATURE_REG);
+			hwif->OUTB(nsectors.b.low, IDE_NSECTOR_REG);
+			hwif->OUTB(block, IDE_SECTOR_REG);
+			hwif->OUTB(block>>=8, IDE_LCYL_REG);
+			hwif->OUTB(block>>=8, IDE_HCYL_REG);
+			hwif->OUTB(((block>>8)&0x0f)|drive->select.all,IDE_SELECT_REG);
 		}
 	} else {
 		unsigned int sect,head,cyl,track;
 		track = block / drive->sect;
 		sect  = block % drive->sect + 1;
-		OUT_BYTE(sect,IDE_SECTOR_REG);
+		hwif->OUTB(sect, IDE_SECTOR_REG);
 		head  = track % drive->head;
 		cyl   = track / drive->head;
 
-		OUT_BYTE(0x00, IDE_FEATURE_REG);
-		OUT_BYTE((rq->nr_sectors==256)?0x00:rq->nr_sectors,IDE_NSECTOR_REG);
-		OUT_BYTE(cyl,IDE_LCYL_REG);
-		OUT_BYTE(cyl>>8,IDE_HCYL_REG);
-		OUT_BYTE(head|drive->select.all,IDE_SELECT_REG);
+		hwif->OUTB(0x00, IDE_FEATURE_REG);
+		hwif->OUTB(nsectors.b.low, IDE_NSECTOR_REG);
+		hwif->OUTB(cyl, IDE_LCYL_REG);
+		hwif->OUTB(cyl>>8, IDE_HCYL_REG);
+		hwif->OUTB(head|drive->select.all,IDE_SELECT_REG);
 #ifdef DEBUG
 		printk("%s: %sing: CHS=%d/%d/%d, sectors=%ld, buffer=0x%08lx\n",
 			drive->name, (rq->cmd==READ)?"read":"writ", cyl,
 			head, sect, rq->nr_sectors, (unsigned long) rq->buffer);
 #endif
 	}
-#ifdef CONFIG_BLK_DEV_PDC4030
-	if (IS_PDC4030_DRIVE) {
-		extern ide_startstop_t do_pdc4030_io(ide_drive_t *, struct request *);
-		return do_pdc4030_io (drive, rq);
-	}
-#endif /* CONFIG_BLK_DEV_PDC4030 */
-	if (rq->cmd == READ) {
+
+	if (rq_data_dir(rq) == READ) {
 #ifdef CONFIG_BLK_DEV_IDEDMA
-		if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_read, drive)))
+		if (drive->using_dma && !hwif->ide_dma_read(drive))
 			return ide_started;
 #endif /* CONFIG_BLK_DEV_IDEDMA */
+		if (HWGROUP(drive)->handler != NULL)
+			BUG();
 		ide_set_handler(drive, &read_intr, WAIT_CMD, NULL);
-		if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing)) {
-			OUT_BYTE(drive->mult_count ? WIN_MULTREAD_EXT : WIN_READ_EXT, IDE_COMMAND_REG);
-		} else {
-			OUT_BYTE(drive->mult_count ? WIN_MULTREAD : WIN_READ, IDE_COMMAND_REG);
-		}
+
+		command = ((drive->mult_count) ?
+			   ((lba48) ? WIN_MULTREAD_EXT : WIN_MULTREAD) :
+			   ((lba48) ? WIN_READ_EXT : WIN_READ));
+		hwif->OUTB(command, IDE_COMMAND_REG);
 		return ide_started;
-	}
-	if (rq->cmd == WRITE) {
+	} else if (rq_data_dir(rq) == WRITE) {
 		ide_startstop_t startstop;
 #ifdef CONFIG_BLK_DEV_IDEDMA
-		if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_write, drive)))
+		if (drive->using_dma && !(HWIF(drive)->ide_dma_write(drive)))
 			return ide_started;
 #endif /* CONFIG_BLK_DEV_IDEDMA */
-		if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing)) {
-			OUT_BYTE(drive->mult_count ? WIN_MULTWRITE_EXT : WIN_WRITE_EXT, IDE_COMMAND_REG);
-		} else {
-			OUT_BYTE(drive->mult_count ? WIN_MULTWRITE : WIN_WRITE, IDE_COMMAND_REG);
-		}
-		if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
-			printk(KERN_ERR "%s: no DRQ after issuing %s\n", drive->name,
+
+		command = ((drive->mult_count) ?
+			   ((lba48) ? WIN_MULTWRITE_EXT : WIN_MULTWRITE) :
+			   ((lba48) ? WIN_WRITE_EXT : WIN_WRITE));
+		hwif->OUTB(command, IDE_COMMAND_REG);
+
+		if (ide_wait_stat(&startstop, drive, DATA_READY,
+				drive->bad_wstat, WAIT_DRQ)) {
+			printk(KERN_ERR "%s: no DRQ after issuing %s\n",
+				drive->name,
 				drive->mult_count ? "MULTWRITE" : "WRITE");
 			return startstop;
 		}
 		if (!drive->unmask)
-			__cli();	/* local CPU only */
+			local_irq_disable();
 		if (drive->mult_count) {
 			ide_hwgroup_t *hwgroup = HWGROUP(drive);
 	/*
@@ -690,8 +505,12 @@
 	 * before returning.  Fortunately, this NEVER happens (right?).
 	 *
 	 * Except when you get an error it seems...
+	 *
+	 * MAJOR DATA INTEGRITY BUG !!! only if we error 
 	 */
 			hwgroup->wrq = *rq; /* scratchpad */
+			if (HWGROUP(drive)->handler != NULL)
+				BUG();
 			ide_set_handler(drive, &multwrite_intr, WAIT_CMD, NULL);
 			if (ide_multwrite(drive, drive->mult_count)) {
 				unsigned long flags;
@@ -703,36 +522,210 @@
 			}
 		} else {
 			unsigned long flags;
-			char *buffer = ide_map_buffer(rq, &flags);
-			ide_set_handler (drive, &write_intr, WAIT_CMD, NULL);
-			idedisk_output_data(drive, buffer, SECTOR_WORDS);
-			ide_unmap_buffer(buffer, &flags);
+			char *to = ide_map_buffer(rq, &flags);
+			if (HWGROUP(drive)->handler != NULL)
+				BUG();
+			ide_set_handler(drive, &write_intr, WAIT_CMD, NULL);
+			taskfile_output_data(drive, to, SECTOR_WORDS);
+			ide_unmap_buffer(to, &flags);
 		}
 		return ide_started;
 	}
 	printk(KERN_ERR "%s: bad command: %d\n", drive->name, rq->cmd);
-	ide_end_request(0, HWGROUP(drive));
+	idedisk_end_request(drive, 0);
 	return ide_stopped;
 }
 
-#endif /* __TASKFILE__IO */
+#else /* CONFIG_IDE_TASKFILE_IO */
+
+static ide_startstop_t chs_rw_disk(ide_drive_t *, struct request *, unsigned long);
+static ide_startstop_t lba_28_rw_disk(ide_drive_t *, struct request *, unsigned long);
+static ide_startstop_t lba_48_rw_disk(ide_drive_t *, struct request *, unsigned long long);
+
+/*
+ * do_rw_disk() issues READ and WRITE commands to a disk,
+ * using LBA if supported, or CHS otherwise, to address sectors.
+ * It also takes care of issuing special DRIVE_CMDs.
+ */
+static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
+{
+	if (!blk_fs_request(rq)) {
+		printk(KERN_ERR "%s: bad command: %d\n", drive->name, rq->cmd);
+		idedisk_end_request(drive, 0);
+		return ide_stopped;
+	}
+
+	/*
+	 * 268435455  == 137439 MB or 28bit limit
+	 *
+	 * need to add split taskfile operations based on 28bit threshold.
+	 */
+
+#if defined(CONFIG_BLK_DEV_PDC4030) || defined(CONFIG_BLK_DEV_PDC4030_MODULE)
+        if (IS_PDC4030_DRIVE)
+                return promise_rw_disk(drive, rq, block);
+#endif /* CONFIG_BLK_DEV_PDC4030 */
+
+	if (drive->addressing == 1)		/* 48-bit LBA */
+		return lba_48_rw_disk(drive, rq, (unsigned long long) block);
+	if (drive->select.b.lba)		/* 28-bit LBA */
+		return lba_28_rw_disk(drive, rq, (unsigned long) block);
+
+	/* 28-bit CHS : DIE DIE DIE piece of legacy crap!!! */
+	return chs_rw_disk(drive, rq, (unsigned long) block);
+}
+
+static task_ioreg_t get_command (ide_drive_t *drive, int cmd)
+{
+	int lba48bit = (drive->id->cfs_enable_2 & 0x0400) ? 1 : 0;
+
+#if 1
+	lba48bit = (drive->addressing == 1) ? 1 : 0;
+#endif
+
+	if ((cmd == READ) && (drive->using_dma))
+		return (lba48bit) ? WIN_READDMA_EXT : WIN_READDMA;
+	else if ((cmd == READ) && (drive->mult_count))
+		return (lba48bit) ? WIN_MULTREAD_EXT : WIN_MULTREAD;
+	else if (cmd == READ)
+		return (lba48bit) ? WIN_READ_EXT : WIN_READ;
+	else if ((cmd == WRITE) && (drive->using_dma))
+		return (lba48bit) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
+	else if ((cmd == WRITE) && (drive->mult_count))
+		return (lba48bit) ? WIN_MULTWRITE_EXT : WIN_MULTWRITE;
+	else if (cmd == WRITE)
+		return (lba48bit) ? WIN_WRITE_EXT : WIN_WRITE;
+	else
+		return WIN_NOP;
+}
+
+static ide_startstop_t chs_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
+{
+	ide_task_t		args;
+	int			sectors;
+	ata_nsector_t		nsectors;
+	task_ioreg_t command	= get_command(drive, rq_data_dir(rq));
+	unsigned int track	= (block / drive->sect);
+	unsigned int sect	= (block % drive->sect) + 1;
+	unsigned int head	= (track % drive->head);
+	unsigned int cyl	= (track / drive->head);
+
+	nsectors.all = (u16) rq->nr_sectors;
+#ifdef DEBUG
+	printk("%s: %sing: ", drive->name, (rq_data_dir(rq)==READ) ? "read" : "writ");
+	printk("CHS=%d/%d/%d, ", cyl, head, sect);
+	printk("sectors=%ld, ", rq->nr_sectors);
+	printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
+#endif
+
+	memset(&args, 0, sizeof(ide_task_t));
+
+	sectors	= (rq->nr_sectors == 256) ? 0x00 : rq->nr_sectors;
+	args.tfRegister[IDE_NSECTOR_OFFSET]	= sectors;
+	args.tfRegister[IDE_SECTOR_OFFSET]	= sect;
+	args.tfRegister[IDE_LCYL_OFFSET]	= cyl;
+	args.tfRegister[IDE_HCYL_OFFSET]	= (cyl>>8);
+	args.tfRegister[IDE_SELECT_OFFSET]	= head;
+	args.tfRegister[IDE_SELECT_OFFSET]	|= drive->select.all;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= command;
+	args.command_type			= ide_cmd_type_parser(&args);
+	args.rq					= (struct request *) rq;
+	rq->special				= (ide_task_t *)&args;
+	return do_rw_taskfile(drive, &args);
+}
+
+static ide_startstop_t lba_28_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
+{
+	ide_task_t		args;
+	int			sectors;
+	ata_nsector_t		nsectors;
+	task_ioreg_t command	= get_command(drive, rq_data_dir(rq));
+
+	nsectors.all = (u16) rq->nr_sectors;
+
+#ifdef DEBUG
+	printk("%s: %sing: ", drive->name, (rq_data_dir(rq)==READ) ? "read" : "writ");
+	printk("LBAsect=%lld, ", block);
+	printk("sectors=%ld, ", rq->nr_sectors);
+	printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
+#endif
+
+	memset(&args, 0, sizeof(ide_task_t));
+
+	sectors = (rq->nr_sectors == 256) ? 0x00 : rq->nr_sectors;
+	args.tfRegister[IDE_NSECTOR_OFFSET]	= sectors;
+	args.tfRegister[IDE_SECTOR_OFFSET]	= block;
+	args.tfRegister[IDE_LCYL_OFFSET]	= (block>>=8);
+	args.tfRegister[IDE_HCYL_OFFSET]	= (block>>=8);
+	args.tfRegister[IDE_SELECT_OFFSET]	= ((block>>8)&0x0f);
+	args.tfRegister[IDE_SELECT_OFFSET]	|= drive->select.all;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= command;
+	args.command_type			= ide_cmd_type_parser(&args);
+	args.rq					= (struct request *) rq;
+	rq->special				= (ide_task_t *)&args;
+	return do_rw_taskfile(drive, &args);
+}
+
+/*
+ * 268435455  == 137439 MB or 28bit limit
+ * 320173056  == 163929 MB or 48bit addressing
+ * 1073741822 == 549756 MB or 48bit addressing fake drive
+ */
+
+static ide_startstop_t lba_48_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long long block)
+{
+	ide_task_t		args;
+	int			sectors;
+	ata_nsector_t		nsectors;
+	task_ioreg_t command	= get_command(drive, rq_data_dir(rq));
+
+	nsectors.all = (u16) rq->nr_sectors;
+
+#ifdef DEBUG
+	printk("%s: %sing: ", drive->name, (rq_data_dir(rq)==READ) ? "read" : "writ");
+	printk("LBAsect=%lld, ", block);
+	printk("sectors=%ld, ", rq->nr_sectors);
+	printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
+#endif
+
+	memset(&args, 0, sizeof(ide_task_t));
+
+	sectors = (rq->nr_sectors == 65536) ? 0 : rq->nr_sectors;
+	args.tfRegister[IDE_NSECTOR_OFFSET]	= sectors;
+	args.tfRegister[IDE_SECTOR_OFFSET]	= block;	/* low lba */
+	args.tfRegister[IDE_LCYL_OFFSET]	= (block>>=8);	/* mid lba */
+	args.tfRegister[IDE_HCYL_OFFSET]	= (block>>=8);	/* hi  lba */
+	args.tfRegister[IDE_SELECT_OFFSET]	= drive->select.all;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= command;
+	args.hobRegister[IDE_NSECTOR_OFFSET_HOB]= sectors >> 8;
+	args.hobRegister[IDE_SECTOR_OFFSET_HOB]	= (block>>=8);	/* low lba */
+	args.hobRegister[IDE_LCYL_OFFSET_HOB]	= (block>>=8);	/* mid lba */
+	args.hobRegister[IDE_HCYL_OFFSET_HOB]	= (block>>=8);	/* hi  lba */
+	args.hobRegister[IDE_SELECT_OFFSET_HOB]	= drive->select.all;
+	args.hobRegister[IDE_CONTROL_OFFSET_HOB]= (drive->ctl|0x80);
+	args.command_type			= ide_cmd_type_parser(&args);
+	args.rq					= (struct request *) rq;
+	rq->special				= (ide_task_t *)&args;
+	return do_rw_taskfile(drive, &args);
+}
+
+#endif /* CONFIG_IDE_TASKFILE_IO */
 
 static int idedisk_open (struct inode *inode, struct file *filp, ide_drive_t *drive)
 {
 	MOD_INC_USE_COUNT;
 	if (drive->removable && drive->usage == 1) {
-		struct hd_drive_task_hdr taskfile;
-		struct hd_drive_hob_hdr hobfile;
-		memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-		memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-		taskfile.command = WIN_DOORLOCK;
+		ide_task_t args;
+		memset(&args, 0, sizeof(ide_task_t));
+		args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORLOCK;
+		args.command_type = ide_cmd_type_parser(&args);
 		check_disk_change(inode->i_rdev);
 		/*
 		 * Ignore the return code from door_lock,
 		 * since the open() has already succeeded,
 		 * and the door_lock is irrelevant at this point.
 		 */
-		if (drive->doorlocking && ide_wait_taskfile(drive, &taskfile, &hobfile, NULL))
+		if (drive->doorlocking && ide_raw_taskfile(drive, &args, NULL))
 			drive->doorlocking = 0;
 	}
 	return 0;
@@ -743,13 +736,12 @@
 static void idedisk_release (struct inode *inode, struct file *filp, ide_drive_t *drive)
 {
 	if (drive->removable && !drive->usage) {
-		struct hd_drive_task_hdr taskfile;
-		struct hd_drive_hob_hdr hobfile;
-		memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-		memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-		taskfile.command = WIN_DOORUNLOCK;
+		ide_task_t args;
+		memset(&args, 0, sizeof(ide_task_t));
+		args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORUNLOCK;
+		args.command_type = ide_cmd_type_parser(&args);
 		invalidate_bdev(inode->i_bdev, 0);
-		if (drive->doorlocking && ide_wait_taskfile(drive, &taskfile, &hobfile, NULL))
+		if (drive->doorlocking && ide_raw_taskfile(drive, &args, NULL))
 			drive->doorlocking = 0;
 	}
 	if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache)
@@ -761,7 +753,8 @@
 
 static int idedisk_media_change (ide_drive_t *drive)
 {
-	return drive->removable;	/* if removable, always assume it was changed */
+	/* if removable, always assume it was changed */
+	return drive->removable;
 }
 
 static void idedisk_revalidate (ide_drive_t *drive)
@@ -771,6 +764,198 @@
 			current_capacity(drive));
 }
 
+static int idedisk_end_request (ide_drive_t *drive, int uptodate)
+{
+	struct request *rq;
+	unsigned long flags;
+	int ret = 1;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	rq = HWGROUP(drive)->rq;
+
+	/*
+	 * decide whether to reenable DMA -- 3 is a random magic for now,
+	 * if we DMA timeout more than 3 times, just stay in PIO
+	 */
+	if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
+		drive->state = 0;
+		HWGROUP(drive)->hwif->ide_dma_on(drive);
+	}
+
+	if (!end_that_request_first(rq, uptodate, drive->name)) {
+		add_blkdev_randomness(MAJOR(rq->rq_dev));
+		blkdev_dequeue_request(rq);
+		HWGROUP(drive)->rq = NULL;
+		end_that_request_last(rq);
+		ret = 0;
+	}
+
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	return ret;
+}
+
+static u8 idedisk_dump_status (ide_drive_t *drive, const char *msg, u8 stat)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	unsigned long flags;
+	u8 err = 0;
+
+	local_irq_set(flags);
+	printk("%s: %s: status=0x%02x", drive->name, msg, stat);
+#if FANCY_STATUS_DUMPS
+	printk(" { ");
+	if (stat & BUSY_STAT)
+		printk("Busy ");
+	else {
+		if (stat & READY_STAT)	printk("DriveReady ");
+		if (stat & WRERR_STAT)	printk("DeviceFault ");
+		if (stat & SEEK_STAT)	printk("SeekComplete ");
+		if (stat & DRQ_STAT)	printk("DataRequest ");
+		if (stat & ECC_STAT)	printk("CorrectedError ");
+		if (stat & INDEX_STAT)	printk("Index ");
+		if (stat & ERR_STAT)	printk("Error ");
+	}
+	printk("}");
+#endif	/* FANCY_STATUS_DUMPS */
+	printk("\n");
+	if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
+		err = hwif->INB(IDE_ERROR_REG);
+		printk("%s: %s: error=0x%02x", drive->name, msg, err);
+#if FANCY_STATUS_DUMPS
+		printk(" { ");
+		if (err & ABRT_ERR)	printk("DriveStatusError ");
+		if (err & ICRC_ERR)
+			printk("Bad%s ", (err & ABRT_ERR) ? "CRC" : "Sector");
+		if (err & ECC_ERR)	printk("UncorrectableError ");
+		if (err & ID_ERR)	printk("SectorIdNotFound ");
+		if (err & TRK0_ERR)	printk("TrackZeroNotFound ");
+		if (err & MARK_ERR)	printk("AddrMarkNotFound ");
+		printk("}");
+		if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR ||
+		    (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
+			if (drive->addressing == 1) {
+				__u64 sectors = 0;
+				u32 low = 0, high = 0;
+				low = idedisk_read_24(drive);
+				hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG);
+				high = idedisk_read_24(drive);
+				sectors = ((__u64)high << 24) | low;
+				printk(", LBAsect=%llu, high=%d, low=%d",
+				       (unsigned long long) sectors,
+				       high, low);
+			} else {
+				u8 cur = hwif->INB(IDE_SELECT_REG);
+				if (cur & 0x40) {	/* using LBA? */
+					printk(", LBAsect=%ld", (unsigned long)
+					 ((cur&0xf)<<24)
+					 |(hwif->INB(IDE_HCYL_REG)<<16)
+					 |(hwif->INB(IDE_LCYL_REG)<<8)
+					 | hwif->INB(IDE_SECTOR_REG));
+				} else {
+					printk(", CHS=%d/%d/%d",
+					 (hwif->INB(IDE_HCYL_REG)<<8) +
+					  hwif->INB(IDE_LCYL_REG),
+					  cur & 0xf,
+					  hwif->INB(IDE_SECTOR_REG));
+				}
+			}
+			if (HWGROUP(drive) && HWGROUP(drive)->rq)
+				printk(", sector=%ld",
+					HWGROUP(drive)->rq->sector);
+		}
+	}
+#endif	/* FANCY_STATUS_DUMPS */
+	printk("\n");
+	local_irq_restore(flags);
+	return err;
+}
+
+ide_startstop_t idedisk_error (ide_drive_t *drive, const char *msg, u8 stat)
+{
+	ide_hwif_t *hwif;
+	struct request *rq;
+	u8 err;
+	int i = (drive->mult_count ? drive->mult_count : 1) * SECTOR_WORDS;
+
+	err = idedisk_dump_status(drive, msg, stat);
+
+	if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
+		return ide_stopped;
+
+	hwif = HWIF(drive);
+	/* retry only "normal" I/O: */
+	switch (rq->cmd) {
+		case IDE_DRIVE_CMD:
+		case IDE_DRIVE_TASK:
+		case IDE_DRIVE_TASKFILE:
+			rq->errors = 1;
+			ide_end_drive_cmd(drive, stat, err);
+			return ide_stopped;
+#if 0
+		case IDE_DRIVE_TASKFILE:
+			rq->errors = 1;
+			ide_end_taskfile(drive, stat, err);
+			return ide_stopped;
+#endif
+		default:
+			break;
+	}
+
+	if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) {
+		/* other bits are useless when BUSY */
+		rq->errors |= ERROR_RESET;
+	} else if (stat & ERR_STAT) {
+		/* err has different meaning on cdrom and tape */
+		if (err == ABRT_ERR) {
+			if (drive->select.b.lba &&
+			    /* some newer drives don't support WIN_SPECIFY */
+			    hwif->INB(IDE_COMMAND_REG) == WIN_SPECIFY)
+				return ide_stopped;
+		} else if ((err & BAD_CRC) == BAD_CRC) {
+			/* UDMA crc error, just retry the operation */
+			drive->crc_count++;
+		} else if (err & (BBD_ERR | ECC_ERR)) {
+			/* retries won't help these */
+			rq->errors = ERROR_MAX;
+		} else if (err & TRK0_ERR) {
+			/* help it find track zero */
+			rq->errors |= ERROR_RECAL;
+		}
+	}
+	if ((stat & DRQ_STAT) && rq_data_dir(rq) == READ) {
+		/*
+		 * try_to_flush_leftover_data() is invoked in response to
+		 * a drive unexpectedly having its DRQ_STAT bit set.  As
+		 * an alternative to resetting the drive, this routine
+		 * tries to clear the condition by read a sector's worth
+		 * of data from the drive.  Of course, this may not help
+		 * if the drive is *waiting* for data from *us*.
+		 */
+		while (i > 0) {
+			u32 buffer[16];
+			unsigned int wcount = (i > 16) ? 16 : i;
+			i -= wcount;
+			taskfile_input_data(drive, buffer, wcount);
+		}
+	}
+	if (hwif->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT)) {
+		/* force an abort */
+		hwif->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);
+	}
+	if (rq->errors >= ERROR_MAX)
+		DRIVER(drive)->end_request(drive, 0);
+	else {
+		if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
+			++rq->errors;
+			return ide_do_reset(drive);
+		}
+		if ((rq->errors & ERROR_RECAL) == ERROR_RECAL)
+			drive->special.b.recalibrate = 1;
+		++rq->errors;
+	}
+	return ide_stopped;
+}
+
 /*
  * Queries for true maximum capacity of the drive.
  * Returns maximum LBA address (> 0) of the drive, 0 if failed.
@@ -780,16 +965,11 @@
 	ide_task_t args;
 	unsigned long addr = 0;
 
-	if (!(drive->id->command_set_1 & 0x0400) &&
-	    !(drive->id->cfs_enable_2 & 0x0100))
-		return addr;
-
 	/* Create IDE/ATA command request structure */
 	memset(&args, 0, sizeof(ide_task_t));
 	args.tfRegister[IDE_SELECT_OFFSET]	= 0x40;
 	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_READ_NATIVE_MAX;
-	args.handler				= task_no_data_intr;
-
+	args.command_type			= ide_cmd_type_parser(&args);
 	/* submit command request */
 	ide_raw_taskfile(drive, &args, NULL);
 
@@ -814,8 +994,7 @@
 
 	args.tfRegister[IDE_SELECT_OFFSET]	= 0x40;
 	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_READ_NATIVE_MAX_EXT;
-	args.handler				= task_no_data_intr;
-
+	args.command_type			= ide_cmd_type_parser(&args);
         /* submit command request */
         ide_raw_taskfile(drive, &args, NULL);
 
@@ -851,7 +1030,7 @@
 	args.tfRegister[IDE_HCYL_OFFSET]	= ((addr_req >> 16) & 0xff);
 	args.tfRegister[IDE_SELECT_OFFSET]	= ((addr_req >> 24) & 0x0f) | 0x40;
 	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SET_MAX;
-	args.handler				= task_no_data_intr;
+	args.command_type			= ide_cmd_type_parser(&args);
 	/* submit command request */
 	ide_raw_taskfile(drive, &args, NULL);
 	/* if OK, read new maximum address value */
@@ -883,7 +1062,7 @@
 	args.hobRegister[IDE_HCYL_OFFSET_HOB]	= ((addr_req >>= 8) & 0xff);
 	args.hobRegister[IDE_SELECT_OFFSET_HOB]	= 0x40;
 	args.hobRegister[IDE_CONTROL_OFFSET_HOB]= (drive->ctl|0x80);
-        args.handler				= task_no_data_intr;
+	args.command_type			= ide_cmd_type_parser(&args);
 	/* submit command request */
 	ide_raw_taskfile(drive, &args, NULL);
 	/* if OK, compute maximum address value */
@@ -899,6 +1078,8 @@
 	return addr_set;
 }
 
+#endif /* CONFIG_IDEDISK_STROKE */
+
 /*
  * Tests if the drive supports Host Protected Area feature.
  * Returns true if supported, false otherwise.
@@ -906,12 +1087,11 @@
 static inline int idedisk_supports_host_protected_area(ide_drive_t *drive)
 {
 	int flag = (drive->id->cfs_enable_1 & 0x0400) ? 1 : 0;
-	printk("%s: host protected area => %d\n", drive->name, flag);
+	if (flag)
+		printk("%s: host protected area => %d\n", drive->name, flag);
 	return flag;
 }
 
-#endif /* CONFIG_IDEDISK_STROKE */
-
 /*
  * Compute drive->capacity, the full capacity of the drive
  * Called with drive->id != NULL.
@@ -937,6 +1117,8 @@
 	drive->capacity48 = 0;
 	drive->select.b.lba = 0;
 
+	(void) idedisk_supports_host_protected_area(drive);
+
 	if (id->cfs_enable_2 & 0x0400) {
 		capacity_2 = id->lba_capacity_2;
 		drive->head		= drive->bios_head = 255;
@@ -955,10 +1137,11 @@
 				drive->id->lba_capacity_2 = capacity_2;
                         }
 #else /* !CONFIG_IDEDISK_STROKE */
-			printk("%s: setmax_ext LBA %llu, native  %llu\n",
+			printk(KERN_INFO "%s: setmax_ext LBA %llu, native  %llu\n",
 				drive->name, set_max_ext, capacity_2);
 #endif /* CONFIG_IDEDISK_STROKE */
 		}
+		drive->cyl = (unsigned int) capacity_2 / (drive->head * drive->sect);
 		drive->bios_cyl		= drive->cyl;
 		drive->capacity48	= capacity_2;
 		drive->capacity		= (unsigned long) capacity_2;
@@ -981,7 +1164,7 @@
 			drive->id->lba_capacity = capacity;
 		}
 #else /* !CONFIG_IDEDISK_STROKE */
-		printk("%s: setmax LBA %lu, native  %lu\n",
+		printk(KERN_INFO "%s: setmax LBA %lu, native  %lu\n",
 			drive->name, set_max, capacity);
 #endif /* CONFIG_IDEDISK_STROKE */
 	}
@@ -989,7 +1172,7 @@
 	drive->capacity = capacity;
 
 	if ((id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400)) {
-                drive->capacity48 = id->lba_capacity_2;
+		drive->capacity48 = id->lba_capacity_2;
 		drive->head = 255;
 		drive->sect = 63;
 		drive->cyl = (unsigned long)(drive->capacity48) / (drive->head * drive->sect);
@@ -1008,47 +1191,40 @@
 	special_t *s = &drive->special;
 
 	if (s->b.set_geometry) {
-		struct hd_drive_task_hdr taskfile;
-		struct hd_drive_hob_hdr hobfile;
-		ide_handler_t *handler = NULL;
-
-		memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-		memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-
 		s->b.set_geometry	= 0;
-		taskfile.sector_number	= drive->sect;
-		taskfile.low_cylinder	= drive->cyl;
-		taskfile.high_cylinder	= drive->cyl>>8;
-		taskfile.device_head	= ((drive->head-1)|drive->select.all)&0xBF;
 		if (!IS_PDC4030_DRIVE) {
-			taskfile.sector_count	= drive->sect;
-			taskfile.command	= WIN_SPECIFY;
-			handler			= ide_handler_parser(&taskfile, &hobfile);
+			ide_task_t args;
+			memset(&args, 0, sizeof(ide_task_t));
+			args.tfRegister[IDE_NSECTOR_OFFSET] = drive->sect;
+			args.tfRegister[IDE_SECTOR_OFFSET]  = drive->sect;
+			args.tfRegister[IDE_LCYL_OFFSET]    = drive->cyl;
+			args.tfRegister[IDE_HCYL_OFFSET]    = drive->cyl>>8;
+			args.tfRegister[IDE_SELECT_OFFSET]  = ((drive->head-1)|drive->select.all)&0xBF;
+			args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SPECIFY;
+			args.command_type = ide_cmd_type_parser(&args);
+			do_rw_taskfile(drive, &args);
 		}
-		do_taskfile(drive, &taskfile, &hobfile, handler);
 	} else if (s->b.recalibrate) {
 		s->b.recalibrate = 0;
 		if (!IS_PDC4030_DRIVE) {
-			struct hd_drive_task_hdr taskfile;
-			struct hd_drive_hob_hdr hobfile;
-			memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-			memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-			taskfile.sector_count	= drive->sect;
-			taskfile.command	= WIN_RESTORE;
-			do_taskfile(drive, &taskfile, &hobfile, ide_handler_parser(&taskfile, &hobfile));
+			ide_task_t args;
+			memset(&args, 0, sizeof(ide_task_t));
+			args.tfRegister[IDE_NSECTOR_OFFSET] = drive->sect;
+			args.tfRegister[IDE_COMMAND_OFFSET] = WIN_RESTORE;
+			args.command_type = ide_cmd_type_parser(&args);
+			do_rw_taskfile(drive, &args);
 		}
 	} else if (s->b.set_multmode) {
 		s->b.set_multmode = 0;
 		if (drive->id && drive->mult_req > drive->id->max_multsect)
 			drive->mult_req = drive->id->max_multsect;
 		if (!IS_PDC4030_DRIVE) {
-			struct hd_drive_task_hdr taskfile;
-			struct hd_drive_hob_hdr hobfile;
-			memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-			memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-			taskfile.sector_count	= drive->mult_req;
-			taskfile.command	= WIN_SETMULT;
-			do_taskfile(drive, &taskfile, &hobfile, ide_handler_parser(&taskfile, &hobfile));
+			ide_task_t args;
+			memset(&args, 0, sizeof(ide_task_t));
+			args.tfRegister[IDE_NSECTOR_OFFSET] = drive->mult_req;
+			args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SETMULT;
+			args.command_type = ide_cmd_type_parser(&args);
+			do_rw_taskfile(drive, &args);
 		}
 	} else if (s->all) {
 		int special = s->all;
@@ -1078,45 +1254,44 @@
 
 static int smart_enable(ide_drive_t *drive)
 {
-	struct hd_drive_task_hdr taskfile;
-	struct hd_drive_hob_hdr hobfile;
-	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-	taskfile.feature	= SMART_ENABLE;
-	taskfile.low_cylinder	= SMART_LCYL_PASS;
-	taskfile.high_cylinder	= SMART_HCYL_PASS;
-	taskfile.command	= WIN_SMART;
-	return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
-}
-
-static int get_smart_values(ide_drive_t *drive, byte *buf)
-{
-	struct hd_drive_task_hdr taskfile;
-	struct hd_drive_hob_hdr hobfile;
-	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-	taskfile.feature	= SMART_READ_VALUES;
-	taskfile.sector_count	= 0x01;
-	taskfile.low_cylinder	= SMART_LCYL_PASS;
-	taskfile.high_cylinder	= SMART_HCYL_PASS;
-	taskfile.command	= WIN_SMART;
+	ide_task_t args;
+
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_FEATURE_OFFSET]	= SMART_ENABLE;
+	args.tfRegister[IDE_LCYL_OFFSET]	= SMART_LCYL_PASS;
+	args.tfRegister[IDE_HCYL_OFFSET]	= SMART_HCYL_PASS;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SMART;
+	args.command_type			= ide_cmd_type_parser(&args);
+	return ide_raw_taskfile(drive, &args, NULL);
+}
+
+static int get_smart_values(ide_drive_t *drive, u8 *buf)
+{
+	ide_task_t args;
+
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_FEATURE_OFFSET]	= SMART_READ_VALUES;
+	args.tfRegister[IDE_NSECTOR_OFFSET]	= 0x01;
+	args.tfRegister[IDE_LCYL_OFFSET]	= SMART_LCYL_PASS;
+	args.tfRegister[IDE_HCYL_OFFSET]	= SMART_HCYL_PASS;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SMART;
+	args.command_type			= ide_cmd_type_parser(&args);
 	(void) smart_enable(drive);
-	return ide_wait_taskfile(drive, &taskfile, &hobfile, buf);
+	return ide_raw_taskfile(drive, &args, buf);
 }
 
-static int get_smart_thresholds(ide_drive_t *drive, byte *buf)
+static int get_smart_thresholds(ide_drive_t *drive, u8 *buf)
 {
-	struct hd_drive_task_hdr taskfile;
-	struct hd_drive_hob_hdr hobfile;
-	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-	taskfile.feature	= SMART_READ_THRESHOLDS;
-	taskfile.sector_count	= 0x01;
-	taskfile.low_cylinder	= SMART_LCYL_PASS;
-	taskfile.high_cylinder	= SMART_HCYL_PASS;
-	taskfile.command	= WIN_SMART;
+	ide_task_t args;
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_FEATURE_OFFSET]	= SMART_READ_THRESHOLDS;
+	args.tfRegister[IDE_NSECTOR_OFFSET]	= 0x01;
+	args.tfRegister[IDE_LCYL_OFFSET]	= SMART_LCYL_PASS;
+	args.tfRegister[IDE_HCYL_OFFSET]	= SMART_HCYL_PASS;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SMART;
+	args.command_type			= ide_cmd_type_parser(&args);
 	(void) smart_enable(drive);
-	return ide_wait_taskfile(drive, &taskfile, &hobfile, buf);
+	return ide_raw_taskfile(drive, &args, buf);
 }
 
 static int proc_idedisk_read_cache
@@ -1185,23 +1360,12 @@
 
 #endif	/* CONFIG_PROC_FS */
 
+/*
+ * This is tightly woven into the driver->do_special can not touch.
+ * DON'T do it again until a total personality rewrite is committed.
+ */
 static int set_multcount(ide_drive_t *drive, int arg)
 {
-#ifdef __TASKFILE__IO
-	struct hd_drive_task_hdr taskfile;
-	struct hd_drive_hob_hdr hobfile;
-
-	if (drive->special.b.set_multmode)
-		return -EBUSY;
-
-	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-	taskfile.sector_count	= drive->mult_req;
-	taskfile.command	= WIN_SETMULT;
-	drive->mult_req		= arg;
-	drive->special.b.set_multmode = 1;
-	ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
-#else /* !__TASKFILE__IO */
 	struct request rq;
 
 	if (drive->special.b.set_multmode)
@@ -1211,7 +1375,6 @@
 	drive->mult_req = arg;
 	drive->special.b.set_multmode = 1;
 	(void) ide_do_drive_cmd (drive, &rq, ide_wait);
-#endif /* __TASKFILE__IO */
 	return (drive->mult_count == arg) ? 0 : -EIO;
 }
 
@@ -1227,57 +1390,112 @@
 
 static int write_cache (ide_drive_t *drive, int arg)
 {
-	struct hd_drive_task_hdr taskfile;
-	struct hd_drive_hob_hdr hobfile;
-	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-	taskfile.feature	= (arg) ? SETFEATURES_EN_WCACHE : SETFEATURES_DIS_WCACHE;
-	taskfile.command	= WIN_SETFEATURES;
+	ide_task_t args;
 
 	if (!(drive->id->cfs_enable_2 & 0x3000))
 		return 1;
 
-	(void) ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_FEATURE_OFFSET]	= (arg) ?
+			SETFEATURES_EN_WCACHE : SETFEATURES_DIS_WCACHE;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SETFEATURES;
+	args.command_type			= ide_cmd_type_parser(&args);
+	(void) ide_raw_taskfile(drive, &args, NULL);
+
 	drive->wcache = arg;
 	return 0;
 }
 
+static int call_idedisk_standby (ide_drive_t *drive, int arg)
+{
+	ide_task_t args;
+	u8 standby = (arg) ? WIN_STANDBYNOW2 : WIN_STANDBYNOW1;
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_COMMAND_OFFSET]	= standby;
+	args.command_type			= ide_cmd_type_parser(&args);
+	return ide_raw_taskfile(drive, &args, NULL);
+}
+
 static int do_idedisk_standby (ide_drive_t *drive)
 {
-	struct hd_drive_task_hdr taskfile;
-	struct hd_drive_hob_hdr hobfile;
-	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-	taskfile.command	= WIN_STANDBYNOW1;
-	return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+	return call_idedisk_standby(drive, 0);
+}
+
+static int call_idedisk_suspend (ide_drive_t *drive, int arg)
+{
+	ide_task_t args;
+	u8 suspend = (arg) ? WIN_SLEEPNOW2 : WIN_SLEEPNOW1;
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_COMMAND_OFFSET]	= suspend;
+	args.command_type			= ide_cmd_type_parser(&args);
+	return ide_raw_taskfile(drive, &args, NULL);
+}
+
+static int do_idedisk_suspend (ide_drive_t *drive)
+{
+	if (drive->suspend_reset)
+		return 1;
+
+	return call_idedisk_suspend(drive, 0);
+}
+
+#if 0
+static int call_idedisk_checkpower (ide_drive_t *drive, int arg)
+{
+	ide_task_t args;
+	u8 ckpw = (arg) ? WIN_CHECKPOWERMODE2 : WIN_CHECKPOWERMODE1;
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_COMMAND_OFFSET]	= ckpw;
+	args.command_type			= ide_cmd_type_parser(&args);
+	ide_raw_taskfile(drive, &args, NULL);
+#if 0
+if (errno != EIO || args[0] != 0 || args[1] != 0)
+   state = "unknown";
+else
+   state = "sleeping";
+} else {
+   state = (args[2] == 255) ? "active/idle" : "standby";
+#endif
+	return 0;
+}
+
+static int do_idedisk_checkpower (ide_drive_t *drive)
+{
+	return call_idedisk_checkpower(drive, 0);
+}
+#endif
+
+static int do_idedisk_resume (ide_drive_t *drive)
+{
+	if (!drive->suspend_reset)
+		return 1;
+	return 0;
 }
 
 static int do_idedisk_flushcache (ide_drive_t *drive)
 {
-	struct hd_drive_task_hdr taskfile;
-	struct hd_drive_hob_hdr hobfile;
-	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-	if (drive->id->cfs_enable_2 & 0x2400) {
-		taskfile.command	= WIN_FLUSH_CACHE_EXT;
-	} else {
-		taskfile.command	= WIN_FLUSH_CACHE;
-	}
-	return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+	ide_task_t args;
+
+	memset(&args, 0, sizeof(ide_task_t));
+	if (drive->id->cfs_enable_2 & 0x2400)
+		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_FLUSH_CACHE_EXT;
+	else
+		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_FLUSH_CACHE;
+	args.command_type	 		= ide_cmd_type_parser(&args);
+	return ide_raw_taskfile(drive, &args, NULL);
 }
 
 static int set_acoustic (ide_drive_t *drive, int arg)
 {
-	struct hd_drive_task_hdr taskfile;
-	struct hd_drive_hob_hdr hobfile;
-	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-
-	taskfile.feature	= (arg)?SETFEATURES_EN_AAM:SETFEATURES_DIS_AAM;
-	taskfile.sector_count	= arg;
+	ide_task_t args;
 
-	taskfile.command	= WIN_SETFEATURES;
-	(void) ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_FEATURE_OFFSET]	= (arg) ? SETFEATURES_EN_AAM :
+							  SETFEATURES_DIS_AAM;
+	args.tfRegister[IDE_NSECTOR_OFFSET]	= arg;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SETFEATURES;
+	args.command_type = ide_cmd_type_parser(&args);
+	ide_raw_taskfile(drive, &args, NULL);
 	drive->acoustic = arg;
 	return 0;
 }
@@ -1286,9 +1504,11 @@
 {
 	drive->addressing =  0;
 
+	if (HWIF(drive)->addressing)
+		return 0;
+
 	if (!(drive->id->cfs_enable_2 & 0x0400))
                 return -EIO;
-
 	drive->addressing = arg;
 	return 0;
 }
@@ -1321,12 +1541,35 @@
  	ide_add_setting(drive,	"max_failures",		SETTING_RW,					-1,			-1,			TYPE_INT,	0,	65535,				1,	1,	&drive->max_failures,		NULL);
 }
 
+static int idedisk_ioctl (ide_drive_t *drive, struct inode *inode,
+		struct file *file, unsigned int cmd, unsigned long arg)
+{
+#if 0
+HDIO_GET_ADDRESS
+HDIO_SET_ADDRESS
+HDIO_GET_WCACHE
+HDIO_SET_WCACHE
+HDIO_GET_ACOUSTIC
+HDIO_SET_ACOUSTIC
+HDIO_GET_MULTCOUNT
+HDIO_SET_MULTCOUNT
+HDIO_GET_NOWERR
+HDIO_SET_NOWERR
+#endif
+	return -EINVAL;
+}
+
 static void idedisk_setup (ide_drive_t *drive)
 {
 	int i;
 	
 	struct hd_driveid *id = drive->id;
 	unsigned long capacity;
+
+#if 0
+	if (IS_PDC4030_DRIVE)
+		DRIVER(drive)->do_request = promise_rw_disk;
+#endif
 	
 	idedisk_add_settings(drive);
 
@@ -1337,7 +1580,7 @@
 	 * CompactFlash cards and their brethern look just like hard drives
 	 * to us, but they are removable and don't have a doorlock mechanism.
 	 */
-	if (drive->removable && !drive_is_flashcard(drive)) {
+	if (drive->removable && !(drive->is_flash)) {
 		/*
 		 * Removable disks (eg. SYQUEST); ignore 'WD' drives 
 		 */
@@ -1355,6 +1598,14 @@
 		break;
 	}
 
+#if 1
+	(void) probe_lba_addressing(drive, 1);
+#else
+	/* if using 48-bit addressing bump the request size up */
+	if (probe_lba_addressing(drive, 1))
+		blk_queue_max_sectors(&drive->queue, 2048);
+#endif
+
 	/* Extract geometry if we did not already have one for the drive */
 	if (!drive->cyl || !drive->head || !drive->sect) {
 		drive->cyl     = drive->bios_cyl  = id->cyls;
@@ -1402,7 +1653,7 @@
 	       drive->bios_cyl, drive->bios_head, drive->bios_sect);
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (drive->using_dma)
-		(void) HWIF(drive)->dmaproc(ide_dma_verbose, drive);
+		(void) HWIF(drive)->ide_dma_verbose(drive);
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 	printk("\n");
 
@@ -1424,10 +1675,9 @@
 	drive->no_io_32bit = id->dword_io ? 1 : 0;
 	if (drive->id->cfs_enable_2 & 0x3000)
 		write_cache(drive, (id->cfs_enable_2 & 0x3000));
-	(void) probe_lba_addressing(drive, 1);
 }
 
-static int idedisk_cleanup (ide_drive_t *drive)
+static int idedisk_cleanup(ide_drive_t *drive)
 {
 	if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache)
 		if (do_idedisk_flushcache(drive))
@@ -1436,7 +1686,8 @@
 	return ide_unregister_subdriver(drive);
 }
 
-int idedisk_reinit(ide_drive_t *drive);
+int idedisk_init (void);
+int idedisk_attach(ide_drive_t *drive);
 
 /*
  *      IDE subdriver functions, registered with ide.c
@@ -1450,10 +1701,14 @@
 	supports_dsc_overlap:	0,
 	cleanup:		idedisk_cleanup,
 	standby:		do_idedisk_standby,
+	suspend:		do_idedisk_suspend,
+	resume:			do_idedisk_resume,
 	flushcache:		do_idedisk_flushcache,
 	do_request:		do_rw_disk,
-	end_request:		NULL,
-	ioctl:			NULL,
+	end_request:		idedisk_end_request,
+	sense:			idedisk_dump_status,
+	error:			idedisk_error,
+	ioctl:			idedisk_ioctl,
 	open:			idedisk_open,
 	release:		idedisk_release,
 	media_change:		idedisk_media_change,
@@ -1462,12 +1717,12 @@
 	capacity:		idedisk_capacity,
 	special:		idedisk_special,
 	proc:			idedisk_proc,
-	reinit:			idedisk_reinit,
+	init:			idedisk_init,
+	attach:			idedisk_attach,
 	ata_prebuilder:		NULL,
 	atapi_prebuilder:	NULL,
 };
 
-int idedisk_init (void);
 static ide_module_t idedisk_module = {
 	IDE_DRIVER_MODULE,
 	idedisk_init,
@@ -1477,30 +1732,30 @@
 
 MODULE_DESCRIPTION("ATA DISK Driver");
 
-int idedisk_reinit (ide_drive_t *drive)
+int idedisk_attach (ide_drive_t *drive)
 {
-	int failed = 0;
+	int ret = 0;
 
 	MOD_INC_USE_COUNT;
-
-	if (ide_register_subdriver (drive, &idedisk_driver, IDE_SUBDRIVER_VERSION)) {
-		printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name);
-		return 1;
+	if (ide_register_subdriver(drive,
+			&idedisk_driver, IDE_SUBDRIVER_VERSION)) {
+		printk(KERN_ERR "ide-disk: %s: Failed to register the "
+			"driver with ide.c\n", drive->name);
+		ret= 1;
+		goto bye_game_over;
 	}
 	DRIVER(drive)->busy++;
 	idedisk_setup(drive);
 	if ((!drive->head || drive->head > 16) && !drive->select.b.lba) {
-		printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", drive->name, drive->head);
+		printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n",
+			drive->name, drive->head);
 		(void) idedisk_cleanup(drive);
-		DRIVER(drive)->busy--;
-		return 1;
+		ret= 1;
 	}
 	DRIVER(drive)->busy--;
-	failed--;
-
-	ide_register_module(&idedisk_module);
+bye_game_over:
 	MOD_DEC_USE_COUNT;
-	return 0;
+	return ret;
 }
 
 static void __exit idedisk_exit (void)
@@ -1508,14 +1763,17 @@
 	ide_drive_t *drive;
 	int failed = 0;
 
-	while ((drive = ide_scan_devices (ide_disk, idedisk_driver.name, &idedisk_driver, failed)) != NULL) {
+	while ((drive = ide_scan_devices(ide_disk, idedisk_driver.name,
+			&idedisk_driver, failed)) != NULL) {
 		if (idedisk_cleanup (drive)) {
-			printk (KERN_ERR "%s: cleanup_module() called while still busy\n", drive->name);
+			printk(KERN_ERR "%s: cleanup_module() called while "
+				"still busy\n", drive->name);
 			failed++;
 		}
-		/* We must remove proc entries defined in this module.
-		   Otherwise we oops while accessing these entries */
 #ifdef CONFIG_PROC_FS
+		/* We must remove proc entries defined in this module.
+		 * Otherwise we oops while accessing these entries
+		 */
 		if (drive->proc)
 			ide_remove_proc_entries(drive->proc, idedisk_proc);
 #endif
@@ -1525,19 +1783,28 @@
 
 int idedisk_init (void)
 {
+#ifdef CLASSIC_BUILTINS_METHOD
 	ide_drive_t *drive;
 	int failed = 0;
-	
+#endif /* CLASSIC_BUILTINS_METHOD */
+
 	MOD_INC_USE_COUNT;
-	while ((drive = ide_scan_devices (ide_disk, idedisk_driver.name, NULL, failed++)) != NULL) {
-		if (ide_register_subdriver (drive, &idedisk_driver, IDE_SUBDRIVER_VERSION)) {
-			printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name);
+
+#ifdef CLASSIC_BUILTINS_METHOD
+	while ((drive = ide_scan_devices(ide_disk,
+			idedisk_driver.name, NULL, failed++)) != NULL) {
+		if (ide_register_subdriver(drive,
+				&idedisk_driver, IDE_SUBDRIVER_VERSION)) {
+			printk(KERN_ERR "ide-disk: %s: Failed to register "
+				"the driver with ide.c\n", drive->name);
 			continue;
 		}
 		DRIVER(drive)->busy++;
 		idedisk_setup(drive);
-		if ((!drive->head || drive->head > 16) && !drive->select.b.lba) {
-			printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", drive->name, drive->head);
+		if ((!drive->head || drive->head > 16) &&
+		    (!drive->select.b.lba)) {
+			printk(KERN_ERR "%s: INVALID GEOMETRY: %d "
+				"PHYSICAL HEADS?\n", drive->name, drive->head);
 			(void) idedisk_cleanup(drive);
 			DRIVER(drive)->busy--;
 			continue;
@@ -1545,11 +1812,85 @@
 		DRIVER(drive)->busy--;
 		failed--;
 	}
+#endif /* CLASSIC_BUILTINS_METHOD */
+
 	ide_register_module(&idedisk_module);
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
+ide_startstop_t panic_box(ide_drive_t *drive)
+{
+#if 0
+	panic("%s: Attempted to corrupt something: ide operation "
+#else
+	printk(KERN_ERR "%s: Attempted to corrupt something: ide operation "
+#endif
+		"was pending accross suspend/resume.\n", drive->name);
+	return ide_stopped;
+}
+
+int ide_disks_busy(void)
+{
+	int i;
+	for (i=0; i<MAX_HWIFS; i++) {
+		struct hwgroup_s *hwgroup = ide_hwifs[i].hwgroup;
+		if (!hwgroup) continue;
+		if ((hwgroup->handler) && (hwgroup->handler != panic_box))
+			return 1;
+	}
+	return 0;
+}
+
+void ide_disk_suspend(void)
+{
+	int i;
+	while (ide_disks_busy()) {
+		printk("*");
+		schedule();
+	}
+	for (i=0; i<MAX_HWIFS; i++) {
+		struct hwgroup_s *hwgroup = ide_hwifs[i].hwgroup;
+
+		if (!hwgroup) continue;
+		hwgroup->handler_save = hwgroup->handler;
+		hwgroup->handler = panic_box;
+	}
+	driver_blocked = 1;
+	if (ide_disks_busy())
+		panic("How did you get that request through?!");
+}
+
+/* unsuspend and resume should be equal in the ideal world */
+
+void ide_disk_unsuspend(void)
+{
+	int i;
+	for (i=0; i<MAX_HWIFS; i++) {
+		struct hwgroup_s *hwgroup = ide_hwifs[i].hwgroup;
+
+		if (!hwgroup) continue;
+		hwgroup->handler = NULL; /* hwgroup->handler_save; */
+		hwgroup->handler_save = NULL;
+	}
+	driver_blocked = 0;
+}
+
+void ide_disk_resume(void)
+{
+	int i;
+	for (i=0; i<MAX_HWIFS; i++) {
+		struct hwgroup_s *hwgroup = ide_hwifs[i].hwgroup;
+
+		if (!hwgroup) continue;
+		if (hwgroup->handler != panic_box)
+			panic("Handler was not set to panic?");
+		hwgroup->handler_save = NULL;
+		hwgroup->handler = NULL;
+	}
+	driver_blocked = 0;
+}
+
 module_init(idedisk_init);
 module_exit(idedisk_exit);
 MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-dma.c linux-2.4.21-pre6/drivers/ide/ide-dma.c
--- linux-2.4.20/drivers/ide/ide-dma.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/ide-dma.c	2003-03-26 23:49:10.000000000 +0000
@@ -70,14 +70,13 @@
  *
  * And, yes, Intel Zappa boards really *do* use both PIIX IDE ports.
  *
- * check_drive_lists(ide_drive_t *drive, int good_bad)
- *
  * ATA-66/100 and recovery functions, I forgot the rest......
- * SELECT_READ_WRITE(hwif,drive,func) for active tuning based on IO direction.
  *
  */
 
 #include <linux/config.h>
+#define __NO_VERSION__
+#include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/timer.h>
@@ -86,22 +85,12 @@
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/ide.h>
+#include <linux/delay.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
 
-/*
- * Long lost data from 2.0.34 that is now in 2.0.39
- *
- * This was used in ./drivers/block/triton.c to do DMA Base address setup
- * when PnP failed.  Oh the things we forget.  I believe this was part
- * of SFF-8038i that has been withdrawn from public access... :-((
- */
-#define DEFAULT_BMIBA	0xe800	/* in case BIOS did not init it */
-#define DEFAULT_BMCRBA	0xcc00	/* VIA's default value */
-#define DEFAULT_BMALIBA	0xd400	/* ALI's default value */
-
-extern char *ide_dmafunc_verbose(ide_dma_action_t dmafunc);
+#define CONFIG_IDEDMA_NEW_DRIVE_LISTINGS
 
 #ifdef CONFIG_IDEDMA_NEW_DRIVE_LISTINGS
 
@@ -123,7 +112,6 @@
 
 	{ "WDC AC11000H"	,	"ALL"		},
 	{ "WDC AC22100H"	,	"ALL"		},
-	{ "WDC AC31000H"	,	"ALL"		},
 	{ "WDC AC32500H"	,	"ALL"		},
 	{ "WDC AC33100H"	,	"ALL"		},
 	{ "WDC AC31600H"	,	"ALL"		},
@@ -159,11 +147,20 @@
 
 };
 
-int in_drive_list(struct hd_driveid *id, struct drive_list_entry * drive_table)
+/**
+ *	in_drive_list	-	look for drive in black/white list
+ *	@id: drive identifier
+ *	@drive_table: list to inspect
+ *
+ *	Look for a drive in the blacklist and the whitelist tables
+ *	Returns 1 if the drive is found in the table.
+ */
+
+static int in_drive_list(struct hd_driveid *id, struct drive_list_entry * drive_table)
 {
 	for ( ; drive_table->id_model ; drive_table++)
 		if ((!strcmp(drive_table->id_model, id->model)) &&
-		    ((!strstr(drive_table->id_firmware, id->fw_rev)) ||
+		    ((strstr(drive_table->id_firmware, id->fw_rev)) ||
 		     (!strcmp(drive_table->id_firmware, "ALL"))))
 			return 1;
 	return 0;
@@ -203,52 +200,52 @@
 
 #endif /* CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
 
-/*
- * Our Physical Region Descriptor (PRD) table should be large enough
- * to handle the biggest I/O request we are likely to see.  Since requests
- * can have no more than 256 sectors, and since the typical blocksize is
- * two or more sectors, we could get by with a limit of 128 entries here for
- * the usual worst case.  Most requests seem to include some contiguous blocks,
- * further reducing the number of table entries required.
- *
- * The driver reverts to PIO mode for individual requests that exceed
- * this limit (possible with 512 byte blocksizes, eg. MSDOS f/s), so handling
- * 100% of all crazy scenarios here is not necessary.
- *
- * As it turns out though, we must allocate a full 4KB page for this,
- * so the two PRD tables (ide0 & ide1) will each get half of that,
- * allowing each to have about 256 entries (8 bytes each) from this.
- */
-#define PRD_BYTES	8
-#define PRD_ENTRIES	(PAGE_SIZE / (2 * PRD_BYTES))
-
-/*
- * dma_intr() is the handler for disk read/write DMA interrupts
+/**
+ *	ide_dma_intr	-	IDE DMA interrupt handler
+ *	@drive: the drive the interrupt is for
+ *
+ *	Handle an interrupt completing a read/write DMA transfer on an 
+ *	IDE device
  */
+ 
 ide_startstop_t ide_dma_intr (ide_drive_t *drive)
 {
+	u8 stat = 0, dma_stat = 0;
 	int i;
-	byte stat, dma_stat;
 
-	dma_stat = HWIF(drive)->dmaproc(ide_dma_end, drive);
-	stat = GET_STAT();			/* get drive status */
+	dma_stat = HWIF(drive)->ide_dma_end(drive);
+	stat = HWIF(drive)->INB(IDE_STATUS_REG);	/* get drive status */
 	if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
 		if (!dma_stat) {
 			struct request *rq = HWGROUP(drive)->rq;
-			rq = HWGROUP(drive)->rq;
+	//		rq = HWGROUP(drive)->rq;
 			for (i = rq->nr_sectors; i > 0;) {
 				i -= rq->current_nr_sectors;
-				ide_end_request(1, HWGROUP(drive));
+				DRIVER(drive)->end_request(drive, 1);
 			}
 			return ide_stopped;
 		}
 		printk("%s: dma_intr: bad DMA status (dma_stat=%x)\n", 
 		       drive->name, dma_stat);
 	}
-	return ide_error(drive, "dma_intr", stat);
+	return DRIVER(drive)->error(drive, "dma_intr", stat);
 }
 
-static int ide_build_sglist (ide_hwif_t *hwif, struct request *rq)
+EXPORT_SYMBOL_GPL(ide_dma_intr);
+
+/**
+ *	ide_build_sglist	-	map IDE scatter gather for DMA I/O
+ *	@hwif: the interface to build the DMA table for
+ *	@rq: the request holding the sg list
+ *	@ddir: data direction
+ *
+ *	Perform the PCI mapping magic neccessary to access the source or
+ *	target buffers of a request via PCI DMA. The lower layers of the
+ *	kernel provide the neccessary cache management so that we can
+ *	operate in a portable fashion
+ */
+ 
+static int ide_build_sglist (ide_hwif_t *hwif, struct request *rq, int ddir)
 {
 	struct buffer_head *bh;
 	struct scatterlist *sg = hwif->sg_table;
@@ -258,66 +255,76 @@
 	if (hwif->sg_dma_active)
 		BUG();
 
-	if (rq->cmd == READ)
-		hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
-	else
-		hwif->sg_dma_direction = PCI_DMA_TODEVICE;
-
 	bh = rq->bh;
 	do {
-		struct scatterlist *sge;
+		int contig = 0;
 
-		/*
-		 * continue segment from before?
-		 */
-		if (bh_phys(bh) == lastdataend) {
+		if (bh->b_page) {
+			if (bh_phys(bh) == lastdataend)
+				contig = 1;
+		} else {
+			if ((unsigned long) bh->b_data == lastdataend)
+				contig = 1;
+		}
+
+		if (contig) {
 			sg[nents - 1].length += bh->b_size;
 			lastdataend += bh->b_size;
 			continue;
 		}
 
-		/*
-		 * start new segment
-		 */
 		if (nents >= PRD_ENTRIES)
 			return 0;
 
-		sge = &sg[nents];
-		memset(sge, 0, sizeof(*sge));
+		memset(&sg[nents], 0, sizeof(*sg));
 
 		if (bh->b_page) {
-			sge->page = bh->b_page;
-			sge->offset = bh_offset(bh);
+			sg[nents].page = bh->b_page;
+			sg[nents].offset = bh_offset(bh);
+			lastdataend = bh_phys(bh) + bh->b_size;
 		} else {
-			if (((unsigned long) bh->b_data) < PAGE_SIZE)
+			if ((unsigned long) bh->b_data < PAGE_SIZE)
 				BUG();
 
-			sge->address = bh->b_data;
+			sg[nents].address = bh->b_data;
+			lastdataend = (unsigned long) bh->b_data + bh->b_size;
 		}
 
-		sge->length = bh->b_size;
-		lastdataend = bh_phys(bh) + bh->b_size;
+		sg[nents].length = bh->b_size;
 		nents++;
 	} while ((bh = bh->b_reqnext) != NULL);
 
-	return pci_map_sg(hwif->pci_dev, sg, nents, hwif->sg_dma_direction);
+	if(nents == 0)
+		BUG();
+		
+	hwif->sg_dma_direction = ddir;
+	return pci_map_sg(hwif->pci_dev, sg, nents, ddir);
 }
 
+/**
+ *	ide_raw_build_sglist	-	map IDE scatter gather for DMA
+ *	@hwif: the interface to build the DMA table for
+ *	@rq: the request holding the sg list
+ *
+ *	Perform the PCI mapping magic neccessary to access the source or
+ *	target buffers of a taskfile request via PCI DMA. The lower layers 
+ *	of the  kernel provide the neccessary cache management so that we can
+ *	operate in a portable fashion
+ */
+ 
 static int ide_raw_build_sglist (ide_hwif_t *hwif, struct request *rq)
 {
 	struct scatterlist *sg = hwif->sg_table;
 	int nents = 0;
 	ide_task_t *args = rq->special;
-	unsigned char *virt_addr = rq->buffer;
+	u8 *virt_addr = rq->buffer;
 	int sector_count = rq->nr_sectors;
 
-//	if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_WRITEDMA) ||
-//	    (args->tfRegister[IDE_COMMAND_OFFSET] == WIN_WRITEDMA_EXT))
 	if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
 		hwif->sg_dma_direction = PCI_DMA_TODEVICE;
 	else
 		hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
-	
+#if 1
 	if (sector_count > 128) {
 		memset(&sg[nents], 0, sizeof(*sg));
 		sg[nents].address = virt_addr;
@@ -330,37 +337,54 @@
 	sg[nents].address = virt_addr;
 	sg[nents].length =  sector_count  * SECTOR_SIZE;
 	nents++;
-   
+#else
+        while (sector_count > 128) {
+		memset(&sg[nents], 0, sizeof(*sg));
+		sg[nents].address	= virt_addr;
+		sg[nents].length	= 128 * SECTOR_SIZE;
+		nents++;
+		virt_addr		= virt_addr + (128 * SECTOR_SIZE);
+		sector_count		-= 128;
+	};
+	memset(&sg[nents], 0, sizeof(*sg));
+	sg[nents].address	= virt_addr;
+	sg[nents].length	= sector_count * SECTOR_SIZE;
+	nents++;
+#endif
 	return pci_map_sg(hwif->pci_dev, sg, nents, hwif->sg_dma_direction);
 }
 
-/*
- * ide_build_dmatable() prepares a dma request.
- * Returns 0 if all went okay, returns 1 otherwise.
- * May also be invoked from trm290.c
- */
-int ide_build_dmatable (ide_drive_t *drive, ide_dma_action_t func)
-{
-	unsigned int *table = HWIF(drive)->dmatable_cpu;
-#ifdef CONFIG_BLK_DEV_TRM290
-	unsigned int is_trm290_chipset = (HWIF(drive)->chipset == ide_trm290);
-#else
-	const int is_trm290_chipset = 0;
-#endif
+/**
+ *	ide_build_dmatable	-	build IDE DMA table
+ *
+ *	ide_build_dmatable() prepares a dma request. We map the command
+ *	to get the pci bus addresses of the buffers and then build up
+ *	the PRD table that the IDE layer wants to be fed. The code
+ *	knows about the 64K wrap bug in the CS5530.
+ *
+ *	Returns 0 if all went okay, returns 1 otherwise.
+ *	May also be invoked from trm290.c
+ */
+ 
+int ide_build_dmatable (ide_drive_t *drive, struct request *rq, int ddir)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	unsigned int *table	= hwif->dmatable_cpu;
+	unsigned int is_trm290	= (hwif->chipset == ide_trm290) ? 1 : 0;
 	unsigned int count = 0;
 	int i;
 	struct scatterlist *sg;
 
-	if (HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE)
-		HWIF(drive)->sg_nents = i = ide_raw_build_sglist(HWIF(drive), HWGROUP(drive)->rq);
+	if (rq->cmd == IDE_DRIVE_TASKFILE)
+		hwif->sg_nents = i = ide_raw_build_sglist(hwif, rq);
 	else
-		HWIF(drive)->sg_nents = i = ide_build_sglist(HWIF(drive), HWGROUP(drive)->rq);
+		hwif->sg_nents = i = ide_build_sglist(hwif, rq, ddir);
 
 	if (!i)
 		return 0;
 
-	sg = HWIF(drive)->sg_table;
-	while (i) {
+	sg = hwif->sg_table;
+	while (i && sg_dma_len(sg)) {
 		u32 cur_addr;
 		u32 cur_len;
 
@@ -374,35 +398,36 @@
 		 */
 
 		while (cur_len) {
-			u32 xcount, bcount = 0x10000 - (cur_addr & 0xffff);
-			
-			if (count++ >= PRD_ENTRIES)
-				BUG();
+			if (count++ >= PRD_ENTRIES) {
+				printk("%s: DMA table too small\n", drive->name);
+				goto use_pio_instead;
+			} else {
+				u32 xcount, bcount = 0x10000 - (cur_addr & 0xffff);
 
-			if (bcount > cur_len)
-				bcount = cur_len;
-			*table++ = cpu_to_le32(cur_addr);
-			xcount = bcount & 0xffff;
-			if (is_trm290_chipset)
-				xcount = ((xcount >> 2) - 1) << 16;
-			if (xcount == 0x0000) {
-				/* 
-				 * Most chipsets correctly interpret a length
-				 * of 0x0000 as 64KB, but at least one
-				 * (e.g. CS5530) misinterprets it as zero (!).
-				 * So here we break the 64KB entry into two
-				 * 32KB entries instead.
-				 */
-				if (count++ >= PRD_ENTRIES)
-					goto use_pio_instead;
-
-				*table++ = cpu_to_le32(0x8000);
-				*table++ = cpu_to_le32(cur_addr + 0x8000);
-				xcount = 0x8000;
+				if (bcount > cur_len)
+					bcount = cur_len;
+				*table++ = cpu_to_le32(cur_addr);
+				xcount = bcount & 0xffff;
+				if (is_trm290)
+					xcount = ((xcount >> 2) - 1) << 16;
+				if (xcount == 0x0000) {
+	/* 
+	 * Most chipsets correctly interpret a length of 0x0000 as 64KB,
+	 * but at least one (e.g. CS5530) misinterprets it as zero (!).
+	 * So here we break the 64KB entry into two 32KB entries instead.
+	 */
+					if (count++ >= PRD_ENTRIES) {
+						printk("%s: DMA table too small\n", drive->name);
+						goto use_pio_instead;
+					}
+					*table++ = cpu_to_le32(0x8000);
+					*table++ = cpu_to_le32(cur_addr + 0x8000);
+					xcount = 0x8000;
+				}
+				*table++ = cpu_to_le32(xcount);
+				cur_addr += bcount;
+				cur_len -= bcount;
 			}
-			*table++ = cpu_to_le32(xcount);
-			cur_addr += bcount;
-			cur_len -= bcount;
 		}
 
 		sg++;
@@ -410,21 +435,33 @@
 	}
 
 	if (count) {
-		if (!is_trm290_chipset)
+		if (!is_trm290)
 			*--table |= cpu_to_le32(0x80000000);
 		return count;
 	}
 	printk("%s: empty DMA table?\n", drive->name);
 use_pio_instead:
-	pci_unmap_sg(HWIF(drive)->pci_dev,
-		     HWIF(drive)->sg_table,
-		     HWIF(drive)->sg_nents,
-		     HWIF(drive)->sg_dma_direction);
-	HWIF(drive)->sg_dma_active = 0;
+	pci_unmap_sg(hwif->pci_dev,
+		     hwif->sg_table,
+		     hwif->sg_nents,
+		     hwif->sg_dma_direction);
+	hwif->sg_dma_active = 0;
 	return 0; /* revert to PIO for this request */
 }
 
-/* Teardown mappings after DMA has completed.  */
+EXPORT_SYMBOL_GPL(ide_build_dmatable);
+
+/**
+ *	ide_destroy_dmatable	-	clean up DMA mapping
+ *	@drive: The drive to unmap
+ *
+ *	Teardown mappings after DMA has completed. This must be called
+ *	after the completion of each use of ide_build_dmatable and before
+ *	the next use of ide_build_dmatable. Failure to do so will cause
+ *	an oops as only one mapping can be live for each target at a given
+ *	time.
+ */
+ 
 void ide_destroy_dmatable (ide_drive_t *drive)
 {
 	struct pci_dev *dev = HWIF(drive)->pci_dev;
@@ -435,336 +472,513 @@
 	HWIF(drive)->sg_dma_active = 0;
 }
 
-/*
- *  For both Blacklisted and Whitelisted drives.
- *  This is setup to be called as an extern for future support
- *  to other special driver code.
+EXPORT_SYMBOL_GPL(ide_destroy_dmatable);
+
+/**
+ *	config_drive_for_dma	-	attempt to activate IDE DMA
+ *	@drive: the drive to place in DMA mode
+ *
+ *	If the drive supports at least mode 2 DMA or UDMA of any kind
+ *	then attempt to place it into DMA mode. Drives that are known to
+ *	support DMA but predate the DMA properties or that are known
+ *	to have DMA handling bugs are also set up appropriately based
+ *	on the good/bad drive lists.
  */
-int check_drive_lists (ide_drive_t *drive, int good_bad)
+ 
+static int config_drive_for_dma (ide_drive_t *drive)
 {
 	struct hd_driveid *id = drive->id;
+	ide_hwif_t *hwif = HWIF(drive);
 
-#ifdef CONFIG_IDEDMA_NEW_DRIVE_LISTINGS
-	if (good_bad) {
-		return in_drive_list(id, drive_whitelist);
-	} else {
-		int blacklist = in_drive_list(id, drive_blacklist);
-		if (blacklist)
-			printk("%s: Disabling (U)DMA for %s\n", drive->name, id->model);
-		return(blacklist);
-	}
-#else /* !CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
-	const char **list;
+	if (id && (id->capability & 1) && hwif->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			return hwif->ide_dma_off(drive);
+
+		/*
+		 * Enable DMA on any drive that has
+		 * UltraDMA (mode 0/1/2/3/4/5/6) enabled
+		 */
+		if ((id->field_valid & 4) && ((id->dma_ultra >> 8) & 0x7f))
+			return hwif->ide_dma_on(drive);
+		/*
+		 * Enable DMA on any drive that has mode2 DMA
+		 * (multi or single) enabled
+		 */
+		if (id->field_valid & 2)	/* regular DMA */
+			if ((id->dma_mword & 0x404) == 0x404 ||
+			    (id->dma_1word & 0x404) == 0x404)
+				return hwif->ide_dma_on(drive);
 
-	if (good_bad) {
 		/* Consult the list of known "good" drives */
-		list = good_dma_drives;
-		while (*list) {
-			if (!strcmp(*list++,id->model))
-				return 1;
-		}
-	} else {
-		/* Consult the list of known "bad" drives */
-		list = bad_dma_drives;
-		while (*list) {
-			if (!strcmp(*list++,id->model)) {
-				printk("%s: Disabling (U)DMA for %s\n",
-					drive->name, id->model);
-				return 1;
-			}
-		}
+		if (hwif->ide_dma_good_drive(drive))
+			return hwif->ide_dma_on(drive);
 	}
-#endif /* CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
-	return 0;
+//	if (hwif->tuneproc != NULL) hwif->tuneproc(drive, 255);
+	return hwif->ide_dma_off_quietly(drive);
 }
 
-int report_drive_dmaing (ide_drive_t *drive)
+/**
+ *	dma_timer_expiry	-	handle a DMA timeout
+ *	@drive: Drive that timed out
+ *
+ *	An IDE DMA transfer timed out. In the event of an error we ask
+ *	the driver to resolve the problem, if a DMA transfer is still
+ *	in progress we continue to wait (arguably we need to add a 
+ *	secondary 'I dont care what the drive thinks' timeout here)
+ *	Finally if we have an interrupt but for some reason got the
+ *	timeout first we complete the I/O. This can occur if an 
+ *	interrupt is lost or due to bugs.
+ */
+ 
+static int dma_timer_expiry (ide_drive_t *drive)
 {
-	struct hd_driveid *id = drive->id;
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 dma_stat		= hwif->INB(hwif->dma_status);
 
-	if ((id->field_valid & 4) && (eighty_ninty_three(drive)) &&
-	    (id->dma_ultra & (id->dma_ultra >> 14) & 3)) {
-		if ((id->dma_ultra >> 15) & 1) {
-			printk(", UDMA(mode 7)");	/* UDMA BIOS-enabled! */
-		} else {
-			printk(", UDMA(133)");	/* UDMA BIOS-enabled! */
-		}
-	} else if ((id->field_valid & 4) && (eighty_ninty_three(drive)) &&
-	  	  (id->dma_ultra & (id->dma_ultra >> 11) & 7)) {
-		if ((id->dma_ultra >> 13) & 1) {
-			printk(", UDMA(100)");	/* UDMA BIOS-enabled! */
-		} else if ((id->dma_ultra >> 12) & 1) {
-			printk(", UDMA(66)");	/* UDMA BIOS-enabled! */
-		} else {
-			printk(", UDMA(44)");	/* UDMA BIOS-enabled! */
-		}
-	} else if ((id->field_valid & 4) &&
-		   (id->dma_ultra & (id->dma_ultra >> 8) & 7)) {
-		if ((id->dma_ultra >> 10) & 1) {
-			printk(", UDMA(33)");	/* UDMA BIOS-enabled! */
-		} else if ((id->dma_ultra >> 9) & 1) {
-			printk(", UDMA(25)");	/* UDMA BIOS-enabled! */
-		} else {
-			printk(", UDMA(16)");	/* UDMA BIOS-enabled! */
-		}
-	} else if (id->field_valid & 4) {
-		printk(", (U)DMA");	/* Can be BIOS-enabled! */
-	} else {
-		printk(", DMA");
+	printk(KERN_WARNING "%s: dma_timer_expiry: dma status == 0x%02x\n",
+		drive->name, dma_stat);
+
+	if ((dma_stat & 0x18) == 0x18)	/* BUSY Stupid Early Timer !! */
+		return WAIT_CMD;
+
+	HWGROUP(drive)->expiry = NULL;	/* one free ride for now */
+
+	/* 1 dmaing, 2 error, 4 intr */
+	
+	if (dma_stat & 2) {	/* ERROR */
+		(void) hwif->ide_dma_end(drive);
+		return DRIVER(drive)->error(drive,
+			"dma_timer_expiry", hwif->INB(IDE_STATUS_REG));
 	}
-	return 1;
+	if (dma_stat & 1)	/* DMAing */
+		return WAIT_CMD;
+
+	if (dma_stat & 4)	/* Got an Interrupt */
+		HWGROUP(drive)->handler(drive);
+
+	return 0;
 }
 
-static int config_drive_for_dma (ide_drive_t *drive)
+/**
+ *	__ide_dma_host_off	-	Generic DMA kill
+ *	@drive: drive to control
+ *
+ *	Perform the generic IDE controller DMA off operation. This
+ *	works for most IDE bus mastering controllers
+ */
+
+int __ide_dma_host_off (ide_drive_t *drive)
 {
-	int config_allows_dma = 1;
-	struct hd_driveid *id = drive->id;
-	ide_hwif_t *hwif = HWIF(drive);
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 unit			= (drive->select.b.unit & 0x01);
+	u8 dma_stat		= hwif->INB(hwif->dma_status);
 
-#ifdef CONFIG_IDEDMA_ONLYDISK
-	if (drive->media != ide_disk)
-		config_allows_dma = 0;
-#endif
+	hwif->OUTB((dma_stat & ~(1<<(5+unit))), hwif->dma_status);
+	return 0;
+}
 
-	if (id && (id->capability & 1) && hwif->autodma && config_allows_dma) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive))
-			return hwif->dmaproc(ide_dma_off, drive);
+EXPORT_SYMBOL(__ide_dma_host_off);
 
-		/* Enable DMA on any drive that has UltraDMA (mode 6/7/?) enabled */
-		if ((id->field_valid & 4) && (eighty_ninty_three(drive)))
-			if ((id->dma_ultra & (id->dma_ultra >> 14) & 2))
-				return hwif->dmaproc(ide_dma_on, drive);
-		/* Enable DMA on any drive that has UltraDMA (mode 3/4/5) enabled */
-		if ((id->field_valid & 4) && (eighty_ninty_three(drive)))
-			if ((id->dma_ultra & (id->dma_ultra >> 11) & 7))
-				return hwif->dmaproc(ide_dma_on, drive);
-		/* Enable DMA on any drive that has UltraDMA (mode 0/1/2) enabled */
-		if (id->field_valid & 4)	/* UltraDMA */
-			if ((id->dma_ultra & (id->dma_ultra >> 8) & 7))
-				return hwif->dmaproc(ide_dma_on, drive);
-		/* Enable DMA on any drive that has mode2 DMA (multi or single) enabled */
-		if (id->field_valid & 2)	/* regular DMA */
-			if ((id->dma_mword & 0x404) == 0x404 || (id->dma_1word & 0x404) == 0x404)
-				return hwif->dmaproc(ide_dma_on, drive);
-		/* Consult the list of known "good" drives */
-		if (ide_dmaproc(ide_dma_good_drive, drive))
-			return hwif->dmaproc(ide_dma_on, drive);
+/**
+ *	__ide_dma_host_off_quietly	-	Generic DMA kill
+ *	@drive: drive to control
+ *
+ *	Turn off the current DMA on this IDE controller. 
+ */
+
+int __ide_dma_off_quietly (ide_drive_t *drive)
+{
+	drive->using_dma = 0;
+	ide_toggle_bounce(drive, 0);
+	return HWIF(drive)->ide_dma_host_off(drive);
+}
+
+EXPORT_SYMBOL(__ide_dma_off_quietly);
+
+/**
+ *	__ide_dma_host_off	-	Generic DMA kill
+ *	@drive: drive to control
+ *
+ *	Turn off the current DMA on this IDE controller. Inform the
+ *	user that DMA has been disabled. 
+ */
+
+int __ide_dma_off (ide_drive_t *drive)
+{
+	printk(KERN_INFO "%s: DMA disabled\n", drive->name);
+	return HWIF(drive)->ide_dma_off_quietly(drive);
+}
+
+EXPORT_SYMBOL(__ide_dma_off);
+
+/**
+ *	__ide_dma_host_on	-	Enable DMA on a host
+ *	@drive: drive to enable for DMA
+ *
+ *	Enable DMA on an IDE controller following generic bus mastering
+ *	IDE controller behaviour
+ */
+ 
+int __ide_dma_host_on (ide_drive_t *drive)
+{
+	if (drive->using_dma) {
+		ide_hwif_t *hwif	= HWIF(drive);
+		u8 unit			= (drive->select.b.unit & 0x01);
+		u8 dma_stat		= hwif->INB(hwif->dma_status);
+
+		hwif->OUTB((dma_stat|(1<<(5+unit))), hwif->dma_status);
+		return 0;
 	}
-	return hwif->dmaproc(ide_dma_off_quietly, drive);
+	return 1;
 }
 
-#ifndef CONFIG_BLK_DEV_IDEDMA_TIMEOUT
-/*
- * 1 dmaing, 2 error, 4 intr
+EXPORT_SYMBOL(__ide_dma_host_on);
+
+/**
+ *	__ide_dma_on		-	Enable DMA on a device
+ *	@drive: drive to enable DMA on
+ *
+ *	Enable IDE DMA for a device on this IDE controller.
  */
-static int dma_timer_expiry (ide_drive_t *drive)
+ 
+int __ide_dma_on (ide_drive_t *drive)
 {
-	byte dma_stat = inb(HWIF(drive)->dma_base+2);
+	drive->using_dma = 1;
+	ide_toggle_bounce(drive, 1);
+	return HWIF(drive)->ide_dma_host_on(drive);
+}
+
+EXPORT_SYMBOL(__ide_dma_on);
+
+/**
+ *	__ide_dma_check		-	check DMA setup
+ *	@drive: drive to check
+ *
+ *	Don't use - due for extermination
+ */
+ 
+int __ide_dma_check (ide_drive_t *drive)
+{
+	return config_drive_for_dma(drive);
+}
 
-#ifdef DEBUG
-	printk("%s: dma_timer_expiry: dma status == 0x%02x\n", drive->name, dma_stat);
-#endif /* DEBUG */
+EXPORT_SYMBOL(__ide_dma_check);
 
+int __ide_dma_read (ide_drive_t *drive /*, struct request *rq */)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct request *rq	= HWGROUP(drive)->rq;
+//	ide_task_t *args	= rq->special;
+	unsigned int reading	= 1 << 3;
+	unsigned int count	= 0;
+	u8 dma_stat = 0, lba48	= (drive->addressing == 1) ? 1 : 0;
+	task_ioreg_t command	= WIN_NOP;
+
+	if (!(count = ide_build_dmatable(drive, rq, PCI_DMA_FROMDEVICE)))
+		/* try PIO instead of DMA */
+		return 1;
+	/* PRD table */
+	hwif->OUTL(hwif->dmatable_dma, hwif->dma_prdtable);
+	/* specify r/w */
+	hwif->OUTB(reading, hwif->dma_command);
+	/* read dma_status for INTR & ERROR flags */
+	dma_stat = hwif->INB(hwif->dma_status);
+	/* clear INTR & ERROR flags */
+	hwif->OUTB(dma_stat|6, hwif->dma_status);
+	drive->waiting_for_dma = 1;
+	if (drive->media != ide_disk)
+		return 0;
+	/* paranoia check */
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	ide_set_handler(drive, &ide_dma_intr, 2*WAIT_CMD, dma_timer_expiry);
+
+	/*
+	 * FIX ME to use only ACB ide_task_t args Struct
+	 */
 #if 0
-	HWGROUP(drive)->expiry = NULL;	/* one free ride for now */
+	{
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#else
+	command = (lba48) ? WIN_READDMA_EXT : WIN_READDMA;
+	if (rq->cmd == IDE_DRIVE_TASKFILE) {
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
 #endif
+	/* issue cmd to drive */
+	hwif->OUTB(command, IDE_COMMAND_REG);
 
-	if (dma_stat & 2) {	/* ERROR */
-		byte stat = GET_STAT();
-		return ide_error(drive, "dma_timer_expiry", stat);
+	return HWIF(drive)->ide_dma_count(drive);
+}
+
+EXPORT_SYMBOL(__ide_dma_read);
+
+int __ide_dma_write (ide_drive_t *drive /*, struct request *rq */)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct request *rq	= HWGROUP(drive)->rq;
+//	ide_task_t *args	= rq->special;
+	unsigned int reading	= 0;
+	unsigned int count	= 0;
+	u8 dma_stat = 0, lba48	= (drive->addressing == 1) ? 1 : 0;
+	task_ioreg_t command	= WIN_NOP;
+
+	if (!(count = ide_build_dmatable(drive, rq, PCI_DMA_TODEVICE)))
+		/* try PIO instead of DMA */
+		return 1;
+	/* PRD table */
+	hwif->OUTL(hwif->dmatable_dma, hwif->dma_prdtable);
+	/* specify r/w */
+	hwif->OUTB(reading, hwif->dma_command);
+	/* read dma_status for INTR & ERROR flags */
+	dma_stat = hwif->INB(hwif->dma_status);
+	/* clear INTR & ERROR flags */
+	hwif->OUTB(dma_stat|6, hwif->dma_status);
+	drive->waiting_for_dma = 1;
+	if (drive->media != ide_disk)
+		return 0;
+	/* paranoia check */
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	ide_set_handler(drive, &ide_dma_intr, 2*WAIT_CMD, dma_timer_expiry);
+	/*
+	 * FIX ME to use only ACB ide_task_t args Struct
+	 */
+#if 0
+	{
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
 	}
-	if (dma_stat & 1)	/* DMAing */
-		return WAIT_CMD;
+#else
+	command = (lba48) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
+	if (rq->cmd == IDE_DRIVE_TASKFILE) {
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#endif
+	/* issue cmd to drive */
+	hwif->OUTB(command, IDE_COMMAND_REG);
+	return HWIF(drive)->ide_dma_count(drive);
+}
+
+EXPORT_SYMBOL(__ide_dma_write);
+
+int __ide_dma_begin (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 dma_cmd		= hwif->INB(hwif->dma_command);
+
+	/* Note that this is done *after* the cmd has
+	 * been issued to the drive, as per the BM-IDE spec.
+	 * The Promise Ultra33 doesn't work correctly when
+	 * we do this part before issuing the drive cmd.
+	 */
+	/* start DMA */
+	hwif->OUTB(dma_cmd|1, hwif->dma_command);
 	return 0;
 }
-#else /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
-static ide_startstop_t ide_dma_timeout_revovery (ide_drive_t *drive)
+
+EXPORT_SYMBOL(__ide_dma_begin);
+
+/* returns 1 on error, 0 otherwise */
+int __ide_dma_end (ide_drive_t *drive)
 {
-	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
 	ide_hwif_t *hwif	= HWIF(drive);
-	int enable_dma		= drive->using_dma;
-	unsigned long flags;
-	ide_startstop_t startstop;
-
-	spin_lock_irqsave(&io_request_lock, flags);
-	hwgroup->handler = NULL;
-	del_timer(&hwgroup->timer);
-	spin_unlock_irqrestore(&io_request_lock, flags);
+	u8 dma_stat = 0, dma_cmd = 0;
 
 	drive->waiting_for_dma = 0;
+	/* get dma_command mode */
+	dma_cmd = hwif->INB(hwif->dma_command);
+	/* stop DMA */
+	hwif->OUTB(dma_cmd&~1, hwif->dma_command);
+	/* get DMA status */
+	dma_stat = hwif->INB(hwif->dma_status);
+	/* clear the INTR & ERROR bits */
+	hwif->OUTB(dma_stat|6, hwif->dma_status);
+	/* purge DMA mappings */
+	ide_destroy_dmatable(drive);
+	/* verify good DMA status */
+	return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0;
+}
 
-	startstop = ide_do_reset(drive);
+EXPORT_SYMBOL(__ide_dma_end);
 
-	if ((enable_dma) && !(drive->using_dma))
-		(void) hwif->dmaproc(ide_dma_on, drive);
+/* returns 1 if dma irq issued, 0 otherwise */
+int __ide_dma_test_irq (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 dma_stat		= hwif->INB(hwif->dma_status);
 
-	return startstop;
+#if 0  /* do not set unless you know what you are doing */
+	if (dma_stat & 4) {
+		u8 stat = hwif->INB(IDE_STATUS_REG);
+		hwif->OUTB(hwif->dma_status, dma_stat & 0xE4);
+	}
+#endif
+	/* return 1 if INTR asserted */
+	if ((dma_stat & 4) == 4)
+		return 1;
+	if (!drive->waiting_for_dma)
+		printk(KERN_WARNING "%s: (%s) called while not waiting\n",
+			drive->name, __FUNCTION__);
+	drive->waiting_for_dma++;
+	return 0;
 }
-#endif /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
 
-static inline void ide_toggle_bounce(ide_drive_t *drive, int on)
-{
-	dma64_addr_t addr = BLK_BOUNCE_HIGH;
+EXPORT_SYMBOL(__ide_dma_test_irq);
 
-	if (HWIF(drive)->no_highio || HWIF(drive)->pci_dev == NULL)
-		return;
+int __ide_dma_bad_drive (ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
 
-	if (on && drive->media == ide_disk) {
-		if (!PCI_DMA_BUS_IS_PHYS)
-			addr = BLK_BOUNCE_ANY;
-		else
-			addr = HWIF(drive)->pci_dev->dma_mask;
+#ifdef CONFIG_IDEDMA_NEW_DRIVE_LISTINGS
+	int blacklist = in_drive_list(id, drive_blacklist);
+	if (blacklist) {
+		printk("%s: Disabling (U)DMA for %s\n", drive->name, id->model);
+		return(blacklist);
+	}
+#else /* !CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
+	const char **list;
+	/* Consult the list of known "bad" drives */
+	list = bad_dma_drives;
+	while (*list) {
+		if (!strcmp(*list++,id->model)) {
+			printk("%s: Disabling (U)DMA for %s\n",
+				drive->name, id->model);
+			return 1;
+		}
 	}
+#endif /* CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
+	return 0;
+}
+
+EXPORT_SYMBOL(__ide_dma_bad_drive);
+
+int __ide_dma_good_drive (ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
 
-	blk_queue_bounce_limit(&drive->queue, addr);
+#ifdef CONFIG_IDEDMA_NEW_DRIVE_LISTINGS
+	return in_drive_list(id, drive_whitelist);
+#else /* !CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
+	const char **list;
+	/* Consult the list of known "good" drives */
+	list = good_dma_drives;
+	while (*list) {
+		if (!strcmp(*list++,id->model))
+			return 1;
+	}
+#endif /* CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
+	return 0;
 }
 
+EXPORT_SYMBOL(__ide_dma_good_drive);
+
 /*
- * ide_dmaproc() initiates/aborts DMA read/write operations on a drive.
- *
- * The caller is assumed to have selected the drive and programmed the drive's
- * sector address using CHS or LBA.  All that remains is to prepare for DMA
- * and then issue the actual read/write DMA/PIO command to the drive.
- *
- * For ATAPI devices, we just prepare for DMA and return. The caller should
- * then issue the packet command to the drive and call us again with
- * ide_dma_begin afterwards.
- *
- * Returns 0 if all went well.
- * Returns 1 if DMA read/write could not be started, in which case
- * the caller should revert to PIO for the current request.
- * May also be invoked from trm290.c
- */
-int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-//	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
-	ide_hwif_t *hwif		= HWIF(drive);
-	unsigned long dma_base		= hwif->dma_base;
-	byte unit			= (drive->select.b.unit & 0x01);
-	unsigned int count, reading = 0, set_high = 1;
-	byte dma_stat;
-
-	switch (func) {
-		case ide_dma_off:
-			printk("%s: DMA disabled\n", drive->name);
-		case ide_dma_off_quietly:
-			set_high = 0;
-			outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
-		case ide_dma_on:
-			drive->using_dma = (func == ide_dma_on);
-			if (drive->using_dma)
-				outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
-			ide_toggle_bounce(drive, set_high);
-			return 0;
-		case ide_dma_check:
-			return config_drive_for_dma (drive);
-		case ide_dma_read:
-			reading = 1 << 3;
-		case ide_dma_write:
-			SELECT_READ_WRITE(hwif,drive,func);
-			if (!(count = ide_build_dmatable(drive, func)))
-				return 1;	/* try PIO instead of DMA */
-			outl(hwif->dmatable_dma, dma_base + 4); /* PRD table */
-			outb(reading, dma_base);			/* specify r/w */
-			outb(inb(dma_base+2)|6, dma_base+2);		/* clear INTR & ERROR flags */
-			drive->waiting_for_dma = 1;
-			if (drive->media != ide_disk)
-				return 0;
-#ifdef CONFIG_BLK_DEV_IDEDMA_TIMEOUT
-			ide_set_handler(drive, &ide_dma_intr, 2*WAIT_CMD, NULL);	/* issue cmd to drive */
-#else /* !CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
-			ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, dma_timer_expiry);	/* issue cmd to drive */
-#endif /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
-			if ((HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE) &&
-			    (drive->addressing == 1)) {
-				ide_task_t *args = HWGROUP(drive)->rq->special;
-				OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
-			} else if (drive->addressing) {
-				OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
+ * Used for HOST FIFO counters for VDMA
+ * PIO over DMA, effective ATA-Bridge operator.
+ */
+int __ide_dma_count (ide_drive_t *drive)
+{
+	return HWIF(drive)->ide_dma_begin(drive);
+}
+
+EXPORT_SYMBOL(__ide_dma_count);
+
+int __ide_dma_verbose (ide_drive_t *drive)
+{
+	struct hd_driveid *id	= drive->id;
+	ide_hwif_t *hwif	= HWIF(drive);
+
+	if (id->field_valid & 4) {
+		if ((id->dma_ultra >> 8) && (id->dma_mword >> 8)) {
+			printk(", BUG DMA OFF");
+			return hwif->ide_dma_off_quietly(drive);
+		}
+		if (id->dma_ultra & ((id->dma_ultra >> 8) & hwif->ultra_mask)) {
+			if (((id->dma_ultra >> 11) & 0x1F) &&
+			    eighty_ninty_three(drive)) {
+				if ((id->dma_ultra >> 15) & 1) {
+					printk(", UDMA(mode 7)");
+				} else if ((id->dma_ultra >> 14) & 1) {
+					printk(", UDMA(133)");
+				} else if ((id->dma_ultra >> 13) & 1) {
+					printk(", UDMA(100)");
+				} else if ((id->dma_ultra >> 12) & 1) {
+					printk(", UDMA(66)");
+				} else if ((id->dma_ultra >> 11) & 1) {
+					printk(", UDMA(44)");
+				} else
+					goto mode_two;
 			} else {
-				OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
-			}
-			return HWIF(drive)->dmaproc(ide_dma_begin, drive);
-		case ide_dma_begin:
-			/* Note that this is done *after* the cmd has
-			 * been issued to the drive, as per the BM-IDE spec.
-			 * The Promise Ultra33 doesn't work correctly when
-			 * we do this part before issuing the drive cmd.
-			 */
-			outb(inb(dma_base)|1, dma_base);		/* start DMA */
-			return 0;
-		case ide_dma_end: /* returns 1 on error, 0 otherwise */
-			drive->waiting_for_dma = 0;
-			outb(inb(dma_base)&~1, dma_base);	/* stop DMA */
-			dma_stat = inb(dma_base+2);		/* get DMA status */
-			outb(dma_stat|6, dma_base+2);	/* clear the INTR & ERROR bits */
-			ide_destroy_dmatable(drive);	/* purge DMA mappings */
-			return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0;	/* verify good DMA status */
-		case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */
-			dma_stat = inb(dma_base+2);
-#if 0  /* do not set unless you know what you are doing */
-			if (dma_stat & 4) {
-				byte stat = GET_STAT();
-				outb(dma_base+2, dma_stat & 0xE4);
+		mode_two:
+				if ((id->dma_ultra >> 10) & 1) {
+					printk(", UDMA(33)");
+				} else if ((id->dma_ultra >> 9) & 1) {
+					printk(", UDMA(25)");
+				} else if ((id->dma_ultra >> 8) & 1) {
+					printk(", UDMA(16)");
+				}
 			}
-#endif
-			return (dma_stat & 4) == 4;	/* return 1 if INTR asserted */
-		case ide_dma_bad_drive:
-		case ide_dma_good_drive:
-			return check_drive_lists(drive, (func == ide_dma_good_drive));
-		case ide_dma_verbose:
-			return report_drive_dmaing(drive);
-		case ide_dma_timeout:
-			// FIXME: Many IDE chipsets do not permit command file register access
-			// FIXME: while the bus-master function is still active.
-			// FIXME: To prevent deadlock with those chipsets, we must be extremely
-			// FIXME: careful here (and in ide_intr() as well) to NOT access any
-			// FIXME: registers from the 0x1Fx/0x17x sets before terminating the
-			// FIXME: bus-master operation via the bus-master control reg.
-			// FIXME: Otherwise, chipset deadlock will occur, and some systems will
-			// FIXME: lock up completely!!
-#ifdef CONFIG_BLK_DEV_IDEDMA_TIMEOUT
-			/*
-			 * Have to issue an abort and requeue the request
-			 * DMA engine got turned off by a goofy ASIC, and
-			 * we have to clean up the mess, and here is as good
-			 * as any.  Do it globally for all chipsets.
-			 */
-			outb(0x00, dma_base);		/* stop DMA */
-			dma_stat = inb(dma_base+2);	/* get DMA status */
-			outb(dma_stat|6, dma_base+2);	/* clear the INTR & ERROR bits */
-			printk("%s: %s: Lets do it again!" \
-				"stat = 0x%02x, dma_stat = 0x%02x\n",
-				drive->name, ide_dmafunc_verbose(func),
-				GET_STAT(), dma_stat);
-
-			if (dma_stat & 0xF0)
-				return ide_dma_timeout_revovery(drive);
-
-			printk("%s: %s: (restart_request) Lets do it again!" \
-				"stat = 0x%02x, dma_stat = 0x%02x\n",
-				drive->name, ide_dmafunc_verbose(func),
-				GET_STAT(), dma_stat);
-
-			return restart_request(drive);  // BUG: return types do not match!!
-//#else
-//			return HWGROUP(drive)->handler(drive);
-#endif /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
-		case ide_dma_retune:
-		case ide_dma_lostirq:
-			printk("ide_dmaproc: chipset supported %s func only: %d\n", ide_dmafunc_verbose(func),  func);
-			return 1;
-		default:
-			printk("ide_dmaproc: unsupported %s func: %d\n", ide_dmafunc_verbose(func), func);
-			return 1;
+		} else {
+			printk(", (U)DMA");	/* Can be BIOS-enabled! */
+		}
+	} else if (id->field_valid & 2) {
+		if ((id->dma_mword >> 8) && (id->dma_1word >> 8)) {
+			printk(", BUG DMA OFF");
+			return hwif->ide_dma_off_quietly(drive);
+		}
+		printk(", DMA");
+	} else if (id->field_valid & 1) {
+		printk(", BUG");
 	}
+	return 1;
+}
+
+EXPORT_SYMBOL(__ide_dma_verbose);
+
+/**
+ *	__ide_dma_retune	-	default retune handler
+ *	@drive: drive to retune
+ *
+ *	Default behaviour when we decide to return the IDE DMA setup.
+ *	The default behaviour is "we don't"
+ */
+ 
+int __ide_dma_retune (ide_drive_t *drive)
+{
+	printk(KERN_WARNING "%s: chipset supported call only\n", __FUNCTION__);
+	return 1;
 }
 
+EXPORT_SYMBOL(__ide_dma_retune);
+
+int __ide_dma_lostirq (ide_drive_t *drive)
+{
+	printk("%s: DMA interrupt recovery\n", drive->name);
+	return 1;
+}
+
+EXPORT_SYMBOL(__ide_dma_lostirq);
+
+int __ide_dma_timeout (ide_drive_t *drive)
+{
+	printk(KERN_ERR "%s: timeout waiting for DMA\n", drive->name);
+	if (HWIF(drive)->ide_dma_test_irq(drive))
+		return 0;
+	return HWIF(drive)->ide_dma_end(drive);
+}
+
+EXPORT_SYMBOL(__ide_dma_timeout);
+
 /*
  * Needed for allowing full modular support of ide-driver
  */
-int ide_release_dma (ide_hwif_t *hwif)
+int ide_release_dma_engine (ide_hwif_t *hwif)
 {
 	if (hwif->dmatable_cpu) {
 		pci_free_consistent(hwif->pci_dev,
@@ -777,128 +991,206 @@
 		kfree(hwif->sg_table);
 		hwif->sg_table = NULL;
 	}
+	return 1;
+}
+
+int ide_release_mmio_dma (ide_hwif_t *hwif)
+{
+	if ((hwif->dma_extra) && (hwif->channel == 0))
+		release_mem_region((hwif->dma_base + 16), hwif->dma_extra);
+	release_mem_region(hwif->dma_base, 8);
+	if (hwif->dma_base2)
+		release_mem_region(hwif->dma_base, 8);
+	return 1;
+}
+
+int ide_release_iomio_dma (ide_hwif_t *hwif)
+{
 	if ((hwif->dma_extra) && (hwif->channel == 0))
 		release_region((hwif->dma_base + 16), hwif->dma_extra);
 	release_region(hwif->dma_base, 8);
+	if (hwif->dma_base2)
+		release_region(hwif->dma_base, 8);
 	return 1;
 }
 
 /*
- *	This can be called for a dynamically installed interface. Don't __init it
+ * Needed for allowing full modular support of ide-driver
  */
- 
-void ide_setup_dma (ide_hwif_t *hwif, unsigned long dma_base, unsigned int num_ports)
+int ide_release_dma (ide_hwif_t *hwif)
 {
-	printk("    %s: BM-DMA at 0x%04lx-0x%04lx", hwif->name, dma_base, dma_base + num_ports - 1);
-	if (check_region(dma_base, num_ports)) {
-		printk(" -- ERROR, PORT ADDRESSES ALREADY IN USE\n");
-		return;
-	}
-	request_region(dma_base, num_ports, hwif->name);
-	hwif->dma_base = dma_base;
-	hwif->dmatable_cpu = pci_alloc_consistent(hwif->pci_dev,
-						    PRD_ENTRIES * PRD_BYTES,
-						    &hwif->dmatable_dma);
-	if (hwif->dmatable_cpu == NULL)
-		goto dma_alloc_failure;
+	if (hwif->chipset == ide_etrax100)
+		return 1;
 
+	ide_release_dma_engine(hwif);
+	if (hwif->mmio)
+		return ide_release_mmio_dma(hwif);
+	return ide_release_iomio_dma(hwif);
+}
+
+int ide_allocate_dma_engine (ide_hwif_t *hwif)
+{
+	hwif->dmatable_cpu = pci_alloc_consistent(hwif->pci_dev,
+						  PRD_ENTRIES * PRD_BYTES,
+						  &hwif->dmatable_dma);
 	hwif->sg_table = kmalloc(sizeof(struct scatterlist) * PRD_ENTRIES,
-				 GFP_KERNEL);
-	if (hwif->sg_table == NULL) {
-		pci_free_consistent(hwif->pci_dev, PRD_ENTRIES * PRD_BYTES,
-				    hwif->dmatable_cpu, hwif->dmatable_dma);
-		goto dma_alloc_failure;
-	}
+				GFP_KERNEL);
+
+	if ((hwif->dmatable_cpu) && (hwif->sg_table))
+		return 0;
 
-	hwif->dmaproc = &ide_dmaproc;
+	printk(KERN_ERR "%s: -- Error, unable to allocate%s%s table(s).\n",
+		(hwif->dmatable_cpu == NULL) ? " CPU" : "",
+		(hwif->sg_table == NULL) ?  " SG DMA" : " DMA",
+		hwif->cds->name);
 
-	if (hwif->chipset != ide_trm290) {
-		byte dma_stat = inb(dma_base+2);
-		printk(", BIOS settings: %s:%s, %s:%s",
-		       hwif->drives[0].name, (dma_stat & 0x20) ? "DMA" : "pio",
-		       hwif->drives[1].name, (dma_stat & 0x40) ? "DMA" : "pio");
+	ide_release_dma_engine(hwif);
+	return 1;
+}
+
+int ide_mmio_dma (ide_hwif_t *hwif, unsigned long base, unsigned int ports)
+{
+	printk(KERN_INFO "    %s: MMIO-DMA at 0x%08lx-0x%08lx",
+		hwif->name, base, base + ports - 1);
+	if (check_mem_region(base, ports)) {
+		printk(" -- Error, MMIO ports already in use.\n");
+		return 1;
 	}
-	printk("\n");
-	return;
+	request_mem_region(base, ports, hwif->name);
+	hwif->dma_base = base;
+	if ((hwif->cds->extra) && (hwif->channel == 0)) {
+		request_region(base+16, hwif->cds->extra, hwif->cds->name);
+		hwif->dma_extra = hwif->cds->extra;
+	}
+	
+	/* There is an issue to watch here. The master might not be 
+	   registered because the BIOS disabled it. Eventually this should
+	   be fixed by always registering the mate */
+	   
+	if(hwif->mate == NULL)
+		hwif->dma_master = base;
+	else
+		hwif->dma_master = (hwif->channel) ? hwif->mate->dma_base : base;
+	if (hwif->dma_base2) {
+		if (!check_mem_region(hwif->dma_base2, ports))
+			request_mem_region(hwif->dma_base2, ports, hwif->name);
+	}
+	return 0;
+}
 
-dma_alloc_failure:
-	printk(" -- ERROR, UNABLE TO ALLOCATE DMA TABLES\n");
+int ide_iomio_dma (ide_hwif_t *hwif, unsigned long base, unsigned int ports)
+{
+	printk(KERN_INFO "    %s: BM-DMA at 0x%04lx-0x%04lx",
+		hwif->name, base, base + ports - 1);
+	if (!request_region(base, ports, hwif->name)) {
+		printk(" -- Error, ports in use.\n");
+		return 1;
+	}
+	hwif->dma_base = base;
+	if ((hwif->cds->extra) && (hwif->channel == 0)) {
+		request_region(base+16, hwif->cds->extra, hwif->cds->name);
+		hwif->dma_extra = hwif->cds->extra;
+	}
+	/* There is an issue to watch here. The master might not be 
+	   registered because the BIOS disabled it. Eventually this should
+	   be fixed by always registering the mate */
+	   
+	if(hwif->mate == NULL)
+		hwif->dma_master = base;
+	else
+		hwif->dma_master = (hwif->channel) ? hwif->mate->dma_base : base;
+	if (hwif->dma_base2) {
+		if (!request_region(hwif->dma_base2, ports, hwif->name))
+		{
+			printk(" -- Error, secondary ports in use.\n");
+			release_region(base, ports);
+			return 1;
+		}
+	}
+	return 0;
 }
 
 /*
- * Fetch the DMA Bus-Master-I/O-Base-Address (BMIBA) from PCI space:
+ * 
  */
-unsigned long __init ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const char *name)
+int ide_dma_iobase (ide_hwif_t *hwif, unsigned long base, unsigned int ports)
 {
-	unsigned long	dma_base = 0;
-	struct pci_dev	*dev = hwif->pci_dev;
+	if (hwif->mmio)
+		return ide_mmio_dma(hwif, base, ports);
+	return ide_iomio_dma(hwif, base, ports);
+}
 
-#ifdef CONFIG_BLK_DEV_IDEDMA_FORCED
-	int second_chance = 0;
-
-second_chance_to_dma:
-#endif /* CONFIG_BLK_DEV_IDEDMA_FORCED */
-
-	if (hwif->mate && hwif->mate->dma_base) {
-		dma_base = hwif->mate->dma_base - (hwif->channel ? 0 : 8);
-	} else {
-		dma_base = pci_resource_start(dev, 4);
-		if (!dma_base) {
-			printk("%s: dma_base is invalid (0x%04lx)\n", name, dma_base);
-			dma_base = 0;
-		}
-	}
+/*
+ * This can be called for a dynamically installed interface. Don't __init it
+ */
+void ide_setup_dma (ide_hwif_t *hwif, unsigned long dma_base, unsigned int num_ports)
+{
+	if (ide_dma_iobase(hwif, dma_base, num_ports))
+		return;
 
-#ifdef CONFIG_BLK_DEV_IDEDMA_FORCED
-	if ((!dma_base) && (!second_chance)) {
-		unsigned long set_bmiba = 0;
-		second_chance++;
-		switch(dev->vendor) {
-			case PCI_VENDOR_ID_AL:
-				set_bmiba = DEFAULT_BMALIBA; break;
-			case PCI_VENDOR_ID_VIA:
-				set_bmiba = DEFAULT_BMCRBA; break;
-			case PCI_VENDOR_ID_INTEL:
-				set_bmiba = DEFAULT_BMIBA; break;
-			default:
-				return dma_base;
-		}
-		pci_write_config_dword(dev, 0x20, set_bmiba|1);
-		goto second_chance_to_dma;
+	if (ide_allocate_dma_engine(hwif)) {
+		ide_release_dma(hwif);
+		return;
 	}
-#endif /* CONFIG_BLK_DEV_IDEDMA_FORCED */
 
-	if (dma_base) {
-		if (extra) /* PDC20246, PDC20262, HPT343, & HPT366 */
-			request_region(dma_base+16, extra, name);
-		dma_base += hwif->channel ? 8 : 0;
-		hwif->dma_extra = extra;
-
-		switch(dev->device) {
-			case PCI_DEVICE_ID_AL_M5219:
-			case PCI_DEVICE_ID_AMD_VIPER_7409:
-			case PCI_DEVICE_ID_CMD_643:
-				outb(inb(dma_base+2) & 0x60, dma_base+2);
-				if (inb(dma_base+2) & 0x80) {
-					printk("%s: simplex device: DMA forced\n", name);
-				}
-				break;
-			default:
-				/*
-				 * If the device claims "simplex" DMA,
-				 * this means only one of the two interfaces
-				 * can be trusted with DMA at any point in time.
-				 * So we should enable DMA only on one of the
-				 * two interfaces.
-				 */
-				if ((inb(dma_base+2) & 0x80)) {	/* simplex device? */
-					if ((!hwif->drives[0].present && !hwif->drives[1].present) ||
-					    (hwif->mate && hwif->mate->dma_base)) {
-						printk("%s: simplex device:  DMA disabled\n", name);
-						dma_base = 0;
-					}
-				}
-		}
+	if (!(hwif->dma_command))
+		hwif->dma_command	= hwif->dma_base;
+	if (!(hwif->dma_vendor1))
+		hwif->dma_vendor1	= (hwif->dma_base + 1);
+	if (!(hwif->dma_status))
+		hwif->dma_status	= (hwif->dma_base + 2);
+	if (!(hwif->dma_vendor3))
+		hwif->dma_vendor3	= (hwif->dma_base + 3);
+	if (!(hwif->dma_prdtable))
+		hwif->dma_prdtable	= (hwif->dma_base + 4);
+
+	if (!hwif->ide_dma_off)
+		hwif->ide_dma_off = &__ide_dma_off;
+	if (!hwif->ide_dma_off_quietly)
+		hwif->ide_dma_off_quietly = &__ide_dma_off_quietly;
+	if (!hwif->ide_dma_host_off)
+		hwif->ide_dma_host_off = &__ide_dma_host_off;
+	if (!hwif->ide_dma_on)
+		hwif->ide_dma_on = &__ide_dma_on;
+	if (!hwif->ide_dma_host_on)
+		hwif->ide_dma_host_on = &__ide_dma_host_on;
+	if (!hwif->ide_dma_check)
+		hwif->ide_dma_check = &__ide_dma_check;
+	if (!hwif->ide_dma_read)
+		hwif->ide_dma_read = &__ide_dma_read;
+	if (!hwif->ide_dma_write)
+		hwif->ide_dma_write = &__ide_dma_write;
+	if (!hwif->ide_dma_count)
+		hwif->ide_dma_count = &__ide_dma_count;
+	if (!hwif->ide_dma_begin)
+		hwif->ide_dma_begin = &__ide_dma_begin;
+	if (!hwif->ide_dma_end)
+		hwif->ide_dma_end = &__ide_dma_end;
+	if (!hwif->ide_dma_test_irq)
+		hwif->ide_dma_test_irq = &__ide_dma_test_irq;
+	if (!hwif->ide_dma_bad_drive)
+		hwif->ide_dma_bad_drive = &__ide_dma_bad_drive;
+	if (!hwif->ide_dma_good_drive)
+		hwif->ide_dma_good_drive = &__ide_dma_good_drive;
+	if (!hwif->ide_dma_verbose)
+		hwif->ide_dma_verbose = &__ide_dma_verbose;
+	if (!hwif->ide_dma_timeout)
+		hwif->ide_dma_timeout = &__ide_dma_timeout;
+	if (!hwif->ide_dma_retune)
+		hwif->ide_dma_retune = &__ide_dma_retune;
+	if (!hwif->ide_dma_lostirq)
+		hwif->ide_dma_lostirq = &__ide_dma_lostirq;
+
+	if (hwif->chipset != ide_trm290) {
+		u8 dma_stat = hwif->INB(hwif->dma_status);
+		printk(", BIOS settings: %s:%s, %s:%s",
+		       hwif->drives[0].name, (dma_stat & 0x20) ? "DMA" : "pio",
+		       hwif->drives[1].name, (dma_stat & 0x40) ? "DMA" : "pio");
 	}
-	return dma_base;
+	printk("\n");
+
+	if (!(hwif->dma_master))
+		BUG();
 }
+
+EXPORT_SYMBOL_GPL(ide_setup_dma);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-features.c linux-2.4.21-pre6/drivers/ide/ide-features.c
--- linux-2.4.20/drivers/ide/ide-features.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/ide-features.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,385 +0,0 @@
-/*
- * linux/drivers/block/ide-features.c	Version 0.04	June 9, 2000
- *
- *  Copyright (C) 1999-2000	Linus Torvalds & authors (see below)
- *  
- *  Copyright (C) 1999-2000	Andre Hedrick <andre@linux-ide.org>
- *
- *  Extracts if ide.c to address the evolving transfer rate code for
- *  the SETFEATURES_XFER callouts.  Various parts of any given function
- *  are credited to previous ATA-IDE maintainers.
- *
- *  Auto-CRC downgrade for Ultra DMA(ing)
- *
- *  May be copied or modified under the terms of the GNU General Public License
- */
-
-#include <linux/config.h>
-#define __NO_VERSION__
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/genhd.h>
-#include <linux/blkpg.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-
-#include <asm/byteorder.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/bitops.h>
-
-/*
- * A Verbose noise maker for debugging on the attempted transfer rates.
- */
-char *ide_xfer_verbose (byte xfer_rate)
-{
-	switch(xfer_rate) {
-		case XFER_UDMA_7:	return("UDMA 7");
-		case XFER_UDMA_6:	return("UDMA 6");
-		case XFER_UDMA_5:	return("UDMA 5");
-		case XFER_UDMA_4:	return("UDMA 4");
-		case XFER_UDMA_3:	return("UDMA 3");
-		case XFER_UDMA_2:	return("UDMA 2");
-		case XFER_UDMA_1:	return("UDMA 1");
-		case XFER_UDMA_0:	return("UDMA 0");
-		case XFER_MW_DMA_2:	return("MW DMA 2");
-		case XFER_MW_DMA_1:	return("MW DMA 1");
-		case XFER_MW_DMA_0:	return("MW DMA 0");
-		case XFER_SW_DMA_2:	return("SW DMA 2");
-		case XFER_SW_DMA_1:	return("SW DMA 1");
-		case XFER_SW_DMA_0:	return("SW DMA 0");
-		case XFER_PIO_4:	return("PIO 4");
-		case XFER_PIO_3:	return("PIO 3");
-		case XFER_PIO_2:	return("PIO 2");
-		case XFER_PIO_1:	return("PIO 1");
-		case XFER_PIO_0:	return("PIO 0");
-		case XFER_PIO_SLOW:	return("PIO SLOW");
-		default:		return("XFER ERROR");
-	}
-}
-
-/*
- *
- */
-char *ide_media_verbose (ide_drive_t *drive)
-{
-	switch (drive->media) {
-		case ide_scsi:		return("scsi   ");
-		case ide_disk:		return("disk   ");
-		case ide_optical:	return("optical");
-		case ide_cdrom:		return("cdrom  ");
-		case ide_tape:		return("tape   ");
-		case ide_floppy:	return("floppy ");
-		default:		return("???????");
-	}
-}
-
-/*
- * A Verbose noise maker for debugging on the attempted dmaing calls.
- */
-char *ide_dmafunc_verbose (ide_dma_action_t dmafunc)
-{
-	switch (dmafunc) {
-		case ide_dma_read:		return("ide_dma_read");
-		case ide_dma_write:		return("ide_dma_write");
-		case ide_dma_begin:		return("ide_dma_begin");
-		case ide_dma_end:		return("ide_dma_end:");
-		case ide_dma_check:		return("ide_dma_check");
-		case ide_dma_on:		return("ide_dma_on");
-		case ide_dma_off:		return("ide_dma_off");
-		case ide_dma_off_quietly:	return("ide_dma_off_quietly");
-		case ide_dma_test_irq:		return("ide_dma_test_irq");
-		case ide_dma_bad_drive:		return("ide_dma_bad_drive");
-		case ide_dma_good_drive:	return("ide_dma_good_drive");
-		case ide_dma_verbose:		return("ide_dma_verbose");
-		case ide_dma_retune:		return("ide_dma_retune");
-		case ide_dma_lostirq:		return("ide_dma_lostirq");
-		case ide_dma_timeout:		return("ide_dma_timeout");
-		default:			return("unknown");
-	}
-}
-
-/*
- *
- */
-byte ide_auto_reduce_xfer (ide_drive_t *drive)
-{
-	if (!drive->crc_count)
-		return drive->current_speed;
-	drive->crc_count = 0;
-
-	switch(drive->current_speed) {
-		case XFER_UDMA_7:	return XFER_UDMA_6;
-		case XFER_UDMA_6:	return XFER_UDMA_5;
-		case XFER_UDMA_5:	return XFER_UDMA_4;
-		case XFER_UDMA_4:	return XFER_UDMA_3;
-		case XFER_UDMA_3:	return XFER_UDMA_2;
-		case XFER_UDMA_2:	return XFER_UDMA_1;
-		case XFER_UDMA_1:	return XFER_UDMA_0;
-			/*
-			 * OOPS we do not goto non Ultra DMA modes
-			 * without iCRC's available we force
-			 * the system to PIO and make the user
-			 * invoke the ATA-1 ATA-2 DMA modes.
-			 */
-		case XFER_UDMA_0:
-		default:		return XFER_PIO_4;
-	}
-}
-
-/*
- * Update the 
- */
-int ide_driveid_update (ide_drive_t *drive)
-{
-	/*
-	 * Re-read drive->id for possible DMA mode
-	 * change (copied from ide-probe.c)
-	 */
-	struct hd_driveid *id;
-	unsigned long timeout, flags;
-
-	SELECT_MASK(HWIF(drive), drive, 1);
-	if (IDE_CONTROL_REG)
-		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
-	ide_delay_50ms();
-	OUT_BYTE(WIN_IDENTIFY, IDE_COMMAND_REG);
-	timeout = jiffies + WAIT_WORSTCASE;
-	do {
-		if (0 < (signed long)(jiffies - timeout)) {
-			SELECT_MASK(HWIF(drive), drive, 0);
-			return 0;	/* drive timed-out */
-		}
-		ide_delay_50ms();	/* give drive a breather */
-	} while (IN_BYTE(IDE_ALTSTATUS_REG) & BUSY_STAT);
-	ide_delay_50ms();	/* wait for IRQ and DRQ_STAT */
-	if (!OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT)) {
-		SELECT_MASK(HWIF(drive), drive, 0);
-		printk("%s: CHECK for good STATUS\n", drive->name);
-		return 0;
-	}
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only; some systems need this */
-	SELECT_MASK(HWIF(drive), drive, 0);
-	id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC);
-	if (!id) {
-		__restore_flags(flags);	/* local CPU only */
-		return 0;
-	}
-	ide_input_data(drive, id, SECTOR_WORDS);
-	(void) GET_STAT();	/* clear drive IRQ */
-	ide__sti();		/* local CPU only */
-	__restore_flags(flags);	/* local CPU only */
-	ide_fix_driveid(id);
-	if (id) {
-		drive->id->dma_ultra = id->dma_ultra;
-		drive->id->dma_mword = id->dma_mword;
-		drive->id->dma_1word = id->dma_1word;
-		/* anything more ? */
-		kfree(id);
-	}
-
-	return 1;
-}
-
-/*
- * Verify that we are doing an approved SETFEATURES_XFER with respect
- * to the hardware being able to support request.  Since some hardware
- * can improperly report capabilties, we check to see if the host adapter
- * in combination with the device (usually a disk) properly detect
- * and acknowledge each end of the ribbon.
- */
-int ide_ata66_check (ide_drive_t *drive, ide_task_t *args)
-{
-	if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
-	    (args->tfRegister[IDE_SECTOR_OFFSET] > XFER_UDMA_2) &&
-	    (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER)) {
-		if (!HWIF(drive)->udma_four) {
-			printk("%s: Speed warnings UDMA 3/4/5 is not functional.\n", HWIF(drive)->name);
-			return 1;
-		}
-#ifndef CONFIG_IDEDMA_IVB
-		if ((drive->id->hw_config & 0x6000) == 0) {
-#else /* !CONFIG_IDEDMA_IVB */
-		if (((drive->id->hw_config & 0x2000) == 0) ||
-		    ((drive->id->hw_config & 0x4000) == 0)) {
-#endif /* CONFIG_IDEDMA_IVB */
-			printk("%s: Speed warnings UDMA 3/4/5 is not functional.\n", drive->name);
-			return 1;
-		}
-	}
-	return 0;
-}
-
-/*
- * Backside of HDIO_DRIVE_CMD call of SETFEATURES_XFER.
- * 1 : Safe to update drive->id DMA registers.
- * 0 : OOPs not allowed.
- */
-int set_transfer (ide_drive_t *drive, ide_task_t *args)
-{
-	if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
-	    (args->tfRegister[IDE_SECTOR_OFFSET] >= XFER_SW_DMA_0) &&
-	    (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER) &&
-	    (drive->id->dma_ultra ||
-	     drive->id->dma_mword ||
-	     drive->id->dma_1word))
-		return 1;
-
-	return 0;
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-/*
- *  All hosts that use the 80c ribbon mus use!
- */
-byte eighty_ninty_three (ide_drive_t *drive)
-{
-#ifdef CONFIG_BLK_DEV_IDEPCI
-	if (HWIF(drive)->pci_devid.vid==0x105a)
-	    return(HWIF(drive)->udma_four);
-#endif
-	/* PDC202XX: that's because some HDD will return wrong info */
-	return ((byte) ((HWIF(drive)->udma_four) &&
-#ifndef CONFIG_IDEDMA_IVB
-			(drive->id->hw_config & 0x4000) &&
-#endif /* CONFIG_IDEDMA_IVB */
-			(drive->id->hw_config & 0x6000)) ? 1 : 0);
-}
-#endif // CONFIG_BLK_DEV_IDEDMA
-
-/*
- * Similar to ide_wait_stat(), except it never calls ide_error internally.
- * This is a kludge to handle the new ide_config_drive_speed() function,
- * and should not otherwise be used anywhere.  Eventually, the tuneproc's
- * should be updated to return ide_startstop_t, in which case we can get
- * rid of this abomination again.  :)   -ml
- *
- * It is gone..........
- *
- * const char *msg == consider adding for verbose errors.
- */
-int ide_config_drive_speed (ide_drive_t *drive, byte speed)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	int	i, error = 1;
-	byte stat;
-
-#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
-	byte unit = (drive->select.b.unit & 0x01);
-	outb(inb(hwif->dma_base+2) & ~(1<<(5+unit)), hwif->dma_base+2);
-#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
-
-	/*
-	 * Don't use ide_wait_cmd here - it will
-	 * attempt to set_geometry and recalibrate,
-	 * but for some reason these don't work at
-	 * this point (lost interrupt).
-	 */
-        /*
-         * Select the drive, and issue the SETFEATURES command
-         */
-	disable_irq(hwif->irq);	/* disable_irq_nosync ?? */
-	udelay(1);
-	SELECT_DRIVE(HWIF(drive), drive);
-	SELECT_MASK(HWIF(drive), drive, 0);
-	udelay(1);
-	if (IDE_CONTROL_REG)
-		OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG);
-	OUT_BYTE(speed, IDE_NSECTOR_REG);
-	OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG);
-	OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG);
-	if ((IDE_CONTROL_REG) && (drive->quirk_list == 2))
-		OUT_BYTE(drive->ctl, IDE_CONTROL_REG);
-	udelay(1);
-	/*
-	 * Wait for drive to become non-BUSY
-	 */
-	if ((stat = GET_STAT()) & BUSY_STAT) {
-		unsigned long flags, timeout;
-		__save_flags(flags);	/* local CPU only */
-		ide__sti();		/* local CPU only -- for jiffies */
-		timeout = jiffies + WAIT_CMD;
-		while ((stat = GET_STAT()) & BUSY_STAT) {
-			if (0 < (signed long)(jiffies - timeout))
-				break;
-		}
-		__restore_flags(flags); /* local CPU only */
-	}
-
-	/*
-	 * Allow status to settle, then read it again.
-	 * A few rare drives vastly violate the 400ns spec here,
-	 * so we'll wait up to 10usec for a "good" status
-	 * rather than expensively fail things immediately.
-	 * This fix courtesy of Matthew Faupel & Niccolo Rigacci.
-	 */
-	for (i = 0; i < 10; i++) {
-		udelay(1);
-		if (OK_STAT((stat = GET_STAT()), DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT)) {
-			error = 0;
-			break;
-		}
-	}
-
-	SELECT_MASK(HWIF(drive), drive, 0);
-
-	enable_irq(hwif->irq);
-
-	if (error) {
-		(void) ide_dump_status(drive, "set_drive_speed_status", stat);
-		return error;
-	}
-
-	drive->id->dma_ultra &= ~0xFF00;
-	drive->id->dma_mword &= ~0x0F00;
-	drive->id->dma_1word &= ~0x0F00;
-
-#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
-	if (speed > XFER_PIO_4) {
-		outb(inb(hwif->dma_base+2)|(1<<(5+unit)), hwif->dma_base+2);
-	} else {
-		outb(inb(hwif->dma_base+2) & ~(1<<(5+unit)), hwif->dma_base+2);
-	}
-#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
-
-	switch(speed) {
-		case XFER_UDMA_7:   drive->id->dma_ultra |= 0x8080; break;
-		case XFER_UDMA_6:   drive->id->dma_ultra |= 0x4040; break;
-		case XFER_UDMA_5:   drive->id->dma_ultra |= 0x2020; break;
-		case XFER_UDMA_4:   drive->id->dma_ultra |= 0x1010; break;
-		case XFER_UDMA_3:   drive->id->dma_ultra |= 0x0808; break;
-		case XFER_UDMA_2:   drive->id->dma_ultra |= 0x0404; break;
-		case XFER_UDMA_1:   drive->id->dma_ultra |= 0x0202; break;
-		case XFER_UDMA_0:   drive->id->dma_ultra |= 0x0101; break;
-		case XFER_MW_DMA_2: drive->id->dma_mword |= 0x0404; break;
-		case XFER_MW_DMA_1: drive->id->dma_mword |= 0x0202; break;
-		case XFER_MW_DMA_0: drive->id->dma_mword |= 0x0101; break;
-		case XFER_SW_DMA_2: drive->id->dma_1word |= 0x0404; break;
-		case XFER_SW_DMA_1: drive->id->dma_1word |= 0x0202; break;
-		case XFER_SW_DMA_0: drive->id->dma_1word |= 0x0101; break;
-		default: break;
-	}
-	return error;
-}
-
-EXPORT_SYMBOL(ide_auto_reduce_xfer);
-EXPORT_SYMBOL(ide_driveid_update);
-EXPORT_SYMBOL(ide_ata66_check);
-EXPORT_SYMBOL(set_transfer);
-#ifdef CONFIG_BLK_DEV_IDEDMA
-EXPORT_SYMBOL(eighty_ninty_three);
-#endif // CONFIG_BLK_DEV_IDEDMA
-EXPORT_SYMBOL(ide_config_drive_speed);
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-floppy.c linux-2.4.21-pre6/drivers/ide/ide-floppy.c
--- linux-2.4.20/drivers/ide/ide-floppy.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/ide-floppy.c	2003-03-26 23:49:19.000000000 +0000
@@ -153,10 +153,10 @@
 	char *b_data;				/* Pointer which runs on the buffers */
 	int b_count;				/* Missing/Available data on the current buffer */
 	struct request *rq;			/* The corresponding request */
-	byte *buffer;				/* Data buffer */
-	byte *current_position;			/* Pointer into the above buffer */
+	u8 *buffer;				/* Data buffer */
+	u8 *current_position;			/* Pointer into the above buffer */
 	void (*callback) (ide_drive_t *);	/* Called when this packet command is completed */
-	byte pc_buffer[IDEFLOPPY_PC_BUFFER_SIZE];	/* Temporary buffer */
+	u8 pc_buffer[IDEFLOPPY_PC_BUFFER_SIZE];	/* Temporary buffer */
 	unsigned long flags;			/* Status/Action bit flags: long for set_bit */
 } idefloppy_pc_t;
 
@@ -272,29 +272,41 @@
 typedef struct {
 	ide_drive_t *drive;
 
-	idefloppy_pc_t *pc;			/* Current packet command */
-	idefloppy_pc_t *failed_pc; 		/* Last failed packet command */
-	idefloppy_pc_t pc_stack[IDEFLOPPY_PC_STACK];/* Packet command stack */
-	int pc_stack_index;			/* Next free packet command storage space */
+	/* Current packet command */
+	idefloppy_pc_t *pc;
+	/* Last failed packet command */
+	idefloppy_pc_t *failed_pc;
+	/* Packet command stack */
+	idefloppy_pc_t pc_stack[IDEFLOPPY_PC_STACK];
+	/* Next free packet command storage space */
+	int pc_stack_index;
 	struct request rq_stack[IDEFLOPPY_PC_STACK];
-	int rq_stack_index;			/* We implement a circular array */
+	/* We implement a circular array */
+	int rq_stack_index;
 
 	/*
 	 *	Last error information
 	 */
-	byte sense_key, asc, ascq;
-	byte ticks;		/* delay this long before sending packet command */
+	u8 sense_key, asc, ascq;
+	/* delay this long before sending packet command */
+	u8 ticks;
 	int progress_indication;
 
 	/*
 	 *	Device information
 	 */
-	int blocks, block_size, bs_factor;			/* Current format */
-	idefloppy_capacity_descriptor_t capacity;		/* Last format capacity */
-	idefloppy_flexible_disk_page_t flexible_disk_page;	/* Copy of the flexible disk page */
-	int wp;							/* Write protect */
-	int srfp;			/* Supports format progress report */
-	unsigned long flags;			/* Status/Action flags */
+	/* Current format */
+	int blocks, block_size, bs_factor;
+	/* Last format capacity */
+	idefloppy_capacity_descriptor_t capacity;
+	/* Copy of the flexible disk page */
+	idefloppy_flexible_disk_page_t flexible_disk_page;
+	/* Write protect */
+	int wp;
+	/* Supports format progress report */
+	int srfp;
+	/* Status/Action flags */
+	unsigned long flags;
 } idefloppy_floppy_t;
 
 #define IDEFLOPPY_TICKS_DELAY	3	/* default delay for ZIP 100 */
@@ -349,20 +361,20 @@
 /*
  *	Special requests for our block device strategy routine.
  */
-#define	IDEFLOPPY_FIRST_RQ		90
+#define	IDEFLOPPY_FIRST_RQ	90
 
 /*
  * 	IDEFLOPPY_PC_RQ is used to queue a packet command in the request queue.
  */
-#define	IDEFLOPPY_PC_RQ			90
+#define	IDEFLOPPY_PC_RQ		90
 
-#define IDEFLOPPY_LAST_RQ		90
+#define IDEFLOPPY_LAST_RQ	90
 
 /*
  *	A macro which can be used to check if a given request command
  *	originated in the driver or in the buffer cache layer.
  */
-#define IDEFLOPPY_RQ_CMD(cmd) 		((cmd >= IDEFLOPPY_FIRST_RQ) && (cmd <= IDEFLOPPY_LAST_RQ))
+#define IDEFLOPPY_RQ_CMD(cmd) 	((cmd >= IDEFLOPPY_FIRST_RQ) && (cmd <= IDEFLOPPY_LAST_RQ))
 
 /*
  *	Error codes which are returned in rq->errors to the higher part
@@ -371,170 +383,6 @@
 #define	IDEFLOPPY_ERROR_GENERAL		101
 
 /*
- *	The ATAPI Status Register.
- */
-typedef union {
-	unsigned all			:8;
-	struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-		unsigned check		:1;	/* Error occurred */
-		unsigned idx		:1;	/* Reserved */
-		unsigned corr		:1;	/* Correctable error occurred */
-		unsigned drq		:1;	/* Data is request by the device */
-		unsigned dsc		:1;	/* Media access command finished */
-		unsigned reserved5	:1;	/* Reserved */
-		unsigned drdy		:1;	/* Ignored for ATAPI commands (ready to accept ATA command) */
-		unsigned bsy		:1;	/* The device has access to the command block */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-		unsigned bsy		:1;	/* The device has access to the command block */
-		unsigned drdy		:1;	/* Ignored for ATAPI commands (ready to accept ATA command) */
-		unsigned reserved5	:1;	/* Reserved */
-		unsigned dsc		:1;	/* Media access command finished */
-		unsigned drq		:1;	/* Data is request by the device */
-		unsigned corr		:1;	/* Correctable error occurred */
-		unsigned idx		:1;	/* Reserved */
-		unsigned check		:1;	/* Error occurred */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-	} b;
-} idefloppy_status_reg_t;
-
-/*
- *	The ATAPI error register.
- */
-typedef union {
-	unsigned all			:8;
-	struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-		unsigned ili		:1;	/* Illegal Length Indication */
-		unsigned eom		:1;	/* End Of Media Detected */
-		unsigned abrt		:1;	/* Aborted command - As defined by ATA */
-		unsigned mcr		:1;	/* Media Change Requested - As defined by ATA */
-		unsigned sense_key	:4;	/* Sense key of the last failed packet command */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-		unsigned sense_key	:4;	/* Sense key of the last failed packet command */
-		unsigned mcr		:1;	/* Media Change Requested - As defined by ATA */
-		unsigned abrt		:1;	/* Aborted command - As defined by ATA */
-		unsigned eom		:1;	/* End Of Media Detected */
-		unsigned ili		:1;	/* Illegal Length Indication */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-	} b;
-} idefloppy_error_reg_t;
-
-/*
- *	ATAPI Feature Register
- */
-typedef union {
-	unsigned all			:8;
-	struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-		unsigned dma		:1;	/* Using DMA or PIO */
-		unsigned reserved321	:3;	/* Reserved */
-		unsigned reserved654	:3;	/* Reserved (Tag Type) */
-		unsigned reserved7	:1;	/* Reserved */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-		unsigned reserved7	:1;	/* Reserved */
-		unsigned reserved654	:3;	/* Reserved (Tag Type) */
-		unsigned reserved321	:3;	/* Reserved */
-		unsigned dma		:1;	/* Using DMA or PIO */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-	} b;
-} idefloppy_feature_reg_t;
-
-/*
- *	ATAPI Byte Count Register.
- */
-typedef union {
-	unsigned all			:16;
-	struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-		unsigned low		:8;	/* LSB */
-		unsigned high		:8;	/* MSB */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-		unsigned high		:8;	/* MSB */
-		unsigned low		:8;	/* LSB */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-	} b;
-} idefloppy_bcount_reg_t;
-
-/*
- *	ATAPI Interrupt Reason Register.
- */
-typedef union {
-	unsigned all			:8;
-	struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-		unsigned cod		:1;	/* Information transferred is command (1) or data (0) */
-		unsigned io		:1;	/* The device requests us to read (1) or write (0) */
-		unsigned reserved	:6;	/* Reserved */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-		unsigned reserved	:6;	/* Reserved */
-		unsigned io		:1;	/* The device requests us to read (1) or write (0) */
-		unsigned cod		:1;	/* Information transferred is command (1) or data (0) */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-	} b;
-} idefloppy_ireason_reg_t;
-
-/*
- *	ATAPI floppy Drive Select Register
- */
-typedef union {	
-	unsigned all			:8;
-	struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-		unsigned sam_lun	:3;	/* Logical unit number */
-		unsigned reserved3	:1;	/* Reserved */
-		unsigned drv		:1;	/* The responding drive will be drive 0 (0) or drive 1 (1) */
-		unsigned one5		:1;	/* Should be set to 1 */
-		unsigned reserved6	:1;	/* Reserved */
-		unsigned one7		:1;	/* Should be set to 1 */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-		unsigned one7		:1;	/* Should be set to 1 */
-		unsigned reserved6	:1;	/* Reserved */
-		unsigned one5		:1;	/* Should be set to 1 */
-		unsigned drv		:1;	/* The responding drive will be drive 0 (0) or drive 1 (1) */
-		unsigned reserved3	:1;	/* Reserved */
-		unsigned sam_lun	:3;	/* Logical unit number */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-	} b;
-} idefloppy_drivesel_reg_t;
-
-/*
- *	ATAPI Device Control Register
- */
-typedef union {			
-	unsigned all			:8;
-	struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-		unsigned zero0		:1;	/* Should be set to zero */
-		unsigned nien		:1;	/* Device interrupt is disabled (1) or enabled (0) */
-		unsigned srst		:1;	/* ATA software reset. ATAPI devices should use the new ATAPI srst. */
-		unsigned one3		:1;	/* Should be set to 1 */
-		unsigned reserved4567	:4;	/* Reserved */
-#elif defined(__BIG_ENDIAN_BITFIELD)
-		unsigned reserved4567	:4;	/* Reserved */
-		unsigned one3		:1;	/* Should be set to 1 */
-		unsigned srst		:1;	/* ATA software reset. ATAPI devices should use the new ATAPI srst. */
-		unsigned nien		:1;	/* Device interrupt is disabled (1) or enabled (0) */
-		unsigned zero0		:1;	/* Should be set to zero */
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-	} b;
-} idefloppy_control_reg_t;
-
-/*
  *	The following is used to format the general configuration word of
  *	the ATAPI IDENTIFY DEVICE command.
  */
@@ -668,32 +516,61 @@
 static void idefloppy_discard_data (ide_drive_t *drive, unsigned int bcount)
 {
 	while (bcount--)
-		IN_BYTE (IDE_DATA_REG);
+		(void) HWIF(drive)->INB(IDE_DATA_REG);
 }
 
 #if IDEFLOPPY_DEBUG_BUGS
 static void idefloppy_write_zeros (ide_drive_t *drive, unsigned int bcount)
 {
 	while (bcount--)
-		OUT_BYTE (0, IDE_DATA_REG);
+		HWIF(drive)->OUTB(0, IDE_DATA_REG);
 }
 #endif /* IDEFLOPPY_DEBUG_BUGS */
 
+
+static int idefloppy_end_request (ide_drive_t *drive, int uptodate)
+{
+	struct request *rq;
+	unsigned long flags;
+	int ret = 1;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	rq = HWGROUP(drive)->rq;
+
+	/*
+	 * decide whether to reenable DMA -- 3 is a random magic for now,
+	 * if we DMA timeout more than 3 times, just stay in PIO
+	 */
+	if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
+		drive->state = 0;
+		HWGROUP(drive)->hwif->ide_dma_on(drive);
+	}
+
+	if (!end_that_request_first(rq, uptodate, drive->name)) {
+		add_blkdev_randomness(MAJOR(rq->rq_dev));
+		blkdev_dequeue_request(rq);
+		HWGROUP(drive)->rq = NULL;
+		end_that_request_last(rq);
+		ret = 0;
+	}
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	return ret;
+}
+
 /*
- *	idefloppy_end_request is used to finish servicing a request.
+ *	idefloppy_do_end_request is used to finish servicing a request.
  *
  *	For read/write requests, we will call ide_end_request to pass to the
  *	next buffer.
  */
-static void idefloppy_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
+static int idefloppy_do_end_request (ide_drive_t *drive, int uptodate)
 {
-	ide_drive_t *drive = hwgroup->drive;
 	idefloppy_floppy_t *floppy = drive->driver_data;
-	struct request *rq = hwgroup->rq;
+	struct request *rq = HWGROUP(drive)->rq;
 	int error;
 
 #if IDEFLOPPY_DEBUG_LOG
-	printk (KERN_INFO "Reached idefloppy_end_request\n");
+	printk(KERN_INFO "Reached idefloppy_end_request\n");
 #endif /* IDEFLOPPY_DEBUG_LOG */
 
 	switch (uptodate) {
@@ -705,13 +582,16 @@
 		floppy->failed_pc = NULL;
 	/* Why does this happen? */
 	if (!rq)
-		return;
-	if (!IDEFLOPPY_RQ_CMD (rq->cmd)) {
-		ide_end_request (uptodate, hwgroup);
-		return;
+		return 0;
+	if (!IDEFLOPPY_RQ_CMD(rq->cmd)) {
+		/* our real local end request function */
+		idefloppy_end_request(drive, uptodate);
+		return 0;
 	}
 	rq->errors = error;
-	ide_end_drive_cmd (drive, 0, 0);
+	/* fixme: need to move this local also */
+	ide_end_drive_cmd(drive, 0, 0);
+	return 0;
 }
 
 static void idefloppy_input_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, unsigned int bcount)
@@ -724,18 +604,21 @@
 		if (pc->b_count == bh->b_size) {
 			rq->sector += rq->current_nr_sectors;
 			rq->nr_sectors -= rq->current_nr_sectors;
-			idefloppy_end_request (1, HWGROUP(drive));
+			idefloppy_do_end_request(drive, 1);
 			if ((bh = rq->bh) != NULL)
 				pc->b_count = 0;
 		}
 		if (bh == NULL) {
-			printk (KERN_ERR "%s: bh == NULL in idefloppy_input_buffers, bcount == %d\n", drive->name, bcount);
-			idefloppy_discard_data (drive, bcount);
+			printk(KERN_ERR "%s: bh == NULL in "
+				"idefloppy_input_buffers, bcount == %d\n",
+				drive->name, bcount);
+			idefloppy_discard_data(drive, bcount);
 			return;
 		}
-		count = IDEFLOPPY_MIN (bh->b_size - pc->b_count, bcount);
-		atapi_input_bytes (drive, bh->b_data + pc->b_count, count);
-		bcount -= count; pc->b_count += count;
+		count = IDEFLOPPY_MIN(bh->b_size - pc->b_count, bcount);
+		HWIF(drive)->atapi_input_bytes(drive, bh->b_data + pc->b_count, count);
+		bcount -= count;
+		pc->b_count += count;
 	}
 }
 
@@ -749,20 +632,24 @@
 		if (!pc->b_count) {
 			rq->sector += rq->current_nr_sectors;
 			rq->nr_sectors -= rq->current_nr_sectors;
-			idefloppy_end_request (1, HWGROUP(drive));
+			idefloppy_do_end_request(drive, 1);
 			if ((bh = rq->bh) != NULL) {
 				pc->b_data = bh->b_data;
 				pc->b_count = bh->b_size;
 			}
 		}
 		if (bh == NULL) {
-			printk (KERN_ERR "%s: bh == NULL in idefloppy_output_buffers, bcount == %d\n", drive->name, bcount);
+			printk(KERN_ERR "%s: bh == NULL in "
+				"idefloppy_output_buffers, bcount == %d\n",
+				drive->name, bcount);
 			idefloppy_write_zeros (drive, bcount);
 			return;
 		}
-		count = IDEFLOPPY_MIN (pc->b_count, bcount);
-		atapi_output_bytes (drive, pc->b_data, count);
-		bcount -= count; pc->b_data += count; pc->b_count -= count;
+		count = IDEFLOPPY_MIN(pc->b_count, bcount);
+		HWIF(drive)->atapi_output_bytes(drive, pc->b_data, count);
+		bcount -= count;
+		pc->b_data += count;
+		pc->b_count -= count;
 	}
 }
 
@@ -773,7 +660,7 @@
 	struct buffer_head *bh = rq->bh;
 
 	while ((bh = rq->bh) != NULL)
-		idefloppy_end_request (1, HWGROUP(drive));
+		idefloppy_do_end_request(drive, 1);
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
@@ -784,17 +671,17 @@
  */
 static void idefloppy_queue_pc_head (ide_drive_t *drive,idefloppy_pc_t *pc,struct request *rq)
 {
-	ide_init_drive_cmd (rq);
-	rq->buffer = (char *) pc;
+	ide_init_drive_cmd(rq);
+	rq->buffer = (char *)pc;
 	rq->cmd = IDEFLOPPY_PC_RQ;
-	(void) ide_do_drive_cmd (drive, rq, ide_preempt);
+	(void) ide_do_drive_cmd(drive, rq, ide_preempt);
 }
 
 static idefloppy_pc_t *idefloppy_next_pc_storage (ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 
-	if (floppy->pc_stack_index==IDEFLOPPY_PC_STACK)
+	if (floppy->pc_stack_index == IDEFLOPPY_PC_STACK)
 		floppy->pc_stack_index=0;
 	return (&floppy->pc_stack[floppy->pc_stack_index++]);
 }
@@ -803,8 +690,8 @@
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 
-	if (floppy->rq_stack_index==IDEFLOPPY_PC_STACK)
-		floppy->rq_stack_index=0;
+	if (floppy->rq_stack_index == IDEFLOPPY_PC_STACK)
+		floppy->rq_stack_index = 0;
 	return (&floppy->rq_stack[floppy->rq_stack_index++]);
 }
 
@@ -816,14 +703,20 @@
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 
-	floppy->sense_key = result->sense_key; floppy->asc = result->asc; floppy->ascq = result->ascq;
-	floppy->progress_indication= result->sksv[0] & 0x80 ?
-		(unsigned short)get_unaligned((u16 *)(result->sksv+1)):0x10000;
+	floppy->sense_key = result->sense_key;
+	floppy->asc = result->asc;
+	floppy->ascq = result->ascq;
+	floppy->progress_indication = result->sksv[0] & 0x80 ?
+		(u16)get_unaligned((u16 *)(result->sksv+1)):0x10000;
 #if IDEFLOPPY_DEBUG_LOG
 	if (floppy->failed_pc)
-		printk (KERN_INFO "ide-floppy: pc = %x, sense key = %x, asc = %x, ascq = %x\n",floppy->failed_pc->c[0],result->sense_key,result->asc,result->ascq);
+		printk(KERN_INFO "ide-floppy: pc = %x, sense key = %x, "
+			"asc = %x, ascq = %x\n", floppy->failed_pc->c[0],
+			result->sense_key, result->asc, result->ascq);
 	else
-		printk (KERN_INFO "ide-floppy: sense key = %x, asc = %x, ascq = %x\n",result->sense_key,result->asc,result->ascq);
+		printk(KERN_INFO "ide-floppy: sense key = %x, asc = %x, "
+			"ascq = %x\n", result->sense_key,
+			result->asc, result->ascq);
 #endif /* IDEFLOPPY_DEBUG_LOG */
 }
 
@@ -832,14 +725,14 @@
 	idefloppy_floppy_t *floppy = drive->driver_data;
 
 #if IDEFLOPPY_DEBUG_LOG
-	printk (KERN_INFO "ide-floppy: Reached idefloppy_request_sense_callback\n");
+	printk(KERN_INFO "ide-floppy: Reached %s\n", __FUNCTION__);
 #endif /* IDEFLOPPY_DEBUG_LOG */
 	if (!floppy->pc->error) {
-		idefloppy_analyze_error (drive,(idefloppy_request_sense_result_t *) floppy->pc->buffer);
-		idefloppy_end_request (1,HWGROUP (drive));
+		idefloppy_analyze_error(drive,(idefloppy_request_sense_result_t *) floppy->pc->buffer);
+		idefloppy_do_end_request(drive, 1);
 	} else {
-		printk (KERN_ERR "Error in REQUEST SENSE itself - Aborting request!\n");
-		idefloppy_end_request (0,HWGROUP (drive));
+		printk(KERN_ERR "Error in REQUEST SENSE itself - Aborting request!\n");
+		idefloppy_do_end_request(drive, 0);
 	}
 }
 
@@ -851,10 +744,10 @@
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	
 #if IDEFLOPPY_DEBUG_LOG
-	printk (KERN_INFO "ide-floppy: Reached idefloppy_pc_callback\n");
+	printk (KERN_INFO "ide-floppy: Reached %s\n", __FUNCTION__);
 #endif /* IDEFLOPPY_DEBUG_LOG */
 
-	idefloppy_end_request (floppy->pc->error ? 0:1, HWGROUP(drive));
+	idefloppy_do_end_request(drive, floppy->pc->error ? 0 : 1);
 }
 
 /*
@@ -862,7 +755,7 @@
  */
 static void idefloppy_init_pc (idefloppy_pc_t *pc)
 {
-	memset (pc->c, 0, 12);
+	memset(pc->c, 0, 12);
 	pc->retries = 0;
 	pc->flags = 0;
 	pc->request_transfer = 0;
@@ -874,7 +767,7 @@
 
 static void idefloppy_create_request_sense_cmd (idefloppy_pc_t *pc)
 {
-	idefloppy_init_pc (pc);	
+	idefloppy_init_pc(pc);	
 	pc->c[0] = IDEFLOPPY_REQUEST_SENSE_CMD;
 	pc->c[4] = 255;
 	pc->request_transfer = 18;
@@ -890,13 +783,13 @@
 {
 	idefloppy_pc_t *pc;
 	struct request *rq;
-	idefloppy_error_reg_t error;
+	atapi_error_t error;
 
-	error.all = IN_BYTE (IDE_ERROR_REG);
-	pc = idefloppy_next_pc_storage (drive);
-	rq = idefloppy_next_rq_storage (drive);
-	idefloppy_create_request_sense_cmd (pc);
-	idefloppy_queue_pc_head (drive, pc, rq);
+	error.all = HWIF(drive)->INB(IDE_ERROR_REG);
+	pc = idefloppy_next_pc_storage(drive);
+	rq = idefloppy_next_rq_storage(drive);
+	idefloppy_create_request_sense_cmd(pc);
+	idefloppy_queue_pc_head(drive, pc, rq);
 }
 
 /*
@@ -906,24 +799,25 @@
 static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
-	idefloppy_status_reg_t status;
-	idefloppy_bcount_reg_t bcount;
-	idefloppy_ireason_reg_t ireason;
-	idefloppy_pc_t *pc=floppy->pc;
+	atapi_status_t status;
+	atapi_bcount_t bcount;
+	atapi_ireason_t ireason;
+	idefloppy_pc_t *pc = floppy->pc;
 	struct request *rq = pc->rq;
 	unsigned int temp;
 
 #if IDEFLOPPY_DEBUG_LOG
-	printk (KERN_INFO "ide-floppy: Reached idefloppy_pc_intr interrupt handler\n");
+	printk(KERN_INFO "ide-floppy: Reached %s interrupt handler\n",
+		__FUNCTION__);
 #endif /* IDEFLOPPY_DEBUG_LOG */	
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (test_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
-		if (HWIF(drive)->dmaproc(ide_dma_end, drive)) {
-			set_bit (PC_DMA_ERROR, &pc->flags);
+	if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
+		if (HWIF(drive)->ide_dma_end(drive)) {
+			set_bit(PC_DMA_ERROR, &pc->flags);
 		} else {
-			pc->actually_transferred=pc->request_transfer;
-			idefloppy_update_buffers (drive, pc);
+			pc->actually_transferred = pc->request_transfer;
+			idefloppy_update_buffers(drive, pc);
 		}
 #if IDEFLOPPY_DEBUG_LOG
 		printk (KERN_INFO "ide-floppy: DMA finished\n");
@@ -931,83 +825,116 @@
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
-	status.all = GET_STAT();					/* Clear the interrupt */
+	/* Clear the interrupt */
+	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
 
-	if (!status.b.drq) {						/* No more interrupts */
+	if (!status.b.drq) {			/* No more interrupts */
 #if IDEFLOPPY_DEBUG_LOG
-		printk (KERN_INFO "Packet command completed, %d bytes transferred\n", pc->actually_transferred);
+		printk(KERN_INFO "Packet command completed, %d bytes "
+			"transferred\n", pc->actually_transferred);
 #endif /* IDEFLOPPY_DEBUG_LOG */
-		clear_bit (PC_DMA_IN_PROGRESS, &pc->flags);
+		clear_bit(PC_DMA_IN_PROGRESS, &pc->flags);
 
-		ide__sti();	/* local CPU only */
+		local_irq_enable();
 
-		if (status.b.check || test_bit (PC_DMA_ERROR, &pc->flags)) {	/* Error detected */
+		if (status.b.check || test_bit(PC_DMA_ERROR, &pc->flags)) {
+			/* Error detected */
 #if IDEFLOPPY_DEBUG_LOG
-			printk (KERN_INFO "ide-floppy: %s: I/O error\n",drive->name);
+			printk(KERN_INFO "ide-floppy: %s: I/O error\n",
+				drive->name);
 #endif /* IDEFLOPPY_DEBUG_LOG */
 			rq->errors++;
 			if (pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) {
-				printk (KERN_ERR "ide-floppy: I/O error in request sense command\n");
-				return ide_do_reset (drive);
+				printk(KERN_ERR "ide-floppy: I/O error in "
+					"request sense command\n");
+				return ide_do_reset(drive);
 			}
-			idefloppy_retry_pc (drive);				/* Retry operation */
-			return ide_stopped; /* queued, but not started */
+			/* Retry operation */
+			idefloppy_retry_pc(drive);
+			/* queued, but not started */
+			return ide_stopped;
 		}
 		pc->error = 0;
 		if (floppy->failed_pc == pc)
-			floppy->failed_pc=NULL;
-		pc->callback(drive);			/* Command finished - Call the callback function */
+			floppy->failed_pc = NULL;
+		/* Command finished - Call the callback function */
+		pc->callback(drive);
 		return ide_stopped;
 	}
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
-		printk (KERN_ERR "ide-floppy: The floppy wants to issue more interrupts in DMA mode\n");
-		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
-		return ide_do_reset (drive);
+	if (test_and_clear_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
+		printk(KERN_ERR "ide-floppy: The floppy wants to issue "
+			"more interrupts in DMA mode\n");
+		(void) HWIF(drive)->ide_dma_off(drive);
+		return ide_do_reset(drive);
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
-	bcount.b.high=IN_BYTE (IDE_BCOUNTH_REG);			/* Get the number of bytes to transfer */
-	bcount.b.low=IN_BYTE (IDE_BCOUNTL_REG);			/* on this interrupt */
-	ireason.all=IN_BYTE (IDE_IREASON_REG);
+	/* Get the number of bytes to transfer */
+	bcount.b.high = HWIF(drive)->INB(IDE_BCOUNTH_REG);
+	bcount.b.low = HWIF(drive)->INB(IDE_BCOUNTL_REG);
+	/* on this interrupt */
+	ireason.all = HWIF(drive)->INB(IDE_IREASON_REG);
 
 	if (ireason.b.cod) {
-		printk (KERN_ERR "ide-floppy: CoD != 0 in idefloppy_pc_intr\n");
-		return ide_do_reset (drive);
+		printk(KERN_ERR "ide-floppy: CoD != 0 in idefloppy_pc_intr\n");
+		return ide_do_reset(drive);
 	}
-	if (ireason.b.io == test_bit (PC_WRITING, &pc->flags)) {	/* Hopefully, we will never get here */
-		printk (KERN_ERR "ide-floppy: We wanted to %s, ", ireason.b.io ? "Write":"Read");
-		printk (KERN_ERR "but the floppy wants us to %s !\n",ireason.b.io ? "Read":"Write");
-		return ide_do_reset (drive);
+	if (ireason.b.io == test_bit(PC_WRITING, &pc->flags)) {
+		/* Hopefully, we will never get here */
+		printk(KERN_ERR "ide-floppy: We wanted to %s, ",
+			ireason.b.io ? "Write":"Read");
+		printk(KERN_ERR "but the floppy wants us to %s !\n",
+			ireason.b.io ? "Read":"Write");
+		return ide_do_reset(drive);
 	}
-	if (!test_bit (PC_WRITING, &pc->flags)) {			/* Reading - Check that we have enough space */
+	if (!test_bit(PC_WRITING, &pc->flags)) {
+		/* Reading - Check that we have enough space */
 		temp = pc->actually_transferred + bcount.all;
-		if ( temp > pc->request_transfer) {
+		if (temp > pc->request_transfer) {
 			if (temp > pc->buffer_size) {
-				printk (KERN_ERR "ide-floppy: The floppy wants to send us more data than expected - discarding data\n");
-				idefloppy_discard_data (drive,bcount.all);
-				ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD, NULL);
+				printk(KERN_ERR "ide-floppy: The floppy wants "
+					"to send us more data than expected "
+					"- discarding data\n");
+				idefloppy_discard_data(drive,bcount.all);
+				if (HWGROUP(drive)->handler != NULL)
+					BUG();
+				ide_set_handler(drive,
+						&idefloppy_pc_intr,
+						IDEFLOPPY_WAIT_CMD,
+						NULL);
 				return ide_started;
 			}
 #if IDEFLOPPY_DEBUG_LOG
-			printk (KERN_NOTICE "ide-floppy: The floppy wants to send us more data than expected - allowing transfer\n");
+			printk(KERN_NOTICE "ide-floppy: The floppy wants to "
+				"send us more data than expected - "
+				"allowing transfer\n");
 #endif /* IDEFLOPPY_DEBUG_LOG */
 		}
 	}
-	if (test_bit (PC_WRITING, &pc->flags)) {
+	if (test_bit(PC_WRITING, &pc->flags)) {
 		if (pc->buffer != NULL)
-			atapi_output_bytes (drive,pc->current_position,bcount.all);	/* Write the current buffer */
+			/* Write the current buffer */
+			HWIF(drive)->atapi_output_bytes(drive,
+						pc->current_position,
+						bcount.all);
 		else
-			idefloppy_output_buffers (drive, pc, bcount.all);
+			idefloppy_output_buffers(drive, pc, bcount.all);
 	} else {
 		if (pc->buffer != NULL)
-			atapi_input_bytes (drive,pc->current_position,bcount.all);	/* Read the current buffer */
+			/* Read the current buffer */
+			HWIF(drive)->atapi_input_bytes(drive,
+						pc->current_position,
+						bcount.all);
 		else
-			idefloppy_input_buffers (drive, pc, bcount.all);
+			idefloppy_input_buffers(drive, pc, bcount.all);
 	}
-	pc->actually_transferred+=bcount.all;				/* Update the current position */
-	pc->current_position+=bcount.all;
-
-	ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD, NULL);		/* And set the interrupt handler again */
+	/* Update the current position */
+	pc->actually_transferred += bcount.all;
+	pc->current_position += bcount.all;
+
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);		/* And set the interrupt handler again */
 	return ide_started;
 }
 
@@ -1020,19 +947,25 @@
 {
 	ide_startstop_t startstop;
 	idefloppy_floppy_t *floppy = drive->driver_data;
-	idefloppy_ireason_reg_t ireason;
+	atapi_ireason_t ireason;
 
-	if (ide_wait_stat (&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
-		printk (KERN_ERR "ide-floppy: Strange, packet command initiated yet DRQ isn't asserted\n");
+	if (ide_wait_stat(&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY)) {
+		printk(KERN_ERR "ide-floppy: Strange, packet command "
+				"initiated yet DRQ isn't asserted\n");
 		return startstop;
 	}
-	ireason.all=IN_BYTE (IDE_IREASON_REG);
+	ireason.all = HWIF(drive)->INB(IDE_IREASON_REG);
 	if (!ireason.b.cod || ireason.b.io) {
-		printk (KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while issuing a packet command\n");
-		return ide_do_reset (drive);
-	}
-	ide_set_handler (drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);	/* Set the interrupt routine */
-	atapi_output_bytes (drive, floppy->pc->c, 12); /* Send the actual packet */
+		printk(KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while "
+				"issuing a packet command\n");
+		return ide_do_reset(drive);
+	}
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	/* Set the interrupt routine */
+	ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);
+	/* Send the actual packet */
+	HWIF(drive)->atapi_output_bytes(drive, floppy->pc->c, 12);
 	return ide_started;
 }
 
@@ -1053,35 +986,42 @@
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 
-	atapi_output_bytes (drive, floppy->pc->c, 12); /* Send the actual packet */
-	return IDEFLOPPY_WAIT_CMD;		/* Timeout for the packet command */
+	/* Send the actual packet */
+	HWIF(drive)->atapi_output_bytes(drive, floppy->pc->c, 12);
+	/* Timeout for the packet command */
+	return IDEFLOPPY_WAIT_CMD;
 }
 
 static ide_startstop_t idefloppy_transfer_pc1 (ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	ide_startstop_t startstop;
-	idefloppy_ireason_reg_t ireason;
+	atapi_ireason_t ireason;
 
-	if (ide_wait_stat (&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
-		printk (KERN_ERR "ide-floppy: Strange, packet command initiated yet DRQ isn't asserted\n");
+	if (ide_wait_stat(&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY)) {
+		printk(KERN_ERR "ide-floppy: Strange, packet command "
+				"initiated yet DRQ isn't asserted\n");
 		return startstop;
 	}
-	ireason.all=IN_BYTE (IDE_IREASON_REG);
+	ireason.all = HWIF(drive)->INB(IDE_IREASON_REG);
 	if (!ireason.b.cod || ireason.b.io) {
-		printk (KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while issuing a packet command\n");
-		return ide_do_reset (drive);
+		printk(KERN_ERR "ide-floppy: (IO,CoD) != (0,1) "
+				"while issuing a packet command\n");
+		return ide_do_reset(drive);
 	}
 	/* 
-	 * The following delay solves a problem with ATAPI Zip 100 drives where the
-	 * Busy flag was apparently being deasserted before the unit was ready to
-	 * receive data. This was happening on a 1200 MHz Athlon system. 10/26/01
-	 * 25msec is too short, 40 and 50msec work well. idefloppy_pc_intr will 
-	 * not be actually used until after the packet is moved in about 50 msec.
+	 * The following delay solves a problem with ATAPI Zip 100 drives
+	 * where the Busy flag was apparently being deasserted before the
+	 * unit was ready to receive data. This was happening on a
+	 * 1200 MHz Athlon system. 10/26/01 25msec is too short,
+	 * 40 and 50msec work well. idefloppy_pc_intr will not be actually
+	 * used until after the packet is moved in about 50 msec.
 	 */
-	ide_set_handler (drive, 
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	ide_set_handler(drive, 
 	  &idefloppy_pc_intr, 		/* service routine for packet command */
-	  floppy->ticks,			/* wait this long before "failing" */
+	  floppy->ticks,		/* wait this long before "failing" */
 	  &idefloppy_transfer_pc2);	/* fail == transfer_pc2 */
 	return ide_started;
 }
@@ -1092,81 +1032,109 @@
 static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *pc)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
-	idefloppy_bcount_reg_t bcount;
-	int dma_ok = 0;
+	atapi_feature_t feature;
+	atapi_bcount_t bcount;
 	ide_handler_t *pkt_xfer_routine;
 
 #if IDEFLOPPY_DEBUG_BUGS
-	if (floppy->pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD && pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) {
-		printk (KERN_ERR "ide-floppy: possible ide-floppy.c bug - Two request sense in serial were issued\n");
+	if (floppy->pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD &&
+	    pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) {
+		printk(KERN_ERR "ide-floppy: possible ide-floppy.c bug - "
+			"Two request sense in serial were issued\n");
 	}
 #endif /* IDEFLOPPY_DEBUG_BUGS */
 
-	if (floppy->failed_pc == NULL && pc->c[0] != IDEFLOPPY_REQUEST_SENSE_CMD)
-		floppy->failed_pc=pc;
-	floppy->pc=pc;							/* Set the current packet command */
+	if (floppy->failed_pc == NULL &&
+	    pc->c[0] != IDEFLOPPY_REQUEST_SENSE_CMD)
+		floppy->failed_pc = pc;
+	/* Set the current packet command */
+	floppy->pc = pc;
 
-	if (pc->retries > IDEFLOPPY_MAX_PC_RETRIES || test_bit (PC_ABORT, &pc->flags)) {
+	if (pc->retries > IDEFLOPPY_MAX_PC_RETRIES ||
+	    test_bit(PC_ABORT, &pc->flags)) {
 		/*
 		 *	We will "abort" retrying a packet command in case
 		 *	a legitimate error code was received.
 		 */
-		if (!test_bit (PC_ABORT, &pc->flags)) {
-			if (!test_bit (PC_SUPPRESS_ERROR, &pc->flags)) {
-				;
-      printk( KERN_ERR "ide-floppy: %s: I/O error, pc = %2x, key = %2x, asc = %2x, ascq = %2x\n",
-				drive->name, pc->c[0], floppy->sense_key, floppy->asc, floppy->ascq);
+		if (!test_bit(PC_ABORT, &pc->flags)) {
+			if (!test_bit(PC_SUPPRESS_ERROR, &pc->flags)) {
+				printk(KERN_ERR "ide-floppy: %s: I/O error, "
+						"pc = %2x, key = %2x, "
+						"asc = %2x, ascq = %2x\n",
+						drive->name, pc->c[0],
+						floppy->sense_key,
+						floppy->asc, floppy->ascq);
 			}
-			pc->error = IDEFLOPPY_ERROR_GENERAL;		/* Giving up */
+			/* Giving up */
+			pc->error = IDEFLOPPY_ERROR_GENERAL;
 		}
-		floppy->failed_pc=NULL;
+		floppy->failed_pc = NULL;
 		pc->callback(drive);
 		return ide_stopped;
 	}
 #if IDEFLOPPY_DEBUG_LOG
-	printk (KERN_INFO "Retry number - %d\n",pc->retries);
+	printk (KERN_INFO "Retry number - %d\n", pc->retries);
 #endif /* IDEFLOPPY_DEBUG_LOG */
 
 	pc->retries++;
-	pc->actually_transferred=0;					/* We haven't transferred any data yet */
-	pc->current_position=pc->buffer;
+	/* We haven't transferred any data yet */
+	pc->actually_transferred = 0;
+	pc->current_position = pc->buffer;
 	bcount.all = IDE_MIN(pc->request_transfer, 63 * 1024);
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
-		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
+	if (test_and_clear_bit(PC_DMA_ERROR, &pc->flags)) {
+		(void) HWIF(drive)->ide_dma_off(drive);
+	}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+	feature.all = 0;
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma) {
+		if (test_bit(PC_WRITING, &pc->flags)) {
+			feature.b.dma = !HWIF(drive)->ide_dma_write(drive);
+		} else {
+			feature.b.dma = !HWIF(drive)->ide_dma_read(drive);
+		}
 	}
-	if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
-		dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
 	if (IDE_CONTROL_REG)
-		OUT_BYTE (drive->ctl,IDE_CONTROL_REG);
-	OUT_BYTE (dma_ok ? 1:0,IDE_FEATURE_REG);			/* Use PIO/DMA */
-	OUT_BYTE (bcount.b.high,IDE_BCOUNTH_REG);
-	OUT_BYTE (bcount.b.low,IDE_BCOUNTL_REG);
-	OUT_BYTE (drive->select.all,IDE_SELECT_REG);
+		HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);
+	/* Use PIO/DMA */
+	HWIF(drive)->OUTB(feature.all, IDE_FEATURE_REG);
+	HWIF(drive)->OUTB(bcount.b.high, IDE_BCOUNTH_REG);
+	HWIF(drive)->OUTB(bcount.b.low, IDE_BCOUNTL_REG);
+	HWIF(drive)->OUTB(drive->select.all, IDE_SELECT_REG);
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (dma_ok) {							/* Begin DMA, if necessary */
-		set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
-		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+	if (feature.b.dma) {	/* Begin DMA, if necessary */
+		set_bit(PC_DMA_IN_PROGRESS, &pc->flags);
+		(void) (HWIF(drive)->ide_dma_begin(drive));
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
 	/* Can we transfer the packet when we get the interrupt or wait? */
-	if (test_bit (IDEFLOPPY_ZIP_DRIVE, &floppy->flags)) {
-		pkt_xfer_routine = &idefloppy_transfer_pc1;	/* wait */
+	if (test_bit(IDEFLOPPY_ZIP_DRIVE, &floppy->flags)) {
+		/* wait */
+		pkt_xfer_routine = &idefloppy_transfer_pc1;
 	} else {
-		pkt_xfer_routine = &idefloppy_transfer_pc;	/* immediate */
+		/* immediate */
+		pkt_xfer_routine = &idefloppy_transfer_pc;
 	}
 	
-	if (test_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags)) {
-		ide_set_handler (drive, pkt_xfer_routine, IDEFLOPPY_WAIT_CMD, NULL);
-		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);		/* Issue the packet command */
+	if (test_bit(IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags)) {
+		if (HWGROUP(drive)->handler != NULL)
+			BUG();
+		ide_set_handler(drive,
+				pkt_xfer_routine,
+				IDEFLOPPY_WAIT_CMD,
+				NULL);
+		/* Issue the packet command */
+		HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG);
 		return ide_started;
 	} else {
-		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);
+		/* Issue the packet command */
+		HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG);
 		return (*pkt_xfer_routine) (drive);
 	}
 }
@@ -1177,24 +1145,25 @@
 	printk (KERN_INFO "ide-floppy: Reached idefloppy_rw_callback\n");
 #endif /* IDEFLOPPY_DEBUG_LOG */
 
-	idefloppy_end_request(1, HWGROUP(drive));
+	idefloppy_do_end_request(drive, 1);
 	return;
 }
 
 static void idefloppy_create_prevent_cmd (idefloppy_pc_t *pc, int prevent)
 {
 #if IDEFLOPPY_DEBUG_LOG
-	printk (KERN_INFO "ide-floppy: creating prevent removal command, prevent = %d\n", prevent);
+	printk(KERN_INFO "ide-floppy: creating prevent removal command, "
+		"prevent = %d\n", prevent);
 #endif /* IDEFLOPPY_DEBUG_LOG */
 
-	idefloppy_init_pc (pc);
+	idefloppy_init_pc(pc);
 	pc->c[0] = IDEFLOPPY_PREVENT_REMOVAL_CMD;
 	pc->c[4] = prevent;
 }
 
 static void idefloppy_create_read_capacity_cmd (idefloppy_pc_t *pc)
 {
-	idefloppy_init_pc (pc);
+	idefloppy_init_pc(pc);
 	pc->c[0] = IDEFLOPPY_READ_CAPACITY_CMD;
 	pc->c[7] = 255;
 	pc->c[8] = 255;
@@ -1204,13 +1173,13 @@
 static void idefloppy_create_format_unit_cmd (idefloppy_pc_t *pc, int b, int l,
 					      int flags)
 {
-	idefloppy_init_pc (pc);
+	idefloppy_init_pc(pc);
 	pc->c[0] = IDEFLOPPY_FORMAT_UNIT_CMD;
 	pc->c[1] = 0x17;
 
 	memset(pc->buffer, 0, 12);
 	pc->buffer[1] = 0xA2;
-	/* Default format list header, byte 1: FOV/DCRT/IMM bits set */
+	/* Default format list header, u8 1: FOV/DCRT/IMM bits set */
 
 	if (flags & 1)				/* Verify bit on... */
 		pc->buffer[1] ^= 0x20;		/* ... turn off DCRT bit */
@@ -1225,11 +1194,11 @@
 /*
  *	A mode sense command is used to "sense" floppy parameters.
  */
-static void idefloppy_create_mode_sense_cmd (idefloppy_pc_t *pc, byte page_code, byte type)
+static void idefloppy_create_mode_sense_cmd (idefloppy_pc_t *pc, u8 page_code, u8 type)
 {
-	unsigned short length = sizeof (idefloppy_mode_parameter_header_t);
+	u16 length = sizeof(idefloppy_mode_parameter_header_t);
 	
-	idefloppy_init_pc (pc);
+	idefloppy_init_pc(pc);
 	pc->c[0] = IDEFLOPPY_MODE_SENSE_CMD;
 	pc->c[1] = 0;
 	pc->c[2] = page_code + (type << 6);
@@ -1242,15 +1211,16 @@
 			length += 32;
 			break;
 		default:
-			printk (KERN_ERR "ide-floppy: unsupported page code in create_mode_sense_cmd\n");
+			printk(KERN_ERR "ide-floppy: unsupported page code "
+				"in create_mode_sense_cmd\n");
 	}
-	put_unaligned (htons (length), (unsigned short *) &pc->c[7]);
+	put_unaligned(htons(length), (u16 *) &pc->c[7]);
 	pc->request_transfer = length;
 }
 
 static void idefloppy_create_start_stop_cmd (idefloppy_pc_t *pc, int start)
 {
-	idefloppy_init_pc (pc);
+	idefloppy_init_pc(pc);
 	pc->c[0] = IDEFLOPPY_START_STOP_CMD;
 	pc->c[4] = start;
 }
@@ -1267,28 +1237,29 @@
 	int blocks = rq->nr_sectors / floppy->bs_factor;
 	
 #if IDEFLOPPY_DEBUG_LOG
-	printk ("create_rw1%d_cmd: block == %d, blocks == %d\n",
-		2 * test_bit (IDEFLOPPY_USE_READ12, &floppy->flags), block, blocks);
+	printk("create_rw1%d_cmd: block == %d, blocks == %d\n",
+		2 * test_bit(IDEFLOPPY_USE_READ12, &floppy->flags),
+		block, blocks);
 #endif /* IDEFLOPPY_DEBUG_LOG */
 
-	idefloppy_init_pc (pc);
-	if (test_bit (IDEFLOPPY_USE_READ12, &floppy->flags)) {
+	idefloppy_init_pc(pc);
+	if (test_bit(IDEFLOPPY_USE_READ12, &floppy->flags)) {
 		pc->c[0] = rq->cmd == READ ? IDEFLOPPY_READ12_CMD : IDEFLOPPY_WRITE12_CMD;
-		put_unaligned (htonl (blocks), (unsigned int *) &pc->c[6]);
+		put_unaligned(htonl(blocks), (unsigned int *) &pc->c[6]);
 	} else {
 		pc->c[0] = rq->cmd == READ ? IDEFLOPPY_READ10_CMD : IDEFLOPPY_WRITE10_CMD;
-		put_unaligned (htons (blocks), (unsigned short *) &pc->c[7]);
+		put_unaligned(htons(blocks), (u16 *) &pc->c[7]);
 	}
-	put_unaligned (htonl (block), (unsigned int *) &pc->c[2]);
+	put_unaligned(htonl(block), (unsigned int *) &pc->c[2]);
 	pc->callback = &idefloppy_rw_callback;
 	pc->rq = rq;
 	pc->b_data = rq->buffer;
 	pc->b_count = rq->cmd == READ ? 0 : rq->bh->b_size;
 	if (rq->cmd == WRITE)
-		set_bit (PC_WRITING, &pc->flags);
+		set_bit(PC_WRITING, &pc->flags);
 	pc->buffer = NULL;
 	pc->request_transfer = pc->buffer_size = blocks * floppy->block_size;
-	set_bit (PC_DMA_RECOMMENDED, &pc->flags);
+	set_bit(PC_DMA_RECOMMENDED, &pc->flags);
 }
 
 /*
@@ -1300,40 +1271,49 @@
 	idefloppy_pc_t *pc;
 
 #if IDEFLOPPY_DEBUG_LOG
-	printk (KERN_INFO "rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->cmd,rq->errors);
-	printk (KERN_INFO "sector: %ld, nr_sectors: %ld, current_nr_sectors: %ld\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors);
+	printk(KERN_INFO "rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",
+		rq->rq_status, (unsigned int) rq->rq_dev, rq->cmd, rq->errors);
+	printk(KERN_INFO "sector: %ld, nr_sectors: %ld, "
+			"current_nr_sectors: %ld\n", rq->sector,
+			rq->nr_sectors, rq->current_nr_sectors);
 #endif /* IDEFLOPPY_DEBUG_LOG */
 
 	if (rq->errors >= ERROR_MAX) {
 		if (floppy->failed_pc != NULL)
-			printk (KERN_ERR "ide-floppy: %s: I/O error, pc = %2x, key = %2x, asc = %2x, ascq = %2x\n",
-				drive->name, floppy->failed_pc->c[0], floppy->sense_key, floppy->asc, floppy->ascq);
+			printk(KERN_ERR "ide-floppy: %s: I/O error, pc = %2x,"
+					" key = %2x, asc = %2x, ascq = %2x\n",
+				drive->name, floppy->failed_pc->c[0],
+				floppy->sense_key, floppy->asc, floppy->ascq);
 		else
-			printk (KERN_ERR "ide-floppy: %s: I/O error\n", drive->name);
-		idefloppy_end_request (0, HWGROUP(drive));
+			printk(KERN_ERR "ide-floppy: %s: I/O error\n",
+				drive->name);
+		idefloppy_do_end_request(drive, 0);
 		return ide_stopped;
 	}
 	switch (rq->cmd) {
 		case READ:
 		case WRITE:
-			if (rq->sector % floppy->bs_factor || rq->nr_sectors % floppy->bs_factor) {
-				printk ("%s: unsupported r/w request size\n", drive->name);
-				idefloppy_end_request (0, HWGROUP(drive));
+			if (rq->sector % floppy->bs_factor ||
+			    rq->nr_sectors % floppy->bs_factor) {
+				printk("%s: unsupported r/w request size\n",
+					drive->name);
+				idefloppy_do_end_request(drive, 0);
 				return ide_stopped;
 			}
-			pc = idefloppy_next_pc_storage (drive);
-			idefloppy_create_rw_cmd (floppy, pc, rq, block);
+			pc = idefloppy_next_pc_storage(drive);
+			idefloppy_create_rw_cmd(floppy, pc, rq, block);
 			break;
 		case IDEFLOPPY_PC_RQ:
 			pc = (idefloppy_pc_t *) rq->buffer;
 			break;
 		default:
-			printk (KERN_ERR "ide-floppy: unsupported command %x in request queue\n", rq->cmd);
-			idefloppy_end_request (0,HWGROUP (drive));
+			printk(KERN_ERR "ide-floppy: unsupported command %x"
+				" in request queue\n", rq->cmd);
+			idefloppy_do_end_request(drive, 0);
 			return ide_stopped;
 	}
 	pc->rq = rq;
-	return idefloppy_issue_pc (drive, pc);
+	return idefloppy_issue_pc(drive, pc);
 }
 
 /*
@@ -1344,10 +1324,10 @@
 {
 	struct request rq;
 
-	ide_init_drive_cmd (&rq);
+	ide_init_drive_cmd(&rq);
 	rq.buffer = (char *) pc;
 	rq.cmd = IDEFLOPPY_PC_RQ;
-	return ide_do_drive_cmd (drive, &rq, ide_wait);
+	return ide_do_drive_cmd(drive, &rq, ide_wait);
 }
 
 /*
@@ -1362,23 +1342,26 @@
 	idefloppy_flexible_disk_page_t *page;
 	int capacity, lba_capacity;
 
-	idefloppy_create_mode_sense_cmd (&pc, IDEFLOPPY_FLEXIBLE_DISK_PAGE, MODE_SENSE_CURRENT);
-	if (idefloppy_queue_pc_tail (drive,&pc)) {
-		printk (KERN_ERR "ide-floppy: Can't get flexible disk page parameters\n");
+	idefloppy_create_mode_sense_cmd(&pc, IDEFLOPPY_FLEXIBLE_DISK_PAGE, MODE_SENSE_CURRENT);
+	if (idefloppy_queue_pc_tail(drive,&pc)) {
+		printk(KERN_ERR "ide-floppy: Can't get flexible disk "
+			"page parameters\n");
 		return 1;
 	}
 	header = (idefloppy_mode_parameter_header_t *) pc.buffer;
 	floppy->wp = header->wp;
 	page = (idefloppy_flexible_disk_page_t *) (header + 1);
 
-	page->transfer_rate = ntohs (page->transfer_rate);
-	page->sector_size = ntohs (page->sector_size);
-	page->cyls = ntohs (page->cyls);
-	page->rpm = ntohs (page->rpm);
+	page->transfer_rate = ntohs(page->transfer_rate);
+	page->sector_size = ntohs(page->sector_size);
+	page->cyls = ntohs(page->cyls);
+	page->rpm = ntohs(page->rpm);
 	capacity = page->cyls * page->heads * page->sectors * page->sector_size;
 	if (memcmp (page, &floppy->flexible_disk_page, sizeof (idefloppy_flexible_disk_page_t)))
-		printk (KERN_INFO "%s: %dkB, %d/%d/%d CHS, %d kBps, %d sector size, %d rpm\n",
-			drive->name, capacity / 1024, page->cyls, page->heads, page->sectors,
+		printk(KERN_INFO "%s: %dkB, %d/%d/%d CHS, %d kBps, "
+				"%d sector size, %d rpm\n",
+			drive->name, capacity / 1024, page->cyls,
+			page->heads, page->sectors,
 			page->transfer_rate / 8, page->sector_size, page->rpm);
 
 	floppy->flexible_disk_page = *page;
@@ -1387,8 +1370,8 @@
 	drive->bios_sect = page->sectors;
 	lba_capacity = floppy->blocks * floppy->block_size;
 	if (capacity < lba_capacity) {
-		printk (KERN_NOTICE "%s: The disk reports a capacity of %d bytes, "
-			"but the drive only handles %d\n",
+		printk(KERN_NOTICE "%s: The disk reports a capacity of %d "
+			"bytes, but the drive only handles %d\n",
 			drive->name, lba_capacity, capacity);
 		floppy->blocks = floppy->block_size ? capacity / floppy->block_size : 0;
 	}
@@ -1402,18 +1385,18 @@
 	idefloppy_mode_parameter_header_t *header;
 	idefloppy_capabilities_page_t *page;
 
-	floppy->srfp=0;
-	idefloppy_create_mode_sense_cmd (&pc, IDEFLOPPY_CAPABILITIES_PAGE,
+	floppy->srfp = 0;
+	idefloppy_create_mode_sense_cmd(&pc, IDEFLOPPY_CAPABILITIES_PAGE,
 						 MODE_SENSE_CURRENT);
 
 	set_bit(PC_SUPPRESS_ERROR, &pc.flags);
-	if (idefloppy_queue_pc_tail (drive,&pc)) {
+	if (idefloppy_queue_pc_tail(drive,&pc)) {
 		return 1;
 	}
 
 	header = (idefloppy_mode_parameter_header_t *) pc.buffer;
 	page= (idefloppy_capabilities_page_t *)(header+1);
-	floppy->srfp=page->srfp;
+	floppy->srfp = page->srfp;
 	return (0);
 }
 
@@ -1434,58 +1417,76 @@
 	floppy->blocks = floppy->bs_factor = 0;
 	drive->part[0].nr_sects = 0;
 
-	idefloppy_create_read_capacity_cmd (&pc);
-	if (idefloppy_queue_pc_tail (drive, &pc)) {
-		printk (KERN_ERR "ide-floppy: Can't get floppy parameters\n");
+	idefloppy_create_read_capacity_cmd(&pc);
+	if (idefloppy_queue_pc_tail(drive, &pc)) {
+		printk(KERN_ERR "ide-floppy: Can't get floppy parameters\n");
 		return 1;
 	}
 	header = (idefloppy_capacity_header_t *) pc.buffer;
-	descriptors = header->length / sizeof (idefloppy_capacity_descriptor_t);
+	descriptors = header->length / sizeof(idefloppy_capacity_descriptor_t);
 	descriptor = (idefloppy_capacity_descriptor_t *) (header + 1);
 
 	for (i = 0; i < descriptors; i++, descriptor++) {
-                blocks = descriptor->blocks = ntohl (descriptor->blocks);
-                length = descriptor->length = ntohs (descriptor->length);
+		blocks = descriptor->blocks = ntohl(descriptor->blocks);
+		length = descriptor->length = ntohs(descriptor->length);
 
 		if (!i) 
 		{
-          	switch (descriptor->dc) {
-                case CAPACITY_UNFORMATTED: /* Clik! drive returns this instead of CAPACITY_CURRENT */
-                        if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags))
-                                break; /* If it is not a clik drive, break out (maintains previous driver behaviour) */
-                case CAPACITY_CURRENT: /* Normal Zip/LS-120 disks */
-                        if (memcmp (descriptor, &floppy->capacity, sizeof (idefloppy_capacity_descriptor_t)))
-                                printk (KERN_INFO "%s: %dkB, %d blocks, %d sector size\n", drive->name, blocks * length / 1024, blocks, length);
-                        floppy->capacity = *descriptor;
-                        if (!length || length % 512)
-                                printk (KERN_NOTICE "%s: %d bytes block size not supported\n", drive->name, length);
-                        else {
+		switch (descriptor->dc) {
+		/* Clik! drive returns this instead of CAPACITY_CURRENT */
+		case CAPACITY_UNFORMATTED:
+			if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags))
+                                /*
+				 * If it is not a clik drive, break out
+				 * (maintains previous driver behaviour)
+				 */
+				break;
+		case CAPACITY_CURRENT:
+			/* Normal Zip/LS-120 disks */
+			if (memcmp(descriptor, &floppy->capacity, sizeof (idefloppy_capacity_descriptor_t)))
+				printk(KERN_INFO "%s: %dkB, %d blocks, %d "
+					"sector size\n", drive->name,
+					blocks * length / 1024, blocks, length);
+			floppy->capacity = *descriptor;
+			if (!length || length % 512) {
+				printk(KERN_NOTICE "%s: %d bytes block size "
+					"not supported\n", drive->name, length);
+			} else {
                                 floppy->blocks = blocks;
                                 floppy->block_size = length;
                                 if ((floppy->bs_factor = length / 512) != 1)
-                                        printk (KERN_NOTICE "%s: warning: non 512 bytes block size not fully supported\n", drive->name);
+                                        printk(KERN_NOTICE "%s: warning: non "
+						"512 bytes block size not "
+						"fully supported\n",
+						drive->name);
                                 rc = 0;
-                        }
-                        break;
-                case CAPACITY_NO_CARTRIDGE:
-                        /* This is a KERN_ERR so it appears on screen for the user to see */
-                        printk (KERN_ERR "%s: No disk in drive\n", drive->name);
-                                        break;
-                case CAPACITY_INVALID:
-                        printk (KERN_ERR "%s: Invalid capacity for disk in drive\n", drive->name);
-                                        break;
+			}
+			break;
+		case CAPACITY_NO_CARTRIDGE:
+			/*
+			 * This is a KERN_ERR so it appears on screen
+			 * for the user to see
+			 */
+			printk(KERN_ERR "%s: No disk in drive\n", drive->name);
+			break;
+		case CAPACITY_INVALID:
+			printk(KERN_ERR "%s: Invalid capacity for disk "
+				"in drive\n", drive->name);
+			break;
 		}
 		}
 		if (!i) {
-		IDEFLOPPY_DEBUG( "Descriptor 0 Code: %d\n", descriptor->dc);
+			IDEFLOPPY_DEBUG( "Descriptor 0 Code: %d\n",
+				descriptor->dc);
 		}
-		IDEFLOPPY_DEBUG( "Descriptor %d: %dkB, %d blocks, %d sector size\n", i, blocks * length / 1024, blocks, length);
+		IDEFLOPPY_DEBUG( "Descriptor %d: %dkB, %d blocks, %d "
+			"sector size\n", i, blocks * length / 1024, blocks,
+			length);
 	}
 
 	/* Clik! disk does not support get_flexible_disk_page */
-        if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags))
-	{
-		(void) idefloppy_get_flexible_disk_page (drive);
+        if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) {
+		(void) idefloppy_get_flexible_disk_page(drive);
 	}
 
 	drive->part[0].nr_sects = floppy->blocks * floppy->bs_factor;
@@ -1532,18 +1533,18 @@
 	if (u_array_size <= 0)
 		return (-EINVAL);
 
-	idefloppy_create_read_capacity_cmd (&pc);
-	if (idefloppy_queue_pc_tail (drive, &pc)) {
-		printk (KERN_ERR "ide-floppy: Can't get floppy parameters\n");
+	idefloppy_create_read_capacity_cmd(&pc);
+	if (idefloppy_queue_pc_tail(drive, &pc)) {
+		printk(KERN_ERR "ide-floppy: Can't get floppy parameters\n");
                 return (-EIO);
         }
         header = (idefloppy_capacity_header_t *) pc.buffer;
         descriptors = header->length /
-		sizeof (idefloppy_capacity_descriptor_t);
+		sizeof(idefloppy_capacity_descriptor_t);
 	descriptor = (idefloppy_capacity_descriptor_t *) (header + 1);
 
-	u_index=0;
-	argp=arg+1;
+	u_index = 0;
+	argp = arg + 1;
 
 	/*
 	** We always skip the first capacity descriptor.  That's the
@@ -1551,18 +1552,17 @@
 	** the formattable capacities.
 	*/
 
-	for (i=0; i<descriptors; i++, descriptor++)
-	{
+	for (i=0; i<descriptors; i++, descriptor++) {
 		if (u_index >= u_array_size)
 			break;	/* User-supplied buffer too small */
 		if (i == 0)
 			continue;	/* Skip the first descriptor */
 
-		blocks = ntohl (descriptor->blocks);
-		length = ntohs (descriptor->length);
+		blocks = ntohl(descriptor->blocks);
+		length = ntohs(descriptor->length);
 
 		if (put_user(blocks, argp))
-			return (-EFAULT);
+			return(-EFAULT);
 		++argp;
 
 		if (put_user(length, argp))
@@ -1603,19 +1603,19 @@
 	int flags;
 	idefloppy_pc_t pc;
 
-	if (get_user(blocks, arg)
-	    || get_user(length, arg+1)
-	    || get_user(flags, arg+2))
-	{
+	if (get_user(blocks, arg) ||
+	    get_user(length, arg+1) ||
+	    get_user(flags, arg+2)) {
 		return (-EFAULT);
 	}
 
-	(void) idefloppy_get_capability_page (drive);	/* Get the SFRP bit */
+	/* Get the SFRP bit */
+	(void) idefloppy_get_capability_page(drive);
 	idefloppy_create_format_unit_cmd(&pc, blocks, length, flags);
-	if (idefloppy_queue_pc_tail (drive, &pc))
-	{
+	if (idefloppy_queue_pc_tail(drive, &pc)) {
                 return (-EIO);
-        }
+	}
+
 	return (0);
 }
 
@@ -1636,35 +1636,30 @@
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	idefloppy_pc_t pc;
-	int progress_indication=0x10000;
+	int progress_indication = 0x10000;
 
-	if (floppy->srfp)
-	{
+	if (floppy->srfp) {
 		idefloppy_create_request_sense_cmd(&pc);
-		if (idefloppy_queue_pc_tail (drive, &pc))
-		{
+		if (idefloppy_queue_pc_tail(drive, &pc)) {
 			return (-EIO);
 		}
 
-		if (floppy->sense_key == 2 && floppy->asc == 4 &&
-		    floppy->ascq == 4)
-		{
-			progress_indication=floppy->progress_indication;
+		if (floppy->sense_key == 2 &&
+		    floppy->asc == 4 &&
+		    floppy->ascq == 4) {
+			progress_indication = floppy->progress_indication;
 		}
 		/* Else assume format_unit has finished, and we're
 		** at 0x10000 */
-	}
-	else
-	{
-		idefloppy_status_reg_t status;
+	} else {
+		atapi_status_t status;
 		unsigned long flags;
 
-		__save_flags(flags);
-		__cli();
-		status.all=GET_STAT();
-		__restore_flags(flags);
+		local_irq_save(flags);
+		status.all = HWIF(drive)->INB(IDE_STATUS_REG);
+		local_irq_restore(flags);
 
-		progress_indication= !status.b.dsc ? 0:0x10000;
+		progress_indication = !status.b.dsc ? 0 : 0x10000;
 	}
 	if (put_user(progress_indication, arg))
 		return (-EFAULT);
@@ -1694,12 +1689,12 @@
 
 		/* The IOMEGA Clik! Drive doesn't support this command - no room for an eject mechanism */
                 if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) {
-			idefloppy_create_prevent_cmd (&pc, prevent);
-			(void) idefloppy_queue_pc_tail (drive, &pc);
+			idefloppy_create_prevent_cmd(&pc, prevent);
+			(void) idefloppy_queue_pc_tail(drive, &pc);
 		}
 		if (cmd == CDROMEJECT) {
-			idefloppy_create_start_stop_cmd (&pc, 2);
-			(void) idefloppy_queue_pc_tail (drive, &pc);
+			idefloppy_create_start_stop_cmd(&pc, 2);
+			(void) idefloppy_queue_pc_tail(drive, &pc);
 		}
 		return 0;
 	case IDEFLOPPY_IOCTL_FORMAT_SUPPORTED:
@@ -1715,16 +1710,13 @@
 		{
 			idefloppy_floppy_t *floppy = drive->driver_data;
 
-			if (drive->usage > 1)
-			{
+			if (drive->usage > 1) {
 				/* Don't format if someone is using the disk */
 
 				clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS,
 					  &floppy->flags);
 				return -EBUSY;
-			}
-			else
-			{
+			} else {
 				int rc;
 
 				set_bit(IDEFLOPPY_FORMAT_IN_PROGRESS,
@@ -1763,7 +1755,7 @@
 	idefloppy_pc_t pc;
 	
 #if IDEFLOPPY_DEBUG_LOG
-	printk (KERN_INFO "Reached idefloppy_open\n");
+	printk(KERN_INFO "Reached idefloppy_open\n");
 #endif /* IDEFLOPPY_DEBUG_LOG */
 
 	MOD_INC_USE_COUNT;
@@ -1773,8 +1765,8 @@
 
 		idefloppy_create_test_unit_ready_cmd(&pc);
 		if (idefloppy_queue_pc_tail(drive, &pc)) {
-			idefloppy_create_start_stop_cmd (&pc, 1);
-			(void) idefloppy_queue_pc_tail (drive, &pc);
+			idefloppy_create_start_stop_cmd(&pc, 1);
+			(void) idefloppy_queue_pc_tail(drive, &pc);
 		}
 
 		if (idefloppy_get_capacity (drive)
@@ -1795,16 +1787,14 @@
 			MOD_DEC_USE_COUNT;
 			return -EROFS;
 		}		
-		set_bit (IDEFLOPPY_MEDIA_CHANGED, &floppy->flags);
+		set_bit(IDEFLOPPY_MEDIA_CHANGED, &floppy->flags);
 		/* IOMEGA Clik! drives do not support lock/unlock commands */
                 if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) {
-			idefloppy_create_prevent_cmd (&pc, 1);
-			(void) idefloppy_queue_pc_tail (drive, &pc);
+			idefloppy_create_prevent_cmd(&pc, 1);
+			(void) idefloppy_queue_pc_tail(drive, &pc);
 		}
 		check_disk_change(inode->i_rdev);
-	}
-	else if (test_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags))
-	{
+	} else if (test_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags)) {
 		drive->usage--;
 		MOD_DEC_USE_COUNT;
 		return -EBUSY;
@@ -1823,12 +1813,12 @@
 	if (!drive->usage) {
 		idefloppy_floppy_t *floppy = drive->driver_data;
 
-		invalidate_bdev (inode->i_bdev, 0);
+		invalidate_bdev(inode->i_bdev, 0);
 
 		/* IOMEGA Clik! drives do not support lock/unlock commands */
                 if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) {
-			idefloppy_create_prevent_cmd (&pc, 0);
-			(void) idefloppy_queue_pc_tail (drive, &pc);
+			idefloppy_create_prevent_cmd(&pc, 0);
+			(void) idefloppy_queue_pc_tail(drive, &pc);
 		}
 
 		clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags);
@@ -1843,7 +1833,7 @@
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	
-	return test_and_clear_bit (IDEFLOPPY_MEDIA_CHANGED, &floppy->flags);
+	return test_and_clear_bit(IDEFLOPPY_MEDIA_CHANGED, &floppy->flags);
 }
 
 /*
@@ -1875,109 +1865,114 @@
 {
 	struct idefloppy_id_gcw gcw;
 #if IDEFLOPPY_DEBUG_INFO
-	unsigned short mask,i;
+	u16 mask,i;
 	char buffer[80];
 #endif /* IDEFLOPPY_DEBUG_INFO */
 
-	*((unsigned short *) &gcw) = id->config;
+	*((u16 *) &gcw) = id->config;
 
 #ifdef CONFIG_PPC
 	/* kludge for Apple PowerBook internal zip */
-	if ((gcw.device_type == 5) && !strstr(id->model, "CD-ROM")
-	    && strstr(id->model, "ZIP"))
+	if ((gcw.device_type == 5) &&
+	    !strstr(id->model, "CD-ROM") &&
+	    strstr(id->model, "ZIP"))
 		gcw.device_type = 0;			
 #endif
 
 #if IDEFLOPPY_DEBUG_INFO
-	printk (KERN_INFO "Dumping ATAPI Identify Device floppy parameters\n");
+	printk(KERN_INFO "Dumping ATAPI Identify Device floppy parameters\n");
 	switch (gcw.protocol) {
-		case 0: case 1: sprintf (buffer, "ATA");break;
-		case 2:	sprintf (buffer, "ATAPI");break;
-		case 3: sprintf (buffer, "Reserved (Unknown to ide-floppy)");break;
+		case 0: case 1: sprintf(buffer, "ATA");break;
+		case 2:	sprintf(buffer, "ATAPI");break;
+		case 3: sprintf(buffer, "Reserved (Unknown to ide-floppy)");break;
 	}
-	printk (KERN_INFO "Protocol Type: %s\n", buffer);
+	printk(KERN_INFO "Protocol Type: %s\n", buffer);
 	switch (gcw.device_type) {
-		case 0: sprintf (buffer, "Direct-access Device");break;
-		case 1: sprintf (buffer, "Streaming Tape Device");break;
+		case 0: sprintf(buffer, "Direct-access Device");break;
+		case 1: sprintf(buffer, "Streaming Tape Device");break;
 		case 2: case 3: case 4: sprintf (buffer, "Reserved");break;
-		case 5: sprintf (buffer, "CD-ROM Device");break;
-		case 6: sprintf (buffer, "Reserved");
-		case 7: sprintf (buffer, "Optical memory Device");break;
-		case 0x1f: sprintf (buffer, "Unknown or no Device type");break;
-		default: sprintf (buffer, "Reserved");
+		case 5: sprintf(buffer, "CD-ROM Device");break;
+		case 6: sprintf(buffer, "Reserved");
+		case 7: sprintf(buffer, "Optical memory Device");break;
+		case 0x1f: sprintf(buffer, "Unknown or no Device type");break;
+		default: sprintf(buffer, "Reserved");
 	}
-	printk (KERN_INFO "Device Type: %x - %s\n", gcw.device_type, buffer);
-	printk (KERN_INFO "Removable: %s\n",gcw.removable ? "Yes":"No");	
+	printk(KERN_INFO "Device Type: %x - %s\n", gcw.device_type, buffer);
+	printk(KERN_INFO "Removable: %s\n",gcw.removable ? "Yes":"No");	
 	switch (gcw.drq_type) {
-		case 0: sprintf (buffer, "Microprocessor DRQ");break;
-		case 1: sprintf (buffer, "Interrupt DRQ");break;
-		case 2: sprintf (buffer, "Accelerated DRQ");break;
-		case 3: sprintf (buffer, "Reserved");break;
+		case 0: sprintf(buffer, "Microprocessor DRQ");break;
+		case 1: sprintf(buffer, "Interrupt DRQ");break;
+		case 2: sprintf(buffer, "Accelerated DRQ");break;
+		case 3: sprintf(buffer, "Reserved");break;
 	}
-	printk (KERN_INFO "Command Packet DRQ Type: %s\n", buffer);
+	printk(KERN_INFO "Command Packet DRQ Type: %s\n", buffer);
 	switch (gcw.packet_size) {
-		case 0: sprintf (buffer, "12 bytes");break;
-		case 1: sprintf (buffer, "16 bytes");break;
-		default: sprintf (buffer, "Reserved");break;
-	}
-	printk (KERN_INFO "Command Packet Size: %s\n", buffer);
-	printk (KERN_INFO "Model: %.40s\n",id->model);
-	printk (KERN_INFO "Firmware Revision: %.8s\n",id->fw_rev);
-	printk (KERN_INFO "Serial Number: %.20s\n",id->serial_no);
-	printk (KERN_INFO "Write buffer size(?): %d bytes\n",id->buf_size*512);
-	printk (KERN_INFO "DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n");
-	printk (KERN_INFO "LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n");
-	printk (KERN_INFO "IORDY can be disabled: %s",id->capability & 0x04 ? "Yes\n":"No\n");
-	printk (KERN_INFO "IORDY supported: %s",id->capability & 0x08 ? "Yes\n":"Unknown\n");
-	printk (KERN_INFO "ATAPI overlap supported: %s",id->capability & 0x20 ? "Yes\n":"No\n");
-	printk (KERN_INFO "PIO Cycle Timing Category: %d\n",id->tPIO);
-	printk (KERN_INFO "DMA Cycle Timing Category: %d\n",id->tDMA);
-	printk (KERN_INFO "Single Word DMA supported modes:\n");
+		case 0: sprintf(buffer, "12 bytes");break;
+		case 1: sprintf(buffer, "16 bytes");break;
+		default: sprintf(buffer, "Reserved");break;
+	}
+	printk(KERN_INFO "Command Packet Size: %s\n", buffer);
+	printk(KERN_INFO "Model: %.40s\n",id->model);
+	printk(KERN_INFO "Firmware Revision: %.8s\n",id->fw_rev);
+	printk(KERN_INFO "Serial Number: %.20s\n",id->serial_no);
+	printk(KERN_INFO "Write buffer size(?): %d bytes\n",id->buf_size*512);
+	printk(KERN_INFO "DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n");
+	printk(KERN_INFO "LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n");
+	printk(KERN_INFO "IORDY can be disabled: %s",id->capability & 0x04 ? "Yes\n":"No\n");
+	printk(KERN_INFO "IORDY supported: %s",id->capability & 0x08 ? "Yes\n":"Unknown\n");
+	printk(KERN_INFO "ATAPI overlap supported: %s",id->capability & 0x20 ? "Yes\n":"No\n");
+	printk(KERN_INFO "PIO Cycle Timing Category: %d\n",id->tPIO);
+	printk(KERN_INFO "DMA Cycle Timing Category: %d\n",id->tDMA);
+	printk(KERN_INFO "Single Word DMA supported modes:\n");
 	for (i=0,mask=1;i<8;i++,mask=mask << 1) {
 		if (id->dma_1word & mask)
-			printk (KERN_INFO "   Mode %d%s\n", i, (id->dma_1word & (mask << 8)) ? " (active)" : "");
+			printk(KERN_INFO "   Mode %d%s\n", i,
+			(id->dma_1word & (mask << 8)) ? " (active)" : "");
 	}
-	printk (KERN_INFO "Multi Word DMA supported modes:\n");
+	printk(KERN_INFO "Multi Word DMA supported modes:\n");
 	for (i=0,mask=1;i<8;i++,mask=mask << 1) {
 		if (id->dma_mword & mask)
-			printk (KERN_INFO "   Mode %d%s\n", i, (id->dma_mword & (mask << 8)) ? " (active)" : "");
+			printk(KERN_INFO "   Mode %d%s\n", i,
+			(id->dma_mword & (mask << 8)) ? " (active)" : "");
 	}
 	if (id->field_valid & 0x0002) {
-		printk (KERN_INFO "Enhanced PIO Modes: %s\n",id->eide_pio_modes & 1 ? "Mode 3":"None");
+		printk(KERN_INFO "Enhanced PIO Modes: %s\n",
+			id->eide_pio_modes & 1 ? "Mode 3":"None");
 		if (id->eide_dma_min == 0)
-			sprintf (buffer, "Not supported");
+			sprintf(buffer, "Not supported");
 		else
-			sprintf (buffer, "%d ns",id->eide_dma_min);
-		printk (KERN_INFO "Minimum Multi-word DMA cycle per word: %s\n", buffer);
+			sprintf(buffer, "%d ns",id->eide_dma_min);
+		printk(KERN_INFO "Minimum Multi-word DMA cycle per word: %s\n", buffer);
 		if (id->eide_dma_time == 0)
-			sprintf (buffer, "Not supported");
+			sprintf(buffer, "Not supported");
 		else
-			sprintf (buffer, "%d ns",id->eide_dma_time);
-		printk (KERN_INFO "Manufacturer\'s Recommended Multi-word cycle: %s\n", buffer);
+			sprintf(buffer, "%d ns",id->eide_dma_time);
+		printk(KERN_INFO "Manufacturer\'s Recommended Multi-word cycle: %s\n", buffer);
 		if (id->eide_pio == 0)
-			sprintf (buffer, "Not supported");
+			sprintf(buffer, "Not supported");
 		else
-			sprintf (buffer, "%d ns",id->eide_pio);
-		printk (KERN_INFO "Minimum PIO cycle without IORDY: %s\n", buffer);
+			sprintf(buffer, "%d ns",id->eide_pio);
+		printk(KERN_INFO "Minimum PIO cycle without IORDY: %s\n",
+			buffer);
 		if (id->eide_pio_iordy == 0)
-			sprintf (buffer, "Not supported");
+			sprintf(buffer, "Not supported");
 		else
-			sprintf (buffer, "%d ns",id->eide_pio_iordy);
-		printk (KERN_INFO "Minimum PIO cycle with IORDY: %s\n", buffer);
+			sprintf(buffer, "%d ns",id->eide_pio_iordy);
+		printk(KERN_INFO "Minimum PIO cycle with IORDY: %s\n", buffer);
 	} else
-		printk (KERN_INFO "According to the device, fields 64-70 are not valid.\n");
+		printk(KERN_INFO "According to the device, fields 64-70 are not valid.\n");
 #endif /* IDEFLOPPY_DEBUG_INFO */
 
 	if (gcw.protocol != 2)
-		printk (KERN_ERR "ide-floppy: Protocol is not ATAPI\n");
+		printk(KERN_ERR "ide-floppy: Protocol is not ATAPI\n");
 	else if (gcw.device_type != 0)
-		printk (KERN_ERR "ide-floppy: Device type is not set to floppy\n");
+		printk(KERN_ERR "ide-floppy: Device type is not set to floppy\n");
 	else if (!gcw.removable)
-		printk (KERN_ERR "ide-floppy: The removable flag is not set\n");
+		printk(KERN_ERR "ide-floppy: The removable flag is not set\n");
 	else if (gcw.drq_type == 3) {
-		printk (KERN_ERR "ide-floppy: Sorry, DRQ type %d not supported\n", gcw.drq_type);
+		printk(KERN_ERR "ide-floppy: Sorry, DRQ type %d not supported\n", gcw.drq_type);
 	} else if (gcw.packet_size != 0) {
-		printk (KERN_ERR "ide-floppy: Packet size is not 12 bytes long\n");
+		printk(KERN_ERR "ide-floppy: Packet size is not 12 bytes long\n");
 	} else
 		return 1;
 	return 0;
@@ -1999,7 +1994,6 @@
 	ide_add_setting(drive,	"file_readahead",	SETTING_RW,					BLKFRAGET,		BLKFRASET,		TYPE_INTA,	0,	INT_MAX,			1,	1024,	&max_readahead[major][minor],	NULL);
 	ide_add_setting(drive,	"max_kb_per_request",	SETTING_RW,					BLKSECTGET,		BLKSECTSET,		TYPE_INTA,	1,	255,				1,	2,	&max_sectors[major][minor],	NULL);
 	ide_add_setting(drive,	"ticks",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	255,				1,	1,	&floppy->ticks,		NULL);
-
 }
 
 /*
@@ -2011,14 +2005,14 @@
 	int major = HWIF(drive)->major, i;
 	int minor = drive->select.b.unit << PARTN_BITS;
 
-	*((unsigned short *) &gcw) = drive->id->config;
+	*((u16 *) &gcw) = drive->id->config;
 	drive->driver_data = floppy;
 	drive->ready_stat = 0;
-	memset (floppy, 0, sizeof (idefloppy_floppy_t));
+	memset(floppy, 0, sizeof(idefloppy_floppy_t));
 	floppy->drive = drive;
 	floppy->pc = floppy->pc_stack;
 	if (gcw.drq_type == 1)
-		set_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags);
+		set_bit(IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags);
 	/*
 	 *	We used to check revisions here. At this point however
 	 *	I'm giving up. Just assume they are all broken, its easier.
@@ -2030,8 +2024,7 @@
 	 *	we'll leave the limitation below for the 2.2.x tree.
 	 */
 
-	if (strcmp(drive->id->model, "IOMEGA ZIP 100 ATAPI") == 0)
-	{
+	if (strcmp(drive->id->model, "IOMEGA ZIP 100 ATAPI") == 0) {
 		set_bit(IDEFLOPPY_ZIP_DRIVE, &floppy->flags);
 		/* This value will be visible in the /proc/ide/hdx/settings */
 		floppy->ticks = IDEFLOPPY_TICKS_DELAY;
@@ -2044,15 +2037,14 @@
 	*      above fix.  It makes nasty clicking noises without
 	*      it, so please don't remove this.
 	*/
-	if (strncmp(drive->id->model, "IOMEGA Clik!", 11) == 0) 
-	{
+	if (strncmp(drive->id->model, "IOMEGA Clik!", 11) == 0) {
 		for (i = 0; i < 1 << PARTN_BITS; i++)
 			max_sectors[major][minor + i] = 64;
 		set_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags);
 	}
 
 
-	(void) idefloppy_get_capacity (drive);
+	(void) idefloppy_get_capacity(drive);
 	idefloppy_add_settings(drive);
 	for (i = 0; i < MAX_DRIVES; ++i) {
 		ide_hwif_t *hwif = HWIF(drive);
@@ -2069,10 +2061,11 @@
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 
-	if (ide_unregister_subdriver (drive))
+	if (ide_unregister_subdriver(drive))
 		return 1;
+
 	drive->driver_data = NULL;
-	kfree (floppy);
+	kfree(floppy);
 	return 0;
 }
 
@@ -2089,7 +2082,8 @@
 
 #endif	/* CONFIG_PROC_FS */
 
-int idefloppy_reinit(ide_drive_t *drive);
+int idefloppy_init (void);
+int idefloppy_attach(ide_drive_t *drive);
 
 /*
  *	IDE subdriver functions, registered with ide.c
@@ -2103,9 +2097,13 @@
 	supports_dsc_overlap:	0,
 	cleanup:		idefloppy_cleanup,
 	standby:		NULL,
+	suspend:		NULL,
+	resume:			NULL,
 	flushcache:		NULL,
 	do_request:		idefloppy_do_request,
-	end_request:		idefloppy_end_request,
+	end_request:		idefloppy_do_end_request,
+	sense:			NULL,
+	error:			NULL,
 	ioctl:			idefloppy_ioctl,
 	open:			idefloppy_open,
 	release:		idefloppy_release,
@@ -2115,12 +2113,12 @@
 	capacity:		idefloppy_capacity,
 	special:		NULL,
 	proc:			idefloppy_proc,
-	reinit:			idefloppy_reinit,
+	init:			idefloppy_init,
+	attach:			idefloppy_attach,
 	ata_prebuilder:		NULL,
 	atapi_prebuilder:	NULL,
 };
 
-int idefloppy_init (void);
 static ide_module_t idefloppy_module = {
 	IDE_DRIVER_MODULE,
 	idefloppy_init,
@@ -2128,38 +2126,45 @@
 	NULL
 };
 
-int idefloppy_reinit (ide_drive_t *drive)
+int idefloppy_attach (ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy;
-	int failed = 0;
+	int ret = 0;
 
 	MOD_INC_USE_COUNT;
-	while ((drive = ide_scan_devices (ide_floppy, idefloppy_driver.name, NULL, failed++)) != NULL) {
-		if (!idefloppy_identify_device (drive, drive->id)) {
-			printk (KERN_ERR "ide-floppy: %s: not supported by this version of ide-floppy\n", drive->name);
-			continue;
-		}
-		if (drive->scsi) {
-			printk("ide-floppy: passing drive %s to ide-scsi emulation.\n", drive->name);
-			continue;
-		}
-		if ((floppy = (idefloppy_floppy_t *) kmalloc (sizeof (idefloppy_floppy_t), GFP_KERNEL)) == NULL) {
-			printk (KERN_ERR "ide-floppy: %s: Can't allocate a floppy structure\n", drive->name);
-			continue;
-		}
-		if (ide_register_subdriver (drive, &idefloppy_driver, IDE_SUBDRIVER_VERSION)) {
-			printk (KERN_ERR "ide-floppy: %s: Failed to register the driver with ide.c\n", drive->name);
-			kfree (floppy);
-			continue;
-		}
-		DRIVER(drive)->busy++;
-		idefloppy_setup (drive, floppy);
-		DRIVER(drive)->busy--;
-		failed--;
-	}
-	ide_register_module(&idefloppy_module);
+	if (!idefloppy_identify_device(drive, drive->id)) {
+		printk(KERN_ERR "ide-floppy: %s: not supported by this "
+			"version of ide-floppy\n", drive->name);
+			ret = 1;
+			goto bye_game_over;
+	}
+	if (drive->scsi) {
+		printk("ide-floppy: passing drive %s to ide-scsi "
+			"emulation.\n", drive->name);
+		ret = 1;
+		goto bye_game_over;
+	}
+	if ((floppy = (idefloppy_floppy_t *) kmalloc(sizeof (idefloppy_floppy_t), GFP_KERNEL)) == NULL) {
+		printk(KERN_ERR "ide-floppy: %s: Can't allocate a floppy "
+			"structure\n", drive->name);
+		ret = 1;
+		goto bye_game_over;
+	}
+	if (ide_register_subdriver(drive,
+			&idefloppy_driver, IDE_SUBDRIVER_VERSION)) {
+		printk(KERN_ERR "ide-floppy: %s: Failed to register the "
+			"driver with ide.c\n", drive->name);
+		kfree(floppy);
+		ret = 1;
+		goto bye_game_over;
+	}
+	DRIVER(drive)->busy++;
+	idefloppy_setup(drive, floppy);
+	DRIVER(drive)->busy--;
+
+bye_game_over:
 	MOD_DEC_USE_COUNT;
-	return 0;
+	return ret;
 }
 
 MODULE_DESCRIPTION("ATAPI FLOPPY Driver");
@@ -2169,9 +2174,11 @@
 	ide_drive_t *drive;
 	int failed = 0;
 
-	while ((drive = ide_scan_devices (ide_floppy, idefloppy_driver.name, &idefloppy_driver, failed)) != NULL) {
-		if (idefloppy_cleanup (drive)) {
-			printk ("%s: cleanup_module() called while still busy\n", drive->name);
+	while ((drive = ide_scan_devices(ide_floppy, idefloppy_driver.name,
+			&idefloppy_driver, failed)) != NULL) {
+		if (idefloppy_cleanup(drive)) {
+			printk("%s: cleanup_module() called while still "
+				"busy\n", drive->name);
 			failed++;
 		}
 		/* We must remove proc entries defined in this module.
@@ -2184,40 +2191,47 @@
 	ide_unregister_module(&idefloppy_module);
 }
 
-/*
- *	idefloppy_init will register the driver for each floppy.
- */
 int idefloppy_init (void)
 {
+#ifdef CLASSIC_BUILTINS_METHOD
 	ide_drive_t *drive;
 	idefloppy_floppy_t *floppy;
 	int failed = 0;
 
 	printk("ide-floppy driver " IDEFLOPPY_VERSION "\n");
+#endif /* CLASSIC_BUILTINS_METHOD */
 	MOD_INC_USE_COUNT;
-	while ((drive = ide_scan_devices (ide_floppy, idefloppy_driver.name, NULL, failed++)) != NULL) {
-		if (!idefloppy_identify_device (drive, drive->id)) {
-			printk (KERN_ERR "ide-floppy: %s: not supported by this version of ide-floppy\n", drive->name);
+#ifdef CLASSIC_BUILTINS_METHOD
+	while ((drive = ide_scan_devices(ide_floppy,
+			idefloppy_driver.name, NULL, failed++)) != NULL) {
+		if (!idefloppy_identify_device(drive, drive->id)) {
+			printk(KERN_ERR "ide-floppy: %s: not supported by "
+				"this version of ide-floppy\n", drive->name);
 			continue;
 		}
 		if (drive->scsi) {
-			printk("ide-floppy: passing drive %s to ide-scsi emulation.\n", drive->name);
-			continue;
-		}
-		if ((floppy = (idefloppy_floppy_t *) kmalloc (sizeof (idefloppy_floppy_t), GFP_KERNEL)) == NULL) {
-			printk (KERN_ERR "ide-floppy: %s: Can't allocate a floppy structure\n", drive->name);
+			printk("ide-floppy: passing drive %s to ide-scsi "
+				"emulation.\n", drive->name);
 			continue;
 		}
-		if (ide_register_subdriver (drive, &idefloppy_driver, IDE_SUBDRIVER_VERSION)) {
-			printk (KERN_ERR "ide-floppy: %s: Failed to register the driver with ide.c\n", drive->name);
-			kfree (floppy);
+		if ((floppy = (idefloppy_floppy_t *) kmalloc(sizeof (idefloppy_floppy_t), GFP_KERNEL)) == NULL) {
+			printk(KERN_ERR "ide-floppy: %s: Can't allocate a "
+				"floppy structure\n", drive->name);
 			continue;
 		}
+		if (ide_register_subdriver(drive,
+				&idefloppy_driver, IDE_SUBDRIVER_VERSION)) {
+			printk(KERN_ERR "ide-floppy: %s: Failed to register "
+				"the driver with ide.c\n", drive->name);
+			kfree(floppy);
+                        continue;
+                }
 		DRIVER(drive)->busy++;
-		idefloppy_setup (drive, floppy);
+		idefloppy_setup(drive, floppy);
 		DRIVER(drive)->busy--;
 		failed--;
 	}
+#endif /* CLASSIC_BUILTINS_METHOD */
 	ide_register_module(&idefloppy_module);
 	MOD_DEC_USE_COUNT;
 	return 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-geometry.c linux-2.4.21-pre6/drivers/ide/ide-geometry.c
--- linux-2.4.20/drivers/ide/ide-geometry.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/ide-geometry.c	2003-03-26 23:48:58.000000000 +0000
@@ -6,8 +6,6 @@
 #include <linux/mc146818rtc.h>
 #include <asm/io.h>
 
-#ifdef CONFIG_BLK_DEV_IDE
-
 /*
  * We query CMOS about hard disks : it could be that we have a SCSI/ESDI/etc
  * controller that is BIOS compatible with ST-506, and thus showing up in our
@@ -25,13 +23,11 @@
  * If a drive is not actually on the primary interface, then these parameters
  * will be ignored.  This results in the user having to supply the logical
  * drive geometry as a boot parameter for each drive not on the primary i/f.
- */
-/*
+ *
  * The only "perfect" way to handle this would be to modify the setup.[cS] code
  * to do BIOS calls Int13h/Fn08h and Int13h/Fn48h to get all of the drive info
  * for us during initialization.  I have the necessary docs -- any takers?  -ml
- */
-/*
+ *
  * I did this, but it doesn't work - there is no reasonable way to find the
  * correspondence between the BIOS numbering of the disks and the Linux
  * numbering. -aeb
@@ -51,14 +47,13 @@
 {
 #ifdef __i386__
 	extern struct drive_info_struct drive_info;
-	byte cmos_disks, *BIOS = (byte *) &drive_info;
+	u8 cmos_disks, *BIOS = (u8 *) &drive_info;
 	int unit;
 	unsigned long flags;
 
-#ifdef CONFIG_BLK_DEV_PDC4030
 	if (hwif->chipset == ide_pdc4030 && hwif->channel != 0)
 		return;
-#endif /* CONFIG_BLK_DEV_PDC4030 */
+
 	spin_lock_irqsave(&rtc_lock, flags);
 	cmos_disks = CMOS_READ(0x12);
 	spin_unlock_irqrestore(&rtc_lock, flags);
@@ -68,7 +63,7 @@
 
 		if ((cmos_disks & (0xf0 >> (unit*4)))
 		   && !drive->present && !drive->nobios) {
-			unsigned short cyl = *(unsigned short *)BIOS;
+			u16 cyl = *(u16 *)BIOS;
 			unsigned char head = *(BIOS+2);
 			unsigned char sect = *(BIOS+14);
 			if (cyl > 0 && head > 0 && sect > 0 && sect < 64) {
@@ -86,10 +81,7 @@
 	}
 #endif
 }
-#endif /* CONFIG_BLK_DEV_IDE */
-
 
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
 
 extern ide_drive_t * get_info_ptr(kdev_t);
 extern unsigned long current_capacity (ide_drive_t *);
@@ -98,10 +90,11 @@
  * If heads is nonzero: find a translation with this many heads and S=63.
  * Otherwise: find out how OnTrack Disk Manager would translate the disk.
  */
-static void
-ontrack(ide_drive_t *drive, int heads, unsigned int *c, int *h, int *s) {
-	static const byte dm_head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0};
-	const byte *headp = dm_head_vals;
+
+static void ontrack(ide_drive_t *drive, int heads, unsigned int *c, int *h, int *s) 
+{
+	static const u8 dm_head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0};
+	const u8 *headp = dm_head_vals;
 	unsigned long total;
 
 	/*
@@ -153,6 +146,7 @@
  * an IDE disk drive, or if a geometry was "forced" on the commandline.
  * Returns 1 if the geometry translation was successful.
  */
+
 int ide_xlate_1024 (kdev_t i_rdev, int xparm, int ptheads, const char *msg)
 {
 	ide_drive_t *drive;
@@ -217,8 +211,7 @@
 	drive->part[0].nr_sects = current_capacity(drive);
 
 	if (ret)
-		printk("%s%s [%d/%d/%d]", msg, msg1,
+		printk(KERN_INFO "%s%s [%d/%d/%d]", msg, msg1,
 		       drive->bios_cyl, drive->bios_head, drive->bios_sect);
 	return ret;
 }
-#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-io.c linux-2.4.21-pre6/drivers/ide/ide-io.c
--- linux-2.4.20/drivers/ide/ide-io.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/ide-io.c	2003-03-26 23:49:08.000000000 +0000
@@ -0,0 +1,1334 @@
+/*
+ *	IDE I/O functions
+ *
+ *	Basic PIO and command management functionality.
+ *
+ * This code was split off from ide.c. See ide.c for history and original
+ * copyrights.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * For the avoidance of doubt the "preferred form" of this code is one which
+ * is in an open non patent encumbered format. Where cryptographic key signing
+ * forms part of the process of creating an executable the information
+ * including keys needed to generate an equivalently functional executable
+ * are deemed to be part of the source code.
+ */
+ 
+ 
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/genhd.h>
+#include <linux/blkpg.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/completion.h>
+#include <linux/reboot.h>
+#include <linux/cdrom.h>
+#include <linux/seq_file.h>
+#include <linux/kmod.h>
+
+#include <asm/byteorder.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+
+#include "ide_modes.h"
+
+#if (DISK_RECOVERY_TIME > 0)
+
+Error So the User Has To Fix the Compilation And Stop Hacking Port 0x43
+Does anyone ever use this anyway ??
+
+/*
+ * For really screwy hardware (hey, at least it *can* be used with Linux)
+ * we can enforce a minimum delay time between successive operations.
+ */
+static unsigned long read_timer (ide_hwif_t *hwif)
+{
+	unsigned long t, flags;
+	int i;
+	
+	/* FIXME this is completely unsafe! */
+	local_irq_save(flags);
+	t = jiffies * 11932;
+	outb_p(0, 0x43);
+	i = inb_p(0x40);
+	i |= inb_p(0x40) << 8;
+	local_irq_restore(flags);
+	return (t - i);
+}
+#endif /* DISK_RECOVERY_TIME */
+
+static inline void set_recovery_timer (ide_hwif_t *hwif)
+{
+#if (DISK_RECOVERY_TIME > 0)
+	hwif->last_time = read_timer(hwif);
+#endif /* DISK_RECOVERY_TIME */
+}
+
+/*
+ *	ide_end_request		-	complete an IDE I/O
+ *	@drive: IDE device for the I/O
+ *	@uptodate: 
+ *
+ *	This is our end_request wrapper function. We complete the I/O
+ *	update random number input and dequeue the request.
+ */
+ 
+int ide_end_request (ide_drive_t *drive, int uptodate)
+{
+	struct request *rq;
+	unsigned long flags;
+	int ret = 1;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	rq = HWGROUP(drive)->rq;
+
+	/*
+	 * decide whether to reenable DMA -- 3 is a random magic for now,
+	 * if we DMA timeout more than 3 times, just stay in PIO
+	 */
+	if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
+		drive->state = 0;
+		HWGROUP(drive)->hwif->ide_dma_on(drive);
+	}
+
+	if (!end_that_request_first(rq, uptodate, drive->name)) {
+		add_blkdev_randomness(MAJOR(rq->rq_dev));
+		blkdev_dequeue_request(rq);
+		HWGROUP(drive)->rq = NULL;
+		end_that_request_last(rq);
+		ret = 0;
+	}
+
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	return ret;
+}
+
+EXPORT_SYMBOL(ide_end_request);
+
+/**
+ *	ide_end_drive_cmd	-	end an explicit drive command
+ *	@drive: command 
+ *	@stat: status bits
+ *	@err: error bits
+ *
+ *	Clean up after success/failure of an explicit drive command.
+ *	These get thrown onto the queue so they are synchronized with
+ *	real I/O operations on the drive.
+ *
+ *	In LBA48 mode we have to read the register set twice to get
+ *	all the extra information out.
+ */
+ 
+void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	unsigned long flags;
+	struct request *rq;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	rq = HWGROUP(drive)->rq;
+	spin_unlock_irqrestore(&io_request_lock, flags);
+
+	switch(rq->cmd) {
+		case IDE_DRIVE_CMD:
+		{
+			u8 *args = (u8 *) rq->buffer;
+			if (rq->errors == 0)
+				rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
+
+			if (args) {
+				args[0] = stat;
+				args[1] = err;
+				args[2] = hwif->INB(IDE_NSECTOR_REG);
+			}
+			break;
+		}
+		case IDE_DRIVE_TASK:
+		{
+			u8 *args = (u8 *) rq->buffer;
+			if (rq->errors == 0)
+				rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
+
+			if (args) {
+				args[0] = stat;
+				args[1] = err;
+				args[2] = hwif->INB(IDE_NSECTOR_REG);
+				args[3] = hwif->INB(IDE_SECTOR_REG);
+				args[4] = hwif->INB(IDE_LCYL_REG);
+				args[5] = hwif->INB(IDE_HCYL_REG);
+				args[6] = hwif->INB(IDE_SELECT_REG);
+			}
+			break;
+		}
+		case IDE_DRIVE_TASKFILE:
+		{
+			ide_task_t *args = (ide_task_t *) rq->special;
+			if (rq->errors == 0)
+				rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
+				
+			if (args) {
+				if (args->tf_in_flags.b.data) {
+					u16 data			= hwif->INW(IDE_DATA_REG);
+					args->tfRegister[IDE_DATA_OFFSET]	= (data) & 0xFF;
+					args->hobRegister[IDE_DATA_OFFSET_HOB]	= (data >> 8) & 0xFF;
+				}
+				args->tfRegister[IDE_ERROR_OFFSET]   = err;
+				args->tfRegister[IDE_NSECTOR_OFFSET] = hwif->INB(IDE_NSECTOR_REG);
+				args->tfRegister[IDE_SECTOR_OFFSET]  = hwif->INB(IDE_SECTOR_REG);
+				args->tfRegister[IDE_LCYL_OFFSET]    = hwif->INB(IDE_LCYL_REG);
+				args->tfRegister[IDE_HCYL_OFFSET]    = hwif->INB(IDE_HCYL_REG);
+				args->tfRegister[IDE_SELECT_OFFSET]  = hwif->INB(IDE_SELECT_REG);
+				args->tfRegister[IDE_STATUS_OFFSET]  = stat;
+
+				if (drive->addressing == 1) {
+					hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG_HOB);
+					args->hobRegister[IDE_FEATURE_OFFSET_HOB] = hwif->INB(IDE_FEATURE_REG);
+					args->hobRegister[IDE_NSECTOR_OFFSET_HOB] = hwif->INB(IDE_NSECTOR_REG);
+					args->hobRegister[IDE_SECTOR_OFFSET_HOB]  = hwif->INB(IDE_SECTOR_REG);
+					args->hobRegister[IDE_LCYL_OFFSET_HOB]    = hwif->INB(IDE_LCYL_REG);
+					args->hobRegister[IDE_HCYL_OFFSET_HOB]    = hwif->INB(IDE_HCYL_REG);
+				}
+			}
+			break;
+		}
+		default:
+			break;
+	}
+	spin_lock_irqsave(&io_request_lock, flags);
+	blkdev_dequeue_request(rq);
+	HWGROUP(drive)->rq = NULL;
+	end_that_request_last(rq);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+EXPORT_SYMBOL(ide_end_drive_cmd);
+
+/**
+ *	try_to_flush_leftover_data	-	flush junk
+ *	@drive: drive to flush
+ *
+ *	try_to_flush_leftover_data() is invoked in response to a drive
+ *	unexpectedly having its DRQ_STAT bit set.  As an alternative to
+ *	resetting the drive, this routine tries to clear the condition
+ *	by read a sector's worth of data from the drive.  Of course,
+ *	this may not help if the drive is *waiting* for data from *us*.
+ */
+void try_to_flush_leftover_data (ide_drive_t *drive)
+{
+	int i = (drive->mult_count ? drive->mult_count : 1) * SECTOR_WORDS;
+
+	if (drive->media != ide_disk)
+		return;
+	while (i > 0) {
+		u32 buffer[16];
+		u32 wcount = (i > 16) ? 16 : i;
+
+		i -= wcount;
+		HWIF(drive)->ata_input_data(drive, buffer, wcount);
+	}
+}
+
+EXPORT_SYMBOL(try_to_flush_leftover_data);
+
+/*
+ * FIXME Add an ATAPI error
+ */
+
+/**
+ *	ide_error	-	handle an error on the IDE
+ *	@drive: drive the error occurred on
+ *	@msg: message to report
+ *	@stat: status bits
+ *
+ *	ide_error() takes action based on the error returned by the drive.
+ *	For normal I/O that may well include retries. We deal with
+ *	both new-style (taskfile) and old style command handling here.
+ *	In the case of taskfile command handling there is work left to
+ *	do
+ */
+ 
+ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, u8 stat)
+{
+	ide_hwif_t *hwif;
+	struct request *rq;
+	u8 err;
+
+	err = ide_dump_status(drive, msg, stat);
+	if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
+		return ide_stopped;
+
+	hwif = HWIF(drive);
+	/* retry only "normal" I/O: */
+	if (rq->cmd == IDE_DRIVE_CMD || rq->cmd == IDE_DRIVE_TASK) {
+		rq->errors = 1;
+		ide_end_drive_cmd(drive, stat, err);
+		return ide_stopped;
+	}
+	if (rq->cmd == IDE_DRIVE_TASKFILE) {
+		rq->errors = 1;
+		ide_end_drive_cmd(drive, stat, err);
+//		ide_end_taskfile(drive, stat, err);
+		return ide_stopped;
+	}
+
+	if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) {
+		 /* other bits are useless when BUSY */
+		rq->errors |= ERROR_RESET;
+	} else {
+		if (drive->media != ide_disk)
+			goto media_out;
+
+		if (stat & ERR_STAT) {
+			/* err has different meaning on cdrom and tape */
+			if (err == ABRT_ERR) {
+				if (drive->select.b.lba &&
+				    (hwif->INB(IDE_COMMAND_REG) == WIN_SPECIFY))
+					/* some newer drives don't
+					 * support WIN_SPECIFY
+					 */
+					return ide_stopped;
+			} else if ((err & BAD_CRC) == BAD_CRC) {
+				drive->crc_count++;
+				/* UDMA crc error -- just retry the operation */
+			} else if (err & (BBD_ERR | ECC_ERR)) {
+				/* retries won't help these */
+				rq->errors = ERROR_MAX;
+			} else if (err & TRK0_ERR) {
+				/* help it find track zero */
+				rq->errors |= ERROR_RECAL;
+			}
+		}
+media_out:
+		if ((stat & DRQ_STAT) && rq->cmd != WRITE)
+			try_to_flush_leftover_data(drive);
+	}
+	if (hwif->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT)) {
+		/* force an abort */
+		hwif->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);
+	}
+	if (rq->errors >= ERROR_MAX) {
+		if (drive->driver != NULL)
+			DRIVER(drive)->end_request(drive, 0);
+		else
+	 		ide_end_request(drive, 0);
+	} else {
+		if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
+			++rq->errors;
+			return ide_do_reset(drive);
+		}
+		if ((rq->errors & ERROR_RECAL) == ERROR_RECAL)
+			drive->special.b.recalibrate = 1;
+		++rq->errors;
+	}
+	return ide_stopped;
+}
+
+EXPORT_SYMBOL(ide_error);
+
+/**
+ *	ide_cmd		-	issue a simple drive command
+ *	@drive: drive the command is for
+ *	@cmd: command byte
+ *	@nsect: sector byte
+ *	@handler: handler for the command completion
+ *
+ *	Issue a simple drive command with interrupts.
+ *	The drive must be selected beforehand.
+ */
+
+void ide_cmd (ide_drive_t *drive, u8 cmd, u8 nsect, ide_handler_t *handler)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	ide_set_handler(drive, handler, WAIT_CMD, NULL);
+	if (IDE_CONTROL_REG)
+		hwif->OUTB(drive->ctl,IDE_CONTROL_REG);	/* clear nIEN */
+	SELECT_MASK(drive,0);
+	hwif->OUTB(nsect,IDE_NSECTOR_REG);
+	hwif->OUTB(cmd,IDE_COMMAND_REG);
+}
+
+EXPORT_SYMBOL(ide_cmd);
+
+/**
+ *	drive_cmd_intr		- 	drive command completion interrupt
+ *	@drive: drive the completion interrupt occurred on
+ *
+ *	drive_cmd_intr() is invoked on completion of a special DRIVE_CMD.
+ *	We do any neccessary daya reading and then wait for the drive to
+ *	go non busy. At that point we may read the error data and complete
+ *	the request
+ */
+ 
+ide_startstop_t drive_cmd_intr (ide_drive_t *drive)
+{
+	struct request *rq = HWGROUP(drive)->rq;
+	ide_hwif_t *hwif = HWIF(drive);
+	u8 *args = (u8 *) rq->buffer;
+	u8 stat = hwif->INB(IDE_STATUS_REG);
+	int retries = 10;
+
+	local_irq_enable();
+	if ((stat & DRQ_STAT) && args && args[3]) {
+		u8 io_32bit = drive->io_32bit;
+		drive->io_32bit = 0;
+		hwif->ata_input_data(drive, &args[4], args[3] * SECTOR_WORDS);
+		drive->io_32bit = io_32bit;
+		while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--)
+			udelay(100);
+	}
+
+	if (!OK_STAT(stat, READY_STAT, BAD_STAT))
+		return DRIVER(drive)->error(drive, "drive_cmd", stat);
+		/* calls ide_end_drive_cmd */
+	ide_end_drive_cmd(drive, stat, hwif->INB(IDE_ERROR_REG));
+	return ide_stopped;
+}
+
+EXPORT_SYMBOL(drive_cmd_intr);
+
+/**
+ *	do_special		-	issue some special commands
+ *	@drive: drive the command is for
+ *
+ *	do_special() is used to issue WIN_SPECIFY, WIN_RESTORE, and WIN_SETMULT
+ *	commands to a drive.  It used to do much more, but has been scaled
+ *	back.
+ */
+
+ide_startstop_t do_special (ide_drive_t *drive)
+{
+	special_t *s = &drive->special;
+
+#ifdef DEBUG
+	printk("%s: do_special: 0x%02x\n", drive->name, s->all);
+#endif
+	if (s->b.set_tune) {
+		s->b.set_tune = 0;
+		if (HWIF(drive)->tuneproc != NULL)
+			HWIF(drive)->tuneproc(drive, drive->tune_req);
+	} else if (drive->driver != NULL) {
+		return DRIVER(drive)->special(drive);
+	} else if (s->all) {
+		printk(KERN_ERR "%s: bad special flag: 0x%02x\n", drive->name, s->all);
+		s->all = 0;
+	}
+	return ide_stopped;
+}
+
+EXPORT_SYMBOL(do_special);
+
+/**
+ *	execute_drive_command	-	issue special drive command
+ *	@drive: the drive to issue th command on
+ *	@rq: the request structure holding the command
+ *
+ *	execute_drive_cmd() issues a special drive command,  usually 
+ *	initiated by ioctl() from the external hdparm program. The
+ *	command can be a drive command, drive task or taskfile 
+ *	operation. Weirdly you can call it with NULL to wait for
+ *	all commands to finish. Don't do this as that is due to change
+ */
+
+ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+ 	switch(rq->cmd) {
+ 		case IDE_DRIVE_TASKFILE:
+ 		{
+ 			ide_task_t *args = rq->special;
+ 
+ 			if (!(args)) break;
+ 
+			if (args->tf_out_flags.all != 0) 
+				return flagged_taskfile(drive, args);
+			return do_rw_taskfile(drive, args);
+ 		}
+ 		case IDE_DRIVE_TASK:
+ 		{
+ 			u8 *args = rq->buffer;
+ 			u8 sel;
+ 
+ 			if (!(args)) break;
+#ifdef DEBUG
+ 			printk("%s: DRIVE_TASK_CMD ", drive->name);
+ 			printk("cmd=0x%02x ", args[0]);
+ 			printk("fr=0x%02x ", args[1]);
+ 			printk("ns=0x%02x ", args[2]);
+ 			printk("sc=0x%02x ", args[3]);
+ 			printk("lcyl=0x%02x ", args[4]);
+ 			printk("hcyl=0x%02x ", args[5]);
+ 			printk("sel=0x%02x\n", args[6]);
+#endif
+ 			hwif->OUTB(args[1], IDE_FEATURE_REG);
+ 			hwif->OUTB(args[3], IDE_SECTOR_REG);
+ 			hwif->OUTB(args[4], IDE_LCYL_REG);
+ 			hwif->OUTB(args[5], IDE_HCYL_REG);
+ 			sel = (args[6] & ~0x10);
+ 			if (drive->select.b.unit)
+ 				sel |= 0x10;
+ 			hwif->OUTB(sel, IDE_SELECT_REG);
+ 			ide_cmd(drive, args[0], args[2], &drive_cmd_intr);
+ 			return ide_started;
+ 		}
+ 		case IDE_DRIVE_CMD:
+ 		{
+ 			u8 *args = rq->buffer;
+ 
+ 			if (!(args)) break;
+#ifdef DEBUG
+ 			printk("%s: DRIVE_CMD ", drive->name);
+ 			printk("cmd=0x%02x ", args[0]);
+ 			printk("sc=0x%02x ", args[1]);
+ 			printk("fr=0x%02x ", args[2]);
+ 			printk("xx=0x%02x\n", args[3]);
+#endif
+ 			if (args[0] == WIN_SMART) {
+ 				hwif->OUTB(0x4f, IDE_LCYL_REG);
+ 				hwif->OUTB(0xc2, IDE_HCYL_REG);
+ 				hwif->OUTB(args[2],IDE_FEATURE_REG);
+ 				hwif->OUTB(args[1],IDE_SECTOR_REG);
+ 				ide_cmd(drive, args[0], args[3], &drive_cmd_intr);
+ 				return ide_started;
+ 			}
+ 			hwif->OUTB(args[2],IDE_FEATURE_REG);
+ 			ide_cmd(drive, args[0], args[1], &drive_cmd_intr);
+ 			return ide_started;
+ 		}
+ 		default:
+ 			break;
+ 	}
+ 	/*
+ 	 * NULL is actually a valid way of waiting for
+ 	 * all current requests to be flushed from the queue.
+ 	 */
+#ifdef DEBUG
+ 	printk("%s: DRIVE_CMD (null)\n", drive->name);
+#endif
+ 	ide_end_drive_cmd(drive,
+			hwif->INB(IDE_STATUS_REG),
+			hwif->INB(IDE_ERROR_REG));
+ 	return ide_stopped;
+}
+
+EXPORT_SYMBOL(execute_drive_cmd);
+
+/**
+ *	start_request	-	start of I/O and command issuing for IDE
+ *
+ *	start_request() initiates handling of a new I/O request. It
+ *	accepts commands and I/O (read/write) requests. It also does
+ *	the final remapping for weird stuff like EZDrive. Once 
+ *	device mapper can work sector level the EZDrive stuff can go away
+ *
+ *	FIXME: this function needs a rename
+ */
+ 
+ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
+{
+	ide_startstop_t startstop;
+	unsigned long block, blockend;
+	unsigned int minor = MINOR(rq->rq_dev), unit = minor >> PARTN_BITS;
+	ide_hwif_t *hwif = HWIF(drive);
+
+#ifdef DEBUG
+	printk("%s: start_request: current=0x%08lx\n",
+		hwif->name, (unsigned long) rq);
+#endif
+
+	/* bail early if we've exceeded max_failures */
+	if (drive->max_failures && (drive->failures > drive->max_failures)) {
+		goto kill_rq;
+	}
+
+	/*
+	 * bail early if we've sent a device to sleep, however how to wake
+	 * this needs to be a masked flag.  FIXME for proper operations.
+	 */
+	if (drive->suspend_reset) {
+		goto kill_rq;
+	}
+
+	if (unit >= MAX_DRIVES) {
+		printk(KERN_ERR "%s: bad device number: %s\n",
+			hwif->name, kdevname(rq->rq_dev));
+		goto kill_rq;
+	}
+#ifdef DEBUG
+	if (rq->bh && !buffer_locked(rq->bh)) {
+		printk(KERN_ERR "%s: block not locked\n", drive->name);
+		goto kill_rq;
+	}
+#endif
+	block    = rq->sector;
+	blockend = block + rq->nr_sectors;
+
+	if (blk_fs_request(rq) &&
+	    (drive->media == ide_disk || drive->media == ide_floppy)) {
+		if ((blockend < block) || (blockend > drive->part[minor&PARTN_MASK].nr_sects)) {
+			printk(KERN_ERR "%s%c: bad access: block=%ld, count=%ld\n", drive->name,
+			 (minor&PARTN_MASK)?'0'+(minor&PARTN_MASK):' ', block, rq->nr_sectors);
+			goto kill_rq;
+		}
+		block += drive->part[minor&PARTN_MASK].start_sect + drive->sect0;
+	}
+	/* Yecch - this will shift the entire interval,
+	   possibly killing some innocent following sector */
+	if (block == 0 && drive->remap_0_to_1 == 1)
+		block = 1;  /* redirect MBR access to EZ-Drive partn table */
+
+#if (DISK_RECOVERY_TIME > 0)
+	while ((read_timer() - hwif->last_time) < DISK_RECOVERY_TIME);
+#endif
+
+	SELECT_DRIVE(drive);
+	if (ide_wait_stat(&startstop, drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) {
+		printk(KERN_ERR "%s: drive not ready for command\n", drive->name);
+		return startstop;
+	}
+	if (!drive->special.all) {
+		switch(rq->cmd) {
+			case IDE_DRIVE_CMD:
+			case IDE_DRIVE_TASK:
+				return execute_drive_cmd(drive, rq);
+			case IDE_DRIVE_TASKFILE:
+				return execute_drive_cmd(drive, rq);
+			default:
+				break;
+		}
+		if (drive->driver != NULL) {
+			return (DRIVER(drive)->do_request(drive, rq, block));
+		}
+		printk(KERN_WARNING "%s: media type %d not supported\n", drive->name, drive->media);
+		goto kill_rq;
+	}
+	return do_special(drive);
+kill_rq:
+	if (drive->driver != NULL)
+		DRIVER(drive)->end_request(drive, 0);
+	else
+		ide_end_request(drive, 0);
+	return ide_stopped;
+}
+
+EXPORT_SYMBOL(start_request);
+
+int restart_request (ide_drive_t *drive, struct request *rq)
+{
+	(void) start_request(drive, rq);
+	return 0;
+}
+
+EXPORT_SYMBOL(restart_request);
+
+/**
+ *	ide_stall_queue		-	pause an IDE device
+ *	@drive: drive to stall
+ *	@timeout: time to stall for (jiffies)
+ *
+ *	ide_stall_queue() can be used by a drive to give excess bandwidth back
+ *	to the hwgroup by sleeping for timeout jiffies.
+ */
+ 
+void ide_stall_queue (ide_drive_t *drive, unsigned long timeout)
+{
+	if (timeout > WAIT_WORSTCASE)
+		timeout = WAIT_WORSTCASE;
+	drive->sleep = timeout + jiffies;
+}
+
+EXPORT_SYMBOL(ide_stall_queue);
+
+#define WAKEUP(drive)	((drive)->service_start + 2 * (drive)->service_time)
+
+/**
+ *	choose_drive		-	select a drive to service
+ *	@hwgroup: hardware group to select on
+ *
+ *	choose_drive() selects the next drive which will be serviced.
+ *	This is neccessary because the IDE layer can't issue commands
+ *	to both drives on the same cable, unlike SCSI.
+ */
+ 
+static inline ide_drive_t *choose_drive (ide_hwgroup_t *hwgroup)
+{
+	ide_drive_t *drive, *best;
+
+repeat:	
+	best = NULL;
+	drive = hwgroup->drive;
+	do {
+		if (!blk_queue_empty(&drive->queue) && (!drive->sleep || time_after_eq(jiffies, drive->sleep))) {
+			if (!best
+			 || (drive->sleep && (!best->sleep || 0 < (signed long)(best->sleep - drive->sleep)))
+			 || (!best->sleep && 0 < (signed long)(WAKEUP(best) - WAKEUP(drive))))
+			{
+				if (!blk_queue_plugged(&drive->queue))
+					best = drive;
+			}
+		}
+	} while ((drive = drive->next) != hwgroup->drive);
+	if (best && best->nice1 && !best->sleep && best != hwgroup->drive && best->service_time > WAIT_MIN_SLEEP) {
+		long t = (signed long)(WAKEUP(best) - jiffies);
+		if (t >= WAIT_MIN_SLEEP) {
+		/*
+		 * We *may* have some time to spare, but first let's see if
+		 * someone can potentially benefit from our nice mood today..
+		 */
+			drive = best->next;
+			do {
+				if (!drive->sleep
+				 && 0 < (signed long)(WAKEUP(drive) - (jiffies - best->service_time))
+				 && 0 < (signed long)((jiffies + t) - WAKEUP(drive)))
+				{
+					ide_stall_queue(best, IDE_MIN(t, 10 * WAIT_MIN_SLEEP));
+					goto repeat;
+				}
+			} while ((drive = drive->next) != best);
+		}
+	}
+	return best;
+}
+
+/*
+ * Issue a new request to a drive from hwgroup
+ * Caller must have already done spin_lock_irqsave(&io_request_lock, ..);
+ *
+ * A hwgroup is a serialized group of IDE interfaces.  Usually there is
+ * exactly one hwif (interface) per hwgroup, but buggy controllers (eg. CMD640)
+ * may have both interfaces in a single hwgroup to "serialize" access.
+ * Or possibly multiple ISA interfaces can share a common IRQ by being grouped
+ * together into one hwgroup for serialized access.
+ *
+ * Note also that several hwgroups can end up sharing a single IRQ,
+ * possibly along with many other devices.  This is especially common in
+ * PCI-based systems with off-board IDE controller cards.
+ *
+ * The IDE driver uses the single global io_request_lock spinlock to protect
+ * access to the request queues, and to protect the hwgroup->busy flag.
+ *
+ * The first thread into the driver for a particular hwgroup sets the
+ * hwgroup->busy flag to indicate that this hwgroup is now active,
+ * and then initiates processing of the top request from the request queue.
+ *
+ * Other threads attempting entry notice the busy setting, and will simply
+ * queue their new requests and exit immediately.  Note that hwgroup->busy
+ * remains set even when the driver is merely awaiting the next interrupt.
+ * Thus, the meaning is "this hwgroup is busy processing a request".
+ *
+ * When processing of a request completes, the completing thread or IRQ-handler
+ * will start the next request from the queue.  If no more work remains,
+ * the driver will clear the hwgroup->busy flag and exit.
+ *
+ * The io_request_lock (spinlock) is used to protect all access to the
+ * hwgroup->busy flag, but is otherwise not needed for most processing in
+ * the driver.  This makes the driver much more friendlier to shared IRQs
+ * than previous designs, while remaining 100% (?) SMP safe and capable.
+ */
+/* --BenH: made non-static as ide-pmac.c uses it to kick the hwgroup back
+ *         into life on wakeup from machine sleep.
+ */ 
+void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
+{
+	ide_drive_t	*drive;
+	ide_hwif_t	*hwif;
+	struct request	*rq;
+	ide_startstop_t	startstop;
+
+	/* for atari only: POSSIBLY BROKEN HERE(?) */
+	ide_get_lock(&ide_intr_lock, ide_intr, hwgroup);
+
+	/* necessary paranoia: ensure IRQs are masked on local CPU */
+	local_irq_disable();
+
+	while (!hwgroup->busy) {
+		hwgroup->busy = 1;
+		drive = choose_drive(hwgroup);
+		if (drive == NULL) {
+			unsigned long sleep = 0;
+			hwgroup->rq = NULL;
+			drive = hwgroup->drive;
+			do {
+				if (drive->sleep && (!sleep || 0 < (signed long)(sleep - drive->sleep)))
+					sleep = drive->sleep;
+			} while ((drive = drive->next) != hwgroup->drive);
+			if (sleep) {
+		/*
+		 * Take a short snooze, and then wake up this hwgroup again.
+		 * This gives other hwgroups on the same a chance to
+		 * play fairly with us, just in case there are big differences
+		 * in relative throughputs.. don't want to hog the cpu too much.
+		 */
+				if (time_before(sleep, jiffies + WAIT_MIN_SLEEP))
+					sleep = jiffies + WAIT_MIN_SLEEP;
+#if 1
+				if (timer_pending(&hwgroup->timer))
+					printk(KERN_ERR "ide_set_handler: timer already active\n");
+#endif
+				/* so that ide_timer_expiry knows what to do */
+				hwgroup->sleeping = 1;
+				mod_timer(&hwgroup->timer, sleep);
+				/* we purposely leave hwgroup->busy==1
+				 * while sleeping */
+			} else {
+				/* Ugly, but how can we sleep for the lock
+				 * otherwise? perhaps from tq_disk?
+				 */
+
+				/* for atari only */
+				ide_release_lock(&ide_intr_lock);
+				hwgroup->busy = 0;
+			}
+			/* no more work for this hwgroup (for now) */
+			return;
+		}
+		hwif = HWIF(drive);
+		if (hwgroup->hwif->sharing_irq &&
+		    hwif != hwgroup->hwif &&
+		    hwif->io_ports[IDE_CONTROL_OFFSET]) {
+			/* set nIEN for previous hwif */
+			SELECT_INTERRUPT(drive);
+		}
+		hwgroup->hwif = hwif;
+		hwgroup->drive = drive;
+		drive->sleep = 0;
+		drive->service_start = jiffies;
+
+		/* paranoia */
+		if (blk_queue_plugged(&drive->queue))
+			printk(KERN_ERR "%s: Huh? nuking plugged queue\n", drive->name);
+
+		rq = blkdev_entry_next_request(&drive->queue.queue_head);
+		hwgroup->rq = rq;
+		/*
+		 * Some systems have trouble with IDE IRQs arriving while
+		 * the driver is still setting things up.  So, here we disable
+		 * the IRQ used by this interface while the request is being started.
+		 * This may look bad at first, but pretty much the same thing
+		 * happens anyway when any interrupt comes in, IDE or otherwise
+		 *  -- the kernel masks the IRQ while it is being handled.
+		 */
+		if (hwif->irq != masked_irq)
+			disable_irq_nosync(hwif->irq);
+		spin_unlock(&io_request_lock);
+		local_irq_enable();
+			/* allow other IRQs while we start this request */
+		startstop = start_request(drive, rq);
+		spin_lock_irq(&io_request_lock);
+		if (hwif->irq != masked_irq)
+			enable_irq(hwif->irq);
+		if (startstop == ide_stopped)
+			hwgroup->busy = 0;
+	}
+}
+
+EXPORT_SYMBOL(ide_do_request);
+
+/*
+ * ide_get_queue() returns the queue which corresponds to a given device.
+ */
+request_queue_t *ide_get_queue (kdev_t dev)
+{
+	ide_hwif_t *hwif = (ide_hwif_t *)blk_dev[MAJOR(dev)].data;
+
+	return &hwif->drives[DEVICE_NR(dev) & 1].queue;
+}
+
+EXPORT_SYMBOL(ide_get_queue);
+
+/*
+ * Passes the stuff to ide_do_request
+ */
+void do_ide_request(request_queue_t *q)
+{
+	ide_do_request(q->queuedata, IDE_NO_IRQ);
+}
+
+/*
+ * un-busy the hwgroup etc, and clear any pending DMA status. we want to
+ * retry the current request in pio mode instead of risking tossing it
+ * all away
+ */
+void ide_dma_timeout_retry(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	struct request *rq;
+
+	/*
+	 * end current dma transaction
+	 */
+	(void) hwif->ide_dma_end(drive);
+
+	/*
+	 * complain a little, later we might remove some of this verbosity
+	 */
+	printk(KERN_ERR "%s: timeout waiting for DMA\n", drive->name);
+	(void) hwif->ide_dma_timeout(drive);
+
+	/*
+	 * disable dma for now, but remember that we did so because of
+	 * a timeout -- we'll reenable after we finish this next request
+	 * (or rather the first chunk of it) in pio.
+	 */
+	drive->retry_pio++;
+	drive->state = DMA_PIO_RETRY;
+	(void) hwif->ide_dma_off_quietly(drive);
+
+	/*
+	 * un-busy drive etc (hwgroup->busy is cleared on return) and
+	 * make sure request is sane
+	 */
+	rq = HWGROUP(drive)->rq;
+	HWGROUP(drive)->rq = NULL;
+
+	rq->errors = 0;
+	rq->sector = rq->bh->b_rsector;
+	rq->current_nr_sectors = rq->bh->b_size >> 9;
+	rq->hard_cur_sectors = rq->current_nr_sectors;
+	rq->buffer = rq->bh->b_data;
+}
+
+EXPORT_SYMBOL(ide_dma_timeout_retry);
+
+/**
+ *	ide_timer_expiry	-	handle lack of an IDE interrupt
+ *	@data: timer callback magic (hwgroup)
+ *
+ *	An IDE command has timed out before the expected drive return
+ *	occurred. At this point we attempt to clean up the current
+ *	mess. If the current handler includes an expiry handler then
+ *	we invoke the expiry handler, and providing it is happy the
+ *	work is done. If that fails we apply generic recovery rules
+ *	invoking the handler and checking the drive DMA status. We
+ *	have an excessively incestuous relationship with the DMA
+ *	logic that wants cleaning up.
+ */
+ 
+void ide_timer_expiry (unsigned long data)
+{
+	ide_hwgroup_t	*hwgroup = (ide_hwgroup_t *) data;
+	ide_handler_t	*handler;
+	ide_expiry_t	*expiry;
+ 	unsigned long	flags;
+	unsigned long	wait;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	del_timer(&hwgroup->timer);
+
+	if ((handler = hwgroup->handler) == NULL) {
+		/*
+		 * Either a marginal timeout occurred
+		 * (got the interrupt just as timer expired),
+		 * or we were "sleeping" to give other devices a chance.
+		 * Either way, we don't really want to complain about anything.
+		 */
+		if (hwgroup->sleeping) {
+			hwgroup->sleeping = 0;
+			hwgroup->busy = 0;
+		}
+	} else {
+		ide_drive_t *drive = hwgroup->drive;
+		if (!drive) {
+			printk(KERN_ERR "ide_timer_expiry: hwgroup->drive was NULL\n");
+			hwgroup->handler = NULL;
+		} else {
+			ide_hwif_t *hwif;
+			ide_startstop_t startstop = ide_stopped;
+			if (!hwgroup->busy) {
+				hwgroup->busy = 1;	/* paranoia */
+				printk(KERN_ERR "%s: ide_timer_expiry: hwgroup->busy was 0 ??\n", drive->name);
+			}
+			if ((expiry = hwgroup->expiry) != NULL) {
+				/* continue */
+				if ((wait = expiry(drive)) != 0) {
+					/* reset timer */
+					hwgroup->timer.expires  = jiffies + wait;
+					add_timer(&hwgroup->timer);
+					spin_unlock_irqrestore(&io_request_lock, flags);
+					return;
+				}
+			}
+			hwgroup->handler = NULL;
+			/*
+			 * We need to simulate a real interrupt when invoking
+			 * the handler() function, which means we need to
+			 * globally mask the specific IRQ:
+			 */
+			spin_unlock(&io_request_lock);
+			hwif  = HWIF(drive);
+#if DISABLE_IRQ_NOSYNC
+			disable_irq_nosync(hwif->irq);
+#else
+			/* disable_irq_nosync ?? */
+			disable_irq(hwif->irq);
+#endif /* DISABLE_IRQ_NOSYNC */
+
+			/* local CPU only,
+			 * as if we were handling an interrupt */
+			local_irq_disable();
+			if (hwgroup->poll_timeout != 0) {
+				startstop = handler(drive);
+			} else if (drive_is_ready(drive)) {
+				if (drive->waiting_for_dma)
+					(void) hwgroup->hwif->ide_dma_lostirq(drive);
+				(void)ide_ack_intr(hwif);
+				printk(KERN_ERR "%s: lost interrupt\n", drive->name);
+				startstop = handler(drive);
+			} else {
+				if (drive->waiting_for_dma) {
+					startstop = ide_stopped;
+					ide_dma_timeout_retry(drive);
+				} else
+					startstop = DRIVER(drive)->error(drive, "irq timeout", hwif->INB(IDE_STATUS_REG));
+			}
+			set_recovery_timer(hwif);
+			drive->service_time = jiffies - drive->service_start;
+			enable_irq(hwif->irq);
+			spin_lock_irq(&io_request_lock);
+			if (startstop == ide_stopped)
+				hwgroup->busy = 0;
+		}
+	}
+	ide_do_request(hwgroup, IDE_NO_IRQ);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+EXPORT_SYMBOL(ide_timer_expiry);
+
+/**
+ *	unexpected_intr		-	handle an unexpected IDE interrupt
+ *	@irq: interrupt line
+ *	@hwgroup: hwgroup being processed
+ *
+ *	There's nothing really useful we can do with an unexpected interrupt,
+ *	other than reading the status register (to clear it), and logging it.
+ *	There should be no way that an irq can happen before we're ready for it,
+ *	so we needn't worry much about losing an "important" interrupt here.
+ *
+ *	On laptops (and "green" PCs), an unexpected interrupt occurs whenever
+ *	the drive enters "idle", "standby", or "sleep" mode, so if the status
+ *	looks "good", we just ignore the interrupt completely.
+ *
+ *	This routine assumes __cli() is in effect when called.
+ *
+ *	If an unexpected interrupt happens on irq15 while we are handling irq14
+ *	and if the two interfaces are "serialized" (CMD640), then it looks like
+ *	we could screw up by interfering with a new request being set up for 
+ *	irq15.
+ *
+ *	In reality, this is a non-issue.  The new command is not sent unless 
+ *	the drive is ready to accept one, in which case we know the drive is
+ *	not trying to interrupt us.  And ide_set_handler() is always invoked
+ *	before completing the issuance of any new drive command, so we will not
+ *	be accidentally invoked as a result of any valid command completion
+ *	interrupt.
+ *
+ *	Note that we must walk the entire hwgroup here. We know which hwif
+ *	is doing the current command, but we don't know which hwif burped
+ *	mysteriously.
+ */
+ 
+static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup)
+{
+	u8 stat;
+	ide_hwif_t *hwif = hwgroup->hwif;
+
+	/*
+	 * handle the unexpected interrupt
+	 */
+	do {
+		if (hwif->irq == irq) {
+			stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
+			if (!OK_STAT(stat, READY_STAT, BAD_STAT)) {
+				/* Try to not flood the console with msgs */
+				static unsigned long last_msgtime, count;
+				++count;
+				if (time_after(jiffies, last_msgtime + HZ)) {
+					last_msgtime = jiffies;
+					printk(KERN_ERR "%s%s: unexpected interrupt, "
+						"status=0x%02x, count=%ld\n",
+						hwif->name,
+						(hwif->next==hwgroup->hwif) ? "" : "(?)", stat, count);
+				}
+			}
+		}
+	} while ((hwif = hwif->next) != hwgroup->hwif);
+}
+
+/**
+ *	ide_intr	-	default IDE interrupt handler
+ *	@irq: interrupt number
+ *	@dev_id: hwif group
+ *	@regs: unused weirdness from the kernel irq layer
+ *
+ *	This is the default IRQ handler for the IDE layer. You should
+ *	not need to override it. If you do be aware it is subtle in
+ *	places
+ *
+ *	hwgroup->hwif is the interface in the group currently performing
+ *	a command. hwgroup->drive is the drive and hwgroup->handler is
+ *	the IRQ handler to call. As we issue a command the handlers
+ *	step through multiple states, reassigning the handler to the
+ *	next step in the process. Unlike a smart SCSI controller IDE
+ *	expects the main processor to sequence the various transfer
+ *	stages. We also manage a poll timer to catch up with most
+ *	timeout situations. There are still a few where the handlers
+ *	don't ever decide to give up.
+ *
+ *	The handler eventually returns ide_stopped to indicate the
+ *	request completed. At this point we issue the next request
+ *	on the hwgroup and the process begins again.
+ */
+ 
+void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned long flags;
+	ide_hwgroup_t *hwgroup = (ide_hwgroup_t *)dev_id;
+	ide_hwif_t *hwif;
+	ide_drive_t *drive;
+	ide_handler_t *handler;
+	ide_startstop_t startstop;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	hwif = hwgroup->hwif;
+
+	if (!ide_ack_intr(hwif)) {
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return;
+	}
+
+	if ((handler = hwgroup->handler) == NULL ||
+	    hwgroup->poll_timeout != 0) {
+		/*
+		 * Not expecting an interrupt from this drive.
+		 * That means this could be:
+		 *	(1) an interrupt from another PCI device
+		 *	sharing the same PCI INT# as us.
+		 * or	(2) a drive just entered sleep or standby mode,
+		 *	and is interrupting to let us know.
+		 * or	(3) a spurious interrupt of unknown origin.
+		 *
+		 * For PCI, we cannot tell the difference,
+		 * so in that case we just ignore it and hope it goes away.
+		 */
+#ifdef CONFIG_BLK_DEV_IDEPCI
+		if (hwif->pci_dev && !hwif->pci_dev->vendor)
+#endif	/* CONFIG_BLK_DEV_IDEPCI */
+		{
+			/*
+			 * Probably not a shared PCI interrupt,
+			 * so we can safely try to do something about it:
+			 */
+			unexpected_intr(irq, hwgroup);
+#ifdef CONFIG_BLK_DEV_IDEPCI
+		} else {
+			/*
+			 * Whack the status register, just in case
+			 * we have a leftover pending IRQ.
+			 */
+			(void) hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+		}
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return;
+	}
+	drive = hwgroup->drive;
+	if (!drive) {
+		/*
+		 * This should NEVER happen, and there isn't much
+		 * we could do about it here.
+		 */
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return;
+	}
+	if (!drive_is_ready(drive)) {
+		/*
+		 * This happens regularly when we share a PCI IRQ with
+		 * another device.  Unfortunately, it can also happen
+		 * with some buggy drives that trigger the IRQ before
+		 * their status register is up to date.  Hopefully we have
+		 * enough advance overhead that the latter isn't a problem.
+		 */
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return;
+	}
+	if (!hwgroup->busy) {
+		hwgroup->busy = 1;	/* paranoia */
+		printk(KERN_ERR "%s: ide_intr: hwgroup->busy was 0 ??\n", drive->name);
+	}
+	hwgroup->handler = NULL;
+	del_timer(&hwgroup->timer);
+	spin_unlock(&io_request_lock);
+
+	if (drive->unmask)
+		local_irq_enable();
+
+	/* service this interrupt, may set handler for next interrupt */
+	startstop = handler(drive);
+	spin_lock_irq(&io_request_lock);
+
+	/*
+	 * Note that handler() may have set things up for another
+	 * interrupt to occur soon, but it cannot happen until
+	 * we exit from this routine, because it will be the
+	 * same irq as is currently being serviced here, and Linux
+	 * won't allow another of the same (on any CPU) until we return.
+	 */
+	set_recovery_timer(HWIF(drive));
+	drive->service_time = jiffies - drive->service_start;
+	if (startstop == ide_stopped) {
+		if (hwgroup->handler == NULL) {	/* paranoia */
+			hwgroup->busy = 0;
+			ide_do_request(hwgroup, hwif->irq);
+		} else {
+			printk(KERN_ERR "%s: ide_intr: huh? expected NULL handler "
+				"on exit\n", drive->name);
+		}
+	}
+	spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+EXPORT_SYMBOL(ide_intr);
+
+/*
+ * get_info_ptr() returns the (ide_drive_t *) for a given device number.
+ * It returns NULL if the given device number does not match any present drives.
+ */
+ide_drive_t *get_info_ptr (kdev_t i_rdev)
+{
+	int		major = MAJOR(i_rdev);
+	unsigned int	h;
+
+	for (h = 0; h < MAX_HWIFS; ++h) {
+		ide_hwif_t  *hwif = &ide_hwifs[h];
+		if (hwif->present && major == hwif->major) {
+			unsigned unit = DEVICE_NR(i_rdev);
+			if (unit < MAX_DRIVES) {
+				ide_drive_t *drive = &hwif->drives[unit];
+				if (drive->present)
+					return drive;
+			}
+			break;
+		}
+	}
+	return NULL;
+}
+
+EXPORT_SYMBOL(get_info_ptr);
+
+/**
+ *	ide_init_drive_cmd	-	initialize a drive command request
+ *	@rq: request object
+ *
+ *	Initialize a request before we fill it in and send it down to
+ *	ide_do_drive_cmd. Commands must be set up by this function. Right
+ *	now it doesn't do a lot, but if that changes abusers will have a
+ *	nasty suprise.
+ */
+
+void ide_init_drive_cmd (struct request *rq)
+{
+	memset(rq, 0, sizeof(*rq));
+	rq->cmd = IDE_DRIVE_CMD;
+}
+
+EXPORT_SYMBOL(ide_init_drive_cmd);
+
+/**
+ *	ide_do_drive_cmd	-	issue IDE special command
+ *	@drive: device to issue command
+ *	@rq: request to issue
+ *	@action: action for processing
+ *
+ *	This function issues a special IDE device request
+ *	onto the request queue.
+ *
+ *	If action is ide_wait, then the rq is queued at the end of the
+ *	request queue, and the function sleeps until it has been processed.
+ *	This is for use when invoked from an ioctl handler.
+ *
+ *	If action is ide_preempt, then the rq is queued at the head of
+ *	the request queue, displacing the currently-being-processed
+ *	request and this function returns immediately without waiting
+ *	for the new rq to be completed.  This is VERY DANGEROUS, and is
+ *	intended for careful use by the ATAPI tape/cdrom driver code.
+ *
+ *	If action is ide_next, then the rq is queued immediately after
+ *	the currently-being-processed-request (if any), and the function
+ *	returns without waiting for the new rq to be completed.  As above,
+ *	This is VERY DANGEROUS, and is intended for careful use by the
+ *	ATAPI tape/cdrom driver code.
+ *
+ *	If action is ide_end, then the rq is queued at the end of the
+ *	request queue, and the function returns immediately without waiting
+ *	for the new rq to be completed. This is again intended for careful
+ *	use by the ATAPI tape/cdrom driver code.
+ */
+ 
+int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action)
+{
+	unsigned long flags;
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+	unsigned int major = HWIF(drive)->major;
+	request_queue_t *q = &drive->queue;
+	struct list_head *queue_head = &q->queue_head;
+	DECLARE_COMPLETION(wait);
+
+#ifdef CONFIG_BLK_DEV_PDC4030
+	if (HWIF(drive)->chipset == ide_pdc4030 && rq->buffer != NULL)
+		return -ENOSYS;  /* special drive cmds not supported */
+#endif
+	rq->errors = 0;
+	rq->rq_status = RQ_ACTIVE;
+	rq->rq_dev = MKDEV(major,(drive->select.b.unit)<<PARTN_BITS);
+	if (action == ide_wait)
+		rq->waiting = &wait;
+	spin_lock_irqsave(&io_request_lock, flags);
+	if (blk_queue_empty(q) || action == ide_preempt) {
+		if (action == ide_preempt)
+			hwgroup->rq = NULL;
+	} else {
+		if (action == ide_wait || action == ide_end) {
+			queue_head = queue_head->prev;
+		} else
+			queue_head = queue_head->next;
+	}
+	list_add(&rq->queue, queue_head);
+	ide_do_request(hwgroup, IDE_NO_IRQ);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	if (action == ide_wait) {
+		/* wait for it to be serviced */
+		wait_for_completion(&wait);
+		/* return -EIO if errors */
+		return rq->errors ? -EIO : 0;
+	}
+	return 0;
+
+}
+
+EXPORT_SYMBOL(ide_do_drive_cmd);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-iops.c linux-2.4.21-pre6/drivers/ide/ide-iops.c
--- linux-2.4.20/drivers/ide/ide-iops.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/ide-iops.c	2003-03-26 23:49:40.000000000 +0000
@@ -0,0 +1,1274 @@
+/*
+ * linux/drivers/ide/ide-iops.c	Version 0.33	April 11, 2002
+ *
+ *  Copyright (C) 2000-2002	Andre Hedrick <andre@linux-ide.org>
+ *
+ *
+ */
+
+#include <linux/config.h>
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/genhd.h>
+#include <linux/blkpg.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+
+#include <asm/byteorder.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+
+
+static u8 ide_inb (unsigned long port)
+{
+	return (u8) inb(port);
+}
+
+static u16 ide_inw (unsigned long port)
+{
+	return (u16) inw(port);
+}
+
+static void ide_insw (unsigned long port, void *addr, u32 count)
+{
+	return insw(port, addr, count);
+}
+
+static u32 ide_inl (unsigned long port)
+{
+	return (u32) inl(port);
+}
+
+static void ide_insl (unsigned long port, void *addr, u32 count)
+{
+	insl(port, addr, count);
+}
+
+static void ide_outb (u8 addr, unsigned long port)
+{
+	outb(addr, port);
+}
+
+static void ide_outw (u16 addr, unsigned long port)
+{
+	outw(addr, port);
+}
+
+static void ide_outsw (unsigned long port, void *addr, u32 count)
+{
+	outsw(port, addr, count);
+}
+
+static void ide_outl (u32 addr, unsigned long port)
+{
+	outl(addr, port);
+}
+
+static void ide_outsl (unsigned long port, void *addr, u32 count)
+{
+	return outsl(port, addr, count);
+}
+
+void default_hwif_iops (ide_hwif_t *hwif)
+{
+	hwif->OUTB	= ide_outb;
+	hwif->OUTW	= ide_outw;
+	hwif->OUTL	= ide_outl;
+	hwif->OUTSW	= ide_outsw;
+	hwif->OUTSL	= ide_outsl;
+	hwif->INB	= ide_inb;
+	hwif->INW	= ide_inw;
+	hwif->INL	= ide_inl;
+	hwif->INSW	= ide_insw;
+	hwif->INSL	= ide_insl;
+}
+
+EXPORT_SYMBOL(default_hwif_iops);
+
+static u8 ide_mm_inb (unsigned long port)
+{
+	return (u8) readb(port);
+}
+
+static u16 ide_mm_inw (unsigned long port)
+{
+	return (u16) readw(port);
+}
+
+static void ide_mm_insw (unsigned long port, void *addr, u32 count)
+{
+	__ide_mm_insw(port, addr, count);
+}
+
+static u32 ide_mm_inl (unsigned long port)
+{
+	return (u32) readl(port);
+}
+
+static void ide_mm_insl (unsigned long port, void *addr, u32 count)
+{
+	__ide_mm_insl(port, addr, count);
+}
+
+static void ide_mm_outb (u8 value, unsigned long port)
+{
+	writeb(value, port);
+}
+
+static void ide_mm_outw (u16 value, unsigned long port)
+{
+	writew(value, port);
+}
+
+static void ide_mm_outsw (unsigned long port, void *addr, u32 count)
+{
+	__ide_mm_outsw(port, addr, count);
+}
+
+static void ide_mm_outl (u32 value, unsigned long port)
+{
+	writel(value, port);
+}
+
+static void ide_mm_outsl (unsigned long port, void *addr, u32 count)
+{
+	__ide_mm_outsl(port, addr, count);
+}
+
+void default_hwif_mmiops (ide_hwif_t *hwif)
+{
+	hwif->OUTB	= ide_mm_outb;
+	hwif->OUTW	= ide_mm_outw;
+	hwif->OUTL	= ide_mm_outl;
+	hwif->OUTSW	= ide_mm_outsw;
+	hwif->OUTSL	= ide_mm_outsl;
+	hwif->INB	= ide_mm_inb;
+	hwif->INW	= ide_mm_inw;
+	hwif->INL	= ide_mm_inl;
+	hwif->INSW	= ide_mm_insw;
+	hwif->INSL	= ide_mm_insl;
+}
+
+EXPORT_SYMBOL(default_hwif_mmiops);
+
+void default_hwif_transport (ide_hwif_t *hwif)
+{
+	hwif->ata_input_data		= ata_input_data;
+	hwif->ata_output_data		= ata_output_data;
+	hwif->atapi_input_bytes		= atapi_input_bytes;
+	hwif->atapi_output_bytes	= atapi_output_bytes;
+}
+
+EXPORT_SYMBOL(default_hwif_transport);
+
+u32 read_24 (ide_drive_t *drive)
+{
+	u8 hcyl = HWIF(drive)->INB(IDE_HCYL_REG);
+	u8 lcyl = HWIF(drive)->INB(IDE_LCYL_REG);
+	u8 sect = HWIF(drive)->INB(IDE_SECTOR_REG);
+	return (hcyl<<16)|(lcyl<<8)|sect;
+}
+
+EXPORT_SYMBOL(read_24);
+
+void SELECT_DRIVE (ide_drive_t *drive)
+{
+	if (HWIF(drive)->selectproc)
+		HWIF(drive)->selectproc(drive);
+	HWIF(drive)->OUTB(drive->select.all, IDE_SELECT_REG);
+}
+
+EXPORT_SYMBOL(SELECT_DRIVE);
+
+void SELECT_INTERRUPT (ide_drive_t *drive)
+{
+	if (HWIF(drive)->intrproc)
+		HWIF(drive)->intrproc(drive);
+	else
+		HWIF(drive)->OUTB(drive->ctl|2, IDE_CONTROL_REG);
+}
+
+EXPORT_SYMBOL(SELECT_INTERRUPT);
+
+void SELECT_MASK (ide_drive_t *drive, int mask)
+{
+	if (HWIF(drive)->maskproc)
+		HWIF(drive)->maskproc(drive, mask);
+}
+
+EXPORT_SYMBOL(SELECT_MASK);
+
+void QUIRK_LIST (ide_drive_t *drive)
+{
+	if (HWIF(drive)->quirkproc)
+		drive->quirk_list = HWIF(drive)->quirkproc(drive);
+}
+
+EXPORT_SYMBOL(QUIRK_LIST);
+
+/*
+ * Some localbus EIDE interfaces require a special access sequence
+ * when using 32-bit I/O instructions to transfer data.  We call this
+ * the "vlb_sync" sequence, which consists of three successive reads
+ * of the sector count register location, with interrupts disabled
+ * to ensure that the reads all happen together.
+ */
+void ata_vlb_sync (ide_drive_t *drive, ide_ioreg_t port)
+{
+	(void) HWIF(drive)->INB(port);
+	(void) HWIF(drive)->INB(port);
+	(void) HWIF(drive)->INB(port);
+}
+
+EXPORT_SYMBOL(ata_vlb_sync);
+
+/*
+ * This is used for most PIO data transfers *from* the IDE interface
+ */
+void ata_input_data (ide_drive_t *drive, void *buffer, u32 wcount)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 io_32bit		= drive->io_32bit;
+
+	if (io_32bit) {
+		if (io_32bit & 2) {
+			unsigned long flags;
+			local_irq_save(flags);
+			ata_vlb_sync(drive, IDE_NSECTOR_REG);
+			hwif->INSL(IDE_DATA_REG, buffer, wcount);
+			local_irq_restore(flags);
+		} else
+			hwif->INSL(IDE_DATA_REG, buffer, wcount);
+	} else {
+		hwif->INSW(IDE_DATA_REG, buffer, wcount<<1);
+	}
+}
+
+EXPORT_SYMBOL(ata_input_data);
+
+/*
+ * This is used for most PIO data transfers *to* the IDE interface
+ */
+void ata_output_data (ide_drive_t *drive, void *buffer, u32 wcount)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 io_32bit		= drive->io_32bit;
+
+	if (io_32bit) {
+		if (io_32bit & 2) {
+			unsigned long flags;
+			local_irq_save(flags);
+			ata_vlb_sync(drive, IDE_NSECTOR_REG);
+			hwif->OUTSL(IDE_DATA_REG, buffer, wcount);
+			local_irq_restore(flags);
+		} else
+			hwif->OUTSL(IDE_DATA_REG, buffer, wcount);
+	} else {
+		hwif->OUTSW(IDE_DATA_REG, buffer, wcount<<1);
+	}
+}
+
+EXPORT_SYMBOL(ata_output_data);
+
+/*
+ * The following routines are mainly used by the ATAPI drivers.
+ *
+ * These routines will round up any request for an odd number of bytes,
+ * so if an odd bytecount is specified, be sure that there's at least one
+ * extra byte allocated for the buffer.
+ */
+
+void atapi_input_bytes (ide_drive_t *drive, void *buffer, u32 bytecount)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+
+	++bytecount;
+#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
+	if (MACH_IS_ATARI || MACH_IS_Q40) {
+		/* Atari has a byte-swapped IDE interface */
+		insw_swapw(IDE_DATA_REG, buffer, bytecount / 2);
+		return;
+	}
+#endif /* CONFIG_ATARI */
+	hwif->ata_input_data(drive, buffer, bytecount / 4);
+	if ((bytecount & 0x03) >= 2)
+		hwif->INSW(IDE_DATA_REG, ((u8 *)buffer)+(bytecount & ~0x03), 1);
+}
+
+EXPORT_SYMBOL(atapi_input_bytes);
+
+void atapi_output_bytes (ide_drive_t *drive, void *buffer, u32 bytecount)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+
+	++bytecount;
+#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
+	if (MACH_IS_ATARI || MACH_IS_Q40) {
+		/* Atari has a byte-swapped IDE interface */
+		outsw_swapw(IDE_DATA_REG, buffer, bytecount / 2);
+		return;
+	}
+#endif /* CONFIG_ATARI */
+	hwif->ata_output_data(drive, buffer, bytecount / 4);
+	if ((bytecount & 0x03) >= 2)
+		hwif->OUTSW(IDE_DATA_REG, ((u8*)buffer)+(bytecount & ~0x03), 1);
+}
+
+EXPORT_SYMBOL(atapi_output_bytes);
+
+/*
+ * Beginning of Taskfile OPCODE Library and feature sets.
+ */
+void ide_fix_driveid (struct hd_driveid *id)
+{
+#ifndef __LITTLE_ENDIAN
+# ifdef __BIG_ENDIAN
+	int i;
+	u16 *stringcast;
+
+	id->config         = __le16_to_cpu(id->config);
+	id->cyls           = __le16_to_cpu(id->cyls);
+	id->reserved2      = __le16_to_cpu(id->reserved2);
+	id->heads          = __le16_to_cpu(id->heads);
+	id->track_bytes    = __le16_to_cpu(id->track_bytes);
+	id->sector_bytes   = __le16_to_cpu(id->sector_bytes);
+	id->sectors        = __le16_to_cpu(id->sectors);
+	id->vendor0        = __le16_to_cpu(id->vendor0);
+	id->vendor1        = __le16_to_cpu(id->vendor1);
+	id->vendor2        = __le16_to_cpu(id->vendor2);
+	stringcast = (u16 *)&id->serial_no[0];
+	for (i = 0; i < (20/2); i++)
+		stringcast[i] = __le16_to_cpu(stringcast[i]);
+	id->buf_type       = __le16_to_cpu(id->buf_type);
+	id->buf_size       = __le16_to_cpu(id->buf_size);
+	id->ecc_bytes      = __le16_to_cpu(id->ecc_bytes);
+	stringcast = (u16 *)&id->fw_rev[0];
+	for (i = 0; i < (8/2); i++)
+		stringcast[i] = __le16_to_cpu(stringcast[i]);
+	stringcast = (u16 *)&id->model[0];
+	for (i = 0; i < (40/2); i++)
+		stringcast[i] = __le16_to_cpu(stringcast[i]);
+	id->dword_io       = __le16_to_cpu(id->dword_io);
+	id->reserved50     = __le16_to_cpu(id->reserved50);
+	id->field_valid    = __le16_to_cpu(id->field_valid);
+	id->cur_cyls       = __le16_to_cpu(id->cur_cyls);
+	id->cur_heads      = __le16_to_cpu(id->cur_heads);
+	id->cur_sectors    = __le16_to_cpu(id->cur_sectors);
+	id->cur_capacity0  = __le16_to_cpu(id->cur_capacity0);
+	id->cur_capacity1  = __le16_to_cpu(id->cur_capacity1);
+	id->lba_capacity   = __le32_to_cpu(id->lba_capacity);
+	id->dma_1word      = __le16_to_cpu(id->dma_1word);
+	id->dma_mword      = __le16_to_cpu(id->dma_mword);
+	id->eide_pio_modes = __le16_to_cpu(id->eide_pio_modes);
+	id->eide_dma_min   = __le16_to_cpu(id->eide_dma_min);
+	id->eide_dma_time  = __le16_to_cpu(id->eide_dma_time);
+	id->eide_pio       = __le16_to_cpu(id->eide_pio);
+	id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy);
+	for (i = 0; i < 2; ++i)
+		id->words69_70[i] = __le16_to_cpu(id->words69_70[i]);
+	for (i = 0; i < 4; ++i)
+		id->words71_74[i] = __le16_to_cpu(id->words71_74[i]);
+	id->queue_depth    = __le16_to_cpu(id->queue_depth);
+	for (i = 0; i < 4; ++i)
+		id->words76_79[i] = __le16_to_cpu(id->words76_79[i]);
+	id->major_rev_num  = __le16_to_cpu(id->major_rev_num);
+	id->minor_rev_num  = __le16_to_cpu(id->minor_rev_num);
+	id->command_set_1  = __le16_to_cpu(id->command_set_1);
+	id->command_set_2  = __le16_to_cpu(id->command_set_2);
+	id->cfsse          = __le16_to_cpu(id->cfsse);
+	id->cfs_enable_1   = __le16_to_cpu(id->cfs_enable_1);
+	id->cfs_enable_2   = __le16_to_cpu(id->cfs_enable_2);
+	id->csf_default    = __le16_to_cpu(id->csf_default);
+	id->dma_ultra      = __le16_to_cpu(id->dma_ultra);
+	id->trseuc         = __le16_to_cpu(id->trseuc);
+	id->trsEuc         = __le16_to_cpu(id->trsEuc);
+	id->CurAPMvalues   = __le16_to_cpu(id->CurAPMvalues);
+	id->mprc           = __le16_to_cpu(id->mprc);
+	id->hw_config      = __le16_to_cpu(id->hw_config);
+	id->acoustic       = __le16_to_cpu(id->acoustic);
+	id->msrqs          = __le16_to_cpu(id->msrqs);
+	id->sxfert         = __le16_to_cpu(id->sxfert);
+	id->sal            = __le16_to_cpu(id->sal);
+	id->spg            = __le32_to_cpu(id->spg);
+	id->lba_capacity_2 = __le64_to_cpu(id->lba_capacity_2);
+	for (i = 0; i < 22; i++)
+		id->words104_125[i]   = __le16_to_cpu(id->words104_125[i]);
+	id->last_lun       = __le16_to_cpu(id->last_lun);
+	id->word127        = __le16_to_cpu(id->word127);
+	id->dlf            = __le16_to_cpu(id->dlf);
+	id->csfo           = __le16_to_cpu(id->csfo);
+	for (i = 0; i < 26; i++)
+		id->words130_155[i] = __le16_to_cpu(id->words130_155[i]);
+	id->word156        = __le16_to_cpu(id->word156);
+	for (i = 0; i < 3; i++)
+		id->words157_159[i] = __le16_to_cpu(id->words157_159[i]);
+	id->cfa_power      = __le16_to_cpu(id->cfa_power);
+	for (i = 0; i < 14; i++)
+		id->words161_175[i] = __le16_to_cpu(id->words161_175[i]);
+	for (i = 0; i < 31; i++)
+		id->words176_205[i] = __le16_to_cpu(id->words176_205[i]);
+	for (i = 0; i < 48; i++)
+		id->words206_254[i] = __le16_to_cpu(id->words206_254[i]);
+	id->integrity_word  = __le16_to_cpu(id->integrity_word);
+# else
+#  error "Please fix <asm/byteorder.h>"
+# endif
+#endif
+}
+
+EXPORT_SYMBOL(ide_fix_driveid);
+
+void ide_fixstring (u8 *s, const int bytecount, const int byteswap)
+{
+	u8 *p = s, *end = &s[bytecount & ~1]; /* bytecount must be even */
+
+	if (byteswap) {
+		/* convert from big-endian to host byte order */
+		for (p = end ; p != s;) {
+			unsigned short *pp = (unsigned short *) (p -= 2);
+			*pp = ntohs(*pp);
+		}
+	}
+	/* strip leading blanks */
+	while (s != end && *s == ' ')
+		++s;
+	/* compress internal blanks and strip trailing blanks */
+	while (s != end && *s) {
+		if (*s++ != ' ' || (s != end && *s && *s != ' '))
+			*p++ = *(s-1);
+	}
+	/* wipe out trailing garbage */
+	while (p != end)
+		*p++ = '\0';
+}
+
+EXPORT_SYMBOL(ide_fixstring);
+
+/*
+ * Needed for PCI irq sharing
+ */
+int drive_is_ready (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 stat			= 0;
+
+	if (drive->waiting_for_dma)
+		return hwif->ide_dma_test_irq(drive);
+
+#if 0
+	/* need to guarantee 400ns since last command was issued */
+	udelay(1);
+#endif
+
+#ifdef CONFIG_IDEPCI_SHARE_IRQ
+	/*
+	 * We do a passive status test under shared PCI interrupts on
+	 * cards that truly share the ATA side interrupt, but may also share
+	 * an interrupt with another pci card/device.  We make no assumptions
+	 * about possible isa-pnp and pci-pnp issues yet.
+	 */
+	if (IDE_CONTROL_REG)
+		stat = hwif->INB(IDE_ALTSTATUS_REG);
+	else
+#endif /* CONFIG_IDEPCI_SHARE_IRQ */
+		/* Note: this may clear a pending IRQ!! */
+		stat = hwif->INB(IDE_STATUS_REG);
+
+	if (stat & BUSY_STAT)
+		/* drive busy:  definitely not interrupting */
+		return 0;
+
+	/* drive ready: *might* be interrupting */
+	return 1;
+}
+
+EXPORT_SYMBOL(drive_is_ready);
+
+/*
+ * Global for All, and taken from ide-pmac.c. Can be called
+ * with spinlock held & IRQs disabled, so don't schedule !
+ */
+int wait_for_ready (ide_drive_t *drive, int timeout)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 stat			= 0;
+
+	while(--timeout) {
+		stat = hwif->INB(IDE_STATUS_REG);
+		if (!(stat & BUSY_STAT)) {
+			if (drive->ready_stat == 0)
+				break;
+			else if ((stat & drive->ready_stat)||(stat & ERR_STAT))
+				break;
+		}
+		mdelay(1);
+	}
+	if ((stat & ERR_STAT) || timeout <= 0) {
+		if (stat & ERR_STAT) {
+			printk(KERN_ERR "%s: wait_for_ready, "
+				"error status: %x\n", drive->name, stat);
+		}
+		return 1;
+	}
+	return 0;
+}
+
+EXPORT_SYMBOL(wait_for_ready);
+
+/*
+ * This routine busy-waits for the drive status to be not "busy".
+ * It then checks the status for all of the "good" bits and none
+ * of the "bad" bits, and if all is okay it returns 0.  All other
+ * cases return 1 after invoking ide_error() -- caller should just return.
+ *
+ * This routine should get fixed to not hog the cpu during extra long waits..
+ * That could be done by busy-waiting for the first jiffy or two, and then
+ * setting a timer to wake up at half second intervals thereafter,
+ * until timeout is achieved, before timing out.
+ */
+int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, u8 good, u8 bad, unsigned long timeout)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	u8 stat;
+	int i;
+	unsigned long flags;
+ 
+	/* bail early if we've exceeded max_failures */
+	if (drive->max_failures && (drive->failures > drive->max_failures)) {
+		*startstop = ide_stopped;
+		return 1;
+	}
+
+	udelay(1);	/* spec allows drive 400ns to assert "BUSY" */
+	if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {
+		local_irq_set(flags);
+		timeout += jiffies;
+		while ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {
+			if (time_after(jiffies, timeout)) {
+				local_irq_restore(flags);
+				*startstop = DRIVER(drive)->error(drive, "status timeout", stat);
+				return 1;
+			}
+		}
+		local_irq_restore(flags);
+	}
+	/*
+	 * Allow status to settle, then read it again.
+	 * A few rare drives vastly violate the 400ns spec here,
+	 * so we'll wait up to 10usec for a "good" status
+	 * rather than expensively fail things immediately.
+	 * This fix courtesy of Matthew Faupel & Niccolo Rigacci.
+	 */
+	for (i = 0; i < 10; i++) {
+		udelay(1);
+		if (OK_STAT((stat = hwif->INB(IDE_STATUS_REG)), good, bad))
+			return 0;
+	}
+	*startstop = DRIVER(drive)->error(drive, "status error", stat);
+	return 1;
+}
+
+EXPORT_SYMBOL(ide_wait_stat);
+
+/*
+ *  All hosts that use the 80c ribbon must use!
+ *  The name is derived from upper byte of word 93 and the 80c ribbon.
+ */
+u8 eighty_ninty_three (ide_drive_t *drive)
+{
+#if 0
+	if (!HWIF(drive)->udma_four)
+		return 0;
+
+	if (drive->id->major_rev_num) {
+		int hssbd = 0;
+		int i;
+		/*
+		 * Determime highest Supported SPEC
+		 */
+		for (i=1; i<=15; i++)
+			if (drive->id->major_rev_num & (1<<i))
+				hssbd++;
+
+		switch (hssbd) {
+			case 7:
+			case 6:
+			case 5:
+		/* ATA-4 and older do not support above Ultra 33 */
+			default:
+				return 0;
+		}
+	}
+
+	return ((u8) (
+#ifndef CONFIG_IDEDMA_IVB
+		(drive->id->hw_config & 0x4000) &&
+#endif /* CONFIG_IDEDMA_IVB */
+		 (drive->id->hw_config & 0x6000)) ? 1 : 0);
+
+#else
+
+	return ((u8) ((HWIF(drive)->udma_four) &&
+#ifndef CONFIG_IDEDMA_IVB
+			(drive->id->hw_config & 0x4000) &&
+#endif /* CONFIG_IDEDMA_IVB */
+			(drive->id->hw_config & 0x6000)) ? 1 : 0);
+#endif
+}
+
+EXPORT_SYMBOL(eighty_ninty_three);
+
+int ide_ata66_check (ide_drive_t *drive, ide_task_t *args)
+{
+	if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
+	    (args->tfRegister[IDE_SECTOR_OFFSET] > XFER_UDMA_2) &&
+	    (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER)) {
+#ifndef CONFIG_IDEDMA_IVB
+		if ((drive->id->hw_config & 0x6000) == 0) {
+#else /* !CONFIG_IDEDMA_IVB */
+		if (((drive->id->hw_config & 0x2000) == 0) ||
+		    ((drive->id->hw_config & 0x4000) == 0)) {
+#endif /* CONFIG_IDEDMA_IVB */
+			printk("%s: Speed warnings UDMA 3/4/5 is not "
+				"functional.\n", drive->name);
+			return 1;
+		}
+		if (!HWIF(drive)->udma_four) {
+			printk("%s: Speed warnings UDMA 3/4/5 is not "
+				"functional.\n",
+				HWIF(drive)->name);
+			return 1;
+		}
+	}
+	return 0;
+}
+
+EXPORT_SYMBOL(ide_ata66_check);
+
+/*
+ * Backside of HDIO_DRIVE_CMD call of SETFEATURES_XFER.
+ * 1 : Safe to update drive->id DMA registers.
+ * 0 : OOPs not allowed.
+ */
+int set_transfer (ide_drive_t *drive, ide_task_t *args)
+{
+	if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
+	    (args->tfRegister[IDE_SECTOR_OFFSET] >= XFER_SW_DMA_0) &&
+	    (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER) &&
+	    (drive->id->dma_ultra ||
+	     drive->id->dma_mword ||
+	     drive->id->dma_1word))
+		return 1;
+
+	return 0;
+}
+
+EXPORT_SYMBOL(set_transfer);
+
+u8 ide_auto_reduce_xfer (ide_drive_t *drive)
+{
+	if (!drive->crc_count)
+		return drive->current_speed;
+	drive->crc_count = 0;
+
+	switch(drive->current_speed) {
+		case XFER_UDMA_7:	return XFER_UDMA_6;
+		case XFER_UDMA_6:	return XFER_UDMA_5;
+		case XFER_UDMA_5:	return XFER_UDMA_4;
+		case XFER_UDMA_4:	return XFER_UDMA_3;
+		case XFER_UDMA_3:	return XFER_UDMA_2;
+		case XFER_UDMA_2:	return XFER_UDMA_1;
+		case XFER_UDMA_1:	return XFER_UDMA_0;
+			/*
+			 * OOPS we do not goto non Ultra DMA modes
+			 * without iCRC's available we force
+			 * the system to PIO and make the user
+			 * invoke the ATA-1 ATA-2 DMA modes.
+			 */
+		case XFER_UDMA_0:
+		default:		return XFER_PIO_4;
+	}
+}
+
+EXPORT_SYMBOL(ide_auto_reduce_xfer);
+
+/*
+ * Update the 
+ */
+int ide_driveid_update (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id;
+#if 0
+	id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC);
+	if (!id)
+		return 0;
+
+	taskfile_lib_get_identify(drive, (char *)&id);
+
+	ide_fix_driveid(id);
+	if (id) {
+		drive->id->dma_ultra = id->dma_ultra;
+		drive->id->dma_mword = id->dma_mword;
+		drive->id->dma_1word = id->dma_1word;
+		/* anything more ? */
+		kfree(id);
+	}
+	return 1;
+#else
+	/*
+	 * Re-read drive->id for possible DMA mode
+	 * change (copied from ide-probe.c)
+	 */
+	unsigned long timeout, flags;
+
+	SELECT_MASK(drive, 1);
+	if (IDE_CONTROL_REG)
+		hwif->OUTB(drive->ctl,IDE_CONTROL_REG);
+	ide_delay_50ms();
+	hwif->OUTB(WIN_IDENTIFY, IDE_COMMAND_REG);
+	timeout = jiffies + WAIT_WORSTCASE;
+	do {
+		if (time_after(jiffies, timeout)) {
+			SELECT_MASK(drive, 0);
+			return 0;	/* drive timed-out */
+		}
+		ide_delay_50ms();	/* give drive a breather */
+	} while (hwif->INB(IDE_ALTSTATUS_REG) & BUSY_STAT);
+	ide_delay_50ms();	/* wait for IRQ and DRQ_STAT */
+	if (!OK_STAT(hwif->INB(IDE_STATUS_REG),DRQ_STAT,BAD_R_STAT)) {
+		SELECT_MASK(drive, 0);
+		printk("%s: CHECK for good STATUS\n", drive->name);
+		return 0;
+	}
+	local_irq_save(flags);
+	SELECT_MASK(drive, 0);
+	id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC);
+	if (!id) {
+		local_irq_restore(flags);
+		return 0;
+	}
+	ata_input_data(drive, id, SECTOR_WORDS);
+	(void) hwif->INB(IDE_STATUS_REG);	/* clear drive IRQ */
+	local_irq_enable();
+	local_irq_restore(flags);
+	ide_fix_driveid(id);
+	if (id) {
+		drive->id->dma_ultra = id->dma_ultra;
+		drive->id->dma_mword = id->dma_mword;
+		drive->id->dma_1word = id->dma_1word;
+		/* anything more ? */
+		kfree(id);
+	}
+
+	return 1;
+#endif
+}
+
+EXPORT_SYMBOL(ide_driveid_update);
+
+/*
+ * Similar to ide_wait_stat(), except it never calls ide_error internally.
+ * This is a kludge to handle the new ide_config_drive_speed() function,
+ * and should not otherwise be used anywhere.  Eventually, the tuneproc's
+ * should be updated to return ide_startstop_t, in which case we can get
+ * rid of this abomination again.  :)   -ml
+ *
+ * It is gone..........
+ *
+ * const char *msg == consider adding for verbose errors.
+ */
+int ide_config_drive_speed (ide_drive_t *drive, u8 speed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	int	i, error	= 1;
+	u8 stat;
+
+//	while (HWGROUP(drive)->busy)
+//		ide_delay_50ms();
+
+#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
+	hwif->ide_dma_host_off(drive);
+#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
+
+	/*
+	 * Don't use ide_wait_cmd here - it will
+	 * attempt to set_geometry and recalibrate,
+	 * but for some reason these don't work at
+	 * this point (lost interrupt).
+	 */
+        /*
+         * Select the drive, and issue the SETFEATURES command
+         */
+	disable_irq(hwif->irq);	/* disable_irq_nosync ?? */
+	udelay(1);
+	SELECT_DRIVE(drive);
+	SELECT_MASK(drive, 0);
+	udelay(1);
+	if (IDE_CONTROL_REG)
+		hwif->OUTB(drive->ctl | 2, IDE_CONTROL_REG);
+	hwif->OUTB(speed, IDE_NSECTOR_REG);
+	hwif->OUTB(SETFEATURES_XFER, IDE_FEATURE_REG);
+	hwif->OUTB(WIN_SETFEATURES, IDE_COMMAND_REG);
+	if ((IDE_CONTROL_REG) && (drive->quirk_list == 2))
+		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
+	udelay(1);
+	/*
+	 * Wait for drive to become non-BUSY
+	 */
+	if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {
+		unsigned long flags, timeout;
+		local_irq_set(flags);
+		timeout = jiffies + WAIT_CMD;
+		while ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {
+			if (time_after(jiffies, timeout))
+				break;
+		}
+		local_irq_restore(flags);
+	}
+
+	/*
+	 * Allow status to settle, then read it again.
+	 * A few rare drives vastly violate the 400ns spec here,
+	 * so we'll wait up to 10usec for a "good" status
+	 * rather than expensively fail things immediately.
+	 * This fix courtesy of Matthew Faupel & Niccolo Rigacci.
+	 */
+	for (i = 0; i < 10; i++) {
+		udelay(1);
+		if (OK_STAT((stat = hwif->INB(IDE_STATUS_REG)), DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT)) {
+			error = 0;
+			break;
+		}
+	}
+
+	SELECT_MASK(drive, 0);
+
+	enable_irq(hwif->irq);
+
+	if (error) {
+		(void) ide_dump_status(drive, "set_drive_speed_status", stat);
+		return error;
+	}
+
+	drive->id->dma_ultra &= ~0xFF00;
+	drive->id->dma_mword &= ~0x0F00;
+	drive->id->dma_1word &= ~0x0F00;
+
+#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
+	if (speed >= XFER_SW_DMA_0)
+		hwif->ide_dma_host_on(drive);
+	else
+		hwif->ide_dma_off_quietly(drive);
+#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
+
+	switch(speed) {
+		case XFER_UDMA_7:   drive->id->dma_ultra |= 0x8080; break;
+		case XFER_UDMA_6:   drive->id->dma_ultra |= 0x4040; break;
+		case XFER_UDMA_5:   drive->id->dma_ultra |= 0x2020; break;
+		case XFER_UDMA_4:   drive->id->dma_ultra |= 0x1010; break;
+		case XFER_UDMA_3:   drive->id->dma_ultra |= 0x0808; break;
+		case XFER_UDMA_2:   drive->id->dma_ultra |= 0x0404; break;
+		case XFER_UDMA_1:   drive->id->dma_ultra |= 0x0202; break;
+		case XFER_UDMA_0:   drive->id->dma_ultra |= 0x0101; break;
+		case XFER_MW_DMA_2: drive->id->dma_mword |= 0x0404; break;
+		case XFER_MW_DMA_1: drive->id->dma_mword |= 0x0202; break;
+		case XFER_MW_DMA_0: drive->id->dma_mword |= 0x0101; break;
+		case XFER_SW_DMA_2: drive->id->dma_1word |= 0x0404; break;
+		case XFER_SW_DMA_1: drive->id->dma_1word |= 0x0202; break;
+		case XFER_SW_DMA_0: drive->id->dma_1word |= 0x0101; break;
+		default: break;
+	}
+	if (!drive->init_speed)
+		drive->init_speed = speed;
+	drive->current_speed = speed;
+	return error;
+}
+
+EXPORT_SYMBOL(ide_config_drive_speed);
+
+
+/*
+ * This should get invoked any time we exit the driver to
+ * wait for an interrupt response from a drive.  handler() points
+ * at the appropriate code to handle the next interrupt, and a
+ * timer is started to prevent us from waiting forever in case
+ * something goes wrong (see the ide_timer_expiry() handler later on).
+ *
+ * See also ide_execute_command
+ */
+void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler,
+		      unsigned int timeout, ide_expiry_t *expiry)
+{
+	unsigned long flags;
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	if (hwgroup->handler != NULL) {
+		printk(KERN_CRIT "%s: ide_set_handler: handler not null; "
+			"old=%p, new=%p\n",
+			drive->name, hwgroup->handler, handler);
+	}
+	hwgroup->handler	= handler;
+	hwgroup->expiry		= expiry;
+	hwgroup->timer.expires	= jiffies + timeout;
+	add_timer(&hwgroup->timer);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+EXPORT_SYMBOL(ide_set_handler);
+
+/**
+ *	ide_execute_command	-	execute an IDE command
+ *	@drive: IDE drive to issue the command against
+ *	@command: command byte to write
+ *	@handler: handler for next phase
+ *	@timeout: timeout for command
+ *	@expiry:  handler to run on timeout
+ *
+ *	Helper function to issue an IDE command. This handles the
+ *	atomicity requirements, command timing and ensures that the 
+ *	handler and IRQ setup do not race. All IDE command kick off
+ *	should go via this function or do equivalent locking.
+ */
+ 
+void ide_execute_command(ide_drive_t *drive, task_ioreg_t cmd, ide_handler_t *handler, unsigned timeout, ide_expiry_t *expiry)
+{
+	unsigned long flags;
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+	ide_hwif_t *hwif = HWIF(drive);
+	
+	spin_lock_irqsave(&io_request_lock, flags);
+	
+	if(hwgroup->handler)
+		BUG();
+	hwgroup->handler	= handler;
+	hwgroup->expiry		= expiry;
+	hwgroup->timer.expires	= jiffies + timeout;
+	add_timer(&hwgroup->timer);
+	hwif->OUTBSYNC(cmd, IDE_COMMAND_REG);
+	/* Drive takes 400nS to respond, we must avoid the IRQ being
+	   serviced before that. 
+	   
+	   FIXME: we could skip this delay with care on non shared
+	   devices 
+	*/
+	ndelay(400);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+EXPORT_SYMBOL(ide_execute_command);
+
+/* needed below */
+ide_startstop_t do_reset1 (ide_drive_t *, int);
+
+/*
+ * atapi_reset_pollfunc() gets invoked to poll the interface for completion every 50ms
+ * during an atapi drive reset operation. If the drive has not yet responded,
+ * and we have not yet hit our maximum waiting time, then the timer is restarted
+ * for another 50ms.
+ */
+static ide_startstop_t atapi_reset_pollfunc (ide_drive_t *drive)
+{
+	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 stat;
+
+	SELECT_DRIVE(drive);
+	udelay (10);
+
+	if (OK_STAT(stat = hwif->INB(IDE_STATUS_REG), 0, BUSY_STAT)) {
+		printk("%s: ATAPI reset complete\n", drive->name);
+	} else {
+		if (time_before(jiffies, hwgroup->poll_timeout)) {
+			if (HWGROUP(drive)->handler != NULL)
+				BUG();
+			ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL);
+			/* continue polling */
+			return ide_started;
+		}
+		/* end of polling */
+		hwgroup->poll_timeout = 0;
+		printk("%s: ATAPI reset timed-out, status=0x%02x\n",
+				drive->name, stat);
+		/* do it the old fashioned way */
+		return do_reset1(drive, 1);
+	}
+	/* done polling */
+	hwgroup->poll_timeout = 0;
+	return ide_stopped;
+}
+
+/*
+ * reset_pollfunc() gets invoked to poll the interface for completion every 50ms
+ * during an ide reset operation. If the drives have not yet responded,
+ * and we have not yet hit our maximum waiting time, then the timer is restarted
+ * for another 50ms.
+ */
+static ide_startstop_t reset_pollfunc (ide_drive_t *drive)
+{
+	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 tmp;
+
+	if (hwif->reset_poll != NULL) {
+		if (hwif->reset_poll(drive)) {
+			printk(KERN_ERR "%s: host reset_poll failure for %s.\n",
+				hwif->name, drive->name);
+			return ide_stopped;
+		}
+	}
+
+	if (!OK_STAT(tmp = hwif->INB(IDE_STATUS_REG), 0, BUSY_STAT)) {
+		if (time_before(jiffies, hwgroup->poll_timeout)) {
+			if (HWGROUP(drive)->handler != NULL)
+				BUG();
+			ide_set_handler(drive, &reset_pollfunc, HZ/20, NULL);
+			/* continue polling */
+			return ide_started;
+		}
+		printk("%s: reset timed-out, status=0x%02x\n", hwif->name, tmp);
+		drive->failures++;
+	} else  {
+		printk("%s: reset: ", hwif->name);
+		if ((tmp = hwif->INB(IDE_ERROR_REG)) == 1) {
+			printk("success\n");
+			drive->failures = 0;
+		} else {
+			drive->failures++;
+#if FANCY_STATUS_DUMPS
+			printk("master: ");
+			switch (tmp & 0x7f) {
+				case 1: printk("passed");
+					break;
+				case 2: printk("formatter device error");
+					break;
+				case 3: printk("sector buffer error");
+					break;
+				case 4: printk("ECC circuitry error");
+					break;
+				case 5: printk("controlling MPU error");
+					break;
+				default:printk("error (0x%02x?)", tmp);
+			}
+			if (tmp & 0x80)
+				printk("; slave: failed");
+			printk("\n");
+#else
+			printk("failed\n");
+#endif /* FANCY_STATUS_DUMPS */
+		}
+	}
+	hwgroup->poll_timeout = 0;	/* done polling */
+	return ide_stopped;
+}
+
+void check_dma_crc (ide_drive_t *drive)
+{
+	if (drive->crc_count) {
+		(void) HWIF(drive)->ide_dma_off_quietly(drive);
+		ide_set_xfer_rate(drive, ide_auto_reduce_xfer(drive));
+		if (drive->current_speed >= XFER_SW_DMA_0)
+			(void) HWIF(drive)->ide_dma_on(drive);
+	} else {
+		(void) HWIF(drive)->ide_dma_off(drive);
+	}
+}
+
+void pre_reset (ide_drive_t *drive)
+{
+	if (drive->driver != NULL)
+		DRIVER(drive)->pre_reset(drive);
+
+	if (!drive->keep_settings) {
+		if (drive->using_dma) {
+			check_dma_crc(drive);
+		} else {
+			drive->unmask = 0;
+			drive->io_32bit = 0;
+		}
+		return;
+	}
+	if (drive->using_dma)
+		check_dma_crc(drive);
+
+	if (HWIF(drive)->pre_reset != NULL)
+		HWIF(drive)->pre_reset(drive);
+
+}
+
+/*
+ * do_reset1() attempts to recover a confused drive by resetting it.
+ * Unfortunately, resetting a disk drive actually resets all devices on
+ * the same interface, so it can really be thought of as resetting the
+ * interface rather than resetting the drive.
+ *
+ * ATAPI devices have their own reset mechanism which allows them to be
+ * individually reset without clobbering other devices on the same interface.
+ *
+ * Unfortunately, the IDE interface does not generate an interrupt to let
+ * us know when the reset operation has finished, so we must poll for this.
+ * Equally poor, though, is the fact that this may a very long time to complete,
+ * (up to 30 seconds worstcase).  So, instead of busy-waiting here for it,
+ * we set a timer to poll at 50ms intervals.
+ */
+ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
+{
+	unsigned int unit;
+	unsigned long flags;
+	ide_hwif_t *hwif = HWIF(drive);
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+
+	local_irq_save(flags);
+
+	/* For an ATAPI device, first try an ATAPI SRST. */
+	if (drive->media != ide_disk && !do_not_try_atapi) {
+		pre_reset(drive);
+		SELECT_DRIVE(drive);
+		udelay (20);
+		hwif->OUTB(WIN_SRST, IDE_COMMAND_REG);
+		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+		if (HWGROUP(drive)->handler != NULL)
+			BUG();
+		ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL);
+		local_irq_restore(flags);
+		return ide_started;
+	}
+
+	/*
+	 * First, reset any device state data we were maintaining
+	 * for any of the drives on this interface.
+	 */
+	for (unit = 0; unit < MAX_DRIVES; ++unit)
+		pre_reset(&hwif->drives[unit]);
+
+#if OK_TO_RESET_CONTROLLER
+	if (!IDE_CONTROL_REG) {
+		local_irq_restore(flags);
+		return ide_stopped;
+	}
+
+# if 0
+        {
+		u8 control = hwif->INB(IDE_CONTROL_REG);
+		control |= 0x04;
+		hwif->OUTB(control,IDE_CONTROL_REG);
+		udelay(30);
+		control &= 0xFB;
+		hwif->OUTB(control, IDE_CONTROL_REG);
+	}
+# else
+	/*
+	 * Note that we also set nIEN while resetting the device,
+	 * to mask unwanted interrupts from the interface during the reset.
+	 * However, due to the design of PC hardware, this will cause an
+	 * immediate interrupt due to the edge transition it produces.
+	 * This single interrupt gives us a "fast poll" for drives that
+	 * recover from reset very quickly, saving us the first 50ms wait time.
+	 */
+	/* set SRST and nIEN */
+	hwif->OUTB(drive->ctl|6,IDE_CONTROL_REG);
+	/* more than enough time */
+	udelay(10);
+	if (drive->quirk_list == 2) {
+		/* clear SRST and nIEN */
+		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
+	} else {
+		/* clear SRST, leave nIEN */
+		hwif->OUTB(drive->ctl|2, IDE_CONTROL_REG);
+	}
+	/* more than enough time */
+	udelay(10);
+	hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	ide_set_handler(drive, &reset_pollfunc, HZ/20, NULL);
+# endif
+	/*
+	 * Some weird controller like resetting themselves to a strange
+	 * state when the disks are reset this way. At least, the Winbond
+	 * 553 documentation says that
+	 */
+	if (hwif->resetproc != NULL) {
+		hwif->resetproc(drive);
+
+# if 0
+		if (drive->failures) {
+			local_irq_restore(flags);
+			return ide_stopped;
+		}
+# endif
+	}
+
+#endif	/* OK_TO_RESET_CONTROLLER */
+
+	local_irq_restore(flags);
+	return ide_started;
+}
+
+#if 0
+/*
+ * ide_do_reset() is the entry point to the drive/interface reset code.
+ */
+ide_startstop_t ide_do_reset (ide_drive_t *drive)
+{
+	return do_reset1(drive, 0);
+}
+#else
+/*
+ * ide_do_reset() is the entry point to the drive/interface reset code.
+ */
+ide_startstop_t ide_do_reset (ide_drive_t *drive)
+{
+	ide_startstop_t start_stop = ide_started;
+# if 0
+        u8 tmp_dma	= drive->using_dma;
+        u8 cspeed	= drive->current_speed;
+	u8 unmask	= drive->unmask;
+# endif
+
+	if (HWGROUP(drive)->handler != NULL) {
+		unsigned long flags;
+		spin_lock_irqsave(&io_request_lock, flags);
+		HWGROUP(drive)->handler = NULL;
+		del_timer(&HWGROUP(drive)->timer);
+		spin_unlock_irqrestore(&io_request_lock, flags);
+	}
+
+	start_stop = do_reset1(drive, 0);
+# if 0
+	/*
+	 * check for suspend-spindown flag,
+	 * to attempt a restart or spinup of device.
+	 */
+	if (drive->suspend_reset) {
+		/*
+		 * APM WAKE UP todo !!
+		 * int nogoodpower = 1;
+		 * while(nogoodpower) {
+		 * 	check_power1() or check_power2()
+		 * 	nogoodpower = 0;
+		 * }
+		 * HWIF(drive)->multiproc(drive);
+		 */
+# endif
+
+	return start_stop;
+}
+#endif
+
+EXPORT_SYMBOL(ide_do_reset);
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-lib.c linux-2.4.21-pre6/drivers/ide/ide-lib.c
--- linux-2.4.20/drivers/ide/ide-lib.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/ide-lib.c	2003-03-26 23:48:58.000000000 +0000
@@ -0,0 +1,439 @@
+#include <linux/config.h>
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/genhd.h>
+#include <linux/blkpg.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+
+#include <asm/byteorder.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+
+#include "ide_modes.h"
+
+/*
+ *	IDE library routines. These are plug in code that most 
+ *	drivers can use but occasionally may be weird enough
+ *	to want to do their own thing with
+ *
+ *	Add common non I/O op stuff here. Make sure it has proper
+ *	kernel-doc function headers or your patch will be rejected
+ */
+ 
+
+/**
+ *	ide_xfer_verbose	-	return IDE mode names
+ *	@xfer_rate: rate to name
+ *
+ *	Returns a constant string giving the name of the mode
+ *	requested.
+ */
+
+char *ide_xfer_verbose (u8 xfer_rate)
+{
+        switch(xfer_rate) {
+                case XFER_UDMA_7:	return("UDMA 7");
+                case XFER_UDMA_6:	return("UDMA 6");
+                case XFER_UDMA_5:	return("UDMA 5");
+                case XFER_UDMA_4:	return("UDMA 4");
+                case XFER_UDMA_3:	return("UDMA 3");
+                case XFER_UDMA_2:	return("UDMA 2");
+                case XFER_UDMA_1:	return("UDMA 1");
+                case XFER_UDMA_0:	return("UDMA 0");
+                case XFER_MW_DMA_2:	return("MW DMA 2");
+                case XFER_MW_DMA_1:	return("MW DMA 1");
+                case XFER_MW_DMA_0:	return("MW DMA 0");
+                case XFER_SW_DMA_2:	return("SW DMA 2");
+                case XFER_SW_DMA_1:	return("SW DMA 1");
+                case XFER_SW_DMA_0:	return("SW DMA 0");
+                case XFER_PIO_4:	return("PIO 4");
+                case XFER_PIO_3:	return("PIO 3");
+                case XFER_PIO_2:	return("PIO 2");
+                case XFER_PIO_1:	return("PIO 1");
+                case XFER_PIO_0:	return("PIO 0");
+                case XFER_PIO_SLOW:	return("PIO SLOW");
+                default:		return("XFER ERROR");
+        }
+}
+
+EXPORT_SYMBOL(ide_xfer_verbose);
+
+/**
+ *	ide_dma_speed	-	compute DMA speed
+ *	@drive: drive
+ *	@mode; intended mode
+ *
+ *	Checks the drive capabilities and returns the speed to use
+ *	for the transfer. Returns -1 if the requested mode is unknown
+ *	(eg PIO)
+ */
+ 
+u8 ide_dma_speed(ide_drive_t *drive, u8 mode)
+{
+	struct hd_driveid *id   = drive->id;
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 speed = 0;
+
+	if (drive->media != ide_disk && hwif->atapi_dma == 0)
+		return 0;
+
+	switch(mode) {
+		case 0x04:
+			if ((id->dma_ultra & 0x0040) &&
+			    (id->dma_ultra & hwif->ultra_mask))
+				{ speed = XFER_UDMA_6; break; }
+		case 0x03:
+			if ((id->dma_ultra & 0x0020) &&
+			    (id->dma_ultra & hwif->ultra_mask))
+				{ speed = XFER_UDMA_5; break; }
+		case 0x02:
+			if ((id->dma_ultra & 0x0010) &&
+			    (id->dma_ultra & hwif->ultra_mask))
+				{ speed = XFER_UDMA_4; break; }
+			if ((id->dma_ultra & 0x0008) &&
+			    (id->dma_ultra & hwif->ultra_mask))
+				{ speed = XFER_UDMA_3; break; }
+		case 0x01:
+			if ((id->dma_ultra & 0x0004) &&
+			    (id->dma_ultra & hwif->ultra_mask))
+				{ speed = XFER_UDMA_2; break; }
+			if ((id->dma_ultra & 0x0002) &&
+			    (id->dma_ultra & hwif->ultra_mask))
+				{ speed = XFER_UDMA_1; break; }
+			if ((id->dma_ultra & 0x0001) &&
+			    (id->dma_ultra & hwif->ultra_mask))
+				{ speed = XFER_UDMA_0; break; }
+		case 0x00:
+			if ((id->dma_mword & 0x0004) &&
+			    (id->dma_mword & hwif->mwdma_mask))
+				{ speed = XFER_MW_DMA_2; break; }
+			if ((id->dma_mword & 0x0002) &&
+			    (id->dma_mword & hwif->mwdma_mask))
+				{ speed = XFER_MW_DMA_1; break; }
+			if ((id->dma_mword & 0x0001) &&
+			    (id->dma_mword & hwif->mwdma_mask))
+				{ speed = XFER_MW_DMA_0; break; }
+			if ((id->dma_1word & 0x0004) &&
+			    (id->dma_1word & hwif->swdma_mask))
+				{ speed = XFER_SW_DMA_2; break; }
+			if ((id->dma_1word & 0x0002) &&
+			    (id->dma_1word & hwif->swdma_mask))
+				{ speed = XFER_SW_DMA_1; break; }
+			if ((id->dma_1word & 0x0001) &&
+			    (id->dma_1word & hwif->swdma_mask))
+				{ speed = XFER_SW_DMA_0; break; }
+	}
+
+//	printk("%s: %s: mode 0x%02x, speed 0x%02x\n",
+//		__FUNCTION__, drive->name, mode, speed);
+
+	return speed;
+}
+
+EXPORT_SYMBOL(ide_dma_speed);
+
+
+/**
+ *	ide_rate_filter		-	return best speed for mode
+ *	@mode: modes available
+ *	@speed: desired speed
+ *
+ *	Given the available DMA/UDMA mode this function returns
+ *	the best available speed at or below the speed requested.
+ */
+
+u8 ide_rate_filter (u8 mode, u8 speed) 
+{
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	static u8 speed_max[] = {
+		XFER_MW_DMA_2, XFER_UDMA_2, XFER_UDMA_4,
+		XFER_UDMA_5, XFER_UDMA_6
+	};
+
+//	printk("%s: mode 0x%02x, speed 0x%02x\n", __FUNCTION__, mode, speed);
+
+	/* So that we remember to update this if new modes appear */
+	if (mode > 4)
+		BUG();
+	return min(speed, speed_max[mode]);
+#else /* !CONFIG_BLK_DEV_IDEDMA */
+	return min(speed, XFER_PIO_4);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+}
+
+EXPORT_SYMBOL(ide_rate_filter);
+
+int ide_dma_enable (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	return ((int)	((((id->dma_ultra >> 8) & hwif->ultra_mask) ||
+			  ((id->dma_mword >> 8) & hwif->mwdma_mask) ||
+			  ((id->dma_1word >> 8) & hwif->swdma_mask)) ? 1 : 0));
+}
+
+EXPORT_SYMBOL(ide_dma_enable);
+
+const ide_pio_timings_t ide_pio_timings[6] = {
+	{ 70,	165,	600 },	/* PIO Mode 0 */
+	{ 50,	125,	383 },	/* PIO Mode 1 */
+	{ 30,	100,	240 },	/* PIO Mode 2 */
+	{ 30,	80,	180 },	/* PIO Mode 3 with IORDY */
+	{ 25,	70,	120 },	/* PIO Mode 4 with IORDY */
+	{ 20,	50,	100 }	/* PIO Mode 5 with IORDY (nonstandard) */
+};
+
+EXPORT_SYMBOL_GPL(ide_pio_timings);
+
+/*
+ * Black list. Some drives incorrectly report their maximal PIO mode,
+ * at least in respect to CMD640. Here we keep info on some known drives.
+ */
+static struct ide_pio_info {
+	const char	*name;
+	int		pio;
+} ide_pio_blacklist [] = {
+/*	{ "Conner Peripherals 1275MB - CFS1275A", 4 }, */
+	{ "Conner Peripherals 540MB - CFS540A", 3 },
+
+	{ "WDC AC2700",  3 },
+	{ "WDC AC2540",  3 },
+	{ "WDC AC2420",  3 },
+	{ "WDC AC2340",  3 },
+	{ "WDC AC2250",  0 },
+	{ "WDC AC2200",  0 },
+	{ "WDC AC21200", 4 },
+	{ "WDC AC2120",  0 },
+	{ "WDC AC2850",  3 },
+	{ "WDC AC1270",  3 },
+	{ "WDC AC1170",  1 },
+	{ "WDC AC1210",  1 },
+	{ "WDC AC280",   0 },
+/*	{ "WDC AC21000", 4 }, */
+	{ "WDC AC31000", 3 },
+	{ "WDC AC31200", 3 },
+/*	{ "WDC AC31600", 4 }, */
+
+	{ "Maxtor 7131 AT", 1 },
+	{ "Maxtor 7171 AT", 1 },
+	{ "Maxtor 7213 AT", 1 },
+	{ "Maxtor 7245 AT", 1 },
+	{ "Maxtor 7345 AT", 1 },
+	{ "Maxtor 7546 AT", 3 },
+	{ "Maxtor 7540 AV", 3 },
+
+	{ "SAMSUNG SHD-3121A", 1 },
+	{ "SAMSUNG SHD-3122A", 1 },
+	{ "SAMSUNG SHD-3172A", 1 },
+
+/*	{ "ST51080A", 4 },
+ *	{ "ST51270A", 4 },
+ *	{ "ST31220A", 4 },
+ *	{ "ST31640A", 4 },
+ *	{ "ST32140A", 4 },
+ *	{ "ST3780A",  4 },
+ */
+	{ "ST5660A",  3 },
+	{ "ST3660A",  3 },
+	{ "ST3630A",  3 },
+	{ "ST3655A",  3 },
+	{ "ST3391A",  3 },
+	{ "ST3390A",  1 },
+	{ "ST3600A",  1 },
+	{ "ST3290A",  0 },
+	{ "ST3144A",  0 },
+	{ "ST3491A",  1 },	/* reports 3, should be 1 or 2 (depending on */	
+				/* drive) according to Seagates FIND-ATA program */
+
+	{ "QUANTUM ELS127A", 0 },
+	{ "QUANTUM ELS170A", 0 },
+	{ "QUANTUM LPS240A", 0 },
+	{ "QUANTUM LPS210A", 3 },
+	{ "QUANTUM LPS270A", 3 },
+	{ "QUANTUM LPS365A", 3 },
+	{ "QUANTUM LPS540A", 3 },
+	{ "QUANTUM LIGHTNING 540A", 3 },
+	{ "QUANTUM LIGHTNING 730A", 3 },
+
+        { "QUANTUM FIREBALL_540", 3 }, /* Older Quantum Fireballs don't work */
+        { "QUANTUM FIREBALL_640", 3 }, 
+        { "QUANTUM FIREBALL_1080", 3 },
+        { "QUANTUM FIREBALL_1280", 3 },
+	{ NULL,	0 }
+};
+
+/**
+ *	ide_scan_pio_blacklist 	-	check for a blacklisted drive
+ *	@model: Drive model string
+ *
+ *	This routine searches the ide_pio_blacklist for an entry
+ *	matching the start/whole of the supplied model name.
+ *
+ *	Returns -1 if no match found.
+ *	Otherwise returns the recommended PIO mode from ide_pio_blacklist[].
+ */
+
+static int ide_scan_pio_blacklist (char *model)
+{
+	struct ide_pio_info *p;
+
+	for (p = ide_pio_blacklist; p->name != NULL; p++) {
+		if (strncmp(p->name, model, strlen(p->name)) == 0)
+			return p->pio;
+	}
+	return -1;
+}
+
+/**
+ *	ide_get_best_pio_mode	-	get PIO mode from drive
+ *	@driver: drive to consider
+ *	@mode_wanted: preferred mode
+ *	@max_mode: highest allowed
+ *	@d: pio data
+ *
+ *	This routine returns the recommended PIO settings for a given drive,
+ *	based on the drive->id information and the ide_pio_blacklist[].
+ *	This is used by most chipset support modules when "auto-tuning".
+ *
+ *	Drive PIO mode auto selection
+ */
+
+u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode, ide_pio_data_t *d)
+{
+	int pio_mode;
+	int cycle_time = 0;
+	int use_iordy = 0;
+	struct hd_driveid* id = drive->id;
+	int overridden  = 0;
+	int blacklisted = 0;
+
+	if (mode_wanted != 255) {
+		pio_mode = mode_wanted;
+	} else if (!drive->id) {
+		pio_mode = 0;
+	} else if ((pio_mode = ide_scan_pio_blacklist(id->model)) != -1) {
+		overridden = 1;
+		blacklisted = 1;
+		use_iordy = (pio_mode > 2);
+	} else {
+		pio_mode = id->tPIO;
+		if (pio_mode > 2) {	/* 2 is maximum allowed tPIO value */
+			pio_mode = 2;
+			overridden = 1;
+		}
+		if (id->field_valid & 2) {	  /* drive implements ATA2? */
+			if (id->capability & 8) { /* drive supports use_iordy? */
+				use_iordy = 1;
+				cycle_time = id->eide_pio_iordy;
+				if (id->eide_pio_modes & 7) {
+					overridden = 0;
+					if (id->eide_pio_modes & 4)
+						pio_mode = 5;
+					else if (id->eide_pio_modes & 2)
+						pio_mode = 4;
+					else
+						pio_mode = 3;
+				}
+			} else {
+				cycle_time = id->eide_pio;
+			}
+		}
+
+#if 0
+		if (drive->id->major_rev_num & 0x0004) printk("ATA-2 ");
+#endif
+
+		/*
+		 * Conservative "downgrade" for all pre-ATA2 drives
+		 */
+		if (pio_mode && pio_mode < 4) {
+			pio_mode--;
+			overridden = 1;
+#if 0
+			use_iordy = (pio_mode > 2);
+#endif
+			if (cycle_time && cycle_time < ide_pio_timings[pio_mode].cycle_time)
+				cycle_time = 0; /* use standard timing */
+		}
+	}
+	if (pio_mode > max_mode) {
+		pio_mode = max_mode;
+		cycle_time = 0;
+	}
+	if (d) {
+		d->pio_mode = pio_mode;
+		d->cycle_time = cycle_time ? cycle_time : ide_pio_timings[pio_mode].cycle_time;
+		d->use_iordy = use_iordy;
+		d->overridden = overridden;
+		d->blacklisted = blacklisted;
+	}
+	return pio_mode;
+}
+
+EXPORT_SYMBOL_GPL(ide_get_best_pio_mode);
+
+/**
+ *	ide_toggle_bounce	-	handle bounce buffering
+ *	@drive: drive to update
+ *	@on: on/off boolean
+ *
+ *	Enable or disable bounce buffering for the device. Drives move
+ *	between PIO and DMA and that changes the rules we need.
+ */
+ 
+void ide_toggle_bounce(ide_drive_t *drive, int on)
+{
+	u64 addr = BLK_BOUNCE_HIGH;	/* dma64_addr_t */
+
+	if (on && drive->media == ide_disk) {
+		if (!PCI_DMA_BUS_IS_PHYS)
+			addr = BLK_BOUNCE_ANY;
+		else
+			addr = HWIF(drive)->pci_dev->dma_mask;
+	}
+
+	blk_queue_bounce_limit(&drive->queue, addr);
+}
+
+EXPORT_SYMBOL(ide_toggle_bounce);
+
+
+/**
+ *	ide_set_xfer_rate	-	set transfer rate
+ *	@drive: drive to set
+ *	@speed: speed to attempt to set
+ *	
+ *	General helper for setting the speed of an IDE device. This
+ *	function knows about user enforced limits from the configuration
+ *	which speedproc() does not.  High level drivers should never
+ *	invoke speedproc() directly.
+ */
+ 
+int ide_set_xfer_rate(ide_drive_t *drive, u8 rate)
+{
+#ifndef CONFIG_BLK_DEV_IDEDMA
+	rate = min(rate, (u8) XFER_PIO_4);
+#endif
+	if(HWIF(drive)->speedproc)
+		return HWIF(drive)->speedproc(drive, rate);
+	else
+		return -1;
+}
+
+EXPORT_SYMBOL_GPL(ide_set_xfer_rate);
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-m8xx.c linux-2.4.21-pre6/drivers/ide/ide-m8xx.c
--- linux-2.4.20/drivers/ide/ide-m8xx.c	2002-02-25 19:37:57.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/ide-m8xx.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,857 +0,0 @@
-/*
- *  linux/drivers/ide/ide-m8xx.c
- *
- *  Copyright (C) 2000, 2001 Wolfgang Denk, wd@denx.de
- *  Modified for direct IDE interface
- *	by Thomas Lange, thomas@corelatus.com
- *  Modified for direct IDE interface on 8xx without using the PCMCIA
- *  controller
- *	by Steven.Scholz@imc-berlin.de
- *  Moved out of arch/ppc/kernel/m8xx_setup.c, other minor cleanups
- *	by Mathew Locke <mattl@mvista.com>
- */
-
-#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/stddef.h>
-#include <linux/unistd.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/user.h>
-#include <linux/a.out.h>
-#include <linux/tty.h>
-#include <linux/major.h>
-#include <linux/interrupt.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-#include <linux/blk.h>
-#include <linux/ioport.h>
-#include <linux/ide.h>
-#include <linux/bootmem.h>
-
-#include <asm/mpc8xx.h>
-#include <asm/mmu.h>
-#include <asm/processor.h>
-#include <asm/residual.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/ide.h>
-#include <asm/8xx_immap.h>
-#include <asm/machdep.h>
-#include <asm/irq.h>
-
-#include "ide_modes.h"
-static int identify  (volatile unsigned char *p);
-static void print_fixed (volatile unsigned char *p);
-static void print_funcid (int func);
-static int check_ide_device (unsigned long base);
-
-static void ide_interrupt_ack (void *dev);
-static void m8xx_ide_tuneproc(ide_drive_t *drive, byte pio);
-
-typedef	struct ide_ioport_desc {
-	unsigned long	base_off;		/* Offset to PCMCIA memory	*/
-	ide_ioreg_t	reg_off[IDE_NR_PORTS];	/* controller register offsets	*/
-	int		irq;			/* IRQ				*/
-} ide_ioport_desc_t;
-
-ide_ioport_desc_t ioport_dsc[MAX_HWIFS] = {
-#ifdef IDE0_BASE_OFFSET
-	{ IDE0_BASE_OFFSET,
-	    {
-		IDE0_DATA_REG_OFFSET,
-		IDE0_ERROR_REG_OFFSET,
-		IDE0_NSECTOR_REG_OFFSET,
-		IDE0_SECTOR_REG_OFFSET,
-		IDE0_LCYL_REG_OFFSET,
-		IDE0_HCYL_REG_OFFSET,
-		IDE0_SELECT_REG_OFFSET,
-		IDE0_STATUS_REG_OFFSET,
-		IDE0_CONTROL_REG_OFFSET,
-		IDE0_IRQ_REG_OFFSET,
-	    },
-	    IDE0_INTERRUPT,
-	},
-#ifdef IDE1_BASE_OFFSET
-	{ IDE1_BASE_OFFSET,
-	    {
-		IDE1_DATA_REG_OFFSET,
-		IDE1_ERROR_REG_OFFSET,
-		IDE1_NSECTOR_REG_OFFSET,
-		IDE1_SECTOR_REG_OFFSET,
-		IDE1_LCYL_REG_OFFSET,
-		IDE1_HCYL_REG_OFFSET,
-		IDE1_SELECT_REG_OFFSET,
-		IDE1_STATUS_REG_OFFSET,
-		IDE1_CONTROL_REG_OFFSET,
-		IDE1_IRQ_REG_OFFSET,
-	    },
-	    IDE1_INTERRUPT,
-	},
-#endif /* IDE1_BASE_OFFSET */
-#endif	/* IDE0_BASE_OFFSET */
-};
-
-ide_pio_timings_t ide_pio_clocks[6];
-int hold_time[6] =  {30, 20, 15, 10, 10, 10 };   /* PIO Mode 5 with IORDY (nonstandard) */
-
-/*
- * Warning: only 1 (ONE) PCMCIA slot supported here,
- * which must be correctly initialized by the firmware (PPCBoot).
- */
-static int _slot_ = -1;			/* will be read from PCMCIA registers   */
-
-/* Make clock cycles and always round up */
-#define PCMCIA_MK_CLKS( t, T ) (( (t) * ((T)/1000000) + 999U ) / 1000U )
-
-
-
-/*
- * IDE stuff.
- */
-static int
-m8xx_ide_default_irq(ide_ioreg_t base)
-{
-#ifdef CONFIG_BLK_DEV_MPC8xx_IDE
-	if (base >= MAX_HWIFS)
-		return 0;
-
-	printk("[%d] m8xx_ide_default_irq %d\n",__LINE__,ioport_dsc[base].irq);
-	
-	return (ioport_dsc[base].irq);
-#else
-        return 9;
-#endif
-}
-
-static ide_ioreg_t
-m8xx_ide_default_io_base(int index)
-{
-        return index;
-}
-
-#define M8XX_PCMCIA_CD2(slot)      (0x10000000 >> (slot << 4))
-#define M8XX_PCMCIA_CD1(slot)      (0x08000000 >> (slot << 4))
-
-/*
- * The TQM850L hardware has two pins swapped! Grrrrgh!
- */
-#ifdef	CONFIG_TQM850L
-#define __MY_PCMCIA_GCRX_CXRESET	PCMCIA_GCRX_CXOE
-#define __MY_PCMCIA_GCRX_CXOE		PCMCIA_GCRX_CXRESET
-#else
-#define __MY_PCMCIA_GCRX_CXRESET	PCMCIA_GCRX_CXRESET
-#define __MY_PCMCIA_GCRX_CXOE		PCMCIA_GCRX_CXOE
-#endif
-
-#if defined(CONFIG_BLK_DEV_MPC8xx_IDE) && defined(CONFIG_IDE_8xx_PCCARD)
-#define PCMCIA_SCHLVL IDE0_INTERRUPT	/* Status Change Interrupt Level	*/
-static int pcmcia_schlvl = PCMCIA_SCHLVL;
-#endif
-
-/*
- * See include/linux/ide.h for definition of hw_regs_t (p, base)
- */
-
-/*
- * m8xx_ide_init_hwif_ports for a direct IDE interface _using_
- */
-#if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT)
-static void
-m8xx_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, 
-		ide_ioreg_t ctrl_port, int *irq)
-{
-	ide_ioreg_t *p = hw->io_ports;
-	int i;
-
-	typedef struct {
-		ulong br;
-		ulong or;
-	} pcmcia_win_t;
-	volatile pcmcia_win_t *win;
-	volatile pcmconf8xx_t *pcmp;
-
-	uint *pgcrx;
-	u32 pcmcia_phy_base;
-	u32 pcmcia_phy_end;
-	static unsigned long pcmcia_base = 0;
-	unsigned long base;
-
-	*p = 0;
-	if (irq)
-		*irq = 0;
-
-	pcmp = (pcmconf8xx_t *)(&(((immap_t *)IMAP_ADDR)->im_pcmcia));
-
-	if (!pcmcia_base) {
-                /*
-                 * Read out PCMCIA registers. Since the reset values
-                 * are undefined, we sure hope that they have been
-                 * set up by firmware
-		 */
-
-		/* Scan all registers for valid settings */
-		pcmcia_phy_base = 0xFFFFFFFF;
-		pcmcia_phy_end = 0;
-		/* br0 is start of brX and orX regs */
-		win = (pcmcia_win_t *) \
-			(&(((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0));
-		for (i = 0; i < 8; i++) {
-			if (win->or & 1) {	/* This bank is marked as valid */
-				if (win->br < pcmcia_phy_base) {
-					pcmcia_phy_base = win->br;
-				}
-				if ((win->br + PCMCIA_MEM_SIZE) > pcmcia_phy_end) {
-					pcmcia_phy_end  = win->br + PCMCIA_MEM_SIZE;
-				}
-				/* Check which slot that has been defined */
-				_slot_ = (win->or >> 2) & 1;
-
-			}					/* Valid bank */
-			win++;
-		}						/* for */
-
-		printk ("PCMCIA slot %c: phys mem %08x...%08x (size %08x)\n",
-			'A' + _slot_,
-			pcmcia_phy_base, pcmcia_phy_end,
-			pcmcia_phy_end - pcmcia_phy_base);
-
-		pcmcia_base=(unsigned long)ioremap(pcmcia_phy_base,
-						   pcmcia_phy_end-pcmcia_phy_base);
-
-#ifdef DEBUG
-		printk ("PCMCIA virt base: %08lx\n", pcmcia_base);
-#endif
-		/* Compute clock cycles for PIO timings */
-		for (i=0; i<6; ++i) {
-			bd_t	*binfo = (bd_t *)__res;
-
-			hold_time[i]   =
-				PCMCIA_MK_CLKS (hold_time[i],
-						binfo->bi_busfreq);
-			ide_pio_clocks[i].setup_time  =
-				PCMCIA_MK_CLKS (ide_pio_timings[i].setup_time,
-						binfo->bi_busfreq);
-			ide_pio_clocks[i].active_time =
-				PCMCIA_MK_CLKS (ide_pio_timings[i].active_time,
-						binfo->bi_busfreq);
-			ide_pio_clocks[i].cycle_time  =
-				PCMCIA_MK_CLKS (ide_pio_timings[i].cycle_time,
-						binfo->bi_busfreq);
-#if 0
-			printk ("PIO mode %d timings: %d/%d/%d => %d/%d/%d\n",
-				i,
-				ide_pio_clocks[i].setup_time,
-				ide_pio_clocks[i].active_time,
-				ide_pio_clocks[i].hold_time,
-				ide_pio_clocks[i].cycle_time,
-				ide_pio_timings[i].setup_time,
-				ide_pio_timings[i].active_time,
-				ide_pio_timings[i].hold_time,
-				ide_pio_timings[i].cycle_time);
-#endif
-		}
-	}
-
-	if (data_port >= MAX_HWIFS)
-		return;
-
-	if (_slot_ == -1) {
-		printk ("PCMCIA slot has not been defined! Using A as default\n");
-		_slot_ = 0;
-	}
-
-#ifdef CONFIG_IDE_8xx_PCCARD
-
-#ifdef DEBUG
-	printk ("PIPR = 0x%08X  slot %c ==> mask = 0x%X\n",
-		pcmp->pcmc_pipr,
-		'A' + _slot_,
-		M8XX_PCMCIA_CD1(_slot_) | M8XX_PCMCIA_CD2(_slot_) );
-#endif /* DEBUG */
-
-	if (pcmp->pcmc_pipr & (M8XX_PCMCIA_CD1(_slot_)|M8XX_PCMCIA_CD2(_slot_))) {
-		printk ("No card in slot %c: PIPR=%08x\n",
-			'A' + _slot_, (u32) pcmp->pcmc_pipr);
-		return;		/* No card in slot */
-	}
-
-	check_ide_device (pcmcia_base);
-
-#endif	/* CONFIG_IDE_8xx_PCCARD */
-
-	base = pcmcia_base + ioport_dsc[data_port].base_off;
-#ifdef DEBUG
-	printk ("base: %08x + %08x = %08x\n",
-			pcmcia_base, ioport_dsc[data_port].base_off, base);
-#endif
-
-	for (i = 0; i < IDE_NR_PORTS; ++i) {
-#ifdef DEBUG
-		printk ("port[%d]: %08x + %08x = %08x\n",
-			i,
-			base,
-			ioport_dsc[data_port].reg_off[i],
-			i, base + ioport_dsc[data_port].reg_off[i]);
-#endif
-	 	*p++ = base + ioport_dsc[data_port].reg_off[i];
-	}
-
-	if (irq) {
-#ifdef CONFIG_IDE_8xx_PCCARD
-		unsigned int reg;
-
-		*irq = ioport_dsc[data_port].irq;
-		if (_slot_)
-			pgcrx = &((immap_t *) IMAP_ADDR)->im_pcmcia.pcmc_pgcrb;
-		else
-			pgcrx = &((immap_t *) IMAP_ADDR)->im_pcmcia.pcmc_pgcra;
-
-		reg = *pgcrx;
-		reg |= mk_int_int_mask (pcmcia_schlvl) << 24;
-		reg |= mk_int_int_mask (pcmcia_schlvl) << 16;
-		*pgcrx = reg;
-#else	/* direct connected IDE drive, i.e. external IRQ, not the PCMCIA irq */
-		*irq = ioport_dsc[data_port].irq;
-#endif	/* CONFIG_IDE_8xx_PCCARD */
-	}
-
-	/* register routine to tune PIO mode */
-	ide_hwifs[data_port].tuneproc = m8xx_ide_tuneproc;
-
-	hw->ack_intr = (ide_ack_intr_t *) ide_interrupt_ack;
-	/* Enable Harddisk Interrupt,
-	 * and make it edge sensitive
-	 */
-	/* (11-18) Set edge detect for irq, no wakeup from low power mode */
-	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_siel |=
-					(0x80000000 >> ioport_dsc[data_port].irq);
-
-#ifdef CONFIG_IDE_8xx_PCCARD
-	/* Make sure we dont get garbage irq */
-	((immap_t *) IMAP_ADDR)->im_pcmcia.pcmc_pscr = 0xFFFF;
-
-	/* Enable falling edge irq */
-	pcmp->pcmc_per = 0x100000 >> (16 * _slot_);
-#endif	/* CONFIG_IDE_8xx_PCCARD */
-}	/* m8xx_ide_init_hwif_ports() using 8xx internal PCMCIA interface */
-#endif /* CONFIG_IDE_8xx_PCCARD || CONFIG_IDE_8xx_DIRECT */
-
-/*
- * m8xx_ide_init_hwif_ports for a direct IDE interface _not_ using
- * MPC8xx's internal PCMCIA interface
- */
-#if defined(CONFIG_IDE_EXT_DIRECT)
-void m8xx_ide_init_hwif_ports (hw_regs_t *hw,
-	ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
-{
-	ide_ioreg_t *p = hw->io_ports;
-	int i;
-
-	u32 ide_phy_base;
-	u32 ide_phy_end;
-	static unsigned long ide_base = 0;
-	unsigned long base;
-
-	*p = 0;
-	if (irq)
-		*irq = 0;
-
-	if (!ide_base) {
-
-		/* TODO:
-		 * - add code to read ORx, BRx
-		 */
-		ide_phy_base = CFG_ATA_BASE_ADDR;
-		ide_phy_end  = CFG_ATA_BASE_ADDR + 0x200;
-
-		printk ("IDE phys mem : %08x...%08x (size %08x)\n",
-			ide_phy_base, ide_phy_end,
-			ide_phy_end - ide_phy_base);
-		
-		ide_base=(unsigned long)ioremap(ide_phy_base,
-						ide_phy_end-ide_phy_base);
-
-#ifdef DEBUG
-		printk ("IDE virt base: %08lx\n", ide_base);
-#endif
-	}
-
-	if (data_port >= MAX_HWIFS)
-		return;
-
-	base = ide_base + ioport_dsc[data_port].base_off;
-#ifdef DEBUG
-	printk ("base: %08x + %08x = %08x\n",
-		ide_base, ioport_dsc[data_port].base_off, base);
-#endif
-
-	for (i = 0; i < IDE_NR_PORTS; ++i) {
-#ifdef DEBUG
-		printk ("port[%d]: %08x + %08x = %08x\n",
-			i,
-			base,
-			ioport_dsc[data_port].reg_off[i],
-			i, base + ioport_dsc[data_port].reg_off[i]);
-#endif
-	 	*p++ = base + ioport_dsc[data_port].reg_off[i];
-	}
-
-	if (irq) {
-		/* direct connected IDE drive, i.e. external IRQ */
-		*irq = ioport_dsc[data_port].irq;
-	}
-
-	/* register routine to tune PIO mode */
-	ide_hwifs[data_port].tuneproc = m8xx_ide_tuneproc;
-
-	hw->ack_intr = (ide_ack_intr_t *) ide_interrupt_ack;
-	/* Enable Harddisk Interrupt,
-	 * and make it edge sensitive
-	 */
-	/* (11-18) Set edge detect for irq, no wakeup from low power mode */
-	((immap_t *) IMAP_ADDR)->im_siu_conf.sc_siel |=
-			(0x80000000 >> ioport_dsc[data_port].irq);
-}	/* m8xx_ide_init_hwif_ports() for CONFIG_IDE_8xx_DIRECT */ 
-
-#endif	/* CONFIG_IDE_8xx_DIRECT */
-
-
-/* -------------------------------------------------------------------- */
-
-
-/* PCMCIA Timing */
-#ifndef	PCMCIA_SHT
-#define PCMCIA_SHT(t)	((t & 0x0F)<<16)	/* Strobe Hold  Time 	*/
-#define PCMCIA_SST(t)	((t & 0x0F)<<12)	/* Strobe Setup Time	*/
-#define PCMCIA_SL(t) ((t==32) ? 0 : ((t & 0x1F)<<7)) /* Strobe Length	*/
-#endif
-
-
-/* Calculate PIO timings */
-static void
-m8xx_ide_tuneproc(ide_drive_t *drive, byte pio)
-{
-	ide_pio_data_t d;
-#if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT)
-	volatile pcmconf8xx_t	*pcmp;
-	ulong timing, mask, reg;
-#endif
-
-	pio = ide_get_best_pio_mode(drive, pio, 4, &d);
-
-#if 1
-	printk("%s[%d] %s: best PIO mode: %d\n",
-		__FILE__,__LINE__,__FUNCTION__, pio);
-#endif
-
-#if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT)
-	pcmp = (pcmconf8xx_t *)(&(((immap_t *)IMAP_ADDR)->im_pcmcia));
-
-	mask = ~(PCMCIA_SHT(0xFF) | PCMCIA_SST(0xFF) | PCMCIA_SL(0xFF));
-
-	timing  = PCMCIA_SHT(hold_time[pio]  )
-		| PCMCIA_SST(ide_pio_clocks[pio].setup_time )
-		| PCMCIA_SL (ide_pio_clocks[pio].active_time)
-		;
-
-#if 1
-	printk ("Setting timing bits 0x%08lx in PCMCIA controller\n", timing);
-#endif
-	if ((reg = pcmp->pcmc_por0 & mask) != 0)
-		pcmp->pcmc_por0 = reg | timing;
-
-	if ((reg = pcmp->pcmc_por1 & mask) != 0)
-		pcmp->pcmc_por1 = reg | timing;
-
-	if ((reg = pcmp->pcmc_por2 & mask) != 0)
-		pcmp->pcmc_por2 = reg | timing;
-
-	if ((reg = pcmp->pcmc_por3 & mask) != 0)
-		pcmp->pcmc_por3 = reg | timing;
-
-	if ((reg = pcmp->pcmc_por4 & mask) != 0)
-		pcmp->pcmc_por4 = reg | timing;
-
-	if ((reg = pcmp->pcmc_por5 & mask) != 0)
-		pcmp->pcmc_por5 = reg | timing;
-
-	if ((reg = pcmp->pcmc_por6 & mask) != 0)
-		pcmp->pcmc_por6 = reg | timing;
-
-	if ((reg = pcmp->pcmc_por7 & mask) != 0)
-		pcmp->pcmc_por7 = reg | timing;
-
-#elif defined(CONFIG_IDE_EXT_DIRECT)
-
-	printk("%s[%d] %s: not implemented yet!\n",
-		__FILE__,__LINE__,__FUNCTION__);
-#endif /* defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_PCMCIA */
-}
-
-static void
-ide_interrupt_ack (void *dev)
-{
-#ifdef CONFIG_IDE_8xx_PCCARD
-	u_int pscr, pipr;
-
-#if (PCMCIA_SOCKETS_NO == 2)
-	u_int _slot_;
-#endif
-
-	/* get interrupt sources */
-
-	pscr = ((volatile immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr;
-	pipr = ((volatile immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pipr;
-
-	/*
-	 * report only if both card detect signals are the same
-	 * not too nice done,
-	 * we depend on that CD2 is the bit to the left of CD1...
-	 */
-
-	if(_slot_==-1){
-	  printk("PCMCIA slot has not been defined! Using A as default\n");
-	  _slot_=0;
-	}
-
-	if(((pipr & M8XX_PCMCIA_CD2(_slot_)) >> 1) ^
-	   (pipr & M8XX_PCMCIA_CD1(_slot_))         ) {
-	  printk ("card detect interrupt\n");
-	}
-	/* clear the interrupt sources */
-	((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr = pscr;
-
-#else /* ! CONFIG_IDE_8xx_PCCARD */
-	/*
-	 * Only CONFIG_IDE_8xx_PCCARD is using the interrupt of the
-	 * MPC8xx's PCMCIA controller, so there is nothing to be done here
-	 * for CONFIG_IDE_8xx_DIRECT and CONFIG_IDE_EXT_DIRECT.
-	 * The interrupt is handled somewhere else.	-- Steven
-	 */
-#endif /* CONFIG_IDE_8xx_PCCARD */
-}
-
-
-
-/*
- * CIS Tupel codes
- */
-#define CISTPL_NULL		0x00
-#define CISTPL_DEVICE		0x01
-#define CISTPL_LONGLINK_CB	0x02
-#define CISTPL_INDIRECT		0x03
-#define CISTPL_CONFIG_CB	0x04
-#define CISTPL_CFTABLE_ENTRY_CB 0x05
-#define CISTPL_LONGLINK_MFC	0x06
-#define CISTPL_BAR		0x07
-#define CISTPL_PWR_MGMNT	0x08
-#define CISTPL_EXTDEVICE	0x09
-#define CISTPL_CHECKSUM		0x10
-#define CISTPL_LONGLINK_A	0x11
-#define CISTPL_LONGLINK_C	0x12
-#define CISTPL_LINKTARGET	0x13
-#define CISTPL_NO_LINK		0x14
-#define CISTPL_VERS_1		0x15
-#define CISTPL_ALTSTR		0x16
-#define CISTPL_DEVICE_A		0x17
-#define CISTPL_JEDEC_C		0x18
-#define CISTPL_JEDEC_A		0x19
-#define CISTPL_CONFIG		0x1a
-#define CISTPL_CFTABLE_ENTRY	0x1b
-#define CISTPL_DEVICE_OC	0x1c
-#define CISTPL_DEVICE_OA	0x1d
-#define CISTPL_DEVICE_GEO	0x1e
-#define CISTPL_DEVICE_GEO_A	0x1f
-#define CISTPL_MANFID		0x20
-#define CISTPL_FUNCID		0x21
-#define CISTPL_FUNCE		0x22
-#define CISTPL_SWIL		0x23
-#define CISTPL_END		0xff
-
-/*
- * CIS Function ID codes
- */
-#define CISTPL_FUNCID_MULTI	0x00
-#define CISTPL_FUNCID_MEMORY	0x01
-#define CISTPL_FUNCID_SERIAL	0x02
-#define CISTPL_FUNCID_PARALLEL	0x03
-#define CISTPL_FUNCID_FIXED	0x04
-#define CISTPL_FUNCID_VIDEO	0x05
-#define CISTPL_FUNCID_NETWORK	0x06
-#define CISTPL_FUNCID_AIMS	0x07
-#define CISTPL_FUNCID_SCSI	0x08
-
-/*
- * Fixed Disk FUNCE codes
- */
-#define CISTPL_IDE_INTERFACE	0x01
-
-#define CISTPL_FUNCE_IDE_IFACE	0x01
-#define CISTPL_FUNCE_IDE_MASTER	0x02
-#define CISTPL_FUNCE_IDE_SLAVE	0x03
-
-/* First feature byte */
-#define CISTPL_IDE_SILICON	0x04
-#define CISTPL_IDE_UNIQUE	0x08
-#define CISTPL_IDE_DUAL		0x10
-
-/* Second feature byte */
-#define CISTPL_IDE_HAS_SLEEP	0x01
-#define CISTPL_IDE_HAS_STANDBY	0x02
-#define CISTPL_IDE_HAS_IDLE	0x04
-#define CISTPL_IDE_LOW_POWER	0x08
-#define CISTPL_IDE_REG_INHIBIT	0x10
-#define CISTPL_IDE_HAS_INDEX	0x20
-#define CISTPL_IDE_IOIS16	0x40
-
-
-/* -------------------------------------------------------------------- */
-
-
-#define	MAX_TUPEL_SZ	512
-#define MAX_FEATURES	4
-
-static int check_ide_device (unsigned long base)
-{
-	volatile unsigned char *ident = NULL;
-	volatile unsigned char *feature_p[MAX_FEATURES];
-	volatile unsigned char *p, *start;
-	int n_features = 0;
-	unsigned char func_id = ~0;
-	unsigned char code, len;
-	unsigned short config_base = 0;
-	int found = 0;
-	int i;
-
-#ifdef DEBUG
-	printk ("PCMCIA MEM: %08lX\n", base);
-#endif
-	start = p = (volatile unsigned char *) base;
-
-	while ((p - start) < MAX_TUPEL_SZ) {
-
-		code = *p; p += 2;
-
-		if (code == 0xFF) { /* End of chain */
-			break;
-		}
-
-		len = *p; p += 2;
-#ifdef	DEBUG_PCMCIA
-		{ volatile unsigned char *q = p;
-			printk ("\nTuple code %02x  length %d\n\tData:",
-				code, len);
-
-			for (i = 0; i < len; ++i) {
-				printk (" %02x", *q);
-				q+= 2;
-			}
-		}
-#endif	/* DEBUG_PCMCIA */
-		switch (code) {
-		case CISTPL_VERS_1:
-			ident = p + 4;
-			break;
-		case CISTPL_FUNCID:
-			func_id = *p;
-			break;
-		case CISTPL_FUNCE:
-			if (n_features < MAX_FEATURES)
-				feature_p[n_features++] = p;
-			break;
-		case CISTPL_CONFIG:
-			config_base = (*(p+6) << 8) + (*(p+4));
-		default:
-			break;
-		}
-		p += 2 * len;
-	}
-
-	found = identify (ident);
-
-	if (func_id != ((unsigned char)~0)) {
-		print_funcid (func_id);
-
-		if (func_id == CISTPL_FUNCID_FIXED)
-			found = 1;
-		else
-			return (1);	/* no disk drive */
-	}
-
-	for (i=0; i<n_features; ++i) {
-		print_fixed (feature_p[i]);
-	}
-
-	if (!found) {
-		printk ("unknown card type\n");
-		return (1);
-	}
-
-	/* set level mode irq and I/O mapped device in config reg*/
-	*((unsigned char *)(base + config_base)) = 0x41;
-
-	return (0);
-}
-
-/* ------------------------------------------------------------------------- */
-
-static void print_funcid (int func)
-{
-	switch (func) {
-	case CISTPL_FUNCID_MULTI:
-		printk (" Multi-Function");
-		break;
-	case CISTPL_FUNCID_MEMORY:
-		printk (" Memory");
-		break;
-	case CISTPL_FUNCID_SERIAL:
-		printk (" Serial Port");
-		break;
-	case CISTPL_FUNCID_PARALLEL:
-		printk (" Parallel Port");
-		break;
-	case CISTPL_FUNCID_FIXED:
-		printk (" Fixed Disk");
-		break;
-	case CISTPL_FUNCID_VIDEO:
-		printk (" Video Adapter");
-		break;
-	case CISTPL_FUNCID_NETWORK:
-		printk (" Network Adapter");
-		break;
-	case CISTPL_FUNCID_AIMS:
-		printk (" AIMS Card");
-		break;
-	case CISTPL_FUNCID_SCSI:
-		printk (" SCSI Adapter");
-		break;
-	default:
-		printk (" Unknown");
-		break;
-	}
-	printk (" Card\n");
-}
-
-/* ------------------------------------------------------------------------- */
-
-static void print_fixed (volatile unsigned char *p)
-{
-	if (p == NULL)
-		return;
-
-	switch (*p) {
-	case CISTPL_FUNCE_IDE_IFACE:
-	    {   unsigned char iface = *(p+2);
-
-		printk ((iface == CISTPL_IDE_INTERFACE) ? " IDE" : " unknown");
-		printk (" interface ");
-		break;
-	    }
-	case CISTPL_FUNCE_IDE_MASTER:
-	case CISTPL_FUNCE_IDE_SLAVE:
-	    {   unsigned char f1 = *(p+2);
-		unsigned char f2 = *(p+4);
-
-		printk ((f1 & CISTPL_IDE_SILICON) ? " [silicon]" : " [rotating]");
-
-		if (f1 & CISTPL_IDE_UNIQUE)
-			printk (" [unique]");
-
-		printk ((f1 & CISTPL_IDE_DUAL) ? " [dual]" : " [single]");
-
-		if (f2 & CISTPL_IDE_HAS_SLEEP)
-			printk (" [sleep]");
-
-		if (f2 & CISTPL_IDE_HAS_STANDBY)
-			printk (" [standby]");
-
-		if (f2 & CISTPL_IDE_HAS_IDLE)
-			printk (" [idle]");
-
-		if (f2 & CISTPL_IDE_LOW_POWER)
-			printk (" [low power]");
-
-		if (f2 & CISTPL_IDE_REG_INHIBIT)
-			printk (" [reg inhibit]");
-
-		if (f2 & CISTPL_IDE_HAS_INDEX)
-			printk (" [index]");
-
-		if (f2 & CISTPL_IDE_IOIS16)
-			printk (" [IOis16]");
-
-		break;
-	    }
-	}
-	printk ("\n");
-}
-
-/* ------------------------------------------------------------------------- */
-
-
-#define MAX_IDENT_CHARS		64
-#define	MAX_IDENT_FIELDS	4
-
-static unsigned char *known_cards[] = {
-	"ARGOSY PnPIDE D5",
-	NULL
-};
-
-static int identify  (volatile unsigned char *p)
-{
-	unsigned char id_str[MAX_IDENT_CHARS];
-	unsigned char data;
-	unsigned char *t;
-	unsigned char **card;
-	int i, done;
-
-	if (p == NULL)
-		return (0);	/* Don't know */
-
-	t = id_str;
-	done =0;
-
-	for (i=0; i<=4 && !done; ++i, p+=2) {
-		while ((data = *p) != '\0') {
-			if (data == 0xFF) {
-				done = 1;
-				break;
-			}
-			*t++ = data;
-			if (t == &id_str[MAX_IDENT_CHARS-1]) {
-				done = 1;
-				break;
-			}
-			p += 2;
-		}
-		if (!done)
-			*t++ = ' ';
-	}
-	*t = '\0';
-	while (--t > id_str) {
-		if (*t == ' ')
-			*t = '\0';
-		else
-			break;
-	}
-	printk ("Card ID: %s\n", id_str);
-
-	for (card=known_cards; *card; ++card) {
-		if (strcmp(*card, id_str) == 0) {	/* found! */
-			return (1);
-		}
-	}
-
-	return (0);	/* don't know */
-}
-
-void m8xx_ide_init(void)
-{
-	ppc_ide_md.default_irq          = m8xx_ide_default_irq;
-	ppc_ide_md.default_io_base      = m8xx_ide_default_io_base;
-	ppc_ide_md.ide_init_hwif        = m8xx_ide_init_hwif_ports;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-pci.c linux-2.4.21-pre6/drivers/ide/ide-pci.c
--- linux-2.4.20/drivers/ide/ide-pci.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/ide-pci.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,1016 +0,0 @@
-/*
- *  linux/drivers/ide/ide-pci.c		Version 1.05	June 9, 2000
- *
- *  Copyright (c) 1998-2000  Andre Hedrick <andre@linux-ide.org>
- *
- *  Copyright (c) 1995-1998  Mark Lord
- *  May be copied or modified under the terms of the GNU General Public License
- */
-
-/*
- *  This module provides support for automatic detection and
- *  configuration of all PCI IDE interfaces present in a system.  
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#define DEVID_PIIXa	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371FB_0})
-#define DEVID_PIIXb	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371FB_1})
-#define DEVID_MPIIX	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371MX})
-#define DEVID_PIIX3	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371SB_1})
-#define DEVID_PIIX4	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371AB})
-#define DEVID_ICH0	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801AB_1})
-#define DEVID_PIIX4E2	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82443MX_1})
-#define DEVID_ICH	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801AA_1})
-#define DEVID_PIIX4U2	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82372FB_1})
-#define DEVID_PIIX4NX	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82451NX})
-#define DEVID_ICH2	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801BA_9})
-#define DEVID_ICH2M	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801BA_8})
-#define DEVID_ICH3M	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801CA_10})
-#define DEVID_ICH3	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801CA_11})
-#define DEVID_ICH4	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801DB_11})
-#define DEVID_CICH	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801E_11})
-#define DEVID_VIA_IDE	((ide_pci_devid_t){PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C561})
-#define DEVID_MR_IDE	((ide_pci_devid_t){PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C576_1})
-#define DEVID_VP_IDE	((ide_pci_devid_t){PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C586_1})
-#define DEVID_PDC20246	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246})
-#define DEVID_PDC20262	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20262})
-#define DEVID_PDC20265	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20265})
-#define DEVID_PDC20267	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20267})
-#define DEVID_PDC20268  ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268})
-#define DEVID_PDC20270  ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20270})
-#define DEVID_PDC20269	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20269})
-#define DEVID_PDC20275	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20275})
-#define DEVID_PDC20276	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20276})
-#define DEVID_RZ1000	((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH,  PCI_DEVICE_ID_PCTECH_RZ1000})
-#define DEVID_RZ1001	((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH,  PCI_DEVICE_ID_PCTECH_RZ1001})
-#define DEVID_SAMURAI	((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH,  PCI_DEVICE_ID_PCTECH_SAMURAI_IDE})
-#define DEVID_CMD640	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_640})
-#define DEVID_CMD643	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_643})
-#define DEVID_CMD646	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_646})
-#define DEVID_CMD648	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_648})
-#define DEVID_CMD649	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_649})
-#define DEVID_CMD680	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_680})
-#define DEVID_SIS5513	((ide_pci_devid_t){PCI_VENDOR_ID_SI,      PCI_DEVICE_ID_SI_5513})
-#define DEVID_OPTI621	((ide_pci_devid_t){PCI_VENDOR_ID_OPTI,    PCI_DEVICE_ID_OPTI_82C621})
-#define DEVID_OPTI621V	((ide_pci_devid_t){PCI_VENDOR_ID_OPTI,    PCI_DEVICE_ID_OPTI_82C558})
-#define DEVID_OPTI621X	((ide_pci_devid_t){PCI_VENDOR_ID_OPTI,    PCI_DEVICE_ID_OPTI_82C825})
-#define DEVID_TRM290	((ide_pci_devid_t){PCI_VENDOR_ID_TEKRAM,  PCI_DEVICE_ID_TEKRAM_DC290})
-#define DEVID_NS87410	((ide_pci_devid_t){PCI_VENDOR_ID_NS,      PCI_DEVICE_ID_NS_87410})
-#define DEVID_NS87415	((ide_pci_devid_t){PCI_VENDOR_ID_NS,      PCI_DEVICE_ID_NS_87415})
-#define DEVID_HT6565	((ide_pci_devid_t){PCI_VENDOR_ID_HOLTEK,  PCI_DEVICE_ID_HOLTEK_6565})
-#define DEVID_AEC6210	((ide_pci_devid_t){PCI_VENDOR_ID_ARTOP,   PCI_DEVICE_ID_ARTOP_ATP850UF})
-#define DEVID_AEC6260	((ide_pci_devid_t){PCI_VENDOR_ID_ARTOP,   PCI_DEVICE_ID_ARTOP_ATP860})
-#define DEVID_AEC6260R	((ide_pci_devid_t){PCI_VENDOR_ID_ARTOP,   PCI_DEVICE_ID_ARTOP_ATP860R})
-#define DEVID_W82C105	((ide_pci_devid_t){PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105})
-#define DEVID_UM8673F	((ide_pci_devid_t){PCI_VENDOR_ID_UMC,     PCI_DEVICE_ID_UMC_UM8673F})
-#define DEVID_UM8886A	((ide_pci_devid_t){PCI_VENDOR_ID_UMC,     PCI_DEVICE_ID_UMC_UM8886A})
-#define DEVID_UM8886BF	((ide_pci_devid_t){PCI_VENDOR_ID_UMC,     PCI_DEVICE_ID_UMC_UM8886BF})
-#define DEVID_HPT34X	((ide_pci_devid_t){PCI_VENDOR_ID_TTI,     PCI_DEVICE_ID_TTI_HPT343})
-#define DEVID_HPT366	((ide_pci_devid_t){PCI_VENDOR_ID_TTI,     PCI_DEVICE_ID_TTI_HPT366})
-#define DEVID_ALI15X3	((ide_pci_devid_t){PCI_VENDOR_ID_AL,      PCI_DEVICE_ID_AL_M5229})
-#define DEVID_CY82C693	((ide_pci_devid_t){PCI_VENDOR_ID_CONTAQ,  PCI_DEVICE_ID_CONTAQ_82C693})
-#define DEVID_HINT	((ide_pci_devid_t){0x3388,                0x8013})
-#define DEVID_CS5530	((ide_pci_devid_t){PCI_VENDOR_ID_CYRIX,   PCI_DEVICE_ID_CYRIX_5530_IDE})
-#define DEVID_AMD7401	((ide_pci_devid_t){PCI_VENDOR_ID_AMD,     PCI_DEVICE_ID_AMD_COBRA_7401})
-#define DEVID_AMD7409	((ide_pci_devid_t){PCI_VENDOR_ID_AMD,     PCI_DEVICE_ID_AMD_VIPER_7409})
-#define DEVID_AMD7411	((ide_pci_devid_t){PCI_VENDOR_ID_AMD,     PCI_DEVICE_ID_AMD_VIPER_7411})
-#define DEVID_AMD7441	((ide_pci_devid_t){PCI_VENDOR_ID_AMD,     PCI_DEVICE_ID_AMD_VIPER_7441})
-#define DEVID_PDCADMA	((ide_pci_devid_t){PCI_VENDOR_ID_PDC,     PCI_DEVICE_ID_PDC_1841})
-#define DEVID_SLC90E66	((ide_pci_devid_t){PCI_VENDOR_ID_EFAR,    PCI_DEVICE_ID_EFAR_SLC90E66_1})
-#define DEVID_OSB4	((ide_pci_devid_t){PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE})
-#define DEVID_CSB5	((ide_pci_devid_t){PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE})
-#define DEVID_ITE8172G	((ide_pci_devid_t){PCI_VENDOR_ID_ITE,     PCI_DEVICE_ID_ITE_IT8172G})
-
-#define	IDE_IGNORE	((void *)-1)
-#define IDE_NO_DRIVER	((void *)-2)
-
-#ifdef CONFIG_BLK_DEV_AEC62XX
-extern unsigned int pci_init_aec62xx(struct pci_dev *, const char *);
-extern unsigned int ata66_aec62xx(ide_hwif_t *);
-extern void ide_init_aec62xx(ide_hwif_t *);
-extern void ide_dmacapable_aec62xx(ide_hwif_t *, unsigned long);
-#define PCI_AEC62XX	&pci_init_aec62xx
-#define ATA66_AEC62XX	&ata66_aec62xx
-#define INIT_AEC62XX	&ide_init_aec62xx
-#define DMA_AEC62XX	&ide_dmacapable_aec62xx
-#else
-#define PCI_AEC62XX	NULL
-#define ATA66_AEC62XX	NULL
-#define INIT_AEC62XX	IDE_NO_DRIVER
-#define DMA_AEC62XX	NULL
-#endif
-
-#ifdef CONFIG_BLK_DEV_ALI15X3
-extern unsigned int pci_init_ali15x3(struct pci_dev *, const char *);
-extern unsigned int ata66_ali15x3(ide_hwif_t *);
-extern void ide_init_ali15x3(ide_hwif_t *);
-extern void ide_dmacapable_ali15x3(ide_hwif_t *, unsigned long);
-#define PCI_ALI15X3	&pci_init_ali15x3
-#define ATA66_ALI15X3	&ata66_ali15x3
-#define INIT_ALI15X3	&ide_init_ali15x3
-#define DMA_ALI15X3	&ide_dmacapable_ali15x3
-#else
-#define PCI_ALI15X3	NULL
-#define ATA66_ALI15X3	NULL
-#define INIT_ALI15X3	IDE_NO_DRIVER
-#define DMA_ALI15X3	NULL
-#endif
-
-#ifdef CONFIG_BLK_DEV_AMD74XX
-extern unsigned int pci_init_amd74xx(struct pci_dev *, const char *);
-extern unsigned int ata66_amd74xx(ide_hwif_t *);
-extern void ide_init_amd74xx(ide_hwif_t *);
-extern void ide_dmacapable_amd74xx(ide_hwif_t *, unsigned long);
-#define PCI_AMD74XX	&pci_init_amd74xx
-#define ATA66_AMD74XX	&ata66_amd74xx
-#define INIT_AMD74XX	&ide_init_amd74xx
-#define DMA_AMD74XX	&ide_dmacapable_amd74xx
-#else
-#define PCI_AMD74XX	NULL
-#define ATA66_AMD74XX	NULL
-#define INIT_AMD74XX	IDE_NO_DRIVER
-#define DMA_AMD74XX	NULL
-#endif
-
-#ifdef CONFIG_BLK_DEV_CMD64X
-extern unsigned int pci_init_cmd64x(struct pci_dev *, const char *);
-extern unsigned int ata66_cmd64x(ide_hwif_t *);
-extern void ide_init_cmd64x(ide_hwif_t *);
-extern void ide_dmacapable_cmd64x(ide_hwif_t *, unsigned long);
-#define PCI_CMD64X	&pci_init_cmd64x
-#define ATA66_CMD64X	&ata66_cmd64x
-#define INIT_CMD64X	&ide_init_cmd64x
-#else
-#define PCI_CMD64X	NULL
-#define ATA66_CMD64X	NULL
-#ifdef __sparc_v9__
-#define INIT_CMD64X	IDE_IGNORE
-#else
-#define INIT_CMD64X	IDE_NO_DRIVER
-#endif
-#endif
-
-#ifdef CONFIG_BLK_DEV_CY82C693
-extern unsigned int pci_init_cy82c693(struct pci_dev *, const char *);
-extern void ide_init_cy82c693(ide_hwif_t *);
-#define PCI_CY82C693	&pci_init_cy82c693
-#define INIT_CY82C693	&ide_init_cy82c693
-#else
-#define PCI_CY82C693	NULL
-#define INIT_CY82C693	IDE_NO_DRIVER
-#endif
-
-#ifdef CONFIG_BLK_DEV_CS5530
-extern unsigned int pci_init_cs5530(struct pci_dev *, const char *);
-extern void ide_init_cs5530(ide_hwif_t *);
-#define PCI_CS5530	&pci_init_cs5530
-#define INIT_CS5530	&ide_init_cs5530
-#else
-#define PCI_CS5530	NULL
-#define INIT_CS5530	IDE_NO_DRIVER
-#endif
-
-#ifdef CONFIG_BLK_DEV_HPT34X
-extern unsigned int pci_init_hpt34x(struct pci_dev *, const char *);
-extern void ide_init_hpt34x(ide_hwif_t *);
-#define PCI_HPT34X	&pci_init_hpt34x
-#define INIT_HPT34X	&ide_init_hpt34x
-#else
-#define PCI_HPT34X	NULL
-#define INIT_HPT34X	IDE_IGNORE
-#endif
-
-#ifdef CONFIG_BLK_DEV_HPT366
-extern byte hpt363_shared_irq;
-extern byte hpt363_shared_pin;
-extern unsigned int pci_init_hpt366(struct pci_dev *, const char *);
-extern unsigned int ata66_hpt366(ide_hwif_t *);
-extern void ide_init_hpt366(ide_hwif_t *);
-extern void ide_dmacapable_hpt366(ide_hwif_t *, unsigned long);
-#define PCI_HPT366	&pci_init_hpt366
-#define ATA66_HPT366	&ata66_hpt366
-#define INIT_HPT366	&ide_init_hpt366
-#define DMA_HPT366	&ide_dmacapable_hpt366
-#else
-static byte hpt363_shared_irq;
-static byte hpt363_shared_pin;
-#define PCI_HPT366	NULL
-#define ATA66_HPT366	NULL
-#define INIT_HPT366	IDE_NO_DRIVER
-#define DMA_HPT366	NULL
-#endif
-
-#ifdef CONFIG_BLK_DEV_NS87415
-extern void ide_init_ns87415(ide_hwif_t *);
-#define INIT_NS87415	&ide_init_ns87415
-#else
-#define INIT_NS87415	IDE_IGNORE
-#endif
-
-#ifdef CONFIG_BLK_DEV_OPTI621
-extern void ide_init_opti621(ide_hwif_t *);
-#define INIT_OPTI621	&ide_init_opti621
-#else
-#define INIT_OPTI621	IDE_NO_DRIVER
-#endif
-
-#ifdef CONFIG_BLK_DEV_PDC_ADMA
-extern unsigned int pci_init_pdcadma(struct pci_dev *, const char *);
-extern unsigned int ata66_pdcadma(ide_hwif_t *);
-extern void ide_init_pdcadma(ide_hwif_t *);
-extern void ide_dmacapable_pdcadma(ide_hwif_t *, unsigned long);
-#define PCI_PDCADMA	&pci_init_pdcadma
-#define ATA66_PDCADMA	&ata66_pdcadma
-#define INIT_PDCADMA	&ide_init_pdcadma
-#define DMA_PDCADMA	&ide_dmacapable_pdcadma
-#else
-#define PCI_PDCADMA	IDE_IGNORE
-#define ATA66_PDCADMA	IDE_IGNORE
-#define INIT_PDCADMA	IDE_IGNORE
-#define DMA_PDCADMA	IDE_IGNORE
-#endif
-
-#ifdef CONFIG_BLK_DEV_PDC202XX
-extern unsigned int pci_init_pdc202xx(struct pci_dev *, const char *);
-extern unsigned int ata66_pdc202xx(ide_hwif_t *);
-extern void ide_init_pdc202xx(ide_hwif_t *);
-#define PCI_PDC202XX	&pci_init_pdc202xx
-#define ATA66_PDC202XX	&ata66_pdc202xx
-#define INIT_PDC202XX	&ide_init_pdc202xx
-#else
-#define PCI_PDC202XX	NULL
-#define ATA66_PDC202XX	NULL
-#define INIT_PDC202XX	NULL
-#endif
-
-#ifdef CONFIG_BLK_DEV_PIIX
-extern unsigned int pci_init_piix(struct pci_dev *, const char *);
-extern unsigned int ata66_piix(ide_hwif_t *);
-extern void ide_init_piix(ide_hwif_t *);
-#define PCI_PIIX	&pci_init_piix
-#define ATA66_PIIX	&ata66_piix
-#define INIT_PIIX	&ide_init_piix
-#else
-#define PCI_PIIX	NULL
-#define ATA66_PIIX	NULL
-#define INIT_PIIX	IDE_NO_DRIVER
-#endif
-
-#ifdef CONFIG_BLK_DEV_IT8172
-extern unsigned int pci_init_it8172(struct pci_dev *, const char *);
-extern unsigned int ata66_it8172(ide_hwif_t *);
-extern void ide_init_it8172(ide_hwif_t *);
-#define PCI_IT8172	&pci_init_it8172
-#define INIT_IT8172	&ide_init_it8172
-#else
-#define PCI_IT8172	NULL
-#define ATA66_IT8172	NULL
-#define INIT_IT8172	NULL
-#endif
-
-#ifdef CONFIG_BLK_DEV_RZ1000
-extern void ide_init_rz1000(ide_hwif_t *);
-#define INIT_RZ1000	&ide_init_rz1000
-#else
-#define INIT_RZ1000	IDE_IGNORE
-#endif
-
-#define INIT_SAMURAI	NULL
-
-#ifdef CONFIG_BLK_DEV_SVWKS
-extern unsigned int pci_init_svwks(struct pci_dev *, const char *);
-extern unsigned int ata66_svwks(ide_hwif_t *);
-extern void ide_init_svwks(ide_hwif_t *);
-#define PCI_SVWKS	&pci_init_svwks
-#define ATA66_SVWKS	&ata66_svwks
-#define INIT_SVWKS	&ide_init_svwks
-#else
-#define PCI_SVWKS	NULL
-#define ATA66_SVWKS	NULL
-#define INIT_SVWKS	IDE_NO_DRIVER
-#endif
-
-#ifdef CONFIG_BLK_DEV_SIS5513
-extern unsigned int pci_init_sis5513(struct pci_dev *, const char *);
-extern unsigned int ata66_sis5513(ide_hwif_t *);
-extern void ide_init_sis5513(ide_hwif_t *);
-#define PCI_SIS5513	&pci_init_sis5513
-#define ATA66_SIS5513	&ata66_sis5513
-#define INIT_SIS5513	&ide_init_sis5513
-#else
-#define PCI_SIS5513	NULL
-#define ATA66_SIS5513	NULL
-#define INIT_SIS5513	IDE_NO_DRIVER
-#endif
-
-#ifdef CONFIG_BLK_DEV_SLC90E66
-extern unsigned int pci_init_slc90e66(struct pci_dev *, const char *);
-extern unsigned int ata66_slc90e66(ide_hwif_t *);
-extern void ide_init_slc90e66(ide_hwif_t *);
-#define PCI_SLC90E66	&pci_init_slc90e66
-#define ATA66_SLC90E66	&ata66_slc90e66
-#define INIT_SLC90E66	&ide_init_slc90e66
-#else
-#define PCI_SLC90E66	NULL
-#define ATA66_SLC90E66	NULL
-#define INIT_SLC90E66	IDE_NO_DRIVER
-#endif
-
-#ifdef CONFIG_BLK_DEV_SL82C105
-extern unsigned int pci_init_sl82c105(struct pci_dev *, const char *);
-extern void dma_init_sl82c105(ide_hwif_t *, unsigned long);
-extern void ide_init_sl82c105(ide_hwif_t *);
-#define PCI_W82C105	&pci_init_sl82c105
-#define DMA_W82C105	&dma_init_sl82c105
-#define INIT_W82C105	&ide_init_sl82c105
-#else
-#define PCI_W82C105	NULL
-#define DMA_W82C105	NULL
-#define INIT_W82C105	IDE_IGNORE
-#endif
-
-#ifdef CONFIG_BLK_DEV_TRM290
-extern void ide_init_trm290(ide_hwif_t *);
-#define INIT_TRM290	&ide_init_trm290
-#else
-#define INIT_TRM290	IDE_IGNORE
-#endif
-
-#ifdef CONFIG_BLK_DEV_VIA82CXXX
-extern unsigned int pci_init_via82cxxx(struct pci_dev *, const char *);
-extern unsigned int ata66_via82cxxx(ide_hwif_t *);
-extern void ide_init_via82cxxx(ide_hwif_t *);
-extern void ide_dmacapable_via82cxxx(ide_hwif_t *, unsigned long);
-#define PCI_VIA82CXXX	&pci_init_via82cxxx
-#define ATA66_VIA82CXXX	&ata66_via82cxxx
-#define INIT_VIA82CXXX	&ide_init_via82cxxx
-#define DMA_VIA82CXXX	&ide_dmacapable_via82cxxx
-#else
-#define PCI_VIA82CXXX	NULL
-#define ATA66_VIA82CXXX	NULL
-#define INIT_VIA82CXXX	IDE_NO_DRIVER
-#define DMA_VIA82CXXX	NULL
-#endif
-
-typedef struct ide_pci_enablebit_s {
-	byte	reg;	/* byte pci reg holding the enable-bit */
-	byte	mask;	/* mask to isolate the enable-bit */
-	byte	val;	/* value of masked reg when "enabled" */
-} ide_pci_enablebit_t;
-
-typedef struct ide_pci_device_s {
-	ide_pci_devid_t		devid;
-	char			*name;
-	unsigned int		(*init_chipset)(struct pci_dev *dev, const char *name);
-	unsigned int		(*ata66_check)(ide_hwif_t *hwif);
-	void 			(*init_hwif)(ide_hwif_t *hwif);
-	void			(*dma_init)(ide_hwif_t *hwif, unsigned long dmabase);
-	ide_pci_enablebit_t	enablebits[2];
-	byte			bootable;
-	unsigned int		extra;
-} ide_pci_device_t;
-
-static ide_pci_device_t ide_pci_chipsets[] __initdata = {
-	{DEVID_PIIXa,	"PIIX",		NULL,		NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
-	{DEVID_PIIXb,	"PIIX",		NULL,		NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
-	{DEVID_MPIIX,	"MPIIX",	NULL,		NULL,		INIT_PIIX,	NULL,		{{0x6D,0x80,0x80}, {0x6F,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_PIIX3,	"PIIX3",	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
-	{DEVID_PIIX4,	"PIIX4",	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
-	{DEVID_ICH0,	"ICH0", 	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_PIIX4E2,	"PIIX4",	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_ICH,	"ICH",  	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_PIIX4U2,	"PIIX4",	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_PIIX4NX,	"PIIX4",	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_ICH2,	"ICH2", 	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_ICH2M,	"ICH2M",	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_ICH3M,	"ICH3M",	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_ICH3,	"ICH3", 	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_ICH4,	"ICH4", 	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_CICH,	"C-ICH",	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_VIA_IDE,	"VIA_IDE",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_MR_IDE,	"VP_IDE",	PCI_VIA82CXXX,	ATA66_VIA82CXXX,INIT_VIA82CXXX,	DMA_VIA82CXXX,	{{0x40,0x02,0x02}, {0x40,0x01,0x01}}, 	ON_BOARD,	0 },
-	{DEVID_VP_IDE,	"VP_IDE",	PCI_VIA82CXXX,	ATA66_VIA82CXXX,INIT_VIA82CXXX,	DMA_VIA82CXXX,	{{0x40,0x02,0x02}, {0x40,0x01,0x01}}, 	ON_BOARD,	0 },
-#ifndef CONFIG_PDC202XX_FORCE
-        {DEVID_PDC20246,"PDC20246",	PCI_PDC202XX,	NULL,		INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	16 },
-        {DEVID_PDC20262,"PDC20262",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	48 },
-        {DEVID_PDC20265,"PDC20265",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	48 },
-        {DEVID_PDC20267,"PDC20267",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	48 },
-#else /* !CONFIG_PDC202XX_FORCE */
-	{DEVID_PDC20246,"PDC20246",	PCI_PDC202XX,	NULL,		INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}}, 	OFF_BOARD,	16 },
-	{DEVID_PDC20262,"PDC20262",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}},	OFF_BOARD,	48 },
-	{DEVID_PDC20265,"PDC20265",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}},	OFF_BOARD,	48 },
-	{DEVID_PDC20267,"PDC20267",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}},	OFF_BOARD,	48 },
-#endif
-	{DEVID_PDC20268,"PDC20268",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
-	/* Promise used a different PCI ident for the raid card apparently to try and
-	   prevent Linux detecting it and using our own raid code. We want to detect
-	   it for the ataraid drivers, so we have to list both here.. */
-	{DEVID_PDC20270,"PDC20270",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
-	{DEVID_PDC20269,"PDC20269",	PCI_PDC202XX,	ATA66_PDC202XX,	 INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
-	{DEVID_PDC20275,"PDC20275",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
-	{DEVID_PDC20276,"PDC20276",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
-	{DEVID_RZ1000,	"RZ1000",	NULL,		NULL,		INIT_RZ1000,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_RZ1001,	"RZ1001",	NULL,		NULL,		INIT_RZ1000,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_SAMURAI,	"SAMURAI",	NULL,		NULL,		INIT_SAMURAI,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_CMD640,	"CMD640",	NULL,		NULL,		IDE_IGNORE,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_NS87410,	"NS87410",	NULL,		NULL,		NULL,		NULL,		{{0x43,0x08,0x08}, {0x47,0x08,0x08}}, 	ON_BOARD,	0 },
-	{DEVID_SIS5513,	"SIS5513",	PCI_SIS5513,	ATA66_SIS5513,	INIT_SIS5513,	NULL,		{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, 	ON_BOARD,	0 },
-	{DEVID_CMD643,	"CMD643",	PCI_CMD64X,	NULL,		INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_CMD646,	"CMD646",	PCI_CMD64X,	NULL,		INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x51,0x80,0x80}}, 	ON_BOARD,	0 },
-	{DEVID_CMD648,	"CMD648",	PCI_CMD64X,	ATA66_CMD64X,	INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_CMD649,	"CMD649",	PCI_CMD64X,	ATA66_CMD64X,	INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-#ifndef CONFIG_BLK_DEV_CMD680
-	{DEVID_CMD680,	"CMD680",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-#else /* CONFIG_BLK_DEV_CMD680 */
-	{DEVID_CMD680,	"CMD680",	PCI_CMD64X,	ATA66_CMD64X,	INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-#endif /* !CONFIG_BLK_DEV_CMD680 */
-	{DEVID_HT6565,	"HT6565",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_OPTI621,	"OPTI621",	NULL,		NULL,		INIT_OPTI621,	NULL,		{{0x45,0x80,0x00}, {0x40,0x08,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_OPTI621X,"OPTI621X",	NULL,		NULL,		INIT_OPTI621,	NULL,		{{0x45,0x80,0x00}, {0x40,0x08,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_TRM290,	"TRM290",	NULL,		NULL,		INIT_TRM290,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_NS87415,	"NS87415",	NULL,		NULL,		INIT_NS87415,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_AEC6210,	"AEC6210",	PCI_AEC62XX,	NULL,		INIT_AEC62XX,	DMA_AEC62XX,	{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, 	OFF_BOARD,	0 },
-	{DEVID_AEC6260,	"AEC6260",	PCI_AEC62XX,	ATA66_AEC62XX,	INIT_AEC62XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	NEVER_BOARD,	0 },
-	{DEVID_AEC6260R,"AEC6260R",	PCI_AEC62XX,	ATA66_AEC62XX,	INIT_AEC62XX,	NULL,		{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},	OFF_BOARD,	0 },
-	{DEVID_W82C105,	"W82C105",	PCI_W82C105,	NULL,		INIT_W82C105,	DMA_W82C105,	{{0x40,0x01,0x01}, {0x40,0x10,0x10}}, 	ON_BOARD,	0 },
-	{DEVID_UM8673F,	"UM8673F",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_UM8886A,	"UM8886A",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_UM8886BF,"UM8886BF",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_HPT34X,	"HPT34X",	PCI_HPT34X,	NULL,		INIT_HPT34X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	NEVER_BOARD,	16 },
-	{DEVID_HPT366,	"HPT366",	PCI_HPT366,	ATA66_HPT366,	INIT_HPT366,	DMA_HPT366,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	240 },
-	{DEVID_ALI15X3,	"ALI15X3",	PCI_ALI15X3,	ATA66_ALI15X3,	INIT_ALI15X3,	DMA_ALI15X3,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_CY82C693,"CY82C693",	PCI_CY82C693,	NULL,		INIT_CY82C693,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_HINT,	"HINT_IDE",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_CS5530,	"CS5530",	PCI_CS5530,	NULL,		INIT_CS5530,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_AMD7401,	"AMD7401",	NULL,		NULL,		NULL,		DMA_AMD74XX,	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},	ON_BOARD,	0 },
-	{DEVID_AMD7409,	"AMD7409",	PCI_AMD74XX,	ATA66_AMD74XX,	INIT_AMD74XX,	DMA_AMD74XX,	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},	ON_BOARD,	0 },
-	{DEVID_AMD7411,	"AMD7411",	PCI_AMD74XX,	ATA66_AMD74XX,	INIT_AMD74XX,	DMA_AMD74XX,	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},	ON_BOARD,	0 },
-	{DEVID_AMD7441,	"AMD7441",	PCI_AMD74XX,	ATA66_AMD74XX,	INIT_AMD74XX,	DMA_AMD74XX,	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},	ON_BOARD,	0 },
-	{DEVID_PDCADMA,	"PDCADMA",	PCI_PDCADMA,	ATA66_PDCADMA,	INIT_PDCADMA,	DMA_PDCADMA,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
-	{DEVID_SLC90E66,"SLC90E66",	PCI_SLC90E66,	ATA66_SLC90E66,	INIT_SLC90E66,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-        {DEVID_OSB4,    "ServerWorks OSB4",		PCI_SVWKS,	ATA66_SVWKS,	INIT_SVWKS,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_CSB5,	"ServerWorks CSB5",		PCI_SVWKS,	ATA66_SVWKS,	INIT_SVWKS,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_ITE8172G,"IT8172G",	PCI_IT8172,	NULL,	INIT_IT8172,	NULL,		{{0x00,0x00,0x00}, {0x40,0x00,0x01}},	ON_BOARD,	0 },
-	{IDE_PCI_DEVID_NULL, "PCI_IDE",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 }};
-
-/*
- * This allows offboard ide-pci cards the enable a BIOS, verify interrupt
- * settings of split-mirror pci-config space, place chipset into init-mode,
- * and/or preserve an interrupt if the card is not native ide support.
- */
-static unsigned int __init ide_special_settings (struct pci_dev *dev, const char *name)
-{
-	switch(dev->device) {
-		case PCI_DEVICE_ID_TTI_HPT366:
-		case PCI_DEVICE_ID_PROMISE_20246:
-		case PCI_DEVICE_ID_PROMISE_20262:
-		case PCI_DEVICE_ID_PROMISE_20265:
-		case PCI_DEVICE_ID_PROMISE_20267:
-		case PCI_DEVICE_ID_PROMISE_20268:
-		case PCI_DEVICE_ID_PROMISE_20270:
-		case PCI_DEVICE_ID_PROMISE_20269:
-		case PCI_DEVICE_ID_PROMISE_20275:
-		case PCI_DEVICE_ID_PROMISE_20276:
-		case PCI_DEVICE_ID_ARTOP_ATP850UF:
-		case PCI_DEVICE_ID_ARTOP_ATP860:
-		case PCI_DEVICE_ID_ARTOP_ATP860R:
-			return dev->irq;
-		default:
-			break;
-	}
-	return 0;
-}
-
-/*
- * Match a PCI IDE port against an entry in ide_hwifs[],
- * based on io_base port if possible.
- */
-static ide_hwif_t __init *ide_match_hwif (unsigned long io_base, byte bootable, const char *name)
-{
-	int h;
-	ide_hwif_t *hwif;
-
-	/*
-	 * Look for a hwif with matching io_base specified using
-	 * parameters to ide_setup().
-	 */
-	for (h = 0; h < MAX_HWIFS; ++h) {
-		hwif = &ide_hwifs[h];
-		if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) {
-			if (hwif->chipset == ide_generic)
-				return hwif; /* a perfect match */
-		}
-	}
-	/*
-	 * Look for a hwif with matching io_base default value.
-	 * If chipset is "ide_unknown", then claim that hwif slot.
-	 * Otherwise, some other chipset has already claimed it..  :(
-	 */
-	for (h = 0; h < MAX_HWIFS; ++h) {
-		hwif = &ide_hwifs[h];
-		if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) {
-			if (hwif->chipset == ide_unknown)
-				return hwif; /* match */
-			printk("%s: port 0x%04lx already claimed by %s\n", name, io_base, hwif->name);
-			return NULL;	/* already claimed */
-		}
-	}
-	/*
-	 * Okay, there is no hwif matching our io_base,
-	 * so we'll just claim an unassigned slot.
-	 * Give preference to claiming other slots before claiming ide0/ide1,
-	 * just in case there's another interface yet-to-be-scanned
-	 * which uses ports 1f0/170 (the ide0/ide1 defaults).
-	 *
-	 * Unless there is a bootable card that does not use the standard
-	 * ports 1f0/170 (the ide0/ide1 defaults). The (bootable) flag.
-	 */
-	if (bootable) {
-		for (h = 0; h < MAX_HWIFS; ++h) {
-			hwif = &ide_hwifs[h];
-			if (hwif->chipset == ide_unknown)
-				return hwif;	/* pick an unused entry */
-		}
-	} else {
-		for (h = 2; h < MAX_HWIFS; ++h) {
-			hwif = ide_hwifs + h;
-			if (hwif->chipset == ide_unknown)
-				return hwif;	/* pick an unused entry */
-		}
-	}
-	for (h = 0; h < 2; ++h) {
-		hwif = ide_hwifs + h;
-		if (hwif->chipset == ide_unknown)
-			return hwif;	/* pick an unused entry */
-	}
-	printk("%s: too many IDE interfaces, no room in table\n", name);
-	return NULL;
-}
-
-static int __init ide_setup_pci_baseregs (struct pci_dev *dev, const char *name)
-{
-	byte reg, progif = 0;
-
-	/*
-	 * Place both IDE interfaces into PCI "native" mode:
-	 */
-	if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) || (progif & 5) != 5) {
-		if ((progif & 0xa) != 0xa) {
-			printk("%s: device not capable of full native PCI mode\n", name);
-			return 1;
-		}
-		printk("%s: placing both ports into native PCI mode\n", name);
-		(void) pci_write_config_byte(dev, PCI_CLASS_PROG, progif|5);
-		if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) || (progif & 5) != 5) {
-			printk("%s: rewrite of PROGIF failed, wanted 0x%04x, got 0x%04x\n", name, progif|5, progif);
-			return 1;
-		}
-	}
-	/*
-	 * Setup base registers for IDE command/control spaces for each interface:
-	 */
-	for (reg = 0; reg < 4; reg++) {
-		struct resource *res = dev->resource + reg;
-		if ((res->flags & IORESOURCE_IO) == 0)
-			continue;
-		if (!res->start) {
-			printk("%s: Missing I/O address #%d\n", name, reg);
-			return 1;
-		}
-	}
-	return 0;
-}
-
-/*
- * ide_setup_pci_device() looks at the primary/secondary interfaces
- * on a PCI IDE device and, if they are enabled, prepares the IDE driver
- * for use with them.  This generic code works for most PCI chipsets.
- *
- * One thing that is not standardized is the location of the
- * primary/secondary interface "enable/disable" bits.  For chipsets that
- * we "know" about, this information is in the ide_pci_device_t struct;
- * for all other chipsets, we just assume both interfaces are enabled.
- */
-static void __init ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d)
-{
-	unsigned int port, at_least_one_hwif_enabled = 0, autodma = 0, pciirq = 0;
-	unsigned short pcicmd = 0, tried_config = 0;
-	byte tmp = 0;
-	ide_hwif_t *hwif, *mate = NULL;
-	unsigned int class_rev;
-	static int secondpdc = 0;
-
-#ifdef CONFIG_IDEDMA_AUTO
-	if (!noautodma)
-		autodma = 1;
-#endif
-
-	if (d->init_hwif == IDE_NO_DRIVER) {
-		printk(KERN_WARNING "%s: detected chipset, but driver not compiled in!\n", d->name);
-		d->init_hwif = NULL;
-	}
-
-	if (pci_enable_device(dev)) {
-		if(pci_enable_device_bars(dev, 1<<4))
-		{
-			printk(KERN_WARNING "%s: (ide_setup_pci_device:) Could not enable device.\n", d->name);
-			return;
-		}
-		printk(KERN_INFO "%s: BIOS setup was incomplete.\n", d->name);
-	}
-
-check_if_enabled:
-	if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd)) {
-		printk("%s: error accessing PCI regs\n", d->name);
-		return;
-	}
-	if (!(pcicmd & PCI_COMMAND_IO)) {	/* is device disabled? */
-		/*
-		 * PnP BIOS was *supposed* to have set this device up for us,
-		 * but we can do it ourselves, so long as the BIOS has assigned an IRQ
-		 *  (or possibly the device is using a "legacy header" for IRQs).
-		 * Maybe the user deliberately *disabled* the device,
-		 * but we'll eventually ignore it again if no drives respond.
-		 */
-		if (tried_config++
-		 || ide_setup_pci_baseregs(dev, d->name)
-		 || pci_write_config_word(dev, PCI_COMMAND, pcicmd | PCI_COMMAND_IO)) {
-			printk("%s: device disabled (BIOS)\n", d->name);
-			return;
-		}
-		autodma = 0;	/* default DMA off if we had to configure it here */
-		goto check_if_enabled;
-	}
-	if (tried_config)
-		printk("%s: device enabled (Linux)\n", d->name);
-
-	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;
-
-	if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X)) {
-		/* see comments in hpt34x.c on why..... */
-		char *chipset_names[] = {"HPT343", "HPT345"};
-		strcpy(d->name, chipset_names[(pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0]);
-		d->bootable = (pcicmd & PCI_COMMAND_MEMORY) ? OFF_BOARD : NEVER_BOARD;
-	}
-
-	printk("%s: chipset revision %d\n", d->name, class_rev);
-
-	/*
-	 * Can we trust the reported IRQ?
-	 */
-	pciirq = dev->irq;
-	
-	if (dev->class >> 8 == PCI_CLASS_STORAGE_RAID)
-	{
-	    /*  By rights we want to ignore these, but the Promise Fastrak
-		 *	people have some strange ideas about proprietary so we have
-		 *	to act otherwise on those. The supertrak however we need
-		 *	to skip 
-		 */
-		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20265))
-		{
-			printk(KERN_INFO "ide: Found promise 20265 in RAID mode.\n");
-			if(dev->bus->self && dev->bus->self->vendor == PCI_VENDOR_ID_INTEL &&
-			   dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960)
-			{
-				printk(KERN_INFO "ide: Skipping Promise PDC20265 attached to I2O RAID controller.\n");
-				return;
-			}
-		}
-		/* Its attached to something else, just a random bridge.
-		   Suspect a fastrak and fall through */
-	}
-
-	if ((dev->class & ~(0xfa)) != ((PCI_CLASS_STORAGE_IDE << 8) | 5)) {
-		printk("%s: not 100%% native mode: will probe irqs later\n", d->name);
-		/*
-		 * This allows offboard ide-pci cards the enable a BIOS,
-		 * verify interrupt settings of split-mirror pci-config
-		 * space, place chipset into init-mode, and/or preserve
-		 * an interrupt if the card is not native ide support.
-		 */
-		pciirq = (d->init_chipset) ? d->init_chipset(dev, d->name) : ide_special_settings(dev, d->name);
-	} else if (tried_config) {
-		printk("%s: will probe irqs later\n", d->name);
-		pciirq = 0;
-	} else if (!pciirq) {
-		printk("%s: bad irq (%d): will probe later\n", d->name, pciirq);
-		pciirq = 0;
-	} else {
-		if (d->init_chipset)
-			(void) d->init_chipset(dev, d->name);
-#ifdef __sparc__
-		printk("%s: 100%% native mode on irq %s\n",
-		       d->name, __irq_itoa(pciirq));
-#else
-		printk("%s: 100%% native mode on irq %d\n", d->name, pciirq);
-#endif
-	}
-
-	/*
-	 * Set up the IDE ports
-	 */
-	for (port = 0; port <= 1; ++port) {
-		unsigned long base = 0, ctl = 0;
-		ide_pci_enablebit_t *e = &(d->enablebits[port]);
-	
-		/* 
-		 * If this is a Promise FakeRaid controller, the 2nd controller will be marked as 
-		 * disabled while it is actually there and enabled by the bios for raid purposes. 
-		 * Skip the normal "is it enabled" test for those.
-		 */
-		if ((IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20265)) && (secondpdc++==1) && (port==1)  ) 
-			goto controller_ok;
-		if ((IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20262)) && (secondpdc++==1) && (port==1)  ) 
-			goto controller_ok;
-			
-		if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) || (tmp & e->mask) != e->val))
-			continue;	/* port not enabled */
-controller_ok:			
-		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) && (port) && (class_rev < 0x03))
-			return;
-		if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE || (dev->class & (port ? 4 : 1)) != 0) {
-			ctl  = dev->resource[(2*port)+1].start;
-			base = dev->resource[2*port].start;
-			if (!(ctl & PCI_BASE_ADDRESS_IO_MASK) ||
-			    !(base & PCI_BASE_ADDRESS_IO_MASK)) {
-				printk("%s: IO baseregs (BIOS) are reported as MEM, report to <andre@linux-ide.org>.\n", d->name);
-#if 0
-				/* FIXME! This really should check that it really gets the IO/MEM part right! */
-				continue;
-#endif
-			}
-		}
-		if ((ctl && !base) || (base && !ctl)) {
-			printk("%s: inconsistent baseregs (BIOS) for port %d, skipping\n", d->name, port);
-			continue;
-		}
-		if (!ctl)
-			ctl = port ? 0x374 : 0x3f4;	/* use default value */
-		if (!base)
-			base = port ? 0x170 : 0x1f0;	/* use default value */
-		if ((hwif = ide_match_hwif(base, d->bootable, d->name)) == NULL)
-			continue;	/* no room in ide_hwifs[] */
-		if (hwif->io_ports[IDE_DATA_OFFSET] != base) {
-			ide_init_hwif_ports(&hwif->hw, base, (ctl | 2), NULL);
-			memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
-			hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
-		}
-		hwif->chipset = ide_pci;
-		hwif->pci_dev = dev;
-		hwif->pci_devid = d->devid;
-		hwif->channel = port;
-		if (!hwif->irq)
-			hwif->irq = pciirq;
-		if (mate) {
-			hwif->mate = mate;
-			mate->mate = hwif;
-			if (IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6210)) {
-				hwif->serialized = 1;
-				mate->serialized = 1;
-			}
-		}
-		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886A) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886BF) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8673F)) {
-			hwif->irq = hwif->channel ? 15 : 14;
-			goto bypass_umc_dma;
-		}
-		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_MPIIX))
-			goto bypass_piix_dma;
-		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDCADMA))
-			goto bypass_legacy_dma;
-		if (hwif->udma_four) {
-			printk("%s: ATA-66/100 forced bit set (WARNING)!!\n", d->name);
-		} else {
-			hwif->udma_four = (d->ata66_check) ? d->ata66_check(hwif) : 0;
-		}
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_SIS5513) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PIIX4NX) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X)  ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_VIA_IDE) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_MR_IDE)  ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_VP_IDE))
-			autodma = 0;
-		if (autodma)
-			hwif->autodma = 1;
-
-		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20262) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20265) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20267) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20268) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20270) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20269) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20275) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20276) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6210) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260R) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CS5530) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CY82C693) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD646) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD648) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD649) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD680) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_OSB4) ||
-		    ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 0x80))) {
-			unsigned long dma_base = ide_get_or_set_dma_base(hwif, (!mate && d->extra) ? d->extra : 0, d->name);
-			if (dma_base && !(pcicmd & PCI_COMMAND_MASTER)) {
-				/*
- 	 			 * Set up BM-DMA capability (PnP BIOS should have done this)
- 	 			 */
-		    		if (!IDE_PCI_DEVID_EQ(d->devid, DEVID_CS5530))
-					hwif->autodma = 0;	/* default DMA off if we had to configure it here */
-				(void) pci_write_config_word(dev, PCI_COMMAND, pcicmd | PCI_COMMAND_MASTER);
-				if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd) || !(pcicmd & PCI_COMMAND_MASTER)) {
-					printk("%s: %s error updating PCICMD\n", hwif->name, d->name);
-					dma_base = 0;
-				}
-			}
-			if (dma_base) {
-				if (d->dma_init) {
-					d->dma_init(hwif, dma_base);
-				} else {
-					ide_setup_dma(hwif, dma_base, 8);
-				}
-			} else {
-				printk("%s: %s Bus-Master DMA disabled (BIOS)\n", hwif->name, d->name);
-			}
-		}
-#endif	/* CONFIG_BLK_DEV_IDEDMA */
-bypass_legacy_dma:
-bypass_piix_dma:
-bypass_umc_dma:
-		if (d->init_hwif)  /* Call chipset-specific routine for each enabled hwif */
-			d->init_hwif(hwif);
-		mate = hwif;
-		at_least_one_hwif_enabled = 1;
-	}
-	if (!at_least_one_hwif_enabled)
-		printk("%s: neither IDE port enabled (BIOS)\n", d->name);
-}
-
-static void __init pdc20270_device_order_fixup (struct pci_dev *dev, ide_pci_device_t *d)
-{
-	struct pci_dev *dev2 = NULL, *findev;
-	ide_pci_device_t *d2;
-
-	if ((dev->bus->self &&
-	     dev->bus->self->vendor == PCI_VENDOR_ID_DEC) &&
-	    (dev->bus->self->device == PCI_DEVICE_ID_DEC_21150)) {
-		if (PCI_SLOT(dev->devfn) & 2) {
-			return;
-		}
-		d->extra = 0;
-		pci_for_each_dev(findev) {
-			if ((findev->vendor == dev->vendor) &&
-			    (findev->device == dev->device) &&
-			    (PCI_SLOT(findev->devfn) & 2)) {
-				byte irq = 0, irq2 = 0;
-				dev2 = findev;
-				pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
-				pci_read_config_byte(dev2, PCI_INTERRUPT_LINE, &irq2);
-                                if (irq != irq2) {
-					dev2->irq = dev->irq;
-                                        pci_write_config_byte(dev2, PCI_INTERRUPT_LINE, irq);
-                                }
-
-			}
-		}
-	}
-
-	printk("%s: IDE controller on PCI bus %02x dev %02x\n", d->name, dev->bus->number, dev->devfn);
-	ide_setup_pci_device(dev, d);
-	if (!dev2)
-		return;
-	d2 = d;
-	printk("%s: IDE controller on PCI bus %02x dev %02x\n", d2->name, dev2->bus->number, dev2->devfn);
-	ide_setup_pci_device(dev2, d2);
-}
-
-static void __init hpt366_device_order_fixup (struct pci_dev *dev, ide_pci_device_t *d)
-{
-	struct pci_dev *dev2 = NULL, *findev;
-	ide_pci_device_t *d2;
-	unsigned char pin1 = 0, pin2 = 0;
-	unsigned int class_rev;
-	char *chipset_names[] = {"HPT366", "HPT366", "HPT368", "HPT370", "HPT370A", "HPT372"};
-
-	if (PCI_FUNC(dev->devfn) & 1)
-		return;
-
-	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;
-	if (class_rev > 5)
-		class_rev = 5;
-	
-	strcpy(d->name, chipset_names[class_rev]);
-
-	switch(class_rev) {
-		case 4:
-		case 3:	printk("%s: IDE controller on PCI bus %02x dev %02x\n", d->name, dev->bus->number, dev->devfn);
-			ide_setup_pci_device(dev, d);
-			return;
-		default:	break;
-	}
-
-	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1);
-	pci_for_each_dev(findev) {
-		if ((findev->vendor == dev->vendor) &&
-		    (findev->device == dev->device) &&
-		    ((findev->devfn - dev->devfn) == 1) &&
-		    (PCI_FUNC(findev->devfn) & 1)) {
-			dev2 = findev;
-			pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin2);
-			hpt363_shared_pin = (pin1 != pin2) ? 1 : 0;
-			hpt363_shared_irq = (dev->irq == dev2->irq) ? 1 : 0;
-			if (hpt363_shared_pin && hpt363_shared_irq) {
-				d->bootable = ON_BOARD;
-				printk("%s: onboard version of chipset, pin1=%d pin2=%d\n", d->name, pin1, pin2);
-#if 0
-				/* I forgot why I did this once, but it fixed something. */
-				pci_write_config_byte(dev2, PCI_INTERRUPT_PIN, dev->irq);
-				printk("PCI: %s: Fixing interrupt %d pin %d to ZERO \n", d->name, dev2->irq, pin2);
-				pci_write_config_byte(dev2, PCI_INTERRUPT_LINE, 0);
-#endif
-			}
-			break;
-		}
-	}
-	printk("%s: IDE controller on PCI bus %02x dev %02x\n", d->name, dev->bus->number, dev->devfn);
-	ide_setup_pci_device(dev, d);
-	if (!dev2)
-		return;
-	d2 = d;
-	printk("%s: IDE controller on PCI bus %02x dev %02x\n", d2->name, dev2->bus->number, dev2->devfn);
-	ide_setup_pci_device(dev2, d2);
-}
-
-/*
- * ide_scan_pcibus() gets invoked at boot time from ide.c.
- * It finds all PCI IDE controllers and calls ide_setup_pci_device for them.
- */
-void __init ide_scan_pcidev (struct pci_dev *dev)
-{
-	ide_pci_devid_t		devid;
-	ide_pci_device_t	*d;
-
-	devid.vid = dev->vendor;
-	devid.did = dev->device;
-	for (d = ide_pci_chipsets; d->devid.vid && !IDE_PCI_DEVID_EQ(d->devid, devid); ++d);
-	if (d->init_hwif == IDE_IGNORE)
-		printk("%s: ignored by ide_scan_pci_device() (uses own driver)\n", d->name);
-	else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_OPTI621V) && !(PCI_FUNC(dev->devfn) & 1))
-		return;
-	else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_CY82C693) && (!(PCI_FUNC(dev->devfn) & 1) || !((dev->class >> 8) == PCI_CLASS_STORAGE_IDE)))
-		return;	/* CY82C693 is more than only a IDE controller */
-	else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_ITE8172G) && (!(PCI_FUNC(dev->devfn) & 1) || !((dev->class >> 8) == PCI_CLASS_STORAGE_IDE)))
-		return;	/* IT8172G is also more than only an IDE controller */
-	else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886A) && !(PCI_FUNC(dev->devfn) & 1))
-		return;	/* UM8886A/BF pair */
-	else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366))
-		hpt366_device_order_fixup(dev, d);
-	else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20270))
-		pdc20270_device_order_fixup(dev, d);
-	else if (!IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL) || (dev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
-		if (IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL))
-			printk("%s: unknown IDE controller on PCI bus %02x device %02x, VID=%04x, DID=%04x\n",
-			       d->name, dev->bus->number, dev->devfn, devid.vid, devid.did);
-		else
-			printk("%s: IDE controller on PCI bus %02x dev %02x\n", d->name, dev->bus->number, dev->devfn);
-		ide_setup_pci_device(dev, d);
-	}
-}
-
-void __init ide_scan_pcibus (int scan_direction)
-{
-	struct pci_dev *dev;
-
-	if (!scan_direction) {
-		pci_for_each_dev(dev) {
-			ide_scan_pcidev(dev);
-		}
-	} else {
-		pci_for_each_dev_reverse(dev) {
-			ide_scan_pcidev(dev);
-		}
-	}
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-pmac.c linux-2.4.21-pre6/drivers/ide/ide-pmac.c
--- linux-2.4.20/drivers/ide/ide-pmac.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/ide-pmac.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,1794 +0,0 @@
-/*
- * linux/drivers/ide/ide-pmac.c
- *
- * Support for IDE interfaces on PowerMacs.
- * These IDE interfaces are memory-mapped and have a DBDMA channel
- * for doing DMA.
- *
- *  Copyright (C) 1998-2001 Paul Mackerras & Ben. Herrenschmidt
- *
- *  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.
- *
- * Some code taken from drivers/ide/ide-dma.c:
- *
- *  Copyright (c) 1995-1998  Mark Lord
- *
- */
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
-#include <linux/pci.h>
-
-#include <asm/prom.h>
-#include <asm/io.h>
-#include <asm/dbdma.h>
-#include <asm/ide.h>
-#include <asm/mediabay.h>
-#include <asm/pci-bridge.h>
-#include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-#include <asm/sections.h>
-#include <asm/irq.h>
-#ifdef CONFIG_PMAC_PBOOK
-#include <linux/adb.h>
-#include <linux/pmu.h>
-#endif
-#include "ide_modes.h"
-
-extern char *ide_dmafunc_verbose(ide_dma_action_t dmafunc);
-extern void ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq);
-
-#define IDE_PMAC_DEBUG
-
-#define DMA_WAIT_TIMEOUT	500
-
-struct pmac_ide_hwif {
-	ide_ioreg_t			regbase;
-	int				irq;
-	int				kind;
-	int				aapl_bus_id;
-	struct device_node*		node;
-	u32				timings[2];
-#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
-	/* Those fields are duplicating what is in hwif. We currently
-	 * can't use the hwif ones because of some assumptions that are
-	 * beeing done by the generic code about the kind of dma controller
-	 * and format of the dma table. This will have to be fixed though.
-	 */
-	volatile struct dbdma_regs*	dma_regs;
-	struct dbdma_cmd*		dma_table_cpu;
-	dma_addr_t			dma_table_dma;
-	struct scatterlist*		sg_table;
-	int				sg_nents;
-	int				sg_dma_direction;
-#endif
-	
-} pmac_ide[MAX_HWIFS] __pmacdata;
-
-static int pmac_ide_count;
-
-enum {
-	controller_ohare,	/* OHare based */
-	controller_heathrow,	/* Heathrow/Paddington */
-	controller_kl_ata3,	/* KeyLargo ATA-3 */
-	controller_kl_ata4,	/* KeyLargo ATA-4 */
-	controller_kl_ata4_80	/* KeyLargo ATA-4 with 80 conductor cable */
-};
-
-/*
- * Extra registers, both 32-bit little-endian
- */
-#define IDE_TIMING_CONFIG	0x200
-#define IDE_INTERRUPT		0x300
-
-/*
- * Timing configuration register definitions
- */
-
-/* Number of IDE_SYSCLK_NS ticks, argument is in nanoseconds */
-#define SYSCLK_TICKS(t)		(((t) + IDE_SYSCLK_NS - 1) / IDE_SYSCLK_NS)
-#define SYSCLK_TICKS_66(t)	(((t) + IDE_SYSCLK_66_NS - 1) / IDE_SYSCLK_66_NS)
-#define IDE_SYSCLK_NS		30	/* 33Mhz cell */
-#define IDE_SYSCLK_66_NS	15	/* 66Mhz cell */
-
-/* 66Mhz cell, found in KeyLargo. Can do ultra mode 0 to 2 on
- * 40 connector cable and to 4 on 80 connector one.
- * Clock unit is 15ns (66Mhz)
- * 
- * 3 Values can be programmed:
- *  - Write data setup, which appears to match the cycle time. They
- *    also call it DIOW setup.
- *  - Ready to pause time (from spec)
- *  - Address setup. That one is weird. I don't see where exactly
- *    it fits in UDMA cycles, I got it's name from an obscure piece
- *    of commented out code in Darwin. They leave it to 0, we do as
- *    well, despite a comment that would lead to think it has a
- *    min value of 45ns.
- * Apple also add 60ns to the write data setup (or cycle time ?) on
- * reads.
- */
-#define TR_66_UDMA_MASK			0xfff00000
-#define TR_66_UDMA_EN			0x00100000 /* Enable Ultra mode for DMA */
-#define TR_66_UDMA_ADDRSETUP_MASK	0xe0000000 /* Address setup */
-#define TR_66_UDMA_ADDRSETUP_SHIFT	29
-#define TR_66_UDMA_RDY2PAUS_MASK	0x1e000000 /* Ready 2 pause time */
-#define TR_66_UDMA_RDY2PAUS_SHIFT	25
-#define TR_66_UDMA_WRDATASETUP_MASK	0x01e00000 /* Write data setup time */
-#define TR_66_UDMA_WRDATASETUP_SHIFT	21
-#define TR_66_MDMA_MASK			0x000ffc00
-#define TR_66_MDMA_RECOVERY_MASK	0x000f8000
-#define TR_66_MDMA_RECOVERY_SHIFT	15
-#define TR_66_MDMA_ACCESS_MASK		0x00007c00
-#define TR_66_MDMA_ACCESS_SHIFT		10
-#define TR_66_PIO_MASK			0x000003ff
-#define TR_66_PIO_RECOVERY_MASK		0x000003e0
-#define TR_66_PIO_RECOVERY_SHIFT	5
-#define TR_66_PIO_ACCESS_MASK		0x0000001f
-#define TR_66_PIO_ACCESS_SHIFT		0
-
-/* 33Mhz cell, found in OHare, Heathrow (& Paddington) and KeyLargo
- * Can do pio & mdma modes, clock unit is 30ns (33Mhz)
- * 
- * The access time and recovery time can be programmed. Some older
- * Darwin code base limit OHare to 150ns cycle time. I decided to do
- * the same here fore safety against broken old hardware ;)
- * The HalfTick bit, when set, adds half a clock (15ns) to the access
- * time and removes one from recovery. It's not supported on KeyLargo
- * implementation afaik. The E bit appears to be set for PIO mode 0 and
- * is used to reach long timings used in this mode.
- */
-#define TR_33_MDMA_MASK			0x003ff800
-#define TR_33_MDMA_RECOVERY_MASK	0x001f0000
-#define TR_33_MDMA_RECOVERY_SHIFT	16
-#define TR_33_MDMA_ACCESS_MASK		0x0000f800
-#define TR_33_MDMA_ACCESS_SHIFT		11
-#define TR_33_MDMA_HALFTICK		0x00200000
-#define TR_33_PIO_MASK			0x000007ff
-#define TR_33_PIO_E			0x00000400
-#define TR_33_PIO_RECOVERY_MASK		0x000003e0
-#define TR_33_PIO_RECOVERY_SHIFT	5
-#define TR_33_PIO_ACCESS_MASK		0x0000001f
-#define TR_33_PIO_ACCESS_SHIFT		0
-
-/*
- * Interrupt register definitions
- */
-#define IDE_INTR_DMA			0x80000000
-#define IDE_INTR_DEVICE			0x40000000
-
-#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
-
-/* Rounded Multiword DMA timings
- * 
- * I gave up finding a generic formula for all controller
- * types and instead, built tables based on timing values
- * used by Apple in Darwin's implementation.
- */
-struct mdma_timings_t {
-	int	accessTime;
-	int	recoveryTime;
-	int	cycleTime;
-};
-
-struct mdma_timings_t mdma_timings_33[] __pmacdata =
-{
-    { 240, 240, 480 },
-    { 180, 180, 360 },
-    { 135, 135, 270 },
-    { 120, 120, 240 },
-    { 105, 105, 210 },
-    {  90,  90, 180 },
-    {  75,  75, 150 },
-    {  75,  45, 120 },
-    {   0,   0,   0 }
-};
-
-struct mdma_timings_t mdma_timings_33k[] __pmacdata =
-{
-    { 240, 240, 480 },
-    { 180, 180, 360 },
-    { 150, 150, 300 },
-    { 120, 120, 240 },
-    {  90, 120, 210 },
-    {  90,  90, 180 },
-    {  90,  60, 150 },
-    {  90,  30, 120 },
-    {   0,   0,   0 }
-};
-
-struct mdma_timings_t mdma_timings_66[] __pmacdata =
-{
-    { 240, 240, 480 },
-    { 180, 180, 360 },
-    { 135, 135, 270 },
-    { 120, 120, 240 },
-    { 105, 105, 210 },
-    {  90,  90, 180 },
-    {  90,  75, 165 },
-    {  75,  45, 120 },
-    {   0,   0,   0 }
-};
-
-/* Ultra DMA timings (rounded) */
-struct {
-	int	addrSetup; /* ??? */
-	int	rdy2pause;
-	int	wrDataSetup;
-} udma_timings[] __pmacdata =
-{
-    {   0, 180,  120 },	/* Mode 0 */
-    {   0, 150,  90 },	/*      1 */
-    {   0, 120,  60 },	/*      2 */
-    {   0, 90,   45 },	/*      3 */
-    {   0, 90,   30 }	/*      4 */
-};
-
-/* allow up to 256 DBDMA commands per xfer */
-#define MAX_DCMDS		256
-
-/* Wait 2s for disk to answer on IDE bus after
- * enable operation.
- * NOTE: There is at least one case I know of a disk that needs about 10sec
- *       before anwering on the bus. I beleive we could add a kernel command
- *       line arg to override this delay for such cases.
- */
-#define IDE_WAKEUP_DELAY_MS	2000
-
-static void pmac_ide_setup_dma(struct device_node *np, int ix);
-static int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive);
-static int pmac_ide_build_dmatable(ide_drive_t *drive, int ix, int wr);
-static int pmac_ide_tune_chipset(ide_drive_t *drive, byte speed);
-static void pmac_ide_tuneproc(ide_drive_t *drive, byte pio);
-static void pmac_ide_selectproc(ide_drive_t *drive);
-
-#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
-
-#ifdef CONFIG_PMAC_PBOOK
-static int idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when);
-struct pmu_sleep_notifier idepmac_sleep_notifier = {
-	idepmac_notify_sleep, SLEEP_LEVEL_BLOCK,
-};
-#endif /* CONFIG_PMAC_PBOOK */
-
-static int pmac_ide_notify_reboot(struct notifier_block *, unsigned long, void *);
-static struct notifier_block pmac_ide_reboot_notifier = {
-	pmac_ide_notify_reboot,
-	NULL,
-	0
-};
-
-static int __pmac
-pmac_ide_find(ide_drive_t *drive)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	ide_ioreg_t base;
-	int i;
-	
-	for (i=0; i<pmac_ide_count; i++) {
-		base = pmac_ide[i].regbase;
-		if (base && base == hwif->io_ports[0])
-			return i;
-	}
-	return -1;
-}
-
-/*
- * N.B. this can't be an initfunc, because the media-bay task can
- * call ide_[un]register at any time.
- */
-void __pmac
-pmac_ide_init_hwif_ports(hw_regs_t *hw,
-			      ide_ioreg_t data_port, ide_ioreg_t ctrl_port,
-			      int *irq)
-{
-	int i, ix;
-
-	if (data_port == 0)
-		return;
-
-	for (ix = 0; ix < MAX_HWIFS; ++ix)
-		if (data_port == pmac_ide[ix].regbase)
-			break;
-
-	if (ix >= MAX_HWIFS) {
-		/* Probably a PCI interface... */
-		for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; ++i)
-			hw->io_ports[i] = data_port + i - IDE_DATA_OFFSET;
-		hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
-		return;
-	}
-
-	for (i = 0; i < 8; ++i)
-		hw->io_ports[i] = data_port + i * 0x10;
-	hw->io_ports[8] = data_port + 0x160;
-
-	if (irq != NULL)
-		*irq = pmac_ide[ix].irq;
-
-	ide_hwifs[ix].tuneproc = pmac_ide_tuneproc;
-	ide_hwifs[ix].selectproc = pmac_ide_selectproc;
-	ide_hwifs[ix].speedproc = &pmac_ide_tune_chipset;
-	if (pmac_ide[ix].dma_regs && pmac_ide[ix].dma_table_cpu) {
-		ide_hwifs[ix].dmaproc = &pmac_ide_dmaproc;
-#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO
-		if (!noautodma)
-			ide_hwifs[ix].autodma = 1;
-#endif
-	}
-}
-
-#if 0
-/* This one could be later extended to handle CMD IDE and be used by some kind
- * of /proc interface. I want to be able to get the devicetree path of a block
- * device for yaboot configuration
- */
-struct device_node*
-pmac_ide_get_devnode(ide_drive_t *drive)
-{
-	int i = pmac_ide_find(drive);
-	if (i < 0)
-		return NULL;
-	return pmac_ide[i].node;
-}
-#endif
-
-/* Setup timings for the selected drive (master/slave). I still need to verify if this
- * is enough, I beleive selectproc will be called whenever an IDE command is started,
- * but... */
-static void __pmac
-pmac_ide_selectproc(ide_drive_t *drive)
-{
-	int i = pmac_ide_find(drive);
-	if (i < 0)
-		return;
-
-	if (drive->select.b.unit & 0x01)
-		out_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE),
-			pmac_ide[i].timings[1]);
-	else
-		out_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE),
-			pmac_ide[i].timings[0]);
-	(void)in_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE));
-}
-
-
-/* Note: We don't use the generic routine here because for some
- * yet unexplained reasons, it cause some media-bay CD-ROMs to
- * lockup the bus. Strangely, this new version of the code is
- * almost identical to the generic one and works, I've not yet
- * managed to figure out what bit is causing the lockup in the
- * generic code, possibly a timing issue...
- * 
- * --BenH
- */
-static int __pmac
-wait_for_ready(ide_drive_t *drive)
-{
-	/* Timeout bumped for some powerbooks */
-	int timeout = 2000;
-	byte stat;
-
-	while(--timeout) {
-		stat = GET_STAT();
-		if(!(stat & BUSY_STAT)) {
-			if (drive->ready_stat == 0)
-				break;
-			else if((stat & drive->ready_stat) || (stat & ERR_STAT))
-				break;
-		}
-		mdelay(1);
-	}
-	if((stat & ERR_STAT) || timeout <= 0) {
-		if (stat & ERR_STAT) {
-			printk(KERN_ERR "ide_pmac: wait_for_ready, error status: %x\n", stat);
-		}
-		return 1;
-	}
-	return 0;
-}
-
-static int __pmac
-pmac_ide_do_setfeature(ide_drive_t *drive, byte command)
-{
-	int result = 1;
-	ide_hwif_t *hwif = HWIF(drive);
-	
-	disable_irq(hwif->irq);	/* disable_irq_nosync ?? */
-	udelay(1);
-	SELECT_DRIVE(HWIF(drive), drive);
-	SELECT_MASK(HWIF(drive), drive, 0);
-	udelay(1);
-	(void)GET_STAT(); /* Get rid of pending error state */
-	if(wait_for_ready(drive)) {
-		printk(KERN_ERR "pmac_ide_do_setfeature disk not ready before SET_FEATURE!\n");
-		goto out;
-	}
-	udelay(10);
-	OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG);
-	OUT_BYTE(command, IDE_NSECTOR_REG);
-	OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG);
-	OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG);
-	udelay(1);
-	result = wait_for_ready(drive);
-	OUT_BYTE(drive->ctl, IDE_CONTROL_REG);
-	if (result)
-		printk(KERN_ERR "pmac_ide_do_setfeature disk not ready after SET_FEATURE !\n");
-out:
-	SELECT_MASK(HWIF(drive), drive, 0);
-	if (result == 0) {
-		drive->id->dma_ultra &= ~0xFF00;
-		drive->id->dma_mword &= ~0x0F00;
-		drive->id->dma_1word &= ~0x0F00;
-		switch(command) {
-			case XFER_UDMA_7:   drive->id->dma_ultra |= 0x8080; break;
-			case XFER_UDMA_6:   drive->id->dma_ultra |= 0x4040; break;
-			case XFER_UDMA_5:   drive->id->dma_ultra |= 0x2020; break;
-			case XFER_UDMA_4:   drive->id->dma_ultra |= 0x1010; break;
-			case XFER_UDMA_3:   drive->id->dma_ultra |= 0x0808; break;
-			case XFER_UDMA_2:   drive->id->dma_ultra |= 0x0404; break;
-			case XFER_UDMA_1:   drive->id->dma_ultra |= 0x0202; break;
-			case XFER_UDMA_0:   drive->id->dma_ultra |= 0x0101; break;
-			case XFER_MW_DMA_2: drive->id->dma_mword |= 0x0404; break;
-			case XFER_MW_DMA_1: drive->id->dma_mword |= 0x0202; break;
-			case XFER_MW_DMA_0: drive->id->dma_mword |= 0x0101; break;
-			case XFER_SW_DMA_2: drive->id->dma_1word |= 0x0404; break;
-			case XFER_SW_DMA_1: drive->id->dma_1word |= 0x0202; break;
-			case XFER_SW_DMA_0: drive->id->dma_1word |= 0x0101; break;
-			default: break;
-		}
-	}
-	enable_irq(hwif->irq);
-	return result;
-}
-
-/* Calculate PIO timings */
-static void __pmac
-pmac_ide_tuneproc(ide_drive_t *drive, byte pio)
-{
-	ide_pio_data_t d;
-	int i;
-	u32 *timings;
-	unsigned accessTicks, recTicks;
-	unsigned accessTime, recTime;
-	
-	i = pmac_ide_find(drive);
-	if (i < 0)
-		return;
-		
-	pio = ide_get_best_pio_mode(drive, pio, 4, &d);
-	accessTicks = SYSCLK_TICKS(ide_pio_timings[pio].active_time);
-	if (drive->select.b.unit & 0x01)
-		timings = &pmac_ide[i].timings[1];
-	else
-		timings = &pmac_ide[i].timings[0];
-
-	recTime = d.cycle_time - ide_pio_timings[pio].active_time
-			- ide_pio_timings[pio].setup_time;
-	recTime = max(recTime, 150U);
-	accessTime = ide_pio_timings[pio].active_time;
-	accessTime = max(accessTime, 150U);
-	if (pmac_ide[i].kind == controller_kl_ata4 ||
-		pmac_ide[i].kind == controller_kl_ata4_80) {
-		/* 66Mhz cell */
-		accessTicks = SYSCLK_TICKS_66(accessTime);
-		accessTicks = min(accessTicks, 0x1fU);
-		recTicks = SYSCLK_TICKS_66(recTime);
-		recTicks = min(recTicks, 0x1fU);
-		*timings = ((*timings) & ~TR_66_PIO_MASK) |
-				(accessTicks << TR_66_PIO_ACCESS_SHIFT) |
-				(recTicks << TR_66_PIO_RECOVERY_SHIFT);
-	} else {
-		/* 33Mhz cell */
-		int ebit = 0;
-		accessTicks = SYSCLK_TICKS(accessTime);
-		accessTicks = min(accessTicks, 0x1fU);
-		accessTicks = max(accessTicks, 4U);
-		recTicks = SYSCLK_TICKS(recTime);
-		recTicks = min(recTicks, 0x1fU);
-		recTicks = max(recTicks, 5U) - 4;
-		if (recTicks > 9) {
-			recTicks--; /* guess, but it's only for PIO0, so... */
-			ebit = 1;
-		}
-		*timings = ((*timings) & ~TR_33_PIO_MASK) |
-				(accessTicks << TR_33_PIO_ACCESS_SHIFT) |
-				(recTicks << TR_33_PIO_RECOVERY_SHIFT);
-		if (ebit)
-			*timings |= TR_33_PIO_E;
-	}
-
-#ifdef IDE_PMAC_DEBUG
-	printk(KERN_ERR "ide_pmac: Set PIO timing for mode %d, reg: 0x%08x\n",
-		pio,  *timings);
-#endif	
-		
-	if (drive->select.all == IN_BYTE(IDE_SELECT_REG))
-		pmac_ide_selectproc(drive);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
-static int __pmac
-set_timings_udma(u32 *timings, byte speed)
-{
-	unsigned rdyToPauseTicks, wrDataSetupTicks, addrTicks;
-
-	rdyToPauseTicks = SYSCLK_TICKS_66(udma_timings[speed & 0xf].rdy2pause);
-	wrDataSetupTicks = SYSCLK_TICKS_66(udma_timings[speed & 0xf].wrDataSetup);
-	addrTicks = SYSCLK_TICKS_66(udma_timings[speed & 0xf].addrSetup);
-
-	*timings = ((*timings) & ~(TR_66_UDMA_MASK | TR_66_MDMA_MASK)) |
-			(wrDataSetupTicks << TR_66_UDMA_WRDATASETUP_SHIFT) | 
-			(rdyToPauseTicks << TR_66_UDMA_RDY2PAUS_SHIFT) |
-			(addrTicks <<TR_66_UDMA_ADDRSETUP_SHIFT) |
-			TR_66_UDMA_EN;
-#ifdef IDE_PMAC_DEBUG
-	printk(KERN_ERR "ide_pmac: Set UDMA timing for mode %d, reg: 0x%08x\n",
-		speed & 0xf,  *timings);
-#endif	
-
-	return 0;
-}
-
-static int __pmac
-set_timings_mdma(int intf_type, u32 *timings, byte speed, int drive_cycle_time)
-{
-	int cycleTime, accessTime, recTime;
-	unsigned accessTicks, recTicks;
-	struct mdma_timings_t* tm;
-	int i;
-
-	/* Get default cycle time for mode */
-	switch(speed & 0xf) {
-		case 0: cycleTime = 480; break;
-		case 1: cycleTime = 150; break;
-		case 2: cycleTime = 120; break;
-		default:
-			return -1;
-	}
-	/* Adjust for drive */
-	if (drive_cycle_time && drive_cycle_time > cycleTime)
-		cycleTime = drive_cycle_time;
-	/* OHare limits according to some old Apple sources */	
-	if ((intf_type == controller_ohare) && (cycleTime < 150))
-		cycleTime = 150;
-	/* Get the proper timing array for this controller */
-	switch(intf_type) {
-		case controller_kl_ata4:
-		case controller_kl_ata4_80:
-			tm = mdma_timings_66;
-			break;
-		case controller_kl_ata3:
-			tm = mdma_timings_33k;
-			break;
-		default:
-			tm = mdma_timings_33;
-			break;
-	}
-	/* Lookup matching access & recovery times */
-	i = -1;
-	for (;;) {
-		if (tm[i+1].cycleTime < cycleTime)
-			break;
-		i++;
-	}
-	if (i < 0)
-		return -1;
-	cycleTime = tm[i].cycleTime;
-	accessTime = tm[i].accessTime;
-	recTime = tm[i].recoveryTime;
-
-#ifdef IDE_PMAC_DEBUG
-	printk(KERN_ERR "ide_pmac: MDMA, cycleTime: %d, accessTime: %d, recTime: %d\n",
-		cycleTime, accessTime, recTime);
-#endif	
-	if (intf_type == controller_kl_ata4 || intf_type == controller_kl_ata4_80) {
-		/* 66Mhz cell */
-		accessTicks = SYSCLK_TICKS_66(accessTime);
-		accessTicks = min(accessTicks, 0x1fU);
-		accessTicks = max(accessTicks, 0x1U);
-		recTicks = SYSCLK_TICKS_66(recTime);
-		recTicks = min(recTicks, 0x1fU);
-		recTicks = max(recTicks, 0x3U);
-		/* Clear out mdma bits and disable udma */
-		*timings = ((*timings) & ~(TR_66_MDMA_MASK | TR_66_UDMA_MASK)) |
-			(accessTicks << TR_66_MDMA_ACCESS_SHIFT) |
-			(recTicks << TR_66_MDMA_RECOVERY_SHIFT);
-	} else if (intf_type == controller_kl_ata3) {
-		/* 33Mhz cell on KeyLargo */
-		accessTicks = SYSCLK_TICKS(accessTime);
-		accessTicks = max(accessTicks, 1U);
-		accessTicks = min(accessTicks, 0x1fU);
-		accessTime = accessTicks * IDE_SYSCLK_NS;
-		recTicks = SYSCLK_TICKS(recTime);
-		recTicks = max(recTicks, 1U);
-		recTicks = min(recTicks, 0x1fU);
-		*timings = ((*timings) & ~TR_33_MDMA_MASK) |
-				(accessTicks << TR_33_MDMA_ACCESS_SHIFT) |
-				(recTicks << TR_33_MDMA_RECOVERY_SHIFT);
-	} else {
-		/* 33Mhz cell on others */
-		int halfTick = 0;
-		int origAccessTime = accessTime;
-		int origRecTime = recTime;
-		
-		accessTicks = SYSCLK_TICKS(accessTime);
-		accessTicks = max(accessTicks, 1U);
-		accessTicks = min(accessTicks, 0x1fU);
-		accessTime = accessTicks * IDE_SYSCLK_NS;
-		recTicks = SYSCLK_TICKS(recTime);
-		recTicks = max(recTicks, 2U) - 1;
-		recTicks = min(recTicks, 0x1fU);
-		recTime = (recTicks + 1) * IDE_SYSCLK_NS;
-		if ((accessTicks > 1) &&
-		    ((accessTime - IDE_SYSCLK_NS/2) >= origAccessTime) &&
-		    ((recTime - IDE_SYSCLK_NS/2) >= origRecTime)) {
-            		halfTick = 1;
-			accessTicks--;
-		}
-		*timings = ((*timings) & ~TR_33_MDMA_MASK) |
-				(accessTicks << TR_33_MDMA_ACCESS_SHIFT) |
-				(recTicks << TR_33_MDMA_RECOVERY_SHIFT);
-		if (halfTick)
-			*timings |= TR_33_MDMA_HALFTICK;
-	}
-#ifdef IDE_PMAC_DEBUG
-	printk(KERN_ERR "ide_pmac: Set MDMA timing for mode %d, reg: 0x%08x\n",
-		speed & 0xf,  *timings);
-#endif	
-	return 0;
-}
-#endif /* #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC */
-
-/* You may notice we don't use this function on normal operation,
- * our, normal mdma function is supposed to be more precise
- */
-static int __pmac
-pmac_ide_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	int intf		= pmac_ide_find(drive);
-	int unit		= (drive->select.b.unit & 0x01);
-	int ret			= 0;
-	u32 *timings;
-
-	if (intf < 0)
-		return 1;
-		
-	timings = &pmac_ide[intf].timings[unit];
-	
-	switch(speed) {
-#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
-		case XFER_UDMA_4:
-		case XFER_UDMA_3:
-			if (pmac_ide[intf].kind != controller_kl_ata4_80)
-				return 1;		
-		case XFER_UDMA_2:
-		case XFER_UDMA_1:
-		case XFER_UDMA_0:
-			if (pmac_ide[intf].kind != controller_kl_ata4 &&
-				pmac_ide[intf].kind != controller_kl_ata4_80)
-				return 1;		
-			ret = set_timings_udma(timings, speed);
-			break;
-		case XFER_MW_DMA_2:
-		case XFER_MW_DMA_1:
-		case XFER_MW_DMA_0:
-			ret = set_timings_mdma(pmac_ide[intf].kind, timings, speed, 0);
-			break;
-		case XFER_SW_DMA_2:
-		case XFER_SW_DMA_1:
-		case XFER_SW_DMA_0:
-			return 1;
-#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
-		case XFER_PIO_4:
-		case XFER_PIO_3:
-		case XFER_PIO_2:
-		case XFER_PIO_1:
-		case XFER_PIO_0:
-			pmac_ide_tuneproc(drive, speed & 0x07);
-			break;
-		default:
-			ret = 1;
-	}
-	if (ret)
-		return ret;
-
-	ret = pmac_ide_do_setfeature(drive, speed);
-	if (ret)
-		return ret;
-		
-	pmac_ide_selectproc(drive);	
-	drive->current_speed = speed;
-
-	return 0;
-}
-
-static void __pmac
-sanitize_timings(int i)
-{
-	unsigned value;
-	
-	switch(pmac_ide[i].kind) {
-		case controller_kl_ata4:
-		case controller_kl_ata4_80:
-			value = 0x0008438c;
-			break;
-		case controller_kl_ata3:
-			value = 0x00084526;
-			break;
-		case controller_heathrow:
-		case controller_ohare:
-		default:
-			value = 0x00074526;
-			break;
-	}
-	pmac_ide[i].timings[0] = pmac_ide[i].timings[1] = value;
-}
-
-ide_ioreg_t __pmac
-pmac_ide_get_base(int index)
-{
-	return pmac_ide[index].regbase;
-}
-
-int __pmac
-pmac_ide_check_base(ide_ioreg_t base)
-{
-	int ix;
-	
- 	for (ix = 0; ix < MAX_HWIFS; ++ix)
-		if (base == pmac_ide[ix].regbase)
-			return ix;
-	return -1;
-}
-
-int __pmac
-pmac_ide_get_irq(ide_ioreg_t base)
-{
-	int ix;
-
-	for (ix = 0; ix < MAX_HWIFS; ++ix)
-		if (base == pmac_ide[ix].regbase)
-			return pmac_ide[ix].irq;
-	return 0;
-}
-
-static int ide_majors[]  __pmacdata = { 3, 22, 33, 34, 56, 57 };
-
-kdev_t __init
-pmac_find_ide_boot(char *bootdevice, int n)
-{
-	int i;
-	
-	/*
-	 * Look through the list of IDE interfaces for this one.
-	 */
-	for (i = 0; i < pmac_ide_count; ++i) {
-		char *name;
-		if (!pmac_ide[i].node || !pmac_ide[i].node->full_name)
-			continue;
-		name = pmac_ide[i].node->full_name;
-		if (memcmp(name, bootdevice, n) == 0 && name[n] == 0) {
-			/* XXX should cope with the 2nd drive as well... */
-			return MKDEV(ide_majors[i], 0);
-		}
-	}
-
-	return 0;
-}
-
-void __init
-pmac_ide_probe(void)
-{
-	struct device_node *np;
-	int i;
-	struct device_node *atas;
-	struct device_node *p, **pp, *removables, **rp;
-	unsigned long base;
-	int irq, big_delay;
-	ide_hwif_t *hwif;
-
-	if (_machine != _MACH_Pmac)
-		return;
-	pp = &atas;
-	rp = &removables;
-	p = find_devices("ATA");
-	if (p == NULL)
-		p = find_devices("IDE");
-	if (p == NULL)
-		p = find_type_devices("ide");
-	if (p == NULL)
-		p = find_type_devices("ata");
-	/* Move removable devices such as the media-bay CDROM
-	   on the PB3400 to the end of the list. */
-	for (; p != NULL; p = p->next) {
-		if (p->parent && p->parent->type
-		    && strcasecmp(p->parent->type, "media-bay") == 0) {
-			*rp = p;
-			rp = &p->next;
-		} else {
-			*pp = p;
-			pp = &p->next;
-		}
-	}
-	*rp = NULL;
-	*pp = removables;
-	big_delay = 0;
-
-	for (i = 0, np = atas; i < MAX_HWIFS && np != NULL; np = np->next) {
-		struct device_node *tp;
-		struct pmac_ide_hwif* pmhw;
-		int *bidp;
-		int in_bay = 0;
-		u8 pbus, pid;
-		struct pci_dev *pdev = NULL;
-
-		/*
-		 * If this node is not under a mac-io or dbdma node,
-		 * leave it to the generic PCI driver.
-		 */
-		for (tp = np->parent; tp != 0; tp = tp->parent)
-			if (tp->type && (strcmp(tp->type, "mac-io") == 0
-					 || strcmp(tp->type, "dbdma") == 0))
-				break;
-		if (tp == 0)
-			continue;
-
-		if (np->n_addrs == 0) {
-			printk(KERN_WARNING "ide: no address for device %s\n",
-			       np->full_name);
-			continue;
-		}
-
-		/* We need to find the pci_dev of the mac-io holding the
-		 * IDE interface
-		 */
-		if (pci_device_from_OF_node(tp, &pbus, &pid) == 0)
-			pdev = pci_find_slot(pbus, pid);
-		if (pdev == NULL)
-			printk(KERN_WARNING "ide: no PCI host for device %s, DMA disabled\n",
-			       np->full_name);
-
-		/*
-		 * If this slot is taken (e.g. by ide-pci.c) try the next one.
-		 */
-		while (i < MAX_HWIFS
-		       && ide_hwifs[i].io_ports[IDE_DATA_OFFSET] != 0)
-			++i;
-		if (i >= MAX_HWIFS)
-			break;
-		pmhw = &pmac_ide[i];
-
-		/*
-		 * Some older OFs have bogus sizes, causing request_OF_resource
-		 * to fail. We fix them up here
-		 */
-		if (np->addrs[0].size > 0x1000)
-			np->addrs[0].size = 0x1000;
-		if (np->n_addrs > 1 && np->addrs[1].size > 0x100)
-			np->addrs[1].size = 0x100;
-
-		if (request_OF_resource(np, 0, "  (mac-io IDE IO)") == NULL) {
-			printk(KERN_ERR "ide-pmac(%s): can't request IO resource !\n", np->name);
-			continue;
-		}
-
-		base = (unsigned long) ioremap(np->addrs[0].address, 0x400) - _IO_BASE;
-
-		/* XXX This is bogus. Should be fixed in the registry by checking
-		   the kind of host interrupt controller, a bit like gatwick
-		   fixes in irq.c
-		 */
-		if (np->n_intrs == 0) {
-			printk(KERN_WARNING "ide: no intrs for device %s, using 13\n",
-			       np->full_name);
-			irq = 13;
-		} else {
-			irq = np->intrs[0].line;
-		}
-		pmhw->regbase = base;
-		pmhw->irq = irq;
-		pmhw->node = np;
-		if (device_is_compatible(np, "keylargo-ata")) {
-			if (strcmp(np->name, "ata-4") == 0)
-				pmhw->kind = controller_kl_ata4;
-			else
-				pmhw->kind = controller_kl_ata3;
-		} else if (device_is_compatible(np, "heathrow-ata"))
-			pmhw->kind = controller_heathrow;
-		else
-			pmhw->kind = controller_ohare;
-
-		bidp = (int *)get_property(np, "AAPL,bus-id", NULL);
-		pmhw->aapl_bus_id =  bidp ? *bidp : 0;
-
-		if (pmhw->kind == controller_kl_ata4) {
-			char* cable = get_property(np, "cable-type", NULL);
-			if (cable && !strncmp(cable, "80-", 3))
-				pmhw->kind = controller_kl_ata4_80;
-		}
-
-		/* Make sure we have sane timings */
-		sanitize_timings(i);
-
-		if (np->parent && np->parent->name
-		    && strcasecmp(np->parent->name, "media-bay") == 0) {
-#ifdef CONFIG_PMAC_PBOOK
-			media_bay_set_ide_infos(np->parent,base,irq,i);
-#endif /* CONFIG_PMAC_PBOOK */
-			in_bay = 1;
-			if (!bidp)
-				pmhw->aapl_bus_id = 1;
-		} else if (pmhw->kind == controller_ohare) {
-			/* The code below is having trouble on some ohare machines
-			 * (timing related ?). Until I can put my hand on one of these
-			 * units, I keep the old way
-			 */
-			ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, 0, 1);
-		} else {
- 			/* This is necessary to enable IDE when net-booting */
-			printk(KERN_INFO "pmac_ide: enabling IDE bus ID %d\n",
-				pmhw->aapl_bus_id);
-			ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmhw->aapl_bus_id, 1);
-			ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmhw->aapl_bus_id, 1);
-			mdelay(10);
-			ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmhw->aapl_bus_id, 0);
-			big_delay = 1;
-		}
-
-		hwif = &ide_hwifs[i];
-		pmac_ide_init_hwif_ports(&hwif->hw, base, 0, &hwif->irq);
-		memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
-		hwif->chipset = ide_pmac;
-		hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET] || in_bay;
-		hwif->udma_four = (pmhw->kind == controller_kl_ata4_80);
-		hwif->pci_dev = pdev;
-		hwif->drives[0].unmask = 1;
-		hwif->drives[1].unmask = 1;
-#ifdef CONFIG_PMAC_PBOOK
-		if (in_bay && check_media_bay_by_base(base, MB_CD) == 0)
-			hwif->noprobe = 0;
-#endif /* CONFIG_PMAC_PBOOK */
-
-#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
-		if (np->n_addrs >= 2) {
-			/* has a DBDMA controller channel */
-			pmac_ide_setup_dma(np, i);
-		}
-#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
-
-		++i;
-	}
-	pmac_ide_count = i;
-	if (big_delay)
-		mdelay(IDE_WAKEUP_DELAY_MS);
-
-#ifdef CONFIG_PMAC_PBOOK
-	pmu_register_sleep_notifier(&idepmac_sleep_notifier);
-#endif /* CONFIG_PMAC_PBOOK */
-	register_reboot_notifier(&pmac_ide_reboot_notifier);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
-
-static void __init 
-pmac_ide_setup_dma(struct device_node *np, int ix)
-{
-	struct pmac_ide_hwif *pmif = &pmac_ide[ix];
-
-	if (request_OF_resource(np, 1, " (mac-io IDE DMA)") == NULL) {
-		printk(KERN_ERR "ide-pmac(%s): can't request DMA resource !\n", np->name);
-		return;
-	}
-
-	pmif->dma_regs =
-		(volatile struct dbdma_regs*)ioremap(np->addrs[1].address, 0x200);
-
-	/*
-	 * Allocate space for the DBDMA commands.
-	 * The +2 is +1 for the stop command and +1 to allow for
-	 * aligning the start address to a multiple of 16 bytes.
-	 */
-	pmif->dma_table_cpu = (struct dbdma_cmd*)pci_alloc_consistent(
-		ide_hwifs[ix].pci_dev,
-		(MAX_DCMDS + 2) * sizeof(struct dbdma_cmd),
-		&pmif->dma_table_dma);
-	if (pmif->dma_table_cpu == NULL) {
-		printk(KERN_ERR "%s: unable to allocate DMA command list\n",
-		       ide_hwifs[ix].name);
-		return;
-	}
-
-	pmif->sg_table = kmalloc(sizeof(struct scatterlist) * MAX_DCMDS,
-				 GFP_KERNEL);
-	if (pmif->sg_table == NULL) {
-		pci_free_consistent(	ide_hwifs[ix].pci_dev,
-					(MAX_DCMDS + 2) * sizeof(struct dbdma_cmd),
-				    	pmif->dma_table_cpu, pmif->dma_table_dma);
-		return;
-	}
-	ide_hwifs[ix].dmaproc = &pmac_ide_dmaproc;
-#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO
-	if (!noautodma)
-		ide_hwifs[ix].autodma = 1;
-#endif
-}
-
-static int
-pmac_ide_build_sglist (int ix, struct request *rq)
-{
-	ide_hwif_t *hwif = &ide_hwifs[ix];
-	struct pmac_ide_hwif *pmif = &pmac_ide[ix];
-	struct buffer_head *bh;
-	struct scatterlist *sg = pmif->sg_table;
-	unsigned long lastdataend = ~0UL;
-	int nents = 0;
-
-	if (hwif->sg_dma_active)
-		BUG();
-
-	if (rq->cmd == READ)
-		pmif->sg_dma_direction = PCI_DMA_FROMDEVICE;
-	else
-		pmif->sg_dma_direction = PCI_DMA_TODEVICE;
-
-	bh = rq->bh;
-	do {
-		struct scatterlist *sge;
-		unsigned int size = bh->b_size;
-
-		/* continue segment from before? */
-		if (bh_phys(bh) == lastdataend) {
-			sg[nents-1].length += size;
-			lastdataend += size;
-			continue;
-		}
-
-		/* start new segment */
-		if (nents >= MAX_DCMDS)
-			return 0;
-
-		sge = &sg[nents];
-		memset(sge, 0, sizeof(*sge));
-
-		if (bh->b_page) {
-			sge->page = bh->b_page;
-			sge->offset = bh_offset(bh);
-		} else {
-			if ((unsigned long)bh->b_data < PAGE_SIZE)
-				BUG();
-			sge->address = bh->b_data;
-		}
-		sge->length = size;
-		lastdataend = bh_phys(bh) + size;
-		nents++;
-	} while ((bh = bh->b_reqnext) != NULL);
-
-	return pci_map_sg(hwif->pci_dev, sg, nents, pmif->sg_dma_direction);
-}
-
-static int
-pmac_ide_raw_build_sglist (int ix, struct request *rq)
-{
-	ide_hwif_t *hwif = &ide_hwifs[ix];
-	struct pmac_ide_hwif *pmif = &pmac_ide[ix];
-	struct scatterlist *sg = hwif->sg_table;
-	int nents = 0;
-	ide_task_t *args = rq->special;
-	unsigned char *virt_addr = rq->buffer;
-	int sector_count = rq->nr_sectors;
-
-//	if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_WRITEDMA) ||
-//	    (args->tfRegister[IDE_COMMAND_OFFSET] == WIN_WRITEDMA_EXT))
-	if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
-		pmif->sg_dma_direction = PCI_DMA_TODEVICE;
-	else
-		pmif->sg_dma_direction = PCI_DMA_FROMDEVICE;
-	
-	if (sector_count > 128) {
-		memset(&sg[nents], 0, sizeof(*sg));
-		sg[nents].address = virt_addr;
-		sg[nents].length = 128  * SECTOR_SIZE;
-		nents++;
-		virt_addr = virt_addr + (128 * SECTOR_SIZE);
-		sector_count -= 128;
-	}
-	memset(&sg[nents], 0, sizeof(*sg));
-	sg[nents].address = virt_addr;
-	sg[nents].length =  sector_count  * SECTOR_SIZE;
-	nents++;
-   
-	return pci_map_sg(hwif->pci_dev, sg, nents, pmif->sg_dma_direction);
-}
-
-/*
- * pmac_ide_build_dmatable builds the DBDMA command list
- * for a transfer and sets the DBDMA channel to point to it.
- */
-static int
-pmac_ide_build_dmatable(ide_drive_t *drive, int ix, int wr)
-{
-	struct dbdma_cmd *table;
-	int i, count = 0;
-	struct request *rq = HWGROUP(drive)->rq;
-	volatile struct dbdma_regs *dma = pmac_ide[ix].dma_regs;
-	struct scatterlist *sg;
-
-	/* DMA table is already aligned */
-	table = (struct dbdma_cmd *) pmac_ide[ix].dma_table_cpu;
-
-	/* Make sure DMA controller is stopped (necessary ?) */
-	out_le32(&dma->control, (RUN|PAUSE|FLUSH|WAKE|DEAD) << 16);
-	while (in_le32(&dma->status) & RUN)
-		udelay(1);
-
-	/* Build sglist */
-	if (HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE)
-		pmac_ide[ix].sg_nents = i = pmac_ide_raw_build_sglist(ix, rq);
-	else
-		pmac_ide[ix].sg_nents = i = pmac_ide_build_sglist(ix, rq);
-	if (!i)
-		return 0;
-
-	/* Build DBDMA commands list */
-	sg = pmac_ide[ix].sg_table;
-	while (i) {
-		u32 cur_addr;
-		u32 cur_len;
-
-		cur_addr = sg_dma_address(sg);
-		cur_len = sg_dma_len(sg);
-
-		while (cur_len) {
-			unsigned int tc = (cur_len < 0xfe00)? cur_len: 0xfe00;
-
-			if (++count >= MAX_DCMDS) {
-				printk(KERN_WARNING "%s: DMA table too small\n",
-				       drive->name);
-				return 0; /* revert to PIO for this request */
-			}
-			st_le16(&table->command, wr? OUTPUT_MORE: INPUT_MORE);
-			st_le16(&table->req_count, tc);
-			st_le32(&table->phy_addr, cur_addr);
-			table->cmd_dep = 0;
-			table->xfer_status = 0;
-			table->res_count = 0;
-			cur_addr += tc;
-			cur_len -= tc;
-			++table;
-		}
-		sg++;
-		i--;
-	}
-
-	/* convert the last command to an input/output last command */
-	if (count)
-		st_le16(&table[-1].command, wr? OUTPUT_LAST: INPUT_LAST);
-	else
-		printk(KERN_DEBUG "%s: empty DMA table?\n", drive->name);
-
-	/* add the stop command to the end of the list */
-	memset(table, 0, sizeof(struct dbdma_cmd));
-	out_le16(&table->command, DBDMA_STOP);
-
-	out_le32(&dma->cmdptr, pmac_ide[ix].dma_table_dma);
-	return 1;
-}
-
-/* Teardown mappings after DMA has completed.  */
-static void
-pmac_ide_destroy_dmatable (ide_drive_t *drive, int ix)
-{
-	struct pci_dev *dev = HWIF(drive)->pci_dev;
-	struct scatterlist *sg = pmac_ide[ix].sg_table;
-	int nents = pmac_ide[ix].sg_nents;
-
-	if (nents) {
-		pci_unmap_sg(dev, sg, nents, pmac_ide[ix].sg_dma_direction);
-		pmac_ide[ix].sg_nents = 0;
-	}
-}
-
-static __inline__ unsigned char
-dma_bits_to_command(unsigned char bits)
-{
-	if(bits & 0x04)
-		return XFER_MW_DMA_2;
-	if(bits & 0x02)
-		return XFER_MW_DMA_1;
-	if(bits & 0x01)
-		return XFER_MW_DMA_0;
-	return 0;
-}
-
-static __inline__ unsigned char
-udma_bits_to_command(unsigned char bits, int high_speed)
-{
-	if (high_speed) {
-		if(bits & 0x10)
-			return XFER_UDMA_4;
-		if(bits & 0x08)
-			return XFER_UDMA_3;
-	}
-	if(bits & 0x04)
-		return XFER_UDMA_2;
-	if(bits & 0x02)
-		return XFER_UDMA_1;
-	if(bits & 0x01)
-		return XFER_UDMA_0;
-	return 0;
-}
-
-/* Calculate MultiWord DMA timings */
-static int __pmac
-pmac_ide_mdma_enable(ide_drive_t *drive, int idx)
-{
-	byte bits = drive->id->dma_mword & 0x07;
-	byte feature = dma_bits_to_command(bits);
-	u32 *timings;
-	int drive_cycle_time;
-	struct hd_driveid *id = drive->id;
-	int ret;
-
-	/* Set feature on drive */
-    	printk(KERN_INFO "%s: Enabling MultiWord DMA %d\n", drive->name, feature & 0xf);
-	ret = pmac_ide_do_setfeature(drive, feature);
-	if (ret) {
-	    	printk(KERN_WARNING "%s: Failed !\n", drive->name);
-	    	return 0;
-	}
-
-	if (!drive->init_speed)
-		drive->init_speed = feature;
-	
-	/* which drive is it ? */
-	if (drive->select.b.unit & 0x01)
-		timings = &pmac_ide[idx].timings[1];
-	else
-		timings = &pmac_ide[idx].timings[0];
-
-	/* Check if drive provide explicit cycle time */
-	if ((id->field_valid & 2) && (id->eide_dma_time))
-		drive_cycle_time = id->eide_dma_time;
-	else
-		drive_cycle_time = 0;
-
-	/* Calculate controller timings */
-	set_timings_mdma(pmac_ide[idx].kind, timings, feature, drive_cycle_time);
-
-	drive->current_speed = feature;	
-	return 1;
-}
-
-/* Calculate Ultra DMA timings */
-static int __pmac
-pmac_ide_udma_enable(ide_drive_t *drive, int idx, int high_speed)
-{
-	byte bits = drive->id->dma_ultra & 0x1f;
-	byte feature = udma_bits_to_command(bits, high_speed);
-	u32 *timings;
-	int ret;
-
-	/* Set feature on drive */
-    	printk(KERN_INFO "%s: Enabling Ultra DMA %d\n", drive->name, feature & 0xf);
-	ret = pmac_ide_do_setfeature(drive, feature);
-	if (ret) {
-		printk(KERN_WARNING "%s: Failed !\n", drive->name);
-		return 0;
-	}
-
-	if (!drive->init_speed)
-		drive->init_speed = feature;
-
-	/* which drive is it ? */
-	if (drive->select.b.unit & 0x01)
-		timings = &pmac_ide[idx].timings[1];
-	else
-		timings = &pmac_ide[idx].timings[0];
-
-	set_timings_udma(timings, feature);
-
-	drive->current_speed = feature;	
-	return 1;
-}
-
-static int __pmac
-pmac_ide_check_dma(ide_drive_t *drive)
-{
-	int ata4, udma, idx;
-	struct hd_driveid *id = drive->id;
-	int enable = 1;
-
-	drive->using_dma = 0;
-	
-	idx = pmac_ide_find(drive);
-	if (idx < 0)
-		return 0;
-		
-	if (drive->media == ide_floppy)
-		enable = 0;
-	if (((id->capability & 1) == 0) && !check_drive_lists(drive, GOOD_DMA_DRIVE))
-		enable = 0;
-	if (check_drive_lists(drive, BAD_DMA_DRIVE))
-		enable = 0;
-
-	udma = 0;
-	ata4 = (pmac_ide[idx].kind == controller_kl_ata4 ||
-		pmac_ide[idx].kind == controller_kl_ata4_80);
-			
-	if(enable) {
-		if (ata4 && (drive->media == ide_disk) &&
-		    (id->field_valid & 0x0004) && (id->dma_ultra & 0x1f)) {
-			/* UltraDMA modes. */
-			drive->using_dma = pmac_ide_udma_enable(drive, idx,
-				pmac_ide[idx].kind == controller_kl_ata4_80);
-		}
-		if (!drive->using_dma && (id->dma_mword & 0x0007)) {
-			/* Normal MultiWord DMA modes. */
-			drive->using_dma = pmac_ide_mdma_enable(drive, idx);
-		}
-		OUT_BYTE(0, IDE_CONTROL_REG);
-		/* Apply settings to controller */
-		pmac_ide_selectproc(drive);
-	}
-	return 0;
-}
-
-static inline void pmac_ide_toggle_bounce(ide_drive_t *drive, int on)
-{
-	dma64_addr_t addr = BLK_BOUNCE_HIGH;
-
-	if (HWIF(drive)->no_highio || HWIF(drive)->pci_dev == NULL)
-		return;
-
-	if (on && drive->media == ide_disk) {
-		if (!PCI_DMA_BUS_IS_PHYS)
-			addr = BLK_BOUNCE_ANY;
-		else
-			addr = HWIF(drive)->pci_dev->dma_mask;
-	}
-
-	blk_queue_bounce_limit(&drive->queue, addr);
-}
-
-static int __pmac
-pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-	int ix, dstat;
-	volatile struct dbdma_regs *dma;
-	byte unit = (drive->select.b.unit & 0x01);
-	byte ata4;
-	int reading = 0;
-
-	/* Can we stuff a pointer to our intf structure in config_data
-	 * or select_data in hwif ?
-	 */
-	ix = pmac_ide_find(drive);
-	if (ix < 0)
-		return 0;		
-	dma = pmac_ide[ix].dma_regs;
-	ata4 = (pmac_ide[ix].kind == controller_kl_ata4 ||
-		pmac_ide[ix].kind == controller_kl_ata4_80);
-	
-	switch (func) {
-	case ide_dma_off:
-		printk(KERN_INFO "%s: DMA disabled\n", drive->name);
-	case ide_dma_off_quietly:
-		drive->using_dma = 0;
-		pmac_ide_toggle_bounce(drive, 0);
-		break;
-	case ide_dma_on:
-	case ide_dma_check:
-		pmac_ide_check_dma(drive);
-		if (drive->using_dma)
-			pmac_ide_toggle_bounce(drive, 1);
-		break;
-	case ide_dma_read:
-		reading = 1;
-	case ide_dma_write:
-		SELECT_READ_WRITE(HWIF(drive),drive,func);
-		if (!pmac_ide_build_dmatable(drive, ix, !reading))
-			return 1;
-		/* Apple adds 60ns to wrDataSetup on reads */
-		if (ata4 && (pmac_ide[ix].timings[unit] & TR_66_UDMA_EN)) {
-			out_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE),
-				pmac_ide[ix].timings[unit] + 
-				(reading ? 0x00800000UL : 0));
-			(void)in_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE));
-		}
-		drive->waiting_for_dma = 1;
-		if (drive->media != ide_disk)
-			return 0;
-		ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
-		if ((HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE) &&
-		    (drive->addressing == 1)) {
-			ide_task_t *args = HWGROUP(drive)->rq->special;
-			OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
-		} else if (drive->addressing) {
-			OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
-		} else {
-			OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
-		}
-	case ide_dma_begin:
-		out_le32(&dma->control, (RUN << 16) | RUN);
-		/* Make sure it gets to the controller right now */
-		(void)in_le32(&dma->control);
-		break;
-	case ide_dma_end: /* returns 1 on error, 0 otherwise */
-		drive->waiting_for_dma = 0;
-		dstat = in_le32(&dma->status);
-		out_le32(&dma->control, ((RUN|WAKE|DEAD) << 16));
-		pmac_ide_destroy_dmatable(drive, ix);
-		/* verify good dma status */
-		return (dstat & (RUN|DEAD|ACTIVE)) != RUN;
-	case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */
-		/* We have to things to deal with here:
-		 * 
-		 * - The dbdma won't stop if the command was started
-		 * but completed with an error without transfering all
-		 * datas. This happens when bad blocks are met during
-		 * a multi-block transfer.
-		 * 
-		 * - The dbdma fifo hasn't yet finished flushing to
-		 * to system memory when the disk interrupt occurs.
-		 * 
-		 * The trick here is to increment drive->waiting_for_dma,
-		 * and return as if no interrupt occured. If the counter
-		 * reach a certain timeout value, we then return 1. If
-		 * we really got the interrupt, it will happen right away
-		 * again.
-		 * Apple's solution here may be more elegant. They issue
-		 * a DMA channel interrupt (a separate irq line) via a DBDMA
-		 * NOP command just before the STOP, and wait for both the
-		 * disk and DBDMA interrupts to have completed.
-		 */
-		 
-		/* If ACTIVE is cleared, the STOP command have passed and
-		 * transfer is complete.
-		 */
-		if (!(in_le32(&dma->status) & ACTIVE))
-			return 1;
-		if (!drive->waiting_for_dma)
-			printk(KERN_WARNING "ide%d, ide_dma_test_irq \
-				called while not waiting\n", ix);
-
-		/* If dbdma didn't execute the STOP command yet, the
-		 * active bit is still set */
-		drive->waiting_for_dma++;
-		if (drive->waiting_for_dma >= DMA_WAIT_TIMEOUT) {
-			printk(KERN_WARNING "ide%d, timeout waiting \
-				for dbdma command stop\n", ix);
-			return 1;
-		}
-		udelay(1);
-		return 0;
-
-		/* Let's implement tose just in case someone wants them */
-	case ide_dma_bad_drive:
-	case ide_dma_good_drive:
-		return check_drive_lists(drive, (func == ide_dma_good_drive));
-	case ide_dma_verbose:
-		return report_drive_dmaing(drive);
-	case ide_dma_retune:
-	case ide_dma_lostirq:
-	case ide_dma_timeout:
-		printk(KERN_WARNING "ide_pmac_dmaproc: chipset supported %s func only: %d\n", ide_dmafunc_verbose(func),  func);
-		return 1;
-	default:
-		printk(KERN_WARNING "ide_pmac_dmaproc: unsupported %s func: %d\n", ide_dmafunc_verbose(func), func);
-		return 1;
-	}
-	return 0;
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
-
-static void __pmac
-idepmac_sleep_device(ide_drive_t *drive, int i, unsigned base)
-{
-	int j;
-	
-	/* FIXME: We only handle the master IDE disk, we shoud
-	 *        try to fix CD-ROMs here
-	 */
-	switch (drive->media) {
-	case ide_disk:
-		/* Spin down the drive */
-		outb(drive->select.all, base+0x60);
-		(void)inb(base+0x60);
-		udelay(100);
-		outb(0x0, base+0x30);
-		outb(0x0, base+0x20);
-		outb(0x0, base+0x40);
-		outb(0x0, base+0x50);
-		outb(0xe0, base+0x70);
-		outb(0x2, base+0x160);   
-		for (j = 0; j < 10; j++) {
-			int status;
-			mdelay(100);
-			status = inb(base+0x70);
-			if (!(status & BUSY_STAT) && (status & DRQ_STAT))
-				break;
-		}
-		break;
-	case ide_cdrom:
-		// todo
-		break;
-	case ide_floppy:
-		// todo
-		break;
-	}
-}
-
-#ifdef CONFIG_PMAC_PBOOK
-static void __pmac
-idepmac_wake_device(ide_drive_t *drive, int used_dma)
-{
-	/* We force the IDE subdriver to check for a media change
-	 * This must be done first or we may lost the condition
-	 *
-	 * Problem: This can schedule. I moved the block device
-	 * wakeup almost late by priority because of that.
-	 */
-	if (DRIVER(drive) && DRIVER(drive)->media_change)
-		DRIVER(drive)->media_change(drive);
-
-	/* We kick the VFS too (see fix in ide.c revalidate) */
-	check_disk_change(MKDEV(HWIF(drive)->major, (drive->select.b.unit) << PARTN_BITS));
-	
-#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
-	/* We re-enable DMA on the drive if it was active. */
-	/* This doesn't work with the CD-ROM in the media-bay, probably
-	 * because of a pending unit attention. The problem if that if I
-	 * clear the error, the filesystem dies.
-	 */
-	if (used_dma && !ide_spin_wait_hwgroup(drive)) {
-		/* Lock HW group */
-		HWGROUP(drive)->busy = 1;
-		pmac_ide_check_dma(drive);
-		HWGROUP(drive)->busy = 0;
-		if (!list_empty(&drive->queue.queue_head))
-			ide_do_request(HWGROUP(drive), 0);
-		spin_unlock_irq(&io_request_lock);
-	}
-#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
-}
-
-static void __pmac
-idepmac_sleep_interface(int i, unsigned base, int mediabay)
-{
-	struct device_node* np = pmac_ide[i].node;
-
-	/* We clear the timings */
-	pmac_ide[i].timings[0] = 0;
-	pmac_ide[i].timings[1] = 0;
-	
-	/* The media bay will handle itself just fine */
-	if (mediabay)
-		return;
-	
-	/* Disable the bus */
-	ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmac_ide[i].aapl_bus_id, 0);
-}
-
-static void __pmac
-idepmac_wake_interface(int i, unsigned long base, int mediabay)
-{
-	struct device_node* np = pmac_ide[i].node;
-
-	if (!mediabay) {
-		/* Revive IDE disk and controller */
-		ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmac_ide[i].aapl_bus_id, 1);
-		ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmac_ide[i].aapl_bus_id, 1);
-		mdelay(10);
-		ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmac_ide[i].aapl_bus_id, 0);
-	}
-}
-
-static void
-idepmac_sleep_drive(ide_drive_t *drive, int idx, unsigned long base)
-{
-	int unlock = 0;
-
-	/* Wait for HW group to complete operations */
-	if (ide_spin_wait_hwgroup(drive)) {
-		// What can we do here ? Wake drive we had already
-		// put to sleep and return an error ?
-	} else {
-		unlock = 1;
-		/* Lock HW group */
-		HWGROUP(drive)->busy = 1;
-		/* Stop the device */
-		idepmac_sleep_device(drive, idx, base);
-	}
-	if (unlock)
-		spin_unlock_irq(&io_request_lock);
-}
-
-static void
-idepmac_wake_drive(ide_drive_t *drive, unsigned long base)
-{
-	unsigned long flags;
-	int j;
-	
-	/* Reset timings */
-	pmac_ide_selectproc(drive);
-	mdelay(10);
-	
-	/* Wait up to 20 seconds for the drive to be ready */
-	for (j = 0; j < 200; j++) {
-		int status;
-		mdelay(100);
-		outb(drive->select.all, base + 0x60);
-		if (inb(base + 0x60) != drive->select.all)
-			continue;
-		status = inb(base + 0x70);
-		if (!(status & BUSY_STAT))
-			break;
-	}
-
-	/* We resume processing on the HW group */
-	spin_lock_irqsave(&io_request_lock, flags);
-	HWGROUP(drive)->busy = 0;
-	if (!list_empty(&drive->queue.queue_head))
-		ide_do_request(HWGROUP(drive), 0);
-	spin_unlock_irqrestore(&io_request_lock, flags);			
-}
-
-/* Note: We support only master drives for now. This will have to be
- * improved if we want to handle sleep on the iMacDV where the CD-ROM
- * is a slave.
- * 
- * Well, actually, that sorta works on the iBook2 when the CD-ROM is
- * a slave, though it will fail to spin_wait_hwgroup for the slave
- * device as it is marked busy by the master sleep code. Well, it's
- * probably not worth fixing now as we don't have sleep code for
- * ATAPI devices anyway. Future kernels will hopefully deal with
- * IDE PM in a more generic way.
- */
-static int __pmac
-idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when)
-{
-	int i, ret;
-	unsigned long base;
-	int big_delay;
- 
-	switch (when) {
-	case PBOOK_SLEEP_REQUEST:
-		break;
-	case PBOOK_SLEEP_REJECT:
-		break;
-	case PBOOK_SLEEP_NOW:
-		for (i = 0; i < pmac_ide_count; ++i) {
-			ide_hwif_t *hwif;
-			int dn;
-
-			if ((base = pmac_ide[i].regbase) == 0)
-				continue;
-
-			hwif = &ide_hwifs[i];
-			for (dn=0; dn<MAX_DRIVES; dn++) {
-				if (!hwif->drives[dn].present)
-					continue;
-				idepmac_sleep_drive(&hwif->drives[dn], i, base);
-			}
-			/* Disable irq during sleep */
-			disable_irq(pmac_ide[i].irq);
-			
-			/* Check if this is a media bay with an IDE device or not
-			 * a media bay.
-			 */
-			ret = check_media_bay_by_base(base, MB_CD);
-			if ((ret == 0) || (ret == -ENODEV))
-				idepmac_sleep_interface(i, base, (ret == 0));
-		}
-		break;
-	case PBOOK_WAKE:
-		big_delay = 0;
-		for (i = 0; i < pmac_ide_count; ++i) {
-
-			if ((base = pmac_ide[i].regbase) == 0)
-				continue;
-				
-			/* Make sure we have sane timings */		
-			sanitize_timings(i);
-
-			/* Check if this is a media bay with an IDE device or not
-			 * a media bay
-			 */
-			ret = check_media_bay_by_base(base, MB_CD);
-			if ((ret == 0) || (ret == -ENODEV)) {
-				idepmac_wake_interface(i, base, (ret == 0));				
-				big_delay = 1;
-			}
-
-		}
-		/* Let hardware get up to speed */
-		if (big_delay)
-			mdelay(IDE_WAKEUP_DELAY_MS);
-	
-		for (i = 0; i < pmac_ide_count; ++i) {
-			ide_hwif_t *hwif;
-			int used_dma, dn;
-			int irq_on = 0;
-			
-			if ((base = pmac_ide[i].regbase) == 0)
-				continue;
-				
-			hwif = &ide_hwifs[i];
-			for (dn=0; dn<MAX_DRIVES; dn++) {
-				ide_drive_t *drive = &hwif->drives[dn];
-				if (!drive->present)
-					continue;
-				/* We don't have re-configured DMA yet */
-				used_dma = drive->using_dma;
-				drive->using_dma = 0;
-				idepmac_wake_drive(drive, base);
-				if (!irq_on) {
-					enable_irq(pmac_ide[i].irq);
-					irq_on = 1;
-				}
-				idepmac_wake_device(drive, used_dma);
-			}
-			if (!irq_on)
-				enable_irq(pmac_ide[i].irq);
-		}
-		break;
-	}
-	return PBOOK_SLEEP_OK;
-}
-#endif /* CONFIG_PMAC_PBOOK */
-
-static int __pmac
-pmac_ide_notify_reboot(struct notifier_block *this, unsigned long code, void *x)
-{
-	int i, gotone;
-	unsigned long base;
-
-	if (code != SYS_HALT && code != SYS_POWER_OFF)
-		return 0;
-
-	gotone = 0;
-	for (i = 0; i < pmac_ide_count; ++i) {
-		ide_hwif_t *hwif;
-		ide_drive_t *drive;
-		int unlock = 0;
-		int dn;
-
-		if ((base = pmac_ide[i].regbase) == 0)
-				continue;	
-
-		hwif = &ide_hwifs[i];
-		for (dn=0; dn<MAX_DRIVES; dn++) {
-			drive = &hwif->drives[dn];
-			if (drive->present) {
-				gotone = 1;
-				/* Wait for HW group to complete operations */
-				if (ide_spin_wait_hwgroup(drive)) {
-					// What can we do here ? Wake drive we had already
-					// put to sleep and return an error ?
-				} else {
-					unlock = 1;
-					/* Lock HW group */
-					HWGROUP(drive)->busy = 1;
-
-					/* Stop the device */
-					idepmac_sleep_device(drive, i, base);
-				}
-			}
-			if (unlock)
-				spin_unlock_irq(&io_request_lock);
-		}
-	}
-	if (gotone)
-		mdelay(1000);
-		
-	return NOTIFY_DONE;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-pnp.c linux-2.4.21-pre6/drivers/ide/ide-pnp.c
--- linux-2.4.20/drivers/ide/ide-pnp.c	2001-05-01 23:06:23.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/ide-pnp.c	2003-03-26 23:49:53.000000000 +0000
@@ -21,12 +21,6 @@
 
 #include <linux/isapnp.h>
 
-#ifndef PREPARE_FUNC
-#define PREPARE_FUNC(dev)  (dev->prepare)
-#define ACTIVATE_FUNC(dev)  (dev->activate)
-#define DEACTIVATE_FUNC(dev)  (dev->deactivate)
-#endif
-
 #define DEV_IO(dev, index) (dev->resource[index].start)
 #define DEV_IRQ(dev, index) (dev->irq_resource[index].start)
 
@@ -54,6 +48,7 @@
 };
 
 /* Generic initialisation function for ISA PnP IDE interface */
+
 static int __init pnpide_generic_init(struct pci_dev *dev, int enable)
 {
 	hw_regs_t hw;
@@ -66,13 +61,16 @@
 		return 1;
 
 	ide_setup_ports(&hw, (ide_ioreg_t) DEV_IO(dev, 0),
-			generic_ide_offsets, (ide_ioreg_t) DEV_IO(dev, 1),
-			0, NULL, DEV_IRQ(dev, 0));
+			generic_ide_offsets,
+			(ide_ioreg_t) DEV_IO(dev, 1),
+			0, NULL,
+//			generic_pnp_ide_iops,
+			DEV_IRQ(dev, 0));
 
 	index = ide_register_hw(&hw, NULL);
 
 	if (index != -1) {
-	    	printk("ide%d: %s IDE interface\n", index, DEV_NAME(dev));
+	    	printk(KERN_INFO "ide%d: %s IDE interface\n", index, DEV_NAME(dev));
 		return 0;
 	}
 
@@ -88,7 +86,6 @@
 	{	0 }
 };
 
-#ifdef MODULE
 #define NR_PNP_DEVICES 8
 struct pnp_dev_inst {
 	struct pci_dev *dev;
@@ -96,11 +93,11 @@
 };
 static struct pnp_dev_inst devices[NR_PNP_DEVICES];
 static int pnp_ide_dev_idx = 0;
-#endif
 
 /*
  * Probe for ISA PnP IDE interfaces.
  */
+
 void __init pnpide_init(int enable)
 {
 	struct pci_dev *dev = NULL;
@@ -109,19 +106,18 @@
 	if (!isapnp_present())
 		return;
 
-#ifdef MODULE
 	/* Module unload, deactivate all registered devices. */
 	if (!enable) {
 		int i;
 		for (i = 0; i < pnp_ide_dev_idx; i++) {
+			dev = devices[i].dev;
 			devices[i].dev_type->init_fn(dev, 0);
-
-			if (DEACTIVATE_FUNC(devices[i].dev))
-				DEACTIVATE_FUNC(devices[i].dev)(devices[i].dev);
+			if (dev->deactivate)
+				dev->deactivate(dev);
 		}
 		return;
 	}
-#endif
+
 	for (dev_type = idepnp_devices; dev_type->vendor; dev_type++) {
 		while ((dev = isapnp_find_dev(NULL, dev_type->vendor,
 			dev_type->device, dev))) {
@@ -129,20 +125,20 @@
 			if (dev->active)
 				continue;
 
-       			if (PREPARE_FUNC(dev) && (PREPARE_FUNC(dev))(dev) < 0) {
-				printk("ide: %s prepare failed\n", DEV_NAME(dev));
+       			if (dev->prepare && dev->prepare(dev) < 0) {
+				printk(KERN_ERR"ide-pnp: %s prepare failed\n", DEV_NAME(dev));
 				continue;
 			}
 
-			if (ACTIVATE_FUNC(dev) && (ACTIVATE_FUNC(dev))(dev) < 0) {
-				printk("ide: %s activate failed\n", DEV_NAME(dev));
+			if (dev->activate && dev->activate(dev) < 0) {
+				printk(KERN_ERR"ide: %s activate failed\n", DEV_NAME(dev));
 				continue;
 			}
 
 			/* Call device initialization function */
 			if (dev_type->init_fn(dev, 1)) {
-				if (DEACTIVATE_FUNC(dev))
-					DEACTIVATE_FUNC(dev)(dev);
+				if (dev->deactivate(dev))
+					dev->deactivate(dev);
 			} else {
 #ifdef MODULE
 				/*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-probe.c linux-2.4.21-pre6/drivers/ide/ide-probe.c
--- linux-2.4.20/drivers/ide/ide-probe.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/ide-probe.c	2003-03-26 23:48:57.000000000 +0000
@@ -46,40 +46,77 @@
 #include <linux/delay.h>
 #include <linux/ide.h>
 #include <linux/spinlock.h>
+#include <linux/pci.h>
+#include <linux/kmod.h>
 
 #include <asm/byteorder.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
-static inline void do_identify (ide_drive_t *drive, byte cmd)
+/*
+ * CompactFlash cards and their brethern pretend to be removable
+ * hard disks, except:
+ *	(1) they never have a slave unit, and
+ *	(2) they don't have doorlock mechanisms.
+ * This test catches them, and is invoked elsewhere when setting
+ * appropriate config bits.
+ *
+ * FIXME: This treatment is probably applicable for *all* PCMCIA (PC CARD)
+ * devices, so in linux 2.3.x we should change this to just treat all PCMCIA
+ * drives this way, and get rid of the model-name tests below
+ * (too big of an interface change for 2.2.x).
+ * At that time, we might also consider parameterizing the timeouts and retries,
+ * since these are MUCH faster than mechanical drives.	-M.Lord
+ */
+inline int drive_is_flashcard (ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
+
+	if (drive->removable && id != NULL) {
+		if (id->config == 0x848a) return 1;	/* CompactFlash */
+		if (!strncmp(id->model, "KODAK ATA_FLASH", 15)	/* Kodak */
+		 || !strncmp(id->model, "Hitachi CV", 10)	/* Hitachi */
+		 || !strncmp(id->model, "SunDisk SDCFB", 13)	/* SunDisk */
+		 || !strncmp(id->model, "HAGIWARA HPC", 12)	/* Hagiwara */
+		 || !strncmp(id->model, "LEXAR ATA_FLASH", 15)	/* Lexar */
+		 || !strncmp(id->model, "ATA_FLASH", 9))	/* Simple Tech */
+		{
+			return 1;	/* yes, it is a flash memory card */
+		}
+	}
+	return 0;	/* no, it is not a flash memory card */
+}
+
+static inline void do_identify (ide_drive_t *drive, u8 cmd)
 {
+	ide_hwif_t *hwif = HWIF(drive);
 	int bswap = 1;
 	struct hd_driveid *id;
 
-	id = drive->id = kmalloc (SECTOR_WORDS*4, GFP_ATOMIC);	/* called with interrupts disabled! */
+	/* called with interrupts disabled! */
+	id = drive->id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC);
 	if (!id) {
-		printk(KERN_WARNING "(ide-probe::do_identify) Out of memory.\n");
+		printk(KERN_WARNING "(ide-probe::do_identify) "
+			"Out of memory.\n");
 		goto err_kmalloc;
 	}
+	/* read 512 bytes of id info */
+	hwif->ata_input_data(drive, id, SECTOR_WORDS);
 
-	ide_input_data(drive, id, SECTOR_WORDS);		/* read 512 bytes of id info */
-	ide__sti();	/* local CPU only */
+	local_irq_enable();
 	ide_fix_driveid(id);
 
-	if (id->word156 == 0x4d42) {
-		printk("%s: drive->id->word156 == 0x%04x \n", drive->name, drive->id->word156);
-	}
-
 	if (!drive->forced_lun)
 		drive->last_lun = id->last_lun & 0x7;
+
 #if defined (CONFIG_SCSI_EATA_DMA) || defined (CONFIG_SCSI_EATA_PIO) || defined (CONFIG_SCSI_EATA)
 	/*
 	 * EATA SCSI controllers do a hardware ATA emulation:
 	 * Ignore them if there is a driver for them available.
 	 */
-	if ((id->model[0] == 'P' && id->model[1] == 'M')
-	 || (id->model[0] == 'S' && id->model[1] == 'K')) {
+	if ((id->model[0] == 'P' && id->model[1] == 'M') ||
+	    (id->model[0] == 'S' && id->model[1] == 'K')) {
 		printk("%s: EATA SCSI HBA %.10s\n", drive->name, id->model);
 		goto err_misc;
 	}
@@ -93,27 +130,30 @@
 		if ((id->model[0] == 'N' && id->model[1] == 'E') /* NEC */
 		 || (id->model[0] == 'F' && id->model[1] == 'X') /* Mitsumi */
 		 || (id->model[0] == 'P' && id->model[1] == 'i'))/* Pioneer */
-			bswap ^= 1;	/* Vertos drives may still be weird */
+			/* Vertos drives may still be weird */
+			bswap ^= 1;	
 	}
-	ide_fixstring (id->model,     sizeof(id->model),     bswap);
-	ide_fixstring (id->fw_rev,    sizeof(id->fw_rev),    bswap);
-	ide_fixstring (id->serial_no, sizeof(id->serial_no), bswap);
+	ide_fixstring(id->model,     sizeof(id->model),     bswap);
+	ide_fixstring(id->fw_rev,    sizeof(id->fw_rev),    bswap);
+	ide_fixstring(id->serial_no, sizeof(id->serial_no), bswap);
 
 	if (strstr(id->model, "E X A B Y T E N E S T"))
 		goto err_misc;
 
-	id->model[sizeof(id->model)-1] = '\0';	/* we depend on this a lot! */
+	/* we depend on this a lot! */
+	id->model[sizeof(id->model)-1] = '\0';
 	printk("%s: %s, ", drive->name, id->model);
 	drive->present = 1;
+	drive->dead = 0;
 
 	/*
 	 * Check for an ATAPI device
 	 */
 	if (cmd == WIN_PIDENTIFY) {
-		byte type = (id->config >> 8) & 0x1f;
+		u8 type = (id->config >> 8) & 0x1f;
 		printk("ATAPI ");
 #ifdef CONFIG_BLK_DEV_PDC4030
-		if (HWIF(drive)->channel == 1 && HWIF(drive)->chipset == ide_pdc4030) {
+		if (hwif->channel == 1 && hwif->chipset == ide_pdc4030) {
 			printk(" -- not supported on 2nd Promise port\n");
 			goto err_misc;
 		}
@@ -121,19 +161,24 @@
 		switch (type) {
 			case ide_floppy:
 				if (!strstr(id->model, "CD-ROM")) {
-					if (!strstr(id->model, "oppy") && !strstr(id->model, "poyp") && !strstr(id->model, "ZIP"))
+					if (!strstr(id->model, "oppy") &&
+					    !strstr(id->model, "poyp") &&
+					    !strstr(id->model, "ZIP"))
 						printk("cdrom or floppy?, assuming ");
 					if (drive->media != ide_cdrom) {
 						printk ("FLOPPY");
+						drive->removable = 1;
 						break;
 					}
 				}
-				type = ide_cdrom;	/* Early cdrom models used zero */
+				/* Early cdrom models used zero */
+				type = ide_cdrom;
 			case ide_cdrom:
 				drive->removable = 1;
 #ifdef CONFIG_PPC
 				/* kludge for Apple PowerBook internal zip */
-				if (!strstr(id->model, "CD-ROM") && strstr(id->model, "ZIP")) {
+				if (!strstr(id->model, "CD-ROM") &&
+				    strstr(id->model, "ZIP")) {
 					printk ("FLOPPY");
 					type = ide_floppy;
 					break;
@@ -164,18 +209,21 @@
 		drive->removable = 1;
 	/*
 	 * Prevent long system lockup probing later for non-existant
-	 * slave drive if the hwif is actually a flash memory card of some variety:
+	 * slave drive if the hwif is actually a flash memory card of
+	 * some variety:
 	 */
+	drive->is_flash = 0;
 	if (drive_is_flashcard(drive)) {
-		ide_drive_t *mate = &HWIF(drive)->drives[1^drive->select.b.unit];
+		ide_drive_t *mate = &hwif->drives[1^drive->select.b.unit];
 		if (!mate->ata_flash) {
 			mate->present = 0;
 			mate->noprobe = 1;
 		}
+		drive->is_flash = 1;
 	}
 	drive->media = ide_disk;
-	printk("ATA DISK drive\n");
-	QUIRK_LIST(HWIF(drive),drive);
+	printk("%s DISK drive\n", (drive->is_flash) ? "CFA" : "ATA" );
+	QUIRK_LIST(drive);
 	return;
 
 err_misc:
@@ -195,95 +243,117 @@
  *		1  device timed-out (no response to identify request)
  *		2  device aborted the command (refused to identify itself)
  */
-static int actual_try_to_identify (ide_drive_t *drive, byte cmd)
+static int actual_try_to_identify (ide_drive_t *drive, u8 cmd)
 {
+	ide_hwif_t *hwif = HWIF(drive);
 	int rc;
 	ide_ioreg_t hd_status;
 	unsigned long timeout;
-	byte s, a;
+	u8 s = 0, a = 0;
 
 	if (IDE_CONTROL_REG) {
 		/* take a deep breath */
 		ide_delay_50ms();
-		a = IN_BYTE(IDE_ALTSTATUS_REG);
-		s = IN_BYTE(IDE_STATUS_REG);
+		a = hwif->INB(IDE_ALTSTATUS_REG);
+		s = hwif->INB(IDE_STATUS_REG);
 		if ((a ^ s) & ~INDEX_STAT) {
-			printk("%s: probing with STATUS(0x%02x) instead of ALTSTATUS(0x%02x)\n", drive->name, s, a);
-			hd_status = IDE_STATUS_REG;	/* ancient Seagate drives, broken interfaces */
+			printk("%s: probing with STATUS(0x%02x) instead of "
+				"ALTSTATUS(0x%02x)\n", drive->name, s, a);
+			/* ancient Seagate drives, broken interfaces */
+			hd_status = IDE_STATUS_REG;
 		} else {
-			hd_status = IDE_ALTSTATUS_REG;	/* use non-intrusive polling */
+			/* use non-intrusive polling */
+			hd_status = IDE_ALTSTATUS_REG;
 		}
 	} else {
 		ide_delay_50ms();
 		hd_status = IDE_STATUS_REG;
 	}
 
-	/* set features register for atapi identify command to be sure of reply */
+	/* set features register for atapi
+	 * identify command to be sure of reply
+	 */
 	if ((cmd == WIN_PIDENTIFY))
-		OUT_BYTE(0,IDE_FEATURE_REG);	/* disable dma & overlap */
+		/* disable dma & overlap */
+		hwif->OUTB(0, IDE_FEATURE_REG);
 
-#if CONFIG_BLK_DEV_PDC4030
-	if (HWIF(drive)->chipset == ide_pdc4030) {
-		/* DC4030 hosted drives need their own identify... */
-		extern int pdc4030_identify(ide_drive_t *);
-		if (pdc4030_identify(drive)) {
+	if (hwif->identify != NULL) {
+		if (hwif->identify(drive))
 			return 1;
-		}
-	} else
-#endif /* CONFIG_BLK_DEV_PDC4030 */
-		OUT_BYTE(cmd,IDE_COMMAND_REG);		/* ask drive for ID */
+	} else {
+		/* ask drive for ID */
+		hwif->OUTB(cmd, IDE_COMMAND_REG);
+	}
 	timeout = ((cmd == WIN_IDENTIFY) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2;
 	timeout += jiffies;
 	do {
-		if (0 < (signed long)(jiffies - timeout)) {
-			return 1;	/* drive timed-out */
+		if (time_after(jiffies, timeout)) {
+			/* drive timed-out */
+			return 1;
 		}
-		ide_delay_50ms();		/* give drive a breather */
-	} while (IN_BYTE(hd_status) & BUSY_STAT);
+		/* give drive a breather */
+		ide_delay_50ms();
+	} while ((hwif->INB(hd_status)) & BUSY_STAT);
 
-	ide_delay_50ms();		/* wait for IRQ and DRQ_STAT */
-	if (OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT)) {
+	/* wait for IRQ and DRQ_STAT */
+	ide_delay_50ms();
+	if (OK_STAT((hwif->INB(IDE_STATUS_REG)), DRQ_STAT, BAD_R_STAT)) {
 		unsigned long flags;
-		__save_flags(flags);	/* local CPU only */
-		__cli();		/* local CPU only; some systems need this */
-		do_identify(drive, cmd); /* drive returned ID */
-		rc = 0;			/* drive responded with ID */
-		(void) GET_STAT();	/* clear drive IRQ */
-		__restore_flags(flags);	/* local CPU only */
-	} else
-		rc = 2;			/* drive refused ID */
+
+		/* local CPU only; some systems need this */
+		local_irq_save(flags);
+		/* drive returned ID */
+		do_identify(drive, cmd);
+		/* drive responded with ID */
+		rc = 0;
+		/* clear drive IRQ */
+		(void) hwif->INB(IDE_STATUS_REG);
+		local_irq_restore(flags);
+	} else {
+		/* drive refused ID */
+		rc = 2;
+	}
 	return rc;
 }
 
-static int try_to_identify (ide_drive_t *drive, byte cmd)
+static int try_to_identify (ide_drive_t *drive, u8 cmd)
 {
+	ide_hwif_t *hwif = HWIF(drive);
 	int retval;
 	int autoprobe = 0;
 	unsigned long cookie = 0;
 
-	if (IDE_CONTROL_REG && !HWIF(drive)->irq) {
+	if (IDE_CONTROL_REG && !hwif->irq) {
 		autoprobe = 1;
 		cookie = probe_irq_on();
-		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);	/* enable device irq */
+		/* enable device irq */
+		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
 	}
 
 	retval = actual_try_to_identify(drive, cmd);
 
 	if (autoprobe) {
 		int irq;
-		OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG);	/* mask device irq */
-		(void) GET_STAT();			/* clear drive IRQ */
+		/* mask device irq */
+		hwif->OUTB(drive->ctl|2, IDE_CONTROL_REG);
+		/* clear drive IRQ */
+		(void) hwif->INB(IDE_STATUS_REG);
 		udelay(5);
 		irq = probe_irq_off(cookie);
-		if (!HWIF(drive)->irq) {
+		if (!hwif->irq) {
 			if (irq > 0) {
-				HWIF(drive)->irq = irq;
-			} else {	/* Mmmm.. multiple IRQs.. don't know which was ours */
-				printk("%s: IRQ probe failed (0x%lx)\n", drive->name, cookie);
+				hwif->irq = irq;
+			} else {
+				/* Mmmm.. multiple IRQs..
+				 * don't know which was ours
+				 */
+				printk("%s: IRQ probe failed (0x%lx)\n",
+					drive->name, cookie);
 #ifdef CONFIG_BLK_DEV_CMD640
 #ifdef CMD640_DUMP_REGS
-				if (HWIF(drive)->chipset == ide_cmd640) {
-					printk("%s: Hmmm.. probably a driver problem.\n", drive->name);
+				if (hwif->chipset == ide_cmd640) {
+					printk("%s: Hmmm.. probably a driver "
+						"problem.\n", drive->name);
 					CMD640_DUMP_REGS;
 				}
 #endif /* CMD640_DUMP_REGS */
@@ -311,11 +381,13 @@
  *		3  bad status from device (possible for ATAPI drives)
  *		4  probe was not attempted because failure was obvious
  */
-static int do_probe (ide_drive_t *drive, byte cmd)
+static int do_probe (ide_drive_t *drive, u8 cmd)
 {
 	int rc;
 	ide_hwif_t *hwif = HWIF(drive);
-	if (drive->present) {	/* avoid waiting for inappropriate probes */
+
+	if (drive->present) {
+		/* avoid waiting for inappropriate probes */
 		if ((drive->media != ide_disk) && (cmd == WIN_IDENTIFY))
 			return 4;
 	}
@@ -324,44 +396,66 @@
 		drive->name, drive->present, drive->media,
 		(cmd == WIN_IDENTIFY) ? "ATA" : "ATAPI");
 #endif
-	ide_delay_50ms();	/* needed for some systems (e.g. crw9624 as drive0 with disk as slave) */
-	SELECT_DRIVE(hwif,drive);
+
+	/* needed for some systems
+	 * (e.g. crw9624 as drive0 with disk as slave)
+	 */
+	ide_delay_50ms();
+	SELECT_DRIVE(drive);
 	ide_delay_50ms();
-	if (IN_BYTE(IDE_SELECT_REG) != drive->select.all && !drive->present) {
+	if (hwif->INB(IDE_SELECT_REG) != drive->select.all && !drive->present) {
 		if (drive->select.b.unit != 0) {
-			SELECT_DRIVE(hwif,&hwif->drives[0]);	/* exit with drive0 selected */
-			ide_delay_50ms();		/* allow BUSY_STAT to assert & clear */
+			/* exit with drive0 selected */
+			SELECT_DRIVE(&hwif->drives[0]);
+			/* allow BUSY_STAT to assert & clear */
+			ide_delay_50ms();
 		}
-		return 3;    /* no i/f present: mmm.. this should be a 4 -ml */
+		/* no i/f present: mmm.. this should be a 4 -ml */
+		return 3;
 	}
 
-	if (OK_STAT(GET_STAT(),READY_STAT,BUSY_STAT)
-	 || drive->present || cmd == WIN_PIDENTIFY)
-	{
-		if ((rc = try_to_identify(drive,cmd)))   /* send cmd and wait */
-			rc = try_to_identify(drive,cmd); /* failed: try again */
-		if (rc == 1 && cmd == WIN_PIDENTIFY && drive->autotune != 2) {
+	if (OK_STAT((hwif->INB(IDE_STATUS_REG)), READY_STAT, BUSY_STAT) ||
+	    drive->present || cmd == WIN_PIDENTIFY) {
+		/* send cmd and wait */
+		if ((rc = try_to_identify(drive, cmd))) {
+			/* failed: try again */
+			rc = try_to_identify(drive,cmd);
+		}
+		if (hwif->INB(IDE_STATUS_REG) == (BUSY_STAT|READY_STAT))
+			return 4;
+
+		if ((rc == 1 && cmd == WIN_PIDENTIFY) &&
+			((drive->autotune == IDE_TUNE_DEFAULT) ||
+			(drive->autotune == IDE_TUNE_AUTO))) {
 			unsigned long timeout;
-			printk("%s: no response (status = 0x%02x), resetting drive\n", drive->name, GET_STAT());
+			printk("%s: no response (status = 0x%02x), "
+				"resetting drive\n", drive->name,
+				hwif->INB(IDE_STATUS_REG));
 			ide_delay_50ms();
-			OUT_BYTE (drive->select.all, IDE_SELECT_REG);
+			hwif->OUTB(drive->select.all, IDE_SELECT_REG);
 			ide_delay_50ms();
-			OUT_BYTE(WIN_SRST, IDE_COMMAND_REG);
+			hwif->OUTB(WIN_SRST, IDE_COMMAND_REG);
 			timeout = jiffies;
-			while ((GET_STAT() & BUSY_STAT) && time_before(jiffies, timeout + WAIT_WORSTCASE))
+			while (((hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) &&
+			       time_before(jiffies, timeout + WAIT_WORSTCASE))
 				ide_delay_50ms();
 			rc = try_to_identify(drive, cmd);
 		}
 		if (rc == 1)
-			printk("%s: no response (status = 0x%02x)\n", drive->name, GET_STAT());
-		(void) GET_STAT();		/* ensure drive irq is clear */
+			printk("%s: no response (status = 0x%02x)\n",
+				drive->name, hwif->INB(IDE_STATUS_REG));
+		/* ensure drive irq is clear */
+		(void) hwif->INB(IDE_STATUS_REG);
 	} else {
-		rc = 3;				/* not present or maybe ATAPI */
+		/* not present or maybe ATAPI */
+		rc = 3;
 	}
 	if (drive->select.b.unit != 0) {
-		SELECT_DRIVE(hwif,&hwif->drives[0]);	/* exit with drive0 selected */
+		/* exit with drive0 selected */
+		SELECT_DRIVE(&hwif->drives[0]);
 		ide_delay_50ms();
-		(void) GET_STAT();		/* ensure drive irq is clear */
+		/* ensure drive irq is clear */
+		(void) hwif->INB(IDE_STATUS_REG);
 	}
 	return rc;
 }
@@ -371,12 +465,13 @@
  */
 static void enable_nest (ide_drive_t *drive)
 {
+	ide_hwif_t *hwif = HWIF(drive);
 	unsigned long timeout;
 
-	printk("%s: enabling %s -- ", HWIF(drive)->name, drive->id->model);
-	SELECT_DRIVE(HWIF(drive), drive);
+	printk("%s: enabling %s -- ", hwif->name, drive->id->model);
+	SELECT_DRIVE(drive);
 	ide_delay_50ms();
-	OUT_BYTE(EXABYTE_ENABLE_NEST, IDE_COMMAND_REG);
+	hwif->OUTB(EXABYTE_ENABLE_NEST, IDE_COMMAND_REG);
 	timeout = jiffies + WAIT_WORSTCASE;
 	do {
 		if (time_after(jiffies, timeout)) {
@@ -384,14 +479,20 @@
 			return;
 		}
 		ide_delay_50ms();
-	} while (GET_STAT() & BUSY_STAT);
+	} while ((hwif->INB(IDE_STATUS_REG)) & BUSY_STAT);
+
 	ide_delay_50ms();
-	if (!OK_STAT(GET_STAT(), 0, BAD_STAT))
-		printk("failed (status = 0x%02x)\n", GET_STAT());
-	else
+
+	if (!OK_STAT((hwif->INB(IDE_STATUS_REG)), 0, BAD_STAT)) {
+		printk("failed (status = 0x%02x)\n", hwif->INB(IDE_STATUS_REG));
+	} else {
 		printk("success\n");
-	if (do_probe(drive, WIN_IDENTIFY) >= 2) {	/* if !(success||timed-out) */
-		(void) do_probe(drive, WIN_PIDENTIFY);	/* look for ATAPI device */
+	}
+
+	/* if !(success||timed-out) */
+	if (do_probe(drive, WIN_IDENTIFY) >= 2) {
+		/* look for ATAPI device */
+		(void) do_probe(drive, WIN_PIDENTIFY);
 	}
 }
 
@@ -401,176 +502,250 @@
  * Returns:	0  no device was found
  *		1  device was found (note: drive->present might still be 0)
  */
-static inline byte probe_for_drive (ide_drive_t *drive)
+static inline u8 probe_for_drive (ide_drive_t *drive)
 {
-	if (drive->noprobe)			/* skip probing? */
+	/* skip probing? */
+	if (drive->noprobe)
 		return drive->present;
-	if (do_probe(drive, WIN_IDENTIFY) >= 2) { /* if !(success||timed-out) */
-		(void) do_probe(drive, WIN_PIDENTIFY); /* look for ATAPI device */
+
+	/* if !(success||timed-out) */
+	if (do_probe(drive, WIN_IDENTIFY) >= 2) {
+		/* look for ATAPI device */
+		(void) do_probe(drive, WIN_PIDENTIFY);
 	}
 	if (drive->id && strstr(drive->id->model, "E X A B Y T E N E S T"))
 		enable_nest(drive);
 	if (!drive->present)
-		return 0;			/* drive not found */
-	if (drive->id == NULL) {		/* identification failed? */
+		/* drive not found */
+		return 0;
+
+	/* identification failed? */
+	if (drive->id == NULL) {
 		if (drive->media == ide_disk) {
-			printk ("%s: non-IDE drive, CHS=%d/%d/%d\n",
-			 drive->name, drive->cyl, drive->head, drive->sect);
+			printk("%s: non-IDE drive, CHS=%d/%d/%d\n",
+				drive->name, drive->cyl,
+				drive->head, drive->sect);
 		} else if (drive->media == ide_cdrom) {
 			printk("%s: ATAPI cdrom (?)\n", drive->name);
 		} else {
-			drive->present = 0;	/* nuke it */
+			/* nuke it */
+			drive->present = 0;
 		}
 	}
-	return 1;	/* drive was found */
+	/* drive was found */
+	return 1;
 }
 
-/*
- * Calculate the region that this interface occupies,
- * handling interfaces where the registers may not be
- * ordered sanely.  We deal with the CONTROL register
- * separately.
- */
+#define hwif_check_region(addr, num) \
+	((hwif->mmio) ? check_mem_region((addr),(num)) : check_region((addr),(num)))
+
 static int hwif_check_regions (ide_hwif_t *hwif)
 {
-	int region_errors = 0;
-
-	hwif->straight8 = 0;
-	region_errors  = ide_check_region(hwif->io_ports[IDE_DATA_OFFSET], 1);
-	region_errors += ide_check_region(hwif->io_ports[IDE_ERROR_OFFSET], 1);
-	region_errors += ide_check_region(hwif->io_ports[IDE_NSECTOR_OFFSET], 1);
-	region_errors += ide_check_region(hwif->io_ports[IDE_SECTOR_OFFSET], 1);
-	region_errors += ide_check_region(hwif->io_ports[IDE_LCYL_OFFSET], 1);
-	region_errors += ide_check_region(hwif->io_ports[IDE_HCYL_OFFSET], 1);
-	region_errors += ide_check_region(hwif->io_ports[IDE_SELECT_OFFSET], 1);
-	region_errors += ide_check_region(hwif->io_ports[IDE_STATUS_OFFSET], 1);
+	u32 i		= 0;
+	int addr_errs	= 0;
 
+	if (hwif->mmio == 2)
+		return 0;
+	addr_errs  = hwif_check_region(hwif->io_ports[IDE_DATA_OFFSET], 1);
+	for (i = IDE_ERROR_OFFSET; i <= IDE_STATUS_OFFSET; i++)
+		addr_errs += hwif_check_region(hwif->io_ports[i], 1);
 	if (hwif->io_ports[IDE_CONTROL_OFFSET])
-		region_errors += ide_check_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1);
+		addr_errs += hwif_check_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1);
 #if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
 	if (hwif->io_ports[IDE_IRQ_OFFSET])
-		region_errors += ide_check_region(hwif->io_ports[IDE_IRQ_OFFSET], 1);
+		addr_errs += hwif_check_region(hwif->io_ports[IDE_IRQ_OFFSET], 1);
 #endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */
-	/*
-	 * If any errors are return, we drop the hwif interface.
-	 */
-	return(region_errors);
+	/* If any errors are return, we drop the hwif interface. */
+	hwif->straight8 = 0;
+	return(addr_errs);
 }
 
+//EXPORT_SYMBOL(hwif_check_regions);
+
+#define hwif_request_region(addr, num, name)	\
+	((hwif->mmio) ? request_mem_region((addr),(num),(name)) : request_region((addr),(num),(name)))
+
 static void hwif_register (ide_hwif_t *hwif)
 {
-	if (((unsigned long)hwif->io_ports[IDE_DATA_OFFSET] | 7) ==
-	    ((unsigned long)hwif->io_ports[IDE_STATUS_OFFSET])) {
-		ide_request_region(hwif->io_ports[IDE_DATA_OFFSET], 8, hwif->name);
-		hwif->straight8 = 1;
-		goto jump_straight8;
-	}
+	u32 i = 0;
 
-	if (hwif->io_ports[IDE_DATA_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_DATA_OFFSET], 1, hwif->name);
-	if (hwif->io_ports[IDE_ERROR_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_ERROR_OFFSET], 1, hwif->name);
-	if (hwif->io_ports[IDE_NSECTOR_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_NSECTOR_OFFSET], 1, hwif->name);
-	if (hwif->io_ports[IDE_SECTOR_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_SECTOR_OFFSET], 1, hwif->name);
-	if (hwif->io_ports[IDE_LCYL_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_LCYL_OFFSET], 1, hwif->name);
-	if (hwif->io_ports[IDE_HCYL_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_HCYL_OFFSET], 1, hwif->name);
-	if (hwif->io_ports[IDE_SELECT_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_SELECT_OFFSET], 1, hwif->name);
-	if (hwif->io_ports[IDE_STATUS_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_STATUS_OFFSET], 1, hwif->name);
-
-jump_straight8:
+	if (hwif->mmio == 2)
+		return;
 	if (hwif->io_ports[IDE_CONTROL_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1, hwif->name);
+		hwif_request_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1, hwif->name);
 #if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
 	if (hwif->io_ports[IDE_IRQ_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_IRQ_OFFSET], 1, hwif->name);
+		hwif_request_region(hwif->io_ports[IDE_IRQ_OFFSET], 1, hwif->name);
 #endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */
+	if (((unsigned long)hwif->io_ports[IDE_DATA_OFFSET] | 7) ==
+	    ((unsigned long)hwif->io_ports[IDE_STATUS_OFFSET])) {
+		hwif_request_region(hwif->io_ports[IDE_DATA_OFFSET], 8, hwif->name);
+		hwif->straight8 = 1;
+		return;
+	}
+
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
+		hwif_request_region(hwif->io_ports[i], 1, hwif->name);
 }
 
+//EXPORT_SYMBOL(hwif_register);
+
 /*
  * This routine only knows how to look for drive units 0 and 1
  * on an interface, so any setting of MAX_DRIVES > 2 won't work here.
  */
-static void probe_hwif (ide_hwif_t *hwif)
+void probe_hwif (ide_hwif_t *hwif)
 {
 	unsigned int unit;
 	unsigned long flags;
+	unsigned int irqd;
 
 	if (hwif->noprobe)
 		return;
 #ifdef CONFIG_BLK_DEV_IDE
 	if (hwif->io_ports[IDE_DATA_OFFSET] == HD_DATA) {
 		extern void probe_cmos_for_drives(ide_hwif_t *);
-
-		probe_cmos_for_drives (hwif);
+		probe_cmos_for_drives(hwif);
 	}
 #endif
-
-	if ((hwif->chipset != ide_4drives || !hwif->mate->present) &&
+	if ((hwif->chipset != ide_4drives || !hwif->mate || !hwif->mate->present) &&
 #if CONFIG_BLK_DEV_PDC4030
 	    (hwif->chipset != ide_pdc4030 || hwif->channel == 0) &&
 #endif /* CONFIG_BLK_DEV_PDC4030 */
 	    (hwif_check_regions(hwif))) {
-		int msgout = 0;
+		u16 msgout = 0;
 		for (unit = 0; unit < MAX_DRIVES; ++unit) {
 			ide_drive_t *drive = &hwif->drives[unit];
 			if (drive->present) {
 				drive->present = 0;
-				printk("%s: ERROR, PORTS ALREADY IN USE\n", drive->name);
+				printk("%s: ERROR, PORTS ALREADY IN USE\n",
+					drive->name);
 				msgout = 1;
 			}
 		}
 		if (!msgout)
-			printk("%s: ports already in use, skipping probe\n", hwif->name);
+			printk("%s: ports already in use, skipping probe\n",
+				hwif->name);
 		return;	
 	}
 
-	__save_flags(flags);	/* local CPU only */
-	__sti();		/* local CPU only; needed for jiffies and irq probing */
+	/*
+	 * We must always disable IRQ, as probe_for_drive will assert IRQ, but
+	 * we'll install our IRQ driver much later...
+	 */
+	irqd = hwif->irq;
+	if (irqd)
+		disable_irq(hwif->irq);
+
+	local_irq_set(flags);
 	/*
 	 * Second drive should only exist if first drive was found,
 	 * but a lot of cdrom drives are configured as single slaves.
 	 */
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
 		ide_drive_t *drive = &hwif->drives[unit];
-		(void) probe_for_drive (drive);
+		drive->dn = ((hwif->channel ? 2 : 0) + unit);
+		hwif->drives[unit].dn = ((hwif->channel ? 2 : 0) + unit);
+		(void) probe_for_drive(drive);
 		if (drive->present && !hwif->present) {
 			hwif->present = 1;
-			if (hwif->chipset != ide_4drives || !hwif->mate->present) {
+			if (hwif->chipset != ide_4drives ||
+			    !hwif->mate || 
+			    !hwif->mate->present) {
 				hwif_register(hwif);
 			}
 		}
 	}
 	if (hwif->io_ports[IDE_CONTROL_OFFSET] && hwif->reset) {
 		unsigned long timeout = jiffies + WAIT_WORSTCASE;
-		byte stat;
+		u8 stat;
 
 		printk("%s: reset\n", hwif->name);
-		OUT_BYTE(12, hwif->io_ports[IDE_CONTROL_OFFSET]);
+		hwif->OUTB(12, hwif->io_ports[IDE_CONTROL_OFFSET]);
 		udelay(10);
-		OUT_BYTE(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
+		hwif->OUTB(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
 		do {
 			ide_delay_50ms();
-			stat = IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);
-		} while ((stat & BUSY_STAT) && 0 < (signed long)(timeout - jiffies));
+			stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
+		} while ((stat & BUSY_STAT) && time_after(timeout, jiffies));
 
 	}
-	__restore_flags(flags);	/* local CPU only */
+	local_irq_restore(flags);
+	/*
+	 * Use cached IRQ number. It might be (and is...) changed by probe
+	 * code above
+	 */
+	if (irqd)
+		enable_irq(irqd);
+
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
 		ide_drive_t *drive = &hwif->drives[unit];
+		int enable_dma = 1;
+
 		if (drive->present) {
-			ide_tuneproc_t *tuneproc = HWIF(drive)->tuneproc;
-			if (tuneproc != NULL && drive->autotune == 1)
-				tuneproc(drive, 255);	/* auto-tune PIO mode */
+			if (hwif->tuneproc != NULL && 
+				drive->autotune == IDE_TUNE_AUTO)
+				/* auto-tune PIO mode */
+				hwif->tuneproc(drive, 255);
+
+#ifdef CONFIG_IDEDMA_ONLYDISK
+			if (drive->media != ide_disk)
+				enable_dma = 0;
+#endif
+			/*
+			 * MAJOR HACK BARF :-/
+			 *
+			 * FIXME: chipsets own this cruft!
+			 */
+			/*
+			 * Move here to prevent module loading clashing.
+			 */
+	//		drive->autodma = hwif->autodma;
+			if ((hwif->ide_dma_check) &&
+				((drive->autotune == IDE_TUNE_DEFAULT) ||
+				(drive->autotune == IDE_TUNE_AUTO))) {
+				/*
+				 * Force DMAing for the beginning of the check.
+				 * Some chipsets appear to do interesting
+				 * things, if not checked and cleared.
+				 *   PARANOIA!!!
+				 */
+				hwif->ide_dma_off_quietly(drive);
+				if (enable_dma)
+					hwif->ide_dma_check(drive);
+			}
 		}
 	}
 }
 
+EXPORT_SYMBOL(probe_hwif);
+
+#if 0
+int hwif_init (ide_hwif_t *hwif);
+int probe_hwif_init (ide_hwif_t *hwif)
+{
+	hwif->initializing = 1;
+	probe_hwif(hwif);
+	hwif_init(hwif);
+
+#if 1
+	if (hwif->present) {
+		u16 unit = 0;
+		for (unit = 0; unit < MAX_DRIVES; ++unit) {
+			ide_drive_t *drive = &hwif->drives[unit];
+			if (drive->present) {
+				ata_attach(drive);
+			}
+		}
+	}
+#endif
+	hwif->initializing = 0;
+	return 0;
+}
+
+EXPORT_SYMBOL(probe_hwif_init);
+#endif
+
 #if MAX_HWIFS > 1
 /*
  * save_match() is used to simplify logic in init_irq() below.
@@ -583,18 +758,20 @@
  *
  * This routine detects and reports such situations, but does not fix them.
  */
-static void save_match (ide_hwif_t *hwif, ide_hwif_t *new, ide_hwif_t **match)
+void save_match (ide_hwif_t *hwif, ide_hwif_t *new, ide_hwif_t **match)
 {
 	ide_hwif_t *m = *match;
 
 	if (m && m->hwgroup && m->hwgroup != new->hwgroup) {
 		if (!new->hwgroup)
 			return;
-		printk("%s: potential irq problem with %s and %s\n", hwif->name, new->name, m->name);
+		printk("%s: potential irq problem with %s and %s\n",
+			hwif->name, new->name, m->name);
 	}
 	if (!m || m->irq != hwif->irq) /* don't undo a prior perfect match */
 		*match = new;
 }
+EXPORT_SYMBOL(save_match);
 #endif /* MAX_HWIFS > 1 */
 
 /*
@@ -606,14 +783,9 @@
 
 	q->queuedata = HWGROUP(drive);
 	blk_init_queue(q, do_ide_request);
-
-	if (drive->media == ide_disk) {
-#ifdef CONFIG_BLK_DEV_ELEVATOR_NOOP
-		elevator_init(&q->elevator, ELEVATOR_NOOP);
-#endif
-	}
 }
 
+#undef __IRQ_HELL_SPIN
 /*
  * This routine sets up the irq for an ide interface, and creates a new
  * hwgroup for the irq/hwif if none was previously assigned.
@@ -627,20 +799,26 @@
  * but anything else has led to problems on some machines.  We re-enable
  * interrupts as much as we can safely do in most places.
  */
-static int init_irq (ide_hwif_t *hwif)
+int init_irq (ide_hwif_t *hwif)
 {
 	unsigned long flags;
 	unsigned int index;
 	ide_hwgroup_t *hwgroup, *new_hwgroup;
 	ide_hwif_t *match = NULL;
 
-	
+#if 0
+	/* Allocate the buffer and no sleep allowed */
+	new_hwgroup = kmalloc(sizeof(ide_hwgroup_t),GFP_ATOMIC);
+#else
 	/* Allocate the buffer and potentially sleep first */
-	
 	new_hwgroup = kmalloc(sizeof(ide_hwgroup_t),GFP_KERNEL);
+#endif
 	
-	save_flags(flags);	/* all CPUs */
-	cli();			/* all CPUs */
+#ifndef __IRQ_HELL_SPIN
+	save_and_cli(flags);
+#else
+	spin_lock_irqsave(&io_request_lock, flags);
+#endif
 
 	hwif->hwgroup = NULL;
 #if MAX_HWIFS > 1
@@ -652,7 +830,8 @@
 		if (h->hwgroup) {  /* scan only initialized hwif's */
 			if (hwif->irq == h->irq) {
 				hwif->sharing_irq = h->sharing_irq = 1;
-				if (hwif->chipset != ide_pci || h->chipset != ide_pci) {
+				if (hwif->chipset != ide_pci ||
+				    h->chipset != ide_pci) {
 					save_match(hwif, h, &match);
 				}
 			}
@@ -677,7 +856,11 @@
 	} else {
 		hwgroup = new_hwgroup;
 		if (!hwgroup) {
-			restore_flags(flags);	/* all CPUs */
+#ifndef __IRQ_HELL_SPIN
+			restore_flags(flags);
+#else
+			spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 			return 1;
 		}
 		memset(hwgroup, 0, sizeof(ide_hwgroup_t));
@@ -695,19 +878,30 @@
 	 * Allocate the irq, if not already obtained for another hwif
 	 */
 	if (!match || match->irq != hwif->irq) {
-#ifdef CONFIG_IDEPCI_SHARE_IRQ
-		int sa = IDE_CHIPSET_IS_PCI(hwif->chipset) ? SA_SHIRQ : SA_INTERRUPT;
-#else /* !CONFIG_IDEPCI_SHARE_IRQ */
-		int sa = IDE_CHIPSET_IS_PCI(hwif->chipset) ? SA_INTERRUPT|SA_SHIRQ : SA_INTERRUPT;
+		int sa = SA_INTERRUPT;
+#if defined(__mc68000__) || defined(CONFIG_APUS)
+		sa = SA_SHIRQ;
+#endif /* __mc68000__ || CONFIG_APUS */
+
+		if (IDE_CHIPSET_IS_PCI(hwif->chipset)) {
+			sa = SA_SHIRQ;
+#ifndef CONFIG_IDEPCI_SHARE_IRQ
+			sa |= SA_INTERRUPT;
 #endif /* CONFIG_IDEPCI_SHARE_IRQ */
+		}
 
 		if (hwif->io_ports[IDE_CONTROL_OFFSET])
-			OUT_BYTE(0x08, hwif->io_ports[IDE_CONTROL_OFFSET]); /* clear nIEN */
+			/* clear nIEN */
+			hwif->OUTB(0x08, hwif->io_ports[IDE_CONTROL_OFFSET]);
 
-		if (ide_request_irq(hwif->irq, &ide_intr, sa, hwif->name, hwgroup)) {
+		if (request_irq(hwif->irq,&ide_intr,sa,hwif->name,hwgroup)) {
 			if (!match)
 				kfree(hwgroup);
-			restore_flags(flags);	/* all CPUs */
+#ifndef __IRQ_HELL_SPIN
+			restore_flags(flags);
+#else
+			spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 			return 1;
 		}
 	}
@@ -735,10 +929,16 @@
 		printk("%s : Adding missed hwif to hwgroup!!\n", hwif->name);
 #endif
 	}
-	restore_flags(flags);	/* all CPUs; safe now that hwif->hwgroup is set up */
+
+	/* all CPUs; safe now that hwif->hwgroup is set up */
+#ifndef __IRQ_HELL_SPIN
+	restore_flags(flags);
+#else
+	spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 
 #if !defined(__mc68000__) && !defined(CONFIG_APUS) && !defined(__sparc__)
-	printk("%s at 0x%03x-0x%03x,0x%03x on irq %d", hwif->name,
+	printk("%s at 0x%03lx-0x%03lx,0x%03lx on irq %d", hwif->name,
 		hwif->io_ports[IDE_DATA_OFFSET],
 		hwif->io_ports[IDE_DATA_OFFSET]+7,
 		hwif->io_ports[IDE_CONTROL_OFFSET], hwif->irq);
@@ -748,7 +948,7 @@
 		hwif->io_ports[IDE_DATA_OFFSET]+7,
 		hwif->io_ports[IDE_CONTROL_OFFSET], __irq_itoa(hwif->irq));
 #else
-	printk("%s at %p on irq 0x%08x", hwif->name,
+	printk("%s at %x on irq 0x%08x", hwif->name,
 		hwif->io_ports[IDE_DATA_OFFSET], hwif->irq);
 #endif /* __mc68000__ && CONFIG_APUS */
 	if (match)
@@ -758,6 +958,8 @@
 	return 0;
 }
 
+EXPORT_SYMBOL(init_irq);
+
 /*
  * init_gendisk() (as opposed to ide_geninit) is called for each major device,
  * after probing for drives, to allocate partition tables and other data
@@ -771,34 +973,27 @@
 	int *bs, *max_sect, *max_ra;
 	extern devfs_handle_t ide_devfs_handle;
 
-#if 1
 	units = MAX_DRIVES;
-#else
-	/* figure out maximum drive number on the interface */
-	for (units = MAX_DRIVES; units > 0; --units) {
-		if (hwif->drives[units-1].present)
-			break;
-	}
-#endif
 
 	minors    = units * (1<<PARTN_BITS);
-	gd        = kmalloc (sizeof(struct gendisk), GFP_KERNEL);
+	gd        = kmalloc(sizeof(struct gendisk), GFP_KERNEL);
 	if (!gd)
 		goto err_kmalloc_gd;
-	memset (gd, 0, sizeof(struct gendisk));
-	gd->sizes = kmalloc (minors * sizeof(int), GFP_KERNEL);
+	memset(gd, 0, sizeof(struct gendisk));
+	
+	gd->sizes = kmalloc(minors * sizeof(int), GFP_KERNEL);
 	if (!gd->sizes)
 		goto err_kmalloc_gd_sizes;
-	gd->part  = kmalloc (minors * sizeof(struct hd_struct), GFP_KERNEL);
+	gd->part  = kmalloc(minors * sizeof(struct hd_struct), GFP_KERNEL);
 	if (!gd->part)
 		goto err_kmalloc_gd_part;
-	bs        = kmalloc (minors*sizeof(int), GFP_KERNEL);
+	bs        = kmalloc(minors*sizeof(int), GFP_KERNEL);
 	if (!bs)
 		goto err_kmalloc_bs;
-	max_sect  = kmalloc (minors*sizeof(int), GFP_KERNEL);
+	max_sect  = kmalloc(minors*sizeof(int), GFP_KERNEL);
 	if (!max_sect)
 		goto err_kmalloc_max_sect;
-	max_ra    = kmalloc (minors*sizeof(int), GFP_KERNEL);
+	max_ra    = kmalloc(minors*sizeof(int), GFP_KERNEL);
 	if (!max_ra)
 		goto err_kmalloc_max_ra;
 
@@ -813,55 +1008,49 @@
 		/*
 		 * IDE can do up to 128K per request == 256
 		 */
-		*max_sect++ = ((hwif->chipset == ide_pdc4030) ? 127 : 128);
+		*max_sect++ = ((hwif->rqsize) ? hwif->rqsize : 128);
 		*max_ra++ = vm_max_readahead;
 	}
 
 	for (unit = 0; unit < units; ++unit)
 		hwif->drives[unit].part = &gd->part[unit << PARTN_BITS];
 
-	gd->major	= hwif->major;		/* our major device number */
-	gd->major_name	= IDE_MAJOR_NAME;	/* treated special in genhd.c */
-	gd->minor_shift	= PARTN_BITS;		/* num bits for partitions */
-	gd->max_p	= 1<<PARTN_BITS;	/* 1 + max partitions / drive */
-	gd->nr_real	= units;		/* current num real drives */
-	gd->real_devices= hwif;			/* ptr to internal data */
-	gd->next	= NULL;			/* linked list of major devs */
-	gd->fops        = ide_fops;             /* file operations */
-	gd->de_arr	= kmalloc (sizeof *gd->de_arr * units, GFP_KERNEL);
-	gd->flags	= kmalloc (sizeof *gd->flags * units, GFP_KERNEL);
+	/* our major device number */
+	gd->major	= hwif->major;
+	/* treated special in genhd.c */
+	gd->major_name	= IDE_MAJOR_NAME;
+	/* num bits for partitions */
+	gd->minor_shift	= PARTN_BITS;
+	/* 1 + max partitions / drive */
+	gd->max_p	= 1<<PARTN_BITS;
+	/* current num real drives */
+	gd->nr_real	= units;
+	/* ptr to internal data */
+	gd->real_devices= hwif;
+	/* linked list of major devs */
+	gd->next	= NULL;
+	/* file operations */
+	gd->fops        = ide_fops;
+	gd->de_arr	= kmalloc(sizeof *gd->de_arr * units, GFP_KERNEL);
+	gd->flags	= kmalloc(sizeof *gd->flags * units, GFP_KERNEL);
 	if (gd->de_arr)
-		memset (gd->de_arr, 0, sizeof *gd->de_arr * units);
+		memset(gd->de_arr, 0, sizeof *gd->de_arr * units);
 	if (gd->flags)
-		memset (gd->flags, 0, sizeof *gd->flags * units);
+		memset(gd->flags, 0, sizeof *gd->flags * units);
 
 	hwif->gd = gd;
 	add_gendisk(gd);
 
 	for (unit = 0; unit < units; ++unit) {
-#if 1
 		char name[64];
 		ide_add_generic_settings(hwif->drives + unit);
-		hwif->drives[unit].dn = ((hwif->channel ? 2 : 0) + unit);
+//		hwif->drives[unit].dn = ((hwif->channel ? 2 : 0) + unit);
 		sprintf (name, "host%d/bus%d/target%d/lun%d",
 			(hwif->channel && hwif->mate) ?
 			hwif->mate->index : hwif->index,
 			hwif->channel, unit, hwif->drives[unit].lun);
 		if (hwif->drives[unit].present)
 			hwif->drives[unit].de = devfs_mk_dir(ide_devfs_handle, name, NULL);
-#else
-		if (hwif->drives[unit].present) {
-			char name[64];
-
-			ide_add_generic_settings(hwif->drives + unit);
-			hwif->drives[unit].dn = ((hwif->channel ? 2 : 0) + unit);
-			sprintf (name, "host%d/bus%d/target%d/lun%d",
-				 (hwif->channel && hwif->mate) ? hwif->mate->index : hwif->index,
-				 hwif->channel, unit, hwif->drives[unit].lun);
-			hwif->drives[unit].de =
-				devfs_mk_dir (ide_devfs_handle, name, NULL);
-		}
-#endif
 	}
 	return;
 
@@ -880,7 +1069,9 @@
 	return;
 }
 
-static int hwif_init (ide_hwif_t *hwif)
+EXPORT_SYMBOL(init_gendisk);
+
+int hwif_init (ide_hwif_t *hwif)
 {
 	if (!hwif->present)
 		return 0;
@@ -893,15 +1084,18 @@
 	}
 #ifdef CONFIG_BLK_DEV_HD
 	if (hwif->irq == HD_IRQ && hwif->io_ports[IDE_DATA_OFFSET] != HD_DATA) {
-		printk("%s: CANNOT SHARE IRQ WITH OLD HARDDISK DRIVER (hd.c)\n", hwif->name);
+		printk("%s: CANNOT SHARE IRQ WITH OLD "
+			"HARDDISK DRIVER (hd.c)\n", hwif->name);
 		return (hwif->present = 0);
 	}
 #endif /* CONFIG_BLK_DEV_HD */
-	
-	hwif->present = 0; /* we set it back to 1 if all is ok below */
+
+	/* we set it back to 1 if all is ok below */	
+	hwif->present = 0;
 
 	if (devfs_register_blkdev (hwif->major, hwif->name, ide_fops)) {
-		printk("%s: UNABLE TO GET MAJOR NUMBER %d\n", hwif->name, hwif->major);
+		printk("%s: UNABLE TO GET MAJOR NUMBER %d\n",
+			hwif->name, hwif->major);
 		return (hwif->present = 0);
 	}
 	
@@ -912,14 +1106,15 @@
 		 *	this port and try that.
 		 */
 		if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET]))) {
-			printk("%s: Disabled unable to get IRQ %d.\n", hwif->name, i);
-			(void) unregister_blkdev (hwif->major, hwif->name);
+			printk("%s: Disabled unable to get IRQ %d.\n",
+				hwif->name, i);
+			(void) unregister_blkdev(hwif->major, hwif->name);
 			return (hwif->present = 0);
 		}
 		if (init_irq(hwif)) {
 			printk("%s: probed IRQ %d and default IRQ %d failed.\n",
 				hwif->name, i, hwif->irq);
-			(void) unregister_blkdev (hwif->major, hwif->name);
+			(void) unregister_blkdev(hwif->major, hwif->name);
 			return (hwif->present = 0);
 		}
 		printk("%s: probed IRQ %d failed, using default.\n",
@@ -942,19 +1137,51 @@
 	return hwif->present;
 }
 
+EXPORT_SYMBOL(hwif_init);
+
 void export_ide_init_queue (ide_drive_t *drive)
 {
 	ide_init_queue(drive);
 }
 
-byte export_probe_for_drive (ide_drive_t *drive)
+EXPORT_SYMBOL(export_ide_init_queue);
+
+u8 export_probe_for_drive (ide_drive_t *drive)
 {
 	return probe_for_drive(drive);
 }
 
-EXPORT_SYMBOL(export_ide_init_queue);
 EXPORT_SYMBOL(export_probe_for_drive);
 
+#ifndef HWIF_PROBE_CLASSIC_METHOD
+int probe_hwif_init (ide_hwif_t *hwif)
+{
+	hwif->initializing = 1;
+	probe_hwif(hwif);
+	hwif_init(hwif);
+
+#ifndef CLASSIC_BUILTINS_METHOD
+#  ifndef FAKE_CLASSIC_ATTACH_METHOD
+#    ifdef DIRECT_HWIF_PROBE_ATTACH_METHOD
+	if (hwif->present) {
+		u16 unit = 0;
+		for (unit = 0; unit < MAX_DRIVES; ++unit) {
+			ide_drive_t *drive = &hwif->drives[unit];
+			if (drive->present)
+				ide_attach_drive(drive);
+		}
+	}
+#    endif /* DIRECT_HWIF_PROBE_ATTACH_METHOD */
+#  endif /* FAKE_CLASSIC_ATTACH_METHOD */
+#endif /* CLASSIC_BUILTINS_METHOD */
+	hwif->initializing = 0;
+	return 0;
+}
+
+EXPORT_SYMBOL(probe_hwif_init);
+
+#endif /* HWIF_PROBE_CLASSIC_METHOD */
+
 int ideprobe_init (void);
 static ide_module_t ideprobe_module = {
 	IDE_PROBE_MODULE,
@@ -975,12 +1202,20 @@
 	/*
 	 * Probe for drives in the usual way.. CMOS/BIOS, then poke at ports
 	 */
+#ifdef HWIF_PROBE_CLASSIC_METHOD
 	for (index = 0; index < MAX_HWIFS; ++index)
 		if (probe[index])
 			probe_hwif(&ide_hwifs[index]);
+
 	for (index = 0; index < MAX_HWIFS; ++index)
 		if (probe[index])
 			hwif_init(&ide_hwifs[index]);
+#else /* HWIF_PROBE_CLASSIC_METHOD */
+	for (index = 0; index < MAX_HWIFS; ++index)
+		if (probe[index])
+			probe_hwif_init(&ide_hwifs[index]);
+#endif /* HWIF_PROBE_CLASSIC_METHOD */
+
 	if (!ide_probe)
 		ide_probe = &ideprobe_module;
 	MOD_DEC_USE_COUNT;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-proc.c linux-2.4.21-pre6/drivers/ide/ide-proc.c
--- linux-2.4.20/drivers/ide/ide-proc.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/ide-proc.c	2003-03-26 23:48:59.000000000 +0000
@@ -57,6 +57,9 @@
  */
 
 #include <linux/config.h>
+#define __NO_VERSION__
+#include <linux/module.h>
+
 #include <asm/uaccess.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
@@ -74,59 +77,6 @@
 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
 #endif
 
-#ifdef CONFIG_BLK_DEV_AEC62XX
-extern byte aec62xx_proc;
-int (*aec62xx_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_AEC62XX */
-#ifdef CONFIG_BLK_DEV_ALI15X3
-extern byte ali_proc;
-int (*ali_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_ALI15X3 */
-#ifdef CONFIG_BLK_DEV_AMD74XX
-extern byte amd74xx_proc;
-int (*amd74xx_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_AMD74XX */
-#ifdef CONFIG_BLK_DEV_CMD64X
-extern byte cmd64x_proc;
-int (*cmd64x_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_CMD64X */
-#ifdef CONFIG_BLK_DEV_CS5530
-extern byte cs5530_proc;
-int (*cs5530_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_CS5530 */
-#ifdef CONFIG_BLK_DEV_HPT34X
-extern byte hpt34x_proc;
-int (*hpt34x_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_HPT34X */
-#ifdef CONFIG_BLK_DEV_HPT366
-extern byte hpt366_proc;
-int (*hpt366_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_HPT366 */
-#ifdef CONFIG_BLK_DEV_PDC202XX
-extern byte pdc202xx_proc;
-int (*pdc202xx_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_PDC202XX */
-#ifdef CONFIG_BLK_DEV_PIIX
-extern byte piix_proc;
-int (*piix_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_PIIX */
-#ifdef CONFIG_BLK_DEV_SVWKS
-extern byte svwks_proc;
-int (*svwks_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_SVWKS */
-#ifdef CONFIG_BLK_DEV_SIS5513
-extern byte sis_proc;
-int (*sis_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_SIS5513 */
-#ifdef CONFIG_BLK_DEV_SLC90E66
-extern byte slc90e66_proc;
-int (*slc90e66_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_SLC90E66 */
-#ifdef CONFIG_BLK_DEV_VIA82CXXX
-extern byte via_proc;
-int (*via_display_info)(char *, char **, off_t, int) = NULL;
-#endif /* CONFIG_BLK_DEV_VIA82CXXX */
-
 static int ide_getxdigit(char c)
 {
 	int digit;
@@ -160,6 +110,17 @@
 
 static struct proc_dir_entry * proc_ide_root = NULL;
 
+#ifdef CONFIG_BLK_DEV_IDEPCI
+#include <linux/delay.h>
+/*
+ * This is the list of registered PCI chipset driver data structures.
+ */
+static ide_pci_host_proc_t * ide_pci_host_proc_list;
+
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+
+#undef __PROC_HELL
+
 static int proc_ide_write_config
 	(struct file *file, const char *buffer, unsigned long count, void *data)
 {
@@ -181,7 +142,11 @@
 	 * Do one full pass to verify all parameters,
 	 * then do another to actually write the regs.
 	 */
+#ifndef __PROC_HELL
 	save_flags(flags);	/* all CPUs */
+#else
+	spin_lock_irqsave(&io_request_lock, flags);
+#endif
 	do {
 		const char *p;
 		if (for_real) {
@@ -190,15 +155,32 @@
 			ide_hwgroup_t *mategroup = NULL;
 			if (hwif->mate && hwif->mate->hwgroup)
 				mategroup = (ide_hwgroup_t *)(hwif->mate->hwgroup);
+#ifndef __PROC_HELL
 			cli();	/* all CPUs; ensure all writes are done together */
-			while (mygroup->busy || (mategroup && mategroup->busy)) {
+#else
+			spin_lock_irqsave(&io_request_lock, flags);
+#endif
+			while (mygroup->busy ||
+			       (mategroup && mategroup->busy)) {
+#ifndef __PROC_HELL
 				sti();	/* all CPUs */
-				if (0 < (signed long)(jiffies - timeout)) {
+#else
+				spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
+				if (time_after(jiffies, timeout)) {
 					printk("/proc/ide/%s/config: channel(s) busy, cannot write\n", hwif->name);
+#ifndef __PROC_HELL
 					restore_flags(flags);	/* all CPUs */
+#else
+					spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 					return -EBUSY;
 				}
+#ifndef __PROC_HELL
 				cli();	/* all CPUs */
+#else
+				spin_lock_irqsave(&io_request_lock, flags);
+#endif
 			}
 		}
 		p = buffer;
@@ -213,7 +195,7 @@
 						break;
 				case 'P':	is_pci = 1;
 #ifdef CONFIG_BLK_DEV_IDEPCI
-						if (hwif->pci_dev && !IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL))
+						if (hwif->pci_dev && !hwif->pci_dev->vendor)
 							break;
 #endif	/* CONFIG_BLK_DEV_IDEPCI */
 						msg = "not a PCI device";
@@ -281,7 +263,11 @@
 							break;
 					}
 					if (rc) {
+#ifndef __PROC_HELL
 						restore_flags(flags);	/* all CPUs */
+#else
+						spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 						printk("proc_ide_write_config: error writing %s at bus %02x dev %02x reg 0x%x value 0x%x\n",
 							msg, dev->bus->number, dev->devfn, reg, val);
 						printk("proc_ide_write_config: error %d\n", rc);
@@ -311,11 +297,11 @@
  * 
  */
 					switch (digits) {
-						case 2:	outb(val, reg);
+						case 2:	hwif->OUTB(val, reg);
 							break;
-						case 4:	outw(val, reg);
+						case 4:	hwif->OUTW(val, reg);
 							break;
-						case 8:	outl(val, reg);
+						case 8:	hwif->OUTL(val, reg);
 							break;
 					}
 #endif /* !__mc68000__ && !CONFIG_APUS */
@@ -323,15 +309,23 @@
 			}
 		}
 	} while (!for_real++);
+#ifndef __PROC_HELL
 	restore_flags(flags);	/* all CPUs */
+#else
+	spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 	return count;
 parse_error:
+#ifndef __PROC_HELL
 	restore_flags(flags);	/* all CPUs */
+#else
+	spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 	printk("parse error\n");
 	return xx_xx_parse_error(start, startn, msg);
 }
 
-static int proc_ide_read_config
+int proc_ide_read_config
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	char		*out = page;
@@ -340,20 +334,26 @@
 #ifdef CONFIG_BLK_DEV_IDEPCI
 	ide_hwif_t	*hwif = (ide_hwif_t *)data;
 	struct pci_dev	*dev = hwif->pci_dev;
-	if (!IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL) && dev && dev->bus) {
+	if ((hwif->pci_dev && hwif->pci_dev->vendor) && dev && dev->bus) {
 		int reg = 0;
 
-		out += sprintf(out, "pci bus %02x device %02x vid %04x did %04x channel %d\n",
-			dev->bus->number, dev->devfn, hwif->pci_devid.vid, hwif->pci_devid.did, hwif->channel);
+		out += sprintf(out, "pci bus %02x device %02x vendor %04x "
+				"device %04x channel %d\n",
+			dev->bus->number, dev->devfn,
+			hwif->pci_dev->vendor, hwif->pci_dev->device,
+			hwif->channel);
 		do {
-			byte val;
+			u8 val;
 			int rc = pci_read_config_byte(dev, reg, &val);
 			if (rc) {
-				printk("proc_ide_read_config: error %d reading bus %02x dev %02x reg 0x%02x\n",
+				printk("proc_ide_read_config: error %d reading"
+					" bus %02x dev %02x reg 0x%02x\n",
 					rc, dev->bus->number, dev->devfn, reg);
-				out += sprintf(out, "??%c", (++reg & 0xf) ? ' ' : '\n');
+				out += sprintf(out, "??%c",
+					(++reg & 0xf) ? ' ' : '\n');
 			} else
-				out += sprintf(out, "%02x%c", val, (++reg & 0xf) ? ' ' : '\n');
+				out += sprintf(out, "%02x%c",
+					val, (++reg & 0xf) ? ' ' : '\n');
 		} while (reg < 0x100);
 	} else
 #endif	/* CONFIG_BLK_DEV_IDEPCI */
@@ -362,6 +362,7 @@
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
+EXPORT_SYMBOL(proc_ide_read_config);
 
 static int ide_getdigit(char c)
 {
@@ -373,7 +374,7 @@
 	return digit;
 }
 
-static int proc_ide_read_drivers
+int proc_ide_read_drivers
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	char		*out = page;
@@ -384,14 +385,17 @@
 	while (p) {
 		driver = (ide_driver_t *) p->info;
 		if (driver)
-			out += sprintf(out, "%s version %s\n", driver->name, driver->version);
+			out += sprintf(out, "%s version %s\n",
+				driver->name, driver->version);
 		p = p->next;
 	}
 	len = out - page;
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
-static int proc_ide_read_imodel
+EXPORT_SYMBOL(proc_ide_read_drivers);
+
+int proc_ide_read_imodel
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	ide_hwif_t	*hwif = (ide_hwif_t *) data;
@@ -421,7 +425,9 @@
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
-static int proc_ide_read_mate
+EXPORT_SYMBOL(proc_ide_read_imodel);
+
+int proc_ide_read_mate
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	ide_hwif_t	*hwif = (ide_hwif_t *) data;
@@ -434,7 +440,9 @@
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
-static int proc_ide_read_channel
+EXPORT_SYMBOL(proc_ide_read_mate);
+
+int proc_ide_read_channel
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	ide_hwif_t	*hwif = (ide_hwif_t *) data;
@@ -446,31 +454,21 @@
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
-static int proc_ide_get_identify(ide_drive_t *drive, byte *buf)
-{
-	struct hd_drive_task_hdr taskfile;
-	struct hd_drive_hob_hdr hobfile;
-	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-
-	taskfile.sector_count = 0x01;
-	taskfile.command = (drive->media == ide_disk) ? WIN_IDENTIFY : WIN_PIDENTIFY ;
-
-	return ide_wait_taskfile(drive, &taskfile, &hobfile, buf);
-}
+EXPORT_SYMBOL(proc_ide_read_channel);
 
-static int proc_ide_read_identify
+int proc_ide_read_identify
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	ide_drive_t	*drive = (ide_drive_t *)data;
 	int		len = 0, i = 0;
 
-	if (drive && !proc_ide_get_identify(drive, page)) {
+	if (drive && !taskfile_lib_get_identify(drive, page)) {
 		unsigned short *val = (unsigned short *) page;
 		char *out = ((char *)val) + (SECTOR_WORDS * 4);
 		page = out;
 		do {
-			out += sprintf(out, "%04x%c", le16_to_cpu(*val), (++i & 7) ? ' ' : '\n');
+			out += sprintf(out, "%04x%c",
+				le16_to_cpu(*val), (++i & 7) ? ' ' : '\n');
 			val += 1;
 		} while (i < (SECTOR_WORDS * 2));
 		len = out - page;
@@ -480,7 +478,9 @@
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
-static int proc_ide_read_settings
+EXPORT_SYMBOL(proc_ide_read_identify);
+
+int proc_ide_read_settings
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	ide_drive_t	*drive = (ide_drive_t *) data;
@@ -510,9 +510,11 @@
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
+EXPORT_SYMBOL(proc_ide_read_settings);
+
 #define MAX_LEN	30
 
-static int proc_ide_write_settings
+int proc_ide_write_settings
 	(struct file *file, const char *buffer, unsigned long count, void *data)
 {
 	ide_drive_t	*drive = (ide_drive_t *) data;
@@ -587,6 +589,8 @@
 	return -EINVAL;
 }
 
+EXPORT_SYMBOL(proc_ide_write_settings);
+
 int proc_ide_read_capacity
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
@@ -598,10 +602,12 @@
 		len = sprintf(page, "(none)\n");
         else
 		len = sprintf(page,"%llu\n",
-			      (unsigned long long) ((ide_driver_t *)drive->driver)->capacity(drive));
+			      (u64) ((ide_driver_t *)drive->driver)->capacity(drive));
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
+EXPORT_SYMBOL(proc_ide_read_capacity);
+
 int proc_ide_read_geometry
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
@@ -609,24 +615,32 @@
 	char		*out = page;
 	int		len;
 
-	out += sprintf(out,"physical     %d/%d/%d\n", drive->cyl, drive->head, drive->sect);
-	out += sprintf(out,"logical      %d/%d/%d\n", drive->bios_cyl, drive->bios_head, drive->bios_sect);
+	out += sprintf(out,"physical     %d/%d/%d\n",
+			drive->cyl, drive->head, drive->sect);
+	out += sprintf(out,"logical      %d/%d/%d\n",
+			drive->bios_cyl, drive->bios_head, drive->bios_sect);
+
 	len = out - page;
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
-static int proc_ide_read_dmodel
+EXPORT_SYMBOL(proc_ide_read_geometry);
+
+int proc_ide_read_dmodel
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	ide_drive_t	*drive = (ide_drive_t *) data;
 	struct hd_driveid *id = drive->id;
 	int		len;
 
-	len = sprintf(page, "%.40s\n", (id && id->model[0]) ? (char *)id->model : "(none)");
+	len = sprintf(page, "%.40s\n",
+		(id && id->model[0]) ? (char *)id->model : "(none)");
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
-static int proc_ide_read_driver
+EXPORT_SYMBOL(proc_ide_read_dmodel);
+
+int proc_ide_read_driver
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	ide_drive_t	*drive = (ide_drive_t *) data;
@@ -636,11 +650,14 @@
 	if (!driver)
 		len = sprintf(page, "(none)\n");
 	else
-		len = sprintf(page, "%s version %s\n", driver->name, driver->version);
+		len = sprintf(page, "%s version %s\n",
+			driver->name, driver->version);
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
-static int proc_ide_write_driver
+EXPORT_SYMBOL(proc_ide_read_driver);
+
+int proc_ide_write_driver
 	(struct file *file, const char *buffer, unsigned long count, void *data)
 {
 	ide_drive_t	*drive = (ide_drive_t *) data;
@@ -652,7 +669,9 @@
 	return count;
 }
 
-static int proc_ide_read_media
+EXPORT_SYMBOL(proc_ide_write_driver);
+
+int proc_ide_read_media
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	ide_drive_t	*drive = (ide_drive_t *) data;
@@ -676,6 +695,8 @@
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
+EXPORT_SYMBOL(proc_ide_read_media);
+
 static ide_proc_entry_t generic_drive_entries[] = {
 	{ "driver",	S_IFREG|S_IRUGO,	proc_ide_read_driver,	proc_ide_write_driver },
 	{ "identify",	S_IFREG|S_IRUSR,	proc_ide_read_identify,	NULL },
@@ -702,6 +723,8 @@
 	}
 }
 
+EXPORT_SYMBOL(ide_add_proc_entries);
+
 void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p)
 {
 	if (!dir || !p)
@@ -712,7 +735,9 @@
 	}
 }
 
-static void create_proc_ide_drives(ide_hwif_t *hwif)
+EXPORT_SYMBOL(ide_remove_proc_entries);
+
+void create_proc_ide_drives(ide_hwif_t *hwif)
 {
 	int	d;
 	struct proc_dir_entry *ent;
@@ -742,6 +767,8 @@
 	}
 }
 
+EXPORT_SYMBOL(create_proc_ide_drives);
+
 void recreate_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive)
 {
 	struct proc_dir_entry *ent;
@@ -769,6 +796,8 @@
 	}
 }
 
+EXPORT_SYMBOL(recreate_proc_ide_device);
+
 void destroy_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive)
 {
 	ide_driver_t *driver = drive->driver;
@@ -783,19 +812,21 @@
 	}
 }
 
+EXPORT_SYMBOL(destroy_proc_ide_device);
+
 void destroy_proc_ide_drives(ide_hwif_t *hwif)
 {
 	int	d;
 
 	for (d = 0; d < MAX_DRIVES; d++) {
 		ide_drive_t *drive = &hwif->drives[d];
-//		ide_driver_t *driver = drive->driver;
-
 		if (drive->proc)
 			destroy_proc_ide_device(hwif, drive);
 	}
 }
 
+EXPORT_SYMBOL(destroy_proc_ide_drives);
+
 static ide_proc_entry_t hwif_entries[] = {
 	{ "channel",	S_IFREG|S_IRUGO,	proc_ide_read_channel,	NULL },
 	{ "config",	S_IFREG|S_IRUGO|S_IWUSR,proc_ide_read_config,	proc_ide_write_config },
@@ -823,7 +854,9 @@
 	}
 }
 
-static void destroy_proc_ide_interfaces(void)
+EXPORT_SYMBOL(create_proc_ide_interfaces);
+
+void destroy_proc_ide_interfaces(void)
 {
 	int	h;
 
@@ -844,8 +877,34 @@
 	}
 }
 
+EXPORT_SYMBOL(destroy_proc_ide_interfaces);
+
+#ifdef CONFIG_BLK_DEV_IDEPCI
+void ide_pci_register_host_proc (ide_pci_host_proc_t *p)
+{
+	ide_pci_host_proc_t *tmp;
+
+	if (!p) return;
+	p->next = NULL;
+	p->set = 1;
+	if (ide_pci_host_proc_list) {
+		tmp = ide_pci_host_proc_list;
+		while (tmp->next) tmp = tmp->next;
+		tmp->next = p;
+	} else
+		ide_pci_host_proc_list = p;
+}
+
+EXPORT_SYMBOL(ide_pci_register_host_proc);
+
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+
 void proc_ide_create(void)
 {
+#ifdef CONFIG_BLK_DEV_IDEPCI
+	ide_pci_host_proc_t *p = ide_pci_host_proc_list;
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+
 	proc_ide_root = proc_mkdir("ide", 0);
 	if (!proc_ide_root) return;
 
@@ -854,120 +913,40 @@
 	create_proc_read_entry("drivers", 0, proc_ide_root,
 				proc_ide_read_drivers, NULL);
 
-#ifdef CONFIG_BLK_DEV_AEC62XX
-	if ((aec62xx_display_info) && (aec62xx_proc))
-		create_proc_info_entry("aec62xx", 0, proc_ide_root, aec62xx_display_info);
-#endif /* CONFIG_BLK_DEV_AEC62XX */
-#ifdef CONFIG_BLK_DEV_ALI15X3
-	if ((ali_display_info) && (ali_proc))
-		create_proc_info_entry("ali", 0, proc_ide_root, ali_display_info);
-#endif /* CONFIG_BLK_DEV_ALI15X3 */
-#ifdef CONFIG_BLK_DEV_AMD74XX
-	if ((amd74xx_display_info) && (amd74xx_proc))
-		create_proc_info_entry("amd74xx", 0, proc_ide_root, amd74xx_display_info);
-#endif /* CONFIG_BLK_DEV_AMD74XX */
-#ifdef CONFIG_BLK_DEV_CMD64X
-	if ((cmd64x_display_info) && (cmd64x_proc))
-		create_proc_info_entry("cmd64x", 0, proc_ide_root, cmd64x_display_info);
-#endif /* CONFIG_BLK_DEV_CMD64X */
-#ifdef CONFIG_BLK_DEV_CS5530
-	if ((cs5530_display_info) && (cs5530_proc))
-		create_proc_info_entry("cs5530", 0, proc_ide_root, cs5530_display_info);
-#endif /* CONFIG_BLK_DEV_CS5530 */
-#ifdef CONFIG_BLK_DEV_HPT34X
-	if ((hpt34x_display_info) && (hpt34x_proc))
-		create_proc_info_entry("hpt34x", 0, proc_ide_root, hpt34x_display_info);
-#endif /* CONFIG_BLK_DEV_HPT34X */
-#ifdef CONFIG_BLK_DEV_HPT366
-	if ((hpt366_display_info) && (hpt366_proc))
-		create_proc_info_entry("hpt366", 0, proc_ide_root, hpt366_display_info);
-#endif /* CONFIG_BLK_DEV_HPT366 */
-#ifdef CONFIG_BLK_DEV_SVWKS
-	if ((svwks_display_info) && (svwks_proc))
-		create_proc_info_entry("svwks", 0, proc_ide_root, svwks_display_info);
-#endif /* CONFIG_BLK_DEV_SVWKS */
-#ifdef CONFIG_BLK_DEV_PDC202XX
-	if ((pdc202xx_display_info) && (pdc202xx_proc))
-		create_proc_info_entry("pdc202xx", 0, proc_ide_root, pdc202xx_display_info);
-#endif /* CONFIG_BLK_DEV_PDC202XX */
-#ifdef CONFIG_BLK_DEV_PIIX
-	if ((piix_display_info) && (piix_proc))
-		create_proc_info_entry("piix", 0, proc_ide_root, piix_display_info);
-#endif /* CONFIG_BLK_DEV_PIIX */
-#ifdef CONFIG_BLK_DEV_SIS5513
-	if ((sis_display_info) && (sis_proc))
-		create_proc_info_entry("sis", 0, proc_ide_root, sis_display_info);
-#endif /* CONFIG_BLK_DEV_SIS5513 */
-#ifdef CONFIG_BLK_DEV_SLC90E66
-	if ((slc90e66_display_info) && (slc90e66_proc))
-		create_proc_info_entry("slc90e66", 0, proc_ide_root, slc90e66_display_info);
-#endif /* CONFIG_BLK_DEV_SLC90E66 */
-#ifdef CONFIG_BLK_DEV_VIA82CXXX
-	if ((via_display_info) && (via_proc))
-		create_proc_info_entry("via", 0, proc_ide_root, via_display_info);
-#endif /* CONFIG_BLK_DEV_VIA82CXXX */
+#ifdef CONFIG_BLK_DEV_IDEPCI
+	while (p != NULL)
+	{
+		if (p->name != NULL && p->set == 1 && p->get_info != NULL) 
+		{
+			p->parent = proc_ide_root;
+			create_proc_info_entry(p->name, 0, p->parent, p->get_info);
+			p->set = 2;
+		}
+		p = p->next;
+	}
+#endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
+EXPORT_SYMBOL(proc_ide_create);
+
 void proc_ide_destroy(void)
 {
-	/*
-	 * Mmmm.. does this free up all resources,
-	 * or do we need to do a more proper cleanup here ??
-	 */
-#ifdef CONFIG_BLK_DEV_AEC62XX
-	if ((aec62xx_display_info) && (aec62xx_proc))
-		remove_proc_entry("ide/aec62xx",0);
-#endif /* CONFIG_BLK_DEV_AEC62XX */
-#ifdef CONFIG_BLK_DEV_ALI15X3
-	if ((ali_display_info) && (ali_proc))
-		remove_proc_entry("ide/ali",0);
-#endif /* CONFIG_BLK_DEV_ALI15X3 */
-#ifdef CONFIG_BLK_DEV_AMD74XX
-	if ((amd74xx_display_info) && (amd74xx_proc))
-		remove_proc_entry("ide/amd74xx",0);
-#endif /* CONFIG_BLK_DEV_AMD74XX */
-#ifdef CONFIG_BLK_DEV_CMD64X
-	if ((cmd64x_display_info) && (cmd64x_proc))
-		remove_proc_entry("ide/cmd64x",0);
-#endif /* CONFIG_BLK_DEV_CMD64X */
-#ifdef CONFIG_BLK_DEV_CS5530
-	if ((cs5530_display_info) && (cs5530_proc))
-		remove_proc_entry("ide/cs5530",0);
-#endif /* CONFIG_BLK_DEV_CS5530 */
-#ifdef CONFIG_BLK_DEV_HPT34X
-	if ((hpt34x_display_info) && (hpt34x_proc))
-		remove_proc_entry("ide/hpt34x",0);
-#endif /* CONFIG_BLK_DEV_HPT34X */
-#ifdef CONFIG_BLK_DEV_HPT366
-	if ((hpt366_display_info) && (hpt366_proc))
-		remove_proc_entry("ide/hpt366",0);
-#endif /* CONFIG_BLK_DEV_HPT366 */
-#ifdef CONFIG_BLK_DEV_PDC202XX
-	if ((pdc202xx_display_info) && (pdc202xx_proc))
-		remove_proc_entry("ide/pdc202xx",0);
-#endif /* CONFIG_BLK_DEV_PDC202XX */
-#ifdef CONFIG_BLK_DEV_PIIX
-	if ((piix_display_info) && (piix_proc))
-		remove_proc_entry("ide/piix",0);
-#endif /* CONFIG_BLK_DEV_PIIX */
-#ifdef CONFIG_BLK_DEV_SVWKS
-	if ((svwks_display_info) && (svwks_proc))
-		remove_proc_entry("ide/svwks",0);
-#endif /* CONFIG_BLK_DEV_SVWKS */
-#ifdef CONFIG_BLK_DEV_SIS5513
-	if ((sis_display_info) && (sis_proc))
-		remove_proc_entry("ide/sis", 0);
-#endif /* CONFIG_BLK_DEV_SIS5513 */
-#ifdef CONFIG_BLK_DEV_SLC90E66
-	if ((slc90e66_display_info) && (slc90e66_proc))
-		remove_proc_entry("ide/slc90e66",0);
-#endif /* CONFIG_BLK_DEV_SLC90E66 */
-#ifdef CONFIG_BLK_DEV_VIA82CXXX
-	if ((via_display_info) && (via_proc))
-		remove_proc_entry("ide/via",0);
-#endif /* CONFIG_BLK_DEV_VIA82CXXX */
+#ifdef CONFIG_BLK_DEV_IDEPCI
+	ide_pci_host_proc_t *p = ide_pci_host_proc_list;
+	char name[32];
 
-	remove_proc_entry("ide/drivers", 0);
+	while ((p->name != NULL) && (p->set) && (p->get_info != NULL)) {
+		name[0] = '\0';
+		sprintf(name, "ide/%s", p->name);
+		if (p->set == 2)
+			remove_proc_entry(p->name, p->parent);
+		if (p->next == NULL) break;
+		p = p->next;
+	}
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+	remove_proc_entry("ide/drivers", proc_ide_root);
 	destroy_proc_ide_interfaces();
 	remove_proc_entry("ide", 0);
 }
+
+EXPORT_SYMBOL(proc_ide_destroy);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-sibyte.c linux-2.4.21-pre6/drivers/ide/ide-sibyte.c
--- linux-2.4.20/drivers/ide/ide-sibyte.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/ide-sibyte.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,333 +0,0 @@
-/*
- * Copyright (C) 2001 Broadcom Corporation
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  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.
- */
-
-/*  Derived loosely from ide-pmac.c, so:
- *  
- *  Copyright (C) 1998 Paul Mackerras.
- *  Copyright (C) 1995-1998 Mark Lord
- */
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <asm/sibyte/sb1250_regs.h>
-#include <asm/sibyte/sb1250_int.h>
-#include <asm/sibyte/sb1250_genbus.h>
-#include <asm/sibyte/64bit.h>
-#include <asm/sibyte/board.h>
-
-/* Note: this should be general for any board using IDE on GenBus */
-
-extern struct ide_ops std_ide_ops;
-
-static ide_hwif_t *sb_ide_hwif = NULL;
-static unsigned long ide_base;
-
-#define SIBYTE_IDE_BASE        (KSEG1ADDR(ide_base)-mips_io_port_base)
-#define SIBYTE_IDE_REG(pcaddr) (SIBYTE_IDE_BASE + ((pcaddr)<<5))
-
-/*
- * We are limiting the number of PCI-IDE devices to leave room for
- * GenBus IDE (and possibly PCMCIA/CF?)
- */
-static int sibyte_ide_default_irq(ide_ioreg_t base)
-{
-	return 0;
-}
-
-static ide_ioreg_t sibyte_ide_default_io_base(int index)
-{
-	return 0;
-}
-
-static void sibyte_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port,
-				       ide_ioreg_t ctrl_port, int *irq)
-{
-	std_ide_ops.ide_init_hwif_ports(hw, data_port, ctrl_port, irq);
-}
-
-static int sibyte_ide_request_irq(unsigned int irq,
-                                void (*handler)(int,void *, struct pt_regs *),
-                                unsigned long flags, const char *device,
-                                void *dev_id)
-{
-	return request_irq(irq, handler, flags, device, dev_id);
-}
-
-static void sibyte_ide_free_irq(unsigned int irq, void *dev_id)
-{
-	free_irq(irq, dev_id);
-}
-
-static inline int is_sibyte_ide(ide_ioreg_t from)
-{
-	return (sb_ide_hwif &&
-		((from == sb_ide_hwif->io_ports[IDE_DATA_OFFSET]) ||
-		 (from == sb_ide_hwif->io_ports[IDE_ERROR_OFFSET]) ||
-		 (from == sb_ide_hwif->io_ports[IDE_NSECTOR_OFFSET]) ||
-		 (from == sb_ide_hwif->io_ports[IDE_SECTOR_OFFSET]) ||
-		 (from == sb_ide_hwif->io_ports[IDE_LCYL_OFFSET]) ||
-		 (from == sb_ide_hwif->io_ports[IDE_HCYL_OFFSET]) ||
-		 (from == sb_ide_hwif->io_ports[IDE_SELECT_OFFSET]) ||
-		 (from == sb_ide_hwif->io_ports[IDE_STATUS_OFFSET]) ||
-		 (from == sb_ide_hwif->io_ports[IDE_CONTROL_OFFSET])));
-}
-
-static int sibyte_ide_check_region(ide_ioreg_t from, unsigned int extent)
-{
-	/* Figure out if it's the SiByte IDE; if so, don't do anything
-           since our I/O space is in a weird place. */
-	if (is_sibyte_ide(from))
-		return 0;
-	else
-#ifdef CONFIG_BLK_DEV_IDE
-		return std_ide_ops.ide_check_region(from, extent);
-#else
-		return 0;
-#endif
-}
-
-static void sibyte_ide_request_region(ide_ioreg_t from, unsigned int extent,
-				     const char *name)
-{
-#ifdef CONFIG_BLK_DEV_IDE
-	if (!is_sibyte_ide(from))
-		std_ide_ops.ide_request_region(from, extent, name);
-#endif
-}
-
-static void sibyte_ide_release_region(ide_ioreg_t from, unsigned int extent)
-{
-#ifdef CONFIG_BLK_DEV_IDE
-	if (!is_sibyte_ide(from))
-		std_ide_ops.ide_release_region(from, extent);
-#endif
-}
-
-struct ide_ops sibyte_ide_ops = {
-	&sibyte_ide_default_irq,
-	&sibyte_ide_default_io_base,
-	&sibyte_ide_init_hwif_ports,
-	&sibyte_ide_request_irq,
-	&sibyte_ide_free_irq,
-	&sibyte_ide_check_region,
-	&sibyte_ide_request_region,
-	&sibyte_ide_release_region
-};
-
-/*
- * I/O operations. The FPGA for SiByte generic bus IDE deals with
- * byte-swapping for us, so we can't share the I/O macros with other
- * IDE (e.g. PCI-IDE) devices.
- */
-
-#define sibyte_outb(val,port)					\
-do {								\
-	*(volatile u8 *)(mips_io_port_base + (port)) = val;	\
-} while(0)
-
-#define sibyte_outw(val,port)					\
-do {								\
-	*(volatile u16 *)(mips_io_port_base + (port)) = val;	\
-} while(0)
-
-#define sibyte_outl(val,port)					\
-do {								\
-	*(volatile u32 *)(mips_io_port_base + (port)) = val;	\
-} while(0)
-
-static inline unsigned char sibyte_inb(unsigned long port)
-{
-	return (*(volatile u8 *)(mips_io_port_base + (port)));
-}
-
-static inline unsigned short sibyte_inw(unsigned long port)
-{
-	return (*(volatile u16 *)(mips_io_port_base + (port)));
-}
-
-static inline unsigned int sibyte_inl(unsigned long port)
-{
-	return (*(volatile u32 *)(mips_io_port_base + (port)));
-}
-
-
-static inline void sibyte_outsb(unsigned long port, void *addr, unsigned int count)
-{
-	while (count--) {
-		sibyte_outb(*(u8 *)addr, port);
-		addr++;
-	}
-}
-
-static inline void sibyte_insb(unsigned long port, void *addr, unsigned int count)
-{
-	while (count--) {
-		*(u8 *)addr = sibyte_inb(port);
-		addr++;
-	}
-}
-
-static inline void sibyte_outsw(unsigned long port, void *addr, unsigned int count)
-{
-	while (count--) {
-		sibyte_outw(*(u16 *)addr, port);
-		addr += 2;
-	}
-}
-
-static inline void sibyte_insw(unsigned long port, void *addr, unsigned int count)
-{
-	while (count--) {
-		*(u16 *)addr = sibyte_inw(port);
-		addr += 2;
-	}
-}
-
-static inline void sibyte_outsl(unsigned long port, void *addr, unsigned int count)
-{
-	while (count--) {
-		sibyte_outl(*(u32 *)addr, port);
-		addr += 4;
-	}
-}
-
-static inline void sibyte_insl(unsigned long port, void *addr, unsigned int count)
-{
-	while (count--) {
-		*(u32 *)addr = sibyte_inl(port);
-		addr += 4;
-	}
-}
-
-static void sibyte_ideproc(ide_ide_action_t action, ide_drive_t *drive,
-			   void *buffer, unsigned int count)
-{
-	/*  slow? vlb_sync? */
-	switch (action) {
-	case ideproc_ide_input_data:
-		if (drive->io_32bit) {
-			sibyte_insl(IDE_DATA_REG, buffer, count);
-		} else {
-			sibyte_insw(IDE_DATA_REG, buffer, count<<1);
-		}
-		break;
-	case ideproc_ide_output_data:
-		if (drive->io_32bit) {
-			sibyte_outsl(IDE_DATA_REG, buffer, count);
-		} else {
-			sibyte_outsw(IDE_DATA_REG, buffer, count<<1);
-		}
-		break;
-	case ideproc_atapi_input_bytes:
-		count++;
-		if (drive->io_32bit) {
-			sibyte_insl(IDE_DATA_REG, buffer, count>>2);
-		} else {
-			sibyte_insw(IDE_DATA_REG, buffer, count>>1);
-		}
-		if ((count & 3) >= 2)
-			sibyte_insw(IDE_DATA_REG, (char *)buffer + (count & ~3), 1);
-		break;
-	case ideproc_atapi_output_bytes:
-		count++;
-		if (drive->io_32bit) {
-			sibyte_outsl(IDE_DATA_REG, buffer, count>>2);
-		} else {
-			sibyte_outsw(IDE_DATA_REG, buffer, count>>1);
-		}
-		if ((count & 3) >= 2)
-			sibyte_outsw(IDE_DATA_REG, (char *)buffer + (count & ~3), 1);
-		break;
-	}
-}
-
-/*
- * selectproc and intrproc aren't really necessary, since
- * byte-swapping doesn't affect byte ops; they are included for
- * consistency.
- */
-static void sibyte_selectproc(ide_drive_t *drive)
-{
-	sibyte_outb(drive->select.all, IDE_SELECT_REG);
-}
-
-static void sibyte_intrproc(ide_drive_t *drive)
-{
-	sibyte_outb(drive->ctl|2, IDE_CONTROL_REG);
-}
-
-void __init sibyte_ide_probe(void)
-{
-	int i;
-	ide_hwif_t *hwif;
-	/* 
-	 * Find the first untaken slot in hwifs 
-	 */
-	for (i = 0; i < MAX_HWIFS; i++) {
-		if (!ide_hwifs[i].io_ports[IDE_DATA_OFFSET]) {
-			break;
-		}
-	}
-	if (i == MAX_HWIFS) {
-		printk("No space for SiByte onboard IDE driver in ide_hwifs[].  Not enabled.\n");
-		return;
-	}
-
-	/* Find memory base address */
-#ifdef __MIPSEL__
-	/* Pass1 workaround (bug 1624) */
-	if (sb1250_pass == K_SYS_REVISION_PASS1)
-		ide_base = G_IO_START_ADDR(csr_in32(4+(IO_SPACE_BASE|A_IO_EXT_REG(R_IO_EXT_REG(R_IO_EXT_START_ADDR, IDE_CS))))) << S_IO_ADDRBASE;
-	else
-#endif
-		ide_base = G_IO_START_ADDR(csr_in32(IO_SPACE_BASE|A_IO_EXT_REG(R_IO_EXT_REG(R_IO_EXT_START_ADDR, IDE_CS)))) << S_IO_ADDRBASE;
-
-	/*
-	 * Set up our stuff; we're a little odd because our io_ports
-	 * aren't in the usual place, and byte-swapping isn't
-	 * necessary.
-	 */
-	hwif = &ide_hwifs[i];
-	hwif->hw.io_ports[IDE_DATA_OFFSET]    = SIBYTE_IDE_REG(0x1f0);
-	hwif->hw.io_ports[IDE_ERROR_OFFSET]   = SIBYTE_IDE_REG(0x1f1);
-	hwif->hw.io_ports[IDE_NSECTOR_OFFSET] = SIBYTE_IDE_REG(0x1f2);
-	hwif->hw.io_ports[IDE_SECTOR_OFFSET]  = SIBYTE_IDE_REG(0x1f3);
-	hwif->hw.io_ports[IDE_LCYL_OFFSET]    = SIBYTE_IDE_REG(0x1f4);
-	hwif->hw.io_ports[IDE_HCYL_OFFSET]    = SIBYTE_IDE_REG(0x1f5);
-	hwif->hw.io_ports[IDE_SELECT_OFFSET]  = SIBYTE_IDE_REG(0x1f6);
-	hwif->hw.io_ports[IDE_STATUS_OFFSET]  = SIBYTE_IDE_REG(0x1f7);
-	hwif->hw.io_ports[IDE_CONTROL_OFFSET] = SIBYTE_IDE_REG(0x3f6);
-	hwif->hw.irq                          = K_INT_GB_IDE;
-	hwif->irq                             = K_INT_GB_IDE;
-	hwif->noprobe                         = 0;
-	/* Use our own non-byte-swapping routines */
-	hwif->ideproc                         = sibyte_ideproc;
-	hwif->selectproc                      = sibyte_selectproc;
-	hwif->intrproc                        = sibyte_intrproc;
-
-	memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
-	printk("SiByte onboard IDE configured as device %i\n", i);
-	sb_ide_hwif = hwif;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-tape.c linux-2.4.21-pre6/drivers/ide/ide-tape.c
--- linux-2.4.20/drivers/ide/ide-tape.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/ide-tape.c	2003-03-26 23:49:09.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/ide/ide-tape.c		Version 1.17a	Jan, 2001
+ * linux/drivers/ide/ide-tape.c		Version 1.17b	Dec, 2002
  *
  * Copyright (C) 1995 - 1999 Gadi Oxman <gadio@netvision.net.il>
  *
@@ -291,6 +291,28 @@
  * Ver 1.17a Apr 2001 Willem Riede osst@riede.org
  * 			- Get drive's actual block size from mode sense block descriptor
  * 			- Limit size of pipeline
+ * Ver 1.17b Dec 2002   Alan Stern <stern@rowland.harvard.edu>
+ *			Changed IDETAPE_MIN_PIPELINE_STAGES to 1 and actually used
+ *			 it in the code!
+ *			Actually removed aborted stages in idetape_abort_pipeline
+ *			 instead of just changing the command code.
+ *			Made the transfer byte count for Request Sense equal to the
+ *			 actual length of the data transfer.
+ *			Changed handling of partial data transfers: they do not
+ *			 cause DMA errors.
+ *			Moved initiation of DMA transfers to the correct place.
+ *			Removed reference to unallocated memory.
+ *			Made __idetape_discard_read_pipeline return the number of
+ *			 sectors skipped, not the number of stages.
+ *			Replaced errant kfree() calls with __idetape_kfree_stage().
+ *			Fixed off-by-one error in testing the pipeline length.
+ *			Fixed handling of filemarks in the read pipeline.
+ *			Small code optimization for MTBSF and MTBSFM ioctls.
+ *			Don't try to unlock the door during device close if is
+ *			 already unlocked!
+ *			Cosmetic fixes to miscellaneous debugging output messages.
+ *			Set the minimum /proc/ide/hd?/settings values for "pipeline",
+ *			 "pipeline_min", and "pipeline_max" to 1.
  *
  * Here are some words from the first releases of hd.c, which are quoted
  * in ide.c and apply here as well:
@@ -400,7 +422,7 @@
  *		sharing a (fast) ATA-2 disk with any (slow) new ATAPI device.
  */
 
-#define IDETAPE_VERSION "1.17a"
+#define IDETAPE_VERSION "1.17b"
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -416,7 +438,6 @@
 #include <linux/errno.h>
 #include <linux/genhd.h>
 #include <linux/slab.h>
-#include <linux/pci.h>
 #include <linux/ide.h>
 #include <linux/smp_lock.h>
 #include <linux/completion.h>
@@ -429,8 +450,6 @@
 #include <asm/bitops.h>
 
 
-#define NO_LONGER_REQUIRED	(1)
-
 /*
  *	OnStream support
  */
@@ -577,9 +596,10 @@
  *	whenever we sense that the pipeline is empty, until we reach
  *	the optimum value or until we reach MAX.
  *
- *	Setting the following parameter to 0 will disable the pipelined mode.
+ *	Setting the following parameter to 0 is illegal: the pipelined mode
+ *	cannot be disabled (calculate_speeds() divides by tape->max_stages.)
  */
-#define IDETAPE_MIN_PIPELINE_STAGES	200
+#define IDETAPE_MIN_PIPELINE_STAGES	  1
 #define IDETAPE_MAX_PIPELINE_STAGES	400
 #define IDETAPE_INCREASE_STAGES_RATE	 20
 
@@ -601,8 +621,8 @@
  *	is verified to be stable enough. This will make it much more
  *	esthetic.
  */
-#define IDETAPE_DEBUG_INFO		1
-#define IDETAPE_DEBUG_LOG		1
+#define IDETAPE_DEBUG_INFO		0
+#define IDETAPE_DEBUG_LOG		0
 #define IDETAPE_DEBUG_LOG_VERBOSE	0
 #define IDETAPE_DEBUG_BUGS		1
 
@@ -724,22 +744,28 @@
 	struct buffer_head *bh;
 	char *b_data;
 	int b_count;
-	byte *buffer;				/* Data buffer */
-	byte *current_position;			/* Pointer into the above buffer */
+	u8 *buffer;				/* Data buffer */
+	u8 *current_position;			/* Pointer into the above buffer */
 	ide_startstop_t (*callback) (ide_drive_t *);	/* Called when this packet command is completed */
-	byte pc_buffer[IDETAPE_PC_BUFFER_SIZE];	/* Temporary buffer */
+	u8 pc_buffer[IDETAPE_PC_BUFFER_SIZE];	/* Temporary buffer */
 	unsigned long flags;			/* Status/Action bit flags: long for set_bit */
 } idetape_pc_t;
 
 /*
  *	Packet command flag bits.
  */
-#define	PC_ABORT			0	/* Set when an error is considered normal - We won't retry */
-#define PC_WAIT_FOR_DSC			1	/* 1 When polling for DSC on a media access command */
-#define PC_DMA_RECOMMENDED		2	/* 1 when we prefer to use DMA if possible */
-#define	PC_DMA_IN_PROGRESS		3	/* 1 while DMA in progress */
-#define	PC_DMA_ERROR			4	/* 1 when encountered problem during DMA */
-#define	PC_WRITING			5	/* Data direction */
+/* Set when an error is considered normal - We won't retry */
+#define	PC_ABORT			0
+/* 1 When polling for DSC on a media access command */
+#define PC_WAIT_FOR_DSC			1
+/* 1 when we prefer to use DMA if possible */
+#define PC_DMA_RECOMMENDED		2
+/* 1 while DMA in progress */
+#define	PC_DMA_IN_PROGRESS		3
+/* 1 when encountered problem during DMA */
+#define	PC_DMA_ERROR			4
+/* Data direction */
+#define	PC_WRITING			5
 
 /*
  *	Capabilities and Mechanical Status Page
@@ -814,6 +840,7 @@
  *	REQUEST SENSE packet command result - Data Format.
  */
 typedef struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
 	unsigned	error_code	:7;	/* Current of deferred errors */
 	unsigned	valid		:1;	/* The information field conforms to QIC-157C */
 	__u8		reserved1	:8;	/* Segment Number - Reserved */
@@ -822,6 +849,18 @@
 	unsigned	ili		:1;	/* Incorrect Length Indicator */
 	unsigned	eom		:1;	/* End Of Medium */
 	unsigned	filemark 	:1;	/* Filemark */
+#elif defined(__BIG_ENDIAN_BITFIELD)
+	unsigned	valid		:1;
+	unsigned	error_code	:7;
+	__u8		reserved1	:8;
+	unsigned	filemark	:1;
+	unsigned	eom		:1;
+	unsigned	ili		:1;
+	unsigned	reserved2_4	:1;
+	unsigned	sense_key	:4;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
 	__u32		information __attribute__ ((packed));
 	__u8		asl;			/* Additional sense length (n-7) */
 	__u32		command_specific;	/* Additional command specific information */
@@ -860,12 +899,17 @@
 	 *	required since an additional packet command is needed before the
 	 *	retry, to get detailed information on what went wrong.
 	 */
-	idetape_pc_t *pc;			/* Current packet command */
-	idetape_pc_t *failed_pc; 		/* Last failed packet command */
-	idetape_pc_t pc_stack[IDETAPE_PC_STACK];/* Packet command stack */
-	int pc_stack_index;			/* Next free packet command storage space */
+	/* Current packet command */
+	idetape_pc_t *pc;
+	/* Last failed packet command */
+	idetape_pc_t *failed_pc;
+	/* Packet command stack */
+	idetape_pc_t pc_stack[IDETAPE_PC_STACK];
+	/* Next free packet command storage space */
+	int pc_stack_index;
 	struct request rq_stack[IDETAPE_PC_STACK];
-	int rq_stack_index;			/* We implement a circular array */
+	/* We implement a circular array */
+	int rq_stack_index;
 
 	/*
 	 *	DSC polling variables.
@@ -879,38 +923,48 @@
 	 *	to ide.c only one at a time.
 	 */
 	struct request *postponed_rq;
-	unsigned long dsc_polling_start;	/* The time in which we started polling for DSC */
-	struct timer_list dsc_timer;		/* Timer used to poll for dsc */
-	unsigned long best_dsc_rw_frequency;	/* Read/Write dsc polling frequency */
-	unsigned long dsc_polling_frequency;	/* The current polling frequency */
-	unsigned long dsc_timeout;		/* Maximum waiting time */
+	/* The time in which we started polling for DSC */
+	unsigned long dsc_polling_start;
+	/* Timer used to poll for dsc */
+	struct timer_list dsc_timer;
+	/* Read/Write dsc polling frequency */
+	unsigned long best_dsc_rw_frequency;
+	/* The current polling frequency */
+	unsigned long dsc_polling_frequency;
+	/* Maximum waiting time */
+	unsigned long dsc_timeout;
 
 	/*
 	 *	Read position information
 	 */
-	byte partition;
-	unsigned int first_frame_position;		/* Current block */
+	u8 partition;
+	/* Current block */
+	unsigned int first_frame_position;
 	unsigned int last_frame_position;
 	unsigned int blocks_in_buffer;
 
 	/*
 	 *	Last error information
 	 */
-	byte sense_key, asc, ascq;
+	u8 sense_key, asc, ascq;
 
 	/*
 	 *	Character device operation
 	 */
 	unsigned int minor;
-	char name[4];					/* device name */
-	idetape_chrdev_direction_t chrdev_direction;	/* Current character device data transfer direction */
+	/* device name */
+	char name[4];
+	/* Current character device data transfer direction */
+	idetape_chrdev_direction_t chrdev_direction;
 
 	/*
 	 *	Device information
 	 */
-	unsigned short tape_block_size;			/* Usually 512 or 1024 bytes */
+	/* Usually 512 or 1024 bytes */
+	unsigned short tape_block_size;
 	int user_bs_factor;
-	idetape_capabilities_page_t capabilities;	/* Copy of the tape's Capabilities and Mechanical Page */
+	/* Copy of the tape's Capabilities and Mechanical Page */
+	idetape_capabilities_page_t capabilities;
 
 	/*
 	 *	Active data transfer request parameters.
@@ -925,8 +979,10 @@
 	 *	The data buffer size is chosen based on the tape's
 	 *	recommendation.
 	 */
-	struct request *active_data_request;	/* Pointer to the request which is waiting in the device request queue */
-	int stage_size;				/* Data buffer size (chosen based on the tape's recommendation */
+	/* Pointer to the request, waiting in the device request queue */
+	struct request *active_data_request;
+	/* Data buffer size (chosen based on the tape's recommendation */
+	int stage_size;
 	idetape_stage_t *merge_stage;
 	int merge_stage_size;
 	struct buffer_head *bh;
@@ -939,19 +995,30 @@
 	 *	To accomplish non-pipelined mode, we simply set the following
 	 *	variables to zero (or NULL, where appropriate).
 	 */
-	int nr_stages;				/* Number of currently used stages */
-	int nr_pending_stages;			/* Number of pending stages */
-	int max_stages, min_pipeline, max_pipeline; /* We will not allocate more than this number of stages */
-	idetape_stage_t *first_stage;		/* The first stage which will be removed from the pipeline */
-	idetape_stage_t *active_stage;		/* The currently active stage */
-	idetape_stage_t *next_stage;		/* Will be serviced after the currently active request */
-	idetape_stage_t *last_stage;		/* New requests will be added to the pipeline here */
-	idetape_stage_t *cache_stage;		/* Optional free stage which we can use */
+	/* Number of currently used stages */
+	int nr_stages;
+	/* Number of pending stages */
+	int nr_pending_stages;
+	/* We will not allocate more than this number of stages */
+	int max_stages, min_pipeline, max_pipeline;
+	/* The first stage which will be removed from the pipeline */
+	idetape_stage_t *first_stage;
+	/* The currently active stage */
+	idetape_stage_t *active_stage;
+	/* Will be serviced after the currently active request */
+	idetape_stage_t *next_stage;
+	/* New requests will be added to the pipeline here */
+	idetape_stage_t *last_stage;
+	/* Optional free stage which we can use */
+	idetape_stage_t *cache_stage;
 	int pages_per_stage;
-	int excess_bh_size;			/* Wasted space in each stage */
+	/* Wasted space in each stage */
+	int excess_bh_size;
 
-	unsigned long flags;			/* Status/Action flags: long for set_bit */
-	spinlock_t spinlock;			/* protects the ide-tape queue */
+	/* Status/Action flags: long for set_bit */
+	unsigned long flags;
+	/* protects the ide-tape queue */
+	spinlock_t spinlock;
 
 	/*
 	 * Measures average tape speed
@@ -960,31 +1027,44 @@
 	int avg_size;
 	int avg_speed;
 
-	idetape_request_sense_result_t sense;	/* last sense information */
+	/* last sense information */
+	idetape_request_sense_result_t sense;
 
 	char vendor_id[10];
 	char product_id[18];
 	char firmware_revision[6];
 	int firmware_revision_num;
 
-	int door_locked;			/* the door is currently locked */
+	/* the door is currently locked */
+	int door_locked;
 
 	/*
 	 * OnStream flags
 	 */
-	int onstream;				/* the tape is an OnStream tape */
-	int raw;				/* OnStream raw access (32.5KB block size) */
-	int cur_frames;				/* current number of frames in internal buffer */
-	int max_frames;				/* max number of frames in internal buffer */
-	int logical_blk_num;			/* logical block number */
-	__u16 wrt_pass_cntr;			/* write pass counter */
-	__u32 update_frame_cntr;		/* update frame counter */
+	/* the tape is an OnStream tape */
+	int onstream;
+	/* OnStream raw access (32.5KB block size) */
+	int raw;
+	/* current number of frames in internal buffer */
+	int cur_frames;
+	/* max number of frames in internal buffer */
+	int max_frames;
+	/* logical block number */
+	int logical_blk_num;
+	/* write pass counter */
+	__u16 wrt_pass_cntr;
+	/* update frame counter */
+	__u32 update_frame_cntr;
 	struct completion *waiting;
-	int onstream_write_error;		/* write error recovery active */
-	int header_ok;				/* header frame verified ok */
-	int linux_media;			/* reading linux-specifc media */
+	/* write error recovery active */
+	int onstream_write_error;
+	/* header frame verified ok */
+	int header_ok;
+	/* reading linux-specifc media */
+	int linux_media;
 	int linux_media_version;
-	char application_sig[5];		/* application signature */
+	/* application signature */
+	char application_sig[5];
 	int filemark_cnt;
 	int first_mark_addr;
 	int last_mark_addr;
@@ -997,8 +1077,10 @@
 	 * Optimize the number of "buffer filling"
 	 * mode sense commands.
 	 */
-	unsigned long last_buffer_fill;		/* last time in which we issued fill cmd */
-	int req_buffer_fill;			/* buffer fill command requested */
+	/* last time in which we issued fill cmd */
+	unsigned long last_buffer_fill;
+	/* buffer fill command requested */
+	int req_buffer_fill;
 	int writes_since_buffer_fill;
 	int reads_since_buffer_fill;
 
@@ -1007,7 +1089,8 @@
 	 * be postponed, to avoid an infinite postpone
 	 * deadlock.
 	 */
-	int postpone_cnt;			/* request postpone count limit */
+	/* request postpone count limit */
+	int postpone_cnt;
 
 	/*
 	 * Measures number of frames:
@@ -1040,11 +1123,17 @@
 	 * Speed regulation negative feedback loop
 	 */
 	int speed_control;
-	int pipeline_head_speed, controlled_pipeline_head_speed, uncontrolled_pipeline_head_speed;
-	int controlled_last_pipeline_head, uncontrolled_last_pipeline_head;
-	unsigned long uncontrolled_pipeline_head_time, controlled_pipeline_head_time;
-	int controlled_previous_pipeline_head, uncontrolled_previous_pipeline_head;
-	unsigned long controlled_previous_head_time, uncontrolled_previous_head_time;
+	int pipeline_head_speed;
+	int controlled_pipeline_head_speed;
+	int uncontrolled_pipeline_head_speed;
+	int controlled_last_pipeline_head;
+	int uncontrolled_last_pipeline_head;
+	unsigned long uncontrolled_pipeline_head_time;
+	unsigned long controlled_pipeline_head_time;
+	int controlled_previous_pipeline_head;
+	int uncontrolled_previous_pipeline_head;
+	unsigned long controlled_previous_head_time;
+	unsigned long uncontrolled_previous_head_time;
 	int restart_speed_control_req;
 
         /*
@@ -1164,101 +1253,6 @@
 #define	IDETAPE_ERROR_EOD		103
 
 /*
- *	The ATAPI Status Register.
- */
-typedef union {
-	unsigned all			:8;
-	struct {
-		unsigned check		:1;	/* Error occurred */
-		unsigned idx		:1;	/* Reserved */
-		unsigned corr		:1;	/* Correctable error occurred */
-		unsigned drq		:1;	/* Data is request by the device */
-		unsigned dsc		:1;	/* Buffer availability / Media access command finished */
-		unsigned reserved5	:1;	/* Reserved */
-		unsigned drdy		:1;	/* Ignored for ATAPI commands (ready to accept ATA command) */
-		unsigned bsy		:1;	/* The device has access to the command block */
-	} b;
-} idetape_status_reg_t;
-
-/*
- *	The ATAPI error register.
- */
-typedef union {
-	unsigned all			:8;
-	struct {
-		unsigned ili		:1;	/* Illegal Length Indication */
-		unsigned eom		:1;	/* End Of Media Detected */
-		unsigned abrt		:1;	/* Aborted command - As defined by ATA */
-		unsigned mcr		:1;	/* Media Change Requested - As defined by ATA */
-		unsigned sense_key	:4;	/* Sense key of the last failed packet command */
-	} b;
-} idetape_error_reg_t;
-
-/*
- *	ATAPI Feature Register
- */
-typedef union {
-	unsigned all			:8;
-	struct {
-		unsigned dma		:1;	/* Using DMA or PIO */
-		unsigned reserved321	:3;	/* Reserved */
-		unsigned reserved654	:3;	/* Reserved (Tag Type) */
-		unsigned reserved7	:1;	/* Reserved */
-	} b;
-} idetape_feature_reg_t;
-
-/*
- *	ATAPI Byte Count Register.
- */
-typedef union {
-	unsigned all			:16;
-	struct {
-		unsigned low		:8;	/* LSB */
-		unsigned high		:8;	/* MSB */
-	} b;
-} idetape_bcount_reg_t;
-
-/*
- *	ATAPI Interrupt Reason Register.
- */
-typedef union {
-	unsigned all			:8;
-	struct {
-		unsigned cod		:1;	/* Information transferred is command (1) or data (0) */
-		unsigned io		:1;	/* The device requests us to read (1) or write (0) */
-		unsigned reserved	:6;	/* Reserved */
-	} b;
-} idetape_ireason_reg_t;
-
-/*
- *	ATAPI Drive Select Register
- */
-typedef union {	
-	unsigned all			:8;
-	struct {
-		unsigned sam_lun	:4;	/* Should be zero with ATAPI (not used) */
-		unsigned drv		:1;	/* The responding drive will be drive 0 (0) or drive 1 (1) */
-		unsigned one5		:1;	/* Should be set to 1 */
-		unsigned reserved6	:1;	/* Reserved */
-		unsigned one7		:1;	/* Should be set to 1 */
-	} b;
-} idetape_drivesel_reg_t;
-
-/*
- *	ATAPI Device Control Register
- */
-typedef union {			
-	unsigned all			:8;
-	struct {
-		unsigned zero0		:1;	/* Should be set to zero */
-		unsigned nien		:1;	/* Device interrupt is disabled (1) or enabled (0) */
-		unsigned srst		:1;	/* ATA software reset. ATAPI devices should use the new ATAPI srst. */
-		unsigned one3		:1;	/* Should be set to 1 */
-		unsigned reserved4567	:4;	/* Reserved */
-	} b;
-} idetape_control_reg_t;
-
-/*
  *	idetape_chrdev_t provides the link between out character device
  *	interface and our block device interface and the corresponding
  *	ide_drive_t structure.
@@ -1432,41 +1426,60 @@
  * DO NOT REMOVE, BUILDING A VERBOSE DEBUG SCHEME FOR ATAPI
  */
 
-char *idetape_sense_key_verbose (byte idetape_sense_key)
+char *idetape_sense_key_verbose (u8 idetape_sense_key)
 {
 	switch (idetape_sense_key) {
 		default: {
 			char buf[22];
-			sprintf(buf, "IDETAPE_SENSE (0x%02x)", idetape_sense_key);
+			sprintf(buf, "IDETAPE_SENSE (0x%02x)",
+				idetape_sense_key);
 			return(buf);
 		}
 
 	}
 }
 
-char *idetape_command_key_verbose (byte idetape_command_key)
+char *idetape_command_key_verbose (u8 idetape_command_key)
 {
 	switch (idetape_command_key) {
-		case IDETAPE_TEST_UNIT_READY_CMD:	return("TEST_UNIT_READY_CMD");
-		case IDETAPE_REWIND_CMD:		return("REWIND_CMD");
-		case IDETAPE_REQUEST_SENSE_CMD:		return("REQUEST_SENSE_CMD");
-		case IDETAPE_READ_CMD:			return("READ_CMD");
-		case IDETAPE_WRITE_CMD:			return("WRITE_CMD");
-		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_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");
-		case IDETAPE_PREVENT_CMD:		return("PREVENT_CMD");
-		case IDETAPE_LOCATE_CMD:		return("LOCATE_CMD");
-		case IDETAPE_READ_POSITION_CMD:		return("READ_POSITION_CMD");
-		case IDETAPE_READ_BUFFER_CMD:		return("READ_BUFFER_CMD");
-		case IDETAPE_SET_SPEED_CMD:		return("SET_SPEED_CMD");
+		case IDETAPE_TEST_UNIT_READY_CMD:
+			return("TEST_UNIT_READY_CMD");
+		case IDETAPE_REWIND_CMD:
+			return("REWIND_CMD");
+		case IDETAPE_REQUEST_SENSE_CMD:
+			return("REQUEST_SENSE_CMD");
+		case IDETAPE_READ_CMD:
+			return("READ_CMD");
+		case IDETAPE_WRITE_CMD:
+			return("WRITE_CMD");
+		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_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");
+		case IDETAPE_PREVENT_CMD:
+			return("PREVENT_CMD");
+		case IDETAPE_LOCATE_CMD:
+			return("LOCATE_CMD");
+		case IDETAPE_READ_POSITION_CMD:
+			return("READ_POSITION_CMD");
+		case IDETAPE_READ_BUFFER_CMD:
+			return("READ_BUFFER_CMD");
+		case IDETAPE_SET_SPEED_CMD:
+			return("SET_SPEED_CMD");
 		default: {
 				char buf[20];
-				sprintf(buf, "CMD (0x%02x)", idetape_command_key);
+				sprintf(buf, "CMD (0x%02x)",
+					idetape_command_key);
 				return(buf);
 			}
 	}
@@ -1482,13 +1495,13 @@
 static void idetape_write_release (struct inode *inode);
 
 /*
- *	Too bad. The drive wants to send us data which we are not ready to accept.
- *	Just throw it away.
+ * Too bad. The drive wants to send us data which we are not ready to accept.
+ * Just throw it away.
  */
 static void idetape_discard_data (ide_drive_t *drive, unsigned int bcount)
 {
 	while (bcount--)
-		IN_BYTE (IDE_DATA_REG);
+		(void) HWIF(drive)->INB(IDE_DATA_REG);
 }
 
 static void idetape_input_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsigned int bcount)
@@ -1499,13 +1512,14 @@
 	while (bcount) {
 #if IDETAPE_DEBUG_BUGS
 		if (bh == NULL) {
-			printk (KERN_ERR "ide-tape: bh == NULL in idetape_input_buffers\n");
-			idetape_discard_data (drive, bcount);
+			printk(KERN_ERR "ide-tape: bh == NULL in %s\n",
+				__FUNCTION__);
+			idetape_discard_data(drive, bcount);
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		count = IDE_MIN (bh->b_size - atomic_read(&bh->b_count), bcount);
-		atapi_input_bytes (drive, bh->b_data + atomic_read(&bh->b_count), count);
+		count = IDE_MIN(bh->b_size - atomic_read(&bh->b_count), bcount);
+		HWIF(drive)->atapi_input_bytes(drive, bh->b_data + atomic_read(&bh->b_count), count);
 		bcount -= count;
 		atomic_add(count, &bh->b_count);
 		if (atomic_read(&bh->b_count) == bh->b_size) {
@@ -1525,12 +1539,13 @@
 	while (bcount) {
 #if IDETAPE_DEBUG_BUGS
 		if (bh == NULL) {
-			printk (KERN_ERR "ide-tape: bh == NULL in idetape_output_buffers\n");
+			printk(KERN_ERR "ide-tape: bh == NULL in %s\n",
+				__FUNCTION__);
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		count = IDE_MIN (pc->b_count, bcount);
-		atapi_output_bytes (drive, pc->b_data, count);
+		count = IDE_MIN(pc->b_count, bcount);
+		HWIF(drive)->atapi_output_bytes(drive, pc->b_data, count);
 		bcount -= count;
 		pc->b_data += count;
 		pc->b_count -= count;
@@ -1550,16 +1565,17 @@
 	struct buffer_head *bh = pc->bh;
 	int count, bcount = pc->actually_transferred;
 
-	if (test_bit (PC_WRITING, &pc->flags))
+	if (test_bit(PC_WRITING, &pc->flags))
 		return;
 	while (bcount) {
 #if IDETAPE_DEBUG_BUGS
 		if (bh == NULL) {
-			printk (KERN_ERR "ide-tape: bh == NULL in idetape_update_buffers\n");
+			printk(KERN_ERR "ide-tape: bh == NULL in %s\n",
+				__FUNCTION__);
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		count = IDE_MIN (bh->b_size, bcount);
+		count = IDE_MIN(bh->b_size, bcount);
 		atomic_set(&bh->b_count, count);
 		if (atomic_read(&bh->b_count) == bh->b_size)
 			bh = bh->b_reqnext;
@@ -1581,9 +1597,10 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 5)
-		printk (KERN_INFO "ide-tape: pc_stack_index=%d\n",tape->pc_stack_index);
+		printk(KERN_INFO "ide-tape: pc_stack_index=%d\n",
+			tape->pc_stack_index);
 #endif /* IDETAPE_DEBUG_LOG */
-	if (tape->pc_stack_index==IDETAPE_PC_STACK)
+	if (tape->pc_stack_index == IDETAPE_PC_STACK)
 		tape->pc_stack_index=0;
 	return (&tape->pc_stack[tape->pc_stack_index++]);
 }
@@ -1607,9 +1624,10 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 5)
-		printk (KERN_INFO "ide-tape: rq_stack_index=%d\n",tape->rq_stack_index);
+		printk(KERN_INFO "ide-tape: rq_stack_index=%d\n",
+			tape->rq_stack_index);
 #endif /* IDETAPE_DEBUG_LOG */
-	if (tape->rq_stack_index==IDETAPE_PC_STACK)
+	if (tape->rq_stack_index == IDETAPE_PC_STACK)
 		tape->rq_stack_index=0;
 	return (&tape->rq_stack[tape->rq_stack_index++]);
 }
@@ -1619,7 +1637,7 @@
  */
 static void idetape_init_pc (idetape_pc_t *pc)
 {
-	memset (pc->c, 0, 12);
+	memset(pc->c, 0, 12);
 	pc->retries = 0;
 	pc->flags = 0;
 	pc->request_transfer = 0;
@@ -1649,19 +1667,23 @@
 	 *	give up retrying.
 	 */
 	if (tape->debug_level >= 1)
-		printk (KERN_INFO "ide-tape: pc = %x, sense key = %x, asc = %x, ascq = %x\n",
-				pc->c[0], result->sense_key, result->asc, result->ascq);
+		printk(KERN_INFO "ide-tape: pc = %x, sense key = %x, "
+			"asc = %x, ascq = %x\n",
+			pc->c[0], result->sense_key,
+			result->asc, result->ascq);
 #if IDETAPE_DEBUG_LOG_VERBOSE
 	if (tape->debug_level >= 1)
-		printk (KERN_INFO "ide-tape: pc = %s, sense key = %x, asc = %x, ascq = %x\n",
-			idetape_command_key_verbose((byte) pc->c[0]),
+		printk (KERN_INFO "ide-tape: pc = %s, sense key = %x, "
+			"asc = %x, ascq = %x\n",
+			idetape_command_key_verbose((u8) pc->c[0]),
 			result->sense_key,
 			result->asc,
 			result->ascq);
 #endif /* IDETAPE_DEBUG_LOG_VERBOSE */
 #endif /* IDETAPE_DEBUG_LOG */
 
-	if (tape->onstream && result->sense_key == 2 && result->asc == 0x53 && result->ascq == 2) {
+	if (tape->onstream && result->sense_key == 2 &&
+	    result->asc == 0x53 && result->ascq == 2) {
 		clear_bit(PC_DMA_ERROR, &pc->flags);
 		ide_stall_queue(drive, HZ / 2);
 		return;
@@ -1671,49 +1693,33 @@
 	/*
 	 *	Correct pc->actually_transferred by asking the tape.
 	 */
-	if (test_bit (PC_DMA_ERROR, &pc->flags)) {
-		pc->actually_transferred = pc->request_transfer - tape->tape_block_size * ntohl (get_unaligned (&result->information));
-		idetape_update_buffers (pc);
+	if (test_bit(PC_DMA_ERROR, &pc->flags)) {
+		pc->actually_transferred = pc->request_transfer - tape->tape_block_size * ntohl(get_unaligned (&result->information));
+		idetape_update_buffers(pc);
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 	if (pc->c[0] == IDETAPE_READ_CMD && result->filemark) {
 		pc->error = IDETAPE_ERROR_FILEMARK;
-		set_bit (PC_ABORT, &pc->flags);
+		set_bit(PC_ABORT, &pc->flags);
 	}
 	if (pc->c[0] == IDETAPE_WRITE_CMD) {
-		if (result->eom || (result->sense_key == 0xd && result->asc == 0x0 && result->ascq == 0x2)) {
+		if (result->eom || (result->sense_key == 0xd &&
+		    result->asc == 0x0 && result->ascq == 0x2)) {
 			pc->error = IDETAPE_ERROR_EOD;
-			set_bit (PC_ABORT, &pc->flags);
+			set_bit(PC_ABORT, &pc->flags);
 		}
 	}
 	if (pc->c[0] == IDETAPE_READ_CMD || pc->c[0] == IDETAPE_WRITE_CMD) {
 		if (result->sense_key == 8) {
 			pc->error = IDETAPE_ERROR_EOD;
-			set_bit (PC_ABORT, &pc->flags);
+			set_bit(PC_ABORT, &pc->flags);
 		}
-		if (!test_bit (PC_ABORT, &pc->flags) && (tape->onstream || pc->actually_transferred))
+		if (!test_bit(PC_ABORT, &pc->flags) &&
+		    (tape->onstream || pc->actually_transferred))
 			pc->retries = IDETAPE_MAX_PC_RETRIES + 1;
 	}
 }
 
-static void idetape_abort_pipeline (ide_drive_t *drive)
-{
-	idetape_tape_t *tape = drive->driver_data;
-	idetape_stage_t *stage = tape->next_stage;
-
-#if IDETAPE_DEBUG_LOG
-	if (tape->debug_level >= 4)
-		printk(KERN_INFO "ide-tape: %s: idetape_abort_pipeline called\n", tape->name);
-#endif
-	while (stage) {
-		if (stage->rq.cmd == IDETAPE_WRITE_RQ)
-			stage->rq.cmd = IDETAPE_ABORTED_WRITE_RQ;
-		else if (stage->rq.cmd == IDETAPE_READ_RQ)
-			stage->rq.cmd = IDETAPE_ABORTED_READ_RQ;
-		stage = stage->next;
-	}
-}
-
 /*
  *	idetape_active_next_stage will declare the next stage as "active".
  */
@@ -1725,11 +1731,12 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_active_next_stage\n");
+		printk(KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 #if IDETAPE_DEBUG_BUGS
 	if (stage == NULL) {
-		printk (KERN_ERR "ide-tape: bug: Trying to activate a non existing stage\n");
+		printk(KERN_ERR "ide-tape: bug: Trying to activate a "
+			"non existing stage\n");
 		return;
 	}
 #endif /* IDETAPE_DEBUG_BUGS */	
@@ -1755,10 +1762,10 @@
 	
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_increase_max_pipeline_stages\n");
+		printk (KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 
-	tape->max_stages += increase;
+	tape->max_stages += IDE_MAX(increase, 1);
 	tape->max_stages = IDE_MAX(tape->max_stages, tape->min_pipeline);
 	tape->max_stages = IDE_MIN(tape->max_stages, tape->max_pipeline);
 }
@@ -1776,21 +1783,21 @@
 		if (bh->b_data != NULL) {
 			size = (int) bh->b_size;
 			while (size > 0) {
-				free_page ((unsigned long) bh->b_data);
+				free_page((unsigned long) bh->b_data);
 				size -= PAGE_SIZE;
 				bh->b_data += PAGE_SIZE;
 			}
 		}
 		prev_bh = bh;
 		bh = bh->b_reqnext;
-		kfree (prev_bh);
+		kfree(prev_bh);
 	}
-	kfree (stage);
+	kfree(stage);
 }
 
 static void idetape_kfree_stage (idetape_tape_t *tape, idetape_stage_t *stage)
 {
-	__idetape_kfree_stage (stage);
+	__idetape_kfree_stage(stage);
 }
 
 /*
@@ -1804,45 +1811,72 @@
 	
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_remove_stage_head\n");
+		printk(KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 #if IDETAPE_DEBUG_BUGS
 	if (tape->first_stage == NULL) {
-		printk (KERN_ERR "ide-tape: bug: tape->first_stage is NULL\n");
+		printk(KERN_ERR "ide-tape: bug: tape->first_stage is NULL\n");
 		return;		
 	}
 	if (tape->active_stage == tape->first_stage) {
-		printk (KERN_ERR "ide-tape: bug: Trying to free our active pipeline stage\n");
+		printk(KERN_ERR "ide-tape: bug: Trying to free our "
+			"active pipeline stage\n");
 		return;
 	}
 #endif /* IDETAPE_DEBUG_BUGS */
 	stage = tape->first_stage;
 	tape->first_stage = stage->next;
-	idetape_kfree_stage (tape, stage);
+	idetape_kfree_stage(tape, stage);
 	tape->nr_stages--;
 	if (tape->first_stage == NULL) {
 		tape->last_stage = NULL;
 #if IDETAPE_DEBUG_BUGS
 		if (tape->next_stage != NULL)
-			printk (KERN_ERR "ide-tape: bug: tape->next_stage != NULL\n");
+			printk(KERN_ERR "ide-tape: bug: "
+				"tape->next_stage != NULL\n");
 		if (tape->nr_stages)
-			printk (KERN_ERR "ide-tape: bug: nr_stages should be 0 now\n");
+			printk(KERN_ERR "ide-tape: bug: nr_stages should "
+				"be 0 now\n");
 #endif /* IDETAPE_DEBUG_BUGS */
 	}
 }
 
+static void idetape_abort_pipeline (ide_drive_t *drive, idetape_stage_t *last_stage)
+{
+	idetape_tape_t *tape = drive->driver_data;
+	idetape_stage_t *stage = tape->next_stage;
+	idetape_stage_t *nstage;
+
+#if IDETAPE_DEBUG_LOG
+	if (tape->debug_level >= 4)
+		printk(KERN_INFO "ide-tape: %s: %s called\n",
+			tape->name, __FUNCTION__);
+#endif
+	while (stage) {
+		nstage = stage->next;
+		idetape_kfree_stage(tape, stage);
+		--tape->nr_stages;
+		--tape->nr_pending_stages;
+		stage = nstage;
+	}
+	tape->last_stage = last_stage;
+	if (last_stage)
+		last_stage->next = NULL;
+	tape->next_stage = NULL;
+}
+
 /*
  *	idetape_end_request is used to finish servicing a request, and to
  *	insert a pending pipeline request into the main device queue.
  */
-static void idetape_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
+static int idetape_end_request (ide_drive_t *drive, int uptodate)
 {
-	ide_drive_t *drive = hwgroup->drive;
-	struct request *rq = hwgroup->rq;
+	struct request *rq = HWGROUP(drive)->rq;
 	idetape_tape_t *tape = drive->driver_data;
 	unsigned long flags;
 	int error;
 	int remove_stage = 0;
+	idetape_stage_t *active_stage;
 #if ONSTREAM_DEBUG
 	idetape_stage_t *stage;
 	os_aux_t *aux;
@@ -1851,7 +1885,7 @@
 
 #if IDETAPE_DEBUG_LOG
         if (tape->debug_level >= 4)
-	printk (KERN_INFO "ide-tape: Reached idetape_end_request\n");
+		printk (KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 
 	switch (uptodate) {
@@ -1864,7 +1898,9 @@
 		tape->failed_pc = NULL;
 
 	spin_lock_irqsave(&tape->spinlock, flags);
-	if (tape->active_data_request == rq) {		/* The request was a pipelined data transfer request */
+	if (tape->active_data_request == rq) {
+		/* The request was a pipelined data transfer request */
+		active_stage = tape->active_stage;
 		tape->active_stage = NULL;
 		tape->active_data_request = NULL;
 		tape->nr_pending_stages--;
@@ -1884,34 +1920,40 @@
 				if (tape->first_frame_position == OS_DATA_ENDFRAME1) { 
 #if ONSTREAM_DEBUG
 					if (tape->debug_level >= 2)
-						printk("ide-tape: %s: skipping over config parition..\n", tape->name);
+						printk("ide-tape: %s: skipping over config partition.\n", tape->name);
 #endif
 					tape->onstream_write_error = OS_PART_ERROR;
-					if (tape->waiting)
+					if (tape->waiting) {
+						rq->waiting = NULL;
 						complete(tape->waiting);
+					}
 				}
 			}
 			remove_stage = 1;
 			if (error) {
-				set_bit (IDETAPE_PIPELINE_ERROR, &tape->flags);
+				set_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 				if (error == IDETAPE_ERROR_EOD)
-					idetape_abort_pipeline (drive);
-				if (tape->onstream && !tape->raw && error == IDETAPE_ERROR_GENERAL && tape->sense.sense_key == 3) {
-					clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags);
+					idetape_abort_pipeline(drive, active_stage);
+				if (tape->onstream && !tape->raw &&
+				    error == IDETAPE_ERROR_GENERAL &&
+				    tape->sense.sense_key == 3) {
+					clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 					printk(KERN_ERR "ide-tape: %s: write error, enabling error recovery\n", tape->name);
 					tape->onstream_write_error = OS_WRITE_ERROR;
 					remove_stage = 0;
 					tape->nr_pending_stages++;
 					tape->next_stage = tape->first_stage;
 					rq->current_nr_sectors = rq->nr_sectors;
-					if (tape->waiting)
+					if (tape->waiting) {
+						rq->waiting = NULL;
 						complete(tape->waiting);
+					}
 				}
 			}
 		} else if (rq->cmd == IDETAPE_READ_RQ) {
 			if (error == IDETAPE_ERROR_EOD) {
-				set_bit (IDETAPE_PIPELINE_ERROR, &tape->flags);
-				idetape_abort_pipeline(drive);
+				set_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
+				idetape_abort_pipeline(drive, active_stage);
 			}
 		}
 		if (tape->next_stage != NULL && !tape->onstream_write_error) {
@@ -1920,18 +1962,19 @@
 			/*
 			 *	Insert the next request into the request queue.
 			 */
-			(void) ide_do_drive_cmd (drive, tape->active_data_request, ide_end);
+			(void) ide_do_drive_cmd(drive, tape->active_data_request, ide_end);
 		} else if (!error) {
 			if (!tape->onstream)
-				idetape_increase_max_pipeline_stages (drive);
+				idetape_increase_max_pipeline_stages(drive);
 		}
 	}
-	ide_end_drive_cmd (drive, 0, 0);
+	ide_end_drive_cmd(drive, 0, 0);
 	if (remove_stage)
-		idetape_remove_stage_head (drive);
+		idetape_remove_stage_head(drive);
 	if (tape->active_data_request == NULL)
 		clear_bit(IDETAPE_PIPELINE_ACTIVE, &tape->flags);
 	spin_unlock_irqrestore(&tape->spinlock, flags);
+	return 0;
 }
 
 static ide_startstop_t idetape_request_sense_callback (ide_drive_t *drive)
@@ -1940,24 +1983,25 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_request_sense_callback\n");
+		printk(KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 	if (!tape->pc->error) {
-		idetape_analyze_error (drive, (idetape_request_sense_result_t *) tape->pc->buffer);
-		idetape_end_request (1, HWGROUP (drive));
+		idetape_analyze_error(drive, (idetape_request_sense_result_t *) tape->pc->buffer);
+		idetape_end_request(drive, 1);
 	} else {
-		printk (KERN_ERR "ide-tape: Error in REQUEST SENSE itself - Aborting request!\n");
-		idetape_end_request (0, HWGROUP (drive));
+		printk(KERN_ERR "ide-tape: Error in REQUEST SENSE "
+			"itself - Aborting request!\n");
+		idetape_end_request(drive, 0);
 	}
 	return ide_stopped;
 }
 
 static void idetape_create_request_sense_cmd (idetape_pc_t *pc)
 {
-	idetape_init_pc (pc);	
+	idetape_init_pc(pc);	
 	pc->c[0] = IDETAPE_REQUEST_SENSE_CMD;
 	pc->c[4] = 20;
-	pc->request_transfer = 18;
+	pc->request_transfer = 20;
 	pc->callback = &idetape_request_sense_callback;
 }
 
@@ -1982,10 +2026,10 @@
  */
 static void idetape_queue_pc_head (ide_drive_t *drive,idetape_pc_t *pc,struct request *rq)
 {
-	ide_init_drive_cmd (rq);
+	ide_init_drive_cmd(rq);
 	rq->buffer = (char *) pc;
 	rq->cmd = IDETAPE_PC_RQ1;
-	(void) ide_do_drive_cmd (drive, rq, ide_preempt);
+	(void) ide_do_drive_cmd(drive, rq, ide_preempt);
 }
 
 /*
@@ -1998,14 +2042,14 @@
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_pc_t *pc;
 	struct request *rq;
-	idetape_error_reg_t error;
+	atapi_error_t error;
 
-	error.all = IN_BYTE (IDE_ERROR_REG);
+	error.all = HWIF(drive)->INB(IDE_ERROR_REG);
 	pc = idetape_next_pc_storage (drive);
 	rq = idetape_next_rq_storage (drive);
-	idetape_create_request_sense_cmd (pc);
-	set_bit (IDETAPE_IGNORE_DSC, &tape->flags);
-	idetape_queue_pc_head (drive, pc, rq);
+	idetape_create_request_sense_cmd(pc);
+	set_bit(IDETAPE_IGNORE_DSC, &tape->flags);
+	idetape_queue_pc_head(drive, pc, rq);
 	return ide_stopped;
 }
 
@@ -2037,9 +2081,9 @@
 static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
-	idetape_status_reg_t status;
-	idetape_bcount_reg_t bcount;
-	idetape_ireason_reg_t ireason;
+	atapi_status_t status;
+	atapi_bcount_t bcount;
+	atapi_ireason_t ireason;
 	idetape_pc_t *pc = tape->pc;
 
 	unsigned int temp;
@@ -2050,14 +2094,16 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_pc_intr interrupt handler\n");
+		printk(KERN_INFO "ide-tape: Reached idetape_pc_intr "
+				"interrupt handler\n");
 #endif /* IDETAPE_DEBUG_LOG */	
 
-	status.all = GET_STAT();					/* Clear the interrupt */
+	/* Clear the interrupt */
+	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (test_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
-		if (HWIF(drive)->dmaproc(ide_dma_end, drive)) {
+	if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
+		if (HWIF(drive)->ide_dma_end(drive) || status.b.check) {
 			/*
 			 * A DMA error is sometimes expected. For example,
 			 * if the tape is crossing a filemark during a
@@ -2069,8 +2115,18 @@
 			 * actually transferred (we can't receive that
 			 * information from the DMA engine on most chipsets).
 			 */
+
+			/*
+			 * On the contrary, a DMA error is never expected;
+			 * it usually indicates a hardware error or abort.
+			 * If the tape crosses a filemark during a READ
+			 * command, it will issue an irq and position itself
+			 * after the filemark (not before). Only a partial
+			 * data transfer will occur, but no DMA error.
+			 * (AS, 19 Apr 2001)
+			 */
 			set_bit (PC_DMA_ERROR, &pc->flags);
-		} else if (!status.b.check) {
+		} else {
 			pc->actually_transferred = pc->request_transfer;
 			idetape_update_buffers (pc);
 		}
@@ -2081,106 +2137,139 @@
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
-	if (!status.b.drq) {						/* No more interrupts */
+	if (!status.b.drq) {			/* No more interrupts */
 		cmd_time = (jiffies - tape->cmd_start_time) * 1000 / HZ;
 		tape->max_cmd_time = IDE_MAX(cmd_time, tape->max_cmd_time);
 #if IDETAPE_DEBUG_LOG
 		if (tape->debug_level >= 2)
-			printk (KERN_INFO "ide-tape: Packet command completed, %d bytes transferred\n", pc->actually_transferred);
+			printk(KERN_INFO "ide-tape: Packet command completed, "
+				"%d bytes transferred\n",
+				pc->actually_transferred);
 #endif /* IDETAPE_DEBUG_LOG */
-		clear_bit (PC_DMA_IN_PROGRESS, &pc->flags);
+		clear_bit(PC_DMA_IN_PROGRESS, &pc->flags);
 
-		ide__sti();	/* local CPU only */
+		local_irq_enable();
 
 #if SIMULATE_ERRORS
-		if ((pc->c[0] == IDETAPE_WRITE_CMD || pc->c[0] == IDETAPE_READ_CMD) && (++error_sim_count % 100) == 0) {
-			printk(KERN_INFO "ide-tape: %s: simulating error\n", tape->name);
+		if ((pc->c[0] == IDETAPE_WRITE_CMD ||
+		     pc->c[0] == IDETAPE_READ_CMD) &&
+		    (++error_sim_count % 100) == 0) {
+			printk(KERN_INFO "ide-tape: %s: simulating error\n",
+				tape->name);
 			status.b.check = 1;
 		}
 #endif
 		if (status.b.check && pc->c[0] == IDETAPE_REQUEST_SENSE_CMD)
 			status.b.check = 0;
-		if (status.b.check || test_bit (PC_DMA_ERROR, &pc->flags)) {	/* Error detected */
-#if IDETAPE_DEBUG_LOG
-			if (tape->debug_level >= 1)
-				printk (KERN_INFO "ide-tape: %s: I/O error, ",tape->name);
-#endif /* IDETAPE_DEBUG_LOG */
+		if (status.b.check || test_bit(PC_DMA_ERROR, &pc->flags)) {
+			/* Error detected */
 			if (pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
-				printk (KERN_ERR "ide-tape: I/O error in request sense command\n");
-				return ide_do_reset (drive);
+				printk(KERN_ERR "ide-tape: I/O error in "
+					"request sense command\n");
+				return ide_do_reset(drive);
 			}
 #if IDETAPE_DEBUG_LOG
 			if (tape->debug_level >= 1)
-				printk(KERN_INFO "ide-tape: [cmd %x]: check condition\n", pc->c[0]);
+				printk(KERN_INFO "ide-tape: [cmd %x]: check "
+					"condition\n", pc->c[0]);
 #endif
-			return idetape_retry_pc (drive);				/* Retry operation */
+			/* Retry operation */
+			return idetape_retry_pc(drive);
 		}
 		pc->error = 0;
-		if (!tape->onstream && test_bit (PC_WAIT_FOR_DSC, &pc->flags) && !status.b.dsc) {	/* Media access command */
+		if (!tape->onstream &&
+		    test_bit(PC_WAIT_FOR_DSC, &pc->flags) &&
+		    !status.b.dsc) {
+			/* Media access command */
 			tape->dsc_polling_start = jiffies;
 			tape->dsc_polling_frequency = IDETAPE_DSC_MA_FAST;
 			tape->dsc_timeout = jiffies + IDETAPE_DSC_MA_TIMEOUT;
-			idetape_postpone_request (drive);		/* Allow ide.c to handle other requests */
+			/* Allow ide.c to handle other requests */
+			idetape_postpone_request(drive);
 			return ide_stopped;
 		}
 		if (tape->failed_pc == pc)
 			tape->failed_pc = NULL;
-		return pc->callback(drive);			/* Command finished - Call the callback function */
+		/* Command finished - Call the callback function */
+		return pc->callback(drive);
 	}
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
-		printk (KERN_ERR "ide-tape: The tape wants to issue more interrupts in DMA mode\n");
-		printk (KERN_ERR "ide-tape: DMA disabled, reverting to PIO\n");
-		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
-		return ide_do_reset (drive);
+	if (test_and_clear_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
+		printk(KERN_ERR "ide-tape: The tape wants to issue more "
+				"interrupts in DMA mode\n");
+		printk(KERN_ERR "ide-tape: DMA disabled, reverting to PIO\n");
+		(void) HWIF(drive)->ide_dma_off(drive);
+		return ide_do_reset(drive);
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
-	bcount.b.high = IN_BYTE (IDE_BCOUNTH_REG);			/* Get the number of bytes to transfer */
-	bcount.b.low  = IN_BYTE (IDE_BCOUNTL_REG);			/* on this interrupt */
-	ireason.all   = IN_BYTE (IDE_IREASON_REG);
+	/* Get the number of bytes to transfer */
+	bcount.b.high	= HWIF(drive)->INB(IDE_BCOUNTH_REG);
+	bcount.b.low	= HWIF(drive)->INB(IDE_BCOUNTL_REG);
+	/* on this interrupt */
+	ireason.all	= HWIF(drive)->INB(IDE_IREASON_REG);
 
 	if (ireason.b.cod) {
-		printk (KERN_ERR "ide-tape: CoD != 0 in idetape_pc_intr\n");
-		return ide_do_reset (drive);
+		printk(KERN_ERR "ide-tape: CoD != 0 in idetape_pc_intr\n");
+		return ide_do_reset(drive);
 	}
-	if (ireason.b.io == test_bit (PC_WRITING, &pc->flags)) {	/* Hopefully, we will never get here */
-		printk (KERN_ERR "ide-tape: We wanted to %s, ", ireason.b.io ? "Write":"Read");
-		printk (KERN_ERR "ide-tape: but the tape wants us to %s !\n",ireason.b.io ? "Read":"Write");
-		return ide_do_reset (drive);
+	if (ireason.b.io == test_bit(PC_WRITING, &pc->flags)) {
+		/* Hopefully, we will never get here */
+		printk(KERN_ERR "ide-tape: We wanted to %s, ",
+			ireason.b.io ? "Write":"Read");
+		printk(KERN_ERR "ide-tape: but the tape wants us to %s !\n",
+			ireason.b.io ? "Read":"Write");
+		return ide_do_reset(drive);
 	}
-	if (!test_bit (PC_WRITING, &pc->flags)) {			/* Reading - Check that we have enough space */
+	if (!test_bit(PC_WRITING, &pc->flags)) {
+		/* Reading - Check that we have enough space */
 		temp = pc->actually_transferred + bcount.all;
-		if ( temp > pc->request_transfer) {
+		if (temp > pc->request_transfer) {
 			if (temp > pc->buffer_size) {
-				printk (KERN_ERR "ide-tape: The tape wants to send us more data than expected - discarding data\n");
-				idetape_discard_data (drive, bcount.all);
-				ide_set_handler (drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
+				printk(KERN_ERR "ide-tape: The tape wants to "
+					"send us more data than expected "
+					"- discarding data\n");
+				idetape_discard_data(drive, bcount.all);
+				if (HWGROUP(drive)->handler != NULL)
+					BUG();
+				ide_set_handler(drive,
+						&idetape_pc_intr,
+						IDETAPE_WAIT_CMD,
+						NULL);
 				return ide_started;
 			}
 #if IDETAPE_DEBUG_LOG
 			if (tape->debug_level >= 2)
-				printk (KERN_NOTICE "ide-tape: The tape wants to send us more data than expected - allowing transfer\n");
+				printk(KERN_NOTICE "ide-tape: The tape wants "
+					"to send us more data than expected "
+					"- allowing transfer\n");
 #endif /* IDETAPE_DEBUG_LOG */
 		}
 	}
-	if (test_bit (PC_WRITING, &pc->flags)) {
+	if (test_bit(PC_WRITING, &pc->flags)) {
 		if (pc->bh != NULL)
-			idetape_output_buffers (drive, pc, bcount.all);
+			idetape_output_buffers(drive, pc, bcount.all);
 		else
-			atapi_output_bytes (drive,pc->current_position,bcount.all);	/* Write the current buffer */
+			/* Write the current buffer */
+			HWIF(drive)->atapi_output_bytes(drive,pc->current_position,bcount.all);
 	} else {
 		if (pc->bh != NULL)
-			idetape_input_buffers (drive, pc, bcount.all);
+			idetape_input_buffers(drive, pc, bcount.all);
 		else
-			atapi_input_bytes (drive,pc->current_position,bcount.all);	/* Read the current buffer */
+			/* Read the current buffer */
+			HWIF(drive)->atapi_input_bytes(drive,pc->current_position,bcount.all);
 	}
-	pc->actually_transferred += bcount.all;					/* Update the current position */
-	pc->current_position+=bcount.all;
+	/* Update the current position */
+	pc->actually_transferred += bcount.all;
+	pc->current_position += bcount.all;
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 2)
-		printk(KERN_INFO "ide-tape: [cmd %x] transferred %d bytes on that interrupt\n", pc->c[0], bcount.all);
+		printk(KERN_INFO "ide-tape: [cmd %x] done %d\n"
+			pc->c[0], bcount.all);
 #endif
-	ide_set_handler (drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);	/* And set the interrupt handler again */
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	/* And set the interrupt handler again */
+	ide_set_handler (drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
 	return ide_started;
 }
 
@@ -2217,9 +2306,9 @@
  *
  *	4.	When the packet command is finished, it will be checked for errors.
  *
- *	5.	In case an error was found, we queue a request sense packet command
- *		in front of the request queue and retry the operation up to
- *		IDETAPE_MAX_PC_RETRIES times.
+ *	5.	In case an error was found, we queue a request sense packet
+ *		command in front of the request queue and retry the operation
+ *		upto IDETAPE_MAX_PC_RETRIES times.
  *
  *	6.	In case no error was found, or we decided to give up and not
  *		to retry again, the callback function will be called and then
@@ -2230,108 +2319,147 @@
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_pc_t *pc = tape->pc;
-	idetape_ireason_reg_t ireason;
+	atapi_ireason_t ireason;
 	int retries = 100;
 	ide_startstop_t startstop;
 
-	if (ide_wait_stat (&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
-		printk (KERN_ERR "ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n");
+	if (ide_wait_stat(&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
+		printk(KERN_ERR "ide-tape: Strange, packet command "
+			"initiated yet DRQ isn't asserted\n");
 		return startstop;
 	}
-	ireason.all = IN_BYTE (IDE_IREASON_REG);
+	ireason.all = HWIF(drive)->INB(IDE_IREASON_REG);
 	while (retries-- && (!ireason.b.cod || ireason.b.io)) {
-		printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while issuing a packet command, retrying\n");
+		printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while issuing "
+				"a packet command, retrying\n");
 		udelay(100);
-		ireason.all = IN_BYTE(IDE_IREASON_REG);
+		ireason.all = HWIF(drive)->INB(IDE_IREASON_REG);
 		if (retries == 0) {
-			printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while issuing a packet command, ignoring\n");
+			printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while "
+					"issuing a packet command, ignoring\n");
 			ireason.b.cod = 1;
 			ireason.b.io = 0;
 		}
 	}
 	if (!ireason.b.cod || ireason.b.io) {
-		printk (KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing a packet command\n");
-		return ide_do_reset (drive);
+		printk(KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing "
+				"a packet command\n");
+		return ide_do_reset(drive);
 	}
 	tape->cmd_start_time = jiffies;
-	ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);	/* Set the interrupt routine */
-	atapi_output_bytes (drive,pc->c,12);			/* Send the actual packet */
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
+	/* Set the interrupt routine */
+	ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	/* Begin DMA, if necessary */
+	if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags))
+		(void) (HWIF(drive)->ide_dma_begin(drive));
+#endif
+	/* Send the actual packet */
+	HWIF(drive)->atapi_output_bytes(drive, pc->c, 12);
 	return ide_started;
 }
 
 static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape_pc_t *pc)
 {
 	idetape_tape_t *tape = drive->driver_data;
-	idetape_bcount_reg_t bcount;
-	int dma_ok = 0;
+	atapi_feature_t feature;
+	atapi_bcount_t bcount;
 
 #if IDETAPE_DEBUG_BUGS
-	if (tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD && pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
-		printk (KERN_ERR "ide-tape: possible ide-tape.c bug - Two request sense in serial were issued\n");
+	if (tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD &&
+	    pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
+		printk(KERN_ERR "ide-tape: possible ide-tape.c bug - "
+			"Two request sense in serial were issued\n");
 	}
 #endif /* IDETAPE_DEBUG_BUGS */
 
 	if (tape->failed_pc == NULL && pc->c[0] != IDETAPE_REQUEST_SENSE_CMD)
 		tape->failed_pc = pc;
-	tape->pc = pc;							/* Set the current packet command */
+	/* Set the current packet command */
+	tape->pc = pc;
 
-	if (pc->retries > IDETAPE_MAX_PC_RETRIES || test_bit (PC_ABORT, &pc->flags)) {
+	if (pc->retries > IDETAPE_MAX_PC_RETRIES ||
+	    test_bit(PC_ABORT, &pc->flags)) {
 		/*
 		 *	We will "abort" retrying a packet command in case
 		 *	a legitimate error code was received (crossing a
-		 *	filemark, or DMA error in the end of media, for
-		 *	example).
+		 *	filemark, or end of the media, for example).
 		 */
 		if (!test_bit (PC_ABORT, &pc->flags)) {
-			if (!(pc->c[0] == IDETAPE_TEST_UNIT_READY_CMD && tape->sense_key == 2 &&
-			      tape->asc == 4 && (tape->ascq == 1 || tape->ascq == 8))) {
-				printk (KERN_ERR "ide-tape: %s: I/O error, pc = %2x, key = %2x, asc = %2x, ascq = %2x\n",
-					tape->name, pc->c[0], tape->sense_key, tape->asc, tape->ascq);
-				if (tape->onstream && pc->c[0] == IDETAPE_READ_CMD && tape->sense_key == 3 && tape->asc == 0x11)  /* AJN-1: 11 should be 0x11 */
+			if (!(pc->c[0] == IDETAPE_TEST_UNIT_READY_CMD &&
+			      tape->sense_key == 2 && tape->asc == 4 &&
+			     (tape->ascq == 1 || tape->ascq == 8))) {
+				printk(KERN_ERR "ide-tape: %s: I/O error, "
+						"pc = %2x, key = %2x, "
+						"asc = %2x, ascq = %2x\n",
+						tape->name, pc->c[0],
+						tape->sense_key, tape->asc,
+						tape->ascq);
+				if (tape->onstream &&
+				    pc->c[0] == IDETAPE_READ_CMD &&
+				    tape->sense_key == 3 &&
+				    tape->asc == 0x11)
+					/* AJN-1: 11 should be 0x11 */
 					printk(KERN_ERR "ide-tape: %s: enabling read error recovery\n", tape->name);
 			}
-			pc->error = IDETAPE_ERROR_GENERAL;		/* Giving up */
+			/* Giving up */
+			pc->error = IDETAPE_ERROR_GENERAL;
 		}
 		tape->failed_pc = NULL;
 		return pc->callback(drive);
 	}
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 2)
-		printk (KERN_INFO "ide-tape: Retry number - %d\n", pc->retries);
+		printk(KERN_INFO "ide-tape: Retry number - %d, cmd = %02X\n",
+				pc->retries, pc->c[0]);
 #endif /* IDETAPE_DEBUG_LOG */
 
 	pc->retries++;
-	pc->actually_transferred = 0;					/* We haven't transferred any data yet */
-	pc->current_position=pc->buffer;
-	bcount.all=pc->request_transfer;				/* Request to transfer the entire buffer at once */
+	/* We haven't transferred any data yet */
+	pc->actually_transferred = 0;
+	pc->current_position = pc->buffer;
+	/* Request to transfer the entire buffer at once */
+	bcount.all = pc->request_transfer;
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
-		printk (KERN_WARNING "ide-tape: DMA disabled, reverting to PIO\n");
-		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
+	if (test_and_clear_bit(PC_DMA_ERROR, &pc->flags)) {
+		printk(KERN_WARNING "ide-tape: DMA disabled, "
+				"reverting to PIO\n");
+		(void) HWIF(drive)->ide_dma_off(drive);
+	}
+	if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma) {
+		if (test_bit(PC_WRITING, &pc->flags)) {
+			feature.b.dma = !HWIF(drive)->ide_dma_write(drive);
+		} else {
+			feature.b.dma = !HWIF(drive)->ide_dma_read(drive);
+		}
 	}
-	if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
-		dma_ok = !HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
 	if (IDE_CONTROL_REG)
-		OUT_BYTE (drive->ctl, IDE_CONTROL_REG);
-	OUT_BYTE (dma_ok ? 1 : 0,    IDE_FEATURE_REG);			/* Use PIO/DMA */
-	OUT_BYTE (bcount.b.high,     IDE_BCOUNTH_REG);
-	OUT_BYTE (bcount.b.low,      IDE_BCOUNTL_REG);
-	OUT_BYTE (drive->select.all, IDE_SELECT_REG);
+		HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);
+	/* Use PIO/DMA */
+	HWIF(drive)->OUTB(feature.all, IDE_FEATURE_REG);
+	HWIF(drive)->OUTB(bcount.b.high, IDE_BCOUNTH_REG);
+	HWIF(drive)->OUTB(bcount.b.low, IDE_BCOUNTL_REG);
+	HWIF(drive)->OUTB(drive->select.all, IDE_SELECT_REG);
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (dma_ok) {						/* Begin DMA, if necessary */
-		set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
-		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
-	}
+	if (feature.b.dma)		/* Will begin DMA later */
+		set_bit(PC_DMA_IN_PROGRESS, &pc->flags);
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 	if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
-		ide_set_handler(drive, &idetape_transfer_pc, IDETAPE_WAIT_CMD, NULL);
-		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
+		if (HWGROUP(drive)->handler != NULL)
+			BUG();
+		ide_set_handler(drive,
+				&idetape_transfer_pc,
+				IDETAPE_WAIT_CMD,
+				NULL);
+		HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG);
 		return ide_started;
 	} else {
-		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
+		HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG);
 		return idetape_transfer_pc(drive);
 	}
 }
@@ -2348,22 +2476,22 @@
 		printk (KERN_INFO "ide-tape: Reached idetape_pc_callback\n");
 #endif /* IDETAPE_DEBUG_LOG */
 
-	idetape_end_request (tape->pc->error ? 0 : 1, HWGROUP(drive));
+	idetape_end_request(drive, tape->pc->error ? 0 : 1);
 	return ide_stopped;
 }
 
 /*
  *	A mode sense command is used to "sense" tape parameters.
  */
-static void idetape_create_mode_sense_cmd (idetape_pc_t *pc, byte page_code)
+static void idetape_create_mode_sense_cmd (idetape_pc_t *pc, u8 page_code)
 {
 	idetape_init_pc (pc);
 	pc->c[0] = IDETAPE_MODE_SENSE_CMD;
 	if (page_code != IDETAPE_BLOCK_DESCRIPTOR)
-		pc->c[1] = 8;			/* DBD = 1 - Don't return block descriptors */
+		pc->c[1] = 8;	/* DBD = 1 - Don't return block descriptors */
 	pc->c[2] = page_code;
-	pc->c[3] = 255;				/* Don't limit the returned information */
-	pc->c[4] = 255;				/* (We will just discard data in that case) */
+	pc->c[3] = 255;		/* Don't limit the returned information */
+	pc->c[4] = 255;		/* (We will just discard data in that case) */
 	if (page_code == IDETAPE_BLOCK_DESCRIPTOR)
 		pc->request_transfer = 12;
 	else if (page_code == IDETAPE_CAPABILITIES_PAGE)
@@ -2391,13 +2519,15 @@
 	}
 	tape->tape_still_time = (jiffies - tape->tape_still_time_begin) * 1000 / HZ;
 #if USE_IOTRACE
-	IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
+	IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head,
+			tape->tape_head, tape->minor);
 #endif
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 1)
-		printk(KERN_INFO "ide-tape: buffer fill callback, %d/%d\n", tape->cur_frames, tape->max_frames);
+		printk(KERN_INFO "ide-tape: buffer fill callback, %d/%d\n",
+			tape->cur_frames, tape->max_frames);
 #endif
-	idetape_end_request (tape->pc->error ? 0 : 1, HWGROUP(drive));
+	idetape_end_request(drive, tape->pc->error ? 0 : 1);
 	return ide_stopped;
 }
 
@@ -2429,7 +2559,8 @@
 	else if (time_after(jiffies, tape->controlled_previous_head_time))
 		tape->controlled_pipeline_head_speed = (tape->pipeline_head - tape->controlled_previous_pipeline_head) * 32 * HZ / (jiffies - tape->controlled_previous_head_time);
 
-	if (tape->nr_pending_stages < tape->max_stages /*- 1 */) { /* -1 for read mode error recovery */
+	if (tape->nr_pending_stages < tape->max_stages /*- 1 */) {
+		/* -1 for read mode error recovery */
 		if (time_after(jiffies, tape->uncontrolled_previous_head_time + 10 * HZ)) {
 			tape->uncontrolled_pipeline_head_time = jiffies;
 			tape->uncontrolled_pipeline_head_speed = (tape->pipeline_head - tape->uncontrolled_previous_pipeline_head) * 32 * HZ / (jiffies - tape->uncontrolled_previous_head_time);
@@ -2465,15 +2596,24 @@
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_pc_t *pc = tape->pc;
-	idetape_status_reg_t status;
+	atapi_status_t status;
 
 	if (tape->onstream)
-		printk(KERN_INFO "ide-tape: bug: onstream, media_access_finished\n");
-	status.all = GET_STAT();
+		printk(KERN_INFO "ide-tape: bug: "
+			"onstream, media_access_finished\n");
+
+	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
+
 	if (status.b.dsc) {
-		if (status.b.check) {					/* Error detected */
-			printk (KERN_ERR "ide-tape: %s: I/O error, ",tape->name);
-			return idetape_retry_pc (drive);			/* Retry operation */
+		if (status.b.check) {
+			/* Error detected */
+			printk(KERN_ERR "ide-tape: %s: I/O error: "
+			    "pc = %2x, key = %2x, asc = %2x, ascq = %2x\n",
+			    tape->name, pc->c[0],
+			    tape->sense_key, tape->asc, tape->ascq);
+
+			/* Retry operation */
+			return idetape_retry_pc(drive);
 		}
 		pc->error = 0;
 		if (tape->failed_pc == pc)
@@ -2510,16 +2650,16 @@
 
 #if IDETAPE_DEBUG_LOG	
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_rw_callback\n");
+		printk(KERN_INFO "ide-tape: Reached idetape_rw_callback\n");
 #endif /* IDETAPE_DEBUG_LOG */
 
 	tape->first_frame_position += blocks;
 	rq->current_nr_sectors -= blocks;
 
 	if (!tape->pc->error)
-		idetape_end_request (1, HWGROUP (drive));
+		idetape_end_request(drive, 1);
 	else
-		idetape_end_request (tape->pc->error, HWGROUP (drive));
+		idetape_end_request(drive, tape->pc->error);
 	return ide_stopped;
 }
 
@@ -2528,7 +2668,7 @@
 	struct buffer_head *p = bh;
 	idetape_init_pc (pc);
 	pc->c[0] = IDETAPE_READ_CMD;
-	put_unaligned (htonl (length), (unsigned int *) &pc->c[1]);
+	put_unaligned(htonl (length), (unsigned int *) &pc->c[1]);
 	pc->c[1] = 1;
 	pc->callback = &idetape_rw_callback;
 	pc->bh = bh;
@@ -2543,11 +2683,11 @@
 	if (!tape->onstream) {
 		pc->request_transfer = pc->buffer_size = length * tape->tape_block_size;
 		if (pc->request_transfer == tape->stage_size)
-			set_bit (PC_DMA_RECOMMENDED, &pc->flags);
+			set_bit(PC_DMA_RECOMMENDED, &pc->flags);
 	} else  {
 		if (length) {
 			pc->request_transfer = pc->buffer_size = 32768 + 512;
-			set_bit (PC_DMA_RECOMMENDED, &pc->flags);
+			set_bit(PC_DMA_RECOMMENDED, &pc->flags);
 		} else
 			pc->request_transfer = 0;
 	}
@@ -2558,7 +2698,7 @@
 	int size = 32768;
 
 	struct buffer_head *p = bh;
-	idetape_init_pc (pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_READ_BUFFER_CMD;
 	pc->c[1] = IDETAPE_RETRIEVE_FAULTY_BLOCK;
 	pc->c[7] = size >> 8;
@@ -2577,9 +2717,9 @@
 static void idetape_create_write_cmd (idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct buffer_head *bh)
 {
 	struct buffer_head *p = bh;
-	idetape_init_pc (pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_WRITE_CMD;
-	put_unaligned (htonl (length), (unsigned int *) &pc->c[1]);
+	put_unaligned(htonl (length), (unsigned int *) &pc->c[1]);
 	pc->c[1] = 1;
 	pc->callback = &idetape_rw_callback;
 	set_bit (PC_WRITING, &pc->flags);
@@ -2596,17 +2736,49 @@
 	if (!tape->onstream) {
 		pc->request_transfer = pc->buffer_size = length * tape->tape_block_size;
 		if (pc->request_transfer == tape->stage_size)
-			set_bit (PC_DMA_RECOMMENDED, &pc->flags);
+			set_bit(PC_DMA_RECOMMENDED, &pc->flags);
 	} else  {
 		if (length) {
 			pc->request_transfer = pc->buffer_size = 32768 + 512;
-			set_bit (PC_DMA_RECOMMENDED, &pc->flags);
+			set_bit(PC_DMA_RECOMMENDED, &pc->flags);
 		} else
 			pc->request_transfer = 0;
 	}
 }
 
 /*
+ * This is our end_request replacement function.
+ */
+static int idetape_do_end_request (ide_drive_t *drive, int uptodate)
+{
+	struct request *rq;
+	unsigned long flags;
+	int ret = 1;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	rq = HWGROUP(drive)->rq;
+
+	/*
+	 * decide whether to reenable DMA -- 3 is a random magic for now,
+	 * if we DMA timeout more than 3 times, just stay in PIO
+	 */
+	if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
+		drive->state = 0;
+		HWGROUP(drive)->hwif->ide_dma_on(drive);
+	}
+
+	if (!end_that_request_first(rq, uptodate, drive->name)) {
+		add_blkdev_randomness(MAJOR(rq->rq_dev));
+		blkdev_dequeue_request(rq);
+		HWGROUP(drive)->rq = NULL;
+		end_that_request_last(rq);
+		ret = 0;
+	}
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	return ret;
+}
+
+/*
  *	idetape_do_request is our request handling function.	
  */
 static ide_startstop_t idetape_do_request (ide_drive_t *drive, struct request *rq, unsigned long block)
@@ -2614,35 +2786,42 @@
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_pc_t *pc;
 	struct request *postponed_rq = tape->postponed_rq;
-	idetape_status_reg_t status;
+	atapi_status_t status;
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 5)
-		printk (KERN_INFO "ide-tape: rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->cmd,rq->errors);
+		printk(KERN_INFO "ide-tape: rq_status: %d, "
+			"rq_dev: %u, cmd: %d, errors: %d\n", rq->rq_status,
+			(unsigned int) rq->rq_dev, rq->cmd, rq->errors);
 	if (tape->debug_level >= 2)
-		printk (KERN_INFO "ide-tape: sector: %ld, nr_sectors: %ld, current_nr_sectors: %ld\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors);
+		printk(KERN_INFO "ide-tape: sector: %ld, "
+			"nr_sectors: %ld, current_nr_sectors: %ld\n",
+			rq->sector, rq->nr_sectors, rq->current_nr_sectors);
 #endif /* IDETAPE_DEBUG_LOG */
 
-	if (!IDETAPE_RQ_CMD (rq->cmd)) {
+	if (!IDETAPE_RQ_CMD(rq->cmd)) {
 		/*
 		 *	We do not support buffer cache originated requests.
 		 */
-		printk (KERN_NOTICE "ide-tape: %s: Unsupported command in request queue (%d)\n", drive->name, rq->cmd);
-		ide_end_request (0, HWGROUP (drive));			/* Let the common code handle it */
+		printk(KERN_NOTICE "ide-tape: %s: Unsupported command in "
+			"request queue (%d)\n", drive->name, rq->cmd);
+		idetape_do_end_request(drive, 0);
 		return ide_stopped;
 	}
 
 	/*
 	 *	Retry a failed packet command
 	 */
-	if (tape->failed_pc != NULL && tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
-		return idetape_issue_packet_command (drive, tape->failed_pc);
+	if (tape->failed_pc != NULL &&
+	    tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
+		return idetape_issue_packet_command(drive, tape->failed_pc);
 	}
 #if IDETAPE_DEBUG_BUGS
 	if (postponed_rq != NULL)
 		if (rq != postponed_rq) {
-			printk (KERN_ERR "ide-tape: ide-tape.c bug - Two DSC requests were queued\n");
-			idetape_end_request (0, HWGROUP (drive));
+			printk(KERN_ERR "ide-tape: ide-tape.c bug - "
+					"Two DSC requests were queued\n");
+			idetape_end_request(drive, 0);
 			return ide_stopped;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
@@ -2653,7 +2832,7 @@
 	 *	If the tape is still busy, postpone our request and service
 	 *	the other device meanwhile.
 	 */
-	status.all = GET_STAT();
+	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
 
 	/*
 	 * The OnStream tape drive doesn't support DSC. Assume
@@ -2662,7 +2841,7 @@
 	if (tape->onstream)
 		status.b.dsc = 1;
 	if (!drive->dsc_overlap && rq->cmd != IDETAPE_PC_RQ2)
-		set_bit (IDETAPE_IGNORE_DSC, &tape->flags);
+		set_bit(IDETAPE_IGNORE_DSC, &tape->flags);
 
 	/*
 	 * For the OnStream tape, check the current status of the tape
@@ -2674,7 +2853,8 @@
 	 */
 	if (tape->tape_still_time > 100 && tape->tape_still_time < 200)
 		tape->measure_insert_time = 1;
-	if (tape->req_buffer_fill && (rq->cmd == IDETAPE_WRITE_RQ || rq->cmd == IDETAPE_READ_RQ)) {
+	if (tape->req_buffer_fill &&
+	    (rq->cmd == IDETAPE_WRITE_RQ || rq->cmd == IDETAPE_READ_RQ)) {
 		tape->req_buffer_fill = 0;
 		tape->writes_since_buffer_fill = 0;
 		tape->reads_since_buffer_fill = 0;
@@ -2699,7 +2879,8 @@
 			tape->insert_speed > tape->max_insert_speed ) ) && rq->nr_sectors) ) ) {
 #if IDETAPE_DEBUG_LOG
 		if (tape->debug_level >= 4)
-			printk(KERN_INFO "ide-tape: postponing request, cmd %d, cur %d, max %d\n",
+			printk(KERN_INFO "ide-tape: postponing request, "
+					"cmd %d, cur %d, max %d\n",
 				rq->cmd, tape->cur_frames, tape->max_frames);
 #endif
 		if (tape->postpone_cnt++ < 500) {
@@ -2708,25 +2889,28 @@
 		}
 #if ONSTREAM_DEBUG
 		else if (tape->debug_level >= 4) 
-			printk(KERN_INFO "ide-tape: %s: postpone_cnt %d\n", tape->name, tape->postpone_cnt);
+			printk(KERN_INFO "ide-tape: %s: postpone_cnt %d\n",
+				tape->name, tape->postpone_cnt);
 #endif
 	}
-	if (!test_and_clear_bit (IDETAPE_IGNORE_DSC, &tape->flags) && !status.b.dsc) {
+	if (!test_and_clear_bit(IDETAPE_IGNORE_DSC, &tape->flags) &&
+	    !status.b.dsc) {
 		if (postponed_rq == NULL) {
 			tape->dsc_polling_start = jiffies;
 			tape->dsc_polling_frequency = tape->best_dsc_rw_frequency;
 			tape->dsc_timeout = jiffies + IDETAPE_DSC_RW_TIMEOUT;
 		} else if ((signed long) (jiffies - tape->dsc_timeout) > 0) {
-			printk (KERN_ERR "ide-tape: %s: DSC timeout\n", tape->name);
+			printk(KERN_ERR "ide-tape: %s: DSC timeout\n",
+				tape->name);
 			if (rq->cmd == IDETAPE_PC_RQ2) {
-				idetape_media_access_finished (drive);
+				idetape_media_access_finished(drive);
 				return ide_stopped;
 			} else {
-				return ide_do_reset (drive);
+				return ide_do_reset(drive);
 			}
 		} else if (jiffies - tape->dsc_polling_start > IDETAPE_DSC_MA_THRESHOLD)
 			tape->dsc_polling_frequency = IDETAPE_DSC_MA_SLOW;
-		idetape_postpone_request (drive);
+		idetape_postpone_request(drive);
 		return ide_stopped;
 	}
 	switch (rq->cmd) {
@@ -2743,8 +2927,8 @@
 				if (time_after(jiffies, tape->last_buffer_fill + 5 * HZ / 100))
 					tape->req_buffer_fill = 1;
 			}
-			pc = idetape_next_pc_storage (drive);
-			idetape_create_read_cmd (tape, pc, rq->current_nr_sectors, rq->bh);
+			pc = idetape_next_pc_storage(drive);
+			idetape_create_read_cmd(tape, pc, rq->current_nr_sectors, rq->bh);
 			break;
 		case IDETAPE_WRITE_RQ:
 			tape->buffer_head++;
@@ -2760,39 +2944,41 @@
 					tape->req_buffer_fill = 1;
 				calculate_speeds(drive);
 			}
-			pc = idetape_next_pc_storage (drive);
-			idetape_create_write_cmd (tape, pc, rq->current_nr_sectors, rq->bh);
+			pc = idetape_next_pc_storage(drive);
+			idetape_create_write_cmd(tape, pc, rq->current_nr_sectors, rq->bh);
 			break;
 		case IDETAPE_READ_BUFFER_RQ:
 			tape->postpone_cnt = 0;
-			pc = idetape_next_pc_storage (drive);
-			idetape_create_read_buffer_cmd (tape, pc, rq->current_nr_sectors, rq->bh);
+			pc = idetape_next_pc_storage(drive);
+			idetape_create_read_buffer_cmd(tape, pc, rq->current_nr_sectors, rq->bh);
 			break;
 		case IDETAPE_ABORTED_WRITE_RQ:
 			rq->cmd = IDETAPE_WRITE_RQ;
-			idetape_end_request (IDETAPE_ERROR_EOD, HWGROUP(drive));
+			idetape_end_request(drive, IDETAPE_ERROR_EOD);
 			return ide_stopped;
 		case IDETAPE_ABORTED_READ_RQ:
 #if IDETAPE_DEBUG_LOG
 			if (tape->debug_level >= 2)
-				printk(KERN_INFO "ide-tape: %s: detected aborted read rq\n", tape->name);
+				printk(KERN_INFO "ide-tape: %s: detected "
+					"aborted read rq\n", tape->name);
 #endif
 			rq->cmd = IDETAPE_READ_RQ;
-			idetape_end_request (IDETAPE_ERROR_EOD, HWGROUP(drive));
+			idetape_end_request(drive, IDETAPE_ERROR_EOD);
 			return ide_stopped;
 		case IDETAPE_PC_RQ1:
 			pc = (idetape_pc_t *) rq->buffer;
 			rq->cmd = IDETAPE_PC_RQ2;
 			break;
 		case IDETAPE_PC_RQ2:
-			idetape_media_access_finished (drive);
+			idetape_media_access_finished(drive);
 			return ide_stopped;
 		default:
-			printk (KERN_ERR "ide-tape: bug in IDETAPE_RQ_CMD macro\n");
-			idetape_end_request (0, HWGROUP (drive));
+			printk(KERN_ERR "ide-tape: bug in "
+				"IDETAPE_RQ_CMD macro\n");
+			idetape_end_request(drive, 0);
 			return ide_stopped;
 	}
-	return idetape_issue_packet_command (drive, pc);
+	return idetape_issue_packet_command(drive, pc);
 }
 
 /*
@@ -2826,11 +3012,11 @@
 	int pages = tape->pages_per_stage;
 	char *b_data;
 
-	if ((stage = (idetape_stage_t *) kmalloc (sizeof (idetape_stage_t),GFP_KERNEL)) == NULL)
+	if ((stage = (idetape_stage_t *) kmalloc(sizeof(idetape_stage_t),GFP_KERNEL)) == NULL)
 		return NULL;
 	stage->next = NULL;
 
-	bh = stage->bh = (struct buffer_head *) kmalloc (sizeof (struct buffer_head), GFP_KERNEL);
+	bh = stage->bh = (struct buffer_head *) kmalloc(sizeof(struct buffer_head), GFP_KERNEL);
 	if (bh == NULL)
 		goto abort;
 	bh->b_reqnext = NULL;
@@ -2840,7 +3026,7 @@
 		memset(bh->b_data, 0, PAGE_SIZE);
 	bh->b_size = PAGE_SIZE;
 	atomic_set(&bh->b_count, full ? bh->b_size : 0);
-	set_bit (BH_Lock, &bh->b_state);
+	set_bit(BH_Lock, &bh->b_state);
 
 	while (--pages) {
 		if ((b_data = (char *) __get_free_page (GFP_KERNEL)) == NULL)
@@ -2861,15 +3047,15 @@
 			continue;
 		}
 		prev_bh = bh;
-		if ((bh = (struct buffer_head *) kmalloc (sizeof (struct buffer_head), GFP_KERNEL)) == NULL) {
-			free_page ((unsigned long) b_data);
+		if ((bh = (struct buffer_head *) kmalloc(sizeof(struct buffer_head), GFP_KERNEL)) == NULL) {
+			free_page((unsigned long) b_data);
 			goto abort;
 		}
 		bh->b_reqnext = NULL;
 		bh->b_data = b_data;
 		bh->b_size = PAGE_SIZE;
 		atomic_set(&bh->b_count, full ? bh->b_size : 0);
-		set_bit (BH_Lock, &bh->b_state);
+		set_bit(BH_Lock, &bh->b_state);
 		prev_bh->b_reqnext = bh;
 	}
 	bh->b_size -= tape->excess_bh_size;
@@ -2879,7 +3065,7 @@
 		stage->aux = (os_aux_t *) (bh->b_data + bh->b_size - OS_AUX_SIZE);
 	return stage;
 abort:
-	__idetape_kfree_stage (stage);
+	__idetape_kfree_stage(stage);
 	return NULL;
 }
 
@@ -2889,7 +3075,7 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_kmalloc_stage\n");
+		printk (KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 
 	if (tape->nr_stages >= tape->max_stages)
@@ -2898,7 +3084,7 @@
 		tape->cache_stage = NULL;
 		return cache_stage;
 	}
-	return __idetape_kmalloc_stage (tape, 0, 0);
+	return __idetape_kmalloc_stage(tape, 0, 0);
 }
 
 static void idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t *stage, const char *buf, int n)
@@ -2909,12 +3095,13 @@
 	while (n) {
 #if IDETAPE_DEBUG_BUGS
 		if (bh == NULL) {
-			printk (KERN_ERR "ide-tape: bh == NULL in idetape_copy_stage_from_user\n");
+			printk(KERN_ERR "ide-tape: bh == NULL in %s\n",
+				__FUNCTION__);
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		count = IDE_MIN (bh->b_size - atomic_read(&bh->b_count), n);
-		copy_from_user (bh->b_data + atomic_read(&bh->b_count), buf, count);
+		count = IDE_MIN(bh->b_size - atomic_read(&bh->b_count), n);
+		copy_from_user(bh->b_data + atomic_read(&bh->b_count), buf, count);
 		n -= count;
 		atomic_add(count, &bh->b_count);
 		buf += count;
@@ -2935,12 +3122,13 @@
 	while (n) {
 #if IDETAPE_DEBUG_BUGS
 		if (bh == NULL) {
-			printk (KERN_ERR "ide-tape: bh == NULL in idetape_copy_stage_to_user\n");
+			printk(KERN_ERR "ide-tape: bh == NULL in %s\n",
+				__FUNCTION__);
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		count = IDE_MIN (tape->b_count, n);
-		copy_to_user (buf, tape->b_data, count);
+		count = IDE_MIN(tape->b_count, n);
+		copy_to_user(buf, tape->b_data, count);
 		n -= count;
 		tape->b_data += count;
 		tape->b_count -= count;
@@ -2960,9 +3148,9 @@
 	struct buffer_head *bh = tape->merge_stage->bh;
 	
 	tape->bh = bh;
-	if (tape->chrdev_direction == idetape_direction_write)
+	if (tape->chrdev_direction == idetape_direction_write) {
 		atomic_set(&bh->b_count, 0);
-	else {
+	} else {
 		tape->b_data = bh->b_data;
 		tape->b_count = atomic_read(&bh->b_count);
 	}
@@ -2973,9 +3161,12 @@
 	struct buffer_head *tmp;
 	os_aux_t *tmp_aux;
 
-	tmp = stage->bh; tmp_aux = stage->aux;
-	stage->bh = tape->merge_stage->bh; stage->aux = tape->merge_stage->aux;
-	tape->merge_stage->bh = tmp; tape->merge_stage->aux = tmp_aux;
+	tmp = stage->bh;
+	tmp_aux = stage->aux;
+	stage->bh = tape->merge_stage->bh;
+	stage->aux = tape->merge_stage->aux;
+	tape->merge_stage->bh = tmp;
+	tape->merge_stage->aux = tmp_aux;
 	idetape_init_merge_stage (tape);
 }
 
@@ -2989,10 +3180,10 @@
 	
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_add_stage_tail\n");
+		printk(KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 	spin_lock_irqsave(&tape->spinlock, flags);
-	stage->next=NULL;
+	stage->next = NULL;
 	if (tape->last_stage != NULL)
 		tape->last_stage->next=stage;
 	else
@@ -3058,10 +3249,13 @@
 		else
 			dat->dat_list[0].flags = OS_DAT_FLAGS_DATA;
 		dat->dat_list[0].reserved = 0;
-	} 
-	aux->filemark_cnt = ntohl(tape->filemark_cnt);		/* shouldn't this be htonl ?? */
-	aux->phys_fm = ntohl(0xffffffff);			/* shouldn't this be htonl ?? */
-	aux->last_mark_addr = ntohl(tape->last_mark_addr);	/* shouldn't this be htonl ?? */
+	}
+	/* shouldn't this be htonl ?? */
+	aux->filemark_cnt = ntohl(tape->filemark_cnt);
+	/* shouldn't this be htonl ?? */
+	aux->phys_fm = ntohl(0xffffffff);
+	/* shouldn't this be htonl ?? */
+	aux->last_mark_addr = ntohl(tape->last_mark_addr);
 }
 
 /*
@@ -3078,7 +3272,8 @@
 
 #if IDETAPE_DEBUG_BUGS
 	if (rq == NULL || !IDETAPE_RQ_CMD (rq->cmd)) {
-		printk (KERN_ERR "ide-tape: bug: Trying to sleep on non-valid request\n");
+		printk(KERN_ERR "ide-tape: bug: Trying to sleep on "
+			"non-valid request\n");
 		return;
 	}
 #endif /* IDETAPE_DEBUG_BUGS */
@@ -3086,7 +3281,7 @@
 	tape->waiting = &wait;
 	spin_unlock(&tape->spinlock);
 	wait_for_completion(&wait);
-	rq->waiting = NULL;
+	/* The stage and its struct request have been deallocated */
 	tape->waiting = NULL;
 	spin_lock_irq(&tape->spinlock);
 }
@@ -3098,35 +3293,39 @@
 	
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_read_position_callback\n");
+		printk(KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 
 	if (!tape->pc->error) {
 		result = (idetape_read_position_result_t *) tape->pc->buffer;
 #if IDETAPE_DEBUG_LOG
 		if (tape->debug_level >= 2)
-			printk (KERN_INFO "ide-tape: BOP - %s\n",result->bop ? "Yes":"No");
+			printk(KERN_INFO "ide-tape: BOP - %s\n",
+				result->bop ? "Yes":"No");
 		if (tape->debug_level >= 2)
-			printk (KERN_INFO "ide-tape: EOP - %s\n",result->eop ? "Yes":"No");
+			printk(KERN_INFO "ide-tape: EOP - %s\n",
+				result->eop ? "Yes":"No");
 #endif /* IDETAPE_DEBUG_LOG */
 		if (result->bpu) {
-			printk (KERN_INFO "ide-tape: Block location is unknown to the tape\n");
-			clear_bit (IDETAPE_ADDRESS_VALID, &tape->flags);
-			idetape_end_request (0, HWGROUP (drive));
+			printk(KERN_INFO "ide-tape: Block location is "
+				"unknown to the tape\n");
+			clear_bit(IDETAPE_ADDRESS_VALID, &tape->flags);
+			idetape_end_request(drive, 0);
 		} else {
 #if IDETAPE_DEBUG_LOG
 			if (tape->debug_level >= 2)
-				printk (KERN_INFO "ide-tape: Block Location - %u\n", ntohl (result->first_block));
+				printk(KERN_INFO "ide-tape: Block Location "
+					"- %u\n", ntohl(result->first_block));
 #endif /* IDETAPE_DEBUG_LOG */
 			tape->partition = result->partition;
-			tape->first_frame_position = ntohl (result->first_block);
-			tape->last_frame_position = ntohl (result->last_block);
+			tape->first_frame_position = ntohl(result->first_block);
+			tape->last_frame_position = ntohl(result->last_block);
 			tape->blocks_in_buffer = result->blocks_in_buffer[2];
-			set_bit (IDETAPE_ADDRESS_VALID, &tape->flags);
-			idetape_end_request (1, HWGROUP (drive));
+			set_bit(IDETAPE_ADDRESS_VALID, &tape->flags);
+			idetape_end_request(drive, 1);
 		}
 	} else {
-		idetape_end_request (0, HWGROUP (drive));
+		idetape_end_request(drive, 0);
 	}
 	return ide_stopped;
 }
@@ -3143,12 +3342,12 @@
 {
 	idetape_tape_t *tape = drive->driver_data;
 
-	idetape_init_pc (pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_WRITE_FILEMARK_CMD;
 	if (tape->onstream)
 		pc->c[1] = 1; /* Immed bit */
 	pc->c[4] = write_filemark;  /* not used for OnStream ?? */
-	set_bit (PC_WAIT_FOR_DSC, &pc->flags);
+	set_bit(PC_WAIT_FOR_DSC, &pc->flags);
 	pc->callback = &idetape_pc_callback;
 }
 
@@ -3165,8 +3364,8 @@
  *	ide_do_drive_cmd from ide.c
  *	cdrom_queue_request and cdrom_queue_packet_command from ide-cd.c
  *
- *	We add a special packet command request to the tail of the request queue,
- *	and wait for it to be serviced.
+ *	We add a special packet command request to the tail of the request
+ *	queue, and wait for it to be serviced.
  *
  *	This is not to be called from within the request handling part
  *	of the driver ! We allocate here data in the stack, and it is valid
@@ -3183,17 +3382,17 @@
 {
 	struct request rq;
 
-	ide_init_drive_cmd (&rq);
+	ide_init_drive_cmd(&rq);
 	rq.buffer = (char *) pc;
 	rq.cmd = IDETAPE_PC_RQ1;
-	return ide_do_drive_cmd (drive, &rq, ide_wait);
+	return ide_do_drive_cmd(drive, &rq, ide_wait);
 }
 
 static void idetape_create_load_unload_cmd (ide_drive_t *drive, idetape_pc_t *pc,int cmd)
 {
 	idetape_tape_t *tape = drive->driver_data;
 
-	idetape_init_pc (pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_LOAD_UNLOAD_CMD;
 	pc->c[4] = cmd;
 	if (tape->onstream) {
@@ -3201,7 +3400,7 @@
 		if (cmd == !IDETAPE_LU_LOAD_MASK)
 			pc->c[4] = 4;
 	}
-	set_bit (PC_WAIT_FOR_DSC, &pc->flags);
+	set_bit(PC_WAIT_FOR_DSC, &pc->flags);
 	pc->callback = &idetape_pc_callback;
 }
 
@@ -3219,13 +3418,14 @@
 		if (!__idetape_queue_pc_tail(drive, &pc))
 			return 0;
 		if (tape->sense_key == 2 && tape->asc == 4 && tape->ascq == 2) {
-			idetape_create_load_unload_cmd (drive, &pc, IDETAPE_LU_LOAD_MASK);
+			idetape_create_load_unload_cmd(drive, &pc, IDETAPE_LU_LOAD_MASK);
 			__idetape_queue_pc_tail(drive, &pc);
 			idetape_create_test_unit_ready_cmd(&pc);
 			if (!__idetape_queue_pc_tail(drive, &pc))
 				return 0;
 		}
-		if (!(tape->sense_key == 2 && tape->asc == 4 && (tape->ascq == 1 || tape->ascq == 8)))
+		if (!(tape->sense_key == 2 && tape->asc == 4 &&
+		    (tape->ascq == 1 || tape->ascq == 8)))
 			break;
 		current->state = TASK_INTERRUPTIBLE;
   		schedule_timeout(HZ / 10);
@@ -3241,9 +3441,13 @@
 	rc = __idetape_queue_pc_tail(drive, pc);
 	if (rc)
 		return rc;
-	if (tape->onstream && test_bit(PC_WAIT_FOR_DSC, &pc->flags))
-		rc = idetape_wait_ready(drive, 60 * 10 * HZ);   /* AJN-4: Changed from 5 to 10 minutes;
-                          because retension takes approx. 8:20 with Onstream 30GB tape */
+	if (tape->onstream && test_bit(PC_WAIT_FOR_DSC, &pc->flags)) {
+		/* AJN-4: Changed from 5 to 10 minutes;
+		 * because retension takes approx.
+		 * 8:20 with Onstream 30GB tape
+		 */
+		rc = idetape_wait_ready(drive, 60 * 10 * HZ);
+	}
 	return rc;
 }
 
@@ -3261,7 +3465,7 @@
 
 static void idetape_create_read_position_cmd (idetape_pc_t *pc)
 {
-	idetape_init_pc (pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_READ_POSITION_CMD;
 	pc->request_transfer = 20;
 	pc->callback = &idetape_read_position_callback;
@@ -3275,42 +3479,27 @@
 
 #if IDETAPE_DEBUG_LOG
         if (tape->debug_level >= 4)
-	printk (KERN_INFO "ide-tape: Reached idetape_read_position\n");
+		printk (KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 
-#ifdef NO_LONGER_REQUIRED
-	idetape_flush_tape_buffers(drive);
-#endif
 	idetape_create_read_position_cmd(&pc);
-	if (idetape_queue_pc_tail (drive, &pc))
+	if (idetape_queue_pc_tail(drive, &pc))
 		return -1;
 	position = tape->first_frame_position;
-#ifdef NO_LONGER_REQUIRED
-	if (tape->onstream) {
-		if ((position != tape->last_frame_position - tape->blocks_in_buffer) &&
-		    (position != tape->last_frame_position + tape->blocks_in_buffer)) {
-			if (tape->blocks_in_buffer == 0) {
-				printk("ide-tape: %s: correcting read position %d, %d, %d\n", tape->name, position, tape->last_frame_position, tape->blocks_in_buffer);
-				position = tape->last_frame_position;
-				tape->first_frame_position = position;
-			}
-		}
-	}
-#endif
 	return position;
 }
 
-static void idetape_create_locate_cmd (ide_drive_t *drive, idetape_pc_t *pc, unsigned int block, byte partition, int skip)
+static void idetape_create_locate_cmd (ide_drive_t *drive, idetape_pc_t *pc, unsigned int block, u8 partition, int skip)
 {
 	idetape_tape_t *tape = drive->driver_data;
 
-	idetape_init_pc (pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_LOCATE_CMD;
 	if (tape->onstream)
 		pc->c[1] = 1; /* Immediate bit */
 	else
 		pc->c[1] = 2;
-	put_unaligned (htonl (block), (unsigned int *) &pc->c[3]);
+	put_unaligned(htonl(block), (unsigned int *) &pc->c[3]);
 	pc->c[8] = partition;
 	if (tape->onstream)
                 /*
@@ -3319,7 +3508,7 @@
                  * data in the drive to this new position!
                  */
 		pc->c[9] = skip << 7;
-	set_bit (PC_WAIT_FOR_DSC, &pc->flags);
+	set_bit(PC_WAIT_FOR_DSC, &pc->flags);
 	pc->callback = &idetape_pc_callback;
 }
 
@@ -3345,11 +3534,15 @@
 
 	if (tape->chrdev_direction != idetape_direction_read)
 		return 0;
+	cnt = tape->merge_stage_size / tape->tape_block_size;
+	if (test_and_clear_bit(IDETAPE_FILEMARK, &tape->flags))
+		++cnt;		/* Filemarks count as 1 sector */
 	tape->merge_stage_size = 0;
 	if (tape->merge_stage != NULL) {
-		__idetape_kfree_stage (tape->merge_stage);
+		__idetape_kfree_stage(tape->merge_stage);
 		tape->merge_stage = NULL;
 	}
+	clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 	tape->chrdev_direction = idetape_direction_none;
 	
 	if (tape->first_stage == NULL)
@@ -3357,13 +3550,18 @@
 
 	spin_lock_irqsave(&tape->spinlock, flags);
 	tape->next_stage = NULL;
-	if (idetape_pipeline_active (tape))
+	if (idetape_pipeline_active(tape))
 		idetape_wait_for_request(drive, tape->active_data_request);
 	spin_unlock_irqrestore(&tape->spinlock, flags);
 
-	cnt = tape->nr_stages - tape->nr_pending_stages;
-	while (tape->first_stage != NULL)
-		idetape_remove_stage_head (drive);
+	while (tape->first_stage != NULL) {
+		struct request *rq_ptr = &tape->first_stage->rq;
+
+		cnt += rq_ptr->nr_sectors - rq_ptr->current_nr_sectors; 
+		if (rq_ptr->errors == IDETAPE_ERROR_FILEMARK)
+			++cnt;
+		idetape_remove_stage_head(drive);
+	}
 	tape->nr_pending_stages = 0;
 	tape->max_stages = tape->min_pipeline;
 	return cnt;
@@ -3378,7 +3576,7 @@
  *	of the request queue and wait for their completion.
  *	
  */
-static int idetape_position_tape (ide_drive_t *drive, unsigned int block, byte partition, int skip)
+static int idetape_position_tape (ide_drive_t *drive, unsigned int block, u8 partition, int skip)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	int retval;
@@ -3387,13 +3585,13 @@
 	if (tape->chrdev_direction == idetape_direction_read)
 		__idetape_discard_read_pipeline(drive);
 	idetape_wait_ready(drive, 60 * 5 * HZ);
-	idetape_create_locate_cmd (drive, &pc, block, partition, skip);
-	retval = idetape_queue_pc_tail (drive, &pc);
+	idetape_create_locate_cmd(drive, &pc, block, partition, skip);
+	retval = idetape_queue_pc_tail(drive, &pc);
 	if (retval)
 		return (retval);
 
-	idetape_create_read_position_cmd (&pc);
-	return (idetape_queue_pc_tail (drive, &pc));
+	idetape_create_read_position_cmd(&pc);
+	return (idetape_queue_pc_tail(drive, &pc));
 }
 
 static void idetape_discard_read_pipeline (ide_drive_t *drive, int restore_position)
@@ -3407,11 +3605,13 @@
 		position = idetape_read_position(drive);
 #if ONSTREAM_DEBUG
 		if (tape->debug_level >= 2)
-			printk(KERN_INFO "ide-tape: address %u, nr_stages %d\n", position, cnt);
+			printk(KERN_INFO "ide-tape: address %u, nr_stages %d\n",
+				position, cnt);
 #endif
 		seek = position > cnt ? position - cnt : 0;
 		if (idetape_position_tape(drive, seek, 0, 0)) {
-			printk(KERN_INFO "ide-tape: %s: position_tape failed in discard_pipeline()\n", tape->name);
+			printk(KERN_INFO "ide-tape: %s: position_tape "
+				"failed in discard_pipeline()\n", tape->name);
 			return;
 		}
 	}
@@ -3421,7 +3621,7 @@
 {
 	idetape_pc_t pc;
 
-	idetape_create_mode_sense_cmd (&pc, IDETAPE_BUFFER_FILLING_PAGE);
+	idetape_create_mode_sense_cmd(&pc, IDETAPE_BUFFER_FILLING_PAGE);
 	pc.callback = idetape_onstream_buffer_fill_callback;
 	(void) idetape_queue_pc_tail(drive, &pc);
 }
@@ -3437,29 +3637,30 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 2)
-		printk (KERN_INFO "ide-tape: idetape_queue_rw_tail: cmd=%d\n",cmd);
+		printk(KERN_INFO "ide-tape: %s: cmd=%d\n", __FUNCTION__, cmd);
 #endif /* IDETAPE_DEBUG_LOG */
 #if IDETAPE_DEBUG_BUGS
 	if (idetape_pipeline_active (tape)) {
-		printk (KERN_ERR "ide-tape: bug: the pipeline is active in idetape_queue_rw_tail\n");
+		printk(KERN_ERR "ide-tape: bug: the pipeline is active in %s\n",
+			__FUNCTION__);
 		return (0);
 	}
 #endif /* IDETAPE_DEBUG_BUGS */	
 
-	ide_init_drive_cmd (&rq);
+	ide_init_drive_cmd(&rq);
 	rq.bh = bh;
 	rq.cmd = cmd;
 	rq.sector = tape->first_frame_position;
 	rq.nr_sectors = rq.current_nr_sectors = blocks;
 	if (tape->onstream)
 		tape->postpone_cnt = 600;
-	(void) ide_do_drive_cmd (drive, &rq, ide_wait);
+	(void) ide_do_drive_cmd(drive, &rq, ide_wait);
 
 	if (cmd != IDETAPE_READ_RQ && cmd != IDETAPE_WRITE_RQ)
 		return 0;
 
 	if (tape->merge_stage)
-		idetape_init_merge_stage (tape);
+		idetape_init_merge_stage(tape);
 	if (rq.errors == IDETAPE_ERROR_GENERAL)
 		return -EIO;
 	return (tape->tape_block_size * (blocks-rq.current_nr_sectors));
@@ -3517,7 +3718,8 @@
 	idetape_update_stats(drive);
 #if ONSTREAM_DEBUG
 	if (tape->debug_level >= 2)
-		printk(KERN_INFO "ide-tape: %s: frames left in buffer: %d\n", tape->name, tape->cur_frames);
+		printk(KERN_INFO "ide-tape: %s: frames left in buffer: %d\n",
+			tape->name, tape->cur_frames);
 #endif
 }
 
@@ -3578,12 +3780,12 @@
 
 	if (tape->next_stage == NULL)
 		return;
-	if (!idetape_pipeline_active (tape)) {
+	if (!idetape_pipeline_active(tape)) {
 		if (tape->onstream_write_error)
 			idetape_onstream_write_error_recovery(drive);
 		set_bit(IDETAPE_PIPELINE_ACTIVE, &tape->flags);
-		idetape_active_next_stage (drive);
-		(void) ide_do_drive_cmd (drive, tape->active_data_request, ide_end);
+		idetape_active_next_stage(drive);
+		(void) ide_do_drive_cmd(drive, tape->active_data_request, ide_end);
 	}
 }
 
@@ -3599,41 +3801,41 @@
 {
 	idetape_tape_t *tape = drive->driver_data;
 
-	idetape_init_pc (pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_REWIND_CMD;
 	if (tape->onstream)
 		pc->c[1] = 1;
-	set_bit (PC_WAIT_FOR_DSC, &pc->flags);
+	set_bit(PC_WAIT_FOR_DSC, &pc->flags);
 	pc->callback = &idetape_pc_callback;
 }
 
 static void idetape_create_mode_select_cmd (idetape_pc_t *pc, int length)
 {
-	idetape_init_pc (pc);
-	set_bit (PC_WRITING, &pc->flags);
+	idetape_init_pc(pc);
+	set_bit(PC_WRITING, &pc->flags);
 	pc->c[0] = IDETAPE_MODE_SELECT_CMD;
 	pc->c[1] = 0x10;
-	put_unaligned (htons(length), (unsigned short *) &pc->c[3]);
+	put_unaligned(htons(length), (unsigned short *) &pc->c[3]);
 	pc->request_transfer = 255;
 	pc->callback = &idetape_pc_callback;
 }
 
 static void idetape_create_erase_cmd (idetape_pc_t *pc)
 {
-	idetape_init_pc (pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_ERASE_CMD;
 	pc->c[1] = 1;
-	set_bit (PC_WAIT_FOR_DSC, &pc->flags);
+	set_bit(PC_WAIT_FOR_DSC, &pc->flags);
 	pc->callback = &idetape_pc_callback;
 }
 
-static void idetape_create_space_cmd (idetape_pc_t *pc,int count,byte cmd)
+static void idetape_create_space_cmd (idetape_pc_t *pc,int count,u8 cmd)
 {
-	idetape_init_pc (pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_SPACE_CMD;
-	put_unaligned (htonl (count), (unsigned int *) &pc->c[1]);
+	put_unaligned(htonl (count), (unsigned int *) &pc->c[1]);
 	pc->c[1] = cmd;
-	set_bit (PC_WAIT_FOR_DSC, &pc->flags);
+	set_bit(PC_WAIT_FOR_DSC, &pc->flags);
 	pc->callback = &idetape_pc_callback;
 }
 
@@ -3662,48 +3864,70 @@
 		return 1;
 	}
 	if (rq->errors == IDETAPE_ERROR_GENERAL) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame %d, read error\n", tape->name, tape->first_frame_position);
+		printk(KERN_INFO "ide-tape: %s: skipping frame %d, "
+			"read error\n", tape->name, tape->first_frame_position);
 		return 0;
 	}
 	if (rq->errors == IDETAPE_ERROR_EOD) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame %d, eod\n", tape->name, tape->first_frame_position);
+		printk(KERN_INFO "ide-tape: %s: skipping frame %d, eod\n",
+			tape->name, tape->first_frame_position);
 		return 0;
 	}
 	if (ntohl(aux->format_id) != 0) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame %d, format_id %u\n", tape->name, tape->first_frame_position, ntohl(aux->format_id));
+		printk(KERN_INFO "ide-tape: %s: skipping frame %d, "
+			"format_id %u\n", tape->name,
+			tape->first_frame_position, ntohl(aux->format_id));
 		return 0;
 	}
 	if (memcmp(aux->application_sig, tape->application_sig, 4) != 0) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame %d, incorrect application signature\n", tape->name, tape->first_frame_position);
+		printk(KERN_INFO "ide-tape: %s: skipping frame %d, "
+			"incorrect application signature\n",
+			tape->name, tape->first_frame_position);
 		return 0;
 	}
 	if (aux->frame_type != OS_FRAME_TYPE_DATA &&
 	    aux->frame_type != OS_FRAME_TYPE_EOD &&
 	    aux->frame_type != OS_FRAME_TYPE_MARKER) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame %d, frame type %x\n", tape->name, tape->first_frame_position, aux->frame_type);
+		printk(KERN_INFO "ide-tape: %s: skipping frame %d, frame "
+			"type %x\n", tape->name,
+			tape->first_frame_position, aux->frame_type);
 		return 0;
 	}
 	if (par->partition_num != OS_DATA_PARTITION) {
 		if (!tape->linux_media || tape->linux_media_version != 2) {
-			printk(KERN_INFO "ide-tape: %s: skipping frame %d, partition num %d\n", tape->name, tape->first_frame_position, par->partition_num);
+			printk(KERN_INFO "ide-tape: %s: skipping frame %d, "
+				"partition num %d\n", tape->name,
+				tape->first_frame_position, par->partition_num);
 			return 0;
 		}
 	}
 	if (par->par_desc_ver != OS_PARTITION_VERSION) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame %d, partition version %d\n", tape->name, tape->first_frame_position, par->par_desc_ver);
+		printk(KERN_INFO "ide-tape: %s: skipping frame %d, "
+			"partition version %d\n", tape->name,
+			tape->first_frame_position, par->par_desc_ver);
 		return 0;
 	}
 	if (ntohs(par->wrt_pass_cntr) != tape->wrt_pass_cntr) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame %d, wrt_pass_cntr %d (expected %d)(logical_blk_num %u)\n", tape->name, tape->first_frame_position, ntohs(par->wrt_pass_cntr), tape->wrt_pass_cntr, ntohl(aux->logical_blk_num));
+		printk(KERN_INFO "ide-tape: %s: skipping frame %d, "
+			"wrt_pass_cntr %d (expected %d)(logical_blk_num %u)\n",
+			tape->name, tape->first_frame_position,
+			ntohs(par->wrt_pass_cntr), tape->wrt_pass_cntr,
+			ntohl(aux->logical_blk_num));
 		return 0;
 	}
 	if (aux->frame_seq_num != aux->logical_blk_num) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame %d, seq != logical\n", tape->name, tape->first_frame_position);
+		printk(KERN_INFO "ide-tape: %s: skipping frame %d, "
+			"seq != logical\n", tape->name,
+			tape->first_frame_position);
 		return 0;
 	}
-	if (logical_blk_num != -1 && ntohl(aux->logical_blk_num) != logical_blk_num) {
+	if (logical_blk_num != -1 &&
+	     ntohl(aux->logical_blk_num) != logical_blk_num) {
 		if (!quiet)
-			printk(KERN_INFO "ide-tape: %s: skipping frame %d, logical_blk_num %u (expected %d)\n", tape->name, tape->first_frame_position, ntohl(aux->logical_blk_num), logical_blk_num);
+			printk(KERN_INFO "ide-tape: %s: skipping frame %d, "
+				"logical_blk_num %u (expected %d)\n",
+				tape->name, tape->first_frame_position,
+				ntohl(aux->logical_blk_num), logical_blk_num);
 		return 0;
 	}
 	if (aux->frame_type == OS_FRAME_TYPE_MARKER) {
@@ -3746,7 +3970,7 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 3)
-		printk (KERN_INFO "ide-tape: Reached idetape_add_chrdev_write_request\n");
+		printk(KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 
      	/*
@@ -3755,31 +3979,32 @@
 	 */
 	while ((new_stage = idetape_kmalloc_stage (tape)) == NULL) {
 		spin_lock_irqsave(&tape->spinlock, flags);
-		if (idetape_pipeline_active (tape)) {
+		if (idetape_pipeline_active(tape)) {
 			idetape_wait_for_request(drive, tape->active_data_request);
 			spin_unlock_irqrestore(&tape->spinlock, flags);
 		} else {
 			spin_unlock_irqrestore(&tape->spinlock, flags);
-			idetape_insert_pipeline_into_queue (drive);
-			if (idetape_pipeline_active (tape))
+			idetape_insert_pipeline_into_queue(drive);
+			if (idetape_pipeline_active(tape))
 				continue;
 			/*
 			 *	Linux is short on memory. Fallback to
 			 *	non-pipelined operation mode for this request.
 			 */
-			return idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bh);
+			return idetape_queue_rw_tail(drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bh);
 		}
 	}
 	rq = &new_stage->rq;
-	ide_init_drive_cmd (rq);
+	ide_init_drive_cmd(rq);
 	rq->cmd = IDETAPE_WRITE_RQ;
-	rq->sector = tape->first_frame_position;	/* Doesn't actually matter - We always assume sequential access */
+	/* Doesn't actually matter - We always assume sequential access */
+	rq->sector = tape->first_frame_position;
 	rq->nr_sectors = rq->current_nr_sectors = blocks;
 
 	idetape_switch_buffers (tape, new_stage);
 	idetape_init_stage(drive, new_stage, OS_FRAME_TYPE_DATA, tape->logical_blk_num);
 	tape->logical_blk_num++;
-	idetape_add_stage_tail (drive, new_stage);
+	idetape_add_stage_tail(drive, new_stage);
 	tape->pipeline_head++;
 #if USE_IOTRACE
 	IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
@@ -3813,10 +4038,11 @@
 		} else if (tape->onstream) {
 			idetape_update_stats(drive);
 			if (tape->cur_frames > 5)
-				idetape_insert_pipeline_into_queue (drive);
+				idetape_insert_pipeline_into_queue(drive);
 		}
 	}
-	if (test_and_clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags))		/* Return a deferred error */
+	if (test_and_clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags))
+		/* Return a deferred error */
 		return -EIO;
 	return blocks;
 }
@@ -3831,7 +4057,7 @@
 	unsigned long flags;
 
 	while (tape->next_stage || idetape_pipeline_active(tape)) {
-		idetape_insert_pipeline_into_queue (drive);
+		idetape_insert_pipeline_into_queue(drive);
 		spin_lock_irqsave(&tape->spinlock, flags);
 		if (idetape_pipeline_active(tape))
 			idetape_wait_for_request(drive, tape->active_data_request);
@@ -3847,11 +4073,12 @@
 	
 #if IDETAPE_DEBUG_BUGS
 	if (tape->chrdev_direction != idetape_direction_write) {
-		printk (KERN_ERR "ide-tape: bug: Trying to empty write pipeline, but we are not writing.\n");
+		printk(KERN_ERR "ide-tape: bug: Trying to empty write "
+			"pipeline, but we are not writing.\n");
 		return;
 	}
 	if (tape->merge_stage_size > tape->stage_size) {
-		printk (KERN_ERR "ide-tape: bug: merge_buffer too big\n");
+		printk(KERN_ERR "ide-tape: bug: merge_buffer too big\n");
 		tape->merge_stage_size = tape->stage_size;
 	}
 #endif /* IDETAPE_DEBUG_BUGS */
@@ -3878,15 +4105,15 @@
 				bh = bh->b_reqnext;
 			}
 		}
-		(void) idetape_add_chrdev_write_request (drive, blocks);
+		(void) idetape_add_chrdev_write_request(drive, blocks);
 		tape->merge_stage_size = 0;
 	}
-	idetape_wait_for_pipeline (drive);
+	idetape_wait_for_pipeline(drive);
 	if (tape->merge_stage != NULL) {
-		__idetape_kfree_stage (tape->merge_stage);
+		__idetape_kfree_stage(tape->merge_stage);
 		tape->merge_stage = NULL;
 	}
-	clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags);
+	clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 	tape->chrdev_direction = idetape_direction_none;
 
 	/*
@@ -3897,10 +4124,14 @@
 	 */
 	tape->max_stages = tape->min_pipeline;
 #if IDETAPE_DEBUG_BUGS
-	if (tape->first_stage != NULL || tape->next_stage != NULL || tape->last_stage != NULL || tape->nr_stages != 0) {
-		printk (KERN_ERR "ide-tape: ide-tape pipeline bug, "
-		"first_stage %p, next_stage %p, last_stage %p, nr_stages %d\n",
-		tape->first_stage, tape->next_stage, tape->last_stage, tape->nr_stages);
+	if (tape->first_stage != NULL ||
+	    tape->next_stage != NULL ||
+	    tape->last_stage != NULL ||
+	    tape->nr_stages != 0) {
+		printk(KERN_ERR "ide-tape: ide-tape pipeline bug, "
+			"first_stage %p, next_stage %p, last_stage %p, "
+			"nr_stages %d\n", tape->first_stage,
+			tape->next_stage, tape->last_stage, tape->nr_stages);
 	}
 #endif /* IDETAPE_DEBUG_BUGS */
 }
@@ -3928,14 +4159,16 @@
 	int bytes_read;
 	int blocks = tape->capabilities.ctl;
 
-	if (tape->chrdev_direction != idetape_direction_read) {		/* Initialize read operation */
+	/* Initialize read operation */
+	if (tape->chrdev_direction != idetape_direction_read) {
 		if (tape->chrdev_direction == idetape_direction_write) {
-			idetape_empty_write_pipeline (drive);
-			idetape_flush_tape_buffers (drive);
+			idetape_empty_write_pipeline(drive);
+			idetape_flush_tape_buffers(drive);
 		}
 #if IDETAPE_DEBUG_BUGS
 		if (tape->merge_stage || tape->merge_stage_size) {
-			printk (KERN_ERR "ide-tape: merge_stage_size should be 0 now\n");
+			printk(KERN_ERR "ide-tape: merge_stage_size "
+				"should be 0 now\n");
 			tape->merge_stage_size = 0;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
@@ -3949,9 +4182,9 @@
 		 *	is switched from completion mode to buffer available
 		 *	mode.
 		 */
-		bytes_read = idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 0, tape->merge_stage->bh);
+		bytes_read = idetape_queue_rw_tail(drive, IDETAPE_READ_RQ, 0, tape->merge_stage->bh);
 		if (bytes_read < 0) {
-			kfree (tape->merge_stage);
+			__idetape_kfree_stage(tape->merge_stage);
 			tape->merge_stage = NULL;
 			tape->chrdev_direction = idetape_direction_none;
 			return bytes_read;
@@ -3959,18 +4192,19 @@
 	}
 	if (tape->restart_speed_control_req)
 		idetape_restart_speed_control(drive);
-	ide_init_drive_cmd (&rq);
+	ide_init_drive_cmd(&rq);
 	rq.cmd = IDETAPE_READ_RQ;
 	rq.sector = tape->first_frame_position;
 	rq.nr_sectors = rq.current_nr_sectors = blocks;
-	if (!test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags) && tape->nr_stages <= max_stages) {
-		new_stage = idetape_kmalloc_stage (tape);
+	if (!test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags) &&
+	    tape->nr_stages < max_stages) {
+		new_stage = idetape_kmalloc_stage(tape);
 		while (new_stage != NULL) {
 			new_stage->rq = rq;
-			idetape_add_stage_tail (drive, new_stage);
+			idetape_add_stage_tail(drive, new_stage);
 			if (tape->nr_stages >= max_stages)
 				break;
-			new_stage = idetape_kmalloc_stage (tape);
+			new_stage = idetape_kmalloc_stage(tape);
 		}
 	}
 	if (!idetape_pipeline_active(tape)) {
@@ -3979,11 +4213,11 @@
 			tape->insert_time = jiffies;
 			tape->insert_size = 0;
 			tape->insert_speed = 0;
-			idetape_insert_pipeline_into_queue (drive);
+			idetape_insert_pipeline_into_queue(drive);
 		} else if (tape->onstream) {
 			idetape_update_stats(drive);
 			if (tape->cur_frames < tape->max_frames - 5)
-				idetape_insert_pipeline_into_queue (drive);
+				idetape_insert_pipeline_into_queue(drive);
 		}
 	}
 	return 0;
@@ -4000,7 +4234,9 @@
 	 */
 	while (1) {
 		if (cnt++ > 1000) {   /* AJN: was 100 */
-			printk(KERN_INFO "ide-tape: %s: couldn't find logical block %d, aborting\n", tape->name, logical_blk_num);
+			printk(KERN_INFO "ide-tape: %s: couldn't find "
+				"logical block %d, aborting\n",
+				tape->name, logical_blk_num);
 			return 0;
 		}
 		idetape_initiate_read(drive, max_stages);
@@ -4012,21 +4248,31 @@
 #endif
 				clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 				position = idetape_read_position(drive);
-				printk(KERN_INFO "ide-tape: %s: blank block detected at %d\n", tape->name, position);
+				printk(KERN_INFO "ide-tape: %s: blank block "
+					"detected at %d\n", tape->name,
+					position);
 				if (position >= 3000 && position < 3080)
-					position += 32;  /* Why is this check and number ??? MM */
-				if (position >= OS_DATA_ENDFRAME1 && position < 3000)
+					/* Why is this check and number ??? MM */
+					position += 32;
+				if (position >= OS_DATA_ENDFRAME1 &&
+				    position < 3000)
 					position = 3000;
 				else
 					/*
-					 * compensate for write errors that generally skip 80 frames,
-					 * expect around 20 read errors in a row...
+					 * compensate for write errors that
+					 * generally skip 80 frames, expect
+					 * around 20 read errors in a row...
 					 */
 					position += 60;
-				if (position >= OS_DATA_ENDFRAME1 && position < 3000)
+				if (position >= OS_DATA_ENDFRAME1 &&
+				    position < 3000)
 					position = 3000;
 				printk(KERN_INFO "ide-tape: %s: positioning tape to block %d\n", tape->name, position);
-				if (position == 3000)  /* seems to be needed to correctly position at block 3000 MM */
+
+				/* seems to be needed to correctly position
+				 * at block 3000 MM
+				 */
+				if (position == 3000)
 					idetape_position_tape(drive, 0, 0, 0);
 				idetape_position_tape(drive, position, 0, 0);
 				cnt += 40;
@@ -4069,10 +4315,17 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_add_chrdev_read_request, %d blocks\n", blocks);
+		printk(KERN_INFO "ide-tape: Reached %s, %d blocks\n",
+			__FUNCTION__, blocks);
 #endif /* IDETAPE_DEBUG_LOG */
 
 	/*
+	 * If we are at a filemark, return a read length of 0
+	 */
+	if (test_bit(IDETAPE_FILEMARK, &tape->flags))
+		return 0;
+
+	/*
 	 * Wait for the next logical block to be available at the head
 	 * of the pipeline
 	 */
@@ -4083,38 +4336,35 @@
 		}
 		if (test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags))
 		 	return 0;
-		return idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, blocks, tape->merge_stage->bh);
+		return idetape_queue_rw_tail(drive, IDETAPE_READ_RQ, blocks, tape->merge_stage->bh);
 	}
 	rq_ptr = &tape->first_stage->rq;
 	bytes_read = tape->tape_block_size * (rq_ptr->nr_sectors - rq_ptr->current_nr_sectors);
 	rq_ptr->nr_sectors = rq_ptr->current_nr_sectors = 0;
 
 
-	if (tape->onstream && !tape->raw && tape->first_stage->aux->frame_type == OS_FRAME_TYPE_EOD) {
+	if (tape->onstream && !tape->raw &&
+	    tape->first_stage->aux->frame_type == OS_FRAME_TYPE_EOD) {
 #if ONSTREAM_DEBUG
 		if (tape->debug_level >= 2)
-			printk(KERN_INFO "ide-tape: %s: EOD reached\n", tape->name);
+			printk(KERN_INFO "ide-tape: %s: EOD reached\n",
+				tape->name);
 #endif
 		return 0;
 	}
 	if (rq_ptr->errors == IDETAPE_ERROR_EOD)
 		return 0;
-	if (rq_ptr->errors == IDETAPE_ERROR_FILEMARK) {
-		idetape_switch_buffers (tape, tape->first_stage);
-		set_bit (IDETAPE_FILEMARK, &tape->flags);
-#if USE_IOTRACE
-		IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
-#endif
-		calculate_speeds(drive);
-	} else {
-		idetape_switch_buffers (tape, tape->first_stage);
+	else {
+		idetape_switch_buffers(tape, tape->first_stage);
 		if (rq_ptr->errors == IDETAPE_ERROR_GENERAL) {
 #if ONSTREAM_DEBUG
 			if (tape->debug_level >= 1)
-				printk(KERN_INFO "ide-tape: error detected, bytes_read %d\n", bytes_read);
+				printk(KERN_INFO "ide-tape: error detected, "
+					"bytes_read %d\n", bytes_read);
 #endif
 		}
-		clear_bit (IDETAPE_FILEMARK, &tape->flags);
+		if (rq_ptr->errors == IDETAPE_ERROR_FILEMARK)
+			set_bit(IDETAPE_FILEMARK, &tape->flags);
 		spin_lock_irqsave(&tape->spinlock, flags);
 		idetape_remove_stage_head (drive);
 		spin_unlock_irqrestore(&tape->spinlock, flags);
@@ -4126,9 +4376,10 @@
 		calculate_speeds(drive);
 	}
 #if IDETAPE_DEBUG_BUGS
-	if (bytes_read > blocks*tape->tape_block_size) {
-		printk (KERN_ERR "ide-tape: bug: trying to return more bytes than requested\n");
-		bytes_read=blocks*tape->tape_block_size;
+	if (bytes_read > blocks * tape->tape_block_size) {
+		printk(KERN_ERR "ide-tape: bug: trying to return more "
+			"bytes than requested\n");
+		bytes_read = blocks * tape->tape_block_size;
 	}
 #endif /* IDETAPE_DEBUG_BUGS */
 	return (bytes_read);
@@ -4142,16 +4393,16 @@
 	
 	while (bcount) {
 		bh = tape->merge_stage->bh;
-		count = IDE_MIN (tape->stage_size, bcount);
+		count = IDE_MIN(tape->stage_size, bcount);
 		bcount -= count;
 		blocks = count / tape->tape_block_size;
 		while (count) {
 			atomic_set(&bh->b_count, IDE_MIN (count, bh->b_size));
-			memset (bh->b_data, 0, atomic_read(&bh->b_count));
+			memset(bh->b_data, 0, atomic_read(&bh->b_count));
 			count -= atomic_read(&bh->b_count);
 			bh = bh->b_reqnext;
 		}
-		idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bh);
+		idetape_queue_rw_tail(drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bh);
 	}
 }
 
@@ -4162,7 +4413,7 @@
 	struct request *rq;
 	int size = 0;
 
-	idetape_wait_for_pipeline (drive);
+	idetape_wait_for_pipeline(drive);
 	stage = tape->first_stage;
 	while (stage != NULL) {
 		rq = &stage->rq;
@@ -4187,16 +4438,16 @@
 	idetape_tape_t *tape = drive->driver_data;
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 2)
-		printk (KERN_INFO "ide-tape: Reached idetape_rewind_tape\n");
+		printk(KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */	
 	
-	idetape_create_rewind_cmd (drive, &pc);
-	retval = idetape_queue_pc_tail (drive, &pc);
+	idetape_create_rewind_cmd(drive, &pc);
+	retval = idetape_queue_pc_tail(drive, &pc);
 	if (retval)
 		return retval;
 
-	idetape_create_read_position_cmd (&pc);
-	retval = idetape_queue_pc_tail (drive, &pc);
+	idetape_create_read_position_cmd(&pc);
+	retval = idetape_queue_pc_tail(drive, &pc);
 	if (retval)
 		return retval;
 	tape->logical_blk_num = 0;
@@ -4218,7 +4469,7 @@
 
 #if IDETAPE_DEBUG_LOG	
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_blkdev_ioctl\n");
+		printk(KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 	switch (cmd) {
 		case 0x0340:
@@ -4248,7 +4499,7 @@
 {
 	MOD_INC_USE_COUNT;
 #if ONSTREAM_DEBUG
-        printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_blkdev_open\n");
+        printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in %s\n", __FUNCTION__);
 #endif
 	return 0;
 }
@@ -4257,7 +4508,7 @@
 {
 	MOD_DEC_USE_COUNT;
 #if ONSTREAM_DEBUG
-        printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_blkdev_release\n");
+        printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in %s\n", __FUNCTION__);
 #endif
 }
 
@@ -4268,7 +4519,7 @@
 {
 	idetape_tape_t *tape = drive->driver_data;
 	if (tape != NULL)
-		set_bit (IDETAPE_IGNORE_DSC, &tape->flags);
+		set_bit(IDETAPE_IGNORE_DSC, &tape->flags);
 }
 
 /*
@@ -4291,7 +4542,8 @@
 	unsigned long flags;
 
 	if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
-		printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks_bwd\n", tape->name);
+		printk(KERN_INFO "ide-tape: %s: couldn't get logical blk "
+			"num in space_filemarks_bwd\n", tape->name);
 		return -EIO;
 	}
 	while (cnt != mt_count) {
@@ -4300,16 +4552,20 @@
 			return -EIO;
 #if ONSTREAM_DEBUG
 		if (tape->debug_level >= 2)
-			printk(KERN_INFO "ide-tape: positioning to last mark at %d\n", last_mark_addr);
+			printk(KERN_INFO "ide-tape: positioning to last "
+			"mark at %d\n", last_mark_addr);
 #endif
 		idetape_position_tape(drive, last_mark_addr, 0, 0);
 		cnt++;
 		if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
-			printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks\n", tape->name);
+			printk(KERN_INFO "ide-tape: %s: couldn't get logical "
+				"blk num in space_filemarks\n", tape->name);
 			return -EIO;
 		}
 		if (tape->first_stage->aux->frame_type != OS_FRAME_TYPE_MARKER) {
-			printk(KERN_INFO "ide-tape: %s: expected to find marker at block %d, not found\n", tape->name, last_mark_addr);
+			printk(KERN_INFO "ide-tape: %s: expected to find "
+				"marker at block %d, not found\n",
+				tape->name, last_mark_addr);
 			return -EIO;
 		}
 	}
@@ -4334,12 +4590,14 @@
 	unsigned long flags;
 
 	if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
-		printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks_fwd\n", tape->name);
+		printk(KERN_INFO "ide-tape: %s: couldn't get logical blk "
+			"num in space_filemarks_fwd\n", tape->name);
 		return -EIO;
 	}
 	while (1) {
 		if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
-			printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks\n", tape->name);
+			printk(KERN_INFO "ide-tape: %s: couldn't get logical "
+				"blk num in space_filemarks\n", tape->name);
 			return -EIO;
 		}
 		if (tape->first_stage->aux->frame_type == OS_FRAME_TYPE_MARKER)
@@ -4347,19 +4605,20 @@
 		if (tape->first_stage->aux->frame_type == OS_FRAME_TYPE_EOD) {
 #if ONSTREAM_DEBUG
 			if (tape->debug_level >= 2)
-				printk(KERN_INFO "ide-tape: %s: space_fwd: EOD reached\n", tape->name);
+				printk(KERN_INFO "ide-tape: %s: space_fwd: "
+					"EOD reached\n", tape->name);
 #endif
 			return -EIO;
 		}
 		if (cnt == mt_count)
 			break;
 		spin_lock_irqsave(&tape->spinlock, flags);
-		idetape_remove_stage_head (drive);
+		idetape_remove_stage_head(drive);
 		spin_unlock_irqrestore(&tape->spinlock, flags);
 	}
 	if (mt_op == MTFSF) {
 		spin_lock_irqsave(&tape->spinlock, flags);
-		idetape_remove_stage_head (drive);
+		idetape_remove_stage_head(drive);
 		tape->logical_blk_num++;
 		spin_unlock_irqrestore(&tape->spinlock, flags);
 	}
@@ -4377,7 +4636,8 @@
 	unsigned long flags;
 
 	if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
-		printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks_fwd\n", tape->name);
+		printk(KERN_INFO "ide-tape: %s: couldn't get logical blk "
+			"num in space_filemarks_fwd\n", tape->name);
 		return -EIO;
 	}
 
@@ -4390,22 +4650,27 @@
 		if (tape->first_stage->aux->frame_type == OS_FRAME_TYPE_EOD) {
 #if ONSTREAM_DEBUG
 			if (tape->debug_level >= 2)
-				printk(KERN_INFO "ide-tape: %s: space_fwd: EOD reached\n", tape->name);
+				printk(KERN_INFO "ide-tape: %s: space_fwd: "
+					"EOD reached\n", tape->name);
 #endif
 			return -EIO;
 		}
 		if (ntohl(tape->first_stage->aux->filemark_cnt) == 0) {
 			if (tape->first_mark_addr == -1) {
-				printk(KERN_INFO "ide-tape: %s: reverting to slow filemark space\n", tape->name);
+				printk(KERN_INFO "ide-tape: %s: reverting to "
+					"slow filemark space\n", tape->name);
 				return idetape_onstream_space_over_filemarks_forward_slow(drive, mt_op, mt_count);
 			}
 			idetape_position_tape(drive, tape->first_mark_addr, 0, 0);
 			if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
-				printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks_fwd_fast\n", tape->name);
+				printk(KERN_INFO "ide-tape: %s: couldn't get "
+					"logical blk num in %s\n",							__FUNCTION__, tape->name);
 				return -EIO;
 			}
 			if (tape->first_stage->aux->frame_type != OS_FRAME_TYPE_MARKER) {
-				printk(KERN_INFO "ide-tape: %s: expected to find filemark at %d\n", tape->name, tape->first_mark_addr);
+				printk(KERN_INFO "ide-tape: %s: expected to "
+					"find filemark at %d\n",
+					tape->name, tape->first_mark_addr);
 				return -EIO;
 			}
 		} else {
@@ -4418,7 +4683,8 @@
 	while (cnt != mt_count) {
 		next_mark_addr = ntohl(tape->first_stage->aux->next_mark_addr);
 		if (!next_mark_addr || next_mark_addr > tape->eod_frame_addr) {
-			printk(KERN_INFO "ide-tape: %s: reverting to slow filemark space\n", tape->name);
+			printk(KERN_INFO "ide-tape: %s: reverting to slow "
+				"filemark space\n", tape->name);
 			return idetape_onstream_space_over_filemarks_forward_slow(drive, mt_op, mt_count - cnt);
 #if ONSTREAM_DEBUG
 		} else if (tape->debug_level >= 2) {
@@ -4428,17 +4694,20 @@
 		idetape_position_tape(drive, next_mark_addr, 0, 0);
 		cnt++;
 		if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
-			printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks\n", tape->name);
+			printk(KERN_INFO "ide-tape: %s: couldn't get logical "
+				"blk num in space_filemarks\n", tape->name);
 			return -EIO;
 		}
 		if (tape->first_stage->aux->frame_type != OS_FRAME_TYPE_MARKER) {
-			printk(KERN_INFO "ide-tape: %s: expected to find marker at block %d, not found\n", tape->name, next_mark_addr);
+			printk(KERN_INFO "ide-tape: %s: expected to find "
+				"marker at block %d, not found\n",
+				tape->name, next_mark_addr);
 			return -EIO;
 		}
 	}
 	if (mt_op == MTFSF) {
 		spin_lock_irqsave(&tape->spinlock, flags);
-		idetape_remove_stage_head (drive);
+		idetape_remove_stage_head(drive);
 		tape->logical_blk_num++;
 		spin_unlock_irqrestore(&tape->spinlock, flags);
 	}
@@ -4478,6 +4747,14 @@
 		tape->restart_speed_control_req = 1;
 		return retval;
 	}
+ 
+	if (mt_count == 0)
+		return 0;
+	if (MTBSF == mt_op || MTBSFM == mt_op) {
+		if (!tape->capabilities.sprev)
+			return -EIO;
+		mt_count = - mt_count;
+	}
 
 	if (tape->chrdev_direction == idetape_direction_read) {
 		/*
@@ -4485,28 +4762,36 @@
 		 *	filemarks.
 		 */
 		tape->merge_stage_size = 0;
-		clear_bit (IDETAPE_FILEMARK, &tape->flags);
+		if (test_and_clear_bit(IDETAPE_FILEMARK, &tape->flags))
+			++count;
 		while (tape->first_stage != NULL) {
-			idetape_wait_first_stage(drive);
-			if (tape->first_stage->rq.errors == IDETAPE_ERROR_FILEMARK)
-				count++;
 			if (count == mt_count) {
-				switch (mt_op) {
-					case MTFSF:
-						spin_lock_irqsave(&tape->spinlock, flags);
-						idetape_remove_stage_head (drive);
-						spin_unlock_irqrestore(&tape->spinlock, flags);
-					case MTFSFM:
-						return (0);
-					default:
-						break;
-				}
+				if (mt_op == MTFSFM)
+					set_bit(IDETAPE_FILEMARK, &tape->flags);
+				return 0;
 			}
 			spin_lock_irqsave(&tape->spinlock, flags);
-			idetape_remove_stage_head (drive);
-			spin_unlock_irqrestore(&tape->spinlock, flags);
+			if (tape->first_stage == tape->active_stage) {
+				/*
+				 *	We have reached the active stage in the read pipeline.
+				 *	There is no point in allowing the drive to continue
+				 *	reading any farther, so we stop the pipeline.
+				 *
+				 *	This section should be moved to a separate subroutine,
+				 *	because a similar function is performed in
+				 *	__idetape_discard_read_pipeline(), for example.
+				 */
+				tape->next_stage = NULL;
+				spin_unlock_irqrestore(&tape->spinlock, flags);
+				idetape_wait_first_stage(drive);
+				tape->next_stage = tape->first_stage->next;
+			} else
+				spin_unlock_irqrestore(&tape->spinlock, flags);
+			if (tape->first_stage->rq.errors == IDETAPE_ERROR_FILEMARK)
+				++count;
+			idetape_remove_stage_head(drive);
 		}
-		idetape_discard_read_pipeline (drive, 1);
+		idetape_discard_read_pipeline(drive, 0);
 	}
 
 	/*
@@ -4515,27 +4800,20 @@
 	 */
 	switch (mt_op) {
 		case MTFSF:
-			idetape_create_space_cmd (&pc,mt_count-count,IDETAPE_SPACE_OVER_FILEMARK);
-			return (idetape_queue_pc_tail (drive, &pc));
-		case MTFSFM:
-			if (!tape->capabilities.sprev)
-				return (-EIO);
-			retval = idetape_space_over_filemarks (drive, MTFSF, mt_count-count);
-			if (retval) return (retval);
-			return (idetape_space_over_filemarks (drive, MTBSF, 1));
 		case MTBSF:
-			if (!tape->capabilities.sprev)
-				return (-EIO);
-			idetape_create_space_cmd (&pc,-(mt_count+count),IDETAPE_SPACE_OVER_FILEMARK);
-			return (idetape_queue_pc_tail (drive, &pc));
+			idetape_create_space_cmd(&pc,mt_count-count,IDETAPE_SPACE_OVER_FILEMARK);
+			return (idetape_queue_pc_tail(drive, &pc));
+		case MTFSFM:
 		case MTBSFM:
 			if (!tape->capabilities.sprev)
 				return (-EIO);
-			retval = idetape_space_over_filemarks (drive, MTBSF, mt_count+count);
+			retval = idetape_space_over_filemarks(drive, MTFSF, mt_count-count);
 			if (retval) return (retval);
-			return (idetape_space_over_filemarks (drive, MTFSF, 1));
+			count = (MTBSFM == mt_op ? 1 : -1);
+			return (idetape_space_over_filemarks(drive, MTFSF, count));
 		default:
-			printk (KERN_ERR "ide-tape: MTIO operation %d not supported\n",mt_op);
+			printk(KERN_ERR "ide-tape: MTIO operation %d not "
+				"supported\n", mt_op);
 			return (-EIO);
 	}
 }
@@ -4562,7 +4840,7 @@
 				    size_t count, loff_t *ppos)
 {
 	struct inode *inode = file->f_dentry->d_inode;
-	ide_drive_t *drive = get_drive_ptr (inode->i_rdev);
+	ide_drive_t *drive = get_drive_ptr(inode->i_rdev);
 	idetape_tape_t *tape = drive->driver_data;
 	ssize_t bytes_read,temp, actually_read = 0, rc;
 
@@ -4571,17 +4849,21 @@
 		return -ENXIO;
 	}
 	if (tape->onstream && (count != tape->tape_block_size)) {
-		printk(KERN_ERR "ide-tape: %s: use %d bytes as block size (%Zd used)\n", tape->name, tape->tape_block_size, count);
+		printk(KERN_ERR "ide-tape: %s: use %d bytes as block size "
+			"(%Zd used)\n", tape->name,
+			tape->tape_block_size, count);
 		return -EINVAL;
 	}
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 3)
-		printk (KERN_INFO "ide-tape: Reached idetape_chrdev_read, count %Zd\n", count);
+		printk (KERN_INFO "ide-tape: Reached %s, count %Zd\n",
+			__FUNCTION__, count);
 #endif /* IDETAPE_DEBUG_LOG */
 
 	if (tape->chrdev_direction != idetape_direction_read) {
-		if (test_bit (IDETAPE_DETECT_BS, &tape->flags))
-			if (count > tape->tape_block_size && (count % tape->tape_block_size) == 0)
+		if (test_bit(IDETAPE_DETECT_BS, &tape->flags))
+			if (count > tape->tape_block_size &&
+			    (count % tape->tape_block_size) == 0)
 				tape->user_bs_factor = count / tape->tape_block_size;
 	}
 	if ((rc = idetape_initiate_read(drive, tape->max_stages)) < 0)
@@ -4589,42 +4871,45 @@
 	if (count == 0)
 		return (0);
 	if (tape->merge_stage_size) {
-		actually_read = IDE_MIN (tape->merge_stage_size, count);
-		idetape_copy_stage_to_user (tape, buf, tape->merge_stage, actually_read);
+		actually_read = IDE_MIN(tape->merge_stage_size, count);
+		idetape_copy_stage_to_user(tape, buf, tape->merge_stage, actually_read);
 		buf += actually_read;
 		tape->merge_stage_size -= actually_read;
 		count -= actually_read;
 	}
 	while (count >= tape->stage_size) {
-		bytes_read = idetape_add_chrdev_read_request (drive, tape->capabilities.ctl);
+		bytes_read = idetape_add_chrdev_read_request(drive, tape->capabilities.ctl);
 		if (bytes_read <= 0)
 			goto finish;
-		idetape_copy_stage_to_user (tape, buf, tape->merge_stage, bytes_read);
+		idetape_copy_stage_to_user(tape, buf, tape->merge_stage, bytes_read);
 		buf += bytes_read;
 		count -= bytes_read;
 		actually_read += bytes_read;
 	}
 	if (count) {
-		bytes_read=idetape_add_chrdev_read_request (drive, tape->capabilities.ctl);
+		bytes_read=idetape_add_chrdev_read_request(drive, tape->capabilities.ctl);
 		if (bytes_read <= 0)
 			goto finish;
-		temp = IDE_MIN (count, bytes_read);
-		idetape_copy_stage_to_user (tape, buf, tape->merge_stage, temp);
+		temp = IDE_MIN(count, bytes_read);
+		idetape_copy_stage_to_user(tape, buf, tape->merge_stage, temp);
 		actually_read += temp;
 		tape->merge_stage_size = bytes_read-temp;
 	}
 finish:
-	if (!actually_read && test_bit (IDETAPE_FILEMARK, &tape->flags)) {
+	if (!actually_read && test_bit(IDETAPE_FILEMARK, &tape->flags)) {
 #if IDETAPE_DEBUG_LOG
 		if (tape->debug_level >= 2)
-			printk(KERN_INFO "ide-tape: %s: spacing over filemark\n", tape->name);
+			printk(KERN_INFO "ide-tape: %s: spacing over "
+				"filemark\n", tape->name);
 #endif
 		idetape_space_over_filemarks (drive, MTFSF, 1);
 		return 0;
 	}
-	if (tape->onstream && !actually_read && test_and_clear_bit(IDETAPE_READ_ERROR, &tape->flags)) {
-		printk(KERN_ERR "ide-tape: %s: unrecovered read error on logical block number %d, skipping\n",
-					tape->name, tape->logical_blk_num);
+	if (tape->onstream && !actually_read &&
+	    test_and_clear_bit(IDETAPE_READ_ERROR, &tape->flags)) {
+		printk(KERN_ERR "ide-tape: %s: unrecovered read error on "
+			"logical block number %d, skipping\n",
+			tape->name, tape->logical_blk_num);
 		tape->logical_blk_num++;
 		return -EIO;
 	}
@@ -4649,21 +4934,25 @@
 	position = idetape_read_position(drive);
 #if ONSTREAM_DEBUG
 	if (tape->debug_level >= 2)
-		printk(KERN_INFO "ide-tape: current position (2) %d, lblk %d\n", position, tape->logical_blk_num);
+		printk(KERN_INFO "ide-tape: current position (2) %d, "
+			"lblk %d\n", position, tape->logical_blk_num);
 	if (tape->debug_level >= 2)
-		printk(KERN_INFO "ide-tape: current position (2) tape block %d\n", tape->last_frame_position);
+		printk(KERN_INFO "ide-tape: current position (2) tape "
+			"block %d\n", tape->last_frame_position);
 #endif
 	idetape_position_tape(drive, last_mark_addr, 0, 0);
-	if (!idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 1, stage->bh)) {
-		printk(KERN_INFO "ide-tape: %s: couldn't read last marker\n", tape->name);
-		__idetape_kfree_stage (stage);
+	if (!idetape_queue_rw_tail(drive, IDETAPE_READ_RQ, 1, stage->bh)) {
+		printk(KERN_INFO "ide-tape: %s: couldn't read last marker\n",
+			tape->name);
+		__idetape_kfree_stage(stage);
 		idetape_position_tape(drive, position, 0, 0);
 		return;
 	}
 	aux = stage->aux;
 	if (aux->frame_type != OS_FRAME_TYPE_MARKER) {
-		printk(KERN_INFO "ide-tape: %s: expected to find marker at addr %d\n", tape->name, last_mark_addr);
-		__idetape_kfree_stage (stage);
+		printk(KERN_INFO "ide-tape: %s: expected to find marker "
+			"at addr %d\n", tape->name, last_mark_addr);
+		__idetape_kfree_stage(stage);
 		idetape_position_tape(drive, position, 0, 0);
 		return;
 	}
@@ -4673,13 +4962,14 @@
 #endif
 	aux->next_mark_addr = htonl(next_mark_addr);
 	idetape_position_tape(drive, last_mark_addr, 0, 0);
-	if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bh)) {
-		printk(KERN_INFO "ide-tape: %s: couldn't write back marker frame at %d\n", tape->name, last_mark_addr);
-		__idetape_kfree_stage (stage);
+	if (!idetape_queue_rw_tail(drive, IDETAPE_WRITE_RQ, 1, stage->bh)) {
+		printk(KERN_INFO "ide-tape: %s: couldn't write back marker "
+			"frame at %d\n", tape->name, last_mark_addr);
+		__idetape_kfree_stage(stage);
 		idetape_position_tape(drive, position, 0, 0);
 		return;
 	}
-	__idetape_kfree_stage (stage);
+	__idetape_kfree_stage(stage);
 	idetape_flush_tape_buffers (drive);
 	idetape_position_tape(drive, position, 0, 0);
 	return;
@@ -4702,18 +4992,20 @@
 #if ONSTREAM_DEBUG
 	printk(KERN_INFO "write_filler: positioning failed it returned %d\n", rc);
 #endif
-	if (rc != 0) 
-		return;	/* don't write fillers if we cannot position the tape. */
+	if (rc != 0)
+		/* don't write fillers if we cannot position the tape. */
+		return;
 
 	strcpy(stage->bh->b_data, "Filler");
 	while (cnt--) {
-		if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bh)) {
-			printk(KERN_INFO "ide-tape: %s: write_filler: couldn't write header frame\n", tape->name);
-			__idetape_kfree_stage (stage);
+		if (!idetape_queue_rw_tail(drive, IDETAPE_WRITE_RQ, 1, stage->bh)) {
+			printk(KERN_INFO "ide-tape: %s: write_filler: "
+				"couldn't write header frame\n", tape->name);
+			__idetape_kfree_stage(stage);
 			return;
 		}
 	}
-	__idetape_kfree_stage (stage);
+	__idetape_kfree_stage(stage);
 }
 
 static void __idetape_write_header (ide_drive_t *drive, int block, int cnt)
@@ -4741,14 +5033,14 @@
 	header.partition.eod_frame_addr = htonl(tape->eod_frame_addr);
 	memcpy(stage->bh->b_data, &header, sizeof(header));
 	while (cnt--) {
-		if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bh)) {
+		if (!idetape_queue_rw_tail(drive, IDETAPE_WRITE_RQ, 1, stage->bh)) {
 			printk(KERN_INFO "ide-tape: %s: couldn't write header frame\n", tape->name);
-			__idetape_kfree_stage (stage);
+			__idetape_kfree_stage(stage);
 			return;
 		}
 	}
-	__idetape_kfree_stage (stage);
-	idetape_flush_tape_buffers (drive);
+	__idetape_kfree_stage(stage);
+	idetape_flush_tape_buffers(drive);
 }
 
 static void idetape_write_header (ide_drive_t *drive, int locate_eod)
@@ -4767,7 +5059,9 @@
 	if (locate_eod) {
 #if ONSTREAM_DEBUG
 		if (tape->debug_level >= 2)
-			printk(KERN_INFO "ide-tape: %s: locating back to eod frame addr %d\n", tape->name, tape->eod_frame_addr);
+			printk(KERN_INFO "ide-tape: %s: locating back to "
+				"eod frame addr %d\n", tape->name,
+				tape->eod_frame_addr);
 #endif
 		idetape_position_tape(drive, tape->eod_frame_addr, 0, 0);
 	}
@@ -4777,7 +5071,7 @@
 				     size_t count, loff_t *ppos)
 {
 	struct inode *inode = file->f_dentry->d_inode;
-	ide_drive_t *drive = get_drive_ptr (inode->i_rdev);
+	ide_drive_t *drive = get_drive_ptr(inode->i_rdev);
 	idetape_tape_t *tape = drive->driver_data;
 	ssize_t retval, actually_written = 0;
 	int position;
@@ -4794,13 +5088,14 @@
 
 	if (tape->onstream) {
 		if (count != tape->tape_block_size) {
-			printk(KERN_ERR "ide-tape: %s: chrdev_write: use %d bytes as block size (%Zd used)\n",
-					tape->name, tape->tape_block_size, count);
+			printk(KERN_ERR "ide-tape: %s: chrdev_write: "
+				"use %d bytes as block size (%Zd used)\n",
+				tape->name, tape->tape_block_size, count);
 			return -EINVAL;
 		}
 		/*
-		 * Check if we reach the end of the tape. Just assume the whole pipeline
-		 * is filled with write requests!
+		 * Check if we reach the end of the tape. Just assume the whole
+		 * pipeline is filled with write requests!
 		 */
 		if (tape->first_frame_position + tape->nr_stages >= tape->capacity - OS_EW)  {
 #if ONSTREAM_DEBUG
@@ -4812,19 +5107,20 @@
 		}
 	}
 
-	if (tape->chrdev_direction != idetape_direction_write) {	/* Initialize write operation */
+	/* Initialize write operation */
+	if (tape->chrdev_direction != idetape_direction_write) {
 		if (tape->chrdev_direction == idetape_direction_read)
-			idetape_discard_read_pipeline (drive, 1);
+			idetape_discard_read_pipeline(drive, 1);
 #if IDETAPE_DEBUG_BUGS
 		if (tape->merge_stage || tape->merge_stage_size) {
-			printk (KERN_ERR "ide-tape: merge_stage_size should be 0 now\n");
+			printk(KERN_ERR "ide-tape: merge_stage_size should be 0 now\n");
 			tape->merge_stage_size = 0;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		if ((tape->merge_stage = __idetape_kmalloc_stage (tape, 0, 0)) == NULL)
+		if ((tape->merge_stage = __idetape_kmalloc_stage(tape, 0, 0)) == NULL)
 			return -ENOMEM;
 		tape->chrdev_direction = idetape_direction_write;
-		idetape_init_merge_stage (tape);
+		idetape_init_merge_stage(tape);
 
 		if (tape->onstream) {
 			position = idetape_read_position(drive);
@@ -4860,9 +5156,9 @@
 		 *	is switched from completion mode to buffer available
 		 *	mode.
 		 */
-		retval = idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 0, tape->merge_stage->bh);
+		retval = idetape_queue_rw_tail(drive, IDETAPE_WRITE_RQ, 0, tape->merge_stage->bh);
 		if (retval < 0) {
-			kfree (tape->merge_stage);
+			__idetape_kfree_stage(tape->merge_stage);
 			tape->merge_stage = NULL;
 			tape->chrdev_direction = idetape_direction_none;
 			return retval;
@@ -4879,35 +5175,35 @@
 	if (tape->merge_stage_size) {
 #if IDETAPE_DEBUG_BUGS
 		if (tape->merge_stage_size >= tape->stage_size) {
-			printk (KERN_ERR "ide-tape: bug: merge buffer too big\n");
+			printk(KERN_ERR "ide-tape: bug: merge buffer too big\n");
 			tape->merge_stage_size = 0;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		actually_written = IDE_MIN (tape->stage_size - tape->merge_stage_size, count);
-		idetape_copy_stage_from_user (tape, tape->merge_stage, buf, actually_written);
+		actually_written = IDE_MIN(tape->stage_size - tape->merge_stage_size, count);
+		idetape_copy_stage_from_user(tape, tape->merge_stage, buf, actually_written);
 		buf += actually_written;
 		tape->merge_stage_size += actually_written;
 		count -= actually_written;
 
 		if (tape->merge_stage_size == tape->stage_size) {
 			tape->merge_stage_size = 0;
-			retval = idetape_add_chrdev_write_request (drive, tape->capabilities.ctl);
+			retval = idetape_add_chrdev_write_request(drive, tape->capabilities.ctl);
 			if (retval <= 0)
 				return (retval);
 		}
 	}
 	while (count >= tape->stage_size) {
-		idetape_copy_stage_from_user (tape, tape->merge_stage, buf, tape->stage_size);
+		idetape_copy_stage_from_user(tape, tape->merge_stage, buf, tape->stage_size);
 		buf += tape->stage_size;
 		count -= tape->stage_size;
-		retval = idetape_add_chrdev_write_request (drive, tape->capabilities.ctl);
+		retval = idetape_add_chrdev_write_request(drive, tape->capabilities.ctl);
 		actually_written += tape->stage_size;
 		if (retval <= 0)
 			return (retval);
 	}
 	if (count) {
-		actually_written+=count;
-		idetape_copy_stage_from_user (tape, tape->merge_stage, buf, count);
+		actually_written += count;
+		idetape_copy_stage_from_user(tape, tape->merge_stage, buf, count);
 		tape->merge_stage_size += count;
 	}
 	return (actually_written);
@@ -4920,19 +5216,20 @@
 	idetape_pc_t pc;
 
 	if (!tape->onstream) {
-		idetape_create_write_filemark_cmd(drive, &pc, 1);	/* Write a filemark */
-		if (idetape_queue_pc_tail (drive, &pc)) {
-			printk (KERN_ERR "ide-tape: Couldn't write a filemark\n");
+		/* Write a filemark */
+		idetape_create_write_filemark_cmd(drive, &pc, 1);
+		if (idetape_queue_pc_tail(drive, &pc)) {
+			printk(KERN_ERR "ide-tape: Couldn't write a filemark\n");
 			return -EIO;
 		}
 	} else if (!tape->raw) {
 		last_mark_addr = idetape_read_position(drive);
-		tape->merge_stage = __idetape_kmalloc_stage (tape, 1, 0);
+		tape->merge_stage = __idetape_kmalloc_stage(tape, 1, 0);
 		if (tape->merge_stage != NULL) {
 			idetape_init_stage(drive, tape->merge_stage, OS_FRAME_TYPE_MARKER, tape->logical_blk_num);
-			idetape_pad_zeros (drive, tape->stage_size);
+			idetape_pad_zeros(drive, tape->stage_size);
 			tape->logical_blk_num++;
-			__idetape_kfree_stage (tape->merge_stage);
+			__idetape_kfree_stage(tape->merge_stage);
 			tape->merge_stage = NULL;
 		}
 		if (tape->filemark_cnt)
@@ -4950,11 +5247,11 @@
 
 	if (!tape->onstream || tape->raw)
 		return;
-	tape->merge_stage = __idetape_kmalloc_stage (tape, 1, 0);
+	tape->merge_stage = __idetape_kmalloc_stage(tape, 1, 0);
 	if (tape->merge_stage != NULL) {
 		tape->eod_frame_addr = idetape_read_position(drive);
 		idetape_init_stage(drive, tape->merge_stage, OS_FRAME_TYPE_EOD, tape->logical_blk_num);
-		idetape_pad_zeros (drive, tape->stage_size);
+		idetape_pad_zeros(drive, tape->stage_size);
 		__idetape_kfree_stage (tape->merge_stage);
 		tape->merge_stage = NULL;
 	}
@@ -4989,7 +5286,9 @@
 error:
 	tape->speed_control = speed_control;
 	tape->restart_speed_control_req = 1;
-	printk(KERN_INFO "ide-tape: %s: couldn't seek to logical block %d (at %d), %d retries\n", tape->name, logical_blk_num, tape->logical_blk_num, retries);
+	printk(KERN_INFO "ide-tape: %s: couldn't seek to logical block %d "
+		"(at %d), %d retries\n", tape->name, logical_blk_num,
+		tape->logical_blk_num, retries);
 	return -EIO;
 ok:
 	tape->speed_control = speed_control;
@@ -5068,7 +5367,8 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 1)
-		printk (KERN_INFO "ide-tape: Handling MTIOCTOP ioctl: mt_op=%d, mt_count=%d\n",mt_op,mt_count);
+		printk(KERN_INFO "ide-tape: Handling MTIOCTOP "
+			"ioctl: mt_op=%d, mt_count=%d\n", mt_op, mt_count);
 #endif /* IDETAPE_DEBUG_LOG */
 	/*
 	 *	Commands which need our pipelined read-ahead stages.
@@ -5080,41 +5380,41 @@
 		case MTBSFM:
 			if (!mt_count)
 				return (0);
-			return (idetape_space_over_filemarks (drive,mt_op,mt_count));
+			return (idetape_space_over_filemarks(drive,mt_op,mt_count));
 		default:
 			break;
 	}
 	switch (mt_op) {
 		case MTWEOF:
-			idetape_discard_read_pipeline (drive, 1);
+			idetape_discard_read_pipeline(drive, 1);
 			for (i = 0; i < mt_count; i++) {
 				retval = idetape_write_filemark(drive);
 				if (retval) return retval;
 			}
 			return (0);
 		case MTREW:
-			idetape_discard_read_pipeline (drive, 0);
+			idetape_discard_read_pipeline(drive, 0);
 			if (idetape_rewind_tape(drive))
 				return -EIO;
 			if (tape->onstream && !tape->raw)
 				return idetape_position_tape(drive, OS_DATA_STARTFRAME1, 0, 0);
 			return 0;
 		case MTLOAD:
-			idetape_discard_read_pipeline (drive, 0);
-			idetape_create_load_unload_cmd (drive, &pc, IDETAPE_LU_LOAD_MASK);
-			return (idetape_queue_pc_tail (drive, &pc));
+			idetape_discard_read_pipeline(drive, 0);
+			idetape_create_load_unload_cmd(drive, &pc, IDETAPE_LU_LOAD_MASK);
+			return (idetape_queue_pc_tail(drive, &pc));
 		case MTUNLOAD:
 		case MTOFFL:
-			idetape_discard_read_pipeline (drive, 0);
-			idetape_create_load_unload_cmd (drive, &pc,!IDETAPE_LU_LOAD_MASK);
-			return (idetape_queue_pc_tail (drive, &pc));
+			idetape_discard_read_pipeline(drive, 0);
+			idetape_create_load_unload_cmd(drive, &pc,!IDETAPE_LU_LOAD_MASK);
+			return (idetape_queue_pc_tail(drive, &pc));
 		case MTNOP:
-			idetape_discard_read_pipeline (drive, 0);
-			return (idetape_flush_tape_buffers (drive));
+			idetape_discard_read_pipeline(drive, 0);
+			return (idetape_flush_tape_buffers(drive));
 		case MTRETEN:
-			idetape_discard_read_pipeline (drive, 0);
-			idetape_create_load_unload_cmd (drive, &pc,IDETAPE_LU_RETENSION_MASK | IDETAPE_LU_LOAD_MASK);
-			return (idetape_queue_pc_tail (drive, &pc));
+			idetape_discard_read_pipeline(drive, 0);
+			idetape_create_load_unload_cmd(drive, &pc,IDETAPE_LU_RETENSION_MASK | IDETAPE_LU_LOAD_MASK);
+			return (idetape_queue_pc_tail(drive, &pc));
 		case MTEOM:
 			if (tape->onstream) {
 #if ONSTREAM_DEBUG
@@ -5128,8 +5428,8 @@
 					return -EIO;
 				return 0;
 			}
-			idetape_create_space_cmd (&pc, 0, IDETAPE_SPACE_TO_EOD);
-			return (idetape_queue_pc_tail (drive, &pc));
+			idetape_create_space_cmd(&pc, 0, IDETAPE_SPACE_TO_EOD);
+			return (idetape_queue_pc_tail(drive, &pc));
 		case MTERASE:
 			if (tape->onstream) {
 				tape->eod_frame_addr = OS_DATA_STARTFRAME1;
@@ -5137,7 +5437,7 @@
 				tape->first_mark_addr = tape->last_mark_addr = -1;
 				idetape_position_tape(drive, tape->eod_frame_addr, 0, 0);
 				idetape_write_eod(drive);
-				idetape_flush_tape_buffers (drive);
+				idetape_flush_tape_buffers(drive);
 				idetape_write_header(drive, 0);
 				/*
 				 * write filler frames to the unused frames...
@@ -5145,13 +5445,13 @@
 				 */
 				idetape_write_filler(drive, OS_DATA_STARTFRAME1 - 10, 10);
 				idetape_write_filler(drive, OS_DATA_ENDFRAME1, 10);
-				idetape_flush_tape_buffers (drive);
-				(void) idetape_rewind_tape (drive);
+				idetape_flush_tape_buffers(drive);
+				(void) idetape_rewind_tape(drive);
 				return 0;
 			}
-			(void) idetape_rewind_tape (drive);
-			idetape_create_erase_cmd (&pc);
-			return (idetape_queue_pc_tail (drive, &pc));
+			(void) idetape_rewind_tape(drive);
+			idetape_create_erase_cmd(&pc);
+			return (idetape_queue_pc_tail(drive, &pc));
 		case MTSETBLK:
 			if (tape->onstream) {
 				if (mt_count != tape->tape_block_size) {
@@ -5164,21 +5464,21 @@
 				if (mt_count < tape->tape_block_size || mt_count % tape->tape_block_size)
 					return -EIO;
 				tape->user_bs_factor = mt_count / tape->tape_block_size;
-				clear_bit (IDETAPE_DETECT_BS, &tape->flags);
+				clear_bit(IDETAPE_DETECT_BS, &tape->flags);
 			} else
-				set_bit (IDETAPE_DETECT_BS, &tape->flags);
+				set_bit(IDETAPE_DETECT_BS, &tape->flags);
 			return 0;
 		case MTSEEK:
 			if (!tape->onstream || tape->raw) {
-				idetape_discard_read_pipeline (drive, 0);
-				return idetape_position_tape (drive, mt_count * tape->user_bs_factor, tape->partition, 0);
+				idetape_discard_read_pipeline(drive, 0);
+				return idetape_position_tape(drive, mt_count * tape->user_bs_factor, tape->partition, 0);
 			}
 			return idetape_seek_logical_blk(drive, mt_count);
 		case MTSETPART:
-			idetape_discard_read_pipeline (drive, 0);
+			idetape_discard_read_pipeline(drive, 0);
 			if (tape->onstream)
 				return -EIO;
-			return (idetape_position_tape (drive, 0, mt_count, 0));
+			return (idetape_position_tape(drive, 0, mt_count, 0));
 		case MTFSR:
 		case MTBSR:
 			if (tape->onstream) {
@@ -5187,26 +5487,26 @@
 				if (mt_op == MTFSR)
 					return idetape_seek_logical_blk(drive, tape->logical_blk_num + mt_count);
 				else {
-					idetape_discard_read_pipeline (drive, 0);
+					idetape_discard_read_pipeline(drive, 0);
 					return idetape_seek_logical_blk(drive, tape->logical_blk_num - mt_count);
 				}
 			}
 		case MTLOCK:
 			if (!idetape_create_prevent_cmd(drive, &pc, 1))
 				return 0;
-			retval = idetape_queue_pc_tail (drive, &pc);
+			retval = idetape_queue_pc_tail(drive, &pc);
 			if (retval) return retval;
 			tape->door_locked = DOOR_EXPLICITLY_LOCKED;
 			return 0;
 		case MTUNLOCK:
 			if (!idetape_create_prevent_cmd(drive, &pc, 0))
 				return 0;
-			retval = idetape_queue_pc_tail (drive, &pc);
+			retval = idetape_queue_pc_tail(drive, &pc);
 			if (retval) return retval;
 			tape->door_locked = DOOR_UNLOCKED;
 			return 0;
 		default:
-			printk (KERN_ERR "ide-tape: MTIO operation %d not supported\n",mt_op);
+			printk(KERN_ERR "ide-tape: MTIO operation %d not supported\n",mt_op);
 			return (-EIO);
 	}
 }
@@ -5236,7 +5536,7 @@
  */
 static int idetape_chrdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
-	ide_drive_t *drive = get_drive_ptr (inode->i_rdev);
+	ide_drive_t *drive = get_drive_ptr(inode->i_rdev);
 	idetape_tape_t *tape = drive->driver_data;
 	struct mtop mtop;
 	struct mtget mtget;
@@ -5245,30 +5545,30 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 3)
-		printk (KERN_INFO "ide-tape: Reached idetape_chrdev_ioctl, cmd=%u\n",cmd);
+		printk(KERN_INFO "ide-tape: Reached idetape_chrdev_ioctl, cmd=%u\n",cmd);
 #endif /* IDETAPE_DEBUG_LOG */
 
 	tape->restart_speed_control_req = 1;
 	if (tape->chrdev_direction == idetape_direction_write) {
-		idetape_empty_write_pipeline (drive);
-		idetape_flush_tape_buffers (drive);
+		idetape_empty_write_pipeline(drive);
+		idetape_flush_tape_buffers(drive);
 	}
 	if (cmd == MTIOCGET || cmd == MTIOCPOS) {
-		block_offset = idetape_pipeline_size (drive) / (tape->tape_block_size * tape->user_bs_factor);
+		block_offset = idetape_pipeline_size(drive) / (tape->tape_block_size * tape->user_bs_factor);
 		if ((position = idetape_read_position(drive)) < 0)
 			return -EIO;
 	}
 	switch (cmd) {
 		case MTIOCTOP:
-			if (copy_from_user ((char *) &mtop, (char *) arg, sizeof (struct mtop)))
+			if (copy_from_user((char *) &mtop, (char *) arg, sizeof (struct mtop)))
 				return -EFAULT;
-			return (idetape_mtioctop (drive,mtop.mt_op,mtop.mt_count));
+			return (idetape_mtioctop(drive,mtop.mt_op,mtop.mt_count));
 		case MTIOCGET:
-			memset (&mtget, 0, sizeof (struct mtget));
+			memset(&mtget, 0, sizeof (struct mtget));
 			mtget.mt_type = MT_ISSCSI2;
-			if (!tape->onstream || tape->raw)
+			if (!tape->onstream || tape->raw) {
 				mtget.mt_blkno = position / tape->user_bs_factor - block_offset;
-			else {
+			} else {
 				if (!idetape_get_logical_blk(drive, -1, 10, 0))
 					mtget.mt_blkno = -1;
 				else
@@ -5297,8 +5597,8 @@
 			return 0;
 		default:
 			if (tape->chrdev_direction == idetape_direction_read)
-				idetape_discard_read_pipeline (drive, 1);
-			return (idetape_blkdev_ioctl (drive,inode,file,cmd,arg));
+				idetape_discard_read_pipeline(drive, 1);
+			return (idetape_blkdev_ioctl(drive,inode,file,cmd,arg));
 	}
 }
 
@@ -5318,7 +5618,7 @@
 	tape->wrt_pass_cntr = 0;
 	tape->eod_frame_addr = OS_DATA_STARTFRAME1;
 	tape->first_mark_addr = tape->last_mark_addr = -1;
-	stage = __idetape_kmalloc_stage (tape, 0, 0);
+	stage = __idetape_kmalloc_stage(tape, 0, 0);
 	if (stage == NULL)
 		return 0;
 #if ONSTREAM_DEBUG
@@ -5326,16 +5626,17 @@
 		printk(KERN_INFO "ide-tape: %s: reading header\n", tape->name);
 #endif
 	idetape_position_tape(drive, block, 0, 0);
-	if (!idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 1, stage->bh)) {
-		printk(KERN_INFO "ide-tape: %s: couldn't read header frame\n", tape->name);
-		__idetape_kfree_stage (stage);
+	if (!idetape_queue_rw_tail(drive, IDETAPE_READ_RQ, 1, stage->bh)) {
+		printk(KERN_INFO "ide-tape: %s: couldn't read header frame\n",
+			tape->name);
+		__idetape_kfree_stage(stage);
 		return 0;
 	}
 	header = (os_header_t *) stage->bh->b_data;
 	aux = stage->aux;
 	if (strncmp(header->ident_str, "ADR_SEQ", 7) != 0) {
 		printk(KERN_INFO "ide-tape: %s: invalid header identification string\n", tape->name);
-		__idetape_kfree_stage (stage);
+		__idetape_kfree_stage(stage);
 		return 0;
 	}
 	if (header->major_rev != 1 || (header->minor_rev > OS_ADR_MINREV))
@@ -5354,17 +5655,21 @@
 		tape->linux_media = 1;
 		tape->linux_media_version = tape->application_sig[3] - '0';
 		if (tape->linux_media_version != 3)
-			printk(KERN_INFO "ide-tape: %s: Linux media version %d detected (current 3)\n",
-					 tape->name, tape->linux_media_version);
+			printk(KERN_INFO "ide-tape: %s: Linux media version "
+				"%d detected (current 3)\n",
+				 tape->name, tape->linux_media_version);
 	} else {
-		printk(KERN_INFO "ide-tape: %s: non Linux media detected (%s)\n", tape->name, tape->application_sig);
+		printk(KERN_INFO "ide-tape: %s: non Linux media detected "
+			"(%s)\n", tape->name, tape->application_sig);
 		tape->linux_media = 0;
 	}
 #if ONSTREAM_DEBUG
 	if (tape->debug_level >= 2)
-		printk(KERN_INFO "ide-tape: %s: detected write pass counter %d, eod frame addr %d\n", tape->name, tape->wrt_pass_cntr, tape->eod_frame_addr);
+		printk(KERN_INFO "ide-tape: %s: detected write pass "
+			"counter %d, eod frame addr %d\n", tape->name,
+			tape->wrt_pass_cntr, tape->eod_frame_addr);
 #endif
-	__idetape_kfree_stage (stage);
+	__idetape_kfree_stage(stage);
 	return 1;
 }
 
@@ -5385,7 +5690,8 @@
 	for (block = 0xbae; block < 0xbb3; block++) /* 2990 - 2994 */
 		if (__idetape_analyze_headers(drive, block))
 			goto ok;
-	printk(KERN_ERR "ide-tape: %s: failed to find valid ADRL header\n", tape->name);
+	printk(KERN_ERR "ide-tape: %s: failed to find valid ADRL header\n",
+		tape->name);
 	return 0;
 ok:
 	if (position < OS_DATA_STARTFRAME1)
@@ -5403,23 +5709,23 @@
 	ide_drive_t *drive;
 	idetape_tape_t *tape;
 	idetape_pc_t pc;
-	unsigned int minor=MINOR (inode->i_rdev);
+	unsigned int minor = MINOR(inode->i_rdev);
 			
 #if IDETAPE_DEBUG_LOG
 	printk (KERN_INFO "ide-tape: Reached idetape_chrdev_open\n");
 #endif /* IDETAPE_DEBUG_LOG */
 	
-	if ((drive = get_drive_ptr (inode->i_rdev)) == NULL)
+	if ((drive = get_drive_ptr(inode->i_rdev)) == NULL)
 		return -ENXIO;
 	tape = drive->driver_data;
 
-	if (test_and_set_bit (IDETAPE_BUSY, &tape->flags))
+	if (test_and_set_bit(IDETAPE_BUSY, &tape->flags))
 		return -EBUSY;
 	MOD_INC_USE_COUNT;
 	if (!tape->onstream) {	
 		idetape_read_position(drive);
-		if (!test_bit (IDETAPE_ADDRESS_VALID, &tape->flags))
-			(void) idetape_rewind_tape (drive);
+		if (!test_bit(IDETAPE_ADDRESS_VALID, &tape->flags))
+			(void) idetape_rewind_tape(drive);
 	} else {
 		if (minor & 64) {
 			tape->tape_block_size = tape->stage_size = 32768 + 512;
@@ -5436,14 +5742,16 @@
 		MOD_DEC_USE_COUNT;
 		return -EBUSY;
 	}
-	idetape_read_position(drive);
+	if (tape->onstream)
+		idetape_read_position(drive);
 	MOD_DEC_USE_COUNT;
-	clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags);
+	if (tape->chrdev_direction != idetape_direction_read)
+		clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 
 	if (tape->chrdev_direction == idetape_direction_none) {
 		MOD_INC_USE_COUNT;
 		if (idetape_create_prevent_cmd(drive, &pc, 1)) {
-			if (!idetape_queue_pc_tail (drive, &pc)) {
+			if (!idetape_queue_pc_tail(drive, &pc)) {
 				if (tape->door_locked != DOOR_EXPLICITLY_LOCKED)
 					tape->door_locked = DOOR_LOCKED;
 			}
@@ -5458,22 +5766,22 @@
 
 static void idetape_write_release (struct inode *inode)
 {
-	ide_drive_t *drive = get_drive_ptr (inode->i_rdev);
+	ide_drive_t *drive = get_drive_ptr(inode->i_rdev);
 	idetape_tape_t *tape = drive->driver_data;
-	unsigned int minor=MINOR (inode->i_rdev);
+	unsigned int minor = MINOR(inode->i_rdev);
 
-	idetape_empty_write_pipeline (drive);
-	tape->merge_stage = __idetape_kmalloc_stage (tape, 1, 0);
+	idetape_empty_write_pipeline(drive);
+	tape->merge_stage = __idetape_kmalloc_stage(tape, 1, 0);
 	if (tape->merge_stage != NULL) {
-		idetape_pad_zeros (drive, tape->tape_block_size * (tape->user_bs_factor - 1));
-		__idetape_kfree_stage (tape->merge_stage);
+		idetape_pad_zeros(drive, tape->tape_block_size * (tape->user_bs_factor - 1));
+		__idetape_kfree_stage(tape->merge_stage);
 		tape->merge_stage = NULL;
 	}
 	idetape_write_filemark(drive);
 	idetape_write_eod(drive);
-	idetape_flush_tape_buffers (drive);
+	idetape_flush_tape_buffers(drive);
 	idetape_write_header(drive, minor >= 128);
-	idetape_flush_tape_buffers (drive);
+	idetape_flush_tape_buffers(drive);
 
 	return;
 }
@@ -5483,16 +5791,16 @@
  */
 static int idetape_chrdev_release (struct inode *inode, struct file *filp)
 {
-	ide_drive_t *drive = get_drive_ptr (inode->i_rdev);
+	ide_drive_t *drive = get_drive_ptr(inode->i_rdev);
 	idetape_tape_t *tape;
 	idetape_pc_t pc;
-	unsigned int minor=MINOR (inode->i_rdev);
+	unsigned int minor = MINOR(inode->i_rdev);
 
 	lock_kernel();
 	tape = drive->driver_data;
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 3)
-		printk (KERN_INFO "ide-tape: Reached idetape_chrdev_release\n");
+		printk(KERN_INFO "ide-tape: Reached idetape_chrdev_release\n");
 #endif /* IDETAPE_DEBUG_LOG */
 
 	if (tape->chrdev_direction == idetape_direction_write) {
@@ -5500,25 +5808,26 @@
 	}
 	if (tape->chrdev_direction == idetape_direction_read) {
 		if (minor < 128)
-			idetape_discard_read_pipeline (drive, 1);
+			idetape_discard_read_pipeline(drive, 1);
 		else
-			idetape_wait_for_pipeline (drive);
+			idetape_wait_for_pipeline(drive);
 	}
 	if (tape->cache_stage != NULL) {
-		__idetape_kfree_stage (tape->cache_stage);
+		__idetape_kfree_stage(tape->cache_stage);
 		tape->cache_stage = NULL;
 	}
 	if (minor < 128)
-		(void) idetape_rewind_tape (drive);
+		(void) idetape_rewind_tape(drive);
 	if (tape->chrdev_direction == idetape_direction_none) {
-		if (tape->door_locked != DOOR_EXPLICITLY_LOCKED) {
-			if (idetape_create_prevent_cmd(drive, &pc, 0))
-				if (!idetape_queue_pc_tail (drive, &pc))
+		if (tape->door_locked == DOOR_LOCKED) {
+			if (idetape_create_prevent_cmd(drive, &pc, 0)) {
+				if (!idetape_queue_pc_tail(drive, &pc))
 					tape->door_locked = DOOR_UNLOCKED;
+			}
 		}
 		MOD_DEC_USE_COUNT;
 	}
-	clear_bit (IDETAPE_BUSY, &tape->flags);
+	clear_bit(IDETAPE_BUSY, &tape->flags);
 	unlock_kernel();
 	return 0;
 }
@@ -5545,107 +5854,107 @@
 	*((unsigned short *) &gcw) = id->config;
 
 #if IDETAPE_DEBUG_INFO
-	printk (KERN_INFO "ide-tape: Dumping ATAPI Identify Device tape parameters\n");
-	printk (KERN_INFO "ide-tape: Protocol Type: ");
+	printk(KERN_INFO "ide-tape: Dumping ATAPI Identify Device tape parameters\n");
+	printk(KERN_INFO "ide-tape: Protocol Type: ");
 	switch (gcw.protocol) {
-		case 0: case 1: printk (KERN_INFO "ATA\n");break;
-		case 2:	printk (KERN_INFO "ATAPI\n");break;
-		case 3: printk (KERN_INFO "Reserved (Unknown to ide-tape)\n");break;
+		case 0: case 1: printk("ATA\n");break;
+		case 2:	printk("ATAPI\n");break;
+		case 3: printk("Reserved (Unknown to ide-tape)\n");break;
 	}
-	printk (KERN_INFO "ide-tape: Device Type: %x - ",gcw.device_type);	
+	printk(KERN_INFO "ide-tape: Device Type: %x - ",gcw.device_type);	
 	switch (gcw.device_type) {
-		case 0: printk (KERN_INFO "Direct-access Device\n");break;
-		case 1: printk (KERN_INFO "Streaming Tape Device\n");break;
-		case 2: case 3: case 4: printk (KERN_INFO "Reserved\n");break;
-		case 5: printk (KERN_INFO "CD-ROM Device\n");break;
-		case 6: printk (KERN_INFO "Reserved\n");
-		case 7: printk (KERN_INFO "Optical memory Device\n");break;
-		case 0x1f: printk (KERN_INFO "Unknown or no Device type\n");break;
-		default: printk (KERN_INFO "Reserved\n");
+		case 0: printk("Direct-access Device\n");break;
+		case 1: printk("Streaming Tape Device\n");break;
+		case 2: case 3: case 4: printk("Reserved\n");break;
+		case 5: printk("CD-ROM Device\n");break;
+		case 6: printk("Reserved\n");
+		case 7: printk("Optical memory Device\n");break;
+		case 0x1f: printk("Unknown or no Device type\n");break;
+		default: printk("Reserved\n");
 	}
-	printk (KERN_INFO "ide-tape: Removable: %s",gcw.removable ? "Yes\n":"No\n");	
-	printk (KERN_INFO "ide-tape: Command Packet DRQ Type: ");
+	printk(KERN_INFO "ide-tape: Removable: %s",gcw.removable ? "Yes\n":"No\n");	
+	printk(KERN_INFO "ide-tape: Command Packet DRQ Type: ");
 	switch (gcw.drq_type) {
-		case 0: printk (KERN_INFO "Microprocessor DRQ\n");break;
-		case 1: printk (KERN_INFO "Interrupt DRQ\n");break;
-		case 2: printk (KERN_INFO "Accelerated DRQ\n");break;
-		case 3: printk (KERN_INFO "Reserved\n");break;
+		case 0: printk("Microprocessor DRQ\n");break;
+		case 1: printk("Interrupt DRQ\n");break;
+		case 2: printk("Accelerated DRQ\n");break;
+		case 3: printk("Reserved\n");break;
 	}
-	printk (KERN_INFO "ide-tape: Command Packet Size: ");
+	printk(KERN_INFO "ide-tape: Command Packet Size: ");
 	switch (gcw.packet_size) {
-		case 0: printk (KERN_INFO "12 bytes\n");break;
-		case 1: printk (KERN_INFO "16 bytes\n");break;
-		default: printk (KERN_INFO "Reserved\n");break;
-	}
-	printk (KERN_INFO "ide-tape: Model: %.40s\n",id->model);
-	printk (KERN_INFO "ide-tape: Firmware Revision: %.8s\n",id->fw_rev);
-	printk (KERN_INFO "ide-tape: Serial Number: %.20s\n",id->serial_no);
-	printk (KERN_INFO "ide-tape: Write buffer size: %d bytes\n",id->buf_size*512);
-	printk (KERN_INFO "ide-tape: DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n");
-	printk (KERN_INFO "ide-tape: LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n");
-	printk (KERN_INFO "ide-tape: IORDY can be disabled: %s",id->capability & 0x04 ? "Yes\n":"No\n");
-	printk (KERN_INFO "ide-tape: IORDY supported: %s",id->capability & 0x08 ? "Yes\n":"Unknown\n");
-	printk (KERN_INFO "ide-tape: ATAPI overlap supported: %s",id->capability & 0x20 ? "Yes\n":"No\n");
-	printk (KERN_INFO "ide-tape: PIO Cycle Timing Category: %d\n",id->tPIO);
-	printk (KERN_INFO "ide-tape: DMA Cycle Timing Category: %d\n",id->tDMA);
-	printk (KERN_INFO "ide-tape: Single Word DMA supported modes: ");
+		case 0: printk("12 bytes\n");break;
+		case 1: printk("16 bytes\n");break;
+		default: printk("Reserved\n");break;
+	}
+	printk(KERN_INFO "ide-tape: Model: %.40s\n",id->model);
+	printk(KERN_INFO "ide-tape: Firmware Revision: %.8s\n",id->fw_rev);
+	printk(KERN_INFO "ide-tape: Serial Number: %.20s\n",id->serial_no);
+	printk(KERN_INFO "ide-tape: Write buffer size: %d bytes\n",id->buf_size*512);
+	printk(KERN_INFO "ide-tape: DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n");
+	printk(KERN_INFO "ide-tape: LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n");
+	printk(KERN_INFO "ide-tape: IORDY can be disabled: %s",id->capability & 0x04 ? "Yes\n":"No\n");
+	printk(KERN_INFO "ide-tape: IORDY supported: %s",id->capability & 0x08 ? "Yes\n":"Unknown\n");
+	printk(KERN_INFO "ide-tape: ATAPI overlap supported: %s",id->capability & 0x20 ? "Yes\n":"No\n");
+	printk(KERN_INFO "ide-tape: PIO Cycle Timing Category: %d\n",id->tPIO);
+	printk(KERN_INFO "ide-tape: DMA Cycle Timing Category: %d\n",id->tDMA);
+	printk(KERN_INFO "ide-tape: Single Word DMA supported modes: ");
 	for (i=0,mask=1;i<8;i++,mask=mask << 1) {
 		if (id->dma_1word & mask)
-			printk (KERN_INFO "%d ",i);
+			printk("%d ",i);
 		if (id->dma_1word & (mask << 8))
-			printk (KERN_INFO "(active) ");
+			printk("(active) ");
 	}
-	printk (KERN_INFO "\n");
-	printk (KERN_INFO "ide-tape: Multi Word DMA supported modes: ");
+	printk("\n");
+	printk(KERN_INFO "ide-tape: Multi Word DMA supported modes: ");
 	for (i=0,mask=1;i<8;i++,mask=mask << 1) {
 		if (id->dma_mword & mask)
-			printk (KERN_INFO "%d ",i);
+			printk("%d ",i);
 		if (id->dma_mword & (mask << 8))
-			printk (KERN_INFO "(active) ");
+			printk("(active) ");
 	}
-	printk (KERN_INFO "\n");
+	printk("\n");
 	if (id->field_valid & 0x0002) {
-		printk (KERN_INFO "ide-tape: Enhanced PIO Modes: %s\n",id->eide_pio_modes & 1 ? "Mode 3":"None");
-		printk (KERN_INFO "ide-tape: Minimum Multi-word DMA cycle per word: ");
+		printk(KERN_INFO "ide-tape: Enhanced PIO Modes: %s\n",id->eide_pio_modes & 1 ? "Mode 3":"None");
+		printk(KERN_INFO "ide-tape: Minimum Multi-word DMA cycle per word: ");
 		if (id->eide_dma_min == 0)
-			printk (KERN_INFO "Not supported\n");
+			printk("Not supported\n");
 		else
-			printk (KERN_INFO "%d ns\n",id->eide_dma_min);
+			printk("%d ns\n",id->eide_dma_min);
 
-		printk (KERN_INFO "ide-tape: Manufacturer\'s Recommended Multi-word cycle: ");
+		printk(KERN_INFO "ide-tape: Manufacturer\'s Recommended Multi-word cycle: ");
 		if (id->eide_dma_time == 0)
-			printk (KERN_INFO "Not supported\n");
+			printk("Not supported\n");
 		else
-			printk (KERN_INFO "%d ns\n",id->eide_dma_time);
+			printk("%d ns\n",id->eide_dma_time);
 
-		printk (KERN_INFO "ide-tape: Minimum PIO cycle without IORDY: ");
+		printk(KERN_INFO "ide-tape: Minimum PIO cycle without IORDY: ");
 		if (id->eide_pio == 0)
-			printk (KERN_INFO "Not supported\n");
+			printk("Not supported\n");
 		else
-			printk (KERN_INFO "%d ns\n",id->eide_pio);
+			printk("%d ns\n",id->eide_pio);
 
-		printk (KERN_INFO "ide-tape: Minimum PIO cycle with IORDY: ");
+		printk(KERN_INFO "ide-tape: Minimum PIO cycle with IORDY: ");
 		if (id->eide_pio_iordy == 0)
-			printk (KERN_INFO "Not supported\n");
+			printk("Not supported\n");
 		else
-			printk (KERN_INFO "%d ns\n",id->eide_pio_iordy);
+			printk("%d ns\n",id->eide_pio_iordy);
 		
 	} else
-		printk (KERN_INFO "ide-tape: According to the device, fields 64-70 are not valid.\n");
+		printk(KERN_INFO "ide-tape: According to the device, fields 64-70 are not valid.\n");
 #endif /* IDETAPE_DEBUG_INFO */
 
 	/* Check that we can support this device */
 
 	if (gcw.protocol !=2 )
-		printk (KERN_ERR "ide-tape: Protocol is not ATAPI\n");
+		printk(KERN_ERR "ide-tape: Protocol is not ATAPI\n");
 	else if (gcw.device_type != 1)
-		printk (KERN_ERR "ide-tape: Device type is not set to tape\n");
+		printk(KERN_ERR "ide-tape: Device type is not set to tape\n");
 	else if (!gcw.removable)
-		printk (KERN_ERR "ide-tape: The removable flag is not set\n");
+		printk(KERN_ERR "ide-tape: The removable flag is not set\n");
 	else if (gcw.packet_size != 0) {
-		printk (KERN_ERR "ide-tape: Packet size is not 12 bytes long\n");
+		printk(KERN_ERR "ide-tape: Packet size is not 12 bytes long\n");
 		if (gcw.packet_size == 1)
-			printk (KERN_ERR "ide-tape: Sorry, padding to 16 bytes is still not supported\n");
+			printk(KERN_ERR "ide-tape: Sorry, padding to 16 bytes is still not supported\n");
 	} else
 		return 1;
 	return 0;
@@ -5672,8 +5981,8 @@
 	pc.buffer[4 + 5] = vendor[3];
 	pc.buffer[4 + 6] = 0;
 	pc.buffer[4 + 7] = 0;
-	if (idetape_queue_pc_tail (drive, &pc))
-		printk (KERN_ERR "ide-tape: Couldn't set vendor name to %s\n", vendor);
+	if (idetape_queue_pc_tail(drive, &pc))
+		printk(KERN_ERR "ide-tape: Couldn't set vendor name to %s\n", vendor);
 
 }
 
@@ -5694,8 +6003,8 @@
 	pc.buffer[4 + 1] = 2;
 	pc.buffer[4 + 2] = 4;
 	pc.buffer[4 + 3] = retries;
-	if (idetape_queue_pc_tail (drive, &pc))
-		printk (KERN_ERR "ide-tape: Couldn't set retries to %d\n", retries);
+	if (idetape_queue_pc_tail(drive, &pc))
+		printk(KERN_ERR "ide-tape: Couldn't set retries to %d\n", retries);
 }
 #endif
 
@@ -5711,9 +6020,9 @@
 	/*
 	 * Get the current block size from the block size mode page
 	 */
-	idetape_create_mode_sense_cmd (&pc, IDETAPE_BLOCK_SIZE_PAGE);
-	if (idetape_queue_pc_tail (drive, &pc))
-		printk (KERN_ERR "ide-tape: can't get tape block size mode page\n");
+	idetape_create_mode_sense_cmd(&pc, IDETAPE_BLOCK_SIZE_PAGE);
+	if (idetape_queue_pc_tail(drive, &pc))
+		printk(KERN_ERR "ide-tape: can't get tape block size mode page\n");
 	header = (idetape_mode_parameter_header_t *) pc.buffer;
 	bs = (idetape_block_size_page_t *) (pc.buffer + sizeof(idetape_mode_parameter_header_t) + header->bdl);
 
@@ -5733,8 +6042,8 @@
 	bs->record32 = 0;
 	bs->record32_5 = 1;
 	idetape_create_mode_select_cmd(&pc, sizeof(*header) + sizeof(*bs));
-	if (idetape_queue_pc_tail (drive, &pc))
-		printk (KERN_ERR "ide-tape: Couldn't set tape block size mode page\n");
+	if (idetape_queue_pc_tail(drive, &pc))
+		printk(KERN_ERR "ide-tape: Couldn't set tape block size mode page\n");
 
 #if ONSTREAM_DEBUG
 	/*
@@ -5756,8 +6065,8 @@
 	idetape_inquiry_result_t *inquiry;
 	
 	idetape_create_inquiry_cmd(&pc);
-	if (idetape_queue_pc_tail (drive, &pc)) {
-		printk (KERN_ERR "ide-tape: %s: can't get INQUIRY results\n", tape->name);
+	if (idetape_queue_pc_tail(drive, &pc)) {
+		printk(KERN_ERR "ide-tape: %s: can't get INQUIRY results\n", tape->name);
 		return;
 	}
 	inquiry = (idetape_inquiry_result_t *) pc.buffer;
@@ -5809,9 +6118,9 @@
 	idetape_mode_parameter_header_t *header;
 	onstream_tape_paramtr_page_t *prm;
 	
-	idetape_create_mode_sense_cmd (&pc, IDETAPE_PARAMTR_PAGE);
-	if (idetape_queue_pc_tail (drive, &pc)) {
-		printk (KERN_ERR "ide-tape: Can't get tape parameters page - probably no tape inserted in onstream drive\n");
+	idetape_create_mode_sense_cmd(&pc, IDETAPE_PARAMTR_PAGE);
+	if (idetape_queue_pc_tail(drive, &pc)) {
+		printk(KERN_ERR "ide-tape: Can't get tape parameters page - probably no tape inserted in onstream drive\n");
 		return;
 	}
 	header = (idetape_mode_parameter_header_t *) pc.buffer;
@@ -5819,7 +6128,7 @@
 
         tape->capacity = ntohs(prm->segtrk) * ntohs(prm->trks);
         if (debug) {
-	    printk (KERN_INFO "ide-tape: %s <-> %s: Tape length %dMB (%d frames/track, %d tracks = %d blocks, density: %dKbpi)\n",
+	    printk(KERN_INFO "ide-tape: %s <-> %s: Tape length %dMB (%d frames/track, %d tracks = %d blocks, density: %dKbpi)\n",
                drive->name, tape->name, tape->capacity/32, ntohs(prm->segtrk), ntohs(prm->trks), tape->capacity, prm->density);
         }
 
@@ -5838,20 +6147,22 @@
 	idetape_mode_parameter_header_t *header;
 	idetape_capabilities_page_t *capabilities;
 	
-	idetape_create_mode_sense_cmd (&pc, IDETAPE_CAPABILITIES_PAGE);
+	idetape_create_mode_sense_cmd(&pc, IDETAPE_CAPABILITIES_PAGE);
 	if (idetape_queue_pc_tail (drive, &pc)) {
-		printk (KERN_ERR "ide-tape: Can't get tape parameters - assuming some default values\n");
-		tape->tape_block_size = 512; tape->capabilities.ctl = 52;
-		tape->capabilities.speed = 450; tape->capabilities.buffer_size = 6 * 52;
+		printk(KERN_ERR "ide-tape: Can't get tape parameters - assuming some default values\n");
+		tape->tape_block_size = 512;
+		tape->capabilities.ctl = 52;
+		tape->capabilities.speed = 450;
+		tape->capabilities.buffer_size = 6 * 52;
 		return;
 	}
 	header = (idetape_mode_parameter_header_t *) pc.buffer;
 	capabilities = (idetape_capabilities_page_t *) (pc.buffer + sizeof(idetape_mode_parameter_header_t) + header->bdl);
 
-	capabilities->max_speed = ntohs (capabilities->max_speed);
-	capabilities->ctl = ntohs (capabilities->ctl);
-	capabilities->speed = ntohs (capabilities->speed);
-	capabilities->buffer_size = ntohs (capabilities->buffer_size);
+	capabilities->max_speed = ntohs(capabilities->max_speed);
+	capabilities->ctl = ntohs(capabilities->ctl);
+	capabilities->speed = ntohs(capabilities->speed);
+	capabilities->buffer_size = ntohs(capabilities->buffer_size);
 
 	if (!capabilities->speed) {
 		printk(KERN_INFO "ide-tape: %s: overriding capabilities->speed (assuming 650KB/sec)\n", drive->name);
@@ -5861,6 +6172,10 @@
 		printk(KERN_INFO "ide-tape: %s: overriding capabilities->max_speed (assuming 650KB/sec)\n", drive->name);
 		capabilities->max_speed = 650;
 	}
+	if (!capabilities->ctl) {
+		printk(KERN_INFO "ide-tape: %s: overriding capabilities->ctl (assuming 26KB)\n", drive->name);
+		capabilities->ctl = 52;
+	}
 
 	tape->capabilities = *capabilities;		/* Save us a copy */
 	if (capabilities->blk512)
@@ -5871,33 +6186,33 @@
 		tape->tape_block_size = 32768;
 
 #if IDETAPE_DEBUG_INFO
-	printk (KERN_INFO "ide-tape: Dumping the results of the MODE SENSE packet command\n");
-	printk (KERN_INFO "ide-tape: Mode Parameter Header:\n");
-	printk (KERN_INFO "ide-tape: Mode Data Length - %d\n",header->mode_data_length);
-	printk (KERN_INFO "ide-tape: Medium Type - %d\n",header->medium_type);
-	printk (KERN_INFO "ide-tape: Device Specific Parameter - %d\n",header->dsp);
-	printk (KERN_INFO "ide-tape: Block Descriptor Length - %d\n",header->bdl);
+	printk(KERN_INFO "ide-tape: Dumping the results of the MODE SENSE packet command\n");
+	printk(KERN_INFO "ide-tape: Mode Parameter Header:\n");
+	printk(KERN_INFO "ide-tape: Mode Data Length - %d\n",header->mode_data_length);
+	printk(KERN_INFO "ide-tape: Medium Type - %d\n",header->medium_type);
+	printk(KERN_INFO "ide-tape: Device Specific Parameter - %d\n",header->dsp);
+	printk(KERN_INFO "ide-tape: Block Descriptor Length - %d\n",header->bdl);
 	
-	printk (KERN_INFO "ide-tape: Capabilities and Mechanical Status Page:\n");
-	printk (KERN_INFO "ide-tape: Page code - %d\n",capabilities->page_code);
-	printk (KERN_INFO "ide-tape: Page length - %d\n",capabilities->page_length);
-	printk (KERN_INFO "ide-tape: Read only - %s\n",capabilities->ro ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports reverse space - %s\n",capabilities->sprev ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports erase initiated formatting - %s\n",capabilities->efmt ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports QFA two Partition format - %s\n",capabilities->qfa ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports locking the medium - %s\n",capabilities->lock ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: The volume is currently locked - %s\n",capabilities->locked ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: The device defaults in the prevent state - %s\n",capabilities->prevent ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports ejecting the medium - %s\n",capabilities->eject ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports error correction - %s\n",capabilities->ecc ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports data compression - %s\n",capabilities->cmprs ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports 512 bytes block size - %s\n",capabilities->blk512 ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports 1024 bytes block size - %s\n",capabilities->blk1024 ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports 32768 bytes block size / Restricted byte count for PIO transfers - %s\n",capabilities->blk32768 ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Maximum supported speed in KBps - %d\n",capabilities->max_speed);
-	printk (KERN_INFO "ide-tape: Continuous transfer limits in blocks - %d\n",capabilities->ctl);
-	printk (KERN_INFO "ide-tape: Current speed in KBps - %d\n",capabilities->speed);	
-	printk (KERN_INFO "ide-tape: Buffer size - %d\n",capabilities->buffer_size*512);
+	printk(KERN_INFO "ide-tape: Capabilities and Mechanical Status Page:\n");
+	printk(KERN_INFO "ide-tape: Page code - %d\n",capabilities->page_code);
+	printk(KERN_INFO "ide-tape: Page length - %d\n",capabilities->page_length);
+	printk(KERN_INFO "ide-tape: Read only - %s\n",capabilities->ro ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports reverse space - %s\n",capabilities->sprev ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports erase initiated formatting - %s\n",capabilities->efmt ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports QFA two Partition format - %s\n",capabilities->qfa ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports locking the medium - %s\n",capabilities->lock ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: The volume is currently locked - %s\n",capabilities->locked ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: The device defaults in the prevent state - %s\n",capabilities->prevent ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports ejecting the medium - %s\n",capabilities->eject ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports error correction - %s\n",capabilities->ecc ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports data compression - %s\n",capabilities->cmprs ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports 512 bytes block size - %s\n",capabilities->blk512 ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports 1024 bytes block size - %s\n",capabilities->blk1024 ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports 32768 bytes block size / Restricted byte count for PIO transfers - %s\n",capabilities->blk32768 ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Maximum supported speed in KBps - %d\n",capabilities->max_speed);
+	printk(KERN_INFO "ide-tape: Continuous transfer limits in blocks - %d\n",capabilities->ctl);
+	printk(KERN_INFO "ide-tape: Current speed in KBps - %d\n",capabilities->speed);	
+	printk(KERN_INFO "ide-tape: Buffer size - %d\n",capabilities->buffer_size*512);
 #endif /* IDETAPE_DEBUG_INFO */
 }
 
@@ -5913,22 +6228,19 @@
 	idetape_mode_parameter_header_t *header;
 	idetape_parameter_block_descriptor_t *block_descrp;
 	
-	idetape_create_mode_sense_cmd (&pc, IDETAPE_BLOCK_DESCRIPTOR);
-	if (idetape_queue_pc_tail (drive, &pc)) {
-		printk (KERN_ERR "ide-tape: Can't get block descriptor\n");
-		if (tape->tape_block_size == 0) {
-			printk(KERN_WARNING "ide-tape: Cannot deal with zero block size, assume 32k\n");
-			tape->tape_block_size =  32768;
-		}
+	idetape_create_mode_sense_cmd(&pc, IDETAPE_BLOCK_DESCRIPTOR);
+	if (idetape_queue_pc_tail(drive, &pc)) {
+		printk(KERN_ERR "ide-tape: Can't get block descriptor\n");
 		return;
 	}
 	header = (idetape_mode_parameter_header_t *) pc.buffer;
 	block_descrp = (idetape_parameter_block_descriptor_t *) (pc.buffer + sizeof(idetape_mode_parameter_header_t));
 	tape->tape_block_size =( block_descrp->length[0]<<16) + (block_descrp->length[1]<<8) + block_descrp->length[2];
 #if IDETAPE_DEBUG_INFO
-	printk (KERN_INFO "ide-tape: Adjusted block size - %d\n", tape->tape_block_size);
+	printk(KERN_INFO "ide-tape: Adjusted block size - %d\n", tape->tape_block_size);
 #endif /* IDETAPE_DEBUG_INFO */
 }
+
 static void idetape_add_settings (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
@@ -5937,9 +6249,9 @@
  *			drive	setting name	read/write	ioctl	ioctl		data type	min			max			mul_factor			div_factor			data pointer				set function
  */
 	ide_add_setting(drive,	"buffer",	SETTING_READ,	-1,	-1,		TYPE_SHORT,	0,			0xffff,			1,				2,				&tape->capabilities.buffer_size,	NULL);
-	ide_add_setting(drive,	"pipeline_min",	SETTING_RW,	-1,	-1,		TYPE_INT,	2,			0xffff,			tape->stage_size / 1024,	1,				&tape->min_pipeline,			NULL);
-	ide_add_setting(drive,	"pipeline",	SETTING_RW,	-1,	-1,		TYPE_INT,	2,			0xffff,			tape->stage_size / 1024,	1,				&tape->max_stages,			NULL);
-	ide_add_setting(drive,	"pipeline_max",	SETTING_RW,	-1,	-1,		TYPE_INT,	2,			0xffff,			tape->stage_size / 1024,	1,				&tape->max_pipeline,			NULL);
+	ide_add_setting(drive,	"pipeline_min",	SETTING_RW,	-1,	-1,		TYPE_INT,	1,			0xffff,			tape->stage_size / 1024,	1,				&tape->min_pipeline,			NULL);
+	ide_add_setting(drive,	"pipeline",	SETTING_RW,	-1,	-1,		TYPE_INT,	1,			0xffff,			tape->stage_size / 1024,	1,				&tape->max_stages,			NULL);
+	ide_add_setting(drive,	"pipeline_max",	SETTING_RW,	-1,	-1,		TYPE_INT,	1,			0xffff,			tape->stage_size / 1024,	1,				&tape->max_pipeline,			NULL);
 	ide_add_setting(drive,	"pipeline_used",SETTING_READ,	-1,	-1,		TYPE_INT,	0,			0xffff,			tape->stage_size / 1024,	1,				&tape->nr_stages,			NULL);
 	ide_add_setting(drive,	"pipeline_pending",SETTING_READ,-1,	-1,		TYPE_INT,	0,			0xffff,			tape->stage_size / 1024,	1,				&tape->nr_pending_stages,		NULL);
 	ide_add_setting(drive,	"speed",	SETTING_READ,	-1,	-1,		TYPE_SHORT,	0,			0xffff,			1,				1,				&tape->capabilities.speed,		NULL);
@@ -5984,29 +6296,24 @@
 	int stage_size;
 	struct sysinfo si;
 
-	memset (tape, 0, sizeof (idetape_tape_t));
+	memset(tape, 0, sizeof (idetape_tape_t));
 	spin_lock_init(&tape->spinlock);
 	drive->driver_data = tape;
-	drive->ready_stat = 0;			/* An ATAPI device ignores DRDY */
+	/* An ATAPI device ignores DRDY */
+	drive->ready_stat = 0;
 	if (strstr(drive->id->model, "OnStream DI-"))
 		tape->onstream = 1;
-	drive->dsc_overlap = 1;
-#ifdef CONFIG_BLK_DEV_IDEPCI
-	if (!tape->onstream && HWIF(drive)->pci_dev != NULL) {
-		/*
-		 * These two ide-pci host adapters appear to need DSC overlap disabled.
-		 * This probably needs further analysis.
-		 */
-		if ((HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) ||
-		    (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_TTI_HPT343)) {
-			printk(KERN_INFO "ide-tape: %s: disabling DSC overlap\n", tape->name);
-		    	drive->dsc_overlap = 0;
-		}
+	drive->dsc_overlap = (HWIF(drive)->no_dsc) ? 0 : 1;
+	if (HWIF(drive)->no_dsc) {
+		printk(KERN_INFO "ide-tape: %s: disabling DSC overlap\n",
+			tape->name);
+		drive->dsc_overlap = 0;
 	}
-#endif /* CONFIG_BLK_DEV_IDEPCI */
 	tape->drive = drive;
 	tape->minor = minor;
-	tape->name[0] = 'h'; tape->name[1] = 't'; tape->name[2] = '0' + minor;
+	tape->name[0] = 'h';
+	tape->name[1] = 't';
+	tape->name[2] = '0' + minor;
 	tape->chrdev_direction = idetape_direction_none;
 	tape->pc = tape->pc_stack;
 	tape->max_insert_speed = 10000;
@@ -6020,6 +6327,10 @@
 	idetape_get_inquiry_results(drive);
 	idetape_get_mode_sense_results(drive);
 	idetape_get_blocksize_from_block_descriptor(drive);
+	if (tape->tape_block_size == 0) {
+		printk(KERN_WARNING "ide-tape: Zero block size, using 512\n");
+		tape->tape_block_size = 512;
+	}
 	if (tape->onstream) {
 		idetape_onstream_mode_sense_tape_parameter_page(drive, 1);
 		idetape_configure_onstream(drive);
@@ -6044,7 +6355,7 @@
 	 *	Select the "best" DSC read/write polling frequency
 	 *	and pipeline size.
 	 */
-	speed = IDE_MAX (tape->capabilities.speed, tape->capabilities.max_speed);
+	speed = IDE_MAX(tape->capabilities.speed, tape->capabilities.max_speed);
 
 	tape->max_stages = speed * 1000 * 10 / tape->stage_size;
 
@@ -6052,10 +6363,13 @@
 	 * 	Limit memory use for pipeline to 10% of physical memory
 	 */
 	si_meminfo(&si);
-	if ( tape->max_stages * tape->stage_size > si.totalram * si.mem_unit / 10)
+	if (tape->max_stages * tape->stage_size > si.totalram * si.mem_unit / 10)
 		tape->max_stages = si.totalram * si.mem_unit / (10 * tape->stage_size);
-	tape->min_pipeline = tape->max_stages;
-	tape->max_pipeline = tape->max_stages * 2;
+	tape->max_stages   = IDE_MIN(tape->max_stages, IDETAPE_MAX_PIPELINE_STAGES);
+	tape->min_pipeline = IDE_MIN(tape->max_stages, IDETAPE_MIN_PIPELINE_STAGES);
+	tape->max_pipeline = IDE_MIN(tape->max_stages * 2, IDETAPE_MAX_PIPELINE_STAGES);
+	if (tape->max_stages == 0)
+		tape->max_stages = tape->min_pipeline = tape->max_pipeline = 1;
 
 	t1 = (tape->stage_size * HZ) / (speed * 1000);
 	tmid = (tape->capabilities.buffer_size * 32 * HZ) / (speed * 125);
@@ -6070,11 +6384,15 @@
 	 *	Ensure that the number we got makes sense; limit
 	 *	it within IDETAPE_DSC_RW_MIN and IDETAPE_DSC_RW_MAX.
 	 */
-	tape->best_dsc_rw_frequency = IDE_MAX (IDE_MIN (t, IDETAPE_DSC_RW_MAX), IDETAPE_DSC_RW_MIN);
-	printk (KERN_INFO "ide-tape: %s <-> %s: %dKBps, %d*%dkB buffer, %dkB pipeline, %lums tDSC%s\n",
-		drive->name, tape->name, tape->capabilities.speed, (tape->capabilities.buffer_size * 512) / tape->stage_size,
-		tape->stage_size / 1024, tape->max_stages * tape->stage_size / 1024,
-		tape->best_dsc_rw_frequency * 1000 / HZ, drive->using_dma ? ", DMA":"");
+	tape->best_dsc_rw_frequency = IDE_MAX(IDE_MIN(t, IDETAPE_DSC_RW_MAX), IDETAPE_DSC_RW_MIN);
+	printk(KERN_INFO "ide-tape: %s <-> %s: %dKBps, %d*%dkB buffer, "
+		"%dkB pipeline, %lums tDSC%s\n",
+		drive->name, tape->name, tape->capabilities.speed,
+		(tape->capabilities.buffer_size * 512) / tape->stage_size,
+		tape->stage_size / 1024,
+		tape->max_stages * tape->stage_size / 1024,
+		tape->best_dsc_rw_frequency * 1000 / HZ,
+		drive->using_dma ? ", DMA":"");
 
 	idetape_add_settings(drive);
 }
@@ -6085,24 +6403,24 @@
 	int minor = tape->minor;
 	unsigned long flags;
 
-	save_flags (flags);	/* all CPUs (overkill?) */
-	cli();			/* all CPUs (overkill?) */
-	if (test_bit (IDETAPE_BUSY, &tape->flags) || tape->first_stage != NULL || tape->merge_stage_size || drive->usage) {
-		restore_flags(flags);	/* all CPUs (overkill?) */
+	spin_lock_irqsave(&io_request_lock, flags);
+	if (test_bit(IDETAPE_BUSY, &tape->flags) || drive->usage ||
+	    tape->first_stage != NULL || tape->merge_stage_size) {
+		spin_unlock_irqrestore(&io_request_lock, flags);
 		return 1;
 	}
 	idetape_chrdevs[minor].drive = NULL;
-	restore_flags (flags);	/* all CPUs (overkill?) */
+	spin_unlock_irqrestore(&io_request_lock, flags);
 	DRIVER(drive)->busy = 0;
-	(void) ide_unregister_subdriver (drive);
+	(void) ide_unregister_subdriver(drive);
 	drive->driver_data = NULL;
-	devfs_unregister (tape->de_r);
-	devfs_unregister (tape->de_n);
-	kfree (tape);
+	devfs_unregister(tape->de_r);
+	devfs_unregister(tape->de_n);
+	kfree(tape);
 	for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++)
 		if (idetape_chrdevs[minor].drive != NULL)
 			return 0;
-	devfs_unregister_chrdev (IDETAPE_MAJOR, "ht");
+	devfs_unregister_chrdev(IDETAPE_MAJOR, "ht");
 	idetape_chrdev_present = 0;
 	return 0;
 }
@@ -6132,7 +6450,8 @@
 
 #endif
 
-int idetape_reinit(ide_drive_t *drive);
+int idetape_init (void);
+int idetape_attach(ide_drive_t *drive);
 
 /*
  *	IDE subdriver functions, registered with ide.c
@@ -6146,9 +6465,13 @@
 	supports_dsc_overlap: 	1,
 	cleanup:		idetape_cleanup,
 	standby:		NULL,
+	suspend:		NULL,
+	resume:			NULL,
 	flushcache:		NULL,
 	do_request:		idetape_do_request,
 	end_request:		idetape_end_request,
+	sense:			NULL,
+	error:			NULL,
 	ioctl:			idetape_blkdev_ioctl,
 	open:			idetape_blkdev_open,
 	release:		idetape_blkdev_release,
@@ -6156,13 +6479,14 @@
 	revalidate:		NULL,
 	pre_reset:		idetape_pre_reset,
 	capacity:		NULL,
+	special:		NULL,
 	proc:			idetape_proc,
-	reinit:			idetape_reinit,
+	init:			idetape_init,
+	attach:			idetape_attach,
 	ata_prebuilder:		NULL,
 	atapi_prebuilder:	NULL,
 };
 
-int idetape_init (void);
 static ide_module_t idetape_module = {
 	IDE_DRIVER_MODULE,
 	idetape_init,
@@ -6182,90 +6506,62 @@
 	release:	idetape_chrdev_release,
 };
 
-int idetape_reinit (ide_drive_t *drive)
+int idetape_attach (ide_drive_t *drive)
 {
-#if 0
 	idetape_tape_t *tape;
-	int minor, failed = 0, supported = 0;
-/* DRIVER(drive)->busy++; */
+	int minor = 0, ret = 0;
+
 	MOD_INC_USE_COUNT;
-#if ONSTREAM_DEBUG
-        printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_init\n");
-#endif
-	if (!idetape_chrdev_present)
-		for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++ )
-			idetape_chrdevs[minor].drive = NULL;
 
-	if ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) == NULL) {
-		ide_register_module (&idetape_module);
-		MOD_DEC_USE_COUNT;
-#if ONSTREAM_DEBUG
-		printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
-#endif
-		return 0;
-	}
-	if (!idetape_chrdev_present &&
-	    devfs_register_chrdev (IDETAPE_MAJOR, "ht", &idetape_fops)) {
-		printk (KERN_ERR "ide-tape: Failed to register character device interface\n");
-		MOD_DEC_USE_COUNT;
-#if ONSTREAM_DEBUG
-		printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
-#endif
-		return -EBUSY;
-	}
-	do {
-		if (!idetape_identify_device (drive, drive->id)) {
-			printk (KERN_ERR "ide-tape: %s: not supported by this version of ide-tape\n", drive->name);
-			continue;
-		}
-		if (drive->scsi) {
-			if (strstr(drive->id->model, "OnStream DI-30")) {
-				printk("ide-tape: ide-scsi emulation is not supported for %s.\n", drive->id->model);
-			} else {
-				printk("ide-tape: passing drive %s to ide-scsi emulation.\n", drive->name);
-				continue;
-			}
-		}
-		tape = (idetape_tape_t *) kmalloc (sizeof (idetape_tape_t), GFP_KERNEL);
-		if (tape == NULL) {
-			printk (KERN_ERR "ide-tape: %s: Can't allocate a tape structure\n", drive->name);
-			continue;
-		}
-		if (ide_register_subdriver (drive, &idetape_driver, IDE_SUBDRIVER_VERSION)) {
-			printk (KERN_ERR "ide-tape: %s: Failed to register the driver with ide.c\n", drive->name);
-			kfree (tape);
-			continue;
-		}
-		for (minor = 0; idetape_chrdevs[minor].drive != NULL; minor++);
-		idetape_setup (drive, tape, minor);
-		idetape_chrdevs[minor].drive = drive;
-		tape->de_r =
-		    devfs_register (drive->de, "mt", DEVFS_FL_DEFAULT,
+	if (!idetape_identify_device(drive, drive->id)) {
+		printk(KERN_ERR "ide-tape: %s: not supported by this "
+			"version of ide-tape\n", drive->name);
+			ret = 1;
+			goto bye_game_over;
+	}
+	if (drive->scsi) {
+		if (strstr(drive->id->model, "OnStream DI-30")) {
+			printk("ide-tape: ide-scsi emulation is not "
+				"supported for %s.\n", drive->id->model);
+		} else {
+			printk("ide-tape: passing drive %s to ide-scsi "
+				"emulation.\n", drive->name);
+			ret = 1;
+			goto bye_game_over;
+		}
+	}
+	tape = (idetape_tape_t *) kmalloc (sizeof (idetape_tape_t), GFP_KERNEL);
+	if (tape == NULL) {
+		printk(KERN_ERR "ide-tape: %s: Can't allocate a "
+			"tape structure\n", drive->name);
+		ret = 1;
+		goto bye_game_over;
+	}
+	if (ide_register_subdriver(drive,
+			&idetape_driver, IDE_SUBDRIVER_VERSION)) {
+		printk(KERN_ERR "ide-tape: %s: Failed to register the "
+				"driver with ide.c\n", drive->name);
+		kfree(tape);
+		ret = 1;
+		goto bye_game_over;
+	}
+	for (minor = 0; idetape_chrdevs[minor].drive != NULL; minor++);
+	idetape_setup (drive, tape, minor);
+	idetape_chrdevs[minor].drive = drive;
+	tape->de_r = devfs_register(drive->de, "mt", DEVFS_FL_DEFAULT,
 				    HWIF(drive)->major, minor,
 				    S_IFCHR | S_IRUGO | S_IWUGO,
 				    &idetape_fops, NULL);
-		tape->de_n =
-		    devfs_register (drive->de, "mtn", DEVFS_FL_DEFAULT,
+	tape->de_n = devfs_register(drive->de, "mtn", DEVFS_FL_DEFAULT,
 				    HWIF(drive)->major, minor + 128,
 				    S_IFCHR | S_IRUGO | S_IWUGO,
 				    &idetape_fops, NULL);
-		devfs_register_tape (tape->de_r);
-		supported++; failed--;
-	} while ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) != NULL);
-	if (!idetape_chrdev_present && !supported) {
-		devfs_unregister_chrdev (IDETAPE_MAJOR, "ht");
-	} else
-		idetape_chrdev_present = 1;
-	ide_register_module (&idetape_module);
+	devfs_register_tape(tape->de_r);
+
+bye_game_over:
 	MOD_DEC_USE_COUNT;
-#if ONSTREAM_DEBUG
-	printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
-#endif
 
-	return 0;
-#else
-	return 1;
-#endif
+	return ret;
 }
 
 MODULE_DESCRIPTION("ATAPI Streaming TAPE Driver");
@@ -6278,94 +6574,120 @@
 
 	for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++) {
 		drive = idetape_chrdevs[minor].drive;
-		if (drive != NULL && idetape_cleanup (drive))
-		printk (KERN_ERR "ide-tape: %s: cleanup_module() called while still busy\n", drive->name);
+		if (drive) {
+			if (idetape_cleanup(drive))
+				printk(KERN_ERR "ide-tape: %s: cleanup_module() "
+					"called while still busy\n", drive->name);
+#ifdef CONFIG_PROC_FS
+			if (drive->proc)
+				ide_remove_proc_entries(drive->proc, idetape_proc);
+#endif
+		}
 	}
+
 	ide_unregister_module(&idetape_module);
 }
 
-/*
- *	idetape_init will register the driver for each tape.
- */
 int idetape_init (void)
 {
+#ifdef CLASSIC_BUILTINS_METHOD
 	ide_drive_t *drive;
 	idetape_tape_t *tape;
 	int minor, failed = 0, supported = 0;
 /* DRIVER(drive)->busy++; */
 	MOD_INC_USE_COUNT;
 #if ONSTREAM_DEBUG
-        printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_init\n");
+	printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_init\n");
 #endif
 	if (!idetape_chrdev_present)
 		for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++ )
 			idetape_chrdevs[minor].drive = NULL;
-
-	if ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) == NULL) {
-		ide_register_module (&idetape_module);
+	if ((drive = ide_scan_devices(ide_tape, idetape_driver.name,
+			NULL, failed++)) == NULL) {
+		ide_register_module(&idetape_module);
 		MOD_DEC_USE_COUNT;
 #if ONSTREAM_DEBUG
-		printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
+		printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in "
+			"idetape_init\n");
 #endif
 		return 0;
 	}
 	if (!idetape_chrdev_present &&
-	    devfs_register_chrdev (IDETAPE_MAJOR, "ht", &idetape_fops)) {
-		printk (KERN_ERR "ide-tape: Failed to register character device interface\n");
+	    devfs_register_chrdev(IDETAPE_MAJOR, "ht", &idetape_fops)) {
+		printk(KERN_ERR "ide-tape: Failed to register character "
+			"device interface\n");
 		MOD_DEC_USE_COUNT;
 #if ONSTREAM_DEBUG
-		printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
+		printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in "
+			"idetape_init\n");
 #endif
 		return -EBUSY;
 	}
 	do {
-		if (!idetape_identify_device (drive, drive->id)) {
-			printk (KERN_ERR "ide-tape: %s: not supported by this version of ide-tape\n", drive->name);
+		if (!idetape_identify_device(drive, drive->id)) {
+			printk(KERN_ERR "ide-tape: %s: not supported by this "
+				"version of ide-tape\n", drive->name);
 			continue;
 		}
 		if (drive->scsi) {
 			if (strstr(drive->id->model, "OnStream DI-")) {
-				printk("ide-tape: ide-scsi emulation is not supported for %s.\n", drive->id->model);
+				printk("ide-tape: ide-scsi emulation is not "
+					"supported for %s.\n",
+					drive->id->model);
 			} else {
-				printk("ide-tape: passing drive %s to ide-scsi emulation.\n", drive->name);
+				printk("ide-tape: passing drive %s to "
+					"ide-scsi emulation.\n", drive->name);
 				continue;
 			}
 		}
 		tape = (idetape_tape_t *) kmalloc (sizeof (idetape_tape_t), GFP_KERNEL);
 		if (tape == NULL) {
-			printk (KERN_ERR "ide-tape: %s: Can't allocate a tape structure\n", drive->name);
+			printk(KERN_ERR "ide-tape: %s: Can't allocate a tape "
+				"structure\n", drive->name);
 			continue;
 		}
-		if (ide_register_subdriver (drive, &idetape_driver, IDE_SUBDRIVER_VERSION)) {
-			printk (KERN_ERR "ide-tape: %s: Failed to register the driver with ide.c\n", drive->name);
-			kfree (tape);
+		if (ide_register_subdriver(drive,
+				&idetape_driver, IDE_SUBDRIVER_VERSION)) {
+			printk(KERN_ERR "ide-tape: %s: Failed to register the "
+				"driver with ide.c\n", drive->name);
+			kfree(tape);
 			continue;
 		}
 		for (minor = 0; idetape_chrdevs[minor].drive != NULL; minor++);
-		idetape_setup (drive, tape, minor);
+		idetape_setup(drive, tape, minor);
 		idetape_chrdevs[minor].drive = drive;
 		tape->de_r =
-		    devfs_register (drive->de, "mt", DEVFS_FL_DEFAULT,
+		    devfs_register(drive->de, "mt", DEVFS_FL_DEFAULT,
 				    HWIF(drive)->major, minor,
 				    S_IFCHR | S_IRUGO | S_IWUGO,
 				    &idetape_fops, NULL);
 		tape->de_n =
-		    devfs_register (drive->de, "mtn", DEVFS_FL_DEFAULT,
+		    devfs_register(drive->de, "mtn", DEVFS_FL_DEFAULT,
 				    HWIF(drive)->major, minor + 128,
 				    S_IFCHR | S_IRUGO | S_IWUGO,
 				    &idetape_fops, NULL);
-		devfs_register_tape (tape->de_r);
-		supported++; failed--;
-	} while ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) != NULL);
+		devfs_register_tape(tape->de_r);
+		supported++;
+		failed--;
+	} while ((drive = ide_scan_devices(ide_tape,
+			idetape_driver.name, NULL, failed++)) != NULL);
 	if (!idetape_chrdev_present && !supported) {
-		devfs_unregister_chrdev (IDETAPE_MAJOR, "ht");
+		devfs_unregister_chrdev(IDETAPE_MAJOR, "ht");
 	} else
 		idetape_chrdev_present = 1;
-	ide_register_module (&idetape_module);
+#else /* ! CLASSIC_BUILTINS_METHOD */
+	int minor = 0;
+
+	if (idetape_chrdev_present)
+		return 0;
+	idetape_chrdev_present = 1;
+	for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++ )
+		idetape_chrdevs[minor].drive = NULL;
+	devfs_register_chrdev(IDETAPE_MAJOR, "ht", &idetape_fops);
+	MOD_INC_USE_COUNT;
+#endif /* CLASSIC_BUILTINS_METHOD */
+	ide_register_module(&idetape_module);
 	MOD_DEC_USE_COUNT;
-#if ONSTREAM_DEBUG
-	printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
-#endif
 	return 0;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-taskfile.c linux-2.4.21-pre6/drivers/ide/ide-taskfile.c
--- linux-2.4.20/drivers/ide/ide-taskfile.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/ide-taskfile.c	2003-03-26 23:49:06.000000000 +0000
@@ -1,12 +1,29 @@
 /*
- * linux/drivers/ide/ide-taskfile.c	Version 0.20	Oct 11, 2000
+ * linux/drivers/ide/ide-taskfile.c	Version 0.33	April 11, 2002
  *
- *  Copyright (C) 2000		Michael Cornwell <cornwell@acm.org>
- *  Copyright (C) 2000		Andre Hedrick <andre@linux-ide.org>
+ *  Copyright (C) 2000-2002	Michael Cornwell <cornwell@acm.org>
+ *  Copyright (C) 2000-2002	Andre Hedrick <andre@linux-ide.org>
+ *  Copyright (C) 2001-2002	Klaus Smolin
+ *					IBM Storage Technology Division
  *
- *  May be copied or modified under the terms of the GNU General Public License
+ *  The big the bad and the ugly.
  *
- * IDE_DEBUG(__LINE__);
+ *  Problems to be fixed because of BH interface or the lack therefore.
+ *
+ *  Fill me in stupid !!!
+ *
+ *  HOST:
+ *	General refers to the Controller and Driver "pair".
+ *  DATA HANDLER:
+ *	Under the context of Linux it generally refers to an interrupt handler.
+ *	However, it correctly describes the 'HOST'
+ *  DATA BLOCK:
+ *	The amount of data needed to be transfered as predefined in the
+ *	setup of the device.
+ *  STORAGE ATOMIC:
+ *	The 'DATA BLOCK' associated to the 'DATA HANDLER', and can be as
+ *	small as a single sector or as large as the entire command block
+ *	request.
  */
 
 #include <linux/config.h>
@@ -34,27 +51,50 @@
 #include <asm/io.h>
 #include <asm/bitops.h>
 
-#ifdef CONFIG_IDE_TASKFILE_IO
-#  define __TASKFILE__IO
-#else /* CONFIG_IDE_TASKFILE_IO */
-#  undef __TASKFILE__IO
-#endif /* CONFIG_IDE_TASKFILE_IO */
-
 #define DEBUG_TASKFILE	0	/* unset when fixed */
 
 #if DEBUG_TASKFILE
-#define DTF(x...) printk(##x)
+#define DTF(x...) printk(x)
 #else
 #define DTF(x...)
 #endif
 
+/*
+ *
+ */
+#define task_rq_offset(rq) \
+	(((rq)->nr_sectors - (rq)->current_nr_sectors) * SECTOR_SIZE)
+
+/*
+ * for now, taskfile requests are special :/
+ *
+ * However, upon the creation of the atapi version of packet_command
+ * data-phase ISR plus it own diagnostics and extensions for direct access
+ * (ioctl,read,write,rip,stream -- atapi), the kmap/kunmap for PIO will
+ * come localized.
+ */
+inline char *task_map_rq (struct request *rq, unsigned long *flags)
+{
+	if (rq->bh)
+		return ide_map_buffer(rq, flags);
+	return rq->buffer + task_rq_offset(rq);
+}
+
+inline void task_unmap_rq (struct request *rq, char *buf, unsigned long *flags)
+{
+	if (rq->bh)
+		ide_unmap_buffer(buf, flags);
+}
+
 inline u32 task_read_24 (ide_drive_t *drive)
 {
-	return	(IN_BYTE(IDE_HCYL_REG)<<16) |
-		(IN_BYTE(IDE_LCYL_REG)<<8) |
-		 IN_BYTE(IDE_SECTOR_REG);
+	return	(HWIF(drive)->INB(IDE_HCYL_REG)<<16) |
+		(HWIF(drive)->INB(IDE_LCYL_REG)<<8) |
+		 HWIF(drive)->INB(IDE_SECTOR_REG);
 }
 
+EXPORT_SYMBOL(task_read_24);
+
 static void ata_bswap_data (void *buffer, int wcount)
 {
 	u16 *p = buffer;
@@ -65,381 +105,178 @@
 	}
 }
 
-#if SUPPORT_VLB_SYNC
-/*
- * Some localbus EIDE interfaces require a special access sequence
- * when using 32-bit I/O instructions to transfer data.  We call this
- * the "vlb_sync" sequence, which consists of three successive reads
- * of the sector count register location, with interrupts disabled
- * to ensure that the reads all happen together.
- */
-static inline void task_vlb_sync (ide_ioreg_t port) {
-	(void) inb (port);
-	(void) inb (port);
-	(void) inb (port);
-}
-#endif /* SUPPORT_VLB_SYNC */
-
-/*
- * This is used for most PIO data transfers *from* the IDE interface
- */
-void ata_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
-{
-	byte io_32bit = drive->io_32bit;
-
-	if (io_32bit) {
-#if SUPPORT_VLB_SYNC
-		if (io_32bit & 2) {
-			unsigned long flags;
-			__save_flags(flags);	/* local CPU only */
-			__cli();		/* local CPU only */
-			task_vlb_sync(IDE_NSECTOR_REG);
-			insl(IDE_DATA_REG, buffer, wcount);
-			__restore_flags(flags);	/* local CPU only */
-		} else
-#endif /* SUPPORT_VLB_SYNC */
-			insl(IDE_DATA_REG, buffer, wcount);
-	} else {
-#if SUPPORT_SLOW_DATA_PORTS
-		if (drive->slow) {
-			unsigned short *ptr = (unsigned short *) buffer;
-			while (wcount--) {
-				*ptr++ = inw_p(IDE_DATA_REG);
-				*ptr++ = inw_p(IDE_DATA_REG);
-			}
-		} else
-#endif /* SUPPORT_SLOW_DATA_PORTS */
-			insw(IDE_DATA_REG, buffer, wcount<<1);
-	}
-}
-
-/*
- * This is used for most PIO data transfers *to* the IDE interface
- */
-void ata_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
-{
-	byte io_32bit = drive->io_32bit;
-
-	if (io_32bit) {
-#if SUPPORT_VLB_SYNC
-		if (io_32bit & 2) {
-			unsigned long flags;
-			__save_flags(flags);	/* local CPU only */
-			__cli();		/* local CPU only */
-			task_vlb_sync(IDE_NSECTOR_REG);
-			outsl(IDE_DATA_REG, buffer, wcount);
-			__restore_flags(flags);	/* local CPU only */
-		} else
-#endif /* SUPPORT_VLB_SYNC */
-			outsl(IDE_DATA_REG, buffer, wcount);
-	} else {
-#if SUPPORT_SLOW_DATA_PORTS
-		if (drive->slow) {
-			unsigned short *ptr = (unsigned short *) buffer;
-			while (wcount--) {
-				outw_p(*ptr++, IDE_DATA_REG);
-				outw_p(*ptr++, IDE_DATA_REG);
-			}
-		} else
-#endif /* SUPPORT_SLOW_DATA_PORTS */
-			outsw(IDE_DATA_REG, buffer, wcount<<1);
-	}
-}
-
 
-static inline void taskfile_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+void taskfile_input_data (ide_drive_t *drive, void *buffer, u32 wcount)
 {
-	ata_input_data(drive, buffer, wcount);
+	HWIF(drive)->ata_input_data(drive, buffer, wcount);
 	if (drive->bswap)
 		ata_bswap_data(buffer, wcount);
 }
 
-static inline void taskfile_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+EXPORT_SYMBOL(taskfile_input_data);
+
+void taskfile_output_data (ide_drive_t *drive, void *buffer, u32 wcount)
 {
 	if (drive->bswap) {
 		ata_bswap_data(buffer, wcount);
-		ata_output_data(drive, buffer, wcount);
+		HWIF(drive)->ata_output_data(drive, buffer, wcount);
 		ata_bswap_data(buffer, wcount);
 	} else {
-		ata_output_data(drive, buffer, wcount);
+		HWIF(drive)->ata_output_data(drive, buffer, wcount);
 	}
 }
 
-ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
-{
-	task_struct_t *taskfile = (task_struct_t *) task->tfRegister;
-	hob_struct_t *hobfile = (hob_struct_t *) task->hobRegister;
-	struct hd_driveid *id = drive->id;
-	byte HIHI = (drive->addressing) ? 0xE0 : 0xEF;
-
-	/* (ks/hs): Moved to start, do not use for multiple out commands */
-	if (task->handler != task_mulout_intr) {
-		if (IDE_CONTROL_REG)
-			OUT_BYTE(drive->ctl, IDE_CONTROL_REG);	/* clear nIEN */
-		SELECT_MASK(HWIF(drive), drive, 0);
-	}
-
-	if ((id->command_set_2 & 0x0400) &&
-	    (id->cfs_enable_2 & 0x0400) &&
-	    (drive->addressing == 1)) {
-		OUT_BYTE(hobfile->feature, IDE_FEATURE_REG);
-		OUT_BYTE(hobfile->sector_count, IDE_NSECTOR_REG);
-		OUT_BYTE(hobfile->sector_number, IDE_SECTOR_REG);
-		OUT_BYTE(hobfile->low_cylinder, IDE_LCYL_REG);
-		OUT_BYTE(hobfile->high_cylinder, IDE_HCYL_REG);
-	}
-
-	OUT_BYTE(taskfile->feature, IDE_FEATURE_REG);
-	OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG);
-	/* refers to number of sectors to transfer */
-	OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG);
-	/* refers to sector offset or start sector */
-	OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG);
-	OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG);
-
-	OUT_BYTE((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG);
-	if (task->handler != NULL) {
-#if 0
-		ide_set_handler (drive, task->handler, WAIT_CMD, NULL);
-		OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
-		/*
-		 * warning check for race between handler and prehandler for
-		 * writing first block of data.  however since we are well
-		 * inside the boundaries of the seek, we should be okay.
-		 */
-		if (task->prehandler != NULL) {
-			return task->prehandler(drive, task->rq);
-		}
-#else
-		ide_startstop_t startstop;
-
-		ide_set_handler (drive, task->handler, WAIT_CMD, NULL);
-		OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
-
-		if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
-			printk(KERN_ERR "%s: no DRQ after issuing %s\n",
-				drive->name,
-				drive->mult_count ? "MULTWRITE" : "WRITE");
-			return startstop;
-		}
-		/* (ks/hs): Fixed Multi Write */
-		if ((taskfile->command != WIN_MULTWRITE) &&
-		    (taskfile->command != WIN_MULTWRITE_EXT)) {
-			struct request *rq = HWGROUP(drive)->rq;
-		/* For Write_sectors we need to stuff the first sector */
-			taskfile_output_data(drive, rq->buffer, SECTOR_WORDS);
-			rq->current_nr_sectors--;
-		} else {
-		/* Stuff first sector(s) by implicitly calling the handler */
-			if (!(drive_is_ready(drive))) {
-			/* FIXME: Replace hard-coded 100, error handling? */
-				int i;
-				for (i=0; i<100; i++) {
-					if (drive_is_ready(drive))
-						break;
-				}
-			}
-			return task->handler(drive);
-		}
-#endif
-	} else {
-		/* for dma commands we down set the handler */
-		if (drive->using_dma && !(HWIF(drive)->dmaproc(((taskfile->command == WIN_WRITEDMA) || (taskfile->command == WIN_WRITEDMA_EXT)) ? ide_dma_write : ide_dma_read, drive)));
-	}
-
-	return ide_started;
-}
+EXPORT_SYMBOL(taskfile_output_data);
 
-void do_taskfile (ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, ide_handler_t *handler)
+int taskfile_lib_get_identify (ide_drive_t *drive, u8 *buf)
 {
-	struct hd_driveid *id = drive->id;
-	byte HIHI = (drive->addressing) ? 0xE0 : 0xEF;
-
-	/* (ks/hs): Moved to start, do not use for multiple out commands */
-	if (*handler != task_mulout_intr) {
-		if (IDE_CONTROL_REG)
-			OUT_BYTE(drive->ctl, IDE_CONTROL_REG);  /* clear nIEN */
-		SELECT_MASK(HWIF(drive), drive, 0);
-	}
-
-	if ((id->command_set_2 & 0x0400) &&
-	    (id->cfs_enable_2 & 0x0400) &&
-	    (drive->addressing == 1)) {
-		OUT_BYTE(hobfile->feature, IDE_FEATURE_REG);
-		OUT_BYTE(hobfile->sector_count, IDE_NSECTOR_REG);
-		OUT_BYTE(hobfile->sector_number, IDE_SECTOR_REG);
-		OUT_BYTE(hobfile->low_cylinder, IDE_LCYL_REG);
-		OUT_BYTE(hobfile->high_cylinder, IDE_HCYL_REG);
-	}
+	ide_task_t args;
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_NSECTOR_OFFSET]	= 0x01;
+	if (drive->media == ide_disk)
+		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_IDENTIFY;
+	else
+		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_PIDENTIFY;
+	args.command_type			= ide_cmd_type_parser(&args);
+	return ide_raw_taskfile(drive, &args, buf);
+}
 
-	OUT_BYTE(taskfile->feature, IDE_FEATURE_REG);
-	OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG);
-	/* refers to number of sectors to transfer */
-	OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG);
-	/* refers to sector offset or start sector */
-	OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG);
-	OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG);
+EXPORT_SYMBOL(taskfile_lib_get_identify);
 
-	OUT_BYTE((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG);
-	if (handler != NULL) {
-		ide_set_handler (drive, handler, WAIT_CMD, NULL);
-		OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
-	} else {
-		/* for dma commands we down set the handler */
-		if (drive->using_dma && !(HWIF(drive)->dmaproc(((taskfile->command == WIN_WRITEDMA) || (taskfile->command == WIN_WRITEDMA_EXT)) ? ide_dma_write : ide_dma_read, drive)));
-	}
+#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
+void debug_taskfile (ide_drive_t *drive, ide_task_t *args)
+{
+	printk(KERN_INFO "%s: ", drive->name);
+//	printk("TF.0=x%02x ", args->tfRegister[IDE_DATA_OFFSET]);
+	printk("TF.1=x%02x ", args->tfRegister[IDE_FEATURE_OFFSET]);
+	printk("TF.2=x%02x ", args->tfRegister[IDE_NSECTOR_OFFSET]);
+	printk("TF.3=x%02x ", args->tfRegister[IDE_SECTOR_OFFSET]);
+	printk("TF.4=x%02x ", args->tfRegister[IDE_LCYL_OFFSET]);
+	printk("TF.5=x%02x ", args->tfRegister[IDE_HCYL_OFFSET]);
+	printk("TF.6=x%02x ", args->tfRegister[IDE_SELECT_OFFSET]);
+	printk("TF.7=x%02x\n", args->tfRegister[IDE_COMMAND_OFFSET]);
+	printk(KERN_INFO "%s: ", drive->name);
+//	printk("HTF.0=x%02x ", args->hobRegister[IDE_DATA_OFFSET_HOB]);
+	printk("HTF.1=x%02x ", args->hobRegister[IDE_FEATURE_OFFSET_HOB]);
+	printk("HTF.2=x%02x ", args->hobRegister[IDE_NSECTOR_OFFSET_HOB]);
+	printk("HTF.3=x%02x ", args->hobRegister[IDE_SECTOR_OFFSET_HOB]);
+	printk("HTF.4=x%02x ", args->hobRegister[IDE_LCYL_OFFSET_HOB]);
+	printk("HTF.5=x%02x ", args->hobRegister[IDE_HCYL_OFFSET_HOB]);
+	printk("HTF.6=x%02x ", args->hobRegister[IDE_SELECT_OFFSET_HOB]);
+	printk("HTF.7=x%02x\n", args->hobRegister[IDE_CONTROL_OFFSET_HOB]);
 }
+#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
 
-#if 0
-ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task)
+ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
 {
-	task_struct_t *taskfile = (task_struct_t *) task->tfRegister;
-	hob_struct_t *hobfile = (hob_struct_t *) task->hobRegister;
-	struct hd_driveid *id = drive->id;
-
-	/*
-	 * (KS) Check taskfile in/out flags.
-	 * If set, then execute as it is defined.
-	 * If not set, then define default settings.
-	 * The default values are:
-	 *	write and read all taskfile registers (except data) 
-	 *	write and read the hob registers (sector,nsector,lcyl,hcyl)
-	 */
-	if (task->tf_out_flags.all == 0) {
-		task->tf_out_flags.all = IDE_TASKFILE_STD_OUT_FLAGS;
-		if ((id->command_set_2 & 0x0400) &&
-		    (id->cfs_enable_2 & 0x0400) &&
-		    (drive->addressing == 1)) {
-			task->tf_out_flags.all != (IDE_HOB_STD_OUT_FLAGS << 8);
-		}
-        }
-
-	if (task->tf_in_flags.all == 0) {
-		task->tf_in_flags.all = IDE_TASKFILE_STD_IN_FLAGS;
-		if ((id->command_set_2 & 0x0400) &&
-		    (id->cfs_enable_2 & 0x0400) &&
-		    (drive->addressing == 1)) {
-			task->tf_in_flags.all  != (IDE_HOB_STD_IN_FLAGS  << 8);
-		}
-        }
-
-	if (IDE_CONTROL_REG)
-		OUT_BYTE(drive->ctl, IDE_CONTROL_REG);	/* clear nIEN */
-	SELECT_MASK(HWIF(drive), drive, 0);
-
-	if (task->tf_out_flags.b.data) {
-		unsigned short data =  taskfile->data + (hobfile->data << 8);
-		OUT_WORD (data, IDE_DATA_REG);
-	}
-
-	/* (KS) send hob registers first */
-	if (task->tf_out_flags.b.nsector_hob)
-		OUT_BYTE(hobfile->sector_count, IDE_NSECTOR_REG);
-	if (task->tf_out_flags.b.sector_hob)
-		OUT_BYTE(hobfile->sector_number, IDE_SECTOR_REG);
-	if (task->tf_out_flags.b.lcyl_hob)
-		OUT_BYTE(hobfile->low_cylinder, IDE_LCYL_REG);
-	if (task->tf_out_flags.b.hcyl_hob)
-		OUT_BYTE(hobfile->high_cylinder, IDE_HCYL_REG);
+	ide_hwif_t *hwif	= HWIF(drive);
+	task_struct_t *taskfile	= (task_struct_t *) task->tfRegister;
+	hob_struct_t *hobfile	= (hob_struct_t *) task->hobRegister;
+	u8 HIHI			= (drive->addressing == 1) ? 0xE0 : 0xEF;
 
+#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
+	void debug_taskfile(drive, task);
+#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
 
-	/* (KS) Send now the standard registers */
-	if (task->tf_out_flags.b.error_feature)
-		OUT_BYTE(taskfile->feature, IDE_FEATURE_REG);
-	/* refers to number of sectors to transfer */
-	if (task->tf_out_flags.b.nsector)
-		OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG);
-	/* refers to sector offset or start sector */
-	if (task->tf_out_flags.b.sector)
-		OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG);
-	if (task->tf_out_flags.b.lcyl)
-		OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG);
-	if (task->tf_out_flags.b.hcyl)
-		OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG);
+	/* ALL Command Block Executions SHALL clear nIEN, unless otherwise */
+	if (IDE_CONTROL_REG) {
+		/* clear nIEN */
+		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
+	}
+	SELECT_MASK(drive, 0);
+
+	if (drive->addressing == 1) {
+		hwif->OUTB(hobfile->feature, IDE_FEATURE_REG);
+		hwif->OUTB(hobfile->sector_count, IDE_NSECTOR_REG);
+		hwif->OUTB(hobfile->sector_number, IDE_SECTOR_REG);
+		hwif->OUTB(hobfile->low_cylinder, IDE_LCYL_REG);
+		hwif->OUTB(hobfile->high_cylinder, IDE_HCYL_REG);
+	}
+
+	hwif->OUTB(taskfile->feature, IDE_FEATURE_REG);
+	hwif->OUTB(taskfile->sector_count, IDE_NSECTOR_REG);
+	hwif->OUTB(taskfile->sector_number, IDE_SECTOR_REG);
+	hwif->OUTB(taskfile->low_cylinder, IDE_LCYL_REG);
+	hwif->OUTB(taskfile->high_cylinder, IDE_HCYL_REG);
 
-        /*
-	 * (KS) Do not modify the specified taskfile. We want to have a
-	 * universal pass through, so we must execute ALL specified values.
-	 *
-	 * (KS) The drive head register is mandatory.
-	 * Don't care about the out flags !
-	 */
-	OUT_BYTE(taskfile->device_head | drive->select.all, IDE_SELECT_REG);
+	hwif->OUTB((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG);
 	if (task->handler != NULL) {
-#if 0
-		ide_set_handler (drive, task->handler, WAIT_CMD, NULL);
-		OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
-		/*
-		 * warning check for race between handler and prehandler for
-		 * writing first block of data.  however since we are well
-		 * inside the boundaries of the seek, we should be okay.
-		 */
-		if (task->prehandler != NULL) {
+		ide_set_handler(drive, task->handler, WAIT_WORSTCASE, NULL);
+		hwif->OUTB(taskfile->command, IDE_COMMAND_REG);
+		if (task->prehandler != NULL)
 			return task->prehandler(drive, task->rq);
-		}
-#else
-		ide_startstop_t startstop;
-
-		ide_set_handler (drive, task->handler, WAIT_CMD, NULL);
-
-		/*
-		 * (KS) The drive command register is also mandatory.
-		 * Don't care about the out flags !
-		 */
-		OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
-
-		if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
-			printk(KERN_ERR "%s: no DRQ after issuing %s\n",
-				drive->name,
-				drive->mult_count ? "MULTWRITE" : "WRITE");
-			return startstop;
-		}
-		/* (ks/hs): Fixed Multi Write */
-		if ((taskfile->command != WIN_MULTWRITE) &&
-		    (taskfile->command != WIN_MULTWRITE_EXT)) {
-			struct request *rq = HWGROUP(drive)->rq;
-		/* For Write_sectors we need to stuff the first sector */
-			taskfile_output_data(drive, rq->buffer, SECTOR_WORDS);
-			rq->current_nr_sectors--;
+		return ide_started;
+	}
+	/* for dma commands we down set the handler */
+#if 0
+	if (blk_fs_request(task->rq) && drive->using_dma) {
+		if (rq_data_dir(task->rq) == READ) {
+			if (hwif->ide_dma_read(drive))
+				return ide_stopped;
 		} else {
-		/* Stuff first sector(s) by implicitly calling the handler */
-			if (!(drive_is_ready(drive))) {
-			/* FIXME: Replace hard-coded 100, error handling? */
-				int i;
-				for (i=0; i<100; i++) {
-					if (drive_is_ready(drive))
-						break;
-				}
-			}
-			return task->handler(drive);
+			if (hwif->ide_dma_write(drive))
+				return ide_stopped;
 		}
-#endif
 	} else {
-		/* for dma commands we down set the handler */
-		if (drive->using_dma && !(HWIF(drive)->dmaproc(((taskfile->command == WIN_WRITEDMA) || (taskfile->command == WIN_WRITEDMA_EXT)) ? ide_dma_write : ide_dma_read, drive)));
-	}
+		if (!drive->using_dma && (task->handler == NULL))
+			return ide_stopped;
 
+		switch(taskfile->command) {
+			case WIN_WRITEDMA_ONCE:
+			case WIN_WRITEDMA:
+			case WIN_WRITEDMA_EXT:
+				hwif->ide_dma_write(drive);
+				break;
+			case WIN_READDMA_ONCE:
+			case WIN_READDMA:
+			case WIN_READDMA_EXT:
+			case WIN_IDENTIFY_DMA:
+				hwif->ide_dma_read(drive);
+				break;
+			default:
+				if (task->handler == NULL)
+					return ide_stopped;
+		}
+	}
 	return ide_started;
-}
+#else
+	switch(taskfile->command) {
+		case WIN_WRITEDMA_ONCE:
+		case WIN_WRITEDMA:
+		case WIN_WRITEDMA_EXT:
+			if (drive->using_dma && !(hwif->ide_dma_write(drive)));
+				return ide_started;
+		case WIN_READDMA_ONCE:
+		case WIN_READDMA:
+		case WIN_READDMA_EXT:
+		case WIN_IDENTIFY_DMA:
+			if (drive->using_dma && !(hwif->ide_dma_read(drive)));
+				return ide_started;
+		default:
+			break;
+	}
+	return ide_stopped;
 #endif
+}
+
+EXPORT_SYMBOL(do_rw_taskfile);
 
-#if 0
 /*
  * Error reporting, in human readable form (luxurious, but a memory hog).
  */
-byte taskfile_dump_status (ide_drive_t *drive, const char *msg, byte stat)
+u8 taskfile_dump_status (ide_drive_t *drive, const char *msg, u8 stat)
 {
+	ide_hwif_t *hwif = HWIF(drive);
 	unsigned long flags;
-	byte err = 0;
+	u8 err = 0;
 
-	__save_flags (flags);	/* local CPU only */
-	ide__sti();		/* local CPU only */
+	local_irq_set(flags);
 	printk("%s: %s: status=0x%02x", drive->name, msg, stat);
 #if FANCY_STATUS_DUMPS
 	printk(" { ");
-	if (stat & BUSY_STAT)
+	if (stat & BUSY_STAT) {
 		printk("Busy ");
-	else {
+	} else {
 		if (stat & READY_STAT)	printk("DriveReady ");
 		if (stat & WRERR_STAT)	printk("DeviceFault ");
 		if (stat & SEEK_STAT)	printk("SeekComplete ");
@@ -452,61 +289,66 @@
 #endif  /* FANCY_STATUS_DUMPS */
 	printk("\n");
 	if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
-		err = GET_ERR();
+		err = hwif->INB(IDE_ERROR_REG);
 		printk("%s: %s: error=0x%02x", drive->name, msg, err);
 #if FANCY_STATUS_DUMPS
-		if (drive->media == ide_disk) {
-			printk(" { ");
-			if (err & ABRT_ERR)	printk("DriveStatusError ");
-			if (err & ICRC_ERR)	printk("%s", (err & ABRT_ERR) ? "BadCRC " : "BadSector ");
-			if (err & ECC_ERR)	printk("UncorrectableError ");
-			if (err & ID_ERR)	printk("SectorIdNotFound ");
-			if (err & TRK0_ERR)	printk("TrackZeroNotFound ");
-			if (err & MARK_ERR)	printk("AddrMarkNotFound ");
-			printk("}");
-			if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR || (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
-				if ((drive->id->command_set_2 & 0x0400) &&
-				    (drive->id->cfs_enable_2 & 0x0400) &&
-				    (drive->addressing == 1)) {
-					__u64 sectors = 0;
-					u32 low = 0, high = 0;
-					low = task_read_24(drive);
-					OUT_BYTE(0x80, IDE_CONTROL_REG);
-					high = task_read_24(drive);
-					sectors = ((__u64)high << 24) | low;
-					printk(", LBAsect=%lld", sectors);
+		if (drive->media == ide_disk)
+			goto media_out;
+
+		printk(" { ");
+		if (err & ABRT_ERR)	printk("DriveStatusError ");
+		if (err & ICRC_ERR)	printk("Bad%s", (err & ABRT_ERR) ? "CRC " : "Sector ");
+		if (err & ECC_ERR)	printk("UncorrectableError ");
+		if (err & ID_ERR)	printk("SectorIdNotFound ");
+		if (err & TRK0_ERR)	printk("TrackZeroNotFound ");
+		if (err & MARK_ERR)	printk("AddrMarkNotFound ");
+		printk("}");
+		if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR ||
+		    (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
+			if (drive->addressing == 1) {
+				u64 sectors = 0;
+				u32 high = 0;
+				u32 low = task_read_24(drive);
+				hwif->OUTB(0x80, IDE_CONTROL_REG);
+				high = task_read_24(drive);
+				sectors = ((u64)high << 24) | low;
+				printk(", LBAsect=%lld", sectors);
+			} else {
+				u8 cur  = hwif->INB(IDE_SELECT_REG);
+				u8 low  = hwif->INB(IDE_LCYL_REG);
+				u8 high = hwif->INB(IDE_HCYL_REG);
+				u8 sect = hwif->INB(IDE_SECTOR_REG);
+				/* using LBA? */
+				if (cur & 0x40) {
+					printk(", LBAsect=%d", (u32)
+						((cur&0xf)<<24)|(high<<16)|
+						(low<<8)|sect);
 				} else {
-					byte cur = IN_BYTE(IDE_SELECT_REG);
-					if (cur & 0x40) {	/* using LBA? */
-						printk(", LBAsect=%ld", (unsigned long)
-						 ((cur&0xf)<<24)
-						 |(IN_BYTE(IDE_HCYL_REG)<<16)
-						 |(IN_BYTE(IDE_LCYL_REG)<<8)
-						 | IN_BYTE(IDE_SECTOR_REG));
-					} else {
-						printk(", CHS=%d/%d/%d",
-						  (IN_BYTE(IDE_HCYL_REG)<<8) +
-						   IN_BYTE(IDE_LCYL_REG),
-						  cur & 0xf,
-						  IN_BYTE(IDE_SECTOR_REG));
-					}
+					printk(", CHS=%d/%d/%d",
+						((high<<8) + low),
+						(cur & 0xf), sect);
 				}
-				if (HWGROUP(drive)->rq)
-					printk(", sector=%llu", (__u64) HWGROUP(drive)->rq->sector);
 			}
+			if (HWGROUP(drive)->rq)
+				printk(", sector=%lu",
+					HWGROUP(drive)->rq->sector);
 		}
+media_out:
 #endif  /* FANCY_STATUS_DUMPS */
 		printk("\n");
 	}
-	__restore_flags (flags);	/* local CPU only */
+	local_irq_restore(flags);
 	return err;
 }
 
+EXPORT_SYMBOL(taskfile_dump_status);
+
 /*
  * Clean up after success/failure of an explicit taskfile operation.
  */
-void ide_end_taskfile (ide_drive_t *drive, byte stat, byte err)
+void ide_end_taskfile (ide_drive_t *drive, u8 stat, u8 err)
 {
+	ide_hwif_t *hwif = HWIF(drive);
 	unsigned long flags;
 	struct request *rq;
 	ide_task_t *args;
@@ -519,28 +361,39 @@
 
 	command = args->tfRegister[IDE_COMMAND_OFFSET];
 
-	rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
+	if (rq->errors == 0)
+		rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
 
+	if (args->tf_in_flags.b.data) {
+		u16 data = hwif->INW(IDE_DATA_REG);
+		args->tfRegister[IDE_DATA_OFFSET] = (data) & 0xFF;
+		args->hobRegister[IDE_DATA_OFFSET_HOB]	= (data >> 8) & 0xFF;
+	}
 	args->tfRegister[IDE_ERROR_OFFSET]   = err;
-	args->tfRegister[IDE_NSECTOR_OFFSET] = IN_BYTE(IDE_NSECTOR_REG);
-	args->tfRegister[IDE_SECTOR_OFFSET]  = IN_BYTE(IDE_SECTOR_REG);
-	args->tfRegister[IDE_LCYL_OFFSET]    = IN_BYTE(IDE_LCYL_REG);
-	args->tfRegister[IDE_HCYL_OFFSET]    = IN_BYTE(IDE_HCYL_REG);
-	args->tfRegister[IDE_SELECT_OFFSET]  = IN_BYTE(IDE_SELECT_REG);
+	args->tfRegister[IDE_NSECTOR_OFFSET] = hwif->INB(IDE_NSECTOR_REG);
+	args->tfRegister[IDE_SECTOR_OFFSET]  = hwif->INB(IDE_SECTOR_REG);
+	args->tfRegister[IDE_LCYL_OFFSET]    = hwif->INB(IDE_LCYL_REG);
+	args->tfRegister[IDE_HCYL_OFFSET]    = hwif->INB(IDE_HCYL_REG);
+	args->tfRegister[IDE_SELECT_OFFSET]  = hwif->INB(IDE_SELECT_REG);
 	args->tfRegister[IDE_STATUS_OFFSET]  = stat;
 	if ((drive->id->command_set_2 & 0x0400) &&
 	    (drive->id->cfs_enable_2 & 0x0400) &&
 	    (drive->addressing == 1)) {
-		OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG_HOB);
-		args->hobRegister[IDE_FEATURE_OFFSET_HOB] = IN_BYTE(IDE_FEATURE_REG);
-		args->hobRegister[IDE_NSECTOR_OFFSET_HOB] = IN_BYTE(IDE_NSECTOR_REG);
-		args->hobRegister[IDE_SECTOR_OFFSET_HOB]  = IN_BYTE(IDE_SECTOR_REG);
-		args->hobRegister[IDE_LCYL_OFFSET_HOB]    = IN_BYTE(IDE_LCYL_REG);
-		args->hobRegister[IDE_HCYL_OFFSET_HOB]    = IN_BYTE(IDE_HCYL_REG);
+		hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG_HOB);
+		args->hobRegister[IDE_FEATURE_OFFSET_HOB] = hwif->INB(IDE_FEATURE_REG);
+		args->hobRegister[IDE_NSECTOR_OFFSET_HOB] = hwif->INB(IDE_NSECTOR_REG);
+		args->hobRegister[IDE_SECTOR_OFFSET_HOB]  = hwif->INB(IDE_SECTOR_REG);
+		args->hobRegister[IDE_LCYL_OFFSET_HOB]    = hwif->INB(IDE_LCYL_REG);
+		args->hobRegister[IDE_HCYL_OFFSET_HOB]    = hwif->INB(IDE_HCYL_REG);
 	}
 
+#if 0
 /*	taskfile_settings_update(drive, args, command); */
 
+	if (args->posthandler != NULL)
+		args->posthandler(drive, args);
+#endif
+
 	spin_lock_irqsave(&io_request_lock, flags);
 	blkdev_dequeue_request(rq);
 	HWGROUP(drive)->rq = NULL;
@@ -548,6 +401,8 @@
 	spin_unlock_irqrestore(&io_request_lock, flags);
 }
 
+EXPORT_SYMBOL(ide_end_taskfile);
+
 /*
  * try_to_flush_leftover_data() is invoked in response to a drive
  * unexpectedly having its DRQ_STAT bit set.  As an alternative to
@@ -565,53 +420,68 @@
 		u32 buffer[16];
 		unsigned int wcount = (i > 16) ? 16 : i;
 		i -= wcount;
-		taskfile_input_data (drive, buffer, wcount);
+		taskfile_input_data(drive, buffer, wcount);
 	}
 }
 
+EXPORT_SYMBOL(task_try_to_flush_leftover_data);
+
 /*
  * taskfile_error() takes action based on the error returned by the drive.
  */
-ide_startstop_t taskfile_error (ide_drive_t *drive, const char *msg, byte stat)
+ide_startstop_t taskfile_error (ide_drive_t *drive, const char *msg, u8 stat)
 {
+	ide_hwif_t *hwif;
 	struct request *rq;
-	byte err;
+	u8 err;
 
         err = taskfile_dump_status(drive, msg, stat);
 	if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
 		return ide_stopped;
+
+	hwif = HWIF(drive);
 	/* retry only "normal" I/O: */
 	if (rq->cmd == IDE_DRIVE_TASKFILE) {
 		rq->errors = 1;
 		ide_end_taskfile(drive, stat, err);
 		return ide_stopped;
 	}
-	if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) { /* other bits are useless when BUSY */
+	if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) {
+		/* other bits are useless when BUSY */
 		rq->errors |= ERROR_RESET;
 	} else {
-		if (drive->media == ide_disk && (stat & ERR_STAT)) {
+		if (drive->media != ide_disk)
+			goto media_out;
+		if (stat & ERR_STAT) {
 			/* err has different meaning on cdrom and tape */
 			if (err == ABRT_ERR) {
-				if (drive->select.b.lba && IN_BYTE(IDE_COMMAND_REG) == WIN_SPECIFY)
-					return ide_stopped;	/* some newer drives don't support WIN_SPECIFY */
-			} else if ((err & (ABRT_ERR | ICRC_ERR)) == (ABRT_ERR | ICRC_ERR)) {
-				drive->crc_count++;	/* UDMA crc error -- just retry the operation */
-			} else if (err & (BBD_ERR | ECC_ERR))	/* retries won't help these */
+				if (drive->select.b.lba &&
+				    (hwif->INB(IDE_COMMAND_REG) == WIN_SPECIFY))
+					/* some newer drives don't
+					 * support WIN_SPECIFY
+					 */
+					return ide_stopped;
+			} else if ((err & BAD_CRC) == BAD_CRC) {
+				/* UDMA crc error -- just retry the operation */
+				drive->crc_count++;
+			} else if (err & (BBD_ERR | ECC_ERR)) {
+				/* retries won't help these */
 				rq->errors = ERROR_MAX;
-			else if (err & TRK0_ERR)	/* help it find track zero */
-                                rq->errors |= ERROR_RECAL;
+			} else if (err & TRK0_ERR) {
+				/* help it find track zero */
+				rq->errors |= ERROR_RECAL;
+			}
                 }
-                if ((stat & DRQ_STAT) && rq->cmd != WRITE)
+media_out:
+                if ((stat & DRQ_STAT) && rq_data_dir(rq) != WRITE)
                         task_try_to_flush_leftover_data(drive);
 	}
-	if (GET_STAT() & (BUSY_STAT|DRQ_STAT))
-		OUT_BYTE(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);	/* force an abort */
-
+	if (hwif->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT)) {
+		/* force an abort */
+		hwif->OUTB(WIN_IDLEIMMEDIATE, IDE_COMMAND_REG);
+	}
 	if (rq->errors >= ERROR_MAX) {
-		if (drive->driver != NULL)
-			DRIVER(drive)->end_request(0, HWGROUP(drive));
-		else
-			ide_end_request(0, HWGROUP(drive));
+		DRIVER(drive)->end_request(drive, 0);
 	} else {
 		if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
 			++rq->errors;
@@ -623,20 +493,18 @@
 	}
 	return ide_stopped;
 }
-#endif
 
-/*
- * Handler for special commands without a data phase from ide-disk
- */
+EXPORT_SYMBOL(taskfile_error);
 
 /*
  * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd.
  */
 ide_startstop_t set_multmode_intr (ide_drive_t *drive)
 {
-	byte stat;
+	ide_hwif_t *hwif = HWIF(drive);
+	u8 stat;
 
-	if (OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT)) {
+	if (OK_STAT(stat = hwif->INB(IDE_STATUS_REG),READY_STAT,BAD_STAT)) {
 		drive->mult_count = drive->mult_req;
 	} else {
 		drive->mult_req = drive->mult_count = 0;
@@ -646,282 +514,373 @@
 	return ide_stopped;
 }
 
+EXPORT_SYMBOL(set_multmode_intr);
+
 /*
  * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd.
  */
 ide_startstop_t set_geometry_intr (ide_drive_t *drive)
 {
-	byte stat;
+	ide_hwif_t *hwif = HWIF(drive);
+	int retries = 5;
+	u8 stat;
+
+	while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--)
+		udelay(10);
 
-	if (OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT))
+	if (OK_STAT(stat, READY_STAT, BAD_STAT))
 		return ide_stopped;
 
 	if (stat & (ERR_STAT|DRQ_STAT))
-		return ide_error(drive, "set_geometry_intr", stat);
+		return DRIVER(drive)->error(drive, "set_geometry_intr", stat);
 
-	ide_set_handler(drive, &set_geometry_intr, WAIT_CMD, NULL);
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	ide_set_handler(drive, &set_geometry_intr, WAIT_WORSTCASE, NULL);
 	return ide_started;
 }
 
+EXPORT_SYMBOL(set_geometry_intr);
+
 /*
  * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd.
  */
 ide_startstop_t recal_intr (ide_drive_t *drive)
 {
-	byte stat = GET_STAT();
+	ide_hwif_t *hwif = HWIF(drive);
+	u8 stat;
 
-	if (!OK_STAT(stat,READY_STAT,BAD_STAT))
-		return ide_error(drive, "recal_intr", stat);
+	if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG), READY_STAT, BAD_STAT))
+		return DRIVER(drive)->error(drive, "recal_intr", stat);
 	return ide_stopped;
 }
 
+EXPORT_SYMBOL(recal_intr);
+
 /*
  * Handler for commands without a data phase
  */
 ide_startstop_t task_no_data_intr (ide_drive_t *drive)
 {
 	ide_task_t *args	= HWGROUP(drive)->rq->special;
-	byte stat		= GET_STAT();
-
-	ide__sti();	/* local CPU only */
-
-	if (!OK_STAT(stat, READY_STAT, BAD_STAT))
-		return ide_error(drive, "task_no_data_intr", stat); /* calls ide_end_drive_cmd */
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 stat;
 
+	local_irq_enable();
+	if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG),READY_STAT,BAD_STAT)) {
+		DTF("%s: command opcode 0x%02x\n", drive->name,
+			args->tfRegister[IDE_COMMAND_OFFSET]);
+		return DRIVER(drive)->error(drive, "task_no_data_intr", stat);
+		/* calls ide_end_drive_cmd */
+	}
 	if (args)
-		ide_end_drive_cmd (drive, stat, GET_ERR());
+		ide_end_drive_cmd(drive, stat, hwif->INB(IDE_ERROR_REG));
 
 	return ide_stopped;
 }
 
+EXPORT_SYMBOL(task_no_data_intr);
+
 /*
- * Handler for command with PIO data-in phase
+ * Handler for command with PIO data-in phase, READ
+ */
+/*
+ * FIXME before 2.4 enable ...
+ *	DATA integrity issue upon error. <andre@linux-ide.org>
  */
 ide_startstop_t task_in_intr (ide_drive_t *drive)
 {
-	byte stat		= GET_STAT();
-	byte io_32bit		= drive->io_32bit;
 	struct request *rq	= HWGROUP(drive)->rq;
+	ide_hwif_t *hwif	= HWIF(drive);
 	char *pBuf		= NULL;
+	u8 stat;
+	unsigned long flags;
 
-	if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
+	if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG),DATA_READY,BAD_R_STAT)) {
 		if (stat & (ERR_STAT|DRQ_STAT)) {
-			return ide_error(drive, "task_in_intr", stat);
+#if 0
+			DTF("%s: attempting to recover last " \
+				"sector counter status=0x%02x\n",
+				drive->name, stat);
+			/*
+			 * Expect a BUG BOMB if we attempt to rewind the
+			 * offset in the BH aka PAGE in the current BLOCK
+			 * segment.  This is different than the HOST segment.
+			 */
+#endif
+			if (!rq->bh)
+				rq->current_nr_sectors++;
+			return DRIVER(drive)->error(drive, "task_in_intr", stat);
 		}
 		if (!(stat & BUSY_STAT)) {
 			DTF("task_in_intr to Soon wait for next interrupt\n");
-			ide_set_handler(drive, &task_in_intr, WAIT_CMD, NULL);
+			if (HWGROUP(drive)->handler == NULL)
+				ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL);
 			return ide_started;  
 		}
 	}
-	DTF("stat: %02x\n", stat);
-	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
-	DTF("Read: %p, rq->current_nr_sectors: %d\n", pBuf, (int) rq->current_nr_sectors);
-
-	drive->io_32bit = 0;
-	taskfile_input_data(drive, pBuf, SECTOR_WORDS);
-	drive->io_32bit = io_32bit;
-
-	if (--rq->current_nr_sectors <= 0) {
-		/* (hs): swapped next 2 lines */
-		DTF("Request Ended stat: %02x\n", GET_STAT());
-		ide_end_request(1, HWGROUP(drive));
-	} else {
-		ide_set_handler(drive, &task_in_intr,  WAIT_CMD, NULL);
-		return ide_started;
-	}
-	return ide_stopped;
-}
+#if 0
 
-#undef ALTSTAT_SCREW_UP
+	/*
+	 * Holding point for a brain dump of a thought :-/
+	 */
 
-#ifdef ALTSTAT_SCREW_UP
-/*
- * (ks/hs): Poll Alternate Status Register to ensure
- * that drive is not busy.
- */
-byte altstat_multi_busy (ide_drive_t *drive, byte stat, const char *msg)
-{
-	int i;
+	if (!OK_STAT(stat,DRIVE_READY,drive->bad_wstat)) {
+		DTF("%s: READ attempting to recover last " \
+			"sector counter status=0x%02x\n",
+			drive->name, stat);
+		rq->current_nr_sectors++;
+		return DRIVER(drive)->error(drive, "task_in_intr", stat);
+        }
+	if (!rq->current_nr_sectors)
+		if (!DRIVER(drive)->end_request(drive, 1))
+			return ide_stopped;
+
+	if (--rq->current_nr_sectors <= 0)
+		if (!DRIVER(drive)->end_request(drive, 1))
+			return ide_stopped;
+#endif
 
-	DTF("multi%s: ASR = %x\n", msg, stat);
-	if (stat & BUSY_STAT) {
-		/* (ks/hs): FIXME: Replace hard-coded 100, error handling? */
-		for (i=0; i<100; i++) {
-			stat = GET_ALTSTAT();
-			if ((stat & BUSY_STAT) == 0)
-				break;
-		}
-	}
+	pBuf = task_map_rq(rq, &flags);
+	DTF("Read: %p, rq->current_nr_sectors: %d, stat: %02x\n",
+		pBuf, (int) rq->current_nr_sectors, stat);
+	taskfile_input_data(drive, pBuf, SECTOR_WORDS);
+	task_unmap_rq(rq, pBuf, &flags);
+	/*
+	 * FIXME :: We really can not legally get a new page/bh
+	 * regardless, if this is the end of our segment.
+	 * BH walking or segment can only be updated after we have a good
+	 * hwif->INB(IDE_STATUS_REG); return.
+	 */
+	if (--rq->current_nr_sectors <= 0)
+		if (!DRIVER(drive)->end_request(drive, 1))
+			return ide_stopped;
 	/*
-	 * (ks/hs): Read Status AFTER Alternate Status Register
+	 * ERM, it is techincally legal to leave/exit here but it makes
+	 * a mess of the code ...
 	 */
-	return(GET_STAT());
+	if (HWGROUP(drive)->handler == NULL)
+		ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL);
+	return ide_started;
 }
 
-/*
- * (ks/hs): Poll Alternate status register to wait for drive
- * to become ready for next transfer
- */
-byte altstat_multi_poll (ide_drive_t *drive, byte stat, const char *msg)
-{
-	/* (ks/hs): FIXME: Error handling, time-out? */
-	while (stat & BUSY_STAT)
-		stat = GET_ALTSTAT();
-	DTF("multi%s: nsect=1, ASR = %x\n", msg, stat);
-	return(GET_STAT());	/* (ks/hs): Clear pending IRQ */
-}
-#endif /* ALTSTAT_SCREW_UP */
+EXPORT_SYMBOL(task_in_intr);
 
 /*
  * Handler for command with Read Multiple
  */
 ide_startstop_t task_mulin_intr (ide_drive_t *drive)
 {
-	unsigned int		msect, nsect;
-
-#ifdef ALTSTAT_SCREW_UP
-	byte stat	= altstat_multi_busy(drive, GET_ALTSTAT(), "read");
-#else
-	byte stat		= GET_STAT();
-#endif /* ALTSTAT_SCREW_UP */
-
-	byte io_32bit		= drive->io_32bit;
+	ide_hwif_t *hwif	= HWIF(drive);
 	struct request *rq	= HWGROUP(drive)->rq;
 	char *pBuf		= NULL;
+	unsigned int msect	= drive->mult_count;
+	unsigned int nsect;
+	unsigned long flags;
+	u8 stat;
 
-	if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
+	if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG),DATA_READY,BAD_R_STAT)) {
 		if (stat & (ERR_STAT|DRQ_STAT)) {
-			return ide_error(drive, "task_mulin_intr", stat);
+			if (!rq->bh) {
+				rq->current_nr_sectors += drive->mult_count;
+				/*
+				 * NOTE: could rewind beyond beginning :-/
+				 */
+			} else {
+				printk("%s: MULTI-READ assume all data " \
+					"transfered is bad status=0x%02x\n",
+					drive->name, stat);
+			}
+			return DRIVER(drive)->error(drive, "task_mulin_intr", stat);
 		}
 		/* no data yet, so wait for another interrupt */
-		ide_set_handler(drive, &task_mulin_intr, WAIT_CMD, NULL);
+		if (HWGROUP(drive)->handler == NULL)
+			ide_set_handler(drive, &task_mulin_intr, WAIT_WORSTCASE, NULL);
 		return ide_started;
 	}
 
-	/* (ks/hs): Fixed Multi-Sector transfer */
-	msect = drive->mult_count;
-
-#ifdef ALTSTAT_SCREW_UP
-	/*
-	 * Screw the request we do not support bad data-phase setups!
-	 * Either read and learn the ATA standard or crash yourself!
-	 */
-	if (!msect) {
+	do {
+		nsect = rq->current_nr_sectors;
+		if (nsect > msect)
+			nsect = msect;
+		pBuf = task_map_rq(rq, &flags);
+		DTF("Multiread: %p, nsect: %d, msect: %d, " \
+			" rq->current_nr_sectors: %d\n",
+			pBuf, nsect, msect, rq->current_nr_sectors);
+		taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
+		task_unmap_rq(rq, pBuf, &flags);
+		rq->errors = 0;
+		rq->current_nr_sectors -= nsect;
+		msect -= nsect;
 		/*
-		 * (ks/hs): Drive supports multi-sector transfer,
-		 * drive->mult_count was not set
+		 * FIXME :: We really can not legally get a new page/bh
+		 * regardless, if this is the end of our segment.
+		 * BH walking or segment can only be updated after we have a
+		 * good hwif->INB(IDE_STATUS_REG); return.
 		 */
-		nsect = 1;
-		while (rq->current_nr_sectors) {
-			pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
-			DTF("Multiread: %p, nsect: %d, rq->current_nr_sectors: %ld\n", pBuf, nsect, rq->current_nr_sectors);
-			drive->io_32bit = 0;
-			taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
-			drive->io_32bit = io_32bit;
-			rq->errors = 0;
-			rq->current_nr_sectors -= nsect;
-			stat = altstat_multi_poll(drive, GET_ALTSTAT(), "read");
-		}
-		ide_end_request(1, HWGROUP(drive));
-		return ide_stopped;
-	}
-#endif /* ALTSTAT_SCREW_UP */
+		if (!rq->current_nr_sectors) {
+			if (!DRIVER(drive)->end_request(drive, 1))
+				return ide_stopped;
+		}
+	} while (msect);
+	if (HWGROUP(drive)->handler == NULL)
+		ide_set_handler(drive, &task_mulin_intr, WAIT_WORSTCASE, NULL);
+	return ide_started;
+}
 
-	nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors;
-	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
-
-	DTF("Multiread: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
-		pBuf, nsect, rq->current_nr_sectors);
-	drive->io_32bit = 0;
-	taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
-	drive->io_32bit = io_32bit;
-	rq->errors = 0;
-	rq->current_nr_sectors -= nsect;
-	if (rq->current_nr_sectors != 0) {
-		ide_set_handler(drive, &task_mulin_intr, WAIT_CMD, NULL);
-		return ide_started;
-	}
-	ide_end_request(1, HWGROUP(drive));
-	return ide_stopped;
-}
+EXPORT_SYMBOL(task_mulin_intr);
 
+/*
+ * VERIFY ME before 2.4 ... unexpected race is possible based on details
+ * RMK with 74LS245/373/374 TTL buffer logic because of passthrough.
+ */
 ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq)
 {
-	ide_task_t *args = rq->special;
+	char *pBuf		= NULL;
+	unsigned long flags;
 	ide_startstop_t startstop;
 
-	if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
-		printk(KERN_ERR "%s: no DRQ after issuing %s\n", drive->name, drive->mult_count ? "MULTWRITE" : "WRITE");
+	if (ide_wait_stat(&startstop, drive, DATA_READY,
+			drive->bad_wstat, WAIT_DRQ)) {
+		printk(KERN_ERR "%s: no DRQ after issuing WRITE%s\n",
+			drive->name,
+			drive->addressing ? "_EXT" : "");
 		return startstop;
 	}
-
-	/* (ks/hs): Fixed Multi Write */
-	if ((args->tfRegister[IDE_COMMAND_OFFSET] != WIN_MULTWRITE) &&
-	    (args->tfRegister[IDE_COMMAND_OFFSET] != WIN_MULTWRITE_EXT)) {
-		/* For Write_sectors we need to stuff the first sector */
-		taskfile_output_data(drive, rq->buffer, SECTOR_WORDS);
-		rq->current_nr_sectors--;
-		return ide_started;
-	} else {
-		/*
-		 * (ks/hs): Stuff the first sector(s)
-		 * by implicitly calling the handler
-		 */
-		if (!(drive_is_ready(drive))) {
-			int i;
-			/*
-			 * (ks/hs): FIXME: Replace hard-coded
-			 *               100, error handling?
-			 */
-			for (i=0; i<100; i++) {
-				if (drive_is_ready(drive))
-					break;
-			}
-		}
-		return args->handler(drive);
-	}
+	/* For Write_sectors we need to stuff the first sector */
+	pBuf = task_map_rq(rq, &flags);
+	taskfile_output_data(drive, pBuf, SECTOR_WORDS);
+	rq->current_nr_sectors--;
+	task_unmap_rq(rq, pBuf, &flags);
 	return ide_started;
 }
 
+EXPORT_SYMBOL(pre_task_out_intr);
+
 /*
- * Handler for command with PIO data-out phase
+ * Handler for command with PIO data-out phase WRITE
+ *
+ * WOOHOO this is a CORRECT STATE DIAGRAM NOW, <andre@linux-ide.org>
  */
 ide_startstop_t task_out_intr (ide_drive_t *drive)
 {
-	byte stat		= GET_STAT();
-	byte io_32bit		= drive->io_32bit;
+	ide_hwif_t *hwif	= HWIF(drive);
 	struct request *rq	= HWGROUP(drive)->rq;
 	char *pBuf		= NULL;
+	unsigned long flags;
+	u8 stat;
 
-	if (!rq->current_nr_sectors) { 
-		ide_end_request(1, HWGROUP(drive));
-		return ide_stopped;
-	}
-
-	if (!OK_STAT(stat,DRIVE_READY,drive->bad_wstat)) {
-		return ide_error(drive, "task_out_intr", stat);
+	if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG), DRIVE_READY, drive->bad_wstat)) {
+		DTF("%s: WRITE attempting to recover last " \
+			"sector counter status=0x%02x\n",
+			drive->name, stat);
+		rq->current_nr_sectors++;
+		return DRIVER(drive)->error(drive, "task_out_intr", stat);
 	}
+	/*
+	 * Safe to update request for partial completions.
+	 * We have a good STATUS CHECK!!!
+	 */
+	if (!rq->current_nr_sectors)
+		if (!DRIVER(drive)->end_request(drive, 1))
+			return ide_stopped;
 	if ((rq->current_nr_sectors==1) ^ (stat & DRQ_STAT)) {
 		rq = HWGROUP(drive)->rq;
-		pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
-		DTF("write: %p, rq->current_nr_sectors: %d\n", pBuf, (int) rq->current_nr_sectors);
-		drive->io_32bit = 0;
+		pBuf = task_map_rq(rq, &flags);
+		DTF("write: %p, rq->current_nr_sectors: %d\n",
+			pBuf, (int) rq->current_nr_sectors);
 		taskfile_output_data(drive, pBuf, SECTOR_WORDS);
-		drive->io_32bit = io_32bit;
+		task_unmap_rq(rq, pBuf, &flags);
 		rq->errors = 0;
 		rq->current_nr_sectors--;
 	}
+	if (HWGROUP(drive)->handler == NULL)
+		ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL);
+	return ide_started;
+}
 
-	if (rq->current_nr_sectors <= 0) {
-		ide_end_request(1, HWGROUP(drive));
-	} else {
-		ide_set_handler(drive, &task_out_intr, WAIT_CMD, NULL);
-		return ide_started;
+EXPORT_SYMBOL(task_out_intr);
+
+#undef ALTERNATE_STATE_DIAGRAM_MULTI_OUT
+
+ide_startstop_t pre_task_mulout_intr (ide_drive_t *drive, struct request *rq)
+{
+#ifdef ALTERNATE_STATE_DIAGRAM_MULTI_OUT
+	ide_hwif_t *hwif		= HWIF(drive);
+	char *pBuf			= NULL;
+	unsigned int nsect = 0, msect	= drive->mult_count;
+        u8 stat;
+	unsigned long flags;
+#endif /* ALTERNATE_STATE_DIAGRAM_MULTI_OUT */
+
+	ide_task_t *args = rq->special;
+	ide_startstop_t startstop;
+
+#if 0
+	/*
+	 * assign private copy for multi-write
+	 */
+	memcpy(&HWGROUP(drive)->wrq, rq, sizeof(struct request));
+#endif
+
+	if (ide_wait_stat(&startstop, drive, DATA_READY,
+			drive->bad_wstat, WAIT_DRQ)) {
+		printk(KERN_ERR "%s: no DRQ after issuing %s\n",
+			drive->name,
+			drive->addressing ? "MULTWRITE_EXT" : "MULTWRITE");
+		return startstop;
 	}
-	return ide_stopped;
+#ifdef ALTERNATE_STATE_DIAGRAM_MULTI_OUT
+
+	do {
+		nsect = rq->current_nr_sectors;
+		if (nsect > msect)
+			nsect = msect;
+		pBuf = task_map_rq(rq, &flags);
+		DTF("Pre-Multiwrite: %p, nsect: %d, msect: %d, " \
+			"rq->current_nr_sectors: %ld\n",
+			pBuf, nsect, msect, rq->current_nr_sectors);
+		msect -= nsect;
+		taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
+		task_unmap_rq(rq, pBuf, &flags);
+		rq->current_nr_sectors -= nsect;
+		if (!rq->current_nr_sectors) {
+			if (!DRIVER(drive)->end_request(drive, 1))
+				if (!rq->bh) {
+					stat = hwif->INB(IDE_STATUS_REG);
+					return ide_stopped;
+				}
+		}
+	} while (msect);
+	rq->errors = 0;
+	return ide_started;
+#else /* ! ALTERNATE_STATE_DIAGRAM_MULTI_OUT */
+
+#if 0
+	if (wait_for_ready(drive, 100))
+		IDE_DEBUG(__LINE__);		//BUG();
+#else
+	if (!(drive_is_ready(drive))) {
+		int i;
+		for (i=0; i<100; i++) {
+			if (drive_is_ready(drive))
+				break;
+		}
+	}
+#endif
+	/*
+	 * WARNING :: if the drive as not acked good status we may not
+	 * move the DATA-TRANSFER T-Bar as BSY != 0. <andre@linux-ide.org>
+	 */
+	return args->handler(drive);
+#endif /* ALTERNATE_STATE_DIAGRAM_MULTI_OUT */
 }
 
+EXPORT_SYMBOL(pre_task_mulout_intr);
+
+/*
+ * FIXME before enabling in 2.4 ... DATA integrity issue upon error.
+ */
 /*
  * Handler for command write multiple
  * Called directly from execute_drive_cmd for the first bunch of sectors,
@@ -929,93 +888,119 @@
  */
 ide_startstop_t task_mulout_intr (ide_drive_t *drive)
 {
-	unsigned int		msect, nsect;
-
-#ifdef ALTSTAT_SCREW_UP
-	byte stat	= altstat_multi_busy(drive, GET_ALTSTAT(), "write");
-#else
-	byte stat		= GET_STAT();
-#endif /* ALTSTAT_SCREW_UP */
-
-	byte io_32bit		= drive->io_32bit;
-	struct request *rq	= HWGROUP(drive)->rq;
-	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
-	char *pBuf		= NULL;
+	ide_hwif_t *hwif		= HWIF(drive);
+	u8 stat				= hwif->INB(IDE_STATUS_REG);
+	struct request *rq		= HWGROUP(drive)->rq;
+	char *pBuf			= NULL;
+	ide_startstop_t startstop	= ide_stopped;
+	unsigned int msect		= drive->mult_count;
+	unsigned int nsect;
+	unsigned long flags;
 
 	/*
 	 * (ks/hs): Handle last IRQ on multi-sector transfer,
-	 * occurs after all data was sent
+	 * occurs after all data was sent in this chunk
 	 */
 	if (rq->current_nr_sectors == 0) {
-		if (stat & (ERR_STAT|DRQ_STAT))
-			return ide_error(drive, "task_mulout_intr", stat);
-		ide_end_request(1, HWGROUP(drive));
-		return ide_stopped;
+		if (stat & (ERR_STAT|DRQ_STAT)) {
+			if (!rq->bh) {
+                                rq->current_nr_sectors += drive->mult_count;
+				/*
+				 * NOTE: could rewind beyond beginning :-/
+				 */
+			} else {
+				printk("%s: MULTI-WRITE assume all data " \
+					"transfered is bad status=0x%02x\n",
+					drive->name, stat);
+			}
+			return DRIVER(drive)->error(drive, "task_mulout_intr", stat);
+		}
+		if (!rq->bh)
+			DRIVER(drive)->end_request(drive, 1);
+		return startstop;
 	}
-
+	/*
+	 * DON'T be lazy code the above and below togather !!!
+	 */
 	if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
 		if (stat & (ERR_STAT|DRQ_STAT)) {
-			return ide_error(drive, "task_mulout_intr", stat);
+			if (!rq->bh) {
+				rq->current_nr_sectors += drive->mult_count;
+				/*
+				 * NOTE: could rewind beyond beginning :-/
+				 */
+			} else {
+				printk("%s: MULTI-WRITE assume all data " \
+					"transfered is bad status=0x%02x\n",
+					drive->name, stat);
+			}
+			return DRIVER(drive)->error(drive, "task_mulout_intr", stat);
 		}
 		/* no data yet, so wait for another interrupt */
-		if (hwgroup->handler == NULL)
-			ide_set_handler(drive, &task_mulout_intr, WAIT_CMD, NULL);
+		if (HWGROUP(drive)->handler == NULL)
+			ide_set_handler(drive, &task_mulout_intr, WAIT_WORSTCASE, NULL);
 		return ide_started;
 	}
 
-	/* (ks/hs): See task_mulin_intr */
-	msect = drive->mult_count;
-
-#ifdef ALTSTAT_SCREW_UP
-	/*
-	 * Screw the request we do not support bad data-phase setups!
-	 * Either read and learn the ATA standard or crash yourself!
-	 */
-	if (!msect) {
-		nsect = 1;
-		while (rq->current_nr_sectors) {
-			pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
-			DTF("Multiwrite: %p, nsect: %d, rq->current_nr_sectors: %ld\n", pBuf, nsect, rq->current_nr_sectors);
-			drive->io_32bit = 0;
-			taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
-			drive->io_32bit = io_32bit;
-			rq->errors = 0;
-			rq->current_nr_sectors -= nsect;
-			stat = altstat_multi_poll(drive, GET_ALTSTAT(), "write");
+#ifndef ALTERNATE_STATE_DIAGRAM_MULTI_OUT
+	if (HWGROUP(drive)->handler != NULL) {
+		unsigned long lflags;
+		spin_lock_irqsave(&io_request_lock, lflags);
+		HWGROUP(drive)->handler = NULL;
+		del_timer(&HWGROUP(drive)->timer);
+		spin_unlock_irqrestore(&io_request_lock, lflags);
+	}
+#endif /* ALTERNATE_STATE_DIAGRAM_MULTI_OUT */
+
+	do {
+		nsect = rq->current_nr_sectors;
+		if (nsect > msect)
+			nsect = msect;
+		pBuf = task_map_rq(rq, &flags);
+		DTF("Multiwrite: %p, nsect: %d, msect: %d, " \
+			"rq->current_nr_sectors: %ld\n",
+			pBuf, nsect, msect, rq->current_nr_sectors);
+		msect -= nsect;
+		taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
+		task_unmap_rq(rq, pBuf, &flags);
+		rq->current_nr_sectors -= nsect;
+		/*
+		 * FIXME :: We really can not legally get a new page/bh
+		 * regardless, if this is the end of our segment.
+		 * BH walking or segment can only be updated after we
+		 * have a good  hwif->INB(IDE_STATUS_REG); return.
+		 */
+		if (!rq->current_nr_sectors) {
+			if (!DRIVER(drive)->end_request(drive, 1))
+				if (!rq->bh)
+					return ide_stopped;
 		}
-		ide_end_request(1, HWGROUP(drive));
-		return ide_stopped;
-	}
-#endif /* ALTSTAT_SCREW_UP */
-
-	nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors;
-	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
-	DTF("Multiwrite: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
-		pBuf, nsect, rq->current_nr_sectors);
-	drive->io_32bit = 0;
-	taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
-	drive->io_32bit = io_32bit;
+	} while (msect);
 	rq->errors = 0;
-	rq->current_nr_sectors -= nsect;
-	if (hwgroup->handler == NULL)
-		ide_set_handler(drive, &task_mulout_intr, WAIT_CMD, NULL);
+	if (HWGROUP(drive)->handler == NULL)
+		ide_set_handler(drive, &task_mulout_intr, WAIT_WORSTCASE, NULL);
 	return ide_started;
 }
 
+EXPORT_SYMBOL(task_mulout_intr);
+
 /* Called by internal to feature out type of command being called */
+//ide_pre_handler_t * ide_pre_handler_parser (task_struct_t *taskfile, hob_struct_t *hobfile)
 ide_pre_handler_t * ide_pre_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile)
 {
 	switch(taskfile->command) {
 				/* IDE_DRIVE_TASK_RAW_WRITE */
 		case CFA_WRITE_MULTI_WO_ERASE:
+	//	case WIN_WRITE_LONG:
+	//	case WIN_WRITE_LONG_ONCE:
 		case WIN_MULTWRITE:
 		case WIN_MULTWRITE_EXT:
-//		case WIN_WRITEDMA:
-//		case WIN_WRITEDMA_QUEUED:
-//		case WIN_WRITEDMA_EXT:
-//		case WIN_WRITEDMA_QUEUED_EXT:
+			return &pre_task_mulout_intr;
+			
 				/* IDE_DRIVE_TASK_OUT */
 		case WIN_WRITE:
+	//	case WIN_WRITE_ONCE:
+		case WIN_WRITE_EXT:
 		case WIN_WRITE_VERIFY:
 		case WIN_WRITE_BUFFER:
 		case CFA_WRITE_SECT_WO_ERASE:
@@ -1025,13 +1010,22 @@
 		case WIN_SMART:
 			if (taskfile->feature == SMART_WRITE_LOG_SECTOR)
 				return &pre_task_out_intr;
+		case WIN_WRITEDMA:
+	//	case WIN_WRITEDMA_ONCE:
+		case WIN_WRITEDMA_QUEUED:
+		case WIN_WRITEDMA_EXT:
+		case WIN_WRITEDMA_QUEUED_EXT:
+				/* IDE_DRIVE_TASK_OUT */
 		default:
 			break;
 	}
 	return(NULL);
 }
 
+EXPORT_SYMBOL(ide_pre_handler_parser);
+
 /* Called by internal to feature out type of command being called */
+//ide_handler_t * ide_handler_parser (task_struct_t *taskfile, hob_struct_t *hobfile)
 ide_handler_t * ide_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile)
 {
 	switch(taskfile->command) {
@@ -1040,6 +1034,7 @@
 		case CFA_TRANSLATE_SECTOR:
 		case WIN_READ_BUFFER:
 		case WIN_READ:
+	//	case WIN_READ_ONCE:
 		case WIN_READ_EXT:
 			return &task_in_intr;
 		case WIN_SECURITY_DISABLE:
@@ -1051,11 +1046,16 @@
 		case WIN_WRITE_BUFFER:
 		case WIN_WRITE_VERIFY:
 		case WIN_WRITE:
+	//	case WIN_WRITE_ONCE:	
 		case WIN_WRITE_EXT:
 			return &task_out_intr;
+	//	case WIN_READ_LONG:
+	//	case WIN_READ_LONG_ONCE:
 		case WIN_MULTREAD:
 		case WIN_MULTREAD_EXT:
 			return &task_mulin_intr;
+	//	case WIN_WRITE_LONG:
+	//	case WIN_WRITE_LONG_ONCE:
 		case CFA_WRITE_MULTI_WO_ERASE:
 		case WIN_MULTWRITE:
 		case WIN_MULTWRITE_EXT:
@@ -1074,13 +1074,16 @@
 		case CFA_REQ_EXT_ERROR_CODE:
 		case CFA_ERASE_SECTORS:
 		case WIN_VERIFY:
+	//	case WIN_VERIFY_ONCE:
 		case WIN_VERIFY_EXT:
 		case WIN_SEEK:
 			return &task_no_data_intr;
 		case WIN_SPECIFY:
 			return &set_geometry_intr;
-		case WIN_RESTORE:
+		case WIN_RECAL:
+	//	case WIN_RESTORE:
 			return &recal_intr;
+		case WIN_NOP:
 		case WIN_DIAGNOSE:
 		case WIN_FLUSH_CACHE:
 		case WIN_FLUSH_CACHE_EXT:
@@ -1111,11 +1114,13 @@
 			return &task_no_data_intr;
 #ifdef CONFIG_BLK_DEV_IDEDMA
 		case WIN_READDMA:
+	//	case WIN_READDMA_ONCE:
 		case WIN_IDENTIFY_DMA:
 		case WIN_READDMA_QUEUED:
 		case WIN_READDMA_EXT:
 		case WIN_READDMA_QUEUED_EXT:
 		case WIN_WRITEDMA:
+	//	case WIN_WRITEDMA_ONCE:
 		case WIN_WRITEDMA_QUEUED:
 		case WIN_WRITEDMA_EXT:
 		case WIN_WRITEDMA_QUEUED_EXT:
@@ -1130,14 +1135,31 @@
 	}	
 }
 
+EXPORT_SYMBOL(ide_handler_parser);
+
+ide_post_handler_t * ide_post_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile)
+{
+	switch(taskfile->command) {
+		case WIN_SPECIFY:	/* set_geometry_intr */
+		case WIN_RESTORE:	/* recal_intr */
+		case WIN_SETMULT:	/* set_multmode_intr */
+		default:
+			return(NULL);
+	}
+}
+
+EXPORT_SYMBOL(ide_post_handler_parser);
+
 /* Called by ioctl to feature out type of command being called */
 int ide_cmd_type_parser (ide_task_t *args)
 {
-	struct hd_drive_task_hdr *taskfile = (struct hd_drive_task_hdr *) args->tfRegister;
-	struct hd_drive_hob_hdr *hobfile = (struct hd_drive_hob_hdr *) args->hobRegister;
 
-	args->prehandler = ide_pre_handler_parser(taskfile, hobfile);
-	args->handler = ide_handler_parser(taskfile, hobfile);
+	task_struct_t *taskfile = (task_struct_t *) args->tfRegister;
+	hob_struct_t *hobfile   = (hob_struct_t *) args->hobRegister;
+
+	args->prehandler	= ide_pre_handler_parser(taskfile, hobfile);
+	args->handler		= ide_handler_parser(taskfile, hobfile);
+	args->posthandler	= ide_post_handler_parser(taskfile, hobfile);
 
 	switch(args->tfRegister[IDE_COMMAND_OFFSET]) {
 		case WIN_IDENTIFY:
@@ -1145,18 +1167,28 @@
 			return IDE_DRIVE_TASK_IN;
 		case CFA_TRANSLATE_SECTOR:
 		case WIN_READ:
+	//	case WIN_READ_ONCE:
+		case WIN_READ_EXT:
 		case WIN_READ_BUFFER:
 			return IDE_DRIVE_TASK_IN;
 		case WIN_WRITE:
+	//	case WIN_WRITE_ONCE:
+		case WIN_WRITE_EXT:
 		case WIN_WRITE_VERIFY:
 		case WIN_WRITE_BUFFER:
 		case CFA_WRITE_SECT_WO_ERASE:
 		case WIN_DOWNLOAD_MICROCODE:
 			return IDE_DRIVE_TASK_RAW_WRITE;
+	//	case WIN_READ_LONG:
+	//	case WIN_READ_LONG_ONCE:
 		case WIN_MULTREAD:
+		case WIN_MULTREAD_EXT:
 			return IDE_DRIVE_TASK_IN;
+	//	case WIN_WRITE_LONG:
+	//	case WIN_WRITE_LONG_ONCE:
 		case CFA_WRITE_MULTI_WO_ERASE:
 		case WIN_MULTWRITE:
+		case WIN_MULTWRITE_EXT:
 			return IDE_DRIVE_TASK_RAW_WRITE;
 		case WIN_SECURITY_DISABLE:
 		case WIN_SECURITY_ERASE_UNIT:
@@ -1178,12 +1210,14 @@
 			}
 #ifdef CONFIG_BLK_DEV_IDEDMA
 		case WIN_READDMA:
+	//	case WIN_READDMA_ONCE:
 		case WIN_IDENTIFY_DMA:
 		case WIN_READDMA_QUEUED:
 		case WIN_READDMA_EXT:
 		case WIN_READDMA_QUEUED_EXT:
 			return IDE_DRIVE_TASK_IN;
 		case WIN_WRITEDMA:
+	//	case WIN_WRITEDMA_ONCE:
 		case WIN_WRITEDMA_QUEUED:
 		case WIN_WRITEDMA_EXT:
 		case WIN_WRITEDMA_QUEUED_EXT:
@@ -1191,20 +1225,32 @@
 #endif
 		case WIN_SETFEATURES:
 			switch(args->tfRegister[IDE_FEATURE_OFFSET]) {
+				case SETFEATURES_EN_8BIT:
+				case SETFEATURES_EN_WCACHE:
+					return IDE_DRIVE_TASK_NO_DATA;
 				case SETFEATURES_XFER:
 					return IDE_DRIVE_TASK_SET_XFER;
 				case SETFEATURES_DIS_DEFECT:
 				case SETFEATURES_EN_APM:
 				case SETFEATURES_DIS_MSN:
+				case SETFEATURES_DIS_RETRY:
+				case SETFEATURES_EN_AAM:
+				case SETFEATURES_RW_LONG:
+				case SETFEATURES_SET_CACHE:
+				case SETFEATURES_DIS_RLA:
 				case SETFEATURES_EN_RI:
 				case SETFEATURES_EN_SI:
 				case SETFEATURES_DIS_RPOD:
 				case SETFEATURES_DIS_WCACHE:
 				case SETFEATURES_EN_DEFECT:
 				case SETFEATURES_DIS_APM:
+				case SETFEATURES_EN_ECC:
 				case SETFEATURES_EN_MSN:
+				case SETFEATURES_EN_RETRY:
 				case SETFEATURES_EN_RLA:
 				case SETFEATURES_PREFETCH:
+				case SETFEATURES_4B_RW_LONG:
+				case SETFEATURES_DIS_AAM:
 				case SETFEATURES_EN_RPOD:
 				case SETFEATURES_DIS_RI:
 				case SETFEATURES_DIS_SI:
@@ -1215,6 +1261,7 @@
 		case CFA_REQ_EXT_ERROR_CODE:
 		case CFA_ERASE_SECTORS:
 		case WIN_VERIFY:
+	//	case WIN_VERIFY_ONCE:
 		case WIN_VERIFY_EXT:
 		case WIN_SEEK:
 		case WIN_SPECIFY:
@@ -1253,6 +1300,8 @@
 	}
 }
 
+EXPORT_SYMBOL(ide_cmd_type_parser);
+
 /*
  * This function is intended to be used prior to invoking ide_do_drive_cmd().
  */
@@ -1262,127 +1311,158 @@
 	rq->cmd = IDE_DRIVE_TASK_NO_DATA;
 }
 
-/*
- * This is kept for internal use only !!!
- * This is an internal call and nobody in user-space has a damn
- * reason to call this taskfile.
- *
- * ide_raw_taskfile is the one that user-space executes.
- */
-int ide_wait_taskfile (ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, byte *buf)
-{
-	struct request rq;
-	ide_task_t args;
+EXPORT_SYMBOL(ide_init_drive_taskfile);
 
-	memset(&args, 0, sizeof(ide_task_t));
+#if 1
 
-	args.tfRegister[IDE_DATA_OFFSET]         = taskfile->data;
-	args.tfRegister[IDE_FEATURE_OFFSET]      = taskfile->feature;
-	args.tfRegister[IDE_NSECTOR_OFFSET]      = taskfile->sector_count;
-	args.tfRegister[IDE_SECTOR_OFFSET]       = taskfile->sector_number;
-	args.tfRegister[IDE_LCYL_OFFSET]         = taskfile->low_cylinder;
-	args.tfRegister[IDE_HCYL_OFFSET]         = taskfile->high_cylinder;
-	args.tfRegister[IDE_SELECT_OFFSET]       = taskfile->device_head;
-	args.tfRegister[IDE_COMMAND_OFFSET]      = taskfile->command;
-
-	args.hobRegister[IDE_DATA_OFFSET_HOB]    = hobfile->data;
-	args.hobRegister[IDE_FEATURE_OFFSET_HOB] = hobfile->feature;
-	args.hobRegister[IDE_NSECTOR_OFFSET_HOB] = hobfile->sector_count;
-	args.hobRegister[IDE_SECTOR_OFFSET_HOB]  = hobfile->sector_number;
-	args.hobRegister[IDE_LCYL_OFFSET_HOB]    = hobfile->low_cylinder;
-	args.hobRegister[IDE_HCYL_OFFSET_HOB]    = hobfile->high_cylinder;
-	args.hobRegister[IDE_SELECT_OFFSET_HOB]  = hobfile->device_head;
-	args.hobRegister[IDE_CONTROL_OFFSET_HOB] = hobfile->control;
+int ide_diag_taskfile (ide_drive_t *drive, ide_task_t *args, unsigned long data_size, u8 *buf)
+{
+	struct request rq;
 
 	ide_init_drive_taskfile(&rq);
-	/* This is kept for internal use only !!! */
-	args.command_type = ide_cmd_type_parser (&args);
-	if (args.command_type != IDE_DRIVE_TASK_NO_DATA)
-		rq.current_nr_sectors = rq.nr_sectors = (hobfile->sector_count << 8) | taskfile->sector_count;
-
 	rq.cmd = IDE_DRIVE_TASKFILE;
 	rq.buffer = buf;
-	rq.special = &args;
+
+	/*
+	 * (ks) We transfer currently only whole sectors.
+	 * This is suffient for now.  But, it would be great,
+	 * if we would find a solution to transfer any size.
+	 * To support special commands like READ LONG.
+	 */
+	if (args->command_type != IDE_DRIVE_TASK_NO_DATA) {
+		if (data_size == 0)
+			rq.current_nr_sectors = rq.nr_sectors = (args->hobRegister[IDE_NSECTOR_OFFSET_HOB] << 8) | args->tfRegister[IDE_NSECTOR_OFFSET];
+		/*	rq.hard_cur_sectors	*/
+		else
+			rq.current_nr_sectors = rq.nr_sectors = data_size / SECTOR_SIZE;
+		/*	rq.hard_cur_sectors	*/
+	}
+
+	if (args->tf_out_flags.all == 0) {
+		/*
+		 * clean up kernel settings for driver sanity, regardless.
+		 * except for discrete diag services.
+		 */
+		args->posthandler = ide_post_handler_parser(
+				(struct hd_drive_task_hdr *) args->tfRegister,
+				(struct hd_drive_hob_hdr *) args->hobRegister);
+
+	}
+	rq.special = args;
 	return ide_do_drive_cmd(drive, &rq, ide_wait);
 }
 
-int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *args, byte *buf)
+#else
+
+int ide_diag_taskfile (ide_drive_t *drive, ide_task_t *args, unsigned long data_size, u8 *buf)
 {
-	struct request rq;
-	ide_init_drive_taskfile(&rq);
-	rq.cmd = IDE_DRIVE_TASKFILE;
-	rq.buffer = buf;
+	struct request *rq;
+	unsigned long flags;
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+	unsigned int major = HWIF(drive)->major;
+	struct list_head *queue_head = &drive->queue.queue_head;
+	DECLARE_COMPLETION(wait);
 
-	if (args->command_type != IDE_DRIVE_TASK_NO_DATA)
-		rq.current_nr_sectors = rq.nr_sectors = (args->hobRegister[IDE_NSECTOR_OFFSET_HOB] << 8) | args->tfRegister[IDE_NSECTOR_OFFSET];
+	if (HWIF(drive)->chipset == ide_pdc4030 && buf != NULL)
+		return -ENOSYS; /* special drive cmds not supported */
 
-	rq.special = args;
-	return ide_do_drive_cmd(drive, &rq, ide_wait);
+	memset(rq, 0, sizeof(*rq));
+	rq->cmd = IDE_DRIVE_TASKFILE;
+	rq->buffer = buf;
+
+	/*
+	 * (ks) We transfer currently only whole sectors.
+	 * This is suffient for now.  But, it would be great,
+	 * if we would find a solution to transfer any size.
+	 * To support special commands like READ LONG.
+	 */
+	if (args->command_type != IDE_DRIVE_TASK_NO_DATA) {
+		if (data_size == 0) {
+			ata_nsector_t nsector;
+			nsector.b.low = args->hobRegister[IDE_NSECTOR_OFFSET_HOB];
+			nsector.b.high = args->tfRegister[IDE_NSECTOR_OFFSET];
+			rq.nr_sectors = nsector.all;
+		} else {
+			rq.nr_sectors = data_size / SECTOR_SIZE;
+		}
+		rq.current_nr_sectors = rq.nr_sectors;
+	//	rq.hard_cur_sectors = rq.nr_sectors;
+	}
+
+	if (args->tf_out_flags.all == 0) {
+		/*
+		 * clean up kernel settings for driver sanity, regardless.
+		 * except for discrete diag services.
+		 */
+		args->posthandler = ide_post_handler_parser(
+				(struct hd_drive_task_hdr *) args->tfRegister,
+				(struct hd_drive_hob_hdr *) args->hobRegister);
+	}
+	rq->special = args;
+	rq->errors = 0;
+	rq->rq_status = RQ_ACTIVE;
+	rq->rq_dev = MKDEV(major,(drive->select.b.unit)<<PARTN_BITS);
+	rq->waiting = &wait;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	queue_head = queue_head->prev;
+	list_add(&rq->queue, queue_head);
+	ide_do_request(hwgroup, 0);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+
+	wait_for_completion(&wait);	/* wait for it to be serviced */
+	return rq->errors ? -EIO : 0;	/* return -EIO if errors */
 }
 
+#endif
+
+EXPORT_SYMBOL(ide_diag_taskfile);
 
+int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *args, u8 *buf)
+{
+	return ide_diag_taskfile(drive, args, 0, buf);
+}
+
+EXPORT_SYMBOL(ide_raw_taskfile);
+	
 #ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
 char * ide_ioctl_verbose (unsigned int cmd)
 {
 	return("unknown");
 }
 
-char * ide_task_cmd_verbose (byte task)
+char * ide_task_cmd_verbose (u8 task)
 {
 	return("unknown");
 }
 #endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
 
-/*
- *  The taskfile glue table
- *
- *  reqtask.data_phase	reqtask.req_cmd
- *  			args.command_type		args.handler
- *
- *  TASKFILE_P_OUT_DMAQ	??				??
- *  TASKFILE_P_IN_DMAQ	??				??
- *  TASKFILE_P_OUT_DMA	??				??
- *  TASKFILE_P_IN_DMA	??				??
- *  TASKFILE_P_OUT	??				??
- *  TASKFILE_P_IN	??				??
- *
- *  TASKFILE_OUT_DMAQ	IDE_DRIVE_TASK_RAW_WRITE	NULL
- *  TASKFILE_IN_DMAQ	IDE_DRIVE_TASK_IN		NULL
- *
- *  TASKFILE_OUT_DMA	IDE_DRIVE_TASK_RAW_WRITE	NULL
- *  TASKFILE_IN_DMA	IDE_DRIVE_TASK_IN		NULL
- *
- *  TASKFILE_IN_OUT	??				??
- *
- *  TASKFILE_MULTI_OUT	IDE_DRIVE_TASK_RAW_WRITE	task_mulout_intr
- *  TASKFILE_MULTI_IN	IDE_DRIVE_TASK_IN		task_mulin_intr
- *
- *  TASKFILE_OUT	IDE_DRIVE_TASK_RAW_WRITE	task_out_intr
- *  TASKFILE_OUT	IDE_DRIVE_TASK_OUT		task_out_intr
- *
- *  TASKFILE_IN		IDE_DRIVE_TASK_IN		task_in_intr
- *  TASKFILE_NO_DATA	IDE_DRIVE_TASK_NO_DATA		task_no_data_intr
- *
- *  			IDE_DRIVE_TASK_SET_XFER		task_no_data_intr
- *  			IDE_DRIVE_TASK_INVALID
- *
- */
-
 #define MAX_DMA		(256*SECTOR_WORDS)
 
+ide_startstop_t flagged_taskfile(ide_drive_t *, ide_task_t *);
+ide_startstop_t flagged_task_no_data_intr(ide_drive_t *);
+ide_startstop_t flagged_task_in_intr(ide_drive_t *);
+ide_startstop_t flagged_task_mulin_intr(ide_drive_t *);
+ide_startstop_t flagged_pre_task_out_intr(ide_drive_t *, struct request *);
+ide_startstop_t flagged_task_out_intr(ide_drive_t *);
+ide_startstop_t flagged_pre_task_mulout_intr(ide_drive_t *, struct request *);
+ide_startstop_t flagged_task_mulout_intr(ide_drive_t *);
+
 int ide_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
 	ide_task_request_t	*req_task;
 	ide_task_t		args;
-
-	byte *outbuf		= NULL;
-	byte *inbuf		= NULL;
+	u8 *outbuf		= NULL;
+	u8 *inbuf		= NULL;
 	task_ioreg_t *argsptr	= args.tfRegister;
 	task_ioreg_t *hobsptr	= args.hobRegister;
 	int err			= 0;
 	int tasksize		= sizeof(struct ide_task_request_s);
 	int taskin		= 0;
 	int taskout		= 0;
+	u8 io_32bit		= drive->io_32bit;
+
+//	printk("IDE Taskfile ...\n");
 
 	req_task = kmalloc(tasksize, GFP_KERNEL);
 	if (req_task == NULL) return -ENOMEM;
@@ -1423,8 +1503,7 @@
 		}
 	}
 
-	memset(argsptr, 0, HDIO_DRIVE_TASK_HDR_SIZE);
-	memset(hobsptr, 0, HDIO_DRIVE_HOB_HDR_SIZE);
+	memset(&args, 0, sizeof(ide_task_t));
 	memcpy(argsptr, req_task->io_ports, HDIO_DRIVE_TASK_HDR_SIZE);
 	memcpy(hobsptr, req_task->hob_ports, HDIO_DRIVE_HOB_HDR_SIZE);
 
@@ -1440,64 +1519,61 @@
 		ide_task_cmd_verbose(args.tfRegister[IDE_COMMAND_OFFSET]));
 #endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
 
+	drive->io_32bit = 0;
 	switch(req_task->data_phase) {
 		case TASKFILE_OUT_DMAQ:
 		case TASKFILE_OUT_DMA:
-			args.prehandler = NULL;
-			args.handler = NULL;
-			args.posthandler = NULL;
-			err = ide_raw_taskfile(drive, &args, outbuf);
+			err = ide_diag_taskfile(drive, &args, taskout, outbuf);
 			break;
 		case TASKFILE_IN_DMAQ:
 		case TASKFILE_IN_DMA:
-			args.prehandler = NULL;
-			args.handler = NULL;
-			args.posthandler = NULL;
-			err = ide_raw_taskfile(drive, &args, inbuf);
+			err = ide_diag_taskfile(drive, &args, taskin, inbuf);
 			break;
 		case TASKFILE_IN_OUT:
 #if 0
 			args.prehandler = &pre_task_out_intr;
 			args.handler = &task_out_intr;
 			args.posthandler = NULL;
-			err = ide_raw_taskfile(drive, &args, outbuf);
+			err = ide_diag_taskfile(drive, &args, taskout, outbuf);
 			args.prehandler = NULL;
 			args.handler = &task_in_intr;
 			args.posthandler = NULL;
-			err = ide_raw_taskfile(drive, &args, inbuf);
+			err = ide_diag_taskfile(drive, &args, taskin, inbuf);
 			break;
 #else
 			err = -EFAULT;
 			goto abort;
 #endif
 		case TASKFILE_MULTI_OUT:
-			if (drive->mult_count) {
-				args.prehandler = &pre_task_out_intr;
-				args.handler = &task_mulout_intr;
-				args.posthandler = NULL;
-				err = ide_raw_taskfile(drive, &args, outbuf);
-			} else {
+			if (!drive->mult_count) {
 				/* (hs): give up if multcount is not set */
 				printk("%s: %s Multimode Write " \
 					"multcount is not set\n",
-					 drive->name, __FUNCTION__);
+					drive->name, __FUNCTION__);
 				err = -EPERM;
 				goto abort;
 			}
+			if (args.tf_out_flags.all != 0) {
+				args.prehandler = &flagged_pre_task_mulout_intr;
+				args.handler = &flagged_task_mulout_intr;
+			} else {
+				args.prehandler = &pre_task_mulout_intr;
+				args.handler = &task_mulout_intr;
+			}
+			err = ide_diag_taskfile(drive, &args, taskout, outbuf);
 			break;
 		case TASKFILE_OUT:
-			args.prehandler = &pre_task_out_intr;
-			args.handler = &task_out_intr;
-			args.posthandler = NULL;
-			err = ide_raw_taskfile(drive, &args, outbuf);
+			if (args.tf_out_flags.all != 0) {
+				args.prehandler = &flagged_pre_task_out_intr;
+				args.handler    = &flagged_task_out_intr;
+			} else {
+				args.prehandler = &pre_task_out_intr;
+				args.handler = &task_out_intr;
+			}
+			err = ide_diag_taskfile(drive, &args, taskout, outbuf);
 			break;
 		case TASKFILE_MULTI_IN:
-			if (drive->mult_count) {
-				args.prehandler = NULL;
-				args.handler = &task_mulin_intr;
-				args.posthandler = NULL;
-				err = ide_raw_taskfile(drive, &args, inbuf);
-			} else {
+			if (!drive->mult_count) {
 				/* (hs): give up if multcount is not set */
 				printk("%s: %s Multimode Read failure " \
 					"multcount is not set\n",
@@ -1505,23 +1581,30 @@
 				err = -EPERM;
 				goto abort;
 			}
+			if (args.tf_out_flags.all != 0) {
+				args.handler = &flagged_task_mulin_intr;
+			} else {
+				args.handler = &task_mulin_intr;
+			}
+			err = ide_diag_taskfile(drive, &args, taskin, inbuf);
 			break;
 		case TASKFILE_IN:
-			args.prehandler = NULL;
-			args.handler = &task_in_intr;
-			args.posthandler = NULL;
-			err = ide_raw_taskfile(drive, &args, inbuf);
+			if (args.tf_out_flags.all != 0) {
+				args.handler = &flagged_task_in_intr;
+			} else {
+				args.handler = &task_in_intr;
+			}
+			err = ide_diag_taskfile(drive, &args, taskin, inbuf);
 			break;
 		case TASKFILE_NO_DATA:
-			args.prehandler = NULL;
-			args.handler = &task_no_data_intr;
-			args.posthandler = NULL;
-			err = ide_raw_taskfile(drive, &args, NULL);
+			if (args.tf_out_flags.all != 0) {
+				args.handler = &flagged_task_no_data_intr;
+			} else {
+				args.handler = &task_no_data_intr;
+			}
+			err = ide_diag_taskfile(drive, &args, 0, NULL);
 			break;
 		default:
-			args.prehandler = NULL;
-			args.handler = NULL;
-			args.posthandler = NULL;
 			err = -EFAULT;
 			goto abort;
 	}
@@ -1555,153 +1638,594 @@
 		kfree(outbuf);
 	if (inbuf != NULL)
 		kfree(inbuf);
+
+//	printk("IDE Taskfile ioctl ended. rc = %i\n", err);
+
+	drive->io_32bit = io_32bit;
+
 	return err;
 }
 
-EXPORT_SYMBOL(task_read_24);
-EXPORT_SYMBOL(do_rw_taskfile);
-EXPORT_SYMBOL(do_taskfile);
-// EXPORT_SYMBOL(flagged_taskfile);
+EXPORT_SYMBOL(ide_taskfile_ioctl);
 
-//EXPORT_SYMBOL(ide_end_taskfile);
+int ide_wait_cmd (ide_drive_t *drive, u8 cmd, u8 nsect, u8 feature, u8 sectors, u8 *buf)
+{
+	struct request rq;
+	u8 buffer[4];
 
-EXPORT_SYMBOL(set_multmode_intr);
-EXPORT_SYMBOL(set_geometry_intr);
-EXPORT_SYMBOL(recal_intr);
+	if (!buf)
+		buf = buffer;
+	memset(buf, 0, 4 + SECTOR_WORDS * 4 * sectors);
+	ide_init_drive_cmd(&rq);
+	rq.buffer = buf;
+	*buf++ = cmd;
+	*buf++ = nsect;
+	*buf++ = feature;
+	*buf++ = sectors;
+	return ide_do_drive_cmd(drive, &rq, ide_wait);
+}
 
-EXPORT_SYMBOL(task_no_data_intr);
-EXPORT_SYMBOL(task_in_intr);
-EXPORT_SYMBOL(task_mulin_intr);
-EXPORT_SYMBOL(pre_task_out_intr);
-EXPORT_SYMBOL(task_out_intr);
-EXPORT_SYMBOL(task_mulout_intr);
+EXPORT_SYMBOL(ide_wait_cmd);
 
-EXPORT_SYMBOL(ide_init_drive_taskfile);
-EXPORT_SYMBOL(ide_wait_taskfile);
-EXPORT_SYMBOL(ide_raw_taskfile);
-EXPORT_SYMBOL(ide_pre_handler_parser);
-EXPORT_SYMBOL(ide_handler_parser);
-EXPORT_SYMBOL(ide_cmd_type_parser);
-EXPORT_SYMBOL(ide_taskfile_ioctl);
+/*
+ * FIXME : this needs to map into at taskfile. <andre@linux-ide.org>
+ */
+int ide_cmd_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+#if 1
+	int err = 0;
+	u8 args[4], *argbuf = args;
+	u8 xfer_rate = 0;
+	int argsize = 4;
+	ide_task_t tfargs;
 
-#ifdef CONFIG_PKT_TASK_IOCTL
+	if (NULL == (void *) arg) {
+		struct request rq;
+		ide_init_drive_cmd(&rq);
+		return ide_do_drive_cmd(drive, &rq, ide_wait);
+	}
 
-#if 0
+	if (copy_from_user(args, (void *)arg, 4))
+		return -EFAULT;
+
+	memset(&tfargs, 0, sizeof(ide_task_t));
+	tfargs.tfRegister[IDE_FEATURE_OFFSET] = args[2];
+	tfargs.tfRegister[IDE_NSECTOR_OFFSET] = args[3];
+	tfargs.tfRegister[IDE_SECTOR_OFFSET]  = args[1];
+	tfargs.tfRegister[IDE_LCYL_OFFSET]    = 0x00;
+	tfargs.tfRegister[IDE_HCYL_OFFSET]    = 0x00;
+	tfargs.tfRegister[IDE_SELECT_OFFSET]  = 0x00;
+	tfargs.tfRegister[IDE_COMMAND_OFFSET] = args[0];
+
+	if (args[3]) {
+		argsize = 4 + (SECTOR_WORDS * 4 * args[3]);
+		argbuf = kmalloc(argsize, GFP_KERNEL);
+		if (argbuf == NULL)
+			return -ENOMEM;
+		memcpy(argbuf, args, 4);
+	}
+	if (set_transfer(drive, &tfargs)) {
+		xfer_rate = args[1];
+		if (ide_ata66_check(drive, &tfargs))
+			goto abort;
+	}
+
+	err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf);
+
+	if (!err && xfer_rate) {
+		/* active-retuning-calls future */
+		ide_set_xfer_rate(drive, xfer_rate);
+		ide_driveid_update(drive);
+	}
+abort:
+	if (copy_to_user((void *)arg, argbuf, argsize))
+		err = -EFAULT;
+	if (argsize > 4)
+		kfree(argbuf);
+	return err;
+
+#else
+
+	int err = 0;
+	u8 args[4], *argbuf = args;
+	u8 xfer_rate = 0;
+	int argsize = 0;
+	ide_task_t tfargs;
+
+	if (NULL == (void *) arg) {
+		struct request rq;
+		ide_init_drive_cmd(&rq);
+		return ide_do_drive_cmd(drive, &rq, ide_wait);
+	}
+
+	if (copy_from_user(args, (void *)arg, 4))
+		return -EFAULT;
+
+	memset(&tfargs, 0, sizeof(ide_task_t));
+	tfargs.tfRegister[IDE_FEATURE_OFFSET] = args[2];
+	tfargs.tfRegister[IDE_NSECTOR_OFFSET] = args[3];
+	tfargs.tfRegister[IDE_SECTOR_OFFSET]  = args[1];
+	tfargs.tfRegister[IDE_LCYL_OFFSET]    = 0x00;
+	tfargs.tfRegister[IDE_HCYL_OFFSET]    = 0x00;
+	tfargs.tfRegister[IDE_SELECT_OFFSET]  = 0x00;
+	tfargs.tfRegister[IDE_COMMAND_OFFSET] = args[0];
+
+	if (args[3]) {
+		argsize = (SECTOR_WORDS * 4 * args[3]);
+		argbuf = kmalloc(argsize, GFP_KERNEL);
+		if (argbuf == NULL)
+			return -ENOMEM;
+	}
+
+	if (set_transfer(drive, &tfargs)) {
+		xfer_rate = args[1];
+		if (ide_ata66_check(drive, &tfargs))
+			goto abort;
+	}
+
+	tfargs.command_type = ide_cmd_type_parser(&tfargs);
+	err = ide_raw_taskfile(drive, &tfargs, argbuf);
+
+	if (!err && xfer_rate) {
+		/* active-retuning-calls future */
+		ide_set_xfer_rate(drive, xfer_rate);
+		ide_driveid_update(drive);
+	}
+abort:
+	args[0] = tfargs.tfRegister[IDE_COMMAND_OFFSET];
+	args[1] = tfargs.tfRegister[IDE_FEATURE_OFFSET];
+	args[2] = tfargs.tfRegister[IDE_NSECTOR_OFFSET];
+	args[3] = 0;
+
+	if (copy_to_user((void *)arg, argbuf, 4))
+		err = -EFAULT;
+	if (argbuf != NULL) {
+		if (copy_to_user((void *)arg, argbuf + 4, argsize))
+			err = -EFAULT;
+		kfree(argbuf);
+	}
+	return err;
+
+#endif
+}
+
+EXPORT_SYMBOL(ide_cmd_ioctl);
+
+int ide_wait_cmd_task (ide_drive_t *drive, u8 *buf)
 {
+	struct request rq;
 
-{ /* start cdrom */
+	ide_init_drive_cmd(&rq);
+	rq.cmd = IDE_DRIVE_TASK;
+	rq.buffer = buf;
+	return ide_do_drive_cmd(drive, &rq, ide_wait);
+}
 
-	struct cdrom_info *info = drive->driver_data;
+EXPORT_SYMBOL(ide_wait_cmd_task);
 
-	if (info->dma) {
-		if (info->cmd == READ) {
-			info->dma = !HWIF(drive)->dmaproc(ide_dma_read, drive);
-		} else if (info->cmd == WRITE) {
-			info->dma = !HWIF(drive)->dmaproc(ide_dma_write, drive);
-		} else {
-			printk("ide-cd: DMA set, but not allowed\n");
+/*
+ * FIXME : this needs to map into at taskfile. <andre@linux-ide.org>
+ */
+int ide_task_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	int err = 0;
+	u8 args[7], *argbuf = args;
+	int argsize = 7;
+
+	if (copy_from_user(args, (void *)arg, 7))
+		return -EFAULT;
+	err = ide_wait_cmd_task(drive, argbuf);
+	if (copy_to_user((void *)arg, argbuf, argsize))
+		err = -EFAULT;
+	return err;
+}
+
+EXPORT_SYMBOL(ide_task_ioctl);
+
+/*
+ * NOTICE: This is additions from IBM to provide a discrete interface,
+ * for selective taskregister access operations.  Nice JOB Klaus!!!
+ * Glad to be able to work and co-develop this with you and IBM.
+ */
+ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	task_struct_t *taskfile	= (task_struct_t *) task->tfRegister;
+	hob_struct_t *hobfile	= (hob_struct_t *) task->hobRegister;
+#if DEBUG_TASKFILE
+	u8 status;
+#endif
+
+
+#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
+	void debug_taskfile(drive, task);
+#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
+
+	/*
+	 * (ks) Check taskfile in/out flags.
+	 * If set, then execute as it is defined.
+	 * If not set, then define default settings.
+	 * The default values are:
+	 *	write and read all taskfile registers (except data) 
+	 *	write and read the hob registers (sector,nsector,lcyl,hcyl)
+	 */
+	if (task->tf_out_flags.all == 0) {
+		task->tf_out_flags.all = IDE_TASKFILE_STD_OUT_FLAGS;
+		if (drive->addressing == 1)
+			task->tf_out_flags.all |= (IDE_HOB_STD_OUT_FLAGS << 8);
+        }
+
+	if (task->tf_in_flags.all == 0) {
+		task->tf_in_flags.all = IDE_TASKFILE_STD_IN_FLAGS;
+		if (drive->addressing == 1)
+			task->tf_in_flags.all |= (IDE_HOB_STD_IN_FLAGS  << 8);
+        }
+
+	/* ALL Command Block Executions SHALL clear nIEN, unless otherwise */
+	if (IDE_CONTROL_REG)
+		/* clear nIEN */
+		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
+	SELECT_MASK(drive, 0);
+
+#if DEBUG_TASKFILE
+	status = hwif->INB(IDE_STATUS_REG);
+	if (status & 0x80) {
+		printk("flagged_taskfile -> Bad status. Status = %02x. wait 100 usec ...\n", status);
+		udelay(100);
+		status = hwif->INB(IDE_STATUS_REG);
+		printk("flagged_taskfile -> Status = %02x\n", status);
+	}
+#endif
+
+	if (task->tf_out_flags.b.data) {
+		u16 data =  taskfile->data + (hobfile->data << 8);
+		hwif->OUTW(data, IDE_DATA_REG);
+	}
+
+	/* (ks) send hob registers first */
+	if (task->tf_out_flags.b.nsector_hob)
+		hwif->OUTB(hobfile->sector_count, IDE_NSECTOR_REG);
+	if (task->tf_out_flags.b.sector_hob)
+		hwif->OUTB(hobfile->sector_number, IDE_SECTOR_REG);
+	if (task->tf_out_flags.b.lcyl_hob)
+		hwif->OUTB(hobfile->low_cylinder, IDE_LCYL_REG);
+	if (task->tf_out_flags.b.hcyl_hob)
+		hwif->OUTB(hobfile->high_cylinder, IDE_HCYL_REG);
+
+	/* (ks) Send now the standard registers */
+	if (task->tf_out_flags.b.error_feature)
+		hwif->OUTB(taskfile->feature, IDE_FEATURE_REG);
+	/* refers to number of sectors to transfer */
+	if (task->tf_out_flags.b.nsector)
+		hwif->OUTB(taskfile->sector_count, IDE_NSECTOR_REG);
+	/* refers to sector offset or start sector */
+	if (task->tf_out_flags.b.sector)
+		hwif->OUTB(taskfile->sector_number, IDE_SECTOR_REG);
+	if (task->tf_out_flags.b.lcyl)
+		hwif->OUTB(taskfile->low_cylinder, IDE_LCYL_REG);
+	if (task->tf_out_flags.b.hcyl)
+		hwif->OUTB(taskfile->high_cylinder, IDE_HCYL_REG);
+
+        /*
+	 * (ks) In the flagged taskfile approch, we will used all specified
+	 * registers and the register value will not be changed. Except the
+	 * select bit (master/slave) in the drive_head register. We must make
+	 * sure that the desired drive is selected.
+	 */
+	hwif->OUTB(taskfile->device_head | drive->select.all, IDE_SELECT_REG);
+	switch(task->data_phase) {
+
+   	        case TASKFILE_OUT_DMAQ:
+		case TASKFILE_OUT_DMA:
+			hwif->ide_dma_write(drive);
+			break;
+
+		case TASKFILE_IN_DMAQ:
+		case TASKFILE_IN_DMA:
+			hwif->ide_dma_read(drive);
+			break;
+
+	        default:
+ 			if (task->handler == NULL)
+				return ide_stopped;
+
+			ide_set_handler(drive, task->handler, WAIT_WORSTCASE, NULL);
+			/* Issue the command */
+			hwif->OUTB(taskfile->command, IDE_COMMAND_REG);
+			if (task->prehandler != NULL)
+				return task->prehandler(drive, HWGROUP(drive)->rq);
+	}
+
+	return ide_started;
+}
+
+EXPORT_SYMBOL(flagged_taskfile);
+
+ide_startstop_t flagged_task_no_data_intr (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	u8 stat;
+
+	local_irq_enable();
+
+	if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG), READY_STAT, BAD_STAT)) {
+		if (stat & ERR_STAT) {
+			return DRIVER(drive)->error(drive, "flagged_task_no_data_intr", stat);
 		}
+		/*
+		 * (ks) Unexpected ATA data phase detected.
+		 * This should not happen. But, it can !
+		 * I am not sure, which function is best to clean up
+		 * this situation.  I choose: ide_error(...)
+		 */
+ 		return DRIVER(drive)->error(drive, "flagged_task_no_data_intr (unexpected phase)", stat); 
 	}
 
-	/* Set up the controller registers. */
-	OUT_BYTE (info->dma, IDE_FEATURE_REG);
-	OUT_BYTE (0, IDE_NSECTOR_REG);
-	OUT_BYTE (0, IDE_SECTOR_REG);
+	ide_end_drive_cmd(drive, stat, hwif->INB(IDE_ERROR_REG));
 
-	OUT_BYTE (xferlen & 0xff, IDE_LCYL_REG);
-	OUT_BYTE (xferlen >> 8  , IDE_HCYL_REG);
-	if (IDE_CONTROL_REG)
-		OUT_BYTE (drive->ctl, IDE_CONTROL_REG);
+	return ide_stopped;
+}
+
+/*
+ * Handler for command with PIO data-in phase
+ */
+ide_startstop_t flagged_task_in_intr (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 stat			= hwif->INB(IDE_STATUS_REG);
+	struct request *rq	= HWGROUP(drive)->rq;
+	char *pBuf		= NULL;
+	int retries             = 5;
+
+	if (rq->current_nr_sectors == 0) 
+		return DRIVER(drive)->error(drive, "flagged_task_in_intr (no data requested)", stat); 
+
+	if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) {
+		if (stat & ERR_STAT) {
+			return DRIVER(drive)->error(drive, "flagged_task_in_intr", stat);
+		}
+		/*
+		 * (ks) Unexpected ATA data phase detected.
+		 * This should not happen. But, it can !
+		 * I am not sure, which function is best to clean up
+		 * this situation.  I choose: ide_error(...)
+		 */
+		return DRIVER(drive)->error(drive, "flagged_task_in_intr (unexpected data phase)", stat); 
+	}
+
+	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+	DTF("Read - rq->current_nr_sectors: %d, status: %02x\n", (int) rq->current_nr_sectors, stat);
 
-	if (info->dma)
-		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+	taskfile_input_data(drive, pBuf, SECTOR_WORDS);
 
-	if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
-		ide_set_handler (drive, handler, WAIT_CMD, cdrom_timer_expiry);
-		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
+	if (--rq->current_nr_sectors != 0) {
+		/*
+                 * (ks) We don't know which command was executed. 
+		 * So, we wait the 'WORSTCASE' value.
+                 */
+		ide_set_handler(drive, &flagged_task_in_intr,  WAIT_WORSTCASE, NULL);
 		return ide_started;
-	} else {
-		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
-		return (*handler) (drive);
 	}
+	/*
+	 * (ks) Last sector was transfered, wait until drive is ready. 
+	 * This can take up to 10 usec. We willl wait max 50 us.
+	 */
+	while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--)
+		udelay(10);
+	ide_end_drive_cmd (drive, stat, hwif->INB(IDE_ERROR_REG));
 
-} /* end cdrom */
+	return ide_stopped;
+}
 
-{ /* start floppy */
+ide_startstop_t flagged_task_mulin_intr (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 stat			= hwif->INB(IDE_STATUS_REG);
+	struct request *rq	= HWGROUP(drive)->rq;
+	char *pBuf		= NULL;
+	int retries             = 5;
+	unsigned int msect, nsect;
 
-	idefloppy_floppy_t *floppy = drive->driver_data;
-	idefloppy_bcount_reg_t bcount;
-	int dma_ok = 0;
+	if (rq->current_nr_sectors == 0) 
+		return DRIVER(drive)->error(drive, "flagged_task_mulin_intr (no data requested)", stat); 
 
-	floppy->pc=pc;		/* Set the current packet command */
+	msect = drive->mult_count;
+	if (msect == 0) 
+		return DRIVER(drive)->error(drive, "flagged_task_mulin_intr (multimode not set)", stat); 
 
-	pc->retries++;
-	pc->actually_transferred=0; /* We haven't transferred any data yet */
-	pc->current_position=pc->buffer;
-	bcount.all = IDE_MIN(pc->request_transfer, 63 * 1024);
+	if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) {
+		if (stat & ERR_STAT) {
+			return DRIVER(drive)->error(drive, "flagged_task_mulin_intr", stat);
+		}
+		/*
+		 * (ks) Unexpected ATA data phase detected.
+		 * This should not happen. But, it can !
+		 * I am not sure, which function is best to clean up
+		 * this situation.  I choose: ide_error(...)
+		 */
+		return DRIVER(drive)->error(drive, "flagged_task_mulin_intr (unexpected data phase)", stat); 
+	}
 
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
-		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
+	nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors;
+	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+
+	DTF("Multiread: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
+	    pBuf, nsect, rq->current_nr_sectors);
+
+	taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
+
+	rq->current_nr_sectors -= nsect;
+	if (rq->current_nr_sectors != 0) {
+		/*
+                 * (ks) We don't know which command was executed. 
+		 * So, we wait the 'WORSTCASE' value.
+                 */
+		ide_set_handler(drive, &flagged_task_mulin_intr,  WAIT_WORSTCASE, NULL);
+		return ide_started;
 	}
-	if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
-		dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
 
-	if (IDE_CONTROL_REG)
-		OUT_BYTE (drive->ctl,IDE_CONTROL_REG);
-	OUT_BYTE (dma_ok ? 1:0,IDE_FEATURE_REG);	/* Use PIO/DMA */
-	OUT_BYTE (bcount.b.high,IDE_BCOUNTH_REG);
-	OUT_BYTE (bcount.b.low,IDE_BCOUNTL_REG);
-	OUT_BYTE (drive->select.all,IDE_SELECT_REG);
+	/*
+	 * (ks) Last sector was transfered, wait until drive is ready. 
+	 * This can take up to 10 usec. We willl wait max 50 us.
+	 */
+	while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--)
+		udelay(10);
+	ide_end_drive_cmd (drive, stat, hwif->INB(IDE_ERROR_REG));
 
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (dma_ok) {	/* Begin DMA, if necessary */
-		set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
-		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+	return ide_stopped;
+}
+
+/*
+ * Pre handler for command with PIO data-out phase
+ */
+ide_startstop_t flagged_pre_task_out_intr (ide_drive_t *drive, struct request *rq)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 stat			= hwif->INB(IDE_STATUS_REG);
+	ide_startstop_t startstop;
+
+	if (!rq->current_nr_sectors) {
+		return DRIVER(drive)->error(drive, "flagged_pre_task_out_intr (write data not specified)", stat);
 	}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
 
-} /* end floppy */
+	if (ide_wait_stat(&startstop, drive, DATA_READY,
+			BAD_W_STAT, WAIT_DRQ)) {
+		printk(KERN_ERR "%s: No DRQ bit after issuing write command.\n", drive->name);
+		return startstop;
+	}
 
-{ /* start tape */
+	taskfile_output_data(drive, rq->buffer, SECTOR_WORDS);
+	--rq->current_nr_sectors;
 
-	idetape_tape_t *tape = drive->driver_data;
+	return ide_started;
+}
 
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
-		printk (KERN_WARNING "ide-tape: DMA disabled, reverting to PIO\n");
-		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
-	}
-	if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
-		dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
+ide_startstop_t flagged_task_out_intr (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 stat			= hwif->INB(IDE_STATUS_REG);
+	struct request *rq	= HWGROUP(drive)->rq;
+	char *pBuf		= NULL;
 
-	if (IDE_CONTROL_REG)
-		OUT_BYTE (drive->ctl,IDE_CONTROL_REG);
-	OUT_BYTE (dma_ok ? 1:0,IDE_FEATURE_REG);	/* Use PIO/DMA */
-	OUT_BYTE (bcount.b.high,IDE_BCOUNTH_REG);
-	OUT_BYTE (bcount.b.low,IDE_BCOUNTL_REG);
-	OUT_BYTE (drive->select.all,IDE_SELECT_REG);
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (dma_ok) {	/* Begin DMA, if necessary */
-		set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
-		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
-	}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-	if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
-		ide_set_handler(drive, &idetape_transfer_pc, IDETAPE_WAIT_CMD, NULL);
-		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
-		return ide_started;
-	} else {
-		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
-		return idetape_transfer_pc(drive);
+	if (!OK_STAT(stat, DRIVE_READY, BAD_W_STAT)) 
+		return DRIVER(drive)->error(drive, "flagged_task_out_intr", stat);
+	
+	if (!rq->current_nr_sectors) { 
+		ide_end_drive_cmd (drive, stat, hwif->INB(IDE_ERROR_REG));
+		return ide_stopped;
 	}
 
-} /* end tape */
+	if (!OK_STAT(stat, DATA_READY, BAD_W_STAT)) {
+		/*
+		 * (ks) Unexpected ATA data phase detected.
+		 * This should not happen. But, it can !
+		 * I am not sure, which function is best to clean up
+		 * this situation.  I choose: ide_error(...)
+		 */
+		return DRIVER(drive)->error(drive, "flagged_task_out_intr (unexpected data phase)", stat); 
+	}
+
+	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+	DTF("Write - rq->current_nr_sectors: %d, status: %02x\n",
+		(int) rq->current_nr_sectors, stat);
+
+	taskfile_output_data(drive, pBuf, SECTOR_WORDS);
+	--rq->current_nr_sectors;
 
+	/*
+	 * (ks) We don't know which command was executed. 
+	 * So, we wait the 'WORSTCASE' value.
+	 */
+	ide_set_handler(drive, &flagged_task_out_intr, WAIT_WORSTCASE, NULL);
+
+	return ide_started;
 }
-#endif
+
+ide_startstop_t flagged_pre_task_mulout_intr (ide_drive_t *drive, struct request *rq)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 stat			= hwif->INB(IDE_STATUS_REG);
+	char *pBuf		= NULL;
+	ide_startstop_t startstop;
+	unsigned int msect, nsect;
+
+	if (!rq->current_nr_sectors) 
+		return DRIVER(drive)->error(drive, "flagged_pre_task_mulout_intr (write data not specified)", stat);
+
+	msect = drive->mult_count;
+	if (msect == 0)
+		return DRIVER(drive)->error(drive, "flagged_pre_task_mulout_intr (multimode not set)", stat);
+
+	if (ide_wait_stat(&startstop, drive, DATA_READY,
+			BAD_W_STAT, WAIT_DRQ)) {
+		printk(KERN_ERR "%s: No DRQ bit after issuing write command.\n", drive->name);
+		return startstop;
+	}
+
+	nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors;
+	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+	DTF("Multiwrite: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
+	    pBuf, nsect, rq->current_nr_sectors);
+
+	taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
+
+	rq->current_nr_sectors -= nsect;
+
+	return ide_started;
+}
+
+ide_startstop_t flagged_task_mulout_intr (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 stat			= hwif->INB(IDE_STATUS_REG);
+	struct request *rq	= HWGROUP(drive)->rq;
+	char *pBuf		= NULL;
+	unsigned int msect, nsect;
+
+	msect = drive->mult_count;
+	if (msect == 0)
+		return DRIVER(drive)->error(drive, "flagged_task_mulout_intr (multimode not set)", stat);
+
+	if (!OK_STAT(stat, DRIVE_READY, BAD_W_STAT)) 
+		return DRIVER(drive)->error(drive, "flagged_task_mulout_intr", stat);
+	
+	if (!rq->current_nr_sectors) { 
+		ide_end_drive_cmd (drive, stat, hwif->INB(IDE_ERROR_REG));
+		return ide_stopped;
+	}
+
+	if (!OK_STAT(stat, DATA_READY, BAD_W_STAT)) {
+		/*
+		 * (ks) Unexpected ATA data phase detected.
+		 * This should not happen. But, it can !
+		 * I am not sure, which function is best to clean up
+		 * this situation.  I choose: ide_error(...)
+		 */
+		return DRIVER(drive)->error(drive, "flagged_task_mulout_intr (unexpected data phase)", stat); 
+	}
+
+	nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors;
+	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+	DTF("Multiwrite: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
+	    pBuf, nsect, rq->current_nr_sectors);
+
+	taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
+	rq->current_nr_sectors -= nsect;
+
+	/*
+	 * (ks) We don't know which command was executed. 
+	 * So, we wait the 'WORSTCASE' value.
+	 */
+	ide_set_handler(drive, &flagged_task_mulout_intr, WAIT_WORSTCASE, NULL);
+
+	return ide_started;
+}
+
+/*
+ * Beginning of Taskfile OPCODE Library and feature sets.
+ */
+
+#ifdef CONFIG_PKT_TASK_IOCTL
 
 int pkt_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide-timing.h linux-2.4.21-pre6/drivers/ide/ide-timing.h
--- linux-2.4.20/drivers/ide/ide-timing.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/ide-timing.h	2003-03-26 23:49:50.000000000 +0000
@@ -245,6 +245,14 @@
 	}
 
 /*
+ * If the drive is an ATAPI device it may need slower address setup timing,
+ * so we stay on the safe side.
+ */
+
+	if (drive->media != ide_disk)
+		p.setup = 120;
+
+/*
  * Convert the timing to bus clock counts.
  */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide.c linux-2.4.21-pre6/drivers/ide/ide.c
--- linux-2.4.20/drivers/ide/ide.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/ide.c	2003-03-26 23:49:55.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/ide/ide.c		Version 6.31	June 9, 2000
+ *  linux/drivers/ide/ide.c		Version 7.00beta1	Nov 29 2002
  *
  *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
  */
@@ -12,7 +12,8 @@
  *  See linux/MAINTAINERS for address of current maintainer.
  *
  * This is the multiple IDE interface driver, as evolved from hd.c.
- * It supports up to MAX_HWIFS IDE interfaces, on one or more IRQs (usually 14 & 15).
+ * It supports up to MAX_HWIFS IDE interfaces, on one or more IRQs
+ *   (usually 14 & 15).
  * There can be up to two drives per interface, as per the ATA-2 spec.
  *
  * Primary:    ide0, port 0x1f0; major=3;  hda is minor=0; hdb is minor=64
@@ -113,16 +114,15 @@
  * Version 6.31		Debug Share INTR's and request queue streaming
  *			Native ATA-100 support
  *			Prep for Cascades Project
+ * Version 7.00alpha	First named revision of ide rearrange
+ * Version 7.00beta	(2.4 backport)
  *
  *  Some additional driver compile-time options are in ./include/linux/ide.h
  *
- *  To do, in likely order of completion:
- *	- modify kernel to obtain BIOS geometry for drives on 2nd/3rd/4th i/f
- *
  */
 
-#define	REVISION	"Revision: 6.31"
-#define	VERSION		"Id: ide.c 6.31 2000/06/09"
+#define	REVISION	"Revision: 7.00beta-2.4"
+#define	VERSION		"Id: ide.c 7.00b1 20021129"
 
 #undef REALLY_SLOW_IO		/* most systems can safely undef this */
 
@@ -141,9 +141,7 @@
 #include <linux/genhd.h>
 #include <linux/blkpg.h>
 #include <linux/slab.h>
-#ifndef MODULE
 #include <linux/init.h>
-#endif /* MODULE */
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/ide.h>
@@ -159,81 +157,65 @@
 
 #include "ide_modes.h"
 
-#ifdef CONFIG_KMOD
 #include <linux/kmod.h>
-#endif /* CONFIG_KMOD */
-
-#ifdef CONFIG_IDE_TASKFILE_IO
-#  define __TASKFILE__IO
-#else /* CONFIG_IDE_TASKFILE_IO */
-#  undef __TASKFILE__IO
-#endif /* CONFIG_IDE_TASKFILE_IO */
-
-#ifdef __TASKFILE__IO
-#else /* !__TASKFILE__IO */
-#endif /* __TASKFILE__IO */
 
 /* default maximum number of failures */
 #define IDE_DEFAULT_MAX_FAILURES 	1
 
-static const byte ide_hwif_to_major[] = { IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, IDE4_MAJOR, IDE5_MAJOR, IDE6_MAJOR, IDE7_MAJOR, IDE8_MAJOR, IDE9_MAJOR };
-
-static int	idebus_parameter; /* holds the "idebus=" parameter */
-static int	system_bus_speed; /* holds what we think is VESA/PCI bus speed */
-static int	initializing;     /* set while initializing built-in drivers */
+static const u8 ide_hwif_to_major[] = { IDE0_MAJOR, IDE1_MAJOR,
+					IDE2_MAJOR, IDE3_MAJOR,
+					IDE4_MAJOR, IDE5_MAJOR,
+					IDE6_MAJOR, IDE7_MAJOR,
+					IDE8_MAJOR, IDE9_MAJOR };
+
+static int idebus_parameter;	/* holds the "idebus=" parameter */
+static int system_bus_speed;	/* holds what we think is VESA/PCI bus speed */
+static int initializing;	/* set while initializing built-in drivers */
 
-#ifdef CONFIG_BLK_DEV_IDEPCI
-static int	ide_scan_direction;	/* THIS was formerly 2.2.x pci=reverse */
-#endif /* CONFIG_BLK_DEV_IDEPCI */
+static int ide_scan_direction;	/* THIS was formerly 2.2.x pci=reverse */
 
 #if defined(__mc68000__) || defined(CONFIG_APUS)
 /*
  * ide_lock is used by the Atari code to obtain access to the IDE interrupt,
  * which is shared between several drivers.
  */
-static int	ide_lock;
+static int ide_intr_lock;
 #endif /* __mc68000__ || CONFIG_APUS */
 
+#ifdef CONFIG_IDEDMA_AUTO
 int noautodma = 0;
+#else
+int noautodma = 1;
+#endif
+
+EXPORT_SYMBOL(noautodma);
+
 
 /*
  * ide_modules keeps track of the available IDE chipset/probe/driver modules.
  */
+ide_module_t *ide_chipsets;
 ide_module_t *ide_modules;
 ide_module_t *ide_probe;
 
 /*
  * This is declared extern in ide.h, for access by other IDE modules:
  */
-ide_hwif_t	ide_hwifs[MAX_HWIFS];	/* master data repository */
+ide_hwif_t ide_hwifs[MAX_HWIFS];	/* master data repository */
 
-#if (DISK_RECOVERY_TIME > 0)
-/*
- * For really screwy hardware (hey, at least it *can* be used with Linux)
- * we can enforce a minimum delay time between successive operations.
- */
-static unsigned long read_timer (void)
-{
-	unsigned long t, flags;
-	int i;
+EXPORT_SYMBOL(ide_hwifs);
 
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-	t = jiffies * 11932;
-    	outb_p(0, 0x43);
-	i = inb_p(0x40);
-	i |= inb(0x40) << 8;
-	__restore_flags(flags);	/* local CPU only */
-	return (t - i);
-}
-#endif /* DISK_RECOVERY_TIME */
-
-static inline void set_recovery_timer (ide_hwif_t *hwif)
-{
-#if (DISK_RECOVERY_TIME > 0)
-	hwif->last_time = read_timer();
-#endif /* DISK_RECOVERY_TIME */
-}
+ide_devices_t *idedisk;
+ide_devices_t *idecd;
+ide_devices_t *idefloppy;
+ide_devices_t *idetape;
+ide_devices_t *idescsi;
+
+EXPORT_SYMBOL(idedisk);
+EXPORT_SYMBOL(idecd);
+EXPORT_SYMBOL(idefloppy);
+EXPORT_SYMBOL(idetape);
+EXPORT_SYMBOL(idescsi);
 
 /*
  * Do not even *think* about calling this!
@@ -264,6 +246,16 @@
 	hwif->name[2]	= 'e';
 	hwif->name[3]	= '0' + index;
 	hwif->bus_state = BUSSTATE_ON;
+	hwif->reset_poll= NULL;
+	hwif->pre_reset = NULL;
+
+	hwif->atapi_dma = 0;		/* disable all atapi dma */ 
+	hwif->ultra_mask = 0x80;	/* disable all ultra */
+	hwif->mwdma_mask = 0x80;	/* disable all mwdma */
+	hwif->swdma_mask = 0x80;	/* disable all swdma */
+
+	default_hwif_iops(hwif);
+	default_hwif_transport(hwif);
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
 		ide_drive_t *drive = &hwif->drives[unit];
 
@@ -279,6 +271,8 @@
 		drive->name[1]			= 'd';
 		drive->name[2]			= 'a' + (index * MAX_DRIVES) + unit;
 		drive->max_failures		= IDE_DEFAULT_MAX_FAILURES;
+		drive->using_dma		= 0;
+		drive->is_flash			= 0;
 		init_waitqueue_head(&drive->wqueue);
 	}
 }
@@ -291,1726 +285,169 @@
  * This routine is normally called at driver initialization time,
  * but may also be called MUCH earlier during kernel "command-line"
  * parameter processing.  As such, we cannot depend on any other parts
- * of the kernel (such as memory allocation) to be functioning yet.
- *
- * This is too bad, as otherwise we could dynamically allocate the
- * ide_drive_t structs as needed, rather than always consuming memory
- * for the max possible number (MAX_HWIFS * MAX_DRIVES) of them.
- */
-#define MAGIC_COOKIE 0x12345678
-static void __init init_ide_data (void)
-{
-	unsigned int index;
-	static unsigned long magic_cookie = MAGIC_COOKIE;
-
-	if (magic_cookie != MAGIC_COOKIE)
-		return;		/* already initialized */
-	magic_cookie = 0;
-
-	/* Initialise all interface structures */
-	for (index = 0; index < MAX_HWIFS; ++index)
-		init_hwif_data(index);
-
-	/* Add default hw interfaces */
-	ide_init_default_hwifs();
-
-	idebus_parameter = 0;
-	system_bus_speed = 0;
-}
-
-/*
- * CompactFlash cards and their brethern pretend to be removable hard disks, except:
- *	(1) they never have a slave unit, and
- *	(2) they don't have doorlock mechanisms.
- * This test catches them, and is invoked elsewhere when setting appropriate config bits.
- *
- * FIXME: This treatment is probably applicable for *all* PCMCIA (PC CARD) devices,
- * so in linux 2.3.x we should change this to just treat all PCMCIA drives this way,
- * and get rid of the model-name tests below (too big of an interface change for 2.2.x).
- * At that time, we might also consider parameterizing the timeouts and retries,
- * since these are MUCH faster than mechanical drives.	-M.Lord
- */
-int drive_is_flashcard (ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-
-	if (drive->removable && id != NULL) {
-		if (id->config == 0x848a) return 1;	/* CompactFlash */
-		if (!strncmp(id->model, "KODAK ATA_FLASH", 15)	/* Kodak */
-		 || !strncmp(id->model, "Hitachi CV", 10)	/* Hitachi */
-		 || !strncmp(id->model, "SunDisk SDCFB", 13)	/* SunDisk */
-		 || !strncmp(id->model, "HAGIWARA HPC", 12)	/* Hagiwara */
-		 || !strncmp(id->model, "LEXAR ATA_FLASH", 15)	/* Lexar */
-		 || !strncmp(id->model, "ATA_FLASH", 9))	/* Simple Tech */
-		{
-			return 1;	/* yes, it is a flash memory card */
-		}
-	}
-	return 0;	/* no, it is not a flash memory card */
-}
-
-/*
- * ide_system_bus_speed() returns what we think is the system VESA/PCI
- * bus speed (in MHz).  This is used for calculating interface PIO timings.
- * The default is 40 for known PCI systems, 50 otherwise.
- * The "idebus=xx" parameter can be used to override this value.
- * The actual value to be used is computed/displayed the first time through.
- */
-int ide_system_bus_speed (void)
-{
-	if (!system_bus_speed) {
-		if (idebus_parameter)
-			system_bus_speed = idebus_parameter;	/* user supplied value */
-#ifdef CONFIG_PCI
-		else if (pci_present())
-			system_bus_speed = 33;	/* safe default value for PCI */
-#endif /* CONFIG_PCI */
-		else
-			system_bus_speed = 50;	/* safe default value for VESA and PCI */
-		printk("ide: Assuming %dMHz system bus speed for PIO modes%s\n", system_bus_speed,
-			idebus_parameter ? "" : "; override with idebus=xx");
-	}
-	return system_bus_speed;
-}
-
-#if SUPPORT_VLB_SYNC
-/*
- * Some localbus EIDE interfaces require a special access sequence
- * when using 32-bit I/O instructions to transfer data.  We call this
- * the "vlb_sync" sequence, which consists of three successive reads
- * of the sector count register location, with interrupts disabled
- * to ensure that the reads all happen together.
- */
-static inline void do_vlb_sync (ide_ioreg_t port) {
-	(void) inb (port);
-	(void) inb (port);
-	(void) inb (port);
-}
-#endif /* SUPPORT_VLB_SYNC */
-
-/*
- * This is used for most PIO data transfers *from* the IDE interface
- */
-void ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
-{
-	byte io_32bit;
-
-	/* first check if this controller has defined a special function
-	 * for handling polled ide transfers
-	 */
-
-	if(HWIF(drive)->ideproc) {
-		HWIF(drive)->ideproc(ideproc_ide_input_data,
-				     drive, buffer, wcount);
-		return;
-	}
-
-	io_32bit = drive->io_32bit;
-
-	if (io_32bit) {
-#if SUPPORT_VLB_SYNC
-		if (io_32bit & 2) {
-			unsigned long flags;
-			__save_flags(flags);	/* local CPU only */
-			__cli();		/* local CPU only */
-			do_vlb_sync(IDE_NSECTOR_REG);
-			insl(IDE_DATA_REG, buffer, wcount);
-			__restore_flags(flags);	/* local CPU only */
-		} else
-#endif /* SUPPORT_VLB_SYNC */
-			insl(IDE_DATA_REG, buffer, wcount);
-	} else {
-#if SUPPORT_SLOW_DATA_PORTS
-		if (drive->slow) {
-			unsigned short *ptr = (unsigned short *) buffer;
-			while (wcount--) {
-				*ptr++ = inw_p(IDE_DATA_REG);
-				*ptr++ = inw_p(IDE_DATA_REG);
-			}
-		} else
-#endif /* SUPPORT_SLOW_DATA_PORTS */
-			insw(IDE_DATA_REG, buffer, wcount<<1);
-	}
-}
-
-/*
- * This is used for most PIO data transfers *to* the IDE interface
- */
-void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
-{
-	byte io_32bit;
-
-	if(HWIF(drive)->ideproc) {
-		HWIF(drive)->ideproc(ideproc_ide_output_data,
-				     drive, buffer, wcount);
-		return;
-	}
-
-	io_32bit = drive->io_32bit;
-
-	if (io_32bit) {
-#if SUPPORT_VLB_SYNC
-		if (io_32bit & 2) {
-			unsigned long flags;
-			__save_flags(flags);	/* local CPU only */
-			__cli();		/* local CPU only */
-			do_vlb_sync(IDE_NSECTOR_REG);
-			outsl(IDE_DATA_REG, buffer, wcount);
-			__restore_flags(flags);	/* local CPU only */
-		} else
-#endif /* SUPPORT_VLB_SYNC */
-			outsl(IDE_DATA_REG, buffer, wcount);
-	} else {
-#if SUPPORT_SLOW_DATA_PORTS
-		if (drive->slow) {
-			unsigned short *ptr = (unsigned short *) buffer;
-			while (wcount--) {
-				outw_p(*ptr++, IDE_DATA_REG);
-				outw_p(*ptr++, IDE_DATA_REG);
-			}
-		} else
-#endif /* SUPPORT_SLOW_DATA_PORTS */
-			outsw(IDE_DATA_REG, buffer, wcount<<1);
-	}
-}
-
-/*
- * The following routines are mainly used by the ATAPI drivers.
- *
- * These routines will round up any request for an odd number of bytes,
- * so if an odd bytecount is specified, be sure that there's at least one
- * extra byte allocated for the buffer.
- */
-void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
-{
-	if(HWIF(drive)->ideproc) {
-		HWIF(drive)->ideproc(ideproc_atapi_input_bytes,
-				     drive, buffer, bytecount);
-		return;
-	}
-
-	++bytecount;
-#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
-	if (MACH_IS_ATARI || MACH_IS_Q40) {
-		/* Atari has a byte-swapped IDE interface */
-		insw_swapw(IDE_DATA_REG, buffer, bytecount / 2);
-		return;
-	}
-#endif /* CONFIG_ATARI */
-	ide_input_data (drive, buffer, bytecount / 4);
-	if ((bytecount & 0x03) >= 2)
-		insw (IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1);
-}
-
-void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
-{
-	if(HWIF(drive)->ideproc) {
-		HWIF(drive)->ideproc(ideproc_atapi_output_bytes,
-				     drive, buffer, bytecount);
-		return;
-	}
-
-	++bytecount;
-#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
-	if (MACH_IS_ATARI || MACH_IS_Q40) {
-		/* Atari has a byte-swapped IDE interface */
-		outsw_swapw(IDE_DATA_REG, buffer, bytecount / 2);
-		return;
-	}
-#endif /* CONFIG_ATARI */
-	ide_output_data (drive, buffer, bytecount / 4);
-	if ((bytecount & 0x03) >= 2)
-		outsw (IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1);
-}
-
-/*
- * Needed for PCI irq sharing
- */
-//static inline
-int drive_is_ready (ide_drive_t *drive)
-{
-	byte stat = 0;
-	if (drive->waiting_for_dma)
-		return HWIF(drive)->dmaproc(ide_dma_test_irq, drive);
-#if 0
-	udelay(1);	/* need to guarantee 400ns since last command was issued */
-#endif
-
-#ifdef CONFIG_IDEPCI_SHARE_IRQ
-	/*
-	 * We do a passive status test under shared PCI interrupts on
-	 * cards that truly share the ATA side interrupt, but may also share
-	 * an interrupt with another pci card/device.  We make no assumptions
-	 * about possible isa-pnp and pci-pnp issues yet.
-	 */
-	if (IDE_CONTROL_REG)
-		stat = GET_ALTSTAT();
-	else
-#endif /* CONFIG_IDEPCI_SHARE_IRQ */
-	stat = GET_STAT();	/* Note: this may clear a pending IRQ!! */
-
-	if (stat & BUSY_STAT)
-		return 0;	/* drive busy:  definitely not interrupting */
-	return 1;		/* drive ready: *might* be interrupting */
-}
-
-/*
- * This is our end_request replacement function.
- */
-void ide_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
-{
-	struct request *rq;
-	unsigned long flags;
-	ide_drive_t *drive = hwgroup->drive;
-
-	spin_lock_irqsave(&io_request_lock, flags);
-	rq = hwgroup->rq;
-
-	/*
-	 * decide whether to reenable DMA -- 3 is a random magic for now,
-	 * if we DMA timeout more than 3 times, just stay in PIO
-	 */
-	if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
-		drive->state = 0;
-		hwgroup->hwif->dmaproc(ide_dma_on, drive);
-	}
-
-	if (!end_that_request_first(rq, uptodate, hwgroup->drive->name)) {
-		add_blkdev_randomness(MAJOR(rq->rq_dev));
-		blkdev_dequeue_request(rq);
-        	hwgroup->rq = NULL;
-		end_that_request_last(rq);
-	}
-	spin_unlock_irqrestore(&io_request_lock, flags);
-}
-
-/*
- * This should get invoked any time we exit the driver to
- * wait for an interrupt response from a drive.  handler() points
- * at the appropriate code to handle the next interrupt, and a
- * timer is started to prevent us from waiting forever in case
- * something goes wrong (see the ide_timer_expiry() handler later on).
- */
-void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler,
-		      unsigned int timeout, ide_expiry_t *expiry)
-{
-	unsigned long flags;
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-
-	spin_lock_irqsave(&io_request_lock, flags);
-	if (hwgroup->handler != NULL) {
-		printk("%s: ide_set_handler: handler not null; old=%p, new=%p\n",
-			drive->name, hwgroup->handler, handler);
-	}
-	hwgroup->handler	= handler;
-	hwgroup->expiry		= expiry;
-	hwgroup->timer.expires	= jiffies + timeout;
-	add_timer(&hwgroup->timer);
-	spin_unlock_irqrestore(&io_request_lock, flags);
-}
-
-/*
- * current_capacity() returns the capacity (in sectors) of a drive
- * according to its current geometry/LBA settings.
- */
-unsigned long current_capacity (ide_drive_t *drive)
-{
-	if (!drive->present)
-		return 0;
-	if (drive->driver != NULL)
-		return DRIVER(drive)->capacity(drive);
-	return 0;
-}
-
-extern struct block_device_operations ide_fops[];
-/*
- * ide_geninit() is called exactly *once* for each interface.
- */
-void ide_geninit (ide_hwif_t *hwif)
-{
-	unsigned int unit;
-	struct gendisk *gd = hwif->gd;
-
-	for (unit = 0; unit < MAX_DRIVES; ++unit) {
-		ide_drive_t *drive = &hwif->drives[unit];
-
-		if (!drive->present)
-			continue;
-		if (drive->media!=ide_disk && drive->media!=ide_floppy)
-			continue;
-		register_disk(gd,MKDEV(hwif->major,unit<<PARTN_BITS),
-#ifdef CONFIG_BLK_DEV_ISAPNP
-			(drive->forced_geom && drive->noprobe) ? 1 :
-#endif /* CONFIG_BLK_DEV_ISAPNP */
-			1<<PARTN_BITS, ide_fops,
-			current_capacity(drive));
-	}
-}
-
-static ide_startstop_t do_reset1 (ide_drive_t *, int);		/* needed below */
-
-/*
- * atapi_reset_pollfunc() gets invoked to poll the interface for completion every 50ms
- * during an atapi drive reset operation. If the drive has not yet responded,
- * and we have not yet hit our maximum waiting time, then the timer is restarted
- * for another 50ms.
- */
-static ide_startstop_t atapi_reset_pollfunc (ide_drive_t *drive)
-{
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	byte stat;
-
-	SELECT_DRIVE(HWIF(drive),drive);
-	udelay (10);
-
-	if (OK_STAT(stat=GET_STAT(), 0, BUSY_STAT)) {
-		printk("%s: ATAPI reset complete\n", drive->name);
-	} else {
-		if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) {
-			ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20, NULL);
-			return ide_started;	/* continue polling */
-		}
-		hwgroup->poll_timeout = 0;	/* end of polling */
-		printk("%s: ATAPI reset timed-out, status=0x%02x\n", drive->name, stat);
-		return do_reset1 (drive, 1);	/* do it the old fashioned way */
-	}
-	hwgroup->poll_timeout = 0;	/* done polling */
-	return ide_stopped;
-}
-
-/*
- * reset_pollfunc() gets invoked to poll the interface for completion every 50ms
- * during an ide reset operation. If the drives have not yet responded,
- * and we have not yet hit our maximum waiting time, then the timer is restarted
- * for another 50ms.
- */
-static ide_startstop_t reset_pollfunc (ide_drive_t *drive)
-{
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	ide_hwif_t *hwif = HWIF(drive);
-	byte tmp;
-
-	if (!OK_STAT(tmp=GET_STAT(), 0, BUSY_STAT)) {
-		if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) {
-			ide_set_handler (drive, &reset_pollfunc, HZ/20, NULL);
-			return ide_started;	/* continue polling */
-		}
-		printk("%s: reset timed-out, status=0x%02x\n", hwif->name, tmp);
-		drive->failures++;
-	} else  {
-		printk("%s: reset: ", hwif->name);
-		if ((tmp = GET_ERR()) == 1) {
-			printk("success\n");
-			drive->failures = 0;
-		} else {
-			drive->failures++;
-#if FANCY_STATUS_DUMPS
-			printk("master: ");
-			switch (tmp & 0x7f) {
-				case 1: printk("passed");
-					break;
-				case 2: printk("formatter device error");
-					break;
-				case 3: printk("sector buffer error");
-					break;
-				case 4: printk("ECC circuitry error");
-					break;
-				case 5: printk("controlling MPU error");
-					break;
-				default:printk("error (0x%02x?)", tmp);
-			}
-			if (tmp & 0x80)
-				printk("; slave: failed");
-			printk("\n");
-#else
-			printk("failed\n");
-#endif /* FANCY_STATUS_DUMPS */
-		}
-	}
-	hwgroup->poll_timeout = 0;	/* done polling */
-	return ide_stopped;
-}
-
-static void check_dma_crc (ide_drive_t *drive)
-{
-	if (drive->crc_count) {
-		(void) HWIF(drive)->dmaproc(ide_dma_off_quietly, drive);
-		if ((HWIF(drive)->speedproc) != NULL)
-			HWIF(drive)->speedproc(drive, ide_auto_reduce_xfer(drive));
-		if (drive->current_speed >= XFER_SW_DMA_0)
-			(void) HWIF(drive)->dmaproc(ide_dma_on, drive);
-	} else {
-		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
-	}
-}
-
-static void pre_reset (ide_drive_t *drive)
-{
-	if (drive->driver != NULL)
-		DRIVER(drive)->pre_reset(drive);
-
-	if (!drive->keep_settings) {
-		if (drive->using_dma) {
-			check_dma_crc(drive);
-		} else {
-			drive->unmask = 0;
-			drive->io_32bit = 0;
-		}
-		return;
-	}
-	if (drive->using_dma)
-		check_dma_crc(drive);
-}
-
-/*
- * do_reset1() attempts to recover a confused drive by resetting it.
- * Unfortunately, resetting a disk drive actually resets all devices on
- * the same interface, so it can really be thought of as resetting the
- * interface rather than resetting the drive.
- *
- * ATAPI devices have their own reset mechanism which allows them to be
- * individually reset without clobbering other devices on the same interface.
- *
- * Unfortunately, the IDE interface does not generate an interrupt to let
- * us know when the reset operation has finished, so we must poll for this.
- * Equally poor, though, is the fact that this may a very long time to complete,
- * (up to 30 seconds worstcase).  So, instead of busy-waiting here for it,
- * we set a timer to poll at 50ms intervals.
- */
-static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
-{
-	unsigned int unit;
-	unsigned long flags;
-	ide_hwif_t *hwif = HWIF(drive);
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-
-	/* For an ATAPI device, first try an ATAPI SRST. */
-	if (drive->media != ide_disk && !do_not_try_atapi) {
-		pre_reset(drive);
-		SELECT_DRIVE(hwif,drive);
-		udelay (20);
-		OUT_BYTE (WIN_SRST, IDE_COMMAND_REG);
-		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
-		ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20, NULL);
-		__restore_flags (flags);	/* local CPU only */
-		return ide_started;
-	}
-
-	/*
-	 * First, reset any device state data we were maintaining
-	 * for any of the drives on this interface.
-	 */
-	for (unit = 0; unit < MAX_DRIVES; ++unit)
-		pre_reset(&hwif->drives[unit]);
-
-#if OK_TO_RESET_CONTROLLER
-	if (!IDE_CONTROL_REG) {
-		__restore_flags(flags);
-		return ide_stopped;
-	}
-	/*
-	 * Note that we also set nIEN while resetting the device,
-	 * to mask unwanted interrupts from the interface during the reset.
-	 * However, due to the design of PC hardware, this will cause an
-	 * immediate interrupt due to the edge transition it produces.
-	 * This single interrupt gives us a "fast poll" for drives that
-	 * recover from reset very quickly, saving us the first 50ms wait time.
-	 */
-	OUT_BYTE(drive->ctl|6,IDE_CONTROL_REG);	/* set SRST and nIEN */
-	udelay(10);			/* more than enough time */
-	if (drive->quirk_list == 2) {
-		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);	/* clear SRST and nIEN */
-	} else {
-		OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG);	/* clear SRST, leave nIEN */
-	}
-	udelay(10);			/* more than enough time */
-	hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
-	ide_set_handler (drive, &reset_pollfunc, HZ/20, NULL);
-
-	/*
-	 * Some weird controller like resetting themselves to a strange
-	 * state when the disks are reset this way. At least, the Winbond
-	 * 553 documentation says that
-	 */
-	if (hwif->resetproc != NULL)
-		hwif->resetproc(drive);
-
-#endif	/* OK_TO_RESET_CONTROLLER */
-
-	__restore_flags (flags);	/* local CPU only */
-	return ide_started;
-}
-
-/*
- * ide_do_reset() is the entry point to the drive/interface reset code.
- */
-ide_startstop_t ide_do_reset (ide_drive_t *drive)
-{
-	return do_reset1 (drive, 0);
-}
-
-static inline u32 read_24 (ide_drive_t *drive)
-{
-	return  (IN_BYTE(IDE_HCYL_REG)<<16) |
-		(IN_BYTE(IDE_LCYL_REG)<<8) |
-		 IN_BYTE(IDE_SECTOR_REG);
-}
-
-/*
- * Clean up after success/failure of an explicit drive cmd
- */
-void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err)
-{
-	unsigned long flags;
-	struct request *rq;
-
-	spin_lock_irqsave(&io_request_lock, flags);
-	rq = HWGROUP(drive)->rq;
-	spin_unlock_irqrestore(&io_request_lock, flags);
-
-	switch(rq->cmd) {
-		case IDE_DRIVE_CMD:
-		{
-			byte *args = (byte *) rq->buffer;
-			rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
-			if (args) {
-				args[0] = stat;
-				args[1] = err;
-				args[2] = IN_BYTE(IDE_NSECTOR_REG);
-			}
-			break;
-		}
-		case IDE_DRIVE_TASK:
-		{
-			byte *args = (byte *) rq->buffer;
-			rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
-			if (args) {
-				args[0] = stat;
-				args[1] = err;
-				args[2] = IN_BYTE(IDE_NSECTOR_REG);
-				args[3] = IN_BYTE(IDE_SECTOR_REG);
-				args[4] = IN_BYTE(IDE_LCYL_REG);
-				args[5] = IN_BYTE(IDE_HCYL_REG);
-				args[6] = IN_BYTE(IDE_SELECT_REG);
-			}
-			break;
-		}
-		case IDE_DRIVE_TASKFILE:
-		{
-			ide_task_t *args = (ide_task_t *) rq->special;
-			rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
-			if (args) {
-				if (args->tf_in_flags.b.data) {
-					unsigned short data			= IN_WORD(IDE_DATA_REG);
-					args->tfRegister[IDE_DATA_OFFSET]	= (data) & 0xFF;
-					args->hobRegister[IDE_DATA_OFFSET_HOB]	= (data >> 8) & 0xFF;
-				}
-				args->tfRegister[IDE_ERROR_OFFSET]   = err;
-				args->tfRegister[IDE_NSECTOR_OFFSET] = IN_BYTE(IDE_NSECTOR_REG);
-				args->tfRegister[IDE_SECTOR_OFFSET]  = IN_BYTE(IDE_SECTOR_REG);
-				args->tfRegister[IDE_LCYL_OFFSET]    = IN_BYTE(IDE_LCYL_REG);
-				args->tfRegister[IDE_HCYL_OFFSET]    = IN_BYTE(IDE_HCYL_REG);
-				args->tfRegister[IDE_SELECT_OFFSET]  = IN_BYTE(IDE_SELECT_REG);
-				args->tfRegister[IDE_STATUS_OFFSET]  = stat;
-
-				if ((drive->id->command_set_2 & 0x0400) &&
-				    (drive->id->cfs_enable_2 & 0x0400) &&
-				    (drive->addressing == 1)) {
-					OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG_HOB);
-					args->hobRegister[IDE_FEATURE_OFFSET_HOB] = IN_BYTE(IDE_FEATURE_REG);
-					args->hobRegister[IDE_NSECTOR_OFFSET_HOB] = IN_BYTE(IDE_NSECTOR_REG);
-					args->hobRegister[IDE_SECTOR_OFFSET_HOB]  = IN_BYTE(IDE_SECTOR_REG);
-					args->hobRegister[IDE_LCYL_OFFSET_HOB]    = IN_BYTE(IDE_LCYL_REG);
-					args->hobRegister[IDE_HCYL_OFFSET_HOB]    = IN_BYTE(IDE_HCYL_REG);
-				}
-			}
-			break;
-		}
-		default:
-			break;
-	}
-	spin_lock_irqsave(&io_request_lock, flags);
-	blkdev_dequeue_request(rq);
-	HWGROUP(drive)->rq = NULL;
-	end_that_request_last(rq);
-	spin_unlock_irqrestore(&io_request_lock, flags);
-}
-
-/*
- * Error reporting, in human readable form (luxurious, but a memory hog).
- */
-byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat)
-{
-	unsigned long flags;
-	byte err = 0;
-
-	__save_flags (flags);	/* local CPU only */
-	ide__sti();		/* local CPU only */
-	printk("%s: %s: status=0x%02x", drive->name, msg, stat);
-#if FANCY_STATUS_DUMPS
-	printk(" { ");
-	if (stat & BUSY_STAT)
-		printk("Busy ");
-	else {
-		if (stat & READY_STAT)	printk("DriveReady ");
-		if (stat & WRERR_STAT)	printk("DeviceFault ");
-		if (stat & SEEK_STAT)	printk("SeekComplete ");
-		if (stat & DRQ_STAT)	printk("DataRequest ");
-		if (stat & ECC_STAT)	printk("CorrectedError ");
-		if (stat & INDEX_STAT)	printk("Index ");
-		if (stat & ERR_STAT)	printk("Error ");
-	}
-	printk("}");
-#endif	/* FANCY_STATUS_DUMPS */
-	printk("\n");
-	if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
-		err = GET_ERR();
-		printk("%s: %s: error=0x%02x", drive->name, msg, err);
-#if FANCY_STATUS_DUMPS
-		if (drive->media == ide_disk) {
-			printk(" { ");
-			if (err & ABRT_ERR)	printk("DriveStatusError ");
-			if (err & ICRC_ERR)	printk("%s", (err & ABRT_ERR) ? "BadCRC " : "BadSector ");
-			if (err & ECC_ERR)	printk("UncorrectableError ");
-			if (err & ID_ERR)	printk("SectorIdNotFound ");
-			if (err & TRK0_ERR)	printk("TrackZeroNotFound ");
-			if (err & MARK_ERR)	printk("AddrMarkNotFound ");
-			printk("}");
-			if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR || (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
-				if ((drive->id->command_set_2 & 0x0400) &&
-				    (drive->id->cfs_enable_2 & 0x0400) &&
-				    (drive->addressing == 1)) {
-					__u64 sectors = 0;
-					u32 low = 0, high = 0;
-					low = read_24(drive);
-					OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG);
-					high = read_24(drive);
-
-					sectors = ((__u64)high << 24) | low;
-					printk(", LBAsect=%llu, high=%d, low=%d",
-					       (unsigned long long) sectors,
-					       high, low);
-				} else {
-					byte cur = IN_BYTE(IDE_SELECT_REG);
-					if (cur & 0x40) {	/* using LBA? */
-						printk(", LBAsect=%ld", (unsigned long)
-						 ((cur&0xf)<<24)
-						 |(IN_BYTE(IDE_HCYL_REG)<<16)
-						 |(IN_BYTE(IDE_LCYL_REG)<<8)
-						 | IN_BYTE(IDE_SECTOR_REG));
-					} else {
-						printk(", CHS=%d/%d/%d",
-						 (IN_BYTE(IDE_HCYL_REG)<<8) +
-						  IN_BYTE(IDE_LCYL_REG),
-						  cur & 0xf,
-						  IN_BYTE(IDE_SECTOR_REG));
-					}
-				}
-				if (HWGROUP(drive) && HWGROUP(drive)->rq)
-					printk(", sector=%ld", HWGROUP(drive)->rq->sector);
-			}
-		}
-#endif	/* FANCY_STATUS_DUMPS */
-		printk("\n");
-	}
-	__restore_flags (flags);	/* local CPU only */
-	return err;
-}
-
-/*
- * try_to_flush_leftover_data() is invoked in response to a drive
- * unexpectedly having its DRQ_STAT bit set.  As an alternative to
- * resetting the drive, this routine tries to clear the condition
- * by read a sector's worth of data from the drive.  Of course,
- * this may not help if the drive is *waiting* for data from *us*.
- */
-static void try_to_flush_leftover_data (ide_drive_t *drive)
-{
-	int i = (drive->mult_count ? drive->mult_count : 1) * SECTOR_WORDS;
-
-	if (drive->media != ide_disk)
-		return;
-	while (i > 0) {
-		u32 buffer[16];
-		unsigned int wcount = (i > 16) ? 16 : i;
-		i -= wcount;
-		ide_input_data (drive, buffer, wcount);
-	}
-}
-
-/*
- * ide_error() takes action based on the error returned by the drive.
- */
-ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, byte stat)
-{
-	struct request *rq;
-	byte err;
-
-	err = ide_dump_status(drive, msg, stat);
-	if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
-		return ide_stopped;
-	/* retry only "normal" I/O: */
-	if (rq->cmd == IDE_DRIVE_CMD || rq->cmd == IDE_DRIVE_TASK) {
-		rq->errors = 1;
-		ide_end_drive_cmd(drive, stat, err);
-		return ide_stopped;
-	}
-	if (rq->cmd == IDE_DRIVE_TASKFILE) {
-		rq->errors = 1;
-		ide_end_drive_cmd(drive, stat, err);
-//		ide_end_taskfile(drive, stat, err);
-		return ide_stopped;
-	}
-
-	if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) { /* other bits are useless when BUSY */
-		rq->errors |= ERROR_RESET;
-	} else {
-		if (drive->media == ide_disk && (stat & ERR_STAT)) {
-			/* err has different meaning on cdrom and tape */
-			if (err == ABRT_ERR) {
-				if (drive->select.b.lba && IN_BYTE(IDE_COMMAND_REG) == WIN_SPECIFY)
-					return ide_stopped; /* some newer drives don't support WIN_SPECIFY */
-			} else if ((err & (ABRT_ERR | ICRC_ERR)) == (ABRT_ERR | ICRC_ERR)) {
-				drive->crc_count++; /* UDMA crc error -- just retry the operation */
-			} else if (err & (BBD_ERR | ECC_ERR))	/* retries won't help these */
-				rq->errors = ERROR_MAX;
-			else if (err & TRK0_ERR)	/* help it find track zero */
-				rq->errors |= ERROR_RECAL;
-		}
-		if ((stat & DRQ_STAT) && rq->cmd != WRITE)
-			try_to_flush_leftover_data(drive);
-	}
-	if (GET_STAT() & (BUSY_STAT|DRQ_STAT))
-		OUT_BYTE(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);	/* force an abort */
-
-	if (rq->errors >= ERROR_MAX) {
-		if (drive->driver != NULL)
-			DRIVER(drive)->end_request(0, HWGROUP(drive));
-		else
-	 		ide_end_request(0, HWGROUP(drive));
-	} else {
-		if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
-			++rq->errors;
-			return ide_do_reset(drive);
-		}
-		if ((rq->errors & ERROR_RECAL) == ERROR_RECAL)
-			drive->special.b.recalibrate = 1;
-		++rq->errors;
-	}
-	return ide_stopped;
-}
-
-/*
- * Issue a simple drive command
- * The drive must be selected beforehand.
- */
-void ide_cmd (ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler)
-{
-	ide_set_handler (drive, handler, WAIT_CMD, NULL);
-	if (IDE_CONTROL_REG)
-		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);	/* clear nIEN */
-	SELECT_MASK(HWIF(drive),drive,0);
-	OUT_BYTE(nsect,IDE_NSECTOR_REG);
-	OUT_BYTE(cmd,IDE_COMMAND_REG);
-}
-
-/*
- * drive_cmd_intr() is invoked on completion of a special DRIVE_CMD.
- */
-static ide_startstop_t drive_cmd_intr (ide_drive_t *drive)
-{
-	struct request *rq = HWGROUP(drive)->rq;
-	byte *args = (byte *) rq->buffer;
-	byte stat = GET_STAT();
-	int retries = 10;
-
-	ide__sti();	/* local CPU only */
-	if ((stat & DRQ_STAT) && args && args[3]) {
-		byte io_32bit = drive->io_32bit;
-		drive->io_32bit = 0;
-		ide_input_data(drive, &args[4], args[3] * SECTOR_WORDS);
-		drive->io_32bit = io_32bit;
-		while (((stat = GET_STAT()) & BUSY_STAT) && retries--)
-			udelay(100);
-	}
-
-	if (!OK_STAT(stat, READY_STAT, BAD_STAT))
-		return ide_error(drive, "drive_cmd", stat); /* calls ide_end_drive_cmd */
-	ide_end_drive_cmd (drive, stat, GET_ERR());
-	return ide_stopped;
-}
-
-/*
- * do_special() is used to issue WIN_SPECIFY, WIN_RESTORE, and WIN_SETMULT
- * commands to a drive.  It used to do much more, but has been scaled back.
- */
-static ide_startstop_t do_special (ide_drive_t *drive)
-{
-	special_t *s = &drive->special;
-
-#ifdef DEBUG
-	printk("%s: do_special: 0x%02x\n", drive->name, s->all);
-#endif
-	if (s->b.set_tune) {
-		ide_tuneproc_t *tuneproc = HWIF(drive)->tuneproc;
-		s->b.set_tune = 0;
-		if (tuneproc != NULL)
-			tuneproc(drive, drive->tune_req);
-	} else if (drive->driver != NULL) {
-		return DRIVER(drive)->special(drive);
-	} else if (s->all) {
-		printk("%s: bad special flag: 0x%02x\n", drive->name, s->all);
-		s->all = 0;
-	}
-	return ide_stopped;
-}
-
-/*
- * This routine busy-waits for the drive status to be not "busy".
- * It then checks the status for all of the "good" bits and none
- * of the "bad" bits, and if all is okay it returns 0.  All other
- * cases return 1 after invoking ide_error() -- caller should just return.
- *
- * This routine should get fixed to not hog the cpu during extra long waits..
- * That could be done by busy-waiting for the first jiffy or two, and then
- * setting a timer to wake up at half second intervals thereafter,
- * until timeout is achieved, before timing out.
- */
-int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, byte good, byte bad, unsigned long timeout) {
-	byte stat;
-	int i;
-	unsigned long flags;
- 
-	/* bail early if we've exceeded max_failures */
-	if (drive->max_failures && (drive->failures > drive->max_failures)) {
-		*startstop = ide_stopped;
-		return 1;
-	}
-
-	udelay(1);	/* spec allows drive 400ns to assert "BUSY" */
-	if ((stat = GET_STAT()) & BUSY_STAT) {
-		__save_flags(flags);	/* local CPU only */
-		ide__sti();		/* local CPU only */
-		timeout += jiffies;
-		while ((stat = GET_STAT()) & BUSY_STAT) {
-			if (0 < (signed long)(jiffies - timeout)) {
-				__restore_flags(flags);	/* local CPU only */
-				*startstop = ide_error(drive, "status timeout", stat);
-				return 1;
-			}
-		}
-		__restore_flags(flags);	/* local CPU only */
-	}
-	/*
-	 * Allow status to settle, then read it again.
-	 * A few rare drives vastly violate the 400ns spec here,
-	 * so we'll wait up to 10usec for a "good" status
-	 * rather than expensively fail things immediately.
-	 * This fix courtesy of Matthew Faupel & Niccolo Rigacci.
-	 */
-	for (i = 0; i < 10; i++) {
-		udelay(1);
-		if (OK_STAT((stat = GET_STAT()), good, bad))
-			return 0;
-	}
-	*startstop = ide_error(drive, "status error", stat);
-	return 1;
-}
-
-/*
- * execute_drive_cmd() issues a special drive command,
- * usually initiated by ioctl() from the external hdparm program.
- */
-static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq)
-{
- 	switch(rq->cmd) {
- 		case IDE_DRIVE_TASKFILE:
- 		{
- 			ide_task_t *args = rq->special;
- 
- 			if (!(args)) break;
- 
-#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
-	{
-	printk(KERN_INFO "%s: ", drive->name);
-//	printk("TF.0=x%02x ", args->tfRegister[IDE_DATA_OFFSET]);
-	printk("TF.1=x%02x ", args->tfRegister[IDE_FEATURE_OFFSET]);
-	printk("TF.2=x%02x ", args->tfRegister[IDE_NSECTOR_OFFSET]);
-	printk("TF.3=x%02x ", args->tfRegister[IDE_SECTOR_OFFSET]);
-	printk("TF.4=x%02x ", args->tfRegister[IDE_LCYL_OFFSET]);
-	printk("TF.5=x%02x ", args->tfRegister[IDE_HCYL_OFFSET]);
-	printk("TF.6=x%02x ", args->tfRegister[IDE_SELECT_OFFSET]);
-	printk("TF.7=x%02x\n", args->tfRegister[IDE_COMMAND_OFFSET]);
-	printk(KERN_INFO "%s: ", drive->name);
-//	printk("HTF.0=x%02x ", args->hobRegister[IDE_DATA_OFFSET_HOB]);
-	printk("HTF.1=x%02x ", args->hobRegister[IDE_FEATURE_OFFSET_HOB]);
-	printk("HTF.2=x%02x ", args->hobRegister[IDE_NSECTOR_OFFSET_HOB]);
-	printk("HTF.3=x%02x ", args->hobRegister[IDE_SECTOR_OFFSET_HOB]);
-	printk("HTF.4=x%02x ", args->hobRegister[IDE_LCYL_OFFSET_HOB]);
-	printk("HTF.5=x%02x ", args->hobRegister[IDE_HCYL_OFFSET_HOB]);
-	printk("HTF.6=x%02x ", args->hobRegister[IDE_SELECT_OFFSET_HOB]);
-	printk("HTF.7=x%02x\n", args->hobRegister[IDE_CONTROL_OFFSET_HOB]);
-	}
-#endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
-
-//			if (args->tf_out_flags.all == 0) {
- 			do_taskfile(drive,
- 				(struct hd_drive_task_hdr *)&args->tfRegister,
-				(struct hd_drive_hob_hdr *)&args->hobRegister,
- 				args->handler);
-//			} else {
-//				return flagged_taskfile(drive, args);
-//			} 
-
- 			if (((args->command_type == IDE_DRIVE_TASK_RAW_WRITE) ||
- 			     (args->command_type == IDE_DRIVE_TASK_OUT)) &&
-			      args->prehandler && args->handler)
-				return args->prehandler(drive, rq);
- 			return ide_started;
- 		}
- 		case IDE_DRIVE_TASK:
- 		{
- 			byte *args = rq->buffer;
- 			byte sel;
- 
- 			if (!(args)) break;
-#ifdef DEBUG
- 			printk("%s: DRIVE_TASK_CMD ", drive->name);
- 			printk("cmd=0x%02x ", args[0]);
- 			printk("fr=0x%02x ", args[1]);
- 			printk("ns=0x%02x ", args[2]);
- 			printk("sc=0x%02x ", args[3]);
- 			printk("lcyl=0x%02x ", args[4]);
- 			printk("hcyl=0x%02x ", args[5]);
- 			printk("sel=0x%02x\n", args[6]);
-#endif
- 			OUT_BYTE(args[1], IDE_FEATURE_REG);
- 			OUT_BYTE(args[3], IDE_SECTOR_REG);
- 			OUT_BYTE(args[4], IDE_LCYL_REG);
- 			OUT_BYTE(args[5], IDE_HCYL_REG);
- 			sel = (args[6] & ~0x10);
- 			if (drive->select.b.unit)
- 				sel |= 0x10;
- 			OUT_BYTE(sel, IDE_SELECT_REG);
- 			ide_cmd(drive, args[0], args[2], &drive_cmd_intr);
- 			return ide_started;
- 		}
- 		case IDE_DRIVE_CMD:
- 		{
- 			byte *args = rq->buffer;
- 
- 			if (!(args)) break;
-#ifdef DEBUG
- 			printk("%s: DRIVE_CMD ", drive->name);
- 			printk("cmd=0x%02x ", args[0]);
- 			printk("sc=0x%02x ", args[1]);
- 			printk("fr=0x%02x ", args[2]);
- 			printk("xx=0x%02x\n", args[3]);
-#endif
- 			if (args[0] == WIN_SMART) {
- 				OUT_BYTE(0x4f, IDE_LCYL_REG);
- 				OUT_BYTE(0xc2, IDE_HCYL_REG);
- 				OUT_BYTE(args[2],IDE_FEATURE_REG);
- 				OUT_BYTE(args[1],IDE_SECTOR_REG);
- 				ide_cmd(drive, args[0], args[3], &drive_cmd_intr);
- 				return ide_started;
- 			}
- 			OUT_BYTE(args[2],IDE_FEATURE_REG);
- 			ide_cmd(drive, args[0], args[1], &drive_cmd_intr);
- 			return ide_started;
- 		}
- 		default:
- 			break;
- 	}
- 	/*
- 	 * NULL is actually a valid way of waiting for
- 	 * all current requests to be flushed from the queue.
- 	 */
-#ifdef DEBUG
- 	printk("%s: DRIVE_CMD (null)\n", drive->name);
-#endif
- 	ide_end_drive_cmd(drive, GET_STAT(), GET_ERR());
- 	return ide_stopped;
-}
-
-/*
- * start_request() initiates handling of a new I/O request
- * needed to reverse the perverted changes anonymously made back
- * 2.3.99-pre6
- */
-static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
-{
-	ide_startstop_t startstop;
-	unsigned long block, blockend;
-	unsigned int minor = MINOR(rq->rq_dev), unit = minor >> PARTN_BITS;
-	ide_hwif_t *hwif = HWIF(drive);
-
-#ifdef DEBUG
-	printk("%s: start_request: current=0x%08lx\n", hwif->name, (unsigned long) rq);
-#endif
-	/* bail early if we've exceeded max_failures */
-	if (drive->max_failures && (drive->failures > drive->max_failures)) {
-		goto kill_rq;
-	}
-
-	if (unit >= MAX_DRIVES) {
-		printk("%s: bad device number: %s\n", hwif->name, kdevname(rq->rq_dev));
-		goto kill_rq;
-	}
-#ifdef DEBUG
-	if (rq->bh && !buffer_locked(rq->bh)) {
-		printk("%s: block not locked\n", drive->name);
-		goto kill_rq;
-	}
-#endif
-	block    = rq->sector;
-	blockend = block + rq->nr_sectors;
-
-	if ((rq->cmd == READ || rq->cmd == WRITE) &&
-	    (drive->media == ide_disk || drive->media == ide_floppy)) {
-		if ((blockend < block) || (blockend > drive->part[minor&PARTN_MASK].nr_sects)) {
-			printk("%s%c: bad access: block=%ld, count=%ld\n", drive->name,
-			 (minor&PARTN_MASK)?'0'+(minor&PARTN_MASK):' ', block, rq->nr_sectors);
-			goto kill_rq;
-		}
-		block += drive->part[minor&PARTN_MASK].start_sect + drive->sect0;
-	}
-	/* Yecch - this will shift the entire interval,
-	   possibly killing some innocent following sector */
-	if (block == 0 && drive->remap_0_to_1 == 1)
-		block = 1;  /* redirect MBR access to EZ-Drive partn table */
-
-#if (DISK_RECOVERY_TIME > 0)
-	while ((read_timer() - hwif->last_time) < DISK_RECOVERY_TIME);
-#endif
-
-	SELECT_DRIVE(hwif, drive);
-	if (ide_wait_stat(&startstop, drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) {
-		printk("%s: drive not ready for command\n", drive->name);
-		return startstop;
-	}
-	if (!drive->special.all) {
-		switch(rq->cmd) {
-			case IDE_DRIVE_CMD:
-			case IDE_DRIVE_TASK:
-			case IDE_DRIVE_TASKFILE:
-				return execute_drive_cmd(drive, rq);
-			default:
-				break;
-		}
-		if (drive->driver != NULL) {
-			return (DRIVER(drive)->do_request(drive, rq, block));
-		}
-		printk("%s: media type %d not supported\n", drive->name, drive->media);
-		goto kill_rq;
-	}
-	return do_special(drive);
-kill_rq:
-	if (drive->driver != NULL)
-		DRIVER(drive)->end_request(0, HWGROUP(drive));
-	else
-		ide_end_request(0, HWGROUP(drive));
-	return ide_stopped;
-}
-
-ide_startstop_t restart_request (ide_drive_t *drive)
-{
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	unsigned long flags;
-	struct request *rq;
-
-	spin_lock_irqsave(&io_request_lock, flags);
-	hwgroup->handler = NULL;
-	del_timer(&hwgroup->timer);
-	rq = hwgroup->rq;
-	spin_unlock_irqrestore(&io_request_lock, flags);
-
-	return start_request(drive, rq);
-}
-
-/*
- * ide_stall_queue() can be used by a drive to give excess bandwidth back
- * to the hwgroup by sleeping for timeout jiffies.
- */
-void ide_stall_queue (ide_drive_t *drive, unsigned long timeout)
-{
-	if (timeout > WAIT_WORSTCASE)
-		timeout = WAIT_WORSTCASE;
-	drive->sleep = timeout + jiffies;
-}
-
-#define WAKEUP(drive)	((drive)->service_start + 2 * (drive)->service_time)
-
-/*
- * choose_drive() selects the next drive which will be serviced.
- */
-static inline ide_drive_t *choose_drive (ide_hwgroup_t *hwgroup)
-{
-	ide_drive_t *drive, *best;
-
-repeat:	
-	best = NULL;
-	drive = hwgroup->drive;
-	do {
-		if (!list_empty(&drive->queue.queue_head) && (!drive->sleep || 0 <= (signed long)(jiffies - drive->sleep))) {
-			if (!best
-			 || (drive->sleep && (!best->sleep || 0 < (signed long)(best->sleep - drive->sleep)))
-			 || (!best->sleep && 0 < (signed long)(WAKEUP(best) - WAKEUP(drive))))
-			{
-				if( !drive->queue.plugged )
-					best = drive;
-			}
-		}
-	} while ((drive = drive->next) != hwgroup->drive);
-	if (best && best->nice1 && !best->sleep && best != hwgroup->drive && best->service_time > WAIT_MIN_SLEEP) {
-		long t = (signed long)(WAKEUP(best) - jiffies);
-		if (t >= WAIT_MIN_SLEEP) {
-			/*
-			 * We *may* have some time to spare, but first let's see if
-			 * someone can potentially benefit from our nice mood today..
-			 */
-			drive = best->next;
-			do {
-				if (!drive->sleep
-				 && 0 < (signed long)(WAKEUP(drive) - (jiffies - best->service_time))
-				 && 0 < (signed long)((jiffies + t) - WAKEUP(drive)))
-				{
-					ide_stall_queue(best, IDE_MIN(t, 10 * WAIT_MIN_SLEEP));
-					goto repeat;
-				}
-			} while ((drive = drive->next) != best);
-		}
-	}
-	return best;
-}
-
-/*
- * Issue a new request to a drive from hwgroup
- * Caller must have already done spin_lock_irqsave(&io_request_lock, ..);
- *
- * A hwgroup is a serialized group of IDE interfaces.  Usually there is
- * exactly one hwif (interface) per hwgroup, but buggy controllers (eg. CMD640)
- * may have both interfaces in a single hwgroup to "serialize" access.
- * Or possibly multiple ISA interfaces can share a common IRQ by being grouped
- * together into one hwgroup for serialized access.
- *
- * Note also that several hwgroups can end up sharing a single IRQ,
- * possibly along with many other devices.  This is especially common in
- * PCI-based systems with off-board IDE controller cards.
- *
- * The IDE driver uses the single global io_request_lock spinlock to protect
- * access to the request queues, and to protect the hwgroup->busy flag.
- *
- * The first thread into the driver for a particular hwgroup sets the
- * hwgroup->busy flag to indicate that this hwgroup is now active,
- * and then initiates processing of the top request from the request queue.
- *
- * Other threads attempting entry notice the busy setting, and will simply
- * queue their new requests and exit immediately.  Note that hwgroup->busy
- * remains set even when the driver is merely awaiting the next interrupt.
- * Thus, the meaning is "this hwgroup is busy processing a request".
- *
- * When processing of a request completes, the completing thread or IRQ-handler
- * will start the next request from the queue.  If no more work remains,
- * the driver will clear the hwgroup->busy flag and exit.
- *
- * The io_request_lock (spinlock) is used to protect all access to the
- * hwgroup->busy flag, but is otherwise not needed for most processing in
- * the driver.  This makes the driver much more friendlier to shared IRQs
- * than previous designs, while remaining 100% (?) SMP safe and capable.
- */
-/* --BenH: made non-static as ide-pmac.c uses it to kick the hwgroup back
- *         into life on wakeup from machine sleep.
- */ 
-void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
-{
-	ide_drive_t	*drive;
-	ide_hwif_t	*hwif;
-	struct request	*rq;
-	ide_startstop_t	startstop;
-
-	ide_get_lock(&ide_lock, ide_intr, hwgroup);	/* for atari only: POSSIBLY BROKEN HERE(?) */
-
-	__cli();	/* necessary paranoia: ensure IRQs are masked on local CPU */
-
-	while (!hwgroup->busy) {
-		hwgroup->busy = 1;
-		drive = choose_drive(hwgroup);
-		if (drive == NULL) {
-			unsigned long sleep = 0;
-			hwgroup->rq = NULL;
-			drive = hwgroup->drive;
-			do {
-				if (drive->sleep && (!sleep || 0 < (signed long)(sleep - drive->sleep)))
-					sleep = drive->sleep;
-			} while ((drive = drive->next) != hwgroup->drive);
-			if (sleep) {
-				/*
-				 * Take a short snooze, and then wake up this hwgroup again.
-				 * This gives other hwgroups on the same a chance to
-				 * play fairly with us, just in case there are big differences
-				 * in relative throughputs.. don't want to hog the cpu too much.
-				 */
-				if (0 < (signed long)(jiffies + WAIT_MIN_SLEEP - sleep)) 
-					sleep = jiffies + WAIT_MIN_SLEEP;
-#if 1
-				if (timer_pending(&hwgroup->timer))
-					printk("ide_set_handler: timer already active\n");
-#endif
-				hwgroup->sleeping = 1;	/* so that ide_timer_expiry knows what to do */
-				mod_timer(&hwgroup->timer, sleep);
-				/* we purposely leave hwgroup->busy==1 while sleeping */
-			} else {
-				/* Ugly, but how can we sleep for the lock otherwise? perhaps from tq_disk? */
-				ide_release_lock(&ide_lock);	/* for atari only */
-				hwgroup->busy = 0;
-			}
-			return;		/* no more work for this hwgroup (for now) */
-		}
-		hwif = HWIF(drive);
-		if (hwgroup->hwif->sharing_irq && hwif != hwgroup->hwif && hwif->io_ports[IDE_CONTROL_OFFSET]) {
-			/* set nIEN for previous hwif */
-			SELECT_INTERRUPT(hwif, drive);
-		}
-		hwgroup->hwif = hwif;
-		hwgroup->drive = drive;
-		drive->sleep = 0;
-		drive->service_start = jiffies;
-
-		if ( drive->queue.plugged )	/* paranoia */
-			printk("%s: Huh? nuking plugged queue\n", drive->name);
-
-		rq = hwgroup->rq = blkdev_entry_next_request(&drive->queue.queue_head);
-		/*
-		 * Some systems have trouble with IDE IRQs arriving while
-		 * the driver is still setting things up.  So, here we disable
-		 * the IRQ used by this interface while the request is being started.
-		 * This may look bad at first, but pretty much the same thing
-		 * happens anyway when any interrupt comes in, IDE or otherwise
-		 *  -- the kernel masks the IRQ while it is being handled.
-		 */
-		if (masked_irq && hwif->irq != masked_irq)
-			disable_irq_nosync(hwif->irq);
-		spin_unlock(&io_request_lock);
-		ide__sti();	/* allow other IRQs while we start this request */
-		startstop = start_request(drive, rq);
-		spin_lock_irq(&io_request_lock);
-		if (masked_irq && hwif->irq != masked_irq)
-			enable_irq(hwif->irq);
-		if (startstop == ide_stopped)
-			hwgroup->busy = 0;
-	}
-}
-
-/*
- * ide_get_queue() returns the queue which corresponds to a given device.
- */
-request_queue_t *ide_get_queue (kdev_t dev)
-{
-	ide_hwif_t *hwif = (ide_hwif_t *)blk_dev[MAJOR(dev)].data;
-
-	return &hwif->drives[DEVICE_NR(dev) & 1].queue;
-}
-
-/*
- * Passes the stuff to ide_do_request
- */
-void do_ide_request(request_queue_t *q)
-{
-	ide_do_request(q->queuedata, 0);
-}
-
-/*
- * un-busy the hwgroup etc, and clear any pending DMA status. we want to
- * retry the current request in pio mode instead of risking tossing it
- * all away
- */
-void ide_dma_timeout_retry(ide_drive_t *drive)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	struct request *rq;
-
-	/*
-	 * end current dma transaction
-	 */
-	(void) hwif->dmaproc(ide_dma_end, drive);
-
-	/*
-	 * complain a little, later we might remove some of this verbosity
-	 */
-	printk("%s: timeout waiting for DMA\n", drive->name);
-	(void) hwif->dmaproc(ide_dma_timeout, drive);
-
-	/*
-	 * disable dma for now, but remember that we did so because of
-	 * a timeout -- we'll reenable after we finish this next request
-	 * (or rather the first chunk of it) in pio.
-	 */
-	drive->retry_pio++;
-	drive->state = DMA_PIO_RETRY;
-	(void) hwif->dmaproc(ide_dma_off_quietly, drive);
-
-	/*
-	 * un-busy drive etc (hwgroup->busy is cleared on return) and
-	 * make sure request is sane
-	 */
-	rq = HWGROUP(drive)->rq;
-	HWGROUP(drive)->rq = NULL;
-
-	rq->errors = 0;
-	rq->sector = rq->bh->b_rsector;
-	rq->current_nr_sectors = rq->bh->b_size >> 9;
-	rq->buffer = rq->bh->b_data;
-}
-
-/*
- * ide_timer_expiry() is our timeout function for all drive operations.
- * But note that it can also be invoked as a result of a "sleep" operation
- * triggered by the mod_timer() call in ide_do_request.
- */
-void ide_timer_expiry (unsigned long data)
-{
-	ide_hwgroup_t	*hwgroup = (ide_hwgroup_t *) data;
-	ide_handler_t	*handler;
-	ide_expiry_t	*expiry;
- 	unsigned long	flags;
-	unsigned long	wait;
-
-	spin_lock_irqsave(&io_request_lock, flags);
-	del_timer(&hwgroup->timer);
-
-	if ((handler = hwgroup->handler) == NULL) {
-		/*
-		 * Either a marginal timeout occurred
-		 * (got the interrupt just as timer expired),
-		 * or we were "sleeping" to give other devices a chance.
-		 * Either way, we don't really want to complain about anything.
-		 */
-		if (hwgroup->sleeping) {
-			hwgroup->sleeping = 0;
-			hwgroup->busy = 0;
-		}
-	} else {
-		ide_drive_t *drive = hwgroup->drive;
-		if (!drive) {
-			printk("ide_timer_expiry: hwgroup->drive was NULL\n");
-			hwgroup->handler = NULL;
-		} else {
-			ide_hwif_t *hwif;
-			ide_startstop_t startstop;
-			if (!hwgroup->busy) {
-				hwgroup->busy = 1;	/* paranoia */
-				printk("%s: ide_timer_expiry: hwgroup->busy was 0 ??\n", drive->name);
-			}
-			if ((expiry = hwgroup->expiry) != NULL) {
-				/* continue */
-				if ((wait = expiry(drive)) != 0) {
-					/* reset timer */
-					hwgroup->timer.expires  = jiffies + wait;
-					add_timer(&hwgroup->timer);
-					spin_unlock_irqrestore(&io_request_lock, flags);
-					return;
-				}
-			}
-			hwgroup->handler = NULL;
-			/*
-			 * We need to simulate a real interrupt when invoking
-			 * the handler() function, which means we need to globally
-			 * mask the specific IRQ:
-			 */
-			spin_unlock(&io_request_lock);
-			hwif  = HWIF(drive);
-#if DISABLE_IRQ_NOSYNC
-			disable_irq_nosync(hwif->irq);
-#else
-			disable_irq(hwif->irq);	/* disable_irq_nosync ?? */
-#endif /* DISABLE_IRQ_NOSYNC */
-			__cli();	/* local CPU only, as if we were handling an interrupt */
-			if (hwgroup->poll_timeout != 0) {
-				startstop = handler(drive);
-			} else if (drive_is_ready(drive)) {
-				if (drive->waiting_for_dma)
-					(void) hwgroup->hwif->dmaproc(ide_dma_lostirq, drive);
-				(void)ide_ack_intr(hwif);
-				printk("%s: lost interrupt\n", drive->name);
-				startstop = handler(drive);
-			} else {
-				if (drive->waiting_for_dma) {
-					startstop = ide_stopped;
-					ide_dma_timeout_retry(drive);
-				} else
-					startstop = ide_error(drive, "irq timeout", GET_STAT());
-			}
-			set_recovery_timer(hwif);
-			drive->service_time = jiffies - drive->service_start;
-			enable_irq(hwif->irq);
-			spin_lock_irq(&io_request_lock);
-			if (startstop == ide_stopped)
-				hwgroup->busy = 0;
-		}
-	}
-	ide_do_request(hwgroup, 0);
-	spin_unlock_irqrestore(&io_request_lock, flags);
-}
-
-/*
- * There's nothing really useful we can do with an unexpected interrupt,
- * other than reading the status register (to clear it), and logging it.
- * There should be no way that an irq can happen before we're ready for it,
- * so we needn't worry much about losing an "important" interrupt here.
- *
- * On laptops (and "green" PCs), an unexpected interrupt occurs whenever the
- * drive enters "idle", "standby", or "sleep" mode, so if the status looks
- * "good", we just ignore the interrupt completely.
- *
- * This routine assumes __cli() is in effect when called.
- *
- * If an unexpected interrupt happens on irq15 while we are handling irq14
- * and if the two interfaces are "serialized" (CMD640), then it looks like
- * we could screw up by interfering with a new request being set up for irq15.
- *
- * In reality, this is a non-issue.  The new command is not sent unless the
- * drive is ready to accept one, in which case we know the drive is not
- * trying to interrupt us.  And ide_set_handler() is always invoked before
- * completing the issuance of any new drive command, so we will not be
- * accidentally invoked as a result of any valid command completion interrupt.
- *
- */
-static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup)
-{
-	byte stat;
-	ide_hwif_t *hwif = hwgroup->hwif;
-
-	/*
-	 * handle the unexpected interrupt
-	 */
-	do {
-		if (hwif->irq == irq) {
-			stat = IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);
-			if (!OK_STAT(stat, READY_STAT, BAD_STAT)) {
-				/* Try to not flood the console with msgs */
-				static unsigned long last_msgtime, count;
-				++count;
-				if (0 < (signed long)(jiffies - (last_msgtime + HZ))) {
-					last_msgtime = jiffies;
-					printk("%s%s: unexpected interrupt, status=0x%02x, count=%ld\n",
-					 hwif->name, (hwif->next == hwgroup->hwif) ? "" : "(?)", stat, count);
-				}
-			}
-		}
-	} while ((hwif = hwif->next) != hwgroup->hwif);
-}
-
-/*
- * entry point for all interrupts, caller does __cli() for us
+ * of the kernel (such as memory allocation) to be functioning yet.
+ *
+ * This is too bad, as otherwise we could dynamically allocate the
+ * ide_drive_t structs as needed, rather than always consuming memory
+ * for the max possible number (MAX_HWIFS * MAX_DRIVES) of them.
+ *
+ * FIXME: We should stuff the setup data into __init and copy the
+ * relevant hwifs/allocate them properly during boot.
  */
-void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
+#define MAGIC_COOKIE 0x12345678
+static void __init init_ide_data (void)
 {
-	unsigned long flags;
-	ide_hwgroup_t *hwgroup = (ide_hwgroup_t *)dev_id;
-	ide_hwif_t *hwif;
-	ide_drive_t *drive;
-	ide_handler_t *handler;
-	ide_startstop_t startstop;
+	unsigned int index;
+	static unsigned long magic_cookie = MAGIC_COOKIE;
 
-	spin_lock_irqsave(&io_request_lock, flags);
-	hwif = hwgroup->hwif;
+	if (magic_cookie != MAGIC_COOKIE)
+		return;		/* already initialized */
+	magic_cookie = 0;
 
-	if (!ide_ack_intr(hwif)) {
-		spin_unlock_irqrestore(&io_request_lock, flags);
-		return;
-	}
+	/* Initialise all interface structures */
+	for (index = 0; index < MAX_HWIFS; ++index)
+		init_hwif_data(index);
 
-	if ((handler = hwgroup->handler) == NULL || hwgroup->poll_timeout != 0) {
-		/*
-		 * Not expecting an interrupt from this drive.
-		 * That means this could be:
-		 *	(1) an interrupt from another PCI device
-		 *	sharing the same PCI INT# as us.
-		 * or	(2) a drive just entered sleep or standby mode,
-		 *	and is interrupting to let us know.
-		 * or	(3) a spurious interrupt of unknown origin.
-		 *
-		 * For PCI, we cannot tell the difference,
-		 * so in that case we just ignore it and hope it goes away.
-		 */
-#ifdef CONFIG_BLK_DEV_IDEPCI
-		if (IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL))
-#endif	/* CONFIG_BLK_DEV_IDEPCI */
-		{
-			/*
-			 * Probably not a shared PCI interrupt,
-			 * so we can safely try to do something about it:
-			 */
-			unexpected_intr(irq, hwgroup);
-#ifdef CONFIG_BLK_DEV_IDEPCI
-		} else {
-			/*
-			 * Whack the status register, just in case we have a leftover pending IRQ.
-			 */
-			(void) IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);
-#endif /* CONFIG_BLK_DEV_IDEPCI */
-		}
-		spin_unlock_irqrestore(&io_request_lock, flags);
-		return;
-	}
-	drive = hwgroup->drive;
-	if (!drive) {
-		/*
-		 * This should NEVER happen, and there isn't much we could do about it here.
-		 */
-		spin_unlock_irqrestore(&io_request_lock, flags);
-		return;
-	}
-	if (!drive_is_ready(drive)) {
-		/*
-		 * This happens regularly when we share a PCI IRQ with another device.
-		 * Unfortunately, it can also happen with some buggy drives that trigger
-		 * the IRQ before their status register is up to date.  Hopefully we have
-		 * enough advance overhead that the latter isn't a problem.
-		 */
-		spin_unlock_irqrestore(&io_request_lock, flags);
-		return;
-	}
-	if (!hwgroup->busy) {
-		hwgroup->busy = 1;	/* paranoia */
-		printk("%s: ide_intr: hwgroup->busy was 0 ??\n", drive->name);
-	}
-	hwgroup->handler = NULL;
-	del_timer(&hwgroup->timer);
-	spin_unlock(&io_request_lock);
-
-	if (drive->unmask)
-		ide__sti();	/* local CPU only */
-	startstop = handler(drive);		/* service this interrupt, may set handler for next interrupt */
-	spin_lock_irq(&io_request_lock);
+	/* Add default hw interfaces */
+	ide_init_default_hwifs();
 
-	/*
-	 * Note that handler() may have set things up for another
-	 * interrupt to occur soon, but it cannot happen until
-	 * we exit from this routine, because it will be the
-	 * same irq as is currently being serviced here, and Linux
-	 * won't allow another of the same (on any CPU) until we return.
-	 */
-	set_recovery_timer(HWIF(drive));
-	drive->service_time = jiffies - drive->service_start;
-	if (startstop == ide_stopped) {
-		if (hwgroup->handler == NULL) {	/* paranoia */
-			hwgroup->busy = 0;
-			ide_do_request(hwgroup, hwif->irq);
-		} else {
-			printk("%s: ide_intr: huh? expected NULL handler on exit\n", drive->name);
-		}
-	}
-	spin_unlock_irqrestore(&io_request_lock, flags);
+	idebus_parameter = 0;
+	system_bus_speed = 0;
 }
 
 /*
- * get_info_ptr() returns the (ide_drive_t *) for a given device number.
- * It returns NULL if the given device number does not match any present drives.
+ * ide_system_bus_speed() returns what we think is the system VESA/PCI
+ * bus speed (in MHz).  This is used for calculating interface PIO timings.
+ * The default is 40 for known PCI systems, 50 otherwise.
+ * The "idebus=xx" parameter can be used to override this value.
+ * The actual value to be used is computed/displayed the first time through.
  */
-ide_drive_t *get_info_ptr (kdev_t i_rdev)
+int ide_system_bus_speed (void)
 {
-	int		major = MAJOR(i_rdev);
-#if 0
-	int		minor = MINOR(i_rdev) & PARTN_MASK;
-#endif
-	unsigned int	h;
-
-	for (h = 0; h < MAX_HWIFS; ++h) {
-		ide_hwif_t  *hwif = &ide_hwifs[h];
-		if (hwif->present && major == hwif->major) {
-			unsigned unit = DEVICE_NR(i_rdev);
-			if (unit < MAX_DRIVES) {
-				ide_drive_t *drive = &hwif->drives[unit];
-#if 0
-				if ((drive->present) && (drive->part[minor].nr_sects))
-#else
-				if (drive->present)
-#endif
-					return drive;
-			}
-			break;
+	if (!system_bus_speed) {
+		if (idebus_parameter) {
+			/* user supplied value */
+			system_bus_speed = idebus_parameter;
+		} else if (pci_present()) {
+			/* safe default value for PCI */
+			system_bus_speed = 33;
+		} else {
+			/* safe default value for VESA and PCI */
+			system_bus_speed = 50;
 		}
+		printk(KERN_INFO "ide: Assuming %dMHz system bus speed "
+			"for PIO modes%s\n", system_bus_speed,
+			idebus_parameter ? "" : "; override with idebus=xx");
 	}
-	return NULL;
+	return system_bus_speed;
 }
 
 /*
- * This function is intended to be used prior to invoking ide_do_drive_cmd().
+ * current_capacity() returns the capacity (in sectors) of a drive
+ * according to its current geometry/LBA settings.
  */
-void ide_init_drive_cmd (struct request *rq)
+unsigned long current_capacity (ide_drive_t *drive)
+{
+	if (!drive->present)
+		return 0;
+	if (drive->driver != NULL)
+		return DRIVER(drive)->capacity(drive);
+	return 0;
+}
+
+EXPORT_SYMBOL(current_capacity);
+
+static inline u32 read_24 (ide_drive_t *drive)
 {
-	memset(rq, 0, sizeof(*rq));
-	rq->cmd = IDE_DRIVE_CMD;
+	return  (HWIF(drive)->INB(IDE_HCYL_REG)<<16) |
+		(HWIF(drive)->INB(IDE_LCYL_REG)<<8) |
+		 HWIF(drive)->INB(IDE_SECTOR_REG);
 }
 
 /*
- * This function issues a special IDE device request
- * onto the request queue.
- *
- * If action is ide_wait, then the rq is queued at the end of the
- * request queue, and the function sleeps until it has been processed.
- * This is for use when invoked from an ioctl handler.
- *
- * If action is ide_preempt, then the rq is queued at the head of
- * the request queue, displacing the currently-being-processed
- * request and this function returns immediately without waiting
- * for the new rq to be completed.  This is VERY DANGEROUS, and is
- * intended for careful use by the ATAPI tape/cdrom driver code.
- *
- * If action is ide_next, then the rq is queued immediately after
- * the currently-being-processed-request (if any), and the function
- * returns without waiting for the new rq to be completed.  As above,
- * This is VERY DANGEROUS, and is intended for careful use by the
- * ATAPI tape/cdrom driver code.
- *
- * If action is ide_end, then the rq is queued at the end of the
- * request queue, and the function returns immediately without waiting
- * for the new rq to be completed. This is again intended for careful
- * use by the ATAPI tape/cdrom driver code.
+ * Error reporting, in human readable form (luxurious, but a memory hog).
  */
-int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action)
+u8 ide_dump_status (ide_drive_t *drive, const char *msg, u8 stat)
 {
+	ide_hwif_t *hwif = HWIF(drive);
 	unsigned long flags;
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	unsigned int major = HWIF(drive)->major;
-	struct list_head *queue_head = &drive->queue.queue_head;
-	DECLARE_COMPLETION(wait);
+	u8 err = 0;
 
-#ifdef CONFIG_BLK_DEV_PDC4030
-	if (HWIF(drive)->chipset == ide_pdc4030 && rq->buffer != NULL)
-		return -ENOSYS;  /* special drive cmds not supported */
-#endif
-	rq->errors = 0;
-	rq->rq_status = RQ_ACTIVE;
-	rq->rq_dev = MKDEV(major,(drive->select.b.unit)<<PARTN_BITS);
-	if (action == ide_wait)
-		rq->waiting = &wait;
-	spin_lock_irqsave(&io_request_lock, flags);
-	if (list_empty(queue_head) || action == ide_preempt) {
-		if (action == ide_preempt)
-			hwgroup->rq = NULL;
+	local_irq_set(flags);
+	printk(KERN_WARNING "%s: %s: status=0x%02x", drive->name, msg, stat);
+#if FANCY_STATUS_DUMPS
+	printk(" { ");
+	if (stat & BUSY_STAT) {
+		printk("Busy ");
 	} else {
-		if (action == ide_wait || action == ide_end) {
-			queue_head = queue_head->prev;
-		} else
-			queue_head = queue_head->next;
-	}
-	list_add(&rq->queue, queue_head);
-	ide_do_request(hwgroup, 0);
-	spin_unlock_irqrestore(&io_request_lock, flags);
-	if (action == ide_wait) {
-		wait_for_completion(&wait);	/* wait for it to be serviced */
-		return rq->errors ? -EIO : 0;	/* return -EIO if errors */
+		if (stat & READY_STAT)	printk("DriveReady ");
+		if (stat & WRERR_STAT)	printk("DeviceFault ");
+		if (stat & SEEK_STAT)	printk("SeekComplete ");
+		if (stat & DRQ_STAT)	printk("DataRequest ");
+		if (stat & ECC_STAT)	printk("CorrectedError ");
+		if (stat & INDEX_STAT)	printk("Index ");
+		if (stat & ERR_STAT)	printk("Error ");
 	}
-	return 0;
+	printk("}");
+#endif	/* FANCY_STATUS_DUMPS */
+	printk("\n");
+	if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
+		err = hwif->INB(IDE_ERROR_REG);
+		printk("%s: %s: error=0x%02x", drive->name, msg, err);
+#if FANCY_STATUS_DUMPS
+		if (drive->media == ide_disk) {
+			printk(" { ");
+			if (err & ABRT_ERR)	printk("DriveStatusError ");
+			if (err & ICRC_ERR)	printk("Bad%s ", (err & ABRT_ERR) ? "CRC" : "Sector");
+			if (err & ECC_ERR)	printk("UncorrectableError ");
+			if (err & ID_ERR)	printk("SectorIdNotFound ");
+			if (err & TRK0_ERR)	printk("TrackZeroNotFound ");
+			if (err & MARK_ERR)	printk("AddrMarkNotFound ");
+			printk("}");
+			if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR || (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
+				if ((drive->id->command_set_2 & 0x0400) &&
+				    (drive->id->cfs_enable_2 & 0x0400) &&
+				    (drive->addressing == 1)) {
+					u64 sectors = 0;
+					u32 high = 0;
+					u32 low = read_24(drive);
+					hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG);
+					high = read_24(drive);
 
+					sectors = ((u64)high << 24) | low;
+					printk(", LBAsect=%llu, high=%d, low=%d",
+					       (u64) sectors,
+					       high, low);
+				} else {
+					u8 cur = hwif->INB(IDE_SELECT_REG);
+					if (cur & 0x40) {	/* using LBA? */
+						printk(", LBAsect=%ld", (unsigned long)
+						 ((cur&0xf)<<24)
+						 |(hwif->INB(IDE_HCYL_REG)<<16)
+						 |(hwif->INB(IDE_LCYL_REG)<<8)
+						 | hwif->INB(IDE_SECTOR_REG));
+					} else {
+						printk(", CHS=%d/%d/%d",
+						 (hwif->INB(IDE_HCYL_REG)<<8) +
+						  hwif->INB(IDE_LCYL_REG),
+						  cur & 0xf,
+						  hwif->INB(IDE_SECTOR_REG));
+					}
+				}
+				if (HWGROUP(drive) && HWGROUP(drive)->rq)
+					printk(", sector=%ld", HWGROUP(drive)->rq->sector);
+			}
+		}
+#endif	/* FANCY_STATUS_DUMPS */
+		printk("\n");
+	}
+	local_irq_restore(flags);
+	return err;
 }
 
+EXPORT_SYMBOL(ide_dump_status);
+
+
 /*
  * This routine is called to flush all partitions and partition tables
  * for a changed disk, and then re-read the new partition table.
@@ -2049,7 +486,7 @@
 		drive->part[p].nr_sects   = 0;
 	};
 
-	if (DRIVER(drive)->revalidate)
+	if (DRIVER(drive) && DRIVER(drive)->revalidate)
 		DRIVER(drive)->revalidate(drive);
 
 	drive->busy = 0;
@@ -2058,7 +495,9 @@
 	return 0;
 }
 
-static void revalidate_drives (void)
+EXPORT_SYMBOL(ide_revalidate_disk);
+
+static void revalidate_drives (int revaldiate)
 {
 	ide_hwif_t *hwif;
 	ide_drive_t *drive;
@@ -2070,26 +509,28 @@
 			drive = &ide_hwifs[index].drives[unit];
 			if (drive->revalidate) {
 				drive->revalidate = 0;
-				if (!initializing)
+				if ((!initializing) && (revaldiate))
 					(void) ide_revalidate_disk(MKDEV(hwif->major, unit<<PARTN_BITS));
 			}
 		}
 	}
 }
 
-static void ide_probe_module (void)
+void ide_probe_module (int revaldiate)
 {
 	if (!ide_probe) {
-#if defined(CONFIG_KMOD) && defined(CONFIG_BLK_DEV_IDE_MODULE)
+#if  defined(CONFIG_BLK_DEV_IDE_MODULE)
 		(void) request_module("ide-probe-mod");
-#endif /* (CONFIG_KMOD) && (CONFIG_BLK_DEV_IDE_MODULE) */
+#endif
 	} else {
 		(void) ide_probe->init();
 	}
-	revalidate_drives();
+	revalidate_drives(revaldiate);
 }
 
-static void ide_driver_module (void)
+EXPORT_SYMBOL(ide_probe_module);
+
+void ide_driver_module (int revaldiate)
 {
 	int index;
 	ide_module_t *module = ide_modules;
@@ -2097,15 +538,17 @@
 	for (index = 0; index < MAX_HWIFS; ++index)
 		if (ide_hwifs[index].present)
 			goto search;
-	ide_probe_module();
+	ide_probe_module(revaldiate);
 search:
 	while (module) {
 		(void) module->init();
 		module = module->next;
 	}
-	revalidate_drives();
+	revalidate_drives(revaldiate);
 }
 
+EXPORT_SYMBOL(ide_driver_module);
+
 static int ide_open (struct inode * inode, struct file * filp)
 {
 	ide_drive_t *drive;
@@ -2113,29 +556,28 @@
 	if ((drive = get_info_ptr(inode->i_rdev)) == NULL)
 		return -ENXIO;
 	if (drive->driver == NULL)
-		ide_driver_module();
-#ifdef CONFIG_KMOD
+		ide_driver_module(1);
 	if (drive->driver == NULL) {
 		if (drive->media == ide_disk)
 			(void) request_module("ide-disk");
+		if (drive->scsi)
+			(void) request_module("ide-scsi");
 		if (drive->media == ide_cdrom)
 			(void) request_module("ide-cd");
 		if (drive->media == ide_tape)
 			(void) request_module("ide-tape");
 		if (drive->media == ide_floppy)
 			(void) request_module("ide-floppy");
-#if defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI)
-		if (drive->media == ide_scsi)
-			(void) request_module("ide-scsi");
-#endif /* defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI) */
 	}
-#endif /* CONFIG_KMOD */
+	
+	/* The locking here isnt enough, but this is hard to fix
+	   in the 2.4 cases */
 	while (drive->busy)
 		sleep_on(&drive->wqueue);
 	drive->usage++;
-	if (drive->driver != NULL)
+	if (drive->driver != NULL && !drive->dead)
 		return DRIVER(drive)->open(inode, filp, drive);
-	printk ("%s: driver not present\n", drive->name);
+	printk(KERN_WARNING "%s: driver not present\n", drive->name);
 	drive->usage--;
 	return -ENXIO;
 }
@@ -2156,22 +598,6 @@
 	return 0;
 }
 
-int ide_replace_subdriver (ide_drive_t *drive, const char *driver)
-{
-	if (!drive->present || drive->busy || drive->usage)
-		goto abort;
-	if (drive->driver != NULL && DRIVER(drive)->cleanup(drive))
-		goto abort;
-	strncpy(drive->driver_req, driver, 9);
-	ide_driver_module();
-	drive->driver_req[0] = 0;
-	ide_driver_module();
-	if (DRIVER(drive) && !strcmp(DRIVER(drive)->name, driver))
-		return 0;
-abort:
-	return 1;
-}
-
 #ifdef CONFIG_PROC_FS
 ide_proc_entry_t generic_subdriver_entries[] = {
 	{ "capacity",	S_IFREG|S_IRUGO,	proc_ide_read_capacity,	NULL },
@@ -2179,6 +605,10 @@
 };
 #endif
 
+
+#define hwif_release_region(addr, num) \
+	((hwif->mmio) ? release_mem_region((addr),(num)) : release_region((addr),(num)))
+
 /*
  * Note that we only release the standard ports,
  * and do not even try to handle any extra ports
@@ -2186,36 +616,33 @@
  */
 void hwif_unregister (ide_hwif_t *hwif)
 {
-	if (hwif->straight8) {
-		ide_release_region(hwif->io_ports[IDE_DATA_OFFSET], 8);
-		goto jump_eight;
-	}
-	if (hwif->io_ports[IDE_DATA_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_DATA_OFFSET], 1);
-	if (hwif->io_ports[IDE_ERROR_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_ERROR_OFFSET], 1);
-	if (hwif->io_ports[IDE_NSECTOR_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_NSECTOR_OFFSET], 1);
-	if (hwif->io_ports[IDE_SECTOR_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_SECTOR_OFFSET], 1);
-	if (hwif->io_ports[IDE_LCYL_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_LCYL_OFFSET], 1);
-	if (hwif->io_ports[IDE_HCYL_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_HCYL_OFFSET], 1);
-	if (hwif->io_ports[IDE_SELECT_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_SELECT_OFFSET], 1);
-	if (hwif->io_ports[IDE_STATUS_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_STATUS_OFFSET], 1);
-jump_eight:
+	u32 i = 0;
+
+	if (hwif->mmio == 2)
+		return;
 	if (hwif->io_ports[IDE_CONTROL_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1);
+		hwif_release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1);
 #if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
 	if (hwif->io_ports[IDE_IRQ_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_IRQ_OFFSET], 1);
+		hwif_release_region(hwif->io_ports[IDE_IRQ_OFFSET], 1);
 #endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */
+
+	if (hwif->straight8) {
+		hwif_release_region(hwif->io_ports[IDE_DATA_OFFSET], 8);
+		return;
+	}
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+		if (hwif->io_ports[i]) {
+			hwif_release_region(hwif->io_ports[i], 1);
+		}
+	}
 }
 
-void ide_unregister (unsigned int index)
+EXPORT_SYMBOL(hwif_unregister);
+
+extern void init_hwif_data(unsigned int index);
+
+int ide_unregister (unsigned int index)
 {
 	struct gendisk *gd;
 	ide_drive_t *drive, *d;
@@ -2227,9 +654,9 @@
 	ide_hwif_t old_hwif;
 
 	if (index >= MAX_HWIFS)
-		return;
-	save_flags(flags);	/* all CPUs */
-	cli();			/* all CPUs */
+		BUG();
+		
+	spin_lock_irqsave(&io_request_lock, flags);
 	hwif = &ide_hwifs[index];
 	if (!hwif->present)
 		goto abort;
@@ -2239,7 +666,7 @@
 			continue;
 		if (drive->busy || drive->usage)
 			goto abort;
-		if (drive->driver != NULL && DRIVER(drive)->cleanup(drive))
+		if (drive->driver != NULL && DRIVER(drive)->shutdown(drive))
 			goto abort;
 	}
 	hwif->present = 0;
@@ -2247,11 +674,13 @@
 	/*
 	 * All clear?  Then blow away the buffer cache
 	 */
-	sti();
+	spin_unlock_irqrestore(&io_request_lock, flags);
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
 		drive = &hwif->drives[unit];
 		if (!drive->present)
 			continue;
+		if (drive->driver != NULL)
+			DRIVER(drive)->cleanup(drive);
 		minor = drive->select.b.unit << PARTN_BITS;
 		for (p = 0; p < (1<<PARTN_BITS); ++p) {
 			if (drive->part[p].nr_sects > 0) {
@@ -2263,7 +692,8 @@
 		destroy_proc_ide_drives(hwif);
 #endif
 	}
-	cli();
+
+	spin_lock_irqsave(&io_request_lock, flags);
 	hwgroup = hwif->hwgroup;
 
 	/*
@@ -2293,7 +723,7 @@
 	for (i = 0; i < MAX_DRIVES; ++i) {
 		drive = &hwif->drives[i];
 		if (drive->de) {
-			devfs_unregister (drive->de);
+			devfs_unregister(drive->de);
 			drive->de = NULL;
 		}
 		if (!drive->present)
@@ -2320,12 +750,19 @@
 	else
 		hwgroup->hwif = HWIF(hwgroup->drive);
 
-#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
+#if !defined(CONFIG_DMA_NONPCI)
 	if (hwif->dma_base) {
 		(void) ide_release_dma(hwif);
+
 		hwif->dma_base = 0;
+		hwif->dma_master = 0;
+		hwif->dma_command = 0;
+		hwif->dma_vendor1 = 0;
+		hwif->dma_status = 0;
+		hwif->dma_vendor3 = 0;
+		hwif->dma_prdtable = 0;
 	}
-#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
+#endif /* !(CONFIG_DMA_NONPCI) */
 
 	/*
 	 * Remove us from the kernel's knowledge
@@ -2343,49 +780,137 @@
 		kfree(gd->sizes);
 		kfree(gd->part);
 		if (gd->de_arr)
-			kfree (gd->de_arr);
+			kfree(gd->de_arr);
 		if (gd->flags)
-			kfree (gd->flags);
+			kfree(gd->flags);
 		kfree(gd);
 		hwif->gd = NULL;
 	}
-	old_hwif		= *hwif;
-	init_hwif_data (index);	/* restore hwif data to pristine status */
-	hwif->hwgroup		= old_hwif.hwgroup;
-	hwif->tuneproc		= old_hwif.tuneproc;
-	hwif->speedproc		= old_hwif.speedproc;
-	hwif->selectproc	= old_hwif.selectproc;
-	hwif->resetproc		= old_hwif.resetproc;
-	hwif->intrproc		= old_hwif.intrproc;
-	hwif->maskproc		= old_hwif.maskproc;
-	hwif->quirkproc		= old_hwif.quirkproc;
-	hwif->rwproc		= old_hwif.rwproc;
-	hwif->ideproc		= old_hwif.ideproc;
-	hwif->dmaproc		= old_hwif.dmaproc;
-	hwif->busproc		= old_hwif.busproc;
-	hwif->bus_state		= old_hwif.bus_state;
-	hwif->dma_base		= old_hwif.dma_base;
-	hwif->dma_extra		= old_hwif.dma_extra;
-	hwif->config_data	= old_hwif.config_data;
-	hwif->select_data	= old_hwif.select_data;
-	hwif->proc		= old_hwif.proc;
-#ifndef CONFIG_BLK_DEV_IDECS
-	hwif->irq		= old_hwif.irq;
-#endif /* CONFIG_BLK_DEV_IDECS */
-	hwif->major		= old_hwif.major;
-	hwif->chipset		= old_hwif.chipset;
-	hwif->autodma		= old_hwif.autodma;
-	hwif->udma_four		= old_hwif.udma_four;
+
+	old_hwif			= *hwif;
+	init_hwif_data(index);	/* restore hwif data to pristine status */
+	hwif->hwgroup			= old_hwif.hwgroup;
+
+	hwif->proc			= old_hwif.proc;
+
+	hwif->major			= old_hwif.major;
+//	hwif->index			= old_hwif.index;
+//	hwif->channel			= old_hwif.channel;
+	hwif->straight8			= old_hwif.straight8;
+	hwif->bus_state			= old_hwif.bus_state;
+
+	hwif->atapi_dma			= old_hwif.atapi_dma;
+	hwif->ultra_mask		= old_hwif.ultra_mask;
+	hwif->mwdma_mask		= old_hwif.mwdma_mask;
+	hwif->swdma_mask		= old_hwif.swdma_mask;
+
+	hwif->chipset			= old_hwif.chipset;
+
 #ifdef CONFIG_BLK_DEV_IDEPCI
-	hwif->pci_dev		= old_hwif.pci_dev;
-	hwif->pci_devid		= old_hwif.pci_devid;
+	hwif->pci_dev			= old_hwif.pci_dev;
+	hwif->cds			= old_hwif.cds;
 #endif /* CONFIG_BLK_DEV_IDEPCI */
-	hwif->straight8		= old_hwif.straight8;
-	hwif->hwif_data		= old_hwif.hwif_data;
+
+#if 0
+	hwif->hwifops			= old_hwif.hwifops;
+#else
+	hwif->identify			= old_hwif.identify;
+	hwif->tuneproc			= old_hwif.tuneproc;
+	hwif->speedproc			= old_hwif.speedproc;
+	hwif->selectproc		= old_hwif.selectproc;
+	hwif->reset_poll		= old_hwif.reset_poll;
+	hwif->pre_reset			= old_hwif.pre_reset;
+	hwif->resetproc			= old_hwif.resetproc;
+	hwif->intrproc			= old_hwif.intrproc;
+	hwif->maskproc			= old_hwif.maskproc;
+	hwif->quirkproc			= old_hwif.quirkproc;
+	hwif->busproc			= old_hwif.busproc;
+#endif
+
+#if 0
+	hwif->pioops			= old_hwif.pioops;
+#else
+	hwif->ata_input_data		= old_hwif.ata_input_data;
+	hwif->ata_output_data		= old_hwif.ata_output_data;
+	hwif->atapi_input_bytes		= old_hwif.atapi_input_bytes;
+	hwif->atapi_output_bytes	= old_hwif.atapi_output_bytes;
+#endif
+
+#if 0
+	hwif->dmaops			= old_hwif.dmaops;
+#else
+	hwif->ide_dma_read		= old_hwif.ide_dma_read;
+	hwif->ide_dma_write		= old_hwif.ide_dma_write;
+	hwif->ide_dma_begin		= old_hwif.ide_dma_begin;
+	hwif->ide_dma_end		= old_hwif.ide_dma_end;
+	hwif->ide_dma_check		= old_hwif.ide_dma_check;
+	hwif->ide_dma_on		= old_hwif.ide_dma_on;
+	hwif->ide_dma_off		= old_hwif.ide_dma_off;
+	hwif->ide_dma_off_quietly	= old_hwif.ide_dma_off_quietly;
+	hwif->ide_dma_test_irq		= old_hwif.ide_dma_test_irq;
+	hwif->ide_dma_host_on		= old_hwif.ide_dma_host_on;
+	hwif->ide_dma_host_off		= old_hwif.ide_dma_host_off;
+	hwif->ide_dma_bad_drive		= old_hwif.ide_dma_bad_drive;
+	hwif->ide_dma_good_drive	= old_hwif.ide_dma_good_drive;
+	hwif->ide_dma_count		= old_hwif.ide_dma_count;
+	hwif->ide_dma_verbose		= old_hwif.ide_dma_verbose;
+	hwif->ide_dma_retune		= old_hwif.ide_dma_retune;
+	hwif->ide_dma_lostirq		= old_hwif.ide_dma_lostirq;
+	hwif->ide_dma_timeout		= old_hwif.ide_dma_timeout;
+#endif
+
+#if 0
+	hwif->iops			= old_hwif.iops;
+#else
+	hwif->OUTB		= old_hwif.OUTB;
+	hwif->OUTBSYNC		= old_hwif.OUTBSYNC;
+	hwif->OUTW		= old_hwif.OUTW;
+	hwif->OUTL		= old_hwif.OUTL;
+	hwif->OUTSW		= old_hwif.OUTSW;
+	hwif->OUTSL		= old_hwif.OUTSL;
+
+	hwif->INB		= old_hwif.INB;
+	hwif->INW		= old_hwif.INW;
+	hwif->INL		= old_hwif.INL;
+	hwif->INSW		= old_hwif.INSW;
+	hwif->INSL		= old_hwif.INSL;
+#endif
+
+	hwif->mmio			= old_hwif.mmio;
+	hwif->rqsize			= old_hwif.rqsize;
+	hwif->addressing		= old_hwif.addressing;
+#ifndef CONFIG_BLK_DEV_IDECS
+	hwif->irq			= old_hwif.irq;
+#endif /* CONFIG_BLK_DEV_IDECS */
+	hwif->initializing		= old_hwif.initializing;
+
+	hwif->dma_base			= old_hwif.dma_base;
+	hwif->dma_master		= old_hwif.dma_master;
+	hwif->dma_command		= old_hwif.dma_command;
+	hwif->dma_vendor1		= old_hwif.dma_vendor1;
+	hwif->dma_status		= old_hwif.dma_status;
+	hwif->dma_vendor3		= old_hwif.dma_vendor3;
+	hwif->dma_prdtable		= old_hwif.dma_prdtable;
+
+	hwif->dma_extra			= old_hwif.dma_extra;
+	hwif->config_data		= old_hwif.config_data;
+	hwif->select_data		= old_hwif.select_data;
+	hwif->autodma			= old_hwif.autodma;
+	hwif->udma_four			= old_hwif.udma_four;
+	hwif->no_dsc			= old_hwif.no_dsc;
+
+	hwif->hwif_data			= old_hwif.hwif_data;
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	return 0;
+
 abort:
-	restore_flags(flags);	/* all CPUs */
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	return 1;
+	
 }
 
+EXPORT_SYMBOL(ide_unregister);
+
 /*
  * Setup hw_regs_t structure described by parameters.  You
  * may set up the hw structure yourself OR use this routine to
@@ -2394,7 +919,11 @@
 void ide_setup_ports (	hw_regs_t *hw,
 			ide_ioreg_t base, int *offsets,
 			ide_ioreg_t ctrl, ide_ioreg_t intr,
-			ide_ack_intr_t *ack_intr, int irq)
+			ide_ack_intr_t *ack_intr,
+/*
+ *			ide_io_ops_t *iops,
+ */
+			int irq)
 {
 	int i;
 
@@ -2420,8 +949,13 @@
 	hw->irq = irq;
 	hw->dma = NO_DMA;
 	hw->ack_intr = ack_intr;
+/*
+ *	hw->iops = iops;
+ */
 }
 
+EXPORT_SYMBOL(ide_setup_ports);
+
 /*
  * Register an IDE interface, specifing exactly the registers etc
  * Set init=1 iff calling before probes have taken place.
@@ -2459,11 +993,11 @@
 	hwif->chipset = hw->chipset;
 
 	if (!initializing) {
-		ide_probe_module();
+		ide_probe_module(1);
 #ifdef CONFIG_PROC_FS
 		create_proc_ide_interfaces();
 #endif
-		ide_driver_module();
+		ide_driver_module(1);
 	}
 
 	if (hwifp)
@@ -2472,6 +1006,8 @@
 	return (initializing || hwif->present) ? index : -1;
 }
 
+EXPORT_SYMBOL(ide_register_hw);
+
 /*
  * Compatability function with existing drivers.  If you want
  * something different, use the function above.
@@ -2484,6 +1020,8 @@
 	return ide_register_hw(&hw, NULL);
 }
 
+EXPORT_SYMBOL(ide_register);
+
 void ide_add_setting (ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set)
 {
 	ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL;
@@ -2495,12 +1033,18 @@
 	memset(setting, 0, sizeof(*setting));
 	if ((setting->name = kmalloc(strlen(name) + 1, GFP_KERNEL)) == NULL)
 		goto abort;
-	strcpy(setting->name, name);		setting->rw = rw;
-	setting->read_ioctl = read_ioctl;	setting->write_ioctl = write_ioctl;
-	setting->data_type = data_type;		setting->min = min;
-	setting->max = max;			setting->mul_factor = mul_factor;
-	setting->div_factor = div_factor;	setting->data = data;
-	setting->set = set;			setting->next = *p;
+	strcpy(setting->name, name);
+	setting->rw = rw;
+	setting->read_ioctl = read_ioctl;
+	setting->write_ioctl = write_ioctl;
+	setting->data_type = data_type;
+	setting->min = min;
+	setting->max = max;
+	setting->mul_factor = mul_factor;
+	setting->div_factor = div_factor;
+	setting->data = data;
+	setting->set = set;
+	setting->next = *p;
 	if (drive->driver)
 		setting->auto_remove = 1;
 	*p = setting;
@@ -2510,6 +1054,8 @@
 		kfree(setting);
 }
 
+EXPORT_SYMBOL(ide_add_setting);
+
 void ide_remove_setting (ide_drive_t *drive, char *name)
 {
 	ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting;
@@ -2523,6 +1069,8 @@
 	kfree(setting);
 }
 
+EXPORT_SYMBOL(ide_remove_setting);
+
 static ide_settings_t *ide_find_setting_by_ioctl (ide_drive_t *drive, int cmd)
 {
 	ide_settings_t *setting = drive->settings;
@@ -2595,19 +1143,20 @@
 	while (hwgroup->busy) {
 		unsigned long lflags;
 		spin_unlock_irq(&io_request_lock);
-		__save_flags(lflags);	/* local CPU only */
-		__sti();		/* local CPU only; needed for jiffies */
-		if (0 < (signed long)(jiffies - timeout)) {
-			__restore_flags(lflags);	/* local CPU only */
-			printk("%s: channel busy\n", drive->name);
+		local_irq_set(lflags);
+		if (time_after(jiffies, timeout)) {
+			local_irq_restore(lflags);
+			printk(KERN_ERR "%s: channel busy\n", drive->name);
 			return -EBUSY;
 		}
-		__restore_flags(lflags);	/* local CPU only */
+		local_irq_restore(lflags);
 		spin_lock_irq(&io_request_lock);
 	}
 	return 0;
 }
 
+EXPORT_SYMBOL(ide_spin_wait_hwgroup);
+
 /*
  * FIXME:  This should be changed to enqueue a special request
  * to the driver to change settings, and then wait on a sema for completion.
@@ -2648,6 +1197,8 @@
 	return 0;
 }
 
+EXPORT_SYMBOL(ide_write_setting);
+
 static int set_io_32bit(ide_drive_t *drive, int arg)
 {
 	drive->io_32bit = arg;
@@ -2662,10 +1213,15 @@
 {
 	if (!drive->driver || !DRIVER(drive)->supports_dma)
 		return -EPERM;
-	if (!drive->id || !(drive->id->capability & 1) || !HWIF(drive)->dmaproc)
+	if (!drive->id || !(drive->id->capability & 1))
 		return -EPERM;
-	if (HWIF(drive)->dmaproc(arg ? ide_dma_on : ide_dma_off, drive))
-		return -EIO;
+	if (HWIF(drive)->ide_dma_check == NULL)
+		return -EPERM;
+	if (arg) {
+		if (HWIF(drive)->ide_dma_on(drive)) return -EIO;
+	} else {
+		if (HWIF(drive)->ide_dma_off(drive)) return -EIO;
+	}
 	return 0;
 }
 
@@ -2678,9 +1234,39 @@
 	if (drive->special.b.set_tune)
 		return -EBUSY;
 	ide_init_drive_cmd(&rq);
-	drive->tune_req = (byte) arg;
+	drive->tune_req = (u8) arg;
 	drive->special.b.set_tune = 1;
-	(void) ide_do_drive_cmd (drive, &rq, ide_wait);
+	(void) ide_do_drive_cmd(drive, &rq, ide_wait);
+	return 0;
+}
+
+static int set_xfer_rate (ide_drive_t *drive, int arg)
+{
+	int err = ide_wait_cmd(drive,
+			WIN_SETFEATURES, (u8) arg,
+			SETFEATURES_XFER, 0, NULL);
+
+	if (!err && arg) {
+		ide_set_xfer_rate(drive, (u8) arg);
+		ide_driveid_update(drive);
+	}
+	return err;
+}
+
+int ide_atapi_to_scsi (ide_drive_t *drive, int arg)
+{
+	if (drive->media == ide_disk) {
+		drive->scsi = 0;
+		return 0;
+	}
+	if (drive->driver != NULL) {
+		if (DRIVER(drive)->cleanup(drive)) {
+			drive->scsi = 0;
+			return 0;
+		}
+	}
+	drive->scsi = (u8) arg;
+	ide_attach_drive(drive);
 	return 0;
 }
 
@@ -2696,37 +1282,11 @@
 	ide_add_setting(drive,	"slow",			SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	1,				1,		1,		&drive->slow,			NULL);
 	ide_add_setting(drive,	"unmaskirq",		drive->no_unmask ? SETTING_READ : SETTING_RW,	HDIO_GET_UNMASKINTR,	HDIO_SET_UNMASKINTR,	TYPE_BYTE,	0,	1,				1,		1,		&drive->unmask,			NULL);
 	ide_add_setting(drive,	"using_dma",		SETTING_RW,					HDIO_GET_DMA,		HDIO_SET_DMA,		TYPE_BYTE,	0,	1,				1,		1,		&drive->using_dma,		set_using_dma);
-	ide_add_setting(drive,	"ide_scsi",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	1,				1,		1,		&drive->scsi,			NULL);
-	ide_add_setting(drive,	"init_speed",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	69,				1,		1,		&drive->init_speed,		NULL);
-	ide_add_setting(drive,	"current_speed",	SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	69,				1,		1,		&drive->current_speed,		NULL);
+	ide_add_setting(drive,	"init_speed",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	70,				1,		1,		&drive->init_speed,		NULL);
+	ide_add_setting(drive,	"current_speed",	SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	70,				1,		1,		&drive->current_speed,		set_xfer_rate);
 	ide_add_setting(drive,	"number",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	3,				1,		1,		&drive->dn,			NULL);
-}
-
-int ide_wait_cmd (ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *buf)
-{
-	struct request rq;
-	byte buffer[4];
-
-	if (!buf)
-		buf = buffer;
-	memset(buf, 0, 4 + SECTOR_WORDS * 4 * sectors);
-	ide_init_drive_cmd(&rq);
-	rq.buffer = buf;
-	*buf++ = cmd;
-	*buf++ = nsect;
-	*buf++ = feature;
-	*buf++ = sectors;
-	return ide_do_drive_cmd(drive, &rq, ide_wait);
-}
-
-int ide_wait_cmd_task (ide_drive_t *drive, byte *buf)
-{
-	struct request rq;
-
-	ide_init_drive_cmd(&rq);
-	rq.cmd = IDE_DRIVE_TASK;
-	rq.buffer = buf;
-	return ide_do_drive_cmd(drive, &rq, ide_wait);
+	if (drive->media != ide_disk)
+		ide_add_setting(drive,	"ide-scsi",		SETTING_RW,					-1,		HDIO_SET_IDE_SCSI,		TYPE_BYTE,	0,	1,				1,		1,		&drive->scsi,			ide_atapi_to_scsi);
 }
 
 /*
@@ -2747,19 +1307,53 @@
 #endif /* CONFIG_BLK_DEV_IDECS */
 }
 
+EXPORT_SYMBOL(ide_delay_50ms);
+
 int system_bus_clock (void)
 {
 	return((int) ((!system_bus_speed) ? ide_system_bus_speed() : system_bus_speed ));
 }
 
-int ide_reinit_drive (ide_drive_t *drive)
+EXPORT_SYMBOL(system_bus_clock);
+
+int ide_replace_subdriver (ide_drive_t *drive, const char *driver)
+{
+	if (!drive->present || drive->busy || drive->usage || drive->dead)
+		goto abort;
+	if (drive->driver != NULL && DRIVER(drive)->cleanup(drive))
+		goto abort;
+	strncpy(drive->driver_req, driver, 9);
+	ide_driver_module(0);
+	drive->driver_req[0] = 0;
+	ide_driver_module(0);
+	if (DRIVER(drive) && !strcmp(DRIVER(drive)->name, driver))
+		return 0;
+abort:
+	return 1;
+}
+
+EXPORT_SYMBOL(ide_replace_subdriver);
+
+int ide_attach_drive (ide_drive_t *drive)
 {
+	/* Someone unplugged the device on us */
+	if(drive->dead)
+		return 1;
+		
+#ifdef CONFIG_BLK_DEV_IDESCSI
+	if (drive->scsi) {
+		extern int idescsi_attach(ide_drive_t *drive);
+		if (idescsi_attach(drive))
+			return 0;
+	}
+#endif /* CONFIG_BLK_DEV_IDESCSI */
+
 	switch (drive->media) {
 #ifdef CONFIG_BLK_DEV_IDECD
 		case ide_cdrom:
 		{
-			extern int ide_cdrom_reinit(ide_drive_t *drive);
-			if (ide_cdrom_reinit(drive))
+			extern int ide_cdrom_attach(ide_drive_t *drive);
+			if (ide_cdrom_attach(drive))
 				return 1;
 			break;
 		}
@@ -2767,8 +1361,8 @@
 #ifdef CONFIG_BLK_DEV_IDEDISK
 		case ide_disk:
 		{
-			extern int idedisk_reinit(ide_drive_t *drive);
-			if (idedisk_reinit(drive))
+			extern int idedisk_attach(ide_drive_t *drive);
+			if (idedisk_attach(drive))
 				return 1;
 			break;
 		}
@@ -2776,8 +1370,8 @@
 #ifdef CONFIG_BLK_DEV_IDEFLOPPY
 		case ide_floppy:
 		{
-			extern int idefloppy_reinit(ide_drive_t *drive);
-			if (idefloppy_reinit(drive))
+			extern int idefloppy_attach(ide_drive_t *drive);
+			if (idefloppy_attach(drive))
 				return 1;
 			break;
 		}
@@ -2785,28 +1379,20 @@
 #ifdef CONFIG_BLK_DEV_IDETAPE
 		case ide_tape:
 		{
-			extern int idetape_reinit(ide_drive_t *drive);
-			if (idetape_reinit(drive))
+			extern int idetape_attach(ide_drive_t *drive);
+			if (idetape_attach(drive))
 				return 1;
 			break;
 		}
 #endif /* CONFIG_BLK_DEV_IDETAPE */
-#ifdef CONFIG_BLK_DEV_IDESCSI
-/*
- *              {
- *                      extern int idescsi_reinit(ide_drive_t *drive);
- *                      if (idescsi_reinit(drive))
- *                              return 1;
- *                      break;
- * }
- */
-#endif /* CONFIG_BLK_DEV_IDESCSI */
 		default:
 			return 1;
 	}
 	return 0;
 }
 
+EXPORT_SYMBOL(ide_attach_drive);
+
 static int ide_ioctl (struct inode *inode, struct file *file,
 			unsigned int cmd, unsigned long arg)
 {
@@ -2838,11 +1424,11 @@
 		case HDIO_GETGEO:
 		{
 			struct hd_geometry *loc = (struct hd_geometry *) arg;
-			unsigned short bios_cyl = drive->bios_cyl; /* truncate */
+			u16 bios_cyl = drive->bios_cyl; /* truncate */
 			if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL;
-			if (put_user(drive->bios_head, (byte *) &loc->heads)) return -EFAULT;
-			if (put_user(drive->bios_sect, (byte *) &loc->sectors)) return -EFAULT;
-			if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT;
+			if (put_user(drive->bios_head, (u8 *) &loc->heads)) return -EFAULT;
+			if (put_user(drive->bios_sect, (u8 *) &loc->sectors)) return -EFAULT;
+			if (put_user(bios_cyl, (u16 *) &loc->cylinders)) return -EFAULT;
 			if (put_user((unsigned)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect,
 				(unsigned long *) &loc->start)) return -EFAULT;
 			return 0;
@@ -2852,8 +1438,8 @@
 		{
 			struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
 			if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL;
-			if (put_user(drive->bios_head, (byte *) &loc->heads)) return -EFAULT;
-			if (put_user(drive->bios_sect, (byte *) &loc->sectors)) return -EFAULT;
+			if (put_user(drive->bios_head, (u8 *) &loc->heads)) return -EFAULT;
+			if (put_user(drive->bios_sect, (u8 *) &loc->sectors)) return -EFAULT;
 			if (put_user(drive->bios_cyl, (unsigned int *) &loc->cylinders)) return -EFAULT;
 			if (put_user((unsigned)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect,
 				(unsigned long *) &loc->start)) return -EFAULT;
@@ -2864,8 +1450,8 @@
 		{
 			struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
 			if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL;
-			if (put_user(drive->head, (byte *) &loc->heads)) return -EFAULT;
-			if (put_user(drive->sect, (byte *) &loc->sectors)) return -EFAULT;
+			if (put_user(drive->head, (u8 *) &loc->heads)) return -EFAULT;
+			if (put_user(drive->sect, (u8 *) &loc->sectors)) return -EFAULT;
 			if (put_user(drive->cyl, (unsigned int *) &loc->cylinders)) return -EFAULT;
 			if (put_user((unsigned)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect,
 				(unsigned long *) &loc->start)) return -EFAULT;
@@ -2918,68 +1504,15 @@
 #endif /* CONFIG_IDE_TASK_IOCTL */
 
 		case HDIO_DRIVE_CMD:
-		{
-			byte args[4], *argbuf = args;
-			byte xfer_rate = 0;
-			int argsize = 4;
-			ide_task_t tfargs;
-
 			if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
 				return -EACCES;
-			if (NULL == (void *) arg)
-				return ide_do_drive_cmd(drive, &rq, ide_wait);
-			if (copy_from_user(args, (void *)arg, 4))
-				return -EFAULT;
-
-			tfargs.tfRegister[IDE_FEATURE_OFFSET] = args[2];
-			tfargs.tfRegister[IDE_NSECTOR_OFFSET] = args[3];
-			tfargs.tfRegister[IDE_SECTOR_OFFSET]  = args[1];
-			tfargs.tfRegister[IDE_LCYL_OFFSET]    = 0x00;
-			tfargs.tfRegister[IDE_HCYL_OFFSET]    = 0x00;
-			tfargs.tfRegister[IDE_SELECT_OFFSET]  = 0x00;
-			tfargs.tfRegister[IDE_COMMAND_OFFSET] = args[0];
-
-			if (args[3]) {
-				argsize = 4 + (SECTOR_WORDS * 4 * args[3]);
-				argbuf = kmalloc(argsize, GFP_KERNEL);
-				if (argbuf == NULL)
-					return -ENOMEM;
-				memcpy(argbuf, args, 4);
-			}
-
-			if (set_transfer(drive, &tfargs)) {
-				xfer_rate = args[1];
-				if (ide_ata66_check(drive, &tfargs))
-					goto abort;
-			}
-
-			err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf);
+			return ide_cmd_ioctl(drive, inode, file, cmd, arg);
 
-			if (!err && xfer_rate) {
-				/* active-retuning-calls future */
-				if ((HWIF(drive)->speedproc) != NULL)
-					HWIF(drive)->speedproc(drive, xfer_rate);
-				ide_driveid_update(drive);
-			}
-		abort:
-			if (copy_to_user((void *)arg, argbuf, argsize))
-				err = -EFAULT;
-			if (argsize > 4)
-				kfree(argbuf);
-			return err;
-		}
 		case HDIO_DRIVE_TASK:
-		{
-			byte args[7], *argbuf = args;
-			int argsize = 7;
-			if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) return -EACCES;
-			if (copy_from_user(args, (void *)arg, 7))
-				return -EFAULT;
-			err = ide_wait_cmd_task(drive, argbuf);
-			if (copy_to_user((void *)arg, argbuf, argsize))
-				err = -EFAULT;
-			return err;
-		}
+			if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+				return -EACCES;
+			return ide_task_ioctl(drive, inode, file, cmd, arg);
+
 		case HDIO_SCAN_HWIF:
 		{
 			int args[3];
@@ -3011,18 +1544,15 @@
 		case HDIO_DRIVE_RESET:
 		{
 			unsigned long flags;
-			ide_hwgroup_t *hwgroup = HWGROUP(drive);
-
 			if (!capable(CAP_SYS_ADMIN)) return -EACCES;
 #if 1
 			spin_lock_irqsave(&io_request_lock, flags);
-			if (hwgroup->handler != NULL) {
-				printk("%s: ide_set_handler: handler not null; %p\n", drive->name, hwgroup->handler);
-				(void) hwgroup->handler(drive);
-//				hwgroup->handler = NULL;
-//				hwgroup->expiry	= NULL;
-				hwgroup->timer.expires = jiffies + 0;;
-				del_timer(&hwgroup->timer);
+			if ( HWGROUP(drive)->handler != NULL) {
+				printk(KERN_ERR "%s: ide_set_handler: handler not null; %p\n", drive->name, HWGROUP(drive)->handler);
+				(void) HWGROUP(drive)->handler(drive);
+//				HWGROUP(drive)->handler = NULL;
+				HWGROUP(drive)->expiry	= NULL;
+				del_timer(&HWGROUP(drive)->timer);
 			}
 			spin_unlock_irqrestore(&io_request_lock, flags);
 
@@ -3085,33 +1615,6 @@
 	return 0;
 }
 
-void ide_fixstring (byte *s, const int bytecount, const int byteswap)
-{
-	byte *p = s, *end = &s[bytecount & ~1]; /* bytecount must be even */
-
-	if (byteswap) {
-		/* convert from big-endian to host byte order */
-		for (p = end ; p != s;) {
-			unsigned short *pp = (unsigned short *) (p -= 2);
-			*pp = ntohs(*pp);
-		}
-	}
-
-	/* strip leading blanks */
-	while (s != end && *s == ' ')
-		++s;
-
-	/* compress internal blanks and strip trailing blanks */
-	while (s != end && *s) {
-		if (*s++ != ' ' || (s != end && *s && *s != ' '))
-			*p++ = *(s-1);
-	}
-
-	/* wipe out trailing garbage */
-	while (p != end)
-		*p++ = '\0';
-}
-
 /*
  * stridx() returns the offset of c within s,
  * or -1 if c is '\0' or not found within s.
@@ -3274,7 +1777,7 @@
 	    strncmp(s,"hd",2))		/* hdx= & hdxlun= */
 		return 0;
 
-	printk("ide_setup: %s", s);
+	printk(KERN_INFO "ide_setup: %s", s);
 	init_ide_data ();
 
 #ifdef CONFIG_BLK_DEV_IDEDOUBLER
@@ -3288,7 +1791,7 @@
 #endif /* CONFIG_BLK_DEV_IDEDOUBLER */
 
 	if (!strcmp(s, "ide=nodma")) {
-		printk("IDE: Prevented DMA\n");
+		printk(" : Prevented DMA\n");
 		noautodma = 1;
 		return 1;
 	}
@@ -3418,7 +1921,7 @@
 		const char *ide_words[] = {
 			"noprobe", "serialize", "autotune", "noautotune", "reset", "dma", "ata66",
 			"minus8", "minus9", "minus10",
-			"four", "qd65xx", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", "nohighio", NULL };
+			"four", "qd65xx", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", NULL };
 		hw = s[3] - '0';
 		hwif = &ide_hwifs[hw];
 		i = match_parm(&s[4], ide_words, vals, 3);
@@ -3437,10 +1940,6 @@
 		}
 
 		switch (i) {
-			case -19: /* nohighio */
-				hwif->no_highio = 1;
-				printk("%s: disabled high i/o capability\n", hwif->name);
-				goto done;
 #ifdef CONFIG_BLK_DEV_PDC4030
 			case -18: /* "dc4030" */
 			{
@@ -3580,21 +2079,12 @@
  */
 static void __init probe_for_hwifs (void)
 {
-#ifdef CONFIG_PCI
+#ifdef CONFIG_BLK_DEV_IDEPCI
 	if (pci_present())
 	{
-#ifdef CONFIG_BLK_DEV_IDEPCI
 		ide_scan_pcibus(ide_scan_direction);
-#else
-#ifdef CONFIG_BLK_DEV_RZ1000
-		{
-			extern void ide_probe_for_rz100x(void);
-			ide_probe_for_rz100x();
-		}
-#endif /* CONFIG_BLK_DEV_RZ1000 */
-#endif /* CONFIG_BLK_DEV_IDEPCI */
 	}
-#endif /* CONFIG_PCI */
+#endif /* CONFIG_BLK_DEV_IDEPCI */
 
 #ifdef CONFIG_ETRAX_IDE
 	{
@@ -3676,39 +2166,8 @@
 #endif /* CONFIG_BLK_DEV_ISAPNP */
 }
 
-void __init ide_init_builtin_drivers (void)
+void __init ide_init_builtin_subdrivers (void)
 {
-	/*
-	 * Probe for special PCI and other "known" interface chipsets
-	 */
-	probe_for_hwifs ();
-
-#ifdef CONFIG_BLK_DEV_IDE
-#if defined(__mc68000__) || defined(CONFIG_APUS)
-	if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) {
-		ide_get_lock(&ide_lock, NULL, NULL);	/* for atari only */
-		disable_irq(ide_hwifs[0].irq);	/* disable_irq_nosync ?? */
-//		disable_irq_nosync(ide_hwifs[0].irq);
-	}
-#endif /* __mc68000__ || CONFIG_APUS */
-
-	(void) ideprobe_init();
-
-#if defined(__mc68000__) || defined(CONFIG_APUS)
-	if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) {
-		enable_irq(ide_hwifs[0].irq);
-		ide_release_lock(&ide_lock);	/* for atari only */
-	}
-#endif /* __mc68000__ || CONFIG_APUS */
-#endif /* CONFIG_BLK_DEV_IDE */
-
-#ifdef CONFIG_PROC_FS
-	proc_ide_create();
-#endif
-
-	/*
-	 * Attempt to match drivers for the available drives
-	 */
 #ifdef CONFIG_BLK_DEV_IDEDISK
 	(void) idedisk_init();
 #endif /* CONFIG_BLK_DEV_IDEDISK */
@@ -3730,32 +2189,131 @@
 #endif /* CONFIG_BLK_DEV_IDESCSI */
 }
 
+#ifndef CLASSIC_BUILTINS_METHOD
+#  ifndef DIRECT_HWIF_PROBE_ATTACH_METHOD
+#    ifdef FAKE_CLASSIC_ATTACH_METHOD
+/*
+ * Attempt to match drivers for the available drives
+ */
+void ide_attach_devices (void)
+{
+	ide_hwif_t *hwif;
+	ide_drive_t *drive;
+	int i, unit;
+
+	for (i = 0; i < MAX_HWIFS; i++) {
+		hwif = &ide_hwifs[i];
+		if (!hwif->present)
+			continue;
+		for (unit = 0; unit < MAX_DRIVES; ++unit) {
+			drive = &hwif->drives[unit];
+			if (drive->present && !drive->dead)
+				ide_attach_drive(drive);
+		}
+	}
+}
+#    endif /* FAKE_CLASSIC_ATTACH_METHOD */
+#  endif /* DIRECT_HWIF_PROBE_ATTACH_METHOD */
+#endif /* CLASSIC_BUILTINS_METHOD */
+
+void __init ide_init_builtin_drivers (void)
+{
+	/*
+	 * Probe for special PCI and other "known" interface chipsets
+	 */
+	probe_for_hwifs ();
+
+#ifdef CONFIG_BLK_DEV_IDE
+	if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET])
+		ide_get_lock(&ide_intr_lock, NULL, NULL); /* for atari only */
+
+	(void) ideprobe_init();
+
+	if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET])
+		ide_release_lock(&ide_intr_lock);	/* for atari only */
+#endif /* CONFIG_BLK_DEV_IDE */
+
+#ifdef CONFIG_PROC_FS
+	proc_ide_create();
+#endif
+
+#ifdef CLASSIC_BUILTINS_METHOD
+	ide_init_builtin_subdrivers();
+#else /* ! CLASSIC_BUILTINS_METHOD */
+#  ifndef DIRECT_HWIF_PROBE_ATTACH_METHOD
+#    ifdef FAKE_CLASSIC_ATTACH_METHOD
+	ide_attach_devices();
+#    endif /* FAKE_CLASSIC_ATTACH_METHOD */
+#  endif /* DIRECT_HWIF_PROBE_ATTACH_METHOD */
+#endif /* CLASSIC_BUILTINS_METHOD */
+}
+
+/*
+ *	Actually unregister the subdriver. Called with the
+ *	request lock dropped.
+ */
+ 
 static int default_cleanup (ide_drive_t *drive)
 {
 	return ide_unregister_subdriver(drive);
 }
 
+/*
+ *	Check if we can unregister the subdriver. Called with the
+ *	request lock held.
+ */
+ 
+static int default_shutdown(ide_drive_t *drive)
+{
+	if (drive->usage || drive->busy ||
+	    drive->driver == NULL || DRIVER(drive)->busy) {
+		return 1;
+	}
+	drive->dead = 1;
+	return 0;
+}
+
 static int default_standby (ide_drive_t *drive)
 {
 	return 0;
 }
 
+static int default_suspend (ide_drive_t *drive)
+{
+	return 0;
+}
+
+static int default_resume (ide_drive_t *drive)
+{
+	return 0;
+}
+
 static int default_flushcache (ide_drive_t *drive)
 {
 	return 0;
 }
 
-static ide_startstop_t default_do_request(ide_drive_t *drive, struct request *rq, unsigned long block)
+static ide_startstop_t default_do_request (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
-	ide_end_request(0, HWGROUP(drive));
+	ide_end_request(drive, 0);
 	return ide_stopped;
 }
- 
-static void default_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
+
+static int default_end_request (ide_drive_t *drive, int uptodate)
 {
-	ide_end_request(uptodate, hwgroup);
+	return ide_end_request(drive, uptodate);
 }
-  
+
+static u8 default_sense (ide_drive_t *drive, const char *msg, u8 stat)
+{
+	return ide_dump_status(drive, msg, stat);
+}
+
+static ide_startstop_t default_error (ide_drive_t *drive, const char *msg, u8 stat)
+{
+	return ide_error(drive, msg, stat);
+}
+
 static int default_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file,
 			  unsigned int cmd, unsigned long arg)
 {
@@ -3795,9 +2353,15 @@
 	return ide_stopped;
 }
 
-static int default_reinit (ide_drive_t *drive)
+static int default_init (void)
+{
+	return 0;
+}
+
+static int default_attach (ide_drive_t *drive)
 {
-	printk(KERN_ERR "%s: does not support hotswap of device class !\n", drive->name);
+	printk(KERN_ERR "%s: does not support hotswap of device class !\n",
+		drive->name);
 
 	return 0;
 }
@@ -3807,10 +2371,15 @@
 	ide_driver_t *d = drive->driver;
 
 	if (d->cleanup == NULL)		d->cleanup = default_cleanup;
+	if (d->shutdown == NULL)	d->shutdown = default_shutdown;
 	if (d->standby == NULL)		d->standby = default_standby;
+	if (d->suspend == NULL)		d->suspend = default_suspend;
+	if (d->resume == NULL)		d->resume = default_resume;
 	if (d->flushcache == NULL)	d->flushcache = default_flushcache;
 	if (d->do_request == NULL)	d->do_request = default_do_request;
 	if (d->end_request == NULL)	d->end_request = default_end_request;
+	if (d->sense == NULL)		d->sense = default_sense;
+	if (d->error == NULL)		d->error = default_error;
 	if (d->ioctl == NULL)		d->ioctl = default_ioctl;
 	if (d->open == NULL)		d->open = default_open;
 	if (d->release == NULL)		d->release = default_release;
@@ -3818,10 +2387,11 @@
 	if (d->pre_reset == NULL)	d->pre_reset = default_pre_reset;
 	if (d->capacity == NULL)	d->capacity = default_capacity;
 	if (d->special == NULL)		d->special = default_special;
-	if (d->reinit == NULL)		d->reinit = default_reinit;
+	if (d->init == NULL)		d->init = default_init;
+	if (d->attach == NULL)		d->attach = default_attach;
 }
 
-ide_drive_t *ide_scan_devices (byte media, const char *name, ide_driver_t *driver, int n)
+ide_drive_t *ide_scan_devices (u8 media, const char *name, ide_driver_t *driver, int n)
 {
 	unsigned int unit, index, i;
 
@@ -3834,37 +2404,34 @@
 			char *req = drive->driver_req;
 			if (*req && !strstr(name, req))
 				continue;
-			if (drive->present && drive->media == media && drive->driver == driver && ++i > n)
+			if (drive->present && drive->media == media &&
+			    drive->driver == driver && ++i > n)
 				return drive;
 		}
 	}
 	return NULL;
 }
 
+EXPORT_SYMBOL(ide_scan_devices);
+
 int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int version)
 {
 	unsigned long flags;
 	
-	save_flags(flags);		/* all CPUs */
-	cli();				/* all CPUs */
-	if (version != IDE_SUBDRIVER_VERSION || !drive->present || drive->driver != NULL || drive->busy || drive->usage) {
-		restore_flags(flags);	/* all CPUs */
+	spin_lock_irqsave(&io_request_lock, flags);
+	if (version != IDE_SUBDRIVER_VERSION || !drive->present ||
+	    drive->driver != NULL || drive->busy || drive->usage) {
+		spin_unlock_irqrestore(&io_request_lock, flags);
 		return 1;
 	}
 	drive->driver = driver;
 	setup_driver_defaults(drive);
-	restore_flags(flags);		/* all CPUs */
+	spin_unlock_irqrestore(&io_request_lock, flags);
 	if (drive->autotune != 2) {
-		if (driver->supports_dma && HWIF(drive)->dmaproc != NULL) {
-			/*
-			 * Force DMAing for the beginning of the check.
-			 * Some chipsets appear to do interesting things,
-			 * if not checked and cleared.
-			 *   PARANOIA!!!
-			 */
-			(void) (HWIF(drive)->dmaproc(ide_dma_off_quietly, drive));
-			(void) (HWIF(drive)->dmaproc(ide_dma_check, drive));
-		}
+		/* DMA timings and setup moved to ide-probe.c */
+		if (!driver->supports_dma && HWIF(drive)->ide_dma_off_quietly)
+//			HWIF(drive)->ide_dma_off_quietly(drive);
+			HWIF(drive)->ide_dma_off(drive);
 		drive->dsc_overlap = (drive->next != drive && driver->supports_dsc_overlap);
 		drive->nice1 = 1;
 	}
@@ -3877,14 +2444,16 @@
 	return 0;
 }
 
+EXPORT_SYMBOL(ide_register_subdriver);
+
 int ide_unregister_subdriver (ide_drive_t *drive)
 {
 	unsigned long flags;
 	
-	save_flags(flags);		/* all CPUs */
-	cli();				/* all CPUs */
-	if (drive->usage || drive->busy || drive->driver == NULL || DRIVER(drive)->busy) {
-		restore_flags(flags);	/* all CPUs */
+	spin_lock_irqsave(&io_request_lock, flags);
+	if (drive->usage || drive->busy ||
+	    drive->driver == NULL || DRIVER(drive)->busy) {
+		spin_unlock_irqrestore(&io_request_lock, flags);
 		return 1;
 	}
 #if defined(CONFIG_BLK_DEV_ISAPNP) && defined(CONFIG_ISAPNP) && defined(MODULE)
@@ -3896,10 +2465,12 @@
 #endif
 	auto_remove_settings(drive);
 	drive->driver = NULL;
-	restore_flags(flags);		/* all CPUs */
+	spin_unlock_irqrestore(&io_request_lock, flags);
 	return 0;
 }
 
+EXPORT_SYMBOL(ide_unregister_subdriver);
+
 int ide_register_module (ide_module_t *module)
 {
 	ide_module_t *p = ide_modules;
@@ -3911,10 +2482,12 @@
 	}
 	module->next = ide_modules;
 	ide_modules = module;
-	revalidate_drives();
+	revalidate_drives(1);
 	return 0;
 }
 
+EXPORT_SYMBOL(ide_register_module);
+
 void ide_unregister_module (ide_module_t *module)
 {
 	ide_module_t **p;
@@ -3924,6 +2497,8 @@
 		*p = (*p)->next;
 }
 
+EXPORT_SYMBOL(ide_unregister_module);
+
 struct block_device_operations ide_fops[] = {{
 	owner:			THIS_MODULE,
 	open:			ide_open,
@@ -3933,10 +2508,34 @@
 	revalidate:		ide_revalidate_disk
 }};
 
-EXPORT_SYMBOL(ide_hwifs);
-EXPORT_SYMBOL(ide_register_module);
-EXPORT_SYMBOL(ide_unregister_module);
-EXPORT_SYMBOL(ide_spin_wait_hwgroup);
+EXPORT_SYMBOL(ide_fops);
+
+/*
+ * ide_geninit() is called exactly *once* for each interface.
+ */
+void ide_geninit (ide_hwif_t *hwif)
+{
+	unsigned int unit;
+	struct gendisk *gd = hwif->gd;
+
+	for (unit = 0; unit < MAX_DRIVES; ++unit) {
+		ide_drive_t *drive = &hwif->drives[unit];
+
+		if (!drive->present)
+			continue;
+		if (drive->media!=ide_disk && drive->media!=ide_floppy)
+			continue;
+		register_disk(gd,MKDEV(hwif->major,unit<<PARTN_BITS),
+#ifdef CONFIG_BLK_DEV_ISAPNP
+			(drive->forced_geom && drive->noprobe) ? 1 :
+#endif /* CONFIG_BLK_DEV_ISAPNP */
+			1<<PARTN_BITS, ide_fops,
+			current_capacity(drive));
+	}
+}
+
+EXPORT_SYMBOL(ide_geninit);
+
 
 /*
  * Probe module
@@ -3944,65 +2543,7 @@
 devfs_handle_t ide_devfs_handle;
 
 EXPORT_SYMBOL(ide_probe);
-EXPORT_SYMBOL(drive_is_flashcard);
-EXPORT_SYMBOL(ide_timer_expiry);
-EXPORT_SYMBOL(ide_intr);
-EXPORT_SYMBOL(ide_fops);
-EXPORT_SYMBOL(ide_get_queue);
-EXPORT_SYMBOL(ide_add_generic_settings);
 EXPORT_SYMBOL(ide_devfs_handle);
-EXPORT_SYMBOL(do_ide_request);
-/*
- * Driver module
- */
-EXPORT_SYMBOL(ide_scan_devices);
-EXPORT_SYMBOL(ide_register_subdriver);
-EXPORT_SYMBOL(ide_unregister_subdriver);
-EXPORT_SYMBOL(ide_replace_subdriver);
-EXPORT_SYMBOL(ide_input_data);
-EXPORT_SYMBOL(ide_output_data);
-EXPORT_SYMBOL(atapi_input_bytes);
-EXPORT_SYMBOL(atapi_output_bytes);
-EXPORT_SYMBOL(drive_is_ready);
-EXPORT_SYMBOL(ide_set_handler);
-EXPORT_SYMBOL(ide_dump_status);
-EXPORT_SYMBOL(ide_error);
-EXPORT_SYMBOL(ide_fixstring);
-EXPORT_SYMBOL(ide_wait_stat);
-EXPORT_SYMBOL(ide_do_reset);
-EXPORT_SYMBOL(restart_request);
-EXPORT_SYMBOL(ide_init_drive_cmd);
-EXPORT_SYMBOL(ide_do_drive_cmd);
-EXPORT_SYMBOL(ide_end_drive_cmd);
-EXPORT_SYMBOL(ide_end_request);
-EXPORT_SYMBOL(ide_revalidate_disk);
-EXPORT_SYMBOL(ide_cmd);
-EXPORT_SYMBOL(ide_wait_cmd);
-EXPORT_SYMBOL(ide_wait_cmd_task);
-EXPORT_SYMBOL(ide_delay_50ms);
-EXPORT_SYMBOL(ide_stall_queue);
-#ifdef CONFIG_PROC_FS
-EXPORT_SYMBOL(ide_add_proc_entries);
-EXPORT_SYMBOL(ide_remove_proc_entries);
-EXPORT_SYMBOL(proc_ide_read_geometry);
-EXPORT_SYMBOL(create_proc_ide_interfaces);
-EXPORT_SYMBOL(recreate_proc_ide_device);
-EXPORT_SYMBOL(destroy_proc_ide_device);
-#endif
-EXPORT_SYMBOL(ide_add_setting);
-EXPORT_SYMBOL(ide_remove_setting);
-
-EXPORT_SYMBOL(ide_register_hw);
-EXPORT_SYMBOL(ide_register);
-EXPORT_SYMBOL(ide_unregister);
-EXPORT_SYMBOL(ide_setup_ports);
-EXPORT_SYMBOL(hwif_unregister);
-EXPORT_SYMBOL(get_info_ptr);
-EXPORT_SYMBOL(current_capacity);
-
-EXPORT_SYMBOL(system_bus_clock);
-
-EXPORT_SYMBOL(ide_reinit_drive);
 
 static int ide_notify_reboot (struct notifier_block *this, unsigned long event, void *x)
 {
@@ -4019,7 +2560,7 @@
 			return NOTIFY_DONE;
 	}
 
-	printk("flushing ide devices: ");
+	printk(KERN_INFO "flushing ide devices: ");
 
 	for (i = 0; i < MAX_HWIFS; i++) {
 		hwif = &ide_hwifs[i];
@@ -4036,8 +2577,11 @@
 				if (drive->driver != NULL && DRIVER(drive)->standby(drive))
 				continue;
 
-			if (drive->driver != NULL && DRIVER(drive)->cleanup(drive))
+			if (drive->driver != NULL)
+			{
+				DRIVER(drive)->cleanup(drive);
 				continue;
+			}
 		}
 	}
 	printk("\n");
@@ -4060,12 +2604,16 @@
 
 	if (!banner_printed) {
 		printk(KERN_INFO "Uniform Multi-Platform E-IDE driver " REVISION "\n");
-		ide_devfs_handle = devfs_mk_dir (NULL, "ide", NULL);
+		ide_devfs_handle = devfs_mk_dir(NULL, "ide", NULL);
 		system_bus_speed = ide_system_bus_speed();
 		banner_printed = 1;
 	}
 
-	init_ide_data ();
+	init_ide_data();
+
+#ifndef CLASSIC_BUILTINS_METHOD
+	ide_init_builtin_subdrivers();
+#endif /* CLASSIC_BUILTINS_METHOD */
 
 	initializing = 1;
 	ide_init_builtin_drivers();
@@ -4113,10 +2661,10 @@
 	unregister_reboot_notifier(&ide_notifier);
 	for (index = 0; index < MAX_HWIFS; ++index) {
 		ide_unregister(index);
-#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
+#if !defined(CONFIG_DMA_NONPCI)
 		if (ide_hwifs[index].dma_base)
 			(void) ide_release_dma(&ide_hwifs[index]);
-#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
+#endif /* !(CONFIG_DMA_NONPCI) */
 	}
 
 #ifdef CONFIG_PROC_FS
@@ -4128,5 +2676,6 @@
 #else /* !MODULE */
 
 __setup("", ide_setup);
+module_init(ide_init);
 
 #endif /* MODULE */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ide_modes.h linux-2.4.21-pre6/drivers/ide/ide_modes.h
--- linux-2.4.20/drivers/ide/ide_modes.h	2001-11-22 19:46:58.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/ide_modes.h	2003-03-26 23:49:50.000000000 +0000
@@ -16,8 +16,6 @@
  * breaking the fragile cmd640.c support.
  */
 
-#ifdef CONFIG_BLK_DEV_IDE_MODES
-
 /*
  * Standard (generic) timings for PIO modes, from ATA2 specification.
  * These timings are for access to the IDE data port register *only*.
@@ -31,206 +29,13 @@
 } ide_pio_timings_t;
 
 typedef struct ide_pio_data_s {
-	byte pio_mode;
-	byte use_iordy;
-	byte overridden;
-	byte blacklisted;
+	u8 pio_mode;
+	u8 use_iordy;
+	u8 overridden;
+	u8 blacklisted;
 	unsigned int cycle_time;
 } ide_pio_data_t;
 	
-#ifndef _IDE_C
-
-int ide_scan_pio_blacklist (char *model);
-byte ide_get_best_pio_mode (ide_drive_t *drive, byte mode_wanted, byte max_mode, ide_pio_data_t *d);
+u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode, ide_pio_data_t *d);
 extern const ide_pio_timings_t ide_pio_timings[6];
-
-#else /* _IDE_C */
-
-const ide_pio_timings_t ide_pio_timings[6] = {
-	{ 70,	165,	600 },	/* PIO Mode 0 */
-	{ 50,	125,	383 },	/* PIO Mode 1 */
-	{ 30,	100,	240 },	/* PIO Mode 2 */
-	{ 30,	80,	180 },	/* PIO Mode 3 with IORDY */
-	{ 25,	70,	120 },	/* PIO Mode 4 with IORDY */
-	{ 20,	50,	100 }	/* PIO Mode 5 with IORDY (nonstandard) */
-};
-
-/*
- * Black list. Some drives incorrectly report their maximal PIO mode,
- * at least in respect to CMD640. Here we keep info on some known drives.
- */
-static struct ide_pio_info {
-	const char	*name;
-	int		pio;
-} ide_pio_blacklist [] = {
-/*	{ "Conner Peripherals 1275MB - CFS1275A", 4 }, */
-	{ "Conner Peripherals 540MB - CFS540A", 3 },
-
-	{ "WDC AC2700",  3 },
-	{ "WDC AC2540",  3 },
-	{ "WDC AC2420",  3 },
-	{ "WDC AC2340",  3 },
-	{ "WDC AC2250",  0 },
-	{ "WDC AC2200",  0 },
-	{ "WDC AC21200", 4 },
-	{ "WDC AC2120",  0 },
-	{ "WDC AC2850",  3 },
-	{ "WDC AC1270",  3 },
-	{ "WDC AC1170",  1 },
-	{ "WDC AC1210",  1 },
-	{ "WDC AC280",   0 },
-/*	{ "WDC AC21000", 4 }, */
-	{ "WDC AC31000", 3 },
-	{ "WDC AC31200", 3 },
-/*	{ "WDC AC31600", 4 }, */
-
-	{ "Maxtor 7131 AT", 1 },
-	{ "Maxtor 7171 AT", 1 },
-	{ "Maxtor 7213 AT", 1 },
-	{ "Maxtor 7245 AT", 1 },
-	{ "Maxtor 7345 AT", 1 },
-	{ "Maxtor 7546 AT", 3 },
-	{ "Maxtor 7540 AV", 3 },
-
-	{ "SAMSUNG SHD-3121A", 1 },
-	{ "SAMSUNG SHD-3122A", 1 },
-	{ "SAMSUNG SHD-3172A", 1 },
-
-/*	{ "ST51080A", 4 },
- *	{ "ST51270A", 4 },
- *	{ "ST31220A", 4 },
- *	{ "ST31640A", 4 },
- *	{ "ST32140A", 4 },
- *	{ "ST3780A",  4 },
- */
-	{ "ST5660A",  3 },
-	{ "ST3660A",  3 },
-	{ "ST3630A",  3 },
-	{ "ST3655A",  3 },
-	{ "ST3391A",  3 },
-	{ "ST3390A",  1 },
-	{ "ST3600A",  1 },
-	{ "ST3290A",  0 },
-	{ "ST3144A",  0 },
-	{ "ST3491A",  1 },	/* reports 3, should be 1 or 2 (depending on */	
-				/* drive) according to Seagates FIND-ATA program */
-
-	{ "QUANTUM ELS127A", 0 },
-	{ "QUANTUM ELS170A", 0 },
-	{ "QUANTUM LPS240A", 0 },
-	{ "QUANTUM LPS210A", 3 },
-	{ "QUANTUM LPS270A", 3 },
-	{ "QUANTUM LPS365A", 3 },
-	{ "QUANTUM LPS540A", 3 },
-	{ "QUANTUM LIGHTNING 540A", 3 },
-	{ "QUANTUM LIGHTNING 730A", 3 },
-
-        { "QUANTUM FIREBALL_540", 3 }, /* Older Quantum Fireballs don't work */
-        { "QUANTUM FIREBALL_640", 3 }, 
-        { "QUANTUM FIREBALL_1080", 3 },
-        { "QUANTUM FIREBALL_1280", 3 },
-	{ NULL,	0 }
-};
-
-/*
- * This routine searches the ide_pio_blacklist for an entry
- * matching the start/whole of the supplied model name.
- *
- * Returns -1 if no match found.
- * Otherwise returns the recommended PIO mode from ide_pio_blacklist[].
- */
-int ide_scan_pio_blacklist (char *model)
-{
-	struct ide_pio_info *p;
-
-	for (p = ide_pio_blacklist; p->name != NULL; p++) {
-		if (strncmp(p->name, model, strlen(p->name)) == 0)
-			return p->pio;
-	}
-	return -1;
-}
-
-/*
- * This routine returns the recommended PIO settings for a given drive,
- * based on the drive->id information and the ide_pio_blacklist[].
- * This is used by most chipset support modules when "auto-tuning".
- */
-
-/*
- * Drive PIO mode auto selection
- */
-byte ide_get_best_pio_mode (ide_drive_t *drive, byte mode_wanted, byte max_mode, ide_pio_data_t *d)
-{
-	int pio_mode;
-	int cycle_time = 0;
-	int use_iordy = 0;
-	struct hd_driveid* id = drive->id;
-	int overridden  = 0;
-	int blacklisted = 0;
-
-	if (mode_wanted != 255) {
-		pio_mode = mode_wanted;
-	} else if (!drive->id) {
-		pio_mode = 0;
-	} else if ((pio_mode = ide_scan_pio_blacklist(id->model)) != -1) {
-		overridden = 1;
-		blacklisted = 1;
-		use_iordy = (pio_mode > 2);
-	} else {
-		pio_mode = id->tPIO;
-		if (pio_mode > 2) {	/* 2 is maximum allowed tPIO value */
-			pio_mode = 2;
-			overridden = 1;
-		}
-		if (id->field_valid & 2) {	  /* drive implements ATA2? */
-			if (id->capability & 8) { /* drive supports use_iordy? */
-				use_iordy = 1;
-				cycle_time = id->eide_pio_iordy;
-				if (id->eide_pio_modes & 7) {
-					overridden = 0;
-					if (id->eide_pio_modes & 4)
-						pio_mode = 5;
-					else if (id->eide_pio_modes & 2)
-						pio_mode = 4;
-					else
-						pio_mode = 3;
-				}
-			} else {
-				cycle_time = id->eide_pio;
-			}
-		}
-
-#if 0
-		if (drive->id->major_rev_num & 0x0004) printk("ATA-2 ");
-#endif
-
-		/*
-		 * Conservative "downgrade" for all pre-ATA2 drives
-		 */
-		if (pio_mode && pio_mode < 4) {
-			pio_mode--;
-			overridden = 1;
-#if 0
-			use_iordy = (pio_mode > 2);
-#endif
-			if (cycle_time && cycle_time < ide_pio_timings[pio_mode].cycle_time)
-				cycle_time = 0; /* use standard timing */
-		}
-	}
-	if (pio_mode > max_mode) {
-		pio_mode = max_mode;
-		cycle_time = 0;
-	}
-	if (d) {
-		d->pio_mode = pio_mode;
-		d->cycle_time = cycle_time ? cycle_time : ide_pio_timings[pio_mode].cycle_time;
-		d->use_iordy = use_iordy;
-		d->overridden = overridden;
-		d->blacklisted = blacklisted;
-	}
-	return pio_mode;
-}
-
-#endif /* _IDE_C */
-#endif /* CONFIG_BLK_DEV_IDE_MODES */
 #endif /* _IDE_MODES_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/it8172.c linux-2.4.21-pre6/drivers/ide/it8172.c
--- linux-2.4.20/drivers/ide/it8172.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/it8172.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,286 +0,0 @@
-/*
- *
- * BRIEF MODULE DESCRIPTION
- *      IT8172 IDE controller support
- *
- * Copyright 2000 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- *              stevel@mvista.com or source@mvista.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  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.
- *
- *  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/types.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-#include <asm/it8172/it8172_int.h>
-
-#include "ide_modes.h"
-
-/*
- * Prototypes
- */
-static void it8172_tune_drive (ide_drive_t *drive, byte pio);
-#if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_IT8172_TUNING)
-static byte it8172_dma_2_pio (byte xfer_rate);
-static int it8172_tune_chipset (ide_drive_t *drive, byte speed);
-static int it8172_config_chipset_for_dma (ide_drive_t *drive);
-static int it8172_dmaproc(ide_dma_action_t func, ide_drive_t *drive);
-#endif
-unsigned int __init pci_init_it8172 (struct pci_dev *dev, const char *name);
-void __init ide_init_it8172 (ide_hwif_t *hwif);
-
-
-static void it8172_tune_drive (ide_drive_t *drive, byte pio)
-{
-    unsigned long flags;
-    u16 drive_enables;
-    u32 drive_timing;
-    int is_slave	= (&HWIF(drive)->drives[1] == drive);
-    
-    pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
-    pci_read_config_word(HWIF(drive)->pci_dev, 0x40, &drive_enables);
-    pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, &drive_timing);
-
-    /*
-     * FIX! The DIOR/DIOW pulse width and recovery times in port 0x44
-     * are being left at the default values of 8 PCI clocks (242 nsec
-     * for a 33 MHz clock). These can be safely shortened at higher
-     * PIO modes. The DIOR/DIOW pulse width and recovery times only
-     * apply to PIO modes, not to the DMA modes.
-     */
-    
-    /*
-     * Enable port 0x44. The IT8172G spec is confused; it calls
-     * this register the "Slave IDE Timing Register", but in fact,
-     * it controls timing for both master and slave drives.
-     */
-    drive_enables |= 0x4000;
-
-    if (is_slave) {
-	drive_enables &= 0xc006;
-	if (pio > 1)
-	    /* enable prefetch and IORDY sample-point */
-	    drive_enables |= 0x0060;
-    } else {
-	drive_enables &= 0xc060;
-	if (pio > 1)
-	    /* enable prefetch and IORDY sample-point */
-	    drive_enables |= 0x0006;
-    }
-
-    save_flags(flags);
-    cli();
-    pci_write_config_word(HWIF(drive)->pci_dev, 0x40, drive_enables);
-    restore_flags(flags);
-}
-
-#if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_IT8172_TUNING)
-/*
- *
- */
-static byte it8172_dma_2_pio (byte xfer_rate)
-{
-    switch(xfer_rate) {
-    case XFER_UDMA_5:
-    case XFER_UDMA_4:
-    case XFER_UDMA_3:
-    case XFER_UDMA_2:
-    case XFER_UDMA_1:
-    case XFER_UDMA_0:
-    case XFER_MW_DMA_2:
-    case XFER_PIO_4:
-	return 4;
-    case XFER_MW_DMA_1:
-    case XFER_PIO_3:
-	return 3;
-    case XFER_SW_DMA_2:
-    case XFER_PIO_2:
-	return 2;
-    case XFER_MW_DMA_0:
-    case XFER_SW_DMA_1:
-    case XFER_SW_DMA_0:
-    case XFER_PIO_1:
-    case XFER_PIO_0:
-    case XFER_PIO_SLOW:
-    default:
-	return 0;
-    }
-}
-
-static int it8172_tune_chipset (ide_drive_t *drive, byte speed)
-{
-    ide_hwif_t *hwif	= HWIF(drive);
-    struct pci_dev *dev	= hwif->pci_dev;
-    int a_speed		= 3 << (drive->dn * 4);
-    int u_flag		= 1 << drive->dn;
-    int u_speed		= 0;
-    int err		= 0;
-    byte reg48, reg4a;
-
-    pci_read_config_byte(dev, 0x48, &reg48);
-    pci_read_config_byte(dev, 0x4a, &reg4a);
-
-    /*
-     * Setting the DMA cycle time to 2 or 3 PCI clocks (60 and 91 nsec
-     * at 33 MHz PCI clock) seems to cause BadCRC errors during DMA
-     * transfers on some drives, even though both numbers meet the minimum
-     * ATAPI-4 spec of 73 and 54 nsec for UDMA 1 and 2 respectively.
-     * So the faster times are just commented out here. The good news is
-     * that the slower cycle time has very little affect on transfer
-     * performance.
-     */
-    
-    switch(speed) {
-    case XFER_UDMA_4:
-    case XFER_UDMA_2:	//u_speed = 2 << (drive->dn * 4); break;
-    case XFER_UDMA_5:
-    case XFER_UDMA_3:
-    case XFER_UDMA_1:	//u_speed = 1 << (drive->dn * 4); break;
-    case XFER_UDMA_0:	u_speed = 0 << (drive->dn * 4); break;
-    case XFER_MW_DMA_2:
-    case XFER_MW_DMA_1:
-    case XFER_MW_DMA_0:
-    case XFER_SW_DMA_2:	break;
-    default:		return -1;
-    }
-
-    if (speed >= XFER_UDMA_0) {
-	pci_write_config_byte(dev, 0x48, reg48 | u_flag);
-	reg4a &= ~a_speed;
-	pci_write_config_byte(dev, 0x4a, reg4a | u_speed);
-    } else {
-	pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
-	pci_write_config_byte(dev, 0x4a, reg4a & ~a_speed);
-    }
-
-    it8172_tune_drive(drive, it8172_dma_2_pio(speed));
-
-    if (!drive->init_speed)
-	drive->init_speed = speed;
-    err = ide_config_drive_speed(drive, speed);
-    drive->current_speed = speed;
-    return err;
-}
-
-static int it8172_config_chipset_for_dma (ide_drive_t *drive)
-{
-    struct hd_driveid *id = drive->id;
-    byte speed;
-
-    if (id->dma_ultra & 0x0010) {
-	speed = XFER_UDMA_2;
-    } else if (id->dma_ultra & 0x0008) {
-	speed = XFER_UDMA_1;
-    } else if (id->dma_ultra & 0x0004) {
-	speed = XFER_UDMA_2;
-    } else if (id->dma_ultra & 0x0002) {
-	speed = XFER_UDMA_1;
-    } else if (id->dma_ultra & 0x0001) {
-	speed = XFER_UDMA_0;
-    } else if (id->dma_mword & 0x0004) {
-	speed = XFER_MW_DMA_2;
-    } else if (id->dma_mword & 0x0002) {
-	speed = XFER_MW_DMA_1;
-    } else if (id->dma_mword & 0x0001) {
-	speed = XFER_MW_DMA_0;
-    } else if (id->dma_1word & 0x0004) {
-	speed = XFER_SW_DMA_2;
-    } else {
-	speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 4, NULL);
-    }
-
-    (void) it8172_tune_chipset(drive, speed);
-
-    return ((int)((id->dma_ultra >> 11) & 7) ? ide_dma_on :
-	    ((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-	    ((id->dma_mword >> 8) & 7) ? ide_dma_on :
-	    ((id->dma_1word >> 8) & 7) ? ide_dma_on :
-	    ide_dma_off_quietly);
-}
-
-static int it8172_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-    switch (func) {
-    case ide_dma_check:
-	return ide_dmaproc((ide_dma_action_t)it8172_config_chipset_for_dma(drive),
-			   drive);
-    default :
-	break;
-    }
-    /* Other cases are done by generic IDE-DMA code. */
-    return ide_dmaproc(func, drive);
-}
-
-#endif /* defined(CONFIG_BLK_DEV_IDEDMA) && (CONFIG_IT8172_TUNING) */
-
-
-unsigned int __init pci_init_it8172 (struct pci_dev *dev, const char *name)
-{
-    unsigned char progif;
-    
-    /*
-     * Place both IDE interfaces into PCI "native" mode
-     */
-    (void)pci_read_config_byte(dev, PCI_CLASS_PROG, &progif);
-    (void)pci_write_config_byte(dev, PCI_CLASS_PROG, progif | 0x05);    
-
-    return IT8172_IDE_IRQ;
-}
-
-
-void __init ide_init_it8172 (ide_hwif_t *hwif)
-{
-    struct pci_dev* dev = hwif->pci_dev;
-    unsigned long cmdBase, ctrlBase;
-    
-    hwif->tuneproc = &it8172_tune_drive;
-    hwif->drives[0].autotune = 1;
-    hwif->drives[1].autotune = 1;
-
-    if (!hwif->dma_base)
-	return;
-
-#ifndef CONFIG_BLK_DEV_IDEDMA
-    hwif->autodma = 0;
-#else /* CONFIG_BLK_DEV_IDEDMA */
-#ifdef CONFIG_IT8172_TUNING
-    hwif->autodma = 1;
-    hwif->dmaproc = &it8172_dmaproc;
-    hwif->speedproc = &it8172_tune_chipset;
-#endif /* CONFIG_IT8172_TUNING */
-#endif /* !CONFIG_BLK_DEV_IDEDMA */
-
-    cmdBase = dev->resource[0].start;
-    ctrlBase = dev->resource[1].start;
-    
-    ide_init_hwif_ports(&hwif->hw, cmdBase, ctrlBase | 2, NULL);
-    memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
-    hwif->noprobe = 0;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/Makefile linux-2.4.21-pre6/drivers/ide/legacy/Makefile
--- linux-2.4.20/drivers/ide/legacy/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/legacy/Makefile	2003-03-26 23:49:24.000000000 +0000
@@ -0,0 +1,27 @@
+
+O_TARGET := idedriver-legacy.o
+
+obj-y		:=
+obj-m		:=
+
+obj-$(CONFIG_BLK_DEV_ALI14XX)		+= ali14xx.o
+obj-$(CONFIG_BLK_DEV_DTC2278)		+= dtc2278.o
+obj-$(CONFIG_BLK_DEV_HT6560B)		+= ht6560b.o
+obj-$(CONFIG_BLK_DEV_PDC4030)		+= pdc4030.o
+obj-$(CONFIG_BLK_DEV_QD65XX)		+= qd65xx.o
+obj-$(CONFIG_BLK_DEV_UMC8672)		+= umc8672.o
+
+obj-$(CONFIG_BLK_DEV_BUDDHA)		+= buddha.o
+obj-$(CONFIG_BLK_DEV_FALCON_IDE)	+= falconide.o
+obj-$(CONFIG_BLK_DEV_GAYLE)		+= gayle.o
+obj-$(CONFIG_BLK_DEV_MAC_IDE)		+= macide.o
+obj-$(CONFIG_BLK_DEV_Q40IDE)		+= q40ide.o
+
+obj-$(CONFIG_BLK_DEV_IDECS)		+= ide-cs.o
+
+# Last of all
+obj-$(CONFIG_BLK_DEV_HD)		+= hd.o
+
+EXTRA_CFLAGS	:= -I../
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/ali14xx.c linux-2.4.21-pre6/drivers/ide/legacy/ali14xx.c
--- linux-2.4.20/drivers/ide/legacy/ali14xx.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/legacy/ali14xx.c	2003-03-26 23:49:35.000000000 +0000
@@ -0,0 +1,304 @@
+/*
+ *  linux/drivers/ide/legacy/ali14xx.c		Version 0.03	Feb 09, 1996
+ *
+ *  Copyright (C) 1996  Linus Torvalds & author (see below)
+ */
+
+/*
+ * ALI M14xx chipset EIDE controller
+ *
+ * Works for ALI M1439/1443/1445/1487/1489 chipsets.
+ *
+ * Adapted from code developed by derekn@vw.ece.cmu.edu.  -ml
+ * Derek's notes follow:
+ *
+ * I think the code should be pretty understandable,
+ * but I'll be happy to (try to) answer questions.
+ *
+ * The critical part is in the setupDrive function.  The initRegisters
+ * function doesn't seem to be necessary, but the DOS driver does it, so
+ * I threw it in.
+ *
+ * I've only tested this on my system, which only has one disk.  I posted
+ * it to comp.sys.linux.hardware, so maybe some other people will try it
+ * out.
+ *
+ * Derek Noonburg  (derekn@ece.cmu.edu)
+ * 95-sep-26
+ *
+ * Update 96-jul-13:
+ *
+ * I've since upgraded to two disks and a CD-ROM, with no trouble, and
+ * I've also heard from several others who have used it successfully.
+ * This driver appears to work with both the 1443/1445 and the 1487/1489
+ * chipsets.  I've added support for PIO mode 4 for the 1487.  This
+ * seems to work just fine on the 1443 also, although I'm not sure it's
+ * advertised as supporting mode 4.  (I've been running a WDC AC21200 in
+ * mode 4 for a while now with no trouble.)  -Derek
+ */
+
+#undef REALLY_SLOW_IO           /* most systems can safely undef this */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#ifdef CONFIG_BLK_DEV_ALI14XX_MODULE
+# define _IDE_C
+# include "ide_modes.h"
+# undef _IDE_C
+#else
+# include "ide_modes.h"
+#endif /* CONFIG_BLK_DEV_ALI14XX_MODULE */
+
+/* port addresses for auto-detection */
+#define ALI_NUM_PORTS 4
+static int ports[ALI_NUM_PORTS] __initdata = {0x074, 0x0f4, 0x034, 0x0e4};
+
+/* register initialization data */
+typedef struct { u8 reg, data; } RegInitializer;
+
+static RegInitializer initData[] __initdata = {
+	{0x01, 0x0f}, {0x02, 0x00}, {0x03, 0x00}, {0x04, 0x00},
+	{0x05, 0x00}, {0x06, 0x00}, {0x07, 0x2b}, {0x0a, 0x0f},
+	{0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00}, {0x28, 0x00},
+	{0x29, 0x00}, {0x2a, 0x00}, {0x2f, 0x00}, {0x2b, 0x00},
+	{0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x30, 0x00},
+	{0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00}, {0x34, 0xff},
+	{0x35, 0x03}, {0x00, 0x00}
+};
+
+#define ALI_MAX_PIO 4
+
+/* timing parameter registers for each drive */
+static struct { u8 reg1, reg2, reg3, reg4; } regTab[4] = {
+	{0x03, 0x26, 0x04, 0x27},     /* drive 0 */
+	{0x05, 0x28, 0x06, 0x29},     /* drive 1 */
+	{0x2b, 0x30, 0x2c, 0x31},     /* drive 2 */
+	{0x2d, 0x32, 0x2e, 0x33},     /* drive 3 */
+};
+
+static int basePort;	/* base port address */
+static int regPort;	/* port for register number */
+static int dataPort;	/* port for register data */
+static u8 regOn;	/* output to base port to access registers */
+static u8 regOff;	/* output to base port to close registers */
+
+/*------------------------------------------------------------------------*/
+
+/*
+ * Read a controller register.
+ */
+static inline u8 inReg (u8 reg)
+{
+	outb_p(reg, regPort);
+	return inb(dataPort);
+}
+
+/*
+ * Write a controller register.
+ */
+static void outReg (u8 data, u8 reg)
+{
+	outb_p(reg, regPort);
+	outb_p(data, dataPort);
+}
+
+/*
+ * Set PIO mode for the specified drive.
+ * This function computes timing parameters
+ * and sets controller registers accordingly.
+ */
+static void ali14xx_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	int driveNum;
+	int time1, time2;
+	u8 param1, param2, param3, param4;
+	unsigned long flags;
+	ide_pio_data_t d;
+	int bus_speed = system_bus_clock();
+
+	pio = ide_get_best_pio_mode(drive, pio, ALI_MAX_PIO, &d);
+
+	/* calculate timing, according to PIO mode */
+	time1 = d.cycle_time;
+	time2 = ide_pio_timings[pio].active_time;
+	param3 = param1 = (time2 * bus_speed + 999) / 1000;
+	param4 = param2 = (time1 * bus_speed + 999) / 1000 - param1;
+	if (pio < 3) {
+		param3 += 8;
+		param4 += 8;
+	}
+	printk(KERN_DEBUG "%s: PIO mode%d, t1=%dns, t2=%dns, cycles = %d+%d, %d+%d\n",
+		drive->name, pio, time1, time2, param1, param2, param3, param4);
+
+	/* stuff timing parameters into controller registers */
+	driveNum = (HWIF(drive)->index << 1) + drive->select.b.unit;
+	spin_lock_irqsave(&io_request_lock, flags);
+	outb_p(regOn, basePort);
+	outReg(param1, regTab[driveNum].reg1);
+	outReg(param2, regTab[driveNum].reg2);
+	outReg(param3, regTab[driveNum].reg3);
+	outReg(param4, regTab[driveNum].reg4);
+	outb_p(regOff, basePort);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+/*
+ * Auto-detect the IDE controller port.
+ */
+static int __init findPort (void)
+{
+	int i;
+	u8 t;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	for (i = 0; i < ALI_NUM_PORTS; ++i) {
+		basePort = ports[i];
+		regOff = inb(basePort);
+		for (regOn = 0x30; regOn <= 0x33; ++regOn) {
+			outb_p(regOn, basePort);
+			if (inb(basePort) == regOn) {
+				regPort = basePort + 4;
+				dataPort = basePort + 8;
+				t = inReg(0) & 0xf0;
+				outb_p(regOff, basePort);
+				local_irq_restore(flags);
+				if (t != 0x50)
+					return 0;
+				return 1;  /* success */
+			}
+		}
+		outb_p(regOff, basePort);
+	}
+	local_irq_restore(flags);
+	return 0;
+}
+
+/*
+ * Initialize controller registers with default values.
+ */
+static int __init initRegisters (void) {
+	RegInitializer *p;
+	u8 t;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	outb_p(regOn, basePort);
+	for (p = initData; p->reg != 0; ++p)
+		outReg(p->data, p->reg);
+	outb_p(0x01, regPort);
+	t = inb(regPort) & 0x01;
+	outb_p(regOff, basePort);
+	local_irq_restore(flags);
+	return t;
+}
+
+int __init probe_ali14xx (void)
+{
+	/* auto-detect IDE controller port */
+	if (!findPort()) {
+		printk(KERN_ERR "ali14xx: not found.\n");
+		return 1;
+	}
+
+	printk(KERN_DEBUG "ali14xx: base= 0x%03x, regOn = 0x%02x.\n", basePort, regOn);
+	ide_hwifs[0].chipset = ide_ali14xx;
+	ide_hwifs[1].chipset = ide_ali14xx;
+	ide_hwifs[0].tuneproc = &ali14xx_tune_drive;
+	ide_hwifs[1].tuneproc = &ali14xx_tune_drive;
+	ide_hwifs[0].mate = &ide_hwifs[1];
+	ide_hwifs[1].mate = &ide_hwifs[0];
+	ide_hwifs[1].channel = 1;
+
+	/* initialize controller registers */
+	if (!initRegisters()) {
+		printk(KERN_ERR "ali14xx: Chip initialization failed.\n");
+		return 1;
+	}
+
+#ifndef HWIF_PROBE_CLASSIC_METHOD
+	probe_hwif_init(&ide_hwifs[0]);
+	probe_hwif_init(&ide_hwifs[1]);
+#endif /* HWIF_PROBE_CLASSIC_METHOD */
+
+	return 0;
+}
+
+void __init ali14xx_release (void)
+{
+	if (ide_hwifs[0].chipset != ide_ali14xx &&
+	    ide_hwifs[1].chipset != ide_ali14xx)
+		return;
+
+	ide_hwifs[0].chipset = ide_unknown;
+	ide_hwifs[1].chipset = ide_unknown;
+	ide_hwifs[0].tuneproc = NULL;
+	ide_hwifs[1].tuneproc = NULL;
+	ide_hwifs[0].mate = NULL;
+	ide_hwifs[1].mate = NULL;
+}
+
+#ifndef MODULE
+/*
+ * init_ali14xx:
+ *
+ * called by ide.c when parsing command line
+ */
+
+void __init init_ali14xx (void)
+{
+	/* auto-detect IDE controller port */
+        if (findPort())
+		if (probe_ali14xx())
+			goto no_detect;
+	return;
+
+no_detect:
+	printk(KERN_ERR "ali14xx: not found.\n");
+	ali14xx_release();
+}
+
+#else
+
+MODULE_AUTHOR("see local file");
+MODULE_DESCRIPTION("support of ALI 14XX IDE chipsets");
+MODULE_LICENSE("GPL");
+
+int __init ali14xx_mod_init(void)
+{
+	/* auto-detect IDE controller port */
+	if (findPort())
+		if (probe_ali14xx()) {
+			ali14xx_release();
+			return -ENODEV;
+		}
+
+	if (ide_hwifs[0].chipset != ide_ali14xx &&
+	    ide_hwifs[1].chipset != ide_ali14xx) {
+		ali14xx_release();
+		return -ENODEV;
+	}
+	return 0;
+}
+module_init(ali14xx_mod_init);
+
+void __init ali14xx_mod_exit(void)
+{
+	ali14xx_release();
+}
+module_exit(ali14xx_mod_exit);
+#endif
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/buddha.c linux-2.4.21-pre6/drivers/ide/legacy/buddha.c
--- linux-2.4.20/drivers/ide/legacy/buddha.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/legacy/buddha.c	2003-03-26 23:49:31.000000000 +0000
@@ -0,0 +1,233 @@
+/*
+ *  linux/drivers/ide/legacy/buddha.c -- Amiga Buddha, Catweasel and X-Surf IDE Driver
+ *
+ *	Copyright (C) 1997, 2001 by Geert Uytterhoeven and others
+ *
+ *  This driver was written based on the specifications in README.buddha and
+ *  the X-Surf info from Inside_XSurf.txt available at
+ *  http://www.jschoenfeld.com
+ *
+ *  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.
+ *
+ *  TODO:
+ *    - test it :-)
+ *    - tune the timings using the speed-register
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/zorro.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+
+
+    /*
+     *  The Buddha has 2 IDE interfaces, the Catweasel has 3, X-Surf has 2
+     */
+
+#define BUDDHA_NUM_HWIFS	2
+#define CATWEASEL_NUM_HWIFS	3
+#define XSURF_NUM_HWIFS         2
+
+    /*
+     *  Bases of the IDE interfaces (relative to the board address)
+     */
+
+#define BUDDHA_BASE1	0x800
+#define BUDDHA_BASE2	0xa00
+#define BUDDHA_BASE3	0xc00
+
+#define XSURF_BASE1     0xb000 /* 2.5" Interface */
+#define XSURF_BASE2     0xd000 /* 3.5" Interface */
+
+static u_int buddha_bases[CATWEASEL_NUM_HWIFS] __initdata = {
+    BUDDHA_BASE1, BUDDHA_BASE2, BUDDHA_BASE3
+};
+
+static u_int xsurf_bases[XSURF_NUM_HWIFS] __initdata = {
+     XSURF_BASE1, XSURF_BASE2
+};
+
+
+    /*
+     *  Offsets from one of the above bases
+     */
+
+#define BUDDHA_DATA	0x00
+#define BUDDHA_ERROR	0x06		/* see err-bits */
+#define BUDDHA_NSECTOR	0x0a		/* nr of sectors to read/write */
+#define BUDDHA_SECTOR	0x0e		/* starting sector */
+#define BUDDHA_LCYL	0x12		/* starting cylinder */
+#define BUDDHA_HCYL	0x16		/* high byte of starting cyl */
+#define BUDDHA_SELECT	0x1a		/* 101dhhhh , d=drive, hhhh=head */
+#define BUDDHA_STATUS	0x1e		/* see status-bits */
+#define BUDDHA_CONTROL	0x11a
+#define XSURF_CONTROL   -1              /* X-Surf has no CS1* (Control/AltStat) */
+
+static int buddha_offsets[IDE_NR_PORTS] __initdata = {
+    BUDDHA_DATA, BUDDHA_ERROR, BUDDHA_NSECTOR, BUDDHA_SECTOR, BUDDHA_LCYL,
+    BUDDHA_HCYL, BUDDHA_SELECT, BUDDHA_STATUS, BUDDHA_CONTROL, -1
+};
+
+static int xsurf_offsets[IDE_NR_PORTS] __initdata = {
+    BUDDHA_DATA, BUDDHA_ERROR, BUDDHA_NSECTOR, BUDDHA_SECTOR, BUDDHA_LCYL,
+    BUDDHA_HCYL, BUDDHA_SELECT, BUDDHA_STATUS, XSURF_CONTROL, -1
+};
+
+    /*
+     *  Other registers
+     */
+
+#define BUDDHA_IRQ1	0xf00		/* MSB = 1, Harddisk is source of */
+#define BUDDHA_IRQ2	0xf40		/* interrupt */
+#define BUDDHA_IRQ3	0xf80
+
+#define XSURF_IRQ1      0x7e
+#define XSURF_IRQ2      0x7e
+
+static int buddha_irqports[CATWEASEL_NUM_HWIFS] __initdata = {
+    BUDDHA_IRQ1, BUDDHA_IRQ2, BUDDHA_IRQ3
+};
+
+static int xsurf_irqports[XSURF_NUM_HWIFS] __initdata = {
+    XSURF_IRQ1, XSURF_IRQ2
+};
+
+#define BUDDHA_IRQ_MR	0xfc0		/* master interrupt enable */
+
+
+    /*
+     *  Board information
+     */
+
+typedef enum BuddhaType_Enum {
+    BOARD_BUDDHA, BOARD_CATWEASEL, BOARD_XSURF
+} BuddhaType;
+
+
+    /*
+     *  Check and acknowledge the interrupt status
+     */
+
+static int buddha_ack_intr(ide_hwif_t *hwif)
+{
+    unsigned char ch;
+
+    ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]);
+    if (!(ch & 0x80))
+	    return 0;
+    return 1;
+}
+
+static int xsurf_ack_intr(ide_hwif_t *hwif)
+{
+    unsigned char ch;
+
+    ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]);
+    /* X-Surf needs a 0 written to IRQ register to ensure ISA bit A11 stays at 0 */
+    z_writeb(0, hwif->io_ports[IDE_IRQ_OFFSET]); 
+    if (!(ch & 0x80))
+	    return 0;
+    return 1;
+}
+
+    /*
+     *  Probe for a Buddha or Catweasel IDE interface
+     */
+
+void __init buddha_init(void)
+{
+	hw_regs_t hw;
+	int i, index;
+
+	struct zorro_dev *z = NULL;
+	u_long buddha_board = 0;
+	BuddhaType type;
+	int buddha_num_hwifs;
+
+	while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
+		unsigned long board;
+		if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_BUDDHA) {
+			buddha_num_hwifs = BUDDHA_NUM_HWIFS;
+			type=BOARD_BUDDHA;
+		} else if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_CATWEASEL) {
+			buddha_num_hwifs = CATWEASEL_NUM_HWIFS;
+			type=BOARD_CATWEASEL;
+		} else if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF) {
+			buddha_num_hwifs = XSURF_NUM_HWIFS;
+			type=BOARD_XSURF;
+		} else 
+			continue;
+		
+		board = z->resource.start;
+
+/*
+ * FIXME: we now have selectable mmio v/s iomio transports.
+ */
+
+		if(type != BOARD_XSURF) {
+			if (!request_mem_region(board+BUDDHA_BASE1, 0x800, "IDE"))
+				continue;
+		} else {
+			if (!request_mem_region(board+XSURF_BASE1, 0x1000, "IDE"))
+				continue;
+			if (!request_mem_region(board+XSURF_BASE2, 0x1000, "IDE"))
+				goto fail_base2;
+			if (!request_mem_region(board+XSURF_IRQ1, 0x8, "IDE")) {
+				release_mem_region(board+XSURF_BASE2, 0x1000);
+fail_base2:
+				release_mem_region(board+XSURF_BASE1, 0x1000);
+				continue;
+			}
+		}	  
+		buddha_board = ZTWO_VADDR(board);
+		
+		/* write to BUDDHA_IRQ_MR to enable the board IRQ */
+		/* X-Surf doesn't have this.  IRQs are always on */
+		if (type != BOARD_XSURF)
+			z_writeb(0, buddha_board+BUDDHA_IRQ_MR);
+		
+		for(i=0;i<buddha_num_hwifs;i++) {
+			if(type != BOARD_XSURF) {
+				ide_setup_ports(&hw, (ide_ioreg_t)(buddha_board+buddha_bases[i]),
+						buddha_offsets, 0,
+						(ide_ioreg_t)(buddha_board+buddha_irqports[i]),
+						buddha_ack_intr,
+//						budda_iops,
+						IRQ_AMIGA_PORTS);
+			} else {
+				ide_setup_ports(&hw, (ide_ioreg_t)(buddha_board+xsurf_bases[i]),
+						xsurf_offsets, 0,
+						(ide_ioreg_t)(buddha_board+xsurf_irqports[i]),
+						xsurf_ack_intr,
+//						xsurf_iops,
+						IRQ_AMIGA_PORTS);
+			}	
+			
+			index = ide_register_hw(&hw, NULL);
+			if (index != -1) {
+				printk("ide%d: ", index);
+				switch(type) {
+				case BOARD_BUDDHA:
+					printk("Buddha");
+					break;
+				case BOARD_CATWEASEL:
+					printk("Catweasel");
+					break;
+				case BOARD_XSURF:
+					printk("X-Surf");
+					break;
+				}
+				printk(" IDE interface\n");	    
+			}		      
+		}
+	}
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/dtc2278.c linux-2.4.21-pre6/drivers/ide/legacy/dtc2278.c
--- linux-2.4.20/drivers/ide/legacy/dtc2278.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/legacy/dtc2278.c	2003-03-26 23:49:35.000000000 +0000
@@ -0,0 +1,203 @@
+/*
+ *  linux/drivers/ide/legacy/dtc2278.c		Version 0.02	Feb 10, 1996
+ *
+ *  Copyright (C) 1996  Linus Torvalds & author (see below)
+ */
+
+#undef REALLY_SLOW_IO           /* most systems can safely undef this */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#ifdef CONFIG_BLK_DEV_DTC2278_MODULE
+# define _IDE_C
+# include "ide_modes.h"
+# undef _IDE_C
+#else
+# include "ide_modes.h"
+#endif /* CONFIG_BLK_DEV_DTC2278_MODULE */
+
+/*
+ * Changing this #undef to #define may solve start up problems in some systems.
+ */
+#undef ALWAYS_SET_DTC2278_PIO_MODE
+
+/*
+ * From: andy@cercle.cts.com (Dyan Wile)
+ *
+ * Below is a patch for DTC-2278 - alike software-programmable controllers
+ * The code enables the secondary IDE controller and the PIO4 (3?) timings on
+ * the primary (EIDE). You may probably have to enable the 32-bit support to
+ * get the full speed. You better get the disk interrupts disabled ( hdparm -u0
+ * /dev/hd.. ) for the drives connected to the EIDE interface. (I get my
+ * filesystem  corrupted with -u1, but under heavy disk load only :-)
+ *
+ * This card is now forced to use the "serialize" feature,
+ * and irq-unmasking is disallowed.  If io_32bit is enabled,
+ * it must be done for BOTH drives on each interface.
+ *
+ * This code was written for the DTC2278E, but might work with any of these:
+ *
+ * DTC2278S has only a single IDE interface.
+ * DTC2278D has two IDE interfaces and is otherwise identical to the S version.
+ * DTC2278E also has serial ports and a printer port
+ * DTC2278EB: has onboard BIOS, and "works like a charm" -- Kent Bradford <kent@theory.caltech.edu>
+ *
+ * There may be a fourth controller type. The S and D versions use the
+ * Winbond chip, and I think the E version does also.
+ *
+ */
+
+static void sub22 (char b, char c)
+{
+	int i;
+
+	for(i = 0; i < 3; ++i) {
+		inb(0x3f6);
+		outb_p(b,0xb0);
+		inb(0x3f6);
+		outb_p(c,0xb4);
+		inb(0x3f6);
+		if(inb(0xb4) == c) {
+			outb_p(7,0xb0);
+			inb(0x3f6);
+			return;	/* success */
+		}
+	}
+}
+
+static void tune_dtc2278 (ide_drive_t *drive, u8 pio)
+{
+	unsigned long flags;
+
+	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+
+	if (pio >= 3) {
+		spin_lock_irqsave(&io_request_lock, flags);
+		/*
+		 * This enables PIO mode4 (3?) on the first interface
+		 */
+		sub22(1,0xc3);
+		sub22(0,0xa0);
+		spin_unlock_irqrestore(&io_request_lock, flags);
+	} else {
+		/* we don't know how to set it back again.. */
+	}
+
+	/*
+	 * 32bit I/O has to be enabled for *both* drives at the same time.
+	 */
+	drive->io_32bit = 1;
+	HWIF(drive)->drives[!drive->select.b.unit].io_32bit = 1;
+}
+
+void __init probe_dtc2278 (void)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	/*
+	 * This enables the second interface
+	 */
+	outb_p(4,0xb0);
+	inb(0x3f6);
+	outb_p(0x20,0xb4);
+	inb(0x3f6);
+#ifdef ALWAYS_SET_DTC2278_PIO_MODE
+	/*
+	 * This enables PIO mode4 (3?) on the first interface
+	 * and may solve start-up problems for some people.
+	 */
+	sub22(1,0xc3);
+	sub22(0,0xa0);
+#endif
+	local_irq_restore(flags);
+
+	ide_hwifs[0].serialized = 1;
+	ide_hwifs[1].serialized = 1;
+	ide_hwifs[0].chipset = ide_dtc2278;
+	ide_hwifs[1].chipset = ide_dtc2278;
+	ide_hwifs[0].tuneproc = &tune_dtc2278;
+	ide_hwifs[0].drives[0].no_unmask = 1;
+	ide_hwifs[0].drives[1].no_unmask = 1;
+	ide_hwifs[1].drives[0].no_unmask = 1;
+	ide_hwifs[1].drives[1].no_unmask = 1;
+	ide_hwifs[0].mate = &ide_hwifs[1];
+	ide_hwifs[1].mate = &ide_hwifs[0];
+	ide_hwifs[1].channel = 1;
+
+#ifndef HWIF_PROBE_CLASSIC_METHOD
+	probe_hwif_init(&ide_hwifs[0]);
+	probe_hwif_init(&ide_hwifs[1]);
+#endif /* HWIF_PROBE_CLASSIC_METHOD */
+
+}
+
+void __init dtc2278_release (void)
+{
+	if (ide_hwifs[0].chipset != ide_dtc2278 &&
+	    ide_hwifs[1].chipset != ide_dtc2278)
+		return;
+
+	ide_hwifs[0].serialized = 0;
+	ide_hwifs[1].serialized = 0;
+	ide_hwifs[0].chipset = ide_unknown;
+	ide_hwifs[1].chipset = ide_unknown;
+	ide_hwifs[0].tuneproc = NULL;
+	ide_hwifs[0].drives[0].no_unmask = 0;
+	ide_hwifs[0].drives[1].no_unmask = 0;
+	ide_hwifs[1].drives[0].no_unmask = 0;
+	ide_hwifs[1].drives[1].no_unmask = 0;
+	ide_hwifs[0].mate = NULL;
+	ide_hwifs[1].mate = NULL;
+}
+
+#ifndef MODULE
+/*
+ * init_dtc2278:
+ *
+ * called by ide.c when parsing command line
+ */
+
+void __init init_dtc2278 (void)
+{
+	probe_dtc2278();
+}
+
+#else
+
+MODULE_AUTHOR("See Local File");
+MODULE_DESCRIPTION("support of DTC-2278 VLB IDE chipsets");
+MODULE_LICENSE("GPL");
+
+int __init dtc2278_mod_init(void)
+{
+	probe_dtc2278();
+	if (ide_hwifs[0].chipset != ide_dtc2278 &&
+	    ide_hwifs[1].chipset != ide_dtc2278) {
+		dtc2278_release();
+		return -ENODEV;
+	}
+	return 0;
+}
+module_init(dtc2278_mod_init);
+
+void __init dtc2278_mod_exit(void)
+{
+	dtc2278_release();
+}
+module_exit(dtc2278_mod_exit);
+#endif
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/falconide.c linux-2.4.21-pre6/drivers/ide/legacy/falconide.c
--- linux-2.4.20/drivers/ide/legacy/falconide.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/legacy/falconide.c	2003-03-26 23:49:34.000000000 +0000
@@ -0,0 +1,70 @@
+/*
+ *  linux/drivers/ide/legacy/falconide.c -- Atari Falcon IDE Driver
+ *
+ *     Created 12 Jul 1997 by Geert Uytterhoeven
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/setup.h>
+#include <asm/atarihw.h>
+#include <asm/atariints.h>
+#include <asm/atari_stdma.h>
+
+
+    /*
+     *  Base of the IDE interface
+     */
+
+#define ATA_HD_BASE	0xfff00000
+
+    /*
+     *  Offsets from the above base
+     */
+
+#define ATA_HD_DATA	0x00
+#define ATA_HD_ERROR	0x05		/* see err-bits */
+#define ATA_HD_NSECTOR	0x09		/* nr of sectors to read/write */
+#define ATA_HD_SECTOR	0x0d		/* starting sector */
+#define ATA_HD_LCYL	0x11		/* starting cylinder */
+#define ATA_HD_HCYL	0x15		/* high byte of starting cyl */
+#define ATA_HD_SELECT	0x19		/* 101dhhhh , d=drive, hhhh=head */
+#define ATA_HD_STATUS	0x1d		/* see status-bits */
+#define ATA_HD_CONTROL	0x39
+
+static int falconide_offsets[IDE_NR_PORTS] __initdata = {
+    ATA_HD_DATA, ATA_HD_ERROR, ATA_HD_NSECTOR, ATA_HD_SECTOR, ATA_HD_LCYL,
+    ATA_HD_HCYL, ATA_HD_SELECT, ATA_HD_STATUS, ATA_HD_CONTROL, -1
+};
+
+
+    /*
+     *  Probe for a Falcon IDE interface
+     */
+
+void __init falconide_init(void)
+{
+    if (MACH_IS_ATARI && ATARIHW_PRESENT(IDE)) {
+	hw_regs_t hw;
+	int index;
+
+	ide_setup_ports(&hw, (ide_ioreg_t)ATA_HD_BASE, falconide_offsets,
+			0, 0, NULL,
+//			falconide_iops,
+			IRQ_MFP_IDE);
+	index = ide_register_hw(&hw, NULL);
+
+	if (index != -1)
+	    printk("ide%d: Falcon IDE interface\n", index);
+    }
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/gayle.c linux-2.4.21-pre6/drivers/ide/legacy/gayle.c
--- linux-2.4.20/drivers/ide/legacy/gayle.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/legacy/gayle.c	2003-03-26 23:49:15.000000000 +0000
@@ -0,0 +1,187 @@
+/*
+ *  linux/drivers/ide/legacy/gayle.c -- Amiga Gayle IDE Driver
+ *
+ *     Created 9 Jul 1997 by Geert Uytterhoeven
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+#include <linux/zorro.h>
+
+#include <asm/setup.h>
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+#include <asm/amigayle.h>
+
+
+    /*
+     *  Bases of the IDE interfaces
+     */
+
+#define GAYLE_BASE_4000	0xdd2020	/* A4000/A4000T */
+#define GAYLE_BASE_1200	0xda0000	/* A1200/A600 */
+
+    /*
+     *  Offsets from one of the above bases
+     */
+
+#define GAYLE_DATA	0x00
+#define GAYLE_ERROR	0x06		/* see err-bits */
+#define GAYLE_NSECTOR	0x0a		/* nr of sectors to read/write */
+#define GAYLE_SECTOR	0x0e		/* starting sector */
+#define GAYLE_LCYL	0x12		/* starting cylinder */
+#define GAYLE_HCYL	0x16		/* high byte of starting cyl */
+#define GAYLE_SELECT	0x1a		/* 101dhhhh , d=drive, hhhh=head */
+#define GAYLE_STATUS	0x1e		/* see status-bits */
+#define GAYLE_CONTROL	0x101a
+
+static int gayle_offsets[IDE_NR_PORTS] __initdata = {
+    GAYLE_DATA, GAYLE_ERROR, GAYLE_NSECTOR, GAYLE_SECTOR, GAYLE_LCYL,
+    GAYLE_HCYL, GAYLE_SELECT, GAYLE_STATUS, -1, -1
+};
+
+
+    /*
+     *  These are at different offsets from the base
+     */
+
+#define GAYLE_IRQ_4000	0xdd3020	/* MSB = 1, Harddisk is source of */
+#define GAYLE_IRQ_1200	0xda9000	/* interrupt */
+
+
+    /*
+     *  Offset of the secondary port for IDE doublers
+     *  Note that GAYLE_CONTROL is NOT available then!
+     */
+
+#define GAYLE_NEXT_PORT	0x1000
+
+#ifndef CONFIG_BLK_DEV_IDEDOUBLER
+#define GAYLE_NUM_HWIFS		1
+#define GAYLE_NUM_PROBE_HWIFS	GAYLE_NUM_HWIFS
+#define GAYLE_HAS_CONTROL_REG	1
+#define GAYLE_IDEREG_SIZE	0x2000
+#else /* CONFIG_BLK_DEV_IDEDOUBLER */
+#define GAYLE_NUM_HWIFS		2
+#define GAYLE_NUM_PROBE_HWIFS	(ide_doubler ? GAYLE_NUM_HWIFS : \
+					       GAYLE_NUM_HWIFS-1)
+#define GAYLE_HAS_CONTROL_REG	(!ide_doubler)
+#define GAYLE_IDEREG_SIZE	(ide_doubler ? 0x1000 : 0x2000)
+int ide_doubler = 0;	/* support IDE doublers? */
+#endif /* CONFIG_BLK_DEV_IDEDOUBLER */
+
+
+    /*
+     *  Check and acknowledge the interrupt status
+     */
+
+static int gayle_ack_intr_a4000(ide_hwif_t *hwif)
+{
+    unsigned char ch;
+
+    ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]);
+    if (!(ch & GAYLE_IRQ_IDE))
+	return 0;
+    return 1;
+}
+
+static int gayle_ack_intr_a1200(ide_hwif_t *hwif)
+{
+    unsigned char ch;
+
+    ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]);
+    if (!(ch & GAYLE_IRQ_IDE))
+	return 0;
+    (void)z_readb(hwif->io_ports[IDE_STATUS_OFFSET]);
+    z_writeb(0x7c, hwif->io_ports[IDE_IRQ_OFFSET]);
+    return 1;
+}
+
+    /*
+     *  Probe for a Gayle IDE interface (and optionally for an IDE doubler)
+     */
+
+void __init gayle_init(void)
+{
+    int a4000, i;
+
+    if (!MACH_IS_AMIGA)
+	return;
+
+    if (!(a4000 = AMIGAHW_PRESENT(A4000_IDE)) && !AMIGAHW_PRESENT(A1200_IDE))
+	return;
+
+    for (i = 0; i < GAYLE_NUM_PROBE_HWIFS; i++) {
+	ide_ioreg_t base, ctrlport, irqport;
+	ide_ack_intr_t *ack_intr;
+	hw_regs_t hw;
+	int index;
+	unsigned long phys_base, res_start, res_n;
+
+	if (a4000) {
+	    phys_base = GAYLE_BASE_4000;
+	    irqport = (ide_ioreg_t)ZTWO_VADDR(GAYLE_IRQ_4000);
+	    ack_intr = gayle_ack_intr_a4000;
+	} else {
+	    phys_base = GAYLE_BASE_1200;
+	    irqport = (ide_ioreg_t)ZTWO_VADDR(GAYLE_IRQ_1200);
+	    ack_intr = gayle_ack_intr_a1200;
+	}
+/*
+ * FIXME: we now have selectable modes between mmio v/s iomio
+ */
+
+	phys_base += i*GAYLE_NEXT_PORT;
+
+	res_start = ((unsigned long)phys_base) & ~(GAYLE_NEXT_PORT-1);
+	res_n = GAYLE_IDEREG_SIZE;
+
+	if (!request_mem_region(res_start, res_n, "IDE"))
+	    continue;
+
+	base = (ide_ioreg_t)ZTWO_VADDR(phys_base);
+	ctrlport = GAYLE_HAS_CONTROL_REG ? (base + GAYLE_CONTROL) : 0;
+
+	ide_setup_ports(&hw, base, gayle_offsets,
+			ctrlport, irqport, ack_intr,
+//			gaule_iops,
+			IRQ_AMIGA_PORTS);
+
+	index = ide_register_hw(&hw, NULL);
+	if (index != -1) {
+	    switch (i) {
+		case 0:
+		    printk("ide%d: Gayle IDE interface (A%d style)\n", index,
+			   a4000 ? 4000 : 1200);
+		    break;
+#ifdef CONFIG_BLK_DEV_IDEDOUBLER
+		case 1:
+		    printk("ide%d: IDE doubler\n", index);
+		    break;
+#endif /* CONFIG_BLK_DEV_IDEDOUBLER */
+	    }
+	} else
+	    release_mem_region(res_start, res_n);
+
+#if 1 /* TESTING */
+	if (i == 1) {
+	    volatile u_short *addr = (u_short *)base;
+	    u_short data;
+	    printk("+++ Probing for IDE doubler... ");
+	    *addr = 0xffff;
+	    data = *addr;
+	    printk("probe returned 0x%02x (PLEASE REPORT THIS!!)\n", data);
+	}
+#endif /* TESTING */
+    }
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/hd.c linux-2.4.21-pre6/drivers/ide/legacy/hd.c
--- linux-2.4.20/drivers/ide/legacy/hd.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/legacy/hd.c	2003-03-26 23:49:08.000000000 +0000
@@ -0,0 +1,925 @@
+/*
+ *  linux/drivers/ide/legacy/hd.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+/*
+ * This is the low-level hd interrupt support. It traverses the
+ * request-list, using interrupts to jump between functions. As
+ * all the functions are called within interrupts, we may not
+ * sleep. Special care is recommended.
+ * 
+ *  modified by Drew Eckhardt to check nr of hd's from the CMOS.
+ *
+ *  Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
+ *  in the early extended-partition checks and added DM partitions
+ *
+ *  IRQ-unmask, drive-id, multiple-mode, support for ">16 heads",
+ *  and general streamlining by Mark Lord.
+ *
+ *  Removed 99% of above. Use Mark's ide driver for those options.
+ *  This is now a lightweight ST-506 driver. (Paul Gortmaker)
+ *
+ *  Modified 1995 Russell King for ARM processor.
+ *
+ *  Bugfix: max_sectors must be <= 255 or the wheels tend to come
+ *  off in a hurry once you queue things up - Paul G. 02/2001
+ */
+  
+/* Uncomment the following if you want verbose error reports. */
+/* #define VERBOSE_ERRORS */
+  
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/fs.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/kernel.h>
+#include <linux/hdreg.h>
+#include <linux/genhd.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/mc146818rtc.h> /* CMOS defines */
+#include <linux/init.h>
+#include <linux/blkpg.h>
+
+#define REALLY_SLOW_IO
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#define MAJOR_NR HD_MAJOR
+#include <linux/blk.h>
+
+#ifdef __arm__
+#undef  HD_IRQ
+#endif
+#include <asm/irq.h>
+#ifdef __arm__
+#define HD_IRQ IRQ_HARDDISK
+#endif
+
+static int revalidate_hddisk(kdev_t, int);
+
+#define	HD_DELAY	0
+
+#define MAX_ERRORS     16	/* Max read/write errors/sector */
+#define RESET_FREQ      8	/* Reset controller every 8th retry */
+#define RECAL_FREQ      4	/* Recalibrate every 4th retry */
+#define MAX_HD		2
+
+#define STAT_OK		(READY_STAT|SEEK_STAT)
+#define OK_STATUS(s)	(((s)&(STAT_OK|(BUSY_STAT|WRERR_STAT|ERR_STAT)))==STAT_OK)
+
+static void recal_intr(void);
+static void bad_rw_intr(void);
+
+static char recalibrate[MAX_HD];
+static char special_op[MAX_HD];
+static int access_count[MAX_HD];
+static char busy[MAX_HD];
+static DECLARE_WAIT_QUEUE_HEAD(busy_wait);
+
+static int reset;
+static int hd_error;
+
+#define SUBSECTOR(block) (CURRENT->current_nr_sectors > 0)
+
+/*
+ *  This struct defines the HD's and their types.
+ */
+struct hd_i_struct {
+	unsigned int head,sect,cyl,wpcom,lzone,ctl;
+};
+	
+#ifdef HD_TYPE
+static struct hd_i_struct hd_info[] = { HD_TYPE };
+static int NR_HD = ((sizeof (hd_info))/(sizeof (struct hd_i_struct)));
+#else
+static struct hd_i_struct hd_info[MAX_HD];
+static int NR_HD;
+#endif
+
+static struct hd_struct hd[MAX_HD<<6];
+static int hd_sizes[MAX_HD<<6];
+static int hd_blocksizes[MAX_HD<<6];
+static int hd_hardsectsizes[MAX_HD<<6];
+static int hd_maxsect[MAX_HD<<6];
+
+static struct timer_list device_timer;
+
+#define SET_TIMER 							\
+	do {								\
+		mod_timer(&device_timer, jiffies + TIMEOUT_VALUE);	\
+	} while (0)
+
+#define CLEAR_TIMER del_timer(&device_timer);
+
+#undef SET_INTR
+
+#define SET_INTR(x) \
+if ((DEVICE_INTR = (x)) != NULL) \
+	SET_TIMER; \
+else \
+	CLEAR_TIMER;
+
+
+#if (HD_DELAY > 0)
+unsigned long last_req;
+
+unsigned long read_timer(void)
+{
+	unsigned long t, flags;
+	int i;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	t = jiffies * 11932;
+    	outb_p(0, 0x43);
+	i = inb_p(0x40);
+	i |= inb(0x40) << 8;
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	return(t - i);
+}
+#endif
+
+void __init hd_setup(char *str, int *ints)
+{
+	int hdind = 0;
+
+	if (ints[0] != 3)
+		return;
+	if (hd_info[0].head != 0)
+		hdind=1;
+	hd_info[hdind].head = ints[2];
+	hd_info[hdind].sect = ints[3];
+	hd_info[hdind].cyl = ints[1];
+	hd_info[hdind].wpcom = 0;
+	hd_info[hdind].lzone = ints[1];
+	hd_info[hdind].ctl = (ints[2] > 8 ? 8 : 0);
+	NR_HD = hdind+1;
+}
+
+static void dump_status (const char *msg, unsigned int stat)
+{
+	unsigned long flags;
+	char devc;
+
+	devc = !QUEUE_EMPTY ? 'a' + DEVICE_NR(CURRENT->rq_dev) : '?';
+	save_flags (flags);
+	sti();
+#ifdef VERBOSE_ERRORS
+	printk("hd%c: %s: status=0x%02x { ", devc, msg, stat & 0xff);
+	if (stat & BUSY_STAT)	printk("Busy ");
+	if (stat & READY_STAT)	printk("DriveReady ");
+	if (stat & WRERR_STAT)	printk("WriteFault ");
+	if (stat & SEEK_STAT)	printk("SeekComplete ");
+	if (stat & DRQ_STAT)	printk("DataRequest ");
+	if (stat & ECC_STAT)	printk("CorrectedError ");
+	if (stat & INDEX_STAT)	printk("Index ");
+	if (stat & ERR_STAT)	printk("Error ");
+	printk("}\n");
+	if ((stat & ERR_STAT) == 0) {
+		hd_error = 0;
+	} else {
+		hd_error = inb(HD_ERROR);
+		printk("hd%c: %s: error=0x%02x { ", devc, msg, hd_error & 0xff);
+		if (hd_error & BBD_ERR)		printk("BadSector ");
+		if (hd_error & ECC_ERR)		printk("UncorrectableError ");
+		if (hd_error & ID_ERR)		printk("SectorIdNotFound ");
+		if (hd_error & ABRT_ERR)	printk("DriveStatusError ");
+		if (hd_error & TRK0_ERR)	printk("TrackZeroNotFound ");
+		if (hd_error & MARK_ERR)	printk("AddrMarkNotFound ");
+		printk("}");
+		if (hd_error & (BBD_ERR|ECC_ERR|ID_ERR|MARK_ERR)) {
+			printk(", CHS=%d/%d/%d",
+				(inb(HD_HCYL)<<8) + inb(HD_LCYL),
+				inb(HD_CURRENT) & 0xf, inb(HD_SECTOR));
+			if (!QUEUE_EMPTY)
+				printk(", sector=%ld", CURRENT->sector);
+		}
+		printk("\n");
+	}
+#else
+	printk("hd%c: %s: status=0x%02x.\n", devc, msg, stat & 0xff);
+	if ((stat & ERR_STAT) == 0) {
+		hd_error = 0;
+	} else {
+		hd_error = inb(HD_ERROR);
+		printk("hd%c: %s: error=0x%02x.\n", devc, msg, hd_error & 0xff);
+	}
+#endif	/* verbose errors */
+	restore_flags (flags);
+}
+
+void check_status(void)
+{
+	int i = inb_p(HD_STATUS);
+
+	if (!OK_STATUS(i)) {
+		dump_status("check_status", i);
+		bad_rw_intr();
+	}
+}
+
+static int controller_busy(void)
+{
+	int retries = 100000;
+	unsigned char status;
+
+	do {
+		status = inb_p(HD_STATUS);
+	} while ((status & BUSY_STAT) && --retries);
+	return status;
+}
+
+static int status_ok(void)
+{
+	unsigned char status = inb_p(HD_STATUS);
+
+	if (status & BUSY_STAT)
+		return 1;	/* Ancient, but does it make sense??? */
+	if (status & WRERR_STAT)
+		return 0;
+	if (!(status & READY_STAT))
+		return 0;
+	if (!(status & SEEK_STAT))
+		return 0;
+	return 1;
+}
+
+static int controller_ready(unsigned int drive, unsigned int head)
+{
+	int retry = 100;
+
+	do {
+		if (controller_busy() & BUSY_STAT)
+			return 0;
+		outb_p(0xA0 | (drive<<4) | head, HD_CURRENT);
+		if (status_ok())
+			return 1;
+	} while (--retry);
+	return 0;
+}
+
+static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
+		unsigned int head,unsigned int cyl,unsigned int cmd,
+		void (*intr_addr)(void))
+{
+	unsigned short port;
+
+#if (HD_DELAY > 0)
+	while (read_timer() - last_req < HD_DELAY)
+		/* nothing */;
+#endif
+	if (reset)
+		return;
+	if (!controller_ready(drive, head)) {
+		reset = 1;
+		return;
+	}
+	SET_INTR(intr_addr);
+	outb_p(hd_info[drive].ctl,HD_CMD);
+	port=HD_DATA;
+	outb_p(hd_info[drive].wpcom>>2,++port);
+	outb_p(nsect,++port);
+	outb_p(sect,++port);
+	outb_p(cyl,++port);
+	outb_p(cyl>>8,++port);
+	outb_p(0xA0|(drive<<4)|head,++port);
+	outb_p(cmd,++port);
+}
+
+static void hd_request (void);
+
+static int drive_busy(void)
+{
+	unsigned int i;
+	unsigned char c;
+
+	for (i = 0; i < 500000 ; i++) {
+		c = inb_p(HD_STATUS);
+		if ((c & (BUSY_STAT | READY_STAT | SEEK_STAT)) == STAT_OK)
+			return 0;
+	}
+	dump_status("reset timed out", c);
+	return 1;
+}
+
+static void reset_controller(void)
+{
+	int	i;
+
+	outb_p(4,HD_CMD);
+	for(i = 0; i < 1000; i++) barrier();
+	outb_p(hd_info[0].ctl & 0x0f,HD_CMD);
+	for(i = 0; i < 1000; i++) barrier();
+	if (drive_busy())
+		printk("hd: controller still busy\n");
+	else if ((hd_error = inb(HD_ERROR)) != 1)
+		printk("hd: controller reset failed: %02x\n",hd_error);
+}
+
+static void reset_hd(void)
+{
+	static int i;
+
+repeat:
+	if (reset) {
+		reset = 0;
+		i = -1;
+		reset_controller();
+	} else {
+		check_status();
+		if (reset)
+			goto repeat;
+	}
+	if (++i < NR_HD) {
+		special_op[i] = recalibrate[i] = 1;
+		hd_out(i,hd_info[i].sect,hd_info[i].sect,hd_info[i].head-1,
+			hd_info[i].cyl,WIN_SPECIFY,&reset_hd);
+		if (reset)
+			goto repeat;
+	} else
+		hd_request();
+}
+
+void do_reset_hd(void)
+{
+	DEVICE_INTR = NULL;
+	reset = 1;
+	reset_hd();
+}
+
+/*
+ * Ok, don't know what to do with the unexpected interrupts: on some machines
+ * doing a reset and a retry seems to result in an eternal loop. Right now I
+ * ignore it, and just set the timeout.
+ *
+ * On laptops (and "green" PCs), an unexpected interrupt occurs whenever the
+ * drive enters "idle", "standby", or "sleep" mode, so if the status looks
+ * "good", we just ignore the interrupt completely.
+ */
+void unexpected_hd_interrupt(void)
+{
+	unsigned int stat = inb_p(HD_STATUS);
+
+	if (stat & (BUSY_STAT|DRQ_STAT|ECC_STAT|ERR_STAT)) {
+		dump_status ("unexpected interrupt", stat);
+		SET_TIMER;
+	}
+}
+
+/*
+ * bad_rw_intr() now tries to be a bit smarter and does things
+ * according to the error returned by the controller.
+ * -Mika Liljeberg (liljeber@cs.Helsinki.FI)
+ */
+static void bad_rw_intr(void)
+{
+	int dev;
+
+	if (QUEUE_EMPTY)
+		return;
+	dev = DEVICE_NR(CURRENT->rq_dev);
+	if (++CURRENT->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) {
+		end_request(0);
+		special_op[dev] = recalibrate[dev] = 1;
+	} else if (CURRENT->errors % RESET_FREQ == 0)
+		reset = 1;
+	else if ((hd_error & TRK0_ERR) || CURRENT->errors % RECAL_FREQ == 0)
+		special_op[dev] = recalibrate[dev] = 1;
+	/* Otherwise just retry */
+}
+
+static inline int wait_DRQ(void)
+{
+	int retries = 100000, stat;
+
+	while (--retries > 0)
+		if ((stat = inb_p(HD_STATUS)) & DRQ_STAT)
+			return 0;
+	dump_status("wait_DRQ", stat);
+	return -1;
+}
+
+static void read_intr(void)
+{
+	int i, retries = 100000;
+
+	do {
+		i = (unsigned) inb_p(HD_STATUS);
+		if (i & BUSY_STAT)
+			continue;
+		if (!OK_STATUS(i))
+			break;
+		if (i & DRQ_STAT)
+			goto ok_to_read;
+	} while (--retries > 0);
+	dump_status("read_intr", i);
+	bad_rw_intr();
+	hd_request();
+	return;
+ok_to_read:
+	insw(HD_DATA,CURRENT->buffer,256);
+	CURRENT->sector++;
+	CURRENT->buffer += 512;
+	CURRENT->errors = 0;
+	i = --CURRENT->nr_sectors;
+	--CURRENT->current_nr_sectors;
+#ifdef DEBUG
+	printk("hd%c: read: sector %ld, remaining = %ld, buffer=0x%08lx\n",
+		dev+'a', CURRENT->sector, CURRENT->nr_sectors,
+		(unsigned long) CURRENT->buffer+512));
+#endif
+	if (CURRENT->current_nr_sectors <= 0)
+		end_request(1);
+	if (i > 0) {
+		SET_INTR(&read_intr);
+		return;
+	}
+	(void) inb_p(HD_STATUS);
+#if (HD_DELAY > 0)
+	last_req = read_timer();
+#endif
+	if (!QUEUE_EMPTY)
+		hd_request();
+	return;
+}
+
+static void write_intr(void)
+{
+	int i;
+	int retries = 100000;
+
+	do {
+		i = (unsigned) inb_p(HD_STATUS);
+		if (i & BUSY_STAT)
+			continue;
+		if (!OK_STATUS(i))
+			break;
+		if ((CURRENT->nr_sectors <= 1) || (i & DRQ_STAT))
+			goto ok_to_write;
+	} while (--retries > 0);
+	dump_status("write_intr", i);
+	bad_rw_intr();
+	hd_request();
+	return;
+ok_to_write:
+	CURRENT->sector++;
+	i = --CURRENT->nr_sectors;
+	--CURRENT->current_nr_sectors;
+	CURRENT->buffer += 512;
+	if (!i || (CURRENT->bh && !SUBSECTOR(i)))
+		end_request(1);
+	if (i > 0) {
+		SET_INTR(&write_intr);
+		outsw(HD_DATA,CURRENT->buffer,256);
+		sti();
+	} else {
+#if (HD_DELAY > 0)
+		last_req = read_timer();
+#endif
+		hd_request();
+	}
+	return;
+}
+
+static void recal_intr(void)
+{
+	check_status();
+#if (HD_DELAY > 0)
+	last_req = read_timer();
+#endif
+	hd_request();
+}
+
+/*
+ * This is another of the error-routines I don't know what to do with. The
+ * best idea seems to just set reset, and start all over again.
+ */
+static void hd_times_out(unsigned long dummy)
+{
+	unsigned int dev;
+
+	DEVICE_INTR = NULL;
+	if (QUEUE_EMPTY)
+		return;
+	disable_irq(HD_IRQ);
+	sti();
+	reset = 1;
+	dev = DEVICE_NR(CURRENT->rq_dev);
+	printk("hd%c: timeout\n", dev+'a');
+	if (++CURRENT->errors >= MAX_ERRORS) {
+#ifdef DEBUG
+		printk("hd%c: too many errors\n", dev+'a');
+#endif
+		end_request(0);
+	}
+	cli();
+	hd_request();
+	enable_irq(HD_IRQ);
+}
+
+int do_special_op (unsigned int dev)
+{
+	if (recalibrate[dev]) {
+		recalibrate[dev] = 0;
+		hd_out(dev,hd_info[dev].sect,0,0,0,WIN_RESTORE,&recal_intr);
+		return reset;
+	}
+	if (hd_info[dev].head > 16) {
+		printk ("hd%c: cannot handle device with more than 16 heads - giving up\n", dev+'a');
+		end_request(0);
+	}
+	special_op[dev] = 0;
+	return 1;
+}
+
+/*
+ * The driver enables interrupts as much as possible.  In order to do this,
+ * (a) the device-interrupt is disabled before entering hd_request(),
+ * and (b) the timeout-interrupt is disabled before the sti().
+ *
+ * Interrupts are still masked (by default) whenever we are exchanging
+ * data/cmds with a drive, because some drives seem to have very poor
+ * tolerance for latency during I/O. The IDE driver has support to unmask
+ * interrupts for non-broken hardware, so use that driver if required.
+ */
+static void hd_request(void)
+{
+	unsigned int dev, block, nsect, sec, track, head, cyl;
+
+	if (!QUEUE_EMPTY && CURRENT->rq_status == RQ_INACTIVE) return;
+	if (DEVICE_INTR)
+		return;
+repeat:
+	del_timer(&device_timer);
+	sti();
+	INIT_REQUEST;
+	if (reset) {
+		cli();
+		reset_hd();
+		return;
+	}
+	dev = MINOR(CURRENT->rq_dev);
+	block = CURRENT->sector;
+	nsect = CURRENT->nr_sectors;
+	if (dev >= (NR_HD<<6) || block >= hd[dev].nr_sects || ((block+nsect) > hd[dev].nr_sects)) {
+#ifdef DEBUG
+		if (dev >= (NR_HD<<6))
+			printk("hd: bad minor number: device=%s\n",
+			       kdevname(CURRENT->rq_dev));
+		else
+			printk("hd%c: bad access: block=%d, count=%d\n",
+				(MINOR(CURRENT->rq_dev)>>6)+'a', block, nsect);
+#endif
+		end_request(0);
+		goto repeat;
+	}
+	block += hd[dev].start_sect;
+	dev >>= 6;
+	if (special_op[dev]) {
+		if (do_special_op(dev))
+			goto repeat;
+		return;
+	}
+	sec   = block % hd_info[dev].sect + 1;
+	track = block / hd_info[dev].sect;
+	head  = track % hd_info[dev].head;
+	cyl   = track / hd_info[dev].head;
+#ifdef DEBUG
+	printk("hd%c: %sing: CHS=%d/%d/%d, sectors=%d, buffer=0x%08lx\n",
+		dev+'a', (CURRENT->cmd == READ)?"read":"writ",
+		cyl, head, sec, nsect, (unsigned long) CURRENT->buffer);
+#endif
+	if (CURRENT->cmd == READ) {
+		hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr);
+		if (reset)
+			goto repeat;
+		return;
+	}
+	if (CURRENT->cmd == WRITE) {
+		hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
+		if (reset)
+			goto repeat;
+		if (wait_DRQ()) {
+			bad_rw_intr();
+			goto repeat;
+		}
+		outsw(HD_DATA,CURRENT->buffer,256);
+		return;
+	}
+	panic("unknown hd-command");
+}
+
+static void do_hd_request (request_queue_t * q)
+{
+	disable_irq(HD_IRQ);
+	hd_request();
+	enable_irq(HD_IRQ);
+}
+
+static int hd_ioctl(struct inode * inode, struct file * file,
+	unsigned int cmd, unsigned long arg)
+{
+	struct hd_geometry *loc = (struct hd_geometry *) arg;
+	int dev;
+
+	if ((!inode) || !(inode->i_rdev))
+		return -EINVAL;
+	dev = DEVICE_NR(inode->i_rdev);
+	if (dev >= NR_HD)
+		return -EINVAL;
+	switch (cmd) {
+		case HDIO_GETGEO:
+		{
+			struct hd_geometry g; 
+			if (!loc)  return -EINVAL;
+			g.heads = hd_info[dev].head;
+			g.sectors = hd_info[dev].sect;
+			g.cylinders = hd_info[dev].cyl;
+			g.start = hd[MINOR(inode->i_rdev)].start_sect;
+			return copy_to_user(loc, &g, sizeof g) ? -EFAULT : 0; 
+		}
+
+         	case BLKGETSIZE:   /* Return device size */
+			return put_user(hd[MINOR(inode->i_rdev)].nr_sects, 
+					(unsigned long *) arg);
+         	case BLKGETSIZE64:
+			return put_user((u64)hd[MINOR(inode->i_rdev)].nr_sects << 9, 
+					(u64 *) arg);
+
+		case BLKRRPART: /* Re-read partition tables */
+			if (!capable(CAP_SYS_ADMIN))
+				return -EACCES;
+			return revalidate_hddisk(inode->i_rdev, 1);
+
+		case BLKROSET:
+		case BLKROGET:
+		case BLKRASET:
+		case BLKRAGET:
+		case BLKFLSBUF:
+		case BLKPG:
+			return blk_ioctl(inode->i_rdev, cmd, arg);
+
+		default:
+			return -EINVAL;
+	}
+}
+
+static int hd_open(struct inode * inode, struct file * filp)
+{
+	int target;
+	target =  DEVICE_NR(inode->i_rdev);
+
+	if (target >= NR_HD)
+		return -ENODEV;
+	while (busy[target])
+		sleep_on(&busy_wait);
+	access_count[target]++;
+	return 0;
+}
+
+/*
+ * Releasing a block device means we sync() it, so that it can safely
+ * be forgotten about...
+ */
+static int hd_release(struct inode * inode, struct file * file)
+{
+        int target =  DEVICE_NR(inode->i_rdev);
+	access_count[target]--;
+	return 0;
+}
+
+extern struct block_device_operations hd_fops;
+
+static struct gendisk hd_gendisk = {
+	major:		MAJOR_NR,
+	major_name:	"hd",
+	minor_shift:	6,
+	max_p:		1 << 6,
+	part:		hd,
+	sizes:		hd_sizes,
+	fops:		&hd_fops,
+};
+	
+static void hd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	void (*handler)(void) = DEVICE_INTR;
+
+	DEVICE_INTR = NULL;
+	del_timer(&device_timer);
+	if (!handler)
+		handler = unexpected_hd_interrupt;
+	handler();
+	sti();
+}
+
+static struct block_device_operations hd_fops = {
+	open:		hd_open,
+	release:	hd_release,
+	ioctl:		hd_ioctl,
+};
+
+/*
+ * This is the hard disk IRQ description. The SA_INTERRUPT in sa_flags
+ * means we run the IRQ-handler with interrupts disabled:  this is bad for
+ * interrupt latency, but anything else has led to problems on some
+ * machines.
+ *
+ * We enable interrupts in some of the routines after making sure it's
+ * safe.
+ */
+static void __init hd_geninit(void)
+{
+	int drive;
+
+	for(drive=0; drive < (MAX_HD << 6); drive++) {
+		hd_blocksizes[drive] = 1024;
+		hd_hardsectsizes[drive] = 512;
+		hd_maxsect[drive]=255;
+	}
+	blksize_size[MAJOR_NR] = hd_blocksizes;
+	hardsect_size[MAJOR_NR] = hd_hardsectsizes;
+	max_sectors[MAJOR_NR] = hd_maxsect;
+
+#ifdef __i386__
+	if (!NR_HD) {
+		extern struct drive_info drive_info;
+		unsigned char *BIOS = (unsigned char *) &drive_info;
+		unsigned long flags;
+		int cmos_disks;
+
+		for (drive=0 ; drive<2 ; drive++) {
+			hd_info[drive].cyl = *(unsigned short *) BIOS;
+			hd_info[drive].head = *(2+BIOS);
+			hd_info[drive].wpcom = *(unsigned short *) (5+BIOS);
+			hd_info[drive].ctl = *(8+BIOS);
+			hd_info[drive].lzone = *(unsigned short *) (12+BIOS);
+			hd_info[drive].sect = *(14+BIOS);
+#ifdef does_not_work_for_everybody_with_scsi_but_helps_ibm_vp
+			if (hd_info[drive].cyl && NR_HD == drive)
+				NR_HD++;
+#endif
+			BIOS += 16;
+		}
+
+	/*
+		We query CMOS about hard disks : it could be that 
+		we have a SCSI/ESDI/etc controller that is BIOS
+		compatible with ST-506, and thus showing up in our
+		BIOS table, but not register compatible, and therefore
+		not present in CMOS.
+
+		Furthermore, we will assume that our ST-506 drives
+		<if any> are the primary drives in the system, and 
+		the ones reflected as drive 1 or 2.
+
+		The first drive is stored in the high nibble of CMOS
+		byte 0x12, the second in the low nibble.  This will be
+		either a 4 bit drive type or 0xf indicating use byte 0x19 
+		for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS.
+
+		Needless to say, a non-zero value means we have 
+		an AT controller hard disk for that drive.
+
+		Currently the rtc_lock is a bit academic since this
+		driver is non-modular, but someday... ?         Paul G.
+	*/
+
+		spin_lock_irqsave(&rtc_lock, flags);
+		cmos_disks = CMOS_READ(0x12);
+		spin_unlock_irqrestore(&rtc_lock, flags);
+
+		if (cmos_disks & 0xf0) {
+			if (cmos_disks & 0x0f)
+				NR_HD = 2;
+			else
+				NR_HD = 1;
+		}
+	}
+#endif /* __i386__ */
+#ifdef __arm__
+	if (!NR_HD) {
+		/* We don't know anything about the drive.  This means
+		 * that you *MUST* specify the drive parameters to the
+		 * kernel yourself.
+		 */
+		printk("hd: no drives specified - use hd=cyl,head,sectors"
+			" on kernel command line\n");
+	}
+#endif
+
+	for (drive=0 ; drive < NR_HD ; drive++) {
+		hd[drive<<6].nr_sects = hd_info[drive].head *
+			hd_info[drive].sect * hd_info[drive].cyl;
+		printk ("hd%c: %ldMB, CHS=%d/%d/%d\n", drive+'a',
+			hd[drive<<6].nr_sects / 2048, hd_info[drive].cyl,
+			hd_info[drive].head, hd_info[drive].sect);
+	}
+	if (!NR_HD)
+		return;
+
+	if (request_irq(HD_IRQ, hd_interrupt, SA_INTERRUPT, "hd", NULL)) {
+		printk("hd: unable to get IRQ%d for the hard disk driver\n",
+			HD_IRQ);
+		NR_HD = 0;
+		return;
+	}
+	request_region(HD_DATA, 8, "hd");
+	request_region(HD_CMD, 1, "hd(cmd)");
+
+	hd_gendisk.nr_real = NR_HD;
+
+	for(drive=0; drive < NR_HD; drive++)
+		register_disk(&hd_gendisk, MKDEV(MAJOR_NR,drive<<6), 1<<6,
+			&hd_fops, hd_info[drive].head * hd_info[drive].sect *
+			hd_info[drive].cyl);
+}
+
+int __init hd_init(void)
+{
+	if (devfs_register_blkdev(MAJOR_NR,"hd",&hd_fops)) {
+		printk("hd: unable to get major %d for hard disk\n",MAJOR_NR);
+		return -1;
+	}
+	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
+	read_ahead[MAJOR_NR] = 8;		/* 8 sector (4kB) read-ahead */
+	add_gendisk(&hd_gendisk);
+	init_timer(&device_timer);
+	device_timer.function = hd_times_out;
+	hd_geninit();
+	return 0;
+}
+
+#define DEVICE_BUSY busy[target]
+#define USAGE access_count[target]
+#define CAPACITY (hd_info[target].head*hd_info[target].sect*hd_info[target].cyl)
+/* We assume that the BIOS parameters do not change, so the disk capacity
+   will not change */
+#undef MAYBE_REINIT
+#define GENDISK_STRUCT hd_gendisk
+
+/*
+ * This routine is called to flush all partitions and partition tables
+ * for a changed disk, and then re-read the new partition table.
+ * If we are revalidating a disk because of a media change, then we
+ * enter with usage == 0.  If we are using an ioctl, we automatically have
+ * usage == 1 (we need an open channel to use an ioctl :-), so this
+ * is our limit.
+ */
+static int revalidate_hddisk(kdev_t dev, int maxusage)
+{
+	int target;
+	struct gendisk * gdev;
+	int max_p;
+	int start;
+	int i;
+	long flags;
+
+	target = DEVICE_NR(dev);
+	gdev = &GENDISK_STRUCT;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	if (DEVICE_BUSY || USAGE > maxusage) {
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return -EBUSY;
+	}
+	DEVICE_BUSY = 1;
+	spin_unlock_irqrestore(&io_request_lock, flags);
+
+	max_p = gdev->max_p;
+	start = target << gdev->minor_shift;
+
+	for (i=max_p - 1; i >=0 ; i--) {
+		int minor = start + i;
+		invalidate_device(MKDEV(MAJOR_NR, minor), 1);
+		gdev->part[minor].start_sect = 0;
+		gdev->part[minor].nr_sects = 0;
+	}
+
+#ifdef MAYBE_REINIT
+	MAYBE_REINIT;
+#endif
+
+	grok_partitions(gdev, target, 1<<6, CAPACITY);
+
+	DEVICE_BUSY = 0;
+	wake_up(&busy_wait);
+	return 0;
+}
+
+static int parse_hd_setup (char *line) {
+	int ints[6];
+
+	(void) get_options(line, ARRAY_SIZE(ints), ints);
+	hd_setup(NULL, ints);
+
+	return 1;
+}
+__setup("hd=", parse_hd_setup);
+
+module_init(hd_init);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/ht6560b.c linux-2.4.21-pre6/drivers/ide/legacy/ht6560b.c
--- linux-2.4.20/drivers/ide/legacy/ht6560b.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/legacy/ht6560b.c	2003-03-26 23:49:10.000000000 +0000
@@ -0,0 +1,430 @@
+/*
+ *  linux/drivers/ide/legacy/ht6560b.c		Version 0.07	Feb  1, 2000
+ *
+ *  Copyright (C) 1995-2000  Linus Torvalds & author (see below)
+ */
+
+/*
+ *
+ *  Version 0.01        Initial version hacked out of ide.c
+ *
+ *  Version 0.02        Added support for PIO modes, auto-tune
+ *
+ *  Version 0.03        Some cleanups
+ *
+ *  Version 0.05        PIO mode cycle timings auto-tune using bus-speed
+ *
+ *  Version 0.06        Prefetch mode now defaults no OFF. To set
+ *                      prefetch mode OFF/ON use "hdparm -p8/-p9".
+ *                      Unmask irq is disabled when prefetch mode
+ *                      is enabled.
+ *
+ *  Version 0.07        Trying to fix CD-ROM detection problem.
+ *                      "Prefetch" mode bit OFF for ide disks and
+ *                      ON for anything else.
+ *
+ *
+ *  HT-6560B EIDE-controller support
+ *  To activate controller support use kernel parameter "ide0=ht6560b".
+ *  Use hdparm utility to enable PIO mode support.
+ *
+ *  Author:    Mikko Ala-Fossi            <maf@iki.fi>
+ *             Jan Evert van Grootheest   <janevert@iae.nl>
+ *
+ *  Try:  http://www.maf.iki.fi/~maf/ht6560b/
+ */
+
+#define HT6560B_VERSION "v0.07"
+
+#undef REALLY_SLOW_IO		/* most systems can safely undef this */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#ifdef CONFIG_BLK_DEV_HT6560B_MODULE
+# define _IDE_C
+# include "ide_modes.h"
+# undef _IDE_C
+#else
+# include "ide_modes.h"
+#endif /* CONFIG_BLK_DEV_HT6560B_MODULE */
+
+/* #define DEBUG */  /* remove comments for DEBUG messages */
+
+/*
+ * The special i/o-port that HT-6560B uses to configuration:
+ *    bit0 (0x01): "1" selects secondary interface
+ *    bit2 (0x04): "1" enables FIFO function
+ *    bit5 (0x20): "1" enables prefetched data read function  (???)
+ *
+ * The special i/o-port that HT-6560A uses to configuration:
+ *    bit0 (0x01): "1" selects secondary interface
+ *    bit1 (0x02): "1" enables prefetched data read function
+ *    bit2 (0x04): "0" enables multi-master system	      (?)
+ *    bit3 (0x08): "1" 3 cycle time, "0" 2 cycle time	      (?)
+ */
+#define HT_CONFIG_PORT	  0x3e6
+#define HT_CONFIG(drivea) (u8)(((drivea)->drive_data & 0xff00) >> 8)
+/*
+ * FIFO + PREFETCH (both a/b-model)
+ */
+#define HT_CONFIG_DEFAULT 0x1c /* no prefetch */
+/* #define HT_CONFIG_DEFAULT 0x3c */ /* with prefetch */
+#define HT_SECONDARY_IF	  0x01
+#define HT_PREFETCH_MODE  0x20
+
+/*
+ * ht6560b Timing values:
+ *
+ * I reviewed some assembler source listings of htide drivers and found
+ * out how they setup those cycle time interfacing values, as they at Holtek
+ * call them. IDESETUP.COM that is supplied with the drivers figures out
+ * optimal values and fetches those values to drivers. I found out that
+ * they use IDE_SELECT_REG to fetch timings to the ide board right after
+ * interface switching. After that it was quite easy to add code to
+ * ht6560b.c.
+ *
+ * IDESETUP.COM gave me values 0x24, 0x45, 0xaa, 0xff that worked fine
+ * for hda and hdc. But hdb needed higher values to work, so I guess
+ * that sometimes it is necessary to give higher value than IDESETUP
+ * gives.   [see cmd640.c for an extreme example of this. -ml]
+ *
+ * Perhaps I should explain something about these timing values:
+ * The higher nibble of value is the Recovery Time  (rt) and the lower nibble
+ * of the value is the Active Time  (at). Minimum value 2 is the fastest and
+ * the maximum value 15 is the slowest. Default values should be 15 for both.
+ * So 0x24 means 2 for rt and 4 for at. Each of the drives should have
+ * both values, and IDESETUP gives automatically rt=15 st=15 for CDROMs or
+ * similar. If value is too small there will be all sorts of failures.
+ *
+ * Timing byte consists of
+ *	High nibble:  Recovery Cycle Time  (rt)
+ *	     The valid values range from 2 to 15. The default is 15.
+ *
+ *	Low nibble:   Active Cycle Time	   (at)
+ *	     The valid values range from 2 to 15. The default is 15.
+ *
+ * You can obtain optimized timing values by running Holtek IDESETUP.COM
+ * for DOS. DOS drivers get their timing values from command line, where
+ * the first value is the Recovery Time and the second value is the
+ * Active Time for each drive. Smaller value gives higher speed.
+ * In case of failures you should probably fall back to a higher value.
+ */
+#define HT_TIMING(drivea) (u8)((drivea)->drive_data & 0x00ff)
+#define HT_TIMING_DEFAULT 0xff
+
+/*
+ * This routine handles interface switching for the peculiar hardware design
+ * on the F.G.I./Holtek HT-6560B VLB IDE interface.
+ * The HT-6560B can only enable one IDE port at a time, and requires a
+ * silly sequence (below) whenever we switch between primary and secondary.
+ */
+
+/*
+ * This routine is invoked from ide.c to prepare for access to a given drive.
+ */
+static void ht6560b_selectproc (ide_drive_t *drive)
+{
+	unsigned long flags;
+	static u8 current_select = 0;
+	static u8 current_timing = 0;
+	u8 select, timing;
+	
+	local_irq_save(flags);
+	
+	select = HT_CONFIG(drive);
+	timing = HT_TIMING(drive);
+	
+	if (select != current_select || timing != current_timing) {
+		current_select = select;
+		current_timing = timing;
+		if (drive->media != ide_disk || !drive->present)
+			select |= HT_PREFETCH_MODE;
+		(void) HWIF(drive)->INB(HT_CONFIG_PORT);
+		(void) HWIF(drive)->INB(HT_CONFIG_PORT);
+		(void) HWIF(drive)->INB(HT_CONFIG_PORT);
+		(void) HWIF(drive)->INB(HT_CONFIG_PORT);
+		HWIF(drive)->OUTB(select, HT_CONFIG_PORT);
+		/*
+		 * Set timing for this drive:
+		 */
+		HWIF(drive)->OUTB(timing, IDE_SELECT_REG);
+		(void) HWIF(drive)->INB(IDE_STATUS_REG);
+#ifdef DEBUG
+		printk("ht6560b: %s: select=%#x timing=%#x\n",
+			drive->name, select, timing);
+#endif
+	}
+	local_irq_restore(flags);
+}
+
+/*
+ * Autodetection and initialization of ht6560b
+ */
+static int __init try_to_init_ht6560b(void)
+{
+	u8 orig_value;
+	int i;
+	
+	/* Autodetect ht6560b */
+	if ((orig_value = inb(HT_CONFIG_PORT)) == 0xff)
+		return 0;
+	
+	for (i=3;i>0;i--) {
+		outb(0x00, HT_CONFIG_PORT);
+		if (!( (~inb(HT_CONFIG_PORT)) & 0x3f )) {
+			outb(orig_value, HT_CONFIG_PORT);
+			return 0;
+		}
+	}
+	outb(0x00, HT_CONFIG_PORT);
+	if ((~inb(HT_CONFIG_PORT))& 0x3f) {
+		outb(orig_value, HT_CONFIG_PORT);
+		return 0;
+	}
+	/*
+	 * Ht6560b autodetected
+	 */
+	outb(HT_CONFIG_DEFAULT, HT_CONFIG_PORT);
+	outb(HT_TIMING_DEFAULT, 0x1f6);  /* IDE_SELECT_REG */
+	(void) inb(0x1f7);               /* IDE_STATUS_REG */
+	
+	printk("\nht6560b " HT6560B_VERSION
+	       ": chipset detected and initialized"
+#ifdef DEBUG
+	       " with debug enabled"
+#endif
+		);
+	return 1;
+}
+
+static u8 ht_pio2timings(ide_drive_t *drive, u8 pio)
+{
+	int active_time, recovery_time;
+	int active_cycles, recovery_cycles;
+	ide_pio_data_t d;
+	int bus_speed = system_bus_clock();
+	
+        if (pio) {
+		pio = ide_get_best_pio_mode(drive, pio, 5, &d);
+		
+		/*
+		 *  Just like opti621.c we try to calculate the
+		 *  actual cycle time for recovery and activity
+		 *  according system bus speed.
+		 */
+		active_time = ide_pio_timings[pio].active_time;
+		recovery_time = d.cycle_time 
+			- active_time
+			- ide_pio_timings[pio].setup_time;
+		/*
+		 *  Cycle times should be Vesa bus cycles
+		 */
+		active_cycles   = (active_time   * bus_speed + 999) / 1000;
+		recovery_cycles = (recovery_time * bus_speed + 999) / 1000;
+		/*
+		 *  Upper and lower limits
+		 */
+		if (active_cycles   < 2)  active_cycles   = 2;
+		if (recovery_cycles < 2)  recovery_cycles = 2;
+		if (active_cycles   > 15) active_cycles   = 15;
+		if (recovery_cycles > 15) recovery_cycles = 0;  /* 0==16 */
+		
+#ifdef DEBUG
+		printk("ht6560b: drive %s setting pio=%d recovery=%d (%dns) active=%d (%dns)\n", drive->name, pio, recovery_cycles, recovery_time, active_cycles, active_time);
+#endif
+		
+		return (u8)((recovery_cycles << 4) | active_cycles);
+	} else {
+		
+#ifdef DEBUG
+		printk("ht6560b: drive %s setting pio=0\n", drive->name);
+#endif
+		
+		return HT_TIMING_DEFAULT;    /* default setting */
+	}
+}
+
+/*
+ *  Enable/Disable so called prefetch mode
+ */
+static void ht_set_prefetch(ide_drive_t *drive, u8 state)
+{
+	unsigned long flags;
+	int t = HT_PREFETCH_MODE << 8;
+	
+	spin_lock_irqsave(&io_request_lock, flags);
+	
+	/*
+	 *  Prefetch mode and unmask irq seems to conflict
+	 */
+	if (state) {
+		drive->drive_data |= t;   /* enable prefetch mode */
+		drive->no_unmask = 1;
+		drive->unmask = 0;
+	} else {
+		drive->drive_data &= ~t;  /* disable prefetch mode */
+		drive->no_unmask = 0;
+	}
+	
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	
+#ifdef DEBUG
+	printk("ht6560b: drive %s prefetch mode %sabled\n", drive->name, (state ? "en" : "dis"));
+#endif
+}
+
+static void tune_ht6560b (ide_drive_t *drive, u8 pio)
+{
+	unsigned long flags;
+	u8 timing;
+	
+	switch (pio) {
+	case 8:         /* set prefetch off */
+	case 9:         /* set prefetch on */
+		ht_set_prefetch(drive, pio & 1);
+		return;
+	}
+	
+	timing = ht_pio2timings(drive, pio);
+	
+	spin_lock_irqsave(&io_request_lock, flags);
+	
+	drive->drive_data &= 0xff00;
+	drive->drive_data |= timing;
+	
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	
+#ifdef DEBUG
+	printk("ht6560b: drive %s tuned to pio mode %#x timing=%#x\n", drive->name, pio, timing);
+#endif
+}
+
+void __init probe_ht6560b (void)
+{
+	int t;
+	
+	request_region(HT_CONFIG_PORT, 1, ide_hwifs[0].name);
+	ide_hwifs[0].chipset = ide_ht6560b;
+	ide_hwifs[1].chipset = ide_ht6560b;
+	ide_hwifs[0].selectproc = &ht6560b_selectproc;
+	ide_hwifs[1].selectproc = &ht6560b_selectproc;
+	ide_hwifs[0].tuneproc = &tune_ht6560b;
+	ide_hwifs[1].tuneproc = &tune_ht6560b;
+	ide_hwifs[0].serialized = 1;  /* is this needed? */
+	ide_hwifs[1].serialized = 1;  /* is this needed? */
+	ide_hwifs[0].mate = &ide_hwifs[1];
+	ide_hwifs[1].mate = &ide_hwifs[0];
+	ide_hwifs[1].channel = 1;
+			
+	/*
+	 * Setting default configurations for drives
+	 */
+	t = (HT_CONFIG_DEFAULT << 8);
+	t |= HT_TIMING_DEFAULT;
+	ide_hwifs[0].drives[0].drive_data = t;
+	ide_hwifs[0].drives[1].drive_data = t;
+	t |= (HT_SECONDARY_IF << 8);
+	ide_hwifs[1].drives[0].drive_data = t;
+	ide_hwifs[1].drives[1].drive_data = t;
+
+#ifndef HWIF_PROBE_CLASSIC_METHOD
+	probe_hwif_init(&ide_hwifs[0]);
+	probe_hwif_init(&ide_hwifs[1]);
+#endif /* HWIF_PROBE_CLASSIC_METHOD */
+
+}
+
+void __init ht6560b_release (void)
+{
+	if (ide_hwifs[0].chipset != ide_ht6560b &&
+	    ide_hwifs[1].chipset != ide_ht6560b)
+                return;
+
+	ide_hwifs[0].chipset = ide_unknown;
+	ide_hwifs[1].chipset = ide_unknown;
+	ide_hwifs[0].tuneproc = NULL;
+	ide_hwifs[1].tuneproc = NULL;
+	ide_hwifs[0].selectproc = NULL;
+	ide_hwifs[1].selectproc = NULL;
+	ide_hwifs[0].serialized = 0;
+	ide_hwifs[1].serialized = 0;
+	ide_hwifs[0].mate = NULL;
+	ide_hwifs[1].mate = NULL;
+
+	ide_hwifs[0].drives[0].drive_data = 0;
+	ide_hwifs[0].drives[1].drive_data = 0;
+	ide_hwifs[1].drives[0].drive_data = 0;
+	ide_hwifs[1].drives[1].drive_data = 0;
+	release_region(HT_CONFIG_PORT, 1);
+}
+
+#ifndef MODULE
+/*
+ * init_ht6560b:
+ *
+ * called by ide.c when parsing command line
+ */
+
+void __init init_ht6560b (void)
+{
+	if (check_region(HT_CONFIG_PORT,1)) {
+		printk(KERN_NOTICE "%s: HT_CONFIG_PORT not found\n",
+			__FUNCTION__);
+		return;
+	}
+	if (!try_to_init_ht6560b()) {
+                printk(KERN_NOTICE "%s: HBA not found\n", __FUNCTION__);
+		return;
+	}
+	probe_ht6560b();
+}
+
+#else
+
+MODULE_AUTHOR("See Local File");
+MODULE_DESCRIPTION("HT-6560B EIDE-controller support");
+MODULE_LICENSE("GPL");
+
+int __init ht6560b_mod_init(void)
+{
+	if (check_region(HT_CONFIG_PORT,1)) {
+		printk(KERN_NOTICE "%s: HT_CONFIG_PORT not found\n",
+			__FUNCTION__);
+		return -ENODEV;
+	}
+
+	if (!try_to_init_ht6560b()) {
+		printk(KERN_NOTICE "%s: HBA not found\n", __FUNCTION__);
+		return -ENODEV;
+	}
+
+	probe_ht6560b();
+        if (ide_hwifs[0].chipset != ide_ht6560b &&
+            ide_hwifs[1].chipset != ide_ht6560b) {
+                ht6560b_release();
+                return -ENODEV;
+        }
+        return 0;
+}
+module_init(ht6560b_mod_init);
+
+void __init ht6560b_mod_exit(void)
+{
+        ht6560b_release();
+}
+module_exit(ht6560b_mod_exit);
+#endif
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/ide-cs.c linux-2.4.21-pre6/drivers/ide/legacy/ide-cs.c
--- linux-2.4.20/drivers/ide/legacy/ide-cs.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/legacy/ide-cs.c	2003-03-26 23:49:25.000000000 +0000
@@ -0,0 +1,500 @@
+/*======================================================================
+
+    A driver for PCMCIA IDE/ATA disk cards
+
+    ide_cs.c 1.26 1999/11/16 02:10:49
+
+    The contents of this file are subject to the Mozilla Public
+    License Version 1.1 (the "License"); you may not use this file
+    except in compliance with the License. You may obtain a copy of
+    the License at http://www.mozilla.org/MPL/
+
+    Software distributed under the License is distributed on an "AS
+    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+    implied. See the License for the specific language governing
+    rights and limitations under the License.
+
+    The initial developer of the original code is David A. Hinds
+    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+
+    Alternatively, the contents of this file may be used under the
+    terms of the GNU General Public License version 2 (the "GPL"), in which
+    case the provisions of the GPL are applicable instead of the
+    above.  If you wish to allow the use of your version of this file
+    only under the terms of the GPL and not to allow others to use
+    your version of this file under the MPL, indicate your decision
+    by deleting the provisions above and replace them with the notice
+    and other provisions required by the GPL.  If you do not delete
+    the provisions above, a recipient may use your version of this
+    file under either the MPL or the GPL.
+    
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <linux/hdreg.h>
+#include <linux/major.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/cisreg.h>
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static char *version =
+"ide_cs.c 1.26 1999/11/16 02:10:49 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* Bit map of interrupts to choose from */
+static u_int irq_mask = 0xdeb8;
+static int irq_list[4] = { -1 };
+
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+
+MODULE_LICENSE("GPL");
+
+
+/*====================================================================*/
+
+static const char ide_major[] = {
+    IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR,
+#ifdef IDE4_MAJOR
+    IDE4_MAJOR, IDE5_MAJOR
+#endif
+};
+
+typedef struct ide_info_t {
+    dev_link_t	link;
+    int		ndev;
+    dev_node_t	node;
+    int		hd;
+    struct tq_struct rel_task;
+} ide_info_t;
+
+static void ide_config(dev_link_t *link);
+static void ide_release(void *arg);
+static int ide_event(event_t event, int priority,
+		     event_callback_args_t *args);
+
+static dev_info_t dev_info = "ide-cs";
+
+static dev_link_t *ide_attach(void);
+static void ide_detach(dev_link_t *);
+
+static dev_link_t *dev_list = NULL;
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+/*======================================================================
+
+    ide_attach() creates an "instance" of the driver, allocating
+    local data structures for one device.  The device is registered
+    with Card Services.
+
+======================================================================*/
+
+static dev_link_t *ide_attach(void)
+{
+    ide_info_t *info;
+    dev_link_t *link;
+    client_reg_t client_reg;
+    int i, ret;
+    
+    DEBUG(0, "ide_attach()\n");
+
+    /* Create new ide device */
+    info = kmalloc(sizeof(*info), GFP_KERNEL);
+    if (!info) return NULL;
+    memset(info, 0, sizeof(*info));
+    link = &info->link; link->priv = info;
+    INIT_TQUEUE(&info->rel_task, ide_release, link);
+
+    link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+    link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
+    link->io.IOAddrLines = 3;
+    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+    link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+    if (irq_list[0] == -1)
+	link->irq.IRQInfo2 = irq_mask;
+    else
+	for (i = 0; i < 4; i++)
+	    link->irq.IRQInfo2 |= 1 << irq_list[i];
+    link->conf.Attributes = CONF_ENABLE_IRQ;
+    link->conf.Vcc = 50;
+    link->conf.IntType = INT_MEMORY_AND_IO;
+    
+    /* Register with Card Services */
+    link->next = dev_list;
+    dev_list = link;
+    client_reg.dev_info = &dev_info;
+    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+    client_reg.EventMask =
+	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+    client_reg.event_handler = &ide_event;
+    client_reg.Version = 0x0210;
+    client_reg.event_callback_args.client_data = link;
+    ret = CardServices(RegisterClient, &link->handle, &client_reg);
+    if (ret != CS_SUCCESS) {
+	cs_error(link->handle, RegisterClient, ret);
+	ide_detach(link);
+	return NULL;
+    }
+    
+    return link;
+} /* ide_attach */
+
+/*======================================================================
+
+    This deletes a driver "instance".  The device is de-registered
+    with Card Services.  If it has been released, all local data
+    structures are freed.  Otherwise, the structures will be freed
+    when the device is released.
+
+======================================================================*/
+
+static void ide_detach(dev_link_t *link)
+{
+    dev_link_t **linkp;
+    ide_info_t *info = link->priv;
+    int ret;
+
+    DEBUG(0, "ide_detach(0x%p)\n", link);
+    
+    /* Locate device structure */
+    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+	if (*linkp == link) break;
+    if (*linkp == NULL)
+	return;
+
+    if (link->state & DEV_CONFIG) {
+	schedule_task(&info->rel_task);
+	flush_scheduled_tasks();
+    }
+    
+    if (link->handle) {
+	ret = CardServices(DeregisterClient, link->handle);
+	if (ret != CS_SUCCESS)
+	    cs_error(link->handle, DeregisterClient, ret);
+    }
+    
+    /* Unlink, free device structure */
+    *linkp = link->next;
+    kfree(info);
+    
+} /* ide_detach */
+
+/*======================================================================
+
+    ide_config() is scheduled to run after a CARD_INSERTION event
+    is received, to configure the PCMCIA socket, and to make the
+    ide device available to the system.
+
+======================================================================*/
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
+
+#define CFG_CHECK(fn, args...) \
+if (CardServices(fn, args) != 0) goto next_entry
+
+int idecs_register (int arg1, int arg2, int irq)
+{
+        hw_regs_t hw;
+        ide_init_hwif_ports(&hw, (ide_ioreg_t) arg1, (ide_ioreg_t) arg2, NULL);
+        hw.irq = irq;
+        hw.chipset = ide_pci; /* this enables IRQ sharing w/ PCI irqs */
+        return ide_register_hw(&hw, NULL);
+}
+
+void ide_config(dev_link_t *link)
+{
+    client_handle_t handle = link->handle;
+    ide_info_t *info = link->priv;
+    tuple_t tuple;
+    u_short buf[128];
+    cisparse_t parse;
+    config_info_t conf;
+    cistpl_cftable_entry_t *cfg = &parse.cftable_entry;
+    cistpl_cftable_entry_t dflt = { 0 };
+    int i, pass, last_ret, last_fn, hd=-1, io_base, ctl_base;
+
+    DEBUG(0, "ide_config(0x%p)\n", link);
+    
+    tuple.TupleData = (cisdata_t *)buf;
+    tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
+    tuple.Attributes = 0;
+    tuple.DesiredTuple = CISTPL_CONFIG;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    CS_CHECK(GetTupleData, handle, &tuple);
+    CS_CHECK(ParseTuple, handle, &tuple, &parse);
+    link->conf.ConfigBase = parse.config.base;
+    link->conf.Present = parse.config.rmask[0];
+    
+    /* Configure card */
+    link->state |= DEV_CONFIG;
+
+    /* Not sure if this is right... look up the current Vcc */
+    CS_CHECK(GetConfigurationInfo, handle, &conf);
+    link->conf.Vcc = conf.Vcc;
+    
+    pass = io_base = ctl_base = 0;
+    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+    tuple.Attributes = 0;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    while (1) {
+	CFG_CHECK(GetTupleData, handle, &tuple);
+	CFG_CHECK(ParseTuple, handle, &tuple, &parse);
+
+	/* Check for matching Vcc, unless we're desperate */
+	if (!pass) {
+	    if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
+		if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000)
+		    goto next_entry;
+	    } else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) {
+		if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM]/10000)
+		    goto next_entry;
+	    }
+	}
+	
+	if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
+	    link->conf.Vpp1 = link->conf.Vpp2 =
+		cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
+	else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM))
+	    link->conf.Vpp1 = link->conf.Vpp2 =
+		dflt.vpp1.param[CISTPL_POWER_VNOM]/10000;
+	
+	if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
+	    cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
+	    link->conf.ConfigIndex = cfg->index;
+	    link->io.BasePort1 = io->win[0].base;
+	    link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
+	    if (!(io->flags & CISTPL_IO_16BIT))
+		link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+	    if (io->nwin == 2) {
+		link->io.NumPorts1 = 8;
+		link->io.BasePort2 = io->win[1].base;
+		link->io.NumPorts2 = 1;
+		CFG_CHECK(RequestIO, link->handle, &link->io);
+		io_base = link->io.BasePort1;
+		ctl_base = link->io.BasePort2;
+	    } else if ((io->nwin == 1) && (io->win[0].len >= 16)) {
+		link->io.NumPorts1 = io->win[0].len;
+		link->io.NumPorts2 = 0;
+		CFG_CHECK(RequestIO, link->handle, &link->io);
+		io_base = link->io.BasePort1;
+		ctl_base = link->io.BasePort1+0x0e;
+	    } else goto next_entry;
+	    /* If we've got this far, we're done */
+	    break;
+	}
+	
+    next_entry:
+	if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
+	if (pass) {
+	    CS_CHECK(GetNextTuple, handle, &tuple);
+	} else if (CardServices(GetNextTuple, handle, &tuple) != 0) {
+	    CS_CHECK(GetFirstTuple, handle, &tuple);
+	    memset(&dflt, 0, sizeof(dflt));
+	    pass++;
+	}
+    }
+    
+    CS_CHECK(RequestIRQ, handle, &link->irq);
+    CS_CHECK(RequestConfiguration, handle, &link->conf);
+
+    /* deal with brain dead IDE resource management */
+    release_region(link->io.BasePort1, link->io.NumPorts1);
+    if (link->io.NumPorts2)
+	release_region(link->io.BasePort2, link->io.NumPorts2);
+
+    /* retry registration in case device is still spinning up */
+    for (i = 0; i < 10; i++) {
+	if (ctl_base)
+	    outb(0x02, ctl_base); /* Set nIEN = disable device interrupts */
+	hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ);
+	if (hd >= 0) break;
+	if (link->io.NumPorts1 == 0x20) {
+	    if (ctl_base)
+		outb(0x02, ctl_base+0x10);
+	    hd = idecs_register(io_base+0x10, ctl_base+0x10,
+			      link->irq.AssignedIRQ);
+	    if (hd >= 0) {
+		io_base += 0x10; ctl_base += 0x10;
+		break;
+	    }
+	}
+	__set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(HZ/10);
+    }
+    
+    if (hd < 0) {
+	printk(KERN_NOTICE "ide_cs: ide_register() at 0x%03x & 0x%03x"
+	       ", irq %u failed\n", io_base, ctl_base,
+	       link->irq.AssignedIRQ);
+	goto failed;
+    }
+
+    MOD_INC_USE_COUNT;
+    info->ndev = 1;
+    sprintf(info->node.dev_name, "hd%c", 'a'+(hd*2));
+    info->node.major = ide_major[hd];
+    info->node.minor = 0;
+    info->hd = hd;
+    link->dev = &info->node;
+    printk(KERN_INFO "ide_cs: %s: Vcc = %d.%d, Vpp = %d.%d\n",
+	   info->node.dev_name, link->conf.Vcc/10, link->conf.Vcc%10,
+	   link->conf.Vpp1/10, link->conf.Vpp1%10);
+
+    link->state &= ~DEV_CONFIG_PENDING;
+    return;
+    
+cs_failed:
+    cs_error(link->handle, last_fn, last_ret);
+failed:
+    ide_release(link);
+
+} /* ide_config */
+
+/*======================================================================
+
+    After a card is removed, ide_release() will unregister the net
+    device, and release the PCMCIA configuration.  If the device is
+    still open, this will be postponed until it is closed.
+    
+======================================================================*/
+
+static void ide_release(void *arg)
+{
+    dev_link_t *link = arg;
+    ide_info_t *info = link->priv;
+    
+    if (!(link->state & DEV_CONFIG))
+	return;
+
+    DEBUG(0, "ide_do_release(0x%p)\n", link);
+
+    if (info->ndev) {
+        /* FIXME: if this fails we need to queue the cleanup somehow
+           -- need to investigate the required PCMCIA magic */
+	ide_unregister(info->hd);
+	MOD_DEC_USE_COUNT;
+    }
+
+    request_region(link->io.BasePort1, link->io.NumPorts1,"ide-cs");
+    if (link->io.NumPorts2)
+	request_region(link->io.BasePort2, link->io.NumPorts2,"ide-cs");
+    
+    info->ndev = 0;
+    link->dev = NULL;
+    
+    CardServices(ReleaseConfiguration, link->handle);
+    CardServices(ReleaseIO, link->handle, &link->io);
+    CardServices(ReleaseIRQ, link->handle, &link->irq);
+    
+    link->state &= ~DEV_CONFIG;
+
+} /* ide_release */
+
+/*======================================================================
+
+    The card status event handler.  Mostly, this schedules other
+    stuff to run after an event is received.  A CARD_REMOVAL event
+    also sets some flags to discourage the ide drivers from
+    talking to the ports.
+    
+======================================================================*/
+
+int ide_event(event_t event, int priority,
+	      event_callback_args_t *args)
+{
+    dev_link_t *link = args->client_data;
+    ide_info_t *info = link->priv;
+
+    DEBUG(1, "ide_event(0x%06x)\n", event);
+    
+    switch (event) {
+    case CS_EVENT_CARD_REMOVAL:
+	link->state &= ~DEV_PRESENT;
+	if (link->state & DEV_CONFIG)
+	    schedule_task(&info->rel_task);
+	break;
+    case CS_EVENT_CARD_INSERTION:
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+	ide_config(link);
+	break;
+    case CS_EVENT_PM_SUSPEND:
+	link->state |= DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_RESET_PHYSICAL:
+	if (link->state & DEV_CONFIG)
+	    CardServices(ReleaseConfiguration, link->handle);
+	break;
+    case CS_EVENT_PM_RESUME:
+	link->state &= ~DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_CARD_RESET:
+	if (DEV_OK(link))
+	    CardServices(RequestConfiguration, link->handle, &link->conf);
+	break;
+    }
+    return 0;
+} /* ide_event */
+
+/*====================================================================*/
+
+static int __init init_ide_cs(void)
+{
+    servinfo_t serv;
+    DEBUG(0, "%s\n", version);
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+	printk(KERN_NOTICE "ide_cs: Card Services release "
+	       "does not match!\n");
+	return -1;
+    }
+    register_pccard_driver(&dev_info, &ide_attach, &ide_detach);
+    return 0;
+}
+
+static void __exit exit_ide_cs(void)
+{
+    DEBUG(0, "ide_cs: unloading\n");
+    unregister_pccard_driver(&dev_info);
+    while (dev_list != NULL)
+	ide_detach(dev_list);
+}
+
+module_init(init_ide_cs);
+module_exit(exit_ide_cs);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/macide.c linux-2.4.21-pre6/drivers/ide/legacy/macide.c
--- linux-2.4.20/drivers/ide/legacy/macide.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/legacy/macide.c	2003-03-26 23:49:07.000000000 +0000
@@ -0,0 +1,153 @@
+/*
+ *  linux/drivers/ide/legacy/macide.c -- Macintosh IDE Driver
+ *
+ *     Copyright (C) 1998 by Michael Schmitz
+ *
+ *  This driver was written based on information obtained from the MacOS IDE
+ *  driver binary by Mikael Forselius
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+
+#include <asm/machw.h>
+#include <asm/macintosh.h>
+#include <asm/macints.h>
+#include <asm/mac_baboon.h>
+
+#define IDE_BASE 0x50F1A000	/* Base address of IDE controller */
+
+/*
+ * Generic IDE registers as offsets from the base
+ * These match MkLinux so they should be correct.
+ */
+
+#define IDE_DATA	0x00
+#define IDE_ERROR	0x04	/* see err-bits */
+#define IDE_NSECTOR	0x08	/* nr of sectors to read/write */
+#define IDE_SECTOR	0x0c	/* starting sector */
+#define IDE_LCYL	0x10	/* starting cylinder */
+#define IDE_HCYL	0x14	/* high byte of starting cyl */
+#define IDE_SELECT	0x18	/* 101dhhhh , d=drive, hhhh=head */
+#define IDE_STATUS	0x1c	/* see status-bits */
+#define IDE_CONTROL	0x38	/* control/altstatus */
+
+/*
+ * Mac-specific registers
+ */
+
+/*
+ * this register is odd; it doesn't seem to do much and it's
+ * not word-aligned like virtually every other hardware register
+ * on the Mac...
+ */
+
+#define IDE_IFR		0x101	/* (0x101) IDE interrupt flags on Quadra:
+				 *
+				 * Bit 0+1: some interrupt flags
+				 * Bit 2+3: some interrupt enable
+				 * Bit 4:   ??
+				 * Bit 5:   IDE interrupt flag (any hwif)
+				 * Bit 6:   maybe IDE interrupt enable (any hwif) ??
+				 * Bit 7:   Any interrupt condition
+				 */
+
+volatile unsigned char *ide_ifr = (unsigned char *) (IDE_BASE + IDE_IFR);
+
+static int macide_offsets[IDE_NR_PORTS] = {
+    IDE_DATA, IDE_ERROR,  IDE_NSECTOR, IDE_SECTOR, IDE_LCYL,
+    IDE_HCYL, IDE_SELECT, IDE_STATUS,  IDE_CONTROL
+};
+
+int macide_ack_intr(ide_hwif_t* hwif)
+{
+	if (*ide_ifr & 0x20) {
+		*ide_ifr &= ~0x20;
+		return 1;
+	}
+	return 0;
+}
+
+#ifdef CONFIG_BLK_DEV_MAC_MEDIABAY
+static void macide_mediabay_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	int state = baboon->mb_status & 0x04;
+
+	printk(KERN_INFO "macide: media bay %s detected\n", state? "removal":"insertion");
+}
+#endif
+
+/*
+ * Probe for a Macintosh IDE interface
+ */
+
+void macide_init(void)
+{
+	hw_regs_t hw;
+	int index = -1;
+
+	switch (macintosh_config->ide_type) {
+	case MAC_IDE_QUADRA:
+		ide_setup_ports(&hw, (ide_ioreg_t)IDE_BASE, macide_offsets,
+				0, 0, macide_ack_intr,
+//				quadra_ide_iops,
+				IRQ_NUBUS_F);
+		index = ide_register_hw(&hw, NULL);
+		break;
+	case MAC_IDE_PB:
+		ide_setup_ports(&hw, (ide_ioreg_t)IDE_BASE, macide_offsets,
+				0, 0, macide_ack_intr,
+//				macide_pb_iops,
+				IRQ_NUBUS_C);
+		index = ide_register_hw(&hw, NULL);
+		break;
+	case MAC_IDE_BABOON:
+		ide_setup_ports(&hw, (ide_ioreg_t)BABOON_BASE, macide_offsets,
+				0, 0, NULL,
+//				macide_baboon_iops,
+				IRQ_BABOON_1);
+		index = ide_register_hw(&hw, NULL);
+		if (index == -1) break;
+		if (macintosh_config->ident == MAC_MODEL_PB190) {
+
+			/* Fix breakage in ide-disk.c: drive capacity	*/
+			/* is not initialized for drives without a 	*/
+			/* hardware ID, and we can't get that without	*/
+			/* probing the drive which freezes a 190.	*/
+
+			ide_drive_t *drive = &ide_hwifs[index].drives[0];
+        		drive->capacity = drive->cyl*drive->head*drive->sect;
+
+#ifdef CONFIG_BLK_DEV_MAC_MEDIABAY
+			request_irq(IRQ_BABOON_2, macide_mediabay_interrupt,
+					IRQ_FLG_FAST, "mediabay",
+					macide_mediabay_interrupt);
+#endif
+		}
+		break;
+
+	default:
+	    return;
+	}
+
+        if (index != -1) {
+		if (macintosh_config->ide_type == MAC_IDE_QUADRA)
+			printk(KERN_INFO "ide%d: Macintosh Quadra IDE interface\n", index);
+		else if (macintosh_config->ide_type == MAC_IDE_PB)
+			printk(KERN_INFO "ide%d: Macintosh Powerbook IDE interface\n", index);
+		else if (macintosh_config->ide_type == MAC_IDE_BABOON)
+			printk(KERN_INFO "ide%d: Macintosh Powerbook Baboon IDE interface\n", index);
+		else
+			printk(KERN_INFO "ide%d: Unknown Macintosh IDE interface\n", index);
+	}
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/pdc4030.c linux-2.4.21-pre6/drivers/ide/legacy/pdc4030.c
--- linux-2.4.20/drivers/ide/legacy/pdc4030.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/legacy/pdc4030.c	2003-03-26 23:49:18.000000000 +0000
@@ -0,0 +1,858 @@
+/*  -*- linux-c -*-
+ *  linux/drivers/ide/legacy/pdc4030.c		Version 0.90  May 27, 1999
+ *
+ *  Copyright (C) 1995-2002  Linus Torvalds & authors (see below)
+ */
+
+/*
+ *  Principal Author/Maintainer:  Peter Denison <promise@pnd-pc.demon.co.uk>
+ *
+ *  This file provides support for the second port and cache of Promise
+ *  IDE interfaces, e.g. DC4030VL, DC4030VL-1 and DC4030VL-2.
+ *
+ *  Thanks are due to Mark Lord for advice and patiently answering stupid
+ *  questions, and all those mugs^H^H^H^Hbrave souls who've tested this,
+ *  especially Andre Hedrick.
+ *
+ *  Version 0.01	Initial version, #include'd in ide.c rather than
+ *                      compiled separately.
+ *                      Reads use Promise commands, writes as before. Drives
+ *                      on second channel are read-only.
+ *  Version 0.02        Writes working on second channel, reads on both
+ *                      channels. Writes fail under high load. Suspect
+ *			transfers of >127 sectors don't work.
+ *  Version 0.03        Brought into line with ide.c version 5.27.
+ *                      Other minor changes.
+ *  Version 0.04        Updated for ide.c version 5.30
+ *                      Changed initialization strategy
+ *  Version 0.05	Kernel integration.  -ml
+ *  Version 0.06	Ooops. Add hwgroup to direct call of ide_intr() -ml
+ *  Version 0.07	Added support for DC4030 variants
+ *			Secondary interface autodetection
+ *  Version 0.08	Renamed to pdc4030.c
+ *  Version 0.09	Obsolete - never released - did manual write request
+ *			splitting before max_sectors[major][minor] available.
+ *  Version 0.10	Updated for 2.1 series of kernels
+ *  Version 0.11	Updated for 2.3 series of kernels
+ *			Autodetection code added.
+ *
+ *  Version 0.90	Transition to BETA code. No lost/unexpected interrupts
+ */
+
+/*
+ * Once you've compiled it in, you'll have to also enable the interface
+ * setup routine from the kernel command line, as in 
+ *
+ *	'linux ide0=dc4030' or 'linux ide1=dc4030'
+ *
+ * It should now work as a second controller also ('ide1=dc4030') but only
+ * if you DON'T have BIOS V4.44, which has a bug. If you have this version
+ * and EPROM programming facilities, you need to fix 4 bytes:
+ * 	2496:	81	81
+ *	2497:	3E	3E
+ *	2498:	22	98	*
+ *	2499:	06	05	*
+ *	249A:	F0	F0
+ *	249B:	01	01
+ *	...
+ *	24A7:	81	81
+ *	24A8:	3E	3E
+ *	24A9:	22	98	*
+ *	24AA:	06	05	*
+ *	24AB:	70	70
+ *	24AC:	01	01
+ *
+ * As of January 1999, Promise Technology Inc. have finally supplied me with
+ * some technical information which has shed a glimmer of light on some of the
+ * problems I was having, especially with writes. 
+ *
+ * There are still potential problems with the robustness and efficiency of
+ * this driver because I still don't understand what the card is doing with
+ * interrupts, however, it has been stable for a while with no reports of ill
+ * effects.
+ */
+
+#define DEBUG_READ
+#define DEBUG_WRITE
+#define __PROMISE_4030
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "pdc4030.h"
+
+/*
+ * promise_selectproc() is invoked by ide.c
+ * in preparation for access to the specified drive.
+ */
+static void promise_selectproc (ide_drive_t *drive)
+{
+	unsigned int number;
+
+	number = (HWIF(drive)->channel << 1) + drive->select.b.unit;
+	HWIF(drive)->OUTB(number, IDE_FEATURE_REG);
+}
+
+/*
+ * pdc4030_cmd handles the set of vendor specific commands that are initiated
+ * by command F0. They all have the same success/failure notification -
+ * 'P' (=0x50) on success, 'p' (=0x70) on failure.
+ */
+int pdc4030_cmd(ide_drive_t *drive, u8 cmd)
+{
+	u32 timeout;
+	u8 status_val;
+
+	promise_selectproc(drive);	/* redundant? */
+	HWIF(drive)->OUTB(0xF3, IDE_SECTOR_REG);
+	HWIF(drive)->OUTB(cmd, IDE_SELECT_REG);
+	HWIF(drive)->OUTB(PROMISE_EXTENDED_COMMAND, IDE_COMMAND_REG);
+	timeout = HZ * 10;
+	timeout += jiffies;
+	do {
+		if(time_after(jiffies, timeout)) {
+			return 2; /* device timed out */
+		}
+		/* Delays at least 10ms to give interface a chance */
+		mdelay(10);
+		status_val = HWIF(drive)->INB(IDE_SECTOR_REG);
+	} while (status_val != 0x50 && status_val != 0x70);
+
+	if(status_val == 0x50)
+		return 0; /* device returned success */
+	else
+		return 1; /* device returned failure */
+}
+
+/*
+ * pdc4030_identify sends a vendor-specific IDENTIFY command to the drive
+ */
+int pdc4030_identify(ide_drive_t *drive)
+{
+	return pdc4030_cmd(drive, PROMISE_IDENTIFY);
+}
+
+int enable_promise_support;
+
+/*
+ * setup_pdc4030()
+ * Completes the setup of a Promise DC4030 controller card, once found.
+ */
+int __init setup_pdc4030(ide_hwif_t *hwif)
+{
+        ide_drive_t *drive;
+	ide_hwif_t *hwif2;
+	struct dc_ident ident;
+	int i;
+	ide_startstop_t startstop;
+	
+	if (!hwif) return 0;
+
+	drive = &hwif->drives[0];
+	hwif2 = &ide_hwifs[hwif->index+1];
+	if (hwif->chipset == ide_pdc4030) /* we've already been found ! */
+		return 1;
+
+	if (hwif->INB(IDE_NSECTOR_REG) == 0xFF ||
+	    hwif->INB(IDE_SECTOR_REG) == 0xFF) {
+		return 0;
+	}
+	if (IDE_CONTROL_REG)
+		hwif->OUTB(0x08, IDE_CONTROL_REG);
+	if (pdc4030_cmd(drive,PROMISE_GET_CONFIG)) {
+		return 0;
+	}
+	if (ide_wait_stat(&startstop, drive,DATA_READY,BAD_W_STAT,WAIT_DRQ)) {
+		printk(KERN_INFO
+			"%s: Failed Promise read config!\n",hwif->name);
+		return 0;
+	}
+	hwif->ata_input_data(drive, &ident, SECTOR_WORDS);
+	if (ident.id[1] != 'P' || ident.id[0] != 'T') {
+		return 0;
+	}
+	printk(KERN_INFO "%s: Promise caching controller, ",hwif->name);
+	switch(ident.type) {
+		case 0x43:	printk("DC4030VL-2, "); break;
+		case 0x41:	printk("DC4030VL-1, "); break;
+		case 0x40:	printk("DC4030VL, "); break;
+		default:
+			printk("unknown - type 0x%02x - please report!\n"
+			       ,ident.type);
+			printk("Please e-mail the following data to "
+			       "promise@pnd-pc.demon.co.uk along with\n"
+			       "a description of your card and drives:\n");
+			for (i=0; i < 0x90; i++) {
+				printk("%02x ", ((unsigned char *)&ident)[i]);
+				if ((i & 0x0f) == 0x0f) printk("\n");
+			}
+			return 0;
+	}
+	printk("%dKB cache, ",(int)ident.cache_mem);
+	switch(ident.irq) {
+            case 0x00: hwif->irq = 14; break;
+            case 0x01: hwif->irq = 12; break;
+            default:   hwif->irq = 15; break;
+	}
+	printk("on IRQ %d\n",hwif->irq);
+
+	/*
+	 * Once found and identified, we set up the next hwif in the array
+	 * (hwif2 = ide_hwifs[hwif->index+1]) with the same io ports, irq
+	 * and other settings as the main hwif. This gives us two "mated"
+	 * hwifs pointing to the Promise card.
+	 *
+	 * We also have to shift the default values for the remaining
+	 * interfaces "up by one" to make room for the second interface on the
+	 * same set of values.
+	 */
+
+	hwif->chipset	= hwif2->chipset = ide_pdc4030;
+	hwif->mate	= hwif2;
+	hwif2->mate	= hwif;
+	hwif2->channel	= 1;
+	hwif->rqsize	= hwif2->rqsize = 127;
+	hwif->addressing = hwif2->addressing = 1;
+	hwif->selectproc = hwif2->selectproc = &promise_selectproc;
+	hwif->serialized = hwif2->serialized = 1;
+	/* DC4030 hosted drives need their own identify... */
+	hwif->identify = hwif2->identify = &pdc4030_identify;
+
+	/* Shift the remaining interfaces up by one */
+	for (i=MAX_HWIFS-1 ; i > hwif->index+1 ; i--) {
+		ide_hwif_t *h = &ide_hwifs[i];
+
+#ifdef DEBUG
+		printk(KERN_DEBUG "pdc4030: Shifting i/f %d values to i/f %d\n",i-1,i);
+#endif /* DEBUG */
+		ide_init_hwif_ports(&h->hw, (h-1)->io_ports[IDE_DATA_OFFSET], 0, NULL);
+		memcpy(h->io_ports, h->hw.io_ports, sizeof(h->io_ports));
+		h->noprobe = (h-1)->noprobe;
+	}
+	ide_init_hwif_ports(&hwif2->hw, hwif->io_ports[IDE_DATA_OFFSET], 0, NULL);
+	memcpy(hwif2->io_ports, hwif->hw.io_ports, sizeof(hwif2->io_ports));
+	hwif2->irq = hwif->irq;
+	hwif2->hw.irq = hwif->hw.irq = hwif->irq;
+	for (i=0; i<2 ; i++) {
+		hwif->drives[i].io_32bit = 3;
+		hwif2->drives[i].io_32bit = 3;
+		hwif->drives[i].keep_settings = 1;
+		hwif2->drives[i].keep_settings = 1;
+		if (!ident.current_tm[i].cyl)
+			hwif->drives[i].noprobe = 1;
+		if (!ident.current_tm[i+2].cyl)
+			hwif2->drives[i].noprobe = 1;
+	}
+#ifndef HWIF_PROBE_CLASSIC_METHOD
+	probe_hwif_init(&ide_hwifs[hwif->index]);
+	probe_hwif_init(&ide_hwifs[hwif2->index]);
+#endif /* HWIF_PROBE_CLASSIC_METHOD */
+
+        return 1;
+}
+
+/*
+ * detect_pdc4030()
+ * Tests for the presence of a DC4030 Promise card on this interface
+ * Returns: 1 if found, 0 if not found
+ */
+int __init detect_pdc4030(ide_hwif_t *hwif)
+{
+	ide_drive_t *drive = &hwif->drives[0];
+
+	if (IDE_DATA_REG == 0) { /* Skip test for non-existent interface */
+		return 0;
+	}
+	hwif->OUTB(0xF3, IDE_SECTOR_REG);
+	hwif->OUTB(0x14, IDE_SELECT_REG);
+	hwif->OUTB(PROMISE_EXTENDED_COMMAND, IDE_COMMAND_REG);
+	
+	ide_delay_50ms();
+
+	if (hwif->INB(IDE_ERROR_REG) == 'P' &&
+	    hwif->INB(IDE_NSECTOR_REG) == 'T' &&
+	    hwif->INB(IDE_SECTOR_REG) == 'I') {
+		return 1;
+	} else {
+		return 0;
+	}
+}
+
+
+#ifndef MODULE
+void __init ide_probe_for_pdc4030(void)
+#else
+int ide_probe_for_pdc4030(void)
+#endif
+{
+	unsigned int	index;
+	ide_hwif_t	*hwif;
+
+#ifndef MODULE
+	if (enable_promise_support == 0)
+		return;
+#endif
+
+	for (index = 0; index < MAX_HWIFS; index++) {
+		hwif = &ide_hwifs[index];
+		if (hwif->chipset == ide_unknown && detect_pdc4030(hwif)) {
+#ifndef MODULE
+			setup_pdc4030(hwif);
+#else
+			return setup_pdc4030(hwif);
+#endif
+		}
+	}
+#ifdef MODULE
+	return 0;
+#endif
+}
+
+void __init release_pdc4030(ide_hwif_t *hwif, ide_hwif_t *mate)
+{
+	hwif->chipset = ide_unknown;
+	hwif->selectproc = NULL;
+	hwif->serialized = 0;
+	hwif->drives[0].io_32bit = 0;
+	hwif->drives[1].io_32bit = 0;
+	hwif->drives[0].keep_settings = 0;
+	hwif->drives[1].keep_settings = 0;
+	hwif->drives[0].noprobe = 0;
+	hwif->drives[1].noprobe = 0;
+
+	if (mate != NULL) {
+		mate->chipset = ide_unknown;
+		mate->selectproc = NULL;
+		mate->serialized = 0;
+		mate->drives[0].io_32bit = 0;
+		mate->drives[1].io_32bit = 0;
+		mate->drives[0].keep_settings = 0;
+		mate->drives[1].keep_settings = 0;
+		mate->drives[0].noprobe = 0;
+		mate->drives[1].noprobe = 0;
+	}
+}
+
+#ifndef MODULE
+/*
+ * init_pdc4030:
+ *
+ * called by ide.c when parsing command line
+ */
+
+void __init init_pdc4030(void)
+{
+	enable_promise_support = 1;
+}
+
+#else
+
+MODULE_AUTHOR("Peter Denison");
+MODULE_DESCRIPTION("Support of Promise 4030 VLB series IDE chipsets");
+MODULE_LICENSE("GPL");
+
+int __init pdc4030_mod_init(void)
+{
+	if (enable_promise_support == 0)
+		enable_promise_support = 1;
+
+	if (!ide_probe_for_pdc4030())
+		return -ENODEV;
+        return 0;
+}
+module_init(pdc4030_mod_init);
+
+void __init pdc4030_mod_exit(void)
+{
+	unsigned int    index;
+	ide_hwif_t      *hwif;
+
+	if (enable_promise_support == 0)
+		return;
+ 
+	for (index = 0; index < MAX_HWIFS; index++) {
+		hwif = &ide_hwifs[index];
+		if (hwif->chipset == ide_pdc4030) {
+			ide_hwif_t *mate = &ide_hwifs[hwif->index+1];
+			if (mate->chipset == ide_pdc4030)
+				release_pdc4030(hwif, mate);
+			else
+				release_pdc4030(hwif, NULL);
+                }
+        }
+	enable_promise_support = 0;
+}
+module_exit(pdc4030_mod_exit);
+#endif
+
+/*
+ * promise_read_intr() is the handler for disk read/multread interrupts
+ */
+static ide_startstop_t promise_read_intr (ide_drive_t *drive)
+{
+	int total_remaining;
+	unsigned int sectors_left, sectors_avail, nsect;
+	struct request *rq;
+	ata_status_t status;
+#ifdef CONFIG_IDE_TASKFILE_IO
+	unsigned long flags;
+	char *to;
+#endif /* CONFIG_IDE_TASKFILE_IO */
+
+	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
+	if (!OK_STAT(status.all, DATA_READY, BAD_R_STAT))
+		return DRIVER(drive)->error(drive,
+			"promise_read_intr", status.all);
+
+read_again:
+	do {
+		sectors_left = HWIF(drive)->INB(IDE_NSECTOR_REG);
+		HWIF(drive)->INB(IDE_SECTOR_REG);
+	} while (HWIF(drive)->INB(IDE_NSECTOR_REG) != sectors_left);
+	rq = HWGROUP(drive)->rq;
+	sectors_avail = rq->nr_sectors - sectors_left;
+	if (!sectors_avail)
+		goto read_again;
+
+read_next:
+	rq = HWGROUP(drive)->rq;
+	nsect = rq->current_nr_sectors;
+	if (nsect > sectors_avail)
+		nsect = sectors_avail;
+	sectors_avail -= nsect;
+#ifdef CONFIG_IDE_TASKFILE_IO
+	to = ide_map_buffer(rq, &flags);
+	HWIF(drive)->ata_input_data(drive, to, nsect * SECTOR_WORDS);
+#else /* !CONFIG_IDE_TASKFILE_IO */
+	HWIF(drive)->ata_input_data(drive, rq->buffer, nsect * SECTOR_WORDS);
+#endif /* CONFIG_IDE_TASKFILE_IO */
+
+#ifdef DEBUG_READ
+	printk(KERN_DEBUG "%s:  promise_read: sectors(%ld-%ld), "
+	       "buf=0x%08lx, rem=%ld\n", drive->name, rq->sector,
+	       rq->sector+nsect-1,
+#ifdef CONFIG_IDE_TASKFILE_IO
+		(unsigned long) to,
+#else /* !CONFIG_IDE_TASKFILE_IO */
+		(unsigned long) rq->buffer,
+#endif /* CONFIG_IDE_TASKFILE_IO */
+	       rq->nr_sectors-nsect);
+#endif /* DEBUG_READ */
+
+#ifdef CONFIG_IDE_TASKFILE_IO
+	ide_unmap_buffer(to, &flags);
+#else /* !CONFIG_IDE_TASKFILE_IO */
+	rq->buffer += nsect<<9;
+#endif /* CONFIG_IDE_TASKFILE_IO */
+	rq->sector += nsect;
+	rq->errors = 0;
+	rq->nr_sectors -= nsect;
+	total_remaining = rq->nr_sectors;
+	if ((rq->current_nr_sectors -= nsect) <= 0) {
+		DRIVER(drive)->end_request(drive, 1);
+	}
+/*
+ * Now the data has been read in, do the following:
+ * 
+ * if there are still sectors left in the request, 
+ *   if we know there are still sectors available from the interface,
+ *     go back and read the next bit of the request.
+ *   else if DRQ is asserted, there are more sectors available, so
+ *     go back and find out how many, then read them in.
+ *   else if BUSY is asserted, we are going to get an interrupt, so
+ *     set the handler for the interrupt and just return
+ */
+	if (total_remaining > 0) {
+		if (sectors_avail)
+			goto read_next;
+		status.all = HWIF(drive)->INB(IDE_STATUS_REG);
+		if (status.b.drq)
+			goto read_again;
+		if (status.b.bsy) {
+			if (HWGROUP(drive)->handler != NULL)
+				BUG();
+			ide_set_handler(drive,
+					&promise_read_intr,
+					WAIT_CMD,
+					NULL);
+#ifdef DEBUG_READ
+			printk(KERN_DEBUG "%s: promise_read: waiting for"
+			       "interrupt\n", drive->name);
+#endif /* DEBUG_READ */
+			return ide_started;
+		}
+		printk(KERN_ERR "%s: Eeek! promise_read_intr: sectors left "
+		       "!DRQ !BUSY\n", drive->name);
+		return DRIVER(drive)->error(drive,
+				"promise read intr", status.all);
+	}
+	return ide_stopped;
+}
+
+/*
+ * promise_complete_pollfunc()
+ * This is the polling function for waiting (nicely!) until drive stops
+ * being busy. It is invoked at the end of a write, after the previous poll
+ * has finished.
+ *
+ * Once not busy, the end request is called.
+ */
+static ide_startstop_t promise_complete_pollfunc(ide_drive_t *drive)
+{
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+	struct request *rq = hwgroup->rq;
+	int i;
+
+	if ((HWIF(drive)->INB(IDE_STATUS_REG)) & BUSY_STAT) {
+		if (time_before(jiffies, hwgroup->poll_timeout)) {
+			if (hwgroup->handler != NULL)
+				BUG();
+			ide_set_handler(drive,
+					&promise_complete_pollfunc,
+					HZ/100,
+					NULL);
+			return ide_started; /* continue polling... */
+		}
+		hwgroup->poll_timeout = 0;
+		printk(KERN_ERR "%s: completion timeout - still busy!\n",
+		       drive->name);
+		return DRIVER(drive)->error(drive, "busy timeout",
+				HWIF(drive)->INB(IDE_STATUS_REG));
+	}
+
+	hwgroup->poll_timeout = 0;
+#ifdef DEBUG_WRITE
+	printk(KERN_DEBUG "%s: Write complete - end_request\n", drive->name);
+#endif /* DEBUG_WRITE */
+	for (i = rq->nr_sectors; i > 0; ) {
+		i -= rq->current_nr_sectors;
+		DRIVER(drive)->end_request(drive, 1);
+	}
+	return ide_stopped;
+}
+
+/*
+ * promise_multwrite() transfers a block of up to mcount sectors of data
+ * to a drive as part of a disk multiple-sector write operation.
+ *
+ * Returns 0 on success.
+ *
+ * Note that we may be called from two contexts - the do_rw_disk context
+ * and IRQ context. The IRQ can happen any time after we've output the
+ * full "mcount" number of sectors, so we must make sure we update the
+ * state _before_ we output the final part of the data!
+ */
+int promise_multwrite (ide_drive_t *drive, unsigned int mcount)
+{
+	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
+	struct request *rq	= &hwgroup->wrq;
+
+	do {
+		char *buffer;
+		int nsect = rq->current_nr_sectors;
+#ifdef CONFIG_IDE_TASKFILE_IO
+		unsigned long flags;
+#endif /* CONFIG_IDE_TASKFILE_IO */
+
+		if (nsect > mcount)
+			nsect = mcount;
+		mcount -= nsect;
+#ifdef CONFIG_IDE_TASKFILE_IO
+		buffer = ide_map_buffer(rq, &flags);
+		rq->sector += nsect;
+#else /* !CONFIG_IDE_TASKFILE_IO */
+		buffer = rq->buffer;
+
+		rq->sector += nsect;
+		rq->buffer += nsect << 9;
+#endif /* CONFIG_IDE_TASKFILE_IO */
+		rq->nr_sectors -= nsect;
+		rq->current_nr_sectors -= nsect;
+
+		/* Do we move to the next bh after this? */
+		if (!rq->current_nr_sectors) {
+			struct buffer_head *bh = rq->bh->b_reqnext;
+
+			/* end early early we ran out of requests */
+			if (!bh) {
+				mcount = 0;
+			} else {
+				rq->bh			= bh;
+				rq->current_nr_sectors	= bh->b_size >> 9;
+				rq->hard_cur_sectors = rq->current_nr_sectors;
+				rq->buffer		= bh->b_data;
+			}
+		}
+
+		/*
+		 * Ok, we're all setup for the interrupt
+		 * re-entering us on the last transfer.
+		 */
+		taskfile_output_data(drive, buffer, nsect<<7);
+#ifdef CONFIG_IDE_TASKFILE_IO
+		ide_unmap_buffer(buffer, &flags);
+#endif /* CONFIG_IDE_TASKFILE_IO */
+	} while (mcount);
+
+	return 0;
+}
+
+/*
+ * promise_write_pollfunc() is the handler for disk write completion polling.
+ */
+static ide_startstop_t promise_write_pollfunc (ide_drive_t *drive)
+{
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+
+	if (HWIF(drive)->INB(IDE_NSECTOR_REG) != 0) {
+		if (time_before(jiffies, hwgroup->poll_timeout)) {
+			if (hwgroup->handler != NULL)
+				BUG();
+			ide_set_handler(drive,
+					&promise_write_pollfunc,
+					HZ/100,
+					NULL);
+			return ide_started; /* continue polling... */
+		}
+		hwgroup->poll_timeout = 0;
+		printk(KERN_ERR "%s: write timed-out!\n",drive->name);
+		return DRIVER(drive)->error(drive, "write timeout",
+				HWIF(drive)->INB(IDE_STATUS_REG));
+	}
+
+	/*
+	 * Now write out last 4 sectors and poll for not BUSY
+	 */
+	promise_multwrite(drive, 4);
+	hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+	if (hwgroup->handler != NULL)
+		BUG();
+	ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
+#ifdef DEBUG_WRITE
+	printk(KERN_DEBUG "%s: Done last 4 sectors - status = %02x\n",
+		drive->name, HWIF(drive)->INB(IDE_STATUS_REG));
+#endif /* DEBUG_WRITE */
+	return ide_started;
+}
+
+/*
+ * promise_write() transfers a block of one or more sectors of data to a
+ * drive as part of a disk write operation. All but 4 sectors are transferred
+ * in the first attempt, then the interface is polled (nicely!) for completion
+ * before the final 4 sectors are transferred. There is no interrupt generated
+ * on writes (at least on the DC4030VL-2), we just have to poll for NOT BUSY.
+ */
+static ide_startstop_t promise_write (ide_drive_t *drive)
+{
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+	struct request *rq = &hwgroup->wrq;
+
+#ifdef DEBUG_WRITE
+	printk(KERN_DEBUG "%s: promise_write: sectors(%ld-%ld), "
+	       "buffer=%p\n", drive->name, rq->sector,
+	       rq->sector + rq->nr_sectors - 1, rq->buffer);
+#endif /* DEBUG_WRITE */
+
+	/*
+	 * If there are more than 4 sectors to transfer, do n-4 then go into
+	 * the polling strategy as defined above.
+	 */
+	if (rq->nr_sectors > 4) {
+		if (promise_multwrite(drive, rq->nr_sectors - 4))
+			return ide_stopped;
+		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+		if (hwgroup->handler != NULL)	/* paranoia check */
+			BUG();
+		ide_set_handler (drive, &promise_write_pollfunc, HZ/100, NULL);
+		return ide_started;
+	} else {
+	/*
+	 * There are 4 or fewer sectors to transfer, do them all in one go
+	 * and wait for NOT BUSY.
+	 */
+		if (promise_multwrite(drive, rq->nr_sectors))
+			return ide_stopped;
+		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+		if (hwgroup->handler != NULL)
+			BUG();
+		ide_set_handler(drive,
+				&promise_complete_pollfunc,
+				HZ/100,
+				NULL);
+
+#ifdef DEBUG_WRITE
+		printk(KERN_DEBUG "%s: promise_write: <= 4 sectors, "
+			"status = %02x\n", drive->name,
+			HWIF(drive)->INB(IDE_STATUS_REG));
+#endif /* DEBUG_WRITE */
+		return ide_started;
+	}
+}
+
+/*
+ * do_pdc4030_io() is called from promise_rw_disk, having had the block number
+ * already set up. It issues a READ or WRITE command to the Promise
+ * controller, assuming LBA has been used to set up the block number.
+ */
+#ifndef CONFIG_IDE_TASKFILE_IO
+ide_startstop_t do_pdc4030_io (ide_drive_t *drive, struct request *rq)
+{
+#else /* CONFIG_IDE_TASKFILE_IO */
+ide_startstop_t do_pdc4030_io (ide_drive_t *drive, ide_task_t *task)
+{
+	struct request *rq	= HWGROUP(drive)->rq;
+	task_struct_t *taskfile = (task_struct_t *) task->tfRegister;
+#endif /* CONFIG_IDE_TASKFILE_IO */
+	ide_startstop_t startstop;
+	unsigned long timeout;
+	u8 stat = 0;
+
+#ifdef CONFIG_IDE_TASKFILE_IO
+	if (IDE_CONTROL_REG)
+		HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);	/* clear nIEN */
+	SELECT_MASK(drive, 0);
+	HWIF(drive)->OUTB(taskfile->feature, IDE_FEATURE_REG);
+	HWIF(drive)->OUTB(taskfile->sector_count, IDE_NSECTOR_REG);
+	/* refers to number of sectors to transfer */
+	HWIF(drive)->OUTB(taskfile->sector_number, IDE_SECTOR_REG);
+	/* refers to sector offset or start sector */
+	HWIF(drive)->OUTB(taskfile->low_cylinder, IDE_LCYL_REG);
+	HWIF(drive)->OUTB(taskfile->high_cylinder, IDE_HCYL_REG);
+	HWIF(drive)->OUTB(taskfile->device_head, IDE_SELECT_REG);
+	HWIF(drive)->OUTB(taskfile->command, IDE_COMMAND_REG);
+#endif /* CONFIG_IDE_TASKFILE_IO */
+
+	switch(rq->cmd) {
+	case READ:
+#ifndef CONFIG_IDE_TASKFILE_IO
+		HWIF(drive)->OUTB(PROMISE_READ, IDE_COMMAND_REG);
+#endif /* CONFIG_IDE_TASKFILE_IO */
+/*
+ * The card's behaviour is odd at this point. If the data is
+ * available, DRQ will be true, and no interrupt will be
+ * generated by the card. If this is the case, we need to call the 
+ * "interrupt" handler (promise_read_intr) directly. Otherwise, if
+ * an interrupt is going to occur, bit0 of the SELECT register will
+ * be high, so we can set the handler the just return and be interrupted.
+ * If neither of these is the case, we wait for up to 50ms (badly I'm
+ * afraid!) until one of them is.
+ */
+		timeout = jiffies + HZ/20; /* 50ms wait */
+		do {
+			stat = HWIF(drive)->INB(IDE_STATUS_REG);
+			if (stat & DRQ_STAT) {
+				udelay(1);
+				return promise_read_intr(drive);
+			}
+			if (HWIF(drive)->INB(IDE_SELECT_REG) & 0x01) {
+#ifdef DEBUG_READ
+				printk(KERN_DEBUG "%s: read: waiting for "
+						"interrupt\n", drive->name);
+#endif /* DEBUG_READ */
+				ide_set_handler(drive,
+						&promise_read_intr,
+						WAIT_CMD,
+						NULL);
+				return ide_started;
+			}
+			udelay(1);
+		} while (time_before(jiffies, timeout));
+
+		printk(KERN_ERR "%s: reading: No DRQ and not "
+				"waiting - Odd!\n", drive->name);
+		return ide_stopped;
+	case WRITE:
+#ifndef CONFIG_IDE_TASKFILE_IO
+		HWIF(drive)->OUTB(PROMISE_WRITE, IDE_COMMAND_REG);
+#endif /* CONFIG_IDE_TASKFILE_IO */
+		if (ide_wait_stat(&startstop, drive, DATA_READY,
+				drive->bad_wstat, WAIT_DRQ)) {
+			printk(KERN_ERR "%s: no DRQ after issuing "
+				"PROMISE_WRITE\n", drive->name);
+			return startstop;
+	    	}
+		if (!drive->unmask)
+			local_irq_disable();
+		HWGROUP(drive)->wrq = *rq; /* scratchpad */
+		return promise_write(drive);
+	default:
+		printk("KERN_WARNING %s: bad command: %d\n",
+			drive->name, rq->cmd);
+		DRIVER(drive)->end_request(drive, 0);
+		return ide_stopped;
+	}
+}
+
+ide_startstop_t promise_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
+{
+	/* The four drives on the two logical (one physical) interfaces
+	   are distinguished by writing the drive number (0-3) to the
+	   Feature register.
+	   FIXME: Is promise_selectproc now redundant??
+	*/
+	int drive_number = (HWIF(drive)->channel << 1) + drive->select.b.unit;
+#ifndef CONFIG_IDE_TASKFILE_IO
+	ide_hwif_t *hwif = HWIF(drive);
+
+	BUG_ON(rq->nr_sectors > 127);
+
+	if (IDE_CONTROL_REG)
+		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
+
+#ifdef DEBUG
+	printk("%s: %sing: LBAsect=%ld, sectors=%ld, "
+		"buffer=0x%08lx\n", drive->name,
+		(rq->cmd==READ)?"read":"writ", block,
+		rq->nr_sectors, (unsigned long) rq->buffer);
+#endif
+	hwif->OUTB(drive_number, IDE_FEATURE_REG);
+	hwif->OUTB(rq->nr_sectors, IDE_NSECTOR_REG);
+	hwif->OUTB(block,IDE_SECTOR_REG);
+	hwif->OUTB(block>>=8,IDE_LCYL_REG);
+	hwif->OUTB(block>>=8,IDE_HCYL_REG);
+	hwif->OUTB(((block>>8)&0x0f)|drive->select.all,IDE_SELECT_REG);
+
+	return do_pdc4030_io(drive, rq);
+
+#else /* CONFIG_IDE_TASKFILE_IO */
+
+	struct hd_drive_task_hdr	taskfile;
+	ide_task_t			args;
+
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+
+	taskfile.feature	= drive_number;
+	taskfile.sector_count	= rq->nr_sectors;
+	taskfile.sector_number	= block;
+	taskfile.low_cylinder	= (block>>=8);
+	taskfile.high_cylinder	= (block>>=8);
+	taskfile.device_head	= ((block>>8)&0x0f)|drive->select.all;
+	taskfile.command	= (rq->cmd==READ)?PROMISE_READ:PROMISE_WRITE;
+
+	memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
+	memset(args.hobRegister, 0, sizeof(struct hd_drive_hob_hdr));
+	/* We can't call ide_cmd_type_parser here, since it won't understand
+	   our command, but that doesn't matter, since we don't use the
+	   generic interrupt handlers either. Setup the bits of args that we
+	   do need.
+	*/
+	args.handler		= NULL;
+	args.rq			= (struct request *) rq;
+	rq->special		= (ide_task_t *)&args;
+
+	return do_pdc4030_io(drive, &args);
+#endif /* CONFIG_IDE_TASKFILE_IO */
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/pdc4030.h linux-2.4.21-pre6/drivers/ide/legacy/pdc4030.h
--- linux-2.4.20/drivers/ide/legacy/pdc4030.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/legacy/pdc4030.h	2003-03-26 23:49:53.000000000 +0000
@@ -0,0 +1,70 @@
+/*
+ *  linux/drivers/ide/legacy/pdc4030.h
+ *
+ *  Copyright (C) 1995-1998  Linus Torvalds & authors
+ */
+
+/*
+ * Principal author: Peter Denison <peterd@pnd-pc.demon.co.uk>
+ */
+
+#ifndef IDE_PROMISE_H
+#define IDE_PROMISE_H
+
+#include <linux/config.h>
+
+#ifndef CONFIG_BLK_DEV_PDC4030
+# ifdef _IDE_DISK
+
+# define IS_PDC4030_DRIVE (0)	/* auto-NULLs out pdc4030 code */
+
+ide_startstop_t promise_rw_disk(ide_drive_t *, struct request *, unsigned long);
+
+ide_startstop_t promise_rw_disk(ide_drive_t *drive, struct request *rq, unsigned long block)
+{
+        return ide_stopped;
+}
+# endif /* _IDE_DISK */
+#else /* CONFIG_BLK_DEV_PDC4030 */
+# ifdef _IDE_DISK
+#  define IS_PDC4030_DRIVE (HWIF(drive)->chipset == ide_pdc4030)
+
+ide_startstop_t promise_rw_disk(ide_drive_t *, struct request *, unsigned long);
+
+# endif /* _IDE_DISK */
+#endif /* CONFIG_BLK_DEV_PDC4030 */
+
+#ifdef __PROMISE_4030
+#define	PROMISE_EXTENDED_COMMAND	0xF0
+#define	PROMISE_READ			0xF2
+#define	PROMISE_WRITE			0xF3
+/* Extended commands - main command code = 0xf0 */
+#define	PROMISE_GET_CONFIG		0x10
+#define	PROMISE_IDENTIFY		0x20
+
+struct translation_mode {
+	u16	cyl;
+	u8	head;
+	u8	sect;
+};
+
+struct dc_ident {
+	u8	type;
+	u8	unknown1;
+	u8	hw_revision;
+	u8	firmware_major;
+	u8	firmware_minor;
+	u8	bios_address;
+	u8	irq;
+	u8	unknown2;
+	u16	cache_mem;
+	u16	unknown3;
+	u8	id[2];
+	u16	info;
+	struct translation_mode current_tm[4];
+	u8	pad[SECTOR_WORDS*4 - 32];
+};
+
+#endif /* __PROMISE_4030 */
+
+#endif /* IDE_PROMISE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/q40ide.c linux-2.4.21-pre6/drivers/ide/legacy/q40ide.c
--- linux-2.4.20/drivers/ide/legacy/q40ide.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/legacy/q40ide.c	2003-03-26 23:49:39.000000000 +0000
@@ -0,0 +1,93 @@
+/*
+ *  linux/drivers/ide/legacy/q40ide.c -- Q40 I/O port IDE Driver
+ *
+ *     (c) Richard Zidlicky
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ *
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+
+#include <linux/ide.h>
+
+    /*
+     *  Bases of the IDE interfaces
+     */
+
+#define Q40IDE_NUM_HWIFS	2
+
+#define PCIDE_BASE1	0x1f0
+#define PCIDE_BASE2	0x170
+#define PCIDE_BASE3	0x1e8
+#define PCIDE_BASE4	0x168
+#define PCIDE_BASE5	0x1e0
+#define PCIDE_BASE6	0x160
+
+static const q40ide_ioreg_t pcide_bases[Q40IDE_NUM_HWIFS] = {
+    PCIDE_BASE1, PCIDE_BASE2, /* PCIDE_BASE3, PCIDE_BASE4  , PCIDE_BASE5,
+    PCIDE_BASE6 */
+};
+
+
+    /*
+     *  Offsets from one of the above bases
+     */
+
+
+/* HD_DATA was redefined in asm-m68k/ide.h */
+#undef HD_DATA
+#define HD_DATA  0x1f0
+
+
+#define PCIDE_REG(x)	((q40ide_ioreg_t)(HD_##x-PCIDE_BASE1))
+
+static const int pcide_offsets[IDE_NR_PORTS] = {
+    PCIDE_REG(DATA), PCIDE_REG(ERROR), PCIDE_REG(NSECTOR), PCIDE_REG(SECTOR),
+    PCIDE_REG(LCYL), PCIDE_REG(HCYL), PCIDE_REG(CURRENT), PCIDE_REG(STATUS),
+    PCIDE_REG(CMD)
+};
+
+static int q40ide_default_irq(q40ide_ioreg_t base)
+{
+           switch (base) { 
+	            case 0x1f0: return 14;
+		    case 0x170: return 15;
+		    case 0x1e8: return 11;
+		    default:
+			return 0;
+	   }
+}
+
+
+
+    /*
+     *  Probe for Q40 IDE interfaces
+     */
+
+void q40ide_init(void)
+{
+    int i;
+
+    if (!MACH_IS_Q40)
+      return ;
+
+    for (i = 0; i < Q40IDE_NUM_HWIFS; i++) {
+	hw_regs_t hw;
+
+	ide_setup_ports(&hw,(ide_ioreg_t) pcide_bases[i], (int *)pcide_offsets, 
+			pcide_bases[i]+0x206, 
+			0, NULL,
+//			pcide_iops,
+			q40ide_default_irq(pcide_bases[i]));
+	ide_register_hw(&hw, NULL);
+    }
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/qd65xx.c linux-2.4.21-pre6/drivers/ide/legacy/qd65xx.c
--- linux-2.4.20/drivers/ide/legacy/qd65xx.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/legacy/qd65xx.c	2003-03-26 23:49:20.000000000 +0000
@@ -0,0 +1,523 @@
+/*
+ *  linux/drivers/ide/legacy/qd65xx.c		Version 0.07	Sep 30, 2001
+ *
+ *  Copyright (C) 1996-2001  Linus Torvalds & author (see below)
+ */
+
+/*
+ *  Version 0.03	Cleaned auto-tune, added probe
+ *  Version 0.04	Added second channel tuning
+ *  Version 0.05	Enhanced tuning ; added qd6500 support
+ *  Version 0.06	Added dos driver's list
+ *  Version 0.07	Second channel bug fix 
+ *
+ * QDI QD6500/QD6580 EIDE controller fast support
+ *
+ * Please set local bus speed using kernel parameter idebus
+ * 	for example, "idebus=33" stands for 33Mhz VLbus
+ * To activate controller support, use "ide0=qd65xx"
+ * To enable tuning, use "ide0=autotune"
+ * To enable second channel tuning (qd6580 only), use "ide1=autotune"
+ */
+
+/*
+ * Rewritten from the work of Colten Edwards <pje120@cs.usask.ca> by
+ * Samuel Thibault <samuel.thibault@fnac.net>
+ */
+
+#undef REALLY_SLOW_IO		/* most systems can safely undef this */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+#ifdef CONFIG_BLK_DEV_QD65XX_MODULE
+# define _IDE_C
+# include "ide_modes.h"
+# undef _IDE_C
+#else
+# include "ide_modes.h"
+#endif /* CONFIG_BLK_DEV_QD65XX_MODULE */
+
+#include "qd65xx.h"
+
+/*
+ * I/O ports are 0x30-0x31 (and 0x32-0x33 for qd6580)
+ *            or 0xb0-0xb1 (and 0xb2-0xb3 for qd6580)
+ *	-- qd6500 is a single IDE interface
+ *	-- qd6580 is a dual IDE interface
+ *
+ * More research on qd6580 being done by willmore@cig.mot.com (David)
+ * More Information given by Petr Soucek (petr@ryston.cz)
+ * http://www.ryston.cz/petr/vlb
+ */
+
+/*
+ * base: Timer1
+ *
+ *
+ * base+0x01: Config (R/O)
+ *
+ * bit 0: ide baseport: 1 = 0x1f0 ; 0 = 0x170 (only useful for qd6500)
+ * bit 1: qd65xx baseport: 1 = 0xb0 ; 0 = 0x30
+ * bit 2: ID3: bus speed: 1 = <=33MHz ; 0 = >33MHz
+ * bit 3: qd6500: 1 = disabled, 0 = enabled
+ *        qd6580: 1
+ * upper nibble:
+ *        qd6500: 1100
+ *        qd6580: either 1010 or 0101
+ *
+ *
+ * base+0x02: Timer2 (qd6580 only)
+ *
+ *
+ * base+0x03: Control (qd6580 only)
+ *
+ * bits 0-3 must always be set 1
+ * bit 4 must be set 1, but is set 0 by dos driver while measuring vlb clock
+ * bit 0 : 1 = Only primary port enabled : channel 0 for hda, channel 1 for hdb
+ *         0 = Primary and Secondary ports enabled : channel 0 for hda & hdb
+ *                                                   channel 1 for hdc & hdd
+ * bit 1 : 1 = only disks on primary port
+ *         0 = disks & ATAPI devices on primary port
+ * bit 2-4 : always 0
+ * bit 5 : status, but of what ?
+ * bit 6 : always set 1 by dos driver
+ * bit 7 : set 1 for non-ATAPI devices on primary port
+ *	(maybe read-ahead and post-write buffer ?)
+ */
+
+static int timings[4]={-1,-1,-1,-1}; /* stores current timing for each timer */
+
+static void qd_write_reg (u8 content, u8 reg)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	outb(content,reg);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+u8 __init qd_read_reg (u8 reg)
+{
+	unsigned long flags;
+	u8 read;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	read = inb(reg);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	return read;
+}
+
+/*
+ * qd_select:
+ *
+ * This routine is invoked from ide.c to prepare for access to a given drive.
+ */
+
+static void qd_select (ide_drive_t *drive)
+{
+	u8 index = ((	(QD_TIMREG(drive)) & 0x80 ) >> 7) |
+			(QD_TIMREG(drive) & 0x02);
+
+	if (timings[index] != QD_TIMING(drive))
+		qd_write_reg(timings[index] = QD_TIMING(drive), QD_TIMREG(drive));
+}
+
+/*
+ * qd6500_compute_timing
+ *
+ * computes the timing value where
+ *	lower nibble represents active time,   in count of VLB clocks
+ *	upper nibble represents recovery time, in count of VLB clocks
+ */
+
+static u8 qd6500_compute_timing (ide_hwif_t *hwif, int active_time, int recovery_time)
+{
+	u8 active_cycle,recovery_cycle;
+
+	if (system_bus_clock()<=33) {
+		active_cycle =   9  - IDE_IN(active_time   * system_bus_clock() / 1000 + 1, 2, 9);
+		recovery_cycle = 15 - IDE_IN(recovery_time * system_bus_clock() / 1000 + 1, 0, 15);
+	} else {
+		active_cycle =   8  - IDE_IN(active_time   * system_bus_clock() / 1000 + 1, 1, 8);
+		recovery_cycle = 18 - IDE_IN(recovery_time * system_bus_clock() / 1000 + 1, 3, 18);
+	}
+
+	return((recovery_cycle<<4) | 0x08 | active_cycle);
+}
+
+/*
+ * qd6580_compute_timing
+ *
+ * idem for qd6580
+ */
+
+static u8 qd6580_compute_timing (int active_time, int recovery_time)
+{
+	u8 active_cycle   = 17 - IDE_IN(active_time   * system_bus_clock() / 1000 + 1, 2, 17);
+	u8 recovery_cycle = 15 - IDE_IN(recovery_time * system_bus_clock() / 1000 + 1, 2, 15);
+
+	return((recovery_cycle<<4) | active_cycle);
+}
+
+/*
+ * qd_find_disk_type
+ *
+ * tries to find timing from dos driver's table
+ */
+
+static int qd_find_disk_type (ide_drive_t *drive,
+		int *active_time, int *recovery_time)
+{
+	struct qd65xx_timing_s *p;
+	char model[40];
+
+	if (!*drive->id->model) return 0;
+
+	strncpy(model,drive->id->model,40);
+	ide_fixstring(model,40,1); /* byte-swap */
+
+	for (p = qd65xx_timing ; p->offset != -1 ; p++) {
+		if (!strncmp(p->model, model+p->offset, 4)) {
+			printk(KERN_DEBUG "%s: listed !\n", drive->name);
+			*active_time = p->active;
+			*recovery_time = p->recovery;
+			return 1;
+		}
+	}
+	return 0;
+}
+
+/*
+ * qd_timing_ok:
+ *
+ * check whether timings don't conflict
+ */
+
+static int qd_timing_ok (ide_drive_t drives[])
+{
+	return (IDE_IMPLY(drives[0].present && drives[1].present,
+			IDE_IMPLY(QD_TIMREG(drives) == QD_TIMREG(drives+1),
+			          QD_TIMING(drives) == QD_TIMING(drives+1))));
+	/* if same timing register, must be same timing */
+}
+
+/*
+ * qd_set_timing:
+ *
+ * records the timing, and enables selectproc as needed
+ */
+
+static void qd_set_timing (ide_drive_t *drive, u8 timing)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+
+	drive->drive_data &= 0xff00;
+	drive->drive_data |= timing;
+	if (qd_timing_ok(hwif->drives)) {
+		qd_select(drive); /* selects once */
+		hwif->selectproc = NULL;
+	} else
+		hwif->selectproc = &qd_select;
+
+	printk(KERN_DEBUG "%s: %#x\n", drive->name, timing);
+}
+
+/*
+ * qd6500_tune_drive
+ */
+
+static void qd6500_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	int active_time   = 175;
+	int recovery_time = 415; /* worst case values from the dos driver */
+
+	if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time)
+		&& drive->id->tPIO && (drive->id->field_valid & 0x02)
+		&& drive->id->eide_pio >= 240) {
+
+		printk(KERN_INFO "%s: PIO mode%d\n", drive->name,
+				drive->id->tPIO);
+		active_time = 110;
+		recovery_time = drive->id->eide_pio - 120;
+	}
+
+	qd_set_timing(drive, qd6500_compute_timing(HWIF(drive), active_time, recovery_time));
+}
+
+/*
+ * qd6580_tune_drive
+ */
+
+static void qd6580_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	ide_pio_data_t d;
+	int base = HWIF(drive)->select_data;
+	int active_time   = 175;
+	int recovery_time = 415; /* worst case values from the dos driver */
+
+	if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time)) {
+		pio = ide_get_best_pio_mode(drive, pio, 255, &d);
+		pio = IDE_MIN(pio,4);
+
+		switch (pio) {
+			case 0: break;
+			case 3:
+				if (d.cycle_time >= 110) {
+					active_time = 86;
+					recovery_time = d.cycle_time - 102;
+				} else
+					printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
+				break;
+			case 4:
+				if (d.cycle_time >= 69) {
+					active_time = 70;
+					recovery_time = d.cycle_time - 61;
+				} else
+					printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
+				break;
+			default:
+				if (d.cycle_time >= 180) {
+					active_time = 110;
+					recovery_time = d.cycle_time - 120;
+				} else {
+					active_time = ide_pio_timings[pio].active_time;
+					recovery_time = d.cycle_time
+							-active_time;
+				}
+		}
+		printk(KERN_INFO "%s: PIO mode%d\n", drive->name,pio);
+	}
+
+	if (!HWIF(drive)->channel && drive->media != ide_disk) {
+		qd_write_reg(0x5f, QD_CONTROL_PORT);
+		printk(KERN_WARNING "%s: ATAPI: disabled read-ahead FIFO "
+			"and post-write buffer on %s.\n",
+			drive->name, HWIF(drive)->name);
+	}
+
+	qd_set_timing(drive, qd6580_compute_timing(active_time, recovery_time));
+}
+
+/*
+ * qd_testreg
+ *
+ * tests if the given port is a register
+ */
+
+static int __init qd_testreg(int port)
+{
+	u8 savereg;
+	u8 readreg;
+	unsigned long flags;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	savereg = inb_p(port);
+	outb_p(QD_TESTVAL, port);	/* safe value */
+	readreg = inb_p(port);
+	outb(savereg, port);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+
+	if (savereg == QD_TESTVAL) {
+		printk(KERN_ERR "Outch ! the probe for qd65xx isn't reliable !\n");
+		printk(KERN_ERR "Please contact maintainers to tell about your hardware\n");
+		printk(KERN_ERR "Assuming qd65xx is not present.\n");
+		return 1;
+	}
+
+	return (readreg != QD_TESTVAL);
+}
+
+/*
+ * qd_setup:
+ *
+ * called to setup an ata channel : adjusts attributes & links for tuning
+ */
+
+void __init qd_setup (int unit, int base, int config, unsigned int data0, unsigned int data1, void (*tuneproc) (ide_drive_t *, u8 pio))
+{
+	ide_hwif_t *hwif = &ide_hwifs[unit];
+
+	hwif->chipset = ide_qd65xx;
+	hwif->channel = unit;
+	hwif->select_data = base;
+	hwif->config_data = config;
+	hwif->drives[0].drive_data = data0;
+	hwif->drives[1].drive_data = data1;
+	hwif->drives[0].io_32bit =
+	hwif->drives[1].io_32bit = 1;
+	hwif->tuneproc = tuneproc;
+#ifndef HWIF_PROBE_CLASSIC_METHOD
+	probe_hwif_init(hwif);
+#endif /* HWIF_PROBE_CLASSIC_METHOD */
+}
+
+/*
+ * qd_unsetup:
+ *
+ * called to unsetup an ata channel : back to default values, unlinks tuning
+ */
+void __init qd_unsetup (int unit)
+{
+	ide_hwif_t *hwif = &ide_hwifs[unit];
+	u8 config = hwif->config_data;
+	int base = hwif->select_data;
+	void *tuneproc = (void *) hwif->tuneproc;
+
+	if (!(hwif->chipset == ide_qd65xx)) return;
+
+	printk(KERN_NOTICE "%s: back to defaults\n", hwif->name);
+
+	hwif->selectproc = NULL;
+	hwif->tuneproc = NULL;
+
+	if (tuneproc == (void *) qd6500_tune_drive) {
+		// will do it for both
+		qd_write_reg(QD6500_DEF_DATA, QD_TIMREG(&hwif->drives[0]));
+	} else if (tuneproc == (void *) qd6580_tune_drive) {
+		if (QD_CONTROL(hwif) & QD_CONTR_SEC_DISABLED) {
+			qd_write_reg(QD6580_DEF_DATA, QD_TIMREG(&hwif->drives[0]));
+			qd_write_reg(QD6580_DEF_DATA2, QD_TIMREG(&hwif->drives[1]));
+		} else {
+			qd_write_reg(unit?QD6580_DEF_DATA2:QD6580_DEF_DATA, QD_TIMREG(&hwif->drives[0]));
+		}
+	} else {
+		printk(KERN_WARNING "Unknown qd65xx tuning fonction !\n");
+		printk(KERN_WARNING "keeping settings !\n");
+	}
+}
+
+/*
+ * qd_probe:
+ *
+ * looks at the specified baseport, and if qd found, registers & initialises it
+ * return 1 if another qd may be probed
+ */
+
+int __init qd_probe (int base)
+{
+	u8 config;
+	u8 unit;
+
+	config = qd_read_reg(QD_CONFIG_PORT);
+
+	if (! ((config & QD_CONFIG_BASEPORT) >> 1 == (base == 0xb0)) )
+		return 1;
+
+	unit = ! (config & QD_CONFIG_IDE_BASEPORT);
+
+	if ((config & 0xf0) == QD_CONFIG_QD6500) {
+
+		if (qd_testreg(base)) return 1;		/* bad register */
+
+		/* qd6500 found */
+
+		printk(KERN_NOTICE "%s: qd6500 at %#x\n",
+			ide_hwifs[unit].name, base);
+		
+		printk(KERN_DEBUG "qd6500: config=%#x, ID3=%u\n",
+			config, QD_ID3);
+		
+		if (config & QD_CONFIG_DISABLED) {
+			printk(KERN_WARNING "qd6500 is disabled !\n");
+			return 1;
+		}
+
+		qd_setup(unit, base, config, QD6500_DEF_DATA,
+			QD6500_DEF_DATA, &qd6500_tune_drive);
+		return 1;
+	}
+
+	if (((config & 0xf0) == QD_CONFIG_QD6580_A) ||
+	    ((config & 0xf0) == QD_CONFIG_QD6580_B)) {
+
+		u8 control;
+
+		if (qd_testreg(base) || qd_testreg(base+0x02)) return 1;
+			/* bad registers */
+
+		/* qd6580 found */
+
+		control = qd_read_reg(QD_CONTROL_PORT);
+
+		printk(KERN_NOTICE "qd6580 at %#x\n", base);
+		printk(KERN_DEBUG "qd6580: config=%#x, control=%#x, ID3=%u\n",
+			config, control, QD_ID3);
+
+		if (control & QD_CONTR_SEC_DISABLED) {
+			/* secondary disabled */
+			printk(KERN_INFO "%s: qd6580: single IDE board\n",
+					ide_hwifs[unit].name);
+			qd_setup(unit, base, config | (control << 8),
+				QD6580_DEF_DATA, QD6580_DEF_DATA2,
+				&qd6580_tune_drive);
+			qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT);
+
+			return 1;
+		} else {
+			/* secondary enabled */
+			printk(KERN_INFO "%s&%s: qd6580: dual IDE board\n",
+					ide_hwifs[0].name,ide_hwifs[1].name);
+
+			qd_setup(0, base, config | (control << 8),
+				QD6580_DEF_DATA, QD6580_DEF_DATA,
+				&qd6580_tune_drive);
+			qd_setup(1, base, config | (control << 8),
+				QD6580_DEF_DATA2, QD6580_DEF_DATA2,
+				&qd6580_tune_drive);
+			qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT);
+
+			return 0; /* no other qd65xx possible */
+		}
+	}
+	/* no qd65xx found */
+	return 1;
+}
+
+#ifndef MODULE
+/*
+ * init_qd65xx:
+ *
+ * called by ide.c when parsing command line
+ */
+
+void __init init_qd65xx (void)
+{
+	if (qd_probe(0x30)) qd_probe(0xb0);
+}
+
+#else
+
+MODULE_AUTHOR("Samuel Thibault");
+MODULE_DESCRIPTION("support of qd65xx vlb ide chipset");
+MODULE_LICENSE("GPL");
+
+int __init qd65xx_mod_init(void)
+{
+	if (qd_probe(0x30)) qd_probe(0xb0);
+	if (ide_hwifs[0].chipset != ide_qd65xx &&
+	    ide_hwifs[1].chipset != ide_qd65xx)
+		return -ENODEV;
+	return 0;
+}
+module_init(qd65xx_mod_init);
+
+void __init qd65xx_mod_exit(void)
+{
+	qd_unsetup(0);
+	qd_unsetup(1);
+}
+module_exit(qd65xx_mod_exit);
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/qd65xx.h linux-2.4.21-pre6/drivers/ide/legacy/qd65xx.h
--- linux-2.4.20/drivers/ide/legacy/qd65xx.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/legacy/qd65xx.h	2003-03-26 23:49:20.000000000 +0000
@@ -0,0 +1,140 @@
+/*
+ * linux/drivers/ide/legacy/qd65xx.h
+ *
+ * Copyright (c) 2000	Linus Torvalds & authors
+ */
+
+/*
+ * Authors:	Petr Soucek <petr@ryston.cz>
+ * 		Samuel Thibault <samuel.thibault@fnac.net>
+ */
+
+/* truncates a in [b,c] */
+#define IDE_IN(a,b,c)   ( ((a)<(b)) ? (b) : ( (a)>(c) ? (c) : (a)) )
+
+#define IDE_IMPLY(a,b)	((!(a)) || (b))
+
+#define QD_TIM1_PORT		(base)
+#define QD_CONFIG_PORT		(base+0x01)
+#define QD_TIM2_PORT		(base+0x02)
+#define QD_CONTROL_PORT		(base+0x03)
+
+#define QD_CONFIG_IDE_BASEPORT	0x01
+#define QD_CONFIG_BASEPORT	0x02
+#define QD_CONFIG_ID3		0x04
+#define QD_CONFIG_DISABLED	0x08
+#define QD_CONFIG_QD6500	0xc0
+#define QD_CONFIG_QD6580_A	0xa0
+#define QD_CONFIG_QD6580_B	0x50
+
+#define QD_CONTR_SEC_DISABLED	0x01
+
+#define QD_ID3			((config & QD_CONFIG_ID3)!=0)
+
+#define QD_CONFIG(hwif)		((hwif)->config_data & 0x00ff)
+#define QD_CONTROL(hwif)	(((hwif)->config_data & 0xff00) >> 8)
+
+#define QD_TIMING(drive)	(byte)(((drive)->drive_data) & 0x00ff)
+#define QD_TIMREG(drive)	(byte)((((drive)->drive_data) & 0xff00) >> 8)
+
+#define QD6500_DEF_DATA		((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0c : 0x08))
+#define QD6580_DEF_DATA		((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0a : 0x00))
+#define QD6580_DEF_DATA2	((QD_TIM2_PORT<<8) | (QD_ID3 ? 0x0a : 0x00))
+#define QD_DEF_CONTR		(0x40 | ((control & 0x02) ? 0x9f : 0x1f))
+
+#define QD_TESTVAL		0x19	/* safe value */
+
+/* Drive specific timing taken from DOS driver v3.7 */
+
+struct qd65xx_timing_s {
+	char	offset;   /* ofset from the beginning of Model Number" */
+	char	model[4];    /* 4 chars from Model number, no conversion */
+	short	active;   /* active time */
+	short	recovery; /* recovery time */
+} qd65xx_timing [] = {
+	{ 30, "2040", 110, 225 },  /* Conner CP30204			*/
+	{ 30, "2045", 135, 225 },  /* Conner CP30254			*/
+	{ 30, "1040", 155, 325 },  /* Conner CP30104			*/
+	{ 30, "1047", 135, 265 },  /* Conner CP30174			*/
+	{ 30, "5344", 135, 225 },  /* Conner CP3544			*/
+	{ 30, "01 4", 175, 405 },  /* Conner CP-3104			*/
+	{ 27, "C030", 175, 375 },  /* Conner CP3000			*/
+	{  8, "PL42", 110, 295 },  /* Quantum LP240			*/
+	{  8, "PL21", 110, 315 },  /* Quantum LP120			*/
+	{  8, "PL25", 175, 385 },  /* Quantum LP52			*/
+	{  4, "PA24", 110, 285 },  /* WD Piranha SP4200			*/
+	{  6, "2200", 110, 260 },  /* WD Caviar AC2200			*/
+	{  6, "3204", 110, 235 },  /* WD Caviar AC2340			*/
+	{  6, "1202", 110, 265 },  /* WD Caviar AC2120			*/
+	{  0, "DS3-", 135, 315 },  /* Teac SD340			*/
+	{  8, "KM32", 175, 355 },  /* Toshiba MK234			*/
+	{  2, "53A1", 175, 355 },  /* Seagate ST351A			*/
+	{  2, "4108", 175, 295 },  /* Seagate ST1480A			*/
+	{  2, "1344", 175, 335 },  /* Seagate ST3144A			*/
+	{  6, "7 12", 110, 225 },  /* Maxtor 7213A			*/
+	{ 30, "02F4", 145, 295 },  /* Conner 3204F			*/
+	{  2, "1302", 175, 335 },  /* Seagate ST3120A			*/
+	{  2, "2334", 145, 265 },  /* Seagate ST3243A			*/
+	{  2, "2338", 145, 275 },  /* Seagate ST3283A			*/
+	{  2, "3309", 145, 275 },  /* Seagate ST3390A			*/
+	{  2, "5305", 145, 275 },  /* Seagate ST3550A			*/
+	{  2, "4100", 175, 295 },  /* Seagate ST1400A			*/
+	{  2, "4110", 175, 295 },  /* Seagate ST1401A			*/
+	{  2, "6300", 135, 265 },  /* Seagate ST3600A			*/
+	{  2, "5300", 135, 265 },  /* Seagate ST3500A			*/
+	{  6, "7 31", 135, 225 },  /* Maxtor 7131 AT			*/
+	{  6, "7 43", 115, 265 },  /* Maxtor 7345 AT			*/
+	{  6, "7 42", 110, 255 },  /* Maxtor 7245 AT			*/
+	{  6, "3 04", 135, 265 },  /* Maxtor 340 AT			*/
+	{  6, "61 0", 135, 285 },  /* WD AC160				*/
+	{  6, "1107", 135, 235 },  /* WD AC1170				*/
+	{  6, "2101", 110, 220 },  /* WD AC1210				*/
+	{  6, "4202", 135, 245 },  /* WD AC2420				*/
+	{  6, "41 0", 175, 355 },  /* WD Caviar 140			*/
+	{  6, "82 0", 175, 355 },  /* WD Caviar 280			*/
+	{  8, "PL01", 175, 375 },  /* Quantum LP105			*/
+	{  8, "PL25", 110, 295 },  /* Quantum LP525			*/
+	{ 10, "4S 2", 175, 385 },  /* Quantum ELS42			*/
+	{ 10, "8S 5", 175, 385 },  /* Quantum ELS85			*/
+	{ 10, "1S72", 175, 385 },  /* Quantum ELS127			*/
+	{ 10, "1S07", 175, 385 },  /* Quantum ELS170			*/
+	{  8, "ZE42", 135, 295 },  /* Quantum EZ240			*/
+	{  8, "ZE21", 175, 385 },  /* Quantum EZ127			*/
+	{  8, "ZE58", 175, 385 },  /* Quantum EZ85			*/
+	{  8, "ZE24", 175, 385 },  /* Quantum EZ42			*/
+	{ 27, "C036", 155, 325 },  /* Conner CP30064			*/
+	{ 27, "C038", 155, 325 },  /* Conner CP30084			*/
+	{  6, "2205", 110, 255 },  /* WDC AC2250			*/
+	{  2, " CHA", 140, 415 },  /* WDC AH series; WDC AH260, WDC	*/
+	{  2, " CLA", 140, 415 },  /* WDC AL series: WDC AL2120, 2170,	*/
+	{  4, "UC41", 140, 415 },  /* WDC CU140				*/
+	{  6, "1207", 130, 275 },  /* WDC AC2170			*/
+	{  6, "2107", 130, 275 },  /* WDC AC1270			*/
+	{  6, "5204", 130, 275 },  /* WDC AC2540			*/
+	{ 30, "3004", 110, 235 },  /* Conner CP30340			*/
+	{ 30, "0345", 135, 255 },  /* Conner CP30544			*/
+	{ 12, "12A3", 175, 320 },  /* MAXTOR LXT-213A			*/
+	{ 12, "43A0", 145, 240 },  /* MAXTOR LXT-340A			*/
+	{  6, "7 21", 180, 290 },  /* Maxtor 7120 AT			*/
+	{  6, "7 71", 135, 240 },  /* Maxtor 7170 AT			*/
+	{ 12, "45\0000", 110, 205 },   /* MAXTOR MXT-540		*/
+	{  8, "PL11", 180, 290 },  /* QUANTUM LP110A			*/
+	{  8, "OG21", 150, 275 },  /* QUANTUM GO120			*/
+	{ 12, "42A5", 175, 320 },  /* MAXTOR LXT-245A			*/
+	{  2, "2309", 175, 295 },  /* ST3290A				*/
+	{  2, "3358", 180, 310 },  /* ST3385A				*/
+	{  2, "6355", 180, 310 },  /* ST3655A				*/
+	{  2, "1900", 175, 270 },  /* ST9100A				*/
+	{  2, "1954", 175, 270 },  /* ST9145A				*/
+	{  2, "1909", 175, 270 },  /* ST9190AG				*/
+	{  2, "2953", 175, 270 },  /* ST9235A				*/
+	{  2, "1359", 175, 270 },  /* ST3195A				*/
+	{ 24, "3R11", 175, 290 },  /* ALPS ELECTRIC Co.,LTD, DR311C	*/
+	{  0, "2M26", 175, 215 },  /* M262XT-0Ah			*/
+	{  4, "2253", 175, 300 },  /* HP C2235A				*/
+	{  4, "-32A", 145, 245 },  /* H3133-A2				*/
+	{ 30, "0326", 150, 270 },  /* Samsung Electronics 120MB		*/
+	{ 30, "3044", 110, 195 },  /* Conner CFA340A			*/
+	{ 30, "43A0", 110, 195 },  /* Conner CFA340A			*/
+	{ -1, "    ", 175, 415 }   /* unknown disk name			*/
+};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/legacy/umc8672.c linux-2.4.21-pre6/drivers/ide/legacy/umc8672.c
--- linux-2.4.20/drivers/ide/legacy/umc8672.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/legacy/umc8672.c	2003-03-26 23:49:25.000000000 +0000
@@ -0,0 +1,237 @@
+/*
+ *  linux/drivers/ide/legacy/umc8672.c		Version 0.05	Jul 31, 1996
+ *
+ *  Copyright (C) 1995-1996  Linus Torvalds & author (see below)
+ */
+
+/*
+ *  Principal Author/Maintainer:  PODIEN@hml2.atlas.de (Wolfram Podien)
+ *
+ *  This file provides support for the advanced features
+ *  of the UMC 8672 IDE interface.
+ *
+ *  Version 0.01	Initial version, hacked out of ide.c,
+ *			and #include'd rather than compiled separately.
+ *			This will get cleaned up in a subsequent release.
+ *
+ *  Version 0.02	now configs/compiles separate from ide.c  -ml
+ *  Version 0.03	enhanced auto-tune, fix display bug
+ *  Version 0.05	replace sti() with restore_flags()  -ml
+ *			add detection of possible race condition  -ml
+ */
+
+/*
+ * VLB Controller Support from 
+ * Wolfram Podien
+ * Rohoefe 3
+ * D28832 Achim
+ * Germany
+ *
+ * To enable UMC8672 support there must a lilo line like
+ * append="ide0=umc8672"...
+ * To set the speed according to the abilities of the hardware there must be a
+ * line like
+ * #define UMC_DRIVE0 11
+ * in the beginning of the driver, which sets the speed of drive 0 to 11 (there
+ * are some lines present). 0 - 11 are allowed speed values. These values are
+ * the results from the DOS speed test program supplied from UMC. 11 is the 
+ * highest speed (about PIO mode 3)
+ */
+#define REALLY_SLOW_IO		/* some systems can safely undef this */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#ifdef CONFIG_BLK_DEV_UMC8672_MODULE
+# define _IDE_C
+# include "ide_modes.h"
+# undef _IDE_C
+#else
+# include "ide_modes.h"
+#endif /* CONFIG_BLK_DEV_UMC8672_MODULE */
+
+/*
+ * Default speeds.  These can be changed with "auto-tune" and/or hdparm.
+ */
+#define UMC_DRIVE0      1              /* DOS measured drive speeds */
+#define UMC_DRIVE1      1              /* 0 to 11 allowed */
+#define UMC_DRIVE2      1              /* 11 = Fastest Speed */
+#define UMC_DRIVE3      1              /* In case of crash reduce speed */
+
+static u8 current_speeds[4] = {UMC_DRIVE0, UMC_DRIVE1, UMC_DRIVE2, UMC_DRIVE3};
+static const u8 pio_to_umc [5] = {0,3,7,10,11};	/* rough guesses */
+
+/*       0    1    2    3    4    5    6    7    8    9    10   11      */
+static const u8 speedtab [3][12] = {
+	{0xf, 0xb, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 },
+	{0x3, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 },
+	{0xff,0xcb,0xc0,0x58,0x36,0x33,0x23,0x22,0x21,0x11,0x10,0x0}};
+
+static void out_umc (char port,char wert)
+{
+	outb_p(port,0x108);
+	outb_p(wert,0x109);
+}
+
+static inline u8 in_umc (char port)
+{
+	outb_p(port,0x108);
+	return inb_p(0x109);
+}
+
+static void umc_set_speeds (u8 speeds[])
+{
+	int i, tmp;
+
+	outb_p(0x5A,0x108); /* enable umc */
+
+	out_umc (0xd7,(speedtab[0][speeds[2]] | (speedtab[0][speeds[3]]<<4)));
+	out_umc (0xd6,(speedtab[0][speeds[0]] | (speedtab[0][speeds[1]]<<4)));
+	tmp = 0;
+	for (i = 3; i >= 0; i--) {
+		tmp = (tmp << 2) | speedtab[1][speeds[i]];
+	}
+	out_umc (0xdc,tmp);
+	for (i = 0;i < 4; i++) {
+		out_umc (0xd0+i,speedtab[2][speeds[i]]);
+		out_umc (0xd8+i,speedtab[2][speeds[i]]);
+	}
+	outb_p(0xa5,0x108); /* disable umc */
+
+	printk ("umc8672: drive speeds [0 to 11]: %d %d %d %d\n",
+		speeds[0], speeds[1], speeds[2], speeds[3]);
+}
+
+static void tune_umc (ide_drive_t *drive, u8 pio)
+{
+	unsigned long flags;
+	ide_hwgroup_t *hwgroup = ide_hwifs[HWIF(drive)->index^1].hwgroup;
+
+	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+	printk("%s: setting umc8672 to PIO mode%d (speed %d)\n",
+		drive->name, pio, pio_to_umc[pio]);
+	spin_lock_irqsave(&io_request_lock, flags);
+	if (hwgroup && hwgroup->handler != NULL) {
+		printk(KERN_ERR "umc8672: other interface is busy: exiting tune_umc()\n");
+	} else {
+		current_speeds[drive->name[2] - 'a'] = pio_to_umc[pio];
+		umc_set_speeds (current_speeds);
+	}
+	spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+int __init probe_umc8672 (void)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	if (!request_region(0x108, 2, "umc8672")) {
+		local_irq_restore(flags);
+		printk(KERN_ERR "umc8672: ports 0x108-0x109 already in use.\n");
+		return 1;
+	}
+	outb_p(0x5A,0x108); /* enable umc */
+	if (in_umc (0xd5) != 0xa0) {
+		local_irq_restore(flags);
+		printk(KERN_ERR "umc8672: not found\n");
+		release_region(0x108, 2);
+		return 1;  
+	}
+	outb_p(0xa5,0x108); /* disable umc */
+
+	umc_set_speeds (current_speeds);
+	local_irq_restore(flags);
+
+	ide_hwifs[0].chipset = ide_umc8672;
+	ide_hwifs[1].chipset = ide_umc8672;
+	ide_hwifs[0].tuneproc = &tune_umc;
+	ide_hwifs[1].tuneproc = &tune_umc;
+	ide_hwifs[0].mate = &ide_hwifs[1];
+	ide_hwifs[1].mate = &ide_hwifs[0];
+	ide_hwifs[1].channel = 1;
+
+#ifndef HWIF_PROBE_CLASSIC_METHOD
+	probe_hwif_init(&ide_hwifs[0]);
+	probe_hwif_init(&ide_hwifs[1]);
+#endif /* HWIF_PROBE_CLASSIC_METHOD */
+
+	return 0;
+}
+
+void __init umc8672_release (void)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	if (ide_hwifs[0].chipset != ide_umc8672 &&
+	    ide_hwifs[1].chipset != ide_umc8672) {
+		local_irq_restore(flags);
+		return;
+	}
+
+	ide_hwifs[0].chipset = ide_unknown;
+	ide_hwifs[1].chipset = ide_unknown;	
+	ide_hwifs[0].tuneproc = NULL;
+	ide_hwifs[1].tuneproc = NULL;
+	ide_hwifs[0].mate = NULL;
+	ide_hwifs[1].mate = NULL;
+	ide_hwifs[0].channel = 0;
+	ide_hwifs[1].channel = 0;
+
+	outb_p(0xa5,0x108); /* disable umc */
+
+	release_region(0x108, 2);
+	local_irq_restore(flags);
+}
+
+#ifndef MODULE
+/*
+ * init_umc8672:
+ *
+ * called by ide.c when parsing command line
+ */
+
+void __init init_umc8672 (void)
+{
+	if (probe_umc8672())
+		printk(KERN_ERR "init_umc8672: umc8672 controller not found.\n");
+}
+
+#else
+
+MODULE_AUTHOR("Wolfram Podien");
+MODULE_DESCRIPTION("Support for UMC 8672 IDE chipset");
+MODULE_LICENSE("GPL");
+
+int __init umc8672_mod_init(void)
+{
+	if (probe_umc8672())
+		return -ENODEV;
+	if (ide_hwifs[0].chipset != ide_umc8672 &&
+	    ide_hwifs[1].chipset != ide_umc8672) {
+		umc8672_release();
+		return -ENODEV;
+	}
+	return 0;
+}
+module_init(umc8672_mod_init);
+
+void __init umc8672_mod_exit(void)
+{
+        umc8672_release();
+}
+module_exit(umc8672_mod_exit);
+#endif
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/macide.c linux-2.4.21-pre6/drivers/ide/macide.c
--- linux-2.4.20/drivers/ide/macide.c	2001-01-04 23:25:55.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/macide.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,147 +0,0 @@
-/*
- *  linux/drivers/ide/macide.c -- Macintosh IDE Driver
- *
- *     Copyright (C) 1998 by Michael Schmitz
- *
- *  This driver was written based on information obtained from the MacOS IDE
- *  driver binary by Mikael Forselius
- *
- *  This file is subject to the terms and conditions of the GNU General Public
- *  License.  See the file COPYING in the main directory of this archive for
- *  more details.
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-
-#include <asm/machw.h>
-#include <asm/macintosh.h>
-#include <asm/macints.h>
-#include <asm/mac_baboon.h>
-
-#define IDE_BASE 0x50F1A000	/* Base address of IDE controller */
-
-/*
- * Generic IDE registers as offsets from the base
- * These match MkLinux so they should be correct.
- */
-
-#define IDE_DATA	0x00
-#define IDE_ERROR	0x04	/* see err-bits */
-#define IDE_NSECTOR	0x08	/* nr of sectors to read/write */
-#define IDE_SECTOR	0x0c	/* starting sector */
-#define IDE_LCYL	0x10	/* starting cylinder */
-#define IDE_HCYL	0x14	/* high byte of starting cyl */
-#define IDE_SELECT	0x18	/* 101dhhhh , d=drive, hhhh=head */
-#define IDE_STATUS	0x1c	/* see status-bits */
-#define IDE_CONTROL	0x38	/* control/altstatus */
-
-/*
- * Mac-specific registers
- */
-
-/*
- * this register is odd; it doesn't seem to do much and it's
- * not word-aligned like virtually every other hardware register
- * on the Mac...
- */
-
-#define IDE_IFR		0x101	/* (0x101) IDE interrupt flags on Quadra:
-				 *
-				 * Bit 0+1: some interrupt flags
-				 * Bit 2+3: some interrupt enable
-				 * Bit 4:   ??
-				 * Bit 5:   IDE interrupt flag (any hwif)
-				 * Bit 6:   maybe IDE interrupt enable (any hwif) ??
-				 * Bit 7:   Any interrupt condition
-				 */
-
-volatile unsigned char *ide_ifr = (unsigned char *) (IDE_BASE + IDE_IFR);
-
-static int macide_offsets[IDE_NR_PORTS] = {
-    IDE_DATA, IDE_ERROR,  IDE_NSECTOR, IDE_SECTOR, IDE_LCYL,
-    IDE_HCYL, IDE_SELECT, IDE_STATUS,  IDE_CONTROL
-};
-
-int macide_ack_intr(ide_hwif_t* hwif)
-{
-	if (*ide_ifr & 0x20) {
-		*ide_ifr &= ~0x20;
-		return 1;
-	}
-	return 0;
-}
-
-#ifdef CONFIG_BLK_DEV_MAC_MEDIABAY
-static void macide_mediabay_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	int state = baboon->mb_status & 0x04;
-
-	printk("macide: media bay %s detected\n", state? "removal":"insertion");
-}
-#endif
-
-/*
- * Probe for a Macintosh IDE interface
- */
-
-void macide_init(void)
-{
-	hw_regs_t hw;
-	int index = -1;
-
-	switch (macintosh_config->ide_type) {
-	case MAC_IDE_QUADRA:
-		ide_setup_ports(&hw, (ide_ioreg_t)IDE_BASE, macide_offsets,
-				0, 0, macide_ack_intr, IRQ_NUBUS_F);
-		index = ide_register_hw(&hw, NULL);
-		break;
-	case MAC_IDE_PB:
-		ide_setup_ports(&hw, (ide_ioreg_t)IDE_BASE, macide_offsets,
-				0, 0, macide_ack_intr, IRQ_NUBUS_C);
-		index = ide_register_hw(&hw, NULL);
-		break;
-	case MAC_IDE_BABOON:
-		ide_setup_ports(&hw, (ide_ioreg_t)BABOON_BASE, macide_offsets,
-				0, 0, NULL, IRQ_BABOON_1);
-		index = ide_register_hw(&hw, NULL);
-		if (index == -1) break;
-		if (macintosh_config->ident == MAC_MODEL_PB190) {
-
-			/* Fix breakage in ide-disk.c: drive capacity	*/
-			/* is not initialized for drives without a 	*/
-			/* hardware ID, and we cna't get that without	*/
-			/* probing the drive which freezes a 190.	*/
-
-			ide_drive_t *drive = &ide_hwifs[index].drives[0];
-        		drive->capacity = drive->cyl*drive->head*drive->sect;
-
-#ifdef CONFIG_BLK_DEV_MAC_MEDIABAY
-			request_irq(IRQ_BABOON_2, macide_mediabay_interrupt,
-					IRQ_FLG_FAST, "mediabay",
-					macide_mediabay_interrupt);
-#endif
-		}
-		break;
-
-	default:
-	    return;
-	}
-
-        if (index != -1) {
-		if (macintosh_config->ide_type == MAC_IDE_QUADRA)
-			printk("ide%d: Macintosh Quadra IDE interface\n", index);
-		else if (macintosh_config->ide_type == MAC_IDE_PB)
-			printk("ide%d: Macintosh Powerbook IDE interface\n", index);
-		else if (macintosh_config->ide_type == MAC_IDE_BABOON)
-			printk("ide%d: Macintosh Powerbook Baboon IDE interface\n", index);
-		else
-			printk("ide%d: Unknown Macintosh IDE interface\n", index);
-	}
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ns87415.c linux-2.4.21-pre6/drivers/ide/ns87415.c
--- linux-2.4.20/drivers/ide/ns87415.c	2000-06-20 14:52:36.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/ns87415.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,193 +0,0 @@
-/*
- * linux/drivers/ide/ns87415.c		Version 1.01  Mar. 18, 2000
- *
- * Copyright (C) 1997-1998	Mark Lord <mlord@pobox.com>
- * Copyright (C) 1998		Eddie C. Dost <ecd@skynet.be>
- * Copyright (C) 1999-2000	Andre Hedrick <andre@linux-ide.org>
- *
- * Inspired by an earlier effort from David S. Miller <davem@redhat.com>
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-static unsigned int ns87415_count = 0, ns87415_control[MAX_HWIFS] = { 0 };
-
-/*
- * This routine either enables/disables (according to drive->present)
- * the IRQ associated with the port (HWIF(drive)),
- * and selects either PIO or DMA handshaking for the next I/O operation.
- */
-static void ns87415_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	unsigned int bit, other, new, *old = (unsigned int *) hwif->select_data;
-	struct pci_dev *dev = hwif->pci_dev;
-	unsigned long flags;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-	new = *old;
-
-	/* Adjust IRQ enable bit */
-	bit = 1 << (8 + hwif->channel);
-	new = drive->present ? (new & ~bit) : (new | bit);
-
-	/* Select PIO or DMA, DMA may only be selected for one drive/channel. */
-	bit   = 1 << (20 + drive->select.b.unit       + (hwif->channel << 1));
-	other = 1 << (20 + (1 - drive->select.b.unit) + (hwif->channel << 1));
-	new = use_dma ? ((new & ~other) | bit) : (new & ~bit);
-
-	if (new != *old) {
-		unsigned char stat;
-
-		/*
-		 * Don't change DMA engine settings while Write Buffers
-		 * are busy.
-		 */
-		(void) pci_read_config_byte(dev, 0x43, &stat);
-		while (stat & 0x03) {
-			udelay(1);
-			(void) pci_read_config_byte(dev, 0x43, &stat);
-		}
-
-		*old = new;
-		(void) pci_write_config_dword(dev, 0x40, new);
-
-		/*
-		 * And let things settle...
-		 */
-		udelay(10);
-	}
-
-	__restore_flags(flags);	/* local CPU only */
-}
-
-static void ns87415_selectproc (ide_drive_t *drive)
-{
-	ns87415_prepare_drive (drive, drive->using_dma);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int ns87415_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-	ide_hwif_t	*hwif = HWIF(drive);
-	byte		dma_stat;
-
-	switch (func) {
-		case ide_dma_end: /* returns 1 on error, 0 otherwise */
-			drive->waiting_for_dma = 0;
-			dma_stat = inb(hwif->dma_base+2);
-			outb(inb(hwif->dma_base)&~1, hwif->dma_base);	/* stop DMA */
-			outb(inb(hwif->dma_base)|6, hwif->dma_base);	/* from ERRATA: clear the INTR & ERROR bits */
-			ide_destroy_dmatable(drive);			/* and free any DMA resources */
-			return (dma_stat & 7) != 4;		/* verify good DMA status */
-		case ide_dma_write:
-		case ide_dma_read:
-			ns87415_prepare_drive(drive, 1);	/* select DMA xfer */
-			if (!ide_dmaproc(func, drive))		/* use standard DMA stuff */
-				return 0;
-			ns87415_prepare_drive(drive, 0);	/* DMA failed: select PIO xfer */
-			return 1;
-		case ide_dma_check:
-			if (drive->media != ide_disk)
-				return ide_dmaproc(ide_dma_off_quietly, drive);
-			/* Fallthrough... */
-		default:
-			return ide_dmaproc(func, drive);	/* use standard DMA stuff */
-	}
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-void __init ide_init_ns87415 (ide_hwif_t *hwif)
-{
-	struct pci_dev *dev = hwif->pci_dev;
-	unsigned int ctrl, using_inta;
-	byte progif;
-#ifdef __sparc_v9__
-	int timeout;
-	byte stat;
-#endif
-
-	/* Set a good latency timer and cache line size value. */
-	(void) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
-#ifdef __sparc_v9__
-	(void) pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x10);
-#endif
-
-	/*
-	 * We cannot probe for IRQ: both ports share common IRQ on INTA.
-	 * Also, leave IRQ masked during drive probing, to prevent infinite
-	 * interrupts from a potentially floating INTA..
-	 *
-	 * IRQs get unmasked in selectproc when drive is first used.
-	 */
-	(void) pci_read_config_dword(dev, 0x40, &ctrl);
-	(void) pci_read_config_byte(dev, 0x09, &progif);
-	/* is irq in "native" mode? */
-	using_inta = progif & (1 << (hwif->channel << 1));
-	if (!using_inta)
-		using_inta = ctrl & (1 << (4 + hwif->channel));
-	if (hwif->mate) {
-		hwif->select_data = hwif->mate->select_data;
-	} else {
-		hwif->select_data = (unsigned long)
-					&ns87415_control[ns87415_count++];
-		ctrl |= (1 << 8) | (1 << 9);	/* mask both IRQs */
-		if (using_inta)
-			ctrl &= ~(1 << 6);	/* unmask INTA */
-		*((unsigned int *)hwif->select_data) = ctrl;
-		(void) pci_write_config_dword(dev, 0x40, ctrl);
-
-		/*
-		 * Set prefetch size to 512 bytes for both ports,
-		 * but don't turn on/off prefetching here.
-		 */
-		pci_write_config_byte(dev, 0x55, 0xee);
-
-#ifdef __sparc_v9__
-		/*
-		 * XXX: Reset the device, if we don't it will not respond
-		 *      to SELECT_DRIVE() properly during first probe_hwif().
-		 */
-		timeout = 10000;
-		outb(12, hwif->io_ports[IDE_CONTROL_OFFSET]);
-		udelay(10);
-		outb(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
-		do {
-			udelay(50);
-			stat = inb(hwif->io_ports[IDE_STATUS_OFFSET]);
-                	if (stat == 0xff)
-                        	break;
-        	} while ((stat & BUSY_STAT) && --timeout);
-#endif
-	}
-
-	if (hwif->dma_base)
-		outb(0x60, hwif->dma_base + 2);
-
-	if (!using_inta)
-		hwif->irq = hwif->channel ? 15 : 14;	/* legacy mode */
-	else if (!hwif->irq && hwif->mate && hwif->mate->irq)
-		hwif->irq = hwif->mate->irq;	/* share IRQ with mate */
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (hwif->dma_base)
-		hwif->dmaproc = &ns87415_dmaproc;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-	hwif->selectproc = &ns87415_selectproc;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/opti621.c linux-2.4.21-pre6/drivers/ide/opti621.c
--- linux-2.4.20/drivers/ide/opti621.c	2001-05-01 23:05:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/opti621.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,316 +0,0 @@
-/*
- *  linux/drivers/ide/opti621.c		Version 0.6	Jan 02, 1999
- *
- *  Copyright (C) 1996-1998  Linus Torvalds & authors (see below)
- */
-
-/*
- * Authors:
- * Jaromir Koutek <miri@punknet.cz>,
- * Jan Harkes <jaharkes@cwi.nl>,
- * Mark Lord <mlord@pobox.com>
- * Some parts of code are from ali14xx.c and from rz1000.c.
- *
- * OPTi is trademark of OPTi, Octek is trademark of Octek.
- *
- * I used docs from OPTi databook, from ftp.opti.com, file 9123-0002.ps
- * and disassembled/traced setupvic.exe (DOS program).
- * It increases kernel code about 2 kB.
- * I don't have this card no more, but I hope I can get some in case
- * of needed development.
- * My card is Octek PIDE 1.01 (on card) or OPTiViC (program).
- * It has a place for a secondary connector in circuit, but nothing
- * is there. Also BIOS says no address for
- * secondary controller (see bellow in ide_init_opti621).
- * I've only tested this on my system, which only has one disk.
- * It's Western Digital WDAC2850, with PIO mode 3. The PCI bus
- * is at 20 MHz (I have DX2/80, I tried PCI at 40, but I got random
- * lockups). I tried the OCTEK double speed CD-ROM and
- * it does not work! But I can't boot DOS also, so it's probably
- * hardware fault. I have connected Conner 80MB, the Seagate 850MB (no
- * problems) and Seagate 1GB (as slave, WD as master). My experiences
- * with the third, 1GB drive: I got 3MB/s (hdparm), but sometimes
- * it slows to about 100kB/s! I don't know why and I have
- * not this drive now, so I can't try it again.
- * I write this driver because I lost the paper ("manual") with
- * settings of jumpers on the card and I have to boot Linux with
- * Loadlin except LILO, cause I have to run the setupvic.exe program
- * already or I get disk errors (my test: rpm -Vf
- * /usr/X11R6/bin/XF86_SVGA - or any big file).
- * Some numbers from hdparm -t /dev/hda:
- * Timing buffer-cache reads:   32 MB in  3.02 seconds =10.60 MB/sec
- * Timing buffered disk reads:  16 MB in  5.52 seconds = 2.90 MB/sec
- * I have 4 Megs/s before, but I don't know why (maybe changes
- * in hdparm test).
- * After release of 0.1, I got some successful reports, so it might work.
- *
- * The main problem with OPTi is that some timings for master
- * and slave must be the same. For example, if you have master
- * PIO 3 and slave PIO 0, driver have to set some timings of
- * master for PIO 0. Second problem is that opti621_tune_drive
- * got only one drive to set, but have to set both drives.
- * This is solved in compute_pios. If you don't set
- * the second drive, compute_pios use ide_get_best_pio_mode
- * for autoselect mode (you can change it to PIO 0, if you want).
- * If you then set the second drive to another PIO, the old value
- * (automatically selected) will be overrided by yours.
- * There is a 25/33MHz switch in configuration
- * register, but driver is written for use at any frequency which get
- * (use idebus=xx to select PCI bus speed).
- * Use ide0=autotune for automatical tune of the PIO modes.
- * If you get strange results, do not use this and set PIO manually
- * by hdparm.
- *
- * Version 0.1, Nov 8, 1996
- * by Jaromir Koutek, for 2.1.8. 
- * Initial version of driver.
- * 
- * Version 0.2
- * Number 0.2 skipped.
- *
- * Version 0.3, Nov 29, 1997
- * by Mark Lord (probably), for 2.1.68
- * Updates for use with new IDE block driver.
- *
- * Version 0.4, Dec 14, 1997
- * by Jan Harkes
- * Fixed some errors and cleaned the code.
- *
- * Version 0.5, Jan 2, 1998
- * by Jaromir Koutek
- * Updates for use with (again) new IDE block driver.
- * Update of documentation.
- * 
- * Version 0.6, Jan 2, 1999
- * by Jaromir Koutek
- * Reversed to version 0.3 of the driver, because
- * 0.5 doesn't work.
- */
-
-#undef REALLY_SLOW_IO	/* most systems can safely undef this */
-#define OPTI621_DEBUG		/* define for debug messages */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-#define OPTI621_MAX_PIO 3
-/* In fact, I do not have any PIO 4 drive
- * (address: 25 ns, data: 70 ns, recovery: 35 ns),
- * but OPTi 82C621 is programmable and it can do (minimal values):
- * on 40MHz PCI bus (pulse 25 ns):
- *  address: 25 ns, data: 25 ns, recovery: 50 ns;
- * on 20MHz PCI bus (pulse 50 ns):
- *  address: 50 ns, data: 50 ns, recovery: 100 ns.
- */
-
-/* #define READ_PREFETCH 0 */
-/* Uncommnent for disable read prefetch.
- * There is some readprefetch capatibility in hdparm,
- * but when I type hdparm -P 1 /dev/hda, I got errors
- * and till reset drive is inaccessible.
- * This (hw) read prefetch is safe on my drive.
- */
-
-#ifndef READ_PREFETCH
-#define READ_PREFETCH 0x40 /* read prefetch is enabled */
-#endif /* else read prefetch is disabled */
-
-#define READ_REG 0	/* index of Read cycle timing register */
-#define WRITE_REG 1	/* index of Write cycle timing register */
-#define CNTRL_REG 3	/* index of Control register */
-#define STRAP_REG 5	/* index of Strap register */
-#define MISC_REG 6	/* index of Miscellaneous register */
-
-int reg_base;
-
-#define PIO_NOT_EXIST 254
-#define PIO_DONT_KNOW 255
-
-/* there are stored pio numbers from other calls of opti621_tune_drive */
-
-static void compute_pios(ide_drive_t *drive, byte pio)
-/* Store values into drive->drive_data
- *	second_contr - 0 for primary controller, 1 for secondary
- *	slave_drive - 0 -> pio is for master, 1 -> pio is for slave
- *	pio - PIO mode for selected drive (for other we don't know)
- */
-{
-	int d;
-	ide_hwif_t *hwif = HWIF(drive);
-
-	drive->drive_data = ide_get_best_pio_mode(drive, pio, OPTI621_MAX_PIO, NULL);
-	for (d = 0; d < 2; ++d) {
-		drive = &hwif->drives[d];
-		if (drive->present) {
-			if (drive->drive_data == PIO_DONT_KNOW)
-				drive->drive_data = ide_get_best_pio_mode(drive, 255, OPTI621_MAX_PIO, NULL);
-#ifdef OPTI621_DEBUG
-			printk("%s: Selected PIO mode %d\n", drive->name, drive->drive_data);
-#endif
-		} else {
-			drive->drive_data = PIO_NOT_EXIST;
-		}
-	}
-}
-
-int cmpt_clk(int time, int bus_speed)
-/* Returns (rounded up) time in clocks for time in ns,
- * with bus_speed in MHz.
- * Example: bus_speed = 40 MHz, time = 80 ns
- * 1000/40 = 25 ns (clk value),
- * 80/25 = 3.2, rounded up to 4 (I hope ;-)).
- * Use idebus=xx to select right frequency.
- */
-{
-	return ((time*bus_speed+999)/1000);
-}
-
-static void write_reg(byte value, int reg)
-/* Write value to register reg, base of register
- * is at reg_base (0x1f0 primary, 0x170 secondary,
- * if not changed by PCI configuration).
- * This is from setupvic.exe program.
- */
-{
-	inw(reg_base+1);
-	inw(reg_base+1);
-	outb(3, reg_base+2);
-	outb(value, reg_base+reg);
-	outb(0x83, reg_base+2);
-}
-
-static byte read_reg(int reg)
-/* Read value from register reg, base of register
- * is at reg_base (0x1f0 primary, 0x170 secondary,
- * if not changed by PCI configuration).
- * This is from setupvic.exe program.
- */
-{
-	byte ret;
-	inw(reg_base+1);
-	inw(reg_base+1);
-	outb(3, reg_base+2);
-	ret=inb(reg_base+reg);
-	outb(0x83, reg_base+2);
-	return ret;
-}
-
-typedef struct pio_clocks_s {
-	int	address_time;	/* Address setup (clocks) */
-	int	data_time;	/* Active/data pulse (clocks) */
-	int	recovery_time;	/* Recovery time (clocks) */
-} pio_clocks_t;
-
-static void compute_clocks(int pio, pio_clocks_t *clks)
-{
-        if (pio != PIO_NOT_EXIST) {
-        	int adr_setup, data_pls;
-		int bus_speed = system_bus_clock();
-
- 	       	adr_setup = ide_pio_timings[pio].setup_time;
-  	      	data_pls = ide_pio_timings[pio].active_time;
-	  	clks->address_time = cmpt_clk(adr_setup, bus_speed);
-	     	clks->data_time = cmpt_clk(data_pls, bus_speed);
-     		clks->recovery_time = cmpt_clk(ide_pio_timings[pio].cycle_time
-     			- adr_setup-data_pls, bus_speed);
-     		if (clks->address_time<1) clks->address_time = 1;
-     		if (clks->address_time>4) clks->address_time = 4;
-     		if (clks->data_time<1) clks->data_time = 1;
-     		if (clks->data_time>16) clks->data_time = 16;
-     		if (clks->recovery_time<2) clks->recovery_time = 2;
-     		if (clks->recovery_time>17) clks->recovery_time = 17;
-	} else {
-		clks->address_time = 1;
-		clks->data_time = 1;
-		clks->recovery_time = 2;
-		/* minimal values */
-	}
- 
-}
-
-/* Main tune procedure, called from tuneproc. */
-static void opti621_tune_drive (ide_drive_t *drive, byte pio)
-{
-	/* primary and secondary drives share some registers,
-	 * so we have to program both drives
-	 */
-	unsigned long flags;
-	byte pio1, pio2;
-	pio_clocks_t first, second;
-	int ax, drdy;
-	byte cycle1, cycle2, misc;
-	ide_hwif_t *hwif = HWIF(drive);
-
-	/* sets drive->drive_data for both drives */
-	compute_pios(drive, pio);
- 	pio1 = hwif->drives[0].drive_data;
- 	pio2 = hwif->drives[1].drive_data;
-
-	compute_clocks(pio1, &first);
-	compute_clocks(pio2, &second);
-
-	/* ax = max(a1,a2) */
-	ax = (first.address_time < second.address_time) ? second.address_time : first.address_time;
-
-	drdy = 2; /* DRDY is default 2 (by OPTi Databook) */
-
-	cycle1 = ((first.data_time-1)<<4)  | (first.recovery_time-2);
-	cycle2 = ((second.data_time-1)<<4) | (second.recovery_time-2);
-	misc = READ_PREFETCH | ((ax-1)<<4) | ((drdy-2)<<1);
-
-#ifdef OPTI621_DEBUG
-	printk("%s: master: address: %d, data: %d, recovery: %d, drdy: %d [clk]\n",
-		hwif->name, ax, first.data_time, first.recovery_time, drdy);
-	printk("%s: slave:  address: %d, data: %d, recovery: %d, drdy: %d [clk]\n",
-		hwif->name, ax, second.data_time, second.recovery_time, drdy);
-#endif
-
-	save_flags(flags);	/* all CPUs */
-	cli();			/* all CPUs */
-
-     	reg_base = hwif->io_ports[IDE_DATA_OFFSET];
-	outb(0xc0, reg_base+CNTRL_REG);	/* allow Register-B */
-	outb(0xff, reg_base+5);		/* hmm, setupvic.exe does this ;-) */
-	inb(reg_base+CNTRL_REG); 	/* if reads 0xff, adapter not exist? */
-	read_reg(CNTRL_REG);		/* if reads 0xc0, no interface exist? */
-	read_reg(STRAP_REG);		/* read version, probably 0 */
-
-	/* program primary drive */
-	write_reg(0,      MISC_REG);	/* select Index-0 for Register-A */
-	write_reg(cycle1, READ_REG);	/* set read cycle timings */
-	write_reg(cycle1, WRITE_REG);	/* set write cycle timings */
-
-	/* program secondary drive */
-	write_reg(1,      MISC_REG);	/* select Index-1 for Register-B */
-	write_reg(cycle2, READ_REG);	/* set read cycle timings */
-	write_reg(cycle2, WRITE_REG);	/* set write cycle timings */
-
-	write_reg(0x85, CNTRL_REG);	/* use Register-A for drive 0 */
-					/* use Register-B for drive 1 */
-
- 	write_reg(misc, MISC_REG);	/* set address setup, DRDY timings,   */
- 					/*  and read prefetch for both drives */
-
-	restore_flags(flags);	/* all CPUs */
-}
-
-/*
- * ide_init_opti621() is called once for each hwif found at boot.
- */
-void __init ide_init_opti621 (ide_hwif_t *hwif)
-{
-	hwif->drives[0].drive_data = PIO_DONT_KNOW;
-	hwif->drives[1].drive_data = PIO_DONT_KNOW;
-	hwif->tuneproc = &opti621_tune_drive;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/Makefile linux-2.4.21-pre6/drivers/ide/pci/Makefile
--- linux-2.4.20/drivers/ide/pci/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/Makefile	2003-03-26 23:49:00.000000000 +0000
@@ -0,0 +1,42 @@
+
+O_TARGET := idedriver-pci.o
+
+obj-y		:=
+obj-m		:=
+
+obj-$(CONFIG_BLK_DEV_ADMA100)		+= adma100.o
+obj-$(CONFIG_BLK_DEV_AEC62XX)		+= aec62xx.o
+obj-$(CONFIG_BLK_DEV_ALI15X3)		+= alim15x3.o
+obj-$(CONFIG_BLK_DEV_AMD74XX)		+= amd74xx.o
+obj-$(CONFIG_BLK_DEV_CMD640)		+= cmd640.o
+obj-$(CONFIG_BLK_DEV_CMD64X)		+= cmd64x.o
+obj-$(CONFIG_BLK_DEV_CS5530)		+= cs5530.o
+obj-$(CONFIG_BLK_DEV_CY82C693)		+= cy82c693.o
+obj-$(CONFIG_BLK_DEV_HPT34X)		+= hpt34x.o
+obj-$(CONFIG_BLK_DEV_HPT366)		+= hpt366.o
+#obj-$(CONFIG_BLK_DEV_HPT37X)		+= hpt37x.o
+obj-$(CONFIG_BLK_DEV_IDE_ICSIDE)	+= icside.o
+obj-$(CONFIG_BLK_DEV_IT8172)		+= it8172.o
+obj-$(CONFIG_BLK_DEV_NS87415)		+= ns87415.o
+obj-$(CONFIG_BLK_DEV_OPTI621)		+= opti621.o
+obj-$(CONFIG_BLK_DEV_PDC202XX_OLD)	+= pdc202xx_old.o
+obj-$(CONFIG_BLK_DEV_PDC202XX_NEW)	+= pdc202xx_new.o
+obj-$(CONFIG_BLK_DEV_PDC_ADMA)		+= pdcadma.o ide-adma.o
+obj-$(CONFIG_BLK_DEV_PIIX)		+= piix.o
+obj-$(CONFIG_BLK_DEV_RZ1000)		+= rz1000.o
+obj-$(CONFIG_BLK_DEV_SVWKS)		+= serverworks.o
+obj-$(CONFIG_BLK_DEV_SC1200)		+= sc1200.o
+obj-$(CONFIG_BLK_DEV_SIIMAGE)		+= siimage.o
+obj-$(CONFIG_BLK_DEV_SIS5513)		+= sis5513.o
+obj-$(CONFIG_BLK_DEV_SL82C105)		+= sl82c105.o
+obj-$(CONFIG_BLK_DEV_SLC90E66)		+= slc90e66.o
+obj-$(CONFIG_BLK_DEV_TRM290)		+= trm290.o
+obj-$(CONFIG_BLK_DEV_VIA82CXXX)		+= via82cxxx.o
+obj-$(CONFIG_BLK_DEV_TRIFLEX)		+= triflex.o
+
+# Must appear at the end of the block
+obj-$(CONFIG_BLK_DEV_GENERIC)		+= generic.o
+
+EXTRA_CFLAGS	:= -I../
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/adma100.c linux-2.4.21-pre6/drivers/ide/pci/adma100.c
--- linux-2.4.20/drivers/ide/pci/adma100.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/adma100.c	2003-03-26 23:49:09.000000000 +0000
@@ -0,0 +1,30 @@
+/*
+ *  linux/drivers/ide/pci/adma100.c -- basic support for Pacific Digital ADMA-100 boards
+ *
+ *     Created 09 Apr 2002 by Mark Lord
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+
+#include <linux/mm.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+void __init ide_init_adma100 (ide_hwif_t *hwif)
+{
+	unsigned long  phy_admctl = pci_resource_start(hwif->pci_dev, 4) + 0x80 + (hwif->channel * 0x20);
+	void *v_admctl;
+
+	hwif->autodma = 0;		// not compatible with normal IDE DMA transfers
+	hwif->dma_base = 0;		// disable DMA completely
+	hwif->io_ports[IDE_CONTROL_OFFSET] += 4;	// chip needs offset of 6 instead of 2
+	v_admctl = ioremap_nocache(phy_admctl, 1024);	// map config regs, so we can turn on drive IRQs
+	*((unsigned short *)v_admctl) &= 3;		// enable aIEN; preserve PIO mode
+	iounmap(v_admctl);				// all done; unmap config regs
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/adma100.h linux-2.4.21-pre6/drivers/ide/pci/adma100.h
--- linux-2.4.20/drivers/ide/pci/adma100.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/adma100.h	2003-03-26 23:48:59.000000000 +0000
@@ -0,0 +1,36 @@
+#ifndef ADMA_100_H
+#define ADMA_100_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+extern void init_setup_pdcadma(struct pci_dev *, ide_pci_device_t *);
+extern unsigned int init_chipset_pdcadma(struct pci_dev *, const char *);
+extern void init_hwif_pdcadma(ide_hwif_t *);
+extern void init_dma_pdcadma(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t pdcadma_chipsets[] __devinitdata = {
+	{
+		.vendor		= PCI_VENDOR_ID_PDC,
+		.device		= PCI_DEVICE_ID_PDC_1841,
+		.name		= "ADMA100",
+		.init_setup	= init_setup_pdcadma,
+		.init_chipset	= init_chipset_pdcadma,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdcadma,
+		.init_dma	= init_dma_pdcadma,
+		.channels	= 2,
+		.autodma	= NODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+}
+
+#endif /* ADMA_100_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/aec62xx.c linux-2.4.21-pre6/drivers/ide/pci/aec62xx.c
--- linux-2.4.20/drivers/ide/pci/aec62xx.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/aec62xx.c	2003-03-26 23:49:27.000000000 +0000
@@ -0,0 +1,563 @@
+/*
+ * linux/drivers/ide/pci/aec62xx.c		Version 0.11	March 27, 2002
+ *
+ * Copyright (C) 1999-2002	Andre Hedrick <andre@linux-ide.org>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "ide_modes.h"
+#include "aec62xx.h"
+
+#if defined(DISPLAY_AEC62XX_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 aec62xx_proc = 0;
+
+#define AEC_MAX_DEVS		5
+
+static struct pci_dev *aec_devs[AEC_MAX_DEVS];
+static int n_aec_devs;
+
+#undef DEBUG_AEC_REGS
+
+static int aec62xx_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	char *chipset_nums[] = {"error", "error", "error", "error",
+				"error", "error", "850UF",   "860",
+				 "860R",   "865",  "865R", "error"  };
+	int i;
+
+	for (i = 0; i < n_aec_devs; i++) {
+		struct pci_dev *dev	= aec_devs[i];
+		unsigned long iobase = pci_resource_start(dev, 4);
+		u8 c0 = 0, c1 = 0, art	= 0;
+#ifdef DEBUG_AEC_REGS
+		u8 uart			= 0;
+#endif /* DEBUG_AEC_REGS */
+
+		c0 = inb(iobase + 0x02);
+		c1 = inb(iobase + 0x0a);
+
+		p += sprintf(p, "\nController: %d\n", i);
+		p += sprintf(p, "Chipset: AEC%s\n", chipset_nums[dev->device]);
+
+		p += sprintf(p, "--------------- Primary Channel "
+				"---------------- Secondary Channel "
+				"-------------\n");
+		(void) pci_read_config_byte(dev, 0x4a, &art);
+		p += sprintf(p, "                %sabled ",
+			(art&0x02)?" en":"dis");
+		p += sprintf(p, "                        %sabled\n",
+			(art&0x04)?" en":"dis");
+		p += sprintf(p, "--------------- drive0 --------- drive1 "
+				"-------- drive0 ---------- drive1 ------\n");
+		p += sprintf(p, "DMA enabled:    %s              %s ",
+			(c0&0x20)?"yes":"no ",(c0&0x40)?"yes":"no ");
+		p += sprintf(p, "            %s               %s\n",
+			(c1&0x20)?"yes":"no ",(c1&0x40)?"yes":"no ");
+
+		if (dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) {
+			(void) pci_read_config_byte(dev, 0x54, &art);
+			p += sprintf(p, "DMA Mode:       %s(%s)",
+				(c0&0x20)?((art&0x03)?"UDMA":" DMA"):" PIO",
+				(art&0x02)?"2":(art&0x01)?"1":"0");
+			p += sprintf(p, "          %s(%s)",
+				(c0&0x40)?((art&0x0c)?"UDMA":" DMA"):" PIO",
+				(art&0x08)?"2":(art&0x04)?"1":"0");
+			p += sprintf(p, "         %s(%s)",
+				(c1&0x20)?((art&0x30)?"UDMA":" DMA"):" PIO",
+				(art&0x20)?"2":(art&0x10)?"1":"0");
+			p += sprintf(p, "           %s(%s)\n",
+				(c1&0x40)?((art&0xc0)?"UDMA":" DMA"):" PIO",
+				(art&0x80)?"2":(art&0x40)?"1":"0");
+#ifdef DEBUG_AEC_REGS
+			(void) pci_read_config_byte(dev, 0x40, &art);
+			p += sprintf(p, "Active:         0x%02x", art);
+			(void) pci_read_config_byte(dev, 0x42, &art);
+			p += sprintf(p, "             0x%02x", art);
+			(void) pci_read_config_byte(dev, 0x44, &art);
+			p += sprintf(p, "            0x%02x", art);
+			(void) pci_read_config_byte(dev, 0x46, &art);
+			p += sprintf(p, "              0x%02x\n", art);
+			(void) pci_read_config_byte(dev, 0x41, &art);
+			p += sprintf(p, "Recovery:       0x%02x", art);
+			(void) pci_read_config_byte(dev, 0x43, &art);
+			p += sprintf(p, "             0x%02x", art);
+			(void) pci_read_config_byte(dev, 0x45, &art);
+			p += sprintf(p, "            0x%02x", art);
+			(void) pci_read_config_byte(dev, 0x47, &art);
+			p += sprintf(p, "              0x%02x\n", art);
+#endif /* DEBUG_AEC_REGS */
+		} else {
+			/*
+			 * case PCI_DEVICE_ID_ARTOP_ATP860:
+			 * case PCI_DEVICE_ID_ARTOP_ATP860R:
+			 * case PCI_DEVICE_ID_ARTOP_ATP865:
+			 * case PCI_DEVICE_ID_ARTOP_ATP865R:
+			 */
+			(void) pci_read_config_byte(dev, 0x44, &art);
+			p += sprintf(p, "DMA Mode:       %s(%s)",
+				(c0&0x20)?((art&0x07)?"UDMA":" DMA"):" PIO",
+				((art&0x07)==0x07)?"6":
+				((art&0x06)==0x06)?"5":
+				((art&0x05)==0x05)?"4":
+				((art&0x04)==0x04)?"3":
+				((art&0x03)==0x03)?"2":
+				((art&0x02)==0x02)?"1":
+				((art&0x01)==0x01)?"0":"?");
+			p += sprintf(p, "          %s(%s)",
+				(c0&0x40)?((art&0x70)?"UDMA":" DMA"):" PIO",
+				((art&0x70)==0x70)?"6":
+				((art&0x60)==0x60)?"5":
+				((art&0x50)==0x50)?"4":
+				((art&0x40)==0x40)?"3":
+				((art&0x30)==0x30)?"2":
+				((art&0x20)==0x20)?"1":
+				((art&0x10)==0x10)?"0":"?");
+			(void) pci_read_config_byte(dev, 0x45, &art);
+			p += sprintf(p, "         %s(%s)",
+				(c1&0x20)?((art&0x07)?"UDMA":" DMA"):" PIO",
+				((art&0x07)==0x07)?"6":
+				((art&0x06)==0x06)?"5":
+				((art&0x05)==0x05)?"4":
+				((art&0x04)==0x04)?"3":
+				((art&0x03)==0x03)?"2":
+				((art&0x02)==0x02)?"1":
+				((art&0x01)==0x01)?"0":"?");
+			p += sprintf(p, "           %s(%s)\n",
+				(c1&0x40)?((art&0x70)?"UDMA":" DMA"):" PIO",
+				((art&0x70)==0x70)?"6":
+				((art&0x60)==0x60)?"5":
+				((art&0x50)==0x50)?"4":
+				((art&0x40)==0x40)?"3":
+				((art&0x30)==0x30)?"2":
+				((art&0x20)==0x20)?"1":
+				((art&0x10)==0x10)?"0":"?");
+#ifdef DEBUG_AEC_REGS
+			(void) pci_read_config_byte(dev, 0x40, &art);
+			p += sprintf(p, "Active:         0x%02x", HIGH_4(art));
+			(void) pci_read_config_byte(dev, 0x41, &art);
+			p += sprintf(p, "             0x%02x", HIGH_4(art));
+			(void) pci_read_config_byte(dev, 0x42, &art);
+			p += sprintf(p, "            0x%02x", HIGH_4(art));
+			(void) pci_read_config_byte(dev, 0x43, &art);
+			p += sprintf(p, "              0x%02x\n", HIGH_4(art));
+			(void) pci_read_config_byte(dev, 0x40, &art);
+			p += sprintf(p, "Recovery:       0x%02x", LOW_4(art));
+			(void) pci_read_config_byte(dev, 0x41, &art);
+			p += sprintf(p, "             0x%02x", LOW_4(art));
+			(void) pci_read_config_byte(dev, 0x42, &art);
+			p += sprintf(p, "            0x%02x", LOW_4(art));
+			(void) pci_read_config_byte(dev, 0x43, &art);
+			p += sprintf(p, "              0x%02x\n", LOW_4(art));
+			(void) pci_read_config_byte(dev, 0x49, &uart);
+			p += sprintf(p, "reg49h = 0x%02x ", uart);
+			(void) pci_read_config_byte(dev, 0x4a, &uart);
+			p += sprintf(p, "reg4ah = 0x%02x\n", uart);
+#endif /* DEBUG_AEC_REGS */
+		}
+	}
+	return p-buffer;/* => must be less than 4k! */
+}
+#endif	/* defined(DISPLAY_AEC62xx_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+/*
+ * TO DO: active tuning and correction of cards without a bios.
+ */
+static u8 pci_bus_clock_list (u8 speed, struct chipset_bus_clock_list_entry * chipset_table)
+{
+	for ( ; chipset_table->xfer_speed ; chipset_table++)
+		if (chipset_table->xfer_speed == speed) {
+			return chipset_table->chipset_settings;
+		}
+	return chipset_table->chipset_settings;
+}
+
+static u8 pci_bus_clock_list_ultra (u8 speed, struct chipset_bus_clock_list_entry * chipset_table)
+{
+	for ( ; chipset_table->xfer_speed ; chipset_table++)
+		if (chipset_table->xfer_speed == speed) {
+			return chipset_table->ultra_settings;
+		}
+	return chipset_table->ultra_settings;
+}
+
+static u8 aec62xx_ratemask (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 mode;
+
+	switch(hwif->pci_dev->device) {
+		case PCI_DEVICE_ID_ARTOP_ATP865:
+		case PCI_DEVICE_ID_ARTOP_ATP865R:
+#if 0
+			mode = (hwif->INB(hwif->dma_master) & 0x10) ? 4 : 3;
+#else
+			mode = (hwif->INB(((hwif->channel) ?
+					hwif->mate->dma_status :
+					hwif->dma_status)) & 0x10) ? 4 : 3;
+#endif
+			break;
+		case PCI_DEVICE_ID_ARTOP_ATP860:
+		case PCI_DEVICE_ID_ARTOP_ATP860R:
+			mode = 2;
+			break;
+		case PCI_DEVICE_ID_ARTOP_ATP850UF:
+		default:
+			return 1;
+	}
+
+	if (!eighty_ninty_three(drive))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+static int aec6210_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u16 d_conf		= 0;
+	u8 speed	= ide_rate_filter(aec62xx_ratemask(drive), xferspeed);
+	u8 ultra = 0, ultra_conf = 0;
+	u8 tmp0 = 0, tmp1 = 0, tmp2 = 0;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	pci_read_config_word(dev, 0x40|(2*drive->dn), &d_conf);
+	tmp0 = pci_bus_clock_list(speed, BUSCLOCK(dev));
+	SPLIT_BYTE(tmp0,tmp1,tmp2);
+	MAKE_WORD(d_conf,tmp1,tmp2);
+	pci_write_config_word(dev, 0x40|(2*drive->dn), d_conf);
+
+	tmp1 = 0x00;
+	tmp2 = 0x00;
+	pci_read_config_byte(dev, 0x54, &ultra);
+	tmp1 = ((0x00 << (2*drive->dn)) | (ultra & ~(3 << (2*drive->dn))));
+	ultra_conf = pci_bus_clock_list_ultra(speed, BUSCLOCK(dev));
+	tmp2 = ((ultra_conf << (2*drive->dn)) | (tmp1 & ~(3 << (2*drive->dn))));
+	pci_write_config_byte(dev, 0x54, tmp2);
+	local_irq_restore(flags);
+	return(ide_config_drive_speed(drive, speed));
+}
+
+static int aec6260_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 speed	= ide_rate_filter(aec62xx_ratemask(drive), xferspeed);
+	u8 unit		= (drive->select.b.unit & 0x01);
+	u8 tmp1 = 0, tmp2 = 0;
+	u8 ultra = 0, drive_conf = 0, ultra_conf = 0;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	pci_read_config_byte(dev, 0x40|drive->dn, &drive_conf);
+	drive_conf = pci_bus_clock_list(speed, BUSCLOCK(dev));
+	pci_write_config_byte(dev, 0x40|drive->dn, drive_conf);
+
+	pci_read_config_byte(dev, (0x44|hwif->channel), &ultra);
+	tmp1 = ((0x00 << (4*unit)) | (ultra & ~(7 << (4*unit))));
+	ultra_conf = pci_bus_clock_list_ultra(speed, BUSCLOCK(dev));
+	tmp2 = ((ultra_conf << (4*unit)) | (tmp1 & ~(7 << (4*unit))));
+	pci_write_config_byte(dev, (0x44|hwif->channel), tmp2);
+	local_irq_restore(flags);
+	return(ide_config_drive_speed(drive, speed));
+}
+
+static int aec62xx_tune_chipset (ide_drive_t *drive, u8 speed)
+{
+	switch (HWIF(drive)->pci_dev->device) {
+		case PCI_DEVICE_ID_ARTOP_ATP865:
+		case PCI_DEVICE_ID_ARTOP_ATP865R:
+		case PCI_DEVICE_ID_ARTOP_ATP860:
+		case PCI_DEVICE_ID_ARTOP_ATP860R:
+			return ((int) aec6260_tune_chipset(drive, speed));
+		case PCI_DEVICE_ID_ARTOP_ATP850UF:
+			return ((int) aec6210_tune_chipset(drive, speed));
+		default:
+			return -1;
+	}
+}
+
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	u8 speed = ide_dma_speed(drive, aec62xx_ratemask(drive));	
+
+	if (!(speed))
+		return 0;
+
+	(void) aec62xx_tune_chipset(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static void aec62xx_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	u8 speed = 0;
+	u8 new_pio = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
+
+	switch(pio) {
+		case 5:		speed = new_pio; break;
+		case 4:		speed = XFER_PIO_4; break;
+		case 3:		speed = XFER_PIO_3; break;
+		case 2:		speed = XFER_PIO_2; break;
+		case 1:		speed = XFER_PIO_1; break;
+		default:	speed = XFER_PIO_0; break;
+	}
+	(void) aec62xx_tune_chipset(drive, speed);
+}
+
+static int aec62xx_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	if (id && (id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		aec62xx_tune_drive(drive, 5);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+static int aec62xx_irq_timeout (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+
+	switch(dev->device) {
+		case PCI_DEVICE_ID_ARTOP_ATP860:
+		case PCI_DEVICE_ID_ARTOP_ATP860R:
+		case PCI_DEVICE_ID_ARTOP_ATP865:
+		case PCI_DEVICE_ID_ARTOP_ATP865R:
+			printk(" AEC62XX time out ");
+#if 0
+			{
+				int i = 0;
+				u8 reg49h = 0;
+				pci_read_config_byte(HWIF(drive)->pci_dev, 0x49, &reg49h);
+				for (i=0;i<256;i++)
+					pci_write_config_byte(HWIF(drive)->pci_dev, 0x49, reg49h|0x10);
+				pci_write_config_byte(HWIF(drive)->pci_dev, 0x49, reg49h & ~0x10);
+			}
+			return 0;
+#endif
+		default:
+			break;
+	}
+#if 0
+	{
+		ide_hwif_t *hwif	= HWIF(drive);
+		struct pci_dev *dev	= hwif->pci_dev;
+		u8 tmp1 = 0, tmp2 = 0, mode6 = 0;
+
+		pci_read_config_byte(dev, 0x44, &tmp1);
+		pci_read_config_byte(dev, 0x45, &tmp2);
+		printk(" AEC6280 r44=%x r45=%x ",tmp1,tmp2);
+		mode6 = HWIF(drive)->INB(((hwif->channel) ?
+					   hwif->mate->dma_status :
+					   hwif->dma_status));
+		printk(" AEC6280 133=%x ", (mode6 & 0x10));
+	}
+#endif
+	return 0;
+}
+
+static unsigned int __init init_chipset_aec62xx (struct pci_dev *dev, const char *name)
+{
+	int bus_speed = system_bus_clock();
+
+	if (dev->resource[PCI_ROM_RESOURCE].start) {
+		pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+		printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
+	}
+
+#if defined(DISPLAY_AEC62XX_TIMINGS) && defined(CONFIG_PROC_FS)
+	aec_devs[n_aec_devs++] = dev;
+
+	if (!aec62xx_proc) {
+		aec62xx_proc = 1;
+		ide_pci_register_host_proc(&aec62xx_procs[0]);
+	}
+#endif /* DISPLAY_AEC62XX_TIMINGS && CONFIG_PROC_FS */
+
+	if (bus_speed <= 33)
+		pci_set_drvdata(dev, (void *) aec6xxx_33_base);
+	else
+		pci_set_drvdata(dev, (void *) aec6xxx_34_base);
+
+	return dev->irq;
+}
+
+static void __init init_hwif_aec62xx (ide_hwif_t *hwif)
+{
+	hwif->autodma = 0;
+	hwif->tuneproc = &aec62xx_tune_drive;
+	hwif->speedproc = &aec62xx_tune_chipset;
+
+	if (hwif->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) {
+		hwif->serialized = hwif->channel;
+		hwif->no_dsc = 1;
+	}
+
+	if (hwif->mate)
+		hwif->mate->serialized = hwif->serialized;
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->ultra_mask = 0x7f;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+	hwif->ide_dma_check	= &aec62xx_config_drive_xfer_rate;
+	hwif->ide_dma_lostirq	= &aec62xx_irq_timeout;
+	hwif->ide_dma_timeout	= &aec62xx_irq_timeout;
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+static void __init init_dma_aec62xx (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	struct pci_dev *dev	= hwif->pci_dev;
+
+	if (dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) {
+		u8 reg54h = 0;
+		unsigned long flags;
+
+		spin_lock_irqsave(&ide_lock, flags);
+		pci_read_config_byte(dev, 0x54, &reg54h);
+		pci_write_config_byte(dev, 0x54, reg54h & ~(hwif->channel ? 0xF0 : 0x0F));
+		spin_unlock_irqrestore(&ide_lock, flags);
+	} else {
+		u8 ata66	= 0;
+		pci_read_config_byte(hwif->pci_dev, 0x49, &ata66);
+	        if (!(hwif->udma_four))
+			hwif->udma_four = (ata66&(hwif->channel?0x02:0x01))?0:1;
+	}
+
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static void __init init_setup_aec62xx (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+static void __init init_setup_aec6x80 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	unsigned long bar4reg = pci_resource_start(dev, 4);
+
+	if (inb(bar4reg+2) & 0x10) {
+		strcpy(d->name, "AEC6880");
+		if (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R)
+			strcpy(d->name, "AEC6880R");
+	} else {
+		strcpy(d->name, "AEC6280");
+		if (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R)
+			strcpy(d->name, "AEC6280R");
+	}
+
+	ide_setup_pci_device(dev, d);
+}
+
+/**
+ *	aec62xx_init_one	-	called when a AEC is found
+ *	@dev: the aec62xx device
+ *	@id: the matching pci id
+ *
+ *	Called when the PCI registration layer (or the IDE initialization)
+ *	finds a device matching our IDE device tables.
+ */
+ 
+static int __devinit aec62xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &aec62xx_chipsets[id->driver_data];
+
+	if (dev->device != d->device)
+		BUG();
+	d->init_setup(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id aec62xx_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP850UF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP860,   PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
+	{ PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP860R,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 },
+	{ PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP865,   PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 },
+	{ PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP865R,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "AEC62xx IDE",
+	.id_table	= aec62xx_pci_tbl,
+	.probe		= aec62xx_init_one,
+};
+
+static int aec62xx_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void aec62xx_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(aec62xx_ide_init);
+module_exit(aec62xx_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for ARTOP AEC62xx IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/aec62xx.h linux-2.4.21-pre6/drivers/ide/pci/aec62xx.h
--- linux-2.4.20/drivers/ide/pci/aec62xx.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/aec62xx.h	2003-03-26 23:49:09.000000000 +0000
@@ -0,0 +1,171 @@
+#ifndef AEC62XX_H
+#define AEC62XX_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_AEC62XX_TIMINGS
+
+struct chipset_bus_clock_list_entry {
+	byte		xfer_speed;
+	byte		chipset_settings;
+	byte		ultra_settings;
+};
+
+struct chipset_bus_clock_list_entry aec6xxx_33_base [] = {
+	{	XFER_UDMA_6,	0x31,	0x07	},
+	{	XFER_UDMA_5,	0x31,	0x06	},
+	{	XFER_UDMA_4,	0x31,	0x05	},
+	{	XFER_UDMA_3,	0x31,	0x04	},
+	{	XFER_UDMA_2,	0x31,	0x03	},
+	{	XFER_UDMA_1,	0x31,	0x02	},
+	{	XFER_UDMA_0,	0x31,	0x01	},
+
+	{	XFER_MW_DMA_2,	0x31,	0x00	},
+	{	XFER_MW_DMA_1,	0x31,	0x00	},
+	{	XFER_MW_DMA_0,	0x0a,	0x00	},
+	{	XFER_PIO_4,	0x31,	0x00	},
+	{	XFER_PIO_3,	0x33,	0x00	},
+	{	XFER_PIO_2,	0x08,	0x00	},
+	{	XFER_PIO_1,	0x0a,	0x00	},
+	{	XFER_PIO_0,	0x00,	0x00	},
+	{	0,		0x00,	0x00	}
+};
+
+struct chipset_bus_clock_list_entry aec6xxx_34_base [] = {
+	{	XFER_UDMA_6,	0x41,	0x06	},
+	{	XFER_UDMA_5,	0x41,	0x05	},
+	{	XFER_UDMA_4,	0x41,	0x04	},
+	{	XFER_UDMA_3,	0x41,	0x03	},
+	{	XFER_UDMA_2,	0x41,	0x02	},
+	{	XFER_UDMA_1,	0x41,	0x01	},
+	{	XFER_UDMA_0,	0x41,	0x01	},
+
+	{	XFER_MW_DMA_2,	0x41,	0x00	},
+	{	XFER_MW_DMA_1,	0x42,	0x00	},
+	{	XFER_MW_DMA_0,	0x7a,	0x00	},
+	{	XFER_PIO_4,	0x41,	0x00	},
+	{	XFER_PIO_3,	0x43,	0x00	},
+	{	XFER_PIO_2,	0x78,	0x00	},
+	{	XFER_PIO_1,	0x7a,	0x00	},
+	{	XFER_PIO_0,	0x70,	0x00	},
+	{	0,		0x00,	0x00	}
+};
+
+
+#ifndef HIGH_4
+#define HIGH_4(H)		((H)=(H>>4))
+#endif
+#ifndef LOW_4
+#define LOW_4(L)		((L)=(L-((L>>4)<<4)))
+#endif
+#ifndef SPLIT_BYTE
+#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
+#endif
+#ifndef MAKE_WORD
+#define MAKE_WORD(W,HB,LB)	((W)=((HB<<8)+LB))
+#endif
+
+#define BUSCLOCK(D)	\
+	((struct chipset_bus_clock_list_entry *) pci_get_drvdata((D)))
+
+#if defined(DISPLAY_AEC62XX_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 aec62xx_proc;
+
+static int aec62xx_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t aec62xx_procs[] __initdata = {
+	{
+		.name		= "aec62xx",
+		.set		= 1,
+		.get_info	= aec62xx_get_info,
+		.parent		= NULL,
+	},
+};
+#endif /* DISPLAY_AEC62XX_TIMINGS && CONFIG_PROC_FS */
+
+static void init_setup_aec6x80(struct pci_dev *, ide_pci_device_t *);
+static void init_setup_aec62xx(struct pci_dev *, ide_pci_device_t *);
+static unsigned int init_chipset_aec62xx(struct pci_dev *, const char *);
+static void init_hwif_aec62xx(ide_hwif_t *);
+static void init_dma_aec62xx(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t aec62xx_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_ARTOP,
+		.device		= PCI_DEVICE_ID_ARTOP_ATP850UF,
+		.name		= "AEC6210",
+		.init_setup	= init_setup_aec62xx,
+		.init_chipset	= init_chipset_aec62xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_aec62xx,
+		.init_dma	= init_dma_aec62xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
+	},{	/* 1 */
+		.vendor		= PCI_VENDOR_ID_ARTOP,
+		.device		= PCI_DEVICE_ID_ARTOP_ATP860,
+		.name		= "AEC6260",
+		.init_setup	= init_setup_aec62xx,
+		.init_chipset	= init_chipset_aec62xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_aec62xx,
+		.init_dma	= init_dma_aec62xx,
+		.channels	= 2,
+		.autodma	= NOAUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
+	},{	/* 2 */
+		.vendor		= PCI_VENDOR_ID_ARTOP,
+		.device		= PCI_DEVICE_ID_ARTOP_ATP860R,
+		.name		= "AEC6260R",
+		.init_setup	= init_setup_aec62xx,
+		.init_chipset	= init_chipset_aec62xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_aec62xx,
+		.init_dma	= init_dma_aec62xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
+		.bootable	= NEVER_BOARD,
+		.extra		= 0,
+	},{	/* 3 */
+		.vendor		= PCI_VENDOR_ID_ARTOP,
+		.device		= PCI_DEVICE_ID_ARTOP_ATP865,
+		.name		= "AEC6X80",
+		.init_setup	= init_setup_aec6x80,
+		.init_chipset	= init_chipset_aec62xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_aec62xx,
+		.init_dma	= init_dma_aec62xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
+	},{	/* 4 */
+		.vendor		= PCI_VENDOR_ID_ARTOP,
+		.device		= PCI_DEVICE_ID_ARTOP_ATP865R,
+		.name		= "AEC6X80R",
+		.init_setup	= init_setup_aec6x80,
+		.init_chipset	= init_chipset_aec62xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_aec62xx,
+		.init_dma	= init_dma_aec62xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
+	}
+};
+
+#endif /* AEC62XX_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/alim15x3.c linux-2.4.21-pre6/drivers/ide/pci/alim15x3.c
--- linux-2.4.20/drivers/ide/pci/alim15x3.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/alim15x3.c	2003-03-26 23:49:49.000000000 +0000
@@ -0,0 +1,900 @@
+/*
+ * linux/drivers/ide/pci/alim15x3.c		Version 0.16	2003/01/02
+ *
+ *  Copyright (C) 1998-2000 Michel Aubry, Maintainer
+ *  Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer
+ *  Copyright (C) 1999-2000 CJ, cjtsai@ali.com.tw, Maintainer
+ *
+ *  Copyright (C) 1998-2000 Andre Hedrick (andre@linux-ide.org)
+ *  May be copied or modified under the terms of the GNU General Public License
+ *  Copyright (C) 2002 Alan Cox <alan@redhat.com>
+ *
+ *  (U)DMA capable version of ali 1533/1543(C), 1535(D)
+ *
+ **********************************************************************
+ *  9/7/99 --Parts from the above author are included and need to be
+ *  converted into standard interface, once I finish the thought.
+ *
+ *  Recent changes
+ *	Don't use LBA48 mode on ALi <= 0xC4
+ *	Don't poke 0x79 with a non ALi northbridge
+ *	Don't flip undefined bits on newer chipsets (fix Fujitsu laptop hang)
+ *
+ *  Documentation
+ *	Chipset documentation available under NDA only
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "ide_modes.h"
+#include "alim15x3.h"
+
+/*
+ *	ALi devices are not plug in. Otherwise these static values would
+ *	need to go. They ought to go away anyway
+ */
+ 
+static u8 m5229_revision;
+static u8 chip_is_1543c_e;
+static struct pci_dev *isa_dev;
+
+#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 ali_proc = 0;
+
+static struct pci_dev *bmide_dev;
+
+static char *fifo[4] = {
+	"FIFO Off",
+	"FIFO On ",
+	"DMA mode",
+	"PIO mode" };
+
+static char *udmaT[8] = {
+	"1.5T",
+	"  2T",
+	"2.5T",
+	"  3T",
+	"3.5T",
+	"  4T",
+	"  6T",
+	"  8T"
+};
+
+static char *channel_status[8] = {
+	"OK            ",
+	"busy          ",
+	"DRQ           ",
+	"DRQ busy      ",
+	"error         ",
+	"error busy    ",
+	"error DRQ     ",
+	"error DRQ busy"
+};
+
+/**
+ *	ali_get_info		-	generate proc file for ALi IDE
+ *	@buffer: buffer to fill
+ *	@addr: address of user start in buffer
+ *	@offset: offset into 'file'
+ *	@count: buffer count
+ *
+ *	Walks the Ali devices and outputs summary data on the tuning and
+ *	anything else that will help with debugging
+ */
+ 
+static int ali_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	unsigned long bibma;
+	u8 reg53h, reg5xh, reg5yh, reg5xh1, reg5yh1, c0, c1, rev, tmp;
+	char *q, *p = buffer;
+
+	/* fetch rev. */
+	pci_read_config_byte(bmide_dev, 0x08, &rev);
+	if (rev >= 0xc1)	/* M1543C or newer */
+		udmaT[7] = " ???";
+	else
+		fifo[3]  = "   ???  ";
+
+	/* first fetch bibma: */
+	
+	bibma = pci_resource_start(bmide_dev, 4);
+
+	/*
+	 * at that point bibma+0x2 et bibma+0xa are byte
+	 * registers to investigate:
+	 */
+	c0 = inb(bibma + 0x02);
+	c1 = inb(bibma + 0x0a);
+
+	p += sprintf(p,
+		"\n                                Ali M15x3 Chipset.\n");
+	p += sprintf(p,
+		"                                ------------------\n");
+	pci_read_config_byte(bmide_dev, 0x78, &reg53h);
+	p += sprintf(p, "PCI Clock: %d.\n", reg53h);
+
+	pci_read_config_byte(bmide_dev, 0x53, &reg53h);
+	p += sprintf(p,
+		"CD_ROM FIFO:%s, CD_ROM DMA:%s\n",
+		(reg53h & 0x02) ? "Yes" : "No ",
+		(reg53h & 0x01) ? "Yes" : "No " );
+	pci_read_config_byte(bmide_dev, 0x74, &reg53h);
+	p += sprintf(p,
+		"FIFO Status: contains %d Words, runs%s%s\n\n",
+		(reg53h & 0x3f),
+		(reg53h & 0x40) ? " OVERWR" : "",
+		(reg53h & 0x80) ? " OVERRD." : "." );
+
+	p += sprintf(p,
+		"-------------------primary channel"
+		"-------------------secondary channel"
+		"---------\n\n");
+
+	pci_read_config_byte(bmide_dev, 0x09, &reg53h);
+	p += sprintf(p,
+		"channel status:       %s"
+		"                               %s\n",
+		(reg53h & 0x20) ? "On " : "Off",
+		(reg53h & 0x10) ? "On " : "Off" );
+
+	p += sprintf(p,
+		"both channels togth:  %s"
+		"                               %s\n",
+		(c0&0x80) ? "No " : "Yes",
+		(c1&0x80) ? "No " : "Yes" );
+
+	pci_read_config_byte(bmide_dev, 0x76, &reg53h);
+	p += sprintf(p,
+		"Channel state:        %s                    %s\n",
+		channel_status[reg53h & 0x07],
+		channel_status[(reg53h & 0x70) >> 4] );
+
+	pci_read_config_byte(bmide_dev, 0x58, &reg5xh);
+	pci_read_config_byte(bmide_dev, 0x5c, &reg5yh);
+	p += sprintf(p,
+		"Add. Setup Timing:    %dT"
+		"                                %dT\n",
+		(reg5xh & 0x07) ? (reg5xh & 0x07) : 8,
+		(reg5yh & 0x07) ? (reg5yh & 0x07) : 8 );
+
+	pci_read_config_byte(bmide_dev, 0x59, &reg5xh);
+	pci_read_config_byte(bmide_dev, 0x5d, &reg5yh);
+	p += sprintf(p,
+		"Command Act. Count:   %dT"
+		"                                %dT\n"
+		"Command Rec. Count:   %dT"
+		"                               %dT\n\n",
+		(reg5xh & 0x70) ? ((reg5xh & 0x70) >> 4) : 8,
+		(reg5yh & 0x70) ? ((reg5yh & 0x70) >> 4) : 8, 
+		(reg5xh & 0x0f) ? (reg5xh & 0x0f) : 16,
+		(reg5yh & 0x0f) ? (reg5yh & 0x0f) : 16 );
+
+	p += sprintf(p,
+		"----------------drive0-----------drive1"
+		"------------drive0-----------drive1------\n\n");
+	p += sprintf(p,
+		"DMA enabled:      %s              %s"
+		"               %s              %s\n",
+		(c0&0x20) ? "Yes" : "No ",
+		(c0&0x40) ? "Yes" : "No ",
+		(c1&0x20) ? "Yes" : "No ",
+		(c1&0x40) ? "Yes" : "No " );
+
+	pci_read_config_byte(bmide_dev, 0x54, &reg5xh);
+	pci_read_config_byte(bmide_dev, 0x55, &reg5yh);
+	q = "FIFO threshold:   %2d Words         %2d Words"
+		"          %2d Words         %2d Words\n";
+	if (rev < 0xc1) {
+		if ((rev == 0x20) &&
+		    (pci_read_config_byte(bmide_dev, 0x4f, &tmp), (tmp &= 0x20))) {
+			p += sprintf(p, q, 8, 8, 8, 8);
+		} else {
+			p += sprintf(p, q,
+				(reg5xh & 0x03) + 12,
+				((reg5xh & 0x30)>>4) + 12,
+				(reg5yh & 0x03) + 12,
+				((reg5yh & 0x30)>>4) + 12 );
+		}
+	} else {
+		int t1 = (tmp = (reg5xh & 0x03)) ? (tmp << 3) : 4;
+		int t2 = (tmp = ((reg5xh & 0x30)>>4)) ? (tmp << 3) : 4;
+		int t3 = (tmp = (reg5yh & 0x03)) ? (tmp << 3) : 4;
+		int t4 = (tmp = ((reg5yh & 0x30)>>4)) ? (tmp << 3) : 4;
+		p += sprintf(p, q, t1, t2, t3, t4);
+	}
+
+#if 0
+	p += sprintf(p, 
+		"FIFO threshold:   %2d Words         %2d Words"
+		"          %2d Words         %2d Words\n",
+		(reg5xh & 0x03) + 12,
+		((reg5xh & 0x30)>>4) + 12,
+		(reg5yh & 0x03) + 12,
+		((reg5yh & 0x30)>>4) + 12 );
+#endif
+
+	p += sprintf(p,
+		"FIFO mode:        %s         %s          %s         %s\n",
+		fifo[((reg5xh & 0x0c) >> 2)],
+		fifo[((reg5xh & 0xc0) >> 6)],
+		fifo[((reg5yh & 0x0c) >> 2)],
+		fifo[((reg5yh & 0xc0) >> 6)] );
+
+	pci_read_config_byte(bmide_dev, 0x5a, &reg5xh);
+	pci_read_config_byte(bmide_dev, 0x5b, &reg5xh1);
+	pci_read_config_byte(bmide_dev, 0x5e, &reg5yh);
+	pci_read_config_byte(bmide_dev, 0x5f, &reg5yh1);
+
+	p += sprintf(p,/*
+		"------------------drive0-----------drive1"
+		"------------drive0-----------drive1------\n")*/
+		"Dt RW act. Cnt    %2dT              %2dT"
+		"               %2dT              %2dT\n"
+		"Dt RW rec. Cnt    %2dT              %2dT"
+		"               %2dT              %2dT\n\n",
+		(reg5xh & 0x70) ? ((reg5xh & 0x70) >> 4) : 8,
+		(reg5xh1 & 0x70) ? ((reg5xh1 & 0x70) >> 4) : 8,
+		(reg5yh & 0x70) ? ((reg5yh & 0x70) >> 4) : 8,
+		(reg5yh1 & 0x70) ? ((reg5yh1 & 0x70) >> 4) : 8,
+		(reg5xh & 0x0f) ? (reg5xh & 0x0f) : 16,
+		(reg5xh1 & 0x0f) ? (reg5xh1 & 0x0f) : 16,
+		(reg5yh & 0x0f) ? (reg5yh & 0x0f) : 16,
+		(reg5yh1 & 0x0f) ? (reg5yh1 & 0x0f) : 16 );
+
+	p += sprintf(p,
+		"-----------------------------------UDMA Timings"
+		"--------------------------------\n\n");
+
+	pci_read_config_byte(bmide_dev, 0x56, &reg5xh);
+	pci_read_config_byte(bmide_dev, 0x57, &reg5yh);
+	p += sprintf(p,
+		"UDMA:             %s               %s"
+		"                %s               %s\n"
+		"UDMA timings:     %s             %s"
+		"              %s             %s\n\n",
+		(reg5xh & 0x08) ? "OK" : "No",
+		(reg5xh & 0x80) ? "OK" : "No",
+		(reg5yh & 0x08) ? "OK" : "No",
+		(reg5yh & 0x80) ? "OK" : "No",
+		udmaT[(reg5xh & 0x07)],
+		udmaT[(reg5xh & 0x70) >> 4],
+		udmaT[reg5yh & 0x07],
+		udmaT[(reg5yh & 0x70) >> 4] );
+
+	return p-buffer; /* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+/**
+ *	ali15x3_tune_drive	-	set up a drive
+ *	@drive: drive to tune
+ *	@pio: unused
+ *
+ *	Select the best PIO timing for the drive in question. Then
+ *	program the controller for this drive set up
+ */
+ 
+static void ali15x3_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	ide_pio_data_t d;
+	ide_hwif_t *hwif = HWIF(drive);
+	struct pci_dev *dev = hwif->pci_dev;
+	int s_time, a_time, c_time;
+	u8 s_clc, a_clc, r_clc;
+	unsigned long flags;
+	int bus_speed = system_bus_clock();
+	int port = hwif->channel ? 0x5c : 0x58;
+	int portFIFO = hwif->channel ? 0x55 : 0x54;
+	u8 cd_dma_fifo = 0;
+
+	pio = ide_get_best_pio_mode(drive, pio, 5, &d);
+	s_time = ide_pio_timings[pio].setup_time;
+	a_time = ide_pio_timings[pio].active_time;
+	if ((s_clc = (s_time * bus_speed + 999) / 1000) >= 8)
+		s_clc = 0;
+	if ((a_clc = (a_time * bus_speed + 999) / 1000) >= 8)
+		a_clc = 0;
+	c_time = ide_pio_timings[pio].cycle_time;
+
+#if 0
+	if ((r_clc = ((c_time - s_time - a_time) * bus_speed + 999) / 1000) >= 16)
+		r_clc = 0;
+#endif
+
+	if (!(r_clc = (c_time * bus_speed + 999) / 1000 - a_clc - s_clc)) {
+		r_clc = 1;
+	} else {
+		if (r_clc >= 16)
+			r_clc = 0;
+	}
+	local_irq_save(flags);
+	
+	/* 
+	 * PIO mode => ATA FIFO on, ATAPI FIFO off
+	 */
+	pci_read_config_byte(dev, portFIFO, &cd_dma_fifo);
+	if (drive->media==ide_disk) {
+		if (hwif->channel) {
+			pci_write_config_byte(dev, portFIFO, (cd_dma_fifo & 0x0F) | 0x50);
+		} else {
+			pci_write_config_byte(dev, portFIFO, (cd_dma_fifo & 0xF0) | 0x05);
+		}
+	} else {
+		if (hwif->channel) {
+			pci_write_config_byte(dev, portFIFO, cd_dma_fifo & 0x0F);
+		} else {
+			pci_write_config_byte(dev, portFIFO, cd_dma_fifo & 0xF0);
+		}
+	}
+	
+	pci_write_config_byte(dev, port, s_clc);
+	pci_write_config_byte(dev, port+drive->select.b.unit+2, (a_clc << 4) | r_clc);
+	local_irq_restore(flags);
+
+	/*
+	 * setup   active  rec
+	 * { 70,   165,    365 },   PIO Mode 0
+	 * { 50,   125,    208 },   PIO Mode 1
+	 * { 30,   100,    110 },   PIO Mode 2
+	 * { 30,   80,     70  },   PIO Mode 3 with IORDY
+	 * { 25,   70,     25  },   PIO Mode 4 with IORDY  ns
+	 * { 20,   50,     30  }    PIO Mode 5 with IORDY (nonstandard)
+	 */
+
+}
+
+/**
+ *	ali15x3_can_ultra	-	check for ultra DMA support
+ *	@drive: drive to do the check
+ *
+ *	Check the drive and controller revisions. Return 0 if UDMA is
+ *	not available, or 1 if UDMA can be used. The actual rules for
+ *	the ALi are
+ *		No UDMA on revisions <= 0x20
+ *		Disk only for revisions < 0xC2
+ *		Not WDC drives for revisions < 0xC2
+ *
+ *	FIXME: WDC ifdef needs to die
+ */
+ 
+static u8 ali15x3_can_ultra (ide_drive_t *drive)
+{
+#ifndef CONFIG_WDC_ALI15X3
+	struct hd_driveid *id	= drive->id;
+#endif /* CONFIG_WDC_ALI15X3 */
+
+	if (m5229_revision <= 0x20) {
+		return 0;
+	} else if ((m5229_revision < 0xC2) &&
+#ifndef CONFIG_WDC_ALI15X3
+		   ((chip_is_1543c_e && strstr(id->model, "WDC ")) ||
+		    (drive->media!=ide_disk))) {
+#else /* CONFIG_WDC_ALI15X3 */
+		   (drive->media!=ide_disk)) {
+#endif /* CONFIG_WDC_ALI15X3 */
+		return 0;
+	} else {
+		return 1;
+	}
+}
+
+/**
+ *	ali15x3_ratemask	-	generate DMA mode list
+ *	@drive: drive to compute against
+ *
+ *	Generate a list of the available DMA modes for the drive. 
+ *	FIXME: this function contains lots of bogus masking we can dump
+ *
+ *	Return the highest available mode (UDMA33, UDMA66, UDMA100,..)
+ */
+ 
+static u8 ali15x3_ratemask (ide_drive_t *drive)
+{
+	u8 mode = 0, can_ultra	= ali15x3_can_ultra(drive);
+
+	if (m5229_revision >= 0xC4 && can_ultra) {
+		mode = 3;
+	} else if (m5229_revision >= 0xC2 && can_ultra) {
+		mode = 2;
+	} else if (can_ultra) {
+		return 1;
+	} else {
+		return 0;
+	}
+
+	/*
+	 *	If the drive sees no suitable cable then UDMA 33
+	 *	is the highest permitted mode
+	 */
+	 
+	if (!eighty_ninty_three(drive))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+/**
+ *	ali15x3_tune_chipset	-	set up chiset for new speed
+ *	@drive: drive to configure for
+ *	@xferspeed: desired speed
+ *
+ *	Configure the hardware for the desired IDE transfer mode.
+ *	We also do the needed drive configuration through helpers
+ */
+ 
+static int ali15x3_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 speed	= ide_rate_filter(ali15x3_ratemask(drive), xferspeed);
+	u8 unit			= (drive->select.b.unit & 0x01);
+	u8 tmpbyte		= 0x00;
+	int m5229_udma		= (hwif->channel) ? 0x57 : 0x56;
+
+	if (speed < XFER_UDMA_0) {
+		u8 ultra_enable	= (unit) ? 0x7f : 0xf7;
+		/*
+		 * clear "ultra enable" bit
+		 */
+		pci_read_config_byte(dev, m5229_udma, &tmpbyte);
+		tmpbyte &= ultra_enable;
+		pci_write_config_byte(dev, m5229_udma, tmpbyte);
+
+		if (speed < XFER_SW_DMA_0)
+			ali15x3_tune_drive(drive, speed);
+	} else {
+		pci_read_config_byte(dev, m5229_udma, &tmpbyte);
+		tmpbyte &= (0x0f << ((1-unit) << 2));
+		/*
+		 * enable ultra dma and set timing
+		 */
+		tmpbyte |= ((0x08 | ((4-speed)&0x07)) << (unit << 2));
+		pci_write_config_byte(dev, m5229_udma, tmpbyte);
+		if (speed >= XFER_UDMA_3) {
+			pci_read_config_byte(dev, 0x4b, &tmpbyte);
+			tmpbyte |= 1;
+			pci_write_config_byte(dev, 0x4b, tmpbyte);
+		}
+	}
+	return (ide_config_drive_speed(drive, speed));
+}
+
+
+/**
+ *	config_chipset_for_dma	-	set up DMA mode
+ *	@drive: drive to configure for
+ *
+ *	Place a drive into DMA mode and tune the chipset for
+ *	the selected speed.
+ *
+ *	Returns true if DMA mode can be used
+ */
+ 
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	u8 speed = ide_dma_speed(drive, ali15x3_ratemask(drive));
+
+	if (!(speed))
+		return 0;
+
+	(void) ali15x3_tune_chipset(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+/**
+ *	ali15x3_config_drive_for_dma	-	configure for DMA
+ *	@drive: drive to configure
+ *
+ *	Configure a drive for DMA operation. If DMA is not possible we
+ *	drop the drive into PIO mode instead.
+ *
+ *	FIXME: exactly what are we trying to return here
+ */
+ 
+static int ali15x3_config_drive_for_dma(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	if ((m5229_revision<=0x20) && (drive->media!=ide_disk))
+		return hwif->ide_dma_off_quietly(drive);
+
+	drive->init_speed = 0;
+
+	if ((id != NULL) && ((id->capability & 1) != 0) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if ((id->field_valid & 4) && (m5229_revision >= 0xC2)) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		hwif->tuneproc(drive, 5);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+/**
+ *	ali15x3_dma_write	-	do a DMA IDE write
+ *	@drive:	drive to issue write for
+ *
+ *	Returns 1 if the DMA write cannot be performed, zero on 
+ *	success.
+ */
+ 
+static int ali15x3_dma_write (ide_drive_t *drive)
+{
+	if ((m5229_revision < 0xC2) && (drive->media != ide_disk))
+		return 1;	/* try PIO instead of DMA */
+	return __ide_dma_write(drive);
+}
+
+/**
+ *	init_chipset_ali15x3	-	Initialise an ALi IDE controller
+ *	@dev: PCI device
+ *	@name: Name of the controller
+ *
+ *	This function initializes the ALI IDE controller and where 
+ *	appropriate also sets up the 1533 southbridge.
+ */
+  
+static unsigned int __init init_chipset_ali15x3 (struct pci_dev *dev, const char *name)
+{
+	unsigned long flags;
+	u8 tmpbyte;
+	struct pci_dev *north = pci_find_slot(0, PCI_DEVFN(0,0));
+
+	pci_read_config_byte(dev, PCI_REVISION_ID, &m5229_revision);
+
+	isa_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
+
+#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!ali_proc) {
+		ali_proc = 1;
+		bmide_dev = dev;
+		ide_pci_register_host_proc(&ali_procs[0]);
+	}
+#endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+	local_irq_save(flags);
+
+	if (m5229_revision < 0xC2) {
+		/*
+		 * revision 0x20 (1543-E, 1543-F)
+		 * revision 0xC0, 0xC1 (1543C-C, 1543C-D, 1543C-E)
+		 * clear CD-ROM DMA write bit, m5229, 0x4b, bit 7
+		 */
+		pci_read_config_byte(dev, 0x4b, &tmpbyte);
+		/*
+		 * clear bit 7
+		 */
+		pci_write_config_byte(dev, 0x4b, tmpbyte & 0x7F);
+		local_irq_restore(flags);
+		return 0;
+	}
+
+	/*
+	 * 1543C-B?, 1535, 1535D, 1553
+	 * Note 1: not all "motherboard" support this detection
+	 * Note 2: if no udma 66 device, the detection may "error".
+	 *         but in this case, we will not set the device to
+	 *         ultra 66, the detection result is not important
+	 */
+
+	/*
+	 * enable "Cable Detection", m5229, 0x4b, bit3
+	 */
+	pci_read_config_byte(dev, 0x4b, &tmpbyte);
+	pci_write_config_byte(dev, 0x4b, tmpbyte | 0x08);
+
+	/*
+	 * We should only tune the 1533 enable if we are using an ALi
+	 * North bridge. We might have no north found on some zany
+	 * box without a device at 0:0.0. The ALi bridge will be at
+	 * 0:0.0 so if we didn't find one we know what is cooking.
+	 */
+	if (north && north->vendor != PCI_VENDOR_ID_AL) {
+		local_irq_restore(flags);
+	        return 0;
+	}
+
+	/*
+	 * set south-bridge's enable bit, m1533, 0x79
+	 */
+
+	pci_read_config_byte(isa_dev, 0x79, &tmpbyte);
+	if (m5229_revision == 0xC2) {
+		/*
+		 * 1543C-B0 (m1533, 0x79, bit 2)
+		 */
+		pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x04);
+	} else if (m5229_revision >= 0xC3) {
+		/*
+		 * 1553/1535 (m1533, 0x79, bit 1)
+		 */
+		pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x02);
+	}
+
+	local_irq_restore(flags);
+	return 0;
+}
+
+/**
+ *	ata66_ali15x3	-	check for UDMA 66 support
+ *	@hwif: IDE interface
+ *
+ *	This checks if the controller and the cable are capable
+ *	of UDMA66 transfers. It doesn't check the drives.
+ *	But see note 2 below!
+ *
+ *	FIXME: frobs bits that are not defined on newer ALi devicea
+ */
+
+static unsigned int __init ata66_ali15x3 (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev	= hwif->pci_dev;
+	unsigned int ata66	= 0;
+	u8 cable_80_pin[2]	= { 0, 0 };
+
+	unsigned long flags;
+	u8 tmpbyte;
+
+	local_irq_save(flags);
+
+	if (m5229_revision >= 0xC2) {
+		/*
+		 * Ultra66 cable detection (from Host View)
+		 * m5229, 0x4a, bit0: primary, bit1: secondary 80 pin
+		 */
+		pci_read_config_byte(dev, 0x4a, &tmpbyte);
+		/*
+		 * 0x4a, bit0 is 0 => primary channel
+		 * has 80-pin (from host view)
+		 */
+		if (!(tmpbyte & 0x01)) cable_80_pin[0] = 1;
+		/*
+		 * 0x4a, bit1 is 0 => secondary channel
+		 * has 80-pin (from host view)
+		 */
+		if (!(tmpbyte & 0x02)) cable_80_pin[1] = 1;
+		/*
+		 * Allow ata66 if cable of current channel has 80 pins
+		 */
+		ata66 = (hwif->channel)?cable_80_pin[1]:cable_80_pin[0];
+	} else {
+		/*
+		 * check m1533, 0x5e, bit 1~4 == 1001 => & 00011110 = 00010010
+		 */
+		pci_read_config_byte(isa_dev, 0x5e, &tmpbyte);
+		chip_is_1543c_e = ((tmpbyte & 0x1e) == 0x12) ? 1: 0;
+	}
+
+	/*
+	 * CD_ROM DMA on (m5229, 0x53, bit0)
+	 *      Enable this bit even if we want to use PIO
+	 * PIO FIFO off (m5229, 0x53, bit1)
+	 *      The hardware will use 0x54h and 0x55h to control PIO FIFO
+	 *	(Not on later devices it seems)
+	 *
+	 *	0x53 changes meaning on later revs - we must no touch
+	 *	bit 1 on them. Need to check if 0x20 is the right break
+	 */
+	 
+	pci_read_config_byte(dev, 0x53, &tmpbyte);
+	
+	if(m5229_revision <= 0x20)
+		tmpbyte = (tmpbyte & (~0x02)) | 0x01;
+	else
+		tmpbyte |= 0x01;
+
+	pci_write_config_byte(dev, 0x53, tmpbyte);
+
+	local_irq_restore(flags);
+
+	return(ata66);
+}
+
+/**
+ *	init_hwif_common_ali15x3	-	Set up ALI IDE hardware
+ *	@hwif: IDE interface
+ *
+ *	Initialize the IDE structure side of the ALi 15x3 driver.
+ */
+ 
+static void __init init_hwif_common_ali15x3 (ide_hwif_t *hwif)
+{
+	hwif->autodma = 0;
+	hwif->tuneproc = &ali15x3_tune_drive;
+	hwif->speedproc = &ali15x3_tune_chipset;
+
+	/* Don't use LBA48 on ALi devices before rev 0xC5 */
+	hwif->addressing = (m5229_revision <= 0xC4) ? 1 : 0;
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	if (m5229_revision > 0x20)
+		hwif->ultra_mask = 0x3f;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+        if (m5229_revision >= 0x20) {
+                /*
+                 * M1543C or newer for DMAing
+                 */
+                hwif->ide_dma_check = &ali15x3_config_drive_for_dma;
+                hwif->ide_dma_write = &ali15x3_dma_write;
+		if (!noautodma)
+			hwif->autodma = 1;
+		if (!(hwif->udma_four))
+			hwif->udma_four = ata66_ali15x3(hwif);
+	}
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+/**
+ *	init_hwif_ali15x3	-	Initialize the ALI IDE x86 stuff
+ *	@hwif: interface to configure
+ *
+ *	Obtain the IRQ tables for an ALi based IDE solution on the PC
+ *	class platforms. This part of the code isn't applicable to the
+ *	Sparc systems
+ */
+
+static void __init init_hwif_ali15x3 (ide_hwif_t *hwif)
+{
+	u8 ideic, inmir;
+	s8 irq_routing_table[] = { -1,  9, 3, 10, 4,  5, 7,  6,
+				      1, 11, 0, 12, 0, 14, 0, 15 };
+	int irq = -1;
+	
+	hwif->irq = hwif->channel ? 15 : 14;
+
+	if (isa_dev) {
+		/*
+		 * read IDE interface control
+		 */
+		pci_read_config_byte(isa_dev, 0x58, &ideic);
+
+		/* bit0, bit1 */
+		ideic = ideic & 0x03;
+
+		/* get IRQ for IDE Controller */
+		if ((hwif->channel && ideic == 0x03) ||
+		    (!hwif->channel && !ideic)) {
+			/*
+			 * get SIRQ1 routing table
+			 */
+			pci_read_config_byte(isa_dev, 0x44, &inmir);
+			inmir = inmir & 0x0f;
+			irq = irq_routing_table[inmir];
+		} else if (hwif->channel && !(ideic & 0x01)) {
+			/*
+			 * get SIRQ2 routing table
+			 */
+			pci_read_config_byte(isa_dev, 0x75, &inmir);
+			inmir = inmir & 0x0f;
+			irq = irq_routing_table[inmir];
+		}
+		if(irq >= 0)
+			hwif->irq = irq;
+	}
+
+	init_hwif_common_ali15x3(hwif);
+}
+
+/**
+ *	init_dma_ali15x3	-	set up DMA on ALi15x3
+ *	@hwif: IDE interface
+ *	@dmabase: DMA interface base PCI address
+ *
+ *	Set up the DMA functionality on the ALi 15x3. For the ALi
+ *	controllers this is generic so we can let the generic code do
+ *	the actual work.
+ */
+
+static void __init init_dma_ali15x3 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	if (m5229_revision < 0x20)
+		return;
+	if (!(hwif->channel))
+		hwif->OUTB(hwif->INB(dmabase+2) & 0x60, dmabase+2);
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+
+/**
+ *	alim15x3_init_one	-	set up an ALi15x3 IDE controller
+ *	@dev: PCI device to set up
+ *
+ *	Perform the actual set up for an ALi15x3 that has been found by the
+ *	hot plug layer.
+ */
+ 
+static int __devinit alim15x3_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &ali15x3_chipsets[id->driver_data];
+	
+	if(pci_find_device(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_IGP, NULL))
+		printk(KERN_ERR "Warning: ATI Radeon IGP Northbridge is not yet fully tested.\n");
+
+#if defined(CONFIG_SPARC64)
+	d->init_hwif = init_hwif_common_ali15x3;
+#endif /* CONFIG_SPARC64 */
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+
+static struct pci_device_id alim15x3_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "ALI15x3 IDE",
+	.id_table	= alim15x3_pci_tbl,
+	.probe		= alim15x3_init_one,
+};
+
+static int ali15x3_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void ali15x3_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(ali15x3_ide_init);
+module_exit(ali15x3_ide_exit);
+
+MODULE_AUTHOR("Michael Aubry, Andrzej Krzysztofowicz, CJ, Andre Hedrick, Alan Cox");
+MODULE_DESCRIPTION("PCI driver module for ALi 15x3 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/alim15x3.h linux-2.4.21-pre6/drivers/ide/pci/alim15x3.h
--- linux-2.4.20/drivers/ide/pci/alim15x3.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/alim15x3.h	2003-03-26 23:48:59.000000000 +0000
@@ -0,0 +1,55 @@
+#ifndef ALI15X3_H
+#define ALI15X3_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_ALI_TIMINGS
+
+#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 ali_proc;
+
+static int ali_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t ali_procs[] __initdata = {
+	{
+		.name		= "ali",
+		.set		= 1,
+		.get_info	= ali_get_info,
+		.parent		= NULL,
+	},
+};
+#endif /* DISPLAY_ALI_TIMINGS && CONFIG_PROC_FS */
+
+static unsigned int init_chipset_ali15x3(struct pci_dev *, const char *);
+static void init_hwif_common_ali15x3(ide_hwif_t *);
+static void init_hwif_ali15x3(ide_hwif_t *);
+static void init_dma_ali15x3(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t ali15x3_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_AL,
+		.device		= PCI_DEVICE_ID_AL_M5229,
+		.name		= "ALI15X3",
+		.init_chipset	= init_chipset_ali15x3,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_ali15x3,
+		.init_dma	= init_dma_ali15x3,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* ALI15X3 */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/amd74xx.c linux-2.4.21-pre6/drivers/ide/pci/amd74xx.c
--- linux-2.4.20/drivers/ide/pci/amd74xx.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/amd74xx.c	2003-03-26 23:48:58.000000000 +0000
@@ -0,0 +1,478 @@
+/*
+ * Version 2.10
+ *
+ * AMD 755/756/766/8111 and nVidia nForce IDE driver for Linux.
+ *
+ * Copyright (c) 2000-2002 Vojtech Pavlik
+ *
+ * Based on the work of:
+ *      Andre Hedrick
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+#include <asm/io.h>
+
+#include "ide-timing.h"
+#include "amd74xx.h"
+
+#define AMD_IDE_ENABLE		(0x00 + amd_config->base)
+#define AMD_IDE_CONFIG		(0x01 + amd_config->base)
+#define AMD_CABLE_DETECT	(0x02 + amd_config->base)
+#define AMD_DRIVE_TIMING	(0x08 + amd_config->base)
+#define AMD_8BIT_TIMING		(0x0e + amd_config->base)
+#define AMD_ADDRESS_SETUP	(0x0c + amd_config->base)
+#define AMD_UDMA_TIMING		(0x10 + amd_config->base)
+
+#define AMD_UDMA		0x07
+#define AMD_UDMA_33		0x01
+#define AMD_UDMA_66		0x02
+#define AMD_UDMA_100		0x03
+#define AMD_CHECK_SWDMA		0x08
+#define AMD_BAD_SWDMA		0x10
+#define AMD_BAD_FIFO		0x20
+
+/*
+ * AMD SouthBridge chips.
+ */
+
+static struct amd_ide_chip {
+	unsigned short id;
+	unsigned char rev;
+	unsigned long base;
+	unsigned char flags;
+} amd_ide_chips[] = {
+	{ PCI_DEVICE_ID_AMD_COBRA_7401, 0x00, 0x40, AMD_UDMA_33 | AMD_BAD_SWDMA },	/* AMD-755 Cobra */
+	{ PCI_DEVICE_ID_AMD_VIPER_7409, 0x00, 0x40, AMD_UDMA_66 | AMD_CHECK_SWDMA },	/* AMD-756 Viper */
+	{ PCI_DEVICE_ID_AMD_VIPER_7411, 0x00, 0x40, AMD_UDMA_100 | AMD_BAD_FIFO },	/* AMD-766 Viper */
+	{ PCI_DEVICE_ID_AMD_OPUS_7441, 0x00, 0x40, AMD_UDMA_100 },			/* AMD-768 Opus */
+	{ PCI_DEVICE_ID_AMD_8111_IDE,  0x00, 0x40, AMD_UDMA_100 },			/* AMD-8111 */
+        { PCI_DEVICE_ID_NVIDIA_NFORCE_IDE, 0x00, 0x50, AMD_UDMA_100 },                  /* nVidia nForce */
+        { PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE, 0x00, 0x50, AMD_UDMA_100 },                  /* nVidia nForce */
+
+	{ 0 }
+};
+
+static struct amd_ide_chip *amd_config;
+static unsigned char amd_enabled;
+static unsigned int amd_80w;
+static unsigned int amd_clock;
+
+static unsigned char amd_cyc2udma[] = { 6, 6, 5, 4, 0, 1, 1, 2, 2, 3, 3 };
+static unsigned char amd_udma2cyc[] = { 4, 6, 8, 10, 3, 2, 1, 1 };
+static char *amd_dma[] = { "MWDMA16", "UDMA33", "UDMA66", "UDMA100" };
+
+/*
+ * AMD /proc entry.
+ */
+
+#ifdef CONFIG_PROC_FS
+
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static unsigned long amd_base;
+static struct pci_dev *bmide_dev;
+extern int (*amd74xx_display_info)(char *, char **, off_t, int); /* ide-proc.c */
+
+#define amd_print(format, arg...) p += sprintf(p, format "\n" , ## arg)
+#define amd_print_drive(name, format, arg...)\
+	p += sprintf(p, name); for (i = 0; i < 4; i++) p += sprintf(p, format, ## arg); p += sprintf(p, "\n");
+
+static int amd74xx_get_info(char *buffer, char **addr, off_t offset, int count)
+{
+	int speed[4], cycle[4], setup[4], active[4], recover[4], den[4],
+		 uen[4], udma[4], active8b[4], recover8b[4];
+	struct pci_dev *dev = bmide_dev;
+	unsigned int v, u, i;
+	unsigned short c, w;
+	unsigned char t;
+	char *p = buffer;
+
+	amd_print("----------AMD BusMastering IDE Configuration----------------");
+
+	amd_print("Driver Version:                     2.10");
+	amd_print("South Bridge:                       %s", bmide_dev->name);
+
+	pci_read_config_byte(dev, PCI_REVISION_ID, &t);
+	amd_print("Revision:                           IDE %#x", t);
+	amd_print("Highest DMA rate:                   %s", amd_dma[amd_config->flags & AMD_UDMA]);
+
+	amd_print("BM-DMA base:                        %#lx", amd_base);
+	amd_print("PCI clock:                          %d.%dMHz", amd_clock / 1000, amd_clock / 100 % 10);
+	
+	amd_print("-----------------------Primary IDE-------Secondary IDE------");
+
+	pci_read_config_byte(dev, AMD_IDE_CONFIG, &t);
+	amd_print("Prefetch Buffer:       %10s%20s", (t & 0x80) ? "yes" : "no", (t & 0x20) ? "yes" : "no");
+	amd_print("Post Write Buffer:     %10s%20s", (t & 0x40) ? "yes" : "no", (t & 0x10) ? "yes" : "no");
+
+	pci_read_config_byte(dev, AMD_IDE_ENABLE, &t);
+	amd_print("Enabled:               %10s%20s", (t & 0x02) ? "yes" : "no", (t & 0x01) ? "yes" : "no");
+
+	c = inb(amd_base + 0x02) | (inb(amd_base + 0x0a) << 8);
+	amd_print("Simplex only:          %10s%20s", (c & 0x80) ? "yes" : "no", (c & 0x8000) ? "yes" : "no");
+
+	amd_print("Cable Type:            %10s%20s", (amd_80w & 1) ? "80w" : "40w", (amd_80w & 2) ? "80w" : "40w");
+
+	if (!amd_clock)
+                return p - buffer;
+
+	amd_print("-------------------drive0----drive1----drive2----drive3-----");
+
+	pci_read_config_byte(dev, AMD_ADDRESS_SETUP, &t);
+	pci_read_config_dword(dev, AMD_DRIVE_TIMING, &v);
+	pci_read_config_word(dev, AMD_8BIT_TIMING, &w);
+	pci_read_config_dword(dev, AMD_UDMA_TIMING, &u);
+
+	for (i = 0; i < 4; i++) {
+		setup[i]     = ((t >> ((3 - i) << 1)) & 0x3) + 1;
+		recover8b[i] = ((w >> ((1 - (i >> 1)) << 3)) & 0xf) + 1;
+		active8b[i]  = ((w >> (((1 - (i >> 1)) << 3) + 4)) & 0xf) + 1;
+		active[i]    = ((v >> (((3 - i) << 3) + 4)) & 0xf) + 1;
+		recover[i]   = ((v >> ((3 - i) << 3)) & 0xf) + 1;
+
+		udma[i] = amd_udma2cyc[((u >> ((3 - i) << 3)) & 0x7)];
+		uen[i]  = ((u >> ((3 - i) << 3)) & 0x40) ? 1 : 0;
+		den[i]  = (c & ((i & 1) ? 0x40 : 0x20) << ((i & 2) << 2));
+
+		if (den[i] && uen[i] && udma[i] == 1) {
+			speed[i] = amd_clock * 3;
+			cycle[i] = 666666 / amd_clock;
+			continue;
+		}
+
+		speed[i] = 4 * amd_clock / ((den[i] && uen[i]) ? udma[i] : (active[i] + recover[i]) * 2);
+		cycle[i] = 1000000 * ((den[i] && uen[i]) ? udma[i] : (active[i] + recover[i]) * 2) / amd_clock / 2;
+	}
+
+	amd_print_drive("Transfer Mode: ", "%10s", den[i] ? (uen[i] ? "UDMA" : "DMA") : "PIO");
+
+	amd_print_drive("Address Setup: ", "%8dns", 1000000 * setup[i] / amd_clock);
+	amd_print_drive("Cmd Active:    ", "%8dns", 1000000 * active8b[i] / amd_clock);
+	amd_print_drive("Cmd Recovery:  ", "%8dns", 1000000 * recover8b[i] / amd_clock);
+	amd_print_drive("Data Active:   ", "%8dns", 1000000 * active[i] / amd_clock);
+	amd_print_drive("Data Recovery: ", "%8dns", 1000000 * recover[i] / amd_clock);
+	amd_print_drive("Cycle Time:    ", "%8dns", cycle[i]);
+	amd_print_drive("Transfer Rate: ", "%4d.%dMB/s", speed[i] / 1000, speed[i] / 100 % 10);
+
+	return p - buffer;	/* hoping it is less than 4K... */
+}
+
+#endif
+
+/*
+ * amd_set_speed() writes timing values to the chipset registers
+ */
+
+static void amd_set_speed(struct pci_dev *dev, unsigned char dn, struct ide_timing *timing)
+{
+	unsigned char t;
+
+	pci_read_config_byte(dev, AMD_ADDRESS_SETUP, &t);
+	t = (t & ~(3 << ((3 - dn) << 1))) | ((FIT(timing->setup, 1, 4) - 1) << ((3 - dn) << 1));
+	pci_write_config_byte(dev, AMD_ADDRESS_SETUP, t);
+
+	pci_write_config_byte(dev, AMD_8BIT_TIMING + (1 - (dn >> 1)),
+		((FIT(timing->act8b, 1, 16) - 1) << 4) | (FIT(timing->rec8b, 1, 16) - 1));
+
+	pci_write_config_byte(dev, AMD_DRIVE_TIMING + (3 - dn),
+		((FIT(timing->active, 1, 16) - 1) << 4) | (FIT(timing->recover, 1, 16) - 1));
+
+	switch (amd_config->flags & AMD_UDMA) {
+		case AMD_UDMA_33:  t = timing->udma ? (0xc0 | (FIT(timing->udma, 2, 5) - 2)) : 0x03; break;
+		case AMD_UDMA_66:  t = timing->udma ? (0xc0 | amd_cyc2udma[FIT(timing->udma, 2, 10)]) : 0x03; break;
+		case AMD_UDMA_100: t = timing->udma ? (0xc0 | amd_cyc2udma[FIT(timing->udma, 1, 10)]) : 0x03; break;
+		default: return;
+	}
+
+	pci_write_config_byte(dev, AMD_UDMA_TIMING + (3 - dn), t);
+}
+
+/*
+ * amd_set_drive() computes timing values configures the drive and
+ * the chipset to a desired transfer mode. It also can be called
+ * by upper layers.
+ */
+
+static int amd_set_drive(ide_drive_t *drive, u8 speed)
+{
+	ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1);
+	struct ide_timing t, p;
+	int T, UT;
+
+	if (speed != XFER_PIO_SLOW && speed != drive->current_speed)
+		if (ide_config_drive_speed(drive, speed))
+			printk(KERN_WARNING "ide%d: Drive %d didn't accept speed setting. Oh, well.\n",
+				drive->dn >> 1, drive->dn & 1);
+
+	T = 1000000000 / amd_clock;
+	UT = T / min_t(int, max_t(int, amd_config->flags & AMD_UDMA, 1), 2);
+
+	ide_timing_compute(drive, speed, &t, T, UT);
+
+	if (peer->present) {
+		ide_timing_compute(peer, peer->current_speed, &p, T, UT);
+		ide_timing_merge(&p, &t, &t, IDE_TIMING_8BIT);
+	}
+
+	if (speed == XFER_UDMA_5 && amd_clock <= 33333) t.udma = 1;
+
+	amd_set_speed(HWIF(drive)->pci_dev, drive->dn, &t);
+
+	if (!drive->init_speed)	
+		drive->init_speed = speed;
+	drive->current_speed = speed;
+
+	return 0;
+}
+
+/*
+ * amd74xx_tune_drive() is a callback from upper layers for
+ * PIO-only tuning.
+ */
+
+static void amd74xx_tune_drive(ide_drive_t *drive, u8 pio)
+{
+	if (!((amd_enabled >> HWIF(drive)->channel) & 1))
+		return;
+
+	if (pio == 255) {
+		amd_set_drive(drive, ide_find_best_mode(drive, XFER_PIO | XFER_EPIO));
+		return;
+	}
+
+	amd_set_drive(drive, XFER_PIO_0 + min_t(byte, pio, 5));
+}
+
+/*
+ * amd74xx_dmaproc() is a callback from upper layers that can do
+ * a lot, but we use it for DMA/PIO tuning only, delegating everything
+ * else to the default ide_dmaproc().
+ */
+
+static int amd74xx_ide_dma_check(ide_drive_t *drive)
+{
+	int w80 = HWIF(drive)->udma_four;
+
+	u8 speed = ide_find_best_mode(drive,
+		XFER_PIO | XFER_EPIO | XFER_MWDMA | XFER_UDMA |
+		((amd_config->flags & AMD_BAD_SWDMA) ? 0 : XFER_SWDMA) |
+		(w80 && (amd_config->flags & AMD_UDMA) >= AMD_UDMA_66 ? XFER_UDMA_66 : 0) |
+		(w80 && (amd_config->flags & AMD_UDMA) >= AMD_UDMA_100 ? XFER_UDMA_100 : 0));
+
+	amd_set_drive(drive, speed);
+
+	if (drive->autodma && (speed & XFER_MODE) != XFER_PIO)
+		return HWIF(drive)->ide_dma_on(drive);
+	return HWIF(drive)->ide_dma_off_quietly(drive);
+}
+
+/*
+ * The initialization callback. Here we determine the IDE chip type
+ * and initialize its drive independent registers.
+ */
+
+static unsigned int __init init_chipset_amd74xx(struct pci_dev *dev, const char *name)
+{
+	unsigned char t;
+	unsigned int u;
+	int i;
+
+/*
+ * Check for bad SWDMA.
+ */
+
+	if (amd_config->flags & AMD_CHECK_SWDMA) {
+		pci_read_config_byte(dev, PCI_REVISION_ID, &t);
+		if (t <= 7)
+			amd_config->flags |= AMD_BAD_SWDMA;
+	}
+
+/*
+ * Check 80-wire cable presence.
+ */
+
+	switch (amd_config->flags & AMD_UDMA) {
+
+		case AMD_UDMA_100:
+			pci_read_config_byte(dev, AMD_CABLE_DETECT, &t);
+			pci_read_config_dword(dev, AMD_UDMA_TIMING, &u);
+			amd_80w = ((t & 0x3) ? 1 : 0) | ((t & 0xc) ? 2 : 0);
+			for (i = 24; i >= 0; i -= 8)
+				if (((u >> i) & 4) && !(amd_80w & (1 << (1 - (i >> 4))))) {
+					printk(KERN_WARNING "AMD_IDE: Bios didn't set cable bits corectly. Enabling workaround.\n");
+					amd_80w |= (1 << (1 - (i >> 4)));
+				}
+			break;
+
+		case AMD_UDMA_66:
+			pci_read_config_dword(dev, AMD_UDMA_TIMING, &u);
+			for (i = 24; i >= 0; i -= 8)
+				if ((u >> i) & 4)
+					amd_80w |= (1 << (1 - (i >> 4)));
+			break;
+	}
+
+	pci_read_config_dword(dev, AMD_IDE_ENABLE, &u);
+	amd_enabled = ((u & 1) ? 2 : 0) | ((u & 2) ? 1 : 0);
+
+/*
+ * Take care of prefetch & postwrite.
+ */
+
+	pci_read_config_byte(dev, AMD_IDE_CONFIG, &t);
+	pci_write_config_byte(dev, AMD_IDE_CONFIG,
+		(amd_config->flags & AMD_BAD_FIFO) ? (t & 0x0f) : (t | 0xf0));
+
+/*
+ * Determine the system bus clock.
+ */
+
+	amd_clock = system_bus_clock() * 1000;
+
+	switch (amd_clock) {
+		case 33000: amd_clock = 33333; break;
+		case 37000: amd_clock = 37500; break;
+		case 41000: amd_clock = 41666; break;
+	}
+
+	if (amd_clock < 20000 || amd_clock > 50000) {
+		printk(KERN_WARNING "AMD_IDE: User given PCI clock speed impossible (%d), using 33 MHz instead.\n", amd_clock);
+		printk(KERN_WARNING "AMD_IDE: Use ide0=ata66 if you want to assume 80-wire cable\n");
+		amd_clock = 33333;
+	}
+
+/*
+ * Print the boot message.
+ */
+
+	pci_read_config_byte(dev, PCI_REVISION_ID, &t);
+	printk(KERN_INFO "AMD_IDE: %s (rev %02x) %s controller on pci%s\n",
+		dev->name, t, amd_dma[amd_config->flags & AMD_UDMA], dev->slot_name);
+
+/*
+ * Register /proc/ide/amd74xx entry
+ */
+
+#if defined(DISPLAY_AMD_TIMINGS) && defined(CONFIG_PROC_FS)
+        if (!amd74xx_proc) {
+                amd_base = pci_resource_start(dev, 4);
+                bmide_dev = dev;
+                ide_pci_register_host_proc(&amd74xx_procs[0]);
+                amd74xx_proc = 1;
+        }
+#endif /* DISPLAY_AMD_TIMINGS && CONFIG_PROC_FS */
+
+
+	return 0;
+}
+
+static unsigned int __init ata66_amd74xx(ide_hwif_t *hwif)
+{
+	return ((amd_enabled & amd_80w) >> hwif->channel) & 1;
+}
+
+static void __init init_hwif_amd74xx(ide_hwif_t *hwif)
+{
+	int i;
+
+	hwif->autodma = 0;
+
+	hwif->tuneproc = &amd74xx_tune_drive;
+	hwif->speedproc = &amd_set_drive;
+
+	for (i = 0; i < 2; i++) {
+		hwif->drives[i].io_32bit = 1;
+		hwif->drives[i].unmask = 1;
+		hwif->drives[i].autotune = 1;
+		hwif->drives[i].dn = hwif->channel * 2 + i;
+	}
+
+	if (!hwif->dma_base)
+		return;
+
+        hwif->atapi_dma = 1;
+        hwif->ultra_mask = 0x7f;
+        hwif->mwdma_mask = 0x07;
+        hwif->swdma_mask = 0x07;
+
+        if (!(hwif->udma_four))
+                hwif->udma_four = ((amd_enabled & amd_80w) >> hwif->channel) & 1;
+        hwif->ide_dma_check = &amd74xx_ide_dma_check;
+        if (!noautodma)
+                hwif->autodma = 1;
+        hwif->drives[0].autodma = hwif->autodma;
+        hwif->drives[1].autodma = hwif->autodma;
+}
+
+/*
+ * We allow the BM-DMA driver only work on enabled interfaces.
+ */
+
+static void __init init_dma_amd74xx(ide_hwif_t *hwif, unsigned long dmabase)
+{
+	if ((amd_enabled >> hwif->channel) & 1)
+		ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static int __devinit amd74xx_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = amd74xx_chipsets + id->driver_data;
+	amd_config = amd_ide_chips + id->driver_data;
+	if (dev->device != d->device) BUG();
+	if (dev->device != amd_config->id) BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id amd74xx_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_COBRA_7401,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7409,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7411,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+	{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_OPUS_7441,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+	{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_IDE, 	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "AMD IDE",
+	.id_table	= amd74xx_pci_tbl,
+	.probe		= amd74xx_probe,
+};
+
+static int amd74xx_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void amd74xx_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(amd74xx_ide_init);
+module_exit(amd74xx_ide_exit);
+
+MODULE_AUTHOR("Vojtech Pavlik");
+MODULE_DESCRIPTION("AMD PCI IDE driver");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/amd74xx.h linux-2.4.21-pre6/drivers/ide/pci/amd74xx.h
--- linux-2.4.20/drivers/ide/pci/amd74xx.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/amd74xx.h	2003-03-26 23:49:29.000000000 +0000
@@ -0,0 +1,135 @@
+#ifndef AMD74XX_H
+#define AMD74XX_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_AMD_TIMINGS
+
+#if defined(DISPLAY_AMD_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 amd74xx_proc;
+
+static int amd74xx_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t amd74xx_procs[] __initdata = {
+	{
+		.name		= "amd74xx",
+		.set		= 1,
+		.get_info	= amd74xx_get_info,
+		.parent		= NULL,
+	},
+};
+#endif  /* defined(DISPLAY_AMD_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static unsigned int init_chipset_amd74xx(struct pci_dev *, const char *);
+static void init_hwif_amd74xx(ide_hwif_t *);
+static void init_dma_amd74xx(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t amd74xx_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_AMD,
+		.device		= PCI_DEVICE_ID_AMD_COBRA_7401,
+		.name		= "AMD7401",
+		.init_chipset	= init_chipset_amd74xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_amd74xx,
+		.init_dma	= init_dma_amd74xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x40,0x01,0x01}, {0x40,0x02,0x02}},
+		.bootable	= ON_BOARD,
+		.extra		= 0
+	},{	/* 1 */
+		.vendor		= PCI_VENDOR_ID_AMD,
+		.device		= PCI_DEVICE_ID_AMD_VIPER_7409,
+		.name		= "AMD7409",
+		.init_chipset	= init_chipset_amd74xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_amd74xx,
+		.init_dma	= init_dma_amd74xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x40,0x01,0x01}, {0x40,0x02,0x02}},
+		.bootable	= ON_BOARD,
+		.extra		= 0
+	},{	/* 2 */
+		.vendor		= PCI_VENDOR_ID_AMD,
+		.device		= PCI_DEVICE_ID_AMD_VIPER_7411,
+		.name		= "AMD7411",
+		.init_chipset	= init_chipset_amd74xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_amd74xx,
+		.init_dma	= init_dma_amd74xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x40,0x01,0x01}, {0x40,0x02,0x02}},
+		.bootable	= ON_BOARD,
+		.extra		= 0
+	},{	/* 3 */
+		.vendor		= PCI_VENDOR_ID_AMD,
+		.device		= PCI_DEVICE_ID_AMD_OPUS_7441,
+		.name		= "AMD7441",
+		.init_chipset	= init_chipset_amd74xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_amd74xx,
+		.init_dma	= init_dma_amd74xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x40,0x01,0x01}, {0x40,0x02,0x02}},
+		.bootable	= ON_BOARD,
+		.extra		= 0
+	},{	/* 4 */
+		.vendor		= PCI_VENDOR_ID_AMD,
+		.device		= PCI_DEVICE_ID_AMD_8111_IDE,
+		.name		= "AMD8111",
+		.init_chipset	= init_chipset_amd74xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_amd74xx,
+		.init_dma	= init_dma_amd74xx,
+		.autodma	= AUTODMA,
+		.channels	= 2,
+		.enablebits	= {{0x40,0x01,0x01}, {0x40,0x02,0x02}},
+		.bootable	= ON_BOARD,
+		.extra		= 0
+	},
+	{	/* 5 */
+		.vendor		= PCI_VENDOR_ID_NVIDIA,
+		.device		= PCI_DEVICE_ID_NVIDIA_NFORCE_IDE,
+		.name		= "NFORCE",
+		.init_chipset	= init_chipset_amd74xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_amd74xx,
+		.init_dma	= init_dma_amd74xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x50,0x01,0x01}, {0x50,0x02,0x02}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},
+	{	/* 6 */
+		.vendor		= PCI_VENDOR_ID_NVIDIA,
+		.device		= PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE,
+		.name		= "NFORCE2",
+		.init_chipset	= init_chipset_amd74xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_amd74xx,
+		.init_dma	= init_dma_amd74xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x50,0x01,0x01}, {0x50,0x02,0x02}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},
+	{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* AMD74XX_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/cmd640.c linux-2.4.21-pre6/drivers/ide/pci/cmd640.c
--- linux-2.4.20/drivers/ide/pci/cmd640.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/cmd640.c	2003-03-26 23:49:34.000000000 +0000
@@ -0,0 +1,886 @@
+/*
+ *  linux/drivers/ide/pci/cmd640.c		Version 1.02  Sep 01, 1996
+ *
+ *  Copyright (C) 1995-1996  Linus Torvalds & authors (see below)
+ */
+
+/*
+ *  Original authors:	abramov@cecmow.enet.dec.com (Igor Abramov)
+ *  			mlord@pobox.com (Mark Lord)
+ *
+ *  See linux/MAINTAINERS for address of current maintainer.
+ *
+ *  This file provides support for the advanced features and bugs
+ *  of IDE interfaces using the CMD Technologies 0640 IDE interface chip.
+ *
+ *  These chips are basically fucked by design, and getting this driver
+ *  to work on every motherboard design that uses this screwed chip seems
+ *  bloody well impossible.  However, we're still trying.
+ *
+ *  Version 0.97 worked for everybody.
+ *
+ *  User feedback is essential.  Many thanks to the beta test team:
+ *
+ *  A.Hartgers@stud.tue.nl, JZDQC@CUNYVM.CUNY.edu, abramov@cecmow.enet.dec.com,
+ *  bardj@utopia.ppp.sn.no, bart@gaga.tue.nl, bbol001@cs.auckland.ac.nz,
+ *  chrisc@dbass.demon.co.uk, dalecki@namu26.Num.Math.Uni-Goettingen.de,
+ *  derekn@vw.ece.cmu.edu, florian@btp2x3.phy.uni-bayreuth.de,
+ *  flynn@dei.unipd.it, gadio@netvision.net.il, godzilla@futuris.net,
+ *  j@pobox.com, jkemp1@mises.uni-paderborn.de, jtoppe@hiwaay.net,
+ *  kerouac@ssnet.com, meskes@informatik.rwth-aachen.de, hzoli@cs.elte.hu,
+ *  peter@udgaard.isgtec.com, phil@tazenda.demon.co.uk, roadcapw@cfw.com,
+ *  s0033las@sun10.vsz.bme.hu, schaffer@tam.cornell.edu, sjd@slip.net,
+ *  steve@ei.org, ulrpeg@bigcomm.gun.de, ism@tardis.ed.ac.uk, mack@cray.com
+ *  liug@mama.indstate.edu, and others.
+ *
+ *  Version 0.01	Initial version, hacked out of ide.c,
+ *			and #include'd rather than compiled separately.
+ *			This will get cleaned up in a subsequent release.
+ *
+ *  Version 0.02	Fixes for vlb initialization code, enable prefetch
+ *			for versions 'B' and 'C' of chip by default,
+ *			some code cleanup.
+ *
+ *  Version 0.03	Added reset of secondary interface,
+ *			and black list for devices which are not compatible
+ *			with prefetch mode. Separate function for setting
+ *			prefetch is added, possibly it will be called some
+ *			day from ioctl processing code.
+ *
+ *  Version 0.04	Now configs/compiles separate from ide.c
+ *
+ *  Version 0.05	Major rewrite of interface timing code.
+ *			Added new function cmd640_set_mode to set PIO mode
+ *			from ioctl call. New drives added to black list.
+ *
+ *  Version 0.06	More code cleanup. Prefetch is enabled only for
+ *			detected hard drives, not included in prefetch
+ *			black list.
+ *
+ *  Version 0.07	Changed to more conservative drive tuning policy.
+ *			Unknown drives, which report PIO < 4 are set to
+ *			(reported_PIO - 1) if it is supported, or to PIO0.
+ *			List of known drives extended by info provided by
+ *			CMD at their ftp site.
+ *
+ *  Version 0.08	Added autotune/noautotune support.
+ *
+ *  Version 0.09	Try to be smarter about 2nd port enabling.
+ *  Version 0.10	Be nice and don't reset 2nd port.
+ *  Version 0.11	Try to handle more weird situations.
+ *
+ *  Version 0.12	Lots of bug fixes from Laszlo Peter
+ *			irq unmasking disabled for reliability.
+ *			try to be even smarter about the second port.
+ *			tidy up source code formatting.
+ *  Version 0.13	permit irq unmasking again.
+ *  Version 0.90	massive code cleanup, some bugs fixed.
+ *			defaults all drives to PIO mode0, prefetch off.
+ *			autotune is OFF by default, with compile time flag.
+ *			prefetch can be turned OFF/ON using "hdparm -p8/-p9"
+ *			 (requires hdparm-3.1 or newer)
+ *  Version 0.91	first release to linux-kernel list.
+ *  Version 0.92	move initial reg dump to separate callable function
+ *			change "readahead" to "prefetch" to avoid confusion
+ *  Version 0.95	respect original BIOS timings unless autotuning.
+ *			tons of code cleanup and rearrangement.
+ *			added CONFIG_BLK_DEV_CMD640_ENHANCED option
+ *			prevent use of unmask when prefetch is on
+ *  Version 0.96	prevent use of io_32bit when prefetch is off
+ *  Version 0.97	fix VLB secondary interface for sjd@slip.net
+ *			other minor tune-ups:  0.96 was very good.
+ *  Version 0.98	ignore PCI version when disabled by BIOS
+ *  Version 0.99	display setup/active/recovery clocks with PIO mode
+ *  Version 1.00	Mmm.. cannot depend on PCMD_ENA in all systems
+ *  Version 1.01	slow/fast devsel can be selected with "hdparm -p6/-p7"
+ *			 ("fast" is necessary for 32bit I/O in some systems)
+ *  Version 1.02	fix bug that resulted in slow "setup times"
+ *			 (patch courtesy of Zoltan Hidvegi)
+ */
+
+#undef REALLY_SLOW_IO		/* most systems can safely undef this */
+#define CMD640_PREFETCH_MASKS 1
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "ide_modes.h"
+
+/*
+ * This flag is set in ide.c by the parameter:  ide0=cmd640_vlb
+ */
+int cmd640_vlb = 0;
+
+/*
+ * CMD640 specific registers definition.
+ */
+
+#define VID		0x00
+#define DID		0x02
+#define PCMD		0x04
+#define   PCMD_ENA	0x01
+#define PSTTS		0x06
+#define REVID		0x08
+#define PROGIF		0x09
+#define SUBCL		0x0a
+#define BASCL		0x0b
+#define BaseA0		0x10
+#define BaseA1		0x14
+#define BaseA2		0x18
+#define BaseA3		0x1c
+#define INTLINE		0x3c
+#define INPINE		0x3d
+
+#define	CFR		0x50
+#define   CFR_DEVREV		0x03
+#define   CFR_IDE01INTR		0x04
+#define	  CFR_DEVID		0x18
+#define	  CFR_AT_VESA_078h	0x20
+#define	  CFR_DSA1		0x40
+#define	  CFR_DSA0		0x80
+
+#define CNTRL		0x51
+#define	  CNTRL_DIS_RA0		0x40
+#define   CNTRL_DIS_RA1		0x80
+#define	  CNTRL_ENA_2ND		0x08
+
+#define	CMDTIM		0x52
+#define	ARTTIM0		0x53
+#define	DRWTIM0		0x54
+#define ARTTIM1 	0x55
+#define DRWTIM1		0x56
+#define ARTTIM23	0x57
+#define   ARTTIM23_DIS_RA2	0x04
+#define   ARTTIM23_DIS_RA3	0x08
+#define DRWTIM23	0x58
+#define BRST		0x59
+
+/*
+ * Registers and masks for easy access by drive index:
+ */
+static u8 prefetch_regs[4]  = {CNTRL, CNTRL, ARTTIM23, ARTTIM23};
+static u8 prefetch_masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2, ARTTIM23_DIS_RA3};
+
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+
+static u8 arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23};
+static u8 drwtim_regs[4] = {DRWTIM0, DRWTIM1, DRWTIM23, DRWTIM23};
+
+/*
+ * Current cmd640 timing values for each drive.
+ * The defaults for each are the slowest possible timings.
+ */
+static u8 setup_counts[4]    = {4, 4, 4, 4};     /* Address setup count (in clocks) */
+static u8 active_counts[4]   = {16, 16, 16, 16}; /* Active count   (encoded) */
+static u8 recovery_counts[4] = {16, 16, 16, 16}; /* Recovery count (encoded) */
+
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+
+/*
+ * These are initialized to point at the devices we control
+ */
+static ide_hwif_t  *cmd_hwif0, *cmd_hwif1;
+static ide_drive_t *cmd_drives[4];
+
+/*
+ * Interface to access cmd640x registers
+ */
+static unsigned int cmd640_key;
+static void (*put_cmd640_reg)(u16 reg, u8 val);
+static u8 (*get_cmd640_reg)(u16 reg);
+
+/*
+ * This is read from the CFR reg, and is used in several places.
+ */
+static unsigned int cmd640_chip_version;
+
+/*
+ * The CMD640x chip does not support DWORD config write cycles, but some
+ * of the BIOSes use them to implement the config services.
+ * Therefore, we must use direct IO instead.
+ */
+
+/* PCI method 1 access */
+
+static void put_cmd640_reg_pci1 (u16 reg, u8 val)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	outb_p((reg & 0xfc) | cmd640_key, 0xcf8);
+	outb_p(val, (reg & 3) | 0xcfc);
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+static u8 get_cmd640_reg_pci1 (u16 reg)
+{
+	u8 b;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	outb_p((reg & 0xfc) | cmd640_key, 0xcf8);
+	b = inb_p((reg & 3) | 0xcfc);
+	spin_unlock_irqrestore(&ide_lock, flags);
+	return b;
+}
+
+/* PCI method 2 access (from CMD datasheet) */
+
+static void put_cmd640_reg_pci2 (u16 reg, u8 val)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	outb_p(0x10, 0xcf8);
+	outb_p(val, cmd640_key + reg);
+	outb_p(0, 0xcf8);
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+static u8 get_cmd640_reg_pci2 (u16 reg)
+{
+	u8 b;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	outb_p(0x10, 0xcf8);
+	b = inb_p(cmd640_key + reg);
+	outb_p(0, 0xcf8);
+	spin_unlock_irqrestore(&ide_lock, flags);
+	return b;
+}
+
+/* VLB access */
+
+static void put_cmd640_reg_vlb (u16 reg, u8 val)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	outb_p(reg, cmd640_key);
+	outb_p(val, cmd640_key + 4);
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+static u8 get_cmd640_reg_vlb (u16 reg)
+{
+	u8 b;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	outb_p(reg, cmd640_key);
+	b = inb_p(cmd640_key + 4);
+	spin_unlock_irqrestore(&ide_lock, flags);
+	return b;
+}
+
+static int __init match_pci_cmd640_device (void)
+{
+	const u8 ven_dev[4] = {0x95, 0x10, 0x40, 0x06};
+	unsigned int i;
+	for (i = 0; i < 4; i++) {
+		if (get_cmd640_reg(i) != ven_dev[i])
+			return 0;
+	}
+#ifdef STUPIDLY_TRUST_BROKEN_PCMD_ENA_BIT
+	if ((get_cmd640_reg(PCMD) & PCMD_ENA) == 0) {
+		printk("ide: cmd640 on PCI disabled by BIOS\n");
+		return 0;
+	}
+#endif /* STUPIDLY_TRUST_BROKEN_PCMD_ENA_BIT */
+	return 1; /* success */
+}
+
+/*
+ * Probe for CMD640x -- pci method 1
+ */
+static int __init probe_for_cmd640_pci1 (void)
+{
+	get_cmd640_reg = get_cmd640_reg_pci1;
+	put_cmd640_reg = put_cmd640_reg_pci1;
+	for (cmd640_key = 0x80000000;
+	     cmd640_key <= 0x8000f800;
+	     cmd640_key += 0x800) {
+		if (match_pci_cmd640_device())
+			return 1; /* success */
+	}
+	return 0;
+}
+
+/*
+ * Probe for CMD640x -- pci method 2
+ */
+static int __init probe_for_cmd640_pci2 (void)
+{
+	get_cmd640_reg = get_cmd640_reg_pci2;
+	put_cmd640_reg = put_cmd640_reg_pci2;
+	for (cmd640_key = 0xc000; cmd640_key <= 0xcf00; cmd640_key += 0x100) {
+		if (match_pci_cmd640_device())
+			return 1; /* success */
+	}
+	return 0;
+}
+
+/*
+ * Probe for CMD640x -- vlb
+ */
+static int __init probe_for_cmd640_vlb (void)
+{
+	u8 b;
+
+	get_cmd640_reg = get_cmd640_reg_vlb;
+	put_cmd640_reg = put_cmd640_reg_vlb;
+	cmd640_key = 0x178;
+	b = get_cmd640_reg(CFR);
+	if (b == 0xff || b == 0x00 || (b & CFR_AT_VESA_078h)) {
+		cmd640_key = 0x78;
+		b = get_cmd640_reg(CFR);
+		if (b == 0xff || b == 0x00 || !(b & CFR_AT_VESA_078h))
+			return 0;
+	}
+	return 1; /* success */
+}
+
+/*
+ *  Returns 1 if an IDE interface/drive exists at 0x170,
+ *  Returns 0 otherwise.
+ */
+static int __init secondary_port_responding (void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ide_lock, flags);
+
+	outb_p(0x0a, 0x170 + IDE_SELECT_OFFSET);	/* select drive0 */
+	udelay(100);
+	if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x0a) {
+		outb_p(0x1a, 0x170 + IDE_SELECT_OFFSET); /* select drive1 */
+		udelay(100);
+		if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x1a) {
+			spin_unlock_irqrestore(&ide_lock, flags);
+			return 0; /* nothing responded */
+		}
+	}
+	spin_unlock_irqrestore(&ide_lock, flags);
+	return 1; /* success */
+}
+
+#ifdef CMD640_DUMP_REGS
+/*
+ * Dump out all cmd640 registers.  May be called from ide.c
+ */
+static void cmd640_dump_regs (void)
+{
+	unsigned int reg = cmd640_vlb ? 0x50 : 0x00;
+
+	/* Dump current state of chip registers */
+	printk("ide: cmd640 internal register dump:");
+	for (; reg <= 0x59; reg++) {
+		if (!(reg & 0x0f))
+			printk("\n%04x:", reg);
+		printk(" %02x", get_cmd640_reg(reg));
+	}
+	printk("\n");
+}
+#endif
+
+/*
+ * Check whether prefetch is on for a drive,
+ * and initialize the unmask flags for safe operation.
+ */
+static void __init check_prefetch (unsigned int index)
+{
+	ide_drive_t *drive = cmd_drives[index];
+	u8 b = get_cmd640_reg(prefetch_regs[index]);
+
+	if (b & prefetch_masks[index]) {	/* is prefetch off? */
+		drive->no_unmask = 0;
+		drive->no_io_32bit = 1;
+		drive->io_32bit = 0;
+	} else {
+#if CMD640_PREFETCH_MASKS
+		drive->no_unmask = 1;
+		drive->unmask = 0;
+#endif
+		drive->no_io_32bit = 0;
+	}
+}
+
+/*
+ * Figure out which devices we control
+ */
+static void __init setup_device_ptrs (void)
+{
+	unsigned int i;
+
+	cmd_hwif0 = &ide_hwifs[0]; /* default, if not found below */
+	cmd_hwif1 = &ide_hwifs[1]; /* default, if not found below */
+	for (i = 0; i < MAX_HWIFS; i++) {
+		ide_hwif_t *hwif = &ide_hwifs[i];
+		if (hwif->chipset == ide_unknown || hwif->chipset == ide_generic) {
+			if (hwif->io_ports[IDE_DATA_OFFSET] == 0x1f0)
+				cmd_hwif0 = hwif;
+			else if (hwif->io_ports[IDE_DATA_OFFSET] == 0x170)
+				cmd_hwif1 = hwif;
+		}
+	}
+	cmd_drives[0] = &cmd_hwif0->drives[0];
+	cmd_drives[1] = &cmd_hwif0->drives[1];
+	cmd_drives[2] = &cmd_hwif1->drives[0];
+	cmd_drives[3] = &cmd_hwif1->drives[1];
+}
+
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+
+/*
+ * Sets prefetch mode for a drive.
+ */
+static void set_prefetch_mode (unsigned int index, int mode)
+{
+	ide_drive_t *drive = cmd_drives[index];
+	int reg = prefetch_regs[index];
+	u8 b;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	b = get_cmd640_reg(reg);
+	if (mode) {	/* want prefetch on? */
+#if CMD640_PREFETCH_MASKS
+		drive->no_unmask = 1;
+		drive->unmask = 0;
+#endif
+		drive->no_io_32bit = 0;
+		b &= ~prefetch_masks[index];	/* enable prefetch */
+	} else {
+		drive->no_unmask = 0;
+		drive->no_io_32bit = 1;
+		drive->io_32bit = 0;
+		b |= prefetch_masks[index];	/* disable prefetch */
+	}
+	put_cmd640_reg(reg, b);
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+/*
+ * Dump out current drive clocks settings
+ */
+static void display_clocks (unsigned int index)
+{
+	u8 active_count, recovery_count;
+
+	active_count = active_counts[index];
+	if (active_count == 1)
+		++active_count;
+	recovery_count = recovery_counts[index];
+	if (active_count > 3 && recovery_count == 1)
+		++recovery_count;
+	if (cmd640_chip_version > 1)
+		recovery_count += 1;  /* cmd640b uses (count + 1)*/
+	printk(", clocks=%d/%d/%d\n", setup_counts[index], active_count, recovery_count);
+}
+
+/*
+ * Pack active and recovery counts into single byte representation
+ * used by controller
+ */
+inline static u8 pack_nibbles (u8 upper, u8 lower)
+{
+	return ((upper & 0x0f) << 4) | (lower & 0x0f);
+}
+
+/*
+ * This routine retrieves the initial drive timings from the chipset.
+ */
+static void __init retrieve_drive_counts (unsigned int index)
+{
+	u8 b;
+
+	/*
+	 * Get the internal setup timing, and convert to clock count
+	 */
+	b = get_cmd640_reg(arttim_regs[index]) & ~0x3f;
+	switch (b) {
+		case 0x00: b = 4; break;
+		case 0x80: b = 3; break;
+		case 0x40: b = 2; break;
+		default:   b = 5; break;
+	}
+	setup_counts[index] = b;
+
+	/*
+	 * Get the active/recovery counts
+	 */
+	b = get_cmd640_reg(drwtim_regs[index]);
+	active_counts[index]   = (b >> 4)   ? (b >> 4)   : 0x10;
+	recovery_counts[index] = (b & 0x0f) ? (b & 0x0f) : 0x10;
+}
+
+
+/*
+ * This routine writes the prepared setup/active/recovery counts
+ * for a drive into the cmd640 chipset registers to active them.
+ */
+static void program_drive_counts (unsigned int index)
+{
+	unsigned long flags;
+	u8 setup_count    = setup_counts[index];
+	u8 active_count   = active_counts[index];
+	u8 recovery_count = recovery_counts[index];
+
+	/*
+	 * Set up address setup count and drive read/write timing registers.
+	 * Primary interface has individual count/timing registers for
+	 * each drive.  Secondary interface has one common set of registers,
+	 * so we merge the timings, using the slowest value for each timing.
+	 */
+	if (index > 1) {
+		unsigned int mate;
+		if (cmd_drives[mate = index ^ 1]->present) {
+			if (setup_count < setup_counts[mate])
+				setup_count = setup_counts[mate];
+			if (active_count < active_counts[mate])
+				active_count = active_counts[mate];
+			if (recovery_count < recovery_counts[mate])
+				recovery_count = recovery_counts[mate];
+		}
+	}
+
+	/*
+	 * Convert setup_count to internal chipset representation
+	 */
+	switch (setup_count) {
+		case 4:	 setup_count = 0x00; break;
+		case 3:	 setup_count = 0x80; break;
+		case 1:
+		case 2:	 setup_count = 0x40; break;
+		default: setup_count = 0xc0; /* case 5 */
+	}
+
+	/*
+	 * Now that everything is ready, program the new timings
+	 */
+	spin_lock_irqsave(&ide_lock, flags);
+	/*
+	 * Program the address_setup clocks into ARTTIM reg,
+	 * and then the active/recovery counts into the DRWTIM reg
+	 * (this converts counts of 16 into counts of zero -- okay).
+	 */
+	setup_count |= get_cmd640_reg(arttim_regs[index]) & 0x3f;
+	put_cmd640_reg(arttim_regs[index], setup_count);
+	put_cmd640_reg(drwtim_regs[index], pack_nibbles(active_count, recovery_count));
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+/*
+ * Set a specific pio_mode for a drive
+ */
+static void cmd640_set_mode (unsigned int index, u8 pio_mode, unsigned int cycle_time)
+{
+	int setup_time, active_time, recovery_time, clock_time;
+	u8 setup_count, active_count, recovery_count, recovery_count2, cycle_count;
+	int bus_speed = system_bus_clock();
+
+	if (pio_mode > 5)
+		pio_mode = 5;
+	setup_time  = ide_pio_timings[pio_mode].setup_time;
+	active_time = ide_pio_timings[pio_mode].active_time;
+	recovery_time = cycle_time - (setup_time + active_time);
+	clock_time = 1000 / bus_speed;
+	cycle_count = (cycle_time + clock_time - 1) / clock_time;
+
+	setup_count = (setup_time + clock_time - 1) / clock_time;
+
+	active_count = (active_time + clock_time - 1) / clock_time;
+	if (active_count < 2)
+		active_count = 2; /* minimum allowed by cmd640 */
+
+	recovery_count = (recovery_time + clock_time - 1) / clock_time;
+	recovery_count2 = cycle_count - (setup_count + active_count);
+	if (recovery_count2 > recovery_count)
+		recovery_count = recovery_count2;
+	if (recovery_count < 2)
+		recovery_count = 2; /* minimum allowed by cmd640 */
+	if (recovery_count > 17) {
+		active_count += recovery_count - 17;
+		recovery_count = 17;
+	}
+	if (active_count > 16)
+		active_count = 16; /* maximum allowed by cmd640 */
+	if (cmd640_chip_version > 1)
+		recovery_count -= 1;  /* cmd640b uses (count + 1)*/
+	if (recovery_count > 16)
+		recovery_count = 16; /* maximum allowed by cmd640 */
+
+	setup_counts[index]    = setup_count;
+	active_counts[index]   = active_count;
+	recovery_counts[index] = recovery_count;
+
+	/*
+	 * In a perfect world, we might set the drive pio mode here
+	 * (using WIN_SETFEATURE) before continuing.
+	 *
+	 * But we do not, because:
+	 *	1) this is the wrong place to do it (proper is do_special() in ide.c)
+	 * 	2) in practice this is rarely, if ever, necessary
+	 */
+	program_drive_counts (index);
+}
+
+/*
+ * Drive PIO mode selection:
+ */
+static void cmd640_tune_drive (ide_drive_t *drive, u8 mode_wanted)
+{
+	u8 b;
+	ide_pio_data_t  d;
+	unsigned int index = 0;
+
+	while (drive != cmd_drives[index]) {
+		if (++index > 3) {
+			printk("%s: bad news in cmd640_tune_drive\n", drive->name);
+			return;
+		}
+	}
+	switch (mode_wanted) {
+		case 6: /* set fast-devsel off */
+		case 7: /* set fast-devsel on */
+			mode_wanted &= 1;
+			b = get_cmd640_reg(CNTRL) & ~0x27;
+			if (mode_wanted)
+				b |= 0x27;
+			put_cmd640_reg(CNTRL, b);
+			printk("%s: %sabled cmd640 fast host timing (devsel)\n", drive->name, mode_wanted ? "en" : "dis");
+			return;
+
+		case 8: /* set prefetch off */
+		case 9: /* set prefetch on */
+			mode_wanted &= 1;
+			set_prefetch_mode(index, mode_wanted);
+			printk("%s: %sabled cmd640 prefetch\n", drive->name, mode_wanted ? "en" : "dis");
+			return;
+	}
+
+	(void) ide_get_best_pio_mode (drive, mode_wanted, 5, &d);
+	cmd640_set_mode (index, d.pio_mode, d.cycle_time);
+
+	printk ("%s: selected cmd640 PIO mode%d (%dns)%s",
+		drive->name,
+		d.pio_mode,
+		d.cycle_time,
+		d.overridden ? " (overriding vendor mode)" : "");
+	display_clocks(index);
+	return;
+}
+
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+
+static int pci_conf1(void)
+{
+	u32 tmp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	outb(0x01, 0xCFB);
+	tmp = inl(0xCF8);
+	outl(0x80000000, 0xCF8);
+	if (inl(0xCF8) == 0x80000000) {
+		outl(tmp, 0xCF8);
+		spin_unlock_irqrestore(&ide_lock, flags);
+		return 1;
+	}
+	outl(tmp, 0xCF8);
+	spin_unlock_irqrestore(&ide_lock, flags);
+	return 0;
+}
+
+static int pci_conf2(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	outb(0x00, 0xCFB);
+	outb(0x00, 0xCF8);
+	outb(0x00, 0xCFA);
+	if (inb(0xCF8) == 0x00 && inb(0xCF8) == 0x00) {
+		spin_unlock_irqrestore(&ide_lock, flags);
+		return 1;
+	}
+	spin_unlock_irqrestore(&ide_lock, flags);
+	return 0;
+}
+
+/*
+ * Probe for a cmd640 chipset, and initialize it if found.  Called from ide.c
+ */
+int __init ide_probe_for_cmd640x (void)
+{
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+	int second_port_toggled = 0;
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+	int second_port_cmd640 = 0;
+	const char *bus_type, *port2;
+	unsigned int index;
+	u8 b, cfr;
+
+	if (cmd640_vlb && probe_for_cmd640_vlb()) {
+		bus_type = "VLB";
+	} else {
+		cmd640_vlb = 0;
+		/* Find out what kind of PCI probing is supported otherwise
+		   Justin Gibbs will sulk.. */
+		if (pci_conf1() && probe_for_cmd640_pci1())
+			bus_type = "PCI (type1)";
+		else if (pci_conf2() && probe_for_cmd640_pci2())
+			bus_type = "PCI (type2)";
+		else
+			return 0;
+	}
+	/*
+	 * Undocumented magic (there is no 0x5b reg in specs)
+	 */
+	put_cmd640_reg(0x5b, 0xbd);
+	if (get_cmd640_reg(0x5b) != 0xbd) {
+		printk(KERN_ERR "ide: cmd640 init failed: wrong value in reg 0x5b\n");
+		return 0;
+	}
+	put_cmd640_reg(0x5b, 0);
+
+#ifdef CMD640_DUMP_REGS
+	CMD640_DUMP_REGS;
+#endif
+
+	/*
+	 * Documented magic begins here
+	 */
+	cfr = get_cmd640_reg(CFR);
+	cmd640_chip_version = cfr & CFR_DEVREV;
+	if (cmd640_chip_version == 0) {
+		printk ("ide: bad cmd640 revision: %d\n", cmd640_chip_version);
+		return 0;
+	}
+
+	/*
+	 * Initialize data for primary port
+	 */
+	setup_device_ptrs ();
+	printk("%s: buggy cmd640%c interface on %s, config=0x%02x\n",
+	       cmd_hwif0->name, 'a' + cmd640_chip_version - 1, bus_type, cfr);
+	cmd_hwif0->chipset = ide_cmd640;
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+	cmd_hwif0->tuneproc = &cmd640_tune_drive;
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+
+	/*
+	 * Ensure compatibility by always using the slowest timings
+	 * for access to the drive's command register block,
+	 * and reset the prefetch burstsize to default (512 bytes).
+	 *
+	 * Maybe we need a way to NOT do these on *some* systems?
+	 */
+	put_cmd640_reg(CMDTIM, 0);
+	put_cmd640_reg(BRST, 0x40);
+
+	/*
+	 * Try to enable the secondary interface, if not already enabled
+	 */
+	if (cmd_hwif1->noprobe) {
+		port2 = "not probed";
+	} else {
+		b = get_cmd640_reg(CNTRL);
+		if (secondary_port_responding()) {
+			if ((b & CNTRL_ENA_2ND)) {
+				second_port_cmd640 = 1;
+				port2 = "okay";
+			} else if (cmd640_vlb) {
+				second_port_cmd640 = 1;
+				port2 = "alive";
+			} else
+				port2 = "not cmd640";
+		} else {
+			put_cmd640_reg(CNTRL, b ^ CNTRL_ENA_2ND); /* toggle the bit */
+			if (secondary_port_responding()) {
+				second_port_cmd640 = 1;
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+				second_port_toggled = 1;
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+				port2 = "enabled";
+			} else {
+				put_cmd640_reg(CNTRL, b); /* restore original setting */
+				port2 = "not responding";
+			}
+		}
+	}
+
+	/*
+	 * Initialize data for secondary cmd640 port, if enabled
+	 */
+	if (second_port_cmd640) {
+		cmd_hwif0->serialized = 1;
+		cmd_hwif1->serialized = 1;
+		cmd_hwif1->chipset = ide_cmd640;
+		cmd_hwif0->mate = cmd_hwif1;
+		cmd_hwif1->mate = cmd_hwif0;
+		cmd_hwif1->channel = 1;
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+		cmd_hwif1->tuneproc = &cmd640_tune_drive;
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+	}
+	printk(KERN_INFO "%s: %sserialized, secondary interface %s\n", cmd_hwif1->name,
+		cmd_hwif0->serialized ? "" : "not ", port2);
+
+	/*
+	 * Establish initial timings/prefetch for all drives.
+	 * Do not unnecessarily disturb any prior BIOS setup of these.
+	 */
+	for (index = 0; index < (2 + (second_port_cmd640 << 1)); index++) {
+		ide_drive_t *drive = cmd_drives[index];
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+		if (drive->autotune || ((index > 1) && second_port_toggled)) {
+	 		/*
+	 		 * Reset timing to the slowest speed and turn off prefetch.
+			 * This way, the drive identify code has a better chance.
+			 */
+			setup_counts    [index] = 4;	/* max possible */
+			active_counts   [index] = 16;	/* max possible */
+			recovery_counts [index] = 16;	/* max possible */
+			program_drive_counts (index);
+			set_prefetch_mode (index, 0);
+			printk("cmd640: drive%d timings/prefetch cleared\n", index);
+		} else {
+			/*
+			 * Record timings/prefetch without changing them.
+			 * This preserves any prior BIOS setup.
+			 */
+			retrieve_drive_counts (index);
+			check_prefetch (index);
+			printk("cmd640: drive%d timings/prefetch(%s) preserved",
+				index, drive->no_io_32bit ? "off" : "on");
+			display_clocks(index);
+		}
+#else
+		/*
+		 * Set the drive unmask flags to match the prefetch setting
+		 */
+		check_prefetch (index);
+		printk("cmd640: drive%d timings/prefetch(%s) preserved\n",
+			index, drive->no_io_32bit ? "off" : "on");
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+	}
+
+#ifdef CMD640_DUMP_REGS
+	CMD640_DUMP_REGS;
+#endif
+	return 1;
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/cmd640.h linux-2.4.21-pre6/drivers/ide/pci/cmd640.h
--- linux-2.4.20/drivers/ide/pci/cmd640.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/cmd640.h	2003-03-26 23:48:59.000000000 +0000
@@ -0,0 +1,32 @@
+#ifndef CMD640_H
+#define CMD640_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define IDE_IGNORE      ((void *)-1)
+
+static ide_pci_device_t cmd640_chipsets[] __initdata = {
+	{
+		.vendor		= PCI_VENDOR_ID_CMD,
+		.device		= PCI_DEVICE_ID_CMD_640,
+		.name		= "CMD640",
+		.init_setup	= NULL,
+		.init_chipset	= NULL,
+		.init_iops	= NULL,
+		.init_hwif	= IDE_IGNORE,
+		.init_dma	= NULL,
+		.channels	= 2,
+		.autodma	= NODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.bootable	= EOL,
+	}
+}
+
+#endif /* CMD640_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/cmd64x.c linux-2.4.21-pre6/drivers/ide/pci/cmd64x.c
--- linux-2.4.20/drivers/ide/pci/cmd64x.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/cmd64x.c	2003-03-26 23:49:29.000000000 +0000
@@ -0,0 +1,798 @@
+/* $Id: cmd64x.c,v 1.21 2000/01/30 23:23:16
+ *
+ * linux/drivers/ide/pci/cmd64x.c		Version 1.30	Sept 10, 2002
+ *
+ * cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines.
+ *           Note, this driver is not used at all on other systems because
+ *           there the "BIOS" has done all of the following already.
+ *           Due to massive hardware bugs, UltraDMA is only supported
+ *           on the 646U2 and not on the 646U.
+ *
+ * Copyright (C) 1998		Eddie C. Dost  (ecd@skynet.be)
+ * Copyright (C) 1998		David S. Miller (davem@redhat.com)
+ *
+ * Copyright (C) 1999-2002	Andre Hedrick <andre@linux-ide.org>
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "ide_modes.h"
+#include "cmd64x.h"
+
+#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 cmd64x_proc = 0;
+
+#define CMD_MAX_DEVS		5
+
+static struct pci_dev *cmd_devs[CMD_MAX_DEVS];
+static int n_cmd_devs;
+
+#undef DEBUG_CMD_REGS
+
+static char * print_cmd64x_get_info (char *buf, struct pci_dev *dev, int index)
+{
+	char *p = buf;
+
+	u8 reg53 = 0, reg54 = 0, reg55 = 0, reg56 = 0;	/* primary */
+	u8 reg57 = 0, reg58 = 0, reg5b;			/* secondary */
+	u8 reg72 = 0, reg73 = 0;			/* primary */
+	u8 reg7a = 0, reg7b = 0;			/* secondary */
+	u8 reg50 = 0, reg71 = 0;			/* extra */
+#ifdef DEBUG_CMD_REGS
+	u8 hi_byte = 0, lo_byte = 0;
+#endif /* DEBUG_CMD_REGS */
+
+	p += sprintf(p, "\nController: %d\n", index);
+	p += sprintf(p, "CMD%x Chipset.\n", dev->device);
+	(void) pci_read_config_byte(dev, CFR,       &reg50);
+	(void) pci_read_config_byte(dev, ARTTIM0,   &reg53);
+	(void) pci_read_config_byte(dev, DRWTIM0,   &reg54);
+	(void) pci_read_config_byte(dev, ARTTIM1,   &reg55);
+	(void) pci_read_config_byte(dev, DRWTIM1,   &reg56);
+	(void) pci_read_config_byte(dev, ARTTIM2,   &reg57);
+	(void) pci_read_config_byte(dev, DRWTIM2,   &reg58);
+	(void) pci_read_config_byte(dev, DRWTIM3,   &reg5b);
+	(void) pci_read_config_byte(dev, MRDMODE,   &reg71);
+	(void) pci_read_config_byte(dev, BMIDESR0,  &reg72);
+	(void) pci_read_config_byte(dev, UDIDETCR0, &reg73);
+	(void) pci_read_config_byte(dev, BMIDESR1,  &reg7a);
+	(void) pci_read_config_byte(dev, UDIDETCR1, &reg7b);
+
+	p += sprintf(p, "--------------- Primary Channel "
+			"---------------- Secondary Channel "
+			"-------------\n");
+	p += sprintf(p, "                %sabled           "
+			"              %sabled\n",
+		(reg72&0x80)?"dis":" en",
+		(reg7a&0x80)?"dis":" en");
+	p += sprintf(p, "--------------- drive0 "
+		"--------- drive1 -------- drive0 "
+		"---------- drive1 ------\n");
+	p += sprintf(p, "DMA enabled:    %s              %s"
+			"             %s               %s\n",
+		(reg72&0x20)?"yes":"no ", (reg72&0x40)?"yes":"no ",
+		(reg7a&0x20)?"yes":"no ", (reg7a&0x40)?"yes":"no ");
+
+	p += sprintf(p, "DMA Mode:       %s(%s)          %s(%s)",
+		(reg72&0x20)?((reg73&0x01)?"UDMA":" DMA"):" PIO",
+		(reg72&0x20)?(
+			((reg73&0x30)==0x30)?(((reg73&0x35)==0x35)?"3":"0"):
+			((reg73&0x20)==0x20)?(((reg73&0x25)==0x25)?"3":"1"):
+			((reg73&0x10)==0x10)?(((reg73&0x15)==0x15)?"4":"2"):
+			((reg73&0x00)==0x00)?(((reg73&0x05)==0x05)?"5":"2"):
+			"X"):"?",
+		(reg72&0x40)?((reg73&0x02)?"UDMA":" DMA"):" PIO",
+		(reg72&0x40)?(
+			((reg73&0xC0)==0xC0)?(((reg73&0xC5)==0xC5)?"3":"0"):
+			((reg73&0x80)==0x80)?(((reg73&0x85)==0x85)?"3":"1"):
+			((reg73&0x40)==0x40)?(((reg73&0x4A)==0x4A)?"4":"2"):
+			((reg73&0x00)==0x00)?(((reg73&0x0A)==0x0A)?"5":"2"):
+			"X"):"?");
+	p += sprintf(p, "         %s(%s)           %s(%s)\n",
+		(reg7a&0x20)?((reg7b&0x01)?"UDMA":" DMA"):" PIO",
+		(reg7a&0x20)?(
+			((reg7b&0x30)==0x30)?(((reg7b&0x35)==0x35)?"3":"0"):
+			((reg7b&0x20)==0x20)?(((reg7b&0x25)==0x25)?"3":"1"):
+			((reg7b&0x10)==0x10)?(((reg7b&0x15)==0x15)?"4":"2"):
+			((reg7b&0x00)==0x00)?(((reg7b&0x05)==0x05)?"5":"2"):
+			"X"):"?",
+		(reg7a&0x40)?((reg7b&0x02)?"UDMA":" DMA"):" PIO",
+		(reg7a&0x40)?(
+			((reg7b&0xC0)==0xC0)?(((reg7b&0xC5)==0xC5)?"3":"0"):
+			((reg7b&0x80)==0x80)?(((reg7b&0x85)==0x85)?"3":"1"):
+			((reg7b&0x40)==0x40)?(((reg7b&0x4A)==0x4A)?"4":"2"):
+			((reg7b&0x00)==0x00)?(((reg7b&0x0A)==0x0A)?"5":"2"):
+			"X"):"?" );
+	p += sprintf(p, "PIO Mode:       %s                %s"
+			"               %s                 %s\n",
+			"?", "?", "?", "?");
+	p += sprintf(p, "                %s                     %s\n",
+		(reg50 & CFR_INTR_CH0) ? "interrupting" : "polling     ",
+		(reg57 & ARTTIM23_INTR_CH1) ? "interrupting" : "polling");
+	p += sprintf(p, "                %s                          %s\n",
+		(reg71 & MRDMODE_INTR_CH0) ? "pending" : "clear  ",
+		(reg71 & MRDMODE_INTR_CH1) ? "pending" : "clear");
+	p += sprintf(p, "                %s                          %s\n",
+		(reg71 & MRDMODE_BLK_CH0) ? "blocked" : "enabled",
+		(reg71 & MRDMODE_BLK_CH1) ? "blocked" : "enabled");
+
+#ifdef DEBUG_CMD_REGS
+	SPLIT_BYTE(reg50, hi_byte, lo_byte);
+	p += sprintf(p, "CFR       = 0x%02x, HI = 0x%02x, "
+			"LOW = 0x%02x\n", reg50, hi_byte, lo_byte);
+	SPLIT_BYTE(reg57, hi_byte, lo_byte);
+	p += sprintf(p, "ARTTIM23  = 0x%02x, HI = 0x%02x, "
+			"LOW = 0x%02x\n", reg57, hi_byte, lo_byte);
+	SPLIT_BYTE(reg71, hi_byte, lo_byte);
+	p += sprintf(p, "MRDMODE   = 0x%02x, HI = 0x%02x, "
+			"LOW = 0x%02x\n", reg71, hi_byte, lo_byte);
+#endif /* DEBUG_CMD_REGS */
+
+	return (char *)p;
+}
+
+static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	int i;
+
+	p += sprintf(p, "\n");
+	for (i = 0; i < n_cmd_devs; i++) {
+		struct pci_dev *dev	= cmd_devs[i];
+		p = print_cmd64x_get_info(p, dev, i);
+	}
+	return p-buffer;	/* => must be less than 4k! */
+}
+
+#endif	/* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+/*
+ * Registers and masks for easy access by drive index:
+ */
+#if 0
+static u8 prefetch_regs[4]  = {CNTRL, CNTRL, ARTTIM23, ARTTIM23};
+static u8 prefetch_masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2, ARTTIM23_DIS_RA3};
+#endif
+
+/*
+ * This routine writes the prepared setup/active/recovery counts
+ * for a drive into the cmd646 chipset registers to active them.
+ */
+static void program_drive_counts (ide_drive_t *drive, int setup_count, int active_count, int recovery_count)
+{
+	unsigned long flags;
+	struct pci_dev *dev = HWIF(drive)->pci_dev;
+	ide_drive_t *drives = HWIF(drive)->drives;
+	u8 temp_b;
+	static const u8 setup_counts[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0};
+	static const u8 recovery_counts[] =
+		{15, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0};
+	static const u8 arttim_regs[2][2] = {
+			{ ARTTIM0, ARTTIM1 },
+			{ ARTTIM23, ARTTIM23 }
+		};
+	static const u8 drwtim_regs[2][2] = {
+			{ DRWTIM0, DRWTIM1 },
+			{ DRWTIM2, DRWTIM3 }
+		};
+	int channel = (int) HWIF(drive)->channel;
+	int slave = (drives != drive);  /* Is this really the best way to determine this?? */
+
+	cmdprintk("program_drive_count parameters = s(%d),a(%d),r(%d),p(%d)\n",
+		setup_count, active_count, recovery_count, drive->present);
+	/*
+	 * Set up address setup count registers.
+	 * Primary interface has individual count/timing registers for
+	 * each drive.  Secondary interface has one common set of registers,
+	 * for address setup so we merge these timings, using the slowest
+	 * value.
+	 */
+	if (channel) {
+		drive->drive_data = setup_count;
+		setup_count = IDE_MAX(drives[0].drive_data,
+					drives[1].drive_data);
+		cmdprintk("Secondary interface, setup_count = %d\n",
+					setup_count);
+	}
+
+	/*
+	 * Convert values to internal chipset representation
+	 */
+	setup_count = (setup_count > 5) ? 0xc0 : (int) setup_counts[setup_count];
+	active_count &= 0xf; /* Remember, max value is 16 */
+	recovery_count = (int) recovery_counts[recovery_count];
+
+	cmdprintk("Final values = %d,%d,%d\n",
+		setup_count, active_count, recovery_count);
+
+	/*
+	 * Now that everything is ready, program the new timings
+	 */
+	local_irq_save(flags);
+	/*
+	 * Program the address_setup clocks into ARTTIM reg,
+	 * and then the active/recovery counts into the DRWTIM reg
+	 */
+	(void) pci_read_config_byte(dev, arttim_regs[channel][slave], &temp_b);
+	(void) pci_write_config_byte(dev, arttim_regs[channel][slave],
+		((u8) setup_count) | (temp_b & 0x3f));
+	(void) pci_write_config_byte(dev, drwtim_regs[channel][slave],
+		(u8) ((active_count << 4) | recovery_count));
+	cmdprintk ("Write %x to %x\n",
+		((u8) setup_count) | (temp_b & 0x3f),
+		arttim_regs[channel][slave]);
+	cmdprintk ("Write %x to %x\n",
+		(u8) ((active_count << 4) | recovery_count),
+		drwtim_regs[channel][slave]);
+	local_irq_restore(flags);
+}
+
+/*
+ * Attempts to set the interface PIO mode.
+ * The preferred method of selecting PIO modes (e.g. mode 4) is 
+ * "echo 'piomode:4' > /proc/ide/hdx/settings".  Special cases are
+ * 8: prefetch off, 9: prefetch on, 255: auto-select best mode.
+ * Called with 255 at boot time.
+ */
+
+static void cmd64x_tuneproc (ide_drive_t *drive, u8 mode_wanted)
+{
+	int setup_time, active_time, recovery_time;
+	int clock_time, pio_mode, cycle_time;
+	u8 recovery_count2, cycle_count;
+	int setup_count, active_count, recovery_count;
+	int bus_speed = system_bus_clock();
+	/*byte b;*/
+	ide_pio_data_t  d;
+
+	switch (mode_wanted) {
+		case 8: /* set prefetch off */
+		case 9: /* set prefetch on */
+			mode_wanted &= 1;
+			/*set_prefetch_mode(index, mode_wanted);*/
+			cmdprintk("%s: %sabled cmd640 prefetch\n",
+				drive->name, mode_wanted ? "en" : "dis");
+			return;
+	}
+
+	mode_wanted = ide_get_best_pio_mode (drive, mode_wanted, 5, &d);
+	pio_mode = d.pio_mode;
+	cycle_time = d.cycle_time;
+
+	/*
+	 * I copied all this complicated stuff from cmd640.c and made a few
+	 * minor changes.  For now I am just going to pray that it is correct.
+	 */
+	if (pio_mode > 5)
+		pio_mode = 5;
+	setup_time  = ide_pio_timings[pio_mode].setup_time;
+	active_time = ide_pio_timings[pio_mode].active_time;
+	recovery_time = cycle_time - (setup_time + active_time);
+	clock_time = 1000 / bus_speed;
+	cycle_count = (cycle_time + clock_time - 1) / clock_time;
+
+	setup_count = (setup_time + clock_time - 1) / clock_time;
+
+	active_count = (active_time + clock_time - 1) / clock_time;
+
+	recovery_count = (recovery_time + clock_time - 1) / clock_time;
+	recovery_count2 = cycle_count - (setup_count + active_count);
+	if (recovery_count2 > recovery_count)
+		recovery_count = recovery_count2;
+	if (recovery_count > 16) {
+		active_count += recovery_count - 16;
+		recovery_count = 16;
+	}
+	if (active_count > 16)
+		active_count = 16; /* maximum allowed by cmd646 */
+
+	/*
+	 * In a perfect world, we might set the drive pio mode here
+	 * (using WIN_SETFEATURE) before continuing.
+	 *
+	 * But we do not, because:
+	 *	1) this is the wrong place to do it
+	 *		(proper is do_special() in ide.c)
+	 * 	2) in practice this is rarely, if ever, necessary
+	 */
+	program_drive_counts (drive, setup_count, active_count, recovery_count);
+
+	cmdprintk("%s: selected cmd646 PIO mode%d : %d (%dns)%s, "
+		"clocks=%d/%d/%d\n",
+		drive->name, pio_mode, mode_wanted, cycle_time,
+		d.overridden ? " (overriding vendor mode)" : "",
+		setup_count, active_count, recovery_count);
+}
+
+static u8 cmd64x_ratemask (ide_drive_t *drive)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	u8 mode = 0;
+
+	switch(dev->device) {
+		case PCI_DEVICE_ID_CMD_649:
+			mode = 3;
+			break;
+		case PCI_DEVICE_ID_CMD_648:
+			mode = 2;
+			break;
+		case PCI_DEVICE_ID_CMD_643:
+			return 0;
+
+		case PCI_DEVICE_ID_CMD_646:
+		{
+			unsigned int class_rev	= 0;
+			pci_read_config_dword(dev,
+				PCI_CLASS_REVISION, &class_rev);
+			class_rev &= 0xff;
+		/*
+		 * UltraDMA only supported on PCI646U and PCI646U2, which
+		 * correspond to revisions 0x03, 0x05 and 0x07 respectively.
+		 * Actually, although the CMD tech support people won't
+		 * tell me the details, the 0x03 revision cannot support
+		 * UDMA correctly without hardware modifications, and even
+		 * then it only works with Quantum disks due to some
+		 * hold time assumptions in the 646U part which are fixed
+		 * in the 646U2.
+		 *
+		 * So we only do UltraDMA on revision 0x05 and 0x07 chipsets.
+		 */
+			switch(class_rev) {
+				case 0x07:
+				case 0x05:
+					return 1;
+				case 0x03:
+				case 0x01:
+				default:
+					return 0;
+			}
+		}
+	}
+	if (!eighty_ninty_three(drive))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+static void config_cmd64x_chipset_for_pio (ide_drive_t *drive, u8 set_speed)
+{
+	u8 speed	= 0x00;
+	u8 set_pio	= ide_get_best_pio_mode(drive, 4, 5, NULL);
+
+	cmd64x_tuneproc(drive, set_pio);
+	speed = XFER_PIO_0 + set_pio;
+	if (set_speed)
+		(void) ide_config_drive_speed(drive, speed);
+}
+
+static void config_chipset_for_pio (ide_drive_t *drive, u8 set_speed)
+{
+	config_cmd64x_chipset_for_pio(drive, set_speed);
+}
+
+static int cmd64x_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+
+	u8 unit			= (drive->select.b.unit & 0x01);
+	u8 regU = 0, pciU	= (hwif->channel) ? UDIDETCR1 : UDIDETCR0;
+	u8 regD = 0, pciD	= (hwif->channel) ? BMIDESR1 : BMIDESR0;
+
+	u8 speed	= ide_rate_filter(cmd64x_ratemask(drive), xferspeed);
+
+	if (speed > XFER_PIO_4) {
+		(void) pci_read_config_byte(dev, pciD, &regD);
+		(void) pci_read_config_byte(dev, pciU, &regU);
+		regD &= ~(unit ? 0x40 : 0x20);
+		regU &= ~(unit ? 0xCA : 0x35);
+		(void) pci_write_config_byte(dev, pciD, regD);
+		(void) pci_write_config_byte(dev, pciU, regU);
+		(void) pci_read_config_byte(dev, pciD, &regD);
+		(void) pci_read_config_byte(dev, pciU, &regU);
+	}
+
+	switch(speed) {
+		case XFER_UDMA_5:	regU |= (unit ? 0x0A : 0x05); break;
+		case XFER_UDMA_4:	regU |= (unit ? 0x4A : 0x15); break;
+		case XFER_UDMA_3:	regU |= (unit ? 0x8A : 0x25); break;
+		case XFER_UDMA_2:	regU |= (unit ? 0x42 : 0x11); break;
+		case XFER_UDMA_1:	regU |= (unit ? 0x82 : 0x21); break;
+		case XFER_UDMA_0:	regU |= (unit ? 0xC2 : 0x31); break;
+		case XFER_MW_DMA_2:	regD |= (unit ? 0x40 : 0x10); break;
+		case XFER_MW_DMA_1:	regD |= (unit ? 0x80 : 0x20); break;
+		case XFER_MW_DMA_0:	regD |= (unit ? 0xC0 : 0x30); break;
+		case XFER_SW_DMA_2:	regD |= (unit ? 0x40 : 0x10); break;
+		case XFER_SW_DMA_1:	regD |= (unit ? 0x80 : 0x20); break;
+		case XFER_SW_DMA_0:	regD |= (unit ? 0xC0 : 0x30); break;
+		case XFER_PIO_4:	cmd64x_tuneproc(drive, 4); break;
+		case XFER_PIO_3:	cmd64x_tuneproc(drive, 3); break;
+		case XFER_PIO_2:	cmd64x_tuneproc(drive, 2); break;
+		case XFER_PIO_1:	cmd64x_tuneproc(drive, 1); break;
+		case XFER_PIO_0:	cmd64x_tuneproc(drive, 0); break;
+
+		default:
+			return 1;
+	}
+
+	if (speed > XFER_PIO_4) {
+		(void) pci_write_config_byte(dev, pciU, regU);
+		regD |= (unit ? 0x40 : 0x20);
+		(void) pci_write_config_byte(dev, pciD, regD);
+	}
+
+	return (ide_config_drive_speed(drive, speed));
+}
+
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	u8 speed	= ide_dma_speed(drive, cmd64x_ratemask(drive));
+
+	config_chipset_for_pio(drive, !speed);
+
+	if (!speed)
+		return 0;
+
+	if(ide_set_xfer_rate(drive, speed))
+		return 0; 
+
+	if (!drive->init_speed)
+		drive->init_speed = speed;
+
+	return ide_dma_enable(drive);
+}
+
+static int cmd64x_config_drive_for_dma (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	if ((id != NULL) && ((id->capability & 1) != 0) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if ((id->field_valid & 4) && cmd64x_ratemask(drive)) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		config_chipset_for_pio(drive, 1);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+static int cmd64x_alt_dma_status (struct pci_dev *dev)
+{
+	switch(dev->device) {
+		case PCI_DEVICE_ID_CMD_648:
+		case PCI_DEVICE_ID_CMD_649:
+			return 1;
+		default:
+			break;
+	}
+	return 0;
+}
+
+static int cmd64x_ide_dma_end (ide_drive_t *drive)
+{
+	u8 dma_stat = 0, dma_cmd = 0;
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+
+	drive->waiting_for_dma = 0;
+	/* read DMA command state */
+	dma_cmd = hwif->INB(hwif->dma_command);
+	/* stop DMA */
+	hwif->OUTB((dma_cmd & ~1), hwif->dma_command);
+	/* get DMA status */
+	dma_stat = hwif->INB(hwif->dma_status);
+	/* clear the INTR & ERROR bits */
+	hwif->OUTB(dma_stat|6, hwif->dma_status);
+	if (cmd64x_alt_dma_status(dev)) {
+		u8 dma_intr	= 0;
+		u8 dma_mask	= (hwif->channel) ? ARTTIM23_INTR_CH1 :
+						    CFR_INTR_CH0;
+		u8 dma_reg	= (hwif->channel) ? ARTTIM2 : CFR;
+		(void) pci_read_config_byte(dev, dma_reg, &dma_intr);
+		/* clear the INTR bit */
+		(void) pci_write_config_byte(dev, dma_reg, dma_intr|dma_mask);
+	}
+	/* purge DMA mappings */
+	ide_destroy_dmatable(drive);
+	/* verify good DMA status */
+	return (dma_stat & 7) != 4;
+}
+
+static int cmd64x_ide_dma_test_irq (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif		= HWIF(drive);
+	struct pci_dev *dev		= hwif->pci_dev;
+        u8 dma_alt_stat = 0, mask	= (hwif->channel) ? MRDMODE_INTR_CH1 :
+							    MRDMODE_INTR_CH0;
+	u8 dma_stat = hwif->INB(hwif->dma_status);
+
+	(void) pci_read_config_byte(dev, MRDMODE, &dma_alt_stat);
+#ifdef DEBUG
+	printk("%s: dma_stat: 0x%02x dma_alt_stat: "
+		"0x%02x mask: 0x%02x\n", drive->name,
+		dma_stat, dma_alt_stat, mask);
+#endif
+	if (!(dma_alt_stat & mask))
+		return 0;
+
+	/* return 1 if INTR asserted */
+	if ((dma_stat & 4) == 4)
+		return 1;
+
+	return 0;
+}
+
+/*
+ * ASUS P55T2P4D with CMD646 chipset revision 0x01 requires the old
+ * event order for DMA transfers.
+ */
+
+static int cmd646_1_ide_dma_end (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	u8 dma_stat = 0, dma_cmd = 0;
+
+	drive->waiting_for_dma = 0;
+	/* get DMA status */
+	dma_stat = hwif->INB(hwif->dma_status);
+	/* read DMA command state */
+	dma_cmd = hwif->INB(hwif->dma_command);
+	/* stop DMA */
+	hwif->OUTB((dma_cmd & ~1), hwif->dma_command);
+	/* clear the INTR & ERROR bits */
+	hwif->OUTB(dma_stat|6, hwif->dma_status);
+	/* and free any DMA resources */
+	ide_destroy_dmatable(drive);
+	/* verify good DMA status */
+	return (dma_stat & 7) != 4;
+}
+
+static unsigned int __init init_chipset_cmd64x (struct pci_dev *dev, const char *name)
+{
+	u32 class_rev = 0;
+	u8 mrdmode = 0;
+
+	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+	class_rev &= 0xff;
+
+#ifdef __i386__
+	if (dev->resource[PCI_ROM_RESOURCE].start) {
+		pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+		printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
+	}
+#endif
+
+	switch(dev->device) {
+		case PCI_DEVICE_ID_CMD_643:
+			break;
+		case PCI_DEVICE_ID_CMD_646:
+			printk("%s: chipset revision 0x%02X, ", name, class_rev);
+			switch(class_rev) {
+				case 0x07:
+				case 0x05:
+					printk("UltraDMA Capable");
+					break;
+				case 0x03:
+					printk("MultiWord DMA Force Limited");
+					break;
+				case 0x01:
+				default:
+					printk("MultiWord DMA Limited, IRQ workaround enabled");
+					break;
+				}
+			printk("\n");
+                        break;
+		case PCI_DEVICE_ID_CMD_648:
+		case PCI_DEVICE_ID_CMD_649:
+			break;
+		default:
+			break;
+	}
+
+	/* Set a good latency timer and cache line size value. */
+	(void) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
+#ifdef __sparc_v9__
+	(void) pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x10);
+#endif
+
+
+	/* Setup interrupts. */
+	(void) pci_read_config_byte(dev, MRDMODE, &mrdmode);
+	mrdmode &= ~(0x30);
+	(void) pci_write_config_byte(dev, MRDMODE, mrdmode);
+
+	/* Use MEMORY READ LINE for reads.
+	 * NOTE: Although not mentioned in the PCI0646U specs,
+	 *       these bits are write only and won't be read
+	 *       back as set or not.  The PCI0646U2 specs clarify
+	 *       this point.
+	 */
+	(void) pci_write_config_byte(dev, MRDMODE, mrdmode | 0x02);
+
+	/* Set reasonable active/recovery/address-setup values. */
+	(void) pci_write_config_byte(dev, ARTTIM0,  0x40);
+	(void) pci_write_config_byte(dev, DRWTIM0,  0x3f);
+	(void) pci_write_config_byte(dev, ARTTIM1,  0x40);
+	(void) pci_write_config_byte(dev, DRWTIM1,  0x3f);
+#ifdef __i386__
+	(void) pci_write_config_byte(dev, ARTTIM23, 0x1c);
+#else
+	(void) pci_write_config_byte(dev, ARTTIM23, 0x5c);
+#endif
+	(void) pci_write_config_byte(dev, DRWTIM23, 0x3f);
+	(void) pci_write_config_byte(dev, DRWTIM3,  0x3f);
+#ifdef CONFIG_PPC
+	(void) pci_write_config_byte(dev, UDIDETCR0, 0xf0);
+#endif /* CONFIG_PPC */
+
+#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
+
+	cmd_devs[n_cmd_devs++] = dev;
+
+	if (!cmd64x_proc) {
+		cmd64x_proc = 1;
+		ide_pci_register_host_proc(&cmd64x_procs[0]);
+	}
+#endif /* DISPLAY_CMD64X_TIMINGS && CONFIG_PROC_FS */
+
+	return 0;
+}
+
+static unsigned int __init ata66_cmd64x (ide_hwif_t *hwif)
+{
+	u8 ata66 = 0, mask = (hwif->channel) ? 0x02 : 0x01;
+
+	switch(hwif->pci_dev->device) {
+		case PCI_DEVICE_ID_CMD_643:
+		case PCI_DEVICE_ID_CMD_646:
+			return ata66;
+		default:
+			break;
+	}
+	pci_read_config_byte(hwif->pci_dev, BMIDECSR, &ata66);
+	return (ata66 & mask) ? 1 : 0;
+}
+
+static void __init init_hwif_cmd64x (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev	= hwif->pci_dev;
+	unsigned int class_rev;
+
+	hwif->autodma = 0;
+	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+	class_rev &= 0xff;
+
+	hwif->tuneproc  = &cmd64x_tuneproc;
+	hwif->speedproc = &cmd64x_tune_chipset;
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->atapi_dma = 1;
+
+	hwif->ultra_mask = 0x3f;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+	if (dev->device == PCI_DEVICE_ID_CMD_643)
+		hwif->ultra_mask = 0x80;
+	if (dev->device == PCI_DEVICE_ID_CMD_646)
+		hwif->ultra_mask = (class_rev > 0x04) ? 0x07 : 0x80;
+	if (dev->device == PCI_DEVICE_ID_CMD_648)
+		hwif->ultra_mask = 0x1f;
+
+	hwif->ide_dma_check = &cmd64x_config_drive_for_dma;
+	if (!(hwif->udma_four))
+		hwif->udma_four = ata66_cmd64x(hwif);
+
+	if (dev->device == PCI_DEVICE_ID_CMD_646) {
+		hwif->chipset = ide_cmd646;
+		if (class_rev == 0x01) {
+			hwif->ide_dma_end = &cmd646_1_ide_dma_end;
+		} else {
+			hwif->ide_dma_end = &cmd64x_ide_dma_end;
+			hwif->ide_dma_test_irq = &cmd64x_ide_dma_test_irq;
+		}
+	} else {
+		hwif->ide_dma_end = &cmd64x_ide_dma_end;
+		hwif->ide_dma_test_irq = &cmd64x_ide_dma_test_irq;
+	}
+
+
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+static void __init init_dma_cmd64x (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static int __devinit cmd64x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &cmd64x_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id cmd64x_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_643, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_648, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+	{ PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_649, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "CMD64x IDE",
+	.id_table	= cmd64x_pci_tbl,
+	.probe		= cmd64x_init_one,
+};
+
+static int cmd64x_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void cmd64x_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(cmd64x_ide_init);
+module_exit(cmd64x_ide_exit);
+
+MODULE_AUTHOR("Eddie Dost, David Miller, Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for CMD64x IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/cmd64x.h linux-2.4.21-pre6/drivers/ide/pci/cmd64x.h
--- linux-2.4.20/drivers/ide/pci/cmd64x.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/cmd64x.h	2003-03-26 23:49:26.000000000 +0000
@@ -0,0 +1,147 @@
+#ifndef CMD64X_H
+#define CMD64X_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_CMD64X_TIMINGS
+
+#define CMD_DEBUG 0
+
+#if CMD_DEBUG
+#define cmdprintk(x...)	printk(x)
+#else
+#define cmdprintk(x...)
+#endif
+
+#ifndef SPLIT_BYTE
+#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
+#endif
+
+/*
+ * CMD64x specific registers definition.
+ */
+#define CFR		0x50
+#define   CFR_INTR_CH0		0x02
+#define CNTRL		0x51
+#define	  CNTRL_DIS_RA0		0x40
+#define   CNTRL_DIS_RA1		0x80
+#define	  CNTRL_ENA_2ND		0x08
+
+#define	CMDTIM		0x52
+#define	ARTTIM0		0x53
+#define	DRWTIM0		0x54
+#define ARTTIM1 	0x55
+#define DRWTIM1		0x56
+#define ARTTIM23	0x57
+#define   ARTTIM23_DIS_RA2	0x04
+#define   ARTTIM23_DIS_RA3	0x08
+#define   ARTTIM23_INTR_CH1	0x10
+#define ARTTIM2		0x57
+#define ARTTIM3		0x57
+#define DRWTIM23	0x58
+#define DRWTIM2		0x58
+#define BRST		0x59
+#define DRWTIM3		0x5b
+
+#define BMIDECR0	0x70
+#define MRDMODE		0x71
+#define   MRDMODE_INTR_CH0	0x04
+#define   MRDMODE_INTR_CH1	0x08
+#define   MRDMODE_BLK_CH0	0x10
+#define   MRDMODE_BLK_CH1	0x20
+#define BMIDESR0	0x72
+#define UDIDETCR0	0x73
+#define DTPR0		0x74
+#define BMIDECR1	0x78
+#define BMIDECSR	0x79
+#define BMIDESR1	0x7A
+#define UDIDETCR1	0x7B
+#define DTPR1		0x7C
+
+#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 cmd64x_proc;
+
+static char * print_cmd64x_get_info(char *, struct pci_dev *, int);
+static int cmd64x_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t cmd64x_procs[] __initdata = {
+	{
+		.name		= "cmd64x",
+		.set		= 1,
+		.get_info	= cmd64x_get_info,
+		.parent		= NULL,
+	},
+};
+#endif  /* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static unsigned int init_chipset_cmd64x(struct pci_dev *, const char *);
+static void init_hwif_cmd64x(ide_hwif_t *);
+static void init_dma_cmd64x(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t cmd64x_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_CMD,
+		.device		= PCI_DEVICE_ID_CMD_643,
+		.name		= "CMD643",
+		.init_chipset	= init_chipset_cmd64x,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_cmd64x,
+		.init_dma	= init_dma_cmd64x,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 1 */
+		.vendor		= PCI_VENDOR_ID_CMD,
+		.device		= PCI_DEVICE_ID_CMD_646,
+		.name		= "CMD646",
+		.init_chipset	= init_chipset_cmd64x,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_cmd64x,
+		.init_dma	= init_dma_cmd64x,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x51,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 2 */
+		.vendor		= PCI_VENDOR_ID_CMD,
+		.device	= PCI_DEVICE_ID_CMD_648,
+		.name		= "CMD648",
+		.init_chipset	= init_chipset_cmd64x,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_cmd64x,
+		.init_dma	= init_dma_cmd64x,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= PCI_VENDOR_ID_CMD,
+		.device		= PCI_DEVICE_ID_CMD_649,
+		.name		= "CMD649",
+		.init_chipset	= init_chipset_cmd64x,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_cmd64x,
+		.init_dma	= init_dma_cmd64x,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 2,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* CMD64X_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/cs5530.c linux-2.4.21-pre6/drivers/ide/pci/cs5530.c
--- linux-2.4.20/drivers/ide/pci/cs5530.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/cs5530.c	2003-03-26 23:49:49.000000000 +0000
@@ -0,0 +1,463 @@
+/*
+ * linux/drivers/ide/pci/cs5530.c		Version 0.7	Sept 10, 2002
+ *
+ * Copyright (C) 2000			Andre Hedrick <andre@linux-ide.org>
+ * Ditto of GNU General Public License.
+ *
+ * Copyright (C) 2000			Mark Lord <mlord@pobox.com>
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ * Development of this chipset driver was funded
+ * by the nice folks at National Semiconductor.
+ *
+ * Documentation:
+ *	CS5530 documentation available from National Semiconductor.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+#include "cs5530.h"
+
+#if defined(DISPLAY_CS5530_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 cs5530_proc = 0;
+
+static struct pci_dev *bmide_dev;
+
+static int cs5530_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	unsigned long bibma = pci_resource_start(bmide_dev, 4);
+	u8  c0 = 0, c1 = 0;
+
+	/*
+	 * at that point bibma+0x2 et bibma+0xa are byte registers
+	 * to investigate:
+	 */
+
+	c0 = inb_p((u16)bibma + 0x02);
+	c1 = inb_p((u16)bibma + 0x0a);
+
+	p += sprintf(p, "\n                                "
+			"Cyrix 5530 Chipset.\n");
+	p += sprintf(p, "--------------- Primary Channel "
+			"---------------- Secondary Channel "
+			"-------------\n");
+	p += sprintf(p, "                %sabled "
+			"                        %sabled\n",
+			(c0&0x80) ? "dis" : " en",
+			(c1&0x80) ? "dis" : " en");
+	p += sprintf(p, "--------------- drive0 --------- drive1 "
+			"-------- drive0 ---------- drive1 ------\n");
+	p += sprintf(p, "DMA enabled:    %s              %s "
+			"            %s               %s\n",
+			(c0&0x20) ? "yes" : "no ",
+			(c0&0x40) ? "yes" : "no ",
+			(c1&0x20) ? "yes" : "no ",
+			(c1&0x40) ? "yes" : "no " );
+
+	p += sprintf(p, "UDMA\n");
+	p += sprintf(p, "DMA\n");
+	p += sprintf(p, "PIO\n");
+
+	return p-buffer;
+}
+#endif /* DISPLAY_CS5530_TIMINGS && CONFIG_PROC_FS */
+
+/**
+ *	cs5530_xfer_set_mode	-	set a new transfer mode at the drive
+ *	@drive: drive to tune
+ *	@mode: new mode
+ *
+ *	Logging wrapper to the IDE driver speed configuration. This can
+ *	probably go away now.
+ */
+ 
+static int cs5530_set_xfer_mode (ide_drive_t *drive, u8 mode)
+{
+	printk(KERN_DEBUG "%s: cs5530_set_xfer_mode(%s)\n",
+		drive->name, ide_xfer_verbose(mode));
+	return (ide_config_drive_speed(drive, mode));
+}
+
+/*
+ * Here are the standard PIO mode 0-4 timings for each "format".
+ * Format-0 uses fast data reg timings, with slower command reg timings.
+ * Format-1 uses fast timings for all registers, but won't work with all drives.
+ */
+static unsigned int cs5530_pio_timings[2][5] = {
+	{0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010},
+	{0xd1329172, 0x71212171, 0x30200080, 0x20102010, 0x00100010}
+};
+
+/*
+ * After chip reset, the PIO timings are set to 0x0000e132, which is not valid.
+ */
+#define CS5530_BAD_PIO(timings) (((timings)&~0x80000000)==0x0000e132)
+#define CS5530_BASEREG(hwif)	(((hwif)->dma_base & ~0xf) + ((hwif)->channel ? 0x30 : 0x20))
+
+/**
+ *	cs5530_tuneproc		-	select/set PIO modes
+ *
+ *	cs5530_tuneproc() handles selection/setting of PIO modes
+ *	for both the chipset and drive.
+ *
+ *	The ide_init_cs5530() routine guarantees that all drives
+ *	will have valid default PIO timings set up before we get here.
+ */
+
+static void cs5530_tuneproc (ide_drive_t *drive, u8 pio)	/* pio=255 means "autotune" */
+{
+	ide_hwif_t	*hwif = HWIF(drive);
+	unsigned int	format;
+	unsigned long basereg = CS5530_BASEREG(hwif);
+	static u8	modes[5] = { XFER_PIO_0, XFER_PIO_1, XFER_PIO_2, XFER_PIO_3, XFER_PIO_4};
+
+	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+	if (!cs5530_set_xfer_mode(drive, modes[pio])) {
+		format = (hwif->INL(basereg+4) >> 31) & 1;
+		hwif->OUTL(cs5530_pio_timings[format][pio],
+			basereg+(drive->select.b.unit<<3));
+	}
+}
+
+/**
+ *	cs5530_config_dma	-	select/set DMA and UDMA modes
+ *	@drive: drive to tune
+ *
+ *	cs5530_config_dma() handles selection/setting of DMA/UDMA modes
+ *	for both the chipset and drive. The CS5530 has limitations about
+ *	mixing DMA/UDMA on the same cable.
+ */
+ 
+static int cs5530_config_dma (ide_drive_t *drive)
+{
+	int			udma_ok = 1, mode = 0;
+	ide_hwif_t		*hwif = HWIF(drive);
+	int			unit = drive->select.b.unit;
+	ide_drive_t		*mate = &hwif->drives[unit^1];
+	struct hd_driveid	*id = drive->id;
+	unsigned int		reg, timings;
+	unsigned long		basereg;
+
+	/*
+	 * Default to DMA-off in case we run into trouble here.
+	 */
+	hwif->ide_dma_off_quietly(drive);
+	/* turn off DMA while we fiddle */
+	hwif->ide_dma_host_off(drive);
+	/* clear DMA_capable bit */
+
+	/*
+	 * The CS5530 specifies that two drives sharing a cable cannot
+	 * mix UDMA/MDMA.  It has to be one or the other, for the pair,
+	 * though different timings can still be chosen for each drive.
+	 * We could set the appropriate timing bits on the fly,
+	 * but that might be a bit confusing.  So, for now we statically
+	 * handle this requirement by looking at our mate drive to see
+	 * what it is capable of, before choosing a mode for our own drive.
+	 *
+	 * Note: This relies on the fact we never fail from UDMA to MWDMA_2
+	 * but instead drop to PIO
+	 */
+	if (mate->present) {
+		struct hd_driveid *mateid = mate->id;
+		if (mateid && (mateid->capability & 1) &&
+		    !hwif->ide_dma_bad_drive(mate)) {
+			if ((mateid->field_valid & 4) &&
+			    (mateid->dma_ultra & 7))
+				udma_ok = 1;
+			else if ((mateid->field_valid & 2) &&
+				 (mateid->dma_mword & 7))
+				udma_ok = 0;
+			else
+				udma_ok = 1;
+		}
+	}
+
+	/*
+	 * Now see what the current drive is capable of,
+	 * selecting UDMA only if the mate said it was ok.
+	 */
+	if (id && (id->capability & 1) && drive->autodma &&
+	    !hwif->ide_dma_bad_drive(drive)) {
+		if (udma_ok && (id->field_valid & 4) && (id->dma_ultra & 7)) {
+			if      (id->dma_ultra & 4)
+				mode = XFER_UDMA_2;
+			else if (id->dma_ultra & 2)
+				mode = XFER_UDMA_1;
+			else if (id->dma_ultra & 1)
+				mode = XFER_UDMA_0;
+		}
+		if (!mode && (id->field_valid & 2) && (id->dma_mword & 7)) {
+			if      (id->dma_mword & 4)
+				mode = XFER_MW_DMA_2;
+			else if (id->dma_mword & 2)
+				mode = XFER_MW_DMA_1;
+			else if (id->dma_mword & 1)
+				mode = XFER_MW_DMA_0;
+		}
+	}
+
+	/*
+	 * Tell the drive to switch to the new mode; abort on failure.
+	 */
+	if (!mode || cs5530_set_xfer_mode(drive, mode))
+		return 1;	/* failure */
+
+	/*
+	 * Now tune the chipset to match the drive:
+	 */
+	switch (mode) {
+		case XFER_UDMA_0:	timings = 0x00921250; break;
+		case XFER_UDMA_1:	timings = 0x00911140; break;
+		case XFER_UDMA_2:	timings = 0x00911030; break;
+		case XFER_MW_DMA_0:	timings = 0x00077771; break;
+		case XFER_MW_DMA_1:	timings = 0x00012121; break;
+		case XFER_MW_DMA_2:	timings = 0x00002020; break;
+		default:
+			printk(KERN_ERR "%s: cs5530_config_dma: huh? mode=%02x\n",
+				drive->name, mode);
+			return 1;	/* failure */
+	}
+	basereg = CS5530_BASEREG(hwif);
+	reg = hwif->INL(basereg+4);		/* get drive0 config register */
+	timings |= reg & 0x80000000;		/* preserve PIO format bit */
+	if (unit == 0) {			/* are we configuring drive0? */
+		hwif->OUTL(timings, basereg+4);	/* write drive0 config register */
+	} else {
+		if (timings & 0x00100000)
+			reg |=  0x00100000;	/* enable UDMA timings for both drives */
+		else
+			reg &= ~0x00100000;	/* disable UDMA timings for both drives */
+		hwif->OUTL(reg,     basereg+4);	/* write drive0 config register */
+		hwif->OUTL(timings, basereg+12);	/* write drive1 config register */
+	}
+	(void) hwif->ide_dma_host_on(drive);
+	/* set DMA_capable bit */
+
+	/*
+	 * Finally, turn DMA on in software, and exit.
+	 */
+	return hwif->ide_dma_on(drive);	/* success */
+}
+
+/**
+ *	init_chipset_5530	-	set up 5530 bridge
+ *	@dev: PCI device
+ *	@name: device name
+ *
+ *	Initialize the cs5530 bridge for reliable IDE DMA operation.
+ */
+
+static unsigned int __init init_chipset_cs5530 (struct pci_dev *dev, const char *name)
+{
+	struct pci_dev *master_0 = NULL, *cs5530_0 = NULL;
+	unsigned long flags;
+
+#if defined(DISPLAY_CS5530_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!cs5530_proc) {
+		cs5530_proc = 1;
+		bmide_dev = dev;
+		ide_pci_register_host_proc(&cs5530_procs[0]);
+	}
+#endif /* DISPLAY_CS5530_TIMINGS && CONFIG_PROC_FS */
+
+	pci_for_each_dev (dev) {
+		if (dev->vendor == PCI_VENDOR_ID_CYRIX) {
+			switch (dev->device) {
+				case PCI_DEVICE_ID_CYRIX_PCI_MASTER:
+					master_0 = dev;
+					break;
+				case PCI_DEVICE_ID_CYRIX_5530_LEGACY:
+					cs5530_0 = dev;
+					break;
+			}
+		}
+	}
+	if (!master_0) {
+		printk(KERN_ERR "%s: unable to locate PCI MASTER function\n", name);
+		return 0;
+	}
+	if (!cs5530_0) {
+		printk(KERN_ERR "%s: unable to locate CS5530 LEGACY function\n", name);
+		return 0;
+	}
+
+	spin_lock_irqsave(&ide_lock, flags);
+		/* all CPUs (there should only be one CPU with this chipset) */
+
+	/*
+	 * Enable BusMaster and MemoryWriteAndInvalidate for the cs5530:
+	 * -->  OR 0x14 into 16-bit PCI COMMAND reg of function 0 of the cs5530
+	 */
+
+	pci_set_master(cs5530_0);
+	pci_set_mwi(cs5530_0);
+
+	/*
+	 * Set PCI CacheLineSize to 16-bytes:
+	 * --> Write 0x04 into 8-bit PCI CACHELINESIZE reg of function 0 of the cs5530
+	 */
+
+	pci_write_config_byte(cs5530_0, PCI_CACHE_LINE_SIZE, 0x04);
+
+	/*
+	 * Disable trapping of UDMA register accesses (Win98 hack):
+	 * --> Write 0x5006 into 16-bit reg at offset 0xd0 of function 0 of the cs5530
+	 */
+
+	pci_write_config_word(cs5530_0, 0xd0, 0x5006);
+
+	/*
+	 * Bit-1 at 0x40 enables MemoryWriteAndInvalidate on internal X-bus:
+	 * The other settings are what is necessary to get the register
+	 * into a sane state for IDE DMA operation.
+	 */
+
+	pci_write_config_byte(master_0, 0x40, 0x1e);
+
+	/* 
+	 * Set max PCI burst size (16-bytes seems to work best):
+	 *	   16bytes: set bit-1 at 0x41 (reg value of 0x16)
+	 *	all others: clear bit-1 at 0x41, and do:
+	 *	  128bytes: OR 0x00 at 0x41
+	 *	  256bytes: OR 0x04 at 0x41
+	 *	  512bytes: OR 0x08 at 0x41
+	 *	 1024bytes: OR 0x0c at 0x41
+	 */
+
+	pci_write_config_byte(master_0, 0x41, 0x14);
+
+	/*
+	 * These settings are necessary to get the chip
+	 * into a sane state for IDE DMA operation.
+	 */
+
+	pci_write_config_byte(master_0, 0x42, 0x00);
+	pci_write_config_byte(master_0, 0x43, 0xc1);
+
+	spin_unlock_irqrestore(&ide_lock, flags);
+
+	return 0;
+}
+
+/**
+ *	init_hwif_cs5530	-	initialise an IDE channel
+ *	@hwif: IDE to initialize
+ *
+ *	This gets invoked by the IDE driver once for each channel. It
+ *	performs channel-specific pre-initialization before drive probing.
+ */
+
+static void __init init_hwif_cs5530 (ide_hwif_t *hwif)
+{
+	unsigned long basereg;
+	u32 d0_timings;
+	hwif->autodma = 0;
+
+	if (hwif->mate)
+		hwif->serialized = hwif->mate->serialized = 1;
+
+	hwif->tuneproc = &cs5530_tuneproc;
+	basereg = CS5530_BASEREG(hwif);
+	d0_timings = hwif->INL(basereg+0);
+	if (CS5530_BAD_PIO(d0_timings)) {
+		/* PIO timings not initialized? */
+		hwif->OUTL(cs5530_pio_timings[(d0_timings>>31)&1][0], basereg+0);
+		if (!hwif->drives[0].autotune)
+			hwif->drives[0].autotune = 1;
+			/* needs autotuning later */
+	}
+	if (CS5530_BAD_PIO(hwif->INL(basereg+8))) {
+	/* PIO timings not initialized? */
+		hwif->OUTL(cs5530_pio_timings[(d0_timings>>31)&1][0], basereg+8);
+		if (!hwif->drives[1].autotune)
+			hwif->drives[1].autotune = 1;
+			/* needs autotuning later */
+	}
+
+	hwif->atapi_dma = 1;
+	hwif->ultra_mask = 0x07;
+	hwif->mwdma_mask = 0x07;
+
+	hwif->ide_dma_check = &cs5530_config_dma;
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+/**
+ *	init_dma_cs5530		-	set up for DMA
+ *	@hwif: interface
+ *	@dmabase: DMA base address
+ *
+ *	FIXME: this can go away
+ */
+ 
+static void __init init_dma_cs5530 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+
+static int __devinit cs5530_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &cs5530_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id cs5530_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "CS5530 IDE",
+	.id_table	= cs5530_pci_tbl,
+	.probe		= cs5530_init_one,
+};
+
+static int cs5530_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void cs5530_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(cs5530_ide_init);
+module_exit(cs5530_ide_exit);
+
+MODULE_AUTHOR("Mark Lord");
+MODULE_DESCRIPTION("PCI driver module for Cyrix/NS 5530 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/cs5530.h linux-2.4.21-pre6/drivers/ide/pci/cs5530.h
--- linux-2.4.20/drivers/ide/pci/cs5530.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/cs5530.h	2003-03-26 23:48:59.000000000 +0000
@@ -0,0 +1,54 @@
+#ifndef CS5530_H
+#define CS5530_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_CS5530_TIMINGS
+
+#if defined(DISPLAY_CS5530_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 cs5530_proc;
+
+static int cs5530_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t cs5530_procs[] __initdata = {
+	{
+		.name		= "cs5530",
+		.set		= 1,
+		.get_info	= cs5530_get_info,
+		.parent		= NULL,
+	},
+};
+#endif /* DISPLAY_CS5530_TIMINGS && CONFIG_PROC_FS */
+
+static unsigned int init_chipset_cs5530(struct pci_dev *, const char *);
+static void init_hwif_cs5530(ide_hwif_t *);
+static void init_dma_cs5530(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t cs5530_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_CYRIX,
+		.device		= PCI_DEVICE_ID_CYRIX_5530_IDE,
+		.name		= "CS5530",
+		.init_chipset	= init_chipset_cs5530,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_cs5530,
+		.init_dma	= init_dma_cs5530,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* CS5530_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/cy82c693.c linux-2.4.21-pre6/drivers/ide/pci/cy82c693.c
--- linux-2.4.20/drivers/ide/pci/cy82c693.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/cy82c693.c	2003-03-26 23:49:19.000000000 +0000
@@ -0,0 +1,470 @@
+/*
+ * linux/drivers/ide/pci/cy82c693.c		Version 0.40	Sep. 10, 2002
+ *
+ *  Copyright (C) 1998-2000 Andreas S. Krebs (akrebs@altavista.net), Maintainer
+ *  Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org>, Integrater
+ *
+ * CYPRESS CY82C693 chipset IDE controller
+ *
+ * The CY82C693 chipset is used on Digital's PC-Alpha 164SX boards.
+ * Writting the driver was quite simple, since most of the job is
+ * done by the generic pci-ide support. 
+ * The hard part was finding the CY82C693's datasheet on Cypress's
+ * web page :-(. But Altavista solved this problem :-).
+ *
+ *
+ * Notes:
+ * - I recently got a 16.8G IBM DTTA, so I was able to test it with
+ *   a large and fast disk - the results look great, so I'd say the
+ *   driver is working fine :-)
+ *   hdparm -t reports 8.17 MB/sec at about 6% CPU usage for the DTTA 
+ * - this is my first linux driver, so there's probably a lot  of room 
+ *   for optimizations and bug fixing, so feel free to do it.
+ * - use idebus=xx parameter to set PCI bus speed - needed to calc
+ *   timings for PIO modes (default will be 40)
+ * - if using PIO mode it's a good idea to set the PIO mode and 
+ *   32-bit I/O support (if possible), e.g. hdparm -p2 -c1 /dev/hda
+ * - I had some problems with my IBM DHEA with PIO modes < 2
+ *   (lost interrupts) ?????
+ * - first tests with DMA look okay, they seem to work, but there is a
+ *   problem with sound - the BusMaster IDE TimeOut should fixed this
+ *
+ * Ancient History:
+ * AMH@1999-08-24: v0.34 init_cy82c693_chip moved to pci_init_cy82c693
+ * ASK@1999-01-23: v0.33 made a few minor code clean ups
+ *                       removed DMA clock speed setting by default
+ *                       added boot message
+ * ASK@1998-11-01: v0.32 added support to set BusMaster IDE TimeOut
+ *                       added support to set DMA Controller Clock Speed
+ * ASK@1998-10-31: v0.31 fixed problem with setting to high DMA modes
+ *                       on some drives.
+ * ASK@1998-10-29: v0.3 added support to set DMA modes
+ * ASK@1998-10-28: v0.2 added support to set PIO modes
+ * ASK@1998-10-27: v0.1 first version - chipset detection
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "ide_modes.h"
+#include "cy82c693.h"
+
+/*
+ * calc clocks using bus_speed
+ * returns (rounded up) time in bus clocks for time in ns
+ */
+static int calc_clk (int time, int bus_speed)
+{
+	int clocks;
+
+	clocks = (time*bus_speed+999)/1000 -1;
+
+	if (clocks < 0)
+		clocks = 0;
+
+	if (clocks > 0x0F)
+		clocks = 0x0F;
+
+	return clocks;
+}
+
+/*
+ * compute the values for the clock registers for PIO
+ * mode and pci_clk [MHz] speed
+ *
+ * NOTE: for mode 0,1 and 2 drives 8-bit IDE command control registers are used
+ *       for mode 3 and 4 drives 8 and 16-bit timings are the same
+ *
+ */ 
+static void compute_clocks (u8 pio, pio_clocks_t *p_pclk)
+{
+	int clk1, clk2;
+	int bus_speed = system_bus_clock();	/* get speed of PCI bus */
+
+	/* we don't check against CY82C693's min and max speed,
+	 * so you can play with the idebus=xx parameter
+	 */
+
+	if (pio > CY82C693_MAX_PIO)
+		pio = CY82C693_MAX_PIO;
+
+	/* let's calc the address setup time clocks */
+	p_pclk->address_time = (u8)calc_clk(ide_pio_timings[pio].setup_time, bus_speed);
+
+	/* let's calc the active and recovery time clocks */
+	clk1 = calc_clk(ide_pio_timings[pio].active_time, bus_speed);
+
+	/* calc recovery timing */
+	clk2 =	ide_pio_timings[pio].cycle_time -
+		ide_pio_timings[pio].active_time -
+		ide_pio_timings[pio].setup_time;
+
+	clk2 = calc_clk(clk2, bus_speed);
+
+	clk1 = (clk1<<4)|clk2;	/* combine active and recovery clocks */
+
+	/* note: we use the same values for 16bit IOR and IOW
+         *	those are all the same, since I don't have other
+	 *	timings than those from ide_modes.h
+	 */
+
+	p_pclk->time_16r = (u8)clk1;
+	p_pclk->time_16w = (u8)clk1;
+
+	/* what are good values for 8bit ?? */
+	p_pclk->time_8 = (u8)clk1;
+}
+
+/*
+ * set DMA mode a specific channel for CY82C693
+ */
+
+static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
+{
+	u8 index = 0, data = 0;
+
+	if (mode>2)	/* make sure we set a valid mode */
+		mode = 2;
+			   
+	if (mode > drive->id->tDMA)  /* to be absolutly sure we have a valid mode */
+		mode = drive->id->tDMA;
+	
+	index = (HWIF(drive)->channel==0) ? CY82_INDEX_CHANNEL0 : CY82_INDEX_CHANNEL1;
+
+#if CY82C693_DEBUG_LOGS
+	/* for debug let's show the previous values */
+
+	HWIF(drive)->OUTB(index, CY82_INDEX_PORT);
+	data = HWIF(drive)->INB(CY82_DATA_PORT);
+
+	printk (KERN_INFO "%s (ch=%d, dev=%d): DMA mode is %d (single=%d)\n",
+		drive->name, HWIF(drive)->channel, drive->select.b.unit,
+		(data&0x3), ((data>>2)&1));
+#endif /* CY82C693_DEBUG_LOGS */
+
+	data = (u8)mode|(u8)(single<<2);
+
+	HWIF(drive)->OUTB(index, CY82_INDEX_PORT);
+	HWIF(drive)->OUTB(data, CY82_DATA_PORT);
+
+#if CY82C693_DEBUG_INFO
+	printk(KERN_INFO "%s (ch=%d, dev=%d): set DMA mode to %d (single=%d)\n",
+		drive->name, HWIF(drive)->channel, drive->select.b.unit,
+		mode, single);
+#endif /* CY82C693_DEBUG_INFO */
+
+	/* 
+	 * note: below we set the value for Bus Master IDE TimeOut Register
+	 * I'm not absolutly sure what this does, but it solved my problem
+	 * with IDE DMA and sound, so I now can play sound and work with
+	 * my IDE driver at the same time :-)
+	 *
+	 * If you know the correct (best) value for this register please
+	 * let me know - ASK
+	 */
+
+	data = BUSMASTER_TIMEOUT;
+	HWIF(drive)->OUTB(CY82_INDEX_TIMEOUT, CY82_INDEX_PORT);
+	HWIF(drive)->OUTB(data, CY82_DATA_PORT);
+
+#if CY82C693_DEBUG_INFO	
+	printk (KERN_INFO "%s: Set IDE Bus Master TimeOut Register to 0x%X\n",
+		drive->name, data);
+#endif /* CY82C693_DEBUG_INFO */
+}
+
+/* 
+ * used to set DMA mode for CY82C693 (single and multi modes)
+ */
+int cy82c693_ide_dma_on (ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
+
+#if CY82C693_DEBUG_INFO
+	printk (KERN_INFO "dma_on: %s\n", drive->name);
+#endif /* CY82C693_DEBUG_INFO */
+
+	if (id != NULL) {		
+		/* Enable DMA on any drive that has DMA
+		 * (multi or single) enabled
+		 */
+		if (id->field_valid & 2) {	/* regular DMA */
+			int mmode, smode;
+
+			mmode = id->dma_mword & (id->dma_mword >> 8);
+			smode = id->dma_1word & (id->dma_1word >> 8);
+			       		      
+			if (mmode != 0) {
+				/* enable multi */
+				cy82c693_dma_enable(drive, (mmode >> 1), 0);
+			} else if (smode != 0) {
+				/* enable single */
+				cy82c693_dma_enable(drive, (smode >> 1), 1);
+			}
+		}
+	}
+        return __ide_dma_on(drive);
+}
+
+/*
+ * tune ide drive - set PIO mode
+ */
+static void cy82c693_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	struct pci_dev *dev = hwif->pci_dev;
+	pio_clocks_t pclk;
+	unsigned int addrCtrl;
+
+	/* select primary or secondary channel */
+	if (hwif->index > 0) {  /* drive is on the secondary channel */
+		dev = pci_find_slot(dev->bus->number, dev->devfn+1);
+		if (!dev) {
+			printk(KERN_ERR "%s: tune_drive: "
+				"Cannot find secondary interface!\n",
+				drive->name);
+			return;
+		}
+	}
+
+#if CY82C693_DEBUG_LOGS
+	/* for debug let's show the register values */
+	
+       	if (drive->select.b.unit == 0) {
+		/*
+		 * get master drive registers               	
+		 * address setup control register
+		 * is 32 bit !!!
+		 */ 
+	  	pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);                
+		addrCtrl &= 0x0F;
+
+		/* now let's get the remaining registers */
+		pci_read_config_byte(dev, CY82_IDE_MASTER_IOR, &pclk.time_16r);
+		pci_read_config_byte(dev, CY82_IDE_MASTER_IOW, &pclk.time_16w);
+		pci_read_config_byte(dev, CY82_IDE_MASTER_8BIT, &pclk.time_8);
+	} else {
+		/*
+		 * set slave drive registers
+		 * address setup control register
+		 * is 32 bit !!!
+		 */ 
+		pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
+
+		addrCtrl &= 0xF0;
+		addrCtrl >>= 4;
+
+		/* now let's get the remaining registers */
+		pci_read_config_byte(dev, CY82_IDE_SLAVE_IOR, &pclk.time_16r);
+		pci_read_config_byte(dev, CY82_IDE_SLAVE_IOW, &pclk.time_16w);
+		pci_read_config_byte(dev, CY82_IDE_SLAVE_8BIT, &pclk.time_8);
+	}
+
+	printk(KERN_INFO "%s (ch=%d, dev=%d): PIO timing is "
+		"(addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n",
+		drive->name, hwif->channel, drive->select.b.unit,
+		addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
+#endif /* CY82C693_DEBUG_LOGS */
+
+	/* first let's calc the pio modes */
+	pio = ide_get_best_pio_mode(drive, pio, CY82C693_MAX_PIO, NULL);
+
+#if CY82C693_DEBUG_INFO
+	printk (KERN_INFO "%s: Selected PIO mode %d\n", drive->name, pio);
+#endif /* CY82C693_DEBUG_INFO */
+
+	/* let's calc the values for this PIO mode */
+	compute_clocks(pio, &pclk);
+
+	/* now let's write  the clocks registers */
+	if (drive->select.b.unit == 0) {
+		/*
+		 * set master drive
+		 * address setup control register
+		 * is 32 bit !!!
+		 */ 
+		pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
+		
+		addrCtrl &= (~0xF);
+		addrCtrl |= (unsigned int)pclk.address_time;
+		pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl);
+
+		/* now let's set the remaining registers */
+		pci_write_config_byte(dev, CY82_IDE_MASTER_IOR, pclk.time_16r);
+		pci_write_config_byte(dev, CY82_IDE_MASTER_IOW, pclk.time_16w);
+		pci_write_config_byte(dev, CY82_IDE_MASTER_8BIT, pclk.time_8);
+		
+		addrCtrl &= 0xF;
+	} else {
+		/*
+		 * set slave drive
+		 * address setup control register
+		 * is 32 bit !!!
+		 */ 
+		pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
+
+		addrCtrl &= (~0xF0);
+		addrCtrl |= ((unsigned int)pclk.address_time<<4);
+		pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl);
+
+		/* now let's set the remaining registers */
+		pci_write_config_byte(dev, CY82_IDE_SLAVE_IOR, pclk.time_16r);
+		pci_write_config_byte(dev, CY82_IDE_SLAVE_IOW, pclk.time_16w);
+		pci_write_config_byte(dev, CY82_IDE_SLAVE_8BIT, pclk.time_8);
+
+		addrCtrl >>= 4;
+		addrCtrl &= 0xF;
+	}	
+
+#if CY82C693_DEBUG_INFO
+	printk(KERN_INFO "%s (ch=%d, dev=%d): set PIO timing to "
+		"(addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n",
+		drive->name, hwif->channel, drive->select.b.unit,
+		addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
+#endif /* CY82C693_DEBUG_INFO */
+}
+
+/*
+ * this function is called during init and is used to setup the cy82c693 chip
+ */
+unsigned int __init init_chipset_cy82c693(struct pci_dev *dev, const char *name)
+{
+	if (PCI_FUNC(dev->devfn) != 1)
+		return 0;
+
+#ifdef CY82C693_SETDMA_CLOCK
+	u8 data = 0;
+#endif /* CY82C693_SETDMA_CLOCK */ 
+
+	/* write info about this verion of the driver */
+	printk(KERN_INFO CY82_VERSION "\n");
+
+#ifdef CY82C693_SETDMA_CLOCK
+       /* okay let's set the DMA clock speed */
+        
+        outb(CY82_INDEX_CTRLREG1, CY82_INDEX_PORT);
+        data = inb(CY82_DATA_PORT);
+
+#if CY82C693_DEBUG_INFO
+	printk(KERN_INFO "%s: Peripheral Configuration Register: 0x%X\n",
+		name, data);
+#endif /* CY82C693_DEBUG_INFO */
+
+        /*
+	 * for some reason sometimes the DMA controller
+	 * speed is set to ATCLK/2 ???? - we fix this here
+	 * 
+	 * note: i don't know what causes this strange behaviour,
+	 *       but even changing the dma speed doesn't solve it :-(
+	 *       the ide performance is still only half the normal speed 
+	 * 
+	 *       if anybody knows what goes wrong with my machine, please
+	 *       let me know - ASK
+         */
+
+	data |= 0x03;
+
+        outb(CY82_INDEX_CTRLREG1, CY82_INDEX_PORT);
+        outb(data, CY82_DATA_PORT);
+
+#if CY82C693_DEBUG_INFO
+	printk (KERN_INFO "%s: New Peripheral Configuration Register: 0x%X\n",
+		name, data);
+#endif /* CY82C693_DEBUG_INFO */
+
+#endif /* CY82C693_SETDMA_CLOCK */
+	return 0;
+}
+
+/*
+ * the init function - called for each ide channel once
+ */
+void __init init_hwif_cy82c693(ide_hwif_t *hwif)
+{
+	hwif->autodma = 0;
+
+	hwif->chipset = ide_cy82c693;
+	hwif->tuneproc = &cy82c693_tune_drive;
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->atapi_dma = 1;
+	hwif->mwdma_mask = 0x04;
+	hwif->swdma_mask = 0x04;
+
+	hwif->ide_dma_on = &cy82c693_ide_dma_on;
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+static __initdata ide_hwif_t *primary;
+
+void __init init_iops_cy82c693(ide_hwif_t *hwif)
+{
+	if (PCI_FUNC(hwif->pci_dev->devfn) == 1)
+		primary = hwif;
+	else {
+		hwif->mate = primary;
+		hwif->channel = 1;
+	}
+}
+
+static int __devinit cy82c693_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &cy82c693_chipsets[id->driver_data];
+	struct pci_dev *dev2;
+
+	/* CY82C693 is more than only a IDE controller.
+	   Function 1 is primary IDE channel, function 2 - secondary. */
+        if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE &&
+	    PCI_FUNC(dev->devfn) == 1) {
+		dev2 = pci_find_slot(dev->bus->number, dev->devfn + 1);
+		ide_setup_pci_devices(dev, dev2, d);
+	}
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id cy82c693_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "Cypress IDE",
+	.id_table	= cy82c693_pci_tbl,
+	.probe		= cy82c693_init_one,
+};
+
+static int cy82c693_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void cy82c693_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(cy82c693_ide_init);
+module_exit(cy82c693_ide_exit);
+
+MODULE_AUTHOR("Andreas Krebs, Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for the Cypress CY82C693 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/cy82c693.h linux-2.4.21-pre6/drivers/ide/pci/cy82c693.h
--- linux-2.4.20/drivers/ide/pci/cy82c693.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/cy82c693.h	2003-03-26 23:49:40.000000000 +0000
@@ -0,0 +1,93 @@
+#ifndef CY82C693_H
+#define CY82C693_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+/* the current version */
+#define CY82_VERSION	"CY82C693U driver v0.34 99-13-12 Andreas S. Krebs (akrebs@altavista.net)"
+
+/*
+ *	The following are used to debug the driver.
+ */
+#define	CY82C693_DEBUG_LOGS	0
+#define	CY82C693_DEBUG_INFO	0
+
+/* define CY82C693_SETDMA_CLOCK to set DMA Controller Clock Speed to ATCLK */
+#undef CY82C693_SETDMA_CLOCK
+
+/*
+ *	NOTE: the value for busmaster timeout is tricky and I got it by
+ *	 trial and error!  By using a to low value will cause DMA timeouts
+ *	 and drop IDE performance, and by using a to high value will cause
+ *	 audio playback to scatter.
+ *	 If you know a better value or how to calc it, please let me know.
+ */
+
+/* twice the value written in cy82c693ub datasheet */
+#define BUSMASTER_TIMEOUT	0x50
+/*
+ * the value above was tested on my machine and it seems to work okay
+ */
+
+/* here are the offset definitions for the registers */
+#define CY82_IDE_CMDREG		0x04
+#define CY82_IDE_ADDRSETUP	0x48
+#define CY82_IDE_MASTER_IOR	0x4C	
+#define CY82_IDE_MASTER_IOW	0x4D	
+#define CY82_IDE_SLAVE_IOR	0x4E	
+#define CY82_IDE_SLAVE_IOW	0x4F
+#define CY82_IDE_MASTER_8BIT	0x50	
+#define CY82_IDE_SLAVE_8BIT	0x51	
+
+#define CY82_INDEX_PORT		0x22
+#define CY82_DATA_PORT		0x23
+
+#define CY82_INDEX_CTRLREG1	0x01
+#define CY82_INDEX_CHANNEL0	0x30
+#define CY82_INDEX_CHANNEL1	0x31
+#define CY82_INDEX_TIMEOUT	0x32
+
+/* the max PIO mode - from datasheet */
+#define CY82C693_MAX_PIO	4
+
+/* the min and max PCI bus speed in MHz - from datasheet */
+#define CY82C963_MIN_BUS_SPEED	25
+#define CY82C963_MAX_BUS_SPEED	33
+
+/* the struct for the PIO mode timings */
+typedef struct pio_clocks_s {
+        u8	address_time;	/* Address setup (clocks) */
+	u8	time_16r;	/* clocks for 16bit IOR (0xF0=Active/data, 0x0F=Recovery) */
+	u8	time_16w;	/* clocks for 16bit IOW (0xF0=Active/data, 0x0F=Recovery) */
+	u8	time_8;		/* clocks for 8bit (0xF0=Active/data, 0x0F=Recovery) */
+} pio_clocks_t;
+
+extern unsigned int init_chipset_cy82c693(struct pci_dev *, const char *);
+extern void init_hwif_cy82c693(ide_hwif_t *);
+extern void init_iops_cy82c693(ide_hwif_t *);
+
+static ide_pci_device_t cy82c693_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_CONTAQ,
+		.device		= PCI_DEVICE_ID_CONTAQ_82C693,
+		.name		= "CY82C693",
+		.init_chipset	= init_chipset_cy82c693,
+		.init_iops	= init_iops_cy82c693,
+		.init_hwif	= init_hwif_cy82c693,
+		.init_dma	= NULL,
+		.channels	= 1,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* CY82C693_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/generic.c linux-2.4.21-pre6/drivers/ide/pci/generic.c
--- linux-2.4.20/drivers/ide/pci/generic.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/generic.c	2003-03-26 23:49:25.000000000 +0000
@@ -0,0 +1,169 @@
+/*
+ *  linux/drivers/ide/pci/generic.c	Version 0.11	December 30, 2002
+ *
+ *  Copyright (C) 2001-2002	Andre Hedrick <andre@linux-ide.org>
+ *  Portions (C) Copyright 2002  Red Hat Inc <alan@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, 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.
+ *
+ * For the avoidance of doubt the "preferred form" of this code is one which
+ * is in an open non patent encumbered format. Where cryptographic key signing
+ * forms part of the process of creating an executable the information
+ * including keys needed to generate an equivalently functional executable
+ * are deemed to be part of the source code.
+ */
+
+#undef REALLY_SLOW_IO		/* most systems can safely undef this */
+
+#include <linux/config.h> /* for CONFIG_BLK_DEV_IDEPCI */
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "generic.h"
+
+static unsigned int __init init_chipset_generic (struct pci_dev *dev, const char *name)
+{
+	return 0;
+}
+
+static void __init init_hwif_generic (ide_hwif_t *hwif)
+{
+	switch(hwif->pci_dev->device) {
+		case PCI_DEVICE_ID_UMC_UM8673F:
+		case PCI_DEVICE_ID_UMC_UM8886A:
+		case PCI_DEVICE_ID_UMC_UM8886BF:
+			hwif->irq = hwif->channel ? 15 : 14;
+			break;
+		default:
+			break;
+	}
+
+	if (!(hwif->dma_base))
+		return;
+
+	hwif->atapi_dma = 1;
+	hwif->ultra_mask = 0x7f;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+static void init_dma_generic (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+#if 0
+
+	/* Logic to add back later on */
+	
+	if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
+		ide_pci_device_t *unknown = unknown_chipset;
+//		unknown->vendor = dev->vendor;
+//		unknown->device = dev->device;
+		init_setup_unknown(dev, unknown);
+		return 1;
+	}
+	return 0;
+#endif	
+
+/**
+ *	generic_init_one	-	called when a PIIX is found
+ *	@dev: the generic device
+ *	@id: the matching pci id
+ *
+ *	Called when the PCI registration layer (or the IDE initialization)
+ *	finds a device matching our IDE device tables.
+ */
+ 
+static int __devinit generic_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &generic_chipsets[id->driver_data];
+	u16 command;
+
+	if (dev->device != d->device)
+		BUG();
+	if ((d->vendor == PCI_VENDOR_ID_UMC) &&
+	    (d->device == PCI_DEVICE_ID_UMC_UM8886A) &&
+	    (!(PCI_FUNC(dev->devfn) & 1)))
+		return 1; /* UM8886A/BF pair */
+
+	if ((d->vendor == PCI_VENDOR_ID_OPTI) &&
+	    (d->device == PCI_DEVICE_ID_OPTI_82C558) &&
+	    (!(PCI_FUNC(dev->devfn) & 1)))
+		return 1;
+
+	pci_read_config_word(dev, PCI_COMMAND, &command);
+	if(!(command & PCI_COMMAND_IO))
+	{
+		printk(KERN_INFO "Skipping disabled %s IDE controller.\n", d->name);
+		return 1; 
+	}
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id generic_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_NS,     PCI_DEVICE_ID_NS_87410,            PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_SAMURAI_IDE,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ PCI_VENDOR_ID_HOLTEK, PCI_DEVICE_ID_HOLTEK_6565,         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+	{ PCI_VENDOR_ID_UMC,    PCI_DEVICE_ID_UMC_UM8673F,         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+	{ PCI_VENDOR_ID_UMC,    PCI_DEVICE_ID_UMC_UM8886A,         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+	{ PCI_VENDOR_ID_UMC,    PCI_DEVICE_ID_UMC_UM8886BF,        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
+	{ PCI_VENDOR_ID_HINT,   PCI_DEVICE_ID_HINT_VXPROII_IDE,    PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6},
+	{ PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_82C561,          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7},
+	{ PCI_VENDOR_ID_OPTI,   PCI_DEVICE_ID_OPTI_82C558,         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "PCI IDE",
+	.id_table	= generic_pci_tbl,
+	.probe		= generic_init_one,
+};
+
+static int generic_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void generic_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(generic_ide_init);
+module_exit(generic_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for generic PCI IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/generic.h linux-2.4.21-pre6/drivers/ide/pci/generic.h
--- linux-2.4.20/drivers/ide/pci/generic.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/generic.h	2003-03-26 23:49:09.000000000 +0000
@@ -0,0 +1,161 @@
+#ifndef IDE_GENERIC_H
+#define IDE_GENERIC_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+static unsigned int init_chipset_generic(struct pci_dev *, const char *);
+static void init_hwif_generic(ide_hwif_t *);
+static void init_dma_generic(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t generic_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_NS,
+		.device		= PCI_DEVICE_ID_NS_87410,
+		.name		= "NS87410",
+		.init_chipset	= init_chipset_generic,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_generic,
+		.init_dma	= init_dma_generic,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x43,0x08,0x08}, {0x47,0x08,0x08}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+        },{	/* 1 */
+		.vendor		= PCI_VENDOR_ID_PCTECH,
+		.device		= PCI_DEVICE_ID_PCTECH_SAMURAI_IDE,
+		.name		= "SAMURAI",
+		.init_chipset	= init_chipset_generic,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_generic,
+		.init_dma	= init_dma_generic,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 2 */
+		.vendor		= PCI_VENDOR_ID_HOLTEK,
+		.device		= PCI_DEVICE_ID_HOLTEK_6565,
+		.name		= "HT6565",
+		.init_chipset	= init_chipset_generic,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_generic,
+		.init_dma	= init_dma_generic,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 3 */
+		.vendor		= PCI_VENDOR_ID_UMC,
+		.device		= PCI_DEVICE_ID_UMC_UM8673F,
+		.name		= "UM8673F",
+		.init_chipset	= init_chipset_generic,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_generic,
+		.init_dma	= init_dma_generic,
+		.channels	= 2,
+		.autodma	= NODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 4 */
+		.vendor		= PCI_VENDOR_ID_UMC,
+		.device		= PCI_DEVICE_ID_UMC_UM8886A,
+		.name		= "UM8886A",
+		.init_chipset	= init_chipset_generic,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_generic,
+		.init_dma	= init_dma_generic,
+		.channels	= 2,
+		.autodma	= NODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 5 */
+		.vendor		= PCI_VENDOR_ID_UMC,
+		.device		= PCI_DEVICE_ID_UMC_UM8886BF,
+		.name		= "UM8886BF",
+		.init_chipset	= init_chipset_generic,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_generic,
+		.init_dma	= init_dma_generic,
+		.channels	= 2,
+		.autodma	= NODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 6 */
+		.vendor		= PCI_VENDOR_ID_HINT,
+		.device		= PCI_DEVICE_ID_HINT_VXPROII_IDE,
+		.name		= "HINT_IDE",
+		.init_chipset	= init_chipset_generic,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_generic,
+		.init_dma	= init_dma_generic,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 7 */
+		.vendor		= PCI_VENDOR_ID_VIA,
+		.device		= PCI_DEVICE_ID_VIA_82C561,
+		.name		= "VIA_IDE",
+		.init_chipset	= init_chipset_generic,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_generic,
+		.init_dma	= init_dma_generic,
+		.channels	= 2,
+		.autodma	= NOAUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 8 */
+		.vendor		= PCI_VENDOR_ID_OPTI,
+		.device		= PCI_DEVICE_ID_OPTI_82C558,
+		.name		= "OPTI621V",
+		.init_chipset	= init_chipset_generic,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_generic,
+		.init_dma	= init_dma_generic,
+		.channels	= 2,
+		.autodma	= NOAUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+static ide_pci_device_t unknown_chipset[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= 0,
+		.device		= 0,
+		.name		= "PCI_IDE",
+		.init_chipset	= init_chipset_generic,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_generic,
+		.init_dma	= init_dma_generic,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+
+};
+
+#endif /* IDE_GENERIC_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/hpt34x.c linux-2.4.21-pre6/drivers/ide/pci/hpt34x.c
--- linux-2.4.20/drivers/ide/pci/hpt34x.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/hpt34x.c	2003-03-26 23:49:06.000000000 +0000
@@ -0,0 +1,366 @@
+/*
+ * linux/drivers/ide/pci/hpt34x.c		Version 0.40	Sept 10, 2002
+ *
+ * Copyright (C) 1998-2000	Andre Hedrick <andre@linux-ide.org>
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ *
+ * 00:12.0 Unknown mass storage controller:
+ * Triones Technologies, Inc.
+ * Unknown device 0003 (rev 01)
+ *
+ * hde: UDMA 2 (0x0000 0x0002) (0x0000 0x0010)
+ * hdf: UDMA 2 (0x0002 0x0012) (0x0010 0x0030)
+ * hde: DMA 2  (0x0000 0x0002) (0x0000 0x0010)
+ * hdf: DMA 2  (0x0002 0x0012) (0x0010 0x0030)
+ * hdg: DMA 1  (0x0012 0x0052) (0x0030 0x0070)
+ * hdh: DMA 1  (0x0052 0x0252) (0x0070 0x00f0)
+ *
+ * ide-pci.c reference
+ *
+ * Since there are two cards that report almost identically,
+ * the only discernable difference is the values reported in pcicmd.
+ * Booting-BIOS card or HPT363 :: pcicmd == 0x07
+ * Non-bootable card or HPT343 :: pcicmd == 0x05
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+#include "hpt34x.h"
+
+#if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 hpt34x_proc = 0;
+
+#define HPT34X_MAX_DEVS		8
+static struct pci_dev *hpt34x_devs[HPT34X_MAX_DEVS];
+static int n_hpt34x_devs;
+
+static int hpt34x_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	int i;
+
+	p += sprintf(p, "\n                             "
+			"HPT34X Chipset.\n");
+	for (i = 0; i < n_hpt34x_devs; i++) {
+		struct pci_dev *dev = hpt34x_devs[i];
+		unsigned long bibma = pci_resource_start(dev, 4);
+		u8  c0 = 0, c1 = 0;
+
+		/*
+		 * at that point bibma+0x2 et bibma+0xa are byte registers
+		 * to investigate:
+		 */
+		c0 = inb_p((u16)bibma + 0x02);
+		c1 = inb_p((u16)bibma + 0x0a);
+		p += sprintf(p, "\nController: %d\n", i);
+		p += sprintf(p, "--------------- Primary Channel "
+				"---------------- Secondary Channel "
+				"-------------\n");
+		p += sprintf(p, "                %sabled "
+				"                        %sabled\n",
+				(c0&0x80) ? "dis" : " en",
+				(c1&0x80) ? "dis" : " en");
+		p += sprintf(p, "--------------- drive0 --------- drive1 "
+				"-------- drive0 ---------- drive1 ------\n");
+		p += sprintf(p, "DMA enabled:    %s              %s"
+				"             %s               %s\n",
+				(c0&0x20) ? "yes" : "no ",
+				(c0&0x40) ? "yes" : "no ",
+				(c1&0x20) ? "yes" : "no ",
+				(c1&0x40) ? "yes" : "no " );
+
+		p += sprintf(p, "UDMA\n");
+		p += sprintf(p, "DMA\n");
+		p += sprintf(p, "PIO\n");
+	}
+	p += sprintf(p, "\n");
+
+	return p-buffer;	/* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static u8 hpt34x_ratemask (ide_drive_t *drive)
+{
+	return 1;
+}
+
+static void hpt34x_clear_chipset (ide_drive_t *drive)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	u32 reg1 = 0, tmp1 = 0, reg2 = 0, tmp2 = 0;
+
+	pci_read_config_dword(dev, 0x44, &reg1);
+	pci_read_config_dword(dev, 0x48, &reg2);
+	tmp1 = ((0x00 << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn))));
+	tmp2 = (reg2 & ~(0x11 << drive->dn));
+	pci_write_config_dword(dev, 0x44, tmp1);
+	pci_write_config_dword(dev, 0x48, tmp2);
+}
+
+static int hpt34x_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	u8 speed	= ide_rate_filter(hpt34x_ratemask(drive), xferspeed);
+	u32 reg1= 0, tmp1 = 0, reg2 = 0, tmp2 = 0;
+	u8			hi_speed, lo_speed;
+
+	SPLIT_BYTE(speed, hi_speed, lo_speed);
+
+	if (hi_speed & 7) {
+		hi_speed = (hi_speed & 4) ? 0x01 : 0x10;
+	} else {
+		lo_speed <<= 5;
+		lo_speed >>= 5;
+	}
+
+	pci_read_config_dword(dev, 0x44, &reg1);
+	pci_read_config_dword(dev, 0x48, &reg2);
+	tmp1 = ((lo_speed << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn))));
+	tmp2 = ((hi_speed << drive->dn) | reg2);
+	pci_write_config_dword(dev, 0x44, tmp1);
+	pci_write_config_dword(dev, 0x48, tmp2);
+
+#if HPT343_DEBUG_DRIVE_INFO
+	printk("%s: %s drive%d (0x%04x 0x%04x) (0x%04x 0x%04x)" \
+		" (0x%02x 0x%02x)\n",
+		drive->name, ide_xfer_verbose(speed),
+		drive->dn, reg1, tmp1, reg2, tmp2,
+		hi_speed, lo_speed);
+#endif /* HPT343_DEBUG_DRIVE_INFO */
+
+	return(ide_config_drive_speed(drive, speed));
+}
+
+static void hpt34x_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+	hpt34x_clear_chipset(drive);
+	(void) hpt34x_tune_chipset(drive, (XFER_PIO_0 + pio));
+}
+
+/*
+ * This allows the configuration of ide_pci chipset registers
+ * for cards that learn about the drive's UDMA, DMA, PIO capabilities
+ * after the drive is reported by the OS.  Initally for designed for
+ * HPT343 UDMA chipset by HighPoint|Triones Technologies, Inc.
+ */
+
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	u8 speed = ide_dma_speed(drive, hpt34x_ratemask(drive));
+
+	if (!(speed))
+		return 0;
+
+	hpt34x_clear_chipset(drive);
+	(void) hpt34x_tune_chipset(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static int hpt34x_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	drive->init_speed = 0;
+
+	if (id && (id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		hpt34x_tune_drive(drive, 255);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+
+#ifndef CONFIG_HPT34X_AUTODMA
+	return hwif->ide_dma_off_quietly(drive);
+#endif /* CONFIG_HPT34X_AUTODMA */
+	return hwif->ide_dma_on(drive);
+}
+
+/*
+ * If the BIOS does not set the IO base addaress to XX00, 343 will fail.
+ */
+#define	HPT34X_PCI_INIT_REG		0x80
+
+static unsigned int __init init_chipset_hpt34x (struct pci_dev *dev, const char *name)
+{
+	int i = 0;
+	unsigned long hpt34xIoBase = pci_resource_start(dev, 4);
+	unsigned long hpt_addr[4] = { 0x20, 0x34, 0x28, 0x3c };
+	unsigned long hpt_addr_len[4] = { 7, 3, 7, 3 };
+	u16 cmd;
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	pci_write_config_byte(dev, HPT34X_PCI_INIT_REG, 0x00);
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+
+	if (cmd & PCI_COMMAND_MEMORY) {
+		if (pci_resource_start(dev, PCI_ROM_RESOURCE)) {
+			pci_write_config_byte(dev, PCI_ROM_ADDRESS,
+				dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+			printk(KERN_INFO "HPT345: ROM enabled at 0x%08lx\n",
+				dev->resource[PCI_ROM_RESOURCE].start);
+		}
+		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0);
+	} else {
+		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
+	}
+
+	/*
+	 * Since 20-23 can be assigned and are R/W, we correct them.
+	 */
+	pci_write_config_word(dev, PCI_COMMAND, cmd & ~PCI_COMMAND_IO);
+	for(i=0; i<4; i++) {
+		dev->resource[i].start = (hpt34xIoBase + hpt_addr[i]);
+		dev->resource[i].end = dev->resource[i].start + hpt_addr_len[i];
+		dev->resource[i].flags = IORESOURCE_IO;
+		pci_write_config_dword(dev,
+				(PCI_BASE_ADDRESS_0 + (i * 4)),
+				dev->resource[i].start);
+	}
+	pci_write_config_word(dev, PCI_COMMAND, cmd);
+
+	local_irq_restore(flags);
+
+#if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS)
+	hpt34x_devs[n_hpt34x_devs++] = dev;
+
+	if (!hpt34x_proc) {
+		hpt34x_proc = 1;
+		ide_pci_register_host_proc(&hpt34x_procs[0]);
+	}
+#endif /* DISPLAY_HPT34X_TIMINGS && CONFIG_PROC_FS */
+
+	return dev->irq;
+}
+
+static void __init init_hwif_hpt34x (ide_hwif_t *hwif)
+{
+	u16 pcicmd = 0;
+
+	hwif->autodma = 0;
+
+	hwif->tuneproc = &hpt34x_tune_drive;
+	hwif->speedproc = &hpt34x_tune_chipset;
+	hwif->no_dsc = 1;
+	hwif->drives[0].autotune = 1;
+	hwif->drives[1].autotune = 1;
+
+	pci_read_config_word(hwif->pci_dev, PCI_COMMAND, &pcicmd);
+
+	if (!hwif->dma_base)
+		return;
+
+	hwif->ultra_mask = 0x07;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+	hwif->ide_dma_check = &hpt34x_config_drive_xfer_rate;
+	if (!noautodma)
+		hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+static void __init init_dma_hpt34x (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static int __devinit hpt34x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &hpt34x_chipsets[id->driver_data];
+	static char *chipset_names[] = {"HPT343", "HPT345"};
+	u16 pcicmd = 0;
+
+	pci_read_config_word(dev, PCI_COMMAND, &pcicmd);
+
+	d->name = chipset_names[(pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0];
+	d->bootable = (pcicmd & PCI_COMMAND_MEMORY) ? OFF_BOARD : NEVER_BOARD;
+
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id hpt34x_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT343, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "HPT34x IDE",
+	.id_table	= hpt34x_pci_tbl,
+	.probe		= hpt34x_init_one,
+};
+
+static int hpt34x_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void hpt34x_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(hpt34x_ide_init);
+module_exit(hpt34x_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for Highpoint 34x IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/hpt34x.h linux-2.4.21-pre6/drivers/ide/pci/hpt34x.h
--- linux-2.4.20/drivers/ide/pci/hpt34x.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/hpt34x.h	2003-03-26 23:48:57.000000000 +0000
@@ -0,0 +1,60 @@
+#ifndef HPT34X_H
+#define HPT34X_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define HPT343_DEBUG_DRIVE_INFO		0
+
+#ifndef SPLIT_BYTE
+#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
+#endif
+
+#undef DISPLAY_HPT34X_TIMINGS
+
+#if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 hpt34x_proc;
+
+static int hpt34x_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t hpt34x_procs[] __initdata = {
+	{
+		.name		= "hpt34x",
+		.set		= 1,
+		.get_info	= hpt34x_get_info,
+		.parent		= NULL,
+	},
+};
+#endif  /* defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static unsigned int init_chipset_hpt34x(struct pci_dev *, const char *);
+static void init_hwif_hpt34x(ide_hwif_t *);
+static void init_dma_hpt34x(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t hpt34x_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_TTI,
+		.device		= PCI_DEVICE_ID_TTI_HPT343,
+		.name		= "HPT34X",
+		.init_chipset	= init_chipset_hpt34x,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_hpt34x,
+		.init_dma	= init_dma_hpt34x,
+		.channels	= 2,
+		.autodma	= NOAUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= NEVER_BOARD,
+		.extra		= 16
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* HPT34X_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/hpt366.c linux-2.4.21-pre6/drivers/ide/pci/hpt366.c
--- linux-2.4.20/drivers/ide/pci/hpt366.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/hpt366.c	2003-03-26 23:49:08.000000000 +0000
@@ -0,0 +1,1219 @@
+/*
+ * linux/drivers/ide/pci/hpt366.c		Version 0.34	Sept 17, 2002
+ *
+ * Copyright (C) 1999-2002		Andre Hedrick <andre@linux-ide.org>
+ * Portions Copyright (C) 2001	        Sun Microsystems, Inc.
+ *
+ * Thanks to HighPoint Technologies for their assistance, and hardware.
+ * Special Thanks to Jon Burchmore in SanDiego for the deep pockets, his
+ * donation of an ABit BP6 mainboard, processor, and memory acellerated
+ * development and support.
+ *
+ * Note that final HPT370 support was done by force extraction of GPL.
+ *
+ * - add function for getting/setting power status of drive
+ * - the HPT370's state machine can get confused. reset it before each dma 
+ *   xfer to prevent that from happening.
+ * - reset state engine whenever we get an error.
+ * - check for busmaster state at end of dma. 
+ * - use new highpoint timings.
+ * - detect bus speed using highpoint register.
+ * - use pll if we don't have a clock table. added a 66MHz table that's
+ *   just 2x the 33MHz table.
+ * - removed turnaround. NOTE: we never want to switch between pll and
+ *   pci clocks as the chip can glitch in those cases. the highpoint
+ *   approved workaround slows everything down too much to be useful. in
+ *   addition, we would have to serialize access to each chip.
+ * 	Adrian Sun <a.sun@sun.com>
+ *
+ * add drive timings for 66MHz PCI bus,
+ * fix ATA Cable signal detection, fix incorrect /proc info
+ * add /proc display for per-drive PIO/DMA/UDMA mode and
+ * per-channel ATA-33/66 Cable detect.
+ * 	Duncan Laurie <void@sun.com>
+ *
+ * fixup /proc output for multiple controllers
+ *	Tim Hockin <thockin@sun.com>
+ *
+ * On hpt366: 
+ * Reset the hpt366 on error, reset on dma
+ * Fix disabling Fast Interrupt hpt366.
+ * 	Mike Waychison <crlf@sun.com>
+ */
+
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+#include "hpt366.h"
+
+#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+#endif  /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static unsigned int hpt_revision(struct pci_dev *dev);
+static unsigned int hpt_minimum_revision(struct pci_dev *dev, int revision);
+
+#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
+
+static u8 hpt366_proc = 0;
+static struct pci_dev *hpt_devs[HPT366_MAX_DEVS];
+static int n_hpt_devs;
+
+static int hpt366_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p	= buffer;
+	char *chipset_nums[] = {"366", "366",  "368",
+				"370", "370A", "372",
+				"302", "371",  "374" };
+	int i;
+
+	p += sprintf(p, "\n                             "
+		"HighPoint HPT366/368/370/372/374\n");
+	for (i = 0; i < n_hpt_devs; i++) {
+		struct pci_dev *dev = hpt_devs[i];
+		unsigned long iobase = dev->resource[4].start;
+		u32 class_rev = hpt_revision(dev);
+		u8 c0, c1;
+
+		p += sprintf(p, "\nController: %d\n", i);
+		p += sprintf(p, "Chipset: HPT%s\n", chipset_nums[class_rev]);
+		p += sprintf(p, "--------------- Primary Channel "
+				"--------------- Secondary Channel "
+				"--------------\n");
+
+		/* get the bus master status registers */
+		c0 = inb(iobase + 0x2);
+		c1 = inb(iobase + 0xa);
+		p += sprintf(p, "Enabled:        %s"
+				"                             %s\n",
+			(c0 & 0x80) ? "no" : "yes",
+			(c1 & 0x80) ? "no" : "yes");
+
+		if (hpt_minimum_revision(dev, 3)) {
+			u8 cbl;
+			cbl = inb(iobase + 0x7b);
+			outb(cbl | 1, iobase + 0x7b);
+			outb(cbl & ~1, iobase + 0x7b);
+			cbl = inb(iobase + 0x7a);
+			p += sprintf(p, "Cable:          ATA-%d"
+					"                          ATA-%d\n",
+				(cbl & 0x02) ? 33 : 66,
+				(cbl & 0x01) ? 33 : 66);
+			p += sprintf(p, "\n");
+		}
+
+		p += sprintf(p, "--------------- drive0 --------- drive1 "
+				"------- drive0 ---------- drive1 -------\n");
+		p += sprintf(p, "DMA capable:    %s              %s" 
+				"            %s               %s\n",
+			(c0 & 0x20) ? "yes" : "no ", 
+			(c0 & 0x40) ? "yes" : "no ",
+			(c1 & 0x20) ? "yes" : "no ", 
+			(c1 & 0x40) ? "yes" : "no ");
+
+		{
+			u8 c2, c3;
+			/* older revs don't have these registers mapped 
+			 * into io space */
+			pci_read_config_byte(dev, 0x43, &c0);
+			pci_read_config_byte(dev, 0x47, &c1);
+			pci_read_config_byte(dev, 0x4b, &c2);
+			pci_read_config_byte(dev, 0x4f, &c3);
+
+			p += sprintf(p, "Mode:           %s             %s"
+					"           %s              %s\n",
+				(c0 & 0x10) ? "UDMA" : (c0 & 0x20) ? "DMA " : 
+					(c0 & 0x80) ? "PIO " : "off ",
+				(c1 & 0x10) ? "UDMA" : (c1 & 0x20) ? "DMA " :
+					(c1 & 0x80) ? "PIO " : "off ",
+				(c2 & 0x10) ? "UDMA" : (c2 & 0x20) ? "DMA " :
+					(c2 & 0x80) ? "PIO " : "off ",
+				(c3 & 0x10) ? "UDMA" : (c3 & 0x20) ? "DMA " :
+					(c3 & 0x80) ? "PIO " : "off ");
+		}
+	}
+	p += sprintf(p, "\n");
+	
+	return p-buffer;/* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static u32 hpt_revision (struct pci_dev *dev)
+{
+	u32 class_rev;
+	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+	class_rev &= 0xff;
+
+	switch(dev->device) {
+		case PCI_DEVICE_ID_TTI_HPT374:
+			class_rev = PCI_DEVICE_ID_TTI_HPT374; break;
+		case PCI_DEVICE_ID_TTI_HPT371:
+			class_rev = PCI_DEVICE_ID_TTI_HPT371; break;
+		case PCI_DEVICE_ID_TTI_HPT302:
+			class_rev = PCI_DEVICE_ID_TTI_HPT302; break;
+		case PCI_DEVICE_ID_TTI_HPT372:
+			class_rev = PCI_DEVICE_ID_TTI_HPT372; break;
+		default:
+			break;
+	}
+	return class_rev;
+}
+
+static u32 hpt_minimum_revision (struct pci_dev *dev, int revision)
+{
+	unsigned int class_rev = hpt_revision(dev);
+	revision--;
+	return ((int) (class_rev > revision) ? 1 : 0);
+}
+
+static int check_in_drive_lists(ide_drive_t *drive, const char **list);
+
+static u8 hpt3xx_ratemask (ide_drive_t *drive)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	u8 mode			= 0;
+
+	if (hpt_minimum_revision(dev, 8)) {		/* HPT374 */
+		mode = (HPT374_ALLOW_ATA133_6) ? 4 : 3;
+	} else if (hpt_minimum_revision(dev, 7)) {	/* HPT371 */
+		mode = (HPT371_ALLOW_ATA133_6) ? 4 : 3;
+	} else if (hpt_minimum_revision(dev, 6)) {	/* HPT302 */
+		mode = (HPT302_ALLOW_ATA133_6) ? 4 : 3;
+	} else if (hpt_minimum_revision(dev, 5)) {	/* HPT372 */
+		mode = (HPT372_ALLOW_ATA133_6) ? 4 : 3;
+	} else if (hpt_minimum_revision(dev, 4)) {	/* HPT370A */
+		mode = (HPT370_ALLOW_ATA100_5) ? 3 : 2;
+	} else if (hpt_minimum_revision(dev, 3)) {	/* HPT370 */
+		mode = (HPT370_ALLOW_ATA100_5) ? 3 : 2;
+		mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : mode;
+	} else {				/* HPT366 and HPT368 */
+		mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : 2;
+	}
+	if (!eighty_ninty_three(drive) && (mode))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+static u8 hpt3xx_ratefilter (ide_drive_t *drive, u8 speed)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	u8 mode			= hpt3xx_ratemask(drive);
+
+	if (drive->media != ide_disk)
+		return min(speed, (u8)XFER_PIO_4);
+
+	switch(mode) {
+		case 0x04:
+			speed = min(speed, (u8)XFER_UDMA_6);
+			break;
+		case 0x03:
+			speed = min(speed, (u8)XFER_UDMA_5);
+			if (hpt_minimum_revision(dev, 5))
+				break;
+			if (check_in_drive_lists(drive, bad_ata100_5))
+				speed = min(speed, (u8)XFER_UDMA_4);
+			break;
+		case 0x02:
+			speed = min(speed, (u8)XFER_UDMA_4);
+	/*
+	 * CHECK ME, Does this need to be set to 5 ??
+	 */
+			if (hpt_minimum_revision(dev, 3))
+				break;
+			if ((check_in_drive_lists(drive, bad_ata66_4)) ||
+			    (!(HPT366_ALLOW_ATA66_4)))
+				speed = min(speed, (u8)XFER_UDMA_3);
+			if ((check_in_drive_lists(drive, bad_ata66_3)) ||
+			    (!(HPT366_ALLOW_ATA66_3)))
+				speed = min(speed, (u8)XFER_UDMA_2);
+			break;
+		case 0x01:
+			speed = min(speed, (u8)XFER_UDMA_2);
+	/*
+	 * CHECK ME, Does this need to be set to 5 ??
+	 */
+			if (hpt_minimum_revision(dev, 3))
+				break;
+			if (check_in_drive_lists(drive, bad_ata33))
+				speed = min(speed, (u8)XFER_MW_DMA_2);
+			break;
+		case 0x00:
+		default:
+			speed = min(speed, (u8)XFER_MW_DMA_2);
+			break;
+	}
+	return speed;
+}
+
+static int check_in_drive_lists (ide_drive_t *drive, const char **list)
+{
+	struct hd_driveid *id = drive->id;
+
+	if (quirk_drives == list) {
+		while (*list)
+			if (strstr(id->model, *list++))
+				return 1;
+	} else {
+		while (*list)
+			if (!strcmp(*list++,id->model))
+				return 1;
+	}
+	return 0;
+}
+
+static unsigned int pci_bus_clock_list (u8 speed, struct chipset_bus_clock_list_entry * chipset_table)
+{
+	for ( ; chipset_table->xfer_speed ; chipset_table++)
+		if (chipset_table->xfer_speed == speed)
+			return chipset_table->chipset_settings;
+	return chipset_table->chipset_settings;
+}
+
+static void hpt366_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	u8 speed		= hpt3xx_ratefilter(drive, xferspeed);
+//	u8 speed		= ide_rate_filter(hpt3xx_ratemask(drive), xferspeed);
+	u8 regtime		= (drive->select.b.unit & 0x01) ? 0x44 : 0x40;
+	u8 regfast		= (HWIF(drive)->channel) ? 0x55 : 0x51;
+	u8 drive_fast		= 0;
+	u32 reg1 = 0, reg2	= 0;
+
+	/*
+	 * Disable the "fast interrupt" prediction.
+	 */
+	pci_read_config_byte(dev, regfast, &drive_fast);
+#if 0
+	if (drive_fast & 0x02)
+		pci_write_config_byte(dev, regfast, drive_fast & ~0x20);
+#else
+	if (drive_fast & 0x80)
+		pci_write_config_byte(dev, regfast, drive_fast & ~0x80);
+#endif
+
+	reg2 = pci_bus_clock_list(speed,
+		(struct chipset_bus_clock_list_entry *) pci_get_drvdata(dev));
+	/*
+	 * Disable on-chip PIO FIFO/buffer
+	 *  (to avoid problems handling I/O errors later)
+	 */
+	pci_read_config_dword(dev, regtime, &reg1);
+	if (speed >= XFER_MW_DMA_0) {
+		reg2 = (reg2 & ~0xc0000000) | (reg1 & 0xc0000000);
+	} else {
+		reg2 = (reg2 & ~0x30070000) | (reg1 & 0x30070000);
+	}	
+	reg2 &= ~0x80000000;
+
+	pci_write_config_dword(dev, regtime, reg2);
+}
+
+static void hpt368_tune_chipset (ide_drive_t *drive, u8 speed)
+{
+	hpt366_tune_chipset(drive, speed);
+}
+
+static void hpt370_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	struct pci_dev *dev = HWIF(drive)->pci_dev;
+	u8 speed	= hpt3xx_ratefilter(drive, xferspeed);
+//	u8 speed	= ide_rate_filter(hpt3xx_ratemask(drive), xferspeed);
+	u8 regfast	= (HWIF(drive)->channel) ? 0x55 : 0x51;
+	u8 drive_pci	= 0x40 + (drive->dn * 4);
+	u8 new_fast	= 0, drive_fast = 0;
+	u32 list_conf	= 0, drive_conf = 0;
+	u32 conf_mask	= (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
+
+	/*
+	 * Disable the "fast interrupt" prediction.
+	 * don't holdoff on interrupts. (== 0x01 despite what the docs say) 
+	 */
+	pci_read_config_byte(dev, regfast, &drive_fast);
+	new_fast = drive_fast;
+	if (new_fast & 0x02)
+		new_fast &= ~0x02;
+
+#ifdef HPT_DELAY_INTERRUPT
+	if (new_fast & 0x01)
+		new_fast &= ~0x01;
+#else
+	if ((new_fast & 0x01) == 0)
+		new_fast |= 0x01;
+#endif
+	if (new_fast != drive_fast)
+		pci_write_config_byte(dev, regfast, new_fast);
+
+	list_conf = pci_bus_clock_list(speed, 
+				       (struct chipset_bus_clock_list_entry *)
+				       pci_get_drvdata(dev));
+
+	pci_read_config_dword(dev, drive_pci, &drive_conf);
+	list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
+	
+	if (speed < XFER_MW_DMA_0) {
+		list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
+	}
+
+	pci_write_config_dword(dev, drive_pci, list_conf);
+}
+
+static void hpt372_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	u8 speed	= hpt3xx_ratefilter(drive, xferspeed);
+//	u8 speed	= ide_rate_filter(hpt3xx_ratemask(drive), xferspeed);
+	u8 regfast	= (HWIF(drive)->channel) ? 0x55 : 0x51;
+	u8 drive_fast	= 0, drive_pci = 0x40 + (drive->dn * 4);
+	u32 list_conf	= 0, drive_conf = 0;
+	u32 conf_mask	= (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
+
+	/*
+	 * Disable the "fast interrupt" prediction.
+	 * don't holdoff on interrupts. (== 0x01 despite what the docs say)
+	 */
+	pci_read_config_byte(dev, regfast, &drive_fast);
+	drive_fast &= ~0x07;
+	pci_write_config_byte(dev, regfast, drive_fast);
+					
+	list_conf = pci_bus_clock_list(speed,
+			(struct chipset_bus_clock_list_entry *)
+					pci_get_drvdata(dev));
+	pci_read_config_dword(dev, drive_pci, &drive_conf);
+	list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
+	if (speed < XFER_MW_DMA_0)
+		list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
+	pci_write_config_dword(dev, drive_pci, list_conf);
+}
+
+static void hpt374_tune_chipset (ide_drive_t *drive, u8 speed)
+{
+	hpt372_tune_chipset(drive, speed);
+}
+
+static int hpt3xx_tune_chipset (ide_drive_t *drive, u8 speed)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+
+	if (hpt_minimum_revision(dev, 8))
+		hpt374_tune_chipset(drive, speed);
+#if 0
+	else if (hpt_minimum_revision(dev, 7))
+		hpt371_tune_chipset(drive, speed);
+	else if (hpt_minimum_revision(dev, 6))
+		hpt302_tune_chipset(drive, speed);
+#endif
+	else if (hpt_minimum_revision(dev, 5))
+		hpt372_tune_chipset(drive, speed);
+	else if (hpt_minimum_revision(dev, 3))
+		hpt370_tune_chipset(drive, speed);
+	else if (hpt_minimum_revision(dev, 2))
+		hpt368_tune_chipset(drive, speed);
+	else
+                hpt366_tune_chipset(drive, speed);
+
+	return ((int) ide_config_drive_speed(drive, speed));
+}
+
+static void hpt3xx_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+	(void) hpt3xx_tune_chipset(drive, (XFER_PIO_0 + pio));
+}
+
+/*
+ * This allows the configuration of ide_pci chipset registers
+ * for cards that learn about the drive's UDMA, DMA, PIO capabilities
+ * after the drive is reported by the OS.  Initally for designed for
+ * HPT366 UDMA chipset by HighPoint|Triones Technologies, Inc.
+ *
+ * check_in_drive_lists(drive, bad_ata66_4)
+ * check_in_drive_lists(drive, bad_ata66_3)
+ * check_in_drive_lists(drive, bad_ata33)
+ *
+ */
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	u8 speed = ide_dma_speed(drive, hpt3xx_ratemask(drive));
+
+	if (!(speed))
+		return 0;
+
+	(void) hpt3xx_tune_chipset(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static int hpt3xx_quirkproc (ide_drive_t *drive)
+{
+	return ((int) check_in_drive_lists(drive, quirk_drives));
+}
+
+static void hpt3xx_intrproc (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+
+	if (drive->quirk_list)
+		return;
+	/* drives in the quirk_list may not like intr setups/cleanups */
+	hwif->OUTB(drive->ctl|2, IDE_CONTROL_REG);
+}
+
+static void hpt3xx_maskproc (ide_drive_t *drive, int mask)
+{
+	struct pci_dev *dev = HWIF(drive)->pci_dev;
+
+	if (drive->quirk_list) {
+		if (hpt_minimum_revision(dev,3)) {
+			u8 reg5a = 0;
+			pci_read_config_byte(dev, 0x5a, &reg5a);
+			if (((reg5a & 0x10) >> 4) != mask)
+				pci_write_config_byte(dev, 0x5a, mask ? (reg5a | 0x10) : (reg5a & ~0x10));
+		} else {
+			if (mask) {
+				disable_irq(HWIF(drive)->irq);
+			} else {
+				enable_irq(HWIF(drive)->irq);
+			}
+		}
+	} else {
+		if (IDE_CONTROL_REG)
+			HWIF(drive)->OUTB(mask ? (drive->ctl | 2) :
+						 (drive->ctl & ~2),
+						 IDE_CONTROL_REG);
+	}
+}
+
+static int hpt366_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	drive->init_speed = 0;
+
+	if (id && (id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if (id->dma_mword & hwif->mwdma_mask) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		hpt3xx_tune_drive(drive, 5);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+/*
+ * This is specific to the HPT366 UDMA bios chipset
+ * by HighPoint|Triones Technologies, Inc.
+ */
+static int hpt366_ide_dma_lostirq (ide_drive_t *drive)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	u8 reg50h = 0, reg52h = 0, reg5ah = 0;
+
+	pci_read_config_byte(dev, 0x50, &reg50h);
+	pci_read_config_byte(dev, 0x52, &reg52h);
+	pci_read_config_byte(dev, 0x5a, &reg5ah);
+	printk("%s: (%s)  reg50h=0x%02x, reg52h=0x%02x, reg5ah=0x%02x\n",
+		drive->name, __FUNCTION__, reg50h, reg52h, reg5ah);
+	if (reg5ah & 0x10)
+		pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10);
+#if 0
+	/* how about we flush and reset, mmmkay? */
+	pci_write_config_byte(dev, 0x51, 0x1F);
+	/* fall through to a reset */
+	case ide_dma_begin:
+	case ide_dma_end:
+	/* reset the chips state over and over.. */
+	pci_write_config_byte(dev, 0x51, 0x13);
+#endif
+	return __ide_dma_lostirq(drive);
+}
+
+static void hpt370_clear_engine (ide_drive_t *drive)
+{
+	u8 regstate = HWIF(drive)->channel ? 0x54 : 0x50;
+	pci_write_config_byte(HWIF(drive)->pci_dev, regstate, 0x37);
+	udelay(10);
+}
+
+static int hpt370_ide_dma_begin (ide_drive_t *drive)
+{
+#ifdef HPT_RESET_STATE_ENGINE
+	hpt370_clear_engine(drive);
+#endif
+	return __ide_dma_begin(drive);
+}
+
+static int hpt370_ide_dma_end (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 dma_stat		= hwif->INB(hwif->dma_status);
+
+	if (dma_stat & 0x01) {
+		/* wait a little */
+		udelay(20);
+		dma_stat = hwif->INB(hwif->dma_status);
+	}
+	if ((dma_stat & 0x01) != 0) 
+		/* fallthrough */
+		(void) HWIF(drive)->ide_dma_timeout(drive);
+
+	return __ide_dma_end(drive);
+}
+
+static void hpt370_lostirq_timeout (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 bfifo = 0, reginfo	= hwif->channel ? 0x56 : 0x52;
+	u8 dma_stat = 0, dma_cmd = 0;
+
+	pci_read_config_byte(HWIF(drive)->pci_dev, reginfo, &bfifo);
+	printk("%s: %d bytes in FIFO\n", drive->name, bfifo);
+	hpt370_clear_engine(drive);
+	/* get dma command mode */
+	dma_cmd = hwif->INB(hwif->dma_command);
+	/* stop dma */
+	hwif->OUTB(dma_cmd & ~0x1, hwif->dma_command);
+	dma_stat = hwif->INB(hwif->dma_status);
+	/* clear errors */
+	hwif->OUTB(dma_stat | 0x6, hwif->dma_status);
+}
+
+static int hpt370_ide_dma_timeout (ide_drive_t *drive)
+{
+	hpt370_lostirq_timeout(drive);
+	hpt370_clear_engine(drive);
+	return __ide_dma_timeout(drive);
+}
+
+static int hpt370_ide_dma_lostirq (ide_drive_t *drive)
+{
+	hpt370_lostirq_timeout(drive);
+	hpt370_clear_engine(drive);
+	return __ide_dma_lostirq(drive);
+}
+
+static int hpt374_ide_dma_end (ide_drive_t *drive)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 msc_stat = 0, mscreg	= hwif->channel ? 0x54 : 0x50;
+	u8 bwsr_stat = 0, bwsr_mask = hwif->channel ? 0x02 : 0x01;
+
+	pci_read_config_byte(dev, 0x6a, &bwsr_stat);
+	pci_read_config_byte(dev, mscreg, &msc_stat);
+	if ((bwsr_stat & bwsr_mask) == bwsr_mask)
+		pci_write_config_byte(dev, mscreg, msc_stat|0x30);
+	return __ide_dma_end(drive);
+}
+
+/*
+ * Since SUN Cobalt is attempting to do this operation, I should disclose
+ * this has been a long time ago Thu Jul 27 16:40:57 2000 was the patch date
+ * HOTSWAP ATA Infrastructure.
+ */
+
+static void hpt3xx_reset (ide_drive_t *drive)
+{
+#if 0
+	unsigned long high_16	= pci_resource_start(HWIF(drive)->pci_dev, 4);
+	u8 reset	= (HWIF(drive)->channel) ? 0x80 : 0x40;
+	u8 reg59h	= 0;
+
+	pci_read_config_byte(HWIF(drive)->pci_dev, 0x59, &reg59h);
+	pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h|reset);
+	pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h);
+#endif
+}
+
+static int hpt3xx_tristate (ide_drive_t * drive, int state)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 reg59h = 0, reset	= (hwif->channel) ? 0x80 : 0x40;
+	u8 regXXh = 0, state_reg= (hwif->channel) ? 0x57 : 0x53;
+
+	if (!hwif)
+		return -EINVAL;
+
+//	hwif->bus_state = state;
+
+	pci_read_config_byte(dev, 0x59, &reg59h);
+	pci_read_config_byte(dev, state_reg, &regXXh);
+
+	if (state) {
+		(void) ide_do_reset(drive);
+		pci_write_config_byte(dev, state_reg, regXXh|0x80);
+		pci_write_config_byte(dev, 0x59, reg59h|reset);
+	} else {
+		pci_write_config_byte(dev, 0x59, reg59h & ~(reset));
+		pci_write_config_byte(dev, state_reg, regXXh & ~(0x80));
+		(void) ide_do_reset(drive);
+	}
+	return 0;
+}
+
+/* 
+ * set/get power state for a drive.
+ * turning the power off does the following things:
+ *   1) soft-reset the drive
+ *   2) tri-states the ide bus
+ *
+ * when we turn things back on, we need to re-initialize things.
+ */
+#define TRISTATE_BIT  0x8000
+static int hpt370_busproc(ide_drive_t * drive, int state)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 tristate = 0, resetmask = 0, bus_reg = 0;
+	u16 tri_reg;
+
+	if (!hwif)
+		return -EINVAL;
+
+	hwif->bus_state = state;
+
+	if (hwif->channel) { 
+		/* secondary channel */
+		tristate = 0x56;
+		resetmask = 0x80; 
+	} else { 
+		/* primary channel */
+		tristate = 0x52;
+		resetmask = 0x40;
+	}
+
+	/* grab status */
+	pci_read_config_word(dev, tristate, &tri_reg);
+	pci_read_config_byte(dev, 0x59, &bus_reg);
+
+	/* set the state. we don't set it if we don't need to do so.
+	 * make sure that the drive knows that it has failed if it's off */
+	switch (state) {
+	case BUSSTATE_ON:
+		hwif->drives[0].failures = 0;
+		hwif->drives[1].failures = 0;
+		if ((bus_reg & resetmask) == 0)
+			return 0;
+		tri_reg &= ~TRISTATE_BIT;
+		bus_reg &= ~resetmask;
+		break;
+	case BUSSTATE_OFF:
+		hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+		hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+		if ((tri_reg & TRISTATE_BIT) == 0 && (bus_reg & resetmask))
+			return 0;
+		tri_reg &= ~TRISTATE_BIT;
+		bus_reg |= resetmask;
+		break;
+	case BUSSTATE_TRISTATE:
+		hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+		hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+		if ((tri_reg & TRISTATE_BIT) && (bus_reg & resetmask))
+			return 0;
+		tri_reg |= TRISTATE_BIT;
+		bus_reg |= resetmask;
+		break;
+	}
+	pci_write_config_byte(dev, 0x59, bus_reg);
+	pci_write_config_word(dev, tristate, tri_reg);
+
+	return 0;
+}
+
+static int __init init_hpt37x(struct pci_dev *dev)
+{
+	int adjust, i;
+	u16 freq;
+	u32 pll;
+	u8 reg5bh;
+
+#if 1
+	u8 reg5ah = 0;
+	pci_read_config_byte(dev, 0x5a, &reg5ah);
+	/* interrupt force enable */
+	pci_write_config_byte(dev, 0x5a, (reg5ah & ~0x10));
+#endif
+
+	/*
+	 * default to pci clock. make sure MA15/16 are set to output
+	 * to prevent drives having problems with 40-pin cables.
+	 */
+	pci_write_config_byte(dev, 0x5b, 0x23);
+
+	/*
+	 * set up the PLL. we need to adjust it so that it's stable. 
+	 * freq = Tpll * 192 / Tpci
+	 */
+	pci_read_config_word(dev, 0x78, &freq);
+	freq &= 0x1FF;
+	if (freq < 0x9c) {
+		pll = F_LOW_PCI_33;
+		if (hpt_minimum_revision(dev,8))
+			pci_set_drvdata(dev, (void *) thirty_three_base_hpt374);
+		else if (hpt_minimum_revision(dev,5))
+			pci_set_drvdata(dev, (void *) thirty_three_base_hpt372);
+		else if (hpt_minimum_revision(dev,4))
+			pci_set_drvdata(dev, (void *) thirty_three_base_hpt370a);
+		else
+			pci_set_drvdata(dev, (void *) thirty_three_base_hpt370);
+		printk("HPT37X: using 33MHz PCI clock\n");
+	} else if (freq < 0xb0) {
+		pll = F_LOW_PCI_40;
+	} else if (freq < 0xc8) {
+		pll = F_LOW_PCI_50;
+		if (hpt_minimum_revision(dev,8))
+			return -EOPNOTSUPP;
+		else if (hpt_minimum_revision(dev,5))
+			pci_set_drvdata(dev, (void *) fifty_base_hpt372);
+		else if (hpt_minimum_revision(dev,4))
+			pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
+		else
+			pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
+		printk("HPT37X: using 50MHz PCI clock\n");
+	} else {
+		pll = F_LOW_PCI_66;
+		if (hpt_minimum_revision(dev,8))
+		{
+			printk(KERN_ERR "HPT37x: 66MHz timings are not supported.\n");
+			return -EOPNOTSUPP;
+		}
+		else if (hpt_minimum_revision(dev,5))
+			pci_set_drvdata(dev, (void *) sixty_six_base_hpt372);
+		else if (hpt_minimum_revision(dev,4))
+			pci_set_drvdata(dev, (void *) sixty_six_base_hpt370a);
+		else
+			pci_set_drvdata(dev, (void *) sixty_six_base_hpt370);
+		printk("HPT37X: using 66MHz PCI clock\n");
+	}
+	
+	/*
+	 * only try the pll if we don't have a table for the clock
+	 * speed that we're running at. NOTE: the internal PLL will
+	 * result in slow reads when using a 33MHz PCI clock. we also
+	 * don't like to use the PLL because it will cause glitches
+	 * on PRST/SRST when the HPT state engine gets reset.
+	 */
+	if (pci_get_drvdata(dev)) 
+		goto init_hpt37X_done;
+	
+	/*
+	 * adjust PLL based upon PCI clock, enable it, and wait for
+	 * stabilization.
+	 */
+	adjust = 0;
+	freq = (pll < F_LOW_PCI_50) ? 2 : 4;
+	while (adjust++ < 6) {
+		pci_write_config_dword(dev, 0x5c, (freq + pll) << 16 |
+				       pll | 0x100);
+
+		/* wait for clock stabilization */
+		for (i = 0; i < 0x50000; i++) {
+			pci_read_config_byte(dev, 0x5b, &reg5bh);
+			if (reg5bh & 0x80) {
+				/* spin looking for the clock to destabilize */
+				for (i = 0; i < 0x1000; ++i) {
+					pci_read_config_byte(dev, 0x5b, 
+							     &reg5bh);
+					if ((reg5bh & 0x80) == 0)
+						goto pll_recal;
+				}
+				pci_read_config_dword(dev, 0x5c, &pll);
+				pci_write_config_dword(dev, 0x5c, 
+						       pll & ~0x100);
+				pci_write_config_byte(dev, 0x5b, 0x21);
+				if (hpt_minimum_revision(dev,8))
+					return -EOPNOTSUPP;
+				else if (hpt_minimum_revision(dev,5))
+					pci_set_drvdata(dev, (void *) fifty_base_hpt372);
+				else if (hpt_minimum_revision(dev,4))
+					pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
+				else
+					pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
+				printk("HPT37X: using 50MHz internal PLL\n");
+				goto init_hpt37X_done;
+			}
+		}
+pll_recal:
+		if (adjust & 1)
+			pll -= (adjust >> 1);
+		else
+			pll += (adjust >> 1);
+	} 
+
+init_hpt37X_done:
+	/* reset state engine */
+	pci_write_config_byte(dev, 0x50, 0x37); 
+	pci_write_config_byte(dev, 0x54, 0x37); 
+	udelay(100);
+	return 0;
+}
+
+static int __init init_hpt366 (struct pci_dev *dev)
+{
+	u32 reg1	= 0;
+	u8 drive_fast	= 0;
+
+	/*
+	 * Disable the "fast interrupt" prediction.
+	 */
+	pci_read_config_byte(dev, 0x51, &drive_fast);
+	if (drive_fast & 0x80)
+		pci_write_config_byte(dev, 0x51, drive_fast & ~0x80);
+	pci_read_config_dword(dev, 0x40, &reg1);
+									
+	/* detect bus speed by looking at control reg timing: */
+	switch((reg1 >> 8) & 7) {
+		case 5:
+			pci_set_drvdata(dev, (void *) forty_base_hpt366);
+			break;
+		case 9:
+			pci_set_drvdata(dev, (void *) twenty_five_base_hpt366);
+			break;
+		case 7:
+		default:
+			pci_set_drvdata(dev, (void *) thirty_three_base_hpt366);
+			break;
+	}
+
+	if (!pci_get_drvdata(dev))
+	{
+		printk(KERN_ERR "hpt366: unknown bus timing.\n");
+		return -EOPNOTSUPP;
+	}
+	return 0;
+}
+
+static unsigned int __init init_chipset_hpt366 (struct pci_dev *dev, const char *name)
+{
+	int ret = 0;
+	u8 test = 0;
+
+	if (dev->resource[PCI_ROM_RESOURCE].start)
+		pci_write_config_byte(dev, PCI_ROM_ADDRESS,
+			dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+
+	pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &test);
+	if (test != (L1_CACHE_BYTES / 4))
+		pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
+			(L1_CACHE_BYTES / 4));
+
+	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &test);
+	if (test != 0x78)
+		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
+
+	pci_read_config_byte(dev, PCI_MIN_GNT, &test);
+	if (test != 0x08)
+		pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
+
+	pci_read_config_byte(dev, PCI_MAX_LAT, &test);
+	if (test != 0x08)
+		pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
+
+	if (hpt_minimum_revision(dev, 3)) {
+		ret = init_hpt37x(dev);
+	} else {
+		ret =init_hpt366(dev);
+	}
+	if (ret)
+		return ret;
+	
+#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
+	hpt_devs[n_hpt_devs++] = dev;
+
+	if (!hpt366_proc) {
+		hpt366_proc = 1;
+		ide_pci_register_host_proc(&hpt366_procs[0]);
+	}
+#endif /* DISPLAY_HPT366_TIMINGS && CONFIG_PROC_FS */
+
+	return dev->irq;
+}
+
+static void __init init_hwif_hpt366 (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev		= hwif->pci_dev;
+	u8 ata66 = 0, regmask		= (hwif->channel) ? 0x01 : 0x02;
+
+	hwif->tuneproc			= &hpt3xx_tune_drive;
+	hwif->speedproc			= &hpt3xx_tune_chipset;
+	hwif->quirkproc			= &hpt3xx_quirkproc;
+	hwif->intrproc			= &hpt3xx_intrproc;
+	hwif->maskproc			= &hpt3xx_maskproc;
+
+	pci_read_config_byte(hwif->pci_dev, 0x5a, &ata66);
+
+#ifdef DEBUG
+	printk("HPT366: reg5ah=0x%02x ATA-%s Cable Port%d\n",
+		ata66, (ata66 & regmask) ? "33" : "66",
+		PCI_FUNC(hwif->pci_dev->devfn));
+#endif /* DEBUG */
+
+#ifdef HPT_SERIALIZE_IO
+	/* serialize access to this device */
+	if (hwif->mate)
+		hwif->serialized = hwif->mate->serialized = 1;
+#endif
+
+	if (hpt_minimum_revision(dev,3)) {
+		u8 reg5ah = 0;
+			pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10);
+		/*
+		 * set up ioctl for power status.
+		 * note: power affects both
+		 * drives on each channel
+		 */
+		hwif->resetproc	= &hpt3xx_reset;
+		hwif->busproc	= &hpt370_busproc;
+//		hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
+	} else if (hpt_minimum_revision(dev,2)) {
+		hwif->resetproc	= &hpt3xx_reset;
+		hwif->busproc	= &hpt3xx_tristate;
+	} else {
+		hwif->resetproc = &hpt3xx_reset;
+		hwif->busproc   = &hpt3xx_tristate;
+	}
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->ultra_mask = 0x7f;
+	hwif->mwdma_mask = 0x07;
+
+	if (!(hwif->udma_four))
+		hwif->udma_four = ((ata66 & regmask) ? 0 : 1);
+	hwif->ide_dma_check = &hpt366_config_drive_xfer_rate;
+
+	if (hpt_minimum_revision(dev,8))
+		hwif->ide_dma_end = &hpt374_ide_dma_end;
+	else if (hpt_minimum_revision(dev,5))
+		hwif->ide_dma_end = &hpt374_ide_dma_end;
+	else if (hpt_minimum_revision(dev,3)) {
+		hwif->ide_dma_begin = &hpt370_ide_dma_begin;
+		hwif->ide_dma_end = &hpt370_ide_dma_end;
+		hwif->ide_dma_timeout = &hpt370_ide_dma_timeout;
+		hwif->ide_dma_lostirq = &hpt370_ide_dma_lostirq;
+	} else if (hpt_minimum_revision(dev,2))
+		hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq;
+	else
+		hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq;
+
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+static void __init init_dma_hpt366 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	u8 masterdma	= 0, slavedma = 0;
+	u8 dma_new	= 0, dma_old = 0;
+	u8 primary	= hwif->channel ? 0x4b : 0x43;
+	u8 secondary	= hwif->channel ? 0x4f : 0x47;
+	unsigned long flags;
+
+	if (!dmabase)
+		return;
+
+	dma_old = hwif->INB(dmabase+2);
+
+	local_irq_save(flags);
+
+	dma_new = dma_old;
+	pci_read_config_byte(hwif->pci_dev, primary, &masterdma);
+	pci_read_config_byte(hwif->pci_dev, secondary, &slavedma);
+
+	if (masterdma & 0x30)	dma_new |= 0x20;
+	if (slavedma & 0x30)	dma_new |= 0x40;
+	if (dma_new != dma_old)
+		hwif->OUTB(dma_new, dmabase+2);
+
+	local_irq_restore(flags);
+
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+extern void ide_setup_pci_devices(struct pci_dev *, struct pci_dev *, ide_pci_device_t *);
+
+static void __init init_setup_hpt374 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	struct pci_dev *findev = NULL;
+
+	if (PCI_FUNC(dev->devfn) & 1)
+		return;
+
+	pci_for_each_dev(findev) {
+		if ((findev->vendor == dev->vendor) &&
+		    (findev->device == dev->device) &&
+		    ((findev->devfn - dev->devfn) == 1) &&
+		    (PCI_FUNC(findev->devfn) & 1)) {
+			u8 irq = 0, irq2 = 0;
+			pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+			pci_read_config_byte(findev, PCI_INTERRUPT_LINE, &irq2);
+			if (irq != irq2) {
+				pci_write_config_byte(findev,
+						PCI_INTERRUPT_LINE, irq);
+				findev->irq = dev->irq;
+				printk("%s: pci-config space interrupt "
+					"fixed.\n", d->name);
+			}
+			ide_setup_pci_devices(dev, findev, d);
+			return;
+		}
+	}
+	ide_setup_pci_device(dev, d);
+}
+
+static void __init init_setup_hpt37x (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+static void __init init_setup_hpt366 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	struct pci_dev *findev = NULL;
+	u8 pin1 = 0, pin2 = 0;
+	unsigned int class_rev;
+	char *chipset_names[] = {"HPT366", "HPT366",  "HPT368",
+				 "HPT370", "HPT370A", "HPT372"};
+
+	if (PCI_FUNC(dev->devfn) & 1)
+		return;
+
+	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+	class_rev &= 0xff;
+
+	strcpy(d->name, chipset_names[class_rev]);
+
+	switch(class_rev) {
+		case 5:
+		case 4:
+		case 3: ide_setup_pci_device(dev, d);
+			return;
+		default:	break;
+	}
+
+	d->channels = 1;
+
+	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1);
+	pci_for_each_dev(findev) {
+		if ((findev->vendor == dev->vendor) &&
+		    (findev->device == dev->device) &&
+		    ((findev->devfn - dev->devfn) == 1) &&
+		    (PCI_FUNC(findev->devfn) & 1)) {
+			pci_read_config_byte(findev, PCI_INTERRUPT_PIN, &pin2);
+			if ((pin1 != pin2) && (dev->irq == findev->irq)) {
+				d->bootable = ON_BOARD;
+				printk("%s: onboard version of chipset, "
+					"pin1=%d pin2=%d\n", d->name,
+					pin1, pin2);
+			}
+			ide_setup_pci_devices(dev, findev, d);
+			return;
+		}
+	}
+	ide_setup_pci_device(dev, d);
+}
+
+
+/**
+ *	hpt366_init_one	-	called when an HPT366 is found
+ *	@dev: the hpt366 device
+ *	@id: the matching pci id
+ *
+ *	Called when the PCI registration layer (or the IDE initialization)
+ *	finds a device matching our IDE device tables.
+ */
+ 
+static int __devinit hpt366_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &hpt366_chipsets[id->driver_data];
+
+	if (dev->device != d->device)
+		BUG();
+	d->init_setup(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id hpt366_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT366, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT372, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT302, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+	{ PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT371, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+	{ PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT374, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "HPT366 IDE",
+	.id_table	= hpt366_pci_tbl,
+	.probe		= hpt366_init_one,
+};
+
+static int hpt366_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void hpt366_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(hpt366_ide_init);
+module_exit(hpt366_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for Highpoint HPT366 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/hpt366.h linux-2.4.21-pre6/drivers/ide/pci/hpt366.h
--- linux-2.4.20/drivers/ide/pci/hpt366.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/hpt366.h	2003-03-26 23:49:54.000000000 +0000
@@ -0,0 +1,523 @@
+#ifndef HPT366_H
+#define HPT366_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_HPT366_TIMINGS
+
+/* various tuning parameters */
+#define HPT_RESET_STATE_ENGINE
+#undef HPT_DELAY_INTERRUPT
+#undef HPT_SERIALIZE_IO
+
+const char *quirk_drives[] = {
+	"QUANTUM FIREBALLlct08 08",
+	"QUANTUM FIREBALLP KA6.4",
+	"QUANTUM FIREBALLP LM20.4",
+	"QUANTUM FIREBALLP LM20.5",
+        NULL
+};
+
+const char *bad_ata100_5[] = {
+	"IBM-DTLA-307075",
+	"IBM-DTLA-307060",
+	"IBM-DTLA-307045",
+	"IBM-DTLA-307030",
+	"IBM-DTLA-307020",
+	"IBM-DTLA-307015",
+	"IBM-DTLA-305040",
+	"IBM-DTLA-305030",
+	"IBM-DTLA-305020",
+	"IC35L010AVER07-0",
+	"IC35L020AVER07-0",
+	"IC35L030AVER07-0",
+	"IC35L040AVER07-0",
+	"IC35L060AVER07-0",
+	"WDC AC310200R",
+	NULL
+};
+
+const char *bad_ata66_4[] = {
+	"IBM-DTLA-307075",
+	"IBM-DTLA-307060",
+	"IBM-DTLA-307045",
+	"IBM-DTLA-307030",
+	"IBM-DTLA-307020",
+	"IBM-DTLA-307015",
+	"IBM-DTLA-305040",
+	"IBM-DTLA-305030",
+	"IBM-DTLA-305020",
+	"IC35L010AVER07-0",
+	"IC35L020AVER07-0",
+	"IC35L030AVER07-0",
+	"IC35L040AVER07-0",
+	"IC35L060AVER07-0",
+	"WDC AC310200R",
+	NULL
+};
+
+const char *bad_ata66_3[] = {
+	"WDC AC310200R",
+	NULL
+};
+
+const char *bad_ata33[] = {
+	"Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3", "Maxtor 90845U3", "Maxtor 90650U2",
+	"Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5", "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2",
+	"Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6", "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4",
+	"Maxtor 90510D4",
+	"Maxtor 90432D3", "Maxtor 90288D2", "Maxtor 90256D2",
+	"Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7", "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4",
+	"Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5", "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2",
+	NULL
+};
+
+struct chipset_bus_clock_list_entry {
+	byte		xfer_speed;
+	unsigned int	chipset_settings;
+};
+
+/* key for bus clock timings
+ * bit
+ * 0:3    data_high_time. inactive time of DIOW_/DIOR_ for PIO and MW
+ *        DMA. cycles = value + 1
+ * 4:8    data_low_time. active time of DIOW_/DIOR_ for PIO and MW
+ *        DMA. cycles = value + 1
+ * 9:12   cmd_high_time. inactive time of DIOW_/DIOR_ during task file
+ *        register access.
+ * 13:17  cmd_low_time. active time of DIOW_/DIOR_ during task file
+ *        register access.
+ * 18:21  udma_cycle_time. clock freq and clock cycles for UDMA xfer.
+ *        during task file register access.
+ * 22:24  pre_high_time. time to initialize 1st cycle for PIO and MW DMA
+ *        xfer.
+ * 25:27  cmd_pre_high_time. time to initialize 1st PIO cycle for task
+ *        register access.
+ * 28     UDMA enable
+ * 29     DMA enable
+ * 30     PIO_MST enable. if set, the chip is in bus master mode during
+ *        PIO.
+ * 31     FIFO enable.
+ */
+struct chipset_bus_clock_list_entry forty_base_hpt366[] = {
+	{	XFER_UDMA_4,	0x900fd943	},
+	{	XFER_UDMA_3,	0x900ad943	},
+	{	XFER_UDMA_2,	0x900bd943	},
+	{	XFER_UDMA_1,	0x9008d943	},
+	{	XFER_UDMA_0,	0x9008d943	},
+
+	{	XFER_MW_DMA_2,	0xa008d943	},
+	{	XFER_MW_DMA_1,	0xa010d955	},
+	{	XFER_MW_DMA_0,	0xa010d9fc	},
+
+	{	XFER_PIO_4,	0xc008d963	},
+	{	XFER_PIO_3,	0xc010d974	},
+	{	XFER_PIO_2,	0xc010d997	},
+	{	XFER_PIO_1,	0xc010d9c7	},
+	{	XFER_PIO_0,	0xc018d9d9	},
+	{	0,		0x0120d9d9	}
+};
+
+struct chipset_bus_clock_list_entry thirty_three_base_hpt366[] = {
+	{	XFER_UDMA_4,	0x90c9a731	},
+	{	XFER_UDMA_3,	0x90cfa731	},
+	{	XFER_UDMA_2,	0x90caa731	},
+	{	XFER_UDMA_1,	0x90cba731	},
+	{	XFER_UDMA_0,	0x90c8a731	},
+
+	{	XFER_MW_DMA_2,	0xa0c8a731	},
+	{	XFER_MW_DMA_1,	0xa0c8a732	},	/* 0xa0c8a733 */
+	{	XFER_MW_DMA_0,	0xa0c8a797	},
+
+	{	XFER_PIO_4,	0xc0c8a731	},
+	{	XFER_PIO_3,	0xc0c8a742	},
+	{	XFER_PIO_2,	0xc0d0a753	},
+	{	XFER_PIO_1,	0xc0d0a7a3	},	/* 0xc0d0a793 */
+	{	XFER_PIO_0,	0xc0d0a7aa	},	/* 0xc0d0a7a7 */
+	{	0,		0x0120a7a7	}
+};
+
+struct chipset_bus_clock_list_entry twenty_five_base_hpt366[] = {
+
+	{	XFER_UDMA_4,	0x90c98521	},
+	{	XFER_UDMA_3,	0x90cf8521	},
+	{	XFER_UDMA_2,	0x90cf8521	},
+	{	XFER_UDMA_1,	0x90cb8521	},
+	{	XFER_UDMA_0,	0x90cb8521	},
+
+	{	XFER_MW_DMA_2,	0xa0ca8521	},
+	{	XFER_MW_DMA_1,	0xa0ca8532	},
+	{	XFER_MW_DMA_0,	0xa0ca8575	},
+
+	{	XFER_PIO_4,	0xc0ca8521	},
+	{	XFER_PIO_3,	0xc0ca8532	},
+	{	XFER_PIO_2,	0xc0ca8542	},
+	{	XFER_PIO_1,	0xc0d08572	},
+	{	XFER_PIO_0,	0xc0d08585	},
+	{	0,		0x01208585	}
+};
+
+/* from highpoint documentation. these are old values */
+struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = {
+/*	{	XFER_UDMA_5,	0x1A85F442,	0x16454e31	}, */
+	{	XFER_UDMA_5,	0x16454e31	},
+	{	XFER_UDMA_4,	0x16454e31	},
+	{	XFER_UDMA_3,	0x166d4e31	},
+	{	XFER_UDMA_2,	0x16494e31	},
+	{	XFER_UDMA_1,	0x164d4e31	},
+	{	XFER_UDMA_0,	0x16514e31	},
+
+	{	XFER_MW_DMA_2,	0x26514e21	},
+	{	XFER_MW_DMA_1,	0x26514e33	},
+	{	XFER_MW_DMA_0,	0x26514e97	},
+
+	{	XFER_PIO_4,	0x06514e21	},
+	{	XFER_PIO_3,	0x06514e22	},
+	{	XFER_PIO_2,	0x06514e33	},
+	{	XFER_PIO_1,	0x06914e43	},
+	{	XFER_PIO_0,	0x06914e57	},
+	{	0,		0x06514e57	}
+};
+
+struct chipset_bus_clock_list_entry sixty_six_base_hpt370[] = {
+	{       XFER_UDMA_5,    0x14846231      },
+	{       XFER_UDMA_4,    0x14886231      },
+	{       XFER_UDMA_3,    0x148c6231      },
+	{       XFER_UDMA_2,    0x148c6231      },
+	{       XFER_UDMA_1,    0x14906231      },
+	{       XFER_UDMA_0,    0x14986231      },
+	
+	{       XFER_MW_DMA_2,  0x26514e21      },
+	{       XFER_MW_DMA_1,  0x26514e33      },
+	{       XFER_MW_DMA_0,  0x26514e97      },
+	
+	{       XFER_PIO_4,     0x06514e21      },
+	{       XFER_PIO_3,     0x06514e22      },
+	{       XFER_PIO_2,     0x06514e33      },
+	{       XFER_PIO_1,     0x06914e43      },
+	{       XFER_PIO_0,     0x06914e57      },
+	{       0,              0x06514e57      }
+};
+
+/* these are the current (4 sep 2001) timings from highpoint */
+struct chipset_bus_clock_list_entry thirty_three_base_hpt370a[] = {
+        {       XFER_UDMA_5,    0x12446231      },
+        {       XFER_UDMA_4,    0x12446231      },
+        {       XFER_UDMA_3,    0x126c6231      },
+        {       XFER_UDMA_2,    0x12486231      },
+        {       XFER_UDMA_1,    0x124c6233      },
+        {       XFER_UDMA_0,    0x12506297      },
+
+        {       XFER_MW_DMA_2,  0x22406c31      },
+        {       XFER_MW_DMA_1,  0x22406c33      },
+        {       XFER_MW_DMA_0,  0x22406c97      },
+
+        {       XFER_PIO_4,     0x06414e31      },
+        {       XFER_PIO_3,     0x06414e42      },
+        {       XFER_PIO_2,     0x06414e53      },
+        {       XFER_PIO_1,     0x06814e93      },
+        {       XFER_PIO_0,     0x06814ea7      },
+        {       0,              0x06814ea7      }
+};
+
+/* 2x 33MHz timings */
+struct chipset_bus_clock_list_entry sixty_six_base_hpt370a[] = {
+	{       XFER_UDMA_5,    0x1488e673       },
+	{       XFER_UDMA_4,    0x1488e673       },
+	{       XFER_UDMA_3,    0x1498e673       },
+	{       XFER_UDMA_2,    0x1490e673       },
+	{       XFER_UDMA_1,    0x1498e677       },
+	{       XFER_UDMA_0,    0x14a0e73f       },
+
+	{       XFER_MW_DMA_2,  0x2480fa73       },
+	{       XFER_MW_DMA_1,  0x2480fa77       }, 
+	{       XFER_MW_DMA_0,  0x2480fb3f       },
+
+	{       XFER_PIO_4,     0x0c82be73       },
+	{       XFER_PIO_3,     0x0c82be95       },
+	{       XFER_PIO_2,     0x0c82beb7       },
+	{       XFER_PIO_1,     0x0d02bf37       },
+	{       XFER_PIO_0,     0x0d02bf5f       },
+	{       0,              0x0d02bf5f       }
+};
+
+struct chipset_bus_clock_list_entry fifty_base_hpt370a[] = {
+	{       XFER_UDMA_5,    0x12848242      },
+	{       XFER_UDMA_4,    0x12ac8242      },
+	{       XFER_UDMA_3,    0x128c8242      },
+	{       XFER_UDMA_2,    0x120c8242      },
+	{       XFER_UDMA_1,    0x12148254      },
+	{       XFER_UDMA_0,    0x121882ea      },
+
+	{       XFER_MW_DMA_2,  0x22808242      },
+	{       XFER_MW_DMA_1,  0x22808254      },
+	{       XFER_MW_DMA_0,  0x228082ea      },
+
+	{       XFER_PIO_4,     0x0a81f442      },
+	{       XFER_PIO_3,     0x0a81f443      },
+	{       XFER_PIO_2,     0x0a81f454      },
+	{       XFER_PIO_1,     0x0ac1f465      },
+	{       XFER_PIO_0,     0x0ac1f48a      },
+	{       0,              0x0ac1f48a      }
+};
+
+struct chipset_bus_clock_list_entry thirty_three_base_hpt372[] = {
+	{	XFER_UDMA_6,	0x1c81dc62	},
+	{	XFER_UDMA_5,	0x1c6ddc62	},
+	{	XFER_UDMA_4,	0x1c8ddc62	},
+	{	XFER_UDMA_3,	0x1c8edc62	},	/* checkme */
+	{	XFER_UDMA_2,	0x1c91dc62	},
+	{	XFER_UDMA_1,	0x1c9adc62	},	/* checkme */
+	{	XFER_UDMA_0,	0x1c82dc62	},	/* checkme */
+
+	{	XFER_MW_DMA_2,	0x2c829262	},
+	{	XFER_MW_DMA_1,	0x2c829266	},	/* checkme */
+	{	XFER_MW_DMA_0,	0x2c82922e	},	/* checkme */
+
+	{	XFER_PIO_4,	0x0c829c62	},
+	{	XFER_PIO_3,	0x0c829c84	},
+	{	XFER_PIO_2,	0x0c829ca6	},
+	{	XFER_PIO_1,	0x0d029d26	},
+	{	XFER_PIO_0,	0x0d029d5e	},
+	{	0,		0x0d029d5e	}
+};
+
+struct chipset_bus_clock_list_entry fifty_base_hpt372[] = {
+	{	XFER_UDMA_5,	0x12848242	},
+	{	XFER_UDMA_4,	0x12ac8242	},
+	{	XFER_UDMA_3,	0x128c8242	},
+	{	XFER_UDMA_2,	0x120c8242	},
+	{	XFER_UDMA_1,	0x12148254	},
+	{	XFER_UDMA_0,	0x121882ea	},
+
+	{	XFER_MW_DMA_2,	0x22808242	},
+	{	XFER_MW_DMA_1,	0x22808254	},
+	{	XFER_MW_DMA_0,	0x228082ea	},
+
+	{	XFER_PIO_4,	0x0a81f442	},
+	{	XFER_PIO_3,	0x0a81f443	},
+	{	XFER_PIO_2,	0x0a81f454	},
+	{	XFER_PIO_1,	0x0ac1f465	},
+	{	XFER_PIO_0,	0x0ac1f48a	},
+	{	0,		0x0a81f443	}
+};
+
+struct chipset_bus_clock_list_entry sixty_six_base_hpt372[] = {
+	{	XFER_UDMA_6,	0x1c869c62	},
+	{	XFER_UDMA_5,	0x1cae9c62	},
+	{	XFER_UDMA_4,	0x1c8a9c62	},
+	{	XFER_UDMA_3,	0x1c8e9c62	},
+	{	XFER_UDMA_2,	0x1c929c62	},
+	{	XFER_UDMA_1,	0x1c9a9c62	},
+	{	XFER_UDMA_0,	0x1c829c62	},
+
+	{	XFER_MW_DMA_2,	0x2c829c62	},
+	{	XFER_MW_DMA_1,	0x2c829c66	},
+	{	XFER_MW_DMA_0,	0x2c829d2e	},
+
+	{	XFER_PIO_4,	0x0c829c62	},
+	{	XFER_PIO_3,	0x0c829c84	},
+	{	XFER_PIO_2,	0x0c829ca6	},
+	{	XFER_PIO_1,	0x0d029d26	},
+	{	XFER_PIO_0,	0x0d029d5e	},
+	{	0,		0x0d029d26	}
+};
+
+struct chipset_bus_clock_list_entry thirty_three_base_hpt374[] = {
+	{	XFER_UDMA_6,	0x12808242	},
+	{	XFER_UDMA_5,	0x12848242	},
+	{	XFER_UDMA_4,	0x12ac8242	},
+	{	XFER_UDMA_3,	0x128c8242	},
+	{	XFER_UDMA_2,	0x120c8242	},
+	{	XFER_UDMA_1,	0x12148254	},
+	{	XFER_UDMA_0,	0x121882ea	},
+
+	{	XFER_MW_DMA_2,	0x22808242	},
+	{	XFER_MW_DMA_1,	0x22808254	},
+	{	XFER_MW_DMA_0,	0x228082ea	},
+
+	{	XFER_PIO_4,	0x0a81f442	},
+	{	XFER_PIO_3,	0x0a81f443	},
+	{	XFER_PIO_2,	0x0a81f454	},
+	{	XFER_PIO_1,	0x0ac1f465	},
+	{	XFER_PIO_0,	0x0ac1f48a	},
+	{	0,		0x06814e93	}
+};
+
+#if 0
+struct chipset_bus_clock_list_entry fifty_base_hpt374[] = {
+	{	XFER_UDMA_6,	},
+	{	XFER_UDMA_5,	},
+	{	XFER_UDMA_4,	},
+	{	XFER_UDMA_3,	},
+	{	XFER_UDMA_2,	},
+	{	XFER_UDMA_1,	},
+	{	XFER_UDMA_0,	},
+	{	XFER_MW_DMA_2,	},
+	{	XFER_MW_DMA_1,	},
+	{	XFER_MW_DMA_0,	},
+	{	XFER_PIO_4,	},
+	{	XFER_PIO_3,	},
+	{	XFER_PIO_2,	},
+	{	XFER_PIO_1,	},
+	{	XFER_PIO_0,	},
+	{	0,	}
+};
+#endif
+#if 0
+struct chipset_bus_clock_list_entry sixty_six_base_hpt374[] = {
+	{	XFER_UDMA_6,	0x12406231	},	/* checkme */
+	{	XFER_UDMA_5,	0x12446231	},
+				0x14846231
+	{	XFER_UDMA_4,		0x16814ea7	},
+				0x14886231
+	{	XFER_UDMA_3,		0x16814ea7	},
+				0x148c6231
+	{	XFER_UDMA_2,		0x16814ea7	},
+				0x148c6231
+	{	XFER_UDMA_1,		0x16814ea7	},
+				0x14906231
+	{	XFER_UDMA_0,		0x16814ea7	},
+				0x14986231
+	{	XFER_MW_DMA_2,		0x16814ea7	},
+				0x26514e21
+	{	XFER_MW_DMA_1,		0x16814ea7	},
+				0x26514e97
+	{	XFER_MW_DMA_0,		0x16814ea7	},
+				0x26514e97
+	{	XFER_PIO_4,		0x06814ea7	},
+				0x06514e21
+	{	XFER_PIO_3,		0x06814ea7	},
+				0x06514e22
+	{	XFER_PIO_2,		0x06814ea7	},
+				0x06514e33
+	{	XFER_PIO_1,		0x06814ea7	},
+				0x06914e43
+	{	XFER_PIO_0,		0x06814ea7	},
+				0x06914e57
+	{	0,		0x06814ea7	}
+};
+#endif
+
+#define HPT366_DEBUG_DRIVE_INFO		0
+#define HPT374_ALLOW_ATA133_6		0
+#define HPT371_ALLOW_ATA133_6		0
+#define HPT302_ALLOW_ATA133_6		0
+#define HPT372_ALLOW_ATA133_6		1
+#define HPT370_ALLOW_ATA100_5		1
+#define HPT366_ALLOW_ATA66_4		1
+#define HPT366_ALLOW_ATA66_3		1
+#define HPT366_MAX_DEVS			8
+
+#define F_LOW_PCI_33      0x23
+#define F_LOW_PCI_40      0x29
+#define F_LOW_PCI_50      0x2d
+#define F_LOW_PCI_66      0x42
+
+#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 hpt366_proc;
+
+static int hpt366_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t hpt366_procs[] __initdata = {
+	{
+		.name		= "hpt366",
+		.set		= 1,
+		.get_info	= hpt366_get_info,
+		.parent		= NULL,
+	},
+};
+#endif  /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static void init_setup_hpt366(struct pci_dev *, ide_pci_device_t *);
+static void init_setup_hpt37x(struct pci_dev *, ide_pci_device_t *);
+static void init_setup_hpt374(struct pci_dev *, ide_pci_device_t *);
+static unsigned int init_chipset_hpt366(struct pci_dev *, const char *);
+static void init_hwif_hpt366(ide_hwif_t *);
+static void init_dma_hpt366(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_TTI,
+		.device		= PCI_DEVICE_ID_TTI_HPT366,
+		.name		= "HPT366",
+		.init_setup	= init_setup_hpt366,
+		.init_chipset	= init_chipset_hpt366,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_hpt366,
+		.init_dma	= init_dma_hpt366,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 240
+	},{	/* 1 */
+		.vendor		= PCI_VENDOR_ID_TTI,
+		.device		= PCI_DEVICE_ID_TTI_HPT372,
+		.name		= "HPT372A",
+		.init_setup	= init_setup_hpt37x,
+		.init_chipset	= init_chipset_hpt366,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_hpt366,
+		.init_dma	= init_dma_hpt366,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0
+	},{	/* 2 */
+		.vendor		= PCI_VENDOR_ID_TTI,
+		.device		= PCI_DEVICE_ID_TTI_HPT302,
+		.name		= "HPT302",
+		.init_setup	= init_setup_hpt37x,
+		.init_chipset	= init_chipset_hpt366,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_hpt366,
+		.init_dma	= init_dma_hpt366,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0
+	},{	/* 3 */
+		.vendor		= PCI_VENDOR_ID_TTI,
+		.device		= PCI_DEVICE_ID_TTI_HPT371,
+		.name		= "HPT371",
+		.init_setup	= init_setup_hpt37x,
+		.init_chipset	= init_chipset_hpt366,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_hpt366,
+		.init_dma	= init_dma_hpt366,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0
+	},{	/* 4 */
+		.vendor		= PCI_VENDOR_ID_TTI,
+		.device		= PCI_DEVICE_ID_TTI_HPT374,
+		.name		= "HPT374",
+		.init_setup	= init_setup_hpt374,
+		.init_chipset	= init_chipset_hpt366,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_hpt366,
+		.init_dma	= init_dma_hpt366,
+		.channels	= 2,	/* 4 */
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* HPT366_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/it8172.c linux-2.4.21-pre6/drivers/ide/pci/it8172.c
--- linux-2.4.20/drivers/ide/pci/it8172.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/it8172.c	2003-03-26 23:49:00.000000000 +0000
@@ -0,0 +1,334 @@
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ *      IT8172 IDE controller support
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *              stevel@mvista.com or source@mvista.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  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.
+ *
+ *  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/types.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/it8172/it8172_int.h>
+
+#include "ide_modes.h"
+#include "it8172.h"
+
+/*
+ * Prototypes
+ */
+static u8 it8172_ratemask (ide_drive_t *drive)
+{
+	return 1;
+}
+
+static void it8172_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	int is_slave		= (hwif->drives[1] == drive);
+	unsigned long flags;
+	u16 drive_enables;
+	u32 drive_timing;
+
+	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+	spin_lock_irqsave(&ide_lock, flags);
+	pci_read_config_word(dev, 0x40, &drive_enables);
+	pci_read_config_dword(dev, 0x44, &drive_timing);
+
+	/*
+	 * FIX! The DIOR/DIOW pulse width and recovery times in port 0x44
+	 * are being left at the default values of 8 PCI clocks (242 nsec
+	 * for a 33 MHz clock). These can be safely shortened at higher
+	 * PIO modes. The DIOR/DIOW pulse width and recovery times only
+	 * apply to PIO modes, not to the DMA modes.
+	 */
+
+	/*
+	 * Enable port 0x44. The IT8172G spec is confused; it calls
+	 * this register the "Slave IDE Timing Register", but in fact,
+	 * it controls timing for both master and slave drives.
+	 */
+	drive_enables |= 0x4000;
+
+	if (is_slave) {
+		drive_enables &= 0xc006;
+		if (pio > 1)
+			/* enable prefetch and IORDY sample-point */
+			drive_enables |= 0x0060;
+	} else {
+		drive_enables &= 0xc060;
+		if (pio > 1)
+			/* enable prefetch and IORDY sample-point */
+			drive_enables |= 0x0006;
+	}
+
+	pci_write_config_word(dev, 0x40, drive_enables);
+	spin_unlock_irqrestore(&ide_lock, flags)
+}
+
+static u8 it8172_dma_2_pio (u8 xfer_rate)
+{
+	switch(xfer_rate) {
+		case XFER_UDMA_5:
+		case XFER_UDMA_4:
+		case XFER_UDMA_3:
+		case XFER_UDMA_2:
+		case XFER_UDMA_1:
+		case XFER_UDMA_0:
+		case XFER_MW_DMA_2:
+		case XFER_PIO_4:
+			return 4;
+		case XFER_MW_DMA_1:
+		case XFER_PIO_3:
+			return 3;
+		case XFER_SW_DMA_2:
+		case XFER_PIO_2:
+			return 2;
+		case XFER_MW_DMA_0:
+		case XFER_SW_DMA_1:
+		case XFER_SW_DMA_0:
+		case XFER_PIO_1:
+		case XFER_PIO_0:
+		case XFER_PIO_SLOW:
+		default:
+			return 0;
+	}
+}
+
+static int it8172_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 speed	= ide_rate_filter(it8172_ratemask(drive), xferspeed);
+	int a_speed		= 3 << (drive->dn * 4);
+	int u_flag		= 1 << drive->dn;
+	int u_speed		= 0;
+	u8 reg48, reg4a;
+
+	pci_read_config_byte(dev, 0x48, &reg48);
+	pci_read_config_byte(dev, 0x4a, &reg4a);
+
+    /*
+     * Setting the DMA cycle time to 2 or 3 PCI clocks (60 and 91 nsec
+     * at 33 MHz PCI clock) seems to cause BadCRC errors during DMA
+     * transfers on some drives, even though both numbers meet the minimum
+     * ATAPI-4 spec of 73 and 54 nsec for UDMA 1 and 2 respectively.
+     * So the faster times are just commented out here. The good news is
+     * that the slower cycle time has very little affect on transfer
+     * performance.
+     */
+    
+	switch(speed) {
+		case XFER_UDMA_4:
+		case XFER_UDMA_2:	//u_speed = 2 << (drive->dn * 4); break;
+		case XFER_UDMA_5:
+		case XFER_UDMA_3:
+		case XFER_UDMA_1:	//u_speed = 1 << (drive->dn * 4); break;
+		case XFER_UDMA_0:	u_speed = 0 << (drive->dn * 4); break;
+		case XFER_MW_DMA_2:
+		case XFER_MW_DMA_1:
+		case XFER_MW_DMA_0:
+		case XFER_SW_DMA_2:	break;
+		case XFER_PIO_4:
+		case XFER_PIO_3:
+		case XFER_PIO_2:
+		case XFER_PIO_0:	break;
+		default:		return -1;
+	}
+
+	if (speed >= XFER_UDMA_0) {
+		pci_write_config_byte(dev, 0x48, reg48 | u_flag);
+		reg4a &= ~a_speed;
+		pci_write_config_byte(dev, 0x4a, reg4a | u_speed);
+	} else {
+		pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
+		pci_write_config_byte(dev, 0x4a, reg4a & ~a_speed);
+	}
+
+	it8172_tune_drive(drive, it8172_dma_2_pio(speed));
+	return (ide_config_drive_speed(drive, speed));
+}
+
+static int it8172_config_chipset_for_dma (ide_drive_t *drive)
+{
+	u8 speed = ide_dma_speed(drive, it8172_ratemask(drive));
+
+	if (!(speed)) {
+		u8 tspeed = ide_get_best_pio_mode(drive, 255, 4, NULL);
+		speed = it8172_dma_2_pio(XFER_PIO_0 + tspeed);
+	}
+
+	(void) it8172_tune_chipset(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static int it8172_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	drive->init_speed = 0;
+
+	if (id && (id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = it8172_config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!it8172_config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!it8172_config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		it8172_tune_drive(drive, 5);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+static unsigned int __init init_chipset_it8172 (struct pci_dev *dev, const char *name)
+{
+	unsigned char progif;
+    
+	/*
+	 * Place both IDE interfaces into PCI "native" mode
+	 */
+	pci_read_config_byte(dev, PCI_CLASS_PROG, &progif);
+	pci_write_config_byte(dev, PCI_CLASS_PROG, progif | 0x05);    
+
+	return IT8172_IDE_IRQ;
+}
+
+
+static void __init init_hwif_it8172 (ide_hwif_t *hwif)
+{
+	struct pci_dev* dev = hwif->pci_dev;
+	unsigned long cmdBase, ctrlBase;
+    
+	hwif->autodma = 0;
+	hwif->tuneproc = &it8172_tune_drive;
+	hwif->speedproc = &it8172_tune_chipset;
+
+	cmdBase = dev->resource[0].start;
+	ctrlBase = dev->resource[1].start;
+    
+	ide_init_hwif_ports(&hwif->hw, cmdBase, ctrlBase | 2, NULL);
+	memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
+	hwif->noprobe = 0;
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->atapi_dma = 1;
+	hwif->ultra_mask = 0x07;
+	hwif->mwdma_mask = 0x06;
+	hwif->swdma_mask = 0x04;
+
+	hwif->ide_dma_check = &it8172_config_drive_xfer_rate;
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+static void __init init_dma_it8172 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static int __devinit it8172_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &it8172_chipsets[id->driver_data];
+        if ((!(PCI_FUNC(dev->devfn) & 1) ||
+            (!((dev->class >> 8) == PCI_CLASS_STORAGE_IDE))))
+                return 1; /* IT8172 is more than only a IDE controller */
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id it8172_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_IT8172G, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "IT8172IDE",
+	.id_table	= it8172_pci_tbl,
+	.probe		= it8172_init_one,
+};
+
+static int it8172_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void it8172_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(it8172_ide_init);
+module_exit(it8172_ide_exit);
+
+MODULE_AUTHOR("SteveL@mvista.com");
+MODULE_DESCRIPTION("PCI driver module for ITE 8172 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/it8172.h linux-2.4.21-pre6/drivers/ide/pci/it8172.h
--- linux-2.4.20/drivers/ide/pci/it8172.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/it8172.h	2003-03-26 23:49:15.000000000 +0000
@@ -0,0 +1,45 @@
+#ifndef ITE8172G_H
+#define ITE8172G_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+static u8 it8172_ratemask(ide_drive_t *drive);
+static u8 it8172_ratefilter(ide_drive_t *drive, u8 speed);
+static void it8172_tune_drive(ide_drive_t *drive, u8 pio);
+static u8 it8172_dma_2_pio(u8 xfer_rate);
+static int it8172_tune_chipset(ide_drive_t *drive, u8 xferspeed);
+#ifdef CONFIG_BLK_DEV_IDEDMA
+static int it8172_config_chipset_for_dma(ide_drive_t *drive);
+#endif
+
+static void init_setup_it8172(struct pci_dev *, ide_pci_device_t *);
+static unsigned int init_chipset_it8172(struct pci_dev *, const char *);
+static void init_hwif_it8172(ide_hwif_t *);
+static void init_dma_it8172(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t it8172_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_ITE,
+		.device		= PCI_DEVICE_ID_ITE_IT8172G,
+		.name		= "IT8172G",
+		.init_setup	= init_setup_it8172,
+		.init_chipset	= init_chipset_it8172,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_it8172,
+                .init_dma	= init_dma_it8172,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x40,0x00,0x01}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* ITE8172G_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/ns87415.c linux-2.4.21-pre6/drivers/ide/pci/ns87415.c
--- linux-2.4.20/drivers/ide/pci/ns87415.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/ns87415.c	2003-03-26 23:49:25.000000000 +0000
@@ -0,0 +1,267 @@
+/*
+ * linux/drivers/ide/pci/ns87415.c		Version 2.00  Sep. 10, 2002
+ *
+ * Copyright (C) 1997-1998	Mark Lord <mlord@pobox.com>
+ * Copyright (C) 1998		Eddie C. Dost <ecd@skynet.be>
+ * Copyright (C) 1999-2000	Andre Hedrick <andre@linux-ide.org>
+ *
+ * Inspired by an earlier effort from David S. Miller <davem@redhat.com>
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "ns87415.h"
+
+static unsigned int ns87415_count = 0, ns87415_control[MAX_HWIFS] = { 0 };
+
+/*
+ * This routine either enables/disables (according to drive->present)
+ * the IRQ associated with the port (HWIF(drive)),
+ * and selects either PIO or DMA handshaking for the next I/O operation.
+ */
+static void ns87415_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	unsigned int bit, other, new, *old = (unsigned int *) hwif->select_data;
+	struct pci_dev *dev = hwif->pci_dev;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	new = *old;
+
+	/* Adjust IRQ enable bit */
+	bit = 1 << (8 + hwif->channel);
+	new = drive->present ? (new & ~bit) : (new | bit);
+
+	/* Select PIO or DMA, DMA may only be selected for one drive/channel. */
+	bit   = 1 << (20 + drive->select.b.unit       + (hwif->channel << 1));
+	other = 1 << (20 + (1 - drive->select.b.unit) + (hwif->channel << 1));
+	new = use_dma ? ((new & ~other) | bit) : (new & ~bit);
+
+	if (new != *old) {
+		unsigned char stat;
+
+		/*
+		 * Don't change DMA engine settings while Write Buffers
+		 * are busy.
+		 */
+		(void) pci_read_config_byte(dev, 0x43, &stat);
+		while (stat & 0x03) {
+			udelay(1);
+			(void) pci_read_config_byte(dev, 0x43, &stat);
+		}
+
+		*old = new;
+		(void) pci_write_config_dword(dev, 0x40, new);
+
+		/*
+		 * And let things settle...
+		 */
+		udelay(10);
+	}
+
+	local_irq_restore(flags);
+}
+
+static void ns87415_selectproc (ide_drive_t *drive)
+{
+	ns87415_prepare_drive (drive, drive->using_dma);
+}
+
+static int ns87415_ide_dma_end (ide_drive_t *drive)
+{
+	ide_hwif_t      *hwif = HWIF(drive);
+	u8 dma_stat = 0, dma_cmd = 0;
+
+	drive->waiting_for_dma = 0;
+	dma_stat = hwif->INB(hwif->dma_status);
+	/* get dma command mode */
+	dma_cmd = hwif->INB(hwif->dma_command);
+	/* stop DMA */
+	hwif->OUTB(dma_cmd & ~1, hwif->dma_command);
+	/* from ERRATA: clear the INTR & ERROR bits */
+	dma_cmd = hwif->INB(hwif->dma_command);
+	hwif->OUTB(dma_cmd|6, hwif->dma_command);
+	/* and free any DMA resources */
+	ide_destroy_dmatable(drive);
+	/* verify good DMA status */
+	return (dma_stat & 7) != 4;
+}
+
+static int ns87415_ide_dma_read (ide_drive_t *drive)
+{
+	/* select DMA xfer */
+	ns87415_prepare_drive(drive, 1);
+	if (!(__ide_dma_read(drive)))
+		return 0;
+	/* DMA failed: select PIO xfer */
+	ns87415_prepare_drive(drive, 0);
+	return 1;
+}
+
+static int ns87415_ide_dma_write (ide_drive_t *drive)
+{
+	/* select DMA xfer */
+	ns87415_prepare_drive(drive, 1);
+	if (!(__ide_dma_write(drive)))
+		return 0;
+	/* DMA failed: select PIO xfer */
+	ns87415_prepare_drive(drive, 0);
+	return 1;
+}
+
+static int ns87415_ide_dma_check (ide_drive_t *drive)
+{
+	if (drive->media != ide_disk)
+		return HWIF(drive)->ide_dma_off_quietly(drive);
+	return __ide_dma_check(drive);
+}
+
+static void __init init_hwif_ns87415 (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev = hwif->pci_dev;
+	unsigned int ctrl, using_inta;
+	u8 progif;
+#ifdef __sparc_v9__
+	int timeout;
+	u8 stat;
+#endif
+
+	hwif->autodma = 0;
+	hwif->selectproc = &ns87415_selectproc;
+
+	/* Set a good latency timer and cache line size value. */
+	(void) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
+#ifdef __sparc_v9__
+	(void) pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x10);
+#endif
+
+	/*
+	 * We cannot probe for IRQ: both ports share common IRQ on INTA.
+	 * Also, leave IRQ masked during drive probing, to prevent infinite
+	 * interrupts from a potentially floating INTA..
+	 *
+	 * IRQs get unmasked in selectproc when drive is first used.
+	 */
+	(void) pci_read_config_dword(dev, 0x40, &ctrl);
+	(void) pci_read_config_byte(dev, 0x09, &progif);
+	/* is irq in "native" mode? */
+	using_inta = progif & (1 << (hwif->channel << 1));
+	if (!using_inta)
+		using_inta = ctrl & (1 << (4 + hwif->channel));
+	if (hwif->mate) {
+		hwif->select_data = hwif->mate->select_data;
+	} else {
+		hwif->select_data = (unsigned long)
+					&ns87415_control[ns87415_count++];
+		ctrl |= (1 << 8) | (1 << 9);	/* mask both IRQs */
+		if (using_inta)
+			ctrl &= ~(1 << 6);	/* unmask INTA */
+		*((unsigned int *)hwif->select_data) = ctrl;
+		(void) pci_write_config_dword(dev, 0x40, ctrl);
+
+		/*
+		 * Set prefetch size to 512 bytes for both ports,
+		 * but don't turn on/off prefetching here.
+		 */
+		pci_write_config_byte(dev, 0x55, 0xee);
+
+#ifdef __sparc_v9__
+		/*
+		 * XXX: Reset the device, if we don't it will not respond
+		 *      to SELECT_DRIVE() properly during first probe_hwif().
+		 */
+		timeout = 10000;
+		hwif->OUTB(12, hwif->io_ports[IDE_CONTROL_OFFSET]);
+		udelay(10);
+		hwif->OUTB(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
+		do {
+			udelay(50);
+			stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
+                	if (stat == 0xff)
+                        	break;
+        	} while ((stat & BUSY_STAT) && --timeout);
+#endif
+	}
+
+	if (!using_inta)
+		hwif->irq = hwif->channel ? 15 : 14;	/* legacy mode */
+	else if (!hwif->irq && hwif->mate && hwif->mate->irq)
+		hwif->irq = hwif->mate->irq;	/* share IRQ with mate */
+
+	if (!hwif->dma_base)
+		return;
+
+	hwif->OUTB(0x60, hwif->dma_status);
+	hwif->ide_dma_read = &ns87415_ide_dma_read;
+	hwif->ide_dma_write = &ns87415_ide_dma_write;
+	hwif->ide_dma_check = &ns87415_ide_dma_check;
+	hwif->ide_dma_end = &ns87415_ide_dma_end;
+
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+static void __init init_dma_ns87415 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static int __devinit ns87415_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &ns87415_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id ns87415_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87415, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "NS87415IDE",
+	.id_table	= ns87415_pci_tbl,
+	.probe		= ns87415_init_one,
+};
+
+static int ns87415_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void ns87415_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(ns87415_ide_init);
+module_exit(ns87415_ide_exit);
+
+MODULE_AUTHOR("Mark Lord, Eddie Dost, Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for NS87415 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/ns87415.h linux-2.4.21-pre6/drivers/ide/pci/ns87415.h
--- linux-2.4.20/drivers/ide/pci/ns87415.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/ns87415.h	2003-03-26 23:49:39.000000000 +0000
@@ -0,0 +1,33 @@
+#ifndef NS87415_H
+#define NS87415_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+static void init_hwif_ns87415(ide_hwif_t *);
+static void init_dma_ns87415(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t ns87415_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_NS,
+		.device		= PCI_DEVICE_ID_NS_87415,
+		.name		= "NS87415",
+		.init_chipset	= NULL,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_ns87415,
+                .init_dma	= init_dma_ns87415,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* NS87415_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/opti621.c linux-2.4.21-pre6/drivers/ide/pci/opti621.c
--- linux-2.4.20/drivers/ide/pci/opti621.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/opti621.c	2003-03-26 23:49:08.000000000 +0000
@@ -0,0 +1,403 @@
+/*
+ *  linux/drivers/ide/pci/opti621.c		Version 0.7	Sept 10, 2002
+ *
+ *  Copyright (C) 1996-1998  Linus Torvalds & authors (see below)
+ */
+
+/*
+ * Authors:
+ * Jaromir Koutek <miri@punknet.cz>,
+ * Jan Harkes <jaharkes@cwi.nl>,
+ * Mark Lord <mlord@pobox.com>
+ * Some parts of code are from ali14xx.c and from rz1000.c.
+ *
+ * OPTi is trademark of OPTi, Octek is trademark of Octek.
+ *
+ * I used docs from OPTi databook, from ftp.opti.com, file 9123-0002.ps
+ * and disassembled/traced setupvic.exe (DOS program).
+ * It increases kernel code about 2 kB.
+ * I don't have this card no more, but I hope I can get some in case
+ * of needed development.
+ * My card is Octek PIDE 1.01 (on card) or OPTiViC (program).
+ * It has a place for a secondary connector in circuit, but nothing
+ * is there. Also BIOS says no address for
+ * secondary controller (see bellow in ide_init_opti621).
+ * I've only tested this on my system, which only has one disk.
+ * It's Western Digital WDAC2850, with PIO mode 3. The PCI bus
+ * is at 20 MHz (I have DX2/80, I tried PCI at 40, but I got random
+ * lockups). I tried the OCTEK double speed CD-ROM and
+ * it does not work! But I can't boot DOS also, so it's probably
+ * hardware fault. I have connected Conner 80MB, the Seagate 850MB (no
+ * problems) and Seagate 1GB (as slave, WD as master). My experiences
+ * with the third, 1GB drive: I got 3MB/s (hdparm), but sometimes
+ * it slows to about 100kB/s! I don't know why and I have
+ * not this drive now, so I can't try it again.
+ * I write this driver because I lost the paper ("manual") with
+ * settings of jumpers on the card and I have to boot Linux with
+ * Loadlin except LILO, cause I have to run the setupvic.exe program
+ * already or I get disk errors (my test: rpm -Vf
+ * /usr/X11R6/bin/XF86_SVGA - or any big file).
+ * Some numbers from hdparm -t /dev/hda:
+ * Timing buffer-cache reads:   32 MB in  3.02 seconds =10.60 MB/sec
+ * Timing buffered disk reads:  16 MB in  5.52 seconds = 2.90 MB/sec
+ * I have 4 Megs/s before, but I don't know why (maybe changes
+ * in hdparm test).
+ * After release of 0.1, I got some successful reports, so it might work.
+ *
+ * The main problem with OPTi is that some timings for master
+ * and slave must be the same. For example, if you have master
+ * PIO 3 and slave PIO 0, driver have to set some timings of
+ * master for PIO 0. Second problem is that opti621_tune_drive
+ * got only one drive to set, but have to set both drives.
+ * This is solved in compute_pios. If you don't set
+ * the second drive, compute_pios use ide_get_best_pio_mode
+ * for autoselect mode (you can change it to PIO 0, if you want).
+ * If you then set the second drive to another PIO, the old value
+ * (automatically selected) will be overrided by yours.
+ * There is a 25/33MHz switch in configuration
+ * register, but driver is written for use at any frequency which get
+ * (use idebus=xx to select PCI bus speed).
+ * Use ide0=autotune for automatical tune of the PIO modes.
+ * If you get strange results, do not use this and set PIO manually
+ * by hdparm.
+ *
+ * Version 0.1, Nov 8, 1996
+ * by Jaromir Koutek, for 2.1.8. 
+ * Initial version of driver.
+ * 
+ * Version 0.2
+ * Number 0.2 skipped.
+ *
+ * Version 0.3, Nov 29, 1997
+ * by Mark Lord (probably), for 2.1.68
+ * Updates for use with new IDE block driver.
+ *
+ * Version 0.4, Dec 14, 1997
+ * by Jan Harkes
+ * Fixed some errors and cleaned the code.
+ *
+ * Version 0.5, Jan 2, 1998
+ * by Jaromir Koutek
+ * Updates for use with (again) new IDE block driver.
+ * Update of documentation.
+ * 
+ * Version 0.6, Jan 2, 1999
+ * by Jaromir Koutek
+ * Reversed to version 0.3 of the driver, because
+ * 0.5 doesn't work.
+ */
+
+#undef REALLY_SLOW_IO	/* most systems can safely undef this */
+#define OPTI621_DEBUG		/* define for debug messages */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/pci.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+
+#include "ide_modes.h"
+#include "opti621.h"
+
+#define OPTI621_MAX_PIO 3
+/* In fact, I do not have any PIO 4 drive
+ * (address: 25 ns, data: 70 ns, recovery: 35 ns),
+ * but OPTi 82C621 is programmable and it can do (minimal values):
+ * on 40MHz PCI bus (pulse 25 ns):
+ *  address: 25 ns, data: 25 ns, recovery: 50 ns;
+ * on 20MHz PCI bus (pulse 50 ns):
+ *  address: 50 ns, data: 50 ns, recovery: 100 ns.
+ */
+
+/* #define READ_PREFETCH 0 */
+/* Uncommnent for disable read prefetch.
+ * There is some readprefetch capatibility in hdparm,
+ * but when I type hdparm -P 1 /dev/hda, I got errors
+ * and till reset drive is inaccessible.
+ * This (hw) read prefetch is safe on my drive.
+ */
+
+#ifndef READ_PREFETCH
+#define READ_PREFETCH 0x40 /* read prefetch is enabled */
+#endif /* else read prefetch is disabled */
+
+#define READ_REG 0	/* index of Read cycle timing register */
+#define WRITE_REG 1	/* index of Write cycle timing register */
+#define CNTRL_REG 3	/* index of Control register */
+#define STRAP_REG 5	/* index of Strap register */
+#define MISC_REG 6	/* index of Miscellaneous register */
+
+static int reg_base;
+
+#define PIO_NOT_EXIST 254
+#define PIO_DONT_KNOW 255
+
+/* there are stored pio numbers from other calls of opti621_tune_drive */
+static void compute_pios(ide_drive_t *drive, u8 pio)
+/* Store values into drive->drive_data
+ *	second_contr - 0 for primary controller, 1 for secondary
+ *	slave_drive - 0 -> pio is for master, 1 -> pio is for slave
+ *	pio - PIO mode for selected drive (for other we don't know)
+ */
+{
+	int d;
+	ide_hwif_t *hwif = HWIF(drive);
+
+	drive->drive_data = ide_get_best_pio_mode(drive, pio, OPTI621_MAX_PIO, NULL);
+	for (d = 0; d < 2; ++d) {
+		drive = &hwif->drives[d];
+		if (drive->present) {
+			if (drive->drive_data == PIO_DONT_KNOW)
+				drive->drive_data = ide_get_best_pio_mode(drive, 255, OPTI621_MAX_PIO, NULL);
+#ifdef OPTI621_DEBUG
+			printk("%s: Selected PIO mode %d\n",
+				drive->name, drive->drive_data);
+#endif
+		} else {
+			drive->drive_data = PIO_NOT_EXIST;
+		}
+	}
+}
+
+static int cmpt_clk(int time, int bus_speed)
+/* Returns (rounded up) time in clocks for time in ns,
+ * with bus_speed in MHz.
+ * Example: bus_speed = 40 MHz, time = 80 ns
+ * 1000/40 = 25 ns (clk value),
+ * 80/25 = 3.2, rounded up to 4 (I hope ;-)).
+ * Use idebus=xx to select right frequency.
+ */
+{
+	return ((time*bus_speed+999)/1000);
+}
+
+static void write_reg(ide_hwif_t *hwif, u8 value, int reg)
+/* Write value to register reg, base of register
+ * is at reg_base (0x1f0 primary, 0x170 secondary,
+ * if not changed by PCI configuration).
+ * This is from setupvic.exe program.
+ */
+{
+	hwif->INW(reg_base+1);
+	hwif->INW(reg_base+1);
+	hwif->OUTB(3, reg_base+2);
+	hwif->OUTB(value, reg_base+reg);
+	hwif->OUTB(0x83, reg_base+2);
+}
+
+static u8 read_reg(ide_hwif_t *hwif, int reg)
+/* Read value from register reg, base of register
+ * is at reg_base (0x1f0 primary, 0x170 secondary,
+ * if not changed by PCI configuration).
+ * This is from setupvic.exe program.
+ */
+{
+	u8 ret = 0;
+
+	hwif->INW(reg_base+1);
+	hwif->INW(reg_base+1);
+	hwif->OUTB(3, reg_base+2);
+	ret = hwif->INB(reg_base+reg);
+	hwif->OUTB(0x83, reg_base+2);
+	return ret;
+}
+
+typedef struct pio_clocks_s {
+	int	address_time;	/* Address setup (clocks) */
+	int	data_time;	/* Active/data pulse (clocks) */
+	int	recovery_time;	/* Recovery time (clocks) */
+} pio_clocks_t;
+
+static void compute_clocks(int pio, pio_clocks_t *clks)
+{
+        if (pio != PIO_NOT_EXIST) {
+        	int adr_setup, data_pls;
+		int bus_speed = system_bus_clock();
+
+ 	       	adr_setup = ide_pio_timings[pio].setup_time;
+  	      	data_pls = ide_pio_timings[pio].active_time;
+	  	clks->address_time = cmpt_clk(adr_setup, bus_speed);
+	     	clks->data_time = cmpt_clk(data_pls, bus_speed);
+     		clks->recovery_time = cmpt_clk(ide_pio_timings[pio].cycle_time
+     			- adr_setup-data_pls, bus_speed);
+     		if (clks->address_time<1) clks->address_time = 1;
+     		if (clks->address_time>4) clks->address_time = 4;
+     		if (clks->data_time<1) clks->data_time = 1;
+     		if (clks->data_time>16) clks->data_time = 16;
+     		if (clks->recovery_time<2) clks->recovery_time = 2;
+     		if (clks->recovery_time>17) clks->recovery_time = 17;
+	} else {
+		clks->address_time = 1;
+		clks->data_time = 1;
+		clks->recovery_time = 2;
+		/* minimal values */
+	}
+ 
+}
+
+/* Main tune procedure, called from tuneproc. */
+static void opti621_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	/* primary and secondary drives share some registers,
+	 * so we have to program both drives
+	 */
+	unsigned long flags;
+	u8 pio1 = 0, pio2 = 0;
+	pio_clocks_t first, second;
+	int ax, drdy;
+	u8 cycle1, cycle2, misc;
+	ide_hwif_t *hwif = HWIF(drive);
+
+	/* sets drive->drive_data for both drives */
+	compute_pios(drive, pio);
+ 	pio1 = hwif->drives[0].drive_data;
+ 	pio2 = hwif->drives[1].drive_data;
+
+	compute_clocks(pio1, &first);
+	compute_clocks(pio2, &second);
+
+	/* ax = max(a1,a2) */
+	ax = (first.address_time < second.address_time) ? second.address_time : first.address_time;
+
+	drdy = 2; /* DRDY is default 2 (by OPTi Databook) */
+
+	cycle1 = ((first.data_time-1)<<4)  | (first.recovery_time-2);
+	cycle2 = ((second.data_time-1)<<4) | (second.recovery_time-2);
+	misc = READ_PREFETCH | ((ax-1)<<4) | ((drdy-2)<<1);
+
+#ifdef OPTI621_DEBUG
+	printk("%s: master: address: %d, data: %d, "
+		"recovery: %d, drdy: %d [clk]\n",
+		hwif->name, ax, first.data_time,
+		first.recovery_time, drdy);
+	printk("%s: slave:  address: %d, data: %d, "
+		"recovery: %d, drdy: %d [clk]\n",
+		hwif->name, ax, second.data_time,
+		second.recovery_time, drdy);
+#endif
+
+	spin_lock_irqsave(&ide_lock, flags);
+
+     	reg_base = hwif->io_ports[IDE_DATA_OFFSET];
+
+	/* allow Register-B */
+	hwif->OUTB(0xc0, reg_base+CNTRL_REG);
+	/* hmm, setupvic.exe does this ;-) */
+	hwif->OUTB(0xff, reg_base+5);
+	/* if reads 0xff, adapter not exist? */
+	(void) hwif->INB(reg_base+CNTRL_REG);
+	/* if reads 0xc0, no interface exist? */
+	read_reg(hwif, CNTRL_REG);
+	/* read version, probably 0 */
+	read_reg(hwif, STRAP_REG);
+
+	/* program primary drive */
+		/* select Index-0 for Register-A */
+	write_reg(hwif, 0,      MISC_REG);
+		/* set read cycle timings */
+	write_reg(hwif, cycle1, READ_REG);
+		/* set write cycle timings */
+	write_reg(hwif, cycle1, WRITE_REG);
+
+	/* program secondary drive */
+		/* select Index-1 for Register-B */
+	write_reg(hwif, 1,      MISC_REG);
+		/* set read cycle timings */
+	write_reg(hwif, cycle2, READ_REG);
+		/* set write cycle timings */
+	write_reg(hwif, cycle2, WRITE_REG);
+
+	/* use Register-A for drive 0 */
+	/* use Register-B for drive 1 */
+	write_reg(hwif, 0x85, CNTRL_REG);
+
+	/* set address setup, DRDY timings,   */
+	/*  and read prefetch for both drives */
+ 	write_reg(hwif, misc, MISC_REG);
+
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+/*
+ * init_hwif_opti621() is called once for each hwif found at boot.
+ */
+static void __init init_hwif_opti621 (ide_hwif_t *hwif)
+{
+	hwif->autodma = 0;
+	hwif->drives[0].drive_data = PIO_DONT_KNOW;
+	hwif->drives[1].drive_data = PIO_DONT_KNOW;
+	hwif->tuneproc = &opti621_tune_drive;
+
+	if (!(hwif->dma_base))
+		return;
+
+	hwif->atapi_dma = 1;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+static void __init init_dma_opti621 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static void __init init_setup_opti621 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+static int __devinit opti621_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &opti621_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id opti621_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C621, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "Opti621 IDE",
+	.id_table	= opti621_pci_tbl,
+	.probe		= opti621_init_one,
+};
+
+static int opti621_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void opti621_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(opti621_ide_init);
+module_exit(opti621_ide_exit);
+
+MODULE_AUTHOR("Jaromir Koutek, Jan Harkes, Mark Lord");
+MODULE_DESCRIPTION("PCI driver module for Opti621 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/opti621.h linux-2.4.21-pre6/drivers/ide/pci/opti621.h
--- linux-2.4.20/drivers/ide/pci/opti621.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/opti621.h	2003-03-26 23:48:57.000000000 +0000
@@ -0,0 +1,49 @@
+#ifndef OPTI621_H
+#define OPTI621_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+static void init_setup_opti621(struct pci_dev *, ide_pci_device_t *);
+static void init_hwif_opti621(ide_hwif_t *);
+static void init_dma_opti621(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t opti621_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_OPTI,
+		.device		= PCI_DEVICE_ID_OPTI_82C621,
+		.name		= "OPTI621",
+		.init_setup	= init_setup_opti621,
+		.init_chipset	= NULL,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_opti621,
+		.init_dma	= init_dma_opti621,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x45,0x80,0x00}, {0x40,0x08,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 1 */
+		.vendor		= PCI_VENDOR_ID_OPTI,
+		.device		= PCI_DEVICE_ID_OPTI_82C825,
+		.name		= "OPTI621X",
+		.init_setup	= init_setup_opti621,
+		.init_chipset	= NULL,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_opti621,
+                .init_dma	= init_dma_opti621,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x45,0x80,0x00}, {0x40,0x08,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* OPTI621_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/pdc202xx_new.c linux-2.4.21-pre6/drivers/ide/pci/pdc202xx_new.c
--- linux-2.4.20/drivers/ide/pci/pdc202xx_new.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/pdc202xx_new.c	2003-03-26 23:49:06.000000000 +0000
@@ -0,0 +1,676 @@
+/*
+ *  Promise TX2/TX4/TX2000/133 IDE driver
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ *  Split from:
+ *  linux/drivers/ide/pdc202xx.c	Version 0.35	Mar. 30, 2002
+ *  Copyright (C) 1998-2002		Andre Hedrick <andre@linux-ide.org>
+ *  Portions Copyright (C) 1999 Promise Technology, Inc.
+ *  Author: Frank Tiernan (frankt@promise.com)
+ *  Released under terms of General Public License
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+#include "pdc202xx_new.h"
+
+#define PDC202_DEBUG_CABLE	0
+
+#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 pdcnew_proc = 0;
+#define PDC202_MAX_DEVS		5
+static struct pci_dev *pdc202_devs[PDC202_MAX_DEVS];
+static int n_pdc202_devs;
+
+static char * pdcnew_info(char *buf, struct pci_dev *dev)
+{
+	char *p = buf;
+
+	p += sprintf(p, "\n                                ");
+	switch(dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20277:
+			p += sprintf(p, "SBFastTrak 133 Lite"); break;
+		case PCI_DEVICE_ID_PROMISE_20276:
+			p += sprintf(p, "MBFastTrak 133 Lite"); break;
+		case PCI_DEVICE_ID_PROMISE_20275:
+			p += sprintf(p, "MBUltra133"); break;
+		case PCI_DEVICE_ID_PROMISE_20271:
+			p += sprintf(p, "FastTrak TX2000"); break;
+		case PCI_DEVICE_ID_PROMISE_20270:
+			p += sprintf(p, "FastTrak LP/TX2/TX4"); break;
+		case PCI_DEVICE_ID_PROMISE_20269:
+			p += sprintf(p, "Ultra133 TX2"); break;
+		case PCI_DEVICE_ID_PROMISE_20268:
+			p += sprintf(p, "Ultra100 TX2"); break;
+		default:
+			p += sprintf(p, "Ultra series"); break;
+			break;
+	}
+	p += sprintf(p, " Chipset.\n");
+	return (char *)p;
+}
+
+static int pdcnew_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	int i;
+
+	for (i = 0; i < n_pdc202_devs; i++) {
+		struct pci_dev *dev	= pdc202_devs[i];
+		p = pdcnew_info(buffer, dev);
+	}
+	return p-buffer;	/* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+
+static u8 pdcnew_ratemask (ide_drive_t *drive)
+{
+	u8 mode;
+
+	switch(HWIF(drive)->pci_dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20277:
+		case PCI_DEVICE_ID_PROMISE_20276:
+		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20271:
+		case PCI_DEVICE_ID_PROMISE_20269:
+			mode = 4;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20270:
+		case PCI_DEVICE_ID_PROMISE_20268:
+			mode = 3;
+			break;
+		default:
+			return 0;
+	}
+	if (!eighty_ninty_three(drive))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+static int check_in_drive_lists (ide_drive_t *drive, const char **list)
+{
+	struct hd_driveid *id = drive->id;
+
+	if (pdc_quirk_drives == list) {
+		while (*list) {
+			if (strstr(id->model, *list++)) {
+				return 2;
+			}
+		}
+	} else {
+		while (*list) {
+			if (!strcmp(*list++,id->model)) {
+				return 1;
+			}
+		}
+	}
+	return 0;
+}
+
+static int pdcnew_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 drive_pci		= 0x60 + (drive->dn << 2);
+	u8 speed	= ide_rate_filter(pdcnew_ratemask(drive), xferspeed);
+
+	u32			drive_conf;
+	u8			AP, BP, CP, DP;
+	u8			TA = 0, TB = 0, TC = 0;
+
+	if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))
+		return -1;
+
+	pci_read_config_dword(dev, drive_pci, &drive_conf);
+	pci_read_config_byte(dev, (drive_pci), &AP);
+	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+	pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
+
+	if (speed < XFER_SW_DMA_0) {
+		if ((AP & 0x0F) || (BP & 0x07)) {
+			/* clear PIO modes of lower 8421 bits of A Register */
+			pci_write_config_byte(dev, (drive_pci), AP &~0x0F);
+			pci_read_config_byte(dev, (drive_pci), &AP);
+
+			/* clear PIO modes of lower 421 bits of B Register */
+			pci_write_config_byte(dev, (drive_pci)|0x01, BP &~0x07);
+			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+
+			pci_read_config_byte(dev, (drive_pci), &AP);
+			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+		}
+	} else {
+		if ((BP & 0xF0) && (CP & 0x0F)) {
+			/* clear DMA modes of upper 842 bits of B Register */
+			/* clear PIO forced mode upper 1 bit of B Register */
+			pci_write_config_byte(dev, (drive_pci)|0x01, BP &~0xF0);
+			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+
+			/* clear DMA modes of lower 8421 bits of C Register */
+			pci_write_config_byte(dev, (drive_pci)|0x02, CP &~0x0F);
+			pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+		}
+	}
+
+	pci_read_config_byte(dev, (drive_pci), &AP);
+	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+
+	switch(speed) {
+		case XFER_UDMA_6:	speed = XFER_UDMA_5;
+		case XFER_UDMA_5:
+		case XFER_UDMA_4:	TB = 0x20; TC = 0x01; break;
+		case XFER_UDMA_2:	TB = 0x20; TC = 0x01; break;
+		case XFER_UDMA_3:
+		case XFER_UDMA_1:	TB = 0x40; TC = 0x02; break;
+		case XFER_UDMA_0:
+		case XFER_MW_DMA_2:	TB = 0x60; TC = 0x03; break;
+		case XFER_MW_DMA_1:	TB = 0x60; TC = 0x04; break;
+		case XFER_MW_DMA_0:
+		case XFER_SW_DMA_2:	TB = 0x60; TC = 0x05; break;
+		case XFER_SW_DMA_1:	TB = 0x80; TC = 0x06; break;
+		case XFER_SW_DMA_0:	TB = 0xC0; TC = 0x0B; break;
+		case XFER_PIO_4:	TA = 0x01; TB = 0x04; break;
+		case XFER_PIO_3:	TA = 0x02; TB = 0x06; break;
+		case XFER_PIO_2:	TA = 0x03; TB = 0x08; break;
+		case XFER_PIO_1:	TA = 0x05; TB = 0x0C; break;
+		case XFER_PIO_0:
+		default:		TA = 0x09; TB = 0x13; break;
+	}
+
+	if (speed < XFER_SW_DMA_0) {
+		pci_write_config_byte(dev, (drive_pci), AP|TA);
+		pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
+	} else {
+		pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
+		pci_write_config_byte(dev, (drive_pci)|0x02, CP|TC);
+	}
+
+#if PDC202XX_DECODE_REGISTER_INFO
+	pci_read_config_byte(dev, (drive_pci), &AP);
+	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+	pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
+
+	decode_registers(REG_A, AP);
+	decode_registers(REG_B, BP);
+	decode_registers(REG_C, CP);
+	decode_registers(REG_D, DP);
+#endif /* PDC202XX_DECODE_REGISTER_INFO */
+#if PDC202XX_DEBUG_DRIVE_INFO
+	printk(KERN_DEBUG "%s: %s drive%d 0x%08x ",
+		drive->name, ide_xfer_verbose(speed),
+		drive->dn, drive_conf);
+		pci_read_config_dword(dev, drive_pci, &drive_conf);
+	printk("0x%08x\n", drive_conf);
+#endif /* PDC202XX_DEBUG_DRIVE_INFO */
+
+	return (ide_config_drive_speed(drive, speed));
+}
+
+static int pdcnew_new_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	unsigned long indexreg	= hwif->dma_vendor1;
+	unsigned long datareg	= hwif->dma_vendor3;
+	u8 thold		= 0x10;
+	u8 adj			= (drive->dn%2) ? 0x08 : 0x00;
+	u8 speed		= ide_rate_filter(pdcnew_ratemask(drive), xferspeed);
+
+	if (speed == XFER_UDMA_2) {
+		hwif->OUTB((thold + adj), indexreg);
+		hwif->OUTB((hwif->INB(datareg) & 0x7f), datareg);
+	}
+
+	switch (speed) {
+		case XFER_UDMA_7:
+			speed = XFER_UDMA_6;
+		case XFER_UDMA_6:	set_ultra(0x1a, 0x01, 0xcb); break;
+		case XFER_UDMA_5:	set_ultra(0x1a, 0x02, 0xcb); break;
+		case XFER_UDMA_4:	set_ultra(0x1a, 0x03, 0xcd); break;
+		case XFER_UDMA_3:	set_ultra(0x1a, 0x05, 0xcd); break;
+		case XFER_UDMA_2:	set_ultra(0x2a, 0x07, 0xcd); break;
+		case XFER_UDMA_1:	set_ultra(0x3a, 0x0a, 0xd0); break;
+		case XFER_UDMA_0:	set_ultra(0x4a, 0x0f, 0xd5); break;
+		case XFER_MW_DMA_2:	set_ata2(0x69, 0x25); break;
+		case XFER_MW_DMA_1:	set_ata2(0x6b, 0x27); break;
+		case XFER_MW_DMA_0:	set_ata2(0xdf, 0x5f); break;
+		case XFER_PIO_4:	set_pio(0x23, 0x09, 0x25); break;
+		case XFER_PIO_3:	set_pio(0x27, 0x0d, 0x35); break;
+		case XFER_PIO_2:	set_pio(0x23, 0x26, 0x64); break;
+		case XFER_PIO_1:	set_pio(0x46, 0x29, 0xa4); break;
+		case XFER_PIO_0:	set_pio(0xfb, 0x2b, 0xac); break;
+		default:
+			;
+	}
+
+	return (ide_config_drive_speed(drive, speed));
+}
+
+/*   0    1    2    3    4    5    6   7   8
+ * 960, 480, 390, 300, 240, 180, 120, 90, 60
+ *           180, 150, 120,  90,  60
+ * DMA_Speed
+ * 180, 120,  90,  90,  90,  60,  30
+ *  11,   5,   4,   3,   2,   1,   0
+ */
+static int config_chipset_for_pio (ide_drive_t *drive, u8 pio)
+{
+	u8 speed = 0;
+
+	if (pio == 5) pio = 4;
+	speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, pio, NULL);
+        
+	return ((int) pdcnew_tune_chipset(drive, speed));
+}
+
+static void pdcnew_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	(void) config_chipset_for_pio(drive, pio);
+}
+
+static u8 pdcnew_new_cable_detect (ide_hwif_t *hwif)
+{
+	hwif->OUTB(0x0b, hwif->dma_vendor1);
+	return ((u8)((hwif->INB(hwif->dma_vendor3) & 0x04)));
+}
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	struct hd_driveid *id	= drive->id;
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 speed		= -1;
+	u8 cable		= 0;
+
+	u8 ultra_66		= ((id->dma_ultra & 0x0010) ||
+				   (id->dma_ultra & 0x0008)) ? 1 : 0;
+
+	switch(dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20277:
+		case PCI_DEVICE_ID_PROMISE_20276:
+		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20271:
+		case PCI_DEVICE_ID_PROMISE_20269:
+		case PCI_DEVICE_ID_PROMISE_20270:
+		case PCI_DEVICE_ID_PROMISE_20268:
+			cable = pdcnew_new_cable_detect(hwif);
+#if PDC202_DEBUG_CABLE
+			printk(KERN_DEBUG "%s: %s-pin cable, %s-pin cable, %d\n",
+				hwif->name, hwif->udma_four ? "80" : "40",
+				cable ? "40" : "80", cable);
+#endif /* PDC202_DEBUG_CABLE */
+			break;
+		default:
+			/* If its not one we know we should never
+			   arrive here.. */
+			BUG();
+	}
+
+	/*
+	 * Set the control register to use the 66Mhz system
+	 * clock for UDMA 3/4 mode operation. If one drive on
+	 * a channel is U66 capable but the other isn't we
+	 * fall back to U33 mode. The BIOS INT 13 hooks turn
+	 * the clock on then off for each read/write issued. I don't
+	 * do that here because it would require modifying the
+	 * kernel, seperating the fop routines from the kernel or
+	 * somehow hooking the fops calls. It may also be possible to
+	 * leave the 66Mhz clock on and readjust the timing
+	 * parameters.
+	 */
+
+	if ((ultra_66) && (cable)) {
+#ifdef DEBUG
+		printk(KERN_DEBUG "ULTRA 66/100/133: %s channel of Ultra 66/100/133 "
+			"requires an 80-pin cable for Ultra66 operation.\n",
+			hwif->channel ? "Secondary" : "Primary");
+		printk(KERN_DEBUG "         Switching to Ultra33 mode.\n");
+#endif /* DEBUG */
+		/* Primary   : zero out second bit */
+		/* Secondary : zero out fourth bit */
+		printk(KERN_WARNING "Warning: %s channel requires an 80-pin cable for operation.\n", hwif->channel ? "Secondary":"Primary");
+		printk(KERN_WARNING "%s reduced to Ultra33 mode.\n", drive->name);
+	}
+
+	if (drive->media != ide_disk)
+		return 0;
+	if (id->capability & 4) {	/* IORDY_EN & PREFETCH_EN */
+		hwif->OUTB((0x13 + ((drive->dn%2) ? 0x08 : 0x00)), hwif->dma_vendor1);
+		hwif->OUTB((hwif->INB(hwif->dma_vendor3)|0x03), hwif->dma_vendor3);
+	}
+
+	speed = ide_dma_speed(drive, pdcnew_ratemask(drive));
+
+	if (!(speed)) {
+		hwif->tuneproc(drive, 5);
+		return 0;
+	}
+
+	(void) hwif->speedproc(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static int pdcnew_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	drive->init_speed = 0;
+
+	if (id && (id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			    (id->eide_dma_time < 150)) {
+				goto no_dma_set;
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		hwif->tuneproc(drive, 5);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+static int pdcnew_quirkproc (ide_drive_t *drive)
+{
+	return ((int) check_in_drive_lists(drive, pdc_quirk_drives));
+}
+
+static int pdcnew_ide_dma_lostirq(ide_drive_t *drive)
+{
+	if (HWIF(drive)->resetproc != NULL)
+		HWIF(drive)->resetproc(drive);
+	return __ide_dma_lostirq(drive);
+}
+
+static int pdcnew_ide_dma_timeout(ide_drive_t *drive)
+{
+	if (HWIF(drive)->resetproc != NULL)
+		HWIF(drive)->resetproc(drive);
+	return __ide_dma_timeout(drive);
+}
+
+static void pdcnew_new_reset (ide_drive_t *drive)
+{
+	/*
+	 * Deleted this because it is redundant from the caller.
+	 */
+	printk(KERN_WARNING "PDC202XX: %s channel reset.\n",
+		HWIF(drive)->channel ? "Secondary" : "Primary");
+}
+
+static void pdcnew_reset_host (ide_hwif_t *hwif)
+{
+//	unsigned long high_16	= hwif->dma_base - (8*(hwif->channel));
+	unsigned long high_16	= hwif->dma_master;
+	u8 udma_speed_flag	= hwif->INB(high_16|0x001f);
+
+	hwif->OUTB((udma_speed_flag | 0x10), (high_16|0x001f));
+	mdelay(100);
+	hwif->OUTB((udma_speed_flag & ~0x10), (high_16|0x001f));
+	mdelay(2000);	/* 2 seconds ?! */
+
+	printk(KERN_WARNING "PDC202XX: %s channel reset.\n",
+		hwif->channel ? "Secondary" : "Primary");
+}
+
+void pdcnew_reset (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	ide_hwif_t *mate	= hwif->mate;
+	
+	pdcnew_reset_host(hwif);
+	pdcnew_reset_host(mate);
+#if 0
+	/*
+	 * FIXME: Have to kick all the drives again :-/
+	 * What a pain in the ACE!
+	 */
+	if (hwif->present) {
+		u16 hunit = 0;
+		hwif->initializing = 1;
+		for (hunit = 0; hunit < MAX_DRIVES; ++hunit) {
+			ide_drive_t *hdrive = &hwif->drives[hunit];
+			if (hdrive->present) {
+				if (hwif->ide_dma_check)
+					hwif->ide_dma_check(hdrive);
+				else
+					hwif->tuneproc(hdrive, 5);
+			}
+		}
+		hwif->initializing = 0;
+	}
+	if (mate->present) {
+		u16 munit = 0;
+		mate->initializing = 1;
+		for (munit = 0; munit < MAX_DRIVES; ++munit) {
+			ide_drive_t *mdrive = &mate->drives[munit];
+			if (mdrive->present) {
+				if (mate->ide_dma_check) 
+					mate->ide_dma_check(mdrive);
+				else
+					mate->tuneproc(mdrive, 5);
+			}
+		}
+		mate->initializing = 0;
+	}
+#else
+	hwif->tuneproc(drive, 5);
+#endif
+}
+
+static unsigned int __init init_chipset_pdcnew (struct pci_dev *dev, const char *name)
+{
+	if (dev->resource[PCI_ROM_RESOURCE].start) {
+		pci_write_config_dword(dev, PCI_ROM_ADDRESS,
+			dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+		printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n",
+			name, dev->resource[PCI_ROM_RESOURCE].start);
+	}
+
+#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
+	pdc202_devs[n_pdc202_devs++] = dev;
+
+	if (!pdcnew_proc) {
+		pdcnew_proc = 1;
+		ide_pci_register_host_proc(&pdcnew_procs[0]);
+	}
+#endif /* DISPLAY_PDC202XX_TIMINGS && CONFIG_PROC_FS */
+
+	return dev->irq;
+}
+
+static void __init init_hwif_pdc202new (ide_hwif_t *hwif)
+{
+	hwif->autodma = 0;
+
+	hwif->tuneproc  = &pdcnew_tune_drive;
+	hwif->quirkproc = &pdcnew_quirkproc;
+	hwif->speedproc = &pdcnew_new_tune_chipset;
+	hwif->resetproc = &pdcnew_new_reset;
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->ultra_mask = 0x7f;
+	hwif->mwdma_mask = 0x07;
+
+	hwif->ide_dma_check = &pdcnew_config_drive_xfer_rate;
+	hwif->ide_dma_lostirq = &pdcnew_ide_dma_lostirq;
+	hwif->ide_dma_timeout = &pdcnew_ide_dma_timeout;
+	if (!(hwif->udma_four))
+		hwif->udma_four = (pdcnew_new_cable_detect(hwif)) ? 0 : 1;
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
+#if PDC202_DEBUG_CABLE
+	printk(KERN_DEBUG "%s: %s-pin cable\n",
+		hwif->name, hwif->udma_four ? "80" : "40");
+#endif /* PDC202_DEBUG_CABLE */
+}
+
+static void __init init_dma_pdc202new (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+extern void ide_setup_pci_devices(struct pci_dev *, struct pci_dev *, ide_pci_device_t *);
+
+static void __init init_setup_pdcnew (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+static void __init init_setup_pdc20270 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	struct pci_dev *findev;
+
+	if ((dev->bus->self &&
+	     dev->bus->self->vendor == PCI_VENDOR_ID_DEC) &&
+	    (dev->bus->self->device == PCI_DEVICE_ID_DEC_21150)) {
+		if (PCI_SLOT(dev->devfn) & 2) {
+			return;
+		}
+		d->extra = 0;
+		pci_for_each_dev(findev) {
+			if ((findev->vendor == dev->vendor) &&
+			    (findev->device == dev->device) &&
+			    (PCI_SLOT(findev->devfn) & 2)) {
+				u8 irq = 0, irq2 = 0;
+				pci_read_config_byte(dev,
+					PCI_INTERRUPT_LINE, &irq);
+				pci_read_config_byte(findev,
+					PCI_INTERRUPT_LINE, &irq2);
+				if (irq != irq2) {
+					findev->irq = dev->irq;
+					pci_write_config_byte(findev,
+						PCI_INTERRUPT_LINE, irq);
+				}
+				ide_setup_pci_devices(dev, findev, d);
+				return;
+			}
+		}
+	}
+	ide_setup_pci_device(dev, d);
+}
+
+static void __init init_setup_pdc20276 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	if ((dev->bus->self) &&
+	    (dev->bus->self->vendor == PCI_VENDOR_ID_INTEL) &&
+	    ((dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960) ||
+	     (dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960RM))) {
+		printk(KERN_INFO "ide: Skipping Promise PDC20276 "
+			"attached to I2O RAID controller.\n");
+		return;
+	}
+	ide_setup_pci_device(dev, d);
+}
+
+/**
+ *	pdc202new_init_one	-	called when a pdc202xx is found
+ *	@dev: the pdc202new device
+ *	@id: the matching pci id
+ *
+ *	Called when the PCI registration layer (or the IDE initialization)
+ *	finds a device matching our IDE device tables.
+ */
+ 
+static int __devinit pdc202new_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &pdcnew_chipsets[id->driver_data];
+
+	if (dev->device != d->device)
+		BUG();
+	d->init_setup(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id pdc202new_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20269, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20270, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20271, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20275, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20276, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20277, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "Promise IDE",
+	.id_table	= pdc202new_pci_tbl,
+	.probe		= pdc202new_init_one,
+};
+
+static int pdc202new_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void pdc202new_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(pdc202new_ide_init);
+module_exit(pdc202new_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick, Frank Tiernan");
+MODULE_DESCRIPTION("PCI driver module for Promise PDC20268 and higher");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/pdc202xx_new.h linux-2.4.21-pre6/drivers/ide/pci/pdc202xx_new.h
--- linux-2.4.20/drivers/ide/pci/pdc202xx_new.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/pdc202xx_new.h	2003-03-26 23:49:21.000000000 +0000
@@ -0,0 +1,308 @@
+#ifndef PDC202XX_H
+#define PDC202XX_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_PDC202XX_TIMINGS
+
+#ifndef SPLIT_BYTE
+#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
+#endif
+
+#define PDC202XX_DEBUG_DRIVE_INFO		0
+#define PDC202XX_DECODE_REGISTER_INFO		0
+
+const static char *pdc_quirk_drives[] = {
+	"QUANTUM FIREBALLlct08 08",
+	"QUANTUM FIREBALLP KA6.4",
+	"QUANTUM FIREBALLP KA9.1",
+	"QUANTUM FIREBALLP LM20.4",
+	"QUANTUM FIREBALLP KX13.6",
+	"QUANTUM FIREBALLP KX20.5",
+	"QUANTUM FIREBALLP KX27.3",
+	"QUANTUM FIREBALLP LM20.5",
+	NULL
+};
+
+/* A Register */
+#define	SYNC_ERRDY_EN	0xC0
+
+#define	SYNC_IN		0x80	/* control bit, different for master vs. slave drives */
+#define	ERRDY_EN	0x40	/* control bit, different for master vs. slave drives */
+#define	IORDY_EN	0x20	/* PIO: IOREADY */
+#define	PREFETCH_EN	0x10	/* PIO: PREFETCH */
+
+#define	PA3		0x08	/* PIO"A" timing */
+#define	PA2		0x04	/* PIO"A" timing */
+#define	PA1		0x02	/* PIO"A" timing */
+#define	PA0		0x01	/* PIO"A" timing */
+
+/* B Register */
+
+#define	MB2		0x80	/* DMA"B" timing */
+#define	MB1		0x40	/* DMA"B" timing */
+#define	MB0		0x20	/* DMA"B" timing */
+
+#define	PB4		0x10	/* PIO_FORCE 1:0 */
+
+#define	PB3		0x08	/* PIO"B" timing */	/* PIO flow Control mode */
+#define	PB2		0x04	/* PIO"B" timing */	/* PIO 4 */
+#define	PB1		0x02	/* PIO"B" timing */	/* PIO 3 half */
+#define	PB0		0x01	/* PIO"B" timing */	/* PIO 3 other half */
+
+/* C Register */
+#define	IORDYp_NO_SPEED	0x4F
+#define	SPEED_DIS	0x0F
+
+#define	DMARQp		0x80
+#define	IORDYp		0x40
+#define	DMAR_EN		0x20
+#define	DMAW_EN		0x10
+
+#define	MC3		0x08	/* DMA"C" timing */
+#define	MC2		0x04	/* DMA"C" timing */
+#define	MC1		0x02	/* DMA"C" timing */
+#define	MC0		0x01	/* DMA"C" timing */
+
+#if PDC202XX_DECODE_REGISTER_INFO
+
+#define REG_A		0x01
+#define REG_B		0x02
+#define REG_C		0x04
+#define REG_D		0x08
+
+static void decode_registers (u8 registers, u8 value)
+{
+	u8	bit = 0, bit1 = 0, bit2 = 0;
+
+	switch(registers) {
+		case REG_A:
+			bit2 = 0;
+			printk("A Register ");
+			if (value & 0x80) printk("SYNC_IN ");
+			if (value & 0x40) printk("ERRDY_EN ");
+			if (value & 0x20) printk("IORDY_EN ");
+			if (value & 0x10) printk("PREFETCH_EN ");
+			if (value & 0x08) { printk("PA3 ");bit2 |= 0x08; }
+			if (value & 0x04) { printk("PA2 ");bit2 |= 0x04; }
+			if (value & 0x02) { printk("PA1 ");bit2 |= 0x02; }
+			if (value & 0x01) { printk("PA0 ");bit2 |= 0x01; }
+			printk("PIO(A) = %d ", bit2);
+			break;
+		case REG_B:
+			bit1 = 0;bit2 = 0;
+			printk("B Register ");
+			if (value & 0x80) { printk("MB2 ");bit1 |= 0x80; }
+			if (value & 0x40) { printk("MB1 ");bit1 |= 0x40; }
+			if (value & 0x20) { printk("MB0 ");bit1 |= 0x20; }
+			printk("DMA(B) = %d ", bit1 >> 5);
+			if (value & 0x10) printk("PIO_FORCED/PB4 ");
+			if (value & 0x08) { printk("PB3 ");bit2 |= 0x08; }
+			if (value & 0x04) { printk("PB2 ");bit2 |= 0x04; }
+			if (value & 0x02) { printk("PB1 ");bit2 |= 0x02; }
+			if (value & 0x01) { printk("PB0 ");bit2 |= 0x01; }
+			printk("PIO(B) = %d ", bit2);
+			break;
+		case REG_C:
+			bit2 = 0;
+			printk("C Register ");
+			if (value & 0x80) printk("DMARQp ");
+			if (value & 0x40) printk("IORDYp ");
+			if (value & 0x20) printk("DMAR_EN ");
+			if (value & 0x10) printk("DMAW_EN ");
+
+			if (value & 0x08) { printk("MC3 ");bit2 |= 0x08; }
+			if (value & 0x04) { printk("MC2 ");bit2 |= 0x04; }
+			if (value & 0x02) { printk("MC1 ");bit2 |= 0x02; }
+			if (value & 0x01) { printk("MC0 ");bit2 |= 0x01; }
+			printk("DMA(C) = %d ", bit2);
+			break;
+		case REG_D:
+			printk("D Register ");
+			break;
+		default:
+			return;
+	}
+	printk("\n        %s ", (registers & REG_D) ? "DP" :
+				(registers & REG_C) ? "CP" :
+				(registers & REG_B) ? "BP" :
+				(registers & REG_A) ? "AP" : "ERROR");
+	for (bit=128;bit>0;bit/=2)
+		printk("%s", (value & bit) ? "1" : "0");
+	printk("\n");
+}
+
+#endif /* PDC202XX_DECODE_REGISTER_INFO */
+
+#define set_2regs(a, b)					\
+	do {						\
+		hwif->OUTB((a + adj), indexreg);	\
+		hwif->OUTB(b, datareg);			\
+	} while(0)
+
+#define set_ultra(a, b, c)				\
+	do {						\
+		set_2regs(0x10,(a));			\
+		set_2regs(0x11,(b));			\
+		set_2regs(0x12,(c));			\
+	} while(0)
+
+#define set_ata2(a, b)					\
+	do {						\
+		set_2regs(0x0e,(a));			\
+		set_2regs(0x0f,(b));			\
+	} while(0)
+
+#define set_pio(a, b, c)				\
+	do { 						\
+		set_2regs(0x0c,(a));			\
+		set_2regs(0x0d,(b));			\
+		set_2regs(0x13,(c));			\
+	} while(0)
+
+#define DISPLAY_PDC202XX_TIMINGS
+
+#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 pdcnew_proc;
+
+static int pdcnew_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t pdcnew_procs[] __initdata = {
+	{
+		.name		= "pdcnew",
+		.set		= 1,
+		.get_info	= pdcnew_get_info,
+		.parent		= NULL,
+	},
+};
+#endif /* DISPLAY_PDC202XX_TIMINGS && CONFIG_PROC_FS */
+
+
+static void init_setup_pdcnew(struct pci_dev *, ide_pci_device_t *);
+static void init_setup_pdc20270(struct pci_dev *, ide_pci_device_t *);
+static void init_setup_pdc20276(struct pci_dev *dev, ide_pci_device_t *d);
+static unsigned int init_chipset_pdcnew(struct pci_dev *, const char *);
+static void init_hwif_pdc202new(ide_hwif_t *);
+static void init_dma_pdc202new(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t pdcnew_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20268,
+		.name		= "PDC20268",
+		.init_setup	= init_setup_pdcnew,
+		.init_chipset	= init_chipset_pdcnew,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202new,
+		.init_dma	= init_dma_pdc202new,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
+	},{	/* 1 */
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20269,
+		.name		= "PDC20269",
+		.init_setup	= init_setup_pdcnew,
+		.init_chipset	= init_chipset_pdcnew,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202new,
+		.init_dma	= init_dma_pdc202new,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
+	},{	/* 2 */
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20270,
+		.name		= "PDC20270",
+		.init_setup	= init_setup_pdc20270,
+		.init_chipset	= init_chipset_pdcnew,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202new,
+		.init_dma	= init_dma_pdc202new,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+#ifdef CONFIG_PDC202XX_FORCE
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+#else /* !CONFIG_PDC202XX_FORCE */
+		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+#endif
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
+	},{	/* 3 */
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20271,
+		.name		= "PDC20271",
+		.init_setup	= init_setup_pdcnew,
+		.init_chipset	= init_chipset_pdcnew,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202new,
+		.init_dma	= init_dma_pdc202new,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
+	},{	/* 4 */
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20275,
+		.name		= "PDC20275",
+		.init_setup	= init_setup_pdcnew,
+		.init_chipset	= init_chipset_pdcnew,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202new,
+		.init_dma	= init_dma_pdc202new,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
+	},{	/* 5 */
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20276,
+		.name		= "PDC20276",
+		.init_setup	= init_setup_pdc20276,
+		.init_chipset	= init_chipset_pdcnew,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202new,
+		.init_dma	= init_dma_pdc202new,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+#ifdef CONFIG_PDC202XX_FORCE
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+#else /* !CONFIG_PDC202XX_FORCE */
+		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+#endif
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
+	},{	/* 6 */
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20277,
+		.name		= "PDC20277",
+		.init_setup	= init_setup_pdcnew,
+		.init_chipset	= init_chipset_pdcnew,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202new,
+		.init_dma	= init_dma_pdc202new,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* PDC202XX_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/pdc202xx_old.c linux-2.4.21-pre6/drivers/ide/pci/pdc202xx_old.c
--- linux-2.4.20/drivers/ide/pci/pdc202xx_old.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/pdc202xx_old.c	2003-03-26 23:48:57.000000000 +0000
@@ -0,0 +1,959 @@
+/*
+ *  linux/drivers/ide/pci/pdc202xx_old.c	Version 0.36	Sept 11, 2002
+ *
+ *  Copyright (C) 1998-2002		Andre Hedrick <andre@linux-ide.org>
+ *
+ *  Promise Ultra33 cards with BIOS v1.20 through 1.28 will need this
+ *  compiled into the kernel if you have more than one card installed.
+ *  Note that BIOS v1.29 is reported to fix the problem.  Since this is
+ *  safe chipset tuning, including this support is harmless
+ *
+ *  Promise Ultra66 cards with BIOS v1.11 this
+ *  compiled into the kernel if you have more than one card installed.
+ *
+ *  Promise Ultra100 cards.
+ *
+ *  The latest chipset code will support the following ::
+ *  Three Ultra33 controllers and 12 drives.
+ *  8 are UDMA supported and 4 are limited to DMA mode 2 multi-word.
+ *  The 8/4 ratio is a BIOS code limit by promise.
+ *
+ *  UNLESS you enable "CONFIG_PDC202XX_BURST"
+ *
+ */
+
+/*
+ *  Portions Copyright (C) 1999 Promise Technology, Inc.
+ *  Author: Frank Tiernan (frankt@promise.com)
+ *  Released under terms of General Public License
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+#include "pdc202xx_old.h"
+
+#define PDC202_DEBUG_CABLE	0
+
+#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 pdc202xx_proc = 0;
+#define PDC202_MAX_DEVS		5
+static struct pci_dev *pdc202_devs[PDC202_MAX_DEVS];
+static int n_pdc202_devs;
+
+static char * pdc202xx_info (char *buf, struct pci_dev *dev)
+{
+	char *p = buf;
+
+	unsigned long bibma  = pci_resource_start(dev, 4);
+	u32 reg60h = 0, reg64h = 0, reg68h = 0, reg6ch = 0;
+	u16 reg50h = 0, pmask = (1<<10), smask = (1<<11);
+	u8 hi = 0, lo = 0;
+
+        /*
+         * at that point bibma+0x2 et bibma+0xa are byte registers
+         * to investigate:
+         */
+	u8 c0	= inb_p((u16)bibma + 0x02);
+	u8 c1	= inb_p((u16)bibma + 0x0a);
+
+	u8 sc11	= inb_p((u16)bibma + 0x11);
+	u8 sc1a	= inb_p((u16)bibma + 0x1a);
+	u8 sc1b	= inb_p((u16)bibma + 0x1b);
+	u8 sc1c	= inb_p((u16)bibma + 0x1c); 
+	u8 sc1d	= inb_p((u16)bibma + 0x1d);
+	u8 sc1e	= inb_p((u16)bibma + 0x1e);
+	u8 sc1f	= inb_p((u16)bibma + 0x1f);
+
+	pci_read_config_word(dev, 0x50, &reg50h);
+	pci_read_config_dword(dev, 0x60, &reg60h);
+	pci_read_config_dword(dev, 0x64, &reg64h);
+	pci_read_config_dword(dev, 0x68, &reg68h);
+	pci_read_config_dword(dev, 0x6c, &reg6ch);
+
+	p += sprintf(p, "\n                                ");
+	switch(dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20267:
+			p += sprintf(p, "Ultra100"); break;
+		case PCI_DEVICE_ID_PROMISE_20265:
+			p += sprintf(p, "Ultra100 on M/B"); break;
+		case PCI_DEVICE_ID_PROMISE_20263:
+			p += sprintf(p, "FastTrak 66"); break;
+		case PCI_DEVICE_ID_PROMISE_20262:
+			p += sprintf(p, "Ultra66"); break;
+		case PCI_DEVICE_ID_PROMISE_20246:
+			p += sprintf(p, "Ultra33");
+			reg50h |= 0x0c00;
+			break;
+		default:
+			p += sprintf(p, "Ultra Series"); break;
+	}
+	p += sprintf(p, " Chipset.\n");
+
+	p += sprintf(p, "------------------------------- General Status "
+			"---------------------------------\n");
+	p += sprintf(p, "Burst Mode                           : %sabled\n",
+		(sc1f & 0x01) ? "en" : "dis");
+	p += sprintf(p, "Host Mode                            : %s\n",
+		(sc1f & 0x08) ? "Tri-Stated" : "Normal");
+	p += sprintf(p, "Bus Clocking                         : %s\n",
+		((sc1f & 0xC0) == 0xC0) ? "100 External" :
+		((sc1f & 0x80) == 0x80) ? "66 External" :
+		((sc1f & 0x40) == 0x40) ? "33 External" : "33 PCI Internal");
+	p += sprintf(p, "IO pad select                        : %s mA\n",
+		((sc1c & 0x03) == 0x03) ? "10" :
+		((sc1c & 0x02) == 0x02) ? "8" :
+		((sc1c & 0x01) == 0x01) ? "6" :
+		((sc1c & 0x00) == 0x00) ? "4" : "??");
+	SPLIT_BYTE(sc1e, hi, lo);
+	p += sprintf(p, "Status Polling Period                : %d\n", hi);
+	p += sprintf(p, "Interrupt Check Status Polling Delay : %d\n", lo);
+	p += sprintf(p, "--------------- Primary Channel "
+			"---------------- Secondary Channel "
+			"-------------\n");
+	p += sprintf(p, "                %s                         %s\n",
+		(c0&0x80)?"disabled":"enabled ",
+		(c1&0x80)?"disabled":"enabled ");
+	p += sprintf(p, "66 Clocking     %s                         %s\n",
+		(sc11&0x02)?"enabled ":"disabled",
+		(sc11&0x08)?"enabled ":"disabled");
+	p += sprintf(p, "           Mode %s                      Mode %s\n",
+		(sc1a & 0x01) ? "MASTER" : "PCI   ",
+		(sc1b & 0x01) ? "MASTER" : "PCI   ");
+	p += sprintf(p, "                %s                     %s\n",
+		(sc1d & 0x08) ? "Error       " :
+		((sc1d & 0x05) == 0x05) ? "Not My INTR " :
+		(sc1d & 0x04) ? "Interrupting" :
+		(sc1d & 0x02) ? "FIFO Full   " :
+		(sc1d & 0x01) ? "FIFO Empty  " : "????????????",
+		(sc1d & 0x80) ? "Error       " :
+		((sc1d & 0x50) == 0x50) ? "Not My INTR " :
+		(sc1d & 0x40) ? "Interrupting" :
+		(sc1d & 0x20) ? "FIFO Full   " :
+		(sc1d & 0x10) ? "FIFO Empty  " : "????????????");
+	p += sprintf(p, "--------------- drive0 --------- drive1 "
+			"-------- drive0 ---------- drive1 ------\n");
+	p += sprintf(p, "DMA enabled:    %s              %s "
+			"            %s               %s\n",
+		(c0&0x20)?"yes":"no ", (c0&0x40)?"yes":"no ",
+		(c1&0x20)?"yes":"no ", (c1&0x40)?"yes":"no ");
+	p += sprintf(p, "DMA Mode:       %s           %s "
+			"         %s            %s\n",
+		pdc202xx_ultra_verbose(reg60h, (reg50h & pmask)),
+		pdc202xx_ultra_verbose(reg64h, (reg50h & pmask)),
+		pdc202xx_ultra_verbose(reg68h, (reg50h & smask)),
+		pdc202xx_ultra_verbose(reg6ch, (reg50h & smask)));
+	p += sprintf(p, "PIO Mode:       %s            %s "
+			"          %s            %s\n",
+		pdc202xx_pio_verbose(reg60h),
+		pdc202xx_pio_verbose(reg64h),
+		pdc202xx_pio_verbose(reg68h),
+		pdc202xx_pio_verbose(reg6ch));
+#if 0
+	p += sprintf(p, "--------------- Can ATAPI DMA ---------------\n");
+#endif
+	return (char *)p;
+}
+
+static int pdc202xx_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	int i;
+
+	for (i = 0; i < n_pdc202_devs; i++) {
+		struct pci_dev *dev	= pdc202_devs[i];
+		p = pdc202xx_info(buffer, dev);
+	}
+	return p-buffer;	/* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+
+static u8 pdc202xx_ratemask (ide_drive_t *drive)
+{
+	u8 mode;
+
+	switch(HWIF(drive)->pci_dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20267:
+		case PCI_DEVICE_ID_PROMISE_20265:
+			mode = 3;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20263:
+		case PCI_DEVICE_ID_PROMISE_20262:
+			mode = 2;
+			break;
+		case PCI_DEVICE_ID_PROMISE_20246:
+			return 1;
+		default:
+			return 0;
+	}
+	if (!eighty_ninty_three(drive))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+static int check_in_drive_lists (ide_drive_t *drive, const char **list)
+{
+	struct hd_driveid *id = drive->id;
+
+	if (pdc_quirk_drives == list) {
+		while (*list) {
+			if (strstr(id->model, *list++)) {
+				return 2;
+			}
+		}
+	} else {
+		while (*list) {
+			if (!strcmp(*list++,id->model)) {
+				return 1;
+			}
+		}
+	}
+	return 0;
+}
+
+static int pdc202xx_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 drive_pci		= 0x60 + (drive->dn << 2);
+	u8 speed	= ide_rate_filter(pdc202xx_ratemask(drive), xferspeed);
+
+	u32			drive_conf;
+	u8			AP, BP, CP, DP;
+	u8			TA = 0, TB = 0, TC = 0;
+
+	if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))
+		return -1;
+
+	pci_read_config_dword(dev, drive_pci, &drive_conf);
+	pci_read_config_byte(dev, (drive_pci), &AP);
+	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+	pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
+
+	if (speed < XFER_SW_DMA_0) {
+		if ((AP & 0x0F) || (BP & 0x07)) {
+			/* clear PIO modes of lower 8421 bits of A Register */
+			pci_write_config_byte(dev, (drive_pci), AP &~0x0F);
+			pci_read_config_byte(dev, (drive_pci), &AP);
+
+			/* clear PIO modes of lower 421 bits of B Register */
+			pci_write_config_byte(dev, (drive_pci)|0x01, BP &~0x07);
+			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+
+			pci_read_config_byte(dev, (drive_pci), &AP);
+			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+		}
+	} else {
+		if ((BP & 0xF0) && (CP & 0x0F)) {
+			/* clear DMA modes of upper 842 bits of B Register */
+			/* clear PIO forced mode upper 1 bit of B Register */
+			pci_write_config_byte(dev, (drive_pci)|0x01, BP &~0xF0);
+			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+
+			/* clear DMA modes of lower 8421 bits of C Register */
+			pci_write_config_byte(dev, (drive_pci)|0x02, CP &~0x0F);
+			pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+		}
+	}
+
+	pci_read_config_byte(dev, (drive_pci), &AP);
+	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+
+	switch(speed) {
+		case XFER_UDMA_6:	speed = XFER_UDMA_5;
+		case XFER_UDMA_5:
+		case XFER_UDMA_4:	TB = 0x20; TC = 0x01; break;
+		case XFER_UDMA_2:	TB = 0x20; TC = 0x01; break;
+		case XFER_UDMA_3:
+		case XFER_UDMA_1:	TB = 0x40; TC = 0x02; break;
+		case XFER_UDMA_0:
+		case XFER_MW_DMA_2:	TB = 0x60; TC = 0x03; break;
+		case XFER_MW_DMA_1:	TB = 0x60; TC = 0x04; break;
+		case XFER_MW_DMA_0:
+		case XFER_SW_DMA_2:	TB = 0x60; TC = 0x05; break;
+		case XFER_SW_DMA_1:	TB = 0x80; TC = 0x06; break;
+		case XFER_SW_DMA_0:	TB = 0xC0; TC = 0x0B; break;
+		case XFER_PIO_4:	TA = 0x01; TB = 0x04; break;
+		case XFER_PIO_3:	TA = 0x02; TB = 0x06; break;
+		case XFER_PIO_2:	TA = 0x03; TB = 0x08; break;
+		case XFER_PIO_1:	TA = 0x05; TB = 0x0C; break;
+		case XFER_PIO_0:
+		default:		TA = 0x09; TB = 0x13; break;
+	}
+
+	if (speed < XFER_SW_DMA_0) {
+		pci_write_config_byte(dev, (drive_pci), AP|TA);
+		pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
+	} else {
+		pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
+		pci_write_config_byte(dev, (drive_pci)|0x02, CP|TC);
+	}
+
+#if PDC202XX_DECODE_REGISTER_INFO
+	pci_read_config_byte(dev, (drive_pci), &AP);
+	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+	pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
+
+	decode_registers(REG_A, AP);
+	decode_registers(REG_B, BP);
+	decode_registers(REG_C, CP);
+	decode_registers(REG_D, DP);
+#endif /* PDC202XX_DECODE_REGISTER_INFO */
+#if PDC202XX_DEBUG_DRIVE_INFO
+	printk(KERN_DEBUG "%s: %s drive%d 0x%08x ",
+		drive->name, ide_xfer_verbose(speed),
+		drive->dn, drive_conf);
+		pci_read_config_dword(dev, drive_pci, &drive_conf);
+	printk("0x%08x\n", drive_conf);
+#endif /* PDC202XX_DEBUG_DRIVE_INFO */
+
+	return (ide_config_drive_speed(drive, speed));
+}
+
+
+/*   0    1    2    3    4    5    6   7   8
+ * 960, 480, 390, 300, 240, 180, 120, 90, 60
+ *           180, 150, 120,  90,  60
+ * DMA_Speed
+ * 180, 120,  90,  90,  90,  60,  30
+ *  11,   5,   4,   3,   2,   1,   0
+ */
+static void config_chipset_for_pio (ide_drive_t *drive, u8 pio)
+{
+	u8 speed = 0;
+
+	if (pio == 5) pio = 4;
+	speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, pio, NULL);
+        
+	pdc202xx_tune_chipset(drive, speed);
+}
+
+static u8 pdc202xx_old_cable_detect (ide_hwif_t *hwif)
+{
+	u16 CIS = 0, mask = (hwif->channel) ? (1<<11) : (1<<10);
+	pci_read_config_word(hwif->pci_dev, 0x50, &CIS);
+	return ((u8)(CIS & mask));
+}
+
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	struct hd_driveid *id	= drive->id;
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u32 drive_conf		= 0;
+	u8 mask			= hwif->channel ? 0x08 : 0x02;
+	u8 drive_pci		= 0x60 + (drive->dn << 2);
+	u8 test1 = 0, test2 = 0, speed = -1;
+	u8 AP = 0, CLKSPD = 0, cable = 0;
+
+	u8 ultra_66		= ((id->dma_ultra & 0x0010) ||
+				   (id->dma_ultra & 0x0008)) ? 1 : 0;
+
+	switch(dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20267:
+		case PCI_DEVICE_ID_PROMISE_20265:
+		case PCI_DEVICE_ID_PROMISE_20263:
+		case PCI_DEVICE_ID_PROMISE_20262:
+			cable = pdc202xx_old_cable_detect(hwif);
+#if PDC202_DEBUG_CABLE
+			printk(KERN_DEBUG "%s: %s-pin cable, %s-pin cable, %d\n",
+				hwif->name, hwif->udma_four ? "80" : "40",
+				cable ? "40" : "80", cable);
+#endif /* PDC202_DEBUG_CABLE */
+			break;
+		case PCI_DEVICE_ID_PROMISE_20246:
+			ultra_66 = 0;
+			break;
+		default:
+			BUG();
+	}
+
+	CLKSPD = hwif->INB(hwif->dma_master + 0x11);
+
+	/*
+	 * Set the control register to use the 66Mhz system
+	 * clock for UDMA 3/4 mode operation. If one drive on
+	 * a channel is U66 capable but the other isn't we
+	 * fall back to U33 mode. The BIOS INT 13 hooks turn
+	 * the clock on then off for each read/write issued. I don't
+	 * do that here because it would require modifying the
+	 * kernel, seperating the fop routines from the kernel or
+	 * somehow hooking the fops calls. It may also be possible to
+	 * leave the 66Mhz clock on and readjust the timing
+	 * parameters.
+	 */
+
+	if ((ultra_66) && (cable)) {
+#ifdef DEBUG
+		printk(KERN_DEBUG "ULTRA 66/100/133: %s channel of Ultra 66/100/133 "
+			"requires an 80-pin cable for Ultra66 operation.\n",
+			hwif->channel ? "Secondary" : "Primary");
+		printk(KERN_DEBUG "         Switching to Ultra33 mode.\n");
+#endif /* DEBUG */
+		/* Primary   : zero out second bit */
+		/* Secondary : zero out fourth bit */
+		hwif->OUTB(CLKSPD & ~mask, (hwif->dma_master + 0x11));
+		printk(KERN_WARNING "Warning: %s channel requires an 80-pin cable for operation.\n", hwif->channel ? "Secondary":"Primary");
+		printk(KERN_WARNING "%s reduced to Ultra33 mode.\n", drive->name);
+	} else {
+		if (ultra_66) {
+			/*
+			 * check to make sure drive on same channel
+			 * is u66 capable
+			 */
+			if (hwif->drives[!(drive->dn%2)].id) {
+				if (hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0078) {
+					hwif->OUTB(CLKSPD | mask, (hwif->dma_master + 0x11));
+				} else {
+					hwif->OUTB(CLKSPD & ~mask, (hwif->dma_master + 0x11));
+				}
+			} else { /* udma4 drive by itself */
+				hwif->OUTB(CLKSPD | mask, (hwif->dma_master + 0x11));
+			}
+		}
+	}
+
+	drive_pci = 0x60 + (drive->dn << 2);
+	pci_read_config_dword(dev, drive_pci, &drive_conf);
+	if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
+		goto chipset_is_set;
+
+	pci_read_config_byte(dev, drive_pci, &test1);
+	if (!(test1 & SYNC_ERRDY_EN)) {
+		if (drive->select.b.unit & 0x01) {
+			pci_read_config_byte(dev, drive_pci - 4, &test2);
+			if ((test2 & SYNC_ERRDY_EN) &&
+			    !(test1 & SYNC_ERRDY_EN)) {
+				pci_write_config_byte(dev, drive_pci,
+					test1|SYNC_ERRDY_EN);
+			}
+		} else {
+			pci_write_config_byte(dev, drive_pci,
+				test1|SYNC_ERRDY_EN);
+		}
+	}
+
+chipset_is_set:
+
+	if (drive->media == ide_disk) {
+		pci_read_config_byte(dev, (drive_pci), &AP);
+		if (id->capability & 4)	/* IORDY_EN */
+			pci_write_config_byte(dev, (drive_pci), AP|IORDY_EN);
+		pci_read_config_byte(dev, (drive_pci), &AP);
+		if (drive->media == ide_disk)	/* PREFETCH_EN */
+			pci_write_config_byte(dev, (drive_pci), AP|PREFETCH_EN);
+	}
+
+	speed = ide_dma_speed(drive, pdc202xx_ratemask(drive));
+
+	if (!(speed)) {
+		/* restore original pci-config space */
+		pci_write_config_dword(dev, drive_pci, drive_conf);
+		hwif->tuneproc(drive, 5);
+		return 0;
+	}
+
+	(void) hwif->speedproc(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static int pdc202xx_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	drive->init_speed = 0;
+
+	if (id && (id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			    (id->eide_dma_time < 150)) {
+				goto no_dma_set;
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		hwif->tuneproc(drive, 5);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+static int pdc202xx_quirkproc (ide_drive_t *drive)
+{
+	return ((int) check_in_drive_lists(drive, pdc_quirk_drives));
+}
+
+static int pdc202xx_old_ide_dma_begin(ide_drive_t *drive)
+{
+	if (drive->addressing == 1) {
+		struct request *rq	= HWGROUP(drive)->rq;
+		ide_hwif_t *hwif	= HWIF(drive);
+//		struct pci_dev *dev	= hwif->pci_dev;
+//		unsgned long high_16	= pci_resource_start(dev, 4);
+		unsigned long high_16   = hwif->dma_master;
+		unsigned long atapi_reg	= high_16 + (hwif->channel ? 0x24 : 0x20);
+		u32 word_count	= 0;
+		u8 clock = hwif->INB(high_16 + 0x11);
+
+		hwif->OUTB(clock|(hwif->channel ? 0x08 : 0x02), high_16+0x11);
+		word_count = (rq->nr_sectors << 8);
+		word_count = (rq_data_dir(rq) == READ) ?
+					word_count | 0x05000000 :
+					word_count | 0x06000000;
+		hwif->OUTL(word_count, atapi_reg);
+	}
+	return __ide_dma_begin(drive);
+}
+
+static int pdc202xx_old_ide_dma_end(ide_drive_t *drive)
+{
+	if (drive->addressing == 1) {
+		ide_hwif_t *hwif	= HWIF(drive);
+//		unsigned long high_16	= pci_resource_start(hwif->pci_dev, 4);
+		unsigned long high_16	= hwif->dma_master;
+		unsigned long atapi_reg	= high_16 + (hwif->channel ? 0x24 : 0x20);
+		u8 clock		= 0;
+
+		hwif->OUTL(0, atapi_reg); /* zero out extra */
+		clock = hwif->INB(high_16 + 0x11);
+		hwif->OUTB(clock & ~(hwif->channel ? 0x08:0x02), high_16+0x11);
+	}
+	return __ide_dma_end(drive);
+}
+
+static int pdc202xx_old_ide_dma_test_irq(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+//	struct pci_dev *dev	= hwif->pci_dev;
+//	unsigned long high_16	= pci_resource_start(dev, 4);
+	unsigned long high_16	= hwif->dma_master;
+	u8 dma_stat		= hwif->INB(hwif->dma_status);
+	u8 sc1d			= hwif->INB((high_16 + 0x001d));
+
+	if (hwif->channel) {
+		if ((sc1d & 0x50) == 0x50)
+			goto somebody_else;
+		else if ((sc1d & 0x40) == 0x40)
+			return (dma_stat & 4) == 4;
+	} else {
+		if ((sc1d & 0x05) == 0x05)
+			goto somebody_else;
+		else if ((sc1d & 0x04) == 0x04)
+			return (dma_stat & 4) == 4;
+	}
+somebody_else:
+	return (dma_stat & 4) == 4;	/* return 1 if INTR asserted */
+}
+
+static int pdc202xx_ide_dma_lostirq(ide_drive_t *drive)
+{
+	if (HWIF(drive)->resetproc != NULL)
+		HWIF(drive)->resetproc(drive);
+	return __ide_dma_lostirq(drive);
+}
+
+static int pdc202xx_ide_dma_timeout(ide_drive_t *drive)
+{
+	if (HWIF(drive)->resetproc != NULL)
+		HWIF(drive)->resetproc(drive);
+	return __ide_dma_timeout(drive);
+}
+
+static void pdc202xx_reset_host (ide_hwif_t *hwif)
+{
+#ifdef CONFIG_BLK_DEV_IDEDMA
+//	unsigned long high_16	= hwif->dma_base - (8*(hwif->channel));
+	unsigned long high_16	= hwif->dma_master;
+#else /* !CONFIG_BLK_DEV_IDEDMA */
+	unsigned long high_16	= pci_resource_start(hwif->pci_dev, 4);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+	u8 udma_speed_flag	= hwif->INB(high_16|0x001f);
+
+	hwif->OUTB((udma_speed_flag | 0x10), (high_16|0x001f));
+	mdelay(100);
+	hwif->OUTB((udma_speed_flag & ~0x10), (high_16|0x001f));
+	mdelay(2000);	/* 2 seconds ?! */
+
+	printk(KERN_WARNING "PDC202XX: %s channel reset.\n",
+		hwif->channel ? "Secondary" : "Primary");
+}
+
+void pdc202xx_reset (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	ide_hwif_t *mate	= hwif->mate;
+	
+	pdc202xx_reset_host(hwif);
+	pdc202xx_reset_host(mate);
+#if 0
+	/*
+	 * FIXME: Have to kick all the drives again :-/
+	 * What a pain in the ACE!
+	 */
+	if (hwif->present) {
+		u16 hunit = 0;
+		hwif->initializing = 1;
+		for (hunit = 0; hunit < MAX_DRIVES; ++hunit) {
+			ide_drive_t *hdrive = &hwif->drives[hunit];
+			if (hdrive->present) {
+				if (hwif->ide_dma_check)
+					hwif->ide_dma_check(hdrive);
+				else
+					hwif->tuneproc(hdrive, 5);
+			}
+		}
+		hwif->initializing = 0;
+	}
+	if (mate->present) {
+		u16 munit = 0;
+		mate->initializing = 1;
+		for (munit = 0; munit < MAX_DRIVES; ++munit) {
+			ide_drive_t *mdrive = &mate->drives[munit];
+			if (mdrive->present) {
+				if (mate->ide_dma_check) 
+					mate->ide_dma_check(mdrive);
+				else
+					mate->tuneproc(mdrive, 5);
+			}
+		}
+		mate->initializing = 0;
+	}
+#else
+	hwif->tuneproc(drive, 5);
+#endif
+}
+
+/*
+ * Since SUN Cobalt is attempting to do this operation, I should disclose
+ * this has been a long time ago Thu Jul 27 16:40:57 2000 was the patch date
+ * HOTSWAP ATA Infrastructure.
+ */
+static int pdc202xx_tristate (ide_drive_t * drive, int state)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+//	unsigned long high_16	= hwif->dma_base - (8*(hwif->channel));
+	unsigned long high_16	= hwif->dma_master;
+	u8 sc1f			= hwif->INB(high_16|0x001f);
+
+	if (!hwif)
+		return -EINVAL;
+
+//	hwif->bus_state = state;
+
+	if (state) {
+		hwif->OUTB(sc1f | 0x08, (high_16|0x001f));
+	} else {
+		hwif->OUTB(sc1f & ~0x08, (high_16|0x001f));
+	}
+	return 0;
+}
+
+static unsigned int __init init_chipset_pdc202xx (struct pci_dev *dev, const char *name)
+{
+	if (dev->resource[PCI_ROM_RESOURCE].start) {
+		pci_write_config_dword(dev, PCI_ROM_ADDRESS,
+			dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+		printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n",
+			name, dev->resource[PCI_ROM_RESOURCE].start);
+	}
+
+#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
+	pdc202_devs[n_pdc202_devs++] = dev;
+
+	if (!pdc202xx_proc) {
+		pdc202xx_proc = 1;
+		ide_pci_register_host_proc(&pdc202xx_procs[0]);
+	}
+#endif /* DISPLAY_PDC202XX_TIMINGS && CONFIG_PROC_FS */
+
+	/*
+	 * software reset -  this is required because the bios
+	 * will set UDMA timing on if the hdd supports it. The
+	 * user may want to turn udma off. A bug in the pdc20262
+	 * is that it cannot handle a downgrade in timing from
+	 * UDMA to DMA. Disk accesses after issuing a set
+	 * feature command will result in errors. A software
+	 * reset leaves the timing registers intact,
+	 * but resets the drives.
+	 */
+#if 0
+	if ((dev->device == PCI_DEVICE_ID_PROMISE_20267) ||
+	    (dev->device == PCI_DEVICE_ID_PROMISE_20265) ||
+	    (dev->device == PCI_DEVICE_ID_PROMISE_20263) ||
+	    (dev->device == PCI_DEVICE_ID_PROMISE_20262)) {
+		unsigned long high_16	= pci_resource_start(dev, 4);
+		byte udma_speed_flag	= inb(high_16 + 0x001f);
+		outb(udma_speed_flag | 0x10, high_16 + 0x001f);
+		mdelay(100);
+		outb(udma_speed_flag & ~0x10, high_16 + 0x001f);
+		mdelay(2000);	/* 2 seconds ?! */
+	}
+
+#endif
+	return dev->irq;
+}
+
+static void __init init_hwif_pdc202xx (ide_hwif_t *hwif)
+{
+	hwif->autodma = 0;
+	hwif->tuneproc  = &config_chipset_for_pio;
+	hwif->quirkproc = &pdc202xx_quirkproc;
+
+	if (hwif->pci_dev->device == PCI_DEVICE_ID_PROMISE_20265)
+		hwif->addressing = (hwif->channel) ? 0 : 1;
+
+	if (hwif->pci_dev->device != PCI_DEVICE_ID_PROMISE_20246) {
+		hwif->busproc   = &pdc202xx_tristate;
+		hwif->resetproc = &pdc202xx_reset;
+	}
+
+	hwif->speedproc = &pdc202xx_tune_chipset;
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->ultra_mask = 0x3f;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+	hwif->ide_dma_check = &pdc202xx_config_drive_xfer_rate;
+	hwif->ide_dma_lostirq = &pdc202xx_ide_dma_lostirq;
+	hwif->ide_dma_timeout = &pdc202xx_ide_dma_timeout;
+
+	if (hwif->pci_dev->device != PCI_DEVICE_ID_PROMISE_20246) {
+		if (!(hwif->udma_four))
+			hwif->udma_four = (pdc202xx_old_cable_detect(hwif)) ? 0 : 1;
+		hwif->ide_dma_begin = &pdc202xx_old_ide_dma_begin;
+		hwif->ide_dma_end = &pdc202xx_old_ide_dma_end;
+	} 
+	hwif->ide_dma_test_irq = &pdc202xx_old_ide_dma_test_irq;
+
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
+#if PDC202_DEBUG_CABLE
+	printk(KERN_DEBUG "%s: %s-pin cable\n",
+		hwif->name, hwif->udma_four ? "80" : "40");
+#endif /* PDC202_DEBUG_CABLE */	
+}
+
+static void __init init_dma_pdc202xx (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	u8 udma_speed_flag = 0, primary_mode = 0, secondary_mode = 0;
+
+	if (hwif->channel) {
+		ide_setup_dma(hwif, dmabase, 8);
+		return;
+	}
+
+	udma_speed_flag	= hwif->INB((dmabase|0x1f));
+	primary_mode	= hwif->INB((dmabase|0x1a));
+	secondary_mode	= hwif->INB((dmabase|0x1b));
+	printk(KERN_INFO "%s: (U)DMA Burst Bit %sABLED " \
+		"Primary %s Mode " \
+		"Secondary %s Mode.\n", hwif->cds->name,
+		(udma_speed_flag & 1) ? "EN" : "DIS",
+		(primary_mode & 1) ? "MASTER" : "PCI",
+		(secondary_mode & 1) ? "MASTER" : "PCI" );
+
+#ifdef CONFIG_PDC202XX_BURST
+	if (!(udma_speed_flag & 1)) {
+		printk(KERN_INFO "%s: FORCING BURST BIT 0x%02x->0x%02x ",
+			hwif->cds->name, udma_speed_flag,
+			(udma_speed_flag|1));
+		hwif->OUTB(udma_speed_flag|1,(dmabase|0x1f));
+		printk("%sACTIVE\n",
+			(hwif->INB(dmabase|0x1f)&1) ? "":"IN");
+	}
+#endif /* CONFIG_PDC202XX_BURST */
+#ifdef CONFIG_PDC202XX_MASTER
+	if (!(primary_mode & 1)) {
+		printk(KERN_INFO "%s: FORCING PRIMARY MODE BIT "
+			"0x%02x -> 0x%02x ", hwif->cds->name,
+			primary_mode, (primary_mode|1));
+		hwif->OUTB(primary_mode|1, (dmabase|0x1a));
+		printk("%s\n",
+			(hwif->INB((dmabase|0x1a)) & 1) ? "MASTER" : "PCI");
+	}
+
+	if (!(secondary_mode & 1)) {
+		printk(KERN_INFO "%s: FORCING SECONDARY MODE BIT "
+			"0x%02x -> 0x%02x ", hwif->cds->name,
+			secondary_mode, (secondary_mode|1));
+		hwif->OUTB(secondary_mode|1, (dmabase|0x1b));
+		printk("%s\n",
+			(hwif->INB((dmabase|0x1b)) & 1) ? "MASTER" : "PCI");
+	}
+#endif /* CONFIG_PDC202XX_MASTER */
+
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+extern void ide_setup_pci_devices(struct pci_dev *, struct pci_dev *, ide_pci_device_t *);
+
+static void __init init_setup_pdc202ata4 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) {
+		u8 irq = 0, irq2 = 0;
+		pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+		/* 0xbc */
+		pci_read_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, &irq2);
+		if (irq != irq2) {
+			pci_write_config_byte(dev,
+				(PCI_INTERRUPT_LINE)|0x80, irq);     /* 0xbc */
+			printk(KERN_INFO "%s: pci-config space interrupt "
+				"mirror fixed.\n", d->name);
+		}
+	}
+
+#if 0
+        if (dev->device == PCI_DEVICE_ID_PROMISE_20262)
+        if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) ||
+             (tmp & e->mask) != e->val))
+
+        if (d->enablebits[0].reg != d->enablebits[1].reg) {
+                d->enablebits[0].reg    = d->enablebits[1].reg;
+                d->enablebits[0].mask   = d->enablebits[1].mask;
+                d->enablebits[0].val    = d->enablebits[1].val;
+        }
+#endif
+
+	ide_setup_pci_device(dev, d);
+}
+
+static void __init init_setup_pdc20265 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	if ((dev->bus->self) &&
+	    (dev->bus->self->vendor == PCI_VENDOR_ID_INTEL) &&
+	    ((dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960) ||
+	     (dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960RM))) {
+		printk(KERN_INFO "ide: Skipping Promise PDC20265 "
+			"attached to I2O RAID controller.\n");
+		return;
+	}
+
+#if 0
+        {
+                u8 pri = 0, sec = 0;
+
+        if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) ||
+             (tmp & e->mask) != e->val))
+
+        if (d->enablebits[0].reg != d->enablebits[1].reg) {
+                d->enablebits[0].reg    = d->enablebits[1].reg;
+                d->enablebits[0].mask   = d->enablebits[1].mask;
+                d->enablebits[0].val    = d->enablebits[1].val;
+        }
+        }
+#endif
+
+	ide_setup_pci_device(dev, d);
+}
+
+static void __init init_setup_pdc202xx (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+/**
+ *	pdc202xx_init_one	-	called when a PDC202xx is found
+ *	@dev: the pdc202xx device
+ *	@id: the matching pci id
+ *
+ *	Called when the PCI registration layer (or the IDE initialization)
+ *	finds a device matching our IDE device tables.
+ */
+ 
+static int __devinit pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &pdc202xx_chipsets[id->driver_data];
+
+	if (dev->device != d->device)
+		BUG();
+	d->init_setup(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id pdc202xx_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20262, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20263, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20265, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20267, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "Promise Old IDE",
+	.id_table	= pdc202xx_pci_tbl,
+	.probe		= pdc202xx_init_one,
+};
+
+static int pdc202xx_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void pdc202xx_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(pdc202xx_ide_init);
+module_exit(pdc202xx_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick, Frank Tiernan");
+MODULE_DESCRIPTION("PCI driver module for older Promise IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/pdc202xx_old.h linux-2.4.21-pre6/drivers/ide/pci/pdc202xx_old.h
--- linux-2.4.20/drivers/ide/pci/pdc202xx_old.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/pdc202xx_old.h	2003-03-26 23:48:58.000000000 +0000
@@ -0,0 +1,326 @@
+#ifndef PDC202XX_H
+#define PDC202XX_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_PDC202XX_TIMINGS
+
+#ifndef SPLIT_BYTE
+#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
+#endif
+
+#define PDC202XX_DEBUG_DRIVE_INFO		0
+#define PDC202XX_DECODE_REGISTER_INFO		0
+
+const static char *pdc_quirk_drives[] = {
+	"QUANTUM FIREBALLlct08 08",
+	"QUANTUM FIREBALLP KA6.4",
+	"QUANTUM FIREBALLP KA9.1",
+	"QUANTUM FIREBALLP LM20.4",
+	"QUANTUM FIREBALLP KX13.6",
+	"QUANTUM FIREBALLP KX20.5",
+	"QUANTUM FIREBALLP KX27.3",
+	"QUANTUM FIREBALLP LM20.5",
+	NULL
+};
+
+static inline u8 *pdc202xx_pio_verbose (u32 drive_pci)
+{
+	if ((drive_pci & 0x000ff000) == 0x000ff000) return("NOTSET");
+	if ((drive_pci & 0x00000401) == 0x00000401) return("PIO 4");
+	if ((drive_pci & 0x00000602) == 0x00000602) return("PIO 3");
+	if ((drive_pci & 0x00000803) == 0x00000803) return("PIO 2");
+	if ((drive_pci & 0x00000C05) == 0x00000C05) return("PIO 1");
+	if ((drive_pci & 0x00001309) == 0x00001309) return("PIO 0");
+	return("PIO ?");
+}
+
+static inline u8 *pdc202xx_dma_verbose (u32 drive_pci)
+{
+	if ((drive_pci & 0x00036000) == 0x00036000) return("MWDMA 2");
+	if ((drive_pci & 0x00046000) == 0x00046000) return("MWDMA 1");
+	if ((drive_pci & 0x00056000) == 0x00056000) return("MWDMA 0");
+	if ((drive_pci & 0x00056000) == 0x00056000) return("SWDMA 2");
+	if ((drive_pci & 0x00068000) == 0x00068000) return("SWDMA 1");
+	if ((drive_pci & 0x000BC000) == 0x000BC000) return("SWDMA 0");
+	return("PIO---");
+}
+
+static inline u8 *pdc202xx_ultra_verbose (u32 drive_pci, u16 slow_cable)
+{
+	if ((drive_pci & 0x000ff000) == 0x000ff000)
+		return("NOTSET");
+	if ((drive_pci & 0x00012000) == 0x00012000)
+		return((slow_cable) ? "UDMA 2" : "UDMA 4");
+	if ((drive_pci & 0x00024000) == 0x00024000)
+		return((slow_cable) ? "UDMA 1" : "UDMA 3");
+	if ((drive_pci & 0x00036000) == 0x00036000)
+		return("UDMA 0");
+	return(pdc202xx_dma_verbose(drive_pci));
+}
+
+/* A Register */
+#define	SYNC_ERRDY_EN	0xC0
+
+#define	SYNC_IN		0x80	/* control bit, different for master vs. slave drives */
+#define	ERRDY_EN	0x40	/* control bit, different for master vs. slave drives */
+#define	IORDY_EN	0x20	/* PIO: IOREADY */
+#define	PREFETCH_EN	0x10	/* PIO: PREFETCH */
+
+#define	PA3		0x08	/* PIO"A" timing */
+#define	PA2		0x04	/* PIO"A" timing */
+#define	PA1		0x02	/* PIO"A" timing */
+#define	PA0		0x01	/* PIO"A" timing */
+
+/* B Register */
+
+#define	MB2		0x80	/* DMA"B" timing */
+#define	MB1		0x40	/* DMA"B" timing */
+#define	MB0		0x20	/* DMA"B" timing */
+
+#define	PB4		0x10	/* PIO_FORCE 1:0 */
+
+#define	PB3		0x08	/* PIO"B" timing */	/* PIO flow Control mode */
+#define	PB2		0x04	/* PIO"B" timing */	/* PIO 4 */
+#define	PB1		0x02	/* PIO"B" timing */	/* PIO 3 half */
+#define	PB0		0x01	/* PIO"B" timing */	/* PIO 3 other half */
+
+/* C Register */
+#define	IORDYp_NO_SPEED	0x4F
+#define	SPEED_DIS	0x0F
+
+#define	DMARQp		0x80
+#define	IORDYp		0x40
+#define	DMAR_EN		0x20
+#define	DMAW_EN		0x10
+
+#define	MC3		0x08	/* DMA"C" timing */
+#define	MC2		0x04	/* DMA"C" timing */
+#define	MC1		0x02	/* DMA"C" timing */
+#define	MC0		0x01	/* DMA"C" timing */
+
+#if PDC202XX_DECODE_REGISTER_INFO
+
+#define REG_A		0x01
+#define REG_B		0x02
+#define REG_C		0x04
+#define REG_D		0x08
+
+static void decode_registers (u8 registers, u8 value)
+{
+	u8	bit = 0, bit1 = 0, bit2 = 0;
+
+	switch(registers) {
+		case REG_A:
+			bit2 = 0;
+			printk("A Register ");
+			if (value & 0x80) printk("SYNC_IN ");
+			if (value & 0x40) printk("ERRDY_EN ");
+			if (value & 0x20) printk("IORDY_EN ");
+			if (value & 0x10) printk("PREFETCH_EN ");
+			if (value & 0x08) { printk("PA3 ");bit2 |= 0x08; }
+			if (value & 0x04) { printk("PA2 ");bit2 |= 0x04; }
+			if (value & 0x02) { printk("PA1 ");bit2 |= 0x02; }
+			if (value & 0x01) { printk("PA0 ");bit2 |= 0x01; }
+			printk("PIO(A) = %d ", bit2);
+			break;
+		case REG_B:
+			bit1 = 0;bit2 = 0;
+			printk("B Register ");
+			if (value & 0x80) { printk("MB2 ");bit1 |= 0x80; }
+			if (value & 0x40) { printk("MB1 ");bit1 |= 0x40; }
+			if (value & 0x20) { printk("MB0 ");bit1 |= 0x20; }
+			printk("DMA(B) = %d ", bit1 >> 5);
+			if (value & 0x10) printk("PIO_FORCED/PB4 ");
+			if (value & 0x08) { printk("PB3 ");bit2 |= 0x08; }
+			if (value & 0x04) { printk("PB2 ");bit2 |= 0x04; }
+			if (value & 0x02) { printk("PB1 ");bit2 |= 0x02; }
+			if (value & 0x01) { printk("PB0 ");bit2 |= 0x01; }
+			printk("PIO(B) = %d ", bit2);
+			break;
+		case REG_C:
+			bit2 = 0;
+			printk("C Register ");
+			if (value & 0x80) printk("DMARQp ");
+			if (value & 0x40) printk("IORDYp ");
+			if (value & 0x20) printk("DMAR_EN ");
+			if (value & 0x10) printk("DMAW_EN ");
+
+			if (value & 0x08) { printk("MC3 ");bit2 |= 0x08; }
+			if (value & 0x04) { printk("MC2 ");bit2 |= 0x04; }
+			if (value & 0x02) { printk("MC1 ");bit2 |= 0x02; }
+			if (value & 0x01) { printk("MC0 ");bit2 |= 0x01; }
+			printk("DMA(C) = %d ", bit2);
+			break;
+		case REG_D:
+			printk("D Register ");
+			break;
+		default:
+			return;
+	}
+	printk("\n        %s ", (registers & REG_D) ? "DP" :
+				(registers & REG_C) ? "CP" :
+				(registers & REG_B) ? "BP" :
+				(registers & REG_A) ? "AP" : "ERROR");
+	for (bit=128;bit>0;bit/=2)
+		printk("%s", (value & bit) ? "1" : "0");
+	printk("\n");
+}
+
+#endif /* PDC202XX_DECODE_REGISTER_INFO */
+
+#define set_2regs(a, b)					\
+	do {						\
+		hwif->OUTB((a + adj), indexreg);	\
+		hwif->OUTB(b, datareg);			\
+	} while(0)
+
+#define set_ultra(a, b, c)				\
+	do {						\
+		set_2regs(0x10,(a));			\
+		set_2regs(0x11,(b));			\
+		set_2regs(0x12,(c));			\
+	} while(0)
+
+#define set_ata2(a, b)					\
+	do {						\
+		set_2regs(0x0e,(a));			\
+		set_2regs(0x0f,(b));			\
+	} while(0)
+
+#define set_pio(a, b, c)				\
+	do { 						\
+		set_2regs(0x0c,(a));			\
+		set_2regs(0x0d,(b));			\
+		set_2regs(0x13,(c));			\
+	} while(0)
+
+#define DISPLAY_PDC202XX_TIMINGS
+
+#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 pdc202xx_proc;
+
+static int pdc202xx_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t pdc202xx_procs[] __initdata = {
+	{
+		.name		= "pdc202xx",
+		.set		= 1,
+		.get_info	= pdc202xx_get_info,
+		.parent		= NULL,
+	},
+};
+#endif /* DISPLAY_PDC202XX_TIMINGS && CONFIG_PROC_FS */
+
+
+static void init_setup_pdc202ata4(struct pci_dev *dev, ide_pci_device_t *d);
+static void init_setup_pdc20265(struct pci_dev *, ide_pci_device_t *);
+static void init_setup_pdc202xx(struct pci_dev *, ide_pci_device_t *);
+static unsigned int init_chipset_pdc202xx(struct pci_dev *, const char *);
+static void init_hwif_pdc202xx(ide_hwif_t *);
+static void init_dma_pdc202xx(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20246,
+		.name		= "PDC20246",
+		.init_setup	= init_setup_pdc202ata4,
+		.init_chipset	= init_chipset_pdc202xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202xx,
+		.init_dma	= init_dma_pdc202xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+#ifdef CONFIG_PDC202XX_FORCE
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+#else /* !CONFIG_PDC202XX_FORCE */
+		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+#endif
+		.bootable	= OFF_BOARD,
+		.extra		= 16,
+	},{	/* 1 */
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20262,
+		.name		= "PDC20262",
+		.init_setup	= init_setup_pdc202ata4,
+		.init_chipset	= init_chipset_pdc202xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202xx,
+		.init_dma	= init_dma_pdc202xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+#ifdef CONFIG_PDC202XX_FORCE
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+#else /* !CONFIG_PDC202XX_FORCE */
+		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+#endif
+		.bootable	= OFF_BOARD,
+		.extra		= 48,
+	},{	/* 2 */
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20263,
+		.name		= "PDC20263",
+		.init_setup	= init_setup_pdc202ata4,
+		.init_chipset	= init_chipset_pdc202xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202xx,
+		.init_dma	= init_dma_pdc202xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+#ifdef CONFIG_PDC202XX_FORCE
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+#else /* !CONFIG_PDC202XX_FORCE */
+		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+#endif
+		.bootable	= OFF_BOARD,
+		.extra		= 48,
+	},{	/* 3 */
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20265,
+		.name		= "PDC20265",
+		.init_setup	= init_setup_pdc20265,
+		.init_chipset	= init_chipset_pdc202xx,
+		.init_hwif	= init_hwif_pdc202xx,
+		.init_dma	= init_dma_pdc202xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+#ifdef CONFIG_PDC202XX_FORCE
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+#else /* !CONFIG_PDC202XX_FORCE */
+		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+#endif
+		.bootable	= OFF_BOARD,
+		.extra		= 48,
+	},{	/* 4 */
+		.vendor		= PCI_VENDOR_ID_PROMISE,
+		.device		= PCI_DEVICE_ID_PROMISE_20267,
+		.name		= "PDC20267",
+		.init_setup	= init_setup_pdc202xx,
+		.init_chipset	= init_chipset_pdc202xx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdc202xx,
+		.init_dma	= init_dma_pdc202xx,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+#ifdef CONFIG_PDC202XX_FORCE
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+#else /* !CONFIG_PDC202XX_FORCE */
+		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+#endif
+		.bootable	= OFF_BOARD,
+		.extra		= 48,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* PDC202XX_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/pdcadma.c linux-2.4.21-pre6/drivers/ide/pci/pdcadma.c
--- linux-2.4.20/drivers/ide/pci/pdcadma.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/pdcadma.c	2003-03-26 23:49:37.000000000 +0000
@@ -0,0 +1,165 @@
+/*
+ * linux/drivers/ide/pci/pdcadma.c		Version 0.05	Sept 10, 2002
+ *
+ * Copyright (C) 1999-2000		Andre Hedrick <andre@linux-ide.org>
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+#include "pdcadma.h"
+
+#if defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 pdcadma_proc = 0;
+#define PDC_MAX_DEVS		5
+static struct pci_dev *pdc_devs[PDC_MAX_DEVS];
+static int n_pdc_devs;
+
+static int pdcadma_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	int i;
+
+	for (i = 0; i < n_pdc_devs; i++) {
+		struct pci_dev *dev	= pdc_devs[i];
+		unsigned long bibma = pci_resource_start(dev, 4);
+
+		p += sprintf(p, "\n                                "
+			"PDC ADMA %04X Chipset.\n", dev->device);
+		p += sprintf(p, "UDMA\n");
+		p += sprintf(p, "PIO\n");
+
+	}
+	return p-buffer;	/* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+/*
+ * pdcadma_dma functions() initiates/aborts (U)DMA read/write
+ * operations on a drive.
+ */
+#if 0
+        int (*ide_dma_read)(ide_drive_t *drive);
+        int (*ide_dma_write)(ide_drive_t *drive);
+        int (*ide_dma_begin)(ide_drive_t *drive);
+        int (*ide_dma_end)(ide_drive_t *drive);
+        int (*ide_dma_check)(ide_drive_t *drive);
+        int (*ide_dma_on)(ide_drive_t *drive);
+        int (*ide_dma_off)(ide_drive_t *drive);
+        int (*ide_dma_off_quietly)(ide_drive_t *drive);
+        int (*ide_dma_test_irq)(ide_drive_t *drive);
+        int (*ide_dma_host_on)(ide_drive_t *drive);
+        int (*ide_dma_host_off)(ide_drive_t *drive);
+        int (*ide_dma_bad_drive)(ide_drive_t *drive);
+        int (*ide_dma_good_drive)(ide_drive_t *drive);
+        int (*ide_dma_count)(ide_drive_t *drive);
+        int (*ide_dma_verbose)(ide_drive_t *drive);
+        int (*ide_dma_retune)(ide_drive_t *drive);
+        int (*ide_dma_lostirq)(ide_drive_t *drive);
+        int (*ide_dma_timeout)(ide_drive_t *drive);
+
+#endif
+
+static unsigned int __init init_chipset_pdcadma (struct pci_dev *dev, const char *name)
+{
+#if defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS)
+	pdc_devs[n_pdc_devs++] = dev;
+
+	if (!pdcadma_proc) {
+		pdcadma_proc = 1;
+		ide_pci_register_host_proc(&pdcadma_procs[0]);
+	}
+#endif /* DISPLAY_PDCADMA_TIMINGS && CONFIG_PROC_FS */
+	return 0;
+}
+
+static void __init init_hwif_pdcadma (ide_hwif_t *hwif)
+{
+	hwif->autodma = 0;
+	hwif->dma_base = 0;
+
+//	hwif->tuneproc = &pdcadma_tune_drive;
+//	hwif->speedproc = &pdcadma_tune_chipset;
+
+//	if (hwif->dma_base) {
+//		hwif->autodma = 1;
+//	}
+
+	hwif->udma_four = 1;
+
+//	hwif->atapi_dma = 1;
+//	hwif->ultra_mask = 0x7f;
+//	hwif->mwdma_mask = 0x07;
+//	hwif->swdma_mask = 0x07;
+
+}
+
+static void __init init_dma_pdcadma (ide_hwif_t *hwif, unsigned long dmabase)
+{
+#if 0
+	ide_setup_dma(hwif, dmabase, 8);
+#endif
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static int __devinit pdcadma_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &pdcadma_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 1;
+}
+
+static struct pci_device_id pdcadma_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_PDC, PCI_DEVICE_ID_PDC_1841, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "PDCADMA-IDE",
+	.id_table	= pdcadma_pci_tbl,
+	.probe		= pdcadma_init_one,
+};
+
+static int pdcadma_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void pdcadma_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(pdcadma_ide_init);
+module_exit(pdcadma_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for PDCADMA IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/pdcadma.h linux-2.4.21-pre6/drivers/ide/pci/pdcadma.h
--- linux-2.4.20/drivers/ide/pci/pdcadma.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/pdcadma.h	2003-03-26 23:49:30.000000000 +0000
@@ -0,0 +1,56 @@
+#ifndef PDC_ADMA_H
+#define PDC_ADMA_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#undef DISPLAY_PDCADMA_TIMINGS
+
+#if defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 pdcadma_proc;
+
+static int pdcadma_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t pdcadma_procs[] __initdata = {
+	{
+		.name		= "pdcadma",
+		.set		= 1,
+		.get_info	= pdcadma_get_info,
+		.parent		= NULL,
+	},
+};
+#endif  /* defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static void init_setup_pdcadma(struct pci_dev *, ide_pci_device_t *);
+static unsigned int init_chipset_pdcadma(struct pci_dev *, const char *);
+static void init_hwif_pdcadma(ide_hwif_t *);
+static void init_dma_pdcadma(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t pdcadma_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_PDC,
+		.device		= PCI_DEVICE_ID_PDC_1841,
+		.name		= "PDCADMA",
+		.init_setup	= init_setup_pdcadma,
+		.init_chipset	= init_chipset_pdcadma,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_pdcadma,
+		.init_dma	= init_dma_pdcadma,
+		.channels	= 2,
+		.autodma	= NODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= OFF_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* PDC_ADMA_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/piix.c linux-2.4.21-pre6/drivers/ide/pci/piix.c
--- linux-2.4.20/drivers/ide/pci/piix.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/piix.c	2003-03-26 23:49:30.000000000 +0000
@@ -0,0 +1,825 @@
+/*
+ *  linux/drivers/ide/pci/piix.c	Version 0.42	January 11, 2003
+ *
+ *  Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
+ *  Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
+ *  Copyright (C) 2003 Red Hat Inc <alan@redhat.com>
+ *
+ *  May be copied or modified under the terms of the GNU General Public License
+ *
+ *  PIO mode setting function for Intel chipsets.  
+ *  For use instead of BIOS settings.
+ *
+ * 40-41
+ * 42-43
+ * 
+ *                 41
+ *                 43
+ *
+ * | PIO 0       | c0 | 80 | 0 | 	piix_tune_drive(drive, 0);
+ * | PIO 2 | SW2 | d0 | 90 | 4 | 	piix_tune_drive(drive, 2);
+ * | PIO 3 | MW1 | e1 | a1 | 9 | 	piix_tune_drive(drive, 3);
+ * | PIO 4 | MW2 | e3 | a3 | b | 	piix_tune_drive(drive, 4);
+ * 
+ * sitre = word40 & 0x4000; primary
+ * sitre = word42 & 0x4000; secondary
+ *
+ * 44 8421|8421    hdd|hdb
+ * 
+ * 48 8421         hdd|hdc|hdb|hda udma enabled
+ *
+ *    0001         hda
+ *    0010         hdb
+ *    0100         hdc
+ *    1000         hdd
+ *
+ * 4a 84|21        hdb|hda
+ * 4b 84|21        hdd|hdc
+ *
+ *    ata-33/82371AB
+ *    ata-33/82371EB
+ *    ata-33/82801AB            ata-66/82801AA
+ *    00|00 udma 0              00|00 reserved
+ *    01|01 udma 1              01|01 udma 3
+ *    10|10 udma 2              10|10 udma 4
+ *    11|11 reserved            11|11 reserved
+ *
+ * 54 8421|8421    ata66 drive|ata66 enable
+ *
+ * pci_read_config_word(HWIF(drive)->pci_dev, 0x40, &reg40);
+ * pci_read_config_word(HWIF(drive)->pci_dev, 0x42, &reg42);
+ * pci_read_config_word(HWIF(drive)->pci_dev, 0x44, &reg44);
+ * pci_read_config_word(HWIF(drive)->pci_dev, 0x48, &reg48);
+ * pci_read_config_word(HWIF(drive)->pci_dev, 0x4a, &reg4a);
+ * pci_read_config_word(HWIF(drive)->pci_dev, 0x54, &reg54);
+ *
+ * Documentation
+ *	Publically available from Intel web site. Errata documentation
+ * is also publically available. As an aide to anyone hacking on this
+ * driver the list of errata that are relevant is below.going back to
+ * PIIX4. Older device documentation is now a bit tricky to find.
+ *
+ * Errata of note:
+ *
+ * Unfixable
+ *	PIIX4    errata #9	- Only on ultra obscure hw
+ *	ICH3	 errata #13     - Not observed to affect real hw
+ *				  by Intel
+ *
+ * Things we must deal with
+ *	PIIX4	errata #10	- BM IDE hang with non UDMA
+ *				  (must stop/start dma to recover)
+ *	440MX   errata #15	- As PIIX4 errata #10
+ *	PIIX4	errata #15	- Must not read control registers
+ * 				  during a PIO transfer
+ *	440MX   errata #13	- As PIIX4 errata #15
+ *	ICH2	errata #21	- DMA mode 0 doesn't work right
+ *	ICH0/1  errata #55	- As ICH2 errata #21
+ *	ICH2	spec c #9	- Extra operations needed to handle
+ *				  drive hotswap [NOT YET SUPPORTED]
+ *	ICH2    spec c #20	- IDE PRD must not cross a 64K boundary
+ *				  and must be dword aligned
+ *	ICH2    spec c #24	- UDMA mode 4,5 t85/86 should be 6ns not 3.3
+ *
+ * Should have been BIOS fixed:
+ *	450NX:	errata #19	- DMA hangs on old 450NX
+ *	450NX:  errata #20	- DMA hangs on old 450NX
+ *	450NX:  errata #25	- Corruption with DMA on old 450NX
+ *	ICH3    errata #15      - IDE deadlock under high load
+ *				  (BIOS must set dev 31 fn 0 bit 23)
+ *	ICH3	errata #18	- Don't use native mode
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "ide_modes.h"
+#include "piix.h"
+
+#if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 piix_proc = 0;
+#define PIIX_MAX_DEVS		5
+static struct pci_dev *piix_devs[PIIX_MAX_DEVS];
+static int n_piix_devs;
+static int no_piix_dma = 0;
+
+/**
+ *	piix_get_info		-	fill in /proc for PIIX ide
+ *	@buffer: buffer to fill
+ *	@addr: address of user start in buffer
+ *	@offset: offset into 'file'
+ *	@count: buffer count
+ *
+ *	Walks the PIIX devices and outputs summary data on the tuning and
+ *	anything else that will help with debugging
+ */
+ 
+static int piix_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	int i;
+
+	for (i = 0; i < n_piix_devs; i++) {
+		struct pci_dev *dev	= piix_devs[i];
+		unsigned long bibma = pci_resource_start(dev, 4);
+	        u16 reg40 = 0, psitre = 0, reg42 = 0, ssitre = 0;
+		u8  c0 = 0, c1 = 0, reg54 = 0, reg55 = 0;
+		u8  reg44 = 0, reg48 = 0, reg4a = 0, reg4b = 0;
+
+		p += sprintf(p, "\nController: %d\n", i);
+		p += sprintf(p, "\n                                Intel ");
+		switch(dev->device) {
+			case PCI_DEVICE_ID_INTEL_82801BA_8:
+			case PCI_DEVICE_ID_INTEL_82801BA_9:
+			case PCI_DEVICE_ID_INTEL_82801CA_10:
+			case PCI_DEVICE_ID_INTEL_82801CA_11:
+			case PCI_DEVICE_ID_INTEL_82801DB_11:
+			case PCI_DEVICE_ID_INTEL_82801E_11:
+				p += sprintf(p, "PIIX4 Ultra 100 ");
+				break;
+			case PCI_DEVICE_ID_INTEL_82372FB_1:
+			case PCI_DEVICE_ID_INTEL_82801AA_1:
+				p += sprintf(p, "PIIX4 Ultra 66 ");
+				break;
+			case PCI_DEVICE_ID_INTEL_82451NX:
+			case PCI_DEVICE_ID_INTEL_82801AB_1:
+			case PCI_DEVICE_ID_INTEL_82443MX_1:
+			case PCI_DEVICE_ID_INTEL_82371AB:
+				p += sprintf(p, "PIIX4 Ultra 33 ");
+				break;
+			case PCI_DEVICE_ID_INTEL_82371SB_1:
+				p += sprintf(p, "PIIX3 ");
+				break;
+			case PCI_DEVICE_ID_INTEL_82371MX:
+				p += sprintf(p, "MPIIX ");
+				break;
+			case PCI_DEVICE_ID_INTEL_82371FB_1:
+			case PCI_DEVICE_ID_INTEL_82371FB_0:
+			default:
+				p += sprintf(p, "PIIX ");
+				break;
+		}
+		p += sprintf(p, "Chipset.\n");
+
+		if (dev->device == PCI_DEVICE_ID_INTEL_82371MX)
+			continue;
+
+		pci_read_config_word(dev, 0x40, &reg40);
+		pci_read_config_word(dev, 0x42, &reg42);
+		pci_read_config_byte(dev, 0x44, &reg44);
+		pci_read_config_byte(dev, 0x48, &reg48);
+		pci_read_config_byte(dev, 0x4a, &reg4a);
+		pci_read_config_byte(dev, 0x4b, &reg4b);
+		pci_read_config_byte(dev, 0x54, &reg54);
+		pci_read_config_byte(dev, 0x55, &reg55);
+
+		psitre = (reg40 & 0x4000) ? 1 : 0;
+		ssitre = (reg42 & 0x4000) ? 1 : 0;
+
+		/*
+		 * at that point bibma+0x2 et bibma+0xa are byte registers
+		 * to investigate:
+		 */
+		c0 = inb(bibma + 0x02);
+		c1 = inb(bibma + 0x0a);
+
+		p += sprintf(p, "--------------- Primary Channel "
+				"---------------- Secondary Channel "
+				"-------------\n");
+		p += sprintf(p, "                %sabled "
+				"                        %sabled\n",
+				(c0&0x80) ? "dis" : " en",
+				(c1&0x80) ? "dis" : " en");
+		p += sprintf(p, "--------------- drive0 --------- drive1 "
+				"-------- drive0 ---------- drive1 ------\n");
+		p += sprintf(p, "DMA enabled:    %s              %s "
+				"            %s               %s\n",
+				(c0&0x20) ? "yes" : "no ",
+				(c0&0x40) ? "yes" : "no ",
+				(c1&0x20) ? "yes" : "no ",
+				(c1&0x40) ? "yes" : "no " );
+		p += sprintf(p, "UDMA enabled:   %s              %s "
+				"            %s               %s\n",
+				(reg48&0x01) ? "yes" : "no ",
+				(reg48&0x02) ? "yes" : "no ",
+				(reg48&0x04) ? "yes" : "no ",
+				(reg48&0x08) ? "yes" : "no " );
+		p += sprintf(p, "UDMA enabled:   %s                %s "
+				"              %s                 %s\n",
+				((reg54&0x11) &&
+				 (reg55&0x10) && (reg4a&0x01)) ? "5" :
+				((reg54&0x11) && (reg4a&0x02)) ? "4" :
+				((reg54&0x11) && (reg4a&0x01)) ? "3" :
+				(reg4a&0x02) ? "2" :
+				(reg4a&0x01) ? "1" :
+				(reg4a&0x00) ? "0" : "X",
+				((reg54&0x22) &&
+				 (reg55&0x20) && (reg4a&0x10)) ? "5" :
+				((reg54&0x22) && (reg4a&0x20)) ? "4" :
+				((reg54&0x22) && (reg4a&0x10)) ? "3" :
+				(reg4a&0x20) ? "2" :
+				(reg4a&0x10) ? "1" :
+				(reg4a&0x00) ? "0" : "X",
+				((reg54&0x44) &&
+				 (reg55&0x40) && (reg4b&0x03)) ? "5" :
+				((reg54&0x44) && (reg4b&0x02)) ? "4" :
+				((reg54&0x44) && (reg4b&0x01)) ? "3" :
+				(reg4b&0x02) ? "2" :
+				(reg4b&0x01) ? "1" :
+				(reg4b&0x00) ? "0" : "X",
+				((reg54&0x88) &&
+				 (reg55&0x80) && (reg4b&0x30)) ? "5" :
+				((reg54&0x88) && (reg4b&0x20)) ? "4" :
+				((reg54&0x88) && (reg4b&0x10)) ? "3" :
+				(reg4b&0x20) ? "2" :
+				(reg4b&0x10) ? "1" :
+				(reg4b&0x00) ? "0" : "X");
+
+		p += sprintf(p, "UDMA\n");
+		p += sprintf(p, "DMA\n");
+		p += sprintf(p, "PIO\n");
+
+		/*
+		 * FIXME.... Add configuration junk data....blah blah......
+		 */
+	}
+	return p-buffer;	 /* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+/**
+ *	piix_ratemask		-	compute rate mask for PIIX IDE
+ *	@drive: IDE drive to compute for
+ *
+ *	Returns the available modes for the PIIX IDE controller.
+ */
+ 
+static u8 piix_ratemask (ide_drive_t *drive)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	u8 mode;
+
+	switch(dev->device) {
+		/* UDMA 100 capable */
+		case PCI_DEVICE_ID_INTEL_82801BA_8:
+		case PCI_DEVICE_ID_INTEL_82801BA_9:
+		case PCI_DEVICE_ID_INTEL_82801CA_10:
+		case PCI_DEVICE_ID_INTEL_82801CA_11:
+		case PCI_DEVICE_ID_INTEL_82801E_11:
+		case PCI_DEVICE_ID_INTEL_82801DB_11:
+			mode = 3;
+			break;
+		/* UDMA 66 capable */
+		case PCI_DEVICE_ID_INTEL_82801AA_1:
+		case PCI_DEVICE_ID_INTEL_82372FB_1:
+			mode = 2;
+			break;
+		/* UDMA 33 capable */
+		case PCI_DEVICE_ID_INTEL_82371AB:
+		case PCI_DEVICE_ID_INTEL_82443MX_1:
+		case PCI_DEVICE_ID_INTEL_82451NX:
+		case PCI_DEVICE_ID_INTEL_82801AB_1:
+			return 1;
+		/* Non UDMA capable (MWDMA2) */
+		case PCI_DEVICE_ID_INTEL_82371SB_1:
+		case PCI_DEVICE_ID_INTEL_82371FB_1:
+		case PCI_DEVICE_ID_INTEL_82371FB_0:
+		case PCI_DEVICE_ID_INTEL_82371MX:
+		default:
+			return 0;
+	}
+	
+	/*
+	 *	If we are UDMA66 capable fall back to UDMA33 
+	 *	if the drive cannot see an 80pin cable.
+	 */
+	if (!eighty_ninty_three(drive))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+/**
+ *	piix_dma_2_pio		-	return the PIO mode matching DMA
+ *	@xfer_rate: transfer speed
+ *
+ *	Returns the nearest equivalent PIO timing for the PIO or DMA
+ *	mode requested by the controller.
+ */
+ 
+static u8 piix_dma_2_pio (u8 xfer_rate) {
+	switch(xfer_rate) {
+		case XFER_UDMA_5:
+		case XFER_UDMA_4:
+		case XFER_UDMA_3:
+		case XFER_UDMA_2:
+		case XFER_UDMA_1:
+		case XFER_UDMA_0:
+		case XFER_MW_DMA_2:
+		case XFER_PIO_4:
+			return 4;
+		case XFER_MW_DMA_1:
+		case XFER_PIO_3:
+			return 3;
+		case XFER_SW_DMA_2:
+		case XFER_PIO_2:
+			return 2;
+		case XFER_MW_DMA_0:
+		case XFER_SW_DMA_1:
+		case XFER_SW_DMA_0:
+		case XFER_PIO_1:
+		case XFER_PIO_0:
+		case XFER_PIO_SLOW:
+		default:
+			return 0;
+	}
+}
+
+/**
+ *	piix_tune_drive		-	tune a drive attached to a PIIX
+ *	@drive: drive to tune
+ *	@pio: desired PIO mode
+ *
+ *	Set the interface PIO mode based upon  the settings done by AMI BIOS
+ *	(might be useful if drive is not registered in CMOS for any reason).
+ */
+static void piix_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	int is_slave		= (&hwif->drives[1] == drive);
+	int master_port		= hwif->channel ? 0x42 : 0x40;
+	int slave_port		= 0x44;
+	unsigned long flags;
+	u16 master_data;
+	u8 slave_data;
+				 /* ISP  RTC */
+	u8 timings[][2]	= { { 0, 0 },
+			    { 0, 0 },
+			    { 1, 0 },
+			    { 2, 1 },
+			    { 2, 3 }, };
+
+	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+	spin_lock_irqsave(&ide_lock, flags);
+	pci_read_config_word(dev, master_port, &master_data);
+	if (is_slave) {
+		master_data = master_data | 0x4000;
+		if (pio > 1)
+			/* enable PPE, IE and TIME */
+			master_data = master_data | 0x0070;
+		pci_read_config_byte(dev, slave_port, &slave_data);
+		slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0);
+		slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0));
+	} else {
+		master_data = master_data & 0xccf8;
+		if (pio > 1)
+			/* enable PPE, IE and TIME */
+			master_data = master_data | 0x0007;
+		master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8);
+	}
+	pci_write_config_word(dev, master_port, master_data);
+	if (is_slave)
+		pci_write_config_byte(dev, slave_port, slave_data);
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+/**
+ *	piix_tune_chipset	-	tune a PIIX interface
+ *	@drive: IDE drive to tune
+ *	@xferspeed: speed to configure
+ *
+ *	Set a PIIX interface channel to the desired speeds. This involves
+ *	requires the right timing data into the PIIX configuration space
+ *	then setting the drive parameters appropriately
+ */
+ 
+static int piix_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 maslave		= hwif->channel ? 0x42 : 0x40;
+	u8 speed		= ide_rate_filter(piix_ratemask(drive), xferspeed);
+	int a_speed		= 3 << (drive->dn * 4);
+	int u_flag		= 1 << drive->dn;
+	int v_flag		= 0x01 << drive->dn;
+	int w_flag		= 0x10 << drive->dn;
+	int u_speed		= 0;
+	int			sitre;
+	u16			reg4042, reg44, reg48, reg4a, reg54;
+	u8			reg55;
+
+	pci_read_config_word(dev, maslave, &reg4042);
+	sitre = (reg4042 & 0x4000) ? 1 : 0;
+	pci_read_config_word(dev, 0x44, &reg44);
+	pci_read_config_word(dev, 0x48, &reg48);
+	pci_read_config_word(dev, 0x4a, &reg4a);
+	pci_read_config_word(dev, 0x54, &reg54);
+	pci_read_config_byte(dev, 0x55, &reg55);
+
+	switch(speed) {
+		case XFER_UDMA_4:
+		case XFER_UDMA_2:	u_speed = 2 << (drive->dn * 4); break;
+		case XFER_UDMA_5:
+		case XFER_UDMA_3:
+		case XFER_UDMA_1:	u_speed = 1 << (drive->dn * 4); break;
+		case XFER_UDMA_0:	u_speed = 0 << (drive->dn * 4); break;
+		case XFER_MW_DMA_2:
+		case XFER_MW_DMA_1:
+		case XFER_SW_DMA_2:	break;
+		case XFER_PIO_4:
+		case XFER_PIO_3:
+		case XFER_PIO_2:
+		case XFER_PIO_0:	break;
+		default:		return -1;
+	}
+
+	if (speed >= XFER_UDMA_0) {
+		if (!(reg48 & u_flag))
+			pci_write_config_word(dev, 0x48, reg48|u_flag);
+		if (speed == XFER_UDMA_5) {
+			pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag);
+		} else {
+			pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
+		}
+		if (!(reg4a & u_speed)) {
+			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+			pci_write_config_word(dev, 0x4a, reg4a|u_speed);
+		}
+		if (speed > XFER_UDMA_2) {
+			if (!(reg54 & v_flag)) {
+				pci_write_config_word(dev, 0x54, reg54|v_flag);
+			}
+		} else {
+			pci_write_config_word(dev, 0x54, reg54 & ~v_flag);
+		}
+	} else {
+		if (reg48 & u_flag)
+			pci_write_config_word(dev, 0x48, reg48 & ~u_flag);
+		if (reg4a & a_speed)
+			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+		if (reg54 & v_flag)
+			pci_write_config_word(dev, 0x54, reg54 & ~v_flag);
+		if (reg55 & w_flag)
+			pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
+	}
+
+	piix_tune_drive(drive, piix_dma_2_pio(speed));
+	return (ide_config_drive_speed(drive, speed));
+}
+
+/**
+ *	piix_faulty_dma0		-	check for DMA0 errata
+ *	@hwif: IDE interface to check
+ *
+ *	If an ICH/ICH0/ICH2 interface is is operating in multi-word
+ *	DMA mode with 600nS cycle time the IDE PIO prefetch buffer will
+ *	inadvertently provide an extra piece of secondary data to the primary
+ *	device resulting in data corruption.
+ *
+ *	With such a device this test function returns true. This allows
+ *	our tuning code to follow Intel recommendations and use PIO on
+ *	such devices.
+ */
+ 
+static int piix_faulty_dma0(ide_hwif_t *hwif)
+{
+	switch(hwif->pci_dev->device)
+	{
+		case PCI_DEVICE_ID_INTEL_82801AA_1:	/* ICH */
+		case PCI_DEVICE_ID_INTEL_82801AB_1:	/* ICH0 */
+		case PCI_DEVICE_ID_INTEL_82801BA_8:	/* ICH2 */
+		case PCI_DEVICE_ID_INTEL_82801BA_9:	/* ICH2 */
+			return 1;
+	}
+	return 0;
+}
+
+/**
+ *	piix_config_drive_for_dma	-	configure drive for DMA
+ *	@drive: IDE drive to configure
+ *
+ *	Set up a PIIX interface channel for the best available speed.
+ *	We prefer UDMA if it is available and then MWDMA. If DMA is 
+ *	not available we switch to PIO and return 0. 
+ */
+ 
+static int piix_config_drive_for_dma (ide_drive_t *drive)
+{
+	u8 speed = ide_dma_speed(drive, piix_ratemask(drive));
+	
+	/* Some ICH devices cannot support DMA mode 0 */
+	if(speed == XFER_MW_DMA_0 && piix_faulty_dma0(HWIF(drive)))
+		speed = 0;
+
+	/* If no DMA speed was available or the chipset has DMA bugs
+	   then disable DMA and use PIO */
+	   
+	if (!speed || no_piix_dma) {
+		u8 tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL);
+		speed = piix_dma_2_pio(XFER_PIO_0 + tspeed);
+	}
+
+	(void) piix_tune_chipset(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+/**
+ *	piix_config_drive_xfer_rate	-	set up an IDE device
+ *	@drive: IDE drive to configure
+ *
+ *	Set up the PIIX interface for the best available speed on this
+ *	interface, preferring DMA to PIO.
+ */
+ 
+static int piix_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	drive->init_speed = 0;
+
+	if (id && (id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				if ((id->field_valid & 2) &&
+				    (!piix_config_drive_for_dma(drive)))
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!piix_config_drive_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!piix_config_drive_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		hwif->tuneproc(drive, 255);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+/**
+ *	init_chipset_piix	-	set up the PIIX chipset
+ *	@dev: PCI device to set up
+ *	@name: Name of the device
+ *
+ *	Initialize the PCI device as required. For the PIIX this turns
+ *	out to be nice and simple
+ */
+ 
+static unsigned int __devinit init_chipset_piix (struct pci_dev *dev, const char *name)
+{
+        switch(dev->device) {
+		case PCI_DEVICE_ID_INTEL_82801AA_1:
+		case PCI_DEVICE_ID_INTEL_82801AB_1:
+		case PCI_DEVICE_ID_INTEL_82801BA_8:
+		case PCI_DEVICE_ID_INTEL_82801BA_9:
+		case PCI_DEVICE_ID_INTEL_82801CA_10:
+		case PCI_DEVICE_ID_INTEL_82801CA_11:
+		case PCI_DEVICE_ID_INTEL_82801DB_11:
+		case PCI_DEVICE_ID_INTEL_82801E_11:
+		{
+			unsigned int extra = 0;
+			pci_read_config_dword(dev, 0x54, &extra);
+			pci_write_config_dword(dev, 0x54, extra|0x400);
+		}
+		default:
+			break;
+	}
+
+#if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS)
+	piix_devs[n_piix_devs++] = dev;
+
+	if (!piix_proc) {
+		piix_proc = 1;
+		ide_pci_register_host_proc(&piix_procs[0]);
+	}
+#endif /* DISPLAY_PIIX_TIMINGS && CONFIG_PROC_FS */
+	return 0;
+}
+
+/**
+ *	init_hwif_piix		-	fill in the hwif for the PIIX
+ *	@hwif: IDE interface
+ *
+ *	Set up the ide_hwif_t for the PIIX interface according to the
+ *	capabilities of the hardware.
+ */
+ 
+static void __init init_hwif_piix (ide_hwif_t *hwif)
+{
+	u8 reg54h = 0, reg55h = 0, ata66 = 0;
+	u8 mask = hwif->channel ? 0xc0 : 0x30;
+
+#ifndef CONFIG_IA64
+	if (!hwif->irq)
+		hwif->irq = hwif->channel ? 15 : 14;
+#endif /* CONFIG_IA64 */
+
+	if (hwif->pci_dev->device == PCI_DEVICE_ID_INTEL_82371MX) {
+		/* This is a painful system best to let it self tune for now */
+		return;
+	}
+
+	hwif->autodma = 0;
+	hwif->tuneproc = &piix_tune_drive;
+	hwif->speedproc = &piix_tune_chipset;
+	hwif->drives[0].autotune = 1;
+	hwif->drives[1].autotune = 1;
+
+	if (!hwif->dma_base)
+		return;
+
+	hwif->atapi_dma = 1;
+	hwif->ultra_mask = 0x3f;
+	hwif->mwdma_mask = 0x06;
+	hwif->swdma_mask = 0x04;
+
+	switch(hwif->pci_dev->device) {
+		case PCI_DEVICE_ID_INTEL_82371MX:
+			hwif->mwdma_mask = 0x80;
+			hwif->swdma_mask = 0x80;
+		case PCI_DEVICE_ID_INTEL_82371FB_0:
+		case PCI_DEVICE_ID_INTEL_82371FB_1:
+		case PCI_DEVICE_ID_INTEL_82371SB_1:
+			hwif->ultra_mask = 0x80;
+			break;
+		case PCI_DEVICE_ID_INTEL_82371AB:
+		case PCI_DEVICE_ID_INTEL_82443MX_1:
+		case PCI_DEVICE_ID_INTEL_82451NX:
+		case PCI_DEVICE_ID_INTEL_82801AB_1:
+			hwif->ultra_mask = 0x07;
+			break;
+		default:
+			pci_read_config_byte(hwif->pci_dev, 0x54, &reg54h);
+			pci_read_config_byte(hwif->pci_dev, 0x55, &reg55h);
+			ata66 = (reg54h & mask) ? 1 : 0;
+			break;
+	}
+
+	if (!(hwif->udma_four))
+		hwif->udma_four = ata66;
+	hwif->ide_dma_check = &piix_config_drive_xfer_rate;
+	if (!noautodma)
+		hwif->autodma = 1;
+
+	hwif->drives[1].autodma = hwif->autodma;
+	hwif->drives[0].autodma = hwif->autodma;
+}
+
+/**
+ *	init_dma_piix		-	set up the PIIX DMA
+ *	@hwif: IDE interface
+ *	@dmabase: DMA PCI base
+ *
+ *	Set up the DMA on the PIIX controller, providing a DMA base is
+ *	available. The PIIX follows the normal specs so we do nothing
+ *	magical here.
+ */
+
+static void __init init_dma_piix (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+/**
+ *	init_setup_piix		-	callback for IDE initialize
+ *	@dev: PIIX PCI device
+ *	@d: IDE pci info
+ *
+ *	Enable the xp fixup for the PIIX controller and then perform
+ *	a standard ide PCI setup
+ */
+ 
+static void __init init_setup_piix (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+/**
+ *	piix_init_one	-	called when a PIIX is found
+ *	@dev: the piix device
+ *	@id: the matching pci id
+ *
+ *	Called when the PCI registration layer (or the IDE initialization)
+ *	finds a device matching our IDE device tables.
+ */
+ 
+static int __devinit piix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &piix_pci_info[id->driver_data];
+
+	if (dev->device != d->device)
+		BUG();
+	d->init_setup(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/**
+ *	piix_check_450nx	-	Check for problem 450NX setup
+ *	
+ *	Check for the present of 450NX errata #19 and errata #25. If
+ *	they are found, disable use of DMA IDE
+ */
+ 
+static void __init piix_check_450nx(void)
+{
+	struct pci_dev *pdev = NULL;
+	u16 cfg;
+	u8 rev;
+	while((pdev=pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, pdev))!=NULL)
+	{
+		/* Look for 450NX PXB. Check for problem configurations
+		   A PCI quirk checks bit 6 already */
+		pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
+		pci_read_config_word(pdev, 0x41, &cfg);
+		/* Only on the original revision: IDE DMA can hang */
+		if(rev == 0x00)
+			no_piix_dma = 1;
+		/* On all revisions PXB bus lock must be disabled for IDE */
+		else if(cfg & (1<<14))
+			no_piix_dma = 2;
+	}
+	if(no_piix_dma)
+		printk(KERN_WARNING "piix: 450NX errata present, disabling IDE DMA.\n");
+	if(no_piix_dma == 2)
+		printk(KERN_WARNING "piix: A BIOS update may resolve this.\n");
+}		
+
+static struct pci_device_id piix_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371MX,   PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB,   PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82372FB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX,   PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_10,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_11,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_11,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_11, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "PIIX IDE",
+	.id_table	= piix_pci_tbl,
+	.probe		= piix_init_one,
+};
+
+static int piix_ide_init(void)
+{
+	piix_check_450nx();
+	return ide_pci_register_driver(&driver);
+}
+
+static void piix_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(piix_ide_init);
+module_exit(piix_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick, Andrzej Krzysztofowicz");
+MODULE_DESCRIPTION("PCI driver module for Intel PIIX IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/piix.h linux-2.4.21-pre6/drivers/ide/pci/piix.h
--- linux-2.4.20/drivers/ide/pci/piix.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/piix.h	2003-03-26 23:49:55.000000000 +0000
@@ -0,0 +1,275 @@
+#ifndef PIIX_H
+#define PIIX_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define PIIX_DEBUG_DRIVE_INFO		0
+
+#define DISPLAY_PIIX_TIMINGS
+
+#if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 piix_proc;
+
+static int piix_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t piix_procs[] __devinitdata = {
+	{
+		.name		= "piix",
+		.set		= 1,
+		.get_info	= piix_get_info,
+		.parent		= NULL,
+	},
+};
+#endif  /* defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static void init_setup_piix(struct pci_dev *, ide_pci_device_t *);
+static unsigned int __devinit init_chipset_piix(struct pci_dev *, const char *);
+static void init_hwif_piix(ide_hwif_t *);
+static void init_dma_piix(ide_hwif_t *, unsigned long);
+
+
+/*
+ *	Table of the various PIIX capability blocks
+ *
+ */
+ 
+static ide_pci_device_t piix_pci_info[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82371FB_0,
+		.name		= "PIIXa",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 1 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82371FB_1,
+		.name		= "PIIXb",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 2 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82371MX,
+		.name		= "MPIIX",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= NULL,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= NULL,
+		.channels	= 2,
+		.autodma	= NODMA,
+		.enablebits	= {{0x6D,0x80,0x80}, {0x6F,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 3 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82371SB_1,
+		.name		= "PIIX3",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 4 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82371AB,
+		.name		= "PIIX4",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 5 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82801AB_1,
+		.name		= "ICH0",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 6 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82443MX_1,
+		.name		= "PIIX4",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 7 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82801AA_1,
+		.name		= "ICH",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 8 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82372FB_1,
+		.name		= "PIIX4",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 9 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82451NX,
+		.name		= "PIIX4",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= NOAUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 10 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82801BA_9,
+		.name		= "ICH2",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 11 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82801BA_8,
+		.name		= "ICH2M",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 12 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82801CA_10,
+		.name		= "ICH3M",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 13 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82801CA_11,
+		.name		= "ICH3",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 14 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82801DB_11,
+		.name		= "ICH4",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 15 */
+		.vendor		= PCI_VENDOR_ID_INTEL,
+		.device		= PCI_DEVICE_ID_INTEL_82801E_11,
+		.name		= "C-ICH",
+		.init_setup	= init_setup_piix,
+		.init_chipset	= init_chipset_piix,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_piix,
+		.init_dma	= init_dma_piix,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.init_setup	= NULL,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* PIIX_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/rz1000.c linux-2.4.21-pre6/drivers/ide/pci/rz1000.c
--- linux-2.4.20/drivers/ide/pci/rz1000.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/rz1000.c	2003-03-26 23:49:00.000000000 +0000
@@ -0,0 +1,99 @@
+/*
+ *  linux/drivers/ide/pci/rz1000.c	Version 0.06	January 12, 2003
+ *
+ *  Copyright (C) 1995-1998  Linus Torvalds & author (see below)
+ */
+
+/*
+ *  Principal Author:  mlord@pobox.com (Mark Lord)
+ *
+ *  See linux/MAINTAINERS for address of current maintainer.
+ *
+ *  This file provides support for disabling the buggy read-ahead
+ *  mode of the RZ1000 IDE chipset, commonly used on Intel motherboards.
+ *
+ *  Dunno if this fixes both ports, or only the primary port (?).
+ */
+
+#undef REALLY_SLOW_IO		/* most systems can safely undef this */
+
+#include <linux/config.h> /* for CONFIG_BLK_DEV_IDEPCI */
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "rz1000.h"
+
+static void __init init_hwif_rz1000 (ide_hwif_t *hwif)
+{
+	u16 reg;
+	struct pci_dev *dev = hwif->pci_dev;
+
+	hwif->chipset = ide_rz1000;
+	if (!pci_read_config_word (dev, 0x40, &reg) &&
+	    !pci_write_config_word(dev, 0x40, reg & 0xdfff)) {
+		printk(KERN_INFO "%s: disabled chipset read-ahead "
+			"(buggy RZ1000/RZ1001)\n", hwif->name);
+	} else {
+		hwif->serialized = 1;
+		hwif->drives[0].no_unmask = 1;
+		hwif->drives[1].no_unmask = 1;
+		printk(KERN_INFO "%s: serialized, disabled unmasking "
+			"(buggy RZ1000/RZ1001)\n", hwif->name);
+	}
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static int __devinit rz1000_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &rz1000_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id rz1000_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "RZ1000 IDE",
+	.id_table	= rz1000_pci_tbl,
+	.probe		= rz1000_init_one,
+};
+
+static int rz1000_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void rz1000_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(rz1000_ide_init);
+module_exit(rz1000_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for RZ1000 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/rz1000.h linux-2.4.21-pre6/drivers/ide/pci/rz1000.h
--- linux-2.4.20/drivers/ide/pci/rz1000.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/rz1000.h	2003-03-26 23:49:20.000000000 +0000
@@ -0,0 +1,45 @@
+#ifndef RZ100X_H
+#define RZ100X_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+static void init_hwif_rz1000(ide_hwif_t *);
+
+static ide_pci_device_t rz1000_chipsets[] __devinitdata = {
+{
+		.vendor		= PCI_VENDOR_ID_PCTECH,
+		.device		= PCI_DEVICE_ID_PCTECH_RZ1000,
+		.name		= "RZ1000",
+		.init_chipset	= NULL,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_rz1000,
+		.init_dma	= NULL,
+		.channels	= 2,
+		.autodma	= NODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= PCI_VENDOR_ID_PCTECH,
+		.device		= PCI_DEVICE_ID_PCTECH_RZ1001,
+		.name		= "RZ1001",
+		.init_chipset	= NULL,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_rz1000,
+		.init_dma	= NULL,
+		.channels	= 2,
+		.autodma	= NODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* RZ100X_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/sc1200.c linux-2.4.21-pre6/drivers/ide/pci/sc1200.c
--- linux-2.4.20/drivers/ide/pci/sc1200.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/sc1200.c	2003-03-26 23:49:00.000000000 +0000
@@ -0,0 +1,594 @@
+/*
+ * linux/drivers/ide/pci/sc1200.c		Version 0.91	28-Jan-2003
+ *
+ * Copyright (C) 2000-2002		Mark Lord <mlord@pobox.com>
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ * Development of this chipset driver was funded
+ * by the nice folks at National Semiconductor.
+ *
+ * Documentation:
+ *	Available from National Semiconductor
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+#include <linux/pm.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+#include "sc1200.h"
+
+#define DISPLAY_SC1200_TIMINGS
+
+#if defined(DISPLAY_SC1200_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static int sc1200_get_info(char *, char **, off_t, int);
+extern int (*sc1200_display_info)(char *, char **, off_t, int); /* ide-proc.c */
+extern char *ide_media_verbose(ide_drive_t *);
+static u8 sc1200_proc = 0;
+
+#define SC1200_REV_A	0x00
+#define SC1200_REV_B1	0x01
+#define SC1200_REV_B3	0x02
+#define SC1200_REV_C1	0x03
+#define SC1200_REV_D1	0x04
+
+#define PCI_CLK_33	0x00
+#define PCI_CLK_48	0x01
+#define PCI_CLK_66	0x02
+#define PCI_CLK_33A	0x03
+
+static unsigned short sc1200_get_pci_clock (void)
+{
+	unsigned char chip_id, silicon_revision;
+	unsigned int pci_clock;
+	/*
+	 * Check the silicon revision, as not all versions of the chip
+	 * have the register with the fast PCI bus timings.
+	 */
+	chip_id = inb (0x903c);
+	silicon_revision = inb (0x903d);
+
+	// Read the fast pci clock frequency
+	if (chip_id == 0x04 && silicon_revision < SC1200_REV_B1) {
+		pci_clock = PCI_CLK_33;
+	} else {
+		// check clock generator configuration (cfcc)
+		// the clock is in bits 8 and 9 of this word
+
+		pci_clock = inw (0x901e);
+		pci_clock >>= 8;
+		pci_clock &= 0x03;
+		if (pci_clock == PCI_CLK_33A)
+			pci_clock = PCI_CLK_33;
+	}
+	return pci_clock;
+}
+
+static struct pci_dev *bmide_dev;
+
+static int sc1200_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	unsigned long bibma = pci_resource_start(bmide_dev, 4);
+	u8  c0 = 0, c1 = 0;
+
+	/*
+	 * at that point bibma+0x2 et bibma+0xa are byte registers
+	 * to investigate:
+	 */
+
+	c0 = inb_p(bibma + 0x02);
+	c1 = inb_p(bibma + 0x0a);
+
+	p += sprintf(p, "\n                               National SCx200 Chipset.\n");
+	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
+	p += sprintf(p, "                %sabled                         %sabled\n",
+			(c0&0x80) ? "dis" : " en",
+			(c1&0x80) ? "dis" : " en");
+	p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
+	p += sprintf(p, "DMA enabled:    %s              %s             %s               %s\n",
+			(c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ",
+			(c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " );
+
+	p += sprintf(p, "UDMA\n");
+	p += sprintf(p, "DMA\n");
+	p += sprintf(p, "PIO\n");
+
+	return p-buffer;
+}
+#endif /* DISPLAY_SC1200_TIMINGS && CONFIG_PROC_FS */
+
+extern char *ide_xfer_verbose (byte xfer_rate);
+
+/*
+ * Set a new transfer mode at the drive
+ */
+int sc1200_set_xfer_mode (ide_drive_t *drive, byte mode)
+{
+	printk("%s: sc1200_set_xfer_mode(%s)\n", drive->name, ide_xfer_verbose(mode));
+	return ide_config_drive_speed(drive, mode);
+}
+
+/*
+ * Here are the standard PIO mode 0-4 timings for each "format".
+ * Format-0 uses fast data reg timings, with slower command reg timings.
+ * Format-1 uses fast timings for all registers, but won't work with all drives.
+ */
+static const unsigned int sc1200_pio_timings[4][5] =
+	{{0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010},	// format0  33Mhz
+	 {0xd1329172, 0x71212171, 0x30200080, 0x20102010, 0x00100010},	// format1, 33Mhz
+	 {0xfaa3f4f3, 0xc23232b2, 0x513101c1, 0x31213121, 0x10211021},	// format1, 48Mhz
+	 {0xfff4fff4, 0xf35353d3, 0x814102f1, 0x42314231, 0x11311131}};	// format1, 66Mhz
+
+/*
+ * After chip reset, the PIO timings are set to 0x00009172, which is not valid.
+ */
+//#define SC1200_BAD_PIO(timings) (((timings)&~0x80000000)==0x00009172)
+
+static int sc1200_autoselect_dma_mode (ide_drive_t *drive)
+{
+	int			udma_ok = 1, mode = 0;
+	ide_hwif_t		*hwif = HWIF(drive);
+	int			unit = drive->select.b.unit;
+	ide_drive_t		*mate = &hwif->drives[unit^1];
+	struct hd_driveid	*id = drive->id;
+
+	/*
+	 * The SC1200 specifies that two drives sharing a cable cannot
+	 * mix UDMA/MDMA.  It has to be one or the other, for the pair,
+	 * though different timings can still be chosen for each drive.
+	 * We could set the appropriate timing bits on the fly,
+	 * but that might be a bit confusing.  So, for now we statically
+	 * handle this requirement by looking at our mate drive to see
+	 * what it is capable of, before choosing a mode for our own drive.
+	 */
+	if (mate->present) {
+		struct hd_driveid *mateid = mate->id;
+		if (mateid && (mateid->capability & 1) && !hwif->ide_dma_bad_drive(mate)) {
+			if ((mateid->field_valid & 4) && (mateid->dma_ultra & 7))
+				udma_ok = 1;
+			else if ((mateid->field_valid & 2) && (mateid->dma_mword & 7))
+				udma_ok = 0;
+			else
+				udma_ok = 1;
+		}
+	}
+	/*
+	 * Now see what the current drive is capable of,
+	 * selecting UDMA only if the mate said it was ok.
+	 */
+	if (id && (id->capability & 1) && hwif->autodma && !hwif->ide_dma_bad_drive(drive)) {
+		if (udma_ok && (id->field_valid & 4) && (id->dma_ultra & 7)) {
+			if      (id->dma_ultra & 4)
+				mode = XFER_UDMA_2;
+			else if (id->dma_ultra & 2)
+				mode = XFER_UDMA_1;
+			else if (id->dma_ultra & 1)
+				mode = XFER_UDMA_0;
+		}
+		if (!mode && (id->field_valid & 2) && (id->dma_mword & 7)) {
+			if      (id->dma_mword & 4)
+				mode = XFER_MW_DMA_2;
+			else if (id->dma_mword & 2)
+				mode = XFER_MW_DMA_1;
+			else if (id->dma_mword & 1)
+				mode = XFER_MW_DMA_0;
+		}
+	}
+	return mode;
+}
+
+/*
+ * sc1200_config_dma2() handles selection/setting of DMA/UDMA modes
+ * for both the chipset and drive.
+ */
+static int sc1200_config_dma2 (ide_drive_t *drive, int mode)
+{
+	ide_hwif_t		*hwif = HWIF(drive);
+	int			unit = drive->select.b.unit;
+	unsigned int		reg, timings;
+	unsigned short		pci_clock;
+	unsigned int		basereg = hwif->channel ? 0x50 : 0x40;
+
+	/*
+	 * Default to DMA-off in case we run into trouble here.
+	 */
+	hwif->ide_dma_off_quietly(drive);			/* turn off DMA while we fiddle */
+	outb(inb(hwif->dma_base+2)&~(unit?0x40:0x20), hwif->dma_base+2); /* clear DMA_capable bit */
+
+	/*
+	 * Tell the drive to switch to the new mode; abort on failure.
+	 */
+	if (!mode || sc1200_set_xfer_mode(drive, mode)) {
+		printk("SC1200: set xfer mode failure\n");
+		return 1;	/* failure */
+	}
+
+	pci_clock = sc1200_get_pci_clock();
+
+	/*
+	 * Now tune the chipset to match the drive:
+	 *
+	 * Note that each DMA mode has several timings associated with it.
+	 * The correct timing depends on the fast PCI clock freq.
+	 */
+	timings = 0;
+	switch (mode) {
+		case XFER_UDMA_0:
+			switch (pci_clock) {
+				case PCI_CLK_33:	timings = 0x00921250;	break;
+				case PCI_CLK_48:	timings = 0x00932470;	break;
+				case PCI_CLK_66:	timings = 0x009436a1;	break;
+			}
+			break;
+		case XFER_UDMA_1:
+			switch (pci_clock) {
+				case PCI_CLK_33:	timings = 0x00911140;	break;
+				case PCI_CLK_48:	timings = 0x00922260;	break;
+				case PCI_CLK_66:	timings = 0x00933481;	break;
+			}
+			break;
+		case XFER_UDMA_2:
+			switch (pci_clock) {
+				case PCI_CLK_33:	timings = 0x00911030;	break;
+				case PCI_CLK_48:	timings = 0x00922140;	break;
+				case PCI_CLK_66:	timings = 0x00923261;	break;
+			}
+			break;
+		case XFER_MW_DMA_0:
+			switch (pci_clock) {
+				case PCI_CLK_33:	timings = 0x00077771;	break;
+				case PCI_CLK_48:	timings = 0x000bbbb2;	break;
+				case PCI_CLK_66:	timings = 0x000ffff3;	break;
+			}
+			break;
+		case XFER_MW_DMA_1:
+			switch (pci_clock) {
+				case PCI_CLK_33:	timings = 0x00012121;	break;
+				case PCI_CLK_48:	timings = 0x00024241;	break;
+				case PCI_CLK_66:	timings = 0x00035352;	break;
+			}
+			break;
+		case XFER_MW_DMA_2:
+			switch (pci_clock) {
+				case PCI_CLK_33:	timings = 0x00002020;	break;
+				case PCI_CLK_48:	timings = 0x00013131;	break;
+				case PCI_CLK_66:	timings = 0x00015151;	break;
+			}
+			break;
+	}
+
+	if (timings == 0) {
+		printk("%s: sc1200_config_dma: huh? mode=%02x clk=%x \n", drive->name, mode, pci_clock);
+		return 1;	/* failure */
+	}
+
+	if (unit == 0) {			/* are we configuring drive0? */
+		pci_read_config_dword(hwif->pci_dev, basereg+4, &reg);
+		timings |= reg & 0x80000000;	/* preserve PIO format bit */
+		pci_write_config_dword(hwif->pci_dev, basereg+4, timings);
+	} else {
+		pci_write_config_dword(hwif->pci_dev, basereg+12, timings);
+	}
+
+	outb(inb(hwif->dma_base+2)|(unit?0x40:0x20), hwif->dma_base+2);	/* set DMA_capable bit */
+
+	/*
+	 * Finally, turn DMA on in software, and exit.
+	 */
+	return hwif->ide_dma_on(drive);	/* success */
+}
+
+/*
+ * sc1200_config_dma() handles selection/setting of DMA/UDMA modes
+ * for both the chipset and drive.
+ */
+static int sc1200_config_dma (ide_drive_t *drive)
+{
+	return sc1200_config_dma2(drive, sc1200_autoselect_dma_mode(drive));
+}
+
+
+/*  Replacement for the standard ide_dma_end action in
+ *  dma_proc.
+ *
+ *  returns 1 on error, 0 otherwise
+ */
+int sc1200_ide_dma_end (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	unsigned long dma_base = hwif->dma_base;
+	byte dma_stat;
+
+	dma_stat = inb(dma_base+2);		/* get DMA status */
+
+	if (!(dma_stat & 4))
+		printk(" ide_dma_end dma_stat=%0x err=%x newerr=%x\n",
+		  dma_stat, ((dma_stat&7)!=4), ((dma_stat&2)==2));
+
+	outb(dma_stat|0x1b, dma_base+2);	/* clear the INTR & ERROR bits */
+	outb(inb(dma_base)&~1, dma_base);	/* !! DO THIS HERE !! stop DMA */
+
+	drive->waiting_for_dma = 0;
+	ide_destroy_dmatable(drive);		/* purge DMA mappings */
+
+	return (dma_stat & 7) != 4;		/* verify good DMA status */
+}
+
+/*
+ * sc1200_tuneproc() handles selection/setting of PIO modes
+ * for both the chipset and drive.
+ *
+ * All existing BIOSs for this chipset guarantee that all drives
+ * will have valid default PIO timings set up before we get here.
+ */
+static void sc1200_tuneproc (ide_drive_t *drive, byte pio)	/* mode=255 means "autotune" */
+{
+	ide_hwif_t	*hwif = HWIF(drive);
+	unsigned int	format;
+	static byte	modes[5] = {XFER_PIO_0, XFER_PIO_1, XFER_PIO_2, XFER_PIO_3, XFER_PIO_4};
+	int		mode = -1;
+
+	switch (pio) {
+		case 200: mode = XFER_UDMA_0;	break;
+		case 201: mode = XFER_UDMA_1;	break;
+		case 202: mode = XFER_UDMA_2;	break;
+		case 100: mode = XFER_MW_DMA_0;	break;
+		case 101: mode = XFER_MW_DMA_1;	break;
+		case 102: mode = XFER_MW_DMA_2;	break;
+	}
+	if (mode != -1) {
+		printk("SC1200: %s: changing (U)DMA mode\n", drive->name);
+		(void)sc1200_config_dma2(drive, mode);
+		return;
+	}
+
+	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+	printk("SC1200: %s: setting PIO mode%d\n", drive->name, pio);
+	if (!sc1200_set_xfer_mode(drive, modes[pio])) {
+		unsigned int basereg = hwif->channel ? 0x50 : 0x40;
+		pci_read_config_dword (hwif->pci_dev, basereg+4, &format);
+		format = (format >> 31) & 1;
+		if (format)
+			format += sc1200_get_pci_clock();
+		pci_write_config_dword(hwif->pci_dev, basereg + (drive->select.b.unit << 3), sc1200_pio_timings[format][pio]);
+ 	}
+}
+
+static ide_hwif_t *lookup_pci_dev (ide_hwif_t *prev, struct pci_dev *dev)
+{
+	int	h;
+
+	for (h = 0; h < MAX_HWIFS; h++) {
+		ide_hwif_t *hwif = &ide_hwifs[h];
+		if (prev) {
+			if (hwif == prev)
+				prev = NULL;	// found previous, now look for next match
+		} else {
+			if (hwif && hwif->pci_dev == dev)
+				return hwif;	// found next match
+		}
+	}
+	return NULL;	// not found
+}
+
+typedef struct sc1200_saved_state_s {
+	__u32		regs[4];
+} sc1200_saved_state_t;
+
+static int sc1200_save_state (struct pci_dev *dev, u32 state)
+{
+	ide_hwif_t		*hwif = NULL;
+
+printk("SC1200: save_state(%u)\n", state);
+	if (state != 0)
+		return 0;	// we only save state when going from full power to less
+	//
+	// Loop over all interfaces that are part of this PCI device:
+	//
+	while ((hwif = lookup_pci_dev(hwif, dev)) != NULL) {
+		sc1200_saved_state_t	*ss;
+		unsigned int		basereg, r;
+		//
+		// allocate a permanent save area, if not already allocated
+		//
+		ss = (sc1200_saved_state_t *)hwif->config_data;
+		if (ss == NULL) {
+			ss = kmalloc(sizeof(sc1200_saved_state_t), GFP_KERNEL);
+			if (ss == NULL)
+				return -ENOMEM;
+			(sc1200_saved_state_t *)hwif->config_data = ss;
+		}
+		ss = (sc1200_saved_state_t *)hwif->config_data;
+		//
+		// Save timing registers:  this may be unnecessary if BIOS also does it
+		//
+		basereg = hwif->channel ? 0x50 : 0x40;
+		for (r = 0; r < 4; ++r) {
+			pci_read_config_dword (hwif->pci_dev, basereg + (r<<2), &ss->regs[r]);
+		}
+	}
+	return 0;
+}
+
+static int sc1200_suspend (struct pci_dev *dev, u32 state)
+{
+	printk("SC1200: suspend(%u)\n", state);
+	/* You don't need to iterate over disks -- sysfs should have done that for you already */ 
+
+	pci_disable_device(dev);
+	pci_set_power_state(dev,state);
+	dev->current_state = state;
+	return 0;
+}
+
+static int sc1200_resume (struct pci_dev *dev)
+{
+	ide_hwif_t	*hwif = NULL;
+
+printk("SC1200: resume\n");
+	pci_set_power_state(dev,0);	// bring chip back from sleep state
+	dev->current_state = 0;
+	pci_enable_device(dev);
+	//
+	// loop over all interfaces that are part of this pci device:
+	//
+	while ((hwif = lookup_pci_dev(hwif, dev)) != NULL) {
+		unsigned int		basereg, r, d, format;
+		sc1200_saved_state_t	*ss = (sc1200_saved_state_t *)hwif->config_data;
+printk("%s: SC1200: resume\n", hwif->name);
+
+		//
+		// Restore timing registers:  this may be unnecessary if BIOS also does it
+		//
+		basereg = hwif->channel ? 0x50 : 0x40;
+		if (ss != NULL) {
+			for (r = 0; r < 4; ++r) {
+				pci_write_config_dword(hwif->pci_dev, basereg + (r<<2), ss->regs[r]);
+			}
+		}
+		//
+		// Re-program drive PIO modes
+		//
+		pci_read_config_dword(hwif->pci_dev, basereg+4, &format);
+		format = (format >> 31) & 1;
+		if (format)
+			format += sc1200_get_pci_clock();
+		for (d = 0; d < 2; ++d) {
+			ide_drive_t *drive = &(hwif->drives[d]);
+			if (drive->present) {
+				unsigned int pio, timings;
+				pci_read_config_dword(hwif->pci_dev, basereg+(drive->select.b.unit << 3), &timings);
+				for (pio = 0; pio <= 4; ++pio) {
+					if (sc1200_pio_timings[format][pio] == timings)
+						break;
+				}
+				if (pio > 4)
+					pio = 255; /* autotune */
+				(void)sc1200_tuneproc(drive, pio);
+			}
+		}
+		//
+		// Re-program drive DMA modes
+		//
+		for (d = 0; d < MAX_DRIVES; ++d) {
+			ide_drive_t *drive = &(hwif->drives[d]);
+			if (drive->present && !hwif->ide_dma_bad_drive(drive)) {
+				int was_using_dma = drive->using_dma;
+				hwif->ide_dma_off_quietly(drive);
+				sc1200_config_dma(drive);
+				if (!was_using_dma && drive->using_dma) {
+					hwif->ide_dma_off_quietly(drive);
+				}
+			}
+		}
+	}
+	return 0;
+}
+
+/*
+ * Initialize the sc1200 bridge for reliable IDE DMA operation.
+ */
+static unsigned int __init init_chipset_sc1200 (struct pci_dev *dev, const char *name)
+{
+#if defined(DISPLAY_SC1200_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!bmide_dev) {
+		sc1200_proc = 1;
+		bmide_dev = dev;
+		ide_pci_register_host_proc(&sc1200_procs[0]);
+	}
+#endif /* DISPLAY_SC1200_TIMINGS && CONFIG_PROC_FS */
+	return 0;
+}
+
+/*
+ * This gets invoked by the IDE driver once for each channel,
+ * and performs channel-specific pre-initialization before drive probing.
+ */
+static void __init init_hwif_sc1200 (ide_hwif_t *hwif)
+{
+	if (hwif->mate)
+		hwif->serialized = hwif->mate->serialized = 1;
+	hwif->autodma = 0;
+	if (hwif->dma_base) {
+		hwif->ide_dma_check = &sc1200_config_dma;
+		hwif->ide_dma_end   = &sc1200_ide_dma_end;
+        	if (!noautodma)
+                	hwif->autodma = 1;
+		hwif->tuneproc = &sc1200_tuneproc;
+	}
+        hwif->atapi_dma = 1;
+        hwif->ultra_mask = 0x07;
+        hwif->mwdma_mask = 0x07;
+
+        hwif->drives[0].autodma = hwif->autodma;
+        hwif->drives[1].autodma = hwif->autodma;
+}
+
+static void __init init_dma_sc1200 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+
+static int __devinit sc1200_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &sc1200_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id sc1200_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "SC1200 IDE",
+	.id_table	= sc1200_pci_tbl,
+	.probe		= sc1200_init_one,
+	.save_state	= sc1200_save_state,
+	.suspend	= sc1200_suspend,
+	.resume		= sc1200_resume,
+};
+
+static int sc1200_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void sc1200_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(sc1200_ide_init);
+module_exit(sc1200_ide_exit);
+
+MODULE_AUTHOR("Mark Lord");
+MODULE_DESCRIPTION("PCI driver module for NS SC1200 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/sc1200.h linux-2.4.21-pre6/drivers/ide/pci/sc1200.h
--- linux-2.4.20/drivers/ide/pci/sc1200.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/sc1200.h	2003-03-26 23:49:24.000000000 +0000
@@ -0,0 +1,54 @@
+#ifndef SC1200_H
+#define SC1200_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_SC1200_TIMINGS
+
+#if defined(DISPLAY_SC1200_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 sc1200_proc;
+
+static int sc1200_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t sc1200_procs[] __initdata = {
+	{
+		name:		"sc1200",
+		set:		1,
+		get_info:	sc1200_get_info,
+		parent:		NULL,
+	},
+};
+#endif /* DISPLAY_SC1200_TIMINGS && CONFIG_PROC_FS */
+
+static unsigned int init_chipset_sc1200(struct pci_dev *, const char *);
+static void init_hwif_sc1200(ide_hwif_t *);
+static void init_dma_sc1200(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t sc1200_chipsets[] __devinitdata = {
+	{	/* 0 */
+		vendor:		PCI_VENDOR_ID_NS,
+		device:		PCI_DEVICE_ID_NS_SCx200_IDE,
+		name:		"SC1200",
+		init_chipset:	init_chipset_sc1200,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_sc1200,
+		init_dma:	init_dma_sc1200,
+		channels:	2,
+		autodma:	AUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		0,
+		device:		0,
+		channels:	0,
+		bootable:	EOL,
+	}
+};
+
+#endif /* SC1200_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/serverworks.c linux-2.4.21-pre6/drivers/ide/pci/serverworks.c
--- linux-2.4.20/drivers/ide/pci/serverworks.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/serverworks.c	2003-03-26 23:49:40.000000000 +0000
@@ -0,0 +1,835 @@
+/*
+ * linux/drivers/ide/pci/serverworks.c		Version 0.7	10 Sept 2002
+ *
+ * Copyright (C) 1998-2000 Michel Aubry
+ * Copyright (C) 1998-2000 Andrzej Krzysztofowicz
+ * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
+ * Portions copyright (c) 2001 Sun Microsystems
+ *
+ *
+ * RCC/ServerWorks IDE driver for Linux
+ *
+ *   OSB4: `Open South Bridge' IDE Interface (fn 1)
+ *         supports UDMA mode 2 (33 MB/s)
+ *
+ *   CSB5: `Champion South Bridge' IDE Interface (fn 1)
+ *         all revisions support UDMA mode 4 (66 MB/s)
+ *         revision A2.0 and up support UDMA mode 5 (100 MB/s)
+ *
+ *         *** The CSB5 does not provide ANY register ***
+ *         *** to detect 80-conductor cable presence. ***
+ *
+ *   CSB6: `Champion South Bridge' IDE Interface (optional: third channel)
+ *
+ * Documentation:
+ *	Available under NDA only. Errata info very hard to get.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+
+#include "ide_modes.h"
+#include "serverworks.h"
+
+static u8 svwks_revision = 0;
+static struct pci_dev *isa_dev;
+
+#if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 svwks_proc = 0;
+#define SVWKS_MAX_DEVS		2
+static struct pci_dev *svwks_devs[SVWKS_MAX_DEVS];
+static int n_svwks_devs;
+
+static int svwks_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	int i;
+
+	p += sprintf(p, "\n                             "
+			"ServerWorks OSB4/CSB5/CSB6\n");
+
+	for (i = 0; i < n_svwks_devs; i++) {
+		struct pci_dev *dev = svwks_devs[i];
+		unsigned long bibma = pci_resource_start(dev, 4);
+		u32 reg40, reg44;
+		u16 reg48, reg56;
+		u8  reg54, c0=0, c1=0;
+
+		pci_read_config_dword(dev, 0x40, &reg40);
+		pci_read_config_dword(dev, 0x44, &reg44);
+		pci_read_config_word(dev, 0x48, &reg48);
+		pci_read_config_byte(dev, 0x54, &reg54);
+		pci_read_config_word(dev, 0x56, &reg56);
+
+		/*
+		 * at that point bibma+0x2 et bibma+0xa are byte registers
+		 * to investigate:
+		 */
+		c0 = inb_p(bibma + 0x02);
+		c1 = inb_p(bibma + 0x0a);
+
+		p += sprintf(p, "\n                            ServerWorks ");
+		switch(dev->device) {
+			case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2:
+			case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE:
+				p += sprintf(p, "CSB6 ");
+				break;
+			case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
+				p += sprintf(p, "CSB5 ");
+				break;
+			case PCI_DEVICE_ID_SERVERWORKS_OSB4IDE:
+				p += sprintf(p, "OSB4 ");
+				break;
+			default:
+				p += sprintf(p, "%04x ", dev->device);
+				break;
+		}
+		p += sprintf(p, "Chipset (rev %02x)\n", svwks_revision);
+
+		p += sprintf(p, "------------------------------- "
+				"General Status "
+				"---------------------------------\n");
+		p += sprintf(p, "--------------- Primary Channel "
+				"---------------- Secondary Channel "
+				"-------------\n");
+		p += sprintf(p, "                %sabled"
+				"                         %sabled\n",
+				(c0&0x80) ? "dis" : " en",
+				(c1&0x80) ? "dis" : " en");
+		p += sprintf(p, "--------------- drive0 --------- drive1 "
+				"-------- drive0 ---------- drive1 ------\n");
+		p += sprintf(p, "DMA enabled:    %s              %s"
+				"             %s               %s\n",
+			(c0&0x20) ? "yes" : "no ",
+			(c0&0x40) ? "yes" : "no ",
+			(c1&0x20) ? "yes" : "no ",
+			(c1&0x40) ? "yes" : "no " );
+		p += sprintf(p, "UDMA enabled:   %s              %s"
+				"             %s               %s\n",
+			(reg54 & 0x01) ? "yes" : "no ",
+			(reg54 & 0x02) ? "yes" : "no ",
+			(reg54 & 0x04) ? "yes" : "no ",
+			(reg54 & 0x08) ? "yes" : "no " );
+		p += sprintf(p, "UDMA enabled:   %s                %s"
+				"               %s                 %s\n",
+			((reg56&0x0005)==0x0005)?"5":
+				((reg56&0x0004)==0x0004)?"4":
+				((reg56&0x0003)==0x0003)?"3":
+				((reg56&0x0002)==0x0002)?"2":
+				((reg56&0x0001)==0x0001)?"1":
+				((reg56&0x000F))?"?":"0",
+			((reg56&0x0050)==0x0050)?"5":
+				((reg56&0x0040)==0x0040)?"4":
+				((reg56&0x0030)==0x0030)?"3":
+				((reg56&0x0020)==0x0020)?"2":
+				((reg56&0x0010)==0x0010)?"1":
+				((reg56&0x00F0))?"?":"0",
+			((reg56&0x0500)==0x0500)?"5":
+				((reg56&0x0400)==0x0400)?"4":
+				((reg56&0x0300)==0x0300)?"3":
+				((reg56&0x0200)==0x0200)?"2":
+				((reg56&0x0100)==0x0100)?"1":
+				((reg56&0x0F00))?"?":"0",
+			((reg56&0x5000)==0x5000)?"5":
+				((reg56&0x4000)==0x4000)?"4":
+				((reg56&0x3000)==0x3000)?"3":
+				((reg56&0x2000)==0x2000)?"2":
+				((reg56&0x1000)==0x1000)?"1":
+				((reg56&0xF000))?"?":"0");
+		p += sprintf(p, "DMA enabled:    %s                %s"
+				"               %s                 %s\n",
+			((reg44&0x00002000)==0x00002000)?"2":
+				((reg44&0x00002100)==0x00002100)?"1":
+				((reg44&0x00007700)==0x00007700)?"0":
+				((reg44&0x0000FF00)==0x0000FF00)?"X":"?",
+			((reg44&0x00000020)==0x00000020)?"2":
+				((reg44&0x00000021)==0x00000021)?"1":
+				((reg44&0x00000077)==0x00000077)?"0":
+				((reg44&0x000000FF)==0x000000FF)?"X":"?",
+			((reg44&0x20000000)==0x20000000)?"2":
+				((reg44&0x21000000)==0x21000000)?"1":
+				((reg44&0x77000000)==0x77000000)?"0":
+				((reg44&0xFF000000)==0xFF000000)?"X":"?",
+			((reg44&0x00200000)==0x00200000)?"2":
+				((reg44&0x00210000)==0x00210000)?"1":
+				((reg44&0x00770000)==0x00770000)?"0":
+				((reg44&0x00FF0000)==0x00FF0000)?"X":"?");
+
+		p += sprintf(p, "PIO  enabled:   %s                %s"
+				"               %s                 %s\n",
+			((reg40&0x00002000)==0x00002000)?"4":
+				((reg40&0x00002200)==0x00002200)?"3":
+				((reg40&0x00003400)==0x00003400)?"2":
+				((reg40&0x00004700)==0x00004700)?"1":
+				((reg40&0x00005D00)==0x00005D00)?"0":"?",
+			((reg40&0x00000020)==0x00000020)?"4":
+				((reg40&0x00000022)==0x00000022)?"3":
+				((reg40&0x00000034)==0x00000034)?"2":
+				((reg40&0x00000047)==0x00000047)?"1":
+				((reg40&0x0000005D)==0x0000005D)?"0":"?",
+			((reg40&0x20000000)==0x20000000)?"4":
+				((reg40&0x22000000)==0x22000000)?"3":
+				((reg40&0x34000000)==0x34000000)?"2":
+				((reg40&0x47000000)==0x47000000)?"1":
+				((reg40&0x5D000000)==0x5D000000)?"0":"?",
+			((reg40&0x00200000)==0x00200000)?"4":
+				((reg40&0x00220000)==0x00220000)?"3":
+				((reg40&0x00340000)==0x00340000)?"2":
+				((reg40&0x00470000)==0x00470000)?"1":
+				((reg40&0x005D0000)==0x005D0000)?"0":"?");
+
+	}
+	p += sprintf(p, "\n");
+
+	return p-buffer;	 /* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static u8 svwks_ratemask (ide_drive_t *drive)
+{
+	struct pci_dev *dev     = HWIF(drive)->pci_dev;
+	u8 mode;
+
+	if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
+		u32 reg = 0;
+		if (isa_dev)
+			pci_read_config_dword(isa_dev, 0x64, &reg);
+			
+		/*
+		 *	Don't enable UDMA on disk devices for the moment
+		 */
+		if(drive->media == ide_disk)
+			return 0;
+		/* Check the OSB4 DMA33 enable bit */
+		return ((reg & 0x00004000) == 0x00004000) ? 1 : 0;
+	} else if (svwks_revision < SVWKS_CSB5_REVISION_NEW) {
+		return 1;
+	} else if (svwks_revision >= SVWKS_CSB5_REVISION_NEW) {
+		u8 btr = 0;
+		pci_read_config_byte(dev, 0x5A, &btr);
+		mode = btr;
+		if (!eighty_ninty_three(drive))
+			mode = min(mode, (u8)1);
+	}
+	if (((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
+	     (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) &&
+	    (!(PCI_FUNC(dev->devfn) & 1)))
+		mode = 2;
+	return mode;
+}
+
+static u8 svwks_csb_check (struct pci_dev *dev)
+{
+	switch (dev->device) {
+		case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
+		case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE:
+		case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2:
+			return 1;
+		default:
+			break;
+	}
+	return 0;
+}
+static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	u8 udma_modes[]		= { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
+	u8 dma_modes[]		= { 0x77, 0x21, 0x20 };
+	u8 pio_modes[]		= { 0x5d, 0x47, 0x34, 0x22, 0x20 };
+	u8 drive_pci[]		= { 0x41, 0x40, 0x43, 0x42 };
+	u8 drive_pci2[]		= { 0x45, 0x44, 0x47, 0x46 };
+
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 speed		= ide_rate_filter(svwks_ratemask(drive), xferspeed);
+	u8 pio			= ide_get_best_pio_mode(drive, 255, 5, NULL);
+	u8 unit			= (drive->select.b.unit & 0x01);
+	u8 csb5			= svwks_csb_check(dev);
+	u8 ultra_enable		= 0, ultra_timing = 0;
+	u8 dma_timing		= 0, pio_timing = 0;
+	u16 csb5_pio		= 0;
+
+	/* If we are about to put a disk into UDMA mode we screwed up.
+	   Our code assumes we never _ever_ do this on an OSB4 */
+	   
+	if(dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4 &&
+		drive->media == ide_disk && speed >= XFER_UDMA_0)
+			BUG();
+			
+	pci_read_config_byte(dev, drive_pci[drive->dn], &pio_timing);
+	pci_read_config_byte(dev, drive_pci2[drive->dn], &dma_timing);
+	pci_read_config_byte(dev, (0x56|hwif->channel), &ultra_timing);
+	pci_read_config_word(dev, 0x4A, &csb5_pio);
+	pci_read_config_byte(dev, 0x54, &ultra_enable);
+
+	/* Per Specified Design by OEM, and ASIC Architect */
+	if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
+	    (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) {
+		if (!drive->init_speed) {
+			u8 dma_stat = hwif->INB(hwif->dma_status);
+
+dma_pio:
+			if (((ultra_enable << (7-drive->dn) & 0x80) == 0x80) &&
+			    ((dma_stat & (1<<(5+unit))) == (1<<(5+unit)))) {
+				drive->current_speed = drive->init_speed = XFER_UDMA_0 + udma_modes[(ultra_timing >> (4*unit)) & ~(0xF0)];
+				return 0;
+			} else if ((dma_timing) &&
+				   ((dma_stat&(1<<(5+unit)))==(1<<(5+unit)))) {
+				u8 dmaspeed = dma_timing;
+
+				dma_timing &= ~0xFF;
+				if ((dmaspeed & 0x20) == 0x20)
+					dmaspeed = XFER_MW_DMA_2;
+				else if ((dmaspeed & 0x21) == 0x21)
+					dmaspeed = XFER_MW_DMA_1;
+				else if ((dmaspeed & 0x77) == 0x77)
+					dmaspeed = XFER_MW_DMA_0;
+				else
+					goto dma_pio;
+				drive->current_speed = drive->init_speed = dmaspeed;
+				return 0;
+			} else if (pio_timing) {
+				u8 piospeed = pio_timing;
+
+				pio_timing &= ~0xFF;
+				if ((piospeed & 0x20) == 0x20)
+					piospeed = XFER_PIO_4;
+				else if ((piospeed & 0x22) == 0x22)
+					piospeed = XFER_PIO_3;
+				else if ((piospeed & 0x34) == 0x34)
+					piospeed = XFER_PIO_2;
+				else if ((piospeed & 0x47) == 0x47)
+					piospeed = XFER_PIO_1;
+				else if ((piospeed & 0x5d) == 0x5d)
+					piospeed = XFER_PIO_0;
+				else
+					goto oem_setup_failed;
+				drive->current_speed = drive->init_speed = piospeed;
+				return 0;
+			}
+		}
+	}
+
+oem_setup_failed:
+
+	pio_timing	&= ~0xFF;
+	dma_timing	&= ~0xFF;
+	ultra_timing	&= ~(0x0F << (4*unit));
+	ultra_enable	&= ~(0x01 << drive->dn);
+	csb5_pio	&= ~(0x0F << (4*drive->dn));
+
+	switch(speed) {
+		case XFER_PIO_4:
+		case XFER_PIO_3:
+		case XFER_PIO_2:
+		case XFER_PIO_1:
+		case XFER_PIO_0:
+			pio_timing |= pio_modes[speed - XFER_PIO_0];
+			csb5_pio   |= ((speed - XFER_PIO_0) << (4*drive->dn));
+			break;
+
+		case XFER_MW_DMA_2:
+		case XFER_MW_DMA_1:
+		case XFER_MW_DMA_0:
+			pio_timing |= pio_modes[pio];
+			csb5_pio   |= (pio << (4*drive->dn));
+			dma_timing |= dma_modes[speed - XFER_MW_DMA_0];
+			break;
+
+		case XFER_UDMA_5:
+		case XFER_UDMA_4:
+		case XFER_UDMA_3:
+		case XFER_UDMA_2:
+		case XFER_UDMA_1:
+		case XFER_UDMA_0:
+			pio_timing   |= pio_modes[pio];
+			csb5_pio     |= (pio << (4*drive->dn));
+			dma_timing   |= dma_modes[2];
+			ultra_timing |= ((udma_modes[speed - XFER_UDMA_0]) << (4*unit));
+			ultra_enable |= (0x01 << drive->dn);
+		default:
+			break;
+	}
+
+	pci_write_config_byte(dev, drive_pci[drive->dn], pio_timing);
+	if (csb5)
+		pci_write_config_word(dev, 0x4A, csb5_pio);
+
+	pci_write_config_byte(dev, drive_pci2[drive->dn], dma_timing);
+	pci_write_config_byte(dev, (0x56|hwif->channel), ultra_timing);
+	pci_write_config_byte(dev, 0x54, ultra_enable);
+
+	return (ide_config_drive_speed(drive, speed));
+}
+
+static void config_chipset_for_pio (ide_drive_t *drive)
+{
+	u16 eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
+	u16 xfer_pio = drive->id->eide_pio_modes;
+	u8 timing, speed, pio;
+
+	pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
+
+	if (xfer_pio > 4)
+		xfer_pio = 0;
+
+	if (drive->id->eide_pio_iordy > 0)
+		for (xfer_pio = 5;
+			xfer_pio>0 &&
+			drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
+			xfer_pio--);
+	else
+		xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
+			   (drive->id->eide_pio_modes & 2) ? 0x04 :
+			   (drive->id->eide_pio_modes & 1) ? 0x03 :
+			   (drive->id->tPIO & 2) ? 0x02 :
+			   (drive->id->tPIO & 1) ? 0x01 : xfer_pio;
+
+	timing = (xfer_pio >= pio) ? xfer_pio : pio;
+
+	switch(timing) {
+		case 4: speed = XFER_PIO_4;break;
+		case 3: speed = XFER_PIO_3;break;
+		case 2: speed = XFER_PIO_2;break;
+		case 1: speed = XFER_PIO_1;break;
+		default:
+			speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW;
+			break;
+	}
+	(void) svwks_tune_chipset(drive, speed);
+	drive->current_speed = speed;
+}
+
+static void svwks_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	(void) svwks_tune_chipset(drive, (XFER_PIO_0 + pio));
+}
+
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	u8 speed = ide_dma_speed(drive, svwks_ratemask(drive));
+
+	if (!(speed))
+		speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
+
+	(void) svwks_tune_chipset(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static int svwks_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	drive->init_speed = 0;
+
+	if (id && (id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto no_dma_set;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		config_chipset_for_pio(drive);
+		//	hwif->tuneproc(drive, 5);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+static int svwks_ide_dma_end (ide_drive_t *drive)
+{
+	/*
+	 *	We never place the OSB4 into a UDMA mode with a disk
+	 *	medium, that means the UDMA "all my data is 4 byte shifted"
+	 *	problem cannot occur.
+	 */
+#if 0
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 dma_stat		= hwif->INB(hwif->dma_status);
+
+	if ((dma_stat & 1) && drive->media == ide_disk)
+	{
+		printk(KERN_CRIT "Serverworks OSB4 in impossible state.\n");
+		printk(KERN_CRIT "Disable UDMA or if you are using Seagate then try switching disk types\n");
+		printk(KERN_CRIT "on this controller. Please report this event to osb4-bug@ide.cabal.tm\n");
+		/* Panic might sys_sync -> death by corrupt disk */
+		printk(KERN_CRIT "OSB4: continuing might cause disk corruption.\n");
+		while(1)
+			cpu_relax();
+	}
+#endif	
+	return __ide_dma_end(drive);
+}
+
+static unsigned int __init init_chipset_svwks (struct pci_dev *dev, const char *name)
+{
+	unsigned int reg;
+	u8 btr;
+
+	/* save revision id to determine DMA capability */
+	pci_read_config_byte(dev, PCI_REVISION_ID, &svwks_revision);
+
+	/* force Master Latency Timer value to 64 PCICLKs */
+	pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40);
+
+	/* OSB4 : South Bridge and IDE */
+	if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
+		isa_dev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS,
+			  PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL);
+		if (isa_dev) {
+			pci_read_config_dword(isa_dev, 0x64, &reg);
+			reg &= ~0x00002000; /* disable 600ns interrupt mask */
+			if(!(reg & 0x00004000))
+				printk(KERN_DEBUG "%s: UDMA not BIOS enabled.\n", name);
+			reg |=  0x00004000; /* enable UDMA/33 support */
+			pci_write_config_dword(isa_dev, 0x64, reg);
+		}
+	}
+
+	/* setup CSB5/CSB6 : South Bridge and IDE option RAID */
+	else if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ||
+		 (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
+		 (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) {
+//		u32 pioreg = 0, dmareg = 0;
+
+		/* Third Channel Test */
+		if (!(PCI_FUNC(dev->devfn) & 1)) {
+#if 1
+			struct pci_dev * findev = NULL;
+			u32 reg4c = 0;
+			findev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS,
+				PCI_DEVICE_ID_SERVERWORKS_CSB5, NULL);
+			if (findev) {
+				pci_read_config_dword(findev, 0x4C, &reg4c);
+				reg4c &= ~0x000007FF;
+				reg4c |=  0x00000040;
+				reg4c |=  0x00000020;
+				pci_write_config_dword(findev, 0x4C, reg4c);
+			}
+#endif
+			outb_p(0x06, 0x0c00);
+			dev->irq = inb_p(0x0c01);
+#if 0
+			/* WE need to figure out how to get the correct one */
+			printk("%s: interrupt %d\n", name, dev->irq);
+			if (dev->irq != 0x0B)
+				dev->irq = 0x0B;
+#endif
+#if 0
+			printk("%s: device class (0x%04x)\n",
+				name, dev->class);
+#else
+			if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) {
+				dev->class &= ~0x000F0F00;
+		//		dev->class |= ~0x00000400;
+				dev->class |= ~0x00010100;
+				/**/
+			}
+#endif
+		} else {
+			struct pci_dev * findev = NULL;
+			u8 reg41 = 0;
+
+			findev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS,
+					PCI_DEVICE_ID_SERVERWORKS_CSB6, NULL);
+			if (findev) {
+				pci_read_config_byte(findev, 0x41, &reg41);
+				reg41 &= ~0x40;
+				pci_write_config_byte(findev, 0x41, reg41);
+			}
+			/*
+			 * This is a device pin issue on CSB6.
+			 * Since there will be a future raid mode,
+			 * early versions of the chipset require the
+			 * interrupt pin to be set, and it is a compatablity
+			 * mode issue.
+			 */
+			dev->irq = 0;
+		}
+//		pci_read_config_dword(dev, 0x40, &pioreg)
+//		pci_write_config_dword(dev, 0x40, 0x99999999);
+//		pci_read_config_dword(dev, 0x44, &dmareg);
+//		pci_write_config_dword(dev, 0x44, 0xFFFFFFFF);
+		/* setup the UDMA Control register
+		 *
+		 * 1. clear bit 6 to enable DMA
+		 * 2. enable DMA modes with bits 0-1
+		 * 	00 : legacy
+		 * 	01 : udma2
+		 * 	10 : udma2/udma4
+		 * 	11 : udma2/udma4/udma5
+		 */
+		pci_read_config_byte(dev, 0x5A, &btr);
+		btr &= ~0x40;
+		if (!(PCI_FUNC(dev->devfn) & 1))
+			btr |= 0x2;
+		else
+			btr |= (svwks_revision >= SVWKS_CSB5_REVISION_NEW) ? 0x3 : 0x2;
+		pci_write_config_byte(dev, 0x5A, btr);
+	}
+
+
+#if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS)
+	svwks_devs[n_svwks_devs++] = dev;
+
+	if (!svwks_proc) {
+		svwks_proc = 1;
+		ide_pci_register_host_proc(&svwks_procs[0]);
+	}
+#endif /* DISPLAY_SVWKS_TIMINGS && CONFIG_PROC_FS */
+
+	return (dev->irq) ? dev->irq : 0;
+}
+
+static unsigned int __init ata66_svwks_svwks (ide_hwif_t *hwif)
+{
+//	struct pci_dev *dev = hwif->pci_dev;
+//	return 0;
+	return 1;
+}
+
+/* On Dell PowerEdge servers with a CSB5/CSB6, the top two bits
+ * of the subsystem device ID indicate presence of an 80-pin cable.
+ * Bit 15 clear = secondary IDE channel does not have 80-pin cable.
+ * Bit 15 set   = secondary IDE channel has 80-pin cable.
+ * Bit 14 clear = primary IDE channel does not have 80-pin cable.
+ * Bit 14 set   = primary IDE channel has 80-pin cable.
+ */
+static unsigned int __init ata66_svwks_dell (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev = hwif->pci_dev;
+	if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
+	    dev->vendor	== PCI_VENDOR_ID_SERVERWORKS &&
+	    (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE ||
+	     dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE))
+		return ((1 << (hwif->channel + 14)) &
+			dev->subsystem_device) ? 1 : 0;
+	return 0;
+}
+
+/* Sun Cobalt Alpine hardware avoids the 80-pin cable
+ * detect issue by attaching the drives directly to the board.
+ * This check follows the Dell precedent (how scary is that?!)
+ *
+ * WARNING: this only works on Alpine hardware!
+ */
+static unsigned int __init ata66_svwks_cobalt (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev = hwif->pci_dev;
+	if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN &&
+	    dev->vendor	== PCI_VENDOR_ID_SERVERWORKS &&
+	    dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
+		return ((1 << (hwif->channel + 14)) &
+			dev->subsystem_device) ? 1 : 0;
+	return 0;
+}
+
+static unsigned int __init ata66_svwks (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev = hwif->pci_dev;
+
+	/* Per Specified Design by OEM, and ASIC Architect */
+	if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
+	    (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2))
+		return 1;
+
+	/* Server Works */
+	if (dev->subsystem_vendor == PCI_VENDOR_ID_SERVERWORKS)
+		return ata66_svwks_svwks (hwif);
+	
+	/* Dell PowerEdge */
+	if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL)
+		return ata66_svwks_dell (hwif);
+
+	/* Cobalt Alpine */
+	if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN)
+		return ata66_svwks_cobalt (hwif);
+
+	return 0;
+}
+
+#undef CAN_SW_DMA
+static void __init init_hwif_svwks (ide_hwif_t *hwif)
+{
+	u8 dma_stat = 0;
+
+	if (!hwif->irq)
+		hwif->irq = hwif->channel ? 15 : 14;
+
+	hwif->tuneproc = &svwks_tune_drive;
+	hwif->speedproc = &svwks_tune_chipset;
+
+	hwif->atapi_dma = 1;
+
+	if (hwif->pci_dev->device != PCI_DEVICE_ID_SERVERWORKS_OSB4IDE)
+		hwif->ultra_mask = 0x3f;
+
+	hwif->mwdma_mask = 0x07;
+#ifdef CAN_SW_DMA
+	hwif->swdma_mask = 0x07;
+#endif /* CAN_SW_DMA */
+
+	hwif->autodma = 0;
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->ide_dma_check = &svwks_config_drive_xfer_rate;
+	if (hwif->pci_dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE)
+		hwif->ide_dma_end = &svwks_ide_dma_end;
+	else if (!(hwif->udma_four))
+		hwif->udma_four = ata66_svwks(hwif);
+	if (!noautodma)
+		hwif->autodma = 1;
+
+	dma_stat = hwif->INB(hwif->dma_status);
+	hwif->drives[0].autodma = (dma_stat & 0x20);
+	hwif->drives[1].autodma = (dma_stat & 0x40);
+	hwif->drives[0].autotune = (!(dma_stat & 0x20));
+	hwif->drives[1].autotune = (!(dma_stat & 0x40));
+//	hwif->drives[0].autodma = hwif->autodma;
+//	hwif->drives[1].autodma = hwif->autodma;
+}
+
+/*
+ * We allow the BM-DMA driver to only work on enabled interfaces.
+ */
+static void __init init_dma_svwks (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	struct pci_dev *dev = hwif->pci_dev;
+
+	if (((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
+	     (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) &&
+	    (!(PCI_FUNC(dev->devfn) & 1)) && (hwif->channel))
+		return;
+
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static void __init init_setup_svwks (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	ide_setup_pci_device(dev, d);
+}
+
+static void __init init_setup_csb6 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	if (!(PCI_FUNC(dev->devfn) & 1)) {
+		d->bootable = NEVER_BOARD;
+		if (dev->resource[0].start == 0x01f1)
+			d->bootable = ON_BOARD;
+	} else {
+		if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE)
+			return;
+	}
+#if 0
+	if ((IDE_PCI_DEVID_EQ(d->devid, DEVID_CSB6) &&
+             (!(PCI_FUNC(dev->devfn) & 1)))
+		d->autodma = AUTODMA;
+#endif
+
+	d->channels = (((d->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
+			(d->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) &&
+		       (!(PCI_FUNC(dev->devfn) & 1))) ? 1 : 2;
+
+	ide_setup_pci_device(dev, d);
+}
+
+
+/**
+ *	svwks_init_one	-	called when a OSB/CSB is found
+ *	@dev: the svwks device
+ *	@id: the matching pci id
+ *
+ *	Called when the PCI registration layer (or the IDE initialization)
+ *	finds a device matching our IDE device tables.
+ */
+ 
+static int __devinit svwks_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &serverworks_chipsets[id->driver_data];
+
+	if (dev->device != d->device)
+		BUG();
+	d->init_setup(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id svwks_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+	{ PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "Serverworks IDE",
+	.id_table	= svwks_pci_tbl,
+	.probe		= svwks_init_one,
+#if 0	/* FIXME: implement */
+	.suspend	= ,
+	.resume		= ,
+#endif
+};
+
+static int svwks_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void svwks_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(svwks_ide_init);
+module_exit(svwks_ide_exit);
+
+MODULE_AUTHOR("Michael Aubry. Andrzej Krzysztofowicz, Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for Serverworks OSB4/CSB5/CSB6 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/serverworks.h linux-2.4.21-pre6/drivers/ide/pci/serverworks.h
--- linux-2.4.20/drivers/ide/pci/serverworks.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/serverworks.h	2003-03-26 23:49:54.000000000 +0000
@@ -0,0 +1,105 @@
+
+#ifndef SERVERWORKS_H
+#define SERVERWORKS_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#undef SVWKS_DEBUG_DRIVE_INFO
+
+#define SVWKS_CSB5_REVISION_NEW	0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */
+#define SVWKS_CSB6_REVISION	0xa0 /* min PCI_REVISION_ID for UDMA4 (A1.0) */
+
+#define DISPLAY_SVWKS_TIMINGS	1
+
+#if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 svwks_proc;
+
+static int svwks_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t svwks_procs[] __initdata = {
+{
+		.name		= "svwks",
+		.set		= 1,
+		.get_info	= svwks_get_info,
+		.parent		= NULL,
+	},
+};
+#endif  /* defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static void init_setup_svwks(struct pci_dev *, ide_pci_device_t *);
+static void init_setup_csb6(struct pci_dev *, ide_pci_device_t *);
+static unsigned int init_chipset_svwks(struct pci_dev *, const char *);
+static void init_hwif_svwks(ide_hwif_t *);
+static void init_dma_svwks(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t serverworks_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_SERVERWORKS,
+		.device		= PCI_DEVICE_ID_SERVERWORKS_OSB4IDE,
+		.name		= "SvrWks OSB4",
+		.init_setup	= init_setup_svwks,
+		.init_chipset	= init_chipset_svwks,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_svwks,
+		.init_dma	= NULL,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 1 */
+		.vendor		= PCI_VENDOR_ID_SERVERWORKS,
+		.device		= PCI_DEVICE_ID_SERVERWORKS_CSB5IDE,
+		.name		= "SvrWks CSB5",
+		.init_setup	= init_setup_svwks,
+		.init_chipset	= init_chipset_svwks,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_svwks,
+		.init_dma	= init_dma_svwks,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 2 */
+		.vendor		= PCI_VENDOR_ID_SERVERWORKS,
+		.device		= PCI_DEVICE_ID_SERVERWORKS_CSB6IDE,
+		.name		= "SvrWks CSB6",
+		.init_setup	= init_setup_csb6,
+		.init_chipset	= init_chipset_svwks,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_svwks,
+		.init_dma	= init_dma_svwks,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 3 */
+		.vendor		= PCI_VENDOR_ID_SERVERWORKS,
+		.device		= PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2,
+		.name		= "SvrWks CSB6",
+		.init_setup	= init_setup_csb6,
+		.init_chipset	= init_chipset_svwks,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_svwks,
+		.init_dma	= init_dma_svwks,
+		.channels	= 1,	/* 2 */
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* SERVERWORKS_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/siimage.c linux-2.4.21-pre6/drivers/ide/pci/siimage.c
--- linux-2.4.20/drivers/ide/pci/siimage.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/siimage.c	2003-03-26 23:49:20.000000000 +0000
@@ -0,0 +1,853 @@
+/*
+ * linux/drivers/ide/pci/siimage.c		Version 1.02	Jan 30, 2003
+ *
+ * Copyright (C) 2001-2002	Andre Hedrick <andre@linux-ide.org>
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "ide_modes.h"
+#include "siimage.h"
+
+#if defined(DISPLAY_SIIMAGE_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 siimage_proc = 0;
+#define SIIMAGE_MAX_DEVS		5
+static struct pci_dev *siimage_devs[SIIMAGE_MAX_DEVS];
+static int n_siimage_devs;
+
+static char * print_siimage_get_info (char *buf, struct pci_dev *dev, int index)
+{
+	char *p		= buf;
+	u8 mmio		= (pci_get_drvdata(dev) != NULL) ? 1 : 0;
+	unsigned long bmdma	= (mmio) ? ((unsigned long) pci_get_drvdata(dev)) :
+				    (pci_resource_start(dev, 4));
+
+	p += sprintf(p, "\nController: %d\n", index);
+	p += sprintf(p, "SiI%x Chipset.\n", dev->device);
+	if (mmio)
+		p += sprintf(p, "MMIO Base 0x%lx\n", bmdma);
+	p += sprintf(p, "%s-DMA Base 0x%lx\n", (mmio)?"MMIO":"BM", bmdma);
+	p += sprintf(p, "%s-DMA Base 0x%lx\n", (mmio)?"MMIO":"BM", bmdma+8);
+
+	p += sprintf(p, "--------------- Primary Channel "
+			"---------------- Secondary Channel "
+			"-------------\n");
+	p += sprintf(p, "--------------- drive0 --------- drive1 "
+			"-------- drive0 ---------- drive1 ------\n");
+	p += sprintf(p, "PIO Mode:       %s                %s"
+			"               %s                 %s\n",
+			"?", "?", "?", "?");
+	return (char *)p;
+}
+
+static int siimage_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	u16 i;
+
+	p += sprintf(p, "\n");
+	for (i = 0; i < n_siimage_devs; i++) {
+		struct pci_dev *dev	= siimage_devs[i];
+		p = print_siimage_get_info(p, dev, i);
+	}
+	return p-buffer;	/* => must be less than 4k! */
+}
+
+#endif	/* defined(DISPLAY_SIIMAGE_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static byte siimage_ratemask (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 mode	= 0, scsc = 0;
+
+	if (hwif->mmio)
+		scsc = hwif->INB(HWIFADDR(0x4A));
+	else
+		pci_read_config_byte(hwif->pci_dev, 0x8A, &scsc);
+
+	switch(hwif->pci_dev->device) {
+		case PCI_DEVICE_ID_SII_3112:
+			return 4;
+		case PCI_DEVICE_ID_SII_680:
+			if ((scsc & 0x10) == 0x10)	/* 133 */
+				mode = 4;
+			else if ((scsc & 0x30) == 0x00)	/* 100 */
+				mode = 3;
+			else if ((scsc & 0x20) == 0x20)	/* 66 eek */
+				BUG();	// mode = 2;
+			break;
+		default:	return 0;
+	}
+	if (!eighty_ninty_three(drive))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+static byte siimage_taskfile_timing (ide_hwif_t *hwif)
+{
+	u16 timing	= 0x328a;
+
+	if (hwif->mmio)
+		timing = hwif->INW(SELADDR(2));
+	else
+		pci_read_config_word(hwif->pci_dev, SELREG(2), &timing);
+
+	switch (timing) {
+		case 0x10c1:	return 4;
+		case 0x10c3:	return 3;
+		case 0x1281:	return 2;
+		case 0x2283:	return 1;
+		case 0x328a:
+		default:	return 0;
+	}
+}
+
+static void siimage_tuneproc (ide_drive_t *drive, byte mode_wanted)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u16 speedt		= 0;
+	u8 unit			= drive->select.b.unit;
+
+	if (hwif->mmio)
+		speedt = hwif->INW(SELADDR(0x04|(unit<<unit)));
+	else
+		pci_read_config_word(dev, SELADDR(0x04|(unit<<unit)), &speedt);
+
+	/* cheat for now and use the docs */
+//	switch(siimage_taskfile_timing(hwif)) {
+	switch(mode_wanted) {
+		case 4:		speedt = 0x10c1; break;
+		case 3:		speedt = 0x10C3; break;
+		case 2:		speedt = 0x1104; break;
+		case 1:		speedt = 0x2283; break;
+		case 0:
+		default:	speedt = 0x328A; break;
+	}
+	if (hwif->mmio)
+		hwif->OUTW(speedt, SELADDR(0x04|(unit<<unit)));
+	else
+		pci_write_config_word(dev, SELADDR(0x04|(unit<<unit)), speedt);
+}
+
+static void config_siimage_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+{
+	u8 channel_timings	= siimage_taskfile_timing(HWIF(drive));
+	u8 speed = 0, set_pio	= ide_get_best_pio_mode(drive, 4, 5, NULL);
+
+	/* WARNING PIO timing mess is going to happen b/w devices, argh */
+	if ((channel_timings != set_pio) && (set_pio > channel_timings))
+		set_pio = channel_timings;
+
+	siimage_tuneproc(drive, set_pio);
+	speed = XFER_PIO_0 + set_pio;
+	if (set_speed)
+		(void) ide_config_drive_speed(drive, speed);
+}
+
+static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+{
+	config_siimage_chipset_for_pio(drive, set_speed);
+}
+
+static int siimage_tune_chipset (ide_drive_t *drive, byte xferspeed)
+{
+	u8 ultra6[]		= { 0x0F, 0x0B, 0x07, 0x05, 0x03, 0x02, 0x01 };
+	u8 ultra5[]		= { 0x0C, 0x07, 0x05, 0x04, 0x02, 0x01 };
+	u16 dma[]		= { 0x2208, 0x10C2, 0x10C1 };
+
+	ide_hwif_t *hwif	= HWIF(drive);
+	u16 ultra = 0, multi	= 0;
+	u8 mode = 0, unit	= drive->select.b.unit;
+	u8 speed	= ide_rate_filter(siimage_ratemask(drive), xferspeed);
+	u8 scsc = 0, addr_mask	= ((hwif->channel) ?
+				    ((hwif->mmio) ? 0xF4 : 0x84) :
+				    ((hwif->mmio) ? 0xB4 : 0x80));
+
+	if (hwif->mmio) {
+		scsc = hwif->INB(HWIFADDR(0x4A));
+		mode = hwif->INB(HWIFADDR(addr_mask));
+		multi = hwif->INW(SELADDR(0x08|(unit<<unit)));
+		ultra = hwif->INW(SELADDR(0x0C|(unit<<unit)));
+	} else {
+		pci_read_config_byte(hwif->pci_dev, HWIFADDR(0x8A), &scsc);
+		pci_read_config_byte(hwif->pci_dev, addr_mask, &mode);
+		pci_read_config_word(hwif->pci_dev,
+				SELREG(0x08|(unit<<unit)), &multi);
+		pci_read_config_word(hwif->pci_dev,
+				SELREG(0x0C|(unit<<unit)), &ultra);
+	}
+
+	mode &= ~((unit) ? 0x30 : 0x03);
+	ultra &= ~0x3F;
+	scsc = ((scsc & 0x30) == 0x00) ? 0 : 1;
+
+	scsc = (hwif->pci_dev->device == PCI_DEVICE_ID_SII_3112) ? 1 : scsc;
+
+	switch(speed) {
+		case XFER_PIO_4:
+		case XFER_PIO_3:
+		case XFER_PIO_2:
+		case XFER_PIO_1:
+		case XFER_PIO_0:
+			siimage_tuneproc(drive, (speed - XFER_PIO_0));
+			mode |= ((unit) ? 0x10 : 0x01);
+			break;
+		case XFER_MW_DMA_2:
+		case XFER_MW_DMA_1:
+		case XFER_MW_DMA_0:
+			multi = dma[speed - XFER_MW_DMA_0];
+			mode |= ((unit) ? 0x20 : 0x02);
+			config_siimage_chipset_for_pio(drive, 0);
+			break;
+		case XFER_UDMA_6:
+		case XFER_UDMA_5:
+		case XFER_UDMA_4:
+		case XFER_UDMA_3:
+		case XFER_UDMA_2:
+		case XFER_UDMA_1:
+		case XFER_UDMA_0:
+			multi = dma[2];
+			ultra |= ((scsc) ? (ultra5[speed - XFER_UDMA_0]) :
+					   (ultra6[speed - XFER_UDMA_0]));
+			mode |= ((unit) ? 0x30 : 0x03);
+			config_siimage_chipset_for_pio(drive, 0);
+			break;
+		default:
+			return 1;
+	}
+
+	if (hwif->mmio) {
+		hwif->OUTB(mode, HWIFADDR(addr_mask));
+		hwif->OUTW(multi, SELADDR(0x08|(unit<<unit)));
+		hwif->OUTW(ultra, SELADDR(0x0C|(unit<<unit)));
+	} else {
+		pci_write_config_byte(hwif->pci_dev, addr_mask, mode);
+		pci_write_config_word(hwif->pci_dev,
+				SELREG(0x08|(unit<<unit)), multi);
+		pci_write_config_word(hwif->pci_dev,
+				SELREG(0x0C|(unit<<unit)), ultra);
+	}
+
+	return (ide_config_drive_speed(drive, speed));
+}
+
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	u8 speed	= ide_dma_speed(drive, siimage_ratemask(drive));
+
+	config_chipset_for_pio(drive, !speed);
+
+	if (!speed)
+		return 0;
+
+	if (ide_set_xfer_rate(drive, speed))
+		return 0;
+
+	if (!drive->init_speed)
+		drive->init_speed = speed;
+
+	return ide_dma_enable(drive);
+}
+
+static int siimage_config_drive_for_dma (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	if (id != NULL && (id->capability & 1) != 0 && drive->autodma) {
+		if (!(hwif->atapi_dma))
+			goto fast_ata_pio;
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+
+		if ((id->field_valid & 4) && siimage_ratemask(drive)) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		config_chipset_for_pio(drive, 1);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+/* returns 1 if dma irq issued, 0 otherwise */
+static int siimage_io_ide_dma_test_irq (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 dma_altstat		= 0;
+
+	/* return 1 if INTR asserted */
+	if ((hwif->INB(hwif->dma_status) & 4) == 4)
+		return 1;
+
+	/* return 1 if Device INTR asserted */
+	pci_read_config_byte(hwif->pci_dev, SELREG(1), &dma_altstat);
+	if (dma_altstat & 8)
+		return 0;	//return 1;
+	return 0;
+}
+
+static int siimage_mmio_ide_dma_count (ide_drive_t *drive)
+{
+#ifdef SIIMAGE_VIRTUAL_DMAPIO
+	struct request *rq	= HWGROUP(drive)->rq;
+	ide_hwif_t *hwif	= HWIF(drive);
+	u32 count		= (rq->nr_sectors * SECTOR_SIZE);
+	u32 rcount		= 0;
+
+	hwif->OUTL(count, SELADDR(0x1C));
+	rcount = hwif->INL(SELADDR(0x1C));
+
+	printk("\n%s: count = %d, rcount = %d, nr_sectors = %lu\n",
+		drive->name, count, rcount, rq->nr_sectors);
+
+#endif /* SIIMAGE_VIRTUAL_DMAPIO */
+	return __ide_dma_count(drive);
+}
+
+/* returns 1 if dma irq issued, 0 otherwise */
+static int siimage_mmio_ide_dma_test_irq (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+
+	if (SATA_ERROR_REG) {
+		u32 ext_stat = hwif->INL(HWIFADDR(0x10));
+		u8 watchdog = 0;
+		if (ext_stat & ((hwif->channel) ? 0x40 : 0x10)) {
+			u32 sata_error = hwif->INL(SATA_ERROR_REG);
+			hwif->OUTL(sata_error, SATA_ERROR_REG);
+			watchdog = (sata_error & 0x00680000) ? 1 : 0;
+#if 1
+			printk(KERN_WARNING "%s: sata_error = 0x%08x, "
+				"watchdog = %d, %s\n",
+				drive->name, sata_error, watchdog,
+				__FUNCTION__);
+#endif
+
+		} else {
+			watchdog = (ext_stat & 0x8000) ? 1 : 0;
+		}
+		ext_stat >>= 16;
+
+		if (!(ext_stat & 0x0404) && !watchdog)
+			return 0;
+	}
+
+	/* return 1 if INTR asserted */
+	if ((hwif->INB(hwif->dma_status) & 0x04) == 0x04)
+		return 1;
+
+	/* return 1 if Device INTR asserted */
+	if ((hwif->INB(SELADDR(1)) & 8) == 8)
+		return 0;	//return 1;
+
+	return 0;
+}
+
+static int siimage_mmio_ide_dma_verbose (ide_drive_t *drive)
+{
+	int temp = __ide_dma_verbose(drive);
+#if 0
+	drive->using_dma = 0;
+#endif
+	return temp;
+}
+
+static int siimage_busproc (ide_drive_t * drive, int state)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u32 stat_config		= 0;
+
+	if (hwif->mmio) {
+		stat_config = hwif->INL(SELADDR(0));
+	} else
+		pci_read_config_dword(hwif->pci_dev, SELREG(0), &stat_config);
+
+	switch (state) {
+		case BUSSTATE_ON:
+			hwif->drives[0].failures = 0;
+			hwif->drives[1].failures = 0;
+			break;
+		case BUSSTATE_OFF:
+			hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+			hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+			break;
+		case BUSSTATE_TRISTATE:
+			hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+			hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+			break;
+		default:
+			return 0;
+	}
+	hwif->bus_state = state;
+	return 0;
+}
+
+static int siimage_reset_poll (ide_drive_t *drive)
+{
+	if (SATA_STATUS_REG) {
+		ide_hwif_t *hwif	= HWIF(drive);
+
+		if ((hwif->INL(SATA_STATUS_REG) & 0x03) != 0x03) {
+			printk(KERN_WARNING "%s: reset phy dead, status=0x%08x\n",
+				hwif->name, hwif->INL(SATA_STATUS_REG));
+			HWGROUP(drive)->poll_timeout = 0;
+#if 0
+			drive->failures++;
+			return ide_stopped;
+#else
+			return ide_started;
+#endif
+			return 1;
+		}
+		return 0;
+	} else {
+		return 0;
+	}
+}
+
+static void siimage_pre_reset (ide_drive_t *drive)
+{
+	if (drive->media != ide_disk)
+		return;
+
+	if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_SII_3112) {
+		drive->special.b.set_geometry = 0;
+		drive->special.b.recalibrate = 0;
+	}
+}
+
+static void siimage_reset (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 reset		= 0;
+
+	if (hwif->mmio) {
+		reset = hwif->INB(SELADDR(0));
+		hwif->OUTB((reset|0x03), SELADDR(0));
+		udelay(25);
+		hwif->OUTB(reset, SELADDR(0));
+		(void) hwif->INB(SELADDR(0));
+	} else {
+		pci_read_config_byte(hwif->pci_dev, SELREG(0), &reset);
+		pci_write_config_byte(hwif->pci_dev, SELREG(0), reset|0x03);
+		udelay(25);
+		pci_write_config_byte(hwif->pci_dev, SELREG(0), reset);
+		pci_read_config_byte(hwif->pci_dev, SELREG(0), &reset);
+	}
+
+	if (SATA_STATUS_REG) {
+		u32 sata_stat = hwif->INL(SATA_STATUS_REG);
+		printk(KERN_WARNING "%s: reset phy, status=0x%08x, %s\n",
+			hwif->name, sata_stat, __FUNCTION__);
+		if (!(sata_stat)) {
+			printk(KERN_WARNING "%s: reset phy dead, status=0x%08x\n",
+				hwif->name, sata_stat);
+			drive->failures++;
+		}
+	}
+
+}
+
+static void proc_reports_siimage (struct pci_dev *dev, u8 clocking, const char *name)
+{
+	if (dev->device == PCI_DEVICE_ID_SII_3112)
+		goto sata_skip;
+
+	printk(KERN_INFO "%s: BASE CLOCK ", name);
+	clocking &= ~0x0C;
+	switch(clocking) {
+		case 0x03: printk("DISABLED !\n"); break;
+		case 0x02: printk("== 2X PCI \n"); break;
+		case 0x01: printk("== 133 \n"); break;
+		case 0x00: printk("== 100 \n"); break;
+		default:
+			BUG();
+	}
+
+sata_skip:
+
+#if defined(DISPLAY_SIIMAGE_TIMINGS) && defined(CONFIG_PROC_FS)
+	siimage_devs[n_siimage_devs++] = dev;
+
+	if (!siimage_proc) {
+		siimage_proc = 1;
+		ide_pci_register_host_proc(&siimage_procs[0]);
+	}
+#endif /* DISPLAY_SIIMAGE_TIMINGS && CONFIG_PROC_FS */
+}
+
+static unsigned int setup_mmio_siimage (struct pci_dev *dev, const char *name)
+{
+	unsigned long bar5	= pci_resource_start(dev, 5);
+	unsigned long end5	= pci_resource_end(dev, 5);
+	u8 tmpbyte	= 0;
+	unsigned long addr;
+	void *ioaddr;
+
+	ioaddr = ioremap_nocache(bar5, (end5 - bar5));
+
+	if (ioaddr == NULL)
+		return 0;
+
+	pci_set_master(dev);
+	pci_set_drvdata(dev, ioaddr);
+	addr = (unsigned long) ioaddr;
+
+	if (dev->device == PCI_DEVICE_ID_SII_3112) {
+		writel(0, DEVADDR(0x148));
+		writel(0, DEVADDR(0x1C8));
+	}
+
+	writeb(0, DEVADDR(0xB4));
+	writeb(0, DEVADDR(0xF4));
+	tmpbyte = readb(DEVADDR(0x4A));
+
+	switch(tmpbyte) {
+		case 0x01:
+			writeb(tmpbyte|0x10, DEVADDR(0x4A));
+			tmpbyte = readb(DEVADDR(0x4A));
+		case 0x31:
+			/* if clocking is disabled */
+			/* 133 clock attempt to force it on */
+			writeb(tmpbyte & ~0x20, DEVADDR(0x4A));
+			tmpbyte = readb(DEVADDR(0x4A));
+		case 0x11:
+		case 0x21:
+			break;
+		default:
+			tmpbyte &= ~0x30;
+			tmpbyte |= 0x20;
+			writeb(tmpbyte, DEVADDR(0x4A));
+			break;
+	}
+	
+	writeb(0x72, DEVADDR(0xA1));
+	writew(0x328A, DEVADDR(0xA2));
+	writel(0x62DD62DD, DEVADDR(0xA4));
+	writel(0x43924392, DEVADDR(0xA8));
+	writel(0x40094009, DEVADDR(0xAC));
+	writeb(0x72, DEVADDR(0xE1));
+	writew(0x328A, DEVADDR(0xE2));
+	writel(0x62DD62DD, DEVADDR(0xE4));
+	writel(0x43924392, DEVADDR(0xE8));
+	writel(0x40094009, DEVADDR(0xEC));
+
+	if (dev->device == PCI_DEVICE_ID_SII_3112) {
+		writel(0xFFFF0000, DEVADDR(0x108));
+		writel(0xFFFF0000, DEVADDR(0x188));
+		writel(0x00680000, DEVADDR(0x148));
+		writel(0x00680000, DEVADDR(0x1C8));
+	}
+
+	tmpbyte = readb(DEVADDR(0x4A));
+
+	proc_reports_siimage(dev, (tmpbyte>>=4), name);
+	return 1;
+}
+
+static unsigned int __init init_chipset_siimage (struct pci_dev *dev, const char *name)
+{
+	u32 class_rev	= 0;
+	u8 tmpbyte	= 0;
+	u8 BA5_EN	= 0;
+
+        pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+        class_rev &= 0xff;
+	pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (class_rev) ? 1 : 255);	
+
+	pci_read_config_byte(dev, 0x8A, &BA5_EN);
+	if ((BA5_EN & 0x01) || (pci_resource_start(dev, 5))) {
+		if (setup_mmio_siimage(dev, name)) {
+			return 0;
+		}
+	}
+
+	pci_write_config_byte(dev, 0x80, 0x00);
+	pci_write_config_byte(dev, 0x84, 0x00);
+	pci_read_config_byte(dev, 0x8A, &tmpbyte);
+	switch(tmpbyte) {
+		case 0x00:
+		case 0x01:
+			/* 133 clock attempt to force it on */
+			pci_write_config_byte(dev, 0x8A, tmpbyte|0x10);
+			pci_read_config_byte(dev, 0x8A, &tmpbyte);
+		case 0x30:
+		case 0x31:
+			/* if clocking is disabled */
+			/* 133 clock attempt to force it on */
+			pci_write_config_byte(dev, 0x8A, tmpbyte & ~0x20);
+			pci_read_config_byte(dev, 0x8A, &tmpbyte);
+		case 0x10:
+		case 0x11:
+		case 0x20:
+		case 0x21:
+			break;
+		default:
+			tmpbyte &= ~0x30;
+			tmpbyte |= 0x20;
+			pci_write_config_byte(dev, 0x8A, tmpbyte);
+			break;
+	}
+
+	pci_read_config_byte(dev, 0x8A, &tmpbyte);
+	pci_write_config_byte(dev, 0xA1, 0x72);
+	pci_write_config_word(dev, 0xA2, 0x328A);
+	pci_write_config_dword(dev, 0xA4, 0x62DD62DD);
+	pci_write_config_dword(dev, 0xA8, 0x43924392);
+	pci_write_config_dword(dev, 0xAC, 0x40094009);
+	pci_write_config_byte(dev, 0xB1, 0x72);
+	pci_write_config_word(dev, 0xB2, 0x328A);
+	pci_write_config_dword(dev, 0xB4, 0x62DD62DD);
+	pci_write_config_dword(dev, 0xB8, 0x43924392);
+	pci_write_config_dword(dev, 0xBC, 0x40094009);
+
+	pci_read_config_byte(dev, 0x8A, &tmpbyte);
+	proc_reports_siimage(dev, (tmpbyte>>=4), name);
+	return 0;
+}
+
+static void __init init_mmio_iops_siimage (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev	= hwif->pci_dev;
+	unsigned long addr	= (unsigned long) pci_get_drvdata(hwif->pci_dev);
+	u8 ch			= hwif->channel;
+//	u16 i			= 0;
+	hw_regs_t hw;
+
+	default_hwif_mmiops(hwif);
+	memset(&hw, 0, sizeof(hw_regs_t));
+
+#if 1
+#ifdef SIIMAGE_BUFFERED_TASKFILE
+	hw.io_ports[IDE_DATA_OFFSET]	= DEVADDR((ch) ? 0xD0 : 0x90);
+	hw.io_ports[IDE_ERROR_OFFSET]	= DEVADDR((ch) ? 0xD1 : 0x91);
+	hw.io_ports[IDE_NSECTOR_OFFSET]	= DEVADDR((ch) ? 0xD2 : 0x92);
+	hw.io_ports[IDE_SECTOR_OFFSET]	= DEVADDR((ch) ? 0xD3 : 0x93);
+	hw.io_ports[IDE_LCYL_OFFSET]	= DEVADDR((ch) ? 0xD4 : 0x94);
+	hw.io_ports[IDE_HCYL_OFFSET]	= DEVADDR((ch) ? 0xD5 : 0x95);
+	hw.io_ports[IDE_SELECT_OFFSET]	= DEVADDR((ch) ? 0xD6 : 0x96);
+	hw.io_ports[IDE_STATUS_OFFSET]	= DEVADDR((ch) ? 0xD7 : 0x97);
+	hw.io_ports[IDE_CONTROL_OFFSET]	= DEVADDR((ch) ? 0xDA : 0x9A);
+#else /* ! SIIMAGE_BUFFERED_TASKFILE */
+	hw.io_ports[IDE_DATA_OFFSET]	= DEVADDR((ch) ? 0xC0 : 0x80);
+	hw.io_ports[IDE_ERROR_OFFSET]	= DEVADDR((ch) ? 0xC1 : 0x81);
+	hw.io_ports[IDE_NSECTOR_OFFSET]	= DEVADDR((ch) ? 0xC2 : 0x82);
+	hw.io_ports[IDE_SECTOR_OFFSET]	= DEVADDR((ch) ? 0xC3 : 0x83);
+	hw.io_ports[IDE_LCYL_OFFSET]	= DEVADDR((ch) ? 0xC4 : 0x84);
+	hw.io_ports[IDE_HCYL_OFFSET]	= DEVADDR((ch) ? 0xC5 : 0x85);
+	hw.io_ports[IDE_SELECT_OFFSET]	= DEVADDR((ch) ? 0xC6 : 0x86);
+	hw.io_ports[IDE_STATUS_OFFSET]	= DEVADDR((ch) ? 0xC7 : 0x87);
+	hw.io_ports[IDE_CONTROL_OFFSET]	= DEVADDR((ch) ? 0xCA : 0x8A);
+#endif /* SIIMAGE_BUFFERED_TASKFILE */
+#else
+#ifdef SIIMAGE_BUFFERED_TASKFILE
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
+		hw.io_ports[i] = DEVADDR((ch) ? 0xD0 : 0x90)|(i);
+	hw.io_ports[IDE_CONTROL_OFFSET] = DEVADDR((ch) ? 0xDA : 0x9A);
+#else /* ! SIIMAGE_BUFFERED_TASKFILE */
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
+		hw.io_ports[i] = DEVADDR((ch) ? 0xC0 : 0x80)|(i);
+	hw.io_ports[IDE_CONTROL_OFFSET] = DEVADDR((ch) ? 0xCA : 0x8A);
+#endif /* SIIMAGE_BUFFERED_TASKFILE */
+#endif
+
+#if 0
+	printk(KERN_DEBUG "%s: ", hwif->name);
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
+		printk("0x%08x ", DEVADDR((ch) ? 0xC0 : 0x80)|(i));
+	printk("0x%08x ", DEVADDR((ch) ? 0xCA : 0x8A)|(i));
+#endif
+
+	hw.io_ports[IDE_IRQ_OFFSET]	= 0;
+
+        if (dev->device == PCI_DEVICE_ID_SII_3112) {
+		hw.sata_scr[SATA_STATUS_OFFSET]	= DEVADDR((ch) ? 0x184 : 0x104);
+		hw.sata_scr[SATA_ERROR_OFFSET]	= DEVADDR((ch) ? 0x188 : 0x108);
+		hw.sata_scr[SATA_CONTROL_OFFSET]= DEVADDR((ch) ? 0x180 : 0x100);
+		hw.sata_misc[SATA_MISC_OFFSET]	= DEVADDR((ch) ? 0x1C0 : 0x140);
+		hw.sata_misc[SATA_PHY_OFFSET]	= DEVADDR((ch) ? 0x1C4 : 0x144);
+		hw.sata_misc[SATA_IEN_OFFSET]	= DEVADDR((ch) ? 0x1C8 : 0x148);
+	}
+
+	hw.priv				= (void *) addr;
+//	hw.priv				= pci_get_drvdata(hwif->pci_dev);
+	hw.irq				= hwif->pci_dev->irq;
+
+	memcpy(&hwif->hw, &hw, sizeof(hw));
+	memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->hw.io_ports));
+
+	if (hwif->pci_dev->device == PCI_DEVICE_ID_SII_3112) {
+		memcpy(hwif->sata_scr, hwif->hw.sata_scr, sizeof(hwif->hw.sata_scr));
+		memcpy(hwif->sata_misc, hwif->hw.sata_misc, sizeof(hwif->hw.sata_misc));
+	}
+
+#ifdef SIIMAGE_BUFFERED_TASKFILE
+        hwif->addressing = 1;
+#endif /* SIIMAGE_BUFFERED_TASKFILE */
+	hwif->irq			= hw.irq;
+	hwif->hwif_data			= pci_get_drvdata(hwif->pci_dev);
+
+#ifdef SIIMAGE_LARGE_DMA
+	hwif->dma_base			= DEVADDR((ch) ? 0x18 : 0x10);
+	hwif->dma_base2			= DEVADDR((ch) ? 0x08 : 0x00);
+	hwif->dma_prdtable		= (hwif->dma_base2 + 4);
+#else /* ! SIIMAGE_LARGE_DMA */
+	hwif->dma_base			= DEVADDR((ch) ? 0x08 : 0x00);
+	hwif->dma_base2			= DEVADDR((ch) ? 0x18 : 0x10);
+#endif /* SIIMAGE_LARGE_DMA */
+	hwif->mmio			= 1;
+}
+
+static void __init init_iops_siimage (ide_hwif_t *hwif)
+{
+	struct pci_dev *dev	= hwif->pci_dev;
+	u32 class_rev		= 0;
+
+	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+	class_rev &= 0xff;
+
+	hwif->rqsize = 128;
+	if ((dev->device == PCI_DEVICE_ID_SII_3112) && (!(class_rev)))
+		hwif->rqsize = 16;
+
+	if (pci_get_drvdata(dev) == NULL)
+		return;
+	init_mmio_iops_siimage(hwif);
+}
+
+static unsigned int __init ata66_siimage (ide_hwif_t *hwif)
+{
+	if (pci_get_drvdata(hwif->pci_dev) == NULL) {
+		u8 ata66 = 0;
+		pci_read_config_byte(hwif->pci_dev, SELREG(0), &ata66);
+		return (ata66 & 0x01) ? 1 : 0;
+	}
+
+	return (hwif->INB(SELADDR(0)) & 0x01) ? 1 : 0;
+}
+
+static void __init init_hwif_siimage (ide_hwif_t *hwif)
+{
+	hwif->autodma = 0;
+	hwif->busproc   = &siimage_busproc;
+	hwif->resetproc = &siimage_reset;
+	hwif->speedproc = &siimage_tune_chipset;
+	hwif->tuneproc	= &siimage_tuneproc;
+	hwif->reset_poll = &siimage_reset_poll;
+	hwif->pre_reset = &siimage_pre_reset;
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->ultra_mask = 0x7f;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+	if (hwif->pci_dev->device != PCI_DEVICE_ID_SII_3112)
+		hwif->atapi_dma = 1;
+
+	hwif->ide_dma_check = &siimage_config_drive_for_dma;
+	if (!(hwif->udma_four))
+		hwif->udma_four = ata66_siimage(hwif);
+
+	if (hwif->mmio) {
+		hwif->ide_dma_count = &siimage_mmio_ide_dma_count;
+		hwif->ide_dma_test_irq = &siimage_mmio_ide_dma_test_irq;
+		hwif->ide_dma_verbose = &siimage_mmio_ide_dma_verbose;
+	} else {
+		hwif->ide_dma_test_irq = & siimage_io_ide_dma_test_irq;
+	}
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+static void __init init_dma_siimage (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+
+static int __devinit siimage_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &siimage_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id siimage_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_680,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "SiI IDE",
+	.id_table	= siimage_pci_tbl,
+	.probe		= siimage_init_one,
+};
+
+static int siimage_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void siimage_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(siimage_ide_init);
+module_exit(siimage_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for SiI IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/siimage.h linux-2.4.21-pre6/drivers/ide/pci/siimage.h
--- linux-2.4.20/drivers/ide/pci/siimage.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/siimage.h	2003-03-26 23:48:57.000000000 +0000
@@ -0,0 +1,96 @@
+#ifndef SIIMAGE_H
+#define SIIMAGE_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+
+#define DISPLAY_SIIMAGE_TIMINGS
+
+#undef SIIMAGE_VIRTUAL_DMAPIO
+#undef SIIMAGE_BUFFERED_TASKFILE
+#undef SIIMAGE_LARGE_DMA
+
+#if 0
+typedef struct ide_io_ops_s siimage_iops {
+
+}
+#endif
+
+#define SII_DEBUG 0
+
+#if SII_DEBUG
+#define siiprintk(x...)	printk(x)
+#else
+#define siiprintk(x...)
+#endif
+
+#define ADJREG(B,R)	((B)|(R)|((hwif->channel)<<(4+(2*(hwif->mmio)))))
+#define SELREG(R)	ADJREG((0xA0),(R))
+#define SELADDR(R)	((((unsigned long)hwif->hwif_data)*(hwif->mmio))|SELREG((R)))
+#define HWIFADDR(R)	((((unsigned long)hwif->hwif_data)*(hwif->mmio))|(R))
+#define DEVADDR(R)	(((unsigned long) pci_get_drvdata(dev))|(R))
+
+
+#if defined(DISPLAY_SIIMAGE_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static char * print_siimage_get_info(char *, struct pci_dev *, int);
+static int siimage_get_info(char *, char **, off_t, int);
+
+static u8 siimage_proc;
+
+static ide_pci_host_proc_t siimage_procs[] __initdata = {
+	{
+		.name		= "siimage",
+		.set		= 1,
+		.get_info	= siimage_get_info,
+		.parent		= NULL,
+	},
+};
+#endif /* DISPLAY_SIIMAGE_TIMINGS && CONFIG_PROC_FS */	
+
+static unsigned int init_chipset_siimage(struct pci_dev *, const char *);
+static void init_iops_siimage(ide_hwif_t *);
+static void init_hwif_siimage(ide_hwif_t *);
+static void init_dma_siimage(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t siimage_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_CMD,
+		.device		= PCI_DEVICE_ID_SII_680,
+		.name		= "SiI680",
+		.init_chipset	= init_chipset_siimage,
+		.init_iops	= init_iops_siimage,
+		.init_hwif	= init_hwif_siimage,
+		.init_dma	= init_dma_siimage,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 1 */
+		.vendor		= PCI_VENDOR_ID_CMD,
+		.device		= PCI_DEVICE_ID_SII_3112,
+		.name		= "SiI3112 Serial ATA",
+		.init_chipset	= init_chipset_siimage,
+		.init_iops	= init_iops_siimage,
+		.init_hwif	= init_hwif_siimage,
+		.init_dma	= init_dma_siimage,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* SIIMAGE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/sis5513.c linux-2.4.21-pre6/drivers/ide/pci/sis5513.c
--- linux-2.4.20/drivers/ide/pci/sis5513.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/sis5513.c	2003-03-26 23:49:29.000000000 +0000
@@ -0,0 +1,1103 @@
+/*
+ * linux/drivers/ide/pci/sis5513.c		Version 0.14ac	Sept 11, 2002
+ *
+ * Copyright (C) 1999-2000	Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 2002		Lionel Bouton <Lionel.Bouton@inet6.fr>, Maintainer
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ *
+ * Thanks :
+ *
+ * SiS Taiwan		: for direct support and hardware.
+ * Daniela Engert	: for initial ATA100 advices and numerous others.
+ * John Fremlin, Manfred Spraul, Dave Morgan, Peter Kjellerstedt	:
+ *			  for checking code correctness, providing patches.
+ *
+ *
+ * Original tests and design on the SiS620/5513 chipset.
+ * ATA100 tests and design on the SiS735/5513 chipset.
+ * ATA16/33 support from specs
+ * ATA133 support for SiS961/962 by L.C. Chang <lcchang@sis.com.tw>
+ *
+ * Documentation:
+ *	SiS chipset documentation available under NDA to companies not
+ *	individuals only.
+ */
+
+/*
+ * Notes/Special cases:
+ * - SiS5513 derivatives usually have the same PCI IDE register layout when
+ *  supporting the same UDMA modes.
+ * - There are exceptions :
+ *  . SiS730 and SiS550 use the same layout than ATA_66 chipsets but support
+ *   ATA_100
+ *  . ATA_133 capable chipsets mark a shift in SiS chipset designs : previously
+ *   south and northbridge were integrated, making IDE (a southbridge function)
+ *   capabilities easily deduced from the northbridge PCI id. With ATA_133,
+ *   chipsets started to be split in the usual north/south bridges chips
+ *   -> the driver needs to detect the correct southbridge when faced to newest
+ *   northbridges.
+ *  . On ATA133 capable chipsets when bit 30 of dword at 0x54 is 1 the
+ *   configuration space is moved from 0x40 to 0x70.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+#include "sis5513.h"
+
+/* When DEBUG is defined it outputs initial PCI config register
+   values and changes made to them by the driver */
+// #define DEBUG
+/* When BROKEN_LEVEL is defined it limits the DMA mode
+   at boot time to its value */
+// #define BROKEN_LEVEL XFER_SW_DMA_0
+
+/* Miscellaneaous flags */
+#define SIS5513_LATENCY		0x01
+
+/* registers layout and init values are chipset family dependant */
+/* 1/ define families */
+#define ATA_00		0x00
+#define ATA_16		0x01
+#define ATA_33		0x02
+#define ATA_66		0x03
+#define ATA_100a	0x04 // SiS730 is ATA100 with ATA66 layout
+#define ATA_100		0x05
+#define ATA_133a	0x06 // SiS961b with 133 support
+#define ATA_133		0x07 // SiS962
+/* 2/ variable holding the controller chipset family value */
+static u8 chipset_family;
+
+
+/*
+ * Debug code: following IDE config registers' changes
+ */
+#ifdef DEBUG
+/* Copy of IDE Config registers fewer will be used
+ * Some odd chipsets hang if unused registers are accessed
+ * -> We only access them in #DEBUG code (then we'll see if SiS did
+ * it right from day one) */
+static u8 ide_regs_copy[0xff];
+
+/* Read config registers, print differences from previous read */
+static void sis5513_load_verify_registers(struct pci_dev* dev, char* info) {
+	int i;
+	u8 reg_val;
+	u8 changed=0;
+
+	printk("SIS5513: %s, changed registers:\n", info);
+	for(i=0; i<=0xff; i++) {
+		pci_read_config_byte(dev, i, &reg_val);
+		if (reg_val != ide_regs_copy[i]) {
+			printk("%02x: %02x -> %02x\n",
+			       i, ide_regs_copy[i], reg_val);
+			ide_regs_copy[i]=reg_val;
+			changed=1;
+		}
+	}
+
+	if (!changed) {
+		printk("none\n");
+	}
+}
+
+/* Load config registers, no printing */
+static void sis5513_load_registers(struct pci_dev* dev) {
+	int i;
+
+	for(i=0; i<=0xff; i++) {
+		pci_read_config_byte(dev, i, &(ide_regs_copy[i]));
+	}
+}
+
+/* Print config space registers a la "lspci -vxxx" */
+static void sis5513_print_registers(struct pci_dev* dev, char* marker) {
+	int i,j;
+
+	sis5513_load_registers(dev);
+	printk("SIS5513 %s\n", marker);
+
+	for(i=0; i<=0xf; i++) {
+		printk("SIS5513 dump: %d" "0:", i);
+		for(j=0; j<=0xf; j++) {
+			printk(" %02x", ide_regs_copy[(i<<16)+j]);
+		}
+		printk("\n");
+	}
+}
+#endif
+
+
+/*
+ * Devices supported
+ */
+static const struct {
+	const char *name;
+	u16 host_id;
+	u8 chipset_family;
+	u8 flags;
+} SiSHostChipInfo[] = {
+	{ "SiS752",	PCI_DEVICE_ID_SI_752,	ATA_133,	0 },
+	{ "SiS751",	PCI_DEVICE_ID_SI_751,	ATA_133,	0 },
+	{ "SiS750",	PCI_DEVICE_ID_SI_750,	ATA_133,	0 },
+	{ "SiS748",	PCI_DEVICE_ID_SI_748,	ATA_133,	0 },
+	{ "SiS746",	PCI_DEVICE_ID_SI_746,	ATA_133,	0 },
+	{ "SiS745",	PCI_DEVICE_ID_SI_745,	ATA_133,	0 },
+	{ "SiS740",	PCI_DEVICE_ID_SI_740,	ATA_100,	0 },
+	{ "SiS735",	PCI_DEVICE_ID_SI_735,	ATA_100,	SIS5513_LATENCY },
+	{ "SiS730",	PCI_DEVICE_ID_SI_730,	ATA_100a,	SIS5513_LATENCY },
+	{ "SiS652",	PCI_DEVICE_ID_SI_652,	ATA_133,	0 },
+	{ "SiS651",	PCI_DEVICE_ID_SI_651,	ATA_133,	0 },
+	{ "SiS650",	PCI_DEVICE_ID_SI_650,	ATA_133,	0 },
+	{ "SiS648",	PCI_DEVICE_ID_SI_648,	ATA_133,	0 },
+	{ "SiS646",	PCI_DEVICE_ID_SI_646,	ATA_133,	0 },
+	{ "SiS645",	PCI_DEVICE_ID_SI_645,	ATA_133,	0 },
+	{ "SiS635",	PCI_DEVICE_ID_SI_635,	ATA_100,	SIS5513_LATENCY },
+	{ "SiS640",	PCI_DEVICE_ID_SI_640,	ATA_66,		SIS5513_LATENCY },
+	{ "SiS630",	PCI_DEVICE_ID_SI_630,	ATA_66,		SIS5513_LATENCY },
+	{ "SiS620",	PCI_DEVICE_ID_SI_620,	ATA_66,		SIS5513_LATENCY },
+	{ "SiS550",	PCI_DEVICE_ID_SI_550,	ATA_100a,	0},
+	{ "SiS540",	PCI_DEVICE_ID_SI_540,	ATA_66,		0},
+	{ "SiS530",	PCI_DEVICE_ID_SI_530,	ATA_66,		0},
+	{ "SiS5600",	PCI_DEVICE_ID_SI_5600,	ATA_33,		0},
+	{ "SiS5598",	PCI_DEVICE_ID_SI_5598,	ATA_33,		0},
+	{ "SiS5597",	PCI_DEVICE_ID_SI_5597,	ATA_33,		0},
+	{ "SiS5591",	PCI_DEVICE_ID_SI_5591,	ATA_33,		0},
+	{ "SiS5513",	PCI_DEVICE_ID_SI_5513,	ATA_16,		0},
+	{ "SiS5511",	PCI_DEVICE_ID_SI_5511,	ATA_16,		0},
+};
+
+/* Cycle time bits and values vary accross chip dma capabilities
+   These three arrays hold the register layout and the values to set.
+   Indexed by chipset_family and (dma_mode - XFER_UDMA_0) */
+
+/* {ATA_00, ATA_16, ATA_33, ATA_66, ATA_100a, ATA_100, ATA_133} */
+static u8 cycle_time_offset[] = {0,0,5,4,4,0,0};
+static u8 cycle_time_range[] = {0,0,2,3,3,4,4};
+static u8 cycle_time_value[][XFER_UDMA_6 - XFER_UDMA_0 + 1] = {
+	{0,0,0,0,0,0,0}, /* no udma */
+	{0,0,0,0,0,0,0}, /* no udma */
+	{3,2,1,0,0,0,0}, /* ATA_33 */
+	{7,5,3,2,1,0,0}, /* ATA_66 */
+	{7,5,3,2,1,0,0}, /* ATA_100a (730 specific), differences are on cycle_time range and offset */
+	{11,7,5,4,2,1,0}, /* ATA_100 */
+	{15,10,7,5,3,2,1}, /* ATA_133a (earliest 691 southbridges) */
+	{15,10,7,5,3,2,1}, /* ATA_133 */
+};
+/* CRC Valid Setup Time vary accross IDE clock setting 33/66/100/133
+   See SiS962 data sheet for more detail */
+static u8 cvs_time_value[][XFER_UDMA_6 - XFER_UDMA_0 + 1] = {
+	{0,0,0,0,0,0,0}, /* no udma */
+	{0,0,0,0,0,0,0}, /* no udma */
+	{2,1,1,0,0,0,0},
+	{4,3,2,1,0,0,0},
+	{4,3,2,1,0,0,0},
+	{6,4,3,1,1,1,0},
+	{9,6,4,2,2,2,2},
+	{9,6,4,2,2,2,2},
+};
+/* Initialize time, Active time, Recovery time vary accross
+   IDE clock settings. These 3 arrays hold the register value
+   for PIO0/1/2/3/4 and DMA0/1/2 mode in order */
+static u8 ini_time_value[][8] = {
+	{0,0,0,0,0,0,0,0},
+	{0,0,0,0,0,0,0,0},
+	{2,1,0,0,0,1,0,0},
+	{4,3,1,1,1,3,1,1},
+	{4,3,1,1,1,3,1,1},
+	{6,4,2,2,2,4,2,2},
+	{9,6,3,3,3,6,3,3},
+	{9,6,3,3,3,6,3,3},
+};
+static u8 act_time_value[][8] = {
+	{0,0,0,0,0,0,0,0},
+	{0,0,0,0,0,0,0,0},
+	{9,9,9,2,2,7,2,2},
+	{19,19,19,5,4,14,5,4},
+	{19,19,19,5,4,14,5,4},
+	{28,28,28,7,6,21,7,6},
+	{38,38,38,10,9,28,10,9},
+	{38,38,38,10,9,28,10,9},
+};
+static u8 rco_time_value[][8] = {
+	{0,0,0,0,0,0,0,0},
+	{0,0,0,0,0,0,0,0},
+	{9,2,0,2,0,7,1,1},
+	{19,5,1,5,2,16,3,2},
+	{19,5,1,5,2,16,3,2},
+	{30,9,3,9,4,25,6,4},
+	{40,12,4,12,5,34,12,5},
+	{40,12,4,12,5,34,12,5},
+};
+
+static struct pci_dev *host_dev = NULL;
+
+/*
+ * Printing configuration
+ */
+/* Used for chipset type printing at boot time */
+static char* chipset_capability[] = {
+	"ATA", "ATA 16",
+	"ATA 33", "ATA 66",
+	"ATA 100", "ATA 100",
+	"ATA 133", "ATA 133"
+};
+
+#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 sis_proc = 0;
+
+static struct pci_dev *bmide_dev;
+
+static char* cable_type[] = {
+	"80 pins",
+	"40 pins"
+};
+
+static char* recovery_time[] ={
+	"12 PCICLK", "1 PCICLK",
+	"2 PCICLK", "3 PCICLK",
+	"4 PCICLK", "5 PCICLCK",
+	"6 PCICLK", "7 PCICLCK",
+	"8 PCICLK", "9 PCICLCK",
+	"10 PCICLK", "11 PCICLK",
+	"13 PCICLK", "14 PCICLK",
+	"15 PCICLK", "15 PCICLK"
+};
+
+static char* active_time[] = {
+	"8 PCICLK", "1 PCICLCK",
+	"2 PCICLK", "3 PCICLK",
+	"4 PCICLK", "5 PCICLK",
+	"6 PCICLK", "12 PCICLK"
+};
+
+static char* cycle_time[] = {
+	"Reserved", "2 CLK",
+	"3 CLK", "4 CLK",
+	"5 CLK", "6 CLK",
+	"7 CLK", "8 CLK",
+	"9 CLK", "10 CLK",
+	"11 CLK", "12 CLK",
+	"13 CLK", "14 CLK",
+	"15 CLK", "16 CLK"
+};
+
+/* Generic add master or slave info function */
+static char* get_drives_info (char *buffer, u8 pos)
+{
+	u8 reg00, reg01, reg10, reg11; /* timing registers */
+	u32 regdw0, regdw1;
+	char* p = buffer;
+
+/* Postwrite/Prefetch */
+	if (chipset_family < ATA_133) {
+		pci_read_config_byte(bmide_dev, 0x4b, &reg00);
+		p += sprintf(p, "Drive %d:        Postwrite %s \t \t Postwrite %s\n",
+			     pos, (reg00 & (0x10 << pos)) ? "Enabled" : "Disabled",
+			     (reg00 & (0x40 << pos)) ? "Enabled" : "Disabled");
+		p += sprintf(p, "                Prefetch  %s \t \t Prefetch  %s\n",
+			     (reg00 & (0x01 << pos)) ? "Enabled" : "Disabled",
+			     (reg00 & (0x04 << pos)) ? "Enabled" : "Disabled");
+		pci_read_config_byte(bmide_dev, 0x40+2*pos, &reg00);
+		pci_read_config_byte(bmide_dev, 0x41+2*pos, &reg01);
+		pci_read_config_byte(bmide_dev, 0x44+2*pos, &reg10);
+		pci_read_config_byte(bmide_dev, 0x45+2*pos, &reg11);
+	} else {
+		u32 reg54h;
+		u8 drive_pci = 0x40;
+		pci_read_config_dword(bmide_dev, 0x54, &reg54h);
+		if (reg54h & 0x40000000) {
+			// Configuration space remapped to 0x70
+			drive_pci = 0x70;
+		}
+		pci_read_config_dword(bmide_dev, (unsigned long)drive_pci+8*pos, &regdw0);
+		pci_read_config_dword(bmide_dev, (unsigned long)drive_pci+8*pos+4, &regdw1);
+		p += sprintf(p, "Drive %d:\n", pos);
+	}
+
+
+/* UDMA */
+	if (chipset_family >= ATA_133) {
+		p += sprintf(p, "                UDMA %s \t \t \t UDMA %s\n",
+			     (regdw0 & 0x04) ? "Enabled" : "Disabled",
+			     (regdw1 & 0x04) ? "Enabled" : "Disabled");
+		p += sprintf(p, "                UDMA Cycle Time    %s \t UDMA Cycle Time    %s\n",
+			     cycle_time[(regdw0 & 0xF0) >> 4],
+			     cycle_time[(regdw1 & 0xF0) >> 4]);
+	} else if (chipset_family >= ATA_33) {
+		p += sprintf(p, "                UDMA %s \t \t \t UDMA %s\n",
+			     (reg01 & 0x80) ? "Enabled" : "Disabled",
+			     (reg11 & 0x80) ? "Enabled" : "Disabled");
+
+		p += sprintf(p, "                UDMA Cycle Time    ");
+		switch(chipset_family) {
+			case ATA_33:	p += sprintf(p, cycle_time[(reg01 & 0x60) >> 5]); break;
+			case ATA_66:
+			case ATA_100a:	p += sprintf(p, cycle_time[(reg01 & 0x70) >> 4]); break;
+			case ATA_100:
+			case ATA_133a:	p += sprintf(p, cycle_time[reg01 & 0x0F]); break;
+			case ATA_133:
+			default:	p += sprintf(p, "133+ ?"); break;
+		}
+		p += sprintf(p, " \t UDMA Cycle Time    ");
+		switch(chipset_family) {
+			case ATA_33:	p += sprintf(p, cycle_time[(reg11 & 0x60) >> 5]); break;
+			case ATA_66:
+			case ATA_100a:	p += sprintf(p, cycle_time[(reg11 & 0x70) >> 4]); break;
+			case ATA_100:
+			case ATA_133a:  p += sprintf(p, cycle_time[reg11 & 0x0F]); break;
+			case ATA_133:
+			default:	p += sprintf(p, "133+ ?"); break;
+		}
+		p += sprintf(p, "\n");
+	}
+
+/* Data Active */
+	p += sprintf(p, "                Data Active Time   ");
+	switch(chipset_family) {
+		case ATA_00:
+		case ATA_16: /* confirmed */
+		case ATA_33:
+		case ATA_66:
+		case ATA_100a: p += sprintf(p, active_time[reg01 & 0x07]); break;
+		case ATA_100:
+		case ATA_133a: p += sprintf(p, active_time[(reg00 & 0x70) >> 4]); break;
+		case ATA_133:
+		default: p += sprintf(p, "133+ ?"); break;
+	}
+	p += sprintf(p, " \t Data Active Time   ");
+	switch(chipset_family) {
+		case ATA_00:
+		case ATA_16:
+		case ATA_33:
+		case ATA_66:
+		case ATA_100a: p += sprintf(p, active_time[reg11 & 0x07]); break;
+		case ATA_100:
+		case ATA_133a: p += sprintf(p, active_time[(reg10 & 0x70) >> 4]); break;
+		case ATA_133:
+		default: p += sprintf(p, "133+ ?"); break;
+	}
+	p += sprintf(p, "\n");
+
+/* Data Recovery */
+	/* warning: may need (reg&0x07) for pre ATA66 chips */
+	if (chipset_family < ATA_133) {
+		p += sprintf(p, "                Data Recovery Time %s \t Data Recovery Time %s\n",
+			     recovery_time[reg00 & 0x0f], recovery_time[reg10 & 0x0f]);
+	}
+
+	return p;
+}
+
+static char* get_masters_info(char* buffer)
+{
+	return get_drives_info(buffer, 0);
+}
+
+static char* get_slaves_info(char* buffer)
+{
+	return get_drives_info(buffer, 1);
+}
+
+/* Main get_info, called on /proc/ide/sis reads */
+static int sis_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	u8 reg;
+	u16 reg2, reg3;
+
+	p += sprintf(p, "\nSiS 5513 ");
+	switch(chipset_family) {
+		case ATA_00: p += sprintf(p, "Unknown???"); break;
+		case ATA_16: p += sprintf(p, "DMA 16"); break;
+		case ATA_33: p += sprintf(p, "Ultra 33"); break;
+		case ATA_66: p += sprintf(p, "Ultra 66"); break;
+		case ATA_100a:
+		case ATA_100: p += sprintf(p, "Ultra 100"); break;
+		case ATA_133a:
+		case ATA_133: p += sprintf(p, "Ultra 133"); break;
+		default: p+= sprintf(p, "Unknown???"); break;
+	}
+	p += sprintf(p, " chipset\n");
+	p += sprintf(p, "--------------- Primary Channel "
+		     "---------------- Secondary Channel "
+		     "-------------\n");
+
+/* Status */
+	pci_read_config_byte(bmide_dev, 0x4a, &reg);
+	if (chipset_family == ATA_133) {
+		pci_read_config_word(bmide_dev, 0x50, &reg2);
+		pci_read_config_word(bmide_dev, 0x52, &reg3);
+	}
+	p += sprintf(p, "Channel Status: ");
+	if (chipset_family < ATA_66) {
+		p += sprintf(p, "%s \t \t \t \t %s\n",
+			     (reg & 0x04) ? "On" : "Off",
+			     (reg & 0x02) ? "On" : "Off");
+	} else if (chipset_family < ATA_133) {
+		p += sprintf(p, "%s \t \t \t \t %s \n",
+			     (reg & 0x02) ? "On" : "Off",
+			     (reg & 0x04) ? "On" : "Off");
+	} else { /* ATA_133 */
+		p += sprintf(p, "%s \t \t \t \t %s \n",
+			     (reg2 & 0x02) ? "On" : "Off",
+			     (reg3 & 0x02) ? "On" : "Off");
+	}
+
+/* Operation Mode */
+	pci_read_config_byte(bmide_dev, 0x09, &reg);
+	p += sprintf(p, "Operation Mode: %s \t \t \t %s \n",
+		     (reg & 0x01) ? "Native" : "Compatible",
+		     (reg & 0x04) ? "Native" : "Compatible");
+
+/* 80-pin cable ? */
+	if (chipset_family >= ATA_133) {
+		p += sprintf(p, "Cable Type:     %s \t \t \t %s\n",
+			     (reg2 & 0x01) ? cable_type[1] : cable_type[0],
+			     (reg3 & 0x01) ? cable_type[1] : cable_type[0]);
+	} else if (chipset_family > ATA_33) {
+		pci_read_config_byte(bmide_dev, 0x48, &reg);
+		p += sprintf(p, "Cable Type:     %s \t \t \t %s\n",
+			     (reg & 0x10) ? cable_type[1] : cable_type[0],
+			     (reg & 0x20) ? cable_type[1] : cable_type[0]);
+	}
+
+/* Prefetch Count */
+	if (chipset_family < ATA_133) {
+		pci_read_config_word(bmide_dev, 0x4c, &reg2);
+		pci_read_config_word(bmide_dev, 0x4e, &reg3);
+		p += sprintf(p, "Prefetch Count: %d \t \t \t \t %d\n",
+			     reg2, reg3);
+	}
+
+	p = get_masters_info(p);
+	p = get_slaves_info(p);
+
+	return p-buffer;
+}
+#endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static u8 sis5513_ratemask (ide_drive_t *drive)
+{
+#if 0
+	u8 rates[] = { 0, 0, 1, 2, 3, 3, 4, 4 };
+	u8 mode = rates[chipset_family];
+#else
+	u8 mode;
+
+	switch(chipset_family) {
+		case ATA_133:
+		case ATA_133a:
+			mode = 4;
+			break;
+		case ATA_100:
+		case ATA_100a:
+			mode = 3;
+			break;
+		case ATA_66:
+			mode = 2;
+			break;
+		case ATA_33:
+			return 1;
+		case ATA_16:
+                case ATA_00:	
+		default:
+			return 0;
+	}
+#endif
+	if (!eighty_ninty_three(drive))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+/*
+ * Configuration functions
+ */
+/* Enables per-drive prefetch and postwrite */
+static void config_drive_art_rwp (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+
+	u8 reg4bh		= 0;
+	u8 rw_prefetch		= (0x11 << drive->dn);
+
+#ifdef DEBUG
+	printk("SIS5513: config_drive_art_rwp, drive %d\n", drive->dn);
+	sis5513_load_verify_registers(dev, "config_drive_art_rwp start");
+#endif
+
+	if (drive->media != ide_disk)
+		return;
+	pci_read_config_byte(dev, 0x4b, &reg4bh);
+
+	if ((reg4bh & rw_prefetch) != rw_prefetch)
+		pci_write_config_byte(dev, 0x4b, reg4bh|rw_prefetch);
+#ifdef DEBUG
+	sis5513_load_verify_registers(dev, "config_drive_art_rwp end");
+#endif
+}
+
+
+/* Set per-drive active and recovery time */
+static void config_art_rwp_pio (ide_drive_t *drive, u8 pio)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+
+	u8			timing, drive_pci, test1, test2;
+
+	u16 eide_pio_timing[6] = {600, 390, 240, 180, 120, 90};
+	u16 xfer_pio = drive->id->eide_pio_modes;
+
+#ifdef DEBUG
+	sis5513_load_verify_registers(dev, "config_drive_art_rwp_pio start");
+#endif
+
+	config_drive_art_rwp(drive);
+	pio = ide_get_best_pio_mode(drive, 255, pio, NULL);
+
+	if (xfer_pio> 4)
+		xfer_pio = 0;
+
+	if (drive->id->eide_pio_iordy > 0) {
+		for (xfer_pio = 5;
+			(xfer_pio > 0) &&
+			(drive->id->eide_pio_iordy > eide_pio_timing[xfer_pio]);
+			xfer_pio--);
+	} else {
+		xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
+			   (drive->id->eide_pio_modes & 2) ? 0x04 :
+			   (drive->id->eide_pio_modes & 1) ? 0x03 : xfer_pio;
+	}
+
+	timing = (xfer_pio >= pio) ? xfer_pio : pio;
+
+#ifdef DEBUG
+	printk("SIS5513: config_drive_art_rwp_pio, "
+		"drive %d, pio %d, timing %d\n",
+	       drive->dn, pio, timing);
+#endif
+
+	/* In pre ATA_133 case, drives sit at 0x40 + 4*drive->dn */
+	drive_pci = 0x40;
+	/* In SiS962 case drives sit at (0x40 or 0x70) + 8*drive->dn) */
+	if (chipset_family >= ATA_133) {
+		u32 reg54h;
+		pci_read_config_dword(dev, 0x54, &reg54h);
+		if (reg54h & 0x40000000) drive_pci = 0x70;
+		drive_pci += ((drive->dn)*0x4);
+	} else {
+		drive_pci += ((drive->dn)*0x2);
+	}
+
+	/* register layout changed with newer ATA100 chips */
+	if (chipset_family < ATA_100) {
+		pci_read_config_byte(dev, drive_pci, &test1);
+		pci_read_config_byte(dev, drive_pci+1, &test2);
+
+		/* Clear active and recovery timings */
+		test1 &= ~0x0F;
+		test2 &= ~0x07;
+
+		switch(timing) {
+			case 4:		test1 |= 0x01; test2 |= 0x03; break;
+			case 3:		test1 |= 0x03; test2 |= 0x03; break;
+			case 2:		test1 |= 0x04; test2 |= 0x04; break;
+			case 1:		test1 |= 0x07; test2 |= 0x06; break;
+			default:	break;
+		}
+		pci_write_config_byte(dev, drive_pci, test1);
+		pci_write_config_byte(dev, drive_pci+1, test2);
+	} else if (chipset_family < ATA_133) {
+		switch(timing) { /*		active  recovery
+						  v     v */
+			case 4:		test1 = 0x30|0x01; break;
+			case 3:		test1 = 0x30|0x03; break;
+			case 2:		test1 = 0x40|0x04; break;
+			case 1:		test1 = 0x60|0x07; break;
+			default:	break;
+		}
+		pci_write_config_byte(dev, drive_pci, test1);
+	} else { /* ATA_133 */
+		u32 test3;
+		pci_read_config_dword(dev, drive_pci, &test3);
+		test3 &= 0xc0c00fff;
+		if (test3 & 0x08) {
+			test3 |= (unsigned long)ini_time_value[ATA_133-ATA_00][timing] << 12;
+			test3 |= (unsigned long)act_time_value[ATA_133-ATA_00][timing] << 16;
+			test3 |= (unsigned long)rco_time_value[ATA_133-ATA_00][timing] << 24;
+		} else {
+			test3 |= (unsigned long)ini_time_value[ATA_100-ATA_00][timing] << 12;
+			test3 |= (unsigned long)act_time_value[ATA_100-ATA_00][timing] << 16;
+			test3 |= (unsigned long)rco_time_value[ATA_100-ATA_00][timing] << 24;
+		}
+		pci_write_config_dword(dev, drive_pci, test3);
+	}
+
+#ifdef DEBUG
+	sis5513_load_verify_registers(dev, "config_drive_art_rwp_pio start");
+#endif
+}
+
+static int config_chipset_for_pio (ide_drive_t *drive, u8 pio)
+{
+#if 0
+	config_art_rwp_pio(drive, pio);
+	return ide_config_drive_speed(drive, (XFER_PIO_0 + pio));
+#else
+	u8 speed;
+
+	switch(pio) {
+		case 4:		speed = XFER_PIO_4; break;
+		case 3:		speed = XFER_PIO_3; break;
+		case 2:		speed = XFER_PIO_2; break;
+		case 1:		speed = XFER_PIO_1; break;
+		default:	speed = XFER_PIO_0; break;
+	}
+
+	config_art_rwp_pio(drive, pio);
+	return ide_config_drive_speed(drive, speed);
+#endif
+}
+
+static int sis5513_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+
+	u8 drive_pci, reg, speed;
+	u32 regdw;
+
+#ifdef DEBUG
+	sis5513_load_verify_registers(dev, "sis5513_tune_chipset start");
+#endif
+
+#ifdef BROKEN_LEVEL
+#ifdef DEBUG
+	printk("SIS5513: BROKEN_LEVEL activated, speed=%d -> speed=%d\n", xferspeed, BROKEN_LEVEL);
+#endif
+	if (xferspeed > BROKEN_LEVEL) xferspeed = BROKEN_LEVEL;
+#endif
+
+	speed = ide_rate_filter(sis5513_ratemask(drive), xferspeed);
+
+#ifdef DEBUG
+	printk("SIS5513: sis5513_tune_chipset, drive %d, speed %d\n",
+	       drive->dn, xferspeed);
+#endif
+
+	/* See config_art_rwp_pio for drive pci config registers */
+	drive_pci = 0x40;
+	if (chipset_family >= ATA_133) {
+		u32 reg54h;
+		pci_read_config_dword(dev, 0x54, &reg54h);
+		if (reg54h & 0x40000000) drive_pci = 0x70;
+		drive_pci += ((drive->dn)*0x4);
+		pci_read_config_dword(dev, (unsigned long)drive_pci, &regdw);
+		/* Disable UDMA bit for non UDMA modes on UDMA chips */
+		if (speed < XFER_UDMA_0) {
+			regdw &= 0xfffffffb;
+			pci_write_config_dword(dev, (unsigned long)drive_pci, regdw);
+		}
+	
+	} else {
+		drive_pci += ((drive->dn)*0x2);
+		pci_read_config_byte(dev, drive_pci+1, &reg);
+		/* Disable UDMA bit for non UDMA modes on UDMA chips */
+		if ((speed < XFER_UDMA_0) && (chipset_family > ATA_16)) {
+			reg &= 0x7F;
+			pci_write_config_byte(dev, drive_pci+1, reg);
+		}
+	}
+
+	/* Config chip for mode */
+	switch(speed) {
+		case XFER_UDMA_6:
+		case XFER_UDMA_5:
+		case XFER_UDMA_4:
+		case XFER_UDMA_3:
+		case XFER_UDMA_2:
+		case XFER_UDMA_1:
+		case XFER_UDMA_0:
+			if (chipset_family >= ATA_133) {
+				regdw |= 0x04;
+				regdw &= 0xfffff00f;
+				/* check if ATA133 enable */
+				if (regdw & 0x08) {
+					regdw |= (unsigned long)cycle_time_value[ATA_133-ATA_00][speed-XFER_UDMA_0] << 4;
+					regdw |= (unsigned long)cvs_time_value[ATA_133-ATA_00][speed-XFER_UDMA_0] << 8;
+				} else {
+				/* if ATA133 disable, we should not set speed above UDMA5 */
+					if (speed > XFER_UDMA_5)
+						speed = XFER_UDMA_5;
+					regdw |= (unsigned long)cycle_time_value[ATA_100-ATA_00][speed-XFER_UDMA_0] << 4;
+					regdw |= (unsigned long)cvs_time_value[ATA_100-ATA_00][speed-XFER_UDMA_0] << 8;
+				}
+				pci_write_config_dword(dev, (unsigned long)drive_pci, regdw);
+			} else {
+				/* Force the UDMA bit on if we want to use UDMA */
+				reg |= 0x80;
+				/* clean reg cycle time bits */
+				reg &= ~((0xFF >> (8 - cycle_time_range[chipset_family]))
+					 << cycle_time_offset[chipset_family]);
+				/* set reg cycle time bits */
+				reg |= cycle_time_value[chipset_family-ATA_00][speed-XFER_UDMA_0]
+					<< cycle_time_offset[chipset_family];
+				pci_write_config_byte(dev, drive_pci+1, reg);
+			}
+			break;
+		case XFER_MW_DMA_2:
+		case XFER_MW_DMA_1:
+		case XFER_MW_DMA_0:
+		case XFER_SW_DMA_2:
+		case XFER_SW_DMA_1:
+		case XFER_SW_DMA_0:
+			break;
+		case XFER_PIO_4: return((int) config_chipset_for_pio(drive, 4));
+		case XFER_PIO_3: return((int) config_chipset_for_pio(drive, 3));
+		case XFER_PIO_2: return((int) config_chipset_for_pio(drive, 2));
+		case XFER_PIO_1: return((int) config_chipset_for_pio(drive, 1));
+		case XFER_PIO_0:
+		default:	 return((int) config_chipset_for_pio(drive, 0));	
+	}
+#ifdef DEBUG
+	sis5513_load_verify_registers(dev, "sis5513_tune_chipset end");
+#endif
+	return ((int) ide_config_drive_speed(drive, speed));
+}
+
+static void sis5513_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	(void) config_chipset_for_pio(drive, pio);
+}
+
+/*
+ * ((id->hw_config & 0x4000|0x2000) && (HWIF(drive)->udma_four))
+ */
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+	u8 speed	= ide_dma_speed(drive, sis5513_ratemask(drive));
+
+#ifdef DEBUG
+	printk("SIS5513: config_chipset_for_dma, drive %d, ultra %x\n",
+	       drive->dn, drive->id->dma_ultra);
+#endif
+
+	if (!(speed))
+		return 0;
+
+	sis5513_tune_chipset(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static int sis5513_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	drive->init_speed = 0;
+
+	if (id && (id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = config_chipset_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!config_chipset_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!config_chipset_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		sis5513_tune_drive(drive, 5);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+
+/* initiates/aborts (U)DMA read/write operations on a drive. */
+static int sis5513_config_xfer_rate (ide_drive_t *drive)
+{
+	config_drive_art_rwp(drive);
+	config_art_rwp_pio(drive, 5);
+	return sis5513_config_drive_xfer_rate(drive);
+}
+
+/* Chip detection and general config */
+static unsigned int __init init_chipset_sis5513 (struct pci_dev *dev, const char *name)
+{
+	struct pci_dev *host;
+	int i = 0;
+
+	/* Find the chip */
+	for (i = 0; i < ARRAY_SIZE(SiSHostChipInfo) && !host_dev; i++) {
+		host = pci_find_device (PCI_VENDOR_ID_SI,
+					SiSHostChipInfo[i].host_id,
+					NULL);
+		if (!host)
+			continue;
+
+		host_dev = host;
+		chipset_family = SiSHostChipInfo[i].chipset_family;
+	
+		/* check 100/133 chipset family */
+		if (chipset_family == ATA_133) {
+			u32 reg54h;
+			u16 reg02h;
+			pci_read_config_dword(dev, 0x54, &reg54h);
+			pci_write_config_dword(dev, 0x54, (reg54h & 0x7fffffff));
+			pci_read_config_word(dev, 0x02, &reg02h);
+			pci_write_config_dword(dev, 0x54, reg54h);
+			/* devid 5518 here means SiS962 or later
+			   which supports ATA133 */
+			if (reg02h != 0x5518) {
+				u8 reg49h;
+				unsigned long sbrev;
+				/* SiS961 family */
+
+		/*
+		 * FIXME !!! GAK!!!!!!!!!! PCI DIRECT POKING 
+		 */
+				outl(0x80001008, 0x0cf8);
+				sbrev = inl(0x0cfc);
+
+				pci_read_config_byte(dev, 0x49, &reg49h);
+				if (((sbrev & 0xff) == 0x10) && (reg49h & 0x80))
+					chipset_family = ATA_133a;
+				else
+					chipset_family = ATA_100;
+			}
+		}
+		printk(SiSHostChipInfo[i].name);
+		printk("    %s controller", chipset_capability[chipset_family]);
+		printk("\n");
+
+#ifdef DEBUG
+		sis5513_print_registers(dev, "pci_init_sis5513 start");
+#endif
+
+		if (SiSHostChipInfo[i].flags & SIS5513_LATENCY) {
+			u8 latency = (chipset_family == ATA_100)? 0x80 : 0x10; /* Lacking specs */
+			pci_write_config_byte(dev, PCI_LATENCY_TIMER, latency);
+		}
+	}
+
+	/* Make general config ops here
+	   1/ tell IDE channels to operate in Compabitility mode only
+	   2/ tell old chips to allow per drive IDE timings */
+	if (host_dev) {
+		u8 reg;
+		u16 regw;
+		switch(chipset_family) {
+			case ATA_133:
+				/* SiS962 operation mode */
+				pci_read_config_word(dev, 0x50, &regw);
+				if (regw & 0x08)
+					pci_write_config_word(dev, 0x50, regw&0xfff7);
+				pci_read_config_word(dev, 0x52, &regw);
+				if (regw & 0x08)
+					pci_write_config_word(dev, 0x52, regw&0xfff7);
+				break;
+			case ATA_133a:
+			case ATA_100:
+				/* Set compatibility bit */
+				pci_read_config_byte(dev, 0x49, &reg);
+				if (!(reg & 0x01)) {
+					pci_write_config_byte(dev, 0x49, reg|0x01);
+				}
+				break;
+			case ATA_100a:
+			case ATA_66:
+				/* On ATA_66 chips the bit was elsewhere */
+				pci_read_config_byte(dev, 0x52, &reg);
+				if (!(reg & 0x04)) {
+					pci_write_config_byte(dev, 0x52, reg|0x04);
+				}
+				break;
+			case ATA_33:
+				/* On ATA_33 we didn't have a single bit to set */
+				pci_read_config_byte(dev, 0x09, &reg);
+				if ((reg & 0x0f) != 0x00) {
+					pci_write_config_byte(dev, 0x09, reg&0xf0);
+				}
+			case ATA_16:
+				/* force per drive recovery and active timings
+				   needed on ATA_33 and below chips */
+				pci_read_config_byte(dev, 0x52, &reg);
+				if (!(reg & 0x08)) {
+					pci_write_config_byte(dev, 0x52, reg|0x08);
+				}
+				break;
+			case ATA_00:
+			default: break;
+		}
+
+#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS)
+		if (!sis_proc) {
+			sis_proc = 1;
+			bmide_dev = dev;
+			ide_pci_register_host_proc(&sis_procs[0]);
+		}
+#endif
+	}
+#ifdef DEBUG
+	sis5513_load_verify_registers(dev, "pci_init_sis5513 end");
+#endif
+	return 0;
+}
+
+static unsigned int __init ata66_sis5513 (ide_hwif_t *hwif)
+{
+	u8 ata66 = 0;
+
+	if (chipset_family >= ATA_133) {
+		u16 regw = 0;
+		u16 reg_addr = hwif->channel ? 0x52: 0x50;
+		pci_read_config_word(hwif->pci_dev, reg_addr, &regw);
+		ata66 = (regw & 0x8000) ? 0 : 1;
+	} else if (chipset_family >= ATA_66) {
+		u8 reg48h = 0;
+		u8 mask = hwif->channel ? 0x20 : 0x10;
+		pci_read_config_byte(hwif->pci_dev, 0x48, &reg48h);
+		ata66 = (reg48h & mask) ? 0 : 1;
+	}
+        return ata66;
+}
+
+static void __init init_hwif_sis5513 (ide_hwif_t *hwif)
+{
+	hwif->autodma = 0;
+
+	if (!hwif->irq)
+		hwif->irq = hwif->channel ? 15 : 14;
+
+	hwif->tuneproc = &sis5513_tune_drive;
+	hwif->speedproc = &sis5513_tune_chipset;
+
+	if (!(hwif->dma_base)) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->atapi_dma = 1;
+	hwif->ultra_mask = 0x7f;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+	if (!host_dev)
+		return;
+
+	if (!(hwif->udma_four))
+		hwif->udma_four = ata66_sis5513(hwif);
+
+	if (chipset_family > ATA_16) {
+		hwif->ide_dma_check = &sis5513_config_xfer_rate;
+		if (!noautodma)
+			hwif->autodma = 1;
+	}
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+	return;
+}
+
+static void __init init_dma_sis5513 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+
+static int __devinit sis5513_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &sis5513_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id sis5513_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5513, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "SIS IDE",
+	.id_table	= sis5513_pci_tbl,
+	.probe		= sis5513_init_one,
+};
+
+static int sis5513_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void sis5513_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(sis5513_ide_init);
+module_exit(sis5513_ide_exit);
+
+MODULE_AUTHOR("Lionel Bouton, L C Chang, Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for SIS IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
+
+/*
+ * TODO:
+ *	- Get ridden of SisHostChipInfo[] completness dependancy.
+ *	- Study drivers/ide/ide-timing.h.
+ *	- Are there pre-ATA_16 SiS5513 chips ? -> tune init code for them
+ *	  or remove ATA_00 define
+ *	- More checks in the config registers (force values instead of
+ *	  relying on the BIOS setting them correctly).
+ *	- Further optimisations ?
+ *	  . for example ATA66+ regs 0x48 & 0x4A
+ */
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/sis5513.h linux-2.4.21-pre6/drivers/ide/pci/sis5513.h
--- linux-2.4.20/drivers/ide/pci/sis5513.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/sis5513.h	2003-03-26 23:49:20.000000000 +0000
@@ -0,0 +1,54 @@
+#ifndef SIS5513_H
+#define SIS5513_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_SIS_TIMINGS
+
+#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 sis_proc;
+
+static int sis_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t sis_procs[] __initdata = {
+{
+		.name		= "sis",
+		.set		= 1,
+		.get_info	= sis_get_info,
+		.parent		= NULL,
+	},
+};
+#endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static unsigned int init_chipset_sis5513(struct pci_dev *, const char *);
+static void init_hwif_sis5513(ide_hwif_t *);
+static void init_dma_sis5513(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t sis5513_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_SI,
+		.device		= PCI_DEVICE_ID_SI_5513,
+		.name		= "SIS5513",
+		.init_chipset	= init_chipset_sis5513,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_sis5513,
+		.init_dma	= init_dma_sis5513,
+		.channels	= 2,
+		.autodma	= NOAUTODMA,
+		.enablebits	= {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
+		.bootable	= ON_BOARD,
+		.extra		= 0
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* SIS5513_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/sl82c105.c linux-2.4.21-pre6/drivers/ide/pci/sl82c105.c
--- linux-2.4.20/drivers/ide/pci/sl82c105.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/sl82c105.c	2003-03-26 23:49:21.000000000 +0000
@@ -0,0 +1,541 @@
+/*
+ * linux/drivers/ide/pci/sl82c105.c
+ *
+ * SL82C105/Winbond 553 IDE driver
+ *
+ * Maintainer unknown.
+ *
+ * Drive tuning added from Rebel.com's kernel sources
+ *  -- Russell King (15/11/98) linux@arm.linux.org.uk
+ * 
+ * Merge in Russell's HW workarounds, fix various problems
+ * with the timing registers setup.
+ *  -- Benjamin Herrenschmidt (01/11/03) benh@kernel.crashing.org
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include "ide_modes.h"
+#include "sl82c105.h"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(arg) printk arg
+#else
+#define DBG(fmt,...)
+#endif
+/*
+ * SL82C105 PCI config register 0x40 bits.
+ */
+#define CTRL_IDE_IRQB   (1 << 30)
+#define CTRL_IDE_IRQA   (1 << 28)
+#define CTRL_LEGIRQ     (1 << 11)
+#define CTRL_P1F16      (1 << 5)
+#define CTRL_P1EN       (1 << 4)
+#define CTRL_P0F16      (1 << 1)
+#define CTRL_P0EN       (1 << 0)
+
+/*
+ * Convert a PIO mode and cycle time to the required on/off
+ * times for the interface.  This has protection against run-away
+ * timings.
+ */
+static unsigned int get_timing_sl82c105(ide_pio_data_t *p)
+{
+	unsigned int cmd_on;
+	unsigned int cmd_off;
+
+	cmd_on = (ide_pio_timings[p->pio_mode].active_time + 29) / 30;
+	cmd_off = (p->cycle_time - 30 * cmd_on + 29) / 30;
+
+	if (cmd_on > 32)
+		cmd_on = 32;
+	if (cmd_on == 0)
+		cmd_on = 1;
+
+	if (cmd_off > 32)
+		cmd_off = 32;
+	if (cmd_off == 0)
+		cmd_off = 1;
+
+	return (cmd_on - 1) << 8 | (cmd_off - 1) | (p->use_iordy ? 0x40 : 0x00);
+}
+
+/*
+ * Configure the drive and chipset for PIO
+ */
+static void config_for_pio(ide_drive_t *drive, int pio, int report, int chipset_only)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	struct pci_dev *dev = hwif->pci_dev;
+	ide_pio_data_t p;
+	u16 drv_ctrl = 0x909;
+	unsigned int xfer_mode, reg;
+
+	DBG(("config_for_pio(drive:%s, pio:%d, report:%d, chipset_only:%d)\n",
+		drive->name, pio, report, chipset_only));
+		
+	reg = (hwif->channel ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
+
+	pio = ide_get_best_pio_mode(drive, pio, 5, &p);
+
+	xfer_mode = XFER_PIO_0 + pio;
+
+	if (chipset_only || ide_config_drive_speed(drive, xfer_mode) == 0) {
+		drv_ctrl = get_timing_sl82c105(&p);
+		drive->pio_speed = xfer_mode;
+	} else
+		drive->pio_speed = XFER_PIO_0;
+
+	if (drive->using_dma == 0) {
+		/*
+		 * If we are actually using MW DMA, then we can not
+		 * reprogram the interface drive control register.
+		 */
+		pci_write_config_word(dev, reg, drv_ctrl);
+		pci_read_config_word(dev, reg, &drv_ctrl);
+
+		if (report) {
+			printk("%s: selected %s (%dns) (%04X)\n", drive->name,
+			       ide_xfer_verbose(xfer_mode), p.cycle_time, drv_ctrl);
+		}
+	}
+}
+
+/*
+ * Configure the drive and the chipset for DMA
+ */
+static int config_for_dma (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	struct pci_dev *dev = hwif->pci_dev;
+	unsigned int reg;
+
+	DBG(("config_for_dma(drive:%s)\n", drive->name));
+
+	reg = (hwif->channel ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
+
+	if (ide_config_drive_speed(drive, XFER_MW_DMA_2) != 0)
+		return 1;
+
+	pci_write_config_word(dev, reg, 0x0240);
+
+	return 0;
+}
+
+/*
+ * Check to see if the drive and
+ * chipset is capable of DMA mode
+ */
+
+static int sl82c105_check_drive (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+
+	DBG(("sl82c105_check_drive(drive:%s)\n", drive->name));
+
+	do {
+		struct hd_driveid *id = drive->id;
+
+		if (!drive->autodma)
+			break;
+
+		if (!id || !(id->capability & 1))
+			break;
+
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			break;
+
+		if (id->field_valid & 2) {
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask))
+				return hwif->ide_dma_on(drive);
+		}
+
+		if (hwif->ide_dma_good_drive(drive))
+			return hwif->ide_dma_on(drive);
+	} while (0);
+
+	return hwif->ide_dma_off_quietly(drive);
+}
+
+/*
+ * The SL82C105 holds off all IDE interrupts while in DMA mode until
+ * all DMA activity is completed.  Sometimes this causes problems (eg,
+ * when the drive wants to report an error condition).
+ *
+ * 0x7e is a "chip testing" register.  Bit 2 resets the DMA controller
+ * state machine.  We need to kick this to work around various bugs.
+ */
+static inline void sl82c105_reset_host(struct pci_dev *dev)
+{
+	u16 val;
+
+	pci_read_config_word(dev, 0x7e, &val);
+	pci_write_config_word(dev, 0x7e, val | (1 << 2));
+	pci_write_config_word(dev, 0x7e, val & ~(1 << 2));
+}
+
+/*
+ * If we get an IRQ timeout, it might be that the DMA state machine
+ * got confused.  Fix from Todd Inglett.  Details from Winbond.
+ *
+ * This function is called when the IDE timer expires, the drive
+ * indicates that it is READY, and we were waiting for DMA to complete.
+ */
+static int sl82c105_ide_dma_lost_irq(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	struct pci_dev *dev = hwif->pci_dev;
+	u32 val, mask = hwif->channel ? CTRL_IDE_IRQB : CTRL_IDE_IRQA;
+	unsigned long dma_base = hwif->dma_base;
+
+	printk("sl82c105: lost IRQ: resetting host\n");
+
+	/*
+	 * Check the raw interrupt from the drive.
+	 */
+	pci_read_config_dword(dev, 0x40, &val);
+	if (val & mask)
+		printk("sl82c105: drive was requesting IRQ, but host lost it\n");
+
+	/*
+	 * Was DMA enabled?  If so, disable it - we're resetting the
+	 * host.  The IDE layer will be handling the drive for us.
+	 */
+	val = hwif->INB(dma_base);
+	if (val & 1) {
+		outb(val & ~1, dma_base);
+		printk("sl82c105: DMA was enabled\n");
+	}
+
+	sl82c105_reset_host(dev);
+
+	/* ide_dmaproc would return 1, so we do as well */
+	return 1;
+}
+
+/*
+ * ATAPI devices can cause the SL82C105 DMA state machine to go gaga.
+ * Winbond recommend that the DMA state machine is reset prior to
+ * setting the bus master DMA enable bit.
+ *
+ * The generic IDE core will have disabled the BMEN bit before this
+ * function is called.
+ */
+static int sl82c105_ide_dma_begin(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	struct pci_dev *dev = hwif->pci_dev;
+
+//	DBG(("sl82c105_ide_dma_begin(drive:%s)\n", drive->name));
+
+	sl82c105_reset_host(dev);
+	return __ide_dma_begin(drive);
+}
+
+static int sl82c105_ide_dma_timeout(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	struct pci_dev *dev = hwif->pci_dev;
+
+	DBG(("sl82c105_ide_dma_timeout(drive:%s)\n", drive->name));
+
+	sl82c105_reset_host(dev);
+	return __ide_dma_timeout(drive);
+}
+
+static int sl82c105_ide_dma_on (ide_drive_t *drive)
+{
+	DBG(("sl82c105_ide_dma_on(drive:%s)\n", drive->name));
+
+	if (config_for_dma(drive)) {
+		config_for_pio(drive, 4, 0, 0);
+		return HWIF(drive)->ide_dma_off_quietly(drive);
+	}
+	printk(KERN_INFO "%s: DMA enabled\n", drive->name);
+	return __ide_dma_on(drive);
+}
+
+static int sl82c105_ide_dma_off (ide_drive_t *drive)
+{
+	u8 speed = XFER_PIO_0;
+	int rc;
+	
+	DBG(("sl82c105_ide_dma_off(drive:%s)\n", drive->name));
+
+	rc = __ide_dma_off(drive);
+	if (drive->pio_speed)
+		speed = drive->pio_speed - XFER_PIO_0;
+	config_for_pio(drive, speed, 0, 1);
+	drive->current_speed = drive->pio_speed;
+
+	return rc;
+}
+
+static int sl82c105_ide_dma_off_quietly (ide_drive_t *drive)
+{
+	u8 speed = XFER_PIO_0;
+	int rc;
+	
+	DBG(("sl82c105_ide_dma_off_quietly(drive:%s)\n", drive->name));
+
+	rc = __ide_dma_off_quietly(drive);
+	if (drive->pio_speed)
+		speed = drive->pio_speed - XFER_PIO_0;
+	config_for_pio(drive, speed, 0, 1);
+	drive->current_speed = drive->pio_speed;
+
+	return rc;
+}
+
+/*
+ * Ok, that is nasty, but we must make sure the DMA timings
+ * won't be used for a PIO access. The solution here is
+ * to make sure the 16 bits mode is diabled on the channel
+ * when DMA is enabled, thus causing the chip to use PIO0
+ * timings for those operations.
+ */
+static void sl82c105_selectproc(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	struct pci_dev *dev = hwif->pci_dev;
+	u32 val, old, mask;
+
+	//DBG(("sl82c105_selectproc(drive:%s)\n", drive->name));
+
+	mask = hwif->channel ? CTRL_P1F16 : CTRL_P0F16;
+	old = val = *((u32 *)&hwif->hwif_data);
+	if (drive->using_dma)
+		val &= ~mask;
+	else
+		val |= mask;
+	if (old != val) {
+		pci_write_config_dword(dev, 0x40, val);	
+		*((u32 *)&hwif->hwif_data) = val;
+	}
+}
+
+/*
+ * ATA reset will clear the 16 bits mode in the control
+ * register, we need to update our cache
+ */
+static void sl82c105_resetproc(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	struct pci_dev *dev = hwif->pci_dev;
+	u32 val;
+
+	DBG(("sl82c105_resetproc(drive:%s)\n", drive->name));
+
+	pci_read_config_dword(dev, 0x40, &val);
+	*((u32 *)&hwif->hwif_data) = val;
+}
+	
+/*
+ * We only deal with PIO mode here - DMA mode 'using_dma' is not
+ * initialised at the point that this function is called.
+ */
+static void tune_sl82c105(ide_drive_t *drive, u8 pio)
+{
+	DBG(("tune_sl82c105(drive:%s)\n", drive->name));
+
+	config_for_pio(drive, pio, 1, 0);
+
+	/*
+	 * We support 32-bit I/O on this interface, and it
+	 * doesn't have problems with interrupts.
+	 */
+	drive->io_32bit = 1;
+	drive->unmask = 1;
+}
+
+/*
+ * Return the revision of the Winbond bridge
+ * which this function is part of.
+ */
+static unsigned int sl82c105_bridge_revision(struct pci_dev *dev)
+{
+	struct pci_dev *bridge;
+	u8 rev;
+
+	/*
+	 * The bridge should be part of the same device, but function 0.
+	 */
+	bridge = pci_find_slot(dev->bus->number,
+			       PCI_DEVFN(PCI_SLOT(dev->devfn), 0));
+	if (!bridge)
+		return -1;
+
+	/*
+	 * Make sure it is a Winbond 553 and is an ISA bridge.
+	 */
+	if (bridge->vendor != PCI_VENDOR_ID_WINBOND ||
+	    bridge->device != PCI_DEVICE_ID_WINBOND_83C553 ||
+	    bridge->class >> 8 != PCI_CLASS_BRIDGE_ISA)
+		return -1;
+
+	/*
+	 * We need to find function 0's revision, not function 1
+	 */
+	pci_read_config_byte(bridge, PCI_REVISION_ID, &rev);
+
+	return rev;
+}
+
+/*
+ * Enable the PCI device
+ * 
+ * --BenH: It's arch fixup code that should enable channels that
+ * have not been enabled by firmware. I decided we can still enable
+ * channel 0 here at least, but channel 1 has to be enabled by
+ * firmware or arch code. We still set both to 16 bits mode.
+ */
+static unsigned int __init init_chipset_sl82c105(struct pci_dev *dev, const char *msg)
+{
+	u32 val;
+
+	DBG(("init_chipset_sl82c105()\n"));
+
+	pci_read_config_dword(dev, 0x40, &val);
+	val |= CTRL_P0EN | CTRL_P0F16 | CTRL_P1F16;
+	pci_write_config_dword(dev, 0x40, val);
+
+	return dev->irq;
+}
+
+static void __init init_dma_sl82c105(ide_hwif_t *hwif, unsigned long dma_base)
+{
+	unsigned int rev;
+	u8 dma_state;
+
+	DBG(("init_dma_sl82c105(hwif: ide%d, dma_base: 0x%08x)\n", hwif->index, dma_base));
+
+	hwif->autodma = 0;
+
+	if (!dma_base)
+		return;
+
+	dma_state = hwif->INB(dma_base + 2);
+	rev = sl82c105_bridge_revision(hwif->pci_dev);
+	if (rev <= 5) {
+		printk("    %s: Winbond 553 bridge revision %d, BM-DMA disabled\n",
+		       hwif->name, rev);
+		dma_state &= ~0x60;
+	} else {
+		dma_state |= 0x60;
+		if (!noautodma)
+			hwif->autodma = 1;
+	}
+	hwif->OUTB(dma_state, dma_base + 2);
+
+	ide_setup_dma(hwif, dma_base, 8);
+}
+
+/*
+ * Initialise the chip
+ */
+
+static void __init init_hwif_sl82c105(ide_hwif_t *hwif)
+{
+	struct pci_dev *dev = hwif->pci_dev;
+	u32 val;
+	
+	DBG(("init_hwif_sl82c105(hwif: ide%d)\n", hwif->index));
+
+	hwif->tuneproc = tune_sl82c105;
+	hwif->selectproc = sl82c105_selectproc;
+	hwif->resetproc = sl82c105_resetproc;
+	
+	/* Default to PIO 0 for fallback unless tuned otherwise,
+	 * we always autotune PIO, this is done before DMA is
+	 * checked, so there is no risk of accidentally disabling
+	 * DMA
+	  */
+	hwif->drives[0].pio_speed = XFER_PIO_0;
+	hwif->drives[0].autotune = 1;
+	hwif->drives[1].pio_speed = XFER_PIO_1;
+	hwif->drives[1].autotune = 1;
+
+	pci_read_config_dword(dev, 0x40, &val);
+	*((u32 *)&hwif->hwif_data) = val;
+	
+	if (!hwif->dma_base)
+		return;
+
+	hwif->atapi_dma = 1;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	hwif->ide_dma_check = &sl82c105_check_drive;
+	hwif->ide_dma_on = &sl82c105_ide_dma_on;
+	hwif->ide_dma_off = &sl82c105_ide_dma_off;
+	hwif->ide_dma_off_quietly = &sl82c105_ide_dma_off_quietly;
+	hwif->ide_dma_lostirq = &sl82c105_ide_dma_lost_irq;
+	hwif->ide_dma_begin = &sl82c105_ide_dma_begin;
+	hwif->ide_dma_timeout = &sl82c105_ide_dma_timeout;
+
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static int __devinit sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &sl82c105_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id sl82c105_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "W82C105 IDE",
+	.id_table	= sl82c105_pci_tbl,
+	.probe		= sl82c105_init_one,
+};
+
+static int sl82c105_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void sl82c105_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(sl82c105_ide_init);
+module_exit(sl82c105_ide_exit);
+
+MODULE_DESCRIPTION("PCI driver module for W82C105 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/sl82c105.h linux-2.4.21-pre6/drivers/ide/pci/sl82c105.h
--- linux-2.4.20/drivers/ide/pci/sl82c105.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/sl82c105.h	2003-03-26 23:48:57.000000000 +0000
@@ -0,0 +1,34 @@
+#ifndef W82C105_H
+#define W82C105_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+static unsigned int init_chipset_sl82c105(struct pci_dev *, const char *);
+static void init_hwif_sl82c105(ide_hwif_t *);
+static void init_dma_sl82c105(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t sl82c105_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_WINBOND,
+		.device		= PCI_DEVICE_ID_WINBOND_82C105,
+		.name		= "W82C105",
+		.init_chipset	= init_chipset_sl82c105,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_sl82c105,
+		.init_dma	= init_dma_sl82c105,
+		.channels	= 2,
+		.autodma	= NOAUTODMA,
+		.enablebits	= {{0x40,0x01,0x01}, {0x40,0x10,0x10}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* W82C105_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/slc90e66.c linux-2.4.21-pre6/drivers/ide/pci/slc90e66.c
--- linux-2.4.20/drivers/ide/pci/slc90e66.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/slc90e66.c	2003-03-26 23:48:59.000000000 +0000
@@ -0,0 +1,407 @@
+/*
+ *  linux/drivers/ide/pci/slc90e66.c	Version 0.11	September 11, 2002
+ *
+ *  Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org>
+ *
+ * This a look-a-like variation of the ICH0 PIIX4 Ultra-66,
+ * but this keeps the ISA-Bridge and slots alive.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "ide_modes.h"
+#include "slc90e66.h"
+
+#if defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 slc90e66_proc = 0;
+static struct pci_dev *bmide_dev;
+
+static int slc90e66_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+	char *p = buffer;
+	unsigned long bibma = pci_resource_start(bmide_dev, 4);
+        u16 reg40 = 0, psitre = 0, reg42 = 0, ssitre = 0;
+	u8  c0 = 0, c1 = 0;
+	u8  reg44 = 0, reg47 = 0, reg48 = 0, reg4a = 0, reg4b = 0;
+
+	pci_read_config_word(bmide_dev, 0x40, &reg40);
+	pci_read_config_word(bmide_dev, 0x42, &reg42);
+	pci_read_config_byte(bmide_dev, 0x44, &reg44);
+	pci_read_config_byte(bmide_dev, 0x47, &reg47);
+	pci_read_config_byte(bmide_dev, 0x48, &reg48);
+	pci_read_config_byte(bmide_dev, 0x4a, &reg4a);
+	pci_read_config_byte(bmide_dev, 0x4b, &reg4b);
+
+	psitre = (reg40 & 0x4000) ? 1 : 0;
+	ssitre = (reg42 & 0x4000) ? 1 : 0;
+
+        /*
+         * at that point bibma+0x2 et bibma+0xa are byte registers
+         * to investigate:
+         */
+	c0 = inb_p(bibma + 0x02);
+	c1 = inb_p(bibma + 0x0a);
+
+	p += sprintf(p, "                                SLC90E66 Chipset.\n");
+	p += sprintf(p, "--------------- Primary Channel "
+			"---------------- Secondary Channel "
+			"-------------\n");
+	p += sprintf(p, "                %sabled "
+			"                        %sabled\n",
+			(c0&0x80) ? "dis" : " en",
+			(c1&0x80) ? "dis" : " en");
+	p += sprintf(p, "--------------- drive0 --------- drive1 "
+			"-------- drive0 ---------- drive1 ------\n");
+	p += sprintf(p, "DMA enabled:    %s              %s "
+			"            %s               %s\n",
+			(c0&0x20) ? "yes" : "no ",
+			(c0&0x40) ? "yes" : "no ",
+			(c1&0x20) ? "yes" : "no ",
+			(c1&0x40) ? "yes" : "no " );
+	p += sprintf(p, "UDMA enabled:   %s              %s "
+			"            %s               %s\n",
+			(reg48&0x01) ? "yes" : "no ",
+			(reg48&0x02) ? "yes" : "no ",
+			(reg48&0x04) ? "yes" : "no ",
+			(reg48&0x08) ? "yes" : "no " );
+	p += sprintf(p, "UDMA enabled:   %s                %s "
+			"              %s                 %s\n",
+			((reg4a&0x04)==0x04) ? "4" :
+			((reg4a&0x03)==0x03) ? "3" :
+			(reg4a&0x02) ? "2" :
+			(reg4a&0x01) ? "1" :
+			(reg4a&0x00) ? "0" : "X",
+			((reg4a&0x40)==0x40) ? "4" :
+			((reg4a&0x30)==0x30) ? "3" :
+			(reg4a&0x20) ? "2" :
+			(reg4a&0x10) ? "1" :
+			(reg4a&0x00) ? "0" : "X",
+			((reg4b&0x04)==0x04) ? "4" :
+			((reg4b&0x03)==0x03) ? "3" :
+			(reg4b&0x02) ? "2" :
+			(reg4b&0x01) ? "1" :
+			(reg4b&0x00) ? "0" : "X",
+			((reg4b&0x40)==0x40) ? "4" :
+			((reg4b&0x30)==0x30) ? "3" :
+			(reg4b&0x20) ? "2" :
+			(reg4b&0x10) ? "1" :
+			(reg4b&0x00) ? "0" : "X");
+
+	p += sprintf(p, "UDMA\n");
+	p += sprintf(p, "DMA\n");
+	p += sprintf(p, "PIO\n");
+
+/*
+ *	FIXME.... Add configuration junk data....blah blah......
+ */
+
+	return p-buffer;	 /* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static u8 slc90e66_ratemask (ide_drive_t *drive)
+{
+	u8 mode	= 2;
+
+	if (!eighty_ninty_three(drive))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+static u8 slc90e66_dma_2_pio (u8 xfer_rate) {
+	switch(xfer_rate) {
+		case XFER_UDMA_4:
+		case XFER_UDMA_3:
+		case XFER_UDMA_2:
+		case XFER_UDMA_1:
+		case XFER_UDMA_0:
+		case XFER_MW_DMA_2:
+		case XFER_PIO_4:
+			return 4;
+		case XFER_MW_DMA_1:
+		case XFER_PIO_3:
+			return 3;
+		case XFER_SW_DMA_2:
+		case XFER_PIO_2:
+			return 2;
+		case XFER_MW_DMA_0:
+		case XFER_SW_DMA_1:
+		case XFER_SW_DMA_0:
+		case XFER_PIO_1:
+		case XFER_PIO_0:
+		case XFER_PIO_SLOW:
+		default:
+			return 0;
+	}
+}
+
+/*
+ *  Based on settings done by AMI BIOS
+ *  (might be useful if drive is not registered in CMOS for any reason).
+ */
+static void slc90e66_tune_drive (ide_drive_t *drive, u8 pio)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	int is_slave		= (&hwif->drives[1] == drive);
+	int master_port		= hwif->channel ? 0x42 : 0x40;
+	int slave_port		= 0x44;
+	unsigned long flags;
+	u16 master_data;
+	u8 slave_data;
+				 /* ISP  RTC */
+	u8 timings[][2]	= { { 0, 0 },
+				    { 0, 0 },
+				    { 1, 0 },
+				    { 2, 1 },
+				    { 2, 3 }, };
+
+	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+	spin_lock_irqsave(&ide_lock, flags);
+	pci_read_config_word(dev, master_port, &master_data);
+	if (is_slave) {
+		master_data = master_data | 0x4000;
+		if (pio > 1)
+			/* enable PPE, IE and TIME */
+			master_data = master_data | 0x0070;
+		pci_read_config_byte(dev, slave_port, &slave_data);
+		slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0);
+		slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0));
+	} else {
+		master_data = master_data & 0xccf8;
+		if (pio > 1)
+			/* enable PPE, IE and TIME */
+			master_data = master_data | 0x0007;
+		master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8);
+	}
+	pci_write_config_word(dev, master_port, master_data);
+	if (is_slave)
+		pci_write_config_byte(dev, slave_port, slave_data);
+	spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+static int slc90e66_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct pci_dev *dev	= hwif->pci_dev;
+	u8 maslave		= hwif->channel ? 0x42 : 0x40;
+	u8 speed	= ide_rate_filter(slc90e66_ratemask(drive), xferspeed);
+	int sitre = 0, a_speed	= 7 << (drive->dn * 4);
+	int u_speed = 0, u_flag = 1 << drive->dn;
+	u16			reg4042, reg44, reg48, reg4a;
+
+	pci_read_config_word(dev, maslave, &reg4042);
+	sitre = (reg4042 & 0x4000) ? 1 : 0;
+	pci_read_config_word(dev, 0x44, &reg44);
+	pci_read_config_word(dev, 0x48, &reg48);
+	pci_read_config_word(dev, 0x4a, &reg4a);
+
+	switch(speed) {
+#ifdef CONFIG_BLK_DEV_IDEDMA
+		case XFER_UDMA_4:	u_speed = 4 << (drive->dn * 4); break;
+		case XFER_UDMA_3:	u_speed = 3 << (drive->dn * 4); break;
+		case XFER_UDMA_2:	u_speed = 2 << (drive->dn * 4); break;
+		case XFER_UDMA_1:	u_speed = 1 << (drive->dn * 4); break;
+		case XFER_UDMA_0:	u_speed = 0 << (drive->dn * 4); break;
+		case XFER_MW_DMA_2:
+		case XFER_MW_DMA_1:
+		case XFER_SW_DMA_2:	break;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+		case XFER_PIO_4:
+		case XFER_PIO_3:
+		case XFER_PIO_2:
+		case XFER_PIO_0:        break;
+		default:		return -1;
+	}
+
+	if (speed >= XFER_UDMA_0) {
+		if (!(reg48 & u_flag))
+			pci_write_config_word(dev, 0x48, reg48|u_flag);
+		if ((reg4a & u_speed) != u_speed) {
+			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+			pci_read_config_word(dev, 0x4a, &reg4a);
+			pci_write_config_word(dev, 0x4a, reg4a|u_speed);
+		}
+	} else {
+		if (reg48 & u_flag)
+			pci_write_config_word(dev, 0x48, reg48 & ~u_flag);
+		if (reg4a & a_speed)
+			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+	}
+
+	slc90e66_tune_drive(drive, slc90e66_dma_2_pio(speed));
+	return (ide_config_drive_speed(drive, speed));
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+static int slc90e66_config_drive_for_dma (ide_drive_t *drive)
+{
+	u8 speed = ide_dma_speed(drive, slc90e66_ratemask(drive));
+
+	if (!(speed)) {
+		u8 tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL);
+		speed = slc90e66_dma_2_pio(XFER_PIO_0 + tspeed);
+	}
+
+	(void) slc90e66_tune_chipset(drive, speed);
+	return ide_dma_enable(drive);
+}
+
+static int slc90e66_config_drive_xfer_rate (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+
+	drive->init_speed = 0;
+
+	if (id && (id->capability & 1) && drive->autodma) {
+		/* Consult the list of known "bad" drives */
+		if (hwif->ide_dma_bad_drive(drive))
+			goto fast_ata_pio;
+
+		if (id->field_valid & 4) {
+			if (id->dma_ultra & hwif->ultra_mask) {
+				/* Force if Capable UltraDMA */
+				int dma = slc90e66_config_drive_for_dma(drive);
+				if ((id->field_valid & 2) && !dma)
+					goto try_dma_modes;
+			}
+		} else if (id->field_valid & 2) {
+try_dma_modes:
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+			    (id->dma_1word & hwif->swdma_mask)) {
+				/* Force if Capable regular DMA modes */
+				if (!slc90e66_config_drive_for_dma(drive))
+					goto no_dma_set;
+			}
+		} else if (hwif->ide_dma_good_drive(drive) &&
+			   (id->eide_dma_time < 150)) {
+			/* Consult the list of known "good" drives */
+			if (!slc90e66_config_drive_for_dma(drive))
+				goto no_dma_set;
+		} else {
+			goto fast_ata_pio;
+		}
+	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+no_dma_set:
+		hwif->tuneproc(drive, 5);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+	return hwif->ide_dma_on(drive);
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+static unsigned int __init init_chipset_slc90e66 (struct pci_dev *dev, const char *name)
+{
+#if defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!slc90e66_proc) {
+		slc90e66_proc = 1;
+		bmide_dev = dev;
+		ide_pci_register_host_proc(&slc90e66_procs[0]);
+	}
+#endif /* DISPLAY_SLC90E66_TIMINGS && CONFIG_PROC_FS */
+	return 0;
+}
+
+static void __init init_hwif_slc90e66 (ide_hwif_t *hwif)
+{
+	u8 reg47 = 0;
+	u8 mask = hwif->channel ? 0x01 : 0x02;  /* bit0:Primary */
+
+	hwif->autodma = 0;
+
+	if (!hwif->irq)
+		hwif->irq = hwif->channel ? 15 : 14;
+
+	hwif->speedproc = &slc90e66_tune_chipset;
+	hwif->tuneproc = &slc90e66_tune_drive;
+
+	pci_read_config_byte(hwif->pci_dev, 0x47, &reg47);
+
+	if (!hwif->dma_base) {
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+		return;
+	}
+
+	hwif->atapi_dma = 1;
+	hwif->ultra_mask = 0x1f;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA 
+	if (!(hwif->udma_four))
+		/* bit[0(1)]: 0:80, 1:40 */
+		hwif->udma_four = (reg47 & mask) ? 0 : 1;
+
+	hwif->ide_dma_check = &slc90e66_config_drive_xfer_rate;
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+#endif /* !CONFIG_BLK_DEV_IDEDMA */
+}
+
+static void __init init_dma_slc90e66 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+	ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+
+static int __devinit slc90e66_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &slc90e66_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id slc90e66_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name		= "SLC90e66 IDE",
+	.id_table	= slc90e66_pci_tbl,
+	.probe		= slc90e66_init_one,
+};
+
+static int slc90e66_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void slc90e66_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(slc90e66_ide_init);
+module_exit(slc90e66_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for SLC90E66 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/slc90e66.h linux-2.4.21-pre6/drivers/ide/pci/slc90e66.h
--- linux-2.4.20/drivers/ide/pci/slc90e66.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/slc90e66.h	2003-03-26 23:49:40.000000000 +0000
@@ -0,0 +1,56 @@
+#ifndef SLC90E66_H
+#define SLC90E66_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_SLC90E66_TIMINGS
+
+#define SLC90E66_DEBUG_DRIVE_INFO	0
+
+#if defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 slc90e66_proc;
+
+static int slc90e66_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t slc90e66_procs[] __initdata = {
+	{
+		.name		= "slc90e66",
+		.set		= 1,
+		.get_info	= slc90e66_get_info,
+		.parent		= NULL,
+	},
+};
+#endif	/* defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static unsigned int init_chipset_slc90e66(struct pci_dev *, const char *);
+static void init_hwif_slc90e66(ide_hwif_t *);
+static void init_dma_slc90e66(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t slc90e66_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_EFAR,
+		.device		= PCI_DEVICE_ID_EFAR_SLC90E66_1,
+		.name		= "SLC90E66",
+		.init_chipset	= init_chipset_slc90e66,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_slc90e66,
+		.init_dma	= init_dma_slc90e66,
+		.channels	= 2,
+		.autodma	= AUTODMA,
+		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* SLC90E66_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/triflex.c linux-2.4.21-pre6/drivers/ide/pci/triflex.c
--- linux-2.4.20/drivers/ide/pci/triflex.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/triflex.c	2003-03-26 23:49:30.000000000 +0000
@@ -0,0 +1,252 @@
+/*
+ * triflex.c
+ * 
+ * IDE Chipset driver for the Compaq TriFlex IDE controller.
+ * 
+ * Known to work with the Compaq Workstation 5x00 series.
+ *
+ * Copyright (C) 2002 Hewlett-Packard Development Group, L.P.
+ * Author: Torben Mathiasen <torben.mathiasen@hp.com>
+ *
+ * This program is free software; you can redistribute 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 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
+ * 
+ * Loosely based on the piix & svwks drivers.
+ *
+ * Documentation:
+ *	Not publically available.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include "ide_modes.h"
+#include "triflex.h"
+
+static struct pci_dev *triflex_dev;
+
+static int triflex_get_info(char *buf, char **addr, off_t offset, int count)
+{
+	char *p = buf;
+
+	struct pci_dev *dev	= triflex_dev;
+	unsigned long bibma = pci_resource_start(dev, 4);
+	u8  c0 = 0, c1 = 0;
+	u32 pri_timing, sec_timing;
+
+	p += sprintf(p, "\n                                Compaq Triflex Chipset\n");
+	
+	pci_read_config_dword(dev, 0x70, &pri_timing);
+	pci_read_config_dword(dev, 0x74, &sec_timing);
+
+	/*
+	 * at that point bibma+0x2 et bibma+0xa are byte registers
+	 * to investigate:
+	 */
+	c0 = inb((unsigned short)bibma + 0x02);
+	c1 = inb((unsigned short)bibma + 0x0a);
+
+	p += sprintf(p, "--------------- Primary Channel "
+			"---------------- Secondary Channel "
+			"-------------\n");
+	p += sprintf(p, "                %sabled "
+			"                        %sabled\n",
+			(c0&0x80) ? "dis" : " en",
+			(c1&0x80) ? "dis" : " en");
+	p += sprintf(p, "--------------- drive0 --------- drive1 "
+			"-------- drive0 ---------- drive1 ------\n");
+	p += sprintf(p, "DMA enabled:    %s              %s "
+			"            %s               %s\n",
+			(c0&0x20) ? "yes" : "no ",
+			(c0&0x40) ? "yes" : "no ",
+			(c1&0x20) ? "yes" : "no ",
+			(c1&0x40) ? "yes" : "no " );
+
+	p += sprintf(p, "DMA\n");
+	p += sprintf(p, "PIO\n");
+	
+	return p-buf;
+}
+
+static int triflex_tune_chipset(ide_drive_t *drive, u8 xferspeed)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	struct pci_dev *dev = hwif->pci_dev;
+	u8 channel_offset = hwif->channel ? 0x74 : 0x70;
+	u16 timing = 0;
+	u32 triflex_timings = 0;
+	u8 unit = (drive->select.b.unit & 0x01);
+	u8 speed = ide_rate_filter(0, xferspeed);
+	
+	pci_read_config_dword(dev, channel_offset, &triflex_timings);
+	
+	switch(speed) {
+		case XFER_MW_DMA_2:
+			timing = 0x0103; 
+			break;
+		case XFER_MW_DMA_1:
+			timing = 0x0203;
+			break;
+		case XFER_MW_DMA_0:
+			timing = 0x0808;
+			break;
+		case XFER_SW_DMA_2:
+		case XFER_SW_DMA_1:
+		case XFER_SW_DMA_0:
+			timing = 0x0f0f;
+			break;
+		case XFER_PIO_4:
+			timing = 0x0202;
+			break;
+		case XFER_PIO_3:
+			timing = 0x0204;
+			break;
+		case XFER_PIO_2:
+			timing = 0x0404;
+			break;
+		case XFER_PIO_1:
+			timing = 0x0508;
+			break;
+		case XFER_PIO_0:
+			timing = 0x0808;
+			break;
+		default:
+			return -1;
+	}
+
+	triflex_timings &= ~(0xFFFF << (16 * unit));
+	triflex_timings |= (timing << (16 * unit));
+	
+	pci_write_config_dword(dev, channel_offset, triflex_timings);
+	
+	return (ide_config_drive_speed(drive, speed));
+}
+
+static void triflex_tune_drive(ide_drive_t *drive, u8 pio)
+{
+	int use_pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+	(void) triflex_tune_chipset(drive, (XFER_PIO_0 + use_pio));
+}
+
+static int triflex_config_drive_for_dma(ide_drive_t *drive)
+{
+	int speed = ide_dma_speed(drive, 0); /* No ultra speeds */
+
+	if (!speed) { 
+		u8 pspeed = ide_get_best_pio_mode(drive, 255, 4, NULL);
+		speed = XFER_PIO_0 + pspeed;
+	}
+	
+	(void) triflex_tune_chipset(drive, speed);
+	 return ide_dma_enable(drive);
+}
+
+static int triflex_config_drive_xfer_rate(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id	= drive->id;
+	
+	if (id && (id->capability & 1) && drive->autodma) {
+		if (hwif->ide_dma_bad_drive(drive))
+			goto tune_pio;
+		if (id->field_valid & 2) {
+			if ((id->dma_mword & hwif->mwdma_mask) ||
+				(id->dma_1word & hwif->swdma_mask)) {
+				if (!triflex_config_drive_for_dma(drive))
+					goto tune_pio;
+			}
+		} else 
+			goto tune_pio;
+	} else {
+tune_pio:
+		hwif->tuneproc(drive, 255);
+		return hwif->ide_dma_off_quietly(drive);
+	}
+
+	return hwif->ide_dma_on(drive);
+}
+
+static void __init init_hwif_triflex(ide_hwif_t *hwif)
+{
+	hwif->tuneproc = &triflex_tune_drive;
+	hwif->speedproc = &triflex_tune_chipset;
+
+	hwif->atapi_dma  = 1;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+	hwif->ide_dma_check = &triflex_config_drive_xfer_rate;
+	
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+static unsigned int __init init_chipset_triflex(struct pci_dev *dev, 
+		const char *name) 
+{
+#ifdef CONFIG_PROC_FS
+	ide_pci_register_host_proc(&triflex_proc);
+#endif
+	return 0;	
+}
+
+static int __devinit triflex_init_one(struct pci_dev *dev, 
+		const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &triflex_devices[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	
+	ide_setup_pci_device(dev, d);
+	triflex_dev = dev;
+	MOD_INC_USE_COUNT;
+	
+	return 0;
+}
+
+static struct pci_driver driver = {
+	.name		= "TRIFLEX IDE",
+	.id_table	= triflex_pci_tbl,
+	.probe		= triflex_init_one,
+};
+
+static int triflex_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void triflex_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(triflex_ide_init);
+module_exit(triflex_ide_exit);
+
+MODULE_AUTHOR("Torben Mathiasen");
+MODULE_DESCRIPTION("PCI driver module for Compaq Triflex IDE");
+MODULE_LICENSE("GPL");
+
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/triflex.h linux-2.4.21-pre6/drivers/ide/pci/triflex.h
--- linux-2.4.20/drivers/ide/pci/triflex.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/triflex.h	2003-03-26 23:49:00.000000000 +0000
@@ -0,0 +1,55 @@
+/* 
+ * triflex.h
+ *
+ * Copyright (C) 2002 Hewlett-Packard Development Group, L.P.
+ * Author: Torben Mathiasen <torben.mathiasen@hp.com>
+ *
+ */
+#ifndef TRIFLEX_H
+#define TRIFLEX_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+static unsigned int __devinit init_chipset_triflex(struct pci_dev *, const char *);
+static void init_hwif_triflex(ide_hwif_t *);
+static int triflex_get_info(char *, char **, off_t, int);
+
+static ide_pci_device_t triflex_devices[] __devinitdata = {
+	{
+		.vendor 	PCI_VENDOR_ID_COMPAQ,
+		.device		PCI_DEVICE_ID_COMPAQ_TRIFLEX_IDE,
+		.name		"TRIFLEX",
+		.init_chipset	init_chipset_triflex,
+		.init_iops	NULL,
+		.init_hwif	init_hwif_triflex,
+		.channels	2,
+		.autodma	AUTODMA,
+		.enablebits	{{0x80, 0x01, 0x01}, {0x80, 0x02, 0x02}},
+		.bootable	ON_BOARD,
+		.extra		0,
+	},{	
+		.vendor		0,
+		.device		0,
+		.channels	0,
+		.bootable	EOL,
+	}
+};
+
+#ifdef CONFIG_PROC_FS
+static ide_pci_host_proc_t triflex_proc __initdata = {
+		name:		"triflex",
+		set:		1,
+		get_info: 	triflex_get_info,
+		parent: 	NULL,
+};
+#endif
+
+static struct pci_device_id triflex_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_TRIFLEX_IDE, PCI_ANY_ID, 
+		PCI_ANY_ID, 0, 0, 0 },
+	{ 0, },
+};
+
+#endif /* TRIFLEX_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/trm290.c linux-2.4.21-pre6/drivers/ide/pci/trm290.c
--- linux-2.4.20/drivers/ide/pci/trm290.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/trm290.c	2003-03-26 23:49:10.000000000 +0000
@@ -0,0 +1,452 @@
+/*
+ *  linux/drivers/ide/pci/trm290.c		Version 1.02	Mar. 18, 2000
+ *
+ *  Copyright (c) 1997-1998  Mark Lord
+ *  May be copied or modified under the terms of the GNU General Public License
+ */
+
+/*
+ * This module provides support for the bus-master IDE DMA function
+ * of the Tekram TRM290 chip, used on a variety of PCI IDE add-on boards,
+ * including a "Precision Instruments" board.  The TRM290 pre-dates
+ * the sff-8038 standard (ide-dma.c) by a few months, and differs
+ * significantly enough to warrant separate routines for some functions,
+ * while re-using others from ide-dma.c.
+ *
+ * EXPERIMENTAL!  It works for me (a sample of one).
+ *
+ * Works reliably for me in DMA mode (READs only),
+ * DMA WRITEs are disabled by default (see #define below);
+ *
+ * DMA is not enabled automatically for this chipset,
+ * but can be turned on manually (with "hdparm -d1") at run time.
+ *
+ * I need volunteers with "spare" drives for further testing
+ * and development, and maybe to help figure out the peculiarities.
+ * Even knowing the registers (below), some things behave strangely.
+ */
+
+#define TRM290_NO_DMA_WRITES	/* DMA writes seem unreliable sometimes */
+
+/*
+ * TRM-290 PCI-IDE2 Bus Master Chip
+ * ================================
+ * The configuration registers are addressed in normal I/O port space
+ * and are used as follows:
+ *
+ * trm290_base depends on jumper settings, and is probed for by ide-dma.c
+ *
+ * trm290_base+2 when WRITTEN: chiptest register (byte, write-only)
+ *	bit7 must always be written as "1"
+ *	bits6-2 undefined
+ *	bit1 1=legacy_compatible_mode, 0=native_pci_mode
+ *	bit0 1=test_mode, 0=normal(default)
+ *
+ * trm290_base+2 when READ: status register (byte, read-only)
+ *	bits7-2 undefined
+ *	bit1 channel0 busmaster interrupt status 0=none, 1=asserted
+ *	bit0 channel0 interrupt status 0=none, 1=asserted
+ *
+ * trm290_base+3 Interrupt mask register
+ *	bits7-5 undefined
+ *	bit4 legacy_header: 1=present, 0=absent
+ *	bit3 channel1 busmaster interrupt status 0=none, 1=asserted (read only)
+ *	bit2 channel1 interrupt status 0=none, 1=asserted (read only)
+ *	bit1 channel1 interrupt mask: 1=masked, 0=unmasked(default)
+ *	bit0 channel0 interrupt mask: 1=masked, 0=unmasked(default)
+ *
+ * trm290_base+1 "CPR" Config Pointer Register (byte)
+ *	bit7 1=autoincrement CPR bits 2-0 after each access of CDR
+ *	bit6 1=min. 1 wait-state posted write cycle (default), 0=0 wait-state
+ *	bit5 0=enabled master burst access (default), 1=disable  (write only)
+ *	bit4 PCI DEVSEL# timing select: 1=medium(default), 0=fast
+ *	bit3 0=primary IDE channel, 1=secondary IDE channel
+ *	bits2-0 register index for accesses through CDR port
+ *
+ * trm290_base+0 "CDR" Config Data Register (word)
+ *	two sets of seven config registers,
+ *	selected by CPR bit 3 (channel) and CPR bits 2-0 (index 0 to 6),
+ *	each index defined below:
+ *
+ * Index-0 Base address register for command block (word)
+ *	defaults: 0x1f0 for primary, 0x170 for secondary
+ *
+ * Index-1 general config register (byte)
+ *	bit7 1=DMA enable, 0=DMA disable
+ *	bit6 1=activate IDE_RESET, 0=no action (default)
+ *	bit5 1=enable IORDY, 0=disable IORDY (default)
+ *	bit4 0=16-bit data port(default), 1=8-bit (XT) data port
+ *	bit3 interrupt polarity: 1=active_low, 0=active_high(default)
+ *	bit2 power-saving-mode(?): 1=enable, 0=disable(default) (write only)
+ *	bit1 bus_master_mode(?): 1=enable, 0=disable(default)
+ *	bit0 enable_io_ports: 1=enable(default), 0=disable
+ *
+ * Index-2 read-ahead counter preload bits 0-7 (byte, write only)
+ *	bits7-0 bits7-0 of readahead count
+ *
+ * Index-3 read-ahead config register (byte, write only)
+ *	bit7 1=enable_readahead, 0=disable_readahead(default)
+ *	bit6 1=clear_FIFO, 0=no_action
+ *	bit5 undefined
+ *	bit4 mode4 timing control: 1=enable, 0=disable(default)
+ *	bit3 undefined
+ *	bit2 undefined
+ *	bits1-0 bits9-8 of read-ahead count
+ *
+ * Index-4 base address register for control block (word)
+ *	defaults: 0x3f6 for primary, 0x376 for secondary
+ *
+ * Index-5 data port timings (shared by both drives) (byte)
+ *	standard PCI "clk" (clock) counts, default value = 0xf5
+ *
+ *	bits7-6 setup time:  00=1clk, 01=2clk, 10=3clk, 11=4clk
+ *	bits5-3 hold time:	000=1clk, 001=2clk, 010=3clk,
+ *				011=4clk, 100=5clk, 101=6clk,
+ *				110=8clk, 111=12clk
+ *	bits2-0 active time:	000=2clk, 001=3clk, 010=4clk,
+ *				011=5clk, 100=6clk, 101=8clk,
+ *				110=12clk, 111=16clk
+ *
+ * Index-6 command/control port timings (shared by both drives) (byte)
+ *	same layout as Index-5, default value = 0xde
+ *
+ * Suggested CDR programming for PIO mode0 (600ns):
+ *	0x01f0,0x21,0xff,0x80,0x03f6,0xf5,0xde	; primary
+ *	0x0170,0x21,0xff,0x80,0x0376,0xf5,0xde	; secondary
+ *
+ * Suggested CDR programming for PIO mode3 (180ns):
+ *	0x01f0,0x21,0xff,0x80,0x03f6,0x09,0xde	; primary
+ *	0x0170,0x21,0xff,0x80,0x0376,0x09,0xde	; secondary
+ *
+ * Suggested CDR programming for PIO mode4 (120ns):
+ *	0x01f0,0x21,0xff,0x80,0x03f6,0x00,0xde	; primary
+ *	0x0170,0x21,0xff,0x80,0x0376,0x00,0xde	; secondary
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/init.h>
+#include <linux/hdreg.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+
+#include "trm290.h"
+
+static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	u16 reg = 0;
+	unsigned long flags;
+
+	/* select PIO or DMA */
+	reg = use_dma ? (0x21 | 0x82) : (0x21 & ~0x82);
+
+	local_irq_save(flags);
+
+	if (reg != hwif->select_data) {
+		hwif->select_data = reg;
+		/* set PIO/DMA */
+		hwif->OUTB(0x51|(hwif->channel<<3), hwif->config_data+1);
+		hwif->OUTW(reg & 0xff, hwif->config_data);
+	}
+
+	/* enable IRQ if not probing */
+	if (drive->present) {
+		reg = hwif->INW(hwif->config_data + 3);
+		reg &= 0x13;
+		reg &= ~(1 << hwif->channel);
+		hwif->OUTW(reg, hwif->config_data+3);
+	}
+
+	local_irq_restore(flags);
+}
+
+static void trm290_selectproc (ide_drive_t *drive)
+{
+	trm290_prepare_drive(drive, drive->using_dma);
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+static int trm290_ide_dma_write (ide_drive_t *drive /*, struct request *rq */)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct request *rq	= HWGROUP(drive)->rq;
+//	ide_task_t *args	= rq->special;
+	task_ioreg_t command	= WIN_NOP;
+	unsigned int count, reading = 2, writing = 0;
+
+	reading = 0;
+	writing = 1;
+#ifdef TRM290_NO_DMA_WRITES
+	/* always use PIO for writes */
+	trm290_prepare_drive(drive, 0);	/* select PIO xfer */
+	return 1;
+#endif
+	if (!(count = ide_build_dmatable(drive, rq, PCI_DMA_TODEVICE))) {
+		/* try PIO instead of DMA */
+		trm290_prepare_drive(drive, 0); /* select PIO xfer */
+		return 1;
+	}
+	/* select DMA xfer */
+	trm290_prepare_drive(drive, 1);
+	hwif->OUTL(hwif->dmatable_dma|reading|writing, hwif->dma_command);
+	drive->waiting_for_dma = 1;
+	/* start DMA */
+	hwif->OUTW((count * 2) - 1, hwif->dma_status);
+	if (drive->media != ide_disk)
+		return 0;
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
+	ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
+	/*
+	 * FIX ME to use only ACB ide_task_t args Struct
+	 */
+#if 0
+	{
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#else
+	command = /* (lba48) ? WIN_READDMA_EXT : */ WIN_READDMA;
+	if (rq->cmd == IDE_DRIVE_TASKFILE) {
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#endif
+	/* issue cmd to drive */
+	hwif->OUTB(command, IDE_COMMAND_REG);
+	return HWIF(drive)->ide_dma_count(drive);
+}
+
+static int trm290_ide_dma_read (ide_drive_t *drive  /*, struct request *rq */)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct request *rq	= HWGROUP(drive)->rq;
+//	ide_task_t *args	= rq->special;
+	task_ioreg_t command	= WIN_NOP;
+	unsigned int count, reading = 2, writing = 0;
+
+	if (!(count = ide_build_dmatable(drive, rq, PCI_DMA_FROMDEVICE))) {
+		/* try PIO instead of DMA */
+		trm290_prepare_drive(drive, 0); /* select PIO xfer */
+		return 1;
+	}
+	/* select DMA xfer */
+	trm290_prepare_drive(drive, 1);
+	hwif->OUTL(hwif->dmatable_dma|reading|writing, hwif->dma_command);
+	drive->waiting_for_dma = 1;
+	/* start DMA */
+	hwif->OUTW((count * 2) - 1, hwif->dma_status);
+	if (drive->media != ide_disk)
+		return 0;
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
+	ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
+	/*
+	 * FIX ME to use only ACB ide_task_t args Struct
+	 */
+#if 0
+	{
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#else
+	command = /* (lba48) ? WIN_WRITEDMA_EXT : */ WIN_WRITEDMA;
+	if (rq->cmd == IDE_DRIVE_TASKFILE) {
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#endif
+	/* issue cmd to drive */
+	hwif->OUTB(command, IDE_COMMAND_REG);
+	return HWIF(drive)->ide_dma_count(drive);
+}
+
+static int trm290_ide_dma_begin (ide_drive_t *drive)
+{
+	return 0;
+}
+
+static int trm290_ide_dma_end (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	u16 status = 0;;
+
+	drive->waiting_for_dma = 0;
+	/* purge DMA mappings */
+	ide_destroy_dmatable(drive);
+	status = hwif->INW(hwif->dma_status);
+	return (status != 0x00ff);
+}
+
+static int trm290_ide_dma_test_irq (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	u16 status = 0;
+
+	status = hwif->INW(hwif->dma_status);
+	return (status == 0x00ff);
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+/*
+ * Invoked from ide-dma.c at boot time.
+ */
+void __init init_hwif_trm290 (ide_hwif_t *hwif)
+{
+	unsigned int cfgbase = 0;
+	unsigned long flags;
+	u8 reg = 0;
+	struct pci_dev *dev = hwif->pci_dev;
+
+	hwif->addressing = 1;
+	hwif->chipset = ide_trm290;
+	cfgbase = pci_resource_start(dev, 4);
+	if ((dev->class & 5) && cfgbase) {
+		hwif->config_data = cfgbase;
+		printk(KERN_INFO "TRM290: chip config base at 0x%04lx\n",
+			hwif->config_data);
+	} else {
+		hwif->config_data = 0x3df0;
+		printk(KERN_INFO "TRM290: using default config base at 0x%04lx\n",
+			hwif->config_data);
+	}
+
+	local_irq_save(flags);
+	/* put config reg into first byte of hwif->select_data */
+	hwif->OUTB(0x51|(hwif->channel<<3), hwif->config_data+1);
+	/* select PIO as default */
+	hwif->select_data = 0x21;
+	hwif->OUTB(hwif->select_data, hwif->config_data);
+	/* get IRQ info */
+	reg = hwif->INB(hwif->config_data+3);
+	/* mask IRQs for both ports */
+	reg = (reg & 0x10) | 0x03;
+	hwif->OUTB(reg, hwif->config_data+3);
+	local_irq_restore(flags);
+
+	if ((reg & 0x10))
+		/* legacy mode */
+		hwif->irq = hwif->channel ? 15 : 14;
+	else if (!hwif->irq && hwif->mate && hwif->mate->irq)
+		/* sharing IRQ with mate */
+		hwif->irq = hwif->mate->irq;
+
+	ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->channel ? 0x0080 : 0x0000), 3);
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	hwif->ide_dma_write = &trm290_ide_dma_write;
+	hwif->ide_dma_read = &trm290_ide_dma_read;
+	hwif->ide_dma_begin = &trm290_ide_dma_begin;
+	hwif->ide_dma_end = &trm290_ide_dma_end;
+	hwif->ide_dma_test_irq = &trm290_ide_dma_test_irq;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+	hwif->selectproc = &trm290_selectproc;
+	hwif->autodma = 0;		/* play it safe for now */
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+#if 1
+	{
+	/*
+	 * My trm290-based card doesn't seem to work with all possible values
+	 * for the control basereg, so this kludge ensures that we use only
+	 * values that are known to work.  Ugh.		-ml
+	 */
+		u16 new, old, compat = hwif->channel ? 0x374 : 0x3f4;
+		static u16 next_offset = 0;
+		u8 old_mask;
+
+		hwif->OUTB(0x54|(hwif->channel<<3), hwif->config_data+1);
+		old = hwif->INW(hwif->config_data);
+		old &= ~1;
+		old_mask = hwif->INB(old+2);
+		if (old != compat && old_mask == 0xff) {
+			/* leave lower 10 bits untouched */
+			compat += (next_offset += 0x400);
+#  if 1
+			if (check_region(compat + 2, 1))
+				printk(KERN_ERR "%s: check_region failure at 0x%04x\n",
+					hwif->name, (compat + 2));
+			/*
+			 * The region check is not needed; however.........
+			 * Since this is the checked in ide-probe.c,
+			 * this is only an assignment.
+			 */
+#  endif
+			hwif->io_ports[IDE_CONTROL_OFFSET] = compat + 2;
+			hwif->OUTW(compat|1, hwif->config_data);
+			new = hwif->INW(hwif->config_data);
+			printk(KERN_INFO "%s: control basereg workaround: "
+				"old=0x%04x, new=0x%04x\n",
+				hwif->name, old, new & ~1);
+		}
+	}
+#endif
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static int __devinit trm290_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &trm290_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/**
+ *	trm290_remove_one	-	called when an trm290 is unplugged
+ *	@dev: the device that was removed
+ *
+ *	Disconnect a trm290 device that has been unplugged either by hotplug
+ *	or by a more civilized notification scheme. Not yet supported.
+ */
+ 
+static void trm290_remove_one(struct pci_dev *dev)
+{
+	printk("trm290 removal not yet supported.\n");
+}
+
+static struct pci_device_id trm290_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_TEKRAM, PCI_DEVICE_ID_TEKRAM_DC290, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	name:		"TRM290 IDE",
+	id_table:	trm290_pci_tbl,
+	probe:		trm290_init_one,
+	remove:		__devexit_p(trm290_remove_one),
+};
+
+static int trm290_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void trm290_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(trm290_ide_init);
+module_exit(trm290_ide_exit);
+
+MODULE_AUTHOR("Mark Lord");
+MODULE_DESCRIPTION("PCI driver module for Tekram TRM290 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/trm290.h linux-2.4.21-pre6/drivers/ide/pci/trm290.h
--- linux-2.4.20/drivers/ide/pci/trm290.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/trm290.h	2003-03-26 23:49:56.000000000 +0000
@@ -0,0 +1,32 @@
+#ifndef TRM290_H
+#define TRM290_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+extern void init_hwif_trm290(ide_hwif_t *);
+
+static ide_pci_device_t trm290_chipsets[] __devinitdata = {
+	{	/* 0 */
+		vendor:		PCI_VENDOR_ID_TEKRAM,
+		device:		PCI_DEVICE_ID_TEKRAM_DC290,
+		name:		"TRM290",
+		init_chipset:	NULL,
+		init_iops:	NULL,
+		init_hwif:	init_hwif_trm290,
+		init_dma:	NULL,
+		channels:	2,
+		autodma:	NOAUTODMA,
+		enablebits:	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},
+		bootable:	ON_BOARD,
+		extra:		0,
+	},{
+		vendor:		0,
+		device:		0,
+		channels:	0,
+		bootable:	EOL,
+	}
+};
+
+#endif /* TRM290_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/via82cxxx.c linux-2.4.21-pre6/drivers/ide/pci/via82cxxx.c
--- linux-2.4.20/drivers/ide/pci/via82cxxx.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/via82cxxx.c	2003-03-26 23:49:54.000000000 +0000
@@ -0,0 +1,675 @@
+/*
+ * $Id: via82cxxx.c,v 3.35-ac2 2002/09/111 Alan Exp $
+ *
+ *  Copyright (c) 2000-2001 Vojtech Pavlik
+ *
+ *  Based on the work of:
+ *	Michel Aubry
+ *	Jeff Garzik
+ *	Andre Hedrick
+ */
+
+/*
+ * Version 3.35
+ *
+ * VIA IDE driver for Linux. Supported southbridges:
+ *
+ *   vt82c576, vt82c586, vt82c586a, vt82c586b, vt82c596a, vt82c596b,
+ *   vt82c686, vt82c686a, vt82c686b, vt8231, vt8233, vt8233c, vt8233a,
+ *   vt8235
+ *
+ * Copyright (c) 2000-2002 Vojtech Pavlik
+ *
+ * Based on the work of:
+ *	Michel Aubry
+ *	Jeff Garzik
+ *	Andre Hedrick
+ *
+ * Documentation:
+ *	Obsolete device documentation publically available from via.com.tw
+ *	Current device documentation available under NDA only
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+#include <asm/io.h>
+
+#include "ide-timing.h"
+#include "via82cxxx.h"
+
+#define VIA_IDE_ENABLE		0x40
+#define VIA_IDE_CONFIG		0x41
+#define VIA_FIFO_CONFIG		0x43
+#define VIA_MISC_1		0x44
+#define VIA_MISC_2		0x45
+#define VIA_MISC_3		0x46
+#define VIA_DRIVE_TIMING	0x48
+#define VIA_8BIT_TIMING		0x4e
+#define VIA_ADDRESS_SETUP	0x4c
+#define VIA_UDMA_TIMING		0x50
+
+#define VIA_UDMA		0x007
+#define VIA_UDMA_NONE		0x000
+#define VIA_UDMA_33		0x001
+#define VIA_UDMA_66		0x002
+#define VIA_UDMA_100		0x003
+#define VIA_UDMA_133		0x004
+#define VIA_BAD_PREQ		0x010	/* Crashes if PREQ# till DDACK# set */
+#define VIA_BAD_CLK66		0x020	/* 66 MHz clock doesn't work correctly */
+#define VIA_SET_FIFO		0x040	/* Needs to have FIFO split set */
+#define VIA_NO_UNMASK		0x080	/* Doesn't work with IRQ unmasking on */
+#define VIA_BAD_ID		0x100	/* Has wrong vendor ID (0x1107) */
+
+/*
+ * VIA SouthBridge chips.
+ */
+
+static struct via_isa_bridge {
+	char *name;
+	u16 id;
+	u8 rev_min;
+	u8 rev_max;
+	u16 flags;
+} via_isa_bridges[] = {
+#ifdef FUTURE_BRIDGES
+	{ "vt8237",	PCI_DEVICE_ID_VIA_8237,     0x00, 0x2f, VIA_UDMA_133 },
+#endif
+	{ "vt8235",	PCI_DEVICE_ID_VIA_8235,     0x00, 0x2f, VIA_UDMA_133 },
+	{ "vt8233a",	PCI_DEVICE_ID_VIA_8233A,    0x00, 0x2f, VIA_UDMA_133 },
+	{ "vt8233c",	PCI_DEVICE_ID_VIA_8233C_0,  0x00, 0x2f, VIA_UDMA_100 },
+	{ "vt8233",	PCI_DEVICE_ID_VIA_8233_0,   0x00, 0x2f, VIA_UDMA_100 },
+	{ "vt8231",	PCI_DEVICE_ID_VIA_8231,     0x00, 0x2f, VIA_UDMA_100 },
+	{ "vt82c686b",	PCI_DEVICE_ID_VIA_82C686,   0x40, 0x4f, VIA_UDMA_100 },
+	{ "vt82c686a",	PCI_DEVICE_ID_VIA_82C686,   0x10, 0x2f, VIA_UDMA_66 },
+	{ "vt82c686",	PCI_DEVICE_ID_VIA_82C686,   0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 },
+	{ "vt82c596b",	PCI_DEVICE_ID_VIA_82C596,   0x10, 0x2f, VIA_UDMA_66 },
+	{ "vt82c596a",	PCI_DEVICE_ID_VIA_82C596,   0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 },
+	{ "vt82c586b",	PCI_DEVICE_ID_VIA_82C586_0, 0x47, 0x4f, VIA_UDMA_33 | VIA_SET_FIFO },
+	{ "vt82c586b",	PCI_DEVICE_ID_VIA_82C586_0, 0x40, 0x46, VIA_UDMA_33 | VIA_SET_FIFO | VIA_BAD_PREQ },
+	{ "vt82c586b",	PCI_DEVICE_ID_VIA_82C586_0, 0x30, 0x3f, VIA_UDMA_33 | VIA_SET_FIFO },
+	{ "vt82c586a",	PCI_DEVICE_ID_VIA_82C586_0, 0x20, 0x2f, VIA_UDMA_33 | VIA_SET_FIFO },
+	{ "vt82c586",	PCI_DEVICE_ID_VIA_82C586_0, 0x00, 0x0f, VIA_UDMA_NONE | VIA_SET_FIFO },
+	{ "vt82c576",	PCI_DEVICE_ID_VIA_82C576,   0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK },
+	{ "vt82c576",	PCI_DEVICE_ID_VIA_82C576,   0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK | VIA_BAD_ID },
+	{ NULL }
+};
+
+static struct via_isa_bridge *via_config;
+static unsigned char via_enabled;
+static unsigned int via_80w;
+static unsigned int via_clock;
+static char *via_dma[] = { "MWDMA16", "UDMA33", "UDMA66", "UDMA100", "UDMA133" };
+
+/*
+ * VIA /proc entry.
+ */
+
+#if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS)
+
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 via_proc = 0;
+static unsigned long via_base;
+static struct pci_dev *bmide_dev, *isa_dev;
+
+static char *via_control3[] = { "No limit", "64", "128", "192" };
+
+#define via_print(format, arg...) p += sprintf(p, format "\n" , ## arg)
+#define via_print_drive(name, format, arg...)\
+	p += sprintf(p, name); for (i = 0; i < 4; i++) p += sprintf(p, format, ## arg); p += sprintf(p, "\n");
+
+
+/**
+ *	via_get_info		-	generate via /proc file 
+ *	@buffer: buffer for data
+ *	@addr: set to start of data to use
+ *	@offset: current file offset
+ *	@count: size of read
+ *
+ *	Fills in buffer with the debugging/configuration information for
+ *	the VIA chipset tuning and attached drives
+ */
+ 
+static int via_get_info(char *buffer, char **addr, off_t offset, int count)
+{
+	int speed[4], cycle[4], setup[4], active[4], recover[4], den[4],
+		 uen[4], udma[4], umul[4], active8b[4], recover8b[4];
+	struct pci_dev *dev = bmide_dev;
+	unsigned int v, u, i;
+	u16 c, w;
+	u8 t, x;
+	char *p = buffer;
+
+	via_print("----------VIA BusMastering IDE Configuration"
+		"----------------");
+
+	via_print("Driver Version:                     3.35-ac");
+	via_print("South Bridge:                       VIA %s",
+		via_config->name);
+
+	pci_read_config_byte(isa_dev, PCI_REVISION_ID, &t);
+	pci_read_config_byte(dev, PCI_REVISION_ID, &x);
+	via_print("Revision:                           ISA %#x IDE %#x", t, x);
+	via_print("Highest DMA rate:                   %s",
+		via_dma[via_config->flags & VIA_UDMA]);
+
+	via_print("BM-DMA base:                        %#lx", via_base);
+	via_print("PCI clock:                          %d.%dMHz",
+		via_clock / 1000, via_clock / 100 % 10);
+
+	pci_read_config_byte(dev, VIA_MISC_1, &t);
+	via_print("Master Read  Cycle IRDY:            %dws",
+		(t & 64) >> 6);
+	via_print("Master Write Cycle IRDY:            %dws",
+		(t & 32) >> 5);
+	via_print("BM IDE Status Register Read Retry:  %s",
+		(t & 8) ? "yes" : "no");
+
+	pci_read_config_byte(dev, VIA_MISC_3, &t);
+	via_print("Max DRDY Pulse Width:               %s%s",
+		via_control3[(t & 0x03)], (t & 0x03) ? " PCI clocks" : "");
+
+	via_print("-----------------------Primary IDE"
+		"-------Secondary IDE------");
+	via_print("Read DMA FIFO flush:   %10s%20s",
+		(t & 0x80) ? "yes" : "no", (t & 0x40) ? "yes" : "no");
+	via_print("End Sector FIFO flush: %10s%20s",
+		(t & 0x20) ? "yes" : "no", (t & 0x10) ? "yes" : "no");
+
+	pci_read_config_byte(dev, VIA_IDE_CONFIG, &t);
+	via_print("Prefetch Buffer:       %10s%20s",
+		(t & 0x80) ? "yes" : "no", (t & 0x20) ? "yes" : "no");
+	via_print("Post Write Buffer:     %10s%20s",
+		(t & 0x40) ? "yes" : "no", (t & 0x10) ? "yes" : "no");
+
+	pci_read_config_byte(dev, VIA_IDE_ENABLE, &t);
+	via_print("Enabled:               %10s%20s",
+		(t & 0x02) ? "yes" : "no", (t & 0x01) ? "yes" : "no");
+
+	c = inb(via_base + 0x02) | (inb(via_base + 0x0a) << 8);
+	via_print("Simplex only:          %10s%20s",
+		(c & 0x80) ? "yes" : "no", (c & 0x8000) ? "yes" : "no");
+
+	via_print("Cable Type:            %10s%20s",
+		(via_80w & 1) ? "80w" : "40w", (via_80w & 2) ? "80w" : "40w");
+
+	via_print("-------------------drive0----drive1"
+		"----drive2----drive3-----");
+
+	pci_read_config_byte(dev, VIA_ADDRESS_SETUP, &t);
+	pci_read_config_dword(dev, VIA_DRIVE_TIMING, &v);
+	pci_read_config_word(dev, VIA_8BIT_TIMING, &w);
+
+	if (via_config->flags & VIA_UDMA)
+		pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
+	else u = 0;
+
+	for (i = 0; i < 4; i++) {
+
+		setup[i]     = ((t >> ((3 - i) << 1)) & 0x3) + 1;
+		recover8b[i] = ((w >> ((1 - (i >> 1)) << 3)) & 0xf) + 1;
+		active8b[i]  = ((w >> (((1 - (i >> 1)) << 3) + 4)) & 0xf) + 1;
+		active[i]    = ((v >> (((3 - i) << 3) + 4)) & 0xf) + 1;
+		recover[i]   = ((v >> ((3 - i) << 3)) & 0xf) + 1;
+		udma[i]      = ((u >> ((3 - i) << 3)) & 0x7) + 2;
+		umul[i]      = ((u >> (((3 - i) & 2) << 3)) & 0x8) ? 1 : 2;
+		uen[i]       = ((u >> ((3 - i) << 3)) & 0x20);
+		den[i]       = (c & ((i & 1) ? 0x40 : 0x20) << ((i & 2) << 2));
+
+		speed[i] = 2 * via_clock / (active[i] + recover[i]);
+		cycle[i] = 1000000 * (active[i] + recover[i]) / via_clock;
+
+		if (!uen[i] || !den[i])
+			continue;
+
+		switch (via_config->flags & VIA_UDMA) {
+
+			case VIA_UDMA_33:
+				speed[i] = 2 * via_clock / udma[i];
+				cycle[i] = 1000000 * udma[i] / via_clock;
+				break;
+
+			case VIA_UDMA_66:
+				speed[i] = 4 * via_clock / (udma[i] * umul[i]);
+				cycle[i] = 500000 * (udma[i] * umul[i]) / via_clock;
+				break;
+
+			case VIA_UDMA_100:
+				speed[i] = 6 * via_clock / udma[i];
+				cycle[i] = 333333 * udma[i] / via_clock;
+				break;
+
+			case VIA_UDMA_133:
+				speed[i] = 8 * via_clock / udma[i];
+				cycle[i] = 250000 * udma[i] / via_clock;
+				break;
+		}
+	}
+
+	via_print_drive("Transfer Mode: ", "%10s",
+		den[i] ? (uen[i] ? "UDMA" : "DMA") : "PIO");
+
+	via_print_drive("Address Setup: ", "%8dns",
+		1000000 * setup[i] / via_clock);
+	via_print_drive("Cmd Active:    ", "%8dns",
+		1000000 * active8b[i] / via_clock);
+	via_print_drive("Cmd Recovery:  ", "%8dns",
+		1000000 * recover8b[i] / via_clock);
+	via_print_drive("Data Active:   ", "%8dns",
+		1000000 * active[i] / via_clock);
+	via_print_drive("Data Recovery: ", "%8dns",
+		1000000 * recover[i] / via_clock);
+	via_print_drive("Cycle Time:    ", "%8dns",
+		cycle[i]);
+	via_print_drive("Transfer Rate: ", "%4d.%dMB/s",
+		speed[i] / 1000, speed[i] / 100 % 10);
+
+	/* hoping it is less than 4K... */
+	return p - buffer;
+}
+
+#endif /* DISPLAY_VIA_TIMINGS && CONFIG_PROC_FS */
+
+/**
+ *	via_set_speed			-	write timing registers
+ *	@dev: PCI device
+ *	@dn: device
+ *	@timing: IDE timing data to use
+ *
+ *	via_set_speed writes timing values to the chipset registers
+ */
+
+static void via_set_speed(struct pci_dev *dev, u8 dn, struct ide_timing *timing)
+{
+	u8 t;
+
+	pci_read_config_byte(dev, VIA_ADDRESS_SETUP, &t);
+	t = (t & ~(3 << ((3 - dn) << 1))) | ((FIT(timing->setup, 1, 4) - 1) << ((3 - dn) << 1));
+	pci_write_config_byte(dev, VIA_ADDRESS_SETUP, t);
+
+	pci_write_config_byte(dev, VIA_8BIT_TIMING + (1 - (dn >> 1)),
+		((FIT(timing->act8b, 1, 16) - 1) << 4) | (FIT(timing->rec8b, 1, 16) - 1));
+
+	pci_write_config_byte(dev, VIA_DRIVE_TIMING + (3 - dn),
+		((FIT(timing->active, 1, 16) - 1) << 4) | (FIT(timing->recover, 1, 16) - 1));
+
+	switch (via_config->flags & VIA_UDMA) {
+		case VIA_UDMA_33:  t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 5) - 2)) : 0x03; break;
+		case VIA_UDMA_66:  t = timing->udma ? (0xe8 | (FIT(timing->udma, 2, 9) - 2)) : 0x0f; break;
+		case VIA_UDMA_100: t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 9) - 2)) : 0x07; break;
+		case VIA_UDMA_133: t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 9) - 2)) : 0x07; break;
+		default: return;
+	}
+
+	pci_write_config_byte(dev, VIA_UDMA_TIMING + (3 - dn), t);
+}
+
+/**
+ *	via_set_drive		-	configure transfer mode
+ *	@drive: Drive to set up
+ *	@speed: desired speed
+ *
+ *	via_set_drive() computes timing values configures the drive and
+ *	the chipset to a desired transfer mode. It also can be called
+ *	by upper layers.
+ */
+
+static int via_set_drive(ide_drive_t *drive, u8 speed)
+{
+	ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1);
+	struct ide_timing t, p;
+	unsigned int T, UT;
+
+	if (speed != XFER_PIO_SLOW && speed != drive->current_speed)
+		if (ide_config_drive_speed(drive, speed))
+			printk(KERN_WARNING "ide%d: Drive %d didn't "
+				"accept speed setting. Oh, well.\n",
+				drive->dn >> 1, drive->dn & 1);
+
+	T = 1000000000 / via_clock;
+
+	switch (via_config->flags & VIA_UDMA) {
+		case VIA_UDMA_33:   UT = T;   break;
+		case VIA_UDMA_66:   UT = T/2; break;
+		case VIA_UDMA_100:  UT = T/3; break;
+		case VIA_UDMA_133:  UT = T/4; break;
+		default: UT = T;
+	}
+
+	ide_timing_compute(drive, speed, &t, T, UT);
+
+	if (peer->present) {
+		ide_timing_compute(peer, peer->current_speed, &p, T, UT);
+		ide_timing_merge(&p, &t, &t, IDE_TIMING_8BIT);
+	}
+
+	via_set_speed(HWIF(drive)->pci_dev, drive->dn, &t);
+
+	if (!drive->init_speed)
+		drive->init_speed = speed;
+	drive->current_speed = speed;
+
+	return 0;
+}
+
+/**
+ *	via82cxxx_tune_drive	-	PIO setup
+ *	@drive: drive to set up
+ *	@pio: mode to use (255 for 'best possible')
+ *
+ *	A callback from the upper layers for PIO-only tuning.
+ */
+
+static void via82cxxx_tune_drive(ide_drive_t *drive, u8 pio)
+{
+	if (!((via_enabled >> HWIF(drive)->channel) & 1))
+		return;
+
+	if (pio == 255) {
+		via_set_drive(drive,
+			ide_find_best_mode(drive, XFER_PIO | XFER_EPIO));
+		return;
+	}
+
+	via_set_drive(drive, XFER_PIO_0 + MIN(pio, 5));
+}
+
+/**
+ *	via82cxxx_ide_dma_check		-	set up for DMA if possible
+ *	@drive: IDE drive to set up
+ *
+ *	Set up the drive for the highest supported speed considering the
+ *	driver, controller and cable
+ */
+ 
+static int via82cxxx_ide_dma_check (ide_drive_t *drive)
+{
+	u16 w80 = HWIF(drive)->udma_four;
+
+	u16 speed = ide_find_best_mode(drive,
+		XFER_PIO | XFER_EPIO | XFER_SWDMA | XFER_MWDMA |
+		(via_config->flags & VIA_UDMA ? XFER_UDMA : 0) |
+		(w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_66 ? XFER_UDMA_66 : 0) |
+		(w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_100 ? XFER_UDMA_100 : 0) |
+		(w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_133 ? XFER_UDMA_133 : 0));
+
+	via_set_drive(drive, speed);
+
+	if (drive->autodma && (speed & XFER_MODE) != XFER_PIO)
+		return HWIF(drive)->ide_dma_on(drive);
+	return HWIF(drive)->ide_dma_off_quietly(drive);
+}
+
+/**
+ *	init_chipset_via82cxxx	-	initialization handler
+ *	@dev: PCI device
+ *	@name: Name of interface
+ *
+ *	The initialization callback. Here we determine the IDE chip type
+ *	and initialize its drive independent registers.
+ */
+
+static unsigned int __init init_chipset_via82cxxx(struct pci_dev *dev, const char *name)
+{
+	struct pci_dev *isa = NULL;
+	u8 t, v;
+	unsigned int u;
+	int i;
+
+	/*
+	 * Find the ISA bridge to see how good the IDE is.
+	 */
+
+	for (via_config = via_isa_bridges; via_config->id; via_config++)
+		if ((isa = pci_find_device(PCI_VENDOR_ID_VIA +
+			!!(via_config->flags & VIA_BAD_ID),
+			via_config->id, NULL))) {
+
+			pci_read_config_byte(isa, PCI_REVISION_ID, &t);
+			if (t >= via_config->rev_min &&
+			    t <= via_config->rev_max)
+				break;
+		}
+
+	if (!via_config->id) {
+		printk(KERN_WARNING "VP_IDE: Unknown VIA SouthBridge, disabling DMA.\n");
+		return -ENODEV;
+	}
+
+	/*
+	 * Check 80-wire cable presence and setup Clk66.
+	 */
+
+	switch (via_config->flags & VIA_UDMA) {
+
+		case VIA_UDMA_66:
+			/* Enable Clk66 */
+			pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
+			pci_write_config_dword(dev, VIA_UDMA_TIMING, u|0x80008);
+			for (i = 24; i >= 0; i -= 8)
+				if (((u >> (i & 16)) & 8) &&
+				    ((u >> i) & 0x20) &&
+				     (((u >> i) & 7) < 2)) {
+					/*
+					 * 2x PCI clock and
+					 * UDMA w/ < 3T/cycle
+					 */
+					via_80w |= (1 << (1 - (i >> 4)));
+				}
+			break;
+
+		case VIA_UDMA_100:
+			pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
+			for (i = 24; i >= 0; i -= 8)
+				if (((u >> i) & 0x10) ||
+				    (((u >> i) & 0x20) &&
+				     (((u >> i) & 7) < 4))) {
+					/* BIOS 80-wire bit or
+					 * UDMA w/ < 60ns/cycle
+					 */
+					via_80w |= (1 << (1 - (i >> 4)));
+				}
+			break;
+
+		case VIA_UDMA_133:
+			pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
+			for (i = 24; i >= 0; i -= 8)
+				if (((u >> i) & 0x10) ||
+				    (((u >> i) & 0x20) &&
+				     (((u >> i) & 7) < 8))) {
+					/* BIOS 80-wire bit or
+					 * UDMA w/ < 60ns/cycle
+					 */
+					via_80w |= (1 << (1 - (i >> 4)));
+				}
+			break;
+
+	}
+
+	/* Disable Clk66 */
+	if (via_config->flags & VIA_BAD_CLK66) {
+		/* Would cause trouble on 596a and 686 */
+		pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
+		pci_write_config_dword(dev, VIA_UDMA_TIMING, u & ~0x80008);
+	}
+
+	/*
+	 * Check whether interfaces are enabled.
+	 */
+
+	pci_read_config_byte(dev, VIA_IDE_ENABLE, &v);
+	via_enabled = ((v & 1) ? 2 : 0) | ((v & 2) ? 1 : 0);
+
+	/*
+	 * Set up FIFO sizes and thresholds.
+	 */
+
+	pci_read_config_byte(dev, VIA_FIFO_CONFIG, &t);
+
+	/* Disable PREQ# till DDACK# */
+	if (via_config->flags & VIA_BAD_PREQ) {
+		/* Would crash on 586b rev 41 */
+		t &= 0x7f;
+	}
+
+	/* Fix FIFO split between channels */
+	if (via_config->flags & VIA_SET_FIFO) {
+		t &= (t & 0x9f);
+		switch (via_enabled) {
+			case 1: t |= 0x00; break;	/* 16 on primary */
+			case 2: t |= 0x60; break;	/* 16 on secondary */
+			case 3: t |= 0x20; break;	/* 8 pri 8 sec */
+		}
+	}
+
+	pci_write_config_byte(dev, VIA_FIFO_CONFIG, t);
+
+	/*
+	 * Determine system bus clock.
+	 */
+
+	via_clock = system_bus_clock() * 1000;
+
+	switch (via_clock) {
+		case 33000: via_clock = 33333; break;
+		case 37000: via_clock = 37500; break;
+		case 41000: via_clock = 41666; break;
+	}
+
+	if (via_clock < 20000 || via_clock > 50000) {
+		printk(KERN_WARNING "VP_IDE: User given PCI clock speed "
+			"impossible (%d), using 33 MHz instead.\n", via_clock);
+		printk(KERN_WARNING "VP_IDE: Use ide0=ata66 if you want "
+			"to assume 80-wire cable.\n");
+		via_clock = 33333;
+	}
+
+	/*
+	 * Print the boot message.
+	 */
+
+	pci_read_config_byte(isa, PCI_REVISION_ID, &t);
+	printk(KERN_INFO "VP_IDE: VIA %s (rev %02x) IDE %s "
+		"controller on pci%s\n",
+		via_config->name, t,
+		via_dma[via_config->flags & VIA_UDMA],
+		dev->slot_name);
+
+	/*
+	 * Setup /proc/ide/via entry.
+	 */
+
+#if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS)
+	if (!via_proc) {
+		via_base = pci_resource_start(dev, 4);
+		bmide_dev = dev;
+		isa_dev = isa;
+		ide_pci_register_host_proc(&via_procs[0]);
+		via_proc = 1;
+	}
+#endif /* DISPLAY_VIA_TIMINGS && CONFIG_PROC_FS */
+	return 0;
+}
+
+static void __init init_hwif_via82cxxx(ide_hwif_t *hwif)
+{
+	int i;
+
+	hwif->autodma = 0;
+
+	hwif->tuneproc = &via82cxxx_tune_drive;
+	hwif->speedproc = &via_set_drive;
+
+	for (i = 0; i < 2; i++) {
+		hwif->drives[i].io_32bit = 1;
+		hwif->drives[i].unmask = (via_config->flags & VIA_NO_UNMASK) ? 0 : 1;
+		hwif->drives[i].autotune = 1;
+		hwif->drives[i].dn = hwif->channel * 2 + i;
+	}
+
+	if (!hwif->dma_base)
+		return;
+
+	hwif->atapi_dma = 1;
+	hwif->ultra_mask = 0x7f;
+	hwif->mwdma_mask = 0x07;
+	hwif->swdma_mask = 0x07;
+
+	if (!(hwif->udma_four))
+		hwif->udma_four = ((via_enabled & via_80w) >> hwif->channel) & 1;
+	hwif->ide_dma_check = &via82cxxx_ide_dma_check;
+	if (!noautodma)
+		hwif->autodma = 1;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
+}
+
+/**
+ *	init_dma_via82cxxx	-	set up for IDE DMA
+ *	@hwif: IDE interface
+ *	@dmabase: DMA base address
+ *
+ *	We allow the BM-DMA driver to only work on enabled interfaces.
+ */
+
+static void __init init_dma_via82cxxx(ide_hwif_t *hwif, unsigned long dmabase)
+{
+	if ((via_enabled >> hwif->channel) & 1)
+		ide_setup_dma(hwif, dmabase, 8);
+}
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+
+static int __devinit via_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &via82cxxx_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static struct pci_device_id via_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	.name 		= "VIA IDE",
+	.id_table 	= via_pci_tbl,
+	.probe 		= via_init_one,
+};
+
+static int via_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void via_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(via_ide_init);
+module_exit(via_ide_exit);
+
+MODULE_AUTHOR("Vojtech Pavlik, Michel Aubry, Jeff Garzik, Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for VIA IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pci/via82cxxx.h linux-2.4.21-pre6/drivers/ide/pci/via82cxxx.h
--- linux-2.4.20/drivers/ide/pci/via82cxxx.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pci/via82cxxx.h	2003-03-26 23:49:50.000000000 +0000
@@ -0,0 +1,67 @@
+#ifndef VIA82CXXX_H
+#define VIA82CXXX_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DISPLAY_VIA_TIMINGS
+
+#if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 via_proc;
+
+static int via_get_info(char *, char **, off_t, int);
+
+static ide_pci_host_proc_t via_procs[] __initdata = {
+	{
+		.name		= "via",
+		.set		= 1,
+		.get_info	= via_get_info,
+		.parent		= NULL,
+	},
+};
+#endif /* DISPLAY_VIA_TIMINGS && CONFIG_PROC_FS */
+
+static unsigned int init_chipset_via82cxxx(struct pci_dev *, const char *);
+static void init_hwif_via82cxxx(ide_hwif_t *);
+static void init_dma_via82cxxx(ide_hwif_t *, unsigned long);
+
+static ide_pci_device_t via82cxxx_chipsets[] __devinitdata = {
+	{	/* 0 */
+		.vendor		= PCI_VENDOR_ID_VIA,
+		.device		= PCI_DEVICE_ID_VIA_82C576_1,
+		.name		= "VP_IDE",
+		.init_chipset	= init_chipset_via82cxxx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_via82cxxx,
+		.init_dma	= init_dma_via82cxxx,
+		.channels	= 2,
+		.autodma	= NOAUTODMA,
+		.enablebits	= {{0x40,0x02,0x02}, {0x40,0x01,0x01}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{	/* 1 */
+		.vendor		= PCI_VENDOR_ID_VIA,
+		.device		= PCI_DEVICE_ID_VIA_82C586_1,
+		.name		= "VP_IDE",
+		.init_chipset	= init_chipset_via82cxxx,
+		.init_iops	= NULL,
+		.init_hwif	= init_hwif_via82cxxx,
+		.init_dma	= init_dma_via82cxxx,
+		.channels	= 2,
+		.autodma	= NOAUTODMA,
+		.enablebits	= {{0x40,0x02,0x02}, {0x40,0x01,0x01}},
+		.bootable	= ON_BOARD,
+		.extra		= 0,
+	},{
+		.vendor		= 0,
+		.device		= 0,
+		.channels	= 0,
+		.bootable	= EOL,
+	}
+};
+
+#endif /* VIA82CXXX_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pdc202xx.c linux-2.4.21-pre6/drivers/ide/pdc202xx.c
--- linux-2.4.20/drivers/ide/pdc202xx.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pdc202xx.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,1188 +0,0 @@
-/*
- *  linux/drivers/ide/pdc202xx.c	Version 0.32	Feb. 27, 2002
- *
- *  Copyright (C) 1998-2000	Andre Hedrick <andre@linux-ide.org>
- *  May be copied or modified under the terms of the GNU General Public License
- *
- *  Promise Ultra66 cards with BIOS v1.11 this
- *  compiled into the kernel if you have more than one card installed.
- *
- *  Promise Ultra100 cards with BIOS v2.01 this
- *  compiled into the kernel if you have more than one card installed.
- *
- *  Promise Ultra100TX2 with BIOS v2.10 & Ultra133TX2 with BIOS v2.20
- *  support 8 hard drives on UDMA mode.
- *
- *  Linux kernel will misunderstand FastTrak ATA-RAID series as Ultra
- *  IDE Controller, UNLESS you enable "CONFIG_PDC202XX_FORCE"
- *  That's you can use FastTrak ATA-RAID controllers as IDE controllers.
- *
- *  History :
- *  05/22/01    v1.20 b1
- *           (1) support PDC20268
- *           (2) fix cable judge function
- *  08/22/01    v1.20 b2
- *           (1) support ATA-133 PDC20269/75
- *           (2) support UDMA Mode 6
- *           (3) fix proc report information
- *           (4) set ATA133 timing
- *           (5) fix ultra dma bit 14 selectable
- *           (6) support 32bit LBA
- *  09/11/01    v1.20 b3 
- *           (1) fix eighty_ninty_three()
- *           (2) fix offset address 0x1c~0x1f
- *  10/30/01    v1.20 b4
- *           (1) fix 48bit LBA HOB bit
- *           (2) force rescan drive under PIO modes if need
- *  11/02/01    v1.20.0.5
- *           (1) could be patched with ext3 filesystem code
- *  11/06/01    v1.20.0.6
- *           (1) fix LBA48 drive running without Promise controllers
- *           (2) fix LBA48 drive running under PIO modes
- *  01/28/02    v1.20.0.6
- *           (1) release for linux IDE Group kernel 2.4.18
- *           (2) add version and controller info to proc
- *  05/23/02    v1.20.0.7
- *           (1) disable PDC20262 running with 48bit
- *           (2) Add quirk drive lists for PDC20265/67
- *
- *  Copyright (C) 1999-2002 Promise Technology, Inc.
- *  Author: Frank Tiernan <frankt@promise.com>
- *          PROMISE pdc202xx IDE Controller driver MAINTAINERS
- *  Released under terms of General Public License
- */
- 
-#define VERSION	"1.20.0.7"
-#define VERDATE "2002-05-23"
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include "ide_modes.h"
-
-#define PDC202XX_DEBUG_DRIVE_INFO		0
-#define PDC202XX_DECODE_REGISTER_INFO		0
-
-#define DISPLAY_PDC202XX_TIMINGS
-
-#ifndef SPLIT_BYTE
-#define SPLIT_BYTE(B,H,L)	((H)=(B>>4), (L)=(B-((B>>4)<<4)))
-#endif
-
-#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int pdc202xx_get_info(char *, char **, off_t, int);
-extern int (*pdc202xx_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-extern char *ide_media_verbose(ide_drive_t *);
-static struct pci_dev *bmide_dev;
-static struct hd_driveid *id[4];
-static int speed_rate[4];
-
-static char * pdc202xx_info (char *buf, struct pci_dev *dev)
-{
-	char *p = buf;
-
-	u32 bibma  = pci_resource_start(dev, 4);
-	u32 reg60h = 0, reg64h = 0, reg68h = 0, reg6ch = 0;
-	u16 reg50h = 0;
-	u16 word88 = 0;
-	int udmasel[4] = {0,0,0,0}, piosel[4] = {0,0,0,0};
-	int i = 0, hd = 0;
-
-        /*
-         * at that point bibma+0x2 et bibma+0xa are byte registers
-         * to investigate:
-         */
-	u8 c0	= inb_p((unsigned short)bibma + 0x02);
-	u8 c1	= inb_p((unsigned short)bibma + 0x0a);
-
-	u8 sc11	= inb_p((unsigned short)bibma + 0x11);
-	u8 sc1a	= inb_p((unsigned short)bibma + 0x1a);
-	u8 sc1b	= inb_p((unsigned short)bibma + 0x1b);
-	/* u8 sc1c	= inb_p((unsigned short)bibma + 0x1c); 
-	u8 sc1d	= inb_p((unsigned short)bibma + 0x1d);
-	u8 sc1e	= inb_p((unsigned short)bibma + 0x1e);
-	u8 sc1f	= inb_p((unsigned short)bibma + 0x1f); */
-
-	pci_read_config_word(dev, 0x50, &reg50h);
-	pci_read_config_dword(dev, 0x60, &reg60h);
-	pci_read_config_dword(dev, 0x64, &reg64h);
-	pci_read_config_dword(dev, 0x68, &reg68h);
-	pci_read_config_dword(dev, 0x6c, &reg6ch);
-
-	p+=sprintf(p, "\nPROMISE Ultra series driver Ver %s %s Adapter: ", VERSION, VERDATE);
-	switch(dev->device) {
-		case PCI_DEVICE_ID_PROMISE_20275:
-			p += sprintf(p, "MBUltra133\n");
-			break;
-		case PCI_DEVICE_ID_PROMISE_20269:
-			p += sprintf(p, "Ultra133 TX2\n");
-			break;
-		case PCI_DEVICE_ID_PROMISE_20268:
-			p += sprintf(p, "Ultra100 TX2\n");
-			break;
-		case PCI_DEVICE_ID_PROMISE_20267:
-			p += sprintf(p, "Ultra100\n");
-			break;
-		case PCI_DEVICE_ID_PROMISE_20265:
-			p += sprintf(p, "Ultra100 on M/B\n");
-			break;
-		case PCI_DEVICE_ID_PROMISE_20262:
-			p += sprintf(p, "Ultra66\n");
-			break;
-		case PCI_DEVICE_ID_PROMISE_20246:
-			p += sprintf(p, "Ultra33\n");
-			reg50h |= 0x0c00;
-			break;
-		default:
-			p += sprintf(p, "Ultra Series\n");
-			break;
-	}
-
-	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
-	p += sprintf(p, "                %s                         %s\n",
-		(c0&0x80)?"disabled":"enabled ",
-		(c1&0x80)?"disabled":"enabled ");
-	p += sprintf(p, "66 Clocking     %s                         %s\n",
-		(sc11&0x02)?"enabled ":"disabled",
-		(sc11&0x08)?"enabled ":"disabled");
-	p += sprintf(p, "Mode            %s                           %s\n",
-		(sc1a & 0x01) ? "MASTER" : "PCI   ",
-		(sc1b & 0x01) ? "MASTER" : "PCI   ");
-	p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
-	p += sprintf(p, "DMA enabled:    %s              %s             %s               %s\n",
-		(id[0]!=NULL && (c0&0x20))?"yes":"no ",(id[1]!=NULL && (c0&0x40))?"yes":"no ",
-		(id[2]!=NULL && (c1&0x20))?"yes":"no ",(id[3]!=NULL && (c1&0x40))?"yes":"no ");
-	for( hd = 0; hd < 4 ; hd++) {
-		if (id[hd] == NULL)
-			continue;
-		word88 = id[hd]->dma_ultra;
-		for ( i = 7 ; i >= 0 ; i--)
-			if (word88 >> (i+8)) {
-				udmasel[hd] = i;	/* get select UDMA mode */
-				break;
-			}
-		piosel[hd] = (id[hd]->eide_pio_modes >= 0x02) ? 4 : 3;
-        }
-	p += sprintf(p, "UDMA Mode:      %d                %d               %d                 %d\n",
-		udmasel[0], udmasel[1], udmasel[2], udmasel[3]);
-	p += sprintf(p, "PIO Mode:       %d                %d               %d                 %d\n",
-		piosel[0], piosel[1], piosel[2], piosel[3]);
-#if 0
-	p += sprintf(p, "--------------- Can ATAPI DMA ---------------\n");
-#endif
-	return (char *)p;
-}
-
-static int pdc202xx_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	
-	p = pdc202xx_info(buffer, bmide_dev);
-	return p-buffer;	/* => must be less than 4k! */
-}
-#endif  /* defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-byte pdc202xx_proc = 0;
-
-const char *pdc_quirk_drives[] = {
-	"QUANTUM FIREBALLlct08 08",
-	"QUANTUM FIREBALLP KA6.4",
-	"QUANTUM FIREBALLP KA9.1",
-	"QUANTUM FIREBALLP LM20.4",
-	"QUANTUM FIREBALLP KX13.6",
-	"QUANTUM FIREBALLP KX20.5",
-	"QUANTUM FIREBALLP KX27.3",
-	"QUANTUM FIREBALLP LM20.5",
-	NULL
-};
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-/* A Register */
-#define	SYNC_ERRDY_EN	0xC0
-
-#define	SYNC_IN		0x80	/* control bit, different for master vs. slave drives */
-#define	ERRDY_EN	0x40	/* control bit, different for master vs. slave drives */
-#define	IORDY_EN	0x20	/* PIO: IOREADY */
-#define	PREFETCH_EN	0x10	/* PIO: PREFETCH */
-
-#define	PA3		0x08	/* PIO"A" timing */
-#define	PA2		0x04	/* PIO"A" timing */
-#define	PA1		0x02	/* PIO"A" timing */
-#define	PA0		0x01	/* PIO"A" timing */
-
-/* B Register */
-
-#define	MB2		0x80	/* DMA"B" timing */
-#define	MB1		0x40	/* DMA"B" timing */
-#define	MB0		0x20	/* DMA"B" timing */
-
-#define	PB4		0x10	/* PIO_FORCE 1:0 */
-
-#define	PB3		0x08	/* PIO"B" timing */	/* PIO flow Control mode */
-#define	PB2		0x04	/* PIO"B" timing */	/* PIO 4 */
-#define	PB1		0x02	/* PIO"B" timing */	/* PIO 3 half */
-#define	PB0		0x01	/* PIO"B" timing */	/* PIO 3 other half */
-
-/* C Register */
-#define	IORDYp_NO_SPEED	0x4F
-#define	SPEED_DIS	0x0F
-
-#define	DMARQp		0x80
-#define	IORDYp		0x40
-#define	DMAR_EN		0x20
-#define	DMAW_EN		0x10
-
-#define	MC3		0x08	/* DMA"C" timing */
-#define	MC2		0x04	/* DMA"C" timing */
-#define	MC1		0x02	/* DMA"C" timing */
-#define	MC0		0x01	/* DMA"C" timing */
-
-#if PDC202XX_DECODE_REGISTER_INFO
-
-#define REG_A		0x01
-#define REG_B		0x02
-#define REG_C		0x04
-#define REG_D		0x08
-
-static void decode_registers (byte registers, byte value)
-{
-	byte	bit = 0, bit1 = 0, bit2 = 0;
-
-	switch(registers) {
-		case REG_A:
-			bit2 = 0;
-			printk("A Register ");
-			if (value & 0x80) printk("SYNC_IN ");
-			if (value & 0x40) printk("ERRDY_EN ");
-			if (value & 0x20) printk("IORDY_EN ");
-			if (value & 0x10) printk("PREFETCH_EN ");
-			if (value & 0x08) { printk("PA3 ");bit2 |= 0x08; }
-			if (value & 0x04) { printk("PA2 ");bit2 |= 0x04; }
-			if (value & 0x02) { printk("PA1 ");bit2 |= 0x02; }
-			if (value & 0x01) { printk("PA0 ");bit2 |= 0x01; }
-			printk("PIO(A) = %d ", bit2);
-			break;
-		case REG_B:
-			bit1 = 0;bit2 = 0;
-			printk("B Register ");
-			if (value & 0x80) { printk("MB2 ");bit1 |= 0x80; }
-			if (value & 0x40) { printk("MB1 ");bit1 |= 0x40; }
-			if (value & 0x20) { printk("MB0 ");bit1 |= 0x20; }
-			printk("DMA(B) = %d ", bit1 >> 5);
-			if (value & 0x10) printk("PIO_FORCED/PB4 ");
-			if (value & 0x08) { printk("PB3 ");bit2 |= 0x08; }
-			if (value & 0x04) { printk("PB2 ");bit2 |= 0x04; }
-			if (value & 0x02) { printk("PB1 ");bit2 |= 0x02; }
-			if (value & 0x01) { printk("PB0 ");bit2 |= 0x01; }
-			printk("PIO(B) = %d ", bit2);
-			break;
-		case REG_C:
-			bit2 = 0;
-			printk("C Register ");
-			if (value & 0x80) printk("DMARQp ");
-			if (value & 0x40) printk("IORDYp ");
-			if (value & 0x20) printk("DMAR_EN ");
-			if (value & 0x10) printk("DMAW_EN ");
-
-			if (value & 0x08) { printk("MC3 ");bit2 |= 0x08; }
-			if (value & 0x04) { printk("MC2 ");bit2 |= 0x04; }
-			if (value & 0x02) { printk("MC1 ");bit2 |= 0x02; }
-			if (value & 0x01) { printk("MC0 ");bit2 |= 0x01; }
-			printk("DMA(C) = %d ", bit2);
-			break;
-		case REG_D:
-			printk("D Register ");
-			break;
-		default:
-			return;
-	}
-	printk("\n        %s ", (registers & REG_D) ? "DP" :
-				(registers & REG_C) ? "CP" :
-				(registers & REG_B) ? "BP" :
-				(registers & REG_A) ? "AP" : "ERROR");
-	for (bit=128;bit>0;bit/=2)
-		printk("%s", (value & bit) ? "1" : "0");
-	printk("\n");
-}
-
-#endif /* PDC202XX_DECODE_REGISTER_INFO */
-
-static int check_in_drive_lists (ide_drive_t *drive, const char **list)
-{
-	struct hd_driveid *id = drive->id;
-
-	if (pdc_quirk_drives == list) {
-		while (*list) {
-			if (strstr(id->model, *list++)) {
-				return 2;
-			}
-		}
-	} else {
-		while (*list) {
-			if (!strcmp(*list++,id->model)) {
-				return 1;
-			}
-		}
-	}
-	return 0;
-}
-
-static int pdc202xx_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-
-	unsigned int		drive_conf;
-	int			err = 0, i = 0, j = hwif->channel ? 2 : 0 ;
-	byte			drive_pci, AP, BP, CP, DP;
-	byte			TA = 0, TB = 0, TC = 0;
-
-	switch (drive->dn) {
-		case 0: drive_pci = 0x60; break;
-		case 1: drive_pci = 0x64; break;
-		case 2: drive_pci = 0x68; break;
-		case 3: drive_pci = 0x6c; break;
-		default: return -1;
-	}
-
-	if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))	return -1;
-
-	pci_read_config_dword(dev, drive_pci, &drive_conf);
-	pci_read_config_byte(dev, (drive_pci), &AP);
-	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
-	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
-	pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (speed >= XFER_SW_DMA_0) {
-		if ((BP & 0xF0) && (CP & 0x0F)) {
-			/* clear DMA modes of upper 842 bits of B Register */
-			/* clear PIO forced mode upper 1 bit of B Register */
-			pci_write_config_byte(dev, (drive_pci)|0x01, BP & ~0xF0);
-			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
-
-			/* clear DMA modes of lower 8421 bits of C Register */
-			pci_write_config_byte(dev, (drive_pci)|0x02, CP & ~0x0F);
-			pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
-		}
-	} else {
-#else
-	{
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-		if ((AP & 0x0F) || (BP & 0x07)) {
-			/* clear PIO modes of lower 8421 bits of A Register */
-			pci_write_config_byte(dev, (drive_pci), AP & ~0x0F);
-			pci_read_config_byte(dev, (drive_pci), &AP);
-
-			/* clear PIO modes of lower 421 bits of B Register */
-			pci_write_config_byte(dev, (drive_pci)|0x01, BP & ~0x07);
-			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
-
-			pci_read_config_byte(dev, (drive_pci), &AP);
-			pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
-		}
-	}
-
-	pci_read_config_byte(dev, (drive_pci), &AP);
-	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
-	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
-
-	for ( i = 0; i < 2; i++)
-		if (hwif->drives[i].present)
-	  		id[i+j] = hwif->drives[i].id;	/* get identify structs */
-
-	switch(speed) {
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		/* case XFER_UDMA_6: */
-		case XFER_UDMA_5:
-		case XFER_UDMA_4:	TB = 0x20; TC = 0x01; break;	/* speed 8 == UDMA mode 4 */
-		case XFER_UDMA_3:	TB = 0x40; TC = 0x02; break;	/* speed 7 == UDMA mode 3 */
-		case XFER_UDMA_2:	TB = 0x20; TC = 0x01; break;	/* speed 6 == UDMA mode 2 */
-		case XFER_UDMA_1:	TB = 0x40; TC = 0x02; break;	/* speed 5 == UDMA mode 1 */
-		case XFER_UDMA_0:	TB = 0x60; TC = 0x03; break;	/* speed 4 == UDMA mode 0 */
-		case XFER_MW_DMA_2:	TB = 0x60; TC = 0x03; break;	/* speed 4 == MDMA mode 2 */
-		case XFER_MW_DMA_1:	TB = 0x60; TC = 0x04; break;	/* speed 3 == MDMA mode 1 */
-		case XFER_MW_DMA_0:	TB = 0x60; TC = 0x05; break;	/* speed 2 == MDMA mode 0 */
-		case XFER_SW_DMA_2:	TB = 0x60; TC = 0x05; break;	/* speed 0 == SDMA mode 2 */
-		case XFER_SW_DMA_1:	TB = 0x80; TC = 0x06; break;	/* speed 1 == SDMA mode 1 */
-		case XFER_SW_DMA_0:	TB = 0xC0; TC = 0x0B; break;	/* speed 0 == SDMA mode 0 */
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-		case XFER_PIO_4:	TA = 0x01; TB = 0x04; break;
-		case XFER_PIO_3:	TA = 0x02; TB = 0x06; break;
-		case XFER_PIO_2:	TA = 0x03; TB = 0x08; break;
-		case XFER_PIO_1:	TA = 0x05; TB = 0x0C; break;
-		case XFER_PIO_0:
-		default:		TA = 0x09; TB = 0x13; break;
-	}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-        if (speed >= XFER_SW_DMA_0) {
-		pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
-		pci_write_config_byte(dev, (drive_pci)|0x02, CP|TC);
-	} else {
-#else
-	{
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-		pci_write_config_byte(dev, (drive_pci), AP|TA);
-		pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
-	}
-
-#if PDC202XX_DECODE_REGISTER_INFO
-	pci_read_config_byte(dev, (drive_pci), &AP);
-	pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
-	pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
-	pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
-
-	decode_registers(REG_A, AP);
-	decode_registers(REG_B, BP);
-	decode_registers(REG_C, CP);
-	decode_registers(REG_D, DP);
-#endif /* PDC202XX_DECODE_REGISTER_INFO */
-
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-	err = ide_config_drive_speed(drive, speed);
-	drive->current_speed = speed;
-
-#if PDC202XX_DEBUG_DRIVE_INFO
-	printk("%s: %s drive%d 0x%08x ",
-		drive->name, ide_xfer_verbose(speed),
-		drive->dn, drive_conf);
-		pci_read_config_dword(dev, drive_pci, &drive_conf);
-	printk("0x%08x\n", drive_conf);
-#endif /* PDC202XX_DEBUG_DRIVE_INFO */
-	return err;
-}
-
-static int pdc202xx_new_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	unsigned long indexreg	= (hwif->dma_base + 1);
-	unsigned long datareg	= (hwif->dma_base + 3);
-#else
-	struct pci_dev *dev	= hwif->pci_dev;
-	unsigned long high_16	= pci_resource_start(dev, 4);
-	unsigned long indexreg	= high_16 + (hwif->channel ? 0x09 : 0x01);
-	unsigned long datareg	= (indexreg + 2);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-	byte thold		= 0x10;
-	byte adj		= (drive->dn%2) ? 0x08 : 0x00;
-	int set_speed		= 0, i=0, j=hwif->channel ? 2:0;
-	int                     err;
-
-	/* Setting tHOLD bit to 0 if using UDMA mode 2 */
-	if (speed == XFER_UDMA_2) {
-		OUT_BYTE((thold + adj), indexreg);
-		OUT_BYTE((IN_BYTE(datareg) & 0x7f), datareg);
-	}
-	
-	/* We need to set ATA133 timing if ATA133 drives exist */
-	if (speed>=XFER_UDMA_6)
-		set_speed=1;
-
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-#if PDC202XX_DEBUG_DRIVE_INFO
-	printk("%s: Before set_feature = %s, word88 = %#x\n",
-		drive->name, ide_xfer_verbose(speed), drive->id->dma_ultra );
-#endif /* PDC202XX_DEBUG_DRIVE_INFO */
-	err = ide_config_drive_speed(drive, speed);
-	drive->current_speed = speed;	
-	for ( i = 0 ; i < 2 ; i++)
-		if (hwif->drives[i].present) {
-	  		id[i+j] = hwif->drives[i].id;	/* get identify structs */
-	 		speed_rate[i+j] = speed;	/* get current speed */
-	 	}
-	if (set_speed) {
-		for (i=0; i<4; i++) {
-			if (id[i]==NULL)
-				continue;
-			switch(speed_rate[i]) {
-#ifdef CONFIG_BLK_DEV_IDEDMA
-				case XFER_UDMA_6:
-					OUT_BYTE((0x10 + adj), indexreg);
-					OUT_BYTE(0x1a, datareg);
-					OUT_BYTE((0x11 + adj), indexreg);
-					OUT_BYTE(0x01, datareg);
-					OUT_BYTE((0x12 + adj), indexreg);
-					OUT_BYTE(0xcb, datareg);
-					break;
-				case XFER_UDMA_5:
-					OUT_BYTE((0x10 + adj), indexreg);
-					OUT_BYTE(0x1a, datareg);
-					OUT_BYTE((0x11 + adj), indexreg);
-					OUT_BYTE(0x02, datareg);
-					OUT_BYTE((0x12 + adj), indexreg);
-					OUT_BYTE(0xcb, datareg);
-					break;
-				case XFER_UDMA_4:
-					OUT_BYTE((0x10 + adj), indexreg);
-					OUT_BYTE(0x1a, datareg);
-					OUT_BYTE((0x11 + adj), indexreg);
-					OUT_BYTE(0x03, datareg);
-					OUT_BYTE((0x12 + adj), indexreg);
-					OUT_BYTE(0xcd, datareg);
-					break;
-				case XFER_UDMA_3:
-					OUT_BYTE((0x10 + adj), indexreg);
-					OUT_BYTE(0x1a, datareg);
-					OUT_BYTE((0x11 + adj), indexreg);
-					OUT_BYTE(0x05, datareg);
-					OUT_BYTE((0x12 + adj), indexreg);
-					OUT_BYTE(0xcd, datareg);
-					break;
-				case XFER_UDMA_2:
-					OUT_BYTE((0x10 + adj), indexreg);
-					OUT_BYTE(0x2a, datareg);
-					OUT_BYTE((0x11 + adj), indexreg);
-					OUT_BYTE(0x07, datareg);
-					OUT_BYTE((0x12 + adj), indexreg);
-					OUT_BYTE(0xcd, datareg);
-					break;
-				case XFER_UDMA_1:
-					OUT_BYTE((0x10 + adj), indexreg);
-					OUT_BYTE(0x3a, datareg);
-					OUT_BYTE((0x11 + adj), indexreg);
-					OUT_BYTE(0x0a, datareg);
-					OUT_BYTE((0x12 + adj), indexreg);
-					OUT_BYTE(0xd0, datareg);
-					break;
-				case XFER_UDMA_0:
-					OUT_BYTE((0x10 + adj), indexreg);
-					OUT_BYTE(0x4a, datareg);
-					OUT_BYTE((0x11 + adj), indexreg);
-					OUT_BYTE(0x0f, datareg);
-					OUT_BYTE((0x12 + adj), indexreg);
-					OUT_BYTE(0xd5, datareg);
-					break;
-				case XFER_MW_DMA_2:
-					OUT_BYTE((0x0e + adj), indexreg);
-					OUT_BYTE(0x69, datareg);
-					OUT_BYTE((0x0f + adj), indexreg);
-					OUT_BYTE(0x25, datareg);
-					break;
-				case XFER_MW_DMA_1:
-					OUT_BYTE((0x0e + adj), indexreg);
-					OUT_BYTE(0x6b, datareg);
-					OUT_BYTE((0x0f+ adj), indexreg);
-					OUT_BYTE(0x27, datareg);
-					break;
-				case XFER_MW_DMA_0:
-					OUT_BYTE((0x0e + adj), indexreg);
-					OUT_BYTE(0xdf, datareg);
-					OUT_BYTE((0x0f + adj), indexreg);
-					OUT_BYTE(0x5f, datareg);
-					break;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-				case XFER_PIO_4:
-					OUT_BYTE((0x0c + adj), indexreg);
-					OUT_BYTE(0x23, datareg);
-					OUT_BYTE((0x0d + adj), indexreg);
-					OUT_BYTE(0x09, datareg);
-					OUT_BYTE((0x13 + adj), indexreg);
-					OUT_BYTE(0x25, datareg);
-					break;
-				case XFER_PIO_3:
-					OUT_BYTE((0x0c + adj), indexreg);
-					OUT_BYTE(0x27, datareg);
-					OUT_BYTE((0x0d + adj), indexreg);
-					OUT_BYTE(0x0d, datareg);
-					OUT_BYTE((0x13 + adj), indexreg);
-					OUT_BYTE(0x35, datareg);
-					break;
-				case XFER_PIO_2:
-					OUT_BYTE((0x0c + adj), indexreg);
-					OUT_BYTE(0x23, datareg);
-					OUT_BYTE((0x0d + adj), indexreg);
-					OUT_BYTE(0x26, datareg);
-					OUT_BYTE((0x13 + adj), indexreg);
-					OUT_BYTE(0x64, datareg);
-					break;
-				case XFER_PIO_1:
-					OUT_BYTE((0x0c + adj), indexreg);
-					OUT_BYTE(0x46, datareg);
-					OUT_BYTE((0x0d + adj), indexreg);
-					OUT_BYTE(0x29, datareg);
-					OUT_BYTE((0x13 + adj), indexreg);
-					OUT_BYTE(0xa4, datareg);
-					break;
-				case XFER_PIO_0:
-					OUT_BYTE((0x0c + adj), indexreg);
-					OUT_BYTE(0xfb, datareg);
-					OUT_BYTE((0x0d + adj), indexreg);
-					OUT_BYTE(0x2b, datareg);
-					OUT_BYTE((0x13 + adj), indexreg);
-					OUT_BYTE(0xac, datareg);
-					break;
-				default:
-			}
-		}
-	}
-	return err;
-}
-
-/*   0    1    2    3    4    5    6   7   8
- * 960, 480, 390, 300, 240, 180, 120, 90, 60
- *           180, 150, 120,  90,  60
- * DMA_Speed
- * 180, 120,  90,  90,  90,  60,  30
- *  11,   5,   4,   3,   2,   1,   0
- */
-static int config_chipset_for_pio (ide_drive_t *drive, byte pio)
-{
-	byte speed = 0x00;
-
-	pio = (pio == 5) ? 4 : pio;
-	speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, pio, NULL);
-        
-	return ((int) pdc202xx_tune_chipset(drive, speed));
-}
-
-static void pdc202xx_tune_drive (ide_drive_t *drive, byte pio)
-{
-	(void) config_chipset_for_pio(drive, pio);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
-{
-	struct hd_driveid *id	= drive->id;
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	unsigned long high_16   = pci_resource_start(dev, 4);
-	unsigned long dma_base  = hwif->dma_base;
-	unsigned long indexreg	= dma_base + 1;
-	unsigned long datareg	= dma_base + 3;
-	byte iordy		= 0x13;
-	byte adj		= (drive->dn%2) ? 0x08 : 0x00;
-	byte cable		= 0;
-	byte new_chip		= 0;
-	byte unit		= (drive->select.b.unit & 0x01);
-	unsigned int		drive_conf;
-	byte			drive_pci = 0;
-	byte			test1, test2, speed = -1;
-	byte			AP;
-	unsigned short		EP;
-	byte CLKSPD		= 0;
-	byte clockreg		= high_16 + 0x11;
-	byte udma_33		= ultra;
-	byte udma_66		= ((eighty_ninty_three(drive)) && udma_33) ? 1 : 0;
-	byte udma_100		= 0;
-	byte udma_133		= 0;
-	byte mask			= hwif->channel ? 0x08 : 0x02;
-	unsigned short c_mask	= hwif->channel ? (1<<11) : (1<<10);
-
-	byte ultra_66		= ((id->dma_ultra & 0x0010) ||
-				   (id->dma_ultra & 0x0008)) ? 1 : 0;
-	byte ultra_100		= ((id->dma_ultra & 0x0020) ||
-				   (ultra_66)) ? 1 : 0;
-	byte ultra_133		= ((id->dma_ultra & 0x0040) ||
-				   (ultra_100)) ? 1 : 0;
-
-	switch(dev->device) {
-		case PCI_DEVICE_ID_PROMISE_20276:
-		case PCI_DEVICE_ID_PROMISE_20275:
-		case PCI_DEVICE_ID_PROMISE_20269:
-			udma_133 = (udma_66) ? 1 : 0;
-			udma_100 = (udma_66) ? 1 : 0;
-			OUT_BYTE(0x0b, (hwif->dma_base + 1));
-			cable = ((IN_BYTE((hwif->dma_base + 3)) & 0x04));
-			new_chip = 1;
-			break;
-		case PCI_DEVICE_ID_PROMISE_20268:
-		case PCI_DEVICE_ID_PROMISE_20270:
-			udma_100 = (udma_66) ? 1 : 0;
-			OUT_BYTE(0x0b, (hwif->dma_base + 1));
-			cable = ((IN_BYTE((hwif->dma_base + 3)) & 0x04));
-			new_chip = 1;
-			break;
-		case PCI_DEVICE_ID_PROMISE_20267:
-		case PCI_DEVICE_ID_PROMISE_20265:
-			udma_100 = (udma_66) ? 1 : 0;
-			pci_read_config_word(dev, 0x50, &EP);
-			cable = (EP & c_mask);
-			new_chip = 0;
-			CLKSPD = IN_BYTE(clockreg);
-			break;
-		case PCI_DEVICE_ID_PROMISE_20262:
-			pci_read_config_word(dev, 0x50, &EP);
-			cable = (EP & c_mask);
-			new_chip = 0;
-			CLKSPD = IN_BYTE(clockreg);
-			break;
-		default:
-			udma_100 = 0; udma_133 = 0; cable = 0; new_chip = 1;
-			break;
-	}
-
-	/*
-	 * Set the control register to use the 66Mhz system
-	 * clock for UDMA 3/4 mode operation. If one drive on
-	 * a channel is U66 capable but the other isn't we
-	 * fall back to U33 mode. The BIOS INT 13 hooks turn
-	 * the clock on then off for each read/write issued. I don't
-	 * do that here because it would require modifying the
-	 * kernel, seperating the fop routines from the kernel or
-	 * somehow hooking the fops calls. It may also be possible to
-	 * leave the 66Mhz clock on and readjust the timing
-	 * parameters.
-	 */
-
-	if (((ultra_66) || (ultra_100) || (ultra_133)) && (cable)) {
-#ifdef DEBUG
-		printk("ULTRA66: %s channel of Ultra 66 requires an 80-pin cable for Ultra66 operation.\n", hwif->channel ? "Secondary" : "Primary");
-		printk("         Switching to Ultra33 mode.\n");
-#endif /* DEBUG */
-		/* Primary   : zero out second bit */
-		/* Secondary : zero out fourth bit */
-		//if (!new_chip)
-		OUT_BYTE(CLKSPD & ~mask, clockreg);
-		printk("Warning: %s channel requires an 80-pin cable for operation.\n", hwif->channel ? "Secondary":"Primary");
-		printk("%s reduced to Ultra33 mode.\n", drive->name);
-		udma_66 = 0; udma_100 = 0; udma_133 = 0;
-	} else {
-		if ((ultra_66) || (ultra_100) || (ultra_133)) {
-			/*
-			 * check to make sure drive on same channel
-			 * is u66 capable
-			 */
-			if (hwif->drives[!(drive->dn%2)].id) {
-				if ((hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0040) ||
-				    (hwif->drives[!(drive->dn%2)].id->dma_ultra
-& 0x0020) ||
-				    (hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0010) ||
-				    (hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0008)) {
-					OUT_BYTE(CLKSPD | mask, clockreg);
-				} else {
-					OUT_BYTE(CLKSPD & ~mask, clockreg);
-				}
-			} else { /* udma4 drive by itself */
-				OUT_BYTE(CLKSPD | mask, clockreg);
-			}
-		}
-	}
-
-	if (new_chip)	goto chipset_is_set;
-
-	switch(drive->dn) {
-		case 0:	drive_pci = 0x60;
-			pci_read_config_dword(dev, drive_pci, &drive_conf);
-			if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
-				goto chipset_is_set;
-			pci_read_config_byte(dev, (drive_pci), &test1);
-			if (!(test1 & SYNC_ERRDY_EN))
-				pci_write_config_byte(dev, (drive_pci), test1|SYNC_ERRDY_EN);
-			break;
-		case 1:	drive_pci = 0x64;
-			pci_read_config_dword(dev, drive_pci, &drive_conf);
-			if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
-				goto chipset_is_set;
-			pci_read_config_byte(dev, 0x60, &test1);
-			pci_read_config_byte(dev, (drive_pci), &test2);
-			if ((test1 & SYNC_ERRDY_EN) && !(test2 & SYNC_ERRDY_EN))
-				pci_write_config_byte(dev, (drive_pci), test2|SYNC_ERRDY_EN);
-			break;
-		case 2:	drive_pci = 0x68;
-			pci_read_config_dword(dev, drive_pci, &drive_conf);
-			if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
-				goto chipset_is_set;
-			pci_read_config_byte(dev, (drive_pci), &test1);
-			if (!(test1 & SYNC_ERRDY_EN))
-				pci_write_config_byte(dev, (drive_pci), test1|SYNC_ERRDY_EN);
-			break;
-		case 3:	drive_pci = 0x6c;
-			pci_read_config_dword(dev, drive_pci, &drive_conf);
-			if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
-				goto chipset_is_set;
-			pci_read_config_byte(dev, 0x68, &test1);
-			pci_read_config_byte(dev, (drive_pci), &test2);
-			if ((test1 & SYNC_ERRDY_EN) && !(test2 & SYNC_ERRDY_EN))
-				pci_write_config_byte(dev, (drive_pci), test2|SYNC_ERRDY_EN);
-			break;
-		default:
-			return ide_dma_off;
-	}
-
-chipset_is_set:
-
-	if (drive->media != ide_disk)
-		return ide_dma_off_quietly;
-	
-	if (new_chip) {
-		if (id->capability & 4) {	/* IORDY_EN & PREFETCH_EN */
-			OUT_BYTE((iordy + adj), indexreg);
-			OUT_BYTE((IN_BYTE(datareg)|0x03), datareg);
-		}
-	}
-	else {
-		pci_read_config_byte(dev, (drive_pci), &AP);
-		if (id->capability & 4)	/* IORDY_EN */
-			pci_write_config_byte(dev, (drive_pci), AP|IORDY_EN);
-		pci_read_config_byte(dev, (drive_pci), &AP);
-		if (drive->media == ide_disk)	/* PREFETCH_EN */
-			pci_write_config_byte(dev, (drive_pci), AP|PREFETCH_EN);
-	}
-
-	if ((id->dma_ultra & 0x0040)&&(udma_133))	speed = XFER_UDMA_6;
-	else if ((id->dma_ultra & 0x0020)&&(udma_100))	speed = XFER_UDMA_5;
-	else if ((id->dma_ultra & 0x0010)&&(udma_66))	speed = XFER_UDMA_4;
-	else if ((id->dma_ultra & 0x0008)&&(udma_66))	speed = XFER_UDMA_3;
-	else if ((id->dma_ultra & 0x0004)&&(udma_33))	speed = XFER_UDMA_2;
-	else if ((id->dma_ultra & 0x0002)&&(udma_33))	speed = XFER_UDMA_1;
-	else if ((id->dma_ultra & 0x0001)&&(udma_33))	speed = XFER_UDMA_0;
-	else if (id->dma_mword & 0x0004)		speed = XFER_MW_DMA_2;
-	else if (id->dma_mword & 0x0002)		speed = XFER_MW_DMA_1;
-	else if (id->dma_mword & 0x0001)		speed = XFER_MW_DMA_0;
-	else if ((id->dma_1word & 0x0004)&&(!new_chip))	speed = XFER_SW_DMA_2;
-	else if ((id->dma_1word & 0x0002)&&(!new_chip))	speed = XFER_SW_DMA_1;
-	else if ((id->dma_1word & 0x0001)&&(!new_chip))	speed = XFER_SW_DMA_0;
-	else {
-		/* restore original pci-config space */
-		if (!new_chip)
-			pci_write_config_dword(dev, drive_pci, drive_conf);
-		return ide_dma_off_quietly;
-	}
-
-	outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
-	(void) hwif->speedproc(drive, speed);
-
-	return ((int)	((id->dma_ultra >> 14) & 3) ? ide_dma_on :
-			((id->dma_ultra >> 11) & 7) ? ide_dma_on :
-			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-			((id->dma_mword >> 8) & 7) ? ide_dma_on : 
-			((id->dma_1word >> 8) & 7) ? ide_dma_on :
-						     ide_dma_off_quietly);
-}
-
-static int config_drive_xfer_rate (ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-	ide_hwif_t *hwif = HWIF(drive);
-	ide_dma_action_t dma_func = ide_dma_off_quietly;
-
-	if (id && (id->capability & 1) && hwif->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x007F) {
-				/* Force if Capable UltraDMA */
-				dma_func = config_chipset_for_dma(drive, 1);
-				if ((id->field_valid & 2) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    (id->dma_1word & 0x0007)) {
-				/* Force if Capable regular DMA modes */
-				dma_func = config_chipset_for_dma(drive, 0);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			dma_func = config_chipset_for_dma(drive, 0);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-		(void) config_chipset_for_pio(drive, 5);
-	}
-
-	return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-int pdc202xx_quirkproc (ide_drive_t *drive)
-{
-	return ((int) check_in_drive_lists(drive, pdc_quirk_drives));
-}
-
-/*
- * pdc202xx_dmaproc() initiates/aborts (U)DMA read/write operations on a drive.
- */
-int pdc202xx_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	byte dma_stat		= 0;
-	byte sc1d		= 0;
-	byte newchip		= 0;
-	byte clock		= 0;
-	byte hardware48fix	= 0;
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	unsigned long high_16	= pci_resource_start(dev, 4);
-	unsigned long dma_base	= hwif->dma_base;
-	unsigned long atapi_port= hwif->channel ? high_16+0x24 : high_16+0x20;
-
-	switch (dev->device) {
-		case PCI_DEVICE_ID_PROMISE_20276:
-		case PCI_DEVICE_ID_PROMISE_20275:
-		case PCI_DEVICE_ID_PROMISE_20269:
-		case PCI_DEVICE_ID_PROMISE_20268:
-		case PCI_DEVICE_ID_PROMISE_20270:
-			newchip = 1;
-			break;
-		case PCI_DEVICE_ID_PROMISE_20267:
-		case PCI_DEVICE_ID_PROMISE_20265:
-			hardware48fix = 1;
-			clock = IN_BYTE(high_16 + 0x11);
-		default:
-			break;
-	}
-
-	switch (func) {
-		case ide_dma_check:
-			return config_drive_xfer_rate(drive);
-		case ide_dma_begin:
-			/* Note that this is done *after* the cmd has
-			 * been issued to the drive, as per the BM-IDE spec.
-			 * The Promise Ultra33 doesn't work correctly when
-			 * we do this part before issuing the drive cmd.
-			 */
-			/* Enable ATAPI UDMA port for 48bit data on PDC20267 */
-			if ((drive->addressing) && (hardware48fix)) {
-				struct request *rq = HWGROUP(drive)->rq;
-				unsigned long word_count = 0;
-				unsigned long hankval = 0;
-				byte	clockreg = high_16 + 0x11;
-				
-				OUT_BYTE(clock|(hwif->channel ? 0x08:0x02), clockreg);
-				word_count = (rq->nr_sectors << 8);
-				hankval = (rq->cmd == READ) ? 0x05<<24 : 0x06<<24;
-				hankval = hankval | word_count ;
-				outl(hankval, atapi_port);
-			}  
-			break;
-		case ide_dma_end:
-			/* Disable ATAPI UDMA port for 48bit data on PDC20267 */
-			if ((drive->addressing) && (hardware48fix)) {
-				unsigned long hankval = 0;
-				byte	clockreg = high_16 + 0x11;
-				
-			    	outl(hankval, atapi_port);	/* zero out extra */
-				clock = IN_BYTE(clockreg);
-				OUT_BYTE(clock & ~(hwif->channel ? 0x08:0x02), clockreg);
-			}
-			break;
-		case ide_dma_test_irq:	/* returns 1 if dma irq issued, 0 otherwise */
-			dma_stat = IN_BYTE(dma_base+2);
-			if (newchip)
-				return (dma_stat & 4) == 4;
-
-			sc1d = IN_BYTE(high_16 + 0x001d);
-			if (HWIF(drive)->channel) {
-				if ((sc1d & 0x50) == 0x50) goto somebody_else;
-				else if ((sc1d & 0x40) == 0x40)
-					return (dma_stat & 4) == 4;
-			} else {
-				if ((sc1d & 0x05) == 0x05) goto somebody_else;
-				else if ((sc1d & 0x04) == 0x04)
-					return (dma_stat & 4) == 4;
-			}
-somebody_else:
-			return (dma_stat & 4) == 4;	/* return 1 if INTR asserted */
-		case ide_dma_lostirq:
-		case ide_dma_timeout:
-			if (HWIF(drive)->resetproc != NULL)
-				HWIF(drive)->resetproc(drive);
-		default:
-			break;
-	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-void pdc202xx_reset (ide_drive_t *drive)
-{
-	OUT_BYTE(0x04,IDE_CONTROL_REG);
-	mdelay(1000);
-	OUT_BYTE(0x00,IDE_CONTROL_REG);
-	mdelay(1000);
-	printk("PDC202XX: %s channel reset.\n",
-		HWIF(drive)->channel ? "Secondary" : "Primary");
-}
-
-/*
- * Since SUN Cobalt is attempting to do this operation, I should disclose
- * this has been a long time ago Thu Jul 27 16:40:57 2000 was the patch date
- * HOTSWAP ATA Infrastructure.
- */
-static int pdc202xx_tristate (ide_drive_t * drive, int state)
-{
-#if 0
-	ide_hwif_t *hwif	= HWIF(drive);
-	unsigned long high_16	= pci_resource_start(hwif->pci_dev, 4);
-	byte sc1f		= inb(high_16 + 0x001f);
-
-	if (!hwif)
-		return -EINVAL;
-
-//	hwif->bus_state = state;
-
-	if (state) {
-		outb(sc1f | 0x08, high_16 + 0x001f);
-	} else {
-		outb(sc1f & ~0x08, high_16 + 0x001f);
-	}
-#endif
-	return 0;
-}
-
-unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name)
-{
-	unsigned long high_16	= pci_resource_start(dev, 4);
-	byte udma_speed_flag	= IN_BYTE(high_16 + 0x001f);
-	byte primary_mode	= IN_BYTE(high_16 + 0x001a);
-	byte secondary_mode	= IN_BYTE(high_16 + 0x001b);
-
-	OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f);
-	mdelay(100);
-	OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f);
-	mdelay(2000);	/* 2 seconds ?! */
-
-	if (dev->resource[PCI_ROM_RESOURCE].start) {
-		pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
-		printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
-	}
-	
-	printk("%s: (U)DMA Burst Bit %sABLED " \
-		"Primary %s Mode " \
-		"Secondary %s Mode.\n",
-		name,
-		(udma_speed_flag & 1) ? "EN" : "DIS",
-		(primary_mode & 1) ? "MASTER" : "PCI",
-		(secondary_mode & 1) ? "MASTER" : "PCI" );
-
-#ifdef CONFIG_PDC202XX_BURST
-	if (!(udma_speed_flag & 1)) {
-		printk("%s: FORCING BURST BIT 0x%02x -> 0x%02x ", name, udma_speed_flag, (udma_speed_flag|1));
-		OUT_BYTE(udma_speed_flag|1, high_16 + 0x001f);
-		printk("%sCTIVE\n", (IN_BYTE(high_16 + 0x001f) & 1) ? "A" : "INA");
-	}
-#endif /* CONFIG_PDC202XX_BURST */
-
-#ifdef CONFIG_PDC202XX_MASTER
-	if (!(primary_mode & 1)) {
-		printk("%s: FORCING PRIMARY MODE BIT 0x%02x -> 0x%02x ",
-			name, primary_mode, (primary_mode|1));
-		OUT_BYTE(primary_mode|1, high_16 + 0x001a);
-		printk("%s\n", (IN_BYTE(high_16 + 0x001a) & 1) ? "MASTER" : "PCI");
-	}
-
-	if (!(secondary_mode & 1)) {
-		printk("%s: FORCING SECONDARY MODE BIT 0x%02x -> 0x%02x ",
-			name, secondary_mode, (secondary_mode|1));
-		OUT_BYTE(secondary_mode|1, high_16 + 0x001b);
-		printk("%s\n", (IN_BYTE(high_16 + 0x001b) & 1) ? "MASTER" : "PCI");
-	}
-#endif /* CONFIG_PDC202XX_MASTER */
-
-#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!pdc202xx_proc) {
-		pdc202xx_proc = 1;
-		bmide_dev = dev;
-		pdc202xx_display_info = &pdc202xx_get_info;
-	}
-#endif /* DISPLAY_PDC202XX_TIMINGS && CONFIG_PROC_FS */
-	return dev->irq;
-}
-
-unsigned int __init ata66_pdc202xx (ide_hwif_t *hwif)
-{
-	unsigned short mask = (hwif->channel) ? (1<<11) : (1<<10);
-	unsigned short CIS;
-
-        	switch(hwif->pci_dev->device) {
-		case PCI_DEVICE_ID_PROMISE_20276:
-		case PCI_DEVICE_ID_PROMISE_20275:
-		case PCI_DEVICE_ID_PROMISE_20269:
-		case PCI_DEVICE_ID_PROMISE_20268:
-		case PCI_DEVICE_ID_PROMISE_20270:
-			OUT_BYTE(0x0b, (hwif->dma_base + 1));
-			return (!(IN_BYTE((hwif->dma_base + 3)) & 0x04));
-			/* check 80pin cable */
-		default:
-			pci_read_config_word(hwif->pci_dev, 0x50, &CIS);
-			return (!(CIS & mask));
-			/* check 80pin cable */
-	}
-}
-
-void __init ide_init_pdc202xx (ide_hwif_t *hwif)
-{
-	hwif->tuneproc  = &pdc202xx_tune_drive;
-	hwif->quirkproc = &pdc202xx_quirkproc;
-	hwif->resetproc = &pdc202xx_reset;
-
-        switch(hwif->pci_dev->device) {
-		case PCI_DEVICE_ID_PROMISE_20276:
-		case PCI_DEVICE_ID_PROMISE_20275:
-		case PCI_DEVICE_ID_PROMISE_20269:
-		case PCI_DEVICE_ID_PROMISE_20268:
-		case PCI_DEVICE_ID_PROMISE_20270:
-			hwif->speedproc = &pdc202xx_new_tune_chipset;
-			break;
-		case PCI_DEVICE_ID_PROMISE_20267:
-		case PCI_DEVICE_ID_PROMISE_20265:
-		case PCI_DEVICE_ID_PROMISE_20262:
-			hwif->busproc   = &pdc202xx_tristate;
-		case PCI_DEVICE_ID_PROMISE_20246:
-			hwif->speedproc = &pdc202xx_tune_chipset;
-		default:
-			break;
-	}
-
-#undef CONFIG_PDC202XX_32_UNMASK
-#ifdef CONFIG_PDC202XX_32_UNMASK
-	hwif->drives[0].io_32bit = 1;
-	hwif->drives[1].io_32bit = 1;
-	hwif->drives[0].unmask = 1;
-	hwif->drives[1].unmask = 1;
-#endif /* CONFIG_PDC202XX_32_UNMASK */
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (hwif->dma_base) {
-		hwif->dmaproc = &pdc202xx_dmaproc;
-		if (!noautodma)
-			hwif->autodma = 1;
-	} else {
-		hwif->drives[0].autotune = 1;
-		hwif->drives[1].autotune = 1;
-		hwif->autodma = 0;
-	}
-#else /* !CONFIG_BLK_DEV_IDEDMA */
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-	hwif->autodma = 0;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pdc4030.c linux-2.4.21-pre6/drivers/ide/pdc4030.c
--- linux-2.4.20/drivers/ide/pdc4030.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pdc4030.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,578 +0,0 @@
-/*  -*- linux-c -*-
- *  linux/drivers/ide/pdc4030.c		Version 0.90  May 27, 1999
- *
- *  Copyright (C) 1995-1999  Linus Torvalds & authors (see below)
- */
-
-/*
- *  Principal Author/Maintainer:  peterd@pnd-pc.demon.co.uk
- *
- *  This file provides support for the second port and cache of Promise
- *  IDE interfaces, e.g. DC4030VL, DC4030VL-1 and DC4030VL-2.
- *
- *  Thanks are due to Mark Lord for advice and patiently answering stupid
- *  questions, and all those mugs^H^H^H^Hbrave souls who've tested this,
- *  especially Andre Hedrick.
- *
- *  Version 0.01	Initial version, #include'd in ide.c rather than
- *                      compiled separately.
- *                      Reads use Promise commands, writes as before. Drives
- *                      on second channel are read-only.
- *  Version 0.02        Writes working on second channel, reads on both
- *                      channels. Writes fail under high load. Suspect
- *			transfers of >127 sectors don't work.
- *  Version 0.03        Brought into line with ide.c version 5.27.
- *                      Other minor changes.
- *  Version 0.04        Updated for ide.c version 5.30
- *                      Changed initialization strategy
- *  Version 0.05	Kernel integration.  -ml
- *  Version 0.06	Ooops. Add hwgroup to direct call of ide_intr() -ml
- *  Version 0.07	Added support for DC4030 variants
- *			Secondary interface autodetection
- *  Version 0.08	Renamed to pdc4030.c
- *  Version 0.09	Obsolete - never released - did manual write request
- *			splitting before max_sectors[major][minor] available.
- *  Version 0.10	Updated for 2.1 series of kernels
- *  Version 0.11	Updated for 2.3 series of kernels
- *			Autodetection code added.
- *
- *  Version 0.90	Transition to BETA code. No lost/unexpected interrupts
- */
-
-/*
- * Once you've compiled it in, you'll have to also enable the interface
- * setup routine from the kernel command line, as in 
- *
- *	'linux ide0=dc4030' or 'linux ide1=dc4030'
- *
- * It should now work as a second controller also ('ide1=dc4030') but only
- * if you DON'T have BIOS V4.44, which has a bug. If you have this version
- * and EPROM programming facilities, you need to fix 4 bytes:
- * 	2496:	81	81
- *	2497:	3E	3E
- *	2498:	22	98	*
- *	2499:	06	05	*
- *	249A:	F0	F0
- *	249B:	01	01
- *	...
- *	24A7:	81	81
- *	24A8:	3E	3E
- *	24A9:	22	98	*
- *	24AA:	06	05	*
- *	24AB:	70	70
- *	24AC:	01	01
- *
- * As of January 1999, Promise Technology Inc. have finally supplied me with
- * some technical information which has shed a glimmer of light on some of the
- * problems I was having, especially with writes. 
- *
- * There are still problems with the robustness and efficiency of this driver
- * because I still don't understand what the card is doing with interrupts.
- */
-
-#define DEBUG_READ
-#define DEBUG_WRITE
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include "pdc4030.h"
-
-#ifdef CONFIG_IDE_TASKFILE_IO
-#  define __TASKFILE__IO
-#else /* CONFIG_IDE_TASKFILE_IO */
-#  undef __TASKFILE__IO
-#endif /* CONFIG_IDE_TASKFILE_IO */
-
-/*
- * promise_selectproc() is invoked by ide.c
- * in preparation for access to the specified drive.
- */
-static void promise_selectproc (ide_drive_t *drive)
-{
-	unsigned int number;
-
-	number = (HWIF(drive)->channel << 1) + drive->select.b.unit;
-	OUT_BYTE(number,IDE_FEATURE_REG);
-}
-
-/*
- * pdc4030_cmd handles the set of vendor specific commands that are initiated
- * by command F0. They all have the same success/failure notification -
- * 'P' (=0x50) on success, 'p' (=0x70) on failure.
- */
-int pdc4030_cmd(ide_drive_t *drive, byte cmd)
-{
-	unsigned long timeout, timer;
-	byte status_val;
-
-	promise_selectproc(drive);	/* redundant? */
-	OUT_BYTE(0xF3,IDE_SECTOR_REG);
-	OUT_BYTE(cmd,IDE_SELECT_REG);
-	OUT_BYTE(PROMISE_EXTENDED_COMMAND,IDE_COMMAND_REG);
-	timeout = HZ * 10;
-	timeout += jiffies;
-	do {
-		if(time_after(jiffies, timeout)) {
-			return 2; /* device timed out */
-		}
-		/* This is out of delay_10ms() */
-		/* Delays at least 10ms to give interface a chance */
-		timer = jiffies + (HZ + 99)/100 + 1;
-		while (time_after(timer, jiffies));
-		status_val = IN_BYTE(IDE_SECTOR_REG);
-	} while (status_val != 0x50 && status_val != 0x70);
-
-	if(status_val == 0x50)
-		return 0; /* device returned success */
-	else
-		return 1; /* device returned failure */
-}
-
-/*
- * pdc4030_identify sends a vendor-specific IDENTIFY command to the drive
- */
-int pdc4030_identify(ide_drive_t *drive)
-{
-	return pdc4030_cmd(drive, PROMISE_IDENTIFY);
-}
-
-int enable_promise_support = 0;
-
-void __init init_pdc4030 (void)
-{
-	enable_promise_support = 1;
-}
-
-/*
- * setup_pdc4030()
- * Completes the setup of a Promise DC4030 controller card, once found.
- */
-int __init setup_pdc4030 (ide_hwif_t *hwif)
-{
-        ide_drive_t *drive;
-	ide_hwif_t *hwif2;
-	struct dc_ident ident;
-	int i;
-	ide_startstop_t startstop;
-	
-	if (!hwif) return 0;
-
-	drive = &hwif->drives[0];
-	hwif2 = &ide_hwifs[hwif->index+1];
-	if (hwif->chipset == ide_pdc4030) /* we've already been found ! */
-		return 1;
-
-	if (IN_BYTE(IDE_NSECTOR_REG) == 0xFF || IN_BYTE(IDE_SECTOR_REG) == 0xFF) {
-		return 0;
-	}
-	if (IDE_CONTROL_REG)
-		OUT_BYTE(0x08,IDE_CONTROL_REG);
-	if (pdc4030_cmd(drive,PROMISE_GET_CONFIG)) {
-		return 0;
-	}
-	if (ide_wait_stat(&startstop, drive,DATA_READY,BAD_W_STAT,WAIT_DRQ)) {
-		printk(KERN_INFO
-			"%s: Failed Promise read config!\n",hwif->name);
-		return 0;
-	}
-	ide_input_data(drive,&ident,SECTOR_WORDS);
-	if (ident.id[1] != 'P' || ident.id[0] != 'T') {
-		return 0;
-	}
-	printk(KERN_INFO "%s: Promise caching controller, ",hwif->name);
-	switch(ident.type) {
-		case 0x43:	printk("DC4030VL-2, "); break;
-		case 0x41:	printk("DC4030VL-1, "); break;
-		case 0x40:	printk("DC4030VL, "); break;
-		default:
-			printk("unknown - type 0x%02x - please report!\n"
-			       ,ident.type);
-			printk("Please e-mail the following data to "
-			       "promise@pnd-pc.demon.co.uk along with\n"
-			       "a description of your card and drives:\n");
-			for (i=0; i < 0x90; i++) {
-				printk("%02x ", ((unsigned char *)&ident)[i]);
-				if ((i & 0x0f) == 0x0f) printk("\n");
-			}
-			return 0;
-	}
-	printk("%dKB cache, ",(int)ident.cache_mem);
-	switch(ident.irq) {
-            case 0x00: hwif->irq = 14; break;
-            case 0x01: hwif->irq = 12; break;
-            default:   hwif->irq = 15; break;
-	}
-	printk("on IRQ %d\n",hwif->irq);
-
-	/*
-	 * Once found and identified, we set up the next hwif in the array
-	 * (hwif2 = ide_hwifs[hwif->index+1]) with the same io ports, irq
-	 * and other settings as the main hwif. This gives us two "mated"
-	 * hwifs pointing to the Promise card.
-	 *
-	 * We also have to shift the default values for the remaining
-	 * interfaces "up by one" to make room for the second interface on the
-	 * same set of values.
-	 */
-
-	hwif->chipset	= hwif2->chipset = ide_pdc4030;
-	hwif->mate	= hwif2;
-	hwif2->mate	= hwif;
-	hwif2->channel	= 1;
-	hwif->selectproc = hwif2->selectproc = &promise_selectproc;
-	hwif->serialized = hwif2->serialized = 1;
-
-/* Shift the remaining interfaces down by one */
-	for (i=MAX_HWIFS-1 ; i > hwif->index+1 ; i--) {
-		ide_hwif_t *h = &ide_hwifs[i];
-
-#ifdef DEBUG
-		printk(KERN_DEBUG "Shifting i/f %d values to i/f %d\n",i-1,i);
-#endif
-		ide_init_hwif_ports(&h->hw, (h-1)->io_ports[IDE_DATA_OFFSET], 0, NULL);
-		memcpy(h->io_ports, h->hw.io_ports, sizeof(h->io_ports));
-		h->noprobe = (h-1)->noprobe;
-	}
-	ide_init_hwif_ports(&hwif2->hw, hwif->io_ports[IDE_DATA_OFFSET], 0, NULL);
-	memcpy(hwif2->io_ports, hwif->hw.io_ports, sizeof(hwif2->io_ports));
-	hwif2->irq = hwif->irq;
-	hwif2->hw.irq = hwif->hw.irq = hwif->irq;
-	for (i=0; i<2 ; i++) {
-		hwif->drives[i].io_32bit = 3;
-		hwif2->drives[i].io_32bit = 3;
-		hwif->drives[i].keep_settings = 1;
-		hwif2->drives[i].keep_settings = 1;
-		if (!ident.current_tm[i].cyl)
-			hwif->drives[i].noprobe = 1;
-		if (!ident.current_tm[i+2].cyl)
-			hwif2->drives[i].noprobe = 1;
-	}
-        return 1;
-}
-
-/*
- * detect_pdc4030()
- * Tests for the presence of a DC4030 Promise card on this interface
- * Returns: 1 if found, 0 if not found
- */
-int __init detect_pdc4030(ide_hwif_t *hwif)
-{
-	ide_drive_t *drive = &hwif->drives[0];
-
-	if (IDE_DATA_REG == 0) { /* Skip test for non-existent interface */
-		return 0;
-	}
-	OUT_BYTE(0xF3, IDE_SECTOR_REG);
-	OUT_BYTE(0x14, IDE_SELECT_REG);
-	OUT_BYTE(PROMISE_EXTENDED_COMMAND, IDE_COMMAND_REG);
-	
-	ide_delay_50ms();
-
-	if (IN_BYTE(IDE_ERROR_REG) == 'P' &&
-	    IN_BYTE(IDE_NSECTOR_REG) == 'T' &&
-	    IN_BYTE(IDE_SECTOR_REG) == 'I') {
-		return 1;
-	} else {
-		return 0;
-	}
-}
-
-void __init ide_probe_for_pdc4030(void)
-{
-	unsigned int	index;
-	ide_hwif_t	*hwif;
-
-	if (enable_promise_support == 0)
-		return;
-	for (index = 0; index < MAX_HWIFS; index++) {
-		hwif = &ide_hwifs[index];
-		if (hwif->chipset == ide_unknown && detect_pdc4030(hwif)) {
-			setup_pdc4030(hwif);
-		}
-	}
-}
-
-/*
- * promise_read_intr() is the handler for disk read/multread interrupts
- */
-static ide_startstop_t promise_read_intr (ide_drive_t *drive)
-{
-	byte stat;
-	int total_remaining;
-	unsigned int sectors_left, sectors_avail, nsect;
-	struct request *rq;
-
-	if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) {
-		return ide_error(drive, "promise_read_intr", stat);
-	}
-
-read_again:
-	do {
-		sectors_left = IN_BYTE(IDE_NSECTOR_REG);
-		IN_BYTE(IDE_SECTOR_REG);
-	} while (IN_BYTE(IDE_NSECTOR_REG) != sectors_left);
-	rq = HWGROUP(drive)->rq;
-	sectors_avail = rq->nr_sectors - sectors_left;
-	if (!sectors_avail)
-		goto read_again;
-
-read_next:
-	rq = HWGROUP(drive)->rq;
-	nsect = rq->current_nr_sectors;
-	if (nsect > sectors_avail)
-		nsect = sectors_avail;
-	sectors_avail -= nsect;
-	ide_input_data(drive, rq->buffer, nsect * SECTOR_WORDS);
-#ifdef DEBUG_READ
-	printk(KERN_DEBUG "%s:  promise_read: sectors(%ld-%ld), "
-	       "buf=0x%08lx, rem=%ld\n", drive->name, rq->sector,
-	       rq->sector+nsect-1, (unsigned long) rq->buffer,
-	       rq->nr_sectors-nsect);
-#endif
-	rq->sector += nsect;
-	rq->buffer += nsect<<9;
-	rq->errors = 0;
-	rq->nr_sectors -= nsect;
-	total_remaining = rq->nr_sectors;
-	if ((rq->current_nr_sectors -= nsect) <= 0) {
-		ide_end_request(1, HWGROUP(drive));
-	}
-/*
- * Now the data has been read in, do the following:
- * 
- * if there are still sectors left in the request, 
- *   if we know there are still sectors available from the interface,
- *     go back and read the next bit of the request.
- *   else if DRQ is asserted, there are more sectors available, so
- *     go back and find out how many, then read them in.
- *   else if BUSY is asserted, we are going to get an interrupt, so
- *     set the handler for the interrupt and just return
- */
-	if (total_remaining > 0) {
-		if (sectors_avail)
-			goto read_next;
-		stat = GET_STAT();
-		if (stat & DRQ_STAT)
-			goto read_again;
-		if (stat & BUSY_STAT) {
-			ide_set_handler (drive, &promise_read_intr, WAIT_CMD, NULL);
-#ifdef DEBUG_READ
-			printk(KERN_DEBUG "%s: promise_read: waiting for"
-			       "interrupt\n", drive->name);
-#endif
-			return ide_started;
-		}
-		printk(KERN_ERR "%s: Eeek! promise_read_intr: sectors left "
-		       "!DRQ !BUSY\n", drive->name);
-		return ide_error(drive, "promise read intr", stat);
-	}
-	return ide_stopped;
-}
-
-/*
- * promise_complete_pollfunc()
- * This is the polling function for waiting (nicely!) until drive stops
- * being busy. It is invoked at the end of a write, after the previous poll
- * has finished.
- *
- * Once not busy, the end request is called.
- */
-static ide_startstop_t promise_complete_pollfunc(ide_drive_t *drive)
-{
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	struct request *rq = hwgroup->rq;
-	int i;
-
-	if (GET_STAT() & BUSY_STAT) {
-		if (time_before(jiffies, hwgroup->poll_timeout)) {
-			ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
-			return ide_started; /* continue polling... */
-		}
-		hwgroup->poll_timeout = 0;
-		printk(KERN_ERR "%s: completion timeout - still busy!\n",
-		       drive->name);
-		return ide_error(drive, "busy timeout", GET_STAT());
-	}
-
-	hwgroup->poll_timeout = 0;
-#ifdef DEBUG_WRITE
-	printk(KERN_DEBUG "%s: Write complete - end_request\n", drive->name);
-#endif
-	for (i = rq->nr_sectors; i > 0; ) {
-		i -= rq->current_nr_sectors;
-		ide_end_request(1, hwgroup);
-	}
-	return ide_stopped;
-}
-
-/*
- * promise_write_pollfunc() is the handler for disk write completion polling.
- */
-static ide_startstop_t promise_write_pollfunc (ide_drive_t *drive)
-{
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-
-	if (IN_BYTE(IDE_NSECTOR_REG) != 0) {
-		if (time_before(jiffies, hwgroup->poll_timeout)) {
-			ide_set_handler (drive, &promise_write_pollfunc, HZ/100, NULL);
-			return ide_started; /* continue polling... */
-		}
-		hwgroup->poll_timeout = 0;
-		printk(KERN_ERR "%s: write timed-out!\n",drive->name);
-		return ide_error (drive, "write timeout", GET_STAT());
-	}
-
-	/*
-	 * Now write out last 4 sectors and poll for not BUSY
-	 */
-	ide_multwrite(drive, 4);
-	hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
-	ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
-#ifdef DEBUG_WRITE
-	printk(KERN_DEBUG "%s: Done last 4 sectors - status = %02x\n",
-		drive->name, GET_STAT());
-#endif
-	return ide_started;
-}
-
-/*
- * promise_write() transfers a block of one or more sectors of data to a
- * drive as part of a disk write operation. All but 4 sectors are transferred
- * in the first attempt, then the interface is polled (nicely!) for completion
- * before the final 4 sectors are transferred. There is no interrupt generated
- * on writes (at least on the DC4030VL-2), we just have to poll for NOT BUSY.
- */
-static ide_startstop_t promise_write (ide_drive_t *drive)
-{
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	struct request *rq = &hwgroup->wrq;
-
-#ifdef DEBUG_WRITE
-	printk(KERN_DEBUG "%s: promise_write: sectors(%ld-%ld), "
-	       "buffer=%p\n", drive->name, rq->sector,
-	       rq->sector + rq->nr_sectors - 1, rq->buffer);
-#endif
-
-	/*
-	 * If there are more than 4 sectors to transfer, do n-4 then go into
-	 * the polling strategy as defined above.
-	 */
-	if (rq->nr_sectors > 4) {
-		if (ide_multwrite(drive, rq->nr_sectors - 4))
-			return ide_stopped;
-		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
-		ide_set_handler (drive, &promise_write_pollfunc, HZ/100, NULL);
-		return ide_started;
-	} else {
-	/*
-	 * There are 4 or fewer sectors to transfer, do them all in one go
-	 * and wait for NOT BUSY.
-	 */
-		if (ide_multwrite(drive, rq->nr_sectors))
-			return ide_stopped;
-		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
-		ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
-#ifdef DEBUG_WRITE
-		printk(KERN_DEBUG "%s: promise_write: <= 4 sectors, "
-			"status = %02x\n", drive->name, GET_STAT());
-#endif
-		return ide_started;
-	}
-}
-
-/*
- * do_pdc4030_io() is called from do_rw_disk, having had the block number
- * already set up. It issues a READ or WRITE command to the Promise
- * controller, assuming LBA has been used to set up the block number.
- */
-ide_startstop_t do_pdc4030_io (ide_drive_t *drive, struct request *rq)
-{
-	ide_startstop_t startstop;
-	unsigned long timeout;
-	byte stat;
-
-	switch(rq->cmd) {
-		case READ:
-#ifndef __TASKFILE__IO
-			OUT_BYTE(PROMISE_READ, IDE_COMMAND_REG);
-#endif
-/*
- * The card's behaviour is odd at this point. If the data is
- * available, DRQ will be true, and no interrupt will be
- * generated by the card. If this is the case, we need to call the 
- * "interrupt" handler (promise_read_intr) directly. Otherwise, if
- * an interrupt is going to occur, bit0 of the SELECT register will
- * be high, so we can set the handler the just return and be interrupted.
- * If neither of these is the case, we wait for up to 50ms (badly I'm
- * afraid!) until one of them is.
- */
-			timeout = jiffies + HZ/20; /* 50ms wait */
-			do {
-				stat=GET_STAT();
-				if (stat & DRQ_STAT) {
-					udelay(1);
-					return promise_read_intr(drive);
-				}
-				if (IN_BYTE(IDE_SELECT_REG) & 0x01) {
-#ifdef DEBUG_READ
-	printk(KERN_DEBUG "%s: read: waiting for interrupt\n", drive->name);
-#endif
-					ide_set_handler(drive, &promise_read_intr, WAIT_CMD, NULL);
-					return ide_started;
-				}
-				udelay(1);
-			} while (time_before(jiffies, timeout));
-
-			printk(KERN_ERR "%s: reading: No DRQ and not waiting - Odd!\n", drive->name);
-			return ide_stopped;
-		case WRITE:
-#ifndef __TASKFILE__IO
-			OUT_BYTE(PROMISE_WRITE, IDE_COMMAND_REG);
-#endif
-			if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
-				printk(KERN_ERR "%s: no DRQ after issuing PROMISE_WRITE\n", drive->name);
-				return startstop;
-		    	}
-			if (!drive->unmask)
-				__cli();	/* local CPU only */
-			HWGROUP(drive)->wrq = *rq; /* scratchpad */
-			return promise_write(drive);
-		default:
-			printk("KERN_WARNING %s: bad command: %d\n", drive->name, rq->cmd);
-			ide_end_request(0, HWGROUP(drive));
-			return ide_stopped;
-	}
-}
-
-#ifdef __TASKFILE__IO
-
-ide_startstop_t promise_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
-{
-	struct hd_drive_task_hdr taskfile;
-
-	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-
-	taskfile.sector_count	= rq->nr_sectors;
-	taskfile.sector_number	= block;
-	taskfile.low_cylinder	= (block>>=8);
-	taskfile.high_cylinder	= (block>>=8);
-	taskfile.device_head	= ((block>>8)&0x0f)|drive->select.all;
-	taskfile.command	= (rq->cmd==READ)?PROMISE_READ:PROMISE_WRITE;
-
-	do_taskfile(drive, &taskfile, NULL, NULL);
-	return do_pdc4030_io(drive, rq);
-}
-#endif
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pdc4030.h linux-2.4.21-pre6/drivers/ide/pdc4030.h
--- linux-2.4.20/drivers/ide/pdc4030.h	2001-07-18 01:53:55.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pdc4030.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,44 +0,0 @@
-/*
- *  linux/drivers/ide/pdc4030.h
- *
- *  Copyright (C) 1995-1998  Linus Torvalds & authors
- */
-
-/*
- * Principal author: Peter Denison <peterd@pnd-pc.demon.co.uk>
- */
-
-#ifndef IDE_PROMISE_H
-#define IDE_PROMISE_H
-
-#define	PROMISE_EXTENDED_COMMAND	0xF0
-#define	PROMISE_READ			0xF2
-#define	PROMISE_WRITE			0xF3
-/* Extended commands - main command code = 0xf0 */
-#define	PROMISE_GET_CONFIG		0x10
-#define	PROMISE_IDENTIFY		0x20
-
-struct translation_mode {
-	u16	cyl;
-	u8	head;
-	u8	sect;
-};
-
-struct dc_ident {
-	u8	type;
-	u8	unknown1;
-	u8	hw_revision;
-	u8	firmware_major;
-	u8	firmware_minor;
-	u8	bios_address;
-	u8	irq;
-	u8	unknown2;
-	u16	cache_mem;
-	u16	unknown3;
-	u8	id[2];
-	u16	info;
-	struct translation_mode current_tm[4];
-	u8	pad[SECTOR_WORDS*4 - 32];
-};
-
-#endif /* IDE_PROMISE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pdcraid.c linux-2.4.21-pre6/drivers/ide/pdcraid.c
--- linux-2.4.20/drivers/ide/pdcraid.c	2001-11-13 17:19:41.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pdcraid.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,646 +0,0 @@
-/*
-   pdcraid.c  Copyright (C) 2001 Red Hat, Inc. 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, or (at your option)
-   any later version.
-   
-   You should have received a copy of the GNU General Public License
-   (for example /usr/src/linux/COPYING); if not, write to the Free
-   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
-   
-   Authors: 	Arjan van de Ven <arjanv@redhat.com>
-   		
-   Based on work done by Søren Schmidt for FreeBSD  
-
-*/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/blkdev.h>
-#include <linux/blkpg.h>
-#include <linux/genhd.h>
-#include <linux/ioctl.h>
-
-#include <linux/ide.h>
-#include <asm/uaccess.h>
-
-#include "ataraid.h"
-
-static int pdcraid_open(struct inode * inode, struct file * filp);
-static int pdcraid_release(struct inode * inode, struct file * filp);
-static int pdcraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
-static int pdcraid0_make_request (request_queue_t *q, int rw, struct buffer_head * bh);
-static int pdcraid1_make_request (request_queue_t *q, int rw, struct buffer_head * bh);
-
-struct disk_dev {
-	int major;
-	int minor;
-	int device;
-};
-
-static struct disk_dev devlist[]= {
-	{IDE0_MAJOR,  0,  -1 },
-	{IDE0_MAJOR, 64,  -1 },
-	{IDE1_MAJOR,  0,  -1 },
-	{IDE1_MAJOR, 64,  -1 },
-	{IDE2_MAJOR,  0,  -1 },
-	{IDE2_MAJOR, 64,  -1 },
-	{IDE3_MAJOR,  0,  -1 },
-	{IDE3_MAJOR, 64,  -1 },
-	{IDE4_MAJOR,  0,  -1 },
-	{IDE4_MAJOR, 64,  -1 },
-	{IDE5_MAJOR,  0,  -1 },
-	{IDE5_MAJOR, 64,  -1 },
-	{IDE6_MAJOR,  0,  -1 },
-	{IDE6_MAJOR, 64,  -1 },
-};
-
-
-struct pdcdisk {
-	kdev_t	device;
-	unsigned long sectors;
-	struct block_device *bdev;
-	unsigned long last_pos;
-};
-
-struct pdcraid {
-	unsigned int stride;
-	unsigned int disks;
-	unsigned long sectors;
-	struct geom geom;
-	
-	struct pdcdisk disk[8];
-	
-	unsigned long cutoff[8];
-	unsigned int cutoff_disks[8];
-};
-
-static struct raid_device_operations pdcraid0_ops = {
-        open:                   pdcraid_open,
-	release:                pdcraid_release,
-	ioctl:			pdcraid_ioctl,
-	make_request:		pdcraid0_make_request
-};
-
-static struct raid_device_operations pdcraid1_ops = {
-        open:                   pdcraid_open,
-	release:                pdcraid_release,
-	ioctl:			pdcraid_ioctl,
-	make_request:		pdcraid1_make_request
-};
-
-static struct pdcraid raid[16];
-
-
-static int pdcraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-	unsigned int minor;
-   	unsigned long sectors;
-
-	if (!inode || !inode->i_rdev) 
-		return -EINVAL;
-
-	minor = MINOR(inode->i_rdev)>>SHIFT;
-	
-	switch (cmd) {
-
-         	case BLKGETSIZE:   /* Return device size */
- 			if (!arg)  return -EINVAL;
-			sectors = ataraid_gendisk.part[MINOR(inode->i_rdev)].nr_sects;
-			if (MINOR(inode->i_rdev)&15)
-				return put_user(sectors, (unsigned long *) arg);
-			return put_user(raid[minor].sectors , (unsigned long *) arg);
-			break;
-			
-
-		case HDIO_GETGEO:
-		{
-			struct hd_geometry *loc = (struct hd_geometry *) arg;
-			unsigned short bios_cyl = raid[minor].geom.cylinders; /* truncate */
-			
-			if (!loc) return -EINVAL;
-			if (put_user(raid[minor].geom.heads, (byte *) &loc->heads)) return -EFAULT;
-			if (put_user(raid[minor].geom.sectors, (byte *) &loc->sectors)) return -EFAULT;
-			if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT;
-			if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
-				(unsigned long *) &loc->start)) return -EFAULT;
-			return 0;
-		}
-
-		case HDIO_GETGEO_BIG:
-		{
-			struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
-			if (!loc) return -EINVAL;
-			if (put_user(raid[minor].geom.heads, (byte *) &loc->heads)) return -EFAULT;
-			if (put_user(raid[minor].geom.sectors, (byte *) &loc->sectors)) return -EFAULT;
-			if (put_user(raid[minor].geom.cylinders, (unsigned int *) &loc->cylinders)) return -EFAULT;
-			if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
-				(unsigned long *) &loc->start)) return -EFAULT;
-			return 0;
-		}
-
-			
-		case BLKROSET:
-		case BLKROGET:
-		case BLKSSZGET:
-			return blk_ioctl(inode->i_rdev, cmd, arg);
-
-		default:
-			printk("Invalid ioctl \n");
-			return -EINVAL;
-	};
-
-	return 0;
-}
-
-
-unsigned long partition_map_normal(unsigned long block, unsigned long partition_off, unsigned long partition_size, int stride)
-{
-	return block + partition_off;
-}
-
-unsigned long partition_map_linux(unsigned long block, unsigned long partition_off, unsigned long partition_size, int stride)
-{
-	unsigned long newblock;
-	
-	newblock = stride - (partition_off%stride); if (newblock == stride) newblock = 0;
-	newblock += block;
-	newblock = newblock % partition_size;
-	newblock += partition_off;
-	
-	return newblock;
-}
-
-static int funky_remap[8] = { 0, 1,  2, 3, 4, 5, 6, 7 };
-
-unsigned long partition_map_linux_raid0_4disk(unsigned long block, unsigned long partition_off, unsigned long partition_size, int stride)
-{
-	unsigned long newblock,temp,temp2;
-	
-	newblock = stride - (partition_off%stride); if (newblock == stride) newblock = 0;
-
-	if (block < (partition_size / (8*stride))*8*stride ) {
-		temp = block % stride;
-		temp2 = block / stride;
-		temp2 = ((temp2>>3)<<3)|(funky_remap[temp2&7]);
-		block = temp2*stride+temp;
-	}
-
-	
-	newblock += block;
-	newblock = newblock % partition_size;
-	newblock += partition_off;
-	
-	return newblock;
-}
-
-
-
-static int pdcraid0_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
-{
-	unsigned long rsect;
-	unsigned long rsect_left,rsect_accum = 0;
-	unsigned long block;
-	unsigned int disk=0,real_disk=0;
-	int i;
-	int device;
-	struct pdcraid *thisraid;
-
-	rsect = bh->b_rsector;
-	
-	/* Ok. We need to modify this sector number to a new disk + new sector number. 
-	 * If there are disks of different sizes, this gets tricky. 
-	 * Example with 3 disks (1Gb, 4Gb and 5 GB):
-	 * The first 3 Gb of the "RAID" are evenly spread over the 3 disks.
-	 * Then things get interesting. The next 2Gb (RAID view) are spread across disk 2 and 3
-	 * and the last 1Gb is disk 3 only.
-	 *
-	 * the way this is solved is like this: We have a list of "cutoff" points where everytime
-	 * a disk falls out of the "higher" count, we mark the max sector. So once we pass a cutoff
-	 * point, we have to divide by one less.
-	 */
-	
-	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
-	thisraid = &raid[device];
-	if (thisraid->stride==0)
-		thisraid->stride=1;
-
-	/* Partitions need adding of the start sector of the partition to the requested sector */
-	
-	rsect = partition_map_normal(rsect, ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect, ataraid_gendisk.part[MINOR(bh->b_rdev)].nr_sects, thisraid->stride);
-
-	/* Woops we need to split the request to avoid crossing a stride barrier */
-	if ((rsect/thisraid->stride) != ((rsect+(bh->b_size/512)-1)/thisraid->stride)) {
-		return -1;  
-	}
-	
-	rsect_left = rsect;
-	
-	for (i=0;i<8;i++) {
-		if (thisraid->cutoff_disks[i]==0)
-			break;
-		if (rsect > thisraid->cutoff[i]) {
-			/* we're in the wrong area so far */
-			rsect_left -= thisraid->cutoff[i];
-			rsect_accum += thisraid->cutoff[i]/thisraid->cutoff_disks[i];
-		} else {
-			block = rsect_left / thisraid->stride;
-			disk = block % thisraid->cutoff_disks[i];
-			block = (block / thisraid->cutoff_disks[i]) * thisraid->stride;
-			rsect = rsect_accum + (rsect_left % thisraid->stride) + block;
-			break;
-		}
-	}
-	
-	for (i=0;i<8;i++) {
-		if ((disk==0) && (thisraid->disk[i].sectors > rsect_accum)) {
-			real_disk = i;
-			break;
-		}
-		if ((disk>0) && (thisraid->disk[i].sectors >= rsect_accum)) {
-			disk--;
-		}
-		
-	}
-	disk = real_disk;
-		
-	
-	/*
-	 * The new BH_Lock semantics in ll_rw_blk.c guarantee that this
-	 * is the only IO operation happening on this bh.
-	 */
-	bh->b_rdev = thisraid->disk[disk].device;
-	bh->b_rsector = rsect;
-
-	/*
-	 * Let the main block layer submit the IO and resolve recursion:
-	 */
-	return 1;
-}
-
-static int pdcraid1_write_request(request_queue_t *q, int rw, struct buffer_head * bh)
-{
-	struct buffer_head *bh1;
-	struct ataraid_bh_private *private;
-	int device;
-	int i;
-
-	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
-	private = ataraid_get_private();
-	if (private==NULL)
-		BUG();
-
-	private->parent = bh;
-	
-	atomic_set(&private->count,raid[device].disks);
-
-
-	for (i = 0; i< raid[device].disks; i++) { 
-		bh1=ataraid_get_bhead();
-		/* If this ever fails we're doomed */
-		if (!bh1)
-			BUG();
-	
-		/* dupe the bufferhead and update the parts that need to be different */
-		memcpy(bh1, bh, sizeof(*bh));
-		
-		bh1->b_end_io = ataraid_end_request;
-		bh1->b_private = private;
-		bh1->b_rsector += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect; /* partition offset */
-		bh1->b_rdev = raid[device].disk[i].device;
-
-		/* update the last known head position for the drive */
-		raid[device].disk[i].last_pos = bh1->b_rsector+(bh1->b_size>>9);
-
-		generic_make_request(rw,bh1);
-	}
-	return 0;
-}
-
-static int pdcraid1_read_request (request_queue_t *q, int rw, struct buffer_head * bh)
-{
-	int device;
-	int dist;
-	int bestsofar,bestdist,i;
-	static int previous;
-
-	/* Reads are simple in principle. Pick a disk and go. 
-	   Initially I cheat by just picking the one which the last known
-	   head position is closest by.
-	   Later on, online/offline checking and performance needs adding */
-	
-	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
-	bh->b_rsector += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect;
-
-	bestsofar = 0; 
-	bestdist = raid[device].disk[0].last_pos - bh->b_rsector;
-	if (bestdist<0) 
-		bestdist=-bestdist;
-	if (bestdist>4095)
-		bestdist=4095;
-
-	for (i=1 ; i<raid[device].disks; i++) {
-		dist = raid[device].disk[i].last_pos - bh->b_rsector;
-		if (dist<0) 
-			dist = -dist;
-		if (dist>4095)
-			dist=4095;
-		
-		if (bestdist==dist) {  /* it's a tie; try to do some read balancing */
-			if ((previous>bestsofar)&&(previous<=i))  
-				bestsofar = i;
-			previous = (previous + 1) % raid[device].disks;
-		} else if (bestdist>dist) {
-			bestdist = dist;
-			bestsofar = i;
-		}
-	
-	}
-	
-	bh->b_rdev = raid[device].disk[bestsofar].device; 
-	raid[device].disk[bestsofar].last_pos = bh->b_rsector+(bh->b_size>>9);
-
-	/*
-	 * Let the main block layer submit the IO and resolve recursion:
-	 */
-                          	
-	return 1;
-}
-
-
-static int pdcraid1_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
-{
-	/* Read and Write are totally different cases; split them totally here */
-	if (rw==READA)
-		rw = READ;
-	
-	if (rw==READ)
-		return pdcraid1_read_request(q,rw,bh);
-	else
-		return pdcraid1_write_request(q,rw,bh);
-}
-
-#include "pdcraid.h"
-
-static unsigned long calc_pdcblock_offset (int major,int minor)
-{
-	unsigned long lba = 0;
-	kdev_t dev;
-	ide_drive_t *ideinfo;
-	
-	dev = MKDEV(major,minor);
-	ideinfo = get_info_ptr (dev);
-	if (ideinfo==NULL)
-		return 0;
-	
-	
-	/* first sector of the last cluster */
-	if (ideinfo->head==0) 
-		return 0;
-	if (ideinfo->sect==0)
-		return 0;
-	lba = (ideinfo->capacity / (ideinfo->head*ideinfo->sect));
-	lba = lba * (ideinfo->head*ideinfo->sect);
-	lba = lba - ideinfo->sect;
-
-	return lba;
-}
-
-
-static int read_disk_sb (int major, int minor, unsigned char *buffer,int bufsize)
-{
-	int ret = -EINVAL;
-	struct buffer_head *bh = NULL;
-	kdev_t dev = MKDEV(major,minor);
-	unsigned long sb_offset;
-
-	if (blksize_size[major]==NULL)   /* device doesn't exist */
-		return -EINVAL;
-                       
-	
-	/*
-	 * Calculate the position of the superblock,
-	 * it's at first sector of the last cylinder
-	 */
-	sb_offset = calc_pdcblock_offset(major,minor)/8;
-	/* The /8 transforms sectors into 4Kb blocks */
-
-	if (sb_offset==0)
-		return -1;	
-	
-	set_blocksize (dev, 4096);
-
-	bh = bread (dev, sb_offset, 4096);
-	
-	if (bh) {
-		memcpy (buffer, bh->b_data, bufsize);
-	} else {
-		printk(KERN_ERR "pdcraid: Error reading superblock.\n");
-		goto abort;
-	}
-	ret = 0;
-abort:
-	if (bh)
-		brelse (bh);
-	return ret;
-}
-
-static unsigned int calc_sb_csum (unsigned int* ptr)
-{	
-	unsigned int sum;
-	int count;
-	
-	sum = 0;
-	for (count=0;count<511;count++)
-		sum += *ptr++;
-	
-	return sum;
-}
-
-static int cookie = 0;
-
-static void __init probedisk(int devindex,int device, int raidlevel)
-{
-	int i;
-	int major, minor;
-        struct promise_raid_conf *prom;
-	static unsigned char block[4096];
-	struct block_device *bdev;
-
-	if (devlist[devindex].device!=-1) /* already assigned to another array */
-		return;
-	
-	major = devlist[devindex].major;
-	minor = devlist[devindex].minor; 
-
-        if (read_disk_sb(major,minor,(unsigned char*)&block,sizeof(block)))
-        	return;
-                                                                                                                 
-        prom = (struct promise_raid_conf*)&block[512];
-
-        /* the checksums must match */
-	if (prom->checksum != calc_sb_csum((unsigned int*)prom))
-		return;
-	if (prom->raid.type!=raidlevel) /* different raidlevel */
-		return;
-
-	if ((cookie!=0) && (cookie != prom->raid.magic_1)) /* different array */
-		return;
-	
-	cookie = prom->raid.magic_1;
-
-	/* This looks evil. But basically, we have to search for our adapternumber
-	   in the arraydefinition, both of which are in the superblock */	
-        for (i=0;(i<prom->raid.total_disks)&&(i<8);i++) {
-        	if ( (prom->raid.disk[i].channel== prom->raid.channel) &&
-        	     (prom->raid.disk[i].device == prom->raid.device) ) {
-
-        	        bdev = bdget(MKDEV(major,minor));
-        	        if (bdev && blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_RAW) == 0) {
-				raid[device].disk[i].bdev = bdev;
-			}
-			raid[device].disk[i].device = MKDEV(major,minor);
-			raid[device].disk[i].sectors = prom->raid.disk_secs;
-			raid[device].stride = (1<<prom->raid.raid0_shift);
-			raid[device].disks = prom->raid.total_disks;
-			raid[device].sectors = prom->raid.total_secs;
-			raid[device].geom.heads = prom->raid.heads+1;
-			raid[device].geom.sectors = prom->raid.sectors;
-			raid[device].geom.cylinders = prom->raid.cylinders+1;
-			devlist[devindex].device=device;
-        	     }
-        }
-	               
-}
-
-static void __init fill_cutoff(int device)
-{
-	int i,j;
-	unsigned long smallest;
-	unsigned long bar;
-	int count;
-	
-	bar = 0;
-	for (i=0;i<8;i++) {
-		smallest = ~0;
-		for (j=0;j<8;j++) 
-			if ((raid[device].disk[j].sectors < smallest) && (raid[device].disk[j].sectors>bar))
-				smallest = raid[device].disk[j].sectors;
-		count = 0;
-		for (j=0;j<8;j++) 
-			if (raid[device].disk[j].sectors >= smallest)
-				count++;
-				
-		smallest = smallest * count;
-		bar = smallest;
-		raid[device].cutoff[i] = smallest;
-		raid[device].cutoff_disks[i] = count;
-	}
-}
-			   
-static __init int pdcraid_init_one(int device,int raidlevel)
-{
-	int i, count;
-
-	for (i=0; i<14; i++)
-		probedisk(i, device, raidlevel);
-	
-	if (raidlevel==0)
-		fill_cutoff(device);
-	
-	/* Initialize the gendisk structure */
-	
-	ataraid_register_disk(device,raid[device].sectors);        
-		
-	count=0;
-	
-	for (i=0;i<8;i++) {
-		if (raid[device].disk[i].device!=0) {
-			printk(KERN_INFO "Drive %i is %li Mb (%i / %i) \n",
-				i,raid[device].disk[i].sectors/2048,MAJOR(raid[device].disk[i].device),MINOR(raid[device].disk[i].device));
-			count++;
-		}
-	}
-	if (count) {
-		printk(KERN_INFO "Raid%i array consists of %i drives. \n",raidlevel,count);
-		return 0;
-	} else {
-		return -ENODEV;
-	}
-}
-
-static __init int pdcraid_init(void)
-{
-	int retval, device, count = 0;
-
-	do {
-		cookie = 0;
-		device=ataraid_get_device(&pdcraid0_ops);
-		if (device<0)
-			break;
-		retval = pdcraid_init_one(device,0);
-		if (retval) {
-			ataraid_release_device(device);
-			break;
-		} else {
-			count++;
-		}
-	} while (1);
-
-	do {
-	
-		cookie = 0;
-		device=ataraid_get_device(&pdcraid1_ops);
-		if (device<0)
-			break;
-		retval = pdcraid_init_one(device,1);
-		if (retval) {
-			ataraid_release_device(device);
-			break;
-		} else {
-			count++;
-		}
-	} while (1);
-
-	if (count) {
-		printk(KERN_INFO "Promise Fasttrak(tm) Softwareraid driver for linux version 0.03beta\n");
-		return 0;
-	}
-	printk(KERN_DEBUG "Promise Fasttrak(tm) Softwareraid driver 0.03beta: No raid array found\n");
-	return -ENODEV;
-}
-
-static void __exit pdcraid_exit (void)
-{
-	int i,device;
-	for (device = 0; device<16; device++) {
-		for (i=0;i<8;i++) {
-			struct block_device *bdev = raid[device].disk[i].bdev;
-			raid[device].disk[i].bdev = NULL;
-			if (bdev)
-				blkdev_put(bdev, BDEV_RAW);
-		}	
-		if (raid[device].sectors)
-			ataraid_release_device(device);
-	}
-}
-
-static int pdcraid_open(struct inode * inode, struct file * filp) 
-{
-	MOD_INC_USE_COUNT;
-	return 0;
-}
-static int pdcraid_release(struct inode * inode, struct file * filp)
-{	
-	MOD_DEC_USE_COUNT;
-	return 0;
-}
-
-module_init(pdcraid_init);
-module_exit(pdcraid_exit);
-MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/pdcraid.h linux-2.4.21-pre6/drivers/ide/pdcraid.h
--- linux-2.4.20/drivers/ide/pdcraid.h	2001-09-18 06:23:40.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/pdcraid.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,47 +0,0 @@
-struct promise_raid_conf {
-    char                promise_id[24];
-
-    u32             dummy_0;
-    u32             magic_0;
-    u32             dummy_1;
-    u32             magic_1;
-    u16             dummy_2;
-    u8              filler1[470];
-    struct {
-        u32 flags;                          /* 0x200 */
-        u8          dummy_0;
-        u8          disk_number;
-        u8          channel;
-        u8          device;
-        u32         magic_0;
-        u32         dummy_1;
-        u32         dummy_2;                /* 0x210 */
-        u32         disk_secs;
-        u32         dummy_3;
-        u16         dummy_4;
-        u8          status;
-        u8          type;
-        u8        total_disks;            /* 0x220 */
-        u8        raid0_shift;
-        u8        raid0_disks;
-        u8        array_number;
-        u32       total_secs;
-        u16       cylinders;
-        u8        heads;
-        u8        sectors;
-        u32         magic_1;
-        u32         dummy_5;                /* 0x230 */
-        struct {
-            u16     dummy_0;
-            u8      channel;
-            u8      device;
-            u32     magic_0;
-            u32     disk_number;
-        } disk[8];
-    } raid;
-    u32             filler2[346];
-    u32            checksum;
-};
-
-#define PR_MAGIC        "Promise Technology, Inc."
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/piix.c linux-2.4.21-pre6/drivers/ide/piix.c
--- linux-2.4.20/drivers/ide/piix.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/piix.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,542 +0,0 @@
-/*
- *  linux/drivers/ide/piix.c		Version 0.32	June 9, 2000
- *
- *  Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
- *  Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
- *  May be copied or modified under the terms of the GNU General Public License
- *
- *  PIO mode setting function for Intel chipsets.  
- *  For use instead of BIOS settings.
- *
- * 40-41
- * 42-43
- * 
- *                 41
- *                 43
- *
- * | PIO 0       | c0 | 80 | 0 | 	piix_tune_drive(drive, 0);
- * | PIO 2 | SW2 | d0 | 90 | 4 | 	piix_tune_drive(drive, 2);
- * | PIO 3 | MW1 | e1 | a1 | 9 | 	piix_tune_drive(drive, 3);
- * | PIO 4 | MW2 | e3 | a3 | b | 	piix_tune_drive(drive, 4);
- * 
- * sitre = word40 & 0x4000; primary
- * sitre = word42 & 0x4000; secondary
- *
- * 44 8421|8421    hdd|hdb
- * 
- * 48 8421         hdd|hdc|hdb|hda udma enabled
- *
- *    0001         hda
- *    0010         hdb
- *    0100         hdc
- *    1000         hdd
- *
- * 4a 84|21        hdb|hda
- * 4b 84|21        hdd|hdc
- *
- *    ata-33/82371AB
- *    ata-33/82371EB
- *    ata-33/82801AB            ata-66/82801AA
- *    00|00 udma 0              00|00 reserved
- *    01|01 udma 1              01|01 udma 3
- *    10|10 udma 2              10|10 udma 4
- *    11|11 reserved            11|11 reserved
- *
- * 54 8421|8421    ata66 drive|ata66 enable
- *
- * pci_read_config_word(HWIF(drive)->pci_dev, 0x40, &reg40);
- * pci_read_config_word(HWIF(drive)->pci_dev, 0x42, &reg42);
- * pci_read_config_word(HWIF(drive)->pci_dev, 0x44, &reg44);
- * pci_read_config_word(HWIF(drive)->pci_dev, 0x48, &reg48);
- * pci_read_config_word(HWIF(drive)->pci_dev, 0x4a, &reg4a);
- * pci_read_config_word(HWIF(drive)->pci_dev, 0x54, &reg54);
- *
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-#define PIIX_DEBUG_DRIVE_INFO		0
-
-#define DISPLAY_PIIX_TIMINGS
-
-#if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int piix_get_info(char *, char **, off_t, int);
-extern int (*piix_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-extern char *ide_media_verbose(ide_drive_t *);
-static struct pci_dev *bmide_dev;
-
-static int piix_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	u32 bibma = pci_resource_start(bmide_dev, 4);
-        u16 reg40 = 0, psitre = 0, reg42 = 0, ssitre = 0;
-	u8  c0 = 0, c1 = 0;
-	u8  reg44 = 0, reg48 = 0, reg4a = 0, reg4b = 0, reg54 = 0, reg55 = 0;
-
-	switch(bmide_dev->device) {
-		case PCI_DEVICE_ID_INTEL_82801BA_8:
-		case PCI_DEVICE_ID_INTEL_82801BA_9:
-	        case PCI_DEVICE_ID_INTEL_82801CA_10:
-	        case PCI_DEVICE_ID_INTEL_82801CA_11:
-	        case PCI_DEVICE_ID_INTEL_82801DB_11:
-	        case PCI_DEVICE_ID_INTEL_82801E_11:
-			p += sprintf(p, "\n                                Intel PIIX4 Ultra 100 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_INTEL_82372FB_1:
-		case PCI_DEVICE_ID_INTEL_82801AA_1:
-			p += sprintf(p, "\n                                Intel PIIX4 Ultra 66 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_INTEL_82451NX:
-		case PCI_DEVICE_ID_INTEL_82801AB_1:
-		case PCI_DEVICE_ID_INTEL_82443MX_1:
-		case PCI_DEVICE_ID_INTEL_82371AB:
-			p += sprintf(p, "\n                                Intel PIIX4 Ultra 33 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_INTEL_82371SB_1:
-			p += sprintf(p, "\n                                Intel PIIX3 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_INTEL_82371MX:
-			p += sprintf(p, "\n                                Intel MPIIX Chipset.\n");
-			return p-buffer;	/* => must be less than 4k! */
-		case PCI_DEVICE_ID_INTEL_82371FB_1:
-		case PCI_DEVICE_ID_INTEL_82371FB_0:
-		default:
-			p += sprintf(p, "\n                                Intel PIIX Chipset.\n");
-			break;
-	}
-
-	pci_read_config_word(bmide_dev, 0x40, &reg40);
-	pci_read_config_word(bmide_dev, 0x42, &reg42);
-	pci_read_config_byte(bmide_dev, 0x44, &reg44);
-	pci_read_config_byte(bmide_dev, 0x48, &reg48);
-	pci_read_config_byte(bmide_dev, 0x4a, &reg4a);
-	pci_read_config_byte(bmide_dev, 0x4b, &reg4b);
-	pci_read_config_byte(bmide_dev, 0x54, &reg54);
-	pci_read_config_byte(bmide_dev, 0x55, &reg55);
-
-	psitre = (reg40 & 0x4000) ? 1 : 0;
-	ssitre = (reg42 & 0x4000) ? 1 : 0;
-
-	/*
-	 * at that point bibma+0x2 et bibma+0xa are byte registers
-	 * to investigate:
-	 */
-	c0 = inb_p((unsigned short)bibma + 0x02);
-	c1 = inb_p((unsigned short)bibma + 0x0a);
-
-	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
-	p += sprintf(p, "                %sabled                         %sabled\n",
-			(c0&0x80) ? "dis" : " en",
-			(c1&0x80) ? "dis" : " en");
-	p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
-	p += sprintf(p, "DMA enabled:    %s              %s             %s               %s\n",
-			(c0&0x20) ? "yes" : "no ",
-			(c0&0x40) ? "yes" : "no ",
-			(c1&0x20) ? "yes" : "no ",
-			(c1&0x40) ? "yes" : "no " );
-	p += sprintf(p, "UDMA enabled:   %s              %s             %s               %s\n",
-			(reg48&0x01) ? "yes" : "no ",
-			(reg48&0x02) ? "yes" : "no ",
-			(reg48&0x04) ? "yes" : "no ",
-			(reg48&0x08) ? "yes" : "no " );
-	p += sprintf(p, "UDMA enabled:   %s                %s               %s                 %s\n",
-			((reg54&0x11) && (reg55&0x10) && (reg4a&0x01)) ? "5" :
-			((reg54&0x11) && (reg4a&0x02)) ? "4" :
-			((reg54&0x11) && (reg4a&0x01)) ? "3" :
-			(reg4a&0x02) ? "2" :
-			(reg4a&0x01) ? "1" :
-			(reg4a&0x00) ? "0" : "X",
-			((reg54&0x22) && (reg55&0x20) && (reg4a&0x10)) ? "5" :
-			((reg54&0x22) && (reg4a&0x20)) ? "4" :
-			((reg54&0x22) && (reg4a&0x10)) ? "3" :
-			(reg4a&0x20) ? "2" :
-			(reg4a&0x10) ? "1" :
-			(reg4a&0x00) ? "0" : "X",
-			((reg54&0x44) && (reg55&0x40) && (reg4b&0x03)) ? "5" :
-			((reg54&0x44) && (reg4b&0x02)) ? "4" :
-			((reg54&0x44) && (reg4b&0x01)) ? "3" :
-			(reg4b&0x02) ? "2" :
-			(reg4b&0x01) ? "1" :
-			(reg4b&0x00) ? "0" : "X",
-			((reg54&0x88) && (reg55&0x80) && (reg4b&0x30)) ? "5" :
-			((reg54&0x88) && (reg4b&0x20)) ? "4" :
-			((reg54&0x88) && (reg4b&0x10)) ? "3" :
-			(reg4b&0x20) ? "2" :
-			(reg4b&0x10) ? "1" :
-			(reg4b&0x00) ? "0" : "X");
-
-	p += sprintf(p, "UDMA\n");
-	p += sprintf(p, "DMA\n");
-	p += sprintf(p, "PIO\n");
-
-/*
- *	FIXME.... Add configuration junk data....blah blah......
- */
-
-	return p-buffer;	 /* => must be less than 4k! */
-}
-#endif  /* defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-/*
- *  Used to set Fifo configuration via kernel command line:
- */
-
-byte piix_proc = 0;
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-#if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_PIIX_TUNING)
-/*
- *
- */
-static byte piix_dma_2_pio (byte xfer_rate) {
-	switch(xfer_rate) {
-		case XFER_UDMA_5:
-		case XFER_UDMA_4:
-		case XFER_UDMA_3:
-		case XFER_UDMA_2:
-		case XFER_UDMA_1:
-		case XFER_UDMA_0:
-		case XFER_MW_DMA_2:
-		case XFER_PIO_4:
-			return 4;
-		case XFER_MW_DMA_1:
-		case XFER_PIO_3:
-			return 3;
-		case XFER_SW_DMA_2:
-		case XFER_PIO_2:
-			return 2;
-		case XFER_MW_DMA_0:
-		case XFER_SW_DMA_1:
-		case XFER_SW_DMA_0:
-		case XFER_PIO_1:
-		case XFER_PIO_0:
-		case XFER_PIO_SLOW:
-		default:
-			return 0;
-	}
-}
-#endif /* defined(CONFIG_BLK_DEV_IDEDMA) && (CONFIG_PIIX_TUNING) */
-
-/*
- *  Based on settings done by AMI BIOS
- *  (might be useful if drive is not registered in CMOS for any reason).
- */
-static void piix_tune_drive (ide_drive_t *drive, byte pio)
-{
-	unsigned long flags;
-	u16 master_data;
-	byte slave_data;
-	int is_slave		= (&HWIF(drive)->drives[1] == drive);
-	int master_port		= HWIF(drive)->index ? 0x42 : 0x40;
-	int slave_port		= 0x44;
-				 /* ISP  RTC */
-	byte timings[][2]	= { { 0, 0 },
-				    { 0, 0 },
-				    { 1, 0 },
-				    { 2, 1 },
-				    { 2, 3 }, };
-
-	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
-	pci_read_config_word(HWIF(drive)->pci_dev, master_port, &master_data);
-	if (is_slave) {
-		master_data = master_data | 0x4000;
-		if (pio > 1)
-			/* enable PPE, IE and TIME */
-			master_data = master_data | 0x0070;
-		pci_read_config_byte(HWIF(drive)->pci_dev, slave_port, &slave_data);
-		slave_data = slave_data & (HWIF(drive)->index ? 0x0f : 0xf0);
-		slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1])
-					   << (HWIF(drive)->index ? 4 : 0));
-	} else {
-		master_data = master_data & 0xccf8;
-		if (pio > 1)
-			/* enable PPE, IE and TIME */
-			master_data = master_data | 0x0007;
-		master_data = master_data | (timings[pio][0] << 12) |
-			      (timings[pio][1] << 8);
-	}
-	save_flags(flags);
-	cli();
-	pci_write_config_word(HWIF(drive)->pci_dev, master_port, master_data);
-	if (is_slave)
-		pci_write_config_byte(HWIF(drive)->pci_dev, slave_port, slave_data);
-	restore_flags(flags);
-}
-
-#if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_PIIX_TUNING)
-static int piix_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte maslave		= hwif->channel ? 0x42 : 0x40;
-	int a_speed		= 3 << (drive->dn * 4);
-	int u_flag		= 1 << drive->dn;
-	int v_flag		= 0x01 << drive->dn;
-	int w_flag		= 0x10 << drive->dn;
-	int u_speed		= 0;
-	int err			= 0;
-	int			sitre;
-	short			reg4042, reg44, reg48, reg4a, reg54;
-	byte			reg55;
-
-	pci_read_config_word(dev, maslave, &reg4042);
-	sitre = (reg4042 & 0x4000) ? 1 : 0;
-	pci_read_config_word(dev, 0x44, &reg44);
-	pci_read_config_word(dev, 0x48, &reg48);
-	pci_read_config_word(dev, 0x4a, &reg4a);
-	pci_read_config_word(dev, 0x54, &reg54);
-	pci_read_config_byte(dev, 0x55, &reg55);
-
-	switch(speed) {
-		case XFER_UDMA_4:
-		case XFER_UDMA_2:	u_speed = 2 << (drive->dn * 4); break;
-		case XFER_UDMA_5:
-		case XFER_UDMA_3:
-		case XFER_UDMA_1:	u_speed = 1 << (drive->dn * 4); break;
-		case XFER_UDMA_0:	u_speed = 0 << (drive->dn * 4); break;
-		case XFER_MW_DMA_2:
-		case XFER_MW_DMA_1:
-		case XFER_SW_DMA_2:	break;
-		default:		return -1;
-	}
-
-	if (speed >= XFER_UDMA_0) {
-		if (!(reg48 & u_flag))
-			pci_write_config_word(dev, 0x48, reg48|u_flag);
-		if (speed == XFER_UDMA_5) {
-			pci_write_config_byte(dev, 0x55, (byte) reg55|w_flag);
-		} else {
-			pci_write_config_byte(dev, 0x55, (byte) reg55 & ~w_flag);
-		}
-		if (!(reg4a & u_speed)) {
-			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
-			pci_write_config_word(dev, 0x4a, reg4a|u_speed);
-		}
-		if (speed > XFER_UDMA_2) {
-			if (!(reg54 & v_flag)) {
-				pci_write_config_word(dev, 0x54, reg54|v_flag);
-			}
-		} else {
-			pci_write_config_word(dev, 0x54, reg54 & ~v_flag);
-		}
-	}
-	if (speed < XFER_UDMA_0) {
-		if (reg48 & u_flag)
-			pci_write_config_word(dev, 0x48, reg48 & ~u_flag);
-		if (reg4a & a_speed)
-			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
-		if (reg54 & v_flag)
-			pci_write_config_word(dev, 0x54, reg54 & ~v_flag);
-		if (reg55 & w_flag)
-			pci_write_config_byte(dev, 0x55, (byte) reg55 & ~w_flag);
-	}
-
-	piix_tune_drive(drive, piix_dma_2_pio(speed));
-
-#if PIIX_DEBUG_DRIVE_INFO
-	printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive->dn);
-#endif /* PIIX_DEBUG_DRIVE_INFO */
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-	err = ide_config_drive_speed(drive, speed);
-	drive->current_speed = speed;
-	return err;
-}
-
-static int piix_config_drive_for_dma (ide_drive_t *drive)
-{
-	struct hd_driveid *id	= drive->id;
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte			speed;
-
-	byte udma_66		= eighty_ninty_three(drive);
-	int ultra100		= ((dev->device == PCI_DEVICE_ID_INTEL_82801BA_8) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82801BA_9) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82801CA_10) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82801CA_11) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82801DB_11) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82801E_11)) ? 1 : 0;
-	int ultra66		= ((ultra100) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82801AA_1) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82372FB_1)) ? 1 : 0;
-	int ultra		= ((ultra66) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82371AB) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82443MX_1) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82451NX) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82801AB_1)) ? 1 : 0;
-
-	if ((id->dma_ultra & 0x0020) && (udma_66) && (ultra100)) {
-		speed = XFER_UDMA_5;
-	} else if ((id->dma_ultra & 0x0010) && (ultra)) {
-		speed = ((udma_66) && (ultra66)) ? XFER_UDMA_4 : XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0008) && (ultra)) {
-		speed = ((udma_66) && (ultra66)) ? XFER_UDMA_3 : XFER_UDMA_1;
-	} else if ((id->dma_ultra & 0x0004) && (ultra)) {
-		speed = XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0002) && (ultra)) {
-		speed = XFER_UDMA_1;
-	} else if ((id->dma_ultra & 0x0001) && (ultra)) {
-		speed = XFER_UDMA_0;
-	} else if (id->dma_mword & 0x0004) {
-		speed = XFER_MW_DMA_2;
-	} else if (id->dma_mword & 0x0002) {
-		speed = XFER_MW_DMA_1;
-	} else if (id->dma_1word & 0x0004) {
-		speed = XFER_SW_DMA_2;
-        } else {
-		speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
-	}
-
-	(void) piix_tune_chipset(drive, speed);
-
-	return ((int)	((id->dma_ultra >> 11) & 7) ? ide_dma_on :
-			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-			((id->dma_mword >> 8) & 7) ? ide_dma_on :
-			((id->dma_1word >> 8) & 7) ? ide_dma_on :
-						     ide_dma_off_quietly);
-}
-
-static void config_chipset_for_pio (ide_drive_t *drive)
-{
-	piix_tune_drive(drive, ide_get_best_pio_mode(drive, 255, 5, NULL));
-}
-
-static int config_drive_xfer_rate (ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-	ide_dma_action_t dma_func = ide_dma_on;
-
-	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x003F) {
-				/* Force if Capable UltraDMA */
-				dma_func = piix_config_drive_for_dma(drive);
-				if ((id->field_valid & 2) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    (id->dma_1word & 0x007)) {
-				/* Force if Capable regular DMA modes */
-				dma_func = piix_config_drive_for_dma(drive);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			dma_func = piix_config_drive_for_dma(drive);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-		config_chipset_for_pio(drive);
-	}
-	return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-static int piix_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch (func) {
-		case ide_dma_check:
-			return config_drive_xfer_rate(drive);
-		default :
-			break;
-	}
-	/* Other cases are done by generic IDE-DMA code. */
-	return ide_dmaproc(func, drive);
-}
-#endif /* defined(CONFIG_BLK_DEV_IDEDMA) && (CONFIG_PIIX_TUNING) */
-
-unsigned int __init pci_init_piix (struct pci_dev *dev, const char *name)
-{
-#if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!piix_proc) {
-		piix_proc = 1;
-		bmide_dev = dev;
-		piix_display_info = &piix_get_info;
-	}
-#endif /* DISPLAY_PIIX_TIMINGS && CONFIG_PROC_FS */
-	return 0;
-}
-
-/*
- * Sheesh, someone at Intel needs to go read the ATA-4/5 T13 standards.
- * It does not specify device detection, but channel!!!
- * You determine later if bit 13 of word93 is set...
- */
-unsigned int __init ata66_piix (ide_hwif_t *hwif)
-{
-	byte reg54h = 0, reg55h = 0, ata66 = 0;
-	byte mask = hwif->channel ? 0xc0 : 0x30;
-
-	pci_read_config_byte(hwif->pci_dev, 0x54, &reg54h);
-	pci_read_config_byte(hwif->pci_dev, 0x55, &reg55h);
-
-	ata66 = (reg54h & mask) ? 1 : 0;
-
-	return ata66;
-}
-
-void __init ide_init_piix (ide_hwif_t *hwif)
-{
-#ifndef CONFIG_IA64
-	if (!hwif->irq)
-		hwif->irq = hwif->channel ? 15 : 14;
-#endif /* CONFIG_IA64 */
-
-	if (hwif->pci_dev->device == PCI_DEVICE_ID_INTEL_82371MX) {
-		/* This is a painful system best to let it self tune for now */
-		return;
-	}
-
-	hwif->tuneproc = &piix_tune_drive;
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-
-	if (!hwif->dma_base)
-		return;
-
-#ifndef CONFIG_BLK_DEV_IDEDMA
-	hwif->autodma = 0;
-#else /* CONFIG_BLK_DEV_IDEDMA */
-#ifdef CONFIG_PIIX_TUNING
-	if (!noautodma)
-		hwif->autodma = 1;
-	hwif->dmaproc = &piix_dmaproc;
-	hwif->speedproc = &piix_tune_chipset;
-#endif /* CONFIG_PIIX_TUNING */
-#endif /* !CONFIG_BLK_DEV_IDEDMA */
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ppc/Makefile linux-2.4.21-pre6/drivers/ide/ppc/Makefile
--- linux-2.4.20/drivers/ide/ppc/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/ppc/Makefile	2003-03-26 23:49:53.000000000 +0000
@@ -0,0 +1,13 @@
+
+O_TARGET := idedriver-ppc.o
+
+obj-y		:=
+obj-m		:=
+
+obj-$(CONFIG_BLK_DEV_MPC8xx_IDE)	+= mpc8xx.o
+obj-$(CONFIG_BLK_DEV_IDE_PMAC)		+= pmac.o
+obj-$(CONFIG_BLK_DEV_IDE_SWARM)		+= swarm.o
+
+EXTRA_CFLAGS	:= -I../
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ppc/mpc8xx.c linux-2.4.21-pre6/drivers/ide/ppc/mpc8xx.c
--- linux-2.4.20/drivers/ide/ppc/mpc8xx.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/ppc/mpc8xx.c	2003-03-26 23:49:31.000000000 +0000
@@ -0,0 +1,857 @@
+/*
+ *  linux/drivers/ide/ppc/ide-m8xx.c
+ *
+ *  Copyright (C) 2000, 2001 Wolfgang Denk, wd@denx.de
+ *  Modified for direct IDE interface
+ *	by Thomas Lange, thomas@corelatus.com
+ *  Modified for direct IDE interface on 8xx without using the PCMCIA
+ *  controller
+ *	by Steven.Scholz@imc-berlin.de
+ *  Moved out of arch/ppc/kernel/m8xx_setup.c, other minor cleanups
+ *	by Mathew Locke <mattl@mvista.com>
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/major.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/blk.h>
+#include <linux/ioport.h>
+#include <linux/ide.h>
+#include <linux/bootmem.h>
+
+#include <asm/mpc8xx.h>
+#include <asm/mmu.h>
+#include <asm/processor.h>
+#include <asm/residual.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/ide.h>
+#include <asm/8xx_immap.h>
+#include <asm/machdep.h>
+#include <asm/irq.h>
+
+#include "ide_modes.h"
+static int identify  (volatile u8 *p);
+static void print_fixed (volatile u8 *p);
+static void print_funcid (int func);
+static int check_ide_device (unsigned long base);
+
+static void ide_interrupt_ack (void *dev);
+static void m8xx_ide_tuneproc(ide_drive_t *drive, u8 pio);
+
+typedef	struct ide_ioport_desc {
+	unsigned long	base_off;		/* Offset to PCMCIA memory	*/
+	ide_ioreg_t	reg_off[IDE_NR_PORTS];	/* controller register offsets	*/
+	int		irq;			/* IRQ				*/
+} ide_ioport_desc_t;
+
+ide_ioport_desc_t ioport_dsc[MAX_HWIFS] = {
+#ifdef IDE0_BASE_OFFSET
+	{ IDE0_BASE_OFFSET,
+	    {
+		IDE0_DATA_REG_OFFSET,
+		IDE0_ERROR_REG_OFFSET,
+		IDE0_NSECTOR_REG_OFFSET,
+		IDE0_SECTOR_REG_OFFSET,
+		IDE0_LCYL_REG_OFFSET,
+		IDE0_HCYL_REG_OFFSET,
+		IDE0_SELECT_REG_OFFSET,
+		IDE0_STATUS_REG_OFFSET,
+		IDE0_CONTROL_REG_OFFSET,
+		IDE0_IRQ_REG_OFFSET,
+	    },
+	    IDE0_INTERRUPT,
+	},
+#ifdef IDE1_BASE_OFFSET
+	{ IDE1_BASE_OFFSET,
+	    {
+		IDE1_DATA_REG_OFFSET,
+		IDE1_ERROR_REG_OFFSET,
+		IDE1_NSECTOR_REG_OFFSET,
+		IDE1_SECTOR_REG_OFFSET,
+		IDE1_LCYL_REG_OFFSET,
+		IDE1_HCYL_REG_OFFSET,
+		IDE1_SELECT_REG_OFFSET,
+		IDE1_STATUS_REG_OFFSET,
+		IDE1_CONTROL_REG_OFFSET,
+		IDE1_IRQ_REG_OFFSET,
+	    },
+	    IDE1_INTERRUPT,
+	},
+#endif /* IDE1_BASE_OFFSET */
+#endif	/* IDE0_BASE_OFFSET */
+};
+
+ide_pio_timings_t ide_pio_clocks[6];
+int hold_time[6] =  {30, 20, 15, 10, 10, 10 };   /* PIO Mode 5 with IORDY (nonstandard) */
+
+/*
+ * Warning: only 1 (ONE) PCMCIA slot supported here,
+ * which must be correctly initialized by the firmware (PPCBoot).
+ */
+static int _slot_ = -1;			/* will be read from PCMCIA registers   */
+
+/* Make clock cycles and always round up */
+#define PCMCIA_MK_CLKS( t, T ) (( (t) * ((T)/1000000) + 999U ) / 1000U )
+
+
+
+/*
+ * IDE stuff.
+ */
+static int
+m8xx_ide_default_irq(ide_ioreg_t base)
+{
+#ifdef CONFIG_BLK_DEV_MPC8xx_IDE
+	if (base >= MAX_HWIFS)
+		return 0;
+
+	printk("[%d] m8xx_ide_default_irq %d\n",__LINE__,ioport_dsc[base].irq);
+	
+	return (ioport_dsc[base].irq);
+#else
+        return 9;
+#endif
+}
+
+static ide_ioreg_t
+m8xx_ide_default_io_base(int index)
+{
+        return index;
+}
+
+#define M8XX_PCMCIA_CD2(slot)      (0x10000000 >> (slot << 4))
+#define M8XX_PCMCIA_CD1(slot)      (0x08000000 >> (slot << 4))
+
+/*
+ * The TQM850L hardware has two pins swapped! Grrrrgh!
+ */
+#ifdef	CONFIG_TQM850L
+#define __MY_PCMCIA_GCRX_CXRESET	PCMCIA_GCRX_CXOE
+#define __MY_PCMCIA_GCRX_CXOE		PCMCIA_GCRX_CXRESET
+#else
+#define __MY_PCMCIA_GCRX_CXRESET	PCMCIA_GCRX_CXRESET
+#define __MY_PCMCIA_GCRX_CXOE		PCMCIA_GCRX_CXOE
+#endif
+
+#if defined(CONFIG_BLK_DEV_MPC8xx_IDE) && defined(CONFIG_IDE_8xx_PCCARD)
+#define PCMCIA_SCHLVL IDE0_INTERRUPT	/* Status Change Interrupt Level	*/
+static int pcmcia_schlvl = PCMCIA_SCHLVL;
+#endif
+
+/*
+ * See include/linux/ide.h for definition of hw_regs_t (p, base)
+ */
+
+/*
+ * m8xx_ide_init_hwif_ports for a direct IDE interface _using_
+ */
+#if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT)
+static void
+m8xx_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, 
+		ide_ioreg_t ctrl_port, int *irq)
+{
+	ide_ioreg_t *p = hw->io_ports;
+	int i;
+
+	typedef struct {
+		ulong br;
+		ulong or;
+	} pcmcia_win_t;
+	volatile pcmcia_win_t *win;
+	volatile pcmconf8xx_t *pcmp;
+
+	uint *pgcrx;
+	u32 pcmcia_phy_base;
+	u32 pcmcia_phy_end;
+	static unsigned long pcmcia_base = 0;
+	unsigned long base;
+
+	*p = 0;
+	if (irq)
+		*irq = 0;
+
+	pcmp = (pcmconf8xx_t *)(&(((immap_t *)IMAP_ADDR)->im_pcmcia));
+
+	if (!pcmcia_base) {
+                /*
+                 * Read out PCMCIA registers. Since the reset values
+                 * are undefined, we sure hope that they have been
+                 * set up by firmware
+		 */
+
+		/* Scan all registers for valid settings */
+		pcmcia_phy_base = 0xFFFFFFFF;
+		pcmcia_phy_end = 0;
+		/* br0 is start of brX and orX regs */
+		win = (pcmcia_win_t *) \
+			(&(((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0));
+		for (i = 0; i < 8; i++) {
+			if (win->or & 1) {	/* This bank is marked as valid */
+				if (win->br < pcmcia_phy_base) {
+					pcmcia_phy_base = win->br;
+				}
+				if ((win->br + PCMCIA_MEM_SIZE) > pcmcia_phy_end) {
+					pcmcia_phy_end  = win->br + PCMCIA_MEM_SIZE;
+				}
+				/* Check which slot that has been defined */
+				_slot_ = (win->or >> 2) & 1;
+
+			}					/* Valid bank */
+			win++;
+		}						/* for */
+
+		printk ("PCMCIA slot %c: phys mem %08x...%08x (size %08x)\n",
+			'A' + _slot_,
+			pcmcia_phy_base, pcmcia_phy_end,
+			pcmcia_phy_end - pcmcia_phy_base);
+
+		pcmcia_base=(unsigned long)ioremap(pcmcia_phy_base,
+						   pcmcia_phy_end-pcmcia_phy_base);
+
+#ifdef DEBUG
+		printk ("PCMCIA virt base: %08lx\n", pcmcia_base);
+#endif
+		/* Compute clock cycles for PIO timings */
+		for (i=0; i<6; ++i) {
+			bd_t	*binfo = (bd_t *)__res;
+
+			hold_time[i]   =
+				PCMCIA_MK_CLKS (hold_time[i],
+						binfo->bi_busfreq);
+			ide_pio_clocks[i].setup_time  =
+				PCMCIA_MK_CLKS (ide_pio_timings[i].setup_time,
+						binfo->bi_busfreq);
+			ide_pio_clocks[i].active_time =
+				PCMCIA_MK_CLKS (ide_pio_timings[i].active_time,
+						binfo->bi_busfreq);
+			ide_pio_clocks[i].cycle_time  =
+				PCMCIA_MK_CLKS (ide_pio_timings[i].cycle_time,
+						binfo->bi_busfreq);
+#if 0
+			printk ("PIO mode %d timings: %d/%d/%d => %d/%d/%d\n",
+				i,
+				ide_pio_clocks[i].setup_time,
+				ide_pio_clocks[i].active_time,
+				ide_pio_clocks[i].hold_time,
+				ide_pio_clocks[i].cycle_time,
+				ide_pio_timings[i].setup_time,
+				ide_pio_timings[i].active_time,
+				ide_pio_timings[i].hold_time,
+				ide_pio_timings[i].cycle_time);
+#endif
+		}
+	}
+
+	if (data_port >= MAX_HWIFS)
+		return;
+
+	if (_slot_ == -1) {
+		printk ("PCMCIA slot has not been defined! Using A as default\n");
+		_slot_ = 0;
+	}
+
+#ifdef CONFIG_IDE_8xx_PCCARD
+
+#ifdef DEBUG
+	printk ("PIPR = 0x%08X  slot %c ==> mask = 0x%X\n",
+		pcmp->pcmc_pipr,
+		'A' + _slot_,
+		M8XX_PCMCIA_CD1(_slot_) | M8XX_PCMCIA_CD2(_slot_) );
+#endif /* DEBUG */
+
+	if (pcmp->pcmc_pipr & (M8XX_PCMCIA_CD1(_slot_)|M8XX_PCMCIA_CD2(_slot_))) {
+		printk ("No card in slot %c: PIPR=%08x\n",
+			'A' + _slot_, (u32) pcmp->pcmc_pipr);
+		return;		/* No card in slot */
+	}
+
+	check_ide_device (pcmcia_base);
+
+#endif	/* CONFIG_IDE_8xx_PCCARD */
+
+	base = pcmcia_base + ioport_dsc[data_port].base_off;
+#ifdef DEBUG
+	printk ("base: %08x + %08x = %08x\n",
+			pcmcia_base, ioport_dsc[data_port].base_off, base);
+#endif
+
+	for (i = 0; i < IDE_NR_PORTS; ++i) {
+#ifdef DEBUG
+		printk ("port[%d]: %08x + %08x = %08x\n",
+			i,
+			base,
+			ioport_dsc[data_port].reg_off[i],
+			i, base + ioport_dsc[data_port].reg_off[i]);
+#endif
+	 	*p++ = base + ioport_dsc[data_port].reg_off[i];
+	}
+
+	if (irq) {
+#ifdef CONFIG_IDE_8xx_PCCARD
+		unsigned int reg;
+
+		*irq = ioport_dsc[data_port].irq;
+		if (_slot_)
+			pgcrx = &((immap_t *) IMAP_ADDR)->im_pcmcia.pcmc_pgcrb;
+		else
+			pgcrx = &((immap_t *) IMAP_ADDR)->im_pcmcia.pcmc_pgcra;
+
+		reg = *pgcrx;
+		reg |= mk_int_int_mask (pcmcia_schlvl) << 24;
+		reg |= mk_int_int_mask (pcmcia_schlvl) << 16;
+		*pgcrx = reg;
+#else	/* direct connected IDE drive, i.e. external IRQ, not the PCMCIA irq */
+		*irq = ioport_dsc[data_port].irq;
+#endif	/* CONFIG_IDE_8xx_PCCARD */
+	}
+
+	/* register routine to tune PIO mode */
+	ide_hwifs[data_port].tuneproc = m8xx_ide_tuneproc;
+
+	hw->ack_intr = (ide_ack_intr_t *) ide_interrupt_ack;
+	/* Enable Harddisk Interrupt,
+	 * and make it edge sensitive
+	 */
+	/* (11-18) Set edge detect for irq, no wakeup from low power mode */
+	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_siel |=
+					(0x80000000 >> ioport_dsc[data_port].irq);
+
+#ifdef CONFIG_IDE_8xx_PCCARD
+	/* Make sure we dont get garbage irq */
+	((immap_t *) IMAP_ADDR)->im_pcmcia.pcmc_pscr = 0xFFFF;
+
+	/* Enable falling edge irq */
+	pcmp->pcmc_per = 0x100000 >> (16 * _slot_);
+#endif	/* CONFIG_IDE_8xx_PCCARD */
+}	/* m8xx_ide_init_hwif_ports() using 8xx internal PCMCIA interface */
+#endif /* CONFIG_IDE_8xx_PCCARD || CONFIG_IDE_8xx_DIRECT */
+
+/*
+ * m8xx_ide_init_hwif_ports for a direct IDE interface _not_ using
+ * MPC8xx's internal PCMCIA interface
+ */
+#if defined(CONFIG_IDE_EXT_DIRECT)
+void m8xx_ide_init_hwif_ports (hw_regs_t *hw,
+	ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
+{
+	ide_ioreg_t *p = hw->io_ports;
+	int i;
+
+	u32 ide_phy_base;
+	u32 ide_phy_end;
+	static unsigned long ide_base = 0;
+	unsigned long base;
+
+	*p = 0;
+	if (irq)
+		*irq = 0;
+
+	if (!ide_base) {
+
+		/* TODO:
+		 * - add code to read ORx, BRx
+		 */
+		ide_phy_base = CFG_ATA_BASE_ADDR;
+		ide_phy_end  = CFG_ATA_BASE_ADDR + 0x200;
+
+		printk ("IDE phys mem : %08x...%08x (size %08x)\n",
+			ide_phy_base, ide_phy_end,
+			ide_phy_end - ide_phy_base);
+		
+		ide_base=(unsigned long)ioremap(ide_phy_base,
+						ide_phy_end-ide_phy_base);
+
+#ifdef DEBUG
+		printk ("IDE virt base: %08lx\n", ide_base);
+#endif
+	}
+
+	if (data_port >= MAX_HWIFS)
+		return;
+
+	base = ide_base + ioport_dsc[data_port].base_off;
+#ifdef DEBUG
+	printk ("base: %08x + %08x = %08x\n",
+		ide_base, ioport_dsc[data_port].base_off, base);
+#endif
+
+	for (i = 0; i < IDE_NR_PORTS; ++i) {
+#ifdef DEBUG
+		printk ("port[%d]: %08x + %08x = %08x\n",
+			i,
+			base,
+			ioport_dsc[data_port].reg_off[i],
+			i, base + ioport_dsc[data_port].reg_off[i]);
+#endif
+	 	*p++ = base + ioport_dsc[data_port].reg_off[i];
+	}
+
+	if (irq) {
+		/* direct connected IDE drive, i.e. external IRQ */
+		*irq = ioport_dsc[data_port].irq;
+	}
+
+	/* register routine to tune PIO mode */
+	ide_hwifs[data_port].tuneproc = m8xx_ide_tuneproc;
+
+	hw->ack_intr = (ide_ack_intr_t *) ide_interrupt_ack;
+	/* Enable Harddisk Interrupt,
+	 * and make it edge sensitive
+	 */
+	/* (11-18) Set edge detect for irq, no wakeup from low power mode */
+	((immap_t *) IMAP_ADDR)->im_siu_conf.sc_siel |=
+			(0x80000000 >> ioport_dsc[data_port].irq);
+}	/* m8xx_ide_init_hwif_ports() for CONFIG_IDE_8xx_DIRECT */ 
+
+#endif	/* CONFIG_IDE_8xx_DIRECT */
+
+
+/* -------------------------------------------------------------------- */
+
+
+/* PCMCIA Timing */
+#ifndef	PCMCIA_SHT
+#define PCMCIA_SHT(t)	((t & 0x0F)<<16)	/* Strobe Hold  Time 	*/
+#define PCMCIA_SST(t)	((t & 0x0F)<<12)	/* Strobe Setup Time	*/
+#define PCMCIA_SL(t) ((t==32) ? 0 : ((t & 0x1F)<<7)) /* Strobe Length	*/
+#endif
+
+
+/* Calculate PIO timings */
+static void
+m8xx_ide_tuneproc(ide_drive_t *drive, u8 pio)
+{
+	ide_pio_data_t d;
+#if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT)
+	volatile pcmconf8xx_t	*pcmp;
+	ulong timing, mask, reg;
+#endif
+
+	pio = ide_get_best_pio_mode(drive, pio, 4, &d);
+
+#if 1
+	printk("%s[%d] %s: best PIO mode: %d\n",
+		__FILE__,__LINE__,__FUNCTION__, pio);
+#endif
+
+#if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT)
+	pcmp = (pcmconf8xx_t *)(&(((immap_t *)IMAP_ADDR)->im_pcmcia));
+
+	mask = ~(PCMCIA_SHT(0xFF) | PCMCIA_SST(0xFF) | PCMCIA_SL(0xFF));
+
+	timing  = PCMCIA_SHT(hold_time[pio]  )
+		| PCMCIA_SST(ide_pio_clocks[pio].setup_time )
+		| PCMCIA_SL (ide_pio_clocks[pio].active_time)
+		;
+
+#if 1
+	printk ("Setting timing bits 0x%08lx in PCMCIA controller\n", timing);
+#endif
+	if ((reg = pcmp->pcmc_por0 & mask) != 0)
+		pcmp->pcmc_por0 = reg | timing;
+
+	if ((reg = pcmp->pcmc_por1 & mask) != 0)
+		pcmp->pcmc_por1 = reg | timing;
+
+	if ((reg = pcmp->pcmc_por2 & mask) != 0)
+		pcmp->pcmc_por2 = reg | timing;
+
+	if ((reg = pcmp->pcmc_por3 & mask) != 0)
+		pcmp->pcmc_por3 = reg | timing;
+
+	if ((reg = pcmp->pcmc_por4 & mask) != 0)
+		pcmp->pcmc_por4 = reg | timing;
+
+	if ((reg = pcmp->pcmc_por5 & mask) != 0)
+		pcmp->pcmc_por5 = reg | timing;
+
+	if ((reg = pcmp->pcmc_por6 & mask) != 0)
+		pcmp->pcmc_por6 = reg | timing;
+
+	if ((reg = pcmp->pcmc_por7 & mask) != 0)
+		pcmp->pcmc_por7 = reg | timing;
+
+#elif defined(CONFIG_IDE_EXT_DIRECT)
+
+	printk("%s[%d] %s: not implemented yet!\n",
+		__FILE__,__LINE__,__FUNCTION__);
+#endif /* defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_PCMCIA */
+}
+
+static void
+ide_interrupt_ack (void *dev)
+{
+#ifdef CONFIG_IDE_8xx_PCCARD
+	u_int pscr, pipr;
+
+#if (PCMCIA_SOCKETS_NO == 2)
+	u_int _slot_;
+#endif
+
+	/* get interrupt sources */
+
+	pscr = ((volatile immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr;
+	pipr = ((volatile immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pipr;
+
+	/*
+	 * report only if both card detect signals are the same
+	 * not too nice done,
+	 * we depend on that CD2 is the bit to the left of CD1...
+	 */
+
+	if(_slot_==-1){
+	  printk("PCMCIA slot has not been defined! Using A as default\n");
+	  _slot_=0;
+	}
+
+	if(((pipr & M8XX_PCMCIA_CD2(_slot_)) >> 1) ^
+	   (pipr & M8XX_PCMCIA_CD1(_slot_))         ) {
+	  printk ("card detect interrupt\n");
+	}
+	/* clear the interrupt sources */
+	((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr = pscr;
+
+#else /* ! CONFIG_IDE_8xx_PCCARD */
+	/*
+	 * Only CONFIG_IDE_8xx_PCCARD is using the interrupt of the
+	 * MPC8xx's PCMCIA controller, so there is nothing to be done here
+	 * for CONFIG_IDE_8xx_DIRECT and CONFIG_IDE_EXT_DIRECT.
+	 * The interrupt is handled somewhere else.	-- Steven
+	 */
+#endif /* CONFIG_IDE_8xx_PCCARD */
+}
+
+
+
+/*
+ * CIS Tupel codes
+ */
+#define CISTPL_NULL		0x00
+#define CISTPL_DEVICE		0x01
+#define CISTPL_LONGLINK_CB	0x02
+#define CISTPL_INDIRECT		0x03
+#define CISTPL_CONFIG_CB	0x04
+#define CISTPL_CFTABLE_ENTRY_CB 0x05
+#define CISTPL_LONGLINK_MFC	0x06
+#define CISTPL_BAR		0x07
+#define CISTPL_PWR_MGMNT	0x08
+#define CISTPL_EXTDEVICE	0x09
+#define CISTPL_CHECKSUM		0x10
+#define CISTPL_LONGLINK_A	0x11
+#define CISTPL_LONGLINK_C	0x12
+#define CISTPL_LINKTARGET	0x13
+#define CISTPL_NO_LINK		0x14
+#define CISTPL_VERS_1		0x15
+#define CISTPL_ALTSTR		0x16
+#define CISTPL_DEVICE_A		0x17
+#define CISTPL_JEDEC_C		0x18
+#define CISTPL_JEDEC_A		0x19
+#define CISTPL_CONFIG		0x1a
+#define CISTPL_CFTABLE_ENTRY	0x1b
+#define CISTPL_DEVICE_OC	0x1c
+#define CISTPL_DEVICE_OA	0x1d
+#define CISTPL_DEVICE_GEO	0x1e
+#define CISTPL_DEVICE_GEO_A	0x1f
+#define CISTPL_MANFID		0x20
+#define CISTPL_FUNCID		0x21
+#define CISTPL_FUNCE		0x22
+#define CISTPL_SWIL		0x23
+#define CISTPL_END		0xff
+
+/*
+ * CIS Function ID codes
+ */
+#define CISTPL_FUNCID_MULTI	0x00
+#define CISTPL_FUNCID_MEMORY	0x01
+#define CISTPL_FUNCID_SERIAL	0x02
+#define CISTPL_FUNCID_PARALLEL	0x03
+#define CISTPL_FUNCID_FIXED	0x04
+#define CISTPL_FUNCID_VIDEO	0x05
+#define CISTPL_FUNCID_NETWORK	0x06
+#define CISTPL_FUNCID_AIMS	0x07
+#define CISTPL_FUNCID_SCSI	0x08
+
+/*
+ * Fixed Disk FUNCE codes
+ */
+#define CISTPL_IDE_INTERFACE	0x01
+
+#define CISTPL_FUNCE_IDE_IFACE	0x01
+#define CISTPL_FUNCE_IDE_MASTER	0x02
+#define CISTPL_FUNCE_IDE_SLAVE	0x03
+
+/* First feature byte */
+#define CISTPL_IDE_SILICON	0x04
+#define CISTPL_IDE_UNIQUE	0x08
+#define CISTPL_IDE_DUAL		0x10
+
+/* Second feature byte */
+#define CISTPL_IDE_HAS_SLEEP	0x01
+#define CISTPL_IDE_HAS_STANDBY	0x02
+#define CISTPL_IDE_HAS_IDLE	0x04
+#define CISTPL_IDE_LOW_POWER	0x08
+#define CISTPL_IDE_REG_INHIBIT	0x10
+#define CISTPL_IDE_HAS_INDEX	0x20
+#define CISTPL_IDE_IOIS16	0x40
+
+
+/* -------------------------------------------------------------------- */
+
+
+#define	MAX_TUPEL_SZ	512
+#define MAX_FEATURES	4
+
+static int check_ide_device (unsigned long base)
+{
+	volatile u8 *ident = NULL;
+	volatile u8 *feature_p[MAX_FEATURES];
+	volatile u8 *p, *start;
+	int n_features = 0;
+	u8 func_id = ~0;
+	u8 code, len;
+	unsigned short config_base = 0;
+	int found = 0;
+	int i;
+
+#ifdef DEBUG
+	printk ("PCMCIA MEM: %08lX\n", base);
+#endif
+	start = p = (volatile u8 *) base;
+
+	while ((p - start) < MAX_TUPEL_SZ) {
+
+		code = *p; p += 2;
+
+		if (code == 0xFF) { /* End of chain */
+			break;
+		}
+
+		len = *p; p += 2;
+#ifdef	DEBUG_PCMCIA
+		{ volatile u8 *q = p;
+			printk ("\nTuple code %02x  length %d\n\tData:",
+				code, len);
+
+			for (i = 0; i < len; ++i) {
+				printk (" %02x", *q);
+				q+= 2;
+			}
+		}
+#endif	/* DEBUG_PCMCIA */
+		switch (code) {
+		case CISTPL_VERS_1:
+			ident = p + 4;
+			break;
+		case CISTPL_FUNCID:
+			func_id = *p;
+			break;
+		case CISTPL_FUNCE:
+			if (n_features < MAX_FEATURES)
+				feature_p[n_features++] = p;
+			break;
+		case CISTPL_CONFIG:
+			config_base = (*(p+6) << 8) + (*(p+4));
+		default:
+			break;
+		}
+		p += 2 * len;
+	}
+
+	found = identify (ident);
+
+	if (func_id != ((u8)~0)) {
+		print_funcid (func_id);
+
+		if (func_id == CISTPL_FUNCID_FIXED)
+			found = 1;
+		else
+			return (1);	/* no disk drive */
+	}
+
+	for (i=0; i<n_features; ++i) {
+		print_fixed (feature_p[i]);
+	}
+
+	if (!found) {
+		printk ("unknown card type\n");
+		return (1);
+	}
+
+	/* set level mode irq and I/O mapped device in config reg*/
+	*((u8 *)(base + config_base)) = 0x41;
+
+	return (0);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void print_funcid (int func)
+{
+	switch (func) {
+	case CISTPL_FUNCID_MULTI:
+		printk (" Multi-Function");
+		break;
+	case CISTPL_FUNCID_MEMORY:
+		printk (" Memory");
+		break;
+	case CISTPL_FUNCID_SERIAL:
+		printk (" Serial Port");
+		break;
+	case CISTPL_FUNCID_PARALLEL:
+		printk (" Parallel Port");
+		break;
+	case CISTPL_FUNCID_FIXED:
+		printk (" Fixed Disk");
+		break;
+	case CISTPL_FUNCID_VIDEO:
+		printk (" Video Adapter");
+		break;
+	case CISTPL_FUNCID_NETWORK:
+		printk (" Network Adapter");
+		break;
+	case CISTPL_FUNCID_AIMS:
+		printk (" AIMS Card");
+		break;
+	case CISTPL_FUNCID_SCSI:
+		printk (" SCSI Adapter");
+		break;
+	default:
+		printk (" Unknown");
+		break;
+	}
+	printk (" Card\n");
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void print_fixed (volatile u8 *p)
+{
+	if (p == NULL)
+		return;
+
+	switch (*p) {
+	case CISTPL_FUNCE_IDE_IFACE:
+	    {   u8 iface = *(p+2);
+
+		printk ((iface == CISTPL_IDE_INTERFACE) ? " IDE" : " unknown");
+		printk (" interface ");
+		break;
+	    }
+	case CISTPL_FUNCE_IDE_MASTER:
+	case CISTPL_FUNCE_IDE_SLAVE:
+	    {   u8 f1 = *(p+2);
+		u8 f2 = *(p+4);
+
+		printk ((f1 & CISTPL_IDE_SILICON) ? " [silicon]" : " [rotating]");
+
+		if (f1 & CISTPL_IDE_UNIQUE)
+			printk (" [unique]");
+
+		printk ((f1 & CISTPL_IDE_DUAL) ? " [dual]" : " [single]");
+
+		if (f2 & CISTPL_IDE_HAS_SLEEP)
+			printk (" [sleep]");
+
+		if (f2 & CISTPL_IDE_HAS_STANDBY)
+			printk (" [standby]");
+
+		if (f2 & CISTPL_IDE_HAS_IDLE)
+			printk (" [idle]");
+
+		if (f2 & CISTPL_IDE_LOW_POWER)
+			printk (" [low power]");
+
+		if (f2 & CISTPL_IDE_REG_INHIBIT)
+			printk (" [reg inhibit]");
+
+		if (f2 & CISTPL_IDE_HAS_INDEX)
+			printk (" [index]");
+
+		if (f2 & CISTPL_IDE_IOIS16)
+			printk (" [IOis16]");
+
+		break;
+	    }
+	}
+	printk ("\n");
+}
+
+/* ------------------------------------------------------------------------- */
+
+
+#define MAX_IDENT_CHARS		64
+#define	MAX_IDENT_FIELDS	4
+
+static u8 *known_cards[] = {
+	"ARGOSY PnPIDE D5",
+	NULL
+};
+
+static int identify  (volatile u8 *p)
+{
+	u8 id_str[MAX_IDENT_CHARS];
+	u8 data;
+	u8 *t;
+	u8 **card;
+	int i, done;
+
+	if (p == NULL)
+		return (0);	/* Don't know */
+
+	t = id_str;
+	done =0;
+
+	for (i=0; i<=4 && !done; ++i, p+=2) {
+		while ((data = *p) != '\0') {
+			if (data == 0xFF) {
+				done = 1;
+				break;
+			}
+			*t++ = data;
+			if (t == &id_str[MAX_IDENT_CHARS-1]) {
+				done = 1;
+				break;
+			}
+			p += 2;
+		}
+		if (!done)
+			*t++ = ' ';
+	}
+	*t = '\0';
+	while (--t > id_str) {
+		if (*t == ' ')
+			*t = '\0';
+		else
+			break;
+	}
+	printk ("Card ID: %s\n", id_str);
+
+	for (card=known_cards; *card; ++card) {
+		if (strcmp(*card, id_str) == 0) {	/* found! */
+			return (1);
+		}
+	}
+
+	return (0);	/* don't know */
+}
+
+void m8xx_ide_init(void)
+{
+	ppc_ide_md.default_irq          = m8xx_ide_default_irq;
+	ppc_ide_md.default_io_base      = m8xx_ide_default_io_base;
+	ppc_ide_md.ide_init_hwif        = m8xx_ide_init_hwif_ports;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ppc/pmac.c linux-2.4.21-pre6/drivers/ide/ppc/pmac.c
--- linux-2.4.20/drivers/ide/ppc/pmac.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/ppc/pmac.c	2003-03-26 23:49:50.000000000 +0000
@@ -0,0 +1,1786 @@
+/*
+ * linux/drivers/ide/ppc/ide-pmac.c
+ *
+ * Support for IDE interfaces on PowerMacs.
+ * These IDE interfaces are memory-mapped and have a DBDMA channel
+ * for doing DMA.
+ *
+ *  Copyright (C) 1998-2001 Paul Mackerras & Ben. Herrenschmidt
+ *
+ *  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.
+ *
+ * Some code taken from drivers/ide/ide-dma.c:
+ *
+ *  Copyright (c) 1995-1998  Mark Lord
+ *
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/pci.h>
+
+#include <asm/prom.h>
+#include <asm/io.h>
+#include <asm/dbdma.h>
+#include <asm/ide.h>
+#include <asm/mediabay.h>
+#include <asm/pci-bridge.h>
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
+#include <asm/sections.h>
+#include <asm/irq.h>
+#ifdef CONFIG_PMAC_PBOOK
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#endif
+#include "ide_modes.h"
+
+extern void ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq);
+
+#define IDE_PMAC_DEBUG
+
+#define DMA_WAIT_TIMEOUT	500
+
+typedef struct pmac_ide_hwif {
+	ide_ioreg_t			regbase;
+	int				irq;
+	int				kind;
+	int				aapl_bus_id;
+	struct device_node*		node;
+	u32				timings[2];
+	int				index;
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+	/* Those fields are duplicating what is in hwif. We currently
+	 * can't use the hwif ones because of some assumptions that are
+	 * beeing done by the generic code about the kind of dma controller
+	 * and format of the dma table. This will have to be fixed though.
+	 */
+	volatile struct dbdma_regs*	dma_regs;
+	struct dbdma_cmd*		dma_table_cpu;
+	dma_addr_t			dma_table_dma;
+	struct scatterlist*		sg_table;
+	int				sg_nents;
+	int				sg_dma_direction;
+#endif
+	
+} pmac_ide_hwif_t;
+
+static pmac_ide_hwif_t pmac_ide[MAX_HWIFS] __pmacdata;
+static int pmac_ide_count;
+
+enum {
+	controller_ohare,	/* OHare based */
+	controller_heathrow,	/* Heathrow/Paddington */
+	controller_kl_ata3,	/* KeyLargo ATA-3 */
+	controller_kl_ata4,	/* KeyLargo ATA-4 */
+	controller_kl_ata4_80	/* KeyLargo ATA-4 with 80 conductor cable */
+};
+
+/*
+ * Extra registers, both 32-bit little-endian
+ */
+#define IDE_TIMING_CONFIG	0x200
+#define IDE_INTERRUPT		0x300
+
+/*
+ * Timing configuration register definitions
+ */
+
+/* Number of IDE_SYSCLK_NS ticks, argument is in nanoseconds */
+#define SYSCLK_TICKS(t)		(((t) + IDE_SYSCLK_NS - 1) / IDE_SYSCLK_NS)
+#define SYSCLK_TICKS_66(t)	(((t) + IDE_SYSCLK_66_NS - 1) / IDE_SYSCLK_66_NS)
+#define IDE_SYSCLK_NS		30	/* 33Mhz cell */
+#define IDE_SYSCLK_66_NS	15	/* 66Mhz cell */
+
+/* 66Mhz cell, found in KeyLargo. Can do ultra mode 0 to 2 on
+ * 40 connector cable and to 4 on 80 connector one.
+ * Clock unit is 15ns (66Mhz)
+ * 
+ * 3 Values can be programmed:
+ *  - Write data setup, which appears to match the cycle time. They
+ *    also call it DIOW setup.
+ *  - Ready to pause time (from spec)
+ *  - Address setup. That one is weird. I don't see where exactly
+ *    it fits in UDMA cycles, I got it's name from an obscure piece
+ *    of commented out code in Darwin. They leave it to 0, we do as
+ *    well, despite a comment that would lead to think it has a
+ *    min value of 45ns.
+ * Apple also add 60ns to the write data setup (or cycle time ?) on
+ * reads. I can't explain that, I tried it and it broke everything
+ * here.
+ */
+#define TR_66_UDMA_MASK			0xfff00000
+#define TR_66_UDMA_EN			0x00100000 /* Enable Ultra mode for DMA */
+#define TR_66_UDMA_ADDRSETUP_MASK	0xe0000000 /* Address setup */
+#define TR_66_UDMA_ADDRSETUP_SHIFT	29
+#define TR_66_UDMA_RDY2PAUS_MASK	0x1e000000 /* Ready 2 pause time */
+#define TR_66_UDMA_RDY2PAUS_SHIFT	25
+#define TR_66_UDMA_WRDATASETUP_MASK	0x01e00000 /* Write data setup time */
+#define TR_66_UDMA_WRDATASETUP_SHIFT	21
+#define TR_66_MDMA_MASK			0x000ffc00
+#define TR_66_MDMA_RECOVERY_MASK	0x000f8000
+#define TR_66_MDMA_RECOVERY_SHIFT	15
+#define TR_66_MDMA_ACCESS_MASK		0x00007c00
+#define TR_66_MDMA_ACCESS_SHIFT		10
+#define TR_66_PIO_MASK			0x000003ff
+#define TR_66_PIO_RECOVERY_MASK		0x000003e0
+#define TR_66_PIO_RECOVERY_SHIFT	5
+#define TR_66_PIO_ACCESS_MASK		0x0000001f
+#define TR_66_PIO_ACCESS_SHIFT		0
+
+/* 33Mhz cell, found in OHare, Heathrow (& Paddington) and KeyLargo
+ * Can do pio & mdma modes, clock unit is 30ns (33Mhz)
+ * 
+ * The access time and recovery time can be programmed. Some older
+ * Darwin code base limit OHare to 150ns cycle time. I decided to do
+ * the same here fore safety against broken old hardware ;)
+ * The HalfTick bit, when set, adds half a clock (15ns) to the access
+ * time and removes one from recovery. It's not supported on KeyLargo
+ * implementation afaik. The E bit appears to be set for PIO mode 0 and
+ * is used to reach long timings used in this mode.
+ */
+#define TR_33_MDMA_MASK			0x003ff800
+#define TR_33_MDMA_RECOVERY_MASK	0x001f0000
+#define TR_33_MDMA_RECOVERY_SHIFT	16
+#define TR_33_MDMA_ACCESS_MASK		0x0000f800
+#define TR_33_MDMA_ACCESS_SHIFT		11
+#define TR_33_MDMA_HALFTICK		0x00200000
+#define TR_33_PIO_MASK			0x000007ff
+#define TR_33_PIO_E			0x00000400
+#define TR_33_PIO_RECOVERY_MASK		0x000003e0
+#define TR_33_PIO_RECOVERY_SHIFT	5
+#define TR_33_PIO_ACCESS_MASK		0x0000001f
+#define TR_33_PIO_ACCESS_SHIFT		0
+
+/*
+ * Interrupt register definitions
+ */
+#define IDE_INTR_DMA			0x80000000
+#define IDE_INTR_DEVICE			0x40000000
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+
+/* Rounded Multiword DMA timings
+ * 
+ * I gave up finding a generic formula for all controller
+ * types and instead, built tables based on timing values
+ * used by Apple in Darwin's implementation.
+ */
+struct mdma_timings_t {
+	int	accessTime;
+	int	recoveryTime;
+	int	cycleTime;
+};
+
+struct mdma_timings_t mdma_timings_33[] __pmacdata =
+{
+    { 240, 240, 480 },
+    { 180, 180, 360 },
+    { 135, 135, 270 },
+    { 120, 120, 240 },
+    { 105, 105, 210 },
+    {  90,  90, 180 },
+    {  75,  75, 150 },
+    {  75,  45, 120 },
+    {   0,   0,   0 }
+};
+
+struct mdma_timings_t mdma_timings_33k[] __pmacdata =
+{
+    { 240, 240, 480 },
+    { 180, 180, 360 },
+    { 150, 150, 300 },
+    { 120, 120, 240 },
+    {  90, 120, 210 },
+    {  90,  90, 180 },
+    {  90,  60, 150 },
+    {  90,  30, 120 },
+    {   0,   0,   0 }
+};
+
+struct mdma_timings_t mdma_timings_66[] __pmacdata =
+{
+    { 240, 240, 480 },
+    { 180, 180, 360 },
+    { 135, 135, 270 },
+    { 120, 120, 240 },
+    { 105, 105, 210 },
+    {  90,  90, 180 },
+    {  90,  75, 165 },
+    {  75,  45, 120 },
+    {   0,   0,   0 }
+};
+
+/* Ultra DMA timings (rounded) */
+struct {
+	int	addrSetup; /* ??? */
+	int	rdy2pause;
+	int	wrDataSetup;
+} udma_timings[] __pmacdata =
+{
+    {   0, 180,  120 },	/* Mode 0 */
+    {   0, 150,  90 },	/*      1 */
+    {   0, 120,  60 },	/*      2 */
+    {   0, 90,   45 },	/*      3 */
+    {   0, 90,   30 }	/*      4 */
+};
+
+/* allow up to 256 DBDMA commands per xfer */
+#define MAX_DCMDS		256
+
+/* Wait 2s for disk to answer on IDE bus after
+ * enable operation.
+ * NOTE: There is at least one case I know of a disk that needs about 10sec
+ *       before anwering on the bus. I beleive we could add a kernel command
+ *       line arg to override this delay for such cases.
+ */
+#define IDE_WAKEUP_DELAY_MS	2000
+
+static void pmac_ide_setup_dma(struct device_node *np, int ix);
+static int pmac_ide_build_dmatable(ide_drive_t *drive, int wr);
+static int pmac_ide_tune_chipset(ide_drive_t *drive, u8 speed);
+static void pmac_ide_tuneproc(ide_drive_t *drive, u8 pio);
+static void pmac_ide_selectproc(ide_drive_t *drive);
+static int pmac_ide_dma_begin (ide_drive_t *drive);
+
+#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
+
+#ifdef CONFIG_PMAC_PBOOK
+static int idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when);
+struct pmu_sleep_notifier idepmac_sleep_notifier = {
+	idepmac_notify_sleep, SLEEP_LEVEL_BLOCK,
+};
+#endif /* CONFIG_PMAC_PBOOK */
+
+/*
+ * N.B. this can't be an initfunc, because the media-bay task can
+ * call ide_[un]register at any time.
+ */
+void __pmac
+pmac_ide_init_hwif_ports(hw_regs_t *hw,
+			      ide_ioreg_t data_port, ide_ioreg_t ctrl_port,
+			      int *irq)
+{
+	int i, ix;
+
+	if (data_port == 0)
+		return;
+
+	for (ix = 0; ix < MAX_HWIFS; ++ix)
+		if (data_port == pmac_ide[ix].regbase)
+			break;
+
+	if (ix >= MAX_HWIFS) {
+		/* Probably a PCI interface... */
+		for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; ++i)
+			hw->io_ports[i] = data_port + i - IDE_DATA_OFFSET;
+		hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
+		return;
+	}
+
+	for (i = 0; i < 8; ++i)
+		hw->io_ports[i] = data_port + i * 0x10;
+	hw->io_ports[8] = data_port + 0x160;
+
+	if (irq != NULL)
+		*irq = pmac_ide[ix].irq;
+}
+
+/* Setup timings for the selected drive (master/slave). I still need to verify if this
+ * is enough, I beleive selectproc will be called whenever an IDE command is started,
+ * but... */
+static void __pmac
+pmac_ide_selectproc(ide_drive_t *drive)
+{
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+
+	if (pmif == NULL)
+		return;
+
+	if (drive->select.b.unit & 0x01)
+		writel(pmif->timings[1],
+			(unsigned *)(IDE_DATA_REG+IDE_TIMING_CONFIG));
+	else
+		writel(pmif->timings[0],
+			(unsigned *)(IDE_DATA_REG+IDE_TIMING_CONFIG));
+	(void)readl((unsigned *)(IDE_DATA_REG+IDE_TIMING_CONFIG));
+}
+
+
+static int __pmac
+pmac_ide_do_setfeature(ide_drive_t *drive, u8 command)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	int result = 1;
+	
+	disable_irq(hwif->irq);	/* disable_irq_nosync ?? */
+	udelay(1);
+	SELECT_DRIVE(drive);
+	SELECT_MASK(drive, 0);
+	udelay(1);
+	/* Get rid of pending error state */
+	(void) hwif->INB(IDE_STATUS_REG);
+	/* Timeout bumped for some powerbooks */
+	if (wait_for_ready(drive, 2000)) {
+		/* Timeout bumped for some powerbooks */
+		printk(KERN_ERR "pmac_ide_do_setfeature disk not ready "
+			"before SET_FEATURE!\n");
+		goto out;
+	}
+	udelay(10);
+	hwif->OUTB(drive->ctl | 2, IDE_CONTROL_REG);
+	hwif->OUTB(command, IDE_NSECTOR_REG);
+	hwif->OUTB(SETFEATURES_XFER, IDE_FEATURE_REG);
+	hwif->OUTB(WIN_SETFEATURES, IDE_COMMAND_REG);
+	udelay(1);
+	/* Timeout bumped for some powerbooks */
+	result = wait_for_ready(drive, 2000);
+	hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
+	if (result)
+		printk(KERN_ERR "pmac_ide_do_setfeature disk not ready "
+			"after SET_FEATURE !\n");
+out:
+	SELECT_MASK(drive, 0);
+	if (result == 0) {
+		drive->id->dma_ultra &= ~0xFF00;
+		drive->id->dma_mword &= ~0x0F00;
+		drive->id->dma_1word &= ~0x0F00;
+		switch(command) {
+			case XFER_UDMA_7:
+				drive->id->dma_ultra |= 0x8080; break;
+			case XFER_UDMA_6:
+				drive->id->dma_ultra |= 0x4040; break;
+			case XFER_UDMA_5:
+				drive->id->dma_ultra |= 0x2020; break;
+			case XFER_UDMA_4:
+				drive->id->dma_ultra |= 0x1010; break;
+			case XFER_UDMA_3:
+				drive->id->dma_ultra |= 0x0808; break;
+			case XFER_UDMA_2:
+				drive->id->dma_ultra |= 0x0404; break;
+			case XFER_UDMA_1:
+				drive->id->dma_ultra |= 0x0202; break;
+			case XFER_UDMA_0:
+				drive->id->dma_ultra |= 0x0101; break;
+			case XFER_MW_DMA_2:
+				drive->id->dma_mword |= 0x0404; break;
+			case XFER_MW_DMA_1:
+				drive->id->dma_mword |= 0x0202; break;
+			case XFER_MW_DMA_0:
+				drive->id->dma_mword |= 0x0101; break;
+			case XFER_SW_DMA_2:
+				drive->id->dma_1word |= 0x0404; break;
+			case XFER_SW_DMA_1:
+				drive->id->dma_1word |= 0x0202; break;
+			case XFER_SW_DMA_0:
+				drive->id->dma_1word |= 0x0101; break;
+			default: break;
+		}
+	}
+	enable_irq(hwif->irq);
+	return result;
+}
+
+/* Calculate PIO timings */
+static void __pmac
+pmac_ide_tuneproc(ide_drive_t *drive, u8 pio)
+{
+	ide_pio_data_t d;
+	u32 *timings;
+	unsigned accessTicks, recTicks;
+	unsigned accessTime, recTime;
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+	
+	if (pmif == NULL)
+		return;
+		
+	pio = ide_get_best_pio_mode(drive, pio, 4, &d);
+	accessTicks = SYSCLK_TICKS(ide_pio_timings[pio].active_time);
+	if (drive->select.b.unit & 0x01)
+		timings = &pmif->timings[1];
+	else
+		timings = &pmif->timings[0];
+
+	recTime = d.cycle_time - ide_pio_timings[pio].active_time
+			- ide_pio_timings[pio].setup_time;
+	recTime = max(recTime, 150U);
+	accessTime = ide_pio_timings[pio].active_time;
+	accessTime = max(accessTime, 150U);
+	if (pmif->kind == controller_kl_ata4 ||
+		pmif->kind == controller_kl_ata4_80) {
+		/* 66Mhz cell */
+		accessTicks = SYSCLK_TICKS_66(accessTime);
+		accessTicks = min(accessTicks, 0x1fU);
+		recTicks = SYSCLK_TICKS_66(recTime);
+		recTicks = min(recTicks, 0x1fU);
+		*timings = ((*timings) & ~TR_66_PIO_MASK) |
+				(accessTicks << TR_66_PIO_ACCESS_SHIFT) |
+				(recTicks << TR_66_PIO_RECOVERY_SHIFT);
+	} else {
+		/* 33Mhz cell */
+		int ebit = 0;
+		accessTicks = SYSCLK_TICKS(accessTime);
+		accessTicks = min(accessTicks, 0x1fU);
+		accessTicks = max(accessTicks, 4U);
+		recTicks = SYSCLK_TICKS(recTime);
+		recTicks = min(recTicks, 0x1fU);
+		recTicks = max(recTicks, 5U) - 4;
+		if (recTicks > 9) {
+			recTicks--; /* guess, but it's only for PIO0, so... */
+			ebit = 1;
+		}
+		*timings = ((*timings) & ~TR_33_PIO_MASK) |
+				(accessTicks << TR_33_PIO_ACCESS_SHIFT) |
+				(recTicks << TR_33_PIO_RECOVERY_SHIFT);
+		if (ebit)
+			*timings |= TR_33_PIO_E;
+	}
+
+#ifdef IDE_PMAC_DEBUG
+	printk(KERN_ERR "ide_pmac: Set PIO timing for mode %d, reg: 0x%08x\n",
+		pio,  *timings);
+#endif	
+
+	if (drive->select.all == HWIF(drive)->INB(IDE_SELECT_REG))
+		pmac_ide_selectproc(drive);
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+static int __pmac
+set_timings_udma(u32 *timings, u8 speed)
+{
+	unsigned rdyToPauseTicks, wrDataSetupTicks, addrTicks;
+
+	rdyToPauseTicks = SYSCLK_TICKS_66(udma_timings[speed & 0xf].rdy2pause);
+	wrDataSetupTicks = SYSCLK_TICKS_66(udma_timings[speed & 0xf].wrDataSetup);
+	addrTicks = SYSCLK_TICKS_66(udma_timings[speed & 0xf].addrSetup);
+
+	*timings = ((*timings) & ~(TR_66_UDMA_MASK | TR_66_MDMA_MASK)) |
+			(wrDataSetupTicks << TR_66_UDMA_WRDATASETUP_SHIFT) | 
+			(rdyToPauseTicks << TR_66_UDMA_RDY2PAUS_SHIFT) |
+			(addrTicks <<TR_66_UDMA_ADDRSETUP_SHIFT) |
+			TR_66_UDMA_EN;
+#ifdef IDE_PMAC_DEBUG
+	printk(KERN_ERR "ide_pmac: Set UDMA timing for mode %d, reg: 0x%08x\n",
+		speed & 0xf,  *timings);
+#endif	
+
+	return 0;
+}
+
+static int __pmac
+set_timings_mdma(int intf_type, u32 *timings, u8 speed, int drive_cycle_time)
+{
+	int cycleTime, accessTime, recTime;
+	unsigned accessTicks, recTicks;
+	struct mdma_timings_t* tm;
+	int i;
+
+	/* Get default cycle time for mode */
+	switch(speed & 0xf) {
+		case 0: cycleTime = 480; break;
+		case 1: cycleTime = 150; break;
+		case 2: cycleTime = 120; break;
+		default:
+			return -1;
+	}
+	/* Adjust for drive */
+	if (drive_cycle_time && drive_cycle_time > cycleTime)
+		cycleTime = drive_cycle_time;
+	/* OHare limits according to some old Apple sources */	
+	if ((intf_type == controller_ohare) && (cycleTime < 150))
+		cycleTime = 150;
+	/* Get the proper timing array for this controller */
+	switch(intf_type) {
+		case controller_kl_ata4:
+		case controller_kl_ata4_80:
+			tm = mdma_timings_66;
+			break;
+		case controller_kl_ata3:
+			tm = mdma_timings_33k;
+			break;
+		default:
+			tm = mdma_timings_33;
+			break;
+	}
+	/* Lookup matching access & recovery times */
+	i = -1;
+	for (;;) {
+		if (tm[i+1].cycleTime < cycleTime)
+			break;
+		i++;
+	}
+	if (i < 0)
+		return -1;
+	cycleTime = tm[i].cycleTime;
+	accessTime = tm[i].accessTime;
+	recTime = tm[i].recoveryTime;
+
+#ifdef IDE_PMAC_DEBUG
+	printk(KERN_ERR "ide_pmac: MDMA, cycleTime: %d, accessTime: %d, recTime: %d\n",
+		cycleTime, accessTime, recTime);
+#endif	
+	if (intf_type == controller_kl_ata4 || intf_type == controller_kl_ata4_80) {
+		/* 66Mhz cell */
+		accessTicks = SYSCLK_TICKS_66(accessTime);
+		accessTicks = min(accessTicks, 0x1fU);
+		accessTicks = max(accessTicks, 0x1U);
+		recTicks = SYSCLK_TICKS_66(recTime);
+		recTicks = min(recTicks, 0x1fU);
+		recTicks = max(recTicks, 0x3U);
+		/* Clear out mdma bits and disable udma */
+		*timings = ((*timings) & ~(TR_66_MDMA_MASK | TR_66_UDMA_MASK)) |
+			(accessTicks << TR_66_MDMA_ACCESS_SHIFT) |
+			(recTicks << TR_66_MDMA_RECOVERY_SHIFT);
+	} else if (intf_type == controller_kl_ata3) {
+		/* 33Mhz cell on KeyLargo */
+		accessTicks = SYSCLK_TICKS(accessTime);
+		accessTicks = max(accessTicks, 1U);
+		accessTicks = min(accessTicks, 0x1fU);
+		accessTime = accessTicks * IDE_SYSCLK_NS;
+		recTicks = SYSCLK_TICKS(recTime);
+		recTicks = max(recTicks, 1U);
+		recTicks = min(recTicks, 0x1fU);
+		*timings = ((*timings) & ~TR_33_MDMA_MASK) |
+				(accessTicks << TR_33_MDMA_ACCESS_SHIFT) |
+				(recTicks << TR_33_MDMA_RECOVERY_SHIFT);
+	} else {
+		/* 33Mhz cell on others */
+		int halfTick = 0;
+		int origAccessTime = accessTime;
+		int origRecTime = recTime;
+		
+		accessTicks = SYSCLK_TICKS(accessTime);
+		accessTicks = max(accessTicks, 1U);
+		accessTicks = min(accessTicks, 0x1fU);
+		accessTime = accessTicks * IDE_SYSCLK_NS;
+		recTicks = SYSCLK_TICKS(recTime);
+		recTicks = max(recTicks, 2U) - 1;
+		recTicks = min(recTicks, 0x1fU);
+		recTime = (recTicks + 1) * IDE_SYSCLK_NS;
+		if ((accessTicks > 1) &&
+		    ((accessTime - IDE_SYSCLK_NS/2) >= origAccessTime) &&
+		    ((recTime - IDE_SYSCLK_NS/2) >= origRecTime)) {
+            		halfTick = 1;
+			accessTicks--;
+		}
+		*timings = ((*timings) & ~TR_33_MDMA_MASK) |
+				(accessTicks << TR_33_MDMA_ACCESS_SHIFT) |
+				(recTicks << TR_33_MDMA_RECOVERY_SHIFT);
+		if (halfTick)
+			*timings |= TR_33_MDMA_HALFTICK;
+	}
+#ifdef IDE_PMAC_DEBUG
+	printk(KERN_ERR "ide_pmac: Set MDMA timing for mode %d, reg: 0x%08x\n",
+		speed & 0xf,  *timings);
+#endif	
+	return 0;
+}
+#endif /* #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC */
+
+/* You may notice we don't use this function on normal operation,
+ * our, normal mdma function is supposed to be more precise
+ */
+static int __pmac
+pmac_ide_tune_chipset (ide_drive_t *drive, u8 speed)
+{
+	int unit = (drive->select.b.unit & 0x01);
+	int ret = 0;
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+	u32 *timings;
+	
+	if (pmif == NULL)
+		return 1;
+
+	timings = &pmif->timings[unit];
+	
+	switch(speed) {
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+		case XFER_UDMA_4:
+		case XFER_UDMA_3:
+			if (pmif->kind != controller_kl_ata4_80)
+				return 1;		
+		case XFER_UDMA_2:
+		case XFER_UDMA_1:
+		case XFER_UDMA_0:
+			if (pmif->kind != controller_kl_ata4 &&
+				pmif->kind != controller_kl_ata4_80)
+				return 1;		
+			ret = set_timings_udma(timings, speed);
+			break;
+		case XFER_MW_DMA_2:
+		case XFER_MW_DMA_1:
+		case XFER_MW_DMA_0:
+			ret = set_timings_mdma(pmif->kind, timings, speed, 0);
+			break;
+		case XFER_SW_DMA_2:
+		case XFER_SW_DMA_1:
+		case XFER_SW_DMA_0:
+			return 1;
+#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
+		case XFER_PIO_4:
+		case XFER_PIO_3:
+		case XFER_PIO_2:
+		case XFER_PIO_1:
+		case XFER_PIO_0:
+			pmac_ide_tuneproc(drive, speed & 0x07);
+			break;
+		default:
+			ret = 1;
+	}
+	if (ret)
+		return ret;
+
+	ret = pmac_ide_do_setfeature(drive, speed);
+	if (ret)
+		return ret;
+		
+	pmac_ide_selectproc(drive);	
+	drive->current_speed = speed;
+
+	return 0;
+}
+
+static void __pmac
+sanitize_timings(pmac_ide_hwif_t *pmif)
+{
+	unsigned value;
+	
+	switch(pmif->kind) {
+		case controller_kl_ata4:
+		case controller_kl_ata4_80:
+			value = 0x0008438c;
+			break;
+		case controller_kl_ata3:
+			value = 0x00084526;
+			break;
+		case controller_heathrow:
+		case controller_ohare:
+		default:
+			value = 0x00074526;
+			break;
+	}
+	pmif->timings[0] = pmif->timings[1] = value;
+}
+
+ide_ioreg_t __pmac
+pmac_ide_get_base(int index)
+{
+	return pmac_ide[index].regbase;
+}
+
+int __pmac
+pmac_ide_check_base(ide_ioreg_t base)
+{
+	int ix;
+	
+ 	for (ix = 0; ix < MAX_HWIFS; ++ix)
+		if (base == pmac_ide[ix].regbase)
+			return ix;
+	return -1;
+}
+
+int __pmac
+pmac_ide_get_irq(ide_ioreg_t base)
+{
+	int ix;
+
+	for (ix = 0; ix < MAX_HWIFS; ++ix)
+		if (base == pmac_ide[ix].regbase)
+			return pmac_ide[ix].irq;
+	return 0;
+}
+
+static int ide_majors[]  __pmacdata = { 3, 22, 33, 34, 56, 57 };
+
+kdev_t __init
+pmac_find_ide_boot(char *bootdevice, int n)
+{
+	int i;
+	
+	/*
+	 * Look through the list of IDE interfaces for this one.
+	 */
+	for (i = 0; i < pmac_ide_count; ++i) {
+		char *name;
+		if (!pmac_ide[i].node || !pmac_ide[i].node->full_name)
+			continue;
+		name = pmac_ide[i].node->full_name;
+		if (memcmp(name, bootdevice, n) == 0 && name[n] == 0) {
+			/* XXX should cope with the 2nd drive as well... */
+			return MKDEV(ide_majors[i], 0);
+		}
+	}
+
+	return 0;
+}
+
+void __init
+pmac_ide_probe(void)
+{
+	struct device_node *np;
+	int i;
+	struct device_node *atas;
+	struct device_node *p, **pp, *removables, **rp;
+	unsigned long base;
+	int irq, big_delay;
+	ide_hwif_t *hwif;
+
+	if (_machine != _MACH_Pmac)
+		return;
+	pp = &atas;
+	rp = &removables;
+	p = find_devices("ATA");
+	if (p == NULL)
+		p = find_devices("IDE");
+	if (p == NULL)
+		p = find_type_devices("ide");
+	if (p == NULL)
+		p = find_type_devices("ata");
+	/* Move removable devices such as the media-bay CDROM
+	   on the PB3400 to the end of the list. */
+	for (; p != NULL; p = p->next) {
+		if (p->parent && p->parent->type
+		    && strcasecmp(p->parent->type, "media-bay") == 0) {
+			*rp = p;
+			rp = &p->next;
+		} else {
+			*pp = p;
+			pp = &p->next;
+		}
+	}
+	*rp = NULL;
+	*pp = removables;
+	big_delay = 0;
+
+	for (i = 0, np = atas; i < MAX_HWIFS && np != NULL; np = np->next) {
+		struct device_node *tp;
+		struct pmac_ide_hwif* pmif;
+		int *bidp;
+		int in_bay = 0;
+		u8 pbus, pid;
+		struct pci_dev *pdev = NULL;
+
+		/*
+		 * If this node is not under a mac-io or dbdma node,
+		 * leave it to the generic PCI driver.
+		 */
+		for (tp = np->parent; tp != 0; tp = tp->parent)
+			if (tp->type && (strcmp(tp->type, "mac-io") == 0
+					 || strcmp(tp->type, "dbdma") == 0))
+				break;
+		if (tp == 0)
+			continue;
+
+		if (np->n_addrs == 0) {
+			printk(KERN_WARNING "ide: no address for device %s\n",
+			       np->full_name);
+			continue;
+		}
+
+		/* We need to find the pci_dev of the mac-io holding the
+		 * IDE interface
+		 */
+		if (pci_device_from_OF_node(tp, &pbus, &pid) == 0)
+			pdev = pci_find_slot(pbus, pid);
+		if (pdev == NULL)
+			printk(KERN_WARNING "ide: no PCI host for device %s, DMA disabled\n",
+			       np->full_name);
+
+		/*
+		 * If this slot is taken (e.g. by ide-pci.c) try the next one.
+		 */
+		while (i < MAX_HWIFS
+		       && ide_hwifs[i].io_ports[IDE_DATA_OFFSET] != 0)
+			++i;
+		if (i >= MAX_HWIFS)
+			break;
+		pmif = &pmac_ide[i];
+
+		/*
+		 * Some older OFs have bogus sizes, causing request_OF_resource
+		 * to fail. We fix them up here
+		 */
+		if (np->addrs[0].size > 0x1000)
+			np->addrs[0].size = 0x1000;
+		if (np->n_addrs > 1 && np->addrs[1].size > 0x100)
+			np->addrs[1].size = 0x100;
+
+		if (request_OF_resource(np, 0, "  (mac-io IDE IO)") == NULL) {
+			printk(KERN_ERR "ide-pmac(%s): can't request IO resource !\n", np->name);
+			continue;
+		}
+
+		base = (unsigned long) ioremap(np->addrs[0].address, 0x400);
+
+		/* XXX This is bogus. Should be fixed in the registry by checking
+		   the kind of host interrupt controller, a bit like gatwick
+		   fixes in irq.c
+		 */
+		if (np->n_intrs == 0) {
+			printk(KERN_WARNING "ide: no intrs for device %s, using 13\n",
+			       np->full_name);
+			irq = 13;
+		} else {
+			irq = np->intrs[0].line;
+		}
+		pmif->regbase = base;
+		pmif->irq = irq;
+		pmif->node = np;
+		pmif->index = i;
+		if (device_is_compatible(np, "keylargo-ata")) {
+			if (strcmp(np->name, "ata-4") == 0)
+				pmif->kind = controller_kl_ata4;
+			else
+				pmif->kind = controller_kl_ata3;
+		} else if (device_is_compatible(np, "heathrow-ata"))
+			pmif->kind = controller_heathrow;
+		else
+			pmif->kind = controller_ohare;
+
+		bidp = (int *)get_property(np, "AAPL,bus-id", NULL);
+		pmif->aapl_bus_id =  bidp ? *bidp : 0;
+
+		if (pmif->kind == controller_kl_ata4) {
+			char* cable = get_property(np, "cable-type", NULL);
+			if (cable && !strncmp(cable, "80-", 3))
+				pmif->kind = controller_kl_ata4_80;
+		}
+
+		/* Make sure we have sane timings */
+		sanitize_timings(pmif);
+
+		if (np->parent && np->parent->name
+		    && strcasecmp(np->parent->name, "media-bay") == 0) {
+#ifdef CONFIG_PMAC_PBOOK
+			media_bay_set_ide_infos(np->parent,base,irq,i);
+#endif /* CONFIG_PMAC_PBOOK */
+			in_bay = 1;
+			if (!bidp)
+				pmif->aapl_bus_id = 1;
+		} else if (pmif->kind == controller_ohare) {
+			/* The code below is having trouble on some ohare machines
+			 * (timing related ?). Until I can put my hand on one of these
+			 * units, I keep the old way
+			 */
+			ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, 0, 1);
+		} else {
+ 			/* This is necessary to enable IDE when net-booting */
+			printk(KERN_INFO "pmac_ide: enabling IDE bus ID %d\n",
+				pmif->aapl_bus_id);
+			ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 1);
+			ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmif->aapl_bus_id, 1);
+			mdelay(10);
+			ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 0);
+			big_delay = 1;
+		}
+
+		hwif = &ide_hwifs[i];
+		/* Setup MMIO ops */
+		default_hwif_mmiops(hwif);
+		/* Tell common code _not_ to mess with resources */
+		hwif->mmio = 2;
+		hwif->hwif_data = pmif;
+		pmac_ide_init_hwif_ports(&hwif->hw, base, 0, &hwif->irq);
+		memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
+		hwif->chipset = ide_pmac;
+		hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET] || in_bay;
+		hwif->udma_four = (pmif->kind == controller_kl_ata4_80);
+		hwif->pci_dev = pdev;
+		hwif->drives[0].unmask = 1;
+		hwif->drives[1].unmask = 1;
+		hwif->tuneproc = pmac_ide_tuneproc;
+		hwif->selectproc = pmac_ide_selectproc;
+		hwif->speedproc = pmac_ide_tune_chipset;
+#ifdef CONFIG_PMAC_PBOOK
+		if (in_bay && check_media_bay_by_base(base, MB_CD) == 0)
+			hwif->noprobe = 0;
+#endif /* CONFIG_PMAC_PBOOK */
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+		if (np->n_addrs >= 2) {
+			/* has a DBDMA controller channel */
+			pmac_ide_setup_dma(np, i);
+		}
+		hwif->atapi_dma = 1;
+		hwif->ultra_mask = 0x1f;
+		hwif->mwdma_mask = 0x07;
+		hwif->swdma_mask = 0x07;
+
+#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
+
+		++i;
+	}
+	pmac_ide_count = i;
+	if (big_delay)
+		mdelay(IDE_WAKEUP_DELAY_MS);
+
+#ifdef CONFIG_PMAC_PBOOK
+	pmu_register_sleep_notifier(&idepmac_sleep_notifier);
+#endif /* CONFIG_PMAC_PBOOK */
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+
+static int
+pmac_ide_build_sglist(ide_hwif_t *hwif, struct request *rq, int data_dir)
+{
+	pmac_ide_hwif_t *pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
+	struct buffer_head *bh;
+	struct scatterlist *sg = pmif->sg_table;
+	int nents = 0;
+
+	if (hwif->sg_dma_active)
+		BUG();
+		
+	bh = rq->bh;
+	do {
+		unsigned char *virt_addr = bh->b_data;
+		unsigned int size = bh->b_size;
+
+		if (nents >= MAX_DCMDS)
+			return 0;
+
+		while ((bh = bh->b_reqnext) != NULL) {
+			if ((virt_addr + size) != (unsigned char *) bh->b_data)
+				break;
+			size += bh->b_size;
+		}
+		memset(&sg[nents], 0, sizeof(*sg));
+		sg[nents].address = virt_addr;
+		sg[nents].length = size;
+		nents++;
+	} while (bh != NULL);
+
+	pmif->sg_dma_direction = data_dir;
+	return pci_map_sg(hwif->pci_dev, sg, nents, data_dir);
+}
+
+static int
+pmac_ide_raw_build_sglist(ide_hwif_t *hwif, struct request *rq)
+{
+	pmac_ide_hwif_t *pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
+	struct scatterlist *sg = hwif->sg_table;
+	int nents = 0;
+	ide_task_t *args = rq->special;
+	unsigned char *virt_addr = rq->buffer;
+	int sector_count = rq->nr_sectors;
+
+	if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
+		pmif->sg_dma_direction = PCI_DMA_TODEVICE;
+	else
+		pmif->sg_dma_direction = PCI_DMA_FROMDEVICE;
+	
+	if (sector_count > 128) {
+		memset(&sg[nents], 0, sizeof(*sg));
+		sg[nents].address = virt_addr;
+		sg[nents].length = 128  * SECTOR_SIZE;
+		nents++;
+		virt_addr = virt_addr + (128 * SECTOR_SIZE);
+		sector_count -= 128;
+	}
+	memset(&sg[nents], 0, sizeof(*sg));
+	sg[nents].address = virt_addr;
+	sg[nents].length =  sector_count  * SECTOR_SIZE;
+	nents++;
+   
+	return pci_map_sg(hwif->pci_dev, sg, nents, pmif->sg_dma_direction);
+}
+
+/*
+ * pmac_ide_build_dmatable builds the DBDMA command list
+ * for a transfer and sets the DBDMA channel to point to it.
+ */
+static int
+pmac_ide_build_dmatable(ide_drive_t *drive, int wr)
+{
+	struct dbdma_cmd *table;
+	int i, count = 0;
+	struct request *rq = HWGROUP(drive)->rq;
+	ide_hwif_t *hwif = HWIF(drive);
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
+	volatile struct dbdma_regs *dma = pmif->dma_regs;
+	struct scatterlist *sg;
+	int data_dir;
+
+	/* DMA table is already aligned */
+	table = (struct dbdma_cmd *) pmif->dma_table_cpu;
+
+	/* Make sure DMA controller is stopped (necessary ?) */
+	writel((RUN|PAUSE|FLUSH|WAKE|DEAD) << 16, &dma->control);
+	while (readl(&dma->status) & RUN)
+		udelay(1);
+
+	if (wr)
+		data_dir = PCI_DMA_TODEVICE;
+	else
+		data_dir = PCI_DMA_FROMDEVICE;
+
+	/* Build sglist */
+	if (rq->cmd == IDE_DRIVE_TASKFILE)
+		pmif->sg_nents = i = pmac_ide_raw_build_sglist(hwif, rq);
+	else
+		pmif->sg_nents = i = pmac_ide_build_sglist(hwif, rq, data_dir);
+	if (!i)
+		return 0;
+
+	/* Build DBDMA commands list */
+	sg = pmif->sg_table;
+	while (i && sg_dma_len(sg)) {
+		u32 cur_addr;
+		u32 cur_len;
+
+		cur_addr = sg_dma_address(sg);
+		cur_len = sg_dma_len(sg);
+
+		while (cur_len) {
+			unsigned int tc = (cur_len < 0xfe00)? cur_len: 0xfe00;
+
+			if (++count >= MAX_DCMDS) {
+				printk(KERN_WARNING "%s: DMA table too small\n",
+				       drive->name);
+				return 0; /* revert to PIO for this request */
+			}
+			st_le16(&table->command, wr? OUTPUT_MORE: INPUT_MORE);
+			st_le16(&table->req_count, tc);
+			st_le32(&table->phy_addr, cur_addr);
+			table->cmd_dep = 0;
+			table->xfer_status = 0;
+			table->res_count = 0;
+			cur_addr += tc;
+			cur_len -= tc;
+			++table;
+		}
+		sg++;
+		i--;
+	}
+
+	/* convert the last command to an input/output last command */
+	if (count)
+		st_le16(&table[-1].command, wr? OUTPUT_LAST: INPUT_LAST);
+	else
+		printk(KERN_DEBUG "%s: empty DMA table?\n", drive->name);
+
+	/* add the stop command to the end of the list */
+	memset(table, 0, sizeof(struct dbdma_cmd));
+	st_le16(&table->command, DBDMA_STOP);
+	mb();
+	writel(pmif->dma_table_dma, &dma->cmdptr);
+	return 1;
+}
+
+/* Teardown mappings after DMA has completed.  */
+static void
+pmac_ide_destroy_dmatable (ide_drive_t *drive)
+{
+	struct pci_dev *dev = HWIF(drive)->pci_dev;
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+	struct scatterlist *sg = pmif->sg_table;
+	int nents = pmif->sg_nents;
+
+	if (nents) {
+		pci_unmap_sg(dev, sg, nents, pmif->sg_dma_direction);
+		pmif->sg_nents = 0;
+	}
+}
+
+static __inline__ unsigned char
+dma_bits_to_command(unsigned char bits)
+{
+	if(bits & 0x04)
+		return XFER_MW_DMA_2;
+	if(bits & 0x02)
+		return XFER_MW_DMA_1;
+	if(bits & 0x01)
+		return XFER_MW_DMA_0;
+	return 0;
+}
+
+static __inline__ unsigned char
+udma_bits_to_command(unsigned char bits, int high_speed)
+{
+	if (high_speed) {
+		if(bits & 0x10)
+			return XFER_UDMA_4;
+		if(bits & 0x08)
+			return XFER_UDMA_3;
+	}
+	if(bits & 0x04)
+		return XFER_UDMA_2;
+	if(bits & 0x02)
+		return XFER_UDMA_1;
+	if(bits & 0x01)
+		return XFER_UDMA_0;
+	return 0;
+}
+
+/* Calculate MultiWord DMA timings */
+static int __pmac
+pmac_ide_mdma_enable(ide_drive_t *drive)
+{
+	u8 bits = drive->id->dma_mword & 0x07;
+	u8 feature = dma_bits_to_command(bits);
+	u32 *timings;
+	int drive_cycle_time;
+	struct hd_driveid *id = drive->id;
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+	int ret;
+
+	/* Set feature on drive */
+    	printk(KERN_INFO "%s: Enabling MultiWord DMA %d\n", drive->name, feature & 0xf);
+	ret = pmac_ide_do_setfeature(drive, feature);
+	if (ret) {
+	    	printk(KERN_WARNING "%s: Failed !\n", drive->name);
+	    	return 0;
+	}
+
+	if (!drive->init_speed)
+		drive->init_speed = feature;
+	
+	/* which drive is it ? */
+	if (drive->select.b.unit & 0x01)
+		timings = &pmif->timings[1];
+	else
+		timings = &pmif->timings[0];
+
+	/* Check if drive provide explicit cycle time */
+	if ((id->field_valid & 2) && (id->eide_dma_time))
+		drive_cycle_time = id->eide_dma_time;
+	else
+		drive_cycle_time = 0;
+
+	/* Calculate controller timings */
+	set_timings_mdma(pmif->kind, timings, feature, drive_cycle_time);
+
+	drive->current_speed = feature;	
+	return 1;
+}
+
+/* Calculate Ultra DMA timings */
+static int __pmac
+pmac_ide_udma_enable(ide_drive_t *drive, int high_speed)
+{
+	u8 bits = drive->id->dma_ultra & 0x1f;
+	u8 feature = udma_bits_to_command(bits, high_speed);
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+	u32 *timings;
+	int ret;
+
+	/* Set feature on drive */
+    	printk(KERN_INFO "%s: Enabling Ultra DMA %d\n", drive->name, feature & 0xf);
+	ret = pmac_ide_do_setfeature(drive, feature);
+	if (ret) {
+		printk(KERN_WARNING "%s: Failed !\n", drive->name);
+		return 0;
+	}
+
+	if (!drive->init_speed)
+		drive->init_speed = feature;
+
+	/* which drive is it ? */
+	if (drive->select.b.unit & 0x01)
+		timings = &pmif->timings[1];
+	else
+		timings = &pmif->timings[0];
+
+	set_timings_udma(timings, feature);
+
+	drive->current_speed = feature;	
+	return 1;
+}
+
+int pmac_ide_dma_check(ide_drive_t *drive)
+{
+	int ata4, udma;
+	struct hd_driveid *id = drive->id;
+	ide_hwif_t *hwif = HWIF(drive);
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
+	int enable = 1;
+
+	drive->using_dma = 0;
+	
+	if (pmif == NULL)
+		return 0;
+		
+	if (drive->media == ide_floppy)
+		enable = 0;
+	if (((id->capability & 1) == 0) &&
+	    !HWIF(drive)->ide_dma_good_drive(drive))
+		enable = 0;
+	if (HWIF(drive)->ide_dma_bad_drive(drive))
+		enable = 0;
+	udma = 0;
+	ata4 = (pmif->kind == controller_kl_ata4 ||
+		pmif->kind == controller_kl_ata4_80);
+			
+	if(enable) {
+		if (ata4 && (drive->media == ide_disk) &&
+		    (id->field_valid & 0x0004) && (id->dma_ultra & 0x1f)) {
+			/* UltraDMA modes. */
+			drive->using_dma = pmac_ide_udma_enable(drive,
+				pmif->kind == controller_kl_ata4_80);
+		}
+		if (!drive->using_dma && (id->dma_mword & 0x0007)) {
+			/* Normal MultiWord DMA modes. */
+			drive->using_dma = pmac_ide_mdma_enable(drive);
+		}
+		hwif->OUTB(0, IDE_CONTROL_REG);
+		/* Apply settings to controller */
+		pmac_ide_selectproc(drive);
+	}
+	return 0;
+}
+
+static int
+pmac_ide_dma_read (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
+	struct request *rq = HWGROUP(drive)->rq;
+//	ide_task_t *args = rq->special;
+	u8 unit = (drive->select.b.unit & 0x01);
+	u8 ata4;
+	u8 lba48 = (drive->addressing == 1) ? 1 : 0;
+	task_ioreg_t command = WIN_NOP;
+
+	if (pmif == NULL)
+		return 1;
+
+	ata4 = (pmif->kind == controller_kl_ata4 ||
+		pmif->kind == controller_kl_ata4_80);
+
+	if (!pmac_ide_build_dmatable(drive, 0))
+		return 1;
+	/* Apple adds 60ns to wrDataSetup on reads */
+	if (ata4 && (pmif->timings[unit] & TR_66_UDMA_EN)) {
+		writel(pmif->timings[unit]+0x00800000UL,
+			(unsigned *)(IDE_DATA_REG+IDE_TIMING_CONFIG));
+		(void)readl((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG));
+	}
+	drive->waiting_for_dma = 1;
+	if (drive->media != ide_disk)
+		return 0;
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
+	ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
+	/*
+	 * FIX ME to use only ACB ide_task_t args Struct
+	 */
+#if 0
+	{
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#else
+	command = (lba48) ? WIN_READDMA_EXT : WIN_READDMA;
+	if (rq->cmd == IDE_DRIVE_TASKFILE) {
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#endif
+	/* issue cmd to drive */
+	hwif->OUTB(command, IDE_COMMAND_REG);
+
+	return pmac_ide_dma_begin(drive);
+}
+
+static int
+pmac_ide_dma_write (ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
+	struct request *rq = HWGROUP(drive)->rq;
+//	ide_task_t *args = rq->special;
+	u8 unit = (drive->select.b.unit & 0x01);
+	u8 ata4;
+	u8 lba48 = (drive->addressing == 1) ? 1 : 0;
+	task_ioreg_t command = WIN_NOP;
+
+	if (pmif == NULL)
+		return 1;
+
+	ata4 = (pmif->kind == controller_kl_ata4 ||
+		pmif->kind == controller_kl_ata4_80);
+
+	if (!pmac_ide_build_dmatable(drive, 1))
+		return 1;
+	/* Apple adds 60ns to wrDataSetup on reads */
+	if (ata4 && (pmif->timings[unit] & TR_66_UDMA_EN)) {
+		writel(pmif->timings[unit],
+			(unsigned *)(IDE_DATA_REG+IDE_TIMING_CONFIG));
+		(void)readl((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG));
+	}
+	drive->waiting_for_dma = 1;
+	if (drive->media != ide_disk)
+		return 0;
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
+	ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
+	/*
+	 * FIX ME to use only ACB ide_task_t args Struct
+	 */
+#if 0
+	{
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#else
+	command = (lba48) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
+	if (rq->cmd == IDE_DRIVE_TASKFILE) {
+		ide_task_t *args = rq->special;
+		command = args->tfRegister[IDE_COMMAND_OFFSET];
+	}
+#endif
+	/* issue cmd to drive */
+	hwif->OUTB(command, IDE_COMMAND_REG);
+
+	return pmac_ide_dma_begin(drive);
+}
+
+static int
+pmac_ide_dma_count (ide_drive_t *drive)
+{
+	return HWIF(drive)->ide_dma_begin(drive);
+}
+
+static int
+pmac_ide_dma_begin (ide_drive_t *drive)
+{
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+	volatile struct dbdma_regs *dma;
+
+	if (pmif == NULL)
+		return 1;
+	dma = pmif->dma_regs;
+
+	writel((RUN << 16) | RUN, &dma->control);
+	/* Make sure it gets to the controller right now */
+	(void)readl(&dma->control);
+	return 0;
+}
+
+static int
+pmac_ide_dma_end (ide_drive_t *drive)
+{
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+	volatile struct dbdma_regs *dma;
+	u32 dstat;
+	
+	if (pmif == NULL)
+		return 0;
+	dma = pmif->dma_regs;
+
+	drive->waiting_for_dma = 0;
+	dstat = readl(&dma->status);
+	writel(((RUN|WAKE|DEAD) << 16), &dma->control);
+	pmac_ide_destroy_dmatable(drive);
+	/* verify good dma status */
+	return (dstat & (RUN|DEAD|ACTIVE)) != RUN;
+}
+
+static int
+pmac_ide_dma_test_irq (ide_drive_t *drive)
+{
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+	volatile struct dbdma_regs *dma;
+	unsigned long status;
+
+	if (pmif == NULL)
+		return 0;
+	dma = pmif->dma_regs;
+
+	/* We have to things to deal with here:
+	 * 
+	 * - The dbdma won't stop if the command was started
+	 * but completed with an error without transfering all
+	 * datas. This happens when bad blocks are met during
+	 * a multi-block transfer.
+	 * 
+	 * - The dbdma fifo hasn't yet finished flushing to
+	 * to system memory when the disk interrupt occurs.
+	 * 
+	 * The trick here is to increment drive->waiting_for_dma,
+	 * and return as if no interrupt occured. If the counter
+	 * reach a certain timeout value, we then return 1. If
+	 * we really got the interrupt, it will happen right away
+	 * again.
+	 * Apple's solution here may be more elegant. They issue
+	 * a DMA channel interrupt (a separate irq line) via a DBDMA
+	 * NOP command just before the STOP, and wait for both the
+	 * disk and DBDMA interrupts to have completed.
+	 */
+ 
+	/* If ACTIVE is cleared, the STOP command have passed and
+	 * transfer is complete.
+	 */
+	status = readl(&dma->status);
+	if (!(status & ACTIVE))
+		return 1;
+	if (!drive->waiting_for_dma)
+		printk(KERN_WARNING "ide%d, ide_dma_test_irq \
+			called while not waiting\n", pmif->index);
+
+	/* If dbdma didn't execute the STOP command yet, the
+	 * active bit is still set */
+	drive->waiting_for_dma++;
+	if (drive->waiting_for_dma >= DMA_WAIT_TIMEOUT) {
+		printk(KERN_WARNING "ide%d, timeout waiting \
+			for dbdma command stop\n", pmif->index);
+		return 1;
+	}
+	udelay(1);
+	return 0;
+}
+
+static int
+pmac_ide_dma_host_off (ide_drive_t *drive)
+{
+	return 0;
+}
+
+static int
+pmac_ide_dma_host_on (ide_drive_t *drive)
+{
+	return 0;
+}
+
+static int
+pmac_ide_dma_lostirq (ide_drive_t *drive)
+{
+	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+	volatile struct dbdma_regs *dma;
+	unsigned long status;
+
+	if (pmif == NULL)
+		return 0;
+	dma = pmif->dma_regs;
+
+	status = readl(&dma->status);
+	printk(KERN_ERR "ide-pmac lost interrupt, dma status: %lx\n", status);
+	return 0;
+}
+
+static void __init 
+pmac_ide_setup_dma(struct device_node *np, int ix)
+{
+	struct pmac_ide_hwif *pmif = &pmac_ide[ix];
+
+	if (request_OF_resource(np, 1, " (mac-io IDE DMA)") == NULL) {
+		printk(KERN_ERR "ide-pmac(%s): can't request DMA resource !\n", np->name);
+		return;
+	}
+
+	pmif->dma_regs =
+		(volatile struct dbdma_regs*)ioremap(np->addrs[1].address, 0x200);
+
+	/*
+	 * Allocate space for the DBDMA commands.
+	 * The +2 is +1 for the stop command and +1 to allow for
+	 * aligning the start address to a multiple of 16 bytes.
+	 */
+	pmif->dma_table_cpu = (struct dbdma_cmd*)pci_alloc_consistent(
+		ide_hwifs[ix].pci_dev,
+		(MAX_DCMDS + 2) * sizeof(struct dbdma_cmd),
+		&pmif->dma_table_dma);
+	if (pmif->dma_table_cpu == NULL) {
+		printk(KERN_ERR "%s: unable to allocate DMA command list\n",
+		       ide_hwifs[ix].name);
+		return;
+	}
+
+	pmif->sg_table = kmalloc(sizeof(struct scatterlist) * MAX_DCMDS,
+				 GFP_KERNEL);
+	if (pmif->sg_table == NULL) {
+		pci_free_consistent(	ide_hwifs[ix].pci_dev,
+					(MAX_DCMDS + 2) * sizeof(struct dbdma_cmd),
+				    	pmif->dma_table_cpu, pmif->dma_table_dma);
+		return;
+	}
+	ide_hwifs[ix].ide_dma_off = &__ide_dma_off;
+	ide_hwifs[ix].ide_dma_off_quietly = &__ide_dma_off_quietly;
+	ide_hwifs[ix].ide_dma_on = &__ide_dma_on;
+	ide_hwifs[ix].ide_dma_check = &pmac_ide_dma_check;
+	ide_hwifs[ix].ide_dma_read = &pmac_ide_dma_read;
+	ide_hwifs[ix].ide_dma_write = &pmac_ide_dma_write;
+	ide_hwifs[ix].ide_dma_count = &pmac_ide_dma_count;
+	ide_hwifs[ix].ide_dma_begin = &pmac_ide_dma_begin;
+	ide_hwifs[ix].ide_dma_end = &pmac_ide_dma_end;
+	ide_hwifs[ix].ide_dma_test_irq = &pmac_ide_dma_test_irq;
+	ide_hwifs[ix].ide_dma_host_off = &pmac_ide_dma_host_off;
+	ide_hwifs[ix].ide_dma_host_on = &pmac_ide_dma_host_on;
+	ide_hwifs[ix].ide_dma_good_drive = &__ide_dma_good_drive;
+	ide_hwifs[ix].ide_dma_bad_drive = &__ide_dma_bad_drive;
+	ide_hwifs[ix].ide_dma_verbose = &__ide_dma_verbose;
+	ide_hwifs[ix].ide_dma_timeout = &__ide_dma_timeout;
+	ide_hwifs[ix].ide_dma_retune = &__ide_dma_retune;
+	ide_hwifs[ix].ide_dma_lostirq = &pmac_ide_dma_lostirq;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO
+	if (!noautodma)
+		ide_hwifs[ix].autodma = 1;
+#endif
+	ide_hwifs[ix].drives[0].autodma = ide_hwifs[ix].autodma;
+	ide_hwifs[ix].drives[1].autodma = ide_hwifs[ix].autodma;
+}
+
+#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
+
+static void __pmac
+idepmac_sleep_device(ide_drive_t *drive, unsigned base)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	int j;
+	
+	/* FIXME: We only handle the master IDE disk, we shoud
+	 *        try to fix CD-ROMs here
+	 */
+	switch (drive->media) {
+	case ide_disk:
+		/* Spin down the drive */
+		hwif->OUTB(drive->select.all, base+0x60);
+		(void) hwif->INB(base+0x60);
+		udelay(100);
+		hwif->OUTB(0x0, base+0x30);
+		hwif->OUTB(0x0, base+0x20);
+		hwif->OUTB(0x0, base+0x40);
+		hwif->OUTB(0x0, base+0x50);
+		hwif->OUTB(0xe0, base+0x70);
+		hwif->OUTB(0x2, base+0x160);   
+		for (j = 0; j < 10; j++) {
+			u8 status;
+			mdelay(100);
+			status = hwif->INB(base+0x70);
+			if (!(status & BUSY_STAT) && (status & DRQ_STAT))
+				break;
+		}
+		break;
+	case ide_cdrom:
+		// todo
+		break;
+	case ide_floppy:
+		// todo
+		break;
+	}
+}
+
+#ifdef CONFIG_PMAC_PBOOK
+static void __pmac
+idepmac_wake_device(ide_drive_t *drive, int used_dma)
+{
+	/* We force the IDE subdriver to check for a media change
+	 * This must be done first or we may lost the condition
+	 *
+	 * Problem: This can schedule. I moved the block device
+	 * wakeup almost late by priority because of that.
+	 */
+	if (DRIVER(drive) && DRIVER(drive)->media_change)
+		DRIVER(drive)->media_change(drive);
+
+	/* We kick the VFS too (see fix in ide.c revalidate) */
+	check_disk_change(MKDEV(HWIF(drive)->major, (drive->select.b.unit) << PARTN_BITS));
+	
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+	/* We re-enable DMA on the drive if it was active. */
+	/* This doesn't work with the CD-ROM in the media-bay, probably
+	 * because of a pending unit attention. The problem if that if I
+	 * clear the error, the filesystem dies.
+	 */
+	if (used_dma && !ide_spin_wait_hwgroup(drive)) {
+		/* Lock HW group */
+		HWGROUP(drive)->busy = 1;
+		pmac_ide_dma_check(drive);
+		HWGROUP(drive)->busy = 0;
+		if (!list_empty(&drive->queue.queue_head))
+			ide_do_request(HWGROUP(drive), 0);
+		spin_unlock_irq(&io_request_lock);
+	}
+#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
+}
+
+static void __pmac
+idepmac_sleep_interface(pmac_ide_hwif_t *pmif, unsigned base, int mediabay)
+{
+	struct device_node* np = pmif->node;
+
+	/* We clear the timings */
+	pmif->timings[0] = 0;
+	pmif->timings[1] = 0;
+	
+	/* The media bay will handle itself just fine */
+	if (mediabay)
+		return;
+	
+	/* Disable the bus */
+	ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmif->aapl_bus_id, 0);
+}
+
+static void __pmac
+idepmac_wake_interface(pmac_ide_hwif_t *pmif, unsigned long base, int mediabay)
+{
+	struct device_node* np = pmif->node;
+
+	if (!mediabay) {
+		/* Revive IDE disk and controller */
+		ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 1);
+		ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmif->aapl_bus_id, 1);
+		mdelay(10);
+		ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 0);
+	}
+}
+
+static void
+idepmac_sleep_drive(ide_drive_t *drive, unsigned long base)
+{
+	int unlock = 0;
+
+	/* Wait for HW group to complete operations */
+	if (ide_spin_wait_hwgroup(drive)) {
+		// What can we do here ? Wake drive we had already
+		// put to sleep and return an error ?
+	} else {
+		unlock = 1;
+		/* Lock HW group */
+		HWGROUP(drive)->busy = 1;
+		/* Stop the device */
+		idepmac_sleep_device(drive, base);
+	}
+	if (unlock)
+		spin_unlock_irq(&io_request_lock);
+}
+
+static void
+idepmac_wake_drive(ide_drive_t *drive, unsigned long base)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	unsigned long flags;
+	int j;
+	
+	/* Reset timings */
+	pmac_ide_selectproc(drive);
+	mdelay(10);
+	
+	/* Wait up to 20 seconds for the drive to be ready */
+	for (j = 0; j < 200; j++) {
+		u8 status = 0;
+		mdelay(100);
+		hwif->OUTB(drive->select.all, base + 0x60);
+		if ((hwif->INB(base + 0x60)) != drive->select.all)
+			continue;
+		status = hwif->INB(base + 0x70);
+		if (!(status & BUSY_STAT))
+			break;
+	}
+
+	/* We resume processing on the HW group */
+	spin_lock_irqsave(&io_request_lock, flags);
+	HWGROUP(drive)->busy = 0;
+	if (!list_empty(&drive->queue.queue_head))
+		ide_do_request(HWGROUP(drive), 0);
+	spin_unlock_irqrestore(&io_request_lock, flags);			
+}
+
+/* Note: We support only master drives for now. This will have to be
+ * improved if we want to handle sleep on the iMacDV where the CD-ROM
+ * is a slave
+ */
+static int __pmac
+idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when)
+{
+	int i, ret;
+	unsigned long base;
+	int big_delay;
+ 
+	switch (when) {
+	case PBOOK_SLEEP_REQUEST:
+		break;
+	case PBOOK_SLEEP_REJECT:
+		break;
+	case PBOOK_SLEEP_NOW:
+		for (i = 0; i < pmac_ide_count; ++i) {
+			ide_hwif_t *hwif;
+			int dn;
+
+			if ((base = pmac_ide[i].regbase) == 0)
+				continue;
+
+			hwif = &ide_hwifs[i];
+			for (dn=0; dn<MAX_DRIVES; dn++) {
+				if (!hwif->drives[dn].present)
+					continue;
+				idepmac_sleep_drive(&hwif->drives[dn], base);
+			}
+			/* Disable irq during sleep */
+			disable_irq(pmac_ide[i].irq);
+			
+			/* Check if this is a media bay with an IDE device or not
+			 * a media bay.
+			 */
+			ret = check_media_bay_by_base(base, MB_CD);
+			if ((ret == 0) || (ret == -ENODEV))
+				idepmac_sleep_interface(&pmac_ide[i], base, (ret == 0));
+		}
+		break;
+	case PBOOK_WAKE:
+		big_delay = 0;
+		for (i = 0; i < pmac_ide_count; ++i) {
+
+			if ((base = pmac_ide[i].regbase) == 0)
+				continue;
+				
+			/* Make sure we have sane timings */		
+			sanitize_timings(&pmac_ide[i]);
+
+			/* Check if this is a media bay with an IDE device or not
+			 * a media bay
+			 */
+			ret = check_media_bay_by_base(base, MB_CD);
+			if ((ret == 0) || (ret == -ENODEV)) {
+				idepmac_wake_interface(&pmac_ide[i], base, (ret == 0));				
+				big_delay = 1;
+			}
+
+		}
+		/* Let hardware get up to speed */
+		if (big_delay)
+			mdelay(IDE_WAKEUP_DELAY_MS);
+	
+		for (i = 0; i < pmac_ide_count; ++i) {
+			ide_hwif_t *hwif;
+			int used_dma, dn;
+			int irq_on = 0;
+			
+			if ((base = pmac_ide[i].regbase) == 0)
+				continue;
+				
+			hwif = &ide_hwifs[i];
+			for (dn=0; dn<MAX_DRIVES; dn++) {
+				ide_drive_t *drive = &hwif->drives[dn];
+				if (!drive->present)
+					continue;
+				/* We don't have re-configured DMA yet */
+				used_dma = drive->using_dma;
+				drive->using_dma = 0;
+				idepmac_wake_drive(drive, base);
+				if (!irq_on) {
+					enable_irq(pmac_ide[i].irq);
+					irq_on = 1;
+				}
+				idepmac_wake_device(drive, used_dma);
+			}
+			if (!irq_on)
+				enable_irq(pmac_ide[i].irq);
+		}
+		break;
+	}
+	return PBOOK_SLEEP_OK;
+}
+#endif /* CONFIG_PMAC_PBOOK */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/ppc/swarm.c linux-2.4.21-pre6/drivers/ide/ppc/swarm.c
--- linux-2.4.20/drivers/ide/ppc/swarm.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/ppc/swarm.c	2003-03-26 23:49:55.000000000 +0000
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2001 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  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.
+ */
+
+/*  Derived loosely from ide-pmac.c, so:
+ *  
+ *  Copyright (C) 1998 Paul Mackerras.
+ *  Copyright (C) 1995-1998 Mark Lord
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/sibyte/sb1250_int.h>
+
+#define __IDE_SWARM_C
+
+#include <asm/sibyte/swarm_ide.h>
+
+void __init swarm_ide_probe(void)
+{
+	int i;
+	ide_hwif_t *hwif;
+	/* 
+	 * Find the first untaken slot in hwifs 
+	 */
+	for (i = 0; i < MAX_HWIFS; i++) {
+		if (!ide_hwifs[i].io_ports[IDE_DATA_OFFSET]) {
+			break;
+		}
+	}
+	if (i == MAX_HWIFS) {
+		printk("No space for SWARM onboard IDE driver in ide_hwifs[].  Not enabled.\n");
+		return;
+	}
+
+	/* Set up our stuff */
+	hwif = &ide_hwifs[i];
+	hwif->hw.io_ports[IDE_DATA_OFFSET]    = SWARM_IDE_REG(0x1f0);
+	hwif->hw.io_ports[IDE_ERROR_OFFSET]   = SWARM_IDE_REG(0x1f1);
+	hwif->hw.io_ports[IDE_NSECTOR_OFFSET] = SWARM_IDE_REG(0x1f2);
+	hwif->hw.io_ports[IDE_SECTOR_OFFSET]  = SWARM_IDE_REG(0x1f3);
+	hwif->hw.io_ports[IDE_LCYL_OFFSET]    = SWARM_IDE_REG(0x1f4);
+	hwif->hw.io_ports[IDE_HCYL_OFFSET]    = SWARM_IDE_REG(0x1f5);
+	hwif->hw.io_ports[IDE_SELECT_OFFSET]  = SWARM_IDE_REG(0x1f6);
+	hwif->hw.io_ports[IDE_STATUS_OFFSET]  = SWARM_IDE_REG(0x1f7);
+	hwif->hw.io_ports[IDE_CONTROL_OFFSET] = SWARM_IDE_REG(0x3f6);
+	hwif->hw.io_ports[IDE_IRQ_OFFSET]     = SWARM_IDE_REG(0x3f7);
+//	hwif->hw->ack_intr                    = swarm_ide_ack_intr;
+	hwif->hw.irq                          = SWARM_IDE_INT;
+#if 0
+	hwif->iops                            = swarm_iops;
+#else
+	hwif->OUTB      = hwif->OUTBP         = swarm_outb;
+	hwif->OUTW      = hwif->OUTWP         = swarm_outw;
+	hwif->OUTL      = hwif->OUTLP         = swarm_outl;
+	hwif->OUTSW     = hwif->OUTSWP        = swarm_outsw;
+	hwif->OUTSL     = hwif->OUTSLP        = swarm_outsl;
+	hwif->INB       = hwif->INBP          = swarm_inb;
+	hwif->INW       = hwif->INWP          = swarm_inw;
+	hwif->INL       = hwif->INLP          = swarm_inl;
+	hwif->INSW      = hwif->INSWP         = swarm_insw;
+	hwif->INSL      = hwif->INSLP         = swarm_insl;
+#endif
+#if 0
+	hwif->pioops                          = swarm_pio_ops;
+#else
+	hwif->ata_input_data                  = swarm_ata_input_data;
+	hwif->ata_output_data                 = swarm_ata_output_data;
+	hwif->atapi_input_bytes               = swarm_atapi_input_bytes;
+	hwif->atapi_output_bytes              = swarm_atapi_output_bytes;
+#endif
+	memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
+	hwif->irq                             = hwif->hw.irq;
+	printk("SWARM onboard IDE configured as device %i\n", i);
+
+#ifndef HWIF_PROBE_CLASSIC_METHOD
+	probe_hwif_init(hwif->index);
+#endif /* HWIF_PROBE_CLASSIC_METHOD */
+
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/q40ide.c linux-2.4.21-pre6/drivers/ide/q40ide.c
--- linux-2.4.20/drivers/ide/q40ide.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/q40ide.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,91 +0,0 @@
-/*
- *  linux/drivers/ide/q40ide.c -- Q40 I/O port IDE Driver
- *
- *     (c) Richard Zidlicky
- *
- *  This file is subject to the terms and conditions of the GNU General Public
- *  License.  See the file COPYING in the main directory of this archive for
- *  more details.
- *
- *
- */
-
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-
-#include <linux/ide.h>
-
-    /*
-     *  Bases of the IDE interfaces
-     */
-
-#define Q40IDE_NUM_HWIFS	2
-
-#define PCIDE_BASE1	0x1f0
-#define PCIDE_BASE2	0x170
-#define PCIDE_BASE3	0x1e8
-#define PCIDE_BASE4	0x168
-#define PCIDE_BASE5	0x1e0
-#define PCIDE_BASE6	0x160
-
-static const q40ide_ioreg_t pcide_bases[Q40IDE_NUM_HWIFS] = {
-    PCIDE_BASE1, PCIDE_BASE2, /* PCIDE_BASE3, PCIDE_BASE4  , PCIDE_BASE5,
-    PCIDE_BASE6 */
-};
-
-
-    /*
-     *  Offsets from one of the above bases
-     */
-
-
-/* HD_DATA was redefined in asm-m68k/ide.h */
-#undef HD_DATA
-#define HD_DATA  0x1f0
-
-
-#define PCIDE_REG(x)	((q40ide_ioreg_t)(HD_##x-PCIDE_BASE1))
-
-static const int pcide_offsets[IDE_NR_PORTS] = {
-    PCIDE_REG(DATA), PCIDE_REG(ERROR), PCIDE_REG(NSECTOR), PCIDE_REG(SECTOR),
-    PCIDE_REG(LCYL), PCIDE_REG(HCYL), PCIDE_REG(CURRENT), PCIDE_REG(STATUS),
-    PCIDE_REG(CMD)
-};
-
-static int q40ide_default_irq(q40ide_ioreg_t base)
-{
-           switch (base) { 
-	            case 0x1f0: return 14;
-		    case 0x170: return 15;
-		    case 0x1e8: return 11;
-		    default:
-			return 0;
-	   }
-}
-
-
-
-    /*
-     *  Probe for Q40 IDE interfaces
-     */
-
-void q40ide_init(void)
-{
-    int i;
-
-    if (!MACH_IS_Q40)
-      return ;
-
-    for (i = 0; i < Q40IDE_NUM_HWIFS; i++) {
-	hw_regs_t hw;
-
-	ide_setup_ports(&hw, (ide_ioreg_t)pcide_bases[i], (int *)pcide_offsets,
-			(ide_ioreg_t)pcide_bases[i]+0x206,
-			0, NULL, q40ide_default_irq(pcide_bases[i]));
-	ide_register_hw(&hw, NULL);
-    }
-}
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/qd65xx.c linux-2.4.21-pre6/drivers/ide/qd65xx.c
--- linux-2.4.20/drivers/ide/qd65xx.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/qd65xx.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,456 +0,0 @@
-/*
- *  linux/drivers/ide/qd65xx.c		Version 0.07	Sep 30, 2001
- *
- *  Copyright (C) 1996-2001  Linus Torvalds & author (see below)
- */
-
-/*
- *  Version 0.03	Cleaned auto-tune, added probe
- *  Version 0.04	Added second channel tuning
- *  Version 0.05	Enhanced tuning ; added qd6500 support
- *  Version 0.06	Added dos driver's list
- *  Version 0.07	Second channel bug fix 
- *
- * QDI QD6500/QD6580 EIDE controller fast support
- *
- * Please set local bus speed using kernel parameter idebus
- * 	for example, "idebus=33" stands for 33Mhz VLbus
- * To activate controller support, use "ide0=qd65xx"
- * To enable tuning, use "ide0=autotune"
- * To enable second channel tuning (qd6580 only), use "ide1=autotune"
- */
-
-/*
- * Rewritten from the work of Colten Edwards <pje120@cs.usask.ca> by
- * Samuel Thibault <samuel.thibault@fnac.net>
- */
-
-#undef REALLY_SLOW_IO		/* most systems can safely undef this */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-#include <asm/io.h>
-
-#include "ide_modes.h"
-#include "qd65xx.h"
-
-/*
- * I/O ports are 0x30-0x31 (and 0x32-0x33 for qd6580)
- *            or 0xb0-0xb1 (and 0xb2-0xb3 for qd6580)
- *	-- qd6500 is a single IDE interface
- *	-- qd6580 is a dual IDE interface
- *
- * More research on qd6580 being done by willmore@cig.mot.com (David)
- * More Information given by Petr Soucek (petr@ryston.cz)
- * http://www.ryston.cz/petr/vlb
- */
-
-/*
- * base: Timer1
- *
- *
- * base+0x01: Config (R/O)
- *
- * bit 0: ide baseport: 1 = 0x1f0 ; 0 = 0x170 (only useful for qd6500)
- * bit 1: qd65xx baseport: 1 = 0xb0 ; 0 = 0x30
- * bit 2: ID3: bus speed: 1 = <=33MHz ; 0 = >33MHz
- * bit 3: qd6500: 1 = disabled, 0 = enabled
- *        qd6580: 1
- * upper nibble:
- *        qd6500: 1100
- *        qd6580: either 1010 or 0101
- *
- *
- * base+0x02: Timer2 (qd6580 only)
- *
- *
- * base+0x03: Control (qd6580 only)
- *
- * bits 0-3 must always be set 1
- * bit 4 must be set 1, but is set 0 by dos driver while measuring vlb clock
- * bit 0 : 1 = Only primary port enabled : channel 0 for hda, channel 1 for hdb
- *         0 = Primary and Secondary ports enabled : channel 0 for hda & hdb
- *                                                   channel 1 for hdc & hdd
- * bit 1 : 1 = only disks on primary port
- *         0 = disks & ATAPI devices on primary port
- * bit 2-4 : always 0
- * bit 5 : status, but of what ?
- * bit 6 : always set 1 by dos driver
- * bit 7 : set 1 for non-ATAPI devices on primary port
- * 	(maybe read-ahead and post-write buffer ?)
- */
-
-static int timings[4]={-1,-1,-1,-1}; /* stores current timing for each timer */
-
-static void qd_write_reg (byte content, byte reg)
-{
-	unsigned long flags;
-
-	save_flags(flags);	/* all CPUs */
-	cli();			/* all CPUs */
-	outb(content,reg);
-	restore_flags(flags);	/* all CPUs */
-}
-
-byte __init qd_read_reg (byte reg)
-{
-	unsigned long flags;
-	byte read;
-
-	save_flags(flags);	/* all CPUs */
-	cli();			/* all CPUs */
-	read = inb(reg);
-	restore_flags(flags);	/* all CPUs */
-	return read;
-}
-
-/*
- * qd_select:
- *
- * This routine is invoked from ide.c to prepare for access to a given drive.
- */
-
-static void qd_select (ide_drive_t *drive)
-{
-	byte index = (( (QD_TIMREG(drive)) & 0x80 ) >> 7) |
-			(QD_TIMREG(drive) & 0x02);
-
-	if (timings[index] != QD_TIMING(drive))
-		qd_write_reg(timings[index] = QD_TIMING(drive), QD_TIMREG(drive));
-}
-
-/*
- * qd6500_compute_timing
- *
- * computes the timing value where
- * 	lower nibble represents active time,   in count of VLB clocks
- * 	upper nibble represents recovery time, in count of VLB clocks
- */
-
-static byte qd6500_compute_timing (ide_hwif_t *hwif, int active_time, int recovery_time)
-{
-	byte active_cycle,recovery_cycle;
-
-	if (ide_system_bus_speed()<=33) {
-		active_cycle =   9  - IDE_IN(active_time   * ide_system_bus_speed() / 1000 + 1, 2, 9);
-		recovery_cycle = 15 - IDE_IN(recovery_time * ide_system_bus_speed() / 1000 + 1, 0, 15);
-	} else {
-		active_cycle =   8  - IDE_IN(active_time   * ide_system_bus_speed() / 1000 + 1, 1, 8);
-		recovery_cycle = 18 - IDE_IN(recovery_time * ide_system_bus_speed() / 1000 + 1, 3, 18);
-	}
-
-	return((recovery_cycle<<4) | 0x08 | active_cycle);
-}
-
-/*
- * qd6580_compute_timing
- *
- * idem for qd6580
- */
-
-static byte qd6580_compute_timing (int active_time, int recovery_time)
-{
-	byte active_cycle   = 17-IDE_IN(active_time   * ide_system_bus_speed() / 1000 + 1, 2, 17);
-	byte recovery_cycle = 15-IDE_IN(recovery_time * ide_system_bus_speed() / 1000 + 1, 2, 15);
-
-	return((recovery_cycle<<4) | active_cycle);
-}
-
-/*
- * qd_find_disk_type
- *
- * tries to find timing from dos driver's table
- */
-
-static int qd_find_disk_type (ide_drive_t *drive,
-		int *active_time, int *recovery_time)
-{
-	struct qd65xx_timing_s *p;
-	char model[40];
-
-	if (!*drive->id->model) return 0;
-
-	strncpy(model,drive->id->model,40);
-	ide_fixstring(model,40,1); /* byte-swap */
-
-	for (p = qd65xx_timing ; p->offset != -1 ; p++) {
-		if (!strncmp(p->model, model+p->offset,4)) {
-			printk(KERN_DEBUG "%s: listed !\n",drive->name);
-			*active_time = p->active;
-			*recovery_time = p->recovery;
-			return 1;
-		}
-	}
-	return 0;
-}
-
-/*
- * qd_timing_ok:
- *
- * check whether timings don't conflict
- */
-
-static int qd_timing_ok (ide_drive_t drives[])
-{
-	return (IDE_IMPLY(drives[0].present && drives[1].present,
-			IDE_IMPLY(QD_TIMREG(drives) == QD_TIMREG(drives+1),
-			          QD_TIMING(drives) == QD_TIMING(drives+1))));
-	/* if same timing register, must be same timing */
-}
-
-/*
- * qd_set_timing:
- *
- * records the timing, and enables selectproc as needed
- */
-
-static void qd_set_timing (ide_drive_t *drive, byte timing)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-
-	drive->drive_data &= 0xff00;
-	drive->drive_data |= timing;
-	if (qd_timing_ok(hwif->drives)) {
-		qd_select(drive); /* selects once */
-		hwif->selectproc = NULL;
-	} else
-		hwif->selectproc = &qd_select;
-
-	printk(KERN_DEBUG "%s: %#x\n",drive->name,timing);
-}
-
-/*
- * qd6500_tune_drive
- */
-
-static void qd6500_tune_drive (ide_drive_t *drive, byte pio)
-{
-	int active_time   = 175;
-	int recovery_time = 415; /* worst case values from the dos driver */
-
-	if (drive->id && !qd_find_disk_type(drive,&active_time,&recovery_time)
-		&& drive->id->tPIO && (drive->id->field_valid & 0x02)
-		&& drive->id->eide_pio >= 240) {
-
-		printk(KERN_INFO "%s: PIO mode%d\n", drive->name,
-				drive->id->tPIO);
-		active_time = 110;
-		recovery_time = drive->id->eide_pio - 120;
-	}
-
-	qd_set_timing(drive,qd6500_compute_timing(HWIF(drive),active_time,recovery_time));
-}
-
-/*
- * qd6580_tune_drive
- */
-
-static void qd6580_tune_drive (ide_drive_t *drive, byte pio)
-{
-	ide_pio_data_t d;
-	int base = HWIF(drive)->select_data;
-	int active_time   = 175;
-	int recovery_time = 415; /* worst case values from the dos driver */
-
-	if (drive->id && !qd_find_disk_type(drive,&active_time,&recovery_time)) {
-		pio = ide_get_best_pio_mode(drive, pio, 255, &d);
-		pio = IDE_MIN(pio,4);
-
-		switch (pio) {
-			case 0: break;
-			case 3:
-				if (d.cycle_time >= 110) {
-					active_time = 86;
-					recovery_time = d.cycle_time-102;
-				} else
-					printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
-				break;
-			case 4:
-				if (d.cycle_time >= 69) {
-					active_time = 70;
-					recovery_time = d.cycle_time-61;
-				} else
-					printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
-				break;
-			default:
-				if (d.cycle_time >= 180) {
-					active_time = 110;
-					recovery_time = d.cycle_time - 120;
-				} else {
-					active_time = ide_pio_timings[pio].active_time;
-					recovery_time = d.cycle_time
-							-active_time;
-				}
-		}
-		printk(KERN_INFO "%s: PIO mode%d\n",drive->name,pio);
-	}
-
-	if (!HWIF(drive)->channel && drive->media != ide_disk) {
-		qd_write_reg(0x5f,QD_CONTROL_PORT);
-		printk(KERN_WARNING "%s: ATAPI: disabled read-ahead FIFO and post-write buffer on %s.\n",drive->name,HWIF(drive)->name);
-	}
-
-	qd_set_timing(drive,qd6580_compute_timing(active_time,recovery_time));
-}
-
-/*
- * qd_testreg
- *
- * tests if the given port is a register
- */
-
-static int __init qd_testreg(int port)
-{
-	byte savereg;
-	byte readreg;
-	unsigned long flags;
-
-	save_flags(flags);	/* all CPUs */
-	cli();			/* all CPUs */
-	savereg = inb_p(port);
-	outb_p(QD_TESTVAL,port);	/* safe value */
-	readreg = inb_p(port);
-	outb(savereg,port);
-	restore_flags(flags);	/* all CPUs */
-
-	if (savereg == QD_TESTVAL) {
-		printk(KERN_ERR "Outch ! the probe for qd65xx isn't reliable !\n");
-		printk(KERN_ERR "Please contact maintainers to tell about your hardware\n");
-		printk(KERN_ERR "Assuming qd65xx is not present.\n");
-		return 1;
-	}
-
-	return (readreg != QD_TESTVAL);
-}
-
-/*
- * probe:
- *
- * looks at the specified baseport, and if qd found, registers & initialises it
- * return 1 if another qd may be probed
- */
-
-int __init probe (int base)
-{
-	byte config;
-	byte index;
-
-	config = qd_read_reg(QD_CONFIG_PORT);
-
-	if (! ((config & QD_CONFIG_BASEPORT) >> 1 == (base == 0xb0)) ) return 1;
-
-	index = ! (config & QD_CONFIG_IDE_BASEPORT);
-
-	if ((config & 0xf0) == QD_CONFIG_QD6500) {
-		ide_hwif_t *hwif = &ide_hwifs[index];
-
-		if (qd_testreg(base)) return 1;		/* bad register */
-
-			/* qd6500 found */
-
-		printk(KERN_NOTICE "%s: qd6500 at %#x\n",
-			ide_hwifs[index].name, base);
-		
-		printk(KERN_DEBUG "qd6500: config=%#x, ID3=%u\n",
-			config, QD_ID3);
-		
-		if (config & QD_CONFIG_DISABLED) {
-			printk(KERN_WARNING "qd6500 is disabled !\n");
-			return 1;
-		}
-
-		hwif->chipset = ide_qd65xx;
-		hwif->select_data = base;
-		hwif->config_data = config;
-		hwif->drives[0].drive_data =
-		hwif->drives[1].drive_data = QD6500_DEF_DATA;
-		hwif->drives[0].io_32bit =
-		hwif->drives[1].io_32bit = 1;
-		hwif->tuneproc = &qd6500_tune_drive;
-		return 1;
-	}
-
-	if (((config & 0xf0) == QD_CONFIG_QD6580_A) || ((config & 0xf0) == QD_CONFIG_QD6580_B)) {
-
-		byte control;
-
-		if (qd_testreg(base) || qd_testreg(base+0x02)) return 1;
-			/* bad registers */
-
-			/* qd6580 found */
-
-		control = qd_read_reg(QD_CONTROL_PORT);
-
-		printk(KERN_NOTICE "qd6580 at %#x\n", base);
-		printk(KERN_DEBUG "qd6580: config=%#x, control=%#x, ID3=%u\n",
-			config, control, QD_ID3);
-
-		if (control & QD_CONTR_SEC_DISABLED) {
-			ide_hwif_t *hwif = &ide_hwifs[index];
-
-			/* secondary disabled */
-			printk(KERN_INFO "%s: qd6580: single IDE board\n",
-					ide_hwifs[index].name);
-
-			hwif->chipset = ide_qd65xx;
-			hwif->select_data = base;
-			hwif->config_data = config | (control <<8);
-			hwif->drives[0].drive_data =
-			hwif->drives[1].drive_data = QD6580_DEF_DATA;
-			hwif->drives[0].io_32bit =
-			hwif->drives[1].io_32bit = 1;
-			hwif->tuneproc = &qd6580_tune_drive;
-
-			qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT);
-
-			return 1;
-		} else {
-			int i,j;
-			/* secondary enabled */
-			printk(KERN_INFO "%s&%s: qd6580: dual IDE board\n",
-					ide_hwifs[0].name,ide_hwifs[1].name);
-
-			for (i=0;i<2;i++) {
-
-				ide_hwifs[i].chipset = ide_qd65xx;
-				ide_hwifs[i].mate = &ide_hwifs[i^1];
-				ide_hwifs[i].channel = i;
-
-				ide_hwifs[i].select_data = base;
-				ide_hwifs[i].config_data = config | (control <<8);
-				ide_hwifs[i].tuneproc = &qd6580_tune_drive;
-
-				for (j=0;j<2;j++) {
-					ide_hwifs[i].drives[j].drive_data =
-					       i?QD6580_DEF_DATA2:QD6580_DEF_DATA;
-					ide_hwifs[i].drives[j].io_32bit = 1;
-				}
-			}
-
-			qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT);
-
-			return 0; /* no other qd65xx possible */
-		}
-	}
-	/* no qd65xx found */
-	return 1;
-}
-
-/*
- * init_qd65xx:
- *
- * called at the very beginning of initialization ; should just probe and link
- */
-
-void __init init_qd65xx (void)
-{
-	if (probe(0x30)) probe(0xb0);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/qd65xx.h linux-2.4.21-pre6/drivers/ide/qd65xx.h
--- linux-2.4.20/drivers/ide/qd65xx.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/qd65xx.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,140 +0,0 @@
-/*
- * linux/drivers/ide/qd65xx.h
- *
- * Copyright (c) 2000	Linus Torvalds & authors
- */
-
-/*
- * Authors:	Petr Soucek <petr@ryston.cz>
- * 		Samuel Thibault <samuel.thibault@fnac.net>
- */
-
-/* truncates a in [b,c] */
-#define IDE_IN(a,b,c)   ( ((a)<(b)) ? (b) : ( (a)>(c) ? (c) : (a)) )
-
-#define IDE_IMPLY(a,b)	((!(a)) || (b))
-
-#define QD_TIM1_PORT		(base)
-#define QD_CONFIG_PORT		(base+0x01)
-#define QD_TIM2_PORT		(base+0x02)
-#define QD_CONTROL_PORT		(base+0x03)
-
-#define QD_CONFIG_IDE_BASEPORT	0x01
-#define QD_CONFIG_BASEPORT	0x02
-#define QD_CONFIG_ID3		0x04
-#define QD_CONFIG_DISABLED	0x08
-#define QD_CONFIG_QD6500	0xc0
-#define QD_CONFIG_QD6580_A	0xa0
-#define QD_CONFIG_QD6580_B	0x50
-
-#define QD_CONTR_SEC_DISABLED	0x01
-
-#define QD_ID3			((config & QD_CONFIG_ID3)!=0)
-
-#define QD_CONFIG(hwif)		((hwif)->config_data & 0x00ff)
-#define QD_CONTROL(hwif)	(((hwif)->config_data & 0xff00) >> 8)
-
-#define QD_TIMING(drive)	(byte)(((drive)->drive_data) & 0x00ff)
-#define QD_TIMREG(drive)	(byte)((((drive)->drive_data) & 0xff00) >> 8)
-
-#define QD6500_DEF_DATA		((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0c : 0x08))
-#define QD6580_DEF_DATA		((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0a : 0x00))
-#define QD6580_DEF_DATA2	((QD_TIM2_PORT<<8) | (QD_ID3 ? 0x0a : 0x00))
-#define QD_DEF_CONTR		(0x40 | ((control & 0x02) ? 0x9f : 0x1f))
-
-#define QD_TESTVAL		0x19	/* safe value */
-
-/* Drive specific timing taken from DOS driver v3.7 */
-
-struct qd65xx_timing_s {
-	char	offset;   /* ofset from the beginning of Model Number" */
-	char	model[4];    /* 4 chars from Model number, no conversion */
-	short	active;   /* active time */
-	short	recovery; /* recovery time */
-} qd65xx_timing [] = {
-	{ 30, "2040", 110, 225 },  /* Conner CP30204			*/
-	{ 30, "2045", 135, 225 },  /* Conner CP30254			*/
-	{ 30, "1040", 155, 325 },  /* Conner CP30104			*/
-	{ 30, "1047", 135, 265 },  /* Conner CP30174			*/
-	{ 30, "5344", 135, 225 },  /* Conner CP3544			*/
-	{ 30, "01 4", 175, 405 },  /* Conner CP-3104			*/
-	{ 27, "C030", 175, 375 },  /* Conner CP3000			*/
-	{  8, "PL42", 110, 295 },  /* Quantum LP240			*/
-	{  8, "PL21", 110, 315 },  /* Quantum LP120			*/
-	{  8, "PL25", 175, 385 },  /* Quantum LP52			*/
-	{  4, "PA24", 110, 285 },  /* WD Piranha SP4200			*/
-	{  6, "2200", 110, 260 },  /* WD Caviar AC2200			*/
-	{  6, "3204", 110, 235 },  /* WD Caviar AC2340			*/
-	{  6, "1202", 110, 265 },  /* WD Caviar AC2120			*/
-	{  0, "DS3-", 135, 315 },  /* Teac SD340			*/
-	{  8, "KM32", 175, 355 },  /* Toshiba MK234			*/
-	{  2, "53A1", 175, 355 },  /* Seagate ST351A			*/
-	{  2, "4108", 175, 295 },  /* Seagate ST1480A			*/
-	{  2, "1344", 175, 335 },  /* Seagate ST3144A			*/
-	{  6, "7 12", 110, 225 },  /* Maxtor 7213A			*/
-	{ 30, "02F4", 145, 295 },  /* Conner 3204F			*/
-	{  2, "1302", 175, 335 },  /* Seagate ST3120A			*/
-	{  2, "2334", 145, 265 },  /* Seagate ST3243A			*/
-	{  2, "2338", 145, 275 },  /* Seagate ST3283A			*/
-	{  2, "3309", 145, 275 },  /* Seagate ST3390A			*/
-	{  2, "5305", 145, 275 },  /* Seagate ST3550A			*/
-	{  2, "4100", 175, 295 },  /* Seagate ST1400A			*/
-	{  2, "4110", 175, 295 },  /* Seagate ST1401A			*/
-	{  2, "6300", 135, 265 },  /* Seagate ST3600A			*/
-	{  2, "5300", 135, 265 },  /* Seagate ST3500A			*/
-	{  6, "7 31", 135, 225 },  /* Maxtor 7131 AT			*/
-	{  6, "7 43", 115, 265 },  /* Maxtor 7345 AT			*/
-	{  6, "7 42", 110, 255 },  /* Maxtor 7245 AT			*/
-	{  6, "3 04", 135, 265 },  /* Maxtor 340 AT			*/
-	{  6, "61 0", 135, 285 },  /* WD AC160				*/
-	{  6, "1107", 135, 235 },  /* WD AC1170				*/
-	{  6, "2101", 110, 220 },  /* WD AC1210				*/
-	{  6, "4202", 135, 245 },  /* WD AC2420				*/
-	{  6, "41 0", 175, 355 },  /* WD Caviar 140			*/
-	{  6, "82 0", 175, 355 },  /* WD Caviar 280			*/
-	{  8, "PL01", 175, 375 },  /* Quantum LP105			*/
-	{  8, "PL25", 110, 295 },  /* Quantum LP525			*/
-	{ 10, "4S 2", 175, 385 },  /* Quantum ELS42			*/
-	{ 10, "8S 5", 175, 385 },  /* Quantum ELS85			*/
-	{ 10, "1S72", 175, 385 },  /* Quantum ELS127			*/
-	{ 10, "1S07", 175, 385 },  /* Quantum ELS170			*/
-	{  8, "ZE42", 135, 295 },  /* Quantum EZ240			*/
-	{  8, "ZE21", 175, 385 },  /* Quantum EZ127			*/
-	{  8, "ZE58", 175, 385 },  /* Quantum EZ85			*/
-	{  8, "ZE24", 175, 385 },  /* Quantum EZ42			*/
-	{ 27, "C036", 155, 325 },  /* Conner CP30064			*/
-	{ 27, "C038", 155, 325 },  /* Conner CP30084			*/
-	{  6, "2205", 110, 255 },  /* WDC AC2250			*/
-	{  2, " CHA", 140, 415 },  /* WDC AH series; WDC AH260, WDC	*/
-	{  2, " CLA", 140, 415 },  /* WDC AL series: WDC AL2120, 2170,	*/
-	{  4, "UC41", 140, 415 },  /* WDC CU140				*/
-	{  6, "1207", 130, 275 },  /* WDC AC2170			*/
-	{  6, "2107", 130, 275 },  /* WDC AC1270			*/
-	{  6, "5204", 130, 275 },  /* WDC AC2540			*/
-	{ 30, "3004", 110, 235 },  /* Conner CP30340			*/
-	{ 30, "0345", 135, 255 },  /* Conner CP30544			*/
-	{ 12, "12A3", 175, 320 },  /* MAXTOR LXT-213A			*/
-	{ 12, "43A0", 145, 240 },  /* MAXTOR LXT-340A			*/
-	{  6, "7 21", 180, 290 },  /* Maxtor 7120 AT			*/
-	{  6, "7 71", 135, 240 },  /* Maxtor 7170 AT			*/
-	{ 12, "45\0000", 110, 205 },   /* MAXTOR MXT-540		*/
-	{  8, "PL11", 180, 290 },  /* QUANTUM LP110A			*/
-	{  8, "OG21", 150, 275 },  /* QUANTUM GO120			*/
-	{ 12, "42A5", 175, 320 },  /* MAXTOR LXT-245A			*/
-	{  2, "2309", 175, 295 },  /* ST3290A				*/
-	{  2, "3358", 180, 310 },  /* ST3385A				*/
-	{  2, "6355", 180, 310 },  /* ST3655A				*/
-	{  2, "1900", 175, 270 },  /* ST9100A				*/
-	{  2, "1954", 175, 270 },  /* ST9145A				*/
-	{  2, "1909", 175, 270 },  /* ST9190AG				*/
-	{  2, "2953", 175, 270 },  /* ST9235A				*/
-	{  2, "1359", 175, 270 },  /* ST3195A				*/
-	{ 24, "3R11", 175, 290 },  /* ALPS ELECTRIC Co.,LTD, DR311C	*/
-	{  0, "2M26", 175, 215 },  /* M262XT-0Ah			*/
-	{  4, "2253", 175, 300 },  /* HP C2235A				*/
-	{  4, "-32A", 145, 245 },  /* H3133-A2				*/
-	{ 30, "0326", 150, 270 },  /* Samsung Electronics 120MB		*/
-	{ 30, "3044", 110, 195 },  /* Conner CFA340A			*/
-	{ 30, "43A0", 110, 195 },  /* Conner CFA340A			*/
-	{ -1, "    ", 175, 415 }   /* unknown disk name			*/
-};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/raid/Makefile linux-2.4.21-pre6/drivers/ide/raid/Makefile
--- linux-2.4.20/drivers/ide/raid/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/raid/Makefile	2003-03-26 23:49:51.000000000 +0000
@@ -0,0 +1,19 @@
+
+O_TARGET := idedriver-raid.o
+
+obj-y		:=
+obj-m		:=
+
+export-objs := ataraid.o
+
+# The virtualised raid layers MUST come after the ide itself or bad stuff
+# will happen.
+
+obj-$(CONFIG_BLK_DEV_ATARAID)		+= ataraid.o
+obj-$(CONFIG_BLK_DEV_ATARAID_PDC)	+= pdcraid.o
+obj-$(CONFIG_BLK_DEV_ATARAID_HPT)	+= hptraid.o
+obj-$(CONFIG_BLK_DEV_ATARAID_SII)	+= silraid.o
+
+EXTRA_CFLAGS	:= -I../
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/raid/ataraid.c linux-2.4.21-pre6/drivers/ide/raid/ataraid.c
--- linux-2.4.20/drivers/ide/raid/ataraid.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/raid/ataraid.c	2003-03-26 23:49:35.000000000 +0000
@@ -0,0 +1,317 @@
+/*
+   ataraid.c  Copyright (C) 2001 Red Hat, Inc. 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, or (at your option)
+   any later version.
+   
+   You should have received a copy of the GNU General Public License
+   (for example /usr/src/linux/COPYING); if not, write to the Free
+   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
+   
+   Authors: 	Arjan van de Ven <arjanv@redhat.com>
+   		
+   
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <asm/semaphore.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/blkdev.h>
+#include <linux/blkpg.h>
+#include <linux/genhd.h>
+#include <linux/ioctl.h>
+#include <linux/kdev_t.h>
+#include <linux/swap.h>
+
+#include <linux/ide.h>
+#include <asm/uaccess.h>
+
+#include "ataraid.h"
+
+                                        
+static int ataraid_hardsect_size[256];
+static int ataraid_blksize_size[256];
+
+static struct raid_device_operations* ataraid_ops[16];
+
+static int ataraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+static int ataraid_open(struct inode * inode, struct file * filp);
+static int ataraid_release(struct inode * inode, struct file * filp);
+static void ataraid_split_request(request_queue_t *q, int rw, struct buffer_head * bh);
+
+
+struct gendisk ataraid_gendisk;
+static int ataraid_gendisk_sizes[256];
+static int ataraid_readahead[256];
+
+static struct block_device_operations ataraid_fops = {
+	owner:			THIS_MODULE,
+	open:                   ataraid_open,
+	release:                ataraid_release,
+	ioctl:                  ataraid_ioctl,
+};
+                
+
+
+static DECLARE_MUTEX(ataraid_sem);
+
+/* Bitmap for the devices currently in use */
+static unsigned int ataraiduse;
+
+
+/* stub fops functions */
+
+static int ataraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)  
+{
+	int minor;
+	minor = MINOR(inode->i_rdev)>>SHIFT;
+	
+	if ((ataraid_ops[minor])&&(ataraid_ops[minor]->ioctl))
+		return (ataraid_ops[minor]->ioctl)(inode,file,cmd,arg);
+	return -EINVAL;
+}
+
+static int ataraid_open(struct inode * inode, struct file * filp)
+{
+	int minor;
+	minor = MINOR(inode->i_rdev)>>SHIFT;
+
+	if ((ataraid_ops[minor])&&(ataraid_ops[minor]->open))
+		return (ataraid_ops[minor]->open)(inode,filp);
+	return -EINVAL;
+}
+
+
+static int ataraid_release(struct inode * inode, struct file * filp)
+{
+	int minor;
+	minor = MINOR(inode->i_rdev)>>SHIFT;
+
+	if ((ataraid_ops[minor])&&(ataraid_ops[minor]->release))
+		return (ataraid_ops[minor]->release)(inode,filp);
+	return -EINVAL;
+}
+
+static int ataraid_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
+{
+	int minor;
+	int retval;
+	minor = MINOR(bh->b_rdev)>>SHIFT;
+
+	if ((ataraid_ops[minor])&&(ataraid_ops[minor]->make_request)) {
+		
+		retval= (ataraid_ops[minor]->make_request)(q,rw,bh);
+		if (retval == -1) {
+			ataraid_split_request(q,rw,bh);		
+			return 0;
+		} else
+			return retval;
+	}
+	return -EINVAL;
+}
+
+struct buffer_head *ataraid_get_bhead(void)
+{
+	void *ptr = NULL;
+	while (!ptr) {
+		ptr=kmalloc(sizeof(struct buffer_head),GFP_NOIO);
+		if (!ptr) {
+			__set_current_state(TASK_RUNNING);
+			yield();
+		}
+	}
+	return ptr;
+}
+
+EXPORT_SYMBOL(ataraid_get_bhead);
+
+struct ataraid_bh_private *ataraid_get_private(void)
+{
+	void *ptr = NULL;
+	while (!ptr) {
+		ptr=kmalloc(sizeof(struct ataraid_bh_private),GFP_NOIO);
+		if (!ptr) {
+			__set_current_state(TASK_RUNNING);
+			yield();
+		}
+	}
+	return ptr;
+}
+
+EXPORT_SYMBOL(ataraid_get_private);
+
+void ataraid_end_request(struct buffer_head *bh, int uptodate)
+{
+	struct ataraid_bh_private *private = bh->b_private;
+
+	if (private==NULL)
+		BUG();
+
+	if (atomic_dec_and_test(&private->count)) {
+		private->parent->b_end_io(private->parent,uptodate);
+		private->parent = NULL;
+		kfree(private);
+	}
+	kfree(bh);
+}
+
+EXPORT_SYMBOL(ataraid_end_request);
+
+static void ataraid_split_request(request_queue_t *q, int rw, struct buffer_head * bh)
+{
+	struct buffer_head *bh1,*bh2;
+	struct ataraid_bh_private *private;
+	bh1=ataraid_get_bhead();
+	bh2=ataraid_get_bhead();
+
+	/* If either of those ever fails we're doomed */
+	if ((!bh1)||(!bh2))
+		BUG();
+	private = ataraid_get_private();
+	if (private==NULL)
+		BUG();
+	
+	memcpy(bh1, bh, sizeof(*bh));
+	memcpy(bh2, bh, sizeof(*bh));
+	
+	bh1->b_end_io = ataraid_end_request;
+	bh2->b_end_io = ataraid_end_request;
+
+	bh2->b_rsector += bh->b_size >> 10;
+	bh1->b_size /= 2;
+	bh2->b_size /= 2;
+	private->parent = bh;
+
+	bh1->b_private = private;
+	bh2->b_private = private;
+	atomic_set(&private->count,2);
+
+	bh2->b_data +=  bh->b_size/2;
+
+	generic_make_request(rw,bh1);
+	generic_make_request(rw,bh2);
+}
+
+
+
+
+/* device register / release functions */
+
+
+int ataraid_get_device(struct raid_device_operations *fops)
+{
+	int bit;
+	down(&ataraid_sem);
+	if (ataraiduse==~0U) {
+		up(&ataraid_sem);
+		return -ENODEV;
+	}
+	bit=ffz(ataraiduse); 
+	ataraiduse |= 1<<bit;
+	ataraid_ops[bit] = fops;
+	up(&ataraid_sem);
+	return bit;
+}
+
+void ataraid_release_device(int device)
+{
+	down(&ataraid_sem);
+	
+	if ((ataraiduse & (1<<device))==0)
+		BUG();	/* device wasn't registered at all */
+	
+	ataraiduse &= ~(1<<device);
+	ataraid_ops[device] = NULL;
+	up(&ataraid_sem);
+}
+
+void ataraid_register_disk(int device,long size)
+{
+	register_disk(&ataraid_gendisk, MKDEV(ATAMAJOR,16*device),16,
+		&ataraid_fops,size);
+
+}
+
+static __init int ataraid_init(void) 
+{
+	int i;
+        for(i=0;i<256;i++)
+	{
+        	ataraid_hardsect_size[i] = 512;
+		ataraid_blksize_size[i] = 1024;  
+		ataraid_readahead[i] = 1023;
+	}
+	
+	if (blksize_size[ATAMAJOR]==NULL)
+		blksize_size[ATAMAJOR] = ataraid_blksize_size;
+	if (hardsect_size[ATAMAJOR]==NULL)
+		hardsect_size[ATAMAJOR] = ataraid_hardsect_size;
+	
+	
+	/* setup the gendisk structure */	
+	ataraid_gendisk.part = kmalloc(256 * sizeof(struct hd_struct),GFP_KERNEL);
+	if (ataraid_gendisk.part==NULL) {
+		printk(KERN_ERR "ataraid: Couldn't allocate memory, aborting \n");
+		return -1;
+	}
+	
+	memset(&ataraid_gendisk.part[0],0,256*sizeof(struct hd_struct));
+	
+	
+	ataraid_gendisk.major       = ATAMAJOR;
+	ataraid_gendisk.major_name  = "ataraid";
+	ataraid_gendisk.minor_shift = 4;
+	ataraid_gendisk.max_p	    = 15;
+	ataraid_gendisk.sizes	    = &ataraid_gendisk_sizes[0];
+	ataraid_gendisk.nr_real	    = 16;
+	ataraid_gendisk.fops        = &ataraid_fops;
+	
+	
+	add_gendisk(&ataraid_gendisk);
+			
+	if (register_blkdev(ATAMAJOR, "ataraid", &ataraid_fops)) {
+		printk(KERN_ERR "ataraid: Could not get major %d \n",ATAMAJOR);
+		return -1;
+	}
+	
+	                
+	
+	blk_queue_make_request(BLK_DEFAULT_QUEUE(ATAMAJOR),ataraid_make_request);
+                                                                                     	
+	return 0;                                                        	
+}
+
+
+static void __exit ataraid_exit(void)
+{
+	unregister_blkdev(ATAMAJOR, "ataraid");
+	hardsect_size[ATAMAJOR] = NULL;
+	blk_size[ATAMAJOR] = NULL;
+	blksize_size[ATAMAJOR] = NULL;                       
+	max_readahead[ATAMAJOR] = NULL;
+
+	del_gendisk(&ataraid_gendisk);
+        
+	if (ataraid_gendisk.part) {
+		kfree(ataraid_gendisk.part);
+		ataraid_gendisk.part = NULL;
+	}
+}
+
+module_init(ataraid_init);
+module_exit(ataraid_exit);
+
+
+
+EXPORT_SYMBOL(ataraid_get_device);
+EXPORT_SYMBOL(ataraid_release_device);
+EXPORT_SYMBOL(ataraid_gendisk);
+EXPORT_SYMBOL(ataraid_register_disk);
+MODULE_LICENSE("GPL");
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/raid/ataraid.h linux-2.4.21-pre6/drivers/ide/raid/ataraid.h
--- linux-2.4.20/drivers/ide/raid/ataraid.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/raid/ataraid.h	2003-03-26 23:49:25.000000000 +0000
@@ -0,0 +1,72 @@
+/*
+   ataraid.h  Copyright (C) 2001 Red Hat, Inc. 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, or (at your option)
+   any later version.
+   
+   You should have received a copy of the GNU General Public License
+   (for example /usr/src/linux/COPYING); if not, write to the Free
+   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
+   
+   Authors: 	Arjan van de Ven <arjanv@redhat.com>
+   		
+   
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <asm/semaphore.h>
+#include <linux/blkdev.h>
+#include <linux/blkpg.h>
+#include <linux/genhd.h>
+#include <linux/ioctl.h>
+
+#include <linux/ide.h>
+#include <asm/uaccess.h>
+
+#define ATAMAJOR 114
+#define SHIFT 4
+#define MINOR_MASK 15
+#define MAJOR_MASK 15
+
+                                        
+/* raid_device_operations is a light struct block_device_operations with an
+   added method for make_request */
+struct raid_device_operations {
+	int (*open) (struct inode *, struct file *);
+	int (*release) (struct inode *, struct file *);
+	int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long);
+	int (*make_request) (request_queue_t *q, int rw, struct buffer_head * bh);
+};
+
+
+struct geom {
+	unsigned char heads;
+	unsigned int cylinders;
+	unsigned char sectors;
+};
+
+/* structure for the splitting of bufferheads */
+
+struct ataraid_bh_private {
+	struct buffer_head *parent;
+	atomic_t count;
+};
+
+extern struct gendisk ataraid_gendisk;
+
+extern int ataraid_get_device(struct raid_device_operations *fops);
+extern void ataraid_release_device(int device);
+extern int get_blocksize(kdev_t dev);
+extern void ataraid_register_disk(int device,long size);
+extern struct buffer_head *ataraid_get_bhead(void);
+extern struct ataraid_bh_private *ataraid_get_private(void);
+extern void ataraid_end_request(struct buffer_head *bh, int uptodate);
+
+
+
+
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/raid/hptraid.c linux-2.4.21-pre6/drivers/ide/raid/hptraid.c
--- linux-2.4.20/drivers/ide/raid/hptraid.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/raid/hptraid.c	2003-03-26 23:49:39.000000000 +0000
@@ -0,0 +1,436 @@
+/*
+   hptraid.c  Copyright (C) 2001 Red Hat, Inc. 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, or (at your option)
+   any later version.
+   
+   You should have received a copy of the GNU General Public License
+   (for example /usr/src/linux/COPYING); if not, write to the Free
+   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
+   
+   Authors: 	Arjan van de Ven <arjanv@redhat.com>
+
+   Based on work
+   	Copyleft  (C) 2001 by Wilfried Weissmann <wweissmann@gmx.at>
+	Copyright (C) 1994-96 Marc ZYNGIER <zyngier@ufr-info-p7.ibp.fr>
+   Based on work done by Søren Schmidt for FreeBSD
+
+   
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/kernel.h>
+#include <linux/blkdev.h>
+#include <linux/blkpg.h>
+#include <linux/genhd.h>
+#include <linux/ioctl.h>
+
+#include <linux/ide.h>
+#include <asm/uaccess.h>
+
+#include "ataraid.h"
+
+static int hptraid_open(struct inode * inode, struct file * filp);
+static int hptraid_release(struct inode * inode, struct file * filp);
+static int hptraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+static int hptraid_make_request (request_queue_t *q, int rw, struct buffer_head * bh);
+
+
+
+struct hptdisk {
+	kdev_t	device;
+	unsigned long sectors;
+	struct block_device *bdev;
+};
+
+struct hptraid {
+	unsigned int stride;
+	unsigned int disks;
+	unsigned long sectors;
+	struct geom geom;
+	
+	struct hptdisk disk[8];
+	
+	unsigned long cutoff[8];
+	unsigned int cutoff_disks[8];	
+};
+
+static struct raid_device_operations hptraid_ops = {
+	open:                   hptraid_open,
+	release:                hptraid_release,
+	ioctl:			hptraid_ioctl,
+	make_request:		hptraid_make_request
+};
+
+static struct hptraid raid[16];
+
+static int hptraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	unsigned int minor;
+	unsigned char val;
+	unsigned long sectors;
+	
+	if (!inode || !inode->i_rdev) 	
+		return -EINVAL;
+
+	minor = MINOR(inode->i_rdev)>>SHIFT;
+	
+	switch (cmd) {
+         	case BLKGETSIZE:   /* Return device size */
+			if (!arg)  return -EINVAL;
+			sectors = ataraid_gendisk.part[MINOR(inode->i_rdev)].nr_sects;
+			if (MINOR(inode->i_rdev)&15)
+				return put_user(sectors, (unsigned long *) arg);
+			return put_user(raid[minor].sectors , (unsigned long *) arg);
+			break;
+			
+
+		case HDIO_GETGEO:
+		{
+			struct hd_geometry *loc = (struct hd_geometry *) arg;
+			unsigned short bios_cyl;
+			
+			if (!loc) return -EINVAL;
+			val = 255;
+			if (put_user(val, (byte *) &loc->heads)) return -EFAULT;
+			val=63;
+			if (put_user(val, (byte *) &loc->sectors)) return -EFAULT;
+			bios_cyl = raid[minor].sectors/63/255;
+			if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT;
+			if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
+				(unsigned long *) &loc->start)) return -EFAULT;
+			return 0;
+		}
+
+		case HDIO_GETGEO_BIG:
+		{
+			struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
+			unsigned int bios_cyl;
+			if (!loc) return -EINVAL;
+			val = 255;
+			if (put_user(val, (byte *) &loc->heads)) return -EFAULT;
+			val = 63;
+			if (put_user(val, (byte *) &loc->sectors)) return -EFAULT;
+			bios_cyl = raid[minor].sectors/63/255;
+			if (put_user(bios_cyl, (unsigned int *) &loc->cylinders)) return -EFAULT;
+			if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
+				(unsigned long *) &loc->start)) return -EFAULT;
+			return 0;
+		}
+			
+		default:
+			return blk_ioctl(inode->i_rdev, cmd, arg);
+	};
+
+	return 0;
+}
+
+
+static int hptraid_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
+{
+	unsigned long rsect;
+	unsigned long rsect_left,rsect_accum = 0;
+	unsigned long block;
+	unsigned int disk=0,real_disk=0;
+	int i;
+	int device;
+	struct hptraid *thisraid;
+
+	rsect = bh->b_rsector;
+
+	/* Ok. We need to modify this sector number to a new disk + new sector number. 
+	 * If there are disks of different sizes, this gets tricky. 
+	 * Example with 3 disks (1Gb, 4Gb and 5 GB):
+	 * The first 3 Gb of the "RAID" are evenly spread over the 3 disks.
+	 * Then things get interesting. The next 2Gb (RAID view) are spread across disk 2 and 3
+	 * and the last 1Gb is disk 3 only.
+	 *
+	 * the way this is solved is like this: We have a list of "cutoff" points where everytime
+	 * a disk falls out of the "higher" count, we mark the max sector. So once we pass a cutoff
+	 * point, we have to divide by one less.
+	 */
+	
+	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
+	thisraid = &raid[device];
+	if (thisraid->stride==0)
+		thisraid->stride=1;
+
+	/* Partitions need adding of the start sector of the partition to the requested sector */
+	
+	rsect += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect;
+
+	/* Woops we need to split the request to avoid crossing a stride barrier */
+	if ((rsect/thisraid->stride) != ((rsect+(bh->b_size/512)-1)/thisraid->stride)) {
+		return -1;
+	}
+			
+	rsect_left = rsect;
+	
+	for (i=0;i<8;i++) {
+		if (thisraid->cutoff_disks[i]==0)
+			break;
+		if (rsect > thisraid->cutoff[i]) {
+			/* we're in the wrong area so far */
+			rsect_left -= thisraid->cutoff[i];
+			rsect_accum += thisraid->cutoff[i]/thisraid->cutoff_disks[i];
+		} else {
+			block = rsect_left / thisraid->stride;
+			disk = block % thisraid->cutoff_disks[i];
+			block = (block / thisraid->cutoff_disks[i]) * thisraid->stride;
+			rsect = rsect_accum + (rsect_left % thisraid->stride) + block;
+			break;
+		}
+	}
+	
+	for (i=0;i<8;i++) {
+		if ((disk==0) && (thisraid->disk[i].sectors > rsect_accum)) {
+			real_disk = i;
+			break;
+		}
+		if ((disk>0) && (thisraid->disk[i].sectors >= rsect_accum)) {
+			disk--;
+		}
+		
+	}
+	disk = real_disk;
+	
+	/* All but the first disk have a 10 sector offset */
+	if (i>0)
+		rsect+=10;
+		
+	
+	/*
+	 * The new BH_Lock semantics in ll_rw_blk.c guarantee that this
+	 * is the only IO operation happening on this bh.
+	 */
+	 
+	bh->b_rdev = thisraid->disk[disk].device;
+	bh->b_rsector = rsect;
+
+	/*
+	 * Let the main block layer submit the IO and resolve recursion:
+	 */
+	return 1;
+}
+
+
+#include "hptraid.h"
+
+static int read_disk_sb (int major, int minor, unsigned char *buffer,int bufsize)
+{
+	int ret = -EINVAL;
+	struct buffer_head *bh = NULL;
+	kdev_t dev = MKDEV(major,minor);
+	
+	if (blksize_size[major]==NULL)	 /* device doesn't exist */
+		return -EINVAL;
+	
+
+	/* Superblock is at 4096+412 bytes */
+	set_blocksize (dev, 4096);
+	bh = bread (dev, 1, 4096);
+
+	
+	if (bh) {
+		memcpy (buffer, bh->b_data, bufsize);
+	} else {
+		printk(KERN_ERR "hptraid: Error reading superblock.\n");
+		goto abort;
+	}
+	ret = 0;
+abort:
+	if (bh)
+		brelse (bh);
+	return ret;
+}
+
+static unsigned long maxsectors (int major,int minor)
+{
+	unsigned long lba = 0;
+	kdev_t dev;
+	ide_drive_t *ideinfo;
+	
+	dev = MKDEV(major,minor);
+	ideinfo = get_info_ptr (dev);
+	if (ideinfo==NULL)
+		return 0;
+	
+	
+	/* first sector of the last cluster */
+	if (ideinfo->head==0) 
+		return 0;
+	if (ideinfo->sect==0)
+		return 0;
+	lba = (ideinfo->capacity);
+
+	return lba;
+}
+
+static void __init probedisk(int major, int minor,int device)
+{
+	int i;
+        struct highpoint_raid_conf *prom;
+	static unsigned char block[4096];
+	struct block_device *bdev;
+	
+	if (maxsectors(major,minor)==0)
+		return;
+	
+        if (read_disk_sb(major,minor,(unsigned char*)&block,sizeof(block)))
+        	return;
+                                                                                                                 
+        prom = (struct highpoint_raid_conf*)&block[512];
+                
+        if (prom->magic!=  0x5a7816f0)
+        	return;
+        if (prom->type) {
+        	printk(KERN_INFO "hptraid: only RAID0 is supported currently\n");
+        	return;
+        }
+
+	i = prom->disk_number;
+	if (i<0)
+		return;
+	if (i>8) 
+		return;
+
+	bdev = bdget(MKDEV(major,minor));
+	if (bdev && blkdev_get(bdev,FMODE_READ|FMODE_WRITE,0,BDEV_RAW) == 0) {
+        	int j=0;
+        	struct gendisk *gd;
+		raid[device].disk[i].bdev = bdev;
+        	/* This is supposed to prevent others from stealing our underlying disks */
+		/* now blank the /proc/partitions table for the wrong partition table,
+		   so that scripts don't accidentally mount it and crash the kernel */
+		 /* XXX: the 0 is an utter hack  --hch */
+		gd=get_gendisk(MKDEV(major, 0));
+		if (gd!=NULL) {
+			for (j=1+(minor<<gd->minor_shift);j<((minor+1)<<gd->minor_shift);j++) 
+				gd->part[j].nr_sects=0;					
+		}
+        }
+	raid[device].disk[i].device = MKDEV(major,minor);
+	raid[device].disk[i].sectors = maxsectors(major,minor);
+	raid[device].stride = (1<<prom->raid0_shift);
+	raid[device].disks = prom->raid_disks;
+	raid[device].sectors = prom->total_secs;
+			
+}
+
+static void __init fill_cutoff(int device)
+{
+	int i,j;
+	unsigned long smallest;
+	unsigned long bar;
+	int count;
+	
+	bar = 0;
+	for (i=0;i<8;i++) {
+		smallest = ~0;
+		for (j=0;j<8;j++) 
+			if ((raid[device].disk[j].sectors < smallest) && (raid[device].disk[j].sectors>bar))
+				smallest = raid[device].disk[j].sectors;
+		count = 0;
+		for (j=0;j<8;j++) 
+			if (raid[device].disk[j].sectors >= smallest)
+				count++;
+		
+		smallest = smallest * count;		
+		bar = smallest;
+		raid[device].cutoff[i] = smallest;
+		raid[device].cutoff_disks[i] = count;
+		
+	}
+}
+
+
+static __init int hptraid_init_one(int device)
+{
+	int i,count;
+
+	probedisk(IDE0_MAJOR,  0, device);
+	probedisk(IDE0_MAJOR, 64, device);
+	probedisk(IDE1_MAJOR,  0, device);
+	probedisk(IDE1_MAJOR, 64, device);
+	probedisk(IDE2_MAJOR,  0, device);
+	probedisk(IDE2_MAJOR, 64, device);
+	probedisk(IDE3_MAJOR,  0, device);
+	probedisk(IDE3_MAJOR, 64, device);
+	probedisk(IDE4_MAJOR,  0, device);
+	probedisk(IDE4_MAJOR, 64, device);
+	probedisk(IDE5_MAJOR,  0, device);
+	probedisk(IDE5_MAJOR, 64, device);
+
+	fill_cutoff(device);
+	
+	/* Initialize the gendisk structure */
+	
+	ataraid_register_disk(device,raid[device].sectors);
+
+	count=0;
+	printk(KERN_INFO "Highpoint HPT370 Softwareraid driver for linux version 0.01\n");
+		
+	for (i=0;i<8;i++) {
+		if (raid[device].disk[i].device!=0) {
+			printk(KERN_INFO "Drive %i is %li Mb \n",
+				i,raid[device].disk[i].sectors/2048);
+			count++;
+		}
+	}
+	if (count) {
+		printk(KERN_INFO "Raid array consists of %i drives. \n",count);
+		return 0;
+	} else {
+		printk(KERN_INFO "No raid array found\n");
+		return -ENODEV;
+	}
+	
+}
+
+static __init int hptraid_init(void)
+{
+	int retval,device;
+	
+	device=ataraid_get_device(&hptraid_ops);
+	if (device<0)
+		return -ENODEV;
+	retval = hptraid_init_one(device);
+	if (retval)
+		ataraid_release_device(device);
+	return retval;
+}
+
+static void __exit hptraid_exit (void)
+{
+	int i,device;
+	for (device = 0; device<16; device++) {
+		for (i=0;i<8;i++)  {
+			struct block_device *bdev = raid[device].disk[i].bdev;
+			raid[device].disk[i].bdev = NULL;
+			if (bdev)
+				blkdev_put(bdev, BDEV_RAW);
+		}       
+		if (raid[device].sectors)
+			ataraid_release_device(device);
+	}
+}
+
+static int hptraid_open(struct inode * inode, struct file * filp) 
+{
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+static int hptraid_release(struct inode * inode, struct file * filp)
+{	
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+module_init(hptraid_init);
+module_exit(hptraid_exit);
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/raid/hptraid.h linux-2.4.21-pre6/drivers/ide/raid/hptraid.h
--- linux-2.4.20/drivers/ide/raid/hptraid.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/raid/hptraid.h	2003-03-26 23:49:40.000000000 +0000
@@ -0,0 +1,77 @@
+/*-
+ * Copyright (c) 2000,2001 Søren Schmidt <sos@FreeBSD.org>
+ * 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, this list of conditions and the following disclaimer,
+ *    without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `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.
+ *
+ */
+                            
+struct highpoint_raid_conf
+{
+       int8_t  filler1[32];
+       u_int32_t       magic;
+#define HPT_MAGIC_OK   0x5a7816f0
+#define HPT_MAGIC_BAD  0x5a7816fd  
+
+       u_int32_t       magic_0;
+       u_int32_t       magic_1;
+       u_int32_t       order;  
+#define HPT_O_MIRROR   0x01  
+#define HPT_O_STRIPE   0x02
+#define HPT_O_OK       0x04
+
+       u_int8_t        raid_disks;
+       u_int8_t        raid0_shift; 
+       u_int8_t        type;
+#define HPT_T_RAID_0   0x00 
+#define HPT_T_RAID_1   0x01
+#define HPT_T_RAID_01_RAID_0   0x02
+#define HPT_T_SPAN             0x03
+#define HPT_T_RAID_3           0x04   
+#define HPT_T_RAID_5           0x05
+#define HPT_T_SINGLEDISK       0x06
+#define HPT_T_RAID_01_RAID_1   0x07
+
+       u_int8_t        disk_number;
+       u_int32_t       total_secs; 
+       u_int32_t       disk_mode;  
+       u_int32_t       boot_mode;
+       u_int8_t        boot_disk; 
+       u_int8_t        boot_protect;
+       u_int8_t        error_log_entries;
+       u_int8_t        error_log_index;  
+       struct
+       {
+               u_int32_t       timestamp;
+               u_int8_t        reason;   
+#define HPT_R_REMOVED          0xfe      
+#define HPT_R_BROKEN           0xff      
+
+               u_int8_t        disk;
+               u_int8_t        status;
+               u_int8_t        sectors;
+               u_int32_t       lba;
+       } errorlog[32];
+       u_int8_t        filler[60];
+};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/raid/pdcraid.c linux-2.4.21-pre6/drivers/ide/raid/pdcraid.c
--- linux-2.4.20/drivers/ide/raid/pdcraid.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/raid/pdcraid.c	2003-03-26 23:49:35.000000000 +0000
@@ -0,0 +1,609 @@
+/*
+   pdcraid.c  Copyright (C) 2001 Red Hat, Inc. 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, or (at your option)
+   any later version.
+   
+   You should have received a copy of the GNU General Public License
+   (for example /usr/src/linux/COPYING); if not, write to the Free
+   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
+   
+   Authors: 	Arjan van de Ven <arjanv@redhat.com>
+   		
+   Based on work done by Søren Schmidt for FreeBSD  
+
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/blkdev.h>
+#include <linux/blkpg.h>
+#include <linux/genhd.h>
+#include <linux/ioctl.h>
+
+#include <linux/ide.h>
+#include <asm/uaccess.h>
+
+#include "ataraid.h"
+
+static int pdcraid_open(struct inode * inode, struct file * filp);
+static int pdcraid_release(struct inode * inode, struct file * filp);
+static int pdcraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+static int pdcraid0_make_request (request_queue_t *q, int rw, struct buffer_head * bh);
+static int pdcraid1_make_request (request_queue_t *q, int rw, struct buffer_head * bh);
+
+struct disk_dev {
+	int major;
+	int minor;
+	int device;
+};
+
+static struct disk_dev devlist[]= {
+	{IDE0_MAJOR,  0,  -1 },
+	{IDE0_MAJOR, 64,  -1 },
+	{IDE1_MAJOR,  0,  -1 },
+	{IDE1_MAJOR, 64,  -1 },
+	{IDE2_MAJOR,  0,  -1 },
+	{IDE2_MAJOR, 64,  -1 },
+	{IDE3_MAJOR,  0,  -1 },
+	{IDE3_MAJOR, 64,  -1 },
+	{IDE4_MAJOR,  0,  -1 },
+	{IDE4_MAJOR, 64,  -1 },
+	{IDE5_MAJOR,  0,  -1 },
+	{IDE5_MAJOR, 64,  -1 },
+	{IDE6_MAJOR,  0,  -1 },
+	{IDE6_MAJOR, 64,  -1 },
+};
+
+
+struct pdcdisk {
+	kdev_t	device;
+	unsigned long sectors;
+	struct block_device *bdev;
+	unsigned long last_pos;
+};
+
+struct pdcraid {
+	unsigned int stride;
+	unsigned int disks;
+	unsigned long sectors;
+	struct geom geom;
+	
+	struct pdcdisk disk[8];
+	
+	unsigned long cutoff[8];
+	unsigned int cutoff_disks[8];
+};
+
+static struct raid_device_operations pdcraid0_ops = {
+        open:                   pdcraid_open,
+	release:                pdcraid_release,
+	ioctl:			pdcraid_ioctl,
+	make_request:		pdcraid0_make_request
+};
+
+static struct raid_device_operations pdcraid1_ops = {
+        open:                   pdcraid_open,
+	release:                pdcraid_release,
+	ioctl:			pdcraid_ioctl,
+	make_request:		pdcraid1_make_request
+};
+
+static struct pdcraid raid[16];
+
+
+static int pdcraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	unsigned int minor;
+   	unsigned long sectors;
+
+	if (!inode || !inode->i_rdev) 
+		return -EINVAL;
+
+	minor = MINOR(inode->i_rdev)>>SHIFT;
+	
+	switch (cmd) {
+
+         	case BLKGETSIZE:   /* Return device size */
+ 			if (!arg)  return -EINVAL;
+			sectors = ataraid_gendisk.part[MINOR(inode->i_rdev)].nr_sects;
+			if (MINOR(inode->i_rdev)&15)
+				return put_user(sectors, (unsigned long *) arg);
+			return put_user(raid[minor].sectors , (unsigned long *) arg);
+			break;
+			
+
+		case HDIO_GETGEO:
+		{
+			struct hd_geometry *loc = (struct hd_geometry *) arg;
+			unsigned short bios_cyl = raid[minor].geom.cylinders; /* truncate */
+			
+			if (!loc) return -EINVAL;
+			if (put_user(raid[minor].geom.heads, (byte *) &loc->heads)) return -EFAULT;
+			if (put_user(raid[minor].geom.sectors, (byte *) &loc->sectors)) return -EFAULT;
+			if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT;
+			if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
+				(unsigned long *) &loc->start)) return -EFAULT;
+			return 0;
+		}
+
+		case HDIO_GETGEO_BIG:
+		{
+			struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
+			if (!loc) return -EINVAL;
+			if (put_user(raid[minor].geom.heads, (byte *) &loc->heads)) return -EFAULT;
+			if (put_user(raid[minor].geom.sectors, (byte *) &loc->sectors)) return -EFAULT;
+			if (put_user(raid[minor].geom.cylinders, (unsigned int *) &loc->cylinders)) return -EFAULT;
+			if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
+				(unsigned long *) &loc->start)) return -EFAULT;
+			return 0;
+		}
+
+			
+		case BLKROSET:
+		case BLKROGET:
+		case BLKSSZGET:
+			return blk_ioctl(inode->i_rdev, cmd, arg);
+
+		default:
+			printk("Invalid ioctl \n");
+			return -EINVAL;
+	};
+
+	return 0;
+}
+
+
+static unsigned long partition_map_normal(unsigned long block, unsigned long partition_off, unsigned long partition_size, int stride)
+{
+	return block + partition_off;
+}
+
+static int pdcraid0_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
+{
+	unsigned long rsect;
+	unsigned long rsect_left,rsect_accum = 0;
+	unsigned long block;
+	unsigned int disk=0,real_disk=0;
+	int i;
+	int device;
+	struct pdcraid *thisraid;
+
+	rsect = bh->b_rsector;
+	
+	/* Ok. We need to modify this sector number to a new disk + new sector number. 
+	 * If there are disks of different sizes, this gets tricky. 
+	 * Example with 3 disks (1Gb, 4Gb and 5 GB):
+	 * The first 3 Gb of the "RAID" are evenly spread over the 3 disks.
+	 * Then things get interesting. The next 2Gb (RAID view) are spread across disk 2 and 3
+	 * and the last 1Gb is disk 3 only.
+	 *
+	 * the way this is solved is like this: We have a list of "cutoff" points where everytime
+	 * a disk falls out of the "higher" count, we mark the max sector. So once we pass a cutoff
+	 * point, we have to divide by one less.
+	 */
+	
+	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
+	thisraid = &raid[device];
+	if (thisraid->stride==0)
+		thisraid->stride=1;
+
+	/* Partitions need adding of the start sector of the partition to the requested sector */
+	
+	rsect = partition_map_normal(rsect, ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect, ataraid_gendisk.part[MINOR(bh->b_rdev)].nr_sects, thisraid->stride);
+
+	/* Woops we need to split the request to avoid crossing a stride barrier */
+	if ((rsect/thisraid->stride) != ((rsect+(bh->b_size/512)-1)/thisraid->stride)) {
+		return -1;  
+	}
+	
+	rsect_left = rsect;
+	
+	for (i=0;i<8;i++) {
+		if (thisraid->cutoff_disks[i]==0)
+			break;
+		if (rsect > thisraid->cutoff[i]) {
+			/* we're in the wrong area so far */
+			rsect_left -= thisraid->cutoff[i];
+			rsect_accum += thisraid->cutoff[i]/thisraid->cutoff_disks[i];
+		} else {
+			block = rsect_left / thisraid->stride;
+			disk = block % thisraid->cutoff_disks[i];
+			block = (block / thisraid->cutoff_disks[i]) * thisraid->stride;
+			rsect = rsect_accum + (rsect_left % thisraid->stride) + block;
+			break;
+		}
+	}
+	
+	for (i=0;i<8;i++) {
+		if ((disk==0) && (thisraid->disk[i].sectors > rsect_accum)) {
+			real_disk = i;
+			break;
+		}
+		if ((disk>0) && (thisraid->disk[i].sectors >= rsect_accum)) {
+			disk--;
+		}
+		
+	}
+	disk = real_disk;
+		
+	
+	/*
+	 * The new BH_Lock semantics in ll_rw_blk.c guarantee that this
+	 * is the only IO operation happening on this bh.
+	 */
+	bh->b_rdev = thisraid->disk[disk].device;
+	bh->b_rsector = rsect;
+
+	/*
+	 * Let the main block layer submit the IO and resolve recursion:
+	 */
+	return 1;
+}
+
+static int pdcraid1_write_request(request_queue_t *q, int rw, struct buffer_head * bh)
+{
+	struct buffer_head *bh1;
+	struct ataraid_bh_private *private;
+	int device;
+	int i;
+
+	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
+	private = ataraid_get_private();
+	if (private==NULL)
+		BUG();
+
+	private->parent = bh;
+	
+	atomic_set(&private->count,raid[device].disks);
+
+
+	for (i = 0; i< raid[device].disks; i++) { 
+		bh1=ataraid_get_bhead();
+		/* If this ever fails we're doomed */
+		if (!bh1)
+			BUG();
+	
+		/* dupe the bufferhead and update the parts that need to be different */
+		memcpy(bh1, bh, sizeof(*bh));
+		
+		bh1->b_end_io = ataraid_end_request;
+		bh1->b_private = private;
+		bh1->b_rsector += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect; /* partition offset */
+		bh1->b_rdev = raid[device].disk[i].device;
+
+		/* update the last known head position for the drive */
+		raid[device].disk[i].last_pos = bh1->b_rsector+(bh1->b_size>>9);
+
+		generic_make_request(rw,bh1);
+	}
+	return 0;
+}
+
+static int pdcraid1_read_request (request_queue_t *q, int rw, struct buffer_head * bh)
+{
+	int device;
+	int dist;
+	int bestsofar,bestdist,i;
+	static int previous;
+
+	/* Reads are simple in principle. Pick a disk and go. 
+	   Initially I cheat by just picking the one which the last known
+	   head position is closest by.
+	   Later on, online/offline checking and performance needs adding */
+	
+	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
+	bh->b_rsector += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect;
+
+	bestsofar = 0; 
+	bestdist = raid[device].disk[0].last_pos - bh->b_rsector;
+	if (bestdist<0) 
+		bestdist=-bestdist;
+	if (bestdist>4095)
+		bestdist=4095;
+
+	for (i=1 ; i<raid[device].disks; i++) {
+		dist = raid[device].disk[i].last_pos - bh->b_rsector;
+		if (dist<0) 
+			dist = -dist;
+		if (dist>4095)
+			dist=4095;
+		
+		if (bestdist==dist) {  /* it's a tie; try to do some read balancing */
+			if ((previous>bestsofar)&&(previous<=i))  
+				bestsofar = i;
+			previous = (previous + 1) % raid[device].disks;
+		} else if (bestdist>dist) {
+			bestdist = dist;
+			bestsofar = i;
+		}
+	
+	}
+	
+	bh->b_rdev = raid[device].disk[bestsofar].device; 
+	raid[device].disk[bestsofar].last_pos = bh->b_rsector+(bh->b_size>>9);
+
+	/*
+	 * Let the main block layer submit the IO and resolve recursion:
+	 */
+                          	
+	return 1;
+}
+
+
+static int pdcraid1_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
+{
+	/* Read and Write are totally different cases; split them totally here */
+	if (rw==READA)
+		rw = READ;
+	
+	if (rw==READ)
+		return pdcraid1_read_request(q,rw,bh);
+	else
+		return pdcraid1_write_request(q,rw,bh);
+}
+
+#include "pdcraid.h"
+
+static unsigned long calc_pdcblock_offset (int major,int minor)
+{
+	unsigned long lba = 0;
+	kdev_t dev;
+	ide_drive_t *ideinfo;
+	
+	dev = MKDEV(major,minor);
+	ideinfo = get_info_ptr (dev);
+	if (ideinfo==NULL)
+		return 0;
+	
+	
+	/* first sector of the last cluster */
+	if (ideinfo->head==0) 
+		return 0;
+	if (ideinfo->sect==0)
+		return 0;
+	lba = (ideinfo->capacity / (ideinfo->head*ideinfo->sect));
+	lba = lba * (ideinfo->head*ideinfo->sect);
+	lba = lba - ideinfo->sect;
+
+	return lba;
+}
+
+
+static int read_disk_sb (int major, int minor, unsigned char *buffer,int bufsize)
+{
+	int ret = -EINVAL;
+	struct buffer_head *bh = NULL;
+	kdev_t dev = MKDEV(major,minor);
+	unsigned long sb_offset;
+
+	if (blksize_size[major]==NULL)   /* device doesn't exist */
+		return -EINVAL;
+                       
+	
+	/*
+	 * Calculate the position of the superblock,
+	 * it's at first sector of the last cylinder
+	 */
+	sb_offset = calc_pdcblock_offset(major,minor)/8;
+	/* The /8 transforms sectors into 4Kb blocks */
+
+	if (sb_offset==0)
+		return -1;	
+	
+	set_blocksize (dev, 4096);
+
+	bh = bread (dev, sb_offset, 4096);
+	
+	if (bh) {
+		memcpy (buffer, bh->b_data, bufsize);
+	} else {
+		printk(KERN_ERR "pdcraid: Error reading superblock.\n");
+		goto abort;
+	}
+	ret = 0;
+abort:
+	if (bh)
+		brelse (bh);
+	return ret;
+}
+
+static unsigned int calc_sb_csum (unsigned int* ptr)
+{	
+	unsigned int sum;
+	int count;
+	
+	sum = 0;
+	for (count=0;count<511;count++)
+		sum += *ptr++;
+	
+	return sum;
+}
+
+static int cookie = 0;
+
+static void __init probedisk(int devindex,int device, int raidlevel)
+{
+	int i;
+	int major, minor;
+        struct promise_raid_conf *prom;
+	static unsigned char block[4096];
+	struct block_device *bdev;
+
+	if (devlist[devindex].device!=-1) /* already assigned to another array */
+		return;
+	
+	major = devlist[devindex].major;
+	minor = devlist[devindex].minor; 
+
+        if (read_disk_sb(major,minor,(unsigned char*)&block,sizeof(block)))
+        	return;
+                                                                                                                 
+        prom = (struct promise_raid_conf*)&block[512];
+
+        /* the checksums must match */
+	if (prom->checksum != calc_sb_csum((unsigned int*)prom))
+		return;
+	if (prom->raid.type!=raidlevel) /* different raidlevel */
+		return;
+
+	if ((cookie!=0) && (cookie != prom->raid.magic_1)) /* different array */
+		return;
+	
+	cookie = prom->raid.magic_1;
+
+	/* This looks evil. But basically, we have to search for our adapternumber
+	   in the arraydefinition, both of which are in the superblock */	
+        for (i=0;(i<prom->raid.total_disks)&&(i<8);i++) {
+        	if ( (prom->raid.disk[i].channel== prom->raid.channel) &&
+        	     (prom->raid.disk[i].device == prom->raid.device) ) {
+
+        	        bdev = bdget(MKDEV(major,minor));
+        	        if (bdev && blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_RAW) == 0) {
+				raid[device].disk[i].bdev = bdev;
+			}
+			raid[device].disk[i].device = MKDEV(major,minor);
+			raid[device].disk[i].sectors = prom->raid.disk_secs;
+			raid[device].stride = (1<<prom->raid.raid0_shift);
+			raid[device].disks = prom->raid.total_disks;
+			raid[device].sectors = prom->raid.total_secs;
+			raid[device].geom.heads = prom->raid.heads+1;
+			raid[device].geom.sectors = prom->raid.sectors;
+			raid[device].geom.cylinders = prom->raid.cylinders+1;
+			devlist[devindex].device=device;
+        	     }
+        }
+	               
+}
+
+static void __init fill_cutoff(int device)
+{
+	int i,j;
+	unsigned long smallest;
+	unsigned long bar;
+	int count;
+	
+	bar = 0;
+	for (i=0;i<8;i++) {
+		smallest = ~0;
+		for (j=0;j<8;j++) 
+			if ((raid[device].disk[j].sectors < smallest) && (raid[device].disk[j].sectors>bar))
+				smallest = raid[device].disk[j].sectors;
+		count = 0;
+		for (j=0;j<8;j++) 
+			if (raid[device].disk[j].sectors >= smallest)
+				count++;
+				
+		smallest = smallest * count;
+		bar = smallest;
+		raid[device].cutoff[i] = smallest;
+		raid[device].cutoff_disks[i] = count;
+	}
+}
+			   
+static __init int pdcraid_init_one(int device,int raidlevel)
+{
+	int i, count;
+
+	for (i=0; i<14; i++)
+		probedisk(i, device, raidlevel);
+	
+	if (raidlevel==0)
+		fill_cutoff(device);
+	
+	/* Initialize the gendisk structure */
+	
+	ataraid_register_disk(device,raid[device].sectors);        
+		
+	count=0;
+	
+	for (i=0;i<8;i++) {
+		if (raid[device].disk[i].device!=0) {
+			printk(KERN_INFO "Drive %i is %li Mb (%i / %i) \n",
+				i,raid[device].disk[i].sectors/2048,MAJOR(raid[device].disk[i].device),MINOR(raid[device].disk[i].device));
+			count++;
+		}
+	}
+	if (count) {
+		printk(KERN_INFO "Raid%i array consists of %i drives. \n",raidlevel,count);
+		return 0;
+	} else {
+		return -ENODEV;
+	}
+}
+
+static __init int pdcraid_init(void)
+{
+	int retval, device, count = 0;
+
+	do {
+		cookie = 0;
+		device=ataraid_get_device(&pdcraid0_ops);
+		if (device<0)
+			break;
+		retval = pdcraid_init_one(device,0);
+		if (retval) {
+			ataraid_release_device(device);
+			break;
+		} else {
+			count++;
+		}
+	} while (1);
+
+	do {
+	
+		cookie = 0;
+		device=ataraid_get_device(&pdcraid1_ops);
+		if (device<0)
+			break;
+		retval = pdcraid_init_one(device,1);
+		if (retval) {
+			ataraid_release_device(device);
+			break;
+		} else {
+			count++;
+		}
+	} while (1);
+
+	if (count) {
+		printk(KERN_INFO "Promise Fasttrak(tm) Softwareraid driver for linux version 0.03beta\n");
+		return 0;
+	}
+	printk(KERN_DEBUG "Promise Fasttrak(tm) Softwareraid driver 0.03beta: No raid array found\n");
+	return -ENODEV;
+}
+
+static void __exit pdcraid_exit (void)
+{
+	int i,device;
+	for (device = 0; device<16; device++) {
+		for (i=0;i<8;i++) {
+			struct block_device *bdev = raid[device].disk[i].bdev;
+			raid[device].disk[i].bdev = NULL;
+			if (bdev)
+				blkdev_put(bdev, BDEV_RAW);
+		}	
+		if (raid[device].sectors)
+			ataraid_release_device(device);
+	}
+}
+
+static int pdcraid_open(struct inode * inode, struct file * filp) 
+{
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+static int pdcraid_release(struct inode * inode, struct file * filp)
+{	
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+module_init(pdcraid_init);
+module_exit(pdcraid_exit);
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/raid/pdcraid.h linux-2.4.21-pre6/drivers/ide/raid/pdcraid.h
--- linux-2.4.20/drivers/ide/raid/pdcraid.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/raid/pdcraid.h	2003-03-26 23:49:19.000000000 +0000
@@ -0,0 +1,47 @@
+struct promise_raid_conf {
+    char                promise_id[24];
+
+    u32             dummy_0;
+    u32             magic_0;
+    u32             dummy_1;
+    u32             magic_1;
+    u16             dummy_2;
+    u8              filler1[470];
+    struct {
+        u32 flags;                          /* 0x200 */
+        u8          dummy_0;
+        u8          disk_number;
+        u8          channel;
+        u8          device;
+        u32         magic_0;
+        u32         dummy_1;
+        u32         dummy_2;                /* 0x210 */
+        u32         disk_secs;
+        u32         dummy_3;
+        u16         dummy_4;
+        u8          status;
+        u8          type;
+        u8        total_disks;            /* 0x220 */
+        u8        raid0_shift;
+        u8        raid0_disks;
+        u8        array_number;
+        u32       total_secs;
+        u16       cylinders;
+        u8        heads;
+        u8        sectors;
+        u32         magic_1;
+        u32         dummy_5;                /* 0x230 */
+        struct {
+            u16     dummy_0;
+            u8      channel;
+            u8      device;
+            u32     magic_0;
+            u32     disk_number;
+        } disk[8];
+    } raid;
+    u32             filler2[346];
+    u32            checksum;
+};
+
+#define PR_MAGIC        "Promise Technology, Inc."
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/raid/silraid.c linux-2.4.21-pre6/drivers/ide/raid/silraid.c
--- linux-2.4.20/drivers/ide/raid/silraid.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/raid/silraid.c	2003-03-26 23:49:18.000000000 +0000
@@ -0,0 +1,487 @@
+/*
+   silraid.c  Copyright (C) 2002 Red Hat, Inc. All rights reserved.
+
+   The contents of this file are subject to the Open Software License version 1.1
+   that can be found at http://www.opensource.org/licenses/osl-1.1.txt and is 
+   included herein by reference. 
+   
+   Alternatively, the contents of this file may be used under the
+   terms of the GNU General Public License version 2 (the "GPL") as 
+   distributed in the kernel source COPYING file, in which
+   case the provisions of the GPL are applicable instead of the
+   above.  If you wish to allow the use of your version of this file
+   only under the terms of the GPL and not to allow others to use
+   your version of this file under the OSL, indicate your decision
+   by deleting the provisions above and replace them with the notice
+   and other provisions required by the GPL.  If you do not delete
+   the provisions above, a recipient may use your version of this
+   file under either the OSL or the GPL.
+   
+   Authors: 	Arjan van de Ven <arjanv@redhat.com>
+   		
+
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/blkdev.h>
+#include <linux/blkpg.h>
+#include <linux/genhd.h>
+#include <linux/ioctl.h>
+
+#include <linux/ide.h>
+#include <asm/uaccess.h>
+
+#include "ataraid.h"
+
+static int silraid_open(struct inode * inode, struct file * filp);
+static int silraid_release(struct inode * inode, struct file * filp);
+static int silraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+static int silraid0_make_request (request_queue_t *q, int rw, struct buffer_head * bh);
+
+struct disk_dev {
+	int major;
+	int minor;
+	int device;
+};
+
+static struct disk_dev devlist[]= {
+	{IDE0_MAJOR,  0,  -1 },
+	{IDE0_MAJOR, 64,  -1 },
+	{IDE1_MAJOR,  0,  -1 },
+	{IDE1_MAJOR, 64,  -1 },
+	{IDE2_MAJOR,  0,  -1 },
+	{IDE2_MAJOR, 64,  -1 },
+	{IDE3_MAJOR,  0,  -1 },
+	{IDE3_MAJOR, 64,  -1 },
+	{IDE4_MAJOR,  0,  -1 },
+	{IDE4_MAJOR, 64,  -1 },
+	{IDE5_MAJOR,  0,  -1 },
+	{IDE5_MAJOR, 64,  -1 },
+	{IDE6_MAJOR,  0,  -1 },
+	{IDE6_MAJOR, 64,  -1 },
+};
+
+
+struct sildisk {
+	kdev_t	device;
+	unsigned long sectors;
+	struct block_device *bdev;
+	unsigned long last_pos;
+};
+
+struct silraid {
+	unsigned int stride;
+	unsigned int disks;
+	unsigned long sectors;
+	struct geom geom;
+	
+	struct sildisk disk[8];
+	
+	unsigned long cutoff[8];
+	unsigned int cutoff_disks[8];
+};
+
+static struct raid_device_operations silraid0_ops = {
+        open:                   silraid_open,
+	release:                silraid_release,
+	ioctl:			silraid_ioctl,
+	make_request:		silraid0_make_request
+};
+
+static struct silraid raid[16];
+
+
+static int silraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	unsigned int minor;
+   	unsigned long sectors;
+
+	if (!inode || !inode->i_rdev) 
+		return -EINVAL;
+
+	minor = MINOR(inode->i_rdev)>>SHIFT;
+	
+	switch (cmd) {
+
+         	case BLKGETSIZE:   /* Return device size */
+ 			if (!arg)  return -EINVAL;
+			sectors = ataraid_gendisk.part[MINOR(inode->i_rdev)].nr_sects;
+			if (MINOR(inode->i_rdev)&15)
+				return put_user(sectors, (unsigned long *) arg);
+			return put_user(raid[minor].sectors , (unsigned long *) arg);
+			break;
+			
+
+		case HDIO_GETGEO:
+		{
+			struct hd_geometry *loc = (struct hd_geometry *) arg;
+			unsigned short bios_cyl = raid[minor].geom.cylinders; /* truncate */
+			
+			if (!loc) return -EINVAL;
+			if (put_user(raid[minor].geom.heads, (byte *) &loc->heads)) return -EFAULT;
+			if (put_user(raid[minor].geom.sectors, (byte *) &loc->sectors)) return -EFAULT;
+			if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT;
+			if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
+				(unsigned long *) &loc->start)) return -EFAULT;
+			return 0;
+		}
+
+		case HDIO_GETGEO_BIG:
+		{
+			struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
+			if (!loc) return -EINVAL;
+			if (put_user(raid[minor].geom.heads, (byte *) &loc->heads)) return -EFAULT;
+			if (put_user(raid[minor].geom.sectors, (byte *) &loc->sectors)) return -EFAULT;
+			if (put_user(raid[minor].geom.cylinders, (unsigned int *) &loc->cylinders)) return -EFAULT;
+			if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
+				(unsigned long *) &loc->start)) return -EFAULT;
+			return 0;
+		}
+
+			
+		case BLKROSET:
+		case BLKROGET:
+		case BLKSSZGET:
+			return blk_ioctl(inode->i_rdev, cmd, arg);
+
+		default:
+			printk("Invalid ioctl \n");
+			return -EINVAL;
+	};
+
+	return 0;
+}
+
+
+static unsigned long partition_map_normal(unsigned long block, unsigned long partition_off, unsigned long partition_size, int stride)
+{
+	return block + partition_off;
+}
+
+static int silraid0_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
+{
+	unsigned long rsect;
+	unsigned long rsect_left,rsect_accum = 0;
+	unsigned long block;
+	unsigned int disk=0,real_disk=0;
+	int i;
+	int device;
+	struct silraid *thisraid;
+
+	rsect = bh->b_rsector;
+	
+	/* Ok. We need to modify this sector number to a new disk + new sector number. 
+	 * If there are disks of different sizes, this gets tricky. 
+	 * Example with 3 disks (1Gb, 4Gb and 5 GB):
+	 * The first 3 Gb of the "RAID" are evenly spread over the 3 disks.
+	 * Then things get interesting. The next 2Gb (RAID view) are spread across disk 2 and 3
+	 * and the last 1Gb is disk 3 only.
+	 *
+	 * the way this is solved is like this: We have a list of "cutoff" points where everytime
+	 * a disk falls out of the "higher" count, we mark the max sector. So once we pass a cutoff
+	 * point, we have to divide by one less.
+	 */
+	
+	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
+	thisraid = &raid[device];
+	if (thisraid->stride==0)
+		thisraid->stride=1;
+
+	/* Partitions need adding of the start sector of the partition to the requested sector */
+	
+	rsect = partition_map_normal(rsect, ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect, ataraid_gendisk.part[MINOR(bh->b_rdev)].nr_sects, thisraid->stride);
+
+	/* Woops we need to split the request to avoid crossing a stride barrier */
+	if ((rsect/thisraid->stride) != ((rsect+(bh->b_size/512)-1)/thisraid->stride)) {
+		return -1;  
+	}
+	
+	rsect_left = rsect;
+	
+	for (i=0;i<8;i++) {
+		if (thisraid->cutoff_disks[i]==0)
+			break;
+		if (rsect > thisraid->cutoff[i]) {
+			/* we're in the wrong area so far */
+			rsect_left -= thisraid->cutoff[i];
+			rsect_accum += thisraid->cutoff[i]/thisraid->cutoff_disks[i];
+		} else {
+			block = rsect_left / thisraid->stride;
+			disk = block % thisraid->cutoff_disks[i];
+			block = (block / thisraid->cutoff_disks[i]) * thisraid->stride;
+			rsect = rsect_accum + (rsect_left % thisraid->stride) + block;
+			break;
+		}
+	}
+	
+	for (i=0;i<8;i++) {
+		if ((disk==0) && (thisraid->disk[i].sectors > rsect_accum)) {
+			real_disk = i;
+			break;
+		}
+		if ((disk>0) && (thisraid->disk[i].sectors >= rsect_accum)) {
+			disk--;
+		}
+		
+	}
+	disk = real_disk;
+		
+	
+	/*
+	 * The new BH_Lock semantics in ll_rw_blk.c guarantee that this
+	 * is the only IO operation happening on this bh.
+	 */
+	bh->b_rdev = thisraid->disk[disk].device;
+	bh->b_rsector = rsect;
+
+	/*
+	 * Let the main block layer submit the IO and resolve recursion:
+	 */
+	return 1;
+}
+
+#include "silraid.h"
+
+static unsigned long calc_silblock_offset (int major,int minor)
+{
+	unsigned long lba = 0, cylinders;
+	kdev_t dev;
+	ide_drive_t *ideinfo;
+	
+	dev = MKDEV(major,minor);
+	ideinfo = get_info_ptr (dev);
+	if (ideinfo==NULL)
+		return 0;
+	
+	
+	/* last sector second to last cylinder */
+	if (ideinfo->head==0) 
+		return 0;
+	if (ideinfo->sect==0)
+		return 0;
+	cylinders = (ideinfo->capacity / (ideinfo->head*ideinfo->sect));
+	lba = (cylinders - 1) * (ideinfo->head*ideinfo->sect);
+	lba = lba - ideinfo->head -1;
+	
+//	return 80417215;  
+	printk("Guestimating sector %li for superblock\n",lba);
+	return lba;
+
+}
+
+
+
+static int read_disk_sb (int major, int minor, unsigned char *buffer,int bufsize)
+{
+	int ret = -EINVAL;
+	struct buffer_head *bh = NULL;
+	kdev_t dev = MKDEV(major,minor);
+	unsigned long sb_offset;
+	
+	if (blksize_size[major]==NULL)   /* device doesn't exist */
+		return -EINVAL;
+                       
+
+	/*
+	 * Calculate the position of the superblock,
+	 * it's at first sector of the last cylinder
+	 */
+	sb_offset = calc_silblock_offset(major,minor)/8;
+	/* The /8 transforms sectors into 4Kb blocks */
+
+	if (sb_offset==0)
+		return -1;	
+	
+	set_blocksize (dev, 4096);
+
+	bh = bread (dev, sb_offset, 4096);
+	
+	if (bh) {
+		memcpy (buffer, bh->b_data, bufsize);
+	} else {
+		printk(KERN_ERR "silraid: Error reading superblock.\n");
+		goto abort;
+	}
+	ret = 0;
+abort:
+	if (bh)
+		brelse (bh); return ret;
+}
+
+static unsigned short checksum1(unsigned short *buffer)
+{
+	int i;
+	int sum = 0;
+	for (i=0; i<0x13f/2; i++)
+		sum += buffer[i];	
+	return (-sum)&0xFFFF;
+}
+
+static int cookie = 0;
+
+static void __init probedisk(int devindex,int device, int raidlevel)
+{
+	int i;
+	int major, minor;
+        struct signature *superblock;
+	static unsigned char block[4096];
+	struct block_device *bdev;
+
+	if (devlist[devindex].device!=-1) /* already assigned to another array */
+		return;
+	
+	major = devlist[devindex].major;
+	minor = devlist[devindex].minor; 
+
+        if (read_disk_sb(major,minor,(unsigned char*)&block,sizeof(block)))
+        	return;
+                                                                                                                 
+        superblock = (struct signature*)&block[4096-512];
+        
+        if (superblock->unknown[0] != 'Z') /* Need better check here */
+        	return;
+        	
+        if (superblock->checksum1 != checksum1((unsigned short*)superblock))
+        	return;  
+        
+        
+
+	if (superblock->raidlevel!=raidlevel) /* different raidlevel */
+		return;
+
+	/* This looks evil. But basically, we have to search for our adapternumber
+	   in the arraydefinition, both of which are in the superblock */	
+	 i = superblock->disk_in_set;
+
+	bdev = bdget(MKDEV(major,minor));
+        if (bdev && blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_RAW) == 0) {
+		raid[device].disk[i].bdev = bdev;
+	}
+	raid[device].disk[i].device = MKDEV(major,minor);
+	raid[device].disk[i].sectors = superblock->thisdisk_sectors; 
+	raid[device].stride = superblock->raid0_sectors_per_stride;
+	raid[device].disks = superblock->disks_in_set;
+	raid[device].sectors = superblock->array_sectors;
+	raid[device].geom.heads = 255;
+	raid[device].geom.sectors = 63;
+	raid[device].geom.cylinders =  raid[device].sectors / raid[device].geom.heads / raid[device].geom.sectors; 
+	
+	devlist[devindex].device=device;
+	               
+}
+
+static void __init fill_cutoff(int device)
+{
+	int i,j;
+	unsigned long smallest;
+	unsigned long bar;
+	int count;
+	
+	bar = 0;
+	for (i=0;i<8;i++) {
+		smallest = ~0;
+		for (j=0;j<8;j++) 
+			if ((raid[device].disk[j].sectors < smallest) && (raid[device].disk[j].sectors>bar))
+				smallest = raid[device].disk[j].sectors;
+		count = 0;
+		for (j=0;j<8;j++) 
+			if (raid[device].disk[j].sectors >= smallest)
+				count++;
+				
+		smallest = smallest * count;
+		bar = smallest;
+		raid[device].cutoff[i] = smallest;
+		raid[device].cutoff_disks[i] = count;
+	}
+}
+			   
+static __init int silraid_init_one(int device,int raidlevel)
+{
+	int i, count;
+
+	for (i=0; i<14; i++) 
+		probedisk(i, device, raidlevel);
+	
+	if (raidlevel==0)
+		fill_cutoff(device);
+	
+	/* Initialize the gendisk structure */
+	
+	ataraid_register_disk(device,raid[device].sectors);        
+		
+	count=0;
+	
+	for (i=0;i<8;i++) {
+		if (raid[device].disk[i].device!=0) {
+			printk(KERN_INFO "Drive %i is %li Mb (%i / %i) \n",
+				i,raid[device].disk[i].sectors/2048,MAJOR(raid[device].disk[i].device),MINOR(raid[device].disk[i].device));
+			count++;
+		}
+	}
+	if (count) {
+		printk(KERN_INFO "Raid%i array consists of %i drives. \n",raidlevel,count);
+		return 0;
+	} else {
+		return -ENODEV;
+	}
+}
+
+static __init int silraid_init(void)
+{
+	int retval, device, count = 0;
+
+	do {
+		cookie = 0;
+		device=ataraid_get_device(&silraid0_ops);
+		if (device<0)
+			break;
+		retval = silraid_init_one(device,0);
+		if (retval) {
+			ataraid_release_device(device);
+			break;
+		} else {
+			count++;
+		}
+	} while (1);
+
+	if (count) {
+		printk(KERN_INFO "driver for Silicon Image(tm) Medley(tm) hardware version 0.0.1\n");
+		return 0;
+	}
+	printk(KERN_DEBUG "driver for Silicon Image(tm) Medley(tm) hardware version 0.0.1: No raid array found\n");
+	return -ENODEV;
+}
+
+static void __exit silraid_exit (void)
+{
+	int i,device;
+	for (device = 0; device<16; device++) {
+		for (i=0;i<8;i++) {
+			struct block_device *bdev = raid[device].disk[i].bdev;
+			raid[device].disk[i].bdev = NULL;
+			if (bdev)
+				blkdev_put(bdev, BDEV_RAW);
+		}	
+		if (raid[device].sectors)
+			ataraid_release_device(device);
+	}
+}
+
+static int silraid_open(struct inode * inode, struct file * filp) 
+{
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+static int silraid_release(struct inode * inode, struct file * filp)
+{	
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+module_init(silraid_init);
+module_exit(silraid_exit);
+MODULE_LICENSE("GPL and additional rights");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/raid/silraid.h linux-2.4.21-pre6/drivers/ide/raid/silraid.h
--- linux-2.4.20/drivers/ide/raid/silraid.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/raid/silraid.h	2003-03-26 23:49:10.000000000 +0000
@@ -0,0 +1,30 @@
+struct signature {
+	char unknown[0x36];  		/* 0x00 to 0x35 */
+	char diskname[32];	     	/* 0x36 to 0x56 */
+	char unknown2[0x6c-86];		/* 0x57 to 0x6B */	
+	unsigned int array_sectors;	/* 0x6C to 0x6F */
+	char unknown2b[8];		/* 0x70 to 0x77 */
+	unsigned int thisdisk_sectors;	/* 0x78 to 0x7B */
+	char unknown2c[0xFF-0x7B];	/* 0x7C to 0xFF */
+	char unknown3[4];		/* 0x100 to 0x103 */
+	unsigned short PCI_DEV_ID;	/* 0x104 and 0x105 */
+	unsigned short PCI_VEND_ID;	/* 0x106 and 0x107 */
+	char unknown4[4];		/* 0x108 to 0x10B */
+	unsigned char seconds;		/* 0x10C */
+	unsigned char minutes;		/* 0x10D */
+	unsigned char hour;		/* 0x10E */
+	unsigned char day;		/* 0x10F */
+	unsigned char month;		/* 0x110 */
+	unsigned char year;		/* 0x111 */
+	unsigned short raid0_sectors_per_stride; /* 0x112 */
+	char unknown6[2];		/* 0x113 - 0x115 */
+	unsigned char disk_in_set;	/* 0x116 */
+	unsigned char raidlevel;	/* 0x117 */
+	unsigned char disks_in_set;	/* 0x118 */
+	char unknown7[0x12a - 0x118];   /* 0x118 - 0x12a */
+	unsigned char idechannel;	/* 0x12b */
+	char unknown8[0x13D-0x12B];	/* 0x12c - 0x13d */
+	unsigned short checksum1;	/* 0x13e and 0x13f */	
+	char assumed_zeros[509-0x13f];
+	unsigned short checksum2;	/* 0x1FE and 0x1FF */
+} __attribute__((packed));
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/rapide.c linux-2.4.21-pre6/drivers/ide/rapide.c
--- linux-2.4.20/drivers/ide/rapide.c	2001-10-11 16:14:32.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/rapide.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,94 +0,0 @@
-/*
- * linux/drivers/ide/rapide.c
- *
- * Copyright (c) 1996-1998 Russell King.
- *
- * Changelog:
- *  08-06-1996	RMK	Created
- *  13-04-1998	RMK	Added manufacturer and product IDs
- */
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/blkdev.h>
-#include <linux/errno.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/ecard.h>
-
-static card_ids __init rapide_cids[] = {
-	{ MANU_YELLOWSTONE, PROD_YELLOWSTONE_RAPIDE32 },
-	{ 0xffff, 0xffff }
-};
-
-static struct expansion_card *ec[MAX_ECARDS];
-static int result[MAX_ECARDS];
-
-static inline int rapide_register(struct expansion_card *ec)
-{
-	unsigned long port = ecard_address (ec, ECARD_MEMC, 0);
-	hw_regs_t hw;
-
-	int i;
-
-	memset(&hw, 0, sizeof(hw));
-
-	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
-		hw.io_ports[i] = (ide_ioreg_t)port;
-		port += 1 << 4;
-	}
-	hw.io_ports[IDE_CONTROL_OFFSET] = port + 0x206;
-	hw.irq = ec->irq;
-
-	return ide_register_hw(&hw, NULL);
-}
-
-int __init rapide_init(void)
-{
-	int i;
-
-	for (i = 0; i < MAX_ECARDS; i++)
-		ec[i] = NULL;
-
-	ecard_startfind();
-
-	for (i = 0; ; i++) {
-		if ((ec[i] = ecard_find(0, rapide_cids)) == NULL)
-			break;
-
-		ecard_claim(ec[i]);
-		result[i] = rapide_register(ec[i]);
-	}
-	for (i = 0; i < MAX_ECARDS; i++)
-		if (ec[i] && result[i] < 0) {
-			ecard_release(ec[i]);
-			ec[i] = NULL;
-	}
-	return 0;
-}
-
-#ifdef MODULE
-MODULE_LICENSE("GPL");
-
-int init_module (void)
-{
-	return rapide_init();
-}
-
-void cleanup_module (void)
-{
-	int i;
-
-	for (i = 0; i < MAX_ECARDS; i++)
-		if (ec[i]) {
-			unsigned long port;
-			port = ecard_address(ec[i], ECARD_MEMC, 0);
-
-			ide_unregister_port(port, ec[i]->irq, 16);
-			ecard_release(ec[i]);
-			ec[i] = NULL;
-		}
-}
-#endif
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/rz1000.c linux-2.4.21-pre6/drivers/ide/rz1000.c
--- linux-2.4.20/drivers/ide/rz1000.c	2001-05-01 23:05:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/rz1000.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,97 +0,0 @@
-/*
- *  linux/drivers/ide/rz1000.c		Version 0.05	December 8, 1997
- *
- *  Copyright (C) 1995-1998  Linus Torvalds & author (see below)
- */
-
-/*
- *  Principal Author:  mlord@pobox.com (Mark Lord)
- *
- *  See linux/MAINTAINERS for address of current maintainer.
- *
- *  This file provides support for disabling the buggy read-ahead
- *  mode of the RZ1000 IDE chipset, commonly used on Intel motherboards.
- *
- *  Dunno if this fixes both ports, or only the primary port (?).
- */
-
-#undef REALLY_SLOW_IO		/* most systems can safely undef this */
-
-#include <linux/config.h> /* for CONFIG_BLK_DEV_IDEPCI */
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#ifdef CONFIG_BLK_DEV_IDEPCI
-
-void __init ide_init_rz1000 (ide_hwif_t *hwif)	/* called from ide-pci.c */
-{
-	unsigned short reg;
-	struct pci_dev *dev = hwif->pci_dev;
-
-	hwif->chipset = ide_rz1000;
-	if (!pci_read_config_word (dev, 0x40, &reg)
-	 && !pci_write_config_word(dev, 0x40, reg & 0xdfff))
-	{
-		printk("%s: disabled chipset read-ahead (buggy RZ1000/RZ1001)\n", hwif->name);
-	} else {
-		hwif->serialized = 1;
-		hwif->drives[0].no_unmask = 1;
-		hwif->drives[1].no_unmask = 1;
-		printk("%s: serialized, disabled unmasking (buggy RZ1000/RZ1001)\n", hwif->name);
-	}
-}
-
-#else
-
-static void __init init_rz1000 (struct pci_dev *dev, const char *name)
-{
-	unsigned short reg, h;
-
-	if (!pci_read_config_word (dev, PCI_COMMAND, &reg) && !(reg & PCI_COMMAND_IO)) {
-		printk("%s: buggy IDE controller disabled (BIOS)\n", name);
-		return;
-	}
-	if (!pci_read_config_word (dev, 0x40, &reg)
-	 && !pci_write_config_word(dev, 0x40, reg & 0xdfff))
-	{
-		printk("IDE: disabled chipset read-ahead (buggy %s)\n", name);
-	} else {
-		for (h = 0; h < MAX_HWIFS; ++h) {
-			ide_hwif_t *hwif = &ide_hwifs[h];
-			if ((hwif->io_ports[IDE_DATA_OFFSET] == 0x1f0 || hwif->io_ports[IDE_DATA_OFFSET] == 0x170)
-			 && (hwif->chipset == ide_unknown || hwif->chipset == ide_generic))
-			{
-				hwif->chipset = ide_rz1000;
-				hwif->serialized = 1;
-				hwif->drives[0].no_unmask = 1;
-				hwif->drives[1].no_unmask = 1;
-				if (hwif->io_ports[IDE_DATA_OFFSET] == 0x170)
-					hwif->channel = 1;
-				printk("%s: serialized, disabled unmasking (buggy %s)\n", hwif->name, name);
-			}
-		}
-	}
-}
-
-void __init ide_probe_for_rz100x (void)	/* called from ide.c */
-{
-	struct pci_dev *dev = NULL;
-
-	while ((dev = pci_find_device(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000, dev))!=NULL)
-		init_rz1000 (dev, "RZ1000");
-	while ((dev = pci_find_device(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001, dev))!=NULL)
-		init_rz1000 (dev, "RZ1001");
-}
-
-#endif /* CONFIG_BLK_DEV_IDEPCI */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/serverworks.c linux-2.4.21-pre6/drivers/ide/serverworks.c
--- linux-2.4.20/drivers/ide/serverworks.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/serverworks.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,675 +0,0 @@
-/*
- * linux/drivers/ide/serverworks.c		Version 0.3	26 Oct 2001
- *
- * May be copied or modified under the terms of the GNU General Public License
- *
- * Copyright (C) 1998-2000 Michel Aubry
- * Copyright (C) 1998-2000 Andrzej Krzysztofowicz
- * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
- * Portions copyright (c) 2001 Sun Microsystems
- *
- *
- * RCC/ServerWorks IDE driver for Linux
- *
- *   OSB4: `Open South Bridge' IDE Interface (fn 1)
- *         supports UDMA mode 2 (33 MB/s)
- *
- *   CSB5: `Champion South Bridge' IDE Interface (fn 1)
- *         all revisions support UDMA mode 4 (66 MB/s)
- *         revision A2.0 and up support UDMA mode 5 (100 MB/s)
- *
- *         *** The CSB5 does not provide ANY register ***
- *         *** to detect 80-conductor cable presence. ***
- *
- *
- * here's the default lspci:
- *
- * 00:0f.1 IDE interface: ServerWorks: Unknown device 0211 (prog-if 8a [Master SecP PriP])
- *	Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR+ FastB2B-
- *	Status: Cap- 66Mhz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR-
- *	Latency: 255
- *	Region 4: I/O ports at c200
- * 00: 66 11 11 02 05 01 00 02 00 8a 01 01 00 ff 80 00
- * 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 20: 01 c2 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 40: 99 99 99 99 ff ff ff ff 0c 0c 00 00 00 00 00 00
- * 50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- *
- * 00:0f.1 IDE interface: ServerWorks: Unknown device 0212 (rev 92) (prog-if 8a [Master SecP PriP])
- *         Subsystem: ServerWorks: Unknown device 0212
- *         Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B-
- *         Status: Cap- 66Mhz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR-
- *         Latency: 64, cache line size 08
- *         Region 0: I/O ports at 01f0
- *         Region 1: I/O ports at 03f4
- *         Region 2: I/O ports at 0170
- *         Region 3: I/O ports at 0374
- *         Region 4: I/O ports at 08b0
- *         Region 5: I/O ports at 1000
- *
- * 00:0f.1 IDE interface: ServerWorks: Unknown device 0212 (rev 92)
- * 00: 66 11 12 02 05 00 00 02 92 8a 01 01 08 40 80 00
- * 10: f1 01 00 00 f5 03 00 00 71 01 00 00 75 03 00 00
- * 20: b1 08 00 00 01 10 00 00 00 00 00 00 66 11 12 02
- * 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 40: 4f 4f 4f 4f 20 ff ff ff f0 50 44 44 00 00 00 00
- * 50: 00 00 00 00 07 00 44 02 0f 04 03 00 00 00 00 00
- * 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- *
- *
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-#define DISPLAY_SVWKS_TIMINGS	1
-#undef SVWKS_DEBUG_DRIVE_INFO
-
-#if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static struct pci_dev *bmide_dev;
-static byte svwks_revision = 0;
-
-static int svwks_get_info(char *, char **, off_t, int);
-extern int (*svwks_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-extern char *ide_media_verbose(ide_drive_t *);
-
-static int svwks_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	u32 bibma = pci_resource_start(bmide_dev, 4);
-	u32 reg40, reg44;
-	u16 reg48, reg56;
-	u8  reg54, c0=0, c1=0;
-
-	pci_read_config_dword(bmide_dev, 0x40, &reg40);
-	pci_read_config_dword(bmide_dev, 0x44, &reg44);
-	pci_read_config_word(bmide_dev, 0x48, &reg48);
-	pci_read_config_byte(bmide_dev, 0x54, &reg54);
-	pci_read_config_word(bmide_dev, 0x56, &reg56);
-
-        /*
-         * at that point bibma+0x2 et bibma+0xa are byte registers
-         * to investigate:
-         */
-	c0 = inb_p((unsigned short)bibma + 0x02);
-	c1 = inb_p((unsigned short)bibma + 0x0a);
-
-	switch(bmide_dev->device) {
-		case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
-			p += sprintf(p, "\n                            "
-				     "ServerWorks CSB5 Chipset (rev %02x)\n",
-				     svwks_revision);
-			break;
-		case PCI_DEVICE_ID_SERVERWORKS_OSB4IDE:
-			p += sprintf(p, "\n                            "
-				     "ServerWorks OSB4 Chipset (rev %02x)\n",
-				     svwks_revision);
-			break;
-		default:
-			p += sprintf(p, "\n                            "
-				     "ServerWorks %04x Chipset (rev %02x)\n",
-				     bmide_dev->device, svwks_revision);
-			break;
-	}
-
-	p += sprintf(p, "------------------------------- General Status ---------------------------------\n");
-	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
-	p += sprintf(p, "                %sabled                         %sabled\n",
-			(c0&0x80) ? "dis" : " en",
-			(c1&0x80) ? "dis" : " en");
-	p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
-	p += sprintf(p, "DMA enabled:    %s              %s             %s               %s\n",
-			(c0&0x20) ? "yes" : "no ",
-			(c0&0x40) ? "yes" : "no ",
-			(c1&0x20) ? "yes" : "no ",
-			(c1&0x40) ? "yes" : "no " );
-	p += sprintf(p, "UDMA enabled:   %s              %s             %s               %s\n",
-			(reg54 & 0x01) ? "yes" : "no ",
-			(reg54 & 0x02) ? "yes" : "no ",
-			(reg54 & 0x04) ? "yes" : "no ",
-			(reg54 & 0x08) ? "yes" : "no " );
-	p += sprintf(p, "UDMA enabled:   %s                %s               %s                 %s\n",
-			((reg56&0x0005)==0x0005)?"5":
-				((reg56&0x0004)==0x0004)?"4":
-				((reg56&0x0003)==0x0003)?"3":
-				((reg56&0x0002)==0x0002)?"2":
-				((reg56&0x0001)==0x0001)?"1":
-				((reg56&0x000F))?"?":"0",
-			((reg56&0x0050)==0x0050)?"5":
-				((reg56&0x0040)==0x0040)?"4":
-				((reg56&0x0030)==0x0030)?"3":
-				((reg56&0x0020)==0x0020)?"2":
-				((reg56&0x0010)==0x0010)?"1":
-				((reg56&0x00F0))?"?":"0",
-			((reg56&0x0500)==0x0500)?"5":
-				((reg56&0x0400)==0x0400)?"4":
-				((reg56&0x0300)==0x0300)?"3":
-				((reg56&0x0200)==0x0200)?"2":
-				((reg56&0x0100)==0x0100)?"1":
-				((reg56&0x0F00))?"?":"0",
-			((reg56&0x5000)==0x5000)?"5":
-				((reg56&0x4000)==0x4000)?"4":
-				((reg56&0x3000)==0x3000)?"3":
-				((reg56&0x2000)==0x2000)?"2":
-				((reg56&0x1000)==0x1000)?"1":
-				((reg56&0xF000))?"?":"0");
-	p += sprintf(p, "DMA enabled:    %s                %s               %s                 %s\n",
-			((reg44&0x00002000)==0x00002000)?"2":
-				((reg44&0x00002100)==0x00002100)?"1":
-				((reg44&0x00007700)==0x00007700)?"0":
-				((reg44&0x0000FF00)==0x0000FF00)?"X":"?",
-			((reg44&0x00000020)==0x00000020)?"2":
-				((reg44&0x00000021)==0x00000021)?"1":
-				((reg44&0x00000077)==0x00000077)?"0":
-				((reg44&0x000000FF)==0x000000FF)?"X":"?",
-			((reg44&0x20000000)==0x20000000)?"2":
-				((reg44&0x21000000)==0x21000000)?"1":
-				((reg44&0x77000000)==0x77000000)?"0":
-				((reg44&0xFF000000)==0xFF000000)?"X":"?",
-			((reg44&0x00200000)==0x00200000)?"2":
-				((reg44&0x00210000)==0x00210000)?"1":
-				((reg44&0x00770000)==0x00770000)?"0":
-				((reg44&0x00FF0000)==0x00FF0000)?"X":"?");
-
-		p += sprintf(p, "PIO  enabled:   %s                %s               %s                 %s\n",
-			((reg40&0x00002000)==0x00002000)?"4":
-				((reg40&0x00002200)==0x00002200)?"3":
-				((reg40&0x00003400)==0x00003400)?"2":
-				((reg40&0x00004700)==0x00004700)?"1":
-				((reg40&0x00005D00)==0x00005D00)?"0":"?",
-			((reg40&0x00000020)==0x00000020)?"4":
-				((reg40&0x00000022)==0x00000022)?"3":
-				((reg40&0x00000034)==0x00000034)?"2":
-				((reg40&0x00000047)==0x00000047)?"1":
-				((reg40&0x0000005D)==0x0000005D)?"0":"?",
-			((reg40&0x20000000)==0x20000000)?"4":
-				((reg40&0x22000000)==0x22000000)?"3":
-				((reg40&0x34000000)==0x34000000)?"2":
-				((reg40&0x47000000)==0x47000000)?"1":
-				((reg40&0x5D000000)==0x5D000000)?"0":"?",
-			((reg40&0x00200000)==0x00200000)?"4":
-				((reg40&0x00220000)==0x00220000)?"3":
-				((reg40&0x00340000)==0x00340000)?"2":
-				((reg40&0x00470000)==0x00470000)?"1":
-				((reg40&0x005D0000)==0x005D0000)?"0":"?");
-	return p-buffer;	 /* => must be less than 4k! */
-}
-#endif  /* defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-#define SVWKS_CSB5_REVISION_NEW	0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */
-
-byte svwks_proc = 0;
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-static struct pci_dev *isa_dev;
-
-static int svwks_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	byte udma_modes[]	= { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
-	byte dma_modes[]	= { 0x77, 0x21, 0x20 };
-	byte pio_modes[]	= { 0x5d, 0x47, 0x34, 0x22, 0x20 };
-
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte unit		= (drive->select.b.unit & 0x01);
-	byte csb5		= (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ? 1 : 0;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	unsigned long dma_base	= hwif->dma_base;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-	int err;
-
-	byte drive_pci		= 0x00;
-	byte drive_pci2		= 0x00;
-	byte drive_pci3		= hwif->channel ? 0x57 : 0x56;
-
-	byte ultra_enable	= 0x00;
-	byte ultra_timing	= 0x00;
-	byte dma_timing		= 0x00;
-	byte pio_timing		= 0x00;
-	unsigned short csb5_pio	= 0x00;
-
-	byte pio	= ide_get_best_pio_mode(drive, 255, 5, NULL);
-
-        switch (drive->dn) {
-		case 0: drive_pci = 0x41; drive_pci2 = 0x45; break;
-		case 1: drive_pci = 0x40; drive_pci2 = 0x44; break;
-		case 2: drive_pci = 0x43; drive_pci2 = 0x47; break;
-		case 3: drive_pci = 0x42; drive_pci2 = 0x46; break;
-		default:
-			return -1;
-	}
-
-	pci_read_config_byte(dev, drive_pci, &pio_timing);
-	pci_read_config_byte(dev, drive_pci2, &dma_timing);
-	pci_read_config_byte(dev, drive_pci3, &ultra_timing);
-	pci_read_config_word(dev, 0x4A, &csb5_pio);
-	pci_read_config_byte(dev, 0x54, &ultra_enable);
-
-#ifdef DEBUG
-	printk("%s: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x ",
-		drive->name, ultra_timing, dma_timing, pio_timing);
-#endif
-
-	pio_timing	&= ~0xFF;
-	dma_timing	&= ~0xFF;
-	ultra_timing	&= ~(0x0F << (4*unit));
-	ultra_enable	&= ~(0x01 << drive->dn);
-	csb5_pio	&= ~(0x0F << (4*drive->dn));
-
-	switch(speed) {
-		case XFER_PIO_4:
-		case XFER_PIO_3:
-		case XFER_PIO_2:
-		case XFER_PIO_1:
-		case XFER_PIO_0:
-			pio_timing |= pio_modes[speed - XFER_PIO_0];
-			csb5_pio   |= ((speed - XFER_PIO_0) << (4*drive->dn));
-			break;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		case XFER_MW_DMA_2:
-		case XFER_MW_DMA_1:
-		case XFER_MW_DMA_0:
-			pio_timing |= pio_modes[pio];
-			csb5_pio   |= (pio << (4*drive->dn));
-			dma_timing |= dma_modes[speed - XFER_MW_DMA_0];
-			break;
-
-		case XFER_UDMA_5:
-		case XFER_UDMA_4:
-		case XFER_UDMA_3:
-		case XFER_UDMA_2:
-		case XFER_UDMA_1:
-		case XFER_UDMA_0:
-			pio_timing   |= pio_modes[pio];
-			csb5_pio     |= (pio << (4*drive->dn));
-			dma_timing   |= dma_modes[2];
-			ultra_timing |= ((udma_modes[speed - XFER_UDMA_0]) << (4*unit));
-			ultra_enable |= (0x01 << drive->dn);
-#endif
-		default:
-			break;
-	}
-
-#ifdef DEBUG
-	printk("%s: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x ",
-		drive->name, ultra_timing, dma_timing, pio_timing);
-#endif
-
-#if SVWKS_DEBUG_DRIVE_INFO
-	printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive->dn);
-#endif /* SVWKS_DEBUG_DRIVE_INFO */
-
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-
-	pci_write_config_byte(dev, drive_pci, pio_timing);
-	if (csb5)
-		pci_write_config_word(dev, 0x4A, csb5_pio);
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	pci_write_config_byte(dev, drive_pci2, dma_timing);
-	pci_write_config_byte(dev, drive_pci3, ultra_timing);
-	pci_write_config_byte(dev, 0x54, ultra_enable);
-	
-	if (speed > XFER_PIO_4)
-		outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
-	else
-		outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-	err = ide_config_drive_speed(drive, speed);
-	drive->current_speed = speed;
-	return err;
-}
-
-static void config_chipset_for_pio (ide_drive_t *drive)
-{
-	unsigned short eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
-	unsigned short xfer_pio = drive->id->eide_pio_modes;
-	byte timing, speed, pio;
-
-	pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
-
-	if (xfer_pio> 4)
-		xfer_pio = 0;
-
-	if (drive->id->eide_pio_iordy > 0)
-		for (xfer_pio = 5;
-			xfer_pio>0 &&
-			drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
-			xfer_pio--);
-	else
-		xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
-			   (drive->id->eide_pio_modes & 2) ? 0x04 :
-			   (drive->id->eide_pio_modes & 1) ? 0x03 :
-			   (drive->id->tPIO & 2) ? 0x02 :
-			   (drive->id->tPIO & 1) ? 0x01 : xfer_pio;
-
-	timing = (xfer_pio >= pio) ? xfer_pio : pio;
-
-	switch(timing) {
-		case 4: speed = XFER_PIO_4;break;
-		case 3: speed = XFER_PIO_3;break;
-		case 2: speed = XFER_PIO_2;break;
-		case 1: speed = XFER_PIO_1;break;
-		default:
-			speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW;
-			break;
-	}
-	(void) svwks_tune_chipset(drive, speed);
-	drive->current_speed = speed;
-}
-
-static void svwks_tune_drive (ide_drive_t *drive, byte pio)
-{
-	byte speed;
-	switch(pio) {
-		case 4:		speed = XFER_PIO_4;break;
-		case 3:		speed = XFER_PIO_3;break;
-		case 2:		speed = XFER_PIO_2;break;
-		case 1:		speed = XFER_PIO_1;break;
-		default:	speed = XFER_PIO_0;break;
-	}
-	(void) svwks_tune_chipset(drive, speed);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_chipset_for_dma (ide_drive_t *drive)
-{
-	struct hd_driveid *id	= drive->id;
-	struct pci_dev *dev	= HWIF(drive)->pci_dev;
-	byte udma_66	= eighty_ninty_three(drive);
-	int ultra66	= (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ? 1 : 0;
-	int ultra100 	= (ultra66 && svwks_revision >= SVWKS_CSB5_REVISION_NEW) ? 1 : 0;
-	byte speed;
-
-	if ((id->dma_ultra & 0x0020) && (udma_66) && (ultra100)) {
-		speed = XFER_UDMA_5;
-	} else if (id->dma_ultra & 0x0010) {
-		speed = ((udma_66) && (ultra66)) ? XFER_UDMA_4 : XFER_UDMA_2;
-	} else if (id->dma_ultra & 0x0008) {
-		speed = ((udma_66) && (ultra66)) ? XFER_UDMA_3 : XFER_UDMA_1;
-	} else if (id->dma_ultra & 0x0004) {
-		speed = XFER_UDMA_2;
-	} else if (id->dma_ultra & 0x0002) {
-		speed = XFER_UDMA_1;
-	} else if (id->dma_ultra & 0x0001) {
-		speed = XFER_UDMA_0;
-	} else if (id->dma_mword & 0x0004) {
-		speed = XFER_MW_DMA_2;
-	} else if (id->dma_mword & 0x0002) {
-		speed = XFER_MW_DMA_1;
-	} else if (id->dma_1word & 0x0004) {
-		speed = XFER_SW_DMA_2;
-	} else {
-		speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
-	}
-
-	(void) svwks_tune_chipset(drive, speed);
-
-	return ((int)	((id->dma_ultra >> 11) & 7) ? ide_dma_on :
-			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-			((id->dma_mword >> 8) & 7) ? ide_dma_on :
-			((id->dma_1word >> 8) & 7) ? ide_dma_on :
-						     ide_dma_off_quietly);
-}
-
-static int config_drive_xfer_rate (ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-	ide_dma_action_t dma_func = ide_dma_on;
-
-	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x003F) {
-				/* Force if Capable UltraDMA */
-				dma_func = config_chipset_for_dma(drive);
-				if ((id->field_valid & 2) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    (id->dma_1word & 0x007)) {
-				/* Force if Capable regular DMA modes */
-				dma_func = config_chipset_for_dma(drive);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-		} else if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			if (id->eide_dma_time > 150) {
-				goto no_dma_set;
-			}
-			/* Consult the list of known "good" drives */
-			dma_func = config_chipset_for_dma(drive);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-		config_chipset_for_pio(drive);
-	}
-	return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-static int svwks_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch (func) {
-		case ide_dma_check:
-			return config_drive_xfer_rate(drive);
-		case ide_dma_end:
-		{
-			ide_hwif_t *hwif		= HWIF(drive);
-			unsigned long dma_base		= hwif->dma_base;
-	
-			if(inb(dma_base+0x02)&1)
-			{
-#if 0		
-				int i;
-				printk(KERN_ERR "Curious - OSB4 thinks the DMA is still running.\n");
-				for(i=0;i<10;i++)
-				{
-					if(!(inb(dma_base+0x02)&1))
-					{
-						printk(KERN_ERR "OSB4 now finished.\n");
-						break;
-					}
-					udelay(5);
-				}
-#endif		
-				printk(KERN_CRIT "Serverworks OSB4 in impossible state.\n");
-				printk(KERN_CRIT "Disable UDMA or if you are using Seagate then try switching disk types\n");
-				printk(KERN_CRIT "on this controller. Please report this event to osb4-bug@ide.cabal.tm\n");
-#if 0		
-				/* Panic might sys_sync -> death by corrupt disk */
-				panic("OSB4: continuing might cause disk corruption.\n");
-#else
-				printk(KERN_CRIT "OSB4: continuing might cause disk corruption.\n");
-				while(1)
-					cpu_relax();
-#endif				
-			}
-			/* and drop through */
-		}
-		default:
-			break;
-	}
-	/* Other cases are done by generic IDE-DMA code. */
-	return ide_dmaproc(func, drive);
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-unsigned int __init pci_init_svwks (struct pci_dev *dev, const char *name)
-{
-	unsigned int reg;
-	byte btr;
-
-	/* save revision id to determine DMA capability */
-	pci_read_config_byte(dev, PCI_REVISION_ID, &svwks_revision);
-
-	/* force Master Latency Timer value to 64 PCICLKs */
-	pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40);
-
-	/* OSB4 : South Bridge and IDE */
-	if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
-		isa_dev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS,
-			  PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL);
-		if (isa_dev) {
-			pci_read_config_dword(isa_dev, 0x64, &reg);
-			reg &= ~0x00002000; /* disable 600ns interrupt mask */
-			reg |=  0x00004000; /* enable UDMA/33 support */
-			pci_write_config_dword(isa_dev, 0x64, reg);
-		}
-	}
-
-	/* setup CSB5 : South Bridge and IDE */
-	else if (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) {
-		/* setup the UDMA Control register
-		 *
-		 * 1. clear bit 6 to enable DMA
-		 * 2. enable DMA modes with bits 0-1
-		 *      00 : legacy
-		 *      01 : udma2
-		 *      10 : udma2/udma4
-		 *      11 : udma2/udma4/udma5
-		 */
-		pci_read_config_byte(dev, 0x5A, &btr);
-		btr &= ~0x40;
-		btr |= (svwks_revision >= SVWKS_CSB5_REVISION_NEW) ? 0x3 : 0x2;
-		pci_write_config_byte(dev, 0x5A, btr);
-	}
-
-#if defined(DISPLAY_SVWKS_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!svwks_proc) {
-		svwks_proc = 1;
-		bmide_dev = dev;
-		svwks_display_info = &svwks_get_info;
-	}
-#endif /* DISPLAY_SVWKS_TIMINGS && CONFIG_PROC_FS */
-	return 0;
-}
-
-/* On Dell PowerEdge servers with a CSB5, the top two bits of the subsystem
- * device ID indicate presence of an 80-pin cable.
- * Bit 15 clear = secondary IDE channel does not have 80-pin cable.
- * Bit 15 set   = secondary IDE channel has 80-pin cable.
- * Bit 14 clear = primary IDE channel does not have 80-pin cable.
- * Bit 14 set   = primary IDE channel has 80-pin cable.
- */
-static unsigned int __init ata66_svwks_dell (ide_hwif_t *hwif)
-{
-	struct pci_dev *dev = hwif->pci_dev;
-	if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
-	    dev->vendor	== PCI_VENDOR_ID_SERVERWORKS &&
-	    dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
-		return ((1 << (hwif->channel + 14)) &
-			dev->subsystem_device) ? 1 : 0;
-	return 0;
-}
-
-/* Sun Cobalt Alpine hardware avoids the 80-pin cable
- * detect issue by attaching the drives directly to the board.
- * This check follows the Dell precedent (how scary is that?!)
- *
- * WARNING: this only works on Alpine hardware!
- */
-static unsigned int __init ata66_svwks_cobalt (ide_hwif_t *hwif)
-{
-	struct pci_dev *dev = hwif->pci_dev;
-	if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN &&
-	    dev->vendor	== PCI_VENDOR_ID_SERVERWORKS &&
-	    dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
-		return ((1 << (hwif->channel + 14)) &
-			dev->subsystem_device) ? 1 : 0;
-	return 0;
-}
-
-unsigned int __init ata66_svwks (ide_hwif_t *hwif)
-{
-	struct pci_dev *dev = hwif->pci_dev;
-
-	/* Dell PowerEdge */
-	if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL)
-		return ata66_svwks_dell (hwif);
-
-	/* Cobalt Alpine */
-	if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN)
-		return ata66_svwks_cobalt (hwif);
-
-	return 0;
-}
-
-void __init ide_init_svwks (ide_hwif_t *hwif)
-{
-	if (!hwif->irq)
-		hwif->irq = hwif->channel ? 15 : 14;
-
-	hwif->tuneproc = &svwks_tune_drive;
-	hwif->speedproc = &svwks_tune_chipset;
-
-#ifndef CONFIG_BLK_DEV_IDEDMA
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-	hwif->autodma = 0;
-#else /* CONFIG_BLK_DEV_IDEDMA */
-	if (hwif->dma_base) {
-#ifdef CONFIG_IDEDMA_AUTO
-		if (!noautodma)
-			hwif->autodma = 1;
-#endif	
-		hwif->dmaproc = &svwks_dmaproc;
-	} else {
-		hwif->autodma = 0;
-		hwif->drives[0].autotune = 1;
-		hwif->drives[1].autotune = 1;
-	}
-#endif /* !CONFIG_BLK_DEV_IDEDMA */
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/setup-pci.c linux-2.4.21-pre6/drivers/ide/setup-pci.c
--- linux-2.4.20/drivers/ide/setup-pci.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/setup-pci.c	2003-03-26 23:49:40.000000000 +0000
@@ -0,0 +1,837 @@
+/*
+ *  linux/drivers/ide/setup-pci.c		Version 1.10	2002/08/19
+ *
+ *  Copyright (c) 1998-2000  Andre Hedrick <andre@linux-ide.org>
+ *
+ *  Copyright (c) 1995-1998  Mark Lord
+ *  May be copied or modified under the terms of the GNU General Public License
+ *
+ *  Recent Changes
+ *	Split the set up function into multiple functions
+ *	Use pci_set_master
+ *	Fix misreporting of I/O v MMIO problems
+ *	Initial fixups for simplex devices
+ */
+
+/*
+ *  This module provides support for automatic detection and
+ *  configuration of all PCI IDE interfaces present in a system.  
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+
+/**
+ *	ide_match_hwif	-	match a PCI IDE against an ide_hwif
+ *	@io_base: I/O base of device
+ *	@bootable: set if its bootable
+ *	@name: name of device
+ *
+ *	Match a PCI IDE port against an entry in ide_hwifs[],
+ *	based on io_base port if possible. Return the matching hwif,
+ *	or a new hwif. If we find an error (clashing, out of devices, etc)
+ *	return NULL
+ *
+ *	FIXME: we need to handle mmio matches here too
+ */
+
+static ide_hwif_t *ide_match_hwif(unsigned long io_base, u8 bootable, const char *name)
+{
+	int h;
+	ide_hwif_t *hwif;
+
+	/*
+	 * Look for a hwif with matching io_base specified using
+	 * parameters to ide_setup().
+	 */
+	for (h = 0; h < MAX_HWIFS; ++h) {
+		hwif = &ide_hwifs[h];
+		if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) {
+			if (hwif->chipset == ide_generic)
+				return hwif; /* a perfect match */
+		}
+	}
+	/*
+	 * Look for a hwif with matching io_base default value.
+	 * If chipset is "ide_unknown", then claim that hwif slot.
+	 * Otherwise, some other chipset has already claimed it..  :(
+	 */
+	for (h = 0; h < MAX_HWIFS; ++h) {
+		hwif = &ide_hwifs[h];
+		if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) {
+			if (hwif->chipset == ide_unknown)
+				return hwif; /* match */
+			printk(KERN_ERR "%s: port 0x%04lx already claimed by %s\n",
+				name, io_base, hwif->name);
+			return NULL;	/* already claimed */
+		}
+	}
+	/*
+	 * Okay, there is no hwif matching our io_base,
+	 * so we'll just claim an unassigned slot.
+	 * Give preference to claiming other slots before claiming ide0/ide1,
+	 * just in case there's another interface yet-to-be-scanned
+	 * which uses ports 1f0/170 (the ide0/ide1 defaults).
+	 *
+	 * Unless there is a bootable card that does not use the standard
+	 * ports 1f0/170 (the ide0/ide1 defaults). The (bootable) flag.
+	 */
+	if (bootable) {
+		for (h = 0; h < MAX_HWIFS; ++h) {
+			hwif = &ide_hwifs[h];
+			if (hwif->chipset == ide_unknown)
+				return hwif;	/* pick an unused entry */
+		}
+	} else {
+		for (h = 2; h < MAX_HWIFS; ++h) {
+			hwif = ide_hwifs + h;
+			if (hwif->chipset == ide_unknown)
+				return hwif;	/* pick an unused entry */
+		}
+	}
+	for (h = 0; h < 2; ++h) {
+		hwif = ide_hwifs + h;
+		if (hwif->chipset == ide_unknown)
+			return hwif;	/* pick an unused entry */
+	}
+	printk(KERN_ERR "%s: too many IDE interfaces, no room in table\n", name);
+	return NULL;
+}
+
+/**
+ *	ide_setup_pci_baseregs	-	place a PCI IDE controller native
+ *	@dev: PCI device of interface to switch native
+ *	@name: Name of interface
+ *
+ *	We attempt to place the PCI interface into PCI native mode. If
+ *	we succeed the BARs are ok and the controller is in PCI mode.
+ *	Returns 0 on success or an errno code. 
+ *
+ *	FIXME: if we program the interface and then fail to set the BARS
+ *	we don't switch it back to legacy mode. Do we actually care ??
+ */
+ 
+static int ide_setup_pci_baseregs (struct pci_dev *dev, const char *name)
+{
+	u8 progif = 0;
+
+	/*
+	 * Place both IDE interfaces into PCI "native" mode:
+	 */
+	if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) ||
+			 (progif & 5) != 5) {
+		if ((progif & 0xa) != 0xa) {
+			printk(KERN_INFO "%s: device not capable of full "
+				"native PCI mode\n", name);
+			return -EOPNOTSUPP;
+		}
+		printk("%s: placing both ports into native PCI mode\n", name);
+		(void) pci_write_config_byte(dev, PCI_CLASS_PROG, progif|5);
+		if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) ||
+		    (progif & 5) != 5) {
+			printk(KERN_ERR "%s: rewrite of PROGIF failed, wanted "
+				"0x%04x, got 0x%04x\n",
+				name, progif|5, progif);
+			return -EOPNOTSUPP;
+		}
+	}
+	return 0;
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_FORCED
+/*
+ * Long lost data from 2.0.34 that is now in 2.0.39
+ *
+ * This was used in ./drivers/block/triton.c to do DMA Base address setup
+ * when PnP failed.  Oh the things we forget.  I believe this was part
+ * of SFF-8038i that has been withdrawn from public access... :-((
+ */
+#define DEFAULT_BMIBA	0xe800	/* in case BIOS did not init it */
+#define DEFAULT_BMCRBA	0xcc00	/* VIA's default value */
+#define DEFAULT_BMALIBA	0xd400	/* ALI's default value */
+#endif /* CONFIG_BLK_DEV_IDEDMA_FORCED */
+
+/**
+ *	ide_get_or_set_dma_base		-	setup BMIBA
+ *	@hwif: Interface
+ *
+ *	Fetch the DMA Bus-Master-I/O-Base-Address (BMIBA) from PCI space:
+ *	If need be we set up the DMA base. Where a device has a partner that
+ *	is already in DMA mode we check and enforce IDE simplex rules.
+ */
+
+static unsigned long __init ide_get_or_set_dma_base (ide_hwif_t *hwif)
+{
+	unsigned long	dma_base = 0;
+	struct pci_dev	*dev = hwif->pci_dev;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_FORCED
+	int second_chance = 0;
+
+second_chance_to_dma:
+#endif /* CONFIG_BLK_DEV_IDEDMA_FORCED */
+
+	if ((hwif->mmio) && (hwif->dma_base))
+		return hwif->dma_base;
+
+	if (hwif->mate && hwif->mate->dma_base) {
+		dma_base = hwif->mate->dma_base - (hwif->channel ? 0 : 8);
+	} else {
+		dma_base = (hwif->mmio) ?
+			((unsigned long) hwif->hwif_data) :
+			(pci_resource_start(dev, 4));
+		if (!dma_base) {
+			printk(KERN_ERR "%s: dma_base is invalid (0x%04lx)\n",
+				hwif->cds->name, dma_base);
+			dma_base = 0;
+		}
+	}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_FORCED
+	/* FIXME - should use pci_assign_resource surely */
+	if ((!dma_base) && (!second_chance)) {
+		unsigned long set_bmiba = 0;
+		second_chance++;
+		switch(dev->vendor) {
+			case PCI_VENDOR_ID_AL:
+				set_bmiba = DEFAULT_BMALIBA; break;
+			case PCI_VENDOR_ID_VIA:
+				set_bmiba = DEFAULT_BMCRBA; break;
+			case PCI_VENDOR_ID_INTEL:
+				set_bmiba = DEFAULT_BMIBA; break;
+			default:
+				return dma_base;
+		}
+		pci_write_config_dword(dev, 0x20, set_bmiba|1);
+		goto second_chance_to_dma;
+	}
+#endif /* CONFIG_BLK_DEV_IDEDMA_FORCED */
+
+	if (dma_base) {
+		u8 simplex_stat = 0;
+		dma_base += hwif->channel ? 8 : 0;
+
+		switch(dev->device) {
+			case PCI_DEVICE_ID_AL_M5219:
+			case PCI_DEVICE_ID_AL_M5229:
+			case PCI_DEVICE_ID_AMD_VIPER_7409:
+			case PCI_DEVICE_ID_CMD_643:
+			case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
+				simplex_stat = hwif->INB(dma_base + 2);
+				hwif->OUTB((simplex_stat&0x60),(dma_base + 2));
+				simplex_stat = hwif->INB(dma_base + 2);
+				if (simplex_stat & 0x80) {
+					printk(KERN_INFO "%s: simplex device: "
+						"DMA forced\n",
+						hwif->cds->name);
+				}
+				break;
+			default:
+				/*
+				 * If the device claims "simplex" DMA,
+				 * this means only one of the two interfaces
+				 * can be trusted with DMA at any point in time.
+				 * So we should enable DMA only on one of the
+				 * two interfaces.
+				 */
+				simplex_stat = hwif->INB(dma_base + 2);
+				if (simplex_stat & 0x80) {
+					/* simplex device? */
+#if 0					
+/*
+ *	At this point we haven't probed the drives so we can't make the
+ *	appropriate decision. Really we should defer this problem
+ *	until we tune the drive then try to grab DMA ownership if we want
+ *	to be the DMA end. This has to be become dynamic to handle hot
+ *	plug.
+ */
+					/* Don't enable DMA on a simplex channel with no drives */
+					if (!hwif->drives[0].present && !hwif->drives[1].present)
+					{
+						printk(KERN_INFO "%s: simplex device with no drives: DMA disabled\n",
+								hwif->cds->name);
+						dma_base = 0;
+					}
+					/* If our other channel has DMA then we cannot */
+					else 
+#endif					
+					if(hwif->mate && hwif->mate->dma_base) 
+					{
+						printk(KERN_INFO "%s: simplex device: "
+							"DMA disabled\n",
+							hwif->cds->name);
+						dma_base = 0;
+					}
+				}
+		}
+	}
+	return dma_base;
+}
+
+static void ide_setup_pci_noise (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	if ((d->vendor != dev->vendor) && (d->device != dev->device)) {
+		printk(KERN_INFO "%s: unknown IDE controller at PCI slot "
+			"%s, VID=%04x, DID=%04x\n",
+			d->name, dev->slot_name, dev->vendor, dev->device);
+        } else {
+		printk(KERN_INFO "%s: IDE controller at PCI slot %s\n",
+			d->name, dev->slot_name);
+	}
+}
+
+/**
+ *	ide_pci_enable	-	do PCI enables
+ *	@dev: PCI device
+ *	@d: IDE pci device data
+ *
+ *	Enable the IDE PCI device. We attempt to enable the device in full
+ *	but if that fails then we only need BAR4 so we will enable that.
+ *	
+ *	Returns zero on success or an error code
+ */
+ 
+static int ide_pci_enable(struct pci_dev *dev, ide_pci_device_t *d)
+{
+	
+	if (pci_enable_device(dev)) {
+		if (pci_enable_device_bars(dev, 1 << 4)) {
+			printk(KERN_WARNING "%s: (ide_setup_pci_device:) "
+				"Could not enable device.\n", d->name);
+			return -EBUSY;
+		} else
+			printk(KERN_WARNING "%s: Not fully BIOS configured!\n", d->name);
+	}
+
+	/*
+	 * assume all devices can do 32-bit dma for now. we can add a
+	 * dma mask field to the ide_pci_device_t if we need it (or let
+	 * lower level driver set the dma mask)
+	 */
+	if (pci_set_dma_mask(dev, 0xffffffff)) {
+		printk(KERN_ERR "%s: can't set dma mask\n", d->name);
+		return -EBUSY;
+	}
+	 
+	/* FIXME: Temporary - until we put in the hotplug interface logic
+	   Check that the bits we want are not in use by someone else */
+	if (pci_request_region(dev, 4, "ide_tmp"))
+		return -EBUSY;
+	pci_release_region(dev, 4);
+	
+	return 0;	
+}
+
+/**
+ *	ide_pci_configure	-	configure an unconfigured device
+ *	@dev: PCI device
+ *	@d: IDE pci device data
+ *
+ *	Enable and configure the PCI device we have been passed.
+ *	Returns zero on success or an error code.
+ */
+ 
+static int ide_pci_configure(struct pci_dev *dev, ide_pci_device_t *d)
+{
+	u16 pcicmd = 0;
+	/*
+	 * PnP BIOS was *supposed* to have setup this device, but we
+	 * can do it ourselves, so long as the BIOS has assigned an IRQ
+	 * (or possibly the device is using a "legacy header" for IRQs).
+	 * Maybe the user deliberately *disabled* the device,
+	 * but we'll eventually ignore it again if no drives respond.
+	 */
+	if (ide_setup_pci_baseregs(dev, d->name) || pci_write_config_word(dev, PCI_COMMAND, pcicmd|PCI_COMMAND_IO)) 
+	{
+		printk(KERN_INFO "%s: device disabled (BIOS)\n", d->name);
+		return -ENODEV;
+	}
+	if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd)) {
+		printk(KERN_ERR "%s: error accessing PCI regs\n", d->name);
+		return -EIO;
+	}
+	if (!(pcicmd & PCI_COMMAND_IO)) {
+		printk(KERN_ERR "%s: unable to enable IDE controller\n", d->name);
+		return -ENXIO;
+	}
+	return 0;
+}
+
+/**
+ *	ide_pci_check_iomem	-	check a register is I/O
+ *	@dev: pci device
+ *	@d: ide_pci_device
+ *	@bar: bar number
+ *
+ *	Checks if a BAR is configured and points to MMIO space. If so
+ *	print an error and return an error code. Otherwise return 0
+ */
+ 
+static int ide_pci_check_iomem(struct pci_dev *dev, ide_pci_device_t *d, int bar)
+{
+	ulong flags = pci_resource_flags(dev, bar);
+	
+	/* Unconfigured ? */
+	if (!flags || pci_resource_len(dev, bar) == 0)
+		return 0;
+
+	/* I/O space */		
+	if(flags & PCI_BASE_ADDRESS_IO_MASK)
+		return 0;
+		
+	/* Bad */
+	printk(KERN_ERR "%s: IO baseregs (BIOS) are reported "
+			"as MEM, report to "
+			"<andre@linux-ide.org>.\n", d->name);
+	return -EINVAL;
+}
+	
+		
+/**
+ *	ide_hwif_configure	-	configure an IDE interface
+ *	@dev: PCI device holding interface
+ *	@d: IDE pci data
+ *	@mate: Paired interface if any
+ *
+ *	Perform the initial set up for the hardware interface structure. This
+ *	is done per interface port rather than per PCI device. There may be
+ *	more than one port per device.
+ *
+ *	Returns the new hardware interface structure, or NULL on a failure
+ */
+ 
+static ide_hwif_t *ide_hwif_configure(struct pci_dev *dev, ide_pci_device_t *d, ide_hwif_t *mate, int port, int irq)
+{
+	unsigned long ctl = 0, base = 0;
+	ide_hwif_t *hwif;
+
+	/*  Possibly we should fail if these checks report true */
+	ide_pci_check_iomem(dev, d, 2*port);
+	ide_pci_check_iomem(dev, d, 2*port+1);
+ 
+	ctl  = pci_resource_start(dev, 2*port+1);
+	base = pci_resource_start(dev, 2*port);
+	if ((ctl && !base) || (base && !ctl)) {
+		printk(KERN_ERR "%s: inconsistent baseregs (BIOS) "
+			"for port %d, skipping\n", d->name, port);
+		return NULL;
+	}
+	if (!ctl)
+	{
+		/* Use default values */
+		ctl = port ? 0x374 : 0x3f4;
+		base = port ? 0x170 : 0x1f0;
+	}
+	if ((hwif = ide_match_hwif(base, d->bootable, d->name)) == NULL)
+		return NULL;	/* no room in ide_hwifs[] */
+	if (hwif->io_ports[IDE_DATA_OFFSET] != base) {
+fixup_address:
+		ide_init_hwif_ports(&hwif->hw, base, (ctl | 2), NULL);
+		memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
+		hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
+	} else if (hwif->io_ports[IDE_CONTROL_OFFSET] != (ctl | 2)) {
+		goto fixup_address;
+	}
+	hwif->chipset = ide_pci;
+	hwif->pci_dev = dev;
+	hwif->cds = (struct ide_pci_device_s *) d;
+	hwif->channel = port;
+
+	if (!hwif->irq)
+		hwif->irq = irq;
+	if (mate) {
+		hwif->mate = mate;
+		mate->mate = hwif;
+	}
+	return hwif;
+}
+
+/**
+ *	ide_hwif_setup_dma	-	configure DMA interface
+ *	@dev: PCI device
+ *	@d: IDE pci data
+ *	@hwif: Hardware interface we are configuring
+ *
+ *	Set up the DMA base for the interface. Enable the master bits as
+ *	neccessary and attempt to bring the device DMA into a ready to use
+ *	state
+ */
+ 
+static void ide_hwif_setup_dma(struct pci_dev *dev, ide_pci_device_t *d, ide_hwif_t *hwif)
+{
+	u16 pcicmd;
+	pci_read_config_word(dev, PCI_COMMAND, &pcicmd);
+
+	if ((d->autodma == AUTODMA) ||
+	    ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE &&
+	     (dev->class & 0x80))) {
+		unsigned long dma_base = ide_get_or_set_dma_base(hwif);
+		if (dma_base && !(pcicmd & PCI_COMMAND_MASTER)) {
+			/*
+ 			 * Set up BM-DMA capability
+			 * (PnP BIOS should have done this)
+ 			 */
+			if (!((d->device == PCI_DEVICE_ID_CYRIX_5530_IDE && d->vendor == PCI_VENDOR_ID_CYRIX)
+			    ||(d->device == PCI_DEVICE_ID_NS_SCx200_IDE && d->vendor == PCI_VENDOR_ID_NS)))
+			{
+				/*
+				 * default DMA off if we had to
+				 * configure it here
+				 */
+				hwif->autodma = 0;
+			}
+			pci_set_master(dev);
+			if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd) || !(pcicmd & PCI_COMMAND_MASTER)) {
+				printk(KERN_ERR "%s: %s error updating PCICMD\n",
+					hwif->name, d->name);
+				dma_base = 0;
+			}
+		}
+		if (dma_base) {
+			if (d->init_dma) {
+				d->init_dma(hwif, dma_base);
+			} else {
+				ide_setup_dma(hwif, dma_base, 8);
+			}
+		} else {
+			printk(KERN_INFO "%s: %s Bus-Master DMA disabled "
+				"(BIOS)\n", hwif->name, d->name);
+		}
+	}
+}
+
+/**
+ *	ide_setup_pci_controller	-	set up IDE PCI
+ *	@dev: PCI device
+ *	@d: IDE PCI data
+ *	@noisy: verbose flag
+ *	@config: returned as 1 if we configured the hardware
+ *
+ *	Set up the PCI and controller side of the IDE interface. This brings
+ *	up the PCI side of the device, checks that the device is enabled
+ *	and enables it if need be
+ */
+ 
+static int ide_setup_pci_controller(struct pci_dev *dev, ide_pci_device_t *d, int noisy, int *config)
+{
+	int ret = 0;
+	u32 class_rev;
+	u16 pcicmd;
+
+	if (!noautodma)
+		ret = 1;
+
+	if (noisy)
+		ide_setup_pci_noise(dev, d);
+
+	if (ide_pci_enable(dev, d))
+		return -EBUSY;
+		
+	if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd)) {
+		printk(KERN_ERR "%s: error accessing PCI regs\n", d->name);
+		return -EIO;
+	}
+	if (!(pcicmd & PCI_COMMAND_IO)) {	/* is device disabled? */
+		if (ide_pci_configure(dev, d))
+			return -ENODEV;
+		/* default DMA off if we had to configure it here */
+		ret = 0;
+		*config = 1;
+		printk(KERN_INFO "%s: device enabled (Linux)\n", d->name);
+	}
+
+	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+	class_rev &= 0xff;
+	if (noisy)
+		printk(KERN_INFO "%s: chipset revision %d\n", d->name, class_rev);
+	return ret;
+}
+
+/*
+ * ide_setup_pci_device() looks at the primary/secondary interfaces
+ * on a PCI IDE device and, if they are enabled, prepares the IDE driver
+ * for use with them.  This generic code works for most PCI chipsets.
+ *
+ * One thing that is not standardized is the location of the
+ * primary/secondary interface "enable/disable" bits.  For chipsets that
+ * we "know" about, this information is in the ide_pci_device_t struct;
+ * for all other chipsets, we just assume both interfaces are enabled.
+ */
+static ata_index_t do_ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d, u8 noisy)
+{
+	u32 port, at_least_one_hwif_enabled = 0, autodma = 0;
+	int pciirq = 0;
+	int tried_config = 0;
+	int drive0_tune, drive1_tune;
+	ata_index_t index;
+	u8 tmp = 0;
+	ide_hwif_t *hwif, *mate = NULL;
+	static int secondpdc = 0;
+
+	index.all = 0xf0f0;
+
+	if((autodma = ide_setup_pci_controller(dev, d, noisy, &tried_config)) < 0)
+		return index;
+
+	/*
+	 * Can we trust the reported IRQ?
+	 */
+	pciirq = dev->irq;
+	
+	if ((dev->class & ~(0xfa)) != ((PCI_CLASS_STORAGE_IDE << 8) | 5)) {
+		if (noisy)
+			printk(KERN_INFO "%s: not 100%% native mode: "
+				"will probe irqs later\n", d->name);
+		/*
+		 * This allows offboard ide-pci cards the enable a BIOS,
+		 * verify interrupt settings of split-mirror pci-config
+		 * space, place chipset into init-mode, and/or preserve
+		 * an interrupt if the card is not native ide support.
+		 */
+		pciirq = (d->init_chipset) ? d->init_chipset(dev, d->name) : 0;
+	} else if (tried_config) {
+		if (noisy)
+			printk(KERN_INFO "%s: will probe irqs later\n", d->name);
+		pciirq = 0;
+	} else if (!pciirq) {
+		if (noisy)
+			printk(KERN_WARNING "%s: bad irq (%d): will probe later\n",
+				d->name, pciirq);
+		pciirq = 0;
+	} else {
+		if (d->init_chipset)
+		{
+			if(d->init_chipset(dev, d->name) < 0)
+				return index;
+		}
+		if (noisy)
+#ifdef __sparc__
+			printk(KERN_INFO "%s: 100%% native mode on irq %s\n",
+			       d->name, __irq_itoa(pciirq));
+#else
+			printk(KERN_INFO "%s: 100%% native mode on irq %d\n",
+				d->name, pciirq);
+#endif
+	}
+	
+	if(pciirq < 0)		/* Error not an IRQ */
+		return index;
+
+	/*
+	 * Set up the IDE ports
+	 */
+	 
+	for (port = 0; port <= 1; ++port) {
+		ide_pci_enablebit_t *e = &(d->enablebits[port]);
+	
+		/* 
+		 * If this is a Promise FakeRaid controller,
+		 * the 2nd controller will be marked as 
+		 * disabled while it is actually there and enabled
+		 * by the bios for raid purposes. 
+		 * Skip the normal "is it enabled" test for those.
+		 */
+		if (((d->vendor == PCI_VENDOR_ID_PROMISE) &&
+		     ((d->device == PCI_DEVICE_ID_PROMISE_20262) ||
+		      (d->device == PCI_DEVICE_ID_PROMISE_20265))) &&
+		    (secondpdc++==1) && (port==1))
+			goto controller_ok;
+			
+		if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) ||
+		    (tmp & e->mask) != e->val))
+			continue;	/* port not enabled */
+controller_ok:
+
+		if (d->channels	<= port)
+			return index;
+	
+		if ((hwif = ide_hwif_configure(dev, d, mate, port, pciirq)) == NULL)
+			continue;
+
+		/* setup proper ancestral information */
+		// 2.5 only hwif->gendev.parent = &dev->dev;
+
+		if (hwif->channel) {
+			index.b.high = hwif->index;
+		} else {
+			index.b.low = hwif->index;
+		}
+
+		
+		if (d->init_iops)
+			d->init_iops(hwif);
+
+		if (d->autodma == NODMA)
+			goto bypass_legacy_dma;
+		if (d->autodma == NOAUTODMA)
+			autodma = 0;
+		if (autodma)
+			hwif->autodma = 1;
+		ide_hwif_setup_dma(dev, d, hwif);
+bypass_legacy_dma:
+
+		drive0_tune = hwif->drives[0].autotune;
+		drive1_tune = hwif->drives[1].autotune;
+
+		if (d->init_hwif)
+			/* Call chipset-specific routine
+			 * for each enabled hwif
+			 */
+			d->init_hwif(hwif);
+
+		mate = hwif;
+		at_least_one_hwif_enabled = 1;
+	}
+	if (!at_least_one_hwif_enabled)
+		printk(KERN_INFO "%s: neither IDE port enabled (BIOS)\n", d->name);
+	return index;
+}
+
+void ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d)
+{
+	do_ide_setup_pci_device(dev, d, 1);
+}
+
+EXPORT_SYMBOL_GPL(ide_setup_pci_device);
+
+void ide_setup_pci_devices (struct pci_dev *dev, struct pci_dev *dev2, ide_pci_device_t *d)
+{
+	do_ide_setup_pci_device(dev, d, 1);
+	do_ide_setup_pci_device(dev2, d, 0);
+}
+
+EXPORT_SYMBOL_GPL(ide_setup_pci_devices);
+
+/*
+ *	Module interfaces
+ */
+ 
+static int pre_init = 1;		/* Before first ordered IDE scan */
+static LIST_HEAD(ide_pci_drivers);
+
+/*
+ *	ide_register_pci_driver		-	attach IDE driver
+ *	@driver: pci driver
+ *
+ *	Registers a driver with the IDE layer. The IDE layer arranges that
+ *	boot time setup is done in the expected device order and then 
+ *	hands the controllers off to the core PCI code to do the rest of
+ *	the work.
+ *
+ *	The driver_data of the driver table must point to an ide_pci_device_t
+ *	describing the interface.
+ *
+ *	Returns are the same as for pci_register_driver
+ */
+
+int ide_pci_register_driver(struct pci_driver *driver)
+{
+	if(!pre_init)
+		return pci_module_init(driver);
+	list_add_tail(&driver->node, &ide_pci_drivers);
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(ide_pci_register_driver);
+
+/**
+ *	ide_unregister_pci_driver	-	unregister an IDE driver
+ *	@driver: driver to remove
+ *
+ *	Unregister a currently installed IDE driver. Returns are the same
+ *	as for pci_unregister_driver
+ */
+ 
+void ide_pci_unregister_driver(struct pci_driver *driver)
+{
+	if(!pre_init)
+		pci_unregister_driver(driver);
+	else
+		list_del(&driver->node);
+}
+
+EXPORT_SYMBOL_GPL(ide_pci_unregister_driver);
+
+/**
+ *	ide_scan_pcidev		-	find an IDE driver for a device
+ *	@dev: PCI device to check
+ *
+ *	Look for an IDE driver to handle the device we are considering.
+ *	This is only used during boot up to get the ordering correct. After
+ *	boot up the pci layer takes over the job.
+ */
+ 
+static int __init ide_scan_pcidev(struct pci_dev *dev)
+{
+	struct list_head *l;
+	struct pci_driver *d;
+	
+	list_for_each(l, &ide_pci_drivers)
+	{
+		d = list_entry(l, struct pci_driver, node);
+		if(d->id_table)
+		{
+			const struct pci_device_id *id = pci_match_device(d->id_table, dev);
+			if(id != NULL)
+			{
+				if(d->probe(dev, id) >= 0)
+				{
+					dev->driver = d;
+					return 1;
+				}
+			}
+		}
+	}
+	return 0;
+}
+
+/**
+ *	ide_scan_pcibus		-	perform the initial IDE driver scan
+ *	@scan_direction: set for reverse order scanning
+ *
+ *	Perform the initial bus rather than driver ordered scan of the
+ *	PCI drivers. After this all IDE pci handling becomes standard
+ *	module ordering not traditionally ordered.
+ */
+ 	
+void __init ide_scan_pcibus (int scan_direction)
+{
+	struct pci_dev *dev;
+	struct pci_driver *d;
+	struct list_head *l, *n;
+
+	pre_init = 0;
+	if (!scan_direction) {
+		pci_for_each_dev(dev) {
+			ide_scan_pcidev(dev);
+		}
+	} else {
+		pci_for_each_dev_reverse(dev) {
+			ide_scan_pcidev(dev);
+		}
+	}
+	
+	/*
+	 *	Hand the drivers over to the PCI layer now we
+	 *	are post init.
+	 */
+
+	list_for_each_safe(l, n, &ide_pci_drivers)
+	{
+		list_del(l);
+		d = list_entry(l, struct pci_driver, node);
+		pci_register_driver(d);
+	}
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/sis5513.c linux-2.4.21-pre6/drivers/ide/sis5513.c
--- linux-2.4.20/drivers/ide/sis5513.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/sis5513.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,861 +0,0 @@
-/*
- * linux/drivers/ide/sis5513.c		Version 0.13	March 6, 2002
- *
- * Copyright (C) 1999-2000	Andre Hedrick <andre@linux-ide.org>
- * Copyright (C) 2002		Lionel Bouton <Lionel.Bouton@inet6.fr>, Maintainer
- * May be copied or modified under the terms of the GNU General Public License
- *
- *
- * Thanks :
- *
- * SiS Taiwan		: for direct support and hardware.
- * Daniela Engert	: for initial ATA100 advices and numerous others.
- * John Fremlin, Manfred Spraul :
- *			  for checking code correctness, providing patches.
- *
- *
- * Original tests and design on the SiS620/5513 chipset.
- * ATA100 tests and design on the SiS735/5513 chipset.
- * ATA16/33 design from specs
- */
-
-/*
- * TODO:
- *	- Get ridden of SisHostChipInfo[] completness dependancy.
- *	- Get ATA-133 datasheets, implement ATA-133 init code.
- *	- Study drivers/ide/ide-timing.h.
- *	- Are there pre-ATA_16 SiS5513 chips ? -> tune init code for them
- *	  or remove ATA_00 define
- *	- More checks in the config registers (force values instead of
- *	  relying on the BIOS setting them correctly).
- *	- Further optimisations ?
- *	  . for example ATA66+ regs 0x48 & 0x4A
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include "ide_modes.h"
-
-/* When DEBUG is defined it outputs initial PCI config register
-   values and changes made to them by the driver */   
-// #define DEBUG
-/* When BROKEN_LEVEL is defined it limits the DMA mode
-   at boot time to its value */
-// #define BROKEN_LEVEL XFER_SW_DMA_0
-#define DISPLAY_SIS_TIMINGS
-
-/* Miscellaneaous flags */
-#define SIS5513_LATENCY		0x01
-
-/* registers layout and init values are chipset family dependant */
-/* 1/ define families */
-#define ATA_00		0x00
-#define ATA_16		0x01
-#define ATA_33		0x02
-#define ATA_66		0x03
-#define ATA_100a	0x04 // SiS730 is ATA100 with ATA66 layout
-#define ATA_100		0x05
-#define ATA_133		0x06
-/* 2/ variable holding the controller chipset family value */
-static unsigned char chipset_family;
-
-
-/*
- * Debug code: following IDE config registers' changes
- */
-#ifdef DEBUG
-/* Copy of IDE Config registers 0x00 -> 0x57
-   Fewer might be used depending on the actual chipset */
-static unsigned char ide_regs_copy[0x58];
-
-static byte sis5513_max_config_register(void) {
-	switch(chipset_family) {
-		case ATA_00:
-		case ATA_16:	return 0x4f;
-		case ATA_33:	return 0x52;
-		case ATA_66:
-		case ATA_100a:
-		case ATA_100:
-		case ATA_133:
-		default:	return 0x57;
-	}
-}
-
-/* Read config registers, print differences from previous read */
-static void sis5513_load_verify_registers(struct pci_dev* dev, char* info) {
-	int i;
-	byte reg_val;
-	byte changed=0;
-	byte max = sis5513_max_config_register();
-
-	printk("SIS5513: %s, changed registers:\n", info);
-	for(i=0; i<=max; i++) {
-		pci_read_config_byte(dev, i, &reg_val);
-		if (reg_val != ide_regs_copy[i]) {
-			printk("%0#x: %0#x -> %0#x\n",
-			       i, ide_regs_copy[i], reg_val);
-			ide_regs_copy[i]=reg_val;
-			changed=1;
-		}
-	}
-
-	if (!changed) {
-		printk("none\n");
-	}
-}
-
-/* Load config registers, no printing */
-static void sis5513_load_registers(struct pci_dev* dev) {
-	int i;
-	byte max = sis5513_max_config_register();
-
-	for(i=0; i<=max; i++) {
-		pci_read_config_byte(dev, i, &(ide_regs_copy[i]));
-	}
-}
-
-/* Print a register */
-static void sis5513_print_register(int reg) {
-	printk(" %0#x:%0#x", reg, ide_regs_copy[reg]);
-}
-
-/* Print valuable registers */
-static void sis5513_print_registers(struct pci_dev* dev, char* marker) {
-	int i;
-	byte max = sis5513_max_config_register();
-
-	sis5513_load_registers(dev);
-	printk("SIS5513 %s\n", marker);
-	printk("SIS5513 dump:");
-	for(i=0x00; i<0x40; i++) {
-		if ((i % 0x10)==0) printk("\n             ");
-		sis5513_print_register(i);
-	}
-	for(; i<49; i++) {
-		sis5513_print_register(i);
-	}
-	printk("\n             ");
-
-	for(; i<=max; i++) {
-		sis5513_print_register(i);
-	}
-	printk("\n");
-}
-#endif
-
-
-/*
- * Devices supported
- */
-static const struct {
-	const char *name;
-	unsigned short host_id;
-	unsigned char chipset_family;
-	unsigned char flags;
-} SiSHostChipInfo[] = {
-//	{ "SiS750",	PCI_DEVICE_ID_SI_750,	ATA_100,	SIS5513_LATENCY },
-//	{ "SiS745",	PCI_DEVICE_ID_SI_745,	ATA_100,	SIS5513_LATENCY },
-	{ "SiS740",	PCI_DEVICE_ID_SI_740,	ATA_100,	SIS5513_LATENCY },
-	{ "SiS735",	PCI_DEVICE_ID_SI_735,	ATA_100,	SIS5513_LATENCY },
-	{ "SiS730",	PCI_DEVICE_ID_SI_730,	ATA_100a,	SIS5513_LATENCY },
-//	{ "SiS650",	PCI_DEVICE_ID_SI_650,	ATA_100,	SIS5513_LATENCY },
-//	{ "SiS645",	PCI_DEVICE_ID_SI_645,	ATA_100,	SIS5513_LATENCY },
-	{ "SiS635",	PCI_DEVICE_ID_SI_635,	ATA_100,	SIS5513_LATENCY },
-	{ "SiS640",	PCI_DEVICE_ID_SI_640,	ATA_66,		SIS5513_LATENCY },
-	{ "SiS630",	PCI_DEVICE_ID_SI_630,	ATA_66,		SIS5513_LATENCY },
-	{ "SiS620",	PCI_DEVICE_ID_SI_620,	ATA_66,		SIS5513_LATENCY },
-	{ "SiS540",	PCI_DEVICE_ID_SI_540,	ATA_66,		0},
-	{ "SiS530",	PCI_DEVICE_ID_SI_530,	ATA_66,		0},
-	{ "SiS5600",	PCI_DEVICE_ID_SI_5600,	ATA_33,		0},
-	{ "SiS5598",	PCI_DEVICE_ID_SI_5598,	ATA_33,		0},
-	{ "SiS5597",	PCI_DEVICE_ID_SI_5597,	ATA_33,		0},
-	{ "SiS5591",	PCI_DEVICE_ID_SI_5591,	ATA_33,		0},
-	{ "SiS5513",	PCI_DEVICE_ID_SI_5513,	ATA_16,		0},
-	{ "SiS5511",	PCI_DEVICE_ID_SI_5511,	ATA_16,		0},
-};
-
-/* Cycle time bits and values vary accross chip dma capabilities
-   These three arrays hold the register layout and the values to set.
-   Indexed by chipset_family and (dma_mode - XFER_UDMA_0) */
-static byte cycle_time_offset[] = {0,0,5,4,4,0,0};
-static byte cycle_time_range[] = {0,0,2,3,3,4,4};
-static byte cycle_time_value[][XFER_UDMA_5 - XFER_UDMA_0 + 1] = {
-	{0,0,0,0,0,0}, /* no udma */
-	{0,0,0,0,0,0}, /* no udma */
-	{3,2,1,0,0,0},
-	{7,5,3,2,1,0},
-	{7,5,3,2,1,0},
-	{11,7,5,4,2,1},
-	{0,0,0,0,0,0} /* not yet known, ask SiS */
-};
-
-static struct pci_dev *host_dev = NULL;
-
-
-/*
- * Printing configuration
- */
-#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int sis_get_info(char *, char **, off_t, int);
-extern int (*sis_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-static struct pci_dev *bmide_dev;
-
-static char* cable_type[] = {
-	"80 pins",
-	"40 pins"
-};
-
-static char* recovery_time[] ={
-	"12 PCICLK", "1 PCICLK",
-	"2 PCICLK", "3 PCICLK",
-	"4 PCICLK", "5 PCICLCK",
-	"6 PCICLK", "7 PCICLCK",
-	"8 PCICLK", "9 PCICLCK",
-	"10 PCICLK", "11 PCICLK",
-	"13 PCICLK", "14 PCICLK",
-	"15 PCICLK", "15 PCICLK"
-};
-
-static char* active_time[] = {
-	"8 PCICLK", "1 PCICLCK",
-	"2 PCICLK", "3 PCICLK",
-	"4 PCICLK", "5 PCICLK",
-	"6 PCICLK", "12 PCICLK"
-};
-
-static char* cycle_time[] = {
-	"Reserved", "2 CLK",
-	"3 CLK", "4 CLK",
-	"5 CLK", "6 CLK",
-	"7 CLK", "8 CLK",
-	"9 CLK", "10 CLK",
-	"11 CLK", "12 CLK",
-	"Reserved", "Reserved",
-	"Reserved", "Reserved"
-};
-
-/* Generic add master or slave info function */
-static char* get_drives_info (char *buffer, byte pos)
-{
-	byte reg00, reg01, reg10, reg11; /* timing registers */
-	char* p = buffer;
-
-/* Postwrite/Prefetch */
-	pci_read_config_byte(bmide_dev, 0x4b, &reg00);
-	p += sprintf(p, "Drive %d:        Postwrite %s \t \t Postwrite %s\n",
-		     pos, (reg00 & (0x10 << pos)) ? "Enabled" : "Disabled",
-		     (reg00 & (0x40 << pos)) ? "Enabled" : "Disabled");
-	p += sprintf(p, "                Prefetch  %s \t \t Prefetch  %s\n",
-		     (reg00 & (0x01 << pos)) ? "Enabled" : "Disabled",
-		     (reg00 & (0x04 << pos)) ? "Enabled" : "Disabled");
-
-	pci_read_config_byte(bmide_dev, 0x40+2*pos, &reg00);
-	pci_read_config_byte(bmide_dev, 0x41+2*pos, &reg01);
-	pci_read_config_byte(bmide_dev, 0x44+2*pos, &reg10);
-	pci_read_config_byte(bmide_dev, 0x45+2*pos, &reg11);
-
-/* UDMA */
-	if (chipset_family >= ATA_33) {
-		p += sprintf(p, "                UDMA %s \t \t \t UDMA %s\n",
-			     (reg01 & 0x80)  ? "Enabled" : "Disabled",
-			     (reg11 & 0x80) ? "Enabled" : "Disabled");
-
-		p += sprintf(p, "                UDMA Cycle Time    ");
-		switch(chipset_family) {
-			case ATA_33:	p += sprintf(p, cycle_time[(reg01 & 0x60) >> 5]); break;
-			case ATA_66:
-			case ATA_100a:	p += sprintf(p, cycle_time[(reg01 & 0x70) >> 4]); break;
-			case ATA_100:	p += sprintf(p, cycle_time[reg01 & 0x0F]); break;
-			case ATA_133:
-			default:	p += sprintf(p, "133+ ?"); break;
-		}
-		p += sprintf(p, " \t UDMA Cycle Time    ");
-		switch(chipset_family) {
-			case ATA_33:	p += sprintf(p, cycle_time[(reg11 & 0x60) >> 5]); break;
-			case ATA_66:
-			case ATA_100a:	p += sprintf(p, cycle_time[(reg11 & 0x70) >> 4]); break;
-			case ATA_100:	p += sprintf(p, cycle_time[reg11 & 0x0F]); break;
-			case ATA_133:
-			default:	p += sprintf(p, "133+ ?"); break;
-		}
-		p += sprintf(p, "\n");
-	}
-
-/* Data Active */
-	p += sprintf(p, "                Data Active Time   ");
-	switch(chipset_family) {
-		case ATA_00:
-		case ATA_16: /* confirmed */
-		case ATA_33:
-		case ATA_66:
-		case ATA_100a: p += sprintf(p, active_time[reg01 & 0x07]); break;
-		case ATA_100: p += sprintf(p, active_time[(reg00 & 0x70) >> 4]); break;
-		case ATA_133:
-		default: p += sprintf(p, "133+ ?"); break;
-	}
-	p += sprintf(p, " \t Data Active Time   ");
-	switch(chipset_family) {
-		case ATA_00:
-		case ATA_16:
-		case ATA_33:
-		case ATA_66:
-		case ATA_100a: p += sprintf(p, active_time[reg11 & 0x07]); break;
-		case ATA_100: p += sprintf(p, active_time[(reg10 & 0x70) >> 4]); break;
-		case ATA_133:
-		default: p += sprintf(p, "133+ ?"); break;
-	}
-	p += sprintf(p, "\n");
-
-/* Data Recovery */
-	/* warning: may need (reg&0x07) for pre ATA66 chips */
-	p += sprintf(p, "                Data Recovery Time %s \t Data Recovery Time %s\n",
-		     recovery_time[reg00 & 0x0f], recovery_time[reg10 & 0x0f]);
-
-	return p;
-}
-
-static char* get_masters_info(char* buffer)
-{
-	return get_drives_info(buffer, 0);
-}
-
-static char* get_slaves_info(char* buffer)
-{
-	return get_drives_info(buffer, 1);
-}
-
-/* Main get_info, called on /proc/ide/sis reads */
-static int sis_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	byte reg;
-	u16 reg2, reg3;
-
-	p += sprintf(p, "\nSiS 5513 ");
-	switch(chipset_family) {
-		case ATA_00: p += sprintf(p, "Unknown???"); break;
-		case ATA_16: p += sprintf(p, "DMA 16"); break;
-		case ATA_33: p += sprintf(p, "Ultra 33"); break;
-		case ATA_66: p += sprintf(p, "Ultra 66"); break;
-		case ATA_100a:
-		case ATA_100: p += sprintf(p, "Ultra 100"); break;
-		case ATA_133:
-		default: p+= sprintf(p, "Ultra 133+"); break;
-	}
-	p += sprintf(p, " chipset\n");
-	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
-
-/* Status */
-	pci_read_config_byte(bmide_dev, 0x4a, &reg);
-	p += sprintf(p, "Channel Status: ");
-	if (chipset_family < ATA_66) {
-		p += sprintf(p, "%s \t \t \t \t %s\n",
-			     (reg & 0x04) ? "On" : "Off",
-			     (reg & 0x02) ? "On" : "Off");
-	} else {
-		p += sprintf(p, "%s \t \t \t \t %s \n",
-			     (reg & 0x02) ? "On" : "Off",
-			     (reg & 0x04) ? "On" : "Off");
-	}
-
-/* Operation Mode */
-	pci_read_config_byte(bmide_dev, 0x09, &reg);
-	p += sprintf(p, "Operation Mode: %s \t \t \t %s \n",
-		     (reg & 0x01) ? "Native" : "Compatible",
-		     (reg & 0x04) ? "Native" : "Compatible");
-
-/* 80-pin cable ? */
-	if (chipset_family > ATA_33) {
-		pci_read_config_byte(bmide_dev, 0x48, &reg);
-		p += sprintf(p, "Cable Type:     %s \t \t \t %s\n",
-			     (reg & 0x10) ? cable_type[1] : cable_type[0],
-			     (reg & 0x20) ? cable_type[1] : cable_type[0]);
-	}
-
-/* Prefetch Count */
-	pci_read_config_word(bmide_dev, 0x4c, &reg2);
-	pci_read_config_word(bmide_dev, 0x4e, &reg3);
-	p += sprintf(p, "Prefetch Count: %d \t \t \t \t %d\n",
-		     reg2, reg3);
-
-	p = get_masters_info(p);
-	p = get_slaves_info(p);
-
-	return p-buffer;
-}
-#endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-
-byte sis_proc = 0;
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-
-/*
- * Configuration functions
- */
-/* Enables per-drive prefetch and postwrite */
-static void config_drive_art_rwp (ide_drive_t *drive)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-
-	byte reg4bh		= 0;
-	byte rw_prefetch	= (0x11 << drive->dn);
-
-#ifdef DEBUG
-	printk("SIS5513: config_drive_art_rwp, drive %d\n", drive->dn);
-	sis5513_load_verify_registers(dev, "config_drive_art_rwp start");
-#endif
-
-	if (drive->media != ide_disk)
-		return;
-	pci_read_config_byte(dev, 0x4b, &reg4bh);
-
-	if ((reg4bh & rw_prefetch) != rw_prefetch)
-		pci_write_config_byte(dev, 0x4b, reg4bh|rw_prefetch);
-#ifdef DEBUG
-	sis5513_load_verify_registers(dev, "config_drive_art_rwp end");
-#endif
-}
-
-
-/* Set per-drive active and recovery time */
-static void config_art_rwp_pio (ide_drive_t *drive, byte pio)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-
-	byte			timing, drive_pci, test1, test2;
-
-	unsigned short eide_pio_timing[6] = {600, 390, 240, 180, 120, 90};
-	unsigned short xfer_pio = drive->id->eide_pio_modes;
-
-#ifdef DEBUG
-	sis5513_load_verify_registers(dev, "config_drive_art_rwp_pio start");
-#endif
-
-	config_drive_art_rwp(drive);
-	pio = ide_get_best_pio_mode(drive, 255, pio, NULL);
-
-	if (xfer_pio> 4)
-		xfer_pio = 0;
-
-	if (drive->id->eide_pio_iordy > 0) {
-		for (xfer_pio = 5;
-			(xfer_pio > 0) &&
-			(drive->id->eide_pio_iordy > eide_pio_timing[xfer_pio]);
-			xfer_pio--);
-	} else {
-		xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
-			   (drive->id->eide_pio_modes & 2) ? 0x04 :
-			   (drive->id->eide_pio_modes & 1) ? 0x03 : xfer_pio;
-	}
-
-	timing = (xfer_pio >= pio) ? xfer_pio : pio;
-
-#ifdef DEBUG
-	printk("SIS5513: config_drive_art_rwp_pio, drive %d, pio %d, timing %d\n",
-	       drive->dn, pio, timing);
-#endif
-
-	switch(drive->dn) {
-		case 0:		drive_pci = 0x40; break;
-		case 1:		drive_pci = 0x42; break;
-		case 2:		drive_pci = 0x44; break;
-		case 3:		drive_pci = 0x46; break;
-		default:	return;
-	}
-
-	/* register layout changed with newer ATA100 chips */
-	if (chipset_family < ATA_100) {
-		pci_read_config_byte(dev, drive_pci, &test1);
-		pci_read_config_byte(dev, drive_pci+1, &test2);
-
-		/* Clear active and recovery timings */
-		test1 &= ~0x0F;
-		test2 &= ~0x07;
-
-		switch(timing) {
-			case 4:		test1 |= 0x01; test2 |= 0x03; break;
-			case 3:		test1 |= 0x03; test2 |= 0x03; break;
-			case 2:		test1 |= 0x04; test2 |= 0x04; break;
-			case 1:		test1 |= 0x07; test2 |= 0x06; break;
-			default:	break;
-		}
-		pci_write_config_byte(dev, drive_pci, test1);
-		pci_write_config_byte(dev, drive_pci+1, test2);
-	} else {
-		switch(timing) { /*   active  recovery
-					  v     v */
-			case 4:		test1 = 0x30|0x01; break;
-			case 3:		test1 = 0x30|0x03; break;
-			case 2:		test1 = 0x40|0x04; break;
-			case 1:		test1 = 0x60|0x07; break;
-			default:	break;
-		}
-		pci_write_config_byte(dev, drive_pci, test1);
-	}
-
-#ifdef DEBUG
-	sis5513_load_verify_registers(dev, "config_drive_art_rwp_pio start");
-#endif
-}
-
-static int config_chipset_for_pio (ide_drive_t *drive, byte pio)
-{
-	byte speed;
-
-	switch(pio) {
-		case 4:		speed = XFER_PIO_4; break;
-		case 3:		speed = XFER_PIO_3; break;
-		case 2:		speed = XFER_PIO_2; break;
-		case 1:		speed = XFER_PIO_1; break;
-		default:	speed = XFER_PIO_0; break;
-	}
-
-	config_art_rwp_pio(drive, pio);
-	drive->current_speed = speed;
-	return ide_config_drive_speed(drive, speed);
-}
-
-static int sis5513_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-
-	byte			drive_pci, reg;
-
-#ifdef DEBUG
-	sis5513_load_verify_registers(dev, "sis5513_tune_chipset start");
-	printk("SIS5513: sis5513_tune_chipset, drive %d, speed %d\n",
-	       drive->dn, speed);
-#endif
-	switch(drive->dn) {
-		case 0:		drive_pci = 0x40; break;
-		case 1:		drive_pci = 0x42; break;
-		case 2:		drive_pci = 0x44; break;
-		case 3:		drive_pci = 0x46; break;
-		default:	return ide_dma_off;
-	}
-
-#ifdef BROKEN_LEVEL
-#ifdef DEBUG
-	printk("SIS5513: BROKEN_LEVEL activated, speed=%d -> speed=%d\n", speed, BROKEN_LEVEL);
-#endif
-	if (speed > BROKEN_LEVEL) speed = BROKEN_LEVEL;
-#endif
-
-	pci_read_config_byte(dev, drive_pci+1, &reg);
-	/* Disable UDMA bit for non UDMA modes on UDMA chips */
-	if ((speed < XFER_UDMA_0) && (chipset_family > ATA_16)) {
-		reg &= 0x7F;
-		pci_write_config_byte(dev, drive_pci+1, reg);
-	}
-
-	/* Config chip for mode */
-	switch(speed) {
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		case XFER_UDMA_5:
-		case XFER_UDMA_4:
-		case XFER_UDMA_3:
-		case XFER_UDMA_2:
-		case XFER_UDMA_1:
-		case XFER_UDMA_0:
-			/* Force the UDMA bit on if we want to use UDMA */
-			reg |= 0x80;
-			/* clean reg cycle time bits */
-			reg &= ~((0xFF >> (8 - cycle_time_range[chipset_family]))
-				 << cycle_time_offset[chipset_family]);
-			/* set reg cycle time bits */
-			reg |= cycle_time_value[chipset_family-ATA_00][speed-XFER_UDMA_0]
-				<< cycle_time_offset[chipset_family];
-			pci_write_config_byte(dev, drive_pci+1, reg);
-			break;
-		case XFER_MW_DMA_2:
-		case XFER_MW_DMA_1:
-		case XFER_MW_DMA_0:
-		case XFER_SW_DMA_2:
-		case XFER_SW_DMA_1:
-		case XFER_SW_DMA_0:
-			break;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-		case XFER_PIO_4: return((int) config_chipset_for_pio(drive, 4));
-		case XFER_PIO_3: return((int) config_chipset_for_pio(drive, 3));
-		case XFER_PIO_2: return((int) config_chipset_for_pio(drive, 2));
-		case XFER_PIO_1: return((int) config_chipset_for_pio(drive, 1));
-		case XFER_PIO_0:
-		default:	 return((int) config_chipset_for_pio(drive, 0));	
-	}
-	drive->current_speed = speed;
-#ifdef DEBUG
-	sis5513_load_verify_registers(dev, "sis5513_tune_chipset end");
-#endif
-	return ((int) ide_config_drive_speed(drive, speed));
-}
-
-static void sis5513_tune_drive (ide_drive_t *drive, byte pio)
-{
-	(void) config_chipset_for_pio(drive, pio);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-/*
- * ((id->hw_config & 0x4000|0x2000) && (HWIF(drive)->udma_four))
- */
-static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
-{
-	struct hd_driveid *id	= drive->id;
-	ide_hwif_t *hwif	= HWIF(drive);
-
-	byte			speed = 0;
-
-	byte unit		= (drive->select.b.unit & 0x01);
-	byte udma_66		= eighty_ninty_three(drive);
-
-#ifdef DEBUG
-	printk("SIS5513: config_chipset_for_dma, drive %d, ultra %d\n",
-	       drive->dn, ultra);
-#endif
-
-	if ((id->dma_ultra & 0x0020) && ultra && udma_66 && (chipset_family >= ATA_100a))
-		speed = XFER_UDMA_5;
-	else if ((id->dma_ultra & 0x0010) && ultra && udma_66 && (chipset_family >= ATA_66))
-		speed = XFER_UDMA_4;
-	else if ((id->dma_ultra & 0x0008) && ultra && udma_66 && (chipset_family >= ATA_66))
-		speed = XFER_UDMA_3;
-	else if ((id->dma_ultra & 0x0004) && ultra && (chipset_family >= ATA_33))
-		speed = XFER_UDMA_2;
-	else if ((id->dma_ultra & 0x0002) && ultra && (chipset_family >= ATA_33))
-		speed = XFER_UDMA_1;
-	else if ((id->dma_ultra & 0x0001) && ultra && (chipset_family >= ATA_33))
-		speed = XFER_UDMA_0;
-	else if (id->dma_mword & 0x0004)
-		speed = XFER_MW_DMA_2;
-	else if (id->dma_mword & 0x0002)
-		speed = XFER_MW_DMA_1;
-	else if (id->dma_mword & 0x0001)
-		speed = XFER_MW_DMA_0;
-	else if (id->dma_1word & 0x0004)
-		speed = XFER_SW_DMA_2;
-	else if (id->dma_1word & 0x0002)
-		speed = XFER_SW_DMA_1;
-	else if (id->dma_1word & 0x0001)
-		speed = XFER_SW_DMA_0;
-	else
-		return ((int) ide_dma_off_quietly);
-
-	outb(inb(hwif->dma_base+2)|(1<<(5+unit)), hwif->dma_base+2);
-
-	sis5513_tune_chipset(drive, speed);
-
-	return ((int)	((id->dma_ultra >> 11) & 7) ? ide_dma_on :
-			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-			((id->dma_mword >> 8) & 7) ? ide_dma_on :
-			((id->dma_1word >> 8) & 7) ? ide_dma_on :
-						     ide_dma_off_quietly);
-}
-
-static int config_drive_xfer_rate (ide_drive_t *drive)
-{
-	struct hd_driveid *id		= drive->id;
-	ide_dma_action_t dma_func	= ide_dma_off_quietly;
-
-	(void) config_chipset_for_pio(drive, 5);
-
-	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			goto fast_ata_pio;
-		}
-		dma_func = ide_dma_off_quietly;
-		if (id->field_valid & 4) {
-			if (id->dma_ultra & 0x003F) {
-				/* Force if Capable UltraDMA */
-				dma_func = config_chipset_for_dma(drive, 1);
-				if ((id->field_valid & 2) &&
-				    (dma_func != ide_dma_on))
-					goto try_dma_modes;
-			}
-		} else if (id->field_valid & 2) {
-try_dma_modes:
-			if ((id->dma_mword & 0x0007) ||
-			    (id->dma_1word & 0x0007)) {
-				/* Force if Capable regular DMA modes */
-				dma_func = config_chipset_for_dma(drive, 0);
-				if (dma_func != ide_dma_on)
-					goto no_dma_set;
-			}
-		} else if ((ide_dmaproc(ide_dma_good_drive, drive)) &&
-			   (id->eide_dma_time > 150)) {
-			/* Consult the list of known "good" drives */
-			dma_func = config_chipset_for_dma(drive, 0);
-			if (dma_func != ide_dma_on)
-				goto no_dma_set;
-		} else {
-			goto fast_ata_pio;
-		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
-		dma_func = ide_dma_off_quietly;
-no_dma_set:
-		(void) config_chipset_for_pio(drive, 5);
-	}
-
-	return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-/* initiates/aborts (U)DMA read/write operations on a drive. */
-int sis5513_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch (func) {
-		case ide_dma_check:
-			config_drive_art_rwp(drive);
-			config_art_rwp_pio(drive, 5);
-			return config_drive_xfer_rate(drive);
-		default:
-			break;
-	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-/* Chip detection and general config */
-unsigned int __init pci_init_sis5513 (struct pci_dev *dev, const char *name)
-{
-	struct pci_dev *host;
-	int i = 0;
-
-	/* Find the chip */
-	for (i = 0; i < ARRAY_SIZE(SiSHostChipInfo) && !host_dev; i++) {
-		host = pci_find_device (PCI_VENDOR_ID_SI,
-					SiSHostChipInfo[i].host_id,
-					NULL);
-		if (!host)
-			continue;
-
-		host_dev = host;
-		chipset_family = SiSHostChipInfo[i].chipset_family;
-		printk(SiSHostChipInfo[i].name);
-		printk("\n");
-
-#ifdef DEBUG
-		sis5513_print_registers(dev, "pci_init_sis5513 start");
-#endif
-
-		if (SiSHostChipInfo[i].flags & SIS5513_LATENCY) {
-			byte latency = (chipset_family == ATA_100)? 0x80 : 0x10; /* Lacking specs */
-			pci_write_config_byte(dev, PCI_LATENCY_TIMER, latency);
-		}
-	}
-
-	/* Make general config ops here
-	   1/ tell IDE channels to operate in Compabitility mode only
-	   2/ tell old chips to allow per drive IDE timings */
-	if (host_dev) {
-		byte reg;
-		switch(chipset_family) {
-			case ATA_133:
-			case ATA_100:
-				/* Set compatibility bit */
-				pci_read_config_byte(dev, 0x49, &reg);
-				if (!(reg & 0x01)) {
-					pci_write_config_byte(dev, 0x49, reg|0x01);
-				}
-				break;
-			case ATA_100a:
-			case ATA_66:
-				/* On ATA_66 chips the bit was elsewhere */
-				pci_read_config_byte(dev, 0x52, &reg);
-				if (!(reg & 0x04)) {
-					pci_write_config_byte(dev, 0x52, reg|0x04);
-				}
-				break;
-			case ATA_33:
-				/* On ATA_33 we didn't have a single bit to set */
-				pci_read_config_byte(dev, 0x09, &reg);
-				if ((reg & 0x0f) != 0x00) {
-					pci_write_config_byte(dev, 0x09, reg&0xf0);
-				}
-			case ATA_16:
-				/* force per drive recovery and active timings
-				   needed on ATA_33 and below chips */
-				pci_read_config_byte(dev, 0x52, &reg);
-				if (!(reg & 0x08)) {
-					pci_write_config_byte(dev, 0x52, reg|0x08);
-				}
-				break;
-			case ATA_00:
-			default: break;
-		}
-
-#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS)
-		if (!sis_proc) {
-			sis_proc = 1;
-			bmide_dev = dev;
-			sis_display_info = &sis_get_info;
-		}
-#endif
-	}
-#ifdef DEBUG
-	sis5513_load_verify_registers(dev, "pci_init_sis5513 end");
-#endif
-	return 0;
-}
-
-unsigned int __init ata66_sis5513 (ide_hwif_t *hwif)
-{
-	byte reg48h = 0, ata66 = 0;
-	byte mask = hwif->channel ? 0x20 : 0x10;
-	pci_read_config_byte(hwif->pci_dev, 0x48, &reg48h);
-
-	if (chipset_family >= ATA_66) {
-		ata66 = (reg48h & mask) ? 0 : 1;
-	}
-        return ata66;
-}
-
-void __init ide_init_sis5513 (ide_hwif_t *hwif)
-{
-
-	hwif->irq = hwif->channel ? 15 : 14;
-
-	hwif->tuneproc = &sis5513_tune_drive;
-	hwif->speedproc = &sis5513_tune_chipset;
-
-	if (!(hwif->dma_base))
-		return;
-
-	if (host_dev) {
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		if (chipset_family > ATA_16) {
-			hwif->autodma = noautodma ? 0 : 1;
-			hwif->dmaproc = &sis5513_dmaproc;
-		} else {
-#endif
-			hwif->autodma = 0;
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		}
-#endif
-	}
-	return;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/sl82c105.c linux-2.4.21-pre6/drivers/ide/sl82c105.c
--- linux-2.4.20/drivers/ide/sl82c105.c	2001-09-07 17:45:30.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/sl82c105.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,274 +0,0 @@
-/*
- * linux/drivers/ide/sl82c105.c
- *
- * SL82C105/Winbond 553 IDE driver
- *
- * Maintainer unknown.
- *
- * Drive tuning added from Rebel.com's kernel sources
- *  -- Russell King (15/11/98) linux@arm.linux.org.uk
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/pci.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#include "ide_modes.h"
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-/*
- * Convert a PIO mode and cycle time to the required on/off
- * times for the interface.  This has protection against run-away
- * timings.
- */
-static unsigned int get_timing_sl82c105(ide_pio_data_t *p)
-{
-	unsigned int cmd_on;
-	unsigned int cmd_off;
-
-	cmd_on = (ide_pio_timings[p->pio_mode].active_time + 29) / 30;
-	cmd_off = (p->cycle_time - 30 * cmd_on + 29) / 30;
-
-	if (cmd_on > 32)
-		cmd_on = 32;
-	if (cmd_on == 0)
-		cmd_on = 1;
-
-	if (cmd_off > 32)
-		cmd_off = 32;
-	if (cmd_off == 0)
-		cmd_off = 1;
-
-	return (cmd_on - 1) << 8 | (cmd_off - 1) | (p->use_iordy ? 0x40 : 0x00);
-}
-
-/*
- * Configure the drive and chipset for PIO
- */
-static void config_for_pio(ide_drive_t *drive, int pio, int report)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	struct pci_dev *dev = hwif->pci_dev;
-	ide_pio_data_t p;
-	unsigned short drv_ctrl = 0x909;
-	unsigned int xfer_mode, reg;
-
-	reg = (hwif->channel ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
-
-	pio = ide_get_best_pio_mode(drive, pio, 5, &p);
-
-	switch (pio) {
-	default:
-	case 0:		xfer_mode = XFER_PIO_0;		break;
-	case 1:		xfer_mode = XFER_PIO_1;		break;
-	case 2:		xfer_mode = XFER_PIO_2;		break;
-	case 3:		xfer_mode = XFER_PIO_3;		break;
-	case 4:		xfer_mode = XFER_PIO_4;		break;
-	}
-
-	if (ide_config_drive_speed(drive, xfer_mode) == 0)
-		drv_ctrl = get_timing_sl82c105(&p);
-
-	if (drive->using_dma == 0) {
-		/*
-		 * If we are actually using MW DMA, then we can not
-		 * reprogram the interface drive control register.
-		 */
-		pci_write_config_word(dev, reg, drv_ctrl);
-		pci_read_config_word(dev, reg, &drv_ctrl);
-
-		if (report) {
-			printk("%s: selected %s (%dns) (%04X)\n", drive->name,
-			       ide_xfer_verbose(xfer_mode), p.cycle_time, drv_ctrl);
-		}
-	}
-}
-
-/*
- * Configure the drive and the chipset for DMA
- */
-static int config_for_dma(ide_drive_t *drive)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	struct pci_dev *dev = hwif->pci_dev;
-	unsigned short drv_ctrl = 0x909;
-	unsigned int reg;
-
-	reg = (hwif->channel ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
-
-	if (ide_config_drive_speed(drive, XFER_MW_DMA_2) == 0)
-		drv_ctrl = 0x0240;
-
-	pci_write_config_word(dev, reg, drv_ctrl);
-
-	return 0;
-}
-
-/*
- * Check to see if the drive and
- * chipset is capable of DMA mode
- */
-static int sl82c105_check_drive(ide_drive_t *drive)
-{
-	ide_dma_action_t dma_func = ide_dma_off_quietly;
-
-	do {
-		struct hd_driveid *id = drive->id;
-		ide_hwif_t *hwif = HWIF(drive);
-
-		if (!hwif->autodma)
-			break;
-
-		if (!id || !(id->capability & 1))
-			break;
-
-		/* Consult the list of known "bad" drives */
-		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
-			dma_func = ide_dma_off;
-			break;
-		}
-
-		if (id->field_valid & 2) {
-			if  (id->dma_mword & 7 || id->dma_1word & 7)
-				dma_func = ide_dma_on;
-			break;
-		}
-
-		if (ide_dmaproc(ide_dma_good_drive, drive)) {
-			dma_func = ide_dma_on;
-			break;
-		}
-	} while (0);
-
-	return HWIF(drive)->dmaproc(dma_func, drive);
-}
-
-/*
- * Our own dmaproc, only to intercept ide_dma_check
- */
-static int sl82c105_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch (func) {
-	case ide_dma_check:
-		return sl82c105_check_drive(drive);
-	case ide_dma_on:
-		if (config_for_dma(drive))
-			func = ide_dma_off;
-		/* fall through */
-	case ide_dma_off_quietly:
-	case ide_dma_off:
-		config_for_pio(drive, 4, 0);
-		break;
-	default:
-		break;
-	}
-	return ide_dmaproc(func, drive);
-}
-
-/*
- * We only deal with PIO mode here - DMA mode 'using_dma' is not
- * initialised at the point that this function is called.
- */
-static void tune_sl82c105(ide_drive_t *drive, byte pio)
-{
-	config_for_pio(drive, pio, 1);
-
-	/*
-	 * We support 32-bit I/O on this interface, and it
-	 * doesn't have problems with interrupts.
-	 */
-	drive->io_32bit = 1;
-	drive->unmask = 1;
-}
-
-/*
- * Return the revision of the Winbond bridge
- * which this function is part of.
- */
-static unsigned int sl82c105_bridge_revision(struct pci_dev *dev)
-{
-	struct pci_dev *bridge;
-	unsigned char rev;
-
-	bridge = pci_find_device(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_83C553, NULL);
-
-	/*
-	 * If we are part of a Winbond 553
-	 */
-	if (!bridge || bridge->class >> 8 != PCI_CLASS_BRIDGE_ISA)
-		return -1;
-
-	if (bridge->bus != dev->bus ||
-	    PCI_SLOT(bridge->devfn) != PCI_SLOT(dev->devfn))
-		return -1;
-
-	/*
-	 * We need to find function 0's revision, not function 1
-	 */
-	pci_read_config_byte(bridge, PCI_REVISION_ID, &rev);
-
-	return rev;
-}
-
-/*
- * Enable the PCI device
- */
-unsigned int __init pci_init_sl82c105(struct pci_dev *dev, const char *msg)
-{
-	unsigned char ctrl_stat;
-
-	/*
-	 * Enable the ports
-	 */
-	pci_read_config_byte(dev, 0x40, &ctrl_stat);
-	pci_write_config_byte(dev, 0x40, ctrl_stat | 0x33);
-
-	return dev->irq;
-}
-
-void __init dma_init_sl82c105(ide_hwif_t *hwif, unsigned long dma_base)
-{
-	unsigned int rev;
-	byte dma_state;
-
-	dma_state = inb(dma_base + 2);
-	rev = sl82c105_bridge_revision(hwif->pci_dev);
-	if (rev <= 5) {
-		hwif->autodma = 0;
-		hwif->drives[0].autotune = 1;
-		hwif->drives[1].autotune = 1;
-		printk("    %s: Winbond 553 bridge revision %d, BM-DMA disabled\n",
-		       hwif->name, rev);
-		dma_state &= ~0x60;
-	} else {
-		dma_state |= 0x60;
-		hwif->autodma = 1;
-	}
-	outb(dma_state, dma_base + 2);
-
-	hwif->dmaproc = NULL;
-	ide_setup_dma(hwif, dma_base, 8);
-	if (hwif->dmaproc)
-		hwif->dmaproc = sl82c105_dmaproc;
-}
-
-/*
- * Initialise the chip
- */
-void __init ide_init_sl82c105(ide_hwif_t *hwif)
-{
-	hwif->tuneproc = tune_sl82c105;
-}
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/slc90e66.c linux-2.4.21-pre6/drivers/ide/slc90e66.c
--- linux-2.4.20/drivers/ide/slc90e66.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/slc90e66.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,396 +0,0 @@
-/*
- *  linux/drivers/ide/slc90e66.c	Version 0.10	October 4, 2000
- *
- *  Copyright (C) 2000 Andre Hedrick <andre@linux-ide.org>
- *  May be copied or modified under the terms of the GNU General Public License
- *
- * 00:07.1 IDE interface: EFAR Microsystems:
- * 		Unknown device 9130 (prog-if 8a [Master SecP PriP])
- * Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV-
- * 		VGASnoop- ParErr- Stepping- SERR- FastB2B-
- * Status: Cap- 66Mhz- UDF- FastB2B- ParErr- DEVSEL=medium
- * 		>TAbort- <TAbort- <MAbort- >SERR- <PERR-
- * Latency: 64
- * Interrupt: pin A routed to IRQ 255
- * Region 4: I/O ports at 1050
- *
- * 00: 55 10 30 91 05 00 00 02 00 8a 01 01 00 40 00 00
- * 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 20: 51 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 30: 00 00 00 00 00 00 00 00 00 00 00 00 ff 01 00 00
- * 40: 37 e3 33 e3 b9 55 01 00 0d 00 04 22 00 00 00 00
- * 50: 00 00 ff a0 00 00 00 08 40 00 00 00 00 00 00 00
- * 60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- *
- * This a look-a-like variation of the ICH0 PIIX4 Ultra-66,
- * but this keeps the ISA-Bridge and slots alive.
- *
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-#define SLC90E66_DEBUG_DRIVE_INFO		0
-
-#define DISPLAY_SLC90E66_TIMINGS
-
-#if defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static int slc90e66_get_info(char *, char **, off_t, int);
-extern int (*slc90e66_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-extern char *ide_media_verbose(ide_drive_t *);
-static struct pci_dev *bmide_dev;
-
-static int slc90e66_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	u32 bibma = pci_resource_start(bmide_dev, 4);
-        u16 reg40 = 0, psitre = 0, reg42 = 0, ssitre = 0;
-	u8  c0 = 0, c1 = 0;
-	u8  reg44 = 0, reg47 = 0, reg48 = 0, reg4a = 0, reg4b = 0;
-
-	pci_read_config_word(bmide_dev, 0x40, &reg40);
-	pci_read_config_word(bmide_dev, 0x42, &reg42);
-	pci_read_config_byte(bmide_dev, 0x44, &reg44);
-	pci_read_config_byte(bmide_dev, 0x47, &reg47);
-	pci_read_config_byte(bmide_dev, 0x48, &reg48);
-	pci_read_config_byte(bmide_dev, 0x4a, &reg4a);
-	pci_read_config_byte(bmide_dev, 0x4b, &reg4b);
-
-	psitre = (reg40 & 0x4000) ? 1 : 0;
-	ssitre = (reg42 & 0x4000) ? 1 : 0;
-
-        /*
-         * at that point bibma+0x2 et bibma+0xa are byte registers
-         * to investigate:
-         */
-#ifdef __mips__	/* only for mips? */
-	c0 = inb_p(bibma + 0x02);
-	c1 = inb_p(bibma + 0x0a);
-#else
-	c0 = inb_p((unsigned short)bibma + 0x02);
-	c1 = inb_p((unsigned short)bibma + 0x0a);
-#endif
-
-	p += sprintf(p, "                                SLC90E66 Chipset.\n");
-	p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n");
-	p += sprintf(p, "                %sabled                         %sabled\n",
-			(c0&0x80) ? "dis" : " en",
-			(c1&0x80) ? "dis" : " en");
-	p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
-	p += sprintf(p, "DMA enabled:    %s              %s             %s               %s\n",
-			(c0&0x20) ? "yes" : "no ",
-			(c0&0x40) ? "yes" : "no ",
-			(c1&0x20) ? "yes" : "no ",
-			(c1&0x40) ? "yes" : "no " );
-	p += sprintf(p, "UDMA enabled:   %s              %s             %s               %s\n",
-			(reg48&0x01) ? "yes" : "no ",
-			(reg48&0x02) ? "yes" : "no ",
-			(reg48&0x04) ? "yes" : "no ",
-			(reg48&0x08) ? "yes" : "no " );
-	p += sprintf(p, "UDMA enabled:   %s                %s               %s                 %s\n",
-			((reg4a&0x04)==0x04) ? "4" :
-			((reg4a&0x03)==0x03) ? "3" :
-			(reg4a&0x02) ? "2" :
-			(reg4a&0x01) ? "1" :
-			(reg4a&0x00) ? "0" : "X",
-			((reg4a&0x40)==0x40) ? "4" :
-			((reg4a&0x30)==0x30) ? "3" :
-			(reg4a&0x20) ? "2" :
-			(reg4a&0x10) ? "1" :
-			(reg4a&0x00) ? "0" : "X",
-			((reg4b&0x04)==0x04) ? "4" :
-			((reg4b&0x03)==0x03) ? "3" :
-			(reg4b&0x02) ? "2" :
-			(reg4b&0x01) ? "1" :
-			(reg4b&0x00) ? "0" : "X",
-			((reg4b&0x40)==0x40) ? "4" :
-			((reg4b&0x30)==0x30) ? "3" :
-			(reg4b&0x20) ? "2" :
-			(reg4b&0x10) ? "1" :
-			(reg4b&0x00) ? "0" : "X");
-
-	p += sprintf(p, "UDMA\n");
-	p += sprintf(p, "DMA\n");
-	p += sprintf(p, "PIO\n");
-
-/*
- *	FIXME.... Add configuration junk data....blah blah......
- */
-
-	return p-buffer;	 /* => must be less than 4k! */
-}
-#endif  /* defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-/*
- *  Used to set Fifo configuration via kernel command line:
- */
-
-byte slc90e66_proc = 0;
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-/*
- *
- */
-static byte slc90e66_dma_2_pio (byte xfer_rate) {
-	switch(xfer_rate) {
-		case XFER_UDMA_4:
-		case XFER_UDMA_3:
-		case XFER_UDMA_2:
-		case XFER_UDMA_1:
-		case XFER_UDMA_0:
-		case XFER_MW_DMA_2:
-		case XFER_PIO_4:
-			return 4;
-		case XFER_MW_DMA_1:
-		case XFER_PIO_3:
-			return 3;
-		case XFER_SW_DMA_2:
-		case XFER_PIO_2:
-			return 2;
-		case XFER_MW_DMA_0:
-		case XFER_SW_DMA_1:
-		case XFER_SW_DMA_0:
-		case XFER_PIO_1:
-		case XFER_PIO_0:
-		case XFER_PIO_SLOW:
-		default:
-			return 0;
-	}
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-/*
- *  Based on settings done by AMI BIOS
- *  (might be useful if drive is not registered in CMOS for any reason).
- */
-static void slc90e66_tune_drive (ide_drive_t *drive, byte pio)
-{
-	unsigned long flags;
-	u16 master_data;
-	byte slave_data;
-	int is_slave		= (&HWIF(drive)->drives[1] == drive);
-	int master_port		= HWIF(drive)->index ? 0x42 : 0x40;
-	int slave_port		= 0x44;
-				 /* ISP  RTC */
-	byte timings[][2]	= { { 0, 0 },
-				    { 0, 0 },
-				    { 1, 0 },
-				    { 2, 1 },
-				    { 2, 3 }, };
-
-	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
-	pci_read_config_word(HWIF(drive)->pci_dev, master_port, &master_data);
-	if (is_slave) {
-		master_data = master_data | 0x4000;
-		if (pio > 1)
-			/* enable PPE, IE and TIME */
-			master_data = master_data | 0x0070;
-		pci_read_config_byte(HWIF(drive)->pci_dev, slave_port, &slave_data);
-		slave_data = slave_data & (HWIF(drive)->index ? 0x0f : 0xf0);
-		slave_data = slave_data | ((timings[pio][0] << 2) | (timings[pio][1]
-					   << (HWIF(drive)->index ? 4 : 0)));
-	} else {
-		master_data = master_data & 0xccf8;
-		if (pio > 1)
-			/* enable PPE, IE and TIME */
-			master_data = master_data | 0x0007;
-		master_data = master_data | (timings[pio][0] << 12) |
-			      (timings[pio][1] << 8);
-	}
-	save_flags(flags);
-	cli();
-	pci_write_config_word(HWIF(drive)->pci_dev, master_port, master_data);
-	if (is_slave)
-		pci_write_config_byte(HWIF(drive)->pci_dev, slave_port, slave_data);
-	restore_flags(flags);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int slc90e66_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte maslave		= hwif->channel ? 0x42 : 0x40;
-	int a_speed		= 7 << (drive->dn * 4);
-	int u_flag		= 1 << drive->dn;
-	int u_speed		= 0;
-	int err			= 0;
-	int			sitre;
-	short			reg4042, reg44, reg48, reg4a;
-
-	pci_read_config_word(dev, maslave, &reg4042);
-	sitre = (reg4042 & 0x4000) ? 1 : 0;
-	pci_read_config_word(dev, 0x44, &reg44);
-	pci_read_config_word(dev, 0x48, &reg48);
-	pci_read_config_word(dev, 0x4a, &reg4a);
-
-	switch(speed) {
-		case XFER_UDMA_4:	u_speed = 4 << (drive->dn * 4); break;
-		case XFER_UDMA_3:	u_speed = 3 << (drive->dn * 4); break;
-		case XFER_UDMA_2:	u_speed = 2 << (drive->dn * 4); break;
-		case XFER_UDMA_1:	u_speed = 1 << (drive->dn * 4); break;
-		case XFER_UDMA_0:	u_speed = 0 << (drive->dn * 4); break;
-		case XFER_MW_DMA_2:
-		case XFER_MW_DMA_1:
-		case XFER_SW_DMA_2:	break;
-#if 0	/* allow PIO modes */
-		default:		return -1;
-#endif
-	}
-
-	if (speed >= XFER_UDMA_0) {
-		if (!(reg48 & u_flag))
-			pci_write_config_word(dev, 0x48, reg48|u_flag);
-		if ((reg4a & u_speed) != u_speed) {
-			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
-			pci_read_config_word(dev, 0x4a, &reg4a);
-			pci_write_config_word(dev, 0x4a, reg4a|u_speed);
-		}
-	}
-	if (speed < XFER_UDMA_0) {
-		if (reg48 & u_flag)
-			pci_write_config_word(dev, 0x48, reg48 & ~u_flag);
-		if (reg4a & a_speed)
-			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
-	}
-
-	slc90e66_tune_drive(drive, slc90e66_dma_2_pio(speed));
-
-#if SLC90E66_DEBUG_DRIVE_INFO
-	printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive->dn);
-#endif /* SLC90E66_DEBUG_DRIVE_INFO */
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-	err = ide_config_drive_speed(drive, speed);
-	drive->current_speed = speed;
-	return err;
-}
-
-static int slc90e66_config_drive_for_dma (ide_drive_t *drive)
-{
-	struct hd_driveid *id	= drive->id;
-	int ultra		= 1;
-	byte speed		= 0;
-	byte udma_66		= eighty_ninty_three(drive);
-
-#if 1 /* allow PIO modes */
-	if (!HWIF(drive)->autodma) {
-		speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
-		(void) slc90e66_tune_chipset(drive, speed);
-		return ((int) ide_dma_off_quietly);
-	}
-#endif
-	if ((id->dma_ultra & 0x0010) && (ultra)) {
-		speed = (udma_66) ? XFER_UDMA_4 : XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0008) && (ultra)) {
-		speed = (udma_66) ? XFER_UDMA_3 : XFER_UDMA_1;
-	} else if ((id->dma_ultra & 0x0004) && (ultra)) {
-		speed = XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0002) && (ultra)) {
-		speed = XFER_UDMA_1;
-	} else if ((id->dma_ultra & 0x0001) && (ultra)) {
-		speed = XFER_UDMA_0;
-	} else if (id->dma_mword & 0x0004) {
-		speed = XFER_MW_DMA_2;
-	} else if (id->dma_mword & 0x0002) {
-		speed = XFER_MW_DMA_1;
-	} else if (id->dma_1word & 0x0004) {
-		speed = XFER_SW_DMA_2;
-        } else {
-		speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
-	}
-
-	(void) slc90e66_tune_chipset(drive, speed);
-
-	return ((int)	((id->dma_ultra >> 11) & 7) ? ide_dma_on :
-			((id->dma_ultra >> 8) & 7) ? ide_dma_on :
-			((id->dma_mword >> 8) & 7) ? ide_dma_on :
-			((id->dma_1word >> 8) & 7) ? ide_dma_on :
-						     ide_dma_off_quietly);
-}
-
-static int slc90e66_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch (func) {
-		case ide_dma_check:
-			 return ide_dmaproc((ide_dma_action_t) slc90e66_config_drive_for_dma(drive), drive);
-		default :
-			break;
-	}
-	/* Other cases are done by generic IDE-DMA code. */
-	return ide_dmaproc(func, drive);
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-unsigned int __init pci_init_slc90e66 (struct pci_dev *dev, const char *name)
-{
-#if defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!slc90e66_proc) {
-		slc90e66_proc = 1;
-		bmide_dev = dev;
-		slc90e66_display_info = &slc90e66_get_info;
-	}
-#endif /* DISPLAY_SLC90E66_TIMINGS && CONFIG_PROC_FS */
-	return 0;
-}
-
-unsigned int __init ata66_slc90e66 (ide_hwif_t *hwif)
-{
-#if 1
-	byte reg47 = 0, ata66 = 0;
-	byte mask = hwif->channel ? 0x01 : 0x02;	/* bit0:Primary */
-
-	pci_read_config_byte(hwif->pci_dev, 0x47, &reg47);
-
-	ata66 = (reg47 & mask) ? 0 : 1;	/* bit[0(1)]: 0:80, 1:40 */
-#else
-	byte ata66 = 0;
-#endif
-	return ata66;
-}
-
-void __init ide_init_slc90e66 (ide_hwif_t *hwif)
-{
-	if (!hwif->irq)
-		hwif->irq = hwif->channel ? 15 : 14;
-
-	hwif->tuneproc = &slc90e66_tune_drive;
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-
-	if (!hwif->dma_base)
-		return;
-
-	hwif->autodma = 0;
-#ifdef CONFIG_BLK_DEV_IDEDMA 
-	if (!noautodma)
-		hwif->autodma = 1;
-	hwif->dmaproc = &slc90e66_dmaproc;
-	hwif->speedproc = &slc90e66_tune_chipset;
-#endif /* !CONFIG_BLK_DEV_IDEDMA */
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/trm290.c linux-2.4.21-pre6/drivers/ide/trm290.c
--- linux-2.4.20/drivers/ide/trm290.c	2000-06-20 14:52:36.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/trm290.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,289 +0,0 @@
-/*
- *  linux/drivers/ide/trm290.c		Version 1.02	Mar. 18, 2000
- *
- *  Copyright (c) 1997-1998  Mark Lord
- *  May be copied or modified under the terms of the GNU General Public License
- */
-
-/*
- * This module provides support for the bus-master IDE DMA function
- * of the Tekram TRM290 chip, used on a variety of PCI IDE add-on boards,
- * including a "Precision Instruments" board.  The TRM290 pre-dates
- * the sff-8038 standard (ide-dma.c) by a few months, and differs
- * significantly enough to warrant separate routines for some functions,
- * while re-using others from ide-dma.c.
- *
- * EXPERIMENTAL!  It works for me (a sample of one).
- *
- * Works reliably for me in DMA mode (READs only),
- * DMA WRITEs are disabled by default (see #define below);
- *
- * DMA is not enabled automatically for this chipset,
- * but can be turned on manually (with "hdparm -d1") at run time.
- *
- * I need volunteers with "spare" drives for further testing
- * and development, and maybe to help figure out the peculiarities.
- * Even knowing the registers (below), some things behave strangely.
- */
-
-#define TRM290_NO_DMA_WRITES	/* DMA writes seem unreliable sometimes */
-
-/*
- * TRM-290 PCI-IDE2 Bus Master Chip
- * ================================
- * The configuration registers are addressed in normal I/O port space
- * and are used as follows:
- *
- * trm290_base depends on jumper settings, and is probed for by ide-dma.c
- *
- * trm290_base+2 when WRITTEN: chiptest register (byte, write-only)
- *	bit7 must always be written as "1"
- *	bits6-2 undefined
- *	bit1 1=legacy_compatible_mode, 0=native_pci_mode
- *	bit0 1=test_mode, 0=normal(default)
- *
- * trm290_base+2 when READ: status register (byte, read-only)
- *	bits7-2 undefined
- *	bit1 channel0 busmaster interrupt status 0=none, 1=asserted
- *	bit0 channel0 interrupt status 0=none, 1=asserted
- *
- * trm290_base+3 Interrupt mask register
- *	bits7-5 undefined
- *	bit4 legacy_header: 1=present, 0=absent
- *	bit3 channel1 busmaster interrupt status 0=none, 1=asserted (read only)
- *	bit2 channel1 interrupt status 0=none, 1=asserted (read only)
- *	bit1 channel1 interrupt mask: 1=masked, 0=unmasked(default)
- *	bit0 channel0 interrupt mask: 1=masked, 0=unmasked(default)
- *
- * trm290_base+1 "CPR" Config Pointer Register (byte)
- *	bit7 1=autoincrement CPR bits 2-0 after each access of CDR
- *	bit6 1=min. 1 wait-state posted write cycle (default), 0=0 wait-state
- *	bit5 0=enabled master burst access (default), 1=disable  (write only)
- *	bit4 PCI DEVSEL# timing select: 1=medium(default), 0=fast
- *	bit3 0=primary IDE channel, 1=secondary IDE channel
- *	bits2-0 register index for accesses through CDR port
- *
- * trm290_base+0 "CDR" Config Data Register (word)
- *	two sets of seven config registers,
- *	selected by CPR bit 3 (channel) and CPR bits 2-0 (index 0 to 6),
- *	each index defined below:
- *
- * Index-0 Base address register for command block (word)
- *	defaults: 0x1f0 for primary, 0x170 for secondary
- *
- * Index-1 general config register (byte)
- *	bit7 1=DMA enable, 0=DMA disable
- *	bit6 1=activate IDE_RESET, 0=no action (default)
- *	bit5 1=enable IORDY, 0=disable IORDY (default)
- *	bit4 0=16-bit data port(default), 1=8-bit (XT) data port
- *	bit3 interrupt polarity: 1=active_low, 0=active_high(default)
- *	bit2 power-saving-mode(?): 1=enable, 0=disable(default) (write only)
- *	bit1 bus_master_mode(?): 1=enable, 0=disable(default)
- *	bit0 enable_io_ports: 1=enable(default), 0=disable
- *
- * Index-2 read-ahead counter preload bits 0-7 (byte, write only)
- *	bits7-0 bits7-0 of readahead count
- *
- * Index-3 read-ahead config register (byte, write only)
- *	bit7 1=enable_readahead, 0=disable_readahead(default)
- *	bit6 1=clear_FIFO, 0=no_action
- *	bit5 undefined
- *	bit4 mode4 timing control: 1=enable, 0=disable(default)
- *	bit3 undefined
- *	bit2 undefined
- *	bits1-0 bits9-8 of read-ahead count
- *
- * Index-4 base address register for control block (word)
- *	defaults: 0x3f6 for primary, 0x376 for secondary
- *
- * Index-5 data port timings (shared by both drives) (byte)
- *	standard PCI "clk" (clock) counts, default value = 0xf5
- *
- *	bits7-6 setup time:  00=1clk, 01=2clk, 10=3clk, 11=4clk
- *	bits5-3 hold time:	000=1clk, 001=2clk, 010=3clk,
- *				011=4clk, 100=5clk, 101=6clk,
- *				110=8clk, 111=12clk
- *	bits2-0 active time:	000=2clk, 001=3clk, 010=4clk,
- *				011=5clk, 100=6clk, 101=8clk,
- *				110=12clk, 111=16clk
- *
- * Index-6 command/control port timings (shared by both drives) (byte)
- *	same layout as Index-5, default value = 0xde
- *
- * Suggested CDR programming for PIO mode0 (600ns):
- *	0x01f0,0x21,0xff,0x80,0x03f6,0xf5,0xde	; primary
- *	0x0170,0x21,0xff,0x80,0x0376,0xf5,0xde	; secondary
- *
- * Suggested CDR programming for PIO mode3 (180ns):
- *	0x01f0,0x21,0xff,0x80,0x03f6,0x09,0xde	; primary
- *	0x0170,0x21,0xff,0x80,0x0376,0x09,0xde	; secondary
- *
- * Suggested CDR programming for PIO mode4 (120ns):
- *	0x01f0,0x21,0xff,0x80,0x03f6,0x00,0xde	; primary
- *	0x0170,0x21,0xff,0x80,0x0376,0x00,0xde	; secondary
- *
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/init.h>
-#include <linux/hdreg.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/ide.h>
-
-#include <asm/io.h>
-
-static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	unsigned int reg;
-	unsigned long flags;
-
-	/* select PIO or DMA */
-	reg = use_dma ? (0x21 | 0x82) : (0x21 & ~0x82);
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-
-	if (reg != hwif->select_data) {
-		hwif->select_data = reg;
-		outb(0x51|(hwif->channel<<3), hwif->config_data+1);	/* set PIO/DMA */
-		outw(reg & 0xff, hwif->config_data);
-	}
-
-	/* enable IRQ if not probing */
-	if (drive->present) {
-		reg = inw(hwif->config_data+3) & 0x13;
-		reg &= ~(1 << hwif->channel);
-		outw(reg, hwif->config_data+3);
-	}
-
-	__restore_flags(flags);	/* local CPU only */
-}
-
-static void trm290_selectproc (ide_drive_t *drive)
-{
-	trm290_prepare_drive(drive, drive->using_dma);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int trm290_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	unsigned int count, reading = 2, writing = 0;
-
-	switch (func) {
-		case ide_dma_write:
-			reading = 0;
-			writing = 1;
-#ifdef TRM290_NO_DMA_WRITES
-			break;	/* always use PIO for writes */
-#endif
-		case ide_dma_read:
-			if (!(count = ide_build_dmatable(drive, func)))
-				break;		/* try PIO instead of DMA */
-			trm290_prepare_drive(drive, 1);	/* select DMA xfer */
-			outl(hwif->dmatable_dma|reading|writing, hwif->dma_base);
-			drive->waiting_for_dma = 1;
-			outw((count * 2) - 1, hwif->dma_base+2); /* start DMA */
-			if (drive->media != ide_disk)
-				return 0;
-			ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
-			OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
-			return 0;
-		case ide_dma_begin:
-			return 0;
-		case ide_dma_end:
-			drive->waiting_for_dma = 0;
-			ide_destroy_dmatable(drive);		/* purge DMA mappings */
-			return (inw(hwif->dma_base+2) != 0x00ff);
-		case ide_dma_test_irq:
-			return (inw(hwif->dma_base+2) == 0x00ff);
-		default:
-			return ide_dmaproc(func, drive);
-	}
-	trm290_prepare_drive(drive, 0);	/* select PIO xfer */
-	return 1;
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-/*
- * Invoked from ide-dma.c at boot time.
- */
-void __init ide_init_trm290 (ide_hwif_t *hwif)
-{
-	unsigned int cfgbase = 0;
-	unsigned long flags;
-	byte reg;
-	struct pci_dev *dev = hwif->pci_dev;
-
-	hwif->chipset = ide_trm290;
-	cfgbase = pci_resource_start(dev, 4);
-	if ((dev->class & 5) && cfgbase)
-	{
-		hwif->config_data = cfgbase;
-		printk("TRM290: chip config base at 0x%04lx\n", hwif->config_data);
-	} else {
-		hwif->config_data = 0x3df0;
-		printk("TRM290: using default config base at 0x%04lx\n", hwif->config_data);
-	}
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-	/* put config reg into first byte of hwif->select_data */
-	outb(0x51|(hwif->channel<<3), hwif->config_data+1);
-	hwif->select_data = 0x21;			/* select PIO as default */
-	outb(hwif->select_data, hwif->config_data);
-	reg = inb(hwif->config_data+3);			/* get IRQ info */
-	reg = (reg & 0x10) | 0x03;			/* mask IRQs for both ports */
-	outb(reg, hwif->config_data+3);
-	__restore_flags(flags);	/* local CPU only */
-
-	if ((reg & 0x10))
-		hwif->irq = hwif->channel ? 15 : 14;	/* legacy mode */
-	else if (!hwif->irq && hwif->mate && hwif->mate->irq)
-		hwif->irq = hwif->mate->irq;		/* sharing IRQ with mate */
-	ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->channel ? 0x0080 : 0x0000), 3);
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	hwif->dmaproc = &trm290_dmaproc;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-	hwif->selectproc = &trm290_selectproc;
-	hwif->autodma = 0;				/* play it safe for now */
-#if 1
-	{
-		/*
-		 * My trm290-based card doesn't seem to work with all possible values
-		 * for the control basereg, so this kludge ensures that we use only
-		 * values that are known to work.  Ugh.		-ml
-		 */
-		unsigned short old, compat = hwif->channel ? 0x374 : 0x3f4;
-		static unsigned short next_offset = 0;
-
-		outb(0x54|(hwif->channel<<3), hwif->config_data+1);
-		old = inw(hwif->config_data) & ~1;
-		if (old != compat && inb(old+2) == 0xff) {
-			compat += (next_offset += 0x400);	/* leave lower 10 bits untouched */
-#if 1
-			if (ide_check_region(compat + 2, 1))
-				printk("Aieee %s: ide_check_region failure at 0x%04x\n", hwif->name, (compat + 2));
-			/*
-			 * The region check is not needed; however.........
-			 * Since this is the checked in ide-probe.c,
-			 * this is only an assignment.
-			 */
-#endif
-			hwif->io_ports[IDE_CONTROL_OFFSET] = compat + 2;
-			outw(compat|1, hwif->config_data);
-			printk("%s: control basereg workaround: old=0x%04x, new=0x%04x\n", hwif->name, old, inw(hwif->config_data) & ~1);
-		}
-	}
-#endif
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/umc8672.c linux-2.4.21-pre6/drivers/ide/umc8672.c
--- linux-2.4.20/drivers/ide/umc8672.c	2000-04-14 05:54:26.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/umc8672.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,160 +0,0 @@
-/*
- *  linux/drivers/ide/umc8672.c		Version 0.05	Jul 31, 1996
- *
- *  Copyright (C) 1995-1996  Linus Torvalds & author (see below)
- */
-
-/*
- *  Principal Author/Maintainer:  PODIEN@hml2.atlas.de (Wolfram Podien)
- *
- *  This file provides support for the advanced features
- *  of the UMC 8672 IDE interface.
- *
- *  Version 0.01	Initial version, hacked out of ide.c,
- *			and #include'd rather than compiled separately.
- *			This will get cleaned up in a subsequent release.
- *
- *  Version 0.02	now configs/compiles separate from ide.c  -ml
- *  Version 0.03	enhanced auto-tune, fix display bug
- *  Version 0.05	replace sti() with restore_flags()  -ml
- *			add detection of possible race condition  -ml
- */
-
-/*
- * VLB Controller Support from 
- * Wolfram Podien
- * Rohoefe 3
- * D28832 Achim
- * Germany
- *
- * To enable UMC8672 support there must a lilo line like
- * append="ide0=umc8672"...
- * To set the speed according to the abilities of the hardware there must be a
- * line like
- * #define UMC_DRIVE0 11
- * in the beginning of the driver, which sets the speed of drive 0 to 11 (there
- * are some lines present). 0 - 11 are allowed speed values. These values are
- * the results from the DOS speed test program supplied from UMC. 11 is the 
- * highest speed (about PIO mode 3)
- */
-#define REALLY_SLOW_IO		/* some systems can safely undef this */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "ide_modes.h"
-
-/*
- * Default speeds.  These can be changed with "auto-tune" and/or hdparm.
- */
-#define UMC_DRIVE0      1              /* DOS measured drive speeds */
-#define UMC_DRIVE1      1              /* 0 to 11 allowed */
-#define UMC_DRIVE2      1              /* 11 = Fastest Speed */
-#define UMC_DRIVE3      1              /* In case of crash reduce speed */
-
-static byte current_speeds[4] = {UMC_DRIVE0, UMC_DRIVE1, UMC_DRIVE2, UMC_DRIVE3};
-static const byte pio_to_umc [5] = {0,3,7,10,11};	/* rough guesses */
-
-/*       0    1    2    3    4    5    6    7    8    9    10   11      */
-static const byte speedtab [3][12] = {
-	{0xf, 0xb, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 },
-	{0x3, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 },
-	{0xff,0xcb,0xc0,0x58,0x36,0x33,0x23,0x22,0x21,0x11,0x10,0x0}};
-
-static void out_umc (char port,char wert)
-{
-	outb_p (port,0x108);
-	outb_p (wert,0x109);
-}
-
-static inline byte in_umc (char port)
-{
-	outb_p (port,0x108);
-	return inb_p (0x109);
-}
-
-static void umc_set_speeds (byte speeds[])
-{
-	int i, tmp;
-
-	outb_p (0x5A,0x108); /* enable umc */
-
-	out_umc (0xd7,(speedtab[0][speeds[2]] | (speedtab[0][speeds[3]]<<4)));
-	out_umc (0xd6,(speedtab[0][speeds[0]] | (speedtab[0][speeds[1]]<<4)));
-	tmp = 0;
-	for (i = 3; i >= 0; i--)
-	{
-		tmp = (tmp << 2) | speedtab[1][speeds[i]];
-	}
-	out_umc (0xdc,tmp);
-	for (i = 0;i < 4; i++)
-	{
-		out_umc (0xd0+i,speedtab[2][speeds[i]]);
-		out_umc (0xd8+i,speedtab[2][speeds[i]]);
-	}
-	outb_p (0xa5,0x108); /* disable umc */
-
-	printk ("umc8672: drive speeds [0 to 11]: %d %d %d %d\n",
-		speeds[0], speeds[1], speeds[2], speeds[3]);
-}
-
-static void tune_umc (ide_drive_t *drive, byte pio)
-{
-	unsigned long flags;
-	ide_hwgroup_t *hwgroup = ide_hwifs[HWIF(drive)->index^1].hwgroup;
-
-	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
-	printk("%s: setting umc8672 to PIO mode%d (speed %d)\n", drive->name, pio, pio_to_umc[pio]);
-	save_flags(flags);	/* all CPUs */
-	cli();			/* all CPUs */
-	if (hwgroup && hwgroup->handler != NULL) {
-		printk("umc8672: other interface is busy: exiting tune_umc()\n");
-	} else {
-		current_speeds[drive->name[2] - 'a'] = pio_to_umc[pio];
-		umc_set_speeds (current_speeds);
-	}
-	restore_flags(flags);	/* all CPUs */
-}
-
-void __init init_umc8672 (void)	/* called from ide.c */
-{
-	unsigned long flags;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-	if (check_region(0x108, 2)) {
-		__restore_flags(flags);
-		printk("\numc8672: PORTS 0x108-0x109 ALREADY IN USE\n");
-		return;
-	}
-	outb_p (0x5A,0x108); /* enable umc */
-	if (in_umc (0xd5) != 0xa0)
-	{
-		__restore_flags(flags);	/* local CPU only */
-		printk ("umc8672: not found\n");
-		return;  
-	}
-	outb_p (0xa5,0x108); /* disable umc */
-
-	umc_set_speeds (current_speeds);
-	__restore_flags(flags);	/* local CPU only */
-
-	request_region(0x108, 2, "umc8672");
-	ide_hwifs[0].chipset = ide_umc8672;
-	ide_hwifs[1].chipset = ide_umc8672;
-	ide_hwifs[0].tuneproc = &tune_umc;
-	ide_hwifs[1].tuneproc = &tune_umc;
-	ide_hwifs[0].mate = &ide_hwifs[1];
-	ide_hwifs[1].mate = &ide_hwifs[0];
-	ide_hwifs[1].channel = 1;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ide/via82cxxx.c linux-2.4.21-pre6/drivers/ide/via82cxxx.c
--- linux-2.4.20/drivers/ide/via82cxxx.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ide/via82cxxx.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,532 +0,0 @@
-/*
- * Version 3.35
- *
- * VIA IDE driver for Linux. Supported southbridges:
- *
- *   vt82c576, vt82c586, vt82c586a, vt82c586b, vt82c596a, vt82c596b,
- *   vt82c686, vt82c686a, vt82c686b, vt8231, vt8233, vt8233c, vt8233a,
- *   vt8235
- *
- * Copyright (c) 2000-2002 Vojtech Pavlik
- *
- * Based on the work of:
- *	Michel Aubry
- *	Jeff Garzik
- *	Andre Hedrick
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-#include <asm/io.h>
-
-#include "ide-timing.h"
-
-#define VIA_IDE_ENABLE		0x40
-#define VIA_IDE_CONFIG		0x41
-#define VIA_FIFO_CONFIG		0x43
-#define VIA_MISC_1		0x44
-#define VIA_MISC_2		0x45
-#define VIA_MISC_3		0x46
-#define VIA_DRIVE_TIMING	0x48
-#define VIA_8BIT_TIMING		0x4e
-#define VIA_ADDRESS_SETUP	0x4c
-#define VIA_UDMA_TIMING		0x50
-
-#define VIA_UDMA		0x007
-#define VIA_UDMA_NONE		0x000
-#define VIA_UDMA_33		0x001
-#define VIA_UDMA_66		0x002
-#define VIA_UDMA_100		0x003
-#define VIA_UDMA_133		0x004
-#define VIA_BAD_PREQ		0x010	/* Crashes if PREQ# till DDACK# set */
-#define VIA_BAD_CLK66		0x020	/* 66 MHz clock doesn't work correctly */
-#define VIA_SET_FIFO		0x040	/* Needs to have FIFO split set */
-#define VIA_NO_UNMASK		0x080	/* Doesn't work with IRQ unmasking on */
-#define VIA_BAD_ID		0x100	/* Has wrong vendor ID (0x1107) */
-
-#ifndef PCI_DEVICE_ID_VIA_8235
-#define PCI_DEVICE_ID_VIA_8235 0x3177
-#endif
-
-/*
- * VIA SouthBridge chips.
- */
-
-static struct via_isa_bridge {
-	char *name;
-	unsigned short id;
-	unsigned char rev_min;
-	unsigned char rev_max;
-	unsigned short flags;
-} via_isa_bridges[] = {
-#ifdef FUTURE_BRIDGES
-	{ "vt8237",	PCI_DEVICE_ID_VIA_8237,     0x00, 0x2f, VIA_UDMA_133 },
-#endif
-	{ "vt8235",	PCI_DEVICE_ID_VIA_8235,     0x00, 0x2f, VIA_UDMA_133 },
-	{ "vt8233a",	PCI_DEVICE_ID_VIA_8233A,    0x00, 0x2f, VIA_UDMA_133 },
-	{ "vt8233c",	PCI_DEVICE_ID_VIA_8233C_0,  0x00, 0x2f, VIA_UDMA_100 },
-	{ "vt8233",	PCI_DEVICE_ID_VIA_8233_0,   0x00, 0x2f, VIA_UDMA_100 },
-	{ "vt8231",	PCI_DEVICE_ID_VIA_8231,     0x00, 0x2f, VIA_UDMA_100 },
-	{ "vt82c686b",	PCI_DEVICE_ID_VIA_82C686,   0x40, 0x4f, VIA_UDMA_100 },
-	{ "vt82c686a",	PCI_DEVICE_ID_VIA_82C686,   0x10, 0x2f, VIA_UDMA_66 },
-	{ "vt82c686",	PCI_DEVICE_ID_VIA_82C686,   0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 },
-	{ "vt82c596b",	PCI_DEVICE_ID_VIA_82C596,   0x10, 0x2f, VIA_UDMA_66 },
-	{ "vt82c596a",	PCI_DEVICE_ID_VIA_82C596,   0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 },
-	{ "vt82c586b",	PCI_DEVICE_ID_VIA_82C586_0, 0x47, 0x4f, VIA_UDMA_33 | VIA_SET_FIFO },
-	{ "vt82c586b",	PCI_DEVICE_ID_VIA_82C586_0, 0x40, 0x46, VIA_UDMA_33 | VIA_SET_FIFO | VIA_BAD_PREQ },
-	{ "vt82c586b",	PCI_DEVICE_ID_VIA_82C586_0, 0x30, 0x3f, VIA_UDMA_33 | VIA_SET_FIFO },
-	{ "vt82c586a",	PCI_DEVICE_ID_VIA_82C586_0, 0x20, 0x2f, VIA_UDMA_33 | VIA_SET_FIFO },
-	{ "vt82c586",	PCI_DEVICE_ID_VIA_82C586_0, 0x00, 0x0f, VIA_UDMA_NONE | VIA_SET_FIFO },
-	{ "vt82c576",	PCI_DEVICE_ID_VIA_82C576,   0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK },
-	{ "vt82c576",	PCI_DEVICE_ID_VIA_82C576,   0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK | VIA_BAD_ID },
-	{ NULL }
-};
-
-static struct via_isa_bridge *via_config;
-static unsigned char via_enabled;
-static unsigned int via_80w;
-static unsigned int via_clock;
-static char *via_dma[] = { "MWDMA16", "UDMA33", "UDMA66", "UDMA100", "UDMA133" };
-
-/*
- * VIA /proc entry.
- */
-
-#ifdef CONFIG_PROC_FS
-
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-int via_proc, via_base;
-static struct pci_dev *bmide_dev, *isa_dev;
-extern int (*via_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-
-static char *via_control3[] = { "No limit", "64", "128", "192" };
-
-#define via_print(format, arg...) p += sprintf(p, format "\n" , ## arg)
-#define via_print_drive(name, format, arg...)\
-	p += sprintf(p, name); for (i = 0; i < 4; i++) p += sprintf(p, format, ## arg); p += sprintf(p, "\n");
-
-static int via_get_info(char *buffer, char **addr, off_t offset, int count)
-{
-	int speed[4], cycle[4], setup[4], active[4], recover[4], den[4],
-		 uen[4], udma[4], umul[4], active8b[4], recover8b[4];
-	struct pci_dev *dev = bmide_dev;
-	unsigned int v, u, i;
-	unsigned short c, w;
-	unsigned char t, x;
-	char *p = buffer;
-
-	via_print("----------VIA BusMastering IDE Configuration----------------");
-
-	via_print("Driver Version:                     3.35");
-	via_print("South Bridge:                       VIA %s", via_config->name);
-
-	pci_read_config_byte(isa_dev, PCI_REVISION_ID, &t);
-	pci_read_config_byte(dev, PCI_REVISION_ID, &x);
-	via_print("Revision:                           ISA %#x IDE %#x", t, x);
-	via_print("Highest DMA rate:                   %s", via_dma[via_config->flags & VIA_UDMA]);
-
-	via_print("BM-DMA base:                        %#x", via_base);
-	via_print("PCI clock:                          %d.%dMHz", via_clock / 1000, via_clock / 100 % 10);
-
-	pci_read_config_byte(dev, VIA_MISC_1, &t);
-	via_print("Master Read  Cycle IRDY:            %dws", (t & 64) >> 6);
-	via_print("Master Write Cycle IRDY:            %dws", (t & 32) >> 5);
-	via_print("BM IDE Status Register Read Retry:  %s", (t & 8) ? "yes" : "no");
-
-	pci_read_config_byte(dev, VIA_MISC_3, &t);
-	via_print("Max DRDY Pulse Width:               %s%s", via_control3[(t & 0x03)], (t & 0x03) ? " PCI clocks" : "");
-
-	via_print("-----------------------Primary IDE-------Secondary IDE------");
-	via_print("Read DMA FIFO flush:   %10s%20s", (t & 0x80) ? "yes" : "no", (t & 0x40) ? "yes" : "no");
-	via_print("End Sector FIFO flush: %10s%20s", (t & 0x20) ? "yes" : "no", (t & 0x10) ? "yes" : "no");
-
-	pci_read_config_byte(dev, VIA_IDE_CONFIG, &t);
-	via_print("Prefetch Buffer:       %10s%20s", (t & 0x80) ? "yes" : "no", (t & 0x20) ? "yes" : "no");
-	via_print("Post Write Buffer:     %10s%20s", (t & 0x40) ? "yes" : "no", (t & 0x10) ? "yes" : "no");
-
-	pci_read_config_byte(dev, VIA_IDE_ENABLE, &t);
-	via_print("Enabled:               %10s%20s", (t & 0x02) ? "yes" : "no", (t & 0x01) ? "yes" : "no");
-
-	c = inb(via_base + 0x02) | (inb(via_base + 0x0a) << 8);
-	via_print("Simplex only:          %10s%20s", (c & 0x80) ? "yes" : "no", (c & 0x8000) ? "yes" : "no");
-
-	via_print("Cable Type:            %10s%20s", (via_80w & 1) ? "80w" : "40w", (via_80w & 2) ? "80w" : "40w");
-
-	via_print("-------------------drive0----drive1----drive2----drive3-----");
-
-	pci_read_config_byte(dev, VIA_ADDRESS_SETUP, &t);
-	pci_read_config_dword(dev, VIA_DRIVE_TIMING, &v);
-	pci_read_config_word(dev, VIA_8BIT_TIMING, &w);
-
-	if (via_config->flags & VIA_UDMA)
-		pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
-	else u = 0;
-
-	for (i = 0; i < 4; i++) {
-
-		setup[i]     = ((t >> ((3 - i) << 1)) & 0x3) + 1;
-		recover8b[i] = ((w >> ((1 - (i >> 1)) << 3)) & 0xf) + 1;
-		active8b[i]  = ((w >> (((1 - (i >> 1)) << 3) + 4)) & 0xf) + 1;
-		active[i]    = ((v >> (((3 - i) << 3) + 4)) & 0xf) + 1;
-		recover[i]   = ((v >> ((3 - i) << 3)) & 0xf) + 1;
-		udma[i]      = ((u >> ((3 - i) << 3)) & 0x7) + 2;
-		umul[i]      = ((u >> (((3 - i) & 2) << 3)) & 0x8) ? 1 : 2;
-		uen[i]       = ((u >> ((3 - i) << 3)) & 0x20);
-		den[i]       = (c & ((i & 1) ? 0x40 : 0x20) << ((i & 2) << 2));
-
-		speed[i] = 2 * via_clock / (active[i] + recover[i]);
-		cycle[i] = 1000000 * (active[i] + recover[i]) / via_clock;
-
-		if (!uen[i] || !den[i])
-			continue;
-
-		switch (via_config->flags & VIA_UDMA) {
-
-			case VIA_UDMA_33:
-				speed[i] = 2 * via_clock / udma[i];
-				cycle[i] = 1000000 * udma[i] / via_clock;
-				break;
-
-			case VIA_UDMA_66:
-				speed[i] = 4 * via_clock / (udma[i] * umul[i]);
-				cycle[i] = 500000 * (udma[i] * umul[i]) / via_clock;
-				break;
-
-			case VIA_UDMA_100:
-				speed[i] = 6 * via_clock / udma[i];
-				cycle[i] = 333333 * udma[i] / via_clock;
-				break;
-
-			case VIA_UDMA_133:
-				speed[i] = 8 * via_clock / udma[i];
-				cycle[i] = 250000 * udma[i] / via_clock;
-				break;
-		}
-	}
-
-	via_print_drive("Transfer Mode: ", "%10s", den[i] ? (uen[i] ? "UDMA" : "DMA") : "PIO");
-
-	via_print_drive("Address Setup: ", "%8dns", 1000000 * setup[i] / via_clock);
-	via_print_drive("Cmd Active:    ", "%8dns", 1000000 * active8b[i] / via_clock);
-	via_print_drive("Cmd Recovery:  ", "%8dns", 1000000 * recover8b[i] / via_clock);
-	via_print_drive("Data Active:   ", "%8dns", 1000000 * active[i] / via_clock);
-	via_print_drive("Data Recovery: ", "%8dns", 1000000 * recover[i] / via_clock);
-	via_print_drive("Cycle Time:    ", "%8dns", cycle[i]);
-	via_print_drive("Transfer Rate: ", "%4d.%dMB/s", speed[i] / 1000, speed[i] / 100 % 10);
-
-	return p - buffer;	/* hoping it is less than 4K... */
-}
-
-#endif
-
-/*
- * via_set_speed() writes timing values to the chipset registers
- */
-
-static void via_set_speed(struct pci_dev *dev, unsigned char dn, struct ide_timing *timing)
-{
-	unsigned char t;
-
-	pci_read_config_byte(dev, VIA_ADDRESS_SETUP, &t);
-	t = (t & ~(3 << ((3 - dn) << 1))) | ((FIT(timing->setup, 1, 4) - 1) << ((3 - dn) << 1));
-	pci_write_config_byte(dev, VIA_ADDRESS_SETUP, t);
-
-	pci_write_config_byte(dev, VIA_8BIT_TIMING + (1 - (dn >> 1)),
-		((FIT(timing->act8b, 1, 16) - 1) << 4) | (FIT(timing->rec8b, 1, 16) - 1));
-
-	pci_write_config_byte(dev, VIA_DRIVE_TIMING + (3 - dn),
-		((FIT(timing->active, 1, 16) - 1) << 4) | (FIT(timing->recover, 1, 16) - 1));
-
-	switch (via_config->flags & VIA_UDMA) {
-		case VIA_UDMA_33:  t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 5) - 2)) : 0x03; break;
-		case VIA_UDMA_66:  t = timing->udma ? (0xe8 | (FIT(timing->udma, 2, 9) - 2)) : 0x0f; break;
-		case VIA_UDMA_100: t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 9) - 2)) : 0x07; break;
-		case VIA_UDMA_133: t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 9) - 2)) : 0x07; break;
-		default: return;
-	}
-
-	pci_write_config_byte(dev, VIA_UDMA_TIMING + (3 - dn), t);
-}
-
-/*
- * via_set_drive() computes timing values configures the drive and
- * the chipset to a desired transfer mode. It also can be called
- * by upper layers.
- */
-
-static int via_set_drive(ide_drive_t *drive, unsigned char speed)
-{
-	ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1);
-	struct ide_timing t, p;
-	unsigned int T, UT;
-
-	if (speed != XFER_PIO_SLOW && speed != drive->current_speed)
-		if (ide_config_drive_speed(drive, speed))
-			printk(KERN_WARNING "ide%d: Drive %d didn't accept speed setting. Oh, well.\n",
-				drive->dn >> 1, drive->dn & 1);
-
-	T = 1000000000 / via_clock;
-
-	switch (via_config->flags & VIA_UDMA) {
-		case VIA_UDMA_33:   UT = T;   break;
-		case VIA_UDMA_66:   UT = T/2; break;
-		case VIA_UDMA_100:  UT = T/3; break;
-		case VIA_UDMA_133:  UT = T/4; break;
-		default: UT = T;
-	}
-
-	ide_timing_compute(drive, speed, &t, T, UT);
-
-	if (peer->present) {
-		ide_timing_compute(peer, peer->current_speed, &p, T, UT);
-		ide_timing_merge(&p, &t, &t, IDE_TIMING_8BIT);
-	}
-
-	via_set_speed(HWIF(drive)->pci_dev, drive->dn, &t);
-
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-	drive->current_speed = speed;
-
-	return 0;
-}
-
-/*
- * via82cxxx_tune_drive() is a callback from upper layers for
- * PIO-only tuning.
- */
-
-static void via82cxxx_tune_drive(ide_drive_t *drive, unsigned char pio)
-{
-	if (!((via_enabled >> HWIF(drive)->channel) & 1))
-		return;
-
-	if (pio == 255) {
-		via_set_drive(drive, ide_find_best_mode(drive, XFER_PIO | XFER_EPIO));
-		return;
-	}
-
-	via_set_drive(drive, XFER_PIO_0 + MIN(pio, 5));
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-
-/*
- * via82cxxx_dmaproc() is a callback from upper layers that can do
- * a lot, but we use it for DMA/PIO tuning only, delegating everything
- * else to the default ide_dmaproc().
- */
-
-int via82cxxx_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-
-	if (func == ide_dma_check) {
-
-		short w80 = HWIF(drive)->udma_four;
-
-		short speed = ide_find_best_mode(drive,
-			XFER_PIO | XFER_EPIO | XFER_SWDMA | XFER_MWDMA |
-			(via_config->flags & VIA_UDMA ? XFER_UDMA : 0) |
-			(w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_66 ? XFER_UDMA_66 : 0) |
-			(w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_100 ? XFER_UDMA_100 : 0) |
-			(w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_133 ? XFER_UDMA_133 : 0));
-
-		via_set_drive(drive, speed);
-
-		func = (HWIF(drive)->autodma && (speed & XFER_MODE) != XFER_PIO)
-			? ide_dma_on : ide_dma_off_quietly;
-	}
-
-	return ide_dmaproc(func, drive);
-}
-
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-/*
- * The initialization callback. Here we determine the IDE chip type
- * and initialize its drive independent registers.
- */
-
-unsigned int __init pci_init_via82cxxx(struct pci_dev *dev, const char *name)
-{
-	struct pci_dev *isa = NULL;
-	unsigned char t, v;
-	unsigned int u;
-	int i;
-
-/*
- * Find the ISA bridge to see how good the IDE is.
- */
-
-	for (via_config = via_isa_bridges; via_config->id; via_config++)
-		if ((isa = pci_find_device(PCI_VENDOR_ID_VIA +
-			!!(via_config->flags & VIA_BAD_ID), via_config->id, NULL))) {
-
-			pci_read_config_byte(isa, PCI_REVISION_ID, &t);
-			if (t >= via_config->rev_min && t <= via_config->rev_max)
-				break;
-		}
-
-	if (!via_config->id) {
-		printk(KERN_WARNING "VP_IDE: Unknown VIA SouthBridge, contact Vojtech Pavlik <vojtech@ucw.cz>\n");
-		return -ENODEV;
-	}
-
-/*
- * Check 80-wire cable presence and setup Clk66.
- */
-
-	switch (via_config->flags & VIA_UDMA) {
-
-		case VIA_UDMA_66:
-			pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);	/* Enable Clk66 */
-			pci_write_config_dword(dev, VIA_UDMA_TIMING, u | 0x80008);
-			for (i = 24; i >= 0; i -= 8)
-				if (((u >> (i & 16)) & 8) && ((u >> i) & 0x20) && (((u >> i) & 7) < 2))
-					via_80w |= (1 << (1 - (i >> 4)));	/* 2x PCI clock and UDMA w/ < 3T/cycle */
-			break;
-
-		case VIA_UDMA_100:
-			pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
-			for (i = 24; i >= 0; i -= 8)
-				if (((u >> i) & 0x10) || (((u >> i) & 0x20) && (((u >> i) & 7) < 4)))
-					via_80w |= (1 << (1 - (i >> 4)));	/* BIOS 80-wire bit or UDMA w/ < 60ns/cycle */
-			break;
-
-		case VIA_UDMA_133:
-			pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
-			for (i = 24; i >= 0; i -= 8)
-				if (((u >> i) & 0x10) || (((u >> i) & 0x20) && (((u >> i) & 7) < 8)))
-					via_80w |= (1 << (1 - (i >> 4)));	/* BIOS 80-wire bit or UDMA w/ < 60ns/cycle */
-			break;
-
-	}
-
-	if (via_config->flags & VIA_BAD_CLK66) {			/* Disable Clk66 */
-		pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);	/* Would cause trouble on 596a and 686 */
-		pci_write_config_dword(dev, VIA_UDMA_TIMING, u & ~0x80008);
-	}
-
-/*
- * Check whether interfaces are enabled.
- */
-
-	pci_read_config_byte(dev, VIA_IDE_ENABLE, &v);
-	via_enabled = ((v & 1) ? 2 : 0) | ((v & 2) ? 1 : 0);
-
-/*
- * Set up FIFO sizes and thresholds.
- */
-
-	pci_read_config_byte(dev, VIA_FIFO_CONFIG, &t);
-
-	if (via_config->flags & VIA_BAD_PREQ)				/* Disable PREQ# till DDACK# */
-		t &= 0x7f;						/* Would crash on 586b rev 41 */
-
-	if (via_config->flags & VIA_SET_FIFO) {				/* Fix FIFO split between channels */
-		t &= (t & 0x9f);
-		switch (via_enabled) {
-			case 1: t |= 0x00; break;			/* 16 on primary */
-			case 2: t |= 0x60; break;			/* 16 on secondary */
-			case 3: t |= 0x20; break;			/* 8 pri 8 sec */
-		}
-	}
-
-	pci_write_config_byte(dev, VIA_FIFO_CONFIG, t);
-
-/*
- * Determine system bus clock.
- */
-
-	via_clock = system_bus_clock() * 1000;
-
-	switch (via_clock) {
-		case 33000: via_clock = 33333; break;
-		case 37000: via_clock = 37500; break;
-		case 41000: via_clock = 41666; break;
-	}
-
-	if (via_clock < 20000 || via_clock > 50000) {
-		printk(KERN_WARNING "VP_IDE: User given PCI clock speed impossible (%d), using 33 MHz instead.\n", via_clock);
-		printk(KERN_WARNING "VP_IDE: Use ide0=ata66 if you want to assume 80-wire cable.\n");
-		via_clock = 33333;
-	}
-
-/*
- * Print the boot message.
- */
-
-	pci_read_config_byte(isa, PCI_REVISION_ID, &t);
-	printk(KERN_INFO "VP_IDE: VIA %s (rev %02x) IDE %s controller on pci%s\n",
-		via_config->name, t, via_dma[via_config->flags & VIA_UDMA], dev->slot_name);
-
-/*
- * Setup /proc/ide/via entry.
- */
-
-#ifdef CONFIG_PROC_FS
-	if (!via_proc) {
-		via_base = pci_resource_start(dev, 4);
-		bmide_dev = dev;
-		isa_dev = isa;
-		via_display_info = &via_get_info;
-		via_proc = 1;
-	}
-#endif
-
-	return 0;
-}
-
-unsigned int __init ata66_via82cxxx(ide_hwif_t *hwif)
-{
-	return ((via_enabled & via_80w) >> hwif->channel) & 1;
-}
-
-void __init ide_init_via82cxxx(ide_hwif_t *hwif)
-{
-	int i;
-
-	hwif->tuneproc = &via82cxxx_tune_drive;
-	hwif->speedproc = &via_set_drive;
-	hwif->autodma = 0;
-
-	for (i = 0; i < 2; i++) {
-		hwif->drives[i].io_32bit = 1;
-		hwif->drives[i].unmask = (via_config->flags & VIA_NO_UNMASK) ? 0 : 1;
-		hwif->drives[i].autotune = 1;
-		hwif->drives[i].dn = hwif->channel * 2 + i;
-	}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (hwif->dma_base) {
-		hwif->dmaproc = &via82cxxx_dmaproc;
-#ifdef CONFIG_IDEDMA_AUTO
-		if (!noautodma)
-			hwif->autodma = 1;
-#endif
-	}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-}
-
-/*
- * We allow the BM-DMA driver to only work on enabled interfaces.
- */
-
-void __init ide_dmacapable_via82cxxx(ide_hwif_t *hwif, unsigned long dmabase)
-{
-	if ((via_enabled >> hwif->channel) & 1)
-		ide_setup_dma(hwif, dmabase, 8);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/Makefile linux-2.4.21-pre6/drivers/ieee1394/Makefile
--- linux-2.4.20/drivers/ieee1394/Makefile	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ieee1394/Makefile	2003-03-26 23:49:55.000000000 +0000
@@ -4,11 +4,11 @@
 
 O_TARGET := ieee1394drv.o
 
-export-objs := ieee1394_core.o ohci1394.o cmp.o
+export-objs := ieee1394_core.o ohci1394.o cmp.o iso.o
 
 list-multi := ieee1394.o
 ieee1394-objs := ieee1394_core.o ieee1394_transactions.o hosts.o \
-		 highlevel.o csr.o nodemgr.o
+		 highlevel.o csr.o nodemgr.o dma.o iso.o
 
 obj-$(CONFIG_IEEE1394) += ieee1394.o
 obj-$(CONFIG_IEEE1394_PCILYNX) += pcilynx.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/amdtp.c linux-2.4.21-pre6/drivers/ieee1394/amdtp.c
--- linux-2.4.20/drivers/ieee1394/amdtp.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ieee1394/amdtp.c	2003-03-26 23:49:50.000000000 +0000
@@ -598,6 +598,8 @@
 	struct buffer *b;
 
 	b = kmalloc(sizeof *b + size, SLAB_KERNEL);
+	if (b == NULL)
+		return NULL;
 	b->head = 0;
 	b->tail = 0;
 	b->length = 0;
@@ -834,7 +836,8 @@
 
 	max_packet_size = max_nevents * s->dimension * 4 + 8;
 	s->packet_pool = pci_pool_create("packet pool", s->host->ohci->dev,
-					 max_packet_size, 0, 0, SLAB_KERNEL);
+					 max_packet_size, 0, 0 ,SLAB_KERNEL);
+
 	if (s->packet_pool == NULL)
 		return -1;
 
@@ -1021,6 +1024,7 @@
 	s->descriptor_pool = pci_pool_create("descriptor pool", host->ohci->dev,
 					     sizeof(struct descriptor_block),
 					     16, 0, SLAB_KERNEL);
+
 	if (s->descriptor_pool == NULL) {
 		kfree(s->input);
 		kfree(s);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/amdtp.h linux-2.4.21-pre6/drivers/ieee1394/amdtp.h
--- linux-2.4.20/drivers/ieee1394/amdtp.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ieee1394/amdtp.h	2003-03-26 23:49:40.000000000 +0000
@@ -3,8 +3,8 @@
 #ifndef __AMDTP_H
 #define __AMDTP_H
 
-#include <asm/ioctl.h>
 #include <asm/types.h>
+#include "ieee1394-ioctl.h"
 
 /* The userspace interface for the Audio & Music Data Transmission
  * Protocol driver is really simple. First, open /dev/amdtp, use the
@@ -57,13 +57,6 @@
  *
  */
 
-/* We use '#' for our ioctl magic number because it's cool. */
-
-#define AMDTP_IOC_CHANNEL _IOW('#', 0, sizeof (struct amdtp_ioctl))
-#define AMDTP_IOC_PLUG    _IOW('#', 1, sizeof (struct amdtp_ioctl))
-#define AMDTP_IOC_PING    _IOW('#', 2, sizeof (struct amdtp_ioctl))
-#define AMDTP_IOC_ZAP     _IO('#', 3)
-
 enum {
 	AMDTP_FORMAT_RAW,
 	AMDTP_FORMAT_IEC958_PCM,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/cmp.c linux-2.4.21-pre6/drivers/ieee1394/cmp.c
--- linux-2.4.20/drivers/ieee1394/cmp.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ieee1394/cmp.c	2003-03-26 23:49:09.000000000 +0000
@@ -199,7 +199,7 @@
 }
 
 static int pcr_read(struct hpsb_host *host, int nodeid, quadlet_t *buf,
-		    u64 addr, unsigned int length)
+		    u64 addr, unsigned int length, u16 flags)
 {
 	int csraddr = addr - CSR_REGISTER_BASE;
 	int plug;
@@ -235,7 +235,7 @@
 }
 
 static int pcr_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
-		    u64 addr, quadlet_t data, quadlet_t arg, int extcode)
+		    u64 addr, quadlet_t data, quadlet_t arg, int extcode, u16 flags)
 {
 	int csraddr = addr - CSR_REGISTER_BASE;
 	int plug;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/csr.c linux-2.4.21-pre6/drivers/ieee1394/csr.c
--- linux-2.4.20/drivers/ieee1394/csr.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ieee1394/csr.c	2003-03-26 23:49:18.000000000 +0000
@@ -4,20 +4,33 @@
  * CSR implementation, iso/bus manager implementation.
  *
  * Copyright (C) 1999 Andreas E. Bombe
+ *               2002 Manfred Weihs <weihs@ict.tuwien.ac.at>
  *
  * This code is licensed under the GPL.  See the file COPYING in the root
  * directory of the kernel sources for details.
+ *
+ *
+ * Contributions:
+ *
+ * Manfred Weihs <weihs@ict.tuwien.ac.at>
+ *        configuration ROM manipulation
+ *
  */
 
 #include <linux/string.h>
+#include <linux/module.h> /* needed for MODULE_PARM */
 
 #include "ieee1394_types.h"
 #include "hosts.h"
 #include "ieee1394.h"
 #include "highlevel.h"
 
+/* Module Parameters */
+/* this module parameter can be used to disable mapping of the FCP registers */
+MODULE_PARM(fcp,"i");
+MODULE_PARM_DESC(fcp, "FCP-registers");
+static int fcp = 1;
 
-/* FIXME: this one won't work on little endian with big endian data */
 static u16 csr_crc16(unsigned *data, int length)
 {
         int check=0, i;
@@ -25,7 +38,7 @@
 
         for (i = length; i; i--) {
                 for (next = check, shift = 28; shift >= 0; shift -= 4 ) {
-                        sum = ((next >> 12) ^ (*data >> shift)) & 0xf;
+                        sum = ((next >> 12) ^ (be32_to_cpu(*data) >> shift)) & 0xf;
                         next = (next << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum);
                 }
                 check = next & 0xffff;
@@ -60,6 +73,8 @@
                             | csr_crc16(host->csr.topology_map + 1,
                                         host->selfid_count + 2));
 
+        host->csr.speed_map[1] = 
+                cpu_to_be32(be32_to_cpu(host->csr.speed_map[1]) + 1);
         host->csr.speed_map[0] = cpu_to_be32(0x3f1 << 16 
                                              | csr_crc16(host->csr.speed_map+1,
                                                          0x3f1));
@@ -71,7 +86,7 @@
         host->csr.lock = SPIN_LOCK_UNLOCKED;
 
         host->csr.rom_size = host->driver->get_rom(host, &host->csr.rom);
-
+        host->csr.rom_version           = 0;
         host->csr.state                 = 0;
         host->csr.node_ids              = 0;
         host->csr.split_timeout_hi      = 0;
@@ -84,13 +99,52 @@
         host->csr.channels_available_lo = ~0;
 }
 
+int hpsb_update_config_rom(struct hpsb_host *host, const quadlet_t *new_rom, 
+	size_t size, unsigned char rom_version)
+{
+        int ret,flags;
+        spin_lock_irqsave(&host->csr.lock, flags); 
+        if (rom_version != host->csr.rom_version)
+                 ret = -1;
+        else if (size > (CSR_CONFIG_ROM_SIZE << 2))
+                 ret = -2;
+        else {
+                 memcpy(host->csr.rom,new_rom,size);
+                 host->csr.rom_size=size;
+                 host->csr.rom_version++;
+                 ret=0;
+        }
+        spin_unlock_irqrestore(&host->csr.lock, flags);
+        return ret;
+}
+
+int hpsb_get_config_rom(struct hpsb_host *host, quadlet_t *buffer, 
+	size_t buffersize, size_t *rom_size, unsigned char *rom_version)
+{
+        int ret,flags;
+        spin_lock_irqsave(&host->csr.lock, flags); 
+        *rom_version=host->csr.rom_version;
+        *rom_size=host->csr.rom_size;
+        if (buffersize < host->csr.rom_size)
+                 ret = -1;
+        else {
+                 memcpy(buffer,host->csr.rom,host->csr.rom_size);
+                 ret=0;
+        }
+        spin_unlock_irqrestore(&host->csr.lock, flags);
+        return ret;
+}
+
 
 /* Read topology / speed maps and configuration ROM */
 static int read_maps(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
-                     u64 addr, unsigned int length)
+                     u64 addr, unsigned int length, u16 fl)
 {
         int csraddr = addr - CSR_REGISTER_BASE;
         const char *src;
+        int flags;
+
+        spin_lock_irqsave(&host->csr.lock, flags); 
 
         if (csraddr < CSR_TOPOLOGY_MAP) {
                 if (csraddr + length > CSR_CONFIG_ROM + host->csr.rom_size) {
@@ -105,6 +159,7 @@
         }
 
         memcpy(buffer, src, length);
+        spin_unlock_irqrestore(&host->csr.lock, flags);
         return RCODE_COMPLETE;
 }
 
@@ -112,7 +167,7 @@
 #define out if (--length == 0) break
 
 static int read_regs(struct hpsb_host *host, int nodeid, quadlet_t *buf,
-                     u64 addr, unsigned int length)
+                     u64 addr, unsigned int length, u16 flags)
 {
         int csraddr = addr - CSR_REGISTER_BASE;
         int oldcycle;
@@ -222,7 +277,7 @@
 }
 
 static int write_regs(struct hpsb_host *host, int nodeid, int destid,
-		      quadlet_t *data, u64 addr, unsigned int length)
+		      quadlet_t *data, u64 addr, unsigned int length, u16 flags)
 {
         int csraddr = addr - CSR_REGISTER_BASE;
         
@@ -302,7 +357,7 @@
 
 
 static int lock_regs(struct hpsb_host *host, int nodeid, quadlet_t *store,
-                     u64 addr, quadlet_t data, quadlet_t arg, int extcode)
+                     u64 addr, quadlet_t data, quadlet_t arg, int extcode, u16 fl)
 {
         int csraddr = addr - CSR_REGISTER_BASE;
         unsigned long flags;
@@ -379,7 +434,7 @@
 }
 
 static int write_fcp(struct hpsb_host *host, int nodeid, int dest,
-		     quadlet_t *data, u64 addr, unsigned int length)
+		     quadlet_t *data, u64 addr, unsigned int length, u16 flags)
 {
         int csraddr = addr - CSR_REGISTER_BASE;
 
@@ -436,9 +491,11 @@
         hpsb_register_addrspace(hl, &map_ops, 
                                 CSR_REGISTER_BASE + CSR_CONFIG_ROM,
                                 CSR_REGISTER_BASE + CSR_CONFIG_ROM_END);
-        hpsb_register_addrspace(hl, &fcp_ops,
+        if (fcp) {
+		hpsb_register_addrspace(hl, &fcp_ops,
                                 CSR_REGISTER_BASE + CSR_FCP_COMMAND,
                                 CSR_REGISTER_BASE + CSR_FCP_END);
+	}
         hpsb_register_addrspace(hl, &map_ops,
                                 CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP,
                                 CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP_END);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/csr.h linux-2.4.21-pre6/drivers/ieee1394/csr.h
--- linux-2.4.20/drivers/ieee1394/csr.h	2001-03-02 00:57:11.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ieee1394/csr.h	2003-03-26 23:48:59.000000000 +0000
@@ -41,8 +41,10 @@
         quadlet_t bandwidth_available;
         quadlet_t channels_available_hi, channels_available_lo;
 
-        const quadlet_t *rom;
+        quadlet_t *rom;
         size_t rom_size;
+        unsigned char rom_version;
+
 
         quadlet_t topology_map[256];
         quadlet_t speed_map[1024];
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/dma.c linux-2.4.21-pre6/drivers/ieee1394/dma.c
--- linux-2.4.20/drivers/ieee1394/dma.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ieee1394/dma.c	2003-03-26 23:49:29.000000000 +0000
@@ -0,0 +1,236 @@
+/*
+ * DMA region bookkeeping routines
+ *
+ * Copyright (C) 2002 Maas Digital LLC
+ *
+ * This code is licensed under the GPL.  See the file COPYING in the root
+ * directory of the kernel sources for details.
+ */
+
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include "dma.h"
+
+/* dma_prog_region */
+
+void dma_prog_region_init(struct dma_prog_region *prog)
+{
+	prog->kvirt = NULL;
+	prog->dev = NULL;
+	prog->n_pages = 0;
+	prog->bus_addr = 0;
+}
+
+int  dma_prog_region_alloc(struct dma_prog_region *prog, unsigned long n_bytes, struct pci_dev *dev)
+{
+	/* round up to page size */
+	n_bytes = round_up_to_page(n_bytes);
+
+	prog->n_pages = n_bytes / PAGE_SIZE;
+
+	prog->kvirt = pci_alloc_consistent(dev, prog->n_pages * PAGE_SIZE, &prog->bus_addr);
+	if(!prog->kvirt) {
+		printk(KERN_ERR "dma_prog_region_alloc: pci_alloc_consistent() failed\n");
+		dma_prog_region_free(prog);
+		return -ENOMEM;
+	}
+
+	prog->dev = dev;
+
+	return 0;
+}
+
+void dma_prog_region_free(struct dma_prog_region *prog)
+{
+	if(prog->kvirt) {
+		pci_free_consistent(prog->dev, prog->n_pages * PAGE_SIZE, prog->kvirt, prog->bus_addr);
+	}
+
+	prog->kvirt = NULL;
+	prog->dev = NULL;
+	prog->n_pages = 0;
+	prog->bus_addr = 0;
+}
+
+/* dma_region */
+
+void dma_region_init(struct dma_region *dma)
+{
+	dma->kvirt = NULL;
+	dma->dev = NULL;
+	dma->n_pages = 0;
+	dma->n_dma_pages = 0;
+	dma->sglist = NULL;
+}
+
+int dma_region_alloc(struct dma_region *dma, unsigned long n_bytes, struct pci_dev *dev, int direction)
+{
+	unsigned int i, n_pages;
+
+	/* round up to page size */
+	n_bytes = round_up_to_page(n_bytes);
+
+	n_pages = n_bytes / PAGE_SIZE;
+
+	dma->kvirt = vmalloc_32(n_pages * PAGE_SIZE);
+	if(!dma->kvirt) {
+		printk(KERN_ERR "dma_region_alloc: vmalloc_32() failed\n");
+		goto err;
+	}
+
+	dma->n_pages = n_pages;
+
+	/* Clear the ram out, no junk to the user */
+	memset(dma->kvirt, 0, n_pages * PAGE_SIZE);
+
+	/* allocate scatter/gather list */
+	dma->sglist = kmalloc(dma->n_pages * sizeof(struct scatterlist), GFP_KERNEL);
+	if(!dma->sglist) {
+		printk(KERN_ERR "dma_region_alloc: kmalloc(sglist) failed\n");
+		goto err;
+	}
+
+	/* just to be safe - this will become unnecessary once sglist->address goes away */
+	memset(dma->sglist, 0, dma->n_pages * sizeof(struct scatterlist));
+
+	/* fill scatter/gather list with pages */
+	for(i = 0; i < dma->n_pages; i++) {
+		unsigned long va = (unsigned long) dma->kvirt + i * PAGE_SIZE;
+			
+		dma->sglist[i].page = vmalloc_to_page((void *)va);
+		dma->sglist[i].length = PAGE_SIZE;
+	}
+
+	/* map sglist to the IOMMU */
+	dma->n_dma_pages = pci_map_sg(dev, &dma->sglist[0], dma->n_pages, direction);
+
+	if(dma->n_dma_pages == 0) {
+		printk(KERN_ERR "dma_region_alloc: pci_map_sg() failed\n");
+		goto err;
+	}
+
+	dma->dev = dev;
+	dma->direction = direction;
+
+	return 0;
+
+err:
+	dma_region_free(dma);
+	return -ENOMEM;
+}
+
+void dma_region_free(struct dma_region *dma)
+{
+	if(dma->n_dma_pages) {
+		pci_unmap_sg(dma->dev, dma->sglist, dma->n_pages, dma->direction);
+		dma->n_dma_pages = 0;
+		dma->dev = NULL;
+	}
+
+	if(dma->sglist) {
+		kfree(dma->sglist);
+		dma->sglist = NULL;
+	}
+
+	if(dma->kvirt) {
+		vfree(dma->kvirt);
+		dma->kvirt = NULL;
+		dma->n_pages = 0;
+	}
+}
+
+/* find the scatterlist index and remaining offset corresponding to a
+   given offset from the beginning of the buffer */
+static inline int dma_region_find(struct dma_region *dma, unsigned long offset, unsigned long *rem)
+{
+	int i;
+	unsigned long off = offset;
+
+	for(i = 0; i < dma->n_dma_pages; i++) {
+		if(off < sg_dma_len(&dma->sglist[i])) {
+			*rem = off;
+			return i;
+		}
+
+		off -= sg_dma_len(&dma->sglist[i]);
+	}
+
+	panic("dma_region_find: offset %lu beyond end of DMA mapping\n", offset);
+}
+
+dma_addr_t dma_region_offset_to_bus(struct dma_region *dma, unsigned long offset)
+{
+	unsigned long rem;
+
+	struct scatterlist *sg = &dma->sglist[dma_region_find(dma, offset, &rem)];
+	return sg_dma_address(sg) + rem;
+}
+
+void dma_region_sync(struct dma_region *dma, unsigned long offset, unsigned long len)
+{
+	int first, last;
+	unsigned long rem;
+
+	if(!len)
+		len = 1;
+
+	first = dma_region_find(dma, offset, &rem);
+	last = dma_region_find(dma, offset + len - 1, &rem);
+
+	pci_dma_sync_sg(dma->dev, &dma->sglist[first], last - first + 1, dma->direction);
+}
+
+/* nopage() handler for mmap access */
+
+static struct page*
+dma_region_pagefault(struct vm_area_struct *area, unsigned long address, int write_access)
+{
+	unsigned long offset;
+	unsigned long kernel_virt_addr;
+	struct page *ret = NOPAGE_SIGBUS;
+
+	struct dma_region *dma = (struct dma_region*) area->vm_private_data;
+
+	if(!dma->kvirt)
+		goto out;
+
+	if( (address < (unsigned long) area->vm_start) ||
+	    (address > (unsigned long) area->vm_start + (PAGE_SIZE * dma->n_pages)) )
+		goto out;
+
+	offset = address - area->vm_start;
+	kernel_virt_addr = (unsigned long) dma->kvirt + offset;
+	ret = vmalloc_to_page((void*) kernel_virt_addr);
+	get_page(ret);
+out:
+	return ret;
+}
+
+static struct vm_operations_struct dma_region_vm_ops = {
+	.nopage	= dma_region_pagefault,
+};
+
+int dma_region_mmap(struct dma_region *dma, struct file *file, struct vm_area_struct *vma)
+{
+	unsigned long size;
+
+	if(!dma->kvirt)
+		return -EINVAL;
+
+	/* must be page-aligned */
+	if(vma->vm_pgoff != 0)
+		return -EINVAL;
+
+	/* check the length */
+	size = vma->vm_end - vma->vm_start;
+	if(size > (PAGE_SIZE * dma->n_pages))
+		return -EINVAL;
+
+	vma->vm_ops = &dma_region_vm_ops;
+	vma->vm_private_data = dma;
+	vma->vm_file = file;
+	vma->vm_flags |= VM_RESERVED;
+
+	return 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/dma.h linux-2.4.21-pre6/drivers/ieee1394/dma.h
--- linux-2.4.20/drivers/ieee1394/dma.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ieee1394/dma.h	2003-03-26 23:48:58.000000000 +0000
@@ -0,0 +1,84 @@
+/*
+ * DMA region bookkeeping routines
+ *
+ * Copyright (C) 2002 Maas Digital LLC
+ *
+ * This code is licensed under the GPL.  See the file COPYING in the root
+ * directory of the kernel sources for details.
+ */
+
+#ifndef IEEE1394_DMA_H
+#define IEEE1394_DMA_H
+
+#include <linux/pci.h>
+#include <asm/scatterlist.h>
+
+/* struct dma_prog_region
+   
+   a small, physically-contiguous DMA buffer with random-access,
+   synchronous usage characteristics
+*/
+
+struct dma_prog_region {
+	unsigned char    *kvirt;     /* kernel virtual address */
+	struct pci_dev   *dev;       /* PCI device */
+	unsigned int      n_pages;   /* # of kernel pages */
+	dma_addr_t        bus_addr;  /* base bus address */
+};
+
+/* clear out all fields but do not allocate any memory */
+void dma_prog_region_init(struct dma_prog_region *prog);
+int  dma_prog_region_alloc(struct dma_prog_region *prog, unsigned long n_bytes, struct pci_dev *dev);
+void dma_prog_region_free(struct dma_prog_region *prog);
+
+static inline dma_addr_t dma_prog_region_offset_to_bus(struct dma_prog_region *prog, unsigned long offset)
+{
+	return prog->bus_addr + offset;
+}
+
+/* struct dma_region
+   
+   a large, non-physically-contiguous DMA buffer with streaming,
+   asynchronous usage characteristics
+*/
+
+struct dma_region {
+	unsigned char      *kvirt;       /* kernel virtual address */
+	struct pci_dev     *dev;         /* PCI device */
+	unsigned int        n_pages;     /* # of kernel pages */
+	unsigned int        n_dma_pages; /* # of IOMMU pages */
+	struct scatterlist *sglist;      /* IOMMU mapping */
+	int                 direction;   /* PCI_DMA_TODEVICE, etc */
+};
+
+/* clear out all fields but do not allocate anything */
+void dma_region_init(struct dma_region *dma);
+
+/* allocate the buffer and map it to the IOMMU */
+int  dma_region_alloc(struct dma_region *dma, unsigned long n_bytes, struct pci_dev *dev, int direction);
+
+/* unmap and free the buffer */
+void dma_region_free(struct dma_region *dma);
+
+/* sync the IO bus' view of the buffer with the CPU's view */
+void dma_region_sync(struct dma_region *dma, unsigned long offset, unsigned long len);
+
+/* map the buffer into a user space process */
+int  dma_region_mmap(struct dma_region *dma, struct file *file, struct vm_area_struct *vma);
+
+/* macro to index into a DMA region (or dma_prog_region) */
+#define dma_region_i(_dma, _type, _index) ( ((_type*) ((_dma)->kvirt)) + (_index) )
+
+/* return the DMA bus address of the byte with the given offset
+   relative to the beginning of the dma_region */
+dma_addr_t dma_region_offset_to_bus(struct dma_region *dma, unsigned long offset);
+
+/* round up a number of bytes to be a multiple of the PAGE_SIZE */
+static inline unsigned long round_up_to_page(unsigned long len)
+{
+	if(len % PAGE_SIZE)
+		len += PAGE_SIZE - (len % PAGE_SIZE);
+	return len;
+}
+
+#endif /* IEEE1394_DMA_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/dv1394-private.h linux-2.4.21-pre6/drivers/ieee1394/dv1394-private.h
--- linux-2.4.20/drivers/ieee1394/dv1394-private.h	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ieee1394/dv1394-private.h	2003-03-26 23:49:06.000000000 +0000
@@ -28,8 +28,7 @@
 
 #include "ieee1394.h"
 #include "ohci1394.h"
-#include <linux/pci.h>
-#include <asm/scatterlist.h>
+#include "dma.h"
 
 /* data structures private to the dv1394 driver */
 /* none of this is exposed to user-space */
@@ -167,12 +166,14 @@
 }
  
 static inline void fill_input_last(struct input_last *il,
+				    int want_interrupt,
 				    unsigned int data_size,
 				    unsigned long data_phys_addr)
 {
 	u32 temp =  3 << 28; /* INPUT_LAST */
 	temp |= 8 << 24; /* s = 1, update xferStatus and resCount */
-	temp |= 3 << 20; /* enable interrupts */
+	if (want_interrupt)
+		temp |= 3 << 20; /* enable interrupts */
 	temp |= 0xC << 16; /* enable branch to address */
 	                       /* disable wait on sync field, not used in DV :-( */
 	temp |= data_size;
@@ -301,8 +302,7 @@
 	unsigned long data; 
 
 	/* Max # of packets per frame */
-	/* 320 is enough for NTSC, need to check what PAL is */
-        #define MAX_PACKETS 500
+#define MAX_PACKETS 500
 
 
 	/* a PAGE_SIZE memory pool for allocating CIP headers
@@ -383,35 +383,6 @@
 /* reset f so that it can be used again */
 static void frame_reset(struct frame *f);
 
-
-/* structure for bookkeeping of a large non-physically-contiguous DMA buffer */
-
-struct dma_region {
-	unsigned int n_pages;
-	unsigned int n_dma_pages;
-	struct scatterlist *sglist;
-};
-
-/* return the DMA bus address of the byte with the given offset
-   relative to the beginning of the dma_region */
-
-static inline dma_addr_t dma_offset_to_bus(struct dma_region *dma, unsigned long offset)
-{
-	int i;
-	struct scatterlist *sg;
-	
-	for(i = 0, sg = &dma->sglist[0]; i < dma->n_dma_pages; i++, sg++) {
-		if(offset < sg_dma_len(sg)) {
-			return sg_dma_address(sg) + offset;
-		} 
-		offset -= sg_dma_len(sg);
-	}
-	
-	printk(KERN_ERR "dv1394: dma_offset_to_bus failed for offset %lu!\n", offset);
-	return 0;
-}
-
-
 /* struct video_card contains all data associated with one instance
    of the dv1394 driver 
 */
@@ -487,6 +458,10 @@
 	 */
 	spinlock_t spinlock;
 
+	/* flag to prevent spurious interrupts (which OHCI seems to
+	   generate a lot :) from accessing the struct */
+	int dma_running;
+	
 	/*
 	  3) the sleeping semaphore 'sem' - this is used from process context only,
 	  to serialize various operations on the video_card. Even though only one
@@ -508,9 +483,8 @@
 	
 	/* the large, non-contiguous (rvmalloc()) ringbuffer for DV
            data, exposed to user-space via mmap() */
-	unsigned char     *user_buf;
-	unsigned long      user_buf_size;
-	struct dma_region  user_dma;
+	unsigned long      dv_buf_size;
+	struct dma_region  dv_buf;
 	
 	/* next byte in the ringbuffer that a write() call will fill */
 	size_t write_off;
@@ -579,10 +553,8 @@
 
 	
 	/* physically contiguous packet ringbuffer for receive */
-#define MAX_PACKET_BUFFER 30
-	struct packet *packet_buffer;
-	dma_addr_t     packet_buffer_dma;
-	unsigned long  packet_buffer_size;
+	struct dma_region packet_buf;
+	unsigned long  packet_buf_size;
 	
 	unsigned int current_packet;
 	int first_frame; 	/* received first start frame marker? */
@@ -603,7 +575,7 @@
 
 static int do_dv1394_init(struct video_card *video, struct dv1394_init *init);
 static int do_dv1394_init_default(struct video_card *video);
-static int do_dv1394_shutdown(struct video_card *video, int free_user_buf);
+static void do_dv1394_shutdown(struct video_card *video, int free_user_buf);
 
 
 /* NTSC empty packet rate accurate to within 0.01%, 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/dv1394.c linux-2.4.21-pre6/drivers/ieee1394/dv1394.c
--- linux-2.4.20/drivers/ieee1394/dv1394.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ieee1394/dv1394.c	2003-03-26 23:49:10.000000000 +0000
@@ -53,6 +53,12 @@
     via pci_alloc_consistent()
     
   DONE:
+  - during reception, better handling of dropped frames and continuity errors
+  - during reception, prevent DMA from bypassing the irq tasklets
+  - reduce irq rate during reception (1/250 packets).
+  - add many more internal buffers during reception with scatter/gather dma.
+  - add dbc (continuity) checking on receive, increment status.dropped_frames
+    if not continuous.
   - restart IT DMA after a bus reset
   - safely obtain and release ISO Tx channels in cooperation with OHCI driver
   - map received DIF blocks to their proper location in DV frame (ensure
@@ -91,13 +97,12 @@
 #include <linux/fs.h>
 #include <linux/poll.h>
 #include <linux/smp_lock.h>
+#include <linux/bitops.h>
 #include <asm/byteorder.h>
 #include <asm/atomic.h>
-#include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <linux/proc_fs.h>
-#include <linux/tqueue.h>
 #include <linux/delay.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
@@ -186,39 +191,6 @@
 	return (struct video_card*) file->private_data;
 }
 
-
-/*******************************/
-/* Memory management functions */
-/*******************************/
-
-/* note: we no longer use mem_map_reserve, because it causes a memory
-   leak, and setting vma->vm_flags to VM_RESERVED should be sufficient
-   to pin the pages in memory anyway. */
-
-static void * rvmalloc(unsigned long size)
-{
-	void * mem;
-
-	mem = vmalloc_32(size);
-
-	if(mem)
-		memset(mem, 0, size); /* Clear the ram out, 
-					 no junk to the user */
-	return mem;
-}
-
-static void rvfree(void * mem, unsigned long size)
-{
-	if (mem) {
-		vfree(mem);
-	}
-}
-
-/***********************************/
-/* END Memory management functions */
-/***********************************/
-
-
 /*** FRAME METHODS *********************************************************/
 
 static void frame_reset(struct frame *f)
@@ -447,11 +419,7 @@
 		/******************************/
 
 		/* first descriptor - OUTPUT_MORE_IMMEDIATE, for the controller's IT header */
-		fill_output_more_immediate( &(block->u.out.omi),
-					    /* tag - what is this??? */ 1,
-					    video->channel,
-					    /* sync tag - what is this??? */ 0,
-					    payload_size);
+		fill_output_more_immediate( &(block->u.out.omi), 1, video->channel, 0, payload_size);
 
 		if(empty_packet) {
 			/* second descriptor - OUTPUT_LAST for CIP header */
@@ -502,8 +470,8 @@
 						  PAGE_SIZE - (data_p % PAGE_SIZE),
 
 						  /* DMA address of data_p */
-						  dma_offset_to_bus(&f->video->user_dma,
-								    data_p - (unsigned long) f->video->user_buf));
+						  dma_region_offset_to_bus(&video->dv_buf,
+									   data_p - (unsigned long) video->dv_buf.kvirt));
 
 				fill_output_last( &(block->u.out.u.full.u.cross.ol),
 					  
@@ -517,8 +485,8 @@
 						  480 - (PAGE_SIZE - (data_p % PAGE_SIZE)),
 
 						  /* DMA address of data_p + PAGE_SIZE - (data_p % PAGE_SIZE) */
-						  dma_offset_to_bus(&f->video->user_dma,
-								    data_p + PAGE_SIZE - (data_p % PAGE_SIZE) - (unsigned long) f->video->user_buf));
+						  dma_region_offset_to_bus(&video->dv_buf,
+									   data_p + PAGE_SIZE - (data_p % PAGE_SIZE) - (unsigned long) video->dv_buf.kvirt));
 
 				if(first_packet)
 					f->frame_begin_timestamp = &(block->u.out.u.full.u.cross.ol.q[3]);
@@ -552,8 +520,8 @@
 
 						  
 						  /* DMA address of data_p */
-						  dma_offset_to_bus(&f->video->user_dma,
-								    data_p - (unsigned long) f->video->user_buf));
+						  dma_region_offset_to_bus(&video->dv_buf,
+									   data_p - (unsigned long) video->dv_buf.kvirt));
 				
 				if(first_packet)
 					f->frame_begin_timestamp = &(block->u.out.u.full.u.nocross.ol.q[3]);
@@ -594,13 +562,8 @@
 	   to loop back up to the top */
 	*(f->frame_end_branch) = cpu_to_le32(f->descriptor_pool_dma | f->first_n_descriptors);
 
-
-	/* make the latest version of the frame buffer visible to the PCI card */
-	/* could optimize this by only syncing the pages associated with this frame */
-	pci_dma_sync_sg(video->ohci->dev,
-			&video->user_dma.sglist[0],
-			video->user_dma.n_dma_pages,
-			PCI_DMA_TODEVICE);
+	/* make the latest version of this frame visible to the PCI card */
+	dma_region_sync(&video->dv_buf, f->data - (unsigned long) video->dv_buf.kvirt, video->frame_size);
 
 	/* lock against DMA interrupt */
 	spin_lock_irqsave(&video->spinlock, irq_flags);
@@ -732,7 +695,7 @@
 		wmb();
 #endif
 
-		
+		video->dma_running = 1;
 
 		/* set the 'run' bit */
 		reg_write(video->ohci, video->ohci_IsoXmitContextControlSet, 0x8000);
@@ -799,6 +762,9 @@
 	int dif_sequence = p->data[1] >> 4;           /* dif sequence number is in bits 4 - 7 */
 	int dif_block = p->data[2];
 
+	/* sanity check */
+	if (dif_sequence > 11 || dif_block > 149) return;
+		
 	switch (section_type) {
 	case 0:           /* 1 Header block */
 	        memcpy( (void *) f->data + dif_sequence * 150 * 80, p->data, 480);
@@ -826,47 +792,66 @@
 }
 
 
-static void start_dma_receive(struct video_card *video, struct frame *frame)
+static void start_dma_receive(struct video_card *video)
 {
-	/* reset iso recv control register */
-	reg_write(video->ohci, video->ohci_IsoRcvContextControlClear, 0xFFFFFFFF);
-	wmb();
+	if (video->first_run == 1) {
+		video->first_run = 0;
+		
+		/* start DMA once all of the frames are READY */
+		video->n_clear_frames = 0;
+		video->first_clear_frame = -1;
+		video->current_packet = 0;
+		video->active_frame = 0;
+		
+		/* reset iso recv control register */
+		reg_write(video->ohci, video->ohci_IsoRcvContextControlClear, 0xFFFFFFFF);
+		wmb();
+		
+		/* clear bufferFill, set isochHeader and speed (0=100) */
+		reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x40000000);
 	
-	/* clear bufferFill, set isochHeader and speed (0=100) */
-	reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x40000000);
+		/* match on all tags, listen on channel */
+		reg_write(video->ohci, video->ohci_IsoRcvContextMatch, 0xf0000000 | video->channel);
+		
+		/* address and first descriptor block + Z=1 */
+		reg_write(video->ohci, video->ohci_IsoRcvCommandPtr,             
+			  video->frames[0]->descriptor_pool_dma | 1); /* Z=1 */
+		wmb();
 
-	/* match on all tags, listen on channel */
-	reg_write(video->ohci, video->ohci_IsoRcvContextMatch, 0xf0000000 | video->channel);
-	
-	/* address and first descriptor block + Z=1 */
-	reg_write(video->ohci, video->ohci_IsoRcvCommandPtr,             
-		  frame->descriptor_pool_dma | 1); /* Z=1 */
-	wmb();
-	
-	/* run */
-	reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x8000);
-	flush_pci_write(video->ohci);
-	
-	debug_printk("dv1394: DMA started\n");
+		video->dma_running = 1;
 
-#if DV1394_DEBUG_LEVEL >= 2
-	{
-		int i;
+		/* run */
+		reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x8000);
+		flush_pci_write(video->ohci);
+		
+		debug_printk("dv1394: DMA started\n");
 	
-		for(i = 0; i < 1000; ++i) {
-			mdelay(1);
-			if(reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) {
-				printk("DMA ACTIVE after %d msec\n", i);
-				break;
+#if DV1394_DEBUG_LEVEL >= 2
+		{
+			int i;
+		
+			for(i = 0; i < 1000; ++i) {
+				mdelay(1);
+				if(reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) {
+					printk("DMA ACTIVE after %d msec\n", i);
+					break;
+				}
 			}
+			if( reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) &  (1 << 11) ) {
+				printk("DEAD, event = %x\n", 
+					   reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & 0x1F);
+			} else
+				printk("RUNNING!\n");
 		}
-		if( reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) &  (1 << 11) ) {
-			printk("DEAD, event = %x\n", 
-			       reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & 0x1F);
-		} else
-			printk("RUNNING!\n");
-	}
 #endif
+	} 
+	else if( reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) &  (1 << 11) ) {
+		debug_printk("DEAD, event = %x\n", 
+			     reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & 0x1F);
+
+		/* wake */
+		reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 12));
+	}
 }
 
 
@@ -874,7 +859,7 @@
    receive_packets() - build the DMA program for receiving
 */
 
-static void receive_packets(struct video_card *video, struct frame *f)
+static void receive_packets(struct video_card *video)
 {
 	struct DMA_descriptor_block *block = NULL;
 	dma_addr_t block_dma = 0;
@@ -882,52 +867,46 @@
 	dma_addr_t data_dma = 0;
 	u32 *last_branch_address = NULL;
 	unsigned long irq_flags;
+	int want_interrupt = 0;
+	struct frame *f = NULL;
+	int i, j;
 
 	spin_lock_irqsave(&video->spinlock, irq_flags);
 
-	video->n_clear_frames = 0;
-	video->first_clear_frame = -1;
-
-	for (video->current_packet = 0; video->current_packet < MAX_PACKET_BUFFER; ++video->current_packet) {
-		/* locate a descriptor block and packet from the buffer */
-		block = &(f->descriptor_pool[video->current_packet]);
-		block_dma = ((unsigned long) block - (unsigned long) f->descriptor_pool) + f->descriptor_pool_dma;
-		
-		data = &(video->packet_buffer[video->current_packet]);
-		data_dma = ((unsigned long) data - (unsigned long) video->packet_buffer) + video->packet_buffer_dma;
-		
-		/* setup DMA descriptor block */
-		fill_input_last( &(block->u.in.il), 512, data_dma);
+	for (j = 0; j < video->n_frames; j++) {
 
-		/* link descriptors */
-		last_branch_address = f->frame_end_branch;
+		/* connect frames */
+		if (j > 0 && f != NULL && f->frame_end_branch != NULL)
+			*(f->frame_end_branch) = cpu_to_le32(video->frames[j]->descriptor_pool_dma | 1); /* set Z=1 */
 
-		if (last_branch_address)
-			*(last_branch_address) = cpu_to_le32(block_dma | 1); /* set Z=1 */
+		f = video->frames[j];
 
-		f->frame_end_branch = &(block->u.in.il.q[2]);
-	}
+		for (i = 0; i < MAX_PACKETS; i++) {
+			/* locate a descriptor block and packet from the buffer */
+			block = &(f->descriptor_pool[i]);
+			block_dma = ((unsigned long) block - (unsigned long) f->descriptor_pool) + f->descriptor_pool_dma;
+			
+			data = ((struct packet*)video->packet_buf.kvirt) + f->frame_num * MAX_PACKETS + i;
+			data_dma = dma_region_offset_to_bus( &video->packet_buf, 
+							     ((unsigned long) data - (unsigned long) video->packet_buf.kvirt) );
+			
+			/* setup DMA descriptor block */
+			want_interrupt = ((i % (MAX_PACKETS/2)) == 0 || i == (MAX_PACKETS-1));
+			fill_input_last( &(block->u.in.il), want_interrupt, 512, data_dma);
+	
+			/* link descriptors */
+			last_branch_address = f->frame_end_branch;
+	
+			if (last_branch_address != NULL)
+				*(last_branch_address) = cpu_to_le32(block_dma | 1); /* set Z=1 */
 	
-	/* loop tail to head */
-	if (f->frame_end_branch)
-		*(f->frame_end_branch) = cpu_to_le32(f->descriptor_pool_dma | 1); /* set Z=1 */
+			f->frame_end_branch = &(block->u.in.il.q[2]);
+		}
+	
+	} /* next j */
 
 	spin_unlock_irqrestore(&video->spinlock, irq_flags);
 
-	if (video->first_run) {
-		/* start DMA once all of the frames are READY */
-		video->first_run = 0;
-		video->current_packet = 0;
-		video->active_frame = f->frame_num;
-		start_dma_receive(video, f);
-	} 
-	else if( reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) &  (1 << 11) ) {
-		debug_printk("DEAD, event = %x\n", 
-			     reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & 0x1F);
-
-		/* wake */
-		reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 12));
-	}
 }
 
 
@@ -941,15 +920,16 @@
 	u64 chan_mask;
 	int retval = -EINVAL;
 
+	debug_printk("dv1394: initialising %d\n", video->id);
 	if(init->api_version != DV1394_API_VERSION)
-		goto err;
+		return -EINVAL;
 	
 	/* first sanitize all the parameters */
 	if( (init->n_frames < 2) || (init->n_frames > DV1394_MAX_FRAMES) )
-		goto err;
+		return -EINVAL;
 
 	if( (init->format != DV1394_NTSC) && (init->format != DV1394_PAL) )
-		goto err;
+		return -EINVAL;
 
 	if( (init->syt_offset == 0) || (init->syt_offset > 50) )
 		/* default SYT offset is 3 cycles */
@@ -970,17 +950,15 @@
 	if(new_buf_size % PAGE_SIZE) new_buf_size += PAGE_SIZE - (new_buf_size % PAGE_SIZE);
 
 	/* don't allow the user to allocate the DMA buffer more than once */
-	if( (video->user_buf) &&
-	    (video->user_buf_size != new_buf_size) ) {
-		goto err;
+	if(video->dv_buf.kvirt && video->dv_buf_size != new_buf_size) {
+		printk("dv1394: re-sizing the DMA buffer is not allowed\n");
+		return -EINVAL;
 	}
-	
+
 	/* shutdown the card if it's currently active */
 	/* (the card should not be reset if the parameters are screwy) */
-	if( video_card_initialized(video) )
-		do_dv1394_shutdown(video, 0);
-
 
+	do_dv1394_shutdown(video, 0);
 	
 	/* try to claim the ISO channel */
 	spin_lock_irqsave(&video->ohci->IR_channel_lock, flags);
@@ -997,7 +975,6 @@
 	/* initialize misc. fields of video */
 	video->n_frames = init->n_frames;
 	video->pal_or_ntsc = init->format;
-	
 
 	video->cip_accum = 0;
 	video->continuity_counter = 0;
@@ -1013,7 +990,6 @@
 	video->current_packet = -1;
 	video->first_frame = 0;
 
-
 	if(video->pal_or_ntsc == DV1394_NTSC) {
 		video->cip_n = init->cip_n != 0 ? init->cip_n : CIP_N_NTSC;
 		video->cip_d = init->cip_d != 0 ? init->cip_d : CIP_D_NTSC;
@@ -1026,14 +1002,8 @@
 
 	video->syt_offset = init->syt_offset;
 	
-	
 	/* find and claim DMA contexts on the OHCI card */
 
-	/* XXX this should be the last step of initialization, since the interrupt
-	   handler uses ohci_i*_ctx to indicate whether or not it is safe to touch
-	   frames. I'm not making this change quite yet, since it would be better
-	   to clean up the init/shutdown process first.*/
-
 	if(video->ohci_it_ctx == -1) {
 		ohci1394_init_iso_tasklet(&video->it_tasklet, OHCI_ISO_TRANSMIT,
 					  it_tasklet_func, (unsigned long) video);
@@ -1041,14 +1011,12 @@
 		if (ohci1394_register_iso_tasklet(video->ohci, &video->it_tasklet) < 0) {	
 			printk(KERN_ERR "dv1394: could not find an available IT DMA context\n");
 			retval = -EBUSY;
-			goto err_ctx;
-		}
-		else {
-			video->ohci_it_ctx = video->it_tasklet.context;
-			debug_printk("dv1394: claimed IT DMA context %d\n", video->ohci_it_ctx);
+			goto err;
 		}
+		
+		video->ohci_it_ctx = video->it_tasklet.context;
+		debug_printk("dv1394: claimed IT DMA context %d\n", video->ohci_it_ctx);
 	}
-	
 
 	if(video->ohci_ir_ctx == -1) {
 		ohci1394_init_iso_tasklet(&video->ir_tasklet, OHCI_ISO_RECEIVE,
@@ -1057,14 +1025,11 @@
 		if (ohci1394_register_iso_tasklet(video->ohci, &video->ir_tasklet) < 0) {
 			printk(KERN_ERR "dv1394: could not find an available IR DMA context\n");
 			retval = -EBUSY;
-			goto err_ctx;
-		}
-		else {
-			video->ohci_ir_ctx = video->ir_tasklet.context;
-			debug_printk("dv1394: claimed IR DMA context %d\n", video->ohci_ir_ctx);
+			goto err;
 		}
+		video->ohci_ir_ctx = video->ir_tasklet.context;
+		debug_printk("dv1394: claimed IR DMA context %d\n", video->ohci_ir_ctx);
 	}
-
 	
 	/* allocate struct frames */
 	for(i = 0; i < init->n_frames; i++) {
@@ -1073,97 +1038,43 @@
 		if(!video->frames[i]) {
 			printk(KERN_ERR "dv1394: Cannot allocate frame structs\n");
 			retval = -ENOMEM;
-			goto err_frames;
+			goto err;
 		}
 	}
 
-	
-
-	if(video->user_buf == NULL) {
-		unsigned int i;
-		
+	if(!video->dv_buf.kvirt) {
 		/* allocate the ringbuffer */
-		video->user_buf = rvmalloc(new_buf_size);
-		if(!video->user_buf) {
-			printk(KERN_ERR "dv1394: Cannot allocate frame buffers\n");
-			goto err_frames;
-		}
-		video->user_buf_size = new_buf_size;
-
-		/* allocate the sglist to hold the DMA addresses */
-		video->user_dma.n_pages = video->user_buf_size / PAGE_SIZE;
-		video->user_dma.sglist = kmalloc(video->user_dma.n_pages * sizeof(struct scatterlist), GFP_KERNEL);
-		if(!video->user_dma.sglist) {
-			printk(KERN_ERR "dv1394: Cannot allocate sglist for user buffer\n");
-			goto err_user_buf;
-		}
-
-		/* initialize all fields of all sglist entries to zero
-		   (new requirement due to PCI changes in 2.4.13) */
-
-		memset(video->user_dma.sglist, 0, video->user_dma.n_pages * sizeof(struct scatterlist));
+		retval = dma_region_alloc(&video->dv_buf, new_buf_size, video->ohci->dev, PCI_DMA_TODEVICE);
+		if(retval)
+			goto err;
+					  
+		video->dv_buf_size = new_buf_size;
 
-		
-		/* fill the sglist with the kernel addresses of pages in the non-contiguous buffer */
-		for(i = 0; i < video->user_dma.n_pages; i++) {
-			unsigned long va = (unsigned long) video->user_buf + i * PAGE_SIZE;
-			
-			video->user_dma.sglist[i].page = vmalloc_to_page((void *)va);
-			video->user_dma.sglist[i].length = PAGE_SIZE;
-		}
-		
-		/* map the buffer in the IOMMU */
-		/* the user_data buffer only allows DMA *to* the card for transmission;
-		   incoming DV data comes through the packet_buffer first, and then is copied to user_data */
-		video->user_dma.n_dma_pages = pci_map_sg(video->ohci->dev,
-							 &video->user_dma.sglist[0],
-							 video->user_dma.n_pages,
-							 PCI_DMA_TODEVICE);
-		if(video->user_dma.n_dma_pages == 0) {
-			printk(KERN_ERR "dv1394: Error mapping user buffer to the IOMMU\n");
-			goto err_user_buf;
-		}
-		
 		debug_printk("dv1394: Allocated %d frame buffers, total %u pages (%u DMA pages), %lu bytes\n", 
-			     video->n_frames, video->user_dma.n_pages,
-			     video->user_dma.n_dma_pages, video->user_buf_size);
+			     video->n_frames, video->dv_buf.n_pages,
+			     video->dv_buf.n_dma_pages, video->dv_buf_size);
 	}
 	
 	/* set up the frame->data pointers */
 	for(i = 0; i < video->n_frames; i++)
-		video->frames[i]->data = (unsigned long) video->user_buf + i * video->frame_size;
+		video->frames[i]->data = (unsigned long) video->dv_buf.kvirt + i * video->frame_size;
 
-	/* allocate packet buffers */
-	video->packet_buffer_size = sizeof(struct packet) * MAX_PACKET_BUFFER;
-	if (video->packet_buffer_size % PAGE_SIZE)
-		video->packet_buffer_size += PAGE_SIZE - (video->packet_buffer_size % PAGE_SIZE);
-
-	
-	video->packet_buffer = kmalloc(video->packet_buffer_size, GFP_KERNEL);
-	
-	if(!video->packet_buffer) {
-		printk(KERN_ERR "dv1394: Cannot allocate packet buffers");
-		retval = -ENOMEM;
-		goto err_user_buf;
-	}
-
-	/* map the packet buffer into the IOMMU */
-	video->packet_buffer_dma = pci_map_single(video->ohci->dev,
-						  video->packet_buffer,
-						  video->packet_buffer_size,
-						  PCI_DMA_FROMDEVICE);
-	if(!video->packet_buffer_dma) {
-		printk(KERN_ERR "dv1394: Cannot map packet buffer to IOMMU");
-		kfree(video->packet_buffer);
-		video->packet_buffer = NULL;
-		retval = -ENOMEM;
-		goto err_user_buf;
+	if(!video->packet_buf.kvirt) {
+		/* allocate packet buffer */
+		video->packet_buf_size = sizeof(struct packet) * video->n_frames * MAX_PACKETS;
+		if (video->packet_buf_size % PAGE_SIZE)
+			video->packet_buf_size += PAGE_SIZE - (video->packet_buf_size % PAGE_SIZE);
+		
+		retval = dma_region_alloc(&video->packet_buf, video->packet_buf_size,
+					  video->ohci->dev, PCI_DMA_FROMDEVICE);
+		if(retval)
+			goto err;
+		
+		debug_printk("dv1394: Allocated %d packets in buffer, total %u pages (%u DMA pages), %lu bytes\n", 
+				 video->n_frames*MAX_PACKETS, video->packet_buf.n_pages,
+				 video->packet_buf.n_dma_pages, video->packet_buf_size);
 	}
-
-	debug_printk("dv1394: Allocated %d packet buffers for receive, total %lu bytes\n", 
-		     MAX_PACKET_BUFFER, video->packet_buffer_size);
-
-
+	
 	/* set up register offsets for IT context */
 	/* IT DMA context registers are spaced 16 bytes apart */
 	video->ohci_IsoXmitContextControlSet = OHCI1394_IsoXmitContextControlSet+16*video->ohci_it_ctx;
@@ -1187,47 +1098,8 @@
 	
 	return 0;
 
- err_user_buf:
-	if(video->user_buf) {
-		if(video->user_dma.sglist) {
-			if(video->user_dma.n_dma_pages > 0) {
-				/* unmap it from the IOMMU */
-				pci_unmap_sg(video->ohci->dev,
-					     video->user_dma.sglist,
-					     video->user_dma.n_pages,
-					     PCI_DMA_TODEVICE);
-				video->user_dma.n_dma_pages = 0;
-			}
-			kfree(video->user_dma.sglist);
-			video->user_dma.sglist = NULL;
-			video->user_dma.n_pages = 0;
-		}
-		rvfree(video->user_buf, video->user_buf_size);
-		video->user_buf = NULL;
-		video->user_buf_size = 0;
-	}
-		
- err_frames:
-	for(i = 0; i < DV1394_MAX_FRAMES; i++) {
-		if(video->frames[i])
-			frame_delete(video->frames[i]);
-	}	
-	video->n_frames = 0;
-
- err_ctx:
-	if(video->ohci_it_ctx != -1) {
-		ohci1394_unregister_iso_tasklet(video->ohci, &video->it_tasklet);
-		video->ohci_it_ctx = -1;
-	}
-	if(video->ohci_ir_ctx != -1) {
-		ohci1394_unregister_iso_tasklet(video->ohci, &video->ir_tasklet);
-		video->ohci_ir_ctx = -1;
-	}
-	
-	spin_lock_irqsave(&video->ohci->IR_channel_lock, flags);
-	video->ohci->ISO_channel_usage &= ~chan_mask;
-	spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags);
- err:
+err:
+	do_dv1394_shutdown(video, 1);
 	return retval;
 }
 
@@ -1239,7 +1111,7 @@
 	struct dv1394_init init;
 
 	init.api_version = DV1394_API_VERSION;
-	init.n_frames = 2;
+	init.n_frames = DV1394_MAX_FRAMES / 4;
 	/* the following are now set via proc_fs or devfs */
 	init.channel = video->channel;
 	init.format = video->pal_or_ntsc;
@@ -1255,10 +1127,15 @@
 {
 	unsigned long flags;
 	int i;
-	
+
 	/* no interrupts */
 	spin_lock_irqsave(&video->spinlock, flags);
 
+	video->dma_running = 0;
+
+	if( (video->ohci_it_ctx == -1) && (video->ohci_ir_ctx == -1) )
+		goto out;
+
 	/* stop DMA if in progress */
 	if( (video->active_frame != -1) ||
 	    (reg_read(video->ohci, video->ohci_IsoXmitContextControlClear) & (1 << 10)) ||
@@ -1271,7 +1148,6 @@
 		
 		video->active_frame = -1;
 		video->first_run = 1;
-
 		
 		/* wait until DMA really stops */
 		i = 0;
@@ -1283,6 +1159,7 @@
 			if( (reg_read(video->ohci, video->ohci_IsoXmitContextControlClear) & (1 << 10)) ||
 			    (reg_read(video->ohci, video->ohci_IsoRcvContextControlClear)  & (1 << 10)) ) {
 				/* still active */
+				debug_printk("dv1394: stop_dma: DMA not stopped yet\n" );
 				mb();
 			} else {
 				debug_printk("dv1394: stop_dma: DMA stopped safely after %d ms\n", i/10);
@@ -1296,24 +1173,24 @@
 			printk(KERN_ERR "dv1394: stop_dma: DMA still going after %d ms!\n", i/10);
 		}
 	}
+	else
+		debug_printk("dv1394: stop_dma: already stopped.\n");
 
+out:
 	spin_unlock_irqrestore(&video->spinlock, flags);
 }
 
 
 
-static int do_dv1394_shutdown(struct video_card *video, int free_user_buf)
+static void do_dv1394_shutdown(struct video_card *video, int free_dv_buf)
 {
 	int i;
-	unsigned long flags;
 	
 	debug_printk("dv1394: shutdown...\n");
 
 	/* stop DMA if in progress */
 	stop_dma(video);
 	
-	spin_lock_irqsave(&video->spinlock, flags);
-
 	/* release the DMA contexts */
 	if(video->ohci_it_ctx != -1) {
 		video->ohci_IsoXmitContextControlSet = 0;
@@ -1323,7 +1200,8 @@
 		/* disable interrupts for IT context */
 		reg_write(video->ohci, OHCI1394_IsoXmitIntMaskClear, (1 << video->ohci_it_ctx));
 		
-		clear_bit(video->ohci_it_ctx, &video->ohci->it_ctx_usage);
+		/* remove tasklet */
+		ohci1394_unregister_iso_tasklet(video->ohci, &video->it_tasklet);
 		debug_printk("dv1394: IT context %d released\n", video->ohci_it_ctx);
 		video->ohci_it_ctx = -1;
 	}
@@ -1337,13 +1215,12 @@
 		/* disable interrupts for IR context */
 		reg_write(video->ohci, OHCI1394_IsoRecvIntMaskClear, (1 << video->ohci_ir_ctx));
 
-		clear_bit(video->ohci_ir_ctx, &video->ohci->ir_ctx_usage);
+		/* remove tasklet */
+		ohci1394_unregister_iso_tasklet(video->ohci, &video->ir_tasklet);
 		debug_printk("dv1394: IR context %d released\n", video->ohci_ir_ctx);
 		video->ohci_ir_ctx = -1;
 	}
 
-	spin_unlock_irqrestore(&video->spinlock, flags);
-	
 	/* release the ISO channel */
 	if(video->channel != -1) {
 		u64 chan_mask;
@@ -1370,42 +1247,18 @@
 	/* we can't free the DMA buffer unless it is guaranteed that
 	   no more user-space mappings exist */
 	
-	if(free_user_buf && video->user_buf) {
-		if(video->user_dma.sglist) {
-			if(video->user_dma.n_dma_pages > 0) {
-				/* unmap it from the IOMMU */
-				pci_unmap_sg(video->ohci->dev,
-					     video->user_dma.sglist,
-					     video->user_dma.n_pages,
-					     PCI_DMA_TODEVICE);
-				video->user_dma.n_dma_pages = 0;
-			}
-			kfree(video->user_dma.sglist);
-			video->user_dma.sglist = NULL;
-			video->user_dma.n_pages = 0;
-		}
-		rvfree(video->user_buf, video->user_buf_size);
-		video->user_buf = NULL;
-		video->user_buf_size = 0;
-	}
-	
-	if (video->packet_buffer) {
-		pci_unmap_single(video->ohci->dev,
-				 video->packet_buffer_dma,
-				 video->packet_buffer_size,
-				 PCI_DMA_FROMDEVICE);
-		kfree(video->packet_buffer);
-		video->packet_buffer = NULL;
-		video->packet_buffer_size = 0;
+	if(free_dv_buf) {
+		dma_region_free(&video->dv_buf);
+		video->dv_buf_size = 0;
 	}
 
-	debug_printk("dv1394: shutdown complete\n");
+	/* free packet buffer */
+	dma_region_free(&video->packet_buf);
+	video->packet_buf_size = 0;
 
-	return 0;
+	debug_printk("dv1394: shutdown OK\n");
 }
 
-
-
 /*
        **********************************
        *** MMAP() THEORY OF OPERATION ***
@@ -1428,96 +1281,28 @@
 	force the user to choose one buffer size and stick with
 	it. This small sacrifice is worth the huge reduction in
 	error-prone code in dv1394.
-
-	Note: dv1394_mmap does no page table manipulation. The page
-	table entries are created by the dv1394_nopage() handler as
-	page faults are taken by the user.
-*/
-
-static struct page * dv1394_nopage(struct vm_area_struct * area, unsigned long address, int write_access)
-{
-	unsigned long offset;
-	unsigned long kernel_virt_addr;
-	struct page *ret = NOPAGE_SIGBUS;
-
-	struct video_card *video = (struct video_card*) area->vm_private_data;
-	
-	/* guard against process-context operations and the interrupt */
-	/* (by definition page faults are taken in interrupt context) */
-	spin_lock(&video->spinlock);
-
-	if(!video->user_buf)
-		goto out;
-
-	if( (address < (unsigned long) area->vm_start) ||
-	    (address > (unsigned long) area->vm_start + video->user_buf_size) )
-		goto out;
-
-	offset = address - area->vm_start;
-	kernel_virt_addr = (unsigned long) video->user_buf + offset;
-	ret = vmalloc_to_page((void *)kernel_virt_addr);
-	get_page(ret);
-
- out:
-	spin_unlock(&video->spinlock);
-	return ret;
-}
-
-static struct vm_operations_struct dv1394_vm_ops = {
-	.nopage = dv1394_nopage
-};
-
-/*
-  dv1394_mmap does no page table manipulation. The page table entries
-  are created by the dv1394_nopage() handler as page faults are taken
-  by the user.
 */
 
 int dv1394_mmap(struct file *file, struct vm_area_struct *vma)
 {
 	struct video_card *video = file_to_video_card(file);
-	unsigned long size;
-	int res = -EINVAL;
+	int retval = -EINVAL;
 
 	/* serialize mmap */
 	down(&video->sem);
 
 	if( ! video_card_initialized(video) ) {
-		res = do_dv1394_init_default(video);
-		if(res)
-			goto err;
+		retval = do_dv1394_init_default(video);
+		if(retval)
+			goto out;
 	}
 
-	/* region must be page-aligned */
-	if(vma->vm_pgoff != 0)
-		goto err;
-	
-	/* check the size the user is trying to map */
-	size = vma->vm_end - vma->vm_start;
-	if(size > video->user_buf_size)
-		goto err;
-
-	/* 
-	   we don't actually mess with the page tables here.
-	   (nopage() takes care of that from the page fault handler)
-	   Just set up the vma->vm_ops.
-	*/
-
-        vma->vm_ops = &dv1394_vm_ops;
-	vma->vm_private_data = video;
-	vma->vm_file = file;
-
-	/* don't try to swap this out =) */
-	vma->vm_flags |= VM_RESERVED;
-
+	retval = dma_region_mmap(&video->dv_buf, file, vma);
+out:
 	up(&video->sem);
-	return 0;
- err:
-	up(&video->sem);
-	return res;
+	return retval;
 }
 
-
 /*** DEVICE FILE INTERFACE *************************************************/
 
 /* no need to serialize, multiple threads OK */
@@ -1633,7 +1418,7 @@
 			continue; /* start over from 'while(count > 0)...' */
 		}
 
-		if(copy_from_user(video->user_buf + video->write_off, buffer, cnt)) {
+		if(copy_from_user(video->dv_buf.kvirt + video->write_off, buffer, cnt)) {
 			if(!ret)
 				ret = -EFAULT;
 			break;
@@ -1680,7 +1465,11 @@
 			up(&video->sem);
 			return ret;
 		}
-		receive_packets(video, video->frames[video->first_clear_frame]);
+		video->continuity_counter = -1;
+		
+		receive_packets(video);
+		
+		start_dma_receive(video);
 	}
 
 	ret = 0;
@@ -1733,7 +1522,7 @@
 			continue; /* start over from 'while(count > 0)...' */
 		}
 
-		if(copy_to_user(buffer, video->user_buf + video->write_off, cnt)) {
+		if(copy_to_user(buffer, video->dv_buf.kvirt + video->write_off, cnt)) {
 				if(!ret)
 					ret = -EFAULT;
 				break;
@@ -1785,7 +1574,8 @@
 
 	switch(cmd)
 	{
-	case DV1394_SUBMIT_FRAMES: {
+	case DV1394_SUBMIT_FRAMES:
+	case DV1394_IOC_SUBMIT_FRAMES: {
 		unsigned int n_submit;
 
 		if( !video_card_initialized(video) ) {
@@ -1838,8 +1628,8 @@
 		ret = 0;
 		break;
 	}
-
-	case DV1394_WAIT_FRAMES: {
+	case DV1394_WAIT_FRAMES:
+	case DV1394_IOC_WAIT_FRAMES: {
 		unsigned int n_wait;
 
 		if( !video_card_initialized(video) ) {
@@ -1887,8 +1677,8 @@
 		ret = 0;
 		break;
 	}
-
-	case DV1394_RECEIVE_FRAMES: {
+	case DV1394_RECEIVE_FRAMES:
+	case DV1394_IOC_RECEIVE_FRAMES: {
 		unsigned int n_recv;
 
 		if( !video_card_initialized(video) ) {
@@ -1920,22 +1710,25 @@
 		ret = 0;
 		break;
 	}
-
-	case DV1394_START_RECEIVE: {
-
+	case DV1394_START_RECEIVE:
+	case DV1394_IOC_START_RECEIVE: {
 		if( !video_card_initialized(video) ) {
 			ret = do_dv1394_init_default(video);
 			if(ret)
 				goto out;
 		}
 	
-		receive_packets(video, video->frames[video->first_clear_frame]);
+		video->continuity_counter = -1;
+		
+		receive_packets(video);
+		
+		start_dma_receive(video);
 
 		ret = 0;
 		break;
 	}
-
-	case DV1394_INIT: {
+	case DV1394_INIT:
+	case DV1394_IOC_INIT: {
 		struct dv1394_init init;
 		if(arg == (unsigned long) NULL) {
 			ret = do_dv1394_init_default(video);
@@ -1948,13 +1741,14 @@
 		}
 		break;
 	}
-
 	case DV1394_SHUTDOWN:
-		ret = do_dv1394_shutdown(video, 0);
+	case DV1394_IOC_SHUTDOWN:
+		do_dv1394_shutdown(video, 0);
+		ret = 0;
 		break;
 
-
-        case DV1394_GET_STATUS: {
+	case DV1394_GET_STATUS:
+        case DV1394_IOC_GET_STATUS: {
 		struct dv1394_status status;
 
 		if( !video_card_initialized(video) ) {
@@ -2027,7 +1821,7 @@
 			struct video_card *p;
 			list_for_each(lh, &dv1394_cards) {
 				p = list_entry(lh, struct video_card, list);
-				if((p->id >> 2) == ieee1394_file_to_instance(file)) {
+				if((p->id) == ieee1394_file_to_instance(file)) {
 					video = p;
 					break;
 				}
@@ -2319,9 +2113,10 @@
 	struct video_card *video = (struct video_card*) data;
 
 	spin_lock(&video->spinlock);
-	
-	irq_printk("INTERRUPT! Video = %08lx Iso event Recv: %08x Xmit: %08x\n",
-		   (unsigned long) video, isoRecvIntEvent, isoXmitIntEvent);
+
+	if(!video->dma_running)
+		goto out;
+
 	irq_printk("ContextControl = %08x, CommandPtr = %08x\n", 
 	       reg_read(video->ohci, video->ohci_IsoXmitContextControlSet),
 	       reg_read(video->ohci, video->ohci_IsoXmitCommandPtr)
@@ -2448,14 +2243,15 @@
 		} /* for(each frame) */
 	}
 
-	spin_unlock(&video->spinlock);
-
 	if(wake) {
 		kill_fasync(&video->fasync, SIGIO, POLL_OUT);
 		
 		/* wake readers/writers/ioctl'ers */
 		wake_up_interruptible(&video->waitq);
 	}
+
+out:
+	spin_unlock(&video->spinlock);
 }
 
 static void ir_tasklet_func(unsigned long data)
@@ -2463,83 +2259,151 @@
 	int wake = 0;
 	struct video_card *video = (struct video_card*) data;
 
+	spin_lock(&video->spinlock);
+
+	if(!video->dma_running)
+		goto out;
+	
 	if( (video->ohci_ir_ctx != -1) &&
-	    (reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) ) { 
+	    (reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) )
+	{ 
 
 		int sof=0; /* start-of-frame flag */
 		struct frame *f;
 		u16 packet_length, packet_time;
-
-		packet_length = le16_to_cpu(video->packet_buffer[video->current_packet].data_length);
-		packet_time   = le16_to_cpu(video->packet_buffer[video->current_packet].timestamp);
-
-		irq_printk("received packet %02d, timestamp=%04x, length=%04x, sof=%02x%02x\n", video->current_packet,
-			   packet_time, packet_length, 
-			   video->packet_buffer[video->current_packet].data[0], video->packet_buffer[video->current_packet].data[1]);
-		
-		f = video->frames[video->active_frame];
-
-		/* exclude empty packet */
-		if (packet_length > 8) {
-		
-			/* check for start of frame */
-			sof = (video->packet_buffer[video->current_packet].data[0] == 0x1f &&
-				video->packet_buffer[video->current_packet].data[1] == 0x07);
-
-			if (!video->first_frame) {
-				if (sof) {
-					video->first_frame = 1;
-				}
-
-			} else if (sof) {
-				/* close current frame */
-				frame_reset(f);  /* f->state = STATE_CLEAR */
-				video->n_clear_frames++;
-				if (video->n_clear_frames > video->n_frames) {
-					video->n_clear_frames = video->n_frames;
-					video->dropped_frames++;
-				}
-				if (video->first_clear_frame == -1)
-					video->first_clear_frame = video->active_frame;
-
-				/* get the next frame */
-				video->active_frame = (video->active_frame + 1) % video->n_frames;
-				f = video->frames[video->active_frame];
-			
-				irq_printk("   frame received, active_frame = %d, n_clear_frames = %d, first_clear_frame = %d\n",
-					   video->active_frame, video->n_clear_frames, video->first_clear_frame);
- 			}
-			if (video->first_frame) {
-				if (sof) {
-					/* open next frame */
-					f->state = FRAME_READY;
+		int i, dbc=0;
+		struct DMA_descriptor_block *block = NULL;
+		u16 xferstatus;
+
+		int next_i, prev_i;
+		struct DMA_descriptor_block *next = NULL;
+		dma_addr_t next_dma = 0;
+		struct DMA_descriptor_block *prev = NULL;
+
+		/* loop over all descriptors in all frames */
+		for (i = 0; i < video->n_frames*MAX_PACKETS; i++) {
+			struct packet *p = dma_region_i(&video->packet_buf, struct packet, video->current_packet);
+
+			/* make sure we are seeing the latest changes to p */
+			dma_region_sync(&video->packet_buf,
+					(unsigned long) p - (unsigned long) video->packet_buf.kvirt,
+					sizeof(struct packet));
+					
+			packet_length = le16_to_cpu(p->data_length);
+			packet_time   = le16_to_cpu(p->timestamp);
+	
+			irq_printk("received packet %02d, timestamp=%04x, length=%04x, sof=%02x%02x\n", video->current_packet,
+				   packet_time, packet_length, 
+				   p->data[0], p->data[1]);
+			
+			/* get the descriptor based on packet_buffer cursor */
+			f = video->frames[video->current_packet / MAX_PACKETS];
+			block = &(f->descriptor_pool[video->current_packet % MAX_PACKETS]);
+			xferstatus = le16_to_cpu(block->u.in.il.q[3] >> 16);
+			xferstatus &= 0x1F;
+
+			/* get the current frame */
+			f = video->frames[video->active_frame];
+		
+			/* exclude empty packet */
+			if (packet_length > 8 && xferstatus == 0x11) {
+				irq_printk("ir_tasklet_func: xferStatus/resCount [%d] = 0x%08x\n", i, le32_to_cpu(block->u.in.il.q[3]) );
+			
+				/* check for start of frame */
+				/* DRD> Changed to check section type ([0]>>5==0) 
+				   and dif sequence ([1]>>4==0) */
+				sof = ( (p->data[0] >> 5) == 0 && (p->data[1] >> 4) == 0);
+	
+				dbc = (int) (p->cip_h1 >> 24);
+				if ( video->continuity_counter != -1 && dbc > ((video->continuity_counter + 1) % 256) )
+				{
+					printk(KERN_WARNING "dv1394: discontinuity detected, dropping all frames\n" );
+					video->dropped_frames += video->n_clear_frames + 1;
+					video->first_frame = 0;
+					video->n_clear_frames = 0;
+					video->first_clear_frame = -1;
 				}
+				video->continuity_counter = dbc;
 				
-				/* copy to buffer */
-				if (f->n_packets > (video->frame_size / 480)) {
-					printk(KERN_ERR "frame buffer overflow during receive\n");
+				if (!video->first_frame) {
+					if (sof) {
+						video->first_frame = 1;
+					}
+	
+				} else if (sof) {
+					/* close current frame */
+					frame_reset(f);  /* f->state = STATE_CLEAR */
+					video->n_clear_frames++;
+					if (video->n_clear_frames > video->n_frames) {
+						video->dropped_frames++;
+						printk(KERN_WARNING "dv1394: dropped a frame during reception\n" );
+						video->n_clear_frames = video->n_frames-1;
+						video->first_clear_frame = (video->first_clear_frame + 1) % video->n_frames;
+					}
+					if (video->first_clear_frame == -1)
+						video->first_clear_frame = video->active_frame;
+	
+					/* get the next frame */
+					video->active_frame = (video->active_frame + 1) % video->n_frames;
+					f = video->frames[video->active_frame];
+					irq_printk("   frame received, active_frame = %d, n_clear_frames = %d, first_clear_frame = %d\n",
+						   video->active_frame, video->n_clear_frames, video->first_clear_frame);
 				}
+				if (video->first_frame) {
+					if (sof) {
+						/* open next frame */
+						f->state = FRAME_READY;
+					}
+					
+					/* copy to buffer */
+					if (f->n_packets > (video->frame_size / 480)) {
+						printk(KERN_ERR "frame buffer overflow during receive\n");
+					}
+					
+					frame_put_packet(f, p);
+					
+				} /* first_frame */
+			}
+			
+			/* stop, end of ready packets */
+			else if (xferstatus == 0) {
+				break;
+			}
+	 
+			/* reset xferStatus & resCount */
+			block->u.in.il.q[3] = cpu_to_le32(512);
 
-				/* make sure we are seeing the latest changes to packet_buffer */
-				pci_dma_sync_single(video->ohci->dev,
-						    video->packet_buffer_dma,
-						    video->packet_buffer_size,
-						    PCI_DMA_FROMDEVICE);
-				
-				frame_put_packet( f, &video->packet_buffer[video->current_packet]);
-				
-			} /* first_frame */
- 
-		} /* not empty packet */
- 
-		/* advance packet_buffer cursor */
-		video->current_packet = (video->current_packet + 1) % MAX_PACKET_BUFFER;
+			/* terminate dma chain at this (next) packet */
+			next_i = video->current_packet;
+			f = video->frames[next_i / MAX_PACKETS];
+			next = &(f->descriptor_pool[next_i % MAX_PACKETS]);
+			next_dma = ((unsigned long) block - (unsigned long) f->descriptor_pool) + f->descriptor_pool_dma;
+			next->u.in.il.q[0] |= 3 << 20; /* enable interrupt */
+			next->u.in.il.q[2] = 0; /* disable branch */
+			
+			/* link previous to next */
+			prev_i = (next_i == 0) ? (MAX_PACKETS * video->n_frames - 1) : (next_i - 1);
+			f = video->frames[prev_i / MAX_PACKETS];
+			prev = &(f->descriptor_pool[prev_i % MAX_PACKETS]);
+			if(prev_i % (MAX_PACKETS/2)) {
+				prev->u.in.il.q[0] &= ~(3 << 20); /* no interrupt */
+			} else {
+				prev->u.in.il.q[0] |= 3 << 20; /* enable interrupt */
+			}
+			prev->u.in.il.q[2] =  (cpu_to_le32(next_dma) | 1); /* set Z=1 */
+			wmb();
+
+			/* wake up DMA in case it fell asleep */
+			reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 12));
+
+			/* advance packet_buffer cursor */
+			video->current_packet = (video->current_packet + 1) % (MAX_PACKETS * video->n_frames);
+			
+		} /* for all packets */
  
 		wake = 1; /* why the hell not? */
-
+		
 	} /* receive interrupt */
-
-	spin_unlock(&video->spinlock);
 	
 	if(wake) {
 		kill_fasync(&video->fasync, SIGIO, POLL_IN);
@@ -2547,6 +2411,9 @@
 		/* wake readers/writers/ioctl'ers */
 		wake_up_interruptible(&video->waitq);
 	}
+	
+out:
+	spin_unlock(&video->spinlock);
 }
 
 static struct file_operations dv1394_fops=
@@ -2587,6 +2454,7 @@
 	return p;
 }
 
+#ifdef CONFIG_DEVFS_FS
 static int dv1394_devfs_add_entry(struct video_card *video)
 {
 	char buf[32];
@@ -2694,6 +2562,7 @@
 		kfree(p);
 	}
 }
+#endif /* CONFIG_DEVFS_FS */
 
 /*** IEEE1394 HPSB CALLBACKS ***********************************************/
 
@@ -2715,6 +2584,10 @@
 	/* lower 2 bits of id indicate which of four "plugs"
 	   per host */
 	video->id = ohci->id << 2; 
+	if (format == DV1394_NTSC)
+		video->id |= mode;
+	else
+		video->id |= 2 + mode;
 
 	video->ohci_it_ctx = -1;
 	video->ohci_ir_ctx = -1;
@@ -2747,11 +2620,14 @@
 	for(i = 0; i < DV1394_MAX_FRAMES; i++)
 		video->frames[i] = NULL;
 
-	video->user_buf = NULL;
-	video->user_buf_size = 0;
+	dma_region_init(&video->dv_buf);
+	video->dv_buf_size = 0;
+	dma_region_init(&video->packet_buf);
+	video->packet_buf_size = 0;
 
 	clear_bit(0, &video->open);
 	spin_lock_init(&video->spinlock);
+	video->dma_running = 0;
 	init_MUTEX(&video->sem);
 	init_waitqueue_head(&video->waitq);
 	video->fasync = NULL;
@@ -2761,10 +2637,6 @@
 	list_add_tail(&video->list, &dv1394_cards);
 	spin_unlock_irqrestore(&dv1394_cards_lock, flags);
 	
-	if (format == DV1394_NTSC)
-		video->id |= mode;
-	else video->id |= 2 + mode;
-
 #ifdef CONFIG_DEVFS_FS
 	if (dv1394_devfs_add_entry(video) < 0)
 			goto err_free;
@@ -2806,7 +2678,7 @@
 	struct ti_ohci *ohci;
 	struct video_card *video = NULL;
 	unsigned long flags;
-	struct list_head *lh;
+	struct list_head *lh, *templh;
 	char buf[32];
 	int	n;
 	
@@ -2820,7 +2692,7 @@
 	/* find the corresponding video_cards */
 	spin_lock_irqsave(&dv1394_cards_lock, flags);
 	if(!list_empty(&dv1394_cards)) {
-		list_for_each(lh, &dv1394_cards) {
+		list_for_each_safe(lh, templh, &dv1394_cards) {
 			video = list_entry(lh, struct video_card, list);
 			if((video->id >> 2) == ohci->id)
 				dv1394_un_init(video);
@@ -2852,7 +2724,6 @@
 {
 	struct ti_ohci *ohci;
 	char buf[16];
-	struct dv1394_devfs_entry *devfs_entry;
 
 	/* We only work with the OHCI-1394 driver */
 	if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
@@ -2874,13 +2745,15 @@
 #endif
 
 #ifdef CONFIG_DEVFS_FS
-	devfs_entry = dv1394_devfs_find("dv");
+{
+	struct dv1394_devfs_entry *devfs_entry = dv1394_devfs_find("dv");
 	if (devfs_entry != NULL) {
 		snprintf(buf, sizeof(buf), "host%d", ohci->id);
 		dv1394_devfs_add_dir(buf, devfs_entry, &devfs_entry);
 		dv1394_devfs_add_dir("NTSC", devfs_entry, NULL);
 		dv1394_devfs_add_dir("PAL", devfs_entry, NULL);
 	}
+}
 #endif
 	
 	dv1394_init(ohci, DV1394_NTSC, MODE_RECEIVE);
@@ -2926,6 +2799,9 @@
 	
 	spin_lock_irqsave(&video->spinlock, flags);
 
+	if(!video->dma_running)
+		goto out;
+
 	/* check IT context */
 	if(video->ohci_it_ctx != -1) {
 		u32 ctx;
@@ -2998,7 +2874,8 @@
 				   reg_read(video->ohci, video->ohci_IsoRcvCommandPtr));
 		}
 	}
-	
+
+out:
 	spin_unlock_irqrestore(&video->spinlock, flags);
 	
 	/* wake readers/writers/ioctl'ers */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/dv1394.h linux-2.4.21-pre6/drivers/ieee1394/dv1394.h
--- linux-2.4.20/drivers/ieee1394/dv1394.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ieee1394/dv1394.h	2003-03-26 23:49:49.000000000 +0000
@@ -242,6 +242,7 @@
 	DV1394_GET_STATUS,
 };
 
+#include "ieee1394-ioctl.h"
 
 
 enum pal_or_ntsc {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/eth1394.c linux-2.4.21-pre6/drivers/ieee1394/eth1394.c
--- linux-2.4.20/drivers/ieee1394/eth1394.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ieee1394/eth1394.c	2003-03-26 23:49:51.000000000 +0000
@@ -77,7 +77,7 @@
 	printk(KERN_ERR fmt, ## args)
 
 static char version[] __devinitdata =
-	"$Rev: 546 $ Ben Collins <bcollins@debian.org>";
+	"$Rev: 807 $ Ben Collins <bcollins@debian.org>";
 
 /* Our ieee1394 highlevel driver */
 #define ETHER1394_DRIVER_NAME "ether1394"
@@ -206,7 +206,7 @@
 	unsigned char arp_data[2*(dev->addr_len+4)];
 
 	/* Copy the main data that we need */
-	arp_ptr = memcpy (arp_data, arp_ptr + sizeof(struct arphdr), sizeof (arp_data));
+	memcpy (arp_data, arp_ptr + sizeof(struct arphdr), sizeof (arp_data));
 
 	/* Extend the buffer enough for our new header */
 	skb_put (skb, sizeof (struct eth1394_arp) -
@@ -214,7 +214,7 @@
 
 #define PROCESS_MEMBER(ptr,val,len) \
   memcpy (val, ptr, len); ptr += len
-	arp_ptr += arp1394->hw_addr_len;
+	arp_ptr = arp_data + arp1394->hw_addr_len;
 	PROCESS_MEMBER (arp_ptr, &arp1394->sip, arp1394->ip_addr_len);
 	arp_ptr += arp1394->hw_addr_len;
 	PROCESS_MEMBER (arp_ptr, &arp1394->tip, arp1394->ip_addr_len);
@@ -368,6 +368,7 @@
 	if (register_netdev (dev)) {
 		ETH1394_PRINT (KERN_ERR, dev->name, "Error registering network driver\n");
 		kfree (dev);
+		kfree (hi);
 		return;
 	}
 
@@ -497,7 +498,7 @@
 		spin_unlock_irqrestore (&priv->lock, flags);
 
 #define PROCESS_MEMBER(ptr,val,len) \
-  ptr = memcpy (ptr, val, len) + len
+  memcpy (ptr, val, len); ptr += len
                 PROCESS_MEMBER (arp_ptr, src_hw, dev->addr_len);
                 PROCESS_MEMBER (arp_ptr, &arp1394.sip, 4);
                 PROCESS_MEMBER (arp_ptr, dest_hw, dev->addr_len);
@@ -522,7 +523,7 @@
  * ethernet header, and fill it with some of our other fields. This is
  * an incoming packet from the 1394 bus.  */
 static int ether1394_write (struct hpsb_host *host, int srcid, int destid,
-			    quadlet_t *data, u64 addr, unsigned int len)
+			    quadlet_t *data, u64 addr, unsigned int len, u16 fl)
 {
 	struct sk_buff *skb;
 	char *buf = (char *)data;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/highlevel.c linux-2.4.21-pre6/drivers/ieee1394/highlevel.c
--- linux-2.4.20/drivers/ieee1394/highlevel.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ieee1394/highlevel.c	2003-03-26 23:49:54.000000000 +0000
@@ -5,6 +5,16 @@
  *
  * This code is licensed under the GPL.  See the file COPYING in the root
  * directory of the kernel sources for details.
+ *
+ *
+ * Contributions:
+ *
+ * Christian Toegel <christian.toegel@gmx.at>
+ *        unregister address space
+ *
+ * Manfred Weihs <weihs@ict.tuwien.ac.at>
+ *        unregister address space
+ *
  */
 
 #include <linux/config.h>
@@ -129,6 +139,32 @@
         return retval;
 }
 
+int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, u64 start)
+{
+        int retval = 0;
+        struct hpsb_address_serve *as;
+        struct list_head *entry;
+
+        write_lock_irq(&addr_space_lock);
+
+        entry = hl->addr_list.next;
+
+        while (entry != &hl->addr_list) {
+                as = list_entry(entry, struct hpsb_address_serve, addr_list);
+                entry = entry->next;
+                if (as->start == start) {
+                        list_del(&as->as_list);
+                        list_del(&as->addr_list);
+                        kfree(as);
+                        retval = 1;
+                        break;
+                }
+        }
+
+        write_unlock_irq(&addr_space_lock);
+
+        return retval;
+}
 
 void hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
                          unsigned int channel)
@@ -243,7 +279,7 @@
 }
 
 int highlevel_read(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
-                   u64 addr, unsigned int length)
+                   u64 addr, unsigned int length, u16 flags)
 {
         struct hpsb_address_serve *as;
         struct list_head *entry;
@@ -261,7 +297,7 @@
 
                         if (as->op->read != NULL) {
                                 rcode = as->op->read(host, nodeid, buffer,
-						     addr, partlength);
+						     addr, partlength, flags);
                         } else {
                                 rcode = RCODE_TYPE_ERROR;
                         }
@@ -288,7 +324,7 @@
 }
 
 int highlevel_write(struct hpsb_host *host, int nodeid, int destid,
-		    quadlet_t *data, u64 addr, unsigned int length)
+		    quadlet_t *data, u64 addr, unsigned int length, u16 flags)
 {
         struct hpsb_address_serve *as;
         struct list_head *entry;
@@ -306,7 +342,7 @@
 
                         if (as->op->write != NULL) {
                                 rcode = as->op->write(host, nodeid, destid,
-						      data, addr, partlength);
+						      data, addr, partlength, flags);
                         } else {
                                 rcode = RCODE_TYPE_ERROR;
                         }
@@ -334,7 +370,7 @@
 
 
 int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
-                   u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode)
+                   u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags)
 {
         struct hpsb_address_serve *as;
         struct list_head *entry;
@@ -349,7 +385,7 @@
                 if (as->end > addr) {
                         if (as->op->lock != NULL) {
                                 rcode = as->op->lock(host, nodeid, store, addr,
-                                                     data, arg, ext_tcode);
+                                                     data, arg, ext_tcode, flags);
                         } else {
                                 rcode = RCODE_TYPE_ERROR;
                         }
@@ -367,7 +403,7 @@
 }
 
 int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
-                     u64 addr, octlet_t data, octlet_t arg, int ext_tcode)
+                     u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags)
 {
         struct hpsb_address_serve *as;
         struct list_head *entry;
@@ -383,7 +419,7 @@
                         if (as->op->lock64 != NULL) {
                                 rcode = as->op->lock64(host, nodeid, store,
                                                        addr, data, arg,
-                                                       ext_tcode);
+                                                       ext_tcode, flags);
                         } else {
                                 rcode = RCODE_TYPE_ERROR;
                         }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/highlevel.h linux-2.4.21-pre6/drivers/ieee1394/highlevel.h
--- linux-2.4.20/drivers/ieee1394/highlevel.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ieee1394/highlevel.h	2003-03-26 23:49:25.000000000 +0000
@@ -74,17 +74,22 @@
          */
 
         /* These functions have to implement block reads for themselves. */
+        /* These functions either return a response code
+           or a negative number. In the first case a response will be generated; in the 
+           later case, no response will be sent and the driver, that handled the request
+           will send the response itself
+        */
         int (*read) (struct hpsb_host *host, int nodeid, quadlet_t *buffer,
-                     u64 addr, unsigned int length);
+                     u64 addr, unsigned int length, u16 flags);
         int (*write) (struct hpsb_host *host, int nodeid, int destid,
-		      quadlet_t *data, u64 addr, unsigned int length);
+		      quadlet_t *data, u64 addr, unsigned int length, u16 flags);
 
         /* Lock transactions: write results of ext_tcode operation into
          * *store. */
         int (*lock) (struct hpsb_host *host, int nodeid, quadlet_t *store,
-                     u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode);
+                     u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags);
         int (*lock64) (struct hpsb_host *host, int nodeid, octlet_t *store,
-                       u64 addr, octlet_t data, octlet_t arg, int ext_tcode);
+                       u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags);
 };
 
 
@@ -94,14 +99,23 @@
 void highlevel_remove_host(struct hpsb_host *host);
 void highlevel_host_reset(struct hpsb_host *host);
 
+
+/* these functions are called to handle transactions. They are called, when
+   a packet arrives. The flags argument contains the second word of the first header
+   quadlet of the incoming packet (containing transaction label, retry code,
+   transaction code and priority). These functions either return a response code
+   or a negative number. In the first case a response will be generated; in the 
+   later case, no response will be sent and the driver, that handled the request
+   will send the response itself.
+*/
 int highlevel_read(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
-                   u64 addr, unsigned int length);
+                   u64 addr, unsigned int length, u16 flags);
 int highlevel_write(struct hpsb_host *host, int nodeid, int destid,
-		    quadlet_t *data, u64 addr, unsigned int length);
+		    quadlet_t *data, u64 addr, unsigned int length, u16 flags);
 int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
-                   u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode);
+                   u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags);
 int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
-                     u64 addr, octlet_t data, octlet_t arg, int ext_tcode);
+                     u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags);
 
 void highlevel_iso_receive(struct hpsb_host *host, quadlet_t *data,
                            unsigned int length);
@@ -130,6 +144,8 @@
 int hpsb_register_addrspace(struct hpsb_highlevel *hl,
                             struct hpsb_address_ops *ops, u64 start, u64 end);
 
+int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, u64 start);
+
 /*
  * Enable or disable receving a certain isochronous channel through the
  * iso_receive op.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/hosts.h linux-2.4.21-pre6/drivers/ieee1394/hosts.h
--- linux-2.4.20/drivers/ieee1394/hosts.h	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ieee1394/hosts.h	2003-03-26 23:49:10.000000000 +0000
@@ -2,15 +2,24 @@
 #define _IEEE1394_HOSTS_H
 
 #include <linux/wait.h>
-#include <linux/tqueue.h>
 #include <linux/list.h>
+#include <linux/tqueue.h>
 #include <asm/semaphore.h>
 
 #include "ieee1394_types.h"
 #include "csr.h"
 
+/* size of the array used to store config rom (in quadlets)
+   maximum is 0x100. About 0x40 is needed for the default
+   entries. So 0x80 should provide enough space for additional
+   directories etc. 
+   Note: All lowlevel drivers are required to allocate at least
+         this amount of memory for the configuration rom!
+*/
+#define CSR_CONFIG_ROM_SIZE       0x100
 
 struct hpsb_packet;
+struct hpsb_iso;
 
 struct hpsb_host {
         struct list_head host_list;
@@ -101,6 +110,31 @@
         ISO_UNLISTEN_CHANNEL
 };
 
+enum isoctl_cmd {
+	/* rawiso API - see iso.h for the meanings of these commands
+	 * INIT = allocate resources
+	 * START = begin transmission/reception
+	 * STOP = halt transmission/reception
+	 * QUEUE/RELEASE = produce/consume packets
+	 * SHUTDOWN = deallocate resources
+	 */
+
+	XMIT_INIT,
+	XMIT_START,
+	XMIT_STOP,
+	XMIT_QUEUE,
+	XMIT_SHUTDOWN,
+
+	RECV_INIT,
+	RECV_LISTEN_CHANNEL,   /* multi-channel only */
+	RECV_UNLISTEN_CHANNEL, /* multi-channel only */
+	RECV_SET_CHANNEL_MASK, /* multi-channel only; arg is a *u64 */
+	RECV_START,
+	RECV_STOP,
+	RECV_RELEASE,
+	RECV_SHUTDOWN,
+};
+
 enum reset_types {
         /* 166 microsecond reset -- only type of reset available on
            non-1394a capable IEEE 1394 controllers */
@@ -119,7 +153,7 @@
          * may not fail.  If any allocation is required, it must be done
          * earlier.
          */
-        size_t (*get_rom) (struct hpsb_host *host, const quadlet_t **pointer);
+        size_t (*get_rom) (struct hpsb_host *host, quadlet_t **pointer);
 
         /* This function shall implement packet transmission based on
          * packet->type.  It shall CRC both parts of the packet (unless
@@ -138,6 +172,12 @@
          */
         int (*devctl) (struct hpsb_host *host, enum devctl_cmd command, int arg);
 
+	 /* rawiso transmission/reception functions. Return 0 on success, -1
+	  * (or -EXXX errno code) on failure. If the low-level driver does not
+	  * support the rawiso API, set isoctl to NULL.
+	  */
+	int (*isoctl) (struct hpsb_iso *iso, enum isoctl_cmd command, unsigned long arg);
+
         /* This function is mainly to redirect local CSR reads/locks to the iso
          * management registers (bus manager id, bandwidth available, channels
          * available) to the hardware registers in OHCI.  reg is 0,1,2,3 for bus
@@ -172,4 +212,24 @@
 void hpsb_add_host(struct hpsb_host *host);
 void hpsb_remove_host(struct hpsb_host *h);
 
+/* updates the configuration rom of a host.
+ * rom_version must be the current version,
+ * otherwise it will fail with return value -1.
+ * Return value -2 indicates that the new
+ * rom version is too big.
+ * Return value 0 indicates success
+ */
+int hpsb_update_config_rom(struct hpsb_host *host,
+      const quadlet_t *new_rom, size_t size, unsigned char rom_version);
+
+/* reads the current version of the configuration rom of a host.
+ * buffersize is the size of the buffer, rom_size
+ * returns the size of the current rom image.
+ * rom_version is the version number of the fetched rom.
+ * return value -1 indicates, that the buffer was
+ * too small, 0 indicates success.
+ */
+int hpsb_get_config_rom(struct hpsb_host *host, quadlet_t *buffer,
+      size_t buffersize, size_t *rom_size, unsigned char *rom_version);
+
 #endif /* _IEEE1394_HOSTS_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/ieee1394-ioctl.h linux-2.4.21-pre6/drivers/ieee1394/ieee1394-ioctl.h
--- linux-2.4.20/drivers/ieee1394/ieee1394-ioctl.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ieee1394/ieee1394-ioctl.h	2003-03-26 23:49:09.000000000 +0000
@@ -0,0 +1,105 @@
+/* Base file for all ieee1394 ioctl's. Linux-1394 has allocated base '#'
+ * with a range of 0x00-0x3f. */
+
+#ifndef __IEEE1394_IOCTL_H
+#define __IEEE1394_IOCTL_H
+
+#include <asm/ioctl.h>
+#include <asm/types.h>
+
+
+/* AMDTP Gets 6 */
+#define AMDTP_IOC_CHANNEL	_IOW('#', 0x00, struct amdtp_ioctl)
+#define AMDTP_IOC_PLUG		_IOW('#', 0x01, struct amdtp_ioctl)
+#define AMDTP_IOC_PING		_IOW('#', 0x02, struct amdtp_ioctl)
+#define AMDTP_IOC_ZAP		_IO ('#', 0x03)
+
+
+/* DV1394 Gets 10 */
+
+/* Get the driver ready to transmit video.  pass a struct dv1394_init* as
+ * the parameter (see below), or NULL to get default parameters */
+#define DV1394_IOC_INIT			_IOW('#', 0x06, struct dv1394_init)
+
+/* Stop transmitting video and free the ringbuffer */
+#define DV1394_IOC_SHUTDOWN		_IO ('#', 0x07)
+
+/* Submit N new frames to be transmitted, where the index of the first new
+ * frame is first_clear_buffer, and the index of the last new frame is
+ * (first_clear_buffer + N) % n_frames */
+#define DV1394_IOC_SUBMIT_FRAMES	_IO ('#', 0x08)
+
+/* Block until N buffers are clear (pass N as the parameter) Because we
+ * re-transmit the last frame on underrun, there will at most be n_frames
+ * - 1 clear frames at any time */
+#define DV1394_IOC_WAIT_FRAMES		_IO ('#', 0x09)
+
+/* Capture new frames that have been received, where the index of the
+ * first new frame is first_clear_buffer, and the index of the last new
+ * frame is (first_clear_buffer + N) % n_frames */
+#define DV1394_IOC_RECEIVE_FRAMES	_IO ('#', 0x0a)
+
+/* Tell card to start receiving DMA */
+#define DV1394_IOC_START_RECEIVE	_IO ('#', 0x0b)
+
+/* Pass a struct dv1394_status* as the parameter */
+#define DV1394_IOC_GET_STATUS		_IOR('#', 0x0c, struct dv1394_status)
+
+
+/* Video1394 Gets 10 */
+
+#define VIDEO1394_IOC_LISTEN_CHANNEL		\
+	_IOWR('#', 0x10, struct video1394_mmap)
+#define VIDEO1394_IOC_UNLISTEN_CHANNEL		\
+	_IOW ('#', 0x11, int)
+#define VIDEO1394_IOC_LISTEN_QUEUE_BUFFER	\
+	_IOW ('#', 0x12, struct video1394_wait)
+#define VIDEO1394_IOC_LISTEN_WAIT_BUFFER	\
+	_IOWR('#', 0x13, struct video1394_wait)
+#define VIDEO1394_IOC_TALK_CHANNEL		\
+	_IOWR('#', 0x14, struct video1394_mmap)
+#define VIDEO1394_IOC_UNTALK_CHANNEL		\
+	_IOW ('#', 0x15, int)
+#define VIDEO1394_IOC_TALK_QUEUE_BUFFER 	\
+	_IOW ('#', 0x16, sizeof (struct video1394_wait) + \
+		sizeof (struct video1394_queue_variable))
+#define VIDEO1394_IOC_TALK_WAIT_BUFFER		\
+	_IOW ('#', 0x17, struct video1394_wait)
+#define VIDEO1394_IOC_LISTEN_POLL_BUFFER	\
+	_IOWR('#', 0x18, struct video1394_wait)
+
+
+/* Raw1394's ISO interface */
+#define RAW1394_IOC_ISO_XMIT_INIT		\
+	_IOW ('#', 0x1a, struct raw1394_iso_status)
+#define RAW1394_IOC_ISO_RECV_INIT		\
+	_IOWR('#', 0x1b, struct raw1394_iso_status)
+#define RAW1394_IOC_ISO_RECV_START		\
+	_IOC (_IOC_WRITE, '#', 0x1c, sizeof(int) * 3)
+#define RAW1394_IOC_ISO_XMIT_START		\
+	_IOC (_IOC_WRITE, '#', 0x1d, sizeof(int) * 2)
+#define RAW1394_IOC_ISO_XMIT_RECV_STOP		\
+	_IO  ('#', 0x1e)
+#define RAW1394_IOC_ISO_GET_STATUS		\
+	_IOR ('#', 0x1f, struct raw1394_iso_status)
+#define RAW1394_IOC_ISO_SHUTDOWN		\
+	_IO  ('#', 0x20)
+#define RAW1394_IOC_ISO_QUEUE_ACTIVITY		\
+	_IO  ('#', 0x21)
+#define RAW1394_IOC_ISO_RECV_LISTEN_CHANNEL	\
+	_IOW ('#', 0x22, unsigned char)
+#define RAW1394_IOC_ISO_RECV_UNLISTEN_CHANNEL	\
+	_IOW ('#', 0x23, unsigned char)
+#define RAW1394_IOC_ISO_RECV_SET_CHANNEL_MASK	\
+	_IOW ('#', 0x24, __u64)
+#define RAW1394_IOC_ISO_RECV_PACKETS		\
+	_IOW ('#', 0x25, struct raw1394_iso_packets)
+#define RAW1394_IOC_ISO_RECV_RELEASE_PACKETS	\
+	_IOW ('#', 0x26, unsigned int)
+#define RAW1394_IOC_ISO_XMIT_PACKETS		\
+	_IOW ('#', 0x27, struct raw1394_iso_packets)
+#define RAW1394_IOC_ISO_XMIT_SYNC		\
+	_IO  ('#', 0x28)
+
+
+#endif /* __IEEE1394_IOCTL_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/ieee1394.h linux-2.4.21-pre6/drivers/ieee1394/ieee1394.h
--- linux-2.4.20/drivers/ieee1394/ieee1394.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ieee1394/ieee1394.h	2003-03-26 23:49:21.000000000 +0000
@@ -15,6 +15,7 @@
 #define TCODE_CYCLE_START        0x8
 #define TCODE_LOCK_REQUEST       0x9
 #define TCODE_ISO_DATA           0xa
+#define TCODE_STREAM_DATA        0xa
 #define TCODE_LOCK_RESPONSE      0xb
 
 #define RCODE_COMPLETE           0x0
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/ieee1394_core.c linux-2.4.21-pre6/drivers/ieee1394/ieee1394_core.c
--- linux-2.4.20/drivers/ieee1394/ieee1394_core.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ieee1394/ieee1394_core.c	2003-03-26 23:49:19.000000000 +0000
@@ -5,9 +5,19 @@
  *               highlevel or lowlevel code
  *
  * Copyright (C) 1999, 2000 Andreas E. Bombe
+ *                     2002 Manfred Weihs <weihs@ict.tuwien.ac.at>
  *
  * This code is licensed under the GPL.  See the file COPYING in the root
  * directory of the kernel sources for details.
+ *
+ *
+ * Contributions:
+ *
+ * Manfred Weihs <weihs@ict.tuwien.ac.at>
+ *        loopback functionality in hpsb_send_packet
+ *        allow highlevel drivers to disable automatic response generation
+ *              and to generate responses themselves (deferred)
+ *
  */
 
 #include <linux/config.h>
@@ -19,7 +29,6 @@
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/proc_fs.h>
-#include <linux/tqueue.h>
 #include <asm/bitops.h>
 #include <asm/byteorder.h>
 #include <asm/semaphore.h>
@@ -33,6 +42,8 @@
 #include "csr.h"
 #include "nodemgr.h"
 #include "ieee1394_hotplug.h"
+#include "dma.h"
+#include "iso.h"
 
 /*
  * Disable the nodemgr detection and config rom reading functionality.
@@ -72,7 +83,8 @@
 	struct list_head *lh, *next;
 
 	list_for_each_safe(lh, next, &packet->complete_tq) {
-		struct tq_struct *tq = list_entry(lh, struct tq_struct, list);
+		struct tq_struct *tq =
+			list_entry(lh, struct tq_struct, list);
 		list_del(&tq->list);
 		schedule_task(tq);
 	}
@@ -372,12 +384,19 @@
                 build_speed_map(host, host->node_count);
         }
 
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+        HPSB_INFO("selfid_complete called with successful SelfID stage "
+		"... irm_id: 0x%X node_id: 0x%X",host->irm_id,host->node_id);
+#endif
         /* irm_id is kept up to date by check_selfids() */
         if (host->irm_id == host->node_id) {
                 host->is_irm = 1;
                 host->is_busmgr = 1;
                 host->busmgr_id = host->node_id;
                 host->csr.bus_manager_id = host->node_id;
+        } else {
+                host->is_busmgr = 0;
+                host->is_irm = 0;
         }
 
         host->reset_retries = 0;
@@ -448,6 +467,45 @@
 
         packet->state = hpsb_queued;
 
+        if (packet->node_id == host->node_id)
+        { /* it is a local request, so handle it locally */
+                quadlet_t *data;
+                size_t size=packet->data_size+packet->header_size;
+
+                int kmflags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
+                data = kmalloc(packet->header_size + packet->data_size, kmflags);
+                if (!data) {
+                        HPSB_ERR("unable to allocate memory for concatenating header and data");
+                        return 0;
+                }
+
+                memcpy(data, packet->header, packet->header_size);
+
+                if (packet->data_size)
+                {
+                        if (packet->data_be) {
+                                memcpy(((u8*)data)+packet->header_size, packet->data, packet->data_size);
+                        } else {
+                                int i;
+                                quadlet_t *my_data=(quadlet_t*) ((u8*) data + packet->data_size);
+                                for (i=0; i < packet->data_size/4; i++) {
+                                        my_data[i] = cpu_to_be32(packet->data[i]);
+                                }
+                        }
+                }
+
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+                dump_packet("send packet local:", packet->header,
+                            packet->header_size);
+#endif
+                hpsb_packet_sent(host, packet,  packet->expect_response?ACK_PENDING:ACK_COMPLETE);
+                hpsb_packet_received(host, data, size, 0);
+
+                kfree(data);
+
+                return 1;
+        }
+
         if (packet->type == hpsb_async && packet->node_id != ALL_NODES) {
                 packet->speed_code =
                         host->speed_map[(host->node_id & NODE_MASK) * 64
@@ -600,8 +658,10 @@
 {
         struct hpsb_packet *packet;
         int length, rcode, extcode;
+        quadlet_t buffer;
         nodeid_t source = data[1] >> 16;
-	nodeid_t dest = data[0] >> 16;
+        nodeid_t dest = data[0] >> 16;
+        u16 flags = (u16) data[0];
         u64 addr;
 
         /* big FIXME - no error checking is done for an out of bounds length */
@@ -610,10 +670,11 @@
         case TCODE_WRITEQ:
                 addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
                 rcode = highlevel_write(host, source, dest, data+3,
-					addr, 4);
+					addr, 4, flags);
 
                 if (!write_acked
-                    && ((data[0] >> 16) & NODE_MASK) != NODE_MASK) {
+                    && (((data[0] >> 16) & NODE_MASK) != NODE_MASK)
+                    && (rcode >= 0)) {
                         /* not a broadcast write, reply */
                         PREP_REPLY_PACKET(0);
                         fill_async_write_resp(packet, rcode);
@@ -624,10 +685,11 @@
         case TCODE_WRITEB:
                 addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
                 rcode = highlevel_write(host, source, dest, data+4,
-					addr, data[3]>>16);
+					addr, data[3]>>16, flags);
 
                 if (!write_acked
-                    && ((data[0] >> 16) & NODE_MASK) != NODE_MASK) {
+                    && (((data[0] >> 16) & NODE_MASK) != NODE_MASK)
+                    && (rcode >= 0)) {
                         /* not a broadcast write, reply */
                         PREP_REPLY_PACKET(0);
                         fill_async_write_resp(packet, rcode);
@@ -636,12 +698,14 @@
                 break;
 
         case TCODE_READQ:
-                PREP_REPLY_PACKET(0);
-
                 addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
-                rcode = highlevel_read(host, source, data, addr, 4);
-                fill_async_readquad_resp(packet, rcode, *data);
-                send_packet_nocare(packet);
+                rcode = highlevel_read(host, source, &buffer, addr, 4, flags);
+
+                if (rcode >= 0) {
+                        PREP_REPLY_PACKET(0);
+                        fill_async_readquad_resp(packet, rcode, buffer);
+                        send_packet_nocare(packet);
+                }
                 break;
 
         case TCODE_READB:
@@ -650,9 +714,12 @@
 
                 addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
                 rcode = highlevel_read(host, source, packet->data, addr,
-                                       length);
-                fill_async_readblock_resp(packet, rcode, length);
-                send_packet_nocare(packet);
+                                       length, flags);
+
+                if (rcode >= 0) {
+                        fill_async_readblock_resp(packet, rcode, length);
+                        send_packet_nocare(packet);
+                }
                 break;
 
         case TCODE_LOCK_REQUEST:
@@ -670,7 +737,7 @@
                 switch (length) {
                 case 4:
                         rcode = highlevel_lock(host, source, packet->data, addr,
-                                               data[4], 0, extcode);
+                                               data[4], 0, extcode,flags);
                         fill_async_lock_resp(packet, rcode, extcode, 4);
                         break;
                 case 8:
@@ -679,13 +746,13 @@
                                 rcode = highlevel_lock(host, source,
                                                        packet->data, addr,
                                                        data[5], data[4], 
-                                                       extcode);
+                                                       extcode, flags);
                                 fill_async_lock_resp(packet, rcode, extcode, 4);
                         } else {
                                 rcode = highlevel_lock64(host, source,
                                              (octlet_t *)packet->data, addr,
                                              *(octlet_t *)(data + 4), 0ULL,
-                                             extcode);
+                                             extcode, flags);
                                 fill_async_lock_resp(packet, rcode, extcode, 8);
                         }
                         break;
@@ -694,15 +761,20 @@
                                                  (octlet_t *)packet->data, addr,
                                                  *(octlet_t *)(data + 6),
                                                  *(octlet_t *)(data + 4), 
-                                                 extcode);
+                                                 extcode, flags);
                         fill_async_lock_resp(packet, rcode, extcode, 8);
                         break;
                 default:
-                        fill_async_lock_resp(packet, RCODE_TYPE_ERROR,
+                        rcode = RCODE_TYPE_ERROR;
+                        fill_async_lock_resp(packet, rcode,
                                              extcode, 0);
                 }
 
-                send_packet_nocare(packet);
+                if (rcode >= 0) {
+                        send_packet_nocare(packet);
+                } else {
+                        free_hpsb_packet(packet);
+                }
                 break;
         }
 
@@ -960,7 +1032,7 @@
 	   to get the index of the ieee1394_driver
 	   we want */
 	
-	blocknum = (minor(inode->i_rdev) >> 4) & 0xF;
+	blocknum = (MINOR(inode->i_rdev) >> 4) & 0xF;
 
 	/* look up the driver */
 
@@ -1073,14 +1145,17 @@
 module_exit(ieee1394_cleanup);
 
 /* Exported symbols */
+
+/** hosts.c **/
 EXPORT_SYMBOL(hpsb_alloc_host);
 EXPORT_SYMBOL(hpsb_add_host);
 EXPORT_SYMBOL(hpsb_remove_host);
 EXPORT_SYMBOL(hpsb_ref_host);
 EXPORT_SYMBOL(hpsb_unref_host);
+
+/** ieee1394_core.c **/
 EXPORT_SYMBOL(hpsb_speedto_str);
 EXPORT_SYMBOL(hpsb_add_packet_complete_task);
-
 EXPORT_SYMBOL(alloc_hpsb_packet);
 EXPORT_SYMBOL(free_hpsb_packet);
 EXPORT_SYMBOL(hpsb_send_packet);
@@ -1090,7 +1165,12 @@
 EXPORT_SYMBOL(hpsb_selfid_complete);
 EXPORT_SYMBOL(hpsb_packet_sent);
 EXPORT_SYMBOL(hpsb_packet_received);
+EXPORT_SYMBOL(ieee1394_register_chardev);
+EXPORT_SYMBOL(ieee1394_unregister_chardev);
+EXPORT_SYMBOL(ieee1394_devfs_handle);
+EXPORT_SYMBOL(ieee1394_procfs_entry);
 
+/** ieee1394_transactions.c **/
 EXPORT_SYMBOL(get_tlabel);
 EXPORT_SYMBOL(free_tlabel);
 EXPORT_SYMBOL(fill_async_readquad);
@@ -1109,6 +1189,7 @@
 EXPORT_SYMBOL(hpsb_make_writeqpacket);
 EXPORT_SYMBOL(hpsb_make_writebpacket);
 EXPORT_SYMBOL(hpsb_make_lockpacket);
+EXPORT_SYMBOL(hpsb_make_lock64packet);
 EXPORT_SYMBOL(hpsb_make_phypacket);
 EXPORT_SYMBOL(hpsb_packet_success);
 EXPORT_SYMBOL(hpsb_make_packet);
@@ -1116,9 +1197,11 @@
 EXPORT_SYMBOL(hpsb_write);
 EXPORT_SYMBOL(hpsb_lock);
 
+/** highlevel.c **/
 EXPORT_SYMBOL(hpsb_register_highlevel);
 EXPORT_SYMBOL(hpsb_unregister_highlevel);
 EXPORT_SYMBOL(hpsb_register_addrspace);
+EXPORT_SYMBOL(hpsb_unregister_addrspace);
 EXPORT_SYMBOL(hpsb_listen_channel);
 EXPORT_SYMBOL(hpsb_unlisten_channel);
 EXPORT_SYMBOL(highlevel_read);
@@ -1129,18 +1212,45 @@
 EXPORT_SYMBOL(highlevel_remove_host);
 EXPORT_SYMBOL(highlevel_host_reset);
 
+/** nodemgr.c **/
 EXPORT_SYMBOL(hpsb_guid_get_entry);
 EXPORT_SYMBOL(hpsb_nodeid_get_entry);
 EXPORT_SYMBOL(hpsb_node_fill_packet);
 EXPORT_SYMBOL(hpsb_node_read);
 EXPORT_SYMBOL(hpsb_node_write);
 EXPORT_SYMBOL(hpsb_node_lock);
+EXPORT_SYMBOL(hpsb_update_config_rom);
+EXPORT_SYMBOL(hpsb_get_config_rom);
 EXPORT_SYMBOL(hpsb_register_protocol);
 EXPORT_SYMBOL(hpsb_unregister_protocol);
 EXPORT_SYMBOL(hpsb_release_unit_directory);
 
-EXPORT_SYMBOL(ieee1394_register_chardev);
-EXPORT_SYMBOL(ieee1394_unregister_chardev);
-EXPORT_SYMBOL(ieee1394_devfs_handle);
+/** dma.c **/
+EXPORT_SYMBOL(dma_prog_region_init);
+EXPORT_SYMBOL(dma_prog_region_alloc);
+EXPORT_SYMBOL(dma_prog_region_free);
+EXPORT_SYMBOL(dma_region_init);
+EXPORT_SYMBOL(dma_region_alloc);
+EXPORT_SYMBOL(dma_region_free);
+EXPORT_SYMBOL(dma_region_sync);
+EXPORT_SYMBOL(dma_region_mmap);
+EXPORT_SYMBOL(dma_region_offset_to_bus);
+
+/** iso.c **/
+EXPORT_SYMBOL(hpsb_iso_xmit_init);
+EXPORT_SYMBOL(hpsb_iso_recv_init);
+EXPORT_SYMBOL(hpsb_iso_xmit_start);
+EXPORT_SYMBOL(hpsb_iso_recv_start);
+EXPORT_SYMBOL(hpsb_iso_recv_listen_channel);
+EXPORT_SYMBOL(hpsb_iso_recv_unlisten_channel);
+EXPORT_SYMBOL(hpsb_iso_recv_set_channel_mask);
+EXPORT_SYMBOL(hpsb_iso_stop);
+EXPORT_SYMBOL(hpsb_iso_shutdown);
+EXPORT_SYMBOL(hpsb_iso_xmit_queue_packet);
+EXPORT_SYMBOL(hpsb_iso_xmit_sync);
+EXPORT_SYMBOL(hpsb_iso_recv_release_packets);
+EXPORT_SYMBOL(hpsb_iso_n_ready);
+EXPORT_SYMBOL(hpsb_iso_packet_sent);
+EXPORT_SYMBOL(hpsb_iso_packet_received);
+EXPORT_SYMBOL(hpsb_iso_wake);
 
-EXPORT_SYMBOL(ieee1394_procfs_entry);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/ieee1394_core.h linux-2.4.21-pre6/drivers/ieee1394/ieee1394_core.h
--- linux-2.4.20/drivers/ieee1394/ieee1394_core.h	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ieee1394/ieee1394_core.h	2003-03-26 23:49:09.000000000 +0000
@@ -2,7 +2,6 @@
 #ifndef _IEEE1394_CORE_H
 #define _IEEE1394_CORE_H
 
-#include <linux/tqueue.h>
 #include <linux/slab.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/proc_fs.h>
@@ -195,7 +194,7 @@
 /* return the index (within a minor number block) of a file */
 static inline unsigned char ieee1394_file_to_instance(struct file *file)
 {
-	unsigned char minor = minor(file->f_dentry->d_inode->i_rdev);
+	unsigned char minor = MINOR(file->f_dentry->d_inode->i_rdev);
 	
 	/* return lower 4 bits */
 	return minor & 0xF;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/ieee1394_transactions.c linux-2.4.21-pre6/drivers/ieee1394/ieee1394_transactions.c
--- linux-2.4.20/drivers/ieee1394/ieee1394_transactions.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ieee1394/ieee1394_transactions.c	2003-03-26 23:49:25.000000000 +0000
@@ -297,14 +297,6 @@
         HPSB_PANIC("reached unreachable code 2 in %s", __FUNCTION__);
 }
 
-
-int hpsb_read_trylocal(struct hpsb_host *host, nodeid_t node, u64 addr, 
-                       quadlet_t *buffer, size_t length)
-{
-        if (host->node_id != node) return -1;
-        return highlevel_read(host, node, buffer, addr, length);
-}
-
 struct hpsb_packet *hpsb_make_readqpacket(struct hpsb_host *host, nodeid_t node,
                                           u64 addr)
 {
@@ -400,6 +392,31 @@
         return p;
 }
 
+struct hpsb_packet *hpsb_make_lock64packet(struct hpsb_host *host, nodeid_t node,
+                                           u64 addr, int extcode)
+{
+        struct hpsb_packet *p;
+
+        p = alloc_hpsb_packet(16);
+        if (!p) return NULL;
+
+        p->host = host;
+        p->tlabel = get_tlabel(host, node, 1);
+        p->node_id = node;
+
+        switch (extcode) {
+        case EXTCODE_FETCH_ADD:
+        case EXTCODE_LITTLE_ADD:
+                fill_async_lock(p, addr, extcode, 8);
+                break;
+        default:
+                fill_async_lock(p, addr, extcode, 16);
+                break;
+        }
+
+        return p;
+}
+
 struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host,
                                         quadlet_t data) 
 {
@@ -429,18 +446,6 @@
                 return -EINVAL;
         }
 
-        if (host->node_id == node) {
-                switch(highlevel_read(host, node, buffer, addr, length)) {
-                case RCODE_COMPLETE:
-                        return 0;
-                case RCODE_TYPE_ERROR:
-                        return -EACCES;
-                case RCODE_ADDRESS_ERROR:
-                default:
-                        return -EINVAL;
-                }
-        }
-
         if (length == 4) {
                 packet = hpsb_make_readqpacket(host, node, addr);
         } else {
@@ -509,18 +514,6 @@
 	if (length == 0)
 		return -EINVAL;
 
-	if (host->node_id == node) {
-		switch(highlevel_write(host, node, node, buffer, addr, length)) {
-		case RCODE_COMPLETE:
-			return 0;
-		case RCODE_TYPE_ERROR:
-			return -EACCES;
-		case RCODE_ADDRESS_ERROR:
-		default:
-			return -EINVAL;
-		}
-	}
-
 	packet = hpsb_make_packet (host, node, addr, buffer, length);
 
 	if (!packet)
@@ -551,19 +544,6 @@
         struct hpsb_packet *packet;
         int retval = 0, length;
         
-        if (host->node_id == node) {
-                switch(highlevel_lock(host, node, data, addr, *data, arg,
-                                      extcode)) {
-                case RCODE_COMPLETE:
-                        return 0;
-                case RCODE_TYPE_ERROR:
-                        return -EACCES;
-                case RCODE_ADDRESS_ERROR:
-                default:
-                        return -EINVAL;
-                }
-        }
-
         packet = alloc_hpsb_packet(8);
         if (!packet) {
                 return -ENOMEM;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/ieee1394_transactions.h linux-2.4.21-pre6/drivers/ieee1394/ieee1394_transactions.h
--- linux-2.4.20/drivers/ieee1394/ieee1394_transactions.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ieee1394/ieee1394_transactions.h	2003-03-26 23:49:25.000000000 +0000
@@ -42,6 +42,8 @@
                                            size_t length);
 struct hpsb_packet *hpsb_make_lockpacket(struct hpsb_host *host, nodeid_t node,
                                          u64 addr, int extcode);
+struct hpsb_packet *hpsb_make_lock64packet(struct hpsb_host *host, nodeid_t node,
+                                          u64 addr, int extcode);
 struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host,
                                         quadlet_t data) ;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/ieee1394_types.h linux-2.4.21-pre6/drivers/ieee1394/ieee1394_types.h
--- linux-2.4.20/drivers/ieee1394/ieee1394_types.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ieee1394/ieee1394_types.h	2003-03-26 23:49:50.000000000 +0000
@@ -10,46 +10,6 @@
 #include <asm/byteorder.h>
 
 
-/* The great kdev_t changeover in 2.5.x */
-#include <linux/kdev_t.h>
-#ifndef minor
-#define minor(dev) MINOR(dev)
-#endif
-
-#ifndef __devexit_p
-#define __devexit_p(x) x
-#endif
-
-/* This showed up around this time */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,12)
-
-# ifndef MODULE_LICENSE
-# define MODULE_LICENSE(x)
-# endif
-
-# ifndef min
-# define min(x,y) ({ \
-	const typeof(x) _x = (x);       \
-	const typeof(y) _y = (y);       \
-	(void) (&_x == &_y);            \
-	_x < _y ? _x : _y; })
-# endif
-
-#endif /* Linux version < 2.4.12 */
-
-#include <linux/spinlock.h>
-
-#ifndef list_for_each_safe
-#define list_for_each_safe(pos, n, head) \
-	for (pos = (head)->next, n = pos->next; pos != (head); \
-		pos = n, n = pos->next)
-
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,5)
-#define pte_offset_kernel pte_offset
-#endif
-
 #ifndef MIN
 #define MIN(a,b) ((a) < (b) ? (a) : (b))
 #endif
@@ -58,10 +18,15 @@
 #define MAX(a,b) ((a) > (b) ? (a) : (b))
 #endif
 
+
 typedef u32 quadlet_t;
 typedef u64 octlet_t;
 typedef u16 nodeid_t;
 
+typedef u8  byte_t;
+typedef u64 nodeaddr_t;
+typedef u16 arm_length_t;
+
 #define BUS_MASK  0xffc0
 #define NODE_MASK 0x003f
 #define LOCAL_BUS 0xffc0
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/iso.c linux-2.4.21-pre6/drivers/ieee1394/iso.c
--- linux-2.4.20/drivers/ieee1394/iso.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ieee1394/iso.c	2003-03-26 23:49:15.000000000 +0000
@@ -0,0 +1,439 @@
+/*
+ * IEEE 1394 for Linux
+ *
+ * kernel ISO transmission/reception
+ *
+ * Copyright (C) 2002 Maas Digital LLC
+ *
+ * This code is licensed under the GPL.  See the file COPYING in the root
+ * directory of the kernel sources for details.
+ */
+
+#include <linux/slab.h>
+#include "iso.h"
+
+void hpsb_iso_stop(struct hpsb_iso *iso)
+{
+	if(!iso->flags & HPSB_ISO_DRIVER_STARTED)
+		return;
+
+	iso->host->driver->isoctl(iso, iso->type == HPSB_ISO_XMIT ?
+				  XMIT_STOP : RECV_STOP, 0);
+	iso->flags &= ~HPSB_ISO_DRIVER_STARTED;
+}
+
+void hpsb_iso_shutdown(struct hpsb_iso *iso)
+{
+	if(iso->flags & HPSB_ISO_DRIVER_INIT) {
+		hpsb_iso_stop(iso);
+		iso->host->driver->isoctl(iso, iso->type == HPSB_ISO_XMIT ?
+					  XMIT_SHUTDOWN : RECV_SHUTDOWN, 0);
+		iso->flags &= ~HPSB_ISO_DRIVER_INIT;
+	}
+
+	dma_region_free(&iso->data_buf);
+	kfree(iso->infos);
+	kfree(iso);
+}
+
+static struct hpsb_iso* hpsb_iso_common_init(struct hpsb_host *host, enum hpsb_iso_type type,
+					     unsigned int data_buf_size,
+					     unsigned int buf_packets,
+					     int channel,
+					     int irq_interval,
+					     void (*callback)(struct hpsb_iso*))
+{
+	struct hpsb_iso *iso;
+	int dma_direction;
+
+	/* make sure driver supports the ISO API */
+	if(!host->driver->isoctl) {
+		printk(KERN_INFO "ieee1394: host driver '%s' does not support the rawiso API\n",
+		       host->driver->name);
+		return NULL;
+	}
+
+	/* sanitize parameters */
+
+	if(buf_packets < 2)
+		buf_packets = 2;
+
+	if(irq_interval < 1 || irq_interval > buf_packets / 2)
+		irq_interval = buf_packets / 2;
+
+	if(channel < -1 || channel >= 64)
+		return NULL;
+
+	/* channel = -1 is OK for multi-channel recv but not for xmit */
+	if(type == HPSB_ISO_XMIT && channel < 0)
+		return NULL;
+
+	/* allocate and write the struct hpsb_iso */
+
+	iso = kmalloc(sizeof(*iso), SLAB_KERNEL);
+	if(!iso)
+		return NULL;
+
+	/* allocate ringbuffer of packet descriptors */
+	iso->infos = kmalloc(buf_packets * sizeof(struct hpsb_iso_packet_info), SLAB_KERNEL);
+	if(!iso->infos)
+		return NULL;
+
+	iso->type = type;
+	iso->host = host;
+	iso->hostdata = NULL;
+	iso->callback = callback;
+	init_waitqueue_head(&iso->waitq);
+	iso->channel = channel;
+	iso->irq_interval = irq_interval;
+	dma_region_init(&iso->data_buf);
+	iso->buf_size = round_up_to_page(data_buf_size);
+	iso->buf_packets = buf_packets;
+	iso->pkt_dma = 0;
+	iso->first_packet = 0;
+	spin_lock_init(&iso->lock);
+
+	if(iso->type == HPSB_ISO_XMIT) {
+		iso->n_ready_packets = iso->buf_packets;
+		dma_direction = PCI_DMA_TODEVICE;
+	} else {
+		iso->n_ready_packets = 0;
+		dma_direction = PCI_DMA_FROMDEVICE;
+	}
+
+	atomic_set(&iso->overflows, 0);
+	iso->flags = 0;
+	iso->prebuffer = 0;
+
+	/* allocate the packet buffer */
+	if(dma_region_alloc(&iso->data_buf, iso->buf_size, host->pdev, dma_direction))
+		goto err;
+
+	return iso;
+
+err:
+	hpsb_iso_shutdown(iso);
+	return NULL;
+}
+
+int hpsb_iso_n_ready(struct hpsb_iso* iso)
+{
+	unsigned long flags;
+	int val;
+
+	spin_lock_irqsave(&iso->lock, flags);
+	val = iso->n_ready_packets;
+	spin_unlock_irqrestore(&iso->lock, flags);
+
+	return val;
+}
+
+
+struct hpsb_iso* hpsb_iso_xmit_init(struct hpsb_host *host,
+				    unsigned int data_buf_size,
+				    unsigned int buf_packets,
+				    int channel,
+				    int speed,
+				    int irq_interval,
+				    void (*callback)(struct hpsb_iso*))
+{
+	struct hpsb_iso *iso = hpsb_iso_common_init(host, HPSB_ISO_XMIT,
+						    data_buf_size, buf_packets,
+						    channel, irq_interval, callback);
+	if(!iso)
+		return NULL;
+
+	iso->speed = speed;
+
+	/* tell the driver to start working */
+	if(host->driver->isoctl(iso, XMIT_INIT, 0))
+		goto err;
+
+	iso->flags |= HPSB_ISO_DRIVER_INIT;
+	return iso;
+
+err:
+	hpsb_iso_shutdown(iso);
+	return NULL;
+}
+
+struct hpsb_iso* hpsb_iso_recv_init(struct hpsb_host *host,
+				    unsigned int data_buf_size,
+				    unsigned int buf_packets,
+				    int channel,
+				    int irq_interval,
+				    void (*callback)(struct hpsb_iso*))
+{
+	struct hpsb_iso *iso = hpsb_iso_common_init(host, HPSB_ISO_RECV,
+						    data_buf_size, buf_packets,
+						    channel, irq_interval, callback);
+	if(!iso)
+		return NULL;
+
+	/* tell the driver to start working */
+	if(host->driver->isoctl(iso, RECV_INIT, 0))
+		goto err;
+
+	iso->flags |= HPSB_ISO_DRIVER_INIT;
+	return iso;
+
+err:
+	hpsb_iso_shutdown(iso);
+	return NULL;
+}
+
+int hpsb_iso_recv_listen_channel(struct hpsb_iso *iso, unsigned char channel)
+{
+	if(iso->type != HPSB_ISO_RECV || iso->channel != -1 || channel >= 64)
+		return -EINVAL;
+	return iso->host->driver->isoctl(iso, RECV_LISTEN_CHANNEL, channel);
+}
+
+int hpsb_iso_recv_unlisten_channel(struct hpsb_iso *iso, unsigned char channel)
+{
+       if(iso->type != HPSB_ISO_RECV || iso->channel != -1 || channel >= 64)
+               return -EINVAL;
+       return iso->host->driver->isoctl(iso, RECV_UNLISTEN_CHANNEL, channel);
+}
+
+int hpsb_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask)
+{
+	if(iso->type != HPSB_ISO_RECV || iso->channel != -1)
+		return -EINVAL;
+	return iso->host->driver->isoctl(iso, RECV_SET_CHANNEL_MASK, (unsigned long) &mask);
+}
+
+static int do_iso_xmit_start(struct hpsb_iso *iso, int cycle)
+{
+	int retval = iso->host->driver->isoctl(iso, XMIT_START, cycle);
+	if(retval)
+		return retval;
+
+	iso->flags |= HPSB_ISO_DRIVER_STARTED;
+	return retval;
+}
+
+int hpsb_iso_xmit_start(struct hpsb_iso *iso, int cycle, int prebuffer)
+{
+	if(iso->type != HPSB_ISO_XMIT)
+		return -1;
+
+	if(iso->flags & HPSB_ISO_DRIVER_STARTED)
+		return 0;
+
+	if(cycle < -1)
+		cycle = -1;
+	else if(cycle >= 8000)
+		cycle %= 8000;
+
+	iso->xmit_cycle = cycle;
+
+	if(prebuffer < 0)
+		prebuffer = iso->buf_packets;
+	else if(prebuffer == 0)
+		prebuffer = 1;
+
+	if(prebuffer > iso->buf_packets)
+		prebuffer = iso->buf_packets;
+
+	iso->prebuffer = prebuffer;
+
+	/* remember the starting cycle; DMA will commence from xmit_queue_packets()
+	   once enough packets have been buffered */
+	iso->start_cycle = cycle;
+
+	return 0;
+}
+
+int hpsb_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync)
+{
+	int retval = 0;
+	int isoctl_args[3];
+
+	if(iso->type != HPSB_ISO_RECV)
+		return -1;
+
+	if(iso->flags & HPSB_ISO_DRIVER_STARTED)
+		return 0;
+
+	if(cycle < -1)
+		cycle = -1;
+	else if(cycle >= 8000)
+		cycle %= 8000;
+
+	isoctl_args[0] = cycle;
+	
+	if(tag_mask < 0)
+		/* match all tags */
+		tag_mask = 0xF;
+	isoctl_args[1] = tag_mask;
+
+	isoctl_args[2] = sync;
+
+	retval = iso->host->driver->isoctl(iso, RECV_START, (unsigned long) &isoctl_args[0]);
+	if(retval)
+		return retval;
+
+	iso->flags |= HPSB_ISO_DRIVER_STARTED;
+	return retval;
+}
+
+/* check to make sure the user has not supplied bogus values of offset/len
+   that would cause the kernel to access memory outside the buffer */
+
+static int hpsb_iso_check_offset_len(struct hpsb_iso *iso,
+				     unsigned int offset, unsigned short len,
+				     unsigned int *out_offset, unsigned short *out_len)
+{
+	if(offset >= iso->buf_size)
+		return -EFAULT;
+
+	/* make sure the packet does not go beyond the end of the buffer */
+	if(offset + len > iso->buf_size)
+		return -EFAULT;
+
+	/* check for wrap-around */
+	if(offset + len < offset)
+		return -EFAULT;
+
+	/* now we can trust 'offset' and 'length' */
+	*out_offset = offset;
+	*out_len = len;
+
+	return 0;
+}
+
+
+int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len, u8 tag, u8 sy)
+{
+	struct hpsb_iso_packet_info *info;
+	unsigned long flags;
+	int rv;
+
+	if(iso->type != HPSB_ISO_XMIT)
+		return -EINVAL;
+
+	/* is there space in the buffer? */
+	if(iso->n_ready_packets <= 0) {
+		return -EBUSY;
+	}
+
+	info = &iso->infos[iso->first_packet];
+
+	/* check for bogus offset/length */
+	if(hpsb_iso_check_offset_len(iso, offset, len, &info->offset, &info->len))
+		return -EFAULT;
+
+	info->tag = tag;
+	info->sy = sy;
+
+	spin_lock_irqsave(&iso->lock, flags);
+
+	rv = iso->host->driver->isoctl(iso, XMIT_QUEUE, (unsigned long) info);
+	if(rv)
+		goto out;
+
+	/* increment cursors */
+	iso->first_packet = (iso->first_packet+1) % iso->buf_packets;
+	iso->xmit_cycle = (iso->xmit_cycle+1) % 8000;
+	iso->n_ready_packets--;
+
+	if(iso->prebuffer != 0) {
+		iso->prebuffer--;
+		if(iso->prebuffer <= 0) {
+			iso->prebuffer = 0;
+			rv = do_iso_xmit_start(iso, iso->start_cycle);
+		}
+	}
+
+out:	
+	spin_unlock_irqrestore(&iso->lock, flags);
+	return rv;
+}
+
+int hpsb_iso_xmit_sync(struct hpsb_iso *iso)
+{
+	if(iso->type != HPSB_ISO_XMIT)
+		return -EINVAL;
+
+	return wait_event_interruptible(iso->waitq, hpsb_iso_n_ready(iso) == iso->buf_packets);
+}
+
+void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&iso->lock, flags);
+
+	/* predict the cycle of the next packet to be queued */
+
+	/* jump ahead by the number of packets that are already buffered */
+	cycle += iso->buf_packets - iso->n_ready_packets;
+	cycle %= 8000;
+
+	iso->xmit_cycle = cycle;
+	iso->n_ready_packets++;
+	iso->pkt_dma = (iso->pkt_dma + 1) % iso->buf_packets;
+
+	if(iso->n_ready_packets == iso->buf_packets || error != 0) {
+		/* the buffer has run empty! */
+		atomic_inc(&iso->overflows);
+	}
+
+	spin_unlock_irqrestore(&iso->lock, flags);
+}
+
+void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len,
+			      u16 cycle, u8 channel, u8 tag, u8 sy)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&iso->lock, flags);
+
+	if(iso->n_ready_packets == iso->buf_packets) {
+		/* overflow! */
+		atomic_inc(&iso->overflows);
+	} else {
+		struct hpsb_iso_packet_info *info = &iso->infos[iso->pkt_dma];
+		info->offset = offset;
+		info->len = len;
+		info->cycle = cycle;
+		info->channel = channel;
+		info->tag = tag;
+		info->sy = sy;
+
+		iso->pkt_dma = (iso->pkt_dma+1) % iso->buf_packets;
+		iso->n_ready_packets++;
+	}
+
+	spin_unlock_irqrestore(&iso->lock, flags);
+}
+
+int hpsb_iso_recv_release_packets(struct hpsb_iso *iso, unsigned int n_packets)
+{
+	unsigned long flags;
+	unsigned int i;
+	int rv = 0;
+
+	if(iso->type != HPSB_ISO_RECV)
+		return -1;
+
+	spin_lock_irqsave(&iso->lock, flags);
+	for(i = 0; i < n_packets; i++) {
+		rv = iso->host->driver->isoctl(iso, RECV_RELEASE,
+					       (unsigned long) &iso->infos[iso->first_packet]);
+		if(rv)
+			break;
+
+		iso->first_packet = (iso->first_packet+1) % iso->buf_packets;
+		iso->n_ready_packets--;
+	}
+	spin_unlock_irqrestore(&iso->lock, flags);
+	return rv;
+}
+
+void hpsb_iso_wake(struct hpsb_iso *iso)
+{
+	wake_up_interruptible(&iso->waitq);
+
+	if(iso->callback)
+		iso->callback(iso);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/iso.h linux-2.4.21-pre6/drivers/ieee1394/iso.h
--- linux-2.4.20/drivers/ieee1394/iso.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ieee1394/iso.h	2003-03-26 23:49:40.000000000 +0000
@@ -0,0 +1,184 @@
+/*
+ * IEEE 1394 for Linux
+ *
+ * kernel ISO transmission/reception
+ *
+ * Copyright (C) 2002 Maas Digital LLC
+ *
+ * This code is licensed under the GPL.  See the file COPYING in the root
+ * directory of the kernel sources for details.
+ */
+
+#ifndef IEEE1394_ISO_H
+#define IEEE1394_ISO_H
+
+#include "hosts.h"
+#include "dma.h"
+
+/* high-level ISO interface */
+
+/* This API sends and receives isochronous packets on a large,
+   virtually-contiguous kernel memory buffer. The buffer may be mapped
+   into a user-space process for zero-copy transmission and reception.
+
+   There are no explicit boundaries between packets in the buffer. A
+   packet may be transmitted or received at any location. However,
+   low-level drivers may impose certain restrictions on alignment or
+   size of packets. (e.g. in OHCI no packet may cross a page boundary,
+   and packets should be quadlet-aligned)
+*/
+
+/* Packet descriptor - the API maintains a ring buffer of these packet
+   descriptors in kernel memory (hpsb_iso.infos[]).  */
+
+struct hpsb_iso_packet_info {
+	/* offset of data payload relative to the first byte of the buffer */
+	__u32 offset;
+
+	/* length of the data payload, in bytes (not including the isochronous header) */
+	__u16 len;
+
+	/* (recv only) the cycle number (mod 8000) on which the packet was received */
+	__u16 cycle;
+
+	/* (recv only) channel on which the packet was received */
+	__u8 channel;
+
+	/* 2-bit 'tag' and 4-bit 'sy' fields of the isochronous header */
+	__u8 tag;
+	__u8 sy;
+};
+
+enum hpsb_iso_type { HPSB_ISO_RECV = 0, HPSB_ISO_XMIT = 1 };
+
+struct hpsb_iso {
+	enum hpsb_iso_type type;
+
+	/* pointer to low-level driver and its private data */
+	struct hpsb_host *host;
+	void *hostdata;
+
+	/* a function to be called (from interrupt context) after
+           outgoing packets have been sent, or incoming packets have
+           arrived */
+	void (*callback)(struct hpsb_iso*);
+
+	/* wait for buffer space */
+	wait_queue_head_t waitq;
+
+	int speed; /* SPEED_100, 200, or 400 */
+	int channel; /* -1 if multichannel */
+
+	/* greatest # of packets between interrupts - controls
+	   the maximum latency of the buffer */
+	int irq_interval;
+
+	/* the buffer for packet data payloads */
+	struct dma_region data_buf;
+
+	/* size of data_buf, in bytes (always a multiple of PAGE_SIZE) */
+	unsigned int buf_size;
+
+	/* ringbuffer of packet descriptors in regular kernel memory */
+	struct hpsb_iso_packet_info *infos;
+
+	/* # of packets in the ringbuffer */
+	unsigned int buf_packets;
+
+	/* protects packet cursors */
+	spinlock_t lock;
+
+	/* the index of the next packet that will be produced
+	   or consumed by the user */
+	int first_packet;
+
+	/* the index of the next packet that will be transmitted
+	   or received by the 1394 hardware */
+	int pkt_dma;
+
+	/* how many packets, starting at first_packet:
+	   (transmit) are ready to be filled with data
+	   (receive)  contain received data */
+	int n_ready_packets;
+
+	/* how many times the buffer has overflowed or underflowed */
+	atomic_t overflows;
+
+	/* private flags to track initialization progress */
+#define HPSB_ISO_DRIVER_INIT     (1<<0)
+#define HPSB_ISO_DRIVER_STARTED  (1<<1)
+	unsigned int flags;
+
+	/* # of packets left to prebuffer (xmit only) */
+	int prebuffer;
+
+	/* starting cycle for DMA (xmit only) */
+	int start_cycle;
+
+	/* cycle at which next packet will be transmitted,
+	   -1 if not known */
+	int xmit_cycle;
+};
+
+/* functions available to high-level drivers (e.g. raw1394) */
+
+/* allocate the buffer and DMA context */
+
+struct hpsb_iso* hpsb_iso_xmit_init(struct hpsb_host *host,
+				    unsigned int data_buf_size,
+				    unsigned int buf_packets,
+				    int channel,
+				    int speed,
+				    int irq_interval,
+				    void (*callback)(struct hpsb_iso*));
+
+/* note: if channel = -1, multi-channel receive is enabled */
+struct hpsb_iso* hpsb_iso_recv_init(struct hpsb_host *host,
+				    unsigned int data_buf_size,
+				    unsigned int buf_packets,
+				    int channel,
+				    int irq_interval,
+				    void (*callback)(struct hpsb_iso*));
+
+/* multi-channel only */
+int hpsb_iso_recv_listen_channel(struct hpsb_iso *iso, unsigned char channel);
+int hpsb_iso_recv_unlisten_channel(struct hpsb_iso *iso, unsigned char channel);
+int hpsb_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask);
+
+/* start/stop DMA */
+int hpsb_iso_xmit_start(struct hpsb_iso *iso, int start_on_cycle, int prebuffer);
+int hpsb_iso_recv_start(struct hpsb_iso *iso, int start_on_cycle, int tag_mask, int sync);
+void hpsb_iso_stop(struct hpsb_iso *iso);
+
+/* deallocate buffer and DMA context */
+void hpsb_iso_shutdown(struct hpsb_iso *iso);
+
+/* queue a packet for transmission. 'offset' is relative to the beginning of the
+   DMA buffer, where the packet's data payload should already have been placed */
+int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len, u8 tag, u8 sy);
+
+/* wait until all queued packets have been transmitted to the bus */
+int hpsb_iso_xmit_sync(struct hpsb_iso *iso);
+
+/* N packets have been read out of the buffer, re-use the buffer space */
+int  hpsb_iso_recv_release_packets(struct hpsb_iso *recv, unsigned int n_packets);
+
+/* returns # of packets ready to send or receive */
+int hpsb_iso_n_ready(struct hpsb_iso *iso);
+
+/* the following are callbacks available to low-level drivers */
+
+/* call after a packet has been transmitted to the bus (interrupt context is OK)
+   'cycle' is the _exact_ cycle the packet was sent on
+   'error' should be non-zero if some sort of error occurred when sending the packet
+*/
+void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error);
+
+/* call after a packet has been received (interrupt context OK) */
+void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len,
+			      u16 cycle, u8 channel, u8 tag, u8 sy);
+
+/* call to wake waiting processes after buffer space has opened up. */
+void hpsb_iso_wake(struct hpsb_iso *iso);
+
+#endif /* IEEE1394_ISO_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/ohci1394.c linux-2.4.21-pre6/drivers/ieee1394/ohci1394.c
--- linux-2.4.20/drivers/ieee1394/ohci1394.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ieee1394/ohci1394.c	2003-03-26 23:49:54.000000000 +0000
@@ -26,12 +26,10 @@
  * . Async Request Receive
  * . Async Response Transmit
  * . Iso Receive
+ * . Iso Transmit
  * . DMA mmap for iso receive
  * . Config ROM generation
  *
- * Things implemented, but still in test phase:
- * . Iso Transmit
- * 
  * Things not implemented:
  * . Async Stream Packets
  * . DMA error recovery
@@ -75,6 +73,9 @@
  *  . Updated to 2.4.x module scheme (PCI aswell)
  *  . Removed procfs support since it trashes random mem
  *  . Config ROM generation
+ *
+ * Dan Maas <dmaas@maasdigital.com>
+ *  . New isochronous API (rawiso)
  */
 
 #include <linux/config.h>
@@ -91,7 +92,6 @@
 #include <asm/byteorder.h>
 #include <asm/atomic.h>
 #include <asm/uaccess.h>
-#include <linux/tqueue.h>
 #include <linux/delay.h>
 #include <linux/spinlock.h>
 
@@ -113,6 +113,8 @@
 #include "ieee1394.h"
 #include "ieee1394_types.h"
 #include "hosts.h"
+#include "dma.h"
+#include "iso.h"
 #include "ieee1394_core.h"
 #include "highlevel.h"
 #include "ohci1394.h"
@@ -154,7 +156,7 @@
 printk(level "%s_%d: " fmt "\n" , OHCI1394_DRIVER_NAME, card , ## args)
 
 static char version[] __devinitdata =
-	"$Rev: 578 $ Ben Collins <bcollins@debian.org>";
+	"$Rev: 810 $ Ben Collins <bcollins@debian.org>";
 
 /* Module Parameters */
 MODULE_PARM(attempt_root,"i");
@@ -168,15 +170,18 @@
 static void dma_trm_tasklet(unsigned long data);
 static void dma_trm_reset(struct dma_trm_ctx *d);
 
+static int alloc_dma_rcv_ctx(struct ti_ohci *ohci, struct dma_rcv_ctx *d,
+			     enum context_type type, int ctx, int num_desc,
+			     int buf_size, int split_buf_size, int context_base);
+static void free_dma_rcv_ctx(struct dma_rcv_ctx *d);
+
+static int alloc_dma_trm_ctx(struct ti_ohci *ohci, struct dma_trm_ctx *d,
+			     enum context_type type, int ctx, int num_desc,
+			     int context_base);
+
 static void ohci1394_pci_remove(struct pci_dev *pdev);
 
 #ifndef __LITTLE_ENDIAN
-/* Swap a series of quads inplace. */
-static __inline__ void block_swab32(quadlet_t *data, size_t size) {
-	while (size--)
-		data[size] = swab32(data[size]);
-}
-
 static unsigned hdr_sizes[] = 
 {
 	3,	/* TCODE_WRITEQ */
@@ -194,16 +199,19 @@
 };
 
 /* Swap headers */
-static inline void packet_swab(quadlet_t *data, int tcode, int len)
+static inline void packet_swab(quadlet_t *data, int tcode)
 {
+	size_t size = hdr_sizes[tcode];
+
 	if (tcode > TCODE_LOCK_RESPONSE || hdr_sizes[tcode] == 0)
 		return;
-	block_swab32(data, hdr_sizes[tcode]);
+
+	while (size--)
+		data[size] = swab32(data[size]);
 }
 #else
 /* Don't waste cycles on same sex byte swaps */
-#define packet_swab(w,x,y)
-#define block_swab32(x,y)
+#define packet_swab(w,x)
 #endif /* !LITTLE_ENDIAN */
 
 /***********************************
@@ -312,7 +320,7 @@
 
 	/* SelfID Ok, reset error counter. */
 	ohci->self_id_errors = 0;
-	
+
 	size = ((self_id_count & 0x00001FFC) >> 2) - 1;
 	q++;
 
@@ -376,12 +384,12 @@
 		      "Running dma failed because Node ID == 63");
 		return -1;
 	}
-	
+
 	/* Run the dma context */
 	reg_write(ohci, reg, 0x8000);
-	
+
 	if (msg) PRINT(KERN_DEBUG, ohci->id, "%s", msg);
-	
+
 	return 0;
 }
 
@@ -395,11 +403,11 @@
 
 	for (i=0; i<d->num_desc; i++) {
 		u32 c;
-		
+
 		c = DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | DMA_CTL_BRANCH;
 		if (generate_irq)
 			c |= DMA_CTL_IRQ;
-				
+
 		d->prg_cpu[i]->control = cpu_to_le32(c | d->buf_size);
 
 		/* End of descriptor list? */
@@ -418,10 +426,28 @@
         d->buf_ind = 0;
         d->buf_offset = 0;
 
+	if(d->type == DMA_CTX_ISO) {
+		/* Clear contextControl */
+		reg_write(ohci, d->ctrlClear, 0xffffffff);
+
+		/* Set bufferFill, isochHeader, multichannel for IR context */
+		reg_write(ohci, d->ctrlSet, 0xd0000000);
+			
+		/* Set the context match register to match on all tags */
+		reg_write(ohci, d->ctxtMatch, 0xf0000000);
+
+		/* Clear the multi channel mask high and low registers */
+		reg_write(ohci, OHCI1394_IRMultiChanMaskHiClear, 0xffffffff);
+		reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear, 0xffffffff);
+
+		/* Set up isoRecvIntMask to generate interrupts */
+		reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 1 << d->ctx);
+	}
+
 	/* Tell the controller where the first AR program is */
 	reg_write(ohci, d->cmdPtr, d->prg_bus[0] | 0x1);
 
-	/* Run AR context */
+	/* Run context */
 	reg_write(ohci, d->ctrlSet, 0x00008000);
 
 	DBGMSG(ohci->id, "Receive DMA ctx=%d initialized", d->ctx);
@@ -442,6 +468,11 @@
 	INIT_LIST_HEAD(&d->fifo_list);
 	INIT_LIST_HEAD(&d->pending_list);
 
+	if(d->type == DMA_CTX_ISO) {
+		/* enable interrupts */
+		reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1 << d->ctx);
+	}
+
 	DBGMSG(ohci->id, "Transmit DMA ctx=%d initialized", d->ctx);
 }
 
@@ -453,7 +484,7 @@
 
 	reg_write(ohci, reg, 0xffffffff);
 	tmp = reg_read(ohci, reg);
-	
+
 	DBGMSG(ohci->id,"Iso contexts reg: %08x implemented: %08x", reg, tmp);
 
 	/* Count the number of contexts */
@@ -518,12 +549,6 @@
 	/* Don't accept phy packets into AR request context */ 
 	reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400);
 
-	/* Set bufferFill, isochHeader, multichannel for IR context */
-	reg_write(ohci, OHCI1394_IsoRcvContextControlSet, 0xd0000000);
-			
-	/* Set the context match register to match on all tags */
-	reg_write(ohci, OHCI1394_IsoRcvContextMatch, 0xf0000000);
-
 	/* Clear the interrupt mask */
 	reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff);
 	reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff);
@@ -532,10 +557,6 @@
 	reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff);
 	reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff);
 
-	/* Clear the multi channel mask high and low registers */
-	reg_write(ohci, OHCI1394_IRMultiChanMaskHiClear, 0xffffffff);
-	reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear, 0xffffffff);
-
 	/* Initialize AR dma */
 	initialize_dma_rcv_ctx(&ohci->ar_req_context, 0);
 	initialize_dma_rcv_ctx(&ohci->ar_resp_context, 0);
@@ -544,19 +565,6 @@
 	initialize_dma_trm_ctx(&ohci->at_req_context);
 	initialize_dma_trm_ctx(&ohci->at_resp_context);
 
-	/* Initialize IR dma */
-	initialize_dma_rcv_ctx(&ohci->ir_context, 1);
-
-        /* Initialize IT dma */
-        initialize_dma_trm_ctx(&ohci->it_context);
-
-	/* Set up isoRecvIntMask to generate interrupts for context 0
-	   (thanks to Michael Greger for seeing that I forgot this) */
-	reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 0x00000001);
-
-	/* Set up isoXmitIntMask to generate interrupts for context 0 */
-	reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 0x00000001);
-
 	/* 
 	 * Accept AT requests from all nodes. This probably 
 	 * will have to be controlled from the subsystem
@@ -574,7 +582,8 @@
 	reg_write(ohci, OHCI1394_HCControlClear, 0x40000000);
 
 	/* Enable interrupts */
-	reg_write(ohci, OHCI1394_IntMaskSet, 
+	reg_write(ohci, OHCI1394_IntMaskSet,
+		  OHCI1394_unrecoverableError |
 		  OHCI1394_masterIntEnable | 
 		  OHCI1394_busReset | 
 		  OHCI1394_selfIDComplete |
@@ -600,7 +609,7 @@
 }
 
 /* 
- * Insert a packet in the AT DMA fifo and generate the DMA prg
+ * Insert a packet in the DMA fifo and generate the DMA prg
  * FIXME: rewrite the program in order to accept packets crossing
  *        page boundaries.
  *        check also that a single dma descriptor doesn't cross a 
@@ -642,19 +651,31 @@
                 } else {
                         d->prg_cpu[idx]->data[0] = packet->speed_code<<16 |
                                 (packet->header[0] & 0xFFFF);
-                        d->prg_cpu[idx]->data[1] =
-                                (packet->header[1] & 0xFFFF) | 
-                                (packet->header[0] & 0xFFFF0000);
-                        d->prg_cpu[idx]->data[2] = packet->header[2];
-                        d->prg_cpu[idx]->data[3] = packet->header[3];
-			packet_swab(d->prg_cpu[idx]->data, packet->tcode,
-					packet->header_size>>2);
+
+			if (packet->tcode == TCODE_ISO_DATA) {
+				/* Sending an async stream packet */
+				d->prg_cpu[idx]->data[1] = packet->header[0] & 0xFFFF0000;
+			} else {
+				/* Sending a normal async request or response */
+				d->prg_cpu[idx]->data[1] =
+					(packet->header[1] & 0xFFFF) | 
+					(packet->header[0] & 0xFFFF0000);
+				d->prg_cpu[idx]->data[2] = packet->header[2];
+				d->prg_cpu[idx]->data[3] = packet->header[3];
+			}
+			packet_swab(d->prg_cpu[idx]->data, packet->tcode);
                 }
 
                 if (packet->data_size) { /* block transmit */
-                        d->prg_cpu[idx]->begin.control =
-                                cpu_to_le32(DMA_CTL_OUTPUT_MORE |
-					    DMA_CTL_IMMEDIATE | 0x10);
+			if (packet->tcode == TCODE_STREAM_DATA){
+				d->prg_cpu[idx]->begin.control =
+					cpu_to_le32(DMA_CTL_OUTPUT_MORE |
+						    DMA_CTL_IMMEDIATE | 0x8);
+			} else {
+				d->prg_cpu[idx]->begin.control =
+					cpu_to_le32(DMA_CTL_OUTPUT_MORE |
+						    DMA_CTL_IMMEDIATE | 0x10);
+			}
                         d->prg_cpu[idx]->end.control =
                                 cpu_to_le32(DMA_CTL_OUTPUT_LAST |
 					    DMA_CTL_IRQ | 
@@ -713,7 +734,7 @@
                 d->prg_cpu[idx]->data[0] = packet->speed_code<<16 |
                         (packet->header[0] & 0xFFFF);
                 d->prg_cpu[idx]->data[1] = packet->header[0] & 0xFFFF0000;
-		packet_swab(d->prg_cpu[idx]->data, packet->tcode, packet->header_size>>2);
+		packet_swab(d->prg_cpu[idx]->data, packet->tcode);
   
                 d->prg_cpu[idx]->begin.control = 
 			cpu_to_le32(DMA_CTL_OUTPUT_MORE | 
@@ -760,8 +781,8 @@
 }
 
 /*
- * This function fills the AT FIFO with the (eventual) pending packets
- * and runs or wakes up the AT DMA prg if necessary.
+ * This function fills the FIFO with the (eventual) pending packets
+ * and runs or wakes up the DMA prg if necessary.
  *
  * The function MUST be called with the d->lock held.
  */ 
@@ -777,7 +798,7 @@
 	idx = d->prg_ind;
 	z = (p->data_size) ? 3 : 2;
 
-	/* insert the packets into the at dma fifo */
+	/* insert the packets into the dma fifo */
 	while (d->free_prgs > 0 && !list_empty(&d->pending_list)) {
 		struct hpsb_packet *p = driver_packet(d->pending_list.next);
 		list_del(&p->driver_list);
@@ -799,13 +820,15 @@
 		/* Wake up the dma context if necessary */
 		if (!(reg_read(ohci, d->ctrlSet) & 0x400)) {
 			DBGMSG(ohci->id,"Waking transmit DMA ctx=%d",d->ctx);
-			reg_write(ohci, d->ctrlSet, 0x1000);
 		}
+
+		/* do this always, to avoid race condition */
+		reg_write(ohci, d->ctrlSet, 0x1000);
 	}
 	return 1;
 }
 
-/* Transmission of an async packet */
+/* Transmission of an async or iso packet */
 static int ohci_transmit(struct hpsb_host *host, struct hpsb_packet *packet)
 {
 	struct ti_ohci *ohci = host->hostdata;
@@ -819,12 +842,36 @@
 		return 0;
 	}
 
-	/* Decide wether we have an iso, a request, or a response packet */
+	/* Decide whether we have an iso, a request, or a response packet */
 	if (packet->type == hpsb_raw)
 		d = &ohci->at_req_context;
-	else if (packet->tcode == TCODE_ISO_DATA)
-		d = &ohci->it_context;
-	else if (packet->tcode & 0x02)
+	else if ((packet->tcode == TCODE_ISO_DATA) && (packet->type == hpsb_iso)) {
+		/* The legacy IT DMA context is initialized on first
+		 * use.  However, the alloc cannot be run from
+		 * interrupt context, so we bail out if that is the
+		 * case. I don't see anyone sending ISO packets from
+		 * interrupt context anyway... */
+		
+		if(ohci->it_legacy_context.ohci == NULL) {
+			if(in_interrupt()) {
+				PRINT(KERN_ERR, ohci->id, 
+				      "legacy IT context cannot be initialized during interrupt");
+				return 0;
+			}
+
+			if (alloc_dma_trm_ctx(ohci, &ohci->it_legacy_context,
+					      DMA_CTX_ISO, 0, IT_NUM_DESC,
+					      OHCI1394_IsoXmitContextBase) < 0) {
+				PRINT(KERN_ERR, ohci->id, 
+				      "error initializing legacy IT context");
+				return 0;
+			}
+
+			initialize_dma_trm_ctx(&ohci->it_legacy_context);
+		}
+		
+		d = &ohci->it_legacy_context;
+	} else if ((packet->tcode & 0x02) && (packet->tcode != TCODE_ISO_DATA))
 		d = &ohci->at_resp_context;
 	else 
 		d = &ohci->at_req_context;
@@ -832,7 +879,7 @@
 	spin_lock_irqsave(&d->lock,flags);
 
 	list_add_tail(&packet->driver_list, &d->pending_list);
-	
+
 	dma_trm_flush(ohci, d);
 
 	spin_unlock_irqrestore(&d->lock,flags);
@@ -856,11 +903,11 @@
 	case GET_CYCLE_COUNTER:
 		retval = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
 		break;
-	
+
 	case SET_CYCLE_COUNTER:
 		reg_write(ohci, OHCI1394_IsochronousCycleTimer, arg);
 		break;
-	
+
 	case SET_BUS_ID:
 		PRINT(KERN_ERR, ohci->id, "devctl command SET_BUS_ID err");
 		break;
@@ -920,8 +967,26 @@
 			spin_unlock_irqrestore(&ohci->IR_channel_lock, flags);
 			return -EFAULT;
 		}
-		
+
+		/* activate the legacy IR context */
+		if(ohci->ir_legacy_context.ohci == NULL) {
+			if(alloc_dma_rcv_ctx(ohci, &ohci->ir_legacy_context,
+					     DMA_CTX_ISO, 0, IR_NUM_DESC,
+					     IR_BUF_SIZE, IR_SPLIT_BUF_SIZE,
+					     OHCI1394_IsoRcvContextBase) < 0) {
+				PRINT(KERN_ERR, ohci->id,
+				      "%s: failed to allocate an IR context", 
+				      __FUNCTION__);
+				return -ENOMEM;
+			}
+			ohci->ir_legacy_channels = 0;
+			initialize_dma_rcv_ctx(&ohci->ir_legacy_context, 1);
+
+			DBGMSG(ohci->id, "ISO receive legacy context activated");
+		}
+
 		ohci->ISO_channel_usage |= mask;
+		ohci->ir_legacy_channels |= mask;
 
 		if (arg>31) 
 			reg_write(ohci, OHCI1394_IRMultiChanMaskHiSet, 
@@ -958,6 +1023,7 @@
 		}
 		
 		ohci->ISO_channel_usage &= ~mask;
+		ohci->ir_legacy_channels &= ~mask;
 
 		if (arg>31) 
 			reg_write(ohci, OHCI1394_IRMultiChanMaskHiClear, 
@@ -968,6 +1034,11 @@
 
                 spin_unlock_irqrestore(&ohci->IR_channel_lock, flags);
                 DBGMSG(ohci->id, "Listening disabled on channel %d", arg);
+
+		if(ohci->ir_legacy_channels == 0) {
+			free_dma_rcv_ctx(&ohci->ir_legacy_context);
+			DBGMSG(ohci->id, "ISO receive legacy context deactivated");
+		}
                 break;
         }
 	default:
@@ -978,6 +1049,1063 @@
 	return retval;
 }
 
+/***********************************
+ * rawiso ISO reception            *
+ ***********************************/
+
+/*
+  We use either buffer-fill or packet-per-buffer DMA mode. The DMA
+  buffer is split into "blocks" (regions described by one DMA
+  descriptor). Each block must be one page or less in size, and
+  must not cross a page boundary.
+
+  There is one little wrinkle with buffer-fill mode: a packet that
+  starts in the final block may wrap around into the first block. But
+  the user API expects all packets to be contiguous. Our solution is
+  to keep the very last page of the DMA buffer in reserve - if a
+  packet spans the gap, we copy its tail into this page.
+*/
+
+struct ohci_iso_recv {
+	struct ti_ohci *ohci;
+
+	struct ohci1394_iso_tasklet task;
+	int task_active;
+
+	enum { BUFFER_FILL_MODE,
+	       PACKET_PER_BUFFER_MODE } dma_mode;
+
+	/* memory and PCI mapping for the DMA descriptors */
+	struct dma_prog_region prog;
+	struct dma_cmd *block; /* = (struct dma_cmd*) prog.virt */
+
+	/* how many DMA blocks fit in the buffer */
+	unsigned int nblocks;
+
+	/* stride of DMA blocks */
+	unsigned int buf_stride;
+
+	/* number of blocks to batch between interrupts */
+	int block_irq_interval;
+
+	/* block that DMA will finish next */
+	int block_dma;
+
+	/* (buffer-fill only) block that the reader will release next */
+	int block_reader;
+
+	/* (buffer-fill only) bytes of buffer the reader has released,
+	   less than one block */
+	int released_bytes;
+
+	/* (buffer-fill only) buffer offset at which the next packet will appear */
+	int dma_offset;
+
+	/* OHCI DMA context control registers */
+	u32 ContextControlSet;
+	u32 ContextControlClear;
+	u32 CommandPtr;
+	u32 ContextMatch;
+};
+
+static void ohci_iso_recv_bufferfill_task(unsigned long data);
+static void ohci_iso_recv_packetperbuf_task(unsigned long data);
+static void ohci_iso_recv_stop(struct hpsb_iso *iso);
+static void ohci_iso_recv_shutdown(struct hpsb_iso *iso);
+static int  ohci_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync);
+static void ohci_iso_recv_program(struct hpsb_iso *iso);
+
+static int ohci_iso_recv_init(struct hpsb_iso *iso)
+{
+	struct ti_ohci *ohci = iso->host->hostdata;
+	struct ohci_iso_recv *recv;
+	int ctx;
+	int ret = -ENOMEM;
+
+	recv = kmalloc(sizeof(*recv), SLAB_KERNEL);
+	if(!recv)
+		return -ENOMEM;
+
+	iso->hostdata = recv;
+	recv->ohci = ohci;
+	recv->task_active = 0;
+	dma_prog_region_init(&recv->prog);
+	recv->block = NULL;
+
+	/* use buffer-fill mode, unless irq_interval is 1
+	   (note: multichannel requires buffer-fill) */
+
+	if(iso->irq_interval == 1 && iso->channel != -1) {
+		recv->dma_mode = PACKET_PER_BUFFER_MODE;
+	} else {
+		recv->dma_mode = BUFFER_FILL_MODE;
+	}
+
+	/* set nblocks, buf_stride, block_irq_interval */
+
+	if(recv->dma_mode == BUFFER_FILL_MODE) {
+		recv->buf_stride = PAGE_SIZE;
+
+		/* one block per page of data in the DMA buffer, minus the final guard page */
+		recv->nblocks = iso->buf_size/PAGE_SIZE - 1;
+		if(recv->nblocks < 3) {
+			DBGMSG(ohci->id, "ohci_iso_recv_init: DMA buffer too small");
+			goto err;
+		}
+
+		/* iso->irq_interval is in packets - translate that to blocks */
+		/* (err, sort of... 1 is always the safest value) */
+		recv->block_irq_interval = iso->irq_interval / recv->nblocks;
+		if(recv->block_irq_interval < 1)
+			recv->block_irq_interval = 1;
+		else if(recv->block_irq_interval*4 > recv->nblocks)
+			recv->block_irq_interval = recv->nblocks/4;
+	} else {
+		int max_packet_size;
+
+		recv->nblocks = iso->buf_packets;
+		recv->block_irq_interval = 1;
+
+		/* choose a buffer stride */
+		/* must be a power of 2, and <= PAGE_SIZE */
+
+		max_packet_size = iso->buf_size / iso->buf_packets;
+
+		for(recv->buf_stride = 8; recv->buf_stride < max_packet_size;
+		    recv->buf_stride *= 2);
+	
+		if(recv->buf_stride*iso->buf_packets > iso->buf_size ||
+		   recv->buf_stride > PAGE_SIZE) {
+			/* this shouldn't happen, but anyway... */
+			DBGMSG(ohci->id, "ohci_iso_recv_init: problem choosing a buffer stride");
+			goto err;
+		}
+	}
+
+	recv->block_reader = 0;
+	recv->released_bytes = 0;
+	recv->block_dma = 0;
+	recv->dma_offset = 0;
+
+	/* size of DMA program = one descriptor per block */
+	if (dma_prog_region_alloc(&recv->prog,
+				 sizeof(struct dma_cmd) * recv->nblocks,
+				 recv->ohci->dev))
+		goto err;
+
+	recv->block = (struct dma_cmd*) recv->prog.kvirt;
+
+	ohci1394_init_iso_tasklet(&recv->task,
+				  iso->channel == -1 ? OHCI_ISO_MULTICHANNEL_RECEIVE :
+				                       OHCI_ISO_RECEIVE,
+				  recv->dma_mode == BUFFER_FILL_MODE ?
+				  ohci_iso_recv_bufferfill_task :
+				  ohci_iso_recv_packetperbuf_task,
+				  (unsigned long) iso);
+
+	if(ohci1394_register_iso_tasklet(recv->ohci, &recv->task) < 0)
+		goto err;
+
+	recv->task_active = 1;
+
+	/* recv context registers are spaced 32 bytes apart */
+	ctx = recv->task.context;
+	recv->ContextControlSet = OHCI1394_IsoRcvContextControlSet + 32 * ctx;
+	recv->ContextControlClear = OHCI1394_IsoRcvContextControlClear + 32 * ctx;
+	recv->CommandPtr = OHCI1394_IsoRcvCommandPtr + 32 * ctx;
+	recv->ContextMatch = OHCI1394_IsoRcvContextMatch + 32 * ctx;
+
+	if(iso->channel == -1) {
+		/* clear multi-channel selection mask */
+		reg_write(recv->ohci, OHCI1394_IRMultiChanMaskHiClear, 0xFFFFFFFF);
+		reg_write(recv->ohci, OHCI1394_IRMultiChanMaskLoClear, 0xFFFFFFFF);
+	}
+		
+	/* write the DMA program */
+	ohci_iso_recv_program(iso);
+
+	DBGMSG(ohci->id, "ohci_iso_recv_init: %s mode, DMA buffer is %lu pages"
+	       " (%u bytes), using %u blocks, buf_stride %u, block_irq_interval %d",
+	       recv->dma_mode == BUFFER_FILL_MODE ?
+	       "buffer-fill" : "packet-per-buffer",
+	       iso->buf_size/PAGE_SIZE, iso->buf_size, 
+	       recv->nblocks, recv->buf_stride, recv->block_irq_interval);
+
+	return 0;
+
+err:
+	ohci_iso_recv_shutdown(iso);
+	return ret;
+}
+
+static void ohci_iso_recv_stop(struct hpsb_iso *iso)
+{
+	struct ohci_iso_recv *recv = iso->hostdata;
+
+	/* disable interrupts */
+	reg_write(recv->ohci, OHCI1394_IsoRecvIntMaskClear, 1 << recv->task.context);
+		
+	/* halt DMA */
+	ohci1394_stop_context(recv->ohci, recv->ContextControlClear, NULL);
+}
+
+static void ohci_iso_recv_shutdown(struct hpsb_iso *iso)
+{
+	struct ohci_iso_recv *recv = iso->hostdata;
+
+	if(recv->task_active) {
+		ohci_iso_recv_stop(iso);
+		ohci1394_unregister_iso_tasklet(recv->ohci, &recv->task);
+		recv->task_active = 0;
+	}
+
+	dma_prog_region_free(&recv->prog);
+	kfree(recv);
+	iso->hostdata = NULL;
+}
+
+/* set up a "gapped" ring buffer DMA program */
+static void ohci_iso_recv_program(struct hpsb_iso *iso)
+{
+	struct ohci_iso_recv *recv = iso->hostdata;
+	int blk;
+
+	/* address of 'branch' field in previous DMA descriptor */
+	u32 *prev_branch = NULL;
+
+	for (blk = 0; blk < recv->nblocks; blk++) {
+		u32 control;
+
+		/* the DMA descriptor */
+		struct dma_cmd *cmd = &recv->block[blk];
+
+		/* offset of the DMA descriptor relative to the DMA prog buffer */
+		unsigned long prog_offset = blk * sizeof(struct dma_cmd);
+
+		/* offset of this packet's data within the DMA buffer */
+		unsigned long buf_offset = blk * recv->buf_stride;
+
+		if (recv->dma_mode == BUFFER_FILL_MODE) {
+			control = 2 << 28; /* INPUT_MORE */
+		} else {
+			control = 3 << 28; /* INPUT_LAST */
+		}
+
+		control |= 8 << 24; /* s = 1, update xferStatus and resCount */
+
+		/* interrupt on last block, and at intervals */
+		if (blk == recv->nblocks-1 || (blk % recv->block_irq_interval) == 0) {
+			control |= 3 << 20; /* want interrupt */
+		}
+
+		control |= 3 << 18; /* enable branch to address */
+		control |= recv->buf_stride;
+
+		cmd->control = cpu_to_le32(control);
+		cmd->address = cpu_to_le32(dma_region_offset_to_bus(&iso->data_buf, buf_offset));
+		cmd->branchAddress = 0; /* filled in on next loop */
+		cmd->status = cpu_to_le32(recv->buf_stride);
+
+		/* link the previous descriptor to this one */
+		if (prev_branch) {
+			*prev_branch = cpu_to_le32(dma_prog_region_offset_to_bus(&recv->prog, prog_offset) | 1);
+		}
+
+		prev_branch = &cmd->branchAddress;
+	}
+
+	/* the final descriptor's branch address and Z should be left at 0 */
+}
+
+/* listen or unlisten to a specific channel (multi-channel mode only) */
+static void ohci_iso_recv_change_channel(struct hpsb_iso *iso, unsigned char channel, int listen)
+{
+	struct ohci_iso_recv *recv = iso->hostdata;
+	int reg, i;
+
+	if(channel < 32) {
+		reg = listen ? OHCI1394_IRMultiChanMaskLoSet : OHCI1394_IRMultiChanMaskLoClear;
+		i = channel;
+	} else {
+		reg = listen ? OHCI1394_IRMultiChanMaskHiSet : OHCI1394_IRMultiChanMaskHiClear;
+		i = channel - 32;
+	}
+
+	reg_write(recv->ohci, reg, (1 << i));
+
+	/* issue a dummy read to force all PCI writes to be posted immediately */
+	mb();
+	reg_read(recv->ohci, OHCI1394_IsochronousCycleTimer);
+}
+
+static void ohci_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask)
+{
+	struct ohci_iso_recv *recv = iso->hostdata;
+	int i;
+
+	for(i = 0; i < 64; i++) {
+		if(mask & (1ULL << i)) {
+			if(i < 32)
+				reg_write(recv->ohci, OHCI1394_IRMultiChanMaskLoSet, (1 << i));
+			else
+				reg_write(recv->ohci, OHCI1394_IRMultiChanMaskHiSet, (1 << (i-32)));
+		} else {
+			if(i < 32)
+				reg_write(recv->ohci, OHCI1394_IRMultiChanMaskLoClear, (1 << i));
+			else
+				reg_write(recv->ohci, OHCI1394_IRMultiChanMaskHiClear, (1 << (i-32)));
+		}
+	}
+
+	/* issue a dummy read to force all PCI writes to be posted immediately */
+	mb();
+	reg_read(recv->ohci, OHCI1394_IsochronousCycleTimer);
+}
+
+static int ohci_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync)
+{
+	struct ohci_iso_recv *recv = iso->hostdata;
+	u32 command, contextMatch;
+
+	reg_write(recv->ohci, recv->ContextControlClear, 0xFFFFFFFF);
+	wmb();
+
+	/* always keep ISO headers */
+	command = (1 << 30);
+
+	if(recv->dma_mode == BUFFER_FILL_MODE)
+		command |= (1 << 31);
+
+	reg_write(recv->ohci, recv->ContextControlSet, command);
+
+	/* match on specified tags */
+	contextMatch = tag_mask << 28;
+
+	if(iso->channel == -1) {
+		/* enable multichannel reception */
+		reg_write(recv->ohci, recv->ContextControlSet, (1 << 28));
+	} else {
+		/* listen on channel */
+		contextMatch |= iso->channel;
+	}
+
+	if(cycle != -1) {
+		u32 seconds;
+		
+		/* enable cycleMatch */
+		reg_write(recv->ohci, recv->ContextControlSet, (1 << 29));
+
+		/* set starting cycle */
+		cycle &= 0x1FFF;
+		
+		/* 'cycle' is only mod 8000, but we also need two 'seconds' bits -
+		   just snarf them from the current time */
+		seconds = reg_read(recv->ohci, OHCI1394_IsochronousCycleTimer) >> 25;
+
+		/* advance one second to give some extra time for DMA to start */
+		seconds += 1;
+		
+		cycle |= (seconds & 3) << 13;
+
+		contextMatch |= cycle << 12;
+	}
+
+	if(sync != -1) {
+		/* set sync flag on first DMA descriptor */
+		struct dma_cmd *cmd = &recv->block[recv->block_dma];
+		cmd->control |= DMA_CTL_WAIT;
+
+		/* match sync field */
+		contextMatch |= (sync&0xf)<<8;
+	}
+
+	reg_write(recv->ohci, recv->ContextMatch, contextMatch);
+
+	/* address of first descriptor block */
+	command = dma_prog_region_offset_to_bus(&recv->prog,
+						recv->block_dma * sizeof(struct dma_cmd));
+	command |= 1; /* Z=1 */
+
+	reg_write(recv->ohci, recv->CommandPtr, command);
+
+	/* enable interrupts */
+	reg_write(recv->ohci, OHCI1394_IsoRecvIntMaskSet, 1 << recv->task.context);
+
+	wmb();
+
+	/* run */
+	reg_write(recv->ohci, recv->ContextControlSet, 0x8000);
+
+	/* issue a dummy read of the cycle timer register to force
+	   all PCI writes to be posted immediately */
+	mb();
+	reg_read(recv->ohci, OHCI1394_IsochronousCycleTimer);
+
+	/* check RUN */
+	if(!(reg_read(recv->ohci, recv->ContextControlSet) & 0x8000)) {
+		PRINT(KERN_ERR, recv->ohci->id,
+		      "Error starting IR DMA (ContextControl 0x%08x)\n",
+		      reg_read(recv->ohci, recv->ContextControlSet));
+		return -1;
+	}
+
+	return 0;
+}
+
+static void ohci_iso_recv_release_block(struct ohci_iso_recv *recv, int block)
+{
+	/* re-use the DMA descriptor for the block */
+	/* by linking the previous descriptor to it */
+
+	int next_i = block;
+	int prev_i = (next_i == 0) ? (recv->nblocks - 1) : (next_i - 1);
+
+	struct dma_cmd *next = &recv->block[next_i];
+	struct dma_cmd *prev = &recv->block[prev_i];
+
+	/* 'next' becomes the new end of the DMA chain,
+	   so disable branch and enable interrupt */
+	next->branchAddress = 0;
+	next->control |= cpu_to_le32(3 << 20);
+
+	/* link prev to next */	
+	prev->branchAddress = cpu_to_le32(dma_prog_region_offset_to_bus(&recv->prog,
+									sizeof(struct dma_cmd) * next_i)
+					  | 1); /* Z=1 */
+
+	/* disable interrupt on previous DMA descriptor, except at intervals */
+	if((prev_i % recv->block_irq_interval) == 0) {
+		prev->control |= cpu_to_le32(3 << 20); /* enable interrupt */
+	} else {
+		prev->control &= cpu_to_le32(~(3<<20)); /* disable interrupt */
+	}
+	wmb();
+
+	/* wake up DMA in case it fell asleep */
+	reg_write(recv->ohci, recv->ContextControlSet, (1 << 12));
+}
+
+static void ohci_iso_recv_bufferfill_release(struct ohci_iso_recv *recv,
+					     struct hpsb_iso_packet_info *info)
+{
+	int len;
+
+	/* release the memory where the packet was */
+	len = info->len;
+
+	/* add the wasted space for padding to 4 bytes */
+	if(len % 4)
+		len += 4 - (len % 4);
+
+	/* add 8 bytes for the OHCI DMA data format overhead */
+	len += 8;
+
+	recv->released_bytes += len;
+
+	/* have we released enough memory for one block? */
+	while(recv->released_bytes > recv->buf_stride) {
+		ohci_iso_recv_release_block(recv, recv->block_reader);
+		recv->block_reader = (recv->block_reader + 1) % recv->nblocks;
+		recv->released_bytes -= recv->buf_stride;
+	}
+}
+
+static inline void ohci_iso_recv_release(struct hpsb_iso *iso, struct hpsb_iso_packet_info *info)
+{
+	struct ohci_iso_recv *recv = iso->hostdata;
+	if(recv->dma_mode == BUFFER_FILL_MODE) {
+		ohci_iso_recv_bufferfill_release(recv, info);
+	} else {
+		ohci_iso_recv_release_block(recv, info - iso->infos);
+	}
+}
+
+/* parse all packets from blocks that have been fully received */
+static void ohci_iso_recv_bufferfill_parse(struct hpsb_iso *iso, struct ohci_iso_recv *recv)
+{
+	int wake = 0;
+	int runaway = 0;
+		
+	while(1) {
+		/* we expect the next parsable packet to begin at recv->dma_offset */
+		/* note: packet layout is as shown in section 10.6.1.1 of the OHCI spec */
+		
+		unsigned int offset;
+		unsigned short len, cycle;
+		unsigned char channel, tag, sy;
+		
+		unsigned char *p = iso->data_buf.kvirt;
+
+		unsigned int this_block = recv->dma_offset/recv->buf_stride;
+
+		/* don't loop indefinitely */
+		if(runaway++ > 100000) {
+			atomic_inc(&iso->overflows);
+			PRINT(KERN_ERR, recv->ohci->id,
+			      "IR DMA error - Runaway during buffer parsing!\n");
+			break;
+		}
+
+		/* stop parsing once we arrive at block_dma (i.e. don't get ahead of DMA) */
+		if(this_block == recv->block_dma)
+			break;
+
+		wake = 1;
+		
+		/* parse data length, tag, channel, and sy */
+		
+		/* note: we keep our own local copies of 'len' and 'offset'
+		   so the user can't mess with them by poking in the mmap area */
+		
+		len = p[recv->dma_offset+2] | (p[recv->dma_offset+3] << 8);
+
+		if(len > 4096) {
+			PRINT(KERN_ERR, recv->ohci->id,
+			      "IR DMA error - bogus 'len' value %u\n", len);
+		}
+		
+		channel = p[recv->dma_offset+1] & 0x3F;
+		tag = p[recv->dma_offset+1] >> 6;
+		sy = p[recv->dma_offset+0] & 0xF;
+
+		/* advance to data payload */
+		recv->dma_offset += 4;
+		
+		/* check for wrap-around */
+		if(recv->dma_offset >= recv->buf_stride*recv->nblocks) {
+			recv->dma_offset -= recv->buf_stride*recv->nblocks;
+		}
+
+		/* dma_offset now points to the first byte of the data payload */
+		offset = recv->dma_offset;
+
+		/* advance to xferStatus/timeStamp */
+		recv->dma_offset += len;
+
+		/* payload is padded to 4 bytes */
+		if(len % 4) { 
+			recv->dma_offset += 4 - (len%4);
+		}
+
+		/* check for wrap-around */
+		if(recv->dma_offset >= recv->buf_stride*recv->nblocks) {
+			/* uh oh, the packet data wraps from the last
+                           to the first DMA block - make the packet
+                           contiguous by copying its "tail" into the
+                           guard page */
+
+			int guard_off = recv->buf_stride*recv->nblocks;
+			int tail_len = len - (guard_off - offset);
+
+			if(tail_len > 0  && tail_len < recv->buf_stride) {
+				memcpy(iso->data_buf.kvirt + guard_off,
+				       iso->data_buf.kvirt,
+				       tail_len);
+			}
+
+			recv->dma_offset -= recv->buf_stride*recv->nblocks;
+		}
+
+		/* parse timestamp */
+		cycle = p[recv->dma_offset+0] | (p[recv->dma_offset+1]<<8);
+		cycle &= 0x1FFF;
+
+		/* advance to next packet */
+		recv->dma_offset += 4;
+
+		/* check for wrap-around */
+		if(recv->dma_offset >= recv->buf_stride*recv->nblocks) {
+			recv->dma_offset -= recv->buf_stride*recv->nblocks;
+		}
+
+		hpsb_iso_packet_received(iso, offset, len, cycle, channel, tag, sy);
+	}
+
+	if(wake)
+		hpsb_iso_wake(iso);
+}
+
+static void ohci_iso_recv_bufferfill_task(unsigned long data)
+{
+	struct hpsb_iso *iso = (struct hpsb_iso*) data;
+	struct ohci_iso_recv *recv = iso->hostdata;
+
+	int loop;
+
+	/* loop over all blocks */
+	for(loop = 0; loop < recv->nblocks; loop++) {
+		
+		/* check block_dma to see if it's done */
+		
+		struct dma_cmd *im = &recv->block[recv->block_dma];
+		
+		/* check the DMA descriptor for new writes to xferStatus */
+		u16 xferstatus = im->status >> 16;
+		
+		/* rescount is the number of bytes *remaining to be written* in the block */
+		u16 rescount = im->status & 0xFFFF;
+
+		unsigned char event = xferstatus & 0x1F;
+
+		if(!event) {
+			/* nothing has happened to this block yet */
+			break;
+		}
+
+		if(event != 0x11) {
+			atomic_inc(&iso->overflows);
+			PRINT(KERN_ERR, recv->ohci->id,
+			      "IR DMA error - OHCI error code 0x%02x\n", event);
+		}
+
+		if(rescount != 0) {
+			/* the card is still writing to this block;
+			   we can't touch it until it's done */
+			break;
+		}
+		
+		/* OK, the block is finished... */
+		
+		/* sync our view of the block */
+		dma_region_sync(&iso->data_buf, recv->block_dma*recv->buf_stride, recv->buf_stride);
+		
+		/* reset the DMA descriptor */
+		im->status = recv->buf_stride;
+
+		/* advance block_dma */
+		recv->block_dma = (recv->block_dma + 1) % recv->nblocks;
+
+		if((recv->block_dma+1) % recv->nblocks == recv->block_reader) {
+			atomic_inc(&iso->overflows);
+			DBGMSG(recv->ohci->id, "ISO reception overflow - "
+			       "ran out of DMA blocks");
+		}
+	}
+
+	/* parse any packets that have arrived */
+	ohci_iso_recv_bufferfill_parse(iso, recv);
+}
+
+static void ohci_iso_recv_packetperbuf_task(unsigned long data)
+{
+	struct hpsb_iso *iso = (struct hpsb_iso*) data;
+	struct ohci_iso_recv *recv = iso->hostdata;
+	int count;
+	int wake = 0;
+	
+	/* loop over the entire buffer */
+	for(count = 0; count < recv->nblocks; count++) {
+		u32 packet_len = 0;
+		
+		/* pointer to the DMA descriptor */
+		struct dma_cmd *il = ((struct dma_cmd*) recv->prog.kvirt) + iso->pkt_dma;
+
+		/* check the DMA descriptor for new writes to xferStatus */
+		u16 xferstatus = le32_to_cpu(il->status) >> 16;
+		u16 rescount = le32_to_cpu(il->status) & 0xFFFF;
+
+		unsigned char event = xferstatus & 0x1F;
+
+		if(!event) {
+			/* this packet hasn't come in yet; we are done for now */
+			goto out;
+		}
+		
+		if(event == 0x11) {
+			/* packet received successfully! */
+			
+			/* rescount is the number of bytes *remaining* in the packet buffer,
+			   after the packet was written */
+			packet_len = recv->buf_stride - rescount;
+
+		} else if(event == 0x02) {
+			PRINT(KERN_ERR, recv->ohci->id, "IR DMA error - packet too long for buffer\n");
+		} else if(event) {
+			PRINT(KERN_ERR, recv->ohci->id, "IR DMA error - OHCI error code 0x%02x\n", event);
+		}
+
+		/* sync our view of the buffer */
+		dma_region_sync(&iso->data_buf, iso->pkt_dma * recv->buf_stride, recv->buf_stride);
+			
+		/* record the per-packet info */
+		{
+			/* iso header is 8 bytes ahead of the data payload */
+			unsigned char *hdr;
+
+			unsigned int offset;
+			unsigned short cycle;
+			unsigned char channel, tag, sy;
+
+			offset = iso->pkt_dma * recv->buf_stride;
+			hdr = iso->data_buf.kvirt + offset;
+
+			/* skip iso header */
+			offset += 8;
+			packet_len -= 8;
+			
+			cycle = (hdr[0] | (hdr[1] << 8)) & 0x1FFF;
+			channel = hdr[5] & 0x3F;
+			tag = hdr[5] >> 6;
+			sy = hdr[4] & 0xF;
+
+			hpsb_iso_packet_received(iso, offset, packet_len, cycle, channel, tag, sy);
+		}
+		
+		/* reset the DMA descriptor */
+		il->status = recv->buf_stride;
+
+		wake = 1;
+		recv->block_dma = iso->pkt_dma;
+	}
+
+out:
+	if(wake)
+		hpsb_iso_wake(iso);
+}
+
+
+/***********************************
+ * rawiso ISO transmission         *
+ ***********************************/
+
+struct ohci_iso_xmit {
+	struct ti_ohci *ohci;
+	struct dma_prog_region prog;
+	struct ohci1394_iso_tasklet task;
+	int task_active;
+
+	u32 ContextControlSet;
+	u32 ContextControlClear;
+	u32 CommandPtr;
+};
+
+/* transmission DMA program:
+   one OUTPUT_MORE_IMMEDIATE for the IT header
+   one OUTPUT_LAST for the buffer data */
+
+struct iso_xmit_cmd {
+	struct dma_cmd output_more_immediate;
+	u8 iso_hdr[8];
+	u32 unused[2];
+	struct dma_cmd output_last;
+};
+
+static int ohci_iso_xmit_init(struct hpsb_iso *iso);
+static int ohci_iso_xmit_start(struct hpsb_iso *iso, int cycle);
+static void ohci_iso_xmit_shutdown(struct hpsb_iso *iso);
+static void ohci_iso_xmit_task(unsigned long data);
+
+static int ohci_iso_xmit_init(struct hpsb_iso *iso)
+{
+	struct ohci_iso_xmit *xmit;
+	unsigned int prog_size;
+	int ctx;
+	int ret = -ENOMEM;
+
+	xmit = kmalloc(sizeof(*xmit), SLAB_KERNEL);
+	if(!xmit)
+		return -ENOMEM;
+
+	iso->hostdata = xmit;
+	xmit->ohci = iso->host->hostdata;
+	xmit->task_active = 0;
+
+	dma_prog_region_init(&xmit->prog);
+
+	prog_size = sizeof(struct iso_xmit_cmd) * iso->buf_packets;
+
+	if(dma_prog_region_alloc(&xmit->prog, prog_size, xmit->ohci->dev))
+		goto err;
+
+	ohci1394_init_iso_tasklet(&xmit->task, OHCI_ISO_TRANSMIT,
+				  ohci_iso_xmit_task, (unsigned long) iso);
+
+	if(ohci1394_register_iso_tasklet(xmit->ohci, &xmit->task) < 0)
+		goto err;
+
+	xmit->task_active = 1;
+
+	/* xmit context registers are spaced 16 bytes apart */
+	ctx = xmit->task.context;
+	xmit->ContextControlSet = OHCI1394_IsoXmitContextControlSet + 16 * ctx;
+	xmit->ContextControlClear = OHCI1394_IsoXmitContextControlClear + 16 * ctx;
+	xmit->CommandPtr = OHCI1394_IsoXmitCommandPtr + 16 * ctx;
+
+	return 0;
+
+err:
+	ohci_iso_xmit_shutdown(iso);
+	return ret;
+}
+
+static void ohci_iso_xmit_stop(struct hpsb_iso *iso)
+{
+	struct ohci_iso_xmit *xmit = iso->hostdata;
+
+	/* disable interrupts */
+	reg_write(xmit->ohci, OHCI1394_IsoXmitIntMaskClear, 1 << xmit->task.context);
+
+	/* halt DMA */
+	if(ohci1394_stop_context(xmit->ohci, xmit->ContextControlClear, NULL)) {
+		/* XXX the DMA context will lock up if you try to send too much data! */
+		PRINT(KERN_ERR, xmit->ohci->id,
+		      "you probably exceeded the OHCI card's bandwidth limit - "
+		      "reload the module and reduce xmit bandwidth");
+	}
+}
+
+static void ohci_iso_xmit_shutdown(struct hpsb_iso *iso)
+{
+	struct ohci_iso_xmit *xmit = iso->hostdata;
+
+	if(xmit->task_active) {
+		ohci_iso_xmit_stop(iso);
+		ohci1394_unregister_iso_tasklet(xmit->ohci, &xmit->task);
+		xmit->task_active = 0;
+	}
+
+	dma_prog_region_free(&xmit->prog);
+	kfree(xmit);
+	iso->hostdata = NULL;
+}
+
+static void ohci_iso_xmit_task(unsigned long data)
+{
+	struct hpsb_iso *iso = (struct hpsb_iso*) data;
+	struct ohci_iso_xmit *xmit = iso->hostdata;
+	int wake = 0;
+	int count;
+
+	/* check the whole buffer if necessary, starting at pkt_dma */
+	for(count = 0; count < iso->buf_packets; count++) {
+		int cycle;
+
+		/* DMA descriptor */
+		struct iso_xmit_cmd *cmd = dma_region_i(&xmit->prog, struct iso_xmit_cmd, iso->pkt_dma);
+		
+		/* check for new writes to xferStatus */
+		u16 xferstatus = le32_to_cpu(cmd->output_last.status) >> 16;
+		u8  event = xferstatus & 0x1F;
+
+		if(!event) {
+			/* packet hasn't been sent yet; we are done for now */
+			break;
+		}
+
+		if(event != 0x11)
+			PRINT(KERN_ERR, xmit->ohci->id,
+			      "IT DMA error - OHCI error code 0x%02x\n", event);
+		
+		/* at least one packet went out, so wake up the writer */
+		wake = 1;
+		
+		/* parse cycle */
+		cycle = le32_to_cpu(cmd->output_last.status) & 0x1FFF;
+
+		/* tell the subsystem the packet has gone out */
+		hpsb_iso_packet_sent(iso, cycle, event != 0x11);
+		
+		/* reset the DMA descriptor for next time */
+		cmd->output_last.status = 0;
+	}
+
+	if(wake)
+		hpsb_iso_wake(iso);
+}
+
+static int ohci_iso_xmit_queue(struct hpsb_iso *iso, struct hpsb_iso_packet_info *info)
+{
+	struct ohci_iso_xmit *xmit = iso->hostdata;
+
+	int next_i, prev_i;
+	struct iso_xmit_cmd *next, *prev;
+
+	unsigned int offset;
+	unsigned short len;
+	unsigned char tag, sy;
+
+	/* check that the packet doesn't cross a page boundary
+	   (we could allow this if we added OUTPUT_MORE descriptor support) */
+	if(cross_bound(info->offset, info->len)) {
+		PRINT(KERN_ERR, xmit->ohci->id,
+		      "rawiso xmit: packet %u crosses a page boundary",
+		      iso->first_packet);
+		return -EINVAL;
+	}
+
+	offset = info->offset;
+	len = info->len;
+	tag = info->tag;
+	sy = info->sy;
+
+	/* sync up the card's view of the buffer */
+	dma_region_sync(&iso->data_buf, offset, len);
+
+	/* append first_packet to the DMA chain */
+	/* by linking the previous descriptor to it */
+	/* (next will become the new end of the DMA chain) */
+
+	next_i = iso->first_packet;
+	prev_i = (next_i == 0) ? (iso->buf_packets - 1) : (next_i - 1);
+
+	next = dma_region_i(&xmit->prog, struct iso_xmit_cmd, next_i);
+	prev = dma_region_i(&xmit->prog, struct iso_xmit_cmd, prev_i);
+
+	/* set up the OUTPUT_MORE_IMMEDIATE descriptor */
+	memset(next, 0, sizeof(struct iso_xmit_cmd));
+	next->output_more_immediate.control = cpu_to_le32(0x02000008);
+
+	/* ISO packet header is embedded in the OUTPUT_MORE_IMMEDIATE */
+
+	/* tcode = 0xA, and sy */
+	next->iso_hdr[0] = 0xA0 | (sy & 0xF);
+
+	/* tag and channel number */
+	next->iso_hdr[1] = (tag << 6) | (iso->channel & 0x3F);
+
+	/* transmission speed */
+	next->iso_hdr[2] = iso->speed & 0x7;
+
+	/* payload size */
+	next->iso_hdr[6] = len & 0xFF;
+	next->iso_hdr[7] = len >> 8;
+
+	/* set up the OUTPUT_LAST */
+	next->output_last.control = cpu_to_le32(1 << 28);
+	next->output_last.control |= cpu_to_le32(1 << 27); /* update timeStamp */
+	next->output_last.control |= cpu_to_le32(3 << 20); /* want interrupt */
+	next->output_last.control |= cpu_to_le32(3 << 18); /* enable branch */
+	next->output_last.control |= cpu_to_le32(len);
+
+	/* payload bus address */
+	next->output_last.address = cpu_to_le32(dma_region_offset_to_bus(&iso->data_buf, offset));
+
+	/* leave branchAddress at zero for now */
+
+	/* re-write the previous DMA descriptor to chain to this one */
+
+	/* set prev branch address to point to next (Z=3) */
+	prev->output_last.branchAddress = cpu_to_le32(
+		dma_prog_region_offset_to_bus(&xmit->prog, sizeof(struct iso_xmit_cmd) * next_i) | 3);
+
+	/* disable interrupt, unless required by the IRQ interval */
+	if(prev_i % iso->irq_interval) {
+		prev->output_last.control &= cpu_to_le32(~(3 << 20)); /* no interrupt */
+	} else {
+		prev->output_last.control |= cpu_to_le32(3 << 20); /* enable interrupt */
+	}
+
+	wmb();
+
+	/* wake DMA in case it is sleeping */
+	reg_write(xmit->ohci, xmit->ContextControlSet, 1 << 12);
+
+	/* issue a dummy read of the cycle timer to force all PCI
+	   writes to be posted immediately */
+	mb();
+	reg_read(xmit->ohci, OHCI1394_IsochronousCycleTimer);
+
+	return 0;
+}
+
+static int ohci_iso_xmit_start(struct hpsb_iso *iso, int cycle)
+{
+	struct ohci_iso_xmit *xmit = iso->hostdata;
+
+	/* clear out the control register */
+	reg_write(xmit->ohci, xmit->ContextControlClear, 0xFFFFFFFF);
+	wmb();
+
+	/* address and length of first descriptor block (Z=3) */
+	reg_write(xmit->ohci, xmit->CommandPtr,
+		  dma_prog_region_offset_to_bus(&xmit->prog, iso->pkt_dma * sizeof(struct iso_xmit_cmd)) | 3);
+
+	/* cycle match */
+	if(cycle != -1) {
+		u32 start = cycle & 0x1FFF;
+		
+		/* 'cycle' is only mod 8000, but we also need two 'seconds' bits -
+		   just snarf them from the current time */
+		u32 seconds = reg_read(xmit->ohci, OHCI1394_IsochronousCycleTimer) >> 25;
+
+		/* advance one second to give some extra time for DMA to start */
+		seconds += 1;
+		
+		start |= (seconds & 3) << 13;
+
+		reg_write(xmit->ohci, xmit->ContextControlSet, 0x80000000 | (start << 16));
+	}
+
+	/* enable interrupts */
+	reg_write(xmit->ohci, OHCI1394_IsoXmitIntMaskSet, 1 << xmit->task.context);
+
+	/* run */
+	reg_write(xmit->ohci, xmit->ContextControlSet, 0x8000);
+	mb();
+
+	/* wait 100 usec to give the card time to go active */
+	udelay(100);
+
+	/* check the RUN bit */
+	if(!(reg_read(xmit->ohci, xmit->ContextControlSet) & 0x8000)) {
+		PRINT(KERN_ERR, xmit->ohci->id, "Error starting IT DMA (ContextControl 0x%08x)\n",
+		      reg_read(xmit->ohci, xmit->ContextControlSet));
+		return -1;
+	}
+
+	return 0;
+}
+
+static int ohci_isoctl(struct hpsb_iso *iso, enum isoctl_cmd cmd, unsigned long arg)
+{
+
+	switch(cmd) {
+	case XMIT_INIT:
+		return ohci_iso_xmit_init(iso);
+	case XMIT_START:
+		return ohci_iso_xmit_start(iso, arg);
+	case XMIT_STOP:
+		ohci_iso_xmit_stop(iso);
+		return 0;
+	case XMIT_QUEUE:
+		return ohci_iso_xmit_queue(iso, (struct hpsb_iso_packet_info*) arg);
+	case XMIT_SHUTDOWN:
+		ohci_iso_xmit_shutdown(iso);
+		return 0;
+
+	case RECV_INIT:
+		return ohci_iso_recv_init(iso);
+	case RECV_START: {
+		int *args = (int*) arg;
+		return ohci_iso_recv_start(iso, args[0], args[1], args[2]);
+	}
+	case RECV_STOP:
+		ohci_iso_recv_stop(iso);
+		return 0;
+	case RECV_RELEASE:
+		ohci_iso_recv_release(iso, (struct hpsb_iso_packet_info*) arg);
+		return 0;
+	case RECV_SHUTDOWN:
+		ohci_iso_recv_shutdown(iso);
+		return 0;
+	case RECV_LISTEN_CHANNEL:
+		ohci_iso_recv_change_channel(iso, arg, 1);
+		return 0;
+	case RECV_UNLISTEN_CHANNEL:
+		ohci_iso_recv_change_channel(iso, arg, 0);
+		return 0;
+	case RECV_SET_CHANNEL_MASK:
+		ohci_iso_recv_set_channel_mask(iso, *((u64*) arg));
+		return 0;
+
+	default:
+		PRINT_G(KERN_ERR, "ohci_isoctl cmd %d not implemented yet",
+			cmd);
+		break;
+	}
+	return -EINVAL;
+}
+
 /***************************************
  * IEEE-1394 functionality section END *
  ***************************************/
@@ -1039,7 +2167,7 @@
 
 		if (t->type == OHCI_ISO_TRANSMIT && tx_event & mask)
 			tasklet_schedule(&t->tasklet);
-		if (t->type == OHCI_ISO_RECEIVE && rx_event & mask)
+		else if (rx_event & mask)
 			tasklet_schedule(&t->tasklet);
 	}
 
@@ -1057,7 +2185,7 @@
 	unsigned long flags;
 
 	/* Read and clear the interrupt event register.  Don't clear
-	 * the busReset event, though, this is done when we get the
+	 * the busReset event, though. This is done when we get the
 	 * selfIDComplete interrupt. */
 	spin_lock_irqsave(&ohci->event_lock, flags);
 	event = reg_read(ohci, OHCI1394_IntEventClear);
@@ -1068,37 +2196,85 @@
 
 	DBGMSG(ohci->id, "IntEvent: %08x", event);
 
-	/* Die right here an now */
 	if (event & OHCI1394_unrecoverableError) {
-		PRINT(KERN_ERR, ohci->id, "Unrecoverable error, shutting down card!");
-		return;
+		int ctx;
+		PRINT(KERN_ERR, ohci->id, "Unrecoverable error!");
+
+		if (reg_read(ohci, OHCI1394_AsReqTrContextControlSet) & 0x800)
+			PRINT(KERN_ERR, ohci->id, "Async Req Tx Context died: "
+				"ctrl[%08x] cmdptr[%08x]",
+				reg_read(ohci, OHCI1394_AsReqTrContextControlSet),
+				reg_read(ohci, OHCI1394_AsReqTrCommandPtr));
+
+		if (reg_read(ohci, OHCI1394_AsRspTrContextControlSet) & 0x800)
+			PRINT(KERN_ERR, ohci->id, "Async Rsp Tx Context died: "
+				"ctrl[%08x] cmdptr[%08x]",
+				reg_read(ohci, OHCI1394_AsRspTrContextControlSet),
+				reg_read(ohci, OHCI1394_AsRspTrCommandPtr));
+
+		if (reg_read(ohci, OHCI1394_AsReqRcvContextControlSet) & 0x800)
+			PRINT(KERN_ERR, ohci->id, "Async Req Rcv Context died: "
+				"ctrl[%08x] cmdptr[%08x]",
+				reg_read(ohci, OHCI1394_AsReqRcvContextControlSet),
+				reg_read(ohci, OHCI1394_AsReqRcvCommandPtr));
+
+		if (reg_read(ohci, OHCI1394_AsRspRcvContextControlSet) & 0x800)
+			PRINT(KERN_ERR, ohci->id, "Async Rsp Rcv Context died: "
+				"ctrl[%08x] cmdptr[%08x]",
+				reg_read(ohci, OHCI1394_AsRspRcvContextControlSet),
+				reg_read(ohci, OHCI1394_AsRspRcvCommandPtr));
+
+		for (ctx = 0; ctx < ohci->nb_iso_xmit_ctx; ctx++) {
+			if (reg_read(ohci, OHCI1394_IsoXmitContextControlSet + (16 * ctx)) & 0x800)
+				PRINT(KERN_ERR, ohci->id, "Iso Xmit %d Context died: "
+					"ctrl[%08x] cmdptr[%08x]", ctx,
+					reg_read(ohci, OHCI1394_IsoXmitContextControlSet + (16 * ctx)),
+					reg_read(ohci, OHCI1394_IsoXmitCommandPtr + (16 * ctx)));
+		}
+
+		for (ctx = 0; ctx < ohci->nb_iso_rcv_ctx; ctx++) {
+			if (reg_read(ohci, OHCI1394_IsoRcvContextControlSet + (32 * ctx)) & 0x800)
+				PRINT(KERN_ERR, ohci->id, "Iso Recv %d Context died: "
+					"ctrl[%08x] cmdptr[%08x] match[%08x]", ctx,
+					reg_read(ohci, OHCI1394_IsoRcvContextControlSet + (32 * ctx)),
+					reg_read(ohci, OHCI1394_IsoRcvCommandPtr + (32 * ctx)),
+					reg_read(ohci, OHCI1394_IsoRcvContextMatch + (32 * ctx)));
+		}
+
+		event &= ~OHCI1394_unrecoverableError;
 	}
 
 	if (event & OHCI1394_cycleInconsistent) {
 		/* We subscribe to the cycleInconsistent event only to
 		 * clear the corresponding event bit... otherwise,
-		 * isochronous cycleMatch DMA wont work. */
+		 * isochronous cycleMatch DMA won't work. */
 		DBGMSG(ohci->id, "OHCI1394_cycleInconsistent");
 		event &= ~OHCI1394_cycleInconsistent;
 	}
 
 	if (event & OHCI1394_busReset) {
+		int loops = 0;
+
 		/* The busReset event bit can't be cleared during the
 		 * selfID phase, so we disable busReset interrupts, to
 		 * avoid burying the cpu in interrupt requests. */
 		spin_lock_irqsave(&ohci->event_lock, flags);
   		reg_write(ohci, OHCI1394_IntMaskClear, OHCI1394_busReset);
-		if (ohci->dev->vendor == PCI_VENDOR_ID_APPLE && 
-		    ohci->dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW) {
-  			udelay(10);
-  			while(reg_read(ohci, OHCI1394_IntEventSet) & OHCI1394_busReset) {
-  				reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
-				spin_unlock_irqrestore(&ohci->event_lock, flags);
-	  			udelay(10);
-				spin_lock_irqsave(&ohci->event_lock, flags);
-  			}
+		udelay(10);
+		while (reg_read(ohci, OHCI1394_IntEventSet) & OHCI1394_busReset) {
+			if (loops++ > 10000) {
+				hpsb_reset_bus(host, 1);
+				loops = 0;
+				DBGMSG(ohci->id, "Out of control loop, resetting");
+			}
+
+			reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
+			spin_unlock_irqrestore(&ohci->event_lock, flags);
+			udelay(10);
+			spin_lock_irqsave(&ohci->event_lock, flags);
   		}
 		spin_unlock_irqrestore(&ohci->event_lock, flags);
+
 		if (!host->in_bus_reset) {
 			DBGMSG(ohci->id, "irq_handler: Bus reset requested%s",
 			      (attempt_root) ? " and attempting to become root"
@@ -1174,74 +2350,61 @@
 	}
 	if (event & OHCI1394_selfIDComplete) {
 		if (host->in_bus_reset) {
-			node_id = reg_read(ohci, OHCI1394_NodeID); 
+			node_id = reg_read(ohci, OHCI1394_NodeID);
 
-			/* If our nodeid is not valid, give a msec delay
-			 * to let it settle in and try again.  */
 			if (!(node_id & 0x80000000)) {
-				mdelay(1);
-				node_id = reg_read(ohci, OHCI1394_NodeID);
+				PRINT(KERN_ERR, ohci->id,
+				      "SelfID received, but NodeID invalid "
+				      "(probably new bus reset occurred): %08X",
+				      node_id);
+				goto selfid_not_valid;
 			}
 
-			if (node_id & 0x80000000) { /* NodeID valid */
-				phyid =  node_id & 0x0000003f;
-				isroot = (node_id & 0x40000000) != 0;
+			phyid =  node_id & 0x0000003f;
+			isroot = (node_id & 0x40000000) != 0;
 
-				DBGMSG(ohci->id,
-				      "SelfID interrupt received "
-				      "(phyid %d, %s)", phyid, 
-				      (isroot ? "root" : "not root"));
+			DBGMSG(ohci->id,
+			      "SelfID interrupt received "
+			      "(phyid %d, %s)", phyid, 
+			      (isroot ? "root" : "not root"));
+
+			handle_selfid(ohci, host, phyid, isroot);
+
+			/* Clear the bus reset event and re-enable the
+			 * busReset interrupt.  */
+			spin_lock_irqsave(&ohci->event_lock, flags);
+			reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
+			reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset);
+			spin_unlock_irqrestore(&ohci->event_lock, flags);
 
-				handle_selfid(ohci, host, 
-					      phyid, isroot);
+			/* Accept Physical requests from all nodes. */
+			reg_write(ohci,OHCI1394_AsReqFilterHiSet, 0xffffffff);
+			reg_write(ohci,OHCI1394_AsReqFilterLoSet, 0xffffffff);
+
+			/* Turn on phys dma reception.
+			 *
+			 * TODO: Enable some sort of filtering management.
+			 */
+			if (phys_dma) {
+				reg_write(ohci,OHCI1394_PhyReqFilterHiSet, 0xffffffff);
+				reg_write(ohci,OHCI1394_PhyReqFilterLoSet, 0xffffffff);
+				reg_write(ohci,OHCI1394_PhyUpperBound, 0xffff0000);
 			} else {
-				PRINT(KERN_ERR, ohci->id, 
-				      "SelfID interrupt received, but "
-				      "NodeID is not valid: %08X",
-				      node_id);
+				reg_write(ohci,OHCI1394_PhyReqFilterHiSet, 0x00000000);
+				reg_write(ohci,OHCI1394_PhyReqFilterLoSet, 0x00000000);
 			}
 
-			/* Accept Physical requests from all nodes. */
-			reg_write(ohci,OHCI1394_AsReqFilterHiSet, 
-				  0xffffffff);
-			reg_write(ohci,OHCI1394_AsReqFilterLoSet, 
-				  0xffffffff);
+			DBGMSG(ohci->id, "PhyReqFilter=%08x%08x\n",
+			       reg_read(ohci,OHCI1394_PhyReqFilterHiSet),
+			       reg_read(ohci,OHCI1394_PhyReqFilterLoSet));
+
+			hpsb_selfid_complete(host, phyid, isroot);
 		} else
 			PRINT(KERN_ERR, ohci->id, 
 			      "SelfID received outside of bus reset sequence");
 
-		/* Finally, we clear the busReset event and reenable
-		 * the busReset interrupt. */
-		spin_lock_irqsave(&ohci->event_lock, flags);
-		reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
-		reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset); 
-		spin_unlock_irqrestore(&ohci->event_lock, flags);
-		event &= ~OHCI1394_selfIDComplete;	
-
-		/* Turn on phys dma reception. We should
-		 * probably manage the filtering somehow, 
-		 * instead of blindly turning it on.  */
-
-		/*
-		 * CAUTION!
-		 * Some chips (TI TSB43AB22) won't take a value in
-		 * the PhyReqFilter register until after the IntEvent
-		 * is cleared for bus reset, and even then a short
-		 * delay is required.
-		 */
-		if (phys_dma) {
-			mdelay(1);
-			reg_write(ohci,OHCI1394_PhyReqFilterHiSet,
-				  0xffffffff);
-			reg_write(ohci,OHCI1394_PhyReqFilterLoSet,
-				  0xffffffff);
-			reg_write(ohci,OHCI1394_PhyUpperBound,
-				  0xffff0000);
-		}
-
-		DBGMSG(ohci->id, "PhyReqFilter=%08x%08x\n",
-		       reg_read(ohci,OHCI1394_PhyReqFilterHiSet),
-		       reg_read(ohci,OHCI1394_PhyReqFilterLoSet));
+selfid_not_valid:
+		event &= ~OHCI1394_selfIDComplete;
 	}
 
 	/* Make sure we handle everything, just in case we accidentally
@@ -1267,8 +2430,10 @@
 		PRINT(KERN_INFO, ohci->id, 
 		      "Waking dma ctx=%d ... processing is probably too slow",
 		      d->ctx);
-		reg_write(ohci, d->ctrlSet, 0x1000);
 	}
+
+	/* do this always, to avoid race condition */
+	reg_write(ohci, d->ctrlSet, 0x1000);
 }
 
 #define cond_le32_to_cpu(data, noswap) \
@@ -1413,7 +2578,7 @@
 		 * bus reset. We always ignore it.  */
 		if (tcode != OHCI1394_TCODE_PHY) {
 			if (!ohci->no_swap_incoming)
-				packet_swab(d->spb, tcode, (length - 4) >> 2);
+				packet_swab(d->spb, tcode);
 			DBGMSG(ohci->id, "Packet received from node"
 				" %d ack=0x%02X spd=%d tcode=0x%X"
 				" length=%d ctx=%d tlabel=%d",
@@ -1454,7 +2619,7 @@
 	struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
 	struct hpsb_packet *packet;
 	unsigned long flags;
-	u32 ack;
+	u32 status, ack;
         size_t datasize;
 
 	spin_lock_irqsave(&d->lock, flags);
@@ -1463,25 +2628,16 @@
 		packet = driver_packet(d->fifo_list.next);
                 datasize = packet->data_size;
 		if (datasize && packet->type != hpsb_raw)
-			ack = le32_to_cpu(
+			status = le32_to_cpu(
 				d->prg_cpu[d->sent_ind]->end.status) >> 16;
 		else 
-			ack = le32_to_cpu(
+			status = le32_to_cpu(
 				d->prg_cpu[d->sent_ind]->begin.status) >> 16;
 
-		if (ack == 0) 
+		if (status == 0) 
 			/* this packet hasn't been sent yet*/
 			break;
 
-		if (!(ack & 0x10)) {
-			/* XXX: This is an OHCI evt_* code. We need to handle
-			 * this specially! For right now, we just fake an
-			 * ackx_send_error. */
-			PRINT(KERN_DEBUG, ohci->id, "Received OHCI evt_* error 0x%x",
-			       ack & 0xf);
-			ack = (ack & 0xffe0) | ACK_BUSY_A;
-		}
-
 #ifdef OHCI1394_DEBUG
 		if (datasize)
 			DBGMSG(ohci->id,
@@ -1493,7 +2649,7 @@
                                         >>4)&0xf,
                                 (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])
                                         >>10)&0x3f,
-                                ack&0x1f, (ack>>5)&0x3, 
+                                status&0x1f, (status>>5)&0x3, 
                                 le32_to_cpu(d->prg_cpu[d->sent_ind]->data[3])
                                         >>16,
                                 d->ctx);
@@ -1507,13 +2663,64 @@
                                         >>4)&0xf,
                                 (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])
                                         >>10)&0x3f,
-                                ack&0x1f, (ack>>5)&0x3, 
+                                status&0x1f, (status>>5)&0x3, 
                                 le32_to_cpu(d->prg_cpu[d->sent_ind]->data[3]),
                                 d->ctx);
 #endif		
 
+		if (status & 0x10) {
+			ack = status & 0xf;
+		} else {
+			switch (status & 0x1f) {
+			case EVT_NO_STATUS: /* that should never happen */
+			case EVT_RESERVED_A: /* that should never happen */
+			case EVT_LONG_PACKET: /* that should never happen */
+				PRINT(KERN_WARNING, ohci->id, "Received OHCI evt_* error 0x%x", status & 0x1f);
+				ack = ACKX_SEND_ERROR;
+				break;
+			case EVT_MISSING_ACK:
+				ack = ACKX_TIMEOUT;
+				break;
+			case EVT_UNDERRUN:
+				ack = ACKX_SEND_ERROR;
+				break;
+			case EVT_OVERRUN: /* that should never happen */
+				PRINT(KERN_WARNING, ohci->id, "Received OHCI evt_* error 0x%x", status & 0x1f);
+				ack = ACKX_SEND_ERROR;
+				break;
+			case EVT_DESCRIPTOR_READ:
+			case EVT_DATA_READ:
+			case EVT_DATA_WRITE:
+				ack = ACKX_SEND_ERROR;
+				break;
+			case EVT_BUS_RESET: /* that should never happen */
+				PRINT(KERN_WARNING, ohci->id, "Received OHCI evt_* error 0x%x", status & 0x1f);
+				ack = ACKX_SEND_ERROR;
+				break;
+			case EVT_TIMEOUT:
+				ack = ACKX_TIMEOUT;
+				break;
+			case EVT_TCODE_ERR:
+				ack = ACKX_SEND_ERROR;
+				break;
+			case EVT_RESERVED_B: /* that should never happen */
+			case EVT_RESERVED_C: /* that should never happen */
+				PRINT(KERN_WARNING, ohci->id, "Received OHCI evt_* error 0x%x", status & 0x1f);
+				ack = ACKX_SEND_ERROR;
+				break;
+			case EVT_UNKNOWN:
+			case EVT_FLUSHED:
+				ack = ACKX_SEND_ERROR;
+				break;
+			default:
+				PRINT(KERN_ERR, ohci->id, "Unhandled OHCI evt_* error 0x%x", status & 0x1f);
+				ack = ACKX_SEND_ERROR;
+				BUG();
+			}
+		}
+
                 list_del(&packet->driver_list);
-		hpsb_packet_sent(ohci->host, packet, ack & 0xf);
+		hpsb_packet_sent(ohci->host, packet, ack);
 
 		if (datasize) {
 			pci_unmap_single(ohci->dev, 
@@ -1539,13 +2746,18 @@
 		return;
 
 	DBGMSG(d->ohci->id, "Freeing dma_rcv_ctx %d", d->ctx);
-	
-	ohci1394_stop_context(d->ohci, d->ctrlClear, NULL);
 
-	if (d->type == DMA_CTX_ISO)
-		ohci1394_unregister_iso_tasklet(d->ohci, &d->ohci->ir_tasklet);
-	else
-		tasklet_kill(&d->task);
+	if(d->ctrlClear) {
+		ohci1394_stop_context(d->ohci, d->ctrlClear, NULL);
+
+		if (d->type == DMA_CTX_ISO) {
+			/* disable interrupts */
+			reg_write(d->ohci, OHCI1394_IsoRecvIntMaskClear, 1 << d->ctx);
+			ohci1394_unregister_iso_tasklet(d->ohci, &d->ohci->ir_legacy_tasklet);
+		} else {
+			tasklet_kill(&d->task);
+		}
+	}
 
 	if (d->buf_cpu) {
 		for (i=0; i<d->num_desc; i++)
@@ -1561,11 +2773,11 @@
 	if (d->prg_cpu) {
 		for (i=0; i<d->num_desc; i++) 
 			if (d->prg_cpu[i] && d->prg_bus[i]) {
-				pci_free_consistent(
-					d->ohci->dev, sizeof(struct dma_cmd), 
-					d->prg_cpu[i], d->prg_bus[i]);
+				pci_pool_free(d->prg_pool, d->prg_cpu[i], d->prg_bus[i]);
 				OHCI_DMA_FREE("consistent dma_rcv prg[%d]", i);
 			}
+		pci_pool_destroy(d->prg_pool);
+		OHCI_DMA_FREE("dma_rcv prg pool");
 		kfree(d->prg_cpu);
 		kfree(d->prg_bus);
 	}
@@ -1590,9 +2802,9 @@
 	d->buf_size = buf_size;
 	d->split_buf_size = split_buf_size;
 
-	d->ctrlSet = context_base + OHCI1394_ContextControlSet;
-	d->ctrlClear = context_base + OHCI1394_ContextControlClear;
-	d->cmdPtr = context_base + OHCI1394_ContextCommandPtr;
+	d->ctrlSet = 0;
+	d->ctrlClear = 0;
+	d->cmdPtr = 0;
 
 	d->buf_cpu = kmalloc(d->num_desc * sizeof(quadlet_t*), GFP_KERNEL);
 	d->buf_bus = kmalloc(d->num_desc * sizeof(dma_addr_t), GFP_KERNEL);
@@ -1625,6 +2837,10 @@
 		return -ENOMEM;
 	}
 
+	d->prg_pool = pci_pool_create("ohci1394 rcv prg", ohci->dev,
+				      sizeof(struct dma_cmd), 4, 0, SLAB_KERNEL);
+	OHCI_DMA_ALLOC("dma_rcv prg pool");
+
 	for (i=0; i<d->num_desc; i++) {
 		d->buf_cpu[i] = pci_alloc_consistent(ohci->dev, 
 						     d->buf_size,
@@ -1640,11 +2856,8 @@
 			return -ENOMEM;
 		}
 
-		
-                d->prg_cpu[i] = pci_alloc_consistent(ohci->dev, 
-						     sizeof(struct dma_cmd),
-						     d->prg_bus+i);
-		OHCI_DMA_ALLOC("consistent dma_rcv prg[%d]", i);
+		d->prg_cpu[i] = pci_pool_alloc(d->prg_pool, SLAB_KERNEL, d->prg_bus+i);
+		OHCI_DMA_ALLOC("pool dma_rcv prg[%d]", i);
 
                 if (d->prg_cpu[i] != NULL) {
                         memset(d->prg_cpu[i], 0, sizeof(struct dma_cmd));
@@ -1659,17 +2872,30 @@
         spin_lock_init(&d->lock);
 
 	if (type == DMA_CTX_ISO) {
-		ohci1394_init_iso_tasklet(&ohci->ir_tasklet, OHCI_ISO_RECEIVE,
+		ohci1394_init_iso_tasklet(&ohci->ir_legacy_tasklet,
+					  OHCI_ISO_MULTICHANNEL_RECEIVE,
 					  dma_rcv_tasklet, (unsigned long) d);
 		if (ohci1394_register_iso_tasklet(ohci,
-						  &ohci->ir_tasklet) < 0) {
+						  &ohci->ir_legacy_tasklet) < 0) {
 			PRINT(KERN_ERR, ohci->id, "No IR DMA context available");
 			free_dma_rcv_ctx(d);
 			return -EBUSY;
 		}
-	}
-	else
+
+		/* the IR context can be assigned to any DMA context
+		 * by ohci1394_register_iso_tasklet */
+		d->ctx = ohci->ir_legacy_tasklet.context;
+		d->ctrlSet = OHCI1394_IsoRcvContextControlSet + 32*d->ctx;
+		d->ctrlClear = OHCI1394_IsoRcvContextControlClear + 32*d->ctx;
+		d->cmdPtr = OHCI1394_IsoRcvCommandPtr + 32*d->ctx;
+		d->ctxtMatch = OHCI1394_IsoRcvContextMatch + 32*d->ctx;
+	} else {
+		d->ctrlSet = context_base + OHCI1394_ContextControlSet;
+		d->ctrlClear = context_base + OHCI1394_ContextControlClear;
+		d->cmdPtr = context_base + OHCI1394_ContextCommandPtr;
+
 		tasklet_init (&d->task, dma_rcv_tasklet, (unsigned long) d);
+	}
 
 	return 0;
 }
@@ -1683,21 +2909,27 @@
 
 	DBGMSG(d->ohci->id, "Freeing dma_trm_ctx %d", d->ctx);
 
-	ohci1394_stop_context(d->ohci, d->ctrlClear, NULL);
+	if(d->ctrlClear) {
+		ohci1394_stop_context(d->ohci, d->ctrlClear, NULL);
 
-	if (d->type == DMA_CTX_ISO)
-		ohci1394_unregister_iso_tasklet(d->ohci, &d->ohci->it_tasklet);
-	else
-		tasklet_kill(&d->task);
+		if (d->type == DMA_CTX_ISO) {
+			/* disable interrupts */
+			reg_write(d->ohci, OHCI1394_IsoXmitIntMaskClear, 1 << d->ctx);
+			ohci1394_unregister_iso_tasklet(d->ohci,
+							&d->ohci->it_legacy_tasklet);
+		} else {
+			tasklet_kill(&d->task);
+		}
+	}
 
 	if (d->prg_cpu) {
 		for (i=0; i<d->num_desc; i++) 
 			if (d->prg_cpu[i] && d->prg_bus[i]) {
-				pci_free_consistent(
-					d->ohci->dev, sizeof(struct at_dma_prg), 
-					d->prg_cpu[i], d->prg_bus[i]);
-				OHCI_DMA_FREE("consistent dma_trm prg[%d]", i);
+				pci_pool_free(d->prg_pool, d->prg_cpu[i], d->prg_bus[i]);
+				OHCI_DMA_FREE("pool dma_trm prg[%d]", i);
 			}
+		pci_pool_destroy(d->prg_pool);
+		OHCI_DMA_FREE("dma_trm prg pool");
 		kfree(d->prg_cpu);
 		kfree(d->prg_bus);
 	}
@@ -1717,9 +2949,9 @@
 	d->type = type;
 	d->ctx = ctx;
 	d->num_desc = num_desc;
-	d->ctrlSet = context_base + OHCI1394_ContextControlSet;
-	d->ctrlClear = context_base + OHCI1394_ContextControlClear;
-	d->cmdPtr = context_base + OHCI1394_ContextCommandPtr;
+	d->ctrlSet = 0;
+	d->ctrlClear = 0;
+	d->cmdPtr = 0;
 
 	d->prg_cpu = kmalloc(d->num_desc * sizeof(struct at_dma_prg*), 
 			     GFP_KERNEL);
@@ -1733,11 +2965,13 @@
 	memset(d->prg_cpu, 0, d->num_desc * sizeof(struct at_dma_prg*));
 	memset(d->prg_bus, 0, d->num_desc * sizeof(dma_addr_t));
 
+	d->prg_pool = pci_pool_create("ohci1394 trm prg", ohci->dev,
+				      sizeof(struct at_dma_prg), 4, 0, SLAB_KERNEL);
+	OHCI_DMA_ALLOC("dma_rcv prg pool");
+
 	for (i = 0; i < d->num_desc; i++) {
-                d->prg_cpu[i] = pci_alloc_consistent(ohci->dev, 
-						     sizeof(struct at_dma_prg),
-						     d->prg_bus+i);
-		OHCI_DMA_ALLOC("consistent dma_trm prg[%d]", i);
+		d->prg_cpu[i] = pci_pool_alloc(d->prg_pool, SLAB_KERNEL, d->prg_bus+i);
+		OHCI_DMA_ALLOC("pool dma_trm prg[%d]", i);
 
                 if (d->prg_cpu[i] != NULL) {
                         memset(d->prg_cpu[i], 0, sizeof(struct at_dma_prg));
@@ -1753,17 +2987,26 @@
 
 	/* initialize tasklet */
 	if (type == DMA_CTX_ISO) {
-		ohci1394_init_iso_tasklet(&ohci->it_tasklet, OHCI_ISO_TRANSMIT,
-					  dma_rcv_tasklet, (unsigned long) d);
+		ohci1394_init_iso_tasklet(&ohci->it_legacy_tasklet, OHCI_ISO_TRANSMIT,
+					  dma_trm_tasklet, (unsigned long) d);
 		if (ohci1394_register_iso_tasklet(ohci,
-						  &ohci->it_tasklet) < 0) {
+						  &ohci->it_legacy_tasklet) < 0) {
 			PRINT(KERN_ERR, ohci->id, "No IT DMA context available");
 			free_dma_trm_ctx(d);
 			return -EBUSY;
 		}
-	}
-	else
+
+		/* IT can be assigned to any context by register_iso_tasklet */
+		d->ctx = ohci->it_legacy_tasklet.context;
+		d->ctrlSet = OHCI1394_IsoXmitContextControlSet + 16 * d->ctx;
+		d->ctrlClear = OHCI1394_IsoXmitContextControlClear + 16 * d->ctx;
+		d->cmdPtr = OHCI1394_IsoXmitCommandPtr + 16 * d->ctx;
+	} else {
+		d->ctrlSet = context_base + OHCI1394_ContextControlSet;
+		d->ctrlClear = context_base + OHCI1394_ContextControlClear;
+		d->cmdPtr = context_base + OHCI1394_ContextCommandPtr;
 		tasklet_init (&d->task, dma_trm_tasklet, (unsigned long)d);
+	}
 
 	return 0;
 }
@@ -1905,7 +3148,7 @@
 	ohci->csr_config_rom_length = cr.data - ohci->csr_config_rom_cpu;
 }
 
-static size_t ohci_get_rom(struct hpsb_host *host, const quadlet_t **ptr)
+static size_t ohci_get_rom(struct hpsb_host *host, quadlet_t **ptr)
 {
 	struct ti_ohci *ohci=host->hostdata;
 
@@ -1942,6 +3185,7 @@
 	.get_rom =		ohci_get_rom,
 	.transmit_packet =	ohci_transmit,
 	.devctl =		ohci_devctl,
+	.isoctl =               ohci_isoctl,
 	.hw_csr_reg =		ohci_hw_csr_reg,
 };
 
@@ -1967,7 +3211,7 @@
 	struct hpsb_host *host;
 	struct ti_ohci *ohci;	/* shortcut to currently handled device */
 	unsigned long ohci_base;
-	
+
 	if (version_printed++ == 0)
 		PRINT_G(KERN_INFO, "%s", version);
 
@@ -2043,7 +3287,7 @@
 		pci_alloc_consistent(ohci->dev, OHCI1394_SI_DMA_BUF_SIZE,
                       &ohci->selfid_buf_bus);
 	OHCI_DMA_ALLOC("consistent selfid_buf");
-	
+
 	if (ohci->selfid_buf_cpu == NULL)
 		FAIL(-ENOMEM, "Failed to allocate DMA buffer for self-id packets");
 	ohci->init_state = OHCI_INIT_HAVE_SELFID_BUFFER;
@@ -2116,19 +3360,11 @@
 	ohci->ISO_channel_usage = 0;
         spin_lock_init(&ohci->IR_channel_lock);
 
-	/* IR DMA context */
-	if (alloc_dma_rcv_ctx(ohci, &ohci->ir_context,
-			      DMA_CTX_ISO, 0, IR_NUM_DESC,
-			      IR_BUF_SIZE, IR_SPLIT_BUF_SIZE,
-			      OHCI1394_IsoRcvContextBase) < 0)
-		FAIL(-ENOMEM, "Failed to allocate IR context");
+	/* the IR DMA context is allocated on-demand; mark it inactive */
+	ohci->ir_legacy_context.ohci = NULL;
 
-	
-	/* IT DMA context allocation */
-	if (alloc_dma_trm_ctx(ohci, &ohci->it_context,
-			      DMA_CTX_ISO, 0, IT_NUM_DESC,
-			      OHCI1394_IsoXmitContextBase) < 0)
-		FAIL(-ENOMEM, "Failed to allocate IT context");
+	/* same for the IT DMA context */
+	ohci->it_legacy_context.ohci = NULL;
 
 	if (request_irq(dev->irq, ohci_irq_handler, SA_SHIRQ,
 			 OHCI1394_DRIVER_NAME, ohci))
@@ -2173,11 +3409,11 @@
 		free_dma_trm_ctx(&ohci->at_resp_context);
 
 		/* Free IR dma */
-		free_dma_rcv_ctx(&ohci->ir_context);
-		
+		free_dma_rcv_ctx(&ohci->ir_legacy_context);
+
 		/* Free IT dma */
-		free_dma_trm_ctx(&ohci->it_context);
-	
+		free_dma_trm_ctx(&ohci->it_legacy_context);
+
 	case OHCI_INIT_HAVE_SELFID_BUFFER:
 		pci_free_consistent(ohci->dev, OHCI1394_SI_DMA_BUF_SIZE, 
 				    ohci->selfid_buf_cpu,
@@ -2225,10 +3461,10 @@
 
 static struct pci_device_id ohci1394_pci_tbl[] __devinitdata = {
 	{
-		.class = 		PCI_CLASS_FIREWIRE_OHCI,
-		.class_mask = 	0x00ffffff,
-		.vendor =		PCI_ANY_ID,
-		.device =		PCI_ANY_ID,
+		.class = 	PCI_CLASS_FIREWIRE_OHCI,
+		.class_mask = 	~0,
+		.vendor =	PCI_ANY_ID,
+		.device =	PCI_ANY_ID,
 		.subvendor =	PCI_ANY_ID,
 		.subdevice =	PCI_ANY_ID,
 	},
@@ -2253,7 +3489,7 @@
 /* essentially the only purpose of this code is to allow another
    module to hook into ohci's interrupt handler */
 
-void ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg)
+int ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg)
 {
 	int i=0;
 
@@ -2265,11 +3501,15 @@
 		i++;
 		if (i>5000) {
 			PRINT(KERN_ERR, ohci->id, 
-			      "Runaway loop while stopping context...");
-			break;
+			      "Runaway loop while stopping context: %s...", msg ? msg : "");
+			return 1;
 		}
+
+		mb();
+		udelay(10);
 	}
 	if (msg) PRINT(KERN_ERR, ohci->id, "%s: dma prg stopped", msg);
+	return 0;
 }
 
 void ohci1394_init_iso_tasklet(struct ohci1394_iso_tasklet *tasklet, int type,
@@ -2278,7 +3518,7 @@
 	tasklet_init(&tasklet->tasklet, func, data);
 	tasklet->type = type;
 	/* We init the tasklet->link field, so we can list_del() it
-	 * without worrying wether it was added to the list or not. */
+	 * without worrying whether it was added to the list or not. */
 	INIT_LIST_HEAD(&tasklet->link);
 }
 
@@ -2295,6 +3535,13 @@
 	else {
 		n = ohci->nb_iso_rcv_ctx;
 		usage = &ohci->ir_ctx_usage;
+
+		/* only one receive context can be multichannel (OHCI sec 10.4.1) */
+		if(tasklet->type == OHCI_ISO_MULTICHANNEL_RECEIVE) {
+			if(test_and_set_bit(0, &ohci->ir_multichannel_used)) {
+				return r;
+			}
+		}
 	}
 
 	spin_lock_irqsave(&ohci->iso_tasklet_list_lock, flags);
@@ -2308,7 +3555,7 @@
 		}
 
 	spin_unlock_irqrestore(&ohci->iso_tasklet_list_lock, flags);
-	
+
 	return r;
 }
 
@@ -2323,9 +3570,14 @@
 
 	if (tasklet->type == OHCI_ISO_TRANSMIT)
 		clear_bit(tasklet->context, &ohci->it_ctx_usage);
-	else
+	else {
 		clear_bit(tasklet->context, &ohci->ir_ctx_usage);
 
+		if(tasklet->type == OHCI_ISO_MULTICHANNEL_RECEIVE) {
+			clear_bit(0, &ohci->ir_multichannel_used);
+		}
+	}
+
 	list_del(&tasklet->link);
 
 	spin_unlock_irqrestore(&ohci->iso_tasklet_list_lock, flags);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/ohci1394.h linux-2.4.21-pre6/drivers/ieee1394/ohci1394.h
--- linux-2.4.20/drivers/ieee1394/ohci1394.h	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ieee1394/ohci1394.h	2003-03-26 23:49:07.000000000 +0000
@@ -95,6 +95,7 @@
 	/* dma block descriptors */
         struct dma_cmd **prg_cpu;
         dma_addr_t *prg_bus;
+	struct pci_pool *prg_pool;
 
 	/* dma buffers */
         quadlet_t **buf_cpu;
@@ -108,6 +109,7 @@
 	int ctrlClear;
 	int ctrlSet;
 	int cmdPtr;
+	int ctxtMatch;
 };
 
 /* DMA transmit context */	
@@ -120,6 +122,7 @@
 	/* dma block descriptors */
         struct at_dma_prg **prg_cpu;
 	dma_addr_t *prg_bus;
+	struct pci_pool *prg_pool;
 
         unsigned int prg_ind;
         unsigned int sent_ind;
@@ -143,7 +146,8 @@
 	struct tasklet_struct tasklet;
 	struct list_head link;
 	int context;
-	enum { OHCI_ISO_TRANSMIT, OHCI_ISO_RECEIVE } type;
+	enum { OHCI_ISO_TRANSMIT, OHCI_ISO_RECEIVE,
+	       OHCI_ISO_MULTICHANNEL_RECEIVE } type;
 };
 
 struct ti_ohci {
@@ -168,7 +172,7 @@
 	/* dma buffer for self-id packets */
         quadlet_t *selfid_buf_cpu;
         dma_addr_t selfid_buf_bus;
-	
+
 	/* buffer for csr config rom */
         quadlet_t *csr_config_rom_cpu; 
         dma_addr_t csr_config_rom_bus; 
@@ -185,18 +189,28 @@
 	struct dma_trm_ctx at_req_context;
 
         /* iso receive */
-	struct dma_rcv_ctx ir_context;
-	struct ohci1394_iso_tasklet ir_tasklet;
-        spinlock_t IR_channel_lock;
 	int nb_iso_rcv_ctx;
 	unsigned long ir_ctx_usage; /* use test_and_set_bit() for atomicity */
+	unsigned long ir_multichannel_used; /* ditto */
+        spinlock_t IR_channel_lock;
+
+	/* iso receive (legacy API) */
+	u64 ir_legacy_channels; /* note: this differs from ISO_channel_usage;
+				   it only accounts for channels listened to
+				   by the legacy API, so that we can know when
+				   it is safe to free the legacy API context */
+
+	struct dma_rcv_ctx ir_legacy_context;
+	struct ohci1394_iso_tasklet ir_legacy_tasklet;
 	
         /* iso transmit */
-	struct dma_trm_ctx it_context;
-	struct ohci1394_iso_tasklet it_tasklet;
 	int nb_iso_xmit_ctx;
 	unsigned long it_ctx_usage; /* use test_and_set_bit() for atomicity */
-	
+
+	/* iso transmit (legacy API) */
+	struct dma_trm_ctx it_legacy_context;
+	struct ohci1394_iso_tasklet it_legacy_tasklet;
+
         u64 ISO_channel_usage;
 
         /* IEEE-1394 part follows */
@@ -211,10 +225,10 @@
 
 	/* Tasklets for iso receive and transmit, used by video1394,
 	 * amdtp and dv1394 */
-	
+
 	struct list_head iso_tasklet_list;
 	spinlock_t iso_tasklet_list_lock;
-	
+
 	/* Swap the selfid buffer? */
 	unsigned int selfid_swap:1;
 	/* Some Apple chipset seem to swap incoming headers for us */
@@ -292,6 +306,9 @@
 #define OHCI1394_IsoRecvIntEventClear         0x0A4
 #define OHCI1394_IsoRecvIntMaskSet            0x0A8
 #define OHCI1394_IsoRecvIntMaskClear          0x0AC
+#define OHCI1394_InitialBandwidthAvailable    0x0B0
+#define OHCI1394_InitialChannelsAvailableHi   0x0B4
+#define OHCI1394_InitialChannelsAvailableLo   0x0B8
 #define OHCI1394_FairnessControl              0x0DC
 #define OHCI1394_LinkControlSet               0x0E0
 #define OHCI1394_LinkControlClear             0x0E4
@@ -380,7 +397,7 @@
 
 /* OHCI evt_* error types, table 3-2 of the OHCI 1.1 spec. */
 #define EVT_NO_STATUS		0x0	/* No event status */
-#define EVT_RESERVED		0x1	/* Reserved, not used !!! */
+#define EVT_RESERVED_A		0x1	/* Reserved, not used !!! */
 #define EVT_LONG_PACKET		0x2	/* The revc data was longer than the buf */
 #define EVT_MISSING_ACK		0x3	/* A subaction gap was detected before an ack
 					   arrived, or recv'd ack had a parity error */
@@ -388,17 +405,28 @@
 					   truncated */
 #define EVT_OVERRUN		0x5	/* A recv FIFO overflowed on reception of ISO
 					   packet */
-#define EVT_DESCRIPTOR_READ	0x6	/* An unrecoverable error occured while host was
+#define EVT_DESCRIPTOR_READ	0x6	/* An unrecoverable error occurred while host was
 					   reading a descriptor block */
-#define EVT_DATA_READ		0x7	/* An error occured while host controller was
+#define EVT_DATA_READ		0x7	/* An error occurred while host controller was
 					   attempting to read from host memory in the data
 					   stage of descriptor processing */
-#define EVT_DATA_WRITE		0x8	/* An error occured while host controller was
+#define EVT_DATA_WRITE		0x8	/* An error occurred while host controller was
 					   attempting to write either during the data stage
 					   of descriptor processing, or when processing a single
 					   16-bit host memory write */
 #define EVT_BUS_RESET		0x9	/* Identifies a PHY packet in the recv buffer as
 					   being a synthesized bus reset packet */
+#define EVT_TIMEOUT		0xa	/* Indicates that the asynchronous transmit response
+					   packet expired and was not transmitted, or that an
+					   IT DMA context experienced a skip processing overflow */
+#define EVT_TCODE_ERR		0xb	/* A bad tCode is associated with this packet.
+					   The packet was flushed */
+#define EVT_RESERVED_B		0xc	/* Reserved, not used !!! */
+#define EVT_RESERVED_C		0xd	/* Reserved, not used !!! */
+#define EVT_UNKNOWN		0xe	/* An error condition has occurred that cannot be
+					   represented by any other event codes defined herein. */
+#define EVT_FLUSHED		0xf	/* Send by the link side of output FIFO when asynchronous
+					   packets are being flushed due to a bus reset. */
 
 #define OHCI1394_TCODE_PHY               0xE
 
@@ -411,8 +439,8 @@
 void ohci1394_unregister_iso_tasklet(struct ti_ohci *ohci,
 				     struct ohci1394_iso_tasklet *tasklet);
 
-void ohci1394_stop_context      (struct ti_ohci *ohci, int reg, char *msg);
+/* returns zero if successful, one if DMA context is locked up */
+int ohci1394_stop_context      (struct ti_ohci *ohci, int reg, char *msg);
 struct ti_ohci *ohci1394_get_struct(int card_num);
 
 #endif
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/pcilynx.c linux-2.4.21-pre6/drivers/ieee1394/pcilynx.c
--- linux-2.4.20/drivers/ieee1394/pcilynx.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ieee1394/pcilynx.c	2003-03-26 23:49:27.000000000 +0000
@@ -19,6 +19,17 @@
  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
+/*
+ * Contributions:
+ *
+ * Manfred Weihs <weihs@ict.tuwien.ac.at>
+ *        reading bus info block (containing GUID) from serial 
+ *            eeprom via i2c and storing it in config ROM
+ *        Reworked code for initiating bus resets
+ *            (long, short, with or without hold-off)
+ *        Enhancements in async and iso send code
+ */
+
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
@@ -450,7 +461,7 @@
 
         if (host->in_bus_reset) return; /* in bus reset again */
 
-        if (isroot) reg_set_bits(lynx, LINK_CONTROL, LINK_CONTROL_CYCMASTER);
+        if (isroot) reg_set_bits(lynx, LINK_CONTROL, LINK_CONTROL_CYCMASTER); //FIXME: I do not think, we need this here
         reg_set_bits(lynx, LINK_CONTROL,
                      LINK_CONTROL_RCV_CMP_VALID | LINK_CONTROL_TX_ASYNC_EN
                      | LINK_CONTROL_RX_ASYNC_EN | LINK_CONTROL_CYCTIMEREN);
@@ -466,7 +477,14 @@
         struct hpsb_packet *packet;
 
         d = (what == hpsb_iso ? &lynx->iso_send : &lynx->async);
+        if (!list_empty(&d->pcl_queue)) {
+                PRINT(KERN_ERR, lynx->id, "trying to queue a new packet in nonempty fifo");
+                BUG();
+        }
+
         packet = driver_packet(d->queue.next);
+        list_del(&packet->driver_list);
+        list_add_tail(&packet->driver_list, &d->pcl_queue);
 
         d->header_dma = pci_map_single(lynx->dev, packet->header,
                                        packet->header_size, PCI_DMA_TODEVICE);
@@ -480,6 +498,7 @@
 
         pcl.next = PCL_NEXT_INVALID;
         pcl.async_error_next = PCL_NEXT_INVALID;
+        pcl.pcl_status = 0;
 #ifdef __BIG_ENDIAN
         pcl.buffer[0].control = packet->speed_code << 14 | packet->header_size;
 #else
@@ -546,7 +565,7 @@
         spin_lock_irqsave(&d->queue_lock, flags);
 
 	list_add_tail(&packet->driver_list, &d->queue);
-	if (d->queue.next == &packet->driver_list)
+	if (list_empty(&d->pcl_queue))
                 send_next(lynx, packet->type);
 
         spin_unlock_irqrestore(&d->queue_lock, flags);
@@ -563,6 +582,7 @@
         struct hpsb_packet *packet;
 	LIST_HEAD(packet_list);
         unsigned long flags;
+	int phy_reg;
 
         switch (cmd) {
         case RESET_BUS:
@@ -571,21 +591,47 @@
                         break;
                 }
 
-                if (arg) {
-                        arg = 3 << 6;
-                } else {
-                        arg = 1 << 6;
-                }
-
-                retval = get_phy_reg(lynx, 1);
-                arg |= (retval == -1 ? 63 : retval);
-                retval = 0;
-
-                PRINT(KERN_INFO, lynx->id, "resetting bus on request");
+		switch (arg) {
+		case SHORT_RESET:
+			if (lynx->phyic.reg_1394a) {
+				phy_reg = get_phy_reg(lynx, 5);
+				if (phy_reg == -1) {
+					PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed");
+					retval = -1;
+					break;
+				}
+				phy_reg |= 0x40;
+
+				PRINT(KERN_INFO, lynx->id, "resetting bus (short bus reset) on request");
+
+				lynx->selfid_size = -1;
+				lynx->phy_reg0 = -1;
+				set_phy_reg(lynx, 5, phy_reg); /* set ISBR */
+				break;
+			} else {
+				PRINT(KERN_INFO, lynx->id, "cannot do short bus reset, because of old phy");
+				/* fall through to long bus reset */
+			}
+		case LONG_RESET:
+			phy_reg = get_phy_reg(lynx, 1);
+			if (phy_reg == -1) {
+				PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed");
+				retval = -1;
+				break;
+			}
+			phy_reg |= 0x40;
+
+			PRINT(KERN_INFO, lynx->id, "resetting bus (long bus reset) on request");
+
+			lynx->selfid_size = -1;
+			lynx->phy_reg0 = -1;
+			set_phy_reg(lynx, 1, phy_reg); /* clear RHB, set IBR */
+			break;
+		default:
+			PRINT(KERN_ERR, lynx->id, "unknown argument for reset_bus command %d", arg);
+			retval = -1;
+		}
 
-                lynx->selfid_size = -1;
-                lynx->phy_reg0 = -1;
-                set_phy_reg(lynx, 1, arg);
                 break;
 
         case GET_CYCLE_COUNTER:
@@ -618,7 +664,44 @@
 		list_splice(&lynx->async.queue, &packet_list);
 		INIT_LIST_HEAD(&lynx->async.queue);
 
-                spin_unlock_irqrestore(&lynx->async.queue_lock, flags);
+                if (list_empty(&lynx->async.pcl_queue)) {
+                        spin_unlock_irqrestore(&lynx->async.queue_lock, flags);
+                        PRINTD(KERN_DEBUG, lynx->id, "no async packet in PCL to cancel");
+                } else {
+                        struct ti_pcl pcl;
+                        u32 ack;
+                        struct hpsb_packet *packet;
+
+                        PRINT(KERN_INFO, lynx->id, "cancelling async packet, that was already in PCL");
+
+                        get_pcl(lynx, lynx->async.pcl, &pcl);
+
+                        packet = driver_packet(lynx->async.pcl_queue.next);
+                        list_del(&packet->driver_list);
+
+                        pci_unmap_single(lynx->dev, lynx->async.header_dma,
+                                         packet->header_size, PCI_DMA_TODEVICE);
+                        if (packet->data_size) {
+                                pci_unmap_single(lynx->dev, lynx->async.data_dma,
+                                                 packet->data_size, PCI_DMA_TODEVICE);
+                        }
+
+                        spin_unlock_irqrestore(&lynx->async.queue_lock, flags);
+
+                        if (pcl.pcl_status & DMA_CHAN_STAT_PKTCMPL) {
+                                if (pcl.pcl_status & DMA_CHAN_STAT_SPECIALACK) {
+                                        ack = (pcl.pcl_status >> 15) & 0xf;
+                                        PRINTD(KERN_INFO, lynx->id, "special ack %d", ack);
+                                        ack = (ack == 1 ? ACKX_TIMEOUT : ACKX_SEND_ERROR);
+                                } else {
+                                        ack = (pcl.pcl_status >> 15) & 0xf;
+                                }
+                        } else {
+                                PRINT(KERN_INFO, lynx->id, "async packet was not completed");
+                                ack = ACKX_ABORTED;
+                        }
+                        hpsb_packet_sent(host, packet, ack);
+                }
 
 		while (!list_empty(&packet_list)) {
 			packet = driver_packet(packet_list.next);
@@ -709,7 +792,7 @@
 
 static int mem_open(struct inode *inode, struct file *file)
 {
-        int cid = minor(inode->i_rdev);
+        int cid = MINOR(inode->i_rdev);
         enum { t_rom, t_aux, t_ram } type;
         struct memdata *md;
         
@@ -891,21 +974,13 @@
         ssize_t retval;
         void *membase;
 
-	if (*offset != off)	/* Check for EOF before we trust wrap */
-		return 0;
-	
-	/* FIXME: Signed wrap is undefined in C - wants fixing up */
-	if (off + count > off)
-		return 0;
-		
-        if ((off + count) > PCILYNX_MAX_MEMORY + 1) {
-                count = PCILYNX_MAX_MEMORY + 1 - off;
+        if ((off + count) > PCILYNX_MAX_MEMORY+1) {
+                count = PCILYNX_MAX_MEMORY+1 - off;
         }
-        if (count == 0) {
-                return 0;
+        if (count == 0 || off > PCILYNX_MAX_MEMORY) {
+                return -ENOSPC;
         }
 
-
         switch (md->type) {
         case rom:
                 membase = md->lynx->local_rom;
@@ -1015,11 +1090,11 @@
         linkint = reg_read(lynx, LINK_INT_STATUS);
         intmask = reg_read(lynx, PCI_INT_STATUS);
 
+        if (!(intmask & PCI_INT_INT_PEND)) return;
+
         PRINTD(KERN_DEBUG, lynx->id, "interrupt: 0x%08x / 0x%08x", intmask,
                linkint);
 
-        if (!(intmask & PCI_INT_INT_PEND)) return;
-
         reg_write(lynx, LINK_INT_STATUS, linkint);
         reg_write(lynx, PCI_INT_STATUS, intmask);
 
@@ -1118,62 +1193,96 @@
         }
 
         if (intmask & PCI_INT_DMA_HLT(CHANNEL_ASYNC_SEND)) {
-                u32 ack;
-                struct hpsb_packet *packet;
-                
+                PRINTD(KERN_DEBUG, lynx->id, "async sent");
                 spin_lock(&lynx->async.queue_lock);
 
-                ack = reg_read(lynx, DMA_CHAN_STAT(CHANNEL_ASYNC_SEND));
-
-		packet = driver_packet(lynx->async.queue.next);
-		list_del(&packet->driver_list);
-
-                pci_unmap_single(lynx->dev, lynx->async.header_dma,
-                                 packet->header_size, PCI_DMA_TODEVICE);
-                if (packet->data_size) {
-                        pci_unmap_single(lynx->dev, lynx->async.data_dma,
-                                         packet->data_size, PCI_DMA_TODEVICE);
-                }
+                if (list_empty(&lynx->async.pcl_queue)) {
+                        spin_unlock(&lynx->async.queue_lock);
+                        PRINT(KERN_WARNING, lynx->id, "async dma halted, but no queued packet (maybe it was cancelled)");
+                } else {
+                        struct ti_pcl pcl;
+                        u32 ack;
+                        struct hpsb_packet *packet;
+
+                        get_pcl(lynx, lynx->async.pcl, &pcl);
+
+                        packet = driver_packet(lynx->async.pcl_queue.next);
+                        list_del(&packet->driver_list);
+
+                        pci_unmap_single(lynx->dev, lynx->async.header_dma,
+                                         packet->header_size, PCI_DMA_TODEVICE);
+                        if (packet->data_size) {
+                                pci_unmap_single(lynx->dev, lynx->async.data_dma,
+                                                 packet->data_size, PCI_DMA_TODEVICE);
+                        }
 
-                if (!list_empty(&lynx->async.queue)) {
-                        send_next(lynx, hpsb_async);
-                }
+                        if (!list_empty(&lynx->async.queue)) {
+                                send_next(lynx, hpsb_async);
+                        }
 
-                spin_unlock(&lynx->async.queue_lock);
+                        spin_unlock(&lynx->async.queue_lock);
 
-                if (ack & DMA_CHAN_STAT_SPECIALACK) {
-                        ack = (ack >> 15) & 0xf;
-                        PRINTD(KERN_INFO, lynx->id, "special ack %d", ack);
-                        ack = (ack == 1 ? ACKX_TIMEOUT : ACKX_SEND_ERROR);
-                } else {
-                        ack = (ack >> 15) & 0xf;
+                        if (pcl.pcl_status & DMA_CHAN_STAT_PKTCMPL) {
+                                if (pcl.pcl_status & DMA_CHAN_STAT_SPECIALACK) {
+                                        ack = (pcl.pcl_status >> 15) & 0xf;
+                                        PRINTD(KERN_INFO, lynx->id, "special ack %d", ack);
+                                        ack = (ack == 1 ? ACKX_TIMEOUT : ACKX_SEND_ERROR);
+                                } else {
+                                        ack = (pcl.pcl_status >> 15) & 0xf;
+                                }
+                        } else {
+                                PRINT(KERN_INFO, lynx->id, "async packet was not completed");
+                                ack = ACKX_SEND_ERROR;
+                        }
+                        hpsb_packet_sent(host, packet, ack);
                 }
-                
-                hpsb_packet_sent(host, packet, ack);
         }
 
         if (intmask & PCI_INT_DMA_HLT(CHANNEL_ISO_SEND)) {
-                struct hpsb_packet *packet;
-
+                PRINTD(KERN_DEBUG, lynx->id, "iso sent");
                 spin_lock(&lynx->iso_send.queue_lock);
 
-		packet = driver_packet(lynx->iso_send.queue.next);
-		list_del(&packet->driver_list);
+                if (list_empty(&lynx->iso_send.pcl_queue)) {
+                        spin_unlock(&lynx->iso_send.queue_lock);
+                        PRINT(KERN_ERR, lynx->id, "iso send dma halted, but no queued packet");
+                } else {
+                        struct ti_pcl pcl;
+                        u32 ack;
+                        struct hpsb_packet *packet;
+
+                        get_pcl(lynx, lynx->iso_send.pcl, &pcl);
+
+                        packet = driver_packet(lynx->iso_send.pcl_queue.next);
+                        list_del(&packet->driver_list);
+
+                        pci_unmap_single(lynx->dev, lynx->iso_send.header_dma,
+                                         packet->header_size, PCI_DMA_TODEVICE);
+                        if (packet->data_size) {
+                                pci_unmap_single(lynx->dev, lynx->iso_send.data_dma,
+                                                 packet->data_size, PCI_DMA_TODEVICE);
+                        }
 
-                pci_unmap_single(lynx->dev, lynx->iso_send.header_dma,
-                                 packet->header_size, PCI_DMA_TODEVICE);
-                if (packet->data_size) {
-                        pci_unmap_single(lynx->dev, lynx->iso_send.data_dma,
-                                         packet->data_size, PCI_DMA_TODEVICE);
-                }
+                        if (!list_empty(&lynx->iso_send.queue)) {
+                                send_next(lynx, hpsb_iso);
+                        }
 
-                if (!list_empty(&lynx->iso_send.queue)) {
-                        send_next(lynx, hpsb_iso);
-                }
+                        spin_unlock(&lynx->iso_send.queue_lock);
 
-                spin_unlock(&lynx->iso_send.queue_lock);
+                        if (pcl.pcl_status & DMA_CHAN_STAT_PKTCMPL) {
+                                if (pcl.pcl_status & DMA_CHAN_STAT_SPECIALACK) {
+                                        ack = (pcl.pcl_status >> 15) & 0xf;
+                                        PRINTD(KERN_INFO, lynx->id, "special ack %d", ack);
+                                        ack = (ack == 1 ? ACKX_TIMEOUT : ACKX_SEND_ERROR);
+                                } else {
+                                        ack = (pcl.pcl_status >> 15) & 0xf;
+                                }
+                        } else {
+                                PRINT(KERN_INFO, lynx->id, "iso send packet was not completed");
+                                ack = ACKX_SEND_ERROR;
+                        }
 
-                hpsb_packet_sent(host, packet, ACK_COMPLETE);
+                        hpsb_packet_sent(host, packet, ack); //FIXME: maybe we should just use ACK_COMPLETE and ACKX_SEND_ERROR
+                }
         }
 
         if (intmask & PCI_INT_DMA_HLT(CHANNEL_ASYNC_RCV)) {
@@ -1475,7 +1584,9 @@
         lynx->phy_reg0 = -1;
 
 	INIT_LIST_HEAD(&lynx->async.queue);
+	INIT_LIST_HEAD(&lynx->async.pcl_queue);
 	INIT_LIST_HEAD(&lynx->iso_send.queue);
+	INIT_LIST_HEAD(&lynx->iso_send.pcl_queue);
 
         pcl.next = pcl_bus(lynx, lynx->rcv_pcl);
         put_pcl(lynx, lynx->rcv_pcl_start, &pcl);
@@ -1677,7 +1788,7 @@
 
 
 
-static size_t get_lynx_rom(struct hpsb_host *host, const quadlet_t **ptr)
+static size_t get_lynx_rom(struct hpsb_host *host, quadlet_t **ptr)
 {
         struct ti_lynx *lynx = host->hostdata;
         *ptr = lynx->config_rom;
@@ -1698,7 +1809,7 @@
         .name =     PCILYNX_DRIVER_NAME,
         .id_table = pci_table,
         .probe =    add_card,
-        .remove =   __devexit_p(remove_card),
+        .remove =   remove_card,
 };
 
 static struct hpsb_host_driver lynx_driver = {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/pcilynx.h linux-2.4.21-pre6/drivers/ieee1394/pcilynx.h
--- linux-2.4.20/drivers/ieee1394/pcilynx.h	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ieee1394/pcilynx.h	2003-03-26 23:48:58.000000000 +0000
@@ -95,6 +95,7 @@
         struct lynx_send_data {
                 pcl_t pcl_start, pcl;
                 struct list_head queue;
+                struct list_head pcl_queue; /* this queue contains at most one packet */
                 spinlock_t queue_lock;
                 dma_addr_t header_dma, data_dma;
                 int channel;
@@ -514,13 +515,13 @@
 
 static quadlet_t lynx_csr_rom[] = {
 /* bus info block     offset (hex) */
-        _(0x04040000), /* info/CRC length, CRC              400  */
+        _(0x04046aaf), /* info/CRC length, CRC              400  */
         _(0x31333934), /* 1394 magic number                 404  */
         _(0xf064a000), /* misc. settings                    408  */
         _(0x08002850), /* vendor ID, chip ID high           40c  */
         _(0x0000ffff), /* chip ID low                       410  */
 /* root directory */
-        _(0x00090000), /* directory length, CRC             414  */
+        _(0x00095778), /* directory length, CRC             414  */
         _(0x03080028), /* vendor ID (Texas Instr.)          418  */
         _(0x81000008), /* offset to textual ID              41c  */
         _(0x0c000200), /* node capabilities                 420  */
@@ -530,8 +531,8 @@
         _(0x81000014), /* offset to textual ID              430  */
         _(0x09000000), /* node hardware version             434  */
         _(0x81000018), /* offset to textual ID              438  */
-  /* module vendor ID textual */
-        _(0x00070000), /* CRC length, CRC                   43c  */
+/* module vendor ID textual */
+        _(0x00070812), /* CRC length, CRC                   43c  */
         _(0x00000000), /*                                   440  */
         _(0x00000000), /*                                   444  */
         _(0x54455841), /* "Texas Instruments"               448  */
@@ -540,25 +541,25 @@
         _(0x4d454e54), /*                                   454  */
         _(0x53000000), /*                                   458  */
 /* node unique ID leaf */
-        _(0x00020000), /* CRC length, CRC                   45c  */
+        _(0x00022ead), /* CRC length, CRC                   45c  */
         _(0x08002850), /* vendor ID, chip ID high           460  */
         _(0x0000ffff), /* chip ID low                       464  */
 /* module dependent info */
-        _(0x00050000), /* CRC length, CRC                   468  */
+        _(0x0005d837), /* CRC length, CRC                   468  */
         _(0x81000012), /* offset to module textual ID       46c  */
         _(0x81000017), /* textual descriptor                470  */
         _(0x39010000), /* SRAM size                         474  */
         _(0x3a010000), /* AUXRAM size                       478  */
         _(0x3b000000), /* AUX device                        47c  */
 /* module textual ID */
-        _(0x00050000), /* CRC length, CRC                   480  */
+        _(0x000594df), /* CRC length, CRC                   480  */
         _(0x00000000), /*                                   484  */
         _(0x00000000), /*                                   488  */
         _(0x54534231), /* "TSB12LV21"                       48c  */
         _(0x324c5632), /*                                   490  */
         _(0x31000000), /*                                   494  */
 /* part number */
-        _(0x00060000), /* CRC length, CRC                   498  */
+        _(0x00068405), /* CRC length, CRC                   498  */
         _(0x00000000), /*                                   49c  */
         _(0x00000000), /*                                   4a0  */
         _(0x39383036), /* "9806000-0001"                    4a4  */
@@ -566,14 +567,14 @@
         _(0x30303031), /*                                   4ac  */
         _(0x20000001), /*                                   4b0  */
 /* module hardware version textual */
-        _(0x00050000), /* CRC length, CRC                   4b4  */
+        _(0x00056501), /* CRC length, CRC                   4b4  */
         _(0x00000000), /*                                   4b8  */
         _(0x00000000), /*                                   4bc  */
         _(0x5453424b), /* "TSBKPCITST"                      4c0  */
         _(0x50434954), /*                                   4c4  */
         _(0x53540000), /*                                   4c8  */
 /* node hardware version textual */
-        _(0x00050000), /* CRC length, CRC                   4d0  */
+        _(0x0005d805), /* CRC length, CRC                   4d0  */
         _(0x00000000), /*                                   4d4  */
         _(0x00000000), /*                                   4d8  */
         _(0x54534232), /* "TSB21LV03"                       4dc  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/raw1394-private.h linux-2.4.21-pre6/drivers/ieee1394/raw1394-private.h
--- linux-2.4.20/drivers/ieee1394/raw1394-private.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ieee1394/raw1394-private.h	2003-03-26 23:49:30.000000000 +0000
@@ -0,0 +1,79 @@
+#ifndef IEEE1394_RAW1394_PRIVATE_H
+#define IEEE1394_RAW1394_PRIVATE_H
+
+/* header for definitions that are private to the raw1394 driver
+   and not visible to user-space */
+
+#define RAW1394_DEVICE_MAJOR      171
+#define RAW1394_DEVICE_NAME       "raw1394"
+
+struct iso_block_store {
+        atomic_t refcount;
+        size_t data_size;
+        quadlet_t data[0];
+};
+
+enum raw1394_iso_state { RAW1394_ISO_INACTIVE = 0,
+			 RAW1394_ISO_RECV = 1,
+			 RAW1394_ISO_XMIT = 2 };
+
+struct file_info {
+        struct list_head list;
+
+        enum { opened, initialized, connected } state;
+        unsigned int protocol_version;
+
+        struct hpsb_host *host;
+
+        struct list_head req_pending;
+        struct list_head req_complete;
+        struct semaphore complete_sem;
+        spinlock_t reqlists_lock;
+        wait_queue_head_t poll_wait_complete;
+
+        struct list_head addr_list;           
+
+        u8 *fcp_buffer;
+
+	/* old ISO API */
+        u64 listen_channels;
+        quadlet_t *iso_buffer;
+        size_t iso_buffer_length;
+
+        u8 notification; /* (busreset-notification) RAW1394_NOTIFY_OFF/ON */
+
+	/* new rawiso API */
+	enum raw1394_iso_state iso_state;
+	struct hpsb_iso *iso_handle;
+};
+
+struct arm_addr {
+        struct list_head addr_list; /* file_info list */
+        u64    start, end;
+        u64    arm_tag;
+        u8     access_rights;
+        u8     notification_options;
+        u8     client_transactions;
+        u64    recvb;
+        u16    rec_length;
+        u8     *addr_space_buffer; /* accessed by read/write/lock */
+};
+
+struct pending_request {
+        struct list_head list;
+        struct file_info *file_info;
+        struct hpsb_packet *packet;
+	struct tq_struct tq;
+        struct iso_block_store *ibs;
+        quadlet_t *data;
+        int free_data;
+        struct raw1394_request req;
+};
+
+struct host_info {
+        struct list_head list;
+        struct hpsb_host *host;
+        struct list_head file_info_list;
+};
+
+#endif  /* IEEE1394_RAW1394_PRIVATE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/raw1394.c linux-2.4.21-pre6/drivers/ieee1394/raw1394.c
--- linux-2.4.20/drivers/ieee1394/raw1394.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ieee1394/raw1394.c	2003-03-26 23:48:58.000000000 +0000
@@ -4,9 +4,27 @@
  * Raw interface to the bus
  *
  * Copyright (C) 1999, 2000 Andreas E. Bombe
+ *               2001, 2002 Manfred Weihs <weihs@ict.tuwien.ac.at>
+ *                     2002 Christian Toegel <christian.toegel@gmx.at>
  *
  * This code is licensed under the GPL.  See the file COPYING in the root
  * directory of the kernel sources for details.
+ *
+ *
+ * Contributions:
+ *
+ * Manfred Weihs <weihs@ict.tuwien.ac.at>
+ *        configuration ROM manipulation
+ *        address range mapping
+ *        adaptation for new (transparent) loopback mechanism
+ *        sending of arbitrary async packets
+ * Christian Toegel <christian.toegel@gmx.at>
+ *        address range mapping
+ *        lock64 request
+ *        transmit physical packet
+ *        busreset notification control (switch on/off)
+ *        busreset with selection of type (short/long)
+ *        request_reply
  */
 
 #include <linux/kernel.h>
@@ -28,9 +46,10 @@
 #include "ieee1394_core.h"
 #include "hosts.h"
 #include "highlevel.h"
+#include "iso.h"
 #include "ieee1394_transactions.h"
 #include "raw1394.h"
-
+#include "raw1394-private.h"
 
 #if BITS_PER_LONG == 64
 #define int2ptr(x) ((void *)x)
@@ -40,6 +59,16 @@
 #define ptr2int(x) ((u64)(u32)x)
 #endif
 
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+#define RAW1394_DEBUG
+#endif
+
+#ifdef RAW1394_DEBUG
+#define DBGMSG(fmt, args...) \
+printk(KERN_INFO "raw1394:" fmt "\n" , ## args)
+#else
+#define DBGMSG(fmt, args...)
+#endif
 
 static devfs_handle_t devfs_handle;
 
@@ -53,6 +82,21 @@
 static atomic_t iso_buffer_size;
 static const int iso_buffer_max = 4 * 1024 * 1024; /* 4 MB */
 
+static int arm_read (struct hpsb_host *host, int nodeid, quadlet_t *buffer,
+             u64 addr, unsigned int length, u16 flags);
+static int arm_write (struct hpsb_host *host, int nodeid, int destid,
+              quadlet_t *data, u64 addr, unsigned int length, u16 flags);
+static int arm_lock (struct hpsb_host *host, int nodeid, quadlet_t *store,
+             u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags);
+static int arm_lock64 (struct hpsb_host *host, int nodeid, octlet_t *store,
+               u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags);
+static struct hpsb_address_ops arm_ops = {
+	.read	= arm_read,
+	.write	= arm_write,
+	.lock	= arm_lock,
+	.lock64	= arm_lock64,
+};
+
 static void queue_complete_cb(struct pending_request *req);
 
 static struct pending_request *__alloc_pending_request(int flags)
@@ -64,7 +108,7 @@
         if (req != NULL) {
                 memset(req, 0, sizeof(struct pending_request));
                 INIT_LIST_HEAD(&req->list);
-		INIT_TQUEUE(&req->tq, (void(*)(void*))queue_complete_cb, NULL);
+                INIT_TQUEUE(&req->tq, (void(*)(void*))queue_complete_cb, NULL);
         }
 
         return req;
@@ -89,18 +133,25 @@
         kfree(req);
 }
 
+/* fi->reqlists_lock must be taken */
+static void __queue_complete_req(struct pending_request *req)
+{
+	struct file_info *fi = req->file_info;
+	list_del(&req->list);
+        list_add_tail(&req->list, &fi->req_complete);
+
+	up(&fi->complete_sem);
+        wake_up_interruptible(&fi->poll_wait_complete);
+}
+
 static void queue_complete_req(struct pending_request *req)
 {
         unsigned long flags;
         struct file_info *fi = req->file_info;
 
         spin_lock_irqsave(&fi->reqlists_lock, flags);
-        list_del(&req->list);
-        list_add_tail(&req->list, &fi->req_complete);
+	__queue_complete_req(req);
         spin_unlock_irqrestore(&fi->reqlists_lock, flags);
-
-        up(&fi->complete_sem);
-        wake_up_interruptible(&fi->poll_wait_complete);
 }
 
 static void queue_complete_cb(struct pending_request *req)
@@ -128,7 +179,11 @@
                 req->req.length = 0;
         }
 
-        free_tlabel(packet->host, packet->node_id, packet->tlabel);
+	if ((req->req.type == RAW1394_REQ_ASYNC_READ) ||
+	    (req->req.type == RAW1394_REQ_ASYNC_WRITE) ||
+	    (req->req.type == RAW1394_REQ_LOCK) ||
+	    (req->req.type == RAW1394_REQ_LOCK64))
+                free_tlabel(packet->host, packet->node_id, packet->tlabel);
 
         queue_complete_req(req);
 }
@@ -137,6 +192,7 @@
 static void add_host(struct hpsb_host *host)
 {
         struct host_info *hi;
+        unsigned long flags;
 
         hi = (struct host_info *)kmalloc(sizeof(struct host_info), SLAB_KERNEL);
         if (hi != NULL) {
@@ -144,10 +200,10 @@
                 hi->host = host;
                 INIT_LIST_HEAD(&hi->file_info_list);
 
-                spin_lock_irq(&host_info_lock);
+                spin_lock_irqsave(&host_info_lock, flags);
                 list_add_tail(&hi->list, &host_info_list);
                 host_count++;
-                spin_unlock_irq(&host_info_lock);
+                spin_unlock_irqrestore(&host_info_lock, flags);
         }
 
         atomic_inc(&internal_generation);
@@ -172,15 +228,22 @@
 static void remove_host(struct hpsb_host *host)
 {
         struct host_info *hi;
+        unsigned long flags;
 
-        spin_lock_irq(&host_info_lock);
+        spin_lock_irqsave(&host_info_lock, flags);
         hi = find_host_info(host);
 
         if (hi != NULL) {
                 list_del(&hi->list);
                 host_count--;
+                /* 
+                   FIXME: adressranges should be removed 
+                   and fileinfo states should be initialized
+                   (including setting generation to 
+                   internal-generation ...)
+                */
         }
-        spin_unlock_irq(&host_info_lock);
+        spin_unlock_irqrestore(&host_info_lock, flags);
 
         if (hi == NULL) {
                 printk(KERN_ERR "raw1394: attempt to remove unknown host "
@@ -207,20 +270,22 @@
         if (hi != NULL) {
                 list_for_each(lh, &hi->file_info_list) {
                         fi = list_entry(lh, struct file_info, list);
-                        req = __alloc_pending_request(SLAB_ATOMIC);
+                        if (fi->notification == RAW1394_NOTIFY_ON) {
+                                req = __alloc_pending_request(SLAB_ATOMIC);
 
-                        if (req != NULL) {
-                                req->file_info = fi;
-                                req->req.type = RAW1394_REQ_BUS_RESET;
-                                req->req.generation = get_hpsb_generation(host);
-                                req->req.misc = (host->node_id << 16)
-                                        | host->node_count;
-                                if (fi->protocol_version > 3) {
-                                        req->req.misc |= ((host->irm_id
-                                                           & NODE_MASK) << 8);
-                                }
+                                if (req != NULL) {
+                                        req->file_info = fi;
+                                        req->req.type = RAW1394_REQ_BUS_RESET;
+                                        req->req.generation = get_hpsb_generation(host);
+                                        req->req.misc = (host->node_id << 16)
+                                                | host->node_count;
+                                        if (fi->protocol_version > 3) {
+                                                req->req.misc |= ((host->irm_id
+                                                                   & NODE_MASK) << 8);
+                                        }
 
-                                queue_complete_req(req);
+                                        queue_complete_req(req);
+                                }
                         }
                 }
         }
@@ -529,7 +594,7 @@
 {
         int channel = req->req.misc;
 
-        spin_lock(&host_info_lock);
+        spin_lock_irq(&host_info_lock);
         if ((channel > 63) || (channel < -64)) {
                 req->req.error = RAW1394_ERROR_INVALID_ARG;
         } else if (channel >= 0) {
@@ -556,7 +621,7 @@
 
         req->req.length = 0;
         queue_complete_req(req);
-        spin_unlock(&host_info_lock);
+        spin_unlock_irq(&host_info_lock);
 }
 
 static void handle_fcp_listen(struct file_info *fi, struct pending_request *req)
@@ -579,84 +644,9 @@
         queue_complete_req(req);
 }
 
-static int handle_local_request(struct file_info *fi,
-                                struct pending_request *req, int node)
-{
-        u64 addr = req->req.address & 0xffffffffffffULL;
-
-        req->data = kmalloc(req->req.length, SLAB_KERNEL);
-        if (!req->data) return -ENOMEM;
-        req->free_data = 1;
-
-        switch (req->req.type) {
-        case RAW1394_REQ_ASYNC_READ:
-                req->req.error = highlevel_read(fi->host, node, req->data, addr,
-                                                req->req.length);
-                break;
-
-        case RAW1394_REQ_ASYNC_WRITE:
-                if (copy_from_user(req->data, int2ptr(req->req.sendb),
-                                   req->req.length)) {
-                        req->req.error = RAW1394_ERROR_MEMFAULT;
-                        break;
-                }
-
-                req->req.error = highlevel_write(fi->host, node, node, req->data,
-                                                 addr, req->req.length);
-                req->req.length = 0;
-                break;
 
-        case RAW1394_REQ_LOCK:
-                if ((req->req.misc == EXTCODE_FETCH_ADD)
-                    || (req->req.misc == EXTCODE_LITTLE_ADD)) {
-                        if (req->req.length != 4) {
-                                req->req.error = RAW1394_ERROR_INVALID_ARG;
-                                break;
-                        }
-                } else {
-                        if (req->req.length != 8) {
-                                req->req.error = RAW1394_ERROR_INVALID_ARG;
-                                break;
-                        }
-                }
-
-                if (copy_from_user(req->data, int2ptr(req->req.sendb),
-                                   req->req.length)) {
-                        req->req.error = RAW1394_ERROR_MEMFAULT;
-                        break;
-                }
-
-                if (req->req.length == 8) {
-                        req->req.error = highlevel_lock(fi->host, node,
-                                                        req->data, addr,
-                                                        req->data[1],
-                                                        req->data[0],
-                                                        req->req.misc);
-                        req->req.length = 4;
-                } else {
-                        req->req.error = highlevel_lock(fi->host, node,
-                                                        req->data, addr,
-                                                        req->data[0], 0,
-                                                        req->req.misc);
-                }
-                break;
-
-        case RAW1394_REQ_LOCK64:
-        default:
-                req->req.error = RAW1394_ERROR_STATE_ORDER;
-        }
-
-        if (req->req.error)
-                req->req.length = 0;
-        if (req->req.error >= 0)
-                req->req.error |= ACK_PENDING << 16;
-
-        queue_complete_req(req);
-        return sizeof(struct raw1394_request);
-}
-
-static int handle_remote_request(struct file_info *fi,
-                                 struct pending_request *req, int node)
+static int handle_async_request(struct file_info *fi,
+                                struct pending_request *req, int node)
 {
         struct hpsb_packet *packet = NULL;
         u64 addr = req->req.address & 0xffffffffffffULL;
@@ -664,11 +654,13 @@
         switch (req->req.type) {
         case RAW1394_REQ_ASYNC_READ:
                 if (req->req.length == 4) {
+                        DBGMSG("quadlet_read_request called");        
                         packet = hpsb_make_readqpacket(fi->host, node, addr);
                         if (!packet) return -ENOMEM;
 
                         req->data = &packet->header[3];
                 } else {
+                        DBGMSG("block_read_request called");
                         packet = hpsb_make_readbpacket(fi->host, node, addr,
                                                        req->req.length);
                         if (!packet) return -ENOMEM;
@@ -681,6 +673,7 @@
                 if (req->req.length == 4) {
                         quadlet_t x;
 
+                        DBGMSG("quadlet_write_request called");
                         if (copy_from_user(&x, int2ptr(req->req.sendb), 4)) {
                                 req->req.error = RAW1394_ERROR_MEMFAULT;
                         }
@@ -689,6 +682,7 @@
                                                         x);
                         if (!packet) return -ENOMEM;
                 } else {
+                        DBGMSG("block_write_request called");
                         packet = hpsb_make_writebpacket(fi->host, node, addr,
                                                         req->req.length);
                         if (!packet) return -ENOMEM;
@@ -702,6 +696,7 @@
                 break;
 
         case RAW1394_REQ_LOCK:
+                DBGMSG("lock_request called");
                 if ((req->req.misc == EXTCODE_FETCH_ADD)
                     || (req->req.misc == EXTCODE_LITTLE_ADD)) {
                         if (req->req.length != 4) {
@@ -730,6 +725,33 @@
                 break;
 
         case RAW1394_REQ_LOCK64:
+                DBGMSG("lock64_request called");
+                if ((req->req.misc == EXTCODE_FETCH_ADD)
+                    || (req->req.misc == EXTCODE_LITTLE_ADD)) {
+                        if (req->req.length != 8) {
+                                req->req.error = RAW1394_ERROR_INVALID_ARG;
+                                break;
+                        }
+                } else {
+                        if (req->req.length != 16) {
+                                req->req.error = RAW1394_ERROR_INVALID_ARG;
+                                break;
+                        }
+                }
+                packet = hpsb_make_lock64packet(fi->host, node, addr,
+                                                req->req.misc);
+                if (!packet) return -ENOMEM;
+
+                if (copy_from_user(packet->data, int2ptr(req->req.sendb),
+                                   req->req.length)) {
+                        req->req.error = RAW1394_ERROR_MEMFAULT;
+                        break;
+                }
+
+                req->data = packet->data;
+                req->req.length = 8;
+                break;
+
         default:
                 req->req.error = RAW1394_ERROR_STATE_ORDER;
         }
@@ -783,8 +805,7 @@
                 return sizeof(struct raw1394_request);
         }
 
-        req->tq.data = req;
-        req->tq.routine = (void (*)(void*))queue_complete_req;
+	PREPARE_TQUEUE(&req->tq, (void (*)(void*))queue_complete_req, req);
         req->req.length = 0;
 	hpsb_add_packet_complete_task(packet, &req->tq);
 
@@ -803,25 +824,1092 @@
         return sizeof(struct raw1394_request);
 }
 
-static int state_connected(struct file_info *fi, struct pending_request *req)
+static int handle_async_send(struct file_info *fi, struct pending_request *req)
 {
-        int node = req->req.address >> 48;
+        struct hpsb_packet *packet;
+        int header_length = req->req.misc & 0xffff;
+        int expect_response = req->req.misc >> 16;
 
-        req->req.error = RAW1394_ERROR_NONE;
+        if ((header_length > req->req.length) ||
+            (header_length  < 12))
+        {
+                req->req.error = RAW1394_ERROR_INVALID_ARG;
+                req->req.length = 0;
+                queue_complete_req(req);
+                return sizeof(struct raw1394_request);
+        } 
 
-        if (req->req.type ==  RAW1394_REQ_ISO_SEND) {
-                return handle_iso_send(fi, req, node);
+        packet = alloc_hpsb_packet(req->req.length-header_length);
+        req->packet = packet;
+        if (!packet) return -ENOMEM;
+
+        if (copy_from_user(packet->header, int2ptr(req->req.sendb),
+                           header_length)) {
+                req->req.error = RAW1394_ERROR_MEMFAULT;
+                req->req.length = 0;
+                queue_complete_req(req);
+                return sizeof(struct raw1394_request);
         }
 
-        if (req->req.generation != get_hpsb_generation(fi->host)) {
-                req->req.error = RAW1394_ERROR_GENERATION;
-                req->req.generation = get_hpsb_generation(fi->host);
+        if (copy_from_user(packet->data, ((u8*) int2ptr(req->req.sendb)) + header_length,
+                           packet->data_size)) {
+                req->req.error = RAW1394_ERROR_MEMFAULT;
                 req->req.length = 0;
                 queue_complete_req(req);
                 return sizeof(struct raw1394_request);
         }
 
+        packet->type = hpsb_async;
+        packet->node_id = packet->header[0] >> 16;
+        packet->tcode = (packet->header[0] >> 4) & 0xf;
+        packet->tlabel = (packet->header[0] >> 10) &0x3f;
+        packet->host = fi->host;
+        packet->expect_response = expect_response;
+        packet->header_size=header_length;
+        packet->data_size=req->req.length-header_length;
+
+	PREPARE_TQUEUE(&req->tq, (void (*)(void*))queue_complete_req, req);
+        req->req.length = 0;
+        hpsb_add_packet_complete_task(packet, &req->tq);
+
+        spin_lock_irq(&fi->reqlists_lock);
+        list_add_tail(&req->list, &fi->req_pending);
+        spin_unlock_irq(&fi->reqlists_lock);
+
+        /* Update the generation of the packet just before sending. */
+        packet->generation = get_hpsb_generation(fi->host);
+
+        if (!hpsb_send_packet(packet)) {
+                req->req.error = RAW1394_ERROR_SEND_ERROR;
+                queue_complete_req(req);
+        }
+
+        return sizeof(struct raw1394_request);
+}
+
+static int arm_read (struct hpsb_host *host, int nodeid, quadlet_t *buffer,
+             u64 addr, unsigned int length, u16 flags)
+{
+        struct pending_request *req;
+        struct list_head *lh;
+        struct host_info *hi;
+        struct file_info *fi = NULL;
+        struct list_head *entry;
+        struct arm_addr  *arm_addr = NULL;
+        struct arm_request  *arm_req = NULL;
+        struct arm_response *arm_resp = NULL;
+        int found=0, size=0, rcode=-1;
+        struct arm_request_response *arm_req_resp = NULL;
+
+        DBGMSG("arm_read  called by node: %X"
+              "addr: %4.4x %8.8x length: %u", nodeid,
+              (u16) ((addr >>32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF),
+              length);
+        spin_lock(&host_info_lock);
+        hi = find_host_info(host); /* search address-entry */
+        if (hi != NULL) {
+                list_for_each(lh, &hi->file_info_list) {
+                        fi = list_entry(lh, struct file_info, list);
+                        entry = fi->addr_list.next;
+                        while (entry != &(fi->addr_list)) {
+                                arm_addr = list_entry(entry, struct arm_addr, addr_list);
+                                if (((arm_addr->start) <= (addr)) && 
+                                        ((arm_addr->end) >= (addr+length))) {
+                                        found = 1;
+                                        break;
+                                }
+                                entry = entry->next;
+                        }
+                        if (found) {
+                                break;
+                        }
+                }
+        }
+        rcode = -1;
+        if (!found) {
+                printk(KERN_ERR "raw1394: arm_read FAILED addr_entry not found"
+                " -> rcode_address_error\n");
+                spin_unlock(&host_info_lock);
+                return (RCODE_ADDRESS_ERROR);
+        } else {
+                DBGMSG("arm_read addr_entry FOUND");
+        }
+        if (arm_addr->rec_length < length) {
+                DBGMSG("arm_read blocklength too big -> rcode_data_error");
+                rcode = RCODE_DATA_ERROR; /* hardware error, data is unavailable */
+        }
+        if (rcode == -1) {
+                if (arm_addr->access_rights & ARM_READ) {
+                        if (!(arm_addr->client_transactions & ARM_READ)) {
+                                memcpy(buffer,(arm_addr->addr_space_buffer)+(addr-(arm_addr->start)), 
+                                       length);
+                                DBGMSG("arm_read -> (rcode_complete)");
+                                rcode = RCODE_COMPLETE;
+                        }
+                } else {
+                        rcode = RCODE_TYPE_ERROR; /* function not allowed */
+                        DBGMSG("arm_read -> rcode_type_error (access denied)");
+                }
+        }
+        if (arm_addr->notification_options & ARM_READ) {
+                DBGMSG("arm_read -> entering notification-section");
+                req = __alloc_pending_request(SLAB_ATOMIC);
+                if (!req) {
+                        DBGMSG("arm_read -> rcode_conflict_error");
+                        spin_unlock(&host_info_lock);
+                        return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. 
+                                                        The request may be retried */
+                }
+                if (rcode == RCODE_COMPLETE) {
+                        size =  sizeof(struct arm_request)+sizeof(struct arm_response) +
+                                length * sizeof(byte_t) +
+                                sizeof (struct arm_request_response);
+                } else {
+                        size =  sizeof(struct arm_request)+sizeof(struct arm_response) +
+                                sizeof (struct arm_request_response);
+                }
+                req->data = kmalloc(size, SLAB_ATOMIC);
+                if (!(req->data)) {
+                        free_pending_request(req);
+                        DBGMSG("arm_read -> rcode_conflict_error");
+                        spin_unlock(&host_info_lock);
+                        return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. 
+                                                        The request may be retried */
+                }
+                req->free_data=1;
+                req->file_info = fi;
+                req->req.type = RAW1394_REQ_ARM;
+                req->req.generation = get_hpsb_generation(host);
+                req->req.misc = ( ((length << 16) & (0xFFFF0000)) | (ARM_READ & 0xFF));
+                req->req.tag  = arm_addr->arm_tag;
+                req->req.recvb = arm_addr->recvb;
+                req->req.length = size;
+                arm_req_resp = (struct arm_request_response *) (req->data);
+                arm_req  = (struct arm_request *) ((byte_t *)(req->data) + 
+                        (sizeof (struct arm_request_response)));
+                arm_resp = (struct arm_response *) ((byte_t *)(arm_req) + 
+                        (sizeof(struct arm_request)));
+                arm_req->buffer  = NULL;
+                arm_resp->buffer = NULL;
+                if (rcode == RCODE_COMPLETE) {
+                        arm_resp->buffer = ((byte_t *)(arm_resp) + 
+                                (sizeof(struct arm_response)));
+                        memcpy (arm_resp->buffer,
+                                (arm_addr->addr_space_buffer)+(addr-(arm_addr->start)), 
+                                length);
+                        arm_resp->buffer = int2ptr((arm_addr->recvb) + 
+                                sizeof (struct arm_request_response) +
+                                sizeof (struct arm_request) +
+                                sizeof (struct arm_response));
+                }
+                arm_resp->buffer_length = (rcode == RCODE_COMPLETE) ? length : 0;
+                arm_resp->response_code = rcode;
+                arm_req->buffer_length = 0;
+                arm_req->generation = req->req.generation;
+                arm_req->extended_transaction_code = 0;
+                arm_req->destination_offset = addr;
+                arm_req->source_nodeid = nodeid;
+                arm_req->destination_nodeid = host->node_id;
+                arm_req->tlabel = (flags >> 10) & 0x3f;
+                arm_req->tcode = (flags >> 4) & 0x0f;
+                arm_req_resp->request  = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response));
+                arm_req_resp->response = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response) +
+                        sizeof (struct arm_request));
+                queue_complete_req(req);
+        }
+        spin_unlock(&host_info_lock);
+        return(rcode);
+}
+
+static int arm_write (struct hpsb_host *host, int nodeid, int destid,
+              quadlet_t *data, u64 addr, unsigned int length, u16 flags)
+{
+        struct pending_request *req;
+        struct list_head *lh;
+        struct host_info *hi;
+        struct file_info *fi = NULL;
+        struct list_head *entry;
+        struct arm_addr  *arm_addr = NULL;
+        struct arm_request  *arm_req = NULL;
+        struct arm_response *arm_resp = NULL;        
+        int found=0, size=0, rcode=-1, length_conflict=0;
+        struct arm_request_response *arm_req_resp = NULL;
+
+        DBGMSG("arm_write called by node: %X"
+              "addr: %4.4x %8.8x length: %u", nodeid,
+              (u16) ((addr >>32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF),
+              length);
+        spin_lock(&host_info_lock);
+        hi = find_host_info(host); /* search address-entry */
+        if (hi != NULL) {
+                list_for_each(lh, &hi->file_info_list) {
+                        fi = list_entry(lh, struct file_info, list);
+                        entry = fi->addr_list.next;
+                        while (entry != &(fi->addr_list)) {
+                                arm_addr = list_entry(entry, struct arm_addr, addr_list);
+                                if (((arm_addr->start) <= (addr)) && 
+                                        ((arm_addr->end) >= (addr+length))) {
+                                        found = 1;
+                                        break;
+                                }
+                                entry = entry->next;
+                        }
+                        if (found) {
+                                break;
+                        }
+                }
+        }
+        rcode = -1;
+        if (!found) {
+                printk(KERN_ERR "raw1394: arm_write FAILED addr_entry not found"
+                " -> rcode_address_error\n");
+                spin_unlock(&host_info_lock);
+                return (RCODE_ADDRESS_ERROR);
+        } else {
+                DBGMSG("arm_write addr_entry FOUND");
+        }
+        if (arm_addr->rec_length < length) {
+                DBGMSG("arm_write blocklength too big -> rcode_data_error");
+                length_conflict = 1;
+                rcode = RCODE_DATA_ERROR; /* hardware error, data is unavailable */
+        }
+        if (rcode == -1) {
+                if (arm_addr->access_rights & ARM_WRITE) {
+                        if (!(arm_addr->client_transactions & ARM_WRITE)) {
+                                memcpy((arm_addr->addr_space_buffer)+(addr-(arm_addr->start)),
+                                        data, length);
+                                DBGMSG("arm_write -> (rcode_complete)");
+                                rcode = RCODE_COMPLETE;
+                        }
+                } else {
+                        rcode = RCODE_TYPE_ERROR; /* function not allowed */
+                        DBGMSG("arm_write -> rcode_type_error (access denied)");
+                }
+        }
+        if (arm_addr->notification_options & ARM_WRITE) {
+                DBGMSG("arm_write -> entering notification-section");
+                req = __alloc_pending_request(SLAB_ATOMIC);
+                if (!req) {
+                        DBGMSG("arm_write -> rcode_conflict_error");
+                        spin_unlock(&host_info_lock);
+                        return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. 
+                                                        The request my be retried */
+                }
+                size =  sizeof(struct arm_request)+sizeof(struct arm_response) +
+                        (length) * sizeof(byte_t) +
+                        sizeof (struct arm_request_response);
+                req->data = kmalloc(size, SLAB_ATOMIC);
+                if (!(req->data)) {
+                        free_pending_request(req);
+                        DBGMSG("arm_write -> rcode_conflict_error");
+                        spin_unlock(&host_info_lock);
+                        return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. 
+                                                        The request may be retried */
+                }
+                req->free_data=1;
+                req->file_info = fi;
+                req->req.type = RAW1394_REQ_ARM;
+                req->req.generation = get_hpsb_generation(host);
+                req->req.misc = ( ((length << 16) & (0xFFFF0000)) | (ARM_WRITE & 0xFF));
+                req->req.tag  = arm_addr->arm_tag;
+                req->req.recvb = arm_addr->recvb;
+                req->req.length = size;
+                arm_req_resp = (struct arm_request_response *) (req->data);
+                arm_req  = (struct arm_request *) ((byte_t *)(req->data) + 
+                        (sizeof (struct arm_request_response)));
+                arm_resp = (struct arm_response *) ((byte_t *)(arm_req) + 
+                        (sizeof(struct arm_request)));
+                arm_req->buffer = ((byte_t *)(arm_resp) + 
+                        (sizeof(struct arm_response)));
+                arm_resp->buffer = NULL;
+                memcpy (arm_req->buffer, data, length);
+                arm_req->buffer = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response) +
+                        sizeof (struct arm_request) +
+                        sizeof (struct arm_response));
+                arm_req->buffer_length = length;
+                arm_req->generation = req->req.generation;
+                arm_req->extended_transaction_code = 0;
+                arm_req->destination_offset = addr;
+                arm_req->source_nodeid = nodeid;
+                arm_req->destination_nodeid = destid;
+                arm_req->tlabel = (flags >> 10) & 0x3f;
+                arm_req->tcode = (flags >> 4) & 0x0f;
+                arm_resp->buffer_length = 0;
+                arm_resp->response_code = rcode;
+                arm_req_resp->request  = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response));
+                arm_req_resp->response = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response) +
+                        sizeof (struct arm_request));
+                queue_complete_req(req);
+        }
+        spin_unlock(&host_info_lock);
+        return(rcode);
+}
+
+static int arm_lock (struct hpsb_host *host, int nodeid, quadlet_t *store,
+             u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags)
+{
+        struct pending_request *req;
+        struct list_head *lh;
+        struct host_info *hi;
+        struct file_info *fi = NULL;
+        struct list_head *entry;
+        struct arm_addr  *arm_addr = NULL;
+        struct arm_request  *arm_req = NULL;
+        struct arm_response *arm_resp = NULL;        
+        int found=0, size=0, rcode=-1;
+        quadlet_t old, new;
+        struct arm_request_response *arm_req_resp = NULL;
+
+        if (((ext_tcode & 0xFF) == EXTCODE_FETCH_ADD) ||
+                ((ext_tcode & 0xFF) == EXTCODE_LITTLE_ADD)) {
+                DBGMSG("arm_lock  called by node: %X "
+                      "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X", 
+                      nodeid, (u16) ((addr >>32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF),
+                      ext_tcode & 0xFF , be32_to_cpu(data));
+        } else {
+                DBGMSG("arm_lock  called by node: %X "
+                      "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X arg: %8.8X", 
+                      nodeid, (u16) ((addr >>32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF),
+                      ext_tcode & 0xFF , be32_to_cpu(data), be32_to_cpu(arg));
+        }
+        spin_lock(&host_info_lock);
+        hi = find_host_info(host); /* search address-entry */
+        if (hi != NULL) {
+                list_for_each(lh, &hi->file_info_list) {
+                        fi = list_entry(lh, struct file_info, list);
+                        entry = fi->addr_list.next;
+                        while (entry != &(fi->addr_list)) {
+                                arm_addr = list_entry(entry, struct arm_addr, addr_list);
+                                if (((arm_addr->start) <= (addr)) && 
+                                        ((arm_addr->end) >= (addr+sizeof(*store)))) {
+                                        found = 1;
+                                        break;
+                                }
+                                entry = entry->next;
+                        }
+                        if (found) {
+                                break;
+                        }
+                }
+        }
+        rcode = -1;
+        if (!found) {
+                printk(KERN_ERR "raw1394: arm_lock FAILED addr_entry not found"
+                " -> rcode_address_error\n");
+                spin_unlock(&host_info_lock);
+                return (RCODE_ADDRESS_ERROR);
+        } else {
+                DBGMSG("arm_lock addr_entry FOUND");
+        }
+        if (rcode == -1) {
+                if (arm_addr->access_rights & ARM_LOCK) {
+                        if (!(arm_addr->client_transactions & ARM_LOCK)) {
+                                memcpy(&old,(arm_addr->addr_space_buffer)+(addr-(arm_addr->start)),
+                                        sizeof(old));
+                                switch (ext_tcode) {
+                                        case (EXTCODE_MASK_SWAP):
+                                                new = data | (old & ~arg);
+                                                break;
+                                        case (EXTCODE_COMPARE_SWAP):
+                                                if (old == arg) {
+                                                        new = data;
+                                                } else {
+                                                        new = old;
+                                                }
+                                                break;
+                                        case (EXTCODE_FETCH_ADD):
+                                                new = cpu_to_be32(be32_to_cpu(data) + be32_to_cpu(old));
+                                                break;
+                                        case (EXTCODE_LITTLE_ADD):
+                                                new = cpu_to_le32(le32_to_cpu(data) + le32_to_cpu(old));
+                                                break;
+                                        case (EXTCODE_BOUNDED_ADD):
+                                                if (old != arg) {
+                                                        new = cpu_to_be32(be32_to_cpu(data) + 
+                                                                be32_to_cpu(old));
+                                                } else {
+                                                        new = old;
+                                                }
+                                                break;
+                                        case (EXTCODE_WRAP_ADD):
+                                                if (old != arg) {
+                                                        new = cpu_to_be32(be32_to_cpu(data) + 
+                                                                be32_to_cpu(old));
+                                                } else {
+                                                        new = data;
+                                                }
+                                                break;
+                                        default:
+                                                rcode = RCODE_TYPE_ERROR; /* function not allowed */
+                                                printk(KERN_ERR "raw1394: arm_lock FAILED "
+                                                "ext_tcode not allowed -> rcode_type_error\n");
+                                                break;
+                                } /*switch*/
+                                if (rcode == -1) {
+                                        DBGMSG("arm_lock -> (rcode_complete)");
+                                        rcode = RCODE_COMPLETE;
+                                        memcpy (store, &old, sizeof(*store));
+                                        memcpy ((arm_addr->addr_space_buffer)+
+                                                (addr-(arm_addr->start)), 
+                                                &new, sizeof(*store));
+                                }
+                        }
+                } else {
+                        rcode = RCODE_TYPE_ERROR; /* function not allowed */
+                        DBGMSG("arm_lock -> rcode_type_error (access denied)");
+                }
+        }
+        if (arm_addr->notification_options & ARM_LOCK) {
+                DBGMSG("arm_lock -> entering notification-section");
+                req = __alloc_pending_request(SLAB_ATOMIC);
+                if (!req) {
+                        DBGMSG("arm_lock -> rcode_conflict_error");
+                        spin_unlock(&host_info_lock);
+                        return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. 
+                                                        The request may be retried */
+                }
+                size =  sizeof(struct arm_request)+sizeof(struct arm_response) +
+                        3 * sizeof(*store) + 
+                        sizeof (struct arm_request_response);  /* maximum */
+                req->data = kmalloc(size, SLAB_ATOMIC);
+                if (!(req->data)) {
+                        free_pending_request(req);
+                        DBGMSG("arm_lock -> rcode_conflict_error");
+                        spin_unlock(&host_info_lock);
+                        return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. 
+                                                        The request may be retried */
+                }
+                req->free_data=1;
+                arm_req_resp = (struct arm_request_response *) (req->data);
+                arm_req  = (struct arm_request *) ((byte_t *)(req->data) + 
+                        (sizeof (struct arm_request_response)));
+                arm_resp = (struct arm_response *) ((byte_t *)(arm_req) + 
+                        (sizeof(struct arm_request)));
+                arm_req->buffer = ((byte_t *)(arm_resp) + 
+                        (sizeof(struct arm_response)));
+                arm_resp->buffer = ((byte_t *)(arm_req->buffer) + 
+                        (2* sizeof(*store)));
+                if ((ext_tcode == EXTCODE_FETCH_ADD) || 
+                        (ext_tcode == EXTCODE_LITTLE_ADD)) {
+                        arm_req->buffer_length = sizeof(*store);
+                        memcpy (arm_req->buffer, &data, sizeof(*store));
+
+                } else {
+                        arm_req->buffer_length = 2 * sizeof(*store);
+                        memcpy (arm_req->buffer, &arg,  sizeof(*store));
+                        memcpy (((arm_req->buffer) + sizeof(*store)), 
+                                &data, sizeof(*store));
+                }
+                if (rcode == RCODE_COMPLETE) {
+                        arm_resp->buffer_length = sizeof(*store);
+                        memcpy (arm_resp->buffer, &old, sizeof(*store));
+                } else {
+                        arm_resp->buffer = NULL;
+                        arm_resp->buffer_length = 0;
+                }
+                req->file_info = fi;
+                req->req.type = RAW1394_REQ_ARM;
+                req->req.generation = get_hpsb_generation(host);
+                req->req.misc = ( (((sizeof(*store)) << 16) & (0xFFFF0000)) | 
+                        (ARM_LOCK & 0xFF));
+                req->req.tag  = arm_addr->arm_tag;
+                req->req.recvb = arm_addr->recvb;
+                req->req.length = size;
+                arm_req->generation = req->req.generation;
+                arm_req->extended_transaction_code = ext_tcode;
+                arm_req->destination_offset = addr;
+                arm_req->source_nodeid = nodeid;
+                arm_req->destination_nodeid = host->node_id;
+                arm_req->tlabel = (flags >> 10) & 0x3f;
+                arm_req->tcode = (flags >> 4) & 0x0f;
+                arm_resp->response_code = rcode;
+                arm_req_resp->request  = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response));
+                arm_req_resp->response = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response) +
+                        sizeof (struct arm_request));
+                arm_req->buffer = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response) +
+                        sizeof (struct arm_request) +
+                        sizeof (struct arm_response));
+                arm_resp->buffer = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response) +
+                        sizeof (struct arm_request) +
+                        sizeof (struct arm_response) +
+                        2* sizeof (*store));
+                queue_complete_req(req);
+        }
+        spin_unlock(&host_info_lock);
+        return(rcode);
+}
+
+static int arm_lock64 (struct hpsb_host *host, int nodeid, octlet_t *store,
+               u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags)
+{
+        struct pending_request *req;
+        struct list_head *lh;
+        struct host_info *hi;
+        struct file_info *fi = NULL;
+        struct list_head *entry;
+        struct arm_addr  *arm_addr = NULL;
+        struct arm_request  *arm_req = NULL;
+        struct arm_response *arm_resp = NULL;
+        int found=0, size=0, rcode=-1;
+        octlet_t old, new;
+        struct arm_request_response *arm_req_resp = NULL;
+
+        if (((ext_tcode & 0xFF) == EXTCODE_FETCH_ADD) ||
+                ((ext_tcode & 0xFF) == EXTCODE_LITTLE_ADD)) {
+                DBGMSG("arm_lock64 called by node: %X "
+                      "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X %8.8X ",
+                      nodeid, (u16) ((addr >>32) & 0xFFFF),
+                      (u32) (addr & 0xFFFFFFFF), 
+                      ext_tcode & 0xFF , 
+                      (u32) ((be64_to_cpu(data) >> 32) & 0xFFFFFFFF), 
+                      (u32) (be64_to_cpu(data) & 0xFFFFFFFF));
+        } else {
+                DBGMSG("arm_lock64 called by node: %X "
+                      "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X %8.8X arg: "
+                      "%8.8X %8.8X ",
+                      nodeid, (u16) ((addr >>32) & 0xFFFF),
+                      (u32) (addr & 0xFFFFFFFF), 
+                      ext_tcode & 0xFF , 
+                      (u32) ((be64_to_cpu(data) >> 32) & 0xFFFFFFFF), 
+                      (u32) (be64_to_cpu(data) & 0xFFFFFFFF),
+                      (u32) ((be64_to_cpu(arg)  >> 32) & 0xFFFFFFFF), 
+                      (u32) (be64_to_cpu(arg)  & 0xFFFFFFFF));
+        }
+        spin_lock(&host_info_lock);
+        hi = find_host_info(host); /* search addressentry in file_info's for host */
+        if (hi != NULL) {
+                list_for_each(lh, &hi->file_info_list) {
+                        fi = list_entry(lh, struct file_info, list);
+                        entry = fi->addr_list.next;
+                        while (entry != &(fi->addr_list)) {
+                                arm_addr = list_entry(entry, struct arm_addr, addr_list);
+                                if (((arm_addr->start) <= (addr)) && 
+                                        ((arm_addr->end) >= (addr+sizeof(*store)))) {
+                                        found = 1;
+                                        break;
+                                }
+                                entry = entry->next;
+                        }
+                        if (found) {
+                                break;
+                        }
+                }
+        }
+        rcode = -1;
+        if (!found) {
+                printk(KERN_ERR "raw1394: arm_lock64 FAILED addr_entry not found"
+                " -> rcode_address_error\n");
+                spin_unlock(&host_info_lock);
+                return (RCODE_ADDRESS_ERROR);
+        } else {
+                DBGMSG("arm_lock64 addr_entry FOUND");
+        }
+        if (rcode == -1) {
+                if (arm_addr->access_rights & ARM_LOCK) {
+                        if (!(arm_addr->client_transactions & ARM_LOCK)) {
+                                memcpy(&old,(arm_addr->addr_space_buffer)+(addr-(arm_addr->start)),
+                                        sizeof(old));
+                                switch (ext_tcode) {
+                                        case (EXTCODE_MASK_SWAP):
+                                                new = data | (old & ~arg);
+                                                break;
+                                        case (EXTCODE_COMPARE_SWAP):
+                                                if (old == arg) {
+                                                        new = data;
+                                                } else {
+                                                        new = old;
+                                                }
+                                                break;
+                                        case (EXTCODE_FETCH_ADD):
+                                                new = cpu_to_be64(be64_to_cpu(data) + be64_to_cpu(old));
+                                                break;
+                                        case (EXTCODE_LITTLE_ADD):
+                                                new = cpu_to_le64(le64_to_cpu(data) + le64_to_cpu(old));
+                                                break;
+                                        case (EXTCODE_BOUNDED_ADD):
+                                                if (old != arg) {
+                                                        new = cpu_to_be64(be64_to_cpu(data) + 
+                                                                be64_to_cpu(old));
+                                                } else {
+                                                        new = old;
+                                                }
+                                                break;
+                                        case (EXTCODE_WRAP_ADD):
+                                                if (old != arg) {
+                                                        new = cpu_to_be64(be64_to_cpu(data) + 
+                                                                be64_to_cpu(old));
+                                                } else {
+                                                        new = data;
+                                                }
+                                                break;
+                                        default:
+                                                printk(KERN_ERR "raw1394: arm_lock64 FAILED "
+                                                "ext_tcode not allowed -> rcode_type_error\n");
+                                                rcode = RCODE_TYPE_ERROR; /* function not allowed */
+                                                break;
+                                } /*switch*/
+                                if (rcode == -1) {
+                                        DBGMSG("arm_lock64 -> (rcode_complete)");
+                                        rcode = RCODE_COMPLETE;
+                                        memcpy (store, &old, sizeof(*store));
+                                        memcpy ((arm_addr->addr_space_buffer)+
+                                                (addr-(arm_addr->start)), 
+                                                &new, sizeof(*store));
+                                } 
+                        }
+                } else {
+                        rcode = RCODE_TYPE_ERROR; /* function not allowed */
+                        DBGMSG("arm_lock64 -> rcode_type_error (access denied)");
+                }
+        }
+        if (arm_addr->notification_options & ARM_LOCK) {
+                DBGMSG("arm_lock64 -> entering notification-section");
+                req = __alloc_pending_request(SLAB_ATOMIC);
+                if (!req) {
+                        spin_unlock(&host_info_lock);
+                        DBGMSG("arm_lock64 -> rcode_conflict_error");
+                        return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. 
+                                                        The request may be retried */
+                }
+                size =  sizeof(struct arm_request)+sizeof(struct arm_response) +
+                        3 * sizeof(*store) +
+                        sizeof (struct arm_request_response); /* maximum */
+                req->data = kmalloc(size, SLAB_ATOMIC);
+                if (!(req->data)) {
+                        free_pending_request(req);
+                        spin_unlock(&host_info_lock);
+                        DBGMSG("arm_lock64 -> rcode_conflict_error");
+                        return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. 
+                                                        The request may be retried */
+                }
+                req->free_data=1;
+                arm_req_resp = (struct arm_request_response *) (req->data);
+                arm_req  = (struct arm_request *) ((byte_t *)(req->data) + 
+                        (sizeof (struct arm_request_response)));
+                arm_resp = (struct arm_response *) ((byte_t *)(arm_req) + 
+                        (sizeof(struct arm_request)));
+                arm_req->buffer = ((byte_t *)(arm_resp) + 
+                        (sizeof(struct arm_response)));
+                arm_resp->buffer = ((byte_t *)(arm_req->buffer) + 
+                        (2* sizeof(*store)));
+                if ((ext_tcode == EXTCODE_FETCH_ADD) || 
+                        (ext_tcode == EXTCODE_LITTLE_ADD)) {
+                        arm_req->buffer_length = sizeof(*store);
+                        memcpy (arm_req->buffer, &data, sizeof(*store));
+
+                } else {
+                        arm_req->buffer_length = 2 * sizeof(*store);
+                        memcpy (arm_req->buffer, &arg,  sizeof(*store));
+                        memcpy (((arm_req->buffer) + sizeof(*store)), 
+                                &data, sizeof(*store));
+                }
+                if (rcode == RCODE_COMPLETE) {
+                        arm_resp->buffer_length = sizeof(*store);
+                        memcpy (arm_resp->buffer, &old, sizeof(*store));
+                } else {
+                        arm_resp->buffer = NULL;
+                        arm_resp->buffer_length = 0;
+                }
+                req->file_info = fi;
+                req->req.type = RAW1394_REQ_ARM;
+                req->req.generation = get_hpsb_generation(host);
+                req->req.misc = ( (((sizeof(*store)) << 16) & (0xFFFF0000)) | 
+                        (ARM_LOCK & 0xFF));
+                req->req.tag  = arm_addr->arm_tag;
+                req->req.recvb = arm_addr->recvb;
+                req->req.length = size;
+                arm_req->generation = req->req.generation;
+                arm_req->extended_transaction_code = ext_tcode;
+                arm_req->destination_offset = addr;
+                arm_req->source_nodeid = nodeid;
+                arm_req->destination_nodeid = host->node_id;
+                arm_req->tlabel = (flags >> 10) & 0x3f;
+                arm_req->tcode = (flags >> 4) & 0x0f;
+                arm_resp->response_code = rcode;
+                arm_req_resp->request  = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response));
+                arm_req_resp->response = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response) +
+                        sizeof (struct arm_request));
+                arm_req->buffer = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response) +
+                        sizeof (struct arm_request) +
+                        sizeof (struct arm_response));
+                arm_resp->buffer = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response) +
+                        sizeof (struct arm_request) +
+                        sizeof (struct arm_response) +
+                        2* sizeof (*store));
+                queue_complete_req(req);
+        }
+        spin_unlock(&host_info_lock);
+        return(rcode);
+}
+
+static int arm_register(struct file_info *fi, struct pending_request *req)
+{
+        int retval;
+        struct arm_addr *addr;
+        struct list_head *lh, *lh_1, *lh_2;
+        struct host_info *hi;
+        struct file_info *fi_hlp = NULL;
+        struct list_head *entry;
+        struct arm_addr  *arm_addr = NULL;
+        int same_host, another_host;
+        unsigned long flags;
+
+        DBGMSG("arm_register called "
+              "addr(Offset): %8.8x %8.8x length: %u "
+              "rights: %2.2X notify: %2.2X "
+              "max_blk_len: %4.4X",
+              (u32) ((req->req.address >>32) & 0xFFFF),
+              (u32) (req->req.address & 0xFFFFFFFF),
+              req->req.length, ((req->req.misc >> 8) & 0xFF),
+              (req->req.misc & 0xFF),((req->req.misc >> 16) & 0xFFFF));
+        /* check addressrange */
+        if ((((req->req.address) & ~(0xFFFFFFFFFFFF)) != 0) ||
+                (((req->req.address + req->req.length) & ~(0xFFFFFFFFFFFF)) != 0)) {
+                req->req.length = 0;
+                return (-EINVAL);
+        }
+        /* addr-list-entry for fileinfo */
+        addr = (struct arm_addr *)kmalloc(sizeof(struct arm_addr), SLAB_KERNEL); 
+        if (!addr) {
+                req->req.length = 0;
+                return (-ENOMEM);
+        } 
+        /* allocation of addr_space_buffer */
+        addr->addr_space_buffer = (u8 *)kmalloc(req->req.length,SLAB_KERNEL);
+        if (!(addr->addr_space_buffer)) {
+                kfree(addr);
+                req->req.length = 0;
+                return (-ENOMEM);
+        }
+        /* initialization of addr_space_buffer */
+        if ((req->req.sendb)== (unsigned long)NULL) {
+                /* init: set 0 */
+                memset(addr->addr_space_buffer, 0,req->req.length);
+        } else {
+                /* init: user -> kernel */
+                if (copy_from_user(addr->addr_space_buffer,int2ptr(req->req.sendb),
+                        req->req.length)) {
+                        kfree(addr->addr_space_buffer);
+                        kfree(addr);
+                        return (-EFAULT);
+                }
+        }
+        INIT_LIST_HEAD(&addr->addr_list);
+        addr->arm_tag   = req->req.tag;
+        addr->start     = req->req.address;
+        addr->end       = req->req.address + req->req.length;
+        addr->access_rights = (u8) (req->req.misc & 0x0F);
+        addr->notification_options = (u8) ((req->req.misc >> 4) & 0x0F);
+        addr->client_transactions = (u8) ((req->req.misc >> 8) & 0x0F);
+        addr->access_rights |= addr->client_transactions;
+        addr->notification_options |= addr->client_transactions;
+        addr->recvb     = req->req.recvb;
+        addr->rec_length = (u16) ((req->req.misc >> 16) & 0xFFFF);
+        spin_lock_irqsave(&host_info_lock, flags);
+        hi = find_host_info(fi->host);
+        same_host = 0;
+        another_host = 0;
+        /* same host with address-entry containing same addressrange ? */
+        list_for_each(lh, &hi->file_info_list) {
+                fi_hlp = list_entry(lh, struct file_info, list);
+                entry = fi_hlp->addr_list.next;
+                while (entry != &(fi_hlp->addr_list)) {
+                        arm_addr = list_entry(entry, struct arm_addr, addr_list);
+                        if ( (arm_addr->start == addr->start) && 
+                                (arm_addr->end == addr->end)) {
+                                DBGMSG("same host ownes same "
+                                        "addressrange -> EALREADY");
+                                same_host = 1;
+                                break;
+                        }
+                        entry = entry->next;
+                }
+                if (same_host) {
+                        break;
+                }
+        }
+        if (same_host) {
+                /* addressrange occupied by same host */
+                kfree(addr->addr_space_buffer);
+                kfree(addr);
+                spin_unlock_irqrestore(&host_info_lock, flags);
+                return (-EALREADY);
+        }
+        /* another host with valid address-entry containing same addressrange */
+        list_for_each(lh_1, &host_info_list) {
+                hi = list_entry(lh_1, struct host_info, list);
+                if (hi->host != fi->host) {
+                        list_for_each(lh_2, &hi->file_info_list) {
+                                fi_hlp = list_entry(lh_2, struct file_info, list);
+                                entry = fi_hlp->addr_list.next;
+                                while (entry != &(fi_hlp->addr_list)) {
+                                        arm_addr = list_entry(entry, struct arm_addr, addr_list);
+                                        if ( (arm_addr->start == addr->start) && 
+                                                (arm_addr->end == addr->end)) {
+                                                DBGMSG("another host ownes same "
+                                                "addressrange");
+                                                another_host = 1;
+                                                break;
+                                        }
+                                        entry = entry->next;
+                                }
+                                if (another_host) {
+                                        break;
+                                }
+                        }
+                }
+        }
+        if (another_host) {
+                DBGMSG("another hosts entry is valid -> SUCCESS");
+                if (copy_to_user(int2ptr(req->req.recvb),
+                        int2ptr(&addr->start),sizeof(u64))) {
+                        printk(KERN_ERR "raw1394: arm_register failed "
+                              " address-range-entry is invalid -> EFAULT !!!\n");
+                        kfree(addr->addr_space_buffer);
+                        kfree(addr);
+                        spin_unlock_irqrestore(&host_info_lock, flags);
+                        return (-EFAULT);
+                }
+                free_pending_request(req); /* immediate success or fail */
+                /* INSERT ENTRY */
+                list_add_tail(&addr->addr_list, &fi->addr_list);
+                spin_unlock_irqrestore(&host_info_lock, flags);
+                return sizeof(struct raw1394_request);
+        }
+        retval = hpsb_register_addrspace(hl_handle, &arm_ops, req->req.address,
+                req->req.address + req->req.length);
+        if (retval) {
+               /* INSERT ENTRY */
+               list_add_tail(&addr->addr_list, &fi->addr_list);
+        } else {
+                DBGMSG("arm_register failed errno: %d \n",retval);
+                kfree(addr->addr_space_buffer);
+                kfree(addr);
+                spin_unlock_irqrestore(&host_info_lock, flags);
+                return (-EALREADY); 
+        }
+        spin_unlock_irqrestore(&host_info_lock, flags);
+        free_pending_request(req); /* immediate success or fail */
+        return sizeof(struct raw1394_request);
+}
+
+static int arm_unregister(struct file_info *fi, struct pending_request *req)
+{
+        int found  = 0;
+        int retval = 0;
+        struct list_head *entry;
+        struct arm_addr  *addr = NULL;
+        struct list_head *lh_1, *lh_2;
+        struct host_info *hi;
+        struct file_info *fi_hlp = NULL;
+        struct arm_addr  *arm_addr = NULL;
+        int another_host;
+        unsigned long flags;
+
+        DBGMSG("arm_Unregister called addr(Offset): "
+              "%8.8x %8.8x",
+              (u32) ((req->req.address >>32) & 0xFFFF),
+              (u32) (req->req.address & 0xFFFFFFFF));
+        spin_lock_irqsave(&host_info_lock, flags);
+        /* get addr */
+        entry = fi->addr_list.next;
+        while (entry != &(fi->addr_list)) {
+                addr = list_entry(entry, struct arm_addr, addr_list);
+                if (addr->start == req->req.address) {
+                        found = 1;
+                        break;
+                }
+                entry = entry->next;
+        }
+        if (!found) {
+                DBGMSG("arm_Unregister addr not found");
+                spin_unlock_irqrestore(&host_info_lock, flags);
+                return (-EINVAL);
+        }
+        DBGMSG("arm_Unregister addr found");
+        another_host = 0;
+        /* another host with valid address-entry containing 
+           same addressrange */
+        list_for_each(lh_1, &host_info_list) {
+                hi = list_entry(lh_1, struct host_info, list);
+                if (hi->host != fi->host) {
+                        list_for_each(lh_2, &hi->file_info_list) {
+                                fi_hlp = list_entry(lh_2, struct file_info, list);
+                                entry = fi_hlp->addr_list.next;
+                                while (entry != &(fi_hlp->addr_list)) {
+                                        arm_addr = list_entry(entry, 
+                                                struct arm_addr, addr_list);
+                                        if (arm_addr->start == 
+                                                addr->start) {
+                                                DBGMSG("another host ownes "
+                                                "same addressrange");
+                                                another_host = 1;
+                                                break;
+                                        }
+                                        entry = entry->next;
+                                }
+                                if (another_host) {
+                                        break;
+                                }
+                        }
+                }
+        }
+        if (another_host) {
+                DBGMSG("delete entry from list -> success");
+                list_del(&addr->addr_list);
+                kfree(addr->addr_space_buffer);
+                kfree(addr);
+                free_pending_request(req); /* immediate success or fail */
+                spin_unlock_irqrestore(&host_info_lock, flags);
+                return sizeof(struct raw1394_request);
+        } 
+        retval = hpsb_unregister_addrspace(hl_handle, addr->start);
+        if (!retval) {
+                printk(KERN_ERR "raw1394: arm_Unregister failed -> EINVAL\n");
+                spin_unlock_irqrestore(&host_info_lock, flags);
+                return (-EINVAL);
+        }
+        DBGMSG("delete entry from list -> success");
+        list_del(&addr->addr_list);
+        spin_unlock_irqrestore(&host_info_lock, flags);
+        kfree(addr->addr_space_buffer);
+        kfree(addr);
+        free_pending_request(req); /* immediate success or fail */
+        return sizeof(struct raw1394_request);
+}
+
+static int reset_notification(struct file_info *fi, struct pending_request *req)
+{
+        DBGMSG("reset_notification called - switch %s ",
+                (req->req.misc == RAW1394_NOTIFY_OFF)?"OFF":"ON");
+        if ((req->req.misc == RAW1394_NOTIFY_OFF) ||
+                (req->req.misc == RAW1394_NOTIFY_ON)) {
+                fi->notification=(u8)req->req.misc;
+                free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */
+                return sizeof(struct raw1394_request);
+        } 
+        /* error EINVAL (22) invalid argument */
+        return (-EINVAL);
+}
+
+static int write_phypacket(struct file_info *fi, struct pending_request *req)
+{
+        struct hpsb_packet *packet = NULL;
+        int retval=0;
+        quadlet_t data;
+
+        data = be32_to_cpu((u32)req->req.sendb);
+        DBGMSG("write_phypacket called - quadlet 0x%8.8x ",data);
+        packet = hpsb_make_phypacket (fi->host, data);
+        if (!packet) return -ENOMEM;
+        req->req.length=0;
+        req->packet=packet;
+        req->tq.data=req;
+        hpsb_add_packet_complete_task(packet, &req->tq);
+        spin_lock_irq(&fi->reqlists_lock);
+        list_add_tail(&req->list, &fi->req_pending);
+        spin_unlock_irq(&fi->reqlists_lock);
+        packet->generation = req->req.generation;
+        retval = hpsb_send_packet(packet);
+        DBGMSG("write_phypacket send_packet called => retval: %d ",
+                retval);
+        if (! retval) {
+                req->req.error = RAW1394_ERROR_SEND_ERROR;
+                req->req.length = 0;
+                queue_complete_req(req);
+        }
+        return sizeof(struct raw1394_request);
+}
+
+static int get_config_rom(struct file_info *fi, struct pending_request *req)
+{
+        size_t return_size;
+        unsigned char rom_version;
+        int ret=sizeof(struct raw1394_request);
+        quadlet_t *data = kmalloc(req->req.length, SLAB_KERNEL);
+        int status;
+        if (!data) return -ENOMEM;
+        status = hpsb_get_config_rom(fi->host, data, 
+                req->req.length, &return_size, &rom_version);
+        if (copy_to_user(int2ptr(req->req.recvb), data, 
+                req->req.length))
+                ret = -EFAULT;
+        if (copy_to_user(int2ptr(req->req.tag), &return_size, 
+                sizeof(return_size)))
+                ret = -EFAULT;
+        if (copy_to_user(int2ptr(req->req.address), &rom_version, 
+                sizeof(rom_version)))
+                ret = -EFAULT;
+        if (copy_to_user(int2ptr(req->req.sendb), &status, 
+                sizeof(status)))
+                ret = -EFAULT;
+        kfree(data);
+        if (ret >= 0) {
+                free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */
+        }
+        return ret;
+}
+
+static int update_config_rom(struct file_info *fi, struct pending_request *req)
+{
+        int ret=sizeof(struct raw1394_request);
+        quadlet_t *data = kmalloc(req->req.length, SLAB_KERNEL);
+        if (!data) return -ENOMEM;
+        if (copy_from_user(data,int2ptr(req->req.sendb), 
+                req->req.length)) {
+                ret= -EFAULT;
+        } else {
+                int status = hpsb_update_config_rom(fi->host, 
+                        data, req->req.length, 
+                        (unsigned char) req->req.misc);
+                if (copy_to_user(int2ptr(req->req.recvb), 
+                        &status, sizeof(status)))
+                        ret = -ENOMEM;
+        }
+        kfree(data);
+        if (ret >= 0) {
+                free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */
+        }
+        return ret;
+}
+
+static int state_connected(struct file_info *fi, struct pending_request *req)
+{
+        int node = req->req.address >> 48;
+
+        req->req.error = RAW1394_ERROR_NONE;
+
         switch (req->req.type) {
+
+        case RAW1394_REQ_ECHO:
+                queue_complete_req(req);
+                return sizeof(struct raw1394_request);
+
+        case RAW1394_REQ_ISO_SEND:
+                return handle_iso_send(fi, req, node);
+
+        case RAW1394_REQ_ARM_REGISTER:
+                return arm_register(fi, req);
+
+        case RAW1394_REQ_ARM_UNREGISTER:
+                return arm_unregister(fi, req);
+
+        case RAW1394_REQ_RESET_NOTIFY:
+                return reset_notification(fi, req);
+
         case RAW1394_REQ_ISO_LISTEN:
                 handle_iso_listen(fi, req);
                 return sizeof(struct raw1394_request);
@@ -831,21 +1919,49 @@
                 return sizeof(struct raw1394_request);
 
         case RAW1394_REQ_RESET_BUS:
-                hpsb_reset_bus(fi->host, LONG_RESET);
+                if (req->req.misc == RAW1394_LONG_RESET) {
+                        DBGMSG("busreset called (type: LONG)");
+                        hpsb_reset_bus(fi->host, LONG_RESET);
+                        free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */
+                        return sizeof(struct raw1394_request);
+                }
+                if (req->req.misc == RAW1394_SHORT_RESET) {
+                        DBGMSG("busreset called (type: SHORT)");
+                        hpsb_reset_bus(fi->host, SHORT_RESET);
+                        free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */
+                        return sizeof(struct raw1394_request);
+                }
+                /* error EINVAL (22) invalid argument */
+                return (-EINVAL);
+        case RAW1394_REQ_GET_ROM:
+                return get_config_rom(fi, req);
+
+        case RAW1394_REQ_UPDATE_ROM:
+                return update_config_rom(fi, req);
+        }
+
+        if (req->req.generation != get_hpsb_generation(fi->host)) {
+                req->req.error = RAW1394_ERROR_GENERATION;
+                req->req.generation = get_hpsb_generation(fi->host);
+                req->req.length = 0;
+                queue_complete_req(req);
                 return sizeof(struct raw1394_request);
         }
 
+        switch (req->req.type) {
+        case RAW1394_REQ_PHYPACKET:
+                return write_phypacket(fi, req);
+        case RAW1394_REQ_ASYNC_SEND:
+                return handle_async_send(fi, req);
+        }
+
         if (req->req.length == 0) {
                 req->req.error = RAW1394_ERROR_INVALID_ARG;
                 queue_complete_req(req);
                 return sizeof(struct raw1394_request);
         }
 
-        if (fi->host->node_id == node) {
-                return handle_local_request(fi, req, node);
-        }
-
-        return handle_remote_request(fi, req, node);
+        return handle_async_request(fi, req, node);
 }
 
 
@@ -892,6 +2008,323 @@
         return retval;
 }
 
+/* rawiso operations */
+
+/* check if any RAW1394_REQ_RAWISO_ACTIVITY event is already in the
+ * completion queue (reqlists_lock must be taken) */
+static inline int __rawiso_event_in_queue(struct file_info *fi)
+{
+	struct list_head *lh;
+	struct pending_request *req;
+
+	list_for_each(lh, &fi->req_complete) {
+		req = list_entry(lh, struct pending_request, list);
+		if(req->req.type == RAW1394_REQ_RAWISO_ACTIVITY) {
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+/* put a RAWISO_ACTIVITY event in the queue, if one isn't there already */
+static void queue_rawiso_event(struct file_info *fi)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&fi->reqlists_lock, flags);
+
+	/* only one ISO activity event may be in the queue */
+	if(!__rawiso_event_in_queue(fi)) {
+		struct pending_request *req = __alloc_pending_request(SLAB_ATOMIC);
+
+		if(req) {
+			req->file_info = fi;
+			req->req.type = RAW1394_REQ_RAWISO_ACTIVITY;
+			req->req.generation = get_hpsb_generation(fi->host);
+			__queue_complete_req(req);
+		} else {
+			/* on allocation failure, signal an overflow */
+			if(fi->iso_handle) {
+				atomic_inc(&fi->iso_handle->overflows);
+			}
+		}
+	}
+	spin_unlock_irqrestore(&fi->reqlists_lock, flags);
+}
+
+static void rawiso_activity_cb(struct hpsb_iso *iso)
+{
+	unsigned long flags;
+        struct list_head *lh;
+        struct host_info *hi;
+
+        spin_lock_irqsave(&host_info_lock, flags);
+        hi = find_host_info(iso->host);
+
+	if (hi != NULL) {
+		list_for_each(lh, &hi->file_info_list) {
+			struct file_info *fi = list_entry(lh, struct file_info, list);
+			if(fi->iso_handle == iso)
+				queue_rawiso_event(fi);
+		}
+	}
+
+	spin_unlock_irqrestore(&host_info_lock, flags);
+}
+
+/* helper function - gather all the kernel iso status bits for returning to user-space */
+static void raw1394_iso_fill_status(struct hpsb_iso *iso, struct raw1394_iso_status *stat)
+{
+	stat->config.data_buf_size = iso->buf_size;
+	stat->config.buf_packets = iso->buf_packets;
+	stat->config.channel = iso->channel;
+	stat->config.speed = iso->speed;
+	stat->config.irq_interval = iso->irq_interval;
+	stat->n_packets = hpsb_iso_n_ready(iso);
+	stat->overflows = atomic_read(&iso->overflows);
+	stat->xmit_cycle = iso->xmit_cycle;
+}
+
+static int raw1394_iso_xmit_init(struct file_info *fi, void *uaddr)
+{
+	struct raw1394_iso_status stat;
+
+	if(copy_from_user(&stat, uaddr, sizeof(stat)))
+		return -EFAULT;
+
+	fi->iso_handle = hpsb_iso_xmit_init(fi->host,
+					    stat.config.data_buf_size,
+					    stat.config.buf_packets,
+					    stat.config.channel,
+					    stat.config.speed,
+					    stat.config.irq_interval,
+					    rawiso_activity_cb);
+	if(!fi->iso_handle)
+		return -ENOMEM;
+
+	fi->iso_state = RAW1394_ISO_XMIT;
+
+	raw1394_iso_fill_status(fi->iso_handle, &stat);
+	if(copy_to_user(uaddr, &stat, sizeof(stat)))
+		return -EFAULT;
+
+	/* queue an event to get things started */
+	rawiso_activity_cb(fi->iso_handle);
+
+	return 0;
+}
+
+static int raw1394_iso_recv_init(struct file_info *fi, void *uaddr)
+{
+	struct raw1394_iso_status stat;
+
+	if(copy_from_user(&stat, uaddr, sizeof(stat)))
+		return -EFAULT;
+
+	fi->iso_handle = hpsb_iso_recv_init(fi->host,
+					    stat.config.data_buf_size,
+					    stat.config.buf_packets,
+					    stat.config.channel,
+					    stat.config.irq_interval,
+					    rawiso_activity_cb);
+	if(!fi->iso_handle)
+		return -ENOMEM;
+
+	fi->iso_state = RAW1394_ISO_RECV;
+
+	raw1394_iso_fill_status(fi->iso_handle, &stat);
+	if(copy_to_user(uaddr, &stat, sizeof(stat)))
+		return -EFAULT;
+	return 0;
+}
+
+static int raw1394_iso_get_status(struct file_info *fi, void *uaddr)
+{
+	struct raw1394_iso_status stat;
+	struct hpsb_iso *iso = fi->iso_handle;
+
+	raw1394_iso_fill_status(fi->iso_handle, &stat);
+	if(copy_to_user(uaddr, &stat, sizeof(stat)))
+		return -EFAULT;
+
+	/* reset overflow counter */
+	atomic_set(&iso->overflows, 0);
+
+	return 0;
+}
+
+/* copy N packet_infos out of the ringbuffer into user-supplied array */
+static int raw1394_iso_recv_packets(struct file_info *fi, void *uaddr)
+{
+	struct raw1394_iso_packets upackets;
+	unsigned int packet = fi->iso_handle->first_packet;
+	int i;
+
+	if(copy_from_user(&upackets, uaddr, sizeof(upackets)))
+		return -EFAULT;
+
+	if(upackets.n_packets > hpsb_iso_n_ready(fi->iso_handle))
+		return -EINVAL;
+
+	/* ensure user-supplied buffer is accessible and big enough */
+	if(verify_area(VERIFY_WRITE, upackets.infos,
+		       upackets.n_packets * sizeof(struct raw1394_iso_packet_info)))
+		return -EFAULT;
+
+	/* copy the packet_infos out */
+	for(i = 0; i < upackets.n_packets; i++) {
+		if(__copy_to_user(&upackets.infos[i],
+				  &fi->iso_handle->infos[packet],
+				  sizeof(struct raw1394_iso_packet_info)))
+			return -EFAULT;
+		
+		packet = (packet + 1) % fi->iso_handle->buf_packets;
+	}
+
+	return 0;
+}
+
+/* copy N packet_infos from user to ringbuffer, and queue them for transmission */
+static int raw1394_iso_send_packets(struct file_info *fi, void *uaddr)
+{
+	struct raw1394_iso_packets upackets;
+	int i, rv;
+
+	if(copy_from_user(&upackets, uaddr, sizeof(upackets)))
+		return -EFAULT;
+
+	if(upackets.n_packets > hpsb_iso_n_ready(fi->iso_handle))
+		return -EINVAL;
+
+	/* ensure user-supplied buffer is accessible and big enough */
+	if(verify_area(VERIFY_READ, upackets.infos,
+		       upackets.n_packets * sizeof(struct raw1394_iso_packet_info)))
+		return -EFAULT;
+
+	/* copy the infos structs in and queue the packets */
+	for(i = 0; i < upackets.n_packets; i++) {
+		struct raw1394_iso_packet_info info;
+
+		if(__copy_from_user(&info, &upackets.infos[i],
+				    sizeof(struct raw1394_iso_packet_info)))
+			return -EFAULT;
+
+		rv = hpsb_iso_xmit_queue_packet(fi->iso_handle, info.offset,
+						info.len, info.tag, info.sy);
+		if(rv)
+			return rv;
+	}
+
+	return 0;
+}
+
+static void raw1394_iso_shutdown(struct file_info *fi)
+{
+	if(fi->iso_handle)
+		hpsb_iso_shutdown(fi->iso_handle);
+
+	fi->iso_handle = NULL;
+	fi->iso_state = RAW1394_ISO_INACTIVE;
+}
+
+/* mmap the rawiso xmit/recv buffer */
+static int raw1394_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct file_info *fi = file->private_data;
+
+	if(fi->iso_state == RAW1394_ISO_INACTIVE)
+		return -EINVAL;
+
+	return dma_region_mmap(&fi->iso_handle->data_buf, file, vma);
+}
+
+/* ioctl is only used for rawiso operations */
+static int raw1394_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct file_info *fi = file->private_data;
+
+	switch(fi->iso_state) {
+	case RAW1394_ISO_INACTIVE:
+		switch(cmd) {
+		case RAW1394_IOC_ISO_XMIT_INIT:
+			return raw1394_iso_xmit_init(fi, (void*) arg);
+		case RAW1394_IOC_ISO_RECV_INIT:
+			return raw1394_iso_recv_init(fi, (void*) arg);
+		default:
+			break;
+		}
+		break;
+	case RAW1394_ISO_RECV:
+		switch(cmd) {
+		case RAW1394_IOC_ISO_RECV_START: {
+			/* copy args from user-space */
+			int args[3];
+			if(copy_from_user(&args[0], (void*) arg, sizeof(args)))
+				return -EFAULT;
+			return hpsb_iso_recv_start(fi->iso_handle, args[0], args[1], args[2]);
+		}
+		case RAW1394_IOC_ISO_XMIT_RECV_STOP:
+			hpsb_iso_stop(fi->iso_handle);
+			return 0;
+		case RAW1394_IOC_ISO_RECV_LISTEN_CHANNEL:
+			return hpsb_iso_recv_listen_channel(fi->iso_handle, arg);
+		case RAW1394_IOC_ISO_RECV_UNLISTEN_CHANNEL:
+			return hpsb_iso_recv_unlisten_channel(fi->iso_handle, arg);
+		case RAW1394_IOC_ISO_RECV_SET_CHANNEL_MASK: {
+			/* copy the u64 from user-space */
+			u64 mask;
+			if(copy_from_user(&mask, (void*) arg, sizeof(mask)))
+				return -EFAULT;
+			return hpsb_iso_recv_set_channel_mask(fi->iso_handle, mask);
+		}
+		case RAW1394_IOC_ISO_GET_STATUS:
+			return raw1394_iso_get_status(fi, (void*) arg);
+		case RAW1394_IOC_ISO_RECV_PACKETS:
+			return raw1394_iso_recv_packets(fi, (void*) arg);
+		case RAW1394_IOC_ISO_RECV_RELEASE_PACKETS:
+			return hpsb_iso_recv_release_packets(fi->iso_handle, arg);
+		case RAW1394_IOC_ISO_SHUTDOWN:
+			raw1394_iso_shutdown(fi);
+			return 0;
+		case RAW1394_IOC_ISO_QUEUE_ACTIVITY:
+			queue_rawiso_event(fi);
+			return 0;
+		}
+		break;
+	case RAW1394_ISO_XMIT:
+		switch(cmd) {
+		case RAW1394_IOC_ISO_XMIT_START: {
+			/* copy two ints from user-space */
+			int args[2];
+			if(copy_from_user(&args[0], (void*) arg, sizeof(args)))
+				return -EFAULT;
+			return hpsb_iso_xmit_start(fi->iso_handle, args[0], args[1]);
+		}
+		case RAW1394_IOC_ISO_XMIT_SYNC:
+			return hpsb_iso_xmit_sync(fi->iso_handle);
+		case RAW1394_IOC_ISO_XMIT_RECV_STOP:
+			hpsb_iso_stop(fi->iso_handle);
+			return 0;
+		case RAW1394_IOC_ISO_GET_STATUS:
+			return raw1394_iso_get_status(fi, (void*) arg);
+		case RAW1394_IOC_ISO_XMIT_PACKETS:
+			return raw1394_iso_send_packets(fi, (void*) arg);
+		case RAW1394_IOC_ISO_SHUTDOWN:
+			raw1394_iso_shutdown(fi);
+			return 0;
+		case RAW1394_IOC_ISO_QUEUE_ACTIVITY:
+			queue_rawiso_event(fi);
+			return 0;
+		}
+		break;
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
 static unsigned int raw1394_poll(struct file *file, poll_table *pt)
 {
         struct file_info *fi = file->private_data;
@@ -921,6 +2354,7 @@
                 return -ENOMEM;
         
         memset(fi, 0, sizeof(struct file_info));
+        fi->notification = (u8) RAW1394_NOTIFY_ON; /* busreset notification */
 
         INIT_LIST_HEAD(&fi->list);
         fi->state = opened;
@@ -929,6 +2363,7 @@
         sema_init(&fi->complete_sem, 0);
         spin_lock_init(&fi->reqlists_lock);
         init_waitqueue_head(&fi->poll_wait_complete);
+        INIT_LIST_HEAD(&fi->addr_list);
 
         file->private_data = fi;
 
@@ -940,7 +2375,18 @@
         struct file_info *fi = file->private_data;
         struct list_head *lh;
         struct pending_request *req;
-        int done = 0, i;
+        int done = 0, i, fail = 0;
+        int retval = 0;
+        struct list_head *entry;
+        struct arm_addr  *addr = NULL;
+        struct list_head *lh_1, *lh_2;
+        struct host_info *hi;
+        struct file_info *fi_hlp = NULL;
+        struct arm_addr  *arm_addr = NULL;
+        int another_host;
+
+	if(fi->iso_state != RAW1394_ISO_INACTIVE)
+		raw1394_iso_shutdown(fi);
 
         for (i = 0; i < 64; i++) {
                 if (fi->listen_channels & (1ULL << i)) {
@@ -948,9 +2394,63 @@
                 }
         }
 
-        spin_lock(&host_info_lock);
+        spin_lock_irq(&host_info_lock);
         fi->listen_channels = 0;
-        spin_unlock(&host_info_lock);
+        spin_unlock_irq(&host_info_lock);
+
+        fail = 0;
+        /* set address-entries invalid */
+        spin_lock_irq(&host_info_lock);
+
+        while (!list_empty(&fi->addr_list)) {
+                another_host = 0;
+                lh = fi->addr_list.next;
+                addr = list_entry(lh, struct arm_addr, addr_list);
+                /* another host with valid address-entry containing 
+                   same addressrange? */
+                list_for_each(lh_1, &host_info_list) {
+                        hi = list_entry(lh_1, struct host_info, list);
+                        if (hi->host != fi->host) {
+                                list_for_each(lh_2, &hi->file_info_list) {
+                                        fi_hlp = list_entry(lh_2, struct file_info, list);
+                                        entry = fi_hlp->addr_list.next;
+                                        while (entry != &(fi_hlp->addr_list)) {
+                                                arm_addr = list_entry(entry, 
+                                                        struct arm_addr, addr_list);
+                                                if (arm_addr->start == 
+                                                        addr->start) {
+                                                        DBGMSG("raw1394_release: "
+                                                        "another host ownes "
+                                                        "same addressrange");
+                                                        another_host = 1;
+                                                        break;
+                                                }
+                                                entry = entry->next;
+                                        }
+                                        if (another_host) {
+                                                break;
+                                        }
+                                }
+                        }
+                }
+                if (!another_host) {
+                        DBGMSG("raw1394_release: call hpsb_arm_unregister");
+                        retval = hpsb_unregister_addrspace(hl_handle, addr->start);
+                        if (!retval) {
+                                ++fail;
+                                printk(KERN_ERR "raw1394_release arm_Unregister failed\n");
+                        }
+                }
+                DBGMSG("raw1394_release: delete addr_entry from list");
+                list_del(&addr->addr_list);
+                kfree(addr->addr_space_buffer);
+                kfree(addr);
+        } /* while */
+        spin_unlock_irq(&host_info_lock);
+        if (fail > 0) {
+                printk(KERN_ERR "raw1394: during addr_list-release "
+                        "error(s) occurred \n");
+        }
 
         while (!done) {
                 spin_lock_irq(&fi->reqlists_lock);
@@ -995,7 +2495,9 @@
 static struct file_operations file_ops = {
 	.owner =	THIS_MODULE,
         .read =		raw1394_read, 
-        .write =	raw1394_write, 
+        .write =	raw1394_write,
+	.mmap =         raw1394_mmap,
+	.ioctl =        raw1394_ioctl,
         .poll =		raw1394_poll, 
         .open =		raw1394_open, 
         .release =	raw1394_release, 
@@ -1009,28 +2511,28 @@
                 return -ENOMEM;
         }
 
-	devfs_handle = devfs_register(NULL,
-				      RAW1394_DEVICE_NAME, DEVFS_FL_NONE,
+        devfs_handle = devfs_register(NULL,
+                                      RAW1394_DEVICE_NAME, DEVFS_FL_NONE,
                                       IEEE1394_MAJOR,
-				      IEEE1394_MINOR_BLOCK_RAW1394 * 16,
+                                      IEEE1394_MINOR_BLOCK_RAW1394 * 16,
                                       S_IFCHR | S_IRUSR | S_IWUSR, &file_ops,
                                       NULL);
 
         if (ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_RAW1394,
-				      THIS_MODULE, &file_ops)) {
+                                      THIS_MODULE, &file_ops)) {
                 HPSB_ERR("raw1394 failed to register minor device block");
-		devfs_unregister(devfs_handle);
-		hpsb_unregister_highlevel(hl_handle);
+                devfs_unregister(devfs_handle);
+                hpsb_unregister_highlevel(hl_handle);
                 return -EBUSY;
         }
-	printk(KERN_INFO "raw1394: /dev/%s device initialized\n", RAW1394_DEVICE_NAME);
+        printk(KERN_INFO "raw1394: /dev/%s device initialized\n", RAW1394_DEVICE_NAME);
         return 0;
 }
 
 static void __exit cleanup_raw1394(void)
 {
         ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_RAW1394);
-	devfs_unregister(devfs_handle);
+        devfs_unregister(devfs_handle);
         hpsb_unregister_highlevel(hl_handle);
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/raw1394.h linux-2.4.21-pre6/drivers/ieee1394/raw1394.h
--- linux-2.4.20/drivers/ieee1394/raw1394.h	2000-10-02 02:53:07.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ieee1394/raw1394.h	2003-03-26 23:48:58.000000000 +0000
@@ -1,8 +1,7 @@
 #ifndef IEEE1394_RAW1394_H
 #define IEEE1394_RAW1394_H
 
-#define RAW1394_DEVICE_MAJOR      171
-#define RAW1394_DEVICE_NAME       "raw1394"
+/* header for the raw1394 API that is exported to user-space */
 
 #define RAW1394_KERNELAPI_VERSION 4
 
@@ -14,20 +13,33 @@
 #define RAW1394_REQ_SET_CARD      3
 
 /* state: connected */
-#define RAW1394_REQ_ASYNC_READ    100
-#define RAW1394_REQ_ASYNC_WRITE   101
-#define RAW1394_REQ_LOCK          102
-#define RAW1394_REQ_LOCK64        103
-#define RAW1394_REQ_ISO_SEND      104
-
-#define RAW1394_REQ_ISO_LISTEN    200
-#define RAW1394_REQ_FCP_LISTEN    201
-#define RAW1394_REQ_RESET_BUS     202
+#define RAW1394_REQ_ASYNC_READ      100
+#define RAW1394_REQ_ASYNC_WRITE     101
+#define RAW1394_REQ_LOCK            102
+#define RAW1394_REQ_LOCK64          103
+#define RAW1394_REQ_ISO_SEND        104
+#define RAW1394_REQ_ASYNC_SEND      105
+
+#define RAW1394_REQ_ISO_LISTEN      200
+#define RAW1394_REQ_FCP_LISTEN      201
+#define RAW1394_REQ_RESET_BUS       202
+#define RAW1394_REQ_GET_ROM         203
+#define RAW1394_REQ_UPDATE_ROM      204
+#define RAW1394_REQ_ECHO            205
+
+#define RAW1394_REQ_ARM_REGISTER    300
+#define RAW1394_REQ_ARM_UNREGISTER  301
+
+#define RAW1394_REQ_RESET_NOTIFY    400
+
+#define RAW1394_REQ_PHYPACKET       500
 
 /* kernel to user */
-#define RAW1394_REQ_BUS_RESET     10000
-#define RAW1394_REQ_ISO_RECEIVE   10001
-#define RAW1394_REQ_FCP_REQUEST   10002
+#define RAW1394_REQ_BUS_RESET        10000
+#define RAW1394_REQ_ISO_RECEIVE      10001
+#define RAW1394_REQ_FCP_REQUEST      10002
+#define RAW1394_REQ_ARM              10003
+#define RAW1394_REQ_RAWISO_ACTIVITY  10004
 
 /* error codes */
 #define RAW1394_ERROR_NONE        0
@@ -45,6 +57,17 @@
 #define RAW1394_ERROR_ABORTED     (-1101)
 #define RAW1394_ERROR_TIMEOUT     (-1102)
 
+/* arm_codes */
+#define ARM_READ   1
+#define ARM_WRITE  2
+#define ARM_LOCK   4
+
+#define RAW1394_LONG_RESET  0
+#define RAW1394_SHORT_RESET 1
+
+/* busresetnotify ... */
+#define RAW1394_NOTIFY_OFF 0
+#define RAW1394_NOTIFY_ON  1
 
 #include <asm/types.h>
 
@@ -69,52 +92,83 @@
         __u8 name[32];
 };
 
-#ifdef __KERNEL__
-
-struct iso_block_store {
-        atomic_t refcount;
-        size_t data_size;
-        quadlet_t data[0];
-};
-
-struct file_info {
-        struct list_head list;
-
-        enum { opened, initialized, connected } state;
-        unsigned int protocol_version;
-
-        struct hpsb_host *host;
-
-        struct list_head req_pending;
-        struct list_head req_complete;
-        struct semaphore complete_sem;
-        spinlock_t reqlists_lock;
-        wait_queue_head_t poll_wait_complete;
-
-        u8 *fcp_buffer;
-
-        u64 listen_channels;
-        quadlet_t *iso_buffer;
-        size_t iso_buffer_length;
-};
-
-struct pending_request {
-        struct list_head list;
-        struct file_info *file_info;
-        struct hpsb_packet *packet;
-        struct tq_struct tq;
-        struct iso_block_store *ibs;
-        quadlet_t *data;
-        int free_data;
-        struct raw1394_request req;
-};
-
-struct host_info {
-        struct list_head list;
-        struct hpsb_host *host;
-        struct list_head file_info_list;
+typedef struct arm_request {
+        __u16           destination_nodeid;
+        __u16           source_nodeid;
+        __u64           destination_offset;
+        __u8            tlabel;
+        __u8            tcode;
+        __u8            extended_transaction_code;
+        __u32           generation;
+        __u16           buffer_length;
+        __u8            *buffer;
+} *arm_request_t;
+
+typedef struct arm_response {
+        __s32           response_code;
+        __u16           buffer_length;
+        __u8            *buffer;
+} *arm_response_t;
+
+typedef struct arm_request_response {
+        struct arm_request  *request;
+        struct arm_response *response;
+} *arm_request_response_t;
+
+/* rawiso API */
+#include "ieee1394-ioctl.h"
+
+/* per-packet metadata embedded in the ringbuffer */
+/* must be identical to hpsb_iso_packet_info in iso.h! */
+struct raw1394_iso_packet_info {
+	__u32 offset;
+	__u16 len;
+	__u16 cycle;   /* recv only */
+	__u8  channel; /* recv only */
+	__u8  tag;
+	__u8  sy;
+};
+
+/* argument for RAW1394_ISO_RECV/XMIT_PACKETS ioctls */
+struct raw1394_iso_packets {
+	__u32 n_packets;
+	struct raw1394_iso_packet_info *infos;
+};
+
+struct raw1394_iso_config {
+	/* size of packet data buffer, in bytes (will be rounded up to PAGE_SIZE) */
+	__u32 data_buf_size;
+
+	/* # of packets to buffer */
+	__u32 buf_packets;
+
+	/* iso channel (set to -1 for multi-channel recv) */
+	__s32 channel;
+
+	/* xmit only - iso transmission speed */
+	__u8 speed;
+
+	/* max. latency of buffer, in packets (-1 if you don't care) */
+	__s32 irq_interval;
+};
+
+/* argument to RAW1394_ISO_XMIT/RECV_INIT and RAW1394_ISO_GET_STATUS */
+struct raw1394_iso_status {
+	/* current settings */
+	struct raw1394_iso_config config;
+
+	/* number of packets waiting to be filled with data (ISO transmission)
+	   or containing data received (ISO reception) */
+	__u32 n_packets;
+
+	/* approximate number of packets dropped due to overflow or
+	   underflow of the packet buffer (a value of zero guarantees
+	   that no packets have been dropped) */
+	__u32 overflows;
+
+	/* cycle number at which next packet will be transmitted;
+	   -1 if not known */
+	__s16 xmit_cycle;
 };
 
-#endif /* __KERNEL__ */
-
 #endif /* IEEE1394_RAW1394_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/sbp2.c linux-2.4.21-pre6/drivers/ieee1394/sbp2.c
--- linux-2.4.20/drivers/ieee1394/sbp2.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ieee1394/sbp2.c	2003-03-26 23:49:07.000000000 +0000
@@ -84,7 +84,7 @@
  * sbp2_serialize_io		- Serialize all I/O coming down from the scsi drivers 
  *				  (0 = deserialized, 1 = serialized, default = 0)
  * sbp2_max_sectors, 		- Change max sectors per I/O supported (default = 255)
- * sbp2_max_outstanding_cmds	- Change max outstanding concurrent commands (default = 8)
+ * sbp2_max_outstanding_cmds	- Change max outstanding concurrent commands (default = 64)
  * sbp2_max_cmds_per_lun	- Change max concurrent commands per sbp2 device (default = 1)
  * sbp2_exclusive_login		- Set to zero if you'd like to allow multiple hosts the ability
  *				  to log in at the same time. Sbp2 device must support this,
@@ -298,6 +298,9 @@
  *		   returns the dead bit in status. Thanks to Chandan (chandan@toad.net) for this one.
  *	04/27/02 - Fix sbp2 login problem on SMP systems, enable real spinlocks by default. (JSG)
  *	06/09/02 - Don't force 36-bute SCSI inquiry, but leave in a define for badly behaved devices. (JSG)   
+ *	02/04/03 - Fixed a SMP deadlock (don't hold sbp2_command_lock while calling sbp2scsi_complete_command).
+ *		   Also save/restore irq flags in sbp2scsi_complete_command  - Sancho Dauskardt <sda@bdit.de>
+ *
  */
 
 
@@ -320,7 +323,6 @@
 #include <linux/blk.h>
 #include <linux/smp_lock.h>
 #include <linux/init.h>
-#include <linux/blk.h>
 #include <asm/current.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -351,7 +353,7 @@
 #include "sbp2.h"
 
 static char version[] __devinitdata =
-	"$Rev: 584 $ James Goodwin <jamesg@filanet.com>";
+	"$Rev: 792 $ James Goodwin <jamesg@filanet.com>";
 
 /*
  * Module load parameter definitions
@@ -400,7 +402,7 @@
  * sbp2 devices attached (or if you need to do some debugging).
  */
 MODULE_PARM(sbp2_max_outstanding_cmds,"i");
-MODULE_PARM_DESC(sbp2_max_outstanding_cmds, "Change max outstanding concurrent commands (default = 8)");
+MODULE_PARM_DESC(sbp2_max_outstanding_cmds, "Change max outstanding concurrent commands (default = 64)");
 static int sbp2_max_outstanding_cmds = SBP2SCSI_MAX_OUTSTANDING_CMDS;
 
 /*
@@ -421,8 +423,9 @@
  * talking to a single sbp2 device at the same time (filesystem coherency,
  * etc.). If you're running an sbp2 device that supports multiple logins,
  * and you're either running read-only filesystems or some sort of special
- * filesystem supporting multiple hosts, then set sbp2_exclusive_login to
- * zero. Note: The Oxsemi OXFW911 sbp2 chipset supports up to four
+ * filesystem supporting multiple hosts (one such filesystem is OpenGFS,
+ * see opengfs.sourceforge.net for more info), then set sbp2_exclusive_login
+ * to zero. Note: The Oxsemi OXFW911 sbp2 chipset supports up to four
  * concurrent logins.
  */
 MODULE_PARM(sbp2_exclusive_login,"i");
@@ -513,22 +516,10 @@
 #define SBP2_ERR(fmt, args...)		HPSB_ERR("sbp2: "fmt, ## args)
 
 /*
- * Spinlock debugging stuff.
+ * Globals
  */
-#define SBP2_USE_REAL_SPINLOCKS
 
-#ifdef SBP2_USE_REAL_SPINLOCKS
-#define sbp2_spin_lock(lock, flags)	spin_lock_irqsave(lock, flags)	
-#define sbp2_spin_unlock(lock, flags)	spin_unlock_irqrestore(lock, flags);
 static spinlock_t sbp2_host_info_lock = SPIN_LOCK_UNLOCKED;
-#else
-#define sbp2_spin_lock(lock, flags)	do {save_flags(flags); cli();} while (0)	
-#define sbp2_spin_unlock(lock, flags)	do {restore_flags(flags);} while (0)
-#endif
-
-/*
- * Globals
- */
 
 static Scsi_Host_Template scsi_driver_template;
 
@@ -724,7 +715,7 @@
 	/* 
 	 * Go through free list releasing packets
 	 */
-	sbp2_spin_lock(&hi->sbp2_request_packet_lock, flags);
+	spin_lock_irqsave(&hi->sbp2_request_packet_lock, flags);
 	while (!list_empty(&hi->sbp2_req_free)) {
 
 		lh = hi->sbp2_req_free.next;
@@ -741,7 +732,7 @@
 
 	}
 	kfree(hi->request_packet);
-	sbp2_spin_unlock(&hi->sbp2_request_packet_lock, flags);
+	spin_unlock_irqrestore(&hi->sbp2_request_packet_lock, flags);
 
 	return;
 }
@@ -763,7 +754,7 @@
 	struct hpsb_packet *packet;
 	unsigned long flags;
 
-	sbp2_spin_lock(&hi->sbp2_request_packet_lock, flags);
+	spin_lock_irqsave(&hi->sbp2_request_packet_lock, flags);
 	if (!list_empty(&hi->sbp2_req_free)) {
 
 		/*
@@ -800,8 +791,9 @@
 		 * Set up a task queue completion routine, which returns
 		 * the packet to the free list and releases the tlabel.
 		 */
-		request_packet->tq.routine = (void (*)(void*))sbp2util_free_request_packet;
-		request_packet->tq.data = request_packet;
+		PREPARE_TQUEUE(&request_packet->tq,
+				  (void (*)(void*))sbp2util_free_request_packet,
+				  request_packet);
 		request_packet->hi_context = hi;
 		hpsb_add_packet_complete_task(packet, &request_packet->tq);
 
@@ -813,7 +805,7 @@
 	} else {
 		SBP2_ERR("sbp2util_allocate_request_packet - no packets available!");
 	}
-	sbp2_spin_unlock(&hi->sbp2_request_packet_lock, flags);
+	spin_unlock_irqrestore(&hi->sbp2_request_packet_lock, flags);
 
 	return(request_packet);
 }
@@ -830,12 +822,12 @@
 	/*
 	 * Free the tlabel, and return the packet to the free pool.
 	 */
-	sbp2_spin_lock(&hi->sbp2_request_packet_lock, flags);
+	spin_lock_irqsave(&hi->sbp2_request_packet_lock, flags);
 	free_tlabel(hi->host, LOCAL_BUS | request_packet->packet->node_id,
 		    request_packet->packet->tlabel);
 	list_del(&request_packet->list);
 	list_add_tail(&request_packet->list, &hi->sbp2_req_free);
-	sbp2_spin_unlock(&hi->sbp2_request_packet_lock, flags);
+	spin_unlock_irqrestore(&hi->sbp2_request_packet_lock, flags);
 
 	return;
 }
@@ -851,12 +843,12 @@
 	unsigned long flags;
 	struct sbp2_command_info *command;
         
-	sbp2_spin_lock(&scsi_id->sbp2_command_orb_lock, flags);
+	spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
 	for (i = 0; i < scsi_id->sbp2_total_command_orbs; i++) {
 		command = (struct sbp2_command_info *)
 		    kmalloc(sizeof(struct sbp2_command_info), GFP_KERNEL);
 		if (!command) {
-			sbp2_spin_unlock(&scsi_id->sbp2_command_orb_lock, flags);
+			spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
 			return(-ENOMEM);
 		}
 		memset(command, '\0', sizeof(struct sbp2_command_info));
@@ -873,7 +865,7 @@
 		INIT_LIST_HEAD(&command->list);
 		list_add_tail(&command->list, &scsi_id->sbp2_command_orb_completed);
 	}
-	sbp2_spin_unlock(&scsi_id->sbp2_command_orb_lock, flags);
+	spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
 	return 0;
 }
 
@@ -887,7 +879,7 @@
 	struct sbp2_command_info *command;
 	unsigned long flags;
         
-	sbp2_spin_lock(&scsi_id->sbp2_command_orb_lock, flags);
+	spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
 	if (!list_empty(&scsi_id->sbp2_command_orb_completed)) {
 		list_for_each_safe(lh, next, &scsi_id->sbp2_command_orb_completed) {
 			command = list_entry(lh, struct sbp2_command_info, list);
@@ -905,7 +897,7 @@
 			kfree(command);
 		}
 	}
-	sbp2_spin_unlock(&scsi_id->sbp2_command_orb_lock, flags);
+	spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
 	return;
 }
 
@@ -920,17 +912,17 @@
 	struct sbp2_command_info *command;
 	unsigned long flags;
 
-	sbp2_spin_lock(&scsi_id->sbp2_command_orb_lock, flags);
+	spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
 	if (!list_empty(&scsi_id->sbp2_command_orb_inuse)) {
 		list_for_each(lh, &scsi_id->sbp2_command_orb_inuse) {
 			command = list_entry(lh, struct sbp2_command_info, list);
 			if (command->command_orb_dma == orb) {
-				sbp2_spin_unlock(&scsi_id->sbp2_command_orb_lock, flags);
+				spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
 				return (command);
 			}
 		}
 	}
-	sbp2_spin_unlock(&scsi_id->sbp2_command_orb_lock, flags);
+	spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
 
 	SBP2_ORB_DEBUG("could not match command orb %x", (unsigned int)orb);
 
@@ -947,17 +939,17 @@
 	struct sbp2_command_info *command;
 	unsigned long flags;
 
-	sbp2_spin_lock(&scsi_id->sbp2_command_orb_lock, flags);
+	spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
 	if (!list_empty(&scsi_id->sbp2_command_orb_inuse)) {
 		list_for_each(lh, &scsi_id->sbp2_command_orb_inuse) {
 			command = list_entry(lh, struct sbp2_command_info, list);
 			if (command->Current_SCpnt == SCpnt) {
-				sbp2_spin_unlock(&scsi_id->sbp2_command_orb_lock, flags);
+				spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
 				return (command);
 			}
 		}
 	}
-	sbp2_spin_unlock(&scsi_id->sbp2_command_orb_lock, flags);
+	spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
 	return(NULL);
 }
 
@@ -974,7 +966,7 @@
 	struct sbp2_command_info *command = NULL;
 	unsigned long flags;
 
-	sbp2_spin_lock(&scsi_id->sbp2_command_orb_lock, flags);
+	spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
 	if (!list_empty(&scsi_id->sbp2_command_orb_completed)) {
 		lh = scsi_id->sbp2_command_orb_completed.next;
 		list_del(lh);
@@ -985,7 +977,7 @@
 	} else {
 		SBP2_ERR("sbp2util_allocate_command_orb - No orbs available!");
 	}
-	sbp2_spin_unlock(&scsi_id->sbp2_command_orb_lock, flags);
+	spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
 	return (command);
 }
 
@@ -1007,13 +999,8 @@
 					 command->dma_size, command->dma_dir);
 			SBP2_DMA_FREE("single bulk");
 		} else if (command->dma_type == CMD_DMA_PAGE) {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,13)
-			pci_unmap_single(hi->host->pdev, command->cmd_dma,
-					 command->dma_size, command->dma_dir);
-#else
 			pci_unmap_page(hi->host->pdev, command->cmd_dma,
 				       command->dma_size, command->dma_dir);
-#endif /* Linux version < 2.4.13 */
 			SBP2_DMA_FREE("single page");
 		} /* XXX: Check for CMD_DMA_NONE bug */
 		command->dma_type = CMD_DMA_NONE;
@@ -1035,11 +1022,11 @@
 {
 	unsigned long flags;
 
-	sbp2_spin_lock(&scsi_id->sbp2_command_orb_lock, flags);
+	spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
 	list_del(&command->list);
 	sbp2util_free_command_dma(command);
 	list_add_tail(&command->list, &scsi_id->sbp2_command_orb_completed);
-	sbp2_spin_unlock(&scsi_id->sbp2_command_orb_lock, flags);
+	spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
 }
 
 
@@ -1162,9 +1149,9 @@
 	/* Complete any pending commands with busy (so they get
 	 * retried) and remove them from our queue
 	 */
-	sbp2_spin_lock(&hi->sbp2_command_lock, flags);
+	spin_lock_irqsave(&hi->sbp2_command_lock, flags);
 	sbp2scsi_complete_all_commands(hi, scsi_id, DID_BUS_BUSY);
-	sbp2_spin_unlock(&hi->sbp2_command_lock, flags);
+	spin_unlock_irqrestore(&hi->sbp2_command_lock, flags);
 }
 
 /*
@@ -1203,9 +1190,9 @@
 		return;
 	}
 
-	sbp2_spin_lock(&sbp2_host_info_lock, flags);
+	spin_lock_irqsave(&sbp2_host_info_lock, flags);
 	list_add_tail(&hi->list, &sbp2_host_info_list);
-	sbp2_spin_unlock(&sbp2_host_info_lock, flags);
+	spin_unlock_irqrestore(&sbp2_host_info_lock, flags);
 
 	/* Register our host with the SCSI stack. */
 	hi->scsi_host = scsi_register (&scsi_driver_template, sizeof(void *));
@@ -1264,7 +1251,7 @@
 
 	SBP2_DEBUG("sbp2_remove_host");
 
-	sbp2_spin_lock(&sbp2_host_info_lock, flags);
+	spin_lock_irqsave(&sbp2_host_info_lock, flags);
 
 	hi = sbp2_find_host_info(host);
 	if (hi != NULL) {
@@ -1275,7 +1262,7 @@
 	else
 		SBP2_ERR("attempt to remove unknown host %p", host);
 
-	sbp2_spin_unlock(&sbp2_host_info_lock, flags);
+	spin_unlock_irqrestore(&sbp2_host_info_lock, flags);
 }
 
 /*
@@ -1515,7 +1502,7 @@
  * physical dma in hardware). Mostly just here for debugging...
  */
 static int sbp2_handle_physdma_write(struct hpsb_host *host, int nodeid, int destid, quadlet_t *data,
-                                     u64 addr, unsigned int length)
+                                     u64 addr, unsigned int length, u16 flags)
 {
 
         /*
@@ -1531,7 +1518,7 @@
  * physical dma in hardware). Mostly just here for debugging...
  */
 static int sbp2_handle_physdma_read(struct hpsb_host *host, int nodeid, quadlet_t *data,
-                                    u64 addr, unsigned int length)
+                                    u64 addr, unsigned int length, u16 flags)
 {
 
         /*
@@ -2146,17 +2133,11 @@
 			command->dma_dir = dma_dir;
 			command->dma_size = sgpnt[0].length;
 			command->dma_type = CMD_DMA_PAGE;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,13)
-			command->cmd_dma = pci_map_single (hi->host->pdev, sgpnt[0].address,
-							   command->dma_size,
-							   command->dma_dir);
-#else
 			command->cmd_dma = pci_map_page(hi->host->pdev,
 							sgpnt[0].page,
 							sgpnt[0].offset,
 							command->dma_size,
 							command->dma_dir);
-#endif /* Linux version < 2.4.13 */
 			SBP2_DMA_ALLOC("single page scatter element");
 
 			command_orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id);
@@ -2702,7 +2683,7 @@
  * This function deals with status writes from the SBP-2 device
  */
 static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int destid,
-				    quadlet_t *data, u64 addr, unsigned int length)
+				    quadlet_t *data, u64 addr, unsigned int length, u16 fl)
 {
 	struct sbp2scsi_host_info *hi = NULL;
 	struct scsi_id_instance_data *scsi_id = NULL;
@@ -2721,16 +2702,16 @@
 		return(RCODE_ADDRESS_ERROR);
 	}
 
-	sbp2_spin_lock(&sbp2_host_info_lock, flags);
+	spin_lock_irqsave(&sbp2_host_info_lock, flags);
 	hi = sbp2_find_host_info(host);
-	sbp2_spin_unlock(&sbp2_host_info_lock, flags);
+	spin_unlock_irqrestore(&sbp2_host_info_lock, flags);
 
 	if (!hi) {
 		SBP2_ERR("host info is NULL - this is bad!");
 		return(RCODE_ADDRESS_ERROR);
 	}
 
-	sbp2_spin_lock(&hi->sbp2_command_lock, flags);
+	spin_lock_irqsave(&hi->sbp2_command_lock, flags);
 
 	/*
 	 * Find our scsi_id structure by looking at the status fifo address written to by
@@ -2741,7 +2722,7 @@
 
 	if (!scsi_id) {
 		SBP2_ERR("scsi_id is NULL - device is gone?");
-		sbp2_spin_unlock(&hi->sbp2_command_lock, flags);
+		spin_unlock_irqrestore(&hi->sbp2_command_lock, flags);
 		return(RCODE_ADDRESS_ERROR);
 	}
 
@@ -2805,13 +2786,6 @@
 			}
 
 			SBP2_ORB_DEBUG("completing command orb %p", &command->command_orb);
-
-			/*
-			 * Complete the SCSI command
-			 */
-			SBP2_DEBUG("Completing SCSI command");
-			sbp2scsi_complete_command(hi, scsi_id, scsi_status, SCpnt, command->Current_done);
-			SBP2_ORB_DEBUG("command orb completed");
 		}
 
 		/*
@@ -2835,7 +2809,23 @@
 		}
 	}
 
-	sbp2_spin_unlock(&hi->sbp2_command_lock, flags);
+	spin_unlock_irqrestore(&hi->sbp2_command_lock, flags);
+
+
+	if (SCpnt) {
+
+		/*
+		 * Complete the SCSI command.
+		 *
+		 * Only do it after we've released the sbp2_command_lock,
+		 * as it might otherwise deadlock with the 
+		 * io_request_lock (in sbp2scsi_queuecommand).
+		 */
+		SBP2_DEBUG("Completing SCSI command");
+		sbp2scsi_complete_command(hi, scsi_id, scsi_status, SCpnt, command->Current_done);
+		SBP2_ORB_DEBUG("command orb completed");
+	}
+
 	return(RCODE_COMPLETE);
 }
 
@@ -2915,12 +2905,12 @@
 	/*
 	 * Try and send our SCSI command
 	 */
-	sbp2_spin_lock(&hi->sbp2_command_lock, flags);
+	spin_lock_irqsave(&hi->sbp2_command_lock, flags);
 	if (sbp2_send_command(hi, scsi_id, SCpnt, done)) {
 		SBP2_ERR("Error sending SCSI command");
 		sbp2scsi_complete_command(hi, scsi_id, SBP2_SCSI_STATUS_SELECTION_TIMEOUT, SCpnt, done);
 	}
-	sbp2_spin_unlock(&hi->sbp2_command_lock, flags);
+	spin_unlock_irqrestore(&hi->sbp2_command_lock, flags);
 
 	return(0);
 }
@@ -2961,10 +2951,14 @@
 
 /*
  * This function is called in order to complete a regular SBP-2 command.
+ *
+ * This can be called in interrupt context.
  */
 static void sbp2scsi_complete_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, u32 scsi_status,
 				      Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
 {
+	unsigned long flags;
+
 	SBP2_DEBUG("sbp2scsi_complete_command");
 
 	/*
@@ -3063,15 +3057,9 @@
 	/*
 	 * Tell scsi stack that we're done with this command
 	 */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	spin_lock_irq(&io_request_lock);
-	done (SCpnt);
-	spin_unlock_irq(&io_request_lock);
-#else
-	spin_lock_irq(hi->scsi_host->host_lock);
+	spin_lock_irqsave(&io_request_lock, flags);
 	done (SCpnt);
-	spin_unlock_irq(hi->scsi_host->host_lock);
-#endif
+	spin_unlock_irqrestore(&io_request_lock, flags);
 
 	return;
 }
@@ -3096,7 +3084,7 @@
 		 * Right now, just return any matching command structures
 		 * to the free pool.
 		 */
-		sbp2_spin_lock(&hi->sbp2_command_lock, flags);
+		spin_lock_irqsave(&hi->sbp2_command_lock, flags);
 		command = sbp2util_find_command_for_SCpnt(scsi_id, SCpnt);
 		if (command) {
 			SBP2_DEBUG("Found command to abort");
@@ -3121,7 +3109,7 @@
 		 */
 		sbp2_agent_reset(hi, scsi_id, SBP2_SEND_NO_WAIT);
 		sbp2scsi_complete_all_commands(hi, scsi_id, DID_BUS_BUSY);		
-		sbp2_spin_unlock(&hi->sbp2_command_lock, flags);
+		spin_unlock_irqrestore(&hi->sbp2_command_lock, flags);
 	}
 
 	return(SUCCESS);
@@ -3148,11 +3136,7 @@
 /*
  * Called by scsi stack to get bios parameters (used by fdisk, and at boot).
  */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,28)
 static int sbp2scsi_biosparam (Scsi_Disk *disk, kdev_t dev, int geom[]) 
-#else
-static int sbp2scsi_biosparam (Scsi_Disk *disk, struct block_device *dev, int geom[]) 
-#endif
 {
 	int heads, sectors, cylinders;
 
@@ -3160,12 +3144,12 @@
 
 	heads = 64;
 	sectors = 32;
-	cylinders = disk->capacity / (heads * sectors);
+	cylinders = (int)disk->capacity / (heads * sectors);
 
 	if (cylinders > 1024) {
 		heads = 255;
 		sectors = 63;
-		cylinders = disk->capacity / (heads * sectors);
+		cylinders = (int)disk->capacity / (heads * sectors);
 	}
 
 	geom[0] = heads;
@@ -3189,13 +3173,9 @@
 	 * we register a scsi host with the scsi stack.
 	 */
 	
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
 	spin_unlock_irq(&io_request_lock);
 	sbp2_init();
 	spin_lock_irq(&io_request_lock);
-#else
-	sbp2_init();
-#endif
 
 	/* We return the number of hosts registered. */
 	return scsi_driver_template.present;
@@ -3253,9 +3233,7 @@
 	.this_id =		-1,
 	.sg_tablesize =		SBP2_MAX_SG_ELEMENTS,
 	.use_clustering =	SBP2_CLUSTERING,
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
 	.use_new_eh_code =	TRUE,
-#endif
 	.emulated =		1,
 	.proc_name =	SBP2_DEVICE_NAME,
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/sbp2.h linux-2.4.21-pre6/drivers/ieee1394/sbp2.h
--- linux-2.4.20/drivers/ieee1394/sbp2.h	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ieee1394/sbp2.h	2003-03-26 23:49:10.000000000 +0000
@@ -23,13 +23,8 @@
 #define SBP2_H
 
 /* Some compatibility code */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
 #define SCSI_REGISTER_HOST(tmpl)	scsi_register_module(MODULE_SCSI_HA, tmpl)
 #define SCSI_UNREGISTER_HOST(tmpl)	scsi_unregister_module(MODULE_SCSI_HA, tmpl)
-#else
-#define SCSI_REGISTER_HOST(tmpl)	scsi_register_host(tmpl)
-#define SCSI_UNREGISTER_HOST(tmpl)	scsi_unregister_host(tmpl)
-#endif
 
 #define SBP2_DEVICE_NAME		"sbp2"
 #define SBP2_DEVICE_NAME_SIZE		4
@@ -270,7 +265,7 @@
 #define SBP2_CLUSTERING			ENABLE_CLUSTERING
 #define SBP2_MAX_SG_ELEMENT_LENGTH	0xf000
 #define SBP2SCSI_MAX_SCSI_IDS		16	/* Max sbp2 device instances supported */
-#define SBP2SCSI_MAX_OUTSTANDING_CMDS	8	/* Max total outstanding sbp2 commands allowed at a time! */
+#define SBP2SCSI_MAX_OUTSTANDING_CMDS	64	/* Max total outstanding sbp2 commands allowed at a time! */
 #define SBP2SCSI_MAX_CMDS_PER_LUN	1 	/* Max outstanding sbp2 commands per device - tune as needed */
 #define SBP2_MAX_SECTORS		255	/* Max sectors supported */
 
@@ -510,9 +505,9 @@
 
 #ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
 static int sbp2_handle_physdma_write(struct hpsb_host *host, int nodeid, int destid, quadlet_t *data,
-                                     u64 addr, unsigned int length);
+                                     u64 addr, unsigned int length, u16 flags);
 static int sbp2_handle_physdma_read(struct hpsb_host *host, int nodeid, quadlet_t *data,
-                                    u64 addr, unsigned int length);
+                                    u64 addr, unsigned int length, u16 flags);
 #endif
 
 /*
@@ -522,7 +517,7 @@
 static int sbp2_reconnect_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id); 
 static int sbp2_logout_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id); 
 static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int destid,
-				    quadlet_t *data, u64 addr, unsigned int length);
+				    quadlet_t *data, u64 addr, unsigned int length, u16 flags);
 static int sbp2_agent_reset(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, u32 flags);
 static int sbp2_create_command_orb(struct sbp2scsi_host_info *hi, 
 				   struct scsi_id_instance_data *scsi_id,
@@ -549,11 +544,7 @@
 static int sbp2scsi_detect (Scsi_Host_Template *tpnt);
 static const char *sbp2scsi_info (struct Scsi_Host *host);
 void sbp2scsi_setup(char *str, int *ints);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,28)
 static int sbp2scsi_biosparam (Scsi_Disk *disk, kdev_t dev, int geom[]);
-#else
-static int sbp2scsi_biosparam (Scsi_Disk *disk, struct block_device *dev, int geom[]);
-#endif
 static int sbp2scsi_abort (Scsi_Cmnd *SCpnt); 
 static int sbp2scsi_reset (Scsi_Cmnd *SCpnt); 
 static int sbp2scsi_queuecommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *));
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/video1394.c linux-2.4.21-pre6/drivers/ieee1394/video1394.c
--- linux-2.4.20/drivers/ieee1394/video1394.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ieee1394/video1394.c	2003-03-26 23:49:08.000000000 +0000
@@ -35,7 +35,6 @@
 #include <linux/poll.h>
 #include <linux/smp_lock.h>
 #include <linux/proc_fs.h>
-#include <linux/tqueue.h>
 #include <linux/delay.h>
 #include <linux/devfs_fs_kernel.h>
 
@@ -52,6 +51,7 @@
 #include "ieee1394_core.h"
 #include "highlevel.h"
 #include "video1394.h"
+#include "dma.h"
 
 #include "ohci1394.h"
 
@@ -65,13 +65,8 @@
 #define vmalloc_32(x) vmalloc(x)
 #endif
 
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,3))
 #define remap_page_range_1394(vma, start, addr, size, prot) \
 	remap_page_range(start, addr, size, prot)
-#else
-#define remap_page_range_1394(vma, start, addr, size, prot) \
-	remap_page_range(vma, start, addr, size, prot)
-#endif
 
 struct it_dma_prg {
 	struct dma_cmd begin;
@@ -96,9 +91,14 @@
 	unsigned int packet_size;
 	unsigned int left_size;
 	unsigned int nb_cmd;
-	unsigned char *buf;
+
+	struct dma_region dma;
+
+	struct dma_prog_region *prg_reg;
+
         struct dma_cmd **ir_prg;
 	struct it_dma_prg **it_prg;
+
 	unsigned int *buffer_status;
         struct timeval *buffer_time; /* time when the buffer was received */
 	unsigned int *last_used_cmd; /* For ISO Transmit with 
@@ -161,74 +161,6 @@
 static devfs_handle_t devfs_handle;
 static struct hpsb_highlevel *hl_handle = NULL;
 
-/* Code taken from bttv.c */
-
-/*******************************/
-/* Memory management functions */
-/*******************************/
-
-static inline unsigned long kvirt_to_bus(unsigned long adr) 
-{
-	unsigned long kva, ret;
-
-	kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
-	kva |= adr & (PAGE_SIZE-1); /* restore the offset */
-	ret = virt_to_bus((void *)kva);
-	return ret;
-}
-
-/* Here we want the physical address of the memory.
- * This is used when initializing the contents of the area.
- */
-static inline unsigned long kvirt_to_pa(unsigned long adr) 
-{
-        unsigned long kva, ret;
-
-	kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
-	kva |= adr & (PAGE_SIZE-1); /* restore the offset */
-	ret = __pa(kva);
-        return ret;
-}
-
-static void * rvmalloc(unsigned long size)
-{
-	void * mem;
-	unsigned long adr;
-
-	size=PAGE_ALIGN(size);
-	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) 
-                {
-			mem_map_reserve(vmalloc_to_page((void *)adr));
-			adr+=PAGE_SIZE;
-			size-=PAGE_SIZE;
-		}
-	}
-	return mem;
-}
-
-static void rvfree(void * mem, unsigned long size)
-{
-        unsigned long adr;
-
-	if (mem) 
-	{
-	        adr=(unsigned long) mem;
-		while ((long) size > 0) 
-                {
-			mem_map_unreserve(vmalloc_to_page((void *)adr));
-			adr+=PAGE_SIZE;
-			size-=PAGE_SIZE;
-		}
-		vfree(mem);
-	}
-}
-/* End of code taken from bttv.c */
 
 static int free_dma_iso_ctx(struct dma_iso_ctx *d)
 {
@@ -240,20 +172,19 @@
 	if (d->iso_tasklet.link.next != NULL)
 		ohci1394_unregister_iso_tasklet(d->ohci, &d->iso_tasklet);
 
-	if (d->buf)
-		rvfree((void *)d->buf, d->num_desc * d->buf_size);
+	dma_region_free(&d->dma);
 
-	if (d->ir_prg) {
-		for (i=0;i<d->num_desc;i++) 
-			if (d->ir_prg[i]) kfree(d->ir_prg[i]);
-		kfree(d->ir_prg);
+	if (d->prg_reg) {
+		for (i = 0; i < d->num_desc; i++)
+			dma_prog_region_free(&d->prg_reg[i]);
+		kfree(d->prg_reg);
 	}
 
-	if (d->it_prg) {
-		for (i=0;i<d->num_desc;i++) 
-			if (d->it_prg[i]) kfree(d->it_prg[i]);
+	if (d->ir_prg)
+		kfree(d->ir_prg);
+
+	if (d->it_prg)
 		kfree(d->it_prg);
-	}
 
 	if (d->buffer_status)
 		kfree(d->buffer_status);
@@ -293,18 +224,17 @@
 	d->frame_size = buf_size;
 	d->buf_size = PAGE_ALIGN(buf_size);
 	d->last_buffer = -1;
-	d->buf = NULL;
-	d->ir_prg = NULL;
 	init_waitqueue_head(&d->waitq);
 
-	d->buf = rvmalloc(d->num_desc * d->buf_size);
+	/* Init the regions for easy cleanup */
+	dma_region_init(&d->dma);
 
-	if (d->buf == NULL) {
+	if (dma_region_alloc(&d->dma, d->num_desc * d->buf_size, ohci->dev,
+			     PCI_DMA_BIDIRECTIONAL)) {
 		PRINT(KERN_ERR, ohci->id, "Failed to allocate dma buffer");
 		free_dma_iso_ctx(d);
 		return NULL;
 	}
-	memset(d->buf, 0, d->num_desc * d->buf_size);
 
 	if (type == OHCI_ISO_RECEIVE)
 		ohci1394_init_iso_tasklet(&d->iso_tasklet, type,
@@ -323,6 +253,17 @@
 	}
 	d->ctx = d->iso_tasklet.context;
 
+	d->prg_reg = kmalloc(d->num_desc * sizeof(struct dma_prog_region),
+			GFP_KERNEL);
+	if (d->prg_reg == NULL) {
+		PRINT(KERN_ERR, ohci->id, "Failed to allocate ir prg regs");
+		free_dma_iso_ctx(d);
+		return NULL;
+	}
+	/* Makes for easier cleanup */
+	for (i = 0; i < d->num_desc; i++)
+		dma_prog_region_init(&d->prg_reg[i]);
+
 	if (type == OHCI_ISO_RECEIVE) {
 		d->ctrlSet = OHCI1394_IsoRcvContextControlSet+32*d->ctx;
 		d->ctrlClear = OHCI1394_IsoRcvContextControlClear+32*d->ctx;
@@ -333,31 +274,27 @@
 				    GFP_KERNEL);
 
 		if (d->ir_prg == NULL) {
-			PRINT(KERN_ERR, ohci->id, 
-			      "Failed to allocate dma ir prg");
+			PRINT(KERN_ERR, ohci->id, "Failed to allocate dma ir prg");
 			free_dma_iso_ctx(d);
 			return NULL;
 		}
 		memset(d->ir_prg, 0, d->num_desc * sizeof(struct dma_cmd *));
-	
+
 		d->nb_cmd = d->buf_size / PAGE_SIZE + 1;
 		d->left_size = (d->frame_size % PAGE_SIZE) ?
 			d->frame_size % PAGE_SIZE : PAGE_SIZE;
  
-		for (i=0;i<d->num_desc;i++) {
-			d->ir_prg[i] = kmalloc(d->nb_cmd * 
-					       sizeof(struct dma_cmd), 
-					       GFP_KERNEL);
-			if (d->ir_prg[i] == NULL) {
-				PRINT(KERN_ERR, ohci->id, 
-				      "Failed to allocate dma ir prg");
+		for (i = 0;i < d->num_desc; i++) {
+			if (dma_prog_region_alloc(&d->prg_reg[i], d->nb_cmd *
+						  sizeof(struct dma_cmd), ohci->dev)) {
+				PRINT(KERN_ERR, ohci->id, "Failed to allocate dma ir prg");
 				free_dma_iso_ctx(d);
 				return NULL;
 			}
+			d->ir_prg[i] = (struct dma_cmd *)d->prg_reg[i].kvirt;
 		}
 
-	}
-	else {  /* OHCI_ISO_TRANSMIT */
+	} else {  /* OHCI_ISO_TRANSMIT */
 		d->ctrlSet = OHCI1394_IsoXmitContextControlSet+16*d->ctx;
 		d->ctrlClear = OHCI1394_IsoXmitContextControlClear+16*d->ctx;
 		d->cmdPtr = OHCI1394_IsoXmitCommandPtr+16*d->ctx;
@@ -388,20 +325,17 @@
 		if (d->frame_size % d->packet_size) {
 			d->nb_cmd++;
 			d->left_size = d->frame_size % d->packet_size;
-		}
-		else
+		} else
 			d->left_size = d->packet_size;
 
-		for (i=0;i<d->num_desc;i++) {
-			d->it_prg[i] = kmalloc(d->nb_cmd * 
-					       sizeof(struct it_dma_prg), 
-					       GFP_KERNEL);
-			if (d->it_prg[i] == NULL) {
-				PRINT(KERN_ERR, ohci->id, 
-				      "Failed to allocate dma it prg");
+		for (i = 0; i < d->num_desc; i++) {
+			if (dma_prog_region_alloc(&d->prg_reg[i], d->nb_cmd *
+						sizeof(struct it_dma_prg), ohci->dev)) {
+				PRINT(KERN_ERR, ohci->id, "Failed to allocate dma it prg");
 				free_dma_iso_ctx(d);
 				return NULL;
 			}
+			d->it_prg[i] = (struct it_dma_prg *)d->prg_reg[i].kvirt;
 		}
 	}
 
@@ -454,7 +388,7 @@
 	int i;
 	d->ir_prg[n][0].status = cpu_to_le32(4);
 	d->ir_prg[n][1].status = cpu_to_le32(PAGE_SIZE-4);
-	for (i=2;i<d->nb_cmd-1;i++)
+	for (i = 2; i < d->nb_cmd - 1; i++)
 		d->ir_prg[n][i].status = cpu_to_le32(PAGE_SIZE);
 	d->ir_prg[n][i].status = cpu_to_le32(d->left_size);
 }
@@ -462,7 +396,8 @@
 static void initialize_dma_ir_prg(struct dma_iso_ctx *d, int n, int flags)
 {
 	struct dma_cmd *ir_prg = d->ir_prg[n];
-	unsigned long buf = (unsigned long)d->buf+n*d->buf_size;
+	struct dma_prog_region *ir_reg = &d->prg_reg[n];
+	unsigned long buf = (unsigned long)d->dma.kvirt + n * d->buf_size;
 	int i;
 
 	/* the first descriptor will read only 4 bytes */
@@ -473,31 +408,37 @@
 	if (flags & VIDEO1394_SYNC_FRAMES)
 		ir_prg[0].control |= cpu_to_le32(DMA_CTL_WAIT);
 
-	ir_prg[0].address = cpu_to_le32(kvirt_to_bus(buf));
-	ir_prg[0].branchAddress =  cpu_to_le32((virt_to_bus(&(ir_prg[1].control)) 
-				    & 0xfffffff0) | 0x1);
+	ir_prg[0].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, buf -
+				(unsigned long)d->dma.kvirt));
+	ir_prg[0].branchAddress = cpu_to_le32((dma_prog_region_offset_to_bus(ir_reg,
+					1 * sizeof(struct dma_cmd)) & 0xfffffff0) | 0x1);
 
 	/* the second descriptor will read PAGE_SIZE-4 bytes */
 	ir_prg[1].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
 		DMA_CTL_BRANCH | (PAGE_SIZE-4));
-	ir_prg[1].address = cpu_to_le32(kvirt_to_bus(buf+4));
-	ir_prg[1].branchAddress =  cpu_to_le32((virt_to_bus(&(ir_prg[2].control)) 
-				    & 0xfffffff0) | 0x1);
+	ir_prg[1].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, (buf + 4) -
+					(unsigned long)d->dma.kvirt));
+	ir_prg[1].branchAddress = cpu_to_le32((dma_prog_region_offset_to_bus(ir_reg,
+					2 * sizeof(struct dma_cmd)) & 0xfffffff0) | 0x1);
 	
 	for (i=2;i<d->nb_cmd-1;i++) {
 		ir_prg[i].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | 
 			DMA_CTL_BRANCH | PAGE_SIZE);
-		ir_prg[i].address = cpu_to_le32(kvirt_to_bus(buf+(i-1)*PAGE_SIZE));
-
-		ir_prg[i].branchAddress =  
-			cpu_to_le32((virt_to_bus(&(ir_prg[i+1].control)) 
-			 & 0xfffffff0) | 0x1);
+		ir_prg[i].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma,
+					        (buf+(i-1)*PAGE_SIZE) -
+						(unsigned long)d->dma.kvirt));
+
+		ir_prg[i].branchAddress =
+			cpu_to_le32((dma_prog_region_offset_to_bus(ir_reg,
+				(i + 1) * sizeof(struct dma_cmd)) & 0xfffffff0) | 0x1);
 	}
 
 	/* the last descriptor will generate an interrupt */
 	ir_prg[i].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | 
 		DMA_CTL_IRQ | DMA_CTL_BRANCH | d->left_size);
-	ir_prg[i].address = cpu_to_le32(kvirt_to_bus(buf+(i-1)*PAGE_SIZE));
+	ir_prg[i].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma,
+					(buf+(i-1)*PAGE_SIZE) -
+					(unsigned long)d->dma.kvirt));
 }
 	
 static void initialize_dma_ir_ctx(struct dma_iso_ctx *d, int tag, int flags)
@@ -559,11 +500,7 @@
 		if (d->ir_prg[i][d->nb_cmd-1].status & cpu_to_le32(0xFFFF0000)) {
 			reset_ir_status(d, i);
 			d->buffer_status[i] = VIDEO1394_BUFFER_READY;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,18)
-			get_fast_time(&d->buffer_time[i]);
-#else
 			do_gettimeofday(&d->buffer_time[i]);
-#endif
 		}
 	}
 
@@ -576,7 +513,7 @@
 static inline void put_timestamp(struct ti_ohci *ohci, struct dma_iso_ctx * d,
 				 int n)
 {
-	unsigned char* buf = d->buf + n * d->buf_size;
+	unsigned char* buf = d->dma.kvirt + n * d->buf_size;
 	u32 cycleTimer;
 	u32 timeStamp;
 
@@ -605,7 +542,7 @@
 	if (n == -1) {
 	  return;
 	}
-	buf = d->buf + n * d->buf_size;
+	buf = d->dma.kvirt + n * d->buf_size;
 
 	timeStamp += (d->last_used_cmd[n] << 12) & 0xffff;
 
@@ -652,7 +589,8 @@
 static void initialize_dma_it_prg(struct dma_iso_ctx *d, int n, int sync_tag)
 {
 	struct it_dma_prg *it_prg = d->it_prg[n];
-	unsigned long buf = (unsigned long)d->buf+n*d->buf_size;
+	struct dma_prog_region *it_reg = &d->prg_reg[n];
+	unsigned long buf = (unsigned long)d->dma.kvirt + n * d->buf_size;
 	int i;
 	d->last_used_cmd[n] = d->nb_cmd - 1;
 	for (i=0;i<d->nb_cmd;i++) {
@@ -676,18 +614,18 @@
 		it_prg[i].end.control = cpu_to_le32(DMA_CTL_OUTPUT_LAST |
 			    	    	     DMA_CTL_BRANCH);
 		it_prg[i].end.address =
-			cpu_to_le32(kvirt_to_bus(buf+i*d->packet_size));
+			cpu_to_le32(dma_region_offset_to_bus(&d->dma, (buf+i*d->packet_size) -
+						(unsigned long)d->dma.kvirt));
 
 		if (i<d->nb_cmd-1) {
 			it_prg[i].end.control |= cpu_to_le32(d->packet_size);
 			it_prg[i].begin.branchAddress = 
-				cpu_to_le32((virt_to_bus(&(it_prg[i+1].begin.control)) 
-				 & 0xfffffff0) | 0x3);
+				cpu_to_le32((dma_prog_region_offset_to_bus(it_reg, (i + 1) *
+					sizeof(struct it_dma_prg)) & 0xfffffff0) | 0x3);
 			it_prg[i].end.branchAddress = 
-				cpu_to_le32((virt_to_bus(&(it_prg[i+1].begin.control)) 
-				 & 0xfffffff0) | 0x3);
-		}
-		else {
+				cpu_to_le32((dma_prog_region_offset_to_bus(it_reg, (i + 1) *
+					sizeof(struct it_dma_prg)) & 0xfffffff0) | 0x3);
+		} else {
 			/* the last prg generates an interrupt */
 			it_prg[i].end.control |= cpu_to_le32(DMA_CTL_UPDATE | 
 				DMA_CTL_IRQ | d->left_size);
@@ -696,15 +634,6 @@
 			it_prg[i].end.branchAddress = 0;
 		}
 		it_prg[i].end.status = 0;
-
-#if 0
-		printk("%d:%d: %08x-%08x ctrl %08x brch %08x d0 %08x d1 %08x\n",n,i,
-		       virt_to_bus(&(it_prg[i].begin.control)),
-		       virt_to_bus(&(it_prg[i].end.control)),
-		       it_prg[i].end.control,
-		       it_prg[i].end.branchAddress,
-		       it_prg[i].data[0], it_prg[i].data[1]);
-#endif
 	}
 }
 
@@ -713,6 +642,7 @@
 	struct ti_ohci *ohci)
 {
 	struct it_dma_prg *it_prg = d->it_prg[n];
+	struct dma_prog_region *it_reg = &d->prg_reg[n];
 	int i;
 
 #if 0
@@ -734,12 +664,12 @@
 
 		if (i < d->nb_cmd-1 && packet_sizes[i+1] != 0) {
 			it_prg[i].end.control |= cpu_to_le32(size);
-			it_prg[i].begin.branchAddress = 
-				cpu_to_le32((virt_to_bus(&(it_prg[i+1].begin.control)) 
-				 & 0xfffffff0) | 0x3);
-			it_prg[i].end.branchAddress = 
-				cpu_to_le32((virt_to_bus(&(it_prg[i+1].begin.control)) 
-				 & 0xfffffff0) | 0x3);
+			it_prg[i].begin.branchAddress =
+				cpu_to_le32((dma_prog_region_offset_to_bus(it_reg, (i + 1) *
+					sizeof(struct it_dma_prg)) & 0xfffffff0) | 0x3);
+			it_prg[i].end.branchAddress =
+				cpu_to_le32((dma_prog_region_offset_to_bus(it_reg, (i + 1) *
+					sizeof(struct it_dma_prg)) & 0xfffffff0) | 0x3);
 		} else {
 			/* the last prg generates an interrupt */
 			it_prg[i].end.control |= cpu_to_le32(DMA_CTL_UPDATE | 
@@ -771,37 +701,6 @@
 	reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1<<d->ctx);
 }
 
-static int do_iso_mmap(struct ti_ohci *ohci, struct dma_iso_ctx *d,
-		       struct vm_area_struct *vma)
-{
-        unsigned long start = vma->vm_start;
-	unsigned long size = vma->vm_end - vma->vm_start;
-        unsigned long page, pos;
-
-        if (size > d->num_desc * d->buf_size) {
-		PRINT(KERN_ERR, ohci->id, 
-		      "iso context %d buf size is different from mmap size", 
-		      d->ctx);
-                return -EINVAL;
-	}
-        if (!d->buf) {
-		PRINT(KERN_ERR, ohci->id, 
-		      "iso context %d is not allocated", d->ctx);
-		return -EINVAL;
-	}
-
-	pos = (unsigned long) d->buf;
-        while (size > 0) {
-                page = kvirt_to_pa(pos);
-                if (remap_page_range_1394(vma, start, page, PAGE_SIZE, PAGE_SHARED))
-                        return -EAGAIN;
-                start += PAGE_SIZE;
-                pos += PAGE_SIZE;
-                size -= PAGE_SIZE;
-        }
-        return 0;
-}
-
 static int video1394_ioctl(struct inode *inode, struct file *file,
 			   unsigned int cmd, unsigned long arg)
 {
@@ -814,6 +713,8 @@
 	{
 	case VIDEO1394_LISTEN_CHANNEL:
 	case VIDEO1394_TALK_CHANNEL:
+	case VIDEO1394_IOC_LISTEN_CHANNEL:
+	case VIDEO1394_IOC_TALK_CHANNEL:
 	{
 		struct video1394_mmap v;
 		u64 mask;
@@ -872,7 +773,7 @@
 			return -EFAULT;
 		}
 
-		if (cmd == VIDEO1394_LISTEN_CHANNEL) {
+		if (cmd == VIDEO1394_IOC_LISTEN_CHANNEL || cmd == VIDEO1394_LISTEN_CHANNEL) {
 			d = alloc_dma_iso_ctx(ohci, OHCI_ISO_RECEIVE,
 					      v.nb_buffers, v.buf_size, 
 					      v.channel, 0);
@@ -922,8 +823,10 @@
 
 		return 0;
 	}
-	case VIDEO1394_UNLISTEN_CHANNEL: 
+	case VIDEO1394_UNLISTEN_CHANNEL:
 	case VIDEO1394_UNTALK_CHANNEL:
+	case VIDEO1394_IOC_UNLISTEN_CHANNEL: 
+	case VIDEO1394_IOC_UNTALK_CHANNEL:
 	{
 		int channel;
 		u64 mask;
@@ -947,7 +850,7 @@
 		/* Mark this channel as unused */
 		ohci->ISO_channel_usage &= ~mask;
 
-		if (cmd == VIDEO1394_UNLISTEN_CHANNEL)
+		if (cmd == VIDEO1394_IOC_UNLISTEN_CHANNEL || cmd == VIDEO1394_UNLISTEN_CHANNEL)
 			d = find_ctx(&ctx->context_list, OHCI_ISO_RECEIVE, channel);
 		else
 			d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, channel);
@@ -960,6 +863,7 @@
 		return 0;
 	}
 	case VIDEO1394_LISTEN_QUEUE_BUFFER:
+	case VIDEO1394_IOC_LISTEN_QUEUE_BUFFER:
 	{
 		struct video1394_wait v;
 		struct dma_iso_ctx *d;
@@ -986,10 +890,10 @@
 		
 		d->buffer_status[v.buffer]=VIDEO1394_BUFFER_QUEUED;
 
-		if (d->last_buffer>=0) 
-			d->ir_prg[d->last_buffer][d->nb_cmd-1].branchAddress = 
-				cpu_to_le32((virt_to_bus(&(d->ir_prg[v.buffer][0].control)) 
-				 & 0xfffffff0) | 0x1);
+		if (d->last_buffer>=0)
+			d->ir_prg[d->last_buffer][d->nb_cmd-1].branchAddress =
+				cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[v.buffer], 0)
+					& 0xfffffff0) | 0x1);
 
 		d->last_buffer = v.buffer;
 
@@ -1002,9 +906,9 @@
 			DBGMSG(ohci->id, "Starting iso DMA ctx=%d",d->ctx);
 
 			/* Tell the controller where the first program is */
-			reg_write(ohci, d->cmdPtr, 
-				  virt_to_bus(&(d->ir_prg[v.buffer][0]))|0x1);
-			
+			reg_write(ohci, d->cmdPtr,
+				dma_prog_region_offset_to_bus(&d->prg_reg[v.buffer], 0) | 0x1);
+
 			/* Run IR context */
 			reg_write(ohci, d->ctrlSet, 0x8000);
 		}
@@ -1021,6 +925,8 @@
 	}
 	case VIDEO1394_LISTEN_WAIT_BUFFER:
 	case VIDEO1394_LISTEN_POLL_BUFFER:
+	case VIDEO1394_IOC_LISTEN_WAIT_BUFFER:
+	case VIDEO1394_IOC_LISTEN_POLL_BUFFER:
 	{
 		struct video1394_wait v;
 		struct dma_iso_ctx *d;
@@ -1047,7 +953,8 @@
 			d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE;
 			break;
 		case VIDEO1394_BUFFER_QUEUED:
-			if (cmd == VIDEO1394_LISTEN_POLL_BUFFER) {
+			if (cmd == VIDEO1394_IOC_LISTEN_POLL_BUFFER ||
+			    cmd == VIDEO1394_LISTEN_POLL_BUFFER) {
 			    /* for polling, return error code EINTR */
 			    spin_unlock_irqrestore(&d->lock, flags);
 			    return -EINTR;
@@ -1102,6 +1009,7 @@
 		return 0;
 	}
 	case VIDEO1394_TALK_QUEUE_BUFFER:
+	case VIDEO1394_IOC_TALK_QUEUE_BUFFER:
 	{
 		struct video1394_wait v;
 		struct video1394_queue_variable qv;
@@ -1144,18 +1052,16 @@
 
 		d->buffer_status[v.buffer]=VIDEO1394_BUFFER_QUEUED;
 
-		if (d->last_buffer>=0) {
+		if (d->last_buffer >= 0) {
 			d->it_prg[d->last_buffer]
-				[ d->last_used_cmd[d->last_buffer]
-					].end.branchAddress = 
-				cpu_to_le32((virt_to_bus(&(d->it_prg[v.buffer][0].begin.control)) 
-				 & 0xfffffff0) | 0x3);
+				[ d->last_used_cmd[d->last_buffer] ].end.branchAddress = 
+					cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[v.buffer],
+						0) & 0xfffffff0) | 0x3);
 
 			d->it_prg[d->last_buffer]
-				[d->last_used_cmd[d->last_buffer]
-					].begin.branchAddress = 
-				cpu_to_le32((virt_to_bus(&(d->it_prg[v.buffer][0].begin.control)) 
-				 & 0xfffffff0) | 0x3);
+				[ d->last_used_cmd[d->last_buffer] ].begin.branchAddress =
+					cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[v.buffer],
+						0) & 0xfffffff0) | 0x3);
 			d->next_buffer[d->last_buffer] = v.buffer;
 		}
 		d->last_buffer = v.buffer;
@@ -1172,9 +1078,9 @@
 			put_timestamp(ohci, d, d->last_buffer);
 
 			/* Tell the controller where the first program is */
-			reg_write(ohci, d->cmdPtr, 
-				  virt_to_bus(&(d->it_prg[v.buffer][0]))|0x3);
-			
+			reg_write(ohci, d->cmdPtr,
+				dma_prog_region_offset_to_bus(&d->prg_reg[v.buffer], 0) | 0x3);
+
 			/* Run IT context */
 			reg_write(ohci, d->ctrlSet, 0x8000);
 		}
@@ -1192,6 +1098,7 @@
 		
 	}
 	case VIDEO1394_TALK_WAIT_BUFFER:
+	case VIDEO1394_IOC_TALK_WAIT_BUFFER:
 	{
 		struct video1394_wait v;
 		struct dma_iso_ctx *d;
@@ -1260,7 +1167,7 @@
 	if (ctx->current_ctx == NULL) {
 		PRINT(KERN_ERR, ohci->id, "Current iso context not set");
 	} else
-		res = do_iso_mmap(ohci, ctx->current_ctx, vma);
+		res = dma_region_mmap(&ctx->current_ctx->dma, file, vma);
 	unlock_kernel();
 	return res;
 }
@@ -1455,12 +1362,7 @@
  		return -EIO;
  	}
 	
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
-	devfs_handle = devfs_mk_dir(NULL, VIDEO1394_DRIVER_NAME,
-			strlen(VIDEO1394_DRIVER_NAME), NULL);
-#else
 	devfs_handle = devfs_mk_dir(NULL, VIDEO1394_DRIVER_NAME, NULL);
-#endif
 
 	hl_handle = hpsb_register_highlevel (VIDEO1394_DRIVER_NAME, &hl_ops);
 	if (hl_handle == NULL) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/ieee1394/video1394.h linux-2.4.21-pre6/drivers/ieee1394/video1394.h
--- linux-2.4.20/drivers/ieee1394/video1394.h	2001-12-21 17:41:54.000000000 +0000
+++ linux-2.4.21-pre6/drivers/ieee1394/video1394.h	2003-03-26 23:49:50.000000000 +0000
@@ -21,6 +21,8 @@
 #ifndef _VIDEO_1394_H
 #define _VIDEO_1394_H
 
+#include "ieee1394-ioctl.h"
+
 #define VIDEO1394_DRIVER_NAME "video1394"
 
 #define VIDEO1394_MAX_SIZE 0x4000000
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/input/evdev.c linux-2.4.21-pre6/drivers/input/evdev.c
--- linux-2.4.20/drivers/input/evdev.c	2002-02-25 19:37:58.000000000 +0000
+++ linux-2.4.21-pre6/drivers/input/evdev.c	2003-03-26 23:49:50.000000000 +0000
@@ -223,6 +223,9 @@
 	struct input_dev *dev = evdev->handle.dev;
 	int retval;
 
+	if (!evdev->exist)
+		return -ENODEV;
+
 	switch (cmd) {
 
 		case EVIOCGVERSION:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/input/input.c linux-2.4.21-pre6/drivers/input/input.c
--- linux-2.4.20/drivers/input/input.c	2001-09-30 19:26:05.000000000 +0000
+++ linux-2.4.21-pre6/drivers/input/input.c	2003-03-26 23:49:40.000000000 +0000
@@ -130,6 +130,8 @@
 
 			if (code > MSC_MAX || !test_bit(code, dev->mscbit))
 				return;
+
+			if (dev->event) dev->event(dev, type, code, value);	
 	
 			break;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/input/joydev.c linux-2.4.21-pre6/drivers/input/joydev.c
--- linux-2.4.20/drivers/input/joydev.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/input/joydev.c	2003-03-26 23:49:39.000000000 +0000
@@ -50,6 +50,8 @@
 #define JOYDEV_MINORS		32
 #define JOYDEV_BUFFER_SIZE	64
 
+#define MSECS(t)	(1000 * ((t) / HZ) + 1000 * ((t) % HZ) / HZ)
+
 struct joydev {
 	int exist;
 	int open;
@@ -134,7 +136,7 @@
 			return;
 	}  
 
-	event.time = jiffies * (1000 / HZ);
+	event.time = MSECS(jiffies);
 
 	while (list) {
 
@@ -229,6 +231,9 @@
 
 	if (count < sizeof(struct js_event))
 		return -EINVAL;
+	
+	if (!joydev->exist)
+		return -ENODEV;
 
 	if (count == sizeof(struct JS_DATA_TYPE)) {
 
@@ -256,6 +261,10 @@
 
 		while (list->head == list->tail) {
 
+			if (!joydev->exist) {
+                                retval = -ENODEV;
+                                break;
+                        }
 			if (file->f_flags & O_NONBLOCK) {
 				retval = -EAGAIN;
 				break;
@@ -279,7 +288,7 @@
 
 		struct js_event event;
 
-		event.time = jiffies * (1000/HZ);
+		event.time = MSECS(jiffies);
 
 		if (list->startup < joydev->nkey) {
 			event.type = JS_EVENT_BUTTON | JS_EVENT_INIT;
@@ -327,6 +336,9 @@
 	struct input_dev *dev = joydev->handle.dev;
 	int i;
 
+	if (!joydev->exist)
+		return -ENODEV;
+
 	switch (cmd) {
 
 		case JS_SET_CAL:
@@ -365,7 +377,7 @@
 		case JSIOCSAXMAP:
 			if (copy_from_user(joydev->abspam, (__u8 *) arg, sizeof(__u8) * ABS_MAX))
 				return -EFAULT;
-			for (i = 0; i < ABS_MAX; i++) {
+			for (i = 0; i < joydev->nabs; i++) {
 				if (joydev->abspam[i] > ABS_MAX) return -EINVAL;
 				joydev->absmap[joydev->abspam[i]] = i;
 			}
@@ -374,11 +386,11 @@
 			return copy_to_user((__u8 *) arg, joydev->abspam,
 						sizeof(__u8) * ABS_MAX) ? -EFAULT : 0;
 		case JSIOCSBTNMAP:
-			if (copy_from_user(joydev->absmap, (__u16 *) arg, sizeof(__u16) * (KEY_MAX - BTN_MISC)))
+			if (copy_from_user(joydev->keypam, (__u16 *) arg, sizeof(__u16) * (KEY_MAX - BTN_MISC)))
 				return -EFAULT;
-			for (i = 0; i < KEY_MAX - BTN_MISC; i++); {
+			for (i = 0; i < joydev->nkey; i++) {
 				if (joydev->keypam[i] > KEY_MAX || joydev->keypam[i] < BTN_MISC) return -EINVAL;
-				joydev->keymap[joydev->abspam[i - BTN_MISC]] = i;
+				joydev->keymap[joydev->keypam[i] - BTN_MISC] = i;
 			}
 			return 0;
 		case JSIOCGBTNMAP:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/input/keybdev.c linux-2.4.21-pre6/drivers/input/keybdev.c
--- linux-2.4.20/drivers/input/keybdev.c	2001-10-11 16:14:32.000000000 +0000
+++ linux-2.4.21-pre6/drivers/input/keybdev.c	2003-03-26 23:49:51.000000000 +0000
@@ -201,6 +201,7 @@
 	input_open_device(handle);
 
 //	printk(KERN_INFO "keybdev.c: Adding keyboard: input%d\n", dev->number);
+	kbd_refresh_leds();
 
 	return handle;
 }
@@ -222,6 +223,7 @@
 {
 	input_register_handler(&keybdev_handler);
 	kbd_ledfunc = keybdev_ledfunc;
+	kbd_refresh_leds();
 
 	if (jp_kbd_109) {
 		x86_keycodes[0xb5] = 0x73;	/* backslash, underscore */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/input/mousedev.c linux-2.4.21-pre6/drivers/input/mousedev.c
--- linux-2.4.20/drivers/input/mousedev.c	2001-09-30 19:26:05.000000000 +0000
+++ linux-2.4.21-pre6/drivers/input/mousedev.c	2003-03-26 23:49:29.000000000 +0000
@@ -409,10 +409,13 @@
 	int minor = 0;
 
 	if (!test_bit(EV_KEY, dev->evbit) ||
-	   (!test_bit(BTN_LEFT, dev->keybit) && !test_bit(BTN_TOUCH, dev->keybit)))
+	    (!test_bit(BTN_LEFT, dev->keybit) && 
+	     !test_bit(BTN_MIDDLE, dev->keybit) && 
+	     !test_bit(BTN_TOUCH, dev->keybit)))
 		return NULL;
 
 	if ((!test_bit(EV_REL, dev->evbit) || !test_bit(REL_X, dev->relbit)) &&
+	    (!test_bit(EV_REL, dev->evbit) || !test_bit(REL_WHEEL, dev->relbit)) &&
 	    (!test_bit(EV_ABS, dev->evbit) || !test_bit(ABS_X, dev->absbit)))
 		return NULL;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/isdn/Config.in linux-2.4.21-pre6/drivers/isdn/Config.in
--- linux-2.4.20/drivers/isdn/Config.in	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/isdn/Config.in	2003-03-26 23:48:58.000000000 +0000
@@ -87,8 +87,9 @@
    dep_tristate 'Sedlbauer PCMCIA cards'                              CONFIG_HISAX_SEDLBAUER_CS  $CONFIG_ISDN_DRV_HISAX $CONFIG_PCMCIA
    dep_tristate 'ELSA PCMCIA MicroLink cards'                         CONFIG_HISAX_ELSA_CS       $CONFIG_ISDN_DRV_HISAX $CONFIG_PCMCIA
    dep_tristate 'AVM A1 PCMCIA cards'                                 CONFIG_HISAX_AVM_A1_CS     $CONFIG_ISDN_DRV_HISAX $CONFIG_PCMCIA $CONFIG_HISAX_AVM_A1_PCMCIA
-   dep_tristate 'ST5481 USB ISDN modem (EXPERIMENTAL)'                CONFIG_HISAX_ST5481        $CONFIG_ISDN_DRV_HISAX $CONFIG_USB    $CONFIG_EXPERIMENTAL
+   dep_tristate 'ST5481 USB ISDN modem (EXPERIMENTAL)'                CONFIG_HISAX_ST5481        $CONFIG_ISDN_DRV_HISAX    $CONFIG_EXPERIMENTAL
    dep_tristate 'AVM Fritz!Card PCI/PCIv2/PnP support (EXPERIMENTAL)' CONFIG_HISAX_FRITZ_PCIPNP  $CONFIG_ISDN_DRV_HISAX                $CONFIG_EXPERIMENTAL
+   dep_tristate 'Auerswald devices ISDN support'                      CONFIG_USB_AUERISDN        $CONFIG_ISDN_DRV_HISAX
 
 fi
 endmenu
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/isdn/avmb1/capidrv.c linux-2.4.21-pre6/drivers/isdn/avmb1/capidrv.c
--- linux-2.4.20/drivers/isdn/avmb1/capidrv.c	2001-12-21 17:41:54.000000000 +0000
+++ linux-2.4.21-pre6/drivers/isdn/avmb1/capidrv.c	2003-03-26 23:49:34.000000000 +0000
@@ -105,6 +105,7 @@
 				int oldstate;
 				/* */
 				__u16 datahandle;
+                                spinlock_t lock;
 				struct ncci_datahandle_queue {
 				    struct ncci_datahandle_queue *next;
 				    __u16                         datahandle;
@@ -422,6 +423,7 @@
 	nccip->plcip = plcip;
 	nccip->chan = plcip->chan;
 	nccip->datahandle = 0;
+        nccip->lock = SPIN_LOCK_UNLOCKED;
 
 	nccip->next = plcip->ncci_list;
 	plcip->ncci_list = nccip;
@@ -478,6 +480,7 @@
 		           __u16 datahandle, int len)
 {
 	struct ncci_datahandle_queue *n, **pp;
+	unsigned long flags;
 
 	n = (struct ncci_datahandle_queue *)
 		kmalloc(sizeof(struct ncci_datahandle_queue), GFP_ATOMIC);
@@ -488,25 +491,31 @@
 	n->next = 0;
 	n->datahandle = datahandle;
 	n->len = len;
+	spin_lock_irqsave(&nccip->lock, flags);
 	for (pp = &nccip->ackqueue; *pp; pp = &(*pp)->next) ;
 	*pp = n;
+	spin_unlock_irqrestore(&nccip->lock, flags);
 	return 0;
 }
 
 static int capidrv_del_ack(struct capidrv_ncci *nccip, __u16 datahandle)
 {
 	struct ncci_datahandle_queue **pp, *p;
+	unsigned long flags;
 	int len;
 
+	spin_lock_irqsave(&nccip->lock, flags);
 	for (pp = &nccip->ackqueue; *pp; pp = &(*pp)->next) {
  		if ((*pp)->datahandle == datahandle) {
 			p = *pp;
 			len = p->len;
 			*pp = (*pp)->next;
+	                spin_unlock_irqrestore(&nccip->lock, flags);
 		        kfree(p);
 			return len;
 		}
 	}
+        spin_unlock_irqrestore(&nccip->lock, flags);
 	return -1;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/isdn/avmb1/kcapi.c linux-2.4.21-pre6/drivers/isdn/avmb1/kcapi.c
--- linux-2.4.20/drivers/isdn/avmb1/kcapi.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/isdn/avmb1/kcapi.c	2003-03-26 23:49:53.000000000 +0000
@@ -64,6 +64,7 @@
 	__u32 ncci;
 	__u32 winsize;
 	int   nmsg;
+        spinlock_t lock;
 	struct msgidqueue *msgidqueue;
 	struct msgidqueue *msgidlast;
 	struct msgidqueue *msgidfree;
@@ -640,6 +641,7 @@
 static inline void mq_init(struct capi_ncci * np)
 {
 	int i;
+        np->lock = SPIN_LOCK_UNLOCKED;
 	np->msgidqueue = 0;
 	np->msgidlast = 0;
 	np->nmsg = 0;
@@ -654,8 +656,11 @@
 static inline int mq_enqueue(struct capi_ncci * np, __u16 msgid)
 {
 	struct msgidqueue *mq;
-	if ((mq = np->msgidfree) == 0)
+	spin_lock_bh(&np->lock);
+	if ((mq = np->msgidfree) == 0) {
+	        spin_unlock_bh(&np->lock);
 		return 0;
+	}
 	np->msgidfree = mq->next;
 	mq->msgid = msgid;
 	mq->next = 0;
@@ -665,12 +670,14 @@
 	if (!np->msgidqueue)
 		np->msgidqueue = mq;
 	np->nmsg++;
+	spin_unlock_bh(&np->lock);
 	return 1;
 }
 
 static inline int mq_dequeue(struct capi_ncci * np, __u16 msgid)
 {
 	struct msgidqueue **pp;
+	spin_lock_bh(&np->lock);
 	for (pp = &np->msgidqueue; *pp; pp = &(*pp)->next) {
 		if ((*pp)->msgid == msgid) {
 			struct msgidqueue *mq = *pp;
@@ -680,9 +687,11 @@
 			mq->next = np->msgidfree;
 			np->msgidfree = mq;
 			np->nmsg--;
+	                spin_unlock_bh(&np->lock);
 			return 1;
 		}
 	}
+	spin_unlock_bh(&np->lock);
 	return 0;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/isdn/hisax/Makefile linux-2.4.21-pre6/drivers/isdn/hisax/Makefile
--- linux-2.4.20/drivers/isdn/hisax/Makefile	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/isdn/hisax/Makefile	2003-03-26 23:49:30.000000000 +0000
@@ -10,15 +10,14 @@
 
 # Objects that export symbols.
 
-export-objs	  := config.o hisax_isac.o
+export-objs	  := config.o hisax_isac.o isdnhdlc.o
 
 # Multipart objects.
 
 list-multi	  := hisax.o hisax_st5481.o
 hisax-objs	  := config.o isdnl1.o tei.o isdnl2.o isdnl3.o \
 		     lmgr.o q931.o callc.o fsm.o cert.o
-hisax_st5481-objs := st5481_init.o st5481_usb.o st5481_d.o st5481_b.o \
-		     st5481_hdlc.o
+hisax_st5481-objs := st5481_init.o st5481_usb.o st5481_d.o st5481_b.o
 
 # Optional parts of multipart objects.
 hisax-objs-$(CONFIG_HISAX_EURO) += l3dss1.o
@@ -63,8 +62,9 @@
 obj-$(CONFIG_HISAX_SEDLBAUER_CS)	+= sedlbauer_cs.o
 obj-$(CONFIG_HISAX_ELSA_CS)		+= elsa_cs.o
 obj-$(CONFIG_HISAX_AVM_A1_CS)		+= avma1_cs.o
-obj-$(CONFIG_HISAX_ST5481)		+= hisax_st5481.o
+obj-$(CONFIG_HISAX_ST5481)		+= hisax_st5481.o isdnhdlc.o
 obj-$(CONFIG_HISAX_FRITZ_PCIPNP)        += hisax_isac.o hisax_fcpcipnp.o
+obj-$(CONFIG_USB_AUERISDN)	        += isdnhdlc.o
 
 CERT := $(shell md5sum -c md5sums.asc >> /dev/null;echo $$?)
 CFLAGS_cert.o := -DCERTIFICATION=$(CERT)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/isdn/hisax/amd7930.c linux-2.4.21-pre6/drivers/isdn/hisax/amd7930.c
--- linux-2.4.20/drivers/isdn/hisax/amd7930.c	2001-12-21 17:41:54.000000000 +0000
+++ linux-2.4.21-pre6/drivers/isdn/hisax/amd7930.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,755 +0,0 @@
-/* $Id: amd7930.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
- *
- * HiSax ISDN driver - chip specific routines for AMD 7930
- *
- * Author       Brent Baccala
- * Copyright    by Brent Baccala <baccala@FreeSoft.org>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- *    - Existing ISDN HiSax driver provides all the smarts
- *    - it compiles, runs, talks to an isolated phone switch, connects
- *      to a Cisco, pings go through
- *    - AMD 7930 support only (no DBRI yet)
- *    - no US NI-1 support (may not work on US phone system - untested)
- *    - periodic packet loss, apparently due to lost interrupts
- *    - ISDN sometimes freezes, requiring reboot before it will work again
- *
- * The code is unreliable enough to be consider alpha
- *
- * This file is (c) under GNU General Public License
- *
- * Advanced Micro Devices' Am79C30A is an ISDN/audio chip used in the
- * SparcStation 1+.  The chip provides microphone and speaker interfaces
- * which provide mono-channel audio at 8K samples per second via either
- * 8-bit A-law or 8-bit mu-law encoding.  Also, the chip features an
- * ISDN BRI Line Interface Unit (LIU), I.430 S/T physical interface,
- * which performs basic D channel LAPD processing and provides raw
- * B channel data.  The digital audio channel, the two ISDN B channels,
- * and two 64 Kbps channels to the microprocessor are all interconnected
- * via a multiplexer.
- *
- * This driver interfaces to the Linux HiSax ISDN driver, which performs
- * all high-level Q.921 and Q.931 ISDN functions.  The file is not
- * itself a hardware driver; rather it uses functions exported by
- * the AMD7930 driver in the sparcaudio subsystem (drivers/sbus/audio),
- * allowing the chip to be simultaneously used for both audio and ISDN data.
- * The hardware driver does _no_ buffering, but provides several callbacks
- * which are called during interrupt service and should therefore run quickly.
- *
- * D channel transmission is performed by passing the hardware driver the
- * address and size of an skb's data area, then waiting for a callback
- * to signal successful transmission of the packet.  A task is then
- * queued to notify the HiSax driver that another packet may be transmitted.
- *
- * D channel reception is quite simple, mainly because of:
- *   1) the slow speed of the D channel - 16 kbps, and
- *   2) the presence of an 8- or 32-byte (depending on chip version) FIFO
- *      to buffer the D channel data on the chip
- * Worst case scenario of back-to-back packets with the 8 byte buffer
- * at 16 kbps yields an service time of 4 ms - long enough to preclude
- * the need for fancy buffering.  We queue a background task that copies
- * data out of the receive buffer into an skb, and the hardware driver
- * simply does nothing until we're done with the receive buffer and
- * reset it for a new packet.
- *
- * B channel processing is more complex, because of:
- *   1) the faster speed - 64 kbps,
- *   2) the lack of any on-chip buffering (it interrupts for every byte), and
- *   3) the lack of any chip support for HDLC encapsulation
- *
- * The HiSax driver can put each B channel into one of three modes -
- * L1_MODE_NULL (channel disabled), L1_MODE_TRANS (transparent data relay),
- * and L1_MODE_HDLC (HDLC encapsulation by low-level driver).
- * L1_MODE_HDLC is the most common, used for almost all "pure" digital
- * data sessions.  L1_MODE_TRANS is used for ISDN audio.
- *
- * HDLC B channel transmission is performed via a large buffer into
- * which the skb is copied while performing HDLC bit-stuffing.  A CRC
- * is computed and attached to the end of the buffer, which is then
- * passed to the low-level routines for raw transmission.  Once
- * transmission is complete, the hardware driver is set to enter HDLC
- * idle by successive transmission of mark (all 1) bytes, waiting for
- * the ISDN driver to prepare another packet for transmission and
- * deliver it.
- *
- * HDLC B channel reception is performed via an X-byte ring buffer
- * divided into N sections of X/N bytes each.  Defaults: X=256 bytes, N=4.
- * As the hardware driver notifies us that each section is full, we
- * hand it the next section and schedule a background task to peruse
- * the received section, bit-by-bit, with an HDLC decoder.  As
- * packets are detected, they are copied into a large buffer while
- * decoding HDLC bit-stuffing.  The ending CRC is verified, and if
- * it is correct, we alloc a new skb of the correct length (which we
- * now know), copy the packet into it, and hand it to the upper layers.
- * Optimization: for large packets, we hand the buffer (which also
- * happens to be an skb) directly to the upper layer after an skb_trim,
- * and alloc a new large buffer for future packets, thus avoiding a copy.
- * Then we return to HDLC processing; state is saved between calls.
- * 
- */
-
-#define __NO_VERSION__
-#include "hisax.h"
-#include "../../sbus/audio/amd7930.h"
-#include "isac.h"
-#include "isdnl1.h"
-#include "rawhdlc.h"
-#include <linux/interrupt.h>
-
-static const char *amd7930_revision = "$Revision: 1.1.4.1 $";
-
-#define RCV_BUFSIZE	1024	/* Size of raw receive buffer in bytes */
-#define RCV_BUFBLKS	4	/* Number of blocks to divide buffer into
-				 * (must divide RCV_BUFSIZE) */
-
-static void Bchan_fill_fifo(struct BCState *, struct sk_buff *);
-
-static void
-Bchan_xmt_bh(struct BCState *bcs)
-{
-	struct sk_buff *skb;
-
-	if (bcs->hw.amd7930.tx_skb != NULL) {
-		dev_kfree_skb(bcs->hw.amd7930.tx_skb);
-		bcs->hw.amd7930.tx_skb = NULL;
-	}
-
-	if ((skb = skb_dequeue(&bcs->squeue))) {
-		Bchan_fill_fifo(bcs, skb);
-	} else {
-		clear_bit(BC_FLG_BUSY, &bcs->Flag);
-		bcs->event |= 1 << B_XMTBUFREADY;
-		queue_task(&bcs->tqueue, &tq_immediate);
-		mark_bh(IMMEDIATE_BH);
-	}
-}
-
-static void
-Bchan_xmit_callback(struct BCState *bcs)
-{
-	queue_task(&bcs->hw.amd7930.tq_xmt, &tq_immediate);
-	mark_bh(IMMEDIATE_BH);
-}
-
-/* B channel transmission: two modes (three, if you count L1_MODE_NULL)
- *
- * L1_MODE_HDLC - We need to do HDLC encapsulation before transmiting
- * the packet (i.e. make_raw_hdlc_data).  Since this can be a
- * time-consuming operation, our completion callback just schedules
- * a bottom half to do encapsulation for the next packet.  In between,
- * the link will just idle
- *
- * L1_MODE_TRANS - Data goes through, well, transparent.  No HDLC encap,
- * and we can't just let the link idle, so the "bottom half" actually
- * gets called during the top half (it's our callback routine in this case),
- * but it's a lot faster now since we don't call make_raw_hdlc_data
- */
-
-static void
-Bchan_fill_fifo(struct BCState *bcs, struct sk_buff *skb)
-{
-	struct IsdnCardState *cs = bcs->cs;
-	int len;
-
-	if ((cs->debug & L1_DEB_HSCX) || (cs->debug & L1_DEB_HSCX_FIFO)) {
-		char tmp[1024];
-		char *t = tmp;
-
-		t += sprintf(t, "amd7930_fill_fifo %c cnt %d",
-			     bcs->channel ? 'B' : 'A', skb->len);
-		if (cs->debug & L1_DEB_HSCX_FIFO)
-			QuickHex(t, skb->data, skb->len);
-		debugl1(cs, tmp);
-	}
-
-	if (bcs->mode == L1_MODE_HDLC) {
-		len = make_raw_hdlc_data(skb->data, skb->len,
-					 bcs->hw.amd7930.tx_buff, RAW_BUFMAX);
-		if (len > 0)
-			amd7930_bxmit(0, bcs->channel,
-				      bcs->hw.amd7930.tx_buff, len,
-				      (void *) &Bchan_xmit_callback,
-				      (void *) bcs);
-		dev_kfree_skb(skb);
-	} else if (bcs->mode == L1_MODE_TRANS) {
-		amd7930_bxmit(0, bcs->channel,
-			      bcs->hw.amd7930.tx_buff, skb->len,
-			      (void *) &Bchan_xmt_bh,
-			      (void *) bcs);
-		bcs->hw.amd7930.tx_skb = skb;
-	} else {
-		dev_kfree_skb(skb);
-	}
-}
-
-static void
-Bchan_mode(struct BCState *bcs, int mode, int bc)
-{
-	struct IsdnCardState *cs = bcs->cs;
-
-	if (cs->debug & L1_DEB_HSCX) {
-		char tmp[40];
-		sprintf(tmp, "AMD 7930 mode %d bchan %d/%d",
-			mode, bc, bcs->channel);
-		debugl1(cs, tmp);
-	}
-	bcs->mode = mode;
-}
-
-/* Bchan_l2l1 is the entry point for upper layer routines that want to
- * transmit on the B channel.  PH_DATA_REQ is a normal packet that
- * we either start transmitting (if idle) or queue (if busy).
- * PH_PULL_REQ can be called to request a callback message (PH_PULL_CNF)
- * once the link is idle.  After a "pull" callback, the upper layer
- * routines can use PH_PULL_IND to send data.
- */
-
-static void
-Bchan_l2l1(struct PStack *st, int pr, void *arg)
-{
-	struct sk_buff *skb = arg;
-
-	switch (pr) {
-		case (PH_DATA_REQ):
-			if (test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag)) {
-				skb_queue_tail(&st->l1.bcs->squeue, skb);
-			} else {
-				test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
-				Bchan_fill_fifo(st->l1.bcs, skb);
-			}
-			break;
-		case (PH_PULL_IND):
-			if (test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag)) {
-				printk(KERN_WARNING "amd7930: this shouldn't happen\n");
-				break;
-			}
-			test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
-			Bchan_fill_fifo(st->l1.bcs, skb);
-			break;
-		case (PH_PULL_REQ):
-			if (!test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag)) {
-				clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
-				st->l1.l1l2(st, PH_PULL_CNF, NULL);
-			} else
-				set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
-			break;
-	}
-}
-
-/* Receiver callback and bottom half - decodes HDLC at leisure (if
- * L1_MODE_HDLC) and passes newly received skb on via bcs->rqueue.  If
- * a large packet is received, stick rv_skb (the buffer that the
- * packet has been decoded into) on the receive queue and alloc a new
- * (large) skb to act as buffer for future receives.  If a small
- * packet is received, leave rv_skb alone, alloc a new skb of the
- * correct size, and copy the packet into it
- */
-
-static void
-Bchan_recv_callback(struct BCState *bcs)
-{
-	struct amd7930_hw *hw = &bcs->hw.amd7930;
-
-	hw->rv_buff_in += RCV_BUFSIZE/RCV_BUFBLKS;
-	hw->rv_buff_in %= RCV_BUFSIZE;
-
-	if (hw->rv_buff_in != hw->rv_buff_out) {
-		amd7930_brecv(0, bcs->channel,
-			      hw->rv_buff + hw->rv_buff_in,
-			      RCV_BUFSIZE/RCV_BUFBLKS,
-			      (void *) &Bchan_recv_callback, (void *) bcs);
-	}
-
-	queue_task(&hw->tq_rcv, &tq_immediate);
-	mark_bh(IMMEDIATE_BH);
-}
-
-static void
-Bchan_rcv_bh(struct BCState *bcs)
-{
-	struct IsdnCardState *cs = bcs->cs;
-	struct amd7930_hw *hw = &bcs->hw.amd7930;
-	struct sk_buff *skb;
-	int len;
-
-	if (cs->debug & L1_DEB_HSCX) {
-		char tmp[1024];
-
-		sprintf(tmp, "amd7930_Bchan_rcv (%d/%d)",
-			hw->rv_buff_in, hw->rv_buff_out);
-		debugl1(cs, tmp);
-		QuickHex(tmp, hw->rv_buff + hw->rv_buff_out,
-			 RCV_BUFSIZE/RCV_BUFBLKS);
-		debugl1(cs, tmp);
-	}
-
-	do {
-		if (bcs->mode == L1_MODE_HDLC) {
-			while ((len = read_raw_hdlc_data(hw->hdlc_state,
-							 hw->rv_buff + hw->rv_buff_out, RCV_BUFSIZE/RCV_BUFBLKS,
-							 hw->rv_skb->tail, HSCX_BUFMAX))) {
-				if (len > 0 && (cs->debug & L1_DEB_HSCX_FIFO)) {
-					char tmp[1024];
-					char *t = tmp;
-
-					t += sprintf(t, "amd7930_Bchan_rcv %c cnt %d", bcs->channel ? 'B' : 'A', len);
-					QuickHex(t, hw->rv_skb->tail, len);
-					debugl1(cs, tmp);
-				}
-
-				if (len > HSCX_BUFMAX/2) {
-					/* Large packet received */
-
-					if (!(skb = dev_alloc_skb(HSCX_BUFMAX))) {
-						printk(KERN_WARNING "amd7930: receive out of memory");
-					} else {
-						skb_put(hw->rv_skb, len);
-						skb_queue_tail(&bcs->rqueue, hw->rv_skb);
-						hw->rv_skb = skb;
-						bcs->event |= 1 << B_RCVBUFREADY;
-						queue_task(&bcs->tqueue, &tq_immediate);
-					}
-				} else if (len > 0) {
-					/* Small packet received */
-
-					if (!(skb = dev_alloc_skb(len))) {
-						printk(KERN_WARNING "amd7930: receive out of memory\n");
-					} else {
-						memcpy(skb_put(skb, len), hw->rv_skb->tail, len);
-						skb_queue_tail(&bcs->rqueue, skb);
-						bcs->event |= 1 << B_RCVBUFREADY;
-						queue_task(&bcs->tqueue, &tq_immediate);
-						mark_bh(IMMEDIATE_BH);
-					}
-				} else {
-					/* Reception Error */
-					/* printk("amd7930: B channel receive error\n"); */
-				}
-			}
-		} else if (bcs->mode == L1_MODE_TRANS) {
-			if (!(skb = dev_alloc_skb(RCV_BUFSIZE/RCV_BUFBLKS))) {
-				printk(KERN_WARNING "amd7930: receive out of memory\n");
-			} else {
-				memcpy(skb_put(skb, RCV_BUFSIZE/RCV_BUFBLKS),
-				       hw->rv_buff + hw->rv_buff_out,
-				       RCV_BUFSIZE/RCV_BUFBLKS);
-				skb_queue_tail(&bcs->rqueue, skb);
-				bcs->event |= 1 << B_RCVBUFREADY;
-				queue_task(&bcs->tqueue, &tq_immediate);
-				mark_bh(IMMEDIATE_BH);
-			}
-		}
-
-		if (hw->rv_buff_in == hw->rv_buff_out) {
-			/* Buffer was filled up - need to restart receiver */
-			amd7930_brecv(0, bcs->channel,
-				      hw->rv_buff + hw->rv_buff_in,
-				      RCV_BUFSIZE/RCV_BUFBLKS,
-				      (void *) &Bchan_recv_callback,
-				      (void *) bcs);
-		}
-
-		hw->rv_buff_out += RCV_BUFSIZE/RCV_BUFBLKS;
-		hw->rv_buff_out %= RCV_BUFSIZE;
-
-	} while (hw->rv_buff_in != hw->rv_buff_out);
-}
-
-static void
-Bchan_close(struct BCState *bcs)
-{
-	struct sk_buff *skb;
-
-	Bchan_mode(bcs, 0, 0);
-	amd7930_bclose(0, bcs->channel);
-
-	if (test_bit(BC_FLG_INIT, &bcs->Flag)) {
-		skb_queue_purge(&bcs->rqueue);
-		skb_queue_purge(&bcs->squeue);
-	}
-	test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
-}
-
-static int
-Bchan_open(struct BCState *bcs)
-{
-	struct amd7930_hw *hw = &bcs->hw.amd7930;
-
-	if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
-		skb_queue_head_init(&bcs->rqueue);
-		skb_queue_head_init(&bcs->squeue);
-	}
-	test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
-
-	amd7930_bopen(0, bcs->channel, 0xff);
-	hw->rv_buff_in = 0;
-	hw->rv_buff_out = 0;
-	hw->tx_skb = NULL;
-	init_hdlc_state(hw->hdlc_state, 0);
-	amd7930_brecv(0, bcs->channel,
-		      hw->rv_buff + hw->rv_buff_in, RCV_BUFSIZE/RCV_BUFBLKS,
-		      (void *) &Bchan_recv_callback, (void *) bcs);
-
-	bcs->event = 0;
-	bcs->tx_cnt = 0;
-	return (0);
-}
-
-static void
-Bchan_init(struct BCState *bcs)
-{
-	if (!(bcs->hw.amd7930.tx_buff = kmalloc(RAW_BUFMAX, GFP_ATOMIC))) {
-		printk(KERN_WARNING
-		       "HiSax: No memory for amd7930.tx_buff\n");
-		return;
-	}
-	if (!(bcs->hw.amd7930.rv_buff = kmalloc(RCV_BUFSIZE, GFP_ATOMIC))) {
-		printk(KERN_WARNING
-		       "HiSax: No memory for amd7930.rv_buff\n");
-		return;
-	}
-	if (!(bcs->hw.amd7930.rv_skb = dev_alloc_skb(HSCX_BUFMAX))) {
-		printk(KERN_WARNING
-		       "HiSax: No memory for amd7930.rv_skb\n");
-		return;
-	}
-	if (!(bcs->hw.amd7930.hdlc_state = kmalloc(sizeof(struct hdlc_state),
-						   GFP_ATOMIC))) {
-		printk(KERN_WARNING
-		       "HiSax: No memory for amd7930.hdlc_state\n");
-		return;
-	}
-
-	bcs->hw.amd7930.tq_rcv.sync = 0;
-	bcs->hw.amd7930.tq_rcv.routine = (void (*)(void *)) &Bchan_rcv_bh;
-	bcs->hw.amd7930.tq_rcv.data = (void *) bcs;
-
-	bcs->hw.amd7930.tq_xmt.sync = 0;
-	bcs->hw.amd7930.tq_xmt.routine = (void (*)(void *)) &Bchan_xmt_bh;
-	bcs->hw.amd7930.tq_xmt.data = (void *) bcs;
-}
-
-static void
-Bchan_manl1(struct PStack *st, int pr,
-	  void *arg)
-{
-	switch (pr) {
-		case (PH_ACTIVATE_REQ):
-			test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
-			Bchan_mode(st->l1.bcs, st->l1.mode, st->l1.bc);
-			st->l1.l1man(st, PH_ACTIVATE_CNF, NULL);
-			break;
-		case (PH_DEACTIVATE_REQ):
-			if (!test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag))
-				Bchan_mode(st->l1.bcs, 0, 0);
-			test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
-			break;
-	}
-}
-
-int
-setstack_amd7930(struct PStack *st, struct BCState *bcs)
-{
-	if (Bchan_open(bcs))
-		return (-1);
-	st->l1.bcs = bcs;
-	st->l2.l2l1 = Bchan_l2l1;
-	st->ma.manl1 = Bchan_manl1;
-	setstack_manager(st);
-	bcs->st = st;
-	return (0);
-}
-
-
-static void
-amd7930_drecv_callback(void *arg, int error, unsigned int count)
-{
-	struct IsdnCardState *cs = (struct IsdnCardState *) arg;
-	static struct tq_struct task;
-	struct sk_buff *skb;
-
-        /* NOTE: This function is called directly from an interrupt handler */
-
-	if (1) {
-		if (!(skb = alloc_skb(count, GFP_ATOMIC)))
-			printk(KERN_WARNING "HiSax: D receive out of memory\n");
-		else {
-			memcpy(skb_put(skb, count), cs->rcvbuf, count);
-			skb_queue_tail(&cs->rq, skb);
-		}
-
-		task.routine = (void *) DChannel_proc_rcv;
-		task.data = (void *) cs;
-		queue_task(&task, &tq_immediate);
-		mark_bh(IMMEDIATE_BH);
-	}
-
-	if (cs->debug & L1_DEB_ISAC_FIFO) {
-		char tmp[128];
-		char *t = tmp;
-
-		t += sprintf(t, "amd7930 Drecv cnt %d", count);
-		if (error) t += sprintf(t, " ERR %x", error);
-		QuickHex(t, cs->rcvbuf, count);
-		debugl1(cs, tmp);
-	}
-
-	amd7930_drecv(0, cs->rcvbuf, MAX_DFRAME_LEN,
-		      &amd7930_drecv_callback, cs);
-}
-
-static void
-amd7930_dxmit_callback(void *arg, int error)
-{
-	struct IsdnCardState *cs = (struct IsdnCardState *) arg;
-	static struct tq_struct task;
-
-        /* NOTE: This function is called directly from an interrupt handler */
-
-	/* may wish to do retransmission here, if error indicates collision */
-
-	if (cs->debug & L1_DEB_ISAC_FIFO) {
-		char tmp[128];
-		char *t = tmp;
-
-		t += sprintf(t, "amd7930 Dxmit cnt %d", cs->tx_skb->len);
-		if (error) t += sprintf(t, " ERR %x", error);
-		QuickHex(t, cs->tx_skb->data, cs->tx_skb->len);
-		debugl1(cs, tmp);
-	}
-
-	cs->tx_skb = NULL;
-
-	task.routine = (void *) DChannel_proc_xmt;
-	task.data = (void *) cs;
-	queue_task(&task, &tq_immediate);
-	mark_bh(IMMEDIATE_BH);
-}
-
-static void
-amd7930_Dchan_l2l1(struct PStack *st, int pr, void *arg)
-{
-	struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
-	struct sk_buff *skb = arg;
-	char str[64];
-
-	switch (pr) {
-		case (PH_DATA_REQ):
-			if (cs->tx_skb) {
-				skb_queue_tail(&cs->sq, skb);
-#ifdef L2FRAME_DEBUG		/* psa */
-				if (cs->debug & L1_DEB_LAPD)
-					Logl2Frame(cs, skb, "PH_DATA Queued", 0);
-#endif
-			} else {
-				if ((cs->dlogflag) && (!(skb->data[2] & 1))) {
-					/* I-FRAME */
-					LogFrame(cs, skb->data, skb->len);
-					sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei);
-					dlogframe(cs, skb->data+4, skb->len-4,
-						  str);
-				}
-				cs->tx_skb = skb;
-				cs->tx_cnt = 0;
-#ifdef L2FRAME_DEBUG		/* psa */
-				if (cs->debug & L1_DEB_LAPD)
-					Logl2Frame(cs, skb, "PH_DATA", 0);
-#endif
-				amd7930_dxmit(0, skb->data, skb->len,
-					      &amd7930_dxmit_callback, cs);
-			}
-			break;
-		case (PH_PULL_IND):
-			if (cs->tx_skb) {
-				if (cs->debug & L1_DEB_WARN)
-					debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
-				skb_queue_tail(&cs->sq, skb);
-				break;
-			}
-			if ((cs->dlogflag) && (!(skb->data[2] & 1))) {	/* I-FRAME */
-				LogFrame(cs, skb->data, skb->len);
-				sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei);
-				dlogframe(cs, skb->data + 4, skb->len - 4,
-					  str);
-			}
-			cs->tx_skb = skb;
-			cs->tx_cnt = 0;
-#ifdef L2FRAME_DEBUG		/* psa */
-			if (cs->debug & L1_DEB_LAPD)
-				Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
-#endif
-			amd7930_dxmit(0, cs->tx_skb->data, cs->tx_skb->len,
-				      &amd7930_dxmit_callback, cs);
-			break;
-		case (PH_PULL_REQ):
-#ifdef L2FRAME_DEBUG		/* psa */
-			if (cs->debug & L1_DEB_LAPD)
-				debugl1(cs, "-> PH_REQUEST_PULL");
-#endif
-			if (!cs->tx_skb) {
-				test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
-				st->l1.l1l2(st, PH_PULL_CNF, NULL);
-			} else
-				test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
-			break;
-	}
-}
-
-int
-setDstack_amd7930(struct PStack *st, struct IsdnCardState *cs)
-{
-	st->l2.l2l1 = amd7930_Dchan_l2l1;
-	if (! cs->rcvbuf) {
-		printk("setDstack_amd7930: No cs->rcvbuf!\n");
-	} else {
-		amd7930_drecv(0, cs->rcvbuf, MAX_DFRAME_LEN,
-			      &amd7930_drecv_callback, cs);
-	}
-	return (0);
-}
-
-static void
-manl1_msg(struct IsdnCardState *cs, int msg, void *arg) {
-	struct PStack *st;
-
-	st = cs->stlist;
-	while (st) {
-		st->ma.manl1(st, msg, arg);
-		st = st->next;
-	}
-}
-
-static void
-amd7930_new_ph(struct IsdnCardState *cs)
-{
-	switch (amd7930_get_liu_state(0)) {
-	        case 3:
-			manl1_msg(cs, PH_POWERUP_CNF, NULL);
-                        break;
-
-	        case 7:
-			manl1_msg(cs, PH_I4_P8_IND, NULL);
-			break;
-
-	        case 8:
-			manl1_msg(cs, PH_RSYNC_IND, NULL);
-			break;
-	}
-}
-
-/* amd7930 LIU state change callback */
-
-static void
-amd7930_liu_callback(struct IsdnCardState *cs)
-{
-	static struct tq_struct task;
-
-	if (!cs)
-		return;
-
-	if (cs->debug & L1_DEB_ISAC) {
-		char tmp[32];
-		sprintf(tmp, "amd7930_liu state %d", amd7930_get_liu_state(0));
-		debugl1(cs, tmp);
-	}
-
-	task.sync = 0;
-	task.routine = (void *) &amd7930_new_ph;
-	task.data = (void *) cs;
-	queue_task(&task, &tq_immediate);
-	mark_bh(IMMEDIATE_BH);
-}
-
-void
-amd7930_l1cmd(struct IsdnCardState *cs, int msg, void *arg)
-{
-	u_char val;
-	char tmp[32];
-	
-	if (cs->debug & L1_DEB_ISAC) {
-		char tmp[32];
-		sprintf(tmp, "amd7930_l1cmd msg %x", msg);
-		debugl1(cs, tmp);
-	}
-
-	switch(msg) {
-		case PH_RESET_REQ:
-			if (amd7930_get_liu_state(0) <= 3)
-				amd7930_liu_activate(0,0);
-			else
-				amd7930_liu_deactivate(0);
-			break;
-		case PH_ENABLE_REQ:
-			break;
-		case PH_INFO3_REQ:
-			amd7930_liu_activate(0,0);
-			break;
-		case PH_TESTLOOP_REQ:
-			break;
-		default:
-			if (cs->debug & L1_DEB_WARN) {
-				sprintf(tmp, "amd7930_l1cmd unknown %4x", msg);
-				debugl1(cs, tmp);
-			}
-			break;
-	}
-}
-
-static void init_amd7930(struct IsdnCardState *cs)
-{
-	Bchan_init(&cs->bcs[0]);
-	Bchan_init(&cs->bcs[1]);
-	cs->bcs[0].BC_SetStack = setstack_amd7930;
-	cs->bcs[1].BC_SetStack = setstack_amd7930;
-	cs->bcs[0].BC_Close = Bchan_close;
-	cs->bcs[1].BC_Close = Bchan_close;
-	Bchan_mode(cs->bcs, 0, 0);
-	Bchan_mode(cs->bcs + 1, 0, 0);
-}
-
-void
-release_amd7930(struct IsdnCardState *cs)
-{
-}
-
-static int
-amd7930_card_msg(struct IsdnCardState *cs, int mt, void *arg)
-{
-	switch (mt) {
-		case CARD_RESET:
-			return(0);
-		case CARD_RELEASE:
-			release_amd7930(cs);
-			return(0);
-		case CARD_INIT:
-			cs->l1cmd = amd7930_l1cmd;
-			amd7930_liu_init(0, &amd7930_liu_callback, (void *)cs);
-			init_amd7930(cs);
-			return(0);
-		case CARD_TEST:
-			return(0);
-	}
-	return(0);
-}
-
-int __init
-setup_amd7930(struct IsdnCard *card)
-{
-	struct IsdnCardState *cs = card->cs;
-	char tmp[64];
-
-	strcpy(tmp, amd7930_revision);
-	printk(KERN_INFO "HiSax: AMD7930 driver Rev. %s\n", HiSax_getrev(tmp));
-	if (cs->typ != ISDN_CTYPE_AMD7930)
-		return (0);
-
-        cs->irq = amd7930_get_irqnum(0);
-        if (cs->irq == 0)
-		return (0);
-
-	cs->cardmsg = &amd7930_card_msg;
-
-	return (1);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/isdn/hisax/hisax.h linux-2.4.21-pre6/drivers/isdn/hisax/hisax.h
--- linux-2.4.20/drivers/isdn/hisax/hisax.h	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/isdn/hisax/hisax.h	2003-03-26 23:49:50.000000000 +0000
@@ -472,6 +472,8 @@
 #define BC_FLG_FTI_RUN	13
 #define BC_FLG_LL_OK	14
 #define BC_FLG_LL_CONN	15
+#define BC_FLG_FTI_FTS	16
+#define BC_FLG_FRH_WAIT	17
 
 #define L1_MODE_NULL	0
 #define L1_MODE_TRANS	1
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/isdn/hisax/isar.c linux-2.4.21-pre6/drivers/isdn/hisax/isar.c
--- linux-2.4.20/drivers/isdn/hisax/isar.c	2001-12-21 17:41:54.000000000 +0000
+++ linux-2.4.21-pre6/drivers/isdn/hisax/isar.c	2003-03-26 23:49:34.000000000 +0000
@@ -21,10 +21,12 @@
 #define DLE	0x10
 #define ETX	0x03
 
-
-const u_char faxmodulation_s[] = "3,24,48,72,73,74,96,97,98,121,122,145,146"; 
-const u_char faxmodulation[] = {3,24,48,72,73,74,96,97,98,121,122,145,146}; 
-#define FAXMODCNT 13
+#define FAXMODCNT	13
+const	u_char	faxmodulation[] = {3,24,48,72,73,74,96,97,98,121,122,145,146};
+static	u_int	modmask = 0x1fff;
+static	int	frm_extra_delay = 2;
+static	int	para_TOA = 6;
+const   u_char  *FC1_CMD[] = {"FAE", "FTS", "FRS", "FTM", "FRM", "FTH", "FRH", "CTRL" };
 
 void isar_setup(struct IsdnCardState *cs);
 static void isar_pump_cmd(struct BCState *bcs, u_char cmd, u_char para);
@@ -125,7 +127,7 @@
 	ireg->clsb = cs->BC_Read_Reg(cs, 1, ISAR_CTRL_L);
 #if DUMP_MBOXFRAME
 	if (cs->debug & L1_DEB_HSCX)
-		debugl1(cs, "rcv_mbox(%02x,%02x,%d)", ireg->iis, ireg->cmsb,
+		debugl1(cs, "irq_stat(%02x,%02x,%d)", ireg->iis, ireg->cmsb,
 			ireg->clsb);
 #endif
 }
@@ -412,6 +414,7 @@
 	}
 	cs->debug = debug;
 	isar_setup(cs);
+
 	ret = 0;
 reterrflg:
 	restore_flags(flags);
@@ -581,7 +584,6 @@
 				if (ireg->cmsb & SART_NMD) { /* ABORT */
 					if (cs->debug & L1_DEB_WARN)
 						debugl1(cs, "isar_rcv_frame: no more data");
-					cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
 					bcs->hw.isar.rcvidx = 0;
 					send_DLE_ETX(bcs);
 					sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) |
@@ -592,7 +594,6 @@
 				}
 			} else {
 				printk(KERN_WARNING "HiSax: skb out of memory\n");
-				cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
 			}
 			break;
 		}
@@ -617,8 +618,9 @@
 			bcs->hw.isar.rcvidx = 0;
 			cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
 		} else {
-			if (ireg->cmsb & HDLC_FSD)
+			if (ireg->cmsb & HDLC_FSD) {
 				bcs->hw.isar.rcvidx = 0;
+			}
 			ptr = bcs->hw.isar.rcvbuf + bcs->hw.isar.rcvidx;
 			bcs->hw.isar.rcvidx += ireg->clsb;
 			rcv_mbox(cs, ireg, ptr);
@@ -629,6 +631,8 @@
 					if (cs->debug & L1_DEB_WARN)
 						debugl1(cs, "isar frame to short %d",
 							bcs->hw.isar.rcvidx);
+					printk(KERN_WARNING "ISAR: frame to short %d\n",
+						bcs->hw.isar.rcvidx);
 				} else if (!(skb = dev_alloc_skb(bcs->hw.isar.rcvidx))) {
 					printk(KERN_WARNING "ISAR: receive out of memory\n");
 				} else {
@@ -639,6 +643,7 @@
 					isar_sched_event(bcs, B_RCVBUFREADY);
 					send_DLE_ETX(bcs);
 					isar_sched_event(bcs, B_LL_OK);
+					test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag);
 				}
 				bcs->hw.isar.rcvidx = 0;
 			}
@@ -646,13 +651,14 @@
 		if (ireg->cmsb & SART_NMD) { /* ABORT */
 			if (cs->debug & L1_DEB_WARN)
 				debugl1(cs, "isar_rcv_frame: no more data");
-			cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
 			bcs->hw.isar.rcvidx = 0;
-			send_DLE_ETX(bcs);
 			sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) |
 				ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 0, NULL);
 			bcs->hw.isar.state = STFAX_ESCAPE;
-			isar_sched_event(bcs, B_LL_NOCARRIER);
+			if (test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag)) {
+				send_DLE_ETX(bcs);
+				isar_sched_event(bcs, B_LL_NOCARRIER);
+			}
 		}
 		break;
 	default:
@@ -1075,19 +1081,22 @@
 			if (cs->debug & L1_DEB_HSCX)
 				debugl1(cs, "pump stev RSP_DISC");
 			if (bcs->hw.isar.state == STFAX_ESCAPE) {
+				p1 = 5;
 				switch(bcs->hw.isar.newcmd) {
 					case 0:
 						bcs->hw.isar.state = STFAX_READY;
 						break;
-					case PCTRL_CMD_FTH:
 					case PCTRL_CMD_FTM:
-						p1 = 10;
+						p1 = 2;
+					case PCTRL_CMD_FTH:
 						sendmsg(cs, dps | ISAR_HIS_PUMPCTRL,
 							PCTRL_CMD_SILON, 1, &p1);
 						bcs->hw.isar.state = STFAX_SILDET;
 						break;
-					case PCTRL_CMD_FRH:
 					case PCTRL_CMD_FRM:
+						if (frm_extra_delay)
+							mdelay(frm_extra_delay);
+					case PCTRL_CMD_FRH:
 						p1 = bcs->hw.isar.mod = bcs->hw.isar.newmod;
 						bcs->hw.isar.newmod = 0;
 						bcs->hw.isar.cmd = bcs->hw.isar.newcmd;
@@ -1206,6 +1215,9 @@
 					isar_pump_statev_modem(bcs, ireg->cmsb);
 				} else if (bcs->mode == L1_MODE_FAX) {
 					isar_pump_statev_fax(bcs, ireg->cmsb);
+				} else if (ireg->cmsb == PSEV_10MS_TIMER) {
+					if (cs->debug & L1_DEB_HSCX)
+						debugl1(cs, "pump stev TIMER");
 				} else {
 					if (cs->debug & L1_DEB_WARN)
 						debugl1(cs, "isar IIS_PSTEV pmode %d stat %x",
@@ -1266,6 +1278,9 @@
 	if (test_and_clear_bit(BC_FLG_LL_CONN, &bcs->Flag)) {
 		isar_sched_event(bcs, B_LL_CONNECT);
 	}
+	if (test_and_clear_bit(BC_FLG_FTI_FTS, &bcs->Flag)) {
+		isar_sched_event(bcs, B_LL_OK);
+	}
 }
 
 static void
@@ -1288,7 +1303,7 @@
 			} else {
 				param[5] = PV32P6_ATN;
 			}
-			param[0] = 6; /* 6 db */
+			param[0] = para_TOA; /* 6 db */
 			param[1] = PV32P2_V23R | PV32P2_V22A | PV32P2_V22B |
 				   PV32P2_V22C | PV32P2_V21 | PV32P2_BEL; 
 			param[2] = PV32P3_AMOD | PV32P3_V32B | PV32P3_V23B;
@@ -1304,7 +1319,7 @@
 			} else {
 				param[1] = PFAXP2_ATN;
 			}
-			param[0] = 6; /* 6 db */
+			param[0] = para_TOA; /* 6 db */
 			sendmsg(cs, dps | ISAR_HIS_PUMPCFG, ctrl, 2, param);
 			bcs->hw.isar.state = STFAX_NULL;
 			bcs->hw.isar.newcmd = 0;
@@ -1333,7 +1348,6 @@
 				"\0\0");
 			break;
 		case L1_MODE_HDLC:
-		case L1_MODE_FAX:
 			param[0] = 0;
 			sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_HDLC, 1,
 				param);
@@ -1345,6 +1359,9 @@
 			sendmsg(cs, dps | ISAR_HIS_SARTCFG, ctrl, 2,
 				param);
 			break;
+		case L1_MODE_FAX:
+			/* SART must not configured with FAX */
+			break;
 	}
 	udelay(1000);
 	sendmsg(cs, dps | ISAR_HIS_BSTREQ, 0, 0, NULL);
@@ -1448,6 +1465,7 @@
 
 	switch(cmd) {
 		case ISDN_FAX_CLASS1_FTM:
+			test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag);
 			if (bcs->hw.isar.state == STFAX_READY) {
 				p1 = para;
 				ctrl = PCTRL_CMD_FTM;
@@ -1471,6 +1489,7 @@
 			}
 			break;
 		case ISDN_FAX_CLASS1_FTH:
+			test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag);
 			if (bcs->hw.isar.state == STFAX_READY) {
 				p1 = para;
 				ctrl = PCTRL_CMD_FTH;
@@ -1494,6 +1513,7 @@
 			}
 			break;
 		case ISDN_FAX_CLASS1_FRM:
+			test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag);
 			if (bcs->hw.isar.state == STFAX_READY) {
 				p1 = para;
 				ctrl = PCTRL_CMD_FRM;
@@ -1517,6 +1537,7 @@
 			}
 			break;
 		case ISDN_FAX_CLASS1_FRH:
+			test_and_set_bit(BC_FLG_FRH_WAIT, &bcs->Flag);
 			if (bcs->hw.isar.state == STFAX_READY) {
 				p1 = para;
 				ctrl = PCTRL_CMD_FRH;
@@ -1539,6 +1560,11 @@
 				bcs->hw.isar.state = STFAX_ESCAPE; 
 			}
 			break;
+		case ISDN_FAXPUMP_HALT:
+			bcs->hw.isar.state = STFAX_NULL;
+			nom = 0;
+			ctrl = PCTRL_CMD_HALT;
+			break;
 	}
 	if (ctrl)
 		sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, ctrl, nom, &p1);
@@ -1632,6 +1658,15 @@
 			l1_msg_b(st, pr, arg);
 			break;
 		case (PH_DEACTIVATE | CONFIRM):
+			switch(st->l1.mode) {
+				case L1_MODE_TRANS:
+				case L1_MODE_HDLC:
+				case L1_MODE_V32:
+					break;
+				case L1_MODE_FAX:
+					isar_pump_cmd(st->l1.bcs, ISDN_FAXPUMP_HALT, 0);
+					break;
+			}
 			test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
 			test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
 			if (st->l1.bcs->cs->debug & L1_DEB_HSCX)
@@ -1723,6 +1758,51 @@
 						test_and_set_bit(BC_FLG_DLEETX,
 							&bcs->Flag);
 					break;
+				case ISDN_FAX_CLASS1_FTS:
+					if (ic->parm.aux.subcmd == AT_QUERY) {
+						ic->command = ISDN_STAT_FAXIND;
+						ic->parm.aux.cmd = ISDN_FAX_CLASS1_OK;
+						cs->iif.statcallb(ic);
+						return(0);
+					} else if (ic->parm.aux.subcmd == AT_EQ_QUERY) {
+						strcpy(ic->parm.aux.para, "0-255");
+						ic->command = ISDN_STAT_FAXIND;
+						ic->parm.aux.cmd = ISDN_FAX_CLASS1_QUERY;
+						cs->iif.statcallb(ic);
+						return(0);
+					} else if (ic->parm.aux.subcmd == AT_EQ_VALUE) {
+						if (cs->debug & L1_DEB_HSCX)
+							debugl1(cs, "isar_auxcmd %s=%d",
+								FC1_CMD[ic->parm.aux.cmd], ic->parm.aux.para[0]);
+						if (bcs->hw.isar.state == STFAX_READY) {
+							if (! ic->parm.aux.para[0]) {
+								ic->command = ISDN_STAT_FAXIND;
+								ic->parm.aux.cmd = ISDN_FAX_CLASS1_OK;
+								cs->iif.statcallb(ic);
+								return(0);
+							}
+							if (! test_and_set_bit(BC_FLG_FTI_RUN, &bcs->Flag)) {
+								/* n*10 ms */
+								bcs->hw.isar.ftimer.expires =
+									jiffies + ((ic->parm.aux.para[0] * 10 * HZ)/1000);
+								test_and_set_bit(BC_FLG_FTI_FTS, &bcs->Flag);
+								add_timer(&bcs->hw.isar.ftimer);
+								return(0);
+							} else {
+								if (cs->debug)
+									debugl1(cs, "isar FTS=%d and FTI busy",
+										ic->parm.aux.para[0]);
+							}
+						} else {
+							if (cs->debug)
+								debugl1(cs, "isar FTS=%d and isar.state not ready(%x)",
+									ic->parm.aux.para[0],bcs->hw.isar.state);
+						}
+						ic->command = ISDN_STAT_FAXIND;
+						ic->parm.aux.cmd = ISDN_FAX_CLASS1_ERROR;
+						cs->iif.statcallb(ic);
+					}
+					break;
 				case ISDN_FAX_CLASS1_FRM:
 				case ISDN_FAX_CLASS1_FRH:
 				case ISDN_FAX_CLASS1_FTM:
@@ -1735,16 +1815,24 @@
 						cs->iif.statcallb(ic);
 						return(0);
 					} else if (ic->parm.aux.subcmd == AT_EQ_QUERY) {
-						strcpy(ic->parm.aux.para, faxmodulation_s);
+						char *p = ic->parm.aux.para;
+						for(i=0;i<FAXMODCNT;i++)
+							if ((1<<i) & modmask)
+								p += sprintf(p, "%d,", faxmodulation[i]);
+						p--;
+						*p=0;
 						ic->command = ISDN_STAT_FAXIND;
 						ic->parm.aux.cmd = ISDN_FAX_CLASS1_QUERY;
 						cs->iif.statcallb(ic);
 						return(0);
 					} else if (ic->parm.aux.subcmd == AT_EQ_VALUE) {
+						if (cs->debug & L1_DEB_HSCX)
+							debugl1(cs, "isar_auxcmd %s=%d",
+								FC1_CMD[ic->parm.aux.cmd], ic->parm.aux.para[0]);
 						for(i=0;i<FAXMODCNT;i++)
 							if (faxmodulation[i]==ic->parm.aux.para[0])
 								break;
-						if ((FAXMODCNT > i) && 
+						if ((i < FAXMODCNT) && ((1<<i) & modmask) && 
 							test_bit(BC_FLG_INIT, &bcs->Flag)) {
 							isar_pump_cmd(bcs,
 								ic->parm.aux.cmd,
@@ -1762,7 +1850,7 @@
 			break;
 		case (ISDN_CMD_IOCTL):
 			switch (ic->arg) {
-				case (9): /* load firmware */
+				case 9: /* load firmware */
 					features = ISDN_FEATURE_L2_MODEM |
 						ISDN_FEATURE_L2_FAX |
 						ISDN_FEATURE_L3_FCLASS1;
@@ -1772,6 +1860,26 @@
 					else 
 						ll_run(cs, features);
 					break;
+				case 20:
+					features = *(unsigned int *) ic->parm.num;
+					printk(KERN_DEBUG "HiSax: max modulation old(%04x) new(%04x)\n",
+						modmask, features);
+					modmask = features;
+					break;
+				case 21:
+					features = *(unsigned int *) ic->parm.num;
+					printk(KERN_DEBUG "HiSax: FRM extra delay old(%d) new(%d) ms\n",
+						frm_extra_delay, features);
+					if (features >= 0)
+						frm_extra_delay = features;
+					break;
+				case 22:
+					features = *(unsigned int *) ic->parm.num;
+					printk(KERN_DEBUG "HiSax: TOA old(%d) new(%d) db\n",
+						para_TOA, features);
+					if (features >= 0 && features < 32)
+						para_TOA = features;
+					break;
 				default:
 					printk(KERN_DEBUG "HiSax: invalid ioctl %d\n",
 					       (int) ic->arg);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/isdn/hisax/isar.h linux-2.4.21-pre6/drivers/isdn/hisax/isar.h
--- linux-2.4.20/drivers/isdn/hisax/isar.h	2001-12-21 17:41:54.000000000 +0000
+++ linux-2.4.21-pre6/drivers/isdn/hisax/isar.h	2003-03-26 23:49:19.000000000 +0000
@@ -28,6 +28,8 @@
 #define ISAR_HIS_FIRM		0x1e
 #define ISAR_HIS_STDSP		0x08
 #define ISAR_HIS_DIAG		0x05
+#define ISAR_HIS_WAITSTATE	0x27
+#define ISAR_HIS_TIMERIRQ	0x25
 #define ISAR_HIS_P0CFG		0x3c
 #define ISAR_HIS_P12CFG		0x24
 #define ISAR_HIS_SARTCFG	0x25	
@@ -43,6 +45,10 @@
 #define ISAR_HIS_DPS2		0x80
 #define SET_DPS(x)		((x<<6) & 0xc0)
 
+#define ISAR_CMD_TIMERIRQ_OFF	0x20
+#define ISAR_CMD_TIMERIRQ_ON	0x21
+
+
 #define ISAR_IIS_MSCMSD		0x3f
 #define ISAR_IIS_VNR		0x15
 #define ISAR_IIS_DKEY		0x03
@@ -207,6 +213,8 @@
 #define STFAX_ESCAPE	5
 #define STFAX_SILDET	6
 
+#define ISDN_FAXPUMP_HALT	100
+
 extern int ISARVersion(struct IsdnCardState *cs, char *s);
 extern void isar_int_main(struct IsdnCardState *cs);
 extern void initisar(struct IsdnCardState *cs);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/isdn/hisax/isdnhdlc.c linux-2.4.21-pre6/drivers/isdn/hisax/isdnhdlc.c
--- linux-2.4.20/drivers/isdn/hisax/isdnhdlc.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/isdn/hisax/isdnhdlc.c	2003-03-26 23:49:55.000000000 +0000
@@ -0,0 +1,669 @@
+/*
+ * isdnhdlc.c  --  General purpose ISDN HDLC decoder.
+ *
+ *Copyright (C) 2002	Wolfgang Mües      <wolfgang@iksw-muees.de>
+ *		2001 	Frode Isaksen      <fisaksen@bewan.com>
+ *              2001 	Kai Germaschewski  <kai.germaschewski@gmx.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/init.h>
+#include "isdnhdlc.h"
+
+/*-------------------------------------------------------------------*/
+
+MODULE_AUTHOR("Wolfgang Mües <wolfgang@iksw-muees.de>, "
+	      "Frode Isaksen <fisaksen@bewan.com>, "
+	      "Kai Germaschewski <kai.germaschewski@gmx.de>");
+MODULE_DESCRIPTION("General purpose ISDN HDLC decoder");
+MODULE_LICENSE("GPL");
+
+/*-------------------------------------------------------------------*/
+
+/* bit swap table.
+ * Very handy for devices with different bit order,
+ * and neccessary for each transparent B-channel access for all
+ * devices which works with this HDLC decoder without bit reversal.
+ */
+const unsigned char isdnhdlc_bit_rev_tab[256] = {
+	0x00,0x80,0x40,0xC0,0x20,0xA0,0x60,0xE0,0x10,0x90,0x50,0xD0,0x30,0xB0,0x70,0xF0,
+	0x08,0x88,0x48,0xC8,0x28,0xA8,0x68,0xE8,0x18,0x98,0x58,0xD8,0x38,0xB8,0x78,0xF8,
+	0x04,0x84,0x44,0xC4,0x24,0xA4,0x64,0xE4,0x14,0x94,0x54,0xD4,0x34,0xB4,0x74,0xF4,
+	0x0C,0x8C,0x4C,0xCC,0x2C,0xAC,0x6C,0xEC,0x1C,0x9C,0x5C,0xDC,0x3C,0xBC,0x7C,0xFC,
+	0x02,0x82,0x42,0xC2,0x22,0xA2,0x62,0xE2,0x12,0x92,0x52,0xD2,0x32,0xB2,0x72,0xF2,
+	0x0A,0x8A,0x4A,0xCA,0x2A,0xAA,0x6A,0xEA,0x1A,0x9A,0x5A,0xDA,0x3A,0xBA,0x7A,0xFA,
+	0x06,0x86,0x46,0xC6,0x26,0xA6,0x66,0xE6,0x16,0x96,0x56,0xD6,0x36,0xB6,0x76,0xF6,
+	0x0E,0x8E,0x4E,0xCE,0x2E,0xAE,0x6E,0xEE,0x1E,0x9E,0x5E,0xDE,0x3E,0xBE,0x7E,0xFE,
+	0x01,0x81,0x41,0xC1,0x21,0xA1,0x61,0xE1,0x11,0x91,0x51,0xD1,0x31,0xB1,0x71,0xF1,
+	0x09,0x89,0x49,0xC9,0x29,0xA9,0x69,0xE9,0x19,0x99,0x59,0xD9,0x39,0xB9,0x79,0xF9,
+	0x05,0x85,0x45,0xC5,0x25,0xA5,0x65,0xE5,0x15,0x95,0x55,0xD5,0x35,0xB5,0x75,0xF5,
+	0x0D,0x8D,0x4D,0xCD,0x2D,0xAD,0x6D,0xED,0x1D,0x9D,0x5D,0xDD,0x3D,0xBD,0x7D,0xFD,
+	0x03,0x83,0x43,0xC3,0x23,0xA3,0x63,0xE3,0x13,0x93,0x53,0xD3,0x33,0xB3,0x73,0xF3,
+	0x0B,0x8B,0x4B,0xCB,0x2B,0xAB,0x6B,0xEB,0x1B,0x9B,0x5B,0xDB,0x3B,0xBB,0x7B,0xFB,
+	0x07,0x87,0x47,0xC7,0x27,0xA7,0x67,0xE7,0x17,0x97,0x57,0xD7,0x37,0xB7,0x77,0xF7,
+	0x0F,0x8F,0x4F,0xCF,0x2F,0xAF,0x6F,0xEF,0x1F,0x9F,0x5F,0xDF,0x3F,0xBF,0x7F,0xFF
+};
+
+/* Table for CRC16. Internal used only. */
+static const unsigned short int crc16_tab[] = {
+	0x0000,0x1189,0x2312,0x329b,0x4624,0x57ad,0x6536,0x74bf,
+	0x8c48,0x9dc1,0xaf5a,0xbed3,0xca6c,0xdbe5,0xe97e,0xf8f7,
+	0x1081,0x0108,0x3393,0x221a,0x56a5,0x472c,0x75b7,0x643e,
+	0x9cc9,0x8d40,0xbfdb,0xae52,0xdaed,0xcb64,0xf9ff,0xe876,
+	0x2102,0x308b,0x0210,0x1399,0x6726,0x76af,0x4434,0x55bd,
+	0xad4a,0xbcc3,0x8e58,0x9fd1,0xeb6e,0xfae7,0xc87c,0xd9f5,
+	0x3183,0x200a,0x1291,0x0318,0x77a7,0x662e,0x54b5,0x453c,
+	0xbdcb,0xac42,0x9ed9,0x8f50,0xfbef,0xea66,0xd8fd,0xc974,
+	0x4204,0x538d,0x6116,0x709f,0x0420,0x15a9,0x2732,0x36bb,
+	0xce4c,0xdfc5,0xed5e,0xfcd7,0x8868,0x99e1,0xab7a,0xbaf3,
+	0x5285,0x430c,0x7197,0x601e,0x14a1,0x0528,0x37b3,0x263a,
+	0xdecd,0xcf44,0xfddf,0xec56,0x98e9,0x8960,0xbbfb,0xaa72,
+	0x6306,0x728f,0x4014,0x519d,0x2522,0x34ab,0x0630,0x17b9,
+	0xef4e,0xfec7,0xcc5c,0xddd5,0xa96a,0xb8e3,0x8a78,0x9bf1,
+	0x7387,0x620e,0x5095,0x411c,0x35a3,0x242a,0x16b1,0x0738,
+	0xffcf,0xee46,0xdcdd,0xcd54,0xb9eb,0xa862,0x9af9,0x8b70,
+	0x8408,0x9581,0xa71a,0xb693,0xc22c,0xd3a5,0xe13e,0xf0b7,
+	0x0840,0x19c9,0x2b52,0x3adb,0x4e64,0x5fed,0x6d76,0x7cff,
+	0x9489,0x8500,0xb79b,0xa612,0xd2ad,0xc324,0xf1bf,0xe036,
+	0x18c1,0x0948,0x3bd3,0x2a5a,0x5ee5,0x4f6c,0x7df7,0x6c7e,
+	0xa50a,0xb483,0x8618,0x9791,0xe32e,0xf2a7,0xc03c,0xd1b5,
+	0x2942,0x38cb,0x0a50,0x1bd9,0x6f66,0x7eef,0x4c74,0x5dfd,
+	0xb58b,0xa402,0x9699,0x8710,0xf3af,0xe226,0xd0bd,0xc134,
+	0x39c3,0x284a,0x1ad1,0x0b58,0x7fe7,0x6e6e,0x5cf5,0x4d7c,
+	0xc60c,0xd785,0xe51e,0xf497,0x8028,0x91a1,0xa33a,0xb2b3,
+	0x4a44,0x5bcd,0x6956,0x78df,0x0c60,0x1de9,0x2f72,0x3efb,
+	0xd68d,0xc704,0xf59f,0xe416,0x90a9,0x8120,0xb3bb,0xa232,
+	0x5ac5,0x4b4c,0x79d7,0x685e,0x1ce1,0x0d68,0x3ff3,0x2e7a,
+	0xe70e,0xf687,0xc41c,0xd595,0xa12a,0xb0a3,0x8238,0x93b1,
+	0x6b46,0x7acf,0x4854,0x59dd,0x2d62,0x3ceb,0x0e70,0x1ff9,
+	0xf78f,0xe606,0xd49d,0xc514,0xb1ab,0xa022,0x92b9,0x8330,
+	0x7bc7,0x6a4e,0x58d5,0x495c,0x3de3,0x2c6a,0x1ef1,0x0f78
+};
+
+
+enum {
+	HDLC_FAST_IDLE,HDLC_GET_FLAG_B0,HDLC_GETFLAG_B1A6,HDLC_GETFLAG_B7,
+	HDLC_GET_DATA,HDLC_FAST_FLAG
+};
+
+enum {
+	HDLC_SEND_DATA,HDLC_SEND_CRC1,HDLC_SEND_FAST_FLAG,
+	HDLC_SEND_FIRST_FLAG,HDLC_SEND_CRC2,HDLC_SEND_CLOSING_FLAG,
+	HDLC_SEND_IDLE1,HDLC_SEND_FAST_IDLE,HDLC_SENDFLAG_B0,
+	HDLC_SENDFLAG_B1A6,HDLC_SENDFLAG_B7,STOPPED
+};
+
+void isdnhdlc_rcv_init (struct isdnhdlc_vars *hdlc, int do_adapt56)
+{
+   	hdlc->bit_shift = 0;
+	hdlc->hdlc_bits1 = 0;
+	hdlc->data_bits = 0;
+	hdlc->ffbit_shift = 0;
+	hdlc->data_received = 0;
+	hdlc->state = HDLC_GET_DATA;
+	hdlc->do_adapt56 = do_adapt56;
+	hdlc->dchannel = 0;
+	hdlc->crc = 0;
+	hdlc->cbin = 0;
+	hdlc->shift_reg = 0;
+	hdlc->ffvalue = 0;
+	hdlc->dstpos = 0;
+}
+
+void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc, int is_d_channel, int do_adapt56)
+{
+   	hdlc->bit_shift = 0;
+	hdlc->hdlc_bits1 = 0;
+	hdlc->data_bits = 0;
+	hdlc->ffbit_shift = 0;
+	hdlc->data_received = 0;
+	hdlc->do_closing = 0;
+	hdlc->ffvalue = 0;
+	if (is_d_channel) {
+		hdlc->dchannel = 1;
+		hdlc->state = HDLC_SEND_FIRST_FLAG;
+	} else {
+		hdlc->dchannel = 0;
+		hdlc->state = HDLC_SEND_FAST_FLAG;
+		hdlc->ffvalue = 0x7e;
+	}
+	hdlc->cbin = 0x7e;
+	hdlc->bit_shift = 0;
+	if(do_adapt56){
+		hdlc->do_adapt56 = 1;
+		hdlc->data_bits = 0;
+		hdlc->state = HDLC_SENDFLAG_B0;
+	} else {
+		hdlc->do_adapt56 = 0;
+		hdlc->data_bits = 8;
+	}
+	hdlc->shift_reg = 0;
+}
+
+/*
+  isdnhdlc_decode - decodes HDLC frames from a transparent bit stream.
+
+  The source buffer is scanned for valid HDLC frames looking for
+  flags (01111110) to indicate the start of a frame. If the start of
+  the frame is found, the bit stuffing is removed (0 after 5 1's).
+  When a new flag is found, the complete frame has been received
+  and the CRC is checked.
+  If a valid frame is found, the function returns the frame length
+  excluding the CRC with the bit HDLC_END_OF_FRAME set.
+  If the beginning of a valid frame is found, the function returns
+  the length.
+  If a framing error is found (too many 1s and not a flag) the function
+  returns the length with the bit HDLC_FRAMING_ERROR set.
+  If a CRC error is found the function returns the length with the
+  bit HDLC_CRC_ERROR set.
+  If the frame length exceeds the destination buffer size, the function
+  returns the length with the bit HDLC_LENGTH_ERROR set.
+
+  src - source buffer
+  slen - source buffer length
+  count - number of bytes removed (decoded) from the source buffer
+  dst _ destination buffer
+  dsize - destination buffer size
+  returns - number of decoded bytes in the destination buffer and status
+  flag.
+ */
+int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src,
+		     int slen, int *count, unsigned char *dst, int dsize)
+{
+	int status=0;
+
+	static const unsigned char fast_flag[]={
+		0x00,0x00,0x00,0x20,0x30,0x38,0x3c,0x3e,0x3f
+	};
+
+	static const unsigned char fast_flag_value[]={
+		0x00,0x7e,0xfc,0xf9,0xf3,0xe7,0xcf,0x9f,0x3f
+	};
+
+	static const unsigned char fast_abort[]={
+		0x00,0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff
+	};
+
+	*count = slen;
+
+	while(slen > 0){
+		if(hdlc->bit_shift==0){
+			hdlc->cbin = *src++;
+			slen--;
+			hdlc->bit_shift = 8;
+			if(hdlc->do_adapt56){
+				hdlc->bit_shift --;
+			}
+		}
+
+		switch(hdlc->state){
+		case STOPPED:
+			return 0;
+		case HDLC_FAST_IDLE:
+			if(hdlc->cbin == 0xff){
+				hdlc->bit_shift = 0;
+				break;
+			}
+			hdlc->state = HDLC_GET_FLAG_B0;
+			hdlc->hdlc_bits1 = 0;
+			hdlc->bit_shift = 8;
+			break;
+		case HDLC_GET_FLAG_B0:
+			if(!(hdlc->cbin & 0x80)) {
+				hdlc->state = HDLC_GETFLAG_B1A6;
+				hdlc->hdlc_bits1 = 0;
+			} else {
+				if(!hdlc->do_adapt56){
+					if(++hdlc->hdlc_bits1 >=8 ) if(hdlc->bit_shift==1)
+						hdlc->state = HDLC_FAST_IDLE;
+				}
+			}
+			hdlc->cbin<<=1;
+			hdlc->bit_shift --;
+			break;
+		case HDLC_GETFLAG_B1A6:
+			if(hdlc->cbin & 0x80){
+				hdlc->hdlc_bits1++;
+				if(hdlc->hdlc_bits1==6){
+					hdlc->state = HDLC_GETFLAG_B7;
+				}
+			} else {
+				hdlc->hdlc_bits1 = 0;
+			}
+			hdlc->cbin<<=1;
+			hdlc->bit_shift --;
+			break;
+		case HDLC_GETFLAG_B7:
+			if(hdlc->cbin & 0x80) {
+				hdlc->state = HDLC_GET_FLAG_B0;
+			} else {
+				hdlc->state = HDLC_GET_DATA;
+				hdlc->crc = 0xffff;
+				hdlc->shift_reg = 0;
+				hdlc->hdlc_bits1 = 0;
+				hdlc->data_bits = 0;
+				hdlc->data_received = 0;
+			}
+			hdlc->cbin<<=1;
+			hdlc->bit_shift --;
+			break;
+		case HDLC_GET_DATA:
+			if(hdlc->cbin & 0x80){
+				hdlc->hdlc_bits1++;
+				switch(hdlc->hdlc_bits1){
+				case 6:
+					break;
+				case 7:
+					if(hdlc->data_received) {
+						// bad frame
+						status = -HDLC_FRAMING_ERROR;
+					}
+					if(!hdlc->do_adapt56){
+						if(hdlc->cbin==fast_abort[hdlc->bit_shift+1]){
+							hdlc->state = HDLC_FAST_IDLE;
+							hdlc->bit_shift=1;
+							break;
+						}
+					} else {
+						hdlc->state = HDLC_GET_FLAG_B0;
+					}
+					break;
+				default:
+					hdlc->shift_reg>>=1;
+					hdlc->shift_reg |= 0x80;
+					hdlc->data_bits++;
+					break;
+				}
+			} else {
+				switch(hdlc->hdlc_bits1){
+				case 5:
+					break;
+				case 6:
+					if(hdlc->data_received){
+						if (hdlc->dstpos < 2) {
+							status = -HDLC_FRAMING_ERROR;
+						} else if (hdlc->crc != 0xf0b8){
+							// crc error
+							status = -HDLC_CRC_ERROR;
+						} else {
+							// remove CRC
+							hdlc->dstpos -= 2;
+							// good frame
+							status = hdlc->dstpos;
+						}
+					}
+					hdlc->crc = 0xffff;
+					hdlc->shift_reg = 0;
+					hdlc->data_bits = 0;
+					if(!hdlc->do_adapt56){
+						if(hdlc->cbin==fast_flag[hdlc->bit_shift]){
+							hdlc->ffvalue = fast_flag_value[hdlc->bit_shift];
+							hdlc->state = HDLC_FAST_FLAG;
+							hdlc->ffbit_shift = hdlc->bit_shift;
+							hdlc->bit_shift = 1;
+						} else {
+							hdlc->state = HDLC_GET_DATA;
+							hdlc->data_received = 0;
+						}
+					} else {
+						hdlc->state = HDLC_GET_DATA;
+						hdlc->data_received = 0;
+					}
+					break;
+				default:
+					hdlc->shift_reg>>=1;
+					hdlc->data_bits++;
+					break;
+				}
+				hdlc->hdlc_bits1 = 0;
+			}
+			if (status) {
+				hdlc->dstpos = 0;
+				*count -= slen;
+				hdlc->cbin <<= 1;
+				hdlc->bit_shift--;
+				return status;
+			}
+			if(hdlc->data_bits==8){
+				unsigned cval;
+
+				hdlc->data_bits = 0;
+				hdlc->data_received = 1;
+				cval = (hdlc->crc^hdlc->shift_reg) & 0xff;
+				hdlc->crc = (hdlc->crc>>8)^crc16_tab[cval];
+				// good byte received
+				if (dsize--) {
+					dst[hdlc->dstpos++] = hdlc->shift_reg;
+				} else {
+					// frame too long
+					status = -HDLC_LENGTH_ERROR;
+					hdlc->dstpos = 0;
+				}
+			}
+			hdlc->cbin <<= 1;
+			hdlc->bit_shift--;
+			break;
+		case HDLC_FAST_FLAG:
+			if(hdlc->cbin==hdlc->ffvalue){
+				hdlc->bit_shift = 0;
+				break;
+			} else {
+				if(hdlc->cbin == 0xff){
+					hdlc->state = HDLC_FAST_IDLE;
+					hdlc->bit_shift=0;
+				} else if(hdlc->ffbit_shift==8){
+					hdlc->state = HDLC_GETFLAG_B7;
+					break;
+				} else {
+					hdlc->shift_reg = fast_abort[hdlc->ffbit_shift-1];
+					hdlc->hdlc_bits1 = hdlc->ffbit_shift-2;
+					if(hdlc->hdlc_bits1<0)hdlc->hdlc_bits1 = 0;
+					hdlc->data_bits = hdlc->ffbit_shift-1;
+					hdlc->state = HDLC_GET_DATA;
+					hdlc->data_received = 0;
+				}
+			}
+			break;
+		default:
+			break;
+		}
+	}
+	*count -= slen;
+	return 0;
+}
+
+/*
+  isdnhdlc_encode - encodes HDLC frames to a transparent bit stream.
+
+  The bit stream starts with a beginning flag (01111110). After
+  that each byte is added to the bit stream with bit stuffing added
+  (0 after 5 1's).
+  When the last byte has been removed from the source buffer, the
+  CRC (2 bytes is added) and the frame terminates with the ending flag.
+  For the dchannel, the idle character (all 1's) is also added at the end.
+  If this function is called with empty source buffer (slen=0), flags or
+  idle character will be generated.
+
+  src - source buffer
+  slen - source buffer length
+  count - number of bytes removed (encoded) from source buffer
+  dst _ destination buffer
+  dsize - destination buffer size
+  returns - number of encoded bytes in the destination buffer
+*/
+int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src,
+		unsigned short slen, int *count,
+		unsigned char *dst, int dsize)
+{
+	static const unsigned char xfast_flag_value[] = {
+		0x7e,0x3f,0x9f,0xcf,0xe7,0xf3,0xf9,0xfc,0x7e
+	};
+
+	int len = 0;
+
+	*count = slen;
+
+	while (dsize > 0) {
+		if(hdlc->bit_shift==0){
+			if(slen && !hdlc->do_closing){
+				hdlc->shift_reg = *src++;
+				slen--;
+				if (slen == 0)
+					hdlc->do_closing = 1;  /* closing sequence, CRC + flag(s) */
+				hdlc->bit_shift = 8;
+			} else {
+				if(hdlc->state == HDLC_SEND_DATA){
+					if(hdlc->data_received){
+						hdlc->state = HDLC_SEND_CRC1;
+						hdlc->crc ^= 0xffff;
+						hdlc->bit_shift = 8;
+						hdlc->shift_reg = hdlc->crc & 0xff;
+					} else if(!hdlc->do_adapt56){
+						hdlc->state = HDLC_SEND_FAST_FLAG;
+					} else {
+						hdlc->state = HDLC_SENDFLAG_B0;
+					}
+				}
+
+			}
+		}
+
+		switch(hdlc->state){
+		case STOPPED:
+			while (dsize--)
+				*dst++ = 0xff;
+
+			return dsize;
+		case HDLC_SEND_FAST_FLAG:
+			hdlc->do_closing = 0;
+			if(slen == 0){
+				*dst++ = hdlc->ffvalue;
+				len++;
+				dsize--;
+				break;
+			}
+			if(hdlc->bit_shift==8){
+				hdlc->cbin = hdlc->ffvalue>>(8-hdlc->data_bits);
+				hdlc->state = HDLC_SEND_DATA;
+				hdlc->crc = 0xffff;
+				hdlc->hdlc_bits1 = 0;
+				hdlc->data_received = 1;
+			}
+			break;
+		case HDLC_SENDFLAG_B0:
+			hdlc->do_closing = 0;
+			hdlc->cbin <<= 1;
+			hdlc->data_bits++;
+			hdlc->hdlc_bits1 = 0;
+			hdlc->state = HDLC_SENDFLAG_B1A6;
+			break;
+		case HDLC_SENDFLAG_B1A6:
+			hdlc->cbin <<= 1;
+			hdlc->data_bits++;
+			hdlc->cbin++;
+			if(++hdlc->hdlc_bits1 == 6)
+				hdlc->state = HDLC_SENDFLAG_B7;
+			break;
+		case HDLC_SENDFLAG_B7:
+			hdlc->cbin <<= 1;
+			hdlc->data_bits++;
+			if(slen == 0){
+				hdlc->state = HDLC_SENDFLAG_B0;
+				break;
+			}
+			if(hdlc->bit_shift==8){
+				hdlc->state = HDLC_SEND_DATA;
+				hdlc->crc = 0xffff;
+				hdlc->hdlc_bits1 = 0;
+				hdlc->data_received = 1;
+			}
+			break;
+		case HDLC_SEND_FIRST_FLAG:
+			hdlc->data_received = 1;
+			if(hdlc->data_bits==8){
+				hdlc->state = HDLC_SEND_DATA;
+				hdlc->crc = 0xffff;
+				hdlc->hdlc_bits1 = 0;
+				break;
+			}
+			hdlc->cbin <<= 1;
+			hdlc->data_bits++;
+			if(hdlc->shift_reg & 0x01)
+				hdlc->cbin++;
+			hdlc->shift_reg >>= 1;
+			hdlc->bit_shift--;
+			if(hdlc->bit_shift==0){
+				hdlc->state = HDLC_SEND_DATA;
+				hdlc->crc = 0xffff;
+				hdlc->hdlc_bits1 = 0;
+			}
+			break;
+		case HDLC_SEND_DATA:
+			hdlc->cbin <<= 1;
+			hdlc->data_bits++;
+			if(hdlc->hdlc_bits1 == 5){
+				hdlc->hdlc_bits1 = 0;
+				break;
+			}
+			if(hdlc->bit_shift==8){
+				unsigned cval;
+
+				cval = (hdlc->crc^hdlc->shift_reg) & 0xff;
+				hdlc->crc = (hdlc->crc>>8)^crc16_tab[cval];
+			}
+			if(hdlc->shift_reg & 0x01){
+				hdlc->hdlc_bits1++;
+				hdlc->cbin++;
+				hdlc->shift_reg >>= 1;
+				hdlc->bit_shift--;
+			} else {
+				hdlc->hdlc_bits1 = 0;
+				hdlc->shift_reg >>= 1;
+				hdlc->bit_shift--;
+			}
+			break;
+		case HDLC_SEND_CRC1:
+			hdlc->cbin <<= 1;
+			hdlc->data_bits++;
+			if(hdlc->hdlc_bits1 == 5){
+				hdlc->hdlc_bits1 = 0;
+				break;
+			}
+			if(hdlc->shift_reg & 0x01){
+				hdlc->hdlc_bits1++;
+				hdlc->cbin++;
+				hdlc->shift_reg >>= 1;
+				hdlc->bit_shift--;
+			} else {
+				hdlc->hdlc_bits1 = 0;
+				hdlc->shift_reg >>= 1;
+				hdlc->bit_shift--;
+			}
+			if(hdlc->bit_shift==0){
+				hdlc->shift_reg = (hdlc->crc >> 8);
+				hdlc->state = HDLC_SEND_CRC2;
+				hdlc->bit_shift = 8;
+			}
+			break;
+		case HDLC_SEND_CRC2:
+			hdlc->cbin <<= 1;
+			hdlc->data_bits++;
+			if(hdlc->hdlc_bits1 == 5){
+				hdlc->hdlc_bits1 = 0;
+				break;
+			}
+			if(hdlc->shift_reg & 0x01){
+				hdlc->hdlc_bits1++;
+				hdlc->cbin++;
+				hdlc->shift_reg >>= 1;
+				hdlc->bit_shift--;
+			} else {
+				hdlc->hdlc_bits1 = 0;
+				hdlc->shift_reg >>= 1;
+				hdlc->bit_shift--;
+			}
+			if(hdlc->bit_shift==0){
+				hdlc->shift_reg = 0x7e;
+				hdlc->state = HDLC_SEND_CLOSING_FLAG;
+				hdlc->bit_shift = 8;
+			}
+			break;
+		case HDLC_SEND_CLOSING_FLAG:
+			hdlc->cbin <<= 1;
+			hdlc->data_bits++;
+			if(hdlc->hdlc_bits1 == 5){
+				hdlc->hdlc_bits1 = 0;
+				break;
+			}
+			if(hdlc->shift_reg & 0x01){
+				hdlc->cbin++;
+			}
+			hdlc->shift_reg >>= 1;
+			hdlc->bit_shift--;
+			if(hdlc->bit_shift==0){
+				hdlc->ffvalue = xfast_flag_value[hdlc->data_bits];
+				if(hdlc->dchannel){
+					hdlc->ffvalue = 0x7e;
+					hdlc->state = HDLC_SEND_IDLE1;
+					hdlc->bit_shift = 8-hdlc->data_bits;
+					if(hdlc->bit_shift==0)
+						hdlc->state = HDLC_SEND_FAST_IDLE;
+				} else {
+					if(!hdlc->do_adapt56){
+						hdlc->state = HDLC_SEND_FAST_FLAG;
+						hdlc->data_received = 0;
+					} else {
+						hdlc->state = HDLC_SENDFLAG_B0;
+						hdlc->data_received = 0;
+					}
+					// Finished with this frame, send flags
+					if (dsize > 1) dsize = 1;
+				}
+			}
+			break;
+		case HDLC_SEND_IDLE1:
+			hdlc->do_closing = 0;
+			hdlc->cbin <<= 1;
+			hdlc->cbin++;
+			hdlc->data_bits++;
+			hdlc->bit_shift--;
+			if(hdlc->bit_shift==0){
+				hdlc->state = HDLC_SEND_FAST_IDLE;
+				hdlc->bit_shift = 0;
+			}
+			break;
+		case HDLC_SEND_FAST_IDLE:
+			hdlc->do_closing = 0;
+			hdlc->cbin = 0xff;
+			hdlc->data_bits = 8;
+			if(hdlc->bit_shift == 8){
+				hdlc->cbin = 0x7e;
+				hdlc->state = HDLC_SEND_FIRST_FLAG;
+			} else {
+				*dst++ = hdlc->cbin;
+				hdlc->bit_shift = hdlc->data_bits = 0;
+				len++;
+				dsize = 0;
+			}
+			break;
+		default:
+			break;
+		}
+		if(hdlc->do_adapt56){
+			if(hdlc->data_bits==7){
+				hdlc->cbin <<= 1;
+				hdlc->cbin++;
+				hdlc->data_bits++;
+			}
+		}
+		if(hdlc->data_bits==8){
+			*dst++ = hdlc->cbin;
+			hdlc->data_bits = 0;
+			len++;
+			dsize--;
+		}
+	}
+	*count -= slen;
+
+	return len;
+}
+
+EXPORT_SYMBOL(isdnhdlc_bit_rev_tab);
+EXPORT_SYMBOL(isdnhdlc_rcv_init);
+EXPORT_SYMBOL(isdnhdlc_decode);
+EXPORT_SYMBOL(isdnhdlc_out_init);
+EXPORT_SYMBOL(isdnhdlc_encode);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/isdn/hisax/isdnhdlc.h linux-2.4.21-pre6/drivers/isdn/hisax/isdnhdlc.h
--- linux-2.4.20/drivers/isdn/hisax/isdnhdlc.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/isdn/hisax/isdnhdlc.h	2003-03-26 23:49:51.000000000 +0000
@@ -0,0 +1,72 @@
+/*
+ * isdnhdlc.h  --  General purpose ISDN HDLC decoder.
+ *
+ * Implementation of a HDLC decoder/encoder in software.
+ * Neccessary because some ISDN devices don't have HDLC
+ * controllers. Also included: a bit reversal table.
+ *
+ *Copyright (C) 2002    Wolfgang Mües      <wolfgang@iksw-muees.de>
+ *		2001 	Frode Isaksen      <fisaksen@bewan.com>
+ *              2001 	Kai Germaschewski  <kai.germaschewski@gmx.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 __ISDNHDLC_H__
+#define __ISDNHDLC_H__
+
+struct isdnhdlc_vars {
+	int bit_shift;
+	int hdlc_bits1;
+	int data_bits;
+	int ffbit_shift; 	// encoding only
+	int state;
+	int dstpos;
+
+	unsigned short crc;
+
+	unsigned char cbin;
+	unsigned char shift_reg;
+	unsigned char ffvalue;
+
+	int data_received:1; 	// set if transferring data
+	int dchannel:1; 	// set if D channel (send idle instead of flags)
+	int do_adapt56:1; 	// set if 56K adaptation
+        int do_closing:1; 	// set if in closing phase (need to send CRC + flag
+};
+
+
+/*
+  The return value from isdnhdlc_decode is
+  the frame length, 0 if no complete frame was decoded,
+  or a negative error number
+*/
+#define HDLC_FRAMING_ERROR     1
+#define HDLC_CRC_ERROR         2
+#define HDLC_LENGTH_ERROR      3
+
+extern const unsigned char isdnhdlc_bit_rev_tab[256];
+
+extern void isdnhdlc_rcv_init (struct isdnhdlc_vars *hdlc, int do_adapt56);
+
+extern int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, int slen,int *count,
+	                    unsigned char *dst, int dsize);
+
+extern void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc,int is_d_channel,int do_adapt56);
+
+extern int isdnhdlc_encode (struct isdnhdlc_vars *hdlc,const unsigned char *src,unsigned short slen,int *count,
+	                    unsigned char *dst,int dsize);
+
+#endif /* __ISDNHDLC_H__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/isdn/hisax/rawhdlc.c linux-2.4.21-pre6/drivers/isdn/hisax/rawhdlc.c
--- linux-2.4.20/drivers/isdn/hisax/rawhdlc.c	2001-12-21 17:41:54.000000000 +0000
+++ linux-2.4.21-pre6/drivers/isdn/hisax/rawhdlc.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,543 +0,0 @@
-/* $Id: rawhdlc.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
- *
- * support routines for cards that don't support HDLC
- *
- * Author     Brent Baccala
- * Copyright  by Karsten Keil <keil@isdn4linux.de>
- *            by Brent Baccala <baccala@FreeSoft.org>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- *
- * Some passive ISDN cards, such as the Traverse NETJet and the AMD 7930,
- * don't perform HDLC encapsulation over the B channel.  Drivers for
- * such cards use support routines in this file to perform B channel HDLC.
- *
- * Bit-synchronous HDLC encapsulation is a means of encapsulating packets
- * over a continuously transmitting serial communications link.
- * It looks like this:
- *
- *      11111111101111110...........0111111011111111111
- *      iiiiiiiiiffffffffdddddddddddffffffffiiiiiiiiiii
- *
- *      i = idle     f = flag     d = data
- *
- * When idle, the channel sends a continuous string of ones (mark
- * idle; illustrated), or a continuous string of flag characters (flag
- * idle).  The beginning of a data frame is marked by a flag character
- * (01111110), then comes the actual data, followed by another flag
- * character, after which another frame may be sent immediately (a
- * single flag may serve as both the end of one frame and the start of
- * the next), or the link may return to idle.  Obviously, the flag
- * character can not appear anywhere in the data (or a false
- * end-of-frame would occur), so the transmitter performs
- * "bit-stuffing" - inserting a zero bit after every five one bits,
- * irregardless of the original bit after the five ones.  Byte
- * ordering is irrelevent at this point - the data is treated as a
- * string of bits, not bytes.  Since no more than 5 ones may now occur
- * in a row, the flag sequence, with its 6 ones, is unique.
- *
- * Upon reception, a zero bit that occur after 5 one bits is simply
- * discarded.  A series of 6 one bits is end-of-frame, and a series of
- * 7 one bits is an abort.  Once bit-stuffing has been corrected for,
- * an integer number of bytes should now be present.  The last two
- * of these bytes form the Frame Check Sequence, a CRC that is verified
- * and then discarded.  Note that bit-stuffing is performed on the FCS
- * just as if it were regular data.
- *
- *
- *
- * int make_raw_hdlc_data(u_char *src, u_int slen,
- *                        u_char *dst, u_int dsize)
- *
- *   Used for transmission.  Copies slen bytes from src to dst, performing
- *   HDLC encapsulation (flag bytes, bit-stuffing, CRC) in the process.
- *   dsize is size of destination buffer, and should be at least
- *   ((6*slen)/5)+5 bytes to ensure adequate space will be available.
- *   Function returns length (in bytes) of valid destination buffer, or
- *   0 upon destination overflow.
- *
- * void init_hdlc_state(struct hdlc_state *stateptr, int mode)
- *
- *   Initializes hdlc_state structure before first call to read_raw_hdlc_data
- *
- *   mode = 0: Sane mode
- *   mode = 1/2: 
- *             Insane mode; NETJet use a shared unsigned int memory block (
- * 	       with busmaster DMA), the bit pattern of every word is 
- *  	       <8 B1> <8 B2> <8 Mon> <2 D> <4 C/I> <MX> <MR>
- *	       according to Siemens IOM-2 interface, so we have to handle
- *             the src buffer as unsigned int and have to shift/mask the
- *             B-channel bytes.
- *             mode 1 -> B1  mode 2  -> B2 data is used
- *
- * int read_raw_hdlc_data(struct hdlc_state *saved_state,
- *                        u_char *src, u_int slen,
- *                        u_char *dst, u_int dsize)
- *
- *   Used for reception.  Scans source buffer bit-by-bit looking for
- *   valid HDLC frames, which are copied to destination buffer.  HDLC
- *   state information is stored in a structure, which allows this
- *   function to process frames spread across several blocks of raw
- *   HDLC data.  Part of the state information is bit offsets into
- *   the source and destination buffers.
- *
- *   A return value >0 indicates the length of a valid frame, now
- *   stored in the destination buffer.  In this case, the source
- *   buffer might not be completely processed, so this function should
- *   be called again with the same source buffer, possibly with a
- *   different destination buffer.
- *
- *   A return value of zero indicates that the source buffer was
- *   completely processed without finding a valid end-of-packet;
- *   however, we might be in the middle of packet reception, so
- *   the function should be called again with the next block of
- *   raw HDLC data and the same destination buffer.  It is NOT
- *   permitted to change the destination buffer in this case,
- *   since data may already have begun to be stored there.
- *
- *   A return value of -1 indicates some kind of error - destination
- *   buffer overflow, CRC check failed, frame not a multiple of 8
- *   bits.  Destination buffer probably contains invalid data, which
- *   should be discarded.  Call function again with same source buffer
- *   and a new (or same) destination buffer.
- *
- *   Suggested calling sequence:
- *
- *      init_hdlc_state(...);
- *      for (EACH_RAW_DATA_BLOCK) {
- *         while (len = read_raw_hdlc_data(...)) {
- *             if (len == -1) DISCARD_FRAME;
- *             else PROCESS_FRAME;
- *         }
- *      }
- *
- *
- * Test the code in this file as follows:
- *    gcc -DDEBUGME -o rawhdlctest rawhdlc.c
- *    ./rawhdlctest < rawdata
- *
- * The file "rawdata" can be easily generated from a HISAX B-channel
- * hex dump (CF CF CF 02 ...) using the following perl script:
- *
- * while(<>) {
- *     @hexlist = split ' ';
- *     while ($hexstr = shift(@hexlist)) {
- *         printf "%c", hex($hexstr);
- *     }
- * }
- *
- */
-
-#ifdef DEBUGME
-#include <stdio.h>
-#endif
-
-#include <linux/types.h>
-#include <linux/ppp_defs.h>
-#include "rawhdlc.h"
-
-/* There's actually an identical copy of this table in the PPP code
- * (ppp_crc16_table), but I don't want this code dependent on PPP
- */
-
-// static 
-__u16 fcstab[256] =
-{
-	0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
-	0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
-	0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
-	0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
-	0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
-	0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
-	0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
-	0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
-	0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
-	0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
-	0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
-	0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
-	0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
-	0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
-	0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
-	0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
-	0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
-	0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
-	0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
-	0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
-	0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
-	0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
-	0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
-	0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
-	0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
-	0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
-	0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
-	0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
-	0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
-	0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
-	0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
-	0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
-};
-
-#define HDLC_ZERO_SEARCH 0
-#define HDLC_FLAG_SEARCH 1
-#define HDLC_FLAG_FOUND  2
-#define HDLC_FRAME_FOUND 3
-#define HDLC_NULL 4
-#define HDLC_PART 5
-#define HDLC_FULL 6
-
-#define HDLC_FLAG_VALUE	0x7e
-
-
-#define MAKE_RAW_BYTE for (j=0; j<8; j++) { \
-			bitcnt++;\
-			out_val >>= 1;\
-			if (val & 1) {\
-				s_one++;\
-				out_val |= 0x80;\
-			} else {\
-				s_one = 0;\
-				out_val &= 0x7f;\
-			}\
-			if (bitcnt==8) {\
-				if (d_cnt == dsize) return 0;\
-				dst[d_cnt++] = out_val;\
-				bitcnt = 0;\
-			}\
-			if (s_one == 5) {\
-				out_val >>= 1;\
-				out_val &= 0x7f;\
-				bitcnt++;\
-				s_one = 0;\
-			}\
-			if (bitcnt==8) {\
-				if (d_cnt == dsize) return 0;\
-				dst[d_cnt++] = out_val;\
-				bitcnt = 0;\
-			}\
-			val >>= 1;\
-		}
-
-/* Optimization suggestion: If needed, this function could be
- * dramatically sped up using a state machine.  Each state would
- * correspond to having seen N one bits, and being offset M bits into
- * the current output byte.  N ranges from 0 to 4, M from 0 to 7, so
- * we need 5*8 = 35 states.  Each state would have a table with 256
- * entries, one for each input character.  Each entry would contain
- * three output characters, an output state, an a byte increment
- * that's either 1 or 2.  All this could fit in four bytes; so we need
- * 4 bytes * 256 characters = 1 KB for each state (35 KB total).  Zero
- * the output buffer before you start.  For each character in your
- * input, you look it up in the current state's table and get three
- * bytes to be or'ed into the output at the current byte offset, and
- * an byte increment to move your pointer forward.  A simple Perl
- * script could generate the tables.  Given HDLC semantics, probably
- * would be better to set output to all 1s, then use ands instead of ors.
- * A smaller state machine could operate on nibbles instead of bytes.
- * A state machine for 32-bit architectures could use word offsets
- * instead of byte offsets, requiring 5*32 = 160 states; probably
- * best to work on nibbles in such a case.
- */
-
-
-int make_raw_hdlc_data(u_char *src, u_int slen, u_char *dst, u_int dsize)
-{
-	register u_int i,d_cnt=0;
-	register u_char j;
-	register u_char val;
-	register u_char s_one = 0;
-	register u_char out_val = 0;
-	register u_char bitcnt = 0;
-	u_int fcs;
-	
-	
-	dst[d_cnt++] = HDLC_FLAG_VALUE;
-	fcs = PPP_INITFCS;
-	for (i=0; i<slen; i++) {
-		val = src[i];
-		fcs = PPP_FCS (fcs, val);
-		MAKE_RAW_BYTE;
-	}
-	fcs ^= 0xffff;
-	val = fcs & 0xff;
-	MAKE_RAW_BYTE;
-	val = (fcs>>8) & 0xff;
-	MAKE_RAW_BYTE;
-	val = HDLC_FLAG_VALUE;
-	for (j=0; j<8; j++) { 
-		bitcnt++;
-		out_val >>= 1;
-		if (val & 1)
-			out_val |= 0x80;
-		else
-			out_val &= 0x7f;
-		if (bitcnt==8) {
-			if (d_cnt == dsize) return 0;
-			dst[d_cnt++] = out_val;
-			bitcnt = 0;
-		}
-		val >>= 1;
-	}
-	if (bitcnt) {
-		while (8>bitcnt++) {
-			out_val >>= 1;
-			out_val |= 0x80;
-		}
-		if (d_cnt == dsize) return 0;
-		dst[d_cnt++] = out_val;
-	}
-
-	return d_cnt;
-}
-
-void init_hdlc_state(struct hdlc_state *stateptr, int mode)
-{
-	stateptr->state = HDLC_ZERO_SEARCH;
-	stateptr->r_one = 0;
-	stateptr->r_val = 0;
-	stateptr->o_bitcnt = 0;
-	stateptr->i_bitcnt = 0;
-	stateptr->insane_mode = mode;
-}
-
-/* Optimization suggestion: A similar state machine could surely
- * be developed for this function as well.
- */
-
-int read_raw_hdlc_data(struct hdlc_state *saved_state,
-                       u_char *src, u_int slen, u_char *dst, u_int dsize)
-{
-	int retval=0;
-	register u_char val;
-	register u_char state = saved_state->state;
-	register u_char r_one = saved_state->r_one;
-	register u_char r_val = saved_state->r_val;
-	register u_int o_bitcnt = saved_state->o_bitcnt;
-	register u_int i_bitcnt = saved_state->i_bitcnt;
-	register u_int fcs    = saved_state->fcs;
-	register u_int *isrc = (u_int *) src;
-        
-	/* Use i_bitcnt (bit offset into source buffer) to reload "val"
-	 * in case we're starting up again partway through a source buffer
-	 */
-
-	if ((i_bitcnt >> 3) < slen) {
-		if (saved_state->insane_mode==1) {
-			val = isrc[(i_bitcnt >> 3)] & 0xff;
-		} else if (saved_state->insane_mode==2) {
-			val = (isrc[i_bitcnt >> 3] >>8) & 0xff;
-		} else {
-			val = src[i_bitcnt >> 3];
-		}
-		val >>= i_bitcnt & 7;
-	}
-
-	/* One bit per loop.  Keep going until we've got something to
-	 * report (retval != 0), or we exhaust the source buffer
-	 */
-
-	while ((retval == 0) && ((i_bitcnt >> 3) < slen)) {
-		if ((i_bitcnt & 7) == 0) {
-			if (saved_state->insane_mode==1) {
-				val = isrc[(i_bitcnt >> 3)] & 0xff;
-			} else if (saved_state->insane_mode==2) {
-				val = (isrc[i_bitcnt >> 3] >>8) & 0xff;
-			} else {
-				val = src[i_bitcnt >> 3];
-			}
-#ifdef DEBUGME
-			printf("Input byte %d: 0x%2x\n", i_bitcnt>>3, val);
-#endif
-			if (val == 0xff) {
-				state = HDLC_ZERO_SEARCH;
-				o_bitcnt = 0;
-				r_one = 0;
-				i_bitcnt += 8;
-				continue;
-			}
-		}
-
-#ifdef DEBUGME
-		/* printf("Data bit=%d (%d/%d)\n", val&1, i_bitcnt>>3, i_bitcnt&7);*/
-#endif
-
-		if (state == HDLC_ZERO_SEARCH) {
-			if (val & 1) {
-				r_one++;
-			} else {
-				r_one=0;
-				state= HDLC_FLAG_SEARCH;
-			}
-		} else if (state == HDLC_FLAG_SEARCH) { 
-			if (val & 1) {
-				r_one++;
-				if (r_one>6) {
-					state=HDLC_ZERO_SEARCH;
-				}
-			} else {
-				if (r_one==6) {
-					o_bitcnt=0;
-					r_val=0;
-					state=HDLC_FLAG_FOUND;
-				}
-				r_one=0;
-			}
-		} else if (state ==  HDLC_FLAG_FOUND) {
-			if (val & 1) {
-				r_one++;
-				if (r_one>6) {
-					state=HDLC_ZERO_SEARCH;
-				} else {
-					r_val >>= 1;
-					r_val |= 0x80;
-					o_bitcnt++;
-				}
-			} else {
-				if (r_one==6) {
-					o_bitcnt=0;
-					r_val=0;
-					r_one=0;
-					i_bitcnt++;
-					val >>= 1;
-					continue;
-				} else if (r_one!=5) {
-					r_val >>= 1;
-					r_val &= 0x7f;
-					o_bitcnt++;
-				}
-				r_one=0;	
-			}
-			if ((state != HDLC_ZERO_SEARCH) &&
-				!(o_bitcnt & 7)) {
-#ifdef DEBUGME
-				printf("HDLC_FRAME_FOUND at i_bitcnt:%d\n",i_bitcnt);
-#endif
-				state=HDLC_FRAME_FOUND;
-				fcs = PPP_INITFCS;
-				dst[0] = r_val;
-				fcs = PPP_FCS (fcs, r_val);
-			}
-		} else if (state ==  HDLC_FRAME_FOUND) {
-			if (val & 1) {
-				r_one++;
-				if (r_one>6) {
-					state=HDLC_ZERO_SEARCH;
-					o_bitcnt=0;
-				} else {
-					r_val >>= 1;
-					r_val |= 0x80;
-					o_bitcnt++;
-				}
-			} else {
-				if (r_one==6) {
-					r_val=0; 
-					r_one=0;
-					o_bitcnt++;
-					if (o_bitcnt & 7) {
-						/* Alignment error */
-#ifdef DEBUGME
-						printf("Alignment error\n");
-#endif
-						state=HDLC_FLAG_SEARCH;
-						retval = -1;
-					} else if (fcs==PPP_GOODFCS) {
-						/* Valid frame */
-						state=HDLC_FLAG_FOUND;
-						retval = (o_bitcnt>>3)-3;
-					} else {
-						/* CRC error */
-#ifdef DEBUGME
-						printf("CRC error; fcs was 0x%x, should have been 0x%x\n", fcs, PPP_GOODFCS);
-#endif
-						state=HDLC_FLAG_FOUND;
-						retval = -1;
-					}
-				} else if (r_one==5) {
-					r_one=0;
-					i_bitcnt++;
-					val >>= 1;
-					continue;
-				} else {
-					r_val >>= 1;
-					r_val &= 0x7f;
-					o_bitcnt++;
-				}
-				r_one=0;	
-			}
-			if ((state == HDLC_FRAME_FOUND) &&
-				!(o_bitcnt & 7)) {
-				if ((o_bitcnt>>3)>=dsize) {
-					/* Buffer overflow error */
-#ifdef DEBUGME
-					printf("Buffer overflow error\n");
-#endif
-					r_val=0; 
-					state=HDLC_FLAG_SEARCH;
-					retval = -1;
-				} else {
-					dst[(o_bitcnt>>3)-1] = r_val;
-					fcs = PPP_FCS (fcs, r_val);
-#ifdef DEBUGME
-					printf("Output byte %d: 0x%02x; FCS 0x%04x\n", (o_bitcnt>>3)-1, r_val, fcs);
-#endif
-				}
-			}
-		}
-		i_bitcnt ++;
-		val >>= 1;
-	}
-
-	/* We exhausted the source buffer before anything else happened
-	 * (retval==0).  Reset i_bitcnt in expectation of a new source
-	 * buffer.  Other, we either had an error or a valid frame, so
-	 * reset o_bitcnt in expectation of a new destination buffer.
-	 */
-
-	if (retval == 0) {
-		i_bitcnt = 0;
-	} else {
-		o_bitcnt = 0;
-	}
-
-	saved_state->state = state;
-	saved_state->r_one = r_one;
-	saved_state->r_val = r_val;
-	saved_state->fcs = fcs;
-	saved_state->o_bitcnt = o_bitcnt;
-	saved_state->i_bitcnt = i_bitcnt;
-
-	return (retval);
-}
-
-
-
-#ifdef DEBUGME
-
-char buffer[1024];
-char obuffer[1024];
-
-main()
-{
-  int buflen=0;
-  int len;
-  struct hdlc_state hdlc_state;
-
-  while((buffer[buflen] = getc(stdin)) != EOF && buflen<1024) buflen++;
-
-  printf("buflen = %d\n", buflen);
-
-  init_hdlc_state(&hdlc_state, 0);
-
-  while (len = read_raw_hdlc_data(&hdlc_state,buffer,buflen,obuffer,1024)) {
-    if (len == -1) printf("Error @ byte %d/bit %d\n",
-			  hdlc_state.i_bitcnt>>3, hdlc_state.i_bitcnt & 7);
-    else {
-      printf("Frame received: len %d\n", len);
-    }
-  }
-
-  printf("Done\n");
-}
-
-#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/isdn/hisax/rawhdlc.h linux-2.4.21-pre6/drivers/isdn/hisax/rawhdlc.h
--- linux-2.4.20/drivers/isdn/hisax/rawhdlc.h	2001-12-21 17:41:54.000000000 +0000
+++ linux-2.4.21-pre6/drivers/isdn/hisax/rawhdlc.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,28 +0,0 @@
-/* $Id: rawhdlc.h,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
- *
- * Author     Brent Baccala
- * Copyright  by Brent Baccala <baccala@FreeSoft.org>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#ifndef RAWHDLC_H
-struct hdlc_state {
-	char insane_mode;
-	u_char state;
-	u_char r_one;
-	u_char r_val;
-	u_int o_bitcnt;
-	u_int i_bitcnt;
-	u_int fcs;
-};
-
-
-int make_raw_hdlc_data(u_char *src, u_int slen, u_char *dst, u_int dsize);
-void init_hdlc_state(struct hdlc_state *stateptr, int mode);
-int read_raw_hdlc_data(struct hdlc_state *saved_state,
-                       u_char *src, u_int slen, u_char *dst, u_int dsize);
-#define RAWHDLC_H
-#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/isdn/hisax/st5481.h linux-2.4.21-pre6/drivers/isdn/hisax/st5481.h
--- linux-2.4.20/drivers/isdn/hisax/st5481.h	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/isdn/hisax/st5481.h	2003-03-26 23:49:50.000000000 +0000
@@ -227,7 +227,7 @@
 #define INFO(format, arg...) \
 printk(KERN_INFO __FILE__ ": " __FUNCTION__ ": " format "\n" , ## arg)
 
-#include "st5481_hdlc.h"
+#include "isdnhdlc.h"
 #include "fsm.h"
 #include "hisax_if.h"
 #include <linux/skbuff.h>
@@ -236,7 +236,7 @@
  * FIFO handling
  */
 
-/* Generic FIFO structure */ 
+/* Generic FIFO structure */
 struct fifo {
 	u_char r,w,count,size;
 	spinlock_t lock;
@@ -270,7 +270,7 @@
 		index = -1;
 	} else {
 		// Return index where to get the next data to add to the FIFO
-		index = fifo->w++ & (fifo->size-1); 
+		index = fifo->w++ & (fifo->size-1);
 		fifo->count++;
 	}
 	spin_unlock_irqrestore(&fifo->lock, flags);
@@ -289,13 +289,13 @@
 		return -1;
 	}
 
-	spin_lock_irqsave(&fifo->lock, flags);		
+	spin_lock_irqsave(&fifo->lock, flags);
 	if (!fifo->count) {
 		// FIFO empty
 		index = -1;
 	} else {
 		// Return index where to get the next data from the FIFO
-		index = fifo->r++ & (fifo->size-1); 
+		index = fifo->r++ & (fifo->size-1);
 		fifo->count--;
 	}
 	spin_unlock_irqrestore(&fifo->lock, flags);
@@ -336,7 +336,7 @@
 };
 
 struct st5481_d_out {
-	struct hdlc_vars hdlc_state;
+	struct isdnhdlc_vars hdlc_state;
 	struct urb *urb[2]; /* double buffering */
 	unsigned long busy;
 	struct sk_buff *tx_skb;
@@ -344,7 +344,7 @@
 };
 
 struct st5481_b_out {
-	struct hdlc_vars hdlc_state;
+	struct isdnhdlc_vars hdlc_state;
 	struct urb *urb[2]; /* double buffering */
 	u_char flow_event;
 	u_long busy;
@@ -352,7 +352,7 @@
 };
 
 struct st5481_in {
-	struct hdlc_vars hdlc_state;
+	struct isdnhdlc_vars hdlc_state;
 	struct urb *urb[2]; /* double buffering */
 	int mode;
 	int bufsize;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/isdn/hisax/st5481_b.c linux-2.4.21-pre6/drivers/isdn/hisax/st5481_b.c
--- linux-2.4.20/drivers/isdn/hisax/st5481_b.c	2001-12-21 17:41:54.000000000 +0000
+++ linux-2.4.21-pre6/drivers/isdn/hisax/st5481_b.c	2003-03-26 23:49:30.000000000 +0000
@@ -67,24 +67,28 @@
 				bytes_sent = buf_size - len;
 				if (skb->len < bytes_sent)
 					bytes_sent = skb->len;
-
-				memcpy(urb->transfer_buffer+len, skb->data, bytes_sent);
-				
+				{	/* swap tx bytes to get hearable audio data */
+					register unsigned char *src  = skb->data;
+					register unsigned char *dest = urb->transfer_buffer+len;
+					register unsigned int count;
+					for (count = 0; count < bytes_sent; count++)
+						*dest++ = isdnhdlc_bit_rev_tab[*src++];
+				}
 				len += bytes_sent;
 			} else {
-				len += hdlc_encode(&b_out->hdlc_state, 
-						   skb->data, skb->len, &bytes_sent,
-						   urb->transfer_buffer+len, buf_size-len);
+				len += isdnhdlc_encode(&b_out->hdlc_state,
+						       skb->data, skb->len, &bytes_sent,
+						       urb->transfer_buffer+len, buf_size-len);
 			}
 
 			skb_pull(skb, bytes_sent);
-			
+
 			if (!skb->len) {
 				// Frame sent
 				b_out->tx_skb = NULL;
 				B_L1L2(bcs, PH_DATA | CONFIRM, (void *) skb->truesize);
 				dev_kfree_skb_any(skb);
-				
+
 /* 				if (!(bcs->tx_skb = skb_dequeue(&bcs->sq))) { */
 /* 					st5481B_sched_event(bcs, B_XMTBUFREADY); */
 /* 				} */
@@ -95,9 +99,9 @@
 				len = buf_size;
 			} else {
 				// Send flags
-				len += hdlc_encode(&b_out->hdlc_state, 
-						   NULL, 0, &bytes_sent,
-						   urb->transfer_buffer+len, buf_size-len);
+				len += isdnhdlc_encode(&b_out->hdlc_state,
+						       NULL, 0, &bytes_sent,
+						       urb->transfer_buffer+len, buf_size-len);
 			}
 		}	
 	}
@@ -209,7 +213,7 @@
 	if (bcs->mode != L1_MODE_NULL) {
 		// Open the B channel
 		if (bcs->mode != L1_MODE_TRANS) {
-			hdlc_out_init(&b_out->hdlc_state, 0, bcs->mode == L1_MODE_HDLC_56K);
+			isdnhdlc_out_init(&b_out->hdlc_state, 0, bcs->mode == L1_MODE_HDLC_56K);
 		}
 		st5481_usb_pipe_reset(adapter, (bcs->channel+1)*2, NULL, NULL);
 	
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/isdn/hisax/st5481_d.c linux-2.4.21-pre6/drivers/isdn/hisax/st5481_d.c
--- linux-2.4.20/drivers/isdn/hisax/st5481_d.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/isdn/hisax/st5481_d.c	2003-03-26 23:49:35.000000000 +0000
@@ -313,15 +313,15 @@
 	buf_size = NUM_ISO_PACKETS_D * SIZE_ISO_PACKETS_D_OUT;
 	
 	if (skb) {
-		len = hdlc_encode(&d_out->hdlc_state, 
-				  skb->data, skb->len, &bytes_sent,
-				  urb->transfer_buffer, buf_size);
+		len = isdnhdlc_encode(&d_out->hdlc_state,
+				      skb->data, skb->len, &bytes_sent,
+				      urb->transfer_buffer, buf_size);
 		skb_pull(skb,bytes_sent);
 	} else {
 		// Send flags or idle
-		len = hdlc_encode(&d_out->hdlc_state, 
-				  NULL, 0, &bytes_sent,
-				  urb->transfer_buffer, buf_size);
+		len = isdnhdlc_encode(&d_out->hdlc_state,
+				      NULL, 0, &bytes_sent,
+				      urb->transfer_buffer, buf_size);
 	}
 	
 	if (len < buf_size) {
@@ -413,7 +413,7 @@
 
 	DBG(2,"len=%d",skb->len);
 
-	hdlc_out_init(&d_out->hdlc_state, 1, 0);
+	isdnhdlc_out_init(&d_out->hdlc_state, 1, 0);
 
 	if (test_and_set_bit(buf_nr, &d_out->busy)) {
 		WARN("ep %d urb %d busy %#lx", EP_D_OUT, buf_nr, d_out->busy);
@@ -422,9 +422,9 @@
 	urb = d_out->urb[buf_nr];
 
 	DBG_SKB(0x10, skb);
-	len = hdlc_encode(&d_out->hdlc_state, 
-			  skb->data, skb->len, &bytes_sent,
-			  urb->transfer_buffer, 16);
+	len = isdnhdlc_encode(&d_out->hdlc_state,
+			      skb->data, skb->len, &bytes_sent,
+			      urb->transfer_buffer, 16);
 	skb_pull(skb, bytes_sent);
 
 	if(len < 16)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/isdn/hisax/st5481_init.c linux-2.4.21-pre6/drivers/isdn/hisax/st5481_init.c
--- linux-2.4.20/drivers/isdn/hisax/st5481_init.c	2001-12-21 17:41:54.000000000 +0000
+++ linux-2.4.21-pre6/drivers/isdn/hisax/st5481_init.c	2003-03-26 23:49:30.000000000 +0000
@@ -14,7 +14,6 @@
  * TODO:
  *
  * b layer1 delay?
- * hdlc as module
  * hotplug / unregister issues
  * mod_inc/dec_use_count
  * unify parts of d/b channel usb handling
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/isdn/hisax/st5481_usb.c linux-2.4.21-pre6/drivers/isdn/hisax/st5481_usb.c
--- linux-2.4.20/drivers/isdn/hisax/st5481_usb.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/isdn/hisax/st5481_usb.c	2003-03-26 23:49:49.000000000 +0000
@@ -484,16 +484,18 @@
 	ptr = urb->transfer_buffer;
 	while (len > 0) {
 		if (in->mode == L1_MODE_TRANS) {
-			memcpy(in->rcvbuf, ptr, len);
+			/* swap rx bytes to get hearable audio */
+			register unsigned char *dest = in->rcvbuf;
 			status = len;
-			len = 0;
+			for (; len; len--)
+				*dest++ = isdnhdlc_bit_rev_tab[*ptr++];
 		} else {
-			status = hdlc_decode(&in->hdlc_state, ptr, len, &count,
-					     in->rcvbuf, in->bufsize);
+			status = isdnhdlc_decode(&in->hdlc_state, ptr, len, &count,
+					         in->rcvbuf, in->bufsize);
 			ptr += count;
 			len -= count;
 		}
-		
+
 		if (status > 0) {
 			// Good frame received
 			DBG(4,"count=%d",status);
@@ -622,8 +624,8 @@
 
 	if (in->mode != L1_MODE_NULL) {
 		if (in->mode != L1_MODE_TRANS)
-			hdlc_rcv_init(&in->hdlc_state,
-				      in->mode == L1_MODE_HDLC_56K);
+			isdnhdlc_rcv_init(&in->hdlc_state,
+				          in->mode == L1_MODE_HDLC_56K);
 		
 		st5481_usb_pipe_reset(in->adapter, in->ep, NULL, NULL);
 		st5481_usb_device_ctrl_msg(in->adapter, in->counter,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/isdn/hysdn/hysdn_boot.c linux-2.4.21-pre6/drivers/isdn/hysdn/hysdn_boot.c
--- linux-2.4.20/drivers/isdn/hysdn/hysdn_boot.c	2001-12-21 17:41:54.000000000 +0000
+++ linux-2.4.21-pre6/drivers/isdn/hysdn/hysdn_boot.c	2003-03-26 23:49:34.000000000 +0000
@@ -143,7 +143,7 @@
 					     (boot->pof_recid == TAG_CABSDATA) ? "CABSDATA" : "ABSDATA",
 					     datlen, boot->pof_recoffset);
 
-			if ((boot->last_error = card->writebootseq(card, boot->buf.BootBuf, datlen) < 0))
+			if ((boot->last_error = card->writebootseq(card, boot->buf.BootBuf, datlen)) < 0)
 				return (boot->last_error);	/* error writing data */
 
 			if (boot->pof_recoffset + datlen >= boot->pof_reclen)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/isdn/isdn_audio.c linux-2.4.21-pre6/drivers/isdn/isdn_audio.c
--- linux-2.4.20/drivers/isdn/isdn_audio.c	2002-02-25 19:37:58.000000000 +0000
+++ linux-2.4.21-pre6/drivers/isdn/isdn_audio.c	2003-03-26 23:48:57.000000000 +0000
@@ -169,39 +169,19 @@
 	0x8a, 0x8a, 0x6a, 0x6a, 0xea, 0xea, 0x2a, 0x2a
 };
 
-#define NCOEFF           16     /* number of frequencies to be analyzed       */
-#define DTMF_TRESH    25000     /* above this is dtmf                         */
+#define NCOEFF            8     /* number of frequencies to be analyzed       */
+#define DTMF_TRESH     4000     /* above this is dtmf                         */
 #define SILENCE_TRESH   200     /* below this is silence                      */
-#define H2_TRESH      20000     /* 2nd harmonic                               */
 #define AMP_BITS          9     /* bits per sample, reduced to avoid overflow */
 #define LOGRP             0
 #define HIGRP             1
 
-typedef struct {
-	int grp;                /* low/high group     */
-	int k;                  /* k                  */
-	int k2;                 /* k fuer 2. harmonic */
-} dtmf_t;
-
 /* For DTMF recognition:
  * 2 * cos(2 * PI * k / N) precalculated for all k
  */
 static int cos2pik[NCOEFF] =
 {
-	55812, 29528, 53603, 24032, 51193, 14443, 48590, 6517,
-	38113, -21204, 33057, -32186, 25889, -45081, 18332, -55279
-};
-
-static dtmf_t dtmf_tones[8] =
-{
-	{LOGRP, 0, 1},          /*  697 Hz */
-	{LOGRP, 2, 3},          /*  770 Hz */
-	{LOGRP, 4, 5},          /*  852 Hz */
-	{LOGRP, 6, 7},          /*  941 Hz */
-	{HIGRP, 8, 9},          /* 1209 Hz */
-	{HIGRP, 10, 11},        /* 1336 Hz */
-	{HIGRP, 12, 13},        /* 1477 Hz */
-	{HIGRP, 14, 15}         /* 1633 Hz */
+	55813, 53604, 51193, 48591, 38114, 33057, 25889, 18332
 };
 
 static char dtmf_matrix[4][4] =
@@ -499,6 +479,18 @@
 			sk2 = sk1;
 			sk1 = sk;
 		}
+		/* Avoid overflows */
+		sk >>= 1;
+		sk2 >>= 1;
+		/* compute |X(k)|**2 */
+		/* report overflows. This should not happen. */
+		/* Comment this out if desired */
+		if (sk < -32768 || sk > 32767)
+			printk(KERN_DEBUG
+			       "isdn_audio: dtmf goertzel overflow, sk=%d\n", sk);
+		if (sk2 < -32768 || sk2 > 32767)
+			printk(KERN_DEBUG
+			       "isdn_audio: dtmf goertzel overflow, sk2=%d\n", sk2);
 		result[k] =
 		    ((sk * sk) >> AMP_BITS) -
 		    ((((cos2pik[k] * sk) >> 15) * sk2) >> AMP_BITS) +
@@ -522,28 +514,58 @@
 	int grp[2];
 	char what;
 	char *p;
+	int thresh;
 
 	while ((skb = skb_dequeue(&info->dtmf_queue))) {
 		result = (int *) skb->data;
 		s = info->dtmf_state;
-		grp[LOGRP] = grp[HIGRP] = -2;
+		grp[LOGRP] = grp[HIGRP] = -1;
 		silence = 0;
-		for (i = 0; i < 8; i++) {
-			if ((result[dtmf_tones[i].k] > DTMF_TRESH) &&
-			    (result[dtmf_tones[i].k2] < H2_TRESH))
-				grp[dtmf_tones[i].grp] = (grp[dtmf_tones[i].grp] == -2) ? i : -1;
-			else if ((result[dtmf_tones[i].k] < SILENCE_TRESH) &&
-			      (result[dtmf_tones[i].k2] < SILENCE_TRESH))
+		thresh = 0;
+		for (i = 0; i < NCOEFF; i++) {
+			if (result[i] > DTMF_TRESH) {
+				if (result[i] > thresh)
+					thresh = result[i];
+			}
+			else if (result[i] < SILENCE_TRESH)
 				silence++;
 		}
-		if (silence == 8)
+		if (silence == NCOEFF)
 			what = ' ';
 		else {
-			if ((grp[LOGRP] >= 0) && (grp[HIGRP] >= 0)) {
-				what = dtmf_matrix[grp[LOGRP]][grp[HIGRP] - 4];
-				if (s->last != ' ' && s->last != '.')
-					s->last = what;	/* min. 1 non-DTMF between DTMF */
-			} else
+			if (thresh > 0)	{
+				thresh = thresh >> 4;  /* touchtones must match within 12 dB */
+				for (i = 0; i < NCOEFF; i++) {
+					if (result[i] < thresh)
+						continue;  /* ignore */
+					/* good level found. This is allowed only one time per group */
+					if (i < NCOEFF / 2) {
+						/* lowgroup*/
+						if (grp[LOGRP] >= 0) {
+							// Bad. Another tone found. */
+							grp[LOGRP] = -1;
+							break;
+						}
+						else
+							grp[LOGRP] = i;
+					}
+					else { /* higroup */
+						if (grp[HIGRP] >= 0) { // Bad. Another tone found. */
+							grp[HIGRP] = -1;
+							break;
+						}
+						else
+							grp[HIGRP] = i - NCOEFF/2;
+					}
+				}
+				if ((grp[LOGRP] >= 0) && (grp[HIGRP] >= 0)) {
+					what = dtmf_matrix[grp[LOGRP]][grp[HIGRP]];
+					if (s->last != ' ' && s->last != '.')
+						s->last = what;	/* min. 1 non-DTMF between DTMF */
+				} else
+					what = '.';
+			}
+			else
 				what = '.';
 		}
 		if ((what != s->last) && (what != ' ') && (what != '.')) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/isdn/isdn_audio.h linux-2.4.21-pre6/drivers/isdn/isdn_audio.h
--- linux-2.4.20/drivers/isdn/isdn_audio.h	2001-12-21 17:41:54.000000000 +0000
+++ linux-2.4.21-pre6/drivers/isdn/isdn_audio.h	2003-03-26 23:49:08.000000000 +0000
@@ -20,6 +20,7 @@
 
 typedef struct dtmf_state {
 	char last;
+	char llast;
 	int idx;
 	int buf[DTMF_NPOINTS];
 } dtmf_state;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/isdn/isdn_ppp.c linux-2.4.21-pre6/drivers/isdn/isdn_ppp.c
--- linux-2.4.20/drivers/isdn/isdn_ppp.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/isdn/isdn_ppp.c	2003-03-26 23:49:50.000000000 +0000
@@ -380,7 +380,7 @@
 	is->slcomp = NULL;
 #endif
 
-/* TODO: if this was the previous master: link the the stuff to the new master */
+/* TODO: if this was the previous master: link the stuff to the new master */
 	if(is->comp_stat)
 		is->compressor->free(is->comp_stat);
 	if(is->link_comp_stat)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/macintosh/nvram.c linux-2.4.21-pre6/drivers/macintosh/nvram.c
--- linux-2.4.20/drivers/macintosh/nvram.c	2001-10-15 20:43:24.000000000 +0000
+++ linux-2.4.21-pre6/drivers/macintosh/nvram.c	2003-03-26 23:49:06.000000000 +0000
@@ -113,8 +113,7 @@
 {
 	printk(KERN_INFO "Macintosh non-volatile memory driver v%s\n",
 		NVRAM_VERSION);
-	misc_register(&nvram_dev);
-	return 0;
+	return misc_register(&nvram_dev);
 }
 
 void __exit nvram_cleanup(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/md/linear.c linux-2.4.21-pre6/drivers/md/linear.c
--- linux-2.4.20/drivers/md/linear.c	2001-09-30 19:26:06.000000000 +0000
+++ linux-2.4.21-pre6/drivers/md/linear.c	2003-03-26 23:49:34.000000000 +0000
@@ -153,31 +153,29 @@
 	return 1;
 }
 
-static int linear_status (char *page, mddev_t *mddev)
+static void linear_status (struct seq_file *seq, mddev_t *mddev)
 {
-	int sz = 0;
 
 #undef MD_DEBUG
 #ifdef MD_DEBUG
 	int j;
 	linear_conf_t *conf = mddev_to_conf(mddev);
   
-	sz += sprintf(page+sz, "      ");
+	seq_printf(seq, "      ");
 	for (j = 0; j < conf->nr_zones; j++)
 	{
-		sz += sprintf(page+sz, "[%s",
+		seq_printf(seq, "[%s",
 			partition_name(conf->hash_table[j].dev0->dev));
 
 		if (conf->hash_table[j].dev1)
-			sz += sprintf(page+sz, "/%s] ",
+			seq_printf(seq, "/%s] ",
 			  partition_name(conf->hash_table[j].dev1->dev));
 		else
-			sz += sprintf(page+sz, "] ");
+			seq_printf(seq, "] ");
 	}
-	sz += sprintf(page+sz, "\n");
+	seq_printf(seq, "\n");
 #endif
-	sz += sprintf(page+sz, " %dk rounding", mddev->param.chunk_size/1024);
-	return sz;
+	seq_printf(seq, " %dk rounding", mddev->param.chunk_size/1024);
 }
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/md/lvm.c linux-2.4.21-pre6/drivers/md/lvm.c
--- linux-2.4.20/drivers/md/lvm.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/md/lvm.c	2003-03-26 23:49:40.000000000 +0000
@@ -2253,7 +2253,7 @@
 
 	if (lv_ptr->lv_access & LV_SNAPSHOT) {
 		/*
-		 * Atomically make the the snapshot invisible
+		 * Atomically make the snapshot invisible
 		 * to the original lv before playing with it.
 		 */
 		lv_t * org = lv_ptr->lv_snapshot_org;
@@ -2405,7 +2405,7 @@
 		}
 	}
 
-	/* save availiable i/o statistic data */
+	/* save available i/o statistic data */
 	if (old_lv->lv_stripes < 2) {	/* linear logical volume */
 		end = min(old_lv->lv_current_le, new_lv->lv_current_le);
 		for (l = 0; l < end; l++) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/md/md.c linux-2.4.21-pre6/drivers/md/md.c
--- linux-2.4.20/drivers/md/md.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/md/md.c	2003-03-26 23:49:21.000000000 +0000
@@ -445,21 +445,22 @@
 	if (rdev->sb)
 		MD_BUG();
 
-	rdev->sb = (mdp_super_t *) __get_free_page(GFP_KERNEL);
-	if (!rdev->sb) {
+	rdev->sb_page = alloc_page(GFP_KERNEL);
+	if (!rdev->sb_page) {
 		printk(OUT_OF_MEM);
 		return -EINVAL;
 	}
-	md_clear_page(rdev->sb);
+	rdev->sb = (mdp_super_t *) page_address(rdev->sb_page);
 
 	return 0;
 }
 
 static void free_disk_sb(mdk_rdev_t * rdev)
 {
-	if (rdev->sb) {
-		free_page((unsigned long) rdev->sb);
+	if (rdev->sb_page) {
+		page_cache_release(rdev->sb_page);
 		rdev->sb = NULL;
+		rdev->sb_page = NULL;
 		rdev->sb_offset = 0;
 		rdev->size = 0;
 	} else {
@@ -468,12 +469,43 @@
 	}
 }
 
+
+static void bh_complete(struct buffer_head *bh, int uptodate)
+{
+
+	if (uptodate)
+		set_bit(BH_Uptodate, &bh->b_state);
+
+	complete((struct completion*)bh->b_private);
+}
+
+static int sync_page_io(kdev_t dev, unsigned long sector, int size,
+			struct page *page, int rw)
+{
+	struct buffer_head bh;
+	struct completion event;
+
+	init_completion(&event);
+	init_buffer(&bh, bh_complete, &event);
+	bh.b_rdev = dev;
+	bh.b_rsector = sector;
+	bh.b_state	= (1 << BH_Req) | (1 << BH_Mapped) | (1 << BH_Lock);
+	bh.b_size = size;
+	bh.b_page = page;
+	bh.b_reqnext = NULL;
+	bh.b_data = page_address(page);
+	generic_make_request(rw, &bh);
+
+	run_task_queue(&tq_disk);
+	wait_for_completion(&event);
+
+	return test_bit(BH_Uptodate, &bh.b_state);
+}
+
 static int read_disk_sb(mdk_rdev_t * rdev)
 {
 	int ret = -EINVAL;
-	struct buffer_head *bh = NULL;
 	kdev_t dev = rdev->dev;
-	mdp_super_t *sb;
 	unsigned long sb_offset;
 
 	if (!rdev->sb) {
@@ -487,22 +519,14 @@
 	 */
 	sb_offset = calc_dev_sboffset(rdev->dev, rdev->mddev, 1);
 	rdev->sb_offset = sb_offset;
-	fsync_dev(dev);
-	set_blocksize (dev, MD_SB_BYTES);
-	bh = bread (dev, sb_offset / MD_SB_BLOCKS, MD_SB_BYTES);
-
-	if (bh) {
-		sb = (mdp_super_t *) bh->b_data;
-		memcpy (rdev->sb, sb, MD_SB_BYTES);
-	} else {
-		printk(NO_SB,partition_name(rdev->dev));
-		goto abort;
+
+	if (!sync_page_io(dev, sb_offset<<1, MD_SB_BYTES, rdev->sb_page, READ)) {
+		printk(NO_SB,partition_name(dev));
+		return -EINVAL;
 	}
 	printk(KERN_INFO " [events: %08lx]\n", (unsigned long)rdev->sb->events_lo);
 	ret = 0;
 abort:
-	if (bh)
-		brelse (bh);
 	return ret;
 }
 
@@ -890,10 +914,8 @@
 
 static int write_disk_sb(mdk_rdev_t * rdev)
 {
-	struct buffer_head *bh;
 	kdev_t dev;
 	unsigned long sb_offset, size;
-	mdp_super_t *sb;
 
 	if (!rdev->sb) {
 		MD_BUG();
@@ -928,23 +950,11 @@
 	}
 
 	printk(KERN_INFO "(write) %s's sb offset: %ld\n", partition_name(dev), sb_offset);
-	fsync_dev(dev);
-	set_blocksize(dev, MD_SB_BYTES);
-	bh = getblk(dev, sb_offset / MD_SB_BLOCKS, MD_SB_BYTES);
-	if (!bh) {
-		printk(GETBLK_FAILED, partition_name(dev));
+
+	if (!sync_page_io(dev, sb_offset<<1, MD_SB_BYTES, rdev->sb_page, WRITE)) {
+		printk("md: write_disk_sb failed for device %s\n", partition_name(dev));
 		return 1;
 	}
-	memset(bh->b_data,0,bh->b_size);
-	sb = (mdp_super_t *) bh->b_data;
-	memcpy(sb, rdev->sb, MD_SB_BYTES);
-
-	mark_buffer_uptodate(bh, 1);
-	mark_buffer_dirty(bh);
-	ll_rw_block(WRITE, 1, &bh);
-	wait_on_buffer(bh);
-	brelse(bh);
-	fsync_dev(dev);
 skip:
 	return 0;
 }
@@ -1038,7 +1048,11 @@
 			printk("(skipping faulty ");
 		if (rdev->alias_device)
 			printk("(skipping alias ");
-
+		if (!rdev->faulty && disk_faulty(&rdev->sb->this_disk)) {
+			printk("(skipping new-faulty %s )\n",
+			       partition_name(rdev->dev));
+			continue;
+		}
 		printk("%s ", partition_name(rdev->dev));
 		if (!rdev->faulty && !rdev->alias_device) {
 			printk("[events: %08lx]",
@@ -1065,7 +1079,6 @@
  *   - the device is nonexistent (zero size)
  *   - the device has no valid superblock
  *
- * a faulty rdev _never_ has rdev->sb set.
  */
 static int md_import_device(kdev_t newdev, int on_disk)
 {
@@ -1137,8 +1150,6 @@
 	md_list_add(&rdev->all, &all_raid_disks);
 	MD_INIT_LIST_HEAD(&rdev->pending);
 
-	if (rdev->faulty && rdev->sb)
-		free_disk_sb(rdev);
 	return 0;
 
 abort_free:
@@ -2337,20 +2348,16 @@
 		return -EINVAL;
 	}
 	disk = &mddev->sb->disks[rdev->desc_nr];
-	if (disk_active(disk)) {
-		MD_BUG();
+	if (disk_active(disk))
 		goto busy;
-	}
-	if (disk_removed(disk)) {
-		MD_BUG();
+
+	if (disk_removed(disk))
 		return -EINVAL;
-	}
 
 	err = mddev->pers->diskop(mddev, &disk, DISKOP_HOT_REMOVE_DISK);
-	if (err == -EBUSY) {
-		MD_BUG();
+	if (err == -EBUSY)
 		goto busy;
-	}
+
 	if (err) {
 		MD_BUG();
 		return -EINVAL;
@@ -2388,13 +2395,6 @@
 	}
 
 	persistent = !mddev->sb->not_persistent;
-	size = calc_dev_size(dev, mddev, persistent);
-
-	if (size < mddev->sb->size) {
-		printk(KERN_WARNING "md%d: disk size %d blocks < array size %d\n",
-				mdidx(mddev), size, mddev->sb->size);
-		return -ENOSPC;
-	}
 
 	rdev = find_rdev(mddev, dev);
 	if (rdev)
@@ -2416,6 +2416,14 @@
 		err = -EINVAL;
 		goto abort_export;
 	}
+	size = calc_dev_size(dev, mddev, persistent);
+
+	if (size < mddev->sb->size) {
+		printk(KERN_WARNING "md%d: disk size %d blocks < array size %d\n",
+				mdidx(mddev), size, mddev->sb->size);
+		err = -ENOSPC;
+		goto abort_export;
+	}
 	bind_rdev_to_array(rdev, mddev);
 
 	/*
@@ -2610,21 +2618,8 @@
 			goto done;
 #endif
 
-		case BLKGETSIZE:	/* Return device size */
-			if (!arg) {
-				err = -EINVAL;
-				MD_BUG();
-				goto abort;
-			}
-			err = md_put_user(md_hd_struct[minor].nr_sects,
-						(unsigned long *) arg);
-			goto done;
-
-		case BLKGETSIZE64:	/* Return device size */
-			err = md_put_user((u64)md_hd_struct[minor].nr_sects << 9,
-						(u64 *) arg);
-			goto done;
-
+		case BLKGETSIZE:
+		case BLKGETSIZE64:
 		case BLKRAGET:
 		case BLKRASET:
 		case BLKFLSBUF:
@@ -3056,7 +3051,6 @@
 		return 0;
 	if (!mddev->pers->error_handler
 			|| mddev->pers->error_handler(mddev,rdev) <= 0) {
-		free_disk_sb(rrdev);
 		rrdev->faulty = 1;
 	} else
 		return 1;
@@ -3072,13 +3066,13 @@
 	return 0;
 }
 
-static int status_unused(char * page)
+static void status_unused(struct seq_file *seq)
 {
-	int sz = 0, i = 0;
+	int i = 0;
 	mdk_rdev_t *rdev;
 	struct md_list_head *tmp;
 
-	sz += sprintf(page + sz, "unused devices: ");
+	seq_printf(seq, "unused devices: ");
 
 	ITERATE_RDEV_ALL(rdev,tmp) {
 		if (!rdev->same_set.next && !rdev->same_set.prev) {
@@ -3086,21 +3080,19 @@
 			 * The device is not yet used by any array.
 			 */
 			i++;
-			sz += sprintf(page + sz, "%s ",
+			seq_printf(seq, "%s ",
 				partition_name(rdev->dev));
 		}
 	}
 	if (!i)
-		sz += sprintf(page + sz, "<none>");
+		seq_printf(seq, "<none>");
 
-	sz += sprintf(page + sz, "\n");
-	return sz;
+	seq_printf(seq, "\n");
 }
 
 
-static int status_resync(char * page, mddev_t * mddev)
+static void status_resync(struct seq_file *seq, mddev_t * mddev)
 {
-	int sz = 0;
 	unsigned long max_blocks, resync, res, dt, db, rt;
 
 	resync = (mddev->curr_resync - atomic_read(&mddev->recovery_active))/2;
@@ -3109,32 +3101,31 @@
 	/*
 	 * Should not happen.
 	 */
-	if (!max_blocks) {
+	if (!max_blocks)
 		MD_BUG();
-		return 0;
-	}
+
 	res = (resync/1024)*1000/(max_blocks/1024 + 1);
 	{
 		int i, x = res/50, y = 20-x;
-		sz += sprintf(page + sz, "[");
+		seq_printf(seq, "[");
 		for (i = 0; i < x; i++)
-			sz += sprintf(page + sz, "=");
-		sz += sprintf(page + sz, ">");
+			seq_printf(seq, "=");
+		seq_printf(seq, ">");
 		for (i = 0; i < y; i++)
-			sz += sprintf(page + sz, ".");
-		sz += sprintf(page + sz, "] ");
+			seq_printf(seq, ".");
+		seq_printf(seq, "] ");
 	}
 	if (!mddev->recovery_running)
 		/*
 		 * true resync
 		 */
-		sz += sprintf(page + sz, " resync =%3lu.%lu%% (%lu/%lu)",
+		seq_printf(seq, " resync =%3lu.%lu%% (%lu/%lu)",
 				res/10, res % 10, resync, max_blocks);
 	else
 		/*
 		 * recovery ...
 		 */
-		sz += sprintf(page + sz, " recovery =%3lu.%lu%% (%lu/%lu)",
+		seq_printf(seq, " recovery =%3lu.%lu%% (%lu/%lu)",
 				res/10, res % 10, resync, max_blocks);
 
 	/*
@@ -3151,84 +3142,156 @@
 	db = resync - (mddev->resync_mark_cnt/2);
 	rt = (dt * ((max_blocks-resync) / (db/100+1)))/100;
 
-	sz += sprintf(page + sz, " finish=%lu.%lumin", rt / 60, (rt % 60)/6);
+	seq_printf(seq, " finish=%lu.%lumin", rt / 60, (rt % 60)/6);
 
-	sz += sprintf(page + sz, " speed=%ldK/sec", db/dt);
+	seq_printf(seq, " speed=%ldK/sec", db/dt);
 
-	return sz;
 }
 
-static int md_status_read_proc(char *page, char **start, off_t off,
-			int count, int *eof, void *data)
+
+static void *md_seq_start(struct seq_file *seq, loff_t *pos)
 {
-	int sz = 0, j, size;
-	struct md_list_head *tmp, *tmp2;
-	mdk_rdev_t *rdev;
+	struct list_head *tmp;
+	loff_t l = *pos;
 	mddev_t *mddev;
 
-	sz += sprintf(page + sz, "Personalities : ");
-	for (j = 0; j < MAX_PERSONALITY; j++)
-	if (pers[j])
-		sz += sprintf(page+sz, "[%s] ", pers[j]->name);
+	if (l > 0x10000)
+		return NULL;
+	if (!l--)
+		/* header */
+		return (void*)1;
 
-	sz += sprintf(page+sz, "\n");
+	list_for_each(tmp,&all_mddevs)
+		if (!l--) {
+			mddev = list_entry(tmp, mddev_t, all_mddevs);
+			return mddev;
+		}
+	return (void*)2;/* tail */
+}
 
+static void *md_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	struct list_head *tmp;
+	mddev_t *next_mddev, *mddev = v;
+	
+	++*pos;
+	if (v == (void*)2)
+		return NULL;
 
-	sz += sprintf(page+sz, "read_ahead ");
-	if (read_ahead[MD_MAJOR] == INT_MAX)
-		sz += sprintf(page+sz, "not set\n");
+	if (v == (void*)1)
+		tmp = all_mddevs.next;
 	else
-		sz += sprintf(page+sz, "%d sectors\n", read_ahead[MD_MAJOR]);
+		tmp = mddev->all_mddevs.next;
+	if (tmp != &all_mddevs)
+		next_mddev = list_entry(tmp,mddev_t,all_mddevs);
+	else {
+		next_mddev = (void*)2;
+		*pos = 0x10000;
+	}		
 
-	ITERATE_MDDEV(mddev,tmp) {
-		sz += sprintf(page + sz, "md%d : %sactive", mdidx(mddev),
-						mddev->pers ? "" : "in");
-		if (mddev->pers) {
-			if (mddev->ro)
-				sz += sprintf(page + sz, " (read-only)");
-			sz += sprintf(page + sz, " %s", mddev->pers->name);
-		}
+	return next_mddev;
 
-		size = 0;
-		ITERATE_RDEV(mddev,rdev,tmp2) {
-			sz += sprintf(page + sz, " %s[%d]",
-				partition_name(rdev->dev), rdev->desc_nr);
-			if (rdev->faulty) {
-				sz += sprintf(page + sz, "(F)");
-				continue;
-			}
-			size += rdev->size;
-		}
+}
 
-		if (mddev->nb_dev) {
-			if (mddev->pers)
-				sz += sprintf(page + sz, "\n      %d blocks",
-						 md_size[mdidx(mddev)]);
-			else
-				sz += sprintf(page + sz, "\n      %d blocks", size);
-		}
+static void md_seq_stop(struct seq_file *seq, void *v)
+{
+
+}
 
-		if (!mddev->pers) {
-			sz += sprintf(page+sz, "\n");
+static int md_seq_show(struct seq_file *seq, void *v)
+{
+	int j, size;
+	struct md_list_head *tmp2;
+	mdk_rdev_t *rdev;
+	mddev_t *mddev = v;
+
+	if (v == (void*)1) {
+		seq_printf(seq, "Personalities : ");
+		for (j = 0; j < MAX_PERSONALITY; j++)
+			if (pers[j])
+				seq_printf(seq, "[%s] ", pers[j]->name);
+
+		seq_printf(seq, "\n");
+		seq_printf(seq, "read_ahead ");
+		if (read_ahead[MD_MAJOR] == INT_MAX)
+			seq_printf(seq, "not set\n");
+		else
+			seq_printf(seq, "%d sectors\n", read_ahead[MD_MAJOR]);
+		return 0;
+	}
+	if (v == (void*)2) {
+		status_unused(seq);
+		return 0;
+	}
+
+	seq_printf(seq, "md%d : %sactive", mdidx(mddev),
+		   mddev->pers ? "" : "in");
+	if (mddev->pers) {
+		if (mddev->ro)
+			seq_printf(seq, " (read-only)");
+		seq_printf(seq, " %s", mddev->pers->name);
+	}
+	
+	size = 0;
+	ITERATE_RDEV(mddev,rdev,tmp2) {
+		seq_printf(seq, " %s[%d]",
+			   partition_name(rdev->dev), rdev->desc_nr);
+		if (rdev->faulty) {
+			seq_printf(seq, "(F)");
 			continue;
 		}
+		size += rdev->size;
+	}
 
-		sz += mddev->pers->status (page+sz, mddev);
+	if (mddev->nb_dev) {
+		if (mddev->pers)
+			seq_printf(seq, "\n      %d blocks",
+				   md_size[mdidx(mddev)]);
+		else
+			seq_printf(seq, "\n      %d blocks", size);
+	}
 
-		sz += sprintf(page+sz, "\n      ");
+	if (mddev->pers) {
+
+		mddev->pers->status (seq, mddev);
+
+		seq_printf(seq, "\n      ");
 		if (mddev->curr_resync) {
-			sz += status_resync (page+sz, mddev);
+			status_resync (seq, mddev);
 		} else {
 			if (sem_getcount(&mddev->resync_sem) != 1)
-				sz += sprintf(page + sz, "	resync=DELAYED");
+				seq_printf(seq, "	resync=DELAYED");
 		}
-		sz += sprintf(page + sz, "\n");
 	}
-	sz += status_unused(page + sz);
+	seq_printf(seq, "\n");
 
-	return sz;
+	return 0;
 }
 
+  
+static struct seq_operations md_seq_ops = {
+	.start  = md_seq_start,
+	.next   = md_seq_next,
+	.stop   = md_seq_stop,
+	.show   = md_seq_show,
+};
+
+static int md_seq_open(struct inode *inode, struct file *file)
+{
+	int error;
+
+	error = seq_open(file, &md_seq_ops);
+	return error;
+}
+
+static struct file_operations md_seq_fops = {
+	.open           = md_seq_open,
+	.read           = seq_read,
+	.llseek         = seq_lseek,
+	.release	= seq_release,
+};
+
+
 int register_md_personality(int pnum, mdk_personality_t *p)
 {
 	if (pnum >= MAX_PERSONALITY) {
@@ -3628,6 +3691,7 @@
 
 static void md_geninit(void)
 {
+	struct proc_dir_entry *p;
 	int i;
 
 	for(i = 0; i < MAX_MD_DEVS; i++) {
@@ -3644,7 +3708,9 @@
 	dprintk("md: sizeof(mdp_super_t) = %d\n", (int)sizeof(mdp_super_t));
 
 #ifdef CONFIG_PROC_FS
-	create_proc_read_entry("mdstat", 0, NULL, md_status_read_proc, NULL);
+	p = create_proc_entry("mdstat", S_IRUGO, NULL);
+	if (p)
+		p->proc_fops = &md_seq_fops;
 #endif
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/md/multipath.c linux-2.4.21-pre6/drivers/md/multipath.c
--- linux-2.4.20/drivers/md/multipath.c	2002-02-25 19:37:58.000000000 +0000
+++ linux-2.4.21-pre6/drivers/md/multipath.c	2003-03-26 23:49:35.000000000 +0000
@@ -281,18 +281,17 @@
 	return 0;
 }
 
-static int multipath_status (char *page, mddev_t *mddev)
+static void multipath_status (struct seq_file *seq, mddev_t *mddev)
 {
 	multipath_conf_t *conf = mddev_to_conf(mddev);
-	int sz = 0, i;
+	int i;
 	
-	sz += sprintf (page+sz, " [%d/%d] [", conf->raid_disks,
+	seq_printf (seq, " [%d/%d] [", conf->raid_disks,
 						 conf->working_disks);
 	for (i = 0; i < conf->raid_disks; i++)
-		sz += sprintf (page+sz, "%s",
+		seq_printf (seq, "%s",
 			conf->multipaths[i].operational ? "U" : "_");
-	sz += sprintf (page+sz, "]");
-	return sz;
+	seq_printf (seq, "]");
 }
 
 #define LAST_DISK KERN_ALERT \
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/md/raid0.c linux-2.4.21-pre6/drivers/md/raid0.c
--- linux-2.4.20/drivers/md/raid0.c	2001-09-30 19:26:06.000000000 +0000
+++ linux-2.4.21-pre6/drivers/md/raid0.c	2003-03-26 23:49:40.000000000 +0000
@@ -289,41 +289,40 @@
 	return 0;
 }
 			   
-static int raid0_status (char *page, mddev_t *mddev)
+static void raid0_status (struct seq_file *seq, mddev_t *mddev)
 {
-	int sz = 0;
 #undef MD_DEBUG
 #ifdef MD_DEBUG
 	int j, k;
 	raid0_conf_t *conf = mddev_to_conf(mddev);
   
-	sz += sprintf(page + sz, "      ");
+	seq_printf(seq, "      ");
 	for (j = 0; j < conf->nr_zones; j++) {
-		sz += sprintf(page + sz, "[z%d",
+		seq_printf(seq, "[z%d",
 				conf->hash_table[j].zone0 - conf->strip_zone);
 		if (conf->hash_table[j].zone1)
-			sz += sprintf(page+sz, "/z%d] ",
+			seq_printf(seq, "/z%d] ",
 				conf->hash_table[j].zone1 - conf->strip_zone);
 		else
-			sz += sprintf(page+sz, "] ");
+			seq_printf(seq, "] ");
 	}
   
-	sz += sprintf(page + sz, "\n");
+	seq_printf(seq, "\n");
   
 	for (j = 0; j < conf->nr_strip_zones; j++) {
-		sz += sprintf(page + sz, "      z%d=[", j);
+		seq_printf(seq, "      z%d=[", j);
 		for (k = 0; k < conf->strip_zone[j].nb_dev; k++)
-			sz += sprintf (page+sz, "%s/", partition_name(
+			seq_printf (seq, "%s/", partition_name(
 				conf->strip_zone[j].dev[k]->dev));
-		sz--;
-		sz += sprintf (page+sz, "] zo=%d do=%d s=%d\n",
+
+		seq_printf (seq, "] zo=%d do=%d s=%d\n",
 				conf->strip_zone[j].zone_offset,
 				conf->strip_zone[j].dev_offset,
 				conf->strip_zone[j].size);
 	}
 #endif
-	sz += sprintf(page + sz, " %dk chunks", mddev->param.chunk_size/1024);
-	return sz;
+	seq_printf(seq, " %dk chunks", mddev->param.chunk_size/1024);
+	return;
 }
 
 static mdk_personality_t raid0_personality=
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/md/raid1.c linux-2.4.21-pre6/drivers/md/raid1.c
--- linux-2.4.20/drivers/md/raid1.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/md/raid1.c	2003-03-26 23:48:57.000000000 +0000
@@ -719,18 +719,17 @@
 	return (0);
 }
 
-static int raid1_status (char *page, mddev_t *mddev)
+static void raid1_status(struct seq_file *seq, mddev_t *mddev)
 {
 	raid1_conf_t *conf = mddev_to_conf(mddev);
-	int sz = 0, i;
+	int i;
 	
-	sz += sprintf (page+sz, " [%d/%d] [", conf->raid_disks,
+	seq_printf(seq, " [%d/%d] [", conf->raid_disks,
 						 conf->working_disks);
 	for (i = 0; i < conf->raid_disks; i++)
-		sz += sprintf (page+sz, "%s",
+		seq_printf(seq, "%s",
 			conf->mirrors[i].operational ? "U" : "_");
-	sz += sprintf (page+sz, "]");
-	return sz;
+	seq_printf(seq, "]");
 }
 
 #define LAST_DISK KERN_ALERT \
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/md/raid5.c linux-2.4.21-pre6/drivers/md/raid5.c
--- linux-2.4.20/drivers/md/raid5.c	2002-02-25 19:37:58.000000000 +0000
+++ linux-2.4.21-pre6/drivers/md/raid5.c	2003-03-26 23:49:10.000000000 +0000
@@ -1681,23 +1681,23 @@
 }
 #endif
 
-static int raid5_status (char *page, mddev_t *mddev)
+static void raid5_status (struct seq_file *seq, mddev_t *mddev)
 {
 	raid5_conf_t *conf = (raid5_conf_t *) mddev->private;
 	mdp_super_t *sb = mddev->sb;
-	int sz = 0, i;
+	int i;
 
-	sz += sprintf (page+sz, " level %d, %dk chunk, algorithm %d", sb->level, sb->chunk_size >> 10, sb->layout);
-	sz += sprintf (page+sz, " [%d/%d] [", conf->raid_disks, conf->working_disks);
+	seq_printf (seq, " level %d, %dk chunk, algorithm %d", sb->level, sb->chunk_size >> 10, sb->layout);
+	seq_printf (seq, " [%d/%d] [", conf->raid_disks, conf->working_disks);
 	for (i = 0; i < conf->raid_disks; i++)
-		sz += sprintf (page+sz, "%s", conf->disks[i].operational ? "U" : "_");
-	sz += sprintf (page+sz, "]");
+		seq_printf (seq, "%s", conf->disks[i].operational ? "U" : "_");
+	seq_printf (seq, "]");
 #if RAID5_DEBUG
 #define D(x) \
-	sz += sprintf (page+sz, "<"#x":%d>", atomic_read(&conf->x))
+	seq_printf (seq, "<"#x":%d>", atomic_read(&conf->x))
 	printall(conf);
 #endif
-	return sz;
+
 }
 
 static void print_raid5_conf (raid5_conf_t *conf)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/radio/Config.in linux-2.4.21-pre6/drivers/media/radio/Config.in
--- linux-2.4.20/drivers/media/radio/Config.in	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/media/radio/Config.in	2003-03-26 23:49:40.000000000 +0000
@@ -30,6 +30,7 @@
 if [ "$CONFIG_ISA" = "y" ]; then
    dep_tristate '    miroSOUND PCM20 radio RDS user interface (EXPERIMENTAL)' CONFIG_RADIO_MIROPCM20_RDS $CONFIG_RADIO_MIROPCM20 $CONFIG_EXPERIMENTAL
    dep_tristate '  SF16FMI Radio' CONFIG_RADIO_SF16FMI $CONFIG_VIDEO_DEV
+   dep_tristate '  SF16FMR2 Radio' CONFIG_RADIO_SF16FMR2 $CONFIG_VIDEO_DEV
    dep_tristate '  TerraTec ActiveRadio ISA Standalone' CONFIG_RADIO_TERRATEC $CONFIG_VIDEO_DEV
    if [ "$CONFIG_RADIO_TERRATEC" = "y" ]; then
       hex '    Terratec i/o port (normally 0x590)' CONFIG_RADIO_TERRATEC_PORT 590
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/radio/Makefile linux-2.4.21-pre6/drivers/media/radio/Makefile
--- linux-2.4.20/drivers/media/radio/Makefile	2001-08-05 20:15:05.000000000 +0000
+++ linux-2.4.21-pre6/drivers/media/radio/Makefile	2003-03-26 23:49:40.000000000 +0000
@@ -30,6 +30,7 @@
 obj-$(CONFIG_RADIO_AZTECH) += radio-aztech.o
 obj-$(CONFIG_RADIO_RTRACK2) += radio-rtrack2.o
 obj-$(CONFIG_RADIO_SF16FMI) += radio-sf16fmi.o
+obj-$(CONFIG_RADIO_SF16FMR2) += radio-sf16fmr2.o
 obj-$(CONFIG_RADIO_CADET) += radio-cadet.o
 obj-$(CONFIG_RADIO_TYPHOON) += radio-typhoon.o
 obj-$(CONFIG_RADIO_TERRATEC) += radio-terratec.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/radio/radio-aimslab.c linux-2.4.21-pre6/drivers/media/radio/radio-aimslab.c
--- linux-2.4.20/drivers/media/radio/radio-aimslab.c	2001-09-30 19:26:06.000000000 +0000
+++ linux-2.4.21-pre6/drivers/media/radio/radio-aimslab.c	2003-03-26 23:49:20.000000000 +0000
@@ -1,6 +1,6 @@
 /* radiotrack (radioreveal) driver for Linux radio support
  * (c) 1997 M. Kirkwood
- * Coverted to new API by Alan Cox <Alan.Cox@linux.org>
+ * Converted to new API by Alan Cox <Alan.Cox@linux.org>
  * Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
  *
  * History:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/radio/radio-cadet.c linux-2.4.21-pre6/drivers/media/radio/radio-cadet.c
--- linux-2.4.20/drivers/media/radio/radio-cadet.c	2001-09-30 19:26:06.000000000 +0000
+++ linux-2.4.21-pre6/drivers/media/radio/radio-cadet.c	2003-03-26 23:49:34.000000000 +0000
@@ -20,7 +20,9 @@
  *		Removed dead CONFIG_RADIO_CADET_PORT code
  *		PnP detection on load is now default (no args necessary)
  *
-*/
+ * 2003-01-31	Alan Cox <alan@redhat.com>
+ *		Cleaned up locking, delay code, general odds and ends
+ */
 
 #include <linux/module.h>	/* Modules 			*/
 #include <linux/init.h>		/* Initdata			*/
@@ -40,11 +42,11 @@
 static int curtuner=0;
 static int tunestat=0;
 static int sigstrength=0;
-static wait_queue_head_t tunerq,rdsq,readq;
+static wait_queue_head_t readq;
 struct timer_list tunertimer,rdstimer,readtimer;
 static __u8 rdsin=0,rdsout=0,rdsstat=0;
 static unsigned char rdsbuf[RDS_BUFFER];
-static int cadet_lock=0;
+static spinlock_t cadet_io_lock;
 
 static int cadet_probe(void);
 static struct pci_dev *dev;
@@ -57,37 +59,19 @@
  */
 static __u16 sigtable[2][4]={{5,10,30,150},{28,40,63,1000}};
 
-void cadet_wake(unsigned long qnum)
-{
-        switch(qnum) {
-	case 0:           /* cadet_setfreq */
-	        wake_up(&tunerq);
-		break;
-	case 1:           /* cadet_getrds */
-	        wake_up(&rdsq);
-		break;
-	}	
-}
-
-
-
 static int cadet_getrds(void)
 {
         int rdsstat=0;
 
-	cadet_lock++;
+	spin_lock(&cadet_io_lock);
         outb(3,io);                 /* Select Decoder Control/Status */
 	outb(inb(io+1)&0x7f,io+1);  /* Reset RDS detection */
-	cadet_lock--;
-	init_timer(&rdstimer);
-	rdstimer.function=cadet_wake;
-	rdstimer.data=(unsigned long)1;
-	rdstimer.expires=jiffies+(HZ/10);
-	init_waitqueue_head(&rdsq);
-	add_timer(&rdstimer);
-	sleep_on(&rdsq);
+	spin_unlock(&cadet_io_lock);
 	
-	cadet_lock++;
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(HZ/10);
+
+	spin_lock(&cadet_io_lock);	
         outb(3,io);                 /* Select Decoder Control/Status */
 	if((inb(io+1)&0x80)!=0) {
 	        rdsstat|=VIDEO_TUNER_RDS_ON;
@@ -95,32 +79,24 @@
 	if((inb(io+1)&0x10)!=0) {
 	        rdsstat|=VIDEO_TUNER_MBS_ON;
 	}
-	cadet_lock--;
+	spin_unlock(&cadet_io_lock);
 	return rdsstat;
+	
 }
 
-
-
-
 static int cadet_getstereo(void)
 {
-        if(curtuner!=0) {          /* Only FM has stereo capability! */
+	int ret = 0;
+        if(curtuner != 0)           /* Only FM has stereo capability! */
 	        return 0;
-	}
-        cadet_lock++;
+	spin_lock(&cadet_io_lock);
         outb(7,io);          /* Select tuner control */
-        if((inb(io+1)&0x40)==0) {
-	        cadet_lock--;
-                return 1;    /* Stereo pilot detected */
-        }
-        else {
-	        cadet_lock--;
-                return 0;    /* Mono */
-        }
+	if( (inb(io+1) & 0x40) == 0)
+        	ret = 1;
+        spin_unlock(&cadet_io_lock);
+        return ret;
 }
 
-
-
 static unsigned cadet_gettune(void)
 {
         int curvol,i;
@@ -129,7 +105,9 @@
         /*
          * Prepare for read
          */
-	cadet_lock++;
+
+	spin_lock(&cadet_io_lock);
+	
         outb(7,io);       /* Select tuner control */
         curvol=inb(io+1); /* Save current volume/mute setting */
         outb(0x00,io+1);  /* Ensure WRITE-ENABLE is LOW */
@@ -151,7 +129,8 @@
          * Restore volume/mute setting
          */
         outb(curvol,io+1);
-	cadet_lock--;
+
+	spin_unlock(&cadet_io_lock);
 	
 	return fifo;
 }
@@ -197,7 +176,8 @@
         int i;
 	unsigned test;  
 
-	cadet_lock++;
+	spin_lock(&cadet_io_lock);
+	
 	outb(7,io);                /* Select tuner control */
 	/*
 	 * Write the shift register
@@ -216,7 +196,7 @@
 		test=0x1c|((fifo>>23)&0x02);
 		outb(test,io+1);
 	}
-	cadet_lock--;
+	spin_unlock(&cadet_io_lock);
 }
 
 
@@ -252,92 +232,92 @@
         /*
          * Save current volume/mute setting
          */
-	cadet_lock++;
+
+	spin_lock(&cadet_io_lock);
 	outb(7,io);                /* Select tuner control */
         curvol=inb(io+1); 
+        spin_unlock(&cadet_io_lock);
 
 	/*
 	 * Tune the card
 	 */
 	for(j=3;j>-1;j--) {
 	        cadet_settune(fifo|(j<<16));
+	        
+	        spin_lock(&cadet_io_lock);
 		outb(7,io);         /* Select tuner control */
 		outb(curvol,io+1);
-		cadet_lock--;
-		init_timer(&tunertimer);
-		tunertimer.function=cadet_wake;
-		tunertimer.data=(unsigned long)0;
-		tunertimer.expires=jiffies+(HZ/10);
-		init_waitqueue_head(&tunerq);
-		add_timer(&tunertimer);
-		sleep_on(&tunerq);
+		spin_unlock(&cadet_io_lock);
+		
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(HZ/10);
+
 		cadet_gettune();
-		if((tunestat&0x40)==0) {   /* Tuned */
+		if((tunestat & 0x40) == 0) {   /* Tuned */
 		        sigstrength=sigtable[curtuner][j];
 			return;
 		}
-		cadet_lock++;
 	}
-	cadet_lock--;
 	sigstrength=0;
 }
 
 
 static int cadet_getvol(void)
 {
-        cadet_lock++;
+	int ret = 0;
+	
+	spin_lock(&cadet_io_lock);
+	
         outb(7,io);                /* Select tuner control */
-        if((inb(io+1)&0x20)!=0) {
-	        cadet_lock--;
-                return 0xffff;
-        }
-        else {
-	        cadet_lock--;
-                return 0;
-        }
+        if((inb(io + 1) & 0x20) != 0)
+        	ret = 0xffff;
+        
+        spin_unlock(&cadet_io_lock);
+        return ret;
 }
 
 
 static void cadet_setvol(int vol)
 {
-        cadet_lock++;
+	spin_lock(&cadet_io_lock);
         outb(7,io);                /* Select tuner control */
-        if(vol>0) {
+        if(vol>0)
                 outb(0x20,io+1);
-        }
-        else {
+        else
                 outb(0x00,io+1);
-        }
-	cadet_lock--;
-}  
 
+	spin_unlock(&cadet_io_lock);
+}  
 
 
-void cadet_handler(unsigned long data)
+static void cadet_handler(unsigned long data)
 {
 	/*
 	 * Service the RDS fifo
 	 */
-        if(cadet_lock==0) {
+
+	if(spin_trylock(&cadet_io_lock))
+	{
 	        outb(0x3,io);       /* Select RDS Decoder Control */
 		if((inb(io+1)&0x20)!=0) {
 		        printk(KERN_CRIT "cadet: RDS fifo overflow\n");
 		}
 		outb(0x80,io);      /* Select RDS fifo */
 		while((inb(io)&0x80)!=0) {
-		        rdsbuf[rdsin++]=inb(io+1);
+		        rdsbuf[rdsin]=inb(io+1);
 			if(rdsin==rdsout) {
-			        printk(KERN_CRIT "cadet: RDS buffer overflow\n");
+			        printk(KERN_WARNING "cadet: RDS buffer overflow\n");
 			}
+			else rdsin++;
 		}
+		spin_unlock(&cadet_io_lock);
 	}
 
 	/*
 	 * Service pending read
 	 */
-	if( rdsin!=rdsout) {
+	if( rdsin!=rdsout)
 	        wake_up_interruptible(&readq);
-	}
 
 	/* 
 	 * Clean up and exit
@@ -358,10 +338,10 @@
 	unsigned char readbuf[RDS_BUFFER];
 
         if(rdsstat==0) {
-	        cadet_lock++;
+		spin_lock(&cadet_io_lock);
 	        rdsstat=1;
 		outb(0x80,io);        /* Select RDS fifo */
-		cadet_lock--;
+		spin_unlock(&cadet_io_lock);
 		init_timer(&readtimer);
 		readtimer.function=cadet_handler;
 		readtimer.data=(unsigned long)0;
@@ -369,17 +349,15 @@
 		add_timer(&readtimer);
 	}
 	if(rdsin==rdsout) {
-  	        if(nonblock) {
+  	        if(nonblock)
 		        return -EWOULDBLOCK;
-		}
 	        interruptible_sleep_on(&readq);
 	}		
-	while((i<count)&&(rdsin!=rdsout)) {
+	while( i < count && rdsin != rdsout) {
 	        readbuf[i++]=rdsbuf[rdsout++];
 	}
-	if(copy_to_user(buf,readbuf,i)) {
+	if(copy_to_user(buf,readbuf,i))
 	        return -EFAULT;
-	}
 	return i;
 }
 
@@ -393,14 +371,10 @@
 		case VIDIOCGCAP:
 		{
 			struct video_capability v;
+			memset(&v, 0, sizeof(v));
 			v.type=VID_TYPE_TUNER;
 			v.channels=2;
 			v.audios=1;
-			/* No we don't do pictures */
-			v.maxwidth=0;
-			v.maxheight=0;
-			v.minwidth=0;
-			v.minheight=0;
 			strcpy(v.name, "ADS Cadet");
 			if(copy_to_user(arg,&v,sizeof(v)))
 				return -EFAULT;
@@ -409,54 +383,46 @@
 		case VIDIOCGTUNER:
 		{
 			struct video_tuner v;
-			if(copy_from_user(&v, arg,sizeof(v))!=0) { 
+			if(copy_from_user(&v, arg,sizeof(v))!=0)
 				return -EFAULT;
-			}
-			if((v.tuner<0)||(v.tuner>1)) {
-				return -EINVAL;
-			}
+			
 			switch(v.tuner) {
-			        case 0:
+		        case 0:
 			        strcpy(v.name,"FM");
 			        v.rangelow=1400;     /* 87.5 MHz */
 			        v.rangehigh=1728;    /* 108.0 MHz */
 			        v.flags=0;
-			        v.mode=0;
 			        v.mode|=VIDEO_MODE_AUTO;
-			        v.signal=sigstrength;
-			        if(cadet_getstereo()==1) {
+			        if(cadet_getstereo()==1)
 				        v.flags|=VIDEO_TUNER_STEREO_ON;
-			        }
+			        
 				v.flags|=cadet_getrds();
-			        if(copy_to_user(arg,&v, sizeof(v))) {
-				        return -EFAULT;
-			        }
 			        break;
-			        case 1:
+		        case 1:
 			        strcpy(v.name,"AM");
 			        v.rangelow=8320;      /* 520 kHz */
 			        v.rangehigh=26400;    /* 1650 kHz */
-			        v.flags=0;
-			        v.flags|=VIDEO_TUNER_LOW;
-			        v.mode=0;
-			        v.mode|=VIDEO_MODE_AUTO;
-			        v.signal=sigstrength;
-			        if(copy_to_user(arg,&v, sizeof(v))) {
-				        return -EFAULT;
-			        }
+			        v.flags = VIDEO_TUNER_LOW;
+			        v.mode = VIDEO_MODE_AUTO;
 			        break;
+			default:
+				return -EINVAL;
 			}
+		        v.signal=sigstrength;
+		        if(copy_to_user(arg,&v, sizeof(v))) {
+			        return -EFAULT;
+		        }
 			return 0;
 		}
 		case VIDIOCSTUNER:
 		{
 			struct video_tuner v;
-			if(copy_from_user(&v, arg, sizeof(v))) {
+			if(copy_from_user(&v, arg, sizeof(v)))
 				return -EFAULT;
-			}
-			if((v.tuner<0)||(v.tuner>1)) {
+
+			if(v.tuner < 0 || v.tuner > 1)
 				return -EINVAL;
-			}
+
 			curtuner=v.tuner;	
 			return 0;
 		}
@@ -468,25 +434,24 @@
 		case VIDIOCSFREQ:
 			if(copy_from_user(&freq, arg,sizeof(freq)))
 				return -EFAULT;
-			if((curtuner==0)&&((freq<1400)||(freq>1728))) {
+			if(curtuner==0 && (freq<1400 || freq>1728))
 			        return -EINVAL;
-			}
-			if((curtuner==1)&&((freq<8320)||(freq>26400))) {
+			if(curtuner==1 && (freq<8320 || freq>26400))
 			        return -EINVAL;
-			}
+
 			cadet_setfreq(freq);
 			return 0;
+
 		case VIDIOCGAUDIO:
 		{	
 			struct video_audio v;
 			memset(&v,0, sizeof(v));
 			v.flags=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
-			if(cadet_getstereo()==0) {
+			if(cadet_getstereo()==0)
 			        v.mode=VIDEO_SOUND_MONO;
-			}
-			else {
-			  v.mode=VIDEO_SOUND_STEREO;
-			}
+			else
+				v.mode=VIDEO_SOUND_STEREO;
+
 			v.volume=cadet_getvol();
 			v.step=0xffff;
 			strcpy(v.name, "Radio");
@@ -525,10 +490,8 @@
 
 static void cadet_close(struct video_device *dev)
 {
-        if(rdsstat==1) {
-                del_timer(&readtimer);
-		rdsstat=0;
-	}
+	del_timer_sync(&readtimer);
+	rdsstat=0;
 	users--;
 }
 
@@ -557,13 +520,13 @@
 	if (!(dev->resource[0].flags & IORESOURCE_IO))
 		return -ENODEV;
 	if (dev->activate(dev)<0) {
-		printk ("radio-cadet: isapnp configure failed (out of resources?)\n");
+		printk(KERN_ERR "radio-cadet: isapnp configure failed (out of resources?)\n");
 		return -ENOMEM;
 	}
 
 	io = dev->resource[0].start;
 
-	printk ("radio-cadet: ISAPnP reports card at %#x\n", io);
+	printk(KERN_INFO "radio-cadet: ISAPnP reports card at %#x\n", io);
 
 	return io;
 }
@@ -575,7 +538,7 @@
 
 	for(i=0;i<8;i++) {
 	        io=iovals[i];
-	        if(request_region(io,2, "cadet-probe")>=0) {
+	        if(request_region(io,2, "cadet-probe") != NULL) {
 		        cadet_setfreq(1410);
 			if(cadet_getfreq()==1410) {
 				release_region(io, 2);
@@ -594,6 +557,9 @@
 
 static int __init cadet_init(void)
 {
+
+	spin_lock_init(&cadet_io_lock);
+	
 	/*
 	 *	If a probe was requested then probe ISAPnP first (safest)
 	 */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/radio/radio-gemtek.c linux-2.4.21-pre6/drivers/media/radio/radio-gemtek.c
--- linux-2.4.20/drivers/media/radio/radio-gemtek.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/media/radio/radio-gemtek.c	2003-03-26 23:48:57.000000000 +0000
@@ -8,7 +8,7 @@
  *    RadioTrack II driver for Linux radio support (C) 1998 Ben Pfaff
  * 
  *    Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood
- *    Coverted to new API by Alan Cox <Alan.Cox@linux.org>
+ *    Converted to new API by Alan Cox <Alan.Cox@linux.org>
  *    Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
  *
  * TODO: Allow for more than one of these foolish entities :-)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/radio/radio-maxiradio.c linux-2.4.21-pre6/drivers/media/radio/radio-maxiradio.c
--- linux-2.4.20/drivers/media/radio/radio-maxiradio.c	2001-12-21 17:41:54.000000000 +0000
+++ linux-2.4.21-pre6/drivers/media/radio/radio-maxiradio.c	2003-03-26 23:49:30.000000000 +0000
@@ -54,7 +54,7 @@
 
 
 /* TEA5757 pin mappings */
-const int clk = 1, data = 2, wren = 4, mo_st = 8, power = 16 ;
+static const int clk = 1, data = 2, wren = 4, mo_st = 8, power = 16 ;
 
 static int radio_nr = -1;
 MODULE_PARM(radio_nr, "i");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/radio/radio-rtrack2.c linux-2.4.21-pre6/drivers/media/radio/radio-rtrack2.c
--- linux-2.4.20/drivers/media/radio/radio-rtrack2.c	2001-09-30 19:26:06.000000000 +0000
+++ linux-2.4.21-pre6/drivers/media/radio/radio-rtrack2.c	2003-03-26 23:49:07.000000000 +0000
@@ -1,7 +1,7 @@
 /* RadioTrack II driver for Linux radio support (C) 1998 Ben Pfaff
  * 
  * Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood
- * Coverted to new API by Alan Cox <Alan.Cox@linux.org>
+ * Converted to new API by Alan Cox <Alan.Cox@linux.org>
  * Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
  *
  * TODO: Allow for more than one of these foolish entities :-)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/radio/radio-sf16fmr2.c linux-2.4.21-pre6/drivers/media/radio/radio-sf16fmr2.c
--- linux-2.4.20/drivers/media/radio/radio-sf16fmr2.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/media/radio/radio-sf16fmr2.c	2003-03-26 23:49:19.000000000 +0000
@@ -0,0 +1,473 @@
+/* SF16FMR2 radio driver for Linux radio support
+ * heavily based on fmi driver...
+ * (c) 2000-2002 Ziglio Frediano, freddy77@angelfire.com
+ *
+ * Notes on the hardware
+ *
+ *  Frequency control is done digitally -- ie out(port,encodefreq(95.8));
+ *  No volume control - only mute/unmute - you have to use line volume
+ *  
+ *  For read stereo/mono you must wait 0.1 sec after set frequency and 
+ *  card unmuted so I set frequency on unmute
+ *  Signal handling seem to work only on autoscanning (not implemented)
+ */
+
+#include <linux/module.h>	/* Modules 			*/
+#include <linux/init.h>		/* Initdata			*/
+#include <linux/ioport.h>	/* check_region, request_region	*/
+#include <linux/delay.h>	/* udelay			*/
+#include <asm/io.h>		/* outb, outb_p			*/
+#include <asm/uaccess.h>	/* copy to/from user		*/
+#include <linux/videodev.h>	/* kernel radio structs		*/
+#include <asm/semaphore.h>
+
+static struct semaphore lock;
+
+#undef DEBUG
+//#define DEBUG 1
+
+#ifdef DEBUG
+# define  debug_print(s) printk s
+#else
+# define  debug_print(s)
+#endif
+
+/* this should be static vars for module size */
+struct fmr2_device
+{
+	int port;
+	int curvol; /* 0-65535, if not volume 0 or 65535 */
+	int mute;
+	int stereo; /* card is producing stereo audio */
+	unsigned long curfreq; /* freq in kHz */
+	int card_type; 
+	__u32 flags;
+};
+
+static int io = 0x384; 
+static int radio_nr = -1;
+static int users = 0;
+
+/* hw precision is 12.5 kHz 
+ * It is only usefull to give freq in intervall of 200 (=0.0125Mhz),
+ * other bits will be truncated
+ */
+#define RSF16_ENCODE(x)	((x)/200+856)
+#define RSF16_MINFREQ 87*16000
+#define RSF16_MAXFREQ 108*16000
+
+/* from radio-aimslab */
+static void sleep_delay(unsigned long n)
+{
+	unsigned d=n/(1000000U/HZ);
+	if (!d)
+		udelay(n);
+	else
+	{
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(d);
+	}
+}
+
+static inline void wait(int n,int port)
+{
+	for (;n;--n) inb(port);
+}
+
+static void outbits(int bits, unsigned int data, int nWait, int port)
+{
+	int bit;
+	for(;--bits>=0;) {
+		bit = (data>>bits) & 1;
+		outb(bit,port);
+		wait(nWait,port);
+		outb(bit|2,port);
+		wait(nWait,port);
+		outb(bit,port);
+		wait(nWait,port);
+	}
+}
+
+static inline void fmr2_mute(int port)
+{
+	outb(0x00, port);
+	wait(4,port);
+}
+
+static inline void fmr2_unmute(int port)
+{
+	outb(0x04, port);
+	wait(4,port);
+}
+
+static inline int fmr2_stereo_mode(int port)
+{
+	int n = inb(port);
+	outb(6,port);
+	inb(port);
+	n = ((n>>3)&1)^1;
+	debug_print((KERN_DEBUG "stereo: %d\n", n));
+	return n;
+}
+
+static int fmr2_product_info(struct fmr2_device *dev)
+{
+	int n = inb(dev->port);
+	n &= 0xC1;
+	if (n == 0)
+	{
+		/* this should support volume set */
+		dev->card_type = 12;
+		return 0;
+	}
+	/* not volume (mine is 11) */
+	dev->card_type = (n==128)?11:0;
+	return n;
+}
+
+static inline int fmr2_getsigstr(struct fmr2_device *dev)
+{
+	/* !!! work only if scanning freq */
+	int port = dev->port, res = 0xffff;
+	outb(5,port);
+	wait(4,port);
+	if (!(inb(port)&1)) res = 0;
+	debug_print((KERN_DEBUG "signal: %d\n", res));
+	return res;
+}
+
+/* set frequency and unmute card */
+static int fmr2_setfreq(struct fmr2_device *dev)
+{
+	int port = dev->port;
+	unsigned long freq = dev->curfreq;
+
+	fmr2_mute(port);
+
+	/* 0x42 for mono output
+	 * 0x102 forward scanning
+	 * 0x182 scansione avanti 
+	 */
+	outbits(9,0x2,3,port);
+	outbits(16,RSF16_ENCODE(freq),2,port);
+
+	fmr2_unmute(port);
+
+	/* wait 0.11 sec */
+	sleep_delay(110000LU);
+
+	/* NOTE if mute this stop radio
+	   you must set freq on unmute */
+	dev->stereo = fmr2_stereo_mode(port);
+	return 0;
+}
+
+/* !!! not tested, in my card this does't work !!! */
+static int fmr2_setvolume(struct fmr2_device *dev)
+{
+	int i,a,n, port = dev->port;
+
+	if (dev->card_type != 11) return 1;
+
+	switch( (dev->curvol+(1<<11)) >> 12 )
+	{
+	case 0: case 1: n = 0x21; break;
+	case 2: n = 0x84; break;
+	case 3: n = 0x90; break;
+	case 4: n = 0x104; break;
+	case 5: n = 0x110; break;
+	case 6: n = 0x204; break;
+	case 7: n = 0x210; break;
+	case 8: n = 0x402; break;
+	case 9: n = 0x404; break;
+	default:
+	case 10: n = 0x408; break;
+	case 11: n = 0x410; break;
+	case 12: n = 0x801; break;
+	case 13: n = 0x802; break;
+	case 14: n = 0x804; break;
+	case 15: n = 0x808; break;
+	case 16: n = 0x810; break;
+	}
+	for(i=12;--i>=0;)
+	{
+		a = ((n >> i) & 1) << 6; /* if (a=0) a= 0; else a= 0x40; */
+		outb(a|4, port);
+		wait(4,port);
+		outb(a|0x24, port);
+		wait(4,port);
+		outb(a|4, port);
+		wait(4,port);
+	}
+	for(i=6;--i>=0;)
+	{
+		a = ((0x18 >> i) & 1) << 6;
+		outb(a|4, port);
+		wait(4,port);
+		outb(a|0x24, port);
+		wait(4,port);
+		outb(a|4, port);
+		wait(4,port);
+	}
+	wait(4,port);
+	outb(0x14, port);
+
+	return 0;
+}
+
+static int fmr2_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+{
+	struct fmr2_device *fmr2=dev->priv;
+	debug_print((KERN_DEBUG "freq %ld flags %d vol %d mute %d "
+		"stereo %d type %d\n",
+		fmr2->curfreq, fmr2->flags, fmr2->curvol, fmr2->mute, 
+		fmr2->stereo, fmr2->card_type));
+	
+	switch(cmd)
+	{
+		case VIDIOCGCAP:
+		{
+			struct video_capability v;
+			strcpy(v.name, "SF16-FMR2 radio");
+			v.type=VID_TYPE_TUNER;
+			v.channels=1;
+			v.audios=1;
+			/* No we don't do pictures */
+			v.maxwidth=0;
+			v.maxheight=0;
+			v.minwidth=0;
+			v.minheight=0;
+			if(copy_to_user(arg,&v,sizeof(v)))
+				return -EFAULT;
+			return 0;
+		}
+		case VIDIOCGTUNER:
+		{
+			struct video_tuner v;
+			int mult;
+
+			if(copy_from_user(&v, arg,sizeof(v))!=0)
+				return -EFAULT;
+			if(v.tuner)	/* Only 1 tuner */
+				return -EINVAL;
+			strcpy(v.name, "FM");
+			mult = (fmr2->flags & VIDEO_TUNER_LOW) ? 1 : 1000;
+			v.rangelow = RSF16_MINFREQ/mult;
+			v.rangehigh = RSF16_MAXFREQ/mult;
+			v.flags = fmr2->flags | VIDEO_AUDIO_MUTABLE;
+			if (fmr2->mute)
+				v.flags |= VIDEO_AUDIO_MUTE;
+			v.mode=VIDEO_MODE_AUTO;
+			down(&lock);
+			v.signal = fmr2_getsigstr(fmr2);
+			up(&lock);
+			if(copy_to_user(arg,&v, sizeof(v)))
+				return -EFAULT;
+			return 0;
+		}
+		case VIDIOCSTUNER:
+		{
+			struct video_tuner v;
+			if(copy_from_user(&v, arg, sizeof(v)))
+				return -EFAULT;
+			if(v.tuner!=0)
+				return -EINVAL;
+			fmr2->flags = v.flags & VIDEO_TUNER_LOW;
+			return 0;
+		}
+		case VIDIOCGFREQ:
+		{
+			unsigned long tmp = fmr2->curfreq;
+			if (!(fmr2->flags & VIDEO_TUNER_LOW))
+				tmp /= 1000;
+			if(copy_to_user(arg, &tmp, sizeof(tmp)))
+				return -EFAULT;
+			return 0;
+		}
+		case VIDIOCSFREQ:
+		{
+			unsigned long tmp;
+			if(copy_from_user(&tmp, arg, sizeof(tmp)))
+				return -EFAULT;
+			if (!(fmr2->flags & VIDEO_TUNER_LOW))
+				tmp *= 1000;
+			if ( tmp<RSF16_MINFREQ || tmp>RSF16_MAXFREQ )
+				return -EINVAL;
+			/* rounding in steps of 200 to match th freq
+			 * that will be used 
+			 */
+			fmr2->curfreq = (tmp/200)*200; 
+
+			/* set card freq (if not muted) */
+			if (fmr2->curvol && !fmr2->mute)
+			{
+				down(&lock);
+				fmr2_setfreq(fmr2);
+				up(&lock);
+			}
+			return 0;
+		}
+		case VIDIOCGAUDIO:
+		{
+			struct video_audio v;
+			v.audio=0;
+			v.volume=0;
+			v.bass=0;
+			v.treble=0;
+			/* !!! do not return VIDEO_AUDIO_MUTE */
+			v.flags = VIDEO_AUDIO_MUTABLE;
+			strcpy(v.name, "Radio");
+			/* get current stereo mode */
+			v.mode = fmr2->stereo ? VIDEO_SOUND_STEREO: VIDEO_SOUND_MONO;
+			v.balance = 0;
+			v.step=0; /* No volume, just (un)mute */
+			/* volume supported ? */
+			if (fmr2->card_type == 11)
+			{
+				v.flags |= VIDEO_AUDIO_VOLUME;
+				v.step = 1 << 12;
+				v.volume = fmr2->curvol;
+			}
+			debug_print((KERN_DEBUG "Get flags %d vol %d\n", v.flags, v.volume));
+			if(copy_to_user(arg,&v, sizeof(v)))
+				return -EFAULT;
+			return 0;
+		}
+		case VIDIOCSAUDIO:
+		{
+			struct video_audio v;
+			if(copy_from_user(&v, arg, sizeof(v)))
+				return -EFAULT;
+			if(v.audio)
+				return -EINVAL;
+			debug_print((KERN_DEBUG "Set flags %d vol %d\n", v.flags, v.volume));
+			/* set volume */
+			if (v.flags & VIDEO_AUDIO_VOLUME)
+				fmr2->curvol = v.volume; /* !!! set with precision */
+			if (fmr2->card_type != 11) fmr2->curvol = 65535;
+			fmr2->mute = 0;
+			if (v.flags&VIDEO_AUDIO_MUTE)
+				fmr2->mute = 1;
+#ifdef DEBUG
+			if (fmr2->curvol && !fmr2->mute)
+				printk(KERN_DEBUG "unmute\n");
+			else
+				printk(KERN_DEBUG "mute\n");
+#endif
+			down(&lock);
+			if (fmr2->curvol && !fmr2->mute)
+			{
+				fmr2_setvolume(fmr2);
+				fmr2_setfreq(fmr2);
+			}
+			else fmr2_mute(fmr2->port);
+			up(&lock);
+			return 0;
+		}
+		case VIDIOCGUNIT:
+		{
+			struct video_unit v;
+			v.video=VIDEO_NO_UNIT;
+			v.vbi=VIDEO_NO_UNIT;
+			v.radio=dev->minor;
+			v.audio=0; /* How do we find out this??? */
+			v.teletext=VIDEO_NO_UNIT;
+			if(copy_to_user(arg, &v, sizeof(v)))
+				return -EFAULT;
+			return 0;			
+		}
+		default:
+			return -ENOIOCTLCMD;
+	}
+}
+
+static int fmr2_open(struct video_device *dev, int flags)
+{
+	if(users)
+		return -EBUSY;
+	users++;
+	return 0;
+}
+
+static void fmr2_close(struct video_device *dev)
+{
+	users--;
+}
+
+static struct fmr2_device fmr2_unit;
+
+static struct video_device fmr2_radio=
+{
+	owner:		THIS_MODULE,
+	name:		"SF16FMR2 radio",
+	type:		VID_TYPE_TUNER,
+	hardware:	VID_HARDWARE_SF16FMR2,
+	open:		fmr2_open,
+	close:		fmr2_close,
+	ioctl:		fmr2_ioctl,
+};
+
+static int __init fmr2_init(void)
+{
+	if (check_region(io, 2)) 
+	{
+		printk(KERN_ERR "fmr2: port 0x%x already in use\n", io);
+		return -EBUSY;
+	}
+
+	fmr2_unit.port = io;
+	fmr2_unit.curvol = 0;
+	fmr2_unit.mute = 0;
+	fmr2_unit.curfreq = 0;
+	fmr2_unit.stereo = 1;
+	fmr2_unit.flags = VIDEO_TUNER_LOW;
+	fmr2_unit.card_type = 0;
+	fmr2_radio.priv = &fmr2_unit;
+
+	init_MUTEX(&lock);
+
+	if(video_register_device(&fmr2_radio, VFL_TYPE_RADIO, radio_nr)==-1)
+		return -EINVAL;
+
+	request_region(io, 2, "fmr2");
+	printk(KERN_INFO "SF16FMR2 radio card driver at 0x%x.\n", io);
+	debug_print((KERN_DEBUG "Mute %d Low %d\n",VIDEO_AUDIO_MUTE,VIDEO_TUNER_LOW));
+	/* mute card - prevents noisy bootups */
+	down(&lock);
+	fmr2_mute(io);
+	fmr2_product_info(&fmr2_unit);
+	up(&lock);
+	debug_print((KERN_DEBUG "card_type %d\n", fmr2_unit.card_type));
+	return 0;
+}
+
+MODULE_AUTHOR("Ziglio Frediano, freddy77@angelfire.com");
+MODULE_DESCRIPTION("A driver for the SF16FMR2 radio.");
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(io, "i");
+MODULE_PARM_DESC(io, "I/O address of the SF16FMR2 card (should be 0x384, if do not work try 0x284)");
+MODULE_PARM(radio_nr, "i");
+
+EXPORT_NO_SYMBOLS;
+
+static void __exit fmr2_cleanup_module(void)
+{
+	video_unregister_device(&fmr2_radio);
+	release_region(io,2);
+}
+
+module_init(fmr2_init);
+module_exit(fmr2_cleanup_module);
+
+#ifndef MODULE
+
+static int __init fmr2_setup_io(char *str)
+{
+	get_option(&str, &io);
+	return 1;
+}
+
+__setup("sf16fmr2=", fmr2_setup_io);
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/video/Config.in linux-2.4.21-pre6/drivers/media/video/Config.in
--- linux-2.4.20/drivers/media/video/Config.in	2001-12-21 17:41:54.000000000 +0000
+++ linux-2.4.21-pre6/drivers/media/video/Config.in	2003-03-26 23:49:40.000000000 +0000
@@ -8,9 +8,7 @@
 dep_tristate '  I2C on parallel port' CONFIG_I2C_PARPORT $CONFIG_PARPORT $CONFIG_I2C
 
 comment 'Video Adapters'
-if [ "$CONFIG_I2C_ALGOBIT" = "y" -o "$CONFIG_I2C_ALGOBIT" = "m" ]; then
-   dep_tristate '  BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C_ALGOBIT
-fi
+dep_tristate '  BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C_ALGOBIT $CONFIG_SOUND
 dep_tristate '  Mediavision Pro Movie Studio Video For Linux' CONFIG_VIDEO_PMS $CONFIG_VIDEO_DEV
 if [ "$CONFIG_ALL_PPC" = "y" ]; then
    dep_tristate '  PlanB Video-In on PowerMac' CONFIG_VIDEO_PLANB $CONFIG_VIDEO_DEV
@@ -49,7 +47,7 @@
 dep_tristate '  Linux Media Labs LML33 support' CONFIG_VIDEO_ZORAN_LML33 $CONFIG_VIDEO_ZORAN $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C
 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
+  dep_tristate '  Sony Vaio Picturebook Motion Eye Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_MEYE $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_SONYPI
 fi
 
 endmenu
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/video/Makefile linux-2.4.21-pre6/drivers/media/video/Makefile
--- linux-2.4.20/drivers/media/video/Makefile	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/media/video/Makefile	2003-03-26 23:49:29.000000000 +0000
@@ -35,7 +35,7 @@
 
 obj-$(CONFIG_BUS_I2C) += i2c-old.o
 obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tvaudio.o \
-	tda7432.o tda9875.o tuner.o
+	tda7432.o tda9875.o tda9887.o tuner.o
 obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o
 
 obj-$(CONFIG_VIDEO_ZR36120) += zoran.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/video/audiochip.h linux-2.4.21-pre6/drivers/media/video/audiochip.h
--- linux-2.4.20/drivers/media/video/audiochip.h	2000-11-13 04:47:19.000000000 +0000
+++ linux-2.4.21-pre6/drivers/media/video/audiochip.h	2003-03-26 23:49:19.000000000 +0000
@@ -30,41 +30,7 @@
  * make sense in v4l context only.  So I think that's acceptable...
  */
 
-#if 0
-
-/* TODO (if it is ever [to be] accessible in the V4L[2] spec):
- *   maybe fade? (back/front)
- * notes:
- * NEWCHANNEL and SWITCH_MUTE are here because the MSP3400 has a special
- * routine to go through when it tunes in to a new channel before turning
- * back on the sound.
- * Either SET_RADIO, NEWCHANNEL, and SWITCH_MUTE or SET_INPUT need to be
- * implemented (MSP3400 uses SET_RADIO to select inputs, and SWITCH_MUTE for
- * channel-change mute -- TEA6300 et al use SET_AUDIO to select input [TV, 
- * radio, external, or MUTE]).  If both methods are implemented, you get a
- * cookie for doing such a good job! :)
- */
-
-#define AUDC_SET_TVNORM       _IOW('m',1,int)  /* TV mode + PAL/SECAM/NTSC  */
-#define AUDC_NEWCHANNEL       _IO('m',3)       /* indicate new chan - off mute */
-
-#define AUDC_GET_VOLUME_LEFT  _IOR('m',4,__u16)
-#define AUDC_GET_VOLUME_RIGHT _IOR('m',5,__u16)
-#define AUDC_SET_VOLUME_LEFT  _IOW('m',6,__u16)
-#define AUDC_SET_VOLUME_RIGHT _IOW('m',7,__u16)
-
-#define AUDC_GET_STEREO       _IOR('m',8,__u16)
-#define AUDC_SET_STEREO       _IOW('m',9,__u16)
-
-#define AUDC_GET_DC           _IOR('m',10,__u16)/* ??? */
-
-#define AUDC_GET_BASS         _IOR('m',11,__u16)
-#define AUDC_SET_BASS         _IOW('m',12,__u16)
-#define AUDC_GET_TREBLE       _IOR('m',13,__u16)
-#define AUDC_SET_TREBLE       _IOW('m',14,__u16)
-
-#define AUDC_GET_UNIT         _IOR('m',15,int) /* ??? - unimplemented in MSP3400 */
-#define AUDC_SWITCH_MUTE      _IO('m',16)      /* turn on mute */
-#endif
+/* misc stuff to pass around config info to i2c chips */
+#define AUDC_CONFIG_PINNACLE  _IOW('m',32,int)
 
 #endif /* AUDIOCHIP_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/video/bt832.c linux-2.4.21-pre6/drivers/media/video/bt832.c
--- linux-2.4.20/drivers/media/video/bt832.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/media/video/bt832.c	2003-03-26 23:49:07.000000000 +0000
@@ -0,0 +1,288 @@
+/* Driver for Bt832 CMOS Camera Video Processor
+    i2c-adresses: 0x88 or 0x8a
+
+  The BT832 interfaces to a Quartzsight Digital Camera (352x288, 25 or 30 fps)
+  via a 9 pin connector ( 4-wire SDATA, 2-wire i2c, SCLK, VCC, GND).
+  It outputs an 8-bit 4:2:2 YUV or YCrCb video signal which can be directly
+  connected to bt848/bt878 GPIO pins on this purpose.
+  (see: VLSI Vision Ltd. www.vvl.co.uk for camera datasheets)
+  
+  Supported Cards:
+  -  Pixelview Rev.4E: 0x8a
+		GPIO 0x400000 toggles Bt832 RESET, and the chip changes to i2c 0x88 !
+
+  (c) Gunther Mayer, 2002
+
+  STATUS:
+  - detect chip and hexdump
+  - reset chip and leave low power mode
+  - detect camera present
+
+  TODO:
+  - make it work (find correct setup for Bt832 and Bt878)
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/types.h>
+#include <linux/videodev.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+#include "id.h"
+#include "audiochip.h"
+#include "bttv.h"
+#include "bt832.h"
+
+MODULE_LICENSE("GPL");
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = {I2C_CLIENT_END};
+static unsigned short normal_i2c_range[] = {I2C_BT832_ALT1>>1,I2C_BT832_ALT2>>1,I2C_CLIENT_END};
+I2C_CLIENT_INSMOD;
+
+/* ---------------------------------------------------------------------- */
+
+#define dprintk     if (debug) printk
+
+static int bt832_detach(struct i2c_client *client);
+
+
+static struct i2c_driver driver;
+static struct i2c_client client_template;
+
+struct bt832 {
+        struct i2c_client client;
+};
+
+int bt832_hexdump(struct i2c_client *i2c_client_s, unsigned char *buf)
+{
+	int i,rc;
+	buf[0]=0x80; // start at register 0 with auto-increment
+        if (1 != (rc = i2c_master_send(i2c_client_s,buf,1)))
+                printk("bt832: i2c i/o error: rc == %d (should be 1)\n",rc);
+
+        for(i=0;i<65;i++)
+                buf[i]=0;
+        if (65 != (rc=i2c_master_recv(i2c_client_s,buf,65)))
+                printk("bt832: i2c i/o error: rc == %d (should be 65)\n",rc);
+
+        // Note: On READ the first byte is the current index
+        //  (e.g. 0x80, what we just wrote)
+
+        if(1) {
+                int i;
+                printk("BT832 hexdump:\n");
+                for(i=1;i<65;i++) {
+			if(i!=1) {
+			  if(((i-1)%8)==0) printk(" ");
+                          if(((i-1)%16)==0) printk("\n");
+			}
+                        printk(" %02x",buf[i]);
+                }
+                printk("\n");
+        }
+	return 0;
+}
+
+// Return: 1 (is a bt832), 0 (No bt832 here)
+int bt832_init(struct i2c_client *i2c_client_s)
+{
+	unsigned char *buf;
+	int rc;
+
+	buf=kmalloc(65,GFP_KERNEL);
+	bt832_hexdump(i2c_client_s,buf);
+	
+	if(buf[0x40] != 0x31) {
+		printk("bt832: this i2c chip is no bt832 (id=%02x). Detaching.\n",buf[0x40]);
+		kfree(buf);
+		return 0;
+	}
+
+        printk("Write 0 tp VPSTATUS\n");
+        buf[0]=BT832_VP_STATUS; // Reg.52
+        buf[1]= 0x00;
+        if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
+                printk("bt832: i2c i/o error VPS: rc == %d (should be 2)\n",rc);
+
+        bt832_hexdump(i2c_client_s,buf);
+
+
+	// Leave low power mode:
+	printk("Bt832: leave low power mode.\n");
+	buf[0]=BT832_CAM_SETUP0; //0x39 57
+	buf[1]=0x08;
+	if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
+                printk("bt832: i2c i/o error LLPM: rc == %d (should be 2)\n",rc);
+
+        bt832_hexdump(i2c_client_s,buf);
+
+	printk("Write 0 tp VPSTATUS\n");
+        buf[0]=BT832_VP_STATUS; // Reg.52
+        buf[1]= 0x00;
+        if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
+                printk("bt832: i2c i/o error VPS: rc == %d (should be 2)\n",rc);
+
+        bt832_hexdump(i2c_client_s,buf);
+
+
+	// Enable Output
+	printk("Enable Output\n");
+	buf[0]=BT832_VP_CONTROL1; // Reg.40
+	buf[1]= 0x27 & (~0x01); // Default | !skip
+	if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
+                printk("bt832: i2c i/o error EO: rc == %d (should be 2)\n",rc);
+	
+        bt832_hexdump(i2c_client_s,buf);
+
+#if 0
+	// Full 30/25 Frame rate
+	printk("Full 30/25 Frame rate\n");
+	buf[0]=BT832_VP_CONTROL0; // Reg.39
+        buf[1]= 0x00;
+        if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
+                printk("bt832: i2c i/o error FFR: rc == %d (should be 2)\n",rc);
+
+        bt832_hexdump(i2c_client_s,buf);
+#endif
+
+#if 1
+	// for testing (even works when no camera attached)
+	printk("bt832: *** Generate NTSC M Bars *****\n");
+	buf[0]=BT832_VP_TESTCONTROL0; // Reg. 42
+	buf[1]=3; // Generate NTSC System M bars, Generate Frame timing internally
+        if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
+                printk("bt832: i2c i/o error MBAR: rc == %d (should be 2)\n",rc);
+#endif
+
+	printk("Bt832: Camera Present: %s\n",
+		(buf[1+BT832_CAM_STATUS] & BT832_56_CAMERA_PRESENT) ? "yes":"no");
+
+        bt832_hexdump(i2c_client_s,buf);
+	kfree(buf);
+	return 1;
+}
+
+
+
+static int bt832_attach(struct i2c_adapter *adap, int addr,
+			  unsigned short flags, int kind)
+{
+	struct bt832 *t;
+
+	printk("bt832_attach\n");
+
+        client_template.adapter = adap;
+        client_template.addr    = addr;
+
+        printk("bt832: chip found @ 0x%x\n", addr<<1);
+
+        if (NULL == (t = kmalloc(sizeof(*t), GFP_KERNEL)))
+                return -ENOMEM;
+	memset(t,0,sizeof(*t));
+	t->client = client_template;
+        t->client.data = t;
+        i2c_attach_client(&t->client);
+
+	MOD_INC_USE_COUNT;
+	if(! bt832_init(&t->client)) {
+		bt832_detach(&t->client);
+		return -1;
+	}
+        
+	return 0;
+}
+
+static int bt832_probe(struct i2c_adapter *adap)
+{
+	int rc;
+
+	printk("bt832_probe\n");
+
+	switch (adap->id) {
+	case I2C_ALGO_BIT | I2C_HW_B_BT848:
+	case I2C_ALGO_BIT | I2C_HW_B_RIVA:
+	case I2C_ALGO_SAA7134:
+		printk("bt832: probing %s i2c adapter [id=0x%x]\n",
+		       adap->name,adap->id);
+		rc = i2c_probe(adap, &addr_data, bt832_attach);
+		break;
+	default:
+		printk("bt832: ignoring %s i2c adapter [id=0x%x]\n",
+		       adap->name,adap->id);
+		rc = 0;
+		/* nothing */
+	}
+	return rc;
+}
+
+static int bt832_detach(struct i2c_client *client)
+{
+	struct bt832 *t = (struct bt832*)client->data;
+
+	printk("bt832: detach.\n");
+	i2c_detach_client(client);
+	kfree(t);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int
+bt832_command(struct i2c_client *client, unsigned int cmd, void *arg)
+{
+	struct bt832 *t = (struct bt832*)client->data;
+
+	printk("bt832: command %x\n",cmd);
+
+        switch (cmd) {
+		case BT832_HEXDUMP: {
+			unsigned char *buf;
+			buf=kmalloc(65,GFP_KERNEL);
+			bt832_hexdump(&t->client,buf);
+			kfree(buf);
+		}
+		break;
+		case BT832_REATTACH:
+			printk("bt832: re-attach\n");
+			i2c_del_driver(&driver);
+			i2c_add_driver(&driver);
+		break;
+	}
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_driver driver = {
+        .name           = "i2c bt832 driver",
+        .id             = -1, /* FIXME */
+        .flags          = I2C_DF_NOTIFY,
+        .attach_adapter = bt832_probe,
+        .detach_client  = bt832_detach,
+        .command        = bt832_command,
+};
+static struct i2c_client client_template =
+{
+        .name   = "bt832",
+	.flags  = I2C_CLIENT_ALLOW_USE,
+        .driver = &driver,
+};
+
+
+int bt832_init_module(void)
+{
+	i2c_add_driver(&driver);
+	return 0;
+}
+
+static void bt832_cleanup_module(void)
+{
+	i2c_del_driver(&driver);
+}
+
+module_init(bt832_init_module);
+module_exit(bt832_cleanup_module);
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/video/bt832.h linux-2.4.21-pre6/drivers/media/video/bt832.h
--- linux-2.4.20/drivers/media/video/bt832.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/media/video/bt832.h	2003-03-26 23:49:35.000000000 +0000
@@ -0,0 +1,305 @@
+/* Bt832 CMOS Camera Video Processor (VP)
+
+ The Bt832 CMOS Camera Video Processor chip connects a Quartsight CMOS 
+  color digital camera directly to video capture devices via an 8-bit,
+  4:2:2 YUV or YCrCb video interface.
+
+ i2c adresses: 0x88 or 0x8a
+ */
+
+/* The 64 registers: */
+
+// Input Processor
+#define BT832_OFFSET 0
+#define BT832_RCOMP	1
+#define BT832_G1COMP	2
+#define BT832_G2COMP	3
+#define BT832_BCOMP	4
+// Exposures:
+#define BT832_FINEH	5
+#define BT832_FINEL	6
+#define BT832_COARSEH	7
+#define BT832_COARSEL   8
+#define BT832_CAMGAIN	9
+// Main Processor:
+#define BT832_M00	10
+#define BT832_M01	11
+#define BT832_M02	12
+#define BT832_M10	13
+#define BT832_M11	14
+#define BT832_M12	15
+#define BT832_M20	16
+#define BT832_M21	17
+#define BT832_M22	18
+#define BT832_APCOR	19
+#define BT832_GAMCOR	20
+// Level Accumulator Inputs
+#define BT832_VPCONTROL2	21
+#define BT832_ZONECODE0	22
+#define BT832_ZONECODE1	23
+#define BT832_ZONECODE2	24
+#define BT832_ZONECODE3	25
+// Level Accumulator Outputs:
+#define BT832_RACC	26
+#define BT832_GACC	27
+#define BT832_BACC	28
+#define BT832_BLACKACC	29
+#define BT832_EXP_AGC	30
+#define BT832_LACC0	31
+#define BT832_LACC1	32
+#define BT832_LACC2	33
+#define BT832_LACC3	34
+#define BT832_LACC4	35
+#define BT832_LACC5	36
+#define BT832_LACC6	37
+#define BT832_LACC7	38
+// System:
+#define BT832_VP_CONTROL0	39
+#define BT832_VP_CONTROL1	40
+#define BT832_THRESH	41
+#define BT832_VP_TESTCONTROL0	42
+#define BT832_VP_DMCODE	43
+#define BT832_ACB_CONFIG	44
+#define BT832_ACB_GNBASE	45
+#define BT832_ACB_MU	46
+#define BT832_CAM_TEST0	47
+#define BT832_AEC_CONFIG	48
+#define BT832_AEC_TL	49
+#define BT832_AEC_TC	50
+#define BT832_AEC_TH	51
+// Status:
+#define BT832_VP_STATUS	52
+#define BT832_VP_LINECOUNT	53
+#define BT832_CAM_DEVICEL	54 // e.g. 0x19
+#define BT832_CAM_DEVICEH	55 // e.g. 0x40  == 0x194 Mask0, 0x194 = 404 decimal (VVL-404 camera)
+#define BT832_CAM_STATUS		56
+ #define BT832_56_CAMERA_PRESENT 0x20
+//Camera Setups:
+#define BT832_CAM_SETUP0	57
+#define BT832_CAM_SETUP1	58
+#define BT832_CAM_SETUP2	59
+#define BT832_CAM_SETUP3	60
+// System:
+#define BT832_DEFCOR		61
+#define BT832_VP_TESTCONTROL1	62
+#define BT832_DEVICE_ID		63
+# define BT832_DEVICE_ID__31		0x31 // Bt832 has ID 0x31
+
+/* STMicroelectronivcs VV5404 camera module 
+   i2c: 0x20: sensor address
+   i2c: 0xa0: eeprom for ccd defect map
+ */
+#define VV5404_device_h		0x00  // 0x19
+#define VV5404_device_l		0x01  // 0x40
+#define VV5404_status0		0x02
+#define VV5404_linecountc	0x03 // current line counter
+#define VV5404_linecountl	0x04
+#define VV5404_setup0		0x10
+#define VV5404_setup1		0x11
+#define VV5404_setup2		0x12
+#define VV5404_setup4		0x14
+#define VV5404_setup5		0x15
+#define VV5404_fine_h		0x20  // fine exposure
+#define VV5404_fine_l		0x21
+#define VV5404_coarse_h		0x22  //coarse exposure
+#define VV5404_coarse_l		0x23
+#define VV5404_gain		0x24 // ADC pre-amp gain setting
+#define VV5404_clk_div		0x25
+#define VV5404_cr		0x76 // control register
+#define VV5404_as0		0x77 // ADC setup register
+
+
+// IOCTL
+#define BT832_HEXDUMP   _IOR('b',1,int)
+#define BT832_REATTACH	_IOR('b',2,int)
+
+/* from BT8x8VXD/capdrv/dialogs.cpp */
+
+/*
+typedef enum { SVI, Logitech, Rockwell } CAMERA;
+
+static COMBOBOX_ENTRY gwCameraOptions[] =
+{
+   { SVI,      "Silicon Vision 512N" },
+   { Logitech, "Logitech VideoMan 1.3"  },
+   { Rockwell, "Rockwell QuartzSight PCI 1.0"   }
+};
+
+// SRAM table values
+//===========================================================================
+typedef enum { TGB_NTSC624, TGB_NTSC780, TGB_NTSC858, TGB_NTSC392 } TimeGenByte;
+
+BYTE SRAMTable[][ 60 ] =
+{
+   // TGB_NTSC624
+   {
+      0x33, // size of table = 51
+      0x0E, 0xC0, 0x00, 0x00, 0x90, 0x02, 0x03, 0x10, 0x03, 0x06,
+      0x10, 0x04, 0x12, 0x12, 0x05, 0x02, 0x13, 0x04, 0x19, 0x00,
+      0x04, 0x39, 0x00, 0x06, 0x59, 0x08, 0x03, 0x85, 0x08, 0x07,
+      0x03, 0x50, 0x00, 0x91, 0x40, 0x00, 0x11, 0x01, 0x01, 0x4D,
+      0x0D, 0x02, 0x03, 0x11, 0x01, 0x05, 0x37, 0x00, 0x37, 0x21, 0x00
+   },
+   // TGB_NTSC780
+   {
+      0x33, // size of table = 51
+      0x0e, 0xc0, 0x00, 0x00, 0x90, 0xe2, 0x03, 0x10, 0x03, 0x06,
+      0x10, 0x34, 0x12, 0x12, 0x65, 0x02, 0x13, 0x24, 0x19, 0x00,
+      0x24, 0x39, 0x00, 0x96, 0x59, 0x08, 0x93, 0x85, 0x08, 0x97,
+      0x03, 0x50, 0x50, 0xaf, 0x40, 0x30, 0x5f, 0x01, 0xf1, 0x7f,
+      0x0d, 0xf2, 0x03, 0x11, 0xf1, 0x05, 0x37, 0x30, 0x85, 0x21, 0x50
+   },
+   // TGB_NTSC858
+   {
+      0x33, // size of table = 51
+      0x0c, 0xc0, 0x00, 0x00, 0x90, 0xc2, 0x03, 0x10, 0x03, 0x06,
+      0x10, 0x34, 0x12, 0x12, 0x65, 0x02, 0x13, 0x24, 0x19, 0x00,
+      0x24, 0x39, 0x00, 0x96, 0x59, 0x08, 0x93, 0x83, 0x08, 0x97,
+      0x03, 0x50, 0x30, 0xc0, 0x40, 0x30, 0x86, 0x01, 0x01, 0xa6,
+      0x0d, 0x62, 0x03, 0x11, 0x61, 0x05, 0x37, 0x30, 0xac, 0x21, 0x50
+   },
+   // TGB_NTSC392
+   // This table has been modified to be used for Fusion Rev D
+   {
+      0x2A, // size of table = 42
+      0x06, 0x08, 0x04, 0x0a, 0xc0, 0x00, 0x18, 0x08, 0x03, 0x24,
+      0x08, 0x07, 0x02, 0x90, 0x02, 0x08, 0x10, 0x04, 0x0c, 0x10,
+      0x05, 0x2c, 0x11, 0x04, 0x55, 0x48, 0x00, 0x05, 0x50, 0x00,
+      0xbf, 0x0c, 0x02, 0x2f, 0x3d, 0x00, 0x2f, 0x3f, 0x00, 0xc3,
+      0x20, 0x00
+   }
+};
+
+//===========================================================================
+// This is the structure of the camera specifications
+//===========================================================================
+typedef struct tag_cameraSpec
+{
+   SignalFormat signal;       // which digital signal format the camera has
+   VideoFormat  vidFormat;    // video standard
+   SyncVideoRef syncRef;      // which sync video reference is used
+   State        syncOutput;   // enable sync output for sync video input?
+   DecInputClk  iClk;         // which input clock is used
+   TimeGenByte  tgb;          // which timing generator byte does the camera use
+   int          HReset;       // select 64, 48, 32, or 16 CLKx1 for HReset
+   PLLFreq      pllFreq;      // what synthesized frequency to set PLL to
+   VSIZEPARMS   vSize;        // video size the camera produces
+   int          lineCount;    // expected total number of half-line per frame - 1
+   BOOL         interlace;    // interlace signal?
+} CameraSpec;
+
+//===========================================================================
+// <UPDATE REQUIRED>
+// Camera specifications database. Update this table whenever camera spec
+// has been changed or added/deleted supported camera models
+//===========================================================================
+static CameraSpec dbCameraSpec[ N_CAMERAOPTIONS ] =
+{  // Silicon Vision 512N
+   { Signal_CCIR656, VFormat_NTSC, VRef_alignedCb, Off, DecClk_GPCLK, TGB_NTSC624, 64, KHz19636,
+      // Clkx1_HACTIVE, Clkx1_HDELAY, VActive, VDelay, linesPerField; lineCount, Interlace
+   {         512,           0x64,       480,    0x13,      240 },         0,       TRUE
+   },
+   // Logitech VideoMan 1.3
+   { Signal_CCIR656, VFormat_NTSC, VRef_alignedCb, Off, DecClk_GPCLK, TGB_NTSC780, 64, KHz24545,
+      // Clkx1_HACTIVE, Clkx1_HDELAY, VActive, VDelay, linesPerField; lineCount, Interlace
+      {      640,           0x80,       480,    0x1A,      240 },         0,       TRUE
+   },
+   // Rockwell QuartzSight
+   // Note: Fusion Rev D (rev ID 0x02) and later supports 16 pixels for HReset which is preferable.
+   //       Use 32 for earlier version of hardware. Clkx1_HDELAY also changed from 0x27 to 0x20.
+   { Signal_CCIR656, VFormat_NTSC, VRef_alignedCb, Off, DecClk_GPCLK, TGB_NTSC392, 16, KHz28636,
+      // Clkx1_HACTIVE, Clkx1_HDELAY, VActive, VDelay, linesPerField; lineCount, Interlace
+      {      352,           0x20,       576,    0x08,      288 },       607,       FALSE
+   }
+};
+*/
+
+/*
+The corresponding APIs required to be invoked are:
+SetConnector( ConCamera, TRUE/FALSE );
+SetSignalFormat( spec.signal );
+SetVideoFormat( spec.vidFormat );
+SetSyncVideoRef( spec.syncRef );
+SetEnableSyncOutput( spec.syncOutput );
+SetTimGenByte( SRAMTable[ spec.tgb ], SRAMTableSize[ spec.tgb ] );
+SetHReset( spec.HReset );
+SetPLL( spec.pllFreq );
+SetDecInputClock( spec.iClk );
+SetVideoInfo( spec.vSize );
+SetTotalLineCount( spec.lineCount );
+SetInterlaceMode( spec.interlace );
+*/
+
+/* from web:
+ Video Sampling
+Digital video is a sampled form of analog video. The most common sampling schemes in use today are:
+                  Pixel Clock   Horiz    Horiz    Vert
+                   Rate         Total    Active
+NTSC square pixel  12.27 MHz    780      640      525
+NTSC CCIR-601      13.5  MHz    858      720      525
+NTSC 4FSc          14.32 MHz    910      768      525
+PAL  square pixel  14.75 MHz    944      768      625
+PAL  CCIR-601      13.5  MHz    864      720      625
+PAL  4FSc          17.72 MHz   1135      948      625
+
+For the CCIR-601 standards, the sampling is based on a static orthogonal sampling grid. The luminance component (Y) is sampled at 13.5 MHz, while the two color difference signals, Cr and Cb are sampled at half that, or 6.75 MHz. The Cr and Cb samples are colocated with alternate Y samples, and they are taken at the same position on each line, such that one sample is coincident with the 50% point of the falling edge of analog sync. The samples are coded to either 8 or 10 bits per component.
+*/
+
+/* from DScaler:*/
+/*
+//===========================================================================
+// CCIR656 Digital Input Support: The tables were taken from DScaler proyect
+//
+// 13 Dec 2000 - Michael Eskin, Conexant Systems - Initial version
+//
+
+//===========================================================================
+// Timing generator SRAM table values for CCIR601 720x480 NTSC
+//===========================================================================
+// For NTSC CCIR656 
+BYTE BtCard::SRAMTable_NTSC[] =
+{
+    // SRAM Timing Table for NTSC
+    0x0c, 0xc0, 0x00, 
+    0x00, 0x90, 0xc2, 
+    0x03, 0x10, 0x03, 
+    0x06, 0x10, 0x34, 
+    0x12, 0x12, 0x65, 
+    0x02, 0x13, 0x24, 
+    0x19, 0x00, 0x24, 
+    0x39, 0x00, 0x96, 
+    0x59, 0x08, 0x93, 
+    0x83, 0x08, 0x97,
+    0x03, 0x50, 0x30, 
+    0xc0, 0x40, 0x30, 
+    0x86, 0x01, 0x01, 
+    0xa6, 0x0d, 0x62, 
+    0x03, 0x11, 0x61, 
+    0x05, 0x37, 0x30, 
+    0xac, 0x21, 0x50
+};
+
+//===========================================================================
+// Timing generator SRAM table values for CCIR601 720x576 NTSC
+//===========================================================================
+// For PAL CCIR656
+BYTE BtCard::SRAMTable_PAL[] =
+{
+    // SRAM Timing Table for PAL
+    0x36, 0x11, 0x01,
+    0x00, 0x90, 0x02,
+    0x05, 0x10, 0x04,
+    0x16, 0x14, 0x05,
+    0x11, 0x00, 0x04,
+    0x12, 0xc0, 0x00,
+    0x31, 0x00, 0x06,
+    0x51, 0x08, 0x03,
+    0x89, 0x08, 0x07,
+    0xc0, 0x44, 0x00,
+    0x81, 0x01, 0x01,
+    0xa9, 0x0d, 0x02,
+    0x02, 0x50, 0x03,
+    0x37, 0x3d, 0x00,
+    0xaf, 0x21, 0x00,
+};
+*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/video/bt848.h linux-2.4.21-pre6/drivers/media/video/bt848.h
--- linux-2.4.20/drivers/media/video/bt848.h	2001-08-05 20:15:05.000000000 +0000
+++ linux-2.4.21-pre6/drivers/media/video/bt848.h	2003-03-26 23:49:19.000000000 +0000
@@ -204,6 +204,9 @@
 #define BT848_COLOR_FMT_YCrCb411    0x99
 #define BT848_COLOR_FMT_RAW         0xee
 
+#define BT848_VTOTAL_LO             0xB0
+#define BT848_VTOTAL_HI             0xB4
+
 #define BT848_COLOR_CTL                0x0D8
 #define BT848_COLOR_CTL_EXT_FRMRATE    (1<<7)
 #define BT848_COLOR_CTL_COLOR_BARS     (1<<6)
@@ -311,29 +314,28 @@
 
 /* WRITE and SKIP */
 /* disable which bytes of each DWORD */
-#define BT848_RISC_BYTE0       (1<<12)
-#define BT848_RISC_BYTE1       (1<<13)
-#define BT848_RISC_BYTE2       (1<<14)
-#define BT848_RISC_BYTE3       (1<<15)
-#define BT848_RISC_BYTE_ALL    (0x0f<<12)
+#define BT848_RISC_BYTE0       (1U<<12)
+#define BT848_RISC_BYTE1       (1U<<13)
+#define BT848_RISC_BYTE2       (1U<<14)
+#define BT848_RISC_BYTE3       (1U<<15)
+#define BT848_RISC_BYTE_ALL    (0x0fU<<12)
 #define BT848_RISC_BYTE_NONE   0
 /* cause RISCI */
-#define BT848_RISC_IRQ         (1<<24)
+#define BT848_RISC_IRQ         (1U<<24)
 /* RISC command is last one in this line */
-#define BT848_RISC_EOL         (1<<26)
+#define BT848_RISC_EOL         (1U<<26)
 /* RISC command is first one in this line */
-#define BT848_RISC_SOL         (1<<27)
-
-#define BT848_RISC_WRITE       (0x01<<28)
-#define BT848_RISC_SKIP        (0x02<<28)
-#define BT848_RISC_WRITEC      (0x05<<28)
-#define BT848_RISC_JUMP        (0x07<<28)
-#define BT848_RISC_SYNC        (0x08<<28)
-
-#define BT848_RISC_WRITE123    (0x09<<28)
-#define BT848_RISC_SKIP123     (0x0a<<28)
-#define BT848_RISC_WRITE1S23   (0x0b<<28)
+#define BT848_RISC_SOL         (1U<<27)
 
+#define BT848_RISC_WRITE       (0x01U<<28)
+#define BT848_RISC_SKIP        (0x02U<<28)
+#define BT848_RISC_WRITEC      (0x05U<<28)
+#define BT848_RISC_JUMP        (0x07U<<28)
+#define BT848_RISC_SYNC        (0x08U<<28)
+
+#define BT848_RISC_WRITE123    (0x09U<<28)
+#define BT848_RISC_SKIP123     (0x0aU<<28)
+#define BT848_RISC_WRITE1S23   (0x0bU<<28)
 
 
 /* Bt848A and higher only !! */
@@ -347,6 +349,8 @@
 #define BT848_PLL_X            (1<<7)
 #define BT848_PLL_C            (1<<6)
 
+#define BT848_DVSIF            0x0FC
+
 /* Bt878 register */
 
 #define BT878_DEVCTRL 0x40
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/video/bttv-cards.c linux-2.4.21-pre6/drivers/media/video/bttv-cards.c
--- linux-2.4.20/drivers/media/video/bttv-cards.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/media/video/bttv-cards.c	2003-03-26 23:49:38.000000000 +0000
@@ -37,15 +37,16 @@
 
 #include "bttvp.h"
 #include "tuner.h"
+#include "bt832.h"
 
 /* fwd decl */
 static void boot_msp34xx(struct bttv *btv, int pin);
+static void boot_bt832(struct bttv *btv);
 static void hauppauge_eeprom(struct bttv *btv);
 static void avermedia_eeprom(struct bttv *btv);
+static void osprey_eeprom(struct bttv *btv);
+static void modtec_eeprom(struct bttv *btv);
 static void init_PXC200(struct bttv *btv);
-#if 0
-static void init_tea5757(struct bttv *btv);
-#endif
 
 static void winview_audio(struct bttv *btv, struct video_audio *v, int set);
 static void lt9415_audio(struct bttv *btv, struct video_audio *v, int set);
@@ -57,23 +58,33 @@
 static void pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set);
 static void fv2000s_audio(struct bttv *btv, struct video_audio *v, int set);
 static void windvr_audio(struct bttv *btv, struct video_audio *v, int set);
+static void adtvk503_audio(struct bttv *btv, struct video_audio *v, int set);
 static void rv605_muxsel(struct bttv *btv, unsigned int input);
+static void eagle_muxsel(struct bttv *btv, unsigned int input);
+
+static int terratec_active_radio_upgrade(struct bttv *btv);
+static int tea5757_read(struct bttv *btv);
+static int tea5757_write(struct bttv *btv, int value);
+static void identify_by_eeprom(struct bttv *btv,
+			       unsigned char eeprom_data[256]);
 
 /* config variables */
-static int triton1=0;
-static int vsfx=0;
-int no_overlay=-1;
-static unsigned int card[BTTV_MAX]  = { [ 0 ... (BTTV_MAX-1) ] = -1};
-static unsigned int pll[BTTV_MAX]   = { [ 0 ... (BTTV_MAX-1) ] = -1};
-static unsigned int tuner[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = -1};
+static unsigned int triton1=0;
+static unsigned int vsfx=0;
+static unsigned int latency = UNSET;
+unsigned int no_overlay=-1;
+
+static unsigned int card[BTTV_MAX]  = { [ 0 ... (BTTV_MAX-1) ] = UNSET};
+static unsigned int pll[BTTV_MAX]   = { [ 0 ... (BTTV_MAX-1) ] = UNSET};
+static unsigned int tuner[BTTV_MAX] = { [ 0 ... (BTTV_MAX-1) ] = UNSET};
 #ifdef MODULE
 static unsigned int autoload = 1;
 #else
 static unsigned int autoload = 0;
 #endif
-static unsigned int gpiomask = -1;
-static unsigned int audioall = -1;
-static unsigned int audiomux[5] = { -1, -1, -1, -1, -1 };
+static unsigned int gpiomask = UNSET;
+static unsigned int audioall = UNSET;
+static unsigned int audiomux[5] = { [ 0 ... 4 ] = UNSET };
 
 /* insmod options */
 MODULE_PARM(triton1,"i");
@@ -83,6 +94,8 @@
 MODULE_PARM_DESC(vsfx,"set VSFX pci config bit "
 		 "[yet another chipset flaw workaround]");
 MODULE_PARM(no_overlay,"i");
+MODULE_PARM(latency,"i");
+MODULE_PARM_DESC(latency,"pci latency timer");
 MODULE_PARM(card,"1-" __stringify(BTTV_MAX) "i");
 MODULE_PARM_DESC(card,"specify TV/grabber card model, see CARDLIST file for a list");
 MODULE_PARM(pll,"1-" __stringify(BTTV_MAX) "i");
@@ -128,23 +141,28 @@
 	{ 0x13eb0070, BTTV_HAUPPAUGE878,  "Hauppauge WinTV" },
 	{ 0x39000070, BTTV_HAUPPAUGE878,  "Hauppauge WinTV-D" },
 	{ 0x45000070, BTTV_HAUPPAUGEPVR,  "Hauppauge WinTV/PVR" },
-	{ 0xff000070, BTTV_HAUPPAUGE878,  "Osprey-100" },
-	{ 0xff010070, BTTV_HAUPPAUGE878,  "Osprey-200" },
+	{ 0xff000070, BTTV_OSPREY1x0,     "Osprey-100" },
+	{ 0xff010070, BTTV_OSPREY2x0_SVID,"Osprey-200" },
+	{ 0xff020070, BTTV_OSPREY500,     "Osprey-500" },
+	{ 0xff030070, BTTV_OSPREY2000,    "Osprey-2000" },
+	{ 0xff040070, BTTV_OSPREY540,     "Osprey-540" },
 
 	{ 0x00011002, BTTV_ATI_TVWONDER,  "ATI TV Wonder" },
 	{ 0x00031002, BTTV_ATI_TVWONDERVE,"ATI TV Wonder/VE" },
 
 	{ 0x6606107d, BTTV_WINFAST2000,   "Leadtek WinFast TV 2000" },
 	{ 0x6607107d, BTTV_WINFAST2000,   "Leadtek WinFast VC 100" },
-	{ 0x263610b4, BTTV_STB2,          "STB TV PCI FM, P/N 6000704" },
+	{ 0x263610b4, BTTV_STB2,          "STB TV PCI FM, Gateway P/N 6000704" },
  	{ 0x402010fc, BTTV_GVBCTV3PCI,    "I-O Data Co. GV-BCTV3/PCI" },
 	{ 0x405010fc, BTTV_GVBCTV4PCI,    "I-O Data Co. GV-BCTV4/PCI" },
+	{ 0x407010fc, BTTV_GVBCTV5PCI,    "I-O Data Co. GV-BCTV5/PCI" },
 
 	{ 0x1200bd11, BTTV_PINNACLE,      "Pinnacle PCTV" },
 	{ 0x001211bd, BTTV_PINNACLE,      "Pinnacle PCTV" },
-	{ 0x001c11bd, BTTV_PINNACLE,      "Pinnacle PCTV Sat" },
+	{ 0x001c11bd, BTTV_PINNACLESAT,   "Pinnacle PCTV Sat" },
 
 	{ 0x3000121a, BTTV_VOODOOTV_FM,   "3Dfx VoodooTV FM/ VoodooTV 200" },
+	{ 0x3060121a, BTTV_STB2,	  "3Dfx VoodooTV 100/ STB OEM" },
 	
 	{ 0x3000144f, BTTV_MAGICTVIEW063, "(Askey Magic/others) TView99 CPH06x" },
 	{ 0x3002144f, BTTV_MAGICTVIEW061, "(Askey Magic/others) TView99 CPH05x" },
@@ -154,29 +172,32 @@
 	{ 0x00021461, BTTV_AVERMEDIA98,   "AVermedia TVCapture 98" },
 	{ 0x00031461, BTTV_AVPHONE98,     "AVerMedia TVPhone98" },
 	{ 0x00041461, BTTV_AVERMEDIA98,   "AVerMedia TVCapture 98" },
+	{ 0x03001461, BTTV_AVERMEDIA98,   "VDOMATE TV TUNER CARD" },
 
 	{ 0x300014ff, BTTV_MAGICTVIEW061, "TView 99 (CPH061)" },
 	{ 0x300214ff, BTTV_PHOEBE_TVMAS,  "Phoebe TV Master (CPH060)" },
 
-	{ 0x1117153b, BTTV_TERRATVALUE,   "Terratec TValue" },
-	{ 0x1118153b, BTTV_TERRATVALUE,   "Terratec TValue" },
-	{ 0x1119153b, BTTV_TERRATVALUE,   "Terratec TValue" },
-	{ 0x111a153b, BTTV_TERRATVALUE,   "Terratec TValue" },
+	{ 0x1117153b, BTTV_TERRATVALUE,   "Terratec TValue (Philips PAL B/G)" },
+	{ 0x1118153b, BTTV_TERRATVALUE,   "Terratec TValue (Temic PAL B/G)" },
+	{ 0x1119153b, BTTV_TERRATVALUE,   "Terratec TValue (Philips PAL I)" },
+	{ 0x111a153b, BTTV_TERRATVALUE,   "Terratec TValue (Temic PAL I)" },
+ 
 	{ 0x1123153b, BTTV_TERRATVRADIO,  "Terratec TV Radio+" },
-	{ 0x1127153b, BTTV_TERRATV,       "Terratec TV+"    },
+	{ 0x1127153b, BTTV_TERRATV,       "Terratec TV+ (V1.05)"    },
 	// clashes with FlyVideo
-	//{ 0x18521852, BTTV_TERRATV,     "Terratec TV+"    },
-	{ 0x1134153b, BTTV_TERRATVALUE,   "Terratec TValue" },
-	{ 0x1135153b, BTTV_TERRATVALUER,  "Terratec TValue Radio" },
-	{ 0x5018153b, BTTV_TERRATVALUE,   "Terratec TValue" },
+	//{ 0x18521852, BTTV_TERRATV,     "Terratec TV+ (V1.10)"    },
+	{ 0x1134153b, BTTV_TERRATVALUE,   "Terratec TValue (LR102)" },
+	{ 0x1135153b, BTTV_TERRATVALUER,  "Terratec TValue Radio" }, // LR102
+	{ 0x5018153b, BTTV_TERRATVALUE,   "Terratec TValue" }, // ??
 
+	{ 0x400015b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV" },
 	{ 0x400a15b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV" },
 	{ 0x400d15b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
 	{ 0x401015b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
 	{ 0x401615b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
 
     	{ 0x010115cb, BTTV_GMV1,          "AG GMV1" },
-	{ 0x010114c7, BTTV_MODTEC_205,    "Modular Technology MM205 PCTV" },
+	{ 0x010114c7, BTTV_MODTEC_205,    "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV" },
 	{ 0x18501851, BTTV_CHRONOS_VS2,   "FlyVideo 98 (LR50)/ Chronos Video Shuttle II" },
 	{ 0x18511851, BTTV_FLYVIDEO98EZ,  "FlyVideo 98EZ (LR51)/ CyberMail AV" },
 	{ 0x18521852, BTTV_TYPHOON_TVIEW, "FlyVideo 98FM (LR50)/ Typhoon TView TV/FM Tuner" },
@@ -186,6 +207,18 @@
 	{ 0x00790e11, BTTV_WINDVR,        "Canopus WinDVR PCI" },
 	{ 0xa0fca1a0, BTTV_ZOLTRIX,       "Face to Face Tvmax" },
 
+	{ 0x1460aa00, BTTV_PV150,         "Provideo PV150A-1" },
+	{ 0x1461aa01, BTTV_PV150,         "Provideo PV150A-2" },
+	{ 0x1462aa02, BTTV_PV150,         "Provideo PV150A-3" },
+	{ 0x1463aa03, BTTV_PV150,         "Provideo PV150A-4" },
+	{ 0x1464aa04, BTTV_PV150,         "Provideo PV150B-1" },
+	{ 0x1465aa05, BTTV_PV150,         "Provideo PV150B-2" },
+	{ 0x1466aa06, BTTV_PV150,         "Provideo PV150B-3" },
+	{ 0x1467aa07, BTTV_PV150,         "Provideo PV150B-4" },
+
+	// likely broken, vendor id doesn't match the other magic views ...
+	//{ 0xa0fca04f, BTTV_MAGICTVIEW063, "Guillemot Maxi TV Video 3" },
+
 	{ 0, -1, NULL }
 };
 
@@ -195,414 +228,451 @@
 struct tvcard bttv_tvcards[] = {
 {
 /* ---- card 0x00 ---------------------------------- */
-	name:		" *** UNKNOWN/GENERIC *** ",
-	video_inputs:	4,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		2,
-	muxsel:		{ 2, 3, 1, 0},
-	tuner_type:	-1,
-},{
-	name:		"MIRO PCTV",
-	video_inputs:	4,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	15,
-	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 2, 0, 0, 0, 10},
-	needs_tvaudio:	1,
-	tuner_type:	-1,
-},{
-	name:		"Hauppauge (bt848)",
-	video_inputs:	4,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	7,
-	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 0, 1, 2, 3, 4},
-	needs_tvaudio:	1,
-	tuner_type:	-1,
-},{
-	name:		"STB",
-	video_inputs:	3,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	7,
-	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 4, 0, 2, 3, 1},
-	no_msp34xx:	1,
-	needs_tvaudio:	1,
-	tuner_type:	-1,
+	.name		= " *** UNKNOWN/GENERIC *** ",
+	.video_inputs	= 4,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= 2,
+	.muxsel		= { 2, 3, 1, 0},
+	.tuner_type	= -1,
+},{
+	.name		= "MIRO PCTV",
+	.video_inputs	= 4,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= 2,
+	.gpiomask	= 15,
+	.muxsel		= { 2, 3, 1, 1},
+	.audiomux	= { 2, 0, 0, 0, 10},
+	.needs_tvaudio	= 1,
+	.tuner_type	= -1,
+},{
+	.name		= "Hauppauge (bt848)",
+	.video_inputs	= 4,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= 2,
+	.gpiomask	= 7,
+	.muxsel		= { 2, 3, 1, 1},
+	.audiomux	= { 0, 1, 2, 3, 4},
+	.needs_tvaudio	= 1,
+	.tuner_type	= -1,
+},{
+	.name		= "STB, Gateway P/N 6000699 (bt848)",
+	.video_inputs	= 3,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= 2,
+	.gpiomask	= 7,
+	.muxsel		= { 2, 3, 1, 1},
+	.audiomux	= { 4, 0, 2, 3, 1},
+	.no_msp34xx	= 1,
+	.needs_tvaudio	= 1,
+	.tuner_type     = TUNER_PHILIPS_NTSC,
+	.pll            = PLL_28,
+	.has_radio      = 1,
 },{
 
 /* ---- card 0x04 ---------------------------------- */
-	name:		"Intel Create and Share PCI/ Smart Video Recorder III",
-	video_inputs:	4,
-	audio_inputs:	0,
-	tuner:		-1,
-	svhs:		2,
-	gpiomask:	0,
-	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 0 },
-	needs_tvaudio:	0,
-	tuner_type:	4,
-},{
-	name:		"Diamond DTV2000",
-	video_inputs:	4,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	3,
-	muxsel:		{ 2, 3, 1, 0},
-	audiomux:	{ 0, 1, 0, 1, 3},
-	needs_tvaudio:	1,
-	tuner_type:	-1,
-},{
-	name:		"AVerMedia TVPhone",
-	video_inputs:	3,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		3,
-	muxsel:		{ 2, 3, 1, 1},
-	gpiomask:	0x0f,
-	audiomux:	{ 0x0c, 0x04, 0x08, 0x04, 0},
+	.name		= "Intel Create and Share PCI/ Smart Video Recorder III",
+	.video_inputs	= 4,
+	.audio_inputs	= 0,
+	.tuner		= -1,
+	.svhs		= 2,
+	.gpiomask	= 0,
+	.muxsel		= { 2, 3, 1, 1},
+	.audiomux	= { 0 },
+	.needs_tvaudio	= 0,
+	.tuner_type	= 4,
+},{
+	.name		= "Diamond DTV2000",
+	.video_inputs	= 4,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= 2,
+	.gpiomask	= 3,
+	.muxsel		= { 2, 3, 1, 0},
+	.audiomux	= { 0, 1, 0, 1, 3},
+	.needs_tvaudio	= 1,
+	.tuner_type	= -1,
+},{
+	.name		= "AVerMedia TVPhone",
+	.video_inputs	= 3,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= 3,
+	.muxsel		= { 2, 3, 1, 1},
+	.gpiomask	= 0x0f,
+	.audiomux	= { 0x0c, 0x04, 0x08, 0x04, 0},
 	/*                0x04 for some cards ?? */
-	needs_tvaudio:	1,
-	tuner_type:	-1,
-	audio_hook:	avermedia_tvphone_audio,
-},{
-	name:		"MATRIX-Vision MV-Delta",
-	video_inputs:	5,
-	audio_inputs:	1,
-	tuner:		-1,
-	svhs:		3,
-	gpiomask:	0,
-	muxsel:		{ 2, 3, 1, 0, 0},
-	audiomux:	{0 },
-	needs_tvaudio:	1,
-	tuner_type:	-1,
+	.needs_tvaudio	= 1,
+	.tuner_type	= -1,
+	.audio_hook	= avermedia_tvphone_audio,
+},{
+	.name		= "MATRIX-Vision MV-Delta",
+	.video_inputs	= 5,
+	.audio_inputs	= 1,
+	.tuner		= -1,
+	.svhs		= 3,
+	.gpiomask	= 0,
+	.muxsel		= { 2, 3, 1, 0, 0},
+	.audiomux	= {0 },
+	.needs_tvaudio	= 1,
+	.tuner_type	= -1,
 },{
 
 /* ---- card 0x08 ---------------------------------- */
-	name:		"Lifeview FlyVideo II (Bt848) LR26",
-	video_inputs:	4,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	0xc00,
-	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 0, 0xc00, 0x800, 0x400, 0xc00, 0},
-	needs_tvaudio:	1,
-	pll:		PLL_28,
-	tuner_type:	-1,
-},{
-	name:		"IMS/IXmicro TurboTV",
-	video_inputs:	3,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	3,
-	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 1, 1, 2, 3, 0},
-	needs_tvaudio:	0,
-	pll:		PLL_28,
-	tuner_type:	TUNER_TEMIC_PAL,
-},{
-	name:		"Hauppauge (bt878)",
-	video_inputs:	4,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	0x0f, /* old: 7 */
-	muxsel:		{ 2, 0, 1, 1},
-	audiomux:	{ 0, 1, 2, 3, 4},
-	needs_tvaudio:	1,
-	pll:		PLL_28,
-	tuner_type:	-1,
-},{
-	name:		"MIRO PCTV pro",
-	video_inputs:	3,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	0x3014f,
-	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 0x20001,0x10001, 0, 0,10},
-	needs_tvaudio:	1,
-	tuner_type:	-1,
+	.name		= "Lifeview FlyVideo II (Bt848) LR26",
+	.video_inputs	= 4,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= 2,
+	.gpiomask	= 0xc00,
+	.muxsel		= { 2, 3, 1, 1},
+	.audiomux	= { 0, 0xc00, 0x800, 0x400, 0xc00, 0},
+	.needs_tvaudio	= 1,
+	.pll		= PLL_28,
+	.tuner_type	= -1,
+},{
+	.name		= "IMS/IXmicro TurboTV",
+	.video_inputs	= 3,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= 2,
+	.gpiomask	= 3,
+	.muxsel		= { 2, 3, 1, 1},
+	.audiomux	= { 1, 1, 2, 3, 0},
+	.needs_tvaudio	= 0,
+	.pll		= PLL_28,
+	.tuner_type	= TUNER_TEMIC_PAL,
+},{
+	.name		= "Hauppauge (bt878)",
+	.video_inputs	= 4,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= 2,
+	.gpiomask	= 0x0f, /* old: 7 */
+	.muxsel		= { 2, 0, 1, 1},
+	.audiomux	= { 0, 1, 2, 3, 4},
+	.needs_tvaudio	= 1,
+	.pll		= PLL_28,
+	.tuner_type	= -1,
+},{
+	.name		= "MIRO PCTV pro",
+	.video_inputs	= 3,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= 2,
+	.gpiomask	= 0x3014f,
+	.muxsel		= { 2, 3, 1, 1},
+	.audiomux	= { 0x20001,0x10001, 0, 0,10},
+	.needs_tvaudio	= 1,
+	.tuner_type	= -1,
 },{
 
 /* ---- card 0x0c ---------------------------------- */
-	name:		"ADS Technologies Channel Surfer TV (bt848)",
-	video_inputs:	3,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	15,
-	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 13, 14, 11, 7, 0, 0},
-	needs_tvaudio:	1,
-	tuner_type:	-1,
-},{
-	name:		"AVerMedia TVCapture 98",
-	video_inputs:	3,
-	audio_inputs:	4,
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	15,
-	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 13, 14, 11, 7, 0, 0},
-	needs_tvaudio:	1,
-	pll:		PLL_28,
-	tuner_type:	TUNER_PHILIPS_PAL,
-},{
-	name:		"Aimslab Video Highway Xtreme (VHX)",
-	video_inputs:	3,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	7,
-	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 0, 2, 1, 3, 4}, /* old: { 0, 1, 2, 3, 4} */
-	needs_tvaudio:	1,
-	pll:		PLL_28,
-	tuner_type:	-1,
-},{
-	name:		"Zoltrix TV-Max",
-	video_inputs:	3,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	15,
-	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{0 , 0, 1 , 0, 10},
-	needs_tvaudio:	1,
-	tuner_type:	-1,
+	.name		= "ADS Technologies Channel Surfer TV (bt848)",
+	.video_inputs	= 3,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= 2,
+	.gpiomask	= 15,
+	.muxsel		= { 2, 3, 1, 1},
+	.audiomux	= { 13, 14, 11, 7, 0, 0},
+	.needs_tvaudio	= 1,
+	.tuner_type	= -1,
+},{
+	.name		= "AVerMedia TVCapture 98",
+	.video_inputs	= 3,
+	.audio_inputs	= 4,
+	.tuner		= 0,
+	.svhs		= 2,
+	.gpiomask	= 15,
+	.muxsel		= { 2, 3, 1, 1},
+	.audiomux	= { 13, 14, 11, 7, 0, 0},
+	.needs_tvaudio	= 1,
+	.msp34xx_alt    = 1,
+	.pll		= PLL_28,
+	.tuner_type	= TUNER_PHILIPS_PAL,
+},{
+	.name		= "Aimslab Video Highway Xtreme (VHX)",
+	.video_inputs	= 3,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= 2,
+	.gpiomask	= 7,
+	.muxsel		= { 2, 3, 1, 1},
+	.audiomux	= { 0, 2, 1, 3, 4}, /* old: { 0, 1, 2, 3, 4} */
+	.needs_tvaudio	= 1,
+	.pll		= PLL_28,
+	.tuner_type	= -1,
+},{
+	.name		= "Zoltrix TV-Max",
+	.video_inputs	= 3,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= 2,
+	.gpiomask	= 15,
+	.muxsel		= { 2, 3, 1, 1},
+	.audiomux	= {0 , 0, 1 , 0, 10},
+	.needs_tvaudio	= 1,
+	.tuner_type	= -1,
 },{
 
 /* ---- card 0x10 ---------------------------------- */
-	name:		"Prolink Pixelview PlayTV (bt878)",
-	video_inputs:	3,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	0x01fe00,
-	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 },
-	needs_tvaudio:	1,
-	pll:		PLL_28,
-	tuner_type:	-1,
-},{
-	name:		"Leadtek WinView 601",
-	video_inputs:	3,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	0x8300f8,
-	muxsel:		{ 2, 3, 1, 1,0},
-	audiomux:	{ 0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007},
-	needs_tvaudio:	1,
-	tuner_type:	-1,
-	audio_hook:	winview_audio,
-	has_radio:	1,
-},{
-	name:		"AVEC Intercapture",
-	video_inputs:	3,
-	audio_inputs:	2,
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	0,
-	muxsel:		{2, 3, 1, 1},
-	audiomux:	{1, 0, 0, 0, 0},
-	needs_tvaudio:	1,
-	tuner_type:	-1,
-},{
-	name:		"Lifeview FlyVideo II EZ /FlyKit LR38 Bt848 (capture only)",
-	video_inputs:	4,
-	audio_inputs:	1,
-	tuner:		-1,
-	svhs:		-1,
-	gpiomask:	0x8dff00,
-	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 0 },
-	no_msp34xx:	1,
-	tuner_type:	-1,
+	.name		= "Prolink Pixelview PlayTV (bt878)",
+	.video_inputs	= 3,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= 2,
+	.gpiomask	= 0x01fe00,
+	.muxsel		= { 2, 3, 1, 1},
+	.audiomux	= { 0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 },
+	.needs_tvaudio	= 1,
+	.pll		= PLL_28,
+	.tuner_type	= -1,
+},{
+	.name		= "Leadtek WinView 601",
+	.video_inputs	= 3,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= 2,
+	.gpiomask	= 0x8300f8,
+	.muxsel		= { 2, 3, 1, 1,0},
+	.audiomux	= { 0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007},
+	.needs_tvaudio	= 1,
+	.tuner_type	= -1,
+	.audio_hook	= winview_audio,
+	.has_radio	= 1,
+},{
+	.name		= "AVEC Intercapture",
+	.video_inputs	= 3,
+	.audio_inputs	= 2,
+	.tuner		= 0,
+	.svhs		= 2,
+	.gpiomask	= 0,
+	.muxsel		= {2, 3, 1, 1},
+	.audiomux	= {1, 0, 0, 0, 0},
+	.needs_tvaudio	= 1,
+	.tuner_type	= -1,
+},{
+	.name		= "Lifeview FlyVideo II EZ /FlyKit LR38 Bt848 (capture only)",
+	.video_inputs	= 4,
+	.audio_inputs	= 1,
+	.tuner		= -1,
+	.svhs		= -1,
+	.gpiomask	= 0x8dff00,
+	.muxsel		= { 2, 3, 1, 1},
+	.audiomux	= { 0 },
+	.no_msp34xx	= 1,
+	.tuner_type	= -1,
 },{
 
 /* ---- card 0x14 ---------------------------------- */
-	name:		"CEI Raffles Card",
-	video_inputs:	3,
-	audio_inputs:	3,
-	tuner:		0,
-	svhs:		2,
-	muxsel:		{2, 3, 1, 1},
-	tuner_type:	-1,
-},{
-	name:		"Lifeview FlyVideo 98/ Lucky Star Image World ConferenceTV LR50",
-	video_inputs:	4,
-	audio_inputs:	2,  // tuner, line in
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	0x1800,
-	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 0, 0x800, 0x1000, 0x1000, 0x1800},
-	pll:		PLL_28,
-	tuner_type:	TUNER_PHILIPS_PAL_I,
-},{
-	name:		"Askey CPH050/ Phoebe Tv Master + FM",
-	video_inputs:	3,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	0xc00,
-	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{0, 1, 0x800, 0x400, 0xc00, 0},
-	needs_tvaudio:	1,
-	pll:		PLL_28,
-	tuner_type:	-1,
-},{
-	name:		"Modular Technology MM205 PCTV, bt878",
-	video_inputs:	2,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		-1,
-	gpiomask:	7,
-	muxsel:		{ 2, 3 },
-	audiomux:	{ 0, 0, 0, 0, 0 },
-	no_msp34xx:	1,
-	pll:            PLL_28,
-	tuner_type:     TUNER_ALPS_TSBB5_PAL_I,
+	.name		= "CEI Raffles Card",
+	.video_inputs	= 3,
+	.audio_inputs	= 3,
+	.tuner		= 0,
+	.svhs		= 2,
+	.muxsel		= {2, 3, 1, 1},
+	.tuner_type	= -1,
+},{
+	.name		= "Lifeview FlyVideo 98/ Lucky Star Image World ConferenceTV LR50",
+	.video_inputs	= 4,
+	.audio_inputs	= 2,  // tuner, line in
+	.tuner		= 0,
+	.svhs		= 2,
+	.gpiomask	= 0x1800,
+	.muxsel		= { 2, 3, 1, 1},
+	.audiomux	= { 0, 0x800, 0x1000, 0x1000, 0x1800},
+	.pll		= PLL_28,
+	.tuner_type	= TUNER_PHILIPS_PAL_I,
+},{
+	.name		= "Askey CPH050/ Phoebe Tv Master + FM",
+	.video_inputs	= 3,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= 2,
+	.gpiomask	= 0xc00,
+	.muxsel		= { 2, 3, 1, 1},
+	.audiomux	= {0, 1, 0x800, 0x400, 0xc00, 0},
+	.needs_tvaudio	= 1,
+	.pll		= PLL_28,
+	.tuner_type	= -1,
+},{
+	.name		= "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV, bt878",
+	.video_inputs	= 3,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= -1,
+	.gpiomask	= 7,
+	.muxsel		= { 2, 3, -1 },
+        .digital_mode   = DIGITAL_MODE_CAMERA,
+	.audiomux	= { 0, 0, 0, 0, 0 },
+	.no_msp34xx	= 1,
+	.pll            = PLL_28,
+	.tuner_type     = TUNER_ALPS_TSBB5_PAL_I,
 },{
 
 /* ---- card 0x18 ---------------------------------- */
-	name:		"Askey CPH05X/06X (bt878) [many vendors]",
-	video_inputs:	3,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	0xe00,
-	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{0x400, 0x400, 0x400, 0x400, 0xc00},
-	needs_tvaudio:	1,
-	pll:		PLL_28,
-	tuner_type:	-1,
-},{
-	name:		"Terratec Terra TV+ Version 1.0 (Bt848)/Vobis TV-Boostar",
-	video_inputs:	3,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	16777215,
-	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 131072, 1, 1638400, 3,4},
-	needs_tvaudio:	1,
-	tuner_type:	-1,
-},{
-	name:		"Hauppauge WinCam newer (bt878)",
-	video_inputs:	4,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		3,
-	gpiomask:	7,
-	muxsel:		{ 2, 0, 1, 1},
-	audiomux:	{ 0, 1, 2, 3, 4},
-	needs_tvaudio:	1,
-	tuner_type:	-1,
-},{
-	name:		"Lifeview FlyVideo 98/ MAXI TV Video PCI2 LR50",
-	video_inputs:	4,
-	audio_inputs:	2,
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	0x1800,
-	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 0, 0x800, 0x1000, 0x1000, 0x1800},
-	pll:            PLL_28,
-	tuner_type:	TUNER_PHILIPS_SECAM,
+	.name		= "Askey CPH05X/06X (bt878) [many vendors]",
+	.video_inputs	= 3,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= 2,
+	.gpiomask	= 0xe00,
+	.muxsel		= { 2, 3, 1, 1},
+	.audiomux	= {0x400, 0x400, 0x400, 0x400, 0xc00},
+	.needs_tvaudio	= 1,
+	.pll		= PLL_28,
+	.tuner_type	= -1,
+},{
+	.name           = "Terratec TerraTV+ Version 1.0 (Bt848)/ Terra TValue Version 1.0/ Vobis TV-Boostar",
+	.video_inputs	= 3,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= 2,
+	.gpiomask       = 0x1f0fff,
+	.muxsel		= { 2, 3, 1, 1},
+	.audiomux       = { 0x20000, 0x30000, 0x10000, 0, 0x40000},
+	.needs_tvaudio	= 0,
+	.tuner_type	= TUNER_PHILIPS_PAL,
+	.audio_hook     = terratv_audio,
+},{
+	.name		= "Hauppauge WinCam newer (bt878)",
+	.video_inputs	= 4,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= 3,
+	.gpiomask	= 7,
+	.muxsel		= { 2, 0, 1, 1},
+	.audiomux	= { 0, 1, 2, 3, 4},
+	.needs_tvaudio	= 1,
+	.tuner_type	= -1,
+},{
+	.name		= "Lifeview FlyVideo 98/ MAXI TV Video PCI2 LR50",
+	.video_inputs	= 4,
+	.audio_inputs	= 2,
+	.tuner		= 0,
+	.svhs		= 2,
+	.gpiomask	= 0x1800,
+	.muxsel		= { 2, 3, 1, 1},
+	.audiomux	= { 0, 0x800, 0x1000, 0x1000, 0x1800},
+	.pll            = PLL_28,
+	.tuner_type	= TUNER_PHILIPS_SECAM,
 },{
 
 /* ---- card 0x1c ---------------------------------- */
-	name:		"Terratec TerraTV+",
-	video_inputs:	3,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	0x70000,
-	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 0x20000, 0x30000, 0x10000, 0x00000, 0x40000},
-	needs_tvaudio:	1,
-	tuner_type:	TUNER_PHILIPS_PAL,
-	audio_hook:	terratv_audio,
+	.name           = "Terratec TerraTV+ Version 1.1 (bt878)",
+	.video_inputs	= 3,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= 2,
+	.gpiomask	= 0x1f0fff,
+	.muxsel		= { 2, 3, 1, 1},
+	.audiomux	= { 0x20000, 0x30000, 0x10000, 0x00000, 0x40000},
+	.needs_tvaudio	= 0,
+	.tuner_type	= TUNER_PHILIPS_PAL,
+	.audio_hook	= terratv_audio,
+	/* GPIO wiring:
+               External 20 pin connector (for Active Radio Upgrade board)
+               gpio00: i2c-sda
+               gpio01: i2c-scl
+               gpio02: om5610-data
+               gpio03: om5610-clk
+               gpio04: om5610-wre
+               gpio05: om5610-stereo
+               gpio06: rds6588-davn
+               gpio07: Pin 7 n.c.
+               gpio08: nIOW
+               gpio09+10: nIOR, nSEL ?? (bt878)
+                gpio09: nIOR (bt848)
+                gpio10: nSEL (bt848)
+              Sound Routing:
+               gpio16: u2-A0 (1st 4052bt)
+               gpio17: u2-A1
+               gpio18: u2-nEN
+               gpio19: u4-A0 (2nd 4052)
+               gpio20: u4-A1
+                       u4-nEN - GND
+	    Btspy:
+	  	00000 : Cdrom (internal audio input)
+		10000 : ext. Video audio input
+		20000 : TV Mono
+		a0000 : TV Mono/2
+	       1a0000 : TV Stereo	
+		30000 : Radio
+		40000 : Mute
+       */
+
 },{
 	/* Jannik Fritsch <jannik@techfak.uni-bielefeld.de> */
-	name:		"Imagenation PXC200",
-	video_inputs:	5,
-	audio_inputs:	1,
-	tuner:		-1,
-	svhs:		1, /* was: 4 */
-	gpiomask:	0,
-	muxsel:		{ 2, 3, 1, 0, 0},
-	audiomux:	{ 0 },
-	needs_tvaudio:	1,
-	tuner_type:	-1,
-},{
-	name:		"Lifeview FlyVideo 98 LR50",
-	video_inputs:	4,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	0x1800,  //0x8dfe00
-	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 0, 0x0800, 0x1000, 0x1000, 0x1800, 0 },
-	pll:            PLL_28,
-	tuner_type:	-1,
-},{
-	name:		"Formac iProTV",
-	video_inputs:	3,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	1,
-	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 1, 0, 0, 0, 0 },
-	tuner_type:	-1,
+	.name		= "Imagenation PXC200",
+	.video_inputs	= 5,
+	.audio_inputs	= 1,
+	.tuner		= -1,
+	.svhs		= 1, /* was: 4 */
+	.gpiomask	= 0,
+	.muxsel		= { 2, 3, 1, 0, 0},
+	.audiomux	= { 0 },
+	.needs_tvaudio	= 1,
+	.tuner_type	= -1,
+},{
+	.name		= "Lifeview FlyVideo 98 LR50",
+	.video_inputs	= 4,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= 2,
+	.gpiomask	= 0x1800,  //0x8dfe00
+	.muxsel		= { 2, 3, 1, 1},
+	.audiomux	= { 0, 0x0800, 0x1000, 0x1000, 0x1800, 0 },
+	.pll            = PLL_28,
+	.tuner_type	= -1,
+},{
+	.name		= "Formac iProTV",
+	.video_inputs	= 4,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= 3,
+	.gpiomask	= 1,
+	.muxsel		= { 2, 3, 1, 1},
+	.audiomux	= { 1, 0, 0, 0, 0 },
+	.pll            = PLL_28,
+	.tuner_type	= TUNER_PHILIPS_PAL,
 },{
 
 /* ---- card 0x20 ---------------------------------- */
-	name:		"Intel Create and Share PCI/ Smart Video Recorder III",
-	video_inputs:	4,
-	audio_inputs:	0,
-	tuner:		-1,
-	svhs:		2,
-	gpiomask:	0,
-	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 0 },
-	needs_tvaudio:	0,
-	tuner_type:	4,
-},{
-	name:		"Terratec TerraTValue",
-	video_inputs:	3,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	0xffff00,
-	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 0x500, 0, 0x300, 0x900, 0x900},
-	needs_tvaudio:	1,
-	pll:		PLL_28,
-	tuner_type:	TUNER_PHILIPS_PAL,
-},{
-	name:		"Leadtek WinFast 2000/ WinFast 2000 XP",
-	video_inputs:	4,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	0xc33000,
-	muxsel:		{ 2, 3, 1, 1, 0}, // TV, CVid, SVid, CVid over SVid connector
-	audiomux:	{ 0x422000,0x1000,0x0000,0x620000,0x800000},
+	.name		= "Intel Create and Share PCI/ Smart Video Recorder III",
+	.video_inputs	= 4,
+	.audio_inputs	= 0,
+	.tuner		= -1,
+	.svhs		= 2,
+	.gpiomask	= 0,
+	.muxsel		= { 2, 3, 1, 1},
+	.audiomux	= { 0 },
+	.needs_tvaudio	= 0,
+	.tuner_type	= 4,
+},{
+	.name           = "Terratec TerraTValue Version Bt878",
+	.video_inputs	= 3,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= 2,
+	.gpiomask	= 0xffff00,
+	.muxsel		= { 2, 3, 1, 1},
+	.audiomux	= { 0x500, 0, 0x300, 0x900, 0x900},
+	.needs_tvaudio	= 1,
+	.pll		= PLL_28,
+	.tuner_type	= TUNER_PHILIPS_PAL,
+},{
+	.name		= "Leadtek WinFast 2000/ WinFast 2000 XP",
+	.video_inputs	= 4,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= 2,
+	.gpiomask	= 0xc33000,
+	.muxsel		= { 2, 3, 1, 1, 0}, // TV, CVid, SVid, CVid over SVid connector
+	.audiomux	= { 0x422000,0x1000,0x0000,0x620000,0x800000},
 	/* Audio Routing for "WinFast 2000 XP" (no tv stereo !)
 		gpio23 -- hef4052:nEnable (0x800000)
 		gpio12 -- hef4052:A1
@@ -614,237 +684,250 @@
           Note: There exists another variant "Winfast 2000" with tv stereo !?
 	  Note: eeprom only contains FF and pci subsystem id 107d:6606
 	 */
-	needs_tvaudio:	0,
-	pll:		PLL_28,
-	has_radio:	1,
-	tuner_type:	5, // default for now, gpio reads BFFF06 for Pal bg+dk
-	audio_hook:	winfast2000_audio,
-},{
-	name:		"Lifeview FlyVideo 98 LR50 / Chronos Video Shuttle II",
-	video_inputs:	4,
-	audio_inputs:	3,
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	0x1800,
-	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 0, 0x800, 0x1000, 0x1000, 0x1800},
-	pll:		PLL_28,
-	tuner_type:	-1,
+	.needs_tvaudio	= 0,
+	.pll		= PLL_28,
+	.has_radio	= 1,
+	.tuner_type	= 5, // default for now, gpio reads BFFF06 for Pal bg+dk
+	.audio_hook	= winfast2000_audio,
+},{
+	.name		= "Lifeview FlyVideo 98 LR50 / Chronos Video Shuttle II",
+	.video_inputs	= 4,
+	.audio_inputs	= 3,
+	.tuner		= 0,
+	.svhs		= 2,
+	.gpiomask	= 0x1800,
+	.muxsel		= { 2, 3, 1, 1},
+	.audiomux	= { 0, 0x800, 0x1000, 0x1000, 0x1800},
+	.pll		= PLL_28,
+	.tuner_type	= -1,
 },{
 
 /* ---- card 0x24 ---------------------------------- */
-	name:		"Lifeview FlyVideo 98FM LR50 / Typhoon TView TV/FM Tuner",
-	video_inputs:	4,
-	audio_inputs:	3,
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	0x1800,
-	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 0, 0x800, 0x1000, 0x1000, 0x1800, 0 },
-	pll:		PLL_28,
-	tuner_type:	-1,
-	has_radio:	1,
-},{
-	name:		"Prolink PixelView PlayTV pro",
-	video_inputs:	3,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	0xff,
-	muxsel:		{ 2, 3, 1, 1 },
-	audiomux:	{ 0x21, 0x20, 0x24, 0x2c, 0x29, 0x29 },
-	no_msp34xx:	1,
-	pll:		PLL_28,
-	tuner_type:	-1,
-},{
-	name:		"Askey CPH06X TView99",
-	video_inputs:	4,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	0x551e00,
-	muxsel:		{ 2, 3, 1, 0},
-	audiomux:	{ 0x551400, 0x551200, 0, 0, 0x551c00, 0x551200 },
-	needs_tvaudio:	1,
-	pll:		PLL_28,
-	tuner_type:	-1,
-},{
-	name:		"Pinnacle PCTV Studio/Rave",
-	video_inputs:	3,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	0x03000F,
-	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 2, 0, 0, 0, 1},
-	needs_tvaudio:	1,
-	pll:		PLL_28,
-	tuner_type:	-1,
+	.name		= "Lifeview FlyVideo 98FM LR50 / Typhoon TView TV/FM Tuner",
+	.video_inputs	= 4,
+	.audio_inputs	= 3,
+	.tuner		= 0,
+	.svhs		= 2,
+	.gpiomask	= 0x1800,
+	.muxsel		= { 2, 3, 1, 1},
+	.audiomux	= { 0, 0x800, 0x1000, 0x1000, 0x1800, 0 },
+	.pll		= PLL_28,
+	.tuner_type	= -1,
+	.has_radio	= 1,
+},{
+	.name		= "Prolink PixelView PlayTV pro",
+	.video_inputs	= 3,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= 2,
+	.gpiomask	= 0xff,
+	.muxsel		= { 2, 3, 1, 1 },
+	.audiomux	= { 0x21, 0x20, 0x24, 0x2c, 0x29, 0x29 },
+	.no_msp34xx	= 1,
+	.pll		= PLL_28,
+	.tuner_type	= -1,
+},{
+	.name		= "Askey CPH06X TView99",
+	.video_inputs	= 4,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= 2,
+	.gpiomask	= 0x551e00,
+	.muxsel		= { 2, 3, 1, 0},
+	.audiomux	= { 0x551400, 0x551200, 0, 0, 0x551c00, 0x551200 },
+	.needs_tvaudio	= 1,
+	.pll		= PLL_28,
+	.tuner_type	= -1,
+},{
+	.name		= "Pinnacle PCTV Studio/Rave",
+	.video_inputs	= 3,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= 2,
+	.gpiomask	= 0x03000F,
+	.muxsel		= { 2, 3, 1, 1},
+	.audiomux	= { 2, 0, 0, 0, 1},
+	.needs_tvaudio	= 1,
+	.pll		= PLL_28,
+	.tuner_type	= -1,
 },{
 
 /* ---- card 0x28 ---------------------------------- */
-	name:		"STB2",
-	video_inputs:	3,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	7,
-	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 4, 0, 2, 3, 1},
-	no_msp34xx:	1,
-	needs_tvaudio:	1,
-	tuner_type:	-1,
-},{
-	name:		"AVerMedia TVPhone 98",
-	video_inputs:	3,
-	audio_inputs:	4,
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	15,
-	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 13, 4, 11, 7, 0, 0},
-	needs_tvaudio:	1,
-	pll:		PLL_28,
-	tuner_type:	-1,
-	has_radio:	1,
-},{
-	name:		"ProVideo PV951", /* pic16c54 */
-	video_inputs:	3,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	0,
-	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 0, 0, 0, 0, 0},
-	needs_tvaudio:	1,
-	no_msp34xx:	1,
-	pll:		PLL_28,
-	tuner_type:	1,
-},{
-	name:		"Little OnAir TV",
-	video_inputs:	3,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	0xe00b,
-	muxsel:		{2, 3, 1, 1},
-	audiomux:	{0xff9ff6, 0xff9ff6, 0xff1ff7, 0, 0xff3ffc},
-	no_msp34xx:	1,
-	tuner_type:	-1,
+	.name		= "STB TV PCI FM, Gateway P/N 6000704 (bt878), 3Dfx VoodooTV 100",
+	.video_inputs	= 3,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= 2,
+	.gpiomask	= 7,
+	.muxsel		= { 2, 3, 1, 1},
+	.audiomux	= { 4, 0, 2, 3, 1},
+	.no_msp34xx	= 1,
+	.needs_tvaudio	= 1,
+	.tuner_type     = TUNER_PHILIPS_NTSC,
+	.pll            = PLL_28,
+	.has_radio      = 1,
+},{
+	.name		= "AVerMedia TVPhone 98",
+	.video_inputs	= 3,
+	.audio_inputs	= 4,
+	.tuner		= 0,
+	.svhs		= 2,
+	.gpiomask	= 15,
+	.muxsel		= { 2, 3, 1, 1},
+	.audiomux	= { 13, 4, 11, 7, 0, 0},
+	.needs_tvaudio	= 1,
+	.pll		= PLL_28,
+	.tuner_type	= -1,
+	.has_radio	= 1,
+	.audio_hook	= avermedia_tvphone_audio,
+},{
+	.name		= "ProVideo PV951", /* pic16c54 */
+	.video_inputs	= 3,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= 2,
+	.gpiomask	= 0,
+	.muxsel		= { 2, 3, 1, 1},
+	.audiomux	= { 0, 0, 0, 0, 0},
+	.needs_tvaudio	= 1,
+	.no_msp34xx	= 1,
+	.pll		= PLL_28,
+	.tuner_type	= 1,
+},{
+	.name		= "Little OnAir TV",
+	.video_inputs	= 3,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= 2,
+	.gpiomask	= 0xe00b,
+	.muxsel		= {2, 3, 1, 1},
+	.audiomux	= {0xff9ff6, 0xff9ff6, 0xff1ff7, 0, 0xff3ffc},
+	.no_msp34xx	= 1,
+	.tuner_type	= -1,
 },{
 
 /* ---- card 0x2c ---------------------------------- */
-	name:		"Sigma TVII-FM",
-	video_inputs:	2,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		-1,
-	gpiomask:	3,
-	muxsel:		{2, 3, 1, 1},
-	audiomux:	{1, 1, 0, 2, 3},
-	no_msp34xx:	1,
-	pll:		PLL_NONE,
-	tuner_type:	-1,
-},{
-	name:		"MATRIX-Vision MV-Delta 2",
-	video_inputs:	5,
-	audio_inputs:	1,
-	tuner:		-1,
-	svhs:		3,
-	gpiomask:	0,
-	muxsel:		{ 2, 3, 1, 0, 0},
-	audiomux:	{0 },
-	no_msp34xx:	1,
-	pll:		PLL_28,
-	tuner_type:	-1,
-},{
-	name:		"Zoltrix Genie TV/FM",
-	video_inputs:	3,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	0xbcf03f,
-	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 0xbc803f, 0xbc903f, 0xbcb03f, 0, 0xbcb03f},
-	no_msp34xx:	1,
-	pll:		PLL_28,
-	tuner_type:	21,
-},{
-	name:		"Terratec TV/Radio+",
-	video_inputs:	3,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	0x70000,
-	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 0x20000, 0x30000, 0x10000, 0, 0x40000, 0x20000 },
-	needs_tvaudio:	1,
-	no_msp34xx:	1,
-	pll:		PLL_35,
-	tuner_type:	1,
-	has_radio:	1,
+	.name		= "Sigma TVII-FM",
+	.video_inputs	= 2,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= -1,
+	.gpiomask	= 3,
+	.muxsel		= {2, 3, 1, 1},
+	.audiomux	= {1, 1, 0, 2, 3},
+	.no_msp34xx	= 1,
+	.pll		= PLL_NONE,
+	.tuner_type	= -1,
+},{
+	.name		= "MATRIX-Vision MV-Delta 2",
+	.video_inputs	= 5,
+	.audio_inputs	= 1,
+	.tuner		= -1,
+	.svhs		= 3,
+	.gpiomask	= 0,
+	.muxsel		= { 2, 3, 1, 0, 0},
+	.audiomux	= {0 },
+	.no_msp34xx	= 1,
+	.pll		= PLL_28,
+	.tuner_type	= -1,
+},{
+	.name		= "Zoltrix Genie TV/FM",
+	.video_inputs	= 3,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= 2,
+	.gpiomask	= 0xbcf03f,
+	.muxsel		= { 2, 3, 1, 1},
+	.audiomux	= { 0xbc803f, 0xbc903f, 0xbcb03f, 0, 0xbcb03f},
+	.no_msp34xx	= 1,
+	.pll		= PLL_28,
+	.tuner_type	= 21,
+},{
+	.name		= "Terratec TV/Radio+",
+	.video_inputs	= 3,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= 2,
+	.gpiomask	= 0x70000,
+	.muxsel		= { 2, 3, 1, 1},
+	.audiomux	= { 0x20000, 0x30000, 0x10000, 0, 0x40000, 0x20000 },
+	.needs_tvaudio	= 1,
+	.no_msp34xx	= 1,
+	.pll		= PLL_35,
+	.tuner_type	= 1,
+	.has_radio	= 1,
 },{
 
 /* ---- card 0x30 ---------------------------------- */
-	name:		"Askey CPH03x/ Dynalink Magic TView",
-	video_inputs:	3,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	15,
-	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{2,0,0,0,1},
-	needs_tvaudio:	1,
-	pll:		PLL_28,
-	tuner_type:	-1,
-},{
-	name:		"IODATA GV-BCTV3/PCI",
-	video_inputs:	3,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	0x010f00,
-	muxsel:		{2, 3, 0, 0},
-	audiomux:	{0x10000, 0, 0x10000, 0, 0, 0},
-	no_msp34xx:	1,
-	pll:		PLL_28,
-	tuner_type:	TUNER_ALPS_TSHC6_NTSC,
-	audio_hook:	gvbctv3pci_audio,
-},{
-	name:		"Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP",
-	video_inputs:	4,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		3,
-	gpiomask:	0xAA0000,
-	muxsel:		{ 2,3,1,1 },
-	audiomux:	{ 0x20000, 0, 0x80000, 0x80000, 0xa8000, 0x46000  },
-	no_msp34xx:	1,
-	pll:		PLL_28,
-	tuner_type:	TUNER_PHILIPS_PAL_I,
-},{
-	name:           "Eagle Wireless Capricorn2 (bt878A)",
-	video_inputs:   4,
-	audio_inputs:   1,
-	tuner:          0,
-	svhs:           2,
-	gpiomask:       7,
-	muxsel:         { 2, 0, 1, 1},
-	audiomux:       { 0, 1, 2, 3, 4},
-	pll:            PLL_28,
-	tuner_type:     -1 /* TUNER_ALPS_TMDH2_NTSC */,
+	.name		= "Askey CPH03x/ Dynalink Magic TView",
+	.video_inputs	= 3,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= 2,
+	.gpiomask	= 15,
+	.muxsel		= { 2, 3, 1, 1},
+	.audiomux	= {2,0,0,0,1},
+	.needs_tvaudio	= 1,
+	.pll		= PLL_28,
+	.tuner_type	= -1,
+},{
+	.name		= "IODATA GV-BCTV3/PCI",
+	.video_inputs	= 3,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= 2,
+	.gpiomask	= 0x010f00,
+	.muxsel		= {2, 3, 0, 0},
+	.audiomux	= {0x10000, 0, 0x10000, 0, 0, 0},
+	.no_msp34xx	= 1,
+	.pll		= PLL_28,
+	.tuner_type	= TUNER_ALPS_TSHC6_NTSC,
+	.audio_hook	= gvbctv3pci_audio,
+},{
+	.name		= "Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP",
+	.video_inputs	= 5,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= 3,
+	.gpiomask	= 0xAA0000,
+	.muxsel		= { 2,3,1,1,-1 },
+	.digital_mode   = DIGITAL_MODE_CAMERA,
+	.audiomux	= { 0x20000, 0, 0x80000, 0x80000, 0xa8000, 0x46000  },
+	.no_msp34xx	= 1,
+	.pll		= PLL_28,
+	.tuner_type	= TUNER_PHILIPS_PAL_I,
+	/* GPIO wiring: (different from Rev.4C !)
+		GPIO17: U4.A0 (first hef4052bt)
+		GPIO19: U4.A1
+		GPIO20: U5.A1 (second hef4052bt)
+		GPIO21: U4.nEN
+		GPIO22: BT832 Reset Line
+		GPIO23: A5,A0, U5,nEN
+	   Note: At i2c=0x8a is a Bt832 chip, which changes to 0x88 after being reset via GPIO22
+	 */
+},{
+	.name           = "Eagle Wireless Capricorn2 (bt878A)",
+	.video_inputs   = 4,
+	.audio_inputs   = 1,
+	.tuner          = 0,
+	.svhs           = 2,
+	.gpiomask       = 7,
+	.muxsel         = { 2, 0, 1, 1},
+	.audiomux       = { 0, 1, 2, 3, 4},
+	.pll            = PLL_28,
+	.tuner_type     = -1 /* TUNER_ALPS_TMDH2_NTSC */,
 },{
 
 /* ---- card 0x34 ---------------------------------- */
 	/* David Härdeman <david@2gen.com> */
-	name:           "Pinnacle PCTV Studio Pro",
-	video_inputs:   3,
-	audio_inputs:   1,
-	tuner:          0,
-	svhs:           2,
-	gpiomask:       0x03000F,
-	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 1, 0x10001, 0, 0, 10},
+	.name           = "Pinnacle PCTV Studio Pro",
+	.video_inputs   = 3,
+	.audio_inputs   = 1,
+	.tuner          = 0,
+	.svhs           = 3,
+	.gpiomask       = 0x03000F,
+	.muxsel		= { 2, 3, 1, 1},
+	.audiomux	= { 1, 0xd0001, 0, 0, 10},
 			/* sound path (5 sources):
 			   MUX1 (mask 0x03), Enable Pin 0x08 (0=enable, 1=disable)
 				0= ext. Audio IN
@@ -854,424 +937,701 @@
 			   MUX2 (mask 0x30000):
 				0,2,3= from MSP34xx
 				1= FM stereo Radio from Tuner */
-	needs_tvaudio:  1,
-	pll:            PLL_28,
-	tuner_type:     -1,
+	.needs_tvaudio  = 1,
+	.pll            = PLL_28,
+	.tuner_type     = -1,
 },{
 	/* Claas Langbehn <claas@bigfoot.com>,
 	   Sven Grothklags <sven@upb.de> */
-	name:		"Typhoon TView RDS + FM Stereo / KNC1 TV Station RDS",
-	video_inputs:	3,
-	audio_inputs:	3,
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	0x1c,
-	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 0, 0, 0x10, 8, 4 },
-	needs_tvaudio:	1,
-	pll:		PLL_28,
-	tuner_type:	TUNER_PHILIPS_PAL_I,
-	has_radio:	1,
+	.name		= "Typhoon TView RDS + FM Stereo / KNC1 TV Station RDS",
+	.video_inputs	= 3,
+	.audio_inputs	= 3,
+	.tuner		= 0,
+	.svhs		= 2,
+	.gpiomask	= 0x1c,
+	.muxsel		= { 2, 3, 1, 1},
+	.audiomux	= { 0, 0, 0x10, 8, 4 },
+	.needs_tvaudio	= 1,
+	.pll		= PLL_28,
+	.tuner_type	= TUNER_PHILIPS_PAL_I,
+	.has_radio	= 1,
 },{
 	/* Tim Röstermundt <rosterm@uni-muenster.de>
 	   in de.comp.os.unix.linux.hardware:
 		options bttv card=0 pll=1 radio=1 gpiomask=0x18e0
 		audiomux=0x44c71f,0x44d71f,0,0x44d71f,0x44dfff
 		options tuner type=5 */
-	name:		"Lifeview FlyVideo 2000 /FlyVideo A2/ Lifetec LT 9415 TV [LR90]",
-	video_inputs:	4,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	0x18e0,
-	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 0x0000,0x0800,0x1000,0x1000,0x18e0 },
+	.name		= "Lifeview FlyVideo 2000 /FlyVideo A2/ Lifetec LT 9415 TV [LR90]",
+	.video_inputs	= 4,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= 2,
+	.gpiomask	= 0x18e0,
+	.muxsel		= { 2, 3, 1, 1},
+	.audiomux	= { 0x0000,0x0800,0x1000,0x1000,0x18e0 },
 		       /* For cards with tda9820/tda9821:
 			  0x0000: Tuner normal stereo
 			  0x0080: Tuner A2 SAP (second audio program = Zweikanalton)
 			  0x0880: Tuner A2 stereo */
-	pll:		PLL_28,
-	tuner_type:	-1,
+	.pll		= PLL_28,
+	.tuner_type	= -1,
 },{
 	/* Miguel Angel Alvarez <maacruz@navegalia.com>
 	   old Easy TV BT848 version (model CPH031) */
-	name:           "Askey CPH031/ BESTBUY Easy TV",
-	video_inputs:	4,
-	audio_inputs:   1,
-	tuner:          0,
-	svhs:           2,
-	gpiomask:       0xF,
-	muxsel:         { 2, 3, 1, 0},
-	audiomux:       { 2, 0, 0, 0, 10},
-	needs_tvaudio:  0,
-	pll:		PLL_28,
-	tuner_type:	TUNER_TEMIC_PAL,
+	.name           = "Askey CPH031/ BESTBUY Easy TV",
+	.video_inputs	= 4,
+	.audio_inputs   = 1,
+	.tuner          = 0,
+	.svhs           = 2,
+	.gpiomask       = 0xF,
+	.muxsel         = { 2, 3, 1, 0},
+	.audiomux       = { 2, 0, 0, 0, 10},
+	.needs_tvaudio  = 0,
+	.pll		= PLL_28,
+	.tuner_type	= TUNER_TEMIC_PAL,
 },{
 
 /* ---- card 0x38 ---------------------------------- */
 	/* Gordon Heydon <gjheydon@bigfoot.com ('98) */
-	name:           "Lifeview FlyVideo 98FM LR50",
-	video_inputs:   4,
-	audio_inputs:   3,
-	tuner:          0,
-	svhs:           2,
-	gpiomask:       0x1800,
-	muxsel:         { 2, 3, 1, 1},
-	audiomux:       { 0, 0x800, 0x1000, 0x1000, 0x1800, 0 },
-	pll:            PLL_28,
-	tuner_type:     5,
+	.name           = "Lifeview FlyVideo 98FM LR50",
+	.video_inputs   = 4,
+	.audio_inputs   = 3,
+	.tuner          = 0,
+	.svhs           = 2,
+	.gpiomask       = 0x1800,
+	.muxsel         = { 2, 3, 1, 1},
+	.audiomux       = { 0, 0x800, 0x1000, 0x1000, 0x1800, 0 },
+	.pll            = PLL_28,
+	.tuner_type     = 5,
 },{
 	/* This is the ultimate cheapo capture card 
 	 * just a BT848A on a small PCB!
 	 * Steve Hosgood <steve@equiinet.com> */
-	name:           "GrandTec 'Grand Video Capture' (Bt848)",
-	video_inputs:   2,
-	audio_inputs:   0,
-	tuner:          -1,
-	svhs:           1,
-	gpiomask:       0,
-	muxsel:         { 3, 1 },
-	audiomux:       { 0 },
-	needs_tvaudio:  0,
-	no_msp34xx:     1,
-	pll:            PLL_35,
-	tuner_type:     -1,
+	.name           = "GrandTec 'Grand Video Capture' (Bt848)",
+	.video_inputs   = 2,
+	.audio_inputs   = 0,
+	.tuner          = -1,
+	.svhs           = 1,
+	.gpiomask       = 0,
+	.muxsel         = { 3, 1 },
+	.audiomux       = { 0 },
+	.needs_tvaudio  = 0,
+	.no_msp34xx     = 1,
+	.pll            = PLL_35,
+	.tuner_type     = -1,
 },{
         /* Daniel Herrington <daniel.herrington@home.com> */
-        name:           "Askey CPH060/ Phoebe TV Master Only (No FM)",
-        video_inputs:   3,
-        audio_inputs:   1,
-        tuner:          0,
-        svhs:           2,
-        gpiomask:       0xe00,
-        muxsel:         { 2, 3, 1, 1},
-        audiomux:       { 0x400, 0x400, 0x400, 0x400, 0x800, 0x400 },
-        needs_tvaudio:  1,
-        pll:            PLL_28,
-        tuner_type:     TUNER_TEMIC_4036FY5_NTSC,
+        .name           = "Askey CPH060/ Phoebe TV Master Only (No FM)",
+        .video_inputs   = 3,
+        .audio_inputs   = 1,
+        .tuner          = 0,
+        .svhs           = 2,
+        .gpiomask       = 0xe00,
+        .muxsel         = { 2, 3, 1, 1},
+        .audiomux       = { 0x400, 0x400, 0x400, 0x400, 0x800, 0x400 },
+        .needs_tvaudio  = 1,
+        .pll            = PLL_28,
+        .tuner_type     = TUNER_TEMIC_4036FY5_NTSC,
 },{
 	/* Matti Mottus <mottus@physic.ut.ee> */
-	name:		"Askey CPH03x TV Capturer",
-	video_inputs:	4,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		2,
-        gpiomask:       0x03000F,
-	muxsel:		{ 2, 3, 1, 0},
-        audiomux:       { 2,0,0,0,1 },
-	pll:            PLL_28,
-	tuner_type:	0,
+	.name		= "Askey CPH03x TV Capturer",
+	.video_inputs	= 4,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= 2,
+        .gpiomask       = 0x03000F,
+	.muxsel		= { 2, 3, 1, 0},
+        .audiomux       = { 2,0,0,0,1 },
+	.pll            = PLL_28,
+	.tuner_type	= 0,
 },{
 
 /* ---- card 0x3c ---------------------------------- */
 	/* Philip Blundell <philb@gnu.org> */
-	name:           "Modular Technology MM100PCTV",
-	video_inputs:   2,
-	audio_inputs:   2,
-	tuner:		0,
-	svhs:		-1,
-	gpiomask:       11,
-	muxsel:         { 2, 3, 1, 1},
-	audiomux:       { 2, 0, 0, 1, 8},
-	pll:            PLL_35,
-	tuner_type:     TUNER_TEMIC_PAL,
+	.name           = "Modular Technology MM100PCTV",
+	.video_inputs   = 2,
+	.audio_inputs   = 2,
+	.tuner		= 0,
+	.svhs		= -1,
+	.gpiomask       = 11,
+	.muxsel         = { 2, 3, 1, 1},
+	.audiomux       = { 2, 0, 0, 1, 8},
+	.pll            = PLL_35,
+	.tuner_type     = TUNER_TEMIC_PAL,
 
 },{
 	/* Adrian Cox <adrian@humboldt.co.uk */
-	name:	        "AG Electronics GMV1",
-	video_inputs:   2,
-	audio_inputs:   0,
-	tuner:	        -1,
-	svhs:	        1,
-	gpiomask:       0xF,
-	muxsel:	        { 2, 2},
-	audiomux:       { },
-	no_msp34xx:     1,
-	needs_tvaudio:  0,
-	pll:	        PLL_28,
-	tuner_type:     -1,
+	.name	        = "AG Electronics GMV1",
+	.video_inputs   = 2,
+	.audio_inputs   = 0,
+	.tuner	        = -1,
+	.svhs	        = 1,
+	.gpiomask       = 0xF,
+	.muxsel	        = { 2, 2},
+	.audiomux       = { },
+	.no_msp34xx     = 1,
+	.needs_tvaudio  = 0,
+	.pll	        = PLL_28,
+	.tuner_type     = -1,
 },{
 	/* Miguel Angel Alvarez <maacruz@navegalia.com>
 	   new Easy TV BT878 version (model CPH061) 
 	   special thanks to Informatica Mieres for providing the card */
-	name:           "Askey CPH061/ BESTBUY Easy TV (bt878)",
-	video_inputs:	3,
-	audio_inputs:   2,
-	tuner:          0,
-	svhs:           2,
-	gpiomask:       0xFF,
-	muxsel:         { 2, 3, 1, 0},
-	audiomux:       { 1, 0, 4, 4, 9},
-	needs_tvaudio:  0,
-	pll:		PLL_28,
-	tuner_type:	TUNER_PHILIPS_PAL,
+	.name           = "Askey CPH061/ BESTBUY Easy TV (bt878)",
+	.video_inputs	= 3,
+	.audio_inputs   = 2,
+	.tuner          = 0,
+	.svhs           = 2,
+	.gpiomask       = 0xFF,
+	.muxsel         = { 2, 3, 1, 0},
+	.audiomux       = { 1, 0, 4, 4, 9},
+	.needs_tvaudio  = 0,
+	.pll		= PLL_28,
+	.tuner_type	= TUNER_PHILIPS_PAL,
 },{
 	/* Lukas Gebauer <geby@volny.cz> */
-	name:		"ATI TV-Wonder",
-	video_inputs:	3,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	0xf03f,
-	muxsel:		{ 2, 3, 1, 0 },
-	audiomux:	{ 0xbffe, 0, 0xbfff, 0, 0xbffe},
-	pll:		PLL_28,
-	tuner_type:	TUNER_TEMIC_4006FN5_MULTI_PAL,
+	.name		= "ATI TV-Wonder",
+	.video_inputs	= 3,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= 2,
+	.gpiomask	= 0xf03f,
+	.muxsel		= { 2, 3, 1, 0 },
+	.audiomux	= { 0xbffe, 0, 0xbfff, 0, 0xbffe},
+	.pll		= PLL_28,
+	.tuner_type	= TUNER_TEMIC_4006FN5_MULTI_PAL,
 },{
 
 /* ---- card 0x40 ---------------------------------- */
 	/* Lukas Gebauer <geby@volny.cz> */
-	name:		"ATI TV-Wonder VE",
-	video_inputs:	2,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		-1,
-	gpiomask:	1,
-	muxsel:		{ 2, 3, 0, 1},
-	audiomux:	{ 0, 0, 1, 0, 0},
-	no_msp34xx:	1,
-	pll:		PLL_28,
-	tuner_type:	TUNER_TEMIC_4006FN5_MULTI_PAL,
+	.name		= "ATI TV-Wonder VE",
+	.video_inputs	= 2,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= -1,
+	.gpiomask	= 1,
+	.muxsel		= { 2, 3, 0, 1},
+	.audiomux	= { 0, 0, 1, 0, 0},
+	.no_msp34xx	= 1,
+	.pll		= PLL_28,
+	.tuner_type	= TUNER_TEMIC_4006FN5_MULTI_PAL,
 },{
 	/* DeeJay <deejay@westel900.net (2000S) */
-	name:           "Lifeview FlyVideo 2000S LR90",
-	video_inputs:   3,
-	audio_inputs:   3,
-	tuner:          0,
-	svhs:           2,
-	gpiomask:	0x18e0,
-	muxsel:		{ 2, 3, 0, 1},
+	.name           = "Lifeview FlyVideo 2000S LR90",
+	.video_inputs   = 3,
+	.audio_inputs   = 3,
+	.tuner          = 0,
+	.svhs           = 2,
+	.gpiomask	= 0x18e0,
+	.muxsel		= { 2, 3, 0, 1},
 			/* Radio changed from 1e80 to 0x800 to make
 			   FlyVideo2000S in .hu happy (gm)*/
 			/* -dk-???: set mute=0x1800 for tda9874h daughterboard */
-	audiomux:	{ 0x0000,0x0800,0x1000,0x1000,0x1800, 0x1080 },
-	audio_hook:	fv2000s_audio,
-	no_msp34xx:	1,
-	no_tda9875:	1,
-	needs_tvaudio:  1,
-	pll:            PLL_28,
-	tuner_type:     5,
-},{
-	name:		"Terratec TValueRadio",
-	video_inputs:	3,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	0xffff00,
-	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 0x500, 0x500, 0x300, 0x900, 0x900},
-	needs_tvaudio:	1,
-	pll:		PLL_28,
-	tuner_type:	TUNER_PHILIPS_PAL,
-	has_radio:	1,
+	.audiomux	= { 0x0000,0x0800,0x1000,0x1000,0x1800, 0x1080 },
+	.audio_hook	= fv2000s_audio,
+	.no_msp34xx	= 1,
+	.no_tda9875	= 1,
+	.needs_tvaudio  = 1,
+	.pll            = PLL_28,
+	.tuner_type     = 5,
+},{
+	.name		= "Terratec TValueRadio",
+	.video_inputs	= 3,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= 2,
+	.gpiomask	= 0xffff00,
+	.muxsel		= { 2, 3, 1, 1},
+	.audiomux	= { 0x500, 0x500, 0x300, 0x900, 0x900},
+	.needs_tvaudio	= 1,
+	.pll		= PLL_28,
+	.tuner_type	= TUNER_PHILIPS_PAL,
+	.has_radio	= 1,
 },{
 	/* TANAKA Kei <peg00625@nifty.com> */
-	name:           "IODATA GV-BCTV4/PCI",
-	video_inputs:   3,
-	audio_inputs:   1,
-	tuner:          0,
-	svhs:           2,
-	gpiomask:       0x010f00,
-	muxsel:         {2, 3, 0, 0},
-	audiomux:       {0x10000, 0, 0x10000, 0, 0, 0},
-	no_msp34xx:     1,
-	pll:            PLL_28,
-	tuner_type:     TUNER_SHARP_2U5JF5540_NTSC,
-	audio_hook:     gvbctv3pci_audio,
+	.name           = "IODATA GV-BCTV4/PCI",
+	.video_inputs   = 3,
+	.audio_inputs   = 1,
+	.tuner          = 0,
+	.svhs           = 2,
+	.gpiomask       = 0x010f00,
+	.muxsel         = {2, 3, 0, 0},
+	.audiomux       = {0x10000, 0, 0x10000, 0, 0, 0},
+	.no_msp34xx     = 1,
+	.pll            = PLL_28,
+	.tuner_type     = TUNER_SHARP_2U5JF5540_NTSC,
+	.audio_hook     = gvbctv3pci_audio,
 },{
 
 /* ---- card 0x44 ---------------------------------- */
-        name:           "3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA)",
+        .name           = "3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA)",
 	// try "insmod msp3400 simple=0" if you have
 	// sound problems with this card.
-        video_inputs:   4,
-        audio_inputs:   1,
-        tuner:          0,
-        svhs:           -1,
-        gpiomask:       0x4f8a00,
+        .video_inputs   = 4,
+        .audio_inputs   = 1,
+        .tuner          = 0,
+        .svhs           = -1,
+        .gpiomask       = 0x4f8a00,
 	// 0x100000: 1=MSP enabled (0=disable again)
 	// 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC)
-        audiomux:       {0x947fff, 0x987fff,0x947fff,0x947fff, 0x947fff},
+        .audiomux       = {0x947fff, 0x987fff,0x947fff,0x947fff, 0x947fff},
 	// tvtuner, radio,   external,internal, mute,  stereo
 	/* tuner, Composit, SVid, Composit-on-Svid-adapter*/
-        muxsel:         { 2, 3 ,0 ,1},
-        tuner_type:     TUNER_MT2032,
-	pll:		PLL_28,
-	has_radio:	1,
+        .muxsel         = { 2, 3 ,0 ,1},
+        .tuner_type     = TUNER_MT2032,
+	.pll		= PLL_28,
+	.has_radio	= 1,
 },{
 	/* Philip Blundell <pb@nexus.co.uk> */
-	name:           "Active Imaging AIMMS",
-	video_inputs:   1,
-	audio_inputs:   0,
-	tuner:          -1,
-	tuner_type:     -1,
-	pll:            PLL_28,
-	muxsel:         { 2 },
+	.name           = "Active Imaging AIMMS",
+	.video_inputs   = 1,
+	.audio_inputs   = 0,
+	.tuner          = -1,
+	.tuner_type     = -1,
+	.pll            = PLL_28,
+	.muxsel         = { 2 },
 	gpiomask:       0
 },{
         /* Tomasz Pyra <hellfire@sedez.iq.pl> */
-        name:           "Prolink Pixelview PV-BT878P+ (Rev.4C)",
-        video_inputs:   3,
-        audio_inputs:   4,
-        tuner:          0,
-        svhs:           2,
-        gpiomask:       15,
-        muxsel:         { 2, 3, 1, 1},
-        audiomux:       { 0, 0, 11, 7, 13, 0},
-        needs_tvaudio:  1,
-        pll:            PLL_28,
-        tuner_type:     25,
-},{
-	name:		"Lifeview FlyVideo 98EZ (capture only) LR51",
-	video_inputs:	4,
-	audio_inputs:   0,
-	tuner:		-1,
-	svhs:		2,
-	muxsel:		{ 2, 3, 1, 1}, // AV1, AV2, SVHS, CVid adapter on SVHS
-	pll:		PLL_28,
-	no_msp34xx:	1,
+        .name           = "Prolink Pixelview PV-BT878P+ (Rev.4C,8E)",
+        .video_inputs   = 3,
+        .audio_inputs   = 4,
+        .tuner          = 0,
+        .svhs           = 2,
+        .gpiomask       = 15,
+        .muxsel         = { 2, 3, 1, 1},
+        .audiomux       = { 0, 0, 11, 7, 13, 0}, // TV and Radio with same GPIO !
+        .needs_tvaudio  = 1,
+        .pll            = PLL_28,
+        .tuner_type     = 25,
+	/* GPIO wiring:
+		GPIO0: U4.A0 (hef4052bt)
+		GPIO1: U4.A1
+		GPIO2: U4.A1 (second hef4052bt)
+		GPIO3: U4.nEN, U5.A0, A5.nEN
+		GPIO8-15: vrd866b ?
+	 */
+},{
+	.name		= "Lifeview FlyVideo 98EZ (capture only) LR51",
+	.video_inputs	= 4,
+	.audio_inputs   = 0,
+	.tuner		= -1,
+	.svhs		= 2,
+	.muxsel		= { 2, 3, 1, 1}, // AV1, AV2, SVHS, CVid adapter on SVHS
+	.pll		= PLL_28,
+	.no_msp34xx	= 1,
 },{
 
 /* ---- card 0x48 ---------------------------------- */
 	/* Dariusz Kowalewski <darekk@automex.pl> */
-	name:		"Prolink Pixelview PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM)",
-	video_inputs:	3,
-	audio_inputs:	1,
-	tuner:		0,
-	svhs:		2,
-	gpiomask:	0x3f,
-	muxsel:		{ 2, 3, 0, 1 },
-	audiomux:	{ 0x01, 0x00, 0x03, 0x03, 0x09, 0x02 },
-	needs_tvaudio:  1,
-	no_msp34xx:	1,
-	no_tda9875:	1,
-	pll:		PLL_28,
-	tuner_type:	-1,
-	audio_hook:	pvbt878p9b_audio,
-	has_radio:	1,
+	.name		= "Prolink Pixelview PV-BT878P+9B (PlayTV Pro rev.9B FM+NICAM)",
+	.video_inputs	= 4,
+	.audio_inputs	= 1,
+	.tuner		= 0,
+	.svhs		= 2,
+	.gpiomask	= 0x3f,
+	.muxsel		= { 2, 3, 1, 1 },
+	.audiomux	= { 0x01, 0x00, 0x03, 0x03, 0x09, 0x02 },
+	.needs_tvaudio  = 1,
+	.no_msp34xx	= 1,
+	.no_tda9875	= 1,
+	.pll		= PLL_28,
+	.tuner_type	= 5,
+	.audio_hook	= pvbt878p9b_audio, // Note: not all cards have stereo
+	.has_radio	= 1,  // Note: not all cards have radio
+	/* GPIO wiring:
+		GPIO0: A0 hef4052
+		GPIO1: A1 hef4052
+		GPIO3: nEN hef4052
+		GPIO8-15: vrd866b
+		GPIO20,22,23: R30,R29,R28
+	 */
 },{
 	/* Clay Kunz <ckunz@mail.arc.nasa.gov> */
 	/* you must jumper JP5 for the card to work */
-	name:           "Sensoray 311",
-	video_inputs:   5,
-	audio_inputs:   0,
-	tuner:          -1,
-	svhs:           4,
-	gpiomask:       0,
-	muxsel:         { 2, 3, 1, 0, 0},
-	audiomux:       { 0 },
-	needs_tvaudio:  0,
-	tuner_type:     -1,
+	.name           = "Sensoray 311",
+	.video_inputs   = 5,
+	.audio_inputs   = 0,
+	.tuner          = -1,
+	.svhs           = 4,
+	.gpiomask       = 0,
+	.muxsel         = { 2, 3, 1, 0, 0},
+	.audiomux       = { 0 },
+	.needs_tvaudio  = 0,
+	.tuner_type     = -1,
 },{
 	/* Miguel Freitas <miguel@cetuc.puc-rio.br> */
-	name:           "RemoteVision MX (RV605)",
-	video_inputs:   16,
-	audio_inputs:   0,
-	tuner:          -1,
-	svhs:           -1,
-	gpiomask:       0x00,
-	gpiomask2:      0x07ff,
-	muxsel:         { 0x33, 0x13, 0x23, 0x43, 0xf3, 0x73, 0xe3, 0x03,
+	.name           = "RemoteVision MX (RV605)",
+	.video_inputs   = 16,
+	.audio_inputs   = 0,
+	.tuner          = -1,
+	.svhs           = -1,
+	.gpiomask       = 0x00,
+	.gpiomask2      = 0x07ff,
+	.muxsel         = { 0x33, 0x13, 0x23, 0x43, 0xf3, 0x73, 0xe3, 0x03,
 			  0xd3, 0xb3, 0xc3, 0x63, 0x93, 0x53, 0x83, 0xa3 },
-	no_msp34xx:     1,
-	no_tda9875:     1,
-	tuner_type:     -1,
-	muxsel_hook:    rv605_muxsel,
+	.no_msp34xx     = 1,
+	.no_tda9875     = 1,
+	.tuner_type     = -1,
+	.muxsel_hook    = rv605_muxsel,
 },{
-        name:           "Powercolor MTV878/ MTV878R/ MTV878F",
-        video_inputs:   3,
+        .name           = "Powercolor MTV878/ MTV878R/ MTV878F",
+        .video_inputs   = 3,
         audio_inputs:   2, 
-	tuner:		0,
-        svhs:           2,
-        gpiomask:       0x1C800F,  // Bit0-2: Audio select, 8-12:remote control 14:remote valid 15:remote reset
-        muxsel:         { 2, 1, 1, },
-        audiomux:       { 0, 1, 2, 2, 4 },
-        needs_tvaudio:  0,
-        tuner_type:     TUNER_PHILIPS_PAL,
-	pll:		PLL_28,
-	has_radio:	1,
+	.tuner		= 0,
+        .svhs           = 2,
+        .gpiomask       = 0x1C800F,  // Bit0-2: Audio select, 8-12:remote control 14:remote valid 15:remote reset
+        .muxsel         = { 2, 1, 1, },
+        .audiomux       = { 0, 1, 2, 2, 4 },
+        .needs_tvaudio  = 0,
+        .tuner_type     = TUNER_PHILIPS_PAL,
+	.pll		= PLL_28,
+	.has_radio	= 1,
 },{
 
 /* ---- card 0x4c ---------------------------------- */
         /* Masaki Suzuki <masaki@btree.org> */
-        name:           "Canopus WinDVR PCI (COMPAQ Presario 3524JP, 5112JP)",
-        video_inputs:   3,
-        audio_inputs:   1,
-        tuner:          0,
-        svhs:           2,
-        gpiomask:       0x140007,
-        muxsel:         { 2, 3, 1, 1 },
-        audiomux:       { 0, 1, 2, 3, 4, 0 },
-        tuner_type:     TUNER_PHILIPS_NTSC,
-        audio_hook:     windvr_audio,
-},{
-        name:           "GrandTec Multi Capture Card (Bt878)",
-        video_inputs:   4,
-        audio_inputs:   0,
-        tuner:          -1,
-        svhs:           -1,
-        gpiomask:       0,
-        muxsel:         { 2, 3, 1, 0 },
-        audiomux:       { 0 },
-        needs_tvaudio:  0,
-        no_msp34xx:     1,
-        pll:            PLL_28,
-        tuner_type:     -1,
+        .name           = "Canopus WinDVR PCI (COMPAQ Presario 3524JP, 5112JP)",
+        .video_inputs   = 3,
+        .audio_inputs   = 1,
+        .tuner          = 0,
+        .svhs           = 2,
+        .gpiomask       = 0x140007,
+        .muxsel         = { 2, 3, 1, 1 },
+        .audiomux       = { 0, 1, 2, 3, 4, 0 },
+        .tuner_type     = TUNER_PHILIPS_NTSC,
+        .audio_hook     = windvr_audio,
+},{
+        .name           = "GrandTec Multi Capture Card (Bt878)",
+        .video_inputs   = 4,
+        .audio_inputs   = 0,
+        .tuner          = -1,
+        .svhs           = -1,
+        .gpiomask       = 0,
+        .muxsel         = { 2, 3, 1, 0 },
+        .audiomux       = { 0 },
+        .needs_tvaudio  = 0,
+        .no_msp34xx     = 1,
+        .pll            = PLL_28,
+        .tuner_type     = -1,
 },{
-        name:           "Jetway TV/Capture JW-TV878-FBK, Kworld KW-TV878RF",
-        video_inputs:   4,
+        .name           = "Jetway TV/Capture JW-TV878-FBK, Kworld KW-TV878RF",
+        .video_inputs   = 4,
         audio_inputs:   3, 
-        tuner:          0,
-        svhs:           2,
-        gpiomask:       7,
-        muxsel:         { 2, 3, 1, 1 },   // Tuner, SVid, SVHS, SVid to SVHS connector
-        audiomux:       { 0 ,0 ,4, 4,4,4},// Yes, this tuner uses the same audio output for TV and FM radio!
+        .tuner          = 0,
+        .svhs           = 2,
+        .gpiomask       = 7,
+        .muxsel         = { 2, 3, 1, 1 },   // Tuner, SVid, SVHS, SVid to SVHS connector
+        .audiomux       = { 0 ,0 ,4, 4,4,4},// Yes, this tuner uses the same audio output for TV and FM radio!
 					  // This card lacks external Audio In, so we mute it on Ext. & Int.
 					  // The PCB can take a sbx1637/sbx1673, wiring unknown.
 					  // This card lacks PCI subsystem ID, sigh.
 					  // audiomux=1: lower volume, 2+3: mute
 					  // btwincap uses 0x80000/0x80003
-        needs_tvaudio:  0,
-        no_msp34xx:     1,
-        pll:            PLL_28,
-        tuner_type:     5, // Samsung TCPA9095PC27A (BG+DK), philips compatible, w/FM, stereo and
+        .needs_tvaudio  = 0,
+        .no_msp34xx     = 1,
+        .pll            = PLL_28,
+        .tuner_type     = 5, // Samsung TCPA9095PC27A (BG+DK), philips compatible, w/FM, stereo and
 			   // radio signal strength indicators work fine.
-	has_radio:		1,
+	.has_radio		= 1,
 	/* GPIO Info:
 		GPIO0,1:   HEF4052 A0,A1
 		GPIO2:     HEF4052 nENABLE
 		GPIO3-7:   n.c.
-		GPIO8-13:  IRDC357 data0,5 (data6 n.c. ?) [chip not present on my card]
+		GPIO8-13:  IRDC357 data0-5 (data6 n.c. ?) [chip not present on my card]
 		GPIO14,15: ??
 		GPIO16-21: n.c.
 		GPIO22,23: ??
 		??       : mtu8b56ep microcontroller for IR (GPIO wiring unknown)*/
 },{
         /* Arthur Tetzlaff-Deas, DSP Design Ltd <software@dspdesign.com> */
-        name:           "DSP Design TCVIDEO",
-        video_inputs:   4,
-        svhs:           -1,
-        muxsel:         { 2, 3, 1, 0},
-        pll:            PLL_28,
-        tuner_type:     -1,
+        .name           = "DSP Design TCVIDEO",
+        .video_inputs   = 4,
+        .svhs           = -1,
+        .muxsel         = { 2, 3, 1, 0},
+        .pll            = PLL_28,
+        .tuner_type     = -1,
 },{
 
         /* ---- card 0x50 ---------------------------------- */
-	name:           "Hauppauge WinTV PVR",
-        video_inputs:   4,
-        audio_inputs:   1,
-        tuner:          0,
-        svhs:           2,
-        muxsel:         { 2, 0, 1, 1},
-        needs_tvaudio:  1,
-        pll:            PLL_28,
-        tuner_type:     -1,
+	.name           = "Hauppauge WinTV PVR",
+        .video_inputs   = 4,
+        .audio_inputs   = 1,
+        .tuner          = 0,
+        .svhs           = 2,
+        .muxsel         = { 2, 0, 1, 1},
+        .needs_tvaudio  = 1,
+        .pll            = PLL_28,
+        .tuner_type     = -1,
+
+	.gpiomask       = 7,
+	.audiomux       = {7},
+},{
+	.name           = "GV-BCTV5/PCI",
+	.video_inputs   = 3,
+	.audio_inputs   = 1,
+	.tuner          = 0,
+	.svhs           = 2,
+	.gpiomask       = 0x010f00,
+	.muxsel         = {2, 3, 1, 0},
+	.audiomux       = {0x10000, 0, 0x10000, 0, 0, 0},
+	.no_msp34xx     = 1,
+	.pll            = PLL_28,
+	.tuner_type     = TUNER_PHILIPS_NTSC_M,
+	.audio_hook     = gvbctv3pci_audio,
+},{
+	.name           = "Osprey 100/150 (878)", /* 0x1(2|3)-45C6-C1 */
+	.video_inputs   = 4,                  /* id-inputs-clock */
+	.audio_inputs   = 0,
+	.tuner          = -1,
+	.svhs           = 3,
+	.muxsel         = { 3, 2, 0, 1 },
+	.pll            = PLL_28,
+	.tuner_type     = -1,
+        .no_msp34xx     = 1,
+        .no_tda9875     = 1,
+        .no_tda7432     = 1,
+},{
+	.name           = "Osprey 100/150 (848)", /* 0x04-54C0-C1 & older boards */
+	.video_inputs   = 3,
+	.audio_inputs   = 0,
+	.tuner          = -1,
+	.svhs           = 2,
+	.muxsel         = { 2, 3, 1 },
+	.pll            = PLL_28,
+	.tuner_type     = -1,
+        .no_msp34xx     = 1,
+        .no_tda9875     = 1,
+        .no_tda7432     = 1,
+},{
+
+	/* ---- card 0x54 ---------------------------------- */
+	.name           = "Osprey 101 (848)", /* 0x05-40C0-C1 */
+	.video_inputs   = 2,
+	.audio_inputs   = 0,
+	.tuner          = -1,
+	.svhs           = 1,
+	.muxsel         = { 3, 1 },
+	.pll            = PLL_28,
+	.tuner_type     = -1,
+        .no_msp34xx     = 1,
+        .no_tda9875     = 1,
+        .no_tda7432     = 1,
+},{
+	.name           = "Osprey 101/151",       /* 0x1(4|5)-0004-C4 */
+	.video_inputs   = 1,
+	.audio_inputs   = 0,
+	.tuner          = -1,
+	.svhs           = -1,
+	.muxsel         = { 0 },
+	.pll            = PLL_28,
+	.tuner_type     = -1,
+        .no_msp34xx     = 1,
+        .no_tda9875     = 1,
+        .no_tda7432     = 1,
+},{
+	.name           = "Osprey 101/151 w/ svid",  /* 0x(16|17|20)-00C4-C1 */
+	.video_inputs   = 2,
+	.audio_inputs   = 0,
+	.tuner          = -1,
+	.svhs           = 1,
+	.muxsel         = { 0, 1 },
+	.pll            = PLL_28,
+	.tuner_type     = -1,
+        .no_msp34xx     = 1,
+        .no_tda9875     = 1,
+        .no_tda7432     = 1,
+},{
+	.name           = "Osprey 200/201/250/251",  /* 0x1(8|9|E|F)-0004-C4 */
+	.video_inputs   = 1,
+	.audio_inputs   = 1,
+	.tuner          = -1,
+	.svhs           = -1,
+	.muxsel         = { 0 },
+	.pll            = PLL_28,
+	.tuner_type     = -1,
+        .no_msp34xx     = 1,
+        .no_tda9875     = 1,
+        .no_tda7432     = 1,
+},{
+	
+	/* ---- card 0x58 ---------------------------------- */
+	.name           = "Osprey 200/250",   /* 0x1(A|B)-00C4-C1 */
+	.video_inputs   = 2,
+	.audio_inputs   = 1,
+	.tuner          = -1,
+	.svhs           = 1,
+	.muxsel         = { 0, 1 },
+	.pll            = PLL_28,
+	.tuner_type     = -1,
+        .no_msp34xx     = 1,
+        .no_tda9875     = 1,
+        .no_tda7432     = 1,
+},{
+	.name           = "Osprey 210/220",   /* 0x1(A|B)-04C0-C1 */
+	.video_inputs   = 2,
+	.audio_inputs   = 1,
+	.tuner          = -1,
+	.svhs           = 1,
+	.muxsel         = { 2, 3 },
+	.pll            = PLL_28,
+	.tuner_type     = -1,
+        .no_msp34xx     = 1,
+        .no_tda9875     = 1,
+        .no_tda7432     = 1,
+},{
+	.name           = "Osprey 500",   /* 500 */
+	.video_inputs   = 2,
+	.audio_inputs   = 1,
+	.tuner          = -1,
+	.svhs           = 1,
+	.muxsel         = { 2, 3 },
+	.pll            = PLL_28,
+	.tuner_type     = -1,
+        .no_msp34xx     = 1,
+        .no_tda9875     = 1,
+        .no_tda7432     = 1,
+},{
+       .name           = "Osprey 540",   /* 540 */
+       .video_inputs   = 4,
+       .audio_inputs   = 1,
+       .tuner          = -1,
+#if 0 /* TODO ... */
+       .svhs           = OSPREY540_SVID_ANALOG,
+       .muxsel         = {       [OSPREY540_COMP_ANALOG] = 2,
+                               [OSPREY540_SVID_ANALOG] = 3, },
+#endif
+       .pll            = PLL_28,
+       .tuner_type     = -1,
+       .no_msp34xx     = 1,
+       .no_tda9875     = 1,
+       .no_tda7432     = 1,
+#if 0 /* TODO ... */
+       .muxsel_hook    = osprey_540_muxsel,
+       .picture_hook   = osprey_540_set_picture,
+#endif
+},{
 
-	gpiomask:       7,
-	audiomux:       {7},
+	/* ---- card 0x5C ---------------------------------- */
+	.name           = "Osprey 2000",  /* 2000 */
+	.video_inputs   = 2,
+	.audio_inputs   = 1,
+	.tuner          = -1,
+	.svhs           = 1,
+	.muxsel         = { 2, 3 },
+	.pll            = PLL_28,
+	.tuner_type     = -1,
+        .no_msp34xx     = 1,
+        .no_tda9875     = 1,
+        .no_tda7432     = 1,      /* must avoid, conflicts with the bt860 */
+},{
+	/* M G Berberich <berberic@forwiss.uni-passau.de> */
+	.name           = "IDS Eagle",
+	.video_inputs   = 4,
+	.audio_inputs   = 0,
+	.tuner          = -1,
+	.tuner_type     = -1,
+	.svhs           = -1,
+	.gpiomask       = 0,
+	.muxsel         = { 0, 1, 2, 3 },
+	.muxsel_hook    = eagle_muxsel,
+	.no_msp34xx     = 1,
+	.no_tda9875     = 1,
+	.pll            = PLL_28,
+},{
+	.name           = "Pinnacle PCTV Sat",
+	.video_inputs   = 2,
+	.audio_inputs   = 0,
+	.svhs           = 1,
+	.tuner          = -1,
+	.tuner_type     = -1,
+	.no_msp34xx     = 1,
+	.no_tda9875     = 1,
+	.no_tda7432     = 1,   
+	.muxsel         = { 3, 0, 1, 2},
+	.needs_tvaudio  = 0, 
+	.pll            = PLL_28,
+},{
+        .name           = "Formac ProTV II",
+        .video_inputs   = 4,
+        .audio_inputs   = 1,
+        .tuner          = 0,
+        .svhs           = 3,
+        .gpiomask       = 2,
+	// TV, Comp1, Composite over SVID con, SVID
+        .muxsel         = { 2, 3, 1, 1},
+        .audiomux       = { 2, 2, 0, 0, 0 }, 
+        .pll            = PLL_28,
+	.has_radio      = 1,
+        .tuner_type     = TUNER_PHILIPS_PAL,
+      /* sound routing:
+           GPIO=0x00,0x01,0x03: mute (?)
+              0x02: both TV and radio (tuner: FM1216/I)
+         The card has onboard audio connectors labeled "cdrom" and "board",
+	 not soldered here, though unknown wiring.
+         Card lacks: external audio in, pci subsystem id.
+       */
+
+},{
+	/* ---- card 0x60 ---------------------------------- */
+	.name           = "MachTV",
+        .video_inputs   = 3,
+        .audio_inputs   = 1,
+        .tuner          = 0,
+        .svhs           = -1,
+        .gpiomask       = 7,
+        .muxsel         = { 2, 3, 1, 1},
+        .audiomux       = { 0, 1, 2, 3, 4},
+        .needs_tvaudio  = 1,
+        .tuner_type     = 5,
+	.pll            = 1,
+},{
+	.name           = "Euresys Picolo",
+	.video_inputs   = 3,
+	.audio_inputs   = 0,
+	.tuner          = -1,
+	.svhs           = 2,
+	.gpiomask       = 0,
+	.no_msp34xx     = 1,
+	.no_tda9875     = 1,
+	.no_tda7432     = 1,
+	.muxsel         = { 2, 0, 1},
+	.pll            = PLL_28,
+},{
+	/* Luc Van Hoeylandt <luc@e-magic.be> */
+	.name           = "ProVideo PV150", /* 0x4f */
+	.video_inputs   = 2,
+	.audio_inputs   = 0,
+	.tuner          = -1,
+	.svhs           = -1,
+	.gpiomask       = 0,
+	.muxsel         = { 2, 3 },
+	.audiomux       = { 0 },
+	.needs_tvaudio  = 0,
+	.no_msp34xx     = 1,
+	.pll            = PLL_28,
+	.tuner_type     = -1,
+},{
+	/* Hiroshi Takekawa <sian@big.or.jp> */
+	/* This card lacks subsystem ID */
+	.name           = "AD-TVK503", /* 0x63 */
+	.video_inputs   = 4,
+	.audio_inputs   = 1,
+	.tuner          = 0,
+	.svhs           = 2,
+	.gpiomask       = 0x001e8007,
+	.muxsel         = { 2, 3, 1, 0 },
+                         /* Tuner,      Radio, external, internal, mute, stereo */
+	.audiomux       = { 0x00060000, 0x000, 0x000000, 0x000000, 0x07, 0x0000 }, /* Sub: 0x00180000 */
+	.needs_tvaudio  = 0,
+	.no_msp34xx     = 1,
+	.pll            = PLL_28,
+	.tuner_type     = 2,
+	.audio_hook	= adtvk503_audio,
 }};
 
-const int bttv_num_tvcards = (sizeof(bttv_tvcards)/sizeof(struct tvcard));
+const unsigned int bttv_num_tvcards =
+	(sizeof(bttv_tvcards)/sizeof(bttv_tvcards[0]));
 
 /* ----------------------------------------------------------------------- */
 
@@ -1312,10 +1672,10 @@
 			printk(KERN_DEBUG "please mail id, board name and "
 			       "the correct card= insmod option to kraxel@bytesex.org\n");
 		}
-	}
+	} 
 
 	/* let the user override the autodetected type */
-	if (card[btv->nr] >= 0 && card[btv->nr] < bttv_num_tvcards)
+	if (card[btv->nr] < bttv_num_tvcards)
 		btv->type=card[btv->nr];
 	
 	/* print which card config we are using */
@@ -1325,14 +1685,14 @@
 		bttv_tvcards[btv->type].name);
 	printk(KERN_INFO "bttv%d: using: %s [card=%d,%s]\n",btv->nr,
 	       btv->video_dev.name,btv->type,
-	       (card[btv->nr] >= 0 && card[btv->nr] < bttv_num_tvcards) ?
-	       "insmod option" : "autodetected");
+	       card[btv->nr] < bttv_num_tvcards
+	       ? "insmod option" : "autodetected");
 
 	/* overwrite gpio stuff ?? */
-	if (-1 == audioall && -1 == audiomux[0])
+	if (UNSET == audioall && UNSET == audiomux[0])
 		return;
 
-	if (-1 != audiomux[0]) {
+	if (UNSET != audiomux[0]) {
 		gpiobits = 0;
 		for (i = 0; i < 5; i++) {
 			bttv_tvcards[btv->type].audiomux[i] = audiomux[i];
@@ -1344,7 +1704,7 @@
 			bttv_tvcards[btv->type].audiomux[i] = audioall;
 		}
 	}
-	bttv_tvcards[btv->type].gpiomask = (-1 != gpiomask) ? gpiomask : gpiobits;
+	bttv_tvcards[btv->type].gpiomask = (UNSET != gpiomask) ? gpiomask : gpiobits;
 	printk(KERN_INFO "bttv%d: gpio config override: mask=0x%x, mux=",
 	       btv->nr,bttv_tvcards[btv->type].gpiomask);
 	for (i = 0; i < 5; i++) {
@@ -1357,6 +1717,25 @@
  * (most) board specific initialisations goes here
  */
 
+/* Some Modular Technology cards have an eeprom, but no subsystem ID */
+void identify_by_eeprom(struct bttv *btv, unsigned char eeprom_data[256])
+{
+	int type = -1;
+	
+	if (0 == strncmp(eeprom_data,"GET.MM20xPCTV",13))
+		type = BTTV_MODTEC_205;
+	else if (0 == strncmp(eeprom_data+20,"Picolo",7))
+		type = BTTV_EURESYS_PICOLO;
+	else if (eeprom_data[0] == 0x84 && eeprom_data[2]== 0)
+                type = BTTV_HAUPPAUGE; /* old bt848 */
+
+	if (-1 != type) {
+		btv->type = type;
+		printk("bttv%d: detected by eeprom: %s [card=%d]\n",
+		       btv->nr, bttv_tvcards[btv->type].name, btv->type);
+	}
+}
+
 static void flyvideo_gpio(struct bttv *btv)
 { 
 	int gpio,outbits,has_remote,has_radio,is_capture_only,is_lr90,has_tda9820_tda9821;
@@ -1380,7 +1759,7 @@
 
 	ttype=(gpio&0x0f0000)>>16;
 	switch(ttype) {
-	case 0x0: tuner=4; // None
+	case 0x0: tuner=2; // NTSC, e.g. TPI8NSR11P
 		break;
         case 0x2: tuner=39;// LG NTSC (newer TAPC series) TAPC-H701P
 		break;
@@ -1403,6 +1782,9 @@
 	is_lr90             = !(gpio & 0x002000); // else LR26/LR50 (LR38/LR51 f. capture only)
         //		        gpio & 0x001000 // output bit for audio routing
 
+	if(is_capture_only) 
+		tuner=4; // No tuner present 
+
 	printk(KERN_INFO "bttv%d: FlyVideo Radio=%s RemoteControl=%s Tuner=%d gpio=0x%06x\n", 
 	       btv->nr, has_radio? "yes":"no ", has_remote? "yes":"no ", tuner, gpio); 
 	printk(KERN_INFO "bttv%d: FlyVideo  LR90=%s tda9821/tda9820=%s capture_only=%s\n",
@@ -1415,7 +1797,7 @@
 
 	// LR90 Audio Routing is done by 2 hef4052, so Audio_Mask has 4 bits: 0x001c80
         // LR26/LR50 only has 1 hef4052, Audio_Mask 0x000c00
-	// Audio options: from tuner, from tda9821/tda9821(mono,stereo.sap), from tda9874, ext., mute
+	// Audio options: from tuner, from tda9821/tda9821(mono,stereo,sap), from tda9874, ext., mute
 	if(has_tda9820_tda9821) btv->audio_hook = lt9415_audio;
 	//todo: if(has_tda9874) btv->audio_hook = fv2000s_audio;
 }
@@ -1423,41 +1805,134 @@
 int miro_tunermap[] = { 0,6,2,3,   4,5,6,0,  3,0,4,5,  5,2,16,1,
 			14,2,17,1, 4,1,4,3,  1,2,16,1, 4,4,4,4 };
 int miro_fmtuner[]  = { 0,0,0,0,   0,0,0,0,  0,0,0,0,  0,0,0,1,
-			1,1,1,1,   1,1,1,0,  0,0,0,0,  0,0,0,0 };
+			1,1,1,1,   1,1,1,0,  0,0,0,0,  0,1,0,0 };
 
 static void miro_pinnacle_gpio(struct bttv *btv)
 {
-	int id,msp;
-	
-	id  = ((btread(BT848_GPIO_DATA)>>10) & 31) -1;
-	msp = bttv_I2CRead(btv, I2C_MSP3400, "MSP34xx");
-	btv->tuner_type = miro_tunermap[id];
-	if (0 == (btread(BT848_GPIO_DATA) & 0x20)) {
-		btv->has_radio = 1;
-		if (!miro_fmtuner[id]) {
-			btv->has_matchbox = 1;
-			btv->mbox_we    = (1<<6);
-			btv->mbox_most  = (1<<7);
-			btv->mbox_clk   = (1<<8);
-			btv->mbox_data  = (1<<9);
-			btv->mbox_mask  = (1<<6)|(1<<7)|(1<<8)|(1<<9);
+	int id,msp,gpio;
+	char *info;
+
+	btwrite(0,BT848_GPIO_OUT_EN);
+        gpio = btread(BT848_GPIO_DATA);
+	id   = ((gpio>>10) & 63) -1;
+	msp  = bttv_I2CRead(btv, I2C_MSP3400, "MSP34xx");
+	if (id < 32) {
+		btv->tuner_type = miro_tunermap[id];
+		if (0 == (gpio & 0x20)) {
+			btv->has_radio = 1;
+			if (!miro_fmtuner[id]) {
+				btv->has_matchbox = 1;
+				btv->mbox_we    = (1<<6);
+				btv->mbox_most  = (1<<7);
+				btv->mbox_clk   = (1<<8);
+				btv->mbox_data  = (1<<9);
+				btv->mbox_mask  = (1<<6)|(1<<7)|(1<<8)|(1<<9);
+			}
+		} else {
+			btv->has_radio = 0;
 		}
+		if (-1 != msp) {
+			if (btv->type == BTTV_MIRO)
+				btv->type = BTTV_MIROPRO;
+			if (btv->type == BTTV_PINNACLE)
+				btv->type = BTTV_PINNACLEPRO;
+		}
+		printk(KERN_INFO
+		       "bttv%d: miro: id=%d tuner=%d radio=%s stereo=%s\n",
+		       btv->nr, id+1, btv->tuner_type,
+		       !btv->has_radio ? "no" :
+		       (btv->has_matchbox ? "matchbox" : "fmtuner"),
+		       (-1 == msp) ? "no" : "yes");
 	} else {
+		/* new cards with microtune tuner */
+		id = 63 - id;
 		btv->has_radio = 0;
-	}
-	if (-1 != msp) {
-		if (btv->type == BTTV_MIRO)
-			btv->type = BTTV_MIROPRO;
-		if (btv->type == BTTV_PINNACLE)
+		switch (id) {
+		case 1:
+			info = "PAL / mono";
+			break;
+		case 2:
+			info = "PAL+SECAM / stereo";
+			btv->has_radio = 1;
+			break;
+		case 3:
+			info = "NTSC / stereo";
+			btv->has_radio = 1;
+			break;
+		case 4:
+			info = "PAL+SECAM / mono";
+			break;
+		case 5:
+			info = "NTSC / mono";
+			break;
+		case 6:
+			info = "NTSC / stereo";
+			break;
+		default:
+			info = "oops: unknown card";
+			break;
+		}
+		if (-1 != msp)
 			btv->type = BTTV_PINNACLEPRO;
+		printk(KERN_INFO
+		       "bttv%d: pinnacle/mt: id=%d info=\"%s\" radio=%s\n",
+		       btv->nr, id, info, btv->has_radio ? "yes" : "no");
+		btv->tuner_type  = 33;
+		btv->pinnacle_id = id;
 	}
-	printk(KERN_INFO "bttv%d: miro: id=%d tuner=%d radio=%s stereo=%s\n",
-	       btv->nr, id+1, btv->tuner_type,
-	       !btv->has_radio ? "no" :
-	       (btv->has_matchbox ? "matchbox" : "fmtuner"),
-	       (-1 == msp) ? "no" : "yes");
 }
 
+/* GPIO21   L: Buffer aktiv, H: Buffer inaktiv */
+#define LM1882_SYNC_DRIVE     0x200000L
+
+static void init_ids_eagle(struct bttv *btv)
+{
+	btwrite(0xFFFF37, BT848_GPIO_OUT_EN);
+	btwrite(0x000000, BT848_GPIO_REG_INP);
+	
+	btwrite(0x200020, BT848_GPIO_DATA);
+	
+	/* flash strobe inverter ?! */
+	btwrite(0x200024, BT848_GPIO_DATA);
+	
+	/* switch sync drive off */
+	btor(LM1882_SYNC_DRIVE, BT848_GPIO_DATA);
+	
+	/* set BT848 muxel to 2 */
+	btaor((2)<<5, ~(2<<5), BT848_IFORM);
+}
+
+/* Muxsel helper for the IDS Eagle.
+ * the eagles does not use the standard muxsel-bits but
+ * has its own multiplexer */
+static void eagle_muxsel(struct bttv *btv, unsigned int input)
+{
+	btaor((2)<<5, ~(3<<5), BT848_IFORM);
+	btaor((bttv_tvcards[btv->type].muxsel[input&7]&3),
+	      ~3, BT848_GPIO_DATA);
+
+#if 0
+       /* svhs */
+       /* wake chroma ADC */
+       btand(~BT848_ADC_C_SLEEP, BT848_ADC);
+       /* set to YC video */
+       btor(BT848_CONTROL_COMP, BT848_E_CONTROL);
+       btor(BT848_CONTROL_COMP, BT848_O_CONTROL);
+#else
+       /* composite */
+       /* set chroma ADC to sleep */
+       btor(BT848_ADC_C_SLEEP, BT848_ADC);
+       /* set to composite video */
+       btand(~BT848_CONTROL_COMP, BT848_E_CONTROL);
+       btand(~BT848_CONTROL_COMP, BT848_O_CONTROL);
+#endif
+
+       /* switch sync drive off */
+       btor(LM1882_SYNC_DRIVE, BT848_GPIO_DATA);
+}
+
+/* ----------------------------------------------------------------------- */
+
 /* initialization part one -- before registering i2c bus */
 void __devinit bttv_init_card1(struct bttv *btv)
 {
@@ -1469,6 +1944,9 @@
 	case BTTV_VOODOOTV_FM:
                 boot_msp34xx(btv,20);
 		break;
+	case BTTV_AVERMEDIA98:
+		boot_msp34xx(btv,11);
+		break;
 	case BTTV_HAUPPAUGEPVR:
 		pvr_boot(btv);
 		break;
@@ -1480,6 +1958,11 @@
 {
         btv->tuner_type = -1;
 
+	if (BTTV_UNKNOWN == btv->type) {
+		bttv_readee(btv,eeprom_data,0xa0);
+		identify_by_eeprom(btv,eeprom_data);
+	}
+
 	switch (btv->type) {
 	case BTTV_MIRO:
 	case BTTV_MIROPRO:
@@ -1525,12 +2008,45 @@
 		btv->mbox_data    = 0x10;
 		btv->mbox_mask    = 0x38;
 		break;
+	case BTTV_VOBIS_BOOSTAR:
+	case BTTV_TERRATV:
+		terratec_active_radio_upgrade(btv);
+		break;
 	case BTTV_MAGICTVIEW061:
-		if (btv->cardid == 0x4002144f) {
+		if (btv->cardid == 0x3002144f) {
 			btv->has_radio=1;
 			printk("bttv%d: radio detected by subsystem id (CPH05x)\n",btv->nr);
 		}
 		break;
+       case BTTV_STB2:
+                if (btv->cardid == 0x3060121a) {
+			/* Fix up entry for 3DFX VoodooTV 100,
+			   which is an OEM STB card variant. */
+			btv->has_radio=0;
+			btv->tuner_type=TUNER_TEMIC_NTSC;
+		}
+		break;
+	case BTTV_OSPREY1x0:
+	case BTTV_OSPREY1x0_848:
+	case BTTV_OSPREY101_848:
+	case BTTV_OSPREY1x1:
+	case BTTV_OSPREY1x1_SVID:
+	case BTTV_OSPREY2xx:
+	case BTTV_OSPREY2x0_SVID:
+	case BTTV_OSPREY2x0:
+	case BTTV_OSPREY500:
+	case BTTV_OSPREY540:
+	case BTTV_OSPREY2000:
+		bttv_readee(btv,eeprom_data,0xa0);
+                osprey_eeprom(btv);
+		break;
+	case BTTV_IDS_EAGLE:
+		init_ids_eagle(btv);
+		break;
+	case BTTV_MODTEC_205:
+		bttv_readee(btv,eeprom_data,0xa0);
+		modtec_eeprom(btv);
+		break;
 	}
 
 	/* pll configuration */
@@ -1565,23 +2081,33 @@
                         break;
                 }
         }
+	btv->pll.pll_current = -1;
 
 	/* tuner configuration (from card list / autodetect / insmod option) */
- 	if (-1 != bttv_tvcards[btv->type].tuner_type)
-		if( -1 == btv->tuner_type) 
+ 	if (UNSET != bttv_tvcards[btv->type].tuner_type)
+		if(UNSET == btv->tuner_type) 
                 	btv->tuner_type = bttv_tvcards[btv->type].tuner_type;
-	if (-1 != tuner[btv->nr])
+	if (UNSET != tuner[btv->nr])
 		btv->tuner_type = tuner[btv->nr];
-	if (btv->tuner_type != -1)
-		bttv_call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type);
 	printk("bttv%d: using tuner=%d\n",btv->nr,btv->tuner_type);
+	if (btv->pinnacle_id != UNSET)
+		bttv_call_i2c_clients(btv,AUDC_CONFIG_PINNACLE,
+				      &btv->pinnacle_id);
+	if (btv->tuner_type != UNSET)
+		bttv_call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type);
 
 	if (bttv_tvcards[btv->type].has_radio)
 		btv->has_radio=1;
-
 	if (bttv_tvcards[btv->type].audio_hook)
 		btv->audio_hook=bttv_tvcards[btv->type].audio_hook;
 
+	if (bttv_tvcards[btv->type].digital_mode == DIGITAL_MODE_CAMERA) {
+		/* detect Bt832 chip for quartzsight digital camera */
+		if ((bttv_I2CRead(btv, I2C_BT832_ALT1, "Bt832") >=0) ||
+		    (bttv_I2CRead(btv, I2C_BT832_ALT2, "Bt832") >=0))
+			boot_bt832(btv);
+	}
+
 	/* try to detect audio/fader chips */
 	if (!bttv_tvcards[btv->type].no_msp34xx &&
 	    bttv_I2CRead(btv, I2C_MSP3400, "MSP34xx") >=0) {
@@ -1589,13 +2115,20 @@
 			request_module("msp3400");
 	}
 
+	if (bttv_tvcards[btv->type].msp34xx_alt &&
+	    bttv_I2CRead(btv, I2C_MSP3400_ALT, "MSP34xx (alternate address)") >=0) {
+		if (autoload)
+			request_module("msp3400");
+	}
+
 	if (!bttv_tvcards[btv->type].no_tda9875 &&
 	    bttv_I2CRead(btv, I2C_TDA9875, "TDA9875") >=0) {
 		if (autoload)
 			request_module("tda9875");
 	}
 
-	if (bttv_I2CRead(btv, I2C_TDA7432, "TDA7432") >=0) {
+	if (!bttv_tvcards[btv->type].no_tda7432 && 
+	    bttv_I2CRead(btv, I2C_TDA7432, "TDA7432") >=0) {
 		if (autoload)
 			request_module("tda7432");
 	}
@@ -1605,7 +2138,12 @@
 			request_module("tvaudio");
 	}
 
-	if (bttv_tvcards[btv->type].tuner != -1) {
+	/* tuner modules */
+	if (btv->pinnacle_id != UNSET) {
+		if (autoload)
+			request_module("tda9887");
+	}
+	if (btv->tuner_type != UNSET) {
 		if (autoload)
 			request_module("tuner");
 	}
@@ -1668,16 +2206,28 @@
         { TUNER_TEMIC_4046FM5,     "Temic 4046FM5" },
 	{ TUNER_TEMIC_4009FN5_MULTI_PAL_FM, "Temic 4009FN5" },
 	{ TUNER_ABSENT,        "Philips TD1536D_FH_44"},
-	{ TUNER_LG_NTSC_FM,    "LG TP18NSR01F"},
-	{ TUNER_LG_PAL_FM,     "LG TP18PSB01D"},
-	{ TUNER_LG_PAL,        "LG TP18PSB11D"},	
+	{ TUNER_LG_NTSC_FM,    "LG TPI8NSR01F"},
+	{ TUNER_LG_PAL_FM,     "LG TPI8PSB01D"},
+	{ TUNER_LG_PAL,        "LG TPI8PSB11D"},	
 	{ TUNER_LG_PAL_I_FM,   "LG TAPC-I001D"},
 	{ TUNER_LG_PAL_I,      "LG TAPC-I701D"}
 };
 
+static void modtec_eeprom(struct bttv *btv)
+{
+	if( strncmp(&(eeprom_data[0x1e]),"Temic 4066 FY5",14) ==0) {
+		btv->tuner_type=TUNER_TEMIC_4066FY5_PAL_I;
+		printk("bttv Modtec: Tuner autodetected %s\n",
+		       &eeprom_data[0x1e]);
+	} else {
+		printk("bttv Modtec: Unknown TunerString:%s\n",
+		       &eeprom_data[0x1e]);
+	}
+}
+
 static void __devinit hauppauge_eeprom(struct bttv *btv)
 {
-	int blk2,tuner,radio,model;
+	unsigned int blk2,tuner,radio,model;
 
 	if (eeprom_data[0] != 0x84 || eeprom_data[2] != 0)
 		printk(KERN_WARNING "bttv%d: Hauppauge eeprom: invalid\n",
@@ -1703,6 +2253,37 @@
 		       btv->tuner_type, radio ? "yes" : "no");
 }
 
+static int terratec_active_radio_upgrade(struct bttv *btv)
+{
+	int freq;
+
+	btv->has_radio    = 1;
+	btv->has_matchbox = 1;
+	btv->mbox_we      = 0x10;
+	btv->mbox_most    = 0x20;
+	btv->mbox_clk     = 0x08;
+	btv->mbox_data    = 0x04;
+	btv->mbox_mask    = 0x3c;
+
+	btv->mbox_iow     = 1 <<  8;
+	btv->mbox_ior     = 1 <<  9;
+	btv->mbox_csel    = 1 << 10;
+
+	freq=88000/62.5;
+	tea5757_write(btv, 5 * freq + 0x358); // write 0x1ed8
+	if (0x1ed8 == tea5757_read(btv)) {
+		printk("bttv%d: Terratec Active Radio Upgrade found.\n",
+		       btv->nr);
+		btv->has_radio    = 1;
+		btv->has_matchbox = 1;
+	} else {
+		btv->has_radio    = 0;
+		btv->has_matchbox = 0;
+	}
+	return 0;
+}	
+
+
 /* ----------------------------------------------------------------------- */
 
 /*
@@ -1784,11 +2365,115 @@
 }
 
 /* ----------------------------------------------------------------------- */
+/* some osprey specific stuff                                              */
+
+static void __devinit osprey_eeprom(struct bttv *btv)
+{
+       int i = 0;
+       unsigned char *ee = eeprom_data;
+       unsigned long serial = 0;
+    
+       if (btv->type == 0) {
+               /* this might be an antique... check for MMAC label in eeprom */
+               if ((ee[0]=='M') && (ee[1]=='M') && (ee[2]=='A') && (ee[3]=='C')) {
+                       unsigned char checksum = 0;
+                       for (i =0; i<21; i++)
+			       checksum += ee[i];
+                       if (checksum != ee[21])
+			       return;
+		       btv->type = BTTV_OSPREY1x0_848;
+		       for (i = 12; i < 21; i++)
+			       serial *= 10, serial += ee[i] - '0';
+               }
+       } else {
+	       unsigned short type;
+               int offset = 4*16;
+        
+               for(; offset < 8*16; offset += 16) {
+                       unsigned short checksum = 0;
+                       /* verify the checksum */
+                       for(i = 0; i<14; i++) checksum += ee[i+offset];
+                               checksum = ~checksum;  /* no idea why */
+                               if ((((checksum>>8)&0x0FF) == ee[offset+14]) &&
+                                   ((checksum & 0x0FF) == ee[offset+15])) {
+                               break;
+                       }
+               }
+        
+               if (offset >= 8*16)
+		       return;
+
+	       /* found a valid descriptor */
+	       type = (ee[offset+4]<<8) | (ee[offset+5]);
+	       
+	       switch(type) {
+
+	       /* 848 based */
+	       case 0x0004:
+		       btv->type = BTTV_OSPREY1x0_848;
+		       break;
+	       case 0x0005:
+		       btv->type = BTTV_OSPREY101_848;
+		       break;
+		       
+               /* 878 based */
+	       case 0x0012:
+	       case 0x0013:
+		       btv->type = BTTV_OSPREY1x0;
+		       break;
+	       case 0x0014:
+	       case 0x0015:
+		       btv->type = BTTV_OSPREY1x1;
+		       break;
+	       case 0x0016:
+	       case 0x0017:
+	       case 0x0020:
+		       btv->type = BTTV_OSPREY1x1_SVID;
+		       break;
+	       case 0x0018:
+	       case 0x0019:
+	       case 0x001E:
+	       case 0x001F:
+		       btv->type = BTTV_OSPREY2xx;
+		       break;
+	       case 0x001A:
+	       case 0x001B:
+		       btv->type = BTTV_OSPREY2x0_SVID;
+		       break;
+	       case 0x0040:
+		       btv->type = BTTV_OSPREY500;
+		       break;
+	       case 0x0050:
+	       case 0x0056:
+		       btv->type = BTTV_OSPREY540;
+		       /* bttv_osprey_540_init(btv); */
+		       break;
+	       case 0x0060:
+	       case 0x0070:
+		       btv->type = BTTV_OSPREY2x0;
+		       //enable output on select control lines
+		       btwrite(0x000303, BT848_GPIO_OUT_EN);
+		       break;
+	       default:
+		       /* unknown...leave generic, but get serial # */
+		       break;
+	       }
+	       serial =  (ee[offset+6] << 24)
+		       | (ee[offset+7] << 16)
+		       | (ee[offset+8] <<  8)
+		       | (ee[offset+9]);
+       }
+       
+       printk(KERN_INFO "bttv%d: osprey eeprom: card=%d name=%s serial=%ld\n",
+	      btv->nr, btv->type, bttv_tvcards[btv->type].name,serial);
+}	
+
+/* ----------------------------------------------------------------------- */
 /* AVermedia specific stuff, from  bktr_card.c                             */
 
 int tuner_0_table[] = {
-        TUNER_PHILIPS_NTSC,  TUNER_PHILIPS_PAL,
-        TUNER_PHILIPS_PAL,   TUNER_PHILIPS_PAL,
+        TUNER_PHILIPS_NTSC,  TUNER_PHILIPS_PAL /* PAL-BG*/,
+        TUNER_PHILIPS_PAL,   TUNER_PHILIPS_PAL /* PAL-I*/,
         TUNER_PHILIPS_PAL,   TUNER_PHILIPS_PAL,
         TUNER_PHILIPS_SECAM, TUNER_PHILIPS_SECAM,
         TUNER_PHILIPS_SECAM, TUNER_PHILIPS_PAL};
@@ -1879,6 +2564,41 @@
 		       "init [%d]\n", btv->nr, pin);
 }
 
+static void __devinit boot_bt832(struct bttv *btv)
+{
+	int outbits,databits,resetbit=0;
+
+	switch (btv->type) {
+	case BTTV_PXELVWPLTVPAK:
+		resetbit = 0x400000;
+		break;
+	case BTTV_MODTEC_205:
+		resetbit = 1<<9;
+		break;
+	default:
+		BUG();
+	}
+
+	request_module("bt832");
+	bttv_call_i2c_clients(btv, BT832_HEXDUMP, NULL);
+
+	printk("bttv%d: Reset Bt832 [line=0x%x]\n",btv->nr,resetbit);
+	btwrite(0, BT848_GPIO_DATA);
+	outbits = btread(BT848_GPIO_OUT_EN);
+	databits= btread(BT848_GPIO_DATA);
+	btwrite(resetbit, BT848_GPIO_OUT_EN);
+	udelay(5);
+	btwrite(resetbit, BT848_GPIO_DATA);
+	udelay(5);
+	btwrite(0, BT848_GPIO_DATA);
+	udelay(5);
+	btwrite(outbits, BT848_GPIO_OUT_EN);
+	btwrite(databits, BT848_GPIO_DATA);
+
+	// bt832 on pixelview changes from i2c 0x8a to 0x88 after
+	// being reset as above. So we must follow by this:
+	bttv_call_i2c_clients(btv, BT832_REATTACH, NULL);
+}
 
 /* ----------------------------------------------------------------------- */
 /*  Imagenation L-Model PXC200 Framegrabber */
@@ -1891,7 +2611,8 @@
 	static int vals[] __devinitdata = { 0x08, 0x09, 0x0a, 0x0b, 0x0d, 0x0d,
 					    0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
 					    0x00 };
-	int i,tmp;
+	unsigned int i;
+	int tmp;
 
 	/* Initialise GPIO-connevted stuff */
 	btwrite(1<<13,BT848_GPIO_OUT_EN); /* Reset pin only */
@@ -1941,17 +2662,55 @@
  * Brutally hacked by Dan Sheridan <dan.sheridan@contact.org.uk> djs52 8/3/00
  */
 
-#if 0
-/* bus bits on the GPIO port */
-#define TEA_WE			6
-#define TEA_DATA		9
-#define TEA_CLK			8
-#define TEA_MOST		7
-#endif
+void bus_low(struct bttv *btv, int bit)
+{
+	if (btv->mbox_ior) {
+		btor(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
+		     BT848_GPIO_DATA);
+		udelay(5);
+	}
+
+	btand(~(bit), BT848_GPIO_DATA);
+	udelay(5);
+
+	if (btv->mbox_ior) {
+		btand(~(btv->mbox_iow | btv->mbox_csel),
+		      BT848_GPIO_DATA);
+		udelay(5);
+	}
+}
+
+void bus_high(struct bttv *btv, int bit)
+{
+	if (btv->mbox_ior) {
+		btor(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
+		     BT848_GPIO_DATA);
+		udelay(5);
+	}
+
+	btor((bit), BT848_GPIO_DATA);
+	udelay(5);
+
+	if (btv->mbox_ior) {
+		btand(~(btv->mbox_iow | btv->mbox_csel),
+		      BT848_GPIO_DATA);
+		udelay(5);
+	}
+}
 
-#define BUS_LOW(bit) 	btand(~(bit), BT848_GPIO_DATA)
-#define BUS_HIGH(bit)	btor((bit), BT848_GPIO_DATA)
-#define BUS_IN(bit)	(btread(BT848_GPIO_DATA) & (bit))
+int bus_in(struct bttv *btv, int bit)
+{
+	if (btv->mbox_ior) {
+		btor(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
+		     BT848_GPIO_DATA);
+		udelay(5);
+
+		btand(~(btv->mbox_ior | btv->mbox_csel),
+		      BT848_GPIO_DATA);
+		udelay(5);
+	}
+	return btread(BT848_GPIO_DATA) & (bit);
+}
 
 /* TEA5757 register bits */
 #define TEA_FREQ		0:14
@@ -1990,34 +2749,41 @@
 	/* better safe than sorry */
 	btaor((btv->mbox_clk | btv->mbox_we),
 	      ~btv->mbox_mask, BT848_GPIO_OUT_EN);
+
+	if (btv->mbox_ior) {
+		btor(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
+		     BT848_GPIO_DATA);
+		udelay(5);
+	}
+
 	if (bttv_gpio)
 		bttv_gpio_tracking(btv,"tea5757 read");
 	
-	BUS_LOW(btv->mbox_we);
-	BUS_LOW(btv->mbox_clk);
+	bus_low(btv,btv->mbox_we);
+	bus_low(btv,btv->mbox_clk);
 	
 	udelay(10);
-	for(timeout = jiffies + 10 * HZ;
-	    BUS_IN(btv->mbox_data) && time_before(jiffies, timeout);
-	    schedule());	/* 10 s */
-	if (BUS_IN(btv->mbox_data)) {
+	timeout= jiffies + HZ;
+
+	// wait for DATA line to go low; error if it doesn't
+	while (bus_in(btv,btv->mbox_data) && time_before(jiffies, timeout))
+		schedule();
+	if (bus_in(btv,btv->mbox_data)) {
 		printk(KERN_WARNING "bttv%d: tea5757: read timeout\n",btv->nr);
 		return -1;
 	}
-	for(timeout = jiffies + HZ/5;
-	    BUS_IN(btv->mbox_data) == 1 && time_before(jiffies, timeout);
-	    schedule());	/* 0.2 s */
+
 	dprintk("bttv%d: tea5757:",btv->nr);
 	for(i = 0; i < 24; i++)
 	{
 		udelay(5);
-		BUS_HIGH(btv->mbox_clk);
+		bus_high(btv,btv->mbox_clk);
 		udelay(5);
-		dprintk("%c",(BUS_IN(btv->mbox_most) == 0)?'T':'-');
-		BUS_LOW(btv->mbox_clk);
+		dprintk("%c",(bus_in(btv,btv->mbox_most) == 0)?'T':'-');
+		bus_low(btv,btv->mbox_clk);
 		value <<= 1;
-		value |= (BUS_IN(btv->mbox_data) == 0)?0:1;  /* MSB first */
-		dprintk("%c", (BUS_IN(btv->mbox_most) == 0)?'S':'M');
+		value |= (bus_in(btv,btv->mbox_data) == 0)?0:1;  /* MSB first */
+		dprintk("%c", (bus_in(btv,btv->mbox_most) == 0)?'S':'M');
 	}
 	dprintk("\nbttv%d: tea5757: read 0x%X\n", btv->nr, value);
 	return value;
@@ -2030,32 +2796,43 @@
 	
 	btaor(btv->mbox_clk | btv->mbox_we | btv->mbox_data,
 	      ~btv->mbox_mask, BT848_GPIO_OUT_EN);
+
+	if (btv->mbox_ior) {
+		btor(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
+		     BT848_GPIO_DATA);
+		udelay(5);
+	}
 	if (bttv_gpio)
 		bttv_gpio_tracking(btv,"tea5757 write");
+
 	dprintk("bttv%d: tea5757: write 0x%X\n", btv->nr, value);
-	BUS_LOW(btv->mbox_clk);
-	BUS_HIGH(btv->mbox_we);
+	bus_low(btv,btv->mbox_clk);
+	bus_high(btv,btv->mbox_we);
 	for(i = 0; i < 25; i++)
 	{
 		if (reg & 0x1000000)
-			BUS_HIGH(btv->mbox_data);
+			bus_high(btv,btv->mbox_data);
 		else
-			BUS_LOW(btv->mbox_data);
+			bus_low(btv,btv->mbox_data);
 		reg <<= 1;
-		BUS_HIGH(btv->mbox_clk);
+		bus_high(btv,btv->mbox_clk);
 		udelay(10);
-		BUS_LOW(btv->mbox_clk);
+		bus_low(btv,btv->mbox_clk);
 		udelay(10);
 	}
-	BUS_LOW(btv->mbox_we);  /* unmute !!! */
+	bus_low(btv,btv->mbox_we);  /* unmute !!! */
 	return 0;
 }
 
 void tea5757_set_freq(struct bttv *btv, unsigned short freq)
 {
+	dprintk("tea5757_set_freq %d\n",freq);
 	tea5757_write(btv, 5 * freq + 0x358); /* add 10.7MHz (see docs) */
-	if (bttv_debug)
-		tea5757_read(btv);
+#if 0
+	/* breaks Miro PCTV */
+	value = tea5757_read(btv);
+	dprintk("bttv%d: tea5757 readback=0x%x\n",btv->nr,value);
+#endif
 }
 
 
@@ -2195,7 +2972,7 @@
         }
 }
 
-
+// TDA9821 on TerraTV+ Bt848, Bt878
 static void
 terratv_audio(struct bttv *btv, struct video_audio *v, int set)
 {
@@ -2246,6 +3023,9 @@
  * Dariusz Kowalewski <darekk@automex.pl>
  * sound control for Prolink PV-BT878P+9B (PixelView PlayTV Pro FM+NICAM
  * revision 9B has on-board TDA9874A sound decoder).
+ *
+ * Note: There are card variants without tda9874a. Forcing the "stereo sound route"
+ *       will mute this cards.
  */
 static void
 pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set)
@@ -2344,6 +3124,38 @@
         }
 }
 
+/*
+ * sound control for AD-TVK503
+ * Hiroshi Takekawa <sian@big.or.jp>
+ */
+static void
+adtvk503_audio(struct bttv *btv, struct video_audio *v, int set)
+{
+	unsigned int con = 0xffffff;
+
+	//btaor(0x1e0000, ~0x1e0000, BT848_GPIO_OUT_EN);
+
+	if (set) {
+		//btor(***, BT848_GPIO_OUT_EN);
+		if (v->mode & VIDEO_SOUND_LANG1)
+			con = 0x00000000;
+		if (v->mode & VIDEO_SOUND_LANG2)
+			con = 0x00180000;
+		if (v->mode & VIDEO_SOUND_STEREO)
+			con = 0x00000000;
+		if (v->mode & VIDEO_SOUND_MONO)
+			con = 0x00060000;
+		if (con != 0xffffff) {
+			btaor(con, ~0x1e0000, BT848_GPIO_DATA);
+			if (bttv_gpio)
+				bttv_gpio_tracking(btv, "adtvk503");
+		}
+	} else {
+		v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
+			  VIDEO_SOUND_LANG1  | VIDEO_SOUND_LANG2;
+	}
+}
+
 /* RemoteVision MX (rv605) muxsel helper [Miguel Freitas]
  *
  * This is needed because rv605 don't use a normal multiplex, but a crosspoint
@@ -2393,13 +3205,16 @@
 	int pcipci_fail = 0;
 	struct pci_dev *dev = NULL;
 
-	/* for 2.4.x we'll use the pci quirks (drivers/pci/quirks.c) */
 	if (pci_pci_problems & PCIPCI_FAIL)
 		pcipci_fail = 1;
 	if (pci_pci_problems & (PCIPCI_TRITON|PCIPCI_NATOMA|PCIPCI_VIAETBF))
 		triton1 = 1;
 	if (pci_pci_problems & PCIPCI_VSFX)
 		vsfx = 1;
+#ifdef PCIPCI_ALIMAGIK
+	if (pci_pci_problems & PCIPCI_ALIMAGIK)
+		latency = 0x0A;
+#endif
 
 	/* print which chipset we have */
 	while ((dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8,dev)))
@@ -2410,38 +3225,41 @@
 		printk(KERN_INFO "bttv: Host bridge needs ETBF enabled.\n");
 	if (vsfx)
 		printk(KERN_INFO "bttv: Host bridge needs VSFX enabled.\n");
-
 	if (pcipci_fail) {
 		printk(KERN_WARNING "bttv: BT848 and your chipset may not work together.\n");
-		if (-1 == no_overlay) {
+		if (UNSET == no_overlay) {
 			printk(KERN_WARNING "bttv: going to disable overlay.\n");
 			no_overlay = 1;
 		}
 	}
+	if (UNSET != latency)
+		printk(KERN_INFO "bttv: pci latency fixup [%d]\n",latency);
 
 	while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL,
 				      PCI_DEVICE_ID_INTEL_82441, dev))) {
                 unsigned char b;
-                pci_read_config_byte(dev, 0x53, &b);
+		pci_read_config_byte(dev, 0x53, &b);
 		if (bttv_debug)
 			printk(KERN_INFO "bttv: Host bridge: 82441FX Natoma, "
 			       "bufcon=0x%02x\n",b);
 	}
-
 }
 
 int __devinit bttv_handle_chipset(struct bttv *btv)
 {
  	unsigned char command;
 
-	if (!triton1 && !vsfx)
+	if (!triton1 && !vsfx && UNSET == latency)
 		return 0;
 
 	if (bttv_verbose) {
 		if (triton1)
-			printk("bttv%d: enabling ETBF (430FX/VP3 compatibilty)\n",btv->nr);
+			printk(KERN_INFO "bttv%d: enabling ETBF (430FX/VP3 compatibilty)\n",btv->nr);
 		if (vsfx && btv->id >= 878)
-			printk("bttv%d: enabling VSFX\n",btv->nr);
+			printk(KERN_INFO "bttv%d: enabling VSFX\n",btv->nr);
+		if (UNSET != latency)
+			printk(KERN_INFO "bttv%d: setting pci timer to %d\n",
+			       btv->nr,latency);
 	}
 
 	if (btv->id < 878) {
@@ -2457,6 +3275,8 @@
 			command |= BT878_EN_VSFX;
                 pci_write_config_byte(btv->dev, BT878_DEVCTRL, command);
         }
+	if (UNSET != latency)
+		pci_write_config_byte(btv->dev, PCI_LATENCY_TIMER, latency);
 	return 0;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/video/bttv-driver.c linux-2.4.21-pre6/drivers/media/video/bttv-driver.c
--- linux-2.4.20/drivers/media/video/bttv-driver.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/media/video/bttv-driver.c	2003-03-26 23:49:51.000000000 +0000
@@ -3,7 +3,7 @@
 
     Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
                            & Marcus Metzler (mocm@thp.uni-koeln.de)
-    (c) 1999,2000 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+    (c) 1999-2003 Gerd Knorr <kraxel@goldbach.in-berlin.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
@@ -52,9 +52,12 @@
 #define MIN(a,b) (((a)>(b))?(b):(a))
 #define MAX(a,b) (((a)>(b))?(a):(b))
 
+/* fwd decl */
 static void bt848_set_risc_jmps(struct bttv *btv, int state);
+static void make_vbitab(struct bttv *btv);
+static void bt848_set_winsize(struct bttv *btv);
 
-int bttv_num;			/* number of Bt848s in use */
+unsigned int bttv_num;			/* number of Bt848s in use */
 struct bttv bttvs[BTTV_MAX];
 
 /* configuration variables */
@@ -65,10 +68,10 @@
 #endif
 static unsigned int radio[BTTV_MAX];
 static unsigned int fieldnr = 0;
+static unsigned int gpint = 1;
 static unsigned int irq_debug = 0;
 static unsigned int gbuffers = 4;
 static unsigned int gbufsize = BTTV_MAX_FBUF;
-static int latency = -1;
 
 static unsigned int combfilter = 0;
 static unsigned int lumafilter = 0;
@@ -101,8 +104,7 @@
 MODULE_PARM_DESC(gbuffers,"number of capture buffers, default is 2 (64 max)");
 MODULE_PARM(gbufsize,"i");
 MODULE_PARM_DESC(gbufsize,"size of the capture buffers, default is 0x208000");
-MODULE_PARM(latency,"i");
-MODULE_PARM_DESC(latency,"pci latency timer");
+MODULE_PARM(gpint,"i");
 
 MODULE_PARM(combfilter,"i");
 MODULE_PARM(lumafilter,"i");
@@ -327,78 +329,75 @@
         btwrite(fi|BT848_PLL_X, BT848_PLL_XCI);
 }
 
-static int set_pll(struct bttv *btv)
+static void set_pll(struct bttv *btv)
 {
         int i;
-	unsigned long tv;
 
         if (!btv->pll.pll_crystal)
-                return 0;
+                return;
+
+	if (btv->pll.pll_ofreq == btv->pll.pll_current) {
+		dprintk("bttv%d: PLL: no change required\n",btv->nr);
+                return;
+        }
 
         if (btv->pll.pll_ifreq == btv->pll.pll_ofreq) {
                 /* no PLL needed */
-                if (btv->pll.pll_current == 0) {
-                        /* printk ("bttv%d: PLL: is off\n",btv->nr); */
-                        return 0;
-                }
-		if (bttv_verbose)
-			printk ("bttv%d: PLL: switching off\n",btv->nr);
+                if (btv->pll.pll_current == 0)
+                        return;
+		vprintk(KERN_INFO "bttv%d: PLL can sleep, using XTAL (%d).\n",
+			btv->nr,btv->pll.pll_ifreq);
                 btwrite(0x00,BT848_TGCTRL);
                 btwrite(0x00,BT848_PLL_XCI);
                 btv->pll.pll_current = 0;
-                return 0;
-        }
-
-        if (btv->pll.pll_ofreq == btv->pll.pll_current) {
-                /* printk("bttv%d: PLL: no change required\n",btv->nr); */
-                return 1;
+                return;
         }
 
-        if (bttv_verbose)
-		printk("bttv%d: PLL: %d => %d ... ",btv->nr,
-		       btv->pll.pll_ifreq, btv->pll.pll_ofreq);
-
+	vprintk(KERN_INFO "bttv%d: PLL: %d => %d ",btv->nr,
+		btv->pll.pll_ifreq, btv->pll.pll_ofreq);
 	set_pll_freq(btv, btv->pll.pll_ifreq, btv->pll.pll_ofreq);
 
-	/*  Let other people run while the PLL stabilizes */
-	tv=jiffies+HZ/10;       /* .1 seconds */
-	do
-	{
-		schedule();
-	}
-	while(time_before(jiffies,tv));
-
-        for (i=0; i<100; i++) 
-        {
-                if ((btread(BT848_DSTATUS)&BT848_DSTATUS_PLOCK))
-                        btwrite(0,BT848_DSTATUS);
-                else
-                {
+        for (i=0; i<10; i++) {
+		/*  Let other people run while the PLL stabilizes */
+		vprintk(".");
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(HZ/10);
+		
+                if (btread(BT848_DSTATUS) & BT848_DSTATUS_PLOCK) {
+			btwrite(0,BT848_DSTATUS);
+                } else {
                         btwrite(0x08,BT848_TGCTRL);
                         btv->pll.pll_current = btv->pll.pll_ofreq;
-			if (bttv_verbose)
-				printk("ok\n");
-                        return 1;
+			vprintk(" ok\n");
+                        return;
                 }
-                mdelay(10);
         }
-        btv->pll.pll_current = 0;
-	if (bttv_verbose)
-		printk("oops\n");
-        return -1;
+        btv->pll.pll_current = -1;
+	vprintk("failed\n");
+        return;
 }
 
 static void bt848_muxsel(struct bttv *btv, unsigned int input)
 {
+	dprintk("bttv%d: bt848_muxsel %d\n",btv->nr,input);
+
+	if (bttv_tvcards[btv->type].muxsel[input] < 0) {
+		dprintk("bttv%d: digital ccir muxsel\n", btv->nr);
+		btv->channel = input;
+		return;
+	}
+
         /* needed by RemoteVideo MX */
 	if (bttv_tvcards[btv->type].gpiomask2)
 		btaor(bttv_tvcards[btv->type].gpiomask2,
 		      ~bttv_tvcards[btv->type].gpiomask2,
 		      BT848_GPIO_OUT_EN);
 
+#if 0
 	/* This seems to get rid of some synchronization problems */
 	btand(~(3<<5), BT848_IFORM);
 	mdelay(10);
+#endif
 
 	input %= bttv_tvcards[btv->type].video_inputs;
 	if (input==bttv_tvcards[btv->type].svhs)
@@ -428,8 +427,42 @@
 	if (bttv_gpio)
 		bttv_gpio_tracking(btv,"muxsel");
 
+	btv->channel=input;
 }
 
+/* special timing tables from conexant... */
+static u8 SRAM_Table[][60] =
+{
+	/* PAL digital input over GPIO[7:0] */
+	{
+		45, // 45 bytes following
+		0x36,0x11,0x01,0x00,0x90,0x02,0x05,0x10,0x04,0x16,
+		0x12,0x05,0x11,0x00,0x04,0x12,0xC0,0x00,0x31,0x00,
+		0x06,0x51,0x08,0x03,0x89,0x08,0x07,0xC0,0x44,0x00,
+		0x81,0x01,0x01,0xA9,0x0D,0x02,0x02,0x50,0x03,0x37,
+		0x37,0x00,0xAF,0x21,0x00
+	},
+	/* NTSC digital input over GPIO[7:0] */
+	{
+		51, // 51 bytes following
+		0x0C,0xC0,0x00,0x00,0x90,0x02,0x03,0x10,0x03,0x06,
+		0x10,0x04,0x12,0x12,0x05,0x02,0x13,0x04,0x19,0x00,
+		0x04,0x39,0x00,0x06,0x59,0x08,0x03,0x83,0x08,0x07,
+		0x03,0x50,0x00,0xC0,0x40,0x00,0x86,0x01,0x01,0xA6,
+		0x0D,0x02,0x03,0x11,0x01,0x05,0x37,0x00,0xAC,0x21,
+		0x00,
+	},
+	// TGB_NTSC392 // quartzsight
+	// This table has been modified to be used for Fusion Rev D
+	{
+		0x2A, // size of table = 42
+		0x06, 0x08, 0x04, 0x0a, 0xc0, 0x00, 0x18, 0x08, 0x03, 0x24,
+		0x08, 0x07, 0x02, 0x90, 0x02, 0x08, 0x10, 0x04, 0x0c, 0x10,
+		0x05, 0x2c, 0x11, 0x04, 0x55, 0x48, 0x00, 0x05, 0x50, 0x00,
+		0xbf, 0x0c, 0x02, 0x2f, 0x3d, 0x00, 0x2f, 0x3f, 0x00, 0xc3,
+		0x20, 0x00
+	}
+};
 
 struct tvnorm
 {
@@ -441,57 +474,209 @@
 	u16 hdelayx1, hactivex1;
 	u16 vdelay;
         u8 vbipack;
+	int sram; /* index into SRAM_Table */
 };
 
 static struct tvnorm tvnorms[] = {
 	/* PAL-BDGHI */
         /* max. active video is actually 922, but 924 is divisible by 4 and 3! */
  	/* actually, max active PAL with HSCALE=0 is 948, NTSC is 768 - nil */
-        { 35468950,
-          924, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
-          1135, 186, 924,
+	{
+		.Fsc            = 35468950,
+		.swidth         = 924,
+		.sheight        = 576,
+		.totalwidth     = 1135,
+		.adelay         = 0x7f,
+		.bdelay         = 0x72, 
+		.iform          = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
+		.scaledtwidth   = 1135,
+		.hdelayx1       = 186,
+		.hactivex1      = 924,
 #ifdef VIDEODAT_HACK
-	  VBI_MAXLINES*2,
+		.vdelay         = VBI_MAXLINES*2,
 #else
-	  0x20,
+		.vdelay         = 0x20,
 #endif
-	  255},
+		.vbipack        = 255,
+		.sram           = 0,
+	},{
+                /* NTSC */
+		.Fsc            = 28636363,
+		.swidth         = 768,
+		.sheight        = 480,
+		.totalwidth     = 910,
+		.adelay         = 0x68,
+		.bdelay         = 0x5d,
+		.iform          = (BT848_IFORM_NTSC|BT848_IFORM_XT0),
+		.scaledtwidth   = 910,
+		.hdelayx1       = 128,
+		.hactivex1      = 910,
+		.vdelay         = 0x1a,
+		.vbipack        = 144,
+		.sram           = 1,
+	},{
+		/* SECAM L */
+		.Fsc            = 35468950,
+		.swidth         = 924,
+		.sheight        = 576,
+		.totalwidth     = 1135,
+		.adelay         = 0x7f,
+		.bdelay         = 0xb0,
+		.iform          = (BT848_IFORM_SECAM|BT848_IFORM_XT1),
+		.scaledtwidth   = 1135,
+		.hdelayx1       = 186,
+		.hactivex1      = 922,
+		.vdelay         = 0x20,
+		.vbipack        = 255,
+		.sram           = 0, /* like PAL, correct? */
+	},{
+		/* PAL-NC */
+		.Fsc            = 28636363,
+		.swidth         = 640,
+		.sheight        = 576,
+		.totalwidth     = 910,
+		.adelay         = 0x68,
+		.bdelay         = 0x5d,
+		.iform          = (BT848_IFORM_PAL_NC|BT848_IFORM_XT0),
+		.scaledtwidth   = 780,
+		.hdelayx1       = 130,
+		.hactivex1      = 734,
+		.vdelay         = 0x1a,
+		.vbipack        = 144,
+		.sram           = -1,
+	},{
+		/* PAL-M */
+		.Fsc            = 28636363,
+		.swidth         = 640,
+		.sheight        = 480,
+		.totalwidth     = 910,
+		.adelay         = 0x68,
+		.bdelay         = 0x5d,
+		.iform          = (BT848_IFORM_PAL_M|BT848_IFORM_XT0),
+		.scaledtwidth   = 780,
+		.hdelayx1       = 135,
+		.hactivex1      = 754,
+		.vdelay         = 0x1a,
+		.vbipack        = 144,
+		.sram           = -1,
+	},{
+		/* PAL-N */
+		.Fsc             35468950,
+		.swidth         = 768,
+		.sheight        = 576,
+		.totalwidth     = 1135,
+		.adelay         = 0x7f,
+		.bdelay         = 0x72,
+		.iform          = (BT848_IFORM_PAL_N|BT848_IFORM_XT1),
+		.scaledtwidth   = 944,
+		.hdelayx1       = 186,
+		.hactivex1      = 922,
+		.vdelay         = 0x20,
+		.vbipack        = 144,
+		.sram           = -1,
+	},{
+		/* NTSC-Japan */
+		.Fsc            = 28636363,
+		.swidth         = 640,
+		.sheight        = 480,
+		.totalwidth     = 910,
+		.adelay         = 0x68,
+		.bdelay         = 0x5d,
+		.iform          = (BT848_IFORM_NTSC_J|BT848_IFORM_XT0),
+		.scaledtwidth   = 780,
+		.hdelayx1       = 135,
+		.hactivex1      = 754,
+		.vdelay         = 0x16,
+		.vbipack        = 144,
+		.sram           = -1,
+	},{
+		/* Quartzsight digital camera 
+		 * From Bt832 datasheet: 393x304 pixel @30Hz,
+		 * Visible: 352x288 pixel
+		 */
+                .Fsc            = 27000000,
+                .swidth         = 352,
+                .sheight        = 576, //2*288 ?
+                .totalwidth     = 392,
+                .adelay         = 0x68,
+                .bdelay         = 0x5d,
+                .iform          = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
+                .scaledtwidth   = 392,
+                .hdelayx1       = 0x20,
+                .hactivex1      = 352,
+                .vdelay         = 0x08,
+                .vbipack        = 0, //255
+                .sram           = 2,
+        }
+};
+#define TVNORMS (sizeof(tvnorms)/sizeof(struct tvnorm))
+
+/* used to switch between the bt848's analog/digital video capture modes */
+void bt848A_set_timing(struct bttv *btv)
+{
+	int i, len;
+	int table_idx = tvnorms[btv->win.norm].sram;
+	int fsc       = tvnorms[btv->win.norm].Fsc;
+
+	if (bttv_tvcards[btv->type].muxsel[btv->channel] < 0) {
+		dprintk("bttv%d: load digital timing table (table_idx=%d)\n",
+			btv->nr,table_idx);
+
+		/* timing change...reset timing generator address */
+       		btwrite(0x00, BT848_TGCTRL);
+       		btwrite(0x02, BT848_TGCTRL);
+       		btwrite(0x00, BT848_TGCTRL);
+
+		len=SRAM_Table[table_idx][0];
+		for(i = 1; i <= len; i++)
+			btwrite(SRAM_Table[table_idx][i],BT848_TGLB);
+		btv->pll.pll_ofreq = 27000000;
+
+		set_pll(btv);
+		btwrite(0x11, BT848_TGCTRL);
+		btwrite(0x41, BT848_DVSIF);
+	} else {
+		btv->pll.pll_ofreq = fsc;
+		set_pll(btv);
+		btwrite(0x0, BT848_DVSIF);
+	}
+}
+
+static void bttv_set_norm(struct bttv *btv, int new_norm)
+{
+	unsigned long irq_flags;
 
-	/* NTSC */
-	{ 28636363,
-          768, 480,  910, 0x68, 0x5d, (BT848_IFORM_NTSC|BT848_IFORM_XT0),
-          910, 128, 910, 0x1a, 144},
+	if (bttv_tvcards[btv->type].muxsel[btv->channel] < 0 &&
+	    bttv_tvcards[btv->type].digital_mode == DIGITAL_MODE_CAMERA) {
+		//override norm by quartzsight mode
+		new_norm=7;
+		dprintk("bttv%d: set_norm fix-up digital: %d\n",
+			btv->nr, new_norm);
+	}
+	       
+	if (btv->win.norm != new_norm) {
+		btv->win.norm = new_norm;
+		
+		make_vbitab(btv);
+		spin_lock_irqsave(&btv->s_lock, irq_flags);
+		bt848_set_winsize(btv);
+		spin_unlock_irqrestore(&btv->s_lock, irq_flags);
+		
+		bt848A_set_timing(btv);
+		switch (btv->type) {
+		case BTTV_VOODOOTV_FM:
+			bttv_tda9880_setnorm(btv,new_norm);
+			break;
 #if 0
-	/* SECAM EAST */
-	{ 35468950, 
-          768, 576, 1135, 0x7f, 0xb0, (BT848_IFORM_SECAM|BT848_IFORM_XT1),
-	  944, 186, 922, 0x20, 255},
-#else
-	/* SECAM L */
-        { 35468950,
-          924, 576, 1135, 0x7f, 0xb0, (BT848_IFORM_SECAM|BT848_IFORM_XT1),
-          1135, 186, 922, 0x20, 255},
+		case BTTV_OSPREY540:
+			osprey_540_set_norm(btv,new_norm);
+			break;
 #endif
-        /* PAL-NC */
-        { 28636363,
-          640, 576,  910, 0x68, 0x5d, (BT848_IFORM_PAL_NC|BT848_IFORM_XT0),
-          780, 130, 734, 0x1a, 144},
-	/* PAL-M */
-	{ 28636363, 
-          640, 480, 910, 0x68, 0x5d, (BT848_IFORM_PAL_M|BT848_IFORM_XT0),
-	  780, 135, 754, 0x1a, 144},
-	/* PAL-N */
-	{ 35468950, 
-          768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_N|BT848_IFORM_XT1),
-	  944, 186, 922, 0x20, 144},
-	/* NTSC-Japan */
-	{ 28636363,
-          640, 480,  910, 0x68, 0x5d, (BT848_IFORM_NTSC_J|BT848_IFORM_XT0),
-	  780, 135, 754, 0x16, 144},
-};
-#define TVNORMS (sizeof(tvnorms)/sizeof(tvnorm))
-#define VBI_SPL 2044
+		}
+	}
+}
 
+#define VBI_SPL 2044
 /* RISC command to write one VBI data line */
 #define VBI_RISC BT848_RISC_WRITE|VBI_SPL|BT848_RISC_EOL|BT848_RISC_SOL
 
@@ -506,8 +691,7 @@
 		       btv->nr,virt_to_bus(po), virt_to_bus(pe));
         
 	*(po++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(po++)=0;
-	for (i=0; i<VBI_MAXLINES; i++) 
-	{
+	for (i=0; i<VBI_MAXLINES; i++) {
 		*(po++)=cpu_to_le32(VBI_RISC);
 		*(po++)=cpu_to_le32(kvirt_to_bus((unsigned long)btv->vbibuf+i*2048));
 	}
@@ -515,8 +699,7 @@
 	*(po++)=cpu_to_le32(virt_to_bus(btv->risc_jmp+4));
 
 	*(pe++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(pe++)=0;
-	for (i=VBI_MAXLINES; i<VBI_MAXLINES*2; i++) 
-	{
+	for (i=VBI_MAXLINES; i<VBI_MAXLINES*2; i++) {
 		*(pe++)=cpu_to_le32(VBI_RISC);
 		*(pe++)=cpu_to_le32(kvirt_to_bus((unsigned long)btv->vbibuf+i*2048));
 	}
@@ -528,12 +711,12 @@
 		       btv->nr,virt_to_bus(po), virt_to_bus(pe));
 }
 
-static int fmtbppx2[16] = {
+static unsigned int fmtbppx2[16] = {
         8, 6, 4, 4, 4, 3, 2, 2, 4, 3, 0, 0, 0, 0, 2, 0 
 };
 
-static int palette2fmt[] = {
-	0,
+static unsigned int palette2fmt[] = {
+	UNSET,
 	BT848_COLOR_FMT_Y8,
 	BT848_COLOR_FMT_RGB8,
 	BT848_COLOR_FMT_RGB16,
@@ -542,29 +725,28 @@
 	BT848_COLOR_FMT_RGB15,
 	BT848_COLOR_FMT_YUY2,
 	BT848_COLOR_FMT_YUY2,
-	-1,
-	-1,
-	-1,
+	UNSET,
+	UNSET,
+	UNSET,
 	BT848_COLOR_FMT_RAW,
 	BT848_COLOR_FMT_YCrCb422,
 	BT848_COLOR_FMT_YCrCb411,
 	BT848_COLOR_FMT_YCrCb422,
 	BT848_COLOR_FMT_YCrCb411,
 };
-#define PALETTEFMT_MAX (sizeof(palette2fmt)/sizeof(int))
+#define PALETTEFMT_MAX (sizeof(palette2fmt)/sizeof(palette2fmt[0]))
 
-static int make_rawrisctab(struct bttv *btv, unsigned int *ro,
-			   unsigned int *re, unsigned int *vbuf)
+static int make_rawrisctab(struct bttv *btv, u32 *ro, u32 *re, u32 *vbuf)
 {
-        unsigned long line;
-	unsigned long bpl=1024;		/* bytes per line */
+	u32 line;
+	u32 bpl=1024;		/* bytes per line */
 	unsigned long vadr=(unsigned long) vbuf;
 
 	*(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); 
         *(ro++)=cpu_to_le32(0);
 	*(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
         *(re++)=cpu_to_le32(0);
-  
+	
         /* In PAL 650 blocks of 256 DWORDs are sampled, but only if VDELAY
            is 2 and without separate VBI grabbing.
            We'll have to handle this inside the IRQ handler ... */
@@ -586,19 +768,17 @@
 	return 0;
 }
 
-static int  make_prisctab(struct bttv *btv, unsigned int *ro,
-                          unsigned int *re, 
-                          unsigned int *vbuf, unsigned short width,
-                          unsigned short height, unsigned short fmt)
+static int  make_prisctab(struct bttv *btv, u32 *ro, u32 *re, u32 *vbuf,
+			  u16 width, u16 height, u16 fmt)
 {
-        unsigned long line, lmask;
-	unsigned long bl, blcr, blcb, rcmd;
-	unsigned long todo;
-	unsigned int **rp;
+	u16 line, lmask;
+	u32 bl, blcr, blcb, rcmd;
+	u32 todo;
+	u32 **rp;
 	int inter;
-	unsigned long cbadr, cradr;
+	u32 cbadr, cradr;
 	unsigned long vadr=(unsigned long) vbuf;
-	int shift, csize;	
+	u32 shift, csize;
 
 	if (bttv_debug > 1)
 		printk("bttv%d: prisc1: ro=%08lx re=%08lx\n",
@@ -680,7 +860,7 @@
 		 *((*rp)++)=cpu_to_le32(blcb|(blcr<<16));
 		 *((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr));
 		 vadr+=bl;
-		 if((rcmd&(15<<28))==BT848_RISC_WRITE123)
+		 if ((rcmd&(15<<28))==BT848_RISC_WRITE123)
 		 {
 		 	*((*rp)++)=cpu_to_le32(kvirt_to_bus(cbadr));
 		 	cbadr+=blcb;
@@ -703,25 +883,22 @@
 
 	return 0;
 }
- 
-static int  make_vrisctab(struct bttv *btv, unsigned int *ro,
-                          unsigned int *re, 
-                          unsigned int *vbuf, unsigned short width,
-                          unsigned short height, unsigned short palette)
-{
-        unsigned long line;
-	unsigned long bpl;  /* bytes per line */
-	unsigned long bl;
-	unsigned long todo;
-	unsigned int **rp;
+
+static int  make_vrisctab(struct bttv *btv, u32 *ro, u32 *re, u32 *vbuf,
+			  u16 width, u16 height, u16 palette)
+{
+	u16 line;
+	u32 bpl;  /* bytes per line */
+	u32 bl;
+	u32 todo;
+	u32 **rp;
 	int inter;
-	unsigned long vadr=(unsigned long) vbuf;
+	unsigned long vadr=(unsigned long)vbuf;
 
         if (palette==VIDEO_PALETTE_RAW) 
                 return make_rawrisctab(btv, ro, re, vbuf);
         if (palette>=VIDEO_PALETTE_PLANAR)
                 return make_prisctab(btv, ro, re, vbuf, width, height, palette);
-
 	if (bttv_debug > 1)
 		printk("bttv%d: vrisc1: ro=%08lx re=%08lx\n",
 		       btv->nr,virt_to_bus(ro), virt_to_bus(re));
@@ -845,9 +1022,10 @@
 
 static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr)
 {
-	int i, line, x, y, bpl, width, height, inter, maxw;
-	unsigned int bpp, dx, sx, **rp, *ro, *re, flags, len;
-	unsigned long adr;
+	u32 line, x, y, bpl, width, height, inter, maxw;
+	u32 bpp, dx, sx, **rp, *ro, *re, flags, len;
+	u32 adr;
+	int i;
 	unsigned char *clipmap, *clipline, cbit, lastbit, outofmem;
 
 	/* take care: bpp != btv->win.bpp is allowed here */
@@ -987,13 +1165,25 @@
 	u32 xsf, sr;
 	u16 hdelay;
 	u8 crop, vtc;
+
 	int inter = (height>tvn->sheight/2) ? 0 : 1;
         int off = odd ? 0x80 : 0x00;
 
-	xsf = (width*tvn->scaledtwidth)/tvn->swidth;
-	hscale = ((tvn->totalwidth*4096UL)/xsf-4096);
+	int swidth       = tvn->swidth;
+	int totalwidth   = tvn->totalwidth;
+	int scaledtwidth = tvn->scaledtwidth;
+
+	if (bttv_tvcards[btv->type].muxsel[btv->channel] < 0) {
+		dprintk("bttv%d: DIGITAL_MODE_VIDEO override width\n",btv->nr);
+		swidth       = 720;
+		totalwidth   = 858;
+		scaledtwidth = 858;
+	}
+
+	xsf = (width*scaledtwidth)/swidth;
+	hscale = ((totalwidth*4096UL)/xsf-4096);
 	hdelay =  tvn->hdelayx1;
-	hdelay =  (hdelay*width)/tvn->swidth;
+	hdelay =  (hdelay*width)/swidth;
 	hdelay &= 0x3fe;
 	sr=((tvn->sheight>>inter)*512)/height-512;
 	vscale=(0x10000UL-sr)&0x1fff;
@@ -1038,7 +1228,10 @@
 	btwrite(tvn->bdelay, BT848_BDELAY);
 	btaor(tvn->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH), BT848_IFORM);
 	btwrite(tvn->vbipack, BT848_VBI_PACK_SIZE);
-	btwrite(1, BT848_VBI_PACK_DEL);
+	if (bttv_tvcards[btv->type].muxsel[btv->channel] < 0)
+		btwrite(0x39, BT848_VBI_PACK_DEL);
+	else
+		btwrite(0x01, BT848_VBI_PACK_DEL);
 
         btv->pll.pll_ofreq = tvn->Fsc;
 	if (!in_interrupt())
@@ -1142,8 +1335,8 @@
 
 static int vgrab(struct bttv *btv, struct video_mmap *mp)
 {
-	unsigned int *ro, *re;
-	unsigned int *vbuf;
+	u32 *ro, *re;
+	u32 *vbuf;
 	unsigned long flags;
 	
 	if(btv->fbuffer==NULL)
@@ -1162,10 +1355,10 @@
 	if (mp->format >= PALETTEFMT_MAX)
 		return -EINVAL;
 
-	if (mp->height*mp->width*fmtbppx2[palette2fmt[mp->format]&0x0f]/2
-	    > gbufsize)
+	if ((unsigned int)mp->height * mp->width *
+	    fmtbppx2[palette2fmt[mp->format]&0x0f]/2 > gbufsize)
 		return -EINVAL;
-	if (-1 == palette2fmt[mp->format])
+	if (UNSET == palette2fmt[mp->format])
 		return -EINVAL;
 
 	/*
@@ -1214,54 +1407,8 @@
 
 static long bttv_read(struct video_device *v, char *buf, unsigned long count, int nonblock)
 {
-	struct bttv *btv= (struct bttv *)v;
-	int q;
-	unsigned long todo;
-	DECLARE_WAITQUEUE(wait, current);
-
-	/* BROKEN: RETURNS VBI WHEN IT SHOULD RETURN GRABBED VIDEO FRAME */
-	todo=count;
-	while (todo && todo>(q=VBIBUF_SIZE-btv->vbip)) 
-	{
-		if(copy_to_user((void *) buf, (void *) btv->vbibuf+btv->vbip, q))
-			return -EFAULT;
-		todo-=q;
-		buf+=q;
-
-		add_wait_queue(&btv->vbiq, &wait);
-		current->state = TASK_INTERRUPTIBLE;
-		if (todo && q==VBIBUF_SIZE-btv->vbip) 
-		{
-			if(nonblock)
-			{
-				remove_wait_queue(&btv->vbiq, &wait);
-                                current->state = TASK_RUNNING;
-				if(count==todo)
-					return -EWOULDBLOCK;
-				return count-todo;
-			}
-			schedule();	
-			if(signal_pending(current))
-			{
-				remove_wait_queue(&btv->vbiq, &wait);
-                                current->state = TASK_RUNNING;
-
-				if(todo==count)
-					return -EINTR;
-				else
-					return count-todo;
-			}
-		}
-		remove_wait_queue(&btv->vbiq, &wait);
-                current->state = TASK_RUNNING;
-	}
-	if (todo) 
-	{
-		if(copy_to_user((void *) buf, (void *) btv->vbibuf+btv->vbip, todo))
-			return -EFAULT;
-		btv->vbip+=todo;
-	}
-	return count;
+	/* use bttv 0.9.x if you need capture via read() */
+	return -EINVAL;
 }
 
 static inline void burst(int on)
@@ -1281,7 +1428,7 @@
  */
 static void bt848_offline(struct bttv *btv)
 {
-	int i;
+	unsigned int i;
 	spin_lock(&btv->s_lock);
 
 	/* cancel all outstanding grab requests */
@@ -1318,7 +1465,7 @@
 		BT848_RISC_STRT_ADD);
 
 	/* enforce pll reprogramming */
-	btv->pll.pll_current = 0;
+	btv->pll.pll_current = -1;
 	set_pll(btv);
 
 	spin_lock_irqsave(&btv->s_lock, irq_flags);
@@ -1336,7 +1483,8 @@
 static int bttv_open(struct video_device *dev, int flags)
 {
 	struct bttv *btv = (struct bttv *)dev;
-        int i,ret;
+        unsigned int i;
+	int ret;
 
 	ret = -EBUSY;
 	if (bttv_debug)
@@ -1472,7 +1620,7 @@
 {
 	struct bttv *btv=(struct bttv *)dev;
  	unsigned long irq_flags;
- 	int i,ret = 0;
+ 	int ret = 0;
 
 	if (bttv_debug > 1)
 		printk("bttv%d: ioctl 0x%x\n",btv->nr,cmd);
@@ -1483,7 +1631,7 @@
 		struct video_capability b;
 		strcpy(b.name,btv->video_dev.name);
 		b.type = VID_TYPE_CAPTURE|
-			((bttv_tvcards[btv->type].tuner != -1) ? VID_TYPE_TUNER : 0) |
+			((bttv_tvcards[btv->type].tuner != UNSET) ? VID_TYPE_TUNER : 0) |
 			VID_TYPE_OVERLAY|
 			VID_TYPE_CLIPPING|
 			VID_TYPE_FRAMERAM|
@@ -1501,23 +1649,28 @@
 	case VIDIOCGCHAN:
 	{
 		struct video_channel v;
+		unsigned int  channel;
+
 		if(copy_from_user(&v, arg,sizeof(v)))
 			return -EFAULT;
+		channel = v.channel;
+		if (channel>=bttv_tvcards[btv->type].video_inputs)
+			return -EINVAL;
 		v.flags=VIDEO_VC_AUDIO;
 		v.tuners=0;
 		v.type=VIDEO_TYPE_CAMERA;
 		v.norm = btv->win.norm;
-		if (v.channel>=bttv_tvcards[btv->type].video_inputs)
-			return -EINVAL;
-		if(v.channel==bttv_tvcards[btv->type].tuner) 
+		if(channel==bttv_tvcards[btv->type].tuner) 
 		{
 			strcpy(v.name,"Television");
 			v.flags|=VIDEO_VC_TUNER;
 			v.type=VIDEO_TYPE_TV;
 			v.tuners=1;
 		} 
-		else if(v.channel==bttv_tvcards[btv->type].svhs) 
+		else if (channel==bttv_tvcards[btv->type].svhs) 
 			strcpy(v.name,"S-Video");
+		else if (bttv_tvcards[btv->type].muxsel[v.channel] < 0)
+			strcpy(v.name,"Digital Video");
 		else
 			sprintf(v.name,"Composite%d",v.channel);
 		
@@ -1531,27 +1684,21 @@
 	case VIDIOCSCHAN:
 	{
 		struct video_channel v;
+		unsigned int  channel;
+
 		if(copy_from_user(&v, arg,sizeof(v)))
 			return -EFAULT;
+		channel = v.channel;
 		
-		if (v.channel>bttv_tvcards[btv->type].video_inputs)
+		if (channel>bttv_tvcards[btv->type].video_inputs)
 			return -EINVAL;
-		if (v.norm > (sizeof(tvnorms)/sizeof(*tvnorms)))
+		if (v.norm > TVNORMS)
 			return -EOPNOTSUPP;
 
 		bttv_call_i2c_clients(btv,cmd,&v);
 		down(&btv->lock);
-		bt848_muxsel(btv, v.channel);
-		btv->channel=v.channel;
-		if (btv->win.norm != v.norm) {
-			if (btv->type == BTTV_VOODOOTV_FM)
-				bttv_tda9880_setnorm(btv,v.norm);
-			btv->win.norm = v.norm;
-			make_vbitab(btv);
-			spin_lock_irqsave(&btv->s_lock, irq_flags);
-			bt848_set_winsize(btv);
-			spin_unlock_irqrestore(&btv->s_lock, irq_flags);
-		}
+		bt848_muxsel(btv, channel);
+		bttv_set_norm(btv, v.norm);
 		up(&btv->lock);
 		return 0;
 	}
@@ -1579,10 +1726,13 @@
 	case VIDIOCSTUNER:
 	{
 		struct video_tuner v;
+		unsigned int tuner;
+		
 		if(copy_from_user(&v, arg, sizeof(v)))
 			return -EFAULT;
+		tuner = v.tuner;
 		/* Only one channel has a tuner */
-		if(v.tuner!=bttv_tvcards[btv->type].tuner)
+		if(tuner!=bttv_tvcards[btv->type].tuner)
 			return -EINVAL;
  				
 		if(v.mode!=VIDEO_MODE_PAL&&v.mode!=VIDEO_MODE_NTSC
@@ -1590,13 +1740,8 @@
 			return -EOPNOTSUPP;
 		bttv_call_i2c_clients(btv,cmd,&v);
 		if (btv->win.norm != v.mode) {
-			btv->win.norm = v.mode;
                         down(&btv->lock);
-			set_pll(btv);
-			make_vbitab(btv);
-			spin_lock_irqsave(&btv->s_lock, irq_flags);
-			bt848_set_winsize(btv);
-			spin_unlock_irqrestore(&btv->s_lock, irq_flags);
+			bttv_set_norm(btv,v.mode);
 			up(&btv->lock);
 		}
 		return 0;
@@ -1615,7 +1760,7 @@
 			return -EFAULT;
 		if (p.palette > PALETTEFMT_MAX)
 			return -EINVAL;
-		if (-1 == palette2fmt[p.palette])
+		if (UNSET == palette2fmt[p.palette])
 			return -EINVAL;
 		down(&btv->lock);
 		/* We want -128 to 127 we get 0-65535 */
@@ -1845,17 +1990,16 @@
 	case VIDIOCSAUDIO:
 	{
 		struct video_audio v;
+		unsigned int n;
 
 		if(copy_from_user(&v,arg, sizeof(v)))
 			return -EFAULT;
+		n = v.audio;
+		if(n >= bttv_tvcards[btv->type].audio_inputs)
+			return -EINVAL;
 		down(&btv->lock);
 		if(v.flags&VIDEO_AUDIO_MUTE)
 			audio(btv, AUDIO_MUTE);
-		/* One audio source per tuner -- huh? <GA> */
-		if(v.audio<0 || v.audio >= bttv_tvcards[btv->type].audio_inputs) {
-			up(&btv->lock);
-			return -EINVAL;
-		}
 		/* bt848_muxsel(btv,v.audio); */
 		if(!(v.flags&VIDEO_AUDIO_MUTE))
 			audio(btv, AUDIO_UNMUTE);
@@ -1874,10 +2018,11 @@
 	case VIDIOCSYNC:
 	{
 		DECLARE_WAITQUEUE(wait, current);
+		unsigned int i;
 
 		if(copy_from_user((void *)&i,arg,sizeof(int)))
 			return -EFAULT;
-		if (i < 0 || i >= gbuffers)
+		if (i >= gbuffers)
 			return -EINVAL;
 		switch (btv->gbuf[i].stat) {
 		case GBUFFER_UNUSED:
@@ -1949,6 +2094,8 @@
 	case VIDIOCGMBUF:
 	{
 		struct video_mbuf vm;
+		unsigned int i;
+		
 		memset(&vm, 0 , sizeof(vm));
 		vm.size=gbufsize*gbuffers;
 		vm.frames=gbuffers;
@@ -2050,17 +2197,17 @@
 
 static struct video_device bttv_template=
 {
-	owner:		THIS_MODULE,
-	name:		"UNSET",
-	type:		VID_TYPE_TUNER|VID_TYPE_CAPTURE|VID_TYPE_OVERLAY|VID_TYPE_TELETEXT,
-	hardware:	VID_HARDWARE_BT848,
-	open:		bttv_open,
-	close:		bttv_close,
-	read:		bttv_read,
-	write:		bttv_write,
-	ioctl:		bttv_ioctl,
-	mmap:		bttv_mmap,
-	minor:		-1,
+	.owner		= THIS_MODULE,
+	.name		= "UNSET",
+	.type		= VID_TYPE_TUNER|VID_TYPE_CAPTURE|VID_TYPE_OVERLAY|VID_TYPE_TELETEXT,
+	.hardware	= VID_HARDWARE_BT848,
+	.open		= bttv_open,
+	.close		= bttv_close,
+	.read		= bttv_read,
+	.write		= bttv_write,
+	.ioctl		= bttv_ioctl,
+	.mmap		= bttv_mmap,
+	.minor		= -1,
 };
 
 
@@ -2068,7 +2215,8 @@
 		     int nonblock)
 {
 	struct bttv *btv=(struct bttv *)(v-2);
-	int q,todo;
+	unsigned long todo;
+	unsigned int q;
 	DECLARE_WAITQUEUE(wait, current);
 
 	todo=count;
@@ -2172,8 +2320,8 @@
 	{
 		struct video_capability b;
 		strcpy(b.name,btv->vbi_dev.name);
-		b.type = ((bttv_tvcards[btv->type].tuner != -1) ? VID_TYPE_TUNER : 0) |
-			VID_TYPE_TELETEXT;
+		b.type = ((bttv_tvcards[btv->type].tuner != UNSET) ? VID_TYPE_TUNER : 0)
+			| VID_TYPE_TELETEXT;
 		b.channels = 0;
 		b.audios = 0;
 		b.maxwidth = 0;
@@ -2202,17 +2350,17 @@
 
 static struct video_device vbi_template=
 {
-	owner:		THIS_MODULE,
-	name:		"bttv vbi",
-	type:		VID_TYPE_CAPTURE|VID_TYPE_TELETEXT,
-	hardware:	VID_HARDWARE_BT848,
-	open:		vbi_open,
-	close:		vbi_close,
-	read:		vbi_read,
-	write:		bttv_write,
-	poll:		vbi_poll,
-	ioctl:		vbi_ioctl,
-	minor:		-1,
+	.owner		= THIS_MODULE,
+	.name		= "bttv vbi",
+	.type		= VID_TYPE_CAPTURE|VID_TYPE_TELETEXT,
+	.hardware	= VID_HARDWARE_BT848,
+	.open		= vbi_open,
+	.close		= vbi_close,
+	.read		= vbi_read,
+	.write		= bttv_write,
+	.poll		= vbi_poll,
+	.ioctl		= vbi_ioctl,
+	.minor		= -1,
 };
 
 
@@ -2321,16 +2469,16 @@
 
 static struct video_device radio_template=
 {
-	owner:		THIS_MODULE,
-	name:		"bttv radio",
-	type:		VID_TYPE_TUNER,
-	hardware:	VID_HARDWARE_BT848,
-	open:		radio_open,
-	close:		radio_close,
-	read:		radio_read,          /* just returns -EINVAL */
-	write:		bttv_write,          /* just returns -EINVAL */
-	ioctl:		radio_ioctl,
-	minor:		-1,
+	.owner		= THIS_MODULE,
+	.name		= "bttv radio",
+	.type		= VID_TYPE_TUNER,
+	.hardware	= VID_HARDWARE_BT848,
+	.open		= radio_open,
+	.close		= radio_close,
+	.read		= radio_read,          /* just returns -EINVAL */
+	.write		= bttv_write,          /* just returns -EINVAL */
+	.ioctl		= radio_ioctl,
+	.minor		= -1,
 };
 
 
@@ -2343,6 +2491,8 @@
 			flags |= 0x03;
 		if (btv->vbi_on)
 			flags |= 0x0c;
+		if (bttv_tvcards[btv->type].muxsel[btv->channel] < 0)
+			flags |= 0x0c;
 #if 0
 		/* Hmm ... */
 		if ((0 != btv->risc_cap_even) ||
@@ -2472,7 +2622,8 @@
 
 static int __devinit init_bt848(struct bttv *btv)
 {
-	int j,val;
+	int val;
+	unsigned int j;
  	unsigned long irq_flags;
 
 	btv->user=0; 
@@ -2602,15 +2753,13 @@
 	btwrite(btv->triton1|
                 /*BT848_INT_PABORT|BT848_INT_RIPERR|BT848_INT_PPERR|
                   BT848_INT_FDSR|BT848_INT_FTRGT|BT848_INT_FBUS|*/
-                (fieldnr ? BT848_INT_VSYNC : 0)|
-		BT848_INT_GPINT|
+                (fieldnr ? BT848_INT_VSYNC : 0) |
+                (gpint   ? BT848_INT_GPINT : 0) |
 		BT848_INT_SCERR|
 		BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES|
 		BT848_INT_FMTCHG|BT848_INT_HLOCK,
 		BT848_INT_MASK);
 
-	bt848_muxsel(btv, 1);
-	bt848_set_winsize(btv);
 	make_vbitab(btv);
 	spin_lock_irqsave(&btv->s_lock, irq_flags);
 	bt848_set_risc_jmps(btv,-1);
@@ -2620,12 +2769,16 @@
 	bttv_init_card1(btv);
 
 	/* register i2c */
-        btv->tuner_type=-1;
+        btv->tuner_type  = UNSET;
+        btv->pinnacle_id = UNSET;
         init_bttv_i2c(btv);
 
 	/* some card-specific stuff (needs working i2c) */
 	bttv_init_card2(btv);
 
+	bt848_muxsel(btv, 1);
+	bt848_set_winsize(btv);
+
 	/*
 	 *	Now add the template and register the device unit.
 	 */
@@ -2663,7 +2816,7 @@
 		dstat=btread(BT848_DSTATUS);
 
 		if (irq_debug) {
-			int i;
+			unsigned int i;
 			printk(KERN_DEBUG "bttv%d: irq loop=%d risc=%x, bits:",
 			       btv->nr, count, stat>>28);
 			for (i = 0; i < (sizeof(irq_name)/sizeof(char*)); i++) {
@@ -2804,7 +2957,7 @@
 static void bttv_remove(struct pci_dev *pci_dev)
 {
         u8 command;
-        int j;
+        unsigned int j;
         struct bttv *btv = pci_get_drvdata(pci_dev);
 
 	if (bttv_verbose)
@@ -2819,8 +2972,8 @@
 
         /* first disable interrupts before unmapping the memory! */
         btwrite(0, BT848_INT_MASK);
-        btwrite(~0x0UL,BT848_INT_STAT);
-        btwrite(0x0, BT848_GPIO_OUT_EN);
+        btwrite(~(u32)0,BT848_INT_STAT);
+        btwrite(0, BT848_GPIO_OUT_EN);
 	if (bttv_gpio)
 		bttv_gpio_tracking(btv,"cleanup");
 
@@ -2930,11 +3083,6 @@
         else
                 btv->i2c_command=(I2C_TIMING | BT848_I2C_SCL | BT848_I2C_SDA);
 
-	if (-1 != latency) {
-		printk(KERN_INFO "bttv%d: setting pci latency timer to %d\n",
-		       bttv_num,latency);
-		pci_write_config_byte(dev, PCI_LATENCY_TIMER, latency);
-	}
         pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision);
         pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
         printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %02x:%02x.%x, ",
@@ -3017,10 +3165,10 @@
 MODULE_DEVICE_TABLE(pci, bttv_pci_tbl);
 
 static struct pci_driver bttv_pci_driver = {
-        name:     "bttv",
-        id_table: bttv_pci_tbl,
-        probe:    bttv_probe,
-        remove:   bttv_remove,
+        .name     = "bttv",
+        .id_table = bttv_pci_tbl,
+        .probe    = bttv_probe,
+        .remove   = bttv_remove,
 };
 
 static int bttv_init_module(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/video/bttv-if.c linux-2.4.21-pre6/drivers/media/video/bttv-if.c
--- linux-2.4.20/drivers/media/video/bttv-if.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/media/video/bttv-if.c	2003-03-26 23:49:07.000000000 +0000
@@ -7,7 +7,7 @@
 
     Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
                            & Marcus Metzler (mocm@thp.uni-koeln.de)
-    (c) 1999,2000 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+    (c) 1999-2003 Gerd Knorr <kraxel@bytesex.org>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -54,7 +54,7 @@
 /*                      gpio ports (IR for example)                        */
 /*                      see bttv.h for comments                            */
 
-int bttv_get_cardinfo(unsigned int card, int *type, int *cardid)
+int bttv_get_cardinfo(unsigned int card, int *type, unsigned *cardid)
 {
 	if (card >= bttv_num) {
 		return -1;
@@ -207,36 +207,16 @@
 static int attach_inform(struct i2c_client *client)
 {
         struct bttv *btv = (struct bttv*)client->adapter->data;
-	int i;
 
-	for (i = 0; i < I2C_CLIENTS_MAX; i++) {
-		if (btv->i2c_clients[i] == NULL) {
-			btv->i2c_clients[i] = client;
-			break;
-		}
-	}
-	if (btv->tuner_type != -1)
+	if (btv->tuner_type != UNSET)
 		bttv_call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type);
-        if (bttv_verbose)
-		printk("bttv%d: i2c attach [client=%s,%s]\n",btv->nr,
-		       client->name, (i < I2C_CLIENTS_MAX) ?  "ok" : "failed");
-        return 0;
-}
-
-static int detach_inform(struct i2c_client *client)
-{
-        struct bttv *btv = (struct bttv*)client->adapter->data;
-	int i;
-
-	for (i = 0; i < I2C_CLIENTS_MAX; i++) {
-		if (btv->i2c_clients[i] == client) {
-			btv->i2c_clients[i] = NULL;
-			break;
-		}
-	}
-        if (bttv_verbose)
-		printk("bttv%d: i2c detach [client=%s,%s]\n",btv->nr,
-		       client->name, (i < I2C_CLIENTS_MAX) ?  "ok" : "failed");
+	if (btv->pinnacle_id != UNSET)
+		bttv_call_i2c_clients(btv,AUDC_CONFIG_PINNACLE,
+				      &btv->pinnacle_id);
+
+        if (bttv_debug)
+		printk("bttv%d: i2c attach [client=%s]\n",
+		       btv->nr,client->name);
         return 0;
 }
 
@@ -245,12 +225,12 @@
 	int i;
 	
 	for (i = 0; i < I2C_CLIENTS_MAX; i++) {
-		if (NULL == btv->i2c_clients[i])
+		if (NULL == btv->i2c_adap.clients[i])
 			continue;
-		if (NULL == btv->i2c_clients[i]->driver->command)
+		if (NULL == btv->i2c_adap.clients[i]->driver->command)
 			continue;
-		btv->i2c_clients[i]->driver->command(
-			btv->i2c_clients[i],cmd,arg);
+		btv->i2c_adap.clients[i]->driver->command
+			(btv->i2c_adap.clients[i],cmd,arg);
 	}
 }
 
@@ -262,27 +242,26 @@
 }
 
 static struct i2c_algo_bit_data bttv_i2c_algo_template = {
-	setsda:  bttv_bit_setsda,
-	setscl:  bttv_bit_setscl,
-	getsda:  bttv_bit_getsda,
-	getscl:  bttv_bit_getscl,
-	udelay:  16,
-	mdelay:  10,
-	timeout: 200,
+	.setsda  = bttv_bit_setsda,
+	.setscl  = bttv_bit_setscl,
+	.getsda  = bttv_bit_getsda,
+	.getscl  = bttv_bit_getscl,
+	.udelay  = 16,
+	.mdelay  = 10,
+	.timeout = 200,
 };
 
 static struct i2c_adapter bttv_i2c_adap_template = {
-	name:              "bt848",
-	id:                I2C_HW_B_BT848,
-	inc_use:           bttv_inc_use,
-	dec_use:           bttv_dec_use,
-	client_register:   attach_inform,
-	client_unregister: detach_inform,
+	.inc_use           = bttv_inc_use,
+	.dec_use           = bttv_dec_use,
+	.name              = "bt848",
+	.id                = I2C_HW_B_BT848,
+	.client_register   = attach_inform,
 };
 
 static struct i2c_client bttv_i2c_client_template = {
-        name: "bttv internal use only",
-        id:   -1,
+        .name = "bttv internal use only",
+        .id   = -1,
 };
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/video/bttv.h linux-2.4.21-pre6/drivers/media/video/bttv.h
--- linux-2.4.20/drivers/media/video/bttv.h	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/media/video/bttv.h	2003-03-26 23:49:07.000000000 +0000
@@ -90,11 +90,32 @@
 #define BTTV_SENSORAY311    0x49
 #define BTTV_RV605          0x4a
 #define BTTV_WINDVR         0x4c
+#define BTTV_KWORLD         0x4e
 #define BTTV_HAUPPAUGEPVR   0x50
+#define BTTV_GVBCTV5PCI     0x51
+#define BTTV_OSPREY1x0      0x52
+#define BTTV_OSPREY1x0_848  0x53
+#define BTTV_OSPREY101_848  0x54
+#define BTTV_OSPREY1x1      0x55
+#define BTTV_OSPREY1x1_SVID 0x56
+#define BTTV_OSPREY2xx      0x57
+#define BTTV_OSPREY2x0_SVID 0x58
+#define BTTV_OSPREY2x0      0x59
+#define BTTV_OSPREY500      0x5a
+#define BTTV_OSPREY540      0x5b
+#define BTTV_OSPREY2000     0x5c
+#define BTTV_IDS_EAGLE      0x5d
+#define BTTV_PINNACLESAT    0x5e
+#define BTTV_FORMAC_PROTV   0x5f
+#define BTTV_EURESYS_PICOLO 0x61
+#define BTTV_PV150          0x62
+#define BTTV_AD_TVK503      0x63
 
 /* i2c address list */
 #define I2C_TSA5522        0xc2
 #define I2C_TDA7432        0x8a
+#define I2C_BT832_ALT1	   0x88
+#define I2C_BT832_ALT2	   0x8a // alternate setting
 #define I2C_TDA8425        0x82
 #define I2C_TDA9840        0x84
 #define I2C_TDA9850        0xb6 /* also used by 9855,9873 */
@@ -104,8 +125,10 @@
 #define I2C_STBEE          0xae
 #define I2C_VHX            0xc0
 #define I2C_MSP3400        0x80
+#define I2C_MSP3400_ALT    0x88
 #define I2C_TEA6300        0x80
 #define I2C_DPL3518	   0x84
+#define I2C_TDA9887	   0x86
 
 /* more card-specific defines */
 #define PT2254_L_CHANNEL 0x10
@@ -116,39 +139,46 @@
 #define WINVIEW_PT2254_DATA 0x20
 #define WINVIEW_PT2254_STROBE 0x80
 
+/* digital_mode */
+#define DIGITAL_MODE_VIDEO 1
+#define DIGITAL_MODE_CAMERA 2
+
 struct bttv;
 
 struct tvcard
 {
         char *name;
-        int video_inputs;
-        int audio_inputs;
-        int tuner;
-        int svhs;
+        unsigned int video_inputs;
+        unsigned int audio_inputs;
+        unsigned int tuner;
+        unsigned int svhs;
+	unsigned int digital_mode; // DIGITAL_MODE_CAMERA or DIGITAL_MODE_VIDEO
         u32 gpiomask;
         u32 muxsel[16];
         u32 audiomux[6]; /* Tuner, Radio, external, internal, mute, stereo */
         u32 gpiomask2;   /* GPIO MUX mask */
 
 	/* i2c audio flags */
-	int no_msp34xx:1;
-	int no_tda9875:1;
-	int needs_tvaudio:1;
+	unsigned int no_msp34xx:1;
+	unsigned int no_tda9875:1;
+	unsigned int no_tda7432:1;
+	unsigned int needs_tvaudio:1;
+	unsigned int msp34xx_alt:1;
 
 	/* other settings */
-	int pll;
+	unsigned int pll;
 #define PLL_NONE 0
 #define PLL_28   1
 #define PLL_35   2
 
-	int tuner_type;
-	int has_radio;
+	unsigned int tuner_type;
+	unsigned int has_radio;
 	void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set);
 	void (*muxsel_hook)(struct bttv *btv, unsigned int input);
 };
 
 extern struct tvcard bttv_tvcards[];
-extern const int bttv_num_tvcards;
+extern const unsigned int bttv_num_tvcards;
 
 /* identification / initialization of the card */
 extern void bttv_idcard(struct bttv *btv);
@@ -174,7 +204,8 @@
    for possible values see lines below beginning with #define BTTV_UNKNOWN
    returns negative value if error occurred 
 */
-extern int bttv_get_cardinfo(unsigned int card, int *type, int *cardid);
+extern int bttv_get_cardinfo(unsigned int card, int *type,
+			     unsigned int *cardid);
 extern struct pci_dev* bttv_get_pcidev(unsigned int card);
 
 /* obsolete, use bttv_get_cardinfo instead */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/video/bttvp.h linux-2.4.21-pre6/drivers/media/video/bttvp.h
--- linux-2.4.20/drivers/media/video/bttvp.h	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/media/video/bttvp.h	2003-03-26 23:49:29.000000000 +0000
@@ -25,7 +25,7 @@
 #ifndef _BTTVP_H_
 #define _BTTVP_H_
 
-#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,96)
+#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,104)
 
 #include <linux/types.h>
 #include <linux/wait.h>
@@ -42,7 +42,7 @@
 /* bttv-driver.c                                              */
 
 /* insmod options / kernel args */
-extern int no_overlay;
+extern unsigned int no_overlay;
 extern unsigned int bttv_verbose;
 extern unsigned int bttv_debug;
 extern unsigned int bttv_gpio;
@@ -50,17 +50,15 @@
 extern int init_bttv_i2c(struct bttv *btv);
 extern int pvr_boot(struct bttv *btv);
 
-#define dprintk		if (bttv_debug) printk
+#define dprintk		if (bttv_debug)   printk
+#define vprintk		if (bttv_verbose) printk
 
 /* Anybody who uses more than four? */
 #define BTTV_MAX 4
-extern int bttv_num;			/* number of Bt848s in use */
+extern unsigned int bttv_num;			/* number of Bt848s in use */
 extern struct bttv bttvs[BTTV_MAX];
 
-
-#ifndef O_NONCAP  
-#define O_NONCAP	O_TRUNC
-#endif
+#define UNSET -1U
 
 #ifdef VIDEODAT_HACK
 # define VBI_MAXLINES   19
@@ -120,18 +118,17 @@
 
 	spinlock_t s_lock;
         struct semaphore lock;
-	int user;
-	int capuser;
+	unsigned int user;
 
 	/* i2c */
 	struct i2c_adapter         i2c_adap;
 	struct i2c_algo_bit_data   i2c_algo;
 	struct i2c_client          i2c_client;
 	int                        i2c_state, i2c_rc;
-	struct i2c_client         *i2c_clients[I2C_CLIENTS_MAX];
 
-        int tuner_type;
-        int channel;
+        unsigned int tuner_type;
+        unsigned int pinnacle_id;
+        unsigned int channel;
         
         unsigned int nr;
 	unsigned short id;
@@ -146,7 +143,7 @@
 	struct bttv_window win;
 	int fb_color_ctl;
 	int type;            /* card type  */
-	int cardid;
+	unsigned int cardid;
 	int audio;           /* audio mode */
 	int audio_chip;      /* set to one of the chips supported by bttv.c */
 	int radio;
@@ -161,6 +158,11 @@
 	int mbox_most;
 	int mbox_mask;
 
+	/* ISA stuff (Terratec Active Radio Upgrade) */
+	int mbox_ior;
+	int mbox_iow;
+	int mbox_csel;
+
 	u32 *risc_jmp;
 	u32 *vbi_odd;
 	u32 *vbi_even;
@@ -168,7 +170,7 @@
 	u32 bus_vbi_odd;
         wait_queue_head_t vbiq;
 	wait_queue_head_t capq;
-	int vbip;
+	unsigned int vbip;
 
 	u32 *risc_scr_odd;
 	u32 *risc_scr_even;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/video/cpia.c linux-2.4.21-pre6/drivers/media/video/cpia.c
--- linux-2.4.20/drivers/media/video/cpia.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/media/video/cpia.c	2003-03-26 23:49:50.000000000 +0000
@@ -6,6 +6,7 @@
  * (C) Copyright 1999-2000 Peter Pregler
  * (C) Copyright 1999-2000 Scott J. Bertin
  * (C) Copyright 1999-2000 Johannes Erdfelt <johannes@erdfelt.com>
+ * (C) Copyright 2000 STMicroelectronics
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -22,7 +23,9 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-/* #define _CPIA_DEBUG_		define for verbose debug output */
+/* define _CPIA_DEBUG_ for verbose debug output (see cpia.h) */
+/* #define _CPIA_DEBUG_  1 */  
+
 #include <linux/config.h>
 
 #include <linux/module.h>
@@ -512,6 +515,46 @@
 	return len;
 }
 
+static int match(char *checkstr, char **buffer, unsigned long *count,
+                 int *find_colon, int *err)
+{
+	int ret, colon_found = 1;
+	int len = strlen(checkstr);
+	ret = (len <= *count && strncmp(*buffer, checkstr, len) == 0);
+	if (ret) {
+		*buffer += len;
+		*count -= len;
+		if (*find_colon) {
+			colon_found = 0;
+			while (*count && (**buffer == ' ' || **buffer == '\t' ||
+			       (!colon_found && **buffer == ':'))) {
+				if (**buffer == ':')
+					colon_found = 1;
+				--*count;
+				++*buffer;
+			}
+			if (!*count || !colon_found)
+				*err = -EINVAL;
+			*find_colon = 0;
+		}
+	}
+	return ret;
+}
+
+static unsigned long int value(char **buffer, unsigned long *count, int *err)
+{
+	char *p;
+	unsigned long int ret;
+	ret = simple_strtoul(*buffer, &p, 0);
+	if (p == *buffer)
+		*err = -EINVAL;
+	else {
+		*count -= p - *buffer;
+		*buffer = p;
+	}
+	return ret;
+}
+
 static int cpia_write_proc(struct file *file, const char *buf,
                            unsigned long count, void *data)
 {
@@ -566,44 +609,11 @@
 	memcpy(&new_params, &cam->params, sizeof(struct cam_params));
 	new_mains = cam->mainsFreq;
 	
-#define MATCH(x) \
-	({ \
-		int _len = strlen(x), _ret, _colon_found; \
-		_ret = (_len <= count && strncmp(buffer, x, _len) == 0); \
-		if (_ret) { \
-			buffer += _len; \
-			count -= _len; \
-			if (find_colon) { \
-				_colon_found = 0; \
-				while (count && (*buffer == ' ' || *buffer == '\t' || \
-				       (!_colon_found && *buffer == ':'))) { \
-					if (*buffer == ':')  \
-						_colon_found = 1; \
-					--count; \
-					++buffer; \
-				} \
-				if (!count || !_colon_found) \
-					retval = -EINVAL; \
-				find_colon = 0; \
-			} \
-		} \
-		_ret; \
-	})
+#define MATCH(x) (match(x, &buffer, &count, &find_colon, &retval))
+#define VALUE (value(&buffer,&count, &retval))
 #define FIRMWARE_VERSION(x,y) (new_params.version.firmwareVersion == (x) && \
                                new_params.version.firmwareRevision == (y))
-#define VALUE \
-	({ \
-		char *_p; \
-		unsigned long int _ret; \
-		_ret = simple_strtoul(buffer, &_p, 0); \
-		if (_p == buffer) \
-			retval = -EINVAL; \
-		else { \
-			count -= _p - buffer; \
-			buffer = _p; \
-		} \
-		_ret; \
-	})
+
 
 	retval = 0;
 	while (count && !retval) {
@@ -1248,10 +1258,9 @@
 		}
 	}
 #undef MATCH	
-#undef FIRMWARE_VERSION
 #undef VALUE
-#undef FIND_VALUE
-#undef FIND_END
+#undef FIRMWARE_VERSION
+
 	if (!retval) {
 		if (command_flags & COMMAND_SETCOLOURPARAMS) {
 			/* Adjust cam->vp to reflect these changes */
@@ -1560,7 +1569,7 @@
 }
 
 
-static void inline free_frames(struct cpia_frame frame[FRAME_NUM])
+static inline void free_frames(struct cpia_frame frame[FRAME_NUM])
 {
 	int i;
 
@@ -1745,7 +1754,7 @@
 
 	retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
 	if (retval)
-		LOG("%x - failed\n", command);
+		DBG("%x - failed\n", command);
 
 	return retval;
 }
@@ -1970,7 +1979,7 @@
 	while (size > 0) {
 		size -= (ll+2);
 		if (size < 0) {
-			LOG("Insufficient data in buffer\n");
+			DBG("Insufficient data in buffer\n");
 			return -1;
 		}
 
@@ -1985,7 +1994,7 @@
 				int skipsize = skipcount(*ibuf >> 1, out_fmt);
 				obuf += skipsize;
 				if (obuf > end_obuf) {
-					LOG("Insufficient data in buffer\n");
+					DBG("Insufficient data in buffer\n");
 					return -1;
 				}
 				++ibuf;
@@ -1994,7 +2003,7 @@
 		}
 		if (ll == 1) {
 			if (*ibuf != EOL) {
-				LOG("EOL not found giving up after %d/%d"
+				DBG("EOL not found giving up after %d/%d"
 				    " bytes\n", origsize-size, origsize);
 				return -1;
 			}
@@ -2012,7 +2021,7 @@
 				ibuf += 2; /* skip over line length */
 			}
 		} else {
-			LOG("line length was not 1 but %d after %d/%d bytes\n",
+			DBG("line length was not 1 but %d after %d/%d bytes\n",
 			    ll, origsize-size, origsize);
 			return -1;
 		}
@@ -2501,54 +2510,56 @@
 	return 0;
 }
 
+static void put_cam(struct cpia_camera_ops* ops)
+{
+	if (ops->owner)
+		__MOD_DEC_USE_COUNT(ops->owner);
+}
+
 /* ------------------------- V4L interface --------------------- */
-static int cpia_open(struct video_device *dev, int flags)
+static int cpia_open(struct inode *inode, struct file *file)
 {
-	int i;
+	struct video_device *dev = video_devdata(file);
 	struct cam_data *cam = dev->priv;
+	int err;
 
 	if (!cam) {
 		DBG("Internal error, cam_data not found!\n");
-		return -EBUSY;
+		return -ENODEV;
 	}
-	    
+
 	if (cam->open_count > 0) {
 		DBG("Camera already open\n");
 		return -EBUSY;
 	}
-	
+
+	if (!try_inc_mod_count(cam->ops->owner))
+	  return -ENODEV;
+
+	down(&cam->busy_lock);
+
+	err = -ENOMEM;	
 	if (!cam->raw_image) {
 		cam->raw_image = rvmalloc(CPIA_MAX_IMAGE_SIZE);
 		if (!cam->raw_image)
-			return -ENOMEM;
+			goto oops;
 	}
 
 	if (!cam->decompressed_frame.data) {
 		cam->decompressed_frame.data = rvmalloc(CPIA_MAX_FRAME_SIZE);
-		if (!cam->decompressed_frame.data) {
-			rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
-			cam->raw_image = NULL;
-			return -ENOMEM;
-		}
+		if (!cam->decompressed_frame.data) 
+			goto oops;
 	}
 	
 	/* open cpia */
-	if (cam->ops->open(cam->lowlevel_data)) {
-		rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
-		cam->decompressed_frame.data = NULL;
-		rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
-		cam->raw_image = NULL;
-		return -ENODEV;
-	}
+	err = -ENODEV;
+	if (cam->ops->open(cam->lowlevel_data)) 
+		goto oops;
 	
 	/* reset the camera */
-	if ((i = reset_camera(cam)) != 0) {
+	if ((err = reset_camera(cam)) != 0) {
 		cam->ops->close(cam->lowlevel_data);
-		rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
-		cam->decompressed_frame.data = NULL;
-		rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
-		cam->raw_image = NULL;
-		return i;
+		goto oops;
 	}
 	
 	/* Set ownership of /proc/cpia/videoX to current user */
@@ -2562,14 +2573,28 @@
 	cam->mmap_kludge = 0;
 	
 	++cam->open_count;
+	file->private_data = dev;
+	up(&cam->busy_lock);
 	return 0;
+
+ oops:
+	if (cam->decompressed_frame.data) {
+		rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
+		cam->decompressed_frame.data = NULL;
+	}
+	if (cam->raw_image) {
+		rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
+		cam->raw_image = NULL;
+	}
+	up(&cam->busy_lock);
+	put_cam(cam->ops);
+	return err;
 }
 
-static void cpia_close(struct video_device *dev)
+static int cpia_close(struct inode *inode, struct file *file)
 {
-	struct cam_data *cam;
-
-	cam = dev->priv;
+	struct  video_device *dev = file->private_data;
+	struct cam_data *cam = dev->priv;
 
 	if (cam->ops) {
 	        /* Return ownership of /proc/cpia/videoX to root */
@@ -2590,6 +2615,7 @@
 
 		/* close cpia */
 		cam->ops->close(cam->lowlevel_data);
+		put_cam(cam->ops);
 	}
 
 	if (--cam->open_count == 0) {
@@ -2607,20 +2633,20 @@
 		if (cam->frame_buf)
 			free_frame_buf(cam);
 
-		if (!cam->ops) {
-			video_unregister_device(dev);
+		if (!cam->ops) 
 			kfree(cam);
-		}
 	}
 	
+	file->private_data = NULL;
 
-	return;
+	return 0;
 }
 
-static long cpia_read(struct video_device *dev, char *buf,
-                      unsigned long count, int noblock)
+static int cpia_read(struct file *file, char *buf,
+		     size_t count, loff_t *ppos)
 {
-	struct cam_data *cam = dev->priv;
+	struct video_device *dev = file->private_data;
+ 	struct cam_data *cam = dev->priv;
 
 	/* make this _really_ smp and multithread-safe */
 	if (down_interruptible(&cam->busy_lock))
@@ -2659,7 +2685,7 @@
 	/* copy data to user space */
 	if (cam->decompressed_frame.count > count) {
 		DBG("count wrong: %d, %lu\n", cam->decompressed_frame.count,
-		    count);
+		    (unsigned long) count);
 		up(&cam->busy_lock);
 		return -EFAULT;
 	}
@@ -2674,8 +2700,10 @@
 	return cam->decompressed_frame.count;
 }
 
-static int cpia_ioctl(struct video_device *dev, unsigned int ioctlnr, void *arg)
+static int cpia_do_ioctl(struct inode *inode, struct file *file,
+			 unsigned int ioctlnr, void *arg)
 {
+	struct video_device *dev = file->private_data;
 	struct cam_data *cam = dev->priv;
 	int retval = 0;
 
@@ -2692,20 +2720,17 @@
 	/* query capabilites */
 	case VIDIOCGCAP:
 	{
-		struct video_capability b;
+		struct video_capability *b = arg;
 
 		DBG("VIDIOCGCAP\n");
-		strcpy(b.name, "CPiA Camera");
-		b.type = VID_TYPE_CAPTURE;
-		b.channels = 1;
-		b.audios = 0;
-		b.maxwidth = 352;	/* VIDEOSIZE_CIF */
-		b.maxheight = 288;
-		b.minwidth = 48;	/* VIDEOSIZE_48_48 */
-		b.minheight = 48;
-
-		if (copy_to_user(arg, &b, sizeof(b)))
-			retval = -EFAULT;
+		strcpy(b->name, "CPiA Camera");
+		b->type = VID_TYPE_CAPTURE;
+		b->channels = 1;
+		b->audios = 0;
+		b->maxwidth = 352;	/* VIDEOSIZE_CIF */
+		b->maxheight = 288;
+		b->minwidth = 48;	/* VIDEOSIZE_48_48 */
+		b->minheight = 48;
 
 		break;
 	}
@@ -2713,39 +2738,30 @@
 	/* get/set video source - we are a camera and nothing else */
 	case VIDIOCGCHAN:
 	{
-		struct video_channel v;
+		struct video_channel *v = arg;
 
 		DBG("VIDIOCGCHAN\n");
-		if (copy_from_user(&v, arg, sizeof(v))) {
-			retval = -EFAULT;
-			break;
-		}
-		if (v.channel != 0) {
+		if (v->channel != 0) {
 			retval = -EINVAL;
 			break;
 		}
 
-		v.channel = 0;
-		strcpy(v.name, "Camera");
-		v.tuners = 0;
-		v.flags = 0;
-		v.type = VIDEO_TYPE_CAMERA;
-		v.norm = 0;
+		v->channel = 0;
+		strcpy(v->name, "Camera");
+		v->tuners = 0;
+		v->flags = 0;
+		v->type = VIDEO_TYPE_CAMERA;
+		v->norm = 0;
 
-		if (copy_to_user(arg, &v, sizeof(v)))
-			retval = -EFAULT;
 		break;
 	}
 	
 	case VIDIOCSCHAN:
 	{
-		int v;
+		struct video_channel *v = arg;
 
 		DBG("VIDIOCSCHAN\n");
-		if (copy_from_user(&v, arg, sizeof(v)))
-			retval = -EFAULT;
-
-		if (retval == 0 && v != 0)
+		if (v->channel != 0)
 			retval = -EINVAL;
 
 		break;
@@ -2753,38 +2769,35 @@
 
 	/* image properties */
 	case VIDIOCGPICT:
+	{
+ 		struct video_picture *pic = arg;
+
 		DBG("VIDIOCGPICT\n");
-		if (copy_to_user(arg, &cam->vp, sizeof(struct video_picture)))
-			retval = -EFAULT;
+ 		*pic = cam->vp;
 		break;
-	
+	}
+
 	case VIDIOCSPICT:
 	{
-		struct video_picture vp;
+		struct video_picture *vp = arg;
 
 		DBG("VIDIOCSPICT\n");
 
-		/* copy_from_user */
-		if (copy_from_user(&vp, arg, sizeof(vp))) {
-			retval = -EFAULT;
-			break;
-		}
-
 		/* check validity */
-		DBG("palette: %d\n", vp.palette);
-		DBG("depth: %d\n", vp.depth);
-		if (!valid_mode(vp.palette, vp.depth)) {
+		DBG("palette: %d\n", vp->palette);
+		DBG("depth: %d\n", vp->depth);
+		if (!valid_mode(vp->palette, vp->depth)) {
 			retval = -EINVAL;
 			break;
 		}
 
 		down(&cam->param_lock);
 		/* brightness, colour, contrast need no check 0-65535 */
-		memcpy( &cam->vp, &vp, sizeof(vp) );
+		cam->vp = *vp;
 		/* update cam->params.colourParams */
-		cam->params.colourParams.brightness = vp.brightness*100/65535;
-		cam->params.colourParams.contrast = vp.contrast*100/65535;
-		cam->params.colourParams.saturation = vp.colour*100/65535;
+		cam->params.colourParams.brightness = vp->brightness*100/65535;
+		cam->params.colourParams.contrast = vp->contrast*100/65535;
+		cam->params.colourParams.saturation = vp->colour*100/65535;
 		/* contrast is in steps of 8, so round */
 		cam->params.colourParams.contrast =
 			((cam->params.colourParams.contrast + 3) / 8) * 8;
@@ -2799,34 +2812,33 @@
 		cam->cmd_queue |= COMMAND_SETCOLOURPARAMS;
 		up(&cam->param_lock);
 		DBG("VIDIOCSPICT: %d / %d // %d / %d / %d / %d\n",
-		    vp.depth, vp.palette, vp.brightness, vp.hue, vp.colour,
-		    vp.contrast);
+		    vp->depth, vp->palette, vp->brightness, vp->hue, 
+		    vp->colour, vp->contrast);
 		break;
 	}
 
 	/* get/set capture window */
 	case VIDIOCGWIN:
+	{
+		struct video_window *vw = arg;
+
 		DBG("VIDIOCGWIN\n");
 
-		if (copy_to_user(arg, &cam->vw, sizeof(struct video_window)))
-			retval = -EFAULT;
+		*vw = cam->vw;
 		break;
-	
+	}	
+
 	case VIDIOCSWIN:
 	{
 		/* copy_from_user, check validity, copy to internal structure */
-		struct video_window vw;
+		struct video_window *vw = arg;
 		DBG("VIDIOCSWIN\n");
-		if (copy_from_user(&vw, arg, sizeof(vw))) {
-			retval = -EFAULT;
-			break;
-		}
 
-		if (vw.clipcount != 0) {    /* clipping not supported */
+		if (vw->clipcount != 0) {    /* clipping not supported */
 			retval = -EINVAL;
 			break;
 		}
-		if (vw.clips != NULL) {     /* clipping not supported */
+		if (vw->clips != NULL) {     /* clipping not supported */
 			retval = -EINVAL;
 			break;
 		}
@@ -2835,8 +2847,8 @@
 		* is requested by the user???
 		*/
 		down(&cam->param_lock);
-		if (vw.width != cam->vw.width || vw.height != cam->vw.height) {
-			int video_size = match_videosize(vw.width, vw.height);
+		if (vw->width != cam->vw.width || vw->height != cam->vw.height) {
+			int video_size = match_videosize(vw->width, vw->height);
 
 			if (video_size < 0) {
 				retval = -EINVAL;
@@ -2865,41 +2877,34 @@
 	/* mmap interface */
 	case VIDIOCGMBUF:
 	{
-		struct video_mbuf vm;
+		struct video_mbuf *vm = arg;
 		int i;
 
 		DBG("VIDIOCGMBUF\n");
-		memset(&vm, 0, sizeof(vm));
-		vm.size = CPIA_MAX_FRAME_SIZE*FRAME_NUM;
-		vm.frames = FRAME_NUM;
+		memset(vm, 0, sizeof(*vm));
+		vm->size = CPIA_MAX_FRAME_SIZE*FRAME_NUM;
+		vm->frames = FRAME_NUM;
 		for (i = 0; i < FRAME_NUM; i++)
-			vm.offsets[i] = CPIA_MAX_FRAME_SIZE * i;
-
-		if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
-			retval = -EFAULT;
+			vm->offsets[i] = CPIA_MAX_FRAME_SIZE * i;
 
 		break;
 	}
 	
 	case VIDIOCMCAPTURE:
 	{
-		struct video_mmap vm;
+		struct video_mmap *vm = arg;
 		int video_size;
 
-		if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm))) {
-			retval = -EFAULT;
-			break;
-		}
-		DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm.format, vm.frame,
-		    vm.width, vm.height);
-		if (vm.frame<0||vm.frame>=FRAME_NUM) {
+		DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm->format, vm->frame,
+		    vm->width, vm->height);
+		if (vm->frame<0||vm->frame>=FRAME_NUM) {
 			retval = -EINVAL;
 			break;
 		}
 
 		/* set video format */
-		cam->vp.palette = vm.format;
-		switch(vm.format) {
+		cam->vp.palette = vm->format;
+		switch(vm->format) {
 		case VIDEO_PALETTE_GREY:
 			cam->vp.depth=8;
 			break;
@@ -2924,7 +2929,7 @@
 			break;
 
 		/* set video size */
-		video_size = match_videosize(vm.width, vm.height);
+		video_size = match_videosize(vm->width, vm->height);
 		if (video_size < 0) {
 			retval = -EINVAL;
 			break;
@@ -2937,37 +2942,33 @@
 		}
 		/* according to v4l-spec we must start streaming here */
 		cam->mmap_kludge = 1;
-		retval = capture_frame(cam, &vm);
+		retval = capture_frame(cam, vm);
 
 		break;
 	}
 	
 	case VIDIOCSYNC:
 	{
-		int frame;
+		int *frame = arg;
 
-		if (copy_from_user((void *)&frame, arg, sizeof(int))) {
-			retval = -EFAULT;
-			break;
-		}
-		//DBG("VIDIOCSYNC: %d\n", frame);
+		//DBG("VIDIOCSYNC: %d\n", *frame);
 
-		if (frame<0 || frame >= FRAME_NUM) {
+		if (*frame<0 || *frame >= FRAME_NUM) {
 			retval = -EINVAL;
 			break;
 		}
 
-		switch (cam->frame[frame].state) {
+		switch (cam->frame[*frame].state) {
 		case FRAME_UNUSED:
 		case FRAME_READY:
 		case FRAME_GRABBING:
-			DBG("sync to unused frame %d\n", frame);
+			DBG("sync to unused frame %d\n", *frame);
 			retval = -EINVAL;
 			break;
 
 		case FRAME_DONE:
-			cam->frame[frame].state = FRAME_UNUSED;
-			//DBG("VIDIOCSYNC: %d synced\n", frame);
+			cam->frame[*frame].state = FRAME_UNUSED;
+			//DBG("VIDIOCSYNC: %d synced\n", *frame);
 			break;
 		}
 		if (retval == -EINTR) {
@@ -2979,36 +2980,22 @@
 
 	/* pointless to implement overlay with this camera */
 	case VIDIOCCAPTURE:
-		retval = -EINVAL;
-		break;
 	case VIDIOCGFBUF:
-		retval = -EINVAL;
-		break;
 	case VIDIOCSFBUF:
-		retval = -EINVAL;
-		break;
 	case VIDIOCKEY:
 		retval = -EINVAL;
 		break;
 
 	/* tuner interface - we have none */
 	case VIDIOCGTUNER:
-		retval = -EINVAL;
-		break;
 	case VIDIOCSTUNER:
-		retval = -EINVAL;
-		break;
 	case VIDIOCGFREQ:
-		retval = -EINVAL;
-		break;
 	case VIDIOCSFREQ:
 		retval = -EINVAL;
 		break;
 
 	/* audio interface - we have none */
 	case VIDIOCGAUDIO:
-		retval = -EINVAL;
-		break;
 	case VIDIOCSAUDIO:
 		retval = -EINVAL;
 		break;
@@ -3017,16 +3004,23 @@
 		break;
 	}
 
-	up(&cam->param_lock);
 	up(&cam->busy_lock);
 	return retval;
 } 
 
+static int cpia_ioctl(struct inode *inode, struct file *file,
+		     unsigned int cmd, unsigned long arg)
+{
+	return video_usercopy(inode, file, cmd, arg, cpia_do_ioctl);
+}
+
+
 /* FIXME */
-static int cpia_mmap(struct video_device *dev, const char *adr,
-                     unsigned long size)
+static int cpia_mmap(struct file *file, struct vm_area_struct *vma)
 {
-	unsigned long start = (unsigned long)adr;
+	struct video_device *dev = file->private_data;
+	unsigned long start = vma->vm_start;
+	unsigned long size  = vma->vm_end - vma->vm_start;
 	unsigned long page, pos;
 	struct cam_data *cam = dev->priv;
 	int retval;
@@ -3074,25 +3068,22 @@
 	return 0;
 }
 
-int cpia_video_init(struct video_device *vdev)
-{
-#ifdef CONFIG_PROC_FS
-	create_proc_cpia_cam(vdev->priv);
-#endif
-	return 0;
-}
+static struct file_operations cpia_fops = {
+	owner:		THIS_MODULE,
+	open:		cpia_open,
+	release:	cpia_close,
+	read:		cpia_read,
+	mmap:		cpia_mmap,
+	ioctl:		cpia_ioctl,
+	llseek:         no_llseek,
+};
 
 static struct video_device cpia_template = {
 	owner:		THIS_MODULE,
 	name:		"CPiA Camera",
 	type:		VID_TYPE_CAPTURE,
 	hardware:	VID_HARDWARE_CPIA,
-	open:		cpia_open,
-	close:		cpia_close,
-	read:		cpia_read,
-	ioctl:		cpia_ioctl,
-	mmap:		cpia_mmap,
-	initialize:	cpia_video_init,
+	fops:           &cpia_fops,
 	minor:		-1,
 };
 
@@ -3229,16 +3220,10 @@
 
 struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowlevel)
 {
-        struct cam_data *camera;
-	
-	/* Need a lock when adding/removing cameras.  This doesn't happen
-	 * often and doesn't take very long, so grabbing the kernel lock
-	 * should be OK. */
+	struct cam_data *camera;
 	
-	if ((camera = kmalloc(sizeof(struct cam_data), GFP_KERNEL)) == NULL) {
-		unlock_kernel();
+	if ((camera = kmalloc(sizeof(struct cam_data), GFP_KERNEL)) == NULL)
 		return NULL;
-	}
 	
 	init_camera_struct( camera, ops );
 	camera->lowlevel_data = lowlevel;
@@ -3246,7 +3231,6 @@
 	/* register v4l device */
 	if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
 		kfree(camera);
-		unlock_kernel();
 		printk(KERN_DEBUG "video_register_device failed\n");
 		return NULL;
 	}
@@ -3266,6 +3250,10 @@
 	/* close cpia */
 	camera->ops->close(camera->lowlevel_data);
 
+#ifdef CONFIG_PROC_FS
+	create_proc_cpia_cam(camera);
+#endif
+
 	printk(KERN_INFO "  CPiA Version: %d.%02d (%d.%d)\n",
 	       camera->params.version.firmwareVersion,
 	       camera->params.version.firmwareRevision,
@@ -3285,12 +3273,10 @@
 
 void cpia_unregister_camera(struct cam_data *cam)
 {
-	if (!cam->open_count) {
-		DBG("unregistering video\n");
-		video_unregister_device(&cam->vdev);
-	} else {
-		LOG("/dev/video%d removed while open, "
-		    "deferring video_unregister_device\n", cam->vdev.minor);
+	DBG("unregistering video\n");
+	video_unregister_device(&cam->vdev);
+	if (cam->open_count) {
+		put_cam(cam->ops);
 		DBG("camera open -- setting ops to NULL\n");
 		cam->ops = NULL;
 	}
@@ -3313,9 +3299,6 @@
 	proc_cpia_create();
 #endif
 
-#ifdef CONFIG_VIDEO_CPIA_PP
-	cpia_pp_init();
-#endif
 #ifdef CONFIG_KMOD
 #ifdef CONFIG_VIDEO_CPIA_PP_MODULE
 	request_module("cpia_pp");
@@ -3325,6 +3308,10 @@
 	request_module("cpia_usb");
 #endif
 #endif	/* CONFIG_KMOD */
+
+#ifdef CONFIG_VIDEO_CPIA_PP
+	cpia_pp_init();
+#endif
 #ifdef CONFIG_VIDEO_CPIA_USB
 	cpia_usb_init();
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/video/cpia.h linux-2.4.21-pre6/drivers/media/video/cpia.h
--- linux-2.4.20/drivers/media/video/cpia.h	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/media/video/cpia.h	2003-03-26 23:49:54.000000000 +0000
@@ -27,12 +27,16 @@
  */
 
 #define CPIA_MAJ_VER	0
-#define CPIA_MIN_VER    8
-#define CPIA_PATCH_VER	1
+#define CPIA_MIN_VER   8
+#define CPIA_PATCH_VER	5
 
-#define CPIA_PP_MAJ_VER       0
-#define CPIA_PP_MIN_VER       8
-#define CPIA_PP_PATCH_VER     1
+#define CPIA_PP_MAJ_VER       CPIA_MAJ_VER
+#define CPIA_PP_MIN_VER       CPIA_MIN_VER
+#define CPIA_PP_PATCH_VER     CPIA_PATCH_VER
+
+#define CPIA_USB_MAJ_VER      CPIA_MAJ_VER
+#define CPIA_USB_MIN_VER      CPIA_MIN_VER
+#define CPIA_USB_PATCH_VER    CPIA_PATCH_VER
 
 #define CPIA_MAX_FRAME_SIZE_UNALIGNED	(352 * 288 * 4)   /* CIF at RGB32 */
 #define CPIA_MAX_FRAME_SIZE	((CPIA_MAX_FRAME_SIZE_UNALIGNED + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)) /* align above to PAGE_SIZE */
@@ -41,6 +45,7 @@
 
 #include <asm/uaccess.h>
 #include <linux/videodev.h>
+#include <linux/list.h>
 #include <linux/smp_lock.h>
 
 struct cpia_camera_ops
@@ -93,6 +98,10 @@
 	 * is STREAM_READY before calling streamRead.
 	 */
 	int wait_for_stream_ready;
+	/*
+	 * Used to maintain lowlevel module usage counts
+	 */
+	struct module *owner;
 };
 
 struct cpia_frame {
@@ -233,8 +242,7 @@
 #define FRAME_NUM	2	/* double buffering for now */
 
 struct cam_data {
-	struct cam_data **previous;
-	struct cam_data *next;
+	struct list_head cam_data_list;
 
         struct semaphore busy_lock;     /* guard against SMP multithreading */
 	struct cpia_camera_ops *ops;	/* lowlevel driver operations */
@@ -400,24 +408,6 @@
       (p)&0x80?1:0, (p)&0x40?1:0, (p)&0x20?1:0, (p)&0x10?1:0,\
         (p)&0x08?1:0, (p)&0x04?1:0, (p)&0x02?1:0, (p)&0x01?1:0);
 
-static inline void cpia_add_to_list(struct cam_data* l, struct cam_data* drv)
-{
-	drv->next = l;
-	drv->previous = &l;
-	l = drv;
-}
-
-static inline void cpia_remove_from_list(struct cam_data* drv)
-{
-	if (drv->previous != NULL) {
-		if (drv->next != NULL)
-			drv->next->previous = drv->previous;
-		*(drv->previous) = drv->next;
-		drv->previous = NULL;
-		drv->next = NULL;
-	}
-}
-
 #endif /* __KERNEL__ */
 
 #endif /* cpia_h */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/video/cpia_pp.c linux-2.4.21-pre6/drivers/media/video/cpia_pp.c
--- linux-2.4.20/drivers/media/video/cpia_pp.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/media/video/cpia_pp.c	2003-03-26 23:48:58.000000000 +0000
@@ -22,6 +22,9 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+/* define _CPIA_DEBUG_ for verbose debug output (see cpia.h) */
+/* #define _CPIA_DEBUG_  1 */  
+
 #include <linux/config.h>
 #include <linux/version.h>
 
@@ -33,6 +36,7 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/smp_lock.h>
+#include <linux/sched.h>
 
 #include <linux/kmod.h>
 
@@ -50,65 +54,6 @@
 
 #define ABOUT "Parallel port driver for Vision CPiA based cameras"
 
-/* IEEE 1284 Compatiblity Mode signal names 	*/
-#define nStrobe		PARPORT_CONTROL_STROBE	  /* inverted */
-#define nAutoFd		PARPORT_CONTROL_AUTOFD	  /* inverted */
-#define nInit		PARPORT_CONTROL_INIT
-#define nSelectIn	PARPORT_CONTROL_SELECT
-#define IntrEnable	PARPORT_CONTROL_INTEN	  /* normally zero for no IRQ */
-#define DirBit		PARPORT_CONTROL_DIRECTION /* 0 = Forward, 1 = Reverse	*/
-
-#define nFault		PARPORT_STATUS_ERROR
-#define Select		PARPORT_STATUS_SELECT
-#define PError		PARPORT_STATUS_PAPEROUT
-#define nAck		PARPORT_STATUS_ACK
-#define Busy		PARPORT_STATUS_BUSY	  /* inverted */	
-
-/* some more */
-#define HostClk		nStrobe
-#define HostAck		nAutoFd
-#define nReverseRequest	nInit
-#define Active_1284	nSelectIn
-#define nPeriphRequest	nFault
-#define XFlag		Select
-#define nAckReverse	PError
-#define PeriphClk	nAck
-#define PeriphAck	Busy
-
-/* these can be used to correct for the inversion on some bits */
-#define STATUS_INVERSION_MASK	(Busy)
-#define CONTROL_INVERSION_MASK	(nStrobe|nAutoFd|nSelectIn)
-
-#define ECR_empty	0x01
-#define ECR_full	0x02
-#define ECR_serviceIntr 0x04
-#define ECR_dmaEn	0x08
-#define ECR_nErrIntrEn	0x10
-
-#define ECR_mode_mask	0xE0
-#define ECR_SPP_mode	0x00
-#define ECR_PS2_mode	0x20
-#define ECR_FIFO_mode	0x40
-#define ECR_ECP_mode	0x60
-
-#define ECP_FIFO_SIZE	16
-#define DMA_BUFFER_SIZE               PAGE_SIZE
-	/* for 16bit DMA make sure DMA_BUFFER_SIZE is 16 bit aligned */
-#define PARPORT_CHUNK_SIZE	PAGE_SIZE/* >=2.3.x */
-				/* we read this many bytes at once */
-
-#define GetECRMasked(port,mask)	(parport_read_econtrol(port) & (mask))
-#define GetStatus(port)		((parport_read_status(port)^STATUS_INVERSION_MASK)&(0xf8))
-#define SetStatus(port,val)	parport_write_status(port,(val)^STATUS_INVERSION_MASK)
-#define GetControl(port)	((parport_read_control(port)^CONTROL_INVERSION_MASK)&(0x3f))
-#define SetControl(port,val)	parport_write_control(port,(val)^CONTROL_INVERSION_MASK)
-
-#define GetStatusMasked(port,mask)	(GetStatus(port) & (mask))
-#define GetControlMasked(port,mask)	(GetControl(port) & (mask))
-#define SetControlMasked(port,mask)	SetControl(port,GetControl(port) | (mask));
-#define ClearControlMasked(port,mask)	SetControl(port,GetControl(port)&~(mask));
-#define FrobControlBit(port,mask,value)	SetControl(port,(GetControl(port)&~(mask))|((value)&(mask)));
-
 #define PACKET_LENGTH 	8
 
 /* Magic numbers for defining port-device mappings */
@@ -156,35 +101,13 @@
 	cpia_pp_streamStop,
 	cpia_pp_streamRead,
 	cpia_pp_close,
-	1
+	1,
+	THIS_MODULE
 };
 
-static struct cam_data *cam_list;
+static LIST_HEAD(cam_list);
 static spinlock_t cam_list_lock_pp;
 
-#ifdef _CPIA_DEBUG_
-#define DEB_PORT(port) { \
-u8 controll = GetControl(port); \
-u8 statusss = GetStatus(port); \
-DBG("nsel %c per %c naut %c nstrob %c nak %c busy %c nfaul %c sel %c init %c dir %c\n",\
-((controll & nSelectIn)	? 'U' : 'D'), \
-((statusss & PError)	? 'U' : 'D'), \
-((controll & nAutoFd)	? 'U' : 'D'), \
-((controll & nStrobe)	? 'U' : 'D'), \
-((statusss & nAck)	? 'U' : 'D'), \
-((statusss & Busy)	? 'U' : 'D'), \
-((statusss & nFault)	? 'U' : 'D'), \
-((statusss & Select)	? 'U' : 'D'), \
-((controll & nInit)	? 'U' : 'D'), \
-((controll & DirBit)	? 'R' : 'F')  \
-); }
-#else
-#define DEB_PORT(port) {}
-#endif
-
-#define WHILE_OUT_TIMEOUT (HZ/10)
-#define DMA_TIMEOUT 10*HZ
-
 /* FIXME */
 static void cpia_parport_enable_irq( struct parport *port ) {
 	parport_enable_irq(port);
@@ -198,6 +121,14 @@
 	return;
 }
 
+/* Special CPiA PPC modes: These are invoked by using the 1284 Extensibility
+ * Link Flag during negotiation */  
+#define UPLOAD_FLAG  0x08
+#define ECP_TRANSFER 0x03
+
+#define PARPORT_CHUNK_SIZE	PAGE_SIZE
+
+
 /****************************************************************************
  *
  *  EndTransferMode
@@ -240,7 +171,7 @@
 {
 	int retry;
 	int mode = IEEE1284_MODE_ECP;
-	if(extensibility) mode = 8|3|IEEE1284_EXT_LINK;
+	if(extensibility) mode = UPLOAD_FLAG|ECP_TRANSFER|IEEE1284_EXT_LINK;
 
 	/* After some commands the camera needs extra time before
 	 * it will respond again, so we try up to 3 times */
@@ -345,11 +276,22 @@
  *  cpia_pp_streamRead
  *
  ***************************************************************************/
+static int cpia_pp_read(struct parport *port, u8 *buffer, int len)
+{
+	int bytes_read, new_bytes;
+	for(bytes_read=0; bytes_read<len; bytes_read += new_bytes) {
+		new_bytes = parport_read(port, buffer+bytes_read,
+			                 len-bytes_read);
+		if(new_bytes < 0) break;
+	}
+	return bytes_read;
+}
+
 static int cpia_pp_streamRead(void *privdata, u8 *buffer, int noblock)
 {
 	struct pp_cam_entry *cam = privdata;
 	int read_bytes = 0;
-	int i, endseen;
+	int i, endseen, block_size, new_bytes;
 
 	if(cam == NULL) {
 		DBG("Internal driver error: cam is NULL\n");
@@ -378,25 +320,34 @@
 			return -EIO;
 		}
 	}
-	read_bytes = parport_read(cam->port, buffer, CPIA_MAX_IMAGE_SIZE );
-
-	EndTransferMode(cam);
-	DBG("read %d bytes\n", read_bytes);
-	if( read_bytes<0) return -EIO;
-	endseen = 0;
 	endseen = 0;
-	for( i=0; i<read_bytes && endseen<4; i++ ) {
-	  if( *buffer==EOI ) {
-	    endseen++;
-	  } else {
-	    endseen=0;
-	  }
-	  buffer++;
-	}
-	if( endseen>3 ) {
-	  cam->image_complete=1;
-	  DBG("endseen at %d bytes\n", i);
+	block_size = PARPORT_CHUNK_SIZE;
+	while( !cam->image_complete ) {
+		if(current->need_resched)  schedule();
+		
+		new_bytes = cpia_pp_read(cam->port, buffer, block_size );
+		if( new_bytes <= 0 ) {
+			break;
+		}
+		i=-1;
+		while(++i<new_bytes && endseen<4) {
+	        	if(*buffer==EOI) {
+	                	endseen++;
+	                } else {
+	                	endseen=0;
+	                }
+			buffer++;
+		}
+		read_bytes += i;
+		if( endseen==4 ) {
+			cam->image_complete=1;
+			break;
+		}
+		if( CPIA_MAX_IMAGE_SIZE-read_bytes <= PARPORT_CHUNK_SIZE ) {
+			block_size=CPIA_MAX_IMAGE_SIZE-read_bytes;
+		}
 	}
+	EndTransferMode(cam);
 	return cam->image_complete ? read_bytes : -EIO;
 }
 
@@ -566,7 +517,7 @@
 		return -ENXIO;
 	}
 	spin_lock( &cam_list_lock_pp );
-	cpia_add_to_list(cam_list, cpia);
+	list_add( &cpia->cam_data_list, &cam_list );
 	spin_unlock( &cam_list_lock_pp );
 
 	return 0;
@@ -574,27 +525,34 @@
 
 static void cpia_pp_detach (struct parport *port)
 {
-	struct cam_data *cpia;
+	struct list_head *tmp;
+	struct cam_data *cpia = NULL;
+	struct pp_cam_entry *cam;
 
 	spin_lock( &cam_list_lock_pp );
-	for(cpia = cam_list; cpia != NULL; cpia = cpia->next) {
-		struct pp_cam_entry *cam = cpia->lowlevel_data;
+	list_for_each (tmp, &cam_list) {
+		cpia = list_entry(tmp, struct cam_data, cam_data_list);
+		cam = (struct pp_cam_entry *) cpia->lowlevel_data;
 		if (cam && cam->port->number == port->number) {
-			cpia_remove_from_list(cpia);
-			spin_unlock( &cam_list_lock_pp );			
-			cpia_unregister_camera(cpia);
-			
-			if(cam->open_count > 0) {
-				cpia_pp_close(cam);
-			}
-
-			parport_unregister_device(cam->pdev);
-		
-			kfree(cam);
-			cpia->lowlevel_data = NULL;
+			list_del(&cpia->cam_data_list);
 			break;
 		}
+		cpia = NULL;
+	}
+	spin_unlock( &cam_list_lock_pp );			
+
+	if (!cpia) {
+		DBG("cpia_pp_detach failed to find cam_data in cam_list\n");
+		return;
 	}
+	
+	cam = (struct pp_cam_entry *) cpia->lowlevel_data;	
+	cpia_unregister_camera(cpia);
+	if(cam->open_count > 0) 
+		cpia_pp_close(cam);
+	parport_unregister_device(cam->pdev);
+	cpia->lowlevel_data = NULL;	
+	kfree(cam);
 }
 
 static void cpia_pp_attach (struct parport *port)
@@ -642,14 +600,12 @@
 		return 0;
 	}
 	
+	spin_lock_init( &cam_list_lock_pp );
+
 	if (parport_register_driver (&cpia_pp_driver)) {
 		LOG ("unable to register with parport\n");
 		return -EIO;
 	}
-	
-	cam_list = NULL;
-	spin_lock_init( &cam_list_lock_pp );
-
 	return 0;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/video/cpia_usb.c linux-2.4.21-pre6/drivers/media/video/cpia_usb.c
--- linux-2.4.20/drivers/media/video/cpia_usb.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/media/video/cpia_usb.c	2003-03-26 23:48:58.000000000 +0000
@@ -21,11 +21,13 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+/* define _CPIA_DEBUG_ for verbose debug output (see cpia.h) */
+/* #define _CPIA_DEBUG_  1 */  
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/wait.h>
-#include <linux/sched.h>
 #include <linux/list.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
@@ -100,10 +102,11 @@
 	cpia_usb_streamStop,
 	cpia_usb_streamRead,
 	cpia_usb_close,
-	0
+	0,
+	THIS_MODULE
 };
 
-static struct cam_data *cam_list;
+static LIST_HEAD(cam_list);
 static spinlock_t cam_list_lock_usb;
 
 static void cpia_usb_complete(struct urb *urb)
@@ -456,12 +459,14 @@
 {
 	struct usb_cpia *ucpia = (struct usb_cpia *) privdata;
 
-	ucpia->open = 0;
+	if(!ucpia)
+		return -ENODEV;
 
-	cpia_usb_free_resources(ucpia, 1);
+	ucpia->open = 0;
 
-	if (!ucpia->present)
-		kfree(ucpia);
+	/* ucpia->present = 0 protects against trying to reset the
+	 * alt setting if camera is physically disconnected while open */
+	cpia_usb_free_resources(ucpia, ucpia->present);
 
 	return 0;
 }
@@ -540,7 +545,7 @@
 	}
 
 	spin_lock( &cam_list_lock_usb );
-	cpia_add_to_list(cam_list, cam);
+	list_add( &cam->cam_data_list, &cam_list );
 	spin_unlock( &cam_list_lock_usb );
 
 	return cam;
@@ -555,6 +560,7 @@
 	vfree(ucpia->buffers[0]);
 	ucpia->buffers[0] = NULL;
 fail_alloc_0:
+	kfree(ucpia);
 
 	return NULL;
 }
@@ -578,76 +584,57 @@
 	id_table:	cpia_id_table,
 };
 
-/* don't use dev, it may be NULL! (see usb_cpia_cleanup) */
-/* _disconnect from usb_cpia_cleanup is not necessary since usb_deregister */
-/* will do it for us as well as passing a udev structure - jerdfelt */
 static void cpia_disconnect(struct usb_device *udev, void *ptr)
 {
 	struct cam_data *cam = (struct cam_data *) ptr;
 	struct usb_cpia *ucpia = (struct usb_cpia *) cam->lowlevel_data;
   
 	spin_lock( &cam_list_lock_usb );
-	cpia_remove_from_list(cam);
+	list_del(&cam->cam_data_list);
 	spin_unlock( &cam_list_lock_usb );
 	
-	/* Don't even try to reset the altsetting if we're disconnected */
-	cpia_usb_free_resources(ucpia, 0);
-
 	ucpia->present = 0;
-
 	cpia_unregister_camera(cam);
+	if(ucpia->open)
+		cpia_usb_close(cam->lowlevel_data);
 
 	ucpia->curbuff->status = FRAME_ERROR;
-
 	if (waitqueue_active(&ucpia->wq_stream))
 		wake_up_interruptible(&ucpia->wq_stream);
-
 	usb_driver_release_interface(&cpia_driver,
 				     &udev->actconfig->interface[0]);
-
 	ucpia->curbuff = ucpia->workbuff = NULL;
-
 	if (ucpia->buffers[2]) {
 		vfree(ucpia->buffers[2]);
 		ucpia->buffers[2] = NULL;
 	}
-
 	if (ucpia->buffers[1]) {
 		vfree(ucpia->buffers[1]);
 		ucpia->buffers[1] = NULL;
 	}
-
 	if (ucpia->buffers[0]) {
 		vfree(ucpia->buffers[0]);
 		ucpia->buffers[0] = NULL;
 	}
 
-	if (!ucpia->open) {
-		kfree(ucpia);
-		cam->lowlevel_data = NULL;
-	}
+	cam->lowlevel_data = NULL;
+	kfree(ucpia);
 }
 
 static int __init usb_cpia_init(void)
 {
-	cam_list = NULL;
+	printk(KERN_INFO "%s v%d.%d.%d\n",ABOUT, 
+	       CPIA_USB_MAJ_VER,CPIA_USB_MIN_VER,CPIA_USB_PATCH_VER);
+
 	spin_lock_init(&cam_list_lock_usb);
 	return usb_register(&cpia_driver);
 }
 
 static void __exit usb_cpia_cleanup(void)
 {
-/*
-	struct cam_data *cam;
-
-	while ((cam = cam_list) != NULL)
-		cpia_disconnect(NULL, cam);
-*/
-
 	usb_deregister(&cpia_driver);
 }
 
-
 module_init (usb_cpia_init);
 module_exit (usb_cpia_cleanup);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/video/meye.c linux-2.4.21-pre6/drivers/media/video/meye.c
--- linux-2.4.20/drivers/media/video/meye.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/media/video/meye.c	2003-03-26 23:49:40.000000000 +0000
@@ -1,7 +1,9 @@
 /* 
  * Motion Eye video4linux driver for Sony Vaio PictureBook
  *
- * Copyright (C) 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
+ * Copyright (C) 2001-2003 Stelian Pop <stelian@popies.net>
+ *
+ * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
  *
  * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com>
  *
@@ -169,16 +171,28 @@
 	meye.mchip_ptable[MCHIP_NB_PAGES] = pci_alloc_consistent(meye.mchip_dev, 
 								 PAGE_SIZE, 
 								 &meye.mchip_dmahandle);
-	if (!meye.mchip_ptable[MCHIP_NB_PAGES])
+	if (!meye.mchip_ptable[MCHIP_NB_PAGES]) {
+		meye.mchip_dmahandle = 0;
 		return -1;
+	}
 
 	pt = (u32 *)meye.mchip_ptable[MCHIP_NB_PAGES];
 	for (i = 0; i < MCHIP_NB_PAGES; i++) {
 		meye.mchip_ptable[i] = pci_alloc_consistent(meye.mchip_dev, 
 							    PAGE_SIZE,
 							    pt);
-		if (!meye.mchip_ptable[i])
+		if (!meye.mchip_ptable[i]) {
+			int j;
+			pt = (u32 *)meye.mchip_ptable[MCHIP_NB_PAGES];
+			for (j = 0; j < i; ++j) {
+				pci_free_consistent(meye.mchip_dev,
+						    PAGE_SIZE,
+						    meye.mchip_ptable[j], *pt);
+				pt++;
+			}
+			meye.mchip_dmahandle = 0;
 			return -1;
+		}
 		pt++;
 	}
 	return 0;
@@ -189,11 +203,13 @@
 	int i;
 
 	pt = (u32 *)meye.mchip_ptable[MCHIP_NB_PAGES];
-	for (i = 0; i < MCHIP_NB_PAGES; i++)
+	for (i = 0; i < MCHIP_NB_PAGES; i++) {
 		if (meye.mchip_ptable[i])
 			pci_free_consistent(meye.mchip_dev, 
 					    PAGE_SIZE, 
 					    meye.mchip_ptable[i], *pt);
+		pt++;
+	}
 
 	if (meye.mchip_ptable[MCHIP_NB_PAGES])
 		pci_free_consistent(meye.mchip_dev, 
@@ -569,6 +585,16 @@
 	mchip_load_tables();
 }
 
+/* sets the DMA parameters into the chip */
+static void mchip_dma_setup(u32 dma_addr) {
+	int i;
+
+	mchip_set(MCHIP_MM_PT_ADDR, dma_addr);
+	for (i = 0; i < 4; i++)
+		mchip_set(MCHIP_MM_FIR(i), 0);
+	meye.mchip_fnum = 0;
+}
+
 /* setup for DMA transfers - also zeros the framebuffer */
 static int mchip_dma_alloc(void) {
 	if (!meye.mchip_dmahandle)
@@ -579,18 +605,10 @@
 
 /* frees the DMA buffer */
 static void mchip_dma_free(void) {
-	if (meye.mchip_dmahandle)
+	if (meye.mchip_dmahandle) {
+		mchip_dma_setup(0);
 		ptable_free();
-}
-
-/* sets the DMA parameters into the chip */
-static void mchip_dma_setup(void) {
-	int i;
-
-	mchip_set(MCHIP_MM_PT_ADDR, meye.mchip_dmahandle);
-	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
@@ -698,7 +716,7 @@
 	
 	mchip_hic_stop();
 	mchip_subsample();
-	mchip_dma_setup();
+	mchip_dma_setup(meye.mchip_dmahandle);
 
 	mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_STILL_CAP);
 	mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START);
@@ -741,7 +759,7 @@
 	mchip_hic_stop();
 	mchip_subsample();
 	mchip_set_framerate();
-	mchip_dma_setup();
+	mchip_dma_setup(meye.mchip_dmahandle);
 
 	meye.mchip_mode = MCHIP_HIC_MODE_CONT_OUT;
 
@@ -801,7 +819,7 @@
 	mchip_vrj_setup(0x3f);
 	mchip_subsample();
 	mchip_set_framerate();
-	mchip_dma_setup();
+	mchip_dma_setup(meye.mchip_dmahandle);
 
 	meye.mchip_mode = MCHIP_HIC_MODE_CONT_COMP;
 
@@ -823,7 +841,7 @@
 	while (1) {
 		v = mchip_get_frame();
 		if (!(v & MCHIP_MM_FIR_RDY))
-			goto out;
+			return;
 		switch (meye.mchip_mode) {
 
 		case MCHIP_HIC_MODE_CONT_OUT:
@@ -856,12 +874,11 @@
 
 		default:
 			/* do not free frame, since it can be a snap */
-			goto out;
+			return;
 		} /* switch */
 
 		mchip_free_frame();
 	}
-out: ;
 }
 
 /****************************************************************************/
@@ -889,6 +906,7 @@
 
 static int meye_release(struct inode *inode, struct file *file) {
 	mchip_hic_stop();
+	mchip_dma_free();
 	video_exclusive_release(inode,file);
 	return 0;
 }
@@ -957,7 +975,6 @@
 
 	case VIDIOCSYNC: {
 		int *i = arg;
-		DECLARE_WAITQUEUE(wait, current);
 
 		if (*i < 0 || *i >= gbuffers)
 			return -EINVAL;
@@ -967,18 +984,9 @@
 		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;
+			if (wait_event_interruptible(meye.grabq.proc_list,
+						     (meye.grab_buffer[*i].state != MEYE_BUF_USING)))
+				return -EINTR;
 			/* fall through */
 		case MEYE_BUF_DONE:
 			meye.grab_buffer[*i].state = MEYE_BUF_UNUSED;
@@ -1095,7 +1103,6 @@
 
 	case MEYEIOC_SYNC: {
 		int *i = arg;
-		DECLARE_WAITQUEUE(wait, current);
 
 		if (*i < 0 || *i >= gbuffers)
 			return -EINVAL;
@@ -1105,18 +1112,9 @@
 		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;
+			if (wait_event_interruptible(meye.grabq.proc_list,
+						     (meye.grab_buffer[*i].state != MEYE_BUF_USING)))
+				return -EINTR;
 			/* fall through */
 		case MEYE_BUF_DONE:
 			meye.grab_buffer[*i].state = MEYE_BUF_UNUSED;
@@ -1211,22 +1209,58 @@
 }
 
 static struct file_operations meye_fops = {
-	owner:		THIS_MODULE,
-	open:		meye_open,
-	release:	meye_release,
-	mmap:		meye_mmap,
-	ioctl:		meye_ioctl,
-	llseek:		no_llseek,
+	.owner		= THIS_MODULE,
+	.open		= meye_open,
+	.release	= meye_release,
+	.mmap		= meye_mmap,
+	.ioctl		= meye_ioctl,
+	.llseek		= no_llseek,
 };
 
 static struct video_device meye_template = {
-	owner:		THIS_MODULE,
-	name:		"meye",
-	type:		VID_TYPE_CAPTURE,
-	hardware:	VID_HARDWARE_MEYE,
-	fops:		&meye_fops,
+	.owner		= THIS_MODULE,
+	.name		= "meye",
+	.type		= VID_TYPE_CAPTURE,
+	.hardware	= VID_HARDWARE_MEYE,
+	.fops		= &meye_fops,
 };
 
+#ifdef CONFIG_PM
+static int meye_suspend(struct pci_dev *pdev, u32 state)
+{
+	pci_save_state(pdev, meye.pm_state);
+	meye.pm_mchip_mode = meye.mchip_mode;
+	mchip_hic_stop();
+	mchip_set(MCHIP_MM_INTA, 0x0);
+	return 0;
+}
+
+static int meye_resume(struct pci_dev *pdev)
+{
+	pci_restore_state(pdev, meye.pm_state);
+	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);
+
+	switch (meye.pm_mchip_mode) {
+	case MCHIP_HIC_MODE_CONT_OUT:
+		mchip_continuous_start();
+		break;
+	case MCHIP_HIC_MODE_CONT_COMP:
+		mchip_cont_compression_start();
+		break;
+	}
+	return 0;
+}
+#endif
+
 static int __devinit meye_probe(struct pci_dev *pcidev, 
 		                const struct pci_device_id *ent) {
 	int ret;
@@ -1244,15 +1278,9 @@
 	meye.mchip_dev = pcidev;
 	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;
+		goto out2;
 	}
 
 	meye.mchip_irq = pcidev->irq;
@@ -1260,14 +1288,14 @@
 	if (!mchip_adr) {
 		printk(KERN_ERR "meye: mchip has no device base address\n");
 		ret = -EIO;
-		goto out4;
+		goto out3;
 	}
 	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;
+		goto out3;
 	}
 
 	pci_read_config_byte(meye.mchip_dev, PCI_REVISION_ID, &revision);
@@ -1280,14 +1308,14 @@
 	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;
+		goto out4;
 	}
 
 	meye.mchip_mmregs = ioremap(mchip_adr, MCHIP_MM_REGS);
 	if (!meye.mchip_mmregs) {
 		printk(KERN_ERR "meye: ioremap failed\n");
 		ret = -EIO;
-		goto out6;
+		goto out5;
 	}
 	
 	/* Ask the camera to perform a soft reset. */
@@ -1309,7 +1337,7 @@
 
 		printk(KERN_ERR "meye: video_register_device failed\n");
 		ret = -EIO;
-		goto out7;
+		goto out6;
 	}
 	
 	printk(KERN_INFO "meye: Motion Eye Camera Driver v%d.%d.\n",
@@ -1343,17 +1371,15 @@
 	sonypi_camera_command(SONYPI_COMMAND_SETCAMERAAGC, 48);
 
 	return 0;
-out7:
-	iounmap(meye.mchip_mmregs);
 out6:
-	free_irq(meye.mchip_irq, meye_irq);
+	iounmap(meye.mchip_mmregs);
 out5:
+	free_irq(meye.mchip_irq, meye_irq);
+out4:
 	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();
+	pci_disable_device(meye.mchip_dev);
 out2:
 	sonypi_camera_command(SONYPI_COMMAND_SETCAMERA, 0);
 out1:
@@ -1371,7 +1397,6 @@
 
 	free_irq(meye.mchip_irq, meye_irq);
 
-
 	iounmap(meye.mchip_mmregs);
 
 	release_mem_region(pci_resource_start(meye.mchip_dev, 0),
@@ -1398,10 +1423,14 @@
 MODULE_DEVICE_TABLE(pci, meye_pci_tbl);
 
 static struct pci_driver meye_driver = {
-	name:		"meye",
-	id_table:	meye_pci_tbl,
-	probe:		meye_probe,
-	remove:		__devexit_p(meye_remove),
+	.name		= "meye",
+	.id_table	= meye_pci_tbl,
+	.probe		= meye_probe,
+	.remove		= __devexit_p(meye_remove),
+#ifdef CONFIG_PM
+	.suspend	= meye_suspend,
+	.resume		= meye_resume,
+#endif
 };
 
 static int __init meye_init_module(void) {
@@ -1441,7 +1470,7 @@
 __setup("meye=", meye_setup);
 #endif
 
-MODULE_AUTHOR("Stelian Pop <stelian.pop@fr.alcove.com>");
+MODULE_AUTHOR("Stelian Pop <stelian@popies.net>");
 MODULE_DESCRIPTION("video4linux driver for the MotionEye camera");
 MODULE_LICENSE("GPL");
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/video/meye.h linux-2.4.21-pre6/drivers/media/video/meye.h
--- linux-2.4.20/drivers/media/video/meye.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/media/video/meye.h	2003-03-26 23:49:40.000000000 +0000
@@ -1,7 +1,9 @@
 /* 
  * Motion Eye video4linux driver for Sony Vaio PictureBook
  *
- * Copyright (C) 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
+ * Copyright (C) 2001-2003 Stelian Pop <stelian@popies.net>
+ *
+ * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
  *
  * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com>
  *
@@ -29,7 +31,13 @@
 #define _MEYE_PRIV_H_
 
 #define MEYE_DRIVER_MAJORVERSION	1
-#define MEYE_DRIVER_MINORVERSION	4
+#define MEYE_DRIVER_MINORVERSION	6
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/sonypi.h>
+#include <linux/meye.h>
 
 /****************************************************************************/
 /* Motion JPEG chip registers                                               */
@@ -307,6 +315,10 @@
 	struct video_device video_dev;	/* video device parameters */
 	struct video_picture picture;	/* video picture parameters */
 	struct meye_params params;	/* additional parameters */
+#ifdef CONFIG_PM
+	u32 pm_state[16];		/* PCI configuration space */
+	u8 pm_mchip_mode;		/* old mchip mode */
+#endif
 };
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/video/msp3400.c linux-2.4.21-pre6/drivers/media/video/msp3400.c
--- linux-2.4.20/drivers/media/video/msp3400.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/media/video/msp3400.c	2003-03-26 23:49:00.000000000 +0000
@@ -59,28 +59,13 @@
 #include "audiochip.h"
 #include "msp3400.h"
 
-/* Addresses to scan */
-static unsigned short normal_i2c[] = {I2C_CLIENT_END};
-static unsigned short normal_i2c_range[] = {0x40,0x40,I2C_CLIENT_END};
-static unsigned short probe[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short probe_range[2]  = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore[2]       = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short force[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
-static struct i2c_client_address_data addr_data = {
-	normal_i2c, normal_i2c_range, 
-	probe, probe_range, 
-	ignore, ignore_range, 
-	force
-};
-
 /* insmod parameters */
-static int debug   = 0;    /* debug output */
-static int once    = 0;    /* no continous stereo monitoring */
-static int amsound = 0;    /* hard-wire AM sound at 6.5 Hz (france),
+static int debug    = 0;    /* debug output */
+static int once     = 0;    /* no continous stereo monitoring */
+static int amsound  = 0;    /* hard-wire AM sound at 6.5 Hz (france),
 			      the autoscan seems work well only with FM... */
-static int simple  = -1;   /* use short programming (>= msp3410 only) */
-static int dolby   = 0;
+static int simple   = -1;   /* use short programming (>= msp3410 only) */
+static int dolby    = 0;
 
 #define DFP_COUNT 0x41
 static const int bl_dfp[] = {
@@ -89,8 +74,9 @@
 };
 
 struct msp3400c {
+	int rev1,rev2;
+	
 	int simple;
-	int nicam;
 	int mode;
 	int norm;
 	int stereo;
@@ -117,6 +103,10 @@
 	struct timer_list    wake_stereo;
 };
 
+#define HAVE_NICAM(msp)   (((msp->rev2>>8) & 0xff)     != 00)
+#define HAVE_SIMPLE(msp)  ((msp->rev1      & 0xff)+'@' >= 'D')
+#define HAVE_RADIO(msp)   ((msp->rev1      & 0xff)+'@' >= 'G')
+
 #define MSP3400_MAX 4
 static struct i2c_client *msps[MSP3400_MAX];
 
@@ -139,23 +129,50 @@
 /* ---------------------------------------------------------------------- */
 
 #define I2C_MSP3400C       0x80
+#define I2C_MSP3400C_ALT   0x88
+
 #define I2C_MSP3400C_DEM   0x10
 #define I2C_MSP3400C_DFP   0x12
 
+/* Addresses to scan */
+static unsigned short normal_i2c[] = {
+	I2C_MSP3400C      >> 1,
+	I2C_MSP3400C_ALT  >> 1,
+	I2C_CLIENT_END
+};
+static unsigned short normal_i2c_range[] = {I2C_CLIENT_END,I2C_CLIENT_END};
+I2C_CLIENT_INSMOD;
+
 /* ----------------------------------------------------------------------- */
 /* functions for talking to the MSP3400C Sound processor                   */
 
+#ifndef I2C_M_IGNORE_NAK
+# define I2C_M_IGNORE_NAK 0x1000
+#endif
+
 static int msp3400c_reset(struct i2c_client *client)
 {
-        static char reset_off[3] = { 0x00, 0x80, 0x00 };
-        static char reset_on[3]  = { 0x00, 0x00, 0x00 };
-
-        i2c_master_send(client,reset_off,3);  /* XXX ignore errors here */
-        if (3 != i2c_master_send(client,reset_on, 3)) {
-		printk(KERN_ERR "msp3400: chip reset failed, penguin on i2c bus?\n");
-                return -1;
-	}
-        return 0;
+	/* reset and read revision code */
+	static char reset_off[3] = { 0x00, 0x80, 0x00 };
+	static char reset_on[3]  = { 0x00, 0x00, 0x00 };
+	static char write[3]     = { I2C_MSP3400C_DFP + 1, 0x00, 0x1e };
+	char read[2];
+	struct i2c_msg reset[2] = {
+		{ client->addr, I2C_M_IGNORE_NAK, 3, reset_off },
+		{ client->addr, I2C_M_IGNORE_NAK, 3, reset_on  },
+	};
+	struct i2c_msg test[2] = {
+		{ client->addr, 0,        3, write },
+		{ client->addr, I2C_M_RD, 2, read  },
+	};
+	
+	if ( (1 != i2c_transfer(client->adapter,&reset[0],1)) ||
+	     (1 != i2c_transfer(client->adapter,&reset[1],1)) ||
+	     (2 != i2c_transfer(client->adapter,test,2)) ) {
+		printk(KERN_ERR "msp3400: chip reset failed\n");
+		return -1;
+        }
+	return 0; 
 }
 
 static int
@@ -348,7 +365,8 @@
 	if (-1 == scarts[out][in])
 		return;
 
-	dprintk("msp34xx: scart switch: %s => %d\n",scart_names[in],out);
+	dprintk(KERN_DEBUG
+		"msp34xx: scart switch: %s => %d\n",scart_names[in],out);
 	msp->acb &= ~scarts[out][SCART_MASK];
 	msp->acb |=  scarts[out][in];
 	msp3400c_write(client,I2C_MSP3400C_DFP, 0x0013, msp->acb);
@@ -378,7 +396,8 @@
 		balance = ((right-left) * 127) / vol;
 	}
 
-	dprintk("msp34xx: setvolume: mute=%s %d:%d  v=0x%02x b=0x%02x\n",
+	dprintk(KERN_DEBUG
+		"msp34xx: setvolume: mute=%s %d:%d  v=0x%02x b=0x%02x\n",
 		muted ? "on" : "off", left, right, val>>8, balance);
 	msp3400c_write(client,I2C_MSP3400C_DFP, 0x0000, val); /* loudspeaker */
 	msp3400c_write(client,I2C_MSP3400C_DFP, 0x0006, val); /* headphones  */
@@ -391,7 +410,7 @@
 {
 	int val = ((bass-32768) * 0x60 / 65535) << 8;
 
-	dprintk("msp34xx: setbass: %d 0x%02x\n",bass, val>>8);
+	dprintk(KERN_DEBUG "msp34xx: setbass: %d 0x%02x\n",bass, val>>8);
 	msp3400c_write(client,I2C_MSP3400C_DFP, 0x0002, val); /* loudspeaker */
 }
 
@@ -399,7 +418,7 @@
 {
 	int val = ((treble-32768) * 0x60 / 65535) << 8;
 
-	dprintk("msp34xx: settreble: %d 0x%02x\n",treble, val>>8);
+	dprintk(KERN_DEBUG "msp34xx: settreble: %d 0x%02x\n",treble, val>>8);
 	msp3400c_write(client,I2C_MSP3400C_DFP, 0x0003, val); /* loudspeaker */
 }
 
@@ -408,7 +427,7 @@
 	struct msp3400c *msp = client->data;
 	int i;
 	
-	dprintk("msp3400: setmode: %d\n",type);
+	dprintk(KERN_DEBUG "msp3400: setmode: %d\n",type);
 	msp->mode   = type;
 	msp->stereo = VIDEO_SOUND_MONO;
 
@@ -454,7 +473,7 @@
 	msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e,
 		       msp_init_data[type].dfp_matrix);
 
-	if (msp->nicam) {
+	if (HAVE_NICAM(msp)) {
 		/* nicam prescale */
 		msp3400c_write(client,I2C_MSP3400C_DFP, 0x0010, 0x5a00); /* was: 0x3000 */
 	}
@@ -472,7 +491,7 @@
 	/* switch demodulator */
 	switch (msp->mode) {
 	case MSP_MODE_FM_TERRA:
-		dprintk("msp3400: FM setstereo: %s\n",strmode[mode]);
+		dprintk(KERN_DEBUG "msp3400: FM setstereo: %s\n",strmode[mode]);
 		msp3400c_setcarrier(client,msp->second,msp->main);
 		switch (mode) {
 		case VIDEO_SOUND_STEREO:
@@ -486,7 +505,7 @@
 		}
 		break;
 	case MSP_MODE_FM_SAT:
-		dprintk("msp3400: SAT setstereo: %s\n",strmode[mode]);
+		dprintk(KERN_DEBUG "msp3400: SAT setstereo: %s\n",strmode[mode]);
 		switch (mode) {
 		case VIDEO_SOUND_MONO:
 			msp3400c_setcarrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5));
@@ -505,24 +524,24 @@
 	case MSP_MODE_FM_NICAM1:
 	case MSP_MODE_FM_NICAM2:
 	case MSP_MODE_AM_NICAM:
-		dprintk("msp3400: NICAM setstereo: %s\n",strmode[mode]);
+		dprintk(KERN_DEBUG "msp3400: NICAM setstereo: %s\n",strmode[mode]);
 		msp3400c_setcarrier(client,msp->second,msp->main);
 		if (msp->nicam_on)
 			nicam=0x0100;
 		break;
 	case MSP_MODE_BTSC:
-		dprintk("msp3400: BTSC setstereo: %s\n",strmode[mode]);
+		dprintk(KERN_DEBUG "msp3400: BTSC setstereo: %s\n",strmode[mode]);
 		nicam=0x0300;
 		break;
 	case MSP_MODE_EXTERN:
-		dprintk("msp3400: extern setstereo: %s\n",strmode[mode]);
+		dprintk(KERN_DEBUG "msp3400: extern setstereo: %s\n",strmode[mode]);
 		nicam = 0x0200;
 		break;
 	case MSP_MODE_FM_RADIO:
-		dprintk("msp3400: FM-Radio setstereo: %s\n",strmode[mode]);
+		dprintk(KERN_DEBUG "msp3400: FM-Radio setstereo: %s\n",strmode[mode]);
 		break;
 	default:
-		dprintk("msp3400: mono setstereo\n");
+		dprintk(KERN_DEBUG "msp3400: mono setstereo\n");
 		return;
 	}
 
@@ -551,7 +570,8 @@
 		src = 0x0010 | nicam;
 		break;
 	}
-	dprintk("msp3400: setstereo final source/matrix = 0x%x\n", src);
+	dprintk(KERN_DEBUG
+		"msp3400: setstereo final source/matrix = 0x%x\n", src);
 
 	if (dolby) {
 		msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,0x0520);
@@ -570,22 +590,22 @@
 msp3400c_print_mode(struct msp3400c *msp)
 {
 	if (msp->main == msp->second) {
-		printk("msp3400: mono sound carrier: %d.%03d MHz\n",
+		printk(KERN_DEBUG "msp3400: mono sound carrier: %d.%03d MHz\n",
 		       msp->main/910000,(msp->main/910)%1000);
 	} else {
-		printk("msp3400: main sound carrier: %d.%03d MHz\n",
+		printk(KERN_DEBUG "msp3400: main sound carrier: %d.%03d MHz\n",
 		       msp->main/910000,(msp->main/910)%1000);
 	}
 	if (msp->mode == MSP_MODE_FM_NICAM1 ||
 	    msp->mode == MSP_MODE_FM_NICAM2)
-		printk("msp3400: NICAM/FM carrier   : %d.%03d MHz\n",
+		printk(KERN_DEBUG "msp3400: NICAM/FM carrier   : %d.%03d MHz\n",
 		       msp->second/910000,(msp->second/910)%1000);
 	if (msp->mode == MSP_MODE_AM_NICAM)
-		printk("msp3400: NICAM/AM carrier   : %d.%03d MHz\n",
+		printk(KERN_DEBUG "msp3400: NICAM/AM carrier   : %d.%03d MHz\n",
 		       msp->second/910000,(msp->second/910)%1000);
 	if (msp->mode == MSP_MODE_FM_TERRA &&
 	    msp->main != msp->second) {
-		printk("msp3400: FM-stereo carrier : %d.%03d MHz\n",
+		printk(KERN_DEBUG "msp3400: FM-stereo carrier : %d.%03d MHz\n",
 		       msp->second/910000,(msp->second/910)%1000);
 	}
 }
@@ -632,8 +652,8 @@
 		val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x18);
 		if (val > 32767)
 			val -= 65536;
-		dprintk("msp34xx: stereo detect register: %d\n",val);
-		
+		dprintk(KERN_DEBUG
+			"msp34xx: stereo detect register: %d\n",val);
 		if (val > 4096) {
 			newstereo = VIDEO_SOUND_STEREO | VIDEO_SOUND_MONO;
 		} else if (val < -4096) {
@@ -647,7 +667,9 @@
 	case MSP_MODE_FM_NICAM2:
 	case MSP_MODE_AM_NICAM:
 		val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x23);
-		dprintk("msp34xx: nicam sync=%d, mode=%d\n",val & 1, (val & 0x1e) >> 1);
+		dprintk(KERN_DEBUG
+			"msp34xx: nicam sync=%d, mode=%d\n",
+			val & 1, (val & 0x1e) >> 1);
 
 		if (val & 1) {
 			/* nicam synced */
@@ -679,7 +701,8 @@
 		break;
 	case MSP_MODE_BTSC:
 		val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x200);
-		dprintk("msp3410: status=0x%x (pri=%s, sec=%s, %s%s%s)\n",
+		dprintk(KERN_DEBUG
+			"msp3410: status=0x%x (pri=%s, sec=%s, %s%s%s)\n",
 			val,
 			(val & 0x0002) ? "no"     : "yes",
 			(val & 0x0004) ? "no"     : "yes",
@@ -693,13 +716,13 @@
 	}
 	if (newstereo != msp->stereo) {
 		update = 1;
-		dprintk("msp34xx: watch: stereo %d => %d\n",
+		dprintk(KERN_DEBUG "msp34xx: watch: stereo %d => %d\n",
 			msp->stereo,newstereo);
 		msp->stereo   = newstereo;
 	}
 	if (newnicam != msp->nicam_on) {
 		update = 1;
-		dprintk("msp34xx: watch: nicam %d => %d\n",
+		dprintk(KERN_DEBUG "msp34xx: watch: nicam %d => %d\n",
 			msp->nicam_on,newnicam);
 		msp->nicam_on = newnicam;
 	}
@@ -728,6 +751,8 @@
 			msp3400c_setstereo(client,VIDEO_SOUND_STEREO);
 		else if (msp->stereo & VIDEO_SOUND_LANG1)
 			msp3400c_setstereo(client,VIDEO_SOUND_LANG1);
+		else if (msp->stereo & VIDEO_SOUND_LANG2)
+			msp3400c_setstereo(client,VIDEO_SOUND_LANG2);
 		else
 			msp3400c_setstereo(client,VIDEO_SOUND_MONO);
 	}
@@ -774,10 +799,6 @@
 		if (msp->rmmod || signal_pending(current))
 			goto done;
 
-		if (VIDEO_MODE_RADIO == msp->norm ||
-		    MSP_MODE_EXTERN  == msp->mode)
-			continue;  /* nothing to do */
-	
 		msp->active = 1;
 
 		if (msp->watch_stereo) {
@@ -794,8 +815,13 @@
 		
 	restart:
 		if (VIDEO_MODE_RADIO == msp->norm ||
-		    MSP_MODE_EXTERN  == msp->mode)
-			continue;  /* nothing to do */
+		    MSP_MODE_EXTERN  == msp->mode) {
+			/* no carrier scan, just unmute */
+			printk("msp3400: thread: no carrier scan\n");
+			msp3400c_setvolume(client, msp->muted,
+					   msp->left, msp->right);
+			continue;
+		}
 		msp->restart = 0;
 		msp3400c_setvolume(client, msp->muted, 0, 0);
 		msp3400c_setmode(client, MSP_MODE_AM_DETECT /* +1 */ );
@@ -880,7 +906,7 @@
 				msp->nicam_on = 0;
 				msp3400c_setstereo(client, VIDEO_SOUND_MONO);
 				msp->watch_stereo = 1;
-			} else if (max2 == 1 && msp->nicam) {
+			} else if (max2 == 1 && HAVE_NICAM(msp)) {
 				/* B/G NICAM */
 				msp->second = carrier_detect_55[max2].cdo;
 				msp3400c_setmode(client, MSP_MODE_FM_NICAM1);
@@ -918,7 +944,7 @@
 				/* volume prescale for SCART (AM mono input) */
 				msp3400c_write(client,I2C_MSP3400C_DFP, 0x000d, 0x1900);
 				msp->watch_stereo = 1;
-			} else if (max2 == 0 && msp->nicam) {
+			} else if (max2 == 0 && HAVE_NICAM(msp)) {
 				/* D/K NICAM */
 				msp->second = carrier_detect_65[max2].cdo;
 				msp3400c_setmode(client, MSP_MODE_FM_NICAM1);
@@ -955,7 +981,7 @@
 	}
 
 done:
-	dprintk("msp3400: thread: exit\n");
+	dprintk(KERN_DEBUG "msp3400: thread: exit\n");
 	msp->active = 0;
 	msp->thread = NULL;
 
@@ -1023,16 +1049,13 @@
 		if (msp->rmmod)
 			goto done;
 		if (debug > 1)
-			printk("msp3410: thread: sleep\n");
+			printk(KERN_DEBUG "msp3410: thread: sleep\n");
 		interruptible_sleep_on(&msp->wq);
 		if (debug > 1)
-			printk("msp3410: thread: wakeup\n");
+			printk(KERN_DEBUG "msp3410: thread: wakeup\n");
 		if (msp->rmmod || signal_pending(current))
 			goto done;
 
-		if (msp->mode == MSP_MODE_EXTERN)
-			continue;
-		
 		msp->active = 1;
 
 		if (msp->watch_stereo) {
@@ -1048,8 +1071,13 @@
 			goto done;
 
 	restart:
-		if (msp->mode == MSP_MODE_EXTERN)
+		if (msp->mode == MSP_MODE_EXTERN) {
+			/* no carrier scan needed, just unmute */
+			dprintk(KERN_DEBUG "msp3410: thread: no carrier scan\n");
+			msp3400c_setvolume(client, msp->muted,
+					   msp->left, msp->right);
 			continue;
+		}
 		msp->restart = 0;
 		del_timer(&msp->wake_stereo);
 		msp->watch_stereo = 0;
@@ -1071,7 +1099,7 @@
 			mode = 0x0003;
 			std  = 1;
 			break;
-		case VIDEO_MODE_RADIO: 
+		case VIDEO_MODE_RADIO:
 			mode = 0x0003;
 			std  = 0x0040;
 			break;
@@ -1088,7 +1116,7 @@
 			for (i = 0; modelist[i].name != NULL; i++)
 				if (modelist[i].retval == std)
 					break;
-			printk("msp3410: setting mode: %s (0x%04x)\n",
+			printk(KERN_DEBUG "msp3410: setting mode: %s (0x%04x)\n",
 			       modelist[i].name ? modelist[i].name : "unknown",std);
 		}
 
@@ -1109,13 +1137,13 @@
 				val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x7e);
 				if (val < 0x07ff)
 					break;
-				dprintk("msp3410: detection still in progress\n");
+				dprintk(KERN_DEBUG "msp3410: detection still in progress\n");
 			}
 		}
 		for (i = 0; modelist[i].name != NULL; i++)
 			if (modelist[i].retval == val)
 				break;
-		dprintk("msp3410: current mode: %s (0x%04x)\n",
+		dprintk(KERN_DEBUG "msp3410: current mode: %s (0x%04x)\n",
 			modelist[i].name ? modelist[i].name : "unknown",
 			val);
 		msp->main   = modelist[i].main;
@@ -1123,7 +1151,8 @@
 
 		if (amsound && (msp->norm == VIDEO_MODE_SECAM) && (val != 0x0009)) {
 			/* autodetection has failed, let backup */
-			dprintk("msp3410: autodetection failed, switching to backup mode: %s (0x%04x)\n",
+			dprintk(KERN_DEBUG "msp3410: autodetection failed,"
+				" switching to backup mode: %s (0x%04x)\n",
 				modelist[8].name ? modelist[8].name : "unknown",val);
 			val = 0x0009;
 			msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, val);
@@ -1168,11 +1197,24 @@
 			msp->stereo = VIDEO_SOUND_STEREO;
 			msp->nicam_on = 0;
 			msp->watch_stereo = 0;
+			/* not needed in theory if HAVE_RADIO(), but
+			   short programming enables carrier mute */
+			msp3400c_setmode(client,MSP_MODE_FM_RADIO);
+			msp3400c_setcarrier(client, MSP_CARRIER(10.7),
+					    MSP_CARRIER(10.7));
 			/* scart routing */
 			msp3400c_set_scart(client,SCART_IN2,0);
+#if 0
+			/* radio from SCART_IN2 */
 			msp3400c_write(client,I2C_MSP3400C_DFP, 0x08, 0x0220);
 			msp3400c_write(client,I2C_MSP3400C_DFP, 0x09, 0x0220);
 			msp3400c_write(client,I2C_MSP3400C_DFP, 0x0b, 0x0220);
+#else
+			/* msp34xx does radio decoding */
+			msp3400c_write(client,I2C_MSP3400C_DFP, 0x08, 0x0020);
+			msp3400c_write(client,I2C_MSP3400C_DFP, 0x09, 0x0020);
+			msp3400c_write(client,I2C_MSP3400C_DFP, 0x0b, 0x0020);
+#endif
 			break;
 		case 0x0003:
 			msp->mode   = MSP_MODE_FM_TERRA;
@@ -1195,7 +1237,7 @@
 	}
 
 done:
-	dprintk("msp3410: thread: exit\n");
+	dprintk(KERN_DEBUG "msp3410: thread: exit\n");
 	msp->active = 0;
 	msp->thread = NULL;
 
@@ -1213,19 +1255,19 @@
 static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg);
 
 static struct i2c_driver driver = {
-        name:           "i2c msp3400 driver",
-        id:             I2C_DRIVERID_MSP3400,
-        flags:          I2C_DF_NOTIFY,
-        attach_adapter: msp_probe,
-        detach_client:  msp_detach,
-        command:        msp_command,
+        .name           = "i2c msp3400 driver",
+        .id             = I2C_DRIVERID_MSP3400,
+        .flags          = I2C_DF_NOTIFY,
+        .attach_adapter = msp_probe,
+        .detach_client  = msp_detach,
+        .command        = msp_command,
 };
 
 static struct i2c_client client_template = 
 {
-	name:   "(unset)",
-	flags:  I2C_CLIENT_ALLOW_USE,
-        driver: &driver,
+	.name   = "(unset)",
+	.flags  = I2C_CLIENT_ALLOW_USE,
+        .driver = &driver,
 };
 
 static int msp_attach(struct i2c_adapter *adap, int addr,
@@ -1234,7 +1276,7 @@
 	DECLARE_MUTEX_LOCKED(sem);
 	struct msp3400c *msp;
         struct i2c_client *c;
-	int              rev1,rev2,i;
+	int i;
 
         client_template.adapter = adap;
         client_template.addr = addr;
@@ -1258,6 +1300,7 @@
 	msp->bass   = 32768;
 	msp->treble = 32768;
 	msp->input  = -1;
+	msp->muted  = 1;
 	for (i = 0; i < DFP_COUNT; i++)
 		msp->dfp_regs[i] = -1;
 
@@ -1271,10 +1314,10 @@
 		return -1;
 	}
     
-	rev1 = msp3400c_read(c, I2C_MSP3400C_DFP, 0x1e);
-	if (-1 != rev1)
-		rev2 = msp3400c_read(c, I2C_MSP3400C_DFP, 0x1f);
-	if ((-1 == rev1) || (0 == rev1 && 0 == rev2)) {
+	msp->rev1 = msp3400c_read(c, I2C_MSP3400C_DFP, 0x1e);
+	if (-1 != msp->rev1)
+		msp->rev2 = msp3400c_read(c, I2C_MSP3400C_DFP, 0x1f);
+	if ((-1 == msp->rev1) || (0 == msp->rev1 && 0 == msp->rev2)) {
 		kfree(msp);
 		kfree(c);
 		printk("msp3400: error while reading chip version\n");
@@ -1283,30 +1326,35 @@
 
 #if 0
 	/* this will turn on a 1kHz beep - might be useful for debugging... */
-	msp3400c_write(client,I2C_MSP3400C_DFP, 0x0014, 0x1040);
+	msp3400c_write(c,I2C_MSP3400C_DFP, 0x0014, 0x1040);
 #endif
+	msp3400c_setvolume(c,msp->muted,msp->left,msp->right);
 
 	sprintf(c->name,"MSP34%02d%c-%c%d",
-		(rev2>>8)&0xff, (rev1&0xff)+'@', ((rev1>>8)&0xff)+'@', rev2&0x1f);
-	msp->nicam = (((rev2>>8)&0xff) != 00) ? 1 : 0;
+		(msp->rev2>>8)&0xff, (msp->rev1&0xff)+'@',
+		((msp->rev1>>8)&0xff)+'@', msp->rev2&0x1f);
 
 	if (simple == -1) {
 		/* default mode */
-		/* msp->simple = (((rev2>>8)&0xff) == 0) ? 0 : 1; */
-		msp->simple = ((rev1&0xff)+'@' > 'C');
+		msp->simple = HAVE_SIMPLE(msp);
 	} else {
 		/* use insmod option */
 		msp->simple = simple;
 	}
 
 	/* timer for stereo checking */
+	init_timer(&msp->wake_stereo);
 	msp->wake_stereo.function = msp3400c_stereo_wake;
 	msp->wake_stereo.data     = (unsigned long)msp;
 
 	/* hello world :-) */
 	printk(KERN_INFO "msp34xx: init: chip=%s",c->name);
-	if (msp->nicam)
-		printk(", has NICAM support");
+	if (HAVE_NICAM(msp))
+		printk(" +nicam");
+	if (HAVE_SIMPLE(msp))
+		printk(" +simple");
+	if (HAVE_RADIO(msp))
+		printk(" +radio");
 	printk("\n");
 
 	/* startup control thread */
@@ -1434,7 +1482,7 @@
 		msp->norm = VIDEO_MODE_RADIO;
 		msp->watch_stereo=0;
 		del_timer(&msp->wake_stereo);
-		dprintk("msp34xx: switching to radio mode\n");
+		dprintk(KERN_DEBUG "msp34xx: switching to radio mode\n");
 		if (msp->simple) {
 			/* the thread will do for us */
 			msp_wake_thread(client);
@@ -1453,7 +1501,7 @@
 	case MSP_SET_DFPREG:
 	{
 		struct msp_dfpreg *r = arg;
-		int i;
+		unsigned int i;
 
 		if (r->reg < 0 || r->reg >= DFP_COUNT)
 			return -EINVAL;
@@ -1521,7 +1569,7 @@
 		msp3400c_setbass(client,msp->bass);
 		msp3400c_settreble(client,msp->treble);
 
-		if (va->mode != 0) {
+		if (va->mode != 0 && msp->norm != VIDEO_MODE_RADIO) {
 			msp->watch_stereo=0;
 			del_timer(&msp->wake_stereo);
 			msp->stereo = va->mode;
@@ -1534,7 +1582,6 @@
 		struct video_channel *vc = arg;
 		
 		dprintk(KERN_DEBUG "msp34xx: VIDIOCSCHAN\n");
-		dprintk("msp34xx: switching to TV mode\n");
 		msp->norm = vc->norm;
 		break;
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/video/pms.c linux-2.4.21-pre6/drivers/media/video/pms.c
--- linux-2.4.20/drivers/media/video/pms.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/media/video/pms.c	2003-03-26 23:49:20.000000000 +0000
@@ -622,7 +622,7 @@
 }
 
 
-static int pms_capture(struct pms_device *dev, char *buf, int rgb555, int count)
+static int pms_capture(struct pms_device *dev, char *buf, int rgb555, unsigned long count)
 {
 	int y;
 	int dw = 2*dev->width;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/video/tda7432.c linux-2.4.21-pre6/drivers/media/video/tda7432.c
--- linux-2.4.20/drivers/media/video/tda7432.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/media/video/tda7432.c	2003-03-26 23:49:50.000000000 +0000
@@ -52,6 +52,10 @@
 #include "audiochip.h"
 #include "id.h"
 
+#ifndef VIDEO_AUDIO_BALANCE
+# define VIDEO_AUDIO_BALANCE 32
+#endif
+
 MODULE_AUTHOR("Eric Sandeen <eric_sandeen@bigfoot.com>");
 MODULE_DESCRIPTION("bttv driver for the tda7432 audio processor chip");
 MODULE_LICENSE("GPL");
@@ -68,19 +72,10 @@
 /* Address to scan (I2C address of this chip) */
 static unsigned short normal_i2c[] = {
 	I2C_TDA7432 >> 1,
-	I2C_CLIENT_END};
-static unsigned short normal_i2c_range[] = {I2C_CLIENT_END};
-static unsigned short probe[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short probe_range[2]  = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore[2]       = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short force[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
-static struct i2c_client_address_data addr_data = {
-	normal_i2c, normal_i2c_range, 
-	probe, probe_range, 
-	ignore, ignore_range, 
-	force
+	I2C_CLIENT_END,
 };
+static unsigned short normal_i2c_range[] = { I2C_CLIENT_END, I2C_CLIENT_END };
+I2C_CLIENT_INSMOD;
 
 /* Structure of address and subaddresses for the tda7432 */
 
@@ -395,10 +390,10 @@
 		 * Max (0dB) is 0x20 (829)
 		 * (Mask out bit 7 of vol - it's for the loudness setting)
 		 */
-		if(!maxvol){  /* max +20db */
+		if (!maxvol){  /* max +20db */
 			va->volume = ( 0x6f - (t->volume & 0x7F) ) * 630;
-		} else {     /* max 0db   */
-			va->volume = (int )(( 0x6f - (t->volume & 0x7F) ) * 829.557);
+		} else {       /* max 0db   */
+			va->volume = ( 0x6f - (t->volume & 0x7F) ) * 829;
 		}
 		
 		/* Balance depends on L,R attenuation
@@ -436,11 +431,10 @@
 		dprintk("tda7432: VIDEOCSAUDIO\n");
 
 		if(va->flags & VIDEO_AUDIO_VOLUME){
-				
 			if(!maxvol){ /* max +20db */
-				t->volume = 0x6f - ( (va->volume)/630 );
+				t->volume = 0x6f - ((va->volume)/630);
 			} else {    /* max 0db   */
-				t->volume = 0x6f - ((int) (va->volume)/829.557 );
+				t->volume = 0x6f - ((va->volume)/829);
 			}
 		
 		if (loudness)		/* Turn on the loudness bit */
@@ -520,35 +514,28 @@
 	return 0;
 }
 
-
 static struct i2c_driver driver = {
-        "i2c tda7432 driver",
-	I2C_DRIVERID_TDA7432,
-        I2C_DF_NOTIFY,
-	tda7432_probe,
-        tda7432_detach,
-        tda7432_command,
+        .name            = "i2c tda7432 driver",
+	.id              = I2C_DRIVERID_TDA7432,
+        .flags           = I2C_DF_NOTIFY,
+	.attach_adapter  = tda7432_probe,
+        .detach_client   = tda7432_detach,
+        .command         = tda7432_command,
 };
 
 static struct i2c_client client_template =
 {
-        "(unset)",		/* name */
-        -1,
-        0,
-        0,
-        NULL,
-        &driver
+        .name   = "tda7432",
+        .id     = -1,
+	.driver = &driver, 
 };
 
 static int tda7432_init(void)
 {
-
-	if ( (loudness < 0) || (loudness > 15) )
-	{
+	if ( (loudness < 0) || (loudness > 15) ) {
 		printk(KERN_ERR "tda7432: loudness parameter must be between 0 and 15\n");
 		return -EINVAL;
 	}
-
 	i2c_add_driver(&driver);
 	return 0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/video/tda9875.c linux-2.4.21-pre6/drivers/media/video/tda9875.c
--- linux-2.4.20/drivers/media/video/tda9875.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/media/video/tda9875.c	2003-03-26 23:49:34.000000000 +0000
@@ -42,19 +42,10 @@
 /* Addresses to scan */
 static unsigned short normal_i2c[] =  {
     I2C_TDA9875 >> 1,
-    I2C_CLIENT_END};
-static unsigned short normal_i2c_range[] = {I2C_CLIENT_END};
-static unsigned short probe[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short probe_range[2]  = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore[2]       = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short force[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
-static struct i2c_client_address_data addr_data = {
-	normal_i2c, normal_i2c_range, 
-	probe, probe_range, 
-	ignore, ignore_range, 
-	force
+    I2C_CLIENT_END
 };
+static unsigned short normal_i2c_range[] = {I2C_CLIENT_END};
+I2C_CLIENT_INSMOD;
 
 /* This is a superset of the TDA9875 */
 struct tda9875 {
@@ -64,7 +55,6 @@
 	struct i2c_client c;
 };
 
-
 static struct i2c_driver driver;
 static struct i2c_client client_template;
 
@@ -397,22 +387,19 @@
 
 
 static struct i2c_driver driver = {
-        "i2c tda9875 driver",
-        I2C_DRIVERID_TDA9875, /* Get new one for TDA9875 */
-        I2C_DF_NOTIFY,
-	tda9875_probe,
-        tda9875_detach,
-        tda9875_command,
+        .name           = "i2c tda9875 driver",
+        .id             = I2C_DRIVERID_TDA9875,
+        .flags          = I2C_DF_NOTIFY,
+	.attach_adapter = tda9875_probe,
+        .detach_client  = tda9875_detach,
+        .command        = tda9875_command,
 };
 
 static struct i2c_client client_template =
 {
-        "(unset)",		/* name */
-        -1,
-        0,
-        0,
-        NULL,
-        &driver
+        .name    = "tda9875",
+        .id      = -1,
+        .driver  = &driver,
 };
 
 static int tda9875_init(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/video/tda9887.c linux-2.4.21-pre6/drivers/media/video/tda9887.c
--- linux-2.4.20/drivers/media/video/tda9887.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/media/video/tda9887.c	2003-03-26 23:49:54.000000000 +0000
@@ -0,0 +1,485 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/types.h>
+#include <linux/videodev.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+#include "id.h"
+#include "audiochip.h"
+
+/* Chips:
+   TDA9885 (PAL, NTSC)
+   TDA9886 (PAL, SECAM, NTSC)
+   TDA9887 (PAL, SECAM, NTSC, FM Radio)
+
+   found on:
+   - Pinnacle PCTV (Jul.2002 Version with MT2032, bttv)
+      TDA9887 (world), TDA9885 (USA)
+      Note: OP2 of tda988x must be set to 1, else MT2032 is disabled!
+   - KNC One TV-Station RDS (saa7134)
+*/
+    
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = {I2C_CLIENT_END};
+static unsigned short normal_i2c_range[] = {0x86>>1,0x86>>1,I2C_CLIENT_END};
+I2C_CLIENT_INSMOD;
+
+/* insmod options */
+static int debug =  0;
+static char *pal =  "b";
+static char *secam =  "l";
+MODULE_PARM(debug,"i");
+MODULE_PARM(pal,"s");
+MODULE_PARM(secam,"s");
+MODULE_LICENSE("GPL");
+
+/* ---------------------------------------------------------------------- */
+
+#define dprintk     if (debug) printk
+
+struct tda9887 {
+	struct i2c_client client;
+	int radio,tvnorm;
+	int pinnacle_id;
+};
+
+static struct i2c_driver driver;
+static struct i2c_client client_template;
+
+/* ---------------------------------------------------------------------- */
+
+//
+// TDA defines
+//
+
+//// first reg
+#define cVideoTrapBypassOFF     0x00    // bit b0
+#define cVideoTrapBypassON      0x01    // bit b0
+
+#define cAutoMuteFmInactive     0x00    // bit b1
+#define cAutoMuteFmActive       0x02    // bit b1
+
+#define cIntercarrier           0x00    // bit b2
+#define cQSS                    0x04    // bit b2
+
+#define cPositiveAmTV           0x00    // bit b3:4
+#define cFmRadio                0x08    // bit b3:4
+#define cNegativeFmTV           0x10    // bit b3:4
+
+
+#define cForcedMuteAudioON      0x20    // bit b5
+#define cForcedMuteAudioOFF     0x00    // bit b5
+
+#define cOutputPort1Active      0x00    // bit b6
+#define cOutputPort1Inactive    0x40    // bit b6
+
+#define cOutputPort2Active      0x00    // bit b7
+#define cOutputPort2Inactive    0x80    // bit b7
+
+
+//// second reg
+#define cDeemphasisOFF          0x00    // bit c5
+#define cDeemphasisON           0x20    // bit c5
+
+#define cDeemphasis75           0x00    // bit c6
+#define cDeemphasis50           0x40    // bit c6
+
+#define cAudioGain0             0x00    // bit c7
+#define cAudioGain6             0x80    // bit c7
+
+
+//// third reg
+#define cAudioIF_4_5             0x00    // bit e0:1
+#define cAudioIF_5_5             0x01    // bit e0:1
+#define cAudioIF_6_0             0x02    // bit e0:1
+#define cAudioIF_6_5             0x03    // bit e0:1
+
+
+#define cVideoIF_58_75           0x00    // bit e2:4
+#define cVideoIF_45_75           0x04    // bit e2:4
+#define cVideoIF_38_90           0x08    // bit e2:4
+#define cVideoIF_38_00           0x0C    // bit e2:4
+#define cVideoIF_33_90           0x10    // bit e2:4
+#define cVideoIF_33_40           0x14    // bit e2:4
+#define cRadioIF_45_75           0x18    // bit e2:4
+#define cRadioIF_38_90           0x1C    // bit e2:4
+
+
+#define cTunerGainNormal         0x00    // bit e5
+#define cTunerGainLow            0x20    // bit e5
+
+#define cGating_18               0x00    // bit e6
+#define cGating_36               0x40    // bit e6
+
+#define cAgcOutON                0x80    // bit e7
+#define cAgcOutOFF               0x00    // bit e7
+
+static int tda9887_miro(struct tda9887 *t)
+{
+	int rc;
+	u8   bData[4]     = { 0 };
+	u8   bVideoIF     = 0;
+	u8   bAudioIF     = 0;
+	u8   bDeEmphasis  = 0;
+	u8   bDeEmphVal   = 0;
+	u8   bModulation  = 0;
+	u8   bCarrierMode = 0;
+	u8   bOutPort1    = cOutputPort1Inactive;
+#if 0
+	u8   bOutPort2    = cOutputPort2Inactive & mbTADState; // store i2c tuner state
+#else
+	u8   bOutPort2    = cOutputPort2Inactive;
+#endif
+	u8   bVideoTrap   = cVideoTrapBypassOFF;
+#if 1
+	u8   bTopAdjust   = 0x0e /* -2dB */;
+#else
+	u8   bTopAdjust   = 0;
+#endif
+
+#if 0
+	if (mParams.fVideoTrap)
+		bVideoTrap   = cVideoTrapBypassON;
+#endif
+
+	if (t->radio) {
+		bVideoTrap   = cVideoTrapBypassOFF;
+		bCarrierMode = cQSS;
+		bModulation  = cFmRadio;
+		bOutPort1    = cOutputPort1Inactive;
+		bDeEmphasis  = cDeemphasisON;
+		if (3 == t->pinnacle_id) {
+			/* ntsc */
+			bDeEmphVal   = cDeemphasis75;
+			bAudioIF     = cAudioIF_4_5;
+			bVideoIF     = cRadioIF_45_75;
+		} else {
+			/* pal */
+			bAudioIF     = cAudioIF_5_5;
+			bVideoIF     = cRadioIF_38_90;
+			bDeEmphVal   = cDeemphasis50;
+		}
+
+	} else if (t->tvnorm == VIDEO_MODE_PAL) {
+		bDeEmphasis  = cDeemphasisON;
+		bDeEmphVal   = cDeemphasis50;
+		bModulation  = cNegativeFmTV;
+		bOutPort1    = cOutputPort1Inactive;
+		if (1 == t->pinnacle_id) {
+			bCarrierMode = cIntercarrier;
+		} else {
+			// stereo boards
+			bCarrierMode = cQSS;
+		}
+		switch (pal[0]) {
+		case 'b':
+		case 'g':
+		case 'h':
+			bVideoIF     = cVideoIF_38_90;
+			bAudioIF     = cAudioIF_5_5;
+			break;
+		case 'd':
+			bVideoIF     = cVideoIF_38_00;
+			bAudioIF     = cAudioIF_6_5;
+			break;
+		case 'i':
+			bVideoIF     = cVideoIF_38_90;
+			bAudioIF     = cAudioIF_6_0;
+			break;
+		case 'm':
+		case 'n':
+			bVideoIF     = cVideoIF_45_75;
+			bAudioIF     = cAudioIF_4_5;
+			bDeEmphVal   = cDeemphasis75;
+			if ((5 == t->pinnacle_id) || (6 == t->pinnacle_id)) {
+				bCarrierMode = cIntercarrier;
+			} else {
+				bCarrierMode = cQSS;
+			}
+			break;
+		}
+
+	} else if (t->tvnorm == VIDEO_MODE_SECAM) {
+		bAudioIF     = cAudioIF_6_5;
+		bDeEmphasis  = cDeemphasisON;
+		bDeEmphVal   = cDeemphasis50;
+		bModulation  = cNegativeFmTV;
+		bCarrierMode = cQSS;
+		bOutPort1    = cOutputPort1Inactive;                
+		switch (secam[0]) {
+		case 'd':
+			bVideoIF     = cVideoIF_38_00;
+			break;
+		case 'k':
+			bVideoIF     = cVideoIF_38_90;
+			break;
+		case 'l':
+			bVideoIF     = cVideoIF_38_90;
+			bDeEmphasis  = cDeemphasisOFF;
+			bDeEmphVal   = cDeemphasis75;
+			bModulation  = cPositiveAmTV;
+			break;
+		case 'L' /* L1 */:
+			bVideoIF     = cVideoIF_33_90;
+			bDeEmphasis  = cDeemphasisOFF;
+			bDeEmphVal   = cDeemphasis75;
+			bModulation  = cPositiveAmTV;
+			break;
+		}
+
+	} else if (t->tvnorm == VIDEO_MODE_NTSC) {
+                bVideoIF     = cVideoIF_45_75;
+                bAudioIF     = cAudioIF_4_5;
+                bDeEmphasis  = cDeemphasisON;
+                bDeEmphVal   = cDeemphasis75;
+                bModulation  = cNegativeFmTV;                
+                bOutPort1    = cOutputPort1Inactive;
+                if ((5 == t->pinnacle_id) || (6 == t->pinnacle_id)) {
+			bCarrierMode = cIntercarrier;
+		} else {
+			bCarrierMode = cQSS;
+                }
+	}
+
+	bData[1] = bVideoTrap        |  // B0: video trap bypass
+		cAutoMuteFmInactive  |  // B1: auto mute
+		bCarrierMode         |  // B2: InterCarrier for PAL else QSS 
+		bModulation          |  // B3 - B4: positive AM TV for SECAM only
+		cForcedMuteAudioOFF  |  // B5: forced Audio Mute (off)
+		bOutPort1            |  // B6: Out Port 1 
+		bOutPort2;              // B7: Out Port 2 
+	bData[2] = bTopAdjust |   // C0 - C4: Top Adjust 0 == -16dB  31 == 15dB
+		bDeEmphasis   |   // C5: De-emphasis on/off
+		bDeEmphVal    |   // C6: De-emphasis 50/75 microsec
+		cAudioGain0;      // C7: normal audio gain
+	bData[3] = bAudioIF      |  // E0 - E1: Sound IF
+		bVideoIF         |  // E2 - E4: Video IF
+		cTunerGainNormal |  // E5: Tuner gain (normal)
+		cGating_18       |  // E6: Gating (18%)
+		cAgcOutOFF;         // E7: VAGC  (off)
+	
+	dprintk("tda9885/6/7: 0x%02x 0x%02x 0x%02x [pinnacle_id=%d]\n",
+		bData[1],bData[2],bData[3],t->pinnacle_id);
+	if (4 != (rc = i2c_master_send(&t->client,bData,4)))
+		printk("tda9885/6/7: i2c i/o error: rc == %d (should be 4)\n",rc);
+	return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+#if 0
+/* just for reference: old knc-one saa7134 stuff */
+static unsigned char buf_pal_bg[]    = { 0x00, 0x16, 0x70, 0x49 };
+static unsigned char buf_pal_i[]     = { 0x00, 0x16, 0x70, 0x4a };
+static unsigned char buf_pal_dk[]    = { 0x00, 0x16, 0x70, 0x4b };
+static unsigned char buf_pal_l[]     = { 0x00, 0x06, 0x50, 0x4b };
+static unsigned char buf_fm_stereo[] = { 0x00, 0x0e, 0x0d, 0x77 };
+#endif
+
+static unsigned char buf_pal_bg[]    = { 0x00, 0x96, 0x70, 0x49 };
+static unsigned char buf_pal_i[]     = { 0x00, 0x96, 0x70, 0x4a };
+static unsigned char buf_pal_dk[]    = { 0x00, 0x96, 0x70, 0x4b };
+static unsigned char buf_pal_l[]     = { 0x00, 0x86, 0x50, 0x4b };
+static unsigned char buf_fm_stereo[] = { 0x00, 0x8e, 0x0d, 0x77 };
+static unsigned char buf_ntsc[]	     = { 0x00, 0x96, 0x70, 0x44 };
+static unsigned char buf_ntsc_jp[]   = { 0x00, 0x96, 0x70, 0x40 };
+
+static int tda9887_configure(struct tda9887 *t)
+{
+	unsigned char *buf = NULL;
+	int rc;
+
+	printk("tda9887_configure\n");
+
+	if (t->radio) {
+		dprintk("tda9885/6/7: FM Radio mode\n");
+		buf = buf_fm_stereo;
+
+	} else if (t->tvnorm == VIDEO_MODE_PAL) {
+		dprintk("tda9885/6/7: PAL-%c mode\n",pal[0]);
+		switch (pal[0]) {
+		case 'b':
+		case 'g':
+			buf = buf_pal_bg;
+			break;
+		case 'i':
+			buf = buf_pal_i;
+			break;
+		case 'd':
+		case 'k':
+			buf = buf_pal_dk;
+			break;
+		case 'l':
+			buf = buf_pal_l;
+			break;
+		}
+
+	} else if (t->tvnorm == VIDEO_MODE_NTSC) {
+		dprintk("tda9885/6/7: NTSC mode\n");
+		buf = buf_ntsc;
+
+	} else if (t->tvnorm == VIDEO_MODE_SECAM) {
+		dprintk("tda9885/6/7: SECAM mode\n");
+                buf = buf_pal_l;
+
+        } else if (t->tvnorm == 6 /* BTTV hack */) {
+		dprintk("tda9885/6/7: NTSC-Japan mode\n");
+                buf = buf_ntsc_jp;
+        }
+
+	if (NULL == buf) {
+		printk("tda9885/6/7 unknown norm=%d\n",t->tvnorm);
+		return 0;
+	}
+
+	dprintk("tda9885/6/7: 0x%02x 0x%02x 0x%02x\n",
+		buf[1],buf[2],buf[3]);
+        if (4 != (rc = i2c_master_send(&t->client,buf,4)))
+                printk("tda9885/6/7: i2c i/o error: rc == %d (should be 4)\n",rc);
+	return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int tda9887_attach(struct i2c_adapter *adap, int addr,
+			  unsigned short flags, int kind)
+{
+	struct tda9887 *t;
+
+        client_template.adapter = adap;
+        client_template.addr    = addr;
+
+        printk("tda9887: chip found @ 0x%x\n", addr<<1);
+
+        if (NULL == (t = kmalloc(sizeof(*t), GFP_KERNEL)))
+                return -ENOMEM;
+	memset(t,0,sizeof(*t));
+	t->client = client_template;
+        t->client.data = t;
+	t->pinnacle_id = -1;
+	t->tvnorm=VIDEO_MODE_PAL;
+        i2c_attach_client(&t->client);
+        
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int tda9887_probe(struct i2c_adapter *adap)
+{
+	int rc;
+
+	switch (adap->id) {
+	case I2C_ALGO_BIT | I2C_HW_B_BT848:
+	case I2C_ALGO_BIT | I2C_HW_B_RIVA:
+	case I2C_ALGO_SAA7134:
+		printk("tda9887: probing %s i2c adapter [id=0x%x]\n",
+		       adap->name,adap->id);
+		rc = i2c_probe(adap, &addr_data, tda9887_attach);
+		break;
+	default:
+		printk("tda9887: ignoring %s i2c adapter [id=0x%x]\n",
+		       adap->name,adap->id);
+		rc = 0;
+		/* nothing */
+	}
+	return rc;
+}
+
+static int tda9887_detach(struct i2c_client *client)
+{
+	struct tda9887 *t = (struct tda9887*)client->data;
+
+	i2c_detach_client(client);
+	kfree(t);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int
+tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg)
+{
+	struct tda9887 *t = (struct tda9887*)client->data;
+
+        switch (cmd) {
+
+	/* --- configuration --- */
+	case AUDC_SET_RADIO:
+		t->radio = 1;
+		if (-1 != t->pinnacle_id)
+			tda9887_miro(t);
+		else
+			tda9887_configure(t);
+		break;
+		
+	case AUDC_CONFIG_PINNACLE:
+	{
+		int *i = arg;
+
+		t->pinnacle_id = *i;
+		tda9887_miro(t);
+		break;
+	}
+	/* --- v4l ioctls --- */
+	/* take care: bttv does userspace copying, we'll get a
+	   kernel pointer here... */
+	case VIDIOCSCHAN:
+	{
+		struct video_channel *vc = arg;
+
+		t->radio  = 0;
+		t->tvnorm = vc->norm;
+		if (-1 != t->pinnacle_id)
+			tda9887_miro(t);
+		else
+			tda9887_configure(t);
+		break;
+	}
+	default:
+		/* nothing */
+		break;
+	}
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_driver driver = {
+        .name           = "i2c tda9887 driver",
+        .id             = -1, /* FIXME */
+        .flags          = I2C_DF_NOTIFY,
+        .attach_adapter = tda9887_probe,
+        .detach_client  = tda9887_detach,
+        .command        = tda9887_command,
+};
+static struct i2c_client client_template =
+{
+        .name   = "tda9887",
+	.flags  = I2C_CLIENT_ALLOW_USE,
+        .driver = &driver,
+};
+
+static int tda9887_init_module(void)
+{
+	i2c_add_driver(&driver);
+	return 0;
+}
+
+static void tda9887_cleanup_module(void)
+{
+	i2c_del_driver(&driver);
+}
+
+module_init(tda9887_init_module);
+module_exit(tda9887_cleanup_module);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/video/tuner.c linux-2.4.21-pre6/drivers/media/video/tuner.c
--- linux-2.4.20/drivers/media/video/tuner.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/media/video/tuner.c	2003-03-26 23:49:53.000000000 +0000
@@ -18,25 +18,17 @@
 /* Addresses to scan */
 static unsigned short normal_i2c[] = {I2C_CLIENT_END};
 static unsigned short normal_i2c_range[] = {0x60,0x6f,I2C_CLIENT_END};
-static unsigned short probe[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short probe_range[2]  = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore[2]       = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short force[2]        = { I2C_CLIENT_END, I2C_CLIENT_END };
-static struct i2c_client_address_data addr_data = {
-	normal_i2c, normal_i2c_range, 
-	probe, probe_range, 
-	ignore, ignore_range, 
-	force
-};
+I2C_CLIENT_INSMOD;
+
+#define UNSET (-1U)
 
 /* insmod options */
-static int debug =  0;
-static int type  = -1;
-static int addr  =  0;
+static unsigned int debug =  0;
+static unsigned int type  =  UNSET;
+static unsigned int addr  =  0;
 static char *pal =  "b";
-static int tv_range[2]    = { 44, 958 };
-static int radio_range[2] = { 65, 108 };
+static unsigned int tv_range[2]    = { 44, 958 };
+static unsigned int radio_range[2] = { 65, 108 };
 MODULE_PARM(debug,"i");
 MODULE_PARM(type,"i");
 MODULE_PARM(addr,"i");
@@ -55,13 +47,16 @@
 
 struct tuner
 {
-	int type;            /* chip type */
-	int freq;            /* keep track of the current settings */
-	int std;
-
-	int radio;
-	int mode;            /* current norm for multi-norm tuners */
-	int xogc;	     // only for MT2032
+	unsigned int type;            /* chip type */
+	unsigned int freq;            /* keep track of the current settings */
+	unsigned int std;
+	
+	unsigned int radio;
+	unsigned int mode;            /* current norm for multi-norm tuners */
+	
+	// only for MT2032
+	unsigned int xogc;
+	unsigned int radio_if2;
 };
 
 static struct i2c_driver driver;
@@ -127,7 +122,9 @@
 	unsigned char VHF_H;
 	unsigned char UHF;
 	unsigned char config; 
-	unsigned short IFPCoff; /* 622.4=16*38.90 MHz PAL, 732=16*45.75 NTSC */
+	unsigned short IFPCoff; /* 622.4=16*38.90 MHz PAL, 
+				   732  =16*45.75 NTSCi, 
+				   940  =58.75 NTSC-Japan */
 };
 
 /*
@@ -140,7 +137,7 @@
 	  16*140.25,16*463.25,0x02,0x04,0x01,0x8e,623},
 	{ "Philips PAL_I (FI1246 and compatibles)", Philips, PAL_I,
 	  16*140.25,16*463.25,0xa0,0x90,0x30,0x8e,623},
-	{ "Philips NTSC (FI1236 and compatibles)", Philips, NTSC,
+	{ "Philips NTSC (FI1236,FM1236 and compatibles)", Philips, NTSC,
 	  16*157.25,16*451.25,0xA0,0x90,0x30,0x8e,732},
 	{ "Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF)", Philips, SECAM,
 	  16*168.25,16*447.25,0xA7,0x97,0x37,0x8e,623},
@@ -226,7 +223,7 @@
 	{ "LG NTSC (newer TAPC series)", LGINNOTEK, NTSC,
           16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,732},
 };
-#define TUNERS (sizeof(tuners)/sizeof(struct tunertype))
+#define TUNERS (sizeof(tuners)/sizeof(tuners[0]))
 
 /* ---------------------------------------------------------------------- */
 
@@ -303,6 +300,13 @@
                 }
                 printk("\n ");
         }
+	// Look for MT2032 id:
+	// part= 0x04(MT2032), 0x06(MT2030), 0x07(MT2040)
+        if((buf[0x11] != 0x4d) || (buf[0x12] != 0x54) || (buf[0x13] != 0x04)) {
+                printk("not a MT2032.\n");
+                return 0;
+        }
+
 
         // Initialize Registers per spec.
         buf[1]=2; // Index to register 2
@@ -382,10 +386,15 @@
 	return 1;
 }
 
-static int mt2032_compute_freq(int rfin, int if1, int if2, int spectrum_from,
-	int spectrum_to, unsigned char *buf, int *ret_sel, int xogc) //all in Hz
+static int mt2032_compute_freq(unsigned int rfin,
+			       unsigned int if1, unsigned int if2,
+			       unsigned int spectrum_from,
+			       unsigned int spectrum_to,
+			       unsigned char *buf,
+			       int *ret_sel,
+			       unsigned int xogc) //all in Hz
 {
-        int fref,lo1,lo1n,lo1a,s,sel,lo1freq, desired_lo1,
+        unsigned int fref,lo1,lo1n,lo1a,s,sel,lo1freq, desired_lo1,
 		desired_lo2,lo2,lo2n,lo2a,lo2num,lo2freq;
 
         fref= 5250 *1000; //5.25MHz
@@ -514,7 +523,9 @@
 }
 
 
-static void mt2032_set_if_freq(struct i2c_client *c,int rfin, int if1, int if2, int from, int to)
+static void mt2032_set_if_freq(struct i2c_client *c, unsigned int rfin,
+			       unsigned int if1, unsigned int if2,
+			       unsigned int from, unsigned int to)
 {
 	unsigned char buf[21];
 	int lint_try,ret,sel,lock=0;
@@ -569,7 +580,8 @@
 }
 
 
-static void mt2032_set_tv_freq(struct i2c_client *c, int freq, int norm)
+static void mt2032_set_tv_freq(struct i2c_client *c,
+			       unsigned int freq, unsigned int norm)
 {
 	int if2,from,to;
 
@@ -590,7 +602,7 @@
 
 
 // Set tuner frequency,  freq in Units of 62.5kHz = 1/16MHz
-static void set_tv_freq(struct i2c_client *c, int freq)
+static void set_tv_freq(struct i2c_client *c, unsigned int freq)
 {
 	u8 config;
 	u16 div;
@@ -599,7 +611,7 @@
         unsigned char buffer[4];
 	int rc;
 
-	if (t->type == -1) {
+	if (t->type == UNSET) {
 		printk("tuner: tuner type not set\n");
 		return;
 	}
@@ -721,21 +733,22 @@
 
 }
 
-static void mt2032_set_radio_freq(struct i2c_client *c,int freq)
-{               
-        int if2;
-
-        if2=10700*1000; //  10.7MHz FM intermediate frequency
+static void mt2032_set_radio_freq(struct i2c_client *c, int freq)
+{
+	struct tuner *t = (struct tuner*)c->data;
+	int if2 = t->radio_if2;
 
+	// per Manual for FM tuning: first if center freq. 1085 MHz
         mt2032_set_if_freq(c,freq* 1000*1000/16, 1085*1000*1000,if2,if2,if2);
 }
 
-static void set_radio_freq(struct i2c_client *c, int freq)
+static void set_radio_freq(struct i2c_client *c, unsigned int freq)
 {
 	struct tunertype *tun;
 	struct tuner *t = (struct tuner*)c->data;
         unsigned char buffer[4];
-	int rc,div;
+	unsigned div;
+	int rc;
 
 	if (freq < radio_range[0]*16 || freq > radio_range[1]*16) {
 		printk("tuner: radio freq (%d.%02d) out of range (%d-%d)\n",
@@ -743,7 +756,7 @@
 		       radio_range[0],radio_range[1]);
 		return;
 	}
-	if (t->type == -1) {
+	if (t->type == UNSET) {
 		printk("tuner: tuner type not set\n");
 		return;
 	}
@@ -800,18 +813,19 @@
                 return -ENOMEM;
         }
         memset(t,0,sizeof(struct tuner));
-	if (type >= 0 && type < TUNERS) {
+	t->type       = UNSET;
+	t->radio_if2  = 10700*1000; // 10.7MHz - FM radio
+
+	if (type < TUNERS) {
 		t->type = type;
+		printk("tuner(bttv): type forced to %d (%s) [insmod]\n",t->type,tuners[t->type].name);
 		strncpy(client->name, tuners[t->type].name, sizeof(client->name));
-	} else {
-		t->type = -1;
 	}
         i2c_attach_client(client);
         if (t->type == TUNER_MT2032)
                  mt2032_init(client);
 
 	MOD_INC_USE_COUNT;
-
 	return 0;
 }
 
@@ -828,6 +842,7 @@
 	case I2C_ALGO_BIT | I2C_HW_B_BT848:
 	case I2C_ALGO_BIT | I2C_HW_B_RIVA:
 	case I2C_ALGO_SAA7134:
+	case I2C_ALGO_SAA7146:
 		printk("tuner: probing %s i2c adapter [id=0x%x]\n",
 		       adap->name,adap->id);
 		rc = i2c_probe(adap, &addr_data, tuner_attach);
@@ -856,21 +871,20 @@
 tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
 {
 	struct tuner *t = (struct tuner*)client->data;
-        int   *iarg = (int*)arg;
-#if 0
-        __u16 *sarg = (__u16*)arg;
-#endif
+        unsigned int *iarg = (int*)arg;
 
         switch (cmd) {
 
 	/* --- configuration --- */
 	case TUNER_SET_TYPE:
-		if (t->type != -1)
+		if (t->type != UNSET) {
+			printk("tuner: type already set (%d)\n",t->type);
 			return 0;
-		if (*iarg < 0 || *iarg >= TUNERS)
+		}
+		if (*iarg >= TUNERS)
 			return 0;
 		t->type = *iarg;
-		dprintk("tuner: type set to %d (%s)\n",
+		printk("tuner: type set to %d (%s)\n",
                         t->type,tuners[t->type].name);
 		strncpy(client->name, tuners[t->type].name, sizeof(client->name));
 		if (t->type == TUNER_MT2032)
@@ -879,6 +893,18 @@
 	case AUDC_SET_RADIO:
 		t->radio = 1;
 		break;
+	case AUDC_CONFIG_PINNACLE:
+		switch (*iarg) {
+		case 2:
+			dprintk("tuner: pinnacle pal\n");
+			t->radio_if2 = 33300 * 1000;
+			break;
+		case 3:
+			dprintk("tuner: pinnacle ntsc\n");
+			t->radio_if2 = 41300 * 1000;
+			break;
+		}
+                break;
 		
 	/* --- v4l ioctls --- */
 	/* take care: bttv does userspace copying, we'll get a
@@ -924,35 +950,6 @@
 			va->mode = (tuner_stereo(client) ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO);
 		return 0;
 	}
-	
-#if 0
-	/* --- old, obsolete interface --- */
-	case TUNER_SET_TVFREQ:
-		dprintk("tuner: tv freq set to %d.%02d\n",
-			(*iarg)/16,(*iarg)%16*100/16);
-		set_tv_freq(client,*iarg);
-		t->radio = 0;
-		t->freq = *iarg;
-		break;
-
-	case TUNER_SET_RADIOFREQ:
-		dprintk("tuner: radio freq set to %d.%02d\n",
-			(*iarg)/16,(*iarg)%16*100/16);
-		set_radio_freq(client,*iarg);
-		t->radio = 1;
-		t->freq = *iarg;
-		break;
-	case TUNER_SET_MODE:
-		if (t->type != TUNER_PHILIPS_SECAM) {
-			dprintk("tuner: trying to change mode for other than TUNER_PHILIPS_SECAM\n");
-		} else {
-			int mode=(*sarg==VIDEO_MODE_SECAM)?1:0;
-			dprintk("tuner: mode set to %d\n", *sarg);
-			t->mode = mode;
-			set_tv_freq(client,t->freq);
-		}
-		break;
-#endif
 	default:
 		/* nothing */
 		break;
@@ -964,18 +961,18 @@
 /* ----------------------------------------------------------------------- */
 
 static struct i2c_driver driver = {
-        name:           "i2c TV tuner driver",
-        id:             I2C_DRIVERID_TUNER,
-        flags:          I2C_DF_NOTIFY,
-        attach_adapter: tuner_probe,
-        detach_client:  tuner_detach,
-        command:        tuner_command,
+        .name           = "i2c TV tuner driver",
+        .id             = I2C_DRIVERID_TUNER,
+        .flags          = I2C_DF_NOTIFY,
+        .attach_adapter = tuner_probe,
+        .detach_client  = tuner_detach,
+        .command        = tuner_command,
 };
 static struct i2c_client client_template =
 {
-        name:   "(unset)",
-	flags:  I2C_CLIENT_ALLOW_USE,
-        driver: &driver,
+        .name   = "(tuner unset)",
+	.flags  = I2C_CLIENT_ALLOW_USE,
+        .driver = &driver,
 };
 
 static int tuner_init_module(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/video/tuner.h linux-2.4.21-pre6/drivers/media/video/tuner.h
--- linux-2.4.20/drivers/media/video/tuner.h	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/media/video/tuner.h	2003-03-26 23:49:09.000000000 +0000
@@ -86,7 +86,9 @@
 
 #define TUNER_SET_TYPE               _IOW('t',1,int)    /* set tuner type */
 #define TUNER_SET_TVFREQ             _IOW('t',2,int)    /* set tv freq */
-#define TUNER_SET_RADIOFREQ          _IOW('t',3,int)    /* set radio freq */
-#define TUNER_SET_MODE               _IOW('t',4,int)    /* set tuner mode */
+#if 0 /* obsolete */
+# define TUNER_SET_RADIOFREQ         _IOW('t',3,int)    /* set radio freq */
+# define TUNER_SET_MODE              _IOW('t',4,int)    /* set tuner mode */
+#endif
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/video/tvaudio.c linux-2.4.21-pre6/drivers/media/video/tvaudio.c
--- linux-2.4.20/drivers/media/video/tvaudio.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/media/video/tvaudio.c	2003-03-26 23:49:25.000000000 +0000
@@ -146,17 +146,7 @@
 	I2C_PIC16C54  >> 1,
 	I2C_CLIENT_END };
 static unsigned short normal_i2c_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short probe[2]            = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short probe_range[2]      = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore[2]           = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short ignore_range[2]     = { I2C_CLIENT_END, I2C_CLIENT_END };
-static unsigned short force[2]            = { I2C_CLIENT_END, I2C_CLIENT_END };
-static struct i2c_client_address_data addr_data = {
-	normal_i2c, normal_i2c_range, 
-	probe, probe_range, 
-	ignore, ignore_range, 
-	force
-};
+I2C_CLIENT_INSMOD;
 
 static struct i2c_driver driver;
 static struct i2c_client client_template;
@@ -1088,6 +1078,19 @@
 static int tda8425_shift10(int val) { return (val >> 10) | 0xc0; }
 static int tda8425_shift12(int val) { return (val >> 12) | 0xf0; }
 
+static int tda8425_initialize(struct CHIPSTATE *chip)
+{
+	struct CHIPDESC *desc = chiplist + chip->type;
+	int inputmap[8] = { /* tuner	*/ TDA8425_S1_CH2, /* radio  */ TDA8425_S1_CH1,
+			    /* extern	*/ TDA8425_S1_CH1, /* intern */ TDA8425_S1_OFF,
+			    /* off	*/ TDA8425_S1_OFF, /* on     */ TDA8425_S1_CH2};
+
+	if (chip->c.adapter->id == (I2C_ALGO_BIT | I2C_HW_B_RIVA)) {
+		memcpy (desc->inputmap, inputmap, sizeof (inputmap));
+	}
+	return 0;
+}
+
 static void tda8425_setmode(struct CHIPSTATE *chip, int mode)
 {
 	int s1 = chip->shadow.bytes[TDA8425_S1+1] & 0xe1;
@@ -1156,165 +1159,166 @@
 
 static struct CHIPDESC chiplist[] = {
 	{
-		name:       "tda9840",
-		id:         I2C_DRIVERID_TDA9840,
-		insmodopt:  &tda9840,
-		addr_lo:    I2C_TDA9840 >> 1,
-		addr_hi:    I2C_TDA9840 >> 1,
-		registers:  5,
-
-		getmode:    tda9840_getmode,
-		setmode:    tda9840_setmode,
-		checkmode:  generic_checkmode,
+		.name       = "tda9840",
+		.id         = I2C_DRIVERID_TDA9840,
+		.insmodopt  = &tda9840,
+		.addr_lo    = I2C_TDA9840 >> 1,
+		.addr_hi    = I2C_TDA9840 >> 1,
+		.registers  = 5,
+
+		.getmode    = tda9840_getmode,
+		.setmode    = tda9840_setmode,
+		.checkmode  = generic_checkmode,
 
-	        init:       { 2, { TDA9840_TEST, TDA9840_TEST_INT1SN
+	        .init       = { 2, { TDA9840_TEST, TDA9840_TEST_INT1SN
 				/* ,TDA9840_SW, TDA9840_MONO */} }
 	},
 	{
-		name:       "tda9873h",
-		id:         I2C_DRIVERID_TDA9873,
-		checkit:    tda9873_checkit,
-		insmodopt:  &tda9873,
-		addr_lo:    I2C_TDA985x_L >> 1,
-		addr_hi:    I2C_TDA985x_H >> 1,
-		registers:  3,
-		flags:      CHIP_HAS_INPUTSEL,
-
-		getmode:    tda9873_getmode,
-		setmode:    tda9873_setmode,
-		checkmode:  generic_checkmode,
-
-		init:       { 4, { TDA9873_SW, 0xa4, 0x06, 0x03 } },
-		inputreg:   TDA9873_SW,
-		inputmute:  TDA9873_MUTE | TDA9873_AUTOMUTE,
-		inputmap:   {0xa0, 0xa2, 0xa0, 0xa0, 0xc0},
-		inputmask:  TDA9873_INP_MASK | TDA9873_MUTE | TDA9873_AUTOMUTE
+		.name       = "tda9873h",
+		.id         = I2C_DRIVERID_TDA9873,
+		.checkit    = tda9873_checkit,
+		.insmodopt  = &tda9873,
+		.addr_lo    = I2C_TDA985x_L >> 1,
+		.addr_hi    = I2C_TDA985x_H >> 1,
+		.registers  = 3,
+		.flags      = CHIP_HAS_INPUTSEL,
+
+		.getmode    = tda9873_getmode,
+		.setmode    = tda9873_setmode,
+		.checkmode  = generic_checkmode,
+
+		.init       = { 4, { TDA9873_SW, 0xa4, 0x06, 0x03 } },
+		.inputreg   = TDA9873_SW,
+		.inputmute  = TDA9873_MUTE | TDA9873_AUTOMUTE,
+		.inputmap   = {0xa0, 0xa2, 0xa0, 0xa0, 0xc0},
+		.inputmask  = TDA9873_INP_MASK|TDA9873_MUTE|TDA9873_AUTOMUTE,
 		
 	},
 	{
-		name:       "tda9874h/a",
-		id:         I2C_DRIVERID_TDA9874,
-		checkit:    tda9874a_checkit,
-		initialize: tda9874a_initialize,
-		insmodopt:  &tda9874a,
-		addr_lo:    I2C_TDA9874 >> 1,
-		addr_hi:    I2C_TDA9874 >> 1,
-
-		getmode:    tda9874a_getmode,
-		setmode:    tda9874a_setmode,
-		checkmode:  generic_checkmode,
+		.name       = "tda9874h/a",
+		.id         = I2C_DRIVERID_TDA9874,
+		.checkit    = tda9874a_checkit,
+		.initialize = tda9874a_initialize,
+		.insmodopt  = &tda9874a,
+		.addr_lo    = I2C_TDA9874 >> 1,
+		.addr_hi    = I2C_TDA9874 >> 1,
+
+		.getmode    = tda9874a_getmode,
+		.setmode    = tda9874a_setmode,
+		.checkmode  = generic_checkmode,
 	},
 	{
-		name:       "tda9850",
-		id:         I2C_DRIVERID_TDA9850,
-		insmodopt:  &tda9850,
-		addr_lo:    I2C_TDA985x_L >> 1,
-		addr_hi:    I2C_TDA985x_H >> 1,
-		registers:  11,
+		.name       = "tda9850",
+		.id         = I2C_DRIVERID_TDA9850,
+		.insmodopt  = &tda9850,
+		.addr_lo    = I2C_TDA985x_L >> 1,
+		.addr_hi    = I2C_TDA985x_H >> 1,
+		.registers  = 11,
 
-		getmode:    tda985x_getmode,
-		setmode:    tda985x_setmode,
+		.getmode    = tda985x_getmode,
+		.setmode    = tda985x_setmode,
 
-		init:       { 8, { TDA9850_C4, 0x08, 0x08, TDA985x_STEREO, 0x07, 0x10, 0x10, 0x03 } }
+		.init       = { 8, { TDA9850_C4, 0x08, 0x08, TDA985x_STEREO, 0x07, 0x10, 0x10, 0x03 } }
 	},
 	{
-		name:       "tda9855",
-		id:         I2C_DRIVERID_TDA9855,
-		insmodopt:  &tda9855,
-		addr_lo:    I2C_TDA985x_L >> 1,
-		addr_hi:    I2C_TDA985x_H >> 1,
-		registers:  11,
-		flags:      CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE,
-
-		leftreg:    TDA9855_VL,
-		rightreg:   TDA9855_VR,
-		bassreg:    TDA9855_BA,
-		treblereg:  TDA9855_TR,
-		volfunc:    tda9855_volume,
-		bassfunc:   tda9855_bass,
-		treblefunc: tda9855_treble,
+		.name       = "tda9855",
+		.id         = I2C_DRIVERID_TDA9855,
+		.insmodopt  = &tda9855,
+		.addr_lo    = I2C_TDA985x_L >> 1,
+		.addr_hi    = I2C_TDA985x_H >> 1,
+		.registers  = 11,
+		.flags      = CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE,
+
+		.leftreg    = TDA9855_VL,
+		.rightreg   = TDA9855_VR,
+		.bassreg    = TDA9855_BA,
+		.treblereg  = TDA9855_TR,
+		.volfunc    = tda9855_volume,
+		.bassfunc   = tda9855_bass,
+		.treblefunc = tda9855_treble,
 
-		getmode:    tda985x_getmode,
-		setmode:    tda985x_setmode,
+		.getmode    = tda985x_getmode,
+		.setmode    = tda985x_setmode,
 
-		init:       { 12, { 0, 0x6f, 0x6f, 0x0e, 0x07<<1, 0x8<<2,
+		.init       = { 12, { 0, 0x6f, 0x6f, 0x0e, 0x07<<1, 0x8<<2,
 				    TDA9855_MUTE | TDA9855_AVL | TDA9855_LOUD | TDA9855_INT,
 				    TDA985x_STEREO | TDA9855_LINEAR | TDA9855_TZCM | TDA9855_VZCM,
 				    0x07, 0x10, 0x10, 0x03 }}
 	},
 	{
-		name:       "tea6300",
-		id:         I2C_DRIVERID_TEA6300,
-		insmodopt:  &tea6300,
-		addr_lo:    I2C_TEA6300 >> 1,
-		addr_hi:    I2C_TEA6300 >> 1,
-		registers:  6,
-		flags:      CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE | CHIP_HAS_INPUTSEL,
-
-		leftreg:    TEA6300_VR,
-		rightreg:   TEA6300_VL,
-		bassreg:    TEA6300_BA,
-		treblereg:  TEA6300_TR,
-		volfunc:    tea6300_shift10,
-		bassfunc:   tea6300_shift12,
-		treblefunc: tea6300_shift12,
-
-		inputreg:   TEA6300_S,
-		inputmap:   { TEA6300_S_SA, TEA6300_S_SB, TEA6300_S_SC },
-		inputmute:  TEA6300_S_GMU,
+		.name       = "tea6300",
+		.id         = I2C_DRIVERID_TEA6300,
+		.insmodopt  = &tea6300,
+		.addr_lo    = I2C_TEA6300 >> 1,
+		.addr_hi    = I2C_TEA6300 >> 1,
+		.registers  = 6,
+		.flags      = CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE | CHIP_HAS_INPUTSEL,
+
+		.leftreg    = TEA6300_VR,
+		.rightreg   = TEA6300_VL,
+		.bassreg    = TEA6300_BA,
+		.treblereg  = TEA6300_TR,
+		.volfunc    = tea6300_shift10,
+		.bassfunc   = tea6300_shift12,
+		.treblefunc = tea6300_shift12,
+
+		.inputreg   = TEA6300_S,
+		.inputmap   = { TEA6300_S_SA, TEA6300_S_SB, TEA6300_S_SC },
+		.inputmute  = TEA6300_S_GMU,
 	},
 	{
-		name:       "tea6420",
-		id:         I2C_DRIVERID_TEA6420,
-		insmodopt:  &tea6420,
-		addr_lo:    I2C_TEA6420 >> 1,
-		addr_hi:    I2C_TEA6420 >> 1,
-		registers:  1,
-		flags:      CHIP_HAS_INPUTSEL,
-
-		inputreg:   -1,
-		inputmap:   { TEA6420_S_SA, TEA6420_S_SB, TEA6420_S_SC },
-		inputmute:  TEA6300_S_GMU,
+		.name       = "tea6420",
+		.id         = I2C_DRIVERID_TEA6420,
+		.insmodopt  = &tea6420,
+		.addr_lo    = I2C_TEA6420 >> 1,
+		.addr_hi    = I2C_TEA6420 >> 1,
+		.registers  = 1,
+		.flags      = CHIP_HAS_INPUTSEL,
+
+		.inputreg   = -1,
+		.inputmap   = { TEA6420_S_SA, TEA6420_S_SB, TEA6420_S_SC },
+		.inputmute  = TEA6300_S_GMU,
 	},
 	{
-		name:       "tda8425",
-		id:         I2C_DRIVERID_TDA8425,
-		insmodopt:  &tda8425,
-		addr_lo:    I2C_TDA8425 >> 1,
-		addr_hi:    I2C_TDA8425 >> 1,
-		registers:  9,
-		flags:      CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE | CHIP_HAS_INPUTSEL,
-
-		leftreg:    TDA8425_VR,
-		rightreg:   TDA8425_VL,
-		bassreg:    TDA8425_BA,
-		treblereg:  TDA8425_TR,
-		volfunc:    tda8425_shift10,
-		bassfunc:   tda8425_shift12,
-		treblefunc: tda8425_shift12,
-
-		inputreg:   TDA8425_S1,
-		inputmap:   { TDA8425_S1_CH1, TDA8425_S1_CH1, TDA8425_S1_CH1 },
-		inputmute:  TDA8425_S1_OFF,
+		.name       = "tda8425",
+		.id         = I2C_DRIVERID_TDA8425,
+		.insmodopt  = &tda8425,
+		.addr_lo    = I2C_TDA8425 >> 1,
+		.addr_hi    = I2C_TDA8425 >> 1,
+		.registers  = 9,
+		.flags      = CHIP_HAS_VOLUME | CHIP_HAS_BASSTREBLE | CHIP_HAS_INPUTSEL,
+
+		.leftreg    = TDA8425_VL,
+		.rightreg   = TDA8425_VR,
+		.bassreg    = TDA8425_BA,
+		.treblereg  = TDA8425_TR,
+		.volfunc    = tda8425_shift10,
+		.bassfunc   = tda8425_shift12,
+		.treblefunc = tda8425_shift12,
+
+		.inputreg   = TDA8425_S1,
+		.inputmap   = { TDA8425_S1_CH1, TDA8425_S1_CH1, TDA8425_S1_CH1 },
+		.inputmute  = TDA8425_S1_OFF,
 
-		setmode:    tda8425_setmode,
+		.setmode    = tda8425_setmode,
+		.initialize = tda8425_initialize,
 	},
 	{
-		name:       "pic16c54 (PV951)",
-		id:         I2C_DRIVERID_PIC16C54_PV951,
-		insmodopt:  &pic16c54,
-		addr_lo:    I2C_PIC16C54 >> 1,
-		addr_hi:    I2C_PIC16C54>> 1,
-		registers:  2,
-		flags:      CHIP_HAS_INPUTSEL,
+		.name       = "pic16c54 (PV951)",
+		.id         = I2C_DRIVERID_PIC16C54_PV951,
+		.insmodopt  = &pic16c54,
+		.addr_lo    = I2C_PIC16C54 >> 1,
+		.addr_hi    = I2C_PIC16C54>> 1,
+		.registers  = 2,
+		.flags      = CHIP_HAS_INPUTSEL,
 
-		inputreg:   PIC16C54_REG_MISC,
-		inputmap:   {PIC16C54_MISC_SND_NOTMUTE|PIC16C54_MISC_SWITCH_TUNER,
+		.inputreg   = PIC16C54_REG_MISC,
+		.inputmap   = {PIC16C54_MISC_SND_NOTMUTE|PIC16C54_MISC_SWITCH_TUNER,
 			     PIC16C54_MISC_SND_NOTMUTE|PIC16C54_MISC_SWITCH_LINE,
 			     PIC16C54_MISC_SND_NOTMUTE|PIC16C54_MISC_SWITCH_LINE,
 			     PIC16C54_MISC_SND_MUTE,PIC16C54_MISC_SND_MUTE,
 			     PIC16C54_MISC_SND_NOTMUTE},
-		inputmute:  PIC16C54_MISC_SND_MUTE,
+		.inputmute  = PIC16C54_MISC_SND_MUTE,
 	},
 	{ name: NULL } /* EOF */
 };
@@ -1392,6 +1396,7 @@
 		/* start async thread */
 		DECLARE_MUTEX_LOCKED(sem);
 		chip->notify = &sem;
+		init_timer(&chip->wt);
 		chip->wt.function = chip_thread_wake;
 		chip->wt.data     = (unsigned long)chip;
 		init_waitqueue_head(&chip->wq);
@@ -1543,19 +1548,19 @@
 
 
 static struct i2c_driver driver = {
-        name:            "generic i2c audio driver",
-        id:              I2C_DRIVERID_TVAUDIO,
-        flags:           I2C_DF_NOTIFY,
-        attach_adapter:  chip_probe,
-        detach_client:   chip_detach,
-        command:         chip_command,
+        .name            = "generic i2c audio driver",
+        .id              = I2C_DRIVERID_TVAUDIO,
+        .flags           = I2C_DF_NOTIFY,
+        .attach_adapter  = chip_probe,
+        .detach_client   = chip_detach,
+        .command         = chip_command,
 };
 
 static struct i2c_client client_template =
 {
-        name:   "(unset)",
-	flags:  I2C_CLIENT_ALLOW_USE,
-        driver: &driver,
+        .name   = "(unset)",
+	.flags  = I2C_CLIENT_ALLOW_USE,
+        .driver = &driver,
 };
 
 static int audiochip_init_module(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/video/tvmixer.c linux-2.4.21-pre6/drivers/media/video/tvmixer.c
--- linux-2.4.20/drivers/media/video/tvmixer.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/media/video/tvmixer.c	2003-03-26 23:49:54.000000000 +0000
@@ -216,19 +216,19 @@
 }
 
 static struct i2c_driver driver = {
-	name:            "tv card mixer driver",
-        id:              I2C_DRIVERID_TVMIXER,
-	flags:           I2C_DF_DUMMY,
-        attach_adapter:  tvmixer_adapters,
-        detach_client:   tvmixer_clients,
+	.name            = "tv card mixer driver",
+        .id              = I2C_DRIVERID_TVMIXER,
+	.flags           = I2C_DF_DUMMY,
+        .attach_adapter  = tvmixer_adapters,
+        .detach_client   = tvmixer_clients,
 };
 
 static struct file_operations tvmixer_fops = {
-	owner:		THIS_MODULE,
-	llseek:         no_llseek,
-	ioctl:          tvmixer_ioctl,
-	open:           tvmixer_open,
-	release:        tvmixer_release,
+	.owner		= THIS_MODULE,
+	.llseek         = no_llseek,
+	.ioctl          = tvmixer_ioctl,
+	.open           = tvmixer_open,
+	.release        = tvmixer_release,
 };
 
 /* ----------------------------------------------------------------------- */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/video/videodev.c linux-2.4.21-pre6/drivers/media/video/videodev.c
--- linux-2.4.20/drivers/media/video/videodev.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/media/video/videodev.c	2003-03-26 23:49:07.000000000 +0000
@@ -186,14 +186,21 @@
 static int video_release(struct inode *inode, struct file *file)
 {
 	struct video_device *vfl;
+	struct module *owner;
 
-	down(&videodev_lock);
 	vfl = video_devdata(file);
-	if(vfl->close)
+	owner = vfl->owner;
+	if (vfl->close)
 		vfl->close(vfl);
-	vfl->users--;
-	if(vfl->owner)
-		__MOD_DEC_USE_COUNT(vfl->owner);
+
+	down(&videodev_lock);
+	/* ->close() might have called video_device_unregister()
+           in case of a hot unplug, thus we have to get vfl again */
+	vfl = video_devdata(file);
+	if (NULL != vfl)
+		vfl->users--;
+	if (owner)
+		__MOD_DEC_USE_COUNT(owner);
 	up(&videodev_lock);
 	return 0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/media/video/w9966.c linux-2.4.21-pre6/drivers/media/video/w9966.c
--- linux-2.4.20/drivers/media/video/w9966.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/media/video/w9966.c	2003-03-26 23:49:19.000000000 +0000
@@ -931,7 +931,7 @@
 		if(copy_from_user(&vtune, arg, sizeof(vtune)) != 0)
 			return -EFAULT;
 
-		if(vtune.tuner != 0);
+		if(vtune.tuner != 0)
 			return -EINVAL;
 
 		strcpy(vtune.name, "no tuner");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/message/fusion/Config.in linux-2.4.21-pre6/drivers/message/fusion/Config.in
--- linux-2.4.20/drivers/message/fusion/Config.in	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/message/fusion/Config.in	2003-03-26 23:49:23.000000000 +0000
@@ -10,6 +10,7 @@
   else
     define_bool CONFIG_FUSION_BOOT n
   fi
+  int  "  Maximum number of scatter gather entries" CONFIG_FUSION_MAX_SGE 40 
 
   if [ "$CONFIG_MODULES" = "y" ]; then
     #  How can we force these options to module or nothing?
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/message/fusion/linux_compat.h linux-2.4.21-pre6/drivers/message/fusion/linux_compat.h
--- linux-2.4.20/drivers/message/fusion/linux_compat.h	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/message/fusion/linux_compat.h	2003-03-26 23:49:25.000000000 +0000
@@ -252,6 +252,37 @@
         #define MPT_SCSI_USE_NEW_EH
 #endif
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,28)
+#define mptscsih_lock(iocp, flags) \
+                spin_lock_irqsave(&iocp->FreeQlock, flags)
+#else
+#define mptscsih_lock(iocp, flags) \
+({	save_flags(flags); \
+	cli(); \
+})
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,28)
+#define mptscsih_unlock(iocp, flags) \
+                spin_unlock_irqrestore(&iocp->FreeQlock, flags)
+#else
+#define mptscsih_unlock(iocp, flags)  restore_flags(flags);
+#endif
+
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,41)
+#define mpt_work_struct work_struct 
+#define MPT_INIT_WORK(_task, _func, _data) INIT_WORK(_task, _func, _data)
+#else
+#define mpt_work_struct tq_struct 
+#define MPT_INIT_WORK(_task, _func, _data) \
+({	(_task)->sync = 0; \
+	(_task)->routine = (_func); \
+	(_task)->data = (void *) (_data); \
+})
+#endif
+
+
 /*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 #endif /* _LINUX_COMPAT_H */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/message/fusion/lsi/mpi.h linux-2.4.21-pre6/drivers/message/fusion/lsi/mpi.h
--- linux-2.4.20/drivers/message/fusion/lsi/mpi.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/message/fusion/lsi/mpi.h	2003-03-26 23:49:07.000000000 +0000
@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2000-2001 LSI Logic Corporation.
+ *  Copyright (c) 2000-2002 LSI Logic Corporation.
  *
  *
  *           Name:  MPI.H
  *          Title:  MPI Message independent structures and definitions
  *  Creation Date:  July 27, 2000
  *
- *    MPI Version:  01.02.03
+ *    MPI.H Version:  01.02.07
  *
  *  Version History
  *  ---------------
@@ -44,6 +44,10 @@
  *                      Added define MPI_FUNCTION_TOOLBOX.
  *  09-28-01  01.02.02  New function code MPI_SCSI_ENCLOSURE_PROCESSOR.
  *  11-01-01  01.02.03  Changed name to MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR.
+ *  03-14-02  01.02.04  Added MPI_HEADER_VERSION_ defines.
+ *  05-31-02  01.02.05  Bumped MPI_HEADER_VERSION_UNIT.
+ *  07-12-02  01.02.06  Added define for MPI_FUNCTION_MAILBOX.
+ *  09-16-02  01.02.07  Bumped value for MPI_HEADER_VERSION_UNIT.
  *  --------------------------------------------------------------------------
  */
 
@@ -59,10 +63,27 @@
 
 #define MPI_VERSION_MAJOR                   (0x01)
 #define MPI_VERSION_MINOR                   (0x02)
-#define MPI_VERSION            ((MPI_VERSION_MAJOR << 8) | MPI_VERSION_MINOR)
-
+#define MPI_VERSION_MAJOR_MASK              (0xFF00)
+#define MPI_VERSION_MAJOR_SHIFT             (8)
+#define MPI_VERSION_MINOR_MASK              (0x00FF)
+#define MPI_VERSION_MINOR_SHIFT             (0)
+#define MPI_VERSION ((MPI_VERSION_MAJOR << MPI_VERSION_MAJOR_SHIFT) |   \
+                                      MPI_VERSION_MINOR)
+
+#define MPI_VERSION_01_00                   (0x0100)
+#define MPI_VERSION_01_01                   (0x0101)
+#define MPI_VERSION_01_02                   (0x0102)
 /* Note: The major versions of 0xe0 through 0xff are reserved */
 
+/* versioning for this MPI header set */
+#define MPI_HEADER_VERSION_UNIT             (0x09)
+#define MPI_HEADER_VERSION_DEV              (0x00)
+#define MPI_HEADER_VERSION_UNIT_MASK        (0xFF00)
+#define MPI_HEADER_VERSION_UNIT_SHIFT       (8)
+#define MPI_HEADER_VERSION_DEV_MASK         (0x00FF)
+#define MPI_HEADER_VERSION_DEV_SHIFT        (0)
+#define MPI_HEADER_VERSION ((MPI_HEADER_VERSION_UNIT << 8) | MPI_HEADER_VERSION_DEV)
+
 /*****************************************************************************
 *
 *        I O C    S t a t e    D e f i n i t i o n s
@@ -228,6 +249,8 @@
 
 #define MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR       (0x18)
 
+#define MPI_FUNCTION_MAILBOX                        (0x19)
+
 #define MPI_FUNCTION_LAN_SEND                       (0x20)
 #define MPI_FUNCTION_LAN_RECEIVE                    (0x21)
 #define MPI_FUNCTION_LAN_RESET                      (0x22)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/message/fusion/lsi/mpi_cnfg.h linux-2.4.21-pre6/drivers/message/fusion/lsi/mpi_cnfg.h
--- linux-2.4.20/drivers/message/fusion/lsi/mpi_cnfg.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/message/fusion/lsi/mpi_cnfg.h	2003-03-26 23:49:40.000000000 +0000
@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2000-2001 LSI Logic Corporation.
+ *  Copyright (c) 2000-2002 LSI Logic Corporation.
  *
  *
  *           Name:  MPI_CNFG.H
  *          Title:  MPI Config message, structures, and Pages
  *  Creation Date:  July 27, 2000
  *
- *    MPI Version:  01.02.05
+ *    MPI_CNFG.H Version:  01.02.09
  *
  *  Version History
  *  ---------------
@@ -108,6 +108,26 @@
  *                      Added generic defines for hot spare pools and RAID
  *                      volume types.
  *  11-01-01 01.02.05   Added define for MPI_IOUNITPAGE1_DISABLE_IR.
+ *  03-14-02 01.02.06   Added PCISlotNum field to CONFIG_PAGE_IOC_1 along with
+ *                      related define, and bumped the page version define.
+ *  05-31-02 01.02.07   Added a Flags field to CONFIG_PAGE_IOC_2_RAID_VOL in a
+ *                      reserved byte and added a define.
+ *                      Added define for
+ *                      MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE.
+ *                      Added new config page: CONFIG_PAGE_IOC_5.
+ *                      Added MaxAliases, MaxHardAliases, and NumCurrentAliases
+ *                      fields to CONFIG_PAGE_FC_PORT_0.
+ *                      Added AltConnector and NumRequestedAliases fields to
+ *                      CONFIG_PAGE_FC_PORT_1.
+ *                      Added new config page: CONFIG_PAGE_FC_PORT_10.
+ *  07-12-02 01.02.08   Added more MPI_MANUFACTPAGE_DEVID_ defines.
+ *                      Added additional MPI_SCSIDEVPAGE0_NP_ defines.
+ *                      Added more MPI_SCSIDEVPAGE1_RP_ defines.
+ *                      Added define for
+ *                      MPI_SCSIDEVPAGE1_CONF_EXTENDED_PARAMS_ENABLE.
+ *                      Added new config page: CONFIG_PAGE_SCSI_DEVICE_3.
+ *                      Modified MPI_FCPORTPAGE5_FLAGS_ defines.
+ *  09-16-02 01.02.09   Added more MPI_SCSIDEVPAGE1_CONF_FORCE_PPR_MSG define.
  *  --------------------------------------------------------------------------
  */
 
@@ -266,6 +286,7 @@
 #define MPI_MANUFACTPAGE_DEVICEID_FC929             (0x0622)
 #define MPI_MANUFACTPAGE_DEVICEID_FC919X            (0x0628)
 #define MPI_MANUFACTPAGE_DEVICEID_FC929X            (0x0626)
+
 #define MPI_MANUFACTPAGE_DEVID_53C1030              (0x0030)
 #define MPI_MANUFACTPAGE_DEVID_53C1030ZC            (0x0031)
 #define MPI_MANUFACTPAGE_DEVID_1030_53C1035         (0x0032)
@@ -273,6 +294,12 @@
 #define MPI_MANUFACTPAGE_DEVID_53C1035              (0x0040)
 #define MPI_MANUFACTPAGE_DEVID_53C1035ZC            (0x0041)
 
+#define MPI_MANUFACTPAGE_DEVID_SA2010               (0x0804)
+#define MPI_MANUFACTPAGE_DEVID_SA2010ZC             (0x0805)
+#define MPI_MANUFACTPAGE_DEVID_SA2020               (0x0806)
+#define MPI_MANUFACTPAGE_DEVID_SA2020ZC             (0x0807)
+
+
 typedef struct _CONFIG_PAGE_MANUFACTURING_0
 {
     fCONFIG_PAGE_HEADER      Header;                     /* 00h */
@@ -481,14 +508,17 @@
     U32                     Flags;                      /* 04h */
     U32                     CoalescingTimeout;          /* 08h */
     U8                      CoalescingDepth;            /* 0Ch */
-    U8                      Reserved[3];                /* 0Dh */
+    U8                      PCISlotNum;                 /* 0Dh */
+    U8                      Reserved[2];                /* 0Eh */
 } 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_PAGEVERSION                        (0x01)
 
 #define MPI_IOCPAGE1_REPLY_COALESCING                   (0x00000001)
 
+#define MPI_IOCPAGE1_PCISLOTNUM_UNKNOWN                 (0xFF)
+
 
 typedef struct _CONFIG_PAGE_IOC_2_RAID_VOL
 {
@@ -497,11 +527,21 @@
     U8                          VolumeIOC;              /* 02h */
     U8                          VolumePageNumber;       /* 03h */
     U8                          VolumeType;             /* 04h */
-    U8                          Reserved2;              /* 05h */
+    U8                          Flags;                  /* 05h */
     U16                         Reserved3;              /* 06h */
 } fCONFIG_PAGE_IOC_2_RAID_VOL, MPI_POINTER PTR_CONFIG_PAGE_IOC_2_RAID_VOL,
   ConfigPageIoc2RaidVol_t, MPI_POINTER pConfigPageIoc2RaidVol_t;
 
+/* IOC Page 2 Volume RAID Type values, also used in RAID Volume pages */
+
+#define MPI_RAID_VOL_TYPE_IS                        (0x00)
+#define MPI_RAID_VOL_TYPE_IME                       (0x01)
+#define MPI_RAID_VOL_TYPE_IM                        (0x02)
+
+/* IOC Page 2 Volume Flags values */
+
+#define MPI_IOCPAGE2_FLAG_VOLUME_INACTIVE           (0x08)
+
 /*
  * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
  * one and check Header.PageLength at runtime.
@@ -522,7 +562,7 @@
 } fCONFIG_PAGE_IOC_2, MPI_POINTER PTR_CONFIG_PAGE_IOC_2,
   IOCPage2_t, MPI_POINTER pIOCPage2_t;
 
-#define MPI_IOCPAGE2_PAGEVERSION                        (0x01)
+#define MPI_IOCPAGE2_PAGEVERSION                        (0x02)
 
 /* IOC Page 2 Capabilities flags */
 
@@ -533,12 +573,6 @@
 #define MPI_IOCPAGE2_CAP_FLAGS_SAFTE_SUPPORT            (0x40000000)
 #define MPI_IOCPAGE2_CAP_FLAGS_CROSS_CHANNEL_SUPPORT    (0x80000000)
 
-/* IOC Page 2 Volume RAID Type values, also used in RAID Volume pages */
-
-#define MPI_RAID_VOL_TYPE_IS                        (0x00)
-#define MPI_RAID_VOL_TYPE_IME                       (0x01)
-#define MPI_RAID_VOL_TYPE_IM                        (0x02)
-
 
 typedef struct _IOC_3_PHYS_DISK
 {
@@ -599,6 +633,41 @@
 #define MPI_IOCPAGE4_PAGEVERSION                        (0x00)
 
 
+typedef struct _IOC_5_HOT_SPARE
+{
+    U8                          PhysDiskNum;            /* 00h */
+    U8                          Reserved;               /* 01h */
+    U8                          HotSparePool;           /* 02h */
+    U8                          Flags;                   /* 03h */
+} IOC_5_HOT_SPARE, MPI_POINTER PTR_IOC_5_HOT_SPARE,
+  Ioc5HotSpare_t, MPI_POINTER pIoc5HotSpare_t;
+
+/* IOC Page 5 HotSpare Flags */
+#define MPI_IOC_PAGE_5_HOT_SPARE_ACTIVE                 (0x01)
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength at runtime.
+ */
+#ifndef MPI_IOC_PAGE_5_HOT_SPARE_MAX
+#define MPI_IOC_PAGE_5_HOT_SPARE_MAX        (1)
+#endif
+
+typedef struct _CONFIG_PAGE_IOC_5
+{
+    fCONFIG_PAGE_HEADER         Header;                         /* 00h */
+    U32                         Reserved1;                      /* 04h */
+    U8                          NumHotSpares;                   /* 08h */
+    U8                          Reserved2;                      /* 09h */
+    U16                         Reserved3;                      /* 0Ah */
+    IOC_5_HOT_SPARE             HotSpare[MPI_IOC_PAGE_5_HOT_SPARE_MAX]; /* 0Ch */
+} fCONFIG_PAGE_IOC_5, MPI_POINTER PTR_CONFIG_PAGE_IOC_5,
+  IOCPage5_t, MPI_POINTER pIOCPage5_t;
+
+#define MPI_IOCPAGE5_PAGEVERSION                        (0x00)
+
+
+
 /****************************************************************************
 *   SCSI Port Config Pages
 ****************************************************************************/
@@ -698,11 +767,16 @@
 } fCONFIG_PAGE_SCSI_DEVICE_0, MPI_POINTER PTR_CONFIG_PAGE_SCSI_DEVICE_0,
   SCSIDevicePage0_t, MPI_POINTER pSCSIDevicePage0_t;
 
-#define MPI_SCSIDEVPAGE0_PAGEVERSION                    (0x02)
+#define MPI_SCSIDEVPAGE0_PAGEVERSION                    (0x03)
 
 #define MPI_SCSIDEVPAGE0_NP_IU                          (0x00000001)
 #define MPI_SCSIDEVPAGE0_NP_DT                          (0x00000002)
 #define MPI_SCSIDEVPAGE0_NP_QAS                         (0x00000004)
+#define MPI_SCSIDEVPAGE0_NP_HOLD_MCS                    (0x00000008)
+#define MPI_SCSIDEVPAGE0_NP_WR_FLOW                     (0x00000010)
+#define MPI_SCSIDEVPAGE0_NP_RD_STRM                     (0x00000020)
+#define MPI_SCSIDEVPAGE0_NP_RTI                         (0x00000040)
+#define MPI_SCSIDEVPAGE0_NP_PCOMP_EN                    (0x00000080)
 #define MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK        (0x0000FF00)
 #define MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK        (0x00FF0000)
 #define MPI_SCSIDEVPAGE0_NP_WIDE                        (0x20000000)
@@ -723,21 +797,25 @@
 } fCONFIG_PAGE_SCSI_DEVICE_1, MPI_POINTER PTR_CONFIG_PAGE_SCSI_DEVICE_1,
   SCSIDevicePage1_t, MPI_POINTER pSCSIDevicePage1_t;
 
-#define MPI_SCSIDEVPAGE1_PAGEVERSION                    (0x03)
+#define MPI_SCSIDEVPAGE1_PAGEVERSION                    (0x04)
 
 #define MPI_SCSIDEVPAGE1_RP_IU                          (0x00000001)
 #define MPI_SCSIDEVPAGE1_RP_DT                          (0x00000002)
 #define MPI_SCSIDEVPAGE1_RP_QAS                         (0x00000004)
+#define MPI_SCSIDEVPAGE1_RP_HOLD_MCS                    (0x00000008)
+#define MPI_SCSIDEVPAGE1_RP_WR_FLOW                     (0x00000010)
+#define MPI_SCSIDEVPAGE1_RP_RD_STRM                     (0x00000020)
+#define MPI_SCSIDEVPAGE1_RP_RTI                         (0x00000040)
+#define MPI_SCSIDEVPAGE1_RP_PCOMP_EN                    (0x00000080)
 #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_WDTR_DISALLOWED           (0x00000002)
 #define MPI_SCSIDEVPAGE1_CONF_SDTR_DISALLOWED           (0x00000004)
+#define MPI_SCSIDEVPAGE1_CONF_EXTENDED_PARAMS_ENABLE    (0x00000008)
+#define MPI_SCSIDEVPAGE1_CONF_FORCE_PPR_MSG             (0x00000010)
 
 
 typedef struct _CONFIG_PAGE_SCSI_DEVICE_2
@@ -749,7 +827,7 @@
 } fCONFIG_PAGE_SCSI_DEVICE_2, MPI_POINTER PTR_CONFIG_PAGE_SCSI_DEVICE_2,
   SCSIDevicePage2_t, MPI_POINTER pSCSIDevicePage2_t;
 
-#define MPI_SCSIDEVPAGE2_PAGEVERSION                    (0x00)
+#define MPI_SCSIDEVPAGE2_PAGEVERSION                    (0x01)
 
 #define MPI_SCSIDEVPAGE2_DV_ISI_ENABLE                  (0x00000010)
 #define MPI_SCSIDEVPAGE2_DV_SECONDARY_DRIVER_ENABLE     (0x00000020)
@@ -781,6 +859,22 @@
 #define MPI_SCSIDEVPAGE2_DPS_BIT_15_PL_SELECT_MASK      (0xC0000000)
 
 
+typedef struct _CONFIG_PAGE_SCSI_DEVICE_3
+{
+    fCONFIG_PAGE_HEADER      Header;                     /* 00h */
+    U16                     MsgRejectCount;             /* 04h */
+    U16                     PhaseErrorCount;            /* 06h */
+    U16                     ParityErrorCount;           /* 08h */
+    U16                     Reserved;                   /* 0Ah */
+} fCONFIG_PAGE_SCSI_DEVICE_3, MPI_POINTER PTR_CONFIG_PAGE_SCSI_DEVICE_3,
+  SCSIDevicePage3_t, MPI_POINTER pSCSIDevicePage3_t;
+
+#define MPI_SCSIDEVPAGE3_PAGEVERSION                    (0x00)
+
+#define MPI_SCSIDEVPAGE3_MAX_COUNTER                    (0xFFFE)
+#define MPI_SCSIDEVPAGE3_UNSUPPORTED_COUNTER            (0xFFFF)
+
+
 /****************************************************************************
 *   FC Port Config Pages
 ****************************************************************************/
@@ -804,10 +898,14 @@
     U64                     FabricWWPN;                 /* 38h */
     U32                     DiscoveredPortsCount;       /* 40h */
     U32                     MaxInitiators;              /* 44h */
+    U8                      MaxAliasesSupported;        /* 48h */
+    U8                      MaxHardAliasesSupported;    /* 49h */
+    U8                      NumCurrentAliases;          /* 4Ah */
+    U8                      Reserved1;                  /* 4Bh */
 } 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_PAGEVERSION                     (0x02)
 
 #define MPI_FCPORTPAGE0_FLAGS_PROT_MASK                 (0x0000000F)
 #define MPI_FCPORTPAGE0_FLAGS_PROT_FCP_INIT             (MPI_PORTFACTS_PROTOCOL_INITIATOR)
@@ -874,11 +972,14 @@
     U8                      HardALPA;                   /* 18h */
     U8                      LinkConfig;                 /* 19h */
     U8                      TopologyConfig;             /* 1Ah */
-    U8                      Reserved;                   /* 1Bh */
+    U8                      AltConnector;               /* 1Bh */
+    U8                      NumRequestedAliases;        /* 1Ch */
+    U8                      Reserved1;                  /* 1Dh */
+    U16                     Reserved2;                  /* 1Eh */
 } fCONFIG_PAGE_FC_PORT_1, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_1,
   FCPortPage1_t, MPI_POINTER pFCPortPage1_t;
 
-#define MPI_FCPORTPAGE1_PAGEVERSION                     (0x02)
+#define MPI_FCPORTPAGE1_PAGEVERSION                     (0x04)
 
 #define MPI_FCPORTPAGE1_FLAGS_EXT_FCP_STATUS_EN         (0x08000000)
 #define MPI_FCPORTPAGE1_FLAGS_IMMEDIATE_ERROR_REPLY     (0x04000000)
@@ -906,6 +1007,8 @@
 #define MPI_FCPORTPAGE1_TOPOLOGY_NPORT                  (0x02)
 #define MPI_FCPORTPAGE1_TOPOLOGY_AUTO                   (0x0F)
 
+#define MPI_FCPORTPAGE1_ALT_CONN_UNKNOWN                (0x00)
+
 
 typedef struct _CONFIG_PAGE_FC_PORT_2
 {
@@ -998,26 +1101,19 @@
   MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_5_ALIAS_INFO,
   FcPortPage5AliasInfo_t, MPI_POINTER pFcPortPage5AliasInfo_t;
 
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.PageLength at runtime.
- */
-#ifndef MPI_FC_PORT_PAGE_5_ALIAS_MAX
-#define MPI_FC_PORT_PAGE_5_ALIAS_MAX        (1)
-#endif
-
 typedef struct _CONFIG_PAGE_FC_PORT_5
 {
-    fCONFIG_PAGE_HEADER                  Header;                     /* 00h */
-    fCONFIG_PAGE_FC_PORT_5_ALIAS_INFO    AliasInfo[MPI_FC_PORT_PAGE_5_ALIAS_MAX];/* 04h */
+    fCONFIG_PAGE_HEADER                  Header;         /* 00h */
+    fCONFIG_PAGE_FC_PORT_5_ALIAS_INFO    AliasInfo;      /* 04h */
 } 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)
+#define MPI_FCPORTPAGE5_PAGEVERSION                     (0x01)
 
+#define MPI_FCPORTPAGE5_FLAGS_ALPA_ACQUIRED             (0x01)
+#define MPI_FCPORTPAGE5_FLAGS_HARD_ALPA                 (0x02)
+#define MPI_FCPORTPAGE5_FLAGS_HARD_WWNN                 (0x04)
+#define MPI_FCPORTPAGE5_FLAGS_HARD_WWPN                 (0x08)
 
 typedef struct _CONFIG_PAGE_FC_PORT_6
 {
@@ -1086,6 +1182,132 @@
 #define MPI_FCPORTPAGE9_PAGEVERSION                     (0x00)
 
 
+typedef struct _CONFIG_PAGE_FC_PORT_10_BASE_SFP_DATA
+{
+    U8                      Id;                         /* 10h */
+    U8                      ExtId;                      /* 11h */
+    U8                      Connector;                  /* 12h */
+    U8                      Transceiver[8];             /* 13h */
+    U8                      Encoding;                   /* 1Bh */
+    U8                      BitRate_100mbs;             /* 1Ch */
+    U8                      Reserved1;                  /* 1Dh */
+    U8                      Length9u_km;                /* 1Eh */
+    U8                      Length9u_100m;              /* 1Fh */
+    U8                      Length50u_10m;              /* 20h */
+    U8                      Length62p5u_10m;            /* 21h */
+    U8                      LengthCopper_m;             /* 22h */
+    U8                      Reseverved2;                /* 22h */
+    U8                      VendorName[16];             /* 24h */
+    U8                      Reserved3;                  /* 34h */
+    U8                      VendorOUI[3];               /* 35h */
+    U8                      VendorPN[16];               /* 38h */
+    U8                      VendorRev[4];               /* 48h */
+    U16                     Reserved4;                  /* 4Ch */
+    U8                      Reserved5;                  /* 4Eh */
+    U8                      CC_BASE;                    /* 4Fh */
+} fCONFIG_PAGE_FC_PORT_10_BASE_SFP_DATA,
+  MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_10_BASE_SFP_DATA,
+  FCPortPage10BaseSfpData_t, MPI_POINTER pFCPortPage10BaseSfpData_t;
+
+#define MPI_FCPORT10_BASE_ID_UNKNOWN        (0x00)
+#define MPI_FCPORT10_BASE_ID_GBIC           (0x01)
+#define MPI_FCPORT10_BASE_ID_FIXED          (0x02)
+#define MPI_FCPORT10_BASE_ID_SFP            (0x03)
+#define MPI_FCPORT10_BASE_ID_SFP_MIN        (0x04)
+#define MPI_FCPORT10_BASE_ID_SFP_MAX        (0x7F)
+#define MPI_FCPORT10_BASE_ID_VEND_SPEC_MASK (0x80)
+
+#define MPI_FCPORT10_BASE_EXTID_UNKNOWN     (0x00)
+#define MPI_FCPORT10_BASE_EXTID_MODDEF1     (0x01)
+#define MPI_FCPORT10_BASE_EXTID_MODDEF2     (0x02)
+#define MPI_FCPORT10_BASE_EXTID_MODDEF3     (0x03)
+#define MPI_FCPORT10_BASE_EXTID_SEEPROM     (0x04)
+#define MPI_FCPORT10_BASE_EXTID_MODDEF5     (0x05)
+#define MPI_FCPORT10_BASE_EXTID_MODDEF6     (0x06)
+#define MPI_FCPORT10_BASE_EXTID_MODDEF7     (0x07)
+#define MPI_FCPORT10_BASE_EXTID_VNDSPC_MASK (0x80)
+
+#define MPI_FCPORT10_BASE_CONN_UNKNOWN      (0x00)
+#define MPI_FCPORT10_BASE_CONN_SC           (0x01)
+#define MPI_FCPORT10_BASE_CONN_COPPER1      (0x02)
+#define MPI_FCPORT10_BASE_CONN_COPPER2      (0x03)
+#define MPI_FCPORT10_BASE_CONN_BNC_TNC      (0x04)
+#define MPI_FCPORT10_BASE_CONN_COAXIAL      (0x05)
+#define MPI_FCPORT10_BASE_CONN_FIBERJACK    (0x06)
+#define MPI_FCPORT10_BASE_CONN_LC           (0x07)
+#define MPI_FCPORT10_BASE_CONN_MT_RJ        (0x08)
+#define MPI_FCPORT10_BASE_CONN_MU           (0x09)
+#define MPI_FCPORT10_BASE_CONN_SG           (0x0A)
+#define MPI_FCPORT10_BASE_CONN_OPT_PIGT     (0x0B)
+#define MPI_FCPORT10_BASE_CONN_RSV1_MIN     (0x0C)
+#define MPI_FCPORT10_BASE_CONN_RSV1_MAX     (0x1F)
+#define MPI_FCPORT10_BASE_CONN_HSSDC_II     (0x20)
+#define MPI_FCPORT10_BASE_CONN_CPR_PIGT     (0x21)
+#define MPI_FCPORT10_BASE_CONN_RSV2_MIN     (0x22)
+#define MPI_FCPORT10_BASE_CONN_RSV2_MAX     (0x7F)
+#define MPI_FCPORT10_BASE_CONN_VNDSPC_MASK  (0x80)
+
+#define MPI_FCPORT10_BASE_ENCODE_UNSPEC     (0x00)
+#define MPI_FCPORT10_BASE_ENCODE_8B10B      (0x01)
+#define MPI_FCPORT10_BASE_ENCODE_4B5B       (0x02)
+#define MPI_FCPORT10_BASE_ENCODE_NRZ        (0x03)
+#define MPI_FCPORT10_BASE_ENCODE_MANCHESTER (0x04)
+
+
+typedef struct _CONFIG_PAGE_FC_PORT_10_EXTENDED_SFP_DATA
+{
+    U8                      Options[2];                 /* 50h */
+    U8                      BitRateMax;                 /* 52h */
+    U8                      BitRateMin;                 /* 53h */
+    U8                      VendorSN[16];               /* 54h */
+    U8                      DateCode[8];                /* 64h */
+    U8                      Reserved5[3];               /* 6Ch */
+    U8                      CC_EXT;                     /* 6Fh */
+} fCONFIG_PAGE_FC_PORT_10_EXTENDED_SFP_DATA,
+  MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_10_EXTENDED_SFP_DATA,
+  FCPortPage10ExtendedSfpData_t, MPI_POINTER pFCPortPage10ExtendedSfpData_t;
+
+#define MPI_FCPORT10_EXT_OPTION1_RATESEL    (0x20)
+#define MPI_FCPORT10_EXT_OPTION1_TX_DISABLE (0x10)
+#define MPI_FCPORT10_EXT_OPTION1_TX_FAULT   (0x08)
+#define MPI_FCPORT10_EXT_OPTION1_LOS_INVERT (0x04)
+#define MPI_FCPORT10_EXT_OPTION1_LOS        (0x02)
+
+
+typedef struct _CONFIG_PAGE_FC_PORT_10
+{
+    fCONFIG_PAGE_HEADER                          Header;             /* 00h */
+    U8                                          Flags;              /* 04h */
+    U8                                          Reserved1;          /* 05h */
+    U16                                         Reserved2;          /* 06h */
+    U32                                         HwConfig1;          /* 08h */
+    U32                                         HwConfig2;          /* 0Ch */
+    fCONFIG_PAGE_FC_PORT_10_BASE_SFP_DATA        Base;               /* 10h */
+    fCONFIG_PAGE_FC_PORT_10_EXTENDED_SFP_DATA    Extended;           /* 50h */
+    U8                                          VendorSpecific[32]; /* 70h */
+} fCONFIG_PAGE_FC_PORT_10, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_10,
+  FCPortPage10_t, MPI_POINTER pFCPortPage10_t;
+
+#define MPI_FCPORTPAGE10_PAGEVERSION                    (0x00)
+
+/* standard MODDEF pin definitions (from GBIC spec.) */
+#define MPI_FCPORTPAGE10_FLAGS_MODDEF_MASK              (0x00000007)
+#define MPI_FCPORTPAGE10_FLAGS_MODDEF2                  (0x00000001)
+#define MPI_FCPORTPAGE10_FLAGS_MODDEF1                  (0x00000002)
+#define MPI_FCPORTPAGE10_FLAGS_MODDEF0                  (0x00000004)
+#define MPI_FCPORTPAGE10_FLAGS_MODDEF_NOGBIC            (0x00000007)
+#define MPI_FCPORTPAGE10_FLAGS_MODDEF_CPR_IEEE_CX       (0x00000006)
+#define MPI_FCPORTPAGE10_FLAGS_MODDEF_COPPER            (0x00000005)
+#define MPI_FCPORTPAGE10_FLAGS_MODDEF_OPTICAL_LW        (0x00000004)
+#define MPI_FCPORTPAGE10_FLAGS_MODDEF_SEEPROM           (0x00000003)
+#define MPI_FCPORTPAGE10_FLAGS_MODDEF_SW_OPTICAL        (0x00000002)
+#define MPI_FCPORTPAGE10_FLAGS_MODDEF_LX_IEEE_OPT_LW    (0x00000001)
+#define MPI_FCPORTPAGE10_FLAGS_MODDEF_SX_IEEE_OPT_SW    (0x00000000)
+
+#define MPI_FCPORTPAGE10_FLAGS_CC_BASE_OK               (0x00000010)
+#define MPI_FCPORTPAGE10_FLAGS_CC_EXT_OK                (0x00000020)
+
+
 /****************************************************************************
 *   FC Device Config Pages
 ****************************************************************************/
@@ -1155,6 +1377,7 @@
 #define MPI_RAIDVOL0_STATUS_FLAG_ENABLED                (0x01)
 #define MPI_RAIDVOL0_STATUS_FLAG_QUIESCED               (0x02)
 #define MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS     (0x04)
+#define MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE        (0x08)
 
 #define MPI_RAIDVOL0_STATUS_STATE_OPTIMAL               (0x00)
 #define MPI_RAIDVOL0_STATUS_STATE_DEGRADED              (0x01)
@@ -1216,7 +1439,7 @@
 } fCONFIG_PAGE_RAID_VOL_0, MPI_POINTER PTR_CONFIG_PAGE_RAID_VOL_0,
   RaidVolumePage0_t, MPI_POINTER pRaidVolumePage0_t;
 
-#define MPI_RAIDVOLPAGE0_PAGEVERSION                    (0x00)
+#define MPI_RAIDVOLPAGE0_PAGEVERSION                    (0x01)
 
 
 /****************************************************************************
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/message/fusion/lsi/mpi_fc.h linux-2.4.21-pre6/drivers/message/fusion/lsi/mpi_fc.h
--- linux-2.4.20/drivers/message/fusion/lsi/mpi_fc.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/message/fusion/lsi/mpi_fc.h	2003-03-26 23:49:08.000000000 +0000
@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2000-2001 LSI Logic Corporation.
+ *  Copyright (c) 2000-2002 LSI Logic Corporation.
  *
  *
  *           Name:  MPI_FC.H
  *          Title:  MPI Fibre Channel messages and structures
  *  Creation Date:  June 12, 2000
  *
- *    MPI Version:  01.02.02
+ *    MPI_FC.H Version:  01.02.03
  *
  *  Version History
  *  ---------------
@@ -35,6 +35,7 @@
  *  08-08-01  01.02.01  Original release for v1.2 work.
  *  09-28-01  01.02.02  Change name of reserved field in
  *                      MSG_LINK_SERVICE_RSP_REPLY.
+ *  05-31-02  01.02.03  Adding AliasIndex to FC Direct Access requests.
  *  --------------------------------------------------------------------------
  */
 
@@ -193,7 +194,7 @@
 typedef struct _MSG_EXLINK_SERVICE_SEND_REQUEST
 {
     U8                      SendFlags;          /* 00h */
-    U8                      Reserved;           /* 01h */
+    U8                      AliasIndex;         /* 01h */
     U8                      ChainOffset;        /* 02h */
     U8                      Function;           /* 03h */
     U32                     MsgFlags_Did;       /* 04h */
@@ -212,7 +213,8 @@
 /* Extended Link Service Send Reply */
 typedef struct _MSG_EXLINK_SERVICE_SEND_REPLY
 {
-    U16                     Reserved;           /* 00h */
+    U8                      Reserved;           /* 00h */
+    U8                      AliasIndex;         /* 01h */
     U8                      MsgLength;          /* 02h */
     U8                      Function;           /* 03h */
     U16                     Reserved1;          /* 04h */
@@ -275,7 +277,7 @@
 typedef struct _MSG_FC_COMMON_TRANSPORT_SEND_REQUEST
 {
     U8                      SendFlags;          /* 00h */
-    U8                      Reserved;           /* 01h */
+    U8                      AliasIndex;         /* 01h */
     U8                      ChainOffset;        /* 02h */
     U8                      Function;           /* 03h */
     U32                     MsgFlags_Did;       /* 04h */
@@ -297,7 +299,8 @@
 /* FC Common Transport Send Reply */
 typedef struct _MSG_FC_COMMON_TRANSPORT_SEND_REPLY
 {
-    U16                     Reserved;           /* 00h */
+    U8                      Reserved;           /* 00h */
+    U8                      AliasIndex;         /* 01h */
     U8                      MsgLength;          /* 02h */
     U8                      Function;           /* 03h */
     U16                     Reserved1;          /* 04h */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/message/fusion/lsi/mpi_init.h linux-2.4.21-pre6/drivers/message/fusion/lsi/mpi_init.h
--- linux-2.4.20/drivers/message/fusion/lsi/mpi_init.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/message/fusion/lsi/mpi_init.h	2003-03-26 23:49:00.000000000 +0000
@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2000-2001 LSI Logic Corporation.
+ *  Copyright (c) 2000-2002 LSI Logic Corporation.
  *
  *
  *           Name:  MPI_INIT.H
  *          Title:  MPI initiator mode messages and structures
  *  Creation Date:  June 8, 2000
  *
- *    MPI Version:  01.02.04
+ *    MPI_INIT.H Version:  01.02.05
  *
  *  Version History
  *  ---------------
@@ -29,6 +29,8 @@
  *  09-28-01  01.02.03  Added structures and defines for SCSI Enclosure
  *                      Processor messages.
  *  10-04-01  01.02.04  Added defines for SEP request Action field.
+ *  05-31-02  01.02.05  Added MPI_SCSIIO_MSGFLGS_CMD_DETERMINES_DATA_DIR define
+ *                      for SCSI IO requests.
  *  --------------------------------------------------------------------------
  */
 
@@ -67,16 +69,17 @@
   SCSIIORequest_t, MPI_POINTER pSCSIIORequest_t;
 
 
-/* SCSIO MsgFlags bits */
+/* SCSI IO 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)
+#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)
+#define MPI_SCSIIO_MSGFLGS_CMD_DETERMINES_DATA_DIR  (0x04)
 
-/* SCSIIO LUN fields */
+/* SCSI IO LUN fields */
 
 #define MPI_SCSIIO_LUN_FIRST_LEVEL_ADDRESSING   (0x0000FFFF)
 #define MPI_SCSIIO_LUN_SECOND_LEVEL_ADDRESSING  (0xFFFF0000)
@@ -85,7 +88,7 @@
 #define MPI_SCSIIO_LUN_LEVEL_1_WORD             (0xFF00)
 #define MPI_SCSIIO_LUN_LEVEL_1_DWORD            (0x0000FF00)
 
-/* SCSIO Control bits */
+/* SCSI IO Control bits */
 
 #define MPI_SCSIIO_CONTROL_DATADIRECTION_MASK   (0x03000000)
 #define MPI_SCSIIO_CONTROL_NODATATRANSFER       (0x00000000)
@@ -114,7 +117,7 @@
 #define MPI_SCSIIO_CONTROL_RESERVED2            (0x00010000)
 
 
-/* SCSIIO reply structure */
+/* SCSI IO reply structure */
 typedef struct _MSG_SCSI_IO_REPLY
 {
     U8                      TargetID;           /* 00h */
@@ -137,7 +140,7 @@
   SCSIIOReply_t, MPI_POINTER pSCSIIOReply_t;
 
 
-/* SCSIIO Reply SCSIStatus values (SAM-2 status codes) */
+/* SCSI IO Reply SCSIStatus values (SAM-2 status codes) */
 
 #define MPI_SCSI_STATUS_SUCCESS                 (0x00)
 #define MPI_SCSI_STATUS_CHECK_CONDITION         (0x02)
@@ -151,7 +154,7 @@
 #define MPI_SCSI_STATUS_ACA_ACTIVE              (0x30)
 
 
-/* SCSIIO Reply SCSIState values */
+/* SCSI IO Reply SCSIState values */
 
 #define MPI_SCSI_STATE_AUTOSENSE_VALID          (0x01)
 #define MPI_SCSI_STATE_AUTOSENSE_FAILED         (0x02)
@@ -160,7 +163,7 @@
 #define MPI_SCSI_STATE_RESPONSE_INFO_VALID      (0x10)
 #define MPI_SCSI_STATE_QUEUE_TAG_REJECTED       (0x20)
 
-/* SCSIIO Reply ResponseInfo values */
+/* SCSI IO Reply ResponseInfo values */
 /* (FCP-1 RSP_CODE values and SPI-3 Packetized Failure codes) */
 
 #define MPI_SCSI_RSP_INFO_FUNCTION_COMPLETE     (0x00000000)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/message/fusion/lsi/mpi_ioc.h linux-2.4.21-pre6/drivers/message/fusion/lsi/mpi_ioc.h
--- linux-2.4.20/drivers/message/fusion/lsi/mpi_ioc.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/message/fusion/lsi/mpi_ioc.h	2003-03-26 23:49:25.000000000 +0000
@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2000-2001 LSI Logic Corporation.
+ *  Copyright (c) 2000-2002 LSI Logic Corporation.
  *
  *
  *           Name:  MPI_IOC.H
  *          Title:  MPI IOC, Port, Event, FW Download, and FW Upload messages
  *  Creation Date:  August 11, 2000
  *
- *    MPI Version:  01.02.04
+ *    MPI_IOC.H Version:  01.02.06
  *
  *  Version History
  *  ---------------
@@ -51,6 +51,10 @@
  *                      MPI_FW_UPLOAD_ITYPE_NVDATA.
  *  09-28-01  01.02.03  Modified Event Data for Integrated RAID.
  *  11-01-01  01.02.04  Added defines for MPI_EXT_IMAGE_HEADER ImageType field.
+ *  03-14-02  01.02.05  Added HeaderVersion field to MSG_IOC_FACTS_REPLY.
+ *  05-31-02  01.02.06  Added define for
+ *                      MPI_IOCFACTS_EXCEPT_RAID_CONFIG_INVALID.
+ *                      Added AliasIndex to EVENT_DATA_LOGOUT structure.
  *  --------------------------------------------------------------------------
  */
 
@@ -151,7 +155,7 @@
     U16                     MsgVersion;                 /* 00h */
     U8                      MsgLength;                  /* 02h */
     U8                      Function;                   /* 03h */
-    U16                     Reserved;                   /* 04h */
+    U16                     HeaderVersion;              /* 04h */
     U8                      IOCNumber;                  /* 06h */
     U8                      MsgFlags;                   /* 07h */
     U32                     MsgContext;                 /* 08h */
@@ -183,7 +187,11 @@
 #define MPI_IOCFACTS_MSGVERSION_MAJOR_MASK          (0xFF00)
 #define MPI_IOCFACTS_MSGVERSION_MINOR_MASK          (0x00FF)
 
+#define MPI_IOCFACTS_HEADERVERSION_UNIT_MASK        (0xFF00)
+#define MPI_IOCFACTS_HEADERVERSION_DEV_MASK         (0x00FF)
+
 #define MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL    (0x0001)
+#define MPI_IOCFACTS_EXCEPT_RAID_CONFIG_INVALID     (0x0002)
 
 #define MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT         (0x01)
 
@@ -464,12 +472,15 @@
 typedef struct _EVENT_DATA_LOGOUT
 {
     U32                     NPortID;                    /* 00h */
-    U8                      Reserved;                   /* 04h */
+    U8                      AliasIndex;                 /* 04h */
     U8                      Port;                       /* 05h */
     U16                     Reserved1;                  /* 06h */
 } EVENT_DATA_LOGOUT, MPI_POINTER PTR_EVENT_DATA_LOGOUT,
   EventDataLogout_t, MPI_POINTER pEventDataLogout_t;
 
+#define MPI_EVENT_LOGOUT_ALL_ALIASES        (0xFF)
+
+
 /* MPI Integrated RAID Event data */
 
 typedef struct _EVENT_DATA_RAID
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/message/fusion/lsi/mpi_lan.h linux-2.4.21-pre6/drivers/message/fusion/lsi/mpi_lan.h
--- linux-2.4.20/drivers/message/fusion/lsi/mpi_lan.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/message/fusion/lsi/mpi_lan.h	2003-03-26 23:49:39.000000000 +0000
@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2000-2001 LSI Logic Corporation.
+ *  Copyright (c) 2000-2002 LSI Logic Corporation.
  *
  *
  *           Name:  MPI_LAN.H
  *          Title:  MPI LAN messages and structures
  *  Creation Date:  June 30, 2000
  *
- *    MPI Version:  01.02.01
+ *    MPI_LAN.H Version:  01.02.01
  *
  *  Version History
  *  ---------------
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/message/fusion/lsi/mpi_raid.h linux-2.4.21-pre6/drivers/message/fusion/lsi/mpi_raid.h
--- linux-2.4.20/drivers/message/fusion/lsi/mpi_raid.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/message/fusion/lsi/mpi_raid.h	2003-03-26 23:49:09.000000000 +0000
@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2001 LSI Logic Corporation.
+ *  Copyright (c) 2001-2002 LSI Logic Corporation.
  *
  *
  *           Name:  MPI_RAID.H
  *          Title:  MPI RAID message and structures
  *  Creation Date:  February 27, 2001
  *
- *    MPI Version:  01.02.04
+ *    MPI_RAID.H Version:  01.02.07
  *
  *  Version History
  *  ---------------
@@ -20,6 +20,11 @@
  *  10-04-01  01.02.03  Added ActionData defines for
  *                      MPI_RAID_ACTION_DELETE_VOLUME action.
  *  11-01-01  01.02.04  Added define for MPI_RAID_ACTION_ADATA_DO_NOT_SYNC.
+ *  03-14-02  01.02.05  Added define for MPI_RAID_ACTION_ADATA_LOW_LEVEL_INIT.
+ *  05-07-02  01.02.06  Added define for MPI_RAID_ACTION_ACTIVATE_VOLUME,
+ *                      MPI_RAID_ACTION_INACTIVATE_VOLUME, and
+ *                      MPI_RAID_ACTION_ADATA_INACTIVATE_ALL.
+ *  07-12-02  01.02.07  Added structures for Mailbox request and reply.
  *  --------------------------------------------------------------------------
  */
 
@@ -74,14 +79,20 @@
 #define MPI_RAID_ACTION_DELETE_PHYSDISK             (0x0E)
 #define MPI_RAID_ACTION_FAIL_PHYSDISK               (0x0F)
 #define MPI_RAID_ACTION_REPLACE_PHYSDISK            (0x10)
+#define MPI_RAID_ACTION_ACTIVATE_VOLUME             (0x11)
+#define MPI_RAID_ACTION_INACTIVATE_VOLUME           (0x12)
 
 /* ActionDataWord defines for use with MPI_RAID_ACTION_CREATE_VOLUME action */
 #define MPI_RAID_ACTION_ADATA_DO_NOT_SYNC           (0x00000001)
+#define MPI_RAID_ACTION_ADATA_LOW_LEVEL_INIT        (0x00000002)
 
 /* ActionDataWord defines for use with MPI_RAID_ACTION_DELETE_VOLUME action */
 #define MPI_RAID_ACTION_ADATA_KEEP_PHYS_DISKS       (0x00000000)
 #define MPI_RAID_ACTION_ADATA_DEL_PHYS_DISKS        (0x00000001)
 
+/* ActionDataWord defines for use with MPI_RAID_ACTION_ACTIVATE_VOLUME action */
+#define MPI_RAID_ACTION_ADATA_INACTIVATE_ALL        (0x00000001)
+
 
 /* RAID Action reply message */
 
@@ -172,6 +183,42 @@
   SCSIIORaidPassthroughReply_t, MPI_POINTER pSCSIIORaidPassthroughReply_t;
 
 
+/****************************************************************************/
+/* Mailbox reqeust structure */
+/****************************************************************************/
+
+typedef struct _MSG_MAILBOX_REQUEST
+{
+    U16                     Reserved1;
+    U8                      ChainOffset;
+    U8                      Function;
+    U16                     Reserved2;
+    U8                      Reserved3;
+    U8                      MsgFlags;
+    U8                      Command[10];
+    U16                     Reserved4;
+    SGE_IO_UNION            SGL;
+} MSG_MAILBOX_REQUEST, MPI_POINTER PTR_MSG_MAILBOX_REQUEST,
+  MailboxRequest_t, MPI_POINTER pMailboxRequest_t;
+
+
+/* Mailbox reply structure */
+typedef struct _MSG_MAILBOX_REPLY
+{
+    U16                     Reserved1;          /* 00h */
+    U8                      MsgLength;          /* 02h */
+    U8                      Function;           /* 03h */
+    U16                     Reserved2;          /* 04h */
+    U8                      Reserved3;          /* 06h */
+    U8                      MsgFlags;           /* 07h */
+    U32                     MsgContext;         /* 08h */
+    U16                     MailboxStatus;      /* 0Ch */
+    U16                     IOCStatus;          /* 0Eh */
+    U32                     IOCLogInfo;         /* 10h */
+    U32                     Reserved4;          /* 14h */
+} MSG_MAILBOX_REPLY, MPI_POINTER PTR_MSG_MAILBOX_REPLY,
+  MailboxReply_t, MPI_POINTER pMailboxReply_t;
+
 #endif
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/message/fusion/lsi/mpi_targ.h linux-2.4.21-pre6/drivers/message/fusion/lsi/mpi_targ.h
--- linux-2.4.20/drivers/message/fusion/lsi/mpi_targ.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/message/fusion/lsi/mpi_targ.h	2003-03-26 23:49:08.000000000 +0000
@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2000-2001 LSI Logic Corporation.
+ *  Copyright (c) 2000-2002 LSI Logic Corporation.
  *
  *
  *           Name:  MPI_TARG.H
  *          Title:  MPI Target mode messages and structures
  *  Creation Date:  June 22, 2000
  *
- *    MPI Version:  01.02.04
+ *    MPI_TARG.H Version:  01.02.07
  *
  *  Version History
  *  ---------------
@@ -34,6 +34,13 @@
  *                      of MPI.
  *  10-04-01  01.02.03  Added PriorityReason to MSG_TARGET_ERROR_REPLY.
  *  11-01-01  01.02.04  Added define for TARGET_STATUS_SEND_FLAGS_HIGH_PRIORITY.
+ *  03-14-02  01.02.05  Modified MPI_TARGET_FCP_RSP_BUFFER to get the proper
+ *                      byte ordering.
+ *  05-31-02  01.02.06  Modified TARGET_MODE_REPLY_ALIAS_MASK to only include
+ *                      one bit.
+ *                      Added AliasIndex field to MPI_TARGET_FCP_CMD_BUFFER.
+ *  09-16-02  01.02.07  Added flags for confirmed completion.
+ *                      Added PRIORITY_REASON_TARGET_BUSY.
  *  --------------------------------------------------------------------------
  */
 
@@ -133,6 +140,7 @@
 #define PRIORITY_REASON_PROTOCOL_ERR            (0x06)
 #define PRIORITY_REASON_DATA_OUT_PARITY_ERR     (0x07)
 #define PRIORITY_REASON_DATA_OUT_CRC_ERR        (0x08)
+#define PRIORITY_REASON_TARGET_BUSY             (0x09)
 #define PRIORITY_REASON_UNKNOWN                 (0xFF)
 
 
@@ -161,6 +169,9 @@
     U8      FcpCntl[4];                                 /* 08h */
     U8      FcpCdb[16];                                 /* 0Ch */
     U32     FcpDl;                                      /* 1Ch */
+    U8      AliasIndex;                                 /* 20h */
+    U8      Reserved1;                                  /* 21h */
+    U16     Reserved2;                                  /* 22h */
 } MPI_TARGET_FCP_CMD_BUFFER, MPI_POINTER PTR_MPI_TARGET_FCP_CMD_BUFFER,
   MpiTargetFcpCmdBuffer, MPI_POINTER pMpiTargetFcpCmdBuffer;
 
@@ -209,6 +220,7 @@
 #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_CONFIRMED               (0x08)
 #define TARGET_ASSIST_FLAGS_REPOST_CMD_BUFFER       (0x80)
 
 
@@ -253,14 +265,19 @@
 
 #define TARGET_STATUS_SEND_FLAGS_AUTO_GOOD_STATUS   (0x01)
 #define TARGET_STATUS_SEND_FLAGS_HIGH_PRIORITY      (0x04)
+#define TARGET_STATUS_SEND_FLAGS_CONFIRMED          (0x08)
 #define TARGET_STATUS_SEND_FLAGS_REPOST_CMD_BUFFER  (0x80)
 
+/*
+ * NOTE: FCP_RSP data is big-endian. When used on a little-endian system, this
+ * structure properly orders the bytes.
+ */
 typedef struct _MPI_TARGET_FCP_RSP_BUFFER
 {
     U8      Reserved0[8];                               /* 00h */
-    U8      FcpStatus;                                  /* 08h */
-    U8      FcpFlags;                                   /* 09h */
-    U8      Reserved1[2];                               /* 0Ah */
+    U8      Reserved1[2];                               /* 08h */
+    U8      FcpFlags;                                   /* 0Ah */
+    U8      FcpStatus;                                  /* 0Bh */
     U32     FcpResid;                                   /* 0Ch */
     U32     FcpSenseLength;                             /* 10h */
     U32     FcpResponseLength;                          /* 14h */
@@ -269,6 +286,10 @@
 } MPI_TARGET_FCP_RSP_BUFFER, MPI_POINTER PTR_MPI_TARGET_FCP_RSP_BUFFER,
   MpiTargetFcpRspBuffer, MPI_POINTER pMpiTargetFcpRspBuffer;
 
+/*
+ * NOTE: The SPI status IU is big-endian. When used on a little-endian system,
+ * this structure properly orders the bytes.
+ */
 typedef struct _MPI_TARGET_SCSI_SPI_STATUS_IU
 {
     U8      Reserved0;                                  /* 00h */
@@ -332,7 +353,7 @@
 #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_MASK            (0x04000000)
 #define TARGET_MODE_REPLY_ALIAS_SHIFT           (26)
 #define TARGET_MODE_REPLY_PORT_MASK             (0x10000000)
 #define TARGET_MODE_REPLY_PORT_SHIFT            (28)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/message/fusion/lsi/mpi_type.h linux-2.4.21-pre6/drivers/message/fusion/lsi/mpi_type.h
--- linux-2.4.20/drivers/message/fusion/lsi/mpi_type.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/message/fusion/lsi/mpi_type.h	2003-03-26 23:49:49.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2000-2001 LSI Logic Corporation.
+ *  Copyright (c) 2000-2002 LSI Logic Corporation.
  *
  *
  *           Name:  MPI_TYPE.H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/message/fusion/mptbase.c linux-2.4.21-pre6/drivers/message/fusion/mptbase.c
--- linux-2.4.20/drivers/message/fusion/mptbase.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/message/fusion/mptbase.c	2003-03-26 23:49:18.000000000 +0000
@@ -49,7 +49,7 @@
  *  (mailto:sjralston1@netscape.net)
  *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptbase.c,v 1.121 2002/07/23 18:56:59 pdelaney Exp $
+ *  $Id: mptbase.c,v 1.124 2002/11/01 17:58:12 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -1416,10 +1416,30 @@
 	else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929X) {
 		ioc->chip_type = FC929X;
 		ioc->prod_name = "LSIFC929X";
+		{
+			/* 929X Chip Fix. Set Split transactions level
+			 * for PCIX. Set bits 5 - 6 to zero, turn on bit 4.
+			 */
+			u16 pcixcmd = 0;
+			pci_read_config_word(pdev, 0x6a, &pcixcmd);
+			pcixcmd &= 0xFF9F;
+			pcixcmd |= 0x0010;
+			pci_write_config_word(pdev, 0x6a, pcixcmd);
+		}
 	}
 	else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919X) {
 		ioc->chip_type = FC919X;
 		ioc->prod_name = "LSIFC919X";
+		{
+			/* 919X Chip Fix. Set Split transactions level
+			 * for PCIX. Set bits 5 - 6 to zero, turn on bit 4.
+			 */
+			u16 pcixcmd = 0;
+			pci_read_config_word(pdev, 0x6a, &pcixcmd);
+			pcixcmd &= 0xFF9F;
+			pcixcmd |= 0x0010;
+			pci_write_config_word(pdev, 0x6a, pcixcmd);
+		}
 	}
 	else if (pdev->device == MPI_MANUFACTPAGE_DEVID_53C1030) {
 		ioc->chip_type = C1030;
@@ -1782,24 +1802,23 @@
 	if (this != NULL) {
 		int sz;
 		u32 state;
+		int ret;
 
 		/* Disable the FW */
 		state = mpt_GetIocState(this, 1);
 		if (state == MPI_IOC_STATE_OPERATIONAL) {
-			if (SendIocReset(this, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, NO_SLEEP) != 0)
-				(void) KickStart(this, 1, NO_SLEEP);
+			SendIocReset(this, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, NO_SLEEP);
 		}
 
 		if (this->cached_fw != NULL) {
 			ddlprintk((KERN_INFO MYNAM ": Pushing FW onto adapter\n"));
 
-			if ((state = mpt_downloadboot(this, NO_SLEEP)) < 0) {
+			if ((ret = mpt_downloadboot(this, NO_SLEEP)) < 0) {
 				printk(KERN_WARNING MYNAM 
-					": firmware downloadboot failure (%d)!\n", state);
+					": firmware downloadboot failure (%d)!\n", ret);
 			}
 		}
 
-
 		/* Disable adapter interrupts! */
 		CHIPREG_WRITE32(&this->chip->IntMask, 0xFFFFFFFF);
 		this->active = 0;
@@ -2006,8 +2025,19 @@
 	}
 
 	/* Is it already READY? */
-	if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY)
-		return 0;
+	if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY) {
+		if ((int)ioc->chip_type <= (int)FC929)
+			return 0;
+		else {
+			/* Workaround from broken 1030 FW.
+			 * Force a diagnostic reset if fails.
+			 */
+			if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0)
+				return 0;
+			else
+				statefault = 4;
+		}
+	} 
 
 	/*
 	 *	Check to see if IOC is in FAULT state.
@@ -2860,6 +2890,7 @@
 	 */
 	diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
 	while ((diag0val & MPI_DIAG_DRWE) == 0) {
+		CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
 		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);
@@ -3095,6 +3126,18 @@
 	int cnt = 0;
 
 	dprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name));
+	if ((int)ioc->chip_type > (int)FC929) {
+		/* Always issue a Msg Unit Reset first. This will clear some
+		 * SCSI bus hang conditions.
+		 */
+		SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
+
+		if (sleepFlag == CAN_SLEEP) {
+			schedule_timeout(HZ);
+		} else {
+			mdelay (1000);
+		}
+	}
 
 	hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag);
 	if (hard_reset_done < 0)
@@ -3173,6 +3216,7 @@
 			/* Write magic sequence to WriteSequence register
 			 * Loop until in diagnostic mode
 			 */
+			CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
 			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);
@@ -3208,7 +3252,11 @@
 				ioc->name, diag0val, diag1val));
 #endif
 		/* Write the PreventIocBoot bit */
+#if 1
+		if ((ioc->cached_fw) || (ioc->alt_ioc && ioc->alt_ioc->cached_fw)) {
+#else
 		if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) {
+#endif
 			diag0val |= MPI_DIAG_PREVENT_IOC_BOOT;
 			CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
 		}
@@ -3254,7 +3302,11 @@
 			/* FIXME?  Examine results here? */
 		}
 
+#if 1
+		if ((ioc->cached_fw) || (ioc->alt_ioc && ioc->alt_ioc->cached_fw)) {
+#else
 		if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) {
+#endif
 			/* If the DownloadBoot operation fails, the
 			 * IOC will be left unusable. This is a fatal error
 			 * case.  _diag_reset will return < 0
@@ -5265,6 +5317,9 @@
 		printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n",
 			rc, ioc->name);
 	}
+	ioc->reload_fw = 0;
+	if (ioc->alt_ioc)
+		ioc->alt_ioc->reload_fw = 0;
 
 	spin_lock_irqsave(&ioc->diagLock, flags);
 	ioc->diagPending = 0;
@@ -5603,8 +5658,46 @@
 static void
 mpt_sp_log_info(MPT_ADAPTER *ioc, u32 log_info)
 {
-	/* FIXME! */
-	printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x)\n", ioc->name, log_info);
+	u32 info = log_info & 0x00FF0000;
+	char *desc = "unknown";
+
+	switch (info) {
+	case 0x00010000:
+		desc = "bug! MID not found";
+		if (ioc->reload_fw == 0)
+			ioc->reload_fw++;
+		break;
+
+	case 0x00020000:
+		desc = "Parity Error";
+		break;
+
+	case 0x00030000:
+		desc = "ASYNC Outbound Overrun";
+		break;
+
+	case 0x00040000:
+		desc = "SYNC Offset Error";
+		break;
+
+	case 0x00050000:
+		desc = "BM Change";
+		break;
+
+	case 0x00060000:
+		desc = "Msg In Overflow";
+		break;
+
+	case 0x00070000:
+		desc = "DMA Error";
+		break;
+
+	case 0x00080000:
+		desc = "Outbound DMA Overrun";
+		break;
+	}
+
+	printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc);
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -5760,6 +5853,15 @@
 
 	while (! Q_IS_EMPTY(&MptAdapters)) {
 		this = MptAdapters.head;
+
+		/* Disable interrupts! */
+		CHIPREG_WRITE32(&this->chip->IntMask, 0xFFFFFFFF);
+
+		this->active = 0;
+
+		/* Clear any lingering interrupt */
+		CHIPREG_WRITE32(&this->chip->IntStatus, 0);
+
 		Q_DEL_ITEM(this);
 		mpt_adapter_dispose(this);
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/message/fusion/mptbase.h linux-2.4.21-pre6/drivers/message/fusion/mptbase.h
--- linux-2.4.20/drivers/message/fusion/mptbase.h	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/message/fusion/mptbase.h	2003-03-26 23:49:09.000000000 +0000
@@ -13,7 +13,7 @@
  *  (mailto:sjralston1@netscape.net)
  *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptbase.h,v 1.133 2002/09/05 22:30:09 pdelaney Exp $
+ *  $Id: mptbase.h,v 1.139 2002/11/11 18:33:40 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -80,8 +80,8 @@
 #define COPYRIGHT	"Copyright (c) 1999-2002 " MODULEAUTHOR
 #endif
 
-#define MPT_LINUX_VERSION_COMMON	"2.02.01"
-#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-2.02.01"
+#define MPT_LINUX_VERSION_COMMON	"2.03.00"
+#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-2.03.00"
 #define WHAT_MAGIC_STRING		"@" "(" "#" ")"
 
 #define show_mptmod_ver(s,ver)  \
@@ -91,7 +91,7 @@
 /*
  *  Fusion MPT(linux) driver configurable stuff...
  */
-#define MPT_MAX_ADAPTERS		16
+#define MPT_MAX_ADAPTERS		18
 #define MPT_MAX_PROTOCOL_DRIVERS	16
 #define MPT_MAX_BUS			1
 #define MPT_MAX_FC_DEVICES		255
@@ -397,8 +397,10 @@
 	ScsiCmndTracker		 SentQ;
 	ScsiCmndTracker		 DoneQ;
 //--- LUN split here?
+#ifdef MPT_SAVE_AUTOSENSE
 	u8			 sense[SCSI_STD_SENSE_BYTES];		/* 18 */
 	u8			 rsvd2[2];	/* alignment */
+#endif
 	u32			 luns;		/* Max LUNs is 32 */
 	u8			 inq_data[SCSI_STD_INQUIRY_BYTES];	/* 36 */
 	u8			 pad0[4];
@@ -424,8 +426,11 @@
 #define MPT_TARGET_DEFAULT_DV_STATUS	0
 #define MPT_TARGET_FLAGS_VALID_NEGO	0x01
 #define MPT_TARGET_FLAGS_VALID_INQUIRY	0x02
+#ifdef MPT_SAVE_AUTOSENSE
 #define MPT_TARGET_FLAGS_VALID_SENSE	0x04
+#endif
 #define MPT_TARGET_FLAGS_Q_YES		0x08
+#define MPT_TARGET_FLAGS_VALID_56	0x10
 
 #define MPT_TARGET_NO_NEGO_WIDE		0x01
 #define MPT_TARGET_NO_NEGO_SYNC		0x02
@@ -527,7 +532,6 @@
 	int		*nvram;			/* table of device NVRAM values */
 	IOCPage3_t	*pIocPg3;		/* table of physical disks */
 	u8		 dvStatus[MPT_MAX_SCSI_DEVICES];
-	u8		 iocntr[MPT_MAX_SCSI_DEVICES];
 	int		 isRaid;		/* bit field, 1 if RAID */
 	u8		 minSyncFactor;		/* 0xFF if async */
 	u8		 maxSyncOffset;		/* 0 if async */
@@ -627,7 +631,8 @@
 	LANPage1_t		 lan_cnfg_page1;
 	u8			 FirstWhoInit;
 	u8			 upload_fw;	/* If set, do a fw upload */
-	u8			 pad1[6];
+	u8			 reload_fw;	/* Force a FW Reload on next reset */
+	u8			 pad1[5];
 } MPT_ADAPTER;
 
 
@@ -889,6 +894,8 @@
 	MPT_Q_TRACKER		  taskQ;		/* TM request Q */
 	spinlock_t		  freedoneQlock;
 	int			  taskQcnt;
+	int			  num_chain;		/* Number of chain buffers */
+	int			  max_sge;		/* Max No of SGE*/
 	u8			  numTMrequests;
 	u8			  tmPending;
 	u8			  resetPending;
@@ -905,6 +912,9 @@
 	MPT_FRAME_HDR		 *cmdPtr;		/* Ptr to nonOS request */
 	struct scsi_cmnd	 *abortSCpnt;
 	MPT_LOCAL_REPLY		  localReply;		/* internal cmd reply struct */
+	unsigned long		  hard_resets;		/* driver forced bus resets count */
+	unsigned long		  soft_resets;		/* fw/external bus resets count */
+	unsigned long		  timeouts;		/* cmd timeouts */
 } MPT_SCSI_HOST;
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/message/fusion/mptctl.c linux-2.4.21-pre6/drivers/message/fusion/mptctl.c
--- linux-2.4.20/drivers/message/fusion/mptctl.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/message/fusion/mptctl.c	2003-03-26 23:48:59.000000000 +0000
@@ -34,7 +34,7 @@
  *  (mailto:sjralston1@netscape.net)
  *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptctl.c,v 1.59 2002/09/05 22:30:10 pdelaney Exp $
+ *  $Id: mptctl.c,v 1.62 2002/11/01 17:58:13 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -136,6 +136,8 @@
 static int mptctl_replace_fw (unsigned long arg);
 
 static int mptctl_do_reset(unsigned long arg);
+static int mptctl_hp_hostinfo(unsigned long arg);
+static int mptctl_hp_targetinfo(unsigned long arg);
 
 static int mptctl_compaq_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
 static int mptctl_cpq_getpciinfo(unsigned long arg);
@@ -415,7 +417,7 @@
 	/* Send request
 	 */
 	if ((mf = mpt_get_msg_frame(mptctl_id, ioctl->ioc->id)) == NULL) {
-		dtmprintk((MYIOC_s_WARN_FMT "IssueTaskMgmt, no msg frames!!\n",
+		dctlprintk((MYIOC_s_WARN_FMT "IssueTaskMgmt, no msg frames!!\n",
 				ioctl->ioc->name));
 
 		mptctl_free_tm_flags(ioctl->ioc);
@@ -627,7 +629,7 @@
 	/* Test for Compaq-specific IOCTL's.
 	 */
 	if ((cmd == CPQFCTS_GETPCIINFO) || (cmd == CPQFCTS_CTLR_STATUS) ||
-		(cmd == CPQFCTS_GETDRIVER) || (cmd == CPQFCTS_SCSI_PASSTHRU) ||
+		(cmd == CPQFCTS_GETDRIVVER) || (cmd == CPQFCTS_SCSI_PASSTHRU) ||
 		(cmd == CPQFCTS_SCSI_IOCTL_FC_TARGET_ADDRESS))
 		return mptctl_compaq_ioctl(file, cmd, arg);
 
@@ -637,7 +639,7 @@
 	iocnumX = khdr.iocnum & 0xFF;
 	if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
 	    (iocp == NULL)) {
-		dtmprintk((KERN_ERR "%s::mptctl_ioctl() @%d - ioc%d not found!\n",
+		dctlprintk((KERN_ERR "%s::mptctl_ioctl() @%d - ioc%d not found!\n",
 				__FILE__, __LINE__, iocnumX));
 		return -ENODEV;
 	}
@@ -683,6 +685,12 @@
 	case MPTHARDRESET:
 		ret = mptctl_do_reset(arg);
 		break;
+	case HP_GETHOSTINFO:
+		ret = mptctl_hp_hostinfo(arg);
+		break;
+	case HP_GETTARGETINFO:
+		ret = mptctl_hp_targetinfo(arg);
+		break;
 	default:
 		ret = -EINVAL;
 	}
@@ -708,7 +716,7 @@
 	}
 
 	if (mpt_verify_adapter(krinfo.hdr.iocnum, &iocp) < 0) {
-		dtmprintk((KERN_ERR "%s@%d::mptctl_do_reset - ioc%d not found!\n",
+		dctlprintk((KERN_ERR "%s@%d::mptctl_do_reset - ioc%d not found!\n",
 				__FILE__, __LINE__, krinfo.hdr.iocnum));
 		return -ENODEV; /* (-6) No such device or address */
 	}
@@ -816,7 +824,7 @@
 	dctlprintk((KERN_INFO "DbG: kfwdl.ioc   = %04xh\n", ioc));
 
 	if ((ioc = mpt_verify_adapter(ioc, &iocp)) < 0) {
-		dtmprintk(("%s@%d::_ioctl_fwdl - ioc%d not found!\n",
+		dctlprintk(("%s@%d::_ioctl_fwdl - ioc%d not found!\n",
 				__FILE__, __LINE__, ioc));
 		return -ENODEV; /* (-6) No such device or address */
 	}
@@ -1252,7 +1260,7 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		dtmprintk((KERN_ERR "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n",
+		dctlprintk((KERN_ERR "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n",
 				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
@@ -1379,7 +1387,7 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		dtmprintk((KERN_ERR "%s::mptctl_gettargetinfo() @%d - ioc%d not found!\n",
+		dctlprintk((KERN_ERR "%s::mptctl_gettargetinfo() @%d - ioc%d not found!\n",
 				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
@@ -1510,7 +1518,7 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		dtmprintk((KERN_ERR "%s::mptctl_readtest() @%d - ioc%d not found!\n",
+		dctlprintk((KERN_ERR "%s::mptctl_readtest() @%d - ioc%d not found!\n",
 				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
@@ -1568,7 +1576,7 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		dtmprintk((KERN_ERR "%s::mptctl_eventquery() @%d - ioc%d not found!\n",
+		dctlprintk((KERN_ERR "%s::mptctl_eventquery() @%d - ioc%d not found!\n",
 				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
@@ -1606,7 +1614,7 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		dtmprintk((KERN_ERR "%s::mptctl_eventenable() @%d - ioc%d not found!\n",
+		dctlprintk((KERN_ERR "%s::mptctl_eventenable() @%d - ioc%d not found!\n",
 				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
@@ -1654,7 +1662,7 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		dtmprintk((KERN_ERR "%s::mptctl_eventreport() @%d - ioc%d not found!\n",
+		dctlprintk((KERN_ERR "%s::mptctl_eventreport() @%d - ioc%d not found!\n",
 				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
@@ -1708,7 +1716,7 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		dtmprintk((KERN_ERR "%s::mptctl_replace_fw() @%d - ioc%d not found!\n",
+		dctlprintk((KERN_ERR "%s::mptctl_replace_fw() @%d - ioc%d not found!\n",
 				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
@@ -1794,7 +1802,7 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		dtmprintk((KERN_ERR "%s::mptctl_mpt_command() @%d - ioc%d not found!\n",
+		dctlprintk((KERN_ERR "%s::mptctl_mpt_command() @%d - ioc%d not found!\n",
 				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
@@ -1842,7 +1850,7 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		dtmprintk((KERN_ERR "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n",
+		dctlprintk((KERN_ERR "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n",
 				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
@@ -1926,6 +1934,14 @@
 			int target = (int) pScsiReq->TargetID;
 			int dataSize;
 
+			if ((target < 0) || (target >= ioc->sh->max_id)) {
+				printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+					"Target ID out of bounds. \n",
+					__FILE__, __LINE__);
+				rc = -ENODEV;
+				goto done_free_mem;
+			}
+
 			pScsiReq->MsgFlags = mpt_msg_flags();
 
 			/* verify that app has not requested
@@ -2330,7 +2346,7 @@
 			this_sge++;	/* go to next structure */
 			this_alloc = bufOut.len;
 			pci_free_consistent(ioc->pcidev,
-				this_alloc, (void *)bufOut.kptr, dma_addr);
+				this_alloc, (void *) bufOut.kptr, dma_addr);
 		}
 
 		if (bufIn.kptr != NULL ) {
@@ -2338,7 +2354,7 @@
 			this_alloc = bufIn.len;
 
 			pci_free_consistent(ioc->pcidev,
-					this_alloc, (void *)bufIn.kptr, dma_addr);
+					this_alloc, (void *) bufIn.kptr, dma_addr);
 		}
 
 		this_alloc = sgSize * sizeof(MptSge_t);
@@ -2357,6 +2373,317 @@
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* Prototype Routine for the HP HOST INFO command.
+ *
+ * Outputs:	None.
+ * Return:	0 if successful
+ *		-EFAULT if data unavailable
+ *		-EBUSY  if previous command timout and IOC reset is not complete.
+ *		-ENODEV if no such device/adapter
+ *		-ETIME	if timer expires
+ *		-ENOMEM if memory allocation error
+ */
+static int
+mptctl_hp_hostinfo(unsigned long arg)
+{
+	hp_host_info_t	*uarg = (hp_host_info_t *) arg;
+	MPT_ADAPTER		*ioc;
+	struct pci_dev		*pdev;
+	char			*pbuf;
+	dma_addr_t		buf_dma;
+	hp_host_info_t		karg;
+	CONFIGPARMS		cfg;
+	ConfigPageHeader_t	hdr;
+	int			iocnum;
+	int			rc;
+
+	dctlprintk((": mptctl_hp_hostinfo called.\n"));
+	if (copy_from_user(&karg, uarg, sizeof(hp_host_info_t))) {
+		printk(KERN_ERR "%s@%d::mptctl_hp_host_info - "
+			"Unable to read in hp_host_info struct @ %p\n",
+				__FILE__, __LINE__, (void*)uarg);
+		return -EFAULT;
+	}
+
+	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+	    (ioc == NULL)) {
+		dctlprintk((KERN_ERR "%s::mptctl_hp_hostinfo() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum));
+		return -ENODEV;
+	}
+
+	/* Fill in the data and return the structure to the calling
+	 * program
+	 */
+	pdev = (struct pci_dev *) ioc->pcidev;
+
+	karg.vendor = pdev->vendor;
+	karg.device = pdev->device;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	karg.subsystem_id = pdev->subsystem_device;
+	karg.subsystem_vendor = pdev->subsystem_vendor;
+#endif
+	karg.devfn = pdev->devfn;
+	karg.bus = pdev->bus->number;
+
+	/* Save the SCSI host no. if
+	 * SCSI driver loaded 
+	 */
+	if (ioc->sh != NULL)
+		karg.host_no = ioc->sh->host_no;
+	else
+		karg.host_no =  -1;
+
+	/* Reformat the fw_version into a string
+	 */
+	karg.fw_version[0] = ioc->facts.FWVersion.Struct.Major >= 10 ?
+		((ioc->facts.FWVersion.Struct.Major / 10) + '0') : '0';
+	karg.fw_version[1] = (ioc->facts.FWVersion.Struct.Major % 10 ) + '0';
+	karg.fw_version[2] = '.';
+	karg.fw_version[3] = ioc->facts.FWVersion.Struct.Minor >= 10 ?
+		((ioc->facts.FWVersion.Struct.Minor / 10) + '0') : '0';
+	karg.fw_version[4] = (ioc->facts.FWVersion.Struct.Minor % 10 ) + '0';
+	karg.fw_version[5] = '.';
+	karg.fw_version[6] = ioc->facts.FWVersion.Struct.Unit >= 10 ?
+		((ioc->facts.FWVersion.Struct.Unit / 10) + '0') : '0';
+	karg.fw_version[7] = (ioc->facts.FWVersion.Struct.Unit % 10 ) + '0';
+	karg.fw_version[8] = '.';
+	karg.fw_version[9] = ioc->facts.FWVersion.Struct.Dev >= 10 ?
+		((ioc->facts.FWVersion.Struct.Dev / 10) + '0') : '0';
+	karg.fw_version[10] = (ioc->facts.FWVersion.Struct.Dev % 10 ) + '0';
+	karg.fw_version[11] = '\0';
+
+	/* Issue a config request to get the device serial number
+	 */
+	hdr.PageVersion = 0;
+	hdr.PageLength = 0;
+	hdr.PageNumber = 0;
+	hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
+	cfg.hdr = &hdr;
+	cfg.physAddr = -1;
+	cfg.pageAddr = 0;
+	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+	cfg.dir = 0;	/* read */
+	cfg.timeout = 10;
+
+	strncpy(karg.serial_number, " ", 24);
+	if (mpt_config(ioc, &cfg) == 0) {
+		if (cfg.hdr->PageLength > 0) {
+			/* Issue the second config page request */
+			cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+			pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
+			if (pbuf) {
+				cfg.physAddr = buf_dma;
+				if (mpt_config(ioc, &cfg) == 0) {
+					ManufacturingPage0_t *pdata = (ManufacturingPage0_t *) pbuf;
+					if (strlen(pdata->BoardTracerNumber) > 1)
+						strncpy(karg.serial_number, pdata->BoardTracerNumber, 24);
+				}
+				pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
+				pbuf = NULL;
+			}
+		}
+	}
+	rc = mpt_GetIocState(ioc, 1);
+	switch (rc) {
+	case MPI_IOC_STATE_OPERATIONAL:
+		karg.ioc_status =  HP_STATUS_OK;
+		break;
+
+	case MPI_IOC_STATE_FAULT:
+		karg.ioc_status =  HP_STATUS_FAILED;
+		break;
+
+	case MPI_IOC_STATE_RESET:
+	case MPI_IOC_STATE_READY:
+	default:
+		karg.ioc_status =  HP_STATUS_OTHER;
+		break;
+	}
+
+	karg.base_io_addr = pdev->PCI_BASEADDR_START(0);
+
+	if ((int)ioc->chip_type <= (int) FC929)
+		karg.bus_phys_width = HP_BUS_WIDTH_UNK;
+	else
+		karg.bus_phys_width = HP_BUS_WIDTH_16;
+
+	karg.hard_resets = 0;
+	karg.soft_resets = 0;
+	karg.timeouts = 0;
+	if (ioc->sh != NULL) {
+		MPT_SCSI_HOST *hd =  (MPT_SCSI_HOST *)ioc->sh->hostdata;
+
+		if (hd) {
+			karg.hard_resets = hd->hard_resets;
+			karg.soft_resets = hd->soft_resets;
+			karg.timeouts = hd->timeouts;
+		}
+	}
+
+	/* Copy the data from kernel memory to user memory
+	 */
+	if (copy_to_user((char *)arg, &karg,
+				sizeof(hp_host_info_t))) {
+		printk(KERN_ERR "%s@%d::mptctl_hpgethostinfo - "
+			"Unable to write out hp_host_info @ %p\n",
+				__FILE__, __LINE__, (void*)uarg);
+		return -EFAULT;
+	}
+
+	return 0;
+
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* Prototype Routine for the HP TARGET INFO command.
+ *
+ * Outputs:	None.
+ * Return:	0 if successful
+ *		-EFAULT if data unavailable
+ *		-EBUSY  if previous command timout and IOC reset is not complete.
+ *		-ENODEV if no such device/adapter
+ *		-ETIME	if timer expires
+ *		-ENOMEM if memory allocation error
+ */
+static int
+mptctl_hp_targetinfo(unsigned long arg)
+{
+	hp_target_info_t	*uarg = (hp_target_info_t *) arg;
+	SCSIDevicePage0_t	*pg0_alloc;
+	SCSIDevicePage3_t	*pg3_alloc;
+	MPT_ADAPTER		*ioc;
+	hp_target_info_t	karg;
+	int			iocnum;
+	int			data_sz;
+	dma_addr_t		page_dma;
+	CONFIGPARMS	 	cfg;
+	ConfigPageHeader_t	hdr;
+	int			tmp, np, rc = 0;
+
+	dctlprintk((": mptctl_hp_targetinfo called.\n"));
+	if (copy_from_user(&karg, uarg, sizeof(hp_target_info_t))) {
+		printk(KERN_ERR "%s@%d::mptctl_hp_targetinfo - "
+			"Unable to read in hp_host_targetinfo struct @ %p\n",
+				__FILE__, __LINE__, (void*)uarg);
+		return -EFAULT;
+	}
+	
+	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
+		(ioc == NULL)) {
+		dctlprintk((KERN_ERR "%s::mptctl_hp_targetinfo() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum));
+		return -ENODEV;
+	}
+
+	/*  There is nothing to do for FCP parts.
+	 */
+	if ((int) ioc->chip_type <= (int) FC929)
+		return 0;
+
+	if ((ioc->spi_data.sdp0length == 0) || (ioc->sh == NULL))
+		return 0;
+
+	if (ioc->sh->host_no != karg.hdr.host)
+		return -ENODEV;
+		
+       /* Get the data transfer speeds
+        */
+	data_sz = ioc->spi_data.sdp0length * 4;
+	pg0_alloc = (SCSIDevicePage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma);
+	if (pg0_alloc) {
+		hdr.PageVersion = ioc->spi_data.sdp0version;
+		hdr.PageLength = data_sz;
+		hdr.PageNumber = 0;
+		hdr.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
+
+		cfg.hdr = &hdr;
+		cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+		cfg.dir = 0;
+		cfg.timeout = 0;
+		cfg.physAddr = page_dma;
+
+		cfg.pageAddr = (karg.hdr.channel << 8) | karg.hdr.id;
+
+		if ((rc = mpt_config(ioc, &cfg)) == 0) {
+			np = le32_to_cpu(pg0_alloc->NegotiatedParameters);
+			karg.negotiated_width = np & MPI_SCSIDEVPAGE0_NP_WIDE ? 
+					HP_BUS_WIDTH_16 : HP_BUS_WIDTH_8;
+
+			if (np & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK) {
+				tmp = (np & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK) >> 8;
+				if (tmp < 0x09)
+					karg.negotiated_speed = HP_DEV_SPEED_ULTRA320;
+				else if (tmp <= 0x09)
+					karg.negotiated_speed = HP_DEV_SPEED_ULTRA160;
+				else if (tmp <= 0x0A)
+					karg.negotiated_speed = HP_DEV_SPEED_ULTRA2;
+				else if (tmp <= 0x0C)
+					karg.negotiated_speed = HP_DEV_SPEED_ULTRA;
+				else if (tmp <= 0x25)
+					karg.negotiated_speed = HP_DEV_SPEED_FAST;
+				else
+					karg.negotiated_speed = HP_DEV_SPEED_ASYNC;
+			} else
+				karg.negotiated_speed = HP_DEV_SPEED_ASYNC;
+		}
+
+		pci_free_consistent(ioc->pcidev, data_sz, (u8 *) pg0_alloc, page_dma);
+	}
+
+	/* Set defaults
+	 */
+	karg.message_rejects = -1;
+	karg.phase_errors = -1;
+	karg.parity_errors = -1;
+	karg.select_timeouts = -1;
+
+	/* Get the target error parameters
+	 */
+	hdr.PageVersion = 0;
+	hdr.PageLength = 0;
+	hdr.PageNumber = 3;
+	hdr.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE;
+
+	cfg.hdr = &hdr;
+	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+	cfg.dir = 0;
+	cfg.timeout = 0;
+	cfg.physAddr = -1;
+	if ((mpt_config(ioc, &cfg) == 0) && (cfg.hdr->PageLength > 0)) {
+		/* Issue the second config page request */
+		cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+		data_sz = (int) cfg.hdr->PageLength * 4;
+		pg3_alloc = (SCSIDevicePage3_t *) pci_alloc_consistent(
+							ioc->pcidev, data_sz, &page_dma);
+		if (pg3_alloc) {
+			cfg.physAddr = page_dma;
+			cfg.pageAddr = (karg.hdr.channel << 8) | karg.hdr.id;
+			if ((rc = mpt_config(ioc, &cfg)) == 0) {
+				karg.message_rejects = (u32) le16_to_cpu(pg3_alloc->MsgRejectCount);
+				karg.phase_errors = (u32) le16_to_cpu(pg3_alloc->PhaseErrorCount);
+				karg.parity_errors = (u32) le16_to_cpu(pg3_alloc->ParityErrorCount);
+			}
+			pci_free_consistent(ioc->pcidev, data_sz, (u8 *) pg3_alloc, page_dma);
+		}
+	}
+
+	/* Copy the data from kernel memory to user memory
+	 */
+	if (copy_to_user((char *)arg, &karg, sizeof(hp_target_info_t))) {
+		printk(KERN_ERR "%s@%d::mptctl_hp_target_info - "
+			"Unable to write out mpt_ioctl_targetinfo struct @ %p\n",
+				__FILE__, __LINE__, (void*)uarg);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /* Routine for the Compaq IOCTL commands.
  *
  * Outputs:	None.
@@ -2389,7 +2716,7 @@
 
 	if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
 	    (iocp == NULL)) {
-		dtmprintk((KERN_ERR "%s::mptctl_compaq_ioctl() @%d - ioc%d not found!\n",
+		dctlprintk((KERN_ERR "%s::mptctl_compaq_ioctl() @%d - ioc%d not found!\n",
 				__FILE__, __LINE__, iocnumX));
 		return -ENODEV;
 	}
@@ -2406,7 +2733,7 @@
 	case CPQFCTS_GETPCIINFO:
 		ret = mptctl_cpq_getpciinfo(arg);
 		break;
-	case CPQFCTS_GETDRIVER:
+	case CPQFCTS_GETDRIVVER:
 		ret = mptctl_cpq_getdriver(arg);
 		break;
 	case CPQFCTS_CTLR_STATUS:
@@ -2462,7 +2789,7 @@
 
 	if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		dtmprintk((KERN_ERR "%s::mptctl_pciinfo() @%d - ioc%d not found!\n",
+		dctlprintk((KERN_ERR "%s::mptctl_pciinfo() @%d - ioc%d not found!\n",
 				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
@@ -2563,7 +2890,7 @@
 
 	if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		dtmprintk((KERN_ERR "%s::mptctl_cpq_getdriver() @%d - ioc%d not found!\n",
+		dctlprintk((KERN_ERR "%s::mptctl_cpq_getdriver() @%d - ioc%d not found!\n",
 				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
@@ -2627,7 +2954,7 @@
 
 	if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		dtmprintk((KERN_ERR "%s::mptctl_cpq_ctlr_status() @%d - ioc%d not found!\n",
+		dctlprintk((KERN_ERR "%s::mptctl_cpq_ctlr_status() @%d - ioc%d not found!\n",
 				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
@@ -2683,7 +3010,7 @@
 
 	if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		dtmprintk((KERN_ERR "%s::mptctl_cpq_target_address() @%d - ioc%d not found!\n",
+		dctlprintk((KERN_ERR "%s::mptctl_cpq_target_address() @%d - ioc%d not found!\n",
 				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
@@ -2786,7 +3113,7 @@
 	iocnumX = karg.lc & 0xFF;
 	if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		dtmprintk((KERN_ERR "%s::mptctl_cpq_passthru() @%d - ioc%d not found!\n",
+		dctlprintk((KERN_ERR "%s::mptctl_cpq_passthru() @%d - ioc%d not found!\n",
 				__FILE__, __LINE__, iocnum));
 		return -ENODEV;
 	}
@@ -2971,7 +3298,7 @@
 	iocnumX = kfw32.iocnum & 0xFF;
 	if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
 	    (iocp == NULL)) {
-		dtmprintk((KERN_ERR MYNAM "::sparc32_mptfwxfer_ioctl @%d - ioc%d not found!\n",
+		dctlprintk((KERN_ERR MYNAM "::sparc32_mptfwxfer_ioctl @%d - ioc%d not found!\n",
 				__LINE__, iocnumX));
 		return -ENODEV;
 	}
@@ -3011,7 +3338,7 @@
 	iocnumX = karg32.hdr.iocnum & 0xFF;
 	if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
 	    (iocp == NULL)) {
-		dtmprintk((KERN_ERR MYNAM "::sparc32_mpt_command @%d - ioc%d not found!\n",
+		dctlprintk((KERN_ERR MYNAM "::sparc32_mpt_command @%d - ioc%d not found!\n",
 				__LINE__, iocnumX));
 		return -ENODEV;
 	}
@@ -3068,7 +3395,7 @@
 	iocnumX = karg32.lc & 0xFF;
 	if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		dtmprintk((KERN_ERR MYNAM "::sparc32_mpt_command @%d - ioc%d not found!\n",
+		dctlprintk((KERN_ERR MYNAM "::sparc32_mpt_command @%d - ioc%d not found!\n",
 				__LINE__, iocnumX));
 		return -ENODEV;
 	}
@@ -3180,12 +3507,16 @@
 	if (++where && err) goto out_fail;
 	err = register_ioctl32_conversion(CPQFCTS_CTLR_STATUS, NULL);
 	if (++where && err) goto out_fail;
-	err = register_ioctl32_conversion(CPQFCTS_GETDRIVER, NULL);
+	err = register_ioctl32_conversion(CPQFCTS_GETDRIVVER, NULL);
 	if (++where && err) goto out_fail;
 	err = register_ioctl32_conversion(CPQFCTS_SCSI_IOCTL_FC_TARGET_ADDRESS, NULL);
 	if (++where && err) goto out_fail;
 	err = register_ioctl32_conversion(CPQFCTS_SCSI_PASSTHRU32, sparc32_mptctl_cpq_passthru);
 	if (++where && err) goto out_fail;
+	err = register_ioctl32_conversion(HP_GETHOSTINFO, NULL);
+	if (++where && err) goto out_fail;
+	err = register_ioctl32_conversion(HP_GETTARGETINFO, NULL);
+	if (++where && err) goto out_fail;
 #endif		/*} linux >= 2.3.x */
 #endif		/*} sparc */
 
@@ -3234,10 +3565,12 @@
 	unregister_ioctl32_conversion(MPTCOMMAND32);
 	unregister_ioctl32_conversion(MPTFWDOWNLOAD32);
 	unregister_ioctl32_conversion(CPQFCTS_GETPCIINFO);
-	unregister_ioctl32_conversion(CPQFCTS_GETDRIVER);
+	unregister_ioctl32_conversion(CPQFCTS_GETDRIVVER);
 	unregister_ioctl32_conversion(CPQFCTS_CTLR_STATUS);
 	unregister_ioctl32_conversion(CPQFCTS_SCSI_IOCTL_FC_TARGET_ADDRESS);
 	unregister_ioctl32_conversion(CPQFCTS_SCSI_PASSTHRU32);
+	unregister_ioctl32_conversion(HP_GETHOSTINFO);
+	unregister_ioctl32_conversion(HP_GETTARGETINFO);
 #endif		/*} linux >= 2.3.x */
 #endif		/*} sparc */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/message/fusion/mptctl.h linux-2.4.21-pre6/drivers/message/fusion/mptctl.h
--- linux-2.4.20/drivers/message/fusion/mptctl.h	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/message/fusion/mptctl.h	2003-03-26 23:49:06.000000000 +0000
@@ -20,7 +20,7 @@
  *  (mailto:sjralston1@netscape.net)
  *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptctl.h,v 1.10 2002/05/28 15:57:16 pdelaney Exp $
+ *  $Id: mptctl.h,v 1.12 2002/10/17 20:15:58 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -319,12 +319,12 @@
 #define CPQFCTS_IOC_MAGIC 'Z'
 
 #define CPQFCTS_GETPCIINFO		_IOR(CPQFCTS_IOC_MAGIC, 1, cpqfc_pci_info_struct)
-#define CPQFCTS_GETDRIVER		_IOR(CPQFCTS_IOC_MAGIC, 2, int)
+#define CPQFCTS_GETDRIVVER		_IOR(CPQFCTS_IOC_MAGIC, 9, int)
 #define CPQFCTS_CTLR_STATUS		_IOR(CPQFCTS_IOC_MAGIC, 3, struct _cpqfc_ctlr_status)
-#define CPQFCTS_SCSI_IOCTL_FC_TARGET_ADDRESS	_IOR(CPQFCTS_IOC_MAGIC, 4, struct scsi_fctargaddress)
-#define CPQFCTS_SCSI_PASSTHRU		_IOWR(CPQFCTS_IOC_MAGIC, 5, VENDOR_IOCTL_REQ)
+#define CPQFCTS_SCSI_IOCTL_FC_TARGET_ADDRESS	_IOR(CPQFCTS_IOC_MAGIC, 13, struct scsi_fctargaddress)
+#define CPQFCTS_SCSI_PASSTHRU		_IOWR(CPQFCTS_IOC_MAGIC, 11, VENDOR_IOCTL_REQ)
 #if defined(__sparc__) && defined(__sparc_v9__)
-#define CPQFCTS_SCSI_PASSTHRU32		_IOWR(CPQFCTS_IOC_MAGIC, 5, VENDOR_IOCTL_REQ32)
+#define CPQFCTS_SCSI_PASSTHRU32		_IOWR(CPQFCTS_IOC_MAGIC, 11, VENDOR_IOCTL_REQ32)
 #endif
 
 typedef struct {
@@ -401,6 +401,90 @@
 #endif
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	HP Specific IOCTL Defines and Structures
+ */
+
+#define HP_GETHOSTINFO		_IOR(CPQFCTS_IOC_MAGIC, 20, hp_host_info_t)
+#define HP_GETTARGETINFO	_IOR(CPQFCTS_IOC_MAGIC, 21, hp_target_info_t)
+
+/* All HP IOCTLs must include this header
+ */
+typedef struct _hp_header {
+	unsigned int iocnum;
+	unsigned int host;
+	unsigned int channel;
+	unsigned int id;
+	unsigned int lun;
+} hp_header_t;
+
+/*  
+ *  Header:
+ *  iocnum 	required (input)
+ *  host 	ignored	
+ *  channe	ignored
+ *  id		ignored
+ *  lun		ignored
+ */
+typedef struct _hp_host_info {
+	hp_header_t	 hdr;
+	u16		 vendor;
+	u16		 device;
+	u16		 subsystem_vendor;
+	u16		 subsystem_id;
+	u8		 devfn;
+	u8		 bus;
+	ushort		 host_no;		/* SCSI Host number, if scsi driver not loaded*/
+	u8		 fw_version[16];	/* string */	
+	u8		 serial_number[24];	/* string */
+	u32		 ioc_status;	
+	u32		 bus_phys_width;
+	u32		 base_io_addr;
+	u32		 rsvd;
+	unsigned long	 hard_resets;		/* driver initiated resets */
+	unsigned long	 soft_resets;		/* ioc, external resets */
+	unsigned long	 timeouts;		/* num timeouts */
+} hp_host_info_t;
+
+/*  
+ *  Header:
+ *  iocnum 	required (input)
+ *  host 	required	
+ *  channel	required	(bus number)
+ *  id		required
+ *  lun		ignored
+ *
+ *  All error values between 0 and 0xFFFF in size.
+ */
+typedef struct _hp_target_info {
+	hp_header_t	 hdr;
+	u32 parity_errors;
+	u32 phase_errors;
+	u32 select_timeouts;
+	u32 message_rejects;
+	u32 negotiated_speed;
+	u8  negotiated_width;
+	u8  rsvd[7];				/* 8 byte alignment */
+} hp_target_info_t;
+
+#define HP_STATUS_OTHER		1
+#define HP_STATUS_OK		2
+#define HP_STATUS_FAILED	3
+
+#define HP_BUS_WIDTH_UNK	1
+#define HP_BUS_WIDTH_8		2
+#define HP_BUS_WIDTH_16		3
+#define HP_BUS_WIDTH_32		4
+
+#define HP_DEV_SPEED_ASYNC	2
+#define HP_DEV_SPEED_FAST	3
+#define HP_DEV_SPEED_ULTRA	4
+#define HP_DEV_SPEED_ULTRA2	5
+#define HP_DEV_SPEED_ULTRA160	6
+#define HP_DEV_SPEED_SCSI1	7
+#define HP_DEV_SPEED_ULTRA320	8
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/message/fusion/mptlan.c linux-2.4.21-pre6/drivers/message/fusion/mptlan.c
--- linux-2.4.20/drivers/message/fusion/mptlan.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/message/fusion/mptlan.c	2003-03-26 23:49:39.000000000 +0000
@@ -26,7 +26,7 @@
  *  Copyright (c) 2000-2002 LSI Logic Corporation
  *  Originally By: Noah Romer
  *
- *  $Id: mptlan.c,v 1.52 2002/05/06 13:45:07 sshirron Exp $
+ *  $Id: mptlan.c,v 1.53 2002/10/17 20:15:58 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -132,7 +132,7 @@
 	u32 total_received;
 	struct net_device_stats stats;	/* Per device statistics */
 
-	struct tq_struct post_buckets_task;
+	struct mpt_work_struct post_buckets_task;
 	unsigned long post_buckets_active;
 };
 
@@ -876,10 +876,22 @@
 	
 	if (test_and_set_bit(0, &priv->post_buckets_active) == 0) {
 		if (priority) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,41)
+			schedule_work(&priv->post_buckets_task);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,40)
+			schedule_task(&priv->post_buckets_task);
+#else
 			queue_task(&priv->post_buckets_task, &tq_immediate);
 			mark_bh(IMMEDIATE_BH);
+#endif
 		} else {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,41)
+			schedule_delayed_work(&priv->post_buckets_task, 1);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,40)
+			schedule_task(&priv->post_buckets_task);
+#else
 			queue_task(&priv->post_buckets_task, &tq_timer);
+#endif
 			dioprintk((KERN_INFO MYNAM ": post_buckets queued on "
 				   "timer.\n"));
 		}
@@ -1365,9 +1377,8 @@
 	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;
+	memset(&priv->post_buckets_task, 0, sizeof(struct mpt_work_struct));
+	MPT_INIT_WORK(&priv->post_buckets_task, mpt_lan_post_receive_buckets, dev);
 	priv->post_buckets_active = 0;
 
 	dlprintk((KERN_INFO MYNAM "@%d: bucketlen = %d\n",
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/message/fusion/mptlan.h linux-2.4.21-pre6/drivers/message/fusion/mptlan.h
--- linux-2.4.20/drivers/message/fusion/mptlan.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/message/fusion/mptlan.h	2003-03-26 23:49:25.000000000 +0000
@@ -20,7 +20,12 @@
 #include <linux/slab.h>
 #include <linux/miscdevice.h>
 #include <linux/spinlock.h>
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,41)
 #include <linux/tqueue.h>
+#else
+#include <linux/workqueue.h>
+#endif
 #include <linux/delay.h>
 // #include <linux/trdevice.h>
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/message/fusion/mptscsih.c linux-2.4.21-pre6/drivers/message/fusion/mptscsih.c
--- linux-2.4.20/drivers/message/fusion/mptscsih.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/message/fusion/mptscsih.c	2003-03-26 23:49:30.000000000 +0000
@@ -26,7 +26,7 @@
  *  (mailto:sjralston1@netscape.net)
  *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptscsih.c,v 1.101 2002/09/05 22:30:11 pdelaney Exp $
+ *  $Id: mptscsih.c,v 1.103 2002/10/17 20:15:59 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -110,6 +110,7 @@
 #define MPT_SCANDV_SENSE		(0x00000002)
 #define MPT_SCANDV_SOME_ERROR		(0x00000004)
 #define MPT_SCANDV_SELECTION_TIMEOUT	(0x00000008)
+#define MPT_SCANDV_ISSUE_SENSE		(0x00000010)
 
 #define MPT_SCANDV_MAX_RETRIES		(10)
 
@@ -163,7 +164,6 @@
 static int	mptscsih_getFreeChainBuffer(MPT_SCSI_HOST *hd, int *retIndex);
 static void	mptscsih_freeChainBuffers(MPT_SCSI_HOST *hd, int req_idx);
 static int	mptscsih_initChainBuffers (MPT_SCSI_HOST *hd, int init);
-
 static void	copy_sense_data(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply);
 #ifndef MPT_SCSI_USE_NEW_EH
 static void	search_taskQ_for_cmd(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd);
@@ -182,7 +182,9 @@
 
 static VirtDevice	*mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char *data, int dlen);
 void		mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56);
+#ifdef MPT_SAVE_AUTOSENSE
 static void	clear_sense_flag(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq);
+#endif
 static void	mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq);
 static void	mptscsih_setDevicePage1Flags (u8 width, u8 factor, u8 offset, int *requestedPtr, int *configurationPtr, u8 flags);
 static void	mptscsih_no_negotiate(MPT_SCSI_HOST *hd, int target_id);
@@ -197,8 +199,8 @@
 static int	mptscsih_do_raid(MPT_SCSI_HOST *hd, u8 action, INTERNAL_CMD *io);
 static void	mptscsih_domainValidation(void *hd);
 static int	mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id);
-static void	mptscsih_qas_check(MPT_SCSI_HOST *hd);
-static void	mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int target);
+static void	mptscsih_qas_check(MPT_SCSI_HOST *hd, int id);
+static int	mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int target);
 static void	mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage);
 static void	mptscsih_fillbuf(char *buffer, int size, int index, int width);
 #endif
@@ -243,7 +245,7 @@
  */
 static spinlock_t mytaskQ_lock = SPIN_LOCK_UNLOCKED;
 static int mytaskQ_bh_active = 0;
-static struct tq_struct	mptscsih_ptaskfoo;
+static struct mpt_work_struct	mptscsih_ptaskfoo;
 static atomic_t	mpt_taskQdepth;
 #endif
 
@@ -254,7 +256,7 @@
 static spinlock_t dvtaskQ_lock = SPIN_LOCK_UNLOCKED;
 static int dvtaskQ_active = 0;
 static int dvtaskQ_release = 0;
-static struct tq_struct	mptscsih_dvTask;
+static struct mpt_work_struct	mptscsih_dvTask;
 #endif
 
 /*
@@ -332,14 +334,6 @@
 	pScsiReq = (SCSIIORequest_t *) mf;
 	pScsiReply = (SCSIIOReply_t *) mr;
 
-#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
-	if (hd->is_spi) {
-		u32 qtag = le32_to_cpu(pScsiReq->Control);
-		if (qtag & MPI_SCSIIO_CONTROL_UNTAGGED)
-			hd->ioc->spi_data.iocntr[sc->target]--;
-	}
-#endif
-
 	if (pScsiReply == NULL) {
 		/* special context reply handling */
 
@@ -358,7 +352,9 @@
 						dlen);
 			}
 		}
+#ifdef MPT_SAVE_AUTOSENSE
 		clear_sense_flag(hd, pScsiReq);
+#endif
 	} else {
 		u32	 xfer_cnt;
 		u16	 status;
@@ -443,17 +439,21 @@
 			 *  precedence!
 			 */
 			sc->result = (DID_OK << 16) | pScsiReply->SCSIStatus;
+#ifdef MPT_SAVE_AUTOSENSE
 			clear_sense_flag(hd, pScsiReq);
-			if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
+#endif
+			if (scsi_state == 0) {
+				;
+			} else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
 				/* Have already saved the status and sense data
 				 */
 				;
-			} else if (pScsiReply->SCSIState & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
+			} else if (scsi_state & (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) {
+			else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
 				/*  Not real sure here either...  */
 				sc->result = DID_RESET << 16;
 			}
@@ -494,9 +494,12 @@
 		case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:	/* 0x0040 */
 		case MPI_IOCSTATUS_SUCCESS:			/* 0x0000 */
 			sc->result = (DID_OK << 16) | pScsiReply->SCSIStatus;
+#ifdef MPT_SAVE_AUTOSENSE
 			clear_sense_flag(hd, pScsiReq);
-
-			if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
+#endif
+			if (scsi_state == 0) {
+				;
+			} else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
 				/*
 				 * If running agains circa 200003dd 909 MPT f/w,
 				 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
@@ -527,7 +530,7 @@
 #endif
 
 			}
-			else if (pScsiReply->SCSIState &
+			else if (scsi_state &
 			         (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
 			   ) {
 				/*
@@ -535,11 +538,11 @@
 				 */
 				sc->result = DID_SOFT_ERROR << 16;
 			}
-			else if (pScsiReply->SCSIState & MPI_SCSI_STATE_TERMINATED) {
+			else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
 				/*  Not real sure here either...  */
 				sc->result = DID_RESET << 16;
 			}
-			else if (pScsiReply->SCSIState & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
+			else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
 				/* Device Inq. data indicates that it supports
 				 * QTags, but rejects QTag messages.
 				 * This command completed OK.
@@ -946,11 +949,6 @@
 			mpt_free_msg_frame(ScsiDoneCtx, hd->ioc->id, mf);
 		}
 	}
-#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
-	/* Clear untagged counting array */
-	for (ii= 0; ii < MPT_MAX_SCSI_DEVICES; ii++)
-		hd->ioc->spi_data.iocntr[ii] = 0;
-#endif
 
 	return;
 }
@@ -1035,21 +1033,13 @@
 	MPT_FRAME_HDR	*chain;
 	u8		*mem;
 	unsigned long	flags;
-	int		sz, ii, numChain;
-
+	int		sz, ii, num_chain;
+	int 		scale, num_sge;
 
-        /* Chain buffer allocations
-	 * Allocate and initialize tracker structures
+	/* ReqToChain size must equal the req_depth
+	 * index = req_idx
 	 */
-	if (hd->ioc->req_sz <= 64)
-		numChain = MPT_SG_REQ_64_SCALE * hd->ioc->req_depth;
-	else if (hd->ioc->req_sz <= 96)
-		numChain = MPT_SG_REQ_96_SCALE * hd->ioc->req_depth;
-	else
-		numChain = MPT_SG_REQ_128_SCALE * hd->ioc->req_depth;
-
-	sz = numChain * sizeof(int);
-
+	sz = hd->ioc->req_depth * sizeof(int);
 	if (hd->ReqToChain == NULL) {
 		mem = kmalloc(sz, GFP_ATOMIC);
 		if (mem == NULL)
@@ -1061,6 +1051,38 @@
 	}
 	memset(mem, 0xFF, sz);
 
+
+	/* ChainToChain size must equal the total number
+	 * of chain buffers to be allocated.
+	 * index = chain_idx
+	 *
+	 * Calculate the number of chain buffers needed(plus 1) per I/O 
+	 * then multiply the the maximum number of simultaneous cmds
+	 *
+	 * num_sge = num sge in request frame + last chain buffer
+	 * scale = num sge per chain buffer if no chain element
+	 */
+	scale = hd->ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
+	if (sizeof(dma_addr_t) == sizeof(u64))
+		num_sge =  scale + (hd->ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
+	else
+		num_sge =  1+ scale + (hd->ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
+
+	num_chain = 1;
+	while (hd->max_sge - num_sge > 0) {
+		num_chain++;
+		num_sge += (scale - 1);
+	}
+	num_chain++;
+
+	if ((int) hd->ioc->chip_type > (int) FC929)
+		num_chain *= MPT_SCSI_CAN_QUEUE;
+	else
+		num_chain *= MPT_FC_CAN_QUEUE;
+
+	hd->num_chain = num_chain;
+
+	sz = num_chain * sizeof(int);
 	if (hd->ChainToChain == NULL) {
 		mem = kmalloc(sz, GFP_ATOMIC);
 		if (mem == NULL)
@@ -1072,10 +1094,10 @@
 	}
 	memset(mem, 0xFF, sz);
 
+	sz = num_chain * hd->ioc->req_sz;
 	if (hd->ChainBuffer == NULL) {
 		/* Allocate free chain buffer pool
 		 */
-		sz = numChain * hd->ioc->req_sz;
 		mem = pci_alloc_consistent(hd->ioc->pcidev, sz, &hd->ChainBufferDMA);
 		if (mem == NULL)
 			return -1;
@@ -1101,7 +1123,7 @@
 	/* Post the chain buffers to the FreeChainQ.
 	 */
 	mem = (u8 *)hd->ChainBuffer;
-	for (ii=0; ii < numChain; ii++) {
+	for (ii=0; ii < num_chain; ii++) {
 		chain = (MPT_FRAME_HDR *) mem;
 		Q_ADD_TAIL(&hd->FreeChainQ.head, &chain->u.frame.linkage, MPT_FRAME_HDR);
 		mem += hd->ioc->req_sz;
@@ -1238,8 +1260,7 @@
 #endif
 			sh = scsi_register(tpnt, sizeof(MPT_SCSI_HOST));
 			if (sh != NULL) {
-				save_flags(flags);
-				cli();
+				mptscsih_lock(this, flags);
 				sh->io_port = 0;
 				sh->n_io_port = 0;
 				sh->irq = 0;
@@ -1266,12 +1287,21 @@
 				}
 				sh->max_lun = MPT_LAST_LUN + 1;
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)
+				sh->max_sectors = MPT_SCSI_MAX_SECTORS;
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,1) || defined CONFIG_HIGHIO
+				sh->highmem_io = 1;
+#endif
 				sh->this_id = this->pfacts[portnum].PortSCSIID;
 
 				/* OS entry to allow host drivers to force
 				 * a queue depth on a per device basis.
 				 */
 				sh->select_queue_depths = mptscsih_select_queue_depths;
+				/* Required entry.
+				 */
+				sh->unique_id = this->id;
 
 				/* Verify that we won't exceed the maximum
 				 * number of chain buffers
@@ -1303,10 +1333,11 @@
 				 */
 				scsi_set_pci_device(sh, this->pcidev);
 
-				restore_flags(flags);
+				mptscsih_unlock(this, flags);
 
 				hd = (MPT_SCSI_HOST *) sh->hostdata;
 				hd->ioc = this;
+				hd->max_sge = sh->sg_tablesize;
 
 				if ((int)this->chip_type > (int)FC929)
 					hd->is_spi = 1;
@@ -1546,7 +1577,6 @@
 		int szc2chain = 0;
 		int szchain = 0;
 		int szQ = 0;
-		int scale;
 
 		/* Synchronize disk caches
 		 */
@@ -1554,13 +1584,6 @@
 
 		sz1 = sz2 = sz3 = 0;
 
-		if (hd->ioc->req_sz <= 64)
-			scale = MPT_SG_REQ_64_SCALE;
-		else if (hd->ioc->req_sz <= 96)
-			scale = MPT_SG_REQ_96_SCALE;
-		else
-			scale = MPT_SG_REQ_128_SCALE;
-
 		if (hd->ScsiLookup != NULL) {
 			sz1 = hd->ioc->req_depth * sizeof(void *);
 			kfree(hd->ScsiLookup);
@@ -1568,19 +1591,19 @@
 		}
 
 		if (hd->ReqToChain != NULL) {
-			szr2chain = scale * hd->ioc->req_depth * sizeof(int);
+			szr2chain = hd->ioc->req_depth * sizeof(int);
 			kfree(hd->ReqToChain);
 			hd->ReqToChain = NULL;
 		}
 
 		if (hd->ChainToChain != NULL) {
-			szc2chain = scale * hd->ioc->req_depth * sizeof(int);
+			szc2chain = hd->num_chain * sizeof(int);
 			kfree(hd->ChainToChain);
 			hd->ChainToChain = NULL;
 		}
 
 		if (hd->ChainBuffer != NULL) {
-			sz2 = scale * hd->ioc->req_depth * hd->ioc->req_sz;
+			sz2 = hd->num_chain * hd->ioc->req_sz;
 			szchain = szr2chain + szc2chain + sz2;
 
 			pci_free_consistent(hd->ioc->pcidev, sz2,
@@ -1603,7 +1626,7 @@
 			if (hd->is_spi) {
 				max = MPT_MAX_SCSI_DEVICES;
 			} else {
-				max = MPT_MAX_FC_DEVICES;
+				max = MPT_MAX_FC_DEVICES<256 ? MPT_MAX_FC_DEVICES : 255;
 			}
 			for (ii=0; ii < max; ii++) {
 				if (hd->Targets[ii]) {
@@ -1817,6 +1840,7 @@
 	dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n",
 			(hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done));
 
+#ifdef MPT_SAVE_AUTOSENSE
 	/* 20000617 -sralston
 	 *  GRRRRR...  Shouldn't have to do this but...
 	 *  Do explicit check for REQUEST_SENSE and cached SenseData.
@@ -1852,6 +1876,7 @@
 			}
 		}
 	}
+#endif
 
 	if (hd->resetPending) {
 		/* Prevent new commands from being issued
@@ -2032,9 +2057,7 @@
 					if (!dvtaskQ_active) {
 						dvtaskQ_active = 1;
 						spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
-						mptscsih_dvTask.sync = 0;
-						mptscsih_dvTask.routine = mptscsih_domainValidation;
-						mptscsih_dvTask.data = (void *) hd;
+						MPT_INIT_WORK(&mptscsih_dvTask, mptscsih_domainValidation, (void *) hd); 
 
 						SCHEDULE_TASK(&mptscsih_dvTask);
 					} else {
@@ -2051,9 +2074,6 @@
 					issueCmd = 0;
 				}
 
-				if (qtag == MPI_SCSIIO_CONTROL_UNTAGGED)
-					hd->ioc->spi_data.iocntr[target]++;
-
 				/* Set the DV flags.
 				 */
 				if (dvStatus & MPT_SCSICFG_DV_NOT_DONE)
@@ -2531,6 +2551,8 @@
 
 		/* Isse the Task Mgmt request.
 		 */
+		if (hd->hard_resets < -1)
+			hd->hard_resets++;
 		rc = mptscsih_IssueTaskMgmt(hd, type, target, lun, ctx2abort, sleepFlag);
 		if (rc) {
 #ifdef MPT_SCSI_USE_NEW_EH
@@ -2549,7 +2571,7 @@
 	}
 #endif
 
-	if (rc) {
+	if (rc || ioc->reload_fw || (ioc->alt_ioc && ioc->alt_ioc->reload_fw)) {
 		dtmprintk((MYIOC_s_INFO_FMT "Falling through to HardReset! \n",
 			 hd->ioc->name));
 		rc = mpt_HardResetHandler(hd->ioc, sleepFlag);
@@ -2686,6 +2708,9 @@
 	printk(KERN_WARNING MYNAM ": %s: IOs outstanding = %d\n",
 	       hd->ioc->name, atomic_read(&queue_depth));
 
+	if (hd->timeouts < -1)
+		hd->timeouts++;
+
 	/* Find this command
 	 */
 	if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
@@ -2908,6 +2933,9 @@
 	printk(KERN_WARNING MYNAM ": %s: IOs outstanding = %d\n",
 	       hd->ioc->name, atomic_read(&queue_depth));
 
+	if (hd->timeouts < -1)
+		hd->timeouts++;
+
 	/*  Wait a fixed amount of time for the TM pending flag to be cleared.
 	 *  If we time out, then we return a FAILED status to the caller.  This
 	 *  call to mptscsih_tm_pending_wait() will set the pending flag if we are
@@ -3064,7 +3092,7 @@
 {
 	MPT_SCSI_HOST		*hd;
 	MPT_FRAME_HDR		*mf;
-	struct tq_struct	*ptaskfoo;
+	struct mpt_work_struct	*ptaskfoo;
 	unsigned long		 flags;
 	int			 scpnt_idx;
 
@@ -3078,6 +3106,9 @@
 		return SCSI_ABORT_NOT_RUNNING;
 	}
 
+	if (hd->timeouts < -1)
+		hd->timeouts++;
+
 	if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
 		/* Cmd not found in ScsiLookup.
 		 * If found in doneQ, delete from Q.
@@ -3172,10 +3203,8 @@
 		 *  Oh how cute, no alloc/free/mgmt needed if we use
 		 *  (bottom/unused portion of) MPT request frame.
 		 */
-		ptaskfoo = (struct tq_struct *) &mptscsih_ptaskfoo;
-		ptaskfoo->sync = 0;
-		ptaskfoo->routine = mptscsih_taskmgmt_bh;
-		ptaskfoo->data = SCpnt;
+		ptaskfoo = (struct mpt_work_struct *) &mptscsih_ptaskfoo;
+		MPT_INIT_WORK(&mptscsih_ptaskfoo, mptscsih_taskmgmt_bh, (void *) SCpnt); 
 
 		SCHEDULE_TASK(ptaskfoo);
 	} else  {
@@ -3200,7 +3229,7 @@
 {
 	MPT_SCSI_HOST		*hd;
 	MPT_FRAME_HDR		*mf;
-	struct tq_struct	*ptaskfoo;
+	struct mpt_work_struct	*ptaskfoo;
 	unsigned long		 flags;
 	int			 scpnt_idx;
 
@@ -3213,6 +3242,9 @@
 		return SCSI_RESET_SUCCESS;
 	}
 
+	if (hd->timeouts < -1)
+		hd->timeouts++;
+
 	if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
 		/* Cmd not found in ScsiLookup.
 		 * If found in doneQ, delete from Q.
@@ -3302,10 +3334,8 @@
 		 *  Oh how cute, no alloc/free/mgmt needed if we use
 		 *  (bottom/unused portion of) MPT request frame.
 		 */
-		ptaskfoo = (struct tq_struct *) &mptscsih_ptaskfoo;
-		ptaskfoo->sync = 0;
-		ptaskfoo->routine = mptscsih_taskmgmt_bh;
-		ptaskfoo->data = SCpnt;
+		ptaskfoo = (struct mpt_work_struct *) &mptscsih_ptaskfoo;
+		MPT_INIT_WORK(&mptscsih_ptaskfoo, mptscsih_taskmgmt_bh, (void *) SCpnt); 
 
 		SCHEDULE_TASK(ptaskfoo);
 	} else  {
@@ -3626,9 +3656,12 @@
 /*
  *	This is anyones guess quite frankly.
  */
-
 int
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,28)
+mptscsih_bios_param(Disk * disk, struct block_device *dev, int *ip)
+#else
 mptscsih_bios_param(Disk * disk, kdev_t dev, int *ip)
+#endif
 {
 	int size;
 
@@ -3670,7 +3703,7 @@
 			if (hd->is_spi)
 				max = MPT_MAX_SCSI_DEVICES;
 			else
-				max = MPT_MAX_FC_DEVICES;
+				max = MPT_MAX_FC_DEVICES<256 ? MPT_MAX_FC_DEVICES : 255;
 
 			for (ii=0; ii < max; ii++) {
 				pTarget = hd->Targets[ii];
@@ -3816,6 +3849,7 @@
 		/* save sense data to the target device
 		 */
 		if (target) {
+#ifdef MPT_SAVE_AUTOSENSE
 			int sz;
 
 			sz = MIN(pReq->SenseBufferLength, sense_count);
@@ -3823,6 +3857,7 @@
 				sz =  SCSI_STD_SENSE_BYTES;
 			memcpy(target->sense, sense_data, sz);
 			target->tflags |= MPT_TARGET_FLAGS_VALID_SENSE;
+#endif
 
 #ifdef ABORT_FIX
 			if (sz >= SCSI_STD_SENSE_BYTES) {
@@ -4166,10 +4201,12 @@
 		/* FIXME! */
 		break;
 	case MPI_EVENT_IOC_BUS_RESET:			/* 04 */
-		/* FIXME! */
-		break;
 	case MPI_EVENT_EXT_BUS_RESET:			/* 05 */
-		/* FIXME! */
+		hd = NULL;
+		if (ioc->sh)
+			hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+		if (hd && (hd->is_spi) && (hd->soft_resets < -1))
+			hd->soft_resets++;
 		break;
 	case MPI_EVENT_LOGOUT:				/* 09 */
 		/* FIXME! */
@@ -4506,6 +4543,7 @@
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#if 0
 static int dump_sd(char *foo, unsigned char *sd)
 {
 	int snsLen = 8 + SD_Additional_Sense_Length(sd);
@@ -4518,6 +4556,7 @@
 
 	return l;
 }
+#endif
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*  Do ASC/ASCQ lookup/grindage to English readable string(s)  */
@@ -4609,6 +4648,15 @@
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
+ *  SCSI Information Report; desired output format...
+ *---
+SCSI Error: (iocnum:target_id:LUN) Status=02h (CHECK CONDITION)
+  Key=6h (UNIT ATTENTION); FRU=03h
+  ASC/ASCQ=29h/00h, "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED"
+  CDB: 00 00 00 00 00 00 - TestUnitReady
+ *---
+ */
+/*
  *  SCSI Error Report; desired output format...
  *---
 SCSI Error Report =-=-=-=-=-=-=-=-=-=-=-=-=-= (ioc0,scsi0:0)
@@ -4632,6 +4680,22 @@
 	unsigned char	 ascq		= SD_ASCQ(ioop->sensePtr);
 	int		 l;
 
+	/* Change the error logging to only report errors on
+	 * read and write commands. Ignore errors on other commands.
+	 * Should this be configurable via proc?
+	 */
+	switch (ioop->cdbPtr[0]) {
+	case READ_6:
+	case WRITE_6:
+	case READ_10:
+	case WRITE_10:
+	case READ_12:
+	case WRITE_12:
+		break;
+	default:
+		return 0;
+	}
+
 	/*
 	 *  More quiet mode.
 	 *  Filter out common, repetitive, warning-type errors...  like:
@@ -4642,6 +4706,7 @@
 	if (sk == SK_NO_SENSE) {
 		return 0;
 	}
+
 	if (	(sk==SK_UNIT_ATTENTION	&& asc==0x29 && (ascq==0x00 || ascq==0x01))
 	     || (sk==SK_NOT_READY	&& asc==0x04 && (ascq==0x01 || ascq==0x02))
 	     || (sk==SK_ILLEGAL_REQUEST && asc==0x25 && ascq==0x00)
@@ -4696,20 +4761,12 @@
 	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 );
-
+	l = sprintf(foo, "SCSI Error: (%s) Status=%02Xh (%s)\n",
+			  ioop->DevIDStr,
+			  ioop->SCSIStatus,
+			  statstr);
+	l += sprintf(foo+l, " Key=%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 = "";
@@ -4721,11 +4778,11 @@
 				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
+	l += sprintf(foo+l, "\n CDB:");
+	l += dump_cdb(foo+l, ioop->cdbPtr);
+	if (opstr)
+		l += sprintf(foo+l, " - \"%s\"", opstr);
+	l += sprintf(foo+l, "\n");
 
 	PrintF(("%s\n", foo));
 
@@ -4783,14 +4840,16 @@
 	}
 
 	if (vdev) {
-		if (hd->ioc->spi_data.isRaid & (1 << target_id))
+		if (hd->ioc->spi_data.isRaid & (1 << target_id)) {
 			vdev->raidVolume = 1;
-		else
+			ddvtprintk((KERN_INFO "RAID Volume @ id %d\n", target_id));
+		} else
 			vdev->raidVolume = 0;
 	}
 
 	if (vdev && data) {
-		if (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) {
+		if ((!(vdev->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) || 
+		((dlen > 56) && (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_56)))) {
 
 			/* Copy the inquiry data  - if we haven't yet.
 			*/
@@ -4801,9 +4860,10 @@
 
 			/* Update the target capabilities
 			 */
-			if (dlen > 56)
+			if (dlen > 56) {
 				mptscsih_setTargetNegoParms(hd, vdev, data[56]);
-			else
+				vdev->tflags |= MPT_TARGET_FLAGS_VALID_56;
+			} else
 				mptscsih_setTargetNegoParms(hd, vdev, 0);
 
 			/* If LUN 0, tape and have not done DV, set the DV flag.
@@ -4845,6 +4905,8 @@
 	u8 version, nfactor;
 	u8 noQas = 1;
 
+	ddvtprintk((KERN_INFO "set Target: (id %d) byte56 0x%x\n", id, byte56));
+
 	/* Set flags based on Inquiry data
 	 */
 	if (target->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) {
@@ -4863,12 +4925,18 @@
 				 */
 				if ((byte56 & 0x04) == 0)
 					factor = MPT_ULTRA2;
+				else if ((byte56 & 0x03) == 0)
+					factor = MPT_ULTRA160;
 				else
 					factor = MPT_ULTRA320;
 
-				/* bit 1 QAS support, non-raid only
+				/* If RAID, never disable QAS
+				 * else if non RAID, do not disable 
+				 *   QAS if bit 1 is set
+				 * bit 1 QAS support, non-raid only
+				 * bit 0 IU support
 				 */
-				if ((target->raidVolume == 0) && (byte56 & 0x02) != 0)
+				if ((target->raidVolume == 1) || ((byte56 & 0x02) != 0))
 					noQas = 0;
 
 				offset = pspi_data->maxSyncOffset;
@@ -4953,6 +5021,7 @@
 			VirtDevice	*vdev;
 			int ii;
 
+			ddvtprintk((KERN_INFO "Disabling QAS!\n"));
 			pspi_data->noQas = MPT_TARGET_NO_NEGO_QAS;
 			for (ii = 0; ii < id; ii++) {
 				vdev = hd->Targets[id];
@@ -4966,6 +5035,7 @@
 	return;
 }
 
+#ifdef MPT_SAVE_AUTOSENSE
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *  Clear sense valid flag.
@@ -4981,6 +5051,7 @@
 
 	return;
 }
+#endif
 
 /* If DV disabled (negoNvram set to USE_NVARM) or if not LUN 0, return.
  * Else set the NEED_DV flag after Read Capacity Issued (disks) 
@@ -5158,6 +5229,7 @@
 				maxfactor = MPT_ASYNC;
 		}
 
+
 		/* Set the negotiation flags.
 		 */
 		negoFlags = ioc->spi_data.noQas;
@@ -5179,6 +5251,17 @@
 			//negoFlags = MPT_TARGET_NO_NEGO_SYNC;
 		}
 
+#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION
+		/* Force to async and narrow if DV has not been executed
+		 * for this ID
+		 */
+		if ((hd->ioc->spi_data.dvStatus[id] & MPT_SCSICFG_DV_NOT_DONE) != 0) {
+			width = 0;
+			factor = MPT_ASYNC;
+			offset = 0;
+		}
+#endif
+
 		/* If id is not a raid volume, get the updated
 		 * transmission settings from the target structure.
 		 */
@@ -5339,7 +5422,7 @@
  *
  *	Remark: Sets a completion code and (possibly) saves sense data
  *	in the IOC member localReply structure.
- *	Used ONLY for bus scan, DV and other internal commands.
+ *	Used ONLY for DV and other internal commands.
  */
 static int
 mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
@@ -5375,10 +5458,13 @@
 	atomic_dec(&queue_depth);
 
 	hd->pLocal = &hd->localReply;
+	hd->pLocal->scsiStatus = 0;
 
 	/* If target struct exists, clear sense valid flag.
 	 */
+#ifdef MPT_SAVE_AUTOSENSE
 	clear_sense_flag(hd, pReq);
+#endif
 
 	if (mr == NULL) {
 		completionCode = MPT_SCANDV_GOOD;
@@ -5390,7 +5476,7 @@
 
 		status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
 
-		ddvprintk((KERN_NOTICE "  IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
+		ddvtprintk((KERN_NOTICE "  IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
 			     status, pReply->SCSIState, pReply->SCSIStatus,
 			     le32_to_cpu(pReply->IOCLogInfo)));
 
@@ -5430,7 +5516,9 @@
 					completionCode = MPT_SCANDV_SOME_ERROR;
 
 			} else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
+#ifdef MPT_SAVE_AUTOSENSE
 				VirtDevice	*target;
+#endif
 				u8		*sense_data;
 				int		 sz;
 
@@ -5445,25 +5533,33 @@
 							SCSI_STD_SENSE_BYTES);
 				memcpy(hd->pLocal->sense, sense_data, sz);
 
+#ifdef MPT_SAVE_AUTOSENSE
 				target = hd->Targets[pReq->TargetID];
 				if (target) {
 					memcpy(target->sense, sense_data, sz);
 					target->tflags
 						|= MPT_TARGET_FLAGS_VALID_SENSE;
 				}
+#endif
 
 				ddvprintk((KERN_NOTICE "  Check Condition, sense ptr %p\n",
 						sense_data));
-			} else if (pReply->SCSIState & (MPI_SCSI_STATE_AUTOSENSE_FAILED |
-							MPI_SCSI_STATE_NO_SCSI_STATUS)) {
+			} else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
+				if (pReq->CDB[0] == CMD_Inquiry)
+					completionCode = MPT_SCANDV_ISSUE_SENSE;
+				else
+					completionCode = MPT_SCANDV_DID_RESET;
+			}
+			else if (pReply->SCSIState & MPI_SCSI_STATE_NO_SCSI_STATUS)
 				completionCode = MPT_SCANDV_DID_RESET;
-			} else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED) {
+			else if (pReply->SCSIState & MPI_SCSI_STATE_TERMINATED)
 				completionCode = MPT_SCANDV_DID_RESET;
-			} else {
+			else {
 				/* If no error, this will be equivalent
 				 * to MPT_SCANDV_GOOD
 				 */
-				completionCode = (int) pReply->SCSIStatus;
+				completionCode = MPT_SCANDV_GOOD;
+				hd->pLocal->scsiStatus = pReply->SCSIStatus;
 			}
 			break;
 
@@ -5480,7 +5576,7 @@
 
 		}	/* switch(status) */
 
-		ddvprintk((KERN_NOTICE "  completionCode set to %08xh\n",
+		ddvtprintk((KERN_NOTICE "  completionCode set to %08xh\n",
 				completionCode));
 	} /* end of address reply case */
 
@@ -5703,6 +5799,14 @@
 		cmdTimeout = 15;
 		break;
 
+	case CMD_RequestSense:
+		cmdLen = 6;
+		CDB[0] = cmd;
+		CDB[4] = io->size;
+		dir = MPI_SCSIIO_CONTROL_READ;
+		cmdTimeout = 10;
+		break;
+
 	case CMD_ReadBuffer:
 		cmdLen = 10;
 		dir = MPI_SCSIIO_CONTROL_READ;
@@ -5807,6 +5911,12 @@
 	else
 		pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
 
+	if (cmd == CMD_RequestSense) {
+		pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
+		ddvprintk((MYIOC_s_INFO_FMT "Untagged! 0x%2x\n",
+			hd->ioc->name, cmd));
+	}
+
 	for (ii=0; ii < 16; ii++)
 		pScsiReq->CDB[ii] = CDB[ii];
 
@@ -5988,7 +6098,7 @@
 		/* If target Ptr NULL or if this target is NOT a disk, skip.
 		 */
 	//	if (pTarget && ((pTarget->inq_data[0] & 0x1F) == 0)) {
-		if (pTarget) {
+		if ((pTarget) && (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)){
 			for (lun=0; lun <= MPT_LAST_LUN; lun++) {
 				/* If LUN present, issue the command
 				 */
@@ -6093,25 +6203,8 @@
 				dvStatus = hd->ioc->spi_data.dvStatus[id];
 
 				if (dvStatus & MPT_SCSICFG_NEED_DV) {
-					VirtDevice *pTarget = hd->Targets[id];
 					did++;
-					if (pTarget && ((pTarget->tflags & MPT_TARGET_FLAGS_Q_YES) == 0)){
-						if (hd->ioc->spi_data.iocntr[id] == 0) {
-							hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_DV_PENDING;
-						} else {
-							/* Wait until not busy
-							 */
-							ddvtprintk((MYIOC_s_NOTE_FMT 
-							" DV Wait: %d untagged and busy. cntr %d\n",
-							ioc->name, id, 
-							hd->ioc->spi_data.iocntr[id]));
-							continue;
-						}
-					} else {
-						hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_DV_PENDING;
-					}
-
-
+					hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_DV_PENDING;
 					hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_NEED_DV;
 
 					set_current_state(TASK_INTERRUPTIBLE);
@@ -6130,9 +6223,16 @@
 						}
 					}
 
-					mptscsih_doDv(hd, 0, id);
-
-					hd->ioc->spi_data.dvStatus[id] &= ~(MPT_SCSICFG_DV_NOT_DONE | MPT_SCSICFG_DV_PENDING);
+					if (mptscsih_doDv(hd, 0, id) == 1) {
+						/* Untagged device was busy, try again
+						 */
+						hd->ioc->spi_data.dvStatus[id] |= MPT_SCSICFG_NEED_DV;
+						hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_DV_PENDING;
+					} else {
+						/* DV is complete. Clear flags.
+						 */
+						hd->ioc->spi_data.dvStatus[id] &= ~(MPT_SCSICFG_DV_NOT_DONE | MPT_SCSICFG_DV_PENDING);
+					}
 
 					if (isPhysDisk) {
 						for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
@@ -6148,7 +6248,7 @@
 					post_pendingQ_commands(hd);
 
 					if (hd->ioc->spi_data.noQas)
-						mptscsih_qas_check(hd);
+						mptscsih_qas_check(hd, id);
 				}
 			}
 		}
@@ -6182,7 +6282,7 @@
 
 /* Write SDP1 if no QAS has been enabled
  */
-static void mptscsih_qas_check(MPT_SCSI_HOST *hd)
+static void mptscsih_qas_check(MPT_SCSI_HOST *hd, int id)
 {
 	VirtDevice *pTarget = NULL;
 	int ii;
@@ -6191,6 +6291,9 @@
 		return;
 
 	for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
+		if (ii == id)
+			continue;
+
 		if ((hd->ioc->spi_data.dvStatus[ii] & MPT_SCSICFG_DV_NOT_DONE) != 0)
 			continue;
 
@@ -6231,7 +6334,7 @@
  *
  *	Return: None.
  */
-static void
+static int
 mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int id)
 {
 	MPT_ADAPTER		*ioc = hd->ioc;
@@ -6259,6 +6362,7 @@
 	int			 notDone;
 	int			 patt;
 	int			 repeat;
+	int			 retcode = 0;
 	char			 firstPass = 1;
 	char			 doFallback = 0;
 	char			 readPage0;
@@ -6266,13 +6370,13 @@
 	char			 inq0 = 0;
 
 	if (ioc->spi_data.sdp1length == 0)
-		return;
+		return 0;
 
 	if (ioc->spi_data.sdp0length == 0)
-		return;
+		return 0;
 
 	if (id == ioc->pfacts[portnum].PortSCSIID)
-		return;
+		return 0;
 
 	lun = 0;
 	bus = 0;
@@ -6292,7 +6396,7 @@
 	dv.cmd = MPT_GET_NVRAM_VALS;
 	mptscsih_dv_parms(hd, &dv, NULL);
 	if ((!dv.max.width) && (!dv.max.offset))
-		return;
+		return 0;
 
 	/* Prep SCSI IO structure
 	 */
@@ -6303,19 +6407,29 @@
 	iocmd.physDiskNum = -1;
 	iocmd.rsvd = iocmd.rsvd2 = 0;
 
-	/* Use tagged commands if possible.
-	 */
 	pTarget = hd->Targets[id];
-	if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES))
-		iocmd.flags |= MPT_ICFLAG_TAGGED_CMD;
-
 	if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) {
 		/* Another GEM workaround. Check peripheral device type,
 		 * if PROCESSOR, quit DV.
 		 */
 		if (((pTarget->inq_data[0] & 0x1F) == 0x03) || ((pTarget->inq_data[0] & 0x1F) > 0x08)) {
 			pTarget->negoFlags |= (MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC);
-			return;
+			return 0;
+		}
+	}
+
+	/* Use tagged commands if possible.
+	 */
+	if (pTarget) {
+		if (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)
+			iocmd.flags |= MPT_ICFLAG_TAGGED_CMD;
+		else {
+			if (hd->ioc->facts.FWVersion.Word < 0x01000600)
+				return 0;
+
+			if ((hd->ioc->facts.FWVersion.Word >= 0x01010000) &&
+				(hd->ioc->facts.FWVersion.Word < 0x01010B00))
+				return 0;
 		}
 	}
 
@@ -6345,7 +6459,7 @@
 
 	pDvBuf = pci_alloc_consistent(ioc->pcidev, dv_alloc, &dvbuf_dma);
 	if (pDvBuf == NULL)
-		return;
+		return 0;
 
 	sz = 0;
 	pbuf1 = (u8 *)pDvBuf;
@@ -6427,8 +6541,10 @@
 	hd->pLocal = NULL;
 	readPage0 = 0;
 	sz = SCSI_STD_INQUIRY_BYTES;
+	rc = MPT_SCANDV_GOOD;
 	while (1) {
 		ddvprintk((MYIOC_s_NOTE_FMT "DV: Start Basic test.\n", ioc->name));
+		retcode = 0;
 		dv.cmd = MPT_SET_MIN;
 		mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
 
@@ -6439,12 +6555,61 @@
 		if (mpt_config(hd->ioc, &cfg) != 0)
 			goto target_done;
 
+		/* Wide - narrow - wide workaround case
+		 */
+		if ((rc == MPT_SCANDV_ISSUE_SENSE) && dv.max.width) { 
+			/* Send an untagged command to reset disk Qs corrupted
+			 * when a parity error occurs on a Request Sense.
+			 */
+			if ((hd->ioc->facts.FWVersion.Word >= 0x01000600) || 
+				((hd->ioc->facts.FWVersion.Word >= 0x01010000) &&
+				(hd->ioc->facts.FWVersion.Word < 0x01010B00)) ) {
+
+				iocmd.cmd = CMD_RequestSense;
+				iocmd.data_dma = buf1_dma;
+				iocmd.data = pbuf1;
+				iocmd.size = 0x12;
+				if (mptscsih_do_cmd(hd, &iocmd) < 0)
+					goto target_done;
+				else {
+					if (hd->pLocal == NULL)
+						goto target_done;
+					rc = hd->pLocal->completion;
+					if ((rc == MPT_SCANDV_GOOD) || (rc == MPT_SCANDV_SENSE)) {
+						dv.max.width = 0;
+						doFallback = 0;
+					} else
+						goto target_done;
+				}
+			} else
+				goto target_done;
+		}
+
 		iocmd.cmd = CMD_Inquiry;
 		iocmd.data_dma = buf1_dma;
 		iocmd.data = pbuf1;
 		iocmd.size = sz;
 		if (mptscsih_do_cmd(hd, &iocmd) < 0)
 			goto target_done;
+		else {
+			if (hd->pLocal == NULL)
+				goto target_done;
+			rc = hd->pLocal->completion;
+			if (rc == MPT_SCANDV_GOOD) {
+				if (hd->pLocal->scsiStatus == STS_BUSY) {
+					retcode = 1;
+					goto target_done;
+				}
+			} else if  (rc == MPT_SCANDV_SENSE) {
+				;
+			} else {
+				/* If first command doesn't complete
+				 * with a good status or with a check condition,
+				 * exit.
+				 */
+				goto target_done;
+			}
+		}
 
 		/* Another GEM workaround. Check peripheral device type,
 		 * if PROCESSOR, quit DV.
@@ -6528,7 +6693,9 @@
 				}
 
 
-			} else if ((rc == MPT_SCANDV_DID_RESET) || (rc == MPT_SCANDV_SENSE))
+			} else if (rc == MPT_SCANDV_ISSUE_SENSE) 
+				doFallback = 1;	/* set fallback flag */
+			else if ((rc == MPT_SCANDV_DID_RESET) || (rc == MPT_SCANDV_SENSE))
 				doFallback = 1;	/* set fallback flag */
 			else
 				goto target_done;
@@ -6951,8 +7118,7 @@
 
 	/* Set if cfg1_dma_addr contents is valid
 	 */
-	if (cfg.hdr != NULL) {
-
+	if ((cfg.hdr != NULL) && (retcode == 0)){
 		/* If disk, not U320, disable QAS
 		 */
 		if ((inq0 == 0) && (dv.now.factor > MPT_ULTRA320))
@@ -6961,6 +7127,10 @@
 		dv.cmd = MPT_SAVE;
 		mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data);
 
+#if 0	
+	/* Double writes to SDP1 can cause problems, 
+	 * skip here since unnecessary
+	 */
 		/* Save the final negotiated settings to
 		 * SCSI device page 1.
 		 */
@@ -6969,13 +7139,14 @@
 		cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
 		cfg.dir = 1;
 		mpt_config(hd->ioc, &cfg);
+#endif
 	}
 
 	/* If this is a RAID Passthrough, enable internal IOs
 	 */
 	if (iocmd.flags & MPT_ICFLAG_PHYS_DISK) {
 		if (mptscsih_do_raid(hd, MPI_RAID_ACTION_ENABLE_PHYS_IO, &iocmd) < 0)
-			ddvprintk((MYIOC_s_ERR_FMT "RAID Queisce FAILED!\n", ioc->name));
+			ddvprintk((MYIOC_s_ERR_FMT "RAID Enable FAILED!\n", ioc->name));
 	}
 
 	/* Done with the DV scan of the current target
@@ -6986,7 +7157,7 @@
 	ddvtprintk((MYIOC_s_INFO_FMT "DV Done. IOs outstanding = %d\n",
 			ioc->name, atomic_read(&queue_depth)));
 
-	return;
+	return retcode;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -7129,8 +7300,7 @@
 			pPage1->Configuration = le32_to_cpu(configuration);
 		}
 		ddvprintk(("width %d, factor %x, offset %x request %x config %x\n",
-				dv->now.width, dv->now.factor,
-				dv->now.offset, val, configuration));
+				width, factor, offset, val, configuration));
 		break;
 
 	case MPT_FALLBACK:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/message/fusion/mptscsih.h linux-2.4.21-pre6/drivers/message/fusion/mptscsih.h
--- linux-2.4.20/drivers/message/fusion/mptscsih.h	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/message/fusion/mptscsih.h	2003-03-26 23:49:55.000000000 +0000
@@ -20,7 +20,7 @@
  *  (mailto:netscape.net)
  *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptscsih.h,v 1.18 2002/06/06 15:32:52 pdelaney Exp $
+ *  $Id: mptscsih.h,v 1.20 2002/10/17 20:16:00 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -77,7 +77,22 @@
 #define MPT_SCSI_CAN_QUEUE	MPT_FC_CAN_QUEUE
 #define MPT_SCSI_CMD_PER_LUN	 7
 
+#define MPT_SCSI_MAX_SECTORS    8192
+
+/*
+ * Set the MAX_SGE value based on user input.
+ */
+#ifdef  CONFIG_FUSION_MAX_SGE
+#if     CONFIG_FUSION_MAX_SGE  < 16
+#define MPT_SCSI_SG_DEPTH	16
+#elif   CONFIG_FUSION_MAX_SGE  > 128
+#define MPT_SCSI_SG_DEPTH	128
+#else
+#define MPT_SCSI_SG_DEPTH	CONFIG_FUSION_MAX_SGE
+#endif
+#else
 #define MPT_SCSI_SG_DEPTH	40
+#endif
 
 /* To disable domain validation, uncomment the
  * following line. No effect for FC devices.
@@ -146,13 +161,25 @@
 /*
  *	tq_scheduler disappeared @ lk-2.4.0-test12
  *	(right when <linux/sched.h> newly defined TQ_ACTIVE)
+ *	tq_struct reworked in 2.5.41. Include workqueue.h.
  */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,41)
+#	include <linux/sched.h>
+#	include <linux/workqueue.h>
+#define SCHEDULE_TASK(x)		\
+	if (schedule_work(x) == 0) {	\
+		/*MOD_DEC_USE_COUNT*/;	\
+	}
+#else
 #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
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,40)
+#		undef HAVE_TQ_SCHED
+#endif
 #endif
 #ifdef HAVE_TQ_SCHED
 #define SCHEDULE_TASK(x)		\
@@ -166,6 +193,7 @@
 		/*MOD_DEC_USE_COUNT*/;	\
 	}
 #endif
+#endif
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
@@ -201,7 +229,11 @@
 extern	int		 x_scsi_old_abort(Scsi_Cmnd *);
 extern	int		 x_scsi_old_reset(Scsi_Cmnd *, unsigned int);
 #endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,28)
+extern	int		 x_scsi_bios_param(Disk *, struct block_device *, int *);
+#else
 extern	int		 x_scsi_bios_param(Disk *, kdev_t, int *);
+#endif
 extern	void		 x_scsi_select_queue_depths(struct Scsi_Host *, Scsi_Device *);
 extern	void		 x_scsi_taskmgmt_bh(void *);
 
@@ -233,6 +265,7 @@
 	can_queue:			MPT_SCSI_CAN_QUEUE,	\
 	this_id:			-1,			\
 	sg_tablesize:			MPT_SCSI_SG_DEPTH,	\
+	max_sectors:			MPT_SCSI_MAX_SECTORS,   \
 	cmd_per_lun:			MPT_SCSI_CMD_PER_LUN,	\
 	unchecked_isa_dma:		0,			\
 	use_clustering:			ENABLE_CLUSTERING,	\
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/message/i2o/i2o_config.c linux-2.4.21-pre6/drivers/message/i2o/i2o_config.c
--- linux-2.4.20/drivers/message/i2o/i2o_config.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/message/i2o/i2o_config.c	2003-03-26 23:49:54.000000000 +0000
@@ -918,7 +918,7 @@
 		printk(KERN_ERR "i2o_config: no memory for page buffer.\n");
 		return -ENOBUFS;
 	}
-	if(misc_register(&i2o_miscdev)==-1)
+	if(misc_register(&i2o_miscdev) < 0)
 	{
 		printk(KERN_ERR "i2o_config: can't register device.\n");
 		kfree(page_buf);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/Config.in linux-2.4.21-pre6/drivers/mtd/Config.in
--- linux-2.4.20/drivers/mtd/Config.in	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/Config.in	2003-03-26 23:49:08.000000000 +0000
@@ -1,5 +1,5 @@
 
-# $Id: Config.in,v 1.73 2002/03/08 16:34:35 rkaiser Exp $
+# $Id: Config.in,v 1.74 2002/04/23 13:52:14 mag Exp $
 
 mainmenu_option next_comment
 comment 'Memory Technology Devices (MTD)'
@@ -14,8 +14,8 @@
    dep_tristate '  MTD partitioning support' CONFIG_MTD_PARTITIONS $CONFIG_MTD
    dep_tristate '  MTD concatenating support' CONFIG_MTD_CONCAT $CONFIG_MTD
    dep_tristate '  RedBoot partition table parsing' CONFIG_MTD_REDBOOT_PARTS $CONFIG_MTD_PARTITIONS
+   dep_tristate '  Command line partition table parsing' CONFIG_MTD_CMDLINE_PARTS $CONFIG_MTD_PARTITIONS
    if [ "$CONFIG_ARM" = "y" ]; then
-      dep_tristate '  Compaq bootldr partition table parsing' CONFIG_MTD_BOOTLDR_PARTS $CONFIG_MTD_PARTITIONS
       dep_tristate '  ARM Firmware Suite partition parsing' CONFIG_MTD_AFS_PARTS $CONFIG_MTD_PARTITIONS
    fi
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/Makefile linux-2.4.21-pre6/drivers/mtd/Makefile
--- linux-2.4.20/drivers/mtd/Makefile	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/Makefile	2003-03-26 23:49:34.000000000 +0000
@@ -19,7 +19,7 @@
 
 O_TARGET	:= mtdlink.o
 
-export-objs	:= mtdcore.o mtdpart.o redboot.o bootldr.o afs.o mtdconcat.o
+export-objs	:= mtdcore.o mtdpart.o redboot.o cmdlinepart.o afs.o mtdconcat.o
 list-multi	:= nftl.o
 
 mod-subdirs	:= 
@@ -44,10 +44,10 @@
 
 # Core functionality.
 obj-$(CONFIG_MTD)		+= mtdcore.o
-obj-$(CONFIG_MTD_CONCAT)		+= mtdconcat.o
+obj-$(CONFIG_MTD_CONCAT)	+= mtdconcat.o
 obj-$(CONFIG_MTD_PARTITIONS)	+= mtdpart.o
 obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
-obj-$(CONFIG_MTD_BOOTLDR_PARTS) += bootldr.o
+obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o
 obj-$(CONFIG_MTD_AFS_PARTS)	+= afs.o
 
 # 'Users' - code which presents functionality to userspace.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/afs.c linux-2.4.21-pre6/drivers/mtd/afs.c
--- linux-2.4.20/drivers/mtd/afs.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/afs.c	2003-03-26 23:49:54.000000000 +0000
@@ -21,7 +21,7 @@
    This is access code for flashes using ARM's flash partitioning 
    standards.
 
-   $Id: afs.c,v 1.7 2001/11/01 20:04:54 rmk Exp $
+   $Id: afs.c,v 1.8 2002/05/04 08:49:09 rmk Exp $
 
 ======================================================================*/
 
@@ -169,6 +169,7 @@
 	if (!parts)
 		return -ENOMEM;
 
+	memset(parts, 0, sz);
 	str = (char *)(parts + idx);
 
 	/*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/bootldr.c linux-2.4.21-pre6/drivers/mtd/bootldr.c
--- linux-2.4.20/drivers/mtd/bootldr.c	2001-10-04 22:14:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/bootldr.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,214 +0,0 @@
-/*
- * Read flash partition table from Compaq Bootloader
- *
- * Copyright 2001 Compaq Computer Corporation.
- *
- * $Id: bootldr.c,v 1.6 2001/10/02 15:05:11 dwmw2 Exp $
- *
- * Use consistent with the GNU GPL is permitted,
- * provided that this copyright notice is
- * preserved in its entirety in all copies and derived works.
- *
- * COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
- * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
- * FITNESS FOR ANY PARTICULAR PURPOSE.
- *
- */
-
-/*
- * Maintainer: Jamey Hicks (jamey.hicks@compaq.com)
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/partitions.h>
-#include <asm/setup.h>
-#include <linux/bootmem.h>
-
-#define FLASH_PARTITION_NAMELEN 32
-enum LFR_FLAGS {
-   LFR_SIZE_PREFIX = 1,		/* prefix data with 4-byte size */
-   LFR_PATCH_BOOTLDR = 2,	/* patch bootloader's 0th instruction */
-   LFR_KERNEL = 4,		/* add BOOTIMG_MAGIC, imgsize and VKERNEL_BASE to head of programmed region (see bootldr.c) */
-   LFR_EXPAND = 8               /* expand partition size to fit rest of flash */
-};
-
-// the tags are parsed too early to malloc or alloc_bootmem so we'll fix it
-// for now
-#define MAX_NUM_PARTITIONS 8
-typedef struct FlashRegion {
-   char name[FLASH_PARTITION_NAMELEN];
-   unsigned long base;
-   unsigned long size;
-   enum LFR_FLAGS flags;
-} FlashRegion;
-
-typedef struct BootldrFlashPartitionTable {
-  int magic; /* should be filled with 0x646c7470 (btlp) BOOTLDR_PARTITION_MAGIC */
-  int npartitions;
-  struct FlashRegion partition[8];
-} BootldrFlashPartitionTable;
-
-#define BOOTLDR_MAGIC      0x646c7462        /* btld: marks a valid bootldr image */
-#define BOOTLDR_PARTITION_MAGIC  0x646c7470  /* btlp: marks a valid bootldr partition table in params sector */
-
-#define BOOTLDR_MAGIC_OFFSET 0x20 /* offset 0x20 into the bootldr */
-#define BOOTCAP_OFFSET 0X30 /* offset 0x30 into the bootldr */
-
-#define BOOTCAP_WAKEUP	(1<<0)
-#define BOOTCAP_PARTITIONS (1<<1) /* partition table stored in params sector */
-#define BOOTCAP_PARAMS_AFTER_BOOTLDR (1<<2) /* params sector right after bootldr sector(s), else in last sector */
-
-static struct BootldrFlashPartitionTable Table;
-static struct BootldrFlashPartitionTable *partition_table = NULL;
-
-
-int parse_bootldr_partitions(struct mtd_info *master, struct mtd_partition **pparts)
-{
-	struct mtd_partition *parts;
-	int ret, retlen, i;
-	int npartitions = 0;
-	long partition_table_offset;
-	long bootmagic = 0;
-	long bootcap = 0;
-	int namelen = 0;
-
-	char *names; 
-
-#if 0
-	/* verify bootldr magic */
-	ret = master->read(master, BOOTLDR_MAGIC_OFFSET, sizeof(long), &retlen, (void *)&bootmagic);
-	if (ret) 
-		goto out;
-        if (bootmagic != BOOTLDR_MAGIC)
-                goto out;
-	/* see if bootldr supports partition tables and where to find the partition table */
-	ret = master->read(master, BOOTCAP_OFFSET, sizeof(long), &retlen, (void *)&bootcap);
-	if (ret) 
-		goto out;
-
-	if (!(bootcap & BOOTCAP_PARTITIONS))
-		goto out;
-	if (bootcap & BOOTCAP_PARAMS_AFTER_BOOTLDR)
-		partition_table_offset = master->erasesize;
-	else
-		partition_table_offset = master->size - master->erasesize;
-
-	printk(__FUNCTION__ ": partition_table_offset=%#lx\n", partition_table_offset);
-	printk(__FUNCTION__ ": ptable_addr=%#lx\n", ptable_addr);
-
-
-	/* Read the partition table */
-	partition_table = (struct BootldrFlashPartitionTable *)kmalloc(PAGE_SIZE, GFP_KERNEL);
-	if (!partition_table)
-		return -ENOMEM;
-
-	ret = master->read(master, partition_table_offset,
-			   PAGE_SIZE, &retlen, (void *)partition_table);
-	if (ret)
-	    goto out;
-
-#endif
-	if (!partition_table)
-	    return -ENOMEM;
-
-	
-	printk(__FUNCTION__ ": magic=%#x\n", partition_table->magic);
-	printk(__FUNCTION__ ": numPartitions=%#x\n", partition_table->npartitions);
-
-
-	/* check for partition table magic number */
-	if (partition_table->magic != BOOTLDR_PARTITION_MAGIC) 
-		goto out;
-	npartitions = (partition_table->npartitions > MAX_NUM_PARTITIONS)?
-	    MAX_NUM_PARTITIONS:partition_table->npartitions;	
-
-	printk(__FUNCTION__ ": npartitions=%#x\n", npartitions);
-
-	for (i = 0; i < npartitions; i++) {
-		namelen += strlen(partition_table->partition[i].name) + 1;
-	}
-
-	parts = kmalloc(sizeof(*parts)*npartitions + namelen, GFP_KERNEL);
-	if (!parts) {
-		ret = -ENOMEM;
-		goto out;
-	}
-	names = (char *)&parts[npartitions];
-	memset(parts, 0, sizeof(*parts)*npartitions + namelen);
-
-
-
-	// from here we use the partition table
-	for (i = 0; i < npartitions; i++) {
-                struct FlashRegion *partition = &partition_table->partition[i];
-		const char *name = partition->name;
-		parts[i].name = names;
-		names += strlen(name) + 1;
-		strcpy(parts[i].name, name);
-
-                if (partition->flags & LFR_EXPAND)
-                        parts[i].size = MTDPART_SIZ_FULL;
-                else
-                        parts[i].size = partition->size;
-		parts[i].offset = partition->base;
-		parts[i].mask_flags = 0;
-		
-		printk("        partition %s o=%x s=%x\n", 
-		       parts[i].name, parts[i].offset, parts[i].size);
-
-	}
-
-	ret = npartitions;
-	*pparts = parts;
-
- out:
-#if 0
-	if (partition_table)
-		kfree(partition_table);
-#endif
-	
-	return ret;
-}
-
-
-static int __init parse_tag_ptable(const struct tag *tag)
-{
-    char buf[128];
-    int i;
-    int j;
-    
-    partition_table = &Table;
-
-#ifdef CONFIG_DEBUG_LL    
-    sprintf(buf,"ptable: magic = = 0x%lx  npartitions= %d \n",
-	    tag->u.ptable.magic,tag->u.ptable.npartitions);
-    printascii(buf);
-    
-    for (i=0; i<tag->u.ptable.npartitions; i++){
-	sprintf(buf,"ptable: partition name = %s base= 0x%lx  size= 0x%lx flags= 0x%lx\n",
-	    (char *) (&tag->u.ptable.partition[i].name[0]),
-		tag->u.ptable.partition[i].base,
-		tag->u.ptable.partition[i].size,
-		tag->u.ptable.partition[i].flags);
-	printascii(buf);
-    }
-#endif
-
-    memcpy((void *)partition_table,(void *) (&(tag->u.ptable)),sizeof(partition_table) +
-	sizeof(struct FlashRegion)*tag->u.ptable.npartitions);
-
-    
-    return 0;
-}
-
-__tagtable(ATAG_PTABLE, parse_tag_ptable);
-
-EXPORT_SYMBOL(parse_bootldr_partitions);
-
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Compaq Computer Corporation");
-MODULE_DESCRIPTION("Parsing code for Compaq bootldr partitions");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/chips/Config.in linux-2.4.21-pre6/drivers/mtd/chips/Config.in
--- linux-2.4.20/drivers/mtd/chips/Config.in	2001-10-04 22:13:18.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/chips/Config.in	2003-03-26 23:49:38.000000000 +0000
@@ -1,19 +1,18 @@
 # drivers/mtd/chips/Config.in
 
-# $Id: Config.in,v 1.12 2001/09/23 15:35:21 dwmw2 Exp $
+# $Id: Config.in,v 1.16 2002/09/03 13:30:43 joern Exp $
 
 mainmenu_option next_comment
 
 comment 'RAM/ROM/Flash chip drivers'
 
 dep_tristate '  Detect flash chips by Common Flash Interface (CFI) probe' CONFIG_MTD_CFI $CONFIG_MTD
-#dep_tristate '  Detect non-CFI Intel-compatible flash chips' CONFIG_MTD_INTELPROBE $CONFIG_MTD
-dep_tristate '  Detect non-CFI AMD/JEDEC-compatible flash chips' CONFIG_MTD_JEDECPROBE $CONFIG_MTD
+dep_tristate '  Detect JEDEC JESD21c compatible flash chips' CONFIG_MTD_JEDECPROBE $CONFIG_MTD
 
-if [ "$CONFIG_MTD_CFI" = "y" -o "$CONFIG_MTD_INTELPROBE" = "y" -o "$CONFIG_MTD_JEDECPROBE" = "y" ]; then
+if [ "$CONFIG_MTD_CFI" = "y" -o "$CONFIG_MTD_JEDECPROBE" = "y" ]; then
    define_bool CONFIG_MTD_GEN_PROBE y
 else
-   if [ "$CONFIG_MTD_CFI" = "m" -o "$CONFIG_MTD_INTELPROBE" = "m" -o "$CONFIG_MTD_JEDECPROBE" = "m" ]; then
+   if [ "$CONFIG_MTD_CFI" = "m" -o "$CONFIG_MTD_JEDECPROBE" = "m" ]; then
       define_bool CONFIG_MTD_GEN_PROBE m
    else
       define_bool CONFIG_MTD_GEN_PROBE n
@@ -31,6 +30,7 @@
        bool '    Support  8-bit buswidth' CONFIG_MTD_CFI_B1
        bool '    Support 16-bit buswidth' CONFIG_MTD_CFI_B2
        bool '    Support 32-bit buswidth' CONFIG_MTD_CFI_B4
+       bool '    Support 64-bit buswidth' CONFIG_MTD_CFI_B8
 	 if [ "$CONFIG_MTD_CFI_B1" = "y" ]; then
 	   define_bool CONFIG_MTD_CFI_I1 y
          else
@@ -38,11 +38,13 @@
 	 fi
        bool '    Support 2-chip flash interleave' CONFIG_MTD_CFI_I2
        bool '    Support 4-chip flash interleave' CONFIG_MTD_CFI_I4
+       bool '    Support 8-chip flash interleave' CONFIG_MTD_CFI_I8
      fi
   fi
 fi
 dep_tristate '  Support for Intel/Sharp flash chips' CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_GEN_PROBE
 dep_tristate '  Support for AMD/Fujitsu flash chips' CONFIG_MTD_CFI_AMDSTD $CONFIG_MTD_GEN_PROBE
+dep_tristate '  Support for ST (Advanced Architecture) flash chips' CONFIG_MTD_CFI_STAA $CONFIG_MTD_GEN_PROBE
 
 dep_tristate '  Support for RAM chips in bus mapping' CONFIG_MTD_RAM $CONFIG_MTD
 dep_tristate '  Support for ROM chips in bus mapping' CONFIG_MTD_ROM $CONFIG_MTD
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/chips/Makefile linux-2.4.21-pre6/drivers/mtd/chips/Makefile
--- linux-2.4.20/drivers/mtd/chips/Makefile	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/chips/Makefile	2003-03-26 23:49:19.000000000 +0000
@@ -17,6 +17,7 @@
 obj-$(CONFIG_MTD)		+= chipreg.o
 obj-$(CONFIG_MTD_AMDSTD)	+= amd_flash.o 
 obj-$(CONFIG_MTD_CFI)		+= cfi_probe.o
+obj-$(CONFIG_MTD_CFI_STAA)	+= cfi_cmdset_0020.o
 obj-$(CONFIG_MTD_CFI_AMDSTD)	+= cfi_cmdset_0002.o
 obj-$(CONFIG_MTD_CFI_INTELEXT)	+= cfi_cmdset_0001.o
 obj-$(CONFIG_MTD_GEN_PROBE)	+= gen_probe.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/chips/amd_flash.c linux-2.4.21-pre6/drivers/mtd/chips/amd_flash.c
--- linux-2.4.20/drivers/mtd/chips/amd_flash.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/chips/amd_flash.c	2003-03-26 23:49:20.000000000 +0000
@@ -3,7 +3,7 @@
  *
  * Author: Jonas Holmberg <jonas.holmberg@axis.com>
  *
- * $Id: amd_flash.c,v 1.17 2002/03/05 17:00:37 jonashg Exp $
+ * $Id: amd_flash.c,v 1.19 2003/01/24 13:30:11 dwmw2 Exp $
  *
  * Copyright (c) 2001 Axis Communications AB
  *
@@ -75,6 +75,7 @@
 /* Fujitsu */
 #define MBM29LV160TE	0x22C4
 #define MBM29LV160BE	0x2249
+#define MBM29LV800BB	0x225B
 
 /* ST - www.st.com */
 #define M29W800T	0x00D7
@@ -560,6 +561,18 @@
 			{ offset: 0x0FC000, erasesize: 0x04000, numblocks:  1 }
 		}
 	}, {
+		mfr_id: MANUFACTURER_FUJITSU,
+		dev_id: MBM29LV800BB,
+		name: "Fujitsu MBM29LV800BB",
+		size: 0x00100000,
+		numeraseregions: 4,
+		regions: {
+			{ offset: 0x000000, erasesize: 0x04000, numblocks:  1 },
+			{ offset: 0x004000, erasesize: 0x02000, numblocks:  2 },
+			{ offset: 0x008000, erasesize: 0x08000, numblocks:  1 },
+			{ offset: 0x010000, erasesize: 0x10000, numblocks: 15 }
+		}
+	}, {
 		mfr_id: MANUFACTURER_ST,
 		dev_id: M29W800T,
 		name: "ST M29W800T",
@@ -913,7 +926,7 @@
 
 	times_left = 500000;
 	while (times_left-- && flash_is_busy(map, adr, private->interleave)) { 
-		if (current->need_resched) {
+		if (need_resched()) {
 			spin_unlock_bh(chip->mutex);
 			schedule();
 			spin_lock_bh(chip->mutex);
@@ -1150,7 +1163,7 @@
 		/* Latency issues. Drop the lock, wait a while and retry */
 		spin_unlock_bh(chip->mutex);
 
-		if (current->need_resched)
+		if (need_resched())
 			schedule();
 		else
 			udelay(1);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/chips/cfi_cmdset_0001.c linux-2.4.21-pre6/drivers/mtd/chips/cfi_cmdset_0001.c
--- linux-2.4.20/drivers/mtd/chips/cfi_cmdset_0001.c	2001-10-04 22:14:59.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/chips/cfi_cmdset_0001.c	2003-03-26 23:49:20.000000000 +0000
@@ -4,7 +4,7 @@
  *
  * (C) 2000 Red Hat. GPL'd
  *
- * $Id: cfi_cmdset_0001.c,v 1.87 2001/10/02 15:05:11 dwmw2 Exp $
+ * $Id: cfi_cmdset_0001.c,v 1.110 2003/01/09 16:57:28 jocke Exp $
  *
  * 
  * 10/10/2000	Nicolas Pitre <nico@cam.org>
@@ -13,6 +13,8 @@
  * 	- scalability vs code size is completely set at compile-time
  * 	  (see include/linux/mtd/cfi.h for selection)
  *	- optimized write buffer method
+ * 02/05/2002	Christopher Hoover <ch@hpl.hp.com>/<ch@murgatroid.com>
+ *	- reworked lock/unlock/erase support for var size flash
  */
 
 #include <linux/module.h>
@@ -30,7 +32,11 @@
 #include <linux/mtd/cfi.h>
 #include <linux/mtd/compatmac.h>
 
+// debugging, turns off buffer write mode #define FORCE_WORD_WRITE
+
 static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
+static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
+static int cfi_intelext_read_fact_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
 static int cfi_intelext_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
 static int cfi_intelext_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
 static int cfi_intelext_erase_varsize(struct mtd_info *, struct erase_info *);
@@ -46,6 +52,11 @@
 
 static struct mtd_info *cfi_intelext_setup (struct map_info *);
 
+static int do_point (struct mtd_info *mtd, loff_t from, size_t len,
+		     size_t *retlen, u_char **mtdbuf);
+static void do_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from,
+			size_t len);
+
 static struct mtd_chip_driver cfi_intelext_chipdrv = {
 	probe: NULL, /* Not usable directly */
 	destroy: cfi_intelext_destroy,
@@ -59,6 +70,7 @@
 #ifdef DEBUG_CFI_FEATURES
 static void cfi_tell_features(struct cfi_pri_intelext *extp)
 {
+	int i;
 	printk("  Feature/Command Support: %4.4X\n", extp->FeatureSupport);
 	printk("     - Chip Erase:         %s\n", extp->FeatureSupport&1?"supported":"unsupported");
 	printk("     - Suspend Erase:      %s\n", extp->FeatureSupport&2?"supported":"unsupported");
@@ -110,7 +122,7 @@
 	int i;
 	__u32 base = cfi->chips[0].start;
 
-	if (cfi->cfi_mode) {
+	if (cfi->cfi_mode == CFI_MODE_CFI) {
 		/* 
 		 * It's a real CFI chip, not one for which the probe
 		 * routine faked a CFI structure. So we read the feature
@@ -149,26 +161,34 @@
 		}
 		
 		/* Do some byteswapping if necessary */
-		extp->FeatureSupport = cfi32_to_cpu(extp->FeatureSupport);
-		extp->BlkStatusRegMask = cfi32_to_cpu(extp->BlkStatusRegMask);
-		
+		extp->FeatureSupport = le32_to_cpu(extp->FeatureSupport);
+		extp->BlkStatusRegMask = le16_to_cpu(extp->BlkStatusRegMask);
+		extp->ProtRegAddr = le16_to_cpu(extp->ProtRegAddr);
+			
 #ifdef DEBUG_CFI_FEATURES
 		/* Tell the user about it in lots of lovely detail */
 		cfi_tell_features(extp);
 #endif	
 
+#ifdef DISABLE_ERASE_SUSPEND_ON_WRITE
+/* Enable this if you suspect buggy suspend support */ 
+		if(extp->SuspendCmdSupport & 1)
+			printk(KERN_WARNING "cfi_cmdset_0001: Suspend "
+			       "erase on write disabled.\n");
+		extp->SuspendCmdSupport &= ~1;
+#endif
 		/* Install our own private info structure */
-		cfi->cmdset_priv = extp;
-	}	
+		cfi->cmdset_priv = extp;	
+	}
 
 	for (i=0; i< cfi->numchips; i++) {
-		cfi->chips[i].word_write_time = 128;
-		cfi->chips[i].buffer_write_time = 128;
-		cfi->chips[i].erase_time = 1024;
+		cfi->chips[i].word_write_time = 1<<cfi->cfiq->WordWriteTimeoutTyp;
+		cfi->chips[i].buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp;
+		cfi->chips[i].erase_time = 1<<cfi->cfiq->BlockEraseTimeoutTyp;
+		cfi->chips[i].ref_point_counter = 0;
 	}		
 
 	map->fldrv = &cfi_intelext_chipdrv;
-	MOD_INC_USE_COUNT;
 	
 	/* Make sure it's in read mode */
 	cfi_send_gen_cmd(0xff, 0x55, base, map, cfi, cfi->device_type, NULL);
@@ -188,8 +208,7 @@
 
 	if (!mtd) {
 		printk(KERN_ERR "Failed to allocate memory for MTD device\n");
-		kfree(cfi->cmdset_priv);
-		return NULL;
+		goto setup_err;
 	}
 
 	memset(mtd, 0, sizeof(*mtd));
@@ -202,8 +221,7 @@
 			* mtd->numeraseregions, GFP_KERNEL);
 	if (!mtd->eraseregions) { 
 		printk(KERN_ERR "Failed to allocate memory for MTD erase region info\n");
-		kfree(cfi->cmdset_priv);
-		return NULL;
+		goto setup_err;
 	}
 	
 	for (i=0; i<cfi->cfiq->NumEraseRegions; i++) {
@@ -220,33 +238,43 @@
 			mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum;
 		}
 		offset += (ersize * ernum);
-		}
+	}
 
-		if (offset != devsize) {
-			/* Argh */
-			printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize);
-			kfree(mtd->eraseregions);
-			kfree(cfi->cmdset_priv);
-			return NULL;
-		}
+	if (offset != devsize) {
+		/* Argh */
+		printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize);
+		goto setup_err;
+	}
 
-		for (i=0; i<mtd->numeraseregions;i++){
-			printk(KERN_DEBUG "%d: offset=0x%x,size=0x%x,blocks=%d\n",
-			       i,mtd->eraseregions[i].offset,
-			       mtd->eraseregions[i].erasesize,
-			       mtd->eraseregions[i].numblocks);
-		}
+	for (i=0; i<mtd->numeraseregions;i++){
+		printk(KERN_DEBUG "%d: offset=0x%x,size=0x%x,blocks=%d\n",
+		       i,mtd->eraseregions[i].offset,
+		       mtd->eraseregions[i].erasesize,
+		       mtd->eraseregions[i].numblocks);
+	}
 
 	/* Also select the correct geometry setup too */ 
-		mtd->erase = cfi_intelext_erase_varsize;
+	mtd->erase = cfi_intelext_erase_varsize;
 	mtd->read = cfi_intelext_read;
+
+	if(map->point && map->unpoint){
+		mtd->point = do_point;
+		mtd->unpoint = do_unpoint;
+	}
+
+#ifndef FORCE_WORD_WRITE
 	if ( cfi->cfiq->BufWriteTimeoutTyp ) {
-		//printk(KERN_INFO "Using buffer write method\n" );
+		printk("Using buffer write method\n" );
 		mtd->write = cfi_intelext_write_buffers;
 	} else {
-		//printk(KERN_INFO "Using word write method\n" );
+#else
+	{
+#endif
+		printk("Using word write method\n" );
 		mtd->write = cfi_intelext_write_words;
 	}
+	mtd->read_user_prot_reg = cfi_intelext_read_user_prot_reg;
+	mtd->read_fact_prot_reg = cfi_intelext_read_fact_prot_reg;
 	mtd->sync = cfi_intelext_sync;
 	mtd->lock = cfi_intelext_lock;
 	mtd->unlock = cfi_intelext_unlock;
@@ -257,12 +285,181 @@
 	MOD_INC_USE_COUNT;
 	mtd->name = map->name;
 	return mtd;
+
+ setup_err:
+	if(mtd) {
+		if(mtd->eraseregions)
+			kfree(mtd->eraseregions);
+		kfree(mtd);
+	}
+	kfree(cfi->cmdset_priv);
+	kfree(cfi->cfiq);
+	return NULL;
+}
+
+static int do_point_onechip (struct map_info *map,  struct flchip *chip, loff_t adr, size_t len)
+{
+	cfi_word status, status_OK;
+	unsigned long timeo;
+	DECLARE_WAITQUEUE(wait, current);
+	unsigned long cmd_addr;
+	struct cfi_private *cfi = map->fldrv_priv;
+
+	adr += chip->start;
+
+	/* Ensure cmd read/writes are aligned. */ 
+	cmd_addr = adr & ~(CFIDEV_BUSWIDTH-1); 
+
+	/* Let's determine this according to the interleave only once */
+	status_OK = CMD(0x80);
+
+	timeo = jiffies + HZ;
+ retry:
+	spin_lock(chip->mutex);
+
+	/* Check that the chip's ready to talk to us.
+	 * If it's in FL_ERASING state, suspend it and make it talk now.
+	 */
+	switch (chip->state) {
+
+	case FL_READY:
+	case FL_POINT:
+		break;
+
+	case FL_CFI_QUERY:
+	case FL_JEDEC_QUERY:
+		cfi_write(map, CMD(0x70), cmd_addr);
+		chip->state = FL_STATUS;
+
+	case FL_STATUS:
+		status = cfi_read(map, cmd_addr);
+		if ((status & status_OK) == status_OK) {
+			cfi_write(map, CMD(0xff), cmd_addr);
+			chip->state = FL_READY;
+			break;
+		}
+		
+		/* Urgh. Chip not yet ready to talk to us. */
+		if (time_after(jiffies, timeo)) {
+			spin_unlock(chip->mutex);
+			printk(KERN_ERR "waiting for chip to be ready timed out in read. WSM status = %llx\n", (__u64)status);
+			return -EIO;
+		}
+
+		/* Latency issues. Drop the lock, wait a while and retry */
+		spin_unlock(chip->mutex);
+		cfi_udelay(1);
+		goto retry;
+
+	default:
+		/* Stick ourselves on a wait queue to be woken when
+		   someone changes the status */
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		add_wait_queue(&chip->wq, &wait);
+		spin_unlock(chip->mutex);
+		schedule();
+		remove_wait_queue(&chip->wq, &wait);
+		timeo = jiffies + HZ;
+		goto retry;
+	}
+
+	chip->state = FL_POINT;
+	chip->ref_point_counter++;
+	spin_unlock(chip->mutex);
+	return 0;
+}
+static int do_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	unsigned long ofs;
+	int chipnum;
+	int ret = 0;
+
+	if (from + len > mtd->size)
+		return -EINVAL;
+	
+	*mtdbuf = map->point(map, from, len);
+	if(*mtdbuf == NULL)
+		return -EINVAL; /* can not point this region */
+	*retlen = 0;
+
+	/* Now lock the chip(s) to POINT state */
+
+	/* ofs: offset within the first chip that the first read should start */
+	chipnum = (from >> cfi->chipshift);
+	ofs = from - (chipnum <<  cfi->chipshift);
+
+	while (len) {
+		unsigned long thislen;
+
+		if (chipnum >= cfi->numchips)
+			break;
+
+		if ((len + ofs -1) >> cfi->chipshift)
+			thislen = (1<<cfi->chipshift) - ofs;
+		else
+			thislen = len;
+
+		ret = do_point_onechip(map, &cfi->chips[chipnum], ofs, thislen);
+		if (ret)
+			break;
+
+		*retlen += thislen;
+		len -= thislen;
+		
+		ofs = 0;
+		chipnum++;
+	}
+	return 0;
 }
 
+static void do_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	unsigned long ofs;
+	int chipnum;
+
+	map->unpoint(map, addr, from, len);
+	/* Now unlock the chip(s) POINT state */
+
+	/* ofs: offset within the first chip that the first read should start */
+	chipnum = (from >> cfi->chipshift);
+	ofs = from - (chipnum <<  cfi->chipshift);
+
+	while (len) {
+		unsigned long thislen;
+		struct flchip *chip;
+
+		chip = &cfi->chips[chipnum];
+		if (chipnum >= cfi->numchips)
+			break;
+
+		if ((len + ofs -1) >> cfi->chipshift)
+			thislen = (1<<cfi->chipshift) - ofs;
+		else
+			thislen = len;
+
+		spin_lock(chip->mutex);
+		if(chip->state == FL_POINT){
+			chip->ref_point_counter--;
+			if(chip->ref_point_counter == 0)
+				chip->state = FL_READY;
+		} else
+			printk("Warning: unpoint called on non pointed region\n"); /* Should this give an error? */
+		wake_up(&chip->wq);
+		spin_unlock(chip->mutex);
+
+		len -= thislen;
+		ofs = 0;
+		chipnum++;
+	}
+}
 
 static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
 {
-	__u32 status, status_OK;
+	cfi_word status, status_OK;
 	unsigned long timeo;
 	DECLARE_WAITQUEUE(wait, current);
 	int suspended = 0;
@@ -279,14 +476,15 @@
 
 	timeo = jiffies + HZ;
  retry:
-	spin_lock_bh(chip->mutex);
+	spin_lock(chip->mutex);
 
 	/* Check that the chip's ready to talk to us.
 	 * If it's in FL_ERASING state, suspend it and make it talk now.
 	 */
 	switch (chip->state) {
 	case FL_ERASING:
-		if (!((struct cfi_pri_intelext *)cfi->cmdset_priv)->FeatureSupport & 2)
+		if (!cfi->cmdset_priv ||
+		    !(((struct cfi_pri_intelext *)cfi->cmdset_priv)->FeatureSupport & 2))
 			goto sleep; /* We don't support erase suspend */
 		
 		cfi_write (map, CMD(0xb0), cmd_addr);
@@ -310,15 +508,15 @@
 				/* make sure we're in 'read status' mode */
 				cfi_write(map, CMD(0x70), cmd_addr);
 				chip->state = FL_ERASING;
-				spin_unlock_bh(chip->mutex);
+				spin_unlock(chip->mutex);
 				printk(KERN_ERR "Chip not ready after erase "
-				       "suspended: status = 0x%x\n", status);
+				       "suspended: status = 0x%llx\n", (__u64)status);
 				return -EIO;
 			}
 			
-			spin_unlock_bh(chip->mutex);
+			spin_unlock(chip->mutex);
 			cfi_udelay(1);
-			spin_lock_bh(chip->mutex);
+			spin_lock(chip->mutex);
 		}
 		
 		suspended = 1;
@@ -332,6 +530,7 @@
 #endif
 
 	case FL_READY:
+	case FL_POINT:
 		break;
 
 	case FL_CFI_QUERY:
@@ -349,13 +548,13 @@
 		
 		/* Urgh. Chip not yet ready to talk to us. */
 		if (time_after(jiffies, timeo)) {
-			spin_unlock_bh(chip->mutex);
-			printk(KERN_ERR "waiting for chip to be ready timed out in read. WSM status = %x\n", status);
+			spin_unlock(chip->mutex);
+			printk(KERN_ERR "waiting for chip to be ready timed out in read. WSM status = %llx\n", (__u64)status);
 			return -EIO;
 		}
 
 		/* Latency issues. Drop the lock, wait a while and retry */
-		spin_unlock_bh(chip->mutex);
+		spin_unlock(chip->mutex);
 		cfi_udelay(1);
 		goto retry;
 
@@ -365,7 +564,7 @@
 		   someone changes the status */
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		add_wait_queue(&chip->wq, &wait);
-		spin_unlock_bh(chip->mutex);
+		spin_unlock(chip->mutex);
 		schedule();
 		remove_wait_queue(&chip->wq, &wait);
 		timeo = jiffies + HZ;
@@ -390,7 +589,7 @@
 	}
 
 	wake_up(&chip->wq);
-	spin_unlock_bh(chip->mutex);
+	spin_unlock(chip->mutex);
 	return 0;
 }
 
@@ -433,13 +632,124 @@
 	return ret;
 }
 
-static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, __u32 datum)
+static int cfi_intelext_read_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, int base_offst, int reg_sz)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	struct cfi_pri_intelext *extp=cfi->cmdset_priv;
+	int ofs_factor = cfi->interleave * cfi->device_type;
+	int   count=len;
+	struct flchip *chip;
+	int chip_num,offst;
+	unsigned long timeo;
+	DECLARE_WAITQUEUE(wait, current);
+
+	chip=0;
+	/* Calculate which chip & protection register offset we need */
+	chip_num=((unsigned int)from/reg_sz);
+	offst=from-(reg_sz*chip_num)+base_offst;
+
+	while(count){
+		
+		if(chip_num>=cfi->numchips)
+			goto out;
+
+		/* Make sure that the chip is in the right state */
+
+		timeo = jiffies + HZ;
+		chip=&cfi->chips[chip_num];
+	retry:		
+		spin_lock(chip->mutex);
+	
+		switch (chip->state) {
+		case FL_READY:
+		case FL_STATUS:
+		case FL_CFI_QUERY:
+		case FL_JEDEC_QUERY:
+			break;
+		
+		default:
+				/* Stick ourselves on a wait queue to be woken when
+				   someone changes the status */
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			add_wait_queue(&chip->wq, &wait);
+			spin_unlock(chip->mutex);
+			schedule();
+			remove_wait_queue(&chip->wq, &wait);
+			timeo = jiffies + HZ;
+			goto retry;
+		}
+			
+		/* Now read the data required from this flash */
+       
+		cfi_send_gen_cmd(0x90, 0x55,chip->start, map, cfi, cfi->device_type, NULL);
+		while(count && ((offst-base_offst)<reg_sz)){
+			*buf=map->read8(map,(chip->start+((extp->ProtRegAddr+1)*ofs_factor)+offst));
+			buf++;
+			offst++;
+			count--;
+		}
+	       
+		chip->state=FL_CFI_QUERY;
+		spin_unlock(chip->mutex);
+		/* Move on to the next chip */
+		chip_num++;
+		offst=base_offst;
+	
+	}
+	
+ out:	
+	wake_up(&chip->wq);
+	return len-count;
+}
+	
+static int cfi_intelext_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	struct cfi_pri_intelext *extp=cfi->cmdset_priv;
+	int base_offst,reg_sz;
+	
+	/* Check that we actually have some protection registers */
+	if(!(extp->FeatureSupport&64)){
+		printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name);
+		return 0;
+	}
+
+	base_offst=(1<<extp->FactProtRegSize);
+	reg_sz=(1<<extp->UserProtRegSize);
+
+	return cfi_intelext_read_prot_reg(mtd, from, len, retlen, buf, base_offst, reg_sz);
+}
+
+static int cfi_intelext_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	struct cfi_pri_intelext *extp=cfi->cmdset_priv;
+	int base_offst,reg_sz;
+	
+	/* Check that we actually have some protection registers */
+	if(!(extp->FeatureSupport&64)){
+		printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name);
+		return 0;
+	}
+
+	base_offst=0;
+	reg_sz=(1<<extp->FactProtRegSize);
+
+	return cfi_intelext_read_prot_reg(mtd, from, len, retlen, buf, base_offst, reg_sz);
+}
+
+
+static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, cfi_word datum)
 {
 	struct cfi_private *cfi = map->fldrv_priv;
-	__u32 status, status_OK;
+	struct cfi_pri_intelext *extp = cfi->cmdset_priv;
+	cfi_word status, status_OK;
 	unsigned long timeo;
 	DECLARE_WAITQUEUE(wait, current);
-	int z;
+	int z, suspended=0, ret=0;
 
 	adr += chip->start;
 
@@ -448,7 +758,7 @@
 
 	timeo = jiffies + HZ;
  retry:
-	spin_lock_bh(chip->mutex);
+	spin_lock(chip->mutex);
 
 	/* Check that the chip's ready to talk to us.
 	 * Later, we can actually think about interrupting it
@@ -471,22 +781,63 @@
 		
 		/* Urgh. Chip not yet ready to talk to us. */
 		if (time_after(jiffies, timeo)) {
-			spin_unlock_bh(chip->mutex);
+			spin_unlock(chip->mutex);
 			printk(KERN_ERR "waiting for chip to be ready timed out in read\n");
 			return -EIO;
 		}
 
 		/* Latency issues. Drop the lock, wait a while and retry */
-		spin_unlock_bh(chip->mutex);
+		spin_unlock(chip->mutex);
 		cfi_udelay(1);
 		goto retry;
 
+	case FL_ERASING:
+		if (!extp || 
+		    !((extp->FeatureSupport & 2) && (extp->SuspendCmdSupport & 1)))
+			goto sleep; /* We don't support erase suspend */
+		
+		cfi_write (map, CMD(0xb0), adr);
+
+		/* If the flash has finished erasing, then 'erase suspend'
+		 * appears to make some (28F320) flash devices switch to
+		 * 'read' mode.  Make sure that we switch to 'read status'
+		 * mode so we get the right data. --rmk
+		 */
+		cfi_write(map, CMD(0x70), adr);
+		chip->oldstate = FL_ERASING;
+		chip->state = FL_ERASE_SUSPENDING;
+		for (;;) {
+			status = cfi_read(map, adr);
+			if ((status & status_OK) == status_OK)
+				break;
+			
+			if (time_after(jiffies, timeo)) {
+				/* Urgh */
+				cfi_write(map, CMD(0xd0), adr);
+				/* make sure we're in 'read status' mode */
+				cfi_write(map, CMD(0x70), adr);
+				chip->state = FL_ERASING;
+				spin_unlock(chip->mutex);
+				printk(KERN_ERR "Chip not ready after erase "
+				       "suspended: status = 0x%x\n", status);
+				return -EIO;
+			}
+			
+			spin_unlock(chip->mutex);
+			cfi_udelay(1);
+			spin_lock(chip->mutex);
+		}
+		suspended = 1;
+		chip->state = FL_STATUS;
+		break;
+
 	default:
+	sleep:
 		/* Stick ourselves on a wait queue to be woken when
 		   someone changes the status */
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		add_wait_queue(&chip->wq, &wait);
-		spin_unlock_bh(chip->mutex);
+		spin_unlock(chip->mutex);
 		schedule();
 		remove_wait_queue(&chip->wq, &wait);
 		timeo = jiffies + HZ;
@@ -498,9 +849,9 @@
 	cfi_write(map, datum, adr);
 	chip->state = FL_WRITING;
 
-	spin_unlock_bh(chip->mutex);
+	spin_unlock(chip->mutex);
 	cfi_udelay(chip->word_write_time);
-	spin_lock_bh(chip->mutex);
+	spin_lock(chip->mutex);
 
 	timeo = jiffies + (HZ/2);
 	z = 0;
@@ -509,11 +860,11 @@
 			/* Someone's suspended the write. Sleep */
 			set_current_state(TASK_UNINTERRUPTIBLE);
 			add_wait_queue(&chip->wq, &wait);
-			spin_unlock_bh(chip->mutex);
+			spin_unlock(chip->mutex);
 			schedule();
 			remove_wait_queue(&chip->wq, &wait);
 			timeo = jiffies + (HZ / 2); /* FIXME */
-			spin_lock_bh(chip->mutex);
+			spin_lock(chip->mutex);
 			continue;
 		}
 
@@ -525,16 +876,16 @@
 		if (time_after(jiffies, timeo)) {
 			chip->state = FL_STATUS;
 			DISABLE_VPP(map);
-			spin_unlock_bh(chip->mutex);
 			printk(KERN_ERR "waiting for chip to be ready timed out in word write\n");
-			return -EIO;
+			ret = -EIO;
+			goto out;
 		}
 
 		/* Latency issues. Drop the lock, wait a while and retry */
-		spin_unlock_bh(chip->mutex);
+		spin_unlock(chip->mutex);
 		z++;
 		cfi_udelay(1);
-		spin_lock_bh(chip->mutex);
+		spin_lock(chip->mutex);
 	}
 	if (!z) {
 		chip->word_write_time--;
@@ -553,13 +904,27 @@
 		cfi_write(map, CMD(0x50), adr);
 		/* put back into read status register mode */
 		cfi_write(map, CMD(0x70), adr);
-		wake_up(&chip->wq);
-		spin_unlock_bh(chip->mutex);
-		return -EROFS;
+		ret = -EROFS;
+		goto out;
+	}
+ out:
+	if (suspended) {
+		chip->state = chip->oldstate;
+		/* What if one interleaved chip has finished and the 
+		   other hasn't? The old code would leave the finished
+		   one in READY mode. That's bad, and caused -EROFS 
+		   errors to be returned from do_erase_oneblock because
+		   that's the only bit it checked for at the time.
+		   As the state machine appears to explicitly allow 
+		   sending the 0x70 (Read Status) command to an erasing
+		   chip and expecting it to be ignored, that's what we 
+		   do. */
+		cfi_write(map, CMD(0xd0), adr);
+		cfi_write(map, CMD(0x70), adr);		
 	}
 	wake_up(&chip->wq);
-	spin_unlock_bh(chip->mutex);
-	return 0;
+	spin_unlock(chip->mutex);
+	return ret;
 }
 
 
@@ -583,8 +948,8 @@
 		unsigned long bus_ofs = ofs & ~(CFIDEV_BUSWIDTH-1);
 		int gap = ofs - bus_ofs;
 		int i = 0, n = 0;
-		u_char tmp_buf[4];
-		__u32 datum;
+		u_char tmp_buf[8];
+		cfi_word datum;
 
 		while (gap--)
 			tmp_buf[i++] = 0xff;
@@ -597,6 +962,8 @@
 			datum = *(__u16*)tmp_buf;
 		} else if (cfi_buswidth_is_4()) {
 			datum = *(__u32*)tmp_buf;
+		} else if (cfi_buswidth_is_8()) {
+			datum = *(__u64*)tmp_buf;
 		} else {
 			return -EINVAL;  /* should never happen, but be safe */
 		}
@@ -619,7 +986,7 @@
 	}
 	
 	while(len >= CFIDEV_BUSWIDTH) {
-		__u32 datum;
+		cfi_word datum;
 
 		if (cfi_buswidth_is_1()) {
 			datum = *(__u8*)buf;
@@ -627,6 +994,8 @@
 			datum = *(__u16*)buf;
 		} else if (cfi_buswidth_is_4()) {
 			datum = *(__u32*)buf;
+		} else if (cfi_buswidth_is_8()) {
+			datum = *(__u64*)buf;
 		} else {
 			return -EINVAL;
 		}
@@ -651,8 +1020,8 @@
 
 	if (len & (CFIDEV_BUSWIDTH-1)) {
 		int i = 0, n = 0;
-		u_char tmp_buf[4];
-		__u32 datum;
+		u_char tmp_buf[8];
+		cfi_word datum;
 
 		while (len--)
 			tmp_buf[i++] = buf[n++];
@@ -663,6 +1032,8 @@
 			datum = *(__u16*)tmp_buf;
 		} else if (cfi_buswidth_is_4()) {
 			datum = *(__u32*)tmp_buf;
+		} else if (cfi_buswidth_is_8()) {
+			datum = *(__u64*)tmp_buf;
 		} else {
 			return -EINVAL;  /* should never happen, but be safe */
 		}
@@ -683,10 +1054,11 @@
 				  unsigned long adr, const u_char *buf, int len)
 {
 	struct cfi_private *cfi = map->fldrv_priv;
-	__u32 status, status_OK;
+	struct cfi_pri_intelext *extp = cfi->cmdset_priv;
+	cfi_word status, status_OK;
 	unsigned long cmd_adr, timeo;
 	DECLARE_WAITQUEUE(wait, current);
-	int wbufsize, z;
+	int wbufsize, z, suspended=0, ret=0;
 
 	wbufsize = CFIDEV_INTERLEAVE << cfi->cfiq->MaxBufWriteSize;
 	adr += chip->start;
@@ -697,7 +1069,7 @@
 
 	timeo = jiffies + HZ;
  retry:
-	spin_lock_bh(chip->mutex);
+	spin_lock(chip->mutex);
 
 	/* Check that the chip's ready to talk to us.
 	 * Later, we can actually think about interrupting it
@@ -706,8 +1078,6 @@
 	 */
 	switch (chip->state) {
 	case FL_READY:
-		break;
-		
 	case FL_CFI_QUERY:
 	case FL_JEDEC_QUERY:
 		cfi_write(map, CMD(0x70), cmd_adr);
@@ -719,50 +1089,104 @@
 			break;
 		/* Urgh. Chip not yet ready to talk to us. */
 		if (time_after(jiffies, timeo)) {
-			spin_unlock_bh(chip->mutex);
+			spin_unlock(chip->mutex);
 			printk(KERN_ERR "waiting for chip to be ready timed out in buffer write\n");
 			return -EIO;
 		}
 
 		/* Latency issues. Drop the lock, wait a while and retry */
-		spin_unlock_bh(chip->mutex);
+		spin_unlock(chip->mutex);
 		cfi_udelay(1);
 		goto retry;
 
+	case FL_ERASING:
+		if (!extp || 
+		    !((extp->FeatureSupport & 2) && (extp->SuspendCmdSupport & 1)))
+			goto sleep; /* We don't support erase suspend */
+		
+		cfi_write (map, CMD(0xb0), adr);
+
+		/* If the flash has finished erasing, then 'erase suspend'
+		 * appears to make some (28F320) flash devices switch to
+		 * 'read' mode.  Make sure that we switch to 'read status'
+		 * mode so we get the right data. --rmk
+		 */
+		cfi_write(map, CMD(0x70), adr);
+		chip->oldstate = FL_ERASING;
+		chip->state = FL_ERASE_SUSPENDING;
+		for (;;) {
+			status = cfi_read(map, adr);
+			if ((status & status_OK) == status_OK)
+				break;
+			
+			if (time_after(jiffies, timeo)) {
+				/* Urgh */
+				cfi_write(map, CMD(0xd0), adr);
+				/* make sure we're in 'read status' mode */
+				cfi_write(map, CMD(0x70), adr);
+				chip->state = FL_ERASING;
+				spin_unlock(chip->mutex);
+				printk(KERN_ERR "Chip not ready after erase "
+				       "suspended: status = 0x%x\n", status);
+				return -EIO;
+			}
+			
+			spin_unlock(chip->mutex);
+			cfi_udelay(1);
+			spin_lock(chip->mutex);
+		}
+		suspended = 1;
+		chip->state = FL_STATUS;
+		break;
+
 	default:
+	sleep:
 		/* Stick ourselves on a wait queue to be woken when
 		   someone changes the status */
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		add_wait_queue(&chip->wq, &wait);
-		spin_unlock_bh(chip->mutex);
+		spin_unlock(chip->mutex);
 		schedule();
 		remove_wait_queue(&chip->wq, &wait);
 		timeo = jiffies + HZ;
 		goto retry;
 	}
-
+	/* We know we're now in FL_STATUS mode, and 'status' is current */
+	/* §4.8 of the 28FxxxJ3A datasheet says "Any time SR.4 and/or SR.5 is set
+	   [...], the device will not accept any more Write to Buffer commands". 
+	   So we must check here and reset those bits if they're set. Otherwise
+	   we're just pissing in the wind */
+	if (status & CMD(0x30)) {
+		printk(KERN_WARNING "SR.4 or SR.5 bits set in buffer write (status %x). Clearing.\n", status);
+		cfi_write(map, CMD(0x50), cmd_adr);
+		cfi_write(map, CMD(0x70), cmd_adr);
+	}
 	ENABLE_VPP(map);
-	cfi_write(map, CMD(0xe8), cmd_adr);
 	chip->state = FL_WRITING_TO_BUFFER;
 
 	z = 0;
 	for (;;) {
+		cfi_write(map, CMD(0xe8), cmd_adr);
+
 		status = cfi_read(map, cmd_adr);
 		if ((status & status_OK) == status_OK)
 			break;
 
-		spin_unlock_bh(chip->mutex);
+		spin_unlock(chip->mutex);
 		cfi_udelay(1);
-		spin_lock_bh(chip->mutex);
+		spin_lock(chip->mutex);
 
 		if (++z > 20) {
 			/* Argh. Not ready for write to buffer */
 			cfi_write(map, CMD(0x70), cmd_adr);
 			chip->state = FL_STATUS;
 			DISABLE_VPP(map);
-			spin_unlock_bh(chip->mutex);
-			printk(KERN_ERR "Chip not ready for buffer write. Xstatus = %x, status = %x\n", status, cfi_read(map, cmd_adr));
-			return -EIO;
+			printk(KERN_ERR "Chip not ready for buffer write. Xstatus = %llx, status = %llx\n", (__u64)status, (__u64)cfi_read(map, cmd_adr));
+			/* Odd. Clear status bits */
+			cfi_write(map, CMD(0x50), cmd_adr);
+			cfi_write(map, CMD(0x70), cmd_adr);
+			ret = -EIO;
+			goto out;
 		}
 	}
 
@@ -777,18 +1201,21 @@
 			map->write16 (map, *((__u16*)buf)++, adr+z);
 		} else if (cfi_buswidth_is_4()) {
 			map->write32 (map, *((__u32*)buf)++, adr+z);
+		} else if (cfi_buswidth_is_8()) {
+			map->write64 (map, *((__u64*)buf)++, adr+z);
 		} else {
 			DISABLE_VPP(map);
-			return -EINVAL;
+			ret = -EINVAL;
+			goto out;
 		}
 	}
 	/* GO GO GO */
 	cfi_write(map, CMD(0xd0), cmd_adr);
 	chip->state = FL_WRITING;
 
-	spin_unlock_bh(chip->mutex);
+	spin_unlock(chip->mutex);
 	cfi_udelay(chip->buffer_write_time);
-	spin_lock_bh(chip->mutex);
+	spin_lock(chip->mutex);
 
 	timeo = jiffies + (HZ/2);
 	z = 0;
@@ -797,11 +1224,11 @@
 			/* Someone's suspended the write. Sleep */
 			set_current_state(TASK_UNINTERRUPTIBLE);
 			add_wait_queue(&chip->wq, &wait);
-			spin_unlock_bh(chip->mutex);
+			spin_unlock(chip->mutex);
 			schedule();
 			remove_wait_queue(&chip->wq, &wait);
 			timeo = jiffies + (HZ / 2); /* FIXME */
-			spin_lock_bh(chip->mutex);
+			spin_lock(chip->mutex);
 			continue;
 		}
 
@@ -813,16 +1240,16 @@
 		if (time_after(jiffies, timeo)) {
 			chip->state = FL_STATUS;
 			DISABLE_VPP(map);
-			spin_unlock_bh(chip->mutex);
 			printk(KERN_ERR "waiting for chip to be ready timed out in bufwrite\n");
-			return -EIO;
+			ret = -EIO;
+			goto out;
 		}
 		
 		/* Latency issues. Drop the lock, wait a while and retry */
-		spin_unlock_bh(chip->mutex);
+		spin_unlock(chip->mutex);
 		cfi_udelay(1);
 		z++;
-		spin_lock_bh(chip->mutex);
+		spin_lock(chip->mutex);
 	}
 	if (!z) {
 		chip->buffer_write_time--;
@@ -841,13 +1268,27 @@
 		cfi_write(map, CMD(0x50), cmd_adr);
 		/* put back into read status register mode */
 		cfi_write(map, CMD(0x70), adr);
-		wake_up(&chip->wq);
-		spin_unlock_bh(chip->mutex);
-		return -EROFS;
+		ret = -EROFS;
+		goto out;
+	}
+ out:
+	if (suspended) {
+		chip->state = chip->oldstate;
+		/* What if one interleaved chip has finished and the 
+		   other hasn't? The old code would leave the finished
+		   one in READY mode. That's bad, and caused -EROFS 
+		   errors to be returned from do_erase_oneblock because
+		   that's the only bit it checked for at the time.
+		   As the state machine appears to explicitly allow 
+		   sending the 0x70 (Read Status) command to an erasing
+		   chip and expecting it to be ignored, that's what we 
+		   do. */
+		cfi_write(map, CMD(0xd0), adr);
+		cfi_write(map, CMD(0x70), adr);		
 	}
 	wake_up(&chip->wq);
-	spin_unlock_bh(chip->mutex);
-	return 0;
+	spin_unlock(chip->mutex);
+	return ret;
 }
 
 static int cfi_intelext_write_buffers (struct mtd_info *mtd, loff_t to, 
@@ -926,11 +1367,102 @@
 	return 0;
 }
 
+typedef int (*varsize_frob_t)(struct map_info *map, struct flchip *chip,
+			      unsigned long adr, void *thunk);
 
-static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr)
+static int cfi_intelext_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob,
+				     loff_t ofs, size_t len, void *thunk)
 {
+	struct map_info *map = mtd->priv;
 	struct cfi_private *cfi = map->fldrv_priv;
-	__u32 status, status_OK;
+	unsigned long adr;
+	int chipnum, ret = 0;
+	int i, first;
+	struct mtd_erase_region_info *regions = mtd->eraseregions;
+
+	if (ofs > mtd->size)
+		return -EINVAL;
+
+	if ((len + ofs) > mtd->size)
+		return -EINVAL;
+
+	/* Check that both start and end of the requested erase are
+	 * aligned with the erasesize at the appropriate addresses.
+	 */
+
+	i = 0;
+
+	/* Skip all erase regions which are ended before the start of 
+	   the requested erase. Actually, to save on the calculations,
+	   we skip to the first erase region which starts after the
+	   start of the requested erase, and then go back one.
+	*/
+	
+	while (i < mtd->numeraseregions && ofs >= regions[i].offset)
+	       i++;
+	i--;
+
+	/* OK, now i is pointing at the erase region in which this 
+	   erase request starts. Check the start of the requested
+	   erase range is aligned with the erase size which is in
+	   effect here.
+	*/
+
+	if (ofs & (regions[i].erasesize-1))
+		return -EINVAL;
+
+	/* Remember the erase region we start on */
+	first = i;
+
+	/* Next, check that the end of the requested erase is aligned
+	 * with the erase region at that address.
+	 */
+
+	while (i<mtd->numeraseregions && (ofs + len) >= regions[i].offset)
+		i++;
+
+	/* As before, drop back one to point at the region in which
+	   the address actually falls
+	*/
+	i--;
+	
+	if ((ofs + len) & (regions[i].erasesize-1))
+		return -EINVAL;
+
+	chipnum = ofs >> cfi->chipshift;
+	adr = ofs - (chipnum << cfi->chipshift);
+
+	i=first;
+
+	while(len) {
+		ret = (*frob)(map, &cfi->chips[chipnum], adr, thunk);
+		
+		if (ret)
+			return ret;
+
+		adr += regions[i].erasesize;
+		len -= regions[i].erasesize;
+
+		if (adr % (1<< cfi->chipshift) == ((regions[i].offset + (regions[i].erasesize * regions[i].numblocks)) %( 1<< cfi->chipshift)))
+			i++;
+
+		if (adr >> cfi->chipshift) {
+			adr = 0;
+			chipnum++;
+			
+			if (chipnum >= cfi->numchips)
+			break;
+		}
+	}
+
+	return 0;
+}
+
+
+static int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, void *thunk)
+{
+	struct cfi_private *cfi = map->fldrv_priv;
+	cfi_word status, status_OK;
 	unsigned long timeo;
 	int retries = 3;
 	DECLARE_WAITQUEUE(wait, current);
@@ -943,7 +1475,7 @@
 
 	timeo = jiffies + HZ;
 retry:
-	spin_lock_bh(chip->mutex);
+	spin_lock(chip->mutex);
 
 	/* Check that the chip's ready to talk to us. */
 	switch (chip->state) {
@@ -960,13 +1492,13 @@
 		
 		/* Urgh. Chip not yet ready to talk to us. */
 		if (time_after(jiffies, timeo)) {
-			spin_unlock_bh(chip->mutex);
+			spin_unlock(chip->mutex);
 			printk(KERN_ERR "waiting for chip to be ready timed out in erase\n");
 			return -EIO;
 		}
 
 		/* Latency issues. Drop the lock, wait a while and retry */
-		spin_unlock_bh(chip->mutex);
+		spin_unlock(chip->mutex);
 		cfi_udelay(1);
 		goto retry;
 
@@ -975,7 +1507,7 @@
 		   someone changes the status */
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		add_wait_queue(&chip->wq, &wait);
-		spin_unlock_bh(chip->mutex);
+		spin_unlock(chip->mutex);
 		schedule();
 		remove_wait_queue(&chip->wq, &wait);
 		timeo = jiffies + HZ;
@@ -990,10 +1522,12 @@
 	cfi_write(map, CMD(0x20), adr);
 	cfi_write(map, CMD(0xD0), adr);
 	chip->state = FL_ERASING;
-	
-	spin_unlock_bh(chip->mutex);
-	schedule_timeout(HZ);
-	spin_lock_bh(chip->mutex);
+	chip->oldstate = 0;
+
+	spin_unlock(chip->mutex);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout((chip->erase_time*HZ)/(2*1000));
+	spin_lock(chip->mutex);
 
 	/* FIXME. Use a timer to check this, and return immediately. */
 	/* Once the state machine's known to be working I'll do that */
@@ -1004,13 +1538,18 @@
 			/* Someone's suspended the erase. Sleep */
 			set_current_state(TASK_UNINTERRUPTIBLE);
 			add_wait_queue(&chip->wq, &wait);
-			spin_unlock_bh(chip->mutex);
+			spin_unlock(chip->mutex);
 			schedule();
 			remove_wait_queue(&chip->wq, &wait);
-			timeo = jiffies + (HZ*20); /* FIXME */
-			spin_lock_bh(chip->mutex);
+			spin_lock(chip->mutex);
 			continue;
 		}
+		if (chip->oldstate) {
+			/* This erase was suspended and resumed.
+			   Adjust the timeout */
+			timeo = jiffies + (HZ*20); /* FIXME */
+			chip->oldstate = 0;
+		}
 
 		status = cfi_read(map, adr);
 		if ((status & status_OK) == status_OK)
@@ -1020,16 +1559,21 @@
 		if (time_after(jiffies, timeo)) {
 			cfi_write(map, CMD(0x70), adr);
 			chip->state = FL_STATUS;
-			printk(KERN_ERR "waiting for erase to complete timed out. Xstatus = %x, status = %x.\n", status, cfi_read(map, adr));
+			printk(KERN_ERR "waiting for erase at %08lx to complete timed out. Xstatus = %llx, status = %llx.\n",
+			       adr, (__u64)status, (__u64)cfi_read(map, adr));
+			/* Clear status bits */
+			cfi_write(map, CMD(0x50), adr);
+			cfi_write(map, CMD(0x70), adr);
 			DISABLE_VPP(map);
-			spin_unlock_bh(chip->mutex);
+			spin_unlock(chip->mutex);
 			return -EIO;
 		}
 		
 		/* Latency issues. Drop the lock, wait a while and retry */
-		spin_unlock_bh(chip->mutex);
-		cfi_udelay(1);
-		spin_lock_bh(chip->mutex);
+		spin_unlock(chip->mutex);
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+		spin_lock(chip->mutex);
 	}
 	
 	DISABLE_VPP(map);
@@ -1048,124 +1592,52 @@
 			for (i = 1; i<CFIDEV_INTERLEAVE; i++) {
 				      chipstatus |= status >> (cfi->device_type * 8);
 			}
-			printk(KERN_WARNING "Status is not identical for all chips: 0x%x. Merging to give 0x%02x\n", status, chipstatus);
+			printk(KERN_WARNING "Status is not identical for all chips: 0x%llx. Merging to give 0x%02x\n", (__u64)status, chipstatus);
 		}
 		/* Reset the error bits */
 		cfi_write(map, CMD(0x50), adr);
 		cfi_write(map, CMD(0x70), adr);
 		
 		if ((chipstatus & 0x30) == 0x30) {
-			printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%x\n", status);
+			printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%llx\n", (__u64)status);
 			ret = -EIO;
 		} else if (chipstatus & 0x02) {
 			/* Protection bit set */
 			ret = -EROFS;
 		} else if (chipstatus & 0x8) {
 			/* Voltage */
-			printk(KERN_WARNING "Chip reports voltage low on erase: status 0x%x\n", status);
+			printk(KERN_WARNING "Chip reports voltage low on erase: status 0x%llx\n", (__u64)status);
 			ret = -EIO;
 		} else if (chipstatus & 0x20) {
 			if (retries--) {
-				printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x. Retrying...\n", adr, status);
+				printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%llx. Retrying...\n", adr, (__u64)status);
 				timeo = jiffies + HZ;
 				chip->state = FL_STATUS;
-				spin_unlock_bh(chip->mutex);
+				spin_unlock(chip->mutex);
 				goto retry;
 			}
-			printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x\n", adr, status);
+			printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%llx\n", adr, (__u64)status);
 			ret = -EIO;
 		}
 	}
 
 	wake_up(&chip->wq);
-	spin_unlock_bh(chip->mutex);
+	spin_unlock(chip->mutex);
 	return ret;
 }
 
 int cfi_intelext_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
-{	struct map_info *map = mtd->priv;
-	struct cfi_private *cfi = map->fldrv_priv;
-	unsigned long adr, len;
-	int chipnum, ret = 0;
-	int i, first;
-	struct mtd_erase_region_info *regions = mtd->eraseregions;
-
-	if (instr->addr > mtd->size)
-		return -EINVAL;
-
-	if ((instr->len + instr->addr) > mtd->size)
-		return -EINVAL;
-
-	/* Check that both start and end of the requested erase are
-	 * aligned with the erasesize at the appropriate addresses.
-	 */
-
-	i = 0;
-
-	/* Skip all erase regions which are ended before the start of 
-	   the requested erase. Actually, to save on the calculations,
-	   we skip to the first erase region which starts after the
-	   start of the requested erase, and then go back one.
-	*/
-	
-	while (i < mtd->numeraseregions && instr->addr >= regions[i].offset)
-	       i++;
-	i--;
-
-	/* OK, now i is pointing at the erase region in which this 
-	   erase request starts. Check the start of the requested
-	   erase range is aligned with the erase size which is in
-	   effect here.
-	*/
-
-	if (instr->addr & (regions[i].erasesize-1))
-		return -EINVAL;
-
-	/* Remember the erase region we start on */
-	first = i;
-
-	/* Next, check that the end of the requested erase is aligned
-	 * with the erase region at that address.
-	 */
-
-	while (i<mtd->numeraseregions && (instr->addr + instr->len) >= regions[i].offset)
-		i++;
-
-	/* As before, drop back one to point at the region in which
-	   the address actually falls
-	*/
-	i--;
-	
-	if ((instr->addr + instr->len) & (regions[i].erasesize-1))
-		return -EINVAL;
+{
+	unsigned long ofs, len;
+	int ret;
 
-	chipnum = instr->addr >> cfi->chipshift;
-	adr = instr->addr - (chipnum << cfi->chipshift);
+	ofs = instr->addr;
 	len = instr->len;
 
-	i=first;
-
-	while(len) {
-		ret = do_erase_oneblock(map, &cfi->chips[chipnum], adr);
-		
-		if (ret)
-			return ret;
-
-		adr += regions[i].erasesize;
-		len -= regions[i].erasesize;
-
-		if (adr % (1<< cfi->chipshift) == ((regions[i].offset + (regions[i].erasesize * regions[i].numblocks)) %( 1<< cfi->chipshift)))
-			i++;
+	ret = cfi_intelext_varsize_frob(mtd, do_erase_oneblock, ofs, len, 0);
+	if (ret)
+		return ret;
 
-		if (adr >> cfi->chipshift) {
-			adr = 0;
-			chipnum++;
-			
-			if (chipnum >= cfi->numchips)
-			break;
-		}
-	}
-		
 	instr->state = MTD_ERASE_DONE;
 	if (instr->callback)
 		instr->callback(instr);
@@ -1186,7 +1658,7 @@
 		chip = &cfi->chips[i];
 
 	retry:
-		spin_lock_bh(chip->mutex);
+		spin_lock(chip->mutex);
 
 		switch(chip->state) {
 		case FL_READY:
@@ -1200,14 +1672,14 @@
 			 * with the chip now anyway.
 			 */
 		case FL_SYNCING:
-			spin_unlock_bh(chip->mutex);
+			spin_unlock(chip->mutex);
 			break;
 
 		default:
 			/* Not an idle state */
 			add_wait_queue(&chip->wq, &wait);
 			
-			spin_unlock_bh(chip->mutex);
+			spin_unlock(chip->mutex);
 			schedule();
 		        remove_wait_queue(&chip->wq, &wait);
 			
@@ -1220,169 +1692,38 @@
 	for (i--; i >=0; i--) {
 		chip = &cfi->chips[i];
 
-		spin_lock_bh(chip->mutex);
+		spin_lock(chip->mutex);
 		
 		if (chip->state == FL_SYNCING) {
 			chip->state = chip->oldstate;
 			wake_up(&chip->wq);
 		}
-		spin_unlock_bh(chip->mutex);
+		spin_unlock(chip->mutex);
 	}
 }
 
-static inline int do_lock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr)
+#ifdef DEBUG_LOCK_BITS
+static int do_printlockstatus_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, void *thunk)
 {
 	struct cfi_private *cfi = map->fldrv_priv;
-	__u32 status, status_OK;
-	unsigned long timeo = jiffies + HZ;
-	DECLARE_WAITQUEUE(wait, current);
-
-	adr += chip->start;
-
-	/* Let's determine this according to the interleave only once */
-	status_OK = CMD(0x80);
-
-	timeo = jiffies + HZ;
-retry:
-	spin_lock_bh(chip->mutex);
-
-	/* Check that the chip's ready to talk to us. */
-	switch (chip->state) {
-	case FL_CFI_QUERY:
-	case FL_JEDEC_QUERY:
-	case FL_READY:
-		cfi_write(map, CMD(0x70), adr);
-		chip->state = FL_STATUS;
-
-	case FL_STATUS:
-		status = cfi_read(map, adr);
-		if ((status & status_OK) == status_OK) 
-			break;
-		
-		/* Urgh. Chip not yet ready to talk to us. */
-		if (time_after(jiffies, timeo)) {
-			spin_unlock_bh(chip->mutex);
-			printk(KERN_ERR "waiting for chip to be ready timed out in lock\n");
-			return -EIO;
-		}
-
-		/* Latency issues. Drop the lock, wait a while and retry */
-		spin_unlock_bh(chip->mutex);
-		cfi_udelay(1);
-		goto retry;
-
-	default:
-		/* Stick ourselves on a wait queue to be woken when
-		   someone changes the status */
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		add_wait_queue(&chip->wq, &wait);
-		spin_unlock_bh(chip->mutex);
-		schedule();
-		remove_wait_queue(&chip->wq, &wait);
-		timeo = jiffies + HZ;
-		goto retry;
-	}
-
-	ENABLE_VPP(map);
-	cfi_write(map, CMD(0x60), adr);
-	cfi_write(map, CMD(0x01), adr);
-	chip->state = FL_LOCKING;
-	
-	spin_unlock_bh(chip->mutex);
-	schedule_timeout(HZ);
-	spin_lock_bh(chip->mutex);
-
-	/* FIXME. Use a timer to check this, and return immediately. */
-	/* Once the state machine's known to be working I'll do that */
-
-	timeo = jiffies + (HZ*2);
-	for (;;) {
+	int ofs_factor = cfi->interleave * cfi->device_type;
 
-		status = cfi_read(map, adr);
-		if ((status & status_OK) == status_OK)
-			break;
-		
-		/* OK Still waiting */
-		if (time_after(jiffies, timeo)) {
-			cfi_write(map, CMD(0x70), adr);
-			chip->state = FL_STATUS;
-			printk(KERN_ERR "waiting for lock to complete timed out. Xstatus = %x, status = %x.\n", status, cfi_read(map, adr));
-			DISABLE_VPP(map);
-			spin_unlock_bh(chip->mutex);
-			return -EIO;
-		}
-		
-		/* Latency issues. Drop the lock, wait a while and retry */
-		spin_unlock_bh(chip->mutex);
-		cfi_udelay(1);
-		spin_lock_bh(chip->mutex);
-	}
+	cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
+	printk(KERN_DEBUG "block status register for 0x%08lx is %x\n",
+	       adr, cfi_read_query(map, adr+(2*ofs_factor)));
+	cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);
 	
-	/* Done and happy. */
-	chip->state = FL_STATUS;
-	DISABLE_VPP(map);
-	wake_up(&chip->wq);
-	spin_unlock_bh(chip->mutex);
 	return 0;
 }
-static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
-{
-	struct map_info *map = mtd->priv;
-	struct cfi_private *cfi = map->fldrv_priv;
-	unsigned long adr;
-	int chipnum, ret = 0;
-#ifdef DEBUG_LOCK_BITS
-	int ofs_factor = cfi->interleave * cfi->device_type;
 #endif
 
-	if (ofs & (mtd->erasesize - 1))
-		return -EINVAL;
-
-	if (len & (mtd->erasesize -1))
-		return -EINVAL;
-
-	if ((len + ofs) > mtd->size)
-		return -EINVAL;
-
-	chipnum = ofs >> cfi->chipshift;
-	adr = ofs - (chipnum << cfi->chipshift);
-
-	while(len) {
-
-#ifdef DEBUG_LOCK_BITS
-		cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
-		printk("before lock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor)));
-		cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);
-#endif
-
-		ret = do_lock_oneblock(map, &cfi->chips[chipnum], adr);
-
-#ifdef DEBUG_LOCK_BITS
-		cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
-		printk("after lock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor)));
-		cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);
-#endif	
-		
-		if (ret)
-			return ret;
-
-		adr += mtd->erasesize;
-		len -= mtd->erasesize;
+#define DO_XXLOCK_ONEBLOCK_LOCK		((void *) 1)
+#define DO_XXLOCK_ONEBLOCK_UNLOCK	((void *) 2)
 
-		if (adr >> cfi->chipshift) {
-			adr = 0;
-			chipnum++;
-			
-			if (chipnum >= cfi->numchips)
-			break;
-		}
-	}
-	return 0;
-}
-static inline int do_unlock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr)
+static int do_xxlock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, void *thunk)
 {
 	struct cfi_private *cfi = map->fldrv_priv;
-	__u32 status, status_OK;
+	cfi_word status, status_OK;
 	unsigned long timeo = jiffies + HZ;
 	DECLARE_WAITQUEUE(wait, current);
 
@@ -1393,7 +1734,7 @@
 
 	timeo = jiffies + HZ;
 retry:
-	spin_lock_bh(chip->mutex);
+	spin_lock(chip->mutex);
 
 	/* Check that the chip's ready to talk to us. */
 	switch (chip->state) {
@@ -1410,13 +1751,13 @@
 		
 		/* Urgh. Chip not yet ready to talk to us. */
 		if (time_after(jiffies, timeo)) {
-			spin_unlock_bh(chip->mutex);
-			printk(KERN_ERR "waiting for chip to be ready timed out in unlock\n");
+			spin_unlock(chip->mutex);
+			printk(KERN_ERR "%s: waiting for chip to be ready timed out\n", __FUNCTION__);
 			return -EIO;
 		}
 
 		/* Latency issues. Drop the lock, wait a while and retry */
-		spin_unlock_bh(chip->mutex);
+		spin_unlock(chip->mutex);
 		cfi_udelay(1);
 		goto retry;
 
@@ -1425,7 +1766,7 @@
 		   someone changes the status */
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		add_wait_queue(&chip->wq, &wait);
-		spin_unlock_bh(chip->mutex);
+		spin_unlock(chip->mutex);
 		schedule();
 		remove_wait_queue(&chip->wq, &wait);
 		timeo = jiffies + HZ;
@@ -1434,17 +1775,24 @@
 
 	ENABLE_VPP(map);
 	cfi_write(map, CMD(0x60), adr);
-	cfi_write(map, CMD(0xD0), adr);
-	chip->state = FL_UNLOCKING;
-	
-	spin_unlock_bh(chip->mutex);
+
+	if (thunk == DO_XXLOCK_ONEBLOCK_LOCK) {
+		cfi_write(map, CMD(0x01), adr);
+		chip->state = FL_LOCKING;
+	} else if (thunk == DO_XXLOCK_ONEBLOCK_UNLOCK) {
+		cfi_write(map, CMD(0xD0), adr);
+		chip->state = FL_UNLOCKING;
+	} else
+		BUG();
+
+	spin_unlock(chip->mutex);
 	schedule_timeout(HZ);
-	spin_lock_bh(chip->mutex);
+	spin_lock(chip->mutex);
 
 	/* FIXME. Use a timer to check this, and return immediately. */
 	/* Once the state machine's known to be working I'll do that */
 
-	timeo = jiffies + (HZ*2);
+	timeo = jiffies + (HZ*20);
 	for (;;) {
 
 		status = cfi_read(map, adr);
@@ -1455,59 +1803,68 @@
 		if (time_after(jiffies, timeo)) {
 			cfi_write(map, CMD(0x70), adr);
 			chip->state = FL_STATUS;
-			printk(KERN_ERR "waiting for unlock to complete timed out. Xstatus = %x, status = %x.\n", status, cfi_read(map, adr));
+			printk(KERN_ERR "waiting for unlock to complete timed out. Xstatus = %llx, status = %llx.\n", (__u64)status, (__u64)cfi_read(map, adr));
 			DISABLE_VPP(map);
-			spin_unlock_bh(chip->mutex);
+			spin_unlock(chip->mutex);
 			return -EIO;
 		}
 		
-		/* Latency issues. Drop the unlock, wait a while and retry */
-		spin_unlock_bh(chip->mutex);
+		/* Latency issues. Drop the lock, wait a while and retry */
+		spin_unlock(chip->mutex);
 		cfi_udelay(1);
-		spin_lock_bh(chip->mutex);
+		spin_lock(chip->mutex);
 	}
 	
 	/* Done and happy. */
 	chip->state = FL_STATUS;
 	DISABLE_VPP(map);
 	wake_up(&chip->wq);
-	spin_unlock_bh(chip->mutex);
+	spin_unlock(chip->mutex);
 	return 0;
 }
-static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
+
+static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
 {
-	struct map_info *map = mtd->priv;
-	struct cfi_private *cfi = map->fldrv_priv;
-	unsigned long adr;
-	int chipnum, ret = 0;
+	int ret;
+
 #ifdef DEBUG_LOCK_BITS
-	int ofs_factor = cfi->interleave * cfi->device_type;
+	printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n",
+	       __FUNCTION__, ofs, len);
+	cfi_intelext_varsize_frob(mtd, do_printlockstatus_oneblock,
+				  ofs, len, 0);
 #endif
 
-	chipnum = ofs >> cfi->chipshift;
-	adr = ofs - (chipnum << cfi->chipshift);
-
+	ret = cfi_intelext_varsize_frob(mtd, do_xxlock_oneblock, 
+					ofs, len, DO_XXLOCK_ONEBLOCK_LOCK);
+	
 #ifdef DEBUG_LOCK_BITS
-	{
-		unsigned long temp_adr = adr;
-		unsigned long temp_len = len;
-                 
-		cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
-                while (temp_len) {
-			printk("before unlock %x: block status register is %x\n",temp_adr,cfi_read_query(map, temp_adr+(2*ofs_factor)));
-			temp_adr += mtd->erasesize;
-			temp_len -= mtd->erasesize;
-		}
-		cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);
-	}
+	printk(KERN_DEBUG __FUNCTION__
+	       "%s: lock status after, ret=%d\n", __FUNCTION__, ret);
+	cfi_intelext_varsize_frob(mtd, do_printlockstatus_oneblock,
+				  ofs, len, 0);
 #endif
 
-	ret = do_unlock_oneblock(map, &cfi->chips[chipnum], adr);
+	return ret;
+}
+
+static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+	int ret;
 
 #ifdef DEBUG_LOCK_BITS
-	cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
-	printk("after unlock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor)));
-	cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);
+	printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n",
+	       __FUNCTION__, ofs, len);
+	cfi_intelext_varsize_frob(mtd, do_printlockstatus_oneblock,
+				  ofs, len, 0);
+#endif
+
+	ret = cfi_intelext_varsize_frob(mtd, do_xxlock_oneblock,
+					ofs, len, DO_XXLOCK_ONEBLOCK_UNLOCK);
+	
+#ifdef DEBUG_LOCK_BITS
+	printk(KERN_DEBUG "%s: lock status after, ret=%d\n", __FUNCTION__, ret);
+	cfi_intelext_varsize_frob(mtd, do_printlockstatus_oneblock, 
+				  ofs, len, 0);
 #endif
 	
 	return ret;
@@ -1524,7 +1881,7 @@
 	for (i=0; !ret && i<cfi->numchips; i++) {
 		chip = &cfi->chips[i];
 
-		spin_lock_bh(chip->mutex);
+		spin_lock(chip->mutex);
 
 		switch(chip->state) {
 		case FL_READY:
@@ -1544,7 +1901,7 @@
 			ret = -EAGAIN;
 			break;
 		}
-		spin_unlock_bh(chip->mutex);
+		spin_unlock(chip->mutex);
 	}
 
 	/* Unlock the chips again */
@@ -1553,7 +1910,7 @@
 		for (i--; i >=0; i--) {
 			chip = &cfi->chips[i];
 			
-			spin_lock_bh(chip->mutex);
+			spin_lock(chip->mutex);
 			
 			if (chip->state == FL_PM_SUSPENDED) {
 				/* No need to force it into a known state here,
@@ -1562,7 +1919,7 @@
 				chip->state = chip->oldstate;
 				wake_up(&chip->wq);
 			}
-			spin_unlock_bh(chip->mutex);
+			spin_unlock(chip->mutex);
 		}
 	} 
 	
@@ -1580,7 +1937,7 @@
 	
 		chip = &cfi->chips[i];
 
-		spin_lock_bh(chip->mutex);
+		spin_lock(chip->mutex);
 		
 		/* Go to known state. Chip may have been power cycled */
 		if (chip->state == FL_PM_SUSPENDED) {
@@ -1589,7 +1946,7 @@
 			wake_up(&chip->wq);
 		}
 
-		spin_unlock_bh(chip->mutex);
+		spin_unlock(chip->mutex);
 	}
 }
 
@@ -1598,7 +1955,9 @@
 	struct map_info *map = mtd->priv;
 	struct cfi_private *cfi = map->fldrv_priv;
 	kfree(cfi->cmdset_priv);
+	kfree(cfi->cfiq);
 	kfree(cfi);
+	kfree(mtd->eraseregions);
 }
 
 static char im_name_1[]="cfi_cmdset_0001";
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/chips/cfi_cmdset_0002.c linux-2.4.21-pre6/drivers/mtd/chips/cfi_cmdset_0002.c
--- linux-2.4.20/drivers/mtd/chips/cfi_cmdset_0002.c	2001-10-25 07:07:09.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/chips/cfi_cmdset_0002.c	2003-03-26 23:49:34.000000000 +0000
@@ -8,7 +8,7 @@
  *
  * This code is GPL
  *
- * $Id: cfi_cmdset_0002.c,v 1.52 2001/10/24 09:37:30 dwmw2 Exp $
+ * $Id: cfi_cmdset_0002.c,v 1.62 2003/01/24 23:30:13 dwmw2 Exp $
  *
  */
 
@@ -30,11 +30,13 @@
 
 static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
 static int cfi_amdstd_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
+static int cfi_amdstd_erase_chip(struct mtd_info *, struct erase_info *);
 static int cfi_amdstd_erase_onesize(struct mtd_info *, struct erase_info *);
 static int cfi_amdstd_erase_varsize(struct mtd_info *, struct erase_info *);
 static void cfi_amdstd_sync (struct mtd_info *);
 static int cfi_amdstd_suspend (struct mtd_info *);
 static void cfi_amdstd_resume (struct mtd_info *);
+static int cfi_amdstd_secsi_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
 
 static void cfi_amdstd_destroy(struct mtd_info *);
 
@@ -58,7 +60,7 @@
 	__u8 major, minor;
 	__u32 base = cfi->chips[0].start;
 
-	if (cfi->cfi_mode==1){
+	if (cfi->cfi_mode==CFI_MODE_CFI){
 		__u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR;
 
 		cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
@@ -74,7 +76,7 @@
 		cfi_send_gen_cmd(0x55, 0x2aa, base, map, cfi, cfi->device_type, NULL);
 		cfi_send_gen_cmd(0x90, 0x555, base, map, cfi, cfi->device_type, NULL);
 		cfi->mfr = cfi_read_query(map, base);
-		cfi->id = cfi_read_query(map, base + ofs_factor);
+		cfi->id = cfi_read_query(map, base + ofs_factor);    
 
 		/* Wheee. Bring me the head of someone at AMD. */
 #ifdef AMD_BOOTLOC_BUG
@@ -135,7 +137,6 @@
 	}		
 	
 	map->fldrv = &cfi_amdstd_chipdrv;
-	MOD_INC_USE_COUNT;
 
 	cfi_send_gen_cmd(0xf0, 0x55, base, map, cfi, cfi->device_type, NULL);
 	return cfi_amdstd_setup(map);
@@ -148,12 +149,12 @@
 	unsigned long devsize = (1<<cfi->cfiq->DevSize) * cfi->interleave;
 
 	mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
-	printk(KERN_NOTICE "number of %s chips: %d\n", (cfi->cfi_mode)?"CFI":"JEDEC",cfi->numchips);
+	printk(KERN_NOTICE "number of %s chips: %d\n", 
+		(cfi->cfi_mode == CFI_MODE_CFI)?"CFI":"JEDEC",cfi->numchips);
 
 	if (!mtd) {
 	  printk(KERN_WARNING "Failed to allocate memory for MTD device\n");
-	  kfree(cfi->cmdset_priv);
-	  return NULL;
+	  goto setup_err;
 	}
 
 	memset(mtd, 0, sizeof(*mtd));
@@ -173,8 +174,7 @@
 		mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) * mtd->numeraseregions, GFP_KERNEL);
 		if (!mtd->eraseregions) { 
 			printk(KERN_WARNING "Failed to allocate memory for MTD erase region info\n");
-			kfree(cfi->cmdset_priv);
-			return NULL;
+			goto setup_err;
 		}
 			
 		for (i=0; i<cfi->cfiq->NumEraseRegions; i++) {
@@ -195,9 +195,7 @@
 		if (offset != devsize) {
 			/* Argh */
 			printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize);
-			kfree(mtd->eraseregions);
-			kfree(cfi->cmdset_priv);
-			return NULL;
+			goto setup_err;
 		}
 #if 0
 		// debug
@@ -220,6 +218,9 @@
 			mtd->erase = cfi_amdstd_erase_varsize;
 		else
 #endif
+		if (((cfi->cfiq->EraseRegionInfo[0] & 0xffff) + 1) == 1)
+			mtd->erase = cfi_amdstd_erase_chip;
+		else
 			mtd->erase = cfi_amdstd_erase_onesize;
 		mtd->read = cfi_amdstd_read;
 		mtd->write = cfi_amdstd_write;
@@ -227,11 +228,38 @@
 
 	default:
 	        printk(KERN_WARNING "Unsupported buswidth\n");
-		kfree(mtd);
-		kfree(cfi->cmdset_priv);
-		return NULL;
+		goto setup_err;
 		break;
 	}
+	if (cfi->fast_prog) {
+		/* In cfi_amdstd_write() we frob the protection stuff
+		   without paying any attention to the state machine.
+		   This upsets in-progress erases. So we turn this flag
+		   off for now till the code gets fixed. */
+		printk(KERN_NOTICE "cfi_cmdset_0002: Disabling fast programming due to code brokenness.\n");
+		cfi->fast_prog = 0;
+	}
+
+
+        /* does this chip have a secsi area? */
+	if(cfi->mfr==1){
+		
+		switch(cfi->id){
+		case 0x50:
+		case 0x53:
+		case 0x55:
+		case 0x56:
+		case 0x5C:
+		case 0x5F:
+			/* Yes */
+			mtd->read_user_prot_reg = cfi_amdstd_secsi_read;
+			mtd->read_fact_prot_reg = cfi_amdstd_secsi_read;
+		default:		       
+			;
+		}
+	}
+	
+		
 	mtd->sync = cfi_amdstd_sync;
 	mtd->suspend = cfi_amdstd_suspend;
 	mtd->resume = cfi_amdstd_resume;
@@ -240,6 +268,16 @@
 	mtd->name = map->name;
 	MOD_INC_USE_COUNT;
 	return mtd;
+
+ setup_err:
+	if(mtd) {
+		if(mtd->eraseregions)
+			kfree(mtd->eraseregions);
+		kfree(mtd);
+	}
+	kfree(cfi->cmdset_priv);
+	kfree(cfi->cfiq);
+	return NULL;
 }
 
 static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
@@ -323,11 +361,104 @@
 	return ret;
 }
 
+static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	unsigned long timeo = jiffies + HZ;
+	struct cfi_private *cfi = map->fldrv_priv;
+
+ retry:
+	cfi_spin_lock(chip->mutex);
+
+	if (chip->state != FL_READY){
+#if 0
+	        printk(KERN_DEBUG "Waiting for chip to read, status = %d\n", chip->state);
+#endif
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		add_wait_queue(&chip->wq, &wait);
+                
+		cfi_spin_unlock(chip->mutex);
+
+		schedule();
+		remove_wait_queue(&chip->wq, &wait);
+#if 0
+		if(signal_pending(current))
+			return -EINTR;
+#endif
+		timeo = jiffies + HZ;
+
+		goto retry;
+	}	
+
+	adr += chip->start;
+
+	chip->state = FL_READY;
+	
+	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
+	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
+	cfi_send_gen_cmd(0x88, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
+	
+	map->copy_from(map, buf, adr, len);
+
+	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
+	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
+	cfi_send_gen_cmd(0x90, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
+	cfi_send_gen_cmd(0x00, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
+	
+	wake_up(&chip->wq);
+	cfi_spin_unlock(chip->mutex);
+
+	return 0;
+}
+
+static int cfi_amdstd_secsi_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	unsigned long ofs;
+	int chipnum;
+	int ret = 0;
+
+
+	/* ofs: offset within the first chip that the first read should start */
+
+	/* 8 secsi bytes per chip */
+	chipnum=from>>3;
+	ofs=from & 7;
+
+
+	*retlen = 0;
+
+	while (len) {
+		unsigned long thislen;
+
+		if (chipnum >= cfi->numchips)
+			break;
+
+		if ((len + ofs -1) >> 3)
+			thislen = (1<<3) - ofs;
+		else
+			thislen = len;
+
+		ret = do_read_secsi_onechip(map, &cfi->chips[chipnum], ofs, thislen, buf);
+		if (ret)
+			break;
+
+		*retlen += thislen;
+		len -= thislen;
+		buf += thislen;
+
+		ofs = 0;
+		chipnum++;
+	}
+	return ret;
+}
+
 static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, __u32 datum, int fast)
 {
 	unsigned long timeo = jiffies + HZ;
-	unsigned int Last[4];
-	unsigned long Count = 0;
+	unsigned int oldstatus, status;
+	unsigned int dq6, dq5;	
 	struct cfi_private *cfi = map->fldrv_priv;
 	DECLARE_WAITQUEUE(wait, current);
 	int ret = 0;
@@ -335,7 +466,7 @@
  retry:
 	cfi_spin_lock(chip->mutex);
 
-	if (chip->state != FL_READY){
+	if (chip->state != FL_READY) {
 #if 0
 	        printk(KERN_DEBUG "Waiting for chip to write, status = %d\n", chip->state);
 #endif
@@ -375,33 +506,63 @@
 	cfi_udelay(chip->word_write_time);
 	cfi_spin_lock(chip->mutex);
 
-	Last[0] = cfi_read(map, adr);
-	//	printk("Last[0] is %x\n", Last[0]);
-	Last[1] = cfi_read(map, adr);
-	//	printk("Last[1] is %x\n", Last[1]);
-	Last[2] = cfi_read(map, adr);
-	//	printk("Last[2] is %x\n", Last[2]);
-
-	for (Count = 3; Last[(Count - 1) % 4] != Last[(Count - 2) % 4] && Count < 10000; Count++){
-		cfi_spin_unlock(chip->mutex);
-		cfi_udelay(10);
-		cfi_spin_lock(chip->mutex);
+	/* Polling toggle bits instead of reading back many times
+	   This ensures that write operation is really completed,
+	   or tells us why it failed. */        
+	dq6 = CMD(1<<6);
+	dq5 = CMD(1<<5);
+	timeo = jiffies + (HZ/1000); /* setting timeout to 1ms for now */
 		
-	        Last[Count % 4] = cfi_read(map, adr);
-		//		printk("Last[%d%%4] is %x\n", Count, Last[Count%4]);
+	oldstatus = cfi_read(map, adr);
+	status = cfi_read(map, adr);
+
+	while( (status & dq6) != (oldstatus & dq6) && 
+	       (status & dq5) != dq5 &&
+	       !time_after(jiffies, timeo) ) {
+
+		if (need_resched()) {
+			cfi_spin_unlock(chip->mutex);
+			yield();
+			cfi_spin_lock(chip->mutex);
+		} else 
+			udelay(1);
+
+		oldstatus = cfi_read( map, adr );
+		status = cfi_read( map, adr );
 	}
 	
-	if (Last[(Count - 1) % 4] != datum){
-		printk(KERN_WARNING "Last[%ld] is %x, datum is %x\n",(Count - 1) % 4,Last[(Count - 1) % 4],datum);
-	        cfi_send_gen_cmd(0xF0, 0, chip->start, map, cfi, cfi->device_type, NULL);
-		DISABLE_VPP(map);
-		ret = -EIO;
-	}       
+	if( (status & dq6) != (oldstatus & dq6) ) {
+		/* The erasing didn't stop?? */
+		if( (status & dq5) == dq5 ) {
+			/* When DQ5 raises, we must check once again
+			   if DQ6 is toggling.  If not, the erase has been
+			   completed OK.  If not, reset chip. */
+			oldstatus = cfi_read(map, adr);
+			status = cfi_read(map, adr);
+		    
+			if ( (oldstatus & 0x00FF) == (status & 0x00FF) ) {
+				printk(KERN_WARNING "Warning: DQ5 raised while program operation was in progress, however operation completed OK\n" );
+			} else { 
+				/* DQ5 is active so we can do a reset and stop the erase */
+				cfi_write(map, CMD(0xF0), chip->start);
+				printk(KERN_WARNING "Internal flash device timeout occurred or write operation was performed while flash was programming.\n" );
+			}
+		} else {
+			printk(KERN_WARNING "Waiting for write to complete timed out in do_write_oneword.");        
+			
+			chip->state = FL_READY;
+			wake_up(&chip->wq);
+			cfi_spin_unlock(chip->mutex);
+			DISABLE_VPP(map);
+			ret = -EIO;
+		}
+	}
+
 	DISABLE_VPP(map);
 	chip->state = FL_READY;
 	wake_up(&chip->wq);
 	cfi_spin_unlock(chip->mutex);
-	
+
 	return ret;
 }
 
@@ -458,10 +619,12 @@
 		}
 	}
 	
-	/* Go into unlock bypass mode */
-	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);
-	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);
-	cfi_send_gen_cmd(0x20, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);
+	if (cfi->fast_prog) {
+		/* Go into unlock bypass mode */
+		cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);
+		cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);
+		cfi_send_gen_cmd(0x20, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);
+	}
 
 	/* We are now aligned, write as much as possible */
 	while(len >= CFIDEV_BUSWIDTH) {
@@ -519,6 +682,7 @@
 		cfi_send_gen_cmd(0x00, 0, chipstart, map, cfi, cfi->device_type, NULL);
 	}
 
+	/* Write the trailing bytes if any */
 	if (len & (CFIDEV_BUSWIDTH-1)) {
 		int i = 0, n = 0;
 		u_char tmp_buf[4];
@@ -547,12 +711,139 @@
 	return 0;
 }
 
+static inline int do_erase_chip(struct map_info *map, struct flchip *chip)
+{
+	unsigned int oldstatus, status;
+	unsigned int dq6, dq5;
+	unsigned long timeo = jiffies + HZ;
+	unsigned int adr;
+	struct cfi_private *cfi = map->fldrv_priv;
+	DECLARE_WAITQUEUE(wait, current);
+
+ retry:
+	cfi_spin_lock(chip->mutex);
+
+	if (chip->state != FL_READY){
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		add_wait_queue(&chip->wq, &wait);
+                
+		cfi_spin_unlock(chip->mutex);
+
+		schedule();
+		remove_wait_queue(&chip->wq, &wait);
+#if 0
+		if(signal_pending(current))
+			return -EINTR;
+#endif
+		timeo = jiffies + HZ;
+
+		goto retry;
+	}	
+
+	chip->state = FL_ERASING;
+	
+	/* Handle devices with one erase region, that only implement
+	 * the chip erase command.
+	 */
+	ENABLE_VPP(map);
+	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
+	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
+	cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
+	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
+	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
+	cfi_send_gen_cmd(0x10, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
+	timeo = jiffies + (HZ*20);
+	adr = cfi->addr_unlock1;
+
+	/* Wait for the end of programing/erasure by using the toggle method.
+	 * As long as there is a programming procedure going on, bit 6 of the last
+	 * written byte is toggling it's state with each consectuve read.
+	 * The toggling stops as soon as the procedure is completed.
+	 *
+	 * If the process has gone on for too long on the chip bit 5 gets.
+	 * After bit5 is set you can kill the operation by sending a reset
+	 * command to the chip.
+	 */
+	dq6 = CMD(1<<6);
+	dq5 = CMD(1<<5);
+
+	oldstatus = cfi_read(map, adr);
+	status = cfi_read(map, adr);
+	while( ((status & dq6) != (oldstatus & dq6)) && 
+		((status & dq5) != dq5) &&
+		!time_after(jiffies, timeo)) {
+		int wait_reps;
+
+		/* an initial short sleep */
+		cfi_spin_unlock(chip->mutex);
+		schedule_timeout(HZ/100);
+		cfi_spin_lock(chip->mutex);
+		
+		if (chip->state != FL_ERASING) {
+			/* Someone's suspended the erase. Sleep */
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			add_wait_queue(&chip->wq, &wait);
+			
+			cfi_spin_unlock(chip->mutex);
+			printk("erase suspended. Sleeping\n");
+			
+			schedule();
+			remove_wait_queue(&chip->wq, &wait);
+#if 0			
+			if (signal_pending(current))
+				return -EINTR;
+#endif			
+			timeo = jiffies + (HZ*2); /* FIXME */
+			cfi_spin_lock(chip->mutex);
+			continue;
+		}
+
+		/* Busy wait for 1/10 of a milisecond */
+		for(wait_reps = 0;
+		    	(wait_reps < 100) &&
+			((status & dq6) != (oldstatus & dq6)) && 
+			((status & dq5) != dq5);
+			wait_reps++) {
+			
+			/* Latency issues. Drop the lock, wait a while and retry */
+			cfi_spin_unlock(chip->mutex);
+			
+			cfi_udelay(1);
+		
+			cfi_spin_lock(chip->mutex);
+			oldstatus = cfi_read(map, adr);
+			status = cfi_read(map, adr);
+		}
+		oldstatus = cfi_read(map, adr);
+		status = cfi_read(map, adr);
+	}
+	if ((status & dq6) != (oldstatus & dq6)) {
+		/* The erasing didn't stop?? */
+		if ((status & dq5) == dq5) {
+			/* dq5 is active so we can do a reset and stop the erase */
+			cfi_write(map, CMD(0xF0), chip->start);
+		}
+		chip->state = FL_READY;
+		wake_up(&chip->wq);
+		cfi_spin_unlock(chip->mutex);
+		printk("waiting for erase to complete timed out.");
+		DISABLE_VPP(map);
+		return -EIO;
+	}
+	DISABLE_VPP(map);
+	chip->state = FL_READY;
+	wake_up(&chip->wq);
+	cfi_spin_unlock(chip->mutex);
+
+	return 0;
+}
+
 static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr)
 {
-	unsigned int status;
+	unsigned int oldstatus, status;
+	unsigned int dq6, dq5;
 	unsigned long timeo = jiffies + HZ;
 	struct cfi_private *cfi = map->fldrv_priv;
-	unsigned int rdy_mask;
 	DECLARE_WAITQUEUE(wait, current);
 
  retry:
@@ -588,18 +879,30 @@
 	
 	timeo = jiffies + (HZ*20);
 
-	cfi_spin_unlock(chip->mutex);
-	schedule_timeout(HZ);
-	cfi_spin_lock(chip->mutex);
-	
-	rdy_mask = CMD(0x80);
-
-	/* FIXME. Use a timer to check this, and return immediately. */
-	/* Once the state machine's known to be working I'll do that */
+	/* Wait for the end of programing/erasure by using the toggle method.
+	 * As long as there is a programming procedure going on, bit 6 of the last
+	 * written byte is toggling it's state with each consectuve read.
+	 * The toggling stops as soon as the procedure is completed.
+	 *
+	 * If the process has gone on for too long on the chip bit 5 gets.
+	 * After bit5 is set you can kill the operation by sending a reset
+	 * command to the chip.
+	 */
+	dq6 = CMD(1<<6);
+	dq5 = CMD(1<<5);
 
-	while ( ( (status = cfi_read(map,adr)) & rdy_mask ) != rdy_mask ) {
-		static int z=0;
+	oldstatus = cfi_read(map, adr);
+	status = cfi_read(map, adr);
+	while( ((status & dq6) != (oldstatus & dq6)) && 
+		((status & dq5) != dq5) &&
+		!time_after(jiffies, timeo)) {
+		int wait_reps;
 
+		/* an initial short sleep */
+		cfi_spin_unlock(chip->mutex);
+		schedule_timeout(HZ/100);
+		cfi_spin_lock(chip->mutex);
+		
 		if (chip->state != FL_ERASING) {
 			/* Someone's suspended the erase. Sleep */
 			set_current_state(TASK_UNINTERRUPTIBLE);
@@ -619,29 +922,58 @@
 			continue;
 		}
 
-		/* OK Still waiting */
-		if (time_after(jiffies, timeo)) {
-			chip->state = FL_READY;
+		/* Busy wait for 1/10 of a milisecond */
+		for(wait_reps = 0;
+		    	(wait_reps < 100) &&
+			((status & dq6) != (oldstatus & dq6)) && 
+			((status & dq5) != dq5);
+			wait_reps++) {
+			
+			/* Latency issues. Drop the lock, wait a while and retry */
 			cfi_spin_unlock(chip->mutex);
-			printk(KERN_WARNING "waiting for erase to complete timed out.");
-			DISABLE_VPP(map);
-			return -EIO;
-		}
+			
+			cfi_udelay(1);
 		
-		/* Latency issues. Drop the lock, wait a while and retry */
+			cfi_spin_lock(chip->mutex);
+			oldstatus = cfi_read(map, adr);
+			status = cfi_read(map, adr);
+		}
+		oldstatus = cfi_read(map, adr);
+		status = cfi_read(map, adr);
+	}
+	if( (status & dq6) != (oldstatus & dq6) ) 
+	{                                       
+		/* The erasing didn't stop?? */
+		if( ( status & dq5 ) == dq5 ) 
+		{   			
+			/* When DQ5 raises, we must check once again if DQ6 is toggling.
+               If not, the erase has been completed OK.  If not, reset chip. */
+		    oldstatus   = cfi_read( map, adr );
+		    status      = cfi_read( map, adr );
+		    
+		    if( ( oldstatus & 0x00FF ) == ( status & 0x00FF ) )
+		    {
+                printk( "Warning: DQ5 raised while erase operation was in progress, but erase completed OK\n" ); 		    
+		    } 			
+			else
+            {
+			    /* DQ5 is active so we can do a reset and stop the erase */
+				cfi_write(map, CMD(0xF0), chip->start);
+                printk( KERN_WARNING "Internal flash device timeout occured or write operation was performed while flash was erasing\n" );
+			}
+		}
+        else
+        {
+		    printk( "Waiting for erase to complete timed out in do_erase_oneblock.");        
+		    
+		chip->state = FL_READY;
+		wake_up(&chip->wq);
 		cfi_spin_unlock(chip->mutex);
-
-		z++;
-		if ( 0 && !(z % 100 )) 
-			printk(KERN_WARNING "chip not ready yet after erase. looping\n");
-
-		cfi_udelay(1);
-		
-		cfi_spin_lock(chip->mutex);
-		continue;
+		DISABLE_VPP(map);
+		return -EIO;
 	}
-	
-	/* Done and happy. */
+	}
+
 	DISABLE_VPP(map);
 	chip->state = FL_READY;
 	wake_up(&chip->wq);
@@ -786,6 +1118,29 @@
 	return 0;
 }
 
+static int cfi_amdstd_erase_chip(struct mtd_info *mtd, struct erase_info *instr)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	int ret = 0;
+
+	if (instr->addr != 0)
+		return -EINVAL;
+
+	if (instr->len != mtd->size)
+		return -EINVAL;
+
+	ret = do_erase_chip(map, &cfi->chips[0]);
+	if (ret)
+		return ret;
+
+	instr->state = MTD_ERASE_DONE;
+	if (instr->callback)
+		instr->callback(instr);
+	
+	return 0;
+}
+
 static void cfi_amdstd_sync (struct mtd_info *mtd)
 {
 	struct map_info *map = mtd->priv;
@@ -853,7 +1208,6 @@
 	int i;
 	struct flchip *chip;
 	int ret = 0;
-//printk("suspend\n");
 
 	for (i=0; !ret && i<cfi->numchips; i++) {
 		chip = &cfi->chips[i];
@@ -906,7 +1260,6 @@
 	struct cfi_private *cfi = map->fldrv_priv;
 	int i;
 	struct flchip *chip;
-//printk("resume\n");
 
 	for (i=0; i<cfi->numchips; i++) {
 	
@@ -931,7 +1284,9 @@
 	struct map_info *map = mtd->priv;
 	struct cfi_private *cfi = map->fldrv_priv;
 	kfree(cfi->cmdset_priv);
+	kfree(cfi->cfiq);
 	kfree(cfi);
+	kfree(mtd->eraseregions);
 }
 
 static char im_name[]="cfi_cmdset_0002";
@@ -953,3 +1308,4 @@
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Crossnet Co. <info@crossnet.co.jp> et al.");
 MODULE_DESCRIPTION("MTD chip driver for AMD/Fujitsu flash chips");
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/chips/cfi_cmdset_0020.c linux-2.4.21-pre6/drivers/mtd/chips/cfi_cmdset_0020.c
--- linux-2.4.20/drivers/mtd/chips/cfi_cmdset_0020.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/chips/cfi_cmdset_0020.c	2003-03-26 23:49:24.000000000 +0000
@@ -0,0 +1,1451 @@
+/*
+ * Common Flash Interface support:
+ *   ST Advanced Architecture Command Set (ID 0x0020)
+ *
+ * (C) 2000 Red Hat. GPL'd
+ *
+ * 
+ * 10/10/2000	Nicolas Pitre <nico@cam.org>
+ * 	- completely revamped method functions so they are aware and
+ * 	  independent of the flash geometry (buswidth, interleave, etc.)
+ * 	- scalability vs code size is completely set at compile-time
+ * 	  (see include/linux/mtd/cfi.h for selection)
+ *	- optimized write buffer method
+ * 06/21/2002	Joern Engel <joern@wh.fh-wedel.de> and others
+ *	- modified Intel Command Set 0x0001 to support ST Advanced Architecture
+ *	  (command set 0x0020)
+ *	- added a writev function
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <asm/io.h>
+#include <asm/byteorder.h>
+
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/cfi.h>
+#include <linux/mtd/compatmac.h>
+
+
+static int cfi_staa_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *);
+static int cfi_staa_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
+static int cfi_staa_writev(struct mtd_info *mtd, const struct iovec *vecs,
+		unsigned long count, loff_t to, size_t *retlen);
+static int cfi_staa_erase_varsize(struct mtd_info *, struct erase_info *);
+static void cfi_staa_sync (struct mtd_info *);
+static int cfi_staa_lock(struct mtd_info *mtd, loff_t ofs, size_t len);
+static int cfi_staa_unlock(struct mtd_info *mtd, loff_t ofs, size_t len);
+static int cfi_staa_suspend (struct mtd_info *);
+static void cfi_staa_resume (struct mtd_info *);
+
+static void cfi_staa_destroy(struct mtd_info *);
+
+struct mtd_info *cfi_cmdset_0020(struct map_info *, int);
+
+static struct mtd_info *cfi_staa_setup (struct map_info *);
+
+static struct mtd_chip_driver cfi_staa_chipdrv = {
+	probe: NULL, /* Not usable directly */
+	destroy: cfi_staa_destroy,
+	name: "cfi_cmdset_0020",
+	module: THIS_MODULE
+};
+
+/* #define DEBUG_LOCK_BITS */
+//#define DEBUG_CFI_FEATURES
+
+#ifdef DEBUG_CFI_FEATURES
+static void cfi_tell_features(struct cfi_pri_intelext *extp)
+{
+        int i;
+        printk("  Feature/Command Support: %4.4X\n", extp->FeatureSupport);
+	printk("     - Chip Erase:         %s\n", extp->FeatureSupport&1?"supported":"unsupported");
+	printk("     - Suspend Erase:      %s\n", extp->FeatureSupport&2?"supported":"unsupported");
+	printk("     - Suspend Program:    %s\n", extp->FeatureSupport&4?"supported":"unsupported");
+	printk("     - Legacy Lock/Unlock: %s\n", extp->FeatureSupport&8?"supported":"unsupported");
+	printk("     - Queued Erase:       %s\n", extp->FeatureSupport&16?"supported":"unsupported");
+	printk("     - Instant block lock: %s\n", extp->FeatureSupport&32?"supported":"unsupported");
+	printk("     - Protection Bits:    %s\n", extp->FeatureSupport&64?"supported":"unsupported");
+	printk("     - Page-mode read:     %s\n", extp->FeatureSupport&128?"supported":"unsupported");
+	printk("     - Synchronous read:   %s\n", extp->FeatureSupport&256?"supported":"unsupported");
+	for (i=9; i<32; i++) {
+		if (extp->FeatureSupport & (1<<i)) 
+			printk("     - Unknown Bit %X:      supported\n", i);
+	}
+	
+	printk("  Supported functions after Suspend: %2.2X\n", extp->SuspendCmdSupport);
+	printk("     - Program after Erase Suspend: %s\n", extp->SuspendCmdSupport&1?"supported":"unsupported");
+	for (i=1; i<8; i++) {
+		if (extp->SuspendCmdSupport & (1<<i))
+			printk("     - Unknown Bit %X:               supported\n", i);
+	}
+	
+	printk("  Block Status Register Mask: %4.4X\n", extp->BlkStatusRegMask);
+	printk("     - Lock Bit Active:      %s\n", extp->BlkStatusRegMask&1?"yes":"no");
+	printk("     - Valid Bit Active:     %s\n", extp->BlkStatusRegMask&2?"yes":"no");
+	for (i=2; i<16; i++) {
+		if (extp->BlkStatusRegMask & (1<<i))
+			printk("     - Unknown Bit %X Active: yes\n",i);
+	}
+	
+	printk("  Vcc Logic Supply Optimum Program/Erase Voltage: %d.%d V\n", 
+	       extp->VccOptimal >> 8, extp->VccOptimal & 0xf);
+	if (extp->VppOptimal)
+		printk("  Vpp Programming Supply Optimum Program/Erase Voltage: %d.%d V\n", 
+		       extp->VppOptimal >> 8, extp->VppOptimal & 0xf);
+}
+#endif
+
+/* This routine is made available to other mtd code via
+ * inter_module_register.  It must only be accessed through
+ * inter_module_get which will bump the use count of this module.  The
+ * addresses passed back in cfi are valid as long as the use count of
+ * this module is non-zero, i.e. between inter_module_get and
+ * inter_module_put.  Keith Owens <kaos@ocs.com.au> 29 Oct 2000.
+ */
+struct mtd_info *cfi_cmdset_0020(struct map_info *map, int primary)
+{
+	struct cfi_private *cfi = map->fldrv_priv;
+	int i;
+	__u32 base = cfi->chips[0].start;
+
+	if (cfi->cfi_mode) {
+		/* 
+		 * It's a real CFI chip, not one for which the probe
+		 * routine faked a CFI structure. So we read the feature
+		 * table from it.
+		 */
+		__u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR;
+		struct cfi_pri_intelext *extp;
+		int ofs_factor = cfi->interleave * cfi->device_type;
+
+                printk(" ST Microelectronics Extended Query Table at 0x%4.4X\n", adr);
+		if (!adr)
+			return NULL;
+
+		/* Switch it into Query Mode */
+		cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
+
+		extp = kmalloc(sizeof(*extp), GFP_KERNEL);
+		if (!extp) {
+			printk(KERN_ERR "Failed to allocate memory\n");
+			return NULL;
+		}
+		
+		/* Read in the Extended Query Table */
+		for (i=0; i<sizeof(*extp); i++) {
+			((unsigned char *)extp)[i] = 
+				cfi_read_query(map, (base+((adr+i)*ofs_factor)));
+		}
+		
+		if (extp->MajorVersion != '1' || 
+                    (extp->MinorVersion < '0' || extp->MinorVersion > '2')) {
+                    printk(KERN_WARNING "  Unknown staa Extended Query "
+                           "version %c.%c.\n",  extp->MajorVersion,
+                           extp->MinorVersion);
+                    kfree(extp);
+                    return NULL;
+		}
+		
+		/* Do some byteswapping if necessary */
+		extp->FeatureSupport = cfi32_to_cpu(extp->FeatureSupport);
+		extp->BlkStatusRegMask = cfi32_to_cpu(extp->BlkStatusRegMask);
+		
+#ifdef DEBUG_CFI_FEATURES
+		/* Tell the user about it in lots of lovely detail */
+		cfi_tell_features(extp);
+#endif	
+
+		/* Install our own private info structure */
+		cfi->cmdset_priv = extp;
+	}	
+
+	for (i=0; i< cfi->numchips; i++) {
+		cfi->chips[i].word_write_time = 128;
+		cfi->chips[i].buffer_write_time = 128;
+		cfi->chips[i].erase_time = 1024;
+	}		
+
+	map->fldrv = &cfi_staa_chipdrv;
+	MOD_INC_USE_COUNT;
+	
+	/* Make sure it's in read mode */
+	cfi_send_gen_cmd(0xff, 0x55, base, map, cfi, cfi->device_type, NULL);
+	return cfi_staa_setup(map);
+}
+
+static struct mtd_info *cfi_staa_setup(struct map_info *map)
+{
+	struct cfi_private *cfi = map->fldrv_priv;
+	struct mtd_info *mtd;
+	unsigned long offset = 0;
+	int i,j;
+	unsigned long devsize = (1<<cfi->cfiq->DevSize) * cfi->interleave;
+
+	mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
+	//printk(KERN_DEBUG "number of CFI chips: %d\n", cfi->numchips);
+
+	if (!mtd) {
+		printk(KERN_ERR "Failed to allocate memory for MTD device\n");
+		kfree(cfi->cmdset_priv);
+		return NULL;
+	}
+
+	memset(mtd, 0, sizeof(*mtd));
+	mtd->priv = map;
+	mtd->type = MTD_NORFLASH;
+	mtd->size = devsize * cfi->numchips;
+
+	mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips;
+	mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) 
+			* mtd->numeraseregions, GFP_KERNEL);
+	if (!mtd->eraseregions) { 
+		printk(KERN_ERR "Failed to allocate memory for MTD erase region info\n");
+		kfree(cfi->cmdset_priv);
+		return NULL;
+	}
+	
+	for (i=0; i<cfi->cfiq->NumEraseRegions; i++) {
+		unsigned long ernum, ersize;
+		ersize = ((cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff) * cfi->interleave;
+		ernum = (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1;
+
+		if (mtd->erasesize < ersize) {
+			mtd->erasesize = ersize;
+		}
+		for (j=0; j<cfi->numchips; j++) {
+			mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].offset = (j*devsize)+offset;
+			mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].erasesize = ersize;
+			mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum;
+		}
+		offset += (ersize * ernum);
+		}
+
+		if (offset != devsize) {
+			/* Argh */
+			printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize);
+			kfree(mtd->eraseregions);
+			kfree(cfi->cmdset_priv);
+			return NULL;
+		}
+
+		for (i=0; i<mtd->numeraseregions;i++){
+			printk(KERN_DEBUG "%d: offset=0x%x,size=0x%x,blocks=%d\n",
+			       i,mtd->eraseregions[i].offset,
+			       mtd->eraseregions[i].erasesize,
+			       mtd->eraseregions[i].numblocks);
+		}
+
+	/* Also select the correct geometry setup too */ 
+	mtd->erase = cfi_staa_erase_varsize;
+	mtd->read = cfi_staa_read;
+        mtd->write = cfi_staa_write_buffers;
+	mtd->writev = cfi_staa_writev;
+	mtd->sync = cfi_staa_sync;
+	mtd->lock = cfi_staa_lock;
+	mtd->unlock = cfi_staa_unlock;
+	mtd->suspend = cfi_staa_suspend;
+	mtd->resume = cfi_staa_resume;
+	mtd->flags = MTD_CAP_NORFLASH;
+	mtd->flags |= MTD_ECC; /* FIXME: Not all STMicro flashes have this */
+	mtd->eccsize = 8; /* FIXME: Should be 0 for STMicro flashes w/out ECC */
+	map->fldrv = &cfi_staa_chipdrv;
+	MOD_INC_USE_COUNT;
+	mtd->name = map->name;
+	return mtd;
+}
+
+
+static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
+{
+	__u32 status, status_OK;
+	unsigned long timeo;
+	DECLARE_WAITQUEUE(wait, current);
+	int suspended = 0;
+	unsigned long cmd_addr;
+	struct cfi_private *cfi = map->fldrv_priv;
+
+	adr += chip->start;
+
+	/* Ensure cmd read/writes are aligned. */ 
+	cmd_addr = adr & ~(CFIDEV_BUSWIDTH-1); 
+
+	/* Let's determine this according to the interleave only once */
+	status_OK = CMD(0x80);
+
+	timeo = jiffies + HZ;
+ retry:
+	spin_lock_bh(chip->mutex);
+
+	/* Check that the chip's ready to talk to us.
+	 * If it's in FL_ERASING state, suspend it and make it talk now.
+	 */
+	switch (chip->state) {
+	case FL_ERASING:
+		if (!((struct cfi_pri_intelext *)cfi->cmdset_priv)->FeatureSupport & 2)
+			goto sleep; /* We don't support erase suspend */
+		
+		cfi_write (map, CMD(0xb0), cmd_addr);
+		/* If the flash has finished erasing, then 'erase suspend'
+		 * appears to make some (28F320) flash devices switch to
+		 * 'read' mode.  Make sure that we switch to 'read status'
+		 * mode so we get the right data. --rmk
+		 */
+		cfi_write(map, CMD(0x70), cmd_addr);
+		chip->oldstate = FL_ERASING;
+		chip->state = FL_ERASE_SUSPENDING;
+		//		printk("Erase suspending at 0x%lx\n", cmd_addr);
+		for (;;) {
+			status = cfi_read(map, cmd_addr);
+			if ((status & status_OK) == status_OK)
+				break;
+			
+			if (time_after(jiffies, timeo)) {
+				/* Urgh */
+				cfi_write(map, CMD(0xd0), cmd_addr);
+				/* make sure we're in 'read status' mode */
+				cfi_write(map, CMD(0x70), cmd_addr);
+				chip->state = FL_ERASING;
+				spin_unlock_bh(chip->mutex);
+				printk(KERN_ERR "Chip not ready after erase "
+				       "suspended: status = 0x%x\n", status);
+				return -EIO;
+			}
+			
+			spin_unlock_bh(chip->mutex);
+			cfi_udelay(1);
+			spin_lock_bh(chip->mutex);
+		}
+		
+		suspended = 1;
+		cfi_write(map, CMD(0xff), cmd_addr);
+		chip->state = FL_READY;
+		break;
+	
+#if 0
+	case FL_WRITING:
+		/* Not quite yet */
+#endif
+
+	case FL_READY:
+		break;
+
+	case FL_CFI_QUERY:
+	case FL_JEDEC_QUERY:
+		cfi_write(map, CMD(0x70), cmd_addr);
+		chip->state = FL_STATUS;
+
+	case FL_STATUS:
+		status = cfi_read(map, cmd_addr);
+		if ((status & status_OK) == status_OK) {
+			cfi_write(map, CMD(0xff), cmd_addr);
+			chip->state = FL_READY;
+			break;
+		}
+		
+		/* Urgh. Chip not yet ready to talk to us. */
+		if (time_after(jiffies, timeo)) {
+			spin_unlock_bh(chip->mutex);
+			printk(KERN_ERR "waiting for chip to be ready timed out in read. WSM status = %x\n", status);
+			return -EIO;
+		}
+
+		/* Latency issues. Drop the lock, wait a while and retry */
+		spin_unlock_bh(chip->mutex);
+		cfi_udelay(1);
+		goto retry;
+
+	default:
+	sleep:
+		/* Stick ourselves on a wait queue to be woken when
+		   someone changes the status */
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		add_wait_queue(&chip->wq, &wait);
+		spin_unlock_bh(chip->mutex);
+		schedule();
+		remove_wait_queue(&chip->wq, &wait);
+		timeo = jiffies + HZ;
+		goto retry;
+	}
+
+	map->copy_from(map, buf, adr, len);
+
+	if (suspended) {
+		chip->state = chip->oldstate;
+		/* What if one interleaved chip has finished and the 
+		   other hasn't? The old code would leave the finished
+		   one in READY mode. That's bad, and caused -EROFS 
+		   errors to be returned from do_erase_oneblock because
+		   that's the only bit it checked for at the time.
+		   As the state machine appears to explicitly allow 
+		   sending the 0x70 (Read Status) command to an erasing
+		   chip and expecting it to be ignored, that's what we 
+		   do. */
+		cfi_write(map, CMD(0xd0), cmd_addr);
+		cfi_write(map, CMD(0x70), cmd_addr);		
+	}
+
+	wake_up(&chip->wq);
+	spin_unlock_bh(chip->mutex);
+	return 0;
+}
+
+static int cfi_staa_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	unsigned long ofs;
+	int chipnum;
+	int ret = 0;
+
+	/* ofs: offset within the first chip that the first read should start */
+	chipnum = (from >> cfi->chipshift);
+	ofs = from - (chipnum <<  cfi->chipshift);
+
+	*retlen = 0;
+
+	while (len) {
+		unsigned long thislen;
+
+		if (chipnum >= cfi->numchips)
+			break;
+
+		if ((len + ofs -1) >> cfi->chipshift)
+			thislen = (1<<cfi->chipshift) - ofs;
+		else
+			thislen = len;
+
+		ret = do_read_onechip(map, &cfi->chips[chipnum], ofs, thislen, buf);
+		if (ret)
+			break;
+
+		*retlen += thislen;
+		len -= thislen;
+		buf += thislen;
+		
+		ofs = 0;
+		chipnum++;
+	}
+	return ret;
+}
+
+static inline int do_write_buffer(struct map_info *map, struct flchip *chip, 
+				  unsigned long adr, const u_char *buf, int len)
+{
+	struct cfi_private *cfi = map->fldrv_priv;
+	__u32 status, status_OK;
+	unsigned long cmd_adr, timeo;
+	DECLARE_WAITQUEUE(wait, current);
+	int wbufsize, z;
+        
+        /* M58LW064A requires bus alignment for buffer wriets -- saw */
+        if (adr & (CFIDEV_BUSWIDTH-1))
+            return -EINVAL;
+
+        wbufsize = CFIDEV_INTERLEAVE << cfi->cfiq->MaxBufWriteSize;
+        adr += chip->start;
+	cmd_adr = adr & ~(wbufsize-1);
+	
+	/* Let's determine this according to the interleave only once */
+        status_OK = CMD(0x80);
+        
+	timeo = jiffies + HZ;
+ retry:
+
+#ifdef DEBUG_CFI_FEATURES
+       printk("%s: chip->state[%d]\n", __FUNCTION__, chip->state);
+#endif
+	spin_lock_bh(chip->mutex);
+ 
+	/* Check that the chip's ready to talk to us.
+	 * Later, we can actually think about interrupting it
+	 * if it's in FL_ERASING state.
+	 * Not just yet, though.
+	 */
+	switch (chip->state) {
+	case FL_READY:
+		break;
+		
+	case FL_CFI_QUERY:
+	case FL_JEDEC_QUERY:
+		cfi_write(map, CMD(0x70), cmd_adr);
+                chip->state = FL_STATUS;
+#ifdef DEBUG_CFI_FEATURES
+        printk("%s: 1 status[%x]\n", __FUNCTION__, cfi_read(map, cmd_adr));
+#endif
+
+	case FL_STATUS:
+		status = cfi_read(map, cmd_adr);
+		if ((status & status_OK) == status_OK)
+			break;
+		/* Urgh. Chip not yet ready to talk to us. */
+		if (time_after(jiffies, timeo)) {
+			spin_unlock_bh(chip->mutex);
+                        printk(KERN_ERR "waiting for chip to be ready timed out in buffer write Xstatus = %x, status = %x\n",
+                               status, cfi_read(map, cmd_adr));
+			return -EIO;
+		}
+
+		/* Latency issues. Drop the lock, wait a while and retry */
+		spin_unlock_bh(chip->mutex);
+		cfi_udelay(1);
+		goto retry;
+
+	default:
+		/* Stick ourselves on a wait queue to be woken when
+		   someone changes the status */
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		add_wait_queue(&chip->wq, &wait);
+		spin_unlock_bh(chip->mutex);
+		schedule();
+		remove_wait_queue(&chip->wq, &wait);
+		timeo = jiffies + HZ;
+		goto retry;
+	}
+
+	ENABLE_VPP(map);
+	cfi_write(map, CMD(0xe8), cmd_adr);
+	chip->state = FL_WRITING_TO_BUFFER;
+
+	z = 0;
+	for (;;) {
+		status = cfi_read(map, cmd_adr);
+		if ((status & status_OK) == status_OK)
+			break;
+
+		spin_unlock_bh(chip->mutex);
+		cfi_udelay(1);
+		spin_lock_bh(chip->mutex);
+
+		if (++z > 100) {
+			/* Argh. Not ready for write to buffer */
+			DISABLE_VPP(map);
+                        cfi_write(map, CMD(0x70), cmd_adr);
+			chip->state = FL_STATUS;
+			spin_unlock_bh(chip->mutex);
+			printk(KERN_ERR "Chip not ready for buffer write. Xstatus = %x\n", status);
+			return -EIO;
+		}
+	}
+
+	/* Write length of data to come */
+	cfi_write(map, CMD(len/CFIDEV_BUSWIDTH-1), cmd_adr );
+        
+	/* Write data */
+	for (z = 0; z < len; z += CFIDEV_BUSWIDTH) {
+		if (cfi_buswidth_is_1()) {
+			map->write8 (map, *((__u8*)buf)++, adr+z);
+		} else if (cfi_buswidth_is_2()) {
+			map->write16 (map, *((__u16*)buf)++, adr+z);
+		} else if (cfi_buswidth_is_4()) {
+			map->write32 (map, *((__u32*)buf)++, adr+z);
+		} else {
+			DISABLE_VPP(map);
+			return -EINVAL;
+		}
+	}
+	/* GO GO GO */
+	cfi_write(map, CMD(0xd0), cmd_adr);
+	chip->state = FL_WRITING;
+
+	spin_unlock_bh(chip->mutex);
+	cfi_udelay(chip->buffer_write_time);
+	spin_lock_bh(chip->mutex);
+
+	timeo = jiffies + (HZ/2);
+	z = 0;
+	for (;;) {
+		if (chip->state != FL_WRITING) {
+			/* Someone's suspended the write. Sleep */
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			add_wait_queue(&chip->wq, &wait);
+			spin_unlock_bh(chip->mutex);
+			schedule();
+			remove_wait_queue(&chip->wq, &wait);
+			timeo = jiffies + (HZ / 2); /* FIXME */
+			spin_lock_bh(chip->mutex);
+			continue;
+		}
+
+		status = cfi_read(map, cmd_adr);
+		if ((status & status_OK) == status_OK)
+			break;
+
+		/* OK Still waiting */
+		if (time_after(jiffies, timeo)) {
+                        /* clear status */
+                        cfi_write(map, CMD(0x50), cmd_adr);
+                        /* put back into read status register mode */
+                        cfi_write(map, CMD(0x70), adr);
+			chip->state = FL_STATUS;
+			DISABLE_VPP(map);
+			spin_unlock_bh(chip->mutex);
+			printk(KERN_ERR "waiting for chip to be ready timed out in bufwrite\n");
+			return -EIO;
+		}
+		
+		/* Latency issues. Drop the lock, wait a while and retry */
+		spin_unlock_bh(chip->mutex);
+		cfi_udelay(1);
+		z++;
+		spin_lock_bh(chip->mutex);
+	}
+	if (!z) {
+		chip->buffer_write_time--;
+		if (!chip->buffer_write_time)
+			chip->buffer_write_time++;
+	}
+	if (z > 1) 
+		chip->buffer_write_time++;
+        
+	/* Done and happy. */
+	DISABLE_VPP(map);
+	chip->state = FL_STATUS;
+
+        /* check for errors: 'lock bit', 'VPP', 'dead cell'/'unerased cell' or 'incorrect cmd' -- saw */
+        if ((status & CMD(0x02)) || (status & CMD(0x08)) ||
+            (status & CMD(0x10)) || (status & CMD(0x20))) {
+#ifdef DEBUG_CFI_FEATURES
+            printk("%s: 2 status[%x]\n", __FUNCTION__, status);
+#endif
+            /* clear status */
+            cfi_write(map, CMD(0x50), cmd_adr);
+            /* put back into read status register mode */
+            cfi_write(map, CMD(0x70), adr);
+            wake_up(&chip->wq);
+            spin_unlock_bh(chip->mutex);
+            return (status & CMD(0x02)) ? -EROFS : -EIO;
+        }
+	wake_up(&chip->wq);
+	spin_unlock_bh(chip->mutex);
+
+        return 0;
+}
+
+static int cfi_staa_write_buffers (struct mtd_info *mtd, loff_t to, 
+				       size_t len, size_t *retlen, const u_char *buf)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	int wbufsize = CFIDEV_INTERLEAVE << cfi->cfiq->MaxBufWriteSize;
+	int ret = 0;
+	int chipnum;
+	unsigned long ofs;
+
+	*retlen = 0;
+	if (!len)
+		return 0;
+
+	chipnum = to >> cfi->chipshift;
+	ofs = to  - (chipnum << cfi->chipshift);
+
+#ifdef DEBUG_CFI_FEATURES
+        printk("%s: CFIDEV_BUSWIDTH[%x]\n", __FUNCTION__, CFIDEV_BUSWIDTH);
+        printk("%s: chipnum[%x] wbufsize[%x]\n", __FUNCTION__, chipnum, wbufsize);
+        printk("%s: ofs[%x] len[%x]\n", __FUNCTION__, ofs, len);
+#endif
+        
+        /* Write buffer is worth it only if more than one word to write... */
+        while (len > 0) {
+		/* We must not cross write block boundaries */
+		int size = wbufsize - (ofs & (wbufsize-1));
+
+                if (size > len)
+                    size = len;
+
+                ret = do_write_buffer(map, &cfi->chips[chipnum], 
+				      ofs, buf, size);
+		if (ret)
+			return ret;
+
+		ofs += size;
+		buf += size;
+		(*retlen) += size;
+		len -= size;
+
+		if (ofs >> cfi->chipshift) {
+			chipnum ++; 
+			ofs = 0;
+			if (chipnum == cfi->numchips)
+				return 0;
+		}
+	}
+        
+	return 0;
+}
+
+/*
+ * Writev for ECC-Flashes is a little more complicated. We need to maintain
+ * a small buffer for this.
+ * XXX: If the buffer size is not a multiple of 2, this will break
+ */
+#define ECCBUF_SIZE (mtd->eccsize)
+#define ECCBUF_DIV(x) ((x) & ~(ECCBUF_SIZE - 1))
+#define ECCBUF_MOD(x) ((x) &  (ECCBUF_SIZE - 1))
+static int
+cfi_staa_writev(struct mtd_info *mtd, const struct iovec *vecs,
+		unsigned long count, loff_t to, size_t *retlen)
+{
+	unsigned long i;
+	size_t	 totlen = 0, thislen;
+	int	 ret = 0;
+	size_t	 buflen = 0;
+	static char *buffer;
+
+	if (!ECCBUF_SIZE) {
+		/* We should fall back to a general writev implementation.
+		 * Until that is written, just break.
+		 */
+		return -EIO;
+	}
+	buffer = kmalloc(ECCBUF_SIZE, GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
+
+	for (i=0; i<count; i++) {
+		size_t elem_len = vecs[i].iov_len;
+		void *elem_base = vecs[i].iov_base;
+		if (!elem_len) /* FIXME: Might be unnecessary. Check that */
+			continue;
+		if (buflen) { /* cut off head */
+			if (buflen + elem_len < ECCBUF_SIZE) { /* just accumulate */
+				memcpy(buffer+buflen, elem_base, elem_len);
+				buflen += elem_len;
+				continue;
+			}
+			memcpy(buffer+buflen, elem_base, ECCBUF_SIZE-buflen);
+			ret = mtd->write(mtd, to, ECCBUF_SIZE, &thislen, buffer);
+			totlen += thislen;
+			if (ret || thislen != ECCBUF_SIZE)
+				goto write_error;
+			elem_len -= thislen-buflen;
+			elem_base += thislen-buflen;
+			to += ECCBUF_SIZE;
+		}
+		if (ECCBUF_DIV(elem_len)) { /* write clean aligned data */
+			ret = mtd->write(mtd, to, ECCBUF_DIV(elem_len), &thislen, elem_base);
+			totlen += thislen;
+			if (ret || thislen != ECCBUF_DIV(elem_len))
+				goto write_error;
+			to += thislen;
+		}
+		buflen = ECCBUF_MOD(elem_len); /* cut off tail */
+		if (buflen) {
+			memset(buffer, 0xff, ECCBUF_SIZE);
+			memcpy(buffer, elem_base + thislen, buflen);
+		}
+	}
+	if (buflen) { /* flush last page, even if not full */
+		/* This is sometimes intended behaviour, really */
+		ret = mtd->write(mtd, to, buflen, &thislen, buffer);
+		totlen += thislen;
+		if (ret || thislen != ECCBUF_SIZE)
+			goto write_error;
+	}
+write_error:
+	if (retlen)
+		*retlen = totlen;
+	return ret;
+}
+
+
+static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr)
+{
+	struct cfi_private *cfi = map->fldrv_priv;
+	__u32 status, status_OK;
+	unsigned long timeo;
+	int retries = 3;
+	DECLARE_WAITQUEUE(wait, current);
+	int ret = 0;
+
+	adr += chip->start;
+
+	/* Let's determine this according to the interleave only once */
+	status_OK = CMD(0x80);
+
+	timeo = jiffies + HZ;
+retry:
+	spin_lock_bh(chip->mutex);
+
+	/* Check that the chip's ready to talk to us. */
+	switch (chip->state) {
+	case FL_CFI_QUERY:
+	case FL_JEDEC_QUERY:
+	case FL_READY:
+		cfi_write(map, CMD(0x70), adr);
+		chip->state = FL_STATUS;
+
+	case FL_STATUS:
+		status = cfi_read(map, adr);
+		if ((status & status_OK) == status_OK)
+			break;
+		
+		/* Urgh. Chip not yet ready to talk to us. */
+		if (time_after(jiffies, timeo)) {
+			spin_unlock_bh(chip->mutex);
+			printk(KERN_ERR "waiting for chip to be ready timed out in erase\n");
+			return -EIO;
+		}
+
+		/* Latency issues. Drop the lock, wait a while and retry */
+		spin_unlock_bh(chip->mutex);
+		cfi_udelay(1);
+		goto retry;
+
+	default:
+		/* Stick ourselves on a wait queue to be woken when
+		   someone changes the status */
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		add_wait_queue(&chip->wq, &wait);
+		spin_unlock_bh(chip->mutex);
+		schedule();
+		remove_wait_queue(&chip->wq, &wait);
+		timeo = jiffies + HZ;
+		goto retry;
+	}
+
+	ENABLE_VPP(map);
+	/* Clear the status register first */
+	cfi_write(map, CMD(0x50), adr);
+
+	/* Now erase */
+	cfi_write(map, CMD(0x20), adr);
+	cfi_write(map, CMD(0xD0), adr);
+	chip->state = FL_ERASING;
+	
+	spin_unlock_bh(chip->mutex);
+	schedule_timeout(HZ);
+	spin_lock_bh(chip->mutex);
+
+	/* FIXME. Use a timer to check this, and return immediately. */
+	/* Once the state machine's known to be working I'll do that */
+
+	timeo = jiffies + (HZ*20);
+	for (;;) {
+		if (chip->state != FL_ERASING) {
+			/* Someone's suspended the erase. Sleep */
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			add_wait_queue(&chip->wq, &wait);
+			spin_unlock_bh(chip->mutex);
+			schedule();
+			remove_wait_queue(&chip->wq, &wait);
+			timeo = jiffies + (HZ*20); /* FIXME */
+			spin_lock_bh(chip->mutex);
+			continue;
+		}
+
+		status = cfi_read(map, adr);
+		if ((status & status_OK) == status_OK)
+			break;
+		
+		/* OK Still waiting */
+		if (time_after(jiffies, timeo)) {
+			cfi_write(map, CMD(0x70), adr);
+			chip->state = FL_STATUS;
+			printk(KERN_ERR "waiting for erase to complete timed out. Xstatus = %x, status = %x.\n", status, cfi_read(map, adr));
+			DISABLE_VPP(map);
+			spin_unlock_bh(chip->mutex);
+			return -EIO;
+		}
+		
+		/* Latency issues. Drop the lock, wait a while and retry */
+		spin_unlock_bh(chip->mutex);
+		cfi_udelay(1);
+		spin_lock_bh(chip->mutex);
+	}
+	
+	DISABLE_VPP(map);
+	ret = 0;
+
+	/* We've broken this before. It doesn't hurt to be safe */
+	cfi_write(map, CMD(0x70), adr);
+	chip->state = FL_STATUS;
+	status = cfi_read(map, adr);
+
+	/* check for lock bit */
+	if (status & CMD(0x3a)) {
+		unsigned char chipstatus = status;
+		if (status != CMD(status & 0xff)) {
+			int i;
+			for (i = 1; i<CFIDEV_INTERLEAVE; i++) {
+				      chipstatus |= status >> (cfi->device_type * 8);
+			}
+			printk(KERN_WARNING "Status is not identical for all chips: 0x%x. Merging to give 0x%02x\n", status, chipstatus);
+		}
+		/* Reset the error bits */
+		cfi_write(map, CMD(0x50), adr);
+		cfi_write(map, CMD(0x70), adr);
+		
+		if ((chipstatus & 0x30) == 0x30) {
+			printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%x\n", status);
+			ret = -EIO;
+		} else if (chipstatus & 0x02) {
+			/* Protection bit set */
+			ret = -EROFS;
+		} else if (chipstatus & 0x8) {
+			/* Voltage */
+			printk(KERN_WARNING "Chip reports voltage low on erase: status 0x%x\n", status);
+			ret = -EIO;
+		} else if (chipstatus & 0x20) {
+			if (retries--) {
+				printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x. Retrying...\n", adr, status);
+				timeo = jiffies + HZ;
+				chip->state = FL_STATUS;
+				spin_unlock_bh(chip->mutex);
+				goto retry;
+			}
+			printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x\n", adr, status);
+			ret = -EIO;
+		}
+	}
+
+	wake_up(&chip->wq);
+	spin_unlock_bh(chip->mutex);
+	return ret;
+}
+
+int cfi_staa_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
+{	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	unsigned long adr, len;
+	int chipnum, ret = 0;
+	int i, first;
+	struct mtd_erase_region_info *regions = mtd->eraseregions;
+
+	if (instr->addr > mtd->size)
+		return -EINVAL;
+
+	if ((instr->len + instr->addr) > mtd->size)
+		return -EINVAL;
+
+	/* Check that both start and end of the requested erase are
+	 * aligned with the erasesize at the appropriate addresses.
+	 */
+
+	i = 0;
+
+	/* Skip all erase regions which are ended before the start of 
+	   the requested erase. Actually, to save on the calculations,
+	   we skip to the first erase region which starts after the
+	   start of the requested erase, and then go back one.
+	*/
+	
+	while (i < mtd->numeraseregions && instr->addr >= regions[i].offset)
+	       i++;
+	i--;
+
+	/* OK, now i is pointing at the erase region in which this 
+	   erase request starts. Check the start of the requested
+	   erase range is aligned with the erase size which is in
+	   effect here.
+	*/
+
+	if (instr->addr & (regions[i].erasesize-1))
+		return -EINVAL;
+
+	/* Remember the erase region we start on */
+	first = i;
+
+	/* Next, check that the end of the requested erase is aligned
+	 * with the erase region at that address.
+	 */
+
+	while (i<mtd->numeraseregions && (instr->addr + instr->len) >= regions[i].offset)
+		i++;
+
+	/* As before, drop back one to point at the region in which
+	   the address actually falls
+	*/
+	i--;
+	
+	if ((instr->addr + instr->len) & (regions[i].erasesize-1))
+		return -EINVAL;
+
+	chipnum = instr->addr >> cfi->chipshift;
+	adr = instr->addr - (chipnum << cfi->chipshift);
+	len = instr->len;
+
+	i=first;
+
+	while(len) {
+		ret = do_erase_oneblock(map, &cfi->chips[chipnum], adr);
+		
+		if (ret)
+			return ret;
+
+		adr += regions[i].erasesize;
+		len -= regions[i].erasesize;
+
+		if (adr % (1<< cfi->chipshift) == ((regions[i].offset + (regions[i].erasesize * regions[i].numblocks)) %( 1<< cfi->chipshift)))
+			i++;
+
+		if (adr >> cfi->chipshift) {
+			adr = 0;
+			chipnum++;
+			
+			if (chipnum >= cfi->numchips)
+			break;
+		}
+	}
+		
+	instr->state = MTD_ERASE_DONE;
+	if (instr->callback)
+		instr->callback(instr);
+	
+	return 0;
+}
+
+static void cfi_staa_sync (struct mtd_info *mtd)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	int i;
+	struct flchip *chip;
+	int ret = 0;
+	DECLARE_WAITQUEUE(wait, current);
+
+	for (i=0; !ret && i<cfi->numchips; i++) {
+		chip = &cfi->chips[i];
+
+	retry:
+		spin_lock_bh(chip->mutex);
+
+		switch(chip->state) {
+		case FL_READY:
+		case FL_STATUS:
+		case FL_CFI_QUERY:
+		case FL_JEDEC_QUERY:
+			chip->oldstate = chip->state;
+			chip->state = FL_SYNCING;
+			/* No need to wake_up() on this state change - 
+			 * as the whole point is that nobody can do anything
+			 * with the chip now anyway.
+			 */
+		case FL_SYNCING:
+			spin_unlock_bh(chip->mutex);
+			break;
+
+		default:
+			/* Not an idle state */
+			add_wait_queue(&chip->wq, &wait);
+			
+			spin_unlock_bh(chip->mutex);
+			schedule();
+		        remove_wait_queue(&chip->wq, &wait);
+			
+			goto retry;
+		}
+	}
+
+	/* Unlock the chips again */
+
+	for (i--; i >=0; i--) {
+		chip = &cfi->chips[i];
+
+		spin_lock_bh(chip->mutex);
+		
+		if (chip->state == FL_SYNCING) {
+			chip->state = chip->oldstate;
+			wake_up(&chip->wq);
+		}
+		spin_unlock_bh(chip->mutex);
+	}
+}
+
+static inline int do_lock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr)
+{
+	struct cfi_private *cfi = map->fldrv_priv;
+	__u32 status, status_OK;
+	unsigned long timeo = jiffies + HZ;
+	DECLARE_WAITQUEUE(wait, current);
+
+	adr += chip->start;
+
+	/* Let's determine this according to the interleave only once */
+	status_OK = CMD(0x80);
+
+	timeo = jiffies + HZ;
+retry:
+	spin_lock_bh(chip->mutex);
+
+	/* Check that the chip's ready to talk to us. */
+	switch (chip->state) {
+	case FL_CFI_QUERY:
+	case FL_JEDEC_QUERY:
+	case FL_READY:
+		cfi_write(map, CMD(0x70), adr);
+		chip->state = FL_STATUS;
+
+	case FL_STATUS:
+		status = cfi_read(map, adr);
+		if ((status & status_OK) == status_OK) 
+			break;
+		
+		/* Urgh. Chip not yet ready to talk to us. */
+		if (time_after(jiffies, timeo)) {
+			spin_unlock_bh(chip->mutex);
+			printk(KERN_ERR "waiting for chip to be ready timed out in lock\n");
+			return -EIO;
+		}
+
+		/* Latency issues. Drop the lock, wait a while and retry */
+		spin_unlock_bh(chip->mutex);
+		cfi_udelay(1);
+		goto retry;
+
+	default:
+		/* Stick ourselves on a wait queue to be woken when
+		   someone changes the status */
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		add_wait_queue(&chip->wq, &wait);
+		spin_unlock_bh(chip->mutex);
+		schedule();
+		remove_wait_queue(&chip->wq, &wait);
+		timeo = jiffies + HZ;
+		goto retry;
+	}
+
+	ENABLE_VPP(map);
+	cfi_write(map, CMD(0x60), adr);
+	cfi_write(map, CMD(0x01), adr);
+	chip->state = FL_LOCKING;
+	
+	spin_unlock_bh(chip->mutex);
+	schedule_timeout(HZ);
+	spin_lock_bh(chip->mutex);
+
+	/* FIXME. Use a timer to check this, and return immediately. */
+	/* Once the state machine's known to be working I'll do that */
+
+	timeo = jiffies + (HZ*2);
+	for (;;) {
+
+		status = cfi_read(map, adr);
+		if ((status & status_OK) == status_OK)
+			break;
+		
+		/* OK Still waiting */
+		if (time_after(jiffies, timeo)) {
+			cfi_write(map, CMD(0x70), adr);
+			chip->state = FL_STATUS;
+			printk(KERN_ERR "waiting for lock to complete timed out. Xstatus = %x, status = %x.\n", status, cfi_read(map, adr));
+			DISABLE_VPP(map);
+			spin_unlock_bh(chip->mutex);
+			return -EIO;
+		}
+		
+		/* Latency issues. Drop the lock, wait a while and retry */
+		spin_unlock_bh(chip->mutex);
+		cfi_udelay(1);
+		spin_lock_bh(chip->mutex);
+	}
+	
+	/* Done and happy. */
+	chip->state = FL_STATUS;
+	DISABLE_VPP(map);
+	wake_up(&chip->wq);
+	spin_unlock_bh(chip->mutex);
+	return 0;
+}
+static int cfi_staa_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	unsigned long adr;
+	int chipnum, ret = 0;
+#ifdef DEBUG_LOCK_BITS
+	int ofs_factor = cfi->interleave * cfi->device_type;
+#endif
+
+	if (ofs & (mtd->erasesize - 1))
+		return -EINVAL;
+
+	if (len & (mtd->erasesize -1))
+		return -EINVAL;
+
+	if ((len + ofs) > mtd->size)
+		return -EINVAL;
+
+	chipnum = ofs >> cfi->chipshift;
+	adr = ofs - (chipnum << cfi->chipshift);
+
+	while(len) {
+
+#ifdef DEBUG_LOCK_BITS
+		cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
+		printk("before lock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor)));
+		cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);
+#endif
+
+		ret = do_lock_oneblock(map, &cfi->chips[chipnum], adr);
+
+#ifdef DEBUG_LOCK_BITS
+		cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
+		printk("after lock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor)));
+		cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);
+#endif	
+		
+		if (ret)
+			return ret;
+
+		adr += mtd->erasesize;
+		len -= mtd->erasesize;
+
+		if (adr >> cfi->chipshift) {
+			adr = 0;
+			chipnum++;
+			
+			if (chipnum >= cfi->numchips)
+			break;
+		}
+	}
+	return 0;
+}
+static inline int do_unlock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr)
+{
+	struct cfi_private *cfi = map->fldrv_priv;
+	__u32 status, status_OK;
+	unsigned long timeo = jiffies + HZ;
+	DECLARE_WAITQUEUE(wait, current);
+
+	adr += chip->start;
+
+	/* Let's determine this according to the interleave only once */
+	status_OK = CMD(0x80);
+
+	timeo = jiffies + HZ;
+retry:
+	spin_lock_bh(chip->mutex);
+
+	/* Check that the chip's ready to talk to us. */
+	switch (chip->state) {
+	case FL_CFI_QUERY:
+	case FL_JEDEC_QUERY:
+	case FL_READY:
+		cfi_write(map, CMD(0x70), adr);
+		chip->state = FL_STATUS;
+
+	case FL_STATUS:
+		status = cfi_read(map, adr);
+		if ((status & status_OK) == status_OK)
+			break;
+		
+		/* Urgh. Chip not yet ready to talk to us. */
+		if (time_after(jiffies, timeo)) {
+			spin_unlock_bh(chip->mutex);
+			printk(KERN_ERR "waiting for chip to be ready timed out in unlock\n");
+			return -EIO;
+		}
+
+		/* Latency issues. Drop the lock, wait a while and retry */
+		spin_unlock_bh(chip->mutex);
+		cfi_udelay(1);
+		goto retry;
+
+	default:
+		/* Stick ourselves on a wait queue to be woken when
+		   someone changes the status */
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		add_wait_queue(&chip->wq, &wait);
+		spin_unlock_bh(chip->mutex);
+		schedule();
+		remove_wait_queue(&chip->wq, &wait);
+		timeo = jiffies + HZ;
+		goto retry;
+	}
+
+	ENABLE_VPP(map);
+	cfi_write(map, CMD(0x60), adr);
+	cfi_write(map, CMD(0xD0), adr);
+	chip->state = FL_UNLOCKING;
+	
+	spin_unlock_bh(chip->mutex);
+	schedule_timeout(HZ);
+	spin_lock_bh(chip->mutex);
+
+	/* FIXME. Use a timer to check this, and return immediately. */
+	/* Once the state machine's known to be working I'll do that */
+
+	timeo = jiffies + (HZ*2);
+	for (;;) {
+
+		status = cfi_read(map, adr);
+		if ((status & status_OK) == status_OK)
+			break;
+		
+		/* OK Still waiting */
+		if (time_after(jiffies, timeo)) {
+			cfi_write(map, CMD(0x70), adr);
+			chip->state = FL_STATUS;
+			printk(KERN_ERR "waiting for unlock to complete timed out. Xstatus = %x, status = %x.\n", status, cfi_read(map, adr));
+			DISABLE_VPP(map);
+			spin_unlock_bh(chip->mutex);
+			return -EIO;
+		}
+		
+		/* Latency issues. Drop the unlock, wait a while and retry */
+		spin_unlock_bh(chip->mutex);
+		cfi_udelay(1);
+		spin_lock_bh(chip->mutex);
+	}
+	
+	/* Done and happy. */
+	chip->state = FL_STATUS;
+	DISABLE_VPP(map);
+	wake_up(&chip->wq);
+	spin_unlock_bh(chip->mutex);
+	return 0;
+}
+static int cfi_staa_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	unsigned long adr;
+	int chipnum, ret = 0;
+#ifdef DEBUG_LOCK_BITS
+	int ofs_factor = cfi->interleave * cfi->device_type;
+#endif
+
+	chipnum = ofs >> cfi->chipshift;
+	adr = ofs - (chipnum << cfi->chipshift);
+
+#ifdef DEBUG_LOCK_BITS
+	{
+		unsigned long temp_adr = adr;
+		unsigned long temp_len = len;
+                 
+		cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
+                while (temp_len) {
+			printk("before unlock %x: block status register is %x\n",temp_adr,cfi_read_query(map, temp_adr+(2*ofs_factor)));
+			temp_adr += mtd->erasesize;
+			temp_len -= mtd->erasesize;
+		}
+		cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);
+	}
+#endif
+
+	ret = do_unlock_oneblock(map, &cfi->chips[chipnum], adr);
+
+#ifdef DEBUG_LOCK_BITS
+	cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
+	printk("after unlock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor)));
+	cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);
+#endif
+	
+	return ret;
+}
+
+static int cfi_staa_suspend(struct mtd_info *mtd)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	int i;
+	struct flchip *chip;
+	int ret = 0;
+
+	for (i=0; !ret && i<cfi->numchips; i++) {
+		chip = &cfi->chips[i];
+
+		spin_lock_bh(chip->mutex);
+
+		switch(chip->state) {
+		case FL_READY:
+		case FL_STATUS:
+		case FL_CFI_QUERY:
+		case FL_JEDEC_QUERY:
+			chip->oldstate = chip->state;
+			chip->state = FL_PM_SUSPENDED;
+			/* No need to wake_up() on this state change - 
+			 * as the whole point is that nobody can do anything
+			 * with the chip now anyway.
+			 */
+		case FL_PM_SUSPENDED:
+			break;
+
+		default:
+			ret = -EAGAIN;
+			break;
+		}
+		spin_unlock_bh(chip->mutex);
+	}
+
+	/* Unlock the chips again */
+
+	if (ret) {
+		for (i--; i >=0; i--) {
+			chip = &cfi->chips[i];
+			
+			spin_lock_bh(chip->mutex);
+			
+			if (chip->state == FL_PM_SUSPENDED) {
+				/* No need to force it into a known state here,
+				   because we're returning failure, and it didn't
+				   get power cycled */
+				chip->state = chip->oldstate;
+				wake_up(&chip->wq);
+			}
+			spin_unlock_bh(chip->mutex);
+		}
+	} 
+	
+	return ret;
+}
+
+static void cfi_staa_resume(struct mtd_info *mtd)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	int i;
+	struct flchip *chip;
+
+	for (i=0; i<cfi->numchips; i++) {
+	
+		chip = &cfi->chips[i];
+
+		spin_lock_bh(chip->mutex);
+		
+		/* Go to known state. Chip may have been power cycled */
+		if (chip->state == FL_PM_SUSPENDED) {
+			cfi_write(map, CMD(0xFF), 0);
+			chip->state = FL_READY;
+			wake_up(&chip->wq);
+		}
+
+		spin_unlock_bh(chip->mutex);
+	}
+}
+
+static void cfi_staa_destroy(struct mtd_info *mtd)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	kfree(cfi->cmdset_priv);
+	kfree(cfi);
+}
+
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
+#define cfi_staa_init init_module
+#define cfi_staa_exit cleanup_module
+#endif
+
+static char im_name[]="cfi_cmdset_0020";
+
+mod_init_t cfi_staa_init(void)
+{
+	inter_module_register(im_name, THIS_MODULE, &cfi_cmdset_0020);
+	return 0;
+}
+
+mod_exit_t cfi_staa_exit(void)
+{
+	inter_module_unregister(im_name);
+}
+
+module_init(cfi_staa_init);
+module_exit(cfi_staa_exit);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/chips/cfi_probe.c linux-2.4.21-pre6/drivers/mtd/chips/cfi_probe.c
--- linux-2.4.20/drivers/mtd/chips/cfi_probe.c	2001-10-04 22:14:59.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/chips/cfi_probe.c	2003-03-26 23:49:51.000000000 +0000
@@ -1,7 +1,7 @@
 /* 
    Common Flash Interface probe code.
    (C) 2000 Red Hat. GPL'd.
-   $Id: cfi_probe.c,v 1.66 2001/10/02 15:05:12 dwmw2 Exp $
+   $Id: cfi_probe.c,v 1.69 2002/05/11 22:13:03 dwmw2 Exp $
 */
 
 #include <linux/config.h>
@@ -24,16 +24,13 @@
 static void print_cfi_ident(struct cfi_ident *);
 #endif
 
-int cfi_jedec_setup(struct cfi_private *p_cfi, int index);
-int cfi_jedec_lookup(int index, int mfr_id, int dev_id);
-
 static int cfi_probe_chip(struct map_info *map, __u32 base,
 			  struct flchip *chips, struct cfi_private *cfi);
 static int cfi_chip_setup(struct map_info *map, struct cfi_private *cfi);
 
 struct mtd_info *cfi_probe(struct map_info *map);
 
-/* check for QRY, or search for jedec id.
+/* check for QRY.
    in: interleave,type,mode
    ret: table index, <0 for error
  */
@@ -55,6 +52,18 @@
 {
 	int i;
 	
+	if ((base + 0) >= map->size) {
+		printk(KERN_NOTICE
+			"Probe at base[0x00](0x%08lx) past the end of the map(0x%08lx)\n",
+			(unsigned long)base, map->size -1);
+		return 0;
+	}
+	if ((base + 0xff) >= map->size) {
+		printk(KERN_NOTICE
+			"Probe at base[0x55](0x%08lx) past the end of the map(0x%08lx)\n",
+			(unsigned long)base + 0x55, map->size -1);
+		return 0;
+	}
 	cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
 	cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
 
@@ -139,7 +148,7 @@
 	
 	memset(cfi->cfiq,0,sizeof(struct cfi_ident));	
 	
-	cfi->cfi_mode = 1;
+	cfi->cfi_mode = CFI_MODE_CFI;
 	cfi->fast_prog=1;		/* CFI supports fast programming */
 	
 	/* Read the CFI info structure */
@@ -250,11 +259,11 @@
 	else
 		printk("Full buffer write not supported\n");
 	
-	printk("Typical block erase timeout: %d µs\n", 1<<cfip->BlockEraseTimeoutTyp);
-	printk("Maximum block erase timeout: %d µs\n", (1<<cfip->BlockEraseTimeoutMax) * (1<<cfip->BlockEraseTimeoutTyp));
+	printk("Typical block erase timeout: %d ms\n", 1<<cfip->BlockEraseTimeoutTyp);
+	printk("Maximum block erase timeout: %d ms\n", (1<<cfip->BlockEraseTimeoutMax) * (1<<cfip->BlockEraseTimeoutTyp));
 	if (cfip->ChipEraseTimeoutTyp || cfip->ChipEraseTimeoutMax) {
-		printk("Typical chip erase timeout: %d µs\n", 1<<cfip->ChipEraseTimeoutTyp); 
-		printk("Maximum chip erase timeout: %d µs\n", (1<<cfip->ChipEraseTimeoutMax) * (1<<cfip->ChipEraseTimeoutTyp));
+		printk("Typical chip erase timeout: %d ms\n", 1<<cfip->ChipEraseTimeoutTyp); 
+		printk("Maximum chip erase timeout: %d ms\n", (1<<cfip->ChipEraseTimeoutMax) * (1<<cfip->ChipEraseTimeoutTyp));
 	}
 	else
 		printk("Chip erase not supported\n");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/chips/chipreg.c linux-2.4.21-pre6/drivers/mtd/chips/chipreg.c
--- linux-2.4.20/drivers/mtd/chips/chipreg.c	2001-10-04 22:14:59.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/chips/chipreg.c	2003-03-26 23:49:26.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * $Id: chipreg.c,v 1.12 2001/10/02 15:29:53 dwmw2 Exp $
+ * $Id: chipreg.c,v 1.13 2002/02/21 08:26:58 dwmw2 Exp $
  *
  * Registration for chip drivers
  *
@@ -29,7 +29,7 @@
 	spin_unlock(&chip_drvs_lock);
 }
 
-static struct mtd_chip_driver *get_mtd_chip_driver (char *name)
+static struct mtd_chip_driver *get_mtd_chip_driver (const char *name)
 {
 	struct list_head *pos;
 	struct mtd_chip_driver *ret = NULL, *this;
@@ -57,7 +57,7 @@
 	/* Hide all the horrid details, like some silly person taking
 	   get_module_symbol() away from us, from the caller. */
 
-struct mtd_info *do_map_probe(char *name, struct map_info *map)
+struct mtd_info *do_map_probe(const char *name, struct map_info *map)
 {
 	struct mtd_chip_driver *drv;
 	struct mtd_info *ret;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/chips/gen_probe.c linux-2.4.21-pre6/drivers/mtd/chips/gen_probe.c
--- linux-2.4.20/drivers/mtd/chips/gen_probe.c	2001-10-04 22:14:59.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/chips/gen_probe.c	2003-03-26 23:49:54.000000000 +0000
@@ -2,7 +2,7 @@
  * Routines common to all CFI-type probes.
  * (C) 2001, 2001 Red Hat, Inc.
  * GPL'd
- * $Id: gen_probe.c,v 1.5 2001/10/02 15:05:12 dwmw2 Exp $
+ * $Id: gen_probe.c,v 1.9 2002/09/05 05:15:32 acurtis Exp $
  */
 
 #include <linux/kernel.h>
@@ -38,7 +38,7 @@
 	if (mtd)
 		return mtd;
 
-	printk(KERN_WARNING"cfi_probe: No supported Vendor Command Set found\n");
+	printk(KERN_WARNING"gen_probe: No supported Vendor Command Set found\n");
 	
 	kfree(cfi->cfiq);
 	kfree(cfi);
@@ -106,6 +106,12 @@
 	 * Now probe for other chips, checking sensibly for aliases while
 	 * we're at it. The new_chip probe above should have let the first
 	 * chip in read mode.
+	 *
+	 * NOTE: Here, we're checking if there is room for another chip
+	 *       the same size within the mapping. Therefore, 
+	 *       base + chipsize <= map->size is the correct thing to do, 
+	 *       because, base + chipsize would be the  _first_ byte of the
+	 *       next chip, not the one we're currently pondering.
 	 */
 
 	for (base = (1<<cfi.chipshift); base + (1<<cfi.chipshift) <= map->size;
@@ -224,6 +230,41 @@
 		break;
 #endif /* CFIDEV_BUSWIDTH_4 */
 
+#ifdef CFIDEV_BUSWIDTH_8
+	case CFIDEV_BUSWIDTH_8:
+#if defined(CFIDEV_INTERLEAVE_2) && defined(SOMEONE_ACTUALLY_MAKES_THESE)
+                cfi->interleave = CFIDEV_INTERLEAVE_2;
+
+                cfi->device_type = CFI_DEVICETYPE_X32;
+		if (cp->probe_chip(map, 0, NULL, cfi))
+			return 1;
+#endif /* CFIDEV_INTERLEAVE_2 */
+#ifdef CFIDEV_INTERLEAVE_4
+		cfi->interleave = CFIDEV_INTERLEAVE_4;
+
+#ifdef SOMEONE_ACTUALLY_MAKES_THESE
+		cfi->device_type = CFI_DEVICETYPE_X32;
+		if (cp->probe_chip(map, 0, NULL, cfi))
+			return 1;
+#endif
+		cfi->device_type = CFI_DEVICETYPE_X16;
+		if (cp->probe_chip(map, 0, NULL, cfi))
+			return 1;
+#endif /* CFIDEV_INTERLEAVE_4 */
+#ifdef CFIDEV_INTERLEAVE_8
+		cfi->interleave = CFIDEV_INTERLEAVE_8;
+
+		cfi->device_type = CFI_DEVICETYPE_X16;
+		if (cp->probe_chip(map, 0, NULL, cfi))
+			return 1;
+
+		cfi->device_type = CFI_DEVICETYPE_X8;
+		if (cp->probe_chip(map, 0, NULL, cfi))
+			return 1;
+#endif /* CFIDEV_INTERLEAVE_8 */
+		break;
+#endif /* CFIDEV_BUSWIDTH_8 */
+
 	default:
 		printk(KERN_WARNING "genprobe_new_chip called with unsupported buswidth %d\n", map->buswidth);
 		return 0;
@@ -289,6 +330,10 @@
 	case 0x0002:
 		return cfi_cmdset_0002(map, primary);
 #endif
+#ifdef CONFIG_MTD_CFI_STAA
+        case 0x0020:
+		return cfi_cmdset_0020(map, primary);
+#endif
 	}
 
 	return cfi_cmdset_unknown(map, primary);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/chips/jedec.c linux-2.4.21-pre6/drivers/mtd/chips/jedec.c
--- linux-2.4.20/drivers/mtd/chips/jedec.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/chips/jedec.c	2003-03-26 23:49:40.000000000 +0000
@@ -11,7 +11,7 @@
  * not going to guess how to send commands to them, plus I expect they will
  * all speak CFI..
  *
- * $Id: jedec.c,v 1.13 2002/02/08 15:57:21 rkaiser Exp $
+ * $Id: jedec.c,v 1.14 2002/06/27 02:19:12 dwmw2 Exp $
  */
 
 #include <linux/mtd/jedec.h>
@@ -465,8 +465,8 @@
       we call this routine with the JEDEC return still enabled, if two or
       more flashes have a truncated address space the probe test will still
       work */
-   if (base + Size+0x555 < map->size &&
-       base + Size+0x555 < (base & (~(my_bank_size-1))) + my_bank_size)
+   if (base + (Size<<2)+0x555 < map->size &&
+       base + (Size<<2)+0x555 < (base & (~(my_bank_size-1))) + my_bank_size)
    {
       if (flread(base+Size) != flread(base+Size + 0x100) ||
 	  flread(base+Size + 1) != flread(base+Size + 0x101))
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/chips/jedec_probe.c linux-2.4.21-pre6/drivers/mtd/chips/jedec_probe.c
--- linux-2.4.20/drivers/mtd/chips/jedec_probe.c	2001-11-09 22:29:40.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/chips/jedec_probe.c	2003-03-26 23:49:37.000000000 +0000
@@ -1,7 +1,9 @@
 /* 
    Common Flash Interface probe code.
    (C) 2000 Red Hat. GPL'd.
-   $Id: jedec_probe.c,v 1.3 2001/10/02 15:05:12 dwmw2 Exp $
+   $Id: jedec_probe.c,v 1.19 2002/11/12 13:12:10 dwmw2 Exp $
+   See JEDEC (http://www.jedec.org/) standard JESD21C (section 3.5)
+   for the standard this probe goes back to.
 */
 
 #include <linux/config.h>
@@ -18,15 +20,17 @@
 #include <linux/mtd/cfi.h>
 #include <linux/mtd/gen_probe.h>
 
-
 /* Manufacturers */
 #define MANUFACTURER_AMD	0x0001
-#define MANUFACTURER_FUJITSU	0x0004
 #define MANUFACTURER_ATMEL	0x001f
+#define MANUFACTURER_FUJITSU	0x0004
+#define MANUFACTURER_INTEL	0x0089
+#define MANUFACTURER_MACRONIX	0x00C2
 #define MANUFACTURER_ST		0x0020
 #define MANUFACTURER_SST	0x00BF
 #define MANUFACTURER_TOSHIBA	0x0098
 
+
 /* AMD */
 #define AM29F800BB	0x2258
 #define AM29F800BT	0x22D6
@@ -34,27 +38,89 @@
 #define AM29LV800BT	0x22DA
 #define AM29LV160DT	0x22C4
 #define AM29LV160DB	0x2249
+#define AM29F017D	0x003D
+#define AM29F016	0x00AD
+#define AM29F080	0x00D5
+#define AM29F040	0x00A4
+#define AM29LV040B	0x004F
+#define AM29F032B	0x0041
 
 /* Atmel */
-#define AT49BV16X4	0x00c0
-#define AT49BV16X4T	0x00c2
+#define AT49BV512	0x0003
+#define AT29LV512	0x003d
+#define AT49BV16X	0x00C0
+#define AT49BV16XT	0x00C2
+#define AT49BV32X	0x00C8
+#define AT49BV32XT	0x00C9
 
 /* Fujitsu */
+#define MBM29LV650UE	0x22D7
+#define MBM29LV320TE	0x22F6
+#define MBM29LV320BE	0x22F9
 #define MBM29LV160TE	0x22C4
 #define MBM29LV160BE	0x2249
+#define MBM29LV800BA	0x225B
+#define MBM29LV800TA	0x22DA
+
+/* Intel */
+#define I28F004B3T	0x00d4
+#define I28F004B3B	0x00d5
+#define I28F400B3T	0x8894
+#define I28F400B3B	0x8895
+#define I28F008S5	0x00a6
+#define I28F016S5	0x00a0
+#define I28F008SA	0x00a2
+#define I28F008B3T	0x00d2
+#define I28F008B3B	0x00d3
+#define I28F800B3T	0x8892
+#define I28F800B3B	0x8893
+#define I28F016S3	0x00aa
+#define I28F016B3T	0x00d0
+#define I28F016B3B	0x00d1
+#define I28F160B3T	0x8890
+#define I28F160B3B	0x8891
+#define I28F320B3T	0x8896
+#define I28F320B3B	0x8897
+#define I28F640B3T	0x8898
+#define I28F640B3B	0x8899
+#define I82802AB	0x00ad
+#define I82802AC	0x00ac
+
+/* Macronix */
+#define MX29LV160T	0x22C4
+#define MX29LV160B	0x2249
+#define MX29F016	0x00AD
+#define MX29F004T	0x0045
+#define MX29F004B	0x0046
 
 /* ST - www.st.com */
 #define M29W800T	0x00D7
 #define M29W160DT	0x22C4
 #define M29W160DB	0x2249
+#define M29W040B	0x00E3
 
 /* SST */
+#define SST29EE512	0x005d
+#define SST29LE512	0x003d
 #define SST39LF800	0x2781
 #define SST39LF160	0x2782
+#define SST39LF512	0x00D4
+#define SST39LF010	0x00D5
+#define SST39LF020	0x00D6
+#define SST39LF040	0x00D7
+#define SST39SF010A	0x00B5
+#define SST39SF020A	0x00B6
+#define SST49LF030A	0x001C
+#define SST49LF040A	0x0051
+#define SST49LF080A	0x005B
 
 /* Toshiba */
 #define TC58FVT160	0x00C2
 #define TC58FVB160	0x0043
+#define TC58FVT321	0x009A
+#define TC58FVB321	0x009C
+#define TC58FVT641	0x0093
+#define TC58FVB641	0x0095
 
 
 struct amd_flash_info {
@@ -64,21 +130,37 @@
 	const int DevSize;
 	const int InterfaceDesc;
 	const int NumEraseRegions;
+	const int CmdSet;
 	const ulong regions[4];
 };
 
 #define ERASEINFO(size,blocks) (size<<8)|(blocks-1)
 
-#define SIZE_1MiB 20
-#define SIZE_2MiB 21
-#define SIZE_4MiB 22
+#define SIZE_64KiB  16
+#define SIZE_128KiB 17
+#define SIZE_256KiB 18
+#define SIZE_512KiB 19
+#define SIZE_1MiB   20
+#define SIZE_2MiB   21
+#define SIZE_4MiB   22
+#define SIZE_8MiB   23
 
 static const struct amd_flash_info jedec_table[] = {
 	{
 		mfr_id: MANUFACTURER_AMD,
+		dev_id: AM29F032B,
+		name: "AMD AM29F032B",
+		DevSize: SIZE_4MiB,
+		CmdSet:	P_ID_AMD_STD,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x10000,64)
+		}
+	}, {
+		mfr_id: MANUFACTURER_AMD,
 		dev_id: AM29LV160DT,
 		name: "AMD AM29LV160DT",
 		DevSize: SIZE_2MiB,
+		CmdSet:	P_ID_AMD_STD,
 		NumEraseRegions: 4,
 		regions: {ERASEINFO(0x10000,31),
 			  ERASEINFO(0x08000,1),
@@ -90,6 +172,7 @@
 		dev_id: AM29LV160DB,
 		name: "AMD AM29LV160DB",
 		DevSize: SIZE_2MiB,
+		CmdSet:	P_ID_AMD_STD,
 		NumEraseRegions: 4,
 		regions: {ERASEINFO(0x04000,1),
 			  ERASEINFO(0x02000,2),
@@ -101,6 +184,7 @@
 		dev_id: TC58FVT160,
 		name: "Toshiba TC58FVT160",
 		DevSize: SIZE_2MiB,
+		CmdSet:	P_ID_AMD_STD,
 		NumEraseRegions: 4,
 		regions: {ERASEINFO(0x10000,31),
 			  ERASEINFO(0x08000,1),
@@ -108,10 +192,92 @@
 			  ERASEINFO(0x04000,1)
 		}
 	}, {
+		mfr_id: MANUFACTURER_TOSHIBA,
+		dev_id: TC58FVB160,
+		name: "Toshiba TC58FVB160",
+		DevSize: SIZE_2MiB,
+		CmdSet:	P_ID_AMD_STD,
+		NumEraseRegions: 4,
+		regions: {ERASEINFO(0x04000,1),
+			  ERASEINFO(0x02000,2),
+			  ERASEINFO(0x08000,1),
+			  ERASEINFO(0x10000,31)
+		}
+	}, {
+		mfr_id: MANUFACTURER_TOSHIBA,
+		dev_id: TC58FVB321,
+		name: "Toshiba TC58FVB321",
+		DevSize: SIZE_4MiB,
+		CmdSet:	P_ID_AMD_STD,
+		NumEraseRegions: 2,
+		regions: {ERASEINFO(0x02000,8),
+			  ERASEINFO(0x10000,63)
+		}
+	}, {
+		mfr_id: MANUFACTURER_TOSHIBA,
+		dev_id: TC58FVT321,
+		name: "Toshiba TC58FVT321",
+		DevSize: SIZE_4MiB,
+		CmdSet:	P_ID_AMD_STD,
+		NumEraseRegions: 2,
+		regions: {ERASEINFO(0x10000,63),
+			  ERASEINFO(0x02000,8)
+		}
+	}, {
+		mfr_id: MANUFACTURER_TOSHIBA,
+		dev_id: TC58FVB641,
+		name: "Toshiba TC58FVB641",
+		DevSize: SIZE_8MiB,
+		CmdSet:	P_ID_AMD_STD,
+		NumEraseRegions: 2,
+		regions: {ERASEINFO(0x02000,8),
+			  ERASEINFO(0x10000,127)
+		}
+	}, {
+		mfr_id: MANUFACTURER_TOSHIBA,
+		dev_id: TC58FVT641,
+		name: "Toshiba TC58FVT641",
+		DevSize: SIZE_8MiB,
+		CmdSet:	P_ID_AMD_STD,
+		NumEraseRegions: 2,
+		regions: {ERASEINFO(0x10000,127),
+			  ERASEINFO(0x02000,8)
+		}
+	}, {
+		mfr_id: MANUFACTURER_FUJITSU,
+		dev_id: MBM29LV650UE,
+		name: "Fujitsu MBM29LV650UE",
+		DevSize: SIZE_8MiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x10000,128)
+		}
+	}, {
+		mfr_id: MANUFACTURER_FUJITSU,
+		dev_id: MBM29LV320TE,
+		name: "Fujitsu MBM29LV320TE",
+		DevSize: SIZE_4MiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 2,
+		regions: {ERASEINFO(0x10000,63),
+			  ERASEINFO(0x02000,8)
+		}
+	}, {
+		mfr_id: MANUFACTURER_FUJITSU,
+		dev_id: MBM29LV320BE,
+		name: "Fujitsu MBM29LV320BE",
+		DevSize: SIZE_4MiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 2,
+		regions: {ERASEINFO(0x02000,8),
+			  ERASEINFO(0x10000,63)
+		}
+	}, {
 		mfr_id: MANUFACTURER_FUJITSU,
 		dev_id: MBM29LV160TE,
 		name: "Fujitsu MBM29LV160TE",
 		DevSize: SIZE_2MiB,
+		CmdSet:	P_ID_AMD_STD,
 		NumEraseRegions: 4,
 		regions: {ERASEINFO(0x10000,31),
 			  ERASEINFO(0x08000,1),
@@ -119,10 +285,11 @@
 			  ERASEINFO(0x04000,1)
 		}
 	}, {
-		mfr_id: MANUFACTURER_TOSHIBA,
-		dev_id: TC58FVB160,
-		name: "Toshiba TC58FVB160",
+		mfr_id: MANUFACTURER_FUJITSU,
+		dev_id: MBM29LV160BE,
+		name: "Fujitsu MBM29LV160BE",
 		DevSize: SIZE_2MiB,
+		CmdSet:	P_ID_AMD_STD,
 		NumEraseRegions: 4,
 		regions: {ERASEINFO(0x04000,1),
 			  ERASEINFO(0x02000,2),
@@ -131,20 +298,34 @@
 		}
 	}, {
 		mfr_id: MANUFACTURER_FUJITSU,
-		dev_id: MBM29LV160BE,
-		name: "Fujitsu MBM29LV160BE",
-		DevSize: SIZE_2MiB,
+		dev_id: MBM29LV800BA,
+		name: "Fujitsu MBM29LV800BA",
+		DevSize: SIZE_1MiB,
+		CmdSet:	P_ID_AMD_STD,
 		NumEraseRegions: 4,
 		regions: {ERASEINFO(0x04000,1),
 			  ERASEINFO(0x02000,2),
 			  ERASEINFO(0x08000,1),
-			  ERASEINFO(0x10000,31)
+			  ERASEINFO(0x10000,15)
+		}
+	}, {
+		mfr_id: MANUFACTURER_FUJITSU,
+		dev_id: MBM29LV800TA,
+		name: "Fujitsu MBM29LV800TA",
+		DevSize: SIZE_1MiB,
+		CmdSet:	P_ID_AMD_STD,
+		NumEraseRegions: 4,
+		regions: {ERASEINFO(0x10000,15),
+ 			  ERASEINFO(0x08000,1),
+ 			  ERASEINFO(0x02000,2),
+ 			  ERASEINFO(0x04000,1)
 		}
 	}, {
 		mfr_id: MANUFACTURER_AMD,
 		dev_id: AM29LV800BB,
 		name: "AMD AM29LV800BB",
 		DevSize: SIZE_1MiB,
+		CmdSet:	P_ID_AMD_STD,
 		NumEraseRegions: 4,
 		regions: {ERASEINFO(0x04000,1),
 			  ERASEINFO(0x02000,2),
@@ -156,6 +337,7 @@
 		dev_id: AM29F800BB,
 		name: "AMD AM29F800BB",
 		DevSize: SIZE_1MiB,
+		CmdSet:	P_ID_AMD_STD,
 		NumEraseRegions: 4,
 		regions: {ERASEINFO(0x04000,1),
 			  ERASEINFO(0x02000,2),
@@ -167,6 +349,7 @@
 		dev_id: AM29LV800BT,
 		name: "AMD AM29LV800BT",
 		DevSize: SIZE_1MiB,
+		CmdSet:	P_ID_AMD_STD,
 		NumEraseRegions: 4,
 		regions: {ERASEINFO(0x10000,15),
 			  ERASEINFO(0x08000,1),
@@ -178,6 +361,7 @@
 		dev_id: AM29F800BT,
 		name: "AMD AM29F800BT",
 		DevSize: SIZE_1MiB,
+		CmdSet:	P_ID_AMD_STD,
 		NumEraseRegions: 4,
 		regions: {ERASEINFO(0x10000,15),
 			  ERASEINFO(0x08000,1),
@@ -189,6 +373,7 @@
 		dev_id: AM29LV800BB,
 		name: "AMD AM29LV800BB",
 		DevSize: SIZE_1MiB,
+		CmdSet:	P_ID_AMD_STD,
 		NumEraseRegions: 4,
 		regions: {ERASEINFO(0x10000,15),
 			  ERASEINFO(0x08000,1),
@@ -196,10 +381,243 @@
 			  ERASEINFO(0x04000,1)
 		}
 	}, {
+		mfr_id:			MANUFACTURER_INTEL,
+		dev_id:			I28F004B3B,
+		name:			"Intel 28F004B3B",
+		DevSize:		SIZE_512KiB,
+		CmdSet:			P_ID_INTEL_STD,
+		NumEraseRegions:	2,
+		regions: {
+			ERASEINFO(0x02000, 8),
+			ERASEINFO(0x10000, 7),
+		}
+	}, {
+		mfr_id:			MANUFACTURER_INTEL,
+		dev_id:			I28F004B3T,
+		name:			"Intel 28F004B3T",
+		DevSize:		SIZE_512KiB,
+		CmdSet:			P_ID_INTEL_STD,
+		NumEraseRegions:	2,
+		regions: {
+			ERASEINFO(0x10000, 7),
+			ERASEINFO(0x02000, 8),
+		}
+	}, {
+		mfr_id:			MANUFACTURER_INTEL,
+		dev_id:			I28F400B3B,
+		name:			"Intel 28F400B3B",
+		DevSize:		SIZE_512KiB,
+		CmdSet:			P_ID_INTEL_STD,
+		NumEraseRegions:	2,
+		regions: {
+			ERASEINFO(0x02000, 8),
+			ERASEINFO(0x10000, 7),
+		}
+	}, {
+		mfr_id:			MANUFACTURER_INTEL,
+		dev_id:			I28F400B3T,
+		name:			"Intel 28F400B3T",
+		DevSize:		SIZE_512KiB,
+		CmdSet:			P_ID_INTEL_STD,
+		NumEraseRegions:	2,
+		regions: {
+			ERASEINFO(0x10000, 7),
+			ERASEINFO(0x02000, 8),
+		}
+	}, {
+		mfr_id:			MANUFACTURER_INTEL,
+		dev_id:			I28F008B3B,
+		name:			"Intel 28F008B3B",
+		DevSize:		SIZE_1MiB,
+		CmdSet:			P_ID_INTEL_STD,
+		NumEraseRegions:	2,
+		regions: {
+			ERASEINFO(0x02000, 8),
+			ERASEINFO(0x10000, 15),
+		}
+	}, {
+		mfr_id:			MANUFACTURER_INTEL,
+		dev_id:			I28F008B3T,
+		name:			"Intel 28F008B3T",
+		DevSize:		SIZE_1MiB,
+		CmdSet:			P_ID_INTEL_STD,
+		NumEraseRegions:	2,
+		regions: {
+			ERASEINFO(0x10000, 15),
+			ERASEINFO(0x02000, 8),
+		}
+	}, {
+		mfr_id: MANUFACTURER_INTEL,
+		dev_id: I28F008S5,
+		name: "Intel 28F008S5",
+		DevSize: SIZE_1MiB,
+		CmdSet: P_ID_INTEL_EXT,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x10000,16),
+		}
+	}, {
+		mfr_id: MANUFACTURER_INTEL,
+		dev_id: I28F016S5,
+		name: "Intel 28F016S5",
+		DevSize: SIZE_2MiB,
+		CmdSet: P_ID_INTEL_EXT,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x10000,32),
+		}
+	}, {
+		mfr_id:			MANUFACTURER_INTEL,
+		dev_id:			I28F008SA,
+		name:			"Intel 28F008SA",
+		DevSize:		SIZE_1MiB,
+		CmdSet:			P_ID_INTEL_STD,
+		NumEraseRegions:	1,
+		regions: {
+			ERASEINFO(0x10000, 16),
+		}
+	}, {
+		mfr_id:			MANUFACTURER_INTEL,
+		dev_id:			I28F800B3B,
+		name:			"Intel 28F800B3B",
+		DevSize:		SIZE_1MiB,
+		CmdSet:			P_ID_INTEL_STD,
+		NumEraseRegions:	2,
+		regions: {
+			ERASEINFO(0x02000, 8),
+			ERASEINFO(0x10000, 15),
+		}
+	}, {
+		mfr_id:			MANUFACTURER_INTEL,
+		dev_id:			I28F800B3T,
+		name:			"Intel 28F800B3T",
+		DevSize:		SIZE_1MiB,
+		CmdSet:			P_ID_INTEL_STD,
+		NumEraseRegions:	2,
+		regions: {
+			ERASEINFO(0x10000, 15),
+			ERASEINFO(0x02000, 8),
+		}
+	}, {
+		mfr_id:			MANUFACTURER_INTEL,
+		dev_id:			I28F016B3B,
+		name:			"Intel 28F016B3B",
+		DevSize:		SIZE_2MiB,
+		CmdSet:			P_ID_INTEL_STD,
+		NumEraseRegions:	2,
+		regions: {
+			ERASEINFO(0x02000, 8),
+			ERASEINFO(0x10000, 31),
+		}
+	}, {
+		mfr_id:			MANUFACTURER_INTEL,
+		dev_id:			I28F016S3,
+		name:			"Intel I28F016S3",
+		DevSize:		SIZE_2MiB,
+		CmdSet:			P_ID_INTEL_STD,
+		NumEraseRegions:	1,
+		regions: {
+			ERASEINFO(0x10000, 32),
+		}
+	}, {
+		mfr_id:			MANUFACTURER_INTEL,
+		dev_id:			I28F016B3T,
+		name:			"Intel 28F016B3T",
+		DevSize:		SIZE_2MiB,
+		CmdSet:			P_ID_INTEL_STD,
+		NumEraseRegions:	2,
+		regions: {
+			ERASEINFO(0x10000, 31),
+			ERASEINFO(0x02000, 8),
+		}
+	}, {
+		mfr_id:			MANUFACTURER_INTEL,
+		dev_id:			I28F160B3B,
+		name:			"Intel 28F160B3B",
+		DevSize:		SIZE_2MiB,
+		CmdSet:			P_ID_INTEL_STD,
+		NumEraseRegions:	2,
+		regions: {
+			ERASEINFO(0x02000, 8),
+			ERASEINFO(0x10000, 31),
+		}
+	}, {
+		mfr_id:			MANUFACTURER_INTEL,
+		dev_id:			I28F160B3T,
+		name:			"Intel 28F160B3T",
+		DevSize:		SIZE_2MiB,
+		CmdSet:			P_ID_INTEL_STD,
+		NumEraseRegions:	2,
+		regions: {
+			ERASEINFO(0x10000, 31),
+			ERASEINFO(0x02000, 8),
+		}
+	}, {
+		mfr_id:			MANUFACTURER_INTEL,
+		dev_id:			I28F320B3B,
+		name:			"Intel 28F320B3B",
+		DevSize:		SIZE_4MiB,
+		CmdSet:			P_ID_INTEL_STD,
+		NumEraseRegions:	2,
+		regions: {
+			ERASEINFO(0x02000, 8),
+			ERASEINFO(0x10000, 63),
+		}
+	}, {
+		mfr_id:			MANUFACTURER_INTEL,
+		dev_id:			I28F320B3T,
+		name:			"Intel 28F320B3T",
+		DevSize:		SIZE_4MiB,
+		CmdSet:			P_ID_INTEL_STD,
+		NumEraseRegions:	2,
+		regions: {
+			ERASEINFO(0x10000, 63),
+			ERASEINFO(0x02000, 8),
+		}
+	}, {
+		mfr_id:			MANUFACTURER_INTEL,
+		dev_id:			I28F640B3B,
+		name:			"Intel 28F640B3B",
+		DevSize:		SIZE_8MiB,
+		CmdSet:			P_ID_INTEL_STD,
+		NumEraseRegions:	2,
+		regions: {
+			ERASEINFO(0x02000, 8),
+			ERASEINFO(0x10000, 127),
+		}
+	}, {
+		mfr_id:			MANUFACTURER_INTEL,
+		dev_id:			I28F640B3T,
+		name:			"Intel 28F640B3T",
+		DevSize:		SIZE_8MiB,
+		CmdSet:			P_ID_INTEL_STD,
+		NumEraseRegions:	2,
+		regions: {
+			ERASEINFO(0x10000, 127),
+			ERASEINFO(0x02000, 8),
+		}
+	}, {
+		mfr_id: MANUFACTURER_INTEL,
+		dev_id: I82802AB,
+		name: "Intel 82802AB",
+		DevSize: SIZE_512KiB,
+		CmdSet: P_ID_INTEL_EXT,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x10000,8),
+		}
+	}, {
+		mfr_id: MANUFACTURER_INTEL,
+		dev_id: I82802AC,
+		name: "Intel 82802AC",
+		DevSize: SIZE_1MiB,
+		CmdSet: P_ID_INTEL_EXT,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x10000,16),
+		}
+	}, {
 		mfr_id: MANUFACTURER_ST,
 		dev_id: M29W800T,
 		name: "ST M29W800T",
 		DevSize: SIZE_1MiB,
+		CmdSet:	P_ID_AMD_STD,
 		NumEraseRegions: 4,
 		regions: {ERASEINFO(0x10000,15),
 			  ERASEINFO(0x08000,1),
@@ -211,6 +629,7 @@
 		dev_id: M29W160DT,
 		name: "ST M29W160DT",
 		DevSize: SIZE_2MiB,
+		CmdSet:	P_ID_AMD_STD,
 		NumEraseRegions: 4,
 		regions: {ERASEINFO(0x10000,31),
 			  ERASEINFO(0x08000,1),
@@ -222,6 +641,7 @@
 		dev_id: M29W160DB,
 		name: "ST M29W160DB",
 		DevSize: SIZE_2MiB,
+		CmdSet:	P_ID_AMD_STD,
 		NumEraseRegions: 4,
 		regions: {ERASEINFO(0x04000,1),
 			  ERASEINFO(0x02000,2),
@@ -230,24 +650,256 @@
 		}
 	}, {
 		mfr_id: MANUFACTURER_ATMEL,
-		dev_id: AT49BV16X4,
-		name: "Atmel AT49BV16X4",
+		dev_id: AT49BV512,
+		name: "Atmel AT49BV512",
+		DevSize: SIZE_64KiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x10000,1)
+		}
+	}, {
+		mfr_id: MANUFACTURER_ATMEL,
+		dev_id: AT29LV512,
+		name: "Atmel AT29LV512",
+		DevSize: SIZE_64KiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 1,
+		regions: {
+			ERASEINFO(0x80,256),
+			ERASEINFO(0x80,256)
+		}
+	}, {
+		mfr_id: MANUFACTURER_ATMEL,
+		dev_id: AT49BV16X,
+		name: "Atmel AT49BV16X",
+		DevSize: SIZE_2MiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 2,
+		regions: {ERASEINFO(0x02000,8),
+			  ERASEINFO(0x10000,31)
+		}
+	}, {
+		mfr_id: MANUFACTURER_ATMEL,
+		dev_id: AT49BV16XT,
+		name: "Atmel AT49BV16XT",
 		DevSize: SIZE_2MiB,
-		NumEraseRegions: 3,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 2,
+		regions: {ERASEINFO(0x10000,31),
+			  ERASEINFO(0x02000,8)
+		}
+	}, {
+		mfr_id: MANUFACTURER_ATMEL,
+		dev_id: AT49BV32X,
+		name: "Atmel AT49BV32X",
+		DevSize: SIZE_4MiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 2,
 		regions: {ERASEINFO(0x02000,8),
-			  ERASEINFO(0x08000,2),
-			  ERASEINFO(0x10000,30)
+			  ERASEINFO(0x10000,63)
 		}
 	}, {
-                mfr_id: MANUFACTURER_ATMEL,
-                dev_id: AT49BV16X4T,
-                name: "Atmel AT49BV16X4T",
-                DevSize: SIZE_2MiB,
-                NumEraseRegions: 3,
-                regions: {ERASEINFO(0x10000,30),
-                          ERASEINFO(0x08000,2),
+		mfr_id: MANUFACTURER_ATMEL,
+		dev_id: AT49BV32XT,
+		name: "Atmel AT49BV32XT",
+		DevSize: SIZE_4MiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 2,
+		regions: {ERASEINFO(0x10000,63),
 			  ERASEINFO(0x02000,8)
-                }
+		}
+	}, {
+		mfr_id: MANUFACTURER_AMD,
+		dev_id: AM29F017D,
+		name: "AMD AM29F017D",
+		DevSize: SIZE_2MiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x10000,32),
+		}
+	}, {
+		mfr_id: MANUFACTURER_AMD,
+		dev_id: AM29F016,
+		name: "AMD AM29F016",
+		DevSize: SIZE_2MiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x10000,32),
+		}
+	}, {
+		mfr_id: MANUFACTURER_AMD,
+		dev_id: AM29F080,
+		name: "AMD AM29F080",
+		DevSize: SIZE_1MiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x10000,16),
+		}
+	}, {
+		mfr_id: MANUFACTURER_AMD,
+		dev_id: AM29F040,
+		name: "AMD AM29F040",
+		DevSize: SIZE_512KiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x10000,8),
+		}
+	}, {
+		mfr_id: MANUFACTURER_AMD,
+		dev_id: AM29LV040B,
+		name: "AMD AM29LV040B",
+		DevSize: SIZE_512KiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x10000,8),
+		}
+        }, {
+		mfr_id: MANUFACTURER_ST,
+		dev_id: M29W040B,
+		name: "ST M29W040B",
+		DevSize: SIZE_512KiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x10000,8),
+		}
+	}, {
+		mfr_id: MANUFACTURER_MACRONIX,
+		dev_id: MX29LV160T,
+		name: "MXIC MX29LV160T",
+		DevSize: SIZE_2MiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 4,
+		regions: {ERASEINFO(0x10000,31),
+			  ERASEINFO(0x08000,1),
+			  ERASEINFO(0x02000,2),
+			  ERASEINFO(0x04000,1)
+		}
+	}, {
+		mfr_id: MANUFACTURER_MACRONIX,
+		dev_id: MX29LV160B,
+		name: "MXIC MX29LV160B",
+		DevSize: SIZE_2MiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 4,
+		regions: {ERASEINFO(0x04000,1),
+			  ERASEINFO(0x02000,2),
+			  ERASEINFO(0x08000,1),
+			  ERASEINFO(0x10000,31)
+		}
+	}, {
+		mfr_id: MANUFACTURER_MACRONIX,
+		dev_id: MX29F016,
+		name: "Macronix MX29F016",
+		DevSize: SIZE_2MiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x10000,32),
+		}
+        }, {
+		mfr_id: MANUFACTURER_MACRONIX,
+		dev_id: MX29F004T,
+		name: "Macronix MX29F004T",
+		DevSize: SIZE_512KiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 4,
+		regions: {ERASEINFO(0x10000,7),
+			  ERASEINFO(0x08000,1),
+			  ERASEINFO(0x02000,2),
+			  ERASEINFO(0x04000,1),
+		}
+        }, {
+		mfr_id: MANUFACTURER_MACRONIX,
+		dev_id: MX29F004B,
+		name: "Macronix MX29F004B",
+		DevSize: SIZE_512KiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 4,
+		regions: {ERASEINFO(0x04000,1),
+			  ERASEINFO(0x02000,2),
+			  ERASEINFO(0x08000,1),
+			  ERASEINFO(0x10000,7),
+		}
+        }, {
+		mfr_id: MANUFACTURER_SST,
+		dev_id: SST39LF512,
+		name: "SST 39LF512",
+		DevSize: SIZE_64KiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x01000,16),
+		}
+        }, {
+		mfr_id: MANUFACTURER_SST,
+		dev_id: SST39LF010,
+		name: "SST 39LF010",
+		DevSize: SIZE_128KiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x01000,32),
+		}
+        }, {
+		mfr_id: MANUFACTURER_SST,
+		dev_id: SST39LF020,
+		name: "SST 39LF020",
+		DevSize: SIZE_256KiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x01000,64),
+		}
+        }, {
+		mfr_id: MANUFACTURER_SST,
+		dev_id: SST39LF040,
+		name: "SST 39LF040",
+		DevSize: SIZE_512KiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x01000,128),
+		}
+        }, {
+		mfr_id: MANUFACTURER_SST,
+		dev_id: SST39SF010A,
+		name: "SST 39SF010A",
+		DevSize: SIZE_128KiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x01000,32),
+		}
+        }, {
+		mfr_id: MANUFACTURER_SST,
+		dev_id: SST39SF020A,
+		name: "SST 39SF020A",
+		DevSize: SIZE_256KiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x01000,64),
+		}
+	}, {
+		mfr_id: MANUFACTURER_SST,
+		dev_id: SST49LF030A,
+		name: "SST 49LF030A",
+		DevSize: SIZE_512KiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x01000,96),
+		}
+	}, {
+		mfr_id: MANUFACTURER_SST,
+		dev_id: SST49LF040A,
+		name: "SST 49LF040A",
+		DevSize: SIZE_512KiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x01000,128),
+		}
+	}, {
+		mfr_id: MANUFACTURER_SST,
+		dev_id: SST49LF080A,
+		name: "SST 49LF080A",
+		DevSize: SIZE_1MiB,
+		CmdSet: P_ID_AMD_STD,
+		NumEraseRegions: 1,
+		regions: {ERASEINFO(0x01000,256),
+		}
 	} 
 };
 
@@ -258,9 +910,42 @@
 			    struct flchip *chips, struct cfi_private *cfi);
 
 struct mtd_info *jedec_probe(struct map_info *map);
-#define jedec_read_mfr(map, base, osf) cfi_read(map, base)
-#define jedec_read_id(map, base, osf) cfi_read(map, (base)+(osf))
 
+static inline u32 jedec_read_mfr(struct map_info *map, __u32 base, 
+	struct cfi_private *cfi)
+{
+	u32 result, mask;
+	mask = (1 << (cfi->device_type * 8)) -1;
+	result = cfi_read(map, base);
+	result &= mask;
+	return result;
+}
+
+static inline u32 jedec_read_id(struct map_info *map, __u32 base, 
+	struct cfi_private *cfi)
+{
+	int osf;
+	u32 result, mask;
+	osf = cfi->interleave *cfi->device_type;
+	mask = (1 << (cfi->device_type * 8)) -1;
+	result = cfi_read(map, base + osf);
+	result &= mask;
+	return result;
+}
+
+static inline void jedec_reset(u32 base, struct map_info *map, 
+	struct cfi_private *cfi)
+{
+	/* Reset */
+	cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
+	/* Some misdesigned intel chips do not respond for 0xF0 for a reset,
+	 * so ensure we're in read mode.  Send both the Intel and the AMD command
+	 * for this.  Intel uses 0xff for this, AMD uses 0xff for NOP, so
+	 * this should be safe.
+	 */ 
+	cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
+
+}
 static int cfi_jedec_setup(struct cfi_private *p_cfi, int index)
 {
 	int i,num_erase_regions;
@@ -276,14 +961,16 @@
 	}
 
 	memset(p_cfi->cfiq,0,sizeof(struct cfi_ident));	
-	
-	p_cfi->cfiq->P_ID = P_ID_AMD_STD;
+
+	p_cfi->cfiq->P_ID = jedec_table[index].CmdSet;
 	p_cfi->cfiq->NumEraseRegions = jedec_table[index].NumEraseRegions;
 	p_cfi->cfiq->DevSize = jedec_table[index].DevSize;
+	p_cfi->cfi_mode = CFI_MODE_JEDEC;
 
 	for (i=0; i<num_erase_regions; i++){
 		p_cfi->cfiq->EraseRegionInfo[i] = jedec_table[index].regions[i];
-	}	
+	}
+	p_cfi->cmdset_priv = 0;
 	return 1; 	/* ok */
 }
 
@@ -291,8 +978,7 @@
 			      struct flchip *chips, struct cfi_private *cfi)
 {
 	int i;
-	int osf = cfi->interleave * cfi->device_type;
-	int retried = 0;
+	int unlockpass = 0;
 
 	if (!cfi->numchips) {
 		switch (cfi->device_type) {
@@ -320,48 +1006,94 @@
 	}
 
  retry:
+	/* Make certain we aren't probing past the end of map */
+	if (base >= map->size) {
+		printk(KERN_NOTICE
+			"Probe at base(0x%08x) past the end of the map(0x%08lx)\n",
+			base, map->size -1);
+		return 0;
+		
+	}
+	if ((base + cfi->addr_unlock1) >= map->size) {
+		printk(KERN_NOTICE
+			"Probe at addr_unlock1(0x%08x + 0x%08x) past the end of the map(0x%08lx)\n",
+			base, cfi->addr_unlock1, map->size -1);
+
+		return 0;
+	}
+	if ((base + cfi->addr_unlock2) >= map->size) {
+		printk(KERN_NOTICE
+			"Probe at addr_unlock2(0x%08x + 0x%08x) past the end of the map(0x%08lx)\n",
+			base, cfi->addr_unlock2, map->size -1);
+		return 0;
+		
+	}
+
 	/* Reset */
-	cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
+	jedec_reset(base, map, cfi);
 
 	/* Autoselect Mode */
-	cfi_send_gen_cmd(0xaa, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL);
-	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, CFI_DEVICETYPE_X8, NULL);
+	if(cfi->addr_unlock1) {
+		cfi_send_gen_cmd(0xaa, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL);
+		cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, CFI_DEVICETYPE_X8, NULL);
+	}
 	cfi_send_gen_cmd(0x90, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL);
 
 	if (!cfi->numchips) {
 		/* This is the first time we're called. Set up the CFI 
 		   stuff accordingly and return */
 		
-		cfi->mfr = jedec_read_mfr(map, base, osf);
-		cfi->id = jedec_read_id(map, base, osf);
-		
+		cfi->mfr = jedec_read_mfr(map, base, cfi);
+		cfi->id = jedec_read_id(map, base, cfi);
+		printk(KERN_INFO "Search for id:(%02x %02x) interleave(%d) type(%d)\n", 
+			cfi->mfr, cfi->id, cfi->interleave, cfi->device_type);
 		for (i=0; i<sizeof(jedec_table)/sizeof(jedec_table[0]); i++) {
 			if (cfi->mfr == jedec_table[i].mfr_id &&
-			    cfi->id == jedec_table[i].dev_id)
-				return cfi_jedec_setup(cfi, i);
+			    cfi->id == jedec_table[i].dev_id) {
+				if (!cfi_jedec_setup(cfi, i))
+					return 0;
+				goto ok_out;
+			}
 		}
-		if (!retried++) {
-			/* Deal with whichever strange chips these were */
-			cfi->addr_unlock1 |= cfi->addr_unlock1 << 8;
-			cfi->addr_unlock2 |= cfi->addr_unlock2 << 8;
+		switch(unlockpass++) {
+		case 0:
+			cfi->addr_unlock1 |= cfi->addr_unlock1 << 4;
+			cfi->addr_unlock2 |= cfi->addr_unlock2 << 4;
+			goto retry;
+		case 1:
+			cfi->addr_unlock1 = cfi->addr_unlock2 = 0;
 			goto retry;
 		}
 		return 0;
+	} else {
+		__u16 mfr;
+		__u16 id;
+
+		/* Make sure it is a chip of the same manufacturer and id */
+		mfr = jedec_read_mfr(map, base, cfi);
+		id = jedec_read_id(map, base, cfi);
+
+		if ((mfr != cfi->mfr) || (id != cfi->id)) {
+			printk(KERN_DEBUG "%s: Found different chip or no chip at all (mfr 0x%x, id 0x%x) at 0x%x\n",
+			       map->name, mfr, id, base);
+			jedec_reset(base, map, cfi);
+			return 0;
+		}
 	}
 	
 	/* Check each previous chip to see if it's an alias */
 	for (i=0; i<cfi->numchips; i++) {
 		/* This chip should be in read mode if it's one
 		   we've already touched. */
-		if (jedec_read_mfr(map, base, osf) == cfi->mfr &&
-		    jedec_read_id(map, base, osf) == cfi->id) {
+		if (jedec_read_mfr(map, chips[i].start, cfi) == cfi->mfr &&
+		    jedec_read_id(map, chips[i].start, cfi) == cfi->id) {
 			/* Eep. This chip also looks like it's in autoselect mode.
 			   Is it an alias for the new one? */
-			
-			cfi_send_gen_cmd(0xF0, 0, chips[i].start, map, cfi, cfi->device_type, NULL);
+			jedec_reset(chips[i].start, map, cfi);
+
 			/* If the device IDs go away, it's an alias */
-			if (jedec_read_mfr(map, base, osf) != cfi->mfr ||
-			    jedec_read_id(map, base, osf) != cfi->id) {
+			if (jedec_read_mfr(map, base, cfi) != cfi->mfr ||
+			    jedec_read_id(map, base, cfi) != cfi->id) {
 				printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n",
 				       map->name, base, chips[i].start);
 				return 0;
@@ -371,9 +1103,9 @@
 			 * unfortunate. Stick the new chip in read mode
 			 * too and if it's the same, assume it's an alias. */
 			/* FIXME: Use other modes to do a proper check */
-			cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
-			if (jedec_read_mfr(map, base, osf) == cfi->mfr &&
-			    jedec_read_id(map, base, osf) == cfi->id) {
+			jedec_reset(base, map, cfi);
+			if (jedec_read_mfr(map, base, cfi) == cfi->mfr &&
+			    jedec_read_id(map, base, cfi) == cfi->id) {
 				printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n",
 				       map->name, base, chips[i].start);
 				return 0;
@@ -392,8 +1124,9 @@
 	chips[cfi->numchips].state = FL_READY;
 	cfi->numchips++;
 		
+ok_out:
 	/* Put it back into Read Mode */
-	cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
+	jedec_reset(base, map, cfi);
 
 	printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit mode\n",
 	       map->name, cfi->interleave, cfi->device_type*8, base, 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/chips/sharp.c linux-2.4.21-pre6/drivers/mtd/chips/sharp.c
--- linux-2.4.20/drivers/mtd/chips/sharp.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/chips/sharp.c	2003-03-26 23:48:58.000000000 +0000
@@ -4,7 +4,7 @@
  * Copyright 2000,2001 David A. Schleef <ds@schleef.org>
  *           2000,2001 Lineo, Inc.
  *
- * $Id: sharp.c,v 1.7 2002/02/13 15:49:07 dwmw2 Exp $
+ * $Id: sharp.c,v 1.8 2002/05/17 08:59:19 dwmw2 Exp $
  *
  * Devices supported:
  *   LH28F016SCT Symmetrical block flash memory, 2Mx8
@@ -421,6 +421,7 @@
 		}
 	}
 
+	instr->state = MTD_ERASE_DONE;
 	if(instr->callback)
 		instr->callback(instr);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/cmdlinepart.c linux-2.4.21-pre6/drivers/mtd/cmdlinepart.c
--- linux-2.4.20/drivers/mtd/cmdlinepart.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/cmdlinepart.c	2003-03-26 23:49:38.000000000 +0000
@@ -0,0 +1,356 @@
+/*
+ * $Id: cmdlinepart.c,v 1.6 2002/11/16 01:37:39 dneuer Exp $
+ *
+ * Read flash partition table from command line
+ *
+ * Copyright 2002 SYSGO Real-Time Solutions GmbH
+ *
+ * The format for the command line is as follows:
+ * 
+ * mtdparts=<mtddef>[;<mtddef]
+ * <mtddef>  := <mtd-id>:<partdef>[,<partdef>]
+ * <partdef> := <size>[@offset][<name>][ro]
+ * <mtd-id>  := unique id used in mapping driver/device
+ * <size>    := standard linux memsize OR "-" to denote all remaining space
+ * <name>    := '(' NAME ')'
+ * 
+ * Examples:
+ * 
+ * 1 NOR Flash, with 1 single writable partition:
+ * edb7312-nor:-
+ * 
+ * 1 NOR Flash with 2 partitions, 1 NAND with one
+ * edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home)
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <asm/setup.h>
+#include <linux/bootmem.h>
+
+/* error message prefix */
+#define ERRP "mtd: "
+
+/* debug macro */
+#if 0
+#define dbg(x) do { printk("DEBUG-CMDLINE-PART: "); printk x; } while(0)
+#else
+#define dbg(x)
+#endif
+
+
+/* special size referring to all the remaining space in a partition */
+#define SIZE_REMAINING 0xffffffff
+
+struct cmdline_mtd_partition {
+	struct cmdline_mtd_partition *next;
+	char *mtd_id;
+	int num_parts;
+	struct mtd_partition *parts;
+};
+
+/* mtdpart_setup() parses into here */
+static struct cmdline_mtd_partition *partitions;
+
+/* the command line passed to mtdpart_setupd() */
+static char *cmdline;
+static int cmdline_parsed = 0;
+
+/*
+ * Parse one partition definition for an MTD. Since there can be many
+ * comma separated partition definitions, this function calls itself 
+ * recursively until no more partition definitions are found. Nice side
+ * effect: the memory to keep the mtd_partition structs and the names
+ * is allocated upon the last definition being found. At that point the
+ * syntax has been verified ok.
+ */
+static struct mtd_partition * newpart(char *s, 
+                                      char **retptr,
+                                      int *num_parts,
+                                      int this_part, 
+                                      unsigned char **extra_mem_ptr, 
+                                      int extra_mem_size)
+{
+	struct mtd_partition *parts;
+	unsigned long size;
+	unsigned long offset = 0;
+	char *name;
+	int name_len;
+	unsigned char *extra_mem;
+	char delim;
+	unsigned int mask_flags;
+
+	/* fetch the partition size */
+	if (*s == '-')
+	{	/* assign all remaining space to this partition */
+		size = SIZE_REMAINING;
+		s++;
+	}
+	else
+	{
+		size = memparse(s, &s);
+		if (size < PAGE_SIZE)
+		{
+			printk(KERN_ERR ERRP "partition size too small (%lx)\n", size);
+			return 0;
+		}
+	}
+
+	/* fetch partition name and flags */
+	mask_flags = 0; /* this is going to be a regular partition */
+	delim = 0;
+        /* check for offset */
+        if (*s == '@') 
+	{
+                s++;
+                offset = memparse(s, &s);
+        }
+        /* now look for name */
+	if (*s == '(')
+	{
+		delim = ')';
+	}
+		
+	if (delim)
+	{
+		char *p;
+
+	    	name = ++s;
+		if ((p = strchr(name, delim)) == 0)
+		{
+			printk(KERN_ERR ERRP "no closing %c found in partition name\n", delim);
+			return 0;
+		}
+		name_len = p - name;
+		s = p + 1;
+	}
+	else
+	{
+	    	name = NULL;
+		name_len = 13; /* Partition_000 */
+	}
+   
+	/* record name length for memory allocation later */
+	extra_mem_size += name_len + 1;
+
+        /* test for options */
+        if (strncmp(s, "ro", 2) == 0) 
+	{
+		mask_flags |= MTD_WRITEABLE;
+		s += 2;
+        }
+
+	/* test if more partitions are following */
+	if (*s == ',')
+	{
+		if (size == SIZE_REMAINING)
+		{
+			printk(KERN_ERR ERRP "no partitions allowed after a fill-up partition\n");
+			return 0;
+		}
+		/* more partitions follow, parse them */
+		if ((parts = newpart(s + 1, &s, num_parts, 
+		                     this_part + 1, &extra_mem, extra_mem_size)) == 0)
+		  return 0;
+	}
+	else
+	{	/* this is the last partition: allocate space for all */
+		int alloc_size;
+
+		*num_parts = this_part + 1;
+		alloc_size = *num_parts * sizeof(struct mtd_partition) +
+			     extra_mem_size;
+		parts = kmalloc(alloc_size, GFP_KERNEL);
+		if (!parts)
+		{
+			printk(KERN_ERR ERRP "out of memory\n");
+			return 0;
+		}
+		memset(parts, 0, alloc_size);
+		extra_mem = (unsigned char *)(parts + *num_parts);
+	}
+	/* enter this partition (offset will be calculated later if it is zero at this point) */
+	parts[this_part].size = size;
+	parts[this_part].offset = offset;
+	parts[this_part].mask_flags = mask_flags;
+	if (name)
+	{
+		strncpy(extra_mem, name, name_len);
+		extra_mem[name_len] = 0;
+	}
+	else
+	{
+		sprintf(extra_mem, "Partition_%03d", this_part);
+	}
+	parts[this_part].name = extra_mem;
+	extra_mem += name_len + 1;
+
+	dbg(("partition %d: name <%s>, offset %x, size %x, mask flags %x\n",
+	     this_part, 
+	     parts[this_part].name,
+	     parts[this_part].offset,
+	     parts[this_part].size,
+	     parts[this_part].mask_flags));
+
+	/* return (updated) pointer to extra_mem memory */
+	if (extra_mem_ptr)
+	  *extra_mem_ptr = extra_mem;
+
+	/* return (updated) pointer command line string */
+	*retptr = s;
+
+	/* return partition table */
+	return parts;
+}
+
+/* 
+ * Parse the command line. 
+ */
+static int mtdpart_setup_real(char *s)
+{
+	cmdline_parsed = 1;
+
+	for( ; s != NULL; )
+	{
+		struct cmdline_mtd_partition *this_mtd;
+		struct mtd_partition *parts;
+	    	int mtd_id_len;
+		int num_parts;
+		char *p, *mtd_id;
+
+	    	mtd_id = s;
+		/* fetch <mtd-id> */
+		if (!(p = strchr(s, ':')))
+		{
+			printk(KERN_ERR ERRP "no mtd-id\n");
+			return 0;
+		}
+		mtd_id_len = p - mtd_id;
+
+		dbg(("parsing <%s>\n", p+1));
+
+		/* 
+		 * parse one mtd. have it reserve memory for the
+		 * struct cmdline_mtd_partition and the mtd-id string.
+		 */
+		parts = newpart(p + 1,		/* cmdline */
+				&s,		/* out: updated cmdline ptr */
+				&num_parts,	/* out: number of parts */
+				0,		/* first partition */
+				(unsigned char**)&this_mtd, /* out: extra mem */
+				mtd_id_len + 1 + sizeof(*this_mtd));
+		if(!parts)
+		{
+			/*
+			 * An error occurred. We're either:
+			 * a) out of memory, or
+			 * b) in the middle of the partition spec
+			 * Either way, this mtd is hosed and we're
+			 * unlikely to succeed in parsing any more
+			 */
+			 return 0;
+		 }
+
+		/* enter results */	    
+		this_mtd->parts = parts;
+		this_mtd->num_parts = num_parts;
+		this_mtd->mtd_id = (char*)(this_mtd + 1);
+		strncpy(this_mtd->mtd_id, mtd_id, mtd_id_len);
+		this_mtd->mtd_id[mtd_id_len] = 0;
+
+		/* link into chain */
+		this_mtd->next = partitions;	    	
+		partitions = this_mtd;
+
+		dbg(("mtdid=<%s> num_parts=<%d>\n", 
+		     this_mtd->mtd_id, this_mtd->num_parts));
+		
+
+		/* EOS - we're done */
+		if (*s == 0)
+			break;
+
+		/* does another spec follow? */
+		if (*s != ';')
+		{
+			printk(KERN_ERR ERRP "bad character after partition (%c)\n", *s);
+			return 0;
+		}
+		s++;
+	}
+	return 1;
+}
+
+/*
+ * Main function to be called from the MTD mapping driver/device to
+ * obtain the partitioning information. At this point the command line
+ * arguments will actually be parsed and turned to struct mtd_partition
+ * information. It returns partitions for the requested mtd device, or
+ * the first one in the chain if a NULL mtd_id is passed in.
+ */
+int parse_cmdline_partitions(struct mtd_info *master, 
+                             struct mtd_partition **pparts,
+                             const char *mtd_id)
+{
+	unsigned long offset;
+	int i;
+	struct cmdline_mtd_partition *part;
+
+	if(!cmdline)
+		return -EINVAL;
+
+	/* parse command line */
+	if (!cmdline_parsed)
+		mtdpart_setup_real(cmdline);
+
+	for(part = partitions; part; part = part->next)
+	{
+		if ((!mtd_id) || (!strcmp(part->mtd_id, mtd_id)))
+		{
+			for(i = 0, offset = 0; i < part->num_parts; i++)
+			{
+				if (!part->parts[i].offset)
+				  part->parts[i].offset = offset;
+				else
+				  offset = part->parts[i].offset;
+				if (part->parts[i].size == SIZE_REMAINING)
+				  part->parts[i].size = master->size - offset;
+				if (offset + part->parts[i].size > master->size)
+				{
+					printk(KERN_WARNING ERRP 
+					       "%s: partitioning exceeds flash size, truncating\n",
+					       part->mtd_id);
+					part->parts[i].size = master->size - offset;
+					part->num_parts = i;
+				}
+				offset += part->parts[i].size;
+			}
+			*pparts = part->parts;
+			return part->num_parts;
+		}
+	}
+	return -EINVAL;
+}
+
+
+/* 
+ * This is the handler for our kernel parameter, called from 
+ * main.c::checksetup(). Note that we can not yet kmalloc() anything,
+ * so we only save the commandline for later processing.
+ */
+static int __init mtdpart_setup(char *s)
+{
+	cmdline = s;
+	return 1;
+}
+
+__setup("mtdparts=", mtdpart_setup);
+
+EXPORT_SYMBOL(parse_cmdline_partitions);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Marius Groeger <mag@sysgo.de>");
+MODULE_DESCRIPTION("Command line configuration of MTD partitions");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/devices/Config.in linux-2.4.21-pre6/drivers/mtd/devices/Config.in
--- linux-2.4.20/drivers/mtd/devices/Config.in	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/devices/Config.in	2003-03-26 23:49:30.000000000 +0000
@@ -1,6 +1,6 @@
 # drivers/mtd/maps/Config.in
 
-# $Id: Config.in,v 1.5 2001/09/23 15:33:10 dwmw2 Exp $
+# $Id: Config.in,v 1.8 2003/01/24 23:25:14 dwmw2 Exp $
 
 mainmenu_option next_comment
 
@@ -11,11 +11,11 @@
    bool '    PMC551 Debugging' CONFIG_MTD_PMC551_DEBUG
 fi
 if [ "$CONFIG_DECSTATION" = "y" ]; then
-   dep_tristate '  DEC MS02-NV NVRAM module support' CONFIG_MTD_MS02NV $CONFIG_MTD $CONFIG_DECSTATION
+   dep_tristate '  DEC MS02-NV NVRAM module support' CONFIG_MTD_MS02NV $CONFIG_MTD
 fi
 dep_tristate '  Uncached system RAM' CONFIG_MTD_SLRAM $CONFIG_MTD
 if [ "$CONFIG_SA1100_LART" = "y" ]; then
-  dep_tristate '  28F160xx flash driver for LART' CONFIG_MTD_LART $CONFIG_MTD
+   dep_tristate '  28F160xx flash driver for LART' CONFIG_MTD_LART $CONFIG_MTD
 fi
 dep_tristate '  Test driver using RAM' CONFIG_MTD_MTDRAM $CONFIG_MTD
 if [ "$CONFIG_MTD_MTDRAM" = "y" -o "$CONFIG_MTD_MTDRAM" = "m" ]; then
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/devices/blkmtd.c linux-2.4.21-pre6/drivers/mtd/devices/blkmtd.c
--- linux-2.4.20/drivers/mtd/devices/blkmtd.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/devices/blkmtd.c	2003-03-26 23:48:59.000000000 +0000
@@ -1,57 +1,36 @@
-/* 
- * $Id: blkmtd.c,v 1.7 2001/11/10 17:06:30 spse Exp $
+/*
+ * $Id: blkmtd.c,v 1.17 2003/01/24 13:00:24 dwmw2 Exp $
  *
  * blkmtd.c - use a block device as a fake MTD
  *
  * Author: Simon Evans <spse@secret.org.uk>
  *
- * Copyright (C) 2001 Simon Evans
- * 
+ * Copyright (C) 2001,2002 Simon Evans
+ *
  * Licence: GPL
  *
  * How it works:
- *       The driver uses raw/io to read/write the device and the page
- *       cache to cache access. Writes update the page cache with the
- *       new data but make a copy of the new page(s) and then a kernel
- *       thread writes pages out to the device in the background. This
- *       ensures that writes are order even if a page is updated twice.
- *       Also, since pages in the page cache are never marked as dirty,
- *       we dont have to worry about writepage() being called on some 
- *       random page which may not be in the write order.
- * 
- *       Erases are handled like writes, so the callback is called after
- *       the page cache has been updated. Sync()ing will wait until it is 
- *       all done.
+ *	The driver uses raw/io to read/write the device and the page
+ *	cache to cache access. Writes update the page cache with the
+ *	new data and mark it dirty and add the page into a kiobuf.
+ *	When the kiobuf becomes full or the next extry is to an earlier
+ *	block in the kiobuf then it is flushed to disk. This allows
+ *	writes to remained ordered and gives a small and simple outgoing
+ *	write cache.
  *
- *       It can be loaded Read-Only to prevent erases and writes to the 
- *       medium.
+ *	It can be loaded Read-Only to prevent erases and writes to the
+ *	medium.
  *
- * Todo:
- *       Make the write queue size dynamic so this it is not too big on
- *       small memory systems and too small on large memory systems.
- * 
- *       Page cache usage may still be a bit wrong. Check we are doing
- *       everything properly.
- * 
- *       Somehow allow writes to dirty the page cache so we dont use too
- *       much memory making copies of outgoing pages. Need to handle case
- *       where page x is written to, then page y, then page x again before
- *       any of them have been committed to disk.
- * 
- *       Reading should read multiple pages at once rather than using 
- *       readpage() for each one. This is easy and will be fixed asap.
  */
 
-
 #include <linux/config.h>
 #include <linux/module.h>
-
 #include <linux/fs.h>
-#include <linux/pagemap.h>
+#include <linux/blkdev.h>
 #include <linux/iobuf.h>
 #include <linux/slab.h>
 #include <linux/pagemap.h>
-#include <linux/mtd/compatmac.h>
+#include <linux/list.h>
 #include <linux/mtd/mtd.h>
 
 #ifdef CONFIG_MTD_DEBUG
@@ -63,918 +42,918 @@
 #endif
 
 
-/* Default erase size in K, always make it a multiple of PAGE_SIZE */
-#define CONFIG_MTD_BLKDEV_ERASESIZE 128
-#define VERSION "1.7"
-extern int *blk_size[];
-extern int *blksize_size[];
+#define err(format, arg...) printk(KERN_ERR "blkmtd: " format "\n" , ## arg)
+#define info(format, arg...) printk(KERN_INFO "blkmtd: " format "\n" , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING "blkmtd: " format "\n" , ## arg)
+#define crit(format, arg...) printk(KERN_CRIT "blkmtd: " format "\n" , ## arg)
 
-/* Info for the block device */
-typedef struct mtd_raw_dev_data_s {
-  struct block_device *binding;
-  int sector_size, sector_bits;
-  int partial_last_page;   // 0 if device ends on page boundary, else page no of last page
-  int last_page_sectors;   // Number of sectors in last page if partial_last_page != 0
-  size_t totalsize;
-  int readonly;
-  struct address_space as;
-  struct mtd_info mtd_info;
-} mtd_raw_dev_data_t;
-
-/* Info for each queue item in the write queue */
-typedef struct mtdblkdev_write_queue_s {
-  mtd_raw_dev_data_t *rawdevice;
-  struct page **pages;
-  int pagenr;
-  int pagecnt;
-  int iserase;
-} mtdblkdev_write_queue_t;
 
+/* Default erase size in KiB, always make it a multiple of PAGE_SIZE */
+#define CONFIG_MTD_BLKDEV_ERASESIZE (128 << 10)	/* 128KiB */
+#define VERSION "1.10"
+
+/* Info for the block device */
+struct blkmtd_dev {
+	struct list_head list;
+	struct block_device *binding;
+	struct mtd_info mtd_info;
+	struct kiobuf *rd_buf, *wr_buf;
+	long iobuf_locks;
+	struct semaphore wrbuf_mutex;
+};
 
-/* Our erase page - always remains locked. */
-static struct page *erase_page;
 
 /* Static info about the MTD, used in cleanup_module */
-static mtd_raw_dev_data_t *mtd_rawdevice;
+static LIST_HEAD(blkmtd_device_list);
 
-/* Write queue fixed size */
-#define WRITE_QUEUE_SZ 512
 
-/* Storage for the write queue */
-static mtdblkdev_write_queue_t *write_queue;
-static int write_queue_sz = WRITE_QUEUE_SZ;
-static int volatile write_queue_head;
-static int volatile write_queue_tail;
-static int volatile write_queue_cnt;
-static spinlock_t mbd_writeq_lock = SPIN_LOCK_UNLOCKED;
-
-/* Tell the write thread to finish */
-static volatile int write_task_finish;
-
-/* ipc with the write thread */
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0)
-static DECLARE_MUTEX_LOCKED(thread_sem);
-static DECLARE_WAIT_QUEUE_HEAD(thr_wq);
-static DECLARE_WAIT_QUEUE_HEAD(mtbd_sync_wq);
-#else
-static struct semaphore thread_sem = MUTEX_LOCKED;
-DECLARE_WAIT_QUEUE_HEAD(thr_wq);
-DECLARE_WAIT_QUEUE_HEAD(mtbd_sync_wq);
-#endif
+static void blkmtd_sync(struct mtd_info *mtd);
 
+#define MAX_DEVICES 4
 
 /* Module parameters passed by insmod/modprobe */
-char *device;    /* the block device to use */
-int erasesz;     /* optional default erase size */
-int ro;          /* optional read only flag */
-int bs;          /* optionally force the block size (avoid using) */
-int count;       /* optionally force the block count (avoid using) */
-int wqs;         /* optionally set the write queue size */
+char *device[MAX_DEVICES];    /* the block device to use */
+int erasesz[MAX_DEVICES];     /* optional default erase size */
+int ro[MAX_DEVICES];          /* optional read only flag */
+int sync;
 
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Simon Evans <spse@secret.org.uk>");
 MODULE_DESCRIPTION("Emulate an MTD using a block device");
-MODULE_PARM(device, "s");
+MODULE_PARM(device, "1-4s");
 MODULE_PARM_DESC(device, "block device to use");
-MODULE_PARM(erasesz, "i");
-MODULE_PARM_DESC(erasesz, "optional erase size to use in KB. eg 4=4K.");
-MODULE_PARM(ro, "i");
+MODULE_PARM(erasesz, "1-4i");
+MODULE_PARM_DESC(erasesz, "optional erase size to use in KiB. eg 4=4KiB.");
+MODULE_PARM(ro, "1-4i");
 MODULE_PARM_DESC(ro, "1=Read only, writes and erases cause errors");
-MODULE_PARM(bs, "i");
-MODULE_PARM_DESC(bs, "force the block size in bytes");
-MODULE_PARM(count, "i");
-MODULE_PARM_DESC(count, "force the block count");
-MODULE_PARM(wqs, "i");
-#endif
-
+MODULE_PARM(sync, "i");
+MODULE_PARM_DESC(sync, "1=Synchronous writes");
 
-/* Page cache stuff */
 
-/* writepage() - should never be called - catch it anyway */
-static int blkmtd_writepage(struct page *page)
+/**
+ * read_pages - read in pages via the page cache
+ * @dev: device to read from
+ * @pagenrs: list of page numbers wanted
+ * @pagelst: storage for struce page * pointers
+ * @pages: count of pages wanted
+ *
+ * Read pages, getting them from the page cache if available
+ * else reading them in from disk if not. pagelst must be preallocated
+ * to hold the page count.
+ */
+static int read_pages(struct blkmtd_dev *dev, int pagenrs[], struct page **pagelst, int pages)
 {
-  printk("blkmtd: writepage called!!!\n");
-  return -EIO;
-}
-
-
-/* readpage() - reads one page from the block device */                 
-static int blkmtd_readpage(mtd_raw_dev_data_t *rawdevice, struct page *page)
-{  
-  int err;
-  int sectornr, sectors, i;
-  struct kiobuf *iobuf;
-  kdev_t dev;
-  unsigned long *blocks;
-
-  if(!rawdevice) {
-    printk("blkmtd: readpage: PANIC file->private_data == NULL\n");
-    return -EIO;
-  }
-  dev = to_kdev_t(rawdevice->binding->bd_dev);
-
-  DEBUG(2, "blkmtd: readpage called, dev = `%s' page = %p index = %ld\n",
-	bdevname(dev), page, page->index);
-
-  if(Page_Uptodate(page)) {
-    DEBUG(2, "blkmtd: readpage page %ld is already upto date\n", page->index);
-    UnlockPage(page);
-    return 0;
-  }
-
-  ClearPageUptodate(page);
-  ClearPageError(page);
-
-  /* see if page is in the outgoing write queue */
-  spin_lock(&mbd_writeq_lock);
-  if(write_queue_cnt) {
-    int i = write_queue_tail;
-    while(i != write_queue_head) {
-      mtdblkdev_write_queue_t *item = &write_queue[i];
-      if(page->index >= item->pagenr && page->index < item->pagenr+item->pagecnt) {
-	/* yes it is */
-	int index = page->index - item->pagenr;
-		
-	DEBUG(2, "blkmtd: readpage: found page %ld in outgoing write queue\n",
-	      page->index);
-	if(item->iserase) {
-	  memset(page_address(page), 0xff, PAGE_SIZE);
-	} else {
-	  memcpy(page_address(page), page_address(item->pages[index]), PAGE_SIZE);
+	kdev_t kdev;
+	struct page *page;
+	int cnt = 0;
+	struct kiobuf *iobuf;
+	int err = 0;
+
+	if(!dev) {
+		err("read_pages: PANIC dev == NULL");
+		return -EIO;
 	}
-	SetPageUptodate(page);
-	flush_dcache_page(page);
-	UnlockPage(page);
-	spin_unlock(&mbd_writeq_lock);
-	return 0;
-      }
-      i++;
-      i %= write_queue_sz;
-    }
-  }
-  spin_unlock(&mbd_writeq_lock);
-
-
-  DEBUG(3, "blkmtd: readpage: getting kiovec\n");
-  err = alloc_kiovec(1, &iobuf);
-  if (err) {
-    printk("blkmtd: cant allocate kiobuf\n");
-    SetPageError(page);
-    return err;
-  }
+	kdev = to_kdev_t(dev->binding->bd_dev);
 
-  /* Pre 2.4.4 doesn't have space for the block list in the kiobuf */ 
+	DEBUG(2, "read_pages: reading %d pages\n", pages);
+	if(test_and_set_bit(0, &dev->iobuf_locks)) {
+		err = alloc_kiovec(1, &iobuf);
+		if (err) {
+			crit("cant allocate kiobuf");
+			return -ENOMEM;
+		}
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
-  blocks = kmalloc(KIO_MAX_SECTORS * sizeof(unsigned long));
-  if(blocks == NULL) {
-    printk("blkmtd: cant allocate iobuf blocks\n");
-    free_kiovec(1, &iobuf);
-    SetPageError(page);
-    return -ENOMEM;
-  }
-#else 
-  blocks = iobuf->blocks;
+		iobuf->blocks = kmalloc(KIO_MAX_SECTORS * sizeof(unsigned long), GFP_KERNEL);
+		if(iobuf->blocks == NULL) {
+			crit("cant allocate iobuf blocks");
+			free_kiovec(1, &iobuf);
+			return -ENOMEM;
+		}
 #endif
+	} else {
+		iobuf = dev->rd_buf;
+	}
+
+	iobuf->nr_pages = 0;
+	iobuf->length = 0;
+	iobuf->offset = 0;
+	iobuf->locked = 1;
+	
+	for(cnt = 0; cnt < pages; cnt++) {
+		page = grab_cache_page(dev->binding->bd_inode->i_mapping, pagenrs[cnt]);
+		pagelst[cnt] = page;
+		if(!PageUptodate(page)) {
+				iobuf->blocks[iobuf->nr_pages] = pagenrs[cnt];
+				iobuf->maplist[iobuf->nr_pages++] = page;
+		}
+	}
+
+	if(iobuf->nr_pages) {
+		iobuf->length = iobuf->nr_pages << PAGE_SHIFT;
+		err = brw_kiovec(READ, 1, &iobuf, kdev, iobuf->blocks, PAGE_SIZE);
+		DEBUG(3, "blkmtd: read_pages: finished, err = %d\n", err);
+		if(err < 0) {
+			while(pages--) {
+				ClearPageUptodate(pagelst[pages]);
+				unlock_page(pagelst[pages]);
+				page_cache_release(pagelst[pages]);
+			}
+		} else {
+			while(iobuf->nr_pages--) {
+				SetPageUptodate(iobuf->maplist[iobuf->nr_pages]);
+			}
+			err = 0;
+		}
+	}
 
-  iobuf->offset = 0;
-  iobuf->nr_pages = 1;
-  iobuf->length = PAGE_SIZE;
-  iobuf->locked = 1;
-  iobuf->maplist[0] = page;
-  sectornr = page->index << (PAGE_SHIFT - rawdevice->sector_bits);
-  sectors = 1 << (PAGE_SHIFT - rawdevice->sector_bits);
-  if(rawdevice->partial_last_page && page->index == rawdevice->partial_last_page) {
-    DEBUG(3, "blkmtd: handling partial last page\n");
-    sectors = rawdevice->last_page_sectors;
-  }
-  DEBUG(3, "blkmtd: readpage: sectornr = %d sectors = %d\n", sectornr, sectors);
-  for(i = 0; i < sectors; i++) {
-    blocks[i] = sectornr++;
-  }
-  /* If only a partial page read in, clear the rest of the page */
-  if(rawdevice->partial_last_page && page->index == rawdevice->partial_last_page) {
-    int offset = rawdevice->last_page_sectors << rawdevice->sector_bits;
-    int count = PAGE_SIZE-offset;
-    DEBUG(3, "blkmtd: clear last partial page: offset = %d count = %d\n", offset, count);
-    memset(page_address(page)+offset, 0, count);
-    sectors = rawdevice->last_page_sectors;
-  }
-
-
-  DEBUG(3, "bklmtd: readpage: starting brw_kiovec\n");
-  err = brw_kiovec(READ, 1, &iobuf, dev, blocks, rawdevice->sector_size);
-  DEBUG(3, "blkmtd: readpage: finished, err = %d\n", err);
-  iobuf->locked = 0;
-  free_kiovec(1, &iobuf);
 
+	if(iobuf != dev->rd_buf) {
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
-  kfree(blocks);
+		kfree(iobuf->blocks);
 #endif
-
-  if(err != PAGE_SIZE) {
-    printk("blkmtd: readpage: error reading page %ld\n", page->index);
-    memset(page_address(page), 0, PAGE_SIZE);
-    SetPageError(page);
-    err = -EIO;
-  } else {
-    DEBUG(3, "blkmtd: readpage: setting page upto date\n");
-    SetPageUptodate(page);
-    err = 0;
-  }
-  flush_dcache_page(page);
-  UnlockPage(page);
-  DEBUG(2, "blkmtd: readpage: finished, err = %d\n", err);
-  return 0;
+		free_kiovec(1, &iobuf);
+	} else {
+		clear_bit(0, &dev->iobuf_locks);
+	}
+	DEBUG(2, "read_pages: done, err = %d\n", err);
+	return err;
 }
 
-                    
-static struct address_space_operations blkmtd_aops = {
-  writepage:     blkmtd_writepage,
-  readpage:      NULL,
-}; 
+
+/**
+ * commit_pages - commit pages in the writeout kiobuf to disk
+ * @dev: device to write to
+ *
+ * If the current dev has pages in the dev->wr_buf kiobuf,
+ * they are written to disk using brw_kiovec()
+ */
+static int commit_pages(struct blkmtd_dev *dev)
+{
+	struct kiobuf *iobuf = dev->wr_buf;
+	kdev_t kdev = to_kdev_t(dev->binding->bd_dev);
+	int err = 0;
+
+	iobuf->length = iobuf->nr_pages << PAGE_SHIFT;
+	iobuf->locked = 1;
+	if(iobuf->length) {
+		int i;
+		DEBUG(2, "blkmtd: commit_pages: nrpages = %d\n", iobuf->nr_pages);
+		/* Check all the pages are dirty and lock them */
+		for(i = 0; i < iobuf->nr_pages; i++) {
+			struct page *page = iobuf->maplist[i];
+			BUG_ON(!PageDirty(page));
+			lock_page(page);
+		}
+		err = brw_kiovec(WRITE, 1, &iobuf, kdev, iobuf->blocks, PAGE_SIZE);
+		DEBUG(3, "commit_write: committed %d pages err = %d\n", iobuf->nr_pages, err);
+		while(iobuf->nr_pages) {
+			struct page *page = iobuf->maplist[--iobuf->nr_pages];
+			ClearPageDirty(page);
+			SetPageUptodate(page);
+			unlock_page(page);
+			page_cache_release(page);
+		}
+	}
+
+	DEBUG(2, "blkmtd: sync: end, err = %d\n", err);
+	iobuf->offset = 0;
+	iobuf->nr_pages = 0;
+	iobuf->length = 0;
+	return err;
+}
 
 
-/* This is the kernel thread that empties the write queue to disk */
-static int write_queue_task(void *data)
+/**
+ * write_pages - write block of data to device via the page cache
+ * @dev: device to write to
+ * @buf: data source or NULL if erase (output is set to 0xff)
+ * @to: offset into output device
+ * @len: amount to data to write
+ * @retlen: amount of data written
+ *
+ * Grab pages from the page cache and fill them with the source data.
+ * Non page aligned start and end result in a readin of the page and
+ * part of the page being modified. Pages are added to the wr_buf kiobuf
+ * until this becomes full or the next page written to has a lower pagenr
+ * then the current max pagenr in the kiobuf.
+ */
+static int write_pages(struct blkmtd_dev *dev, const u_char *buf, loff_t to,
+		    size_t len, int *retlen)
 {
-  int err;
-  struct task_struct *tsk = current;
-  struct kiobuf *iobuf;
-  unsigned long *blocks;
-
-  DECLARE_WAITQUEUE(wait, tsk);
-  DEBUG(1, "blkmtd: writetask: starting (pid = %d)\n", tsk->pid);
-  daemonize();
-  strcpy(tsk->comm, "blkmtdd");
-  tsk->tty = NULL;
-  spin_lock_irq(&tsk->sigmask_lock);
-  sigfillset(&tsk->blocked);
-  recalc_sigpending(tsk);
-  spin_unlock_irq(&tsk->sigmask_lock);
-  exit_sighand(tsk);
-
-  if(alloc_kiovec(1, &iobuf)) {
-    printk("blkmtd: write_queue_task cant allocate kiobuf\n");
-    return 0;
-  }
+	int pagenr, offset;
+	size_t start_len = 0, end_len;
+	int pagecnt = 0;
+	struct kiobuf *iobuf = dev->wr_buf;
+	int err = 0;
+	struct page *pagelst[2];
+	int pagenrs[2];
+	int readpages = 0;
+	int ignorepage = -1;
+
+	pagenr = to >> PAGE_SHIFT;
+	offset = to & ~PAGE_MASK;
+
+	DEBUG(2, "blkmtd: write_pages: buf = %p to = %ld len = %d pagenr = %d offset = %d\n",
+	      buf, (long)to, len, pagenr, offset);
+
+	*retlen = 0;
+	/* see if we have to do a partial write at the start */
+	if(offset) {
+		start_len = ((offset + len) > PAGE_SIZE) ? PAGE_SIZE - offset : len;
+		len -= start_len;
+	}
 
-  /* Pre 2.4.4 doesn't have space for the block list in the kiobuf */ 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
-  blocks = kmalloc(KIO_MAX_SECTORS * sizeof(unsigned long));
-  if(blocks == NULL) {
-    printk("blkmtd: write_queue_task cant allocate iobuf blocks\n");
-    free_kiovec(1, &iobuf);
-    return 0;
-  }
-#else 
-  blocks = iobuf->blocks;
-#endif
+	/* calculate the length of the other two regions */
+	end_len = len & ~PAGE_MASK;
+	len -= end_len;
+
+	if(start_len) {
+		pagenrs[0] = pagenr;
+		readpages++;
+		pagecnt++;
+	}
+	if(len)
+		pagecnt += len >> PAGE_SHIFT;
+	if(end_len) {
+		pagenrs[readpages] = pagenr + pagecnt;
+		readpages++;
+		pagecnt++;
+	}
 
-  DEBUG(2, "blkmtd: writetask: entering main loop\n");
-  add_wait_queue(&thr_wq, &wait);
+	DEBUG(3, "blkmtd: write: start_len = %d len = %d end_len = %d pagecnt = %d\n",
+	      start_len, len, end_len, pagecnt);
 
-  while(1) {
-    spin_lock(&mbd_writeq_lock);
+	down(&dev->wrbuf_mutex);
 
-    if(!write_queue_cnt) {
-      /* If nothing in the queue, wake up anyone wanting to know when there
-	 is space in the queue then sleep for 2*HZ */
-      spin_unlock(&mbd_writeq_lock);
-      DEBUG(4, "blkmtd: writetask: queue empty\n");
-      if(waitqueue_active(&mtbd_sync_wq))
-	 wake_up(&mtbd_sync_wq);
-      interruptible_sleep_on_timeout(&thr_wq, 2*HZ);
-      DEBUG(4, "blkmtd: writetask: woken up\n");
-      if(write_task_finish)
-	break;
-    } else {
-      /* we have stuff to write */
-      mtdblkdev_write_queue_t *item = &write_queue[write_queue_tail];
-      struct page **pages = item->pages;
-
-      int i;
-      int sectornr = item->pagenr << (PAGE_SHIFT - item->rawdevice->sector_bits);
-      int sectorcnt = item->pagecnt << (PAGE_SHIFT - item->rawdevice->sector_bits);
-      int max_sectors = KIO_MAX_SECTORS >> (item->rawdevice->sector_bits - 9);
-      kdev_t dev = to_kdev_t(item->rawdevice->binding->bd_dev);
-
-      /* If we are writing to the last page on the device and it doesn't end
-       * on a page boundary, subtract the number of sectors that dont exist.
-       */
-      if(item->rawdevice->partial_last_page && 
-	 (item->pagenr + item->pagecnt -1) == item->rawdevice->partial_last_page) {
-	sectorcnt -= (1 << (PAGE_SHIFT - item->rawdevice->sector_bits));
-	sectorcnt += item->rawdevice->last_page_sectors;
-      }
-
-      DEBUG(3, "blkmtd: writetask: got %d queue items\n", write_queue_cnt);
-      set_current_state(TASK_RUNNING);
-      spin_unlock(&mbd_writeq_lock);
-
-      DEBUG(2, "blkmtd: writetask: writing pagenr = %d pagecnt = %d sectornr = %d sectorcnt = %d\n", 
-	    item->pagenr, item->pagecnt, sectornr, sectorcnt);
-
-      iobuf->offset = 0;
-      iobuf->locked = 1;
-
-      /* Loop through all the pages to be written in the queue item, remembering
-	 we can only write KIO_MAX_SECTORS at a time */
-	 
-      while(sectorcnt) {
-	int cursectors = (sectorcnt < max_sectors) ? sectorcnt : max_sectors;
-	int cpagecnt = (cursectors << item->rawdevice->sector_bits) + PAGE_SIZE-1;
-	cpagecnt >>= PAGE_SHIFT;
-	
-	for(i = 0; i < cpagecnt; i++) {
-	  if(item->iserase) {
-	    iobuf->maplist[i] = erase_page;
-	  } else {
-	    iobuf->maplist[i] = *(pages++);
-	  }
+	if(iobuf->nr_pages && ((pagenr <= iobuf->blocks[iobuf->nr_pages-1])
+			       || (iobuf->nr_pages + pagecnt) >= KIO_STATIC_PAGES)) {
+
+		if((pagenr == iobuf->blocks[iobuf->nr_pages-1])
+		   && ((iobuf->nr_pages + pagecnt) < KIO_STATIC_PAGES)) {
+			iobuf->nr_pages--;
+			ignorepage = pagenr;
+		} else {
+			DEBUG(3, "blkmtd: doing writeout pagenr = %d max_pagenr = %ld pagecnt = %d idx = %d\n",
+			      pagenr, iobuf->blocks[iobuf->nr_pages-1],
+			      pagecnt, iobuf->nr_pages);
+			commit_pages(dev);
+		}
 	}
 	
-	for(i = 0; i < cursectors; i++) {
-	  blocks[i] = sectornr++;
+	if(readpages) {
+		err = read_pages(dev, pagenrs, pagelst, readpages);
+		if(err < 0)
+			goto readin_err;
 	}
-	
-	iobuf->nr_pages = cpagecnt;
-	iobuf->length = cursectors << item->rawdevice->sector_bits;
-	DEBUG(3, "blkmtd: write_task: about to kiovec\n");
-	err = brw_kiovec(WRITE, 1, &iobuf, dev, blocks, item->rawdevice->sector_size);
-	DEBUG(3, "bklmtd: write_task: done, err = %d\n", err);
-	if(err != (cursectors << item->rawdevice->sector_bits)) {
-	  /* if an error occured - set this to exit the loop */
-	  sectorcnt = 0;
-	} else {
-	  sectorcnt -= cursectors;
+
+	if(start_len) {
+		/* do partial start region */
+		struct page *page;
+
+		DEBUG(3, "blkmtd: write: doing partial start, page = %d len = %d offset = %d\n",
+		      pagenr, start_len, offset);
+		page = pagelst[0];
+		BUG_ON(!buf);
+		if(PageDirty(page) && pagenr != ignorepage) {
+			err("to = %lld start_len = %d len = %d end_len = %d pagenr = %d ignorepage = %d\n",
+			    to, start_len, len, end_len, pagenr, ignorepage);
+			BUG();
+		}
+		memcpy(page_address(page)+offset, buf, start_len);
+		SetPageDirty(page);
+		SetPageUptodate(page);
+		unlock_page(page);
+		buf += start_len;
+		*retlen = start_len;
+		err = 0;
+		iobuf->blocks[iobuf->nr_pages] = pagenr++;
+		iobuf->maplist[iobuf->nr_pages] = page;
+		iobuf->nr_pages++;
 	}
-      }
 
-      /* free up the pages used in the write and list of pages used in the write
-	 queue item */
-      iobuf->locked = 0;
-      spin_lock(&mbd_writeq_lock);
-      write_queue_cnt--;
-      write_queue_tail++;
-      write_queue_tail %= write_queue_sz;
-      if(!item->iserase) {
-	for(i = 0 ; i < item->pagecnt; i++) {
-	  UnlockPage(item->pages[i]);
-	  __free_pages(item->pages[i], 0);
-	}
-	kfree(item->pages);
-      }
-      item->pages = NULL;
-      spin_unlock(&mbd_writeq_lock);
-      /* Tell others there is some space in the write queue */
-      if(waitqueue_active(&mtbd_sync_wq))
-	wake_up(&mtbd_sync_wq);
-    }
-  }
-  remove_wait_queue(&thr_wq, &wait);
-  DEBUG(1, "blkmtd: writetask: exiting\n");
-  free_kiovec(1, &iobuf);
+	/* Now do the main loop to a page aligned, n page sized output */
+	if(len) {
+		int pagesc = len >> PAGE_SHIFT;
+		DEBUG(3, "blkmtd: write: whole pages start = %d, count = %d\n",
+		      pagenr, pagesc);
+		while(pagesc) {
+			struct page *page;
+
+			/* see if page is in the page cache */
+			DEBUG(3, "blkmtd: write: grabbing page %d from page cache\n", pagenr);
+			page = grab_cache_page(dev->binding->bd_inode->i_mapping, pagenr);
+			if(PageDirty(page) && pagenr != ignorepage) {
+				BUG();
+			}
+			if(!page) {
+				warn("write: cant grab cache page %d", pagenr);
+				err = -ENOMEM;
+				goto write_err;
+			}
+			if(!buf) {
+				memset(page_address(page), 0xff, PAGE_SIZE);
+			} else {
+				memcpy(page_address(page), buf, PAGE_SIZE);
+				buf += PAGE_SIZE;
+			}
+			iobuf->blocks[iobuf->nr_pages] = pagenr++;
+			iobuf->maplist[iobuf->nr_pages] = page;
+			iobuf->nr_pages++;
+			SetPageDirty(page);
+			SetPageUptodate(page);
+			unlock_page(page);
+			pagesc--;
+			*retlen += PAGE_SIZE;
+		}
+	}
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
-  kfree(blocks);
-#endif
+	if(end_len) {
+		/* do the third region */
+		struct page *page;
+		DEBUG(3, "blkmtd: write: doing partial end, page = %d len = %d\n",
+		      pagenr, end_len);
+		page = pagelst[readpages-1];
+		BUG_ON(!buf);
+		if(PageDirty(page) && pagenr != ignorepage) {
+			err("to = %lld start_len = %d len = %d end_len = %d pagenr = %d ignorepage = %d\n",
+			    to, start_len, len, end_len, pagenr, ignorepage);
+			BUG();
+		}
+		memcpy(page_address(page), buf, end_len);
+		SetPageDirty(page);
+		SetPageUptodate(page);
+		unlock_page(page);
+		DEBUG(3, "blkmtd: write: writing out partial end\n");
+		*retlen += end_len;
+		err = 0;
+		iobuf->blocks[iobuf->nr_pages] = pagenr;
+		iobuf->maplist[iobuf->nr_pages] = page;
+		iobuf->nr_pages++;
+	}
 
-  /* Tell people we have exitd */
-  up(&thread_sem);
-  return 0;
-}
+	DEBUG(2, "blkmtd: write: end, retlen = %d, err = %d\n", *retlen, err);
 
+	if(sync) {
+write_err:
+		commit_pages(dev);
+	}
 
-/* Add a range of pages into the outgoing write queue, making copies of them */
-static int queue_page_write(mtd_raw_dev_data_t *rawdevice, struct page **pages,
-			    int pagenr, int pagecnt, int iserase)
-{
-  struct page *outpage;
-  struct page **new_pages = NULL;
-  mtdblkdev_write_queue_t *item;
-  int i;
-  DECLARE_WAITQUEUE(wait, current);
-  DEBUG(2, "blkmtd: queue_page_write: adding pagenr = %d pagecnt = %d\n", pagenr, pagecnt);
-
-  if(!pagecnt)
-    return 0;
-
-  if(pages == NULL && !iserase)
-    return -EINVAL;
-
-  /* create a array for the list of pages */
-  if(!iserase) {
-    new_pages = kmalloc(pagecnt * sizeof(struct page *), GFP_KERNEL);
-    if(new_pages == NULL)
-      return -ENOMEM;
-
-    /* make copies of the pages in the page cache */
-    for(i = 0; i < pagecnt; i++) {
-      outpage = alloc_pages(GFP_KERNEL, 0);
-      if(!outpage) {
-	while(i--) {
-	  UnlockPage(new_pages[i]);
-	  __free_pages(new_pages[i], 0);
-	}
-	kfree(new_pages);
-	return -ENOMEM;
-      }
-      lock_page(outpage);
-      memcpy(page_address(outpage), page_address(pages[i]), PAGE_SIZE);
-      new_pages[i] = outpage;
-    }
-  }
-
-  /* wait until there is some space in the write queue */
- test_lock:
-  spin_lock(&mbd_writeq_lock);
-  if(write_queue_cnt == write_queue_sz) {
-    spin_unlock(&mbd_writeq_lock);
-    DEBUG(3, "blkmtd: queue_page: Queue full\n");
-    current->state = TASK_UNINTERRUPTIBLE;
-    add_wait_queue(&mtbd_sync_wq, &wait);
-    wake_up_interruptible(&thr_wq);
-    schedule();
-    current->state = TASK_RUNNING;
-    remove_wait_queue(&mtbd_sync_wq, &wait);
-    DEBUG(3, "blkmtd: queue_page_write: Queue has %d items in it\n", write_queue_cnt);
-    goto test_lock;
-  }
-
-  DEBUG(3, "blkmtd: queue_page_write: qhead: %d qtail: %d qcnt: %d\n", 
-	write_queue_head, write_queue_tail, write_queue_cnt);
-
-  /* fix up the queue item */
-  item = &write_queue[write_queue_head];
-  item->pages = new_pages;
-  item->pagenr = pagenr;
-  item->pagecnt = pagecnt;
-  item->rawdevice = rawdevice;
-  item->iserase = iserase;
-
-  write_queue_head++;
-  write_queue_head %= write_queue_sz;
-  write_queue_cnt++;
-  DEBUG(3, "blkmtd: queue_page_write: qhead: %d qtail: %d qcnt: %d\n", 
-	write_queue_head, write_queue_tail, write_queue_cnt);
-  spin_unlock(&mbd_writeq_lock);
-  DEBUG(2, "blkmtd: queue_page_write: finished\n");
-  return 0;
+readin_err:
+	up(&dev->wrbuf_mutex);
+	return err;
 }
 
 
 /* erase a specified part of the device */
 static int blkmtd_erase(struct mtd_info *mtd, struct erase_info *instr)
 {
-  mtd_raw_dev_data_t *rawdevice = mtd->priv;
-  struct mtd_erase_region_info *einfo = mtd->eraseregions;
-  int numregions = mtd->numeraseregions;
-  size_t from;
-  u_long len;
-  int err = 0;
-
-  /* check readonly */
-  if(rawdevice->readonly) {
-    printk("blkmtd: error: trying to erase readonly device %s\n", device);
-    instr->state = MTD_ERASE_FAILED;
-    goto erase_callback;
-  }
-
-  instr->state = MTD_ERASING;
-  from = instr->addr;
-  len = instr->len;
-
-  /* check erase region has valid start and length */
-  DEBUG(2, "blkmtd: erase: dev = `%s' from = 0x%x len = 0x%lx\n",
-	bdevname(rawdevice->binding->bd_dev), from, len);
-  while(numregions) {
-    DEBUG(3, "blkmtd: checking erase region = 0x%08X size = 0x%X num = 0x%x\n",
-	  einfo->offset, einfo->erasesize, einfo->numblocks);
-    if(from >= einfo->offset && from < einfo->offset + (einfo->erasesize * einfo->numblocks)) {
-      if(len == einfo->erasesize && ( (from - einfo->offset) % einfo->erasesize == 0))
-	break;
-    }
-    numregions--;
-    einfo++;
-  }
-
-  if(!numregions) {
-    /* Not a valid erase block */
-    printk("blkmtd: erase: invalid erase request 0x%lX @ 0x%08X\n", len, from);
-    instr->state = MTD_ERASE_FAILED;
-    err = -EIO;
-  }
-  
-  if(instr->state != MTD_ERASE_FAILED) {
-    /* start the erase */
-    int pagenr, pagecnt;
-    struct page *page, **pages;
-    int i = 0;
-
-    /* Handle the last page of the device not being whole */
-    if(len < PAGE_SIZE)
-      len = PAGE_SIZE;
-
-    pagenr = from >> PAGE_SHIFT;
-    pagecnt = len >> PAGE_SHIFT;
-    DEBUG(3, "blkmtd: erase: pagenr = %d pagecnt = %d\n", pagenr, pagecnt);
-
-    pages = kmalloc(pagecnt * sizeof(struct page *), GFP_KERNEL);
-    if(pages == NULL) {
-      err = -ENOMEM;
-      instr->state = MTD_ERASE_FAILED;
-      goto erase_out;
-    }
-
-
-    while(pagecnt) {
-      /* get the page via the page cache */
-      DEBUG(3, "blkmtd: erase: doing grab_cache_page() for page %d\n", pagenr);
-      page = grab_cache_page(&rawdevice->as, pagenr);
-      if(!page) {
-	DEBUG(3, "blkmtd: erase: grab_cache_page() failed for page %d\n", pagenr);
-	kfree(pages);
-	err = -EIO;
-	instr->state = MTD_ERASE_FAILED;
-	goto erase_out;
-      }
-      memset(page_address(page), 0xff, PAGE_SIZE);
-      pages[i] = page;
-      pagecnt--;
-      pagenr++;
-      i++;
-    }
-    DEBUG(3, "blkmtd: erase: queuing page write\n");
-    err = queue_page_write(rawdevice, NULL, from >> PAGE_SHIFT, len >> PAGE_SHIFT, 1);
-    pagecnt = len >> PAGE_SHIFT;
-    if(!err) {
-      while(pagecnt--) {
-	SetPageUptodate(pages[pagecnt]);
-	UnlockPage(pages[pagecnt]);
-	page_cache_release(pages[pagecnt]);
-	flush_dcache_page(pages[pagecnt]);
-      }
-      kfree(pages);
-      instr->state = MTD_ERASE_DONE;
-    } else {
-      while(pagecnt--) {
-	SetPageError(pages[pagecnt]);
-	page_cache_release(pages[pagecnt]);
-      }
-      kfree(pages);
-      instr->state = MTD_ERASE_FAILED;
-    }
-  }
- erase_out:
-  DEBUG(3, "blkmtd: erase: checking callback\n");
+	struct blkmtd_dev *dev = mtd->priv;
+	struct mtd_erase_region_info *einfo = mtd->eraseregions;
+	int numregions = mtd->numeraseregions;
+	size_t from;
+	u_long len;
+	int err = -EIO;
+	int retlen;
+
+	/* check readonly */
+	if(!dev->wr_buf) {
+		err("error: mtd%d trying to erase readonly device %s",
+		    mtd->index, mtd->name);
+		instr->state = MTD_ERASE_FAILED;
+		goto erase_callback;
+	}
+
+	instr->state = MTD_ERASING;
+	from = instr->addr;
+	len = instr->len;
+
+	/* check erase region has valid start and length */
+	DEBUG(2, "blkmtd: erase: dev = `%s' from = 0x%x len = 0x%lx\n",
+	      bdevname(dev->binding->bd_dev), from, len);
+	while(numregions) {
+		DEBUG(3, "blkmtd: checking erase region = 0x%08X size = 0x%X num = 0x%x\n",
+		      einfo->offset, einfo->erasesize, einfo->numblocks);
+		if(from >= einfo->offset
+		   && from < einfo->offset + (einfo->erasesize * einfo->numblocks)) {
+			if(len == einfo->erasesize
+			   && ( (from - einfo->offset) % einfo->erasesize == 0))
+				break;
+		}
+		numregions--;
+		einfo++;
+	}
+
+	if(!numregions) {
+		/* Not a valid erase block */
+		err("erase: invalid erase request 0x%lX @ 0x%08X", len, from);
+		instr->state = MTD_ERASE_FAILED;
+		err = -EIO;
+	}
+
+	if(instr->state != MTD_ERASE_FAILED) {
+		/* do the erase */
+		DEBUG(3, "Doing erase from = %d len = %ld\n", from, len);
+		err = write_pages(dev, NULL, from, len, &retlen);
+		if(err < 0) {
+			err("erase failed err = %d", err);
+			instr->state = MTD_ERASE_FAILED;
+		} else {
+			instr->state = MTD_ERASE_DONE;
+			err = 0;
+		}
+	}
+
+	DEBUG(3, "blkmtd: erase: checking callback\n");
  erase_callback:
-  if (instr->callback) {
-    (*(instr->callback))(instr);
-  }
-  DEBUG(2, "blkmtd: erase: finished (err = %d)\n", err);
-  return err;
+	if (instr->callback) {
+		(*(instr->callback))(instr);
+	}
+	DEBUG(2, "blkmtd: erase: finished (err = %d)\n", err);
+	return err;
 }
 
 
 /* read a range of the data via the page cache */
 static int blkmtd_read(struct mtd_info *mtd, loff_t from, size_t len,
-	     size_t *retlen, u_char *buf)
+		       size_t *retlen, u_char *buf)
 {
-  mtd_raw_dev_data_t *rawdevice = mtd->priv;
-  int err = 0;
-  int offset;
-  int pagenr, pages;
-
-  *retlen = 0;
-
-  DEBUG(2, "blkmtd: read: dev = `%s' from = %ld len = %d buf = %p\n",
-	bdevname(rawdevice->binding->bd_dev), (long int)from, len, buf);
-
-  pagenr = from >> PAGE_SHIFT;
-  offset = from - (pagenr << PAGE_SHIFT);
-  
-  pages = (offset+len+PAGE_SIZE-1) >> PAGE_SHIFT;
-  DEBUG(3, "blkmtd: read: pagenr = %d offset = %d, pages = %d\n", pagenr, offset, pages);
-
-  /* just loop through each page, getting it via readpage() - slow but easy */
-  while(pages) {
-    struct page *page;
-    int cpylen;
-    DEBUG(3, "blkmtd: read: looking for page: %d\n", pagenr);
-    page = read_cache_page(&rawdevice->as, pagenr, (filler_t *)blkmtd_readpage, rawdevice);
-    if(IS_ERR(page)) {
-      return PTR_ERR(page);
-    }
-    wait_on_page(page);
-    if(!Page_Uptodate(page)) {
-      /* error reading page */
-      printk("blkmtd: read: page not uptodate\n");
-      page_cache_release(page);
-      return -EIO;
-    }
-
-    cpylen = (PAGE_SIZE > len) ? len : PAGE_SIZE;
-    if(offset+cpylen > PAGE_SIZE)
-      cpylen = PAGE_SIZE-offset;
-    
-    memcpy(buf + *retlen, page_address(page) + offset, cpylen);
-    offset = 0;
-    len -= cpylen;
-    *retlen += cpylen;
-    pagenr++;
-    pages--;
-    page_cache_release(page);
-  }
-  
-  DEBUG(2, "blkmtd: end read: retlen = %d, err = %d\n", *retlen, err);
-  return err;
+	struct blkmtd_dev *dev = mtd->priv;
+	int err = 0;
+	int offset;
+	int pagenr, pages;
+	struct page **pagelst;
+	int *pagenrs;
+	int i;
+
+	*retlen = 0;
+
+	DEBUG(2, "blkmtd: read: dev = `%s' from = %ld len = %d buf = %p\n",
+	      bdevname(dev->binding->bd_dev), (long int)from, len, buf);
+
+	pagenr = from >> PAGE_SHIFT;
+	offset = from - (pagenr << PAGE_SHIFT);
+
+	pages = (offset+len+PAGE_SIZE-1) >> PAGE_SHIFT;
+	DEBUG(3, "blkmtd: read: pagenr = %d offset = %d, pages = %d\n",
+	      pagenr, offset, pages);
+
+	pagelst = kmalloc(sizeof(struct page *) * pages, GFP_KERNEL);
+	if(!pagelst)
+		return -ENOMEM;
+	pagenrs = kmalloc(sizeof(int) * pages, GFP_KERNEL);
+	if(!pagenrs) {
+		kfree(pagelst);
+		return -ENOMEM;
+	}
+	for(i = 0; i < pages; i++)
+		pagenrs[i] = pagenr+i;
+
+	err = read_pages(dev, pagenrs, pagelst, pages);
+	if(err)
+		goto readerr;
+
+	pagenr = 0;
+	while(pages) {
+		struct page *page;
+		int cpylen;
+
+		DEBUG(3, "blkmtd: read: looking for page: %d\n", pagenr);
+		page = pagelst[pagenr];
+
+		cpylen = (PAGE_SIZE > len) ? len : PAGE_SIZE;
+		if(offset+cpylen > PAGE_SIZE)
+			cpylen = PAGE_SIZE-offset;
+
+		memcpy(buf + *retlen, page_address(page) + offset, cpylen);
+		offset = 0;
+		len -= cpylen;
+		*retlen += cpylen;
+		pagenr++;
+		pages--;
+		unlock_page(page);
+		if(!PageDirty(page))
+			page_cache_release(page);
+	}
+
+ readerr:
+	kfree(pagelst);
+	kfree(pagenrs);
+	DEBUG(2, "blkmtd: end read: retlen = %d, err = %d\n", *retlen, err);
+	return err;
 }
 
-    
-/* write a range of the data via the page cache.
- *
- * Basic operation. break the write into three parts. 
- *
- * 1. From a page unaligned start up until the next page boundary
- * 2. Page sized, page aligned blocks
- * 3. From end of last aligned block to end of range
- *
- * 1,3 are read via the page cache and readpage() since these are partial
- * pages, 2 we just grab pages from the page cache, not caring if they are
- * already in memory or not since they will be completly overwritten.
- *
- */
- 
+
+/* write data to the underlying device */
 static int blkmtd_write(struct mtd_info *mtd, loff_t to, size_t len,
-	      size_t *retlen, const u_char *buf)
+			size_t *retlen, const u_char *buf)
 {
-  mtd_raw_dev_data_t *rawdevice = mtd->priv;
-  int err = 0;
-  int offset;
-  int pagenr;
-  size_t len1 = 0, len2 = 0, len3 = 0;
-  struct page **pages;
-  int pagecnt = 0;
-
-  *retlen = 0;
-  DEBUG(2, "blkmtd: write: dev = `%s' to = %ld len = %d buf = %p\n",
-	bdevname(rawdevice->binding->bd_dev), (long int)to, len, buf);
-
-  /* handle readonly and out of range numbers */
-
-  if(rawdevice->readonly) {
-    printk("blkmtd: error: trying to write to a readonly device %s\n", device);
-    return -EROFS;
-  }
-
-  if(to >= rawdevice->totalsize) {
-    return -ENOSPC;
-  }
-
-  if(to + len > rawdevice->totalsize) {
-    len = (rawdevice->totalsize - to);
-  }
-
-
-  pagenr = to >> PAGE_SHIFT;
-  offset = to - (pagenr << PAGE_SHIFT);
-
-  /* see if we have to do a partial write at the start */
-  if(offset) {
-    if((offset + len) > PAGE_SIZE) {
-      len1 = PAGE_SIZE - offset;
-      len -= len1;
-    } else {
-      len1 = len;
-      len = 0;
-    }
-  }
-
-  /* calculate the length of the other two regions */
-  len3 = len & ~PAGE_MASK;
-  len -= len3;
-  len2 = len;
-
-
-  if(len1)
-    pagecnt++;
-  if(len2)
-    pagecnt += len2 >> PAGE_SHIFT;
-  if(len3)
-    pagecnt++;
-
-  DEBUG(3, "blkmtd: write: len1 = %d len2 = %d len3 = %d pagecnt = %d\n", len1, len2, len3, pagecnt);
-  
-  /* get space for list of pages */
-  pages = kmalloc(pagecnt * sizeof(struct page *), GFP_KERNEL);
-  if(pages == NULL) {
-    return -ENOMEM;
-  }
-  pagecnt = 0;
-
-  if(len1) {
-    /* do partial start region */
-    struct page *page;
-    
-    DEBUG(3, "blkmtd: write: doing partial start, page = %d len = %d offset = %d\n", pagenr, len1, offset);
-    page = read_cache_page(&rawdevice->as, pagenr, (filler_t *)blkmtd_readpage, rawdevice);
-
-    if(IS_ERR(page)) {
-      kfree(pages);
-      return PTR_ERR(page);
-    }
-    memcpy(page_address(page)+offset, buf, len1);
-    pages[pagecnt++] = page;
-    buf += len1;
-    *retlen = len1;
-    err = 0;
-    pagenr++;
-  }
-
-  /* Now do the main loop to a page aligned, n page sized output */
-  if(len2) {
-    int pagesc = len2 >> PAGE_SHIFT;
-    DEBUG(3, "blkmtd: write: whole pages start = %d, count = %d\n", pagenr, pagesc);
-    while(pagesc) {
-      struct page *page;
-
-      /* see if page is in the page cache */
-      DEBUG(3, "blkmtd: write: grabbing page %d from page cache\n", pagenr);
-      page = grab_cache_page(&rawdevice->as, pagenr);
-      DEBUG(3, "blkmtd: write: got page %d from page cache\n", pagenr);
-      if(!page) {
-	printk("blkmtd: write: cant grab cache page %d\n", pagenr);
-	err = -EIO;
-	goto write_err;
-      }
-      memcpy(page_address(page), buf, PAGE_SIZE);
-      pages[pagecnt++] = page;
-      UnlockPage(page);
-      SetPageUptodate(page);
-      pagenr++;
-      pagesc--;
-      buf += PAGE_SIZE;
-      *retlen += PAGE_SIZE;
-    }
-  }
-
-
-  if(len3) {
-    /* do the third region */
-    struct page *page;
-    DEBUG(3, "blkmtd: write: doing partial end, page = %d len = %d\n", pagenr, len3);
-    page = read_cache_page(&rawdevice->as, pagenr, (filler_t *)blkmtd_readpage, rawdevice);
-    if(IS_ERR(page)) {
-      err = PTR_ERR(page);
-      goto write_err;
-    }
-    memcpy(page_address(page), buf, len3);
-    DEBUG(3, "blkmtd: write: writing out partial end\n");
-    pages[pagecnt++] = page;
-    *retlen += len3;
-    err = 0;
-  }
-  DEBUG(2, "blkmtd: write: end, retlen = %d, err = %d\n", *retlen, err);
-  /* submit it to the write task */
-  err = queue_page_write(rawdevice, pages, to >> PAGE_SHIFT, pagecnt, 0);
-  if(!err) {
-    while(pagecnt--) {
-      SetPageUptodate(pages[pagecnt]);
-      flush_dcache_page(pages[pagecnt]);
-      page_cache_release(pages[pagecnt]);
-    }
-    kfree(pages);
-    return 0;
-  }
-
- write_err:
-  while(--pagecnt) {
-    SetPageError(pages[pagecnt]);
-    page_cache_release(pages[pagecnt]);
-  }
-  kfree(pages);
-  return err;
+	struct blkmtd_dev *dev = mtd->priv;
+	int err;
+
+	*retlen = 0;
+	if(!len)
+		return 0;
+
+	DEBUG(2, "blkmtd: write: dev = `%s' to = %ld len = %d buf = %p\n",
+	      bdevname(dev->binding->bd_dev), (long int)to, len, buf);
+
+	/* handle readonly and out of range numbers */
+
+	if(!dev->wr_buf) {
+		err("error: trying to write to a readonly device %s", mtd->name);
+		return -EROFS;
+	}
+
+	if(to >= mtd->size) {
+		return -ENOSPC;
+	}
+
+	if(to + len > mtd->size) {
+		len = (mtd->size - to);
+	}
+
+	err = write_pages(dev, buf, to, len, retlen);
+	if(err < 0)
+		*retlen = 0;
+	else
+		err = 0;
+	DEBUG(2, "blkmtd: write: end, err = %d\n", err);
+	return err;
 }
 
 
 /* sync the device - wait until the write queue is empty */
 static void blkmtd_sync(struct mtd_info *mtd)
 {
-  DECLARE_WAITQUEUE(wait, current);
-  mtd_raw_dev_data_t *rawdevice = mtd->priv;
-  if(rawdevice->readonly)
-    return;
-
-  DEBUG(2, "blkmtd: sync: called\n");
-
- stuff_inq:
-  spin_lock(&mbd_writeq_lock);
-  if(write_queue_cnt) {
-    spin_unlock(&mbd_writeq_lock);
-    current->state = TASK_UNINTERRUPTIBLE;
-    add_wait_queue(&mtbd_sync_wq, &wait);
-    DEBUG(3, "blkmtd: sync: waking up task\n");
-    wake_up_interruptible(&thr_wq);
-    schedule();
-    current->state = TASK_RUNNING;
-    remove_wait_queue(&mtbd_sync_wq, &wait);
-    DEBUG(3, "blkmtd: sync: waking up after write task\n");
-    goto stuff_inq;
-  }
-  spin_unlock(&mbd_writeq_lock);
+	struct blkmtd_dev *dev = mtd->priv;
+	struct kiobuf *iobuf = dev->wr_buf;
 
-  DEBUG(2, "blkmtd: sync: finished\n");
+	DEBUG(2, "blkmtd: sync: called\n");
+	if(iobuf == NULL)
+		return;
+
+	DEBUG(3, "blkmtd: kiovec: length = %d nr_pages = %d\n",
+	      iobuf->length, iobuf->nr_pages);
+	down(&dev->wrbuf_mutex);
+	if(iobuf->nr_pages)
+		commit_pages(dev);
+	up(&dev->wrbuf_mutex);
 }
 
 
 #ifdef BLKMTD_PROC_DEBUG
 /* procfs stuff */
-static int blkmtd_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data)
+static int blkmtd_proc_read(char *page, char **start, off_t off,
+			    int count, int *eof, void *data)
+{
+	int len;
+	struct list_head *temp1, *temp2;
+
+	MOD_INC_USE_COUNT;
+
+	/* Count the size of the page lists */
+
+	len = sprintf(page, "dev\twr_idx\tmax_idx\tnrpages\tclean\tdirty\tlocked\tlru\n");
+	list_for_each_safe(temp1, temp2, &blkmtd_device_list) {
+		struct blkmtd_dev *dev = list_entry(temp1,  struct blkmtd_dev,
+						    list);
+		struct list_head *temp;
+		struct page *pagei;
+
+		int clean = 0, dirty = 0, locked = 0, lru = 0;
+		/* Count the size of the page lists */
+		list_for_each(temp, &dev->binding->bd_inode->i_mapping->clean_pages) {
+			pagei = list_entry(temp, struct page, list);
+			clean++;
+			if(PageLocked(pagei))
+				locked++;
+			if(PageDirty(pagei))
+				dirty++;
+			if(PageLRU(pagei))
+				lru++;
+		}
+		list_for_each(temp, &dev->binding->bd_inode->i_mapping->dirty_pages) {
+			pagei = list_entry(temp, struct page, list);
+			if(PageLocked(pagei))
+				locked++;
+			if(PageDirty(pagei))
+				dirty++;
+			if(PageLRU(pagei))
+				lru++;
+		}
+		list_for_each(temp, &dev->binding->bd_inode->i_mapping->locked_pages) {
+			pagei = list_entry(temp, struct page, list);
+			if(PageLocked(pagei))
+				locked++;
+			if(PageDirty(pagei))
+				dirty++;
+			if(PageLRU(pagei))
+				lru++;
+		}
+
+		len += sprintf(page+len, "mtd%d:\t%ld\t%d\t%ld\t%d\t%d\t%d\t%d\n",
+			       dev->mtd_info.index,
+			       (dev->wr_buf && dev->wr_buf->nr_pages) ?
+			       dev->wr_buf->blocks[dev->wr_buf->nr_pages-1] : 0,
+			       (dev->wr_buf) ? dev->wr_buf->nr_pages : 0,
+			       dev->binding->bd_inode->i_mapping->nrpages,
+			       clean, dirty, locked, lru);
+	}
+
+	if(len <= count)
+		*eof = 1;
+
+	MOD_DEC_USE_COUNT;
+	return len;
+}
+#endif
+
+
+static void free_device(struct blkmtd_dev *dev)
 {
-  int clean = 0, dirty = 0, locked = 0;
-  struct list_head *temp;
-  int i, len, pages = 0, cnt;
-  MOD_INC_USE_COUNT;
-  spin_lock(&mbd_writeq_lock);
-  cnt = write_queue_cnt;
-  i = write_queue_tail;
-  while(cnt) {
-    if(!write_queue[i].iserase)
-      pages += write_queue[i].pagecnt;
-    i++;
-    i %= write_queue_sz;
-    cnt--;
-  }
-
-  /* Count the size of the page lists */
-  list_for_each(temp, &mtd_rawdevice->as.clean_pages) {
-    clean++;
-  }
-  list_for_each(temp, &mtd_rawdevice->as.dirty_pages) {
-    dirty++;
-  }
-  list_for_each(temp, &mtd_rawdevice->as.locked_pages) {
-    locked++;
-  }
-
-  len = sprintf(page, "Write queue head: %d\nWrite queue tail: %d\n"
-		"Write queue count: %d\nPages in queue: %d (%dK)\n"
-		"Clean Pages: %d\nDirty Pages: %d\nLocked Pages: %d\n"
-		"nrpages: %ld\n",
-		write_queue_head, write_queue_tail, write_queue_cnt,
-		pages, pages << (PAGE_SHIFT-10), clean, dirty, locked,
-		mtd_rawdevice->as.nrpages);
-  if(len <= count)
-    *eof = 1;
-  spin_unlock(&mbd_writeq_lock);
-  MOD_DEC_USE_COUNT;
-  return len;
+	DEBUG(2, "blkmtd: free_device() dev = %p\n", dev);
+	if(dev) {
+		del_mtd_device(&dev->mtd_info);
+		info("mtd%d: [%s] removed", dev->mtd_info.index,
+		     dev->mtd_info.name + strlen("blkmtd: "));
+		if(dev->mtd_info.eraseregions)
+			kfree(dev->mtd_info.eraseregions);
+		if(dev->mtd_info.name)
+			kfree(dev->mtd_info.name);
+
+		if(dev->rd_buf) {
+			dev->rd_buf->locked = 0;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
+			if(dev->rd_buf->blocks)
+				kfree(dev->rd_buf->blocks);
+#endif
+			free_kiovec(1, &dev->rd_buf);
+		}
+		if(dev->wr_buf) {
+			dev->wr_buf->locked = 0;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)			
+			if(dev->wr_buf->blocks)
+				kfree(dev->rw_buf->blocks);
+#endif
+			free_kiovec(1, &dev->wr_buf);
+		}
+
+		if(dev->binding) {
+			kdev_t kdev = to_kdev_t(dev->binding->bd_dev);
+			invalidate_inode_pages(dev->binding->bd_inode);
+			set_blocksize(kdev, 1 << 10);
+			blkdev_put(dev->binding, BDEV_RAW);
+		}
+		kfree(dev);
+	}
 }
+
+
+/* For a given size and initial erase size, calculate the number
+ * and size of each erase region. Goes round the loop twice,
+ * once to find out how many regions, then allocates space,
+ * then round the loop again to fill it in.
+ */
+static struct mtd_erase_region_info *calc_erase_regions(
+	size_t erase_size, size_t total_size, int *regions)
+{
+	struct mtd_erase_region_info *info = NULL;
+
+	DEBUG(2, "calc_erase_regions, es = %d size = %d regions = %d\n",
+	      erase_size, total_size, *regions);
+	/* Make any user specified erasesize be a power of 2
+	   and at least PAGE_SIZE */
+	if(erase_size) {
+		int es = erase_size;
+		erase_size = 1;
+		while(es != 1) {
+			es >>= 1;
+			erase_size <<= 1;
+		}
+		if(erase_size < PAGE_SIZE)
+			erase_size = PAGE_SIZE;
+	} else {
+		erase_size = CONFIG_MTD_BLKDEV_ERASESIZE;
+	}
+
+	*regions = 0;
+
+	do {
+		int tot_size = total_size;
+		int er_size = erase_size;
+		int count = 0, offset = 0, regcnt = 0;
+
+		while(tot_size) {
+			count = tot_size / er_size;
+			if(count) {
+				tot_size = tot_size % er_size;
+				if(info) {
+					DEBUG(2, "adding to erase info off=%d er=%d cnt=%d\n",
+					      offset, er_size, count);
+					(info+regcnt)->offset = offset;
+					(info+regcnt)->erasesize = er_size;
+					(info+regcnt)->numblocks = count;
+					(*regions)++;
+				}
+				regcnt++;
+				offset += (count * er_size);
+			}
+			while(er_size > tot_size)
+				er_size >>= 1;
+		}
+		if(info == NULL) {
+			info = kmalloc(regcnt * sizeof(struct mtd_erase_region_info), GFP_KERNEL);
+			if(!info)
+				break;
+		}
+	} while(!(*regions));
+	DEBUG(2, "calc_erase_regions done, es = %d size = %d regions = %d\n",
+	      erase_size, total_size, *regions);
+	return info;
+}
+
+
+extern kdev_t name_to_kdev_t(char *line) __init;
+
+
+static struct blkmtd_dev *add_device(char *devname, int readonly, int erase_size)
+{
+	int maj, min;
+	kdev_t kdev;
+	int mode;
+	struct blkmtd_dev *dev;
+
+#ifdef MODULE
+	struct file *file = NULL;
+	struct inode *inode;
 #endif
 
+	if(!devname)
+		return NULL;
+
+	/* Get a handle on the device */
+	mode = (readonly) ? O_RDONLY : O_RDWR;
+
+#ifdef MODULE
+
+	file = filp_open(devname, mode, 0);
+	if(IS_ERR(file)) {
+		err("error: cant open device %s", devname);
+		DEBUG(2, "blkmtd: filp_open returned %ld\n", PTR_ERR(file));
+		return NULL;
+	}
+
+	/* determine is this is a block device and
+	 * if so get its major and minor numbers
+	 */
+	inode = file->f_dentry->d_inode;
+	if(!S_ISBLK(inode->i_mode)) {
+		err("%s not a block device", devname);
+		filp_close(file, NULL);
+		return NULL;
+	}
+	kdev = inode->i_rdev;
+	filp_close(file, NULL);
+#else
+	kdev = name_to_kdev_t(devname);
+#endif	/* MODULE */
+
+	if(!kdev) {
+		err("bad block device: `%s'", devname);
+		return NULL;
+	}
+
+	maj = MAJOR(kdev);
+	min = MINOR(kdev);
+	DEBUG(1, "blkmtd: found a block device major = %d, minor = %d\n",
+	      maj, min);
+
+	if(maj == MTD_BLOCK_MAJOR) {
+		err("attempting to use an MTD device as a block device");
+		return NULL;
+	}
+
+	DEBUG(1, "blkmtd: devname = %s\n", bdevname(kdev));
+
+	dev = kmalloc(sizeof(struct blkmtd_dev), GFP_KERNEL);
+	if(dev == NULL)
+		return NULL;
+
+	memset(dev, 0, sizeof(struct blkmtd_dev));
+	if(alloc_kiovec(1, &dev->rd_buf)) {
+		err("cant allocate read iobuf");
+		goto devinit_err;
+	}
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
+	dev->rd_buf->blocks = kmalloc(KIO_MAX_SECTORS * sizeof(unsigned long), GFP_KERNEL);
+	if(dev->rd_buf->blocks == NULL) {
+		crit("cant allocate rd_buf blocks");
+		goto devinit_err;
+	}
+#endif
+	
+	if(!readonly) {
+		if(alloc_kiovec(1, &dev->wr_buf)) {
+			err("cant allocate kiobuf - readonly enabled");
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
+		} else {
+			dev->wr_buf->blocks = kmalloc(KIO_MAX_SECTORS * sizeof(unsigned long), GFP_KERNEL);
+			if(dev->wr_buf->blocks == NULL) {
+				crit("cant allocate wr_buf blocks - readonly enabled");
+				free_kiovec(1, &iobuf);
+			}
+#endif
+		}
+		if(dev->wr_buf)
+			init_MUTEX(&dev->wrbuf_mutex);
+	}
+
+	/* get the block device */
+	dev->binding = bdget(kdev_t_to_nr(MKDEV(maj, min)));
+	if(blkdev_get(dev->binding, mode, 0, BDEV_RAW))
+		goto devinit_err;
+
+	if(set_blocksize(kdev, PAGE_SIZE)) {
+		err("cant set block size to PAGE_SIZE on %s", bdevname(kdev));
+		goto devinit_err;
+	}
+
+	dev->mtd_info.size = dev->binding->bd_inode->i_size & PAGE_MASK;
+
+	/* Setup the MTD structure */
+	/* make the name contain the block device in */
+	dev->mtd_info.name = kmalloc(sizeof("blkmtd: ") + strlen(devname), GFP_KERNEL);
+	if(dev->mtd_info.name == NULL)
+		goto devinit_err;
+
+	sprintf(dev->mtd_info.name, "blkmtd: %s", devname);
+	dev->mtd_info.eraseregions = calc_erase_regions(erase_size, dev->mtd_info.size,
+							&dev->mtd_info.numeraseregions);
+	if(dev->mtd_info.eraseregions == NULL)
+		goto devinit_err;
+
+	dev->mtd_info.erasesize = dev->mtd_info.eraseregions->erasesize;
+	DEBUG(1, "blkmtd: init: found %d erase regions\n",
+	      dev->mtd_info.numeraseregions);
+
+	if(readonly) {
+		dev->mtd_info.type = MTD_ROM;
+		dev->mtd_info.flags = MTD_CAP_ROM;
+	} else {
+		dev->mtd_info.type = MTD_RAM;
+		dev->mtd_info.flags = MTD_CAP_RAM;
+	}
+	dev->mtd_info.erase = blkmtd_erase;
+	dev->mtd_info.read = blkmtd_read;
+	dev->mtd_info.write = blkmtd_write;
+	dev->mtd_info.sync = blkmtd_sync;
+	dev->mtd_info.point = 0;
+	dev->mtd_info.unpoint = 0;
+	dev->mtd_info.priv = dev;
+	dev->mtd_info.module = THIS_MODULE;
+
+	list_add(&dev->list, &blkmtd_device_list);
+	if (add_mtd_device(&dev->mtd_info)) {
+		/* Device didnt get added, so free the entry */
+		list_del(&dev->list);
+		free_device(dev);
+		return NULL;
+	} else {
+		info("mtd%d: [%s] erase_size = %dKiB %s",
+		     dev->mtd_info.index, dev->mtd_info.name + strlen("blkmtd: "),
+		     dev->mtd_info.erasesize >> 10,
+		     (dev->wr_buf) ? "" : "(read-only)");
+	}
+	
+	return dev;
+
+ devinit_err:
+	free_device(dev);
+	return NULL;
+}
+
 
 /* Cleanup and exit - sync the device and kill of the kernel thread */
-static void __exit cleanup_blkmtd(void)
+static void __devexit cleanup_blkmtd(void)
 {
+	struct list_head *temp1, *temp2;
 #ifdef BLKMTD_PROC_DEBUG
-  if(blkmtd_proc) {
-    remove_proc_entry("blkmtd_debug", NULL);
-  }
+	if(blkmtd_proc) {
+		remove_proc_entry("blkmtd_debug", NULL);
+	}
 #endif
 
-  if (mtd_rawdevice) {
-    /* sync the device */
-    if (!mtd_rawdevice->readonly) {
-      blkmtd_sync(&mtd_rawdevice->mtd_info);
-      write_task_finish = 1;
-      wake_up_interruptible(&thr_wq);
-      down(&thread_sem);
-    }
-    del_mtd_device(&mtd_rawdevice->mtd_info);
-    if(mtd_rawdevice->binding != NULL)
-      blkdev_put(mtd_rawdevice->binding, BDEV_RAW);
-
-    if(mtd_rawdevice->mtd_info.eraseregions)
-      kfree(mtd_rawdevice->mtd_info.eraseregions);
-    if(mtd_rawdevice->mtd_info.name)
-      kfree(mtd_rawdevice->mtd_info.name);
-
-    kfree(mtd_rawdevice);
-  }
-  if(write_queue)
-    kfree(write_queue);
-
-  if(erase_page) {
-    UnlockPage(erase_page);
-    __free_pages(erase_page, 0);
-  }
-  printk("blkmtd: unloaded for %s\n", device);
+	/* Remove the MTD devices */
+	list_for_each_safe(temp1, temp2, &blkmtd_device_list) {
+		struct blkmtd_dev *dev = list_entry(temp1, struct blkmtd_dev,
+						    list);
+		blkmtd_sync(&dev->mtd_info);
+		free_device(dev);
+	}
 }
 
-extern struct module __this_module;
-
 #ifndef MODULE
 
 /* Handle kernel boot params */
@@ -982,335 +961,97 @@
 
 static int __init param_blkmtd_device(char *str)
 {
-  device = str;
-  return 1;
+	int i;
+
+	for(i = 0; i < MAX_DEVICES; i++) {
+		device[i] = str;
+		DEBUG(2, "blkmtd: device setup: %d = %s\n", i, device[i]);
+		strsep(&str, ",");
+	}
+	return 1;
 }
 
 
 static int __init param_blkmtd_erasesz(char *str)
 {
-  erasesz = simple_strtol(str, NULL, 0);
-  return 1;
+	int i;
+	for(i = 0; i < MAX_DEVICES; i++) {
+		char *val = strsep(&str, ",");
+		if(val)
+			erasesz[i] = simple_strtoul(val, NULL, 0);
+		DEBUG(2, "blkmtd: erasesz setup: %d = %d\n", i, erasesz[i]);
+	}
+
+	return 1;
 }
 
 
 static int __init param_blkmtd_ro(char *str)
 {
-  ro = simple_strtol(str, NULL, 0);
-  return 1;
-}
-
+	int i;
+	for(i = 0; i < MAX_DEVICES; i++) {
+		char *val = strsep(&str, ",");
+		if(val)
+			ro[i] = simple_strtoul(val, NULL, 0);
+		DEBUG(2, "blkmtd: ro setup: %d = %d\n", i, ro[i]);
+	}
 
-static int __init param_blkmtd_bs(char *str)
-{
-  bs = simple_strtol(str, NULL, 0);
-  return 1;
+	return 1;
 }
 
 
-static int __init param_blkmtd_count(char *str)
+static int __init param_blkmtd_sync(char *str)
 {
-  count = simple_strtol(str, NULL, 0);
-  return 1;
+	if(str[0] == '1')
+		sync = 1;
+	return 1;
 }
 
 __setup("blkmtd_device=", param_blkmtd_device);
 __setup("blkmtd_erasesz=", param_blkmtd_erasesz);
 __setup("blkmtd_ro=", param_blkmtd_ro);
-__setup("blkmtd_bs=", param_blkmtd_bs);
-__setup("blkmtd_count=", param_blkmtd_count);
+__setup("blkmtd_sync=", param_blkmtd_sync);
 
 #endif
 
 
-/* for a given size and initial erase size, calculate the number and size of each
-   erase region */
-static int __init calc_erase_regions(struct mtd_erase_region_info *info, size_t erase_size, size_t total_size)
-{
-  int count = 0;
-  int offset = 0;
-  int regions = 0;
-
-   while(total_size) {
-     count = total_size / erase_size;
-     if(count) {
-       total_size = total_size % erase_size;
-       if(info) {
-	 info->offset = offset;
-	 info->erasesize = erase_size;
-	 info->numblocks = count;
-	 info++;
-       }
-       offset += (count * erase_size);
-       regions++;
-     }
-     while(erase_size > total_size)
-       erase_size >>= 1;
-   }
-   return regions;
-}
-
-
-extern kdev_t name_to_kdev_t(char *line) __init;
-
 /* Startup */
 static int __init init_blkmtd(void)
 {
-#ifdef MODULE
-  struct file *file = NULL;
-  struct inode *inode;
-#endif
+	int i;
 
-  int maj, min;
-  int i, blocksize, blocksize_bits;
-  loff_t size = 0;
-  int readonly = 0;
-  int erase_size = CONFIG_MTD_BLKDEV_ERASESIZE;
-  kdev_t rdev;
-  int err;
-  int mode;
-  int regions;
-
-  /* Check args */
-  if(device == 0) {
-    printk("blkmtd: error, missing `device' name\n");
-    return -EINVAL;
-  }
-
-  if(ro)
-    readonly = 1;
-
-  if(erasesz)
-    erase_size = erasesz;
-
-  if(wqs) {
-    if(wqs < 16) 
-      wqs = 16;
-    if(wqs > 4*WRITE_QUEUE_SZ)
-      wqs = 4*WRITE_QUEUE_SZ;
-    write_queue_sz = wqs;
-  }
-
-  DEBUG(1, "blkmtd: device = `%s' erase size = %dK readonly = %s queue size = %d\n",
-	device, erase_size, readonly ? "yes" : "no", write_queue_sz);
-  /* Get a handle on the device */
-  mode = (readonly) ? O_RDONLY : O_RDWR;
-
-#ifdef MODULE
+	/* Check args - device[0] is the bare minimum*/
+	if(!device[0]) {
+		err("error: missing `device' name\n");
+		return -EINVAL;
+	}
 
-  file = filp_open(device, mode, 0);
-  if(IS_ERR(file)) {
-    printk("blkmtd: error, cant open device %s\n", device);
-    DEBUG(2, "blkmtd: filp_open returned %ld\n", PTR_ERR(file));
-    return 1;
-  }
-  
-  /* determine is this is a block device and if so get its major and minor
-     numbers */
-  inode = file->f_dentry->d_inode;
-  if(!S_ISBLK(inode->i_mode)) {
-    printk("blkmtd: %s not a block device\n", device);
-    filp_close(file, NULL);
-    return 1;
-  }
-  rdev = inode->i_rdev;
-  filp_close(file, NULL);
-#else
-  rdev = name_to_kdev_t(device);
-#endif
+	for(i = 0; i < MAX_DEVICES; i++)
+		add_device(device[i], ro[i], erasesz[i] << 10);
 
-  maj = MAJOR(rdev);
-  min = MINOR(rdev);
-  DEBUG(1, "blkmtd: found a block device major = %d, minor = %d\n", maj, min);
-
-  if(!rdev) {
-    printk("blkmtd: bad block device: `%s'\n", device);
-    return 1;
-  }
-
-  if(maj == MTD_BLOCK_MAJOR) {
-    printk("blkmtd: attempting to use an MTD device as a block device\n");
-    return 1;
-  }
-
-  DEBUG(1, "blkmtd: devname = %s\n", bdevname(rdev));
-  blocksize = BLOCK_SIZE;
-
-  if(bs) {
-    blocksize = bs;
-  } else {
-    if (blksize_size[maj] && blksize_size[maj][min]) {
-      DEBUG(2, "blkmtd: blksize_size = %d\n", blksize_size[maj][min]);
-      blocksize = blksize_size[maj][min];
-    }
-  }
-  i = blocksize;
-  blocksize_bits = 0;
-  while(i != 1) {
-    blocksize_bits++;
-    i >>= 1;
-  }
-
-  if(count) {
-    size = count;
-  } else {
-    if (blk_size[maj]) {
-      size = ((loff_t) blk_size[maj][min] << BLOCK_SIZE_BITS) >> blocksize_bits;
-    }
-  }
-  size *= blocksize;
-  DEBUG(1, "blkmtd: size = %ld\n", (long int)size);
-
-  if(size == 0) {
-    printk("blkmtd: cant determine size\n");
-    return 1;
-  }
-
-  mtd_rawdevice = (mtd_raw_dev_data_t *)kmalloc(sizeof(mtd_raw_dev_data_t), GFP_KERNEL);
-  if(mtd_rawdevice == NULL) {
-    err = -ENOMEM;
-    goto init_err;
-  }
-  memset(mtd_rawdevice, 0, sizeof(mtd_raw_dev_data_t));
-  /* get the block device */
-  mtd_rawdevice->binding = bdget(kdev_t_to_nr(MKDEV(maj, min)));
-  err = blkdev_get(mtd_rawdevice->binding, mode, 0, BDEV_RAW);
-  if (err) {
-    goto init_err;
-  }
-  mtd_rawdevice->totalsize = size;
-  mtd_rawdevice->sector_size = blocksize;
-  mtd_rawdevice->sector_bits = blocksize_bits;
-  mtd_rawdevice->readonly = readonly;
-
-  /* See if device ends on page boundary */
-  if(size % PAGE_SIZE) {
-    mtd_rawdevice->partial_last_page = size >> PAGE_SHIFT;
-    mtd_rawdevice->last_page_sectors = (size & (PAGE_SIZE-1)) >> blocksize_bits;
-  }
-
-  DEBUG(2, "sector_size = %d, sector_bits = %d, partial_last_page = %d last_page_sectors = %d\n", 
-	mtd_rawdevice->sector_size, mtd_rawdevice->sector_bits,
-	mtd_rawdevice->partial_last_page, mtd_rawdevice->last_page_sectors);
-
-  /* Setup the MTD structure */
-  /* make the name contain the block device in */
-  mtd_rawdevice->mtd_info.name = kmalloc(9 + strlen(device), GFP_KERNEL);
-  if(mtd_rawdevice->mtd_info.name == NULL)
-    goto init_err;
-
-  sprintf(mtd_rawdevice->mtd_info.name, "blkmtd: %s", device);
-  if(readonly) {
-    mtd_rawdevice->mtd_info.type = MTD_ROM;
-    mtd_rawdevice->mtd_info.flags = MTD_CAP_ROM;
-    mtd_rawdevice->mtd_info.erasesize = erase_size << 10;
-  } else {
-    mtd_rawdevice->mtd_info.type = MTD_RAM;
-    mtd_rawdevice->mtd_info.flags = MTD_CAP_RAM;
-    mtd_rawdevice->mtd_info.erasesize = erase_size << 10;
-  }
-  mtd_rawdevice->mtd_info.size = size;
-  mtd_rawdevice->mtd_info.erase = blkmtd_erase;
-  mtd_rawdevice->mtd_info.read = blkmtd_read;
-  mtd_rawdevice->mtd_info.write = blkmtd_write;
-  mtd_rawdevice->mtd_info.sync = blkmtd_sync;
-  mtd_rawdevice->mtd_info.point = 0;
-  mtd_rawdevice->mtd_info.unpoint = 0;
-
-  mtd_rawdevice->mtd_info.priv = mtd_rawdevice;
-  regions = calc_erase_regions(NULL, erase_size << 10, size);
-  DEBUG(1, "blkmtd: init: found %d erase regions\n", regions);
-  mtd_rawdevice->mtd_info.eraseregions = kmalloc(regions * sizeof(struct mtd_erase_region_info), GFP_KERNEL);
-  if(mtd_rawdevice->mtd_info.eraseregions == NULL) {
-    err = -ENOMEM;
-    goto init_err;
-  }
-  mtd_rawdevice->mtd_info.numeraseregions = regions;
-  calc_erase_regions(mtd_rawdevice->mtd_info.eraseregions, erase_size << 10, size);
-
-  /* setup the page cache info */
-  
-  mtd_rawdevice->as.nrpages = 0;
-  INIT_LIST_HEAD(&mtd_rawdevice->as.clean_pages);
-  INIT_LIST_HEAD(&mtd_rawdevice->as.dirty_pages);
-  INIT_LIST_HEAD(&mtd_rawdevice->as.locked_pages);
-  mtd_rawdevice->as.host = NULL;
-  spin_lock_init(&(mtd_rawdevice->as.i_shared_lock));
-
-  mtd_rawdevice->as.a_ops = &blkmtd_aops;
-  mtd_rawdevice->as.i_mmap = NULL;
-  mtd_rawdevice->as.i_mmap_shared = NULL;
-  mtd_rawdevice->as.gfp_mask = GFP_KERNEL;
+	if(list_empty(&blkmtd_device_list))
+		goto init_err;
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-  mtd_rawdevice->mtd_info.module = THIS_MODULE;			
-#endif
-  if (add_mtd_device(&mtd_rawdevice->mtd_info)) {
-    err = -EIO;
-    goto init_err;
-  }
-
-  if(!mtd_rawdevice->readonly) {
-    /* Allocate the write queue */
-    write_queue = kmalloc(write_queue_sz * sizeof(mtdblkdev_write_queue_t), GFP_KERNEL);
-    if(!write_queue) {
-      err = -ENOMEM;
-      goto init_err;
-    }
-    /* Set up the erase page */
-    erase_page = alloc_pages(GFP_KERNEL, 0);
-    if(erase_page == NULL) {
-      err = -ENOMEM;
-      goto init_err;
-    }
-    memset(page_address(erase_page), 0xff, PAGE_SIZE);
-    lock_page(erase_page);
-
-    init_waitqueue_head(&thr_wq);
-    init_waitqueue_head(&mtbd_sync_wq);
-    DEBUG(3, "blkmtd: init: kernel task @ %p\n", write_queue_task);
-    DEBUG(2, "blkmtd: init: starting kernel task\n");
-    kernel_thread(write_queue_task, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
-    DEBUG(2, "blkmtd: init: started\n");
-    printk("blkmtd loaded: version = %s using %s erase_size = %dK %s\n",
-	   VERSION, device, erase_size, (readonly) ? "(read-only)" : "");
-  }
+	info("version " VERSION);
 
 #ifdef BLKMTD_PROC_DEBUG
-  /* create proc entry */
-  DEBUG(2, "Creating /proc/blkmtd_debug\n");
-  blkmtd_proc = create_proc_read_entry("blkmtd_debug", 0444,
-				       NULL, blkmtd_proc_read, NULL);
-  if(blkmtd_proc == NULL) {
-    printk("Cant create /proc/blkmtd_debug\n");
-  } else {
-    blkmtd_proc->owner = THIS_MODULE;
-  }
+	/* create proc entry */
+	DEBUG(2, "Creating /proc/blkmtd_debug\n");
+	blkmtd_proc = create_proc_read_entry("blkmtd_debug", 0444,
+					     NULL, blkmtd_proc_read, NULL);
+	if(blkmtd_proc == NULL) {
+		err("Cant create /proc/blkmtd_debug");
+	} else {
+		blkmtd_proc->owner = THIS_MODULE;
+	}
 #endif
-  
-  /* Everything is ok if we got here */
-  return 0;
-  
- init_err:
 
-  if(mtd_rawdevice) {
-    if(mtd_rawdevice->mtd_info.eraseregions)
-      kfree(mtd_rawdevice->mtd_info.eraseregions);
-    if(mtd_rawdevice->mtd_info.name)
-      kfree(mtd_rawdevice->mtd_info.name);
-    if(mtd_rawdevice->binding) 
-      blkdev_put(mtd_rawdevice->binding, BDEV_RAW);
-    kfree(mtd_rawdevice);
-  }
-
-  if(write_queue) {
-    kfree(write_queue);
-    write_queue = NULL;
-  }
-
-  if(erase_page) 
-    __free_pages(erase_page, 0);
-  return err;
+	if(!list_empty(&blkmtd_device_list))
+		/* Everything is ok if we got here */
+		return 0;
+
+ init_err:
+	return -EINVAL;
 }
 
 module_init(init_blkmtd);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/devices/doc1000.c linux-2.4.21-pre6/drivers/mtd/devices/doc1000.c
--- linux-2.4.20/drivers/mtd/devices/doc1000.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/devices/doc1000.c	2003-03-26 23:49:07.000000000 +0000
@@ -1,6 +1,6 @@
 /*======================================================================
 
-  $Id: doc1000.c,v 1.16 2001/12/28 22:45:17 dwmw2 Exp $
+  $Id: doc1000.c,v 1.17 2003/01/24 13:33:20 dwmw2 Exp $
 
 ======================================================================*/
 
@@ -20,8 +20,6 @@
 #include <linux/ioctl.h>
 #include <asm/io.h>
 #include <asm/system.h>
-#include <asm/segment.h>
-#include <stdarg.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/devices/doc2000.c linux-2.4.21-pre6/drivers/mtd/devices/doc2000.c
--- linux-2.4.20/drivers/mtd/devices/doc2000.c	2001-10-04 22:14:59.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/devices/doc2000.c	2003-03-26 23:48:57.000000000 +0000
@@ -4,7 +4,7 @@
  * (c) 1999 Machine Vision Holdings, Inc.
  * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
  *
- * $Id: doc2000.c,v 1.46 2001/10/02 15:05:13 dwmw2 Exp $
+ * $Id: doc2000.c,v 1.50 2002/12/10 15:05:42 gleixner Exp $
  */
 
 #include <linux/kernel.h>
@@ -22,7 +22,6 @@
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
-#include <linux/mtd/nand_ids.h>
 #include <linux/mtd/doc2000.h>
 
 #define DOC_SUPPORT_2000
@@ -54,9 +53,9 @@
 static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
 		     size_t *retlen, const u_char *buf);
 static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
-			size_t *retlen, u_char *buf, u_char *eccbuf);
+			size_t *retlen, u_char *buf, u_char *eccbuf, int oobsel);
 static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
-			 size_t *retlen, const u_char *buf, u_char *eccbuf);
+			 size_t *retlen, const u_char *buf, u_char *eccbuf, int oobsel);
 static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
 			size_t *retlen, u_char *buf);
 static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
@@ -97,12 +96,8 @@
 			DEBUG(MTD_DEBUG_LEVEL2, "_DoC_WaitReady timed out.\n");
 			return -EIO;
 		}
-		if (current->need_resched) {
-			set_current_state(TASK_UNINTERRUPTIBLE);
-			schedule_timeout(1);
-		}
-		else
-			udelay(1);
+		udelay(1);
+		cond_resched();
 	}
 
 	return 0;
@@ -320,7 +315,7 @@
 
 static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)
 {
-	int mfr, id, i;
+	int mfr, id, i, j;
 	volatile char dummy;
 
 	/* Page in the required floor/chip */
@@ -378,12 +373,16 @@
 
 	/* Print and store the manufacturer and ID codes. */
 	for (i = 0; nand_flash_ids[i].name != NULL; i++) {
-		if (mfr == nand_flash_ids[i].manufacture_id &&
-		    id == nand_flash_ids[i].model_id) {
+		if (id == nand_flash_ids[i].id) {
+			/* Try to identify manufacturer */
+			for (j = 0; nand_manuf_ids[j].id != 0x0; j++) {
+				if (nand_manuf_ids[j].id == mfr)
+					break;
+			}	
 			printk(KERN_INFO
 			       "Flash chip found: Manufacturer ID: %2.2X, "
-			       "Chip ID: %2.2X (%s)\n", mfr, id,
-			       nand_flash_ids[i].name);
+			       "Chip ID: %2.2X (%s:%s)\n", mfr, id,
+			       nand_manuf_ids[j].name, nand_flash_ids[i].name);
 			if (!doc->mfr) {
 				doc->mfr = mfr;
 				doc->id = id;
@@ -391,7 +390,7 @@
 				    nand_flash_ids[i].chipshift;
 				doc->page256 = nand_flash_ids[i].page256;
 				doc->pageadrlen =
-				    nand_flash_ids[i].pageadrlen;
+				    nand_flash_ids[i].chipshift > 25 ? 3 : 2;
 				doc->erasesize =
 				    nand_flash_ids[i].erasesize;
 				return 1;
@@ -597,11 +596,11 @@
 		    size_t * retlen, u_char * buf)
 {
 	/* Just a special case of doc_read_ecc */
-	return doc_read_ecc(mtd, from, len, retlen, buf, NULL);
+	return doc_read_ecc(mtd, from, len, retlen, buf, NULL, 0);
 }
 
 static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
-			size_t * retlen, u_char * buf, u_char * eccbuf)
+			size_t * retlen, u_char * buf, u_char * eccbuf, int oobsel)
 {
 	struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
 	unsigned long docptr;
@@ -745,12 +744,12 @@
 		     size_t * retlen, const u_char * buf)
 {
 	char eccbuf[6];
-	return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf);
+	return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, 0);
 }
 
 static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
 			 size_t * retlen, const u_char * buf,
-			 u_char * eccbuf)
+			 u_char * eccbuf, int oobsel)
 {
 	struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
 	int di; /* Yes, DI is a hangover from when I was disassembling the binary driver */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/devices/doc2001.c linux-2.4.21-pre6/drivers/mtd/devices/doc2001.c
--- linux-2.4.20/drivers/mtd/devices/doc2001.c	2001-10-04 22:14:59.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/devices/doc2001.c	2003-03-26 23:49:21.000000000 +0000
@@ -4,7 +4,7 @@
  * (c) 1999 Machine Vision Holdings, Inc.
  * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
  *
- * $Id: doc2001.c,v 1.35 2001/10/02 15:05:13 dwmw2 Exp $
+ * $Id: doc2001.c,v 1.38 2002/12/10 15:05:42 gleixner Exp $
  */
 
 #include <linux/kernel.h>
@@ -22,7 +22,6 @@
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
-#include <linux/mtd/nand_ids.h>
 #include <linux/mtd/doc2000.h>
 
 /* #define ECC_DEBUG */
@@ -38,9 +37,9 @@
 static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
 		     size_t *retlen, const u_char *buf);
 static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
-			size_t *retlen, u_char *buf, u_char *eccbuf);
+			size_t *retlen, u_char *buf, u_char *eccbuf, int oobsel);
 static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
-			 size_t *retlen, const u_char *buf, u_char *eccbuf);
+			 size_t *retlen, const u_char *buf, u_char *eccbuf, int oobsel);
 static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
 			size_t *retlen, u_char *buf);
 static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
@@ -182,7 +181,7 @@
 /* DoC_IdentChip: Identify a given NAND chip given {floor,chip} */
 static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)
 {
-	int mfr, id, i;
+	int mfr, id, i, j;
 	volatile char dummy;
 
 	/* Page in the required floor/chip
@@ -216,11 +215,15 @@
 
 	/* FIXME: to deal with multi-flash on multi-Millennium case more carefully */
 	for (i = 0; nand_flash_ids[i].name != NULL; i++) {
-		if (mfr == nand_flash_ids[i].manufacture_id &&
-		    id == nand_flash_ids[i].model_id) {
+		if ( id == nand_flash_ids[i].id) {
+			/* Try to identify manufacturer */
+			for (j = 0; nand_manuf_ids[j].id != 0x0; j++) {
+				if (nand_manuf_ids[j].id == mfr)
+					break;
+			}	
 			printk(KERN_INFO "Flash chip found: Manufacturer ID: %2.2X, "
-			       "Chip ID: %2.2X (%s)\n",
-			       mfr, id, nand_flash_ids[i].name);
+			       "Chip ID: %2.2X (%s:%s)\n",
+			       mfr, id, nand_manuf_ids[j].name, nand_flash_ids[i].name);
 			doc->mfr = mfr;
 			doc->id = id;
 			doc->chipshift = nand_flash_ids[i].chipshift;
@@ -399,11 +402,11 @@
 		     size_t *retlen, u_char *buf)
 {
 	/* Just a special case of doc_read_ecc */
-	return doc_read_ecc(mtd, from, len, retlen, buf, NULL);
+	return doc_read_ecc(mtd, from, len, retlen, buf, NULL, 0);
 }
 
 static int doc_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
-			 size_t *retlen, u_char *buf, u_char *eccbuf)
+			 size_t *retlen, u_char *buf, u_char *eccbuf, int oobsel)
 {
 	int i, ret;
 	volatile char dummy;
@@ -525,11 +528,11 @@
 		      size_t *retlen, const u_char *buf)
 {
 	char eccbuf[6];
-	return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf);
+	return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, 0);
 }
 
 static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
-			  size_t *retlen, const u_char *buf, u_char *eccbuf)
+			  size_t *retlen, const u_char *buf, u_char *eccbuf, int oobsel)
 {
 	int i,ret = 0;
 	volatile char dummy;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/devices/docprobe.c linux-2.4.21-pre6/drivers/mtd/devices/docprobe.c
--- linux-2.4.20/drivers/mtd/devices/docprobe.c	2001-10-04 22:14:59.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/devices/docprobe.c	2003-03-26 23:49:08.000000000 +0000
@@ -1,9 +1,10 @@
 
 /* Linux driver for Disk-On-Chip devices			*/
 /* Probe routines common to all DoC devices			*/
-/* (c) 1999 Machine Vision Holdings, Inc.			*/
-/* Author: David Woodhouse <dwmw2@infradead.org>		*/
-/* $Id: docprobe.c,v 1.30 2001/10/02 15:05:13 dwmw2 Exp $	*/
+/* (C) 1999 Machine Vision Holdings, Inc.			*/
+/* (C) 1999-2003 David Woodhouse <dwmw2@infradead.org>		*/
+
+/* $Id: docprobe.c,v 1.33 2003/01/24 14:02:47 dwmw2 Exp $	*/
 
 
 
@@ -67,7 +68,7 @@
 
 static unsigned long doc_config_location = CONFIG_MTD_DOCPROBE_ADDRESS;
 MODULE_PARM(doc_config_location, "l");
-
+MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip");
 
 static unsigned long __initdata doc_locations[] = {
 #if defined (__alpha__) || defined(__i386__) || defined(__x86_64__)
@@ -84,11 +85,14 @@
 	0xe0000, 0xe2000, 0xe4000, 0xe6000, 
 	0xe8000, 0xea000, 0xec000, 0xee000,
 #endif /*  CONFIG_MTD_DOCPROBE_HIGH */
-#elif defined(__ppc__)
+#elif defined(__PPC__)
 	0xe4000000,
 #elif defined(CONFIG_MOMENCO_OCELOT)
 	0x2f000000,
-#else
+        0xff000000,
+#elif defined(CONFIG_MOMENCO_OCELOT_G) || defined (CONFIG_MOMENCO_OCELOT_C)
+        0xff000000,
+##else
 #warning Unknown architecture for DiskOnChip. No default probe locations defined
 #endif
 	0 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/devices/ms02-nv.c linux-2.4.21-pre6/drivers/mtd/devices/ms02-nv.c
--- linux-2.4.20/drivers/mtd/devices/ms02-nv.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/devices/ms02-nv.c	2003-03-26 23:49:09.000000000 +0000
@@ -5,6 +5,8 @@
  *      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.
+ *
+ *	$Id: ms02-nv.c,v 1.2 2003/01/24 14:05:17 dwmw2 Exp $
  */
 
 #include <linux/init.h>
@@ -296,6 +298,7 @@
 			stride = 2;
 		break;
 	case MACH_DS5000_2X0:
+	case MACH_DS5000:
 		csr = (volatile u32 *)KN03_MCR_BASE;
 		if (*csr & KN03_MCR_BNK32M)
 			stride = 2;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/devices/mtdram.c linux-2.4.21-pre6/drivers/mtd/devices/mtdram.c
--- linux-2.4.20/drivers/mtd/devices/mtdram.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/devices/mtdram.c	2003-03-26 23:48:59.000000000 +0000
@@ -1,6 +1,6 @@
 /*
  * mtdram - a test mtd device
- * $Id: mtdram.c,v 1.26 2001/12/01 10:24:18 dwmw2 Exp $
+ * $Id: mtdram.c,v 1.29 2002/10/21 13:40:06 jocke Exp $
  * Author: Alexander Larsson <alex@cendio.se>
  *
  * Copyright (c) 1999 Alexander Larsson <alex@cendio.se>
@@ -28,7 +28,9 @@
 static unsigned long total_size = CONFIG_MTDRAM_TOTAL_SIZE;
 static unsigned long erase_size = CONFIG_MTDRAM_ERASE_SIZE;
 MODULE_PARM(total_size,"l");
+MODULE_PARM_DESC(total_size, "Total device size in KiB");
 MODULE_PARM(erase_size,"l");
+MODULE_PARM_DESC(erase_size, "Device erase block size in KiB");
 #define MTDRAM_TOTAL_SIZE (total_size * 1024)
 #define MTDRAM_ERASE_SIZE (erase_size * 1024)
 #else
@@ -69,7 +71,8 @@
   return 0;
 }
 
-static void ram_unpoint (struct mtd_info *mtd, u_char *addr)
+static void ram_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from,
+			 size_t len)
 {
   DEBUG(MTD_DEBUG_LEVEL2, "ram_unpoint\n");
 }
@@ -108,65 +111,119 @@
 {
   if (mtd_info) {
     del_mtd_device(mtd_info);
+#if CONFIG_MTDRAM_TOTAL_SIZE > 0
     if (mtd_info->priv)
 #if CONFIG_MTDRAM_ABS_POS > 0
       iounmap(mtd_info->priv);
 #else
       vfree(mtd_info->priv);
 #endif	
+#endif
     kfree(mtd_info);
   }
 }
 
+int mtdram_init_device(struct mtd_info *mtd, void *mapped_address, 
+                       unsigned long size, char *name)
+{
+   memset(mtd, 0, sizeof(*mtd));
+
+   /* Setup the MTD structure */
+   mtd->name = name;
+   mtd->type = MTD_RAM;
+   mtd->flags = MTD_CAP_RAM;
+   mtd->size = size;
+   mtd->erasesize = MTDRAM_ERASE_SIZE;
+   mtd->priv = mapped_address;
+
+   mtd->module = THIS_MODULE;
+   mtd->erase = ram_erase;
+   mtd->point = ram_point;
+   mtd->unpoint = ram_unpoint;
+   mtd->read = ram_read;
+   mtd->write = ram_write;
+
+   if (add_mtd_device(mtd)) {
+     return -EIO;
+   }
+   
+   return 0;
+}
+
+#if CONFIG_MTDRAM_TOTAL_SIZE > 0
+#if CONFIG_MTDRAM_ABS_POS > 0
 int __init init_mtdram(void)
 {
-   // Allocate some memory
+  void *addr;
+  int err;
+  /* Allocate some memory */
    mtd_info = (struct mtd_info *)kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
    if (!mtd_info)
-      return -ENOMEM;
+     return -ENOMEM;
    
-   memset(mtd_info, 0, sizeof(*mtd_info));
+  addr = ioremap(CONFIG_MTDRAM_ABS_POS, MTDRAM_TOTAL_SIZE);
+  if (!addr) {
+    DEBUG(MTD_DEBUG_LEVEL1, 
+          "Failed to ioremap) memory region of size %ld at ABS_POS:%ld\n", 
+          (long)MTDRAM_TOTAL_SIZE, (long)CONFIG_MTDRAM_ABS_POS);
+    kfree(mtd_info);
+    mtd_info = NULL;
+    return -ENOMEM;
+  }
+  err = mtdram_init_device(mtd_info, addr, 
+                           MTDRAM_TOTAL_SIZE, "mtdram test device");
+  if (err) 
+  {
+    iounmap(addr);
+    kfree(mtd_info);
+    mtd_info = NULL;
+    return err;
+  }
+  memset(mtd_info->priv, 0xff, MTDRAM_TOTAL_SIZE);
+  return err;
+}
 
-   // Setup the MTD structure
-   mtd_info->name = "mtdram test device";
-   mtd_info->type = MTD_RAM;
-   mtd_info->flags = MTD_CAP_RAM;
-   mtd_info->size = MTDRAM_TOTAL_SIZE;
-   mtd_info->erasesize = MTDRAM_ERASE_SIZE;
-#if CONFIG_MTDRAM_ABS_POS > 0
-   mtd_info->priv = ioremap(CONFIG_MTDRAM_ABS_POS, MTDRAM_TOTAL_SIZE);
-#else
-   mtd_info->priv = vmalloc(MTDRAM_TOTAL_SIZE);
-#endif
+#else /* CONFIG_MTDRAM_ABS_POS > 0 */
 
-   if (!mtd_info->priv) {
-     DEBUG(MTD_DEBUG_LEVEL1, "Failed to vmalloc(/ioremap) memory region of size %ld (ABS_POS:%ld)\n", (long)MTDRAM_TOTAL_SIZE, (long)CONFIG_MTDRAM_ABS_POS);
-     kfree(mtd_info);
-     mtd_info = NULL;
+int __init init_mtdram(void)
+{
+  void *addr;
+  int err;
+  /* Allocate some memory */
+   mtd_info = (struct mtd_info *)kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
+   if (!mtd_info)
      return -ENOMEM;
-   }
-   memset(mtd_info->priv, 0xff, MTDRAM_TOTAL_SIZE);
 
-   mtd_info->module = THIS_MODULE;			
-   mtd_info->erase = ram_erase;
-   mtd_info->point = ram_point;
-   mtd_info->unpoint = ram_unpoint;
-   mtd_info->read = ram_read;
-   mtd_info->write = ram_write;
+  addr = vmalloc(MTDRAM_TOTAL_SIZE);
+  if (!addr) {
+    DEBUG(MTD_DEBUG_LEVEL1, 
+          "Failed to vmalloc memory region of size %ld\n", 
+          (long)MTDRAM_TOTAL_SIZE);
+    kfree(mtd_info);
+    mtd_info = NULL;
+    return -ENOMEM;
+  }
+  err = mtdram_init_device(mtd_info, addr, 
+                           MTDRAM_TOTAL_SIZE, "mtdram test device");
+  if (err) 
+  {
+    vfree(addr);
+    kfree(mtd_info);
+    mtd_info = NULL;
+    return err;
+  }
+  memset(mtd_info->priv, 0xff, MTDRAM_TOTAL_SIZE);
+  return err;
+}
+#endif /* !(CONFIG_MTDRAM_ABS_POS > 0) */
 
-   if (add_mtd_device(mtd_info)) {
-#if CONFIG_MTDRAM_ABS_POS > 0
-     iounmap(mtd_info->priv);
-#else
-     vfree(mtd_info->priv);
-#endif	
-     kfree(mtd_info);
-     mtd_info = NULL;
-     return -EIO;
-   }
-   
-   return 0;
+#else /* CONFIG_MTDRAM_TOTAL_SIZE > 0 */
+
+int __init init_mtdram(void)
+{
+  return 0;
 }
+#endif /* !(CONFIG_MTDRAM_TOTAL_SIZE > 0) */
 
 module_init(init_mtdram);
 module_exit(cleanup_mtdram);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/devices/pmc551.c linux-2.4.21-pre6/drivers/mtd/devices/pmc551.c
--- linux-2.4.20/drivers/mtd/devices/pmc551.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/devices/pmc551.c	2003-03-26 23:49:19.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * $Id: pmc551.c,v 1.20 2002/03/05 13:47:08 dwmw2 Exp $
+ * $Id: pmc551.c,v 1.22 2003/01/24 13:34:30 dwmw2 Exp $
  *
  * PMC551 PCI Mezzanine Ram Device
  *
@@ -98,8 +98,6 @@
 #include <linux/ioctl.h>
 #include <asm/io.h>
 #include <asm/system.h>
-#include <asm/segment.h>
-#include <stdarg.h>
 #include <linux/pci.h>
 
 #ifndef CONFIG_PCI
@@ -216,7 +214,7 @@
 }
 
 
-static void pmc551_unpoint (struct mtd_info *mtd, u_char *addr)
+static void pmc551_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
 {
 #ifdef CONFIG_MTD_PMC551_DEBUG
 	printk(KERN_DEBUG "pmc551_unpoint()\n");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/devices/slram.c linux-2.4.21-pre6/drivers/mtd/devices/slram.c
--- linux-2.4.20/drivers/mtd/devices/slram.c	2001-10-04 22:14:59.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/devices/slram.c	2003-03-26 23:48:57.000000000 +0000
@@ -1,6 +1,32 @@
 /*======================================================================
 
-  $Id: slram.c,v 1.25 2001/10/02 15:05:13 dwmw2 Exp $
+  $Id: slram.c,v 1.28 2003/01/24 13:35:34 dwmw2 Exp $
+
+  This driver provides a method to access memory not used by the kernel
+  itself (i.e. if the kernel commandline mem=xxx is used). To actually
+  use slram at least mtdblock or mtdchar is required (for block or
+  character device access).
+
+  Usage:
+
+  if compiled as loadable module:
+    modprobe slram map=<name>,<start>,<end/offset>
+  if statically linked into the kernel use the following kernel cmd.line
+    slram=<name>,<start>,<end/offset>
+
+  <name>: name of the device that will be listed in /proc/mtd
+  <start>: start of the memory region, decimal or hex (0xabcdef)
+  <end/offset>: end of the memory region. It's possible to use +0x1234
+                to specify the offset instead of the absolute address
+    
+  NOTE:
+  With slram it's only possible to map a contigous memory region. Therfore
+  if there's a device mapped somewhere in the region specified slram will
+  fail to load (see kernel log if modprobe fails).
+
+  -
+  
+  Jochen Schaeuble <psionic@psionic.de>
 
 ======================================================================*/
 
@@ -20,8 +46,6 @@
 #include <linux/init.h>
 #include <asm/io.h>
 #include <asm/system.h>
-#include <asm/segment.h>
-#include <stdarg.h>
 
 #include <linux/mtd/mtd.h>
 
@@ -53,7 +77,7 @@
 
 int slram_erase(struct mtd_info *, struct erase_info *);
 int slram_point(struct mtd_info *, loff_t, size_t, size_t *, u_char **);
-void slram_unpoint(struct mtd_info *, u_char *);
+void slram_unpoint(struct mtd_info *, u_char *, loff_t,	size_t);
 int slram_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *);
 int slram_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
 
@@ -94,7 +118,7 @@
 	return(0);
 }
 
-void slram_unpoint(struct mtd_info *mtd, u_char *addr)
+void slram_unpoint(struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
 {
 }
 
@@ -177,7 +201,7 @@
 	(*curmtd)->mtdinfo->write = slram_write;
 	(*curmtd)->mtdinfo->module = THIS_MODULE;
 	(*curmtd)->mtdinfo->type = MTD_RAM;
-	(*curmtd)->mtdinfo->erasesize = 0x10000;
+	(*curmtd)->mtdinfo->erasesize = 0x0;
 
 	if (add_mtd_device((*curmtd)->mtdinfo))	{
 		E("slram: Failed to register new device\n");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/ftl.c linux-2.4.21-pre6/drivers/mtd/ftl.c
--- linux-2.4.20/drivers/mtd/ftl.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/ftl.c	2003-03-26 23:49:20.000000000 +0000
@@ -1,5 +1,5 @@
 /* This version ported to the Linux-MTD system by dwmw2@infradead.org
- * $Id: ftl.c,v 1.43 2002/02/13 15:31:37 dwmw2 Exp $
+ * $Id: ftl.c,v 1.45 2003/01/24 23:31:27 dwmw2 Exp $
  *
  * Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
  * - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups
@@ -70,7 +70,6 @@
 #include <linux/fs.h>
 #include <linux/ioctl.h>
 #include <linux/hdreg.h>
-#include <stdarg.h>
 
 #if (LINUX_VERSION_CODE >= 0x20100)
 #include <linux/vmalloc.h>
@@ -1415,7 +1414,7 @@
 
     memset(myparts, 0, sizeof(myparts));
     
-    DEBUG(0, "$Id: ftl.c,v 1.43 2002/02/13 15:31:37 dwmw2 Exp $\n");
+    DEBUG(0, "$Id: ftl.c,v 1.45 2003/01/24 23:31:27 dwmw2 Exp $\n");
     
     if (register_blkdev(FTL_MAJOR, "ftl", &ftl_blk_fops)) {
 	printk(KERN_NOTICE "ftl_cs: unable to grab major "
@@ -1456,4 +1455,4 @@
 
 MODULE_LICENSE("Dual MPL/GPL");
 MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
-MODULE_DESCRIPTION("Support code for Flash Translation Layer, used on PCMCIA devices and M-Systems DiskOnChip 1000");
+MODULE_DESCRIPTION("Support code for Flash Translation Layer, used on PCMCIA devices");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/maps/Config.in linux-2.4.21-pre6/drivers/mtd/maps/Config.in
--- linux-2.4.20/drivers/mtd/maps/Config.in	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/maps/Config.in	2003-03-26 23:49:39.000000000 +0000
@@ -1,6 +1,6 @@
 # drivers/mtd/maps/Config.in
 
-# $Id: Config.in,v 1.28 2002/03/08 16:34:35 rkaiser Exp $
+# $Id: Config.in,v 1.43 2003/01/24 14:26:38 dwmw2 Exp $
 
 mainmenu_option next_comment
 
@@ -30,9 +30,12 @@
    dep_tristate '  JEDEC Flash device mapped on Mixcom piggyback card' CONFIG_MTD_MIXMEM $CONFIG_MTD_JEDEC
    dep_tristate '  JEDEC Flash device mapped on Octagon 5066 SBC' CONFIG_MTD_OCTAGON $CONFIG_MTD_JEDEC
    dep_tristate '  JEDEC Flash device mapped on Tempustech VMAX SBC301' CONFIG_MTD_VMAX $CONFIG_MTD_JEDEC
+   dep_tristate '  Flash device mapped with DOCCS on NatSemi SCx200' CONFIG_MTD_SCx200_DOCFLASH $CONFIG_MTD_CFI
    dep_tristate '  BIOS flash chip on Intel L440GX boards' CONFIG_MTD_L440GX $CONFIG_MTD_JEDECPROBE
-   dep_tristate ' ROM connected to AMD766 southbridge' CONFIG_MTD_AMD766ROM $CONFIG_MTD_GEN_PROBE   
-   dep_tristate ' ROM connected to Intel Hub Controller 2' CONFIG_MTD_ICH2ROM $CONFIG_MTD_JEDECPROBE
+   dep_tristate '  ROM connected to AMD76X southbridge' CONFIG_MTD_AMD76XROM $CONFIG_MTD_GEN_PROBE   
+   dep_tristate '  ROM connected to Intel Hub Controller 2' CONFIG_MTD_ICH2ROM $CONFIG_MTD_JEDECPROBE
+   dep_tristate '  CFI Flash device mapped on SnapGear/SecureEdge' CONFIG_MTD_NETtel $CONFIG_MTD_PARTITIONS
+   dep_tristate '  BIOS flash chip on Intel SCB2 boards' CONFIG_MTD_SCB2_FLASH $CONFIG_MTD_GEN_PROBE
 fi
 
 if [ "$CONFIG_PPC" = "y" ]; then
@@ -41,16 +44,17 @@
    dep_tristate '  System flash on MBX860 board' CONFIG_MTD_MBX860 $CONFIG_MTD_CFI
    dep_tristate '  CFI Flash device mapped on D-Box2' CONFIG_MTD_DBOX2 $CONFIG_MTD_CFI
    dep_tristate '  CFI Flash device mapping on FlagaDM' CONFIG_MTD_CFI_FLAGADM $CONFIG_MTD_CFI
+   dep_tristate '  CFI Flash device mapped on IBM Redwood-4/5' CONFIG_MTD_REDWOOD $CONFIG_MTD_CFI
 fi
 
 if [ "$CONFIG_MIPS" = "y" ]; then
-   dep_tristate '  Pb1000 boot flash device' CONFIG_MTD_PB1000 $CONFIG_MIPS_PB1000
+   dep_tristate '  Pb1000 MTD support' CONFIG_MTD_PB1000 $CONFIG_MIPS_PB1000
    dep_tristate '  Pb1500 MTD support' CONFIG_MTD_PB1500 $CONFIG_MIPS_PB1500
    dep_tristate '  Pb1100 MTD support' CONFIG_MTD_PB1100 $CONFIG_MIPS_PB1100
    if [ "$CONFIG_MTD_PB1500" = "y" -o "$CONFIG_MTD_PB1500" = "m" \
 	-o "$CONFIG_MTD_PB1100" = "y" -o "$CONFIG_MTD_PB1100" = "m" ]; then
-      bool '  Pb1[015]00 boot flash device' CONFIG_MTD_PB1500_BOOT 
-      bool '  Pb1[015]00 user flash device (2nd 32MB bank)' CONFIG_MTD_PB1500_USER
+      bool '  Pb[15]00 boot flash device' CONFIG_MTD_PB1500_BOOT 
+      bool '  Pb[15]00 user flash device (2nd 32MiB bank)' CONFIG_MTD_PB1500_USER
    fi
    dep_tristate '  Flash chip mapping on ITE QED-4N-S01B, Globespan IVR or custom board' CONFIG_MTD_CSTM_MIPS_IXX $CONFIG_MTD_CFI $CONFIG_MTD_JEDEC $CONFIG_MTD_PARTITIONS 
    if [ "$CONFIG_MTD_CSTM_MIPS_IXX" = "y" -o "$CONFIG_MTD_CSTM_MIPS_IXX" = "m" ]; then
@@ -59,6 +63,7 @@
       int '    Bus width in octets' CONFIG_MTD_CSTM_MIPS_IXX_BUSWIDTH 2
    fi
    dep_tristate '  Momenco Ocelot boot flash device' CONFIG_MTD_OCELOT $CONFIG_MOMENCO_OCELOT
+   dep_tristate '  LASAT flash device' CONFIG_MTD_LASAT $CONFIG_MTD_CFI $CONFIG_LASAT
 fi
 
 if [ "$CONFIG_SUPERH" = "y" ]; then
@@ -74,16 +79,25 @@
    dep_tristate '  CFI Flash device mapped on ARM Integrator/P720T' CONFIG_MTD_ARM_INTEGRATOR $CONFIG_MTD_CFI
    dep_tristate '  Cirrus CDB89712 evaluation board mappings' CONFIG_MTD_CDB89712 $CONFIG_MTD_CFI $CONFIG_ARCH_CDB89712
    dep_tristate '  CFI Flash device mapped on StrongARM SA11x0' CONFIG_MTD_SA1100 $CONFIG_MTD_CFI $CONFIG_ARCH_SA1100 $CONFIG_MTD_PARTITIONS
-   dep_tristate '  CFI Flash device mapped on DC21285 Footbridge' CONFIG_MTD_DC21285 $CONFIG_MTD_CFI $CONFIG_ARCH_FOOTBRIDGE $CONFIG_MTD_PARTITIONS
+   dep_tristate '  CFI Flash device mapped on DC21285 Footbridge' CONFIG_MTD_DC21285 $CONFIG_MTD_CFI $CONFIG_ARCH_FOOTBRIDGE
    dep_tristate '  CFI Flash device mapped on the XScale IQ80310 board' CONFIG_MTD_IQ80310 $CONFIG_MTD_CFI $CONFIG_ARCH_IQ80310
    dep_tristate '  CFI Flash device mapped on Epxa10db' CONFIG_MTD_EPXA10DB $CONFIG_MTD_CFI  $CONFIG_MTD_PARTITIONS $CONFIG_ARCH_CAMELOT
+   dep_tristate '  CFI Flash device mapped on the FortuNet board' CONFIG_MTD_FORTUNET $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS $CONFIG_SA1100_FORTUNET
    dep_tristate '  NV-RAM mapping AUTCPU12 board' CONFIG_MTD_AUTCPU12 $CONFIG_ARCH_AUTCPU12
+   dep_tristate '  CFI Flash device mapped on EDB7312' CONFIG_MTD_EDB7312 $CONFIG_MTD_CFI
+   dep_tristate '  JEDEC Flash device mapped on impA7' CONFIG_MTD_IMPA7 $CONFIG_MTD_JEDECPROBE
+   dep_tristate '  JEDEC Flash device mapped on Ceiva/Polaroid PhotoMax Digital Picture Frame' CONFIG_MTD_CEIVA $CONFIG_MTD_JEDECPROBE  $CONFIG_ARCH_CEIVA
 fi
 if [ "$CONFIG_ALPHA" = "y" ]; then
    dep_tristate '  Flash chip mapping on TSUNAMI' CONFIG_MTD_TSUNAMI $CONFIG_MTD_GENPROBE
 fi
 
+if [ "$CONFIG_UCLINUX" = "y" ]; then
+   dep_tristate '  Generic uClinux RAM/ROM filesystem support' CONFIG_MTD_UCLINUX $CONFIG_MTD_PARTITIONS
+fi
+
 # This needs CFI or JEDEC, depending on the cards found.
 dep_tristate '  PCI MTD driver' CONFIG_MTD_PCI $CONFIG_MTD $CONFIG_PCI
+dep_tristate '  PCMCIA MTD driver' CONFIG_MTD_PCMCIA $CONFIG_MTD $CONFIG_PCMCIA
 
 endmenu
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/maps/Makefile linux-2.4.21-pre6/drivers/mtd/maps/Makefile
--- linux-2.4.20/drivers/mtd/maps/Makefile	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/maps/Makefile	2003-03-26 23:48:57.000000000 +0000
@@ -1,44 +1,65 @@
 #
 # linux/drivers/maps/Makefile
 #
-# $Id: Makefile,v 1.21 2002/02/22 09:34:44 gleixner Exp $
+# $Id: Makefile,v 1.37 2003/01/24 14:26:38 dwmw2 Exp $
 
+BELOW25		:= $(shell echo $(PATCHLEVEL) | sed s/[1234]/y/)
+
+ifeq ($(BELOW25),y)
 O_TARGET	:= mapslink.o
+endif
 
 # Chip mappings
-obj-$(CONFIG_MTD_CDB89712)      += cdb89712.o
+obj-$(CONFIG_MTD_CDB89712)	+= cdb89712.o
 obj-$(CONFIG_MTD_ARM_INTEGRATOR)+= integrator-flash.o
 obj-$(CONFIG_MTD_CFI_FLAGADM)	+= cfi_flagadm.o
-obj-$(CONFIG_MTD_CSTM_MIPS_IXX) += cstm_mips_ixx.o
-obj-$(CONFIG_MTD_DC21285)       += dc21285.o
-obj-$(CONFIG_MTD_DILNETPC)      += dilnetpc.o
-obj-$(CONFIG_MTD_ELAN_104NC)    += elan-104nc.o
-obj-$(CONFIG_MTD_EPXA10DB)      += epxa10db-flash.o
+obj-$(CONFIG_MTD_CSTM_MIPS_IXX)	+= cstm_mips_ixx.o
+obj-$(CONFIG_MTD_DC21285)	+= dc21285.o
+obj-$(CONFIG_MTD_DILNETPC)	+= dilnetpc.o
+obj-$(CONFIG_MTD_ELAN_104NC)	+= elan-104nc.o
+obj-$(CONFIG_MTD_EPXA10DB)	+= epxa10db-flash.o
 obj-$(CONFIG_MTD_IQ80310)	+= iq80310.o
 obj-$(CONFIG_MTD_L440GX)	+= l440gx.o
-obj-$(CONFIG_MTD_AMD766ROM)	+= amd766rom.o
+obj-$(CONFIG_MTD_AMD76XROM)	+= amd76xrom.o
 obj-$(CONFIG_MTD_ICH2ROM)	+= ich2rom.o
 obj-$(CONFIG_MTD_TSUNAMI)	+= tsunami_flash.o
 obj-$(CONFIG_MTD_MBX860)	+= mbx860.o
 obj-$(CONFIG_MTD_NORA)		+= nora.o
+obj-$(CONFIG_MTD_CEIVA)		+= ceiva.o
 obj-$(CONFIG_MTD_OCTAGON)	+= octagon-5066.o
-obj-$(CONFIG_MTD_PHYSMAP)	+= physmap.o 
+ifneq ($(CONFIG_MTD_PHYSMAP),n)
+  ifeq ($(CONFIG_MTD_PHYSMAP_BUSWIDTH),8)
+    obj-$(CONFIG_MTD_PHYSMAP)	+= physmap64.o 
+  else
+    obj-$(CONFIG_MTD_PHYSMAP)	+= physmap.o 
+  endif
+endif
 obj-$(CONFIG_MTD_PNC2000)	+= pnc2000.o
+obj-$(CONFIG_MTD_PCMCIA)	+= pcmciamtd.o
 obj-$(CONFIG_MTD_RPXLITE)	+= rpxlite.o
 obj-$(CONFIG_MTD_TQM8XXL)	+= tqm8xxl.o
-obj-$(CONFIG_MTD_SA1100)        += sa1100-flash.o
+obj-$(CONFIG_MTD_SA1100)	+= sa1100-flash.o
 obj-$(CONFIG_MTD_SBC_GXX)	+= sbc_gxx.o
 obj-$(CONFIG_MTD_SC520CDP)	+= sc520cdp.o
 obj-$(CONFIG_MTD_NETSC520)	+= netsc520.o
-obj-$(CONFIG_MTD_SUN_UFLASH)    += sun_uflash.o
+obj-$(CONFIG_MTD_SUN_UFLASH)	+= sun_uflash.o
 obj-$(CONFIG_MTD_VMAX)		+= vmax301.o
+obj-$(CONFIG_MTD_SCx200_DOCFLASH)+= scx200_docflash.o
 obj-$(CONFIG_MTD_DBOX2)		+= dbox2-flash.o
 obj-$(CONFIG_MTD_OCELOT)	+= ocelot.o
 obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o
 obj-$(CONFIG_MTD_PCI)		+= pci.o
-obj-$(CONFIG_MTD_PB1000)        += pb1xxx-flash.o
-obj-$(CONFIG_MTD_PB1100)        += pb1xxx-flash.o
-obj-$(CONFIG_MTD_PB1500)        += pb1xxx-flash.o
+obj-$(CONFIG_MTD_PB1000)	+= pb1xxx-flash.o
+obj-$(CONFIG_MTD_PB1100)	+= pb1xxx-flash.o
+obj-$(CONFIG_MTD_PB1500)	+= pb1xxx-flash.o
+obj-$(CONFIG_MTD_LASAT)		+= lasat.o
 obj-$(CONFIG_MTD_AUTCPU12)	+= autcpu12-nvram.o
+obj-$(CONFIG_MTD_EDB7312)	+= edb7312.o
+obj-$(CONFIG_MTD_IMPA7)		+= impa7.o
+obj-$(CONFIG_MTD_FORTUNET)	+= fortunet.o
+obj-$(CONFIG_MTD_REDWOOD)	+= redwood.o
+obj-$(CONFIG_MTD_UCLINUX)	+= uclinux.o
+obj-$(CONFIG_MTD_NETtel)	+= nettel.o
+obj-$(CONFIG_MTD_SCB2_FLASH)	+= scb2_flash.o
 
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/maps/amd76xrom.c linux-2.4.21-pre6/drivers/mtd/maps/amd76xrom.c
--- linux-2.4.20/drivers/mtd/maps/amd76xrom.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/maps/amd76xrom.c	2003-03-26 23:49:25.000000000 +0000
@@ -0,0 +1,257 @@
+/*
+ * amd76xrom.c
+ *
+ * Normal mappings of chips in physical memory
+ * $Id: amd76xrom.c,v 1.1 2002/10/18 22:45:48 eric Exp $
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+
+
+struct amd76xrom_map_info {
+	struct map_info map;
+	struct mtd_info *mtd;
+	unsigned long window_addr;
+	u32 window_start, window_size;
+	struct pci_dev *pdev;
+};
+
+static __u8 amd76xrom_read8(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readb(map->map_priv_1 + ofs);
+}
+
+static __u16 amd76xrom_read16(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readw(map->map_priv_1 + ofs);
+}
+
+static __u32 amd76xrom_read32(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readl(map->map_priv_1 + ofs);
+}
+
+static void amd76xrom_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	memcpy_fromio(to, map->map_priv_1 + from, len);
+}
+
+static void amd76xrom_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+	__raw_writeb(d, map->map_priv_1 + adr);
+	mb();
+}
+
+static void amd76xrom_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+	__raw_writew(d, map->map_priv_1 + adr);
+	mb();
+}
+
+static void amd76xrom_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+	__raw_writel(d, map->map_priv_1 + adr);
+	mb();
+}
+
+static void amd76xrom_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	memcpy_toio(map->map_priv_1 + to, from, len);
+}
+
+static struct amd76xrom_map_info amd76xrom_map = {
+	map: {
+		name: "AMD76X rom",
+		size: 0,
+		buswidth: 1,
+		read8: amd76xrom_read8,
+		read16: amd76xrom_read16,
+		read32: amd76xrom_read32,
+		copy_from: amd76xrom_copy_from,
+		write8: amd76xrom_write8,
+		write16: amd76xrom_write16,
+		write32: amd76xrom_write32,
+		copy_to: amd76xrom_copy_to,
+		/* The standard rom socket is for single power supply chips
+		 * that don't have an extra vpp.
+		 */
+	},
+	mtd: 0,
+	window_addr: 0,
+};
+
+static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
+	const struct pci_device_id *ent)
+{
+	struct rom_window {
+		u32 start;
+		u32 size;
+		u8 segen_bits;
+	};
+	static struct rom_window rom_window[] = {
+		{ 0xffb00000, 5*1024*1024, (1<<7) | (1<<6), },
+		{ 0xffc00000, 4*1024*1024, (1<<7), },
+		{ 0xffff0000, 64*1024,     0 },
+		{ 0         , 0,           0 },
+	};
+	static const u32 rom_probe_sizes[] = { 
+		5*1024*1024, 4*1024*1024, 2*1024*1024, 1024*1024, 512*1024, 
+		256*1024, 128*1024, 64*1024, 0};
+	static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", 0 };
+	u8 byte;
+	struct amd76xrom_map_info *info = &amd76xrom_map;
+	struct rom_window *window;
+	int i;
+	u32 rom_size;
+
+	window = &rom_window[0];
+#if 0
+	while(window->size) {
+		if (request_mem_region(window->start, window->size, "amd76xrom")) {
+			break;
+		}
+		window++;
+	}
+	if (!window->size) {
+		printk(KERN_ERR "amd76xrom: cannot reserve rom window\n");
+		goto err_out_none;
+	}
+#endif
+
+	/* Enable the selected rom window */
+	pci_read_config_byte(pdev, 0x43, &byte);
+	pci_write_config_byte(pdev, 0x43, byte | window->segen_bits);
+
+	/* Enable writes through the rom window */
+	pci_read_config_byte(pdev, 0x40, &byte);
+	pci_write_config_byte(pdev, 0x40, byte | 1);
+
+	/* FIXME handle registers 0x80 - 0x8C the bios region locks */
+
+	printk(KERN_NOTICE "amd76xrom window : %x at %x\n", 
+		window->size, window->start);
+	/* For write accesses caches are useless */
+	info->window_addr = (unsigned long)ioremap_nocache(window->start, window->size);
+
+	if (!info->window_addr) {
+		printk(KERN_ERR "Failed to ioremap\n");
+		goto err_out_free_mmio_region;
+	}
+	info->mtd = 0;
+	for(i = 0; (rom_size = rom_probe_sizes[i]); i++) {
+		char **chip_type;
+		if (rom_size > window->size) {
+			continue;
+		}
+		info->map.map_priv_1 = 
+			info->window_addr + window->size - rom_size;
+		info->map.size = rom_size;
+		chip_type = rom_probe_types;
+		for(; !info->mtd && *chip_type; chip_type++) {
+			info->mtd = do_map_probe(*chip_type, &amd76xrom_map.map);
+		}
+		if (info->mtd) {
+			break;
+		}
+	}
+	if (!info->mtd) {
+		goto err_out_iounmap;
+	}
+	printk(KERN_NOTICE "amd76xrom chip at offset: %x\n",
+		window->size - rom_size);
+		
+	info->mtd->module = THIS_MODULE;
+	add_mtd_device(info->mtd);
+	info->window_start = window->start;
+	info->window_size = window->size;
+	return 0;
+
+err_out_iounmap:
+	iounmap((void *)(info->window_addr));
+err_out_free_mmio_region:
+	release_mem_region(window->start, window->size);
+err_out_none:
+	return -ENODEV;
+}
+
+
+static void __devexit amd76xrom_remove_one (struct pci_dev *pdev)
+{
+	struct amd76xrom_map_info *info = &amd76xrom_map;
+	u8 byte;
+
+	del_mtd_device(info->mtd);
+	map_destroy(info->mtd);
+	info->mtd = 0;
+	info->map.map_priv_1 = 0;
+
+	iounmap((void *)(info->window_addr));
+	info->window_addr = 0;
+
+	/* Disable writes through the rom window */
+	pci_read_config_byte(pdev, 0x40, &byte);
+	pci_write_config_byte(pdev, 0x40, byte & ~1);
+	
+	release_mem_region(info->window_start, info->window_size);
+}
+
+static struct pci_device_id amd76xrom_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410,  
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7440,  
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, amd76xrom_pci_tbl);
+
+#if 0
+static struct pci_driver amd76xrom_driver = {
+	name:	  "amd76xrom",
+	id_table: amd76xrom_pci_tbl,
+	probe:    amd76xrom_init_one,
+	remove:   amd76xrom_remove_one,
+};
+#endif
+
+int __init init_amd76xrom(void)
+{
+	struct pci_dev *pdev;
+	struct pci_device_id *id;
+	pdev = 0;
+	for(id = amd76xrom_pci_tbl; id->vendor; id++) {
+		pdev = pci_find_device(id->vendor, id->device, 0);
+		if (pdev) {
+			break;
+		}
+	}
+	if (pdev) {
+		amd76xrom_map.pdev = pdev;
+		return amd76xrom_init_one(pdev, &amd76xrom_pci_tbl[0]);
+	}
+	return -ENXIO;
+#if 0
+	return pci_module_init(&amd76xrom_driver);
+#endif
+}
+
+static void __exit cleanup_amd76xrom(void)
+{
+	amd76xrom_remove_one(amd76xrom_map.pdev);
+}
+
+module_init(init_amd76xrom);
+module_exit(cleanup_amd76xrom);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Eric Biederman <ebiederman@lnxi.com>");
+MODULE_DESCRIPTION("MTD map driver for BIOS chips on the AMD76X southbridge");
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/maps/ceiva.c linux-2.4.21-pre6/drivers/mtd/maps/ceiva.c
--- linux-2.4.20/drivers/mtd/maps/ceiva.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/maps/ceiva.c	2003-03-26 23:49:29.000000000 +0000
@@ -0,0 +1,408 @@
+/*
+ * Ceiva flash memory driver.
+ * Copyright (C) 2002 Rob Scott <rscott@mtrob.fdns.net>
+ *
+ * Note: this driver supports jedec compatible devices. Modification
+ * for CFI compatible devices should be straight forward: change
+ * jedec_probe to cfi_probe.
+ *
+ * Based on: sa1100-flash.c, which has the following copyright:
+ * Flash memory access on SA11x0 based devices
+ *
+ * (C) 2000 Nicolas Pitre <nico@cam.org>
+ *
+ * $Id: ceiva.c,v 1.2 2002/10/14 12:50:22 rmk Exp $
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/concat.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/io.h>
+#include <asm/sizes.h>
+
+/*
+ * This isnt complete yet, so...
+ */
+#define CONFIG_MTD_CEIVA_STATICMAP
+
+static __u8 clps_read8(struct map_info *map, unsigned long ofs)
+{
+	return readb(map->map_priv_1 + ofs);
+}
+
+static __u16 clps_read16(struct map_info *map, unsigned long ofs)
+{
+	return readw(map->map_priv_1 + ofs);
+}
+
+static __u32 clps_read32(struct map_info *map, unsigned long ofs)
+{
+	return readl(map->map_priv_1 + ofs);
+}
+
+static void clps_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	memcpy(to, (void *)(map->map_priv_1 + from), len);
+}
+
+static void clps_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+	writeb(d, map->map_priv_1 + adr);
+}
+
+static void clps_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+	writew(d, map->map_priv_1 + adr);
+}
+
+static void clps_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+	writel(d, map->map_priv_1 + adr);
+}
+
+static void clps_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	memcpy((void *)(map->map_priv_1 + to), from, len);
+}
+
+static struct map_info clps_map __initdata = {
+	name:		"clps flash",
+	read8:		clps_read8,
+	read16:		clps_read16,
+	read32:		clps_read32,
+	copy_from:	clps_copy_from,
+	write8:		clps_write8,
+	write16:	clps_write16,
+	write32:	clps_write32,
+	copy_to:	clps_copy_to,
+};
+
+#ifdef CONFIG_MTD_CEIVA_STATICMAP
+/*
+ * See include/linux/mtd/partitions.h for definition of the mtd_partition
+ * structure.
+ *
+ * Please note:
+ *  1. The flash size given should be the largest flash size that can
+ *     be accomodated.
+ *
+ *  2. The bus width must defined in clps_setup_flash.
+ *
+ * The MTD layer will detect flash chip aliasing and reduce the size of
+ * the map accordingly.
+ *
+ */
+
+#ifdef CONFIG_ARCH_CEIVA
+/* Flash / Partition sizing */
+/* For the 28F8003, we use the block mapping to calcuate the sizes */
+#define MAX_SIZE_KiB                  (16 + 8 + 8 + 96 + (7*128))
+#define BOOT_PARTITION_SIZE_KiB       (16)
+#define PARAMS_PARTITION_SIZE_KiB     (8)
+#define KERNEL_PARTITION_SIZE_KiB     (4*128)
+/* Use both remaing portion of first flash, and all of second flash */
+#define ROOT_PARTITION_SIZE_KiB       (3*128) + (8*128)
+
+static struct mtd_partition ceiva_partitions[] = {
+	{
+		name: "Ceiva BOOT partition",
+		size:   BOOT_PARTITION_SIZE_KiB*1024,
+		offset: 0,
+
+	},{
+		name: "Ceiva parameters partition",
+		size:   PARAMS_PARTITION_SIZE_KiB*1024,
+		offset: (16 + 8) * 1024,
+	},{
+		name: "Ceiva kernel partition",
+		size: (KERNEL_PARTITION_SIZE_KiB)*1024,
+		offset: 0x20000,
+
+	},{
+		name: "Ceiva root filesystem partition",
+		offset: MTDPART_OFS_APPEND,
+		size: (ROOT_PARTITION_SIZE_KiB)*1024,
+	}
+};
+#endif
+
+static int __init clps_static_partitions(struct mtd_partition **parts)
+{
+	int nb_parts = 0;
+
+#ifdef CONFIG_ARCH_CEIVA
+	if (machine_is_ceiva()) {
+		*parts       = ceiva_partitions;
+		nb_parts     = ARRAY_SIZE(ceiva_partitions);
+	}
+#endif
+	return nb_parts;
+}
+#endif
+
+struct clps_info {
+	unsigned long base;
+	unsigned long size;
+	int width;
+	void *vbase;
+	struct map_info *map;
+	struct mtd_info *mtd;
+	struct resource *res;
+};
+
+#define NR_SUBMTD 4
+
+static struct clps_info info[NR_SUBMTD];
+
+static int __init clps_setup_mtd(struct clps_info *clps, int nr, struct mtd_info **rmtd)
+{
+	struct mtd_info *subdev[nr];
+	struct map_info *maps;
+	int i, found = 0, ret = 0;
+
+	/*
+	 * Allocate the map_info structs in one go.
+	 */
+	maps = kmalloc(sizeof(struct map_info) * nr, GFP_KERNEL);
+	if (!maps)
+		return -ENOMEM;
+
+	/*
+	 * Claim and then map the memory regions.
+	 */
+	for (i = 0; i < nr; i++) {
+		if (clps[i].base == (unsigned long)-1)
+			break;
+
+		clps[i].res = request_mem_region(clps[i].base, clps[i].size, "clps flash");
+		if (!clps[i].res) {
+			ret = -EBUSY;
+			break;
+		}
+
+		clps[i].map = maps + i;
+		memcpy(clps[i].map, &clps_map, sizeof(struct map_info));
+
+		clps[i].vbase = ioremap(clps[i].base, clps[i].size);
+		if (!clps[i].vbase) {
+			ret = -ENOMEM;
+			break;
+		}
+
+		clps[i].map->map_priv_1 = (unsigned long)clps[i].vbase;
+		clps[i].map->buswidth = clps[i].width;
+		clps[i].map->size = clps[i].size;
+
+		clps[i].mtd = do_map_probe("jedec_probe", clps[i].map);
+		if (clps[i].mtd == NULL) {
+			ret = -ENXIO;
+			break;
+		}
+		clps[i].mtd->module = THIS_MODULE;
+		subdev[i] = clps[i].mtd;
+
+		printk(KERN_INFO "clps flash: JEDEC device at 0x%08lx, %dMiB, "
+			"%d-bit\n", clps[i].base, clps[i].mtd->size >> 20,
+			clps[i].width * 8);
+		found += 1;
+	}
+
+	/*
+	 * ENXIO is special.  It means we didn't find a chip when
+	 * we probed.  We need to tear down the mapping, free the
+	 * resource and mark it as such.
+	 */
+	if (ret == -ENXIO) {
+		iounmap(clps[i].vbase);
+		clps[i].vbase = NULL;
+		release_resource(clps[i].res);
+		clps[i].res = NULL;
+	}
+
+	/*
+	 * If we found one device, don't bother with concat support.
+	 * If we found multiple devices, use concat if we have it
+	 * available, otherwise fail.
+	 */
+	if (ret == 0 || ret == -ENXIO) {
+		if (found == 1) {
+			*rmtd = subdev[0];
+			ret = 0;
+		} else if (found > 1) {
+			/*
+			 * We detected multiple devices.  Concatenate
+			 * them together.
+			 */
+#ifdef CONFIG_MTD_CONCAT
+			*rmtd = mtd_concat_create(subdev, found,
+						  "clps flash");
+			if (*rmtd == NULL)
+				ret = -ENXIO;
+#else
+			printk(KERN_ERR "clps flash: multiple devices "
+			       "found but MTD concat support disabled.\n");
+			ret = -ENXIO;
+#endif
+		}
+	}
+
+	/*
+	 * If we failed, clean up.
+	 */
+	if (ret) {
+		do {
+			if (clps[i].mtd)
+				map_destroy(clps[i].mtd);
+			if (clps[i].vbase)
+				iounmap(clps[i].vbase);
+			if (clps[i].res)
+				release_resource(clps[i].res);
+		} while (i--);
+
+		kfree(maps);
+	}
+
+	return ret;
+}
+
+static void __exit clps_destroy_mtd(struct clps_info *clps, struct mtd_info *mtd)
+{
+	int i;
+
+	del_mtd_partitions(mtd);
+
+	if (mtd != clps[0].mtd)
+		mtd_concat_destroy(mtd);
+
+	for (i = NR_SUBMTD; i >= 0; i--) {
+		if (clps[i].mtd)
+			map_destroy(clps[i].mtd);
+		if (clps[i].vbase)
+			iounmap(clps[i].vbase);
+		if (clps[i].res)
+			release_resource(clps[i].res);
+	}
+	kfree(clps[0].map);
+}
+
+/*
+ * We define the memory space, size, and width for the flash memory
+ * space here.
+ */
+
+static int __init clps_setup_flash(void)
+{
+	int nr;
+
+#ifdef CONFIG_ARCH_CEIVA
+	if (machine_is_ceiva()) {
+		info[0].base = CS0_PHYS_BASE;
+		info[0].size = SZ_32M;
+		info[0].width = CEIVA_FLASH_WIDTH;
+		info[1].base = CS1_PHYS_BASE;
+		info[1].size = SZ_32M;
+		info[1].width = CEIVA_FLASH_WIDTH;
+		nr = 2;
+	}
+#endif
+	return nr;
+}
+
+extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts);
+extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partition **pparts, char *);
+
+static struct mtd_partition *parsed_parts;
+
+static void __init clps_locate_partitions(struct mtd_info *mtd)
+{
+	const char *part_type = NULL;
+	int nr_parts = 0;
+	do {
+		/*
+		 * Partition selection stuff.
+		 */
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+		nr_parts = parse_cmdline_partitions(mtd, &parsed_parts, "clps");
+		if (nr_parts > 0) {
+			part_type = "command line";
+			break;
+		}
+#endif
+#ifdef CONFIG_MTD_REDBOOT_PARTS
+		nr_parts = parse_redboot_partitions(mtd, &parsed_parts);
+		if (nr_parts > 0) {
+			part_type = "RedBoot";
+			break;
+		}
+#endif
+#ifdef CONFIG_MTD_CEIVA_STATICMAP
+		nr_parts = clps_static_partitions(&parsed_parts);
+		if (nr_parts > 0) {
+			part_type = "static";
+			break;
+		}
+		printk("found: %d partitions\n", nr_parts);
+#endif
+	} while (0);
+
+	if (nr_parts == 0) {
+		printk(KERN_NOTICE "clps flash: no partition info "
+			"available, registering whole flash\n");
+		add_mtd_device(mtd);
+	} else {
+		printk(KERN_NOTICE "clps flash: using %s partition "
+			"definition\n", part_type);
+		add_mtd_partitions(mtd, parsed_parts, nr_parts);
+	}
+
+	/* Always succeeds. */
+}
+
+static void __exit clps_destroy_partitions(void)
+{
+	if (parsed_parts)
+		kfree(parsed_parts);
+}
+
+static struct mtd_info *mymtd;
+
+static int __init clps_mtd_init(void)
+{
+	int ret;
+	int nr;
+
+	nr = clps_setup_flash();
+	if (nr < 0)
+		return nr;
+
+	ret = clps_setup_mtd(info, nr, &mymtd);
+	if (ret)
+		return ret;
+
+	clps_locate_partitions(mymtd);
+
+	return 0;
+}
+
+static void __exit clps_mtd_cleanup(void)
+{
+	clps_destroy_mtd(info, mymtd);
+	clps_destroy_partitions();
+}
+
+module_init(clps_mtd_init);
+module_exit(clps_mtd_cleanup);
+
+MODULE_AUTHOR("Rob Scott");
+MODULE_DESCRIPTION("Cirrus Logic JEDEC map driver");
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/maps/dc21285.c linux-2.4.21-pre6/drivers/mtd/maps/dc21285.c
--- linux-2.4.20/drivers/mtd/maps/dc21285.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/maps/dc21285.c	2003-03-26 23:49:30.000000000 +0000
@@ -5,9 +5,9 @@
  *
  * This code is GPL
  * 
- * $Id: dc21285.c,v 1.7 2001/10/11 16:17:51 nico Exp $
+ * $Id: dc21285.c,v 1.9 2002/10/14 12:22:10 rmk Exp $
  */
-
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -131,7 +131,7 @@
 		dc21285_map.buswidth*8);
 
 	/* Let's map the flash area */
-	dc21285_map.map_priv_1 = (unsigned long)__ioremap(DC21285_FLASH, 16*1024*1024, 0);
+	dc21285_map.map_priv_1 = (unsigned long)ioremap(DC21285_FLASH, 16*1024*1024);
 	if (!dc21285_map.map_priv_1) {
 		printk("Failed to ioremap\n");
 		return -EIO;
@@ -139,21 +139,22 @@
 
 	mymtd = do_map_probe("cfi_probe", &dc21285_map);
 	if (mymtd) {
-		int nrparts;
+		int nrparts = 0;
 
 		mymtd->module = THIS_MODULE;
 			
 		/* partition fixup */
 
+#ifdef CONFIG_MTD_REDBOOT_PARTS
 		nrparts = parse_redboot_partitions(mymtd, &dc21285_parts);
-		if (nrparts <=0) {
+#endif
+		if (nrparts > 0) {
+			add_mtd_partitions(mymtd, dc21285_parts, nrparts);
+		} else if (nrparts == 0) {
 			printk(KERN_NOTICE "RedBoot partition table failed\n");
-			iounmap((void *)dc21285_map.map_priv_1);
-			return -ENXIO;
+			add_mtd_device(mymtd);
 		}
 
-		add_mtd_partitions(mymtd, dc21285_parts, nrparts);
-
 		/* 
 		 * Flash timing is determined with bits 19-16 of the
 		 * CSR_SA110_CNTL.  The value is the number of wait cycles, or
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/maps/edb7312.c linux-2.4.21-pre6/drivers/mtd/maps/edb7312.c
--- linux-2.4.20/drivers/mtd/maps/edb7312.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/maps/edb7312.c	2003-03-26 23:49:39.000000000 +0000
@@ -0,0 +1,202 @@
+/*
+ * $Id: edb7312.c,v 1.2 2002/09/05 05:11:24 acurtis Exp $
+ *
+ * Handle mapping of the NOR flash on Cogent EDB7312 boards
+ *
+ * Copyright 2002 SYSGO Real-Time Solutions GmbH
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/config.h>
+
+#ifdef CONFIG_MTD_PARTITIONS
+#include <linux/mtd/partitions.h>
+#endif
+
+#define WINDOW_ADDR 0x00000000      /* physical properties of flash */
+#define WINDOW_SIZE 0x01000000
+#define BUSWIDTH    2
+#define FLASH_BLOCKSIZE_MAIN	0x20000
+#define FLASH_NUMBLOCKS_MAIN	128
+/* can be "cfi_probe", "jedec_probe", "map_rom", 0 }; */
+#define PROBETYPES { "cfi_probe", 0 }
+
+#define MSG_PREFIX "EDB7312-NOR:"   /* prefix for our printk()'s */
+#define MTDID      "edb7312-nor"    /* for mtdparts= partitioning */
+
+static struct mtd_info *mymtd;
+
+__u8 edb7312nor_read8(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readb(map->map_priv_1 + ofs);
+}
+
+__u16 edb7312nor_read16(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readw(map->map_priv_1 + ofs);
+}
+
+__u32 edb7312nor_read32(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readl(map->map_priv_1 + ofs);
+}
+
+void edb7312nor_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	memcpy_fromio(to, map->map_priv_1 + from, len);
+}
+
+void edb7312nor_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+	__raw_writeb(d, map->map_priv_1 + adr);
+	mb();
+}
+
+void edb7312nor_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+	__raw_writew(d, map->map_priv_1 + adr);
+	mb();
+}
+
+void edb7312nor_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+	__raw_writel(d, map->map_priv_1 + adr);
+	mb();
+}
+
+void edb7312nor_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	memcpy_toio(map->map_priv_1 + to, from, len);
+}
+
+struct map_info edb7312nor_map = {
+	name: "NOR flash on EDB7312",
+	size: WINDOW_SIZE,
+	buswidth: BUSWIDTH,
+	read8: edb7312nor_read8,
+	read16: edb7312nor_read16,
+	read32: edb7312nor_read32,
+	copy_from: edb7312nor_copy_from,
+	write8: edb7312nor_write8,
+	write16: edb7312nor_write16,
+	write32: edb7312nor_write32,
+	copy_to: edb7312nor_copy_to
+};
+
+#ifdef CONFIG_MTD_PARTITIONS
+
+/*
+ * MTD partitioning stuff 
+ */
+static struct mtd_partition static_partitions[3] =
+{
+    {
+	name: "ARMboot",
+	  size: 0x40000,
+	  offset: 0
+    },
+    {
+	name: "Kernel",
+	  size: 0x200000,
+	  offset: 0x40000
+    },
+    {
+	name: "RootFS",
+	  size: 0xDC0000,
+	  offset: 0x240000
+    },
+};
+
+#define NB_OF(x) (sizeof (x) / sizeof (x[0]))
+
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+int parse_cmdline_partitions(struct mtd_info *master, 
+			     struct mtd_partition **pparts,
+			     const char *mtd_id);
+#endif
+
+#endif
+
+static int                   mtd_parts_nb = 0;
+static struct mtd_partition *mtd_parts    = 0;
+
+int __init init_edb7312nor(void)
+{
+	static const char *rom_probe_types[] = PROBETYPES;
+	const char **type;
+	const char *part_type = 0;
+
+       	printk(KERN_NOTICE MSG_PREFIX "0x%08x at 0x%08x\n", 
+	       WINDOW_SIZE, WINDOW_ADDR);
+	edb7312nor_map.map_priv_1 = (unsigned long)
+	  ioremap(WINDOW_ADDR, WINDOW_SIZE);
+
+	if (!edb7312nor_map.map_priv_1) {
+		printk(MSG_PREFIX "failed to ioremap\n");
+		return -EIO;
+	}
+
+	mymtd = 0;
+	type = rom_probe_types;
+	for(; !mymtd && *type; type++) {
+		mymtd = do_map_probe(*type, &edb7312nor_map);
+	}
+	if (mymtd) {
+		mymtd->module = THIS_MODULE;
+
+#ifdef CONFIG_MTD_PARTITIONS
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+		mtd_parts_nb = parse_cmdline_partitions(mymtd, &mtd_parts, MTDID);
+		if (mtd_parts_nb > 0)
+		  part_type = "command line";
+#endif
+		if (mtd_parts_nb == 0)
+		{
+			mtd_parts = static_partitions;
+			mtd_parts_nb = NB_OF(static_partitions);
+			part_type = "static";
+		}
+#endif
+		add_mtd_device(mymtd);
+		if (mtd_parts_nb == 0)
+		  printk(KERN_NOTICE MSG_PREFIX "no partition info available\n");
+		else
+		{
+			printk(KERN_NOTICE MSG_PREFIX
+			       "using %s partition definition\n", part_type);
+			add_mtd_partitions(mymtd, mtd_parts, mtd_parts_nb);
+		}
+		return 0;
+	}
+
+	iounmap((void *)edb7312nor_map.map_priv_1);
+	return -ENXIO;
+}
+
+static void __exit cleanup_edb7312nor(void)
+{
+	if (mymtd) {
+		del_mtd_device(mymtd);
+		map_destroy(mymtd);
+	}
+	if (edb7312nor_map.map_priv_1) {
+		iounmap((void *)edb7312nor_map.map_priv_1);
+		edb7312nor_map.map_priv_1 = 0;
+	}
+}
+
+module_init(init_edb7312nor);
+module_exit(cleanup_edb7312nor);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Marius Groeger <mag@sysgo.de>");
+MODULE_DESCRIPTION("Generic configurable MTD map driver");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/maps/epxa10db-flash.c linux-2.4.21-pre6/drivers/mtd/maps/epxa10db-flash.c
--- linux-2.4.20/drivers/mtd/maps/epxa10db-flash.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/maps/epxa10db-flash.c	2003-03-26 23:48:58.000000000 +0000
@@ -5,7 +5,7 @@
  *  Copyright (C) 2001 Altera Corporation
  *  Copyright (C) 2001 Red Hat, Inc.
  *
- * $Id: epxa10db-flash.c,v 1.2 2001/12/19 13:00:19 jskov Exp $ 
+ * $Id: epxa10db-flash.c,v 1.4 2002/08/22 10:46:19 cdavies 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
@@ -32,6 +32,11 @@
 #include <linux/mtd/partitions.h>
 
 #include <asm/hardware.h>
+#ifdef CONFIG_EPXA10DB
+#define BOARD_NAME "EPXA10DB"
+#else
+#define BOARD_NAME "EPXA1DB"
+#endif
 
 static int nr_parts = 0;
 static struct mtd_partition *parts;
@@ -39,91 +44,94 @@
 static struct mtd_info *mymtd;
 
 extern int parse_redboot_partitions(struct mtd_info *, struct mtd_partition **);
-static int epxa10db_default_partitions(struct mtd_info *master, struct mtd_partition **pparts);
+static int epxa_default_partitions(struct mtd_info *master, struct mtd_partition **pparts);
 
-static __u8 epxa10db_read8(struct map_info *map, unsigned long ofs)
+static __u8 epxa_read8(struct map_info *map, unsigned long ofs)
 {
 	return __raw_readb(map->map_priv_1 + ofs);
 }
 
-static __u16 epxa10db_read16(struct map_info *map, unsigned long ofs)
+static __u16 epxa_read16(struct map_info *map, unsigned long ofs)
 {
 	return __raw_readw(map->map_priv_1 + ofs);
 }
 
-static __u32 epxa10db_read32(struct map_info *map, unsigned long ofs)
+static __u32 epxa_read32(struct map_info *map, unsigned long ofs)
 {
 	return __raw_readl(map->map_priv_1 + ofs);
 }
 
-static void epxa10db_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+static void epxa_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
 {
 	memcpy_fromio(to, (void *)(map->map_priv_1 + from), len);
 }
 
-static void epxa10db_write8(struct map_info *map, __u8 d, unsigned long adr)
+static void epxa_write8(struct map_info *map, __u8 d, unsigned long adr)
 {
 	__raw_writeb(d, map->map_priv_1 + adr);
 	mb();
 }
 
-static void epxa10db_write16(struct map_info *map, __u16 d, unsigned long adr)
+static void epxa_write16(struct map_info *map, __u16 d, unsigned long adr)
 {
 	__raw_writew(d, map->map_priv_1 + adr);
 	mb();
 }
 
-static void epxa10db_write32(struct map_info *map, __u32 d, unsigned long adr)
+static void epxa_write32(struct map_info *map, __u32 d, unsigned long adr)
 {
 	__raw_writel(d, map->map_priv_1 + adr);
 	mb();
 }
 
-static void epxa10db_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+static void epxa_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
 {
 	memcpy_toio((void *)(map->map_priv_1 + to), from, len);
 }
 
 
 
-static struct map_info epxa10db_map = {
-	name:		"EPXA10DB flash",
+static struct map_info epxa_map = {
+	name:		"EPXA flash",
 	size:		FLASH_SIZE,
 	buswidth:	2,
-	read8:		epxa10db_read8,
-	read16:		epxa10db_read16,
-	read32:		epxa10db_read32,
-	copy_from:	epxa10db_copy_from,
-	write8:		epxa10db_write8,
-	write16:	epxa10db_write16,
-	write32:	epxa10db_write32,
-	copy_to:	epxa10db_copy_to
+	read8:		epxa_read8,
+	read16:		epxa_read16,
+	read32:		epxa_read32,
+	copy_from:	epxa_copy_from,
+	write8:		epxa_write8,
+	write16:	epxa_write16,
+	write32:	epxa_write32,
+	copy_to:	epxa_copy_to
 };
 
 
-static int __init epxa10db_mtd_init(void)
+static int __init epxa_mtd_init(void)
 {
 	int i;
-	printk(KERN_NOTICE "Epxa10db flash device: %x at %x\n", FLASH_SIZE, FLASH_START);
-	epxa10db_map.map_priv_1 = (unsigned long)ioremap(FLASH_START, FLASH_SIZE);
-	if (!epxa10db_map.map_priv_1) {
-		printk("Failed to ioremap Epxa10db flash\n");
+	
+	printk(KERN_NOTICE "%s flash device: %x at %x\n", BOARD_NAME, FLASH_SIZE, FLASH_START);
+	epxa_map.map_priv_1 = (unsigned long)ioremap(FLASH_START, FLASH_SIZE);
+	if (!epxa_map.map_priv_1) {
+		printk("Failed to ioremap %s flash\n",BOARD_NAME);
 		return -EIO;
 	}
 
-	mymtd = do_map_probe("cfi_probe", &epxa10db_map);
+	mymtd = do_map_probe("cfi_probe", &epxa_map);
 	if (!mymtd) {
-		iounmap((void *)epxa10db_map.map_priv_1);
+		iounmap((void *)epxa_map.map_priv_1);
 		return -ENXIO;
 	}
 
 	mymtd->module = THIS_MODULE;
 
 	/* Unlock the flash device. */
-	for (i=0; i<mymtd->numeraseregions;i++){
-		int j;
-		for(j=0;j<mymtd->eraseregions[i].numblocks;j++){
-			mymtd->unlock(mymtd,mymtd->eraseregions[i].offset + j * mymtd->eraseregions[i].erasesize,4);
+	if(mymtd->unlock){
+		for (i=0; i<mymtd->numeraseregions;i++){
+			int j;
+			for(j=0;j<mymtd->eraseregions[i].numblocks;j++){
+				mymtd->unlock(mymtd,mymtd->eraseregions[i].offset + j * mymtd->eraseregions[i].erasesize,mymtd->eraseregions[i].erasesize);
+			}
 		}
 	}
 
@@ -145,7 +153,7 @@
 #endif
 
 	/* No recognised partitioning schemes found - use defaults */
-	nr_parts = epxa10db_default_partitions(mymtd, &parts);
+	nr_parts = epxa_default_partitions(mymtd, &parts);
 	if (nr_parts > 0) {
 		add_mtd_partitions(mymtd, parts, nr_parts);
 		return 0;
@@ -156,7 +164,7 @@
 	return 0;
 }
 
-static void __exit epxa10db_mtd_cleanup(void)
+static void __exit epxa_mtd_cleanup(void)
 {
 	if (mymtd) {
 		if (nr_parts)
@@ -165,9 +173,9 @@
 			del_mtd_device(mymtd);
 		map_destroy(mymtd);
 	}
-	if (epxa10db_map.map_priv_1) {
-		iounmap((void *)epxa10db_map.map_priv_1);
-		epxa10db_map.map_priv_1 = 0;
+	if (epxa_map.map_priv_1) {
+		iounmap((void *)epxa_map.map_priv_1);
+		epxa_map.map_priv_1 = 0;
 	}
 }
 
@@ -181,7 +189,7 @@
  * 0x00400000 - 0x00FFFFFF - Flashdisk
  */
 
-static int __init epxa10db_default_partitions(struct mtd_info *master, struct mtd_partition **pparts)
+static int __init epxa_default_partitions(struct mtd_info *master, struct mtd_partition **pparts)
 {
 	struct mtd_partition *parts;
 	int ret, i;
@@ -189,9 +197,10 @@
 	char *names; 
 	const char *name = "jffs";
 
-	printk("Using default partitions for epxa10db\n");
+	printk("Using default partitions for %s\n",BOARD_NAME);
 	npartitions=1;
 	parts = kmalloc(npartitions*sizeof(*parts)+strlen(name), GFP_KERNEL);
+	memzero(parts,npartitions*sizeof(*parts)+strlen(name));
 	if (!parts) {
 		ret = -ENOMEM;
 		goto out;
@@ -202,18 +211,23 @@
 	names += strlen(name) + 1;
 	strcpy(parts[i].name, name);
 
+#ifdef CONFIG_EPXA10DB
 	parts[i].size = FLASH_SIZE-0x00400000;
 	parts[i].offset = 0x00400000;
-	parts[i].mask_flags = 0;
+#else
+	parts[i].size = FLASH_SIZE-0x00180000;
+	parts[i].offset = 0x00180000;
+#endif
 
  out:
 	*pparts = parts;
 	return npartitions;
 }
 
-module_init(epxa10db_mtd_init);
-module_exit(epxa10db_mtd_cleanup);
+
+module_init(epxa_mtd_init);
+module_exit(epxa_mtd_cleanup);
 
 MODULE_AUTHOR("Clive Davies");
-MODULE_DESCRIPTION("Altera epxa10db mtd flash map");
+MODULE_DESCRIPTION("Altera epxa mtd flash map");
 MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/maps/fortunet.c linux-2.4.21-pre6/drivers/mtd/maps/fortunet.c
--- linux-2.4.20/drivers/mtd/maps/fortunet.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/maps/fortunet.c	2003-03-26 23:49:25.000000000 +0000
@@ -0,0 +1,309 @@
+/* fortunet.c memory map
+ *
+ * $Id: fortunet.c,v 1.2 2002/10/14 12:50:22 rmk Exp $
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+#define MAX_NUM_REGIONS		4
+#define MAX_NUM_PARTITIONS	8
+
+#define DEF_WINDOW_ADDR_PHY	0x00000000
+#define DEF_WINDOW_SIZE		0x00800000		// 8 Mega Bytes
+
+#define MTD_FORTUNET_PK		"MTD FortuNet: "
+
+#define MAX_NAME_SIZE		128
+
+struct map_region
+{
+	int			window_addr_phyical;
+	int			altbuswidth;
+	struct map_info		map_info;
+	struct mtd_info		*mymtd;
+	struct mtd_partition	parts[MAX_NUM_PARTITIONS];
+	char			map_name[MAX_NAME_SIZE];
+	char			parts_name[MAX_NUM_PARTITIONS][MAX_NAME_SIZE];
+};
+
+static struct map_region	map_regions[MAX_NUM_REGIONS];
+static int			map_regions_set[MAX_NUM_REGIONS] = {0,0,0,0};
+static int			map_regions_parts[MAX_NUM_REGIONS] = {0,0,0,0};
+
+
+__u8 fortunet_read8(struct map_info *map, unsigned long ofs)
+{
+	return *(__u8 *)(map->map_priv_1 + ofs);
+}
+
+__u16 fortunet_read16(struct map_info *map, unsigned long ofs)
+{
+	return *(__u16 *)(map->map_priv_1 + ofs);
+}
+
+__u32 fortunet_read32(struct map_info *map, unsigned long ofs)
+{
+	return *(__u32 *)(map->map_priv_1 + ofs);
+}
+
+void fortunet_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	memcpy(to, (void *)(map->map_priv_1 + from), len);
+}
+
+void fortunet_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+	*(__u8 *)(map->map_priv_1 + adr) = d;
+}
+
+void fortunet_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+	*(__u16 *)(map->map_priv_1 + adr) = d;
+}
+
+void fortunet_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+	*(__u32 *)(map->map_priv_1 + adr) = d;
+}
+
+void fortunet_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	memcpy((void *)(map->map_priv_1 + to), from, len);
+}
+
+struct map_info default_map = {
+	size: DEF_WINDOW_SIZE,
+	buswidth: 4,
+	read8: fortunet_read8,
+	read16: fortunet_read16,
+	read32: fortunet_read32,
+	copy_from: fortunet_copy_from,
+	write8: fortunet_write8,
+	write16: fortunet_write16,
+	write32: fortunet_write32,
+	copy_to: fortunet_copy_to
+};
+
+static char * __init get_string_option(char *dest,int dest_size,char *sor)
+{
+	if(!dest_size)
+		return sor;
+	dest_size--;
+	while(*sor)
+	{
+		if(*sor==',')
+		{
+			sor++;
+			break;
+		}
+		else if(*sor=='\"')
+		{
+			sor++;
+			while(*sor)
+			{
+				if(*sor=='\"')
+				{
+					sor++;
+					break;
+				}
+				*dest = *sor;
+				dest++;
+				sor++;
+				dest_size--;
+				if(!dest_size)
+				{
+					*dest = 0;
+					return sor;
+				}
+			}
+		}
+		else
+		{
+			*dest = *sor;
+			dest++;
+			sor++;
+			dest_size--;
+			if(!dest_size)
+			{
+				*dest = 0;
+				return sor;
+			}
+		}
+	}
+	*dest = 0;
+	return sor;
+}
+
+static int __init MTD_New_Region(char *line)
+{
+	char	string[MAX_NAME_SIZE];
+	int	params[6];
+	get_options (get_string_option(string,sizeof(string),line),6,params);
+	if(params[0]<1)
+	{
+		printk(MTD_FORTUNET_PK "Bad paramters for MTD Region "
+			" name,region-number[,base,size,buswidth,altbuswidth]\n");
+		return 1;
+	}
+	if((params[1]<0)||(params[1]>=MAX_NUM_REGIONS))
+	{
+		printk(MTD_FORTUNET_PK "Bad region index of %d only have 0..%u regions\n",
+			params[1],MAX_NUM_REGIONS-1);
+		return 1;
+	}
+	memset(&map_regions[params[1]],0,sizeof(map_regions[params[1]]));
+	memcpy(&map_regions[params[1]].map_info,
+		&default_map,sizeof(map_regions[params[1]].map_info));
+        map_regions_set[params[1]] = 1;
+        map_regions[params[1]].window_addr_phyical = DEF_WINDOW_ADDR_PHY;
+        map_regions[params[1]].altbuswidth = 2;
+        map_regions[params[1]].mymtd = NULL;
+	map_regions[params[1]].map_info.name = map_regions[params[1]].map_name;
+	strcpy(map_regions[params[1]].map_info.name,string);
+	if(params[0]>1)
+	{
+		map_regions[params[1]].window_addr_phyical = params[2];
+	}
+	if(params[0]>2)
+	{
+		map_regions[params[1]].map_info.size = params[3];
+	}
+	if(params[0]>3)
+	{
+		map_regions[params[1]].map_info.buswidth = params[4];
+	}
+	if(params[0]>4)
+	{
+		map_regions[params[1]].altbuswidth = params[5];
+	}
+	return 1;
+}
+
+static int __init MTD_New_Partion(char *line)
+{
+	char	string[MAX_NAME_SIZE];
+	int	params[4];
+	get_options (get_string_option(string,sizeof(string),line),4,params);
+	if(params[0]<3)
+	{
+		printk(MTD_FORTUNET_PK "Bad paramters for MTD Partion "
+			" name,region-number,size,offset\n");
+		return 1;
+	}
+	if((params[1]<0)||(params[1]>=MAX_NUM_REGIONS))
+	{
+		printk(MTD_FORTUNET_PK "Bad region index of %d only have 0..%u regions\n",
+			params[1],MAX_NUM_REGIONS-1);
+		return 1;
+	}
+	if(map_regions_parts[params[1]]>=MAX_NUM_PARTITIONS)
+	{
+		printk(MTD_FORTUNET_PK "Out of space for partion in this region\n");
+		return 1;
+	}
+	map_regions[params[1]].parts[map_regions_parts[params[1]]].name =
+		map_regions[params[1]].	parts_name[map_regions_parts[params[1]]];
+	strcpy(map_regions[params[1]].parts[map_regions_parts[params[1]]].name,string);
+	map_regions[params[1]].parts[map_regions_parts[params[1]]].size =
+		params[2];
+	map_regions[params[1]].parts[map_regions_parts[params[1]]].offset =
+		params[3];
+	map_regions[params[1]].parts[map_regions_parts[params[1]]].mask_flags = 0;
+	map_regions_parts[params[1]]++;
+	return 1;
+}
+
+__setup("MTD_Region=", MTD_New_Region);
+__setup("MTD_Partion=", MTD_New_Partion);
+
+int __init init_fortunet(void)
+{
+	int	ix,iy;
+	for(iy=ix=0;ix<MAX_NUM_REGIONS;ix++)
+	{
+		if(map_regions_parts[ix]&&(!map_regions_set[ix]))
+		{
+			printk(MTD_FORTUNET_PK "Region %d is not setup (Seting to default)\n",
+				ix);
+			memset(&map_regions[ix],0,sizeof(map_regions[ix]));
+			memcpy(&map_regions[ix].map_info,&default_map,
+				sizeof(map_regions[ix].map_info));
+			map_regions_set[ix] = 1;
+			map_regions[ix].window_addr_phyical = DEF_WINDOW_ADDR_PHY;
+			map_regions[ix].altbuswidth = 2;
+			map_regions[ix].mymtd = NULL;
+			map_regions[ix].map_info.name = map_regions[ix].map_name;
+			strcpy(map_regions[ix].map_info.name,"FORTUNET");
+		}
+		if(map_regions_set[ix])
+		{
+			iy++;
+			printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash device at phyicaly "
+				" address %x size %x\n",
+				map_regions[ix].map_info.name,
+				map_regions[ix].window_addr_phyical,
+				map_regions[ix].map_info.size);
+			map_regions[ix].map_info.map_priv_1 =
+				(int)ioremap_nocache(
+				map_regions[ix].window_addr_phyical,
+				map_regions[ix].map_info.size);
+			if(!map_regions[ix].map_info.map_priv_1)
+			{
+				printk(MTD_FORTUNET_PK "%s flash failed to ioremap!\n",
+					map_regions[ix].map_info.name);
+				return -ENXIO;
+			}
+			printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash is veritualy at: %x\n",
+				map_regions[ix].map_info.name,
+				map_regions[ix].map_info.map_priv_1);
+			map_regions[ix].mymtd = do_map_probe("cfi_probe",
+				&map_regions[ix].map_info);
+			if((!map_regions[ix].mymtd)&&(
+				map_regions[ix].altbuswidth!=map_regions[ix].map_info.buswidth))
+			{
+				printk(KERN_NOTICE MTD_FORTUNET_PK "Trying alternet buswidth "
+					"for %s flash.\n",
+					map_regions[ix].map_info.name);
+				map_regions[ix].map_info.buswidth =
+					map_regions[ix].altbuswidth;
+				map_regions[ix].mymtd = do_map_probe("cfi_probe",
+					&map_regions[ix].map_info);
+			}
+			map_regions[ix].mymtd->module = THIS_MODULE;
+			add_mtd_partitions(map_regions[ix].mymtd,
+				map_regions[ix].parts,map_regions_parts[ix]);
+		}
+	}
+	if(iy)
+		return 0;
+	return -ENXIO;
+}
+
+static void __exit cleanup_fortunet(void)
+{
+	int	ix;
+	for(ix=0;ix<MAX_NUM_REGIONS;ix++)
+	{
+		if(map_regions_set[ix])
+		{
+			if( map_regions[ix].mymtd )
+			{
+				del_mtd_partitions( map_regions[ix].mymtd );
+				map_destroy( map_regions[ix].mymtd );
+			}
+			iounmap((void *)map_regions[ix].map_info.map_priv_1);
+		}
+	}
+}
+
+module_init(init_fortunet);
+module_exit(cleanup_fortunet);
+
+MODULE_AUTHOR("FortuNet, Inc.");
+MODULE_DESCRIPTION("MTD map driver for FortuNet boards");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/maps/ich2rom.c linux-2.4.21-pre6/drivers/mtd/maps/ich2rom.c
--- linux-2.4.20/drivers/mtd/maps/ich2rom.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/maps/ich2rom.c	2003-03-26 23:49:31.000000000 +0000
@@ -2,7 +2,7 @@
  * ich2rom.c
  *
  * Normal mappings of chips in physical memory
- * $Id: ich2rom.c,v 1.1 2002/01/10 22:59:13 eric Exp $
+ * $Id: ich2rom.c,v 1.2 2002/10/18 22:45:48 eric Exp $
  */
 
 #include <linux/module.h>
@@ -261,6 +261,9 @@
 static struct pci_device_id ich2rom_pci_tbl[] __devinitdata = {
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, 
 	  PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, 
+	  PCI_ANY_ID, PCI_ANY_ID, },
+	{ 0, },
 };
 
 MODULE_DEVICE_TABLE(pci, ich2rom_pci_tbl);
@@ -278,7 +281,14 @@
 int __init init_ich2rom(void)
 {
 	struct pci_dev *pdev;
-	pdev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, 0);
+	struct pci_device_id *id;
+	pdev = 0;
+	for(id = ich2rom_pci_tbl; id->vendor; id++) {
+		pdev = pci_find_device(id->vendor, id->device, 0);
+		if (pdev) {
+			break;
+		}
+	}
 	if (pdev) {
 		mydev = pdev;
 		return ich2rom_init_one(pdev, &ich2rom_pci_tbl[0]);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/maps/impa7.c linux-2.4.21-pre6/drivers/mtd/maps/impa7.c
--- linux-2.4.20/drivers/mtd/maps/impa7.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/maps/impa7.c	2003-03-26 23:49:55.000000000 +0000
@@ -0,0 +1,234 @@
+/*
+ * $Id: impa7.c,v 1.2 2002/09/05 05:11:24 acurtis Exp $
+ *
+ * Handle mapping of the NOR flash on implementa A7 boards
+ *
+ * Copyright 2002 SYSGO Real-Time Solutions GmbH
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/config.h>
+
+#ifdef CONFIG_MTD_PARTITIONS
+#include <linux/mtd/partitions.h>
+#endif
+
+#define WINDOW_ADDR0 0x00000000      /* physical properties of flash */
+#define WINDOW_SIZE0 0x00800000
+#define WINDOW_ADDR1 0x10000000      /* physical properties of flash */
+#define WINDOW_SIZE1 0x00800000
+#define NUM_FLASHBANKS 2
+#define BUSWIDTH     4
+
+/* can be { "cfi_probe", "jedec_probe", "map_rom", 0 }; */
+#define PROBETYPES { "jedec_probe", 0 }
+
+#define MSG_PREFIX "impA7:"   /* prefix for our printk()'s */
+#define MTDID      "impa7-%d"  /* for mtdparts= partitioning */
+
+static struct mtd_info *impa7_mtd[NUM_FLASHBANKS] = { 0 };
+
+__u8 impa7_read8(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readb(map->map_priv_1 + ofs);
+}
+
+__u16 impa7_read16(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readw(map->map_priv_1 + ofs);
+}
+
+__u32 impa7_read32(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readl(map->map_priv_1 + ofs);
+}
+
+void impa7_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	memcpy_fromio(to, map->map_priv_1 + from, len);
+}
+
+void impa7_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+	__raw_writeb(d, map->map_priv_1 + adr);
+	mb();
+}
+
+void impa7_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+	__raw_writew(d, map->map_priv_1 + adr);
+	mb();
+}
+
+void impa7_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+	__raw_writel(d, map->map_priv_1 + adr);
+	mb();
+}
+
+void impa7_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	memcpy_toio(map->map_priv_1 + to, from, len);
+}
+
+static struct map_info impa7_map[NUM_FLASHBANKS] = {
+	{
+	name: "impA7 NOR Flash Bank #0",
+	size: WINDOW_SIZE0,
+	buswidth: BUSWIDTH,
+	read8: impa7_read8,
+	read16: impa7_read16,
+	read32: impa7_read32,
+	copy_from: impa7_copy_from,
+	write8: impa7_write8,
+	write16: impa7_write16,
+	write32: impa7_write32,
+	copy_to: impa7_copy_to
+	},
+	{
+	name: "impA7 NOR Flash Bank #1",
+	size: WINDOW_SIZE1,
+	buswidth: BUSWIDTH,
+	read8: impa7_read8,
+	read16: impa7_read16,
+	read32: impa7_read32,
+	copy_from: impa7_copy_from,
+	write8: impa7_write8,
+	write16: impa7_write16,
+	write32: impa7_write32,
+	copy_to: impa7_copy_to
+	},
+};
+
+#ifdef CONFIG_MTD_PARTITIONS
+
+/*
+ * MTD partitioning stuff 
+ */
+static struct mtd_partition static_partitions[] =
+{
+    {
+	name: "FileSystem",
+	  size: 0x800000,
+	  offset: 0x00000000
+    },
+};
+
+#define NB_OF(x) (sizeof (x) / sizeof (x[0]))
+
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+int parse_cmdline_partitions(struct mtd_info *master, 
+			     struct mtd_partition **pparts,
+			     const char *mtd_id);
+#endif
+
+#endif
+
+static int                   mtd_parts_nb = 0;
+static struct mtd_partition *mtd_parts    = 0;
+
+int __init init_impa7(void)
+{
+	static const char *rom_probe_types[] = PROBETYPES;
+	const char **type;
+	const char *part_type = 0;
+	int i;
+	static struct { u_long addr; u_long size; } pt[NUM_FLASHBANKS] = {
+	  { WINDOW_ADDR0, WINDOW_SIZE0 },
+	  { WINDOW_ADDR1, WINDOW_SIZE1 },
+        };
+	char mtdid[10];
+	int devicesfound = 0;
+
+	for(i=0; i<NUM_FLASHBANKS; i++)
+	{
+		printk(KERN_NOTICE MSG_PREFIX "probing 0x%08lx at 0x%08lx\n",
+		       pt[i].size, pt[i].addr);
+		impa7_map[i].map_priv_1 = (unsigned long)
+		  ioremap(pt[i].addr, pt[i].size);
+
+		if (!impa7_map[i].map_priv_1) {
+			printk(MSG_PREFIX "failed to ioremap\n");
+			return -EIO;
+		}
+
+		impa7_mtd[i] = 0;
+		type = rom_probe_types;
+		for(; !impa7_mtd[i] && *type; type++) {
+			impa7_mtd[i] = do_map_probe(*type, &impa7_map[i]);
+		}
+
+		if (impa7_mtd[i]) 
+		{
+			impa7_mtd[i]->module = THIS_MODULE;
+			add_mtd_device(impa7_mtd[i]);
+			devicesfound++;
+#ifdef CONFIG_MTD_PARTITIONS
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+			sprintf(mtdid, MTDID, i);
+			mtd_parts_nb = parse_cmdline_partitions(impa7_mtd[i], 
+								&mtd_parts, 
+								mtdid);
+			if (mtd_parts_nb > 0)
+			  part_type = "command line";
+#endif
+			if (mtd_parts_nb <= 0)
+			{
+				mtd_parts = static_partitions;
+				mtd_parts_nb = NB_OF(static_partitions);
+				part_type = "static";
+			}
+			if (mtd_parts_nb <= 0)
+			{
+				printk(KERN_NOTICE MSG_PREFIX 
+				       "no partition info available\n");
+			}
+			else
+			{
+				printk(KERN_NOTICE MSG_PREFIX
+				       "using %s partition definition\n", 
+				       part_type);
+				add_mtd_partitions(impa7_mtd[i], 
+						   mtd_parts, mtd_parts_nb);
+			}
+#endif
+		}
+		else 
+		  iounmap((void *)impa7_map[i].map_priv_1);
+	}
+	return devicesfound == 0 ? -ENXIO : 0;
+}
+
+static void __exit cleanup_impa7(void)
+{
+	int i;
+	for (i=0; i<NUM_FLASHBANKS; i++) 
+	{
+		if (impa7_mtd[i]) 
+		{
+			del_mtd_device(impa7_mtd[i]);
+			map_destroy(impa7_mtd[i]);
+		}
+		if (impa7_map[i].map_priv_1)
+		{
+			iounmap((void *)impa7_map[i].map_priv_1);
+			impa7_map[i].map_priv_1 = 0;
+		}
+	}
+}
+
+module_init(init_impa7);
+module_exit(cleanup_impa7);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Pavel Bartusek <pba@sysgo.de>");
+MODULE_DESCRIPTION("MTD map driver for implementa impA7");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/maps/lasat.c linux-2.4.21-pre6/drivers/mtd/maps/lasat.c
--- linux-2.4.20/drivers/mtd/maps/lasat.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/maps/lasat.c	2003-03-26 23:49:10.000000000 +0000
@@ -0,0 +1,140 @@
+/*
+ * Flash device on lasat 100 and 200 boards
+ *
+ * Presumably (C) 2002 Brian Murphy <brian@murphy.dk> or whoever he
+ * works for.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * $Id: lasat.c,v 1.1 2003/01/24 14:26:38 dwmw2 Exp $
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/config.h>
+#include <asm/lasat/lasat.h>
+#include <asm/lasat/lasat_mtd.h>
+
+static struct mtd_info *mymtd;
+
+static __u8 sp_read8(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readb(map->map_priv_1 + ofs);
+}
+
+static __u16 sp_read16(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readw(map->map_priv_1 + ofs);
+}
+
+static __u32 sp_read32(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readl(map->map_priv_1 + ofs);
+}
+
+static void sp_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	memcpy_fromio(to, map->map_priv_1 + from, len);
+}
+
+static void sp_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+	__raw_writeb(d, map->map_priv_1 + adr);
+	mb();
+}
+
+static void sp_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+	__raw_writew(d, map->map_priv_1 + adr);
+	mb();
+}
+
+static void sp_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+	__raw_writel(d, map->map_priv_1 + adr);
+	mb();
+}
+
+static void sp_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	memcpy_toio(map->map_priv_1 + to, from, len);
+}
+
+static struct map_info sp_map = {
+	.name = "SP flash",
+	.buswidth = 4,
+	.read8 = sp_read8,
+	.read16 = sp_read16,
+	.read32 = sp_read32,
+	.copy_from = sp_copy_from,
+	.write8 = sp_write8,
+	.write16 = sp_write16,
+	.write32 = sp_write32,
+	.copy_to = sp_copy_to
+};
+
+static struct mtd_partition partition_info[LASAT_MTD_LAST];
+static char *lasat_mtd_partnames[] = {"Bootloader", "Service", "Normal", "Filesystem", "Config"};
+
+static int __init init_sp(void)
+{
+	int i;
+	/* this does not play well with the old flash code which 
+	 * protects and uprotects the flash when necessary */
+       	printk(KERN_NOTICE "Unprotecting flash\n");
+	*lasat_misc->flash_wp_reg |= 1 << lasat_misc->flash_wp_bit;
+
+	sp_map.map_priv_1 = lasat_flash_partition_start(LASAT_MTD_BOOTLOADER);
+	sp_map.size = lasat_board_info.li_flash_size;
+
+       	printk(KERN_NOTICE "sp flash device: %lx at %lx\n", 
+			sp_map.size, sp_map.map_priv_1);
+
+	for (i=0; i < LASAT_MTD_LAST; i++)
+		partition_info[i].name = lasat_mtd_partnames[i];
+
+	mymtd = do_map_probe("cfi_probe", &sp_map);
+	if (mymtd) {
+		u32 size, offset = 0;
+
+		mymtd->module = THIS_MODULE;
+
+		for (i=0; i < LASAT_MTD_LAST; i++) {
+			size = lasat_flash_partition_size(i);
+			partition_info[i].size = size;
+			partition_info[i].offset = offset;
+			offset += size;
+		}
+
+		add_mtd_partitions( mymtd, partition_info, LASAT_MTD_LAST );
+		return 0;
+	}
+
+	return -ENXIO;
+}
+
+static void __exit cleanup_sp(void)
+{
+	if (mymtd) {
+		del_mtd_partitions(mymtd);
+		map_destroy(mymtd);
+	}
+	if (sp_map.map_priv_1) {
+		sp_map.map_priv_1 = 0;
+	}
+}
+
+module_init(init_sp);
+module_exit(cleanup_sp);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Brian Murphy <brian@murphy.dk>");
+MODULE_DESCRIPTION("Lasat Safepipe/Masquerade MTD map driver");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/maps/nettel.c linux-2.4.21-pre6/drivers/mtd/maps/nettel.c
--- linux-2.4.20/drivers/mtd/maps/nettel.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/maps/nettel.c	2003-03-26 23:48:57.000000000 +0000
@@ -0,0 +1,551 @@
+/****************************************************************************/
+
+/*
+ *      nettel.c -- mappings for NETtel/SecureEdge/SnapGear (x86) boards.
+ *
+ *      (C) Copyright 2000-2001, Greg Ungerer (gerg@snapgear.com)
+ *      (C) Copyright 2001-2002, SnapGear (www.snapgear.com)
+ *
+ *	$Id: nettel.c,v 1.1 2002/08/08 06:30:13 gerg Exp $
+ */
+
+/****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/cfi.h>
+#include <linux/reboot.h>
+#include <asm/io.h>
+
+/****************************************************************************/
+
+#define INTEL_BUSWIDTH		1
+#define AMD_WINDOW_MAXSIZE	0x00200000
+#define AMD_BUSWIDTH	 	1
+
+/*
+ *	PAR masks and shifts, assuming 64K pages.
+ */
+#define SC520_PAR_ADDR_MASK	0x00003fff
+#define SC520_PAR_ADDR_SHIFT	16
+#define SC520_PAR_TO_ADDR(par) \
+	(((par)&SC520_PAR_ADDR_MASK) << SC520_PAR_ADDR_SHIFT)
+
+#define SC520_PAR_SIZE_MASK	0x01ffc000
+#define SC520_PAR_SIZE_SHIFT	2
+#define SC520_PAR_TO_SIZE(par) \
+	((((par)&SC520_PAR_SIZE_MASK) << SC520_PAR_SIZE_SHIFT) + (64*1024))
+
+#define SC520_PAR(cs, addr, size) \
+	((cs) | \
+	((((size)-(64*1024)) >> SC520_PAR_SIZE_SHIFT) & SC520_PAR_SIZE_MASK) | \
+	(((addr) >> SC520_PAR_ADDR_SHIFT) & SC520_PAR_ADDR_MASK))
+
+#define SC520_PAR_BOOTCS	0x8a000000
+#define	SC520_PAR_ROMCS1	0xaa000000
+#define SC520_PAR_ROMCS2	0xca000000	/* Cache disabled, 64K page */
+
+static void *nettel_mmcrp = NULL;
+
+#ifdef CONFIG_MTD_CFI_INTELEXT
+static struct mtd_info *intel_mtd;
+#endif
+static struct mtd_info *amd_mtd;
+
+/****************************************************************************/
+
+static __u8 nettel_read8(struct map_info *map, unsigned long ofs)
+{
+	return(readb(map->map_priv_1 + ofs));
+}
+
+static __u16 nettel_read16(struct map_info *map, unsigned long ofs)
+{
+	return(readw(map->map_priv_1 + ofs));
+}
+
+static __u32 nettel_read32(struct map_info *map, unsigned long ofs)
+{
+	return(readl(map->map_priv_1 + ofs));
+}
+
+static void nettel_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	memcpy_fromio(to, map->map_priv_1 + from, len);
+}
+
+static void nettel_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+	writeb(d, map->map_priv_1 + adr);
+}
+
+static void nettel_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+	writew(d, map->map_priv_1 + adr);
+}
+
+static void nettel_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+	writel(d, map->map_priv_1 + adr);
+}
+
+static void nettel_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	memcpy_toio(map->map_priv_1 + to, from, len);
+}
+
+/****************************************************************************/
+
+#ifdef CONFIG_MTD_CFI_INTELEXT
+static struct map_info nettel_intel_map = {
+	name: "SnapGear Intel",
+	size: 0,
+	buswidth: INTEL_BUSWIDTH,
+	read8: nettel_read8,
+	read16: nettel_read16,
+	read32: nettel_read32,
+	copy_from: nettel_copy_from,
+	write8: nettel_write8,
+	write16: nettel_write16,
+	write32: nettel_write32,
+	copy_to: nettel_copy_to
+};
+
+static struct mtd_partition nettel_intel_partitions[] = {
+	{
+		name: "SnapGear kernel",
+		offset: 0,
+		size: 0x000e0000
+	},
+	{
+		name: "SnapGear filesystem",
+		offset: 0x00100000,
+	},
+	{
+		name: "SnapGear config",
+		offset: 0x000e0000,
+		size: 0x00020000
+	},
+	{
+		name: "SnapGear Intel",
+		offset: 0
+	},
+	{
+		name: "SnapGear BIOS Config",
+		offset: 0x007e0000,
+		size: 0x00020000
+	},
+	{
+		name: "SnapGear BIOS",
+		offset: 0x007e0000,
+		size: 0x00020000
+	},
+};
+#endif
+
+static struct map_info nettel_amd_map = {
+	name: "SnapGear AMD",
+	size: AMD_WINDOW_MAXSIZE,
+	buswidth: AMD_BUSWIDTH,
+	read8: nettel_read8,
+	read16: nettel_read16,
+	read32: nettel_read32,
+	copy_from: nettel_copy_from,
+	write8: nettel_write8,
+	write16: nettel_write16,
+	write32: nettel_write32,
+	copy_to: nettel_copy_to
+};
+
+static struct mtd_partition nettel_amd_partitions[] = {
+	{
+		name: "SnapGear BIOS config",
+		offset: 0x000e0000,
+		size: 0x00010000
+	},
+	{
+		name: "SnapGear BIOS",
+		offset: 0x000f0000,
+		size: 0x00010000
+	},
+	{
+		name: "SnapGear AMD",
+		offset: 0
+	},
+	{
+		name: "SnapGear high BIOS",
+		offset: 0x001f0000,
+		size: 0x00010000
+	}
+};
+
+#define NUM_AMD_PARTITIONS \
+	(sizeof(nettel_amd_partitions)/sizeof(nettel_amd_partitions[0]))
+
+/****************************************************************************/
+
+#ifdef CONFIG_MTD_CFI_INTELEXT
+
+/*
+ *	Set the Intel flash back to read mode since some old boot
+ *	loaders don't.
+ */
+static int nettel_reboot_notifier(struct notifier_block *nb, unsigned long val, void *v)
+{
+	struct cfi_private *cfi = nettel_intel_map.fldrv_priv;
+	unsigned long b;
+	
+	/* Make sure all FLASH chips are put back into read mode */
+	for (b = 0; (b < nettel_intel_partitions[3].size); b += 0x100000) {
+		cfi_send_gen_cmd(0xff, 0x55, b, &nettel_intel_map, cfi,
+			cfi->device_type, NULL);
+	}
+	return(NOTIFY_OK);
+}
+
+static struct notifier_block nettel_notifier_block = {
+	nettel_reboot_notifier, NULL, 0
+};
+
+/*
+ *	Erase the configuration file system.
+ *	Used to support the software reset button.
+ */
+static void nettel_erasecallback(struct erase_info *done)
+{
+	wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv;
+	wake_up(wait_q);
+}
+
+static struct erase_info nettel_erase;
+
+int nettel_eraseconfig(void)
+{
+	struct mtd_info *mtd;
+	DECLARE_WAITQUEUE(wait, current);
+	wait_queue_head_t wait_q;
+	int ret;
+
+	init_waitqueue_head(&wait_q);
+	mtd = get_mtd_device(NULL, 2);
+	if (mtd) {
+		nettel_erase.mtd = mtd;
+		nettel_erase.callback = nettel_erasecallback;
+		nettel_erase.callback = 0;
+		nettel_erase.addr = 0;
+		nettel_erase.len = mtd->size;
+		nettel_erase.priv = (u_long) &wait_q;
+		nettel_erase.priv = 0;
+
+		set_current_state(TASK_INTERRUPTIBLE);
+		add_wait_queue(&wait_q, &wait);
+
+		ret = MTD_ERASE(mtd, &nettel_erase);
+		if (ret) {
+			set_current_state(TASK_RUNNING);
+			remove_wait_queue(&wait_q, &wait);
+			put_mtd_device(mtd);
+			return(ret);
+		}
+
+		schedule();  /* Wait for erase to finish. */
+		remove_wait_queue(&wait_q, &wait);
+		
+		put_mtd_device(mtd);
+	}
+
+	return(0);
+}
+
+#else
+
+int nettel_eraseconfig(void)
+{
+	return(0);
+}
+
+#endif
+
+/****************************************************************************/
+
+int __init nettel_init(void)
+{
+	volatile unsigned long *amdpar;
+	unsigned long amdaddr, maxsize;
+	int num_amd_partitions=0;
+#ifdef CONFIG_MTD_CFI_INTELEXT
+	volatile unsigned long *intel0par, *intel1par;
+	unsigned long orig_bootcspar, orig_romcs1par;
+	unsigned long intel0addr, intel0size;
+	unsigned long intel1addr, intel1size;
+	int intelboot, intel0cs, intel1cs;
+	int num_intel_partitions;
+#endif
+	int rc = 0;
+
+	nettel_mmcrp = (void *) ioremap_nocache(0xfffef000, 4096);
+	if (nettel_mmcrp == NULL) {
+		printk("SNAPGEAR: failed to disable MMCR cache??\n");
+		return(-EIO);
+	}
+
+	/* Set CPU clock to be 33.000MHz */
+	*((unsigned char *) (nettel_mmcrp + 0xc64)) = 0x01;
+
+	amdpar = (volatile unsigned long *) (nettel_mmcrp + 0xc4);
+
+#ifdef CONFIG_MTD_CFI_INTELEXT
+	intelboot = 0;
+	intel0cs = SC520_PAR_ROMCS1;
+	intel0par = (volatile unsigned long *) (nettel_mmcrp + 0xc0);
+	intel1cs = SC520_PAR_ROMCS2;
+	intel1par = (volatile unsigned long *) (nettel_mmcrp + 0xbc);
+
+	/*
+	 *	Save the CS settings then ensure ROMCS1 and ROMCS2 are off,
+	 *	otherwise they might clash with where we try to map BOOTCS.
+	 */
+	orig_bootcspar = *amdpar;
+	orig_romcs1par = *intel0par;
+	*intel0par = 0;
+	*intel1par = 0;
+#endif
+
+	/*
+	 *	The first thing to do is determine if we have a separate
+	 *	boot FLASH device. Typically this is a small (1 to 2MB)
+	 *	AMD FLASH part. It seems that device size is about the
+	 *	only way to tell if this is the case...
+	 */
+	amdaddr = 0x20000000;
+	maxsize = AMD_WINDOW_MAXSIZE;
+
+	*amdpar = SC520_PAR(SC520_PAR_BOOTCS, amdaddr, maxsize);
+	__asm__ ("wbinvd");
+
+	nettel_amd_map.map_priv_1 = (unsigned long)
+		ioremap_nocache(amdaddr, maxsize);
+	if (!nettel_amd_map.map_priv_1) {
+		printk("SNAPGEAR: failed to ioremap() BOOTCS\n");
+		return(-EIO);
+	}
+
+	if ((amd_mtd = do_map_probe("jedec_probe", &nettel_amd_map))) {
+		printk(KERN_NOTICE "SNAPGEAR: AMD flash device size = %dK\n",
+			amd_mtd->size>>10);
+
+		amd_mtd->module = THIS_MODULE;
+
+		/* The high BIOS partition is only present for 2MB units */
+		num_amd_partitions = NUM_AMD_PARTITIONS;
+		if (amd_mtd->size < AMD_WINDOW_MAXSIZE)
+			num_amd_partitions--;
+		/* Don't add the partition until after the primary INTEL's */
+
+#ifdef CONFIG_MTD_CFI_INTELEXT
+		/*
+		 *	Map the Intel flash into memory after the AMD
+		 *	It has to start on a multiple of maxsize.
+		 */
+		maxsize = SC520_PAR_TO_SIZE(orig_romcs1par);
+		if (maxsize < (32 * 1024 * 1024))
+			maxsize = (32 * 1024 * 1024);
+		intel0addr = amdaddr + maxsize;
+#endif
+	} else {
+#ifdef CONFIG_MTD_CFI_INTELEXT
+		/* INTEL boot FLASH */
+		intelboot++;
+
+		if (!orig_romcs1par) {
+			intel0cs = SC520_PAR_BOOTCS;
+			intel0par = (volatile unsigned long *)
+				(nettel_mmcrp + 0xc4);
+			intel1cs = SC520_PAR_ROMCS1;
+			intel1par = (volatile unsigned long *)
+				(nettel_mmcrp + 0xc0);
+
+			intel0addr = SC520_PAR_TO_ADDR(orig_bootcspar);
+			maxsize = SC520_PAR_TO_SIZE(orig_bootcspar);
+		} else {
+			/* Kernel base is on ROMCS1, not BOOTCS */
+			intel0cs = SC520_PAR_ROMCS1;
+			intel0par = (volatile unsigned long *)
+				(nettel_mmcrp + 0xc0);
+			intel1cs = SC520_PAR_BOOTCS;
+			intel1par = (volatile unsigned long *)
+				(nettel_mmcrp + 0xc4);
+
+			intel0addr = SC520_PAR_TO_ADDR(orig_romcs1par);
+			maxsize = SC520_PAR_TO_SIZE(orig_romcs1par);
+		}
+
+		/* Destroy useless AMD MTD mapping */
+		amd_mtd = NULL;
+		iounmap((void *) nettel_amd_map.map_priv_1);
+		nettel_amd_map.map_priv_1 = (unsigned long) NULL;
+#else
+		/* Only AMD flash supported */
+		return(-ENXIO);
+#endif
+	}
+
+#ifdef CONFIG_MTD_CFI_INTELEXT
+	/*
+	 *	We have determined the INTEL FLASH configuration, so lets
+	 *	go ahead and probe for them now.
+	 */
+
+	/* Set PAR to the maximum size */
+	if (maxsize < (32 * 1024 * 1024))
+		maxsize = (32 * 1024 * 1024);
+	*intel0par = SC520_PAR(intel0cs, intel0addr, maxsize);
+
+	/* Turn other PAR off so the first probe doesn't find it */
+	*intel1par = 0;
+
+	/* Probe for the the size of the first Intel flash */
+	nettel_intel_map.size = maxsize;
+	nettel_intel_map.map_priv_1 = (unsigned long)
+		ioremap_nocache(intel0addr, maxsize);
+	if (!nettel_intel_map.map_priv_1) {
+		printk("SNAPGEAR: failed to ioremap() ROMCS1\n");
+		return(-EIO);
+	}
+
+	intel_mtd = do_map_probe("cfi_probe", &nettel_intel_map);
+	if (! intel_mtd) {
+		iounmap((void *) nettel_intel_map.map_priv_1);
+		return(-ENXIO);
+	}
+
+	/* Set PAR to the detected size */
+	intel0size = intel_mtd->size;
+	*intel0par = SC520_PAR(intel0cs, intel0addr, intel0size);
+
+	/*
+	 *	Map second Intel FLASH right after first. Set its size to the
+	 *	same maxsize used for the first Intel FLASH.
+	 */
+	intel1addr = intel0addr + intel0size;
+	*intel1par = SC520_PAR(intel1cs, intel1addr, maxsize);
+	__asm__ ("wbinvd");
+
+	maxsize += intel0size;
+
+	/* Delete the old map and probe again to do both chips */
+	map_destroy(intel_mtd);
+	intel_mtd = NULL;
+	iounmap((void *) nettel_intel_map.map_priv_1);
+
+	nettel_intel_map.size = maxsize;
+	nettel_intel_map.map_priv_1 = (unsigned long)
+		ioremap_nocache(intel0addr, maxsize);
+	if (!nettel_intel_map.map_priv_1) {
+		printk("SNAPGEAR: failed to ioremap() ROMCS1/2\n");
+		return(-EIO);
+	}
+
+	intel_mtd = do_map_probe("cfi_probe", &nettel_intel_map);
+	if (! intel_mtd) {
+		iounmap((void *) nettel_intel_map.map_priv_1);
+		return(-ENXIO);
+	}
+
+	intel1size = intel_mtd->size - intel0size;
+	if (intel1size > 0) {
+		*intel1par = SC520_PAR(intel1cs, intel1addr, intel1size);
+		__asm__ ("wbinvd");
+	} else {
+		*intel1par = 0;
+	}
+
+	printk(KERN_NOTICE "SNAPGEAR: Intel flash device size = %dK\n",
+		(intel_mtd->size >> 10));
+
+	intel_mtd->module = THIS_MODULE;
+
+#ifndef CONFIG_BLK_DEV_INITRD
+	ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, 1);
+#endif
+
+	num_intel_partitions = sizeof(nettel_intel_partitions) /
+		sizeof(nettel_intel_partitions[0]);
+
+	if (intelboot) {
+		/*
+		 *	Adjust offset and size of last boot partition.
+		 *	Must allow for BIOS region at end of FLASH.
+		 */
+		nettel_intel_partitions[1].size = (intel0size + intel1size) -
+			(1024*1024 + intel_mtd->erasesize);
+		nettel_intel_partitions[3].size = intel0size + intel1size;
+		nettel_intel_partitions[4].offset = 
+			(intel0size + intel1size) - intel_mtd->erasesize;
+		nettel_intel_partitions[4].size = intel_mtd->erasesize;
+		nettel_intel_partitions[5].offset =
+			nettel_intel_partitions[4].offset;
+		nettel_intel_partitions[5].size =
+			nettel_intel_partitions[4].size;
+	} else {
+		/* No BIOS regions when AMD boot */
+		num_intel_partitions -= 2;
+	}
+	rc = add_mtd_partitions(intel_mtd, nettel_intel_partitions,
+		num_intel_partitions);
+#endif
+
+	if (amd_mtd) {
+		rc = add_mtd_partitions(amd_mtd, nettel_amd_partitions,
+			num_amd_partitions);
+	}
+
+#ifdef CONFIG_MTD_CFI_INTELEXT
+	register_reboot_notifier(&nettel_notifier_block);
+#endif
+
+	return(rc);
+}
+
+/****************************************************************************/
+
+void __exit nettel_cleanup(void)
+{
+#ifdef CONFIG_MTD_CFI_INTELEXT
+	unregister_reboot_notifier(&nettel_notifier_block);
+#endif
+	if (amd_mtd) {
+		del_mtd_partitions(amd_mtd);
+		map_destroy(amd_mtd);
+	}
+	if (nettel_amd_map.map_priv_1) {
+		iounmap((void *)nettel_amd_map.map_priv_1);
+		nettel_amd_map.map_priv_1 = 0;
+	}
+#ifdef CONFIG_MTD_CFI_INTELEXT
+	if (intel_mtd) {
+		del_mtd_partitions(intel_mtd);
+		map_destroy(intel_mtd);
+	}
+	if (nettel_intel_map.map_priv_1) {
+		iounmap((void *)nettel_intel_map.map_priv_1);
+		nettel_intel_map.map_priv_1 = 0;
+	}
+#endif
+}
+
+/****************************************************************************/
+
+module_init(nettel_init);
+module_exit(nettel_cleanup);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com>");
+MODULE_DESCRIPTION("SnapGear/SecureEdge FLASH support");
+
+/****************************************************************************/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/maps/octagon-5066.c linux-2.4.21-pre6/drivers/mtd/maps/octagon-5066.c
--- linux-2.4.20/drivers/mtd/maps/octagon-5066.c	2001-10-04 22:14:59.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/maps/octagon-5066.c	2003-03-26 23:49:09.000000000 +0000
@@ -1,4 +1,4 @@
-// $Id: octagon-5066.c,v 1.19 2001/10/02 15:05:14 dwmw2 Exp $
+// $Id: octagon-5066.c,v 1.20 2003/01/07 17:21:55 dwmw2 Exp $
 /* ######################################################################
 
    Octagon 5066 MTD Driver. 
@@ -223,33 +223,32 @@
 		}
 	}
 	iounmap((void *)iomapadr);
-	release_region(PAGE_IO,1);
+	release_region(PAGE_IO, 1);
 }
 
 int __init init_oct5066(void)
 {
 	int i;
-	
+	int ret = 0;
+
 	// Do an autoprobe sequence
-	if (check_region(PAGE_IO,1) != 0)
-		{
-			printk("5066: Page Register in Use\n");
-			return -EAGAIN;
-		}
+	if (!request_region(PAGE_IO,1,"Octagon SSD")) {
+		printk(KERN_NOTICE "5066: Page Register in Use\n");
+		return -EAGAIN;
+	}
 	iomapadr = (unsigned long)ioremap(WINDOW_START, WINDOW_LENGTH);
 	if (!iomapadr) {
-		printk("Failed to ioremap memory region\n");
-		return -EIO;
+		printk(KERN_NOTICE "Failed to ioremap memory region\n");
+		ret = -EIO;
+		goto out_rel;
 	}
-	if (OctProbe() != 0)
-		{
-			printk("5066: Octagon Probe Failed, is this an Octagon 5066 SBC?\n");
-			iounmap((void *)iomapadr);
-			return -EAGAIN;
-		}
-	
-	request_region(PAGE_IO,1,"Octagon SSD");
-	
+	if (OctProbe() != 0) {
+		printk(KERN_NOTICE "5066: Octagon Probe Failed, is this an Octagon 5066 SBC?\n");
+		iounmap((void *)iomapadr);
+		ret = -EAGAIN;
+		goto out_unmap;
+	}
+      	
 	// Print out our little header..
 	printk("Octagon 5066 SSD IO:0x%x MEM:0x%x-0x%x\n",PAGE_IO,WINDOW_START,
 	       WINDOW_START+WINDOW_LENGTH);
@@ -272,8 +271,14 @@
 		cleanup_oct5066();
 		return -ENXIO;
 	}	  
-	
+
 	return 0;
+
+ out_unmap:
+	iounmap((void *)iomapadr);
+ out_rel:
+	release_region(PAGE_IO, 1);
+	return ret;
 }
 
 module_init(init_oct5066);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/maps/pb1xxx-flash.c linux-2.4.21-pre6/drivers/mtd/maps/pb1xxx-flash.c
--- linux-2.4.20/drivers/mtd/maps/pb1xxx-flash.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/maps/pb1xxx-flash.c	2003-03-26 23:49:19.000000000 +0000
@@ -3,7 +3,7 @@
  * 
  * (C) 2001 Pete Popov <ppopov@mvista.com>
  * 
- * $Id: pb1xxx-flash.c,v 1.5 2002/02/01 23:08:50 ppopov Exp $
+ * $Id: pb1xxx-flash.c,v 1.4 2002/09/13 13:51:54 dwmw2 Exp $
  */
 
 #include <linux/config.h>
@@ -131,8 +131,8 @@
 
 static unsigned char flash_buswidth = 4;
 #if defined(CONFIG_MTD_PB1500_BOOT) && defined(CONFIG_MTD_PB1500_USER)
-/* both 32MB banks will be used. Combine the first 32MB bank and the
- * first 28MB of the second bank together into a single jffs/jffs2
+/* both 32MiB banks will be used. Combine the first 32MiB bank and the
+ * first 28MiB of the second bank together into a single jffs/jffs2
  * partition.
  */
 static unsigned long flash_size = 0x04000000;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/maps/pci.c linux-2.4.21-pre6/drivers/mtd/maps/pci.c
--- linux-2.4.20/drivers/mtd/maps/pci.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/maps/pci.c	2003-03-26 23:49:09.000000000 +0000
@@ -7,7 +7,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  *
- *  $Id: pci.c,v 1.1 2001/09/27 20:28:45 rmk Exp $
+ *  $Id: pci.c,v 1.2 2003/01/24 13:11:43 dwmw2 Exp $
  * 
  * Generic PCI memory map driver.  We support the following boards:
  *  - Intel IQ80310 ATU.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/maps/pcmciamtd.c linux-2.4.21-pre6/drivers/mtd/maps/pcmciamtd.c
--- linux-2.4.20/drivers/mtd/maps/pcmciamtd.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/maps/pcmciamtd.c	2003-03-26 23:49:50.000000000 +0000
@@ -0,0 +1,895 @@
+/*
+ * $Id: pcmciamtd.c,v 1.39 2003/01/06 17:51:38 spse Exp $
+ *
+ * pcmciamtd.c - MTD driver for PCMCIA flash memory cards
+ *
+ * Author: Simon Evans <spse@secret.org.uk>
+ *
+ * Copyright (C) 2002 Simon Evans
+ *
+ * Licence: GPL
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/timer.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+#include <linux/mtd/map.h>
+
+#ifdef CONFIG_MTD_DEBUG
+static int debug = CONFIG_MTD_DEBUG_VERBOSE;
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Set Debug Level 0=quiet, 5=noisy");
+#undef DEBUG
+#define DEBUG(n, format, arg...) \
+	if (n <= debug) {	 \
+		printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __FUNCTION__ , ## arg); \
+	}
+
+#else
+#undef DEBUG
+#define DEBUG(n, arg...)
+static const int debug = 0;
+#endif
+
+#define err(format, arg...) printk(KERN_ERR "pcmciamtd: " format "\n" , ## arg)
+#define info(format, arg...) printk(KERN_INFO "pcmciamtd: " format "\n" , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING "pcmciamtd: " format "\n" , ## arg)
+
+
+#define DRIVER_DESC	"PCMCIA Flash memory card driver"
+#define DRIVER_VERSION	"$Revision: 1.39 $"
+
+/* Size of the PCMCIA address space: 26 bits = 64 MB */
+#define MAX_PCMCIA_ADDR	0x4000000
+
+struct pcmciamtd_dev {
+	dev_link_t	link;		/* PCMCIA link */
+	dev_node_t	node;		/* device node */
+	caddr_t		win_base;	/* ioremapped address of PCMCIA window */
+	unsigned int	win_size;	/* size of window */
+	unsigned int	offset;		/* offset into card the window currently points at */
+	struct map_info	pcmcia_map;
+	struct mtd_info	*mtd_info;
+	int		vpp;
+	char		mtd_name[sizeof(struct cistpl_vers_1_t)];
+};
+
+
+static dev_info_t dev_info = "pcmciamtd";
+static dev_link_t *dev_list;
+
+/* Module parameters */
+
+/* 2 = do 16-bit transfers, 1 = do 8-bit transfers */
+static int buswidth = 2;
+
+/* Speed of memory accesses, in ns */
+static int mem_speed;
+
+/* Force the size of an SRAM card */
+static int force_size;
+
+/* Force Vpp */
+static int vpp;
+
+/* Set Vpp */
+static int setvpp;
+
+/* Force card to be treated as FLASH, ROM or RAM */
+static int mem_type;
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Simon Evans <spse@secret.org.uk>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_PARM(buswidth, "i");
+MODULE_PARM_DESC(buswidth, "Set buswidth (1=8 bit, 2=16 bit, default=2)");
+MODULE_PARM(mem_speed, "i");
+MODULE_PARM_DESC(mem_speed, "Set memory access speed in ns");
+MODULE_PARM(force_size, "i");
+MODULE_PARM_DESC(force_size, "Force size of card in MB (1-64)");
+MODULE_PARM(setvpp, "i");
+MODULE_PARM_DESC(setvpp, "Set Vpp (0=Never, 1=On writes, 2=Always on, default=0)");
+MODULE_PARM(vpp, "i");
+MODULE_PARM_DESC(vpp, "Vpp value in 1/10ths eg 33=3.3V 120=12V (Dangerous)");
+MODULE_PARM(mem_type, "i");
+MODULE_PARM_DESC(mem_type, "Set Memory type (0=Flash, 1=RAM, 2=ROM, default=0)");
+
+
+
+static inline void cs_error(client_handle_t handle, int func, int ret)
+{
+	error_info_t err = { func, ret };
+	CardServices(ReportError, handle, &err);
+}
+
+
+/* read/write{8,16} copy_{from,to} routines with window remapping to access whole card */
+
+static caddr_t remap_window(struct map_info *map, unsigned long to)
+{
+	struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1;
+	window_handle_t win = (window_handle_t)map->map_priv_2;
+	memreq_t mrq;
+	int ret;
+
+	if(!(dev->link.state & DEV_PRESENT)) {
+		DEBUG(1, "device removed state = 0x%4.4X", dev->link.state);
+		return 0;
+	}
+
+	mrq.CardOffset = to & ~(dev->win_size-1);
+	if(mrq.CardOffset != dev->offset) {
+		DEBUG(2, "Remapping window from 0x%8.8x to 0x%8.8x",
+		      dev->offset, mrq.CardOffset);
+		mrq.Page = 0;
+		if( (ret = CardServices(MapMemPage, win, &mrq)) != CS_SUCCESS) {
+			cs_error(dev->link.handle, MapMemPage, ret);
+			return NULL;
+		}
+		dev->offset = mrq.CardOffset;
+	}
+	return dev->win_base + (to & (dev->win_size-1));
+}
+
+
+static u8 pcmcia_read8_remap(struct map_info *map, unsigned long ofs)
+{
+	caddr_t addr;
+	u8 d;
+
+	addr = remap_window(map, ofs);
+	if(!addr)
+		return 0;
+
+	d = readb(addr);
+	DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%02x", ofs, addr, d);
+	return d;
+}
+
+
+static u16 pcmcia_read16_remap(struct map_info *map, unsigned long ofs)
+{
+	caddr_t addr;
+	u16 d;
+
+	addr = remap_window(map, ofs);
+	if(!addr)
+		return 0;
+
+	d = readw(addr);
+	DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%04x", ofs, addr, d);
+	return d;
+}
+
+
+static void pcmcia_copy_from_remap(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1;
+	unsigned long win_size = dev->win_size;
+
+	DEBUG(3, "to = %p from = %lu len = %u", to, from, len);
+	while(len) {
+		int toread = win_size - (from & (win_size-1));
+		caddr_t addr;
+
+		if(toread > len)
+			toread = len;
+		
+		addr = remap_window(map, from);
+		if(!addr)
+			return;
+
+		DEBUG(4, "memcpy from %p to %p len = %d", addr, to, toread);
+		memcpy_fromio(to, addr, toread);
+		len -= toread;
+		to += toread;
+		from += toread;
+	}
+}
+
+
+static void pcmcia_write8_remap(struct map_info *map, u8 d, unsigned long adr)
+{
+	caddr_t addr = remap_window(map, adr);
+
+	if(!addr)
+		return;
+
+	DEBUG(3, "adr = 0x%08lx (%p)  data = 0x%02x", adr, addr, d);
+	writeb(d, addr);
+}
+
+
+static void pcmcia_write16_remap(struct map_info *map, u16 d, unsigned long adr)
+{
+	caddr_t addr = remap_window(map, adr);
+	if(!addr)
+		return;
+
+	DEBUG(3, "adr = 0x%08lx (%p)  data = 0x%04x", adr, addr, d);
+	writew(d, addr);
+}
+
+
+static void pcmcia_copy_to_remap(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1;
+	unsigned long win_size = dev->win_size;
+
+	DEBUG(3, "to = %lu from = %p len = %u", to, from, len);
+	while(len) {
+		int towrite = win_size - (to & (win_size-1));
+		caddr_t addr;
+
+		if(towrite > len)
+			towrite = len;
+
+		addr = remap_window(map, to);
+		if(!addr)
+			return;
+
+		DEBUG(4, "memcpy from %p to %p len = %d", from, addr, towrite);
+		memcpy_toio(addr, from, towrite);
+		len -= towrite;
+		to += towrite;
+		from += towrite;
+	}
+}
+
+
+/* read/write{8,16} copy_{from,to} routines with direct access */
+
+#define DEV_REMOVED(x)  (!(*(u_int *)x->map_priv_1 & DEV_PRESENT))
+
+static u8 pcmcia_read8(struct map_info *map, unsigned long ofs)
+{
+	caddr_t win_base = (caddr_t)map->map_priv_2;
+	u8 d;
+
+	if(DEV_REMOVED(map))
+		return 0;
+
+	d = readb(win_base + ofs);
+	DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%02x", ofs, win_base + ofs, d);
+	return d;
+}
+
+
+static u16 pcmcia_read16(struct map_info *map, unsigned long ofs)
+{
+	caddr_t win_base = (caddr_t)map->map_priv_2;
+	u16 d;
+
+	if(DEV_REMOVED(map))
+		return 0;
+
+	d = readw(win_base + ofs);
+	DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%04x", ofs, win_base + ofs, d);
+	return d;
+}
+
+
+static void pcmcia_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	caddr_t win_base = (caddr_t)map->map_priv_2;
+
+	if(DEV_REMOVED(map))
+		return;
+
+	DEBUG(3, "to = %p from = %lu len = %u", to, from, len);
+	memcpy_fromio(to, win_base + from, len);
+}
+
+
+static void pcmcia_write8(struct map_info *map, u8 d, unsigned long adr)
+{
+	caddr_t win_base = (caddr_t)map->map_priv_2;
+
+	if(DEV_REMOVED(map))
+		return;
+
+	DEBUG(3, "adr = 0x%08lx (%p)  data = 0x%02x", adr, win_base + adr, d);
+	writeb(d, win_base + adr);
+}
+
+
+static void pcmcia_write16(struct map_info *map, u16 d, unsigned long adr)
+{
+	caddr_t win_base = (caddr_t)map->map_priv_2;
+
+	if(DEV_REMOVED(map))
+		return;
+
+	DEBUG(3, "adr = 0x%08lx (%p)  data = 0x%04x", adr, win_base + adr, d);
+	writew(d, win_base + adr);
+}
+
+
+static void pcmcia_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	caddr_t win_base = (caddr_t)map->map_priv_2;
+
+	if(DEV_REMOVED(map))
+		return;
+
+	DEBUG(3, "to = %lu from = %p len = %u", to, from, len);
+	memcpy_toio(win_base + to, from, len);
+}
+
+
+static void pcmciamtd_set_vpp(struct map_info *map, int on)
+{
+	struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1;
+	dev_link_t *link = &dev->link;
+	modconf_t mod;
+	int ret;
+
+	mod.Attributes = CONF_VPP1_CHANGE_VALID | CONF_VPP2_CHANGE_VALID;
+	mod.Vcc = 0;
+	mod.Vpp1 = mod.Vpp2 = on ? dev->vpp : 0;
+
+	DEBUG(2, "dev = %p on = %d vpp = %d\n", dev, on, dev->vpp);
+	ret = CardServices(ModifyConfiguration, link->handle, &mod);
+	if(ret != CS_SUCCESS) {
+		cs_error(link->handle, ModifyConfiguration, ret);
+	}
+}
+
+
+/* After a card is removed, pcmciamtd_release() will unregister the
+ * device, and release the PCMCIA configuration.  If the device is
+ * still open, this will be postponed until it is closed.
+ */
+
+static void pcmciamtd_release(u_long arg)
+{
+	dev_link_t *link = (dev_link_t *)arg;
+	struct pcmciamtd_dev *dev = link->priv;
+
+	DEBUG(3, "link = 0x%p", link);
+
+	if (link->win) {
+		if(dev->win_base) {
+			iounmap(dev->win_base);
+			dev->win_base = NULL;
+		}
+		CardServices(ReleaseWindow, link->win);
+	}
+	CardServices(ReleaseConfiguration, link->handle);
+	link->state &= ~DEV_CONFIG;
+}
+
+
+static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_name)
+{
+	int rc;
+	tuple_t tuple;
+	cisparse_t parse;
+	u_char buf[64];
+
+	tuple.Attributes = 0;
+	tuple.TupleData = (cisdata_t *)buf;
+	tuple.TupleDataMax = sizeof(buf);
+	tuple.TupleOffset = 0;
+	tuple.DesiredTuple = RETURN_FIRST_TUPLE;
+
+	rc = CardServices(GetFirstTuple, link->handle, &tuple);
+	while(rc == CS_SUCCESS) {
+		rc = CardServices(GetTupleData, link->handle, &tuple);
+		if(rc != CS_SUCCESS) {
+			cs_error(link->handle, GetTupleData, rc);
+			break;
+		}
+		rc = CardServices(ParseTuple, link->handle, &tuple, &parse);
+		if(rc != CS_SUCCESS) {
+			cs_error(link->handle, ParseTuple, rc);
+			break;
+		}
+		
+		switch(tuple.TupleCode) {
+		case  CISTPL_FORMAT: {
+			cistpl_format_t *t = &parse.format;
+			(void)t; /* Shut up, gcc */
+			DEBUG(2, "Format type: %u, Error Detection: %u, offset = %u, length =%u",
+			      t->type, t->edc, t->offset, t->length);
+			break;
+			
+		}
+			
+		case CISTPL_DEVICE: {
+			cistpl_device_t *t = &parse.device;
+			int i;
+			DEBUG(2, "Common memory:");
+			dev->pcmcia_map.size = t->dev[0].size;
+			for(i = 0; i < t->ndev; i++) {
+				DEBUG(2, "Region %d, type = %u", i, t->dev[i].type);
+				DEBUG(2, "Region %d, wp = %u", i, t->dev[i].wp);
+				DEBUG(2, "Region %d, speed = %u ns", i, t->dev[i].speed);
+				DEBUG(2, "Region %d, size = %u bytes", i, t->dev[i].size);
+			}
+			break;
+		}
+			
+		case CISTPL_VERS_1: {
+			cistpl_vers_1_t *t = &parse.version_1;
+			int i;
+			if(t->ns) {
+				dev->mtd_name[0] = '\0';
+				for(i = 0; i < t->ns; i++) {
+					if(i)
+						strcat(dev->mtd_name, " ");
+					strcat(dev->mtd_name, t->str+t->ofs[i]);
+				}
+			}
+			DEBUG(2, "Found name: %s", dev->mtd_name);
+			break;
+		}
+			
+		case CISTPL_JEDEC_C: {
+			cistpl_jedec_t *t = &parse.jedec;
+			int i;
+			for(i = 0; i < t->nid; i++) {
+				DEBUG(2, "JEDEC: 0x%02x 0x%02x", t->id[i].mfr, t->id[i].info);
+			}
+			break;
+		}
+			
+		case CISTPL_DEVICE_GEO: {
+			cistpl_device_geo_t *t = &parse.device_geo;
+			int i;
+			dev->pcmcia_map.buswidth = t->geo[0].buswidth;
+			for(i = 0; i < t->ngeo; i++) {
+				DEBUG(2, "region: %d buswidth = %u", i, t->geo[i].buswidth);
+				DEBUG(2, "region: %d erase_block = %u", i, t->geo[i].erase_block);
+				DEBUG(2, "region: %d read_block = %u", i, t->geo[i].read_block);
+				DEBUG(2, "region: %d write_block = %u", i, t->geo[i].write_block);
+				DEBUG(2, "region: %d partition = %u", i, t->geo[i].partition);
+				DEBUG(2, "region: %d interleave = %u", i, t->geo[i].interleave);
+			}
+			break;
+		}
+			
+		default:
+			DEBUG(2, "Unknown tuple code %d", tuple.TupleCode);
+		}
+		
+		rc = CardServices(GetNextTuple, link->handle, &tuple, &parse);
+	}
+	if(!dev->pcmcia_map.size)
+		dev->pcmcia_map.size = MAX_PCMCIA_ADDR;
+
+	if(!dev->pcmcia_map.buswidth)
+		dev->pcmcia_map.buswidth = 2;
+
+	if(force_size) {
+		dev->pcmcia_map.size = force_size << 20;
+		DEBUG(2, "size forced to %dM", force_size);
+	}
+
+	if(buswidth) {
+		dev->pcmcia_map.buswidth = buswidth;
+		DEBUG(2, "buswidth forced to %d", buswidth);
+	}		
+
+	dev->pcmcia_map.name = dev->mtd_name;
+	if(!dev->mtd_name[0]) {
+		strcpy(dev->mtd_name, "PCMCIA Memory card");
+		*new_name = 1;
+	}
+
+	DEBUG(1, "Device: Size: %lu Width:%d Name: %s",
+	      dev->pcmcia_map.size, dev->pcmcia_map.buswidth << 3, dev->mtd_name);
+}
+
+
+/* pcmciamtd_config() is scheduled to run after a CARD_INSERTION event
+ * is received, to configure the PCMCIA socket, and to make the
+ * MTD device available to the system.
+ */
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
+
+static void pcmciamtd_config(dev_link_t *link)
+{
+	struct pcmciamtd_dev *dev = link->priv;
+	struct mtd_info *mtd = NULL;
+	cs_status_t status;
+	win_req_t req;
+	int last_ret = 0, last_fn = 0;
+	int ret;
+	int i;
+	config_info_t t;
+	static char *probes[] = { "jedec_probe", "cfi_probe" };
+	cisinfo_t cisinfo;
+	int new_name = 0;
+
+	DEBUG(3, "link=0x%p", link);
+
+	/* Configure card */
+	link->state |= DEV_CONFIG;
+
+	DEBUG(2, "Validating CIS");
+	ret = CardServices(ValidateCIS, link->handle, &cisinfo);
+	if(ret != CS_SUCCESS) {
+		cs_error(link->handle, GetTupleData, ret);
+	} else {
+		DEBUG(2, "ValidateCIS found %d chains", cisinfo.Chains);
+	}
+
+	card_settings(dev, link, &new_name);
+
+	dev->pcmcia_map.read8 = pcmcia_read8_remap;
+	dev->pcmcia_map.read16 = pcmcia_read16_remap;
+	dev->pcmcia_map.copy_from = pcmcia_copy_from_remap;
+	dev->pcmcia_map.write8 = pcmcia_write8_remap;
+	dev->pcmcia_map.write16 = pcmcia_write16_remap;
+	dev->pcmcia_map.copy_to = pcmcia_copy_to_remap;
+	if(setvpp == 1)
+		dev->pcmcia_map.set_vpp = pcmciamtd_set_vpp;
+
+	/* Request a memory window for PCMCIA. Some architeures can map windows upto the maximum
+	   that PCMCIA can support (64Mb) - this is ideal and we aim for a window the size of the
+	   whole card - otherwise we try smaller windows until we succeed */
+
+	req.Attributes =  WIN_MEMORY_TYPE_CM | WIN_ENABLE;
+	req.Attributes |= (dev->pcmcia_map.buswidth == 1) ? WIN_DATA_WIDTH_8 : WIN_DATA_WIDTH_16;
+	req.Base = 0;
+	req.AccessSpeed = mem_speed;
+	link->win = (window_handle_t)link->handle;
+	req.Size = (force_size) ? force_size << 20 : MAX_PCMCIA_ADDR;
+	dev->win_size = 0;
+
+	do {
+		int ret;
+		DEBUG(2, "requesting window with size = %dKB memspeed = %d",
+		      req.Size >> 10, req.AccessSpeed);
+		link->win = (window_handle_t)link->handle;
+		ret = CardServices(RequestWindow, &link->win, &req);
+		DEBUG(2, "ret = %d dev->win_size = %d", ret, dev->win_size);
+		if(ret) {
+			req.Size >>= 1;
+		} else {
+			DEBUG(2, "Got window of size %dKB", req.Size >> 10);
+			dev->win_size = req.Size;
+			break;
+		}
+	} while(req.Size >= 0x1000);
+
+	DEBUG(2, "dev->win_size = %d", dev->win_size);
+
+	if(!dev->win_size) {
+		err("Cant allocate memory window");
+		pcmciamtd_release((u_long)link);
+		return;
+	}
+	DEBUG(1, "Allocated a window of %dKB", dev->win_size >> 10);
+		
+	/* Get write protect status */
+	CS_CHECK(GetStatus, link->handle, &status);
+	DEBUG(2, "status value: 0x%x window handle = 0x%8.8lx",
+	      status.CardState, (unsigned long)link->win);
+	dev->win_base = ioremap(req.Base, req.Size);
+	if(!dev->win_base) {
+		err("ioremap(%lu, %u) failed", req.Base, req.Size);
+		pcmciamtd_release((u_long)link);
+		return;
+	}
+	DEBUG(1, "mapped window dev = %p req.base = 0x%lx base = %p size = 0x%x",
+	      dev, req.Base, dev->win_base, req.Size);
+
+	dev->offset = 0;
+	dev->pcmcia_map.map_priv_1 = (unsigned long)dev;
+	dev->pcmcia_map.map_priv_2 = (unsigned long)link->win;
+
+	DEBUG(2, "Getting configuration");
+	CS_CHECK(GetConfigurationInfo, link->handle, &t);
+	DEBUG(2, "Vcc = %d Vpp1 = %d Vpp2 = %d", t.Vcc, t.Vpp1, t.Vpp2);
+	dev->vpp = (vpp) ? vpp : t.Vpp1;
+	link->conf.Attributes = 0;
+	link->conf.Vcc = t.Vcc;
+	if(setvpp == 2) {
+		link->conf.Vpp1 = dev->vpp;
+		link->conf.Vpp2 = dev->vpp;
+	} else {
+		link->conf.Vpp1 = 0;
+		link->conf.Vpp2 = 0;
+	}
+
+	link->conf.IntType = INT_MEMORY;
+	link->conf.ConfigBase = t.ConfigBase;
+	link->conf.Status = t.Status;
+	link->conf.Pin = t.Pin;
+	link->conf.Copy = t.Copy;
+	link->conf.ExtStatus = t.ExtStatus;
+	link->conf.ConfigIndex = 0;
+	link->conf.Present = t.Present;
+	DEBUG(2, "Setting Configuration");
+	ret = CardServices(RequestConfiguration, link->handle, &link->conf);
+	if(ret != CS_SUCCESS) {
+		cs_error(link->handle, RequestConfiguration, ret);
+	}
+
+	if(mem_type == 1) {
+		mtd = do_map_probe("map_ram", &dev->pcmcia_map);
+	} else if(mem_type == 2) {
+		mtd = do_map_probe("map_rom", &dev->pcmcia_map);
+	} else {
+		for(i = 0; i < sizeof(probes) / sizeof(char *); i++) {
+			DEBUG(1, "Trying %s", probes[i]);
+			mtd = do_map_probe(probes[i], &dev->pcmcia_map);
+			if(mtd)
+				break;
+			
+			DEBUG(1, "FAILED: %s", probes[i]);
+		}
+	}
+	
+	if(!mtd) {
+		DEBUG(1, "Cant find an MTD");
+		pcmciamtd_release((u_long)link);
+		return;
+	}
+
+	dev->mtd_info = mtd;
+	mtd->module = THIS_MODULE;
+
+	if(new_name) {
+		int size = 0;
+		char unit = ' ';
+		/* Since we are using a default name, make it better by adding in the
+		   size */
+		if(mtd->size < 1048576) { /* <1MB in size, show size in K */
+			size = mtd->size >> 10;
+			unit = 'K';
+		} else {
+			size = mtd->size >> 20;
+			unit = 'M';
+		}
+		snprintf(dev->mtd_name, sizeof(dev->mtd_name), "%d%cB %s", size, unit, "PCMCIA Memory card");
+	}
+
+	/* If the memory found is fits completely into the mapped PCMCIA window,
+	   use the faster non-remapping read/write functions */
+	if(mtd->size <= dev->win_size) {
+		DEBUG(1, "Using non remapping memory functions");
+		dev->pcmcia_map.map_priv_1 = (unsigned long)&(dev->link.state);
+		dev->pcmcia_map.map_priv_2 = (unsigned long)dev->win_base;
+		dev->pcmcia_map.read8 = pcmcia_read8;
+		dev->pcmcia_map.read16 = pcmcia_read16;
+		dev->pcmcia_map.copy_from = pcmcia_copy_from;
+		dev->pcmcia_map.write8 = pcmcia_write8;
+		dev->pcmcia_map.write16 = pcmcia_write16;
+		dev->pcmcia_map.copy_to = pcmcia_copy_to;
+	}
+
+	if(add_mtd_device(mtd)) {
+		map_destroy(mtd);
+		dev->mtd_info = NULL;
+		err("Couldnt register MTD device");
+		pcmciamtd_release((u_long)link);
+		return;
+	}
+	snprintf(dev->node.dev_name, sizeof(dev->node.dev_name), "mtd%d", mtd->index);
+	info("mtd%d: %s", mtd->index, mtd->name);
+	link->state &= ~DEV_CONFIG_PENDING;
+	link->dev = &dev->node;
+	return;
+
+ cs_failed:
+	cs_error(link->handle, last_fn, last_ret);
+	err("CS Error, exiting");
+	pcmciamtd_release((u_long)link);
+	return;
+}
+
+
+/* The card status event handler.  Mostly, this schedules other
+ * stuff to run after an event is received.  A CARD_REMOVAL event
+ * also sets some flags to discourage the driver from trying
+ * to talk to the card any more.
+ */
+
+static int pcmciamtd_event(event_t event, int priority,
+			event_callback_args_t *args)
+{
+	dev_link_t *link = args->client_data;
+
+	DEBUG(1, "event=0x%06x", event);
+	switch (event) {
+	case CS_EVENT_CARD_REMOVAL:
+		DEBUG(2, "EVENT_CARD_REMOVAL");
+		link->state &= ~DEV_PRESENT;
+		if (link->state & DEV_CONFIG) {
+			struct pcmciamtd_dev *dev = link->priv;
+			if(dev->mtd_info) {
+				del_mtd_device(dev->mtd_info);
+				info("mtd%d: Removed", dev->mtd_info->index);
+			}
+			mod_timer(&link->release, jiffies + HZ/20);
+		}
+		break;
+	case CS_EVENT_CARD_INSERTION:
+		DEBUG(2, "EVENT_CARD_INSERTION");
+		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+		pcmciamtd_config(link);
+		break;
+	case CS_EVENT_PM_SUSPEND:
+		DEBUG(2, "EVENT_PM_SUSPEND");
+		link->state |= DEV_SUSPEND;
+		/* Fall through... */
+	case CS_EVENT_RESET_PHYSICAL:
+		DEBUG(2, "EVENT_RESET_PHYSICAL");
+		/* get_lock(link); */
+		break;
+	case CS_EVENT_PM_RESUME:
+		DEBUG(2, "EVENT_PM_RESUME");
+		link->state &= ~DEV_SUSPEND;
+		/* Fall through... */
+	case CS_EVENT_CARD_RESET:
+		DEBUG(2, "EVENT_CARD_RESET");
+		/* free_lock(link); */
+		break;
+	default:
+		DEBUG(2, "Unknown event %d", event);
+	}
+	return 0;
+}
+
+
+/* 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 pcmciamtd_detach(dev_link_t *link)
+{
+	DEBUG(3, "link=0x%p", link);
+
+	del_timer(&link->release);
+
+	if(link->state & DEV_CONFIG) {
+		pcmciamtd_release((u_long)link);
+	}
+
+	if (link->handle) {
+		int ret;
+		DEBUG(2, "Deregistering with card services");
+		ret = CardServices(DeregisterClient, link->handle);
+		if (ret != CS_SUCCESS)
+			cs_error(link->handle, DeregisterClient, ret);
+	}
+
+	link->state |= DEV_STALE_LINK;
+}
+
+
+/* pcmciamtd_attach() creates an "instance" of the driver, allocating
+ * local data structures for one device.  The device is registered
+ * with Card Services.
+ */
+
+static dev_link_t *pcmciamtd_attach(void)
+{
+	struct pcmciamtd_dev *dev;
+	dev_link_t *link;
+	client_reg_t client_reg;
+	int ret;
+
+	/* Create new memory card device */
+	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev) return NULL;
+	DEBUG(1, "dev=0x%p", dev);
+
+	memset(dev, 0, sizeof(*dev));
+	link = &dev->link;
+	link->priv = dev;
+
+	init_timer(&link->release);
+	link->release.function = &pcmciamtd_release;
+	link->release.data = (u_long)link;
+
+	link->conf.Attributes = 0;
+	link->conf.IntType = INT_MEMORY;
+
+	link->next = dev_list;
+	dev_list = link;
+
+	/* Register with Card Services */
+	client_reg.dev_info = &dev_info;
+	client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+	client_reg.EventMask =
+		CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+		CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+	client_reg.event_handler = &pcmciamtd_event;
+	client_reg.Version = 0x0210;
+	client_reg.event_callback_args.client_data = link;
+	DEBUG(2, "Calling RegisterClient");
+	ret = CardServices(RegisterClient, &link->handle, &client_reg);
+	if (ret != 0) {
+		cs_error(link->handle, RegisterClient, ret);
+		pcmciamtd_detach(link);
+		return NULL;
+	}
+	DEBUG(2, "link = %p", link);
+	return link;
+}
+
+
+static int __init init_pcmciamtd(void)
+{
+	servinfo_t serv;
+
+	info(DRIVER_DESC " " DRIVER_VERSION);
+	CardServices(GetCardServicesInfo, &serv);
+	if (serv.Revision != CS_RELEASE_CODE) {
+		err("Card Services release does not match!");
+		return -1;
+	}
+
+	if(buswidth && buswidth != 1 && buswidth != 2) {
+		info("bad buswidth (%d), using default", buswidth);
+		buswidth = 2;
+	}
+	if(force_size && (force_size < 1 || force_size > 64)) {
+		info("bad force_size (%d), using default", force_size);
+		force_size = 0;
+	}
+	if(mem_type && mem_type != 1 && mem_type != 2) {
+		info("bad mem_type (%d), using default", mem_type);
+		mem_type = 0;
+	}
+	register_pccard_driver(&dev_info, &pcmciamtd_attach, &pcmciamtd_detach);
+	return 0;
+}
+
+
+static void __exit exit_pcmciamtd(void)
+{
+	DEBUG(1, DRIVER_DESC " unloading");
+	unregister_pccard_driver(&dev_info);
+
+	while(dev_list) {
+		dev_link_t *link = dev_list;
+
+		dev_list = link->next;
+		if (link) {
+			struct pcmciamtd_dev *dev = link->priv;
+			
+ 			if(dev) {
+				if(link->state & DEV_PRESENT) {
+					if (!(link->state & DEV_STALE_LINK)) {
+						pcmciamtd_detach(link);
+					}
+					link->state &= ~DEV_PRESENT;
+					if(dev->mtd_info) {
+						del_mtd_device(dev->mtd_info);
+						info("mtd%d: Removed",
+						     dev->mtd_info->index);
+					}
+				}
+				if(dev->mtd_info) {
+					DEBUG(2, "Destroying map for mtd%d",
+					      dev->mtd_info->index);
+					map_destroy(dev->mtd_info);
+				}
+				kfree(dev);
+			}
+		}
+	}
+}
+
+module_init(init_pcmciamtd);
+module_exit(exit_pcmciamtd);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/maps/physmap.c linux-2.4.21-pre6/drivers/mtd/maps/physmap.c
--- linux-2.4.20/drivers/mtd/maps/physmap.c	2001-10-04 22:14:59.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/maps/physmap.c	2003-03-26 23:49:00.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * $Id: physmap.c,v 1.15 2001/10/02 15:05:14 dwmw2 Exp $
+ * $Id: physmap.c,v 1.21 2002/09/05 05:12:54 acurtis Exp $
  *
  * Normal mappings of chips in physical memory
  */
@@ -12,6 +12,9 @@
 #include <linux/mtd/map.h>
 #include <linux/config.h>
 
+#ifdef CONFIG_MTD_PARTITIONS
+#include <linux/mtd/partitions.h>
+#endif
 
 #define WINDOW_ADDR CONFIG_MTD_PHYSMAP_START
 #define WINDOW_SIZE CONFIG_MTD_PHYSMAP_LEN
@@ -76,8 +79,47 @@
 	copy_to: physmap_copy_to
 };
 
+#ifdef CONFIG_MTD_PARTITIONS
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+static struct mtd_partition *mtd_parts = 0;
+static int                   mtd_parts_nb = 0;
+#else
+static struct mtd_partition physmap_partitions[] = {
+/* Put your own partition definitions here */
+#if 0
+	{
+		name:		"bootROM",
+		size:		0x80000,
+		offset:		0,
+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
+	}, {
+		name:		"zImage",
+		size:		0x100000,
+		offset:		MTDPART_OFS_APPEND,
+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
+	}, {
+		name:		"ramdisk.gz",
+		size:		0x300000,
+		offset:		MTDPART_OFS_APPEND,
+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
+	}, {
+		name:		"User FS",
+		size:		MTDPART_SIZ_FULL,
+		offset:		MTDPART_OFS_APPEND,
+	}
+#endif
+};
+
+#define NUM_PARTITIONS	(sizeof(physmap_partitions)/sizeof(struct mtd_partition))
+
+#endif
+#endif
+
 int __init init_physmap(void)
 {
+	static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", 0 };
+	const char **type;
+
        	printk(KERN_NOTICE "physmap flash device: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR);
 	physmap_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
 
@@ -85,11 +127,36 @@
 		printk("Failed to ioremap\n");
 		return -EIO;
 	}
-	mymtd = do_map_probe("cfi_probe", &physmap_map);
+	
+	mymtd = 0;
+	type = rom_probe_types;
+	for(; !mymtd && *type; type++) {
+		mymtd = do_map_probe(*type, &physmap_map);
+	}
 	if (mymtd) {
 		mymtd->module = THIS_MODULE;
 
 		add_mtd_device(mymtd);
+#ifdef CONFIG_MTD_PARTITIONS
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+		mtd_parts_nb = parse_cmdline_partitions(mymtd, &mtd_parts, 
+							"phys");
+		if (mtd_parts_nb > 0)
+		{
+			printk(KERN_NOTICE 
+			       "Using command line partition definition\n");
+			add_mtd_partitions (mymtd, mtd_parts, mtd_parts_nb);
+		}
+#else
+		if (NUM_PARTITIONS != 0) 
+		{
+			printk(KERN_NOTICE 
+			       "Using physmap partition definition\n");
+			add_mtd_partitions (mymtd, physmap_partitions, NUM_PARTITIONS);
+		}
+
+#endif
+#endif
 		return 0;
 	}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/maps/physmap64.c linux-2.4.21-pre6/drivers/mtd/maps/physmap64.c
--- linux-2.4.20/drivers/mtd/maps/physmap64.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/maps/physmap64.c	2003-03-26 23:48:58.000000000 +0000
@@ -0,0 +1,199 @@
+/*
+ * $Id: physmap64.c,v 1.1 2002/09/05 05:12:32 acurtis Exp $
+ *
+ * Normal mappings of chips in physical memory
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/config.h>
+#include <linux/mtd/cfi.h>
+
+#ifdef CONFIG_MTD_PARTITIONS
+#include <linux/mtd/partitions.h>
+#endif
+
+#define WINDOW_ADDR CONFIG_MTD_PHYSMAP_START
+#define WINDOW_SIZE CONFIG_MTD_PHYSMAP_LEN
+#define BUSWIDTH CONFIG_MTD_PHYSMAP_BUSWIDTH
+
+static struct mtd_info *mymtd;
+
+__u8 physmap_read8(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readb(map->map_priv_1 + ofs);
+}
+
+__u16 physmap_read16(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readw(map->map_priv_1 + ofs);
+}
+
+__u32 physmap_read32(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readl(map->map_priv_1 + ofs);
+}
+
+__u64 physmap_read64(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readll(map->map_priv_1 + ofs);
+}
+
+void physmap_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	memcpy_fromio(to, map->map_priv_1 + from, len);
+}
+
+void physmap_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+	__raw_writeb(d, map->map_priv_1 + adr);
+	mb();
+}
+
+void physmap_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+	__raw_writew(d, map->map_priv_1 + adr);
+	mb();
+}
+
+void physmap_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+	__raw_writel(d, map->map_priv_1 + adr);
+	mb();
+}
+
+void physmap_write64(struct map_info *map, __u64 d, unsigned long adr)
+{
+	__raw_writell(d, map->map_priv_1 + adr);
+	mb();
+}
+
+void physmap_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	memcpy_toio(map->map_priv_1 + to, from, len);
+}
+
+struct map_info physmap_map = {
+	name: "Physically mapped flash",
+	size: WINDOW_SIZE,
+	buswidth: BUSWIDTH,
+	read8: physmap_read8,
+	read16: physmap_read16,
+	read32: physmap_read32,
+	read64: physmap_read64,
+	copy_from: physmap_copy_from,
+	write8: physmap_write8,
+	write16: physmap_write16,
+	write32: physmap_write32,
+	write64: physmap_write64,
+	copy_to: physmap_copy_to
+};
+
+#ifdef CONFIG_MTD_PARTITIONS
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+static struct mtd_partition *mtd_parts = 0;
+static int                   mtd_parts_nb = 0;
+#else
+static struct mtd_partition physmap_partitions[] = {
+/* Put your own partition definitions here */
+#if 0
+	{
+		name:		"bootROM",
+		size:		0x80000,
+		offset:		0,
+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
+	}, {
+		name:		"zImage",
+		size:		0x100000,
+		offset:		MTDPART_OFS_APPEND,
+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
+	}, {
+		name:		"ramdisk.gz",
+		size:		0x300000,
+		offset:		MTDPART_OFS_APPEND,
+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
+	}, {
+		name:		"User FS",
+		size:		MTDPART_SIZ_FULL,
+		offset:		MTDPART_OFS_APPEND,
+	}
+#endif
+};
+
+#define NUM_PARTITIONS	(sizeof(physmap_partitions)/sizeof(struct mtd_partition))
+
+#endif
+#endif
+
+int __init init_physmap(void)
+{
+	static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", 0 };
+	const char **type;
+
+       	printk(KERN_NOTICE "physmap flash device: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR);
+	physmap_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
+
+	if (!physmap_map.map_priv_1) {
+		printk("Failed to ioremap\n");
+		return -EIO;
+	}
+	
+	mymtd = 0;
+	type = rom_probe_types;
+	for(; !mymtd && *type; type++) {
+		mymtd = do_map_probe(*type, &physmap_map);
+	}
+	if (mymtd) {
+		mymtd->module = THIS_MODULE;
+
+		add_mtd_device(mymtd);
+#ifdef CONFIG_MTD_PARTITIONS
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+		mtd_parts_nb = parse_cmdline_partitions(mymtd, &mtd_parts, 
+							"phys");
+		if (mtd_parts_nb > 0)
+		{
+			printk(KERN_NOTICE 
+			       "Using command line partition definition\n");
+			add_mtd_partitions (mymtd, mtd_parts, mtd_parts_nb);
+		}
+#else
+		if (NUM_PARTITIONS != 0) 
+		{
+			printk(KERN_NOTICE 
+			       "Using physmap partition definition\n");
+			add_mtd_partitions (mymtd, physmap_partitions, NUM_PARTITIONS);
+		}
+
+#endif
+#endif
+		return 0;
+	}
+
+	iounmap((void *)physmap_map.map_priv_1);
+	return -ENXIO;
+}
+
+static void __exit cleanup_physmap(void)
+{
+	if (mymtd) {
+		del_mtd_device(mymtd);
+		map_destroy(mymtd);
+	}
+	if (physmap_map.map_priv_1) {
+		iounmap((void *)physmap_map.map_priv_1);
+		physmap_map.map_priv_1 = 0;
+	}
+}
+
+module_init(init_physmap);
+module_exit(cleanup_physmap);
+
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
+MODULE_DESCRIPTION("Generic configurable MTD map driver");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/maps/redwood.c linux-2.4.21-pre6/drivers/mtd/maps/redwood.c
--- linux-2.4.20/drivers/mtd/maps/redwood.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/maps/redwood.c	2003-03-26 23:49:51.000000000 +0000
@@ -0,0 +1,173 @@
+/*
+ * $Id:
+ *
+ * redwood.c - mapper for IBM Redwood-4/5 board.
+ *	
+ * Copyright 2001 MontaVista Softare Inc. 
+ *  
+ * This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.    
+ *  
+ *  THIS  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.
+ *  
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  History: 12/17/2001 - Armin
+ *  		migrated to use do_map_probe
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/io.h>
+
+#define WINDOW_ADDR 0xffc00000
+#define WINDOW_SIZE 0x00400000
+
+__u8 redwood_flash_read8(struct map_info *map, unsigned long ofs)
+{
+        return *(__u8 *)(map->map_priv_1 + ofs);
+}
+
+__u16 redwood_flash_read16(struct map_info *map, unsigned long ofs)
+{
+        return *(__u16 *)(map->map_priv_1 + ofs);
+}
+
+__u32 redwood_flash_read32(struct map_info *map, unsigned long ofs)
+{
+        return *(volatile unsigned int *)(map->map_priv_1 + ofs);
+}
+
+void redwood_flash_copy_from(struct map_info *map, void *to,
+                             unsigned long from, ssize_t len)
+{
+        memcpy(to, (void *)(map->map_priv_1 + from), len);
+}
+
+void redwood_flash_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+        *(__u8 *)(map->map_priv_1 + adr) = d;
+}
+
+void redwood_flash_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+        *(__u16 *)(map->map_priv_1 + adr) = d;
+}
+
+void redwood_flash_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+        *(__u32 *)(map->map_priv_1 + adr) = d;
+}
+
+void redwood_flash_copy_to(struct map_info *map, unsigned long to,
+                           const void *from, ssize_t len)
+{
+        memcpy((void *)(map->map_priv_1 + to), from, len);
+}
+
+struct map_info redwood_flash_map = {
+        name: "IBM Redwood",
+        size: WINDOW_SIZE,
+        buswidth: 2,
+        read8: redwood_flash_read8,
+        read16: redwood_flash_read16,
+        read32: redwood_flash_read32,
+        copy_from: redwood_flash_copy_from,
+        write8: redwood_flash_write8,
+        write16: redwood_flash_write16,
+        write32: redwood_flash_write32,
+        copy_to: redwood_flash_copy_to
+};
+
+
+static struct mtd_partition redwood_flash_partitions[] = {
+        {
+                name: "Redwood OpenBIOS Vital Product Data",
+                offset: 0,
+                size:   0x10000,
+                mask_flags: MTD_WRITEABLE       /* force read-only */
+        },
+        {
+                name: "Redwood kernel",
+                offset: 0x10000,
+                size:   0x200000 - 0x10000
+        },
+        {
+                name: "Redwood OpenBIOS non-volatile storage",
+                offset: 0x200000,
+                size:   0x10000,
+                mask_flags: MTD_WRITEABLE       /* force read-only */
+        },
+        {
+                name: "Redwood filesystem",
+                offset: 0x210000,
+                size:   0x200000 - (0x10000 + 0x20000)
+        },
+        {
+                name: "Redwood OpenBIOS",
+                offset: 0x3e0000,
+                size:   0x20000,
+                mask_flags: MTD_WRITEABLE       /* force read-only */
+        }
+};
+#define NUM_REDWOOD_FLASH_PARTITIONS \
+        (sizeof(redwood_flash_partitions)/sizeof(redwood_flash_partitions[0]))
+
+static struct mtd_info *redwood_mtd;
+
+int __init init_redwood_flash(void)
+{
+        printk(KERN_NOTICE "redwood: flash mapping: %x at %x\n",
+               WINDOW_SIZE, WINDOW_ADDR);
+
+        redwood_flash_map.map_priv_1 =
+                (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
+
+        if (!redwood_flash_map.map_priv_1) {
+                printk("init_redwood_flash: failed to ioremap\n");
+                return -EIO;
+        }
+
+        redwood_mtd = do_map_probe("cfi_probe",&redwood_flash_map);
+
+        if (redwood_mtd) {
+                redwood_mtd->module = THIS_MODULE;
+                return add_mtd_partitions(redwood_mtd,
+                                          redwood_flash_partitions,
+                                          NUM_REDWOOD_FLASH_PARTITIONS);
+        }
+
+        return -ENXIO;
+}
+
+static void __exit cleanup_redwood_flash(void)
+{
+        if (redwood_mtd) {
+                del_mtd_partitions(redwood_mtd);
+                iounmap((void *)redwood_flash_map.map_priv_1);
+                map_destroy(redwood_mtd);
+        }
+}
+
+module_init(init_redwood_flash);
+module_exit(cleanup_redwood_flash);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/maps/sa1100-flash.c linux-2.4.21-pre6/drivers/mtd/maps/sa1100-flash.c
--- linux-2.4.20/drivers/mtd/maps/sa1100-flash.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/maps/sa1100-flash.c	2003-03-26 23:49:19.000000000 +0000
@@ -3,7 +3,7 @@
  * 
  * (C) 2000 Nicolas Pitre <nico@cam.org>
  * 
- * $Id: sa1100-flash.c,v 1.26 2002/03/13 16:30:44 rmk Exp $
+ * $Id: sa1100-flash.c,v 1.29 2002/09/06 14:36:19 abz Exp $
  */
 
 #include <linux/config.h>
@@ -393,27 +393,23 @@
 static struct mtd_partition frodo_partitions[] =
 {
 	{
-		name:		"bootloader",
+		name:		"Boot Loader",
 		size:		0x00040000,
-		offset:		0x00000000,
-		mask_flags:	MTD_WRITEABLE
+		offset:		0x00000000
 	}, {
-		name:		"bootloader params",
+		name:		"Parameter Block",
 		size:		0x00040000,
-		offset:		MTDPART_OFS_APPEND,
-		mask_flags:	MTD_WRITEABLE
+		offset:		MTDPART_OFS_APPEND
 	}, {
-		name:		"kernel",
+		name:		"Linux Kernel",
 		size:		0x00100000,
-		offset:		MTDPART_OFS_APPEND,
-		mask_flags:	MTD_WRITEABLE
+		offset:		MTDPART_OFS_APPEND
 	}, {
-		name:		"ramdisk",
-		size:		0x00400000,
-		offset:		MTDPART_OFS_APPEND,
-		mask_flags:	MTD_WRITEABLE
+		name:		"Ramdisk",
+		size:		0x00680000,
+		offset:		MTDPART_OFS_APPEND
 	}, {
-		name:		"file system",
+		name:		"Flash File System",
 		size:		MTDPART_SIZ_FULL,
 		offset:		MTDPART_OFS_APPEND
 	}
@@ -848,6 +844,7 @@
 		sa1100_map.size = FRODO_FLASH_SIZE;
 		base = 0x00000000;
 	}
+#endif
 #ifdef CONFIG_SA1100_GRAPHICSCLIENT
 	if (machine_is_graphicsclient()) {
 		parts = graphicsclient_partitions;
@@ -975,11 +972,11 @@
 		}
 	}
 #endif
-#ifdef CONFIG_MTD_BOOTLDR_PARTS
+#ifdef CONFIG_MTD_CMDLINE_PARTS
 	if (parsed_nr_parts == 0) {
-		int ret = parse_bootldr_partitions(mymtd, &parsed_parts);
+		int ret = parse_cmdline_partitions(mymtd, &parsed_parts, "sa1100");
 		if (ret > 0) {
-			part_type = "Compaq bootldr";
+			part_type = "Command Line";
 			parsed_nr_parts = ret;
 		}
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/maps/sbc_gxx.c linux-2.4.21-pre6/drivers/mtd/maps/sbc_gxx.c
--- linux-2.4.20/drivers/mtd/maps/sbc_gxx.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/maps/sbc_gxx.c	2003-03-26 23:49:40.000000000 +0000
@@ -17,7 +17,7 @@
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 
-   $Id: sbc_gxx.c,v 1.20 2002/02/13 15:30:20 dwmw2 Exp $
+   $Id: sbc_gxx.c,v 1.21 2003/01/24 13:40:14 dwmw2 Exp $
 
 The SBC-MediaGX / SBC-GXx has up to 16 MiB of 
 Intel StrataFlash (28F320/28F640) in x8 mode.  
@@ -26,7 +26,7 @@
 
 The flash is accessed as follows:
 
-   16 kbyte memory window at 0xdc000-0xdffff
+   16 KiB memory window at 0xdc000-0xdffff
    
    Two IO address locations for paging
    
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/maps/scb2_flash.c linux-2.4.21-pre6/drivers/mtd/maps/scb2_flash.c
--- linux-2.4.20/drivers/mtd/maps/scb2_flash.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/maps/scb2_flash.c	2003-03-26 23:49:55.000000000 +0000
@@ -0,0 +1,302 @@
+/*
+ * MTD map driver for BIOS Flash on Intel SCB2 boards
+ * $Id: scb2_flash.c,v 1.2 2003/01/24 13:09:56 dwmw2 Exp $
+ * Copyright (C) 2002 Sun Microsystems, Inc.
+ * Tim Hockin <thockin@sun.com>
+ *
+ * A few notes on this MTD map:
+ *
+ * This was developed with a small number of SCB2 boards to test on.
+ * Hopefully, Intel has not introducted too many unaccounted variables in the
+ * making of this board.
+ *
+ * The BIOS marks its own memory region as 'reserved' in the e820 map.  We
+ * try to request it here, but if it fails, we carry on anyway.
+ *
+ * This is how the chip is attached, so said the schematic:
+ * * a 4 MiB (32 Mb) 16 bit chip
+ * * a 1 MiB memory region
+ * * A20 and A21 pulled up
+ * * D8-D15 ignored
+ * What this means is that, while we are addressing bytes linearly, we are
+ * really addressing words, and discarding the other byte.  This means that
+ * the chip MUST BE at least 2 MiB.  This also means that every block is
+ * actually half as big as the chip reports.  It also means that accesses of
+ * logical address 0 hit higher-address sections of the chip, not physical 0.
+ * One can only hope that these 4MiB x16 chips were a lot cheaper than 1MiB x8
+ * chips.
+ *
+ * This driver assumes the chip is not write-protected by an external signal.
+ * As of the this writing, that is true, but may change, just to spite me.
+ *
+ * The actual BIOS layout has been mostly reverse engineered.  Intel BIOS
+ * updates for this board include 10 related (*.bio - &.bi9) binary files and
+ * another seperate (*.bbo) binary file.  The 10 files are 64k of data + a
+ * small header.  If the headers are stripped off, the 10 64k files can be
+ * concatenated into a 640k image.  This is your BIOS image, proper.  The
+ * seperate .bbo file also has a small header.  It is the 'Boot Block'
+ * recovery BIOS.  Once the header is stripped, no further prep is needed.
+ * As best I can tell, the BIOS is arranged as such:
+ * offset 0x00000 to 0x4ffff (320k):  unknown - SCSI BIOS, etc?
+ * offset 0x50000 to 0xeffff (640k):  BIOS proper
+ * offset 0xf0000 ty 0xfffff (64k):   Boot Block region
+ *
+ * Intel's BIOS update program flashes the BIOS and Boot Block in seperate
+ * steps.  Probably a wise thing to do.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/cfi.h>
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+
+#define MODNAME		"scb2_flash"
+#define SCB2_ADDR	0xfff00000
+#define SCB2_WINDOW	0x00100000
+
+static __u8 scb2_read8(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readb(map->map_priv_1 + ofs);
+}
+
+static __u16 scb2_read16(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readw(map->map_priv_1 + ofs);
+}
+
+static __u32 scb2_read32(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readl(map->map_priv_1 + ofs);
+}
+
+static void scb2_copy_from(struct map_info *map, void *to,
+				 unsigned long from, ssize_t len)
+{
+	memcpy_fromio(to, map->map_priv_1 + from, len);
+}
+
+static void scb2_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+	__raw_writeb(d, map->map_priv_1 + adr);
+	mb();
+}
+
+static void scb2_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+	__raw_writew(d, map->map_priv_1 + adr);
+	mb();
+}
+
+static void scb2_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+	__raw_writel(d, map->map_priv_1 + adr);
+	mb();
+}
+
+static void scb2_copy_to(struct map_info *map, unsigned long to,
+			       const void *from, ssize_t len)
+{
+	memcpy_toio(map->map_priv_1 + to, from, len);
+}
+
+static void *scb2_ioaddr;
+static struct mtd_info *scb2_mtd;
+struct map_info scb2_map = {
+	name:      "SCB2 BIOS Flash",
+	size:      0,
+	buswidth:  1,
+	read8:     scb2_read8,
+	read16:    scb2_read16,
+	read32:    scb2_read32,
+	copy_from: scb2_copy_from,
+	write8:    scb2_write8,
+	write16:   scb2_write16,
+	write32:   scb2_write32,
+	copy_to:   scb2_copy_to,
+};
+static int region_fail;
+
+static int __devinit
+scb2_fixup_mtd(struct mtd_info *mtd)
+{
+	int i;
+	int done = 0;
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+
+	/* barf if this doesn't look right */
+	if (cfi->cfiq->InterfaceDesc != 1) {
+		printk(KERN_ERR MODNAME ": unsupported InterfaceDesc: %#x\n",
+		    cfi->cfiq->InterfaceDesc);
+		return -1;
+	}
+
+	/* the chip is sometimes bigger than the map - what a waste */
+	mtd->size = map->size;
+
+	/*
+	 * We only REALLY get half the chip, due to the way it is
+	 * wired up - D8-D15 are tossed away.  We read linear bytes,
+	 * but in reality we are getting 1/2 of each 16-bit read,
+	 * which LOOKS linear to us.  Because CFI code accounts for
+	 * things like lock/unlock/erase by eraseregions, we need to
+	 * fudge them to reflect this.  Erases go like this:
+	 *   * send an erase to an address
+	 *   * the chip samples the address and erases the block
+	 *   * add the block erasesize to the address and repeat
+	 *   -- the problem is that addresses are 16-bit addressable
+	 *   -- we end up erasing every-other block
+	 */
+	mtd->erasesize /= 2;
+	for (i = 0; i < mtd->numeraseregions; i++) {
+		struct mtd_erase_region_info *region = &mtd->eraseregions[i];
+		region->erasesize /= 2;
+	}
+
+	/*
+	 * If the chip is bigger than the map, it is wired with the high
+	 * address lines pulled up.  This makes us access the top portion of
+	 * the chip, so all our erase-region info is wrong.  Start cutting from
+	 * the bottom.
+	 */
+	for (i = 0; !done && i < mtd->numeraseregions; i++) {
+		struct mtd_erase_region_info *region = &mtd->eraseregions[i];
+
+		if (region->numblocks * region->erasesize > mtd->size) {
+			region->numblocks = (mtd->size / region->erasesize);
+			done = 1;
+		} else {
+			region->numblocks = 0;
+		}
+		region->offset = 0;
+	}
+
+	return 0;
+}
+
+/* CSB5's 'Function Control Register' has bits for decoding @ >= 0xffc00000 */
+#define CSB5_FCR	0x41
+#define CSB5_FCR_DECODE_ALL 0x0e
+static int __devinit
+scb2_flash_probe(struct pci_dev *dev, const struct pci_device_id *ent)
+{
+	u8 reg;
+
+	/* enable decoding of the flash region in the south bridge */
+	pci_read_config_byte(dev, CSB5_FCR, &reg);
+	pci_write_config_byte(dev, CSB5_FCR, reg | CSB5_FCR_DECODE_ALL);
+
+	if (!request_mem_region(SCB2_ADDR, SCB2_WINDOW, scb2_map.name)) {
+		/*
+		 * The BIOS seems to mark the flash region as 'reserved'
+		 * in the e820 map.  Warn and go about our business.
+		 */
+		printk(KERN_WARNING MODNAME
+		    ": warning - can't reserve rom window, continuing\n");
+		region_fail = 1;
+	}
+
+	/* remap the IO window (w/o caching) */
+	scb2_ioaddr = ioremap_nocache(SCB2_ADDR, SCB2_WINDOW);
+	if (!scb2_ioaddr) {
+		printk(KERN_ERR MODNAME ": Failed to ioremap window!\n");
+		if (!region_fail)
+			release_mem_region(SCB2_ADDR, SCB2_WINDOW);
+		return -ENOMEM;
+	}
+
+	scb2_map.map_priv_1 = (unsigned long)scb2_ioaddr;
+	scb2_map.size = SCB2_WINDOW;
+
+	/* try to find a chip */
+	scb2_mtd = do_map_probe("cfi_probe", &scb2_map);
+
+	if (!scb2_mtd) {
+		printk(KERN_ERR MODNAME ": flash probe failed!\n");
+		iounmap(scb2_ioaddr);
+		if (!region_fail)
+			release_mem_region(SCB2_ADDR, SCB2_WINDOW);
+		return -ENODEV;
+	}
+
+	scb2_mtd->module = THIS_MODULE;
+	if (scb2_fixup_mtd(scb2_mtd) < 0) {
+		del_mtd_device(scb2_mtd);
+		map_destroy(scb2_mtd);
+		iounmap(scb2_ioaddr);
+		if (!region_fail)
+			release_mem_region(SCB2_ADDR, SCB2_WINDOW);
+		return -ENODEV;
+	}
+
+	printk(KERN_NOTICE MODNAME ": chip size %x at offset %x\n",
+	       scb2_mtd->size, SCB2_WINDOW - scb2_mtd->size);
+
+	add_mtd_device(scb2_mtd);
+
+	return 0;
+}
+
+static void __devexit
+scb2_flash_remove(struct pci_dev *dev)
+{
+	if (!scb2_mtd)
+		return;
+
+	/* disable flash writes */
+	if (scb2_mtd->lock)
+		scb2_mtd->lock(scb2_mtd, 0, scb2_mtd->size);
+
+	del_mtd_device(scb2_mtd);
+	map_destroy(scb2_mtd);
+
+	iounmap(scb2_ioaddr);
+	scb2_ioaddr = NULL;
+
+	if (!region_fail)
+		release_mem_region(SCB2_ADDR, SCB2_WINDOW);
+	pci_set_drvdata(dev, NULL);
+}
+
+static struct pci_device_id scb2_flash_pci_ids[] __devinitdata = {
+	{
+	  vendor: PCI_VENDOR_ID_SERVERWORKS,
+	  device: PCI_DEVICE_ID_SERVERWORKS_CSB5,
+	  subvendor: PCI_ANY_ID,
+	  subdevice: PCI_ANY_ID
+	},
+	{ 0, }
+};
+
+static struct pci_driver scb2_flash_driver = {
+	name:     "Intel SCB2 BIOS Flash",
+	id_table: scb2_flash_pci_ids,
+	probe:    scb2_flash_probe,
+	remove:   __devexit_p(scb2_flash_remove),
+};
+
+static int __init
+scb2_flash_init(void)
+{
+	return pci_module_init(&scb2_flash_driver);
+}
+
+static void __exit
+scb2_flash_exit(void)
+{
+	pci_unregister_driver(&scb2_flash_driver);
+}
+
+module_init(scb2_flash_init);
+module_exit(scb2_flash_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tim Hockin <thockin@sun.com>");
+MODULE_DESCRIPTION("MTD map driver for Intel SCB2 BIOS Flash");
+MODULE_DEVICE_TABLE(pci, scb2_flash_pci_ids);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/maps/scx200_docflash.c linux-2.4.21-pre6/drivers/mtd/maps/scx200_docflash.c
--- linux-2.4.20/drivers/mtd/maps/scx200_docflash.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/maps/scx200_docflash.c	2003-03-26 23:49:00.000000000 +0000
@@ -0,0 +1,270 @@
+/* linux/drivers/mtd/maps/scx200_docflash.c 
+
+   Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
+
+   $Id: scx200_docflash.c,v 1.1 2003/01/24 13:20:40 dwmw2 Exp $ 
+
+   National Semiconductor SCx200 flash mapped with DOCCS
+*/
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+#include <linux/pci.h>
+#include <linux/scx200.h>
+
+#define NAME "scx200_docflash"
+
+MODULE_AUTHOR("Christer Weinigel <wingel@hack.org>");
+MODULE_DESCRIPTION("NatSemi SCx200 DOCCS Flash Driver");
+MODULE_LICENSE("GPL");
+
+/* Set this to one if you want to partition the flash */
+#define PARTITION 1
+
+MODULE_PARM(probe, "i");
+MODULE_PARM_DESC(probe, "Probe for a BIOS mapping");
+MODULE_PARM(size, "i");
+MODULE_PARM_DESC(size, "Size of the flash mapping");
+MODULE_PARM(width, "i");
+MODULE_PARM_DESC(width, "Data width of the flash mapping (8/16)");
+MODULE_PARM(flashtype, "s");
+MODULE_PARM_DESC(flashtype, "Type of MTD probe to do");
+
+static int probe = 0;		/* Don't autoprobe */
+static unsigned size = 0x1000000; /* 16 MiB the whole ISA address space */
+static unsigned width = 8;	/* Default to 8 bits wide */
+static char *flashtype = "cfi_probe";
+
+static struct resource docmem = {
+	.flags = IORESOURCE_MEM,
+	.name  = "NatSemi SCx200 DOCCS Flash",
+};
+
+static struct mtd_info *mymtd;
+
+#if PARTITION
+static struct mtd_partition partition_info[] = {
+	{ 
+		.name   = "DOCCS Boot kernel", 
+		.offset = 0, 
+		.size   = 0xc0000
+	},
+	{ 
+		.name   = "DOCCS Low BIOS", 
+		.offset = 0xc0000, 
+		.size   = 0x40000
+	},
+	{ 
+		.name   = "DOCCS File system", 
+		.offset = 0x100000, 
+		.size   = ~0	/* calculate from flash size */
+	},
+	{ 
+		.name   = "DOCCS High BIOS", 
+		.offset = ~0, 	/* calculate from flash size */
+		.size   = 0x80000
+	},
+};
+#define NUM_PARTITIONS (sizeof(partition_info)/sizeof(partition_info[0]))
+#endif
+
+static __u8 scx200_docflash_read8(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readb(map->map_priv_1 + ofs);
+}
+
+static __u16 scx200_docflash_read16(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readw(map->map_priv_1 + ofs);
+}
+
+static void scx200_docflash_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	memcpy_fromio(to, map->map_priv_1 + from, len);
+}
+
+static void scx200_docflash_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+	__raw_writeb(d, map->map_priv_1 + adr);
+	mb();
+}
+
+static void scx200_docflash_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+	__raw_writew(d, map->map_priv_1 + adr);
+	mb();
+}
+
+static void scx200_docflash_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	memcpy_toio(map->map_priv_1 + to, from, len);
+}
+
+static struct map_info scx200_docflash_map = {
+	.name      = "NatSemi SCx200 DOCCS Flash",
+	.read8     = scx200_docflash_read8,
+	.read16    = scx200_docflash_read16,
+	.copy_from = scx200_docflash_copy_from,
+	.write8    = scx200_docflash_write8,
+	.write16   = scx200_docflash_write16,
+	.copy_to   = scx200_docflash_copy_to
+};
+
+int __init init_scx200_docflash(void)
+{
+	unsigned u;
+	unsigned base;
+	unsigned ctrl;
+	unsigned pmr;
+	struct pci_dev *bridge;
+
+	printk(KERN_DEBUG NAME ": NatSemi SCx200 DOCCS Flash Driver\n");
+
+	if ((bridge = pci_find_device(PCI_VENDOR_ID_NS, 
+				      PCI_DEVICE_ID_NS_SCx200_BRIDGE,
+				      NULL)) == NULL)
+		return -ENODEV;
+	
+	if (!scx200_cb_probe(SCx200_CB_BASE)) {
+		printk(KERN_WARNING NAME ": no configuration block found\n");
+		return -ENODEV;
+	}
+
+	if (probe) {
+		/* Try to use the present flash mapping if any */
+		pci_read_config_dword(bridge, SCx200_DOCCS_BASE, &base);
+		pci_read_config_dword(bridge, SCx200_DOCCS_CTRL, &ctrl);
+		pmr = inl(SCx200_CB_BASE + SCx200_PMR);
+
+		if (base == 0
+		    || (ctrl & 0x07000000) != 0x07000000
+		    || (ctrl & 0x0007ffff) == 0)
+			return -ENODEV;
+
+		size = ((ctrl&0x1fff)<<13) + (1<<13);
+
+		for (u = size; u > 1; u >>= 1)
+			;
+		if (u != 1)
+			return -ENODEV;
+
+		if (pmr & (1<<6))
+			width = 16;
+		else
+			width = 8;
+
+		docmem.start = base;
+		docmem.end = base + size;
+
+		if (request_resource(&iomem_resource, &docmem)) {
+			printk(KERN_ERR NAME ": unable to allocate memory for flash mapping\n");
+			return -ENOMEM;
+		}
+	} else {
+		for (u = size; u > 1; u >>= 1)
+			;
+		if (u != 1) {
+			printk(KERN_ERR NAME ": invalid size for flash mapping\n");
+			return -EINVAL;
+		}
+		
+		if (width != 8 && width != 16) {
+			printk(KERN_ERR NAME ": invalid bus width for flash mapping\n");
+			return -EINVAL;
+		}
+		
+		if (allocate_resource(&iomem_resource, &docmem, 
+				      size,
+				      0xc0000000, 0xffffffff, 
+				      size, NULL, NULL)) {
+			printk(KERN_ERR NAME ": unable to allocate memory for flash mapping\n");
+			return -ENOMEM;
+		}
+		
+		ctrl = 0x07000000 | ((size-1) >> 13);
+
+		printk(KERN_INFO "DOCCS BASE=0x%08lx, CTRL=0x%08lx\n", (long)docmem.start, (long)ctrl);
+		
+		pci_write_config_dword(bridge, SCx200_DOCCS_BASE, docmem.start);
+		pci_write_config_dword(bridge, SCx200_DOCCS_CTRL, ctrl);
+		pmr = inl(SCx200_CB_BASE + SCx200_PMR);
+		
+		if (width == 8) {
+			pmr &= ~(1<<6);
+		} else {
+			pmr |= (1<<6);
+		}
+		outl(pmr, SCx200_CB_BASE + SCx200_PMR);
+	}
+	
+       	printk(KERN_INFO NAME ": DOCCS mapped at 0x%lx-0x%lx, width %d\n", 
+	       docmem.start, docmem.end, width);
+
+	scx200_docflash_map.size = size;
+	if (width == 8)
+		scx200_docflash_map.buswidth = 1;
+	else
+		scx200_docflash_map.buswidth = 2;
+
+	scx200_docflash_map.map_priv_1 = (unsigned long)ioremap(docmem.start, scx200_docflash_map.size);
+	if (!scx200_docflash_map.map_priv_1) {
+		printk(KERN_ERR NAME ": failed to ioremap the flash\n");
+		release_resource(&docmem);
+		return -EIO;
+	}
+
+	mymtd = do_map_probe(flashtype, &scx200_docflash_map);
+	if (!mymtd) {
+		printk(KERN_ERR NAME ": unable to detect flash\n");
+		iounmap((void *)scx200_docflash_map.map_priv_1);
+		release_resource(&docmem);
+		return -ENXIO;
+	}
+
+	if (size < mymtd->size)
+		printk(KERN_WARNING NAME ": warning, flash mapping is smaller than flash size\n");
+
+	mymtd->module = THIS_MODULE;
+
+#if PARTITION
+	partition_info[3].offset = mymtd->size-partition_info[3].size;
+	partition_info[2].size = partition_info[3].offset-partition_info[2].offset;
+	add_mtd_partitions(mymtd, partition_info, NUM_PARTITIONS);
+#else
+	add_mtd_device(mymtd);
+#endif
+	return 0;
+}
+
+static void __exit cleanup_scx200_docflash(void)
+{
+	if (mymtd) {
+#if PARTITION
+		del_mtd_partitions(mymtd);
+#else
+		del_mtd_device(mymtd);
+#endif
+		map_destroy(mymtd);
+	}
+	if (scx200_docflash_map.map_priv_1) {
+		iounmap((void *)scx200_docflash_map.map_priv_1);
+		release_resource(&docmem);
+	}
+}
+
+module_init(init_scx200_docflash);
+module_exit(cleanup_scx200_docflash);
+
+/*
+    Local variables:
+        compile-command: "make -k -C ../../.. SUBDIRS=drivers/mtd/maps modules"
+        c-basic-offset: 8
+    End:
+*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/maps/tqm8xxl.c linux-2.4.21-pre6/drivers/mtd/maps/tqm8xxl.c
--- linux-2.4.20/drivers/mtd/maps/tqm8xxl.c	2001-10-04 22:14:59.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/maps/tqm8xxl.c	2003-03-26 23:49:09.000000000 +0000
@@ -2,7 +2,7 @@
  * Handle mapping of the flash memory access routines 
  * on TQM8xxL based devices.
  *
- * $Id: tqm8xxl.c,v 1.3 2001/10/02 15:05:14 dwmw2 Exp $
+ * $Id: tqm8xxl.c,v 1.4 2002/06/20 13:41:20 mag Exp $
  *
  * based on rpxlite.c
  *
@@ -91,20 +91,6 @@
 	memcpy_toio((void *)(map->map_priv_1 + to), from, len);
 }
 
-struct map_info tqm8xxl_map = {
-	name: "TQM8xxL",
-	//size: WINDOW_SIZE,
-	buswidth: 4,
-	read8: tqm8xxl_read8,
-	read16: tqm8xxl_read16,
-	read32: tqm8xxl_read32,
-	copy_from: tqm8xxl_copy_from,
-	write8: tqm8xxl_write8,
-	write16: tqm8xxl_write16,
-	write32: tqm8xxl_write32,
-	copy_to: tqm8xxl_copy_to
-};
-
 /*
  * Here are partition information for all known TQM8xxL series devices.
  * See include/linux/mtd/partitions.h for definition of the mtd_partition
@@ -204,8 +190,9 @@
 			goto error_mem;
 		}
 		memset((void *)map_banks[idx]->name, 0, 16);
-		
+
 		sprintf(map_banks[idx]->name, "TQM8xxL%d", idx);
+		map_banks[idx]->size = flash_size;
 		map_banks[idx]->buswidth = 4;
 		map_banks[idx]->read8 = tqm8xxl_read8;
 		map_banks[idx]->read16 = tqm8xxl_read16;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/maps/uclinux.c linux-2.4.21-pre6/drivers/mtd/maps/uclinux.c
--- linux-2.4.20/drivers/mtd/maps/uclinux.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/maps/uclinux.c	2003-03-26 23:49:02.000000000 +0000
@@ -0,0 +1,172 @@
+/****************************************************************************/
+
+/*
+ *	uclinux.c -- generic memory mapped MTD driver for uclinux
+ *
+ *	(C) Copyright 2002, Greg Ungerer (gerg@snapgear.com)
+ *
+ * 	$Id: uclinux.c,v 1.2 2002/08/07 00:43:45 gerg Exp $
+ */
+
+/****************************************************************************/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/major.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <asm/io.h>
+
+/****************************************************************************/
+
+__u8 uclinux_read8(struct map_info *map, unsigned long ofs)
+{
+	return(*((__u8 *) (map->map_priv_1 + ofs)));
+}
+
+__u16 uclinux_read16(struct map_info *map, unsigned long ofs)
+{
+	return(*((__u16 *) (map->map_priv_1 + ofs)));
+}
+
+__u32 uclinux_read32(struct map_info *map, unsigned long ofs)
+{
+	return(*((__u32 *) (map->map_priv_1 + ofs)));
+}
+
+void uclinux_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	memcpy(to, (void *)(map->map_priv_1 + from), len);
+}
+
+void uclinux_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+	*((__u8 *) (map->map_priv_1 + adr)) = d;
+}
+
+void uclinux_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+	*((__u16 *) (map->map_priv_1 + adr)) = d;
+}
+
+void uclinux_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+	*((__u32 *) (map->map_priv_1 + adr)) = d;
+}
+
+void uclinux_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	memcpy((void *) (map->map_priv_1 + to), from, len);
+}
+
+/****************************************************************************/
+
+struct map_info uclinux_ram_map = {
+	name:		"RAM",
+	read8:		uclinux_read8,
+	read16:		uclinux_read16,
+	read32:		uclinux_read32,
+	copy_from:	uclinux_copy_from,
+	write8:		uclinux_write8,
+	write16:	uclinux_write16,
+	write32:	uclinux_write32,
+	copy_to:	uclinux_copy_to,
+};
+
+struct mtd_info *uclinux_ram_mtdinfo;
+
+/****************************************************************************/
+
+struct mtd_partition uclinux_romfs[] = {
+	{ name: "ROMfs", offset: 0 }
+};
+
+#define	NUM_PARTITIONS	(sizeof(uclinux_romfs) / sizeof(uclinux_romfs[0]))
+
+/****************************************************************************/
+
+int uclinux_point(struct mtd_info *mtd, loff_t from, size_t len,
+	size_t *retlen, u_char **mtdbuf)
+{
+	struct map_info *map = (struct map_info *) mtd->priv;
+	*mtdbuf = (u_char *) (map->map_priv_1 + ((int) from));
+	*retlen = len;
+	return(0);
+}
+
+/****************************************************************************/
+
+int __init uclinux_mtd_init(void)
+{
+	struct mtd_info *mtd;
+	struct map_info *mapp;
+	extern char _ebss;
+
+	mapp = &uclinux_ram_map;
+	mapp->map_priv_2 = (unsigned long) &_ebss;
+	mapp->size = PAGE_ALIGN(*((unsigned long *)((&_ebss) + 8)));
+	mapp->buswidth = 4;
+
+	printk("uclinux[mtd]: RAM probe address=0x%x size=0x%x\n",
+	       	(int) mapp->map_priv_2, (int) mapp->size);
+
+	mapp->map_priv_1 = (unsigned long)
+		ioremap_nocache(mapp->map_priv_2, mapp->size);
+
+	if (mapp->map_priv_1 == 0) {
+		printk("uclinux[mtd]: ioremap_nocache() failed\n");
+		return(-EIO);
+	}
+
+	mtd = do_map_probe("map_ram", mapp);
+	if (!mtd) {
+		printk("uclinux[mtd]: failed to find a mapping?\n");
+		iounmap((void *) mapp->map_priv_1);
+		return(-ENXIO);
+	}
+		
+	mtd->module = THIS_MODULE;
+	mtd->point = uclinux_point;
+	mtd->priv = mapp;
+
+	uclinux_ram_mtdinfo = mtd;
+	add_mtd_partitions(mtd, uclinux_romfs, NUM_PARTITIONS);
+
+	printk("uclinux[mtd]: set %s to be root filesystem\n",
+	     	uclinux_romfs[0].name);
+	ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, 0);
+	put_mtd_device(mtd);
+
+	return(0);
+}
+
+/****************************************************************************/
+
+void __exit uclinux_mtd_cleanup(void)
+{
+	if (uclinux_ram_mtdinfo) {
+		del_mtd_partitions(uclinux_ram_mtdinfo);
+		map_destroy(uclinux_ram_mtdinfo);
+		uclinux_ram_mtdinfo = NULL;
+	}
+	if (uclinux_ram_map.map_priv_1) {
+		iounmap((void *) uclinux_ram_map.map_priv_1);
+		uclinux_ram_map.map_priv_1 = 0;
+	}
+}
+
+/****************************************************************************/
+
+module_init(uclinux_mtd_init);
+module_exit(uclinux_mtd_cleanup);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com>");
+MODULE_DESCRIPTION("Generic RAM based MTD for uClinux");
+
+/****************************************************************************/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/mtdblock.c linux-2.4.21-pre6/drivers/mtd/mtdblock.c
--- linux-2.4.20/drivers/mtd/mtdblock.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/mtdblock.c	2003-03-26 23:49:29.000000000 +0000
@@ -311,6 +311,7 @@
 	if (mtdblks[dev]) {
 		mtdblks[dev]->count++;
 		spin_unlock(&mtdblks_lock);
+		put_mtd_device(mtd);
 		return 0;
 	}
 	
@@ -432,7 +433,7 @@
 		res = 0;
 
 		if (MINOR(req->rq_dev) >= MAX_MTD_DEVICES)
-			panic(__FUNCTION__": minor out of bound");
+			panic("%s: minor out of bounds", __FUNCTION__);
 
 		if ((req->sector + req->current_nr_sectors) > (mtdblk->mtd->size >> 9))
 			goto end_req;
@@ -483,20 +484,14 @@
 	struct task_struct *tsk = current;
 	DECLARE_WAITQUEUE(wait, tsk);
 
-	tsk->session = 1;
-	tsk->pgrp = 1;
 	/* we might get involved when memory gets low, so use PF_MEMALLOC */
 	tsk->flags |= PF_MEMALLOC;
 	strcpy(tsk->comm, "mtdblockd");
-	tsk->tty = NULL;
 	spin_lock_irq(&tsk->sigmask_lock);
 	sigfillset(&tsk->blocked);
 	recalc_sigpending(tsk);
 	spin_unlock_irq(&tsk->sigmask_lock);
-	exit_mm(tsk);
-	exit_files(tsk);
-	exit_sighand(tsk);
-	exit_fs(tsk);
+	daemonize();
 
 	while (!leaving) {
 		add_wait_queue(&thr_wq, &wait);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/mtdblock_ro.c linux-2.4.21-pre6/drivers/mtd/mtdblock_ro.c
--- linux-2.4.20/drivers/mtd/mtdblock_ro.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/mtdblock_ro.c	2003-03-26 23:49:38.000000000 +0000
@@ -138,10 +138,11 @@
       }
 
       if (current_request->sector << 9 > mtd->size ||
-	  (current_request->sector + current_request->nr_sectors) << 9 > mtd->size)
+	  (current_request->sector + current_request->current_nr_sectors) << 9 > mtd->size)
       {
 	 printk("mtd: Attempt to read past end of device!\n");
-	 printk("size: %x, sector: %lx, nr_sectors %lx\n", mtd->size, current_request->sector, current_request->nr_sectors);
+	 printk("size: %x, sector: %lx, nr_sectors %lx\n", mtd->size, 
+		current_request->sector, current_request->current_nr_sectors);
 	 end_request(0);
 	 continue;
       }
@@ -162,7 +163,7 @@
 
 	 case READ:
 	 if (MTD_READ(mtd,current_request->sector<<9, 
-		      current_request->nr_sectors << 9, 
+		      current_request->current_nr_sectors << 9, 
 		      &retlen, current_request->buffer) == 0)
 	    res = 1;
 	 else
@@ -172,7 +173,7 @@
 	 case WRITE:
 
 	 /* printk("mtdblock_request WRITE sector=%d(%d)\n",current_request->sector,
-		current_request->nr_sectors);
+		current_request->current_nr_sectors);
 	 */
 
 	 // Read only device
@@ -184,7 +185,7 @@
 
 	 // Do the write
 	 if (MTD_WRITE(mtd,current_request->sector<<9, 
-		       current_request->nr_sectors << 9, 
+		       current_request->current_nr_sectors << 9, 
 		       &retlen, current_request->buffer) == 0)
 	    res = 1;
 	 else
@@ -287,7 +288,7 @@
 static void __exit cleanup_mtdblock(void)
 {
 	unregister_blkdev(MAJOR_NR,DEVICE_NAME);
-	blksize_size[MAJOR_NR] = NULL;
+	blk_size[MAJOR_NR] = NULL;
 	blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/mtdchar.c linux-2.4.21-pre6/drivers/mtd/mtdchar.c
--- linux-2.4.20/drivers/mtd/mtdchar.c	2001-10-04 22:14:59.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/mtdchar.c	2003-03-26 23:49:50.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * $Id: mtdchar.c,v 1.44 2001/10/02 15:05:11 dwmw2 Exp $
+ * $Id: mtdchar.c,v 1.49 2003/01/24 12:02:58 dwmw2 Exp $
  *
  * Character-device access to raw MTD devices.
  * Pure 2.4 version - compatibility cruft removed to mtdchar-compat.c
@@ -60,7 +60,7 @@
 
 static int mtd_open(struct inode *inode, struct file *file)
 {
-	int minor = MINOR(inode->i_rdev);
+	int minor = minor(inode->i_rdev);
 	int devnum = minor >> 1;
 	struct mtd_info *mtd;
 
@@ -287,7 +287,12 @@
 
 	case MEMERASE:
 	{
-		struct erase_info *erase=kmalloc(sizeof(struct erase_info),GFP_KERNEL);
+		struct erase_info *erase;
+
+		if(!(file->f_mode & 2))
+			return -EPERM;
+
+		erase=kmalloc(sizeof(struct erase_info),GFP_KERNEL);
 		if (!erase)
 			ret = -ENOMEM;
 		else {
@@ -338,6 +343,9 @@
 		void *databuf;
 		ssize_t retlen;
 		
+		if(!(file->f_mode & 2))
+			return -EPERM;
+
 		if (copy_from_user(&buf, (struct mtd_oob_buf *)arg, sizeof(struct mtd_oob_buf)))
 			return -EFAULT;
 		
@@ -434,6 +442,80 @@
 		break;
 	}
 
+	case MEMWRITEDATA:
+	{
+		struct mtd_oob_buf buf;
+		void *databuf;
+		ssize_t retlen;
+		
+		if (copy_from_user(&buf, (struct mtd_oob_buf *)arg, sizeof(struct mtd_oob_buf)))
+			return -EFAULT;
+		
+		if (buf.length > 0x4096)
+			return -EINVAL;
+
+		if (!mtd->write_ecc)
+			ret = -EOPNOTSUPP;
+		else
+			ret = verify_area(VERIFY_READ, (char *)buf.ptr, buf.length);
+
+		if (ret)
+			return ret;
+
+		databuf = kmalloc(buf.length, GFP_KERNEL);
+		if (!databuf)
+			return -ENOMEM;
+		
+		if (copy_from_user(databuf, buf.ptr, buf.length)) {
+			kfree(databuf);
+			return -EFAULT;
+		}
+
+		ret = (mtd->write_ecc)(mtd, buf.start, buf.length, &retlen, databuf, NULL, 0);
+
+		if (copy_to_user((void *)arg + sizeof(u_int32_t), &retlen, sizeof(u_int32_t)))
+			ret = -EFAULT;
+
+		kfree(databuf);
+		break;
+
+	}
+
+	case MEMREADDATA:
+	{
+		struct mtd_oob_buf buf;
+		void *databuf;
+		ssize_t retlen = 0;
+
+		if (copy_from_user(&buf, (struct mtd_oob_buf *)arg, sizeof(struct mtd_oob_buf)))
+			return -EFAULT;
+		
+		if (buf.length > 0x4096)
+			return -EINVAL;
+
+		if (!mtd->read_ecc)
+			ret = -EOPNOTSUPP;
+		else
+			ret = verify_area(VERIFY_WRITE, (char *)buf.ptr, buf.length);
+
+		if (ret)
+			return ret;
+
+		databuf = kmalloc(buf.length, GFP_KERNEL);
+		if (!databuf)
+			return -ENOMEM;
+		
+		ret = (mtd->read_ecc)(mtd, buf.start, buf.length, &retlen, databuf, NULL, 0);
+
+		if (copy_to_user((void *)arg + sizeof(u_int32_t), &retlen, sizeof(u_int32_t)))
+			ret = -EFAULT;
+		else if (retlen && copy_to_user(buf.ptr, databuf, retlen))
+			ret = -EFAULT;
+		
+		kfree(databuf);
+		break;
+	}
+
 		
 	default:
 		DEBUG(MTD_DEBUG_LEVEL0, "Invalid ioctl %x (MEMGETINFO = %x)\n", cmd, MEMGETINFO);
@@ -474,7 +556,7 @@
 	sprintf(name, "%dro", mtd->index);
 	devfs_ro_handle[mtd->index] = devfs_register(devfs_dir_handle, name,
 			DEVFS_FL_DEFAULT, MTD_CHAR_MAJOR, mtd->index*2+1,
-			S_IFCHR | S_IRUGO | S_IWUGO,
+			S_IFCHR | S_IRUGO,
 			&mtd_fops, NULL);
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/mtdconcat.c linux-2.4.21-pre6/drivers/mtd/mtdconcat.c
--- linux-2.4.20/drivers/mtd/mtdconcat.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/mtdconcat.c	2003-03-26 23:49:10.000000000 +0000
@@ -5,7 +5,7 @@
  *
  * This code is GPL
  *
- * $Id: mtdconcat.c,v 1.2 2002/03/22 08:45:22 dwmw2 Exp $
+ * $Id: mtdconcat.c,v 1.3 2002/05/21 21:04:25 dwmw2 Exp $
  */
 
 #include <linux/module.h>
@@ -303,11 +303,14 @@
 		 */
 		erase->addr = 0;
 	}
+	kfree(erase);
+	if (err)
+		return err;
+
 	instr->state = MTD_ERASE_DONE;
 	if (instr->callback)
 		instr->callback(instr);
-	kfree(erase);
-	return err;
+	return 0;
 }
 
 static int concat_lock (struct mtd_info *mtd, loff_t ofs, size_t len)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/mtdcore.c linux-2.4.21-pre6/drivers/mtd/mtdcore.c
--- linux-2.4.20/drivers/mtd/mtdcore.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/mtdcore.c	2003-03-26 23:49:37.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * $Id: mtdcore.c,v 1.32 2002/03/07 18:38:10 joern Exp $
+ * $Id: mtdcore.c,v 1.34 2003/01/24 23:32:25 dwmw2 Exp $
  *
  * Core registration and callback routines for MTD
  * drivers and users.
@@ -17,7 +17,6 @@
 #include <linux/major.h>
 #include <linux/fs.h>
 #include <linux/ioctl.h>
-#include <stdarg.h>
 #include <linux/mtd/compatmac.h>
 #ifdef CONFIG_PROC_FS
 #include <linux/proc_fs.h>
@@ -203,11 +202,74 @@
 	return ret;
 }
 
+
+/* default_mtd_writev - default mtd writev method for MTD devices that
+ *			dont implement their own
+ */
+
+int default_mtd_writev(struct mtd_info *mtd, const struct iovec *vecs,
+		       unsigned long count, loff_t to, size_t *retlen)
+{
+	unsigned long i;
+	size_t totlen = 0, thislen;
+	int ret = 0;
+
+	if(!mtd->write) {
+		ret = -EROFS;
+	} else {
+		for (i=0; i<count; i++) {
+			if (!vecs[i].iov_len)
+				continue;
+			ret = mtd->write(mtd, to, vecs[i].iov_len, &thislen, vecs[i].iov_base);
+			totlen += thislen;
+			if (ret || thislen != vecs[i].iov_len)
+				break;
+			to += vecs[i].iov_len;
+		}
+	}
+	if (retlen)
+		*retlen = totlen;
+	return ret;
+}
+
+
+/* default_mtd_readv - default mtd readv method for MTD devices that dont
+ *		       implement their own
+ */
+
+int default_mtd_readv(struct mtd_info *mtd, struct iovec *vecs,
+		      unsigned long count, loff_t from, size_t *retlen)
+{
+	unsigned long i;
+	size_t totlen = 0, thislen;
+	int ret = 0;
+
+	if(!mtd->read) {
+		ret = -EIO;
+	} else {
+		for (i=0; i<count; i++) {
+			if (!vecs[i].iov_len)
+				continue;
+			ret = mtd->read(mtd, from, vecs[i].iov_len, &thislen, vecs[i].iov_base);
+			totlen += thislen;
+			if (ret || thislen != vecs[i].iov_len)
+				break;
+			from += vecs[i].iov_len;
+		}
+	}
+	if (retlen)
+		*retlen = totlen;
+	return ret;
+}
+
+
 EXPORT_SYMBOL(add_mtd_device);
 EXPORT_SYMBOL(del_mtd_device);
 EXPORT_SYMBOL(__get_mtd_device);
 EXPORT_SYMBOL(register_mtd_user);
 EXPORT_SYMBOL(unregister_mtd_user);
+EXPORT_SYMBOL(default_mtd_writev);
+EXPORT_SYMBOL(default_mtd_readv);
 
 /*====================================================================*/
 /* Power management code */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/mtdpart.c linux-2.4.21-pre6/drivers/mtd/mtdpart.c
--- linux-2.4.20/drivers/mtd/mtdpart.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/mtdpart.c	2003-03-26 23:49:10.000000000 +0000
@@ -5,8 +5,7 @@
  *
  * This code is GPL
  *
- * $Id: mtdpart.c,v 1.27 2002/03/08 16:34:35 rkaiser Exp $
- * - with protection register access removed until that code is merged in 2.4.
+ * $Id: mtdpart.c,v 1.32 2002/10/21 13:40:05 jocke Exp $
  *
  * 	02-21-2002	Thomas Gleixner <gleixner@autronix.de>
  *			added support for read_oob, write_oob
@@ -59,6 +58,37 @@
 					len, retlen, buf);
 }
 
+static int part_point (struct mtd_info *mtd, loff_t from, size_t len, 
+			size_t *retlen, u_char **buf)
+{
+	struct mtd_part *part = PART(mtd);
+	if (from >= mtd->size)
+		len = 0;
+	else if (from + len > mtd->size)
+		len = mtd->size - from;
+	return part->master->point (part->master, from + part->offset, 
+				    len, retlen, buf);
+}
+static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
+{
+	struct mtd_part *part = PART(mtd);
+
+	part->master->unpoint (part->master, addr, from + part->offset, len);
+}
+
+
+static int part_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, 
+			size_t *retlen, u_char *buf, u_char *eccbuf, int oobsel)
+{
+	struct mtd_part *part = PART(mtd);
+	if (from >= mtd->size)
+		len = 0;
+	else if (from + len > mtd->size)
+		len = mtd->size - from;
+	return part->master->read_ecc (part->master, from + part->offset, 
+					len, retlen, buf, eccbuf, oobsel);
+}
+
 static int part_read_oob (struct mtd_info *mtd, loff_t from, size_t len, 
 			size_t *retlen, u_char *buf)
 {
@@ -71,6 +101,22 @@
 					len, retlen, buf);
 }
 
+static int part_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, 
+			size_t *retlen, u_char *buf)
+{
+	struct mtd_part *part = PART(mtd);
+	return part->master->read_user_prot_reg (part->master, from, 
+					len, retlen, buf);
+}
+
+static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, 
+			size_t *retlen, u_char *buf)
+{
+	struct mtd_part *part = PART(mtd);
+	return part->master->read_user_prot_reg (part->master, from, 
+					len, retlen, buf);
+}
+
 static int part_write (struct mtd_info *mtd, loff_t to, size_t len,
 			size_t *retlen, const u_char *buf)
 {
@@ -85,6 +131,21 @@
 					len, retlen, buf);
 }
 
+static int part_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
+			size_t *retlen, const u_char *buf,
+			 u_char *eccbuf, int oobsel)
+{
+	struct mtd_part *part = PART(mtd);
+	if (!(mtd->flags & MTD_WRITEABLE))
+		return -EROFS;
+	if (to >= mtd->size)
+		len = 0;
+	else if (to + len > mtd->size)
+		len = mtd->size - to;
+	return part->master->write_ecc (part->master, to + part->offset, 
+					len, retlen, buf, eccbuf, oobsel);
+}
+
 static int part_write_oob (struct mtd_info *mtd, loff_t to, size_t len,
 			size_t *retlen, const u_char *buf)
 {
@@ -99,6 +160,14 @@
 					len, retlen, buf);
 }
 
+static int part_write_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, 
+			size_t *retlen, u_char *buf)
+{
+	struct mtd_part *part = PART(mtd);
+	return part->master->write_user_prot_reg (part->master, from, 
+					len, retlen, buf);
+}
+
 static int part_writev (struct mtd_info *mtd,  const struct iovec *vecs,
 			 unsigned long count, loff_t to, size_t *retlen)
 {
@@ -117,6 +186,28 @@
 					from + part->offset, retlen);
 }
 
+static int part_writev_ecc (struct mtd_info *mtd,  const struct iovec *vecs,
+			 unsigned long count, loff_t to, size_t *retlen,
+			 u_char *eccbuf, int oobsel)
+{
+	struct mtd_part *part = PART(mtd);
+	if (!(mtd->flags & MTD_WRITEABLE))
+		return -EROFS;
+	return part->master->writev_ecc (part->master, vecs, count,
+					to + part->offset, retlen,
+					eccbuf, oobsel);
+}
+
+static int part_readv_ecc (struct mtd_info *mtd,  struct iovec *vecs,
+			 unsigned long count, loff_t from, size_t *retlen,
+			 u_char *eccbuf, int oobsel)
+{
+	struct mtd_part *part = PART(mtd);
+	return part->master->readv_ecc (part->master, vecs, count,
+					from + part->offset, retlen, 
+					eccbuf, oobsel);
+}
+
 static int part_erase (struct mtd_info *mtd, struct erase_info *instr)
 {
 	struct mtd_part *part = PART(mtd);
@@ -235,10 +326,25 @@
 		slave->mtd.read = part_read;
 		slave->mtd.write = part_write;
 
+		if(master->point && master->unpoint){
+			slave->mtd.point = part_point;
+			slave->mtd.unpoint = part_unpoint;
+		}
+		
+		if (master->read_ecc)
+			slave->mtd.read_ecc = part_read_ecc;
+		if (master->write_ecc)
+			slave->mtd.write_ecc = part_write_ecc;
 		if (master->read_oob)
 			slave->mtd.read_oob = part_read_oob;
 		if (master->write_oob)
 			slave->mtd.write_oob = part_write_oob;
+		if(master->read_user_prot_reg)
+			slave->mtd.read_user_prot_reg = part_read_user_prot_reg;
+		if(master->read_fact_prot_reg)
+			slave->mtd.read_fact_prot_reg = part_read_fact_prot_reg;
+		if(master->write_user_prot_reg)
+			slave->mtd.write_user_prot_reg = part_write_user_prot_reg;
 		if (master->sync)
 			slave->mtd.sync = part_sync;
 		if (!i && master->suspend && master->resume) {
@@ -249,6 +355,10 @@
 			slave->mtd.writev = part_writev;
 		if (master->readv)
 			slave->mtd.readv = part_readv;
+		if (master->writev_ecc)
+			slave->mtd.writev_ecc = part_writev_ecc;
+		if (master->readv_ecc)
+			slave->mtd.readv_ecc = part_readv_ecc;
 		if (master->lock)
 			slave->mtd.lock = part_lock;
 		if (master->unlock)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/nand/Config.in linux-2.4.21-pre6/drivers/mtd/nand/Config.in
--- linux-2.4.20/drivers/mtd/nand/Config.in	2001-10-04 22:13:18.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/nand/Config.in	2003-03-26 23:49:51.000000000 +0000
@@ -1,6 +1,6 @@
 # drivers/mtd/nand/Config.in
 
-# $Id: Config.in,v 1.4 2001/09/19 09:35:23 dwmw2 Exp $
+# $Id: Config.in,v 1.11 2002/12/01 13:23:05 gleixner Exp $
 
 mainmenu_option next_comment
 
@@ -8,11 +8,29 @@
 
 dep_tristate '  NAND Device Support' CONFIG_MTD_NAND $CONFIG_MTD
 if [ "$CONFIG_MTD_NAND" = "y" -o "$CONFIG_MTD_NAND" = "m" ]; then
-   bool '    Enable ECC correction algorithm'  CONFIG_MTD_NAND_ECC
    bool '    Verify NAND page writes' CONFIG_MTD_NAND_VERIFY_WRITE
 fi
+
 if [ "$CONFIG_ARM" = "y" -a "$CONFIG_ARCH_P720T" = "y" ]; then
    dep_tristate '  NAND Flash device on SPIA board' CONFIG_MTD_NAND_SPIA $CONFIG_MTD_NAND
 fi
 
+if [ "$CONFIG_ARCH_AUTCPU12" = "y" ]; then
+   dep_tristate ' SmartMedia Card on AUTCPU12 board' CONFIG_MTD_NAND_AUTCPU12 $CONFIG_MTD_NAND
+fi
+
+if [ "$CONFIG_ARCH_EDB7312" = "y" ]; then
+   dep_tristate '  NAND Flash device on EDP7312 board' CONFIG_MTD_NAND_EDB7312 $CONFIG_MTD_NAND
+fi
+
+if [ "$CONFIG_MTD_DOC2001" = "y" -o "$CONFIG_MTD_DOC2000" = "y" -o "$CONFIG_MTD_NAND" = "y" ]; then
+   define_bool CONFIG_MTD_NAND_IDS y
+fi
+
+if [ "$CONFIG_MTD_NAND_IDS" != "y" ]; then
+if [ "$CONFIG_MTD_DOC2001" = "m" -o "$CONFIG_MTD_DOC2000" = "m" -o "$CONFIG_MTD_NAND" = "m" ]; then
+   define_bool CONFIG_MTD_NAND_IDS m
+fi
+fi
+
 endmenu
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/nand/Makefile linux-2.4.21-pre6/drivers/mtd/nand/Makefile
--- linux-2.4.20/drivers/mtd/nand/Makefile	2001-10-04 22:13:18.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/nand/Makefile	2003-03-26 23:48:58.000000000 +0000
@@ -1,16 +1,16 @@
 #
 # linux/drivers/nand/Makefile
 #
-# $Id: Makefile,v 1.5 2001/09/19 22:39:59 dwmw2 Exp $
+# $Id: Makefile,v 1.10 2002/12/01 13:23:05 gleixner Exp $
 
 O_TARGET	:= nandlink.o
 
-export-objs	:= nand.o nand_ecc.o
+export-objs	:= nand.o nand_ecc.o nand_ids.o
 
-nandobjs-y			:= nand.o
-nandobjs-$(CONFIG_MTD_NAND_ECC) += nand_ecc.o
-
-obj-$(CONFIG_MTD_NAND)		+= $(nandobjs-y)
+obj-$(CONFIG_MTD_NAND)		+= nand.o nand_ecc.o
 obj-$(CONFIG_MTD_NAND_SPIA)	+= spia.o
+obj-$(CONFIG_MTD_NAND_AUTCPU12)	+= autcpu12.o
+obj-$(CONFIG_MTD_NAND_EDB7312)  += edb7312.o
+obj-$(CONFIG_MTD_NAND_IDS)	+= nand_ids.o
 
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/nand/autcpu12.c linux-2.4.21-pre6/drivers/mtd/nand/autcpu12.c
--- linux-2.4.20/drivers/mtd/nand/autcpu12.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/nand/autcpu12.c	2003-03-26 23:49:40.000000000 +0000
@@ -0,0 +1,266 @@
+/*
+ *  drivers/mtd/autcpu12.c
+ *
+ *  Copyright (c) 2002 Thomas Gleixner <tgxl@linutronix.de>
+ *
+ *  Derived from drivers/mtd/spia.c
+ * 	 Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
+ * 
+ * $Id: autcpu12.c,v 1.6 2002/11/11 15:47:56 gleixner Exp $
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  Overview:
+ *   This is a device driver for the NAND flash device found on the
+ *   autronix autcpu12 board, which is a SmartMediaCard. It supports 
+ *   16MB, 32MB and 64MB cards.
+ *
+ *
+ *	02-12-2002 TG	Cleanup of module params
+ *
+ *	02-20-2002 TG	adjusted for different rd/wr adress support
+ *			added support for read device ready/busy line
+ *			added page_cache
+ *
+ *	10-06-2002 TG	128K card support added
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <asm/io.h>
+#include <asm/arch/hardware.h>
+#include <asm/sizes.h>
+#include <asm/arch/autcpu12.h>
+
+/*
+ * MTD structure for AUTCPU12 board
+ */
+static struct mtd_info *autcpu12_mtd = NULL;
+
+/*
+ * Module stuff
+ */
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
+#define autcpu12_init init_module
+#define autcpu12_cleanup cleanup_module
+#endif
+
+static int autcpu12_io_base = CS89712_VIRT_BASE;
+static int autcpu12_fio_pbase = AUTCPU12_PHYS_SMC;
+static int autcpu12_fio_ctrl = AUTCPU12_SMC_SELECT_OFFSET;
+static int autcpu12_pedr = AUTCPU12_SMC_PORT_OFFSET;
+static int autcpu12_fio_base;
+
+#ifdef MODULE
+MODULE_PARM(autcpu12_fio_pbase, "i");
+MODULE_PARM(autcpu12_fio_ctrl, "i");
+MODULE_PARM(autcpu12_pedr, "i");
+
+__setup("autcpu12_fio_pbase=",autcpu12_fio_pbase);
+__setup("autcpu12_fio_ctrl=",autcpu12_fio_ctrl);
+__setup("autcpu12_pedr=",autcpu12_pedr);
+#endif
+
+/*
+ * Define partitions for flash devices
+ */
+
+static struct mtd_partition partition_info16k[] = {
+	{ name: "AUTCPU12 flash partition 1",
+	  offset:  0,
+	  size:    8 * SZ_1M },
+	{ name: "AUTCPU12 flash partition 2",
+	  offset:  8 * SZ_1M,
+	  size:    8 * SZ_1M },
+};
+
+static struct mtd_partition partition_info32k[] = {
+	{ name: "AUTCPU12 flash partition 1",
+	  offset:  0,
+	  size:    8 * SZ_1M },
+	{ name: "AUTCPU12 flash partition 2",
+	  offset:  8 * SZ_1M,
+	  size:   24 * SZ_1M },
+};
+
+static struct mtd_partition partition_info64k[] = {
+	{ name: "AUTCPU12 flash partition 1",
+	  offset:  0,
+	  size:   16 * SZ_1M },
+	{ name: "AUTCPU12 flash partition 2",
+	  offset: 16 * SZ_1M,
+	  size:   48 * SZ_1M},
+};
+
+static struct mtd_partition partition_info128k[] = {
+	{ name: "AUTCPU12 flash partition 1",
+	  offset:  0,
+	  size:   16 * SZ_1M },
+	{ name: "AUTCPU12 flash partition 2",
+	  offset: 16 * SZ_1M,
+	  size:   112 * SZ_1M},
+};
+
+#define NUM_PARTITIONS16K 2
+#define NUM_PARTITIONS32K 2
+#define NUM_PARTITIONS64K 2
+#define NUM_PARTITIONS128K 2
+/* 
+ *	hardware specific access to control-lines
+*/
+void autcpu12_hwcontrol(int cmd)
+{
+
+	switch(cmd){
+
+		case NAND_CTL_SETCLE: (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) |=  AUTCPU12_SMC_CLE; break;
+		case NAND_CTL_CLRCLE: (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) &= ~AUTCPU12_SMC_CLE; break;
+
+		case NAND_CTL_SETALE: (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) |=  AUTCPU12_SMC_ALE; break;
+		case NAND_CTL_CLRALE: (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) &= ~AUTCPU12_SMC_ALE; break;
+
+		case NAND_CTL_SETNCE: (*(volatile unsigned char *) (autcpu12_fio_base + autcpu12_fio_ctrl)) = 0x01; break;
+		case NAND_CTL_CLRNCE: (*(volatile unsigned char *) (autcpu12_fio_base + autcpu12_fio_ctrl)) = 0x00; break;
+	}
+}
+
+/*
+*	read device ready pin
+*/
+int autcpu12_device_ready(void)
+{
+
+	return ( (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) & AUTCPU12_SMC_RDY) ? 1 : 0;
+
+}
+/*
+ * Main initialization routine
+ */
+int __init autcpu12_init (void)
+{
+	struct nand_chip *this;
+	int err = 0;
+
+	/* Allocate memory for MTD device structure and private data */
+	autcpu12_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip),
+				GFP_KERNEL);
+	if (!autcpu12_mtd) {
+		printk ("Unable to allocate AUTCPU12 NAND MTD device structure.\n");
+		err = -ENOMEM;
+		goto out;
+	}
+
+	/* map physical adress */
+	autcpu12_fio_base=(unsigned long)ioremap(autcpu12_fio_pbase,SZ_1K);
+	if(!autcpu12_fio_base){
+		printk("Ioremap autcpu12 SmartMedia Card failed\n");
+		err = -EIO;
+		goto out_mtd;
+	}
+
+	/* Get pointer to private data */
+	this = (struct nand_chip *) (&autcpu12_mtd[1]);
+
+	/* Initialize structures */
+	memset((char *) autcpu12_mtd, 0, sizeof(struct mtd_info));
+	memset((char *) this, 0, sizeof(struct nand_chip));
+
+	/* Link the private data with the MTD structure */
+	autcpu12_mtd->priv = this;
+
+	/* Set address of NAND IO lines */
+	this->IO_ADDR_R = autcpu12_fio_base;
+	this->IO_ADDR_W = autcpu12_fio_base;
+	this->hwcontrol = autcpu12_hwcontrol;
+	this->dev_ready = autcpu12_device_ready;
+	/* 20 us command delay time */
+	this->chip_delay = 20;		
+	this->eccmode = NAND_ECC_SOFT;
+
+	/* Scan to find existance of the device */
+	if (nand_scan (autcpu12_mtd)) {
+		err = -ENXIO;
+		goto out_ior;
+	}
+
+	/* Allocate memory for internal data buffer */
+	this->data_buf = kmalloc (sizeof(u_char) * (autcpu12_mtd->oobblock + autcpu12_mtd->oobsize), GFP_KERNEL);
+	if (!this->data_buf) {
+		printk ("Unable to allocate NAND data buffer for AUTCPU12.\n");
+		err = -ENOMEM;
+		goto out_ior;
+	}
+
+	/* Allocate memory for internal data buffer */
+	this->data_cache = kmalloc (sizeof(u_char) * (autcpu12_mtd->oobblock + autcpu12_mtd->oobsize), GFP_KERNEL);
+	if (!this->data_cache) {
+		printk ("Unable to allocate NAND data cache for AUTCPU12.\n");
+		err = -ENOMEM;
+		goto out_buf;
+	}
+	this->cache_page = -1;
+
+	/* Register the partitions */
+	switch(autcpu12_mtd->size){
+		case SZ_16M: add_mtd_partitions(autcpu12_mtd, partition_info16k, NUM_PARTITIONS16K); break;
+		case SZ_32M: add_mtd_partitions(autcpu12_mtd, partition_info32k, NUM_PARTITIONS32K); break;
+		case SZ_64M: add_mtd_partitions(autcpu12_mtd, partition_info64k, NUM_PARTITIONS64K); break; 
+		case SZ_128M: add_mtd_partitions(autcpu12_mtd, partition_info128k, NUM_PARTITIONS128K); break; 
+		default: {
+			printk ("Unsupported SmartMedia device\n"); 
+			err = -ENXIO;
+			goto out_cac;
+		}
+	}
+	goto out;
+
+out_cac:
+	kfree (this->data_cache);    
+out_buf:
+	kfree (this->data_buf);    
+out_ior:
+	iounmap((void *)autcpu12_fio_base);
+out_mtd:
+	kfree (autcpu12_mtd);
+out:
+	return err;
+}
+
+module_init(autcpu12_init);
+
+/*
+ * Clean up routine
+ */
+#ifdef MODULE
+static void __exit autcpu12_cleanup (void)
+{
+	struct nand_chip *this = (struct nand_chip *) &autcpu12_mtd[1];
+
+	/* Unregister partitions */
+	del_mtd_partitions(autcpu12_mtd);
+	
+	/* Unregister the device */
+	del_mtd_device (autcpu12_mtd);
+
+	/* Free internal data buffers */
+	kfree (this->data_buf);
+	kfree (this->data_cache);
+
+	/* unmap physical adress */
+	iounmap((void *)autcpu12_fio_base);
+
+	/* Free the MTD device structure */
+	kfree (autcpu12_mtd);
+}
+module_exit(autcpu12_cleanup);
+#endif
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>");
+MODULE_DESCRIPTION("Glue layer for SmartMediaCard on autronix autcpu12");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/nand/edb7312.c linux-2.4.21-pre6/drivers/mtd/nand/edb7312.c
--- linux-2.4.20/drivers/mtd/nand/edb7312.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/nand/edb7312.c	2003-03-26 23:49:09.000000000 +0000
@@ -0,0 +1,248 @@
+/*
+ *  drivers/mtd/nand/edb7312.c
+ *
+ *  Copyright (C) 2002 Marius Gröger (mag@sysgo.de)
+ *
+ *  Derived from drivers/mtd/nand/autcpu12.c
+ *       Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
+ *
+ * $Id: edb7312.c,v 1.3 2002/06/06 12:58:16 mag Exp $
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  Overview:
+ *   This is a device driver for the NAND flash device found on the
+ *   CLEP7312 board which utilizes the Toshiba TC58V64AFT part. This is
+ *   a 64Mibit (8MiB x 8 bits) NAND flash device.
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <asm/io.h>
+#include <asm/arch/hardware.h> /* for CLPS7111_VIRT_BASE */
+#include <asm/sizes.h>
+#include <asm/hardware/clps7111.h>
+
+/*
+ * MTD structure for EDB7312 board
+ */
+static struct mtd_info *ep7312_mtd = NULL;
+
+/*
+ * Values specific to the EDB7312 board (used with EP7312 processor)
+ */
+#define EP7312_FIO_PBASE 0x10000000	/* Phys address of flash */
+#define EP7312_PXDR	0x0001	/*
+				 * IO offset to Port B data register
+				 * where the CLE, ALE and NCE pins
+				 * are wired to.
+				 */
+#define EP7312_PXDDR	0x0041	/*
+				 * IO offset to Port B data direction
+				 * register so we can control the IO
+				 * lines.
+				 */
+
+/*
+ * Module stuff
+ */
+
+static int ep7312_fio_pbase = EP7312_FIO_PBASE;
+static int ep7312_pxdr = EP7312_PXDR;
+static int ep7312_pxddr = EP7312_PXDDR;
+
+#ifdef MODULE
+MODULE_PARM(ep7312_fio_pbase, "i");
+MODULE_PARM(ep7312_pxdr, "i");
+MODULE_PARM(ep7312_pxddr, "i");
+
+__setup("ep7312_fio_pbase=",ep7312_fio_pbase);
+__setup("ep7312_pxdr=",ep7312_pxdr);
+__setup("ep7312_pxddr=",ep7312_pxddr);
+#endif
+
+#ifdef CONFIG_MTD_PARTITIONS
+/*
+ * Define static partitions for flash device
+ */
+static struct mtd_partition partition_info[] = {
+	{ name: "EP7312 Nand Flash",
+		  offset: 0,
+		  size: 8*1024*1024 }
+};
+#define NUM_PARTITIONS 1
+
+extern int parse_cmdline_partitions(struct mtd_info *master, 
+				    struct mtd_partition **pparts,
+				    const char *mtd_id);
+#endif
+
+
+/* 
+ *	hardware specific access to control-lines
+ */
+static void ep7312_hwcontrol(int cmd) 
+{
+	switch(cmd) {
+		
+	case NAND_CTL_SETCLE: 
+		clps_writeb(clps_readb(ep7312_pxdr) | 0x10, ep7312_pxdr); 
+		break;
+	case NAND_CTL_CLRCLE: 
+		clps_writeb(clps_readb(ep7312_pxdr) & ~0x10, ep7312_pxdr);
+		break;
+		
+	case NAND_CTL_SETALE:
+		clps_writeb(clps_readb(ep7312_pxdr) | 0x20, ep7312_pxdr);
+		break;
+	case NAND_CTL_CLRALE:
+		clps_writeb(clps_readb(ep7312_pxdr) & ~0x20, ep7312_pxdr);
+		break;
+		
+	case NAND_CTL_SETNCE:
+		clps_writeb((clps_readb(ep7312_pxdr) | 0x80) & ~0x40, ep7312_pxdr);
+		break;
+	case NAND_CTL_CLRNCE:
+		clps_writeb((clps_readb(ep7312_pxdr) | 0x80) | 0x40, ep7312_pxdr);
+		break;
+	}
+}
+
+/*
+ *	read device ready pin
+ */
+static int ep7312_device_ready(void)
+{
+	return 1;
+}
+
+/*
+ * Main initialization routine
+ */
+static int __init ep7312_init (void)
+{
+	struct nand_chip *this;
+	const char *part_type = 0;
+	int mtd_parts_nb = 0;
+	struct mtd_partition *mtd_parts = 0;
+	int ep7312_fio_base;
+	
+	/* Allocate memory for MTD device structure and private data */
+	ep7312_mtd = kmalloc(sizeof(struct mtd_info) + 
+			     sizeof(struct nand_chip),
+			     GFP_KERNEL);
+	if (!ep7312_mtd) {
+		printk("Unable to allocate EDB7312 NAND MTD device structure.\n");
+		return -ENOMEM;
+	}
+	
+	/* map physical adress */
+	ep7312_fio_base = (unsigned long)ioremap(ep7312_fio_pbase, SZ_1K);
+	if(!ep7312_fio_base) {
+		printk("ioremap EDB7312 NAND flash failed\n");
+		kfree(ep7312_mtd);
+		return -EIO;
+	}
+	
+	/* Get pointer to private data */
+	this = (struct nand_chip *) (&ep7312_mtd[1]);
+	
+	/* Initialize structures */
+	memset((char *) ep7312_mtd, 0, sizeof(struct mtd_info));
+	memset((char *) this, 0, sizeof(struct nand_chip));
+	
+	/* Link the private data with the MTD structure */
+	ep7312_mtd->priv = this;
+	
+	/*
+	 * Set GPIO Port B control register so that the pins are configured
+	 * to be outputs for controlling the NAND flash.
+	 */
+	clps_writeb(0xf0, ep7312_pxddr);
+	
+	/* insert callbacks */
+	this->IO_ADDR_R = ep7312_fio_base;
+	this->IO_ADDR_W = ep7312_fio_base;
+	this->hwcontrol = ep7312_hwcontrol;
+	this->dev_ready = ep7312_device_ready;
+	/* 15 us command delay time */
+	this->chip_delay = 15;
+	
+	/* Scan to find existence of the device */
+	if (nand_scan (ep7312_mtd)) {
+		iounmap((void *)ep7312_fio_base);
+		kfree (ep7312_mtd);
+		return -ENXIO;
+	}
+	
+	/* Allocate memory for internal data buffer */
+	this->data_buf = kmalloc (sizeof(u_char) * (ep7312_mtd->oobblock + ep7312_mtd->oobsize), GFP_KERNEL);
+	if (!this->data_buf) {
+		printk("Unable to allocate NAND data buffer for EDB7312.\n");
+		iounmap((void *)ep7312_fio_base);
+		kfree (ep7312_mtd);
+		return -ENOMEM;
+	}
+	
+	/* Allocate memory for internal data buffer */
+	this->data_cache = kmalloc (sizeof(u_char) * (ep7312_mtd->oobblock + ep7312_mtd->oobsize), GFP_KERNEL);
+	if (!this->data_cache) {
+		printk("Unable to allocate NAND data cache for EDB7312.\n");
+		kfree (this->data_buf);
+		iounmap((void *)ep7312_fio_base);
+		kfree (ep7312_mtd);
+		return -ENOMEM;
+	}
+	this->cache_page = -1;
+	
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+	mtd_parts_nb = parse_cmdline_partitions(ep7312_mtd, &mtd_parts, 
+						"edb7312-nand");
+	if (mtd_parts_nb > 0)
+	  part_type = "command line";
+	else
+	  mtd_parts_nb = 0;
+#endif
+	if (mtd_parts_nb == 0)
+	{
+		mtd_parts = partition_info;
+		mtd_parts_nb = NUM_PARTITIONS;
+		part_type = "static";
+	}
+	
+	/* Register the partitions */
+	printk(KERN_NOTICE "Using %s partition definition\n", part_type);
+	add_mtd_partitions(ep7312_mtd, mtd_parts, mtd_parts_nb);
+	
+	/* Return happy */
+	return 0;
+}
+module_init(ep7312_init);
+
+/*
+ * Clean up routine
+ */
+static void __exit ep7312_cleanup (void)
+{
+	struct nand_chip *this = (struct nand_chip *) &ep7312_mtd[1];
+	
+	/* Unregister the device */
+	del_mtd_device (ep7312_mtd);
+	
+	/* Free internal data buffer */
+	kfree (this->data_buf);
+	kfree (this->data_cache);
+	
+	/* Free the MTD device structure */
+	kfree (ep7312_mtd);
+}
+module_exit(ep7312_cleanup);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Marius Groeger <mag@sysgo.de>");
+MODULE_DESCRIPTION("MTD map driver for Cogent EDB7312 board");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/nand/nand.c linux-2.4.21-pre6/drivers/mtd/nand/nand.c
--- linux-2.4.20/drivers/mtd/nand/nand.c	2001-10-04 22:14:59.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/nand/nand.c	2003-03-26 23:49:39.000000000 +0000
@@ -1,17 +1,126 @@
 /*
  *  drivers/mtd/nand.c
  *
+ *  Overview:
+ *   This is the generic MTD driver for NAND flash devices. It should be
+ *   capable of working with almost all NAND chips currently available.
+ *   
+ *	Additional technical information is available on
+ *	http://www.linux-mtd.infradead.org/tech/nand.html
+ *	
  *  Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
+ * 		  2002 Thomas Gleixner (tglx@linutronix.de)
+ *
+ *  10-29-2001  Thomas Gleixner (tglx@linutronix.de)
+ * 		- Changed nand_chip structure for controlline function to
+ *		support different hardware structures (Access to
+ *		controllines ALE,CLE,NCE via hardware specific function. 
+ *		- exit out of "failed erase block" changed, to avoid
+ *		driver hangup
+ *		- init_waitqueue_head added in function nand_scan !!
+ *
+ *  01-30-2002  Thomas Gleixner (tglx@linutronix.de)
+ *		change in nand_writev to block invalid vecs entries
+ *
+ *  02-11-2002  Thomas Gleixner (tglx@linutronix.de)
+ *		- major rewrite to avoid duplicated code
+ *		  common nand_write_page function  
+ *		  common get_chip function 
+ *		- added oob_config structure for out of band layouts
+ *		- write_oob changed for partial programming
+ *		- read cache for faster access for subsequent reads
+ *		from the same page.
+ *		- support for different read/write address
+ *		- support for device ready/busy line
+ *		- read oob for more than one page enabled
+ *
+ *  02-27-2002	Thomas Gleixner (tglx@linutronix.de)
+ *		- command-delay can be programmed
+ *		- fixed exit from erase with callback-function enabled
+ *
+ *  03-21-2002  Thomas Gleixner (tglx@linutronix.de)
+ *		- DEBUG improvements provided by Elizabeth Clarke 
+ *		(eclarke@aminocom.com)
+ *		- added zero check for this->chip_delay
+ *
+ *  04-03-2002  Thomas Gleixner (tglx@linutronix.de)
+ *		- added added hw-driver supplied command and wait functions
+ *		- changed blocking for erase (erase suspend enabled)
+ *		- check pointers before accessing flash provided by
+ *		John Hall (john.hall@optionexist.co.uk)
+ *
+ *  04-09-2002  Thomas Gleixner (tglx@linutronix.de)
+ *		- nand_wait repaired
+ *
+ *  04-28-2002  Thomas Gleixner (tglx@linutronix.de)	
+ *		- OOB config defines moved to nand.h 
+ *
+ *  08-01-2002  Thomas Gleixner (tglx@linutronix.de)	
+ *		- changed my mailaddress, added pointer to tech/nand.html
+ *
+ *  08-07-2002 	Thomas Gleixner (tglx@linutronix.de)
+ *		forced bad block location to byte 5 of OOB, even if
+ *		CONFIG_MTD_NAND_ECC_JFFS2 is not set, to prevent
+ *		erase /dev/mtdX from erasing bad blocks and destroying
+ *		bad block info
+ *
+ *  08-10-2002 	Thomas Gleixner (tglx@linutronix.de)
+ *		Fixed writing tail of data. Thanks to Alice Hennessy
+ *		<ahennessy@mvista.com>.
  *
- * $Id: nand.c,v 1.12 2001/10/02 15:05:14 dwmw2 Exp $
+ *  08-10-2002 	Thomas Gleixner (tglx@linutronix.de)
+ *		nand_read_ecc and nand_write_page restructured to support
+ *		hardware ECC. Thanks to Steven Hein (ssh@sgi.com)
+ *		for basic implementation and suggestions.
+ *		3 new pointers in nand_chip structure:
+ *		calculate_ecc, correct_data, enabled_hwecc 					 
+ *		forcing all hw-drivers to support page cache
+ *		eccvalid_pos is now mandatory
+ *
+ *  08-17-2002	tglx: fixed signed/unsigned missmatch in write.c
+ *		Thanks to Ken Offer <koffer@arlut.utexas.edu> 	
+ *
+ *  08-29-2002  tglx: use buffered read/write only for non pagealigned 
+ *		access, speed up the aligned path by using the fs-buffer
+ *		reset chip removed from nand_select(), implicit done
+ *		only, when erase is interrupted
+ *		waitfuntion use yield, instead of schedule_timeout
+ *		support for 6byte/512byte hardware ECC
+ *		read_ecc, write_ecc extended for different oob-layout
+ *		selections: Implemented NAND_NONE_OOB, NAND_JFFS2_OOB,
+ *		NAND_YAFFS_OOB. fs-driver gives one of these constants
+ *		to select the oob-layout fitting the filesystem.
+ *		oobdata can be read together with the raw data, when
+ *		the fs-driver supplies a big enough buffer.
+ *		size = 12 * number of pages to read (256B pagesize)
+ *		       24 * number of pages to read (512B pagesize)
+ *		the buffer contains 8/16 byte oobdata and 4/8 byte
+ *		returncode from calculate_ecc
+ *		oobdata can be given from filesystem to program them
+ *		in one go together with the raw data. ECC codes are
+ *		filled in at the place selected by oobsel.
+ *
+ *  09-04-2002  tglx: fixed write_verify (John Hall (john.hall@optionexist.co.uk))
+ *
+ *  11-11-2002  tglx: fixed debug output in nand_write_page 
+ *		(John Hall (john.hall@optionexist.co.uk))
+ *
+ *  11-25-2002  tglx: Moved device ID/ manufacturer ID from nand_ids.h
+ *		Splitted device ID and manufacturer ID table. 
+ *		Removed CONFIG_MTD_NAND_ECC, as it defaults to ECC_NONE for
+ *		mtd->read / mtd->write and is controllable by the fs driver
+ *		for mtd->read_ecc / mtd->write_ecc
+ *		some minor cleanups
+ *
+ *  12-05-2000  tglx: Dave Ellis (DGE@sixnetio) provided the fix for
+ *		WRITE_VERIFY long time ago. Thanks for remembering me.	
+ *	
+ * $Id: nand.c,v 1.36 2002/12/05 20:59:11 gleixner Exp $
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  *
- *  Overview:
- *   This is the generic MTD driver for NAND flash devices. It should be
- *   capable of working with almost all NAND chips currently available.
  */
 
 #include <linux/delay.h>
@@ -20,178 +129,452 @@
 #include <linux/types.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
-#include <linux/mtd/nand_ids.h>
+#include <linux/mtd/nand_ecc.h>
 #include <linux/interrupt.h>
 #include <asm/io.h>
 
-#ifdef CONFIG_MTD_NAND_ECC
-#include <linux/mtd/nand_ecc.h>
-#endif
-
 /*
  * Macros for low-level register control
  */
-#define NAND_CTRL (*(volatile unsigned char *) \
-			((struct nand_chip *) mtd->priv)->CTRL_ADDR)
-#define nand_select()	NAND_CTRL &= ~this->NCE; \
-			nand_command(mtd, NAND_CMD_RESET, -1, -1); \
-			udelay (10);
-#define nand_deselect() NAND_CTRL |= ~this->NCE;
+#define nand_select()	this->hwcontrol(NAND_CTL_SETNCE);
+
+#define nand_deselect() this->hwcontrol(NAND_CTL_CLRNCE);
+
+/*
+ * out of band configuration for different filesystems
+ */
+static int oobconfigs[][6] = {
+	{ 0,0,0,0,0,0},
+
+	{ NAND_JFFS2_OOB_ECCPOS0, NAND_JFFS2_OOB_ECCPOS1, NAND_JFFS2_OOB_ECCPOS2,
+	NAND_JFFS2_OOB_ECCPOS3, NAND_JFFS2_OOB_ECCPOS4, NAND_JFFS2_OOB_ECCPOS5 },
+
+	{ NAND_YAFFS_OOB_ECCPOS0, NAND_YAFFS_OOB_ECCPOS1, NAND_YAFFS_OOB_ECCPOS2,
+	NAND_YAFFS_OOB_ECCPOS3, NAND_YAFFS_OOB_ECCPOS4, NAND_YAFFS_OOB_ECCPOS5 }	
+};
 
 /*
  * NAND low-level MTD interface functions
  */
-static int nand_read (struct mtd_info *mtd, loff_t from, size_t len,
-			size_t *retlen, u_char *buf);
+static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf);
 static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
-				size_t *retlen, u_char *buf, u_char *ecc_code);
-static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len,
-				size_t *retlen, u_char *buf);
-static int nand_write (struct mtd_info *mtd, loff_t to, size_t len,
-			size_t *retlen, const u_char *buf);
+			  size_t * retlen, u_char * buf, u_char * eccbuf, int oobsel);
+static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf);
+static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf);
 static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
-				size_t *retlen, const u_char *buf,
-				u_char *ecc_code);
-static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len,
-				size_t *retlen, const u_char *buf);
+			   size_t * retlen, const u_char * buf, u_char * eccbuf, int oobsel);
+static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char *buf);
 static int nand_writev (struct mtd_info *mtd, const struct iovec *vecs,
-				unsigned long count, loff_t to, size_t *retlen);
+			unsigned long count, loff_t to, size_t * retlen);
+static int nand_writev_ecc (struct mtd_info *mtd, const struct iovec *vecs,
+			unsigned long count, loff_t to, size_t * retlen, u_char *eccbuf, int oobsel);
 static int nand_erase (struct mtd_info *mtd, struct erase_info *instr);
 static void nand_sync (struct mtd_info *mtd);
-
+static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, int col, 
+			int last, u_char *oob_buf, int oobsel);
 /*
  * Send command to NAND device
  */
-static void nand_command (struct mtd_info *mtd, unsigned command,
-				int column, int page_addr)
+static void nand_command (struct mtd_info *mtd, unsigned command, int column, int page_addr)
 {
 	register struct nand_chip *this = mtd->priv;
-	register unsigned long NAND_IO_ADDR = this->IO_ADDR;
+	register unsigned long NAND_IO_ADDR = this->IO_ADDR_W;
 
 	/* Begin command latch cycle */
-	NAND_CTRL |= this->CLE;
-
+	this->hwcontrol (NAND_CTL_SETCLE);
 	/*
 	 * Write out the command to the device.
 	 */
-	if (command != NAND_CMD_SEQIN)	
+	if (command != NAND_CMD_SEQIN)
 		writeb (command, NAND_IO_ADDR);
 	else {
 		if (mtd->oobblock == 256 && column >= 256) {
 			column -= 256;
-			writeb(NAND_CMD_RESET, NAND_IO_ADDR);
-			writeb(NAND_CMD_READOOB, NAND_IO_ADDR);
-			writeb(NAND_CMD_SEQIN, NAND_IO_ADDR);
-		}
-		else if (mtd->oobblock == 512 && column >= 256) {
+			writeb (NAND_CMD_READOOB, NAND_IO_ADDR);
+			writeb (NAND_CMD_SEQIN, NAND_IO_ADDR);
+		} else if (mtd->oobblock == 512 && column >= 256) {
 			if (column < 512) {
 				column -= 256;
-				writeb(NAND_CMD_READ1, NAND_IO_ADDR);
-				writeb(NAND_CMD_SEQIN, NAND_IO_ADDR);
-			}
-			else {
+				writeb (NAND_CMD_READ1, NAND_IO_ADDR);
+				writeb (NAND_CMD_SEQIN, NAND_IO_ADDR);
+			} else {
 				column -= 512;
-				writeb(NAND_CMD_READOOB, NAND_IO_ADDR);
-				writeb(NAND_CMD_SEQIN, NAND_IO_ADDR);
+				writeb (NAND_CMD_READOOB, NAND_IO_ADDR);
+				writeb (NAND_CMD_SEQIN, NAND_IO_ADDR);
 			}
-		}
-		else {
-			writeb(NAND_CMD_READ0, NAND_IO_ADDR);
-			writeb(NAND_CMD_SEQIN, NAND_IO_ADDR);
+		} else {
+			writeb (NAND_CMD_READ0, NAND_IO_ADDR);
+			writeb (NAND_CMD_SEQIN, NAND_IO_ADDR);
 		}
 	}
 
 	/* Set ALE and clear CLE to start address cycle */
-	NAND_CTRL &= ~this->CLE;
-	NAND_CTRL |= this->ALE;
+	this->hwcontrol (NAND_CTL_CLRCLE);
+
+	if (column != -1 || page_addr != -1) {
+		this->hwcontrol (NAND_CTL_SETALE);
 
-	/* Serially input address */
-	if (column != -1)
-		writeb (column, NAND_IO_ADDR);
-	if (page_addr != -1) {
-		writeb ((unsigned char) (page_addr & 0xff), NAND_IO_ADDR);
-		writeb ((unsigned char) ((page_addr >> 8) & 0xff), NAND_IO_ADDR);
-		/* One more address cycle for higher density devices */
-		if (mtd->size & 0x0c000000) {
-			writeb ((unsigned char) ((page_addr >> 16) & 0x0f),
-					NAND_IO_ADDR);
+		/* Serially input address */
+		if (column != -1)
+			writeb (column, NAND_IO_ADDR);
+		if (page_addr != -1) {
+			writeb ((unsigned char) (page_addr & 0xff), NAND_IO_ADDR);
+			writeb ((unsigned char) ((page_addr >> 8) & 0xff), NAND_IO_ADDR);
+			/* One more address cycle for higher density devices */
+			if (mtd->size & 0x0c000000) 
+				writeb ((unsigned char) ((page_addr >> 16) & 0x0f), NAND_IO_ADDR);
 		}
+		/* Latch in address */
+		this->hwcontrol (NAND_CTL_CLRALE);
 	}
+	
+	/* 
+	 * program and erase have their own busy handlers 
+	 * status and sequential in needs no delay
+	*/
+	switch (command) {
+			
+	case NAND_CMD_PAGEPROG:
+	case NAND_CMD_ERASE1:
+	case NAND_CMD_ERASE2:
+	case NAND_CMD_SEQIN:
+	case NAND_CMD_STATUS:
+		return;
 
-	/* Latch in address */
-	NAND_CTRL &= ~this->ALE;
+	case NAND_CMD_RESET:
+		if (this->dev_ready)	
+			break;
+		this->hwcontrol (NAND_CTL_SETCLE);
+		writeb (NAND_CMD_STATUS, NAND_IO_ADDR);
+		this->hwcontrol (NAND_CTL_CLRCLE);
+		while ( !(readb (this->IO_ADDR_R) & 0x40));
+		return;
 
-	/* Pause for 15us */
-	udelay (15);
+	/* This applies to read commands */	
+	default:
+		/* 
+		 * If we don't have access to the busy pin, we apply the given
+		 * command delay
+		*/
+		if (!this->dev_ready) {
+			udelay (this->chip_delay);
+			return;
+		}	
+	}
+	
+	/* wait until command is processed */
+	while (!this->dev_ready());
 }
 
 /*
- * NAND read
+ *	Get chip for selected access
  */
-static int nand_read (struct mtd_info *mtd, loff_t from, size_t len,
-			size_t *retlen, u_char *buf)
+static inline void nand_get_chip (struct nand_chip *this, struct mtd_info *mtd, int new_state, int *erase_state)
 {
-#ifdef CONFIG_MTD_NAND_ECC
-	struct nand_chip *this = mtd->priv;
+
+	DECLARE_WAITQUEUE (wait, current);
+
+	/* 
+	 * Grab the lock and see if the device is available 
+	 * For erasing, we keep the spinlock until the
+	 * erase command is written. 
+	*/
+retry:
+	spin_lock_bh (&this->chip_lock);
+
+	if (this->state == FL_READY) {
+		this->state = new_state;
+		if (new_state != FL_ERASING)
+			spin_unlock_bh (&this->chip_lock);
+		return;
+	}
+
+	if (this->state == FL_ERASING) {
+		if (new_state != FL_ERASING) {
+			this->state = new_state;
+			spin_unlock_bh (&this->chip_lock);
+			nand_select ();	/* select in any case */
+			this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+			return;
+		}
+	}
+
+	set_current_state (TASK_UNINTERRUPTIBLE);
+	add_wait_queue (&this->wq, &wait);
+	spin_unlock_bh (&this->chip_lock);
+	schedule ();
+	remove_wait_queue (&this->wq, &wait);
+	goto retry;
+}
+
+/*
+ * Wait for command done. This applies to erase and program only
+ * Erase can take up to 400ms and program up to 20ms according to 
+ * general NAND and SmartMedia specs
+ *
+*/
+static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state)
+{
+
+	unsigned long	timeo = jiffies;
+	int	status;
+	
+	if (state == FL_ERASING)
+		 timeo += (HZ * 400) / 1000;
+	else
+		 timeo += (HZ * 20) / 1000;
+
+	spin_lock_bh (&this->chip_lock);
+	this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
+
+	while (time_before(jiffies, timeo)) {		
+		/* Check, if we were interrupted */
+		if (this->state != state) {
+			spin_unlock_bh (&this->chip_lock);
+			return 0;
+		}
+		if (this->dev_ready) {
+			if (this->dev_ready ())
+				break;
+		}
+		if (readb (this->IO_ADDR_R) & 0x40)
+			break;
+						
+		spin_unlock_bh (&this->chip_lock);
+		yield ();
+		spin_lock_bh (&this->chip_lock);
+	}
+	status = (int) readb (this->IO_ADDR_R);
+	spin_unlock_bh (&this->chip_lock);
+
+	return status;
+}
+
+/*
+ *	Nand_page_program function is used for write and writev !
+ */
+static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this,
+			    int page, int col, int last, u_char *oob_buf, int oobsel)
+{
+	int 	i, status;
+	u_char	ecc_code[6], *oob_data;
+	int	eccmode = oobsel ? this->eccmode : NAND_ECC_NONE;
+	int  	*oob_config = oobconfigs[oobsel];
+
+	/* pad oob area, if we have no oob buffer from fs-driver */
+	if (!oob_buf) {
+		oob_data = &this->data_buf[mtd->oobblock];
+		for (i = 0; i < mtd->oobsize; i++)
+			oob_data[i] = 0xff;
+	} else 
+		oob_data = oob_buf;
 	
-	return nand_read_ecc (mtd, from, len, retlen, buf, this->ecc_code_buf);
-#else
-	return nand_read_ecc (mtd, from, len, retlen, buf, NULL);
+	/* software ecc 3 Bytes ECC / 256 Byte Data ? */
+	if (eccmode == NAND_ECC_SOFT) {
+		/* Read back previous written data, if col > 0 */
+		if (col) {
+			this->cmdfunc (mtd, NAND_CMD_READ0, 0, page);
+			for (i = 0; i < col; i++)
+				this->data_poi[i] = readb (this->IO_ADDR_R);
+		}
+		if ((col < this->eccsize) && (last >= this->eccsize)) {
+			this->calculate_ecc (&this->data_poi[0], &(ecc_code[0]));
+			for (i = 0; i < 3; i++)
+				oob_data[oob_config[i]] = ecc_code[i];
+		}
+		/* Calculate and write the second ECC if we have enough data */
+		if ((mtd->oobblock == 512) && (last == 512)) {
+			this->calculate_ecc (&this->data_poi[256], &(ecc_code[3]));
+			for (i = 3; i < 6; i++)
+				oob_data[oob_config[i]] = ecc_code[i];
+		} 
+	} else {
+		/* For hardware ECC skip ECC, if we have no full page write */
+		if (eccmode != NAND_ECC_NONE && (col || last != mtd->oobblock))
+			eccmode = NAND_ECC_NONE;
+	}			
+
+	/* Prepad for partial page programming !!! */
+	for (i = 0; i < col; i++)
+		this->data_poi[i] = 0xff;
+
+	/* Postpad for partial page programming !!! oob is already padded */
+	for (i = last; i < mtd->oobblock; i++)
+		this->data_poi[i] = 0xff;
+
+	/* Send command to begin auto page programming */
+	this->cmdfunc (mtd, NAND_CMD_SEQIN, 0x00, page);
+
+	/* Write out complete page of data, take care of eccmode */
+	switch (this->eccmode) {
+	/* No ecc and software ecc 3/256, write all */
+	case NAND_ECC_NONE:
+	case NAND_ECC_SOFT:
+		for (i = 0; i < mtd->oobblock; i++) 
+			writeb ( this->data_poi[i] , this->IO_ADDR_W);
+		break;
+		
+	/* Hardware ecc 3 byte / 256 data, write first half, get ecc, then second, if 512 byte pagesize */	
+	case NAND_ECC_HW3_256:		
+		this->enable_hwecc (NAND_ECC_WRITE);	/* enable hardware ecc logic for write */
+		for (i = 0; i < mtd->eccsize; i++) 
+			writeb ( this->data_poi[i] , this->IO_ADDR_W);
+		
+		this->calculate_ecc (NULL, &(ecc_code[0]));
+		for (i = 0; i < 3; i++)
+			oob_data[oob_config[i]] = ecc_code[i];
+			
+		if (mtd->oobblock == 512) {
+			this->enable_hwecc (NAND_ECC_WRITE);	/* enable hardware ecc logic for write*/
+			for (i = mtd->eccsize; i < mtd->oobblock; i++) 
+				writeb ( this->data_poi[i] , this->IO_ADDR_W);
+			this->calculate_ecc (NULL, &(ecc_code[3]));
+			for (i = 3; i < 6; i++)
+				oob_data[oob_config[i]] = ecc_code[i];
+		}
+		break;
+				
+	/* Hardware ecc 3 byte / 512 byte data, write full page */	
+	case NAND_ECC_HW3_512:	
+		this->enable_hwecc (NAND_ECC_WRITE);	/* enable hardware ecc logic */
+		for (i = 0; i < mtd->oobblock; i++) 
+			writeb ( this->data_poi[i] , this->IO_ADDR_W);
+		this->calculate_ecc (NULL, &(ecc_code[0]));
+		for (i = 0; i < 3; i++)
+			oob_data[oob_config[i]] = ecc_code[i];
+		break;
+
+	/* Hardware ecc 6 byte / 512 byte data, write full page */	
+	case NAND_ECC_HW6_512:	
+		this->enable_hwecc (NAND_ECC_WRITE);	/* enable hardware ecc logic */
+		for (i = 0; i < mtd->oobblock; i++) 
+			writeb ( this->data_poi[i] , this->IO_ADDR_W);
+		this->calculate_ecc (NULL, &(ecc_code[0]));
+		for (i = 0; i < 6; i++)
+			oob_data[oob_config[i]] = ecc_code[i];
+		break;
+		
+	default:
+		printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode);
+		BUG();	
+	}	
+	
+	/* Write out OOB data */
+	for (i = 0; i <  mtd->oobsize; i++)
+		writeb ( oob_data[i] , this->IO_ADDR_W);
+
+	/* Send command to actually program the data */
+	this->cmdfunc (mtd, NAND_CMD_PAGEPROG, -1, -1);
+
+	/* call wait ready function */
+	status = this->waitfunc (mtd, this, FL_WRITING);
+
+	/* See if device thinks it succeeded */
+	if (status & 0x01) {
+		DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page);
+		return -EIO;
+	}
+
+#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
+	/*
+	 * The NAND device assumes that it is always writing to
+	 * a cleanly erased page. Hence, it performs its internal
+	 * write verification only on bits that transitioned from
+	 * 1 to 0. The device does NOT verify the whole page on a
+	 * byte by byte basis. It is possible that the page was
+	 * not completely erased or the page is becoming unusable
+	 * due to wear. The read with ECC would catch the error
+	 * later when the ECC page check fails, but we would rather
+	 * catch it early in the page write stage. Better to write
+	 * no data than invalid data.
+	 */
+
+	/* Send command to read back the page */
+	this->cmdfunc (mtd, NAND_CMD_READ0, col, page);
+	/* Loop through and verify the data */
+	for (i = col; i < last; i++) {
+		if (this->data_poi[i] != readb (this->IO_ADDR_R)) {
+			DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
+			return -EIO;
+		}
+	}
+
+	/* check, if we have a fs-supplied oob-buffer */
+	if (oob_buf) {
+		for (i = 0; i < mtd->oobsize; i++) {
+			if (oob_data[i] != readb (this->IO_ADDR_R)) {
+				DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
+				return -EIO;
+			}
+		}
+	} else {
+		if (eccmode != NAND_ECC_NONE && !col && last == mtd->oobblock) {
+			int ecc_bytes = 0;
+
+			switch (this->eccmode) {
+			case NAND_ECC_SOFT:
+			case NAND_ECC_HW3_256: ecc_bytes = (mtd->oobblock == 512) ? 6 : 3; break;
+			case NAND_ECC_HW3_512: ecc_bytes = 3; break;
+			case NAND_ECC_HW6_512: ecc_bytes = 6; break;
+			}
+
+			for (i = 0; i < mtd->oobsize; i++)
+				oob_data[i] = readb (this->IO_ADDR_R);
+
+			for (i = 0; i < ecc_bytes; i++) {
+				if (oob_data[oob_config[i]] != ecc_code[i]) {
+					DEBUG (MTD_DEBUG_LEVEL0,
+					       "%s: Failed ECC write "
+				       "verify, page 0x%08x, " "%6i bytes were succesful\n", __FUNCTION__, page, i);
+				return -EIO;
+				}
+			}
+		}
+	}
 #endif
+	return 0;
 }
 
 /*
+*	Use NAND read ECC
+*/
+static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf)
+{
+	return (nand_read_ecc (mtd, from, len, retlen, buf, NULL, 0));
+}			   
+
+
+/*
  * NAND read with ECC
  */
 static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
-				size_t *retlen, u_char *buf, u_char *ecc_code)
+			  size_t * retlen, u_char * buf, u_char * oob_buf, int oobsel)
 {
-	int j, col, page, state;
+	int j, col, page, end, ecc;
 	int erase_state = 0;
+	int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0;
 	struct nand_chip *this = mtd->priv;
-	DECLARE_WAITQUEUE(wait, current);
-#ifdef CONFIG_MTD_NAND_ECC
-	int ecc_result;
+	u_char *data_poi, *oob_data = oob_buf;
 	u_char ecc_calc[6];
-#endif
+	u_char ecc_code[6];
+	int	eccmode = oobsel ? this->eccmode : NAND_ECC_NONE;
 
-	DEBUG (MTD_DEBUG_LEVEL3,
-		"nand_read_ecc: from = 0x%08x, len = %i\n", (unsigned int) from,
-		(int) len);
+	int *oob_config = oobconfigs[oobsel];
+	
+	DEBUG (MTD_DEBUG_LEVEL3, "nand_read_ecc: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
 
 	/* Do not allow reads past end of device */
 	if ((from + len) > mtd->size) {
-		DEBUG (MTD_DEBUG_LEVEL0,
-			"nand_read_ecc: Attempt read beyond end of device\n");
+		DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: Attempt read beyond end of device\n");
 		*retlen = 0;
 		return -EINVAL;
 	}
 
 	/* Grab the lock and see if the device is available */
-retry:
-	spin_lock_bh (&this->chip_lock);
-
-	switch (this->state) {
-	case FL_READY:
-		this->state = FL_READING;
-		spin_unlock_bh (&this->chip_lock);
-		break;
-
-	case FL_ERASING:
-		this->state = FL_READING;
-		erase_state = 1;
-		spin_unlock_bh (&this->chip_lock);
-		break;
-
-	default:
-		set_current_state (TASK_UNINTERRUPTIBLE);
-		add_wait_queue (&this->wq, &wait);
-		spin_unlock_bh (&this->chip_lock);
-		schedule();
+	nand_get_chip (this, mtd ,FL_READING, &erase_state);
 
-		remove_wait_queue (&this->wq, &wait);
-		goto retry;
-	};
+	/* Select the NAND device */
+	nand_select ();
 
 	/* First we calculate the starting page */
 	page = from >> this->page_shift;
@@ -199,122 +582,126 @@
 	/* Get raw starting column */
 	col = from & (mtd->oobblock - 1);
 
-	/* State machine for devices having pages larger than 256 bytes */
-	state = (col < mtd->eccsize) ? 0 : 1;
-
-	/* Calculate column address within ECC block context */
-	col = (col >= mtd->eccsize) ? (col - mtd->eccsize) : col;
-
-	/* Initialize return value */
-	*retlen = 0;
-
-	/* Select the NAND device */
-	nand_select ();
+	end = mtd->oobblock;
+	ecc = mtd->eccsize;
 
+	/* Send the read command */
+	this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page);
+	
 	/* Loop until all data read */
-	while (*retlen < len) {
-
-#ifdef CONFIG_MTD_NAND_ECC
-		/* Send the read command */
-		if (!state)
-			nand_command (mtd, NAND_CMD_READ0, 0x00, page);
-		else 
-			nand_command (mtd, NAND_CMD_READ1, 0x00, page);
-
-		/* Read in a block big enough for ECC */
-		for (j=0 ; j < mtd->eccsize ; j++)
-			this->data_buf[j] = readb (this->IO_ADDR);
-
-		/* Read in the out-of-band data */
-		if (!state) {
-			nand_command (mtd, NAND_CMD_READOOB, 0x00, page);
-			for (j=0 ; j<3 ; j++)
-				ecc_code[j] = readb(this->IO_ADDR);
-			nand_command (mtd, NAND_CMD_READ0, 0x00, page);
-		}
-		else {
-			nand_command (mtd, NAND_CMD_READOOB, 0x03, page);
-			for (j=3 ; j<6 ; j++)
-				ecc_code[j] = readb(this->IO_ADDR);
-			nand_command (mtd, NAND_CMD_READ0, 0x00, page);
-		}
-
-		/* Calculate the ECC and verify it */
-		if (!state) {
-			nand_calculate_ecc (&this->data_buf[0],
-						&ecc_calc[0]);
-			ecc_result = nand_correct_data (&this->data_buf[0],
-						&ecc_code[0], &ecc_calc[0]);
-		}
-		else {
-			nand_calculate_ecc (&this->data_buf[0],
-						&ecc_calc[3]);
-			ecc_result = nand_correct_data (&this->data_buf[0],
-						&ecc_code[3], &ecc_calc[3]);
-		}
-		if (ecc_result == -1) {
-			DEBUG (MTD_DEBUG_LEVEL0,
-				"nand_read_ecc: " \
-				"Failed ECC read, page 0x%08x\n", page);
-			nand_deselect ();
-			spin_lock_bh (&this->chip_lock);
-			if (erase_state)
-				this->state = FL_ERASING;
+	while (read < len) {
+		
+		/* If we have consequent page reads, apply delay or wait for ready/busy pin */
+		if (read) {
+			if (!this->dev_ready) 
+				udelay (this->chip_delay);
 			else
-				this->state = FL_READY;
-			wake_up (&this->wq);
-			spin_unlock_bh (&this->chip_lock);
-			return -EIO;
+				while (!this->dev_ready());	
 		}
 
-		/* Read the data from ECC data buffer into return buffer */
-		if ((*retlen + (mtd->eccsize - col)) >= len) {
-			while (*retlen < len)
-				buf[(*retlen)++] = this->data_buf[col++];
-			/* We're done */
-			continue;
-		}
-		else
-			for (j=col ; j < mtd->eccsize ; j++)
-				buf[(*retlen)++] = this->data_buf[j];
-#else
-		/* Send the read command */
-		if (!state)
-			nand_command (mtd, NAND_CMD_READ0, col, page);
+		/* 
+		 * If the read is not page aligned, we have to read into data buffer
+		 * due to ecc, else we read into return buffer direct
+		 */
+		if (!col && (len - read) >= end)  
+			data_poi = &buf[read];
 		else 
-			nand_command (mtd, NAND_CMD_READ1, col, page);
+			data_poi = this->data_buf;
 
-		/* Read the data directly into the return buffer */ 
-		if ((*retlen + (mtd->eccsize - col)) >= len) {
-			while (*retlen < len)
-				buf[(*retlen)++] = readb (this->IO_ADDR);
-			/* We're done */
-			continue;
-		}
-		else
-			for (j=col ; j < mtd->eccsize ; j++)
-				buf[(*retlen)++] = readb (this->IO_ADDR);
-#endif
+		/* get oob area, if we have no oob buffer from fs-driver */
+		if (!oob_buf) {
+			oob_data = &this->data_buf[end];
+			oob = 0;
+		} 	
+			
+		j = 0;
+		switch (eccmode) {
+		case NAND_ECC_NONE:	/* No ECC, Read in a page */		
+			while (j < end)
+				data_poi[j++] = readb (this->IO_ADDR_R);
+			break;
+			
+		case NAND_ECC_SOFT:	/* Software ECC 3/256: Read in a page + oob data */
+			while (j < end)
+				data_poi[j++] = readb (this->IO_ADDR_R);
+			this->calculate_ecc (&data_poi[0], &ecc_calc[0]);
+			if (mtd->oobblock == 512)
+				this->calculate_ecc (&data_poi[256], &ecc_calc[3]);
+			break;	
+			
+		case NAND_ECC_HW3_256: /* Hardware ECC 3 byte /256 byte data: Read in first 256 byte, get ecc, */
+			this->enable_hwecc (NAND_ECC_READ);	
+			while (j < ecc)
+				data_poi[j++] = readb (this->IO_ADDR_R);
+			this->calculate_ecc (&data_poi[0], &ecc_calc[0]);	/* read from hardware */
+			
+			if (mtd->oobblock == 512) { /* read second, if pagesize = 512 */
+				this->enable_hwecc (NAND_ECC_READ);	
+				while (j < end)
+					data_poi[j++] = readb (this->IO_ADDR_R);
+				this->calculate_ecc (&data_poi[256], &ecc_calc[3]); /* read from hardware */
+			}					
+			break;						
+				
+		case NAND_ECC_HW3_512:	
+		case NAND_ECC_HW6_512: /* Hardware ECC 3/6 byte / 512 byte data : Read in a page  */
+			this->enable_hwecc (NAND_ECC_READ);	
+			while (j < end)
+				data_poi[j++] = readb (this->IO_ADDR_R);
+			this->calculate_ecc (&data_poi[0], &ecc_calc[0]);	/* read from hardware */
+			break;
 
-		/*
-		 * If the amount of data to be read is greater than
-		 * (256 - col), then all subsequent reads will take
-		 * place on page or half-page (in the case of 512 byte
-		 * page devices) aligned boundaries and the column
-		 * address will be zero. Setting the column address to
-		 * to zero after the first read allows us to simplify
-		 * the reading of data and the if/else statements above.
-		 */
-		if (col)
-			col = 0x00;
+		default:
+			printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode);
+			BUG();	
+		}
 
+		/* read oobdata */
+		for (j = 0; j <  mtd->oobsize; j++) 
+			oob_data[oob + j] = readb (this->IO_ADDR_R);
+		
+		/* Skip ECC, if not active */
+		if (eccmode == NAND_ECC_NONE)
+			goto readdata;	
+		
+		/* Pick the ECC bytes out of the oob data */
+		for (j = 0; j < 6; j++)
+			ecc_code[j] = oob_data[oob + oob_config[j]];
+
+		/* correct data, if neccecary */
+		ecc_status = this->correct_data (&data_poi[0], &ecc_code[0], &ecc_calc[0]);
+		/* check, if we have a fs supplied oob-buffer */
+		if (oob_buf) { 
+			oob += mtd->oobsize;
+			*((int *)&oob_data[oob]) = ecc_status;
+			oob += sizeof(int);
+		}
+		if (ecc_status == -1) {	
+			DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page);
+			ecc_failed++;
+		}
+		
+		if (mtd->oobblock == 512 && eccmode != NAND_ECC_HW3_512) {
+			ecc_status = this->correct_data (&data_poi[256], &ecc_code[3], &ecc_calc[3]);
+			if (oob_buf) {
+				*((int *)&oob_data[oob]) = ecc_status;
+				oob += sizeof(int);
+			}
+			if (ecc_status == -1) {
+				DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page);
+				ecc_failed++;
+			}
+		}
+readdata:
+		if (col || (len - read) < end) { 
+			for (j = col; j < end && read < len; j++)
+				buf[read++] = data_poi[j];
+		} else		
+			read += mtd->oobblock;
+		/* For subsequent reads align to page boundary. */
+		col = 0;
 		/* Increment page address */
-		if ((mtd->oobblock == 256) || state)
-			page++;
-
-		/* Toggle state machine */
-		if (mtd->oobblock == 512)
-			state = state ? 0 : 1;
+		page++;
 	}
 
 	/* De-select the NAND device */
@@ -322,31 +709,29 @@
 
 	/* Wake up anyone waiting on the device */
 	spin_lock_bh (&this->chip_lock);
-	if (erase_state)
-		this->state = FL_ERASING;
-	else
-		this->state = FL_READY;
+	this->state = FL_READY;
 	wake_up (&this->wq);
 	spin_unlock_bh (&this->chip_lock);
-	
-	/* Return happy */
-	return 0;
+
+	/*
+	 * Return success, if no ECC failures, else -EIO
+	 * fs driver will take care of that, because
+	 * retlen == desired len and result == -EIO
+	 */
+	*retlen = read;
+	return ecc_failed ? -EIO : 0;
 }
 
 /*
  * NAND read out-of-band
  */
-static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len,
-				size_t *retlen, u_char *buf)
+static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf)
 {
 	int i, col, page;
 	int erase_state = 0;
 	struct nand_chip *this = mtd->priv;
-	DECLARE_WAITQUEUE(wait, current);
-	
-	DEBUG (MTD_DEBUG_LEVEL3,
-		"nand_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from,
-		(int) len);
+
+	DEBUG (MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
 
 	/* Shift to get page */
 	page = ((int) from) >> this->page_shift;
@@ -357,59 +742,36 @@
 	/* Initialize return length value */
 	*retlen = 0;
 
-	/* Do not allow read past end of page */
-	if ((col + len) > mtd->oobsize) {
-		DEBUG (MTD_DEBUG_LEVEL0,
-			"nand_read_oob: Attempt read past end of page " \
-			"0x%08x, column %i, length %i\n", page, col, len);
+	/* Do not allow reads past end of device */
+	if ((from + len) > mtd->size) {
+		DEBUG (MTD_DEBUG_LEVEL0, "nand_read_oob: Attempt read beyond end of device\n");
+		*retlen = 0;
 		return -EINVAL;
 	}
 
-retry:
 	/* Grab the lock and see if the device is available */
-	spin_lock_bh (&this->chip_lock);
-
-	switch (this->state) {
-	case FL_READY:
-		this->state = FL_READING;
-		spin_unlock_bh (&this->chip_lock);
-		break;
-
-	case FL_ERASING:
-		this->state = FL_READING;
-		erase_state = 1;
-		spin_unlock_bh (&this->chip_lock);
-		break;
-
-	default:
-		set_current_state (TASK_UNINTERRUPTIBLE);
-		add_wait_queue (&this->wq, &wait);
-		spin_unlock_bh (&this->chip_lock);
-		schedule();
-
-		remove_wait_queue (&this->wq, &wait);
-		goto retry;
-	};
+	nand_get_chip (this, mtd , FL_READING, &erase_state);
 
 	/* Select the NAND device */
 	nand_select ();
 
 	/* Send the read command */
-	nand_command (mtd, NAND_CMD_READOOB, col, page);	
-
-	/* Read the data */
-	for (i = 0 ; i < len ; i++)
-		buf[i] = readb (this->IO_ADDR);
-
+	this->cmdfunc (mtd, NAND_CMD_READOOB, col, page);
+	/* 
+	 * Read the data, if we read more than one page
+	 * oob data, let the device transfer the data !
+	 */
+	for (i = 0; i < len; i++) {
+		buf[i] = readb (this->IO_ADDR_R);
+		if ((col++ & (mtd->oobsize - 1)) == (mtd->oobsize - 1))
+			udelay (this->chip_delay);
+	}
 	/* De-select the NAND device */
 	nand_deselect ();
 
 	/* Wake up anyone waiting on the device */
 	spin_lock_bh (&this->chip_lock);
-	if (erase_state)
-		this->state = FL_ERASING;
-	else
-		this->state = FL_READY;
+	this->state = FL_READY;
 	wake_up (&this->wq);
 	spin_unlock_bh (&this->chip_lock);
 
@@ -419,264 +781,85 @@
 }
 
 /*
- * NAND write
- */
-static int nand_write (struct mtd_info *mtd, loff_t to, size_t len,
-			size_t *retlen, const u_char *buf)
+*	Use NAND write ECC
+*/
+static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf)
 {
-#ifdef CONFIG_MTD_NAND_ECC
-	struct nand_chip *this = mtd->priv;
-	
-	return nand_write_ecc (mtd, to, len, retlen, buf, this->ecc_code_buf);
-#else
-	return nand_write_ecc (mtd, to, len, retlen, buf, NULL);
-#endif
-}
-
+	return (nand_write_ecc (mtd, to, len, retlen, buf, NULL, 0));
+}			   
 /*
  * NAND write with ECC
  */
 static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
-				size_t *retlen, const u_char *buf,
-				u_char *ecc_code)
+			   size_t * retlen, const u_char * buf, u_char * eccbuf, int oobsel)
 {
-	int i, page, col, cnt, status;
+	int i, page, col, cnt, ret = 0, oob = 0, written = 0;
 	struct nand_chip *this = mtd->priv;
-	DECLARE_WAITQUEUE(wait, current);
-#ifdef CONFIG_MTD_NAND_ECC
-	int ecc_bytes = (mtd->oobblock == 512) ? 6 : 3;
-#endif
 
-	DEBUG (MTD_DEBUG_LEVEL3,
-		"nand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int) to,
-		(int) len);
+	DEBUG (MTD_DEBUG_LEVEL3, "nand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
 
-	/* Do not allow write past end of page */
+	/* Do not allow write past end of device */
 	if ((to + len) > mtd->size) {
-		DEBUG (MTD_DEBUG_LEVEL0,
-			"nand_write_ecc: Attempted write past end of device\n");
+		DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Attempt to write past end of page\n");
 		return -EINVAL;
 	}
 
-retry:
-	/* Grab the lock and see if the device is available */
-	spin_lock_bh (&this->chip_lock);
-
-	switch (this->state) {
-	case FL_READY:
-		this->state = FL_WRITING;
-		spin_unlock_bh (&this->chip_lock);
-		break;
-
-	default:
-		set_current_state (TASK_UNINTERRUPTIBLE);
-		add_wait_queue (&this->wq, &wait);
-		spin_unlock_bh (&this->chip_lock);
-		schedule();
-
-		remove_wait_queue (&this->wq, &wait);
-		goto retry;
-	};
-
 	/* Shift to get page */
 	page = ((int) to) >> this->page_shift;
 
 	/* Get the starting column */
 	col = to & (mtd->oobblock - 1);
 
-	/* Initialize return length value */
-	*retlen = 0;
+	/* Grab the lock and see if the device is available */
+	nand_get_chip (this, mtd, FL_WRITING, NULL);
 
 	/* Select the NAND device */
 	nand_select ();
 
 	/* Check the WP bit */
-	nand_command (mtd, NAND_CMD_STATUS, -1, -1);
-	if (!(readb (this->IO_ADDR) & 0x80)) {
-		DEBUG (MTD_DEBUG_LEVEL0,
-			"nand_write_ecc: Device is write protected!!!\n");
-		nand_deselect ();
-		spin_lock_bh (&this->chip_lock);
-		this->state = FL_READY;
-		wake_up (&this->wq);
-		spin_unlock_bh (&this->chip_lock);
-		return -EIO;
+	this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
+	if (!(readb (this->IO_ADDR_R) & 0x80)) {
+		DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: Device is write protected!!!\n");
+		ret = -EIO;
+		goto out;
 	}
 
 	/* Loop until all data is written */
-	while (*retlen < len) {
-		/* Write data into buffer */
-		if ((col + len) >= mtd->oobblock)
-			for(i=col, cnt=0 ; i < mtd->oobblock ; i++, cnt++)
-				this->data_buf[i] = buf[(*retlen + cnt)];
-		else
-			for(i=col, cnt=0 ; cnt < (len - *retlen) ; i++, cnt++)
-				this->data_buf[i] = buf[(*retlen + cnt)];
-		
-#ifdef CONFIG_MTD_NAND_ECC
-		/* Zero out the ECC array */
-		for (i=0 ; i < 6 ; i++)
-			ecc_code[i] = 0x00;
-
-		/* Calculate and write the ECC if we have enough data */
-		if ((col < mtd->eccsize) &&
-			((col + (len - *retlen)) >= mtd->eccsize)) {
-			nand_command (mtd, NAND_CMD_READ0, col, page);
-			for (i=0 ; i < col ; i++)
-				this->data_buf[i] = readb (this->IO_ADDR); 
-			nand_calculate_ecc (&this->data_buf[0], &ecc_code[0]);
-			for (i=0 ; i<3 ; i++)
-				this->data_buf[(mtd->oobblock + i)] =
-					ecc_code[i];
-		}
-
-		/* Calculate and write the second ECC if we have enough data */
-		if ((mtd->oobblock == 512) &&
-			((col + (len - *retlen)) >= mtd->oobblock)) {
-			nand_calculate_ecc (&this->data_buf[256], &ecc_code[3]);
-			for (i=3 ; i<6 ; i++)
-				this->data_buf[(mtd->oobblock + i)] =
-					ecc_code[i];
-		}
-
-		/* Write ones for partial page programming */
-		for (i=ecc_bytes ; i < mtd->oobsize ; i++)
-			this->data_buf[(mtd->oobblock + i)] = 0xff;
-#else
-		/* Write ones for partial page programming */
-		for (i=mtd->oobblock ; i < (mtd->oobblock + mtd->oobsize) ; i++)
-			this->data_buf[i] = 0xff;
-#endif
-
-		/* Write pre-padding bytes into buffer */
-		for (i=0 ; i < col ; i++)
-			this->data_buf[i] = 0xff;
-
-		/* Write post-padding bytes into buffer */
-		if ((col + (len - *retlen)) < mtd->oobblock) {
-			for(i=(col + cnt) ; i < mtd->oobblock ; i++)
-				this->data_buf[i] = 0xff;
-		}
-
-		/* Send command to begin auto page programming */
-		nand_command (mtd, NAND_CMD_SEQIN, 0x00, page);
-
-		/* Write out complete page of data */
-		for (i=0 ; i < (mtd->oobblock + mtd->oobsize) ; i++)
-			writeb (this->data_buf[i], this->IO_ADDR);
-
-		/* Send command to actually program the data */
-		nand_command (mtd, NAND_CMD_PAGEPROG, -1, -1);
-
-		/*
-		 * Wait for program operation to complete. This could
-		 * take up to 3000us (3ms) on some devices, so we try
-		 * and exit as quickly as possible.
+	while (written < len) {
+		/* 
+		 * Check, if we have a full page write, then we can
+		 * use the given buffer, else we have to copy
 		 */
-		status = 0;
-		for (i=0 ; i<24 ; i++) {
-			/* Delay for 125us */
-			udelay (125);
-
-			/* Check the status */
-			nand_command (mtd, NAND_CMD_STATUS, -1, -1);
-			status = (int) readb (this->IO_ADDR);
-			if (status & 0x40)
-				break;
-		}
-
-		/* See if device thinks it succeeded */
-		if (status & 0x01) {
-			DEBUG (MTD_DEBUG_LEVEL0,
-				"nand_write_ecc: " \
-				"Failed write, page 0x%08x, " \
-				"%6i bytes were succesful\n", page, *retlen);
-			nand_deselect ();
-			spin_lock_bh (&this->chip_lock);
-			this->state = FL_READY;
-			wake_up (&this->wq);
-			spin_unlock_bh (&this->chip_lock);
-			return -EIO;
-		}
-
-#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
-		/*
-		 * The NAND device assumes that it is always writing to
-		 * a cleanly erased page. Hence, it performs its internal
-		 * write verification only on bits that transitioned from
-		 * 1 to 0. The device does NOT verify the whole page on a
-		 * byte by byte basis. It is possible that the page was
-		 * not completely erased or the page is becoming unusable
-		 * due to wear. The read with ECC would catch the error
-		 * later when the ECC page check fails, but we would rather
-		 * catch it early in the page write stage. Better to write
-		 * no data than invalid data.
-		 */
-		
-		/* Send command to read back the page */
-		if (col < mtd->eccsize)
-			nand_command (mtd, NAND_CMD_READ0, col, page);
-		else
-			nand_command (mtd, NAND_CMD_READ1, col - 256, page);
-
-		/* Loop through and verify the data */
-		for (i=col ; i < cnt ; i++) {
-			if (this->data_buf[i] != readb (this->IO_ADDR)) {
-				DEBUG (MTD_DEBUG_LEVEL0,
-					"nand_write_ecc: " \
-					"Failed write verify, page 0x%08x, " \
-					"%6i bytes were succesful\n",
-					page, *retlen);
-				nand_deselect ();
-				spin_lock_bh (&this->chip_lock);
-				this->state = FL_READY;
-				wake_up (&this->wq);
-				spin_unlock_bh (&this->chip_lock);
-				return -EIO;
+		if (!col && (len - written) >= mtd->oobblock) {   
+			this->data_poi = (u_char*) &buf[written];
+			cnt = mtd->oobblock;
+		} else {
+			cnt = 0;
+			for (i = col; i < len && i < mtd->oobblock; i++) {
+				this->data_buf[i] = buf[written + i];
+				cnt++;
 			}
+			this->data_poi = this->data_buf;		
 		}
-
-#ifdef CONFIG_MTD_NAND_ECC
-		/*
-		 * We also want to check that the ECC bytes wrote
-		 * correctly for the same reasons stated above.
-		 */
-		nand_command (mtd, NAND_CMD_READOOB, 0x00, page);
-		for (i=0 ; i < ecc_bytes ; i++) {
-			if ((readb (this->IO_ADDR) != ecc_code[i]) &&
-					ecc_code[i]) {
-				DEBUG (MTD_DEBUG_LEVEL0,
-					"nand_write_ecc: Failed ECC write " \
-					"verify, page 0x%08x, " \
-					"%6i bytes were succesful\n",
-					page, i);
-				nand_deselect ();
-				spin_lock_bh (&this->chip_lock);
-				this->state = FL_READY;
-				wake_up (&this->wq);
-				spin_unlock_bh (&this->chip_lock);
-				return -EIO;
-			}
-		}
-#endif
-
-#endif
-
-		/*
-		 * If we are writing a large amount of data and/or it
-		 * crosses page or half-page boundaries, we set the
-		 * the column to zero. It simplifies the program logic.
-		 */
-		if (col)
-			col = 0x00;
+		/* We use the same function for write and writev !) */
+		if (eccbuf) {
+			ret = nand_write_page (mtd, this, page, col, cnt ,&eccbuf[oob], oobsel);
+			oob += mtd->oobsize;
+		} else 
+			ret = nand_write_page (mtd, this, page, col, cnt, NULL, oobsel);	
+		
+		if (ret)
+			goto out;
 
 		/* Update written bytes count */
-		*retlen += cnt;
-
+		written += cnt;
+		/* Next write is aligned */
+		col = 0;
 		/* Increment page address */
 		page++;
 	}
 
+out:
 	/* De-select the NAND device */
 	nand_deselect ();
 
@@ -686,24 +869,19 @@
 	wake_up (&this->wq);
 	spin_unlock_bh (&this->chip_lock);
 
-	/* Return happy */
-	*retlen = len;
-	return 0;
+	*retlen = written;
+	return ret;
 }
 
 /*
  * NAND write out-of-band
  */
-static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len,
-				size_t *retlen, const u_char *buf)
+static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf)
 {
-	int i, column, page, status;
+	int i, column, page, status, ret = 0;
 	struct nand_chip *this = mtd->priv;
-	DECLARE_WAITQUEUE(wait, current);
-	
-	DEBUG (MTD_DEBUG_LEVEL3,
-		"nand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to,
-		(int) len);
+
+	DEBUG (MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
 
 	/* Shift to get page */
 	page = ((int) to) >> this->page_shift;
@@ -716,105 +894,65 @@
 
 	/* Do not allow write past end of page */
 	if ((column + len) > mtd->oobsize) {
-		DEBUG (MTD_DEBUG_LEVEL0,
-			"nand_write_oob: Attempt to write past end of page\n");
+		DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Attempt to write past end of page\n");
 		return -EINVAL;
 	}
 
-retry:
 	/* Grab the lock and see if the device is available */
-	spin_lock_bh (&this->chip_lock);
-
-	switch (this->state) {
-	case FL_READY:
-		this->state = FL_WRITING;
-		spin_unlock_bh (&this->chip_lock);
-		break;
-
-	default:
-		set_current_state (TASK_UNINTERRUPTIBLE);
-		add_wait_queue (&this->wq, &wait);
-		spin_unlock_bh (&this->chip_lock);
-		schedule();
-
-		remove_wait_queue (&this->wq, &wait);
-		goto retry;
-	};
+	nand_get_chip (this, mtd, FL_WRITING, NULL);
 
 	/* Select the NAND device */
 	nand_select ();
 
 	/* Check the WP bit */
-	nand_command (mtd, NAND_CMD_STATUS, -1, -1);
-	if (!(readb (this->IO_ADDR) & 0x80)) {
-		DEBUG (MTD_DEBUG_LEVEL0,
-			"nand_write_oob: Device is write protected!!!\n");
-		nand_deselect ();
-		spin_lock_bh (&this->chip_lock);
-		this->state = FL_READY;
-		wake_up (&this->wq);
-		spin_unlock_bh (&this->chip_lock);
-		return -EIO;
+	this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
+	if (!(readb (this->IO_ADDR_R) & 0x80)) {
+		DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Device is write protected!!!\n");
+		ret = -EIO;
+		goto out;
 	}
 
 	/* Write out desired data */
-	nand_command (mtd, NAND_CMD_SEQIN, column + 512, page);
-	for (i=0 ; i<len ; i++)
-		writeb (buf[i], this->IO_ADDR);
+	this->cmdfunc (mtd, NAND_CMD_SEQIN, mtd->oobblock, page);
+	/* prepad 0xff for partial programming */
+	for (i = 0; i < column; i++)
+		writeb (0xff, this->IO_ADDR_W);
+	/* write data */
+	for (i = 0; i < len; i++)
+		writeb (buf[i], this->IO_ADDR_W);	
+	/* postpad 0xff for partial programming */
+	for (i = len + column; i < mtd->oobsize; i++)
+		writeb (0xff, this->IO_ADDR_W);
 
 	/* Send command to program the OOB data */
-	nand_command (mtd, NAND_CMD_PAGEPROG, -1, -1);
+	this->cmdfunc (mtd, NAND_CMD_PAGEPROG, -1, -1);
 
-	/*
-	 * Wait for program operation to complete. This could
-	 * take up to 3000us (3ms) on some devices, so we try
-	 * and exit as quickly as possible.
-	 */
-	status = 0;
-	for (i=0 ; i<24 ; i++) {
-		/* Delay for 125us */
-		udelay (125);
-
-		/* Check the status */
-		nand_command (mtd, NAND_CMD_STATUS, -1, -1);
-		status = (int) readb (this->IO_ADDR);
-		if (status & 0x40)
-			break;
-	}
+	status = this->waitfunc (mtd, this, FL_WRITING);
 
 	/* See if device thinks it succeeded */
 	if (status & 0x01) {
-		DEBUG (MTD_DEBUG_LEVEL0,
-			"nand_write_oob: " \
-			"Failed write, page 0x%08x\n", page);
-		nand_deselect ();
-		spin_lock_bh (&this->chip_lock);
-		this->state = FL_READY;
-		wake_up (&this->wq);
-		spin_unlock_bh (&this->chip_lock);
-		return -EIO;
+		DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write, page 0x%08x\n", page);
+		ret = -EIO;
+		goto out;
 	}
+	/* Return happy */
+	*retlen = len;
 
 #ifdef CONFIG_MTD_NAND_VERIFY_WRITE
 	/* Send command to read back the data */
-	nand_command (mtd, NAND_CMD_READOOB, column, page);
+	this->cmdfunc (mtd, NAND_CMD_READOOB, column, page);
 
 	/* Loop through and verify the data */
-	for (i=0 ; i<len ; i++) {
-		if (buf[i] != readb (this->IO_ADDR)) {
-			DEBUG (MTD_DEBUG_LEVEL0,
-				"nand_write_oob: " \
-				"Failed write verify, page 0x%08x\n", page);
-			nand_deselect ();
-			spin_lock_bh (&this->chip_lock);
-			this->state = FL_READY;
-			wake_up (&this->wq);
-			spin_unlock_bh (&this->chip_lock);
-			return -EIO;
+	for (i = 0; i < len; i++) {
+		if (buf[i] != readb (this->IO_ADDR_R)) {
+			DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write verify, page 0x%08x\n", page);
+			ret = -EIO;
+			goto out;
 		}
 	}
 #endif
 
+out:
 	/* De-select the NAND device */
 	nand_deselect ();
 
@@ -824,250 +962,107 @@
 	wake_up (&this->wq);
 	spin_unlock_bh (&this->chip_lock);
 
-	/* Return happy */
-	*retlen = len;
-	return 0;
+	return ret;
 }
 
+
 /*
  * NAND write with iovec
  */
-static int nand_writev (struct mtd_info *mtd, const struct iovec *vecs,
-				unsigned long count, loff_t to, size_t *retlen)
+static int nand_writev (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, 
+		loff_t to, size_t * retlen)
+{
+	return (nand_writev_ecc (mtd, vecs, count, to, retlen, NULL, 0));	
+}
+
+static int nand_writev_ecc (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, 
+		loff_t to, size_t * retlen, u_char *eccbuf, int oobsel)
 {
-	int i, page, col, cnt, len, total_len, status;
+	int i, page, col, cnt, len, total_len, ret = 0, written = 0;
 	struct nand_chip *this = mtd->priv;
-	DECLARE_WAITQUEUE(wait, current);
-#ifdef CONFIG_MTD_NAND_ECC
-	int ecc_bytes = (mtd->oobblock == 512) ? 6 : 3;
-#endif
 
 	/* Calculate total length of data */
 	total_len = 0;
-	for (i=0 ; i < count ; i++)
+	for (i = 0; i < count; i++)
 		total_len += (int) vecs[i].iov_len;
 
 	DEBUG (MTD_DEBUG_LEVEL3,
-		"nand_writev: to = 0x%08x, len = %i\n", (unsigned int) to,
-			(unsigned int) total_len);
+	       "nand_writev: to = 0x%08x, len = %i, count = %ld\n", (unsigned int) to, (unsigned int) total_len, count);
 
 	/* Do not allow write past end of page */
 	if ((to + total_len) > mtd->size) {
-		DEBUG (MTD_DEBUG_LEVEL0,
-			"nand_writev: Attempted write past end of device\n");
+		DEBUG (MTD_DEBUG_LEVEL0, "nand_writev: Attempted write past end of device\n");
 		return -EINVAL;
 	}
 
-retry:
-	/* Grab the lock and see if the device is available */
-	spin_lock_bh (&this->chip_lock);
-
-	switch (this->state) {
-	case FL_READY:
-		this->state = FL_WRITING;
-		spin_unlock_bh (&this->chip_lock);
-		break;
-
-	default:
-		set_current_state (TASK_UNINTERRUPTIBLE);
-		add_wait_queue (&this->wq, &wait);
-		spin_unlock_bh (&this->chip_lock);
-		schedule();
-
-		remove_wait_queue (&this->wq, &wait);
-		goto retry;
-	};
-
 	/* Shift to get page */
 	page = ((int) to) >> this->page_shift;
 
 	/* Get the starting column */
 	col = to & (mtd->oobblock - 1);
 
-	/* Initialize return length value */
-	*retlen = 0;
+	/* Grab the lock and see if the device is available */
+	nand_get_chip (this, mtd, FL_WRITING, NULL);
 
 	/* Select the NAND device */
 	nand_select ();
 
 	/* Check the WP bit */
-	nand_command (mtd, NAND_CMD_STATUS, -1, -1);
-	if (!(readb (this->IO_ADDR) & 0x80)) {
-		DEBUG (MTD_DEBUG_LEVEL0,
-			"nand_writev: Device is write protected!!!\n");
-		nand_deselect ();
-		spin_lock_bh (&this->chip_lock);
-		this->state = FL_READY;
-		wake_up (&this->wq);
-		spin_unlock_bh (&this->chip_lock);
-		return -EIO;
+	this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
+	if (!(readb (this->IO_ADDR_R) & 0x80)) {
+		DEBUG (MTD_DEBUG_LEVEL0, "nand_writev: Device is write protected!!!\n");
+		ret = -EIO;
+		goto out;
 	}
 
 	/* Loop until all iovecs' data has been written */
 	cnt = col;
 	len = 0;
+	
 	while (count) {
-		/* Do any need pre-fill for partial page programming */
-		for (i=0 ; i < cnt ; i++)
-			this->data_buf[i] = 0xff;
-
-		/*
-		 * Read data out of each tuple until we have a full page
-		 * to write or we've read all the tuples.
+		/* 
+		 *  Check, if we write from offset 0 and if the tuple
+		 *  gives us not enough data for a full page write. Then we
+		 *  can use the iov direct, else we have to copy into
+		 *  data_buf.		
 		 */
-		while ((cnt < mtd->oobblock) && count) {
-			this->data_buf[cnt++] =
-				((u_char *) vecs->iov_base)[len++];
+		if (!cnt && (vecs->iov_len - len) >= mtd->oobblock) {
+			cnt = mtd->oobblock;
+			this->data_poi = (u_char *) vecs->iov_base;
+			this->data_poi += len;
+			len += mtd->oobblock; 
+			/* Check, if we have to switch to the next tuple */
 			if (len >= (int) vecs->iov_len) {
 				vecs++;
 				len = 0;
 				count--;
 			}
+		} else {
+			/*
+			 * Read data out of each tuple until we have a full page
+			 * to write or we've read all the tuples.
+		 	*/
+			while ((cnt < mtd->oobblock) && count) {
+				if (vecs->iov_base != NULL && vecs->iov_len) {
+					this->data_buf[cnt++] = ((u_char *) vecs->iov_base)[len++];
+				}
+				/* Check, if we have to switch to the next tuple */
+				if (len >= (int) vecs->iov_len) {
+					vecs++;
+					len = 0;
+					count--;
+				}
+			}	
+			this->data_poi = this->data_buf;	
 		}
 		
-		/* Do any need post-fill for partial page programming */
-		for (i=cnt ; i < mtd->oobblock ; i++)
-			this->data_buf[i] = 0xff;
-
-#ifdef CONFIG_MTD_NAND_ECC
-		/* Zero out the ECC array */
-		for (i=0 ; i < 6 ; i++)
-			this->ecc_code_buf[i] = 0x00;
-
-		/* Calculate and write the first ECC */
-		if (col >= mtd->eccsize) {
-			nand_command (mtd, NAND_CMD_READ0, col, page);
-			for (i=0 ; i < col ; i++)
-				this->data_buf[i] = readb (this->IO_ADDR); 
-			nand_calculate_ecc (&this->data_buf[0],
-				&(this->ecc_code_buf[0]));
-			for (i=0 ; i<3 ; i++)
-				this->data_buf[(mtd->oobblock + i)] =
-					this->ecc_code_buf[i];
-		}
-
-		/* Calculate and write the second ECC */
-		if ((mtd->oobblock == 512) && (cnt == mtd->oobblock)) {
-			nand_calculate_ecc (&this->data_buf[256],
-				&(this->ecc_code_buf[3]));
-			for (i=3 ; i<6 ; i++)
-				this->data_buf[(mtd->oobblock + i)] =
-					this->ecc_code_buf[i];
-		}
-
-		/* Write ones for partial page programming */
-		for (i=ecc_bytes ; i < mtd->oobsize ; i++)
-			this->data_buf[(mtd->oobblock + i)] = 0xff;
-#else
-		/* Write ones for partial page programming */
-		for (i=mtd->oobblock ; i < (mtd->oobblock + mtd->oobsize) ; i++)
-			this->data_buf[i] = 0xff;
-#endif
-		/* Send command to begin auto page programming */
-		nand_command (mtd, NAND_CMD_SEQIN, 0x00, page);
-
-		/* Write out complete page of data */
-		for (i=0 ; i < (mtd->oobblock + mtd->oobsize) ; i++)
-			writeb (this->data_buf[i], this->IO_ADDR);
-
-		/* Send command to actually program the data */
-		nand_command (mtd, NAND_CMD_PAGEPROG, -1, -1);
-
-		/*
-		 * Wait for program operation to complete. This could
-		 * take up to 3000us (3ms) on some devices, so we try
-		 * and exit as quickly as possible.
-		 */
-		status = 0;
-		for (i=0 ; i<24 ; i++) {
-			/* Delay for 125us */
-			udelay (125);
-
-			/* Check the status */
-			nand_command (mtd, NAND_CMD_STATUS, -1, -1);
-			status = (int) readb (this->IO_ADDR);
-			if (status & 0x40)
-				break;
-		}
-
-		/* See if device thinks it succeeded */
-		if (status & 0x01) {
-			DEBUG (MTD_DEBUG_LEVEL0,
-				"nand_writev: " \
-				"Failed write, page 0x%08x, " \
-				"%6i bytes were succesful\n", page, *retlen);
-			nand_deselect ();
-			spin_lock_bh (&this->chip_lock);
-			this->state = FL_READY;
-			wake_up (&this->wq);
-			spin_unlock_bh (&this->chip_lock);
-			return -EIO;
-		}
-
-#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
-		/*
-		 * The NAND device assumes that it is always writing to
-		 * a cleanly erased page. Hence, it performs its internal
-		 * write verification only on bits that transitioned from
-		 * 1 to 0. The device does NOT verify the whole page on a
-		 * byte by byte basis. It is possible that the page was
-		 * not completely erased or the page is becoming unusable
-		 * due to wear. The read with ECC would catch the error
-		 * later when the ECC page check fails, but we would rather
-		 * catch it early in the page write stage. Better to write
-		 * no data than invalid data.
-		 */
-		
-		/* Send command to read back the page */
-		if (col < mtd->eccsize)
-			nand_command (mtd, NAND_CMD_READ0, col, page);
-		else
-			nand_command (mtd, NAND_CMD_READ1, col - 256, page);
-
-		/* Loop through and verify the data */
-		for (i=col ; i < cnt ; i++) {
-			if (this->data_buf[i] != readb (this->IO_ADDR)) {
-				DEBUG (MTD_DEBUG_LEVEL0,
-					"nand_writev: " \
-					"Failed write verify, page 0x%08x, " \
-					"%6i bytes were succesful\n",
-					page, *retlen);
-				nand_deselect ();
-				spin_lock_bh (&this->chip_lock);
-				this->state = FL_READY;
-				wake_up (&this->wq);
-				spin_unlock_bh (&this->chip_lock);
-				return -EIO;
-			}
-		}
-
-#ifdef CONFIG_MTD_NAND_ECC
-		/*
-		 * We also want to check that the ECC bytes wrote
-		 * correctly for the same reasons stated above.
-		 */
-		nand_command (mtd, NAND_CMD_READOOB, 0x00, page);
-		for (i=0 ; i < ecc_bytes ; i++) {
-			if ((readb (this->IO_ADDR) != this->ecc_code_buf[i]) &&
-					this->ecc_code_buf[i]) {
-				DEBUG (MTD_DEBUG_LEVEL0,
-					"nand_writev: Failed ECC write " \
-					"verify, page 0x%08x, " \
-					"%6i bytes were succesful\n",
-					page, i);
-				nand_deselect ();
-				spin_lock_bh (&this->chip_lock);
-				this->state = FL_READY;
-				wake_up (&this->wq);
-				spin_unlock_bh (&this->chip_lock);
-				return -EIO;
-			}
-		}
-#endif
+		/* We use the same function for write and writev !) */
+		ret = nand_write_page (mtd, this, page, col, cnt, NULL, oobsel);
+		if (ret)
+			goto out;
 
-#endif
 		/* Update written bytes count */
-		*retlen += (cnt - col);
+		written += (cnt - col);
 
 		/* Reset written byte counter and column */
 		col = cnt = 0;
@@ -1076,6 +1071,7 @@
 		page++;
 	}
 
+out:
 	/* De-select the NAND device */
 	nand_deselect ();
 
@@ -1085,8 +1081,8 @@
 	wake_up (&this->wq);
 	spin_unlock_bh (&this->chip_lock);
 
-	/* Return happy */
-	return 0;
+	*retlen = written;
+	return ret;
 }
 
 /*
@@ -1094,53 +1090,33 @@
  */
 static int nand_erase (struct mtd_info *mtd, struct erase_info *instr)
 {
-	int i, page, len, status, pages_per_block;
+	int page, len, status, pages_per_block, ret;
 	struct nand_chip *this = mtd->priv;
-	DECLARE_WAITQUEUE(wait, current);
+	DECLARE_WAITQUEUE (wait, current);
 
 	DEBUG (MTD_DEBUG_LEVEL3,
-		"nand_erase: start = 0x%08x, len = %i\n",
-		(unsigned int) instr->addr, (unsigned int) instr->len);
+	       "nand_erase: start = 0x%08x, len = %i\n", (unsigned int) instr->addr, (unsigned int) instr->len);
 
 	/* Start address must align on block boundary */
 	if (instr->addr & (mtd->erasesize - 1)) {
-		DEBUG (MTD_DEBUG_LEVEL0,
-			"nand_erase: Unaligned address\n");
+		DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Unaligned address\n");
 		return -EINVAL;
 	}
 
 	/* Length must align on block boundary */
 	if (instr->len & (mtd->erasesize - 1)) {
-		DEBUG (MTD_DEBUG_LEVEL0,
-			"nand_erase: Length not block aligned\n");
+		DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Length not block aligned\n");
 		return -EINVAL;
 	}
 
 	/* Do not allow erase past end of device */
 	if ((instr->len + instr->addr) > mtd->size) {
-		DEBUG (MTD_DEBUG_LEVEL0,
-			"nand_erase: Erase past end of device\n");
+		DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Erase past end of device\n");
 		return -EINVAL;
 	}
 
-retry:
 	/* Grab the lock and see if the device is available */
-	spin_lock_bh (&this->chip_lock);
-
-	switch (this->state) {
-	case FL_READY:
-		this->state = FL_ERASING;
-		break;
-
-	default:
-		set_current_state (TASK_UNINTERRUPTIBLE);
-		add_wait_queue (&this->wq, &wait);
-		spin_unlock_bh (&this->chip_lock);
-		schedule();
-
-		remove_wait_queue (&this->wq, &wait);
-		goto retry;
-	};
+	nand_get_chip (this, mtd, FL_ERASING, NULL);
 
 	/* Shift to get first page */
 	page = (int) (instr->addr >> this->page_shift);
@@ -1152,81 +1128,78 @@
 	nand_select ();
 
 	/* Check the WP bit */
-	nand_command (mtd, NAND_CMD_STATUS, -1, -1);
-	if (!(readb (this->IO_ADDR) & 0x80)) {
-		DEBUG (MTD_DEBUG_LEVEL0,
-			"nand_erase: Device is write protected!!!\n");
-		nand_deselect ();
-		this->state = FL_READY;
-		spin_unlock_bh (&this->chip_lock);
-		return -EIO;
+	this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
+	if (!(readb (this->IO_ADDR_R) & 0x80)) {
+		DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Device is write protected!!!\n");
+		instr->state = MTD_ERASE_FAILED;
+		goto erase_exit;
 	}
 
 	/* Loop through the pages */
 	len = instr->len;
+
+	instr->state = MTD_ERASING;
+
 	while (len) {
+		/* Check if we have a bad block, we do not erase bad blocks ! */
+		this->cmdfunc (mtd, NAND_CMD_READOOB, NAND_BADBLOCK_POS, page);
+		if (readb (this->IO_ADDR_R) != 0xff) {
+			printk (KERN_WARNING "nand_erase: attempt to erase a bad block at page 0x%08x\n", page);
+			instr->state = MTD_ERASE_FAILED;
+			goto erase_exit;
+		}
+
 		/* Send commands to erase a page */
-		nand_command(mtd, NAND_CMD_ERASE1, -1, page);
-		nand_command(mtd, NAND_CMD_ERASE2, -1, -1);
+		this->cmdfunc (mtd, NAND_CMD_ERASE1, -1, page);
+		this->cmdfunc (mtd, NAND_CMD_ERASE2, -1, -1);
 
-		/*
-		 * Wait for program operation to complete. This could
-		 * take up to 4000us (4ms) on some devices, so we try
-		 * and exit as quickly as possible.
-		 */
-		status = 0;
-		for (i=0 ; i<32 ; i++) {
-			/* Delay for 125us */
-			udelay (125);
-
-			/* Check the status */
-			nand_command (mtd, NAND_CMD_STATUS, -1, -1);
-			status = (int) readb (this->IO_ADDR);
-			if (status & 0x40)
-				break;
-		}
+		spin_unlock_bh (&this->chip_lock);
+		status = this->waitfunc (mtd, this, FL_ERASING);
 
+		/* Get spinlock, in case we exit */
+		spin_lock_bh (&this->chip_lock);
 		/* See if block erase succeeded */
 		if (status & 0x01) {
-			DEBUG (MTD_DEBUG_LEVEL0,
-				"nand_erase: " \
-				"Failed erase, page 0x%08x\n", page);
-			nand_deselect ();
-			this->state = FL_READY;
-			spin_unlock_bh (&this->chip_lock);
-			return -EIO;
+			DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page);
+			instr->state = MTD_ERASE_FAILED;
+			goto erase_exit;
+		}
+		
+		/* Check, if we were interupted */
+		if (this->state == FL_ERASING) {
+			/* Increment page address and decrement length */
+			len -= mtd->erasesize;
+			page += pages_per_block;
 		}
-
-		/* Increment page address and decrement length */
-		len -= mtd->erasesize;
-		page += pages_per_block;
-
 		/* Release the spin lock */
 		spin_unlock_bh (&this->chip_lock);
-
 erase_retry:
-		/* Check the state and sleep if it changed */
 		spin_lock_bh (&this->chip_lock);
-		if (this->state == FL_ERASING) {
+		/* Check the state and sleep if it changed */
+		if (this->state == FL_ERASING || this->state == FL_READY) {
+			/* Select the NAND device again, if we were interrupted */
+			this->state = FL_ERASING;
+			nand_select ();
 			continue;
-		}
-		else {
+		} else {
 			set_current_state (TASK_UNINTERRUPTIBLE);
 			add_wait_queue (&this->wq, &wait);
 			spin_unlock_bh (&this->chip_lock);
-			schedule();
-
+			schedule ();
 			remove_wait_queue (&this->wq, &wait);
 			goto erase_retry;
 		}
 	}
-	spin_unlock_bh (&this->chip_lock);
+	instr->state = MTD_ERASE_DONE;
 
+erase_exit:
 	/* De-select the NAND device */
 	nand_deselect ();
+	spin_unlock_bh (&this->chip_lock);
 
+	ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;;
 	/* Do call back function */
-	if (instr->callback)
+	if (!ret && instr->callback)
 		instr->callback (instr);
 
 	/* The device is ready */
@@ -1234,8 +1207,8 @@
 	this->state = FL_READY;
 	spin_unlock_bh (&this->chip_lock);
 
-	/* Return happy */
-	return 0;
+	/* Return more or less happy */
+	return ret;
 }
 
 /*
@@ -1244,16 +1217,16 @@
 static void nand_sync (struct mtd_info *mtd)
 {
 	struct nand_chip *this = mtd->priv;
-	DECLARE_WAITQUEUE(wait, current);
+	DECLARE_WAITQUEUE (wait, current);
 
 	DEBUG (MTD_DEBUG_LEVEL3, "nand_sync: called\n");
 
 retry:
 	/* Grab the spinlock */
-	spin_lock_bh(&this->chip_lock);
+	spin_lock_bh (&this->chip_lock);
 
 	/* See what's going on */
-	switch(this->state) {
+	switch (this->state) {
 	case FL_READY:
 	case FL_SYNCING:
 		this->state = FL_SYNCING;
@@ -1270,7 +1243,7 @@
 		goto retry;
 	}
 
-        /* Lock the device */
+	/* Lock the device */
 	spin_lock_bh (&this->chip_lock);
 
 	/* Set the device to be ready again */
@@ -1279,7 +1252,7 @@
 		wake_up (&this->wq);
 	}
 
-        /* Unlock the device */
+	/* Unlock the device */
 	spin_unlock_bh (&this->chip_lock);
 }
 
@@ -1291,46 +1264,99 @@
 	int i, nand_maf_id, nand_dev_id;
 	struct nand_chip *this = mtd->priv;
 
+	/* check for proper chip_delay setup, set 20us if not */
+	if (!this->chip_delay)
+		this->chip_delay = 20;
+
+	/* check, if a user supplied command function given */
+	if (this->cmdfunc == NULL)
+		this->cmdfunc = nand_command;
+
+	/* check, if a user supplied wait function given */
+	if (this->waitfunc == NULL)
+		this->waitfunc = nand_wait;
+
 	/* Select the device */
 	nand_select ();
 
 	/* Send the command for reading device ID */
-	nand_command (mtd, NAND_CMD_READID, 0x00, -1);
+	this->cmdfunc (mtd, NAND_CMD_READID, 0x00, -1);
 
 	/* Read manufacturer and device IDs */
-	nand_maf_id = readb (this->IO_ADDR);
-	nand_dev_id = readb (this->IO_ADDR);
+	nand_maf_id = readb (this->IO_ADDR_R);
+	nand_dev_id = readb (this->IO_ADDR_R);
 
 	/* Print and store flash device information */
 	for (i = 0; nand_flash_ids[i].name != NULL; i++) {
-		if (nand_maf_id == nand_flash_ids[i].manufacture_id &&
-		    nand_dev_id == nand_flash_ids[i].model_id) {
-			if (!mtd->size) {
-				mtd->name = nand_flash_ids[i].name;
-				mtd->erasesize = nand_flash_ids[i].erasesize;
-				mtd->size = (1 << nand_flash_ids[i].chipshift);
-				mtd->eccsize = 256;
-				if (nand_flash_ids[i].page256) {
-					mtd->oobblock = 256;
-					mtd->oobsize = 8;
-					this->page_shift = 8;
-				}
-				else {
-					mtd->oobblock = 512;
-					mtd->oobsize = 16;
-					this->page_shift = 9;
-				}
+		if (nand_dev_id == nand_flash_ids[i].id && !mtd->size) {
+			mtd->name = nand_flash_ids[i].name;
+			mtd->erasesize = nand_flash_ids[i].erasesize;
+			mtd->size = (1 << nand_flash_ids[i].chipshift);
+			mtd->eccsize = 256;
+			if (nand_flash_ids[i].page256) {
+				mtd->oobblock = 256;
+				mtd->oobsize = 8;
+				this->page_shift = 8;
+			} else {
+				mtd->oobblock = 512;
+				mtd->oobsize = 16;
+				this->page_shift = 9;
 			}
-			printk (KERN_INFO "NAND device: Manufacture ID:" \
-				" 0x%02x, Chip ID: 0x%02x (%s)\n",
-			       nand_maf_id, nand_dev_id, mtd->name);
+			/* Try to identify manufacturer */
+			for (i = 0; nand_manuf_ids[i].id != 0x0; i++) {
+				if (nand_manuf_ids[i].id == nand_maf_id)
+					break;
+			}	
+			printk (KERN_INFO "NAND device: Manufacture ID:"
+				" 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, 
+				nand_manuf_ids[i].name , mtd->name);
 			break;
 		}
 	}
 
-	/* Initialize state and spinlock */
+	/* 
+	 * check ECC mode, default to software
+	 * if 3byte/512byte hardware ECC is selected and we have 256 byte pagesize
+	 * fallback to software ECC 
+	*/
+	this->eccsize = 256;	/* set default eccsize */	
+
+	switch (this->eccmode) {
+
+	case NAND_ECC_HW3_512: 
+		if (mtd->oobblock == 256) {
+			printk (KERN_WARNING "512 byte HW ECC not possible on 256 Byte pagesize, fallback to SW ECC \n");
+			this->eccmode = NAND_ECC_SOFT;
+			this->calculate_ecc = nand_calculate_ecc;
+			this->correct_data = nand_correct_data;
+			break;		
+		} else 
+			this->eccsize = 512; /* set eccsize to 512 and fall through for function check */
+
+	case NAND_ECC_HW3_256:
+		if (this->calculate_ecc && this->correct_data && this->enable_hwecc)
+			break;
+		printk (KERN_WARNING "No ECC functions supplied, Hardware ECC not possible\n");
+		BUG();	
+
+	case NAND_ECC_NONE: 
+		this->eccmode = NAND_ECC_NONE;
+		break;
+
+	case NAND_ECC_SOFT:	
+		this->calculate_ecc = nand_calculate_ecc;
+		this->correct_data = nand_correct_data;
+		break;
+
+	default:
+		printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode);
+		BUG();	
+	}	
+
+	/* Initialize state, waitqueue and spinlock */
 	this->state = FL_READY;
-	spin_lock_init(&this->chip_lock);
+	init_waitqueue_head (&this->wq);
+	spin_lock_init (&this->chip_lock);
 
 	/* De-select the device */
 	nand_deselect ();
@@ -1357,6 +1383,7 @@
 	mtd->write_oob = nand_write_oob;
 	mtd->readv = NULL;
 	mtd->writev = nand_writev;
+	mtd->writev_ecc = nand_writev_ecc;
 	mtd->sync = nand_sync;
 	mtd->lock = NULL;
 	mtd->unlock = NULL;
@@ -1367,8 +1394,8 @@
 	return 0;
 }
 
-EXPORT_SYMBOL(nand_scan);
+EXPORT_SYMBOL (nand_scan);
 
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Steven J. Hill <sjhill@cotw.com");
-MODULE_DESCRIPTION("Generic NAND flash driver code");
+MODULE_LICENSE ("GPL");
+MODULE_AUTHOR ("Steven J. Hill <sjhill@cotw.com>, Thomas Gleixner <tglx@linutronix.de>");
+MODULE_DESCRIPTION ("Generic NAND flash driver code");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/nand/nand_ecc.c linux-2.4.21-pre6/drivers/mtd/nand/nand_ecc.c
--- linux-2.4.20/drivers/mtd/nand/nand_ecc.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/nand/nand_ecc.c	2003-03-26 23:49:20.000000000 +0000
@@ -4,11 +4,11 @@
  *  Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
  *                     Toshiba America Electronics Components, Inc.
  *
- * $Id: nand_ecc.c,v 1.7 2002/03/21 14:13:50 dwmw2 Exp $
+ * $Id: nand_ecc.c,v 1.8 2002/09/16 09:19:53 dwmw2 Exp $
  *
- * This program is free software; you can redistribute 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 free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
  *
  * This file contains an ECC algorithm from Toshiba that detects and
  * corrects 1 bit errors in a 256 byte block of data.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/nand/nand_ids.c linux-2.4.21-pre6/drivers/mtd/nand/nand_ids.c
--- linux-2.4.20/drivers/mtd/nand/nand_ids.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/nand/nand_ids.c	2003-03-26 23:49:40.000000000 +0000
@@ -0,0 +1,56 @@
+/*
+ *  drivers/mtd/nandids.c
+ *
+ *  Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de)
+ *
+ *
+ * $Id: nand_ids.c,v 1.1 2002/12/02 22:06:04 gleixner Exp $
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/module.h>
+#include <linux/mtd/nand.h>
+
+/*
+*	Chip ID list
+*/
+struct nand_flash_dev nand_flash_ids[] = {
+	{"NAND 1MB 5V", 0x6e, 20, 0x1000, 1},	// 1Mb 5V
+	{"NAND 2MB 5V", 0x64, 21, 0x1000, 1},	// 2Mb 5V
+	{"NAND 4MB 5V", 0x6b, 22, 0x2000, 0},	// 4Mb 5V
+	{"NAND 1MB 3,3V", 0xe8, 20, 0x1000, 1},	// 1Mb 3.3V
+	{"NAND 1MB 3,3V", 0xec, 20, 0x1000, 1},	// 1Mb 3.3V
+	{"NAND 2MB 3,3V", 0xea, 21, 0x1000, 1},	// 2Mb 3.3V
+	{"NAND 4MB 3,3V", 0xd5, 22, 0x2000, 0},	// 4Mb 3.3V
+	{"NAND 4MB 3,3V", 0xe3, 22, 0x2000, 0},	// 4Mb 3.3V
+	{"NAND 4MB 3,3V", 0xe5, 22, 0x2000, 0},	// 4Mb 3.3V
+	{"NAND 8MB 3,3V", 0xd6, 23, 0x2000, 0},	// 8Mb 3.3V
+	{"NAND 8MB 3,3V", 0xe6, 23, 0x2000, 0},	// 8Mb 3.3V
+	{"NAND 16MB 3,3V", 0x73, 24, 0x4000, 0},// 16Mb 3,3V
+	{"NAND 32MB 3,3V", 0x75, 25, 0x4000, 0}, // 32Mb 3,3V
+	{"NAND 64MB 3,3V", 0x76, 26, 0x4000, 0}, // 64Mb 3,3V
+	{"NAND 128MB 3,3V", 0x79, 27, 0x4000, 0}, // 128Mb 3,3V
+	{NULL,}
+};
+
+/*
+*	Manufacturer ID list
+*/
+struct nand_manufacturers nand_manuf_ids[] = {
+	{NAND_MFR_TOSHIBA, "Toshiba"},
+	{NAND_MFR_SAMSUNG, "Samsung"},
+	{NAND_MFR_FUJITSU, "Fujitsu"},
+	{NAND_MFR_NATIONAL, "National"},
+	{0x0, "Unknown"}
+};
+
+
+EXPORT_SYMBOL (nand_manuf_ids);
+EXPORT_SYMBOL (nand_flash_ids);
+
+MODULE_LICENSE ("GPL");
+MODULE_AUTHOR ("Thomas Gleixner <tglx@linutronix.de>");
+MODULE_DESCRIPTION ("Nand device & manufacturer ID's");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/nand/spia.c linux-2.4.21-pre6/drivers/mtd/nand/spia.c
--- linux-2.4.20/drivers/mtd/nand/spia.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/nand/spia.c	2003-03-26 23:48:59.000000000 +0000
@@ -3,7 +3,12 @@
  *
  *  Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
  *
- * $Id: spia.c,v 1.12 2001/10/02 15:05:14 dwmw2 Exp $
+ *
+ *	10-29-2001 TG	change to support hardwarespecific access
+ *			to controllines	(due to change in nand.c)
+ *			page_cache added
+ *
+ * $Id: spia.c,v 1.16 2002/03/05 13:50:47 dwmw2 Exp $
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -75,6 +80,25 @@
 };
 #define NUM_PARTITIONS 2
 
+
+/* 
+ *	hardware specific access to control-lines
+*/
+void spia_hwcontrol(int cmd){
+
+    switch(cmd){
+
+	case NAND_CTL_SETCLE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) |=  0x01; break;
+	case NAND_CTL_CLRCLE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) &= ~0x01; break;
+
+	case NAND_CTL_SETALE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) |=  0x02; break;
+	case NAND_CTL_CLRALE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) &= ~0x02; break;
+
+	case NAND_CTL_SETNCE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) &= ~0x04; break;
+	case NAND_CTL_CLRNCE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) |=  0x04; break;
+    }
+}
+
 /*
  * Main initialization routine
  */
@@ -107,11 +131,12 @@
 	(*(volatile unsigned char *) (spia_io_base + spia_peddr)) = 0x07;
 
 	/* Set address of NAND IO lines */
-	this->IO_ADDR = spia_fio_base;
-	this->CTRL_ADDR = spia_io_base + spia_pedr;
-	this->CLE = 0x01;
-	this->ALE = 0x02;
-	this->NCE = 0x04;
+	this->IO_ADDR_R = spia_fio_base;
+	this->IO_ADDR_W = spia_fio_base;
+	/* Set address of hardware control function */
+	this->hwcontrol = spia_hwcontrol;
+	/* 15 us command delay time */
+	this->chip_delay = 15;		
 
 	/* Scan to find existence of the device */
 	if (nand_scan (spia_mtd)) {
@@ -127,6 +152,16 @@
 		return -ENOMEM;
 	}
 
+	/* Allocate memory for internal data buffer */
+	this->data_cache = kmalloc (sizeof(u_char) * (spia_mtd->oobblock + spia_mtd->oobsize), GFP_KERNEL);
+	if (!this->data_cache) {
+		printk ("Unable to allocate NAND data cache for SPIA.\n");
+		kfree (this->data_buf);
+		kfree (spia_mtd);
+		return = -ENOMEM;
+	}
+	this->cache_page = -1;
+
 	/* Register the partitions */
 	add_mtd_partitions(spia_mtd, partition_info, NUM_PARTITIONS);
 
@@ -148,6 +183,7 @@
 
 	/* Free internal data buffer */
 	kfree (this->data_buf);
+	kfree (this->page_cache);
 
 	/* Free the MTD device structure */
 	kfree (spia_mtd);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/nftlcore.c linux-2.4.21-pre6/drivers/mtd/nftlcore.c
--- linux-2.4.20/drivers/mtd/nftlcore.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/nftlcore.c	2003-03-26 23:48:58.000000000 +0000
@@ -1,7 +1,7 @@
 /* Linux driver for NAND Flash Translation Layer      */
 /* (c) 1999 Machine Vision Holdings, Inc.             */
 /* Author: David Woodhouse <dwmw2@infradead.org>      */
-/* $Id: nftlcore.c,v 1.85 2001/11/20 11:42:33 dwmw2 Exp $ */
+/* $Id: nftlcore.c,v 1.87 2002/09/13 14:35:33 dwmw2 Exp $ */
 
 /*
   The contents of this file are distributed under the GNU General
@@ -29,6 +29,7 @@
 #include <linux/kmod.h>
 #endif
 #include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
 #include <linux/mtd/nftl.h>
 #include <linux/mtd/compatmac.h>
 
@@ -118,9 +119,6 @@
 
 	init_MUTEX(&nftl->mutex);
 
-        /* get physical parameters */
-	nftl->EraseSize = mtd->erasesize;
-        nftl->nb_blocks = mtd->size / mtd->erasesize;
 	nftl->mtd = mtd;
 
         if (NFTL_mount(nftl) < 0) {
@@ -155,7 +153,7 @@
 
 	if (nftl->nr_sects != nftl->heads * nftl->cylinders * nftl->sectors) {
 		printk(KERN_WARNING "Cannot calculate an NFTL geometry to "
-		       "match size of 0x%lx.\n", nftl->nr_sects);
+		       "match size of 0x%x.\n", nftl->nr_sects);
 		printk(KERN_WARNING "Using C:%d H:%d S:%d (== 0x%lx sects)\n", 
 		       nftl->cylinders, nftl->heads , nftl->sectors, 
 		       (long)nftl->cylinders * (long)nftl->heads * (long)nftl->sectors );
@@ -446,17 +444,17 @@
                 if (BlockMap[block] == BLOCK_NIL)
                         continue;
                 
-                ret = MTD_READECC(nftl->mtd, (nftl->EraseSize * BlockMap[block])
-                                  + (block * 512), 512, &retlen, movebuf, (char *)&oob); 
+                ret = MTD_READECC(nftl->mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512),
+				  512, &retlen, movebuf, (char *)&oob, NAND_ECC_DISKONCHIP); 
                 if (ret < 0) {
                     ret = MTD_READECC(nftl->mtd, (nftl->EraseSize * BlockMap[block])
                                       + (block * 512), 512, &retlen,
-                                      movebuf, (char *)&oob); 
+                                      movebuf, (char *)&oob, NAND_ECC_DISKONCHIP); 
                     if (ret != -EIO) 
                         printk("Error went away on retry.\n");
                 }
                 MTD_WRITEECC(nftl->mtd, (nftl->EraseSize * targetEUN) + (block * 512),
-                             512, &retlen, movebuf, (char *)&oob);
+                             512, &retlen, movebuf, (char *)&oob, NAND_ECC_DISKONCHIP);
 	}
         
         /* add the header so that it is now a valid chain */
@@ -723,7 +721,7 @@
 	}
 
 	MTD_WRITEECC(nftl->mtd, (writeEUN * nftl->EraseSize) + blockofs,
-		     512, &retlen, (char *)buffer, (char *)eccbuf);
+		     512, &retlen, (char *)buffer, (char *)eccbuf, NAND_ECC_DISKONCHIP);
         /* no need to write SECTOR_USED flags since they are written in mtd_writeecc */
 
 	return 0;
@@ -785,7 +783,7 @@
 		loff_t ptr = (lastgoodEUN * nftl->EraseSize) + blockofs;
 		size_t retlen;
 		u_char eccbuf[6];
-		if (MTD_READECC(nftl->mtd, ptr, 512, &retlen, buffer, eccbuf))
+		if (MTD_READECC(nftl->mtd, ptr, 512, &retlen, buffer, eccbuf, NAND_ECC_DISKONCHIP))
 			return -EIO;
 	}
 	return 0;
@@ -1062,7 +1060,7 @@
 	int i;
 
 #ifdef PRERELEASE 
-	printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.85 $, nftlmount.c %s\n", nftlmountrev);
+	printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.87 $, nftlmount.c %s\n", nftlmountrev);
 #endif
 
 	if (register_blkdev(MAJOR_NR, "nftl", &nftl_fops)){
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/mtd/nftlmount.c linux-2.4.21-pre6/drivers/mtd/nftlmount.c
--- linux-2.4.20/drivers/mtd/nftlmount.c	2002-02-25 19:37:58.000000000 +0000
+++ linux-2.4.21-pre6/drivers/mtd/nftlmount.c	2003-03-26 23:49:07.000000000 +0000
@@ -4,7 +4,7 @@
  * Author: Fabrice Bellard (fabrice.bellard@netgem.com) 
  * Copyright (C) 2000 Netgem S.A.
  *
- * $Id: nftlmount.c,v 1.25 2001/11/30 16:46:27 dwmw2 Exp $
+ * $Id: nftlmount.c,v 1.31 2002/11/15 16:34:43 dwmw2 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
@@ -34,12 +34,13 @@
 #include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
 #include <linux/mtd/nftl.h>
 #include <linux/mtd/compatmac.h>
 
 #define SECTORSIZE 512
 
-char nftlmountrev[]="$Revision: 1.25 $";
+char nftlmountrev[]="$Revision: 1.31 $";
 
 /* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the
  *	various device information of the NFTL partition and Bad Unit Table. Update
@@ -51,11 +52,16 @@
 	struct nftl_uci1 h1;
 	struct nftl_oob oob;
 	unsigned int block, boot_record_count = 0;
-	int retlen;
+	size_t retlen;
 	u8 buf[SECTORSIZE];
 	struct NFTLMediaHeader *mh = &nftl->MediaHdr;
 	unsigned int i;
 
+        /* Assume logical EraseSize == physical erasesize for starting the scan. 
+	   We'll sort it out later if we find a MediaHeader which says otherwise */
+	nftl->EraseSize = nftl->mtd->erasesize;
+        nftl->nb_blocks = nftl->mtd->size / nftl->EraseSize;
+
 	nftl->MediaUnit = BLOCK_NIL;
 	nftl->SpareMediaUnit = BLOCK_NIL;
 
@@ -88,7 +94,7 @@
 
 		/* To be safer with BIOS, also use erase mark as discriminant */
 		if ((ret = MTD_READOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8,
-				8, &retlen, (char *)&h1) < 0)) {
+				8, &retlen, (char *)&h1)) < 0) {
 			printk(KERN_WARNING "ANAND header found at 0x%x in mtd%d, but OOB data read failed (err %d)\n",
 			       block * nftl->EraseSize, nftl->mtd->index, ret);
 			continue;
@@ -107,7 +113,7 @@
 
 		/* Finally reread to check ECC */
 		if ((ret = MTD_READECC(nftl->mtd, block * nftl->EraseSize, SECTORSIZE,
-				&retlen, buf, (char *)&oob) < 0)) {
+				&retlen, buf, (char *)&oob, NAND_ECC_DISKONCHIP)) < 0) {
 			printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but ECC read failed (err %d)\n",
 			       block * nftl->EraseSize, nftl->mtd->index, ret);
 			continue;
@@ -122,7 +128,6 @@
 			continue;
 		}
 #endif
-			       
 		/* OK, we like it. */
 
 		if (boot_record_count) {
@@ -137,6 +142,10 @@
 			if (boot_record_count == 1)
 				nftl->SpareMediaUnit = block;
 
+			/* Mark this boot record (NFTL MediaHeader) block as reserved */
+			nftl->ReplUnitTable[block] = BLOCK_RESERVED;
+
+
 			boot_record_count++;
 			continue;
 		}
@@ -145,12 +154,18 @@
 		memcpy(mh, buf, sizeof(struct NFTLMediaHeader));
 
 		/* Do some sanity checks on it */
-		if (mh->UnitSizeFactor != 0xff) {
-			printk(KERN_NOTICE "Sorry, we don't support UnitSizeFactor "
-			       "of != 1 yet.\n");
+		if (mh->UnitSizeFactor == 0) {
+			printk(KERN_NOTICE "NFTL: UnitSizeFactor 0x00 detected. This violates the spec but we think we know what it means...\n");
+		} else if (mh->UnitSizeFactor < 0xfc) {
+			printk(KERN_NOTICE "Sorry, we don't support UnitSizeFactor 0x%02x\n",
+			       mh->UnitSizeFactor);
 			return -1;
+		} else if (mh->UnitSizeFactor != 0xff) {
+			printk(KERN_NOTICE "WARNING: Support for NFTL with UnitSizeFactor 0x%02x is experimental\n",
+			       mh->UnitSizeFactor);
+			nftl->EraseSize = nftl->mtd->erasesize << (0xff - mh->UnitSizeFactor);
+			nftl->nb_blocks = nftl->mtd->size / nftl->EraseSize;
 		}
-
 		nftl->nb_boot_blocks = le16_to_cpu(mh->FirstPhysicalEUN);
 		if ((nftl->nb_boot_blocks + 2) >= nftl->nb_blocks) {
 			printk(KERN_NOTICE "NFTL Media Header sanity check failed:\n");
@@ -168,20 +183,50 @@
 		}
 		
 		nftl->nr_sects  = nftl->numvunits * (nftl->EraseSize / SECTORSIZE);
-		
+
 		/* If we're not using the last sectors in the device for some reason,
 		   reduce nb_blocks accordingly so we forget they're there */
 		nftl->nb_blocks = le16_to_cpu(mh->NumEraseUnits) + le16_to_cpu(mh->FirstPhysicalEUN);
 
+		/* XXX: will be suppressed */
+		nftl->lastEUN = nftl->nb_blocks - 1;
+
+		/* memory alloc */
+		nftl->EUNtable = kmalloc(nftl->nb_blocks * sizeof(u16), GFP_KERNEL);
+		if (!nftl->EUNtable) {
+			printk(KERN_NOTICE "NFTL: allocation of EUNtable failed\n");
+			return -ENOMEM;
+		}
+
+		nftl->ReplUnitTable = kmalloc(nftl->nb_blocks * sizeof(u16), GFP_KERNEL);
+		if (!nftl->ReplUnitTable) {
+			kfree(nftl->EUNtable);
+			printk(KERN_NOTICE "NFTL: allocation of ReplUnitTable failed\n");
+			return -ENOMEM;
+		}
+		
+		/* mark the bios blocks (blocks before NFTL MediaHeader) as reserved */
+		for (i = 0; i < nftl->nb_boot_blocks; i++)
+			nftl->ReplUnitTable[i] = BLOCK_RESERVED;
+		/* mark all remaining blocks as potentially containing data */
+		for (; i < nftl->nb_blocks; i++) { 
+			nftl->ReplUnitTable[i] = BLOCK_NOTEXPLORED;
+		}
+
+		/* Mark this boot record (NFTL MediaHeader) block as reserved */
+		nftl->ReplUnitTable[block] = BLOCK_RESERVED;
+
 		/* read the Bad Erase Unit Table and modify ReplUnitTable[] accordingly */
 		for (i = 0; i < nftl->nb_blocks; i++) {
 			if ((i & (SECTORSIZE - 1)) == 0) {
 				/* read one sector for every SECTORSIZE of blocks */
 				if ((ret = MTD_READECC(nftl->mtd, block * nftl->EraseSize +
-						       i + SECTORSIZE, SECTORSIZE,
-						       &retlen, buf, (char *)&oob)) < 0) {
+						       i + SECTORSIZE, SECTORSIZE, &retlen, buf,
+						       (char *)&oob, NAND_ECC_DISKONCHIP)) < 0) {
 					printk(KERN_NOTICE "Read of bad sector table failed (err %d)\n",
 					       ret);
+					kfree(nftl->ReplUnitTable);
+					kfree(nftl->EUNtable);
 					return -1;
 				}
 			}
@@ -246,7 +291,7 @@
  */
 int NFTL_formatblock(struct NFTLrecord *nftl, int block)
 {
-	int retlen;
+	size_t retlen;
 	unsigned int nb_erases, erase_mark;
 	struct nftl_uci1 uci;
 	struct erase_info *instr = &nftl->instr;
@@ -428,7 +473,7 @@
 {
 	struct nftl_uci1 h1;
 	unsigned int erase_mark;
-	int retlen;
+	size_t retlen;
 
 	/* check erase mark. */
 	if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, 
@@ -486,7 +531,7 @@
 static int get_fold_mark(struct NFTLrecord *nftl, unsigned int block)
 {
 	struct nftl_uci2 uci;
-	int retlen;
+	size_t retlen;
 
 	if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + 2 * SECTORSIZE + 8,
 			8, &retlen, (char *)&uci) < 0)
@@ -503,44 +548,14 @@
 	int chain_length, do_format_chain;
 	struct nftl_uci0 h0;
 	struct nftl_uci1 h1;
-	int retlen;
-
-	/* XXX: will be suppressed */
-	s->lastEUN = s->nb_blocks - 1;
-
-	/* memory alloc */
-	s->EUNtable = kmalloc(s->nb_blocks * sizeof(u16), GFP_KERNEL);
-	s->ReplUnitTable = kmalloc(s->nb_blocks * sizeof(u16), GFP_KERNEL);
-	if (!s->EUNtable || !s->ReplUnitTable) {
-	fail:
-		if (s->EUNtable)
-			kfree(s->EUNtable);
-		if (s->ReplUnitTable)
-			kfree(s->ReplUnitTable);
-		return -1;
-	}
-
-	/* mark all blocks as potentially containing data */
-	for (i = 0; i < s->nb_blocks; i++) { 
-		s->ReplUnitTable[i] = BLOCK_NOTEXPLORED;
-	}
+	size_t retlen;
 
 	/* search for NFTL MediaHeader and Spare NFTL Media Header */
 	if (find_boot_record(s) < 0) {
 		printk("Could not find valid boot record\n");
-		goto fail;
+		return -1;
 	}
 
-	/* mark the bios blocks (blocks before NFTL MediaHeader) as reserved */
-	for (i = 0; i < s->nb_boot_blocks; i++)
-		s->ReplUnitTable[i] = BLOCK_RESERVED;
-
-	/* also mark the boot records (NFTL MediaHeader) blocks as reserved */
-	if (s->MediaUnit != BLOCK_NIL)
-		s->ReplUnitTable[s->MediaUnit] = BLOCK_RESERVED;
-	if (s->SpareMediaUnit != BLOCK_NIL)
-		s->ReplUnitTable[s->SpareMediaUnit] = BLOCK_RESERVED;
-
 	/* init the logical to physical table */
 	for (i = 0; i < s->nb_blocks; i++) {
 		s->EUNtable[i] = BLOCK_NIL;
@@ -725,7 +740,7 @@
 
 	/* second pass to format unreferenced blocks  and init free block count */
 	s->numfreeEUNs = 0;
-	s->LastFreeEUN = BLOCK_NIL;
+	s->LastFreeEUN = le16_to_cpu(s->MediaHdr.FirstPhysicalEUN);
 
 	for (block = 0; block < s->nb_blocks; block++) {
 		if (s->ReplUnitTable[block] == BLOCK_NOTEXPLORED) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/3c501.c linux-2.4.21-pre6/drivers/net/3c501.c
--- linux-2.4.20/drivers/net/3c501.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/3c501.c	2003-03-26 23:48:58.000000000 +0000
@@ -35,6 +35,9 @@
     Cleaned up for 2.3.x because we broke SMP now. 
     		20000208 Alan Cox <alan@redhat.com>
     		
+    Fixed zero fill corner case 
+    		20030104 Alan Cox <alan@redhat.com>
+    		
 */
 
 
@@ -503,8 +506,15 @@
 
 	do
 	{
-		int gp_start = 0x800 - (ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN);
+		int len = skb->len;
+		int pad = 0;
+		int gp_start;
 		unsigned char *buf = skb->data;
+		
+		if(len < ETH_ZLEN)
+			pad = ETH_ZLEN - len;
+			
+		gp_start = 0x800 - ( len + pad );
 
 		lp->tx_pkt_start = gp_start;
     		lp->collisions = 0;
@@ -532,7 +542,12 @@
 		
 		outw(0x00, RX_BUF_CLR);		/* Set rx packet area to 0. */
 		outw(gp_start, GP_LOW);		/* aim - packet will be loaded into buffer start */
-		outsb(DATAPORT,buf,skb->len);	/* load buffer (usual thing each byte increments the pointer) */
+		outsb(DATAPORT,buf,len);	/* load buffer (usual thing each byte increments the pointer) */
+		if(pad)
+		{
+			while(pad--)		/* Zero fill buffer tail */
+				outb(0, DATAPORT);
+		}
 		outw(gp_start, GP_LOW);		/* the board reuses the same register */
 	
 		if(lp->loading != 2)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/3c505.c linux-2.4.21-pre6/drivers/net/3c505.c
--- linux-2.4.20/drivers/net/3c505.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/3c505.c	2003-03-26 23:49:38.000000000 +0000
@@ -1036,8 +1036,9 @@
 	adapter->current_dma.direction = 1;
 	adapter->current_dma.start_time = jiffies;
 
-	if ((unsigned long)(skb->data + nlen) >= MAX_DMA_ADDRESS) {
-		memcpy(adapter->dma_buffer, skb->data, nlen);
+	if ((unsigned long)(skb->data + nlen) >= MAX_DMA_ADDRESS || nlen != skb->len) {
+		memcpy(adapter->dma_buffer, skb->data, skb->len);
+		memset(adapter->dma_buffer+skb->len, 0, nlen-skb->len);
 		target = virt_to_bus(adapter->dma_buffer);
 	}
 	else {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/3c507.c linux-2.4.21-pre6/drivers/net/3c507.c
--- linux-2.4.20/drivers/net/3c507.c	2002-02-25 19:37:58.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/3c507.c	2003-03-26 23:49:51.000000000 +0000
@@ -303,7 +303,7 @@
 static struct net_device_stats *el16_get_stats(struct net_device *dev);
 static void el16_tx_timeout (struct net_device *dev);
 
-static void hardware_send_packet(struct net_device *dev, void *buf, short length);
+static void hardware_send_packet(struct net_device *dev, void *buf, short length, short pad);
 static void init_82586_mem(struct net_device *dev);
 static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
 
@@ -505,7 +505,7 @@
 	/* Disable the 82586's input to the interrupt line. */
 	outb (0x80, ioaddr + MISC_CTRL);
 
-	hardware_send_packet (dev, buf, length);
+	hardware_send_packet (dev, buf, skb->len, length - skb->len);
 
 	dev->trans_start = jiffies;
 	/* Enable the 82586 interrupt input. */
@@ -758,12 +758,13 @@
 	return;
 }
 
-static void hardware_send_packet(struct net_device *dev, void *buf, short length)
+static void hardware_send_packet(struct net_device *dev, void *buf, short length, short pad)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
 	short ioaddr = dev->base_addr;
 	ushort tx_block = lp->tx_head;
 	unsigned long write_ptr = dev->mem_start + tx_block;
+	static char padding[ETH_ZLEN];
 
 	/* Set the write pointer to the Tx block, and put out the header. */
 	isa_writew(0x0000,write_ptr);			/* Tx status */
@@ -772,7 +773,7 @@
 	isa_writew(tx_block+8,write_ptr+=2);			/* Data Buffer offset. */
 
 	/* Output the data buffer descriptor. */
-	isa_writew(length | 0x8000,write_ptr+=2);		/* Byte count parameter. */
+	isa_writew((pad + length) | 0x8000,write_ptr+=2);		/* Byte count parameter. */
 	isa_writew(-1,write_ptr+=2);			/* No next data buffer. */
 	isa_writew(tx_block+22+SCB_BASE,write_ptr+=2);	/* Buffer follows the NoOp command. */
 	isa_writew(0x0000,write_ptr+=2);			/* Buffer address high bits (always zero). */
@@ -784,6 +785,8 @@
 
 	/* Output the packet at the write pointer. */
 	isa_memcpy_toio(write_ptr+2, buf, length);
+	if(pad)
+		isa_memcpy_toio(write_ptr+length+2, padding, pad);
 
 	/* Set the old command link pointing to this send packet. */
 	isa_writew(tx_block,dev->mem_start + lp->tx_cmd_link);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/3c509.c linux-2.4.21-pre6/drivers/net/3c509.c
--- linux-2.4.20/drivers/net/3c509.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/3c509.c	2003-03-26 23:48:59.000000000 +0000
@@ -43,7 +43,7 @@
 		v1.18 12Mar2001 Andrew Morton <andrewm@uow.edu.au>
 			- Avoid bogus detect of 3c590's (Andrzej Krzysztofowicz)
 			- Reviewed against 1.18 from scyld.com
-		v1.18a 17Nov2001 Jeff Garzik <jgarzik@mandrakesoft.com>
+		v1.18a 17Nov2001 Jeff Garzik <jgarzik@pobox.com>
 			- ethtool support
 		v1.18b 1Mar2002 Zwane Mwaikambo <zwane@commfireservices.com>
 			- Power Management support
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/3c515.c linux-2.4.21-pre6/drivers/net/3c515.c
--- linux-2.4.20/drivers/net/3c515.c	2002-02-25 19:37:59.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/3c515.c	2003-03-26 23:49:08.000000000 +0000
@@ -91,12 +91,14 @@
 #define REQUEST_IRQ(i,h,f,n, instance) request_irq(i,h,f,n, instance)
 #define IRQ(irq, dev_id, pt_regs) (irq, dev_id, pt_regs)
 
+#define MAX_UNITS 8
+
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("3Com 3c515 Corkscrew driver");
 MODULE_LICENSE("GPL");
 
 MODULE_PARM(debug, "i");
-MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM(rx_copybreak, "i");
 MODULE_PARM(max_interrupt_work, "i");
 MODULE_PARM_DESC(debug, "3c515 debug level (0-6)");
@@ -421,7 +423,7 @@
 */
 /* This driver uses 'options' to pass the media type, full-duplex flag, etc. */
 /* Note: this is the only limit on the number of cards supported!! */
-static int options[8] = { -1, -1, -1, -1, -1, -1, -1, -1, };
+static int options[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1, };
 
 #ifdef MODULE
 static int debug = -1;
@@ -558,9 +560,10 @@
 		printk(KERN_INFO "3c515 Resource configuration register %#4.4x, DCR %4.4x.\n",
 		     inl(ioaddr + 0x2002), inw(ioaddr + 0x2000));
 		irq = inw(ioaddr + 0x2002) & 15;
-		corkscrew_found_device(dev, ioaddr, irq, CORKSCREW_ID, dev
-				       && dev->mem_start ? dev->
-				       mem_start : options[cards_found]);
+		corkscrew_found_device(dev, ioaddr, irq, CORKSCREW_ID,
+				       dev && dev->mem_start ?  dev->mem_start :
+				         (cards_found >= MAX_UNITS ? -1 :
+						options[cards_found]));
 		dev = 0;
 		cards_found++;
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/3c523.c linux-2.4.21-pre6/drivers/net/3c523.c
--- linux-2.4.20/drivers/net/3c523.c	2002-02-25 19:37:59.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/3c523.c	2003-03-26 23:49:38.000000000 +0000
@@ -212,10 +212,11 @@
 	volatile struct iscp_struct *iscp;	/* volatile is important */
 	volatile struct scb_struct *scb;	/* volatile is important */
 	volatile struct tbd_struct *xmit_buffs[NUM_XMIT_BUFFS];
-	volatile struct transmit_cmd_struct *xmit_cmds[NUM_XMIT_BUFFS];
 #if (NUM_XMIT_BUFFS == 1)
+	volatile struct transmit_cmd_struct *xmit_cmds[2];
 	volatile struct nop_cmd_struct *nop_cmds[2];
 #else
+	volatile struct transmit_cmd_struct *xmit_cmds[NUM_XMIT_BUFFS];
 	volatile struct nop_cmd_struct *nop_cmds[NUM_XMIT_BUFFS];
 #endif
 	volatile int nop_point, num_recv_buffs;
@@ -1121,8 +1122,11 @@
 
 	netif_stop_queue(dev);
 
-	memcpy((char *) p->xmit_cbuffs[p->xmit_count], (char *) (skb->data), skb->len);
 	len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
+	
+	if(len != skb->len)
+		memset((char *) p->xmit_cbuffs[p->xmit_count], 0, ETH_ZLEN);
+	memcpy((char *) p->xmit_cbuffs[p->xmit_count], (char *) (skb->data), skb->len);
 
 #if (NUM_XMIT_BUFFS == 1)
 #ifdef NO_NOPCOMMANDS
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/3c527.c linux-2.4.21-pre6/drivers/net/3c527.c
--- linux-2.4.20/drivers/net/3c527.c	2002-02-25 19:37:59.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/3c527.c	2003-03-26 23:48:58.000000000 +0000
@@ -1086,6 +1086,12 @@
 	/* We will need this to flush the buffer out */
 	lp->tx_ring[lp->tx_ring_head].skb=skb;
    	   
+   	if(skb->len < ETH_ZLEN)
+   	{
+   		skb = skb_padto(skb, ETH_ZLEN);
+   		if(skb == NULL)
+   			goto out;
+   	}
 	np->length = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len; 
 			
 	np->data	= virt_to_bus(skb->data);
@@ -1094,7 +1100,7 @@
 	wmb();
 		
 	p->control     &= ~CONTROL_EOL;     /* Clear EOL on p */ 
-	
+out:	
 	restore_flags(flags);
 
 	netif_wake_queue(dev);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/3c59x.c linux-2.4.21-pre6/drivers/net/3c59x.c
--- linux-2.4.20/drivers/net/3c59x.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/3c59x.c	2003-03-26 23:48:57.000000000 +0000
@@ -20,7 +20,7 @@
 	Linux Kernel Additions:
 	
  	0.99H+lk0.9 - David S. Miller - softnet, PCI DMA updates
- 	0.99H+lk1.0 - Jeff Garzik <jgarzik@mandrakesoft.com>
+ 	0.99H+lk1.0 - Jeff Garzik <jgarzik@pobox.com>
 		Remove compatibility defines for kernel versions < 2.2.x.
 		Update for new 2.3.x module interface
 	LK1.1.2 (March 19, 2000)
@@ -441,6 +441,7 @@
 
 	CH_3CCFEM656_1,
 	CH_3C450,
+	CH_3C920,
 };
 
 
@@ -532,6 +533,8 @@
 									MAX_COLLISION_RESET|HAS_HWCKSM, 128, },
 	{"3c450 HomePNA Tornado",						/* AKPM: from Don's 0.99Q */
 	 PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, },
+	{"3c920 Tornado",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, },
 	{0,}, /* 0 terminated list. */
 };
 
@@ -575,6 +578,7 @@
 
 	{ 0x10B7, 0x6564, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFEM656_1 },
 	{ 0x10B7, 0x4500, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C450 },
+	{ 0x10B7, 0x9201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C920 },
 	{0,}						/* 0 terminated list. */
 };
 MODULE_DEVICE_TABLE(pci, vortex_pci_tbl);
@@ -975,7 +979,7 @@
 	int i, step;
 	struct net_device *dev;
 	static int printed_version;
-	int retval, print_info;
+	int retval;
 	struct vortex_chip_info * const vci = &vortex_info_tbl[chip_idx];
 	char *print_name;
 
@@ -1017,10 +1021,7 @@
 			vp->enable_wol = 1;
 	}
 
-	print_info = (vortex_debug > 1);
-	if (print_info)
-		printk (KERN_INFO "See Documentation/networking/vortex.txt\n");
-
+	printk (KERN_INFO "See Documentation/networking/vortex.txt\n");
 	printk(KERN_INFO "%s: 3Com %s %s at 0x%lx. Vers " DRV_VERSION "\n",
 	       print_name,
 	       pdev ? "PCI" : "EISA",
@@ -1146,20 +1147,16 @@
 		printk(" ***INVALID CHECKSUM %4.4x*** ", checksum);
 	for (i = 0; i < 3; i++)
 		((u16 *)dev->dev_addr)[i] = htons(eeprom[i + 10]);
-	if (print_info) {
-		for (i = 0; i < 6; i++)
-			printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]);
-	}
+	for (i = 0; i < 6; i++)
+		printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]);
 	EL3WINDOW(2);
 	for (i = 0; i < 6; i++)
 		outb(dev->dev_addr[i], ioaddr + i);
 
 #ifdef __sparc__
-	if (print_info)
-		printk(", IRQ %s\n", __irq_itoa(dev->irq));
+	printk(", IRQ %s\n", __irq_itoa(dev->irq));
 #else
-	if (print_info)
-		printk(", IRQ %d\n", dev->irq);
+	printk(", IRQ %d\n", dev->irq);
 	/* Tell them about an invalid IRQ. */
 	if (dev->irq <= 0 || dev->irq >= NR_IRQS)
 		printk(KERN_WARNING " *** Warning: IRQ %d is unlikely to work! ***\n",
@@ -1168,12 +1165,9 @@
 
 	EL3WINDOW(4);
 	step = (inb(ioaddr + Wn4_NetDiag) & 0x1e) >> 1;
-	if (print_info) {
-		printk(KERN_INFO "  product code %02x%02x rev %02x.%d date %02d-"
-			"%02d-%02d\n", eeprom[6]&0xff, eeprom[6]>>8, eeprom[0x14],
-			step, (eeprom[4]>>5) & 15, eeprom[4] & 31, eeprom[4]>>9);
-	}
-
+	printk(KERN_INFO "  product code %02x%02x rev %02x.%d date %02d-"
+		"%02d-%02d\n", eeprom[6]&0xff, eeprom[6]>>8, eeprom[0x14],
+		step, (eeprom[4]>>5) & 15, eeprom[4] & 31, eeprom[4]>>9);
 
 	if (pdev && vci->drv_flags & HAS_CB_FNS) {
 		unsigned long fn_st_addr;			/* Cardbus function status space */
@@ -1186,10 +1180,8 @@
 			if (!vp->cb_fn_base)
 				goto free_ring;
 		}
-		if (print_info) {
-			printk(KERN_INFO "%s: CardBus functions mapped %8.8lx->%p\n",
-				print_name, fn_st_addr, vp->cb_fn_base);
-		}
+		printk(KERN_INFO "%s: CardBus functions mapped %8.8lx->%p\n",
+			print_name, fn_st_addr, vp->cb_fn_base);
 		EL3WINDOW(2);
 
 		n = inw(ioaddr + Wn2_ResetOptions) & ~0x4010;
@@ -1207,8 +1199,7 @@
 
 	if (vp->info1 & 0x8000) {
 		vp->full_duplex = 1;
-		if (print_info)
-			printk(KERN_INFO "Full duplex capable\n");
+		printk(KERN_INFO "Full duplex capable\n");
 	}
 
 	{
@@ -1219,17 +1210,16 @@
 		if ((vp->available_media & 0xff) == 0)		/* Broken 3c916 */
 			vp->available_media = 0x40;
 		config = inl(ioaddr + Wn3_Config);
-		if (print_info) {
-			printk(KERN_DEBUG "  Internal config register is %4.4x, "
-				   "transceivers %#x.\n", config, inw(ioaddr + Wn3_Options));
-			printk(KERN_INFO "  %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n",
-				   8 << RAM_SIZE(config),
-				   RAM_WIDTH(config) ? "word" : "byte",
-				   ram_split[RAM_SPLIT(config)],
-				   AUTOSELECT(config) ? "autoselect/" : "",
-				   XCVR(config) > XCVR_ExtMII ? "<invalid transceiver>" :
-				   media_tbl[XCVR(config)].name);
-		}
+		printk(KERN_DEBUG "  Internal config register is %4.4x, "
+				"transceivers %#x.\n", config,
+				inw(ioaddr + Wn3_Options));
+		printk(KERN_INFO "  %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n",
+			   8 << RAM_SIZE(config),
+			   RAM_WIDTH(config) ? "word" : "byte",
+			   ram_split[RAM_SPLIT(config)],
+			   AUTOSELECT(config) ? "autoselect/" : "",
+			   XCVR(config) > XCVR_ExtMII ? "<invalid transceiver>" :
+			   media_tbl[XCVR(config)].name);
 		vp->default_media = XCVR(config);
 		if (vp->default_media == XCVR_NWAY)
 			vp->has_nway = 1;
@@ -1266,10 +1256,9 @@
 			mii_status = mdio_read(dev, phyx, 1);
 			if (mii_status  &&  mii_status != 0xffff) {
 				vp->phys[phy_idx++] = phyx;
-				if (print_info) {
-					printk(KERN_INFO "  MII transceiver found at address %d,"
-						" status %4x.\n", phyx, mii_status);
-				}
+				printk(KERN_INFO "  MII transceiver found at "
+					"address %d, status %4x.\n",
+					phyx, mii_status);
 				if ((mii_status & 0x0040) == 0)
 					mii_preamble_required++;
 			}
@@ -1290,10 +1279,9 @@
 
 	if (vp->capabilities & CapBusMaster) {
 		vp->full_bus_master_tx = 1;
-		if (print_info) {
-			printk(KERN_INFO "  Enabling bus-master transmits and %s receives.\n",
+		printk(KERN_INFO "  Enabling bus-master transmits and %s "
+				"receives.\n",
 			(vp->info2 & 1) ? "early" : "whole-frame" );
-		}
 		vp->full_bus_master_rx = (vp->info2 & 1) ? 1 : 2;
 		vp->bus_master = 0;		/* AKPM: vortex only */
 	}
@@ -1312,12 +1300,10 @@
 		dev->hard_start_xmit = vortex_start_xmit;
 	}
 
-	if (print_info) {
-		printk(KERN_INFO "%s: scatter/gather %sabled. h/w checksums %sabled\n",
-				print_name,
-				(dev->features & NETIF_F_SG) ? "en":"dis",
-				(dev->features & NETIF_F_IP_CSUM) ? "en":"dis");
-	}
+	printk(KERN_INFO "%s: scatter/gather %sabled. h/w checksums %sabled\n",
+			print_name,
+			(dev->features & NETIF_F_SG) ? "en":"dis",
+			(dev->features & NETIF_F_IP_CSUM) ? "en":"dis");
 
 	dev->stop = vortex_close;
 	dev->get_stats = vortex_get_stats;
@@ -1659,10 +1645,12 @@
 			if (vortex_debug > 1)
 				printk(KERN_DEBUG "%s: Media %s has link beat, %x.\n",
 					   dev->name, media_tbl[dev->if_port].name, media_status);
-		} else if (vortex_debug > 1) {
+		} else {
 			netif_carrier_off(dev);
-			printk(KERN_DEBUG "%s: Media %s has no link beat, %x.\n",
-				   dev->name, media_tbl[dev->if_port].name, media_status);
+			if (vortex_debug > 1) {
+				printk(KERN_DEBUG "%s: Media %s has no link beat, %x.\n",
+					   dev->name, media_tbl[dev->if_port].name, media_status);
+			}
 		}
 		break;
 	case XCVR_MII: case XCVR_NWAY:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/7990.c linux-2.4.21-pre6/drivers/net/7990.c
--- linux-2.4.20/drivers/net/7990.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/7990.c	2003-03-26 23:49:50.000000000 +0000
@@ -532,6 +532,8 @@
         ib->btx_ring [entry].length = (-len) | 0xf000;
         ib->btx_ring [entry].misc = 0;
     
+    	if(skb->len < ETH_ZLEN)
+    		memset((char *)&ib->tx_buf[entry][0], 0, ETH_ZLEN);
         memcpy ((char *)&ib->tx_buf [entry][0], skb->data, skblen);
     
         /* Now, give the packet to the lance */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/8139cp.c linux-2.4.21-pre6/drivers/net/8139cp.c
--- linux-2.4.20/drivers/net/8139cp.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/8139cp.c	2003-03-26 23:49:35.000000000 +0000
@@ -1,6 +1,6 @@
 /* 8139cp.c: A Linux PCI Ethernet driver for the RealTek 8139C+ chips. */
 /*
-	Copyright 2001,2002 Jeff Garzik <jgarzik@mandrakesoft.com>
+	Copyright 2001,2002 Jeff Garzik <jgarzik@pobox.com>
 
 	Copyright (C) 2001, 2002 David S. Miller (davem@redhat.com) [tg3.c]
 	Copyright (C) 2000, 2001 David S. Miller (davem@redhat.com) [sungem.c]
@@ -89,7 +89,7 @@
 static char version[] __devinitdata =
 KERN_INFO DRV_NAME ": 10/100 PCI Ethernet driver v" DRV_VERSION " (" DRV_RELDATE ")\n";
 
-MODULE_AUTHOR("Jeff Garzik <jgarzik@mandrakesoft.com>");
+MODULE_AUTHOR("Jeff Garzik <jgarzik@pobox.com>");
 MODULE_DESCRIPTION("RealTek RTL-8139C+ series 10/100 PCI Ethernet driver");
 MODULE_LICENSE("GPL");
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/8139too.c linux-2.4.21-pre6/drivers/net/8139too.c
--- linux-2.4.20/drivers/net/8139too.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/8139too.c	2003-03-26 23:48:57.000000000 +0000
@@ -2,7 +2,7 @@
 
 	8139too.c: A RealTek RTL-8139 Fast Ethernet driver for Linux.
 
-	Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
+	Maintained by Jeff Garzik <jgarzik@pobox.com>
 	Copyright 2000-2002 Jeff Garzik
 
 	Much code comes from Donald Becker's rtl8139.c driver,
@@ -590,7 +590,7 @@
 	unsigned int regs_len;
 };
 
-MODULE_AUTHOR ("Jeff Garzik <jgarzik@mandrakesoft.com>");
+MODULE_AUTHOR ("Jeff Garzik <jgarzik@pobox.com>");
 MODULE_DESCRIPTION ("RealTek RTL-8139 Fast Ethernet driver");
 MODULE_LICENSE("GPL");
 
@@ -969,7 +969,12 @@
 	dev->do_ioctl = netdev_ioctl;
 	dev->tx_timeout = rtl8139_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
-	dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM;
+
+	/* note: the hardware is not capable of sg/csum/highdma, however
+	 * through the use of skb_copy_and_csum_dev we enable these
+	 * features
+	 */
+	dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_HIGHDMA;
 
 	dev->irq = pdev->irq;
 
@@ -1682,6 +1687,8 @@
 	entry = tp->cur_tx % NUM_TX_DESC;
 
 	if (likely(len < TX_BUF_SIZE)) {
+		if(len < ETH_ZLEN)
+			memset(tp->tx_buf[entry], 0, ETH_ZLEN);
 		skb_copy_and_csum_dev(skb, tp->tx_buf[entry]);
 		dev_kfree_skb(skb);
 	} else {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/82596.c linux-2.4.21-pre6/drivers/net/82596.c
--- linux-2.4.20/drivers/net/82596.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/82596.c	2003-03-26 23:49:09.000000000 +0000
@@ -649,7 +649,7 @@
 
 	/* change the scp address */
 
-	MPU_PORT(dev, PORT_ALTSCP, (void *)virt_to_bus(&lp->scp));
+	MPU_PORT(dev, PORT_ALTSCP, (void *)virt_to_bus((void *)&lp->scp));
 
 #elif defined(ENABLE_APRICOT)
 
@@ -680,8 +680,8 @@
 		lp->scp.sysbus = 0x00440000;
 #endif
 
-	lp->scp.iscp = WSWAPiscp(virt_to_bus(&(lp->iscp)));
-	lp->iscp.scb = WSWAPscb(virt_to_bus(&(lp->scb)));
+	lp->scp.iscp = WSWAPiscp(virt_to_bus((void *)&lp->iscp));
+	lp->iscp.scb = WSWAPscb(virt_to_bus((void *)&lp->scb));
 	lp->iscp.stat = ISCP_BUSY;
 	lp->cmd_backlog = 0;
 
@@ -1066,12 +1066,19 @@
 	struct i596_private *lp = (struct i596_private *) dev->priv;
 	struct tx_cmd *tx_cmd;
 	struct i596_tbd *tbd;
-	short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+	short length = skb->len;
 	dev->trans_start = jiffies;
 
 	DEB(DEB_STARTTX,printk(KERN_DEBUG "%s: i596_start_xmit(%x,%x) called\n", dev->name,
 				skb->len, (unsigned int)skb->data));
 
+	if(skb->len < ETH_ZLEN)
+	{
+		skb = skb_padto(skb, ETH_ZLEN);
+		if(skb == NULL)
+			return 0;
+		length = ETH_ZLEN;
+	}
 	netif_stop_queue(dev);
 
 	tx_cmd = lp->tx_cmds + lp->next_tx_cmd;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/8390.c linux-2.4.21-pre6/drivers/net/8390.c
--- linux-2.4.20/drivers/net/8390.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/8390.c	2003-03-26 23:49:07.000000000 +0000
@@ -271,6 +271,7 @@
 	struct ei_device *ei_local = (struct ei_device *) dev->priv;
 	int length, send_length, output_page;
 	unsigned long flags;
+	char scratch[ETH_ZLEN];
 
 	length = skb->len;
 
@@ -341,8 +342,16 @@
 	 * isn't already sending. If it is busy, the interrupt handler will
 	 * trigger the send later, upon receiving a Tx done interrupt.
 	 */
-
-	ei_block_output(dev, length, skb->data, output_page);
+	 
+	if(length == send_length)
+		ei_block_output(dev, length, skb->data, output_page);
+	else
+	{
+		memset(scratch, 0, ETH_ZLEN);
+		memcpy(scratch, skb->data, skb->len);
+		ei_block_output(dev, ETH_ZLEN, scratch, output_page);
+	}
+		
 	if (! ei_local->txing) 
 	{
 		ei_local->txing = 1;
@@ -374,7 +383,14 @@
 	 * reasonable hardware if you only use one Tx buffer.
 	 */
 
-	ei_block_output(dev, length, skb->data, ei_local->tx_start_page);
+	if(length == send_length)
+		ei_block_output(dev, length, skb->data, ei_local->tx_start_page);
+	else
+	{
+		memset(scratch, 0, ETH_ZLEN);
+		memcpy(scratch, skb->data, skb->len);
+		ei_block_output(dev, ETH_ZLEN, scratch, ei_local->tx_start_page);
+	}
 	ei_local->txing = 1;
 	NS8390_trigger_send(dev, send_length, ei_local->tx_start_page);
 	dev->trans_start = jiffies;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/8390.h linux-2.4.21-pre6/drivers/net/8390.h
--- linux-2.4.20/drivers/net/8390.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/8390.h	2003-03-26 23:49:50.000000000 +0000
@@ -117,8 +117,7 @@
  
 #if defined(CONFIG_MAC) ||  \
     defined(CONFIG_ARIADNE2) || defined(CONFIG_ARIADNE2_MODULE) || \
-    defined(CONFIG_HYDRA) || defined(CONFIG_HYDRA_MODULE) || \
-    defined(CONFIG_ARM_ETHERH) || defined(CONFIG_ARM_ETHERH_MODULE)
+    defined(CONFIG_HYDRA) || defined(CONFIG_HYDRA_MODULE)
 #define EI_SHIFT(x)	(ei_local->reg_offset[x])
 #undef inb
 #undef inb_p
@@ -130,6 +129,8 @@
 #define inb_p(port)   in_8(port)
 #define outb_p(val,port)  out_8(port,val)
 
+#elif defined(CONFIG_ARM_ETHERH) || defined(CONFIG_ARM_ETHERH_MODULE)
+#define EI_SHIFT(x)    (ei_local->reg_offset[x])
 #else
 #define EI_SHIFT(x)	(x)
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/Config.in linux-2.4.21-pre6/drivers/net/Config.in
--- linux-2.4.20/drivers/net/Config.in	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/Config.in	2003-03-26 23:49:00.000000000 +0000
@@ -26,10 +26,14 @@
 if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
    if [ "$CONFIG_ARM" = "y" ]; then  
       dep_bool '  ARM EBSA110 AM79C961A support' CONFIG_ARM_AM79C961A $CONFIG_ARCH_EBSA110
+      tristate '  Cirrus Logic CS8900A support' CONFIG_ARM_CIRRUS
       if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
          source drivers/acorn/net/Config.in
       fi
    fi
+   if [ "$CONFIG_ARCH_CAMELOT" = "y" ]; then
+	tristate ' Altera Ether00 support' CONFIG_ETHER00
+   fi
    if [ "$CONFIG_PPC" = "y" ]; then
       dep_tristate '  MACE (Power Mac ethernet) support' CONFIG_MACE $CONFIG_ALL_PPC
       if [ "$CONFIG_MACE" != "n" ]; then
@@ -100,6 +104,9 @@
       if [ "$CONFIG_PCI" = "y" -o "$CONFIG_EISA" = "y" ]; then
          tristate '    3c590/3c900 series (592/595/597) "Vortex/Boomerang" support' CONFIG_VORTEX
       fi
+      if [ "$CONFIG_PCI" = "y" ]; then
+	 tristate '    3cr990 series "Typhoon" support' CONFIG_TYPHOON
+      fi
    fi
    dep_tristate '  AMD LANCE and PCnet (AT1500 and NE2100) support' CONFIG_LANCE $CONFIG_ISA
    bool '  Western Digital/SMC cards' CONFIG_NET_VENDOR_SMC
@@ -158,6 +165,7 @@
    fi
    if [ "$CONFIG_NET_PCI" = "y" ]; then
       dep_tristate '    AMD PCnet32 PCI support' CONFIG_PCNET32 $CONFIG_PCI
+      dep_tristate '    AMD 8111 (new PCI lance) support' CONFIG_AMD8111_ETH $CONFIG_PCI
       dep_tristate '    Adaptec Starfire/DuraLAN support' CONFIG_ADAPTEC_STARFIRE $CONFIG_PCI
       if [ "$CONFIG_ISA" = "y" -o "$CONFIG_EISA" = "y" ]; then
 	 dep_tristate '    Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200 $CONFIG_EXPERIMENTAL
@@ -176,6 +184,11 @@
       fi
       dep_tristate '    Davicom DM910x/DM980x support' CONFIG_DM9102 $CONFIG_PCI
       dep_tristate '    EtherExpressPro/100 support (eepro100, original Becker driver)' CONFIG_EEPRO100 $CONFIG_PCI
+      if [ "$CONFIG_VISWS" = "y" ]; then
+         define_mbool CONFIG_EEPRO100_PIO y
+      else
+         dep_mbool '      Use PIO instead of MMIO' CONFIG_EEPRO100_PIO $CONFIG_EEPRO100
+      fi  
       dep_tristate '    EtherExpressPro/100 support (e100, Alternate Intel driver)' CONFIG_E100 $CONFIG_PCI
       dep_tristate '    Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390 $CONFIG_EISA $CONFIG_EXPERIMENTAL
       dep_tristate '    Myson MTD-8xx PCI Ethernet support' CONFIG_FEALNX $CONFIG_PCI
@@ -248,7 +261,8 @@
 dep_tristate 'National Semiconductor DP83820 support' CONFIG_NS83820 $CONFIG_PCI
 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
-dep_tristate 'SysKonnect SK-98xx support' CONFIG_SK98LIN $CONFIG_PCI
+dep_tristate 'Realtek 8169 Gigabit Ethernet support' CONFIG_R8169 $CONFIG_PCI
+dep_tristate 'SysKonnect SK-98xx and SK-95xx Gigabit Ethernet Adapter family support' CONFIG_SK98LIN $CONFIG_PCI
 dep_tristate 'Broadcom Tigon3 support' CONFIG_TIGON3 $CONFIG_PCI
 
 endmenu
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/Makefile linux-2.4.21-pre6/drivers/net/Makefile
--- linux-2.4.20/drivers/net/Makefile	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/Makefile	2003-03-26 23:49:20.000000000 +0000
@@ -70,6 +70,7 @@
 obj-$(CONFIG_DGRS) += dgrs.o
 obj-$(CONFIG_RCPCI) += rcpci.o
 obj-$(CONFIG_VORTEX) += 3c59x.o mii.o
+obj-$(CONFIG_TYPHOON) += typhoon.o
 obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o
 obj-$(CONFIG_PCNET32) += pcnet32.o mii.o
 obj-$(CONFIG_EEPRO100) += eepro100.o mii.o
@@ -100,7 +101,7 @@
 endif
 
 obj-$(CONFIG_VIA_RHINE) += via-rhine.o mii.o
-obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o
+obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o mii.o
 
 #
 # end link order section
@@ -114,12 +115,12 @@
 
 obj-$(CONFIG_WINBOND_840) += winbond-840.o mii.o
 obj-$(CONFIG_SUNDANCE) += sundance.o mii.o
-obj-$(CONFIG_HAMACHI) += hamachi.o
+obj-$(CONFIG_HAMACHI) += hamachi.o mii.o
 obj-$(CONFIG_NET) += Space.o setup.o net_init.o loopback.o
 obj-$(CONFIG_SEEQ8005) += seeq8005.o
 obj-$(CONFIG_ETHERTAP) += ethertap.o
 obj-$(CONFIG_NET_SB1000) += sb1000.o
-obj-$(CONFIG_MAC8390) += daynaport.o 8390.o
+obj-$(CONFIG_MAC8390) += mac8390.o 8390.o
 obj-$(CONFIG_APNE) += apne.o 8390.o
 obj-$(CONFIG_PCMCIA_PCNET) += 8390.o
 obj-$(CONFIG_SHAPER) += shaper.o
@@ -220,11 +221,18 @@
 obj-$(CONFIG_HYDRA) += hydra.o 8390.o
 obj-$(CONFIG_ARIADNE) += ariadne.o
 obj-$(CONFIG_CS89x0) += cs89x0.o
+obj-$(CONFIG_ARM_CIRRUS) += cirrus.o
 obj-$(CONFIG_MACSONIC) += macsonic.o
 obj-$(CONFIG_MACMACE) += macmace.o
 obj-$(CONFIG_MAC89x0) += mac89x0.o
 obj-$(CONFIG_TUN) += tun.o
+obj-$(CONFIG_ETHER00) +=ether00.o
 obj-$(CONFIG_DL2K) += dl2k.o
+obj-$(CONFIG_R8169) += r8169.o
+obj-$(CONFIG_AMD8111_ETH) += amd8111e.o
+
+# non-drivers/net drivers who want mii lib
+obj-$(CONFIG_PCMCIA_SMC91C92) += mii.o
 
 ifeq ($(CONFIG_ARCH_ACORN),y)
 mod-subdirs	+= ../acorn/net
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/a2065.c linux-2.4.21-pre6/drivers/net/a2065.c
--- linux-2.4.20/drivers/net/a2065.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/a2065.c	2003-03-26 23:49:40.000000000 +0000
@@ -574,6 +574,15 @@
 	unsigned long flags;
 
 	skblen = skb->len;
+	len = skblen;
+	
+	if(len < ETH_ZLEN)
+	{
+		len = ETH_ZLEN;
+		skb = skb_padto(skb, ETH_ZLEN);
+		if(skb == NULL)
+			return 0;
+	}
 
 	save_flags(flags);
 	cli();
@@ -595,7 +604,6 @@
 		}
 	}
 #endif
-	len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen;
 	entry = lp->tx_new & lp->tx_ring_mod_mask;
 	ib->btx_ring [entry].length = (-len) | 0xf000;
 	ib->btx_ring [entry].misc = 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/am79c961a.c linux-2.4.21-pre6/drivers/net/am79c961a.c
--- linux-2.4.20/drivers/net/am79c961a.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/am79c961a.c	2003-03-26 23:49:51.000000000 +0000
@@ -409,10 +409,19 @@
 am79c961_sendpacket(struct sk_buff *skb, struct net_device *dev)
 {
 	struct dev_priv *priv = (struct dev_priv *)dev->priv;
-	unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+	unsigned int length = skb->len;
 	unsigned int hdraddr, bufaddr;
 	unsigned int head;
 	unsigned long flags;
+	
+	/* FIXME: I thought the 79c961 could do padding - RMK ??? */
+	if(length < ETH_ZLEN)
+	{
+		skb = skb_padto(skb, ETH_ZLEN);
+		if(skb == NULL)
+			return 0;
+		length = ETH_ZLEN;
+	}
 
 	head = priv->txhead;
 	hdraddr = priv->txhdr + (head << 3);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/amd8111e.c linux-2.4.21-pre6/drivers/net/amd8111e.c
--- linux-2.4.20/drivers/net/amd8111e.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/amd8111e.c	2003-03-26 23:49:06.000000000 +0000
@@ -0,0 +1,1651 @@
+
+/* Advanced  Micro Devices Inc. AMD8111E Linux Network Driver 
+ * Copyright (C) 2002 Advanced Micro Devices 
+ *
+ * 
+ * Copyright 2001,2002 Jeff Garzik <jgarzik@mandrakesoft.com> [ 8139cp.c,tg3.c ]
+ * Copyright (C) 2001, 2002 David S. Miller (davem@redhat.com)[ tg3.c]
+ * Copyright 1996-1999 Thomas Bogendoerfer [ pcnet32.c ]
+ * Derived from the lance driver written 1993,1994,1995 by Donald Becker.
+ * Copyright 1993 United States Government as represented by the
+ *	Director, National Security Agency.[ pcnet32.c ]
+ * Carsten Langgaard, carstenl@mips.com [ pcnet32.c ]
+ * Copyright (C) 2000 MIPS Technologies, Inc.  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 
+ * USA
+  
+Module Name:
+
+	amd8111e.c
+
+Abstract:
+	
+ 	 AMD8111 based 10/100 Ethernet Controller Driver. 
+
+Environment:
+
+	Kernel Mode
+
+Revision History:
+
+*/
+
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/compiler.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/if_vlan.h>
+#include <linux/ctype.h>	
+#include <linux/crc32.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/byteorder.h>
+#include <asm/uaccess.h>
+
+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
+#define AMD8111E_VLAN_TAG_USED 1
+#else
+#define AMD8111E_VLAN_TAG_USED 0
+#endif
+
+#include "amd8111e.h"
+#define MODULE_NAME	"amd8111e"
+#define MODULE_VERSION	"3.0.0"
+MODULE_AUTHOR("Advanced Micro Devices, Inc.");
+MODULE_DESCRIPTION ("AMD8111 based 10/100 Ethernet Controller. Driver Version 3.0.0"); 
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(speed_duplex, "1-" __MODULE_STRING (MAX_UNITS) "i");
+MODULE_PARM_DESC(speed_duplex, "Set device speed and duplex modes, 0: Auto Negotitate, 1: 10Mbps Half Duplex, 2: 10Mbps Full Duplex, 3: 100Mbps Half Duplex, 4: 100Mbps Full Duplex");
+
+static struct pci_device_id amd8111e_pci_tbl[] __devinitdata = {
+		
+	{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD8111E_7462,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ 0, }
+
+};
+
+/*
+This function will set PHY speed. During initialization sets the original speed to 100 full.
+*/
+static void amd8111e_set_ext_phy(struct net_device *dev)
+{
+	struct amd8111e_priv *lp = (struct amd8111e_priv *)dev->priv;
+	unsigned long  reg_val = 0;
+	void * mmio = lp->mmio;
+	struct amd8111e_link_config *link_config = &lp->link_config;
+	
+	if(!lp->opened){
+		/* Initializing SPEED_100 and DUPLEX_FULL as original values */
+		link_config->orig_speed = SPEED_100;
+		link_config->orig_duplex = DUPLEX_FULL;
+		link_config->orig_phy_option = XPHYSP |XPHYFD;
+	}
+	reg_val = lp->ext_phy_option;
+
+	/* Disable port manager */
+	writel((u32) EN_PMGR, mmio + CMD3 );
+
+	/* Reset PHY */
+	writel((u32)XPHYRST | lp->ext_phy_option, mmio + CTRL2);
+
+	/* Enable port manager */
+	writel((u32)VAL1 | EN_PMGR, mmio + CMD3 );
+}
+
+/* 
+This function will unmap skb->data space and will free 
+all transmit and receive skbuffs.
+*/
+static int amd8111e_free_skbs(struct net_device *dev)
+{
+	struct amd8111e_priv *lp = (struct amd8111e_priv *)dev->priv;
+	struct sk_buff* rx_skbuff;
+	int i;
+
+	/* Freeing transmit skbs */
+	for(i = 0; i < NUM_TX_BUFFERS; i++){
+		if(lp->tx_skbuff[i]){
+			pci_unmap_single(lp->pci_dev,lp->tx_dma_addr[i],					lp->tx_skbuff[i]->len,PCI_DMA_TODEVICE);
+			dev_kfree_skb (lp->tx_skbuff[i]);
+			lp->tx_skbuff[i] = NULL;
+			lp->tx_dma_addr[i] = 0;
+		}
+	}
+	/* Freeing previously allocated receive buffers */
+	for (i = 0; i < NUM_RX_BUFFERS; i++){
+		rx_skbuff = lp->rx_skbuff[i];
+		if(rx_skbuff != NULL){
+			pci_unmap_single(lp->pci_dev,lp->rx_dma_addr[i],
+				  lp->rx_buff_len - 2,PCI_DMA_FROMDEVICE);
+			dev_kfree_skb(lp->rx_skbuff[i]);
+			lp->rx_skbuff[i] = NULL;
+			lp->rx_dma_addr[i] = 0;
+		}
+	}
+	
+	return 0;
+}
+
+/*
+ This will set the receive buffer length corresponding to the mtu size of network interface.
+*/
+static inline void amd8111e_set_rx_buff_len(struct net_device* dev)
+{
+	struct amd8111e_priv* lp = dev->priv;
+	unsigned int mtu = dev->mtu;
+	
+	if (mtu > ETH_DATA_LEN){
+		/* MTU + ethernet header + FCS + optional VLAN tag */
+		lp->rx_buff_len = mtu + ETH_HLEN + 8;
+		lp->options |= OPTION_JUMBO_ENABLE;
+	} else{
+		lp->rx_buff_len = PKT_BUFF_SZ;
+		lp->options &= ~OPTION_JUMBO_ENABLE;
+	}
+}
+
+/* 
+This function will free all the previously allocated buffers, determine new receive buffer length  and will allocate new receive buffers. This function also allocates and initializes both the transmitter and receive hardware descriptors.
+ */
+static int amd8111e_init_ring(struct net_device *dev)
+{
+	struct amd8111e_priv *lp = (struct amd8111e_priv *)dev->priv;
+	int i;
+
+	lp->rx_idx = lp->tx_idx = 0;
+	lp->tx_complete_idx = 0;
+	lp->tx_ring_idx = 0;
+	
+
+	if(lp->opened)
+		/* Free previously allocated transmit and receive skbs */
+		amd8111e_free_skbs(dev);	
+
+	else{
+		 /* allocate the tx and rx descriptors */
+	     	if((lp->tx_ring = pci_alloc_consistent(lp->pci_dev, 
+			sizeof(struct amd8111e_tx_dr)*NUM_TX_RING_DR,
+			&lp->tx_ring_dma_addr)) == NULL)
+		
+			goto err_no_mem;
+	
+	     	if((lp->rx_ring = pci_alloc_consistent(lp->pci_dev, 
+			sizeof(struct amd8111e_rx_dr)*NUM_RX_RING_DR,
+			&lp->rx_ring_dma_addr)) == NULL)
+		
+			goto err_free_tx_ring;
+
+	}
+	/* Set new receive buff size */
+	amd8111e_set_rx_buff_len(dev);
+
+	/* Allocating receive  skbs */
+	for (i = 0; i < NUM_RX_BUFFERS; i++) {
+
+		if (!(lp->rx_skbuff[i] = dev_alloc_skb(lp->rx_buff_len))) {
+				/* Release previos allocated skbs */
+				for(--i; i >= 0 ;i--)
+					dev_kfree_skb(lp->rx_skbuff[i]);
+				goto err_free_rx_ring;
+		}
+		skb_reserve(lp->rx_skbuff[i],2);
+	}
+        /* Initilaizing receive descriptors */
+	for (i = 0; i < NUM_RX_BUFFERS; i++) {
+		lp->rx_dma_addr[i] = pci_map_single(lp->pci_dev, 
+			lp->rx_skbuff[i]->data,lp->rx_buff_len-2, PCI_DMA_FROMDEVICE);
+
+		lp->rx_ring[i].buff_phy_addr = cpu_to_le32(lp->rx_dma_addr[i]);
+		lp->rx_ring[i].buff_count = cpu_to_le16(lp->rx_buff_len);
+		lp->rx_ring[i].rx_dr_offset10 = cpu_to_le16(OWN_BIT);
+	}
+
+	/* Initializing transmit descriptors */
+	for (i = 0; i < NUM_TX_RING_DR; i++) {
+		lp->tx_ring[i].buff_phy_addr = 0;
+		lp->tx_ring[i].tx_dr_offset2 = 0;
+		lp->tx_ring[i].buff_count = 0;
+	}
+
+	return 0;
+
+err_free_rx_ring:
+	
+	pci_free_consistent(lp->pci_dev, 
+		sizeof(struct amd8111e_rx_dr)*NUM_RX_RING_DR,lp->rx_ring,
+		lp->rx_ring_dma_addr);
+
+err_free_tx_ring:
+	
+	pci_free_consistent(lp->pci_dev,
+		 sizeof(struct amd8111e_tx_dr)*NUM_TX_RING_DR,lp->tx_ring, 
+		 lp->tx_ring_dma_addr);
+
+err_no_mem:
+	return -ENOMEM;
+}
+/* 
+This function initializes the device registers  and starts the device.  
+*/
+static int amd8111e_restart(struct net_device *dev)
+{
+	struct amd8111e_priv *lp = (struct amd8111e_priv* )dev->priv;
+	void * mmio = lp->mmio;
+	int i,reg_val;
+
+	/* stop the chip */
+	 writel(RUN, mmio + CMD0);
+
+	if(amd8111e_init_ring(dev))
+		return -ENOMEM;
+	
+	amd8111e_set_ext_phy(dev);
+
+	/* set control registers */
+	reg_val = readl(mmio + CTRL1);
+	
+	writel( reg_val| XMTSP_128 | CACHE_ALIGN | B1_MASK, mmio + CTRL1 );
+
+	/* enable interrupt */
+	writel( APINT5EN | APINT4EN | APINT3EN | APINT2EN | APINT1EN | 
+		APINT0EN | MIIPDTINTEN | MCCIINTEN | MCCINTEN | MREINTEN |
+		SPNDINTEN | MPINTEN | SINTEN | STINTEN, mmio + INTEN0);
+
+	writel(VAL3 | LCINTEN | VAL1 | TINTEN0 | VAL0 | RINTEN0, mmio + INTEN0);
+
+	/* initialize tx and rx ring base addresses */
+	writel((u32)lp->tx_ring_dma_addr,mmio + XMT_RING_BASE_ADDR0);
+	writel((u32)lp->rx_ring_dma_addr,mmio+ RCV_RING_BASE_ADDR0);
+
+	writew((u32)NUM_TX_RING_DR, mmio + XMT_RING_LEN0);
+	writew((u16)NUM_RX_RING_DR, mmio + RCV_RING_LEN0);
+
+	if(lp->options & OPTION_JUMBO_ENABLE){
+		writel((u32)VAL2|JUMBO, mmio + CMD3);
+		/* Reset REX_UFLO */
+		writel( REX_UFLO, mmio + CMD2);
+		/* Should not set REX_UFLO for jumbo frames */
+		writel( VAL0 | APAD_XMT | REX_RTRY, mmio + CMD2);
+	}else
+		writel( VAL0 | APAD_XMT | REX_RTRY|REX_UFLO, mmio + CMD2);
+
+#if AMD8111E_VLAN_TAG_USED
+	writel((u32) VAL2|VSIZE|VL_TAG_DEL, mmio + CMD3);
+#endif
+	writel( VAL0 | APAD_XMT | REX_RTRY, mmio + CMD2 );
+	
+	/* Setting the MAC address to the device */
+	for(i = 0; i < ETH_ADDR_LEN; i++)
+		writeb( dev->dev_addr[i], mmio + PADR + i ); 
+	
+	/* set RUN bit to start the chip */
+	writel(VAL2 | RDMD0, mmio + CMD0);
+	writel(VAL0 | INTREN | RUN, mmio + CMD0);
+	
+	return 0;
+}
+/* 
+This function clears necessary the device registers. 
+*/	
+static void amd8111e_init_hw_default( struct amd8111e_priv* lp)
+{
+	unsigned int reg_val;
+	unsigned int logic_filter[2] ={0,};
+	void * mmio = lp->mmio;
+
+
+	/* AUTOPOLL0 Register *//*TBD default value is 8100 in FPS */
+	writew( 0x8101, mmio + AUTOPOLL0);
+
+	/* Clear RCV_RING_BASE_ADDR */
+	writel(0, mmio + RCV_RING_BASE_ADDR0);
+
+	/* Clear XMT_RING_BASE_ADDR */
+	writel(0, mmio + XMT_RING_BASE_ADDR0);
+	writel(0, mmio + XMT_RING_BASE_ADDR1);
+	writel(0, mmio + XMT_RING_BASE_ADDR2);
+	writel(0, mmio + XMT_RING_BASE_ADDR3);
+
+	/* Clear CMD0  */
+	writel(CMD0_CLEAR,mmio + CMD0);
+	
+	/* Clear CMD2 */
+	writel(CMD2_CLEAR, mmio +CMD2);
+
+	/* Clear CMD7 */
+	writel(CMD7_CLEAR , mmio + CMD7);
+
+	/* Clear DLY_INT_A and DLY_INT_B */
+	writel(0x0, mmio + DLY_INT_A);
+	writel(0x0, mmio + DLY_INT_B);
+
+	/* Clear FLOW_CONTROL */
+	writel(0x0, mmio + FLOW_CONTROL);
+
+	/* Clear INT0  write 1 to clear register */
+	reg_val = readl(mmio + INT0);
+	writel(reg_val, mmio + INT0);
+
+	/* Clear STVAL */
+	writel(0x0, mmio + STVAL);
+
+	/* Clear INTEN0 */
+	writel( INTEN0_CLEAR, mmio + INTEN0);
+
+	/* Clear LADRF */
+	writel(0x0 , mmio + LADRF);
+
+	/* Set SRAM_SIZE & SRAM_BOUNDARY registers  */
+	writel( 0x80010,mmio + SRAM_SIZE);
+
+	/* Clear RCV_RING0_LEN */
+	writel(0x0, mmio +  RCV_RING_LEN0);
+
+	/* Clear XMT_RING0/1/2/3_LEN */
+	writel(0x0, mmio +  XMT_RING_LEN0);
+	writel(0x0, mmio +  XMT_RING_LEN1);
+	writel(0x0, mmio +  XMT_RING_LEN2);
+	writel(0x0, mmio +  XMT_RING_LEN3);
+
+	/* Clear XMT_RING_LIMIT */
+	writel(0x0, mmio + XMT_RING_LIMIT);
+
+	/* Clear MIB */
+	writew(MIB_CLEAR, mmio + MIB_ADDR);
+
+	/* Clear LARF */
+	AMD8111E_WRITE_REG64(mmio, LADRF,logic_filter);
+
+	/* SRAM_SIZE register */
+	reg_val = readl(mmio + SRAM_SIZE);
+	
+	if(lp->options & OPTION_JUMBO_ENABLE)
+		writel( VAL2|JUMBO, mmio + CMD3);
+#if AMD8111E_VLAN_TAG_USED
+	writel(VAL2|VSIZE|VL_TAG_DEL, mmio + CMD3 );
+#endif
+	/* CMD2 register */
+	reg_val = readl(mmio + CMD2);
+
+}
+
+/* 
+This function disables the interrupt and clears all the pending 
+interrupts in INT0
+ */
+static void amd8111e_disable_interrupt(struct amd8111e_priv* lp)
+{	
+	u32 intr0;
+
+	/* Disable interrupt */
+	writel(INTREN, lp->mmio + CMD0);
+	
+	/* Clear INT0 */
+	intr0 = readl(lp->mmio + INT0);
+	writel(intr0, lp->mmio + INT0);
+
+}
+
+/*
+This function stops the chip. 
+*/
+static void amd8111e_stop_chip(struct amd8111e_priv* lp)
+{
+	writel(RUN, lp->mmio + CMD0);
+}
+
+/* 
+This function frees the  transmiter and receiver descriptor rings.
+*/
+static void amd8111e_free_ring(struct amd8111e_priv* lp)
+{	
+
+	/* Free transmit and receive skbs */
+	amd8111e_free_skbs(lp->amd8111e_net_dev);
+
+	/* Free transmit and receive descriptor rings */
+	if(lp->rx_ring){
+		pci_free_consistent(lp->pci_dev, 
+			sizeof(struct amd8111e_rx_dr)*NUM_RX_RING_DR,
+			lp->rx_ring, lp->rx_ring_dma_addr);
+		lp->rx_ring = NULL;
+	}
+	
+	if(lp->tx_ring){
+		pci_free_consistent(lp->pci_dev, 
+			sizeof(struct amd8111e_tx_dr)*NUM_TX_RING_DR,
+			lp->tx_ring, lp->tx_ring_dma_addr);
+
+		lp->tx_ring = NULL;
+	}
+
+}
+#if AMD8111E_VLAN_TAG_USED	
+/* 
+This is the receive indication function for packets with vlan tag.
+*/	
+static int amd8111e_vlan_rx(struct amd8111e_priv *lp, struct sk_buff *skb, u16 vlan_tag)
+{
+	return vlan_hwaccel_rx(skb, lp->vlgrp, vlan_tag);
+}
+#endif
+
+/*
+This function will free all the transmit skbs that are actually transmitted by the device. It will check the ownership of the skb before freeing the skb. 
+*/
+static int amd8111e_tx(struct net_device *dev)
+{
+	struct amd8111e_priv* lp = dev->priv;
+	int tx_index = lp->tx_complete_idx & TX_RING_DR_MOD_MASK;
+	int status;
+	
+	/* Complete all the transmit packet */
+	while (lp->tx_complete_idx != lp->tx_idx){
+		tx_index =  lp->tx_complete_idx & TX_RING_DR_MOD_MASK;
+		status = le16_to_cpu(lp->tx_ring[tx_index].tx_dr_offset2);
+
+		if(status & OWN_BIT)
+			break;	/* It still hasn't been Txed */
+
+		lp->tx_ring[tx_index].buff_phy_addr = 0;
+
+		/* We must free the original skb */
+		if (lp->tx_skbuff[tx_index]) {
+			pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[tx_index],
+				  	lp->tx_skbuff[tx_index]->len,
+					PCI_DMA_TODEVICE);
+			dev_kfree_skb_irq (lp->tx_skbuff[tx_index]);
+			lp->tx_skbuff[tx_index] = 0;
+			lp->tx_dma_addr[tx_index] = 0;
+		}
+		lp->tx_complete_idx++;	
+
+		if (netif_queue_stopped(dev) &&
+			lp->tx_complete_idx > lp->tx_idx - NUM_TX_BUFFERS +2){
+			/* The ring is no longer full, clear tbusy. */
+			netif_wake_queue (dev);
+		}
+	}
+	return 0;
+}
+
+/* 
+This function will check the ownership of receive buffers and descriptors. It will indicate to kernel up to half the number of maximum receive buffers in the descriptor ring, in a single receive interrupt. It will also replenish the descriptors with new skbs.
+*/
+static int amd8111e_rx(struct net_device *dev)
+{
+	struct amd8111e_priv *lp = dev->priv;
+	struct sk_buff *skb,*new_skb;
+	int rx_index = lp->rx_idx & RX_RING_DR_MOD_MASK;
+	int min_pkt_len, status;
+	int num_rx_pkt = 0;
+	int max_rx_pkt = NUM_RX_BUFFERS/2;
+	short pkt_len;
+#if AMD8111E_VLAN_TAG_USED		
+	short vtag;
+#endif
+	
+	/* If we own the next entry, it's a new packet. Send it up. */
+	while(++num_rx_pkt <= max_rx_pkt){
+		if(lp->rx_ring[rx_index].rx_dr_offset10 & OWN_BIT)
+			return 0;
+	       
+		/* check if err summary bit is set */ 
+		if(le16_to_cpu(lp->rx_ring[rx_index].rx_dr_offset10) & ERR_BIT){
+			/* 
+			 * There is a tricky error noted by John Murphy,
+			 * <murf@perftech.com> to Russ Nelson: Even with full-sized
+			 * buffers it's possible for a jabber packet to use two
+			 * buffers, with only the last correctly noting the error.			 */
+			/* reseting flags */
+			lp->rx_ring[rx_index].rx_dr_offset10 &= 
+						cpu_to_le16(RESET_RX_FLAGS);
+			goto err_next_pkt;
+		}
+		/* check for STP and ENP */
+		status = le16_to_cpu(lp->rx_ring[rx_index].rx_dr_offset10);
+		if(!((status & STP_BIT) && (status & ENP_BIT))){
+			/* reseting flags */
+			lp->rx_ring[rx_index].rx_dr_offset10 &= 
+						cpu_to_le16(RESET_RX_FLAGS);
+			goto err_next_pkt;
+		}
+		pkt_len = le16_to_cpu(lp->rx_ring[rx_index].msg_count) - 4;
+
+#if AMD8111E_VLAN_TAG_USED		
+		vtag = le16_to_cpu(lp->rx_ring[rx_index].rx_dr_offset10) & TT_MASK;
+		/*MAC will strip vlan tag*/ 
+		if(lp->vlgrp != NULL && vtag !=0)
+			min_pkt_len =MIN_PKT_LEN - 4;
+		else
+#endif
+			min_pkt_len =MIN_PKT_LEN;
+
+		if (pkt_len < min_pkt_len) {
+			lp->rx_ring[rx_index].rx_dr_offset10 &= 
+				cpu_to_le16(RESET_RX_FLAGS);
+			lp->stats.rx_errors++;
+			goto err_next_pkt;
+		}
+		if(!(new_skb = dev_alloc_skb(lp->rx_buff_len))){
+			/* if allocation fail, 
+				ignore that pkt and go to next one */
+			lp->rx_ring[rx_index].rx_dr_offset10 &= 
+				cpu_to_le16(RESET_RX_FLAGS);
+			lp->stats.rx_errors++;
+			goto err_next_pkt;
+		}
+		
+		skb_reserve(new_skb, 2);
+		skb = lp->rx_skbuff[rx_index];
+		pci_unmap_single(lp->pci_dev,lp->rx_dma_addr[rx_index],
+			lp->rx_buff_len-2, PCI_DMA_FROMDEVICE);
+		skb_put(skb, pkt_len);
+		skb->dev = dev;
+		lp->rx_skbuff[rx_index] = new_skb;
+		new_skb->dev = dev;
+		lp->rx_dma_addr[rx_index] = pci_map_single(lp->pci_dev,
+			new_skb->data, lp->rx_buff_len-2,PCI_DMA_FROMDEVICE);
+	
+		skb->protocol = eth_type_trans(skb, dev);
+
+#if AMD8111E_VLAN_TAG_USED		
+		
+		vtag = lp->rx_ring[rx_index].rx_dr_offset10 & TT_MASK;
+		if(lp->vlgrp != NULL && (vtag == TT_VLAN_TAGGED)){
+			amd8111e_vlan_rx(lp, skb,
+				    lp->rx_ring[rx_index].tag_ctrl_info);
+		} else
+#endif
+			
+			dev->last_rx = jiffies;
+			netif_rx (skb);
+	
+err_next_pkt:
+		lp->rx_ring[rx_index].buff_phy_addr
+			 = cpu_to_le32(lp->rx_dma_addr[rx_index]);
+		lp->rx_ring[rx_index].buff_count = 
+				cpu_to_le16(lp->rx_buff_len-2);
+		lp->rx_ring[rx_index].rx_dr_offset10 |= cpu_to_le16(OWN_BIT);
+		rx_index = (++lp->rx_idx) & RX_RING_DR_MOD_MASK;
+	}
+
+	return 0;
+}
+
+/* 
+This function will store the original speed to restore later, if autoneg is turned on. This speed will be set later when the autoneg is turned off. If the link status indicates that link is down, that will be indicated to the kernel */
+
+static int amd8111e_link_change(struct net_device* dev)
+{	
+	struct amd8111e_priv *lp = dev->priv;
+	int status0,speed;
+
+	/* read the link change */
+     	status0 = readl(lp->mmio + STAT0);
+	
+	if(status0 & LINK_STATS){
+		if(status0 & AUTONEG_COMPLETE){
+			/* keeping the original speeds */
+			if((lp->link_config.speed != SPEED_INVALID)&&
+				(lp->link_config.duplex != DUPLEX_INVALID)){
+			lp->link_config.orig_speed = lp->link_config.speed;
+			lp->link_config.orig_duplex = lp->link_config.duplex;
+			lp->link_config.orig_phy_option = lp->ext_phy_option;
+			}
+	
+			lp->link_config.speed = SPEED_INVALID;
+			lp->link_config.duplex = DUPLEX_INVALID;
+			lp->link_config.autoneg = AUTONEG_ENABLE;
+			netif_carrier_on(dev);
+			return 0;
+		}
+		if(status0 & FULL_DPLX)
+			lp->link_config.duplex = DUPLEX_FULL;
+		else 
+			lp->link_config.duplex = DUPLEX_HALF;
+		speed = (status0 & SPEED_MASK) >> 7;
+		if(speed == PHY_SPEED_10)
+			lp->link_config.speed = SPEED_10;
+		else if(speed == PHY_SPEED_100)
+			lp->link_config.speed = SPEED_100;
+		lp->link_config.autoneg = AUTONEG_DISABLE;
+		netif_carrier_on(dev);
+	}
+	else{	
+		lp->link_config.speed = SPEED_INVALID;
+		lp->link_config.duplex = DUPLEX_INVALID;
+		lp->link_config.autoneg = AUTONEG_INVALID;
+		netif_carrier_off(dev);
+	}
+		
+	return 0;
+}
+/*
+This function reads the mib counters. 	 
+*/
+static int amd8111e_read_mib(void* mmio, u8 MIB_COUNTER)
+{
+	unsigned int  status;
+	unsigned  int data;
+	unsigned int repeat = REPEAT_CNT;
+
+	writew( MIB_RD_CMD | MIB_COUNTER, mmio + MIB_ADDR);
+	do {
+		status = readw(mmio + MIB_ADDR);
+		udelay(2);	/* controller takes MAX 2 us to get mib data */
+	}
+	while (--repeat && (status & MIB_CMD_ACTIVE));
+
+	data = readl(mmio + MIB_DATA);
+	return data;
+}
+
+/*
+This function retuurns the reads the mib registers and returns the hardware statistics. It adds the previous statistics with new values.*/ 
+static struct net_device_stats *amd8111e_get_stats(struct net_device * dev)
+{
+	struct amd8111e_priv *lp = dev->priv;
+	void * mmio = lp->mmio;
+	unsigned long flags;
+	struct net_device_stats *prev_stats = &lp->prev_stats;
+	struct net_device_stats* new_stats = &lp->stats;
+	
+	if(!lp->opened)
+		return prev_stats;	
+	spin_lock_irqsave (&lp->lock, flags);
+
+	/* stats.rx_packets */
+	new_stats->rx_packets = prev_stats->rx_packets+
+		amd8111e_read_mib(mmio, rcv_broadcast_pkts)+
+		amd8111e_read_mib(mmio, rcv_multicast_pkts)+
+		amd8111e_read_mib(mmio, rcv_unicast_pkts);
+
+	/* stats.tx_packets */
+	new_stats->tx_packets = prev_stats->tx_packets+
+		amd8111e_read_mib(mmio, xmt_packets);
+
+	/*stats.rx_bytes */
+	new_stats->rx_bytes = prev_stats->rx_bytes+
+		amd8111e_read_mib(mmio, rcv_octets);
+
+	/* stats.tx_bytes */
+	new_stats->tx_bytes = prev_stats->tx_bytes+
+		amd8111e_read_mib(mmio, xmt_octets);
+
+	/* stats.rx_errors */
+	new_stats->rx_errors = prev_stats->rx_errors+
+		amd8111e_read_mib(mmio, rcv_undersize_pkts)+
+		amd8111e_read_mib(mmio, rcv_fragments)+
+		amd8111e_read_mib(mmio, rcv_jabbers)+
+		amd8111e_read_mib(mmio, rcv_alignment_errors)+
+		amd8111e_read_mib(mmio, rcv_fcs_errors)+
+		amd8111e_read_mib(mmio, rcv_miss_pkts);
+
+	/* stats.tx_errors */
+	new_stats->tx_errors = prev_stats->tx_errors+
+		amd8111e_read_mib(mmio, xmt_underrun_pkts);
+
+	/* stats.rx_dropped*/
+	new_stats->rx_dropped = prev_stats->rx_dropped+
+		amd8111e_read_mib(mmio, rcv_miss_pkts);
+
+	/* stats.tx_dropped*/
+	new_stats->tx_dropped = prev_stats->tx_dropped+
+		amd8111e_read_mib(mmio,  xmt_underrun_pkts);
+
+	/* stats.multicast*/
+	new_stats->multicast = prev_stats->multicast+
+		amd8111e_read_mib(mmio, rcv_multicast_pkts);
+
+	/* stats.collisions*/
+	new_stats->collisions = prev_stats->collisions+
+		amd8111e_read_mib(mmio, xmt_collisions);
+
+	/* stats.rx_length_errors*/
+	new_stats->rx_length_errors = prev_stats->rx_length_errors+
+		amd8111e_read_mib(mmio, rcv_undersize_pkts)+
+		amd8111e_read_mib(mmio, rcv_oversize_pkts);
+
+	/* stats.rx_over_errors*/
+	new_stats->rx_over_errors = prev_stats->rx_over_errors+
+		amd8111e_read_mib(mmio, rcv_miss_pkts);
+
+	/* stats.rx_crc_errors*/
+	new_stats->rx_crc_errors = prev_stats->rx_crc_errors+
+		amd8111e_read_mib(mmio, rcv_fcs_errors);
+
+	/* stats.rx_frame_errors*/
+	new_stats->rx_frame_errors = prev_stats->rx_frame_errors+
+		amd8111e_read_mib(mmio, rcv_alignment_errors);
+
+	/* stats.rx_fifo_errors */
+	new_stats->rx_fifo_errors = prev_stats->rx_fifo_errors+
+		amd8111e_read_mib(mmio, rcv_miss_pkts);
+
+	/* stats.rx_missed_errors */
+	new_stats->rx_missed_errors = prev_stats->rx_missed_errors+
+		amd8111e_read_mib(mmio, rcv_miss_pkts);
+
+	/* stats.tx_aborted_errors*/
+	new_stats->tx_aborted_errors = prev_stats->tx_aborted_errors+
+		amd8111e_read_mib(mmio, xmt_excessive_collision);
+
+	/* stats.tx_carrier_errors*/
+	new_stats->tx_carrier_errors = prev_stats->tx_carrier_errors+
+		amd8111e_read_mib(mmio, xmt_loss_carrier);
+
+	/* stats.tx_fifo_errors*/
+	new_stats->tx_fifo_errors = prev_stats->tx_fifo_errors+
+		amd8111e_read_mib(mmio, xmt_underrun_pkts);
+
+	/* stats.tx_window_errors*/
+	new_stats->tx_window_errors = prev_stats->tx_window_errors+
+		amd8111e_read_mib(mmio, xmt_late_collision);
+
+	spin_unlock_irqrestore (&lp->lock, flags);
+
+	return new_stats;
+}
+
+/*
+This is device interrupt function. It handles transmit, receive and link change interrupts.
+*/
+static void amd8111e_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+
+	struct net_device * dev = (struct net_device *) dev_id;
+	struct amd8111e_priv *lp = dev->priv;
+	void * mmio = lp->mmio;
+	unsigned int intr0;
+
+	if(dev == NULL)
+		return;
+
+	spin_lock (&lp->lock);
+	/* disabling interrupt */
+	writel(INTREN, mmio + CMD0);
+
+	/* Read interrupt status */
+	intr0 = readl(mmio + INT0);
+
+	/* Process all the INT event until INTR bit is clear. */
+
+	if (!(intr0 & INTR))
+		goto err_no_interrupt;
+		 
+	/* Current driver processes 3 interrupts : RINT,TINT,LCINT */
+	writel(intr0, mmio + INT0);
+
+	/* Check if Receive Interrupt has occurred. */
+	if(intr0 & RINT0){
+		amd8111e_rx(dev);
+		writel(VAL2 | RDMD0, mmio + CMD0);
+	}
+
+	/* Check if  Transmit Interrupt has occurred. */
+	if(intr0 & TINT0)
+		amd8111e_tx(dev);
+		
+	/* Check if  Link Change Interrupt has occurred. */
+	if (intr0 & LCINT)
+		amd8111e_link_change(dev);
+	
+err_no_interrupt:
+	writel( VAL0 | INTREN,mmio + CMD0);
+	spin_unlock(&lp->lock);
+	return;
+
+}
+/*
+This function closes the network interface and copies the new set of statistics into the previous statistics structure so that most recent statistics will be available after the interface is down.
+*/
+static int amd8111e_close(struct net_device * dev)
+{
+	struct amd8111e_priv *lp = dev->priv;
+	netif_stop_queue(dev);
+	
+	spin_lock_irq(&lp->lock);
+	
+	amd8111e_disable_interrupt(lp);
+	amd8111e_stop_chip(lp);
+	amd8111e_free_ring(lp);
+	
+	netif_carrier_off(lp->amd8111e_net_dev);
+
+	spin_unlock_irq(&lp->lock);
+
+	free_irq(dev->irq, dev);
+	memcpy(&lp->prev_stats,amd8111e_get_stats(dev), sizeof(lp->prev_stats));
+	lp->opened = 0;
+	return 0;
+}
+/* This function opens new interface.It requests irq for the device, initializes the device,buffers and descriptors, and starts the device. 
+*/
+static int amd8111e_open(struct net_device * dev )
+{
+	struct amd8111e_priv *lp = (struct amd8111e_priv *)dev->priv;
+
+	if(dev->irq ==0 || request_irq(dev->irq, amd8111e_interrupt, SA_SHIRQ,
+					 dev->name, dev)) 
+		return -EAGAIN;
+
+	spin_lock_irq(&lp->lock);
+
+	amd8111e_init_hw_default(lp);
+
+	if(amd8111e_restart(dev)){
+		spin_unlock_irq(&lp->lock);
+		return -ENOMEM;
+	}
+	
+	lp->opened = 1;
+
+	spin_unlock_irq(&lp->lock);
+
+	netif_start_queue(dev);
+
+	return 0;		
+}
+/* 
+This function checks if there is any transmit  descriptors available to queue more packet.
+*/
+static int amd8111e_tx_queue_avail(struct amd8111e_priv* lp )
+{	
+	int tx_index = lp->tx_idx & TX_BUFF_MOD_MASK;
+	if(lp->tx_skbuff[tx_index] != 0)
+		return -1;
+	else
+		return 0;
+	
+}
+/* 
+This function will queue the transmit packets to the descriptors and will trigger the send operation. It also initializes the transmit descriptors with buffer physical address, byte count, ownership to hardware etc.
+*/
+
+static int amd8111e_start_xmit(struct sk_buff *skb, struct net_device * dev)
+{
+	struct amd8111e_priv *lp = dev->priv;
+	int tx_index;
+	unsigned long flags;
+
+	spin_lock_irqsave(&lp->lock, flags);
+
+	tx_index = lp->tx_idx & TX_RING_DR_MOD_MASK;
+
+	lp->tx_ring[tx_index].buff_count = cpu_to_le16(skb->len);
+
+	lp->tx_skbuff[tx_index] = skb;
+	lp->tx_ring[tx_index].tx_dr_offset2 = 0;
+
+#if AMD8111E_VLAN_TAG_USED
+	if((lp->vlgrp != NULL) && vlan_tx_tag_present(skb)){
+
+		lp->tx_ring[tx_index].tag_ctrl_cmd |= 
+				cpu_to_le32(TCC_VLAN_INSERT);	
+		lp->tx_ring[tx_index].tag_ctrl_info = 
+				cpu_to_le16(vlan_tx_tag_get(skb));
+
+	}
+#endif
+	lp->tx_dma_addr[tx_index] =
+	    pci_map_single(lp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE);
+	lp->tx_ring[tx_index].buff_phy_addr =
+	    (u32) cpu_to_le32(lp->tx_dma_addr[tx_index]);
+
+	/*  Set FCS and LTINT bits */
+	lp->tx_ring[tx_index].tx_dr_offset2 |=
+	    cpu_to_le16(OWN_BIT | STP_BIT | ENP_BIT|ADD_FCS_BIT|LTINT_BIT);
+
+	lp->tx_idx++;
+
+	/* Trigger an immediate send poll. */
+	writel( VAL1 | TDMD0, lp->mmio + CMD0);
+	writel( VAL2 | RDMD0,lp->mmio + CMD0);
+
+	dev->trans_start = jiffies;
+
+	if(amd8111e_tx_queue_avail(lp) < 0){
+		netif_stop_queue(dev);
+	}
+	spin_unlock_irqrestore(&lp->lock, flags);
+	return 0;
+}
+/*
+This function returns all the memory mapped registers of the device.
+*/
+static char* amd8111e_read_regs(struct amd8111e_priv* lp)
+{    	
+	void * mmio = lp->mmio;
+        unsigned char * reg_buff;
+
+     	int i;
+     
+     	reg_buff = kmalloc( AMD8111E_REG_DUMP_LEN,GFP_KERNEL);
+	if(NULL == reg_buff)
+		return NULL;
+    	for (i=0; i < AMD8111E_REG_DUMP_LEN; i+=4)
+		reg_buff[i]= readl(mmio + i);	
+	return reg_buff;
+}
+/*
+This function sets promiscuos mode, all-multi mode or the multicast address 
+list to the device.
+*/
+static void amd8111e_set_multicast_list(struct net_device *dev)
+{
+	struct dev_mc_list* mc_ptr;
+	struct amd8111e_priv *lp = dev->priv;
+	u32 mc_filter[2] ;
+	int i,bit_num;
+
+	if(dev->flags & IFF_PROMISC){
+		printk("%s: Setting  promiscuous mode.\n",dev->name);
+		writel( VAL2 | PROM, lp->mmio + CMD2);
+		return;
+	}
+	else
+		writel( PROM, lp->mmio + CMD2);
+	if(dev->flags & IFF_ALLMULTI || dev->mc_count > MAX_FILTER_SIZE){
+		/* get all multicast packet */
+		mc_filter[1] = mc_filter[0] = 0xffffffff;
+		lp->mc_list = dev->mc_list;
+		lp->options |= OPTION_MULTICAST_ENABLE;
+		AMD8111E_WRITE_REG64(lp->mmio, LADRF,mc_filter);
+		return;
+	}
+	if( dev->mc_count == 0 ){
+		/* get only own packets */
+		mc_filter[1] = mc_filter[0] = 0;
+		lp->mc_list = 0;
+		lp->options &= ~OPTION_MULTICAST_ENABLE;
+		AMD8111E_WRITE_REG64(lp->mmio, LADRF,mc_filter);
+		/* disable promiscous mode */
+		writel(PROM, lp->mmio + CMD2);
+		return;
+	}
+	/* load all the multicast addresses in the logic filter */
+	lp->options |= OPTION_MULTICAST_ENABLE;
+	lp->mc_list = dev->mc_list;
+	mc_filter[1] = mc_filter[0] = 0;
+	for (i = 0, mc_ptr = dev->mc_list; mc_ptr && i < dev->mc_count;
+		     i++, mc_ptr = mc_ptr->next) {
+		bit_num = ether_crc(ETH_ALEN, mc_ptr->dmi_addr) >> 26;
+			
+		mc_filter[bit_num >> 5] |= 1 << (bit_num & 31);
+	}	
+
+	AMD8111E_WRITE_REG64(lp->mmio, LADRF, mc_filter);
+	return;
+}
+/*
+This function handles all the  ethtool ioctls. It gives driver info, gets/sets driver speed, gets memory mapped register values, forces auto negotiation, sets/gets WOL options for ethtool application. 
+*/
+	
+static int amd8111e_ethtool_ioctl(struct net_device* dev, void* useraddr)
+{
+	struct amd8111e_priv *lp = dev->priv;
+	struct pci_dev *pci_dev = lp->pci_dev;
+	u32 ethcmd;
+	
+	if( useraddr == NULL) 
+		return -EINVAL;
+	if(copy_from_user (&ethcmd, useraddr, sizeof (ethcmd)))
+		return -EFAULT;
+	
+	switch(ethcmd){
+	
+	case ETHTOOL_GDRVINFO:{
+		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+		strcpy (info.driver, MODULE_NAME);
+		strcpy (info.version, MODULE_VERSION);
+		memset(&info.fw_version, 0, sizeof(info.fw_version));
+		strcpy (info.bus_info, pci_dev->slot_name);
+		info.eedump_len = 0;
+		info.regdump_len = AMD8111E_REG_DUMP_LEN;
+		if (copy_to_user (useraddr, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+	case ETHTOOL_GSET:{
+		struct ethtool_cmd cmd = { ETHTOOL_GSET };
+
+		if (!lp->opened) 
+			return -EAGAIN;
+
+		cmd.supported = SUPPORTED_Autoneg |
+				SUPPORTED_100baseT_Half |
+				SUPPORTED_100baseT_Full |
+			  	SUPPORTED_10baseT_Half |
+			        SUPPORTED_10baseT_Full |
+			        SUPPORTED_MII;
+
+		cmd.advertising = ADVERTISED_Autoneg |
+				ADVERTISED_100baseT_Half |
+				ADVERTISED_100baseT_Full |
+			  	ADVERTISED_10baseT_Half |
+			        ADVERTISED_10baseT_Full |
+			        ADVERTISED_MII;
+		cmd.speed = lp->link_config.speed;
+		cmd.duplex = lp->link_config.duplex;
+		cmd.port = 0;
+		cmd.phy_address = PHY_ID;
+		cmd.transceiver = XCVR_EXTERNAL;
+		cmd.autoneg = lp->link_config.autoneg;
+		cmd.maxtxpkt = 0; /* not implemented interrupt coalasing */
+		cmd.maxrxpkt = 0; /* not implemented interrupt coalasing */
+		if (copy_to_user(useraddr, &cmd, sizeof(cmd)))
+			return -EFAULT;
+		return 0;
+		}
+	case ETHTOOL_SSET: {
+	
+		struct ethtool_cmd cmd;
+
+		if (!lp->opened)
+			return -EAGAIN;
+		if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
+			return -EFAULT;
+
+		spin_lock_irq(&lp->lock);
+
+		if(cmd.autoneg == AUTONEG_ENABLE){
+			/* keeping the original speeds */
+			if((lp->link_config.speed != SPEED_INVALID)&&
+				(lp->link_config.duplex != DUPLEX_INVALID)){
+			lp->link_config.orig_speed = lp->link_config.speed;
+			lp->link_config.orig_duplex = lp->link_config.duplex;
+			lp->link_config.orig_phy_option = lp->ext_phy_option;
+			}
+
+			lp->ext_phy_option = XPHYANE;
+		}
+		else if(cmd.speed == SPEED_100 && cmd.duplex ==  DUPLEX_HALF)
+			lp->ext_phy_option = XPHYSP;
+		else if(cmd.speed == SPEED_100 && cmd.duplex ==  DUPLEX_FULL)
+			lp->ext_phy_option = XPHYSP |XPHYFD;
+		else if(cmd.speed == SPEED_10 && cmd.duplex ==  DUPLEX_HALF)
+			lp->ext_phy_option = 0;
+		else if(cmd.speed == SPEED_10 && cmd.duplex ==  DUPLEX_FULL)
+			lp->ext_phy_option = XPHYFD;
+		else {	
+			/* setting the original speed */
+			cmd.speed = lp->link_config.orig_speed;
+			cmd.duplex = lp->link_config.orig_duplex;
+			lp->ext_phy_option = lp->link_config.orig_phy_option;
+		}
+		lp->link_config.autoneg = cmd.autoneg;
+		if (cmd.autoneg == AUTONEG_ENABLE) {
+			
+			lp->link_config.speed = SPEED_INVALID;
+			lp->link_config.duplex = DUPLEX_INVALID;
+		} else {
+			lp->link_config.speed = cmd.speed;
+			lp->link_config.duplex = cmd.duplex;
+		}
+		amd8111e_set_ext_phy(dev);
+		spin_unlock_irq(&lp->lock);
+		return 0;
+	}
+	case ETHTOOL_GREGS: {
+		struct ethtool_regs regs;
+		u8 *regbuf;
+		int ret;
+
+		if (copy_from_user(&regs, useraddr, sizeof(regs)))
+			return -EFAULT;
+		if (regs.len > AMD8111E_REG_DUMP_LEN)
+			regs.len = AMD8111E_REG_DUMP_LEN;
+		regs.version = 0;
+		if (copy_to_user(useraddr, &regs, sizeof(regs)))
+			return -EFAULT;
+
+		regbuf = amd8111e_read_regs(lp);
+		if (!regbuf)
+			return -ENOMEM;
+
+		useraddr += offsetof(struct ethtool_regs, data);
+		ret = 0;
+		if (copy_to_user(useraddr, regbuf, regs.len))
+			ret = -EFAULT;
+		kfree(regbuf);
+		return ret;
+	}
+	case ETHTOOL_NWAY_RST: {
+		int ret;
+		spin_lock_irq(&lp->lock);
+		if(lp->link_config.autoneg == AUTONEG_ENABLE){
+			lp->ext_phy_option = XPHYANE;
+			amd8111e_set_ext_phy(dev);
+			ret = 0;
+		}else
+			ret =  -EINVAL;
+		spin_unlock_irq(&lp->lock);
+		return ret;
+	}
+	case ETHTOOL_GLINK: {
+		struct ethtool_value val = { ETHTOOL_GLINK };
+
+		val.data = netif_carrier_ok(dev) ? 1 : 0;
+		if (copy_to_user(useraddr, &val, sizeof(val)))
+			return -EFAULT;
+	}
+	case ETHTOOL_GWOL: {
+		struct ethtool_wolinfo wol_info = { ETHTOOL_GWOL };
+
+		wol_info.supported = WAKE_MAGIC|WAKE_PHY;
+		wol_info.wolopts = 0;
+		if (lp->options & OPTION_WOL_ENABLE)
+			wol_info.wolopts = WAKE_MAGIC;
+		memset(&wol_info.sopass, 0, sizeof(wol_info.sopass));
+		if (copy_to_user(useraddr, &wol_info, sizeof(wol_info)))
+			return -EFAULT;
+		return 0;
+	}
+	case ETHTOOL_SWOL: {
+		struct ethtool_wolinfo wol_info;
+
+		if (copy_from_user(&wol_info, useraddr, sizeof(wol_info)))
+			return -EFAULT;
+		if (wol_info.wolopts & ~(WAKE_MAGIC |WAKE_PHY))
+			return -EINVAL;
+		spin_lock_irq(&lp->lock);
+		if(wol_info.wolopts & WAKE_MAGIC)
+			lp->options |= 
+				(OPTION_WOL_ENABLE | OPTION_WAKE_MAGIC_ENABLE);
+		else if(wol_info.wolopts & WAKE_PHY)
+			lp->options |= 
+				(OPTION_WOL_ENABLE | OPTION_WAKE_PHY_ENABLE);
+		else
+			lp->options &= ~OPTION_WOL_ENABLE; 
+		spin_unlock_irq(&lp->lock);
+		return 0;
+	}
+	
+	default:
+		break;
+	}
+		return -EOPNOTSUPP;
+}
+static int amd8111e_read_phy(struct amd8111e_priv* lp, int phy_id, int reg, u32* val)
+{
+	void * mmio = lp->mmio;
+	unsigned int reg_val;
+	unsigned int repeat= REPEAT_CNT;
+
+	reg_val = readl(mmio + PHY_ACCESS);
+	while (reg_val & PHY_CMD_ACTIVE)
+		reg_val = readl( mmio + PHY_ACCESS );
+
+	writel( PHY_RD_CMD | ((phy_id & 0x1f) << 21) |
+			   ((reg & 0x1f) << 16),  mmio +PHY_ACCESS);
+	do{
+		reg_val = readl(mmio + PHY_ACCESS);
+		udelay(30);  /* It takes 30 us to read/write data */
+	} while (--repeat && (reg_val & PHY_CMD_ACTIVE));
+	if(reg_val & PHY_RD_ERR)
+		goto err_phy_read;
+	
+	*val = reg_val & 0xffff;
+	return 0;
+err_phy_read:	
+	*val = 0;
+	return -EINVAL;
+	
+}
+static int amd8111e_write_phy(struct amd8111e_priv* lp,int phy_id, int reg, u32 val)
+{
+	unsigned int repeat = REPEAT_CNT
+	void * mmio = lp->mmio;
+	unsigned int reg_val;
+	
+
+	reg_val = readl(mmio + PHY_ACCESS);
+	while (reg_val & PHY_CMD_ACTIVE)
+		reg_val = readl( mmio + PHY_ACCESS );
+
+	writel( PHY_WR_CMD | ((phy_id & 0x1f) << 21) |
+			   ((reg & 0x1f) << 16)|val, mmio + PHY_ACCESS);
+
+	do{
+		reg_val = readl(mmio + PHY_ACCESS);
+		udelay(30);  /* It takes 30 us to read/write the data */
+	} while (--repeat && (reg_val & PHY_CMD_ACTIVE));
+	
+	if(reg_val & PHY_RD_ERR)
+		goto err_phy_write;
+	
+	return 0;
+
+err_phy_write:	
+	return -EINVAL;
+	
+}
+static int amd8111e_ioctl(struct net_device * dev , struct ifreq *ifr, int cmd)
+{
+	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data;
+	struct amd8111e_priv *lp = dev->priv;
+	int err;
+	u32 mii_regval;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	switch(cmd) {
+	case SIOCETHTOOL:
+		return amd8111e_ethtool_ioctl(dev, (void *) ifr->ifr_data);
+	case SIOCGMIIPHY:
+		data->phy_id = PHY_ID;
+
+	/* fallthru */
+	case SIOCGMIIREG: 
+
+		spin_lock_irq(&lp->lock);
+		err = amd8111e_read_phy(lp, data->phy_id,
+			data->reg_num & PHY_REG_ADDR_MASK, &mii_regval);
+		spin_unlock_irq(&lp->lock);
+
+		data->val_out = mii_regval;
+		return err;
+
+	case SIOCSMIIREG:
+
+		spin_lock_irq(&lp->lock);
+		err = amd8111e_write_phy(lp, data->phy_id,
+			data->reg_num & PHY_REG_ADDR_MASK, data->val_in);
+		spin_unlock_irq(&lp->lock);
+
+		return err;
+
+	default:
+		/* do nothing */
+		break;
+	}
+	return -EOPNOTSUPP;
+}
+/* 
+This function changes the mtu of the device. It restarts the device  to initialize the descriptor with new receive buffers.
+*/  
+int amd8111e_change_mtu(struct net_device *dev, int new_mtu)
+{
+	struct amd8111e_priv *lp = dev->priv;
+	int err;
+
+	if ((new_mtu < AMD8111E_MIN_MTU) || (new_mtu > AMD8111E_MAX_MTU))
+		return -EINVAL;
+
+	if (!netif_running(dev)) {
+		/* new_mtu will be used
+		   when device starts netxt time */ 
+		dev->mtu = new_mtu;
+		return 0;
+	}
+
+	spin_lock_irq(&lp->lock);
+
+        /* stop the chip */
+	writel(RUN, lp->mmio + CMD0);
+
+	dev->mtu = new_mtu;
+
+	/* if (new_mtu > ETH_DATA_LEN)
+		lp->options |= OPTION_JUMBO_ENABLE;
+	else
+		lp->options &= ~OPTION_JUMBO_ENABLE;
+	*/
+	err = amd8111e_restart(dev);
+	spin_unlock_irq(&lp->lock);
+
+	netif_start_queue(dev);
+	return err;
+}
+
+#if AMD8111E_VLAN_TAG_USED
+static void amd8111e_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
+{
+	struct  amd8111e_priv *lp = dev->priv;
+	spin_lock_irq(&lp->lock);
+	lp->vlgrp = grp;
+	spin_unlock_irq(&lp->lock);
+}
+	
+static void amd8111e_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
+{
+	struct amd8111e_priv *lp = dev->priv;
+	spin_lock_irq(&lp->lock);
+	if (lp->vlgrp)
+		lp->vlgrp->vlan_devices[vid] = NULL;
+	spin_unlock_irq(&lp->lock);
+}
+#endif
+static int amd8111e_enable_magicpkt(struct amd8111e_priv* lp)
+{
+	writel( VAL1|MPPLBA, lp->mmio + CMD3);
+	writel( VAL0|MPEN_SW, lp->mmio + CMD7);
+	return 0;
+}
+
+static int amd8111e_enable_link_change(struct amd8111e_priv* lp)
+{
+	/* Adapter is already stoped/suspended/interrupt-disabled */
+	writel(VAL0|LCMODE_SW,lp->mmio + CMD7);
+	return 0;
+}	
+
+/* 
+This function sets the power state of the device. When the device go to lower power states 1,2, and 3 it enables the wake on lan 
+*/  	
+static int amd8111e_set_power_state(struct amd8111e_priv* lp, u32 state)
+{
+	u16 power_control;
+	int pm = lp->pm_cap;
+
+	pci_read_config_word(lp->pci_dev,
+			     pm + PCI_PM_CTRL,
+			     &power_control);
+
+	power_control |= PCI_PM_CTRL_PME_STATUS;
+	power_control &= ~(PCI_PM_CTRL_STATE_MASK);
+	switch (state) {
+	case 0:
+		power_control |= 0;
+		pci_write_config_word(lp->pci_dev,
+				      pm + PCI_PM_CTRL,
+				      power_control);
+		return 0;
+
+	case 1:
+		power_control |= 1;
+		break;
+
+	case 2:
+		power_control |= 2;
+		break;
+
+	case 3:
+		power_control |= 3;
+		break;
+	default:
+
+		printk(KERN_WARNING "%s: Invalid power state (%d) requested.\n",
+		       lp->amd8111e_net_dev->name, state);
+		return -EINVAL;
+	}
+	
+	if(lp->options & OPTION_WAKE_MAGIC_ENABLE)
+		amd8111e_enable_magicpkt(lp);	
+	if(lp->options & OPTION_WAKE_PHY_ENABLE)
+		amd8111e_enable_link_change(lp);	
+
+	/*  Setting new power state. */
+	pci_write_config_word(lp->pci_dev, pm + PCI_PM_CTRL, power_control);
+
+	return 0;
+
+
+}
+static int amd8111e_suspend(struct pci_dev *pci_dev, u32 state)
+{	
+	struct net_device *dev = pci_get_drvdata(pci_dev);
+	struct amd8111e_priv *lp = dev->priv;
+	int err;
+	
+	if (!netif_running(dev))
+		return 0;
+
+	/* disable the interrupt */
+	spin_lock_irq(&lp->lock);
+	amd8111e_disable_interrupt(lp);
+	spin_unlock_irq(&lp->lock);
+
+	netif_device_detach(dev);
+	
+	/* stop chip */
+	spin_lock_irq(&lp->lock);
+	amd8111e_stop_chip(lp);
+	spin_unlock_irq(&lp->lock);
+
+	err = amd8111e_set_power_state(lp, state);
+	if (err) {
+		
+		spin_lock_irq(&lp->lock);
+		amd8111e_restart(dev);
+		spin_unlock_irq(&lp->lock);
+
+		netif_device_attach(dev);
+	}
+	return err;
+}
+static int amd8111e_resume(struct pci_dev *pci_dev)
+{
+	struct net_device *dev = pci_get_drvdata(pci_dev);
+	struct amd8111e_priv *lp = dev->priv;
+	int err;
+	
+	if (!netif_running(dev))
+		return 0;
+
+	err = amd8111e_set_power_state(lp, 0);
+	if (err)
+		return err;
+
+	netif_device_attach(dev);
+
+	spin_lock_irq(&lp->lock);
+	amd8111e_restart(dev);
+	spin_unlock_irq(&lp->lock);
+
+	return 0;
+}
+
+
+static void __devexit amd8111e_remove_one(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	if (dev) {
+		unregister_netdev(dev);
+		iounmap((void *) ((struct amd8111e_priv *)(dev->priv))->mmio);
+		kfree(dev);
+		pci_release_regions(pdev);
+		pci_disable_device(pdev);
+		pci_set_drvdata(pdev, NULL);
+	}
+}
+
+static int __devinit amd8111e_probe_one(struct pci_dev *pdev,
+				  const struct pci_device_id *ent)
+{
+	int err,i,pm_cap;
+	unsigned long reg_addr,reg_len;
+	struct amd8111e_priv* lp;
+	struct net_device* dev;
+	unsigned int chip_version;
+
+	err = pci_enable_device(pdev);
+	if(err){
+		printk(KERN_ERR "amd8111e: Cannot enable new PCI device,"
+			"exiting.\n");
+		return err;
+	}
+
+	if(!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)){
+		printk(KERN_ERR "amd8111e: Cannot find PCI base address"
+		       "exiting.\n");
+		err = -ENODEV;
+		goto err_disable_pdev;
+	}
+
+	err = pci_request_regions(pdev, MODULE_NAME);
+	if(err){
+		printk(KERN_ERR "amd8111e: Cannot obtain PCI resources, "
+		       "exiting.\n");
+		goto err_disable_pdev;
+	}
+
+	pci_set_master(pdev);
+
+	/* Find power-management capability. */
+	if((pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM))==0){
+		printk(KERN_ERR "amd8111e: No Power Management capability, "
+		       "exiting.\n");
+		goto err_free_reg;
+	}
+
+	/* Initialize DMA */
+	if(!pci_dma_supported(pdev, 0xffffffff)){
+		printk(KERN_ERR "amd8111e: DMA not supported,"
+			"exiting.\n");
+		goto  err_free_reg;
+	} else
+		pdev->dma_mask = 0xffffffff;
+	
+	reg_addr = pci_resource_start(pdev, 0);
+	reg_len = pci_resource_len(pdev, 0);
+
+	dev = alloc_etherdev(sizeof(struct amd8111e_priv));
+	if (!dev) {
+		printk(KERN_ERR "amd8111e: Etherdev alloc failed, exiting.\n");
+		err = -ENOMEM;
+		goto err_free_reg;
+	}
+
+	SET_MODULE_OWNER(dev);
+
+#if AMD8111E_VLAN_TAG_USED
+	dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX ;
+	dev->vlan_rx_register =amd8111e_vlan_rx_register;
+	dev->vlan_rx_kill_vid = amd8111e_vlan_rx_kill_vid;
+#endif	
+	
+	lp = dev->priv;
+	memset (lp, 0, sizeof (*lp));
+	lp->pci_dev = pdev;
+	lp->amd8111e_net_dev = dev;
+	lp->pm_cap = pm_cap;
+
+	spin_lock_init(&lp->lock);
+
+	lp->mmio = ioremap(reg_addr, reg_len);
+	if (lp->mmio == 0) {
+		printk(KERN_ERR "amd8111e: Cannot map device registers, "
+		       "exiting\n");
+		err = -ENOMEM;
+		goto err_free_dev;
+	}
+	
+	/* Initializing MAC address */
+	for(i = 0; i < ETH_ADDR_LEN; i++)
+			dev->dev_addr[i] =readb(lp->mmio + PADR + i);
+	/* Setting user defined speed */
+	if (speed_duplex[card_idx] > sizeof(speed_duplex_mapping))
+		lp->ext_phy_option = XPHYANE;
+	else
+		lp->ext_phy_option = 
+				speed_duplex_mapping[speed_duplex[card_idx]];
+	/* Initialize driver entry points */
+	dev->open = amd8111e_open;
+	dev->hard_start_xmit = amd8111e_start_xmit;
+	dev->stop = amd8111e_close;
+	dev->get_stats = amd8111e_get_stats;
+	dev->set_multicast_list = amd8111e_set_multicast_list;
+	dev->do_ioctl = amd8111e_ioctl;
+	dev->change_mtu = amd8111e_change_mtu;
+	dev->irq =pdev->irq;
+
+#if AMD8111E_VLAN_TAG_USED
+	dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+	dev->vlan_rx_register =amd8111e_vlan_rx_register;
+	dev->vlan_rx_kill_vid = amd8111e_vlan_rx_kill_vid;
+#endif	
+	
+	/* Set receive buffer length and set jumbo option*/
+	amd8111e_set_rx_buff_len(dev);
+	
+
+	/* dev->tx_timeout = tg3_tx_timeout; */
+	/* dev->watchdog_timeo = TG3_TX_TIMEOUT; */
+
+	err = register_netdev(dev);
+	if (err) {
+		printk(KERN_ERR "amd8111e: Cannot register net device, "
+		       "exiting.\n");
+		goto err_iounmap;
+	}
+
+	pci_set_drvdata(pdev, dev);
+	
+	/*  display driver and device information */
+
+    chip_version = (readl(lp->mmio + CHIPID) & 0xf0000000)>>28;
+    printk("%s: AMD-8111e Driver Version: %s\n",dev->name,MODULE_VERSION);
+    printk("%s: [ Rev %x ] PCI 10/100BaseT Ethernet ", dev->name, chip_version);
+    for (i = 0; i < 6; i++)
+	printk("%2.2x%c", dev->dev_addr[i],i == 5 ? ' ' : ':');
+     printk("\n");	
+	return 0;
+err_iounmap:
+	iounmap((void *) lp->mmio);
+
+err_free_dev:
+	kfree(dev);
+
+err_free_reg:
+	pci_release_regions(pdev);
+
+err_disable_pdev:
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+	return err;
+
+}
+
+static struct pci_driver amd8111e_driver = {
+	name:		MODULE_NAME,
+	id_table:	amd8111e_pci_tbl,
+	probe:		amd8111e_probe_one,
+	remove:		__devexit_p(amd8111e_remove_one),
+	suspend:	amd8111e_suspend,
+	resume:		amd8111e_resume
+};
+
+static int __init amd8111e_init(void)
+{
+	return pci_module_init(&amd8111e_driver);
+}
+
+static void __exit amd8111e_cleanup(void)
+{
+	pci_unregister_driver(&amd8111e_driver);
+}
+
+module_init(amd8111e_init);
+module_exit(amd8111e_cleanup);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/amd8111e.h linux-2.4.21-pre6/drivers/net/amd8111e.h
--- linux-2.4.20/drivers/net/amd8111e.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/amd8111e.h	2003-03-26 23:49:18.000000000 +0000
@@ -0,0 +1,786 @@
+/*
+ * 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
+
+Module Name:
+
+    amd8111e.h
+
+Abstract:
+	
+ 	 AMD8111 based 10/100 Ethernet Controller driver definitions. 
+
+Environment:
+    
+	Kernel Mode
+
+Revision History:
+
+*/
+
+#ifndef _AMD811E_H
+#define _AMD811E_H
+
+/* Hardware definitions */
+
+#define B31_MASK	0x80000000
+#define B30_MASK	0X40000000
+#define B29_MASK	0x20000000
+#define B28_MASK	0x10000000
+#define B27_MASK	0x08000000
+#define B26_MASK	0x04000000
+#define B25_MASK	0x02000000
+#define B24_MASK	0x01000000
+#define B23_MASK	0x00800000
+#define B22_MASK	0x00400000
+#define B21_MASK	0x00200000
+#define B20_MASK	0x00100000
+#define B19_MASK	0x00080000
+#define B18_MASK	0x00040000
+#define B17_MASK	0x00020000
+#define B16_MASK	0x00010000
+
+#define B15_MASK	0x8000
+#define B14_MASK	0x4000
+#define B13_MASK	0x2000
+#define B12_MASK	0x1000
+#define B11_MASK	0x0800
+#define B10_MASK	0x0400
+#define B9_MASK		0x0200
+#define B8_MASK		0x0100
+#define B7_MASK		0x0080
+#define B6_MASK		0x0040
+#define B5_MASK		0x0020
+#define B4_MASK		0x0010
+#define B3_MASK		0x0008
+#define B2_MASK		0x0004
+#define B1_MASK		0x0002
+#define B0_MASK		0x0001
+
+/* PCI register offset */
+#define PCI_ID_REG		0x00
+#define PCI_COMMAND_REG		0x04
+/* #define MEMEN_BIT		B1_MASK */
+/* #define IOEN_BIT		B0_MASK */
+#define PCI_REV_ID_REG		0x08
+#define PCI_MEM_BASE_REG	0x10
+/* #define MEMBASE_MASK		0xFFFFF000 */
+/* #define MEMBASE_SIZE		4096 */
+#define PCI_INTR_REG		0x3C
+#define PCI_STATUS_REG		0x06
+#define PCI_CAP_ID_REG_OFFSET	0x34
+#define PCI_PMC_REG_OFFSET	0x36
+#define PCI_PMCSR_REG_OFFSET	0x38
+
+/* #define NEW_CAP		0x0010  */
+#define PME_EN			0x0100
+
+#define PARTID_MASK		0xFFFFF000
+#define PARTID_START_BIT	12
+
+/* #define LANCE_DWIO_RESET_PORT	0x18
+#define LANCE_WIO_RESET_PORT	0x14 */
+#define MIB_OFFSET		0x28
+
+/* Command style register access
+
+Registers CMD0, CMD2, CMD3,CMD7 and INTEN0 uses a write access technique called command style access. It allows the write to selected bits of this register without altering the bits that are not selected. Command style registers are divided into 4 bytes that can be written independently. Higher order bit of each byte is the  value bit that specifies the value that will be written into the selected bits of register. 
+
+eg., if the value 10011010b is written into the least significant byte of a command style register, bits 1,3 and 4 of the register will be set to 1, and the other bits will not be altered. If the value 00011010b is written into the same byte, bits 1,3 and 4 will be cleared to 0 and the other bits will not be altered.
+
+*/
+
+/*  Offset for Memory Mapped Registers. */
+/* 32 bit registers */
+
+#define  ASF_STAT		0x00	/* ASF status register */
+#define CHIPID			0x04	/* Chip ID regsiter */
+#define	MIB_DATA		0x10	/* MIB data register */
+#define MIB_ADDR		0x14	/* MIB address register */
+#define STAT0			0x30	/* Status0 register */
+#define INT0			0x38	/* Interrupt0 register */
+#define INTEN0			0x40	/* Interrupt0  enable register*/
+#define CMD0			0x48	/* Command0 register */
+#define CMD2			0x50	/* Command2 register */
+#define CMD3			0x54	/* Command3 resiter */
+#define CMD7			0x64	/* Command7 register */
+
+#define CTRL1 			0x6C	/* Control1 register */
+#define CTRL2 			0x70	/* Control2 register */
+
+#define XMT_RING_LIMIT		0x7C	/* Transmit ring limit register */
+
+#define AUTOPOLL0		0x88	/* Auto-poll0 register */
+#define AUTOPOLL1		0x8A	/* Auto-poll1 register */
+#define AUTOPOLL2		0x8C	/* Auto-poll2 register */
+#define AUTOPOLL3		0x8E	/* Auto-poll3 register */
+#define AUTOPOLL4		0x90	/* Auto-poll4 register */
+#define	AUTOPOLL5		0x92	/* Auto-poll5 register */
+
+#define AP_VALUE		0x98	/* Auto-poll value register */
+#define DLY_INT_A		0xA8	/* Group A delayed interrupt register */
+#define DLY_INT_B		0xAC	/* Group B delayed interrupt register */
+
+#define FLOW_CONTROL		0xC8	/* Flow control register */
+#define PHY_ACCESS		0xD0	/* PHY access register */
+
+#define STVAL			0xD8	/* Software timer value register */
+
+#define XMT_RING_BASE_ADDR0	0x100	/* Transmit ring0 base addr register */
+#define XMT_RING_BASE_ADDR1	0x108	/* Transmit ring1 base addr register */
+#define XMT_RING_BASE_ADDR2	0x110	/* Transmit ring2 base addr register */
+#define XMT_RING_BASE_ADDR3	0x118	/* Transmit ring2 base addr register */
+
+#define RCV_RING_BASE_ADDR0	0x120	/* Transmit ring0 base addr register */
+
+#define PMAT0			0x190	/* OnNow pattern register0 */
+#define PMAT1			0x194	/* OnNow pattern register1 */
+
+/* 16bit registers */
+
+#define XMT_RING_LEN0		0x140	/* Transmit Ring0 length register */
+#define XMT_RING_LEN1		0x144	/* Transmit Ring1 length register */
+#define XMT_RING_LEN2		0x148 	/* Transmit Ring2 length register */
+#define XMT_RING_LEN3		0x14C	/* Transmit Ring3 length register */
+
+#define RCV_RING_LEN0		0x150	/* Transmit Ring0 length register */
+
+#define SRAM_SIZE		0x178	/* SRAM size register */
+#define SRAM_BOUNDARY		0x17A	/* SRAM boundary register */
+
+/* 48bit register */
+
+#define PADR			0x160	/* Physical address register */
+
+/* 64bit register */
+
+#define LADRF			0x168	/* Logical address filter register */
+
+/* 8bit regsisters */
+
+#define IFS1			0x18C	/* Inter-frame spacing Part1 register */
+#define IFS			0x18D	/* Inter-frame spacing register */
+
+/* Register Bit Definitions */
+
+/* STAT_ASF			0x00, 32bit register */
+#define ASF_INIT_DONE		B1_MASK
+#define ASF_INIT_PRESENT	B0_MASK
+
+/* MIB_ADDR			0x14, 16bit register */
+#define	MIB_CMD_ACTIVE		B15_MASK
+#define	MIB_RD_CMD		B13_MASK
+#define	MIB_CLEAR		B12_MASK
+#define	MIB_ADDRESS		0x0000003F	/* 5:0 */
+
+/* QOS_ADDR			0x1C, 16bit register */
+#define QOS_CMD_ACTIVE		B15_MASK
+#define QOS_WR_CMD		B14_MASK
+#define QOS_RD_CMD		B13_MASK
+#define QOS_ADDRESS		0x0000001F	/* 4:0 */
+
+/* STAT0			0x30, 32bit register */
+#define PAUSE_PEND		B14_MASK
+#define PAUSING			B13_MASK
+#define PMAT_DET		B12_MASK
+#define MP_DET			B11_MASK
+#define LC_DET			B10_MASK
+#define SPEED_MASK		0x0380	/* 9:7 */
+#define FULL_DPLX		B6_MASK
+#define LINK_STATS		B5_MASK
+#define AUTONEG_COMPLETE	B4_MASK
+#define MIIPD			B3_MASK
+#define RX_SUSPENDED		B2_MASK
+#define TX_SUSPENDED		B1_MASK
+#define RUNNING			B0_MASK
+#define PHY_SPEED_10		0x2
+#define PHY_SPEED_100		0x3
+
+/* INT0				0x38, 32bit register */
+#define INTR			B31_MASK
+#define PCSINT			B28_MASK
+#define LCINT			B27_MASK
+#define APINT5			B26_MASK
+#define APINT4			B25_MASK
+#define APINT3			B24_MASK
+#define TINT_SUM		B23_MASK
+#define APINT2			B22_MASK
+#define APINT1			B21_MASK
+#define APINT0			B20_MASK
+#define MIIPDTINT		B19_MASK
+#define MCCIINT			B18_MASK
+#define MCCINT			B17_MASK
+#define MREINT			B16_MASK
+#define RINT_SUM		B15_MASK
+#define SPNDINT			B14_MASK
+#define MPINT			B13_MASK
+#define SINT			B12_MASK
+#define TINT3			B11_MASK
+#define TINT2			B10_MASK
+#define TINT1			B9_MASK
+#define TINT0			B8_MASK
+#define UINT			B7_MASK
+#define STINT			B4_MASK
+#define RINT3			B3_MASK
+#define RINT2			B2_MASK
+#define RINT1			B1_MASK
+#define RINT0			B0_MASK
+
+/* INTEN0			0x40, 32bit register */
+#define VAL3			B31_MASK   /* VAL bit for byte 3 */
+#define VAL2			B23_MASK   /* VAL bit for byte 2 */
+#define VAL1			B15_MASK   /* VAL bit for byte 1 */
+#define VAL0			B7_MASK    /* VAL bit for byte 0 */
+/* VAL3 */
+#define PSCINTEN		B28_MASK
+#define LCINTEN			B27_MASK
+#define APINT5EN		B26_MASK
+#define APINT4EN		B25_MASK
+#define APINT3EN		B24_MASK
+/* VAL2 */
+#define APINT2EN		B22_MASK
+#define APINT1EN		B21_MASK
+#define APINT0EN		B20_MASK
+#define MIIPDTINTEN		B19_MASK
+#define MCCIINTEN		B18_MASK
+#define MCCINTEN		B17_MASK
+#define MREINTEN		B16_MASK
+/* VAL1 */
+#define SPNDINTEN		B14_MASK
+#define MPINTEN			B13_MASK
+#define SINTEN			B12_MASK
+#define TINTEN3			B11_MASK
+#define TINTEN2			B10_MASK
+#define TINTEN1			B9_MASK
+#define TINTEN0			B8_MASK
+/* VAL0 */
+#define STINTEN			B4_MASK
+#define RINTEN3			B3_MASK
+#define RINTEN2			B2_MASK
+#define RINTEN1			B1_MASK
+#define RINTEN0			B0_MASK
+
+#define INTEN0_CLEAR 		0x1F7F7F1F /* Command style register */		
+
+/* CMD0				0x48, 32bit register */
+/* VAL2 */
+#define RDMD3			B19_MASK
+#define RDMD2			B18_MASK
+#define RDMD1			B17_MASK
+#define RDMD0			B16_MASK
+/* VAL1 */
+#define TDMD3			B11_MASK
+#define TDMD2			B10_MASK
+#define TDMD1			B9_MASK
+#define TDMD0			B8_MASK
+/* VAL0 */
+#define UINTCMD			B6_MASK
+#define RX_FAST_SPND		B5_MASK
+#define TX_FAST_SPND		B4_MASK
+#define RX_SPND			B3_MASK
+#define TX_SPND			B2_MASK
+#define INTREN			B1_MASK
+#define RUN			B0_MASK
+
+#define CMD0_CLEAR 		0x000F0F7F   /* Command style register */	
+
+/* CMD2 			0x50, 32bit register */
+/* VAL3 */
+#define CONDUIT_MODE		B29_MASK
+/* VAL2 */
+#define RPA			B19_MASK
+#define DRCVPA			B18_MASK
+#define DRCVBC			B17_MASK
+#define PROM			B16_MASK
+/* VAL1 */
+#define ASTRP_RCV		B13_MASK
+#define FCOLL			B12_MASK
+#define EMBA			B11_MASK
+#define DXMT2PD			B10_MASK
+#define LTINTEN			B9_MASK
+#define DXMTFCS			B8_MASK
+/* VAL0 */
+#define APAD_XMT		B6_MASK
+#define DRTY			B5_MASK
+#define INLOOP			B4_MASK
+#define EXLOOP			B3_MASK
+#define REX_RTRY		B2_MASK
+#define REX_UFLO		B1_MASK
+#define REX_LCOL		B0_MASK
+
+#define CMD2_CLEAR 		0x3F7F3F7F   /* Command style register */
+
+/* CMD3				0x54, 32bit register */
+/* VAL3 */
+#define ASF_INIT_DONE_ALIAS	B29_MASK
+/* VAL2 */
+#define JUMBO			B21_MASK
+#define VSIZE			B20_MASK
+#define VLONLY			B19_MASK
+#define VL_TAG_DEL		B18_MASK
+/* VAL1 */
+#define EN_PMGR			B14_MASK
+#define INTLEVEL		B13_MASK
+#define FORCE_FULL_DUPLEX	B12_MASK
+#define FORCE_LINK_STATUS	B11_MASK
+#define APEP			B10_MASK
+#define MPPLBA			B9_MASK
+/* VAL0 */
+#define RESET_PHY_PULSE		B2_MASK
+#define RESET_PHY		B1_MASK
+#define PHY_RST_POL		B0_MASK
+/* CMD7				0x64, 32bit register */
+/* VAL0 */
+#define PMAT_SAVE_MATCH		B4_MASK
+#define PMAT_MODE		B3_MASK
+#define MPEN_SW			B1_MASK
+#define LCMODE_SW		B0_MASK
+
+#define CMD7_CLEAR  		0x0000001B		/* Command style register */
+/* CTRL0			0x68, 32bit register */
+#define PHY_SEL			0x03000000	/* 25:24 */
+#define RESET_PHY_WIDTH		0x00FF0000	/* 23:16 */
+#define BSWP_REGS		B10_MASK
+#define BSWP_DESC		B9_MASK
+#define BSWP_DATA		B8_MASK
+#define CACHE_ALIGN		B4_MASK
+#define BURST_LIMIT		0x0000000F	/* 3:0 */
+
+/* CTRL1			0x6C, 32bit register */
+#define SLOTMOD_MASK		0x03000000	/* 25:24 */
+#define XMTSP_MASK		0x300	/* 17:16 */
+#define XMTSP_128		0x200
+#define XMTSP_64		0x100
+#define CRTL1_DEFAULT		0x00000017
+
+/* CTRL2			0x70, 32bit register */
+#define FS_MASK			0x00070000	/* 18:16 */
+#define FMDC_MASK		0x00000300	/* 9:8 */
+#define XPHYRST			B7_MASK
+#define XPHYANE			B6_MASK
+#define XPHYFD			B5_MASK
+#define XPHYSP			B3_MASK	/* 4:3 */
+#define APDW_MASK		0x00000007	/* 2:0 */
+
+/* RCV_RING_CFG			0x78, 16bit register */
+#define RCV_DROP3		B11_MASK
+#define RCV_DROP2		B10_MASK
+#define RCV_DROP1		B9_MASK
+#define RCV_DROP0		B8_MASK
+#define RCV_RING_DEFAULT	0x0030	/* 5:4 */
+#define RCV_RING3_EN		B3_MASK
+#define RCV_RING2_EN		B2_MASK
+#define RCV_RING1_EN		B1_MASK
+#define RCV_RING0_EN		B0_MASK
+
+/* XMT_RING_LIMIT		0x7C, 32bit register */
+#define XMT_RING2_LIMIT		0x00FF0000	/* 23:16 */
+#define XMT_RING1_LIMIT		0x0000FF00	/* 15:8 */
+#define XMT_RING0_LIMIT		0x000000FF	/* 7:0 */
+
+/* AUTOPOLL0			0x88, 16bit register */
+#define AP_REG0_EN		B15_MASK
+#define AP_REG0_ADDR_MASK	0x1F00	/* 12:8 */
+#define AP_PHY0_ADDR_MASK	0x001F	/* 4:0 */
+
+/* AUTOPOLL1			0x8A, 16bit register */
+#define AP_REG1_EN		B15_MASK
+#define AP_REG1_ADDR_MASK	0x1F00	/* 12:8 */
+#define AP_PRE_SUP1		B6_MASK
+#define AP_PHY1_DFLT		B5_MASK
+#define AP_PHY1_ADDR_MASK	0x001F	/* 4:0 */
+
+/* AUTOPOLL2			0x8C, 16bit register */
+#define AP_REG2_EN		B15_MASK
+#define AP_REG2_ADDR_MASK	0x1F00	/* 12:8 */
+#define AP_PRE_SUP2		B6_MASK
+#define AP_PHY2_DFLT		B5_MASK
+#define AP_PHY2_ADDR_MASK	0x001F	/* 4:0 */
+
+/* AUTOPOLL3			0x8E, 16bit register */
+#define AP_REG3_EN		B15_MASK
+#define AP_REG3_ADDR_MASK	0x1F00	/* 12:8 */
+#define AP_PRE_SUP3		B6_MASK
+#define AP_PHY3_DFLT		B5_MASK
+#define AP_PHY3_ADDR_MASK	0x001F	/* 4:0 */
+
+/* AUTOPOLL4			0x90, 16bit register */
+#define AP_REG4_EN		B15_MASK
+#define AP_REG4_ADDR_MASK	0x1F00	/* 12:8 */
+#define AP_PRE_SUP4		B6_MASK
+#define AP_PHY4_DFLT		B5_MASK
+#define AP_PHY4_ADDR_MASK	0x001F	/* 4:0 */
+
+/* AUTOPOLL5			0x92, 16bit register */
+#define AP_REG5_EN		B15_MASK
+#define AP_REG5_ADDR_MASK	0x1F00	/* 12:8 */
+#define AP_PRE_SUP5		B6_MASK
+#define AP_PHY5_DFLT		B5_MASK
+#define AP_PHY5_ADDR_MASK	0x001F	/* 4:0 */
+
+/* AP_VALUE 			0x98, 32bit ragister */
+#define AP_VAL_ACTIVE		B31_MASK
+#define AP_VAL_RD_CMD		B29_MASK
+#define AP_ADDR			0x00070000	/* 18:16 */
+#define AP_VAL			0x0000FFFF	/* 15:0 */
+
+/* PCS_ANEG			0x9C, 32bit register */
+#define SYNC_LOST		B10_MASK
+#define IMATCH			B9_MASK
+#define CMATCH			B8_MASK
+#define PCS_AN_IDLE		B1_MASK
+#define PCS_AN_CFG		B0_MASK
+
+/* DLY_INT_A			0xA8, 32bit register */
+#define DLY_INT_A_R3		B31_MASK
+#define DLY_INT_A_R2		B30_MASK
+#define DLY_INT_A_R1		B29_MASK
+#define DLY_INT_A_R0		B28_MASK
+#define DLY_INT_A_T3		B27_MASK
+#define DLY_INT_A_T2		B26_MASK
+#define DLY_INT_A_T1		B25_MASK
+#define DLY_INT_A_T0		B24_MASK
+#define EVENT_COUNT_A		0x00FF0000	/* 20:16 */
+#define MAX_DELAY_TIME_A	0x000007FF	/* 10:0 */
+
+/* DLY_INT_B			0xAC, 32bit register */
+#define DLY_INT_B_R3		B31_MASK
+#define DLY_INT_B_R2		B30_MASK
+#define DLY_INT_B_R1		B29_MASK
+#define DLY_INT_B_R0		B28_MASK
+#define DLY_INT_B_T3		B27_MASK
+#define DLY_INT_B_T2		B26_MASK
+#define DLY_INT_B_T1		B25_MASK
+#define DLY_INT_B_T0		B24_MASK
+#define EVENT_COUNT_B		0x00FF0000	/* 20:16 */
+#define MAX_DELAY_TIME_B	0x000007FF	/* 10:0 */
+
+/* DFC_THRESH2			0xC0, 16bit register */
+#define DFC_THRESH2_HIGH	0xFF00	/* 15:8 */
+#define DFC_THRESH2_LOW		0x00FF	/* 7:0 */
+
+/* DFC_THRESH3			0xC2, 16bit register */
+#define DFC_THRESH3_HIGH	0xFF00	/* 15:8 */
+#define DFC_THRESH3_LOW		0x00FF	/* 7:0 */
+
+/* DFC_THRESH0			0xC4, 16bit register */
+#define DFC_THRESH0_HIGH	0xFF00	/* 15:8 */
+#define DFC_THRESH0_LOW		0x00FF	/* 7:0 */
+
+/* DFC_THRESH1			0xC6, 16bit register */
+#define DFC_THRESH1_HIGH	0xFF00	/* 15:8 */
+#define DFC_THRESH1_LOW		0x00FF	/* 7:0 */
+
+/* FLOW_CONTROL 		0xC8, 32bit register */
+#define PAUSE_LEN_CHG		B30_MASK
+#define	FFC_EN			B28_MASK
+#define DFC_RING3_EN		B27_MASK
+#define DFC_RING2_EN		B26_MASK
+#define DFC_RING1_EN		B25_MASK
+#define DFC_RING0_EN		B24_MASK
+#define FIXP_CONGEST		B21_MASK
+#define FPA			B20_MASK
+#define NPA			B19_MASK
+#define FIXP			B18_MASK
+#define FCPEN			B17_MASK
+#define FCCMD			B16_MASK
+#define PAUSE_LEN		0x0000FFFF	/* 15:0 */
+
+/* FFC THRESH			0xCC, 32bit register */
+#define FFC_HIGH		0xFFFF0000	/* 31:16 */
+#define FFC_LOW			0x0000FFFF	/* 15:0 */
+
+/* PHY_ ACCESS			0xD0, 32bit register */
+#define	PHY_CMD_ACTIVE		B31_MASK
+#define PHY_WR_CMD		B30_MASK
+#define PHY_RD_CMD		B29_MASK
+#define PHY_RD_ERR		B28_MASK
+#define PHY_PRE_SUP		B27_MASK
+#define PHY_ADDR		0x03E00000	/* 25:21 */
+#define PHY_REG_ADDR		0x001F0000	/* 20:16 */
+#define PHY_DATA		0x0000FFFF	/* 15:0 */
+
+/* LED0..3			0xE0..0xE6, 16bit register */
+#define LEDOUT			B15_MASK
+#define LEDPOL			B14_MASK
+#define LEDDIS			B13_MASK
+#define LEDSTRETCH		B12_MASK
+#define LED1000			B8_MASK
+#define LED100			B7_MASK
+#define LEDMP			B6_MASK
+#define LEDFD			B5_MASK
+#define LEDLINK			B4_MASK
+#define LEDRCVMAT		B3_MASK
+#define LEDXMT			B2_MASK
+#define LEDRCV			B1_MASK
+#define LEDCOLOUT		B0_MASK
+
+/* EEPROM_ACC			0x17C, 16bit register */
+#define PVALID			B15_MASK
+#define PREAD			B14_MASK
+#define EEDET			B13_MASK
+#define	EEN			B4_MASK
+#define ECS			B2_MASK
+#define EESK			B1_MASK
+#define edi_edo			b0_MASK
+
+/* PMAT0			0x190,	 32bit register */
+#define PMR_ACTIVE		B31_MASK
+#define PMR_WR_CMD		B30_MASK
+#define PMR_RD_CMD		B29_MASK
+#define PMR_BANK		B28_MASK
+#define PMR_ADDR		0x007F0000	/* 22:16 */
+#define PMR_B4			0x000000FF	/* 15:0 */
+
+/* PMAT1			0x194,	 32bit register */
+#define PMR_B3			0xFF000000	/* 31:24 */
+#define PMR_B2			0x00FF0000	/* 23:16 */
+#define PMR_B1			0x0000FF00	/* 15:8 */
+#define PMR_B0			0x000000FF	/* 7:0 */
+
+/************************************************************************/
+/*                                                                      */
+/*                      MIB counter definitions                         */
+/*                                                                      */
+/************************************************************************/
+
+#define rcv_miss_pkts				0x00
+#define rcv_octets				0x01
+#define rcv_broadcast_pkts			0x02
+#define rcv_multicast_pkts			0x03
+#define rcv_undersize_pkts			0x04
+#define rcv_oversize_pkts			0x05
+#define rcv_fragments				0x06
+#define rcv_jabbers				0x07
+#define rcv_unicast_pkts			0x08
+#define rcv_alignment_errors			0x09
+#define rcv_fcs_errors				0x0A
+#define rcv_good_octets				0x0B
+#define rcv_mac_ctrl				0x0C
+#define rcv_flow_ctrl				0x0D
+#define rcv_pkts_64_octets			0x0E
+#define rcv_pkts_65to127_octets			0x0F
+#define rcv_pkts_128to255_octets		0x10
+#define rcv_pkts_256to511_octets		0x11
+#define rcv_pkts_512to1023_octets		0x12
+#define rcv_pkts_1024to1518_octets		0x13
+#define rcv_unsupported_opcode			0x14
+#define rcv_symbol_errors			0x15
+#define rcv_drop_pkts_ring1			0x16
+#define rcv_drop_pkts_ring2			0x17
+#define rcv_drop_pkts_ring3			0x18
+#define rcv_drop_pkts_ring4			0x19
+#define rcv_jumbo_pkts				0x1A
+
+#define xmt_underrun_pkts			0x20
+#define xmt_octets				0x21
+#define xmt_packets				0x22
+#define xmt_broadcast_pkts			0x23
+#define xmt_multicast_pkts			0x24
+#define xmt_collisions				0x25
+#define xmt_unicast_pkts			0x26
+#define xmt_one_collision			0x27
+#define xmt_multiple_collision			0x28
+#define xmt_deferred_transmit			0x29
+#define xmt_late_collision			0x2A
+#define xmt_excessive_defer			0x2B
+#define xmt_loss_carrier			0x2C
+#define xmt_excessive_collision			0x2D
+#define xmt_back_pressure			0x2E
+#define xmt_flow_ctrl				0x2F
+#define xmt_pkts_64_octets			0x30
+#define xmt_pkts_65to127_octets			0x31
+#define xmt_pkts_128to255_octets		0x32
+#define xmt_pkts_256to511_octets		0x33
+#define xmt_pkts_512to1023_octets		0x34
+#define xmt_pkts_1024to1518_octet		0x35
+#define xmt_oversize_pkts			0x36
+#define xmt_jumbo_pkts				0x37
+
+
+/* Driver definitions */
+
+#define	 PCI_VENDOR_ID_AMD		0x1022
+#define  PCI_DEVICE_ID_AMD8111E_7462	0x7462
+
+#define MAX_UNITS			16 /* Maximum number of devices possible */
+
+#define NUM_TX_BUFFERS			32 /* Number of transmit buffers */
+#define NUM_RX_BUFFERS			32 /* Number of receive buffers */	
+
+#define TX_BUFF_MOD_MASK         	31 /* (NUM_TX_BUFFERS -1) */
+#define RX_BUFF_MOD_MASK         	31 /* (NUM_RX_BUFFERS -1) */
+
+#define NUM_TX_RING_DR			32  
+#define NUM_RX_RING_DR			32 
+
+#define TX_RING_DR_MOD_MASK         	31 /* (NUM_TX_RING_DR -1) */
+#define RX_RING_DR_MOD_MASK         	31 /* (NUM_RX_RING_DR -1) */
+
+#define MAX_FILTER_SIZE			64 /* Maximum multicast address */ 
+#define AMD8111E_MIN_MTU	 	60 	
+#define AMD8111E_MAX_MTU		9000			
+
+#define PKT_BUFF_SZ			1536
+#define MIN_PKT_LEN			60
+#define ETH_ADDR_LEN			6
+
+#define OPTION_VLAN_ENABLE		0x0001
+#define OPTION_JUMBO_ENABLE		0x0002
+#define OPTION_MULTICAST_ENABLE		0x0004
+#define OPTION_WOL_ENABLE		0x0008
+#define OPTION_WAKE_MAGIC_ENABLE	0x0010
+#define OPTION_WAKE_PHY_ENABLE		0x0020
+
+#define PHY_REG_ADDR_MASK		0x1f
+
+/* Assume contoller gets data 10 times the maximum processing time */
+#define  REPEAT_CNT			10; 
+     
+/* amd8111e decriptor flag definitions */
+
+#define OWN_BIT			B15_MASK
+#define ADD_FCS_BIT		B13_MASK
+#define LTINT_BIT		B12_MASK
+#define STP_BIT			B9_MASK
+#define ENP_BIT			B8_MASK
+#define KILL_BIT		B6_MASK
+#define TCC_MASK		0x0003
+#define TCC_VLAN_INSERT		B1_MASK
+#define TCC_VLAN_REPLACE	0x0003
+#define RESET_RX_FLAGS		0x0000
+
+#define ERR_BIT 		B14_MASK
+#define FRAM_BIT		B13_MASK
+#define OFLO_BIT		B12_MASK
+#define CRC_BIT			B11_MASK
+#define PAM_BIT			B6_MASK
+#define LAFM_BIT		B5_MASK
+#define BAM_BIT			B4_MASK
+#define TT_MASK			0x000c
+#define TT_VLAN_TAGGED		0x000c
+#define TT_PRTY_TAGGED		0x0008
+
+/* driver ioctl parameters */
+#define PHY_ID 			0x01	/* currently it is fixed */
+#define AMD8111E_REG_DUMP_LEN	4096	/* Memory mapped register length */
+
+/* amd8111e desriptor format */
+
+struct amd8111e_tx_dr{
+
+	u16 buff_count; /* Size of the buffer pointed by this descriptor */
+
+	u16 tx_dr_offset2;
+
+	u16 tag_ctrl_info;
+
+	u16 tag_ctrl_cmd;
+
+	u32 buff_phy_addr;
+
+	u32 reserved;
+}; 
+
+struct amd8111e_rx_dr{
+	
+	u32 reserved;
+
+	u16 msg_count; /* Received message len */
+
+	u16 tag_ctrl_info; 
+
+	u16 buff_count;  /* Len of the buffer pointed by descriptor. */
+
+	u16 rx_dr_offset10;
+
+	u32 buff_phy_addr;
+
+};
+struct amd8111e_link_config{
+
+#define SPEED_INVALID		0xffff
+#define DUPLEX_INVALID		0xff
+#define AUTONEG_INVALID		0xff
+	
+	unsigned long			orig_phy_option;
+	u16				speed;
+	u8				duplex;
+	u8				autoneg;
+	u16 				orig_speed;
+	u8				orig_duplex;
+	u8				reserved;  /* 32bit alignment */
+};
+struct amd8111e_priv{
+	
+	struct amd8111e_tx_dr*  tx_ring;
+	struct amd8111e_rx_dr* rx_ring;
+	dma_addr_t tx_ring_dma_addr;	/* tx descriptor ring base address */
+	dma_addr_t rx_ring_dma_addr;	/* rx descriptor ring base address */
+	const char *name;
+	struct pci_dev *pci_dev;	/* Ptr to the associated pci_dev */
+	struct net_device* amd8111e_net_dev; 	/* ptr to associated net_device */
+	/* Transmit and recive skbs */
+	struct sk_buff *tx_skbuff[NUM_TX_BUFFERS];
+	struct sk_buff *rx_skbuff[NUM_RX_BUFFERS];
+	/* Transmit and receive dma mapped addr */
+	dma_addr_t tx_dma_addr[NUM_TX_BUFFERS];
+	dma_addr_t rx_dma_addr[NUM_RX_BUFFERS];
+	/* Reg memory mapped address */
+	void *  mmio;
+	
+	spinlock_t lock;	/* Guard lock */
+	unsigned long  rx_idx, tx_idx;	/* The next free ring entry */
+	unsigned long  tx_complete_idx;
+	unsigned long tx_ring_complete_idx;
+	unsigned long tx_ring_idx;
+	int rx_buff_len;	/* Buffer length of rx buffers */
+	int options;		/* Options enabled/disabled for the device */
+	unsigned long ext_phy_option;
+	struct amd8111e_link_config link_config;
+	int pm_cap;
+
+	struct net_device *next;
+#if AMD8111E_VLAN_TAG_USED
+	struct vlan_group		*vlgrp;
+#endif	
+	char opened;
+	struct net_device_stats stats;
+	struct net_device_stats prev_stats;
+	struct dev_mc_list* mc_list;
+	
+};
+#define AMD8111E_READ_REG64(_memMapBase, _offset, _pUlData)	\
+			*(u32*)(_pUlData) = readl(_memMapBase + (_offset));	\
+			*((u32*)(_pUlData))+1) = readl(_memMapBase + ((_offset)+4))
+
+#define AMD8111E_WRITE_REG64(_memMapBase, _offset, _pUlData)	\
+			writel(*(u32*)(_pUlData), _memMapBase + (_offset));	\
+			writel(*(u32*)((u8*)(_pUlData)+4), _memMapBase + ((_offset)+4))	\
+
+/* maps the external speed options to internal value */
+static unsigned char speed_duplex_mapping[] = {
+
+	XPHYANE,		/* Auto-negotiation, speed_duplex option 0 */
+	0,			/* 10M Half,  speed_duplex option 1 */
+	XPHYFD,			/* 10M Full,  speed_duplex option 2 */
+	XPHYSP,			/* 100M Half, speed_duplex option 3 */
+	XPHYFD | XPHYSP		/* 100M Full, speed_duplex option 4 */
+};
+static int card_idx;
+static int speed_duplex[MAX_UNITS] = { 0, };
+
+#endif /* _AMD8111E_H */
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/apne.c linux-2.4.21-pre6/drivers/net/apne.c
--- linux-2.4.20/drivers/net/apne.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/apne.c	2003-03-26 23:49:55.000000000 +0000
@@ -113,9 +113,6 @@
 #define MANUAL_HWADDR5 0x9a
 */
 
-#define WORDSWAP(a) ( (((a)>>8)&0xff) | ((a)<<8) )
-
-
 static const char version[] =
     "apne.c:v1.1 7/10/98 Alain Malek (Alain.Malek@cryogen.ch)\n";
 
@@ -403,10 +400,9 @@
     }
 
     outb(ENISR_RDC, nic_base + NE_EN0_ISR);	/* Ack intr. */
-
-    hdr->count = WORDSWAP(hdr->count);
-
     ei_status.dmaing &= ~0x01;
+
+    le16_to_cpus(&hdr->count);
 }
 
 /* Block input and output, similar to the Crynwr packet driver.  If you
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/arcnet/com20020-pci.c linux-2.4.21-pre6/drivers/net/arcnet/com20020-pci.c
--- linux-2.4.20/drivers/net/arcnet/com20020-pci.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/arcnet/com20020-pci.c	2003-03-26 23:49:09.000000000 +0000
@@ -1,5 +1,6 @@
 /*
- * Linux ARCnet driver - COM20020 PCI support (Contemporary Controls PCI20)
+ * Linux ARCnet driver - COM20020 PCI support
+ * for Contemporary Controls PCI20 and SOHARD SH-ARC PCI with com20020 chipset
  * 
  * Written 1994-1999 by Avery Pennarun,
  *    based on an ISA version by David Woodhouse.
@@ -86,7 +87,21 @@
 	memset(lp, 0, sizeof(struct arcnet_local));
 	pci_set_drvdata(pdev, dev);
 
-	ioaddr = pci_resource_start(pdev, 2);
+	// SOHARD needs PCI base addr 4
+	if (pdev->vendor==0x10B5) {
+		BUGMSG(D_NORMAL, "SOHARD\n");
+		ioaddr = pci_resource_start(pdev, 4);
+	}
+	else {
+		BUGMSG(D_NORMAL, "Contemporary Controls\n");
+		ioaddr = pci_resource_start(pdev, 2);
+	}
+
+	// Dummy access after Reset
+	// ARCNET controller needs this access to detect bustype
+	outb(0x00,ioaddr+1);
+	inb(ioaddr+1);
+
 	dev->base_addr = ioaddr;
 	dev->irq = pdev->irq;
 	dev->dev_addr[0] = node;
@@ -152,6 +167,7 @@
 	{ 0x1571, 0xa204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT },
 	{ 0x1571, 0xa205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT },
 	{ 0x1571, 0xa206, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT },
+        { 0x10B5, 0x9050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT },
 	{0,}
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/arcnet/com20020.c linux-2.4.21-pre6/drivers/net/arcnet/com20020.c
--- linux-2.4.20/drivers/net/arcnet/com20020.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/arcnet/com20020.c	2003-03-26 23:49:25.000000000 +0000
@@ -1,6 +1,6 @@
 /*
  * Linux ARCnet driver - COM20020 chipset support
- * 
+ *
  * Written 1997 by David Woodhouse.
  * Written 1994-1999 by Avery Pennarun.
  * Written 1999 by Martin Mares <mj@ucw.cz>.
@@ -98,6 +98,9 @@
 	lp->setup = lp->clockm ? 0 : (lp->clockp << 1);
 	lp->setup2 = (lp->clockm << 4) | 8;
 
+	/* Enable P1Mode for backplane mode */
+	lp->setup = lp->setup | P1MODE;
+
 	SET_SUBADR(SUB_SETUP1);
 	outb(lp->setup, _XREG);
 
@@ -105,7 +108,7 @@
 	{
 		SET_SUBADR(SUB_SETUP2);
 		outb(lp->setup2, _XREG);
-	
+
 		/* must now write the magic "restart operation" command */
 		mdelay(1);
 		outb(0x18, _COMMAND);
@@ -183,7 +186,7 @@
 	{
 		SET_SUBADR(SUB_SETUP2);
 		outb(lp->setup2, _XREG);
-	
+
 		/* must now write the magic "restart operation" command */
 		mdelay(1);
 		outb(0x18, _COMMAND);
@@ -202,7 +205,7 @@
 		return -ENODEV;
 	}
 	/* reserve the I/O region */
-	if (request_region(ioaddr, ARCNET_TOTAL_SIZE, "arcnet (COM20020)")) {
+	if (!request_region(ioaddr, ARCNET_TOTAL_SIZE, "arcnet (COM20020)")) {
 		free_irq(dev->irq, dev);
 		return -EBUSY;
 	}
@@ -218,7 +221,7 @@
 		BUGMSG(D_NORMAL, "Using extended timeout value of %d.\n", lp->timeout);
 
 	BUGMSG(D_NORMAL, "Using CKP %d - data rate %s.\n",
-	       lp->setup >> 1, 
+	       lp->setup >> 1,
 	       clockrates[3 - ((lp->setup2 & 0xF0) >> 4) + ((lp->setup & 0x0F) >> 1)]);
 
 	if (!dev->init && register_netdev(dev)) {
@@ -230,9 +233,9 @@
 }
 
 
-/* 
+/*
  * Do a hardware reset on the card, and set up necessary registers.
- * 
+ *
  * This should be called as little as possible, because it disrupts the
  * token on the network (causes a RECON) and requires a significant delay.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/ariadne.c linux-2.4.21-pre6/drivers/net/ariadne.c
--- linux-2.4.20/drivers/net/ariadne.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/ariadne.c	2003-03-26 23:49:50.000000000 +0000
@@ -577,6 +577,7 @@
     volatile struct Am79C960 *lance = (struct Am79C960*)dev->base_addr;
     int entry;
     unsigned long flags;
+    int len = skb->len;
 
 #if 0
     if (ariadne_debug > 3) {
@@ -587,6 +588,15 @@
     }
 #endif
 
+    /* FIXME: is the 79C960 new enough to do its own padding right ? */
+    if(skb->len < ETH_ZLEN)
+    {
+    	skb = skb_padto(skb, ETH_ZLEN);
+    	if(skb == NULL)
+    	    return 0;
+    	len = ETH_ZLEN;
+    }
+
     /* Fill in a Tx ring entry */
 
 #if 0
@@ -617,8 +627,7 @@
 
     priv->tx_ring[entry]->TMD2 = swapw((u_short)-skb->len);
     priv->tx_ring[entry]->TMD3 = 0x0000;
-    memcpyw(priv->tx_buff[entry], (u_short *)skb->data,
-	    skb->len <= ETH_ZLEN ? ETH_ZLEN : skb->len);
+    memcpyw(priv->tx_buff[entry], (u_short *)skb->data, len);
 
 #if 0
     {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/at1700.c linux-2.4.21-pre6/drivers/net/at1700.c
--- linux-2.4.20/drivers/net/at1700.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/at1700.c	2003-03-26 23:49:30.000000000 +0000
@@ -311,7 +311,6 @@
 		&& inb(ioaddr + SAPROM + 2) == 0x0e)
 		is_fmv18x = 1;
 	else {
-		ret = -ENODEV;
 		goto err_out;
 	}
 			
@@ -336,11 +335,10 @@
 			}
 			if (i == 8) {
 				goto err_out;
-				ret = -ENODEV;
 			}
 		} else {
 			if (fmv18x_probe_list[inb(ioaddr + IOCONFIG) & 0x07] != ioaddr)
-				return -ENODEV;
+				goto err_out;
 			irq = fmv_irqmap[(inb(ioaddr + IOCONFIG)>>6) & 0x03];
 		}
 	}
@@ -578,7 +576,9 @@
 	struct net_local *lp = (struct net_local *) dev->priv;
 	int ioaddr = dev->base_addr;
 	short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+	short len = skb->len;
 	unsigned char *buf = skb->data;
+	static u8 pad[ETH_ZLEN];
 
 	netif_stop_queue (dev);
 
@@ -590,7 +590,17 @@
 	lp->tx_queue_ready = 0;
 	{
 		outw (length, ioaddr + DATAPORT);
-		outsw (ioaddr + DATAPORT, buf, (length + 1) >> 1);
+		/* Packet data */
+		outsw (ioaddr + DATAPORT, buf, len >> 1);
+		/* Check for dribble byte */
+		if(len & 1)
+		{
+			outw(skb->data[skb->len-1], ioaddr + DATAPORT);
+			len++;
+		}
+		/* Check for packet padding */
+		if(length != skb->len)
+			outsw(ioaddr + DATAPORT, pad, (length - len + 1) >> 1);
 
 		lp->tx_queue++;
 		lp->tx_queue_len += length + 2;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/atarilance.c linux-2.4.21-pre6/drivers/net/atarilance.c
--- linux-2.4.20/drivers/net/atarilance.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/atarilance.c	2003-03-26 23:49:18.000000000 +0000
@@ -786,6 +786,22 @@
 	DPRINTK( 2, ( "%s: lance_start_xmit() called, csr0 %4.4x.\n",
 				  dev->name, DREG ));
 
+
+	/* The old LANCE chips doesn't automatically pad buffers to min. size. */
+	len = skb->len;
+	if(len < ETH_ZLEN)
+		len = ETH_ZLEN;
+	/* PAM-Card has a bug: Can only send packets with even number of bytes! */
+	else if (lp->cardtype == PAM_CARD && (len & 1))
+		++len;
+		
+	if(len > skb->len)
+	{
+		skb = skb_padto(skb, len);
+		if(skb == NULL)
+			return 0;
+	}
+		
 	netif_stop_queue (dev);
 
 	/* Fill in a Tx ring entry */
@@ -815,11 +831,6 @@
 	 * last.
 	 */
 
-	/* The old LANCE chips doesn't automatically pad buffers to min. size. */
-	len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
-	/* PAM-Card has a bug: Can only send packets with even number of bytes! */
-	if (lp->cardtype == PAM_CARD && (len & 1))
-		++len;
 
 	head->length = -len;
 	head->misc = 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/atp.c linux-2.4.21-pre6/drivers/net/atp.c
--- linux-2.4.20/drivers/net/atp.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/atp.c	2003-03-26 23:49:35.000000000 +0000
@@ -203,7 +203,7 @@
 static unsigned short eeprom_op(long ioaddr, unsigned int cmd);
 static int net_open(struct net_device *dev);
 static void hardware_init(struct net_device *dev);
-static void write_packet(long ioaddr, int length, unsigned char *packet, int mode);
+static void write_packet(long ioaddr, int length, unsigned char *packet, int pad, int mode);
 static void trigger_send(long ioaddr, int length);
 static int	atp_send_packet(struct sk_buff *skb, struct net_device *dev);
 static void atp_interrupt(int irq, void *dev_id, struct pt_regs *regs);
@@ -500,15 +500,23 @@
 	write_reg(ioaddr, CMR1, CMR1_Xmit);
 }
 
-static void write_packet(long ioaddr, int length, unsigned char *packet, int data_mode)
+static void write_packet(long ioaddr, int length, unsigned char *packet, int pad_len, int data_mode)
 {
-    length = (length + 1) & ~1;		/* Round up to word length. */
+    if(length & 1)
+    {
+    	length++;
+    	pad_len++;
+    }
+
     outb(EOC+MAR, ioaddr + PAR_DATA);
     if ((data_mode & 1) == 0) {
 		/* Write the packet out, starting with the write addr. */
 		outb(WrAddr+MAR, ioaddr + PAR_DATA);
 		do {
 			write_byte_mode0(ioaddr, *packet++);
+		} while (--length > pad_len) ;
+		do {
+			write_byte_mode0(ioaddr, 0);
 		} while (--length > 0) ;
     } else {
 		/* Write the packet out in slow mode. */
@@ -522,8 +530,10 @@
 		outbyte >>= 4;
 		outb(outbyte & 0x0f, ioaddr + PAR_DATA);
 		outb(Ctrl_HNibWrite + Ctrl_IRQEN, ioaddr + PAR_CONTROL);
-		while (--length > 0)
+		while (--length > pad_len)
 			write_byte_mode1(ioaddr, *packet++);
+		while (--length > 0)
+			write_byte_mode1(ioaddr, 0);
     }
     /* Terminate the Tx frame.  End of write: ECB. */
     outb(0xff, ioaddr + PAR_DATA);
@@ -565,7 +575,7 @@
 	write_reg_high(ioaddr, IMR, 0);
 	spin_unlock_irqrestore(&lp->lock, flags);
 
-	write_packet(ioaddr, length, skb->data, dev->if_port);
+	write_packet(ioaddr, length, skb->data, length-skb->len, dev->if_port);
 
 	lp->pac_cnt_in_tx_buf++;
 	if (lp->tx_unit_busy == 0) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/bagetlance.c linux-2.4.21-pre6/drivers/net/bagetlance.c
--- linux-2.4.20/drivers/net/bagetlance.c	2001-10-17 04:56:29.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/bagetlance.c	2003-03-26 23:48:58.000000000 +0000
@@ -835,6 +835,19 @@
 	struct lance_tx_head *head;
 	unsigned long flags;
 
+	/* The old LANCE chips doesn't automatically pad buffers to min. size. */
+	len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
+	/* PAM-Card has a bug: Can only send packets with even number of bytes! */
+	if (lp->cardtype == PAM_CARD && (len & 1))
+		++len;
+
+	if (len > skb->len)
+	{
+		skb = skb_padto(skb, len);
+		if(skb == NULL)
+			return 0;
+	}	
+
 	/* Transmitter timeout, serious problems. */
 	if (dev->tbusy) {
 		int tickssofar = jiffies - dev->trans_start;
@@ -921,12 +934,6 @@
 	 * last.
 	 */
 
-	/* The old LANCE chips doesn't automatically pad buffers to min. size. */
-	len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
-	/* PAM-Card has a bug: Can only send packets with even number of bytes! */
-	if (lp->cardtype == PAM_CARD && (len & 1))
-		++len;
-
 	head->length = -len;
 	head->misc = 0;
 	lp->memcpy_f( PKTBUF_ADDR(head), (void *)skb->data, skb->len );
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/bmac.c linux-2.4.21-pre6/drivers/net/bmac.c
--- linux-2.4.20/drivers/net/bmac.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/bmac.c	2003-03-26 23:48:58.000000000 +0000
@@ -1401,9 +1401,7 @@
 	bp->queue = (struct sk_buff_head *)(bp->rx_cmds + N_RX_RING + 1);
 	skb_queue_head_init(bp->queue);
 
-	memset((char *) bp->tx_cmds, 0,
-	       (N_TX_RING + N_RX_RING + 2) * sizeof(struct dbdma_cmd));
-	/*     init_timer(&bp->tx_timeout); */
+	init_timer(&bp->tx_timeout);
 	/*     bp->timeout_active = 0; */
 
 	ret = request_irq(dev->irq, bmac_misc_intr, 0, "BMAC-misc", dev);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/bonding.c linux-2.4.21-pre6/drivers/net/bonding.c
--- linux-2.4.20/drivers/net/bonding.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/bonding.c	2003-03-26 23:49:29.000000000 +0000
@@ -177,20 +177,91 @@
  *     - Port Gleb Natapov's multicast support patchs from 2.4.12
  *       to 2.4.18 adding support for multicast.
  *
- * 2002/06/17 - Tony Cureington <tony.cureington * hp_com>
+ * 2002/06/10 - Tony Cureington <tony.cureington * hp_com>
  *     - corrected uninitialized pointer (ifr.ifr_data) in bond_check_dev_link;
- *       actually changed function to use ETHTOOL, then MIIPHY, and finally
- *       MIIREG to determine the link status
+ *       actually changed function to use MIIPHY, then MIIREG, and finally
+ *       ETHTOOL to determine the link status
  *     - fixed bad ifr_data pointer assignments in bond_ioctl
  *     - corrected mode 1 being reported as active-backup in bond_get_info;
  *       also added text to distinguish type of load balancing (rr or xor)
  *     - change arp_ip_target module param from "1-12s" (array of 12 ptrs)
  *       to "s" (a single ptr)
  *
+ * 2002/08/30 - Jay Vosburgh <fubar at us dot ibm dot com>
+ *     - Removed acquisition of xmit_lock in set_multicast_list; caused
+ *       deadlock on SMP (lock is held by caller).
+ *     - Revamped SIOCGMIIPHY, SIOCGMIIREG portion of bond_check_dev_link().
+ *
  * 2002/09/18 - Jay Vosburgh <fubar at us dot ibm dot com>
  *     - Fixed up bond_check_dev_link() (and callers): removed some magic
  *	 numbers, banished local MII_ defines, wrapped ioctl calls to
  *	 prevent EFAULT errors
+ *
+ * 2002/9/30 - Jay Vosburgh <fubar at us dot ibm dot com>
+ *     - make sure the ip target matches the arp_target before saving the
+ *	 hw address.
+ *
+ * 2002/9/30 - Dan Eisner <eisner at 2robots dot com>
+ *     - make sure my_ip is set before taking down the link, since
+ *	 not all switches respond if the source ip is not set.
+ *
+ * 2002/10/8 - Janice Girouard <girouard at us dot ibm dot com>
+ *     - read in the local ip address when enslaving a device
+ *     - add primary support
+ *     - make sure 2*arp_interval has passed when a new device
+ *       is brought on-line before taking it down.
+ *
+ * 2002/09/11 - Philippe De Muyter <phdm at macqel dot be>
+ *     - Added bond_xmit_broadcast logic.
+ *     - Added bond_mode() support function.
+ *
+ * 2002/10/26 - Laurent Deniel <laurent.deniel at free.fr>
+ *     - allow to register multicast addresses only on active slave
+ *       (useful in active-backup mode)
+ *     - add multicast module parameter
+ *     - fix deletion of multicast groups after unloading module
+ *
+ * 2002/11/06 - Kameshwara Rayaprolu <kameshwara.rao * wipro_com>
+ *     - Changes to prevent panic from closing the device twice; if we close 
+ *       the device in bond_release, we must set the original_flags to down 
+ *       so it won't be closed again by the network layer.
+ *
+ * 2002/11/07 - Tony Cureington <tony.cureington * hp_com>
+ *     - Fix arp_target_hw_addr memory leak
+ *     - Created activebackup_arp_monitor function to handle arp monitoring 
+ *       in active backup mode - the bond_arp_monitor had several problems... 
+ *       such as allowing slaves to tx arps sequentially without any delay 
+ *       for a response
+ *     - Renamed bond_arp_monitor to loadbalance_arp_monitor and re-wrote
+ *       this function to just handle arp monitoring in load-balancing mode;
+ *       it is a lot more compact now
+ *     - Changes to ensure one and only one slave transmits in active-backup 
+ *       mode
+ *     - Robustesize parameters; warn users about bad combinations of 
+ *       parameters; also if miimon is specified and a network driver does 
+ *       not support MII or ETHTOOL, inform the user of this
+ *     - Changes to support link_failure_count when in arp monitoring mode
+ *     - Fix up/down delay reported in /proc
+ *     - Added version; log version; make version available from "modinfo -d"
+ *     - Fixed problem in bond_check_dev_link - if the first IOCTL (SIOCGMIIPH)
+ *	 failed, the ETHTOOL ioctl never got a chance
+ *
+ * 2002/11/16 - Laurent Deniel <laurent.deniel at free.fr>
+ *     - fix multicast handling in activebackup_arp_monitor
+ *     - remove one unnecessary and confusing current_slave == slave test 
+ *	 in activebackup_arp_monitor
+ *
+ *  2002/11/17 - Laurent Deniel <laurent.deniel at free.fr>
+ *     - fix bond_slave_info_query when slave_id = num_slaves
+ *
+ *  2002/11/19 - Janice Girouard <girouard at us dot ibm dot com>
+ *     - correct ifr_data reference.  Update ifr_data reference
+ *       to mii_ioctl_data struct values to avoid confusion.
+ *
+ *
+ *  2002/11/22 - Bert Barbe <bert.barbe at oracle dot com>
+ *      - Add support for multiple arp_ip_target
+ *
  */
 
 #include <linux/config.h>
@@ -203,6 +274,7 @@
 #include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
+#include <linux/ip.h>
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/init.h>
@@ -216,6 +288,7 @@
 #include <linux/errno.h>
 
 #include <linux/netdevice.h>
+#include <linux/inetdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
@@ -228,6 +301,13 @@
 #include <linux/mii.h>
 #include <linux/ethtool.h>
 
+#define DRV_VERSION		"2.4.20-20021210"
+#define DRV_RELDATE		"December 10, 2002"
+#define DRV_NAME		"bonding"
+#define DRV_DESCRIPTION		"Ethernet Channel Bonding Driver"
+
+static const char *version =
+DRV_NAME ".c:v" DRV_VERSION " (" DRV_RELDATE ")\n";
 
 /* monitor all links that often (in milliseconds). <=0 disables monitoring */
 #ifndef BOND_LINK_MON_INTERV
@@ -238,20 +318,31 @@
 #define BOND_LINK_ARP_INTERV	0
 #endif
 
+#ifndef MAX_ARP_IP_TARGETS
+#define MAX_ARP_IP_TARGETS 16
+#endif
+
 static int arp_interval = BOND_LINK_ARP_INTERV;
-static char *arp_ip_target = NULL;
-static unsigned long arp_target = 0;
+static char *arp_ip_target[MAX_ARP_IP_TARGETS] = { NULL, };
+static unsigned long arp_target[MAX_ARP_IP_TARGETS] = { 0, } ;
+static int arp_ip_count = 0;
 static u32 my_ip = 0;
 char *arp_target_hw_addr = NULL;
 
+static char *primary= NULL;
+
 static int max_bonds	= BOND_DEFAULT_MAX_BONDS;
 static int miimon	= BOND_LINK_MON_INTERV;
 static int mode		= BOND_MODE_ROUNDROBIN;
 static int updelay	= 0;
 static int downdelay	= 0;
 
+#define BOND_MULTICAST_DISABLED 0
+#define BOND_MULTICAST_ACTIVE   1
+#define BOND_MULTICAST_ALL      2
+static int multicast    = BOND_MULTICAST_ALL;
+
 static int first_pass	= 1;
-int bond_cnt;
 static struct bonding *these_bonds =  NULL;
 static struct net_device *dev_bonds = NULL;
 
@@ -262,13 +353,17 @@
 MODULE_PARM(mode, "i");
 MODULE_PARM(arp_interval, "i");
 MODULE_PARM_DESC(arp_interval, "arp interval in milliseconds");
-MODULE_PARM(arp_ip_target, "s");
-MODULE_PARM_DESC(arp_ip_target, "arp target in n.n.n.n form");
+MODULE_PARM(arp_ip_target, "1-" __MODULE_STRING(MAX_ARP_IP_TARGETS) "s");
+MODULE_PARM_DESC(arp_ip_target, "arp targets in n.n.n.n form");
 MODULE_PARM_DESC(mode, "Mode of operation : 0 for round robin, 1 for active-backup, 2 for xor");
 MODULE_PARM(updelay, "i");
 MODULE_PARM_DESC(updelay, "Delay before considering link up, in milliseconds");
 MODULE_PARM(downdelay, "i");
 MODULE_PARM_DESC(downdelay, "Delay before considering link down, in milliseconds");
+MODULE_PARM(primary, "s");
+MODULE_PARM_DESC(primary, "Primary network device to use");
+MODULE_PARM(multicast, "i");
+MODULE_PARM_DESC(multicast, "Mode for multicast support : 0 for none, 1 for active slave, 2 for all slaves (default)");
 
 extern void arp_send( int type, int ptype, u32 dest_ip, struct net_device *dev,
 	u32 src_ip, unsigned char *dest_hw, unsigned char *src_hw, 
@@ -279,7 +374,8 @@
 static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *dev);
 static struct net_device_stats *bond_get_stats(struct net_device *dev);
 static void bond_mii_monitor(struct net_device *dev);
-static void bond_arp_monitor(struct net_device *dev);
+static void loadbalance_arp_monitor(struct net_device *dev);
+static void activebackup_arp_monitor(struct net_device *dev);
 static int bond_event(struct notifier_block *this, unsigned long event, void *ptr);
 static void bond_restore_slave_flags(slave_t *slave);
 static void bond_mc_list_destroy(struct bonding *bond);
@@ -290,6 +386,7 @@
 static void bond_set_promiscuity(bonding_t *bond, int inc);
 static void bond_set_allmulti(bonding_t *bond, int inc);
 static struct dev_mc_list* bond_mc_list_find_dmi(struct dev_mc_list *dmi, struct dev_mc_list *mc_list);
+static void bond_mc_update(bonding_t *bond, slave_t *new, slave_t *old);
 static void bond_set_slave_inactive_flags(slave_t *slave);
 static void bond_set_slave_active_flags(slave_t *slave);
 static int bond_enslave(struct net_device *master, struct net_device *slave);
@@ -311,6 +408,47 @@
 
 #define IS_UP(dev)	((((dev)->flags & (IFF_UP)) == (IFF_UP)) && \
 			(netif_running(dev) && netif_carrier_ok(dev)))
+  
+static void arp_send_all(slave_t *slave)
+{	
+  int i; 
+  for ( i=0; (i<MAX_ARP_IP_TARGETS) && arp_target[i]; i++) { 
+    arp_send(ARPOP_REQUEST, ETH_P_ARP, arp_target[i], slave->dev, 
+	     my_ip, arp_target_hw_addr, slave->dev->dev_addr,
+	     arp_target_hw_addr); 
+  } 
+}
+ 
+
+static const char *bond_mode(void)
+{
+	switch (mode) {
+	case BOND_MODE_ROUNDROBIN :
+		return "load balancing (round-robin)";
+	case BOND_MODE_ACTIVEBACKUP :
+		return "fault-tolerance (active-backup)";
+	case BOND_MODE_XOR :
+		return "load balancing (xor)";
+	case BOND_MODE_BROADCAST :
+		return "fault-tolerance (broadcast)";
+	default :
+		return "unknown";
+	}
+}
+
+static const char *multicast_mode(void)
+{
+	switch(multicast) {
+	case BOND_MULTICAST_DISABLED :
+		return "disabled";
+	case BOND_MULTICAST_ACTIVE :
+		return "active slave only";
+	case BOND_MULTICAST_ALL :
+		return "all slaves";
+	default :
+		return "unknown";
+	}
+}
 
 static void bond_restore_slave_flags(slave_t *slave)
 {
@@ -418,11 +556,24 @@
 		/*       call it and not the others for that team          */
 		/*       member.                                           */
 
-		/* try SOICETHTOOL ioctl, some drivers cache ETHTOOL_GLINK */
-		/* for a period of time; we need to encourage link status  */
-		/* be reported by network drivers in real time; if the     */
-		/* value is cached, the mmimon module parm may have no     */
-		/* effect...                                               */
+		/*
+		 * We cannot assume that SIOCGMIIPHY will also read a
+		 * register; not all network drivers (e.g., e100)
+		 * support that.
+		 */
+
+		/* Yes, the mii is overlaid on the ifreq.ifr_ifru */
+		mii = (struct mii_ioctl_data *)&ifr.ifr_data;
+		if (IOCTL(dev, &ifr, SIOCGMIIPHY) == 0) {
+			mii->reg_num = MII_BMSR;
+			if (IOCTL(dev, &ifr, SIOCGMIIREG) == 0) {
+				return mii->val_out & BMSR_LSTATUS;
+			}
+		}
+
+		/* try SIOCETHTOOL ioctl, some drivers cache ETHTOOL_GLINK */
+		/* for a period of time so we attempt to get link status   */
+		/* from it last if the above MII ioctls fail...            */
 	        etool.cmd = ETHTOOL_GLINK;
 	        ifr.ifr_data = (char*)&etool;
 		if (IOCTL(dev, &ifr, SIOCETHTOOL) == 0) {
@@ -430,26 +581,14 @@
 				return BMSR_LSTATUS;
 			} 
 			else { 
+#ifdef BONDING_DEBUG
+				printk(KERN_INFO 
+					":: SIOCETHTOOL shows failure \n");
+#endif
 				return(0);
 			} 
 		}
 
-		/*
-		 * We cannot assume that SIOCGMIIPHY will also read a
-		 * register; not all network drivers support that.
-		 */
-
-		/* Yes, the mii is overlaid on the ifreq.ifr_ifru */
-		mii = (struct mii_ioctl_data *)&ifr.ifr_data;
-		if (IOCTL(dev, &ifr, SIOCGMIIPHY) != 0) {
-			return BMSR_LSTATUS;	 /* can't tell */
-		}
-
-		mii->reg_num = MII_BMSR;
-		if (IOCTL(dev, &ifr, SIOCGMIIREG) == 0) {
-			return mii->val_out & BMSR_LSTATUS;
-		}
-
 	}
 	return BMSR_LSTATUS;  /* spoof link up ( we can't check it) */
 }
@@ -486,7 +625,11 @@
 		init_timer(arp_timer);
 		arp_timer->expires  = jiffies + (arp_interval * HZ / 1000);
 		arp_timer->data     = (unsigned long)dev;
-		arp_timer->function = (void *)&bond_arp_monitor;
+		if (mode == BOND_MODE_ACTIVEBACKUP) {
+			arp_timer->function = (void *)&activebackup_arp_monitor;
+		} else {
+			arp_timer->function = (void *)&loadbalance_arp_monitor;
+		}
 		add_timer(arp_timer);
 	}
 	return 0;
@@ -504,6 +647,10 @@
 	}
 	if (arp_interval> 0) {  /* arp interval, in milliseconds. */
 		del_timer(&bond->arp_timer);
+                if (arp_target_hw_addr != NULL) {
+			kfree(arp_target_hw_addr); 
+			arp_target_hw_addr = NULL;
+		}
 	}
 
 	/* Release the bonded slaves */
@@ -548,9 +695,18 @@
 static void bond_mc_add(bonding_t *bond, void *addr, int alen)
 { 
 	slave_t *slave;
-
-	for (slave = bond->prev; slave != (slave_t*)bond; slave = slave->prev) {
-		dev_mc_add(slave->dev, addr, alen, 0);
+	switch (multicast) {
+	case BOND_MULTICAST_ACTIVE :
+		/* write lock already acquired */
+		if (bond->current_slave != NULL)
+			dev_mc_add(bond->current_slave->dev, addr, alen, 0);
+		break;
+	case BOND_MULTICAST_ALL :
+		for (slave = bond->prev; slave != (slave_t*)bond; slave = slave->prev)
+			dev_mc_add(slave->dev, addr, alen, 0);
+		break;
+	case BOND_MULTICAST_DISABLED :
+		break;
 	}
 } 
 
@@ -560,9 +716,19 @@
 static void bond_mc_delete(bonding_t *bond, void *addr, int alen)
 { 
 	slave_t *slave; 
-
-	for (slave = bond->prev; slave != (slave_t*)bond; slave = slave->prev)
-		dev_mc_delete(slave->dev, addr, alen, 0);
+	switch (multicast) {
+	case BOND_MULTICAST_ACTIVE :
+		/* write lock already acquired */
+		if (bond->current_slave != NULL)
+			dev_mc_delete(bond->current_slave->dev, addr, alen, 0);
+		break;
+	case BOND_MULTICAST_ALL :
+		for (slave = bond->prev; slave != (slave_t*)bond; slave = slave->prev)
+			dev_mc_delete(slave->dev, addr, alen, 0);
+		break;
+	case BOND_MULTICAST_DISABLED :
+		break;
+	}
 } 
 
 /*
@@ -606,9 +772,19 @@
 static void bond_set_promiscuity(bonding_t *bond, int inc)
 { 
 	slave_t *slave; 
- 
-	for (slave = bond->prev; slave != (slave_t*)bond; slave = slave->prev)
-		dev_set_promiscuity(slave->dev, inc);
+	switch (multicast) {
+	case BOND_MULTICAST_ACTIVE :
+		/* write lock already acquired */
+		if (bond->current_slave != NULL)
+			dev_set_promiscuity(bond->current_slave->dev, inc);
+		break;
+	case BOND_MULTICAST_ALL :
+		for (slave = bond->prev; slave != (slave_t*)bond; slave = slave->prev)
+			dev_set_promiscuity(slave->dev, inc);
+		break;
+	case BOND_MULTICAST_DISABLED :
+		break;
+	}
 } 
 
 /*
@@ -617,9 +793,19 @@
 static void bond_set_allmulti(bonding_t *bond, int inc)
 { 
 	slave_t *slave; 
- 
-	for (slave = bond->prev; slave != (slave_t*)bond; slave = slave->prev)
-		dev_set_allmulti(slave->dev, inc);
+	switch (multicast) {
+	case BOND_MULTICAST_ACTIVE : 
+		/* write lock already acquired */
+		if (bond->current_slave != NULL)
+			dev_set_allmulti(bond->current_slave->dev, inc);
+		break;
+	case BOND_MULTICAST_ALL :
+		for (slave = bond->prev; slave != (slave_t*)bond; slave = slave->prev)
+			dev_set_allmulti(slave->dev, inc);
+		break;
+	case BOND_MULTICAST_DISABLED :
+		break;
+	}
 } 
 
 /* 
@@ -644,6 +830,8 @@
 	struct dev_mc_list *dmi;
 	unsigned long flags = 0;
 
+	if (multicast == BOND_MULTICAST_DISABLED)
+		return;
 	/*
 	 * Lock the private data for the master
 	 */
@@ -686,7 +874,44 @@
 }
 
 /*
- * This function counts the the number of attached 
+ * Update the mc list and multicast-related flags for the new and 
+ * old active slaves (if any) according to the multicast mode
+ */
+static void bond_mc_update(bonding_t *bond, slave_t *new, slave_t *old)
+{
+	struct dev_mc_list *dmi;
+
+	switch(multicast) {
+	case BOND_MULTICAST_ACTIVE :		
+		if (bond->device->flags & IFF_PROMISC) {
+			if (old != NULL && new != old)
+				dev_set_promiscuity(old->dev, -1);
+			dev_set_promiscuity(new->dev, 1);
+		}
+		if (bond->device->flags & IFF_ALLMULTI) {
+			if (old != NULL && new != old)
+				dev_set_allmulti(old->dev, -1);
+			dev_set_allmulti(new->dev, 1);
+		}
+		/* first remove all mc addresses from old slave if any,
+		   and _then_ add them to new active slave */
+		if (old != NULL && new != old) {
+			for (dmi = bond->device->mc_list; dmi != NULL; dmi = dmi->next)
+				dev_mc_delete(old->dev, dmi->dmi_addr, dmi->dmi_addrlen, 0);
+		}
+		for (dmi = bond->device->mc_list; dmi != NULL; dmi = dmi->next)
+			dev_mc_add(new->dev, dmi->dmi_addr, dmi->dmi_addrlen, 0);
+		break;
+	case BOND_MULTICAST_ALL :
+		/* nothing to do: mc list is already up-to-date on all slaves */
+		break;
+	case BOND_MULTICAST_DISABLED :
+		break;
+	}
+}
+
+/*
+ * This function counts the number of attached 
  * slaves for use by bond_xmit_xor.
  */
 static void update_slave_cnt(bonding_t *bond)
@@ -706,9 +931,16 @@
 	bonding_t *bond = NULL;
 	slave_t *new_slave = NULL;
 	unsigned long flags = 0;
+	unsigned long rflags = 0;
 	int ndx = 0;
 	int err = 0;
 	struct dev_mc_list *dmi;
+	struct in_ifaddr **ifap;
+	struct in_ifaddr *ifa;
+	static int (* ioctl)(struct net_device *, struct ifreq *, int);
+	struct ifreq ifr;
+	struct ethtool_value etool; 
+	int link_reporting = 0;
 
 	if (master_dev == NULL || slave_dev == NULL) {
 		return -ENODEV;
@@ -761,17 +993,19 @@
 
 	new_slave->dev = slave_dev;
 
-	/* set promiscuity level to new slave */ 
-	if (master_dev->flags & IFF_PROMISC)
-		dev_set_promiscuity(slave_dev, 1); 
+	if (multicast == BOND_MULTICAST_ALL) {
+		/* set promiscuity level to new slave */ 
+		if (master_dev->flags & IFF_PROMISC)
+			dev_set_promiscuity(slave_dev, 1); 
  
-	/* set allmulti level to new slave */
-	if (master_dev->flags & IFF_ALLMULTI) 
-		dev_set_allmulti(slave_dev, 1); 
- 
-	/* upload master's mc_list to new slave */ 
-	for (dmi = master_dev->mc_list; dmi != NULL; dmi = dmi->next) 
-		dev_mc_add (slave_dev, dmi->dmi_addr, dmi->dmi_addrlen, 0);
+		/* set allmulti level to new slave */
+		if (master_dev->flags & IFF_ALLMULTI) 
+			dev_set_allmulti(slave_dev, 1); 
+		
+		/* upload master's mc_list to new slave */ 
+		for (dmi = master_dev->mc_list; dmi != NULL; dmi = dmi->next) 
+			dev_mc_add (slave_dev, dmi->dmi_addr, dmi->dmi_addrlen, 0);
+	}
 
 	/* 
 	 * queue to the end of the slaves list, make the first element its
@@ -802,6 +1036,56 @@
 	new_slave->delay = 0;
 	new_slave->link_failure_count = 0;
 
+	if (miimon > 0) {
+		/* if the network driver for the slave does not support
+		 * ETHTOOL/MII link status reporting, warn the user of this
+		 */
+		if ((ioctl = slave_dev->do_ioctl) != NULL) {
+			etool.cmd = ETHTOOL_GLINK;
+	        	ifr.ifr_data = (char*)&etool;
+			if (IOCTL(slave_dev, &ifr, SIOCETHTOOL) == 0) {
+				link_reporting = 1;
+			}
+			else {
+				if (IOCTL(slave_dev, &ifr, SIOCGMIIPHY) == 0) {
+		                        /* Yes, the mii is overlaid on the
+					 * ifreq.ifr_ifru
+					 */
+					((struct mii_ioctl_data*)
+					 (&ifr.ifr_data))->reg_num = 1;
+					if (IOCTL(slave_dev, &ifr, SIOCGMIIREG)
+						       			== 0) {
+	                                	link_reporting = 1;
+					}
+				}
+			}
+		}
+
+		if ((link_reporting == 0) && (arp_interval == 0)) {
+			/* miimon is set but a bonded network driver does
+			 * not support ETHTOOL/MII and arp_interval is
+			 * not set
+			 */ 
+			printk(KERN_ERR
+				"bond_enslave(): MII and ETHTOOL support not "
+				"available for interface %s, and "
+				"arp_interval/arp_ip_target module parameters "
+		       		"not specified, thus bonding will not detect "
+				"link failures! see bonding.txt for details.\n",
+		       		slave_dev->name);
+		}
+		else if (link_reporting == 0) {
+			/* unable  get link status using mii/ethtool */
+			printk(KERN_WARNING 
+			       "bond_enslave: can't get link status from "
+			       "interface %s; the network driver associated "
+			       "with this interface does not support "
+			       "MII or ETHTOOL link status reporting, thus "
+			       "miimon has no effect on this interface.\n", 
+			       slave_dev->name);
+		}
+	}
+
 	/* check for initial state */
 	if ((miimon <= 0) ||
 	    (bond_check_dev_link(slave_dev) == BMSR_LSTATUS)) {
@@ -809,6 +1093,7 @@
 		printk(KERN_CRIT "Initial state of slave_dev is BOND_LINK_UP\n");
 #endif
 		new_slave->link  = BOND_LINK_UP;
+		new_slave->jiffies = jiffies;
 	}
 	else {
 #ifdef BONDING_DEBUG
@@ -835,6 +1120,7 @@
 			   is OK, so make this interface the active one */
 			bond->current_slave = new_slave;
 			bond_set_slave_active_flags(new_slave);
+			bond_mc_update(bond, new_slave, NULL);
 		}
 		else {
 #ifdef BONDING_DEBUG
@@ -842,15 +1128,24 @@
 #endif
 			bond_set_slave_inactive_flags(new_slave);
 		}
+		read_lock_irqsave(&(((struct in_device *)slave_dev->ip_ptr)->lock), rflags);
+		ifap= &(((struct in_device *)slave_dev->ip_ptr)->ifa_list);
+		ifa = *ifap;
+		my_ip = ifa->ifa_address;
+		read_unlock_irqrestore(&(((struct in_device *)slave_dev->ip_ptr)->lock), rflags);
+
+		/* if there is a primary slave, remember it */
+		if (primary != NULL)
+		  if( strcmp(primary, new_slave->dev->name) == 0) 
+			bond->primary_slave = new_slave;
 	} else {
 #ifdef BONDING_DEBUG
 		printk(KERN_CRIT "This slave is always active in trunk mode\n");
 #endif
 		/* always active in trunk mode */
 		new_slave->state = BOND_STATE_ACTIVE;
-		if (bond->current_slave == NULL) {
+		if (bond->current_slave == NULL) 
 			bond->current_slave = new_slave;
-		}
 	}
 
 	update_slave_cnt(bond);
@@ -941,6 +1236,7 @@
 	    IS_UP(newactive->dev)) {
 		bond_set_slave_inactive_flags(oldactive);
 		bond_set_slave_active_flags(newactive);
+		bond_mc_update(bond, newactive, oldactive);
 		bond->current_slave = newactive;
 		printk("%s : activate %s(old : %s)\n",
 			master_dev->name, newactive->dev->name, 
@@ -981,6 +1277,7 @@
 			newslave = bond->current_slave = bond->next;
 			write_unlock(&bond->ptrlock);
 		} else {
+
 			printk (" but could not find any %s interface.\n",
 				(mode == BOND_MODE_ACTIVEBACKUP) ? "backup":"other");
 			write_lock(&bond->ptrlock);
@@ -988,16 +1285,38 @@
 			write_unlock(&bond->ptrlock);
 			return NULL; /* still no slave, return NULL */
 		}
+	} else if (mode == BOND_MODE_ACTIVEBACKUP) {
+		/* make sure oldslave doesn't send arps - this could
+		 * cause a ping-pong effect between interfaces since they
+		 * would be able to tx arps - in active backup only one
+		 * slave should be able to tx arps, and that should be
+		 * the current_slave; the only exception is when all
+		 * slaves have gone down, then only one non-current slave can
+		 * send arps at a time; clearing oldslaves' mc list is handled
+		 * later in this function.
+		 */
+		bond_set_slave_inactive_flags(oldslave);
 	}
 
 	mintime = updelay;
 
+	/* first try the primary link; if arping, a link must tx/rx traffic 
+	 * before it can be considered the current_slave - also, we would skip 
+	 * slaves between the current_slave and primary_slave that may be up 
+	 * and able to arp
+	 */
+	if ((bond->primary_slave != NULL) && (arp_interval == 0)) {
+		if (IS_UP(bond->primary_slave->dev)) 
+			newslave = bond->primary_slave;
+	}
+
 	do {
 		if (IS_UP(newslave->dev)) {
 			if (newslave->link == BOND_LINK_UP) {
 				/* this one is immediately usable */
 				if (mode == BOND_MODE_ACTIVEBACKUP) {
 					bond_set_slave_active_flags(newslave);
+					bond_mc_update(bond, newslave, oldslave);
 					printk (" and making interface %s the active one.\n",
 						newslave->dev->name);
 				}
@@ -1033,14 +1352,30 @@
 
 		bestslave->delay = 0;
 		bestslave->link = BOND_LINK_UP;
+		bestslave->jiffies = jiffies;
 		bond_set_slave_active_flags(bestslave);
-
+		bond_mc_update(bond, bestslave, oldslave);
 		write_lock(&bond->ptrlock);
 		bond->current_slave = bestslave;
 		write_unlock(&bond->ptrlock);
 		return bestslave;
 	}
 
+	if ((mode == BOND_MODE_ACTIVEBACKUP) &&
+	    (multicast == BOND_MULTICAST_ACTIVE) &&
+	    (oldslave != NULL)) {
+		/* flush bonds (master's) mc_list from oldslave since it wasn't
+		 * updated (and deleted) above
+		 */ 
+		bond_mc_list_flush(oldslave->dev, bond->device); 
+		if (bond->device->flags & IFF_PROMISC) {
+			dev_set_promiscuity(oldslave->dev, -1);
+		}
+		if (bond->device->flags & IFF_ALLMULTI) {
+			dev_set_allmulti(oldslave->dev, -1);
+		}
+	}
+
 	printk (" but could not find any %s interface.\n",
 		(mode == BOND_MODE_ACTIVEBACKUP) ? "backup":"other");
 	
@@ -1084,6 +1419,7 @@
 		return -EINVAL;
 	}
 
+	bond->current_arp_slave = NULL;
 	our_slave = (slave_t *)bond;
 	old_current = bond->current_slave;
 	while ((our_slave = our_slave->prev) != (slave_t *)bond) {
@@ -1104,16 +1440,18 @@
 
 			/* release the slave from its bond */
 
-			/* flush master's mc_list from slave */ 
-			bond_mc_list_flush (slave, master); 
-       
-			/* unset promiscuity level from slave */
-			if (master->flags & IFF_PROMISC) 
-				dev_set_promiscuity(slave, -1); 
+			if (multicast == BOND_MULTICAST_ALL) {
+				/* flush master's mc_list from slave */ 
+				bond_mc_list_flush (slave, master); 
+				
+				/* unset promiscuity level from slave */
+				if (master->flags & IFF_PROMISC) 
+					dev_set_promiscuity(slave, -1); 
        
-			/* unset allmulti level from slave */ 
-			if (master->flags & IFF_ALLMULTI)
-				dev_set_allmulti(slave, -1); 
+				/* unset allmulti level from slave */ 
+				if (master->flags & IFF_ALLMULTI)
+					dev_set_allmulti(slave, -1); 
+			}
 
 			netdev_set_master(slave, NULL);
 
@@ -1125,6 +1463,7 @@
 			if (slave->flags & IFF_NOARP || 
 				bond->current_slave != NULL) {
 					dev_close(slave);
+					our_slave->original_flags &= ~IFF_UP;
 			}
 
 			bond_restore_slave_flags(our_slave);
@@ -1138,6 +1477,10 @@
 
 			update_slave_cnt(bond);
 
+			if (bond->primary_slave == our_slave) {
+				bond->primary_slave = NULL;
+			}
+
 			write_unlock_irqrestore(&bond->lock, flags);
 			return 0;  /* deletion OK */
 		}
@@ -1169,12 +1512,28 @@
 	}
 
 	bond = (struct bonding *) master->priv;
-	bond->current_slave = NULL;
+	bond->current_arp_slave = NULL;
 
 	while ((our_slave = bond->prev) != (slave_t *)bond) {
 		slave_dev = our_slave->dev;
 		bond->prev = our_slave->prev;
 
+		if (multicast == BOND_MULTICAST_ALL 
+		    || (multicast == BOND_MULTICAST_ACTIVE 
+			&& bond->current_slave == our_slave)) {
+
+			/* flush master's mc_list from slave */ 
+			bond_mc_list_flush (slave_dev, master); 
+			
+			/* unset promiscuity level from slave */
+			if (master->flags & IFF_PROMISC) 
+				dev_set_promiscuity(slave_dev, -1); 
+			
+			/* unset allmulti level from slave */ 
+			if (master->flags & IFF_ALLMULTI)
+				dev_set_allmulti(slave_dev, -1); 
+		}
+
 		kfree(our_slave);
 
 		netdev_set_master(slave_dev, NULL);
@@ -1186,9 +1545,12 @@
 		if (slave_dev->flags & IFF_NOARP)
 			dev_close(slave_dev);
 	}
+
+	bond->current_slave = NULL;
 	bond->next = (slave_t *)bond;
 	bond->slave_cnt = 0;
-	printk (KERN_INFO "%s: releases all slaves\n", master->name);
+	bond->primary_slave = NULL;
+	printk (KERN_INFO "%s: released all slaves\n", master->name);
 
 	return 0;
 }
@@ -1294,6 +1656,7 @@
 			} else {
 				/* link up again */
 				slave->link  = BOND_LINK_UP;
+				slave->jiffies = jiffies;
 				printk(KERN_INFO
 					"%s: link status up again after %d ms "
 					"for interface %s.\n",
@@ -1346,8 +1709,10 @@
 				if (slave->delay == 0) {
 					/* now the link has been up for long time enough */
 					slave->link = BOND_LINK_UP;
+					slave->jiffies = jiffies;
 
-					if (mode == BOND_MODE_ACTIVEBACKUP) {
+					if ( (mode == BOND_MODE_ACTIVEBACKUP) 
+					 || (slave != bond->primary_slave) ) {
 						/* prevent it from being the active one */
 						slave->state = BOND_STATE_BACKUP;
 					}
@@ -1361,15 +1726,26 @@
 						"for interface %s.\n",
 						master->name,
 						dev->name);
+	
+					if ( (bond->primary_slave != NULL)	 
+					  && (slave == bond->primary_slave) )
+						change_active_interface(bond); 
 				}
 				else
 					slave->delay--;
 				
 				/* we'll also look for the mostly eligible slave */
-				if (IS_UP(dev) && (slave->delay < mindelay)) {
+				if (bond->primary_slave == NULL)  {
+				    if (IS_UP(dev) && (slave->delay < mindelay)) {
+					mindelay = slave->delay;
+					bestslave = slave;
+				    } 
+				} else if ( (IS_UP(bond->primary_slave->dev))  || 
+				          ( (!IS_UP(bond->primary_slave->dev))  && 
+				          (IS_UP(dev) && (slave->delay < mindelay)) ) ) {
 					mindelay = slave->delay;
 					bestslave = slave;
-				} 
+				}
 			}
 			break;
 		} /* end of switch */
@@ -1383,7 +1759,8 @@
 	oldcurrent = bond->current_slave;
 	read_unlock(&bond->ptrlock);
 
-	if (oldcurrent == NULL) {  /* no active interface at the moment */
+	/* no active interface at the moment or need to bring up the primary */
+	if (oldcurrent == NULL)  { /* no active interface at the moment */
 		if (bestslave != NULL) { /* last chance to find one ? */
 			if (bestslave->link == BOND_LINK_UP) {
 				printk (KERN_INFO
@@ -1398,10 +1775,12 @@
 
 				bestslave->delay = 0;
 				bestslave->link  = BOND_LINK_UP;
+				bestslave->jiffies = jiffies;
 			}
 
 			if (mode == BOND_MODE_ACTIVEBACKUP) {
 				bond_set_slave_active_flags(bestslave);
+				bond_mc_update(bond, bestslave, NULL);
 			} else {
 				bestslave->state = BOND_STATE_ACTIVE;
 			}
@@ -1423,10 +1802,12 @@
 
 /* 
  * this function is called regularly to monitor each slave's link 
- * insuring that traffic is being sent and received.  If the adapter
- * has been dormant, then an arp is transmitted to generate traffic 
+ * ensuring that traffic is being sent and received when arp monitoring
+ * is used in load-balancing mode. if the adapter has been dormant, then an 
+ * arp is transmitted to generate traffic. see activebackup_arp_monitor for 
+ * arp monitoring in active backup mode. 
  */
-static void bond_arp_monitor(struct net_device *master)
+static void loadbalance_arp_monitor(struct net_device *master)
 {
 	bonding_t *bond;
 	unsigned long flags;
@@ -1442,147 +1823,358 @@
 
 	read_lock_irqsave(&bond->lock, flags);
 
-	if (!IS_UP(master)) {
+	/* TODO: investigate why rtnl_shlock_nowait and rtnl_exlock_nowait
+	 * are called below and add comment why they are required... 
+	 */
+	if ((!IS_UP(master)) || rtnl_shlock_nowait()) {
 		mod_timer(&bond->arp_timer, next_timer);
-		goto arp_monitor_out;
-	}
-
-
-	if (rtnl_shlock_nowait()) {
-		goto arp_monitor_out;
+		read_unlock_irqrestore(&bond->lock, flags);
+		return;
 	}
 
 	if (rtnl_exlock_nowait()) {
 		rtnl_shunlock();
-		goto arp_monitor_out;
+		mod_timer(&bond->arp_timer, next_timer);
+		read_unlock_irqrestore(&bond->lock, flags);
+		return;
 	}
 
-	/* see if any of the previous devices are up now (i.e. they have seen a 
-	 * response from an arp request sent by another adapter, since they 
-	 * have the same hardware address).
+	/* see if any of the previous devices are up now (i.e. they have
+	 * xmt and rcv traffic). the current_slave does not come into
+	 * the picture unless it is null. also, slave->jiffies is not needed
+	 * here because we send an arp on each slave and give a slave as
+	 * long as it needs to get the tx/rx within the delta.
+	 * TODO: what about up/down delay in arp mode? it wasn't here before
+	 *       so it can wait 
 	 */
-
 	slave = (slave_t *)bond;
 	while ((slave = slave->prev) != (slave_t *)bond)  {
 
-		read_lock(&bond->ptrlock);
-	  	if ( (!(slave->link == BOND_LINK_UP))  
-				&& (slave != bond->current_slave) ) {
-
-			read_unlock(&bond->ptrlock);
+	  	if (slave->link != BOND_LINK_UP) {
 
-	  		if ( ((jiffies - slave->dev->trans_start) <= 
+	  		if (((jiffies - slave->dev->trans_start) <= 
 						the_delta_in_ticks) &&  
 			     ((jiffies - slave->dev->last_rx) <= 
-						the_delta_in_ticks) ) {
+						the_delta_in_ticks)) {
 
 				slave->link  = BOND_LINK_UP;
-				write_lock(&bond->ptrlock);
+				slave->state = BOND_STATE_ACTIVE;
+
+				/* primary_slave has no meaning in round-robin
+				 * mode. the window of a slave being up and 
+				 * current_slave being null after enslaving
+				 * is closed.
+				 */
+				read_lock(&bond->ptrlock);
 				if (bond->current_slave == NULL) {
-					slave->state = BOND_STATE_ACTIVE;
+					read_unlock(&bond->ptrlock);
+					printk(KERN_INFO
+						"%s: link status definitely up "
+						"for interface %s, ",
+						master->name,
+						slave->dev->name);
+					change_active_interface(bond); 
+				} else {
+					read_unlock(&bond->ptrlock);
+					printk(KERN_INFO
+						"%s: interface %s is now up\n",
+						master->name,
+						slave->dev->name);
+				}
+			} 
+		} else {
+			/* slave->link == BOND_LINK_UP */
+
+			/* not all switches will respond to an arp request
+			 * when the source ip is 0, so don't take the link down
+			 * if we don't know our ip yet
+			 */
+			if (((jiffies - slave->dev->trans_start) >= 
+		              (2*the_delta_in_ticks)) ||
+		             (((jiffies - slave->dev->last_rx) >= 
+		               (2*the_delta_in_ticks)) && my_ip !=0)) {
+				slave->link  = BOND_LINK_DOWN;
+				slave->state = BOND_STATE_BACKUP;
+				if (slave->link_failure_count < UINT_MAX) {
+					slave->link_failure_count++;
+				}
+				printk(KERN_INFO
+				       "%s: interface %s is now down.\n",
+				       master->name,
+				       slave->dev->name);
+
+				read_lock(&bond->ptrlock);
+				if (slave == bond->current_slave) {
+					read_unlock(&bond->ptrlock);
+					change_active_interface(bond);
+				} else {
+					read_unlock(&bond->ptrlock);
+				}
+			}
+		} 
+
+		/* note: if switch is in round-robin mode, all links 
+		 * must tx arp to ensure all links rx an arp - otherwise
+		 * links may oscillate or not come up at all; if switch is 
+		 * in something like xor mode, there is nothing we can 
+		 * do - all replies will be rx'ed on same link causing slaves 
+		 * to be unstable during low/no traffic periods
+		 */
+		if (IS_UP(slave->dev)) {
+			arp_send_all(slave);
+		}
+	}
+
+	rtnl_exunlock();
+	rtnl_shunlock();
+	read_unlock_irqrestore(&bond->lock, flags);
+
+	/* re-arm the timer */
+	mod_timer(&bond->arp_timer, next_timer);
+}
+
+/* 
+ * When using arp monitoring in active-backup mode, this function is
+ * called to determine if any backup slaves have went down or a new
+ * current slave needs to be found.
+ * The backup slaves never generate traffic, they are considered up by merely 
+ * receiving traffic. If the current slave goes down, each backup slave will 
+ * be given the opportunity to tx/rx an arp before being taken down - this 
+ * prevents all slaves from being taken down due to the current slave not 
+ * sending any traffic for the backups to receive. The arps are not necessarily
+ * necessary, any tx and rx traffic will keep the current slave up. While any 
+ * rx traffic will keep the backup slaves up, the current slave is responsible 
+ * for generating traffic to keep them up regardless of any other traffic they 
+ * may have received.
+ * see loadbalance_arp_monitor for arp monitoring in load balancing mode
+ */
+static void activebackup_arp_monitor(struct net_device *master)
+{
+	bonding_t *bond;
+	unsigned long flags;
+	slave_t *slave;
+	int the_delta_in_ticks =  arp_interval * HZ / 1000;
+	int next_timer = jiffies + (arp_interval * HZ / 1000);
+
+	bond = (struct bonding *) master->priv; 
+	if (master->priv == NULL) {
+		mod_timer(&bond->arp_timer, next_timer);
+		return;
+	}
+
+	read_lock_irqsave(&bond->lock, flags);
+
+	if (!IS_UP(master)) {
+		mod_timer(&bond->arp_timer, next_timer);
+	        read_unlock_irqrestore(&bond->lock, flags);
+		return;
+	}
+
+	/* determine if any slave has come up or any backup slave has 
+	 * gone down 
+	 * TODO: what about up/down delay in arp mode? it wasn't here before
+	 *       so it can wait 
+	 */
+	slave = (slave_t *)bond;
+	while ((slave = slave->prev) != (slave_t *)bond)  {
+
+	  	if (slave->link != BOND_LINK_UP) {
+			if ((jiffies - slave->dev->last_rx) <=
+			    the_delta_in_ticks) {
+
+				slave->link = BOND_LINK_UP;
+				write_lock(&bond->ptrlock);
+				if ((bond->current_slave == NULL) &&
+				    ((jiffies - slave->dev->trans_start) <=
+				     the_delta_in_ticks)) {
 					bond->current_slave = slave;
+					bond_set_slave_active_flags(slave);
+			                bond_mc_update(bond, slave, NULL);
+					bond->current_arp_slave = NULL;
+				} else if (bond->current_slave != slave) {
+					/* this slave has just come up but we 
+					 * already have a current slave; this
+					 * can also happen if bond_enslave adds
+					 * a new slave that is up while we are 
+					 * searching for a new slave
+					 */
+					bond_set_slave_inactive_flags(slave);
+					bond->current_arp_slave = NULL;
 				}
-				if (slave != bond->current_slave) {
-					slave->dev->flags |= IFF_NOARP;
+
+				if (slave == bond->current_slave) {
+					printk(KERN_INFO
+						"%s: %s is up and now the "
+						"active interface\n",
+						master->name,
+						slave->dev->name);
+				} else {
+					printk(KERN_INFO
+						"%s: backup interface %s is "
+						"now up\n",
+						master->name,
+						slave->dev->name);
 				}
+
 				write_unlock(&bond->ptrlock);
-			} else {
-				if ((jiffies - slave->dev->last_rx) <= 
-						the_delta_in_ticks)  {
-					arp_send(ARPOP_REQUEST, ETH_P_ARP, 
-						arp_target, slave->dev, 
-						my_ip, arp_target_hw_addr, 
-						slave->dev->dev_addr, 
-		  				arp_target_hw_addr); 
+			}
+		} else {
+			read_lock(&bond->ptrlock);
+			if ((slave != bond->current_slave) &&
+			    (bond->current_arp_slave == NULL) &&
+			    (((jiffies - slave->dev->last_rx) >=
+			     3*the_delta_in_ticks) && (my_ip != 0))) {
+				/* a backup slave has gone down; three times 
+				 * the delta allows the current slave to be 
+				 * taken out before the backup slave.
+				 * note: a non-null current_arp_slave indicates
+				 * the current_slave went down and we are 
+				 * searching for a new one; under this 
+				 * condition we only take the current_slave 
+				 * down - this gives each slave a chance to 
+				 * tx/rx traffic before being taken out
+				 */
+				read_unlock(&bond->ptrlock);
+				slave->link  = BOND_LINK_DOWN;
+				if (slave->link_failure_count < UINT_MAX) {
+					slave->link_failure_count++;
 				}
+				bond_set_slave_inactive_flags(slave);
+				printk(KERN_INFO
+					"%s: backup interface %s is now down\n",
+					master->name,
+					slave->dev->name);
+			} else {
+				read_unlock(&bond->ptrlock);
 			}
-		} else 
-			read_unlock(&bond->ptrlock);
+		}
 	}
 
 	read_lock(&bond->ptrlock);
 	slave = bond->current_slave;
 	read_unlock(&bond->ptrlock);
 
-	if (slave != 0) {
-	
-	  /* see if you need to take down the current_slave, since
-	   * you haven't seen an arp in 2*arp_intervals
-	   */
-
-		if ( ((jiffies - slave->dev->trans_start) >= 
-		      (2*the_delta_in_ticks)) ||
-		     ((jiffies - slave->dev->last_rx) >= 
-		      (2*the_delta_in_ticks)) ) {
+	if (slave != NULL) {
 
-			if (slave->link == BOND_LINK_UP) {
-				slave->link  = BOND_LINK_DOWN;
-				slave->state = BOND_STATE_BACKUP;
-				/* 
-				 * we want to see arps, otherwise we couldn't 
-				 * bring the adapter back online...  
-				 */
-				printk(KERN_INFO "%s: link status definitely "
-						 "down for interface %s, "
-						 "disabling it",
-				       slave->dev->master->name,
-				       slave->dev->name);
-				/* find a new interface and be verbose */
-				change_active_interface(bond);
-				read_lock(&bond->ptrlock);
-				slave = bond->current_slave;
-				read_unlock(&bond->ptrlock);
-			}
-		} 
+		/* if we have sent traffic in the past 2*arp_intervals but
+		 * haven't xmit and rx traffic in that time interval, select 
+		 * a different slave. slave->jiffies is only updated when
+		 * a slave first becomes the current_slave - not necessarily
+		 * after every arp; this ensures the slave has a full 2*delta 
+		 * before being taken out. if a primary is being used, check 
+		 * if it is up and needs to take over as the current_slave
+		 */
+		if ((((jiffies - slave->dev->trans_start) >= 
+		       (2*the_delta_in_ticks)) ||
+		     (((jiffies - slave->dev->last_rx) >= 
+		       (2*the_delta_in_ticks)) && (my_ip != 0))) &&
+		    ((jiffies - slave->jiffies) >= 2*the_delta_in_ticks)) {
+
+			slave->link  = BOND_LINK_DOWN;
+			if (slave->link_failure_count < UINT_MAX) {
+				slave->link_failure_count++;
+			}
+			printk(KERN_INFO "%s: link status down for "
+					 "active interface %s, disabling it",
+			       master->name,
+			       slave->dev->name);
+			slave = change_active_interface(bond);
+			bond->current_arp_slave = slave;
+			if (slave != NULL) {
+				slave->jiffies = jiffies;
+			}
+
+		} else if ((bond->primary_slave != NULL) && 
+			   (bond->primary_slave != slave) && 
+			   (bond->primary_slave->link == BOND_LINK_UP)) {
+			/* at this point, slave is the current_slave */
+			printk(KERN_INFO 
+			       "%s: changing from interface %s to primary "
+			       "interface %s\n",
+			       master->name, 
+			       slave->dev->name, 
+			       bond->primary_slave->dev->name);
+			       
+			/* primary is up so switch to it */
+			bond_set_slave_inactive_flags(slave);
+			bond_mc_update(bond, bond->primary_slave, slave);
+			write_lock(&bond->ptrlock);
+			bond->current_slave = bond->primary_slave;
+			write_unlock(&bond->ptrlock);
+			slave = bond->primary_slave;
+			bond_set_slave_active_flags(slave);
+			slave->jiffies = jiffies;
+		} else {
+			bond->current_arp_slave = NULL;
+		}
 
-		/* 
-		 * ok, we know up/down, so just send a arp out if there has
-		 * been no activity for a while 
+		/* the current slave must tx an arp to ensure backup slaves
+		 * rx traffic
 		 */
+		if ((slave != NULL) &&
+		    (((jiffies - slave->dev->last_rx) >= the_delta_in_ticks) &&
+		     (my_ip != 0))) {
+		  arp_send_all(slave);
+		}
+	}
 
-		if (slave != NULL ) {
-			if ( ((jiffies - slave->dev->trans_start) >= 
-			       the_delta_in_ticks) || 
-			     ((jiffies - slave->dev->last_rx) >= 
-			       the_delta_in_ticks) ) {
-				arp_send(ARPOP_REQUEST, ETH_P_ARP, 
-					 arp_target, slave->dev,
-					 my_ip, arp_target_hw_addr, 
-					 slave->dev->dev_addr, 
-					 arp_target_hw_addr); 
-			}
+	/* if we don't have a current_slave, search for the next available 
+	 * backup slave from the current_arp_slave and make it the candidate 
+	 * for becoming the current_slave
+	 */
+	if (slave == NULL) { 
+
+		if ((bond->current_arp_slave == NULL) ||
+		    (bond->current_arp_slave == (slave_t *)bond)) {
+			bond->current_arp_slave = bond->prev;
 		} 
 
-	}
+		if (bond->current_arp_slave != (slave_t *)bond) {
+			bond_set_slave_inactive_flags(bond->current_arp_slave);
+			slave = bond->current_arp_slave->next;
+
+			/* search for next candidate */
+			do {
+				if (IS_UP(slave->dev)) {
+					slave->link = BOND_LINK_BACK;
+					bond_set_slave_active_flags(slave);
+					arp_send_all(slave);
+					slave->jiffies = jiffies;
+					bond->current_arp_slave = slave;
+					break;
+				}
 
-	/* if we have no current slave.. try sending 
-	 * an arp on all of the interfaces 
-	 */
+				/* if the link state is up at this point, we 
+				 * mark it down - this can happen if we have 
+				 * simultaneous link failures and 
+				 * change_active_interface doesn't make this 
+				 * one the current slave so it is still marked 
+				 * up when it is actually down
+				 */
+				if (slave->link == BOND_LINK_UP) {
+					slave->link  = BOND_LINK_DOWN;
+					if (slave->link_failure_count < 
+							UINT_MAX) {
+						slave->link_failure_count++;
+					}
 
-	read_lock(&bond->ptrlock);
-	if (bond->current_slave == NULL) { 
-		read_unlock(&bond->ptrlock);
-		slave = (slave_t *)bond;
-		while ((slave = slave->prev) != (slave_t *)bond)   {
-			arp_send(ARPOP_REQUEST, ETH_P_ARP, arp_target, 
-				 slave->dev, my_ip, arp_target_hw_addr, 
-				 slave->dev->dev_addr, arp_target_hw_addr); 
+					bond_set_slave_inactive_flags(slave);
+					printk(KERN_INFO
+						"%s: backup interface "
+						"%s is now down.\n",
+						master->name,
+						slave->dev->name);
+				}
+			} while ((slave = slave->next) != 
+					bond->current_arp_slave->next);
 		}
 	}
-	else {
-		read_unlock(&bond->ptrlock);
-	}
-
-	rtnl_exunlock();
-	rtnl_shunlock();
-
-arp_monitor_out:
-	read_unlock_irqrestore(&bond->lock, flags);
 
-	/* re-arm the timer */
 	mod_timer(&bond->arp_timer, next_timer);
+	read_unlock_irqrestore(&bond->lock, flags);
 }
 
+
 #define isdigit(c) (c >= '0' && c <= '9')
 __inline static int atoi( char **s) 
 {
@@ -1723,7 +2315,7 @@
 	}
 	read_unlock_irqrestore(&bond->lock, flags);
 
-	if (cur_ndx == info->slave_id) {
+	if (slave != (slave_t *)bond) {
 		strcpy(info->slave_name, slave->dev->name);
 		info->link = slave->link;
 		info->state = slave->state;
@@ -1740,7 +2332,7 @@
 	struct net_device *slave_dev = NULL;
 	struct ifbond *u_binfo = NULL, k_binfo;
 	struct ifslave *u_sinfo = NULL, k_sinfo;
-	u16 *data = NULL;
+	struct mii_ioctl_data *mii = NULL;
 	int ret = 0;
 
 #ifdef BONDING_DEBUG
@@ -1750,23 +2342,23 @@
 
 	switch (cmd) {
 	case SIOCGMIIPHY:
-		data = (u16 *)ifr->ifr_data;
-		if (data == NULL) {
+		mii = (struct mii_ioctl_data *)&ifr->ifr_data;
+		if (mii == NULL) {
 			return -EINVAL;
 		}
-		data[0] = 0;
+		mii->phy_id = 0;
 		/* Fall Through */
 	case SIOCGMIIREG:
 		/* 
 		 * We do this again just in case we were called by SIOCGMIIREG
 		 * instead of SIOCGMIIPHY.
 		 */
-		data = (u16 *)ifr->ifr_data;
-		if (data == NULL) {
+		mii = (struct mii_ioctl_data *)&ifr->ifr_data;
+		if (mii == NULL) {
 			return -EINVAL;
 		}
-		if (data[1] == 1) {
-			data[3] = bond_check_mii_link(
+		if (mii->reg_num == 1) {
+			mii->val_out = bond_check_mii_link(
 				(struct bonding *)master_dev->priv);
 		}
 		return 0;
@@ -1849,6 +2441,65 @@
 }
 #endif
 
+/* 
+ * in broadcast mode, we send everything to all usable interfaces.
+ */
+static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *dev)
+{
+	slave_t *slave, *start_at;
+	struct bonding *bond = (struct bonding *) dev->priv;
+	unsigned long flags;
+	struct net_device *device_we_should_send_to = 0;
+
+	if (!IS_UP(dev)) { /* bond down */
+		dev_kfree_skb(skb);
+		return 0;
+	}
+
+	read_lock_irqsave(&bond->lock, flags);
+
+	read_lock(&bond->ptrlock);
+	slave = start_at = bond->current_slave;
+	read_unlock(&bond->ptrlock);
+
+	if (slave == NULL) { /* we're at the root, get the first slave */
+		/* no suitable interface, frame not sent */
+		read_unlock_irqrestore(&bond->lock, flags);
+		dev_kfree_skb(skb);
+		return 0;
+	}
+
+	do {
+		if (IS_UP(slave->dev)
+		    && (slave->link == BOND_LINK_UP)
+		    && (slave->state == BOND_STATE_ACTIVE)) {
+			if (device_we_should_send_to) {
+				struct sk_buff *skb2;
+				if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) {
+					printk(KERN_ERR "bond_xmit_broadcast: skb_clone() failed\n");
+					continue;
+				}
+
+				skb2->dev = device_we_should_send_to;
+				skb2->priority = 1;
+				dev_queue_xmit(skb2);
+			}
+			device_we_should_send_to = slave->dev;
+		}
+	} while ((slave = slave->next) != start_at);
+
+	if (device_we_should_send_to) {
+		skb->dev = device_we_should_send_to;
+		skb->priority = 1;
+		dev_queue_xmit(skb);
+	} else
+		dev_kfree_skb(skb);
+
+	/* frame sent to all suitable interfaces */
+	read_unlock_irqrestore(&bond->lock, flags);
+	return 0;
+}
+
 static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *dev)
 {
 	slave_t *slave, *start_at;
@@ -1981,14 +2632,25 @@
 	}
 
 	/* if we are sending arp packets and don't know 
-	   the target hw address, save it so we don't need 
-	   to use a broadcast address */
-	if ( (arp_interval > 0) && (arp_target_hw_addr == NULL) &&
+	 * the target hw address, save it so we don't need 
+	 * to use a broadcast address.
+	 * don't do this if in active backup mode because the slaves must 
+	 * receive packets to stay up, and the only ones they receive are 
+	 * broadcasts. 
+	 */
+	if ( (mode != BOND_MODE_ACTIVEBACKUP) && 
+             (arp_ip_count == 1) &&
+	     (arp_interval > 0) && (arp_target_hw_addr == NULL) &&
 	     (skb->protocol == __constant_htons(ETH_P_IP) ) ) {
 		struct ethhdr *eth_hdr = 
 			(struct ethhdr *) (((char *)skb->data));
-		arp_target_hw_addr = kmalloc(ETH_ALEN, GFP_KERNEL);
-		memcpy(arp_target_hw_addr, eth_hdr->h_dest, ETH_ALEN);
+		struct iphdr *ip_hdr = (struct iphdr *)(eth_hdr + 1);
+
+		if (arp_target[0] == ip_hdr->daddr) {
+			arp_target_hw_addr = kmalloc(ETH_ALEN, GFP_KERNEL);
+			if (arp_target_hw_addr != NULL)
+				memcpy(arp_target_hw_addr, eth_hdr->h_dest, ETH_ALEN);
+		}
 	}
 
 	read_lock_irqsave(&bond->lock, flags);
@@ -2077,29 +2739,7 @@
 		 */
 		link = bond_check_mii_link(bond);
 
-		len += sprintf(buf + len, "Bonding Mode: ");
-
-		switch (mode) {
-			case BOND_MODE_ACTIVEBACKUP:
-				len += sprintf(buf + len, "%s\n", 
-						"active-backup");
-			break;
-
-			case BOND_MODE_ROUNDROBIN:
-				len += sprintf(buf + len, "%s\n", 
-						"load balancing (round-robin)");
-			break;
-
-			case BOND_MODE_XOR:
-				len += sprintf(buf + len, "%s\n", 
-						"load balancing (xor)");
-			break;
-
-			default:
-				len += sprintf(buf + len, "%s\n", 
-						"unknown");
-			break;
-		}
+		len += sprintf(buf + len, "Bonding Mode: %s\n", bond_mode());
 
 		if (mode == BOND_MODE_ACTIVEBACKUP) {
 			read_lock_irqsave(&bond->lock, flags);
@@ -2118,8 +2758,11 @@
 				link == BMSR_LSTATUS ? "up\n" : "down\n");
 		len += sprintf(buf + len, "MII Polling Interval (ms): %d\n", 
 				miimon);
-		len += sprintf(buf + len, "Up Delay (ms): %d\n", updelay);
-		len += sprintf(buf + len, "Down Delay (ms): %d\n", downdelay);
+		len += sprintf(buf + len, "Up Delay (ms): %d\n", 
+				updelay * miimon);
+		len += sprintf(buf + len, "Down Delay (ms): %d\n", 
+				downdelay * miimon);
+		len += sprintf(buf + len, "Multicast Mode: %s\n", multicast_mode());
 
 		read_lock_irqsave(&bond->lock, flags);
 		for (slave = bond->prev; slave != (slave_t *)bond; 
@@ -2208,6 +2851,7 @@
 static int __init bond_init(struct net_device *dev)
 {
 	bonding_t *bond, *this_bond, *last_bond;
+	int count;
 
 #ifdef BONDING_DEBUG
 	printk (KERN_INFO "Begin bond_init for %s\n", dev->name);
@@ -2231,6 +2875,7 @@
 
 	bond->next = bond->prev = (slave_t *)bond;
 	bond->current_slave = NULL;
+	bond->current_arp_slave = NULL;
 	bond->device = dev;
 	dev->priv = bond;
 
@@ -2241,6 +2886,8 @@
 		dev->hard_start_xmit = bond_xmit_roundrobin;
 	} else if (mode == BOND_MODE_XOR) {
 		dev->hard_start_xmit = bond_xmit_xor;
+	} else if (mode == BOND_MODE_BROADCAST) {
+		dev->hard_start_xmit = bond_xmit_broadcast;
 	} else {
 		printk(KERN_ERR "Unknown bonding mode %d\n", mode);
 		kfree(bond->stats);
@@ -2275,7 +2922,18 @@
 	} else {
 		printk("out MII link monitoring");
 	}
-	printk(", in %s mode.\n",mode?"active-backup":"bonding");
+	printk(", in %s mode.\n", bond_mode());
+
+	printk(KERN_INFO "%s registered with", dev->name);
+	if (arp_interval > 0) {
+		printk(" ARP monitoring set to %d ms with %d target(s):", 
+			arp_interval, arp_ip_count);
+		for (count=0 ; count<arp_ip_count ; count++)
+                        printk (" %s", arp_ip_target[count]);
+		printk("\n");
+	} else {
+		printk("out ARP monitoring\n");
+	}
 
 #ifdef CONFIG_PROC_FS
 	bond->bond_proc_dir = proc_mkdir(dev->name, proc_net);
@@ -2332,6 +2990,8 @@
 	/* Find a name for this unit */
 	static struct net_device *dev_bond = NULL;
 
+	printk(KERN_INFO "%s", version);
+
 	if (max_bonds < 1 || max_bonds > INT_MAX) {
 		printk(KERN_WARNING 
 		       "bonding_init(): max_bonds (%d) not in range %d-%d, "
@@ -2346,6 +3006,14 @@
 	}
 	memset(dev_bonds, 0, max_bonds*sizeof(struct net_device));
 
+	if (miimon < 0) {
+		printk(KERN_WARNING 
+		       "bonding_init(): miimon module parameter (%d), "
+		       "not in range 0-%d, so it was reset to %d\n",
+		       miimon, INT_MAX, BOND_LINK_MON_INTERV);
+		miimon = BOND_LINK_MON_INTERV;
+	}
+
 	if (updelay < 0) {
 		printk(KERN_WARNING 
 		       "bonding_init(): updelay module parameter (%d), "
@@ -2362,6 +3030,52 @@
 		downdelay = 0;
 	}
 
+	if (miimon == 0) {
+		if ((updelay != 0) || (downdelay != 0)) {
+			/* just warn the user the up/down delay will have
+			 * no effect since miimon is zero...
+			 */
+			printk(KERN_WARNING 
+		               "bonding_init(): miimon module parameter not "
+			       "set and updelay (%d) or downdelay (%d) module "
+			       "parameter is set; updelay and downdelay have "
+			       "no effect unless miimon is set\n",
+		               updelay, downdelay);
+		}
+	} else {
+		/* don't allow arp monitoring */
+		if (arp_interval != 0) {
+			printk(KERN_WARNING 
+		               "bonding_init(): miimon (%d) and arp_interval "
+			       "(%d) can't be used simultaneously, "
+			       "disabling ARP monitoring\n",
+		               miimon, arp_interval);
+			arp_interval = 0;
+		}
+
+		if ((updelay % miimon) != 0) {
+			/* updelay will be rounded in bond_init() when it
+			 * is divided by miimon, we just inform user here
+			 */
+			printk(KERN_WARNING 
+		               "bonding_init(): updelay (%d) is not a multiple "
+			       "of miimon (%d), updelay rounded to %d ms\n",
+		               updelay, miimon, (updelay / miimon) * miimon);
+		}
+
+		if ((downdelay % miimon) != 0) {
+			/* downdelay will be rounded in bond_init() when it
+			 * is divided by miimon, we just inform user here
+			 */
+			printk(KERN_WARNING 
+		               "bonding_init(): downdelay (%d) is not a "
+			       "multiple of miimon (%d), downdelay rounded "
+			       "to %d ms\n",
+		               downdelay, miimon, 
+			       (downdelay / miimon) * miimon);
+		}
+	}
+
 	if (arp_interval < 0) {
 		printk(KERN_WARNING 
 		       "bonding_init(): arp_interval module parameter (%d), "
@@ -2370,11 +3084,63 @@
 		arp_interval = BOND_LINK_ARP_INTERV;
 	}
 
-	if (arp_ip_target) {
-		/* TODO: check and log bad ip address */
-		if (my_inet_aton(arp_ip_target, &arp_target) == 0)  {
-			arp_interval = 0;
+        for (arp_ip_count=0 ;
+             (arp_ip_count < MAX_ARP_IP_TARGETS) && arp_ip_target[arp_ip_count];
+              arp_ip_count++ ) {
+                /* TODO: check and log bad ip address */
+                if (my_inet_aton(arp_ip_target[arp_ip_count],
+                                 &arp_target[arp_ip_count]) == 0) {
+                        printk(KERN_WARNING
+                               "bonding_init(): bad arp_ip_target module "
+                               "parameter (%s), ARP monitoring will not be "
+                               "performed\n",
+                               arp_ip_target[arp_ip_count]);
+                        arp_interval = 0;
 		}
+        }
+
+
+	if ( (arp_interval > 0) && (arp_ip_count==0)) {
+		/* don't allow arping if no arp_ip_target given... */
+		printk(KERN_WARNING 
+		       "bonding_init(): arp_interval module parameter "
+		       "(%d) specified without providing an arp_ip_target "
+		       "parameter, arp_interval was reset to 0\n",
+		       arp_interval);
+		arp_interval = 0;
+	}
+
+	if ((miimon == 0) && (arp_interval == 0)) {
+		/* miimon and arp_interval not set, we need one so things
+		 * work as expected, see bonding.txt for details
+		 */
+		printk(KERN_ERR 
+		       "bonding_init(): either miimon or "
+		       "arp_interval and arp_ip_target module parameters "
+		       "must be specified, otherwise bonding will not detect "
+		       "link failures! see bonding.txt for details.\n");
+	}
+
+	if ((primary != NULL) && (mode != BOND_MODE_ACTIVEBACKUP)){
+		/* currently, using a primary only makes sence 
+		 * in active backup mode 
+		 */
+		printk(KERN_WARNING 
+		       "bonding_init(): %s primary device specified but has "
+		       " no effect in %s mode\n",
+		       primary, bond_mode());
+		primary = NULL;
+	}
+
+
+        if (multicast != BOND_MULTICAST_DISABLED &&
+	    multicast != BOND_MULTICAST_ACTIVE &&
+	    multicast != BOND_MULTICAST_ALL) {
+		printk(KERN_WARNING 
+		       "bonding_init(): unknown multicast module "
+		       "parameter (%d), multicast reset to %d\n", 
+		       multicast, BOND_MULTICAST_ALL);
+		multicast = BOND_MULTICAST_ALL;
 	}
 
 	for (no = 0; no < max_bonds; no++) {
@@ -2423,6 +3189,7 @@
 module_init(bonding_init);
 module_exit(bonding_exit);
 MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(DRV_DESCRIPTION ", v" DRV_VERSION);
 
 /*
  * Local variables:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/cirrus.c linux-2.4.21-pre6/drivers/net/cirrus.c
--- linux-2.4.20/drivers/net/cirrus.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/cirrus.c	2003-03-26 23:49:07.000000000 +0000
@@ -0,0 +1,692 @@
+
+/*
+ * linux/drivers/net/cirrus.c
+ *
+ * Author: Abraham van der Merwe <abraham@2d3d.co.za>
+ *
+ * A Cirrus Logic CS8900A driver for Linux
+ * based on the cs89x0 driver written by Russell Nelson,
+ * Donald Becker, and others.
+ *
+ * This source code is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+/*
+ * At the moment the driver does not support memory mode operation.
+ * It is trivial to implement this, but not worth the effort.
+ */
+
+/*
+ * TODO:
+ *
+ *   1. If !ready in send_start(), queue buffer and send it in interrupt handler
+ *      when we receive a BufEvent with Rdy4Tx, send it again. dangerous!
+ *   2. how do we prevent interrupt handler destroying integrity of get_stats()?
+ *   3. Change reset code to check status.
+ *   4. Implement set_mac_address and remove fake mac address
+ *   5. Link status detection stuff
+ *   6. Write utility to write EEPROM, do self testing, etc.
+ *   7. Implement DMA routines (I need a board w/ DMA support for that)
+ *   8. Power management
+ *   9. Add support for multiple ethernet chips
+ *  10. Add support for other cs89xx chips (need hardware for that)
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include "cirrus.h"
+
+/* #define DEBUG */
+/* #define FULL_DUPLEX */
+
+#ifdef CONFIG_SA1100_FRODO
+#	define CIRRUS_DEFAULT_IO FRODO_ETH_IO + 0x300
+#	define CIRRUS_DEFAULT_IRQ FRODO_ETH_IRQ
+#elif CONFIG_SA1100_CERF
+#	define CIRRUS_DEFAULT_IO CERF_ETH_IO + 0x300
+#	define CIRRUS_DEFAULT_IRQ CERF_ETH_IRQ
+#elif CONFIG_ARCH_CDB89712
+#	define CIRRUS_DEFAULT_IO ETHER_BASE + 0x300
+#	define CIRRUS_DEFAULT_IRQ IRQ_EINT3
+#else
+#	define CIRRUS_DEFAULT_IO	0
+#	define CIRRUS_DEFAULT_IRQ	0
+#endif	/* #ifdef CONFIG_SA1100_CERF */
+
+typedef struct {
+	struct net_device_stats stats;
+	u16 txlen;
+} cirrus_t;
+
+typedef struct {
+	u16 io_base;		/* I/O Base Address			*/
+	u16 irq;			/* Interrupt Number			*/
+	u16 dma;			/* DMA Channel Numbers		*/
+	u32 mem_base;		/* Memory Base Address		*/
+	u32 rom_base;		/* Boot PROM Base Address	*/
+	u32 rom_mask;		/* Boot PROM Address Mask	*/
+	u8 mac[6];			/* Individual Address		*/
+} cirrus_eeprom_t;
+
+/*
+ * I/O routines
+ */
+
+static inline u16 cirrus_read (struct net_device *dev,u16 reg)
+{
+	outw (reg,dev->base_addr + PP_Address);
+	return (inw (dev->base_addr + PP_Data));
+}
+
+static inline void cirrus_write (struct net_device *dev,u16 reg,u16 value)
+{
+	outw (reg,dev->base_addr + PP_Address);
+	outw (value,dev->base_addr + PP_Data);
+}
+
+static inline void cirrus_set (struct net_device *dev,u16 reg,u16 value)
+{
+	cirrus_write (dev,reg,cirrus_read (dev,reg) | value);
+}
+
+static inline void cirrus_clear (struct net_device *dev,u16 reg,u16 value)
+{
+	cirrus_write (dev,reg,cirrus_read (dev,reg) & ~value);
+}
+
+static inline void cirrus_frame_read (struct net_device *dev,struct sk_buff *skb,u16 length)
+{
+	insw (dev->base_addr,skb_put (skb,length),(length + 1) / 2);
+}
+
+static inline void cirrus_frame_write (struct net_device *dev,struct sk_buff *skb)
+{
+	outsw (dev->base_addr,skb->data,(skb->len + 1) / 2);
+}
+
+/*
+ * Debugging functions
+ */
+
+#ifdef DEBUG
+static inline int printable (int c)
+{
+	return ((c >= 32 && c <= 126) ||
+			(c >= 174 && c <= 223) ||
+			(c >= 242 && c <= 243) ||
+			(c >= 252 && c <= 253));
+}
+
+static void dump16 (struct net_device *dev,const u8 *s,size_t len)
+{
+	int i;
+	char str[128];
+
+	if (!len) return;
+
+	*str = '\0';
+
+	for (i = 0; i < len; i++) {
+		if (i && !(i % 4)) strcat (str," ");
+		sprintf (str,"%s%.2x ",str,s[i]);
+	}
+
+	for ( ; i < 16; i++) {
+		if (i && !(i % 4)) strcat (str," ");
+		strcat (str,"   ");
+	}
+
+	strcat (str," ");
+	for (i = 0; i < len; i++) sprintf (str,"%s%c",str,printable (s[i]) ? s[i] : '.');
+
+	printk (KERN_DEBUG "%s:     %s\n",dev->name,str);
+}
+
+static void hexdump (struct net_device *dev,const void *ptr,size_t size)
+{
+	const u8 *s = (u8 *) ptr;
+	int i;
+	for (i = 0; i < size / 16; i++, s += 16) dump16 (dev,s,16);
+	dump16 (dev,s,size % 16);
+}
+
+static void dump_packet (struct net_device *dev,struct sk_buff *skb,const char *type)
+{
+	printk (KERN_INFO "%s: %s %d byte frame %.2x:%.2x:%.2x:%.2x:%.2x:%.2x to %.2x:%.2x:%.2x:%.2x:%.2x:%.2x type %.4x\n",
+			dev->name,
+			type,
+			skb->len,
+			skb->data[0],skb->data[1],skb->data[2],skb->data[3],skb->data[4],skb->data[5],
+			skb->data[6],skb->data[7],skb->data[8],skb->data[9],skb->data[10],skb->data[11],
+			(skb->data[12] << 8) | skb->data[13]);
+	if (skb->len < 0x100) hexdump (dev,skb->data,skb->len);
+}
+#endif	/* #ifdef DEBUG */
+
+/*
+ * Driver functions
+ */
+
+static void cirrus_receive (struct net_device *dev)
+{
+	cirrus_t *priv = (cirrus_t *) dev->priv;
+	struct sk_buff *skb;
+	u16 status,length;
+
+	status = cirrus_read (dev,PP_RxStatus);
+	length = cirrus_read (dev,PP_RxLength);
+
+	if (!(status & RxOK)) {
+		priv->stats.rx_errors++;
+		if ((status & (Runt | Extradata))) priv->stats.rx_length_errors++;
+		if ((status & CRCerror)) priv->stats.rx_crc_errors++;
+		return;
+	}
+
+	if ((skb = dev_alloc_skb (length + 4)) == NULL) {
+		priv->stats.rx_dropped++;
+		return;
+	}
+
+	skb->dev = dev;
+	skb_reserve (skb,2);
+
+	cirrus_frame_read (dev,skb,length);
+
+#ifdef DEBUG
+	dump_packet (dev,skb,"recv");
+#endif	/* #ifdef DEBUG */
+
+	skb->protocol = eth_type_trans (skb,dev);
+
+	netif_rx (skb);
+	dev->last_rx = jiffies;
+
+	priv->stats.rx_packets++;
+	priv->stats.rx_bytes += length;
+}
+
+static int cirrus_send_start (struct sk_buff *skb,struct net_device *dev)
+{
+	cirrus_t *priv = (cirrus_t *) dev->priv;
+	u16 status;
+
+	netif_stop_queue (dev);
+
+	cirrus_write (dev,PP_TxCMD,TxStart (After5));
+	cirrus_write (dev,PP_TxLength,skb->len);
+
+	status = cirrus_read (dev,PP_BusST);
+
+	if ((status & TxBidErr)) {
+		printk (KERN_WARNING "%s: Invalid frame size %d!\n",dev->name,skb->len);
+		priv->stats.tx_errors++;
+		priv->stats.tx_aborted_errors++;
+		priv->txlen = 0;
+		return (1);
+	}
+
+	if (!(status & Rdy4TxNOW)) {
+		printk (KERN_WARNING "%s: Transmit buffer not free!\n",dev->name);
+		priv->stats.tx_errors++;
+		priv->txlen = 0;
+		/* FIXME: store skb and send it in interrupt handler */
+		return (1);
+	}
+
+	cirrus_frame_write (dev,skb);
+
+#ifdef DEBUG
+	dump_packet (dev,skb,"send");
+#endif	/* #ifdef DEBUG */
+
+	dev->trans_start = jiffies;
+
+	dev_kfree_skb (skb);
+
+	priv->txlen = skb->len;
+
+	return (0);
+}
+
+static void cirrus_interrupt (int irq,void *id,struct pt_regs *regs)
+{
+	struct net_device *dev = (struct net_device *) id;
+	cirrus_t *priv;
+	u16 status;
+
+	if (dev->priv == NULL) {
+		printk (KERN_WARNING "%s: irq %d for unknown device.\n",dev->name,irq);
+		return;
+	}
+
+	priv = (cirrus_t *) dev->priv;
+
+	while ((status = cirrus_read (dev,PP_ISQ))) {
+		switch (RegNum (status)) {
+		case RxEvent:
+			cirrus_receive (dev);
+			break;
+
+		case TxEvent:
+			priv->stats.collisions += ColCount (cirrus_read (dev,PP_TxCOL));
+			if (!(RegContent (status) & TxOK)) {
+				priv->stats.tx_errors++;
+				if ((RegContent (status) & Out_of_window)) priv->stats.tx_window_errors++;
+				if ((RegContent (status) & Jabber)) priv->stats.tx_aborted_errors++;
+				break;
+			} else if (priv->txlen) {
+				priv->stats.tx_packets++;
+				priv->stats.tx_bytes += priv->txlen;
+			}
+			priv->txlen = 0;
+			netif_wake_queue (dev);
+			break;
+
+		case BufEvent:
+			if ((RegContent (status) & RxMiss)) {
+				u16 missed = MissCount (cirrus_read (dev,PP_RxMISS));
+				priv->stats.rx_errors += missed;
+				priv->stats.rx_missed_errors += missed;
+			}
+			if ((RegContent (status) & TxUnderrun)) {
+				priv->stats.tx_errors++;
+				priv->stats.tx_fifo_errors++;
+			}
+			/* FIXME: if Rdy4Tx, transmit last sent packet (if any) */
+			priv->txlen = 0;
+			netif_wake_queue (dev);
+			break;
+
+		case TxCOL:
+			priv->stats.collisions += ColCount (cirrus_read (dev,PP_TxCOL));
+			break;
+
+		case RxMISS:
+			status = MissCount (cirrus_read (dev,PP_RxMISS));
+			priv->stats.rx_errors += status;
+			priv->stats.rx_missed_errors += status;
+			break;
+		}
+	}
+}
+
+static void cirrus_transmit_timeout (struct net_device *dev)
+{
+	cirrus_t *priv = (cirrus_t *) dev->priv;
+	priv->stats.tx_errors++;
+	priv->stats.tx_heartbeat_errors++;
+	priv->txlen = 0;
+	netif_wake_queue (dev);
+}
+
+static int cirrus_start (struct net_device *dev)
+{
+	int result;
+
+	/* valid ethernet address? */
+	if (!is_valid_ether_addr(dev->dev_addr)) {
+		printk(KERN_ERR "%s: invalid ethernet MAC address\n",dev->name);
+		return (-EINVAL);
+	}
+
+	/* install interrupt handler */
+	if ((result = request_irq (dev->irq,&cirrus_interrupt,0,dev->name,dev)) < 0) {
+		printk (KERN_ERR "%s: could not register interrupt %d\n",dev->name,dev->irq);
+		return (result);
+	}
+
+	/* enable the ethernet controller */
+	cirrus_set (dev,PP_RxCFG,RxOKiE | BufferCRC | CRCerroriE | RuntiE | ExtradataiE);
+	cirrus_set (dev,PP_RxCTL,RxOKA | IndividualA | BroadcastA);
+	cirrus_set (dev,PP_TxCFG,TxOKiE | Out_of_windowiE | JabberiE);
+	cirrus_set (dev,PP_BufCFG,Rdy4TxiE | RxMissiE | TxUnderruniE | TxColOvfiE | MissOvfloiE);
+	cirrus_set (dev,PP_LineCTL,SerRxON | SerTxON);
+	cirrus_set (dev,PP_BusCTL,EnableRQ);
+
+#ifdef FULL_DUPLEX
+	cirrus_set (dev,PP_TestCTL,FDX);
+#endif	/* #ifdef FULL_DUPLEX */
+
+	/* start the queue */
+	netif_start_queue (dev);
+
+	MOD_INC_USE_COUNT;
+
+	return (0);
+}
+
+static int cirrus_stop (struct net_device *dev)
+{
+	/* disable ethernet controller */
+	cirrus_write (dev,PP_BusCTL,0);
+	cirrus_write (dev,PP_TestCTL,0);
+	cirrus_write (dev,PP_SelfCTL,0);
+	cirrus_write (dev,PP_LineCTL,0);
+	cirrus_write (dev,PP_BufCFG,0);
+	cirrus_write (dev,PP_TxCFG,0);
+	cirrus_write (dev,PP_RxCTL,0);
+	cirrus_write (dev,PP_RxCFG,0);
+
+	/* uninstall interrupt handler */
+	free_irq (dev->irq,dev);
+
+	/* stop the queue */
+	netif_stop_queue (dev);
+
+	MOD_DEC_USE_COUNT;
+
+	return (0);
+}
+
+static int cirrus_set_mac_address (struct net_device *dev, void *p)
+{
+	struct sockaddr *addr = (struct sockaddr *)p;
+	int i;
+
+	if (netif_running(dev))
+		return -EBUSY;
+
+	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+	/* configure MAC address */
+	for (i = 0; i < ETH_ALEN; i += 2)
+		cirrus_write (dev,PP_IA + i,dev->dev_addr[i] | (dev->dev_addr[i + 1] << 8));
+
+	return 0;
+}
+
+static struct net_device_stats *cirrus_get_stats (struct net_device *dev)
+{
+	cirrus_t *priv = (cirrus_t *) dev->priv;
+	return (&priv->stats);
+}
+
+static void cirrus_set_receive_mode (struct net_device *dev)
+{
+	if ((dev->flags & IFF_PROMISC))
+		cirrus_set (dev,PP_RxCTL,PromiscuousA);
+	else
+		cirrus_clear (dev,PP_RxCTL,PromiscuousA);
+
+	if ((dev->flags & IFF_ALLMULTI) && dev->mc_list)
+		cirrus_set (dev,PP_RxCTL,MulticastA);
+	else
+		cirrus_clear (dev,PP_RxCTL,MulticastA);
+}
+
+static int cirrus_eeprom_wait (struct net_device *dev)
+{
+	int i;
+
+	for (i = 0; i < 200; i++) {
+		if (!(cirrus_read (dev,PP_SelfST) & SIBUSY))
+			return (0);
+		udelay (1);
+	}
+
+	return (-1);
+}
+
+static int cirrus_eeprom_read (struct net_device *dev,u16 *value,u16 offset)
+{
+	if (cirrus_eeprom_wait (dev) < 0)
+		return (-1);
+
+	cirrus_write (dev,PP_EEPROMCommand,offset | EEReadRegister);
+
+	if (cirrus_eeprom_wait (dev) < 0)
+		return (-1);
+
+	*value = cirrus_read (dev,PP_EEPROMData);
+
+	return (0);
+}
+
+static int cirrus_eeprom (struct net_device *dev,cirrus_eeprom_t *eeprom)
+{
+	u16 offset,buf[16],*word;
+	u8 checksum = 0,*byte;
+
+	if (cirrus_eeprom_read (dev,buf,0) < 0) {
+		read_timed_out:
+		printk (KERN_DEBUG "%s: EEPROM read timed out\n",dev->name);
+		return (-ETIMEDOUT);
+	}
+
+	if ((buf[0] >> 8) != 0xa1) {
+		printk (KERN_DEBUG "%s: No EEPROM present\n",dev->name);
+		return (-ENODEV);
+	}
+
+	if ((buf[0] & 0xff) < sizeof (buf)) {
+		eeprom_too_small:
+		printk (KERN_DEBUG "%s: EEPROM too small\n",dev->name);
+		return (-ENODEV);
+	}
+
+	for (offset = 1; offset < (buf[0] & 0xff); offset++) {
+		if (cirrus_eeprom_read (dev,buf + offset,offset) < 0)
+			goto read_timed_out;
+
+		if (buf[offset] == 0xffff)
+			goto eeprom_too_small;
+	}
+
+	if (buf[1] != 0x2020) {
+		printk (KERN_DEBUG "%s: Group Header #1 mismatch\n",dev->name);
+		return (-EIO);
+	}
+
+	if (buf[5] != 0x502c) {
+		printk (KERN_DEBUG "%s: Group Header #2 mismatch\n",dev->name);
+		return (-EIO);
+	}
+
+	if (buf[12] != 0x2158) {
+		printk (KERN_DEBUG "%s: Group Header #3 mismatch\n",dev->name);
+		return (-EIO);
+	}
+
+	eeprom->io_base = buf[2];
+	eeprom->irq = buf[3];
+	eeprom->dma = buf[4];
+	eeprom->mem_base = (buf[7] << 16) | buf[6];
+	eeprom->rom_base = (buf[9] << 16) | buf[8];
+	eeprom->rom_mask = (buf[11] << 16) | buf[10];
+
+	word = (u16 *) eeprom->mac;
+	for (offset = 0; offset < 3; offset++) word[offset] = buf[13 + offset];
+
+	byte = (u8 *) buf;
+	for (offset = 0; offset < sizeof (buf); offset++) checksum += byte[offset];
+
+	if (cirrus_eeprom_read (dev,&offset,0x10) < 0)
+		goto read_timed_out;
+
+	if ((offset >> 8) != (u8) (0x100 - checksum)) {
+		printk (KERN_DEBUG "%s: Checksum mismatch (expected 0x%.2x, got 0x%.2x instead\n",
+				dev->name,
+				(u8) (0x100 - checksum),
+				offset >> 8);
+		return (-EIO);
+	}
+
+	return (0);
+}
+
+/*
+ * Architecture dependant code
+ */
+
+#ifdef CONFIG_SA1100_FRODO
+static void frodo_reset (struct net_device *dev)
+{
+	int i;
+	volatile u16 value;
+
+	/* reset ethernet controller */
+	FRODO_CPLD_ETHERNET |= FRODO_ETH_RESET;
+	mdelay (50);
+	FRODO_CPLD_ETHERNET &= ~FRODO_ETH_RESET;
+	mdelay (50);
+
+	/* we tied SBHE to CHIPSEL, so each memory access ensure the chip is in 16-bit mode */
+	for (i = 0; i < 3; i++) value = cirrus_read (dev,0);
+
+	/* FIXME: poll status bit */
+}
+#endif	/* #ifdef CONFIG_SA1100_FRODO */
+
+/*
+ * Driver initialization routines
+ */
+
+static int io = 0;
+static int irq = 0;
+
+int __init cirrus_probe (struct net_device *dev)
+{
+	static cirrus_t priv;
+	int i,result;
+	u16 value;
+	cirrus_eeprom_t eeprom;
+
+	printk ("Cirrus Logic CS8900A driver for Linux (V0.02)\n");
+
+	memset (&priv,0,sizeof (cirrus_t));
+
+	ether_setup (dev);
+
+	dev->open               = cirrus_start;
+	dev->stop               = cirrus_stop;
+	dev->hard_start_xmit    = cirrus_send_start;
+	dev->get_stats          = cirrus_get_stats;
+	dev->set_multicast_list = cirrus_set_receive_mode;
+	dev->set_mac_address	= cirrus_set_mac_address;
+	dev->tx_timeout         = cirrus_transmit_timeout;
+	dev->watchdog_timeo     = HZ;
+
+	dev->dev_addr[0] = 0x00;
+	dev->dev_addr[1] = 0x00;
+	dev->dev_addr[2] = 0x00;
+	dev->dev_addr[3] = 0x00;
+	dev->dev_addr[4] = 0x00;
+	dev->dev_addr[5] = 0x00;
+
+	dev->if_port   = IF_PORT_10BASET;
+	dev->priv      = (void *) &priv;
+
+	SET_MODULE_OWNER (dev);
+
+	dev->base_addr = CIRRUS_DEFAULT_IO;
+	dev->irq = CIRRUS_DEFAULT_IRQ;
+
+	/* module parameters override everything */
+	if (io > 0) dev->base_addr = io;
+	if (irq > 0) dev->irq = irq;
+
+	if (!dev->base_addr) {
+		printk (KERN_ERR
+				"%s: No default I/O base address defined. Use io=... or\n"
+				"%s: define CIRRUS_DEFAULT_IO for your platform\n",
+				dev->name,dev->name);
+		return (-EINVAL);
+	}
+
+	if (!dev->irq) {
+		printk (KERN_ERR
+				"%s: No default IRQ number defined. Use irq=... or\n"
+				"%s: define CIRRUS_DEFAULT_IRQ for your platform\n",
+				dev->name,dev->name);
+		return (-EINVAL);
+	}
+
+	if ((result = check_region (dev->base_addr,16))) {
+		printk (KERN_ERR "%s: can't get I/O port address 0x%lx\n",dev->name,dev->base_addr);
+		return (result);
+	}
+
+	if (!request_region (dev->base_addr,16,dev->name))
+		return -EBUSY;
+
+#ifdef CONFIG_SA1100_FRODO
+	frodo_reset (dev);
+#endif	/* #ifdef CONFIG_SA1100_FRODO */
+
+	/* if an EEPROM is present, use it's MAC address */
+	if (!cirrus_eeprom (dev,&eeprom))
+		for (i = 0; i < 6; i++)
+			dev->dev_addr[i] = eeprom.mac[i];
+
+	/* verify EISA registration number for Cirrus Logic */
+	if ((value = cirrus_read (dev,PP_ProductID)) != EISA_REG_CODE) {
+		printk (KERN_ERR "%s: incorrect signature 0x%.4x\n",dev->name,value);
+		return (-ENXIO);
+	}
+
+	/* verify chip version */
+	value = cirrus_read (dev,PP_ProductID + 2);
+	if (VERSION (value) != CS8900A) {
+		printk (KERN_ERR "%s: unknown chip version 0x%.8x\n",dev->name,VERSION (value));
+		return (-ENXIO);
+	}
+	printk (KERN_INFO "%s: CS8900A rev %c detected\n",dev->name,'B' + REVISION (value) - REV_B);
+
+	/* setup interrupt number */
+	cirrus_write (dev,PP_IntNum,0);
+
+	/* configure MAC address */
+	for (i = 0; i < ETH_ALEN; i += 2)
+		cirrus_write (dev,PP_IA + i,dev->dev_addr[i] | (dev->dev_addr[i + 1] << 8));
+
+	return (0);
+}
+
+EXPORT_NO_SYMBOLS;
+
+static struct net_device dev;
+
+static int __init cirrus_init (void)
+{
+	memset (&dev,0,sizeof (struct net_device));
+	dev.init = cirrus_probe;
+	return (register_netdev (&dev));
+}
+
+static void __exit cirrus_cleanup (void)
+{
+	release_region (dev.base_addr,16);
+	unregister_netdev (&dev);
+}
+
+MODULE_AUTHOR ("Abraham van der Merwe <abraham@2d3d.co.za>");
+MODULE_DESCRIPTION ("Cirrus Logic CS8900A driver for Linux (V0.02)");
+MODULE_LICENSE ("GPL");
+MODULE_PARM_DESC (io,"I/O Base Address");
+MODULE_PARM (io,"i");
+MODULE_PARM_DESC (irq,"IRQ Number");
+MODULE_PARM (irq,"i");
+
+module_init (cirrus_init);
+module_exit (cirrus_cleanup);
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/cirrus.h linux-2.4.21-pre6/drivers/net/cirrus.h
--- linux-2.4.20/drivers/net/cirrus.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/cirrus.h	2003-03-26 23:49:39.000000000 +0000
@@ -0,0 +1,235 @@
+#ifndef CIRRUS_H
+#define CIRRUS_H
+
+/*
+ * linux/drivers/net/cirrus.h
+ *
+ * Author: Abraham van der Merwe <abraham@2d3d.co.za>
+ *
+ * A Cirrus Logic CS8900A driver for Linux
+ * based on the cs89x0 driver written by Russell Nelson,
+ * Donald Becker, and others.
+ *
+ * This source code is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+/*
+ * Ports
+ */
+
+#define PP_Address		0x0a	/* PacketPage Pointer Port (Section 4.10.10) */
+#define PP_Data			0x0c	/* PacketPage Data Port (Section 4.10.10) */
+
+/*
+ * Registers
+ */
+
+#define PP_ProductID		0x0000	/* Section 4.3.1   Product Identification Code */
+#define PP_MemBase			0x002c	/* Section 4.9.2   Memory Base Address Register */
+#define PP_IntNum			0x0022	/* Section 3.2.3   Interrupt Number */
+#define PP_EEPROMCommand	0x0040	/* Section 4.3.11  EEPROM Command */
+#define PP_EEPROMData		0x0042	/* Section 4.3.12  EEPROM Data */
+#define PP_RxCFG			0x0102	/* Section 4.4.6   Receiver Configuration */
+#define PP_RxCTL			0x0104	/* Section 4.4.8   Receiver Control */
+#define PP_TxCFG			0x0106	/* Section 4.4.9   Transmit Configuration */
+#define PP_BufCFG			0x010a	/* Section 4.4.12  Buffer Configuration */
+#define PP_LineCTL			0x0112	/* Section 4.4.16  Line Control */
+#define PP_SelfCTL			0x0114	/* Section 4.4.18  Self Control */
+#define PP_BusCTL			0x0116	/* Section 4.4.20  Bus Control */
+#define PP_TestCTL			0x0118	/* Section 4.4.22  Test Control */
+#define PP_ISQ				0x0120	/* Section 4.4.5   Interrupt Status Queue */
+#define PP_TxEvent			0x0128	/* Section 4.4.10  Transmitter Event */
+#define PP_BufEvent			0x012c	/* Section 4.4.13  Buffer Event */
+#define PP_RxMISS			0x0130	/* Section 4.4.14  Receiver Miss Counter */
+#define PP_TxCOL			0x0132	/* Section 4.4.15  Transmit Collision Counter */
+#define PP_SelfST			0x0136	/* Section 4.4.19  Self Status */
+#define PP_BusST			0x0138	/* Section 4.4.21  Bus Status */
+#define PP_TxCMD			0x0144	/* Section 4.4.11  Transmit Command */
+#define PP_TxLength			0x0146	/* Section 4.5.2   Transmit Length */
+#define PP_IA				0x0158	/* Section 4.6.2   Individual Address (IEEE Address) */
+#define PP_RxStatus			0x0400	/* Section 4.7.1   Receive Status */
+#define PP_RxLength			0x0402	/* Section 4.7.1   Receive Length (in bytes) */
+#define PP_RxFrame			0x0404	/* Section 4.7.2   Receive Frame Location */
+#define PP_TxFrame			0x0a00	/* Section 4.7.2   Transmit Frame Location */
+
+/*
+ * Values
+ */
+
+/* PP_IntNum */
+#define INTRQ0			0x0000
+#define INTRQ1			0x0001
+#define INTRQ2			0x0002
+#define INTRQ3			0x0003
+
+/* PP_ProductID */
+#define EISA_REG_CODE	0x630e
+#define REVISION(x)		(((x) & 0x1f00) >> 8)
+#define VERSION(x)		((x) & ~0x1f00)
+
+#define CS8900A			0x0000
+#define REV_B			7
+#define REV_C			8
+#define REV_D			9
+
+/* PP_RxCFG */
+#define Skip_1			0x0040
+#define StreamE			0x0080
+#define RxOKiE			0x0100
+#define RxDMAonly		0x0200
+#define AutoRxDMAE		0x0400
+#define BufferCRC		0x0800
+#define CRCerroriE		0x1000
+#define RuntiE			0x2000
+#define ExtradataiE		0x4000
+
+/* PP_RxCTL */
+#define IAHashA			0x0040
+#define PromiscuousA	0x0080
+#define RxOKA			0x0100
+#define MulticastA		0x0200
+#define IndividualA		0x0400
+#define BroadcastA		0x0800
+#define CRCerrorA		0x1000
+#define RuntA			0x2000
+#define ExtradataA		0x4000
+
+/* PP_TxCFG */
+#define Loss_of_CRSiE	0x0040
+#define SQErroriE		0x0080
+#define TxOKiE			0x0100
+#define Out_of_windowiE	0x0200
+#define JabberiE		0x0400
+#define AnycolliE		0x0800
+#define T16colliE		0x8000
+
+/* PP_BufCFG */
+#define SWint_X			0x0040
+#define RxDMAiE			0x0080
+#define Rdy4TxiE		0x0100
+#define TxUnderruniE	0x0200
+#define RxMissiE		0x0400
+#define Rx128iE			0x0800
+#define TxColOvfiE		0x1000
+#define MissOvfloiE		0x2000
+#define RxDestiE		0x8000
+
+/* PP_LineCTL */
+#define SerRxON			0x0040
+#define SerTxON			0x0080
+#define AUIonly			0x0100
+#define AutoAUI_10BT	0x0200
+#define ModBackoffE		0x0800
+#define PolarityDis		0x1000
+#define L2_partDefDis	0x2000
+#define LoRxSquelch		0x4000
+
+/* PP_SelfCTL */
+#define RESET			0x0040
+#define SWSuspend		0x0100
+#define HWSleepE		0x0200
+#define HWStandbyE		0x0400
+#define HC0E			0x1000
+#define HC1E			0x2000
+#define HCB0			0x4000
+#define HCB1			0x8000
+
+/* PP_BusCTL */
+#define ResetRxDMA		0x0040
+#define DMAextend		0x0100
+#define UseSA			0x0200
+#define MemoryE			0x0400
+#define DMABurst		0x0800
+#define IOCHRDYE		0x1000
+#define RxDMAsize		0x2000
+#define EnableRQ		0x8000
+
+/* PP_TestCTL */
+#define DisableLT		0x0080
+#define ENDECloop		0x0200
+#define AUIloop			0x0400
+#define DisableBackoff	0x0800
+#define FDX				0x4000
+
+/* PP_ISQ */
+#define RegNum(x) ((x) & 0x3f)
+#define RegContent(x) ((x) & ~0x3d)
+
+#define RxEvent			0x0004
+#define TxEvent			0x0008
+#define BufEvent		0x000c
+#define RxMISS			0x0010
+#define TxCOL			0x0012
+
+/* PP_RxStatus */
+#define IAHash			0x0040
+#define Dribblebits		0x0080
+#define RxOK			0x0100
+#define Hashed			0x0200
+#define IndividualAdr	0x0400
+#define Broadcast		0x0800
+#define CRCerror		0x1000
+#define Runt			0x2000
+#define Extradata		0x4000
+
+#define HashTableIndex(x) ((x) >> 0xa)
+
+/* PP_TxCMD */
+#define After5			0
+#define After381		1
+#define After1021		2
+#define AfterAll		3
+#define TxStart(x) ((x) << 6)
+
+#define Force			0x0100
+#define Onecoll			0x0200
+#define InhibitCRC		0x1000
+#define TxPadDis		0x2000
+
+/* PP_BusST */
+#define TxBidErr		0x0080
+#define Rdy4TxNOW		0x0100
+
+/* PP_TxEvent */
+#define Loss_of_CRS		0x0040
+#define SQEerror		0x0080
+#define TxOK			0x0100
+#define Out_of_window	0x0200
+#define Jabber			0x0400
+#define T16coll			0x8000
+
+#define TX_collisions(x) (((x) >> 0xb) & ~0x8000)
+
+/* PP_BufEvent */
+#define SWint			0x0040
+#define RxDMAFrame		0x0080
+#define Rdy4Tx			0x0100
+#define TxUnderrun		0x0200
+#define RxMiss			0x0400
+#define Rx128			0x0800
+#define RxDest			0x8000
+
+/* PP_RxMISS */
+#define MissCount(x) ((x) >> 6)
+
+/* PP_TxCOL */
+#define ColCount(x) ((x) >> 6)
+
+/* PP_SelfST */
+#define T3VActive		0x0040
+#define INITD			0x0080
+#define SIBUSY			0x0100
+#define EEPROMpresent	0x0200
+#define EEPROMOK		0x0400
+#define ELpresent		0x0800
+#define EEsize			0x1000
+
+/* PP_EEPROMCommand */
+#define EEWriteRegister	0x0100
+#define EEReadRegister	0x0200
+#define EEEraseRegister	0x0300
+#define ELSEL			0x0400
+
+#endif	/* #ifndef CIRRUS_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/daynaport.c linux-2.4.21-pre6/drivers/net/daynaport.c
--- linux-2.4.20/drivers/net/daynaport.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/daynaport.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,922 +0,0 @@
-/* daynaport.c: A Macintosh 8390 based ethernet driver for linux. */
-/*
-	Derived from code:
-	
-	Written 1993-94 by Donald Becker.
-
-	Copyright 1993 United States Government as represented by the
-	Director, National Security Agency.
-
-	This software may be used and distributed according to the terms
-	of the GNU General Public License, incorporated herein by reference.
-
-	    TODO:
-
-	    The block output routines may be wrong for non Dayna
-	    cards
-
-		Fix this driver so that it will attempt to use the info
-		(i.e. iobase, iosize) given to it by the new and improved
-		NuBus code.
-
-		Despite its misleading filename, this driver is not Dayna-specific
-		anymore. */
-/* Cabletron E6100 card support added by Tony Mantler (eek@escape.ca) April 1999 */
-
-static const char *version =
-	"daynaport.c: v0.02 1999-05-17 Alan Cox (Alan.Cox@linux.org) and others\n";
-static int version_printed;
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/nubus.h>
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/hwtest.h>
-#include <asm/macints.h>
-#include <linux/delay.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include "8390.h"
-
-static int ns8390_probe1(struct net_device *dev, int word16, char *name, int id,
-				  int prom, struct nubus_dev *ndev);
-
-static int ns8390_open(struct net_device *dev);
-static void ns8390_no_reset(struct net_device *dev);
-static int ns8390_close_card(struct net_device *dev);
-
-/* Interlan */
-static void interlan_reset(struct net_device *dev);
-
-/* Dayna */
-static void dayna_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
-						int ring_page);
-static void dayna_block_input(struct net_device *dev, int count,
-						  struct sk_buff *skb, int ring_offset);
-static void dayna_block_output(struct net_device *dev, int count,
-						   const unsigned char *buf, const int start_page);
-
-/* Sane (32-bit chunk memory read/write) */
-static void sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
-						int ring_page);
-static void sane_block_input(struct net_device *dev, int count,
-						  struct sk_buff *skb, int ring_offset);
-static void sane_block_output(struct net_device *dev, int count,
-						   const unsigned char *buf, const int start_page);
-
-/* Slow Sane (16-bit chunk memory read/write) */
-static void slow_sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
-						int ring_page);
-static void slow_sane_block_input(struct net_device *dev, int count,
-						  struct sk_buff *skb, int ring_offset);
-static void slow_sane_block_output(struct net_device *dev, int count,
-						   const unsigned char *buf, const int start_page);
-
-
-#define WD_START_PG	0x00	/* First page of TX buffer */
-#define WD03_STOP_PG	0x20	/* Last page +1 of RX ring */
-#define WD13_STOP_PG	0x40	/* Last page +1 of RX ring */
-
-#define CABLETRON_RX_START_PG          0x00    /* First page of RX buffer */
-#define CABLETRON_RX_STOP_PG           0x30    /* Last page +1 of RX ring */
-#define CABLETRON_TX_START_PG          CABLETRON_RX_STOP_PG  /* First page of TX buffer */
-
-
-#define DAYNA_MAC_BASE		0xf0007
-#define DAYNA_8390_BASE		0x80000 /* 3 */
-#define DAYNA_8390_MEM		0x00000
-#define DAYNA_MEMSIZE		0x04000	/* First word of each long ! */
-
-#define APPLE_8390_BASE		0xE0000
-#define APPLE_8390_MEM		0xD0000
-#define APPLE_MEMSIZE		8192    /* FIXME: need to dynamically check */
-
-#define KINETICS_MAC_BASE	0xf0004 /* first byte of each long */
-#define KINETICS_8390_BASE	0x80000
-#define KINETICS_8390_MEM	0x00000 /* first word of each long */
-#define KINETICS_MEMSIZE	8192    /* FIXME: need to dynamically check */
-/*#define KINETICS_MEMSIZE	(0x10000/2) * CSA: on the board I have, at least */
-
-#define CABLETRON_8390_BASE		0x90000	
-#define CABLETRON_8390_MEM		0x00000
-
-static int test_8390(volatile char *ptr, int scale)
-{
-	int regd;
-	int v;
-	
-	if(hwreg_present(&ptr[0x00])==0)
-		return -EIO;
-	if(hwreg_present(&ptr[0x0D<<scale])==0)
-		return -EIO;
-	if(hwreg_present(&ptr[0x0D<<scale])==0)
-		return -EIO;
-	ptr[0x00]=E8390_NODMA+E8390_PAGE1+E8390_STOP;
-	regd=ptr[0x0D<<scale];
-	ptr[0x0D<<scale]=0xFF;
-	ptr[0x00]=E8390_NODMA+E8390_PAGE0;
-	v=ptr[0x0D<<scale];
-	if(ptr[0x0D<<scale]!=0)
-	{
-		ptr[0x0D<<scale]=regd;
-		return -ENODEV;
-	}
-/*	printk("NS8390 found at %p scaled %d\n", ptr,scale);*/
-	return 0;
-}
-/*
- *    Identify the species of NS8390 card/driver we need
- */
-
-enum mac8390_type {
-	NS8390_DAYNA,
-	NS8390_INTERLAN,
-	NS8390_KINETICS,
-	NS8390_APPLE,
-	NS8390_FARALLON,
-	NS8390_ASANTE,
-	NS8390_CABLETRON
-};
-
-static int __init ns8390_ident(struct nubus_dev* ndev)
-{
-	/* This really needs to be tested and tested hard.  */
-		
-	/* Summary of what we know so far --
-	 * SW: 0x0104 -- asante,    16 bit, back4_offsets
-	 * SW: 0x010b -- daynaport, 16 bit, fwrd4_offsets
-	 * SW: 0x010c -- farallon,  16 bit, back4_offsets, no long word access
-	 * SW: 0x011a -- focus,     [no details yet]
-	 * SW: ?????? -- interlan,  16 bit, back4_offsets, funny reset
-	 * SW: ?????? -- kinetics,   8 bit, back4_offsets
-	 * -- so i've this hypothesis going that says DrSW&1 says whether the
-	 *    map is forward or backwards -- and maybe DrSW&256 says what the
-	 *    register spacing is -- for all cards that report a DrSW in some
-	 *    range.
-	 *    This would allow the "apple compatible" driver to drive many
-	 *    seemingly different types of cards.  More DrSW info is needed
-	 *    to investigate this properly. [CSA, 21-May-1999]
-	 */
-	/* Dayna ex Kinetics board */
-	if(ndev->dr_sw == NUBUS_DRSW_DAYNA)
-		return NS8390_DAYNA;
-	if(ndev->dr_sw == NUBUS_DRSW_ASANTE)
-		return NS8390_ASANTE;
-	if(ndev->dr_sw == NUBUS_DRSW_FARALLON) /* farallon or sonic systems */
-		return NS8390_FARALLON;
-	if(ndev->dr_sw == NUBUS_DRSW_KINETICS)
-		return NS8390_KINETICS;
-	/* My ATI Engineering card with this combination crashes the */
-	/* driver trying to xmit packets. Best not touch it for now. */
-	/*     - 1999-05-20 (funaho@jurai.org)                       */
-	if(ndev->dr_sw == NUBUS_DRSW_FOCUS)
-		return -1;
-
-	/* Check the HW on this one, because it shares the same DrSW as
-	   the on-board SONIC chips */
-	if(ndev->dr_hw == NUBUS_DRHW_CABLETRON)
-		return NS8390_CABLETRON;
-	/* does anyone have one of these? */
-	if(ndev->dr_hw == NUBUS_DRHW_INTERLAN)
-		return NS8390_INTERLAN;
-
-	/* FIXME: what do genuine Apple boards look like? */
-	return -1;
-}
-
-/*
- *	Memory probe for 8390 cards
- */
- 
-static int __init apple_8390_mem_probe(volatile unsigned short *p)
-{
-	int i, j;
-	/*
-	 *	Algorithm.
-	 *	1.	Check each block size of memory doesn't fault
-	 *	2.	Write a value to it
-	 *	3.	Check all previous blocks are unaffected
-	 */
-	
-	for(i=0;i<2;i++)
-	{
-		volatile unsigned short *m=p+4096*i;
-		/* Unwriteable - we have a fully decoded card and the
-		   RAM end located */
-		   
-		if(hwreg_present(m)==0)
-			return 8192*i;
-			
-		*m=0xA5A0|i;
-		
-		for(j=0;j<i;j++)
-		{
-			/* Partial decode and wrap ? */
-			if(p[4096*j]!=(0xA5A0|j))
-			{
-				/* This is the first misdecode, so it had
-				   one less page than we tried */
-				return 8192*i;
-			}
- 			j++;
- 		}
- 		/* Ok it still decodes.. move on 8K */
- 	}
- 	/* 
- 	 *	We don't look past 16K. That should cover most cards
- 	 *	and above 16K there isnt really any gain.
- 	 */
- 	return 16384;
- }
- 		
-/*
- *    Probe for 8390 cards.  
- *    The ns8390_probe1() routine initializes the card and fills the
- *    station address field.
- *
- *    The NuBus interface has changed!  We now scan for these somewhat
- *    like how the PCI and Zorro drivers do.  It's not clear whether
- *    this is actually better, but it makes things more consistent.
- *
- *    dev->mem_start points
- *    at the memory ring, dev->mem_end gives the end of it.
- */
-
-int __init mac8390_probe(struct net_device *dev)
-{
-	static int slots;
-	volatile unsigned short *i;
-	volatile unsigned char *p;
-	int plen;
-	int id;
-	static struct nubus_dev* ndev;
-
-	/* Find the first card that hasn't already been seen */
-	while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK,
-								   NUBUS_TYPE_ETHERNET, ndev)) != NULL) {
-		/* Have we seen it already? */
-		if (slots & (1<<ndev->board->slot))
-			continue;
-		slots |= 1<<ndev->board->slot;
-
-		/* Is it one of ours? */
-		if ((id = ns8390_ident(ndev)) != -1)
-			break;
-	}
-
-	/* Hm.  No more cards, then */
-	if (ndev == NULL)
-		return -ENODEV;
-
-	dev = init_etherdev(dev, 0);
-	if (!dev)
-		return -ENOMEM;
-	SET_MODULE_OWNER(dev);
-
-	if (!version_printed) {
-		printk(KERN_INFO "%s", version);
-		version_printed = 1;
-	}
-
-	/*
-	 *	Dayna specific init
-	 */
-	if(id==NS8390_DAYNA)
-	{
-		dev->base_addr = (int)(ndev->board->slot_addr+DAYNA_8390_BASE);
-		dev->mem_start = (int)(ndev->board->slot_addr+DAYNA_8390_MEM);
-		dev->mem_end = dev->mem_start+DAYNA_MEMSIZE; /* 8K it seems */
-	
-		printk(KERN_INFO "%s: daynaport. testing board: ", dev->name);
-			
-		printk("memory - ");	
-			
-		i = (void *)dev->mem_start;
-		memset((void *)i,0xAA, DAYNA_MEMSIZE);
-		while(i<(volatile unsigned short *)dev->mem_end)
-		{
-			if(*i!=0xAAAA)
-				goto membad;
-			*i=0x5678; /* make sure we catch byte smearing */
-			if(*i!=0x5678)
-				goto membad;
-			i+=2;	/* Skip a word */
-		}
-			
-		printk("controller - ");
-			
-		p=(void *)dev->base_addr;
-		plen=0;
-			
-		while(plen<0x3FF00)
-		{
-			if(test_8390(p,0)==0)
-				break;
-			if(test_8390(p,1)==0)
-				break;
-			if(test_8390(p,2)==0)
-				break;
-			if(test_8390(p,3)==0)
-				break;
-			plen++;
-			p++;
-		}
-		if(plen==0x3FF00)
-			goto membad;
-		printk("OK\n");
-		dev->irq = SLOT2IRQ(ndev->board->slot);
-		if(ns8390_probe1(dev, 0, "dayna", id, -1, ndev)==0)
-			return 0;
-	}
-	/* Cabletron */
-	if (id==NS8390_CABLETRON) {
-		int memsize = 16<<10; /* fix this */
-		  
-		dev->base_addr=(int)(ndev->board->slot_addr+CABLETRON_8390_BASE);
-		dev->mem_start=(int)(ndev->board->slot_addr+CABLETRON_8390_MEM);
-		dev->mem_end=dev->mem_start+memsize;
-		dev->irq = SLOT2IRQ(ndev->board->slot);
-		  
-		/* The base address is unreadable if 0x00 has been written to the command register */
-		/* Reset the chip by writing E8390_NODMA+E8390_PAGE0+E8390_STOP just to be sure */
-		i = (void *)dev->base_addr;
-		*i = 0x21;
-		  
-		printk(KERN_INFO "%s: cabletron: testing board: ", dev->name);
-		printk("%dK memory - ", memsize>>10);		
-		i=(void *)dev->mem_start;
-		while(i<(volatile unsigned short *)(dev->mem_start+memsize))
-		{
-			*i=0xAAAA;
-			if(*i!=0xAAAA)
-				goto membad;
-			*i=0x5555;
-			if(*i!=0x5555)
-				goto membad;
-			i+=2;	/* Skip a word */
-		}
-		printk("OK\n");
-		  
-		if(ns8390_probe1(dev, 1, "cabletron", id, -1, ndev)==0)
-			return 0;
-	}
-	/* Apple, Farallon, Asante */
-	if(id==NS8390_APPLE || id==NS8390_FARALLON || id==NS8390_ASANTE)
-	{
-		int memsize;
-			
-		dev->base_addr=(int)(ndev->board->slot_addr+APPLE_8390_BASE);
-		dev->mem_start=(int)(ndev->board->slot_addr+APPLE_8390_MEM);
-			
-		memsize = apple_8390_mem_probe((void *)dev->mem_start);
-			
-		dev->mem_end=dev->mem_start+memsize;
-		dev->irq = SLOT2IRQ(ndev->board->slot);
-			
-		switch(id)
-		{
-		case NS8390_FARALLON:
-			printk(KERN_INFO "%s: farallon: testing board: ", dev->name);
-			break;
-		case NS8390_ASANTE:
-			printk(KERN_INFO "%s: asante: testing board: ", dev->name);
-			break;
-		case NS8390_APPLE:
-		default:
-			printk(KERN_INFO "%s: apple/clone: testing board: ", dev->name);
-			break;
-		}
-			
-		printk("%dK memory - ", memsize>>10);		
-			
-		i=(void *)dev->mem_start;
-		memset((void *)i,0xAA, memsize);
-		while(i<(volatile unsigned short *)dev->mem_end)
-		{
-			if(*i!=0xAAAA)
-				goto membad;
-			*i=0x5555;
-			if(*i!=0x5555)
-				goto membad;
-			i+=2;	/* Skip a word */
-		}
-		printk("OK\n");
-			
-		switch (id)
-		{
-		case NS8390_FARALLON:
-			if(ns8390_probe1(dev, 1, "farallon", id, -1, ndev)==0)
-				return 0;
-			break;
-		case NS8390_ASANTE:
-			if(ns8390_probe1(dev, 1, "asante", id, -1, ndev)==0)
-				return 0;
-			break;
-		case NS8390_APPLE:
-		default:
-			if(ns8390_probe1(dev, 1, "apple/clone", id, -1, ndev)==0)
-				return 0;
-			break;
-		}
-	}
-	/* Interlan */
-	if(id==NS8390_INTERLAN)
-	{
-		/* As apple and asante */
-		dev->base_addr=(int)(ndev->board->slot_addr+APPLE_8390_BASE);
-		dev->mem_start=(int)(ndev->board->slot_addr+APPLE_8390_MEM);
-		dev->mem_end=dev->mem_start+APPLE_MEMSIZE; /* 8K it seems */
-		dev->irq = SLOT2IRQ(ndev->board->slot);
-		if(ns8390_probe1(dev, 1, "interlan", id, -1, ndev)==0)
-			return 0;
-	}
-	/* Kinetics (Shiva Etherport) */
-	if(id==NS8390_KINETICS)
-	{
-		dev->base_addr=(int)(ndev->board->slot_addr+KINETICS_8390_BASE);
-		dev->mem_start=(int)(ndev->board->slot_addr+KINETICS_8390_MEM);
-		dev->mem_end=dev->mem_start+KINETICS_MEMSIZE; /* 8K it seems */
-		dev->irq = SLOT2IRQ(ndev->board->slot);
-		if(ns8390_probe1(dev, 0, "kinetics", id, -1, ndev)==0)
-			return 0;
-	}
-
-	/* We should hopefully not get here */
-	printk(KERN_ERR "Probe unsuccessful.\n");
-	return -ENODEV;
-
- membad:
-	printk(KERN_ERR "failed at %p in %p - %p.\n", i,
-		   (void *)dev->mem_start, (void *)dev->mem_end);
-	return -ENODEV;
-}
-
-static int __init mac8390_ethernet_addr(struct nubus_dev* ndev, unsigned char addr[6])
-{
-	struct nubus_dir dir;
-	struct nubus_dirent ent;
-
-	/* Get the functional resource for this device */
-	if (nubus_get_func_dir(ndev, &dir) == -1)
-		return -1;
-	if (nubus_find_rsrc(&dir, NUBUS_RESID_MAC_ADDRESS, &ent) == -1)
-		return -1;
-	
-	nubus_get_rsrc_mem(addr, &ent, 6);
-	return 0;
-}
-
-static int __init ns8390_probe1(struct net_device *dev, int word16, char *model_name,
-			 	int type, int promoff, struct nubus_dev *ndev)
-{
-	static u32 fwrd4_offsets[16]={
-		0,      4,      8,      12,
-		16,     20,     24,     28,
-		32,     36,     40,     44,
-		48,     52,     56,     60
-	};
-	static u32 back4_offsets[16]={
-		60,     56,     52,     48,
-		44,     40,     36,     32,
-		28,     24,     20,     16,
-		12,     8,      4,      0
-	};
-	static u32 fwrd2_offsets[16]={
-		0,      2,      4,      6,
-		8,     10,     12,     14,
-		16,    18,     20,     22,
-		24,    26,     28,     30
-	};
-
-	unsigned char *prom = (unsigned char*) ndev->board->slot_addr + promoff;
-
-	/* Allocate dev->priv and fill in 8390 specific dev fields. */
-	if (ethdev_init(dev)) 
-	{	
-		printk ("%s: unable to get memory for dev->priv.\n", dev->name);
-		return -ENOMEM;
-	}
-
-	/* OK, we are certain this is going to work.  Setup the device. */
-
-	ei_status.name = model_name;
-	ei_status.word16 = word16;
-
-       if (type==NS8390_CABLETRON) {
-               /* Cabletron card puts the RX buffer before the TX buffer */
-               ei_status.tx_start_page = CABLETRON_TX_START_PG;
-               ei_status.rx_start_page = CABLETRON_RX_START_PG;
-               ei_status.stop_page = CABLETRON_RX_STOP_PG;
-               dev->rmem_start = dev->mem_start;
-               dev->rmem_end = dev->mem_start + CABLETRON_RX_STOP_PG*256;
-       } else {
-               ei_status.tx_start_page = WD_START_PG;
-               ei_status.rx_start_page = WD_START_PG + TX_PAGES;
-               ei_status.stop_page = (dev->mem_end - dev->mem_start)/256;
-               dev->rmem_start = dev->mem_start + TX_PAGES*256;
-               dev->rmem_end = dev->mem_end;
-       }
-	
-	if(promoff==-1)		/* Use nubus resources ? */
-	{
-		if(mac8390_ethernet_addr(ndev, dev->dev_addr))
-		{
-		  printk("mac_ns8390: MAC address not in resources!\n");
-		  return -ENODEV;
-		}
-	}
-	else			/* Pull it off the card */
-	{
-		int i=0;
-		int x=1;
-		/* These should go in the end I hope */
-		if(type==NS8390_DAYNA)
-			x=2;
-		if(type==NS8390_INTERLAN || type==NS8390_KINETICS)
-			x=4;
-		while(i<6)
-		{
-			dev->dev_addr[i]=*prom;
-			prom+=x;
-			if(i)
-				printk(":");
-			printk("%02X",dev->dev_addr[i++]);
-		}
-	}
-
-	printk(KERN_INFO "%s: %s in slot %X (type %s)\n",
-		   dev->name, ndev->board->name, ndev->board->slot, model_name);
-	printk(KERN_INFO "MAC ");
-	{
-		int i;
-		for (i = 0; i < 6; i++) {
-			printk("%2.2x", dev->dev_addr[i]);
-			if (i < 5)
-				printk(":");
-		}
-	}
-	printk(" IRQ %d, shared memory at %#lx-%#lx.\n",
-		   dev->irq, dev->mem_start, dev->mem_end-1);
-
-	switch(type)
-	{
-		case NS8390_DAYNA:      /* Dayna card */
-		case NS8390_KINETICS:   /* Kinetics --  8 bit config, but 16 bit mem */
-			/* 16 bit, 4 word offsets */
-			ei_status.reset_8390 = &ns8390_no_reset;
-			ei_status.block_input = &dayna_block_input;
-			ei_status.block_output = &dayna_block_output;
-			ei_status.get_8390_hdr = &dayna_get_8390_hdr;
-			ei_status.reg_offset = fwrd4_offsets;
-			break;
-		case NS8390_CABLETRON: /* Cabletron */
-			/*		16 bit card, register map is short forward */
-			ei_status.reset_8390 = &ns8390_no_reset;
-			/* Ctron card won't accept 32bit values read or written to it */
-			ei_status.block_input = &slow_sane_block_input;
-			ei_status.block_output = &slow_sane_block_output;
-			ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
-			ei_status.reg_offset = fwrd2_offsets;
-			break;
-		case NS8390_FARALLON:
-		case NS8390_APPLE:	/* Apple/Asante/Farallon */
-			/*      16 bit card, register map is reversed */
-			ei_status.reset_8390 = &ns8390_no_reset;
-			ei_status.block_input = &slow_sane_block_input;
-			ei_status.block_output = &slow_sane_block_output;
-			ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
-			ei_status.reg_offset = back4_offsets;
-			break;
-		case NS8390_ASANTE:
-			/*      16 bit card, register map is reversed */
-			ei_status.reset_8390 = &ns8390_no_reset;
-			ei_status.block_input = &sane_block_input;
-			ei_status.block_output = &sane_block_output;
-			ei_status.get_8390_hdr = &sane_get_8390_hdr;
-			ei_status.reg_offset = back4_offsets;
-			break;
-		case NS8390_INTERLAN:   /* Interlan */
-			/*      16 bit card, map is forward */
-			ei_status.reset_8390 = &interlan_reset;
-			ei_status.block_input = &sane_block_input;
-			ei_status.block_output = &sane_block_output;
-			ei_status.get_8390_hdr = &sane_get_8390_hdr;
-			ei_status.reg_offset = back4_offsets;
-			break;
-#if 0 /* i think this suffered code rot.  my kinetics card has much
-	   * different settings.  -- CSA [22-May-1999] */
-		case NS8390_KINETICS:   /* Kinetics */
-			/*      8bit card, map is forward */
-			ei_status.reset_8390 = &ns8390_no_reset;
-			ei_status.block_input = &sane_block_input;
-			ei_status.block_output = &sane_block_output;
-			ei_status.get_8390_hdr = &sane_get_8390_hdr;
-			ei_status.reg_offset = back4_offsets;
-			break;
-#endif
-		default:
-			panic("Detected a card I can't drive - whoops\n");
-	}
-	dev->open = &ns8390_open;
-	dev->stop = &ns8390_close_card;
-
-	NS8390_init(dev, 0);
-
-	return 0;
-}
-
-static int ns8390_open(struct net_device *dev)
-{
-	int ret;
-
-	ei_open(dev);
-
-	/* At least on my card (a Focus Enhancements PDS card) I start */
-	/* getting interrupts right away, so the driver needs to be    */
-	/* completely initialized before enabling the interrupt.        */
-	/*                             - funaho@jurai.org (1999-05-17) */
-
-	/* Non-slow interrupt, works around issues with the SONIC driver */
-	ret = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev); 
-	if (ret) {
-		printk ("%s: unable to get IRQ %d.\n", dev->name, dev->irq);
-		return ret;
-	}
-	return 0;
-}
-
-static void ns8390_no_reset(struct net_device *dev)
-{
-	if (ei_debug > 1) 
-		printk("Need to reset the NS8390 t=%lu...", jiffies);
-	ei_status.txing = 0;
-	if (ei_debug > 1) printk("reset not supported\n");
-}
-
-static int ns8390_close_card(struct net_device *dev)
-{
-	if (ei_debug > 1)
-		printk("%s: Shutting down ethercard.\n", dev->name);
-	free_irq(dev->irq, dev);
-	ei_close(dev);
-	return 0;
-}
-
-/*
- *    Interlan Specific Code Starts Here
- */
-
-static void interlan_reset(struct net_device *dev)
-{
-	unsigned char *target=nubus_slot_addr(IRQ2SLOT(dev->irq));
-	if (ei_debug > 1) 
-		printk("Need to reset the NS8390 t=%lu...", jiffies);
-	ei_status.txing = 0;
-	/* This write resets the card */
-	target[0xC0000]=0;
-	if (ei_debug > 1) printk("reset complete\n");
-	return;
-}
-
-/*
- *    Daynaport code (some is used by other drivers)
- */
-
-
-/* Grab the 8390 specific header. Similar to the block_input routine, but
-   we don't need to be concerned with ring wrap as the header will be at
-   the start of a page, so we optimize accordingly. */
-
-
-/* Block input and output are easy on shared memory ethercards, and trivial
-   on the Daynaport card where there is no choice of how to do it.
-   The only complications are that the ring buffer wraps.
-*/
-
-static void dayna_memcpy_fromcard(struct net_device *dev, void *to, int from, int count)
-{
-	volatile unsigned short *ptr;
-	unsigned short *target=to;
-	from<<=1;	/* word, skip overhead */
-	ptr=(unsigned short *)(dev->mem_start+from);
-	/*
-	 * Leading byte?
-	 */
-	if (from&2) {
-		*((char *)target)++ = *(((char *)ptr++)-1);
-		count--;
-	}
-	while(count>=2)
-	{
-		*target++=*ptr++;	/* Copy and */
-		ptr++;			/* skip cruft */
-		count-=2;
-	}
-	/*
-	 *	Trailing byte ?
-	 */
-	if(count)
-	{
-		/* Big endian */
-		unsigned short v=*ptr;
-		*((char *)target)=v>>8;
-	}
-}
-
-static void dayna_memcpy_tocard(struct net_device *dev, int to, const void *from, int count)
-{
-	volatile unsigned short *ptr;
-	const unsigned short *src=from;
-	to<<=1;	/* word, skip overhead */
-	ptr=(unsigned short *)(dev->mem_start+to);
-	/*
-	 * Leading byte?
-	 */
-	if (to&2) { /* avoid a byte write (stomps on other data) */
-		ptr[-1] = (ptr[-1]&0xFF00)|*((unsigned char *)src)++;
-		ptr++;
-		count--;
-	}
-	while(count>=2)
-	{
-		*ptr++=*src++;		/* Copy and */
-		ptr++;			/* skip cruft */
-		count-=2;
-	}
-	/*
-	 *	Trailing byte ?
-	 */
-	if(count)
-	{
-		/* Big endian */
-		unsigned short v=*src;
-		/* card doesn't like byte writes */
-		*ptr=(*ptr&0x00FF)|(v&0xFF00);
-	}
-}
-
-static void dayna_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
-{
-	unsigned long hdr_start = (ring_page - WD_START_PG)<<8;
-	dayna_memcpy_fromcard(dev, (void *)hdr, hdr_start, 4);
-	/* Register endianism - fix here rather than 8390.c */
-	hdr->count=(hdr->count&0xFF)<<8|(hdr->count>>8);
-}
-
-static void dayna_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
-{
-	unsigned long xfer_base = ring_offset - (WD_START_PG<<8);
-	unsigned long xfer_start = xfer_base+dev->mem_start;
-
-	/*
-	 *	Note the offset maths is done in card memory space which
-	 *	is word per long onto our space.
-	 */
-	 
-	if (xfer_start + count > dev->rmem_end) 
-	{
-		/* We must wrap the input move. */
-		int semi_count = dev->rmem_end - xfer_start;
-		dayna_memcpy_fromcard(dev, skb->data, xfer_base, semi_count);
-		count -= semi_count;
-		dayna_memcpy_fromcard(dev, skb->data + semi_count, 
-			dev->rmem_start - dev->mem_start, count);
-	}
-	else
-	{
-		dayna_memcpy_fromcard(dev, skb->data, xfer_base, count);
-	}
-}
-
-static void dayna_block_output(struct net_device *dev, int count, const unsigned char *buf,
-				int start_page)
-{
-	long shmem = (start_page - WD_START_PG)<<8;
-	
-	dayna_memcpy_tocard(dev, shmem, buf, count);
-}
-
-/*
- *	Cards with full width memory
- */
-
-
-static void sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
-{
-	unsigned long hdr_start = (ring_page - WD_START_PG)<<8;
-	memcpy((void *)hdr, (char *)dev->mem_start+hdr_start, 4);
-	/* Register endianism - fix here rather than 8390.c */
-	hdr->count=(hdr->count&0xFF)<<8|(hdr->count>>8);
-}
-
-static void sane_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
-{
-	unsigned long xfer_base = ring_offset - (WD_START_PG<<8);
-	unsigned long xfer_start = xfer_base+dev->mem_start;
-
-	if (xfer_start + count > dev->rmem_end) 
-	{
-		/* We must wrap the input move. */
-		int semi_count = dev->rmem_end - xfer_start;
-		memcpy(skb->data, (char *)dev->mem_start+xfer_base, semi_count);
-		count -= semi_count;
-		memcpy(skb->data + semi_count, 
-			(char *)dev->rmem_start, count);
-	}
-	else
-	{
-		memcpy(skb->data, (char *)dev->mem_start+xfer_base, count);
-	}
-}
-
-
-static void sane_block_output(struct net_device *dev, int count, const unsigned char *buf,
-				int start_page)
-{
-	long shmem = (start_page - WD_START_PG)<<8;
-	
-	memcpy((char *)dev->mem_start+shmem, buf, count);
-}
-
-static void word_memcpy_tocard(void *tp, const void *fp, int count)
-{
-	volatile unsigned short *to = tp;
-	const unsigned short *from = fp;
-	
-	count++;
-	count/=2;
-	
-	while(count--)
-		*to++=*from++;
-}
-
-static void word_memcpy_fromcard(void *tp, const void *fp, int count)
-{
-	unsigned short *to = tp;
-	const volatile unsigned short *from = fp;
-	
-	count++;
-	count/=2;
-	
-	while(count--)
-		*to++=*from++;
-}
-
-static void slow_sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
-{
-	unsigned long hdr_start = (ring_page - WD_START_PG)<<8;
-	word_memcpy_fromcard((void *)hdr, (char *)dev->mem_start+hdr_start, 4);
-	/* Register endianism - fix here rather than 8390.c */
-	hdr->count=(hdr->count&0xFF)<<8|(hdr->count>>8);
-}
-
-static void slow_sane_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
-{
-	unsigned long xfer_base = ring_offset - (WD_START_PG<<8);
-	unsigned long xfer_start = xfer_base+dev->mem_start;
-
-	if (xfer_start + count > dev->rmem_end) 
-	{
-		/* We must wrap the input move. */
-		int semi_count = dev->rmem_end - xfer_start;
-		word_memcpy_fromcard(skb->data, (char *)dev->mem_start+xfer_base, semi_count);
-		count -= semi_count;
-		word_memcpy_fromcard(skb->data + semi_count, 
-			(char *)dev->rmem_start, count);
-	}
-	else
-	{
-		word_memcpy_fromcard(skb->data, (char *)dev->mem_start+xfer_base, count);
-	}
-}
-
-static void slow_sane_block_output(struct net_device *dev, int count, const unsigned char *buf,
-				int start_page)
-{
-	long shmem = (start_page - WD_START_PG)<<8;
-	
-	word_memcpy_tocard((char *)dev->mem_start+shmem, buf, count);
-#if 0
-	long shmem = (start_page - WD_START_PG)<<8;
-	volatile unsigned short *to=(unsigned short *)(dev->mem_start+shmem);
-	volatile int p;
-	unsigned short *bp=(unsigned short *)buf;
-	
-	count=(count+1)/2;
-	
-	while(count--)
-	{
-		*to++=*bp++;
-		for(p=0;p<10;p++)
-			p++;
-	}
-#endif	
-}
-
-MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/de4x5.c linux-2.4.21-pre6/drivers/net/de4x5.c
--- linux-2.4.20/drivers/net/de4x5.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/de4x5.c	2003-03-26 23:48:58.000000000 +0000
@@ -1229,6 +1229,7 @@
 	lp->pdev = pdev;
 	memcpy((char *)&lp->srom,(char *)&bus.srom,sizeof(struct de4x5_srom));
 	lp->lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
+	init_timer(&lp->timer);
 	de4x5_parse_params(dev);
 
 	/*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/de600.c linux-2.4.21-pre6/drivers/net/de600.c
--- linux-2.4.20/drivers/net/de600.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/de600.c	2003-03-26 23:49:34.000000000 +0000
@@ -403,6 +403,7 @@
 	int	len;
 	int	tickssofar;
 	byte	*buffer = skb->data;
+	int	i;
 
 	if (free_tx_pages <= 0) {	/* Do timeouts, to avoid hangs. */
 		tickssofar = jiffies - dev->trans_start;
@@ -447,8 +448,10 @@
 #endif
 
 	de600_setup_address(transmit_from, RW_ADDR);
-	for ( ; len > 0; --len, ++buffer)
+	for (i = 0;  i < skb->len ; ++i, ++buffer)
 		de600_put_byte(*buffer);
+	for (; i < len; ++i)
+		de600_put_byte(0);
 
 	if (free_tx_pages-- == TX_PAGES) { /* No transmission going on */
 		dev->trans_start = jiffies;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/de620.c linux-2.4.21-pre6/drivers/net/de620.c
--- linux-2.4.20/drivers/net/de620.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/de620.c	2003-03-26 23:48:57.000000000 +0000
@@ -316,7 +316,7 @@
 }
 
 static inline void
-de620_write_block(struct net_device *dev, byte *buffer, int count)
+de620_write_block(struct net_device *dev, byte *buffer, int count, int pad)
 {
 #ifndef LOWSPEED
 	byte uflip = NIC_Cmd ^ (DS0 | DS1);
@@ -335,6 +335,9 @@
 	for ( ; count > 0; --count, ++buffer) {
 		de620_put_byte(dev,*buffer);
 	}
+	for ( count = pad ; count > 0; --count, ++buffer) {
+		de620_put_byte(dev, 0);
+	}
 	de620_send_command(dev,W_DUMMY);
 #ifdef COUNT_LOOPS
 	/* trial debug output: loops per byte in de620_ready() */
@@ -576,7 +579,7 @@
 		restore_flags(flags);
 		return 1;
 	}
-	de620_write_block(dev, buffer, len);
+	de620_write_block(dev, buffer, skb->len, len-skb->len);
 
 	dev->trans_start = jiffies;
 	if(!(using_txbuf == (TXBF0 | TXBF1)))
@@ -850,12 +853,6 @@
 		return -ENODEV;
 	}
 
-#if 0 /* Not yet */
-	if (check_region(dev->base_addr, 3)) {
-		printk(", port 0x%x busy\n", dev->base_addr);
-		return -EBUSY;
-	}
-#endif
 	if (!request_region(dev->base_addr, 3, "de620")) {
 		printk(KERN_ERR "io 0x%3lX, which is busy.\n", dev->base_addr);
 		return -EBUSY;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/declance.c linux-2.4.21-pre6/drivers/net/declance.c
--- linux-2.4.20/drivers/net/declance.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/declance.c	2003-03-26 23:48:58.000000000 +0000
@@ -870,7 +870,15 @@
 
 	skblen = skb->len;
 
-	len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen;
+	len = skblen;
+	
+	if(len < ETH_ZLEN)
+	{
+		skb = skb_padto(skb, ETH_ZLEN);
+		if(skb == NULL)
+			return 0;
+		len = ETH_ZLEN;
+	}
 
 	lp->stats.tx_bytes += len;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/depca.c linux-2.4.21-pre6/drivers/net/depca.c
--- linux-2.4.20/drivers/net/depca.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/depca.c	2003-03-26 23:49:39.000000000 +0000
@@ -862,6 +862,13 @@
 	if (skb->len < 1)
 		goto out;
 
+	if(skb->len < ETH_ZLEN)
+	{
+		skb = skb_padto(skb, ETH_ZLEN);
+		if(skb == NULL)
+			goto out;
+	}
+	
 	netif_stop_queue(dev);
 
 	if (TX_BUFFS_AVAIL) {	/* Fill in a Tx ring entry */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/dl2k.c linux-2.4.21-pre6/drivers/net/dl2k.c
--- linux-2.4.20/drivers/net/dl2k.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/dl2k.c	2003-03-26 23:49:31.000000000 +0000
@@ -30,17 +30,32 @@
     1.09	2002/03/07	Move rx-poll-now to re-fill loop.	
     				Added rio_timer() to watch rx buffers. 
     1.10	2002/04/16	Fixed miscount of carrier error.
-    1.11	2002/05/23	Added ISR schedule scheme.
+    1.11	2002/05/23	Added ISR schedule scheme
     				Fixed miscount of rx frame error for DGE-550SX.
     				Fixed VLAN bug.
     1.12	2002/06/13	Lock tx_coalesce=1 on 10/100Mbps mode.
- */
+    1.13	2002/08/13	1. Fix disconnection (many tx:carrier/rx:frame
+    				   errs) with some mainboards.
+    				2. Use definition "DRV_NAME" "DRV_VERSION" 
+				   "DRV_RELDATE" for flexibility.	
+    1.14	2002/08/14	Support ethtool.	
+    1.15	2002/08/27	Changed the default media to Auto-Negotiation
+				for the fiber devices.    
+    1.16	2002/09/04      More power down time for fiber devices auto-
+    				negotiation.
+				Fix disconnect bug after ifup and ifdown.
+    1.17	2002/10/03	Fix RMON statistics overflow. 
+			     	Always use I/O mapping to access eeprom, 
+				avoid system freezing with some chipsets.
 
+*/
+#define DRV_NAME	"D-Link DL2000-based linux driver"
+#define DRV_VERSION	"v1.17a"
+#define DRV_RELDATE	"2002/10/04"
 #include "dl2k.h"
 
 static char version[] __devinitdata =
-    KERN_INFO "D-Link DL2000-based linux driver v1.12 2002/06/13\n";
-
+      KERN_INFO DRV_NAME " " DRV_VERSION " " DRV_RELDATE "\n";	
 #define MAX_UNITS 8
 static int mtu[MAX_UNITS];
 static int vlan[MAX_UNITS];
@@ -92,6 +107,7 @@
 static void set_multicast (struct net_device *dev);
 static struct net_device_stats *get_stats (struct net_device *dev);
 static int clear_stats (struct net_device *dev);
+static int rio_ethtool_ioctl (struct net_device *dev, void *useraddr);
 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);
@@ -257,12 +273,8 @@
 	np->link_status = 0;
 	/* Set media and reset PHY */
 	if (np->phy_media) {
-		/* default 1000mbps_fd for fiber deivices */
-		if (np->an_enable == 1) {
-			np->an_enable = 0;
-			np->speed = 1000;
-			np->full_duplex = 1;
-		} else if (np->an_enable == 2) {
+		/* default Auto-Negotiation for fiber deivices */
+	 	if (np->an_enable == 2) {
 			np->an_enable = 1;
 		}
 		mii_set_media_pcs (dev);
@@ -275,10 +287,6 @@
 	}
 	pci_read_config_byte(pdev, PCI_REVISION_ID, &np->pci_rev_id);
 
-	/* Reset all logic functions */
-	writew (GlobalReset | DMAReset | FIFOReset | NetworkReset | HostReset,
-		ioaddr + ASICCtrl + 2);
-
 	err = register_netdev (dev);
 	if (err)
 		goto err_out_unmap_rx;
@@ -357,11 +365,16 @@
 
 	int cid, next;
 
+#ifdef	MEM_MAPPING
+	ioaddr = pci_resource_start (np->pdev, 0);
+#endif
 	/* Read eeprom */
 	for (i = 0; i < 128; i++) {
 		((u16 *) sromdata)[i] = le16_to_cpu (read_eeprom (ioaddr, i));
 	}
-
+#ifdef	MEM_MAPPING
+	ioaddr = dev->base_addr;
+#endif	
 	/* Check CRC */
 	crc = ~ether_crc_le (256 - 4, sromdata);
 	if (psrom->crc != crc) {
@@ -421,10 +434,17 @@
 	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
 	int i;
-
+	u16 macctrl;
+	
 	i = request_irq (dev->irq, &rio_interrupt, SA_SHIRQ, dev->name, dev);
 	if (i)
 		return i;
+	
+	/* Reset all logic functions */
+	writew (GlobalReset | DMAReset | FIFOReset | NetworkReset | HostReset,
+		ioaddr + ASICCtrl + 2);
+	mdelay(10);
+	
 	/* DebugCtrl bit 4, 5, 9 must set */
 	writel (readl (ioaddr + DebugCtrl) | 0x0230, ioaddr + DebugCtrl);
 
@@ -448,7 +468,7 @@
 	writeb (0xff, ioaddr + TxDMAPollPeriod);
 	writeb (0x30, ioaddr + RxDMABurstThresh);
 	writeb (0x30, ioaddr + RxDMAUrgentThresh);
-
+	writel (0x0007ffff, ioaddr + RmonStatMask);
 	/* clear statistics */
 	clear_stats (dev);
 
@@ -467,9 +487,6 @@
 			ioaddr + MACCtrl);
 	}
 
-	/* Enable default interrupts */
-	EnableInt ();
-
 	init_timer (&np->timer);
 	np->timer.expires = jiffies + 1*HZ;
 	np->timer.data = (unsigned long) dev;
@@ -479,8 +496,18 @@
 	/* Start Tx/Rx */
 	writel (readl (ioaddr + MACCtrl) | StatsEnable | RxEnable | TxEnable, 
 			ioaddr + MACCtrl);
+	
+	macctrl = 0;
+	macctrl |= (np->vlan) ? AutoVLANuntagging : 0;
+	macctrl |= (np->full_duplex) ? DuplexSelect : 0;
+	macctrl |= (np->tx_flow) ? TxFlowControlEnable : 0;
+	macctrl |= (np->rx_flow) ? RxFlowControlEnable : 0;
+	writew(macctrl,	ioaddr + MACCtrl);
 
 	netif_start_queue (dev);
+	
+	/* Enable default interrupts */
+	EnableInt ();
 	return 0;
 }
 
@@ -626,7 +653,7 @@
 	}
 #endif
 	if (np->vlan) {
-		txdesc->status |=
+		tfc_vlan_tag =
 		    cpu_to_le64 (VLANTagInsert) |
 		    (cpu_to_le64 (np->vlan) << 32) |
 		    (cpu_to_le64 (skb->priority) << 45);
@@ -720,9 +747,10 @@
 	long flag = 0;
 	
 	if (irq)
-		spin_lock_irqsave(&np->tx_lock, flag);
-	else
 		spin_lock(&np->tx_lock);
+	else
+		spin_lock_irqsave(&np->tx_lock, flag);
+			
 	/* Free used tx skbuffs */
 	while (entry != np->cur_tx) {
 		struct sk_buff *skb;
@@ -743,9 +771,9 @@
 		tx_use++;
 	}
 	if (irq)
-		spin_unlock_irqrestore(&np->tx_lock, flag);
-	else
 		spin_unlock(&np->tx_lock);
+	else
+		spin_unlock_irqrestore(&np->tx_lock, flag);
 	np->old_tx = entry;
 
 	/* If the ring is no longer full, clear tx_full and 
@@ -809,8 +837,13 @@
 		/* 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);
 }
@@ -974,7 +1007,9 @@
 {
 	long ioaddr = dev->base_addr;
 	struct netdev_private *np = dev->priv;
+#ifdef MEM_MAPPING
 	int i;
+#endif
 	unsigned int stat_reg;
 
 	/* All statistics registers need to be acknowledged,
@@ -1017,9 +1052,10 @@
 	readw (ioaddr + MacControlFramesXmtd);
 	readw (ioaddr + FramesWEXDeferal);
 
-
+#ifdef MEM_MAPPING
 	for (i = 0x100; i <= 0x150; i += 4)
 		readl (ioaddr + i);
+#endif
 	readw (ioaddr + TxJumboFrames);
 	readw (ioaddr + RxJumboFrames);
 	readw (ioaddr + TCPCheckSumErrors);
@@ -1032,7 +1068,9 @@
 clear_stats (struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
+#ifdef MEM_MAPPING
 	int i;
+#endif 
 
 	/* All statistics registers need to be acknowledged,
 	   else statistic overflow could cause problems */
@@ -1068,9 +1106,10 @@
 	readw (ioaddr + BcstFramesXmtdOk);
 	readw (ioaddr + MacControlFramesXmtd);
 	readw (ioaddr + FramesWEXDeferal);
-
+#ifdef MEM_MAPPING
 	for (i = 0x100; i <= 0x150; i += 4)
 		readl (ioaddr + i);
+#endif 
 	readw (ioaddr + TxJumboFrames);
 	readw (ioaddr + RxJumboFrames);
 	readw (ioaddr + TCPCheckSumErrors);
@@ -1103,6 +1142,7 @@
 	u16 rx_mode = 0;
 	int i;
 	int bit;
+	int index, crc;
 	struct dev_mc_list *mclist;
 	struct netdev_private *np = dev->priv;
 	
@@ -1122,17 +1162,16 @@
 		rx_mode =
 		    ReceiveBroadcast | ReceiveMulticastHash | ReceiveUnicast;
 		for (i=0, mclist = dev->mc_list; mclist && i < dev->mc_count; 
-			i++, mclist=mclist->next) {
-
-			int index = 0;
-			int crc = ether_crc_le (ETH_ALEN, mclist->dmi_addr);
-
+				i++, mclist=mclist->next) 
+		{
+			crc = ether_crc_le (ETH_ALEN, mclist->dmi_addr);
 			/* The inverted high significant 6 bits of CRC are
 			   used as an index to hashtable */
-			for (bit = 0; bit < 6; bit++)
-				if (crc & (1 << (31 - bit)))
-					index |= (1 << bit);
-
+			for (index=0, bit=0; bit < 6; bit++) {
+				if (test_bit(31-bit, &crc)) {
+					 set_bit(bit, &index);
+				}
+			}
 			hash_table[index / 32] |= (1 << (index % 32));
 		}
 	} else {
@@ -1149,6 +1188,132 @@
 }
 
 static int
+rio_ethtool_ioctl (struct net_device *dev, void *useraddr)
+{
+	struct netdev_private *np = dev->priv;
+       	u32 ethcmd;
+	
+	if (copy_from_user (&ethcmd, useraddr, sizeof (ethcmd)))
+		return -EFAULT;
+	switch (ethcmd) {
+		case ETHTOOL_GDRVINFO: {
+			struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+			strcpy(info.driver, "DL2K");
+			strcpy(info.version, DRV_VERSION);
+			strcpy(info.bus_info, np->pdev->slot_name);
+			memset(&info.fw_version, 0, sizeof(info.fw_version));
+			if (copy_to_user(useraddr, &info, sizeof(info)))
+				return -EFAULT;
+			return 0;
+		}	
+ 	
+		case ETHTOOL_GSET: {
+			struct ethtool_cmd cmd = { ETHTOOL_GSET };
+			if (np->phy_media) {
+				/* fiber device */
+				cmd.supported = SUPPORTED_Autoneg | 
+							SUPPORTED_FIBRE;
+				cmd.advertising= ADVERTISED_Autoneg |
+							ADVERTISED_FIBRE;
+				cmd.port = PORT_FIBRE;
+				cmd.transceiver = XCVR_INTERNAL;	
+			} else {
+				/* copper device */
+				cmd.supported = SUPPORTED_10baseT_Half | 
+					SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half
+					| SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full |
+					SUPPORTED_Autoneg | SUPPORTED_MII;
+				cmd.advertising = ADVERTISED_10baseT_Half |
+					ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Half |
+					ADVERTISED_100baseT_Full | ADVERTISED_1000baseT_Full|
+					ADVERTISED_Autoneg | ADVERTISED_MII;
+				cmd.port = PORT_MII;
+				cmd.transceiver = XCVR_INTERNAL;
+			}
+			if ( np->link_status ) { 
+				cmd.speed = np->speed;
+				cmd.duplex = np->full_duplex ? 
+						    DUPLEX_FULL : DUPLEX_HALF;
+			} else {
+				cmd.speed = -1;
+				cmd.duplex = -1;
+			}
+			if ( np->an_enable)
+				cmd.autoneg = AUTONEG_ENABLE;
+			else
+				cmd.autoneg = AUTONEG_DISABLE;
+			
+			cmd.phy_address = np->phy_addr;
+
+			if (copy_to_user(useraddr, &cmd,
+					sizeof(cmd)))
+				return -EFAULT;
+			return 0;				   
+		}
+		case ETHTOOL_SSET: {
+			struct ethtool_cmd cmd;
+			if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
+				return -EFAULT;
+			netif_carrier_off(dev);
+			if (cmd.autoneg == AUTONEG_ENABLE) {
+				if (np->an_enable)
+					return 0;
+				else {
+					np->an_enable = 1;
+					mii_set_media(dev);
+					return 0;	
+				}	
+			} else {
+				np->an_enable = 0;
+				if (np->speed == 1000){
+					cmd.speed = SPEED_100;			
+					cmd.duplex = DUPLEX_FULL;
+					printk("Warning!! Can't disable Auto negotiation in 1000Mbps, change to Manul 100Mbps, Full duplex.\n");
+					}
+				switch(cmd.speed + cmd.duplex){
+				
+				case SPEED_10 + DUPLEX_HALF:
+					np->speed = 10;
+					np->full_duplex = 0;
+					break;
+				
+				case SPEED_10 + DUPLEX_FULL:
+					np->speed = 10;
+					np->full_duplex = 1;
+					break;
+				case SPEED_100 + DUPLEX_HALF:
+					np->speed = 100;
+					np->full_duplex = 0;
+					break;
+				case SPEED_100 + DUPLEX_FULL:
+					np->speed = 100;
+					np->full_duplex = 1;
+					break;
+				case SPEED_1000 + DUPLEX_HALF:/* not supported */
+				case SPEED_1000 + DUPLEX_FULL:/* not supported */
+				default:
+					return -EINVAL;	
+				}
+				mii_set_media(dev);
+			}
+		return 0;		   
+		}
+#ifdef ETHTOOL_GLINK		
+		case ETHTOOL_GLINK:{
+		struct ethtool_value link = { ETHTOOL_GLINK };
+		link.data = np->link_status;
+		if (copy_to_user(useraddr, &link, sizeof(link)))
+			return -EFAULT;
+		return 0;
+		}			   
+#endif
+		default:
+		return -EOPNOTSUPP;
+	}	
+}
+
+
+static int
 rio_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	int phy_addr;
@@ -1160,6 +1325,8 @@
 
 	phy_addr = np->phy_addr;
 	switch (cmd) {
+	case SIOCETHTOOL:
+		return rio_ethtool_ioctl (dev, (void *) rq->ifr_data);		
 	case SIOCDEVPRIVATE:
 		break;
 	
@@ -1210,14 +1377,15 @@
 #define EEP_READ 0x0200
 #define EEP_BUSY 0x8000
 /* Read the EEPROM word */
+/* We use I/O instruction to read/write eeprom to avoid fail on some machines */
 int
 read_eeprom (long ioaddr, int eep_addr)
 {
 	int i = 1000;
-	writew (EEP_READ | (eep_addr & 0xff), ioaddr + EepromCtrl);
+	outw (EEP_READ | (eep_addr & 0xff), ioaddr + EepromCtrl);
 	while (i-- > 0) {
-		if (!(readw (ioaddr + EepromCtrl) & EEP_BUSY)) {
-			return readw (ioaddr + EepromData);
+		if (!(inw (ioaddr + EepromCtrl) & EEP_BUSY)) {
+			return inw (ioaddr + EepromData);
 		}
 	}
 	return 0;
@@ -1464,7 +1632,7 @@
 		/* 3) Power Down */
 		bmcr.image = 0x1940;	/* must be 0x1940 */
 		mii_write (dev, phy_addr, MII_BMCR, bmcr.image);
-		mdelay (10);	/* wait a certain time */
+		mdelay (100);	/* wait a certain time */
 
 		/* 4) Advertise nothing */
 		mii_write (dev, phy_addr, MII_ANAR, 0);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/dl2k.h linux-2.4.21-pre6/drivers/net/dl2k.h
--- linux-2.4.20/drivers/net/dl2k.h	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/dl2k.h	2003-03-26 23:49:27.000000000 +0000
@@ -27,9 +27,11 @@
 #include <linux/skbuff.h>
 #include <linux/init.h>
 #include <linux/crc32.h>
+#include <linux/ethtool.h>
 #include <asm/processor.h>	/* Processor type for cache alignment. */
 #include <asm/bitops.h>
 #include <asm/io.h>
+#include <asm/uaccess.h>
 #include <linux/delay.h>
 #include <linux/spinlock.h>
 #include <linux/time.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/dmfe.c linux-2.4.21-pre6/drivers/net/dmfe.c
--- linux-2.4.20/drivers/net/dmfe.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/dmfe.c	2003-03-26 23:49:54.000000000 +0000
@@ -29,7 +29,7 @@
     Reformatted, fixing spelling etc as I went
     Removed IRQ 0-15 assumption
 
-    Jeff Garzik <jgarzik@mandrakesoft.com> :
+    Jeff Garzik <jgarzik@pobox.com> :
     Updated to use new PCI driver API.
     Resource usage cleanups.
     Report driver version to user.
@@ -48,6 +48,10 @@
     Use time_after for jiffies calculation.  Added ethtool
     support.  Updated PCI resource allocation.  Do not
     forget to unmap PCI mapped skbs.
+    
+    Alan Cox <alan@redhat.com>
+    Added new PCI identifiers provided by Clear Zhang at ALi 
+    for their 1563 ethernet device.
 
     TODO
 
@@ -1977,6 +1981,7 @@
 	{ 0x1282, 0x9102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9102_ID },
 	{ 0x1282, 0x9100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9100_ID },
 	{ 0x1282, 0x9009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9009_ID },
+	{ 0x10B9, 0x5261, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9102_ID },
 	{ 0, }
 };
 MODULE_DEVICE_TABLE(pci, dmfe_pci_tbl);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/e100/Makefile linux-2.4.21-pre6/drivers/net/e100/Makefile
--- linux-2.4.20/drivers/net/e100/Makefile	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/e100/Makefile	2003-03-26 23:48:58.000000000 +0000
@@ -4,7 +4,7 @@
 
 O_TARGET := e100.o
 
-obj-y	 :=	e100_main.o e100_config.o e100_proc.o e100_phy.o \
+obj-y	 :=	e100_main.o e100_config.o e100_phy.o \
 		e100_eeprom.o e100_test.o
 obj-m	 := $(O_TARGET)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/e100/e100.h linux-2.4.21-pre6/drivers/net/e100/e100.h
--- linux-2.4.20/drivers/net/e100/e100.h	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/e100/e100.h	2003-03-26 23:49:34.000000000 +0000
@@ -56,7 +56,6 @@
 
 #include <linux/if.h>
 #include <asm/uaccess.h>
-#include <linux/proc_fs.h>
 #include <linux/ip.h>
 
 #define E100_REGS_LEN 1
@@ -268,6 +267,7 @@
 #define SCB_CUC_NOOP            0
 #define SCB_CUC_START           BIT_4	/* CU Start */
 #define SCB_CUC_RESUME          BIT_5	/* CU Resume */
+#define SCB_CUC_UNKNOWN         BIT_7	/* CU unknown command */
 /* Changed for 82558 enhancements */
 #define SCB_CUC_STATIC_RESUME   (BIT_5 | BIT_7)	/* 82558/9 Static Resume */
 #define SCB_CUC_DUMP_ADDR       BIT_6	/* CU Dump Counters Address */
@@ -925,22 +925,7 @@
 
 	struct cfg_params params;	/* adapter's command line parameters */
 
-	struct proc_dir_entry *proc_parent;
-
-	rwlock_t isolate_lock;
-	int driver_isolated;
 	char *id_string;
-	char *cable_status;
-	char *mdix_status;
-
-	/* Variables for HWI */
-	int saved_open_circut;
-	int saved_short_circut;
-	int saved_distance;
-	int saved_i;
-	int saved_same;
-	unsigned char hwi_started;
-	struct timer_list hwi_timer;	/* hwi timer id */
 
 	u32 speed_duplex_caps;	/* adapter's speed/duplex capabilities */
 
@@ -955,6 +940,10 @@
 	u32 pci_state[16];
 #endif
 	char ifname[IFNAMSIZ];
+#ifdef E100_CU_DEBUG	
+	u8 last_cmd;
+	u8 last_sub_cmd;
+#endif	
 };
 
 #define E100_AUTONEG        0
@@ -966,7 +955,7 @@
 /********* function prototypes *************/
 extern void e100_isolate_driver(struct e100_private *bdp);
 extern void e100_sw_reset(struct e100_private *bdp, u32 reset_cmd);
-extern void e100_start_cu(struct e100_private *bdp, tcb_t *tcb);
+extern u8 e100_start_cu(struct e100_private *bdp, tcb_t *tcb);
 extern void e100_free_non_tx_cmd(struct e100_private *bdp,
 				 nxmit_cb_entry_t *non_tx_cmd);
 extern nxmit_cb_entry_t *e100_alloc_non_tx_cmd(struct e100_private *bdp);
@@ -977,10 +966,11 @@
 extern unsigned char e100_get_link_state(struct e100_private *bdp);
 extern unsigned char e100_wait_scb(struct e100_private *bdp);
 
-extern void e100_deisolate_driver(struct e100_private *bdp,
-				  u8 recover, u8 full_reset);
-extern unsigned char e100_hw_reset_recover(struct e100_private *bdp,
-					   u32 reset_cmd);
+extern void e100_deisolate_driver(struct e100_private *bdp, u8 full_reset);
+extern unsigned char e100_configure_device(struct e100_private *bdp);
+#ifdef E100_CU_DEBUG
+extern unsigned char e100_cu_unknown_state(struct e100_private *bdp);
+#endif
 
 #define ROM_TEST_FAIL		0x01
 #define REGISTER_TEST_FAIL	0x02
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/e100/e100_config.c linux-2.4.21-pre6/drivers/net/e100/e100_config.c
--- linux-2.4.20/drivers/net/e100/e100_config.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/e100/e100_config.c	2003-03-26 23:48:58.000000000 +0000
@@ -494,8 +494,7 @@
  * e100_config_wol
  * @bdp: atapter's private data struct
  *
- * This sets configuration options for Wake On LAN functionality (WOL) in the
- * config record. WOL options are retrieved from wolinfo_wolopts in @bdp
+ * This sets configuration options for PHY and Magic Packet WoL 
  */
 void
 e100_config_wol(struct e100_private *bdp)
@@ -504,14 +503,21 @@
 
 	if (bdp->wolopts & WAKE_PHY) {
 		bdp->config[9] |= CB_LINK_STATUS_WOL;
-		E100_CONFIG(bdp, 9);
+	}
+	else {
+		/* Disable PHY WoL */
+		bdp->config[9] &= ~CB_LINK_STATUS_WOL;
 	}
 
-	if (!(bdp->wolopts & WAKE_MAGIC)) {
+	if (bdp->wolopts & WAKE_MAGIC) {
+		bdp->config[19] &= ~CB_DISABLE_MAGPAK_WAKE;
+	}
+	else {
+		/* Disable Magic Packet WoL */
 		bdp->config[19] |= CB_DISABLE_MAGPAK_WAKE;
-		E100_CONFIG(bdp, 19);
 	}
 
+	E100_CONFIG(bdp, 19);
 	spin_unlock_bh(&(bdp->config_lock));
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/e100/e100_main.c linux-2.4.21-pre6/drivers/net/e100/e100_main.c
--- linux-2.4.20/drivers/net/e100/e100_main.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/e100/e100_main.c	2003-03-26 23:49:06.000000000 +0000
@@ -46,6 +46,21 @@
 
 /* Change Log
  *
+ * 2.1.29	12/20/02
+ *   o Bug fix: Device command timeout due to SMBus processing during init
+ *   o Bug fix: Not setting/clearing I (Interrupt) bit in tcb correctly
+ *   o Bug fix: Not using EEPROM WoL setting as default in ethtool
+ *   o Bug fix: Not able to set autoneg on using ethtool when interface down
+ *   o Bug fix: Not able to change speed/duplex using ethtool/mii
+ *     when interface up
+ *   o Bug fix: Ethtool shows autoneg on when forced to 100/Full
+ *   o Bug fix: Compiler error when CONFIG_PROC_FS not defined
+ *   o Bug fix: 2.5.44 e100 doesn't load with preemptive kernel enabled
+ *     (sleep while holding spinlock)
+ *   o Bug fix: 2.1.24-k1 doesn't display complete statistics
+ *   o Bug fix: System panic due to NULL watchdog timer dereference during
+ *     ifconfig down, rmmod and insmod
+ *
  * 2.1.24       10/7/02
  *   o Bug fix: Wrong files under /proc/net/PRO_LAN_Adapters/ when interface
  *     name is changed
@@ -56,21 +71,6 @@
  *   o Removed misleading printks
  *
  * 2.1.12       8/2/02
- *   o Feature: ethtool register dump
- *   o Bug fix: Driver passes wrong name to /proc/interrupts
- *   o Bug fix: Ethernet bridging not working 
- *   o Bug fix: Promiscuous mode is not working
- *   o Bug fix: Checked return value from copy_from_user (William Stinson,
- *     wstinson@infonie.fr)
- *   o Bug fix: ARP wake on LAN fails
- *   o Bug fix: mii-diag does not update driver level's speed, duplex and
- *     re-configure flow control
- *   o Bug fix: Ethtool shows wrong speed/duplex when not connected
- *   o Bug fix: Ethtool shows wrong speed/duplex when reconnected if forced 
- *     speed/duplex
- *   o Bug fix: PHY loopback diagnostic fails
- *
- * 2.1.6        7/5/02
  */
  
 #include <linux/config.h>
@@ -83,13 +83,15 @@
 #include "e100_phy.h"
 #include "e100_vendor.h"
 
-#ifdef CONFIG_PROC_FS
-extern int e100_create_proc_subdir(struct e100_private *, char *);
-extern void e100_remove_proc_subdir(struct e100_private *, char *);
-#else
-#define e100_create_proc_subdir(X) 0
-#define e100_remove_proc_subdir(X) do {} while(0)
-#endif
+static char e100_gstrings_stats[][ETH_GSTRING_LEN] = {
+	"rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors",
+	"tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions",
+	"rx_length_errors", "rx_over_errors", "rx_crc_errors",
+	"rx_frame_errors", "rx_fifo_errors", "rx_missed_errors",
+	"tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors",
+	"tx_heartbeat_errors", "tx_window_errors",
+};
+#define E100_STATS_LEN	sizeof(e100_gstrings_stats) / ETH_GSTRING_LEN
 
 static int e100_do_ethtool_ioctl(struct net_device *, struct ifreq *);
 static void e100_get_speed_duplex_caps(struct e100_private *);
@@ -135,7 +137,7 @@
 
 /* Global Data structures and variables */
 char e100_copyright[] __devinitdata = "Copyright (c) 2002 Intel Corporation";
-char e100_driver_version[]="2.1.24-k1";
+char e100_driver_version[]="2.1.29-k4";
 const char *e100_full_driver_name = "Intel(R) PRO/100 Network Driver";
 char e100_short_driver_name[] = "e100";
 static int e100nics = 0;
@@ -145,20 +147,11 @@
 static int e100_suspend(struct pci_dev *pcid, u32 state);
 static int e100_resume(struct pci_dev *pcid);
 struct notifier_block e100_notifier_reboot = {
-        notifier_call:  e100_notify_reboot,
-        next:           NULL,
-        priority:       0
+        .notifier_call  = e100_notify_reboot,
+        .next           = NULL,
+        .priority       = 0
 };
 #endif
-static int e100_notify_netdev(struct notifier_block *, unsigned long event, void *ptr);
- 
-struct notifier_block e100_notifier_netdev = {
-	notifier_call:  e100_notify_netdev,
-	next:           NULL,
-	priority:       0
-};
-
-static void e100_get_mdix_status(struct e100_private *bdp);
 
 /*********************************************************************/
 /*! This is a GCC extension to ANSI C.
@@ -196,6 +189,7 @@
 char *e100_get_brand_msg(struct e100_private *);
 static u8 e100_pci_setup(struct pci_dev *, struct e100_private *);
 static u8 e100_sw_init(struct e100_private *);
+static void e100_tco_workaround(struct e100_private *);
 static unsigned char e100_alloc_space(struct e100_private *);
 static void e100_dealloc_space(struct e100_private *);
 static int e100_alloc_tcb_pool(struct e100_private *);
@@ -213,7 +207,7 @@
 
 static unsigned char e100_clr_cntrs(struct e100_private *);
 static unsigned char e100_load_microcode(struct e100_private *);
-static unsigned char e100_hw_init(struct e100_private *, u32);
+static unsigned char e100_hw_init(struct e100_private *);
 static unsigned char e100_setup_iaaddr(struct e100_private *, u8 *);
 static unsigned char e100_update_stats(struct e100_private *bdp);
 
@@ -224,7 +218,7 @@
 static void e100_set_int_option(int *, int, int, int, int, char *);
 static void e100_set_bool_option(struct e100_private *bdp, int, u32, int,
 				 char *);
-unsigned char e100_wait_exec_cmplx(struct e100_private *, u32, u8);
+unsigned char e100_wait_exec_cmplx(struct e100_private *, u32, u8, u8);
 void e100_exec_cmplx(struct e100_private *, u32, u8);
 
 /**
@@ -349,8 +343,6 @@
 u32 e100_rx_srv(struct e100_private *);
 
 void e100_watchdog(struct net_device *);
-static void e100_do_hwi(struct net_device *);
-static void e100_hwi_restore(struct e100_private *);
 void e100_refresh_txthld(struct e100_private *);
 void e100_manage_adaptive_ifs(struct e100_private *);
 void e100_clear_pools(struct e100_private *);
@@ -443,9 +435,21 @@
 	if (!e100_wait_scb(bdp)) {
 		printk(KERN_DEBUG "e100: %s: e100_wait_exec_simple: failed\n",
 		       bdp->device->name);
+#ifdef E100_CU_DEBUG		
+		printk(KERN_ERR "e100: %s: Last command (%x/%x) "
+			"timeout\n", bdp->device->name, 
+			bdp->last_cmd, bdp->last_sub_cmd);
+		printk(KERN_ERR "e100: %s: Current simple command (%x) "
+			"can't be executed\n", 
+			bdp->device->name, scb_cmd_low);
+#endif		
 		return false;
 	}
 	e100_exec_cmd(bdp, scb_cmd_low);
+#ifdef E100_CU_DEBUG	
+	bdp->last_cmd = scb_cmd_low;
+	bdp->last_sub_cmd = 0;
+#endif	
 	return true;
 }
 
@@ -458,12 +462,24 @@
 }
 
 unsigned char
-e100_wait_exec_cmplx(struct e100_private *bdp, u32 phys_addr, u8 cmd)
+e100_wait_exec_cmplx(struct e100_private *bdp, u32 phys_addr, u8 cmd, u8 sub_cmd)
 {
 	if (!e100_wait_scb(bdp)) {
+#ifdef E100_CU_DEBUG		
+		printk(KERN_ERR "e100: %s: Last command (%x/%x) "
+			"timeout\n", bdp->device->name, 
+			bdp->last_cmd, bdp->last_sub_cmd);
+		printk(KERN_ERR "e100: %s: Current complex command "
+			"(%x/%x) can't be executed\n", 
+			bdp->device->name, cmd, sub_cmd);
+#endif		
 		return false;
 	}
 	e100_exec_cmplx(bdp, phys_addr, cmd);
+#ifdef E100_CU_DEBUG	
+	bdp->last_cmd = cmd;
+	bdp->last_sub_cmd = sub_cmd;
+#endif	
 	return true;
 }
 
@@ -494,18 +510,23 @@
 }
 
 /**
- * e100_dis_intr - disable interrupts
+ * e100_disable_clear_intr - disable and clear/ack interrupts
  * @bdp: atapter's private data struct
  *
  * This routine disables interrupts at the hardware, by setting
  * the M (mask) bit in the adapter's CSR SCB command word.
+ * It also clear/ack interrupts.
  */
 static inline void
-e100_dis_intr(struct e100_private *bdp)
+e100_disable_clear_intr(struct e100_private *bdp)
 {
+	u16 intr_status;
 	/* Disable interrupts on our PCI board by setting the mask bit */
 	writeb(SCB_INT_MASK, &bdp->scb->scb_cmd_hi);
-	readw(&(bdp->scb->scb_status));	/* flushes last write, read-safe */
+	intr_status = readw(&bdp->scb->scb_status);
+	/* ack and clear intrs */
+	writew(intr_status, &bdp->scb->scb_status);
+	readw(&bdp->scb->scb_status);
 }
 
 /**
@@ -581,16 +602,14 @@
 	bdp->watchdog_timer.data = (unsigned long) dev;
 	bdp->watchdog_timer.function = (void *) &e100_watchdog;
 
-	init_timer(&bdp->hwi_timer);
-	bdp->hwi_timer.data = (unsigned long) dev;
-	bdp->hwi_timer.function = (void *) &e100_do_hwi;
-
 	if ((rc = e100_pci_setup(pcid, bdp)) != 0) {
 		goto err_dealloc;
 	}
 
 	if (((bdp->pdev->device > 0x1030)
-	     && (bdp->pdev->device < 0x103F))
+	       && (bdp->pdev->device < 0x103F))
+	    || ((bdp->pdev->device >= 0x1050)
+	       && (bdp->pdev->device <= 0x1057))
 	    || (bdp->pdev->device == 0x2449)
 	    || (bdp->pdev->device == 0x2459)
 	    || (bdp->pdev->device == 0x245D)) {
@@ -623,7 +642,7 @@
 	cal_checksum = e100_eeprom_calculate_chksum(bdp);
 	read_checksum = e100_eeprom_read(bdp, (bdp->eeprom_size - 1));
 	if (cal_checksum != read_checksum) {
-                printk(KERN_ERR "e100: Corrupted EERPROM on instance #%d\n",
+                printk(KERN_ERR "e100: Corrupted EEPROM on instance #%d\n",
 		       e100nics);
                 rc = -ENODEV;
                 goto err_pci;
@@ -657,28 +676,18 @@
 	       bdp->device->name, e100_get_brand_msg(bdp));
 	e100_print_brd_conf(bdp);
 	bdp->id_string = e100_get_brand_msg(bdp);
-	e100_get_mdix_status(bdp);
 
-	if (netif_carrier_ok(bdp->device)) 
-		bdp->cable_status = "Cable OK";
-	else {
-		if (bdp->rev_id < D102_REV_ID) 
-			bdp->cable_status = "Not supported";
-		else
-			bdp->cable_status = "Not available";
-	}
-
-	if (e100_create_proc_subdir(bdp, bdp->ifname) < 0) {
-		printk(KERN_ERR "e100: Failed to create proc dir for %s\n",
-		       bdp->device->name);
-	}
-
-	/* Disabling all WOLs as initialization */
-	bdp->wolsupported = bdp->wolopts = 0;
-	if (bdp->rev_id >= D101A4_REV_ID) {
-		bdp->wolsupported = WAKE_PHY | WAKE_MAGIC;
+	bdp->wolsupported = 0;
+	bdp->wolopts = 0;
+	
+	/* Check if WoL is enabled on EEPROM */
+	if (e100_eeprom_read(bdp, EEPROM_ID_WORD) & BIT_5) {
+		if (bdp->rev_id >= D101A4_REV_ID)
+			bdp->wolsupported = WAKE_PHY | WAKE_MAGIC;
 		if (bdp->rev_id >= D101MA_REV_ID)
 			bdp->wolsupported |= WAKE_UCAST | WAKE_ARP;
+		/* Magic Packet WoL is enabled on device by default */
+		/* if EEPROM WoL bit is TRUE                        */
 		bdp->wolopts = WAKE_MAGIC;
 	}
 
@@ -732,8 +741,6 @@
 
 	unregister_netdev(dev);
 
-	e100_remove_proc_subdir(bdp, bdp->ifname);
-
 	e100_sw_reset(bdp, PORT_SELECTIVE_RESET);
 
 	if (bdp->non_tx_command_state != E100_NON_TX_IDLE) {
@@ -770,7 +777,6 @@
 #ifdef CONFIG_PM
 		register_reboot_notifier(&e100_notifier_reboot);
 #endif 
-		register_netdevice_notifier(&e100_notifier_netdev);
 	}
 
 	return ret;
@@ -782,7 +788,6 @@
 #ifdef CONFIG_PM	
 	unregister_reboot_notifier(&e100_notifier_reboot);
 #endif 
-	unregister_netdevice_notifier(&e100_notifier_netdev);
 
 	pci_unregister_driver(&e100_driver);
 }
@@ -935,13 +940,6 @@
 
 	bdp = dev->priv;
 
-	read_lock(&(bdp->isolate_lock));
-
-	if (bdp->driver_isolated) {
-		rc = -EBUSY;
-		goto exit;
-	}
-
 	/* setup the tcb pool */
 	if (!e100_alloc_tcb_pool(bdp)) {
 		rc = -ENOMEM;
@@ -960,12 +958,12 @@
 		goto err_exit;
 	}
 
-	if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE)) {
+	if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE, 0)) {
 		rc = -EAGAIN;
 		goto err_exit;
 	}
 
-	if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE)) {
+	if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE, 0)) {
 		rc = -EAGAIN;
 		goto err_exit;
 	}
@@ -990,7 +988,6 @@
 err_exit:
 	e100_clear_pools(bdp);
 exit:
-	read_unlock(&(bdp->isolate_lock));
 	return rc;
 }
 
@@ -1008,9 +1005,6 @@
 	free_irq(dev->irq, dev);
 	e100_clear_pools(bdp);
 
-	/* set the isolate flag to false, so e100_open can be called */
-	bdp->driver_isolated = false;
-
 	return 0;
 }
 
@@ -1031,13 +1025,6 @@
 	int notify_stop = false;
 	struct e100_private *bdp = dev->priv;
 
-	read_lock(&(bdp->isolate_lock));
-
-	if (bdp->driver_isolated) {
-		rc = -EBUSY;
-		goto exit2;
-	}
-
 	if (!spin_trylock(&bdp->bd_non_tx_lock)) {
 		notify_stop = true;
 		rc = 1;
@@ -1060,7 +1047,6 @@
 exit1:
 	spin_unlock(&bdp->bd_non_tx_lock);
 exit2:
-	read_unlock(&(bdp->isolate_lock));
 	if (notify_stop) {
 		netif_stop_queue(dev);
 	}
@@ -1115,18 +1101,11 @@
 
 	bdp = dev->priv;
 
-	read_lock(&(bdp->isolate_lock));
-
-	if (bdp->driver_isolated) {
-		goto exit;
-	}
 	if (e100_setup_iaaddr(bdp, (u8 *) (p_sockaddr->sa_data))) {
 		memcpy(&(dev->dev_addr[0]), p_sockaddr->sa_data, ETH_ALEN);
 		rc = 0;
 	}
 
-exit:
-	read_unlock(&(bdp->isolate_lock));
 	return rc;
 }
 
@@ -1180,10 +1159,6 @@
 	unsigned char promisc_enbl;
 	unsigned char mulcast_enbl;
 
-	read_lock(&(bdp->isolate_lock));
-	if (bdp->driver_isolated) {
-		goto exit;
-	}
 	promisc_enbl = ((dev->flags & IFF_PROMISC) == IFF_PROMISC);
 	mulcast_enbl = ((dev->flags & IFF_ALLMULTI) ||
 			(dev->mc_count > MAX_MULTICAST_ADDRS));
@@ -1195,14 +1170,11 @@
 	e100_config(bdp);
 
 	if (promisc_enbl || mulcast_enbl) {
-		goto exit;	/* no need for Multicast Cmd */
+		return;	/* no need for Multicast Cmd */
 	}
 
 	/* get the multicast CB */
 	e100_set_multi_exec(dev);
-
-exit:
-	read_unlock(&(bdp->isolate_lock));
 }
 
 static int
@@ -1264,11 +1236,12 @@
 	/* read NIC's part number */
 	e100_rd_pwa_no(bdp);
 
-	if (!e100_hw_init(bdp, PORT_SOFTWARE_RESET)) {
+	if (!e100_hw_init(bdp)) {
 		printk(KERN_ERR "e100: hw init failed\n");
 		return false;
 	}
-	e100_dis_intr(bdp);
+	/* Interrupts are enabled after device reset */
+	e100_disable_clear_intr(bdp);
 
 	return true;
 }
@@ -1308,16 +1281,50 @@
 	spin_lock_init(&(bdp->bd_non_tx_lock));
 	spin_lock_init(&(bdp->config_lock));
 	spin_lock_init(&(bdp->mdi_access_lock));
-	bdp->isolate_lock = RW_LOCK_UNLOCKED;
-	bdp->driver_isolated = false;
 
 	return 1;
 }
 
+static void __devinit
+e100_tco_workaround(struct e100_private *bdp)
+{
+	int i;
+
+	/* Do software reset */
+	e100_sw_reset(bdp, PORT_SOFTWARE_RESET);
+
+	/* Do a dummy LOAD CU BASE command. */
+	/* This gets us out of pre-driver to post-driver. */
+	e100_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE);
+
+	/* Wait 20 msec for reset to take effect */
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(HZ / 50 + 1);
+
+	/* disable interrupts since they are enabled */
+	/* after device reset                        */
+	e100_disable_clear_intr(bdp);
+
+	/* Wait for command to be cleared up to 1 sec */
+	for (i=0; i<100; i++) {
+		if (!readb(&bdp->scb->scb_cmd_low))
+			break;
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(HZ / 100 + 1);
+	}
+
+	/* Wait for TCO request bit in PMDR register to be clear */
+	for (i=0; i<50; i++) {
+		if (!(readb(&bdp->scb->scb_ext.d101m_scb.scb_pmdr) & BIT_1))
+			break;
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(HZ / 100 + 1);
+	}
+}
+
 /**
  * e100_hw_init - initialized tthe hardware
  * @bdp: atapter's private data struct
- * @reset_cmd: s/w reset or selective reset
  *
  * This routine performs a reset on the adapter, and configures the adapter.
  * This includes configuring the 82557 LAN controller, validating and setting
@@ -1329,19 +1336,22 @@
  *      false - If the adapter failed initialization
  */
 unsigned char __devinit
-e100_hw_init(struct e100_private *bdp, u32 reset_cmd)
+e100_hw_init(struct e100_private *bdp)
 {
 	if (!e100_phy_init(bdp))
 		return false;
 
-	/* Issue a software reset to the e100 */
-	e100_sw_reset(bdp, reset_cmd);
+	e100_sw_reset(bdp, PORT_SELECTIVE_RESET);
+
+	/* Only 82559 or above needs TCO workaround */
+	if (bdp->rev_id >= D101MA_REV_ID)
+		e100_tco_workaround(bdp);
 
 	/* Load the CU BASE (set to 0, because we use linear mode) */
-	if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE))
+	if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE, 0))
 		return false;
 
-	if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE))
+	if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE, 0))
 		return false;
 
 	/* Load interrupt microcode  */
@@ -1391,6 +1401,7 @@
 	u32 next_phys;		/* the next phys addr */
 	u16 txcommand = CB_S_BIT | CB_TX_SF_BIT;
 
+	bdp->tx_count = 0;
 	if (bdp->flags & USE_IPCB) {
 		txcommand |= CB_IPCB_TRANSMIT | CB_CID_DEFAULT;
 	} else if (bdp->flags & IS_BACHELOR) {
@@ -1625,14 +1636,15 @@
 {
 	struct e100_private *bdp = dev->priv;
 
-	read_lock(&(bdp->isolate_lock));
-	if (bdp->driver_isolated) {
-		goto exit;
+#ifdef E100_CU_DEBUG
+	if (e100_cu_unknown_state(bdp)) {
+		printk(KERN_ERR "e100: %s: CU unknown state in e100_watchdog\n",
+			dev->name);
 	}
+#endif	
 	if (!netif_running(dev)) {
-		goto exit;
+		return;
 	}
-	e100_get_mdix_status(bdp);
 
 	/* check if link state has changed */
 	if (e100_phy_check(bdp)) {
@@ -1645,37 +1657,10 @@
 
 			e100_config_fc(bdp);
 			e100_config(bdp);  
-			bdp->cable_status = "Cable OK";
 
 		} else {
 			printk(KERN_ERR "e100: %s NIC Link is Down\n",
 			       bdp->device->name);
-                	if (bdp->rev_id < D102_REV_ID)
-				bdp->cable_status = "Not supported";
-		        else {				
-				/* Initiate hwi, ie, cable diagnostic */
-				bdp->saved_open_circut = 0xffff;
-				bdp->saved_short_circut = 0xffff;
-				bdp->saved_distance = 0xffff;
-				bdp->saved_i = 0;
-				bdp->saved_same = 0;
-				bdp->hwi_started = 1;
-				
-				/* Disable MDI/MDI-X auto switching */
-                		e100_mdi_write(bdp, MII_NCONFIG, bdp->phy_addr,
-		                	MDI_MDIX_RESET_ALL_MASK);
-
-				/* Set to 100 Full as required by hwi test */
-				e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr,
-				       BMCR_SPEED100 | BMCR_FULLDPLX);
-
-				/* Enable and execute HWI test */
-				e100_mdi_write(bdp, HWI_CONTROL_REG, bdp->phy_addr,
-					(HWI_TEST_ENABLE | HWI_TEST_EXECUTE));
-
-				/* Launch hwi timer in 1 msec */
-				mod_timer(&(bdp->hwi_timer), jiffies + (HZ / 1000) );
-			}
 		}
 	}
 
@@ -1685,7 +1670,8 @@
 		if (netif_running(dev))
 			netif_wake_queue(dev);
 	} else {
-		netif_stop_queue(dev);
+		if (netif_running(dev))
+			netif_stop_queue(dev);
 	}
 
 	rmb();
@@ -1721,9 +1707,6 @@
 
 	if (list_empty(&bdp->active_rx_list))
 		e100_trigger_SWI(bdp);
-
-exit:
-	read_unlock(&(bdp->isolate_lock));
 }
 
 /**
@@ -1816,11 +1799,8 @@
 		return;
 	}
 
-	/* disable intr before we ack & after identifying the intr as ours */
-	e100_dis_intr(bdp);
-
-	writew(intr_status, &bdp->scb->scb_status);	/* ack intrs */
-	readw(&bdp->scb->scb_status);
+	/* disable and ack intr */
+	e100_disable_clear_intr(bdp);
 
 	/* the device is closed, don't continue or else bad things may happen. */
 	if (!netif_running(dev)) {
@@ -1828,11 +1808,6 @@
 		return;
 	}
 
-	read_lock(&(bdp->isolate_lock));
-	if (bdp->driver_isolated) {
-		goto exit;
-	}
-
 	/* SWI intr (triggered by watchdog) is signal to allocate new skb buffers */
 	if (intr_status & SCB_STATUS_ACK_SWI) {
 		e100_alloc_skbs(bdp);
@@ -1844,14 +1819,10 @@
 		bdp->drv_stats.rx_intr_pkts += e100_rx_srv(bdp);
 
 	/* clean up after tx'ed packets */
-	if (intr_status & (SCB_STATUS_ACK_CNA | SCB_STATUS_ACK_CX)) {
-		bdp->tx_count = 0;	/* restart tx interrupt batch count */
+	if (intr_status & (SCB_STATUS_ACK_CNA | SCB_STATUS_ACK_CX))
 		e100_tx_srv(bdp);
-	}
 
-exit:
 	e100_set_intr_mask(bdp);
-	read_unlock(&(bdp->isolate_lock));
 }
 
 /**
@@ -1861,7 +1832,7 @@
  *
  * This routine frees resources of TX skbs.
  */
-static void inline
+static inline void
 e100_tx_skb_free(struct e100_private *bdp, tcb_t *tcb)
 {
 	if (tcb->tcb_skb) {
@@ -2157,11 +2128,12 @@
 	tcb->tcb_thrshld = bdp->tx_thld;
 	tcb->tcb_hdr.cb_cmd |= __constant_cpu_to_le16(CB_S_BIT);
 
-	/* set the I bit on the modulo tcbs, so we will get an interrupt * to
-	 * clean things up */
-	if (!(++bdp->tx_count % TX_FRAME_CNT)) {
+	/* Set I (Interrupt) bit on every (TX_FRAME_CNT)th packet */
+	if (!(++bdp->tx_count % TX_FRAME_CNT))
 		tcb->tcb_hdr.cb_cmd |= __constant_cpu_to_le16(CB_I_BIT);
-	}
+	else
+		/* Clear I bit on other packets */
+		tcb->tcb_hdr.cb_cmd &= ~__constant_cpu_to_le16(CB_I_BIT);
 
 	tcb->tcb_skb = skb;
 
@@ -2257,10 +2229,11 @@
  *
  * e100_start_cu must be called while holding the tx_lock ! 
  */
-void
+u8
 e100_start_cu(struct e100_private *bdp, tcb_t *tcb)
 {
 	unsigned long lock_flag;
+	u8 ret = true;
 
 	spin_lock_irqsave(&(bdp->bd_lock), lock_flag);
 	switch (bdp->next_cu_cmd) {
@@ -2291,12 +2264,13 @@
 			       "e100: %s: cu_start: timeout waiting for cu\n",
 			       bdp->device->name);
 		if (!e100_wait_exec_cmplx(bdp, (u32) (tcb->tcb_phys),
-					  SCB_CUC_START)) {
+					  SCB_CUC_START, CB_TRANSMIT)) {
 			printk(KERN_DEBUG
 			       "e100: %s: cu_start: timeout waiting for scb\n",
 			       bdp->device->name);
 			e100_exec_cmplx(bdp, (u32) (tcb->tcb_phys),
 					SCB_CUC_START);
+			ret = false;
 		}
 
 		bdp->next_cu_cmd = RESUME_WAIT;
@@ -2308,6 +2282,7 @@
 	bdp->last_tcb = tcb;
 
 	spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag);
+	return ret;
 }
 
 /* ====================================================================== */
@@ -2355,8 +2330,9 @@
 	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule_timeout(HZ / 100 + 1);
 
-	/* disable interrupts since the're now enabled */
-	e100_dis_intr(bdp);
+	/* disable interrupts since they are enabled */
+	/* after device reset during selftest        */
+	e100_disable_clear_intr(bdp);
 
 	/* if The First Self Test DWORD Still Zero, We've timed out. If the
 	 * second DWORD is not zero then we have an error. */
@@ -2454,7 +2430,7 @@
 
 	spin_lock(&bdp->bd_lock);
 
-	if (!e100_wait_exec_cmplx(bdp, rx_struct->dma_addr, SCB_RUC_START)) {
+	if (!e100_wait_exec_cmplx(bdp, rx_struct->dma_addr, SCB_RUC_START, 0)) {
 		printk(KERN_DEBUG
 		       "e100: %s: start_ru: wait_scb failed\n", 
 		       bdp->device->name);
@@ -2522,7 +2498,7 @@
 	*pcmd_complete = 0;
 	wmb();
 
-	if (!e100_wait_exec_cmplx(bdp, bdp->stat_cnt_phys, SCB_CUC_DUMP_ADDR))
+	if (!e100_wait_exec_cmplx(bdp, bdp->stat_cnt_phys, SCB_CUC_DUMP_ADDR, 0))
 		return false;
 
 	/* wait 10 microseconds for the command to complete */
@@ -2644,8 +2620,10 @@
 	unsigned long lock_flag;
 	unsigned long expiration_time;
 	unsigned char rc = true;
+	u8 sub_cmd;
 
 	ntcb_hdr = (cb_header_t *) command->non_tx_cmd;	/* get hdr of non tcb cmd */
+	sub_cmd = cpu_to_le16(ntcb_hdr->cb_cmd);
 
 	/* Set the Command Block to be the last command block */
 	ntcb_hdr->cb_cmd |= __constant_cpu_to_le16(CB_EL_BIT);
@@ -2656,7 +2634,7 @@
 	if (in_interrupt())
 		return e100_delayed_exec_non_cu_cmd(bdp, command);
 
-	if (netif_running(bdp->device) && (!bdp->driver_isolated))
+	if (netif_running(bdp->device) && netif_carrier_ok(bdp->device))
 		return e100_delayed_exec_non_cu_cmd(bdp, command);
 
 	spin_lock_bh(&(bdp->bd_non_tx_lock));
@@ -2678,7 +2656,7 @@
 
 	spin_lock_irqsave(&bdp->bd_lock, lock_flag);
 
-	if (!e100_wait_exec_cmplx(bdp, command->dma_addr, SCB_CUC_START)) {
+	if (!e100_wait_exec_cmplx(bdp, command->dma_addr, SCB_CUC_START, sub_cmd)) {
 		spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag);
 		rc = false;
 		goto exit;
@@ -2698,6 +2676,10 @@
 			yield();
 			spin_lock_bh(&(bdp->bd_non_tx_lock));
 		} else {
+#ifdef E100_CU_DEBUG			
+			printk(KERN_ERR "e100: %s: non-TX command (%x) "
+				"timeout\n", bdp->device->name, sub_cmd);
+#endif			
 			rc = false;
 			goto exit;
 		}
@@ -2743,7 +2725,12 @@
 	}
 
 	/* Mask off our interrupt line -- its unmasked after reset */
-	e100_dis_intr(bdp);
+	e100_disable_clear_intr(bdp);
+#ifdef E100_CU_DEBUG	
+	bdp->last_cmd = 0;
+	bdp->last_sub_cmd = 0;
+#endif	
+
 }
 
 /**
@@ -2943,19 +2930,6 @@
 void __devinit
 e100_print_brd_conf(struct e100_private *bdp)
 {
-	if (netif_carrier_ok(bdp->device)) {
-		printk(KERN_NOTICE
-		       "  Mem:0x%08lx  IRQ:%d  Speed:%d Mbps  Dx:%s\n",
-		       (unsigned long) bdp->device->mem_start,
-		       bdp->device->irq, bdp->cur_line_speed,
-		       (bdp->cur_dplx_mode == FULL_DUPLEX) ? "Full" : "Half");
-	} else {
-		printk(KERN_NOTICE
-		       "  Mem:0x%08lx  IRQ:%d  Speed:%d Mbps  Dx:%s\n",
-		       (unsigned long) bdp->device->mem_start,
-		       bdp->device->irq, 0, "N/A");
-	}
-
 	/* Print the string if checksum Offloading was enabled */
 	if (bdp->flags & DF_CSUM_OFFLOAD)
 		printk(KERN_NOTICE "  Hardware receive checksums enabled\n");
@@ -3054,33 +3028,31 @@
 void
 e100_isolate_driver(struct e100_private *bdp)
 {
-	write_lock_irq(&(bdp->isolate_lock));
-	bdp->driver_isolated = true;
-	write_unlock_irq(&(bdp->isolate_lock));
-
-	del_timer_sync(&bdp->watchdog_timer);
-
-	del_timer_sync(&bdp->hwi_timer);
-	/* If in middle of cable diag, */
-	if (bdp->hwi_started) {
-		bdp->hwi_started = 0;
-		e100_hwi_restore(bdp);
-	}
-
-	if (netif_running(bdp->device))
-		netif_stop_queue(bdp->device);
-
-	bdp->last_tcb = NULL;
 
+	/* Check if interface is up                              */
+	/* NOTE: Can't use netif_running(bdp->device) because    */
+	/* dev_close clears __LINK_STATE_START before calling    */
+	/* e100_close (aka dev->stop)                            */
+	if (bdp->device->flags & IFF_UP) {
+		e100_disable_clear_intr(bdp);
+		del_timer_sync(&bdp->watchdog_timer);
+		netif_carrier_off(bdp->device);
+		netif_stop_queue(bdp->device); 
+		bdp->last_tcb = NULL;
+	} 
 	e100_sw_reset(bdp, PORT_SELECTIVE_RESET);
 }
 
 void
 e100_set_speed_duplex(struct e100_private *bdp)
 {
+	if (netif_carrier_ok(bdp->device))
+		e100_isolate_driver(bdp);
 	e100_phy_set_speed_duplex(bdp, true);
 	e100_config_fc(bdp);	/* re-config flow-control if necessary */
 	e100_config(bdp);	
+	if (netif_carrier_ok(bdp->device))
+		e100_deisolate_driver(bdp, false);
 }
 
 static void
@@ -3095,63 +3067,51 @@
 }
 
 /* 
- * Procedure:   e100_hw_reset_recover
+ * Procedure:   e100_configure_device
  *
- * Description: This routine will recover the hw after reset.
+ * Description: This routine will configure device
  *
  * Arguments:
  *      bdp - Ptr to this card's e100_bdconfig structure
- *        reset_cmd - s/w reset or selective reset. 
  *
  * Returns:
  *        true upon success
  *        false upon failure
  */
 unsigned char
-e100_hw_reset_recover(struct e100_private *bdp, u32 reset_cmd)
+e100_configure_device(struct e100_private *bdp)
 {
-	bdp->last_tcb = NULL;
-	if (reset_cmd == PORT_SOFTWARE_RESET) {
-
-		/*load CU & RU base */
-		if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE)) {
-			return false;
-		}
-
-		if (e100_load_microcode(bdp)) {
-			bdp->flags |= DF_UCODE_LOADED;
-		}
+	/*load CU & RU base */
+	if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE, 0))
+		return false;
 
-		if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE)) {
-			return false;
-		}
+	if (e100_load_microcode(bdp))
+		bdp->flags |= DF_UCODE_LOADED;
 
-		/* Issue the load dump counters address command */
-		if (!e100_wait_exec_cmplx(bdp, bdp->stat_cnt_phys,
-					  SCB_CUC_DUMP_ADDR)) {
-			return false;
-		}
+	if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE, 0))
+		return false;
 
-		if (!e100_setup_iaaddr(bdp, bdp->device->dev_addr)) {
-			printk(KERN_ERR
-			       "e100: e100_hw_reset_recover: "
-			       "setup iaaddr failed\n");
-			return false;
-		}
+	/* Issue the load dump counters address command */
+	if (!e100_wait_exec_cmplx(bdp, bdp->stat_cnt_phys, SCB_CUC_DUMP_ADDR, 0))
+		return false;
 
-		e100_set_multi_exec(bdp->device);
+	if (!e100_setup_iaaddr(bdp, bdp->device->dev_addr)) {
+		printk(KERN_ERR "e100: e100_configure_device: "
+			"setup iaaddr failed\n");
+		return false;
+	}
 
-		/* Change for 82558 enhancement */
-		/* If 82558/9 and if the user has enabled flow control, set up * the
-		 * Flow Control Reg. in the CSR */
-		if ((bdp->flags & IS_BACHELOR)
-		    && (bdp->params.b_params & PRM_FC)) {
-			writeb(DFLT_FC_THLD,
-			       &bdp->scb->scb_ext.d101_scb.scb_fc_thld);
-			writeb(DFLT_FC_CMD,
-			       &bdp->scb->scb_ext.d101_scb.scb_fc_xon_xoff);
-		}
+	e100_set_multi_exec(bdp->device);
 
+	/* Change for 82558 enhancement                                */
+	/* If 82558/9 and if the user has enabled flow control, set up */
+	/* flow Control Reg. in the CSR                                */
+	if ((bdp->flags & IS_BACHELOR)
+	    && (bdp->params.b_params & PRM_FC)) {
+		writeb(DFLT_FC_THLD,
+			&bdp->scb->scb_ext.d101_scb.scb_fc_thld);
+		writeb(DFLT_FC_CMD,
+			&bdp->scb->scb_ext.d101_scb.scb_fc_xon_xoff);
 	}
 
 	e100_force_config(bdp);
@@ -3160,29 +3120,21 @@
 }
 
 void
-e100_deisolate_driver(struct e100_private *bdp, u8 recover, u8 full_init)
+e100_deisolate_driver(struct e100_private *bdp, u8 full_reset)
 {
-	if (full_init) {
-		e100_sw_reset(bdp, PORT_SOFTWARE_RESET);
-		if (!e100_hw_reset_recover(bdp, PORT_SOFTWARE_RESET))
-			printk(KERN_ERR "e100: e100_deisolate_driver:"
-			       " HW SOFTWARE reset recover failed\n");
-	}
+	u32 cmd = full_reset ? PORT_SOFTWARE_RESET : PORT_SELECTIVE_RESET;
+	e100_sw_reset(bdp, cmd);
+	if (cmd == PORT_SOFTWARE_RESET) {
+		if (!e100_configure_device(bdp))
+			printk(KERN_ERR "e100: e100_deisolate_driver:" 
+		       		" device configuration failed\n");
+	} 
 
-	if (recover) {
+	if (netif_running(bdp->device)) {
 
 		bdp->next_cu_cmd = START_WAIT;
 		bdp->last_tcb = NULL;
 
-		/* lets reset the chip */
-		if (!full_init) {
-			e100_sw_reset(bdp, PORT_SELECTIVE_RESET);
-
-			if (!e100_hw_reset_recover(bdp, PORT_SELECTIVE_RESET)) {
-				printk(KERN_ERR "e100: e100_deisolate_driver:"
-				       " HW reset recover failed\n");
-			}
-		}
 		e100_start_ru(bdp);
 
 		/* relaunch watchdog timer in 2 sec */
@@ -3192,14 +3144,9 @@
 		// or have unsent frames on the tcb chain
 		e100_tcb_add_C_bit(bdp);
 		e100_tx_srv(bdp);
-
+		netif_wake_queue(bdp->device);
 		e100_set_intr_mask(bdp);
-
-		if (netif_running(bdp->device))
-			netif_wake_queue(bdp->device);
 	}
-
-	bdp->driver_isolated = false;
 }
 
 static int
@@ -3234,6 +3181,22 @@
 	case ETHTOOL_SEEPROM:
 		rc = e100_ethtool_eeprom(dev, ifr);
 		break;
+	case ETHTOOL_GSTATS: {
+		struct {
+			struct ethtool_stats cmd;
+			uint64_t data[E100_STATS_LEN];
+		} stats = { {ETHTOOL_GSTATS, E100_STATS_LEN} };
+		struct e100_private *bdp = dev->priv;
+		void *addr = ifr->ifr_data;
+		int i;
+
+		for(i = 0; i < E100_STATS_LEN; i++)
+			stats.data[i] =
+				((unsigned long *)&bdp->drv_stats.net_stats)[i];
+		if(copy_to_user(addr, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
 	case ETHTOOL_GWOL:
 	case ETHTOOL_SWOL:
 		rc = e100_ethtool_wol(dev, ifr);
@@ -3316,10 +3279,8 @@
 e100_ethtool_set_settings(struct net_device *dev, struct ifreq *ifr)
 {
 	struct e100_private *bdp;
-	int current_duplex;
 	int e100_new_speed_duplex;
 	int ethtool_new_speed_duplex;
-	int speed_duplex_change_required;
 	struct ethtool_cmd ecmd;
 
 	if (!capable(CAP_NET_ADMIN)) {
@@ -3327,64 +3288,48 @@
 	}
 
 	bdp = dev->priv;
-	if (netif_running(dev)) {
-		return -EBUSY;
-	}
 	if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd))) {
 		return -EFAULT;
 	}
-	current_duplex =
-		(bdp->cur_dplx_mode == HALF_DUPLEX) ? DUPLEX_HALF : DUPLEX_FULL;
-	speed_duplex_change_required = (ecmd.speed != bdp->cur_line_speed)
-		|| (ecmd.duplex != current_duplex);
-
-	if ((ecmd.autoneg == AUTONEG_ENABLE) && speed_duplex_change_required) {
-		return -EINVAL;
-	}
 
 	if ((ecmd.autoneg == AUTONEG_ENABLE)
 	    && (bdp->speed_duplex_caps & SUPPORTED_Autoneg)) {
 		bdp->params.e100_speed_duplex = E100_AUTONEG;
 		e100_set_speed_duplex(bdp);
 	} else {
-		if (speed_duplex_change_required) {
-			if (ecmd.speed == SPEED_10) {
-				if (ecmd.duplex == DUPLEX_HALF) {
-					e100_new_speed_duplex =
-						E100_SPEED_10_HALF;
-					ethtool_new_speed_duplex =
-						SUPPORTED_10baseT_Half;
-
-				} else {
-					e100_new_speed_duplex =
-						E100_SPEED_10_FULL;
-					ethtool_new_speed_duplex =
-						SUPPORTED_10baseT_Full;
-				}
-
-			} else {
-				if (ecmd.duplex == DUPLEX_HALF) {
-					e100_new_speed_duplex =
-						E100_SPEED_100_HALF;
-					ethtool_new_speed_duplex =
-						SUPPORTED_100baseT_Half;
-
-				} else {
-					e100_new_speed_duplex =
-						E100_SPEED_100_FULL;
-					ethtool_new_speed_duplex =
-						SUPPORTED_100baseT_Full;
-				}
-			}
-
-			if (bdp->speed_duplex_caps & ethtool_new_speed_duplex) {
-				bdp->params.e100_speed_duplex =
-					e100_new_speed_duplex;
-				e100_set_speed_duplex(bdp);
-			} else {
-				return -EOPNOTSUPP;
-			}
-		}
+		if (ecmd.speed == SPEED_10) {
+			if (ecmd.duplex == DUPLEX_HALF) {
+				e100_new_speed_duplex =
+					E100_SPEED_10_HALF;
+				ethtool_new_speed_duplex =
+					SUPPORTED_10baseT_Half;
+			} else { 
+				e100_new_speed_duplex =
+					E100_SPEED_10_FULL;
+				ethtool_new_speed_duplex =
+					SUPPORTED_10baseT_Full;
+			} 
+		} else { 
+			if (ecmd.duplex == DUPLEX_HALF) {
+				e100_new_speed_duplex =
+					E100_SPEED_100_HALF;
+				ethtool_new_speed_duplex =
+					SUPPORTED_100baseT_Half;
+			} else { 
+				e100_new_speed_duplex =
+					E100_SPEED_100_FULL;
+				ethtool_new_speed_duplex =
+					SUPPORTED_100baseT_Full;
+			} 
+		}
+
+		if (bdp->speed_duplex_caps & ethtool_new_speed_duplex) {
+			bdp->params.e100_speed_duplex =
+				e100_new_speed_duplex;
+			e100_set_speed_duplex(bdp);
+		} else {
+			return -EOPNOTSUPP;
+		} 
 	}
 
 	return 0;
@@ -3503,6 +3448,7 @@
 		sizeof (info.fw_version) - 1);
 	strncpy(info.bus_info, bdp->pdev->slot_name,
 		sizeof (info.bus_info) - 1);
+	info.n_stats = E100_STATS_LEN;
 	info.regdump_len  = E100_REGS_LEN * sizeof(u32);
 	info.eedump_len = (bdp->eeprom_size << 1);	
 	info.testinfo_len = E100_MAX_TEST_RES;
@@ -3863,6 +3809,19 @@
 				test_strings[i]);
 		}
 		break;
+	case ETH_SS_STATS: {
+		char *strings = NULL;
+		void *addr = ifr->ifr_data;
+		info.len = E100_STATS_LEN;
+		strings = *e100_gstrings_stats;
+		if(copy_to_user(ifr->ifr_data, &info, sizeof(info)))
+			return -EFAULT;
+		addr += offsetof(struct ethtool_gstrings, data);
+		if(copy_to_user(addr, strings,
+		   info.len * ETH_GSTRING_LEN))
+			return -EFAULT;
+		return 0;
+	}
 	default:
 		return -EOPNOTSUPP;
 	}
@@ -3901,9 +3860,6 @@
 	case SIOCSMIIREG:
 		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
-		if (netif_running(dev)) {
-			return -EBUSY;
-		}
 		/* If reg = 0 && change speed/duplex */
 		if (data_ptr->reg_num == 0 && 
 			(data_ptr->val_in == (BMCR_ANENABLE | BMCR_ANRESTART) /* restart cmd */
@@ -3923,10 +3879,9 @@
 					bdp->params.e100_speed_duplex = E100_SPEED_10_HALF;
 				e100_set_speed_duplex(bdp);
 		}
-		else {
-			e100_mdi_write(bdp, data_ptr->reg_num, bdp->phy_addr,
-			       data_ptr->val_in);
-		}
+		else 
+			/* Only allows changing speed/duplex */
+			return -EINVAL;
 		
 		break;
 
@@ -4023,6 +3978,8 @@
 	struct e100_private *bdp = (struct e100_private *) ptr;
 	nxmit_cb_entry_t *active_command;
 	int restart = true;
+	cb_header_t *non_tx_cmd;
+	u8 sub_cmd;
 
 	spin_lock_bh(&(bdp->bd_non_tx_lock));
 
@@ -4050,6 +4007,15 @@
 		    && time_before(jiffies, active_command->expiration_time)) {
 			goto exit;
 		} else {
+			non_tx_cmd = (cb_header_t *) active_command->non_tx_cmd;
+			sub_cmd = CB_CMD_MASK & le16_to_cpu(non_tx_cmd->cb_cmd);
+#ifdef E100_CU_DEBUG			
+			if (!(non_tx_cmd->cb_status 
+			    & __constant_cpu_to_le16(CB_STATUS_COMPLETE)))
+				printk(KERN_ERR "e100: %s: Queued "
+					"command (%x) timeout\n", 
+					bdp->device->name, sub_cmd);
+#endif			
 			list_del(&(active_command->list_elem));
 			e100_free_non_tx_cmd(bdp, active_command);
 		}
@@ -4072,9 +4038,10 @@
 		bdp->non_tx_command_state = E100_WAIT_NON_TX_FINISH;
 		active_command = list_entry(bdp->non_tx_cmd_list.next,
 					    nxmit_cb_entry_t, list_elem);
+		sub_cmd = ((cb_header_t *) active_command->non_tx_cmd)->cb_cmd;
 		spin_lock_irq(&(bdp->bd_lock));
 		e100_wait_exec_cmplx(bdp, active_command->dma_addr,
-				     SCB_CUC_START);
+				     SCB_CUC_START, sub_cmd);
 		spin_unlock_irq(&(bdp->bd_lock));
 		active_command->expiration_time = jiffies + HZ;
 		cmd_type = CB_CMD_MASK &
@@ -4093,29 +4060,6 @@
 	spin_unlock_bh(&(bdp->bd_non_tx_lock));
 }
 
-int e100_notify_netdev(struct notifier_block *nb, unsigned long event, void *p)
-{
-	struct e100_private *bdp;
-	struct net_device *netdev = p;
-	
-	if(netdev == NULL)
-		return NOTIFY_DONE;
-	
-	switch(event) {
-	case NETDEV_CHANGENAME:
-		if(netdev->open == e100_open) {
-			bdp = netdev->priv;
-			/* rename the proc nodes the easy way */
-			e100_remove_proc_subdir(bdp, bdp->ifname);
-			memcpy(bdp->ifname, netdev->name, IFNAMSIZ);
-			bdp->ifname[IFNAMSIZ-1] = 0;
-			e100_create_proc_subdir(bdp, bdp->ifname);
-		}
-		break;
-	}
-	return NOTIFY_DONE;
-}
-
 #ifdef CONFIG_PM
 static int
 e100_notify_reboot(struct notifier_block *nb, unsigned long event, void *p)
@@ -4147,9 +4091,11 @@
 	e100_isolate_driver(bdp);
 	pci_save_state(pcid, bdp->pci_state);
 
+	/* Enable or disable WoL */
+	e100_do_wol(pcid, bdp);
+	
 	/* If wol is enabled */
 	if (bdp->wolopts) {
-		e100_do_wol(pcid, bdp);
 		pci_enable_wake(pcid, 3, 1);	/* Enable PME for power state D3 */
 		pci_set_power_state(pcid, 3);	/* Set power state to D3.        */
 	} else {
@@ -4165,145 +4111,31 @@
 {
 	struct net_device *netdev = pci_get_drvdata(pcid);
 	struct e100_private *bdp = netdev->priv;
-	u8 recover = false;
-	u8 full_init = false;
 
 	pci_set_power_state(pcid, 0);
 	pci_enable_wake(pcid, 0, 0);	/* Clear PME status and disable PME */
 	pci_restore_state(pcid, bdp->pci_state);
 
-	if (netif_running(netdev)) {
-		recover = true;
-	}
-
-	if (bdp->wolopts & (WAKE_UCAST | WAKE_ARP)) {
-		full_init = true;
-	}
-
-	e100_deisolate_driver(bdp, recover, full_init);
+	/* Also do device full reset because device was in D3 state */
+	e100_deisolate_driver(bdp, true);
 
 	return 0;
 }
 #endif /* CONFIG_PM */
 
-static void
-e100_get_mdix_status(struct e100_private *bdp)
-{	
-	if (bdp->rev_id < D102_REV_ID) {
-		if (netif_carrier_ok(bdp->device))
-			bdp->mdix_status = "MDI";				
-		else			
-			bdp->mdix_status = "None";
-	} else {	
-		u16 ctrl_reg;
-		/* Read the MDIX control register */
-		e100_mdi_read(bdp, MII_NCONFIG, bdp->phy_addr, &ctrl_reg);
-		if (ctrl_reg & MDI_MDIX_CONFIG_IS_OK) {
-			if (ctrl_reg & MDI_MDIX_STATUS)
-				bdp->mdix_status = "MDI-X";
-			else
-				bdp->mdix_status = "MDI";
-		} else
-			bdp->mdix_status = "None";
-	}
-}
-
-static void
-e100_do_hwi(struct net_device *dev)
+#ifdef E100_CU_DEBUG
+unsigned char
+e100_cu_unknown_state(struct e100_private *bdp)
 {
-	struct e100_private *bdp = dev->priv;
-	u16 ctrl_reg;
-	int distance, open_circut, short_circut;
-
-	e100_mdi_read(bdp, HWI_CONTROL_REG, bdp->phy_addr, &ctrl_reg);
-
-	distance = ctrl_reg & HWI_TEST_DISTANCE;
-	open_circut = ctrl_reg & HWI_TEST_HIGHZ_PROBLEM;
-	short_circut = ctrl_reg & HWI_TEST_LOWZ_PROBLEM;
-
-	if ((distance == bdp->saved_distance) &&
-	    (open_circut == bdp->saved_open_circut) &&
-	    (short_circut == bdp->saved_short_circut)) 
-		bdp->saved_same++;
-	else {
-		bdp->saved_same = 0;
-		bdp->saved_distance = distance;
-		bdp->saved_open_circut = open_circut;
-		bdp->saved_short_circut = short_circut;
-	}
-		
-	if (bdp->saved_same == MAX_SAME_RESULTS) {
-		if ((open_circut && !(short_circut)) ||
-		    (!(open_circut) && short_circut)) {
-
-			u8 near_end = ((distance * HWI_REGISTER_GRANULARITY) <
-				       HWI_NEAR_END_BOUNDARY);
-			if (open_circut) {
-				if (near_end) 
-					bdp->cable_status = "Open Circut Near End";
-				else 
-					bdp->cable_status = "Open Circut Far End";
-			} else {
-				if (near_end) 
-					bdp->cable_status = "Short Circut Near End";
-				else 
-					bdp->cable_status = "Short Circut Far End";
-			}
-			goto done;
-		}
-	}
-	else if (bdp->saved_i == HWI_MAX_LOOP) {
-		bdp->cable_status = "Test failed";
-		goto done;
-	}
-		
-	/* Do another hwi test */
-	e100_mdi_write(bdp, HWI_CONTROL_REG, bdp->phy_addr,
-		       (HWI_TEST_ENABLE | HWI_TEST_EXECUTE));
-	bdp->saved_i++;
-	/* relaunch hwi timer in 1 msec */
-	mod_timer(&(bdp->hwi_timer), jiffies + (HZ / 1000) );
-	return;
-
-done:
-	e100_hwi_restore(bdp);
-	bdp->hwi_started = 0;
-	return;
+	u8 scb_cmd_low;
+	u16 scb_status;
+	scb_cmd_low = bdp->scb->scb_cmd_low;
+	scb_status = le16_to_cpu(bdp->scb->scb_status);
+	/* If CU is active and executing unknown cmd */
+	if (scb_status & SCB_CUS_ACTIVE && scb_cmd_low & SCB_CUC_UNKNOWN)
+		return true;
+	else
+		return false;
 }
+#endif
 
-static void e100_hwi_restore(struct e100_private *bdp)
-{
-	u16 control = 0;
-
-	/* Restore speed, duplex and autoneg before */
-	/* hwi test, i.e., cable diagnostic         */
-	
-	/* Reset hwi test */
-        e100_mdi_write(bdp, HWI_CONTROL_REG, bdp->phy_addr,					       HWI_RESET_ALL_MASK);
-				
-	if ((bdp->params.e100_speed_duplex == E100_AUTONEG) &&
-        	(bdp->rev_id >= D102_REV_ID)) 
-		/* Enable MDI/MDI-X auto switching */
-                e100_mdi_write(bdp, MII_NCONFIG, bdp->phy_addr,
-			MDI_MDIX_AUTO_SWITCH_ENABLE);
-
-	switch (bdp->params.e100_speed_duplex) {
-	case E100_SPEED_10_HALF:
-		break;
-	case E100_SPEED_10_FULL:
-		control = BMCR_FULLDPLX;
-		break;
-	case E100_SPEED_100_HALF:
-		control = BMCR_SPEED100;
-		break;
-	case E100_SPEED_100_FULL:
-		control = BMCR_SPEED100 | BMCR_FULLDPLX;
-		break;
-	case E100_AUTONEG:
-		control = BMCR_ANENABLE | BMCR_ANRESTART;
-		break;
-	}
-	/* Restore original speed/duplex */
-	e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, control);
-	return;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/e100/e100_proc.c linux-2.4.21-pre6/drivers/net/e100/e100_proc.c
--- linux-2.4.20/drivers/net/e100/e100_proc.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/e100/e100_proc.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,474 +0,0 @@
-/*******************************************************************************
-
-  
-  Copyright(c) 1999 - 2002 Intel Corporation. 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., 59 
-  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-  
-  The full GNU General Public License is included in this distribution in the
-  file called LICENSE.
-  
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-*******************************************************************************/
-
-/**********************************************************************
-*                                                                       *
-* INTEL CORPORATION                                                     *
-*                                                                       *
-* This software is supplied under the terms of the license included     *
-* above.  All use of this driver must be in accordance with the terms   *
-* of that license.                                                      *
-*                                                                       *
-* Module Name:  e100_proc.c                                             *
-*                                                                       *
-* Abstract:     Functions to handle the proc file system.               *
-*               Create the proc directories and files and run read and  *
-*               write requests from the user                            *
-*                                                                       *
-* Environment:  This file is intended to be specific to the Linux       *
-*               operating system.                                       *
-*                                                                       *
-**********************************************************************/
-
-#include <linux/config.h>
-
-#ifdef CONFIG_PROC_FS
-#include "e100.h"
-/* MDI sleep time is at least 50 ms, in jiffies */
-#define MDI_SLEEP_TIME ((HZ / 20) + 1)
-/***************************************************************************/
-/*       /proc File System Interaface Support Functions                    */
-/***************************************************************************/
-
-static struct proc_dir_entry *adapters_proc_dir = 0;
-
-/* externs from e100_main.c */
-extern char e100_short_driver_name[];
-extern char e100_driver_version[];
-extern struct net_device_stats *e100_get_stats(struct net_device *dev);
-extern char *e100_get_brand_msg(struct e100_private *bdp);
-extern int e100_mdi_write(struct e100_private *, u32, u32, u16);
-
-static void e100_proc_cleanup(void);
-static unsigned char e100_init_proc_dir(void);
-
-#define ADAPTERS_PROC_DIR "PRO_LAN_Adapters"
-#define WRITE_BUF_MAX_LEN 20	
-#define READ_BUF_MAX_LEN  256
-#define E100_PE_LEN       25
-
-#define bdp_drv_off(off) (unsigned long)(offsetof(struct e100_private, drv_stats.off))
-#define bdp_prm_off(off) (unsigned long)(offsetof(struct e100_private, params.off))
-
-typedef struct _e100_proc_entry {
-	char *name;
-	read_proc_t *read_proc;
-	write_proc_t *write_proc;
-	unsigned long offset;	/* offset into bdp. ~0 means no value, pass NULL. */
-} e100_proc_entry;
-
-static int
-generic_read(char *page, char **start, off_t off, int count, int *eof, int len)
-{
-	if (len <= off + count)
-		*eof = 1;
-
-	*start = page + off;
-	len -= off;
-	if (len > count)
-		len = count;
-
-	if (len < 0)
-		len = 0;
-
-	return len;
-}
-
-static int
-read_ulong(char *page, char **start, off_t off,
-	   int count, int *eof, unsigned long l)
-{
-	int len;
-
-	len = sprintf(page, "%lu\n", l);
-
-	return generic_read(page, start, off, count, eof, len);
-}
-
-static int
-read_gen_ulong(char *page, char **start, off_t off,
-	       int count, int *eof, void *data)
-{
-	unsigned long val = 0;
-
-	if (data)
-		val = *((unsigned long *) data);
-
-	return read_ulong(page, start, off, count, eof, val);
-}
-
-static int
-read_hwaddr(char *page, char **start, off_t off,
-	    int count, int *eof, unsigned char *hwaddr)
-{
-	int len;
-
-	len = sprintf(page, "%02X:%02X:%02X:%02X:%02X:%02X\n",
-		      hwaddr[0], hwaddr[1], hwaddr[2],
-		      hwaddr[3], hwaddr[4], hwaddr[5]);
-
-	return generic_read(page, start, off, count, eof, len);
-}
-
-static int
-read_descr(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
-	struct e100_private *bdp = data;
-	int len;
-
-	len = sprintf(page, "%s\n", bdp->id_string);
-
-	return generic_read(page, start, off, count, eof, len);
-}
-
-static int
-read_permanent_hwaddr(char *page, char **start, off_t off,
-		      int count, int *eof, void *data)
-{
-	struct e100_private *bdp = data;
-	unsigned char *hwaddr = bdp->perm_node_address;
-
-	return read_hwaddr(page, start, off, count, eof, hwaddr);
-}
-
-static int
-read_part_number(char *page, char **start, off_t off,
-		 int count, int *eof, void *data)
-{
-	struct e100_private *bdp = data;
-	int len;
-
-	len = sprintf(page, "%06lx-%03x\n",
-		      (unsigned long) (bdp->pwa_no >> 8),
-		      (unsigned int) (bdp->pwa_no & 0xFF));
-
-	return generic_read(page, start, off, count, eof, len);
-}
-
-static void
-set_led(struct e100_private *bdp, u16 led_mdi_op)
-{
-	e100_mdi_write(bdp, PHY_82555_LED_SWITCH_CONTROL,
-		       bdp->phy_addr, led_mdi_op);
-
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(MDI_SLEEP_TIME);
-
-	/* turn led ownership to the chip */
-	e100_mdi_write(bdp, PHY_82555_LED_SWITCH_CONTROL,
-		       bdp->phy_addr, PHY_82555_LED_NORMAL_CONTROL);
-}
-
-static int
-write_blink_led_timer(struct file *file, const char *buffer,
-		      unsigned long count, void *data)
-{
-	struct e100_private *bdp = data;
-	char s_blink_op[WRITE_BUF_MAX_LEN + 1];
-	char *res;
-	unsigned long i_blink_op;
-
-	if (!buffer)
-		return -EINVAL;
-
-	if (count > WRITE_BUF_MAX_LEN) {
-		count = WRITE_BUF_MAX_LEN;
-	}
-	if (copy_from_user(s_blink_op, buffer, count))
-		return -EFAULT;
-	s_blink_op[count] = '\0';
-	i_blink_op = simple_strtoul(s_blink_op, &res, 0);
-	if (res == s_blink_op) {
-		return -EINVAL;
-	}
-
-	switch (i_blink_op) {
-
-	case LED_OFF:
-		set_led(bdp, PHY_82555_LED_OFF);
-		break;
-	case LED_ON:
-		if (bdp->rev_id >= D101MA_REV_ID)
-			set_led(bdp, PHY_82555_LED_ON_559);
-		else
-			set_led(bdp, PHY_82555_LED_ON_PRE_559);
-
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return count;
-}
-
-static e100_proc_entry e100_proc_list[] = {
-	{"Description",           read_descr,            0, 0},
-	{"Permanent_HWaddr",      read_permanent_hwaddr, 0, 0},
-	{"Part_Number",           read_part_number,      0, 0},
-	{"\n",},
-	{"Rx_TCP_Checksum_Good",  read_gen_ulong, 0, ~0},
-	{"Rx_TCP_Checksum_Bad",   read_gen_ulong, 0, ~0},
-	{"Tx_TCP_Checksum_Good",  read_gen_ulong, 0, ~0},
-	{"Tx_TCP_Checksum_Bad",   read_gen_ulong, 0, ~0},
-	{"\n",},
-	{"Tx_Abort_Late_Coll",    read_gen_ulong, 0, bdp_drv_off(tx_late_col)},
-	{"Tx_Deferred_Ok",        read_gen_ulong, 0, bdp_drv_off(tx_ok_defrd)},
-	{"Tx_Single_Coll_Ok",     read_gen_ulong, 0, bdp_drv_off(tx_one_retry)},
-	{"Tx_Multi_Coll_Ok",      read_gen_ulong, 0, bdp_drv_off(tx_mt_one_retry)},
-	{"Rx_Long_Length_Errors", read_gen_ulong, 0, ~0},
-	{"\n",},
-	{"Tx_Flow_Control_Pause", read_gen_ulong, 0, bdp_drv_off(xmt_fc_pkts)},
-	{"Rx_Flow_Control_Pause", read_gen_ulong, 0, bdp_drv_off(rcv_fc_pkts)},
-	{"Rx_Flow_Control_Unsup", read_gen_ulong, 0, bdp_drv_off(rcv_fc_unsupported)},
-	{"\n",},
-	{"Tx_TCO_Packets",        read_gen_ulong, 0, bdp_drv_off(xmt_tco_pkts)},
-	{"Rx_TCO_Packets",        read_gen_ulong, 0, bdp_drv_off(rcv_tco_pkts)},
-	{"\n",},
-	{"Rx_Interrupt_Packets",  read_gen_ulong, 0, bdp_drv_off(rx_intr_pkts)},
-	{"Identify_Adapter", 0, write_blink_led_timer, 0},
-	{"", 0, 0, 0}
-};
-
-static int
-read_info(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
-	struct e100_private *bdp = data;
-	e100_proc_entry *pe;
-	int tmp;
-	void *val;
-	int len = 0;
-
-	for (pe = e100_proc_list; pe->name[0]; pe++) {
-		if (pe->name[0] == '\n') {
-			len += sprintf(page + len, "\n");
-			continue;
-		}
-
-		if (pe->read_proc) {
-			if ((len + READ_BUF_MAX_LEN + E100_PE_LEN + 1) >=
-			    PAGE_SIZE)
-				break;
-
-			if (pe->offset != ~0)
-				val = ((char *) bdp) + pe->offset;
-			else
-				val = NULL;
-
-			len += sprintf(page + len, "%-"
-				       __MODULE_STRING(E100_PE_LEN)
-				       "s ", pe->name);
-			len += pe->read_proc(page + len, start, 0,
-					     READ_BUF_MAX_LEN + 1, &tmp, val);
-		}
-	}
-
-	return generic_read(page, start, off, count, eof, len);
-}
-
-static struct proc_dir_entry *
-create_proc_rw(char *name, void *data, struct proc_dir_entry *parent,
-	       read_proc_t * read_proc, write_proc_t * write_proc)
-{
-	struct proc_dir_entry *pdep;
-	mode_t mode = S_IFREG;
-
-	if (write_proc) {
-		mode |= S_IWUSR;
-		if (read_proc) {
-			mode |= S_IRUSR;
-		}
-
-	} else if (read_proc) {
-		mode |= S_IRUGO;
-	}
-
-	if (!(pdep = create_proc_entry(name, mode, parent)))
-		return NULL;
-
-	pdep->read_proc = read_proc;
-	pdep->write_proc = write_proc;
-	pdep->data = data;
-	return pdep;
-}
-
-void
-e100_remove_proc_subdir(struct e100_private *bdp, char *name)
-{
-	e100_proc_entry *pe;
-	char info[256];
-	int len;
-
-	/* If our root /proc dir was not created, there is nothing to remove */
-	if (adapters_proc_dir == NULL) {
-		return;
-	}
-
-	len = strlen(bdp->ifname);
-	strncpy(info, bdp->ifname, sizeof (info));
-	strncat(info + len, ".info", sizeof (info) - len);
-
-	if (bdp->proc_parent) {
-		for (pe = e100_proc_list; pe->name[0]; pe++) {
-			if (pe->name[0] == '\n')
-				continue;
-
-			remove_proc_entry(pe->name, bdp->proc_parent);
-		}
-
-		remove_proc_entry(bdp->ifname, adapters_proc_dir);
-		bdp->proc_parent = NULL;
-	}
-
-	remove_proc_entry(info, adapters_proc_dir);
-
-	/* try to remove the main /proc dir, if it's empty */
-	e100_proc_cleanup();
-}
-
-int
-e100_create_proc_subdir(struct e100_private *bdp)
-{
-	struct proc_dir_entry *dev_dir;
-	e100_proc_entry *pe;
-	char info[256];
-	int len;
-	void *data;
-
-	/* create the main /proc dir if needed */
-	if (!adapters_proc_dir) {
-		if (!e100_init_proc_dir())
-			return -ENOMEM;
-	}
-
-	strncpy(info, bdp->ifname, sizeof (info));
-	len = strlen(info);
-	strncat(info + len, ".info", sizeof (info) - len);
-
-	/* info */
-	if (!(create_proc_rw(info, bdp, adapters_proc_dir, read_info, 0))) {
-		e100_proc_cleanup();
-		return -ENOMEM;
-	}
-
-	dev_dir = create_proc_entry(bdp->ifname, S_IFDIR,
-				    adapters_proc_dir);
-	bdp->proc_parent = dev_dir;
-
-	if (!dev_dir) {
-		e100_remove_proc_subdir(bdp, bdp->ifname);
-		return -ENOMEM;
-	}
-
-	for (pe = e100_proc_list; pe->name[0]; pe++) {
-		if (pe->name[0] == '\n')
-			continue;
-
-		if (pe->offset != ~0)
-			data = ((char *) bdp) + pe->offset;
-		else
-			data = NULL;
-
-		if (!(create_proc_rw(pe->name, data, dev_dir,
-				     pe->read_proc, pe->write_proc))) {
-			e100_remove_proc_subdir(bdp, bdp->ifname);
-			return -ENOMEM;
-		}
-	}
-
-	return 0;
-}
-
-/****************************************************************************
- * Name:          e100_init_proc_dir
- *
- * Description:   This routine creates the top-level /proc directory for the
- *                driver in /proc/net
- *
- * Arguments:     none
- *
- * Returns:       true on success, false on fail
- *
- ***************************************************************************/
-static unsigned char
-e100_init_proc_dir(void)
-{
-	int len;
-
-	/* first check if adapters_proc_dir already exists */
-	len = strlen(ADAPTERS_PROC_DIR);
-	for (adapters_proc_dir = proc_net->subdir;
-	     adapters_proc_dir; adapters_proc_dir = adapters_proc_dir->next) {
-
-		if ((adapters_proc_dir->namelen == len) &&
-		    (!memcmp(adapters_proc_dir->name, ADAPTERS_PROC_DIR, len)))
-			break;
-	}
-
-	if (!adapters_proc_dir)
-		adapters_proc_dir =
-			create_proc_entry(ADAPTERS_PROC_DIR, S_IFDIR, proc_net);
-
-	if (!adapters_proc_dir)
-		return false;
-
-	return true;
-}
-
-/****************************************************************************
- * Name:          e100_proc_cleanup
- *
- * Description:   This routine clears the top-level /proc directory, if empty.
- *
- * Arguments:     none
- *
- * Returns:       none
- *
- ***************************************************************************/
-static void
-e100_proc_cleanup(void)
-{
-	struct proc_dir_entry *de;
-
-	if (adapters_proc_dir == NULL) {
-		return;
-	}
-
-	/* check if subdir list is empty before removing adapters_proc_dir */
-	for (de = adapters_proc_dir->subdir; de; de = de->next) {
-		/* ignore . and .. */
-		if (*(de->name) != '.')
-			break;
-	}
-
-	if (de)
-		return;
-
-	remove_proc_entry(ADAPTERS_PROC_DIR, proc_net);
-	adapters_proc_dir = NULL;
-}
-
-#endif /* CONFIG_PROC_FS */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/e100/e100_test.c linux-2.4.21-pre6/drivers/net/e100/e100_test.c
--- linux-2.4.20/drivers/net/e100/e100_test.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/e100/e100_test.c	2003-03-26 23:49:06.000000000 +0000
@@ -29,7 +29,7 @@
 #include "e100_config.h"
 
 extern u16 e100_eeprom_read(struct e100_private *, u16);
-extern int e100_wait_exec_cmplx(struct e100_private *, u32,u8);
+extern int e100_wait_exec_cmplx(struct e100_private *, u32,u8, u8);
 extern void e100_phy_reset(struct e100_private *bdp);
 extern void e100_phy_autoneg(struct e100_private *bdp);
 extern void e100_phy_set_loopback(struct e100_private *bdp);
@@ -95,15 +95,9 @@
 		test_info [E100_EEPROM_TEST_FAIL] = true;
 	}
 
-	/* fully recover only if the device is open*/
-	if (netif_running(dev))  {
-		e100_deisolate_driver(bdp, true, false);
-	} else {
-    		e100_deisolate_driver(bdp, false, false);
-	}
-	/*Let card recover from the test*/
 	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule_timeout(HZ * 2);
+    	e100_deisolate_driver(bdp, false);
 
 	return flags | (test_result ? 0 : ETH_TEST_FL_FAILED);
 }
@@ -132,7 +126,7 @@
 		}
 	}
 
-	e100_hw_reset_recover(bdp,PORT_SOFTWARE_RESET);
+	e100_configure_device(bdp);
 
 	return retval;
 }
@@ -170,13 +164,19 @@
 {
 	u8 rc = 0;
 
+	printk(KERN_DEBUG "%s: PHY loopback test starts\n", dev->name);
+	e100_sw_reset(dev->priv, PORT_SELECTIVE_RESET);
 	if (!e100_diag_one_loopback(dev, PHY_LOOPBACK)) {
 		rc |= PHY_LOOPBACK;
 	}
+	printk(KERN_DEBUG "%s: PHY loopback test ends\n", dev->name);
 
+	printk(KERN_DEBUG "%s: MAC loopback test starts\n", dev->name);
+	e100_sw_reset(dev->priv, PORT_SELECTIVE_RESET);
 	if (!e100_diag_one_loopback(dev, MAC_LOOPBACK)) {
 		rc |= MAC_LOOPBACK;
 	}
+	printk(KERN_DEBUG "%s: MAC loopback test ends\n", dev->name);
 
 	return rc;
 }
@@ -242,6 +242,9 @@
 		 *dynamic_tbd = e100_config_dynamic_tbd(bdp,*dynamic_tbd);
 
 	if (set_loopback) {
+		/* ICH PHY loopback is broken */
+		if (bdp->flags & IS_ICH && loopback_mode == PHY_LOOPBACK)
+			loopback_mode = MAC_LOOPBACK;
 		/* Configure loopback on MAC */
 		e100_config_loopback_mode(bdp,loopback_mode);
 	} else {
@@ -345,12 +348,12 @@
 e100_diag_loopback_cu_ru_exec(struct e100_private *bdp)
 {
 	/*load CU & RU base */ 
-	if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE))
-		printk("e100: SCB_CUC_LOAD_BASE failed\n");
-	if(!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE))
-		printk("e100: SCB_RUC_LOAD_BASE failed!\n");
-	if(!e100_wait_exec_cmplx(bdp, bdp->loopback.dma_handle, SCB_RUC_START))
-		printk("e100: SCB_RUC_START failed!\n");
+	if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE, 0))
+		printk(KERN_ERR "e100: SCB_CUC_LOAD_BASE failed\n");
+	if(!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE, 0))
+		printk(KERN_ERR "e100: SCB_RUC_LOAD_BASE failed!\n");
+	if(!e100_wait_exec_cmplx(bdp, bdp->loopback.dma_handle, SCB_RUC_START, 0))
+		printk(KERN_ERR "e100: SCB_RUC_START failed!\n");
 
 	bdp->next_cu_cmd = START_WAIT;
 	e100_start_cu(bdp, bdp->loopback.tcb);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/e100/e100_vendor.h linux-2.4.21-pre6/drivers/net/e100/e100_vendor.h
--- linux-2.4.20/drivers/net/e100/e100_vendor.h	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/e100/e100_vendor.h	2003-03-26 23:49:20.000000000 +0000
@@ -285,6 +285,13 @@
 	{0x8086, 0x2449, 0x1014, PCI_ANY_ID, 0, 0, E100_PROVE_D},	
 	{0x8086, 0x2449, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_ALL_BOARDS},
 	
+	{0x8086, 0x1050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVE_NET},
+	{0x8086, 0x1051, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVE_NET},
+	{0x8086, 0x1052, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVM_NET},
+	{0x8086, 0x1053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVM_NET},
+	{0x8086, 0x1054, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVE_NET},
+	{0x8086, 0x1055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVM_NET},
+
 	{0x8086, 0x1059, 0x1179, 0x0005, 0, 0, E100_82551QM},
 	{0x8086, 0x1059, 0x1033, 0x8191, 0, 0, E100_82551QM},
 	{0x8086, 0x1059, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_82551QM},
@@ -303,6 +310,7 @@
 	{0x8086, 0x103C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVM_NET},
 	{0x8086, 0x103D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVE_NET},
 	{0x8086, 0x103E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVM_NET},
+	{0x8086, 0x1050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVM_NET},
 	{0x8086, 0x2459, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_82562},
 	{0x8086, 0x245D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_82562},
 	{0,} /* This has to be the last entry*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/e1000/Makefile linux-2.4.21-pre6/drivers/net/e1000/Makefile
--- linux-2.4.20/drivers/net/e1000/Makefile	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/e1000/Makefile	2003-03-26 23:49:55.000000000 +0000
@@ -32,8 +32,7 @@
 
 O_TARGET := e1000.o
 
-obj-y	:= e1000_main.o e1000_hw.o e1000_ethtool.o e1000_param.o \
-	   e1000_proc.o
+obj-y	:= e1000_main.o e1000_hw.o e1000_ethtool.o e1000_param.o
 obj-m	:= $(O_TARGET)
 
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/e1000/e1000.h linux-2.4.21-pre6/drivers/net/e1000/e1000.h
--- linux-2.4.20/drivers/net/e1000/e1000.h	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/e1000/e1000.h	2003-03-26 23:49:29.000000000 +0000
@@ -112,6 +112,7 @@
 #define E1000_DEFAULT_PBA    0x00000030
 
 #define AUTO_ALL_MODES       0
+#define E1000_EEPROM_APME    4
 
 /* only works for sizes that are powers of 2 */
 #define E1000_ROUNDUP(i, size) ((i) = (((i) + (size) - 1) & ~((size) - 1)))
@@ -155,9 +156,6 @@
 struct e1000_adapter {
 	struct timer_list watchdog_timer;
 	struct timer_list phy_info_timer;
-#ifdef CONFIG_PROC_FS
-	struct list_head proc_list_head;
-#endif
 	struct vlan_group *vlgrp;
 	char *id_string;
 	uint32_t bd_number;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/e1000/e1000_ethtool.c linux-2.4.21-pre6/drivers/net/e1000/e1000_ethtool.c
--- linux-2.4.20/drivers/net/e1000/e1000_ethtool.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/e1000/e1000_ethtool.c	2003-03-26 23:49:07.000000000 +0000
@@ -39,6 +39,16 @@
 extern void e1000_down(struct e1000_adapter *adapter);
 extern void e1000_reset(struct e1000_adapter *adapter);
 
+static char e1000_gstrings_stats[][ETH_GSTRING_LEN] = {
+	"rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors",
+	"tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions",
+	"rx_length_errors", "rx_over_errors", "rx_crc_errors",
+	"rx_frame_errors", "rx_fifo_errors", "rx_missed_errors",
+	"tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors",
+	"tx_heartbeat_errors", "tx_window_errors",
+};
+#define E1000_STATS_LEN	sizeof(e1000_gstrings_stats) / ETH_GSTRING_LEN
+
 static void
 e1000_ethtool_gset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd)
 {
@@ -173,6 +183,7 @@
 	strncpy(drvinfo->version, e1000_driver_version, 32);
 	strncpy(drvinfo->fw_version, "N/A", 32);
 	strncpy(drvinfo->bus_info, adapter->pdev->slot_name, 32);
+	drvinfo->n_stats = E1000_STATS_LEN;
 #define E1000_REGS_LEN 32
 	drvinfo->regdump_len  = E1000_REGS_LEN * sizeof(uint32_t);
 	drvinfo->eedump_len  = e1000_eeprom_size(&adapter->hw);
@@ -194,7 +205,7 @@
 	regs_buff[4]  = E1000_READ_REG(hw, RDH);
 	regs_buff[5]  = E1000_READ_REG(hw, RDT);
 	regs_buff[6]  = E1000_READ_REG(hw, RDTR);
-	
+
 	regs_buff[7]  = E1000_READ_REG(hw, TCTL);
 	regs_buff[8]  = E1000_READ_REG(hw, TDLEN);
 	regs_buff[9]  = E1000_READ_REG(hw, TDH);
@@ -209,18 +220,24 @@
                       struct ethtool_eeprom *eeprom, uint16_t *eeprom_buff)
 {
 	struct e1000_hw *hw = &adapter->hw;
-	int i, max_len, first_word, last_word;
-
-	if(eeprom->len == 0)
-		return -EINVAL;
+	int max_len, first_word, last_word;
+	int ret_val = 0;
+	int i;
+
+	if(eeprom->len == 0) {
+		ret_val = -EINVAL;
+		goto geeprom_error;
+	}
 
 	eeprom->magic = hw->vendor_id | (hw->device_id << 16);
 
 	max_len = e1000_eeprom_size(hw);
 
-	if(eeprom->offset > eeprom->offset + eeprom->len)
-		return -EINVAL;
-	
+	if(eeprom->offset > eeprom->offset + eeprom->len) {
+		ret_val = -EINVAL;
+		goto geeprom_error;
+	}
+
 	if((eeprom->offset + eeprom->len) > max_len)
 		eeprom->len = (max_len - eeprom->offset);
 
@@ -230,17 +247,19 @@
 	for(i = 0; i <= (last_word - first_word); i++)
 		e1000_read_eeprom(hw, first_word + i, &eeprom_buff[i]);
 
-	return 0;
+geeprom_error:
+	return ret_val;
 }
 
-static int 
+static int
 e1000_ethtool_seeprom(struct e1000_adapter *adapter,
                       struct ethtool_eeprom *eeprom, void *user_data)
 {
 	struct e1000_hw *hw = &adapter->hw;
-	uint16_t eeprom_buff[256];
-	int i, max_len, first_word, last_word;
+	uint16_t *eeprom_buff;
+	int max_len, first_word, last_word;
 	void *ptr;
+	int i;
 
 	if(eeprom->len == 0)
 		return -EOPNOTSUPP;
@@ -255,6 +274,10 @@
 
 	first_word = eeprom->offset >> 1;
 	last_word = (eeprom->offset + eeprom->len - 1) >> 1;
+	eeprom_buff = kmalloc(max_len, GFP_KERNEL);
+	if(eeprom_buff == NULL)
+		return -ENOMEM;
+
 	ptr = (void *)eeprom_buff;
 
 	if(eeprom->offset & 1) {
@@ -269,8 +292,10 @@
 		e1000_read_eeprom(hw, last_word,
 		                  &eeprom_buff[last_word - first_word]);
 	}
-	if(copy_from_user(ptr, user_data, eeprom->len))
+	if(copy_from_user(ptr, user_data, eeprom->len)) {
+		kfree(eeprom_buff);
 		return -EFAULT;
+	}
 
 	for(i = 0; i <= (last_word - first_word); i++)
 		e1000_write_eeprom(hw, first_word + i, eeprom_buff[i]);
@@ -279,6 +304,8 @@
 	if(first_word <= EEPROM_CHECKSUM_REG)
 		e1000_update_eeprom_checksum(hw);
 
+	kfree(eeprom_buff);
+
 	return 0;
 }
 
@@ -306,12 +333,10 @@
 		/* Fall Through */
 
 	default:
-		wol->supported = WAKE_PHY | WAKE_UCAST | 
-				 WAKE_MCAST | WAKE_BCAST | WAKE_MAGIC;
-		
+		wol->supported = WAKE_UCAST | WAKE_MCAST
+			         | WAKE_BCAST | WAKE_MAGIC;
+
 		wol->wolopts = 0;
-		if(adapter->wol & E1000_WUFC_LNKC)
-			wol->wolopts |= WAKE_PHY;
 		if(adapter->wol & E1000_WUFC_EX)
 			wol->wolopts |= WAKE_UCAST;
 		if(adapter->wol & E1000_WUFC_MC)
@@ -343,13 +368,11 @@
 		/* Fall Through */
 
 	default:
-		if(wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE))
+		if(wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE | WAKE_PHY))
 			return -EOPNOTSUPP;
 
 		adapter->wol = 0;
 
-		if(wol->wolopts & WAKE_PHY)
-			adapter->wol |= E1000_WUFC_LNKC;
 		if(wol->wolopts & WAKE_UCAST)
 			adapter->wol |= E1000_WUFC_EX;
 		if(wol->wolopts & WAKE_MCAST)
@@ -374,7 +397,7 @@
 e1000_led_blink_callback(unsigned long data)
 {
 	struct e1000_adapter *adapter = (struct e1000_adapter *) data;
-	
+
 	if(test_and_change_bit(E1000_LED_ON, &adapter->led_status))
 		e1000_led_off(&adapter->hw);
 	else
@@ -394,13 +417,13 @@
 
 	e1000_setup_led(&adapter->hw);
 	mod_timer(&adapter->blink_timer, jiffies);
-	
+
 	set_current_state(TASK_INTERRUPTIBLE);
 	if(id->data)
 		schedule_timeout(id->data * HZ);
 	else
 		schedule_timeout(MAX_SCHEDULE_TIMEOUT);
-	
+
 	del_timer_sync(&adapter->blink_timer);
 	e1000_led_off(&adapter->hw);
 	clear_bit(E1000_LED_ON, &adapter->led_status);
@@ -442,6 +465,28 @@
 			return -EFAULT;
 		return 0;
 	}
+	case ETHTOOL_GSTRINGS: {
+		struct ethtool_gstrings gstrings = { ETHTOOL_GSTRINGS };
+		char *strings = NULL;
+
+		if(copy_from_user(&gstrings, addr, sizeof(gstrings)))
+			return -EFAULT;
+		switch(gstrings.string_set) {
+		case ETH_SS_STATS:
+			gstrings.len = E1000_STATS_LEN;
+			strings = *e1000_gstrings_stats;
+			break;
+		default:
+			return -EOPNOTSUPP;
+		}
+		if(copy_to_user(addr, &gstrings, sizeof(gstrings)))
+			return -EFAULT;
+		addr += offsetof(struct ethtool_gstrings, data);
+		if(copy_to_user(addr, strings,
+		   gstrings.len * ETH_GSTRING_LEN))
+			return -EFAULT;
+		return 0;
+	}
 	case ETHTOOL_GREGS: {
 		struct ethtool_regs regs = {ETHTOOL_GREGS};
 		uint32_t regs_buff[E1000_REGS_LEN];
@@ -497,26 +542,40 @@
 	}
 	case ETHTOOL_GEEPROM: {
 		struct ethtool_eeprom eeprom = {ETHTOOL_GEEPROM};
-		uint16_t eeprom_buff[256];
+		uint16_t *eeprom_buff;
 		void *ptr;
-		int err;
+		int max_len, err = 0;
 
-		if(copy_from_user(&eeprom, addr, sizeof(eeprom)))
-			return -EFAULT;
+		max_len = e1000_eeprom_size(&adapter->hw);
 
-		if((err = e1000_ethtool_geeprom(adapter, 
-			&eeprom, eeprom_buff)))
-			return err;
+		eeprom_buff = kmalloc(max_len, GFP_KERNEL);
 
-		if(copy_to_user(addr, &eeprom, sizeof(eeprom)))
-			return -EFAULT;
+		if(eeprom_buff == NULL)
+			return -ENOMEM;
+
+		if(copy_from_user(&eeprom, addr, sizeof(eeprom))) {
+			err = -EFAULT;
+			goto err_geeprom_ioctl;
+		}
+
+		if((err = e1000_ethtool_geeprom(adapter, &eeprom,
+						eeprom_buff)))
+			goto err_geeprom_ioctl;
+
+		if(copy_to_user(addr, &eeprom, sizeof(eeprom))) {
+			err = -EFAULT;
+			goto err_geeprom_ioctl;
+		}
 
 		addr += offsetof(struct ethtool_eeprom, data);
 		ptr = ((void *)eeprom_buff) + (eeprom.offset & 1);
 
 		if(copy_to_user(addr, ptr, eeprom.len))
-			return -EFAULT;
-		return 0;
+			err = -EFAULT;
+
+err_geeprom_ioctl:
+		kfree(eeprom_buff);
+		return err;
 	}
 	case ETHTOOL_SEEPROM: {
 		struct ethtool_eeprom eeprom;
@@ -530,6 +589,20 @@
 		addr += offsetof(struct ethtool_eeprom, data);
 		return e1000_ethtool_seeprom(adapter, &eeprom, addr);
 	}
+	case ETHTOOL_GSTATS: {
+		struct {
+			struct ethtool_stats cmd;
+			uint64_t data[E1000_STATS_LEN];
+		} stats = { {ETHTOOL_GSTATS, E1000_STATS_LEN} };
+		int i;
+
+		for(i = 0; i < E1000_STATS_LEN; i++)
+			stats.data[i] =
+				((unsigned long *)&adapter->net_stats)[i];
+		if(copy_to_user(addr, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
 	default:
 		return -EOPNOTSUPP;
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/e1000/e1000_main.c linux-2.4.21-pre6/drivers/net/e1000/e1000_main.c
--- linux-2.4.20/drivers/net/e1000/e1000_main.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/e1000/e1000_main.c	2003-03-26 23:49:34.000000000 +0000
@@ -26,11 +26,21 @@
 
 *******************************************************************************/
 
-#define __E1000_MAIN__
 #include "e1000.h"
 
 /* Change Log
  *
+ * 4.4.19       11/27/02
+ *   o Feature: Added user-settable knob for interrupt throttle rate (ITR).
+ *   o Cleanup: removed large static array allocations.
+ *   o Cleanup: C99 struct initializer format.
+ *   o Bug fix: restore VLAN settings when interface is brought up.
+ *   o Bug fix: return cleanly in probe if error in detecting MAC type.
+ *   o Bug fix: Wake up on magic packet by default only if enabled in eeprom.
+ *   o Bug fix: Validate MAC address in set_mac.
+ *   o Bug fix: Throw away zero-length Tx skbs.
+ *   o Bug fix: Make ethtool EEPROM acceses work on older versions of ethtool.
+ * 
  * 4.4.12       10/15/02
  *   o Clean up: use members of pci_device rather than direct calls to
  *     pci_read_config_word.
@@ -43,27 +53,13 @@
  *   o Now setting netdev->mem_end in e1000_probe.
  *   o Clean up: Moved tx_timeout from interrupt context to process context
  *     using schedule_task.
- *
- * 4.3.15      8/9/02
- *   o Converted from Dual BSD/GPL license to GPL license.
- *   o Clean up: use pci_[clear|set]_mwi rather than direct calls to
- *     pci_write_config_word.
- *   o Bug fix: added read-behind-write calls to post writes before delays.
- *   o Bug fix: removed mdelay busy-waits in interrupt context.
- *   o Clean up: direct clear of descriptor bits rather than using memset.
- *   o Bug fix: added wmb() for ia-64 between descritor writes and advancing
- *     descriptor tail.
- *   o Feature: added locking mechanism for asf functionality.
- *   o Feature: exposed two Tx and one Rx interrupt delay knobs for finer
- *     control over interurpt rate tuning.
- *   o Misc ethtool bug fixes.
- *
- * 4.3.2       7/5/02
+ * 
+ * 4.3.15       8/9/02
  */
- 
+
 char e1000_driver_name[] = "e1000";
 char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
-char e1000_driver_version[] = "4.4.12-k1";
+char e1000_driver_version[] = "4.4.19-k2";
 char e1000_copyright[] = "Copyright (c) 1999-2002 Intel Corporation.";
 
 /* e1000_pci_tbl - PCI Device ID Table
@@ -168,9 +164,9 @@
 static void e1000_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp);
 static void e1000_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid);
 static void e1000_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid);
+static void e1000_restore_vlan(struct e1000_adapter *adapter);
 
 static int e1000_notify_reboot(struct notifier_block *, unsigned long event, void *ptr);
-static int e1000_notify_netdev(struct notifier_block *, unsigned long event, void *ptr);
 static int e1000_suspend(struct pci_dev *pdev, uint32_t state);
 #ifdef CONFIG_PM
 static int e1000_resume(struct pci_dev *pdev);
@@ -182,17 +178,9 @@
 	.priority	= 0
 };
 
-struct notifier_block e1000_notifier_netdev = {
-	.notifier_call	= e1000_notify_netdev,
-	.next		= NULL,
-	.priority	= 0
-};
-
 /* Exported from other modules */
 
 extern void e1000_check_options(struct e1000_adapter *adapter);
-extern void e1000_proc_dev_setup(struct e1000_adapter *adapter);
-extern void e1000_proc_dev_free(struct e1000_adapter *adapter);
 extern int e1000_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr);
 
 static struct pci_driver e1000_driver = {
@@ -228,10 +216,8 @@
 	printk(KERN_INFO "%s\n", e1000_copyright);
 
 	ret = pci_module_init(&e1000_driver);
-	if(ret >= 0) {
+	if(ret >= 0)
 		register_reboot_notifier(&e1000_notifier_reboot);
-		register_netdevice_notifier(&e1000_notifier_netdev);
-	}
 	return ret;
 }
 
@@ -248,7 +234,6 @@
 e1000_exit_module(void)
 {
 	unregister_reboot_notifier(&e1000_notifier_reboot);
-	unregister_netdevice_notifier(&e1000_notifier_netdev);
 	pci_unregister_driver(&e1000_driver);
 }
 
@@ -267,6 +252,7 @@
 	/* hardware has been reset, we need to reload some things */
 
 	e1000_set_multi(netdev);
+	e1000_restore_vlan(adapter);
 
 	e1000_configure_tx(adapter);
 	e1000_setup_rctl(adapter);
@@ -342,6 +328,7 @@
 	int mmio_len;
 	int pci_using_dac;
 	int i;
+	uint16_t eeprom_data;
 
 	if((i = pci_enable_device(pdev)))
 		return i;
@@ -464,7 +451,7 @@
 	adapter->phy_info_timer.function = &e1000_update_phy_info;
 	adapter->phy_info_timer.data = (unsigned long) adapter;
 
-	INIT_TQUEUE(&adapter->tx_timeout_task, 
+	INIT_TQUEUE(&adapter->tx_timeout_task,
 		(void (*)(void *))e1000_tx_timeout_task, netdev);
 
 	register_netdev(netdev);
@@ -478,15 +465,15 @@
 
 	printk(KERN_INFO "%s: %s\n", netdev->name, adapter->id_string);
 	e1000_check_options(adapter);
-	e1000_proc_dev_setup(adapter);
 
 	/* Initial Wake on LAN setting
 	 * If APM wake is enabled in the EEPROM,
 	 * enable the ACPI Magic Packet filter
 	 */
 
+	e1000_read_eeprom(&adapter->hw, EEPROM_INIT_CONTROL2_REG, &eeprom_data);
 	if((adapter->hw.mac_type >= e1000_82544) &&
-	   (E1000_READ_REG(&adapter->hw, WUC) & E1000_WUC_APME))
+	   (eeprom_data & E1000_EEPROM_APME))
 		adapter->wol |= E1000_WUFC_MAG;
 
 	/* reset the hardware with the new settings */
@@ -535,8 +522,6 @@
 
 	e1000_phy_hw_reset(&adapter->hw);
 
-	e1000_proc_dev_free(adapter);
-
 	iounmap(adapter->hw.hw_addr);
 	pci_release_regions(pdev);
 
@@ -567,6 +552,7 @@
 	hw->subsystem_id = pdev->subsystem_device;
 
 	pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id);
+
 	pci_read_config_word(pdev, PCI_COMMAND, &hw->pci_cmd_word);
 
 	adapter->rx_buffer_len = E1000_RXBUFFER_2048;
@@ -611,7 +597,7 @@
 	hw->adaptive_ifs = TRUE;
 
 	/* Copper options */
-	
+
 	if(hw->media_type == e1000_media_type_copper) {
 		hw->mdix = AUTO_ALL_MODES;
 		hw->disable_polarity_correction = FALSE;
@@ -1128,6 +1114,9 @@
 	struct e1000_adapter *adapter = netdev->priv;
 	struct sockaddr *addr = p;
 
+	if(!is_valid_ether_addr(addr->sa_data))
+		return -EADDRNOTAVAIL;
+
 	/* 82542 2.0 needs to be in reset to write receive address registers */
 
 	if(adapter->hw.mac_type == e1000_82542_rev2_0)
@@ -1331,7 +1320,6 @@
 
 	int f;
 	len = skb->len - skb->data_len;
-
 	i = (tx_ring->next_to_use + tx_ring->count - 1) % tx_ring->count;
 	count = 0;
 
@@ -1432,11 +1420,16 @@
 {
 	struct e1000_adapter *adapter = netdev->priv;
 	int tx_flags = 0, count;
-
 	int f;
 
 	count = TXD_USE_COUNT(skb->len - skb->data_len,
 	                      adapter->max_data_per_txd);
+
+	if(count == 0) {
+		dev_kfree_skb_any(skb);
+		return 0;
+	}
+
 	for(f = 0; f < skb_shinfo(skb)->nr_frags; f++)
 		count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size,
 		                       adapter->max_data_per_txd);
@@ -2143,6 +2136,21 @@
 	e1000_write_vfta(&adapter->hw, index, vfta);
 }
 
+static void
+e1000_restore_vlan(struct e1000_adapter *adapter)
+{
+	e1000_vlan_rx_register(adapter->netdev, adapter->vlgrp);
+
+	if(adapter->vlgrp) {
+		uint16_t vid;
+		for(vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) {
+			if(!adapter->vlgrp->vlan_devices[vid])
+				continue;
+			e1000_vlan_rx_add_vid(adapter->netdev, vid);
+		}
+	}
+}
+
 static int
 e1000_notify_reboot(struct notifier_block *nb, unsigned long event, void *p)
 {
@@ -2161,41 +2169,23 @@
 }
 
 static int
-e1000_notify_netdev(struct notifier_block *nb, unsigned long event, void *p)
-{
-	struct e1000_adapter *adapter;
-	struct net_device *netdev = p;
-	if(netdev == NULL)
-		return NOTIFY_DONE;
-
-	switch(event) {
-	case NETDEV_CHANGENAME:
-		if(netdev->open == e1000_open) {
-			adapter = netdev->priv;
-			/* rename the proc nodes the easy way */
-			e1000_proc_dev_free(adapter);
-			memcpy(adapter->ifname, netdev->name, IFNAMSIZ);
-			adapter->ifname[IFNAMSIZ-1] = 0;
-			e1000_proc_dev_setup(adapter);
-		}
-		break;
-	}
-	return NOTIFY_DONE;
-}
-
-static int
 e1000_suspend(struct pci_dev *pdev, uint32_t state)
 {
 	struct net_device *netdev = pci_get_drvdata(pdev);
 	struct e1000_adapter *adapter = netdev->priv;
-	uint32_t ctrl, ctrl_ext, rctl, manc;
+	uint32_t ctrl, ctrl_ext, rctl, manc, status;
+	uint32_t wufc = adapter->wol;
 
 	netif_device_detach(netdev);
 
 	if(netif_running(netdev))
 		e1000_down(adapter);
 
-	if(adapter->wol) {
+	status = E1000_READ_REG(&adapter->hw, STATUS);
+	if(status & E1000_STATUS_LU)
+		wufc &= ~E1000_WUFC_LNKC;
+
+	if(wufc) {
 		e1000_setup_rctl(adapter);
 		e1000_set_multi(netdev);
 
@@ -2225,7 +2215,7 @@
 		}
 
 		E1000_WRITE_REG(&adapter->hw, WUC, E1000_WUC_PME_EN);
-		E1000_WRITE_REG(&adapter->hw, WUFC, adapter->wol);
+		E1000_WRITE_REG(&adapter->hw, WUFC, wufc);
 		pci_enable_wake(pdev, 3, 1);
 		pci_enable_wake(pdev, 4, 1); /* 4 == D3 cold */
 	} else {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/e1000/e1000_osdep.h linux-2.4.21-pre6/drivers/net/e1000/e1000_osdep.h
--- linux-2.4.20/drivers/net/e1000/e1000_osdep.h	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/e1000/e1000_osdep.h	2003-03-26 23:49:20.000000000 +0000
@@ -27,7 +27,7 @@
 *******************************************************************************/
 
 
-/* glue for the OS independant part of e1000 
+/* glue for the OS independant part of e1000
  * includes register access macros
  */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/e1000/e1000_param.c linux-2.4.21-pre6/drivers/net/e1000/e1000_param.c
--- linux-2.4.20/drivers/net/e1000/e1000_param.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/e1000/e1000_param.c	2003-03-26 23:49:07.000000000 +0000
@@ -230,7 +230,6 @@
 	} arg;
 };
 
-
 static int __devinit
 e1000_validate_option(int *value, struct e1000_option *opt)
 {
@@ -273,7 +272,7 @@
 	default:
 		BUG();
 	}
-		
+
 	printk(KERN_INFO "Invalid %s specified (%i) %s\n",
 	       opt->name, *value, opt->err);
 	*value = opt->def;
@@ -298,7 +297,7 @@
 {
 	int bd = adapter->bd_number;
 	if(bd >= E1000_MAX_NIC) {
-		printk(KERN_NOTICE 
+		printk(KERN_NOTICE
 		       "Warning: no configuration for board #%i\n", bd);
 		printk(KERN_NOTICE "Using defaults for all values\n");
 		bd = E1000_MAX_NIC;
@@ -310,11 +309,11 @@
 			.name = "Transmit Descriptors",
 			.err  = "using default of " __MODULE_STRING(DEFAULT_TXD),
 			.def  = DEFAULT_TXD,
-			.arg  = { r: { min: MIN_TXD }}
+			.arg  = { .r = { .min = MIN_TXD }}
 		};
 		struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
 		e1000_mac_type mac_type = adapter->hw.mac_type;
-		opt.arg.r.max = mac_type < e1000_82544 ? 
+		opt.arg.r.max = mac_type < e1000_82544 ?
 			MAX_TXD : MAX_82544_TXD;
 
 		tx_ring->count = TxDescriptors[bd];
@@ -327,7 +326,7 @@
 			.name = "Receive Descriptors",
 			.err  = "using default of " __MODULE_STRING(DEFAULT_RXD),
 			.def  = DEFAULT_RXD,
-			.arg  = { r: { min: MIN_RXD }}
+			.arg  = { .r = { .min = MIN_RXD }}
 		};
 		struct e1000_desc_ring *rx_ring = &adapter->rx_ring;
 		e1000_mac_type mac_type = adapter->hw.mac_type;
@@ -344,13 +343,13 @@
 			.err  = "defaulting to Enabled",
 			.def  = OPTION_ENABLED
 		};
-		
+
 		int rx_csum = XsumRX[bd];
 		e1000_validate_option(&rx_csum, &opt);
 		adapter->rx_csum = rx_csum;
 	}
 	{ /* Flow Control */
-		
+
 		struct e1000_opt_list fc_list[] =
 			{{ e1000_fc_none,    "Flow Control Disabled" },
 			 { e1000_fc_rx_pause,"Flow Control Receive Only" },
@@ -363,7 +362,7 @@
 			.name = "Flow Control",
 			.err  = "reading default settings from EEPROM",
 			.def  = e1000_fc_default,
-			.arg  = { l: { nr: ARRAY_SIZE(fc_list), p: fc_list }}
+			.arg  = { .l = { .nr = ARRAY_SIZE(fc_list), .p = fc_list }}
 		};
 
 		int fc = FlowControl[bd];
@@ -375,7 +374,7 @@
 		struct e1000_option opt = {
 			.type = range_option,
 			.name = "Transmit Interrupt Delay",
-			.arg  = { r: { min: MIN_TXDELAY, max: MAX_TXDELAY }}
+			.arg  = { .r = { .min = MIN_TXDELAY, .max = MAX_TXDELAY }}
 		};
 		opt.def = DEFAULT_TIDV;
 		opt.err = tidv;
@@ -388,7 +387,7 @@
 		struct e1000_option opt = {
 			.type = range_option,
 			.name = "Transmit Absolute Interrupt Delay",
-			.arg  = { r: { min: MIN_TXABSDELAY, max: MAX_TXABSDELAY }}
+			.arg  = { .r = { .min = MIN_TXABSDELAY, .max = MAX_TXABSDELAY }}
 		};
 		opt.def = DEFAULT_TADV;
 		opt.err = tadv;
@@ -401,7 +400,7 @@
 		struct e1000_option opt = {
 			.type = range_option,
 			.name = "Receive Interrupt Delay",
-			.arg  = { r: { min: MIN_RXDELAY, max: MAX_RXDELAY }}
+			.arg  = { .r = { .min = MIN_RXDELAY, .max = MAX_RXDELAY }}
 		};
 		opt.def = DEFAULT_RDTR;
 		opt.err = rdtr;
@@ -414,7 +413,7 @@
 		struct e1000_option opt = {
 			.type = range_option,
 			.name = "Receive Absolute Interrupt Delay",
-			.arg  = { r: { min: MIN_RXABSDELAY, max: MAX_RXABSDELAY }}
+			.arg  = { .r = { .min = MIN_RXABSDELAY, .max = MAX_RXABSDELAY }}
 		};
 		opt.def = DEFAULT_RADV;
 		opt.err = radv;
@@ -478,15 +477,16 @@
 
 	{ /* Speed */
 		struct e1000_opt_list speed_list[] = {{          0, "" },
-		                                      {   SPEED_10, "" },
-		                                      {  SPEED_100, "" },
-		                                      { SPEED_1000, "" }};
+						      {   SPEED_10, "" },
+						      {  SPEED_100, "" },
+						      { SPEED_1000, "" }};
+
 		struct e1000_option opt = {
 			.type = list_option,
 			.name = "Speed",
 			.err  = "parameter ignored",
 			.def  = 0,
-			.arg  = { l: { nr: ARRAY_SIZE(speed_list), p: speed_list }}
+			.arg  = { .l = { .nr = ARRAY_SIZE(speed_list), .p = speed_list }}
 		};
 
 		speed = Speed[bd];
@@ -494,14 +494,15 @@
 	}
 	{ /* Duplex */
 		struct e1000_opt_list dplx_list[] = {{           0, "" },
-		                                     { HALF_DUPLEX, "" },
-		                                     { FULL_DUPLEX, "" }};
+						     { HALF_DUPLEX, "" },
+						     { FULL_DUPLEX, "" }};
+
 		struct e1000_option opt = {
 			.type = list_option,
 			.name = "Duplex",
 			.err  = "parameter ignored",
 			.def  = 0,
-			.arg  = { l: { nr: ARRAY_SIZE(dplx_list), p: dplx_list }}
+			.arg  = { .l = { .nr = ARRAY_SIZE(dplx_list), .p = dplx_list }}
 		};
 
 		dplx = Duplex[bd];
@@ -553,7 +554,7 @@
 			.name = "AutoNeg",
 			.err  = "parameter ignored",
 			.def  = AUTONEG_ADV_DEFAULT,
-			.arg  = { l: { nr: ARRAY_SIZE(an_list), p: an_list }}
+			.arg  = { .l = { .nr = ARRAY_SIZE(an_list), .p = an_list }}
 		};
 
 		int an = AutoNeg[bd];
@@ -572,7 +573,7 @@
 		printk(KERN_INFO "Half Duplex specified without Speed\n");
 		printk(KERN_INFO "Using Autonegotiation at Half Duplex only\n");
 		adapter->hw.autoneg = 1;
-		adapter->hw.autoneg_advertised = ADVERTISE_10_HALF | 
+		adapter->hw.autoneg_advertised = ADVERTISE_10_HALF |
 		                                 ADVERTISE_100_HALF;
 		break;
 	case FULL_DUPLEX:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/e1000/e1000_proc.c linux-2.4.21-pre6/drivers/net/e1000/e1000_proc.c
--- linux-2.4.20/drivers/net/e1000/e1000_proc.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/e1000/e1000_proc.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,699 +0,0 @@
-/*******************************************************************************
-
-  
-  Copyright(c) 1999 - 2002 Intel Corporation. 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., 59 
-  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-  
-  The full GNU General Public License is included in this distribution in the
-  file called LICENSE.
-  
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-/*
- * Proc fs support.
- *
- * Read-only files created by driver (if CONFIG_PROC_FS):
- *
- * /proc/net/PRO_LAN_Adapters/<ethx>.info
- * /proc/net/PRO_LAN_Adapters/<ethx>/<attribute>
- *
- * where <ethx>      is the system device name, i.e eth0.
- *       <attribute> is the driver attribute name.
- *
- * There is one file for each driver attribute, where the contents
- * of the file is the attribute value.  The ethx.info file contains
- * a list of all driver attributes in one file.
- *
- */
-
-#include "e1000.h"
-
-#ifdef CONFIG_PROC_FS
-
-#include <linux/proc_fs.h>
-
-#define ADAPTERS_PROC_DIR           "PRO_LAN_Adapters"
-#define TAG_MAX_LENGTH              32
-#define LINE_MAX_LENGTH             80
-#define FIELD_MAX_LENGTH            LINE_MAX_LENGTH - TAG_MAX_LENGTH - 3
-
-extern char e1000_driver_name[];
-extern char e1000_driver_version[];
-
-/*
- * The list of driver proc attributes is stored in a proc_list link
- * list.  The list is build with proc_list_setup and is used to
- * build the proc fs nodes.  The private data for each node is the
- * corresponding link in the link list.
- */
-
-struct proc_list {
-	struct list_head list;                  /* link list */
-	char tag[TAG_MAX_LENGTH + 1];           /* attribute name */
-	void *data;                             /* attribute data */
-	size_t len;				/* sizeof data */
-	char *(*func)(void *, size_t, char *);  /* format data func */
-};
-
-static int
-e1000_proc_read(char *page, char **start, off_t off, int count, int *eof)
-{
-	int len = strlen(page);
-
-	page[len++] = '\n';
-
-	if(len <= off + count)
-		*eof = 1;
-	*start = page + off;
-	len -= off;
-	if(len > count)
-		len = count;
-	if(len < 0)
-		len = 0;
-
-	return len;
-}
-
-static int
-e1000_proc_info_read(char *page, char **start, off_t off,
-                     int count, int *eof, void *data)
-{
-	struct list_head *proc_list_head = data, *curr;
-	struct proc_list *elem;
-	char *p = page;
-	char buf[FIELD_MAX_LENGTH + 1];
-
-	list_for_each(curr, proc_list_head) {
-		elem = list_entry(curr, struct proc_list, list);
-
-		if (p - page + LINE_MAX_LENGTH >= PAGE_SIZE)
-			break;
-
-		if(!strlen(elem->tag))
-			p += sprintf(p, "\n");
-		else
-			p += sprintf(p, "%-*.*s %.*s\n", 
-				TAG_MAX_LENGTH, TAG_MAX_LENGTH,
-				elem->tag, FIELD_MAX_LENGTH,
-				elem->func(elem->data, elem->len, buf));
-	}
-
-	*p = '\0';
-
-	return e1000_proc_read(page, start, off, count, eof);
-}
-
-static int
-e1000_proc_single_read(char *page, char **start, off_t off,
-                       int count, int *eof, void *data)
-{
-	struct proc_list *elem = data;
-
-	sprintf(page, "%.*s", FIELD_MAX_LENGTH, elem->func(elem->data, 
-	        elem->len, page));
-
-	return e1000_proc_read(page, start, off, count, eof);
-}
-
-static void
-e1000_proc_dirs_free(char *name, struct list_head *proc_list_head)
-{
-	struct proc_dir_entry *intel_proc_dir, *proc_dir;
-	char info_name[strlen(name) + strlen(".info")];
-
-	for(intel_proc_dir = proc_net->subdir; intel_proc_dir;
-		intel_proc_dir = intel_proc_dir->next) {
-		if((intel_proc_dir->namelen == strlen(ADAPTERS_PROC_DIR)) &&
-		   !memcmp(intel_proc_dir->name, ADAPTERS_PROC_DIR, strlen(ADAPTERS_PROC_DIR)))
-			break;
-	}
-
-	if(!intel_proc_dir)
-		return;
-
-	for(proc_dir = intel_proc_dir->subdir; proc_dir;
-		proc_dir = proc_dir->next) {
-		if ((proc_dir->namelen == strlen(name)) &&
-		    !memcmp(proc_dir->name, name, strlen(name)))
-			break;
-	}
-
-	if(proc_dir) {
-		struct list_head *curr;
-		struct proc_list *elem;
-
-		list_for_each(curr, proc_list_head) {
-			elem = list_entry(curr, struct proc_list, list);
-			remove_proc_entry(elem->tag, proc_dir);
-		}
-
-		strcpy(info_name, name);
-		strcat(info_name, ".info");
-
-		remove_proc_entry(info_name, intel_proc_dir);
-		remove_proc_entry(name, intel_proc_dir);
-	}
-
-	/* If the intel dir is empty, remove it */
-
-	for(proc_dir = intel_proc_dir->subdir; proc_dir;
-		proc_dir = proc_dir->next) {
-
-		/* ignore . and .. */
-
-		if(*(proc_dir->name) == '.')
-			continue;
-		break;
-	}
-
-	if(!proc_dir)
-		remove_proc_entry(ADAPTERS_PROC_DIR, proc_net);
-}
-
-
-static int
-e1000_proc_singles_create(struct proc_dir_entry *parent,
-                          struct list_head *proc_list_head)
-{
-	struct list_head *curr;
-	struct proc_list *elem;
-
-	list_for_each(curr, proc_list_head) {
-		struct proc_dir_entry *proc_entry;
-
-		elem = list_entry(curr, struct proc_list, list);
-
-		if(!strlen(elem->tag))
-			continue;
-
-		if(!(proc_entry =
-			create_proc_entry(elem->tag, S_IFREG, parent)))
-			return 0;
-
-		proc_entry->read_proc = e1000_proc_single_read;
-		proc_entry->data = elem;
-		SET_MODULE_OWNER(proc_entry);
-	}
-
-	return 1;
-}
-
-static void
-e1000_proc_dirs_create(void *data, char *name, 
-                       struct list_head *proc_list_head)
-{
-	struct proc_dir_entry *intel_proc_dir, *proc_dir, *info_entry;
-	char info_name[strlen(name) + strlen(".info")];
-
-	for(intel_proc_dir = proc_net->subdir; intel_proc_dir;
-		intel_proc_dir = intel_proc_dir->next) {
-		if((intel_proc_dir->namelen == strlen(ADAPTERS_PROC_DIR)) &&
-		   !memcmp(intel_proc_dir->name, ADAPTERS_PROC_DIR, strlen(ADAPTERS_PROC_DIR)))
-			break;
-	}
-
-	if(!intel_proc_dir)
-		if(!(intel_proc_dir =
-			create_proc_entry(ADAPTERS_PROC_DIR,
-				S_IFDIR, proc_net)))
-			return;
-
-	if(!(proc_dir =
-		create_proc_entry(name, S_IFDIR, intel_proc_dir)))
-		return;
-	SET_MODULE_OWNER(proc_dir);
-
-	if(!e1000_proc_singles_create(proc_dir, proc_list_head))
-		return;
-
-	strcpy(info_name, name);
-	strcat(info_name, ".info");
-
-	if(!(info_entry =
-		create_proc_entry(info_name, S_IFREG, intel_proc_dir)))
-		return;
-	SET_MODULE_OWNER(info_entry);
-
-	info_entry->read_proc = e1000_proc_info_read;
-	info_entry->data = proc_list_head;
-}
-
-static void
-e1000_proc_list_add(struct list_head *proc_list_head, char *tag,
-                    void *data, size_t len, 
-		    char *(*func)(void *, size_t, char *))
-{
-	struct proc_list *new = (struct proc_list *)
-		kmalloc(sizeof(struct proc_list), GFP_KERNEL);
-
-	if(!new)
-		return;
-
-	strncpy(new->tag, tag, TAG_MAX_LENGTH);
-	new->data = data;
-	new->len  = len;
-	new->func = func;
-
-	list_add_tail(&new->list, proc_list_head);
-}
-
-static void
-e1000_proc_list_free(struct list_head *proc_list_head)
-{
-	struct proc_list *elem;
-
-	while(!list_empty(proc_list_head)) {
-		elem = list_entry(proc_list_head->next, struct proc_list, list);
-		list_del(&elem->list);
-		kfree(elem);
-	}
-}
-
-/*
- * General purpose formating functions
- */
-
-static char *
-e1000_proc_str(void *data, size_t len, char *buf)
-{
-	sprintf(buf, "%s", (char *)data);
-	return buf;
-}
-
-static char *
-e1000_proc_hex(void *data, size_t len, char *buf)
-{
-	switch(len) {
-	case sizeof(uint8_t):
-		sprintf(buf, "0x%02x", *(uint8_t *)data);
-		break;
-	case sizeof(uint16_t):
-		sprintf(buf, "0x%04x", *(uint16_t *)data);
-		break;
-	case sizeof(uint32_t):
-		sprintf(buf, "0x%08x", *(uint32_t *)data);
-		break;
-	case sizeof(uint64_t):
-		sprintf(buf, "0x%08Lx", (unsigned long long)*(uint64_t *)data);
-		break;
-	}
-	return buf;
-}
-
-static char *
-e1000_proc_unsigned(void *data, size_t len, char *buf)
-{
-	switch(len) {
-	case sizeof(uint8_t):
-		sprintf(buf, "%u", *(uint8_t *)data);
-		break;
-	case sizeof(uint16_t):
-		sprintf(buf, "%u", *(uint16_t *)data);
-		break;
-	case sizeof(uint32_t):
-		sprintf(buf, "%u", *(uint32_t *)data);
-		break;
-	case sizeof(uint64_t):
-		sprintf(buf, "%Lu", (unsigned long long)*(uint64_t *)data);
-		break;
-	}
-	return buf;
-}
-
-/*
- * Specific formating functions
- */
-
-static char *
-e1000_proc_part_number(void *data, size_t len, char *buf)
-{
-	sprintf(buf, "%06x-%03x", *(uint32_t *)data >> 8,
-	        *(uint32_t *)data & 0x000000FF);
-	return buf;
-}
-
-static char *
-e1000_proc_slot(void *data, size_t len, char *buf)
-{
-	struct e1000_adapter *adapter = data;
-	sprintf(buf, "%u", PCI_SLOT(adapter->pdev->devfn));
-	return buf;
-}
-
-static char *
-e1000_proc_bus_type(void *data, size_t len, char *buf)
-{
-	e1000_bus_type bus_type = *(e1000_bus_type *)data;
-	sprintf(buf,
-		bus_type == e1000_bus_type_pci  ? "PCI"   :
-		bus_type == e1000_bus_type_pcix ? "PCI-X" :
-		"UNKNOWN");
-	return buf;
-}
-
-static char *
-e1000_proc_bus_speed(void *data, size_t len, char *buf)
-{
-	e1000_bus_speed bus_speed = *(e1000_bus_speed *)data;
-	sprintf(buf,
-		bus_speed == e1000_bus_speed_33  ? "33MHz"  :
-		bus_speed == e1000_bus_speed_66  ? "66MHz"  :
-		bus_speed == e1000_bus_speed_100 ? "100MHz" :
-		bus_speed == e1000_bus_speed_133 ? "133MHz" :
-		"UNKNOWN");
-	return buf;
-}
-
-static char *
-e1000_proc_bus_width(void *data, size_t len, char *buf)
-{
-	e1000_bus_width bus_width = *(e1000_bus_width *)data;
-	sprintf(buf,
-		bus_width == e1000_bus_width_32 ? "32-bit"   :
-		bus_width == e1000_bus_width_64 ? "64-bit" :
-		"UNKNOWN");
-	return buf;
-}
-
-static char *
-e1000_proc_hwaddr(void *data, size_t len, char *buf)
-{
-	unsigned char *hwaddr = data;
-	sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X",
-		hwaddr[0], hwaddr[1], hwaddr[2],
-		hwaddr[3], hwaddr[4], hwaddr[5]);
-	return buf;
-}
-
-static char *
-e1000_proc_link(void *data, size_t len, char *buf)
-{
-	struct e1000_adapter *adapter = data;
-	sprintf(buf, netif_running(adapter->netdev) ?
-		netif_carrier_ok(adapter->netdev) ?
-		"up" : "down" : "N/A");
-	return buf;
-}
-
-static char *
-e1000_proc_link_speed(void *data, size_t len, char *buf)
-{
-	uint16_t link_speed = *(uint16_t *)data;
-	sprintf(buf, link_speed ? "%u" : "N/A", link_speed);
-	return buf;
-}
-
-static char *
-e1000_proc_link_duplex(void *data, size_t len, char *buf)
-{
-	uint16_t link_duplex = *(uint16_t *)data;
-	sprintf(buf,
-		link_duplex == FULL_DUPLEX ? "Full" :
-		link_duplex == HALF_DUPLEX ? "Half" :
-		"N/A");
-	return buf;
-}
-
-static char *
-e1000_proc_state(void *data, size_t len, char *buf)
-{
-	struct e1000_adapter *adapter = data;
-	sprintf(buf, adapter->netdev->flags & IFF_UP ? "up" : "down");
-	return buf;
-}
-
-static char *
-e1000_proc_media_type(void *data, size_t len, char *buf)
-{
-	struct e1000_adapter *adapter = data;
-	sprintf(buf,
-		adapter->hw.media_type == e1000_media_type_copper ?
-		"Copper" : "Fiber");
-	return buf;
-}
-
-static char *
-e1000_proc_cable_length(void *data, size_t len, char *buf)
-{
-	struct e1000_adapter *adapter = data;
-	e1000_cable_length cable_length = adapter->phy_info.cable_length;
-	sprintf(buf, "%s%s",
-		cable_length == e1000_cable_length_50      ? "0-50"    :
-		cable_length == e1000_cable_length_50_80   ? "50-80"   :
-		cable_length == e1000_cable_length_80_110  ? "80-110"  :
-		cable_length == e1000_cable_length_110_140 ? "110-140" :
-		cable_length == e1000_cable_length_140     ? "> 140"   :
-		"Unknown",
-		cable_length != e1000_cable_length_undefined ?
-		" Meters (+/- 20 Meters)" : "");
-	return buf;
-}
-
-static char *
-e1000_proc_extended(void *data, size_t len, char *buf)
-{
-	struct e1000_adapter *adapter = data;
-	e1000_10bt_ext_dist_enable dist_enable =
-		adapter->phy_info.extended_10bt_distance;
-	sprintf(buf,
-		dist_enable == e1000_10bt_ext_dist_enable_normal ? "Disabled" :
-		dist_enable == e1000_10bt_ext_dist_enable_lower  ? "Enabled"  :
-		"Unknown");
-	return buf;
-}
-
-static char *
-e1000_proc_cable_polarity(void *data, size_t len, char *buf)
-{
-	struct e1000_adapter *adapter = data;
-	e1000_rev_polarity polarity = adapter->phy_info.cable_polarity;
-	sprintf(buf,
-		polarity == e1000_rev_polarity_normal   ? "Normal"   :
-		polarity == e1000_rev_polarity_reversed ? "Reversed" :
-		"Unknown");
-	return buf;
-}
-
-static char *
-e1000_proc_polarity_correction(void *data, size_t len, char *buf)
-{
-	struct e1000_adapter *adapter = data;
-	e1000_polarity_reversal correction =
-		adapter->phy_info.polarity_correction;
-	sprintf(buf,
-		correction == e1000_polarity_reversal_enabled  ? "Disabled" :
-		correction == e1000_polarity_reversal_disabled ? "Enabled"  :
-		"Unknown");
-	return buf;
-}
-
-static char *
-e1000_proc_mdi_x_enabled(void *data, size_t len, char *buf)
-{
-	struct e1000_adapter *adapter = data;
-	e1000_auto_x_mode mdix_mode = adapter->phy_info.mdix_mode;
-	sprintf(buf, 
-		mdix_mode == e1000_auto_x_mode_manual_mdi  ? "MDI"   : 
-		mdix_mode == e1000_auto_x_mode_manual_mdix ? "MDI-X" :
-		"Unknown");
-	return buf;
-}
-
-static char *
-e1000_proc_rx_status(void *data, size_t len, char *buf)
-{
-	e1000_1000t_rx_status rx_status = *(e1000_1000t_rx_status *)data;
-	sprintf(buf,
-		rx_status == e1000_1000t_rx_status_not_ok ? "NOT_OK" :
-		rx_status == e1000_1000t_rx_status_ok     ? "OK"     :
-		"Unknown");
-	return buf;
-}
-
-/*
- * e1000_proc_list_setup - build link list of proc praramters
- * @adapter: board private structure
- *
- * Order matters - ethx.info entries are ordered in the order links 
- * are added to list.
- */
-
-#define LIST_ADD_F(T,D,F) \
-	e1000_proc_list_add(proc_list_head, (T), (D), sizeof(*(D)), (F))
-#define LIST_ADD_BLANK() LIST_ADD_F("", NULL, NULL)
-#define LIST_ADD_S(T,D) LIST_ADD_F((T), (D), e1000_proc_str)
-#define LIST_ADD_H(T,D) LIST_ADD_F((T), (D), e1000_proc_hex)
-#define LIST_ADD_U(T,D) LIST_ADD_F((T), (D), e1000_proc_unsigned)
-
-static void
-e1000_proc_list_setup(struct e1000_adapter *adapter)
-{
-	struct e1000_hw *hw = &adapter->hw;
-	struct list_head *proc_list_head = &adapter->proc_list_head;
-
-	INIT_LIST_HEAD(proc_list_head);
-
-	LIST_ADD_S("Description", adapter->id_string);
-	LIST_ADD_F("Part_Number", &adapter->part_num, e1000_proc_part_number);
-	LIST_ADD_S("Driver_Name", e1000_driver_name);
-	LIST_ADD_S("Driver_Version", e1000_driver_version);
-	LIST_ADD_H("PCI_Vendor", &hw->vendor_id);
-	LIST_ADD_H("PCI_Device_ID", &hw->device_id);
-	LIST_ADD_H("PCI_Subsystem_Vendor", &hw->subsystem_vendor_id);
-	LIST_ADD_H("PCI_Subsystem_ID", &hw->subsystem_id);
-	LIST_ADD_H("PCI_Revision_ID", &hw->revision_id);
-	LIST_ADD_U("PCI_Bus", &adapter->pdev->bus->number);
-	LIST_ADD_F("PCI_Slot", adapter, e1000_proc_slot);
-
-	if(adapter->hw.mac_type >= e1000_82543) {
-		LIST_ADD_F("PCI_Bus_Type",
-		           &hw->bus_type, e1000_proc_bus_type);
-		LIST_ADD_F("PCI_Bus_Speed",
-		           &hw->bus_speed, e1000_proc_bus_speed);
-		LIST_ADD_F("PCI_Bus_Width",
-		           &hw->bus_width, e1000_proc_bus_width);
-	}
-
-	LIST_ADD_U("IRQ", &adapter->pdev->irq);
-	LIST_ADD_S("System_Device_Name", adapter->ifname);
-	LIST_ADD_F("Current_HWaddr",
-	            adapter->netdev->dev_addr, e1000_proc_hwaddr);
-	LIST_ADD_F("Permanent_HWaddr",
-	            adapter->hw.perm_mac_addr, e1000_proc_hwaddr);
-
-	LIST_ADD_BLANK();
-
-	LIST_ADD_F("Link", adapter, e1000_proc_link);
-	LIST_ADD_F("Speed", &adapter->link_speed, e1000_proc_link_speed);
-	LIST_ADD_F("Duplex", &adapter->link_duplex, e1000_proc_link_duplex);
-	LIST_ADD_F("State", adapter, e1000_proc_state);
-
-	LIST_ADD_BLANK();
-
-	/* Standard net device stats */
-	LIST_ADD_U("Rx_Packets", &adapter->net_stats.rx_packets);
-	LIST_ADD_U("Tx_Packets", &adapter->net_stats.tx_packets);
-	LIST_ADD_U("Rx_Bytes", &adapter->net_stats.rx_bytes);
-	LIST_ADD_U("Tx_Bytes", &adapter->net_stats.tx_bytes);
-	LIST_ADD_U("Rx_Errors", &adapter->net_stats.rx_errors);
-	LIST_ADD_U("Tx_Errors", &adapter->net_stats.tx_errors);
-	LIST_ADD_U("Rx_Dropped", &adapter->net_stats.rx_dropped);
-	LIST_ADD_U("Tx_Dropped", &adapter->net_stats.tx_dropped);
-
-	LIST_ADD_U("Multicast", &adapter->net_stats.multicast);
-	LIST_ADD_U("Collisions", &adapter->net_stats.collisions);
-
-	LIST_ADD_U("Rx_Length_Errors", &adapter->net_stats.rx_length_errors);
-	LIST_ADD_U("Rx_Over_Errors", &adapter->net_stats.rx_over_errors);
-	LIST_ADD_U("Rx_CRC_Errors", &adapter->net_stats.rx_crc_errors);
-	LIST_ADD_U("Rx_Frame_Errors", &adapter->net_stats.rx_frame_errors);
-	LIST_ADD_U("Rx_FIFO_Errors", &adapter->net_stats.rx_fifo_errors);
-	LIST_ADD_U("Rx_Missed_Errors", &adapter->net_stats.rx_missed_errors);
-
-	LIST_ADD_U("Tx_Aborted_Errors", &adapter->net_stats.tx_aborted_errors);
-	LIST_ADD_U("Tx_Carrier_Errors", &adapter->net_stats.tx_carrier_errors);
-	LIST_ADD_U("Tx_FIFO_Errors", &adapter->net_stats.tx_fifo_errors);
-	LIST_ADD_U("Tx_Heartbeat_Errors", 
-	           &adapter->net_stats.tx_heartbeat_errors);
-	LIST_ADD_U("Tx_Window_Errors", &adapter->net_stats.tx_window_errors);
-
-	/* 8254x-specific stats */
-	LIST_ADD_U("Tx_Abort_Late_Coll", &adapter->stats.latecol);
-	LIST_ADD_U("Tx_Deferred_Ok", &adapter->stats.dc);
-	LIST_ADD_U("Tx_Single_Coll_Ok", &adapter->stats.scc);
-	LIST_ADD_U("Tx_Multi_Coll_Ok", &adapter->stats.mcc);
-	LIST_ADD_U("Rx_Long_Length_Errors", &adapter->stats.roc);
-	LIST_ADD_U("Rx_Short_Length_Errors", &adapter->stats.ruc);
-
-	/* The 82542 does not have an alignment error count register */
-	if(adapter->hw.mac_type >= e1000_82543)
-		LIST_ADD_U("Rx_Align_Errors", &adapter->stats.algnerrc);
-
-	LIST_ADD_U("Rx_Flow_Control_XON", &adapter->stats.xonrxc);
-	LIST_ADD_U("Rx_Flow_Control_XOFF", &adapter->stats.xoffrxc);
-	LIST_ADD_U("Tx_Flow_Control_XON", &adapter->stats.xontxc);
-	LIST_ADD_U("Tx_Flow_Control_XOFF", &adapter->stats.xofftxc);
-	LIST_ADD_U("Rx_CSum_Offload_Good", &adapter->hw_csum_good);
-	LIST_ADD_U("Rx_CSum_Offload_Errors", &adapter->hw_csum_err);
-
-	LIST_ADD_BLANK();
-
-	/* Cable diags */
-	LIST_ADD_F("PHY_Media_Type", adapter, e1000_proc_media_type);
-	if(adapter->hw.media_type == e1000_media_type_copper) {
-		LIST_ADD_F("PHY_Cable_Length",
-		           adapter, e1000_proc_cable_length);
-		LIST_ADD_F("PHY_Extended_10Base_T_Distance",
-		           adapter, e1000_proc_extended);
-		LIST_ADD_F("PHY_Cable_Polarity",
-		           adapter, e1000_proc_cable_polarity);
-		LIST_ADD_F("PHY_Disable_Polarity_Correction",
-		           adapter, e1000_proc_polarity_correction);
-		LIST_ADD_U("PHY_Idle_Errors", 
-		           &adapter->phy_stats.idle_errors);
-		LIST_ADD_U("PHY_Receive_Errors",
-		           &adapter->phy_stats.receive_errors);
-		LIST_ADD_F("PHY_MDI_X_Enabled",
-		           adapter, e1000_proc_mdi_x_enabled);
-		LIST_ADD_F("PHY_Local_Receiver_Status",
-		           &adapter->phy_info.local_rx, 
-			   e1000_proc_rx_status);
-		LIST_ADD_F("PHY_Remote_Receiver_Status",
-		           &adapter->phy_info.remote_rx, 
-			   e1000_proc_rx_status);
-	}
-
-}
-
-/*
- * e1000_proc_dev_setup - create proc fs nodes and link list
- * @adapter: board private structure
- */
-
-void
-e1000_proc_dev_setup(struct e1000_adapter *adapter)
-{
-	e1000_proc_list_setup(adapter);
-
-	e1000_proc_dirs_create(adapter, 
-	                       adapter->ifname,
-	                       &adapter->proc_list_head);
-}
-
-/*
- * e1000_proc_dev_free - free proc fs nodes and link list
- * @adapter: board private structure
- */
-
-void
-e1000_proc_dev_free(struct e1000_adapter *adapter)
-{
-	e1000_proc_dirs_free(adapter->ifname, &adapter->proc_list_head);
-
-	e1000_proc_list_free(&adapter->proc_list_head);
-}
-
-#else /* CONFIG_PROC_FS */
-
-void e1000_proc_dev_setup(struct e1000_adapter *adapter) {}
-void e1000_proc_dev_free(struct e1000_adapter *adapter) {}
-
-#endif /* CONFIG_PROC_FS */
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/e2100.c linux-2.4.21-pre6/drivers/net/e2100.c
--- linux-2.4.20/drivers/net/e2100.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/e2100.c	2003-03-26 23:49:54.000000000 +0000
@@ -72,12 +72,12 @@
 #define E21_SAPROM		0x10	/* Offset to station address data. */
 #define E21_IO_EXTENT	 0x20
 
-static inline void mem_on(short port, volatile char *mem_base,
+static inline void mem_on(short port, unsigned long mem_base,
 						  unsigned char start_page )
 {
 	/* This is a little weird: set the shared memory window by doing a
 	   read.  The low address bits specify the starting page. */
-	readb(mem_base+start_page);
+	isa_readb(mem_base+start_page);
 	inb(port + E21_MEM_ENABLE);
 	outb(E21_MEM_ON, port + E21_MEM_ENABLE + E21_MEM_ON);
 }
@@ -300,15 +300,15 @@
 {
 
 	short ioaddr = dev->base_addr;
-	char *shared_mem = (char *)dev->mem_start;
+	unsigned long shared_mem = dev->mem_start;
 
 	mem_on(ioaddr, shared_mem, ring_page);
 
 #ifdef notdef
 	/* Officially this is what we are doing, but the readl() is faster */
-	memcpy_fromio(hdr, shared_mem, sizeof(struct e8390_pkt_hdr));
+	isa_memcpy_fromio(hdr, shared_mem, sizeof(struct e8390_pkt_hdr));
 #else
-	((unsigned int*)hdr)[0] = readl(shared_mem);
+	((unsigned int*)hdr)[0] = isa_readl(shared_mem);
 #endif
 
 	/* Turn off memory access: we would need to reprogram the window anyway. */
@@ -323,12 +323,11 @@
 e21_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
 {
 	short ioaddr = dev->base_addr;
-	char *shared_mem = (char *)dev->mem_start;
 
-	mem_on(ioaddr, shared_mem, (ring_offset>>8));
+	mem_on(ioaddr, dev->mem_start, (ring_offset>>8));
 
 	/* Packet is always in one chunk -- we can copy + cksum. */
-	eth_io_copy_and_sum(skb, dev->mem_start + (ring_offset & 0xff), count, 0);
+	isa_eth_io_copy_and_sum(skb, dev->mem_start + (ring_offset & 0xff), count, 0);
 
 	mem_off(ioaddr);
 }
@@ -338,14 +337,14 @@
 				 int start_page)
 {
 	short ioaddr = dev->base_addr;
-	volatile char *shared_mem = (char *)dev->mem_start;
+	unsigned long shared_mem = dev->mem_start;
 
 	/* Set the shared memory window start by doing a read, with the low address
 	   bits specifying the starting page. */
-	readb(shared_mem + start_page);
+	isa_readb(shared_mem + start_page);
 	mem_on(ioaddr, shared_mem, start_page);
 
-	memcpy_toio(shared_mem, buf, count);
+	isa_memcpy_toio(shared_mem, buf, count);
 	mem_off(ioaddr);
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/eepro.c linux-2.4.21-pre6/drivers/net/eepro.c
--- linux-2.4.20/drivers/net/eepro.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/eepro.c	2003-03-26 23:49:50.000000000 +0000
@@ -1128,17 +1128,24 @@
 	struct eepro_local *lp = (struct eepro_local *)dev->priv;
 	unsigned long flags;
 	int ioaddr = dev->base_addr;
+	short length = skb->len;
 
 	if (net_debug > 5)
 		printk(KERN_DEBUG  "%s: entering eepro_send_packet routine.\n", dev->name);
 
+	if(length < ETH_ZLEN)
+	{
+		skb = skb_padto(skb, ETH_ZLEN);
+		if(skb == NULL)
+			return 0;
+		length = ETH_ZLEN;
+	}
 	netif_stop_queue (dev);
 
 	eepro_dis_int(ioaddr);
 	spin_lock_irqsave(&lp->lock, flags);
 
 	{
-		short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
 		unsigned char *buf = skb->data;
 
 		if (hardware_send_packet(dev, buf, length))
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/eepro100.c linux-2.4.21-pre6/drivers/net/eepro100.c
--- linux-2.4.20/drivers/net/eepro100.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/eepro100.c	2003-03-26 23:49:50.000000000 +0000
@@ -17,7 +17,7 @@
 	1998 Apr - 2000 Feb  Andrey V. Savochkin <saw@saw.sw.com.sg>
 		Serious fixes for multicast filter list setting, TX timeout routine;
 		RX ring refilling logic;  other stuff
-	2000 Feb  Jeff Garzik <jgarzik@mandrakesoft.com>
+	2000 Feb  Jeff Garzik <jgarzik@pobox.com>
 		Convert to new PCI driver interface
 	2000 Mar 24  Dragan Stancevic <visitor@valinux.com>
 		Disabled FC and ER, to avoid lockups when when we get FCP interrupts.
@@ -41,8 +41,8 @@
 static int txdmacount = 128;
 static int rxdmacount /* = 0 */;
 
-#if defined(__ia64__) || defined(__alpha__) || defined(__sparc__) || defined(__mips__) || \
-	defined(__arm__)
+#if defined(__ia64__) || defined(__alpha__) || defined(__sparc__) || \
+	defined(__mips__) || defined(__arm__) || defined(__hppa__)
   /* align rx buffers to 2 bytes so that IP header is aligned */
 # define rx_align(skb)		skb_reserve((skb), 2)
 # define RxFD_ALIGNMENT		__attribute__ ((aligned (2), packed))
@@ -120,6 +120,11 @@
 #include <linux/ethtool.h>
 #include <linux/mii.h>
 
+/* enable PIO instead of MMIO, if CONFIG_EEPRO100_PIO is selected */
+#ifdef CONFIG_EEPRO100_PIO
+#define USE_IO 1
+#endif
+
 static int debug = -1;
 #define DEBUG_DEFAULT		(NETIF_MSG_DRV		| \
 				 NETIF_MSG_HW		| \
@@ -837,6 +842,7 @@
 	sp->lstats = (struct speedo_stats *)(sp->tx_ring + TX_RING_SIZE);
 	sp->lstats_dma = TX_RING_ELEM_DMA(sp, TX_RING_SIZE);
 	init_timer(&sp->timer); /* used in ioctl() */
+	spin_lock_init(&sp->lock);
 
 	sp->mii_if.full_duplex = option >= 0 && (option & 0x10) ? 1 : 0;
 	if (card_idx >= 0) {
@@ -988,7 +994,6 @@
 	sp->dirty_tx = 0;
 	sp->last_cmd = 0;
 	sp->tx_full = 0;
-	spin_lock_init(&sp->lock);
 	sp->in_interrupt = 0;
 
 	/* .. we can safely take handler calls during init. */
@@ -2387,6 +2392,7 @@
 	{ PCI_VENDOR_ID_INTEL, 0x103C, PCI_ANY_ID, PCI_ANY_ID, },
 	{ PCI_VENDOR_ID_INTEL, 0x103D, PCI_ANY_ID, PCI_ANY_ID, },
 	{ PCI_VENDOR_ID_INTEL, 0x103E, PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_INTEL, 0x1059, PCI_ANY_ID, PCI_ANY_ID, },
 	{ PCI_VENDOR_ID_INTEL, 0x1227, PCI_ANY_ID, PCI_ANY_ID, },
 	{ PCI_VENDOR_ID_INTEL, 0x1228, PCI_ANY_ID, PCI_ANY_ID, },
 	{ PCI_VENDOR_ID_INTEL, 0x2449, PCI_ANY_ID, PCI_ANY_ID, },
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/eexpress.c linux-2.4.21-pre6/drivers/net/eexpress.c
--- linux-2.4.20/drivers/net/eexpress.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/eexpress.c	2003-03-26 23:48:57.000000000 +0000
@@ -640,6 +640,7 @@
 static int eexp_xmit(struct sk_buff *buf, struct net_device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
+	short length = buf->len;
 #ifdef CONFIG_SMP
 	unsigned long flags;
 #endif
@@ -648,6 +649,14 @@
 	printk(KERN_DEBUG "%s: eexp_xmit()\n", dev->name);
 #endif
 
+	if(buf->len < ETH_ZLEN)
+	{
+		buf = skb_padto(buf, ETH_ZLEN);
+		if(buf == NULL)
+			return 0;
+		length = buf->len;
+	}
+
 	disable_irq(dev->irq);
 
 	/*
@@ -660,8 +669,6 @@
 #endif
   
 	{
-		unsigned short length = (ETH_ZLEN < buf->len) ? buf->len :
-			ETH_ZLEN;
 		unsigned short *data = (unsigned short *)buf->data;
 
 		lp->stats.tx_bytes += length;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/epic100.c linux-2.4.21-pre6/drivers/net/epic100.c
--- linux-2.4.20/drivers/net/epic100.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/epic100.c	2003-03-26 23:49:35.000000000 +0000
@@ -975,6 +975,13 @@
 	int entry, free_count;
 	u32 ctrl_word;
 	long flags;
+	
+	if(skb->len < ETH_ZLEN)
+	{
+		skb = skb_padto(skb, ETH_ZLEN);
+		if(skb == NULL)
+			return 0;
+	}
 
 	/* Caution: the write order is important here, set the field with the
 	   "ownership" bit last. */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/eth16i.c linux-2.4.21-pre6/drivers/net/eth16i.c
--- linux-2.4.20/drivers/net/eth16i.c	2001-09-30 19:26:06.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/eth16i.c	2003-03-26 23:49:20.000000000 +0000
@@ -1056,10 +1056,17 @@
 	struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
 	int ioaddr = dev->base_addr;
 	int status = 0;
-	ushort length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+	ushort length = skb->len;
 	unsigned char *buf = skb->data;
 	unsigned long flags;
 
+	if(length < ETH_ZLEN)
+	{
+		skb = skb_padto(skb, ETH_ZLEN);
+		if(skb == NULL)
+			return 0;
+		length = ETH_ZLEN;
+	}
 
 	netif_stop_queue(dev);
 		
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/ether00.c linux-2.4.21-pre6/drivers/net/ether00.c
--- linux-2.4.20/drivers/net/ether00.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/ether00.c	2003-03-26 23:49:55.000000000 +0000
@@ -0,0 +1,1001 @@
+/*
+ *  drivers/net/ether00.c
+ *
+ *  Copyright (C) 2001 Altera Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  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
+ */
+
+/* includes */
+
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/sched.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+#include <linux/module.h>
+#include <linux/tqueue.h>
+#include <linux/mtd/mtd.h>
+#include <asm/arch/excalibur.h>
+#include <asm/arch/hardware.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/sizes.h>
+
+#include <asm/arch/ether00.h>
+#include <asm/arch/tdkphy.h>
+
+
+MODULE_AUTHOR("Clive Davies");
+MODULE_DESCRIPTION("Altera Ether00 IP core driver");
+MODULE_LICENSE("GPL");
+
+static long base=0x60000000;
+static int irq=0x1;
+static int phy_irq=0x2;
+MODULE_PARM(base,"l");
+MODULE_PARM(irq,"i");
+MODULE_PARM(phy_irq,"i");
+
+#define TX_TIMEOUT  (400*HZ/1000)
+#define PKT_BUF_SZ 1540 /* Size of each rx buffer */
+
+
+#undef  DEBUG
+#define DEBUG(x)
+
+#define __dma_va(x) (unsigned int)((unsigned int)priv->dma_data+(((unsigned int)(x))&(EXC_SPSRAM_BLOCK0_SIZE-1)))
+#define __dma_pa(x) (unsigned int)(EXC_SPSRAM_BLOCK0_BASE+(((unsigned int)(x))-(unsigned int)priv->dma_data))
+
+#define ETHER00_BASE	0
+#define	ETHER00_TYPE
+#define ETHER00_NAME "ether00"
+#define MAC_REG_SIZE 0x400 /* size of MAC register area */
+
+
+
+/* typedefs */
+
+/* The definition of the driver control structure */
+
+#define RX_NUM_BUFF     10
+#define RX_NUM_FDESC    10
+#define TX_NUM_FDESC    10
+
+struct tx_fda_ent{
+	FDA_DESC  fd;
+	BUF_DESC  bd;
+	BUF_DESC  pad;
+};
+struct rx_fda_ent{
+	FDA_DESC  fd;
+	BUF_DESC  bd;
+	BUF_DESC  pad;
+};
+struct rx_blist_ent{
+	FDA_DESC  fd;
+	BUF_DESC  bd;
+	BUF_DESC  pad;
+};
+struct net_priv
+{
+	struct net_device_stats stats;
+	struct sk_buff* skb;
+	void* dma_data;
+	struct rx_blist_ent*  rx_blist_vp;
+	struct rx_fda_ent* rx_fda_ptr;
+	struct tx_fda_ent* tx_fdalist_vp;
+	struct tq_struct  tq_memupdate;
+        unsigned char   rx_disabled;
+	unsigned char   memupdate_scheduled;
+	unsigned char   queue_stopped;
+	spinlock_t dma_lock;
+        unsigned int tx_head;
+        unsigned int tx_tail;
+};
+
+static const char vendor_id[2]={0x07,0xed};
+
+#ifdef ETHER00_DEBUG
+
+/* Dump (most) registers for debugging puposes */
+
+static void dump_regs(struct net_device *dev){
+	struct net_priv* priv=dev->priv;
+	unsigned int* i;
+
+	printk("\n RX free descriptor area:\n");
+
+	for(i=(unsigned int*)priv->rx_fda_ptr;
+	    i<((unsigned int*)(priv->rx_fda_ptr+RX_NUM_FDESC));){
+		printk("%#8x %#8x %#8x %#8x\n",*i,*(i+1),*(i+2),*(i+3));
+		i+=4;
+	}
+
+	printk("\n RX buffer list:\n");
+
+	for(i=(unsigned int*)priv->rx_blist_vp;
+	    i<((unsigned int*)(priv->rx_blist_vp+RX_NUM_BUFF));){
+		printk("%#8x %#8x %#8x %#8x\n",*i,*(i+1),*(i+2),*(i+3));
+		i+=4;
+	}
+
+	printk("\n TX frame descriptor list:\n");
+
+	for(i=(unsigned int*)priv->tx_fdalist_vp;
+	    i<((unsigned int*)(priv->tx_fdalist_vp+TX_NUM_FDESC));){
+		printk("%#8x %#8x %#8x %#8x\n",*i,*(i+1),*(i+2),*(i+3));
+		i+=4;
+	}
+
+	printk("\ndma ctl=%#x\n",readw(ETHER_DMA_CTL(dev->base_addr)));
+	printk("txfrmptr=%#x\n",readw(ETHER_TXFRMPTR(dev->base_addr)));
+	printk("txthrsh=%#x\n",readw(ETHER_TXTHRSH(dev->base_addr)));
+	printk("txpollctr=%#x\n",readw(ETHER_TXPOLLCTR(dev->base_addr)));
+	printk("blfrmptr=%#x\n",readw(ETHER_BLFRMPTR(dev->base_addr)));
+	printk("rxfragsize=%#x\n",readw(ETHER_RXFRAGSIZE(dev->base_addr)));
+	printk("tx_int_en=%#x\n",readw(ETHER_INT_EN(dev->base_addr)));
+	printk("fda_bas=%#x\n",readw(ETHER_FDA_BAS(dev->base_addr)));
+	printk("fda_lim=%#x\n",readw(ETHER_FDA_LIM(dev->base_addr)));
+	printk("int_src=%#x\n",readw(ETHER_INT_SRC(dev->base_addr)));
+	printk("pausecnt=%#x\n",readw(ETHER_PAUSECNT(dev->base_addr)));
+	printk("rempaucnt=%#x\n",readw(ETHER_REMPAUCNT(dev->base_addr)));
+	printk("txconfrmstat=%#x\n",readw(ETHER_TXCONFRMSTAT(dev->base_addr)));
+	printk("mac_ctl=%#x\n",readw(ETHER_MAC_CTL(dev->base_addr)));
+	printk("arc_ctl=%#x\n",readw(ETHER_ARC_CTL(dev->base_addr)));
+	printk("tx_ctl=%#x\n",readw(ETHER_TX_CTL(dev->base_addr)));
+}
+#endif /* ETHER00_DEBUG */
+
+
+static int ether00_write_phy(struct net_device *dev, short address, short value)
+{
+	volatile int count = 1024;
+	writew(value,ETHER_MD_DATA(dev->base_addr));
+	writew( ETHER_MD_CA_BUSY_MSK |
+		ETHER_MD_CA_WR_MSK |
+		(address & ETHER_MD_CA_ADDR_MSK),
+		ETHER_MD_CA(dev->base_addr));
+
+	/* Wait for the command to complete */
+	while((readw(ETHER_MD_CA(dev->base_addr)) & ETHER_MD_CA_BUSY_MSK)&&count){
+		count--;
+	}
+	if (!count){
+		printk("Write to phy failed, addr=%#x, data=%#x\n",address, value);
+		return -EIO;
+	}
+	return 0;
+}
+
+static int ether00_read_phy(struct net_device *dev, short address)
+{
+	volatile int count = 1024;
+	writew( ETHER_MD_CA_BUSY_MSK |
+		(address & ETHER_MD_CA_ADDR_MSK),
+		ETHER_MD_CA(dev->base_addr));
+
+	/* Wait for the command to complete */
+	while((readw(ETHER_MD_CA(dev->base_addr)) & ETHER_MD_CA_BUSY_MSK)&&count){
+		count--;
+	}
+	if (!count){
+		printk(KERN_WARNING "Read from phy timed out\n");
+		return -EIO;
+	}
+	return readw(ETHER_MD_DATA(dev->base_addr));
+}
+
+static void ether00_phy_int(int irq_num, void* dev_id, struct pt_regs* regs)
+{
+	struct net_device* dev=dev_id;
+	int irq_status;
+
+	irq_status=ether00_read_phy(dev, PHY_IRQ_CONTROL);
+
+	if(irq_status & PHY_IRQ_CONTROL_ANEG_COMP_INT_MSK){
+		/*
+		 * Autonegotiation complete on epxa10db. The mac doesn't
+		 * twig if we're in full duplex so we need to check the
+		 * phy diagnostic register and configure the mac accordingly
+		 */
+	  if(ether00_read_phy(dev, PHY_DIAGNOSTIC)&PHY_DIAGNOSTIC_DPLX_MSK){
+		  int tmp;
+		  tmp=readl(ETHER_MAC_CTL(dev->base_addr));
+		  writel(tmp|ETHER_MAC_CTL_FULLDUP_MSK,
+			 ETHER_MAC_CTL(dev->base_addr));
+		}
+                else
+		  {
+		    int tmp;
+		    tmp=readl(ETHER_MAC_CTL(dev->base_addr));
+		    writel(tmp&(~ETHER_MAC_CTL_FULLDUP_MSK),
+			   ETHER_MAC_CTL(dev->base_addr));
+
+		  }
+	}
+
+	if(irq_status&PHY_IRQ_CONTROL_LS_CHG_INT_MSK){
+
+		if(ether00_read_phy(dev, PHY_STATUS)& PHY_STATUS_LINK_MSK){
+			/* Link is up */
+			netif_carrier_on(dev);
+		}else{
+			netif_carrier_off(dev);
+		}
+	}
+
+}
+
+static void setup_blist_entry(struct sk_buff* skb,struct rx_blist_ent* blist_ent_ptr){
+	/* Make the buffer consistent with the cache as the mac is going to write
+	 * directly into it*/
+	blist_ent_ptr->fd.FDSystem=(unsigned int)skb;
+	blist_ent_ptr->bd.BuffData=(char*)__pa(skb->data);
+	consistent_sync(skb->data,PKT_BUF_SZ,PCI_DMA_FROMDEVICE);
+        /* align IP on 16 Byte (DMA_CTL set to skip 2 bytes) */
+	skb_reserve(skb,2);
+	blist_ent_ptr->bd.BuffLength=PKT_BUF_SZ-2;
+	blist_ent_ptr->fd.FDLength=1;
+	blist_ent_ptr->fd.FDCtl=FDCTL_COWNSFD_MSK;
+	blist_ent_ptr->bd.BDCtl=BDCTL_COWNSBD_MSK;
+}
+
+
+static int ether00_mem_init(struct net_device* dev)
+{
+	struct net_priv* priv=dev->priv;
+	struct tx_fda_ent *tx_fd_ptr,*tx_end_ptr;
+	struct rx_blist_ent* blist_ent_ptr;
+	int i;
+
+	/*
+	 * Grab a block of on chip SRAM to contain the control stuctures for
+	 * the ethernet MAC. This uncached becuase it needs to be accesses by both
+	 * bus masters (cpu + mac). However, it shouldn't matter too much in terms
+	 * of speed as its on chip memory
+	 */
+	priv->dma_data=ioremap_nocache(EXC_SPSRAM_BLOCK0_BASE,EXC_SPSRAM_BLOCK0_SIZE );
+	if (!priv->dma_data)
+		return -ENOMEM;
+
+	priv->rx_fda_ptr=(struct rx_fda_ent*)priv->dma_data;
+	/*
+	 * Now share it out amongst the Frame descriptors and the buffer list
+	 */
+	priv->rx_blist_vp=(struct rx_blist_ent*)((unsigned int)priv->dma_data+RX_NUM_FDESC*sizeof(struct rx_fda_ent));
+
+	/*
+	 *Initalise the FDA list
+	 */
+	/* set ownership to the controller */
+	memset(priv->rx_fda_ptr,0x80,RX_NUM_FDESC*sizeof(struct rx_fda_ent));
+
+	/*
+	 *Initialise the buffer list
+	 */
+	blist_ent_ptr=priv->rx_blist_vp;
+	i=0;
+	while(blist_ent_ptr<(priv->rx_blist_vp+RX_NUM_BUFF)){
+		struct sk_buff *skb;
+		blist_ent_ptr->fd.FDLength=1;
+		skb=dev_alloc_skb(PKT_BUF_SZ);
+		if(skb){
+			setup_blist_entry(skb,blist_ent_ptr);
+			blist_ent_ptr->fd.FDNext=(FDA_DESC*)__dma_pa(blist_ent_ptr+1);
+			blist_ent_ptr->bd.BDStat=i++;
+			blist_ent_ptr++;
+		}
+		else
+		{
+			printk("Failed to initalise buffer list\n");
+		}
+
+	}
+	blist_ent_ptr--;
+	blist_ent_ptr->fd.FDNext=(FDA_DESC*)__dma_pa(priv->rx_blist_vp);
+
+	priv->tx_fdalist_vp=(struct tx_fda_ent*)(priv->rx_blist_vp+RX_NUM_BUFF);
+
+	/* Initialise the buffers to be a circular list. The mac will then go poll
+	 * the list until it finds a frame ready to transmit */
+	tx_end_ptr=priv->tx_fdalist_vp+TX_NUM_FDESC;
+	for(tx_fd_ptr=priv->tx_fdalist_vp;tx_fd_ptr<tx_end_ptr;tx_fd_ptr++){
+		tx_fd_ptr->fd.FDNext=(FDA_DESC*)__dma_pa((tx_fd_ptr+1));
+		tx_fd_ptr->fd.FDCtl=1;
+		tx_fd_ptr->fd.FDStat=0;
+		tx_fd_ptr->fd.FDSystem=0;
+		tx_fd_ptr->fd.FDLength=1;
+
+	}
+	/* Change the last FDNext pointer to make a circular list */
+	tx_fd_ptr--;
+	tx_fd_ptr->fd.FDNext=(FDA_DESC*)__dma_pa(priv->tx_fdalist_vp);
+
+	/* Point the device at the chain of Rx and Tx Buffers */
+	writel((unsigned int)__dma_pa(priv->rx_fda_ptr),ETHER_FDA_BAS(dev->base_addr));
+	writel((RX_NUM_FDESC-1)*sizeof(struct rx_fda_ent),ETHER_FDA_LIM(dev->base_addr));
+	writel((unsigned int)__dma_pa(priv->rx_blist_vp),ETHER_BLFRMPTR(dev->base_addr));
+
+        priv->tx_tail = priv->tx_head = (unsigned int) priv->tx_fdalist_vp;
+	writel((unsigned int) __dma_pa(priv->tx_head), ETHER_TXFRMPTR(dev->base_addr));
+
+	return 0;
+}
+
+
+void ether00_mem_update(void* dev_id)
+{
+	struct net_device* dev=dev_id;
+	struct net_priv* priv=dev->priv;
+	struct rx_blist_ent* blist_ent_ptr;
+	unsigned long flags;
+        int enable_rx = 0;
+
+	priv->tq_memupdate.sync=0;
+	priv->memupdate_scheduled=0;
+
+	/* Fill in any missing buffers from the received queue */
+	blist_ent_ptr=priv->rx_blist_vp;
+	while(blist_ent_ptr<(priv->rx_blist_vp+RX_NUM_BUFF)){
+		spin_lock_irqsave(&priv->dma_lock,flags);
+		/* fd.FDSystem of 0 indicates we failed to allocate the buffer in the ISR */
+		if(!blist_ent_ptr->fd.FDSystem){
+			struct sk_buff *skb;
+			skb=dev_alloc_skb(PKT_BUF_SZ);
+			blist_ent_ptr->fd.FDSystem=(unsigned int)skb;
+			if(skb){
+				setup_blist_entry(skb,blist_ent_ptr);
+                                enable_rx = 1;
+			}
+			else
+			{
+                                /*
+                                 * reschedule the clean up, since we
+                                 * didn't patch up all the buffers
+                                 */
+
+	                         if(!priv->memupdate_scheduled){
+				   schedule_task(&priv->tq_memupdate);
+				   priv->memupdate_scheduled=1;
+				 }
+		                 spin_unlock_irqrestore(&priv->dma_lock,flags);
+				 break;
+			}
+		}
+		spin_unlock_irqrestore(&priv->dma_lock,flags);
+		blist_ent_ptr++;
+	}
+
+	if(enable_rx){
+	  if (!priv->rx_disabled){
+	        priv->rx_disabled = 0;
+		writel(ETHER_RX_CTL_RXEN_MSK,ETHER_RX_CTL(dev->base_addr));
+	  }
+	}
+}
+
+
+static void ether00_int( int irq_num, void* dev_id, struct pt_regs* regs)
+{
+	struct net_device* dev=dev_id;
+	struct net_priv* priv=dev->priv;
+
+	unsigned int   interruptValue;
+
+        int enable_tx = 0;
+	struct tx_fda_ent *fda_ptr;
+	struct sk_buff* skb;
+
+	interruptValue=readl(ETHER_INT_SRC(dev->base_addr));
+
+	if(!(readl(ETHER_INT_SRC(dev->base_addr)) & ETHER_INT_SRC_IRQ_MSK))
+	{
+		return;		/* Interrupt wasn't caused by us!! */
+	}
+
+	if(readl(ETHER_INT_SRC(dev->base_addr))&
+	   (ETHER_INT_SRC_INTMACRX_MSK |
+	    ETHER_INT_SRC_FDAEX_MSK |
+	    ETHER_INT_SRC_BLEX_MSK)) {
+		struct rx_blist_ent* blist_ent_ptr;
+		struct rx_fda_ent* fda_ent_ptr;
+		struct sk_buff* skb;
+
+		fda_ent_ptr=priv->rx_fda_ptr;
+		spin_lock(&priv->dma_lock);
+		while(fda_ent_ptr<(priv->rx_fda_ptr+RX_NUM_FDESC)){
+			int result;
+
+			if(!(fda_ent_ptr->fd.FDCtl&FDCTL_COWNSFD_MSK))
+			{
+				/* This frame is ready for processing */
+				/*find the corresponding buffer in the bufferlist */
+				blist_ent_ptr=priv->rx_blist_vp+fda_ent_ptr->bd.BDStat;
+				skb=(struct sk_buff*)blist_ent_ptr->fd.FDSystem;
+
+				/* Pass this skb up the stack */
+				skb->dev=dev;
+				skb_put(skb,fda_ent_ptr->fd.FDLength);
+				skb->protocol=eth_type_trans(skb,dev);
+				skb->ip_summed=CHECKSUM_UNNECESSARY;
+				result=netif_rx(skb);
+				/* Update statistics */
+				priv->stats.rx_packets++;
+				priv->stats.rx_bytes+=fda_ent_ptr->fd.FDLength;
+
+				/* Free the FDA entry */
+				fda_ent_ptr->bd.BDStat=0xff;
+				fda_ent_ptr->fd.FDCtl=FDCTL_COWNSFD_MSK;
+
+				/* Allocate a new skb and point the bd entry to it */
+				blist_ent_ptr->fd.FDSystem=0;
+				skb=dev_alloc_skb(PKT_BUF_SZ);
+				if(skb){
+					setup_blist_entry(skb,blist_ent_ptr);
+
+				}
+				else if(!priv->memupdate_scheduled){
+					int tmp;
+					/* There are no buffers at the moment, so schedule */
+					/* the background task to sort this out */
+					schedule_task(&priv->tq_memupdate);
+					priv->memupdate_scheduled=1;
+					printk(KERN_DEBUG "%s:No buffers",dev->name);
+					/* If this interrupt was due to a lack of buffers then
+					 * we'd better stop the receiver too */
+					if(interruptValue&ETHER_INT_SRC_BLEX_MSK){
+						priv->rx_disabled=1;
+						tmp=readl(ETHER_INT_SRC(dev->base_addr));
+						writel(tmp&~ETHER_RX_CTL_RXEN_MSK,ETHER_RX_CTL(dev->base_addr));
+						printk(KERN_DEBUG "%s:Halting rx",dev->name);
+					}
+
+				}
+
+			}
+			fda_ent_ptr++;
+		}
+		spin_unlock(&priv->dma_lock);
+
+		/* Clear the  interrupts */
+		writel(ETHER_INT_SRC_INTMACRX_MSK | ETHER_INT_SRC_FDAEX_MSK
+		       | ETHER_INT_SRC_BLEX_MSK,ETHER_INT_SRC(dev->base_addr));
+
+	}
+
+	if(readl(ETHER_INT_SRC(dev->base_addr))&ETHER_INT_SRC_INTMACTX_MSK){
+
+	  /* Transmit interrupt */
+
+	  fda_ptr=(struct tx_fda_ent*) priv->tx_tail;
+
+          /* free up all completed frames */
+
+	  while(!(FDCTL_COWNSFD_MSK&fda_ptr->fd.FDCtl) && fda_ptr->fd.FDSystem){
+	    priv->stats.tx_packets++;
+	    priv->stats.tx_bytes+=fda_ptr->bd.BuffLength;
+	    skb=(struct sk_buff*)fda_ptr->fd.FDSystem;
+	    dev_kfree_skb_irq(skb);
+	    fda_ptr->fd.FDSystem=0;
+	    fda_ptr->fd.FDStat=0;
+	    fda_ptr->fd.FDCtl=0;
+	    fda_ptr = (struct tx_fda_ent *)__dma_va(fda_ptr->fd.FDNext);
+	    enable_tx = 1;
+	  }
+	  priv->tx_tail = (unsigned int) fda_ptr;
+
+	  if(priv->queue_stopped && enable_tx){
+	    priv->queue_stopped=0;
+	    netif_wake_queue(dev);
+	  }
+
+	  /* Clear the interrupt */
+	  writel(ETHER_INT_SRC_INTMACTX_MSK,ETHER_INT_SRC(dev->base_addr));
+	}
+
+	if (readl(ETHER_INT_SRC(dev->base_addr)) & (ETHER_INT_SRC_SWINT_MSK|
+						    ETHER_INT_SRC_INTEARNOT_MSK|
+						    ETHER_INT_SRC_INTLINK_MSK|
+						    ETHER_INT_SRC_INTEXBD_MSK|
+						    ETHER_INT_SRC_INTTXCTLCMP_MSK))
+	{
+		/*
+		 *	Not using any of these so they shouldn't happen
+		 *
+		 *	In the cased of INTEXBD - if you allocate more
+		 *      than 28 decsriptors you may need to think about this
+		 */
+		printk("Not using this interrupt\n");
+	}
+
+	if (readl(ETHER_INT_SRC(dev->base_addr)) &
+	    (ETHER_INT_SRC_INTSBUS_MSK |
+	     ETHER_INT_SRC_INTNRABT_MSK
+	     |ETHER_INT_SRC_DMPARERR_MSK))
+	{
+		/*
+		 * Hardware errors, we can either ignore them and hope they go away
+		 *or reset the device, I'll try the first for now to see if they happen
+		 */
+		printk("Hardware error\n");
+	}
+}
+
+static void ether00_setup_ethernet_address(struct net_device* dev)
+{
+	int tmp;
+
+	dev->addr_len=6;
+	writew(0,ETHER_ARC_ADR(dev->base_addr));
+	writel((dev->dev_addr[0]<<24) |
+		(dev->dev_addr[1]<<16) |
+		(dev->dev_addr[2]<<8) |
+		dev->dev_addr[3],
+		ETHER_ARC_DATA(dev->base_addr));
+
+	writew(4,ETHER_ARC_ADR(dev->base_addr));
+	tmp=readl(ETHER_ARC_DATA(dev->base_addr));
+	tmp&=0xffff;
+	tmp|=(dev->dev_addr[4]<<24) | (dev->dev_addr[5]<<16);
+	writel(tmp, ETHER_ARC_DATA(dev->base_addr));
+	/* Enable this entry in the ARC */
+
+	writel(1,ETHER_ARC_ENA(dev->base_addr));
+
+	return;
+}
+
+
+static void ether00_reset(struct net_device *dev)
+{
+	/* reset the controller */
+	writew(ETHER_MAC_CTL_RESET_MSK,ETHER_MAC_CTL(dev->base_addr));
+
+	/*
+	 * Make sure we're not going to send anything
+	 */
+
+	writew(ETHER_TX_CTL_TXHALT_MSK,ETHER_TX_CTL(dev->base_addr));
+
+	/*
+	 * Make sure we're not going to receive anything
+	 */
+	writew(ETHER_RX_CTL_RXHALT_MSK,ETHER_RX_CTL(dev->base_addr));
+
+	/*
+	 * Disable Interrupts for now, and set the burst size to 8 bytes
+	 */
+
+	writel(ETHER_DMA_CTL_INTMASK_MSK |
+	       ((8 << ETHER_DMA_CTL_DMBURST_OFST) & ETHER_DMA_CTL_DMBURST_MSK)
+	       |(2<<ETHER_DMA_CTL_RXALIGN_OFST),
+	       ETHER_DMA_CTL(dev->base_addr));
+
+
+	/*
+	 * Set TxThrsh - start transmitting a packet after 1514
+	 * bytes or when a packet is complete, whichever comes first
+	 */
+	 writew(1514,ETHER_TXTHRSH(dev->base_addr));
+
+	/*
+	 * Set TxPollCtr.  Each cycle is
+	 * 61.44 microseconds with a 33 MHz bus
+	 */
+	 writew(1,ETHER_TXPOLLCTR(dev->base_addr));
+
+	/*
+	 * Set Rx_Ctl - Turn off reception and let RxData turn it
+	 * on later
+	 */
+	 writew(ETHER_RX_CTL_RXHALT_MSK,ETHER_RX_CTL(dev->base_addr));
+
+}
+
+
+static void ether00_set_multicast(struct net_device* dev)
+{
+	int count=dev->mc_count;
+
+	/* Set promiscuous mode if it's asked for. */
+
+	if (dev->flags&IFF_PROMISC){
+
+		writew( ETHER_ARC_CTL_COMPEN_MSK |
+			ETHER_ARC_CTL_BROADACC_MSK |
+			ETHER_ARC_CTL_GROUPACC_MSK |
+			ETHER_ARC_CTL_STATIONACC_MSK,
+			ETHER_ARC_CTL(dev->base_addr));
+		return;
+	}
+
+	/*
+	 * Get all multicast packets if required, or if there are too
+	 * many addresses to fit in hardware
+	 */
+	if (dev->flags & IFF_ALLMULTI){
+		writew( ETHER_ARC_CTL_COMPEN_MSK |
+			ETHER_ARC_CTL_GROUPACC_MSK |
+			ETHER_ARC_CTL_BROADACC_MSK,
+			ETHER_ARC_CTL(dev->base_addr));
+		return;
+	}
+	if (dev->mc_count > (ETHER_ARC_SIZE - 1)){
+
+		printk(KERN_WARNING "Too many multicast addresses for hardware to filter - receiving all multicast packets\n");
+		writew( ETHER_ARC_CTL_COMPEN_MSK |
+			ETHER_ARC_CTL_GROUPACC_MSK |
+			ETHER_ARC_CTL_BROADACC_MSK,
+			ETHER_ARC_CTL(dev->base_addr));
+		return;
+	}
+
+	if(dev->mc_count){
+		struct dev_mc_list *mc_list_ent=dev->mc_list;
+		unsigned int temp,i;
+		DEBUG(printk("mc_count=%d mc_list=%#x\n",dev-> mc_count, dev->mc_list));
+		DEBUG(printk("mc addr=%02#x%02x%02x%02x%02x%02x\n",
+			     mc_list_ent->dmi_addr[5],
+			     mc_list_ent->dmi_addr[4],
+			     mc_list_ent->dmi_addr[3],
+			     mc_list_ent->dmi_addr[2],
+			     mc_list_ent->dmi_addr[1],
+			     mc_list_ent->dmi_addr[0]);)
+
+		/*
+		 * The first 6 bytes are the MAC address, so
+		 * don't change them!
+		 */
+		writew(4,ETHER_ARC_ADR(dev->base_addr));
+		temp=readl(ETHER_ARC_DATA(dev->base_addr));
+		temp&=0xffff0000;
+
+		/* Disable the current multicast stuff */
+		writel(1,ETHER_ARC_ENA(dev->base_addr));
+
+		for(;;){
+			temp|=mc_list_ent->dmi_addr[1] |
+				mc_list_ent->dmi_addr[0]<<8;
+			writel(temp,ETHER_ARC_DATA(dev->base_addr));
+
+			i=readl(ETHER_ARC_ADR(dev->base_addr));
+			writew(i+4,ETHER_ARC_ADR(dev->base_addr));
+
+			temp=mc_list_ent->dmi_addr[5]|
+				mc_list_ent->dmi_addr[4]<<8 |
+				mc_list_ent->dmi_addr[3]<<16 |
+				mc_list_ent->dmi_addr[2]<<24;
+			writel(temp,ETHER_ARC_DATA(dev->base_addr));
+
+			count--;
+			if(!mc_list_ent->next || !count){
+				break;
+			}
+			DEBUG(printk("mc_list_next=%#x\n",mc_list_ent->next);)
+			mc_list_ent=mc_list_ent->next;
+
+
+			i=readl(ETHER_ARC_ADR(dev->base_addr));
+			writel(i+4,ETHER_ARC_ADR(dev->base_addr));
+
+			temp=mc_list_ent->dmi_addr[3]|
+				mc_list_ent->dmi_addr[2]<<8 |
+				mc_list_ent->dmi_addr[1]<<16 |
+				mc_list_ent->dmi_addr[0]<<24;
+			writel(temp,ETHER_ARC_DATA(dev->base_addr));
+
+			i=readl(ETHER_ARC_ADR(dev->base_addr));
+			writel(i+4,ETHER_ARC_ADR(dev->base_addr));
+
+			temp=mc_list_ent->dmi_addr[4]<<16 |
+				mc_list_ent->dmi_addr[5]<<24;
+
+			writel(temp,ETHER_ARC_DATA(dev->base_addr));
+
+			count--;
+			if(!mc_list_ent->next || !count){
+				break;
+			}
+			mc_list_ent=mc_list_ent->next;
+		}
+
+
+		if(count)
+			printk(KERN_WARNING "Multicast list size error\n");
+
+
+		writew( ETHER_ARC_CTL_BROADACC_MSK|
+			ETHER_ARC_CTL_COMPEN_MSK,
+			ETHER_ARC_CTL(dev->base_addr));
+
+	}
+
+	/* enable the active ARC enties */
+	writew((1<<(dev->mc_count+2))-1,ETHER_ARC_ENA(dev->base_addr));
+}
+
+
+static int ether00_open(struct net_device* dev)
+{
+	int result,tmp;
+	struct net_priv* priv;
+
+	if (!is_valid_ether_addr(dev->dev_addr))
+		return -EINVAL;
+
+	dev->base_addr=(unsigned int)ioremap_nocache(base,SZ_4K);
+
+	dev->irq=irq;
+
+	/* Allocate private memory */
+	dev->priv=kmalloc(sizeof(struct net_priv),GFP_KERNEL);
+	if(!dev->priv)
+		return -ENOMEM;
+	memset(dev->priv,0,sizeof(struct net_priv));
+	priv=(struct net_priv*)dev->priv;
+	priv->tq_memupdate.routine=ether00_mem_update;
+	priv->tq_memupdate.data=(void*) dev;
+	spin_lock_init(&priv->dma_lock);
+
+	/* Install interrupt handlers */
+	result=request_irq(dev->irq,ether00_int,0,"ether00",dev);
+	if(result)
+		goto open_err1;
+
+	result=request_irq(phy_irq,ether00_phy_int,0,"ether00_phy",dev);
+	if(result)
+		goto open_err2;
+
+	ether00_reset(dev);
+	result=ether00_mem_init(dev);
+	if(result)
+		goto open_err3;
+
+
+	ether00_setup_ethernet_address(dev);
+
+	ether00_set_multicast(dev);
+
+	result=ether00_write_phy(dev,PHY_CONTROL, PHY_CONTROL_ANEGEN_MSK | PHY_CONTROL_RANEG_MSK);
+	if(result)
+		goto open_err4;
+	result=ether00_write_phy(dev,PHY_IRQ_CONTROL, PHY_IRQ_CONTROL_LS_CHG_IE_MSK |
+				 PHY_IRQ_CONTROL_ANEG_COMP_IE_MSK);
+	if(result)
+		goto open_err4;
+
+	/* Start the device enable interrupts */
+	writew(ETHER_RX_CTL_RXEN_MSK
+//	       | ETHER_RX_CTL_STRIPCRC_MSK
+	       | ETHER_RX_CTL_ENGOOD_MSK
+	       | ETHER_RX_CTL_ENRXPAR_MSK| ETHER_RX_CTL_ENLONGERR_MSK
+	       | ETHER_RX_CTL_ENOVER_MSK| ETHER_RX_CTL_ENCRCERR_MSK,
+	       ETHER_RX_CTL(dev->base_addr));
+
+	writew(ETHER_TX_CTL_TXEN_MSK|
+	       ETHER_TX_CTL_ENEXDEFER_MSK|
+	       ETHER_TX_CTL_ENLCARR_MSK|
+	       ETHER_TX_CTL_ENEXCOLL_MSK|
+	       ETHER_TX_CTL_ENLATECOLL_MSK|
+	       ETHER_TX_CTL_ENTXPAR_MSK|
+	       ETHER_TX_CTL_ENCOMP_MSK,
+	       ETHER_TX_CTL(dev->base_addr));
+
+	tmp=readl(ETHER_DMA_CTL(dev->base_addr));
+	writel(tmp&~ETHER_DMA_CTL_INTMASK_MSK,ETHER_DMA_CTL(dev->base_addr));
+
+	return 0;
+
+ open_err4:
+	ether00_reset(dev);
+ open_err3:
+	free_irq(2,dev);
+ open_err2:
+	free_irq(dev->irq,dev);
+ open_err1:
+	iounmap((void*)dev->base_addr);
+	kfree(dev->priv);
+	return result;
+
+}
+
+
+static int ether00_tx(struct sk_buff* skb, struct net_device* dev)
+{
+	struct net_priv *priv=dev->priv;
+	struct tx_fda_ent *fda_ptr;
+	unsigned long flags;
+        int retcode = 0;
+
+	/*
+	 *	Find an empty slot in which to stick the frame
+	 */
+
+	spin_lock_irqsave(&priv->dma_lock,flags);
+
+	fda_ptr=(struct tx_fda_ent*) priv->tx_head;
+
+	priv->tx_head =(unsigned int) __dma_va(fda_ptr->fd.FDNext);
+
+	/* Write the skb data from the cache*/
+	consistent_sync(skb->data,skb->len,PCI_DMA_TODEVICE);
+	fda_ptr->bd.BuffData=(char*)__pa(skb->data);
+	fda_ptr->bd.BuffLength=(unsigned short)skb->len;
+	/* Save the pointer to the skb for freeing later */
+	fda_ptr->fd.FDSystem=(unsigned int)skb;
+	fda_ptr->fd.FDStat=0;
+	/* Pass ownership of the buffers to the controller */
+	fda_ptr->fd.FDCtl=1;
+	fda_ptr->fd.FDCtl|=FDCTL_COWNSFD_MSK;
+
+	fda_ptr=(struct tx_fda_ent*) priv->tx_head;
+
+	/* If the next buffer in the list is full, stop the queue */
+	if (fda_ptr->fd.FDSystem){
+		netif_stop_queue(dev);
+		priv->queue_stopped=1;
+	}
+
+	spin_unlock_irqrestore(&priv->dma_lock,flags);
+	return retcode;
+}
+
+static void ether00_tx_timeout(struct net_device* dev)
+{
+         /*
+          * Something really bad has happened here. This
+          * SHOULD never happen. Given that, it's difficult
+          * to know what to do to recover. For now we'll just
+          * count the error, and restart the queue.
+          */
+
+        struct net_priv *priv=dev->priv;
+
+	priv->stats.tx_errors++;
+
+	priv->queue_stopped=0;
+	netif_wake_queue(dev);
+
+}
+
+static struct net_device_stats *ether00_stats(struct net_device* dev)
+{
+	struct net_priv *priv=dev->priv;
+	return &priv->stats;
+}
+
+
+static int ether00_stop(struct net_device* dev)
+{
+	struct net_priv *priv=dev->priv;
+	int tmp;
+
+	/* Stop/disable the device. */
+	tmp=readw(ETHER_RX_CTL(dev->base_addr));
+	tmp&=~(ETHER_RX_CTL_RXEN_MSK | ETHER_RX_CTL_ENGOOD_MSK);
+	tmp|=ETHER_RX_CTL_RXHALT_MSK;
+	writew(tmp,ETHER_RX_CTL(dev->base_addr));
+
+	tmp=readl(ETHER_TX_CTL(dev->base_addr));
+	tmp&=~ETHER_TX_CTL_TXEN_MSK;
+	tmp|=ETHER_TX_CTL_TXHALT_MSK;
+	writel(tmp,ETHER_TX_CTL(dev->base_addr));
+
+	/* Free up system resources */
+	free_irq(dev->irq,dev);
+	free_irq(2,dev);
+	iounmap(priv->dma_data);
+	iounmap((void*)dev->base_addr);
+	kfree(priv);
+
+	return 0;
+}
+
+
+static void ether00_get_ethernet_address(struct net_device* dev)
+{
+	struct mtd_info *mymtd=NULL;
+	int i;
+	size_t retlen;
+
+	/*
+	 * For the Epxa10 dev board (camelot), the ethernet MAC
+	 * address is of the form  00:aa:aa:00:xx:xx where
+	 * 00:aa:aa is the Altera vendor ID and xx:xx is the
+	 * last 2 bytes of the board serial number, as programmed
+	 * into the OTP area of the flash device on EBI1. If this
+	 * isn't an expa10 dev board, or there's no mtd support to
+	 * read the serial number from flash then we'll force the
+	 * use to set their own mac address using ifconfig.
+	 */
+
+#ifdef CONFIG_ARCH_CAMELOT
+#ifdef CONFIG_MTD
+	/* get the mtd_info structure for the first mtd device*/
+	for(i=0;i<MAX_MTD_DEVICES;i++){
+		mymtd=get_mtd_device(NULL,i);
+		if(!mymtd||!strcmp(mymtd->name,"EPXA10DB flash"))
+			break;
+	}
+
+	if(!mymtd || !mymtd->read_user_prot_reg){
+		printk(KERN_WARNING "%s: Failed to read MAC address from flash\n",dev->name);
+	}else{
+		mymtd->read_user_prot_reg(mymtd,2,1,&retlen,&dev->dev_addr[5]);
+		mymtd->read_user_prot_reg(mymtd,3,1,&retlen,&dev->dev_addr[4]);
+		dev->dev_addr[3]=0;
+		dev->dev_addr[2]=vendor_id[1];
+		dev->dev_addr[1]=vendor_id[0];
+		dev->dev_addr[0]=0;
+	}
+#else
+	printk(KERN_WARNING "%s: MTD support required to read MAC address from EPXA10 dev board\n", dev->name);
+#endif
+#endif
+
+	if (!is_valid_ether_addr(dev->dev_addr))
+		printk("%s: Invalid ethernet MAC address.  Please set using "
+			"ifconfig\n", dev->name);
+
+}
+
+static int ether00_init(struct net_device* dev)
+{
+
+	ether_setup(dev);
+
+	dev->open=ether00_open;
+	dev->stop=ether00_stop;
+	dev->set_multicast_list=ether00_set_multicast;
+	dev->hard_start_xmit=ether00_tx;
+	dev->get_stats=ether00_stats;
+	dev->tx_timeout=ether00_tx_timeout;
+	dev->watchdog_timeo=TX_TIMEOUT;
+
+	ether00_get_ethernet_address(dev);
+
+	SET_MODULE_OWNER(dev);
+	return 0;
+}
+
+
+struct net_device ether00_dev={
+	init:ether00_init,
+	name:"eth%d",
+};
+
+
+static void __exit ether00_cleanup_module(void)
+{
+	unregister_netdev(&ether00_dev);
+}
+module_exit(ether00_cleanup_module);
+
+
+static int __init ether00_mod_init(void)
+{
+	int result;
+
+	result=register_netdev(&ether00_dev);
+	if(result)
+		printk("Ether00: Error %i registering driver\n",result);
+	return result;
+}
+
+module_init(ether00_mod_init);
+
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/ewrk3.c linux-2.4.21-pre6/drivers/net/ewrk3.c
--- linux-2.4.20/drivers/net/ewrk3.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/ewrk3.c	2003-03-26 23:49:34.000000000 +0000
@@ -712,6 +712,7 @@
 	struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;
 	u_char csr, page;
 	u_long iobase = dev->base_addr;
+	int i;
 
 	/*
 	   ** Enable any multicasts
@@ -719,6 +720,13 @@
 	set_multicast_list(dev);
 
 	/*
+	** Set hardware MAC address. Address is initialized from the EEPROM
+	** during startup but may have since been changed by the user.
+	*/
+	for (i=0; i<ETH_ALEN; i++)
+		outb(dev->dev_addr[i], EWRK3_PAR0 + i);
+
+	/*
 	   ** Clean out any remaining entries in all the queues here
 	 */
 	while (inb(EWRK3_TQ));
@@ -1759,23 +1767,17 @@
 		return 0;
 	}
 
-#ifdef BROKEN
 	/* Blink LED for identification */
 	case ETHTOOL_PHYS_ID: {
 		struct ethtool_value edata;
 		u_long flags;
-		long delay, ret;
 		u_char cr;
 		int count;
-		wait_queue_head_t wait;
-
-		init_waitqueue_head(&wait);
 
 		if (copy_from_user(&edata, useraddr, sizeof(edata)))
 			return -EFAULT;
 
 		/* Toggle LED 4x per second */
-		delay = HZ >> 2;
 		count = edata.data << 2;
 
 		spin_lock_irqsave(&lp->hw_lock, flags);
@@ -1796,24 +1798,21 @@
 
 			/* Wait a little while */
 			spin_unlock_irqrestore(&lp->hw_lock, flags);
-			ret = delay;
-			__wait_event_interruptible_timeout(wait, 0, ret);
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			schedule_timeout(HZ>>2);
 			spin_lock_irqsave(&lp->hw_lock, flags);
 
 			/* Exit if we got a signal */
-			if (ret == -ERESTARTSYS)
-				goto out;
+			if (signal_pending(current))
+				break;
 		}
 
-		ret = 0;
-out:
 		lp->led_mask = CR_LED;
 		cr = inb(EWRK3_CR);
 		outb(cr & ~CR_LED, EWRK3_CR);
 		spin_unlock_irqrestore(&lp->hw_lock, flags);
-		return ret;
+		return signal_pending(current) ? -ERESTARTSYS : 0;
 	}
-#endif /* BROKEN */
 
 	}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/fc/iph5526.c linux-2.4.21-pre6/drivers/net/fc/iph5526.c
--- linux-2.4.20/drivers/net/fc/iph5526.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/fc/iph5526.c	2003-03-26 23:49:18.000000000 +0000
@@ -3768,7 +3768,7 @@
 	for (i = 0; i <= MAX_FC_CARDS; i++) 
 		fc[i] = NULL;
 
-	for (i = 0; i < clone_list[i].vendor_id != 0; i++)
+	for (i = 0; clone_list[i].vendor_id != 0; i++)
 	while ((pdev = pci_find_device(clone_list[i].vendor_id, clone_list[i].device_id, pdev))) {
 		unsigned short pci_command;
 		if (pci_enable_device(pdev))
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/fealnx.c linux-2.4.21-pre6/drivers/net/fealnx.c
--- linux-2.4.20/drivers/net/fealnx.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/fealnx.c	2003-03-26 23:49:50.000000000 +0000
@@ -1198,7 +1198,6 @@
 		printk("\n");
 	}
 
-	   + dev->if_port = np->default_port;
 	/* Reinit. Gross */
 
 	/* Reset the chip's Tx and Rx processes. */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/fmv18x.c linux-2.4.21-pre6/drivers/net/fmv18x.c
--- linux-2.4.20/drivers/net/fmv18x.c	2001-10-17 04:56:29.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/fmv18x.c	2003-03-26 23:49:00.000000000 +0000
@@ -369,7 +369,7 @@
 {
 	struct net_local *lp = dev->priv;
 	int ioaddr = dev->base_addr;
-	short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+	short length = skb->len;
 	unsigned char *buf = skb->data;
 	unsigned long flags;
 
@@ -381,6 +381,15 @@
 				dev->name, length);
 		return 1;
 	}
+	
+	if (length < ETH_ZLEN)
+	{
+		skb = skb_padto(skb, ETH_ZLEN);
+		if(skb == NULL)
+			return 0;
+		length = ETH_ZLEN;
+	}
+	
 	if (net_debug > 4)
 		printk("%s: Transmitting a packet of length %lu.\n", dev->name,
 			   (unsigned long)skb->len);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/hamachi.c linux-2.4.21-pre6/drivers/net/hamachi.c
--- linux-2.4.20/drivers/net/hamachi.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/hamachi.c	2003-03-26 23:49:38.000000000 +0000
@@ -158,7 +158,6 @@
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/time.h>
-#include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
@@ -508,13 +507,11 @@
 	unsigned int cur_tx, dirty_tx;
 	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 duplex_lock:1;
-	unsigned int medialock:1;		/* Do not sense media. */
 	unsigned int default_port:4;		/* Last dev->if_port value. */
 	/* MII transceiver section. */
 	int mii_cnt;								/* MII device addresses. */
-	u16 advertising;							/* NWay media advertisement */
+	struct mii_if_info mii_if;		/* MII lib hooks/info */
 	unsigned char phys[MII_CNT];		/* MII device addresses, only first one used. */
 	u32 rx_int_var, tx_int_var;	/* interrupt control variables */
 	u32 option;							/* Hold on to a copy of the options */
@@ -557,8 +554,8 @@
 MODULE_PARM_DESC(force32, "GNIC-II: Bit 0: 32 bit PCI, bit 1: disable parity, bit 2: 64 bit PCI (all boards)");
                                                                         
 static int read_eeprom(long ioaddr, int location);
-static int mdio_read(long ioaddr, int phy_id, int location);
-static void mdio_write(long ioaddr, int phy_id, int location, int value);
+static int mdio_read(struct net_device *dev, int phy_id, int location);
+static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
 static int hamachi_open(struct net_device *dev);
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static void hamachi_timer(unsigned long data);
@@ -640,6 +637,12 @@
 	hmp = dev->priv;
 	spin_lock_init(&hmp->lock);
 
+	hmp->mii_if.dev = dev;
+	hmp->mii_if.mdio_read = mdio_read;
+	hmp->mii_if.mdio_write = mdio_write;
+	hmp->mii_if.phy_id_mask = 0x1f;
+	hmp->mii_if.reg_num_mask = 0x1f;
+
 	ring_space = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &ring_dma);
 	if (!ring_space)
 		goto err_out_cleardev;
@@ -688,18 +691,18 @@
 	if (option > 0) {
 		hmp->option = option;
 		if (option & 0x200)
-			hmp->full_duplex = 1;
+			hmp->mii_if.full_duplex = 1;
 		else if (option & 0x080)
-			hmp->full_duplex = 0;
+			hmp->mii_if.full_duplex = 0;
 		hmp->default_port = option & 15;
 		if (hmp->default_port)
-			hmp->medialock = 1;
+			hmp->mii_if.force_media = 1;
 	}
 	if (card_idx < MAX_UNITS  &&  full_duplex[card_idx] > 0)
-		hmp->full_duplex = 1;
+		hmp->mii_if.full_duplex = 1;
 
 	/* lock the duplex mode if someone specified a value */
-	if (hmp->full_duplex || (option & 0x080))
+	if (hmp->mii_if.full_duplex || (option & 0x080))
 		hmp->duplex_lock = 1;
 
 	/* Set interrupt tuning parameters */
@@ -752,17 +755,21 @@
 	if (chip_tbl[hmp->chip_id].flags & CanHaveMII) {
 		int phy, phy_idx = 0;
 		for (phy = 0; phy < 32 && phy_idx < MII_CNT; phy++) {
-			int mii_status = mdio_read(ioaddr, phy, 1);
+			int mii_status = mdio_read(dev, phy, MII_BMSR);
 			if (mii_status != 0xffff  &&
 				mii_status != 0x0000) {
 				hmp->phys[phy_idx++] = phy;
-				hmp->advertising = mdio_read(ioaddr, phy, 4);
+				hmp->mii_if.advertising = mdio_read(dev, phy, MII_ADVERTISE);
 				printk(KERN_INFO "%s: MII PHY found at address %d, status "
 					   "0x%4.4x advertising %4.4x.\n",
-					   dev->name, phy, mii_status, hmp->advertising);
+					   dev->name, phy, mii_status, hmp->mii_if.advertising);
 			}
 		}
 		hmp->mii_cnt = phy_idx;
+		if (hmp->mii_cnt > 0)
+			hmp->mii_if.phy_id = hmp->phys[0];
+		else
+			memset(&hmp->mii_if, 0, sizeof(hmp->mii_if));
 	}
 	/* Configure gigabit autonegotiation. */
 	writew(0x0400, ioaddr + ANXchngCtrl);	/* Enable legacy links. */
@@ -808,8 +815,9 @@
    These routines assume the MDIO controller is idle, and do not exit until
    the command is finished. */
 
-static int mdio_read(long ioaddr, int phy_id, int location)
+static int mdio_read(struct net_device *dev, int phy_id, int location)
 {
+	long ioaddr = dev->base_addr;
 	int i;
 
 	/* We should check busy first - per docs -KDU */
@@ -824,8 +832,9 @@
 	return readw(ioaddr + MII_Rd_Data);
 }
 
-static void mdio_write(long ioaddr, int phy_id, int location, int value)
+static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
 {
+	long ioaddr = dev->base_addr;
 	int i;
 
 	/* We should check busy first - per docs -KDU */
@@ -915,7 +924,7 @@
 	/* Setting the Rx mode will start the Rx process. */
 	/* If someone didn't choose a duplex, default to full-duplex */ 
 	if (hmp->duplex_lock != 1)
-		hmp->full_duplex = 1;
+		hmp->mii_if.full_duplex = 1;
 
 	/* always 1, takes no more time to do it */
 	writew(0x0001, ioaddr + RxChecksum);
@@ -1463,64 +1472,6 @@
 	spin_unlock(&hmp->lock);
 }
 
-#ifdef TX_CHECKSUM
-/*
- * Copied from eth_type_trans(), with reduced header, since we don't
- * get it on RX, only on TX.
- */
-static unsigned short hamachi_eth_type_trans(struct sk_buff *skb,
-  struct net_device *dev)
-{
-	struct ethhdr *eth;
-	unsigned char *rawp;
-	
-	skb->mac.raw=skb->data;
-	skb_pull(skb,dev->hard_header_len-8);  /* artificially enlarged on tx */
-	eth= skb->mac.ethernet;
-	
-	if(*eth->h_dest&1)
-	{
-		if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0)
-			skb->pkt_type=PACKET_BROADCAST;
-		else
-			skb->pkt_type=PACKET_MULTICAST;
-	}
-	
-	/*
-	 *	This ALLMULTI check should be redundant by 1.4
-	 *	so don't forget to remove it.
-	 *
-	 *	Seems, you forgot to remove it. All silly devices
-	 *	seems to set IFF_PROMISC.
-	 */
-	 
-	else if(dev->flags&(IFF_PROMISC/*|IFF_ALLMULTI*/))
-	{
-		if(memcmp(eth->h_dest,dev->dev_addr, ETH_ALEN))
-			skb->pkt_type=PACKET_OTHERHOST;
-	}
-	
-	if (ntohs(eth->h_proto) >= 1536)
-		return eth->h_proto;
-		
-	rawp = skb->data;
-	
-	/*
-	 *	This is a magic hack to spot IPX packets. Older Novell breaks
-	 *	the protocol design and runs IPX over 802.3 without an 802.2 LLC
-	 *	layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
-	 *	won't work for fault tolerant netware but does for the rest.
-	 */
-	if (*(unsigned short *)rawp == 0xFFFF)
-		return htons(ETH_P_802_3);
-		
-	/*
-	 *	Real 802.2 LLC
-	 */
-	return htons(ETH_P_802_2);
-}
-#endif  /* TX_CHECKSUM */
-
 /* This routine is logically part of the interrupt handler, but seperated
    for clarity and better register allocation. */
 static int hamachi_rx(struct net_device *dev)
@@ -1625,12 +1576,7 @@
 				skb_put(skb = hmp->rx_skbuff[entry], pkt_len);
 				hmp->rx_skbuff[entry] = NULL;
 			}
-#ifdef TX_CHECKSUM
-			/* account for extra TX hard_header bytes */
-			skb->protocol = hamachi_eth_type_trans(skb, dev);
-#else
 			skb->protocol = eth_type_trans(skb, dev);
-#endif
 
 
 #ifdef RX_CHECKSUM
@@ -1912,7 +1858,7 @@
 
 static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
 {
-	struct hamachi_private *hmp = dev->priv;
+	struct hamachi_private *np = dev->priv;
 	u32 ethcmd;
 		
 	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
@@ -1923,12 +1869,53 @@
 		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
 		strcpy(info.driver, DRV_NAME);
 		strcpy(info.version, DRV_VERSION);
-		strcpy(info.bus_info, hmp->pci_dev->slot_name);
+		strcpy(info.bus_info, np->pci_dev->slot_name);
 		if (copy_to_user(useraddr, &info, sizeof(info)))
 			return -EFAULT;
 		return 0;
 	}
 
+	/* get settings */
+	case ETHTOOL_GSET: {
+		struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+		if (!(chip_tbl[np->chip_id].flags & CanHaveMII))
+			return -EINVAL;
+		spin_lock_irq(&np->lock);
+		mii_ethtool_gset(&np->mii_if, &ecmd);
+		spin_unlock_irq(&np->lock);
+		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
+			return -EFAULT;
+		return 0;
+	}
+	/* set settings */
+	case ETHTOOL_SSET: {
+		int r;
+		struct ethtool_cmd ecmd;
+		if (!(chip_tbl[np->chip_id].flags & CanHaveMII))
+			return -EINVAL;
+		if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
+			return -EFAULT;
+		spin_lock_irq(&np->lock);
+		r = mii_ethtool_sset(&np->mii_if, &ecmd);
+		spin_unlock_irq(&np->lock);
+		return r;
+	}
+	/* restart autonegotiation */
+	case ETHTOOL_NWAY_RST: {
+		if (!(chip_tbl[np->chip_id].flags & CanHaveMII))
+			return -EINVAL;
+		return mii_nway_restart(&np->mii_if);
+	}
+	/* get link status */
+	case ETHTOOL_GLINK: {
+		struct ethtool_value edata = {ETHTOOL_GLINK};
+		if (!(chip_tbl[np->chip_id].flags & CanHaveMII))
+			return -EINVAL;
+		edata.data = mii_link_ok(&np->mii_if);
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
         }
 	
 	return -EOPNOTSUPP;
@@ -1936,32 +1923,17 @@
 
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-	long ioaddr = dev->base_addr;
-	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data;
+	struct hamachi_private *np = dev->priv;
+	struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data;
+	int rc;
 
-	switch(cmd) {
-	case SIOCETHTOOL:
-		return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
-	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
-	case SIOCDEVPRIVATE:		/* for binary compat, remove in 2.5 */
-		data->phy_id = ((struct hamachi_private *)dev->priv)->phys[0] & 0x1f;
-		/* Fall Through */
-
-	case SIOCGMIIREG:		/* Read MII PHY register. */
-	case SIOCDEVPRIVATE+1:		/* for binary compat, remove in 2.5 */
-		data->val_out = mdio_read(ioaddr, data->phy_id & 0x1f, data->reg_num & 0x1f);
-		return 0;
+	if (!netif_running(dev))
+		return -EINVAL;
 
-	case SIOCSMIIREG:		/* Write MII PHY register. */
-	case SIOCDEVPRIVATE+2:		/* for binary compat, remove in 2.5 */
-		/* TODO: Check the sequencing of this.  Might need to stop and
-		 * restart Rx and Tx engines. -KDU
-		 */
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		mdio_write(ioaddr, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
-		return 0;
-	case SIOCDEVPRIVATE+3: { /* set rx,tx intr params */
+	if (cmd == SIOCETHTOOL)
+		rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+
+	else if (cmd == (SIOCDEVPRIVATE+3)) { /* set rx,tx intr params */
 		u32 *d = (u32 *)&rq->ifr_data;
 		/* Should add this check here or an ordinary user can do nasty
 		 * things. -KDU
@@ -1975,11 +1947,16 @@
 		printk(KERN_NOTICE "%s: tx %08x, rx %08x intr\n", dev->name,
 		  (u32) readl(dev->base_addr + TxIntrCtrl),
 		  (u32) readl(dev->base_addr + RxIntrCtrl));
-		return 0;
-	    }
-	default:
-		return -EOPNOTSUPP;
+		rc = 0;
+	}
+
+	else {
+		spin_lock_irq(&np->lock);
+		rc = generic_mii_ioctl(&np->mii_if, data, cmd, NULL);
+		spin_unlock_irq(&np->lock);
 	}
+
+	return rc;
 }
 
 
@@ -2010,10 +1987,10 @@
 MODULE_DEVICE_TABLE(pci, hamachi_pci_tbl);
 
 static struct pci_driver hamachi_driver = {
-	name:		DRV_NAME,
-	id_table:	hamachi_pci_tbl,
-	probe:		hamachi_init_one,
-	remove:		__devexit_p(hamachi_remove_one),
+	.name		= DRV_NAME,
+	.id_table	= hamachi_pci_tbl,
+	.probe		= hamachi_init_one,
+	.remove		= __devexit_p(hamachi_remove_one),
 };
 
 static int __init hamachi_init (void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/hp100.c linux-2.4.21-pre6/drivers/net/hp100.c
--- linux-2.4.20/drivers/net/hp100.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/hp100.c	2003-03-26 23:49:29.000000000 +0000
@@ -1542,6 +1542,13 @@
 
 	if (skb->len <= 0)
 		return 0;
+		
+	if (skb->len < ETH_ZLEN && lp->chip == HP100_CHIPID_SHASTA)
+	{
+		skb = skb_padto(skb, ETH_ZLEN);
+		if(skb == NULL)
+			return 0;
+	}
 
 	/* Get Tx ring tail pointer */
 	if (lp->txrtail->next == lp->txrhead) {
@@ -2099,6 +2106,7 @@
 	struct hp100_private *lp = (struct hp100_private *) dev->priv;
 
 #ifdef HP100_DEBUG_B
+	int ioaddr = dev->base_addr;
 	hp100_outw(0x4216, TRACE);
 	printk("hp100: %s: misc_interrupt\n", dev->name);
 #endif
@@ -2538,6 +2546,11 @@
 		return HP100_LAN_10;
 
 	if (val_10 & HP100_AUI_ST) {	/* have we BNC or AUI onboard? */
+		/*
+		 * This can be overriden by dos utility, so if this has no effect,
+		 * perhaps you need to download that utility from HP and set card
+		 * back to "auto detect".
+		 */
 		val_10 |= HP100_AUI_SEL | HP100_LOW_TH;
 		hp100_page(MAC_CTRL);
 		hp100_outb(val_10, 10_LAN_CFG_1);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/irda/Config.in linux-2.4.21-pre6/drivers/net/irda/Config.in
--- linux-2.4.20/drivers/net/irda/Config.in	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/irda/Config.in	2003-03-26 23:49:53.000000000 +0000
@@ -28,6 +28,7 @@
 dep_tristate 'IrDA USB dongles (Experimental)' CONFIG_USB_IRDA $CONFIG_IRDA $CONFIG_USB $CONFIG_EXPERIMENTAL
 dep_tristate 'NSC PC87108/PC87338' CONFIG_NSC_FIR  $CONFIG_IRDA
 dep_tristate 'Winbond W83977AF (IR)' CONFIG_WINBOND_FIR $CONFIG_IRDA
+dep_tristate 'Toshiba Type-O IR Port (old driver)' CONFIG_TOSHIBA_OLD $CONFIG_IRDA
 dep_tristate 'Toshiba Type-O IR Port' CONFIG_TOSHIBA_FIR $CONFIG_IRDA
 if [ "$CONFIG_MIPS" = "y" ]; then
    dep_tristate 'Alchemy Au1000 SIR/FIR' CONFIG_AU1000_FIR $CONFIG_IRDA
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/irda/Makefile linux-2.4.21-pre6/drivers/net/irda/Makefile
--- linux-2.4.20/drivers/net/irda/Makefile	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/irda/Makefile	2003-03-26 23:49:35.000000000 +0000
@@ -17,7 +17,8 @@
 obj-$(CONFIG_NSC_FIR)		+= nsc-ircc.o
 obj-$(CONFIG_WINBOND_FIR)	+= w83977af_ir.o
 obj-$(CONFIG_SA1100_FIR)	+= sa1100_ir.o
-obj-$(CONFIG_TOSHIBA_FIR)	+= toshoboe.o
+obj-$(CONFIG_TOSHIBA_OLD)	+= toshoboe.o
+obj-$(CONFIG_TOSHIBA_FIR)	+= donauboe.o
 obj-$(CONFIG_SMC_IRCC_FIR)	+= smc-ircc.o	irport.o
 obj-$(CONFIG_ALI_FIR)		+= ali-ircc.o
 obj-$(CONFIG_VLSI_FIR)		+= vlsi_ir.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/irda/ali-ircc.c linux-2.4.21-pre6/drivers/net/irda/ali-ircc.c
--- linux-2.4.20/drivers/net/irda/ali-ircc.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/irda/ali-ircc.c	2003-03-26 23:49:30.000000000 +0000
@@ -2017,22 +2017,19 @@
 
 	IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd);
 	
-	/* Disable interrupts & save flags */
-	save_flags(flags);
-	cli();	
-	
 	switch (cmd) {
 	case SIOCSBANDWIDTH: /* Set bandwidth */
 		IRDA_DEBUG(1, "%s(), SIOCSBANDWIDTH\n", __FUNCTION__);
-		/*
-		 * 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))
+		/* Root only */
+		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
 		
+		/* Is it really needed ? And what about spinlock ? */
+		save_flags(flags);
+		cli();	
+
 		ali_ircc_change_speed(self, irq->ifr_baudrate);		
+		restore_flags(flags);
 		break;
 	case SIOCSMEDIABUSY: /* Set media busy */
 		IRDA_DEBUG(1, "%s(), SIOCSMEDIABUSY\n", __FUNCTION__);
@@ -2042,14 +2039,17 @@
 		break;
 	case SIOCGRECEIVING: /* Check if we are receiving right now */
 		IRDA_DEBUG(2, "%s(), SIOCGRECEIVING\n", __FUNCTION__);
+		/* Is it really needed ? And what about spinlock ? */
+		save_flags(flags);
+		cli();	
+
 		irq->ifr_receiving = ali_ircc_is_receiving(self);
+		restore_flags(flags);
 		break;
 	default:
 		ret = -EOPNOTSUPP;
 	}
-	
-	restore_flags(flags);
-	
+
 	IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__);	
 	
 	return ret;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/irda/donauboe.c linux-2.4.21-pre6/drivers/net/irda/donauboe.c
--- linux-2.4.20/drivers/net/irda/donauboe.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/irda/donauboe.c	2003-03-26 23:49:06.000000000 +0000
@@ -0,0 +1,1850 @@
+/*****************************************************************
+ *
+ * Filename:		donauboe.c
+ * Version: 		2.17
+ * Description:   Driver for the Toshiba OBOE (or type-O or 701)
+ *                FIR Chipset, also supports the DONAUOBOE (type-DO
+ *                or d01) FIR chipset which as far as I know is
+ *                register compatible.
+ * Status:        Experimental.
+ * Author:        James McKenzie <james@fishsoup.dhs.org>
+ * Created at:    Sat May 8  12:35:27 1999
+ * Modified:      Paul Bristow <paul.bristow@technologist.com>
+ * Modified:      Mon Nov 11 19:10:05 1999
+ * Modified:      James McKenzie <james@fishsoup.dhs.org>
+ * Modified:      Thu Mar 16 12:49:00 2000 (Substantial rewrite)
+ * Modified:      Sat Apr 29 00:23:03 2000 (Added DONAUOBOE support)
+ * Modified:      Wed May 24 23:45:02 2000 (Fixed chipio_t structure)
+ * Modified: 2.13 Christian Gennerat <christian.gennerat@polytechnique.org>
+ * Modified: 2.13 dim jan 07 21:57:39 2001 (tested with kernel 2.4 & irnet/ppp)
+ * Modified: 2.14 Christian Gennerat <christian.gennerat@polytechnique.org>
+ * Modified: 2.14 lun fev 05 17:55:59 2001 (adapted to patch-2.4.1-pre8-irda1)
+ * Modified: 2.15 Martin Lucina <mato@kotelna.sk>
+ * Modified: 2.15 Fri Jun 21 20:40:59 2002 (sync with 2.4.18, substantial fixes)
+ * Modified: 2.16 Martin Lucina <mato@kotelna.sk>
+ * Modified: 2.16 Sat Jun 22 18:54:29 2002 (fix freeregion, default to verbose)
+ * Modified: 2.17 Christian Gennerat <christian.gennerat@polytechnique.org>
+ * Modified: 2.17 jeu sep 12 08:50:20 2002 (save_flags();cli(); replaced by spinlocks)
+ *
+ *     Copyright (c) 1999 James McKenzie, 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 James McKenzie nor Cambridge University admit liability nor
+ *     provide warranty for any of this software. This material is
+ *     provided "AS-IS" and at no charge.
+ *
+ *     Applicable Models : Libretto 100/110CT and many more.
+ *     Toshiba refers to this chip as the type-O IR port,
+ *     or the type-DO IR port.
+ *
+ ********************************************************************/
+
+/* Look at toshoboe.h (currently in include/net/irda) for details of */
+/* Where to get documentation on the chip         */
+
+
+static char *rcsid =
+  "$Id: donauboe.c V2.17 jeu sep 12 08:50:20 2002 $";
+
+/* See below for a description of the logic in this driver */
+
+/* Is irda_crc16_table[] exported? not yet */
+/* define this if you get errors about multiple defns of irda_crc16_table */
+#undef CRC_EXPORTED
+
+/* User servicable parts */
+/* Enable the code which probes the chip and does a few tests */
+/* Probe code is very useful for understanding how the hardware works */
+/* Use it with various combinations of TT_LEN, RX_LEN */
+/* Strongly recomended, disable if the probe fails on your machine */
+/* and send me <james@fishsoup.dhs.org> the output of dmesg */
+#define DO_PROBE 1
+
+/* Trace Transmit ring, interrupts, Receive ring or not ? */
+#define PROBE_VERBOSE 1
+
+/* Debug option, examine sent and received raw data */
+/* Irdadump is better, but does not see all packets. enable it if you want. */
+#undef DUMP_PACKETS
+
+/* MIR mode has not been tested. Some behaviour is different */
+/* Seems to work against an Ericsson R520 for me. -Martin */
+#define USE_MIR
+
+/* Schedule back to back hardware transmits wherever possible, otherwise */
+/* we need an interrupt for every frame, unset if oboe works for a bit and */
+/* then hangs */
+#define OPTIMIZE_TX
+
+/* Set the number of slots in the rings */
+/* If you get rx/tx fifo overflows at high bitrates, you can try increasing */
+/* these */
+
+#define RING_SIZE (OBOE_RING_SIZE_RX8 | OBOE_RING_SIZE_TX8)
+#define TX_SLOTS    8
+#define RX_SLOTS    8
+
+
+/* Less user servicable parts below here */
+
+/* Test, Transmit and receive buffer sizes, adjust at your peril */
+/* remarks: nfs usually needs 1k blocks */
+/* remarks: in SIR mode, CRC is received, -> RX_LEN=TX_LEN+2 */
+/* remarks: test accepts large blocks. Standard is 0x80 */
+/* When TT_LEN > RX_LEN (SIR mode) data is stored in successive slots. */
+/* When 3 or more slots are needed for each test packet, */
+/* data received in the first slots is overwritten, even */
+/* if OBOE_CTL_RX_HW_OWNS is not set, without any error! */
+#define TT_LEN      0x80
+#define TX_LEN      0xc00
+#define RX_LEN      0xc04
+/* Real transmitted length (SIR mode) is about 14+(2%*TX_LEN) more */
+/* long than user-defined length (see async_wrap_skb) and is less then 4K */
+/* Real received length is (max RX_LEN) differs from user-defined */
+/* length only b the CRC (2 or 4 bytes) */
+#define BUF_SAFETY  0x7a
+#define RX_BUF_SZ   (RX_LEN)
+#define TX_BUF_SZ   (TX_LEN+BUF_SAFETY)
+
+
+/* Logic of the netdev part of this driver                             */
+
+/* The RX ring is filled with buffers, when a packet arrives           */
+/* it is DMA'd into the buffer which is marked used and RxDone called  */
+/* RxDone forms an skb (and checks the CRC if in SIR mode) and ships   */
+/* the packet off upstairs */
+
+/* The transmitter on the oboe chip can work in one of two modes       */
+/* for each ring->tx[] the transmitter can either                      */
+/* a) transmit the packet, leave the trasmitter enabled and proceed to */
+/*    the next ring                                                    */
+/* OR                                                                  */
+/* b) transmit the packet, switch off the transmitter and issue TxDone */
+
+/* All packets are entered into the ring in mode b), if the ring was   */
+/* empty the transmitter is started.                                   */
+
+/* If OPTIMIZE_TX is defined then in TxDone if the ring contains       */
+/* more than one packet, all but the last are set to mode a) [HOWEVER  */
+/* the hardware may not notice this, this is why we start in mode b) ] */
+/* then restart the transmitter                                        */
+
+/* If OPTIMIZE_TX is not defined then we just restart the transmitter  */
+/* if the ring isn't empty */
+
+/* Speed changes are delayed until the TxRing is empty                 */
+/* mtt is handled by generating packets with bad CRCs, before the data */
+
+/* TODO: */
+/* check the mtt works ok      */
+/* finish the watchdog         */
+
+/* No user servicable parts below here */
+
+#define STATIC static
+
+#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/slab.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/rtnetlink.h>
+
+#include <asm/system.h>
+#include <asm/io.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/crc.h>
+
+#include "donauboe.h"
+
+#define INB(port)       inb_p(port)
+#define OUTB(val,port)  outb_p(val,port)
+#define OUTBP(val,port) outb_p(val,port)
+
+#define PROMPT  OUTB(OBOE_PROMPT_BIT,OBOE_PROMPT);
+
+#if PROBE_VERBOSE
+#define PROBE_DEBUG(args...) (printk (args))
+#else
+#define PROBE_DEBUG(args...) ;
+#endif
+
+/* Set the DMA to be byte at a time */
+#define CONFIG0H_DMA_OFF OBOE_CONFIG0H_RCVANY
+#define CONFIG0H_DMA_ON_NORX CONFIG0H_DMA_OFF| OBOE_CONFIG0H_ENDMAC
+#define CONFIG0H_DMA_ON CONFIG0H_DMA_ON_NORX | OBOE_CONFIG0H_ENRX
+
+static struct pci_device_id toshoboe_pci_tbl[] __initdata = {
+	{ PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_FIR701, PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_FIRD01, PCI_ANY_ID, PCI_ANY_ID, },
+	{ }			/* Terminating entry */
+};
+MODULE_DEVICE_TABLE(pci, toshoboe_pci_tbl);
+
+#define DRIVER_NAME "toshoboe"
+static char *driver_name = DRIVER_NAME;
+
+static int max_baud = 4000000;
+static int do_probe = DO_PROBE;
+
+
+/**********************************************************************/
+/* Fcs code */
+
+#ifdef CRC_EXPORTED
+extern __u16 const irda_crc16_table[];
+#else
+static __u16 const irda_crc16_table[256] = {
+  0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+  0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+  0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+  0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+  0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+  0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+  0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+  0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+  0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+  0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+  0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+  0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+  0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+  0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+  0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+  0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+  0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+  0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+  0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+  0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+  0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+  0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+  0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+  0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+  0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+  0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+  0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+  0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+  0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+  0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+  0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+  0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
+#endif
+
+STATIC int
+toshoboe_checkfcs (unsigned char *buf, int len)
+{
+  int i;
+  union
+  {
+    __u16 value;
+    __u8 bytes[2];
+  }
+  fcs;
+
+  fcs.value = INIT_FCS;
+
+  for (i = 0; i < len; ++i)
+    fcs.value = irda_fcs (fcs.value, *(buf++));
+
+  return (fcs.value == GOOD_FCS);
+}
+
+/***********************************************************************/
+/* Generic chip handling code */
+#ifdef DUMP_PACKETS
+static unsigned char dump[50];
+STATIC void 
+_dumpbufs (unsigned char *data, int len, char tete)
+{
+int i,j;
+char head=tete;
+for (i=0;i<len;i+=16) {
+    for (j=0;j<16 && i+j<len;j++) { sprintf(&dump[3*j],"%02x.",data[i+j]); }
+    dump [3*j]=0;
+    IRDA_DEBUG (2, "%c%s\n",head , dump);
+    head='+'; 
+    }
+}
+#endif
+
+/* Dump the registers */
+STATIC void
+toshoboe_dumpregs (struct toshoboe_cb *self)
+{
+  __u32 ringbase;
+
+  IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
+
+  ringbase = INB (OBOE_RING_BASE0) << 10;
+  ringbase |= INB (OBOE_RING_BASE1) << 18;
+  ringbase |= INB (OBOE_RING_BASE2) << 26;
+
+  printk (KERN_ERR DRIVER_NAME ": Register dump:\n");
+  printk (KERN_ERR "Interrupts: Tx:%d Rx:%d TxUnder:%d RxOver:%d Sip:%d\n",
+          self->int_tx, self->int_rx, self->int_txunder, self->int_rxover,
+          self->int_sip);
+  printk (KERN_ERR "RX %02x TX %02x RingBase %08x\n",
+          INB (OBOE_RXSLOT), INB (OBOE_TXSLOT), ringbase);
+  printk (KERN_ERR "RING_SIZE %02x IER %02x ISR %02x\n",
+          INB (OBOE_RING_SIZE), INB (OBOE_IER), INB (OBOE_ISR));
+  printk (KERN_ERR "CONFIG1 %02x STATUS %02x\n",
+          INB (OBOE_CONFIG1), INB (OBOE_STATUS));
+  printk (KERN_ERR "CONFIG0 %02x%02x ENABLE %02x%02x\n",
+          INB (OBOE_CONFIG0H), INB (OBOE_CONFIG0L),
+          INB (OBOE_ENABLEH), INB (OBOE_ENABLEL));
+  printk (KERN_ERR "NEW_PCONFIG %02x%02x CURR_PCONFIG %02x%02x\n",
+          INB (OBOE_NEW_PCONFIGH), INB (OBOE_NEW_PCONFIGL),
+          INB (OBOE_CURR_PCONFIGH), INB (OBOE_CURR_PCONFIGL));
+  printk (KERN_ERR "MAXLEN %02x%02x RXCOUNT %02x%02x\n",
+          INB (OBOE_MAXLENH), INB (OBOE_MAXLENL),
+          INB (OBOE_RXCOUNTL), INB (OBOE_RXCOUNTH));
+
+  if (self->ring)
+    {
+      int i;
+      ringbase = virt_to_bus (self->ring);
+      printk (KERN_ERR "Ring at %08x:\n", ringbase);
+      printk (KERN_ERR "RX:");
+      for (i = 0; i < RX_SLOTS; ++i)
+        printk (" (%d,%02x)",self->ring->rx[i].len,self->ring->rx[i].control);
+      printk ("\n");
+      printk (KERN_ERR "TX:");
+      for (i = 0; i < RX_SLOTS; ++i)
+        printk (" (%d,%02x)",self->ring->tx[i].len,self->ring->tx[i].control);
+      printk ("\n");
+    }
+}
+
+/*Don't let the chip look at memory */
+STATIC void
+toshoboe_disablebm (struct toshoboe_cb *self)
+{
+  __u8 command;
+  IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
+
+  pci_read_config_byte (self->pdev, PCI_COMMAND, &command);
+  command &= ~PCI_COMMAND_MASTER;
+  pci_write_config_byte (self->pdev, PCI_COMMAND, command);
+
+}
+
+/* Shutdown the chip and point the taskfile reg somewhere else */
+STATIC void
+toshoboe_stopchip (struct toshoboe_cb *self)
+{
+  IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
+
+  /*Disable interrupts */
+  OUTB (0x0, OBOE_IER);
+  /*Disable DMA, Disable Rx, Disable Tx */
+  OUTB (CONFIG0H_DMA_OFF, OBOE_CONFIG0H);
+  /*Disable SIR MIR FIR, Tx and Rx */
+  OUTB (0x00, OBOE_ENABLEH);
+  /*Point the ring somewhere safe */
+  OUTB (0x3f, OBOE_RING_BASE2);
+  OUTB (0xff, OBOE_RING_BASE1);
+  OUTB (0xff, OBOE_RING_BASE0);
+
+  OUTB (RX_LEN >> 8, OBOE_MAXLENH);
+  OUTB (RX_LEN & 0xff, OBOE_MAXLENL);
+
+  /*Acknoledge any pending interrupts */
+  OUTB (0xff, OBOE_ISR);
+
+  /*Why */
+  OUTB (OBOE_ENABLEH_PHYANDCLOCK, OBOE_ENABLEH);
+
+  /*switch it off */
+  OUTB (OBOE_CONFIG1_OFF, OBOE_CONFIG1);
+
+  toshoboe_disablebm (self);
+}
+
+/* Transmitter initialization */
+STATIC void
+toshoboe_start_DMA (struct toshoboe_cb *self, int opts)
+{
+  OUTB (0x0, OBOE_ENABLEH);
+  OUTB (CONFIG0H_DMA_ON | opts,  OBOE_CONFIG0H);
+  OUTB (OBOE_ENABLEH_PHYANDCLOCK, OBOE_ENABLEH);
+  PROMPT;
+}
+
+/*Set the baud rate */
+STATIC void
+toshoboe_setbaud (struct toshoboe_cb *self)
+{
+  __u16 pconfig = 0;
+  __u8 config0l = 0;
+
+  IRDA_DEBUG (2, "%s(%d/%d)\n", __FUNCTION__, self->speed, self->io.speed);
+
+  switch (self->speed)
+    {
+    case 2400:
+    case 4800:
+    case 9600:
+    case 19200:
+    case 38400:
+    case 57600:
+    case 115200:
+#ifdef USE_MIR
+    case 1152000:
+#endif
+    case 4000000:
+      break;
+    default:
+
+      printk (KERN_ERR DRIVER_NAME ": switch to unsupported baudrate %d\n",
+              self->speed);
+      return;
+    }
+
+  switch (self->speed)
+    {
+      /* For SIR the preamble is done by adding XBOFs */
+      /* to the packet */
+      /* set to filtered SIR mode, filter looks for BOF and EOF */
+    case 2400:
+      pconfig |= 47 << OBOE_PCONFIG_BAUDSHIFT;
+      pconfig |= 25 << OBOE_PCONFIG_WIDTHSHIFT;
+      break;
+    case 4800:
+      pconfig |= 23 << OBOE_PCONFIG_BAUDSHIFT;
+      pconfig |= 25 << OBOE_PCONFIG_WIDTHSHIFT;
+      break;
+    case 9600:
+      pconfig |= 11 << OBOE_PCONFIG_BAUDSHIFT;
+      pconfig |= 25 << OBOE_PCONFIG_WIDTHSHIFT;
+      break;
+    case 19200:
+      pconfig |= 5 << OBOE_PCONFIG_BAUDSHIFT;
+      pconfig |= 25 << OBOE_PCONFIG_WIDTHSHIFT;
+      break;
+    case 38400:
+      pconfig |= 2 << OBOE_PCONFIG_BAUDSHIFT;
+      pconfig |= 25 << OBOE_PCONFIG_WIDTHSHIFT;
+      break;
+    case 57600:
+      pconfig |= 1 << OBOE_PCONFIG_BAUDSHIFT;
+      pconfig |= 25 << OBOE_PCONFIG_WIDTHSHIFT;
+      break;
+    case 115200:
+      pconfig |= 0 << OBOE_PCONFIG_BAUDSHIFT;
+      pconfig |= 25 << OBOE_PCONFIG_WIDTHSHIFT;
+      break;
+    default:
+      /*Set to packet based reception */
+      OUTB (RX_LEN >> 8, OBOE_MAXLENH);
+      OUTB (RX_LEN & 0xff, OBOE_MAXLENL);
+      break;
+    }
+
+  switch (self->speed)
+    {
+    case 2400:
+    case 4800:
+    case 9600:
+    case 19200:
+    case 38400:
+    case 57600:
+    case 115200:
+      config0l = OBOE_CONFIG0L_ENSIR;
+      if (self->async)
+        {
+          /*Set to character based reception */
+          /*System will lock if MAXLEN=0 */
+          /*so have to be careful */
+          OUTB (0x01, OBOE_MAXLENH);
+          OUTB (0x01, OBOE_MAXLENL);
+          OUTB (0x00, OBOE_MAXLENH);
+        }
+      else
+        {
+          /*Set to packet based reception */
+          config0l |= OBOE_CONFIG0L_ENSIRF;
+          OUTB (RX_LEN >> 8, OBOE_MAXLENH);
+          OUTB (RX_LEN & 0xff, OBOE_MAXLENL);
+        }
+      break;
+
+#ifdef USE_MIR
+      /* MIR mode */
+      /* Set for 16 bit CRC and enable MIR */
+      /* Preamble now handled by the chip */
+    case 1152000:
+      pconfig |= 0 << OBOE_PCONFIG_BAUDSHIFT;
+      pconfig |= 8 << OBOE_PCONFIG_WIDTHSHIFT;
+      pconfig |= 1 << OBOE_PCONFIG_PREAMBLESHIFT;
+      config0l = OBOE_CONFIG0L_CRC16 | OBOE_CONFIG0L_ENMIR;
+      break;
+#endif
+      /* FIR mode */
+      /* Set for 32 bit CRC and enable FIR */
+      /* Preamble handled by the chip */
+    case 4000000:
+      pconfig |= 0 << OBOE_PCONFIG_BAUDSHIFT;
+      /* Documentation says 14, but toshiba use 15 in their drivers */
+      pconfig |= 15 << OBOE_PCONFIG_PREAMBLESHIFT;
+      config0l = OBOE_CONFIG0L_ENFIR;
+      break;
+    }
+
+  /* Copy into new PHY config buffer */
+  OUTBP (pconfig >> 8, OBOE_NEW_PCONFIGH);
+  OUTB (pconfig & 0xff, OBOE_NEW_PCONFIGL);
+  OUTB (config0l, OBOE_CONFIG0L);
+
+  /* Now make OBOE copy from new PHY to current PHY */
+  OUTB (0x0, OBOE_ENABLEH);
+  OUTB (OBOE_ENABLEH_PHYANDCLOCK, OBOE_ENABLEH);
+  PROMPT;
+
+  /* speed change executed */
+  self->new_speed = 0;
+  self->io.speed = self->speed;
+}
+
+/*Let the chip look at memory */
+STATIC void
+toshoboe_enablebm (struct toshoboe_cb *self)
+{
+  IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
+  pci_set_master (self->pdev);
+}
+
+/*setup the ring */
+STATIC void
+toshoboe_initring (struct toshoboe_cb *self)
+{
+  int i;
+
+  IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
+
+  for (i = 0; i < TX_SLOTS; ++i)
+    {
+      self->ring->tx[i].len = 0;
+      self->ring->tx[i].control = 0x00;
+      self->ring->tx[i].address = virt_to_bus (self->tx_bufs[i]);
+    }
+
+  for (i = 0; i < RX_SLOTS; ++i)
+    {
+      self->ring->rx[i].len = RX_LEN;
+      self->ring->rx[i].len = 0;
+      self->ring->rx[i].address = virt_to_bus (self->rx_bufs[i]);
+      self->ring->rx[i].control = OBOE_CTL_RX_HW_OWNS;
+    }
+}
+
+STATIC void
+toshoboe_resetptrs (struct toshoboe_cb *self)
+{
+  /* Can reset pointers by twidling DMA */
+  OUTB (0x0, OBOE_ENABLEH);
+  OUTBP (CONFIG0H_DMA_OFF, OBOE_CONFIG0H);
+  OUTB (OBOE_ENABLEH_PHYANDCLOCK, OBOE_ENABLEH);
+
+  self->rxs = inb_p (OBOE_RXSLOT) & OBOE_SLOT_MASK;
+  self->txs = inb_p (OBOE_TXSLOT) & OBOE_SLOT_MASK;
+}
+
+/* Called in locked state */
+STATIC void
+toshoboe_initptrs (struct toshoboe_cb *self)
+{
+
+  /* spin_lock_irqsave(self->spinlock, flags); */
+  /* save_flags (flags); */
+
+  /* Can reset pointers by twidling DMA */
+  toshoboe_resetptrs (self);
+
+  OUTB (0x0, OBOE_ENABLEH);
+  OUTB (CONFIG0H_DMA_ON, OBOE_CONFIG0H);
+  OUTB (OBOE_ENABLEH_PHYANDCLOCK, OBOE_ENABLEH);
+
+  self->txpending = 0;
+
+  /* spin_unlock_irqrestore(self->spinlock, flags); */
+  /* restore_flags (flags); */
+}
+
+/* Wake the chip up and get it looking at the rings */
+/* Called in locked state */
+STATIC void
+toshoboe_startchip (struct toshoboe_cb *self)
+{
+  __u32 physaddr;
+
+  IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
+
+  toshoboe_initring (self);
+  toshoboe_enablebm (self);
+  OUTBP (OBOE_CONFIG1_RESET, OBOE_CONFIG1);
+  OUTBP (OBOE_CONFIG1_ON, OBOE_CONFIG1);
+
+  /* Stop the clocks */
+  OUTB (0, OBOE_ENABLEH);
+
+  /*Set size of rings */
+  OUTB (RING_SIZE, OBOE_RING_SIZE);
+
+  /*Acknoledge any pending interrupts */
+  OUTB (0xff, OBOE_ISR);
+
+  /*Enable ints */
+  OUTB (OBOE_INT_TXDONE  | OBOE_INT_RXDONE |
+        OBOE_INT_TXUNDER | OBOE_INT_RXOVER | OBOE_INT_SIP , OBOE_IER);
+
+  /*Acknoledge any pending interrupts */
+  OUTB (0xff, OBOE_ISR);
+
+  /*Set the maximum packet length to 0xfff (4095) */
+  OUTB (RX_LEN >> 8, OBOE_MAXLENH);
+  OUTB (RX_LEN & 0xff, OBOE_MAXLENL);
+
+  /*Shutdown DMA */
+  OUTB (CONFIG0H_DMA_OFF, OBOE_CONFIG0H);
+
+  /*Find out where the rings live */
+  physaddr = virt_to_bus (self->ring);
+
+  ASSERT ((physaddr & 0x3ff) == 0,
+          printk (KERN_ERR DRIVER_NAME "ring not correctly aligned\n");
+          return;);
+
+  OUTB ((physaddr >> 10) & 0xff, OBOE_RING_BASE0);
+  OUTB ((physaddr >> 18) & 0xff, OBOE_RING_BASE1);
+  OUTB ((physaddr >> 26) & 0x3f, OBOE_RING_BASE2);
+
+  /*Enable DMA controler in byte mode and RX */
+  OUTB (CONFIG0H_DMA_ON, OBOE_CONFIG0H);
+
+  /* Start up the clocks */
+  OUTB (OBOE_ENABLEH_PHYANDCLOCK, OBOE_ENABLEH);
+
+  /*set to sensible speed */
+  self->speed = 9600;
+  toshoboe_setbaud (self);
+  toshoboe_initptrs (self);
+}
+
+STATIC void
+toshoboe_isntstuck (struct toshoboe_cb *self)
+{
+}
+
+STATIC void
+toshoboe_checkstuck (struct toshoboe_cb *self)
+{
+  unsigned long flags;
+
+  if (0)
+    {
+      spin_lock_irqsave(&self->spinlock, flags);
+
+      /* This will reset the chip completely */
+      printk (KERN_ERR DRIVER_NAME ": Resetting chip\n");
+
+      toshoboe_stopchip (self);
+      toshoboe_startchip (self);
+      spin_unlock_irqrestore(&self->spinlock, flags);
+    }
+}
+
+/*Generate packet of about mtt us long */
+STATIC int
+toshoboe_makemttpacket (struct toshoboe_cb *self, void *buf, int mtt)
+{
+  int xbofs;
+
+  xbofs = ((int) (mtt/100)) * (int) (self->speed);
+  xbofs=xbofs/80000; /*Eight bits per byte, and mtt is in us*/
+  xbofs++;
+
+  IRDA_DEBUG (2, DRIVER_NAME 
+      ": generated mtt of %d bytes for %d us at %d baud\n"
+	  , xbofs,mtt,self->speed);
+
+  if (xbofs > TX_LEN)
+    {
+      printk (KERN_ERR DRIVER_NAME ": wanted %d bytes MTT but TX_LEN is %d\n",
+              xbofs, TX_LEN);
+      xbofs = TX_LEN;
+    }
+
+  /*xbofs will do for SIR, MIR and FIR,SIR mode doesn't generate a checksum anyway */
+  memset (buf, XBOF, xbofs);
+
+  return xbofs;
+}
+
+/***********************************************************************/
+/* Probe code */
+
+STATIC void
+toshoboe_dumptx (struct toshoboe_cb *self)
+{
+  int i;
+  PROBE_DEBUG(KERN_WARNING "TX:");
+  for (i = 0; i < RX_SLOTS; ++i)
+    PROBE_DEBUG(" (%d,%02x)",self->ring->tx[i].len,self->ring->tx[i].control);
+  PROBE_DEBUG(" [%d]\n",self->speed);
+}
+
+STATIC void
+toshoboe_dumprx (struct toshoboe_cb *self, int score)
+{
+  int i;
+  PROBE_DEBUG(" %d\nRX:",score);
+  for (i = 0; i < RX_SLOTS; ++i)
+    PROBE_DEBUG(" (%d,%02x)",self->ring->rx[i].len,self->ring->rx[i].control);
+  PROBE_DEBUG("\n");
+}
+
+static inline int
+stuff_byte (__u8 byte, __u8 * buf)
+{
+  switch (byte)
+    {
+    case BOF:                  /* FALLTHROUGH */
+    case EOF:                  /* FALLTHROUGH */
+    case CE:
+      /* Insert transparently coded */
+      buf[0] = CE;              /* Send link escape */
+      buf[1] = byte ^ IRDA_TRANS; /* Complement bit 5 */
+      return 2;
+      /* break; */
+    default:
+      /* Non-special value, no transparency required */
+      buf[0] = byte;
+      return 1;
+      /* break; */
+    }
+}
+
+STATIC int toshoboe_invalid_dev(int irq) 
+{
+  printk (KERN_WARNING DRIVER_NAME ": irq %d for unknown device.\n", irq);
+  return 1;
+}
+
+STATIC void
+toshoboe_probeinterrupt (int irq, void *dev_id, struct pt_regs *regs)
+{
+  struct toshoboe_cb *self = (struct toshoboe_cb *) dev_id;
+  __u8 irqstat;
+
+  if (self == NULL && toshoboe_invalid_dev(irq)) 
+    return;
+
+  irqstat = INB (OBOE_ISR);
+
+/* was it us */
+  if (!(irqstat & OBOE_INT_MASK))
+    return;
+
+/* Ack all the interrupts */
+  OUTB (irqstat, OBOE_ISR);
+
+  if (irqstat & OBOE_INT_TXDONE)
+    {
+      int txp;
+
+      self->int_tx++;
+      PROBE_DEBUG("T");
+
+      txp = INB (OBOE_TXSLOT) & OBOE_SLOT_MASK;
+      if (self->ring->tx[txp].control & OBOE_CTL_TX_HW_OWNS)
+        {
+          self->int_tx+=100;
+          PROBE_DEBUG("S");
+          toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX | OBOE_CONFIG0H_LOOP);
+        }
+    }
+
+  if (irqstat & OBOE_INT_RXDONE) {
+    self->int_rx++;
+    PROBE_DEBUG("R"); }
+  if (irqstat & OBOE_INT_TXUNDER) {
+    self->int_txunder++;
+    PROBE_DEBUG("U"); }
+  if (irqstat & OBOE_INT_RXOVER) {
+    self->int_rxover++;
+    PROBE_DEBUG("O"); }
+  if (irqstat & OBOE_INT_SIP) {
+    self->int_sip++;
+    PROBE_DEBUG("I"); }
+}
+
+STATIC int
+toshoboe_maketestpacket (unsigned char *buf, int badcrc, int fir)
+{
+  int i;
+  int len = 0;
+  union
+  {
+    __u16 value;
+    __u8 bytes[2];
+  }
+  fcs;
+
+  if (fir)
+    {
+      memset (buf, 0, TT_LEN);
+      return (TT_LEN);
+    }
+
+  fcs.value = INIT_FCS;
+
+  memset (buf, XBOF, 10);
+  len += 10;
+  buf[len++] = BOF;
+
+  for (i = 0; i < TT_LEN; ++i)
+    {
+      len += stuff_byte (i, buf + len);
+      fcs.value = irda_fcs (fcs.value, i);
+    }
+
+  len += stuff_byte (fcs.bytes[0] ^ badcrc, buf + len);
+  len += stuff_byte (fcs.bytes[1] ^ badcrc, buf + len);
+  buf[len++] = EOF;
+  len++;
+  return len;
+}
+
+STATIC int
+toshoboe_probefail (struct toshoboe_cb *self, char *msg)
+{
+  printk (KERN_ERR DRIVER_NAME "probe(%d) failed %s\n",self-> speed, msg);
+  toshoboe_dumpregs (self);
+  toshoboe_stopchip (self);
+  free_irq (self->io.irq, (void *) self);
+  return 0;
+}
+
+STATIC int
+toshoboe_numvalidrcvs (struct toshoboe_cb *self)
+{
+  int i, ret = 0;
+  for (i = 0; i < RX_SLOTS; ++i)
+    if ((self->ring->rx[i].control & 0xe0) == 0)
+      ret++;
+
+  return ret;
+}
+
+STATIC int
+toshoboe_numrcvs (struct toshoboe_cb *self)
+{
+  int i, ret = 0;
+  for (i = 0; i < RX_SLOTS; ++i)
+    if (!(self->ring->rx[i].control & OBOE_CTL_RX_HW_OWNS))
+      ret++;
+
+  return ret;
+}
+
+STATIC int
+toshoboe_probe (struct toshoboe_cb *self)
+{
+  int i, j, n;
+#ifdef USE_MIR
+  int bauds[] = { 9600, 115200, 4000000, 1152000 };
+#else
+  int bauds[] = { 9600, 115200, 4000000 };
+#endif
+  unsigned long flags;
+
+  IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
+
+  if (request_irq (self->io.irq, toshoboe_probeinterrupt,
+                   self->io.irqflags, "toshoboe", (void *) self))
+    {
+      printk (KERN_ERR DRIVER_NAME ": probe failed to allocate irq %d\n",
+              self->io.irq);
+      return 0;
+    }
+
+  /* test 1: SIR filter and back to back */
+
+  for (j = 0; j < (sizeof (bauds) / sizeof (int)); ++j)
+    {
+      int fir = (j > 1);
+      toshoboe_stopchip (self);
+
+
+      spin_lock_irqsave(&self->spinlock, flags);
+      /*Address is already setup */
+      toshoboe_startchip (self);
+      self->int_rx = self->int_tx = 0;
+      self->speed = bauds[j];
+      toshoboe_setbaud (self);
+      toshoboe_initptrs (self);
+      spin_unlock_irqrestore(&self->spinlock, flags); 
+
+      self->ring->tx[self->txs].control =
+/*   (FIR only) OBOE_CTL_TX_SIP needed for switching to next slot */
+/*    MIR: all received data is stored in one slot */
+        (fir) ? OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_RTCENTX
+              : OBOE_CTL_TX_HW_OWNS ;
+      self->ring->tx[self->txs].len =
+        toshoboe_maketestpacket (self->tx_bufs[self->txs], 0, fir);
+      self->txs++;
+      self->txs %= TX_SLOTS;
+
+      self->ring->tx[self->txs].control =
+        (fir) ? OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_SIP
+              : OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_RTCENTX ;
+      self->ring->tx[self->txs].len =
+        toshoboe_maketestpacket (self->tx_bufs[self->txs], 0, fir);
+      self->txs++;
+      self->txs %= TX_SLOTS;
+
+      self->ring->tx[self->txs].control = 
+        (fir) ? OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_RTCENTX
+              : OBOE_CTL_TX_HW_OWNS ;
+      self->ring->tx[self->txs].len =
+        toshoboe_maketestpacket (self->tx_bufs[self->txs], 0, fir);
+      self->txs++;
+      self->txs %= TX_SLOTS;
+
+      self->ring->tx[self->txs].control =
+        (fir) ? OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_RTCENTX
+              | OBOE_CTL_TX_SIP     | OBOE_CTL_TX_BAD_CRC
+              : OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_RTCENTX ;
+      self->ring->tx[self->txs].len =
+        toshoboe_maketestpacket (self->tx_bufs[self->txs], 0, fir);
+      self->txs++;
+      self->txs %= TX_SLOTS;
+
+      toshoboe_dumptx (self);
+      /* Turn on TX and RX and loopback */
+      toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX | OBOE_CONFIG0H_LOOP);
+
+      i = 0;
+      n = fir ? 1 : 4;
+      while (toshoboe_numvalidrcvs (self) != n)
+        {
+          if (i > 4800)
+              return toshoboe_probefail (self, "filter test");
+          udelay ((9600*(TT_LEN+16))/self->speed);
+          i++;
+        }
+
+      n = fir ? 203 : 102;
+      while ((toshoboe_numrcvs(self) != self->int_rx) || (self->int_tx != n))
+        {
+          if (i > 4800)
+              return toshoboe_probefail (self, "interrupt test");
+          udelay ((9600*(TT_LEN+16))/self->speed);
+          i++;
+        }
+     toshoboe_dumprx (self,i);
+
+     }
+
+  /* test 2: SIR in char at a time */
+
+  toshoboe_stopchip (self);
+  self->int_rx = self->int_tx = 0;
+
+  spin_lock_irqsave(&self->spinlock, flags);
+  toshoboe_startchip (self);
+  spin_unlock_irqrestore(&self->spinlock, flags);
+
+  self->async = 1;
+  self->speed = 115200;
+  toshoboe_setbaud (self);
+  self->ring->tx[self->txs].control =
+    OBOE_CTL_TX_RTCENTX | OBOE_CTL_TX_HW_OWNS;
+  self->ring->tx[self->txs].len = 4;
+
+  ((unsigned char *) self->tx_bufs[self->txs])[0] = 'f';
+  ((unsigned char *) self->tx_bufs[self->txs])[1] = 'i';
+  ((unsigned char *) self->tx_bufs[self->txs])[2] = 's';
+  ((unsigned char *) self->tx_bufs[self->txs])[3] = 'h';
+  toshoboe_dumptx (self);
+  toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX | OBOE_CONFIG0H_LOOP);
+
+  i = 0;
+  while (toshoboe_numvalidrcvs (self) != 4)
+    {
+      if (i > 100)
+          return toshoboe_probefail (self, "Async test");
+      udelay (100);
+      i++;
+    }
+
+  while ((toshoboe_numrcvs (self) != self->int_rx) || (self->int_tx != 1))
+    {
+      if (i > 100)
+          return toshoboe_probefail (self, "Async interrupt test");
+      udelay (100);
+      i++;
+    }
+  toshoboe_dumprx (self,i);
+
+  self->async = 0;
+  self->speed = 9600;
+  toshoboe_setbaud (self);
+  toshoboe_stopchip (self);
+
+  free_irq (self->io.irq, (void *) self);
+
+  printk (KERN_WARNING DRIVER_NAME ": Self test passed ok\n");
+
+  return 1;
+}
+
+/******************************************************************/
+/* Netdev style code */
+
+/* Transmit something */
+STATIC int
+toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev)
+{
+  struct toshoboe_cb *self;
+  __s32 speed;
+  int mtt, len, ctl;
+  unsigned long flags;
+  struct irda_skb_cb *cb = (struct irda_skb_cb *) skb->cb;
+
+  self = (struct toshoboe_cb *) dev->priv;
+
+  ASSERT (self != NULL, return 0; );
+
+  IRDA_DEBUG (1, "%s.tx:%x(%x)%x\n", __FUNCTION__ 
+      ,skb->len,self->txpending,INB (OBOE_ENABLEH));
+  if (!cb->magic) {
+      IRDA_DEBUG (2, "%s.Not IrLAP:%x\n", __FUNCTION__, cb->magic);
+#ifdef DUMP_PACKETS
+      _dumpbufs(skb->data,skb->len,'>'); 
+#endif
+    }
+
+  /* change speed pending, wait for its execution */
+  if (self->new_speed)
+      return -EBUSY;
+
+  /* device stopped (apm) wait for restart */
+  if (self->stopped)
+      return -EBUSY;
+
+  toshoboe_checkstuck (self);
+
+  /* Check if we need to change the speed */
+  /* But not now. Wait after transmission if mtt not required */
+  speed=irda_get_next_speed(skb);
+  if ((speed != self->io.speed) && (speed != -1))
+    {
+      spin_lock_irqsave(&self->spinlock, flags);
+
+      if (self->txpending || skb->len)
+        {
+          self->new_speed = speed;
+          IRDA_DEBUG (1, "%s: Queued TxDone scheduled speed change %d\n" ,
+		      __FUNCTION__, speed);
+          /* if no data, that's all! */
+          if (!skb->len) 
+            {
+	      spin_unlock_irqrestore(&self->spinlock, flags);
+              dev_kfree_skb (skb);
+              return 0;
+            }
+          /* True packet, go on, but */
+          /* do not accept anything before change speed execution */
+          netif_stop_queue(dev); 
+          /* ready to process TxDone interrupt */
+	  spin_unlock_irqrestore(&self->spinlock, flags);
+        }
+      else
+        { 
+          /* idle and no data, change speed now */
+          self->speed = speed;
+          toshoboe_setbaud (self);
+	  spin_unlock_irqrestore(&self->spinlock, flags);
+          dev_kfree_skb (skb);
+          return 0;
+        }
+
+    }
+
+  if ((mtt = irda_get_mtt(skb)))
+    {
+      /* This is fair since the queue should be empty anyway */
+      spin_lock_irqsave(&self->spinlock, flags);
+
+      if (self->txpending)
+        {
+	  spin_unlock_irqrestore(&self->spinlock, flags);
+          return -EBUSY;
+        }
+
+      /* If in SIR mode we need to generate a string of XBOFs */
+      /* In MIR and FIR we need to generate a string of data */
+      /* which we will add a wrong checksum to */
+
+      mtt = toshoboe_makemttpacket (self, self->tx_bufs[self->txs], mtt);
+      IRDA_DEBUG (1, "%s.mtt:%x(%x)%d\n", __FUNCTION__ 
+          ,skb->len,mtt,self->txpending);
+      if (mtt)
+        {
+          self->ring->tx[self->txs].len = mtt & 0xfff;
+
+          ctl = OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_RTCENTX;
+          if (INB (OBOE_ENABLEH) & OBOE_ENABLEH_FIRON)
+            {
+              ctl |= OBOE_CTL_TX_BAD_CRC | OBOE_CTL_TX_SIP ;
+            }
+#ifdef USE_MIR
+          else if (INB (OBOE_ENABLEH) & OBOE_ENABLEH_MIRON)
+            {
+              ctl |= OBOE_CTL_TX_BAD_CRC;
+            }
+#endif
+          self->ring->tx[self->txs].control = ctl;
+
+          OUTB (0x0, OBOE_ENABLEH);
+          /* It is only a timer. Do not send mtt packet outside! */
+          toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX | OBOE_CONFIG0H_LOOP);
+
+          self->txpending++;
+
+          self->txs++;
+          self->txs %= TX_SLOTS;
+
+        }
+      else
+        {
+          printk(KERN_ERR DRIVER_NAME ": problem with mtt packet - ignored\n");
+        }
+      spin_unlock_irqrestore(&self->spinlock, flags);
+    }
+
+#ifdef DUMP_PACKETS
+dumpbufs(skb->data,skb->len,'>'); 
+#endif
+
+  spin_lock_irqsave(&self->spinlock, flags);
+
+  if (self->ring->tx[self->txs].control & OBOE_CTL_TX_HW_OWNS)
+    {
+      IRDA_DEBUG (0, "%s.ful:%x(%x)%x\n", __FUNCTION__
+          ,skb->len, self->ring->tx[self->txs].control, self->txpending);
+      toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX);
+      spin_unlock_irqrestore(&self->spinlock, flags);
+      return -EBUSY;
+    }
+
+  if (INB (OBOE_ENABLEH) & OBOE_ENABLEH_SIRON)
+    {
+      len = async_wrap_skb (skb, self->tx_bufs[self->txs], TX_BUF_SZ);
+    }
+  else
+    {
+      len = skb->len;
+      memcpy (self->tx_bufs[self->txs], skb->data, len);
+    }
+  self->ring->tx[self->txs].len = len & 0x0fff;
+
+  /*Sometimes the HW doesn't see us assert RTCENTX in the interrupt code */
+  /*later this plays safe, we garuntee the last packet to be transmitted */
+  /*has RTCENTX set */
+
+  ctl = OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_RTCENTX;
+  if (INB (OBOE_ENABLEH) & OBOE_ENABLEH_FIRON)
+    {
+      ctl |= OBOE_CTL_TX_SIP ;
+    }
+  self->ring->tx[self->txs].control = ctl;
+
+  /* If transmitter is idle start in one-shot mode */
+
+  if (!self->txpending)
+      toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX);
+
+  self->txpending++;
+
+  self->txs++;
+  self->txs %= TX_SLOTS;
+
+  spin_unlock_irqrestore(&self->spinlock, flags);
+  dev_kfree_skb (skb);
+
+  return 0;
+}
+
+/*interrupt handler */
+STATIC void
+toshoboe_interrupt (int irq, void *dev_id, struct pt_regs *regs)
+{
+  struct toshoboe_cb *self = (struct toshoboe_cb *) dev_id;
+  __u8 irqstat;
+  struct sk_buff *skb = NULL;
+
+  if (self == NULL && toshoboe_invalid_dev(irq)) 
+    return;
+
+  irqstat = INB (OBOE_ISR);
+
+/* was it us */
+  if (!(irqstat & OBOE_INT_MASK))
+      return;
+
+/* Ack all the interrupts */
+  OUTB (irqstat, OBOE_ISR);
+
+  toshoboe_isntstuck (self);
+
+/* Txdone */
+  if (irqstat & OBOE_INT_TXDONE)
+    {
+      int txp, txpc;
+      int i;
+
+      txp = self->txpending;
+      self->txpending = 0;
+
+      for (i = 0; i < TX_SLOTS; ++i)
+        {
+          if (self->ring->tx[i].control & OBOE_CTL_TX_HW_OWNS)
+              self->txpending++;
+        }
+      IRDA_DEBUG (1, "%s.txd(%x)%x/%x\n", __FUNCTION__
+          ,irqstat,txp,self->txpending);
+
+      txp = INB (OBOE_TXSLOT) & OBOE_SLOT_MASK;
+
+      /* Got anything queued ? start it together */
+      if (self->ring->tx[txp].control & OBOE_CTL_TX_HW_OWNS)
+        {
+          txpc = txp;
+#ifdef OPTIMIZE_TX
+          while (self->ring->tx[txpc].control & OBOE_CTL_TX_HW_OWNS)
+            {
+              txp = txpc;
+              txpc++;
+              txpc %= TX_SLOTS;
+              self->stats.tx_packets++;
+              if (self->ring->tx[txpc].control & OBOE_CTL_TX_HW_OWNS)
+                  self->ring->tx[txp].control &= ~OBOE_CTL_TX_RTCENTX;
+            }
+          self->stats.tx_packets--;
+#else
+          self->stats.tx_packets++;
+#endif
+          toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX);
+        }
+
+      if ((!self->txpending) && (self->new_speed))
+        {
+          self->speed = self->new_speed;
+          IRDA_DEBUG (1, "%s: Executed TxDone scheduled speed change %d\n",
+		      __FUNCTION__, self->speed);
+          toshoboe_setbaud (self);
+        }
+
+      /* Tell network layer that we want more frames */
+      if (!self->new_speed)
+          netif_wake_queue(self->netdev);
+    }
+
+  if (irqstat & OBOE_INT_RXDONE)
+    {
+      while (!(self->ring->rx[self->rxs].control & OBOE_CTL_RX_HW_OWNS))
+        {
+          int len = self->ring->rx[self->rxs].len;
+          skb = NULL;
+          IRDA_DEBUG (3, "%s.rcv:%x(%x)\n", __FUNCTION__ 
+		      ,len,self->ring->rx[self->rxs].control);
+
+#ifdef DUMP_PACKETS
+dumpbufs(self->rx_bufs[self->rxs],len,'<');
+#endif
+
+          if (self->ring->rx[self->rxs].control == 0)
+            {
+              __u8 enable = INB (OBOE_ENABLEH);
+
+              /* In SIR mode we need to check the CRC as this */
+              /* hasn't been done by the hardware */
+              if (enable & OBOE_ENABLEH_SIRON)
+                {
+                  if (!toshoboe_checkfcs (self->rx_bufs[self->rxs], len))
+                      len = 0;
+                  /*Trim off the CRC */
+                  if (len > 1)
+                      len -= 2;
+                  else
+                      len = 0;
+                  IRDA_DEBUG (1, "%s.SIR:%x(%x)\n", __FUNCTION__, len,enable);
+                }
+
+#ifdef USE_MIR
+              else if (enable & OBOE_ENABLEH_MIRON)
+                {
+                  if (len > 1)
+                      len -= 2;
+                  else
+                      len = 0;
+                  IRDA_DEBUG (2, "%s.MIR:%x(%x)\n", __FUNCTION__, len,enable);
+                }
+#endif
+              else if (enable & OBOE_ENABLEH_FIRON)
+                {
+                  if (len > 3)
+                      len -= 4;   /*FIXME: check this */
+                  else
+                      len = 0;
+                  IRDA_DEBUG (1, "%s.FIR:%x(%x)\n", __FUNCTION__, len,enable);
+                }
+              else 
+                  IRDA_DEBUG (0, "%s.?IR:%x(%x)\n", __FUNCTION__, len,enable);
+
+              if (len)
+                {
+                  skb = dev_alloc_skb (len + 1);
+                  if (skb)
+                    {
+                      skb_reserve (skb, 1);
+
+                      skb_put (skb, len);
+                      memcpy (skb->data, self->rx_bufs[self->rxs], len);
+
+                      self->stats.rx_packets++;
+                      skb->dev = self->netdev;
+                      skb->mac.raw = skb->data;
+                      skb->protocol = htons (ETH_P_IRDA);
+                    }
+                  else
+                    {
+                      printk (KERN_INFO 
+                              "%s(), memory squeeze, dropping frame.\n",
+			      __FUNCTION__);
+                    }
+                }
+            }
+          else 
+            {
+            /* TODO: =========================================== */
+            /*  if OBOE_CTL_RX_LENGTH, our buffers are too small */
+            /* (MIR or FIR) data is lost. */
+            /* (SIR) data is splitted in several slots. */
+            /* we have to join all the received buffers received */
+            /*in a large buffer before checking CRC. */
+            IRDA_DEBUG (0, "%s.err:%x(%x)\n", __FUNCTION__
+                ,len,self->ring->rx[self->rxs].control);
+            }
+
+          self->ring->rx[self->rxs].len = 0x0;
+          self->ring->rx[self->rxs].control = OBOE_CTL_RX_HW_OWNS;
+
+          self->rxs++;
+          self->rxs %= RX_SLOTS;
+
+          if (skb)
+              netif_rx (skb);
+
+        }
+    }
+
+  if (irqstat & OBOE_INT_TXUNDER)
+    {
+      printk (KERN_WARNING DRIVER_NAME ": tx fifo underflow\n");
+    }
+  if (irqstat & OBOE_INT_RXOVER)
+    {
+      printk (KERN_WARNING DRIVER_NAME ": rx fifo overflow\n");
+    }
+/* This must be useful for something... */
+  if (irqstat & OBOE_INT_SIP)
+    {
+      self->int_sip++;
+      IRDA_DEBUG (1, "%s.sip:%x(%x)%x\n", __FUNCTION__
+	      ,self->int_sip,irqstat,self->txpending);
+    }
+}
+
+STATIC int
+toshoboe_net_init (struct net_device *dev)
+{
+  IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
+
+  /* Setup to be a normal IrDA network device driver */
+  irda_device_setup (dev);
+
+  /* Insert overrides below this line! */
+  return 0;
+}
+
+STATIC int
+toshoboe_net_open (struct net_device *dev)
+{
+  struct toshoboe_cb *self;
+  unsigned long flags;
+
+  IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
+
+  ASSERT (dev != NULL, return -1; );
+  self = (struct toshoboe_cb *) dev->priv;
+
+  ASSERT (self != NULL, return 0; );
+
+  if (self->async)
+    return -EBUSY;
+
+  if (self->stopped)
+    return 0;
+
+  if (request_irq (self->io.irq, toshoboe_interrupt,
+                   SA_SHIRQ | SA_INTERRUPT, dev->name, (void *) self))
+    {
+      return -EAGAIN;
+    }
+
+  spin_lock_irqsave(&self->spinlock, flags);
+  toshoboe_startchip (self);
+  spin_unlock_irqrestore(&self->spinlock, flags);
+
+  /* Ready to play! */
+  netif_start_queue(dev);
+
+  /*
+   * Open new IrLAP layer instance, now that everything should be
+   * initialized properly
+   */
+  self->irlap = irlap_open (dev, &self->qos, driver_name);
+
+  self->irdad = 1;
+
+  MOD_INC_USE_COUNT;
+
+  return 0;
+}
+
+STATIC int
+toshoboe_net_close (struct net_device *dev)
+{
+  struct toshoboe_cb *self;
+
+  IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
+
+  ASSERT (dev != NULL, return -1; );
+  self = (struct toshoboe_cb *) dev->priv;
+
+  /* Stop device */
+  netif_stop_queue(dev);
+
+  /* Stop and remove instance of IrLAP */
+  if (self->irlap)
+    irlap_close (self->irlap);
+  self->irlap = NULL;
+
+  self->irdad = 0;
+
+  free_irq (self->io.irq, (void *) self);
+
+  if (!self->stopped)
+    {
+      toshoboe_stopchip (self);
+    }
+
+  MOD_DEC_USE_COUNT;
+
+  return 0;
+}
+
+/*
+ * Function toshoboe_net_ioctl (dev, rq, cmd)
+ *
+ *    Process IOCTL commands for this device
+ *
+ */
+STATIC int
+toshoboe_net_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
+{
+  struct if_irda_req *irq = (struct if_irda_req *) rq;
+  struct toshoboe_cb *self;
+  unsigned long flags;
+  int ret = 0;
+
+  ASSERT (dev != NULL, return -1; );
+
+  self = dev->priv;
+
+  ASSERT (self != NULL, return -1; );
+
+  IRDA_DEBUG (5, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd);
+
+  /* Disable interrupts & save flags */
+  spin_lock_irqsave(&self->spinlock, flags);
+
+  switch (cmd)
+    {
+    case SIOCSBANDWIDTH:       /* Set bandwidth */
+      /* This function will also be used by IrLAP to change the
+       * speed, so we still must allow for speed change within
+       * interrupt context.
+       */
+      IRDA_DEBUG (1, "%s(BANDWIDTH), %s, (%X/%ld\n", __FUNCTION__
+          ,dev->name, INB (OBOE_STATUS), irq->ifr_baudrate );
+      if (!in_interrupt () && !capable (CAP_NET_ADMIN))
+        return -EPERM;
+
+      /* self->speed=irq->ifr_baudrate; */
+      /* toshoboe_setbaud(self); */
+      /* Just change speed once - inserted by Paul Bristow */
+      self->new_speed = irq->ifr_baudrate;
+      break;
+    case SIOCSMEDIABUSY:       /* Set media busy */
+      IRDA_DEBUG (1, "%s(MEDIABUSY), %s, (%X/%x)\n", __FUNCTION__
+          ,dev->name, INB (OBOE_STATUS), capable (CAP_NET_ADMIN) );
+      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 */
+      irq->ifr_receiving = (INB (OBOE_STATUS) & OBOE_STATUS_RXBUSY) ? 1 : 0;
+      IRDA_DEBUG (3, "%s(RECEIVING), %s, (%X/%x)\n", __FUNCTION__
+          ,dev->name, INB (OBOE_STATUS), irq->ifr_receiving );
+      break;
+    default:
+      IRDA_DEBUG (1, "%s(?), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd);
+      ret = -EOPNOTSUPP;
+    }
+
+  spin_unlock_irqrestore(&self->spinlock, flags);
+  return ret;
+
+}
+
+MODULE_DESCRIPTION("Toshiba OBOE IrDA Device Driver");
+MODULE_AUTHOR("James McKenzie <james@fishsoup.dhs.org>");
+MODULE_LICENSE("GPL");
+
+MODULE_PARM (max_baud, "i");
+MODULE_PARM_DESC(max_baud, "Maximum baud rate");
+
+MODULE_PARM (do_probe, "i");
+MODULE_PARM_DESC(do_probe, "Enable/disable chip probing and self-test");
+
+STATIC void
+toshoboe_close (struct pci_dev *pci_dev)
+{
+  int i;
+  struct toshoboe_cb *self = (struct toshoboe_cb*)pci_get_drvdata(pci_dev);
+
+  IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
+
+  ASSERT (self != NULL, return; );
+
+  if (!self->stopped)
+    {
+      toshoboe_stopchip (self);
+    }
+
+  release_region (self->io.fir_base, self->io.fir_ext);
+
+  for (i = 0; i < TX_SLOTS; ++i)
+    {
+      kfree (self->tx_bufs[i]);
+      self->tx_bufs[i] = NULL;
+    }
+
+  for (i = 0; i < RX_SLOTS; ++i)
+    {
+      kfree (self->rx_bufs[i]);
+      self->rx_bufs[i] = NULL;
+    }
+
+  if (self->netdev)
+    {
+      /* Remove netdevice */
+      rtnl_lock ();
+      unregister_netdevice (self->netdev);
+      rtnl_unlock ();
+    }
+
+  kfree (self->ringbuf);
+  self->ringbuf = NULL;
+  self->ring = NULL;
+
+  return;
+}
+
+STATIC int
+toshoboe_open (struct pci_dev *pci_dev, const struct pci_device_id *pdid)
+{
+  struct toshoboe_cb *self;
+  struct net_device *dev;
+  int i = 0;
+  int ok = 0;
+  int err;
+
+  IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
+
+  if ((err=pci_enable_device(pci_dev)))
+    return err;
+
+  self = kmalloc (sizeof (struct toshoboe_cb), GFP_KERNEL);
+
+  if (self == NULL)
+    {
+      printk (KERN_ERR DRIVER_NAME ": can't allocate memory for "
+              "IrDA control block\n");
+      return -ENOMEM;
+    }
+
+  memset (self, 0, sizeof (struct toshoboe_cb));
+
+  self->pdev = pci_dev;
+  self->base = pci_resource_start(pci_dev,0);
+
+  self->io.fir_base = self->base;
+  self->io.fir_ext = OBOE_IO_EXTENT;
+  self->io.irq = pci_dev->irq;
+  self->io.irqflags = SA_SHIRQ | SA_INTERRUPT;
+
+  self->speed = self->io.speed = 9600;
+  self->async = 0;
+
+  /* Lock the port that we need */
+  if (NULL==request_region (self->io.fir_base, self->io.fir_ext, driver_name))
+    {
+      printk (KERN_ERR DRIVER_NAME ": can't get iobase of 0x%03x\n"
+	      ,self->io.fir_base);
+      err = -EBUSY;
+      goto freeself;
+    }
+
+  spin_lock_init(&self->spinlock);
+  
+  irda_init_max_qos_capabilies (&self->qos);
+  self->qos.baud_rate.bits = 0;
+
+  if (max_baud >= 2400)
+    self->qos.baud_rate.bits |= IR_2400;
+  /*if (max_baud>=4800) idev->qos.baud_rate.bits|=IR_4800; */
+  if (max_baud >= 9600)
+    self->qos.baud_rate.bits |= IR_9600;
+  if (max_baud >= 19200)
+    self->qos.baud_rate.bits |= IR_19200;
+  if (max_baud >= 115200)
+    self->qos.baud_rate.bits |= IR_115200;
+#ifdef USE_MIR
+  if (max_baud >= 1152000)
+    {
+      self->qos.baud_rate.bits |= IR_1152000;
+      self->flags |= IFF_MIR;
+    }
+#endif
+  if (max_baud >= 4000000)
+    {
+      self->qos.baud_rate.bits |= (IR_4000000 << 8);
+      self->flags |= IFF_FIR;
+    }
+
+  /*FIXME: work this out... */
+  self->qos.min_turn_time.bits = 0xff;
+
+  irda_qos_bits_to_value (&self->qos);
+
+  self->flags = IFF_SIR | IFF_DMA | IFF_PIO;
+
+  /* Allocate twice the size to guarantee alignment */
+  self->ringbuf = (void *) kmalloc (OBOE_RING_LEN << 1, GFP_KERNEL);
+  if (!self->ringbuf)
+    {
+      printk (KERN_ERR DRIVER_NAME ": can't allocate DMA buffers\n");
+      err = -ENOMEM;
+      goto freeregion;
+    }
+
+  /*We need to align the taskfile on a taskfile size boundary */
+  {
+    __u32 addr;
+
+    addr = (__u32) self->ringbuf;
+    addr &= ~(OBOE_RING_LEN - 1);
+    addr += OBOE_RING_LEN;
+    self->ring = (struct OboeRing *) addr;
+  }
+
+  memset (self->ring, 0, OBOE_RING_LEN);
+  self->io.mem_base = (__u32) self->ring;
+
+  ok = 1;
+  for (i = 0; i < TX_SLOTS; ++i)
+    {
+      self->tx_bufs[i] = kmalloc (TX_BUF_SZ, GFP_KERNEL);
+      if (!self->tx_bufs[i])
+        ok = 0;
+    }
+
+  for (i = 0; i < RX_SLOTS; ++i)
+    {
+      self->rx_bufs[i] = kmalloc (RX_BUF_SZ, GFP_KERNEL);
+      if (!self->rx_bufs[i])
+        ok = 0;
+    }
+
+  if (!ok)
+    {
+      printk (KERN_ERR DRIVER_NAME ": can't allocate rx/tx buffers\n");
+      err = -ENOMEM;
+      goto freebufs;
+    }
+
+  if (do_probe)
+    if (!toshoboe_probe (self))
+      {
+        err = -ENODEV;
+        goto freebufs;
+      }
+
+  if (!(dev = dev_alloc ("irda%d", &err)))
+    {
+      printk (KERN_ERR DRIVER_NAME ": dev_alloc() failed\n");
+      err = -ENOMEM;
+      goto freebufs;
+    }
+
+  dev->priv = (void *) self;
+  self->netdev = dev;
+
+  printk (KERN_INFO "IrDA: Registered device %s\n", dev->name);
+
+  dev->init = toshoboe_net_init;
+  dev->hard_start_xmit = toshoboe_hard_xmit;
+  dev->open = toshoboe_net_open;
+  dev->stop = toshoboe_net_close;
+  dev->do_ioctl = toshoboe_net_ioctl;
+
+  rtnl_lock ();
+  err = register_netdevice (dev);
+  rtnl_unlock ();
+  if (err)
+    {
+      printk (KERN_ERR DRIVER_NAME ": register_netdev() failed\n");
+      err = -ENOMEM;
+      goto freebufs;
+    }
+
+  pci_set_drvdata(pci_dev,self);
+
+  printk (KERN_INFO DRIVER_NAME ": Using multiple tasks, version %s\n", rcsid);
+
+  return 0;
+
+freebufs:
+  for (i = 0; i < TX_SLOTS; ++i)
+    if (self->tx_bufs[i])
+      kfree (self->tx_bufs[i]);
+  for (i = 0; i < RX_SLOTS; ++i)
+    if (self->rx_bufs[i])
+      kfree (self->rx_bufs[i]);
+  kfree(self->ringbuf);
+
+freeregion:
+  release_region (self->io.fir_base, self->io.fir_ext);
+
+freeself:
+  kfree (self);
+
+  return err;
+}
+
+STATIC int
+toshoboe_gotosleep (struct pci_dev *pci_dev, u32 crap)
+{
+  struct toshoboe_cb *self = (struct toshoboe_cb*)pci_get_drvdata(pci_dev);
+  unsigned long flags;
+  int i = 10;
+
+  IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
+
+  if (!self || self->stopped)
+    return 0;
+
+  if ((!self->irdad) && (!self->async))
+    return 0;
+
+/* Flush all packets */
+  while ((i--) && (self->txpending))
+    udelay (10000);
+
+  spin_lock_irqsave(&self->spinlock, flags);
+
+  toshoboe_stopchip (self);
+  self->stopped = 1;
+  self->txpending = 0;
+
+  spin_unlock_irqrestore(&self->spinlock, flags);
+  return 0;
+}
+
+STATIC int
+toshoboe_wakeup (struct pci_dev *pci_dev)
+{
+  struct toshoboe_cb *self = (struct toshoboe_cb*)pci_get_drvdata(pci_dev);
+  unsigned long flags;
+
+  IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
+
+  if (!self || !self->stopped)
+    return 0;
+
+  if ((!self->irdad) && (!self->async))
+    return 0;
+
+  spin_lock_irqsave(&self->spinlock, flags);
+
+  toshoboe_startchip (self);
+  self->stopped = 0;
+
+  netif_wake_queue(self->netdev);
+  spin_unlock_irqrestore(&self->spinlock, flags);
+  return 0;
+}
+
+static struct pci_driver donauboe_pci_driver = {
+	.name		= "donauboe",
+	.id_table	= toshoboe_pci_tbl,
+	.probe		= toshoboe_open,
+	.remove		= toshoboe_close,
+	.suspend	= toshoboe_gotosleep,
+	.resume		= toshoboe_wakeup 
+};
+
+static int __init
+donauboe_init (void)
+{
+  return pci_module_init(&donauboe_pci_driver);
+}
+
+static void __exit
+donauboe_cleanup (void)
+{
+  pci_unregister_driver(&donauboe_pci_driver);
+}
+
+module_init(donauboe_init);
+module_exit(donauboe_cleanup);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/irda/donauboe.h linux-2.4.21-pre6/drivers/net/irda/donauboe.h
--- linux-2.4.20/drivers/net/irda/donauboe.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/irda/donauboe.h	2003-03-26 23:49:55.000000000 +0000
@@ -0,0 +1,363 @@
+/*********************************************************************
+ *                
+ * Filename:      toshoboe.h
+ * Version:       2.16
+ * Description:   Driver for the Toshiba OBOE (or type-O or 701)
+ *                FIR Chipset, also supports the DONAUOBOE (type-DO
+ *                or d01) FIR chipset which as far as I know is
+ *                register compatible.
+ * Status:        Experimental.
+ * Author:        James McKenzie <james@fishsoup.dhs.org>
+ * Created at:    Sat May 8  12:35:27 1999
+ * Modified: 2.16 Martin Lucina <mato@kotelna.sk>
+ * Modified: 2.16 Sat Jun 22 18:54:29 2002 (sync headers)
+ * Modified: 2.17 Christian Gennerat <christian.gennerat@polytechnique.org>
+ * Modified: 2.17 jeu sep 12 08:50:20 2002 (add lock to be used by spinlocks)
+ * 
+ *     Copyright (c) 1999 James McKenzie, 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 James McKenzie nor Cambridge University admit liability nor
+ *     provide warranty for any of this software. This material is 
+ *     provided "AS-IS" and at no charge.
+ * 
+ *     Applicable Models : Libretto 100/110CT and many more.
+ *     Toshiba refers to this chip as the type-O IR port,
+ *     or the type-DO IR port.
+ *
+ * IrDA chip set list from Toshiba Computer Engineering Corp.
+ * model			method	maker	controler		Version 
+ * Portege 320CT	FIR,SIR Toshiba Oboe(Triangle) 
+ * Portege 3010CT	FIR,SIR Toshiba Oboe(Sydney) 
+ * Portege 3015CT	FIR,SIR Toshiba Oboe(Sydney) 
+ * Portege 3020CT	FIR,SIR Toshiba Oboe(Sydney) 
+ * Portege 7020CT	FIR,SIR ?		?
+ * 
+ * Satell. 4090XCDT	FIR,SIR ?		?
+ * 
+ * Libretto 100CT	FIR,SIR Toshiba Oboe 
+ * Libretto 1000CT	FIR,SIR Toshiba Oboe 
+ * 
+ * TECRA750DVD		FIR,SIR Toshiba Oboe(Triangle)	REV ID=14h 
+ * TECRA780			FIR,SIR Toshiba Oboe(Sandlot)	REV ID=32h,33h 
+ * TECRA750CDT		FIR,SIR Toshiba Oboe(Triangle)	REV ID=13h,14h 
+ * TECRA8000		FIR,SIR Toshiba Oboe(ISKUR)		REV ID=23h 
+ * 
+ ********************************************************************/
+
+/* The documentation for this chip is allegedly released         */
+/* However I have not seen it, not have I managed to contact     */
+/* anyone who has. HOWEVER the chip bears a striking resemblence */
+/* to the IrDA controller in the Toshiba RISC TMPR3922 chip      */
+/* the documentation for this is freely available at             */
+/* http://www.toshiba.com/taec/components/Generic/TMPR3922.shtml */
+/* The mapping between the registers in that document and the    */
+/* Registers in the 701 oboe chip are as follows    */
+
+
+/* 3922 reg     701 regs, by bit numbers                        */
+/*               7- 0  15- 8  24-16  31-25                      */
+/* $28            0x0    0x1                                    */
+/* $2c                                     SEE NOTE 1           */
+/* $30            0x6    0x7                                    */
+/* $34            0x8    0x9               SEE NOTE 2           */
+/* $38           0x10   0x11                                    */
+/* $3C                   0xe               SEE NOTE 3           */
+/* $40           0x12   0x13                                    */
+/* $44           0x14   0x15                                    */
+/* $48           0x16   0x17                                    */
+/* $4c           0x18   0x19                                    */
+/* $50           0x1a   0x1b                                    */
+
+/* FIXME: could be 0x1b 0x1a here */
+
+/* $54           0x1d   0x1c                                    */
+/* $5C           0xf                       SEE NOTE 4           */
+/* $130                                    SEE NOTE 5           */
+/* $134                                    SEE NOTE 6           */
+/*                                                              */
+/* NOTES:                                                       */
+/* 1. The pointer to ring is packed in most unceremoniusly      */
+/*    701 Register      Address bits    (A9-A0 must be zero)    */
+/*            0x4:      A17 A16 A15 A14 A13 A12 A11 A10         */
+/*            0x5:      A25 A24 A23 A22 A21 A20 A19 A18         */
+/*            0x2:        0   0 A31 A30 A29 A28 A27 A26         */
+/*                                                              */
+/* 2. The M$ drivers do a write 0x1 to 0x9, however the 3922    */
+/*    documentation would suggest that a write of 0x1 to 0x8    */
+/*    would be more appropriate.                                */
+/*                                                              */
+/* 3. This assignment is tenuous at best, register 0xe seems to */
+/*    have bits arranged 0 0 0 R/W R/W R/W R/W R/W              */
+/*    if either of the lower two bits are set the chip seems to */
+/*    switch off                                                */
+/*                                                              */
+/* 4. Bits 7-4 seem to be different 4 seems just to be generic  */
+/*    receiver busy flag                                        */
+/*                                                              */
+/* 5. and 6. The IER and ISR have a different bit assignment    */
+/*    The lower three bits of both read back as ones            */
+/* ISR is register 0xc, IER is register 0xd                     */
+/*           7      6      5      4      3      2      1      0 */
+/* 0xc: TxDone RxDone TxUndr RxOver SipRcv      1      1      1 */
+/* 0xd: TxDone RxDone TxUndr RxOver SipRcv      1      1      1 */
+/* TxDone xmitt done (generated only if generate interrupt bit  */
+/*   is set in the ring)                                        */
+/* RxDone recv completed (or other recv condition if you set it */
+/*   up                                                         */
+/* TxUnder underflow in Transmit FIFO                           */
+/* RxOver  overflow in Recv FIFO                                */
+/* SipRcv  received serial gap  (or other condition you set)    */
+/* Interrupts are enabled by writing a one to the IER register  */
+/* Interrupts are cleared by writting a one to the ISR register */
+/*                                                              */
+/* 6. The remaining registers: 0x6 and 0x3 appear to be         */
+/*    reserved parts of 16 or 32 bit registersthe remainder     */
+/*    0xa 0xb 0x1e 0x1f could possibly be (by their behaviour)  */
+/*    the Unicast Filter register at $58.                       */
+/*                                                              */
+/* 7. While the core obviously expects 32 bit accesses all the  */
+/*    M$ drivers do 8 bit accesses, infact the Miniport ones    */
+/*    write and read back the byte serveral times (why?)        */
+
+
+#ifndef TOSHOBOE_H
+#define TOSHOBOE_H
+
+/* Registers */
+
+#define OBOE_IO_EXTENT	0x1f
+
+/*Receive and transmit slot pointers */
+#define OBOE_REG(i)	(i+(self->base))
+#define OBOE_RXSLOT	OBOE_REG(0x0)
+#define OBOE_TXSLOT	OBOE_REG(0x1)
+#define OBOE_SLOT_MASK	0x3f
+
+#define OBOE_TXRING_OFFSET		0x200
+#define OBOE_TXRING_OFFSET_IN_SLOTS	0x40
+
+/*pointer to the ring */
+#define OBOE_RING_BASE0	OBOE_REG(0x4)
+#define OBOE_RING_BASE1	OBOE_REG(0x5)
+#define OBOE_RING_BASE2	OBOE_REG(0x2)
+#define OBOE_RING_BASE3	OBOE_REG(0x3)
+
+/*Number of slots in the ring */
+#define OBOE_RING_SIZE  OBOE_REG(0x7)
+#define OBOE_RING_SIZE_RX4	0x00
+#define OBOE_RING_SIZE_RX8	0x01
+#define OBOE_RING_SIZE_RX16	0x03
+#define OBOE_RING_SIZE_RX32	0x07
+#define OBOE_RING_SIZE_RX64	0x0f
+#define OBOE_RING_SIZE_TX4	0x00
+#define OBOE_RING_SIZE_TX8	0x10
+#define OBOE_RING_SIZE_TX16	0x30
+#define OBOE_RING_SIZE_TX32	0x70
+#define OBOE_RING_SIZE_TX64	0xf0
+
+#define OBOE_RING_MAX_SIZE	64
+
+/*Causes the gubbins to re-examine the ring */
+#define OBOE_PROMPT	OBOE_REG(0x9)
+#define OBOE_PROMPT_BIT		0x1
+
+/* Interrupt Status Register */
+#define OBOE_ISR	OBOE_REG(0xc)
+/* Interrupt Enable Register */
+#define OBOE_IER	OBOE_REG(0xd)
+/* Interrupt bits for IER and ISR */
+#define OBOE_INT_TXDONE		0x80
+#define OBOE_INT_RXDONE		0x40
+#define OBOE_INT_TXUNDER	0x20
+#define OBOE_INT_RXOVER		0x10
+#define OBOE_INT_SIP		0x08
+#define OBOE_INT_MASK		0xf8
+
+/*Reset Register */
+#define OBOE_CONFIG1	OBOE_REG(0xe)
+#define OBOE_CONFIG1_RST	0x01
+#define OBOE_CONFIG1_DISABLE	0x02
+#define OBOE_CONFIG1_4		0x08
+#define OBOE_CONFIG1_8		0x08
+
+#define OBOE_CONFIG1_ON		0x8
+#define OBOE_CONFIG1_RESET	0xf
+#define OBOE_CONFIG1_OFF	0xe
+
+#define OBOE_STATUS	OBOE_REG(0xf)
+#define OBOE_STATUS_RXBUSY	0x10
+#define OBOE_STATUS_FIRRX	0x04
+#define OBOE_STATUS_MIRRX	0x02
+#define OBOE_STATUS_SIRRX	0x01
+
+
+/*Speed control registers */
+#define OBOE_CONFIG0L	OBOE_REG(0x10)
+#define OBOE_CONFIG0H	OBOE_REG(0x11)
+
+#define OBOE_CONFIG0H_TXONLOOP  0x80 /*Transmit when looping (dangerous) */
+#define OBOE_CONFIG0H_LOOP	0x40 /*Loopback Tx->Rx */
+#define OBOE_CONFIG0H_ENTX	0x10 /*Enable Tx */
+#define OBOE_CONFIG0H_ENRX	0x08 /*Enable Rx */
+#define OBOE_CONFIG0H_ENDMAC	0x04 /*Enable/reset* the DMA controller */
+#define OBOE_CONFIG0H_RCVANY	0x02 /*DMA mode 1=bytes, 0=dwords */
+
+#define OBOE_CONFIG0L_CRC16	0x80 /*CRC 1=16 bit 0=32 bit */
+#define OBOE_CONFIG0L_ENFIR	0x40 /*Enable FIR */
+#define OBOE_CONFIG0L_ENMIR	0x20 /*Enable MIR */
+#define OBOE_CONFIG0L_ENSIR	0x10 /*Enable SIR */
+#define OBOE_CONFIG0L_ENSIRF	0x08 /*Enable SIR framer */
+#define OBOE_CONFIG0L_SIRTEST	0x04 /*Enable SIR framer in MIR and FIR */
+#define OBOE_CONFIG0L_INVERTTX  0x02 /*Invert Tx Line */
+#define OBOE_CONFIG0L_INVERTRX  0x01 /*Invert Rx Line */
+
+#define OBOE_BOF	OBOE_REG(0x12)
+#define OBOE_EOF	OBOE_REG(0x13)
+
+#define OBOE_ENABLEL	OBOE_REG(0x14)
+#define OBOE_ENABLEH	OBOE_REG(0x15)
+
+#define OBOE_ENABLEH_PHYANDCLOCK	0x80 /*Toggle low to copy config in */
+#define OBOE_ENABLEH_CONFIGERR		0x40
+#define OBOE_ENABLEH_FIRON		0x20
+#define OBOE_ENABLEH_MIRON		0x10
+#define OBOE_ENABLEH_SIRON		0x08
+#define OBOE_ENABLEH_ENTX		0x04
+#define OBOE_ENABLEH_ENRX		0x02
+#define OBOE_ENABLEH_CRC16		0x01
+
+#define OBOE_ENABLEL_BROADCAST		0x01
+
+#define OBOE_CURR_PCONFIGL		OBOE_REG(0x16) /*Current config */
+#define OBOE_CURR_PCONFIGH		OBOE_REG(0x17)
+
+#define OBOE_NEW_PCONFIGL		OBOE_REG(0x18)
+#define OBOE_NEW_PCONFIGH		OBOE_REG(0x19)
+
+#define OBOE_PCONFIGH_BAUDMASK		0xfc
+#define OBOE_PCONFIGH_WIDTHMASK		0x04
+#define OBOE_PCONFIGL_WIDTHMASK		0xe0
+#define OBOE_PCONFIGL_PREAMBLEMASK	0x1f
+
+#define OBOE_PCONFIG_BAUDMASK		0xfc00
+#define OBOE_PCONFIG_BAUDSHIFT		10
+#define OBOE_PCONFIG_WIDTHMASK		0x04e0
+#define OBOE_PCONFIG_WIDTHSHIFT		5
+#define OBOE_PCONFIG_PREAMBLEMASK	0x001f
+#define OBOE_PCONFIG_PREAMBLESHIFT	0
+
+#define OBOE_MAXLENL			OBOE_REG(0x1a)
+#define OBOE_MAXLENH			OBOE_REG(0x1b)
+
+#define OBOE_RXCOUNTH			OBOE_REG(0x1c) /*Reset on recipt */
+#define OBOE_RXCOUNTL			OBOE_REG(0x1d) /*of whole packet */
+
+/* The PCI ID of the OBOE chip */
+#ifndef PCI_DEVICE_ID_FIR701
+#define PCI_DEVICE_ID_FIR701 	0x0701
+#endif
+
+#ifndef PCI_DEVICE_ID_FIRD01
+#define PCI_DEVICE_ID_FIRD01 	0x0d01
+#endif
+
+struct OboeSlot
+{
+  __u16 len;                    /*Tweleve bits of packet length */
+  __u8 unused;
+  __u8 control;                 /*Slot control/status see below */
+  __u32 address;                /*Slot buffer address */
+}
+__attribute__ ((packed));
+
+#define OBOE_NTASKS OBOE_TXRING_OFFSET_IN_SLOTS
+
+struct OboeRing
+{
+  struct OboeSlot rx[OBOE_NTASKS];
+  struct OboeSlot tx[OBOE_NTASKS];
+};
+
+#define OBOE_RING_LEN (sizeof(struct OboeRing))
+
+
+#define OBOE_CTL_TX_HW_OWNS	0x80 /*W/R This slot owned by the hardware */
+#define OBOE_CTL_TX_DISTX_CRC	0x40 /*W Disable CRC generation for [FM]IR */
+#define OBOE_CTL_TX_BAD_CRC     0x20 /*W Generate bad CRC */
+#define OBOE_CTL_TX_SIP		0x10   /*W Generate an SIP after xmittion */
+#define OBOE_CTL_TX_MKUNDER	0x08 /*W Generate an underrun error */
+#define OBOE_CTL_TX_RTCENTX	0x04 /*W Enable receiver and generate TXdone */
+     /*  After this slot is processed        */
+#define OBOE_CTL_TX_UNDER	0x01  /*R Set by hardware to indicate underrun */
+
+
+#define OBOE_CTL_RX_HW_OWNS	0x80 /*W/R This slot owned by hardware */
+#define OBOE_CTL_RX_PHYERR	0x40 /*R Decoder error on receiption */
+#define OBOE_CTL_RX_CRCERR	0x20 /*R CRC error only set for [FM]IR */
+#define OBOE_CTL_RX_LENGTH	0x10 /*R Packet > max Rx length  */
+#define OBOE_CTL_RX_OVER	0x08   /*R set to indicate an overflow */
+#define OBOE_CTL_RX_SIRBAD	0x04 /*R SIR had BOF in packet or ABORT sequence */
+#define OBOE_CTL_RX_RXEOF	0x02  /*R Finished receiving on this slot */
+
+
+struct toshoboe_cb
+{
+  struct net_device *netdev;    /* Yes! we are some kind of netdevice */
+  struct net_device_stats stats;
+  struct tty_driver ttydev;
+
+  struct irlap_cb *irlap;       /* The link layer we are binded to */
+
+  chipio_t io;                  /* IrDA controller information */
+  struct qos_info qos;          /* QoS capabilities for this device */
+
+  __u32 flags;                  /* Interface flags */
+
+  struct pci_dev *pdev;         /*PCI device */
+  int base;                     /*IO base */
+
+
+  int txpending;                /*how many tx's are pending */
+  int txs, rxs;                 /*Which slots are we at  */
+
+  int irdad;                    /*Driver under control of netdev end  */
+  int async;                    /*Driver under control of async end   */
+
+
+  int stopped;                  /*Stopped by some or other APM stuff */
+
+  int filter;                   /*In SIR mode do we want to receive
+                                   frames or byte ranges */
+
+  void *ringbuf;                /*The ring buffer */
+  struct OboeRing *ring;        /*The ring */
+
+  void *tx_bufs[OBOE_RING_MAX_SIZE]; /*The buffers   */
+  void *rx_bufs[OBOE_RING_MAX_SIZE];
+
+
+  int speed;                    /*Current setting of the speed */
+  int new_speed;                /*Set to request a speed change */
+
+/* The spinlock protect critical parts of the driver.
+ *	Locking is done like this :
+ *		spin_lock_irqsave(&self->spinlock, flags);
+ *	Releasing the lock :
+ *		spin_unlock_irqrestore(&self->spinlock, flags);
+ */
+  spinlock_t spinlock;		
+  /* Used for the probe and diagnostics code */
+  int int_rx;
+  int int_tx;
+  int int_txunder;
+  int int_rxover;
+  int int_sip;
+};
+
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/irda/irtty.c linux-2.4.21-pre6/drivers/net/irda/irtty.c
--- linux-2.4.20/drivers/net/irda/irtty.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/irda/irtty.c	2003-03-26 23:49:19.000000000 +0000
@@ -966,9 +966,14 @@
 
 	IRDA_DEBUG(3, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd);
 	
-	/* Disable interrupts & save flags */
-	save_flags(flags);
-	cli();
+	/* Locking :
+	 * irda_device_dongle_init() can't be locked.
+	 * irda_task_execute() doesn't need to be locked (but
+	 * irtty_change_speed() should protect itself).
+	 * As this driver doesn't have spinlock protection, keep
+	 * old fashion locking :-(
+	 * Jean II
+	 */
 	
 	switch (cmd) {
 	case SIOCSBANDWIDTH: /* Set bandwidth */
@@ -994,14 +999,17 @@
 		dongle->write       = irtty_raw_write;
 		dongle->set_dtr_rts = irtty_set_dtr_rts;
 		
-		self->dongle = dongle;
-
-		/* Now initialize the dongle!  */
+		/* Now initialize the dongle!
+		 * Safe to do unlocked : self->dongle is still NULL. */ 
 		dongle->issue->open(dongle, &self->qos);
 		
 		/* Reset dongle */
 		irda_task_execute(dongle, dongle->issue->reset, NULL, NULL, 
 				  NULL);	
+
+		/* Make dongle available to driver only now to avoid
+		 * race conditions - Jean II */
+		self->dongle = dongle;
 		break;
 	case SIOCSMEDIABUSY: /* Set media busy */
 		if (!capable(CAP_NET_ADMIN))
@@ -1015,21 +1023,27 @@
 	case SIOCSDTRRTS:
 		if (!capable(CAP_NET_ADMIN))
 			ret = -EPERM;
-		else
+		else {
+			save_flags(flags);
+			cli();
 			irtty_set_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts);
+			restore_flags(flags);
+		}
 		break;
 	case SIOCSMODE:
 		if (!capable(CAP_NET_ADMIN))
 			ret = -EPERM;
-		else
+		else {
+			save_flags(flags);
+			cli();
 			irtty_set_mode(dev, irq->ifr_mode);
+			restore_flags(flags);
+		}
 		break;
 	default:
 		ret = -EOPNOTSUPP;
 	}
 	
-	restore_flags(flags);
-	
 	return ret;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/irda/smc-ircc.c linux-2.4.21-pre6/drivers/net/irda/smc-ircc.c
--- linux-2.4.20/drivers/net/irda/smc-ircc.c	2002-11-28 23:53:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/irda/smc-ircc.c	2003-03-26 23:48:57.000000000 +0000
@@ -10,6 +10,8 @@
  * Modified by:   Dag Brattli <dag@brattli.net>
  * Modified at:   Tue Jun 26 2001
  * Modified by:   Stefani Seibold <stefani@seibold.net>
+ * Modified at:   Thur Apr 18 2002
+ * Modified by:   Jeff Snyder <je4d@pobox.com>
  * 
  *     Copyright (c) 2001      Stefani Seibold
  *     Copyright (c) 1999-2001 Dag Brattli
@@ -537,7 +539,7 @@
 	if (ircc_irq < 255) {
 		if (ircc_irq!=irq)
 			MESSAGE("%s, Overriding IRQ - chip says %d, using %d\n",
-				driver_name, self->io->irq, ircc_irq);
+				driver_name, irq, ircc_irq);
 		self->io->irq = ircc_irq;
 	}
 	else
@@ -545,13 +547,13 @@
 	if (ircc_dma < 255) {
 		if (ircc_dma!=dma)
 			MESSAGE("%s, Overriding DMA - chip says %d, using %d\n",
-				driver_name, self->io->dma, ircc_dma);
+				driver_name, dma, ircc_dma);
 		self->io->dma = ircc_dma;
 	}
 	else
 		self->io->dma = dma;
 
-	request_region(fir_base, CHIP_IO_EXTENT, driver_name);
+	request_region(self->io->fir_base, CHIP_IO_EXTENT, driver_name);
 
 	/* Initialize QoS for this device */
 	irda_init_max_qos_capabilies(&irport->qos);
@@ -1187,10 +1189,9 @@
         outb(IRCC_CFGB_IR, iobase+IRCC_SCE_CFGB);
 #endif
 	/* Release the PORT that this driver is using */
-	IRDA_DEBUG(0, "%s(), releasing 0x%03x\n", 
-		__FUNCTION__, self->io->fir_base);
+	IRDA_DEBUG(0, "%s(), releasing 0x%03x\n", __FUNCTION__, iobase);
 
-	release_region(self->io->fir_base, self->io->fir_ext);
+	release_region(iobase, CHIP_IO_EXTENT);
 
 	if (self->tx_buff.head)
 		kfree(self->tx_buff.head);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/lance.c linux-2.4.21-pre6/drivers/net/lance.c
--- linux-2.4.20/drivers/net/lance.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/lance.c	2003-03-26 23:49:06.000000000 +0000
@@ -893,8 +893,15 @@
 
 	/* The old LANCE chips doesn't automatically pad buffers to min. size. */
 	if (chip_table[lp->chip_version].flags & LANCE_MUST_PAD) {
-		lp->tx_ring[entry].length =
-			-(ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN);
+		if(skb->len < ETH_ZLEN)
+		{
+			skb = skb_padto(skb, ETH_ZLEN);
+			if(skb == NULL)
+				goto out;
+			lp->tx_ring[entry].length = -ETH_ZLEN;
+		}
+		else 
+			lp->tx_ring[entry].length = -skb->len;
 	} else
 		lp->tx_ring[entry].length = -skb->len;
 
@@ -927,6 +934,7 @@
 	if ((lp->cur_tx - lp->dirty_tx) >= TX_RING_SIZE)
 		netif_stop_queue(dev);
 
+out:
 	spin_unlock_irqrestore(&lp->devlock, flags);
 	return 0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/lasi_82596.c linux-2.4.21-pre6/drivers/net/lasi_82596.c
--- linux-2.4.20/drivers/net/lasi_82596.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/lasi_82596.c	2003-03-26 23:49:07.000000000 +0000
@@ -1084,12 +1084,20 @@
 	struct i596_private *lp = (struct i596_private *) dev->priv;
 	struct tx_cmd *tx_cmd;
 	struct i596_tbd *tbd;
-	short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+	short length = skb->len;
 	dev->trans_start = jiffies;
 
 	DEB(DEB_STARTTX,printk("%s: i596_start_xmit(%x,%p) called\n", dev->name,
 				skb->len, skb->data));
 
+	if(length < ETH_ZLEN)
+	{
+		skb = skb_padto(skb, ETH_ZLEN);
+		if(skb == NULL)
+			return 0;
+		length = ETH_ZLEN;
+	}
+	
 	netif_stop_queue(dev);
 
 	tx_cmd = lp->tx_cmds + lp->next_tx_cmd;
@@ -1412,8 +1420,7 @@
 	DEB(DEB_INIT,printk("%s: Shutting down ethercard, status was %4.4x.\n",
 		       dev->name, lp->scb.status));
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&lp->lock, flags);
 
 	wait_cmd(dev,lp,100,"close1 timed out");
 	lp->scb.command = CUC_ABORT | RX_ABORT;
@@ -1422,7 +1429,7 @@
 	CA(dev);
 
 	wait_cmd(dev,lp,100,"close2 timed out");
-	restore_flags(flags);
+	spin_unlock_irqrestore(&lp->lock, flags);
 	DEB(DEB_STRUCT,i596_display_data(dev));
 	i596_cleanup_cmd(dev,lp);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/lp486e.c linux-2.4.21-pre6/drivers/net/lp486e.c
--- linux-2.4.20/drivers/net/lp486e.c	2001-09-30 19:26:06.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/lp486e.c	2003-03-26 23:49:20.000000000 +0000
@@ -886,7 +886,16 @@
 	if (skb->len <= 0)
 		return 0;
 
-	length = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
+	length = skb->len;
+	
+	if(length < ETH_ZLEN)
+	{
+		skb = skb_padto(skb, ETH_ZLEN);
+		if(skb == NULL)
+			return 0;
+		length = ETH_ZLEN;
+	}
+	
 	dev->trans_start = jiffies;
 
 	tx_cmd = (struct tx_cmd *)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/mac8390.c linux-2.4.21-pre6/drivers/net/mac8390.c
--- linux-2.4.20/drivers/net/mac8390.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/mac8390.c	2003-03-26 23:49:50.000000000 +0000
@@ -0,0 +1,752 @@
+/* mac8390.c: New driver for 8390-based Nubus (or Nubus-alike)
+   Ethernet cards on Linux */
+/* Based on the former daynaport.c driver, by Alan Cox.  Some code
+   taken from or inspired by skeleton.c by Donald Becker, acenic.c by
+   Jes Sorensen, and ne2k-pci.c by Donald Becker and Paul Gortmaker.
+
+   This software may be used and distributed according to the terms of
+   the GNU Public License, incorporated herein by reference.  */
+
+/* 2000-02-28: support added for Dayna and Kinetics cards by 
+   A.G.deWijn@phys.uu.nl */
+/* 2000-04-04: support added for Dayna2 by bart@etpmod.phys.tue.nl */
+/* 2001-04-18: support for DaynaPort E/LC-M by rayk@knightsmanor.org */
+/* 2001-05-15: support for Cabletron ported from old daynaport driver
+ * and fixed access to Sonic Sys card which masquerades as a Farallon 
+ * by rayk@knightsmanor.org */
+
+#include <linux/version.h>
+#include <linux/module.h>
+
+#include <linux/kernel.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/nubus.h>
+#include <linux/in.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/hwtest.h>
+#include <asm/macints.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include "8390.h"
+
+#if (LINUX_VERSION_CODE < 0x02030e)
+#define net_device device
+#endif
+
+#define WD_START_PG			0x00	/* First page of TX buffer */
+#define CABLETRON_RX_START_PG		0x00    /* First page of RX buffer */
+#define CABLETRON_RX_STOP_PG		0x30    /* Last page +1 of RX ring */
+#define CABLETRON_TX_START_PG		CABLETRON_RX_STOP_PG  /* First page of TX buffer */
+
+/* Unfortunately it seems we have to hardcode these for the moment */
+/* Shouldn't the card know about this? Does anyone know where to read it off the card? Do we trust the data provided by the card? */
+
+#define DAYNA_8390_BASE		0x80000
+#define DAYNA_8390_MEM		0x00000
+
+#define KINETICS_8390_BASE	0x80000
+#define KINETICS_8390_MEM	0x00000
+
+#define CABLETRON_8390_BASE	0x90000	
+#define CABLETRON_8390_MEM	0x00000
+
+enum mac8390_type {
+	MAC8390_NONE = -1,
+	MAC8390_APPLE,
+	MAC8390_ASANTE,
+	MAC8390_FARALLON,  /* Apple, Asante, and Farallon are all compatible */
+	MAC8390_CABLETRON,
+	MAC8390_DAYNA,
+	MAC8390_INTERLAN,
+	MAC8390_KINETICS,
+	MAC8390_FOCUS,
+	MAC8390_SONICSYS,
+	MAC8390_DAYNA2,
+	MAC8390_DAYNA3,
+};
+
+static const char * cardname[] = {
+	"apple",
+	"asante",
+	"farallon",
+	"cabletron",
+	"dayna",
+	"interlan",
+	"kinetics",
+	"focus",
+	"sonic systems",
+	"dayna2",
+	"dayna_lc",
+};
+
+static int word16[] = {
+	1, /* apple */
+	1, /* asante */
+	1, /* farallon */
+	1, /* cabletron */
+	0, /* dayna */
+	1, /* interlan */
+	0, /* kinetics */
+	1, /* focus (??) */
+	1, /* sonic systems  */
+	1, /* dayna2 */
+	1, /* dayna-lc */
+};
+
+/* on which cards do we use NuBus resources? */
+static int useresources[] = {
+	1, /* apple */
+	1, /* asante */
+	1, /* farallon */
+	0, /* cabletron */
+	0, /* dayna */
+	0, /* interlan */
+	0, /* kinetics */
+	0, /* focus (??) */
+	1, /* sonic systems */
+	1, /* dayna2 */
+	1, /* dayna-lc */
+};
+
+static const char __initdata * version =
+	"mac8390.c: v0.4 2001-05-15 David Huggins-Daines <dhd@debian.org> and others\n";
+		
+extern int mac8390_probe(struct net_device * dev);
+extern enum mac8390_type mac8390_ident(struct nubus_dev * dev);
+extern int mac8390_memsize(unsigned long membase);
+extern int mac8390_memtest(struct net_device * dev);
+extern int mac8390_initdev(struct net_device * dev, struct nubus_dev * ndev,
+			   enum mac8390_type type);
+
+static int mac8390_open(struct net_device * dev);
+static int mac8390_close(struct net_device * dev);
+static void mac8390_no_reset(struct net_device *dev);
+
+/* Sane (32-bit chunk memory read/write) - Apple/Asante/Farallon do this*/
+static void sane_get_8390_hdr(struct net_device *dev,
+			      struct e8390_pkt_hdr *hdr, int ring_page);
+static void sane_block_input(struct net_device * dev, int count,
+			     struct sk_buff * skb, int ring_offset);
+static void sane_block_output(struct net_device * dev, int count,
+			      const unsigned char * buf, const int start_page);
+
+/* dayna_memcpy to and from card */
+static void dayna_memcpy_fromcard(struct net_device *dev, void *to,
+				int from, int count);
+static void dayna_memcpy_tocard(struct net_device *dev, int to,
+			      const void *from, int count);
+
+/* Dayna - Dayna/Kinetics use this */
+static void dayna_get_8390_hdr(struct net_device *dev,
+			       struct e8390_pkt_hdr *hdr, int ring_page);
+static void dayna_block_input(struct net_device *dev, int count,
+			      struct sk_buff *skb, int ring_offset);
+static void dayna_block_output(struct net_device *dev, int count,
+			       const unsigned char *buf, int start_page);
+
+#define memcpy_fromio(a,b,c)	memcpy((a),(void *)(b),(c))
+#define memcpy_toio(a,b,c)	memcpy((void *)(a),(b),(c))
+
+/* Slow Sane (16-bit chunk memory read/write) Cabletron uses this */
+static void slow_sane_get_8390_hdr(struct net_device *dev,
+				   struct e8390_pkt_hdr *hdr, int ring_page);
+static void slow_sane_block_input(struct net_device *dev, int count,
+				  struct sk_buff *skb, int ring_offset);
+static void slow_sane_block_output(struct net_device *dev, int count,
+				   const unsigned char *buf, int start_page);
+static void word_memcpy_tocard(void *tp, const void *fp, int count);
+static void word_memcpy_fromcard(void *tp, const void *fp, int count);
+
+enum mac8390_type __init mac8390_ident(struct nubus_dev * dev)
+{
+	if (dev->dr_sw == NUBUS_DRSW_ASANTE)
+		return MAC8390_ASANTE;
+	if (dev->dr_sw == NUBUS_DRSW_FARALLON) 
+		return MAC8390_FARALLON;
+	if (dev->dr_sw == NUBUS_DRSW_KINETICS)
+		return MAC8390_KINETICS;
+	if (dev->dr_sw == NUBUS_DRSW_DAYNA)
+		return MAC8390_DAYNA;
+	if (dev->dr_sw == NUBUS_DRSW_DAYNA2)
+		return MAC8390_DAYNA2;
+	if (dev->dr_sw == NUBUS_DRSW_DAYNA_LC)
+		return MAC8390_DAYNA3;
+	if (dev->dr_hw == NUBUS_DRHW_CABLETRON)
+		return MAC8390_CABLETRON;
+	return MAC8390_NONE;
+}
+
+int __init mac8390_memsize(unsigned long membase)
+{
+	unsigned long flags;
+	int i, j;
+	
+	save_flags(flags); cli();
+	/* Check up to 32K in 4K increments */
+	for (i = 0; i < 8; i++) {
+		volatile unsigned short *m = (unsigned short *) (membase + (i * 0x1000));
+
+		/* Unwriteable - we have a fully decoded card and the
+		   RAM end located */
+		if (hwreg_present(m) == 0)
+			break;
+		
+		/* write a distinctive byte */
+		*m = 0xA5A0 | i;
+		/* check that we read back what we wrote */
+		if (*m != (0xA5A0 | i))
+			break;
+
+		/* check for partial decode and wrap */
+		for (j = 0; j < i; j++) {
+			volatile unsigned short *p = (unsigned short *) (membase + (j * 0x1000));
+			if (*p != (0xA5A0 | j))
+				break;
+ 		}
+ 	}
+	restore_flags(flags);
+	/* in any case, we stopped once we tried one block too many,
+           or once we reached 32K */
+ 	return i * 0x1000;
+}
+
+static int probed __initdata = 0;
+
+int __init mac8390_probe(struct net_device * dev)
+{
+	volatile unsigned short *i;
+	int boards_found = 0;
+	int version_disp = 0;
+	struct nubus_dev * ndev = NULL;
+	
+	struct nubus_dir dir;
+	struct nubus_dirent ent;
+	int offset;
+
+	enum mac8390_type cardtype;
+
+	if (probed)
+		return -ENODEV;
+	probed++;
+
+	/* probably should check for Nubus instead */
+
+	if (!MACH_IS_MAC)
+		return -ENODEV;
+
+	while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK, NUBUS_TYPE_ETHERNET, ndev))) {
+		
+		dev = NULL;
+		
+		if ((cardtype = mac8390_ident(ndev)) == MAC8390_NONE)
+			continue;
+
+		dev = init_etherdev(dev, 0);
+		if (dev == NULL) {
+			printk(KERN_ERR "Unable to allocate etherdev"
+					"structure!\n");
+			return -ENOMEM;
+		}
+
+		if (version_disp == 0) {
+			version_disp = 1;
+			printk(version);
+		}
+
+		dev->irq = SLOT2IRQ(ndev->board->slot);
+		/* This is getting to be a habit */
+		dev->base_addr = ndev->board->slot_addr | ((ndev->board->slot&0xf) << 20);
+
+		/* Get some Nubus info - we will trust the card's idea
+		   of where its memory and registers are. */
+
+		if (nubus_get_func_dir(ndev, &dir) == -1) {
+			printk(KERN_ERR "%s: Unable to get Nubus functional"
+					" directory for slot %X!\n",
+			       dev->name, ndev->board->slot);
+			continue;
+		}
+		
+		/* Get the MAC address */
+		if ((nubus_find_rsrc(&dir, NUBUS_RESID_MAC_ADDRESS, &ent)) == -1) {
+			printk(KERN_INFO "%s: Couldn't get MAC address!\n",
+					dev->name);
+			continue;
+		} else {
+			nubus_get_rsrc_mem(dev->dev_addr, &ent, 6);
+			/* Some Sonic Sys cards masquerade as Farallon */
+			if (cardtype == MAC8390_FARALLON && 
+					dev->dev_addr[0] == 0x0 &&
+					dev->dev_addr[1] == 0x40 &&
+					dev->dev_addr[2] == 0x10) {
+				/* This is really Sonic Sys card */
+				cardtype = MAC8390_SONICSYS;
+			}
+		}
+		
+		if (useresources[cardtype] == 1) {
+			nubus_rewinddir(&dir);
+			if (nubus_find_rsrc(&dir, NUBUS_RESID_MINOR_BASEOS, &ent) == -1) {
+				printk(KERN_ERR "%s: Memory offset resource"
+						" for slot %X not found!\n",
+				       dev->name, ndev->board->slot);
+				continue;
+			}
+			nubus_get_rsrc_mem(&offset, &ent, 4);
+			dev->mem_start = dev->base_addr + offset;
+			/* yes, this is how the Apple driver does it */
+			dev->base_addr = dev->mem_start + 0x10000;
+			nubus_rewinddir(&dir);
+			if (nubus_find_rsrc(&dir, NUBUS_RESID_MINOR_LENGTH, &ent) == -1) {
+				printk(KERN_INFO "%s: Memory length resource"
+						 " for slot %X not found"
+						 ", probing\n",
+				       dev->name, ndev->board->slot);
+				offset = mac8390_memsize(dev->mem_start);
+				} else {
+					nubus_get_rsrc_mem(&offset, &ent, 4);
+				}
+			dev->mem_end = dev->mem_start + offset;
+		} else {
+			switch (cardtype) {
+				case MAC8390_KINETICS:
+				case MAC8390_DAYNA: /* it's the same */
+					dev->base_addr = 
+						(int)(ndev->board->slot_addr +
+						DAYNA_8390_BASE);
+					dev->mem_start = 
+						(int)(ndev->board->slot_addr +
+						DAYNA_8390_MEM);
+					dev->mem_end =
+						dev->mem_start +
+						mac8390_memsize(dev->mem_start);
+					break;
+				case MAC8390_CABLETRON:
+					dev->base_addr =
+						(int)(ndev->board->slot_addr +
+						CABLETRON_8390_BASE);
+					dev->mem_start =
+						(int)(ndev->board->slot_addr +
+						CABLETRON_8390_MEM);
+					/* The base address is unreadable if 0x00
+					 * has been written to the command register
+					 * Reset the chip by writing E8390_NODMA +
+					 *   E8390_PAGE0 + E8390_STOP just to be
+					 *   sure
+					 */
+					i = (void *)dev->base_addr;
+					*i = 0x21;
+					dev->mem_end = 
+						dev->mem_start +
+						mac8390_memsize(dev->mem_start);
+					break;
+					
+				default:
+					printk(KERN_ERR "Card type %s is"
+							" unsupported, sorry\n",
+					       cardname[cardtype]);
+					return -ENODEV;
+			}
+		}
+
+		/* Do the nasty 8390 stuff */
+		if (mac8390_initdev(dev, ndev, cardtype))
+			continue;
+		boards_found++;
+	}
+
+	/* We're outta here */
+	if (boards_found > 0)
+		return 0;
+	else
+		return -ENODEV;
+}
+
+#ifdef MODULE
+#if LINUX_VERSION_CODE > 0x20118
+MODULE_AUTHOR("David Huggins-Daines <dhd@debian.org> and others");
+MODULE_DESCRIPTION("Macintosh NS8390-based Nubus Ethernet driver");
+MODUEL_LICENSE("GPL");
+#endif
+
+int init_module(void)
+{
+	if (mac8390_probe(NULL)) {
+		printk(KERN_NOTICE "mac8390.c: No useable cards found, driver NOT installed.\n");
+		return -ENODEV;
+	}
+	lock_8390_module();
+	return 0;
+}
+
+void cleanup_module(void)
+{
+	/* FIXME: should probably keep track of net_device structs
+           somewhere and unregister them here? */
+	unlock_8390_module();
+}
+
+#endif /* MODULE */
+
+int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * ndev,
+			    enum mac8390_type type)
+{
+	static u32 fwrd4_offsets[16]={
+		0,      4,      8,      12,
+		16,     20,     24,     28,
+		32,     36,     40,     44,
+		48,     52,     56,     60
+	};
+	static u32 back4_offsets[16]={
+		60,     56,     52,     48,
+		44,     40,     36,     32,
+		28,     24,     20,     16,
+		12,     8,      4,      0
+	};
+	static u32 fwrd2_offsets[16]={
+		0,      2,      4,      6,
+		8,     10,     12,     14,
+		16,    18,     20,     22,
+		24,    26,     28,     30
+	};
+
+	int access_bitmode;
+	
+	/* 8390 specific init for dev - allocates dev->priv */
+	if (ethdev_init(dev)) {
+		printk(KERN_ERR "%s: Unable to allocate memory for dev->priv!\n", dev->name);
+		return -ENOMEM;
+	}
+
+	/* Now fill in our stuff */
+	dev->open = &mac8390_open;
+	dev->stop = &mac8390_close;
+
+	/* GAR, ei_status is actually a macro even though it looks global */
+	ei_status.name = cardname[type];
+	ei_status.word16 = word16[type];
+
+	/* Cabletron's TX/RX buffers are backwards */
+	if (type == MAC8390_CABLETRON) {
+               ei_status.tx_start_page = CABLETRON_TX_START_PG;
+               ei_status.rx_start_page = CABLETRON_RX_START_PG;
+               ei_status.stop_page = CABLETRON_RX_STOP_PG;
+               dev->rmem_start = dev->mem_start;
+               dev->rmem_end = dev->mem_start + CABLETRON_RX_STOP_PG*256;
+	} else {
+               ei_status.tx_start_page = WD_START_PG;
+               ei_status.rx_start_page = WD_START_PG + TX_PAGES;
+               ei_status.stop_page = (dev->mem_end - dev->mem_start)/256;
+               dev->rmem_start = dev->mem_start + TX_PAGES*256;
+               dev->rmem_end = dev->mem_end;
+	}
+	
+	/* Fill in model-specific information and functions */
+	switch(type) {
+	case MAC8390_SONICSYS:
+		/* 16 bit card, register map is reversed */
+		ei_status.reset_8390 = &mac8390_no_reset;
+		ei_status.block_input = &slow_sane_block_input;
+		ei_status.block_output = &slow_sane_block_output;
+		ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
+		ei_status.reg_offset = back4_offsets;
+		access_bitmode = 0;
+		break;
+	case MAC8390_FARALLON:
+	case MAC8390_APPLE:
+	case MAC8390_ASANTE:
+	case MAC8390_DAYNA2:
+	case MAC8390_DAYNA3:
+		/* 32 bit card, register map is reversed */
+		/* sane */
+		ei_status.reset_8390 = &mac8390_no_reset;
+		ei_status.block_input = &sane_block_input;
+		ei_status.block_output = &sane_block_output;
+		ei_status.get_8390_hdr = &sane_get_8390_hdr;
+		ei_status.reg_offset = back4_offsets;
+		access_bitmode = 1;
+		break;
+	case MAC8390_CABLETRON:
+		/* 16 bit card, register map is short forward */
+		ei_status.reset_8390 = &mac8390_no_reset;
+		ei_status.block_input = &slow_sane_block_input;
+		ei_status.block_output = &slow_sane_block_output;
+		ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
+		ei_status.reg_offset = fwrd2_offsets;
+		access_bitmode = 0;
+		break;
+	case MAC8390_DAYNA:
+	case MAC8390_KINETICS:
+		/* 16 bit memory */
+		/* dayna and similar */
+		ei_status.reset_8390 = &mac8390_no_reset;
+		ei_status.block_input = &dayna_block_input;
+		ei_status.block_output = &dayna_block_output;
+		ei_status.get_8390_hdr = &dayna_get_8390_hdr;
+		ei_status.reg_offset = fwrd4_offsets;
+		access_bitmode = 0;
+		break;
+	default:
+		printk(KERN_ERR "Card type %s is unsupported, sorry\n", cardname[type]);
+		return -ENODEV;
+	}
+		
+	NS8390_init(dev, 0);
+
+	/* Good, done, now spit out some messages */
+	printk(KERN_INFO "%s: %s in slot %X (type %s)\n",
+		   dev->name, ndev->board->name, ndev->board->slot, cardname[type]);
+	printk(KERN_INFO "MAC ");
+	{
+		int i;
+		for (i = 0; i < 6; i++) {
+			printk("%2.2x", dev->dev_addr[i]);
+			if (i < 5)
+				printk(":");
+		}
+	}
+	printk(" IRQ %d, shared memory at %#lx-%#lx,  %d-bit access.\n",
+		   dev->irq, dev->mem_start, dev->mem_end-1, 
+		   access_bitmode?32:16);
+	return 0;
+}
+
+static int mac8390_open(struct net_device *dev)
+{
+	ei_open(dev);
+	if (request_irq(dev->irq, ei_interrupt, 0, "8390 Ethernet", dev)) {
+		printk ("%s: unable to get IRQ %d.\n", dev->name, dev->irq);
+		return -EAGAIN;
+	}	
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int mac8390_close(struct net_device *dev)
+{
+	free_irq(dev->irq, dev);
+	ei_close(dev);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static void mac8390_no_reset(struct net_device *dev)
+{
+	ei_status.txing = 0;
+	if (ei_debug > 1)
+		printk("reset not supported\n");
+	return;
+}
+
+/* dayna_memcpy_fromio/dayna_memcpy_toio */
+/* directly from daynaport.c by Alan Cox */
+static void dayna_memcpy_fromcard(struct net_device *dev, void *to, int from, int count)
+{
+	volatile unsigned short *ptr;
+	unsigned short *target=to;
+	from<<=1;	/* word, skip overhead */
+	ptr=(unsigned short *)(dev->mem_start+from);
+	/* Leading byte? */
+	if (from&2) {
+		*((char *)target)++ = *(((char *)ptr++)-1);
+		count--;
+	}
+	while(count>=2)
+	{
+		*target++=*ptr++;	/* Copy and */
+		ptr++;			/* skip cruft */
+		count-=2;
+	}
+	/* Trailing byte? */
+	if(count)
+	{
+		/* Big endian */
+		unsigned short v=*ptr;
+		*((char *)target)=v>>8;
+	}
+}
+
+static void dayna_memcpy_tocard(struct net_device *dev, int to, const void *from, int count)
+{
+	volatile unsigned short *ptr;
+	const unsigned short *src=from;
+	to<<=1;	/* word, skip overhead */
+	ptr=(unsigned short *)(dev->mem_start+to);
+	/* Leading byte? */
+	if (to&2) { /* avoid a byte write (stomps on other data) */
+		ptr[-1] = (ptr[-1]&0xFF00)|*((unsigned char *)src)++;
+		ptr++;
+		count--;
+	}
+	while(count>=2)
+	{
+		*ptr++=*src++;		/* Copy and */
+		ptr++;			/* skip cruft */
+		count-=2;
+	}
+	/* Trailing byte? */
+	if(count)
+	{
+		/* Big endian */
+		unsigned short v=*src;
+		/* card doesn't like byte writes */
+		*ptr=(*ptr&0x00FF)|(v&0xFF00);
+	}
+}
+
+/* sane block input/output */
+static void sane_get_8390_hdr(struct net_device *dev,
+			      struct e8390_pkt_hdr *hdr, int ring_page)
+{
+	unsigned long hdr_start = (ring_page - WD_START_PG)<<8;
+	memcpy_fromio((void *)hdr, (char *)dev->mem_start + hdr_start, 4);
+	/* Fix endianness */
+	hdr->count = swab16(hdr->count);
+}
+
+static void sane_block_input(struct net_device *dev, int count,
+			     struct sk_buff *skb, int ring_offset)
+{
+	unsigned long xfer_base = ring_offset - (WD_START_PG<<8);
+	unsigned long xfer_start = xfer_base + dev->mem_start;
+
+	if (xfer_start + count > dev->rmem_end) {
+		/* We must wrap the input move. */
+		int semi_count = dev->rmem_end - xfer_start;
+		memcpy_fromio(skb->data, (char *)dev->mem_start + xfer_base, semi_count);
+		count -= semi_count;
+		memcpy_toio(skb->data + semi_count, (char *)dev->rmem_start, count);
+	} else {
+		memcpy_fromio(skb->data, (char *)dev->mem_start + xfer_base, count);
+	}
+}
+
+static void sane_block_output(struct net_device *dev, int count,
+			      const unsigned char *buf, int start_page)
+{
+	long shmem = (start_page - WD_START_PG)<<8;
+	
+	memcpy_toio((char *)dev->mem_start + shmem, buf, count);
+}
+
+/* dayna block input/output */
+static void dayna_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
+{
+	unsigned long hdr_start = (ring_page - WD_START_PG)<<8;
+
+	dayna_memcpy_fromcard(dev, (void *)hdr, hdr_start, 4);
+	/* Fix endianness */
+	hdr->count=(hdr->count&0xFF)<<8|(hdr->count>>8);
+}
+
+static void dayna_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
+{
+	unsigned long xfer_base = ring_offset - (WD_START_PG<<8);
+	unsigned long xfer_start = xfer_base+dev->mem_start;
+
+	/* Note the offset math is done in card memory space which is word
+	   per long onto our space. */
+	 
+	if (xfer_start + count > dev->rmem_end) 
+	{
+		/* We must wrap the input move. */
+		int semi_count = dev->rmem_end - xfer_start;
+		dayna_memcpy_fromcard(dev, skb->data, xfer_base, semi_count);
+		count -= semi_count;
+		dayna_memcpy_fromcard(dev, skb->data + semi_count, 
+			dev->rmem_start - dev->mem_start, count);
+	}
+	else
+	{
+		dayna_memcpy_fromcard(dev, skb->data, xfer_base, count);
+	}
+}
+
+static void dayna_block_output(struct net_device *dev, int count, const unsigned char *buf,
+				int start_page)
+{
+	long shmem = (start_page - WD_START_PG)<<8;
+	
+	dayna_memcpy_tocard(dev, shmem, buf, count);
+}
+
+/* Cabletron block I/O */
+static void slow_sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, 
+	int ring_page)
+{
+	unsigned long hdr_start = (ring_page - WD_START_PG)<<8;
+	word_memcpy_fromcard((void *)hdr, (char *)dev->mem_start+hdr_start, 4);
+	/* Register endianism - fix here rather than 8390.c */
+	hdr->count = (hdr->count&0xFF)<<8|(hdr->count>>8);
+}
+
+static void slow_sane_block_input(struct net_device *dev, int count, struct sk_buff *skb,
+	int ring_offset)
+{
+	unsigned long xfer_base = ring_offset - (WD_START_PG<<8);
+	unsigned long xfer_start = xfer_base+dev->mem_start;
+
+	if (xfer_start + count > dev->rmem_end)
+	{
+		/* We must wrap the input move. */
+		int semi_count = dev->rmem_end - xfer_start;
+		word_memcpy_fromcard(skb->data, (char *)dev->mem_start +
+			xfer_base, semi_count);
+		count -= semi_count;
+		word_memcpy_fromcard(skb->data + semi_count,
+			(char *)dev->rmem_start, count);
+	}
+	else
+	{
+		word_memcpy_fromcard(skb->data, (char *)dev->mem_start +
+			xfer_base, count);
+	}
+}
+
+static void slow_sane_block_output(struct net_device *dev, int count, const unsigned char *buf,
+	int start_page)
+{
+	long shmem = (start_page - WD_START_PG)<<8;
+
+	word_memcpy_tocard((char *)dev->mem_start + shmem, buf, count);
+}
+
+static void word_memcpy_tocard(void *tp, const void *fp, int count)
+{
+	volatile unsigned short *to = tp;
+	const unsigned short *from = fp;
+
+	count++;
+	count/=2;
+
+	while(count--)
+		*to++=*from++;
+}
+
+static void word_memcpy_fromcard(void *tp, const void *fp, int count)
+{
+	unsigned short *to = tp;
+	const volatile unsigned short *from = fp;
+
+	count++;
+	count/=2;
+
+	while(count--)
+		*to++=*from++;
+}
+
+	
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/macmace.c linux-2.4.21-pre6/drivers/net/macmace.c
--- linux-2.4.20/drivers/net/macmace.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/macmace.c	2003-03-26 23:49:29.000000000 +0000
@@ -332,8 +332,8 @@
 		return -ENOMEM;
 	}
 
-	mp->rx_ring_phys = (unsigned char *) virt_to_bus(mp->rx_ring);
-	mp->tx_ring_phys = (unsigned char *) virt_to_bus(mp->tx_ring);
+	mp->rx_ring_phys = (unsigned char *) virt_to_bus((void *)mp->rx_ring);
+	mp->tx_ring_phys = (unsigned char *) virt_to_bus((void *)mp->tx_ring);
 
 	/* We want the Rx buffer to be uncached and the Tx buffer to be writethrough */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/mii.c linux-2.4.21-pre6/drivers/net/mii.c
--- linux-2.4.20/drivers/net/mii.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/mii.c	2003-03-26 23:49:25.000000000 +0000
@@ -2,7 +2,7 @@
 
 	mii.c: MII interface library
 
-	Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
+	Maintained by Jeff Garzik <jgarzik@pobox.com>
 	Copyright 2001,2002 Jeff Garzik
 
 	Various code came from myson803.c and other files by
@@ -124,13 +124,13 @@
 		/* advertise only what has been requested */
 		advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
 		tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
-		if (ADVERTISED_10baseT_Half)
+		if (ecmd->advertising & ADVERTISED_10baseT_Half)
 			tmp |= ADVERTISE_10HALF;
-		if (ADVERTISED_10baseT_Full)
+		if (ecmd->advertising & ADVERTISED_10baseT_Full)
 			tmp |= ADVERTISE_10FULL;
-		if (ADVERTISED_100baseT_Half)
+		if (ecmd->advertising & ADVERTISED_100baseT_Half)
 			tmp |= ADVERTISE_100HALF;
-		if (ADVERTISED_100baseT_Full)
+		if (ecmd->advertising & ADVERTISED_100baseT_Full)
 			tmp |= ADVERTISE_100FULL;
 		if (advert != tmp) {
 			mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp);
@@ -339,7 +339,7 @@
 	return rc;
 }
 
-MODULE_AUTHOR ("Jeff Garzik <jgarzik@mandrakesoft.com>");
+MODULE_AUTHOR ("Jeff Garzik <jgarzik@pobox.com>");
 MODULE_DESCRIPTION ("MII hardware support library");
 MODULE_LICENSE("GPL");
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/ni5010.c linux-2.4.21-pre6/drivers/net/ni5010.c
--- linux-2.4.20/drivers/net/ni5010.c	2001-09-30 19:26:07.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/ni5010.c	2003-03-26 23:49:35.000000000 +0000
@@ -114,7 +114,7 @@
 
 static int	process_xmt_interrupt(struct net_device *dev);
 #define tx_done(dev) 1
-static void	hardware_send_packet(struct net_device *dev, char *buf, int length);
+static void	hardware_send_packet(struct net_device *dev, char *buf, int length, int pad);
 static void 	chipset_init(struct net_device *dev, int startp);
 static void	dump_packet(void *buf, int len);
 static void 	ni5010_show_registers(struct net_device *dev);
@@ -437,7 +437,7 @@
 	 */
 	
 	netif_stop_queue(dev);
-	hardware_send_packet(dev, (unsigned char *)skb->data, length);
+	hardware_send_packet(dev, (unsigned char *)skb->data, skb->len, length-skb->len);
 	dev->trans_start = jiffies;
 	dev_kfree_skb (skb);
 	return 0;
@@ -661,7 +661,7 @@
 	}
 }
 
-static void hardware_send_packet(struct net_device *dev, char *buf, int length)
+static void hardware_send_packet(struct net_device *dev, char *buf, int length, int pad)
 {
 	struct ni5010_local *lp = (struct ni5010_local *)dev->priv;
 	int ioaddr = dev->base_addr;
@@ -686,8 +686,8 @@
 	
 	if (NI5010_DEBUG > 3) dump_packet(buf, length);
 
-        buf_offs = NI5010_BUFSIZE - length;
-        lp->o_pkt_size = length;
+        buf_offs = NI5010_BUFSIZE - length - pad;
+        lp->o_pkt_size = length + pad;
 
 	save_flags(flags);	
 	cli();
@@ -698,6 +698,9 @@
 
 	outw(buf_offs, IE_GP); /* Point GP at start of packet */
 	outsb(IE_XBUF, buf, length); /* Put data in buffer */
+	while(pad--)
+		outb(0, IE_XBUF);
+		
 	outw(buf_offs, IE_GP); /* Rewrite where packet starts */
 
 	/* should work without that outb() (Crynwr used it) */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/ni52.c linux-2.4.21-pre6/drivers/net/ni52.c
--- linux-2.4.20/drivers/net/ni52.c	2001-09-30 19:26:07.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/ni52.c	2003-03-26 23:48:59.000000000 +0000
@@ -226,10 +226,11 @@
 	volatile struct iscp_struct	*iscp;	/* volatile is important */
 	volatile struct scb_struct	*scb;	/* volatile is important */
 	volatile struct tbd_struct	*xmit_buffs[NUM_XMIT_BUFFS];
-	volatile struct transmit_cmd_struct *xmit_cmds[NUM_XMIT_BUFFS];
 #if (NUM_XMIT_BUFFS == 1)
+	volatile struct transmit_cmd_struct *xmit_cmds[2];
 	volatile struct nop_cmd_struct *nop_cmds[2];
 #else
+	volatile struct transmit_cmd_struct *xmit_cmds[NUM_XMIT_BUFFS];
 	volatile struct nop_cmd_struct *nop_cmds[NUM_XMIT_BUFFS];
 #endif
 	volatile int		nop_point,num_recv_buffs;
@@ -1162,7 +1163,12 @@
 #endif
 	{
 		memcpy((char *)p->xmit_cbuffs[p->xmit_count],(char *)(skb->data),skb->len);
-		len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
+		len = skb->len;
+		if(len < ETH_ZLEN)
+		{
+			len = ETH_ZLEN;
+			memset((char *)p->xmit_cbuffs[p->xmit_count]+skb->len, 0, len - skb->len);
+		}
 
 #if (NUM_XMIT_BUFFS == 1)
 #	ifdef NO_NOPCOMMANDS
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/ni65.c linux-2.4.21-pre6/drivers/net/ni65.c
--- linux-2.4.20/drivers/net/ni65.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/ni65.c	2003-03-26 23:49:20.000000000 +0000
@@ -1113,6 +1113,8 @@
 
 			memcpy((char *) p->tmdbounce[p->tmdbouncenum] ,(char *)skb->data,
 							 (skb->len > T_BUF_SIZE) ? T_BUF_SIZE : skb->len);
+			if(len > skb->len)
+				memset((char *)p->tmdbounce[p->tmdbouncenum]+skb->len, 0, len-skb->len);
 			dev_kfree_skb (skb);
 
 			save_flags(flags);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/ns83820.c linux-2.4.21-pre6/drivers/net/ns83820.c
--- linux-2.4.20/drivers/net/ns83820.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/ns83820.c	2003-03-26 23:49:55.000000000 +0000
@@ -499,9 +499,9 @@
 {
 	desc_addr_set(desc + DESC_LINK, link);
 	desc_addr_set(desc + DESC_BUFPTR, buf);
-	desc[DESC_EXTSTS] = extsts;
+	desc[DESC_EXTSTS] = cpu_to_le32(extsts);
 	mb();
-	desc[DESC_CMDSTS] = cmdsts;
+	desc[DESC_CMDSTS] = cpu_to_le32(cmdsts);
 }
 
 #define nr_rx_empty(dev) ((NR_RX_DESC-2 + dev->rx_info.next_rx - dev->rx_info.next_empty) % NR_RX_DESC)
@@ -1214,7 +1214,7 @@
 
 static int ns83820_ioctl(struct net_device *_dev, struct ifreq *rq, int cmd)
 {
-	struct ns83820 *dev = _dev->priv;
+	struct ns83820 *dev = (struct ns83820 *)_dev;
 
 	switch(cmd) {
 	case SIOCETHTOOL:
@@ -1788,6 +1788,7 @@
 	dev->ee.cache = &dev->MEAR_cache;
 	dev->ee.lock = &dev->misc_lock;
 	dev->net_dev.owner = THIS_MODULE;
+	dev->net_dev.priv = dev;
 
 	PREPARE_TQUEUE(&dev->tq_refill, queue_refill, dev);
 	tasklet_init(&dev->rx_tasklet, rx_action, (unsigned long)dev);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/pci-skeleton.c linux-2.4.21-pre6/drivers/net/pci-skeleton.c
--- linux-2.4.20/drivers/net/pci-skeleton.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/pci-skeleton.c	2003-03-26 23:48:58.000000000 +0000
@@ -2,7 +2,7 @@
 
 	drivers/net/pci-skeleton.c
 
-	Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
+	Maintained by Jeff Garzik <jgarzik@pobox.com>
 
 	Original code came from 8139too.c, which in turns was based
 	originally on Donald Becker's rtl8139.c driver, versions 1.11
@@ -483,7 +483,7 @@
 	chip_t chipset;
 };
 
-MODULE_AUTHOR ("Jeff Garzik <jgarzik@mandrakesoft.com>");
+MODULE_AUTHOR ("Jeff Garzik <jgarzik@pobox.com>");
 MODULE_DESCRIPTION ("Skeleton for a PCI Fast Ethernet driver");
 MODULE_LICENSE("GPL");
 MODULE_PARM (multicast_filter_limit, "i");
@@ -1348,6 +1348,16 @@
 	void *ioaddr = tp->mmio_addr;
 	int entry;
 
+	/* If we don't have auto-pad remember not to send random
+	   memory! */
+	   
+	if (skb->len < ETH_ZLEN)
+	{
+		skb = skb_padto(skb, ETH_ZLEN);
+		if(skb == NULL)
+			return 0;
+	}
+	
 	/* Calculate the next Tx descriptor entry. */
 	entry = atomic_read (&tp->cur_tx) % NUM_TX_DESC;
 
@@ -1358,9 +1368,8 @@
 	/* tp->tx_info[entry].mapping = 0; */
 	memcpy (tp->tx_buf[entry], skb->data, skb->len);
 
-	/* Note: the chip doesn't have auto-pad! */
 	NETDRV_W32 (TxStatus0 + (entry * sizeof(u32)),
-		 tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN));
+		 tp->tx_flag | skb->len);
 
 	dev->trans_start = jiffies;
 	atomic_inc (&tp->cur_tx);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/pcmcia/axnet_cs.c linux-2.4.21-pre6/drivers/net/pcmcia/axnet_cs.c
--- linux-2.4.20/drivers/net/pcmcia/axnet_cs.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/pcmcia/axnet_cs.c	2003-03-26 23:48:58.000000000 +0000
@@ -1216,7 +1216,8 @@
 	struct ei_device *ei_local = (struct ei_device *) dev->priv;
 	int length, send_length, output_page;
 	unsigned long flags;
-
+	u8 packet[ETH_ZLEN];
+	
 	netif_stop_queue(dev);
 
 	length = skb->len;
@@ -1241,7 +1242,7 @@
 	ei_local->irqlock = 1;
 
 	send_length = ETH_ZLEN < length ? length : ETH_ZLEN;
-    
+	
 	/*
 	 * We have two Tx slots available for use. Find the first free
 	 * slot, and then perform some sanity checks. With two Tx bufs,
@@ -1286,7 +1287,15 @@
 	 * trigger the send later, upon receiving a Tx done interrupt.
 	 */
 
-	ei_block_output(dev, length, skb->data, output_page);
+	if(length == skb->len)
+		ei_block_output(dev, length, skb->data, output_page);
+	else
+	{
+		memset(packet, 0, ETH_ZLEN);
+		memcpy(packet, skb->data, skb->len);
+		ei_block_output(dev, length, packet, output_page);
+	}
+	
 	if (! ei_local->txing) 
 	{
 		ei_local->txing = 1;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/pcmcia/fmvj18x_cs.c linux-2.4.21-pre6/drivers/net/pcmcia/fmvj18x_cs.c
--- linux-2.4.20/drivers/net/pcmcia/fmvj18x_cs.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/pcmcia/fmvj18x_cs.c	2003-03-26 23:49:07.000000000 +0000
@@ -1,5 +1,5 @@
 /*======================================================================
-    fmvj18x_cs.c 2.6 2001/09/17
+    fmvj18x_cs.c 2.8 2002/03/23
 
     A fmvj18x (and its compatibles) PCMCIA client driver
 
@@ -29,7 +29,7 @@
 ======================================================================*/
 
 #define DRV_NAME	"fmvj18x_cs"
-#define DRV_VERSION	"2.6"
+#define DRV_VERSION	"2.8"
 
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -65,6 +65,10 @@
 /*====================================================================*/
 
 /* Module parameters */
+
+MODULE_DESCRIPTION("fmvj18x and compatible PCMCIA ethernet driver");
+MODULE_LICENSE("GPL");
+
 #define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
 
 /* Bit map of interrupts to choose from */
@@ -80,7 +84,7 @@
 #ifdef PCMCIA_DEBUG
 INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
-static char *version = DRV_NAME ".c " DRV_VERSION " 2001/09/17";
+static char *version = DRV_NAME ".c " DRV_VERSION " 2002/03/23";
 #else
 #define DEBUG(n, args...)
 #endif
@@ -91,6 +95,7 @@
  */
 static void fmvj18x_config(dev_link_t *link);
 static int fmvj18x_get_hwinfo(dev_link_t *link, u_char *node_id);
+static int fmvj18x_setup_mfc(dev_link_t *link);
 static void fmvj18x_release(u_long arg);
 static int fmvj18x_event(event_t event, int priority,
 			  event_callback_args_t *args);
@@ -122,8 +127,6 @@
 	       XXX10304
 } cardtype_t;
 
-#define MANFID_UNGERMANN 0x02c0
-
 /*
     driver specific data structure
 */
@@ -388,6 +391,45 @@
 #define CS_CHECK(fn, args...) \
 while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
 
+static int mfc_try_io_port(dev_link_t *link)
+{
+    int i, ret;
+    static ioaddr_t serial_base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
+
+    for (i = 0; i < 5; i++) {
+	link->io.BasePort2 = serial_base[i];
+	link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
+	if (link->io.BasePort2 == 0) {
+	    link->io.NumPorts2 = 0;
+	    printk(KERN_NOTICE "fmvj18x_cs: out of resource for serial\n");
+	}
+	ret = CardServices(RequestIO, link->handle, &link->io);
+	if (ret == CS_SUCCESS) return ret;
+    }
+    return ret;
+}
+
+static int ungermann_try_io_port(dev_link_t *link)
+{
+    int ret;
+    ioaddr_t ioaddr;
+    /*
+	Ungermann-Bass Access/CARD accepts 0x300,0x320,0x340,0x360
+	0x380,0x3c0 only for ioport.
+    */
+    for (ioaddr = 0x300; ioaddr < 0x3e0; ioaddr += 0x20) {
+	link->io.BasePort1 = ioaddr;
+	ret = CardServices(RequestIO, link->handle, &link->io);
+	if (ret == CS_SUCCESS) {
+	    /* calculate ConfigIndex value */
+	    link->conf.ConfigIndex = 
+		((link->io.BasePort1 & 0x0f0) >> 3) | 0x22;
+	    return ret;
+	}
+    }
+    return ret;	/* RequestIO failed */
+}
+
 static void fmvj18x_config(dev_link_t *link)
 {
     client_handle_t handle = link->handle;
@@ -401,7 +443,7 @@
     cardtype_t cardtype;
     char *card_name = "unknown";
     u_char *node_id;
-    
+
     DEBUG(0, "fmvj18x_config(0x%p)\n", link);
 
     /*
@@ -444,6 +486,11 @@
 		CardServices(GetStatus, handle, &status);
 		if (status.CardState & CS_EVENT_3VCARD)
 		    link->conf.Vcc = 33; /* inserted in 3.3V slot */
+	    } else if (le16_to_cpu(buf[1]) == PRODID_TDK_GN3410) {
+		/* MultiFunction Card */
+		link->conf.ConfigBase = 0x800;
+		link->conf.ConfigIndex = 0x47;
+		link->io.NumPorts2 = 8;
 	    }
 	    break;
 	case MANFID_CONTEC:
@@ -481,31 +528,22 @@
 	    break;
 	case MANFID_UNGERMANN:
 	    cardtype = UNGERMANN;
-	    /*
-	       Ungermann-Bass Access/CARD accepts 0x300,0x320,0x340,0x360
-	       0x380,0x3c0 only for ioport.
-	    */
-	    for (link->io.BasePort1 = 0x300; link->io.BasePort1 < 0x3e0;
-		link->io.BasePort1 += 0x20) {
-		ret = CardServices(RequestIO, link->handle, &link->io);
-		if (ret == CS_SUCCESS) {
-		/* calculate ConfigIndex value */
-		link->conf.ConfigIndex = 
-		    ((link->io.BasePort1 & 0x0f0) >> 3) | 0x22;
-		goto req_irq;
-		}
-	    }
-	    /* if ioport allocation is failed, goto failed */
-	    printk(KERN_NOTICE "fmvj18x_cs: register_netdev() failed\n");
-	    goto failed;
+	    break;
 	default:
 	    cardtype = MBH10302;
 	    link->conf.ConfigIndex = 1;
 	}
     }
 
-    CS_CHECK(RequestIO, link->handle, &link->io);
-req_irq:
+    if (link->io.NumPorts2 != 0) {
+	ret = mfc_try_io_port(link);
+	if (ret != CS_SUCCESS) goto cs_failed;
+    } else if (cardtype == UNGERMANN) {
+	ret = ungermann_try_io_port(link);
+	if (ret != CS_SUCCESS) goto cs_failed;
+    } else { 
+	CS_CHECK(RequestIO, link->handle, &link->io);
+    }
     CS_CHECK(RequestIRQ, link->handle, &link->irq);
     CS_CHECK(RequestConfiguration, link->handle, &link->conf);
     dev->irq = link->irq.AssignedIRQ;
@@ -515,19 +553,22 @@
 	goto failed;
     }
 
+    if (link->io.BasePort2 != 0)
+	fmvj18x_setup_mfc(link);
+
     ioaddr = dev->base_addr;
 
     /* Reset controller */
-    if( sram_config == 0 ) 
+    if (sram_config == 0) 
 	outb(CONFIG0_RST, ioaddr + CONFIG_0);
     else
 	outb(CONFIG0_RST_1, ioaddr + CONFIG_0);
 
     /* Power On chip and select bank 0 */
-    if(cardtype == UNGERMANN)
-	outb(BANK_0U, ioaddr + CONFIG_1);
-    else
+    if (cardtype == MBH10302)
 	outb(BANK_0, ioaddr + CONFIG_1);
+    else
+	outb(BANK_0U, ioaddr + CONFIG_1);
     
     /* Set hardware address */
     switch (cardtype) {
@@ -591,7 +632,6 @@
 
     strcpy(lp->node.dev_name, dev->name);
     link->dev = &lp->node;
-    link->state &= ~DEV_CONFIG_PENDING;
 
     lp->cardtype = cardtype;
     /* print current configuration */
@@ -601,6 +641,7 @@
     for (i = 0; i < 6; i++)
 	printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
 
+    link->state &= ~DEV_CONFIG_PENDING;
     return;
     
 cs_failed:
@@ -608,6 +649,7 @@
     cs_error(link->handle, last_fn, last_ret);
 failed:
     fmvj18x_release((u_long)link);
+    link->state &= ~DEV_CONFIG_PENDING;
 
 } /* fmvj18x_config */
 /*====================================================================*/
@@ -666,6 +708,51 @@
 } /* fmvj18x_get_hwinfo */
 /*====================================================================*/
 
+static int fmvj18x_setup_mfc(dev_link_t *link)
+{
+    win_req_t req;
+    memreq_t mem;
+    u_char *base;
+    int i, j;
+    local_info_t *lp = link->priv;
+    struct net_device *dev = &lp->dev;
+    ioaddr_t ioaddr;
+
+    /* Allocate a small memory window */
+    req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
+    req.Base = 0; req.Size = 0;
+    req.AccessSpeed = 0;
+    link->win = (window_handle_t)link->handle;
+    i = CardServices(RequestWindow, &link->win, &req);
+    if (i != CS_SUCCESS) {
+	cs_error(link->handle, RequestWindow, i);
+	return -1;
+    }
+
+    base = ioremap(req.Base, req.Size);
+    mem.Page = 0;
+    mem.CardOffset = 0;
+    CardServices(MapMemPage, link->win, &mem);
+
+    ioaddr = dev->base_addr;
+    writeb(0x47, base+0x800);	/* Config Option Register of LAN */
+    writeb(0x0, base+0x802);	/* Config and Status Register */
+
+    writeb(ioaddr & 0xff, base+0x80a);		/* I/O Base(Low) of LAN */
+    writeb((ioaddr >> 8) & 0xff, base+0x80c);	/* I/O Base(High) of LAN */
+   
+    writeb(0x45, base+0x820);	/* Config Option Register of Modem */
+    writeb(0x8, base+0x822);	/* Config and Status Register */
+
+    iounmap(base);
+    j = CardServices(ReleaseWindow, link->win);
+    if (j != CS_SUCCESS)
+	cs_error(link->handle, ReleaseWindow, j);
+    return 0;
+
+}
+/*====================================================================*/
+
 static void fmvj18x_release(u_long arg)
 {
     dev_link_t *link = (dev_link_t *)arg;
@@ -752,7 +839,7 @@
     if (serv.Revision != CS_RELEASE_CODE) {
 	printk(KERN_NOTICE "fmvj18x: Card Services release "
 	       "does not match!\n");
-	return -1;
+	return -EINVAL;
     }
     register_pccard_driver(&dev_info, &fmvj18x_attach, &fmvj18x_detach);
     return 0;
@@ -865,11 +952,19 @@
 {
     struct local_info_t *lp = (struct local_info_t *)dev->priv;
     ioaddr_t ioaddr = dev->base_addr;
+    short length = skb->len;
+    
+    if(length < ETH_ZLEN)
+    {
+    	skb = skb_padto(skb, ETH_ZLEN);
+    	if(skb == NULL)
+    		return 0;
+    	length = ETH_ZLEN;
+    }
 
     netif_stop_queue(dev);
 
     {
-	short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
 	unsigned char *buf = skb->data;
 
 	if (length > ETH_FRAME_LEN) {
@@ -942,10 +1037,10 @@
 	outb(CONFIG0_RST_1, ioaddr + CONFIG_0);
 
     /* Power On chip and select bank 0 */
-    if( lp->cardtype == UNGERMANN)
-	outb(BANK_0U, ioaddr + CONFIG_1);
-    else
+    if (lp->cardtype == MBH10302)
 	outb(BANK_0, ioaddr + CONFIG_1);
+    else
+	outb(BANK_0U, ioaddr + CONFIG_1);
 
     /* Set Tx modes */
     outb(D_TX_MODE, ioaddr + TX_MODE);
@@ -957,20 +1052,20 @@
         outb(dev->dev_addr[i], ioaddr + NODE_ID + i);
 
     /* Switch to bank 1 */
-    if ( lp->cardtype == UNGERMANN )
-	outb(BANK_1U, ioaddr + CONFIG_1);
-    else
+    if (lp->cardtype == MBH10302)
 	outb(BANK_1, ioaddr + CONFIG_1);
+    else
+	outb(BANK_1U, ioaddr + CONFIG_1);
 
     /* set the multicast table to accept none. */
     for (i = 0; i < 6; i++) 
         outb(0x00, ioaddr + MAR_ADR + i);
 
     /* Switch to bank 2 (runtime mode) */
-    if ( lp->cardtype == UNGERMANN )
-	outb(BANK_2U, ioaddr + CONFIG_1);
-    else
+    if (lp->cardtype == MBH10302)
 	outb(BANK_2, ioaddr + CONFIG_1);
+    else
+	outb(BANK_2U, ioaddr + CONFIG_1);
 
     /* set 16col ctrl bits */
     if( lp->cardtype == TDK || lp->cardtype == CONTEC) 
@@ -999,16 +1094,16 @@
     outb(0xff, ioaddr + TX_STATUS);
     outb(0xff, ioaddr + RX_STATUS);
 
-    if( lp->cardtype != TDK ) 
-    		outb(INTR_OFF, ioaddr + LAN_CTRL);
+    if (lp->cardtype == MBH10302)
+	outb(INTR_OFF, ioaddr + LAN_CTRL);
 
     /* Turn on Rx interrupts */
     outb(D_TX_INTR, ioaddr + TX_INTR);
     outb(D_RX_INTR, ioaddr + RX_INTR);
 
     /* Turn on interrupts from LAN card controller */
-    if( lp->cardtype != TDK ) 
-		outb(INTR_ON, ioaddr + LAN_CTRL);
+    if (lp->cardtype == MBH10302)
+	outb(INTR_ON, ioaddr + LAN_CTRL);
 } /* fjn_reset */
 
 /*====================================================================*/
@@ -1063,7 +1158,7 @@
 
 	    skb_reserve(skb, 2);
 	    insw(ioaddr + DATAPORT, skb_put(skb, pkt_len),
-		    (pkt_len + 1) >> 1);
+		 (pkt_len + 1) >> 1);
 	    skb->protocol = eth_type_trans(skb, dev);
 
 #ifdef PCMCIA_DEBUG
@@ -1090,7 +1185,7 @@
 	   has done a netif_wake_queue() for us and will work on them
 	   when we get to the bottom-half routine. */
 /*
-    if( lp->cardtype != TDK ) {
+    if (lp->cardtype != TDK) {
 	int i;
 	for (i = 0; i < 20; i++) {
 	    if ((inb(ioaddr + RX_MODE) & F_BUF_EMP) == F_BUF_EMP)
@@ -1223,7 +1318,7 @@
     outb(CHIP_OFF ,ioaddr + CONFIG_1);
 
     /* Set the ethernet adaptor disable IRQ */
-    if( lp->cardtype != TDK ) 
+    if (lp->cardtype == MBH10302)
 	outb(INTR_OFF, ioaddr + LAN_CTRL);
 
     link->open--;
@@ -1252,8 +1347,8 @@
 {
     ioaddr_t ioaddr = dev->base_addr;
     struct local_info_t *lp = (struct local_info_t *)dev->priv;
-    unsigned char mc_filter[8];		 /* Multicast hash filter */
-    unsigned long flags;
+    u_char mc_filter[8];		 /* Multicast hash filter */
+    u_long flags;
     int i;
     
     if (dev->flags & IFF_PROMISC) {
@@ -1293,4 +1388,3 @@
     }
     restore_flags(flags);
 }
-MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/pcmcia/ray_cs.c linux-2.4.21-pre6/drivers/net/pcmcia/ray_cs.c
--- linux-2.4.20/drivers/net/pcmcia/ray_cs.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/pcmcia/ray_cs.c	2003-03-26 23:49:30.000000000 +0000
@@ -1054,7 +1054,7 @@
 {
     ray_dev_t *local = dev->priv;
     dev_link_t *link = local->finder;
-    short length;
+    short length = skb->len;
 
     if (!(link->state & DEV_PRESENT)) {
         DEBUG(2,"ray_dev_start_xmit - device not present\n");
@@ -1070,7 +1070,13 @@
         }
     }
 
-    length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+    if(length < ETH_ZLEN)
+    {
+    	skb = skb_padto(skb, ETH_ZLEN);
+    	if(skb == NULL)
+    		return 0;
+    	length = ETH_ZLEN;
+    }
     switch (ray_hw_xmit( skb->data, length, dev, DATA_TYPE)) {
         case XMIT_NO_CCS:
         case XMIT_NEED_AUTH:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/pcmcia/smc91c92_cs.c linux-2.4.21-pre6/drivers/net/pcmcia/smc91c92_cs.c
--- linux-2.4.20/drivers/net/pcmcia/smc91c92_cs.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/pcmcia/smc91c92_cs.c	2003-03-26 23:49:07.000000000 +0000
@@ -8,8 +8,8 @@
 
     Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net
 
-    smc91c92_cs.c 1.2 2002/09/28 15:00:00
-    
+    smc91c92_cs.c 1.122 2002/10/25 06:26:39
+
     This driver contains code written by Donald Becker
     (becker@scyld.com), Rowan Hughes (x-csrdh@jcu.edu.au),
     David Hinds (dahinds@users.sourceforge.net), and Erik Stahlman
@@ -18,7 +18,7 @@
     incorporated some parts of his driver here.  I (Dave) wrote most
     of the PCMCIA glue code, and the Ositech support code.  Kelly
     Stephens (kstephen@holli.com) added support for the Motorola
-    Mariner, with help from Allen Brost. 
+    Mariner, with help from Allen Brost.
 
     This software may be used and distributed according to the terms of
     the GNU General Public License, incorporated herein by reference.
@@ -92,7 +92,7 @@
 #endif
 
 #define DRV_NAME	"smc91c92_cs"
-#define DRV_VERSION	"1.2"
+#define DRV_VERSION	"1.122"
 
 /*====================================================================*/
 
@@ -130,6 +130,8 @@
     u_short			fast_poll;
     u_short			link_status;
     struct mii_if_info		mii_if;
+    int				duplex;
+    int				rx_ovrn;
 };
 
 /* Special definitions for Megahertz multifunction cards */
@@ -257,7 +259,7 @@
 #define	MULTICAST2	2
 #define	MULTICAST4	4
 #define	MULTICAST6	6
-#define MGMT    	8 
+#define MGMT    	8
 #define REVISION	0x0a
 
 /* Transmit status bits. */
@@ -287,22 +289,22 @@
 static int smc91c92_event(event_t event, int priority,
 			  event_callback_args_t *args);
 
-static int smc91c92_open(struct net_device *dev);
-static int smc91c92_close(struct net_device *dev);
+static int smc_open(struct net_device *dev);
+static int smc_close(struct net_device *dev);
+static int smc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static void smc_tx_timeout(struct net_device *dev);
 static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev);
 static void smc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void smc_rx(struct net_device *dev);
-static struct net_device_stats *smc91c92_get_stats(struct net_device *dev);
+static struct net_device_stats *smc_get_stats(struct net_device *dev);
 static void set_rx_mode(struct net_device *dev);
 static int s9k_config(struct net_device *dev, struct ifmap *map);
 static void smc_set_xcvr(struct net_device *dev, int if_port);
 static void smc_reset(struct net_device *dev);
 static void media_check(u_long arg);
-static void smc_mdio_sync(ioaddr_t addr);
-static int smc_mdio_read(struct net_device *dev, int phy_id, int loc);
-static void smc_mdio_write(struct net_device *dev, int phy_id, int loc, int value);
-static int smc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static void mdio_sync(ioaddr_t addr);
+static int mdio_read(struct net_device *dev, int phy_id, int loc);
+static void mdio_write(struct net_device *dev, int phy_id, int loc, int value);
 static int smc_link_ok(struct net_device *dev);
 
 /*======================================================================
@@ -310,7 +312,7 @@
     This bit of code is used to avoid unregistering network devices
     at inappropriate times.  2.2 and later kernels are fairly picky
     about when this can happen.
-    
+
 ======================================================================*/
 
 static void flush_stale_links(void)
@@ -349,7 +351,7 @@
 
     DEBUG(0, "smc91c92_attach()\n");
     flush_stale_links();
-    
+
     /* Create new ethernet device */
     smc = kmalloc(sizeof(struct smc_private), GFP_KERNEL);
     if (!smc) return NULL;
@@ -375,25 +377,25 @@
 
     /* The SMC91c92-specific entries in the device structure. */
     dev->hard_start_xmit = &smc_start_xmit;
-    dev->get_stats = &smc91c92_get_stats;
+    dev->get_stats = &smc_get_stats;
     dev->set_config = &s9k_config;
     dev->set_multicast_list = &set_rx_mode;
-    dev->do_ioctl = &smc_ioctl;
     ether_setup(dev);
-    dev->open = &smc91c92_open;
-    dev->stop = &smc91c92_close;
+    dev->open = &smc_open;
+    dev->stop = &smc_close;
+    dev->do_ioctl = &smc_ioctl;
 #ifdef HAVE_TX_TIMEOUT
     dev->tx_timeout = smc_tx_timeout;
     dev->watchdog_timeo = TX_TIMEOUT;
 #endif
     dev->priv = link->priv = link->irq.Instance = smc;
-   
+
     smc->mii_if.dev = dev;
-    smc->mii_if.mdio_read = smc_mdio_read;
-    smc->mii_if.mdio_write = smc_mdio_write;
+    smc->mii_if.mdio_read = mdio_read;
+    smc->mii_if.mdio_write = mdio_write;
     smc->mii_if.phy_id_mask = 0x1f;
     smc->mii_if.reg_num_mask = 0x1f;
-    
+
     /* Register with Card Services */
     link->next = dev_list;
     dev_list = link;
@@ -411,7 +413,7 @@
 	smc91c92_detach(link);
 	return NULL;
     }
-    
+
     return link;
 } /* smc91c92_attach */
 
@@ -430,13 +432,13 @@
     dev_link_t **linkp;
 
     DEBUG(0, "smc91c92_detach(0x%p)\n", link);
-    
+
     /* Locate device structure */
     for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
 	if (*linkp == link) break;
     if (*linkp == NULL)
 	return;
-    
+
     del_timer(&link->release);
     if (link->state & DEV_CONFIG) {
 	smc91c92_release((u_long)link);
@@ -445,16 +447,16 @@
 	    return;
 	}
     }
-    
+
     if (link->handle)
 	CardServices(DeregisterClient, link->handle);
-    
+
     /* Unlink device structure, free bits */
     *linkp = link->next;
     if (link->dev)
 	unregister_netdev(&smc->dev);
     kfree(smc);
-    
+
 } /* smc91c92_detach */
 
 /*====================================================================*/
@@ -502,14 +504,14 @@
     mhz_mfc_config() handles socket setup for multifunction (1144
     and 3288) cards.  mhz_setup() gets a card's hardware ethernet
     address.
-    
+
 ======================================================================*/
 
 static int mhz_3288_power(dev_link_t *link)
 {
     struct smc_private *smc = link->priv;
     u_char tmp;
-    
+
     /* Read the ISR twice... */
     readb(smc->base+MEGAHERTZ_ISR);
     udelay(5);
@@ -517,7 +519,7 @@
 
     /* Pause 200ms... */
     mdelay(200);
-    
+
     /* Now read and write the COR... */
     tmp = readb(smc->base + link->conf.ConfigBase + CISREG_COR);
     udelay(5);
@@ -569,7 +571,7 @@
     if (i != CS_SUCCESS)
 	return i;
     dev->base_addr = link->io.BasePort1;
-    
+
     /* Allocate a memory window, for accessing the ISR */
     req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
     req.Base = req.Size = 0;
@@ -583,12 +585,12 @@
     if (smc->manfid == MANFID_MOTOROLA)
 	mem.CardOffset = link->conf.ConfigBase;
     i = CardServices(MapMemPage, link->win, &mem);
-    
+
     if ((i == CS_SUCCESS)
 	&& (smc->manfid == MANFID_MEGAHERTZ)
 	&& (smc->cardid == PRODID_MEGAHERTZ_EM3288))
 	mhz_3288_power(link);
-    
+
     return i;
 }
 
@@ -628,7 +630,7 @@
     buf[12] = '\0';
     if (cvt_ascii_address(dev, buf) == 0)
 	return 0;
-    
+
     return -1;
 }
 
@@ -638,7 +640,7 @@
 
     mot_config() writes directly to the Mariner configuration
     registers because the CIS is just bogus.
-    
+
 ======================================================================*/
 
 static void mot_config(dev_link_t *link)
@@ -647,12 +649,12 @@
     struct net_device *dev = &smc->dev;
     ioaddr_t ioaddr = dev->base_addr;
     ioaddr_t iouart = link->io.BasePort2;
-    
+
     /* Set UART base address and force map with COR bit 1 */
     writeb(iouart & 0xff,        smc->base + MOT_UART + CISREG_IOBASE_0);
     writeb((iouart >> 8) & 0xff, smc->base + MOT_UART + CISREG_IOBASE_1);
     writeb(MOT_NORMAL,           smc->base + MOT_UART + CISREG_COR);
-    
+
     /* Set SMC base address and force map with COR bit 1 */
     writeb(ioaddr & 0xff,        smc->base + MOT_LAN + CISREG_IOBASE_0);
     writeb((ioaddr >> 8) & 0xff, smc->base + MOT_LAN + CISREG_IOBASE_1);
@@ -671,7 +673,7 @@
     u_int addr;
 
     /* Read Ethernet address from Serial EEPROM */
-    
+
     for (i = 0; i < 3; i++) {
 	SMC_SELECT_BANK(2);
 	outw(MOT_EEPROM + i, ioaddr + POINTER);
@@ -691,7 +693,7 @@
 	dev->dev_addr[2*i]   = addr & 0xff;
 	dev->dev_addr[2*i+1] = (addr >> 8) & 0xff;
     }
-    
+
     return 0;
 }
 
@@ -743,7 +745,7 @@
     tuple.Attributes = tuple.TupleOffset = 0;
     tuple.TupleData = buf;
     tuple.TupleDataMax = sizeof(buf);
-    
+
     /* Check for a LAN function extension tuple */
     tuple.DesiredTuple = CISTPL_FUNCE;
     i = first_tuple(handle, &tuple, &parse);
@@ -760,7 +762,7 @@
 	    return 0;
 	}
     }
-    
+
     /* Try the third string in the Version 1 Version/ID tuple. */
     tuple.DesiredTuple = CISTPL_VERS_1;
     if (first_tuple(handle, &tuple, &parse) != CS_SUCCESS)
@@ -780,7 +782,7 @@
     struct net_device *dev = &smc->dev;
     static ioaddr_t com[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
     int i, j;
-    
+
     link->conf.Attributes |= CONF_ENABLE_SPKR;
     link->conf.Status = CCSR_AUDIO_ENA;
     link->irq.Attributes =
@@ -789,10 +791,10 @@
     link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
     link->io.NumPorts2 = 8;
     link->io.IOAddrLines = 16;
-    
+
     /* Enable Hard Decode, LAN, Modem */
     link->conf.ConfigIndex = 0x23;
-    
+
     for (i = j = 0; j < 4; j++) {
 	link->io.BasePort2 = com[j];
 	i = CardServices(RequestIO, link->handle, &link->io);
@@ -816,12 +818,12 @@
     tuple_t tuple;
     u_char buf[255];
     int i;
-    
+
     tuple.Attributes = TUPLE_RETURN_COMMON;
     tuple.TupleData = buf;
     tuple.TupleDataMax = sizeof(buf);
     tuple.TupleOffset = 0;
-    
+
     /* Read the station address from tuple 0x90, subtuple 0x04 */
     tuple.DesiredTuple = 0x90;
     i = CardServices(GetFirstTuple, handle, &tuple);
@@ -862,7 +864,7 @@
 
     This verifies that the chip is some SMC91cXX variant, and returns
     the revision code if successful.  Otherwise, it returns -ENODEV.
-    
+
 ======================================================================*/
 
 static int check_sig(dev_link_t *link)
@@ -888,7 +890,7 @@
     else
 	s &= ~CFG_16BIT;
     outb(s, ioaddr + CONFIG);
-    
+
     /* Check Base Address Register to make sure bus width is OK */
     s = inw(ioaddr + BASE_ADDR);
     if ((inw(ioaddr + BANK_SELECT) >> 8 == 0x33) &&
@@ -936,7 +938,7 @@
     ioaddr_t ioaddr;
 
     DEBUG(0, "smc91c92_config(0x%p)\n", link);
-    
+
     tuple.Attributes = tuple.TupleOffset = 0;
     tuple.TupleData = (cisdata_t *)buf;
     tuple.TupleDataMax = sizeof(buf);
@@ -946,14 +948,14 @@
     CS_EXIT_TEST(i, ParseTuple, config_failed);
     link->conf.ConfigBase = parse.config.base;
     link->conf.Present = parse.config.rmask[0];
-    
+
     tuple.DesiredTuple = CISTPL_MANFID;
     tuple.Attributes = TUPLE_RETURN_COMMON;
     if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) {
 	smc->manfid = parse.manfid.manf;
 	smc->cardid = parse.manfid.card;
     }
-    
+
     /* Configure card */
     link->state |= DEV_CONFIG;
 
@@ -969,12 +971,12 @@
 	i = smc_config(link);
     }
     CS_EXIT_TEST(i, RequestIO, config_failed);
-    
+
     i = CardServices(RequestIRQ, link->handle, &link->irq);
     CS_EXIT_TEST(i, RequestIRQ, config_failed);
     i = CardServices(RequestConfiguration, link->handle, &link->conf);
     CS_EXIT_TEST(i, RequestConfiguration, config_failed);
-    
+
     if (smc->manfid == MANFID_MOTOROLA)
 	mot_config(link);
 
@@ -984,7 +986,7 @@
 	dev->if_port = if_port;
     else
 	printk(KERN_NOTICE "smc91c92_cs: invalid if_port requested\n");
-    
+
     if (register_netdev(dev) != 0) {
 	printk(KERN_ERR "smc91c92_cs: register_netdev() failed\n");
 	goto config_undo;
@@ -1004,16 +1006,16 @@
     default: /* get the hw address from EEPROM */
 	i = mot_setup(link); break;
     }
-    
+
     if (i != 0) {
 	printk(KERN_NOTICE "smc91c92_cs: Unable to find hardware address.\n");
-	link->state &= ~DEV_CONFIG_PENDING;
 	goto config_undo;
     }
 
     strcpy(smc->node.dev_name, dev->name);
     link->dev = &smc->node;
-    link->state &= ~DEV_CONFIG_PENDING;
+    smc->duplex = 0;
+    smc->rx_ovrn = 0;
 
     rev = check_sig(link);
     name = "???";
@@ -1055,12 +1057,12 @@
 	printk(" buffer, %s xcvr\n", (smc->cfg & CFG_MII_SELECT) ?
 	       "MII" : if_names[dev->if_port]);
     }
-    
+
     if (smc->cfg & CFG_MII_SELECT) {
 	SMC_SELECT_BANK(3);
 
 	for (i = 0; i < 32; i++) {
-	    j = smc_mdio_read(dev, i, 1);
+	    j = mdio_read(dev, i, 1);
 	    if ((j != 0) && (j != 0xffff)) break;
 	}
 	smc->mii_if.phy_id = (i < 32) ? i : -1;
@@ -1073,13 +1075,15 @@
 	SMC_SELECT_BANK(0);
     }
 
+    link->state &= ~DEV_CONFIG_PENDING;
     return;
-    
+
 config_undo:
     unregister_netdev(dev);
 config_failed:			/* CS_EXIT_TEST() calls jump to here... */
     smc91c92_release((u_long)link);
-    
+    link->state &= ~DEV_CONFIG_PENDING;
+
 } /* smc91c92_config */
 
 /*======================================================================
@@ -1096,14 +1100,14 @@
     struct smc_private *smc = link->priv;
 
     DEBUG(0, "smc91c92_release(0x%p)\n", link);
-    
+
     if (link->open) {
 	DEBUG(1, "smc91c92_cs: release postponed, '%s' still open\n",
 	      link->dev->dev_name);
 	link->state |= DEV_STALE_CONFIG;
 	return;
     }
-    
+
     CardServices(ReleaseConfiguration, link->handle);
     CardServices(ReleaseIO, link->handle, &link->io);
     CardServices(ReleaseIRQ, link->handle, &link->irq);
@@ -1111,7 +1115,7 @@
 	iounmap(smc->base);
 	CardServices(ReleaseWindow, link->win);
     }
-    
+
     link->state &= ~DEV_CONFIG;
 
 } /* smc91c92_release */
@@ -1131,8 +1135,8 @@
     dev_link_t *link = args->client_data;
     struct smc_private *smc = link->priv;
     struct net_device *dev = &smc->dev;
-    int i;   
- 
+    int i;
+
     DEBUG(1, "smc91c92_event(0x%06x)\n", event);
 
     switch (event) {
@@ -1144,7 +1148,7 @@
 	}
 	break;
     case CS_EVENT_CARD_INSERTION:
-	link->state |= DEV_PRESENT;
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
 	smc91c92_config(link);
 	break;
     case CS_EVENT_PM_SUSPEND:
@@ -1206,7 +1210,7 @@
 #define MDIO_DATA_WRITE1	(MDIO_DIR_WRITE | MDIO_DATA_OUT)
 #define MDIO_DATA_READ		0x02
 
-static void smc_mdio_sync(ioaddr_t addr)
+static void mdio_sync(ioaddr_t addr)
 {
     int bits;
     for (bits = 0; bits < 32; bits++) {
@@ -1215,13 +1219,13 @@
     }
 }
 
-static int smc_mdio_read(struct net_device *dev, int phy_id, int loc)
+static int mdio_read(struct net_device *dev, int phy_id, int loc)
 {
     ioaddr_t addr = dev->base_addr + MGMT;
     u_int cmd = (0x06<<10)|(phy_id<<5)|loc;
     int i, retval = 0;
 
-    smc_mdio_sync(addr);
+    mdio_sync(addr);
     for (i = 13; i >= 0; i--) {
 	int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
 	outb(dat, addr);
@@ -1235,13 +1239,13 @@
     return (retval>>1) & 0xffff;
 }
 
-static void smc_mdio_write(struct net_device *dev, int phy_id, int loc, int value)
+static void mdio_write(struct net_device *dev, int phy_id, int loc, int value)
 {
     ioaddr_t addr = dev->base_addr + MGMT;
     u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value;
     int i;
 
-    smc_mdio_sync(addr);
+    mdio_sync(addr);
     for (i = 31; i >= 0; i--) {
 	int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
 	outb(dat, addr);
@@ -1254,10 +1258,10 @@
 }
 
 /*======================================================================
-  
+
     The driver core code, most of which should be common with a
     non-PCMCIA implementation.
-    
+
 ======================================================================*/
 
 #ifdef PCMCIA_DEBUG
@@ -1277,17 +1281,17 @@
 }
 #endif
 
-static int smc91c92_open(struct net_device *dev)
+static int smc_open(struct net_device *dev)
 {
     struct smc_private *smc = dev->priv;
     dev_link_t *link = &smc->link;
 
 #ifdef PCMCIA_DEBUG
-    DEBUG(0, "%s: smc91c92_open(%p), ID/Window %4.4x.\n",
+    DEBUG(0, "%s: smc_open(%p), ID/Window %4.4x.\n",
 	  dev->name, dev, inw(dev->base_addr + BANK_SELECT));
     if (pc_debug > 1) smc_dump(dev);
 #endif
-    
+
     /* Check that the PCMCIA card is still here. */
     if (!DEV_OK(link))
 	return -ENODEV;
@@ -1302,25 +1306,25 @@
     netif_start_queue(dev);
     smc->saved_skb = 0;
     smc->packets_waiting = 0;
-    
+
     smc_reset(dev);
     smc->media.function = &media_check;
     smc->media.data = (u_long)smc;
     smc->media.expires = jiffies + HZ;
     add_timer(&smc->media);
-    
+
     return 0;
-} /* smc91c92_open */
+} /* smc_open */
 
 /*====================================================================*/
 
-static int smc91c92_close(struct net_device *dev)
+static int smc_close(struct net_device *dev)
 {
     struct smc_private *smc = dev->priv;
     dev_link_t *link = &smc->link;
     ioaddr_t ioaddr = dev->base_addr;
 
-    DEBUG(0, "%s: smc91c92_close(), status %4.4x.\n",
+    DEBUG(0, "%s: smc_close(), status %4.4x.\n",
 	  dev->name, inw(ioaddr + BANK_SELECT));
 
     netif_stop_queue(dev);
@@ -1332,27 +1336,27 @@
     SMC_SELECT_BANK(0);
     mask_bits(0xff00, ioaddr + RCR);
     mask_bits(0xff00, ioaddr + TCR);
-    
+
     /* Put the chip into power-down mode. */
     SMC_SELECT_BANK(1);
     outw(CTL_POWERDOWN, ioaddr + CONTROL );
-    
+
     link->open--;
     del_timer(&smc->media);
     if (link->state & DEV_STALE_CONFIG)
 	mod_timer(&link->release, jiffies + HZ/20);
-    
+
     MOD_DEC_USE_COUNT;
-    
+
     return 0;
-} /* smc91c92_close */
+} /* smc_close */
 
 /*======================================================================
 
    Transfer a packet to the hardware and trigger the packet send.
    This may be called at either from either the Tx queue code
    or the interrupt handler.
-   
+
 ======================================================================*/
 
 static void smc_hardware_send_packet(struct net_device * dev)
@@ -1361,12 +1365,12 @@
     struct sk_buff *skb = smc->saved_skb;
     ioaddr_t ioaddr = dev->base_addr;
     u_char packet_no;
-    
+
     if (!skb) {
 	printk(KERN_ERR "%s: In XMIT with no packet to send.\n", dev->name);
 	return;
     }
-    
+
     /* There should be a packet slot waiting. */
     packet_no = inw(ioaddr + PNR_ARR) >> 8;
     if (packet_no & 0x80) {
@@ -1384,7 +1388,7 @@
     outw(packet_no, ioaddr + PNR_ARR);
     /* point to the beginning of the packet */
     outw(PTR_AUTOINC , ioaddr + POINTER);
-    
+
     /* Send the packet length (+6 for status, length and ctl byte)
        and the status word (set to zeros). */
     {
@@ -1402,15 +1406,15 @@
 	/* The odd last byte, if there is one, goes in the control word. */
 	outw((length & 1) ? 0x2000 | buf[length-1] : 0, ioaddr + DATA_1);
     }
-    
+
     /* Enable the Tx interrupts, both Tx (TxErr) and TxEmpty. */
     outw(((IM_TX_INT|IM_TX_EMPTY_INT)<<8) |
 	 (inw(ioaddr + INTERRUPT) & 0xff00),
 	 ioaddr + INTERRUPT);
-    
+
     /* The chip does the rest of the work. */
     outw(MC_ENQUEUE , ioaddr + MMU_CMD);
-    
+
     smc->saved_skb = NULL;
     dev_kfree_skb_irq(skb);
     dev->trans_start = jiffies;
@@ -1444,9 +1448,9 @@
 
     netif_stop_queue(dev);
 
-    DEBUG(2, "%s: smc91c92_start_xmit(length = %d) called,"
+    DEBUG(2, "%s: smc_start_xmit(length = %d) called,"
 	  " status %4.4x.\n", dev->name, skb->len, inw(ioaddr + 2));
-    
+
     if (smc->saved_skb) {
 	/* THIS SHOULD NEVER HAPPEN. */
 	smc->stats.tx_aborted_errors++;
@@ -1455,9 +1459,9 @@
 	return 1;
     }
     smc->saved_skb = skb;
-    
+
     num_pages = skb->len >> 8;
-    
+
     if (num_pages > 7) {
 	printk(KERN_ERR "%s: Far too big packet error.\n", dev->name);
 	dev_kfree_skb (skb);
@@ -1467,9 +1471,15 @@
     }
     /* A packet is now waiting. */
     smc->packets_waiting++;
-    
+
     SMC_SELECT_BANK(2);	/* Paranoia, we should always be in window 2 */
-    
+
+    /* need MC_RESET to keep the memory consistent. errata? */
+    if (smc->rx_ovrn) {
+	outw(MC_RESET, ioaddr + MMU_CMD);
+	smc->rx_ovrn = 0;
+    }
+
     /* Allocate the memory; send the packet now if we win. */
     outw(MC_ALLOC | num_pages, ioaddr + MMU_CMD);
     for (time_out = MEMORY_WAIT_TIME; time_out >= 0; time_out--) {
@@ -1481,18 +1491,18 @@
 	    return 0;
 	}
     }
-    
+
     /* Otherwise defer until the Tx-space-allocated interrupt. */
     DEBUG(2, "%s: memory allocation deferred.\n", dev->name);
     outw((IM_ALLOC_INT << 8) | (ir & 0xff00), ioaddr + INTERRUPT);
-    
+
     return 0;
 }
 
 /*======================================================================
 
     Handle a Tx anomolous event.  Entered while in Window 2.
-    
+
 ======================================================================*/
 
 static void smc_tx_err(struct net_device * dev)
@@ -1502,13 +1512,13 @@
     int saved_packet = inw(ioaddr + PNR_ARR) & 0xff;
     int packet_no = inw(ioaddr + FIFO_PORTS) & 0x7f;
     int tx_status;
-    
+
     /* select this as the packet to read from */
     outw(packet_no, ioaddr + PNR_ARR);
-    
+
     /* read the first word from this packet */
     outw(PTR_AUTOINC | PTR_READ | 0, ioaddr + POINTER);
-    
+
     tx_status = inw(ioaddr + DATA_1);
 
     smc->stats.tx_errors++;
@@ -1518,21 +1528,21 @@
 	smc->stats.tx_aborted_errors++;
 	smc->tx_err++;
     }
-    
+
     if (tx_status & TS_SUCCESS) {
 	printk(KERN_NOTICE "%s: Successful packet caused error "
 	       "interrupt?\n", dev->name);
     }
     /* re-enable transmit */
     SMC_SELECT_BANK(0);
-    outw(inw(ioaddr + TCR) | TCR_ENABLE, ioaddr + TCR);
+    outw(inw(ioaddr + TCR) | TCR_ENABLE | smc->duplex, ioaddr + TCR);
     SMC_SELECT_BANK(2);
-    
+
     outw(MC_FREEPKT, ioaddr + MMU_CMD); 	/* Free the packet memory. */
-    
+
     /* one less packet waiting for me */
     smc->packets_waiting--;
-    
+
     outw(saved_packet, ioaddr + PNR_ARR);
     return;
 }
@@ -1544,7 +1554,7 @@
     struct smc_private *smc = dev->priv;
     ioaddr_t ioaddr = dev->base_addr;
     u_short card_stats, ephs;
-    
+
     SMC_SELECT_BANK(0);
     ephs = inw(ioaddr + EPH);
     DEBUG(2, "%s: Ethernet protocol handler interrupt, status"
@@ -1561,7 +1571,7 @@
     card_stats >>= 4;			/* excess deferred */
 #endif
     /* If we had a transmit error we must re-enable the transmitter. */
-    outw(inw(ioaddr + TCR) | TCR_ENABLE, ioaddr + TCR);
+    outw(inw(ioaddr + TCR) | TCR_ENABLE | smc->duplex, ioaddr + TCR);
 
     /* Clear a link error interrupt. */
     SMC_SELECT_BANK(1);
@@ -1572,7 +1582,7 @@
 }
 
 /*====================================================================*/
-    
+
 static void smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
     struct smc_private *smc = dev_id;
@@ -1584,10 +1594,10 @@
     if (!netif_device_present(dev))
 	return;
     ioaddr = dev->base_addr;
-    
+
     DEBUG(3, "%s: SMC91c92 interrupt %d at %#x.\n", dev->name,
 	  irq, ioaddr);
-    
+
     smc->watchdog = 0;
     saved_bank = inw(ioaddr + BANK_SELECT);
     if ((saved_bank & 0xff00) != 0x3300) {
@@ -1597,13 +1607,13 @@
 	      "/ejected device.\n", dev->name, irq);
 	goto irq_done;
     }
-    
+
     SMC_SELECT_BANK(2);
     saved_pointer = inw(ioaddr + POINTER);
     mask = inw(ioaddr + INTERRUPT) >> 8;
     /* clear all interrupts */
     outw(0, ioaddr + INTERRUPT);
-    
+
     do { /* read the status flag, and mask it */
 	status = inw(ioaddr + INTERRUPT) & 0xff;
 	DEBUG(3, "%s: Status is %#2.2x (mask %#2.2x).\n", dev->name,
@@ -1629,18 +1639,20 @@
 	if (status & IM_ALLOC_INT) {
 	    /* Clear this interrupt so it doesn't happen again */
 	    mask &= ~IM_ALLOC_INT;
-	    
+	
 	    smc_hardware_send_packet(dev);
-	    
+	
 	    /* enable xmit interrupts based on this */
 	    mask |= (IM_TX_EMPTY_INT | IM_TX_INT);
-	    
+	
 	    /* and let the card send more packets to me */
 	    netif_wake_queue(dev);
 	}
 	if (status & IM_RX_OVRN_INT) {
 	    smc->stats.rx_errors++;
-	    smc->stats.rx_fifo_errors++;		
+	    smc->stats.rx_fifo_errors++;
+	    if (smc->duplex)
+		smc->rx_ovrn = 1; /* need MC_RESET outside smc_interrupt */
 	    outw(IM_RX_OVRN_INT, ioaddr + INTERRUPT);
 	}
 	if (status & IM_EPH_INT)
@@ -1649,7 +1661,7 @@
 
     DEBUG(3, "  Restoring saved registers mask %2.2x bank %4.4x"
 	  " pointer %4.4x.\n", mask, saved_bank, saved_pointer);
-    
+
     /* restore state register */
     outw((mask<<8), ioaddr + INTERRUPT);
     outw(saved_pointer, ioaddr + POINTER);
@@ -1658,7 +1670,7 @@
     DEBUG(3, "%s: Exiting interrupt IRQ%d.\n", dev->name, irq);
 
 irq_done:
-    
+
     if ((smc->manfid == MANFID_OSITECH) &&
 	(smc->cardid != PRODID_OSITECH_SEVEN)) {
 	/* Retrigger interrupt if needed */
@@ -1691,15 +1703,15 @@
     int rx_status;
     int packet_length;	/* Caution: not frame length, rather words
 			   to transfer from the chip. */
-    
+
     /* Assertion: we are in Window 2. */
-    
+
     if (inw(ioaddr + FIFO_PORTS) & FP_RXEMPTY) {
 	printk(KERN_ERR "%s: smc_rx() with nothing on Rx FIFO.\n",
 	       dev->name);
 	return;
     }
-    
+
     /*  Reset the read pointer, and read the status and packet length. */
     outw(PTR_READ | PTR_RCV | PTR_AUTOINC, ioaddr + POINTER);
     rx_status = inw(ioaddr + DATA_1);
@@ -1707,7 +1719,7 @@
 
     DEBUG(2, "%s: Receive status %4.4x length %d.\n",
 	  dev->name, rx_status, packet_length);
-    
+
     if (!(rx_status & RS_ERRORS)) {		
 	/* do stuff to make a new packet */
 	struct sk_buff *skb;
@@ -1725,7 +1737,7 @@
 	packet_length -= (rx_status & RS_ODDFRAME ? 5 : 6);
 	skb_reserve(skb, 2);
 	insw(ioaddr+DATA_1, skb_put(skb, packet_length),
-		(packet_length+1)>>1);
+	     (packet_length+1)>>1);
 	skb->protocol = eth_type_trans(skb, dev);
 	
 	skb->dev = dev;
@@ -1746,31 +1758,30 @@
     }
     /* Let the MMU free the memory of this packet. */
     outw(MC_RELEASE, ioaddr + MMU_CMD);
-    
+
     return;
 }
 
 /*====================================================================*/
 
-static struct net_device_stats *smc91c92_get_stats(struct net_device *dev)
+static struct net_device_stats *smc_get_stats(struct net_device *dev)
 {
     struct smc_private *smc = (struct smc_private *)dev->priv;
     /* Nothing to update - the 91c92 is a pretty primative chip. */
     return &smc->stats;
 }
 
-
 /*======================================================================
-  
+
     Calculate values for the hardware multicast filter hash table.
-    
+
 ======================================================================*/
 
 static void fill_multicast_tbl(int count, struct dev_mc_list *addrs,
 			       u_char *multicast_table)
 {
     struct dev_mc_list	*mc_addr;
-    
+
     for (mc_addr = addrs;  mc_addr && --count > 0;  mc_addr = mc_addr->next) {
 	u_int position = ether_crc(6, mc_addr->dmi_addr);
 #ifndef final_version		/* Verify multicast address. */
@@ -1782,14 +1793,14 @@
 }
 
 /*======================================================================
-  
+
     Set the receive mode.
-    
+
     This routine is used by both the protocol level to notify us of
     promiscuous/multicast mode changes, and by the open/reset code to
     initialize the Rx registers.  We always set the multicast list and
     leave the receiver running.
-    
+
 ======================================================================*/
 
 static void set_rx_mode(struct net_device *dev)
@@ -1799,7 +1810,7 @@
     u_int multicast_table[ 2 ] = { 0, };
     unsigned long flags;
     u_short rx_cfg_setting;
-    
+
     if (dev->flags & IFF_PROMISC) {
 	printk(KERN_NOTICE "%s: setting Rx mode to promiscuous.\n", dev->name);
 	rx_cfg_setting = RxStripCRC | RxEnable | RxPromisc | RxAllMulti;
@@ -1812,7 +1823,7 @@
 	}
 	rx_cfg_setting = RxStripCRC | RxEnable;
     }
-    
+
     /* Load MC table and Rx setting into the chip without interrupts. */
     spin_lock_irqsave(&smc->lock, flags);
     SMC_SELECT_BANK(3);
@@ -1822,14 +1833,14 @@
     outw(rx_cfg_setting, ioaddr + RCR);
     SMC_SELECT_BANK(2);
     spin_unlock_irqrestore(&smc->lock, flags);
- 
+
     return;
 }
 
 /*======================================================================
 
     Senses when a card's config changes. Here, it's coax or TP.
- 
+
 ======================================================================*/
 
 static int s9k_config(struct net_device *dev, struct ifmap *map)
@@ -1889,18 +1900,18 @@
     int i;
 
     DEBUG(0, "%s: smc91c92 reset called.\n", dev->name);
-    
+
     /* The first interaction must be a write to bring the chip out
        of sleep mode. */
     SMC_SELECT_BANK(0);
     /* Reset the chip. */
     outw(RCR_SOFTRESET, ioaddr + RCR);
     udelay(10);
-    
+
     /* Clear the transmit and receive configuration registers. */
     outw(RCR_CLEAR, ioaddr + RCR);
     outw(TCR_CLEAR, ioaddr + TCR);
-    
+
     /* Set the Window 1 control, configuration and station addr registers.
        No point in writing the I/O base register ;-> */
     SMC_SELECT_BANK(1);
@@ -1914,32 +1925,35 @@
 	outw((dev->if_port == 2 ? OSI_AUI_PWR : 0) |
 	     (inw(ioaddr-0x10+OSITECH_AUI_PWR) & 0xff00),
 	     ioaddr - 0x10 + OSITECH_AUI_PWR);
-    
+
     /* Fill in the physical address.  The databook is wrong about the order! */
     for (i = 0; i < 6; i += 2)
 	outw((dev->dev_addr[i+1]<<8)+dev->dev_addr[i],
 	     ioaddr + ADDR0 + i);
-    
+
     /* Reset the MMU */
     SMC_SELECT_BANK(2);
     outw(MC_RESET, ioaddr + MMU_CMD);
     outw(0, ioaddr + INTERRUPT);
-    
+
     /* Re-enable the chip. */
     SMC_SELECT_BANK(0);
     outw(((smc->cfg & CFG_MII_SELECT) ? 0 : TCR_MONCSN) |
-	 TCR_ENABLE | TCR_PAD_EN, ioaddr + TCR);
+	 TCR_ENABLE | TCR_PAD_EN | smc->duplex, ioaddr + TCR);
     set_rx_mode(dev);
 
     if (smc->cfg & CFG_MII_SELECT) {
 	SMC_SELECT_BANK(3);
 
 	/* Reset MII */
-	smc_mdio_write(dev, smc->mii_if.phy_id, 0, 0x8000);
+	mdio_write(dev, smc->mii_if.phy_id, 0, 0x8000);
+
+	/* Advertise 100F, 100H, 10F, 10H */
+	mdio_write(dev, smc->mii_if.phy_id, 4, 0x01e1);
 
 	/* Restart MII autonegotiation */
-	smc_mdio_write(dev, smc->mii_if.phy_id, 0, 0x0000);
-	smc_mdio_write(dev, smc->mii_if.phy_id, 0, 0x1200);
+	mdio_write(dev, smc->mii_if.phy_id, 0, 0x0000);
+	mdio_write(dev, smc->mii_if.phy_id, 0, 0x1200);
     }
 
     /* Enable interrupts. */
@@ -1951,7 +1965,7 @@
 /*======================================================================
 
     Media selection timer routine
-    
+
 ======================================================================*/
 
 static void media_check(u_long arg)
@@ -1968,12 +1982,18 @@
 	goto reschedule;
 
     SMC_SELECT_BANK(2);
+
+    /* need MC_RESET to keep the memory consistent. errata? */
+    if (smc->rx_ovrn) {
+	outw(MC_RESET, ioaddr + MMU_CMD);
+	smc->rx_ovrn = 0;
+    }
     i = inw(ioaddr + INTERRUPT);
     SMC_SELECT_BANK(0);
     media = inw(ioaddr + EPH) & EPH_LINK_OK;
     SMC_SELECT_BANK(1);
     media |= (inw(ioaddr + CONFIG) & CFG_AUI_SELECT) ? 2 : 1;
-    
+
     /* Check for pending interrupt with watchdog flag set: with
        this, we can limp along even if the interrupt is blocked */
     if (smc->watchdog++ && ((i>>8) & i)) {
@@ -1995,7 +2015,7 @@
 	    goto reschedule;
 
 	SMC_SELECT_BANK(3);
-	link = smc_mdio_read(dev, smc->mii_if.phy_id, 1);
+	link = mdio_read(dev, smc->mii_if.phy_id, 1);
 	if (!link || (link == 0xffff)) {
   	    printk(KERN_INFO "%s: MII is missing!\n", dev->name);
 	    smc->mii_if.phy_id = -1;
@@ -2004,21 +2024,23 @@
 
 	link &= 0x0004;
 	if (link != smc->link_status) {
-	    u_short p = smc_mdio_read(dev, smc->mii_if.phy_id, 5);
+	    u_short p = mdio_read(dev, smc->mii_if.phy_id, 5);
 	    printk(KERN_INFO "%s: %s link beat\n", dev->name,
 		(link) ? "found" : "lost");
+	    smc->duplex = (((p & 0x0100) || ((p & 0x1c0) == 0x40))
+			   ? TCR_FDUPLX : 0);
 	    if (link) {
 	        printk(KERN_INFO "%s: autonegotiation complete: "
-	   	    "%sbaseT-%cD selected\n", dev->name,
-		    ((p & 0x0180) ? "100" : "10"),
-		    (((p & 0x0100) || ((p & 0x1c0) == 0x40)) ? 'F' : 'H'));
+		       "%sbaseT-%cD selected\n", dev->name,
+		       ((p & 0x0180) ? "100" : "10"),
+		       (smc->duplex ? 'F' : 'H'));
 	    }
+	    SMC_SELECT_BANK(0);
+	    outw(inw(ioaddr + TCR) | smc->duplex, ioaddr + TCR);
 	    smc->link_status = link;
 	}
-    }
-
-    if (smc->cfg & CFG_MII_SELECT)
 	goto reschedule;
+    }
 
     /* Ignore collisions unless we've had no rx's recently */
     if (jiffies - dev->last_rx > HZ) {
@@ -2053,7 +2075,7 @@
 	}
 	smc->media_status = media;
     }
-    
+
 reschedule:
     smc->media.expires = jiffies + HZ;
     add_timer(&smc->media);
@@ -2167,7 +2189,7 @@
 	    return -EFAULT;
 	spin_lock_irq(&smc->lock);
 	if (smc->cfg & CFG_MII_SELECT)
-	    ret = mii_ethtool_sset(&smc->mii_if, &ecmd);    
+	    ret = mii_ethtool_sset(&smc->mii_if, &ecmd);
 	else
 	    ret = smc_netdev_set_ecmd(dev, &ecmd);
 	spin_unlock_irq(&smc->lock);
@@ -2194,7 +2216,7 @@
 	    return -EFAULT;
 	return 0;
     }
-    
+
     /* set message-level */
     case ETHTOOL_SMSGLVL: {
 	struct ethtool_value edata;
@@ -2211,7 +2233,7 @@
 	else
 	    return -EOPNOTSUPP;
     }
-    
+
     default:
 	break;
     }
@@ -2233,7 +2255,7 @@
     case SIOCETHTOOL:
 	rc = smc_ethtool_ioctl(dev, (void *) rq->ifr_data);
 	break;
-    
+
     default:
 	spin_lock_irq(&smc->lock);
 	rc = generic_mii_ioctl(&smc->mii_if, mii, cmd, NULL);
@@ -2255,7 +2277,7 @@
     if (serv.Revision != CS_RELEASE_CODE) {
 	printk(KERN_ERR
 	       "smc91c92_cs: Card Services release does not match!\n");
-	return -1;
+	return -EINVAL;
     }
     register_pccard_driver(&dev_info, &smc91c92_attach, &smc91c92_detach);
     return 0;
@@ -2271,4 +2293,3 @@
 
 module_init(init_smc91c92_cs);
 module_exit(exit_smc91c92_cs);
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/pcmcia/wavelan_cs.c linux-2.4.21-pre6/drivers/net/pcmcia/wavelan_cs.c
--- linux-2.4.20/drivers/net/pcmcia/wavelan_cs.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/pcmcia/wavelan_cs.c	2003-03-26 23:49:40.000000000 +0000
@@ -707,7 +707,7 @@
   
   while(wavepoint!=NULL)
     {
-      if(wavepoint->last_seen < jiffies-CELL_TIMEOUT)
+      if(time_after(jiffies, wavepoint->last_seen + CELL_TIMEOUT))
 	{
 #ifdef WAVELAN_ROAMING_DEBUG
 	  printk(KERN_DEBUG "WaveLAN: Bye bye %.4X\n",wavepoint->nwid);
@@ -1890,7 +1890,8 @@
 }
 #endif	/* HISTOGRAM */
 
-static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+static inline int
+wl_netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
 {
 	u32 ethcmd;
 		
@@ -1933,7 +1934,7 @@
 #endif
 
   if (cmd == SIOCETHTOOL)
-    return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+    return wl_netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
 
   /* Disable interrupts & save flags */
   wv_splhi(lp, &flags);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/pcmcia/xirc2ps_cs.c linux-2.4.21-pre6/drivers/net/pcmcia/xirc2ps_cs.c
--- linux-2.4.20/drivers/net/pcmcia/xirc2ps_cs.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/pcmcia/xirc2ps_cs.c	2003-03-26 23:49:30.000000000 +0000
@@ -1548,7 +1548,6 @@
     DEBUG(1, "do_start_xmit(skb=%p, dev=%p) len=%u\n",
 	  skb, dev, pktlen);
 
-    netif_stop_queue(dev);
 
     /* adjust the packet length to min. required
      * and hope that the buffer is large enough
@@ -1558,8 +1557,14 @@
      * pad this in his buffer with random bytes
      */
     if (pktlen < ETH_ZLEN)
+    {
+        skb = skb_padto(skb, ETH_ZLEN);
+        if(skb == NULL)
+        	return 0;
 	pktlen = ETH_ZLEN;
+    }
 
+    netif_stop_queue(dev);
     SelectPage(0);
     PutWord(XIRCREG0_TRS, (u_short)pktlen+2);
     freespace = GetWord(XIRCREG0_TSO);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/pcmcia/xircom_cb.c linux-2.4.21-pre6/drivers/net/pcmcia/xircom_cb.c
--- linux-2.4.20/drivers/net/pcmcia/xircom_cb.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/pcmcia/xircom_cb.c	2003-03-26 23:49:51.000000000 +0000
@@ -285,32 +285,30 @@
 	private->lock = SPIN_LOCK_UNLOCKED;
 	dev->irq = pdev->irq;
 	dev->base_addr = private->io_port;
-	
-	
+
 	initialize_card(private);
 	read_mac_address(private);
 	setup_descriptors(private);
-	
+
 	dev->open = &xircom_open;
 	dev->hard_start_xmit = &xircom_start_xmit;
 	dev->stop = &xircom_close;
 	dev->get_stats = &xircom_get_stats;
 	dev->priv = private;
 	dev->do_ioctl = &private_ioctl;
-	pdev->driver_data = dev;
+	pci_set_drvdata(pdev, dev);
 
-	
 	/* start the transmitter to get a heartbeat */
 	/* TODO: send 2 dummy packets here */
 	tranceiver_voodoo(private);
-	
+
 	spin_lock_irqsave(&private->lock,flags);
 	  activate_transmitter(private);
 	  activate_receiver(private);
 	spin_unlock_irqrestore(&private->lock,flags);
-	
+
 	trigger_receive(private);
-	
+
 	leave("xircom_probe");
 	return 0;
 }
@@ -324,7 +322,7 @@
  */
 static void __devexit xircom_remove(struct pci_dev *pdev)
 {
-	struct net_device *dev = pdev->driver_data;
+	struct net_device *dev = pci_get_drvdata(pdev);
 	struct xircom_private *card;
 	enter("xircom_remove");
 	if (dev!=NULL) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/pcmcia/xircom_tulip_cb.c linux-2.4.21-pre6/drivers/net/pcmcia/xircom_tulip_cb.c
--- linux-2.4.20/drivers/net/pcmcia/xircom_tulip_cb.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/pcmcia/xircom_tulip_cb.c	2003-03-26 23:49:08.000000000 +0000
@@ -923,6 +923,14 @@
 	/* Calculate the next Tx descriptor entry. */
 	entry = tp->cur_tx % TX_RING_SIZE;
 
+	/* Seems to be needed even though the docs disagree */
+	if(skb->len < ETH_ZLEN)
+	{
+		skb = skb_padto(skb, ETH_ZLEN);
+		if(skb == NULL)
+			return 0;
+	}
+	
 	tp->tx_skbuff[entry] = skb;
 #ifdef CARDBUS
 	if (tp->chip_id == X3201_3) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/pcnet32.c linux-2.4.21-pre6/drivers/net/pcnet32.c
--- linux-2.4.20/drivers/net/pcnet32.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/pcnet32.c	2003-03-26 23:49:20.000000000 +0000
@@ -1486,7 +1486,9 @@
 	
 	crc = ether_crc_le(6, addrs);
 	crc = crc >> 26;
-	mcast_table [crc >> 4] |= 1 << (crc & 0xf);
+	mcast_table [crc >> 4] = le16_to_cpu(
+		le16_to_cpu(mcast_table [crc >> 4]) | (1 << (crc & 0xf))
+	);
     }
     return;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/ppp_generic.c linux-2.4.21-pre6/drivers/net/ppp_generic.c
--- linux-2.4.20/drivers/net/ppp_generic.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/ppp_generic.c	2003-03-26 23:49:30.000000000 +0000
@@ -965,11 +965,10 @@
 		if (ppp->pass_filter.filter
 		    && sk_run_filter(skb, ppp->pass_filter.filter,
 				     ppp->pass_filter.len) == 0) {
-			if (ppp->debug & 1) {
+			if (ppp->debug & 1)
 				printk(KERN_DEBUG "PPP: outbound frame not passed\n");
-				kfree_skb(skb);
-				return;
-			}
+			kfree_skb(skb);
+			return;
 		}
 		/* if this packet passes the active filter, record the time */
 		if (!(ppp->active_filter.filter
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/r8169.c linux-2.4.21-pre6/drivers/net/r8169.c
--- linux-2.4.20/drivers/net/r8169.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/r8169.c	2003-03-26 23:49:16.000000000 +0000
@@ -0,0 +1,1131 @@
+/*
+=========================================================================
+ r8169.c: A RealTek RTL-8169 Gigabit Ethernet driver for Linux kernel 2.4.x.
+ --------------------------------------------------------------------
+
+ History:
+ Feb  4 2002	- created initially by ShuChen <shuchen@realtek.com.tw>.
+ May 20 2002	- Add link status force-mode and TBI mode support.
+=========================================================================
+  1. The media can be forced in 5 modes.
+	 Command: 'insmod r8169 media = SET_MEDIA'
+	 Ex:	  'insmod r8169 media = 0x04' will force PHY to operate in 100Mpbs Half-duplex.
+	
+	 SET_MEDIA can be:
+ 		_10_Half	= 0x01
+ 		_10_Full	= 0x02
+ 		_100_Half	= 0x04
+ 		_100_Full	= 0x08
+ 		_1000_Full	= 0x10
+  
+  2. Support TBI mode.
+=========================================================================
+VERSION 1.1	<2002/10/4>
+
+	The bit4:0 of MII register 4 is called "selector field", and have to be
+	00001b to indicate support of IEEE std 802.3 during NWay process of
+	exchanging Link Code Word (FLP). 
+
+VERSION 1.2	<2002/11/30>
+
+	- Large style cleanup
+	- Use ether_crc in stock kernel (linux/crc32.h)
+	- Copy mc_filter setup code from 8139cp
+	  (includes an optimization, and avoids set_bit use)
+
+*/
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/crc32.h>
+#include <linux/init.h>
+#include <asm/io.h>
+
+#define RTL8169_VERSION "1.2"
+#define MODULENAME "r8169"
+#define RTL8169_DRIVER_NAME   MODULENAME " Gigabit Ethernet driver " RTL8169_VERSION
+#define PFX MODULENAME ": "
+
+#ifdef RTL8169_DEBUG
+#define assert(expr) \
+        if(!(expr)) {					\
+	        printk( "Assertion failed! %s,%s,%s,line=%d\n",	\
+        	#expr,__FILE__,__FUNCTION__,__LINE__);		\
+        }
+#else
+#define assert(expr) do {} while (0)
+#endif
+
+/* media options */
+#define MAX_UNITS 8
+static int media[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 };
+
+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
+static int max_interrupt_work = 20;
+
+/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
+   The RTL chips use a 64 element hash table based on the Ethernet CRC.  */
+static int multicast_filter_limit = 32;
+
+/* MAC address length*/
+#define MAC_ADDR_LEN	6
+
+/* max supported gigabit ethernet frame size -- must be at least (dev->mtu+14+4).*/
+#define MAX_ETH_FRAME_SIZE	1536
+
+#define TX_FIFO_THRESH 256	/* In bytes */
+
+#define RX_FIFO_THRESH	7	/* 7 means NO threshold, Rx buffer level before first PCI xfer.  */
+#define RX_DMA_BURST	6	/* Maximum PCI burst, '6' is 1024 */
+#define TX_DMA_BURST	6	/* Maximum PCI burst, '6' is 1024 */
+#define EarlyTxThld 	0x3F	/* 0x3F means NO early transmit */
+#define RxPacketMaxSize	0x0800	/* Maximum size supported is 16K-1 */
+#define InterFrameGap	0x03	/* 3 means InterFrameGap = the shortest one */
+
+#define NUM_TX_DESC	64	/* Number of Tx descriptor registers */
+#define NUM_RX_DESC	64	/* Number of Rx descriptor registers */
+#define RX_BUF_SIZE	1536	/* Rx Buffer size */
+
+#define RTL_MIN_IO_SIZE 0x80
+#define TX_TIMEOUT  (6*HZ)
+
+/* write/read MMIO register */
+#define RTL_W8(reg, val8)	writeb ((val8), ioaddr + (reg))
+#define RTL_W16(reg, val16)	writew ((val16), ioaddr + (reg))
+#define RTL_W32(reg, val32)	writel ((val32), ioaddr + (reg))
+#define RTL_R8(reg)		readb (ioaddr + (reg))
+#define RTL_R16(reg)		readw (ioaddr + (reg))
+#define RTL_R32(reg)		((unsigned long) readl (ioaddr + (reg)))
+
+static struct {
+	const char *name;
+} board_info[] __devinitdata = {
+	{
+"RealTek RTL8169 Gigabit Ethernet"},};
+
+static struct pci_device_id rtl8169_pci_tbl[] __devinitdata = {
+	{0x10ec, 0x8169, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0,},
+};
+
+MODULE_DEVICE_TABLE(pci, rtl8169_pci_tbl);
+
+enum RTL8169_registers {
+	MAC0 = 0,		/* Ethernet hardware address. */
+	MAR0 = 8,		/* Multicast filter. */
+	TxDescStartAddr = 0x20,
+	TxHDescStartAddr = 0x28,
+	FLASH = 0x30,
+	ERSR = 0x36,
+	ChipCmd = 0x37,
+	TxPoll = 0x38,
+	IntrMask = 0x3C,
+	IntrStatus = 0x3E,
+	TxConfig = 0x40,
+	RxConfig = 0x44,
+	RxMissed = 0x4C,
+	Cfg9346 = 0x50,
+	Config0 = 0x51,
+	Config1 = 0x52,
+	Config2 = 0x53,
+	Config3 = 0x54,
+	Config4 = 0x55,
+	Config5 = 0x56,
+	MultiIntr = 0x5C,
+	PHYAR = 0x60,
+	TBICSR = 0x64,
+	TBI_ANAR = 0x68,
+	TBI_LPAR = 0x6A,
+	PHYstatus = 0x6C,
+	RxMaxSize = 0xDA,
+	CPlusCmd = 0xE0,
+	RxDescStartAddr = 0xE4,
+	EarlyTxThres = 0xEC,
+	FuncEvent = 0xF0,
+	FuncEventMask = 0xF4,
+	FuncPresetState = 0xF8,
+	FuncForceEvent = 0xFC,
+};
+
+enum RTL8169_register_content {
+	/*InterruptStatusBits */
+	SYSErr = 0x8000,
+	PCSTimeout = 0x4000,
+	SWInt = 0x0100,
+	TxDescUnavail = 0x80,
+	RxFIFOOver = 0x40,
+	RxUnderrun = 0x20,
+	RxOverflow = 0x10,
+	TxErr = 0x08,
+	TxOK = 0x04,
+	RxErr = 0x02,
+	RxOK = 0x01,
+
+	/*RxStatusDesc */
+	RxRES = 0x00200000,
+	RxCRC = 0x00080000,
+	RxRUNT = 0x00100000,
+	RxRWT = 0x00400000,
+
+	/*ChipCmdBits */
+	CmdReset = 0x10,
+	CmdRxEnb = 0x08,
+	CmdTxEnb = 0x04,
+	RxBufEmpty = 0x01,
+
+	/*Cfg9346Bits */
+	Cfg9346_Lock = 0x00,
+	Cfg9346_Unlock = 0xC0,
+
+	/*rx_mode_bits */
+	AcceptErr = 0x20,
+	AcceptRunt = 0x10,
+	AcceptBroadcast = 0x08,
+	AcceptMulticast = 0x04,
+	AcceptMyPhys = 0x02,
+	AcceptAllPhys = 0x01,
+
+	/*RxConfigBits */
+	RxCfgFIFOShift = 13,
+	RxCfgDMAShift = 8,
+
+	/*TxConfigBits */
+	TxInterFrameGapShift = 24,
+	TxDMAShift = 8,		/* DMA burst value (0-7) is shift this many bits */
+
+	/*rtl8169_PHYstatus */
+	TBI_Enable = 0x80,
+	TxFlowCtrl = 0x40,
+	RxFlowCtrl = 0x20,
+	_1000bpsF = 0x10,
+	_100bps = 0x08,
+	_10bps = 0x04,
+	LinkStatus = 0x02,
+	FullDup = 0x01,
+
+	/*GIGABIT_PHY_registers */
+	PHY_CTRL_REG = 0,
+	PHY_STAT_REG = 1,
+	PHY_AUTO_NEGO_REG = 4,
+	PHY_1000_CTRL_REG = 9,
+
+	/*GIGABIT_PHY_REG_BIT */
+	PHY_Restart_Auto_Nego = 0x0200,
+	PHY_Enable_Auto_Nego = 0x1000,
+
+	//PHY_STAT_REG = 1;
+	PHY_Auto_Neco_Comp = 0x0020,
+
+	//PHY_AUTO_NEGO_REG = 4;
+	PHY_Cap_10_Half = 0x0020,
+	PHY_Cap_10_Full = 0x0040,
+	PHY_Cap_100_Half = 0x0080,
+	PHY_Cap_100_Full = 0x0100,
+
+	//PHY_1000_CTRL_REG = 9;
+	PHY_Cap_1000_Full = 0x0200,
+
+	PHY_Cap_Null = 0x0,
+
+	/*_MediaType*/
+	_10_Half = 0x01,
+	_10_Full = 0x02,
+	_100_Half = 0x04,
+	_100_Full = 0x08,
+	_1000_Full = 0x10,
+
+	/*_TBICSRBit*/
+	TBILinkOK = 0x02000000,
+};
+
+const static struct {
+	const char *name;
+	u8 version;		/* depend on RTL8169 docs */
+	u32 RxConfigMask;	/* should clear the bits supported by this chip */
+} rtl_chip_info[] = {
+	{
+"RTL-8169", 0x00, 0xff7e1880,},};
+
+enum _DescStatusBit {
+	OWNbit = 0x80000000,
+	EORbit = 0x40000000,
+	FSbit = 0x20000000,
+	LSbit = 0x10000000,
+};
+
+struct TxDesc {
+	u32 status;
+	u32 vlan_tag;
+	u32 buf_addr;
+	u32 buf_Haddr;
+};
+
+struct RxDesc {
+	u32 status;
+	u32 vlan_tag;
+	u32 buf_addr;
+	u32 buf_Haddr;
+};
+
+struct rtl8169_private {
+	void *mmio_addr;	/* memory map physical address */
+	struct pci_dev *pci_dev;	/* Index of PCI device  */
+	struct net_device_stats stats;	/* statistics of net device */
+	spinlock_t lock;	/* spin lock flag */
+	int chipset;
+	unsigned long cur_rx;	/* Index into the Rx descriptor buffer of next Rx pkt. */
+	unsigned long cur_tx;	/* Index into the Tx descriptor buffer of next Rx pkt. */
+	unsigned long dirty_tx;
+	unsigned char *TxDescArrays;	/* Index of Tx Descriptor buffer */
+	unsigned char *RxDescArrays;	/* Index of Rx Descriptor buffer */
+	struct TxDesc *TxDescArray;	/* Index of 256-alignment Tx Descriptor buffer */
+	struct RxDesc *RxDescArray;	/* Index of 256-alignment Rx Descriptor buffer */
+	unsigned char *RxBufferRings;	/* Index of Rx Buffer  */
+	unsigned char *RxBufferRing[NUM_RX_DESC];	/* Index of Rx Buffer array */
+	struct sk_buff *Tx_skbuff[NUM_TX_DESC];	/* Index of Transmit data buffer */
+};
+
+MODULE_AUTHOR("Realtek");
+MODULE_DESCRIPTION("RealTek RTL-8169 Gigabit Ethernet driver");
+MODULE_PARM(media, "1-" __MODULE_STRING(MAX_UNITS) "i");
+
+static int rtl8169_open(struct net_device *dev);
+static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static void rtl8169_interrupt(int irq, void *dev_instance,
+			      struct pt_regs *regs);
+static void rtl8169_init_ring(struct net_device *dev);
+static void rtl8169_hw_start(struct net_device *dev);
+static int rtl8169_close(struct net_device *dev);
+static void rtl8169_set_rx_mode(struct net_device *dev);
+static void rtl8169_tx_timeout(struct net_device *dev);
+static struct net_device_stats *rtl8169_get_stats(struct net_device *netdev);
+
+static const u16 rtl8169_intr_mask =
+    SYSErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver | TxErr | TxOK |
+    RxErr | RxOK;
+static const unsigned int rtl8169_rx_config =
+    (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift);
+
+void
+mdio_write(void *ioaddr, int RegAddr, int value)
+{
+	int i;
+
+	RTL_W32(PHYAR, 0x80000000 | (RegAddr & 0xFF) << 16 | value);
+	udelay(1000);
+
+	for (i = 2000; i > 0; i--) {
+		// Check if the RTL8169 has completed writing to the specified MII register
+		if (!(RTL_R32(PHYAR) & 0x80000000)) {
+			break;
+		} else {
+			udelay(100);
+		}
+	}
+}
+
+int
+mdio_read(void *ioaddr, int RegAddr)
+{
+	int i, value = -1;
+
+	RTL_W32(PHYAR, 0x0 | (RegAddr & 0xFF) << 16);
+	udelay(1000);
+
+	for (i = 2000; i > 0; i--) {
+		// Check if the RTL8169 has completed retrieving data from the specified MII register
+		if (RTL_R32(PHYAR) & 0x80000000) {
+			value = (int) (RTL_R32(PHYAR) & 0xFFFF);
+			break;
+		} else {
+			udelay(100);
+		}
+	}
+	return value;
+}
+
+static int __devinit
+rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
+		   void **ioaddr_out)
+{
+	void *ioaddr = NULL;
+	struct net_device *dev;
+	struct rtl8169_private *tp;
+	int rc, i;
+	unsigned long mmio_start, mmio_end, mmio_flags, mmio_len;
+	u32 tmp;
+
+	assert(pdev != NULL);
+	assert(ioaddr_out != NULL);
+
+	*ioaddr_out = NULL;
+	*dev_out = NULL;
+
+	// dev zeroed in init_etherdev 
+	dev = init_etherdev(NULL, sizeof (*tp));
+	if (dev == NULL) {
+		printk(KERN_ERR PFX "unable to alloc new ethernet\n");
+		return -ENOMEM;
+	}
+
+	SET_MODULE_OWNER(dev);
+	tp = dev->priv;
+
+	// enable device (incl. PCI PM wakeup and hotplug setup)
+	rc = pci_enable_device(pdev);
+	if (rc)
+		goto err_out;
+
+	mmio_start = pci_resource_start(pdev, 1);
+	mmio_end = pci_resource_end(pdev, 1);
+	mmio_flags = pci_resource_flags(pdev, 1);
+	mmio_len = pci_resource_len(pdev, 1);
+
+	// make sure PCI base addr 1 is MMIO
+	if (!(mmio_flags & IORESOURCE_MEM)) {
+		printk(KERN_ERR PFX
+		       "region #1 not an MMIO resource, aborting\n");
+		rc = -ENODEV;
+		goto err_out;
+	}
+	// check for weird/broken PCI region reporting
+	if (mmio_len < RTL_MIN_IO_SIZE) {
+		printk(KERN_ERR PFX "Invalid PCI region size(s), aborting\n");
+		rc = -ENODEV;
+		goto err_out;
+	}
+
+	rc = pci_request_regions(pdev, dev->name);
+	if (rc)
+		goto err_out;
+
+	// enable PCI bus-mastering
+	pci_set_master(pdev);
+
+	// ioremap MMIO region 
+	ioaddr = ioremap(mmio_start, mmio_len);
+	if (ioaddr == NULL) {
+		printk(KERN_ERR PFX "cannot remap MMIO, aborting\n");
+		rc = -EIO;
+		goto err_out_free_res;
+	}
+
+	// Soft reset the chip. 
+	RTL_W8(ChipCmd, CmdReset);
+
+	// Check that the chip has finished the reset.
+	for (i = 1000; i > 0; i--)
+		if ((RTL_R8(ChipCmd) & CmdReset) == 0)
+			break;
+		else
+			udelay(10);
+
+	// identify chip attached to board
+	tmp = RTL_R32(TxConfig);
+	tmp = ((tmp & 0x7c000000) + ((tmp & 0x00800000) << 2)) >> 24;
+
+	for (i = ARRAY_SIZE(rtl_chip_info) - 1; i >= 0; i--)
+		if (tmp == rtl_chip_info[i].version) {
+			tp->chipset = i;
+			goto match;
+		}
+	//if unknown chip, assume array element #0, original RTL-8169 in this case
+	printk(KERN_DEBUG PFX
+	       "PCI device %s: unknown chip version, assuming RTL-8169\n",
+	       pdev->slot_name);
+	printk(KERN_DEBUG PFX "PCI device %s: TxConfig = 0x%lx\n",
+	       pdev->slot_name, (unsigned long) RTL_R32(TxConfig));
+	tp->chipset = 0;
+
+match:
+	*ioaddr_out = ioaddr;
+	*dev_out = dev;
+	return 0;
+
+err_out_free_res:
+	pci_release_regions(pdev);
+
+err_out:
+	unregister_netdev(dev);
+	kfree(dev);
+	return rc;
+}
+
+static int __devinit
+rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	struct net_device *dev = NULL;
+	struct rtl8169_private *tp = NULL;
+	void *ioaddr = NULL;
+	static int board_idx = -1;
+	static int printed_version = 0;
+	int i;
+	int option = -1, Cap10_100 = 0, Cap1000 = 0;
+
+	assert(pdev != NULL);
+	assert(ent != NULL);
+
+	board_idx++;
+
+	if (!printed_version) {
+		printk(KERN_INFO RTL8169_DRIVER_NAME " loaded\n");
+		printed_version = 1;
+	}
+
+	i = rtl8169_init_board(pdev, &dev, &ioaddr);
+	if (i < 0) {
+		return i;
+	}
+
+	tp = dev->priv;
+	assert(ioaddr != NULL);
+	assert(dev != NULL);
+	assert(tp != NULL);
+
+	// Get MAC address //
+	for (i = 0; i < MAC_ADDR_LEN; i++) {
+		dev->dev_addr[i] = RTL_R8(MAC0 + i);
+	}
+
+	dev->open = rtl8169_open;
+	dev->hard_start_xmit = rtl8169_start_xmit;
+	dev->get_stats = rtl8169_get_stats;
+	dev->stop = rtl8169_close;
+	dev->tx_timeout = rtl8169_tx_timeout;
+	dev->set_multicast_list = rtl8169_set_rx_mode;
+	dev->watchdog_timeo = TX_TIMEOUT;
+	dev->irq = pdev->irq;
+	dev->base_addr = (unsigned long) ioaddr;
+//      dev->do_ioctl           = mii_ioctl;
+
+	tp = dev->priv;		// private data //
+	tp->pci_dev = pdev;
+	tp->mmio_addr = ioaddr;
+
+	printk(KERN_DEBUG "%s: Identified chip type is '%s'.\n", dev->name,
+	       rtl_chip_info[tp->chipset].name);
+
+	spin_lock_init(&tp->lock);
+
+	pci_set_drvdata(pdev, dev);
+
+	printk(KERN_INFO "%s: %s at 0x%lx, "
+	       "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
+	       "IRQ %d\n",
+	       dev->name,
+	       board_info[ent->driver_data].name,
+	       dev->base_addr,
+	       dev->dev_addr[0], dev->dev_addr[1],
+	       dev->dev_addr[2], dev->dev_addr[3],
+	       dev->dev_addr[4], dev->dev_addr[5], dev->irq);
+
+	// if TBI is not endbled
+	if (!(RTL_R8(PHYstatus) & TBI_Enable)) {
+		int val = mdio_read(ioaddr, PHY_AUTO_NEGO_REG);
+
+		option = (board_idx >= MAX_UNITS) ? 0 : media[board_idx];
+		// Force RTL8169 in 10/100/1000 Full/Half mode.
+		if (option > 0) {
+			printk(KERN_INFO "%s: Force-mode Enabled.\n",
+			       dev->name);
+			Cap10_100 = 0, Cap1000 = 0;
+			switch (option) {
+			case _10_Half:
+				Cap10_100 = PHY_Cap_10_Half;
+				Cap1000 = PHY_Cap_Null;
+				break;
+			case _10_Full:
+				Cap10_100 = PHY_Cap_10_Full;
+				Cap1000 = PHY_Cap_Null;
+				break;
+			case _100_Half:
+				Cap10_100 = PHY_Cap_100_Half;
+				Cap1000 = PHY_Cap_Null;
+				break;
+			case _100_Full:
+				Cap10_100 = PHY_Cap_100_Full;
+				Cap1000 = PHY_Cap_Null;
+				break;
+			case _1000_Full:
+				Cap10_100 = PHY_Cap_Null;
+				Cap1000 = PHY_Cap_1000_Full;
+				break;
+			default:
+				break;
+			}
+			mdio_write(ioaddr, PHY_AUTO_NEGO_REG, Cap10_100 | (val & 0x1F));	//leave PHY_AUTO_NEGO_REG bit4:0 unchanged
+			mdio_write(ioaddr, PHY_1000_CTRL_REG, Cap1000);
+		} else {
+			printk(KERN_INFO "%s: Auto-negotiation Enabled.\n",
+			       dev->name);
+
+			// enable 10/100 Full/Half Mode, leave PHY_AUTO_NEGO_REG bit4:0 unchanged
+			mdio_write(ioaddr, PHY_AUTO_NEGO_REG,
+				   PHY_Cap_10_Half | PHY_Cap_10_Full |
+				   PHY_Cap_100_Half | PHY_Cap_100_Full | (val &
+									  0x1F));
+
+			// enable 1000 Full Mode
+			mdio_write(ioaddr, PHY_1000_CTRL_REG,
+				   PHY_Cap_1000_Full);
+
+		}
+
+		// Enable auto-negotiation and restart auto-nigotiation
+		mdio_write(ioaddr, PHY_CTRL_REG,
+			   PHY_Enable_Auto_Nego | PHY_Restart_Auto_Nego);
+		udelay(100);
+
+		// wait for auto-negotiation process
+		for (i = 10000; i > 0; i--) {
+			//check if auto-negotiation complete
+			if (mdio_read(ioaddr, PHY_STAT_REG) &
+			    PHY_Auto_Neco_Comp) {
+				udelay(100);
+				option = RTL_R8(PHYstatus);
+				if (option & _1000bpsF) {
+					printk(KERN_INFO
+					       "%s: 1000Mbps Full-duplex operation.\n",
+					       dev->name);
+				} else {
+					printk(KERN_INFO
+					       "%s: %sMbps %s-duplex operation.\n",
+					       dev->name,
+					       (option & _100bps) ? "100" :
+					       "10",
+					       (option & FullDup) ? "Full" :
+					       "Half");
+				}
+				break;
+			} else {
+				udelay(100);
+			}
+		}		// end for-loop to wait for auto-negotiation process
+
+	} else {
+		udelay(100);
+		printk(KERN_INFO
+		       "%s: 1000Mbps Full-duplex operation, TBI Link %s!\n",
+		       dev->name,
+		       (RTL_R32(TBICSR) & TBILinkOK) ? "OK" : "Failed");
+
+	}
+
+	return 0;
+}
+
+static void __devexit
+rtl8169_remove_one(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct rtl8169_private *tp = (struct rtl8169_private *) (dev->priv);
+
+	assert(dev != NULL);
+	assert(tp != NULL);
+
+	unregister_netdev(dev);
+	iounmap(tp->mmio_addr);
+	pci_release_regions(pdev);
+
+	// poison memory before freeing 
+	memset(dev, 0xBC,
+	       sizeof (struct net_device) + sizeof (struct rtl8169_private));
+
+	kfree(dev);
+	pci_set_drvdata(pdev, NULL);
+}
+
+static int
+rtl8169_open(struct net_device *dev)
+{
+	struct rtl8169_private *tp = dev->priv;
+	int retval;
+	u8 diff;
+	u32 TxPhyAddr, RxPhyAddr;
+
+	retval =
+	    request_irq(dev->irq, rtl8169_interrupt, SA_SHIRQ, dev->name, dev);
+	if (retval) {
+		return retval;
+	}
+
+	tp->TxDescArrays =
+	    kmalloc(NUM_TX_DESC * sizeof (struct TxDesc) + 256, GFP_KERNEL);
+	// Tx Desscriptor needs 256 bytes alignment;
+	TxPhyAddr = virt_to_bus(tp->TxDescArrays);
+	diff = 256 - (TxPhyAddr - ((TxPhyAddr >> 8) << 8));
+	TxPhyAddr += diff;
+	tp->TxDescArray = (struct TxDesc *) (tp->TxDescArrays + diff);
+
+	tp->RxDescArrays =
+	    kmalloc(NUM_RX_DESC * sizeof (struct RxDesc) + 256, GFP_KERNEL);
+	// Rx Desscriptor needs 256 bytes alignment;
+	RxPhyAddr = virt_to_bus(tp->RxDescArrays);
+	diff = 256 - (RxPhyAddr - ((RxPhyAddr >> 8) << 8));
+	RxPhyAddr += diff;
+	tp->RxDescArray = (struct RxDesc *) (tp->RxDescArrays + diff);
+
+	if (tp->TxDescArrays == NULL || tp->RxDescArrays == NULL) {
+		printk(KERN_INFO
+		       "Allocate RxDescArray or TxDescArray failed\n");
+		free_irq(dev->irq, dev);
+		if (tp->TxDescArrays)
+			kfree(tp->TxDescArrays);
+		if (tp->RxDescArrays)
+			kfree(tp->RxDescArrays);
+		return -ENOMEM;
+	}
+	tp->RxBufferRings = kmalloc(RX_BUF_SIZE * NUM_RX_DESC, GFP_KERNEL);
+	if (tp->RxBufferRings == NULL) {
+		printk(KERN_INFO "Allocate RxBufferRing failed\n");
+	}
+
+	rtl8169_init_ring(dev);
+	rtl8169_hw_start(dev);
+
+	return 0;
+
+}
+
+static void
+rtl8169_hw_start(struct net_device *dev)
+{
+	struct rtl8169_private *tp = dev->priv;
+	void *ioaddr = tp->mmio_addr;
+	u32 i;
+
+	/* Soft reset the chip. */
+	RTL_W8(ChipCmd, CmdReset);
+
+	/* Check that the chip has finished the reset. */
+	for (i = 1000; i > 0; i--) {
+		if ((RTL_R8(ChipCmd) & CmdReset) == 0)
+			break;
+		else
+			udelay(10);
+	}
+
+	RTL_W8(Cfg9346, Cfg9346_Unlock);
+	RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+	RTL_W8(EarlyTxThres, EarlyTxThld);
+
+	// For gigabit rtl8169
+	RTL_W16(RxMaxSize, RxPacketMaxSize);
+
+	// Set Rx Config register
+	i = rtl8169_rx_config | (RTL_R32(RxConfig) & rtl_chip_info[tp->chipset].
+				 RxConfigMask);
+	RTL_W32(RxConfig, i);
+
+	/* Set DMA burst size and Interframe Gap Time */
+	RTL_W32(TxConfig,
+		(TX_DMA_BURST << TxDMAShift) | (InterFrameGap <<
+						TxInterFrameGapShift));
+
+	tp->cur_rx = 0;
+
+	RTL_W32(TxDescStartAddr, virt_to_bus(tp->TxDescArray));
+	RTL_W32(RxDescStartAddr, virt_to_bus(tp->RxDescArray));
+	RTL_W8(Cfg9346, Cfg9346_Lock);
+	udelay(10);
+
+	RTL_W32(RxMissed, 0);
+
+	rtl8169_set_rx_mode(dev);
+
+	/* no early-rx interrupts */
+	RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
+
+	/* Enable all known interrupts by setting the interrupt mask. */
+	RTL_W16(IntrMask, rtl8169_intr_mask);
+
+	netif_start_queue(dev);
+
+}
+
+static void
+rtl8169_init_ring(struct net_device *dev)
+{
+	struct rtl8169_private *tp = dev->priv;
+	int i;
+
+	tp->cur_rx = 0;
+	tp->cur_tx = 0;
+	tp->dirty_tx = 0;
+	memset(tp->TxDescArray, 0x0, NUM_TX_DESC * sizeof (struct TxDesc));
+	memset(tp->RxDescArray, 0x0, NUM_RX_DESC * sizeof (struct RxDesc));
+
+	for (i = 0; i < NUM_TX_DESC; i++) {
+		tp->Tx_skbuff[i] = NULL;
+	}
+	for (i = 0; i < NUM_RX_DESC; i++) {
+		if (i == (NUM_RX_DESC - 1))
+			tp->RxDescArray[i].status =
+			    (OWNbit | EORbit) + RX_BUF_SIZE;
+		else
+			tp->RxDescArray[i].status = OWNbit + RX_BUF_SIZE;
+
+		tp->RxBufferRing[i] = &(tp->RxBufferRings[i * RX_BUF_SIZE]);
+		tp->RxDescArray[i].buf_addr = virt_to_bus(tp->RxBufferRing[i]);
+	}
+}
+
+static void
+rtl8169_tx_clear(struct rtl8169_private *tp)
+{
+	int i;
+
+	tp->cur_tx = 0;
+	for (i = 0; i < NUM_TX_DESC; i++) {
+		if (tp->Tx_skbuff[i] != NULL) {
+			dev_kfree_skb(tp->Tx_skbuff[i]);
+			tp->Tx_skbuff[i] = NULL;
+			tp->stats.tx_dropped++;
+		}
+	}
+}
+
+static void
+rtl8169_tx_timeout(struct net_device *dev)
+{
+	struct rtl8169_private *tp = dev->priv;
+	void *ioaddr = tp->mmio_addr;
+	u8 tmp8;
+
+	/* disable Tx, if not already */
+	tmp8 = RTL_R8(ChipCmd);
+	if (tmp8 & CmdTxEnb)
+		RTL_W8(ChipCmd, tmp8 & ~CmdTxEnb);
+
+	/* Disable interrupts by clearing the interrupt mask. */
+	RTL_W16(IntrMask, 0x0000);
+
+	/* Stop a shared interrupt from scavenging while we are. */
+	spin_lock_irq(&tp->lock);
+	rtl8169_tx_clear(tp);
+	spin_unlock_irq(&tp->lock);
+
+	/* ...and finally, reset everything */
+	rtl8169_hw_start(dev);
+
+	netif_wake_queue(dev);
+}
+
+static int
+rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct rtl8169_private *tp = dev->priv;
+	void *ioaddr = tp->mmio_addr;
+	int entry = tp->cur_tx % NUM_TX_DESC;
+
+	if(skb->len < ETH_ZLEN)
+	{
+		skb = skb_padto(skb, ETH_ZLEN);
+		if(skb == NULL)
+			return 0;
+	}
+	
+	spin_lock_irq(&tp->lock);
+
+	if ((tp->TxDescArray[entry].status & OWNbit) == 0) {
+		tp->Tx_skbuff[entry] = skb;
+		tp->TxDescArray[entry].buf_addr = virt_to_bus(skb->data);
+		if (entry != (NUM_TX_DESC - 1))
+			tp->TxDescArray[entry].status =
+			    (OWNbit | FSbit | LSbit) | ((skb->len > ETH_ZLEN) ?
+							skb->len : ETH_ZLEN);
+		else
+			tp->TxDescArray[entry].status =
+			    (OWNbit | EORbit | FSbit | LSbit) |
+			    ((skb->len > ETH_ZLEN) ? skb->len : ETH_ZLEN);
+
+		RTL_W8(TxPoll, 0x40);	//set polling bit
+
+		dev->trans_start = jiffies;
+
+		tp->cur_tx++;
+	}
+
+	spin_unlock_irq(&tp->lock);
+
+	if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx) {
+		netif_stop_queue(dev);
+	}
+
+	return 0;
+}
+
+static void
+rtl8169_tx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
+		     void *ioaddr)
+{
+	unsigned long dirty_tx, tx_left = 0;
+	int entry = tp->cur_tx % NUM_TX_DESC;
+
+	assert(dev != NULL);
+	assert(tp != NULL);
+	assert(ioaddr != NULL);
+
+	dirty_tx = tp->dirty_tx;
+	tx_left = tp->cur_tx - dirty_tx;
+
+	while (tx_left > 0) {
+		if ((tp->TxDescArray[entry].status & OWNbit) == 0) {
+			dev_kfree_skb_irq(tp->
+					  Tx_skbuff[dirty_tx % NUM_TX_DESC]);
+			tp->Tx_skbuff[dirty_tx % NUM_TX_DESC] = NULL;
+			tp->stats.tx_packets++;
+			dirty_tx++;
+			tx_left--;
+			entry++;
+		}
+	}
+
+	if (tp->dirty_tx != dirty_tx) {
+		tp->dirty_tx = dirty_tx;
+		if (netif_queue_stopped(dev))
+			netif_wake_queue(dev);
+	}
+}
+
+static void
+rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
+		     void *ioaddr)
+{
+	int cur_rx;
+	struct sk_buff *skb;
+	int pkt_size = 0;
+
+	assert(dev != NULL);
+	assert(tp != NULL);
+	assert(ioaddr != NULL);
+
+	cur_rx = tp->cur_rx;
+
+	while ((tp->RxDescArray[cur_rx].status & OWNbit) == 0) {
+
+		if (tp->RxDescArray[cur_rx].status & RxRES) {
+			printk(KERN_INFO "%s: Rx ERROR!!!\n", dev->name);
+			tp->stats.rx_errors++;
+			if (tp->RxDescArray[cur_rx].status & (RxRWT | RxRUNT))
+				tp->stats.rx_length_errors++;
+			if (tp->RxDescArray[cur_rx].status & RxCRC)
+				tp->stats.rx_crc_errors++;
+		} else {
+			pkt_size =
+			    (int) (tp->RxDescArray[cur_rx].
+				   status & 0x00001FFF) - 4;
+			skb = dev_alloc_skb(pkt_size + 2);
+			if (skb != NULL) {
+				skb->dev = dev;
+				skb_reserve(skb, 2);	// 16 byte align the IP fields. //
+				eth_copy_and_sum(skb, tp->RxBufferRing[cur_rx],
+						 pkt_size, 0);
+				skb_put(skb, pkt_size);
+				skb->protocol = eth_type_trans(skb, dev);
+				netif_rx(skb);
+
+				if (cur_rx == (NUM_RX_DESC - 1))
+					tp->RxDescArray[cur_rx].status =
+					    (OWNbit | EORbit) + RX_BUF_SIZE;
+				else
+					tp->RxDescArray[cur_rx].status =
+					    OWNbit + RX_BUF_SIZE;
+
+				tp->RxDescArray[cur_rx].buf_addr =
+				    virt_to_bus(tp->RxBufferRing[cur_rx]);
+				dev->last_rx = jiffies;
+				tp->stats.rx_bytes += pkt_size;
+				tp->stats.rx_packets++;
+			} else {
+				printk(KERN_WARNING
+				       "%s: Memory squeeze, deferring packet.\n",
+				       dev->name);
+				/* We should check that some rx space is free.
+				   If not, free one and mark stats->rx_dropped++. */
+				tp->stats.rx_dropped++;
+			}
+		}
+
+		cur_rx = (cur_rx + 1) % NUM_RX_DESC;
+
+	}
+
+	tp->cur_rx = cur_rx;
+}
+
+/* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */
+static void
+rtl8169_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+{
+	struct net_device *dev = (struct net_device *) dev_instance;
+	struct rtl8169_private *tp = dev->priv;
+	int boguscnt = max_interrupt_work;
+	void *ioaddr = tp->mmio_addr;
+	int status = 0;
+
+	do {
+		status = RTL_R16(IntrStatus);
+
+		/* h/w no longer present (hotplug?) or major error, bail */
+		if (status == 0xFFFF)
+			break;
+
+/*
+		if (status & RxUnderrun)
+			link_changed = RTL_R16 (CSCR) & CSCR_LinkChangeBit;
+*/
+		RTL_W16(IntrStatus,
+			(status & RxFIFOOver) ? (status | RxOverflow) : status);
+
+		if ((status &
+		     (SYSErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver
+		      | TxErr | TxOK | RxErr | RxOK)) == 0)
+			break;
+
+		// Rx interrupt 
+		if (status & (RxOK | RxUnderrun | RxOverflow | RxFIFOOver)) {
+			rtl8169_rx_interrupt(dev, tp, ioaddr);
+		}
+		// Tx interrupt
+		if (status & (TxOK | TxErr)) {
+			spin_lock(&tp->lock);
+			rtl8169_tx_interrupt(dev, tp, ioaddr);
+			spin_unlock(&tp->lock);
+		}
+
+		boguscnt--;
+	} while (boguscnt > 0);
+
+	if (boguscnt <= 0) {
+		printk(KERN_WARNING "%s: Too much work at interrupt!\n",
+		       dev->name);
+		/* Clear all interrupt sources. */
+		RTL_W16(IntrStatus, 0xffff);
+	}
+}
+
+static int
+rtl8169_close(struct net_device *dev)
+{
+	struct rtl8169_private *tp = dev->priv;
+	void *ioaddr = tp->mmio_addr;
+	int i;
+
+	netif_stop_queue(dev);
+
+	spin_lock_irq(&tp->lock);
+
+	/* Stop the chip's Tx and Rx DMA processes. */
+	RTL_W8(ChipCmd, 0x00);
+
+	/* Disable interrupts by clearing the interrupt mask. */
+	RTL_W16(IntrMask, 0x0000);
+
+	/* Update the error counts. */
+	tp->stats.rx_missed_errors += RTL_R32(RxMissed);
+	RTL_W32(RxMissed, 0);
+
+	spin_unlock_irq(&tp->lock);
+
+	synchronize_irq();
+	free_irq(dev->irq, dev);
+
+	rtl8169_tx_clear(tp);
+	kfree(tp->TxDescArrays);
+	kfree(tp->RxDescArrays);
+	tp->TxDescArrays = NULL;
+	tp->RxDescArrays = NULL;
+	tp->TxDescArray = NULL;
+	tp->RxDescArray = NULL;
+	kfree(tp->RxBufferRings);
+	for (i = 0; i < NUM_RX_DESC; i++) {
+		tp->RxBufferRing[i] = NULL;
+	}
+
+	return 0;
+}
+
+static void
+rtl8169_set_rx_mode(struct net_device *dev)
+{
+	struct rtl8169_private *tp = dev->priv;
+	void *ioaddr = tp->mmio_addr;
+	unsigned long flags;
+	u32 mc_filter[2];	/* Multicast hash filter */
+	int i, rx_mode;
+	u32 tmp = 0;
+
+	if (dev->flags & IFF_PROMISC) {
+		/* Unconditionally log net taps. */
+		printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n",
+		       dev->name);
+		rx_mode =
+		    AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
+		    AcceptAllPhys;
+		mc_filter[1] = mc_filter[0] = 0xffffffff;
+	} else if ((dev->mc_count > multicast_filter_limit)
+		   || (dev->flags & IFF_ALLMULTI)) {
+		/* Too many to filter perfectly -- accept all multicasts. */
+		rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
+		mc_filter[1] = mc_filter[0] = 0xffffffff;
+	} else {
+		struct dev_mc_list *mclist;
+		rx_mode = AcceptBroadcast | AcceptMyPhys;
+		mc_filter[1] = mc_filter[0] = 0;
+		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+		     i++, mclist = mclist->next) {
+			int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
+			mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
+			rx_mode |= AcceptMulticast;
+		}
+	}
+
+	spin_lock_irqsave(&tp->lock, flags);
+
+	tmp =
+	    rtl8169_rx_config | rx_mode | (RTL_R32(RxConfig) &
+					   rtl_chip_info[tp->chipset].
+					   RxConfigMask);
+
+	RTL_W32(RxConfig, tmp);
+	RTL_W32(MAR0 + 0, mc_filter[0]);
+	RTL_W32(MAR0 + 4, mc_filter[1]);
+
+	spin_unlock_irqrestore(&tp->lock, flags);
+}
+
+struct net_device_stats *
+rtl8169_get_stats(struct net_device *dev)
+{
+	struct rtl8169_private *tp = dev->priv;
+
+	return &tp->stats;
+}
+
+static struct pci_driver rtl8169_pci_driver = {
+	.name		= MODULENAME,
+	.id_table	= rtl8169_pci_tbl,
+	.probe		= rtl8169_init_one,
+	.remove		= rtl8169_remove_one,
+	.suspend	= NULL,
+	.resume		= NULL,
+};
+
+static int __init
+rtl8169_init_module(void)
+{
+	return pci_module_init(&rtl8169_pci_driver);
+}
+
+static void __exit
+rtl8169_cleanup_module(void)
+{
+	pci_unregister_driver(&rtl8169_pci_driver);
+}
+
+module_init(rtl8169_init_module);
+module_exit(rtl8169_cleanup_module);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/saa9730.c linux-2.4.21-pre6/drivers/net/saa9730.c
--- linux-2.4.20/drivers/net/saa9730.c	2001-10-17 04:56:29.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/saa9730.c	2003-03-26 23:48:58.000000000 +0000
@@ -265,7 +265,7 @@
 	lp->NextRcvPacketIndex = 0;
 	lp->NextRcvToUseIsA = 1;
 
-	/* Set current buffer index & next availble packet index */
+	/* Set current buffer index & next available packet index */
 	lp->NextTxmPacketIndex = 0;
 	lp->NextTxmBufferIndex = 0;
 	lp->PendingTxmPacketIndex = 0;
@@ -520,7 +520,7 @@
 	lp->NextRcvPacketIndex = 0;
 	lp->NextRcvToUseIsA = 1;
 
-	/* Set current buffer index & next availble packet index */
+	/* Set current buffer index & next available packet index */
 	lp->NextTxmPacketIndex = 0;
 	lp->NextTxmBufferIndex = 0;
 	lp->PendingTxmPacketIndex = 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/seeq8005.c linux-2.4.21-pre6/drivers/net/seeq8005.c
--- linux-2.4.20/drivers/net/seeq8005.c	2001-10-17 04:56:29.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/seeq8005.c	2003-03-26 23:49:51.000000000 +0000
@@ -378,9 +378,16 @@
 static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
-	short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+	short length = skb->len;
 	unsigned char *buf = skb->data;
 
+	if(length < ETH_ZLEN)
+	{
+		skb = skb_padto(skb, ETH_ZLEN);
+		if(skb == NULL)
+			return 0;
+		length = ETH_ZLEN;
+	}
 	/* Block a timer-based transmit from overlapping */
 	netif_stop_queue(dev);
 	
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sgiseeq.c linux-2.4.21-pre6/drivers/net/sgiseeq.c
--- linux-2.4.20/drivers/net/sgiseeq.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sgiseeq.c	2003-03-26 23:49:54.000000000 +0000
@@ -537,6 +537,8 @@
 	 *    added this new entry and restarted it.
 	 */
 	memcpy((char *)(long)td->buf_vaddr, skb->data, skblen);
+	if(len != skblen)
+		memset((char *)(long)td->buf_vaddr + skb->len, 0, len-skblen);
 	td->tdma.cntinfo = (len & HPCDMA_BCNT) |
 	                   (HPCDMA_XIU | HPCDMA_EOXP | HPCDMA_XIE | HPCDMA_EOX);
 	if (sp->tx_old != sp->tx_new) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sis900.c linux-2.4.21-pre6/drivers/net/sis900.c
--- linux-2.4.20/drivers/net/sis900.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sis900.c	2003-03-26 23:49:34.000000000 +0000
@@ -30,13 +30,13 @@
    Rev 1.07.09 Feb.  9 2001 Dave Jones <davej@suse.de> PCI enable cleanup
    Rev 1.07.08 Jan.  8 2001 Lei-Chun Chang added RTL8201 PHY support
    Rev 1.07.07 Nov. 29 2000 Lei-Chun Chang added kernel-doc extractable documentation and 630 workaround fix
-   Rev 1.07.06 Nov.  7 2000 Jeff Garzik <jgarzik@mandrakesoft.com> some bug fix and cleaning
+   Rev 1.07.06 Nov.  7 2000 Jeff Garzik <jgarzik@pobox.com> some bug fix and cleaning
    Rev 1.07.05 Nov.  6 2000 metapirat<metapirat@gmx.de> contribute media type select by ifconfig
    Rev 1.07.04 Sep.  6 2000 Lei-Chun Chang added ICS1893 PHY support
    Rev 1.07.03 Aug. 24 2000 Lei-Chun Chang (lcchang@sis.com.tw) modified 630E eqaulizer workaround rule
    Rev 1.07.01 Aug. 08 2000 Ollie Lho minor update for SiS 630E and SiS 630E A1
    Rev 1.07    Mar. 07 2000 Ollie Lho bug fix in Rx buffer ring
-   Rev 1.06.04 Feb. 11 2000 Jeff Garzik <jgarzik@mandrakesoft.com> softnet and init for kernel 2.4
+   Rev 1.06.04 Feb. 11 2000 Jeff Garzik <jgarzik@pobox.com> softnet and init for kernel 2.4
    Rev 1.06.03 Dec. 23 1999 Ollie Lho Third release
    Rev 1.06.02 Nov. 23 1999 Ollie Lho bug in mac probing fixed
    Rev 1.06.01 Nov. 16 1999 Ollie Lho CRC calculation provide by Joseph Zbiciak (im14u2c@primenet.com)
@@ -532,6 +532,13 @@
 		
 		if ((mii_phy = kmalloc(sizeof(struct mii_phy), GFP_KERNEL)) == NULL) {
 			printk(KERN_INFO "Cannot allocate mem for struct mii_phy\n");
+			mii_phy = sis_priv->first_mii;
+			while (mii_phy) {
+				struct mii_phy *phy;
+				phy = mii_phy;
+				mii_phy = mii_phy->next;
+				kfree(phy);
+			}
 			return 0;
 		}
 		
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sk98lin/build_no.c linux-2.4.21-pre6/drivers/net/sk98lin/build_no.c
--- linux-2.4.20/drivers/net/sk98lin/build_no.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sk98lin/build_no.c	2003-03-26 23:48:58.000000000 +0000
@@ -0,0 +1,10 @@
+/******************************************************************************
+ *
+ *	Name:		Build_No.c
+ *	Version:	1.01
+ *
+ */
+
+static const char SysKonnectBuildNumber[] =
+	"@(#)SK-BUILD: 6.02 (20021219) PL: ALL.01";
+^Z
\ No newline at end of file
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sk98lin/h/lm80.h linux-2.4.21-pre6/drivers/net/sk98lin/h/lm80.h
--- linux-2.4.20/drivers/net/sk98lin/h/lm80.h	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sk98lin/h/lm80.h	2003-03-26 23:49:25.000000000 +0000
@@ -2,8 +2,8 @@
  *
  * Name:	lm80.h	
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.3 $
- * Date:	$Date: 1999/11/22 13:41:19 $
+ * Version:	$Revision: 1.4 $
+ * Date:	$Date: 2002/04/25 11:04:10 $
  * Purpose:	Contains all defines for the LM80 Chip
  *		(National Semiconductor).
  *
@@ -11,8 +11,7 @@
 
 /******************************************************************************
  *
- *	(C)Copyright 1998,1999 SysKonnect,
- *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *	(C)Copyright 1998-2002 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: lm80.h,v $
+ *	Revision 1.4  2002/04/25 11:04:10  rschmidt
+ *	Editorial changes
+ *	
  *	Revision 1.3  1999/11/22 13:41:19  cgoos
  *	Changed license header to GPL.
  *	
@@ -53,23 +55,23 @@
  *
  * All registers are 8 bit wide
  */
-#define	LM80_CFG		0x00	/* Configuration Register */
-#define	LM80_ISRC_1		0x01	/* Interrupt Status Register 1 */
-#define LM80_ISRC_2		0x02	/* Interrupt Status Register 2 */
-#define LM80_IMSK_1		0x03	/* Interrupt Mask Register 1 */
-#define LM80_IMSK_2		0x04	/* Interrupt Mask Register 2 */
+#define	LM80_CFG			0x00	/* Configuration Register */
+#define	LM80_ISRC_1			0x01	/* Interrupt Status Register 1 */
+#define LM80_ISRC_2			0x02	/* Interrupt Status Register 2 */
+#define LM80_IMSK_1			0x03	/* Interrupt Mask Register 1 */
+#define LM80_IMSK_2			0x04	/* Interrupt Mask Register 2 */
 #define LM80_FAN_CTRL		0x05	/* Fan Devisor/RST#/OS# Register */
 #define LM80_TEMP_CTRL		0x06	/* OS# Config, Temp Res. Reg */
 	/* 0x07 - 0x1f reserved	*/
 	/* current values */
-#define LM80_VT0_IN		0x20	/* current Voltage 0 value */
-#define LM80_VT1_IN		0x21	/* current Voltage 1 value */
-#define LM80_VT2_IN		0x22	/* current Voltage 2 value */
-#define LM80_VT3_IN		0x23	/* current Voltage 3 value */
-#define LM80_VT4_IN		0x24	/* current Voltage 4 value */
-#define LM80_VT5_IN		0x25	/* current Voltage 5 value */
-#define LM80_VT6_IN		0x26	/* current Voltage 6 value */
-#define LM80_TEMP_IN		0x27	/* current temperature value */
+#define LM80_VT0_IN			0x20	/* current Voltage 0 value */
+#define LM80_VT1_IN			0x21	/* current Voltage 1 value */
+#define LM80_VT2_IN			0x22	/* current Voltage 2 value */
+#define LM80_VT3_IN			0x23	/* current Voltage 3 value */
+#define LM80_VT4_IN			0x24	/* current Voltage 4 value */
+#define LM80_VT5_IN			0x25	/* current Voltage 5 value */
+#define LM80_VT6_IN			0x26	/* current Voltage 6 value */
+#define LM80_TEMP_IN		0x27	/* current Temperature value */
 #define LM80_FAN1_IN		0x28	/* current Fan 1 count */
 #define LM80_FAN2_IN		0x29	/* current Fan 2 count */
 	/* limit values */
@@ -111,23 +113,23 @@
 
 /*	LM80_ISRC_1		Interrupt Status Register 1 */
 /*	LM80_IMSK_1		Interrupt Mask Register 1 */
-#define LM80_IS_VT0		(1<<0)	/* limit exceeded for Voltage 0 */
-#define LM80_IS_VT1		(1<<1)	/* limit exceeded for Voltage 1 */
-#define LM80_IS_VT2		(1<<2)	/* limit exceeded for Voltage 2 */
-#define LM80_IS_VT3		(1<<3)	/* limit exceeded for Voltage 3 */
-#define LM80_IS_VT4		(1<<4)	/* limit exceeded for Voltage 4 */
-#define LM80_IS_VT5		(1<<5)	/* limit exceeded for Voltage 5 */
-#define LM80_IS_VT6		(1<<6)	/* limit exceeded for Voltage 6 */
+#define LM80_IS_VT0			(1<<0)	/* limit exceeded for Voltage 0 */
+#define LM80_IS_VT1			(1<<1)	/* limit exceeded for Voltage 1 */
+#define LM80_IS_VT2			(1<<2)	/* limit exceeded for Voltage 2 */
+#define LM80_IS_VT3			(1<<3)	/* limit exceeded for Voltage 3 */
+#define LM80_IS_VT4			(1<<4)	/* limit exceeded for Voltage 4 */
+#define LM80_IS_VT5			(1<<5)	/* limit exceeded for Voltage 5 */
+#define LM80_IS_VT6			(1<<6)	/* limit exceeded for Voltage 6 */
 #define LM80_IS_INT_IN		(1<<7)	/* state of INT_IN# */
 
 /*	LM80_ISRC_2		Interrupt Status Register 2 */
 /*	LM80_IMSK_2		Interrupt Mask Register 2 */
 #define	LM80_IS_TEMP		(1<<0)	/* HOT temperature limit exceeded */
-#define LM80_IS_BTI		(1<<1)	/* state of BTI# pin */
+#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 occured */
-#define LM80_IS_OS		(1<<5)	/* OS temperature limit exceeded */
+#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 */
 #define LM80_IS_OT_IRQ_MD	(1<<7)	/* OS temperature interrupt mode */
@@ -181,7 +183,7 @@
 /*	LM80_FAN2_COUNT_LIM	Fan 2 count limit (low) */
 	/* 0x3e - 0x3f reserved	*/
 
-#define LM80_ADDR	0x28	/* LM80 default addr */
+#define LM80_ADDR		0x28	/* LM80 default addr */
 
 /* typedefs *******************************************************************/
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sk98lin/h/skaddr.h linux-2.4.21-pre6/drivers/net/sk98lin/h/skaddr.h
--- linux-2.4.20/drivers/net/sk98lin/h/skaddr.h	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sk98lin/h/skaddr.h	2003-03-26 23:49:39.000000000 +0000
@@ -2,8 +2,8 @@
  *
  * Name:	skaddr.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.24 $
- * Date:	$Date: 2001/01/22 13:41:34 $
+ * Version:	$Revision: 1.26 $
+ * Date:	$Date: 2002/11/15 07:24:42 $
  * Purpose:	Header file for Address Management (MC, UC, Prom).
  *
  ******************************************************************************/
@@ -26,6 +26,14 @@
  * History:
  *
  *	$Log: skaddr.h,v $
+ *	Revision 1.26  2002/11/15 07:24:42  tschilli
+ *	SK_ADDR_EQUAL macro fixed.
+ *	
+ *	Revision 1.25  2002/06/10 13:55:18  tschilli
+ *	Changes for handling YUKON.
+ *	All changes are internally and not visible to the programmer
+ *	using this module.
+ *	
  *	Revision 1.24  2001/01/22 13:41:34  rassmann
  *	Supporting two nets on dual-port adapters.
  *	
@@ -144,7 +152,7 @@
 /* ----- Common return values ----- */
 
 #define SK_ADDR_SUCCESS				0	/* Function returned successfully. */
-#define SK_ADDR_ILLEGAL_PORT		100	/* Port number too high. */
+#define SK_ADDR_ILLEGAL_PORT			100	/* Port number too high. */
 #define SK_ADDR_TOO_EARLY			101	/* Function called too early. */
 
 /* ----- Clear/Add flag bits ----- */
@@ -198,6 +206,7 @@
 
 /* Macros */
 
+#if 0
 #ifndef SK_ADDR_EQUAL
 /*
  * "&" instead of "&&" allows better optimization on IA-64.
@@ -217,6 +226,23 @@
 	(*(SK_U32 *)&(((SK_U8 *)(A1))[0]) == *(SK_U32 *)&(((SK_U8 *)(A2))[0])))
 #endif	/* SK_ADDR_DWORD_COMPARE */
 #endif	/* SK_ADDR_EQUAL */
+#endif /* 0 */
+
+#ifndef SK_ADDR_EQUAL
+#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]))
+#else	/* SK_ADDR_DWORD_COMPARE */
+#define SK_ADDR_EQUAL(A1,A2)	( \
+	(*(SK_U16 *)&(((SK_U8 *)(A1))[4]) == *(SK_U16 *)&(((SK_U8 *)(A2))[4])) && \
+	(*(SK_U32 *)&(((SK_U8 *)(A1))[0]) == *(SK_U32 *)&(((SK_U8 *)(A2))[0])))
+#endif	/* SK_ADDR_DWORD_COMPARE */
+#endif	/* SK_ADDR_EQUAL */
 
 /* typedefs *******************************************************************/
 
@@ -239,13 +265,13 @@
 
 /* ----- Public part (read-only) ----- */
 
-	SK_MAC_ADDR	CurrentMacAddress;		/* Current physical MAC Address. */
+	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_MAC_ADDR	PreviousMacAddress;	/* Prev. phys. MAC Address. */
 	SK_BOOL		CurrentMacAddressSet;	/* CurrentMacAddress is set. */
 	SK_U8		Align01;
 
@@ -255,18 +281,20 @@
 	SK_U32		NextExactMatchDrv;
 	SK_MAC_ADDR	Exact[SK_ADDR_EXACT_MATCHES];
 	SK_FILTER64	InexactFilter;			/* For 64-bit hash register. */
+	SK_FILTER64	InexactRlmtFilter;		/* For 64-bit hash register. */
+	SK_FILTER64	InexactDrvFilter;		/* 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		CurrentMacAddress;	/* Logical MAC Address. */
 	SK_MAC_ADDR		PermanentMacAddress;	/* Logical MAC Address. */
 
 /* ----- Private part ----- */
 
-	SK_U32			ActivePort;				/* View of module ADDR. */
+	SK_U32			ActivePort;		/* View of module ADDR. */
 	SK_BOOL			CurrentMacAddressSet;	/* CurrentMacAddress is set. */
 	SK_U8			Align01;
 	SK_U16			Align02;
@@ -294,38 +322,86 @@
 extern	int	SkAddrInit(
 	SK_AC	*pAC,
 	SK_IOC	IoC,
-	int		Level);
+	int	Level);
 
 extern	int	SkAddrMcClear(
 	SK_AC	*pAC,
 	SK_IOC	IoC,
 	SK_U32	PortNumber,
-	int		Flags);
+	int	Flags);
+
+extern	int	SkAddrXmacMcClear(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	SK_U32	PortNumber,
+	int	Flags);
+
+extern	int	SkAddrGmacMcClear(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	SK_U32	PortNumber,
+	int	Flags);
 
 extern	int	SkAddrMcAdd(
 	SK_AC		*pAC,
 	SK_IOC		IoC,
 	SK_U32		PortNumber,
 	SK_MAC_ADDR	*pMc,
-	int			Flags);
+	int		Flags);
+
+extern	int	SkAddrXmacMcAdd(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	SK_U32		PortNumber,
+	SK_MAC_ADDR	*pMc,
+	int		Flags);
+
+extern	int	SkAddrGmacMcAdd(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	SK_U32		PortNumber,
+	SK_MAC_ADDR	*pMc,
+	int		Flags);
 
 extern	int	SkAddrMcUpdate(
 	SK_AC	*pAC,
 	SK_IOC	IoC,
 	SK_U32	PortNumber);
 
+extern	int	SkAddrXmacMcUpdate(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	SK_U32	PortNumber);
+
+extern	int	SkAddrGmacMcUpdate(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	SK_U32	PortNumber);
+
 extern	int	SkAddrOverride(
 	SK_AC		*pAC,
 	SK_IOC		IoC,
 	SK_U32		PortNumber,
 	SK_MAC_ADDR	*pNewAddr,
-	int			Flags);
+	int		Flags);
 
 extern	int	SkAddrPromiscuousChange(
 	SK_AC	*pAC,
 	SK_IOC	IoC,
 	SK_U32	PortNumber,
-	int		NewPromMode);
+	int	NewPromMode);
+
+extern	int	SkAddrXmacPromiscuousChange(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	SK_U32	PortNumber,
+	int	NewPromMode);
+
+extern	int	SkAddrGmacPromiscuousChange(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	SK_U32	PortNumber,
+	int	NewPromMode);	
 
 extern	int	SkAddrSwap(
 	SK_AC	*pAC,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sk98lin/h/skdebug.h linux-2.4.21-pre6/drivers/net/sk98lin/h/skdebug.h
--- linux-2.4.20/drivers/net/sk98lin/h/skdebug.h	2000-09-15 21:34:19.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sk98lin/h/skdebug.h	2003-03-26 23:49:39.000000000 +0000
@@ -2,16 +2,15 @@
  *
  * Name:	skdebug.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.10 $
- * Date:	$Date: 1999/11/22 13:47:40 $
+ * Version:	$Revision: 1.12 $
+ * Date:	$Date: 2002/07/15 15:37:13 $
  * Purpose:	SK specific DEBUG support
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998,1999 SysKonnect,
- *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *	(C)Copyright 1998-2002 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,13 @@
  *
  * History:
  *	$Log: skdebug.h,v $
+ *	Revision 1.12  2002/07/15 15:37:13  rschmidt
+ *	Power Management support
+ *	Editorial changes
+ *	
+ *	Revision 1.11  2002/04/25 11:04:39  rschmidt
+ *	Editorial changes
+ *	
  *	Revision 1.10  1999/11/22 13:47:40  cgoos
  *	Changed license header to GPL.
  *	
@@ -89,26 +95,25 @@
 
 #define SK_DBGMOD_MERR	0x00000001L	/* general module error indication */
 #define SK_DBGMOD_HWM	0x00000002L	/* Hardware init module */
-#define	SK_DBGMOD_RLMT	0x00000004L	/* RLMT module */
-#define	SK_DBGMOD_VPD	0x00000008L	/* VPD module */
-#define	SK_DBGMOD_I2C	0x00000010L	/* I2C module */
-#define	SK_DBGMOD_PNMI	0x00000020L	/* PNMI module */
-#define	SK_DBGMOD_CSUM	0x00000040L	/* CSUM module */
-#define	SK_DBGMOD_ADDR	0x00000080L	/* ADDR module */
+#define SK_DBGMOD_RLMT	0x00000004L	/* RLMT module */
+#define SK_DBGMOD_VPD	0x00000008L	/* VPD module */
+#define SK_DBGMOD_I2C	0x00000010L	/* I2C module */
+#define SK_DBGMOD_PNMI	0x00000020L	/* PNMI module */
+#define SK_DBGMOD_CSUM	0x00000040L	/* CSUM module */
+#define SK_DBGMOD_ADDR	0x00000080L	/* ADDR module */
 #define SK_DBGMOD_PECP	0x00000100L	/* PECP module */
+#define SK_DBGMOD_POWM	0x00000200L	/* Power Management module */
 
 /* Debug events */
 
-#define	SK_DBGCAT_INIT	0x00000001L	/* module/driver initialization */
-#define	SK_DBGCAT_CTRL	0x00000002L	/* controlling: add/rmv MCA/MAC
-					 * and other controls (IOCTL)
-					 */
-#define	SK_DBGCAT_ERR	0x00000004L	/* error handling paths */
-#define	SK_DBGCAT_TX	0x00000008L	/* transmit path */
-#define	SK_DBGCAT_RX	0x00000010L	/* receive path */
-#define	SK_DBGCAT_IRQ	0x00000020L	/* general IRQ handling */
-#define	SK_DBGCAT_QUEUE	0x00000040L	/* any queue management */
-#define	SK_DBGCAT_DUMP	0x00000080L	/* large data output e.g. hex dump */
-#define	SK_DBGCAT_FATAL	0x00000100L	/* large data output e.g. hex dump */
+#define SK_DBGCAT_INIT	0x00000001L	/* module/driver initialization */
+#define SK_DBGCAT_CTRL	0x00000002L	/* controlling devices */
+#define SK_DBGCAT_ERR	0x00000004L	/* error handling paths */
+#define SK_DBGCAT_TX	0x00000008L	/* transmit path */
+#define SK_DBGCAT_RX	0x00000010L	/* receive path */
+#define SK_DBGCAT_IRQ	0x00000020L	/* general IRQ handling */
+#define SK_DBGCAT_QUEUE	0x00000040L	/* any queue management */
+#define SK_DBGCAT_DUMP	0x00000080L	/* large data output e.g. hex dump */
+#define SK_DBGCAT_FATAL	0x00000100L	/* fatal error */
 
 #endif	/* __INC_SKDEBUG_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sk98lin/h/skdrv1st.h linux-2.4.21-pre6/drivers/net/sk98lin/h/skdrv1st.h
--- linux-2.4.20/drivers/net/sk98lin/h/skdrv1st.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sk98lin/h/skdrv1st.h	2003-03-26 23:48:58.000000000 +0000
@@ -2,8 +2,8 @@
  *
  * Name:	skdrv1st.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.9.2.1 $
- * Date:	$Date: 2001/03/12 16:50:59 $
+ * Version:	$Revision: 1.9.2.2 $
+ * Date:	$Date: 2001/12/07 12:06:42 $
  * Purpose:	First header file for driver and all other modules
  *
  ******************************************************************************/
@@ -27,6 +27,9 @@
  * History:
  *
  *	$Log: skdrv1st.h,v $
+ *	Revision 1.9.2.2  2001/12/07 12:06:42  mlindner
+ *	Fix: malloc -> slab changes
+ *	
  *	Revision 1.9.2.1  2001/03/12 16:50:59  mlindner
  *	chg: kernel 2.4 adaption
  *	
@@ -84,6 +87,10 @@
 #ifndef __INC_SKDRV1ST_H
 #define __INC_SKDRV1ST_H
 
+/* Check kernel version */
+#include <linux/version.h>
+#if (LINUX_VERSION_CODE > 0x020300)
+#endif
 
 typedef struct s_AC	SK_AC;
 
@@ -116,7 +123,6 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
-#include <linux/crc32.h>
 #include <asm/byteorder.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -140,6 +146,8 @@
 #define SK_BIG_ENDIAN
 #endif
 
+#define SK_NET_DEVICE	net_device
+
 
 /* we use gethrtime(), return unit: nanoseconds */
 #define SK_TICKS_PER_SEC	HZ
@@ -161,17 +169,17 @@
 #define SK_MEMCPY(dest,src,size)	memcpy(dest,src,size)
 #define SK_MEMCMP(s1,s2,size)		memcmp(s1,s2,size)
 #define SK_MEMSET(dest,val,size)	memset(dest,val,size)
-#define SK_STRLEN(pStr)			strlen((char*)pStr)
-#define SK_STRNCPY(pDest,pSrc,size)	strncpy((char*)pDest,(char*)pSrc,size)
-#define SK_STRCMP(pStr1,pStr2)		strcmp((char*)pStr1,(char*)pStr2)
+#define SK_STRLEN(pStr)			strlen((char*)(pStr))
+#define SK_STRNCPY(pDest,pSrc,size)	strncpy((char*)(pDest),(char*)(pSrc),size)
+#define SK_STRCMP(pStr1,pStr2)		strcmp((char*)(pStr1),(char*)(pStr2))
 
 /* macros to access the adapter */
-#define SK_OUT8(b,a,v)		writeb(v, (b+a))	
-#define SK_OUT16(b,a,v)		writew(v, (b+a))	
-#define SK_OUT32(b,a,v)		writel(v, (b+a))	
-#define SK_IN8(b,a,pv)		(*(pv) = readb(b+a))
-#define SK_IN16(b,a,pv)		(*(pv) = readw(b+a))
-#define SK_IN32(b,a,pv)		(*(pv) = readl(b+a))
+#define SK_OUT8(b,a,v)		writeb((v), ((b)+(a)))	
+#define SK_OUT16(b,a,v)		writew((v), ((b)+(a)))	
+#define SK_OUT32(b,a,v)		writel((v), ((b)+(a)))	
+#define SK_IN8(b,a,pv)		(*(pv) = readb((b)+(a)))
+#define SK_IN16(b,a,pv)		(*(pv) = readw((b)+(a)))
+#define SK_IN32(b,a,pv)		(*(pv) = readl((b)+(a)))
 
 #define int8_t		char
 #define int16_t		short
@@ -222,11 +230,11 @@
 #define SK_DBGCAT_DRV_INT_SRC		0x04000000
 #define SK_DBGCAT_DRV_EVENT		0x08000000
 
-#endif /* DEBUG */
+#endif
 
 #define SK_ERR_LOG		SkErrorLog
 
 extern void SkErrorLog(SK_AC*, int, int, char*);
 
-#endif /* __INC_SKDRV1ST_H */
+#endif
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sk98lin/h/skdrv2nd.h linux-2.4.21-pre6/drivers/net/sk98lin/h/skdrv2nd.h
--- linux-2.4.20/drivers/net/sk98lin/h/skdrv2nd.h	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sk98lin/h/skdrv2nd.h	2003-03-26 23:49:55.000000000 +0000
@@ -2,8 +2,8 @@
  *
  * Name:	skdrv2nd.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.12.2.1 $
- * Date:	$Date: 2001/03/12 16:50:59 $
+ * Version:	$Revision: 1.12.2.2 $
+ * Date:	$Date: 2001/09/05 12:14:50 $
  * Purpose:	Second header file for driver and all other modules
  *
  ******************************************************************************/
@@ -27,6 +27,9 @@
  * History:
  *
  *	$Log: skdrv2nd.h,v $
+ *	Revision 1.12.2.2  2001/09/05 12:14:50  mlindner
+ *	add: New hardware revision int
+ *	
  *	Revision 1.12.2.1  2001/03/12 16:50:59  mlindner
  *	chg: kernel 2.4 adaption
  *	
@@ -202,7 +205,7 @@
 	SK_U32		VDataLow;	/* Receive buffer Addr, low dword */
 	SK_U32		VDataHigh;	/* Receive buffer Addr, high dword */
 	SK_U32		FrameStat;	/* Receive Frame Status word */
-	SK_U32		TimeStamp;	/* Time stamp from XMAX */
+	SK_U32		TimeStamp;	/* Time stamp from XMAC */
 	SK_U32		TcpSums;	/* TCP Sum 2 / TCP Sum 1 */
 	SK_U32		TcpSumStarts;	/* TCP Sum Start 2 / TCP Sum Start 1 */
 	RXD		*pNextRxd;	/* Pointer to next Rxd */
@@ -218,7 +221,8 @@
 	SK_U32		VDataHigh;	/* Transmit Buffer Addr, high dword */
 	SK_U32		FrameStat;	/* Transmit Frame Status Word */
 	SK_U32		TcpSumOfs;	/* Reserved / TCP Sum Offset */
-	SK_U32		TcpSumStWr;	/* TCP Sum Start / TCP Sum Write */
+	SK_U16		TcpSumSt;	/* TCP Sum Start */
+	SK_U16		TcpSumWr;	/* TCP Sum Write */
 	SK_U32		TcpReserved;	/* not used */
 	TXD		*pNextTxd;	/* Pointer to next Txd */
 	struct sk_buff	*pMBuf;		/* Pointer to Linux' socket buffer */
@@ -445,11 +449,11 @@
 	int		BoardLevel;	/* level of active hw init (0-2) */
 	char		DeviceStr[80];	/* adapter string from vpd */
 	SK_U32		AllocFlag;	/* flag allocation of resources */
-	struct pci_dev	PciDev;		/* for access to pci config space */
+	struct pci_dev	*PciDev;	/* for access to pci config space */
 	SK_U32		PciDevId;	/* pci device id */
-	struct net_device	*dev[2];		/* pointer to device struct */
+	struct SK_NET_DEVICE	*dev[2];	/* pointer to device struct */
 	char		Name[30];	/* driver name */
-	struct net_device	*Next;		/* link all devices (for clearing) */
+	struct SK_NET_DEVICE	*Next;		/* link all devices (for clearing) */
 	int		RxBufSize;	/* length of receive buffers */
         struct net_device_stats stats;	/* linux 'netstat -i' statistics */
 	int		Index;		/* internal board index number */
@@ -465,12 +469,12 @@
 					/*  addresses for this board */
 					/*  (may be more than HW can)*/
 
+	int		HWRevision;	/* Hardware revision */
 	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 */
 
-	
 	caddr_t		pDescrMem;	/* Pointer to the descriptor area */
 	dma_addr_t	pDescrMemDMA;	/* PCI DMA address of area */
 
@@ -483,6 +487,11 @@
 	SK_U32		CsOfs;		/* for checksum calculation */
 
 	SK_BOOL		CheckQueue;	/* check event queue soon */
+
+	/* Only for tests */
+	int		PortUp;
+	int		PortDown;
+
 };
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sk98lin/h/skerror.h linux-2.4.21-pre6/drivers/net/sk98lin/h/skerror.h
--- linux-2.4.20/drivers/net/sk98lin/h/skerror.h	2000-09-15 21:34:19.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sk98lin/h/skerror.h	2003-03-26 23:49:38.000000000 +0000
@@ -2,16 +2,15 @@
  *
  * Name:	skerror.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.4 $
- * Date:	$Date: 1999/11/22 13:51:59 $
+ * Version:	$Revision: 1.5 $
+ * Date:	$Date: 2002/04/25 11:05:10 $
  * Purpose:	SK specific Error log support
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998,1999 SysKonnect,
- *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *	(C)Copyright 1998-2002 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,9 @@
  *
  * History:
  *	$Log: skerror.h,v $
+ *	Revision 1.5  2002/04/25 11:05:10  rschmidt
+ *	Editorial changes
+ *	
  *	Revision 1.4  1999/11/22 13:51:59  cgoos
  *	Changed license header to GPL.
  *	
@@ -49,29 +51,29 @@
 #define _INC_SKERROR_H_
 
 /*
- * Define the Error Classes
+ * Define Error Classes
  */
-#define	SK_ERRCL_OTHER		(0)	/* Other error */
+#define	SK_ERRCL_OTHER		(0)		/* Other error */
 #define	SK_ERRCL_CONFIG		(1L<<0)	/* Configuration error */
 #define	SK_ERRCL_INIT		(1L<<1)	/* Initialization error */
-#define	SK_ERRCL_NORES		(1L<<2)	/* Out of resources error */
-#define	SK_ERRCL_SW		(1L<<3)	/* internal Software error */
-#define	SK_ERRCL_HW		(1L<<4)	/* Hardware failure */
+#define	SK_ERRCL_NORES		(1L<<2)	/* Out of Resources error */
+#define	SK_ERRCL_SW			(1L<<3)	/* Internal Software error */
+#define	SK_ERRCL_HW			(1L<<4)	/* Hardware Failure */
 #define	SK_ERRCL_COMM		(1L<<5)	/* Communication error */
 
 
 /*
- * Define Error code bases
+ * Define Error Code Bases
  */
-#define	SK_ERRBASE_RLMT		100	/* Base Error number for RLMT */
-#define	SK_ERRBASE_HWINIT	200	/* Base Error number for HWInit */
-#define	SK_ERRBASE_VPD		300	/* Base Error number for VPD */
-#define	SK_ERRBASE_PNMI		400	/* Base Error number for PNMI */
-#define	SK_ERRBASE_CSUM		500	/* Base Error number for Checksum */
-#define	SK_ERRBASE_SIRQ		600	/* Base Error number for Special IRQ */
-#define	SK_ERRBASE_I2C		700	/* Base Error number for i2C module */
-#define	SK_ERRBASE_QUEUE	800	/* Base Error number for Scheduler */
-#define	SK_ERRBASE_ADDR		900	/* Base Error number for Address mod. */
+#define	SK_ERRBASE_RLMT		 100	/* Base Error number for RLMT */
+#define	SK_ERRBASE_HWINIT	 200	/* Base Error number for HWInit */
+#define	SK_ERRBASE_VPD		 300	/* Base Error number for VPD */
+#define	SK_ERRBASE_PNMI		 400	/* Base Error number for PNMI */
+#define	SK_ERRBASE_CSUM		 500	/* Base Error number for Checksum */
+#define	SK_ERRBASE_SIRQ		 600	/* Base Error number for Special IRQ */
+#define	SK_ERRBASE_I2C		 700	/* Base Error number for I2C module */
+#define	SK_ERRBASE_QUEUE	 800	/* Base Error number for Scheduler */
+#define	SK_ERRBASE_ADDR		 900	/* Base Error number for Address module */
 #define SK_ERRBASE_PECP		1000    /* Base Error number for PECP */
 #define	SK_ERRBASE_DRV		1100	/* Base Error number for Driver */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sk98lin/h/skgedrv.h linux-2.4.21-pre6/drivers/net/sk98lin/h/skgedrv.h
--- linux-2.4.20/drivers/net/sk98lin/h/skgedrv.h	2000-09-15 21:34:19.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sk98lin/h/skgedrv.h	2003-03-26 23:49:50.000000000 +0000
@@ -2,16 +2,15 @@
  *
  * Name:	skgedrv.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.4 $
- * Date:	$Date: 1999/11/22 13:52:46 $
+ * Version:	$Revision: 1.6 $
+ * Date:	$Date: 2002/07/15 15:38:01 $
  * Purpose:	Interface with the driver
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998,1999 SysKonnect,
- *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *	(C)Copyright 1998-2002 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,13 @@
  * History:
  *
  *	$Log: skgedrv.h,v $
+ *	Revision 1.6  2002/07/15 15:38:01  rschmidt
+ *	Power Management support
+ *	Editorial changes
+ *	
+ *	Revision 1.5  2002/04/25 11:05:47  rschmidt
+ *	Editorial changes
+ *	
  *	Revision 1.4  1999/11/22 13:52:46  cgoos
  *	Changed license header to GPL.
  *	
@@ -49,17 +55,18 @@
 
 /*
  * Define the driver events.
- * Usually the events are defined by the destination module. In case of the
- * driver we put the definition of the events here.
+ * Usually the events are defined by the destination module.
+ * In case of the driver we put the definition of the events here.
  */
-#define SK_DRV_PORT_RESET	1	/* The port needs to be reset */
-#define SK_DRV_NET_UP   	2	/* The net is now operational */
-#define SK_DRV_NET_DOWN		3	/* The net is now down */
-#define	SK_DRV_SWITCH_SOFT	4	/* Ports switch with both links conn */
-#define	SK_DRV_SWITCH_HARD	5	/* Port switch due to link failure */
-#define	SK_DRV_RLMT_SEND	6	/* Send a RLMT packet */
-#define	SK_DRV_ADAP_FAIL	7	/* The whole adapter fails */
-#define	SK_DRV_PORT_FAIL	8	/* One port fails */
-#define	SK_DRV_SWITCH_INTERN	9	/* Port switch from driver to itself */
+#define SK_DRV_PORT_RESET		 1	/* The port needs to be reset */
+#define SK_DRV_NET_UP   		 2	/* The net is operational */
+#define SK_DRV_NET_DOWN			 3	/* The net is down */
+#define SK_DRV_SWITCH_SOFT		 4	/* Ports switch with both links connected */
+#define SK_DRV_SWITCH_HARD		 5	/* Port switch due to link failure */
+#define SK_DRV_RLMT_SEND		 6	/* Send a RLMT packet */
+#define SK_DRV_ADAP_FAIL		 7	/* The whole adapter fails */
+#define SK_DRV_PORT_FAIL		 8	/* One port fails */
+#define SK_DRV_SWITCH_INTERN	 9	/* Port switch by the driver itself */
+#define SK_DRV_POWER_DOWN		10	/* Power down mode */
 
 #endif	/* __INC_SKGEDRV_H_ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sk98lin/h/skgehw.h linux-2.4.21-pre6/drivers/net/sk98lin/h/skgehw.h
--- linux-2.4.20/drivers/net/sk98lin/h/skgehw.h	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sk98lin/h/skgehw.h	2003-03-26 23:49:55.000000000 +0000
@@ -2,16 +2,15 @@
  *
  * Name:	skgehw.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.36 $
- * Date:	$Date: 2000/11/09 12:32:49 $
- * Purpose:	Defines and Macros for the Gigabit Ethernet Adapter Product
- *		Family
+ * Version:	$Revision: 1.48 $
+ * Date:	$Date: 2002/12/05 10:25:11 $
+ * Purpose:	Defines and Macros for the Gigabit Ethernet Adapter Product Family
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998-2000 SysKonnect GmbH.
+ *	(C)Copyright 1998-2002 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,61 @@
  *
  * History:
  * $Log: skgehw.h,v $
+ * Revision 1.48  2002/12/05 10:25:11  rschmidt
+ * Added defines for Half Duplex Burst Mode On/Off
+ * Added defines for Rx GMAC FIFO Flush feature
+ * Editorial changes
+ *
+ * Revision 1.47  2002/11/12 17:01:31  rschmidt
+ * Added defines for WOL_CTL_DEFAULT
+ * Editorial changes
+ *
+ * Revision 1.46  2002/10/14 14:47:57  rschmidt
+ * Corrected bit mask for HW self test results
+ * Added defines for WOL Registers
+ * Editorial changes
+ *
+ * Revision 1.45  2002/10/11 09:25:22  mkarl
+ * Added bit mask for HW self test results.
+ *
+ * Revision 1.44  2002/08/16 14:44:36  rschmidt
+ * Added define GPC_HWCFG_GMII_FIB for YUKON Fiber
+ *
+ * Revision 1.43  2002/08/12 13:31:50  rschmidt
+ * Corrected macros for GMAC Address Registers: GM_INADDR(),
+ * GM_OUTADDR(), GM_INHASH, GM_OUTHASH.
+ * Editorial changes
+ *
+ * Revision 1.42  2002/08/08 15:37:56  rschmidt
+ * Added defines for Power Management Capabilities
+ * Editorial changes
+ *
+ * Revision 1.41  2002/07/23 16:02:25  rschmidt
+ * Added macro WOL_REG() to access WOL reg. (HW-Bug in YUKON 1st rev.)
+ *
+ * Revision 1.40  2002/07/15 15:41:37  rschmidt
+ * Added new defines for Power Management Cap. & Control
+ * Editorial changes
+ *
+ * Revision 1.39  2002/06/10 09:37:07  rschmidt
+ * Added macros for the ADDR-Modul
+ *
+ * Revision 1.38  2002/06/05 08:15:19  rschmidt
+ * Added defines for WOL Registers
+ * Editorial changes
+ *
+ * Revision 1.37  2002/04/25 11:39:23  rschmidt
+ * Added new defines for PCI Our Register 1
+ * Added new registers and defines for YUKON (Rx FIFO, Tx FIFO,
+ * Time Stamp Timer, GMAC Control, GPHY Control,Link Control,
+ * GMAC IRQ Source and Mask, Wake-up Frame Pattern Match);
+ * Added new defines for Control/Status (VAUX available)
+ * Added Chip ID for YUKON
+ * Added define for descriptors with UDP ext. for YUKON
+ * Added macros to access the GMAC
+ * Added new Phy Type for Marvell 88E1011S (GPHY)
+ * Editorial changes
+ *
  * Revision 1.36  2000/11/09 12:32:49  rassmann
  * Renamed variables.
  *
@@ -36,7 +90,7 @@
  * Changed license header to GPL.
  *
  * Revision 1.33  1999/08/27 11:17:10  malthoff
- * It's more savely to put bracket around marco parameters.
+ * It's more savely to put brackets around macro parameters.
  * Brackets added for PHY_READ and PHY_WRITE.
  *
  * Revision 1.32  1999/05/19 07:31:01  cgoos
@@ -50,7 +104,7 @@
  * Add PCI_ERRBITS.
  *
  * Revision 1.29  1999/01/26 08:55:48  malthoff
- * Bugfix: The 16 bit field releations inside the descriptor are
+ * Bugfix: The 16 bit field relations inside the descriptor are
  * 	endianess dependend if the descriptor reversal feature
  * 	(PCI_REV_DESC bit in PCI_OUR_REG_2) is enabled.
  * 	Drivers which use this feature has to set the define
@@ -91,7 +145,7 @@
  * fix: typo B0_XM_IMSK regs
  *
  * Revision 1.18  1998/10/16 09:46:54  malthoff
- * Remove temp defines for ML diag prototyp.
+ * Remove temp defines for ML diag prototype.
  * Fix register definition for B0_XM1_PHY_DATA, B0_XM1_PHY_DATA
  * B0_XM2_PHY_DATA, B0_XM2_PHY_ADDR, B0_XA1_CSR, B0_XS1_CSR,
  * B0_XS2_CSR, and B0_XA2_CSR.
@@ -133,7 +187,7 @@
  *
  * Revision 1.10  1998/09/02 11:16:39  malthoff
  * Temporary modify B2_I2C_SW to make tests with
- * the GE/ML prototyp.
+ * the GE/ML prototype.
  *
  * Revision 1.9  1998/08/19 09:11:49  gklug
  * fix: struct are removed from c-source (see CCC)
@@ -145,7 +199,7 @@
  *
  * Revision 1.7  1998/07/03 14:42:26  malthoff
  * bug fix: Correct macro XMA().
- * Add temporary workaround to access the PCI config space over IO
+ * Add temporary workaround to access the PCI config space over I/O
  *
  * Revision 1.6  1998/06/23 11:30:36  malthoff
  * Remove ';' with ',' in macors.
@@ -174,38 +228,120 @@
 
 /* defines ********************************************************************/
 
+#define BIT_31		(1UL << 31)
+#define BIT_30		(1L << 30)
+#define BIT_29		(1L << 29)
+#define BIT_28		(1L << 28)
+#define BIT_27		(1L << 27)
+#define BIT_26		(1L << 26)
+#define BIT_25		(1L << 25)
+#define BIT_24		(1L << 24)
+#define BIT_23		(1L << 23)
+#define BIT_22		(1L << 22)
+#define BIT_21		(1L << 21)
+#define BIT_20		(1L << 20)
+#define BIT_19		(1L << 19)
+#define BIT_18		(1L << 18)
+#define BIT_17		(1L << 17)
+#define BIT_16		(1L << 16)
+#define BIT_15		(1L << 15)
+#define BIT_14		(1L << 14)
+#define BIT_13		(1L << 13)
+#define BIT_12		(1L << 12)
+#define BIT_11		(1L << 11)
+#define BIT_10		(1L << 10)
+#define BIT_9		(1L << 9)
+#define BIT_8		(1L << 8)
+#define BIT_7		(1L << 7)
+#define BIT_6		(1L << 6)
+#define BIT_5		(1L << 5)
+#define BIT_4		(1L << 4)
+#define BIT_3		(1L << 3)
+#define BIT_2		(1L << 2)
+#define BIT_1		(1L << 1)
+#define BIT_0		1L
+
+#define BIT_15S		(1U << 15)
+#define BIT_14S		(1 << 14)
+#define BIT_13S		(1 << 13)
+#define BIT_12S		(1 << 12)
+#define BIT_11S		(1 << 11)
+#define BIT_10S		(1 << 10)
+#define BIT_9S		(1 << 9)
+#define BIT_8S		(1 << 8)
+#define BIT_7S 		(1 << 7)
+#define BIT_6S		(1 << 6)
+#define BIT_5S		(1 << 5)
+#define BIT_4S		(1 << 4)
+#define BIT_3S		(1 << 3)
+#define BIT_2S		(1 << 2)
+#define BIT_1S		(1 << 1)
+#define BIT_0S		1
+
+#define SHIFT31(x)	((x) << 31)
+#define SHIFT30(x)	((x) << 30)
+#define SHIFT29(x)	((x) << 29)
+#define SHIFT28(x)	((x) << 28)
+#define SHIFT27(x)	((x) << 27)
+#define SHIFT26(x)	((x) << 26)
+#define SHIFT25(x)	((x) << 25)
+#define SHIFT24(x)	((x) << 24)
+#define SHIFT23(x)	((x) << 23)
+#define SHIFT22(x)	((x) << 22)
+#define SHIFT21(x)	((x) << 21)
+#define SHIFT20(x)	((x) << 20)
+#define SHIFT19(x)	((x) << 19)
+#define SHIFT18(x)	((x) << 18)
+#define SHIFT17(x)	((x) << 17)
+#define SHIFT16(x)	((x) << 16)
+#define SHIFT15(x)	((x) << 15)
+#define SHIFT14(x)	((x) << 14)
+#define SHIFT13(x)	((x) << 13)
+#define SHIFT12(x)	((x) << 12)
+#define SHIFT11(x)	((x) << 11)
+#define SHIFT10(x)	((x) << 10)
+#define SHIFT9(x)	((x) << 9)
+#define SHIFT8(x)	((x) << 8)
+#define SHIFT7(x)	((x) << 7)
+#define SHIFT6(x)	((x) << 6)
+#define SHIFT5(x)	((x) << 5)
+#define SHIFT4(x)	((x) << 4)
+#define SHIFT3(x)	((x) << 3)
+#define SHIFT2(x)	((x) << 2)
+#define SHIFT1(x)	((x) << 1)
+#define SHIFT0(x)	((x) << 0)
+
 /*
  * Configuration Space header
  * Since this module is used for different OS', those may be
  * duplicate on some of them (e.g. Linux). But to keep the
  * common source, we have to live with this...
  */
-#define	PCI_VENDOR_ID	0x00	/* 16 bit	Vendor ID */
-#define	PCI_DEVICE_ID	0x02	/* 16 bit	Device ID */
-#define	PCI_COMMAND		0x04	/* 16 bit	Command */
-#define	PCI_STATUS		0x06	/* 16 bit	Status */
-#define	PCI_REV_ID		0x08	/*  8 bit	Revision ID */
-#define	PCI_CLASS_CODE	0x09	/* 24 bit	Class Code */
-#define	PCI_CACHE_LSZ	0x0c	/*  8 bit	Cache Line Size */
-#define	PCI_LAT_TIM		0x0d	/*  8 bit	Latency Timer */
-#define	PCI_HEADER_T	0x0e	/*  8 bit	Header Type */
-#define	PCI_BIST		0x0f	/*  8 bit	Built-in selftest */
-#define	PCI_BASE_1ST	0x10	/* 32 bit	1st Base address */
-#define	PCI_BASE_2ND	0x14	/* 32 bit	2nd Base address */
-	/* Byte 18..2b:	reserved */
-#define	PCI_SUB_VID		0x2c	/* 16 bit	Subsystem Vendor ID */
-#define	PCI_SUB_ID		0x2e	/* 16 bit	Subsystem ID */
-#define	PCI_BASE_ROM	0x30	/* 32 bit	Expansion ROM Base Address */
-	/* Byte 34..33:	reserved */
+#define PCI_VENDOR_ID	0x00	/* 16 bit	Vendor ID */
+#define PCI_DEVICE_ID	0x02	/* 16 bit	Device ID */
+#define PCI_COMMAND		0x04	/* 16 bit	Command */
+#define PCI_STATUS		0x06	/* 16 bit	Status */
+#define PCI_REV_ID		0x08	/*  8 bit	Revision ID */
+#define PCI_CLASS_CODE	0x09	/* 24 bit	Class Code */
+#define PCI_CACHE_LSZ	0x0c	/*  8 bit	Cache Line Size */
+#define PCI_LAT_TIM		0x0d	/*  8 bit	Latency Timer */
+#define PCI_HEADER_T	0x0e	/*  8 bit	Header Type */
+#define PCI_BIST		0x0f	/*  8 bit	Built-in selftest */
+#define PCI_BASE_1ST	0x10	/* 32 bit	1st Base address */
+#define PCI_BASE_2ND	0x14	/* 32 bit	2nd Base address */
+	/* Byte 0x18..0x2b:	reserved */
+#define PCI_SUB_VID		0x2c	/* 16 bit	Subsystem Vendor ID */
+#define PCI_SUB_ID		0x2e	/* 16 bit	Subsystem ID */
+#define PCI_BASE_ROM	0x30	/* 32 bit	Expansion ROM Base Address */
 #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_LINE	0x3c	/*  8 bit	Interrupt Line */
+#define PCI_IRQ_PIN		0x3d	/*  8 bit	Interrupt Pin */
+#define PCI_MIN_GNT		0x3e	/*  8 bit	Min_Gnt */
+#define PCI_MAX_LAT		0x3f	/*  8 bit	Max_Lat */
 	/* Device Dependent Region */
-#define	PCI_OUR_REG_1	0x40	/* 32 bit 	Our Register 1 */
-#define	PCI_OUR_REG_2	0x44	/* 32 bit 	Our Register 2 */
+#define PCI_OUR_REG_1	0x40	/* 32 bit 	Our Register 1 */
+#define PCI_OUR_REG_2	0x44	/* 32 bit 	Our Register 2 */
 	/* Power Management Region */
 #define PCI_PM_CAP_ID	0x48	/*  8 bit 	Power Management Cap. ID */
 #define PCI_PM_NITEM	0x49	/*  8 bit 	Next Item Ptr */
@@ -214,11 +350,11 @@
 	/* Byte 0x4e:	reserved */
 #define PCI_PM_DAT_REG	0x4f	/*  8 bit 	Power Manag. Data Register */
 	/* VPD Region */
-#define	PCI_VPD_CAP_ID	0x50	/*  8 bit 	VPD Cap. ID */
+#define PCI_VPD_CAP_ID	0x50	/*  8 bit 	VPD Cap. ID */
 #define PCI_VPD_NITEM	0x51	/*  8 bit 	Next Item Ptr */
 #define PCI_VPD_ADR_REG	0x52	/* 16 bit 	VPD Address Register */
 #define PCI_VPD_DAT_REG	0x54	/* 32 bit 	VPD Data Register */
-	/* Byte 58..ff:	reserved */
+	/* Byte 0x58..0xff:	reserved */
 
 /*
  * I2C Address (PCI Config)
@@ -231,38 +367,38 @@
 /*
  * Define Bits and Values of the registers
  */
-/*	PCI_VENDOR_ID	16 bit	Vendor ID */
-/*	PCI_DEVICE_ID	16 bit	Device ID */
-/* Values for Vendor ID and Device ID shall be patched into the code */
 /*	PCI_COMMAND	16 bit	Command */
 								/* 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_FBTEN		BIT_9S		/* Fast Back-To-Back enable */
+#define PCI_SERREN		BIT_8S		/* SERR enable */
+#define PCI_ADSTEP		BIT_7S		/* Address Stepping */
+#define PCI_PERREN		BIT_6S		/* Parity Report Response enable */
+#define PCI_VGA_SNOOP	BIT_5S		/* VGA palette snoop */
+#define PCI_MWIEN		BIT_4S		/* Memory write an inv cycl ena */
+#define PCI_SCYCEN		BIT_3S		/* Special Cycle enable */
+#define PCI_BMEN		BIT_2S		/* Bus Master enable */
+#define PCI_MEMEN		BIT_1S		/* Memory Space Access enable */
+#define PCI_IOEN		BIT_0S		/* I/O Space Access enable */
+
+#define PCI_COMMAND_VAL	(PCI_FBTEN | PCI_SERREN | PCI_PERREN | PCI_MWIEN |\
+						 PCI_BMEN | PCI_MEMEN | PCI_IOEN)
 
 /*	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 */
+#define PCI_PERR		BIT_15S		/* Parity Error */
+#define PCI_SERR		BIT_14S		/* Signaled SERR */
+#define PCI_RMABORT		BIT_13S		/* Received Master Abort */
+#define PCI_RTABORT		BIT_12S		/* 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_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_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	BIT_8S		/* DATA Parity error detected */
+#define PCI_FB2BCAP		BIT_7S		/* Fast Back-to-Back Capability */
+#define PCI_UDF			BIT_6S		/* User Defined Features */
+#define PCI_66MHZCAP	BIT_5S		/* 66 MHz PCI bus clock capable */
+#define PCI_NEWCAP		BIT_4S		/* New cap. list implemented */
+								/* Bit  3.. 0:	reserved */
 
 #define PCI_ERRBITS	(PCI_PERR | PCI_SERR | PCI_RMABORT | PCI_RTABORT |\
 			PCI_DATAPERR)
@@ -276,160 +412,167 @@
 /*	Possible values: 0,2,4,8,16,32,64,128	*/
 
 /*	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_MF_DEV	BIT_7S	/* 0= single, 1= multi-func dev */
+#define PCI_HD_TYPE		0x7f	/* Bit 6..0:	Header Layout 0= normal */
 
 /*	PCI_BIST	8 bit	Built-in selftest */
 /*	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_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_MEM32BIT	(0L<<1)		/* Base addr anywhere in 32 Bit range */
-#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. */
+#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		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_MEM64BIT	(2L<<1)		/* Base addr anywhere in 64 Bit range */
+#define PCI_MEMSPACE	BIT_0		/* Memory Space Indic. */
 
 /*	PCI_BASE_2ND	32 bit	2nd Base address */
-#define	PCI_IOBASE		0xffffff00L	/* Bit 31..8:	I/O Base address */
-#define	PCI_IOSIZE		0x000000fcL	/* Bit	7..2:	I/O Size Requirements */
+#define PCI_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_IOSPACE		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 */
+#define PCI_ROMBASE		0xfffe0000L	/* 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_ROMEN		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 */
-#define	PCI_EN_FPROM	(1L<<22)	/* Bit 22:	FLASH mapped to mem? */
+									/* Bit 31..29:	reserved */
+#define PCI_PHY_COMA	BIT_28		/* Set PHY to Coma Mode */
+#define PCI_EN_CAL		BIT_27		/* Enable  PCI buffer strength calibr. */
+#define PCI_DIS_CAL		BIT_26		/* Disable PCI buffer strength calibr. */
+#define PCI_VIO			BIT_25		/* PCI I/O Voltage, 0 = 3.3V, 1 = 5V */
+#define PCI_EN_BOOT		BIT_24		/* Enable BOOT via ROM */
+#define PCI_EN_IO		BIT_23		/* Mapping to I/O space */
+#define PCI_EN_FPROM	BIT_22		/* FLASH mapped to mem? */
 									/*		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_32K	(1L<<20)	/*		32 k pages	*/
-#define	PCI_PAGE_64K	(2L<<20)	/*		64 k pages	*/
-#define	PCI_PAGE_128K	(3L<<20)	/*		128 k pages	*/
+#define PCI_PAGESIZE	(3L<<20)	/* Bit 21..20:	FLASH Page Size	*/
+#define PCI_PAGE_16		(0L<<20)	/*		16 k pages	*/
+#define PCI_PAGE_32K	(1L<<20)	/*		32 k pages	*/
+#define PCI_PAGE_64K	(2L<<20)	/*		64 k pages	*/
+#define PCI_PAGE_128K	(3L<<20)	/*		128 k pages	*/
 									/* Bit 19:	reserved	*/
-#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_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*/
-#define	PCI_SKEW_DAS	(0xfL<<4)	/* Bit	7..4:	Skew Ctrl, DAS Ext */
-#define	PCI_SKEW_BASE	(0xfL<<0)	/* Bit	3..0:	Skew Ctrl, Base	*/
+#define PCI_PAGEREG		(7L<<16)	/* Bit 18..16:	Page Register	*/
+#define PCI_NOTAR		BIT_15		/* No turnaround cycle */
+#define PCI_FORCE_BE	BIT_14		/* Assert all BEs on MR */
+#define PCI_DIS_MRL		BIT_13		/* Disable Mem Read Line */
+#define PCI_DIS_MRM		BIT_12		/* Disable Mem Read Multiple */
+#define PCI_DIS_MWI		BIT_11		/* Disable Mem Write & Invalidate */
+#define PCI_DISC_CLS	BIT_10		/* Disc: cacheLsz bound */
+#define PCI_BURST_DIS	BIT_9		/* Burst Disable */
+#define PCI_DIS_PCI_CLK	BIT_8		/* Disable PCI clock driving */
+#define PCI_SKEW_DAS	(0xfL<<4)	/* Bit	7.. 4:	Skew Ctrl, DAS Ext */
+#define PCI_SKEW_BASE	0xfL		/* Bit	3.. 0:	Skew Ctrl, Base	*/
 
 
 /*	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_VPD_ROM_SZ	(7L<<14)	/* Bit 16..14:	VPD ROM Size	*/
+#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	*/
-#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)
-#define	PCI_PATCH_DIR_2	(1L<<10)
-#define	PCI_PATCH_DIR_3	(1L<<11)
-#define PCI_EXT_PATCHS	(0xfL<<4)	/* Bit	7..4:	Extended Patches 3..0 */
-#define	PCI_EXT_PATCH_0	(1L<<4)
-#define	PCI_EXT_PATCH_1	(1L<<5)
-#define	PCI_EXT_PATCH_2	(1L<<6)
-#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 */
+#define PCI_PATCH_DIR	(0xfL<<8)	/* Bit 11.. 8:	Ext Patches dir 3..0 */
+#define PCI_PATCH_DIR_3	BIT_11
+#define PCI_PATCH_DIR_2	BIT_10
+#define PCI_PATCH_DIR_1	BIT_9
+#define PCI_PATCH_DIR_0	BIT_8
+#define PCI_EXT_PATCHS	(0xfL<<4)	/* Bit	7.. 4:	Extended Patches 3..0 */
+#define PCI_EXT_PATCH_3	BIT_7
+#define PCI_EXT_PATCH_2	BIT_6
+#define PCI_EXT_PATCH_1	BIT_5
+#define PCI_EXT_PATCH_0	BIT_4
+#define PCI_EN_DUMMY_RD	BIT_3		/* Enable Dummy Read */
+#define PCI_REV_DESC	BIT_2		/* Reverse Desc. Bytes */
 									/* Bit	1:	reserved */
-#define PCI_USEDATA64	(1L<<0)		/* Bit	0:	Use 64Bit Data bus ext*/
+#define PCI_USEDATA64	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_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 */
-#define PCI_PME_CLOCK	(1<<3)		/* Bit	3:	PM Event Clock */
-#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# */
+#define PCI_PME_SUP		(0x1f<<11)	/* Bit 15..11:	PM Event Support */
+#define PCI_PME_D3C_SUP	BIT_15S		/* PME from D3cold Support (if Vaux) */
+#define PCI_PME_D3H_SUP	BIT_14S		/* PME from D3hot Support */
+#define PCI_PME_D2_SUP	BIT_13S		/* PME from D2 Support */
+#define PCI_PME_D1_SUP	BIT_12S		/* PME from D1 Support */
+#define PCI_PME_D0_SUP	BIT_11S		/* PME from D0 Support */
+#define PCI_PM_D2_SUP	BIT_10S		/* D2 Support in 33 MHz mode */
+#define PCI_PM_D1_SUP	BIT_9S		/* D1 Support */
+									/* Bit	8.. 6:	reserved */
+#define PCI_PM_DSI		BIT_5S		/* Device Specific Initialization */
+#define PCI_PM_APS		BIT_4S		/* Auxialiary Power Source */
+#define PCI_PME_CLOCK	BIT_3S		/* PM Event Clock */
+#define PCI_PM_VER_MSK		7		/* Bit	2.. 0:	PM PCI Spec. version */
+
+/*	PCI_PM_CTL_STS		16 bit	Power Management Control/Status */
+#define PCI_PME_STATUS	BIT_15S		/* PME Status (YUKON only) */
+#define PCI_PM_DAT_SCL	(3<<13)		/* Bit 14..13:	Data Reg. scaling factor */
+#define PCI_PM_DAT_SEL	(0xf<<9)	/* Bit 12.. 9:	PM data selector field */
+#define PCI_PME_EN		BIT_8S		/* Enable PME# generation (YUKON only) */
 									/* 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 */
-#define PCI_PM_STATE_D2	(2<<0)		/* D2:	not supported */
-#define PCI_PM_STATE_D3 (3<<0)		/* D3:	HOT, Power Down and Reset */
+#define PCI_PM_STATE_MSK	3		/* Bit	1.. 0:	Power Management State */
+
+#define PCI_PM_STATE_D0		0		/* D0:	Operational (default) */
+#define PCI_PM_STATE_D1		1		/* D1:	(YUKON only) */
+#define PCI_PM_STATE_D2		2		/* D2:	(YUKON only) */
+#define PCI_PM_STATE_D3 	3		/* D3:	HOT, Power Down and Reset */
 
 /* VPD Region */
 /*	PCI_VPD_ADR_REG		16 bit	VPD Address Register */
-#define	PCI_VPD_FLAG	(1L<<15)	/* Bit 15:	starts VPD rd/wd cycle*/
-#define PCI_VPD_ADDR	(0x3fffL<<0)	/* Bit 14..0:	VPD address */
+#define PCI_VPD_FLAG	BIT_15S			/* starts VPD rd/wd cycle*/
+#define PCI_VPD_ADDR	0x3fffL		/* Bit 14.. 0:	VPD address */
+
+/*	Control Register File (Address Map) */
 
 /*
- *	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 */
-	/* 0x0007:		reserved */
-#define	B0_ISRC			0x0008	/* 32 bit	Interrupt Source Register */
-#define	B0_IMSK			0x000c	/* 32 bit	Interrupt Mask Register */
+#define B0_CTST			0x0004	/* 16 bit	Control/Status register */
+#define B0_LED			0x0006	/*  8 Bit	LED register */
+#define B0_POWER_CTRL	0x0007	/*  8 Bit	Power Control reg (YUKON only) */
+#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*/
-	/* 0x0022 - 0x0027	reserved */
+/* B0 XMAC 1 registers (GENESIS only) */
+#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 */
-	/* 0x002a - 0x002f	reserved */
+	/* 0x002a - 0x002f:	reserved */
 #define B0_XM1_PHY_ADDR 0x0030	/* 16 bit r/w	XMAC 1 PHY Address Register */
-	/* 0x0032 - 0x0033	reserved */
+	/* 0x0032 - 0x0033:	reserved */
 #define B0_XM1_PHY_DATA 0x0034	/* 16 bit r/w	XMAC 1 PHY Data Register */
-	/* 0x0036 - 0x003f	reserved */
+	/* 0x0036 - 0x003f:	reserved */
 
-/* B0 XMAC 2 registers */
-#define	B0_XM2_IMSK		0x0040	/* 16 bit r/w	XMAC 2 Interrupt Mask Register*/
-	/* 0x0042 - 0x0047	reserved */
+/* B0 XMAC 2 registers (GENESIS only) */
+#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 */
-	/* 0x004a - 0x004f	reserved */
+	/* 0x004a - 0x004f:	reserved */
 #define B0_XM2_PHY_ADDR 0x0050	/* 16 bit r/w	XMAC 2 PHY Address Register */
-	/* 0x0052 - 0x0053	reserved */
+	/* 0x0052 - 0x0053:	reserved */
 #define B0_XM2_PHY_DATA 0x0054	/* 16 bit r/w	XMAC 2 PHY Data Register */
-				/* 0x0056 - 0x005f	reserved */
+	/* 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*/
-	/* x0078 - 0x007f	reserved */
+#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*/
+	/* 0x0078 - 0x007f:	reserved */
 
 /*
  *	Bank 1
@@ -441,20 +584,19 @@
  *	Bank 2
  */
 /* NA reg = 48 bit Network Address Register, 3x16 or 8x8 bit readable */
-
-#define	B2_MAC_1		0x0100	/* NA reg	 MAC Address 1 */
-	/* 0x0106 - 0x0107	reserved */
-#define	B2_MAC_2		0x0108	/* NA reg	 MAC Address 2 */
-	/* 0x010e - 0x010f	reserved */
-#define	B2_MAC_3		0x0110	/* NA reg	 MAC Address 3 */
-	/* 0x0116 - 0x0117	reserved */
+#define B2_MAC_1		0x0100	/* NA reg	 MAC Address 1 */
+	/* 0x0106 - 0x0107:	reserved */
+#define B2_MAC_2		0x0108	/* NA reg	 MAC Address 2 */
+	/* 0x010e - 0x010f:	reserved */
+#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_MAC_CFG		0x011a	/*  8 bit	MAC Configuration / Chip Revision */
+#define B2_CHIP_ID		0x011b	/*  8 bit 	Chip Identification 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_0			0x011c	/*  8 bit	EPROM Byte 0 (ext. SRAM size */
+#define B2_E_1			0x011d	/*  8 bit	EPROM Byte 1 (PHY type) */
 #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 */
@@ -463,9 +605,9 @@
 #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_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.*/
@@ -475,14 +617,16 @@
 #define B2_IRQM_MSK 	0x014c	/* 32 bit	IRQ Moderation Mask */
 #define B2_IRQM_HWE_MSK 0x0150	/* 32 bit	IRQ Moderation HW Error Mask */
 	/* 0x0154 - 0x0157:	reserved */
-#define	B2_TST_CTRL1	0x0158	/*  8 bit	Test Control Register 1 */
+#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_GP_IO		0x015c	/* 32 bit	General Purpose I/O 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 */
+
+/* Blink Source Counter (GENESIS only) */
 #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 */
@@ -493,66 +637,70 @@
 /*
  *	Bank 3
  */
+/* RAM Random Registers */
 #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 */
+
 /* RAM Interface Registers */
 /*
- * The HW-Spec. call this registers Timeout Value 0..11. But this names are
+ * The HW-Spec. calls 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 transfered continously.
+ * the number of qWords transferred continuously.
  */
-#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) */
-#define B3_RI_WTO_XS1	0x0192	/* 8 bit RAM Iface WR Timeout Queue XS1 (TO2) */
-#define B3_RI_RTO_R1	0x0193	/* 8 bit RAM Iface RD Timeout Queue R1	(TO3) */
-#define B3_RI_RTO_XA1	0x0194	/* 8 bit RAM Iface RD Timeout Queue XA1	(TO4) */
-#define B3_RI_RTO_XS1	0x0195	/* 8 bit RAM Iface RD Timeout Queue XS1	(TO5) */
-#define B3_RI_WTO_R2	0x0196	/* 8 bit RAM Iface WR Timeout Queue R2	(TO6) */
-#define B3_RI_WTO_XA2	0x0197	/* 8 bit RAM Iface WR Timeout Queue XA2	(TO7) */
-#define B3_RI_WTO_XS2	0x0198	/* 8 bit RAM Iface WR Timeout Queue XS2	(TO8) */
-#define B3_RI_RTO_R2	0x0199	/* 8 bit RAM Iface RD Timeout Queue R2	(TO9) */
-#define B3_RI_RTO_XA2	0x019a	/* 8 bit RAM Iface RD Timeout Queue XA2	(TO10)*/
-#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 */
-	/* 0x01a3 - 0x01af	reserved */
-/* MAC Arbiter Registers */
-/* Please notice these are the number of qWord tranfered continously and */
-/* NOT real timeouts */
-#define B3_MA_TOINI_RX1	0x01b0	/* 8 bit Timeout Init Value Rx Path MAC 1 */
-#define B3_MA_TOINI_RX2	0x01b1	/* 8 bit Timeout Init Value Rx Path MAC 2 */
-#define B3_MA_TOINI_TX1	0x01b2	/* 8 bit Timeout Init Value Tx Path MAC 1 */
-#define B3_MA_TOINI_TX2	0x01b3	/* 8 bit Timeout Init Value Tx Path MAC 2 */
-#define B3_MA_TOVAL_RX1	0x01b4	/* 8 bit Timeout Value Rx Path MAC 1 */
-#define B3_MA_TOVAL_RX2	0x01b5	/* 8 bit Timeout Value Rx Path MAC 1 */
-#define B3_MA_TOVAL_TX1	0x01b6	/* 8 bit Timeout Value Tx Path MAC 2 */
-#define B3_MA_TOVAL_TX2	0x01b7	/* 8 bit Timeout Value Tx Path MAC 2 */
+#define B3_RI_WTO_R1	0x0190	/*  8 bit	WR Timeout Queue R1		(TO0) */
+#define B3_RI_WTO_XA1	0x0191	/*  8 bit	WR Timeout Queue XA1	(TO1) */
+#define B3_RI_WTO_XS1	0x0192	/*  8 bit	WR Timeout Queue XS1	(TO2) */
+#define B3_RI_RTO_R1	0x0193	/*  8 bit	RD Timeout Queue R1		(TO3) */
+#define B3_RI_RTO_XA1	0x0194	/*  8 bit	RD Timeout Queue XA1	(TO4) */
+#define B3_RI_RTO_XS1	0x0195	/*  8 bit	RD Timeout Queue XS1	(TO5) */
+#define B3_RI_WTO_R2	0x0196	/*  8 bit	WR Timeout Queue R2		(TO6) */
+#define B3_RI_WTO_XA2	0x0197	/*  8 bit	WR Timeout Queue XA2	(TO7) */
+#define B3_RI_WTO_XS2	0x0198	/*  8 bit	WR Timeout Queue XS2	(TO8) */
+#define B3_RI_RTO_R2	0x0199	/*  8 bit	RD Timeout Queue R2		(TO9) */
+#define B3_RI_RTO_XA2	0x019a	/*  8 bit	RD Timeout Queue XA2	(TO10)*/
+#define B3_RI_RTO_XS2	0x019b	/*  8 bit	RD Timeout Queue XS2	(TO11)*/
+#define B3_RI_TO_VAL	0x019c	/*  8 bit	Current Timeout Count Val */
+	/* 0x019d - 0x019f:	reserved */
+#define B3_RI_CTRL		0x01a0	/* 16 bit	RAM Interface Control Register */
+#define B3_RI_TEST		0x01a2	/*  8 bit	RAM Interface Test Register */
+	/* 0x01a3 - 0x01af:	reserved */
+
+/* MAC Arbiter Registers (GENESIS only) */
+/* these are the no. of qWord transferred continuously and NOT real timeouts */
+#define B3_MA_TOINI_RX1	0x01b0	/*  8 bit	Timeout Init Val Rx Path MAC 1 */
+#define B3_MA_TOINI_RX2	0x01b1	/*  8 bit	Timeout Init Val Rx Path MAC 2 */
+#define B3_MA_TOINI_TX1	0x01b2	/*  8 bit	Timeout Init Val Tx Path MAC 1 */
+#define B3_MA_TOINI_TX2	0x01b3	/*  8 bit	Timeout Init Val Tx Path MAC 2 */
+#define B3_MA_TOVAL_RX1	0x01b4	/*  8 bit	Timeout Value Rx Path MAC 1 */
+#define B3_MA_TOVAL_RX2	0x01b5	/*  8 bit	Timeout Value Rx Path MAC 1 */
+#define B3_MA_TOVAL_TX1	0x01b6	/*  8 bit	Timeout Value Tx Path MAC 2 */
+#define B3_MA_TOVAL_TX2	0x01b7	/*  8 bit	Timeout Value Tx Path MAC 2 */
 #define B3_MA_TO_CTRL	0x01b8	/* 16 bit	MAC Arbiter Timeout Ctrl Reg */
 #define B3_MA_TO_TEST	0x01ba	/* 16 bit	MAC Arbiter Timeout Test Reg */
-	/* 0x01bc - 0x01bf	reserved */
-#define B3_MA_RCINI_RX1	0x01c0	/* 8 bit Recovery Init Value Rx Path MAC 1 */
-#define B3_MA_RCINI_RX2	0x01c1	/* 8 bit Recovery Init Value Rx Path MAC 2 */
-#define B3_MA_RCINI_TX1	0x01c2	/* 8 bit Recovery Init Value Tx Path MAC 1 */
-#define B3_MA_RCINI_TX2	0x01c3	/* 8 bit Recovery Init Value Tx Path MAC 2 */
-#define B3_MA_RCVAL_RX1	0x01c4	/* 8 bit Recovery Value Rx Path MAC 1 */
-#define B3_MA_RCVAL_RX2	0x01c5	/* 8 bit Recovery Value Rx Path MAC 1 */
-#define B3_MA_RCVAL_TX1	0x01c6	/* 8 bit Recovery Value Tx Path MAC 2 */
-#define B3_MA_RCVAL_TX2	0x01c7	/* 8 bit Recovery Value Tx Path MAC 2 */
+	/* 0x01bc - 0x01bf:	reserved */
+#define B3_MA_RCINI_RX1	0x01c0	/*  8 bit	Recovery Init Val Rx Path MAC 1 */
+#define B3_MA_RCINI_RX2	0x01c1	/*  8 bit	Recovery Init Val Rx Path MAC 2 */
+#define B3_MA_RCINI_TX1	0x01c2	/*  8 bit	Recovery Init Val Tx Path MAC 1 */
+#define B3_MA_RCINI_TX2	0x01c3	/*  8 bit	Recovery Init Val Tx Path MAC 2 */
+#define B3_MA_RCVAL_RX1	0x01c4	/*  8 bit	Recovery Value Rx Path MAC 1 */
+#define B3_MA_RCVAL_RX2	0x01c5	/*  8 bit	Recovery Value Rx Path MAC 1 */
+#define B3_MA_RCVAL_TX1	0x01c6	/*  8 bit	Recovery Value Tx Path MAC 2 */
+#define B3_MA_RCVAL_TX2	0x01c7	/*  8 bit	Recovery Value Tx Path MAC 2 */
 #define B3_MA_RC_CTRL	0x01c8	/* 16 bit	MAC Arbiter Recovery Ctrl Reg */
 #define B3_MA_RC_TEST	0x01ca	/* 16 bit	MAC Arbiter Recovery Test Reg */
-	/* 0x01cc - 0x01cf	reserved */
-/* Packet Arbiter Registers, This are real timeouts */
-#define B3_PA_TOINI_RX1	0x01d0	/* 16 bit	Timeout Init Val Rx Path MAC 1*/
+	/* 0x01cc - 0x01cf:	reserved */
+
+/* Packet Arbiter Registers (GENESIS only) */
+/* these are real timeouts */
+#define B3_PA_TOINI_RX1	0x01d0	/* 16 bit	Timeout Init Val Rx Path MAC 1 */
 	/* 0x01d2 - 0x01d3:	reserved */
-#define B3_PA_TOINI_RX2	0x01d4	/* 16 bit	Timeout Init Val Rx Path MAC 2*/
+#define B3_PA_TOINI_RX2	0x01d4	/* 16 bit	Timeout Init Val Rx Path MAC 2 */
 	/* 0x01d6 - 0x01d7:	reserved */
-#define B3_PA_TOINI_TX1	0x01d8	/* 16 bit	Timeout Init Val Tx Path MAC 1*/
+#define B3_PA_TOINI_TX1	0x01d8	/* 16 bit	Timeout Init Val Tx Path MAC 1 */
 	/* 0x01da - 0x01db:	reserved */
-#define B3_PA_TOINI_TX2	0x01dc	/* 16 bit	Timeout Init Val Tx Path MAC 2*/
+#define B3_PA_TOINI_TX2	0x01dc	/* 16 bit	Timeout Init Val Tx Path MAC 2 */
 	/* 0x01de - 0x01df:	reserved */
 #define B3_PA_TOVAL_RX1	0x01e0	/* 16 bit	Timeout Val Rx Path MAC 1 */
 	/* 0x01e2 - 0x01e3:	reserved */
@@ -569,8 +717,7 @@
 /*
  *	Bank 4 - 5
  */
-
-/* Transmit Arbiter Registers MAC 1 and 2, user MR_ADDR() to address */
+/* Transmit Arbiter Registers MAC 1 and 2, use MR_ADDR() to access */
 #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 */
@@ -579,11 +726,13 @@
 #define TXA_TEST		0x0211	/*  8 bit	Tx Arbiter Test Register */
 #define TXA_STAT		0x0212	/*  8 bit	Tx Arbiter Status Register */
 	/* 0x0213 - 0x027f:	reserved */
+	/* 0x0280 - 0x0292:	MAC 2 */
+	/* 0x0213 - 0x027f:	reserved */
 
 /*
  *	Bank 6
  */
-/* External registers */
+/* External registers (GENESIS only) */
 #define B6_EXT_REG		0x0300
 
 /*
@@ -596,7 +745,7 @@
  *	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 */
@@ -620,254 +769,371 @@
  *	Bank 16 - 23
  */
 /* RAM Buffer Registers */
-#define	B16_RAM_REGS	0x0800
+#define B16_RAM_REGS	0x0800
 
-/* RAM Buffer Register Offsets */
-/* use RB_ADDR(Queue,Offs) to address */
-#define RB_START	0x00	/* 32 bit	RAM Buffer Start Address */
-#define RB_END		0x04	/* 32 bit	RAM Buffer End Address */
-#define RB_WP		0x08	/* 32 bit	RAM Buffer Write Pointer */
-#define RB_RP		0x0c	/* 32 bit	RAM Buffer Read Pointer */
-#define RB_RX_UTPP	0x10	/* 32 bit	Rx Upper Threshold, Pause Pack*/
-#define RB_RX_LTPP	0x14	/* 32 bit	Rx Lower Threshold, Pause Pack*/
-#define RB_RX_UTHP	0x18	/* 32 bit	Rx Upper Threshold, High Prio */
-#define RB_RX_LTHP	0x1c	/* 32 bit	Rx Lower Threshold, High Prio */
-	/* 0x10 - 0x1f:		reserved for Tx RAM Buffer Registers */
-#define RB_PC		0x20	/* 32 bit	RAM Buffer Packet Counter */
-#define RB_LEV		0x24	/* 32 bit	RAM Buffer Level Register */
-#define RB_CTRL		0x28	/*  8 bit	RAM Buffer Control Register */
-#define RB_TST1		0x29	/*  8 bit	RAM Buffer Test Register 1 */
-#define RB_TST2		0x2A	/*  8 bit	RAM Buffer Test Register 2 */
-	/* 0x2c - 0x7f:		reserved */
+/* RAM Buffer Register Offsets, use RB_ADDR() to access */
+#define RB_START		0x00	/* 32 bit	RAM Buffer Start Address */
+#define RB_END			0x04	/* 32 bit	RAM Buffer End Address */
+#define RB_WP			0x08	/* 32 bit	RAM Buffer Write Pointer */
+#define RB_RP			0x0c	/* 32 bit	RAM Buffer Read Pointer */
+#define RB_RX_UTPP		0x10	/* 32 bit	Rx Upper Threshold, Pause Pack */
+#define RB_RX_LTPP		0x14	/* 32 bit	Rx Lower Threshold, Pause Pack */
+#define RB_RX_UTHP		0x18	/* 32 bit	Rx Upper Threshold, High Prio */
+#define RB_RX_LTHP		0x1c	/* 32 bit	Rx Lower Threshold, High Prio */
+	/* 0x10 - 0x1f:	reserved at Tx RAM Buffer Registers */
+#define RB_PC			0x20	/* 32 bit	RAM Buffer Packet Counter */
+#define RB_LEV			0x24	/* 32 bit	RAM Buffer Level Register */
+#define RB_CTRL			0x28	/*  8 bit	RAM Buffer Control Register */
+#define RB_TST1			0x29	/*  8 bit	RAM Buffer Test Register 1 */
+#define RB_TST2			0x2A	/*  8 bit	RAM Buffer Test Register 2 */
+	/* 0x2c - 0x7f:	reserved */
 
 /*
- *	Bank 24 - 25
+ *	Bank 24
+ */
+/*
+ * Receive MAC FIFO, Receive LED, and Link_Sync regs (GENESIS only)
+ * use MR_ADDR() to access
  */
-/* 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*/
-	/* 0x0c08 - 0x0c0b	reserved */
+#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_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_TIST_TO	0x0c1b	/*  8 bit	Receive MAC Time Stamp 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 */
-	/* 0x0c1f		reserved */
+	/* 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 */
-	/* 0x0c2a - 0x0c2f	reserved */
+	/* 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_CTRL	0x0c38	/*  8 bit	Link Sync Cnt Control Register */
 #define LNK_SYNC_TST	0x0c39	/*  8 bit	Link Sync Cnt Test Register */
-	/* 0x0c3a - 0x0c3b	reserved */
+	/* 0x0c3a - 0x0c3b:	reserved */
 #define LNK_LED_REG		0x0c3c	/*  8 bit	Link LED Register */
-	/* 0x0c3d - 0x0c7f	reserved */
+	/* 0x0c3d - 0x0c3f:	reserved */
+
+/* Receive GMAC FIFO (YUKON only), use MR_ADDR() to access */
+#define RX_GMF_EA		0x0c40	/* 32 bit	Rx GMAC FIFO End Address */
+#define RX_GMF_AF_THR	0x0c44	/* 32 bit	Rx GMAC FIFO Almost Full Thresh. */
+#define RX_GMF_CTRL_T	0x0c48	/* 32 bit	Rx GMAC FIFO Control/Test */
+#define RX_GMF_FL_MSK	0x0c4c	/* 32 bit	Rx GMAC FIFO Flush Mask */
+#define RX_GMF_FL_THR	0x0c50	/* 32 bit	Rx GMAC FIFO Flush Threshold */
+	/* 0x0c54 - 0x0c5f:	reserved */
+#define RX_GMF_WP		0x0c60	/* 32 bit 	Rx GMAC FIFO Write Pointer */
+	/* 0x0c64 - 0x0c67:	reserved */
+#define RX_GMF_WLEV		0x0c68	/* 32 bit 	Rx GMAC FIFO Write Level */
+	/* 0x0c6c - 0x0c6f:	reserved */
+#define RX_GMF_RP		0x0c70	/* 32 bit 	Rx GMAC FIFO Read Pointer */
+	/* 0x0c74 - 0x0c77:	reserved */
+#define RX_GMF_RLEV		0x0c78	/* 32 bit 	Rx GMAC FIFO Read Level */
+	/* 0x0c7c - 0x0c7f:	reserved */
+
+/*
+ *	Bank 25
+ */
+	/* 0x0c80 - 0x0cbf:	MAC 2 */
+	/* 0x0cc0 - 0x0cff:	reserved */
 
 /*
- *	Bank 26 - 27
+ *	Bank 26
+ */
+/*
+ * Transmit MAC FIFO and Transmit LED Registers (GENESIS only),
+ * use MR_ADDR() to access
  */
-/* 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_WSP		0x0d08	/* 32 bit	Transmit MAC FIFO WR Shadow Ptr */
 #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*/
-	/* 0x0c1b		reserved */
+#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 */
-	/* 0x0d1f		reserved */
+	/* 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*/
-	/* 0x0d2a - 0x0d7f	reserved */
+#define TX_LED_TST		0x0d29	/*  8 bit	Transmit LED Cnt Test Reg */
+	/* 0x0d2a - 0x0d3f:	reserved */
+
+/* Transmit GMAC FIFO (YUKON only), use MR_ADDR() to access */
+#define TX_GMF_EA		0x0d40	/* 32 bit	Tx GMAC FIFO End Address */
+#define TX_GMF_AE_THR	0x0d44	/* 32 bit	Tx GMAC FIFO Almost Empty Thresh.*/
+#define TX_GMF_CTRL_T	0x0d48	/* 32 bit	Tx GMAC FIFO Control/Test */
+	/* 0x0d4c - 0x0d5f:	reserved */
+#define TX_GMF_WP		0x0d60	/* 32 bit 	Tx GMAC FIFO Write Pointer */
+#define TX_GMF_WSP		0x0d64	/* 32 bit 	Tx GMAC FIFO Write Shadow Ptr. */
+#define TX_GMF_WLEV		0x0d68	/* 32 bit 	Tx GMAC FIFO Write Level */
+	/* 0x0d6c - 0x0d6f:	reserved */
+#define TX_GMF_RP		0x0d70	/* 32 bit 	Tx GMAC FIFO Read Pointer */
+#define TX_GMF_RSTP		0x0d74	/* 32 bit 	Tx GMAC FIFO Restart Pointer */
+#define TX_GMF_RLEV		0x0d78	/* 32 bit 	Tx GMAC FIFO Read Level */
+	/* 0x0d7c - 0x0d7f:	reserved */
+
+/*
+ *	Bank 27
+ */
+	/* 0x0d80 - 0x0dbf:	MAC 2 */
+	/* 0x0daa - 0x0dff:	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_CTRL	0x0e08	/*  8 bit	Descriptor Poll Timer Ctrl Reg*/
-	/* 0x0e09:		reserved */
-#define B28_DPT_TST		0x0e0a	/*  8 bit	Descriptor Poll Timer Test Reg*/
-	/* 0x0e0b - 0x0e8f:	reserved */
+#define B28_DPT_INI		0x0e00	/* 24 bit	Descriptor Poll Timer Init Val */
+#define B28_DPT_VAL		0x0e04	/* 24 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 */
+	/* 0x0e0b:	reserved */
+
+/* Time Stamp Timer Registers (YUKON only) */
+	/* 0x0e10:	reserved */
+#define GMAC_TI_ST_VAL	0x0e14	/* 32 bit	Time Stamp Timer Curr Val */
+#define GMAC_TI_ST_CTRL	0x0e18	/*  8 bit	Time Stamp Timer Ctrl Reg */
+	/* 0x0e19:	reserved */
+#define GMAC_TI_ST_TST	0x0e1a	/*  8 bit	Time Stamp Timer Test Reg */
+	/* 0x0e1b - 0x0e7f:	reserved */
+
+/*
+ *	Bank 29
+ */
+	/* 0x0e80 - 0x0efc:	reserved */
+
+/*
+ *	Bank 30
+ */
+/* GMAC and GPHY Control Registers (YUKON only) */
+#define GMAC_CTRL		0x0f00	/* 32 bit	GMAC Control Reg */
+#define GPHY_CTRL		0x0f04	/* 32 bit	GPHY Control Reg */
+#define GMAC_IRQ_SRC	0x0f08	/*  8 bit	GMAC Interrupt Source Reg */
+	/* 0x0f09 - 0x0f0b:	reserved */
+#define GMAC_IRQ_MSK	0x0f0c	/*  8 bit	GMAC Interrupt Mask Reg */
+	/* 0x0f0d - 0x0f0f:	reserved */
+#define GMAC_LINK_CTRL	0x0f10	/* 16 bit	Link Control Reg */
+	/* 0x0f14 - 0x0f1f:	reserved */
+
+/* Wake-up Frame Pattern Match Control Registers (YUKON only) */
+
+#define WOL_REG_OFFS	0x20	/* HW-Bug: Address is + 0x20 against spec. */
+
+#define WOL_CTRL_STAT	0x0f20	/* 16 bit	WOL Control/Status Reg */
+#define WOL_MATCH_CTL	0x0f22	/*  8 bit	WOL Match Control Reg */
+#define WOL_MATCH_RES	0x0f23	/*  8 bit	WOL Match Result Reg */
+#define WOL_MAC_ADDR_LO	0x0f24	/* 32 bit	WOL MAC Address Low */
+#define WOL_MAC_ADDR_HI	0x0f28	/* 16 bit	WOL MAC Address High */
+#define WOL_PATT_RPTR	0x0f2c	/*  8 bit	WOL Pattern Read Ptr */
+
+/* use this macro to access above registers */
+#define WOL_REG(Reg)	((Reg) + (pAC->GIni.GIWolOffs))
+
+
+/* WOL Pattern Length Registers (YUKON only) */
+
+#define WOL_PATT_LEN_LO	0x0f30		/* 32 bit	WOL Pattern Length 3..0 */
+#define WOL_PATT_LEN_HI	0x0f34		/* 24 bit	WOL Pattern Length 6..4 */
+
+/* WOL Pattern Counter Registers (YUKON only) */
+
+#define WOL_PATT_CNT_0	0x0f38		/* 32 bit	WOL Pattern Counter 3..0 */
+#define WOL_PATT_CNT_4	0x0f3c		/* 24 bit	WOL Pattern Counter 6..4 */
+	/* 0x0f40 - 0x0f7f:	reserved */
+
+/*
+ *	Bank 31
+ */
+/* 0x0f80 - 0x0fff:	reserved */
 
 /*
- *	Bank 29 - 31
+ *	Bank 32	- 33
  */
-/* 0x0e90 - 0x0fff:	reserved */
+#define WOL_PATT_RAM_1	0x1000	/*  WOL Pattern RAM Link 1 */
 
 /*
- *	Bank 0x20 - 0x3f
+ *	Bank 0x22 - 0x3f
  */
-/* 0x1000 - 0x1fff:	reserved */
+/* 0x1100 - 0x1fff:	reserved */
 
 /*
  *	Bank 0x40 - 0x4f
  */
-/* XMAC 1 registers */
-#define B40_XMAC1	0x2000
+#define BASE_XMAC_1		0x2000	/* XMAC 1 registers */
 
 /*
  *	Bank 0x50 - 0x5f
  */
-/* 0x2800 - 0x2fff:	reserved */
+
+#define BASE_GMAC_1		0x2800	/* GMAC 1 registers */
 
 /*
  *	Bank 0x60 - 0x6f
  */
-/* XMAC 2 registers */
-#define B40_XMAC2	0x3000
+#define BASE_XMAC_2		0x3000	/* XMAC 2 registers */
 
 /*
  *	Bank 0x70 - 0x7f
  */
-/* 0x3800 - 0x3fff:	reserved */
+#define BASE_GMAC_2		0x3800	/* GMAC 2 registers */
 
 /*
  *	Control Register Bit Definitions:
  */
 /*	B0_RAP		8 bit	Register Address Port */
-				/* Bit 7:	reserved */
-#define	RAP_RAP			0x3f	/* Bit 6..0:	0 = block 0, .., 6f = block 6f*/
+								/* Bit 7:	reserved */
+#define RAP_RAP			0x3f	/* Bit 6..0:	0 = block 0,..,6f = block 6f */
 
 /*	B0_CTST		16 bit	Control/Status register */
-				/* Bit 15..10:	reserved */
-#define CS_BUS_CLOCK	(1<<9)	/* Bit	9:	Bus Clock 0/1 = 33/66MHz */
-#define CS_BUS_SLOT_SZ	(1<<8)	/* Bit	8:	Slot Size 0/1 = 32/64 bit slot*/
-#define CS_ST_SW_IRQ	(1<<7)	/* Bit	7:	Set IRQ SW Request	*/
-#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	*/
+								/* Bit 15..11:	reserved */
+#define CS_VAUX_AVAIL	BIT_10S		/* VAUX available (YUKON only) */
+#define CS_BUS_CLOCK	BIT_9S		/* Bus Clock 0/1 = 33/66 MHz */
+#define CS_BUS_SLOT_SZ	BIT_8S		/* Slot Size 0/1 = 32/64 bit slot */
+#define CS_ST_SW_IRQ	BIT_7S		/* Set IRQ SW Request */
+#define CS_CL_SW_IRQ	BIT_6S		/* Clear IRQ SW Request */
+#define CS_STOP_DONE	BIT_5S		/* Stop Master is finished */
+#define CS_STOP_MAST	BIT_4S		/* Command Bit to stop the master */
+#define CS_MRST_CLR		BIT_3S		/* Clear Master reset	*/
+#define CS_MRST_SET		BIT_2S		/* Set Master reset	*/
+#define CS_RST_CLR		BIT_1S		/* Clear Software reset	*/
+#define CS_RST_SET		BIT_0S		/* 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_OFF	(1<<0)	/* Bit 0:	Status LED off	*/
+								/* Bit  7.. 2:	reserved */
+#define LED_STAT_ON		BIT_1S		/* Status LED on	*/
+#define LED_STAT_OFF	BIT_0S		/* Status LED off	*/
+
+/*	B0_POWER_CTRL	 8 Bit	Power Control reg (YUKON only) */
+#define PC_VAUX_ENA		BIT_7		/* Switch VAUX Enable  */
+#define PC_VAUX_DIS		BIT_6       /* Switch VAUX Disable */
+#define PC_VCC_ENA		BIT_5       /* Switch VCC Enable  */
+#define PC_VCC_DIS		BIT_4       /* Switch VCC Disable */
+#define PC_VAUX_ON		BIT_3       /* Switch VAUX On  */
+#define PC_VAUX_OFF		BIT_2       /* Switch VAUX Off */
+#define PC_VCC_ON		BIT_1       /* Switch VCC On  */
+#define PC_VCC_OFF		BIT_0       /* Switch VCC 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_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_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_LNK_SYNC_M2	(1L<<18)	/* Bit 18:	Link Sync Cnt wrap M2 */
+#define IS_HW_ERR		BIT_31		/* Interrupt HW Error */
+								/* Bit 30:	reserved */
+#define IS_PA_TO_RX1	BIT_29		/* Packet Arb Timeout Rx1 */
+#define IS_PA_TO_RX2	BIT_28		/* Packet Arb Timeout Rx2 */
+#define IS_PA_TO_TX1	BIT_27		/* Packet Arb Timeout Tx1 */
+#define IS_PA_TO_TX2	BIT_26		/* Packet Arb Timeout Tx2 */
+#define IS_I2C_READY	BIT_25		/* IRQ on end of I2C Tx */
+#define IS_IRQ_SW		BIT_24		/* SW forced IRQ	*/
+#define IS_EXT_REG		BIT_23		/* IRQ from LM80 or PHY (GENESIS only) */
+									/* IRQ from PHY (YUKON only) */
+#define IS_TIMINT		BIT_22		/* IRQ from Timer	*/
+#define IS_MAC1			BIT_21		/* IRQ from MAC 1	*/
+#define IS_LNK_SYNC_M1	BIT_20		/* Link Sync Cnt wrap MAC 1 */
+#define IS_MAC2			BIT_19		/* IRQ from MAC 2	*/
+#define IS_LNK_SYNC_M2	BIT_18		/* Link Sync Cnt wrap MAC 2 */
 /* 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			BIT_17		/* Q_R1 End of Buffer */
+#define IS_R1_F			BIT_16		/* Q_R1 End of Frame */
+#define IS_R1_C			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			BIT_14		/* Q_R2 End of Buffer */
+#define IS_R2_F			BIT_13		/* Q_R2 End of Frame */
+#define IS_R2_C			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		BIT_11		/* Q_XS1 End of Buffer */
+#define IS_XS1_F		BIT_10		/* Q_XS1 End of Frame */
+#define IS_XS1_C		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		BIT_8		/* Q_XA1 End of Buffer */
+#define IS_XA1_F		BIT_7		/* Q_XA1 End of Frame */
+#define IS_XA1_C		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		BIT_5		/* Q_XS2 End of Buffer */
+#define IS_XS2_F		BIT_4		/* Q_XS2 End of Frame */
+#define IS_XS2_C		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		BIT_2		/* Q_XA2 End of Buffer */
+#define IS_XA2_F		BIT_1		/* Q_XA2 End of Frame */
+#define IS_XA2_C		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_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 */
-#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*/
-#define IS_NO_TIST_M2	(1L<<6)		/* Bit	6:	No Timestamp from MAC2*/
-#define IS_RAM_RD_PAR	(1L<<5)		/* Bit	5:	RAM Read Parity Error */
-#define IS_RAM_WR_PAR	(1L<<4)		/* Bit	4:	RAM Write Parity Error*/
-#define IS_M1_PAR_ERR	(1L<<3)		/* Bit	3:	MAC 1 Parity Error */
-#define IS_M2_PAR_ERR	(1L<<2)		/* Bit	2:	MAC 2 Parity Error */
-#define IS_R1_PAR_ERR	(1L<<1)		/* Bit	1:	Queue R1 Parity Error */
-#define IS_R2_PAR_ERR	(1L<<0)		/* Bit	0:	Queue R2 Parity Error */
+								/* Bit 31..14:	reserved */
+#define IS_IRQ_TIST_OV	BIT_13	/* Time Stamp Timer Overflow (YUKON only) */
+#define IS_IRQ_SENSOR	BIT_12	/* IRQ from Sensor (YUKON only) */
+#define IS_IRQ_MST_ERR	BIT_11	/* IRQ master error detected */
+#define IS_IRQ_STAT		BIT_10	/* IRQ status exception */
+#define IS_NO_STAT_M1	BIT_9	/* No Rx Status from MAC 1 */
+#define IS_NO_STAT_M2	BIT_8	/* No Rx Status from MAC 2 */
+#define IS_NO_TIST_M1	BIT_7	/* No Time Stamp from MAC 1 */
+#define IS_NO_TIST_M2	BIT_6	/* No Time Stamp from MAC 2 */
+#define IS_RAM_RD_PAR	BIT_5	/* RAM Read  Parity Error */
+#define IS_RAM_WR_PAR	BIT_4	/* RAM Write Parity Error */
+#define IS_M1_PAR_ERR	BIT_3	/* MAC 1 Parity Error */
+#define IS_M2_PAR_ERR	BIT_2	/* MAC 2 Parity Error */
+#define IS_R1_PAR_ERR	BIT_1	/* Queue R1 Parity Error */
+#define IS_R2_PAR_ERR	BIT_0	/* Queue R2 Parity Error */
 
 /*	B2_CONN_TYP	 8 bit	Connector type */
 /*	B2_PMD_TYP	 8 bit	PMD type */
 /*	Values of connector and PMD type comply to SysKonnect internal std */
 
-/*	B2_MAC_CFG	 8 bit	MAC Configuration */
-								/* 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*/
-
-/*	B2_CHIP_REV	 8 bit 	Queen Chip Revision Number */
-#define FIRST_CHIP_REV	0x0a	/* Initial Revision Value */
+/*	B2_MAC_CFG	 8 bit	MAC Configuration / Chip Revision */
+#define CFG_CHIP_R_MSK	(0xf<<4)	/* Bit 7.. 4: Chip Revision */
+									/* Bit 3.. 2:	reserved */
+#define CFG_DIS_M2_CLK	BIT_1S		/* Disable Clock for 2nd MAC */
+#define CFG_SNG_MAC		BIT_0S		/* MAC Config: 0=2 MACs / 1=1 MAC*/
+
+/*	B2_CHIP_ID	 8 bit 	Chip Identification Number */
+#define CHIP_ID_GENESIS	0x0a		/* Chip ID for GENESIS */
+#define CHIP_ID_YUKON	0xb0		/* Chip ID for YUKON */
 
 /*	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			BIT_3S	/* Loader Test mode on */
+#define LD_T_OFF		BIT_2S	/* Loader Test mode off */
+#define LD_T_STEP		BIT_1S	/* Decrement FPROM addr. Counter */
+#define LD_START		BIT_0S	/* 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		BIT_2S	/* Start Timer */
+#define TIM_STOP		BIT_1S	/* Stop  Timer */
+#define TIM_CLR_IRQ		BIT_0S	/* 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		BIT_2S	/* Test mode on */
+#define TIM_T_OFF		BIT_1S	/* Test mode off */
+#define TIM_T_STEP		BIT_0S	/* Test step */
 
 /*	B28_DPT_INI	32 bit	Descriptor Poll Timer Init Val */
 /*	B28_DPT_VAL	32 bit	Descriptor Poll Timer Curr Val */
@@ -875,100 +1141,101 @@
 #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		BIT_1S	/* Start Descriptor Poll Timer */
+#define DPT_STOP		BIT_0S	/* Stop  Descriptor Poll Timer */
 
+/*	B2_E_3			 8 bit 	lower 4 bits used for HW self test result */
+#define B2_E3_RES_MASK	0x0f
 
 /*	B2_TST_CTRL1	 8 bit	Test Control Register 1 */
-#define	TST_FRC_DPERR_MR	(1<<7)	/* Bit 7: force DATAPERR on MST RD */
-#define	TST_FRC_DPERR_MW	(1<<6)	/* Bit 6: force DATAPERR on MST WR */
-#define	TST_FRC_DPERR_TR	(1<<5)	/* Bit 5: force DATAPERR on TRG RD */
-#define	TST_FRC_DPERR_TW	(1<<4)	/* Bit 4: force DATAPERR on TRG WR */
-#define	TST_FRC_APERR_M		(1<<3)	/* Bit 3: force ADDRPERR on MST */
-#define	TST_FRC_APERR_T		(1<<2)	/* Bit 2: force ADDRPERR on TRG */
-#define	TST_CFG_WRITE_ON	(1<<1)	/* Bit 1: Enable Config Reg WR */
-#define	TST_CFG_WRITE_OFF	(1<<0)	/* Bit 0: Disable Config Reg WR */
+#define TST_FRC_DPERR_MR	BIT_7S	/* force DATAPERR on MST RD */
+#define TST_FRC_DPERR_MW	BIT_6S	/* force DATAPERR on MST WR */
+#define TST_FRC_DPERR_TR	BIT_5S	/* force DATAPERR on TRG RD */
+#define TST_FRC_DPERR_TW	BIT_4S	/* force DATAPERR on TRG WR */
+#define TST_FRC_APERR_M		BIT_3S	/* force ADDRPERR on MST */
+#define TST_FRC_APERR_T		BIT_2S	/* force ADDRPERR on TRG */
+#define TST_CFG_WRITE_ON	BIT_1S	/* Enable  Config Reg WR */
+#define TST_CFG_WRITE_OFF	BIT_0S	/* Disable Config Reg WR */
 
 /*	B2_TST_CTRL2	 8 bit	Test Control Register 2 */
-									/* Bit 7..4:	reserved */
-					/* force the following error on */
-					/* the next master read/write	*/
-#define TST_FRC_DPERR_MR64	(1<<3)	/* Bit 3:	DataPERR RD 64	*/
-#define TST_FRC_DPERR_MW64	(1<<2)	/* Bit 2:	DataPERR WR 64	*/
-#define TST_FRC_APERR_1M64	(1<<1)	/* Bit 1:	AddrPERR on 1. phase */
-#define TST_FRC_APERR_2M64	(1<<0)	/* Bit 0:	AddrPERR on 2. phase */
-
-/*	B2_GP_IO	32 bit	General Purpose IO Register */
-								/* 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 */
-#define	GP_DIR_6	(1L<<22)	/* Bit 22:	IO_6 direct, 0=I/1=O */
-#define	GP_DIR_5	(1L<<21)	/* Bit 21:	IO_5 direct, 0=I/1=O */
-#define	GP_DIR_4	(1L<<20)	/* Bit 20:	IO_4 direct, 0=I/1=O */
-#define	GP_DIR_3	(1L<<19)	/* Bit 19:	IO_3 direct, 0=I/1=O */
-#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 */
-#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 */
-#define	GP_IO_6		(1L<<6)		/* Bit	6:	IO_6 pin */
-#define	GP_IO_5		(1L<<5)		/* Bit	5:	IO_5 pin */
-#define	GP_IO_4		(1L<<4)		/* Bit	4:	IO_4 pin */
-#define	GP_IO_3		(1L<<3)		/* Bit	3:	IO_3 pin */
-#define	GP_IO_2		(1L<<2)		/* Bit	2:	IO_2 pin */
-#define	GP_IO_1		(1L<<1)		/* Bit	1:	IO_1 pin */
-#define	GP_IO_0		(1L<<0)		/* Bit	0:	IO_0 pin */
+									/* Bit 7.. 4:	reserved */
+			/* force the following error on the next master read/write	*/
+#define TST_FRC_DPERR_MR64	BIT_3S	/* DataPERR RD 64	*/
+#define TST_FRC_DPERR_MW64	BIT_2S	/* DataPERR WR 64	*/
+#define TST_FRC_APERR_1M64	BIT_1S	/* AddrPERR on 1. phase */
+#define TST_FRC_APERR_2M64	BIT_0S	/* AddrPERR on 2. phase */
+
+/*	B2_GP_IO	32 bit	General Purpose I/O Register */
+							/* Bit 31..26:	reserved */
+#define GP_DIR_9	BIT_25	/* IO_9 direct, 0=I/1=O */
+#define GP_DIR_8	BIT_24	/* IO_8 direct, 0=I/1=O */
+#define GP_DIR_7	BIT_23	/* IO_7 direct, 0=I/1=O */
+#define GP_DIR_6	BIT_22	/* IO_6 direct, 0=I/1=O */
+#define GP_DIR_5	BIT_21	/* IO_5 direct, 0=I/1=O */
+#define GP_DIR_4	BIT_20	/* IO_4 direct, 0=I/1=O */
+#define GP_DIR_3	BIT_19	/* IO_3 direct, 0=I/1=O */
+#define GP_DIR_2	BIT_18	/* IO_2 direct, 0=I/1=O */
+#define GP_DIR_1	BIT_17	/* IO_1 direct, 0=I/1=O */
+#define GP_DIR_0	BIT_16	/* IO_0 direct, 0=I/1=O */
+						/* Bit 15..10:	reserved */
+#define GP_IO_9		BIT_9	/* IO_9 pin */
+#define GP_IO_8		BIT_8	/* IO_8 pin */
+#define GP_IO_7		BIT_7	/* IO_7 pin */
+#define GP_IO_6		BIT_6	/* IO_6 pin */
+#define GP_IO_5		BIT_5	/* IO_5 pin */
+#define GP_IO_4		BIT_4	/* IO_4 pin */
+#define GP_IO_3		BIT_3	/* IO_3 pin */
+#define GP_IO_2		BIT_2	/* IO_2 pin */
+#define GP_IO_1		BIT_1	/* IO_1 pin */
+#define GP_IO_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_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_BURST_LEN	(1L<<4)		/* Bit	4:	Burst Len, 1/4 bytes */
+#define I2C_FLAG		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_BURST_LEN	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_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_4K_DEV		(4L<<1)		/*		4: 4096 Bytes	*/
+#define I2C_8K_DEV		(5L<<1)		/*		5: 8192 Bytes	*/
+#define I2C_16K_DEV		(6L<<1)		/*		6: 16384 Bytes	*/
+#define I2C_32K_DEV		(7L<<1)		/*		7: 32768 Bytes	*/
+#define I2C_STOP		BIT_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		BIT_0	/* Clear I2C IRQ */
 
-/*	B2_I2C_SW	32 bit	I2C HW SW Port Register */
-								/* 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	*/
+/*	B2_I2C_SW	32 bit (8 bit access)	I2C HW SW Port Register */
+								/* Bit  7.. 3:	reserved */
+#define I2C_DATA_DIR	BIT_2S		/* direction of I2C_DATA */
+#define I2C_DATA		BIT_1S		/* I2C Data Port	*/
+#define I2C_CLK			BIT_0S		/* I2C Clock Port	*/
 
 /*
  * I2C Address
  */
-#define	I2C_SENS_ADDR	LM80_ADDR	/* I2C Sensor Address, (Volt and Temp)*/
+#define I2C_SENS_ADDR	LM80_ADDR	/* I2C Sensor Address, (Volt and Temp)*/
 
 
 /*	B2_BSC_CTRL	 8 bit	Blink Source Counter Control */
-							/* 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 */
+							/* Bit  7.. 2:	reserved */
+#define BSC_START	BIT_1S		/* Start Blink Source Counter */
+#define BSC_STOP	BIT_0S		/* Stop  Blink Source Counter */
 
 /*	B2_BSC_STAT	 8 bit	Blink Source Counter Status */
-							/* Bit 7..1:	reserved */
-#define BSC_SRC		(1<<0)	/* Bit 0:	Blink Source, 0=Off / 1=On */
+							/* Bit  7.. 1:	reserved */
+#define BSC_SRC		BIT_0S		/* Blink Source, 0=Off / 1=On */
 
 /*	B2_BSC_TST	16 bit	Blink Source Counter Test Reg */
-#define	BSC_T_ON	(1<<2)	/* Bit 2:	Test mode on */
-#define	BSC_T_OFF	(1<<1)	/* Bit 1:	Test mode off */
-#define	BSC_T_STEP	(1<<0)	/* Bit 0:	Test step */
+#define BSC_T_ON	BIT_2S		/* Test mode on */
+#define BSC_T_OFF	BIT_1S		/* Test mode off */
+#define BSC_T_STEP	BIT_0S		/* Test step */
 
 
 /*	B3_RAM_ADDR	32 bit	RAM Address, to read or write */
@@ -978,55 +1245,55 @@
 /* RAM Interface Registers */
 /*	B3_RI_CTRL	16 bit	RAM Iface Control Register */
 								/* 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 */
+#define RI_CLR_RD_PERR	BIT_9S	/* Clear IRQ RAM Read Parity Err */
+#define RI_CLR_WR_PERR	BIT_8S	/* Clear IRQ RAM Write Parity Err*/
+								/* Bit	7.. 2:	reserved */
+#define RI_RST_CLR		BIT_1S	/* Clear RAM Interface Reset */
+#define RI_RST_SET		BIT_0S	/* 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 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 */
+								/* Bit 15.. 4:	reserved */
+#define RI_T_EV			BIT_3S	/* Timeout Event occured */
+#define RI_T_ON			BIT_2S	/* Timeout Timer Test On */
+#define RI_T_OFF		BIT_1S	/* Timeout Timer Test Off */
+#define RI_T_STEP		BIT_0S	/* 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		BIT_3S	/* XMAC Fast Output Enable ON */
+#define MA_FOE_OFF		BIT_2S	/* XMAC Fast Output Enable OFF */
+#define MA_RST_CLR		BIT_1S	/* Clear MAC Arbiter Reset */
+#define MA_RST_SET		BIT_0S	/* Set   MAC Arbiter Reset */
 
 /*	B3_MA_RC_CTRL	16 bit	MAC Arbiter Recovery Ctrl Reg */
-								/* 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 */
-#define MA_DIS_REC_TX1	(1<<4)	/* Bit	4:	Disable Recovery Timer TX1 */
-#define MA_ENA_REC_RX2	(1<<3)	/* Bit	3:	Enable Recovery Timer RX2 */
-#define MA_DIS_REC_RX2	(1<<2)	/* Bit	2:	Disable Recovery Timer RX2 */
-#define MA_ENA_REC_RX1	(1<<1)	/* Bit	1:	Enable Recovery Timer RX1 */
-#define MA_DIS_REC_RX1	(1<<0)	/* Bit	0:	Disable Recovery Timer RX1 */
+								/* Bit 15.. 8:	reserved */
+#define MA_ENA_REC_TX2	BIT_7S	/* Enable  Recovery Timer TX2 */
+#define MA_DIS_REC_TX2	BIT_6S	/* Disable Recovery Timer TX2 */
+#define MA_ENA_REC_TX1	BIT_5S	/* Enable  Recovery Timer TX1 */
+#define MA_DIS_REC_TX1	BIT_4S	/* Disable Recovery Timer TX1 */
+#define MA_ENA_REC_RX2	BIT_3S	/* Enable  Recovery Timer RX2 */
+#define MA_DIS_REC_RX2	BIT_2S	/* Disable Recovery Timer RX2 */
+#define MA_ENA_REC_RX1	BIT_1S	/* Enable  Recovery Timer RX1 */
+#define MA_DIS_REC_RX1	BIT_0S	/* Disable Recovery Timer RX1 */
 
 /* Packet Arbiter Registers */
 /*	B3_PA_CTRL	16 bit	Packet Arbiter Ctrl Register */
 								/* 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 */
-#define PA_CLR_TO_RX1	(1<<10)	/* Bit 10:	Clear IRQ Packet Timeout RX1 */
-#define PA_ENA_TO_TX2	(1<<9)	/* Bit	9:	Enable Timeout Timer TX2 */
-#define PA_DIS_TO_TX2	(1<<8)	/* Bit	8:	Disable Timeout Timer TX2 */
-#define PA_ENA_TO_TX1	(1<<7)	/* Bit	7:	Enable Timeout Timer TX1 */
-#define PA_DIS_TO_TX1	(1<<6)	/* Bit	6:	Disable Timeout Timer TX1 */
-#define PA_ENA_TO_RX2	(1<<5)	/* Bit	5:	Enable Timeout Timer RX2 */
-#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_CLR_TO_TX2	BIT_13S	/* Clear IRQ Packet Timeout TX2 */
+#define PA_CLR_TO_TX1	BIT_12S	/* Clear IRQ Packet Timeout TX1 */
+#define PA_CLR_TO_RX2	BIT_11S	/* Clear IRQ Packet Timeout RX2 */
+#define PA_CLR_TO_RX1	BIT_10S	/* Clear IRQ Packet Timeout RX1 */
+#define PA_ENA_TO_TX2	BIT_9S	/* Enable  Timeout Timer TX2 */
+#define PA_DIS_TO_TX2	BIT_8S	/* Disable Timeout Timer TX2 */
+#define PA_ENA_TO_TX1	BIT_7S	/* Enable  Timeout Timer TX1 */
+#define PA_DIS_TO_TX1	BIT_6S	/* Disable Timeout Timer TX1 */
+#define PA_ENA_TO_RX2	BIT_5S	/* Enable  Timeout Timer RX2 */
+#define PA_DIS_TO_RX2	BIT_4S	/* Disable Timeout Timer RX2 */
+#define PA_ENA_TO_RX1	BIT_3S	/* Enable  Timeout Timer RX1 */
+#define PA_DIS_TO_RX1	BIT_2S	/* Disable Timeout Timer RX1 */
+#define PA_RST_CLR		BIT_1S	/* Clear MAC Arbiter Reset */
+#define PA_RST_SET		BIT_0S	/* 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)
@@ -1036,57 +1303,57 @@
 /*	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 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 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 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 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 */
+#define TX2_T_EV	BIT_15S		/* TX2 Timeout/Recv Event occured */
+#define TX2_T_ON	BIT_14S		/* TX2 Timeout/Recv Timer Test On */
+#define TX2_T_OFF	BIT_13S		/* TX2 Timeout/Recv Timer Tst Off */
+#define TX2_T_STEP	BIT_12S		/* TX2 Timeout/Recv Timer Step */
+#define TX1_T_EV	BIT_11S		/* TX1 Timeout/Recv Event occured */
+#define TX1_T_ON	BIT_10S		/* TX1 Timeout/Recv Timer Test On */
+#define TX1_T_OFF	BIT_9S		/* TX1 Timeout/Recv Timer Tst Off */
+#define TX1_T_STEP	BIT_8S		/* TX1 Timeout/Recv Timer Step */
+#define RX2_T_EV	BIT_7S		/* RX2 Timeout/Recv Event occured */
+#define RX2_T_ON	BIT_6S		/* RX2 Timeout/Recv Timer Test On */
+#define RX2_T_OFF	BIT_5S		/* RX2 Timeout/Recv Timer Tst Off */
+#define RX2_T_STEP	BIT_4S		/* RX2 Timeout/Recv Timer Step */
+#define RX1_T_EV	BIT_3S		/* RX1 Timeout/Recv Event occured */
+#define RX1_T_ON	BIT_2S		/* RX1 Timeout/Recv Timer Test On */
+#define RX1_T_OFF	BIT_1S		/* RX1 Timeout/Recv Timer Tst Off */
+#define RX1_T_STEP	BIT_0S		/* RX1 Timeout/Recv Timer Step */
 
 
-/* Transmit Arbiter Registers MAC 1 and 2, user MR_ADDR() to address */
+/* Transmit Arbiter Registers MAC 1 and 2, use MR_ADDR() to access */
 /*	TXA_ITI_INI	32 bit	Tx Arb Interval Timer Init Val */
 /*	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 */
-#define	TXA_MAX_VAL	0x00ffffffL	/* Bit 23.. 0:	Max TXA Timer/Cnt Val */
+#define TXA_MAX_VAL	0x00ffffffL	/* Bit 23.. 0:	Max TXA Timer/Cnt Val */
 
 /*	TXA_CTRL	 8 bit	Tx Arbiter Control Register */
-#define TXA_ENA_FSYNC	(1<<7)	/* Bit 7:	Enable force of sync tx queue */
-#define TXA_DIS_FSYNC	(1<<6)	/* Bit 6:	Disable force of sync tx queue*/
-#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_ENA_FSYNC	BIT_7S	/* Enable  force of sync Tx queue */
+#define TXA_DIS_FSYNC	BIT_6S	/* Disable force of sync Tx queue */
+#define TXA_ENA_ALLOC	BIT_5S	/* Enable  alloc of free bandwidth */
+#define TXA_DIS_ALLOC	BIT_4S	/* Disable alloc of free bandwidth */
+#define TXA_START_RC	BIT_3S	/* Start sync Rate Control */
+#define TXA_STOP_RC		BIT_2S	/* Stop  sync Rate Control */
+#define TXA_ENA_ARB		BIT_1S	/* Enable  Tx Arbiter */
+#define TXA_DIS_ARB		BIT_0S	/* Disable Tx Arbiter */
 
 /*	TXA_TEST	 8 bit	Tx Arbiter Test Register */
-				/* Bit 7..6:	reserved */
-#define TXA_INT_T_ON	(1<<5)	/* Bit 5:	Tx Arb Interval Timer Test On */
-#define TXA_INT_T_OFF	(1<<4)	/* Bit 4:	Tx Arb Interval Timer Test Off*/
-#define TXA_INT_T_STEP	(1<<3)	/* Bit 3:	Tx Arb Interval Timer Step */
-#define TXA_LIM_T_ON	(1<<2)	/* Bit 2:	Tx Arb Limit Timer Test On */
-#define TXA_LIM_T_OFF	(1<<1)	/* Bit 1:	Tx Arb Limit Timer Test Off */
-#define TXA_LIM_T_STEP	(1<<0)	/* Bit 0:	Tx Arb Limit Timer Step */
+								/* Bit 7.. 6:	reserved */
+#define TXA_INT_T_ON	BIT_5S	/* Tx Arb Interval Timer Test On */
+#define TXA_INT_T_OFF	BIT_4S	/* Tx Arb Interval Timer Test Off */
+#define TXA_INT_T_STEP	BIT_3S	/* Tx Arb Interval Timer Step */
+#define TXA_LIM_T_ON	BIT_2S	/* Tx Arb Limit Timer Test On */
+#define TXA_LIM_T_OFF	BIT_1S	/* Tx Arb Limit Timer Test Off */
+#define TXA_LIM_T_STEP	BIT_0S	/* 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		BIT_0S	/* sync queue has prio to send */
 
 /*	Q_BC	32 bit	Current Byte Counter */
-				/* Bit 31..16:	reserved */
+								/* Bit 31..16:	reserved */
 #define BC_MAX			0xffff	/* Bit 15.. 0:	Byte counter */
 
 /* BMU Control Status Registers */
@@ -1096,94 +1363,95 @@
 /*	B0_XS1_CSR	32 bit	BMU Ctrl/Stat Async Tx Queue 1 */
 /*	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 */
-#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_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_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)
-#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)
-
+/*	Q_CSR		32 bit	BMU Control/Status Register */
+								/* Bit 31..25:	reserved */
+#define CSR_SV_IDLE		BIT_24		/* BMU SM Idle */
+								/* Bit 23..22:	reserved */
+#define CSR_DESC_CLR	BIT_21		/* Clear Reset for Descr */
+#define CSR_DESC_SET	BIT_20		/* Set   Reset for Descr */
+#define CSR_FIFO_CLR	BIT_19		/* Clear Reset for FIFO */
+#define CSR_FIFO_SET	BIT_18		/* Set   Reset for FIFO */
+#define CSR_HPI_RUN		BIT_17		/* Release HPI SM */
+#define CSR_HPI_RST		BIT_16		/* Reset   HPI SM to Idle */
+#define CSR_SV_RUN		BIT_15		/* Release Supervisor SM */
+#define CSR_SV_RST		BIT_14		/* Reset   Supervisor SM */
+#define CSR_DREAD_RUN	BIT_13		/* Release Descr Read SM */
+#define CSR_DREAD_RST	BIT_12		/* Reset   Descr Read SM */
+#define CSR_DWRITE_RUN	BIT_11		/* Release Descr Write SM */
+#define CSR_DWRITE_RST	BIT_10		/* Reset   Descr Write SM */
+#define CSR_TRANS_RUN	BIT_9		/* Release Transfer SM */
+#define CSR_TRANS_RST	BIT_8		/* Reset   Transfer SM */
+#define CSR_ENA_POL		BIT_7		/* Enable  Descr Polling */
+#define CSR_DIS_POL		BIT_6		/* Disable Descr Polling */
+#define CSR_STOP		BIT_5		/* Stop  Rx/Tx Queue */
+#define CSR_START		BIT_4		/* Start Rx/Tx Queue */
+#define CSR_IRQ_CL_P	BIT_3		/* (Rx)	Clear Parity IRQ */
+#define CSR_IRQ_CL_B	BIT_2		/* Clear EOB IRQ */
+#define CSR_IRQ_CL_F	BIT_1		/* Clear EOF IRQ */
+#define CSR_IRQ_CL_C	BIT_0		/* Clear ERR IRQ */
+
+#define CSR_SET_RESET	(CSR_DESC_SET | CSR_FIFO_SET | CSR_HPI_RST |\
+						CSR_SV_RST | CSR_DREAD_RST | CSR_DWRITE_RST |\
+						CSR_TRANS_RST)
+#define CSR_CLR_RESET	(CSR_DESC_CLR | CSR_FIFO_CLR | CSR_HPI_RUN |\
+						CSR_SV_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_WM_REACHED	(1L<<25)	/* Bit 25: 	Watermark reached */
-									/* Bit 24:	reserved */
+									/* Bit 31..28:	reserved */
+#define F_ALM_FULL		BIT_27		/* Rx FIFO: almost full */
+#define F_EMPTY			BIT_27		/* Tx FIFO: empty flag */
+#define F_FIFO_EOF		BIT_26		/* Tag (EOF Flag) bit in FIFO */
+#define F_WM_REACHED	BIT_25		/* Watermark reached */
+									/* reserved */
 #define F_FIFO_LEVEL	(0x1fL<<16)	/* Bit 23..16:	# of Qwords in FIFO */
 									/* Bit 15..11: 	reserved */
 #define F_WATER_MARK	0x0007ffL	/* Bit 10.. 0:	Watermark */
 
 /*	Q_T1	32 bit	Test Register 1 */
 /*		Holds four State Machine control Bytes */
-#define	SM_CRTL_SV	(0xffL<<24)	/* Bit 31..24:	Control Supervisor SM */
-#define	SM_CRTL_RD	(0xffL<<16)	/* Bit 23..16:	Control Read Desc SM */
-#define	SM_CRTL_WR	(0xffL<<8)	/* Bit 15.. 8:	Control Write Desc SM */
-#define	SM_CRTL_TR	(0xffL<<0)	/* Bit	7.. 0:	Control Transfer SM */
+#define SM_CRTL_SV_MSK	(0xffL<<24)	/* Bit 31..24:	Control Supervisor SM */
+#define SM_CRTL_RD_MSK	(0xffL<<16)	/* Bit 23..16:	Control Read Desc SM */
+#define SM_CRTL_WR_MSK	(0xffL<<8)	/* Bit 15.. 8:	Control Write Desc SM */
+#define SM_CRTL_TR_MSK	0xffL		/* Bit	7.. 0:	Control Transfer SM */
 
 /*	Q_T1_TR	 8 bit	Test Register 1 Transfer SM */
 /*	Q_T1_WR	 8 bit	Test Register 1 Write Descriptor SM */
 /*	Q_T1_RD	 8 bit	Test Register 1 Read Descriptor SM */
 /*	Q_T1_SV	 8 bit	Test Register 1 Supervisor SM */
+
 /* The control status byte of each machine looks like ... */
-#define	SM_STATE	0xf0	/* Bit 7..4:	State which shall be loaded */
-#define	SM_LOAD		(1<<3)	/* Bit 3:	Load the SM with SM_STATE */
-#define	SM_TEST_ON	(1<<2)	/* Bit 2:	Switch on SM Test Mode */
-#define	SM_TEST_OFF	(1<<1)	/* Bit 1:	Go off the Test Mode */
-#define	SM_STEP		(1<<0)	/* Bit 0:	Step the State Machine */
+#define SM_STATE		0xf0	/* Bit 7.. 4:	State which shall be loaded */
+#define SM_LOAD			BIT_3S	/* Load the SM with SM_STATE */
+#define SM_TEST_ON		BIT_2S	/* Switch on SM Test Mode */
+#define SM_TEST_OFF		BIT_1S	/* Go off the Test Mode */
+#define SM_STEP			BIT_0S	/* Step the State Machine */
 /* The encoding of the states is not supported by the Diagnostics Tool */
 
 /*	Q_T2	32 bit	Test Register 2	*/
-				/* Bit 31..8:	reserved */
-#define	T2_AC_T_ON	(1<<7)	/* Bit 7:	Address Counter Test Mode on */
-#define	T2_AC_T_OFF	(1<<6)	/* Bit 6:	Address Counter Test Mode off*/
-#define	T2_BC_T_ON	(1<<5)	/* Bit 5:	Byte Counter Test Mode on */
-#define	T2_BC_T_OFF	(1<<4)	/* Bit 4:	Byte Counter Test Mode off */
-#define	T2_STEP04	(1<<3)	/* Bit 3:	Inc AC/Dec BC by 4 */
-#define	T2_STEP03	(1<<2)	/* Bit 2:	Inc AC/Dec BC by 3 */
-#define	T2_STEP02	(1<<1)	/* Bit 1:	Inc AC/Dec BC by 2 */
-#define	T2_STEP01	(1<<0)	/* Bit 0:	Inc AC/Dec BC by 1 */
+								/* Bit 31.. 8:	reserved */
+#define T2_AC_T_ON		BIT_7	/* Address Counter Test Mode on */
+#define T2_AC_T_OFF		BIT_6	/* Address Counter Test Mode off */
+#define T2_BC_T_ON		BIT_5	/* Byte Counter Test Mode on */
+#define T2_BC_T_OFF		BIT_4	/* Byte Counter Test Mode off */
+#define T2_STEP04		BIT_3	/* Inc AC/Dec BC by 4 */
+#define T2_STEP03		BIT_2	/* Inc AC/Dec BC by 3 */
+#define T2_STEP02		BIT_1	/* Inc AC/Dec BC by 2 */
+#define T2_STEP01		BIT_0	/* Inc AC/Dec BC by 1 */
 
 /*	Q_T3	32 bit	Test Register 3	*/
-							/* Bit 31..7:	reserved */
-#define	T3_MUX		(7<<4)	/* Bit 6.. 4:	Mux Position */
-							/* Bit 3:	reserved */
-#define	T3_VRAM		(7<<0)	/* Bit 2.. 0:	Virtual RAM Buffer Address */
+								/* Bit 31.. 7:	reserved */
+#define T3_MUX_MSK		(7<<4)	/* Bit  6.. 4:	Mux Position */
+								/* Bit  3:	reserved */
+#define T3_VRAM_MSK		7		/* Bit  2.. 0:	Virtual RAM Buffer Address */
 
-/* RAM Buffer Register Offsets */
-/* use RB_ADDR(Queue,Offs) to address */
+/* RAM Buffer Register Offsets, use RB_ADDR(Queue, Offs) to access */
 /*	RB_START	32 bit	RAM Buffer Start Address */
 /*	RB_END		32 bit	RAM Buffer End Address */
 /*	RB_WP		32 bit	RAM Buffer Write Pointer */
 /*	RB_RP		32 bit	RAM Buffer Read Pointer */
 /*	RB_RX_UTPP	32 bit	Rx Upper Threshold, Pause Pack */
-/*	RB_RX_LTPP	32 bit	Rx Lower Threshold, Pasue Pack */
+/*	RB_RX_LTPP	32 bit	Rx Lower Threshold, Pause Pack */
 /*	RB_RX_UTHP	32 bit	Rx Upper Threshold, High Prio */
 /*	RB_RX_LTHP	32 bit	Rx Lower Threshold, High Prio */
 /*	RB_PC		32 bit	RAM Buffer Packet Counter */
@@ -1191,144 +1459,325 @@
 				/* Bit 31..19:	reserved */
 #define RB_MSK	0x0007ffff	/* Bit 18.. 0:	RAM Buffer Pointer Bits */
 
-/*	RB_TST2		8 bit	RAM Buffer Test Register 2 */
-							/* 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 */
-#define RB_PC_INC	(1<<0)	/* Bit 0:	Packet Counter Increm */
-
-/*	RB_TST1		8 bit	RAM Buffer Test Register 1 */
-				/* Bit 7:	reserved */
-#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 */
-#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 */
-#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 */
+/*	RB_TST2			 8 bit	RAM Buffer Test Register 2 */
+								/* Bit 7.. 4:	reserved */
+#define RB_PC_DEC		BIT_3S	/* Packet Counter Decrem */
+#define RB_PC_T_ON		BIT_2S	/* Packet Counter Test On */
+#define RB_PC_T_OFF		BIT_1S	/* Packet Counter Tst Off */
+#define RB_PC_INC		BIT_0S	/* Packet Counter Increm */
+
+/*	RB_TST1			 8 bit	RAM Buffer Test Register 1 */
+							/* Bit 7:	reserved */
+#define RB_WP_T_ON		BIT_6S	/* Write Pointer Test On */
+#define RB_WP_T_OFF		BIT_5S	/* Write Pointer Test Off */
+#define RB_WP_INC		BIT_4S	/* Write Pointer Increm */
+								/* Bit 3:	reserved */
+#define RB_RP_T_ON		BIT_2S	/* Read Pointer Test On */
+#define RB_RP_T_OFF		BIT_1S	/* Read Pointer Test Off */
+#define RB_RP_DEC		BIT_0S	/* Read Pointer Decrement */
+
+/*	RB_CTRL			 8 bit	RAM Buffer Control Register */
+								/* Bit 7.. 6:	reserved */
+#define RB_ENA_STFWD	BIT_5S	/* Enable  Store & Forward */
+#define RB_DIS_STFWD	BIT_4S	/* Disable Store & Forward */
+#define RB_ENA_OP_MD	BIT_3S	/* Enable  Operation Mode */
+#define RB_DIS_OP_MD	BIT_2S	/* Disable Operation Mode */
+#define RB_RST_CLR		BIT_1S	/* Clear RAM Buf STM Reset */
+#define RB_RST_SET		BIT_0S	/* Set   RAM Buf STM Reset */
+
 
+/* Receive and Transmit MAC FIFO Registers (GENESIS only) */
 
-/* Receive and Transmit MAC FIFO Registers, use MR_ADDR() to address */
 /*	RX_MFF_EA	32 bit	Receive MAC FIFO End Address */
 /*	RX_MFF_WP	32 bit 	Receive MAC FIFO Write Pointer */
 /*	RX_MFF_RP	32 bit	Receive MAC FIFO Read Pointer */
-/*	RX_MFF_PC	32 bit	Receive MAC FIFO Packet Counter*/
+/*	RX_MFF_PC	32 bit	Receive MAC FIFO Packet Counter */
 /*	RX_MFF_LEV	32 bit	Receive MAC FIFO Level */
 /*	TX_MFF_EA	32 bit	Transmit MAC FIFO End Address */
-/*	TX_MFF_WP	32 bit 	Transmit MAC FIFO Write Pointer*/
-/*	TX_MFF_WSP	32 bit	Transmit MAC FIFO WR Shadow Pt*/
+/*	TX_MFF_WP	32 bit 	Transmit MAC FIFO Write Pointer */
+/*	TX_MFF_WSP	32 bit	Transmit MAC FIFO WR Shadow Pointer */
 /*	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 */
-#define MFF_MSK		0x007fL	/* Bit	5..0:	MAC FIFO Address/Pointer Bits */
+								/* Bit 31.. 6:	reserved */
+#define MFF_MSK			0x007fL	/* Bit	5.. 0:	MAC FIFO Address/Ptr Bits */
 
 /*	RX_MFF_CTRL1	16 bit	Receive MAC FIFO Control Reg 1 */
-									/* 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 */
-#define MFF_DIS_TIM_PAT	(1<<10)		/* Bit 10:	Disable Timing Patch */
-#define MFF_ENA_ALM_FUL	(1<<9)		/* Bit	9:	Enable AlmostFull Sign*/
-#define MFF_DIS_ALM_FUL	(1<<8)		/* Bit	8:	Disab. AlmostFull Sign*/
-#define MFF_ENA_PAUSE	(1<<7)		/* Bit	7:	Enable Pause Signaling*/
-#define MFF_DIS_PAUSE	(1<<6)		/* Bit	6:	Disab. Pause Signaling*/
-#define MFF_ENA_FLUSH	(1<<5)		/* Bit	5:	Enable Frame Flushing */
-#define MFF_DIS_FLUSH	(1<<4)		/* Bit	4:	Disab. Frame Flushing */
-#define MFF_ENA_TIST	(1<<3)		/* Bit	3:	Enable Timestamp Gener*/
-#define MFF_DIS_TIST	(1<<2)		/* Bit	2:	Disab. Timestamp Gener*/
-#define MFF_CLR_INTIST	(1<<1)		/* Bit	1:	Clear IRQ No Timestamp*/
-#define MFF_CLR_INSTAT	(1<<0)		/* Bit	0:	Clear IRQ No Status */
+								/* Bit 15..14:	reserved */
+#define MFF_ENA_RDY_PAT	BIT_13S		/* Enable  Ready Patch */
+#define MFF_DIS_RDY_PAT	BIT_12S		/* Disable Ready Patch */
+#define MFF_ENA_TIM_PAT	BIT_11S		/* Enable  Timing Patch */
+#define MFF_DIS_TIM_PAT	BIT_10S		/* Disable Timing Patch */
+#define MFF_ENA_ALM_FUL	BIT_9S		/* Enable  AlmostFull Sign */
+#define MFF_DIS_ALM_FUL	BIT_8S		/* Disable AlmostFull Sign */
+#define MFF_ENA_PAUSE	BIT_7S		/* Enable  Pause Signaling */
+#define MFF_DIS_PAUSE	BIT_6S		/* Disable Pause Signaling */
+#define MFF_ENA_FLUSH	BIT_5S		/* Enable  Frame Flushing */
+#define MFF_DIS_FLUSH	BIT_4S		/* Disable Frame Flushing */
+#define MFF_ENA_TIST	BIT_3S		/* Enable  Time Stamp Gener */
+#define MFF_DIS_TIST	BIT_2S		/* Disable Time Stamp Gener */
+#define MFF_CLR_INTIST	BIT_1S		/* Clear IRQ No Time Stamp */
+#define MFF_CLR_INSTAT	BIT_0S		/* Clear IRQ No Status */
 
 #define MFF_RX_CTRL_DEF MFF_ENA_TIM_PAT
 
 /*	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 */
-#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 */
-/*	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 */
-#define MFF_DIS_LOOPB	(1<<2)		/* Bit	2:	Disable Loopback */
-#define MFF_CLR_MAC_RST	(1<<1)		/* Bit	1:	Clear XMAC Reset */
-#define MFF_SET_MAC_RST	(1<<0)		/* Bit	0:	Set XMAC Reset */
+#define MFF_CLR_PERR	BIT_15S		/* Clear Parity Error IRQ */
+								/* Bit 14:	reserved */
+#define MFF_ENA_PKT_REC	BIT_13S		/* Enable  Packet Recovery */
+#define MFF_DIS_PKT_REC BIT_12S		/* Disable Packet Recovery */
+/*	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  Almost Full Sign */
+/*	MFF_DIS_ALM_FUL	 (see RX_MFF_CTRL1) Bit	 8:	Disable Almost Full Sign */
+#define MFF_ENA_W4E		BIT_7S		/* Enable  Wait for Empty */
+#define MFF_DIS_W4E		BIT_6S		/* Disable Wait for Empty */
+/*	MFF_ENA_FLUSH	 (see RX_MFF_CTRL1) Bit	 5:	Enable  Frame Flushing */
+/*	MFF_DIS_FLUSH	 (see RX_MFF_CTRL1) Bit	 4:	Disable Frame Flushing */
+#define MFF_ENA_LOOPB	BIT_3S		/* Enable  Loopback */
+#define MFF_DIS_LOOPB	BIT_2S		/* Disable Loopback */
+#define MFF_CLR_MAC_RST	BIT_1S		/* Clear XMAC Reset */
+#define MFF_SET_MAC_RST	BIT_0S		/* Set   XMAC Reset */
 
 #define MFF_TX_CTRL_DEF	(MFF_ENA_PKT_REC | MFF_ENA_TIM_PAT | MFF_ENA_FLUSH)
 
-/*	RX_MFF_TST2	 8 bit	Receive MAC FIFO Test Register 2 */
-/*	TX_MFF_TST2	 8 bit	Transmit MAC FIFO Test Register 2 */
+/*	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 */
-#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_PC_T_OFF	(1<<1)	/* Bit 1:	Packet Counter Tst Off */
-#define MFF_PC_INC		(1<<0)	/* Bit 0:	Packet Counter Increm  */
+#define MFF_WSP_T_ON	BIT_6S	/* Tx: Write Shadow Ptr TestOn */
+#define MFF_WSP_T_OFF	BIT_5S	/* Tx: Write Shadow Ptr TstOff */
+#define MFF_WSP_INC		BIT_4S	/* Tx: Write Shadow Ptr Increment */
+#define MFF_PC_DEC		BIT_3S	/* Packet Counter Decrement */
+#define MFF_PC_T_ON		BIT_2S	/* Packet Counter Test On */
+#define MFF_PC_T_OFF	BIT_1S	/* Packet Counter Test Off */
+#define MFF_PC_INC		BIT_0S	/* Packet Counter Increment */
 
-/*	RX_MFF_TST1	 8 bit	Receive MAC FIFO Test Register 1 */
-/*	TX_MFF_TST1	 8 bit	Transmit MAC FIFO Test Register 1 */
+/*	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 */
-#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_RP_T_OFF	(1<<1)	/* Bit 1:	Read Pointer Test Off */
-#define MFF_RP_DEC		(1<<0)	/* Bit 0:	Read Pointer Decrement */
+#define MFF_WP_T_ON		BIT_6S	/* Write Pointer Test On */
+#define MFF_WP_T_OFF	BIT_5S	/* Write Pointer Test Off */
+#define MFF_WP_INC		BIT_4S	/* Write Pointer Increm */
+							/* Bit 3:	reserved */
+#define MFF_RP_T_ON		BIT_2S	/* Read Pointer Test On */
+#define MFF_RP_T_OFF	BIT_1S	/* Read Pointer Test Off */
+#define MFF_RP_DEC		BIT_0S	/* 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 */
-#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 */
-
-
-/* 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 */
-#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 */
-#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 */
-#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 MFF_ENA_OP_MD	BIT_3S	/* Enable  Operation Mode */
+#define MFF_DIS_OP_MD	BIT_2S	/* Disable Operation Mode */
+#define MFF_RST_CLR		BIT_1S	/* Clear MAC FIFO Reset */
+#define MFF_RST_SET		BIT_0S	/* Set   MAC FIFO Reset */
+
+
+/*	Link LED Counter Registers (GENESIS only) */
+
+/*	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		BIT_2S	/* Start Timer */
+#define LED_STOP		BIT_1S	/* Stop Timer */
+#define LED_STATE		BIT_0S	/* Rx/Tx: LED State, 1=LED on */
+#define LED_CLR_IRQ		BIT_0S	/* 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 */
+#define LED_T_ON		BIT_2S	/* LED Counter Test mode On */
+#define LED_T_OFF		BIT_1S	/* LED Counter Test mode Off */
+#define LED_T_STEP		BIT_0S	/* LED Counter Step */
+
+/*	LNK_LED_REG	 	 8 bit	Link LED Register */
+								/* Bit 7.. 6:	reserved */
+#define LED_BLK_ON		BIT_5S	/* Link LED Blinking On */
+#define LED_BLK_OFF		BIT_4S	/* Link LED Blinking Off */
+#define LED_SYNC_ON		BIT_3S	/* Use Sync Wire to switch LED */
+#define LED_SYNC_OFF	BIT_2S	/* Disable Sync Wire Input */
+#define LED_ON			BIT_1S	/* switch LED on */
+#define LED_OFF			BIT_0S	/* switch LED off */
+
+/*	Receive and Transmit GMAC FIFO Registers (YUKON only) */
+
+/*	RX_GMF_EA		32 bit	Rx GMAC FIFO End Address */
+/*	RX_GMF_AF_THR	32 bit	Rx GMAC FIFO Almost Full Thresh. */
+/*	RX_GMF_WP		32 bit 	Rx GMAC FIFO Write Pointer */
+/*	RX_GMF_WLEV		32 bit 	Rx GMAC FIFO Write Level */
+/*	RX_GMF_RP		32 bit 	Rx GMAC FIFO Read Pointer */
+/*	RX_GMF_RLEV		32 bit 	Rx GMAC FIFO Read Level */
+/*	TX_GMF_EA		32 bit	Tx GMAC FIFO End Address */
+/*	TX_GMF_AE_THR	32 bit	Tx GMAC FIFO Almost Empty Thresh.*/
+/*	TX_GMF_WP		32 bit 	Tx GMAC FIFO Write Pointer */
+/*	TX_GMF_WSP		32 bit 	Tx GMAC FIFO Write Shadow Ptr. */
+/*	TX_GMF_WLEV		32 bit 	Tx GMAC FIFO Write Level */
+/*	TX_GMF_RP		32 bit 	Tx GMAC FIFO Read Pointer */
+/*	TX_GMF_RSTP		32 bit 	Tx GMAC FIFO Restart Pointer */
+/*	TX_GMF_RLEV		32 bit 	Tx GMAC FIFO Read Level */
+
+/*	RX_GMF_CTRL_T	32 bit	Rx GMAC FIFO Control/Test */
+						/* Bits 31..15:	reserved */
+#define GMF_WP_TST_ON	BIT_14		/* Write Pointer Test On */
+#define GMF_WP_TST_OFF	BIT_13		/* Write Pointer Test Off */
+#define GMF_WP_STEP		BIT_12		/* Write Pointer Step/Increment */
+						/* Bit 11:	reserved */
+#define GMF_RP_TST_ON	BIT_10		/* Read Pointer Test On */
+#define GMF_RP_TST_OFF	BIT_9		/* Read Pointer Test Off */
+#define GMF_RP_STEP		BIT_8		/* Read Pointer Step/Increment */
+#define GMF_RX_F_FL_ON	BIT_7		/* Rx FIFO Flush Mode On */
+#define GMF_RX_F_FL_OFF	BIT_6		/* Rx FIFO Flush Mode Off */
+#define GMF_CLI_RX_FO	BIT_5		/* Clear IRQ Rx FIFO Overrun */
+#define GMF_CLI_RX_FC	BIT_4		/* Clear IRQ Rx Frame Complete */
+#define GMF_OPER_ON		BIT_3		/* Operational Mode On */
+#define GMF_OPER_OFF	BIT_2		/* Operational Mode Off */
+#define GMF_RST_CLR		BIT_1		/* Clear GMAC FIFO Reset */
+#define GMF_RST_SET		BIT_0		/* Set   GMAC FIFO Reset */
+
+/*	TX_GMF_CTRL_T	32 bit	Tx GMAC FIFO Control/Test */
+						/* Bits 31..19:	reserved */
+#define GMF_WSP_TST_ON	BIT_18		/* Write Shadow Pointer Test On */
+#define GMF_WSP_TST_OFF	BIT_17		/* Write Shadow Pointer Test Off */
+#define GMF_WSP_STEP	BIT_16		/* Write Shadow Pointer Step/Increment */
+						/* Bits 15..7: same as for RX_GMF_CTRL_T */
+#define GMF_CLI_TX_FU	BIT_6		/* Clear IRQ Tx FIFO Underrun */
+#define GMF_CLI_TX_FC	BIT_5		/* Clear IRQ Tx Frame Complete */
+#define GMF_CLI_TX_PE	BIT_4		/* Clear IRQ Tx Parity Error */
+						/* Bits 3..0: same as for RX_GMF_CTRL_T */
+
+#define GMF_RX_CTRL_DEF		GMF_OPER_ON
+#define GMF_TX_CTRL_DEF		GMF_OPER_ON
+
+/*	GMAC_TI_ST_CTRL		  8 bit	Time Stamp Timer Ctrl Reg (YUKON only) */
+								/* Bit 7.. 3:	reserved */
+#define GMT_ST_START	BIT_2S		/* Start Time Stamp Timer */
+#define GMT_ST_STOP		BIT_1S		/* Stop  Time Stamp Timer */
+#define GMT_ST_CLR_IRQ	BIT_0S		/* Clear Time Stamp Timer IRQ */
+
+/*	GMAC_CTRL		32 bit	GMAC Control Reg (YUKON only) */
+						/* Bits 31.. 8:	reserved */
+#define GMC_H_BURST_ON	BIT_7		/* Half Duplex Burst Mode On */
+#define GMC_H_BURST_OFF	BIT_6		/* Half Duplex Burst Mode Off */
+#define GMC_F_LOOPB_ON	BIT_5		/* FIFO Loopback On */
+#define GMC_F_LOOPB_OFF	BIT_4		/* FIFO Loopback Off */
+#define GMC_PAUSE_ON	BIT_3		/* Pause On */
+#define GMC_PAUSE_OFF	BIT_2		/* Pause Off */
+#define GMC_RST_CLR		BIT_1		/* Clear GMAC Reset */
+#define GMC_RST_SET		BIT_0		/* Set   GMAC Reset */
+
+/*	GPHY_CTRL		32 bit	GPHY Control Reg (YUKON only) */
+						/* Bits 31..29:	reserved */
+#define GPC_SEL_BDT		BIT_28	/* Select Bi-Dir. Transfer for MDC/MDIO */
+#define GPC_INT_POL_HI	BIT_27	/* IRQ Polarity is Active HIGH */
+#define GPC_75_OHM		BIT_26	/* Use 75 Ohm Termination instead of 50 */
+#define GPC_DIS_FC		BIT_25	/* Disable Automatic Fiber/Copper Detection */
+#define GPC_DIS_SLEEP	BIT_24	/* Disable Energy Detect */
+#define GPC_HWCFG_M_3	BIT_23	/* HWCFG_MODE[3] */
+#define GPC_HWCFG_M_2	BIT_22	/* HWCFG_MODE[2] */
+#define GPC_HWCFG_M_1	BIT_21	/* HWCFG_MODE[1] */
+#define GPC_HWCFG_M_0	BIT_20	/* HWCFG_MODE[0] */
+#define GPC_ANEG_0		BIT_19	/* ANEG[0] */
+#define GPC_ENA_XC		BIT_18	/* Enable MDI crossover */
+#define GPC_DIS_125		BIT_17	/* Disable 125 MHz clock */
+#define GPC_ANEG_3		BIT_16	/* ANEG[3] */
+#define GPC_ANEG_2		BIT_15	/* ANEG[2] */
+#define GPC_ANEG_1		BIT_14	/* ANEG[1] */
+#define GPC_ENA_PAUSE	BIT_13	/* Enable Pause (SYM_OR_REM) */
+#define GPC_PHYADDR_4	BIT_12	/* Bit 4 of Phy Addr */
+#define GPC_PHYADDR_3	BIT_11	/* Bit 3 of Phy Addr */
+#define GPC_PHYADDR_2	BIT_10	/* Bit 2 of Phy Addr */
+#define GPC_PHYADDR_1	BIT_9	/* Bit 1 of Phy Addr */
+#define GPC_PHYADDR_0	BIT_8	/* Bit 0 of Phy Addr */
+						/* Bits  7..2:	reserved */
+#define GPC_RST_CLR		BIT_1	/* Clear GPHY Reset */
+#define GPC_RST_SET		BIT_0	/* Set   GPHY Reset */
+
+#define GPC_HWCFG_GMII_COP	(GPC_HWCFG_M_3 | GPC_HWCFG_M_2 | \
+							 GPC_HWCFG_M_1 | GPC_HWCFG_M_0)
+
+#define GPC_HWCFG_GMII_FIB	(				 GPC_HWCFG_M_2 | \
+							 GPC_HWCFG_M_1 | GPC_HWCFG_M_0)
+
+#define GPC_ANEG_ADV_ALL_M	(GPC_ANEG_3 | GPC_ANEG_2 | \
+							 GPC_ANEG_1 | GPC_ANEG_0)
+
+/* forced speed and duplex mode (don't mix with other ANEG bits) */
+#define GPC_FRC10MBIT_HALF	0
+#define GPC_FRC10MBIT_FULL	GPC_ANEG_0
+#define GPC_FRC100MBIT_HALF	GPC_ANEG_1
+#define GPC_FRC100MBIT_FULL	(GPC_ANEG_0 | GPC_ANEG_1)
+
+/* auto-negotiation with limited advertised speeds */
+/* mix only with master/slave settings (for copper) */
+#define GPC_ADV_1000_HALF	GPC_ANEG_2
+#define GPC_ADV_1000_FULL	GPC_ANEG_3
+#define GPC_ADV_ALL			(GPC_ANEG_2 | GPC_ANEG_3)
+
+/* master/slave settings */
+/* only for copper with 1000 Mbps */
+#define GPC_FORCE_MASTER	0
+#define GPC_FORCE_SLAVE		GPC_ANEG_0
+#define GPC_PREF_MASTER		GPC_ANEG_1
+#define GPC_PREF_SLAVE		(GPC_ANEG_1 | GPC_ANEG_0)
+
+/*	GMAC_IRQ_SRC	 8 bit	GMAC Interrupt Source Reg (YUKON only) */
+/*	GMAC_IRQ_MSK	 8 bit	GMAC Interrupt Mask   Reg (YUKON only) */
+#define GM_IS_TX_CO_OV	BIT_5		/* Transmit Counter Overflow IRQ */
+#define GM_IS_RX_CO_OV	BIT_4		/* Receive Counter Overflow IRQ */
+#define GM_IS_TX_FF_UR	BIT_3		/* Transmit FIFO Underrun */
+#define GM_IS_TX_COMPL	BIT_2		/* Frame Transmission Complete */
+#define GM_IS_RX_FF_OR	BIT_1		/* Receive FIFO Overrun */
+#define GM_IS_RX_COMPL	BIT_0		/* Frame Reception Complete */
+
+#define GMAC_DEF_MSK	(GM_IS_TX_CO_OV | GM_IS_RX_CO_OV | \
+						GM_IS_TX_FF_UR)
+
+/*	GMAC_LINK_CTRL		16 bit	GMAC Link Control Reg (YUKON only) */
+						/* Bits 15.. 2:	reserved */
+#define GMLC_RST_CLR	BIT_1S		/* Clear GMAC Link Reset */
+#define GMLC_RST_SET	BIT_0S		/* Set   GMAC Link Reset */
+
+
+/*	WOL_CTRL_STAT		16 bit	WOL Control/Status Reg */
+#define WOL_CTL_LINK_CHG_OCC			BIT_15S
+#define WOL_CTL_MAGIC_PKT_OCC			BIT_14S
+#define WOL_CTL_PATTERN_OCC				BIT_13S
+
+#define WOL_CTL_CLEAR_RESULT			BIT_12S
+
+#define WOL_CTL_ENA_PME_ON_LINK_CHG		BIT_11S
+#define WOL_CTL_DIS_PME_ON_LINK_CHG		BIT_10S
+#define WOL_CTL_ENA_PME_ON_MAGIC_PKT	BIT_9S
+#define WOL_CTL_DIS_PME_ON_MAGIC_PKT	BIT_8S
+#define WOL_CTL_ENA_PME_ON_PATTERN		BIT_7S
+#define WOL_CTL_DIS_PME_ON_PATTERN		BIT_6S
+
+#define WOL_CTL_ENA_LINK_CHG_UNIT		BIT_5S
+#define WOL_CTL_DIS_LINK_CHG_UNIT		BIT_4S
+#define WOL_CTL_ENA_MAGIC_PKT_UNIT		BIT_3S
+#define WOL_CTL_DIS_MAGIC_PKT_UNIT		BIT_2S
+#define WOL_CTL_ENA_PATTERN_UNIT		BIT_1S
+#define WOL_CTL_DIS_PATTERN_UNIT		BIT_0S
+
+#define WOL_CTL_DEFAULT				\
+	(WOL_CTL_DIS_PME_ON_LINK_CHG |	\
+	WOL_CTL_DIS_PME_ON_PATTERN |	\
+	WOL_CTL_DIS_PME_ON_MAGIC_PKT |	\
+	WOL_CTL_DIS_LINK_CHG_UNIT |		\
+	WOL_CTL_DIS_PATTERN_UNIT |		\
+	WOL_CTL_DIS_MAGIC_PKT_UNIT)
+	
+/*	WOL_MATCH_CTL		 8 bit	WOL Match Control Reg */
+#define WOL_CTL_PATT_ENA(x)				(BIT_0 << (x))
+
+#define SK_NUM_WOL_PATTERN		7
+#define SK_PATTERN_PER_WORD		4
+#define SK_BITMASK_PATTERN		7
+#define SK_POW_PATTERN_LENGTH	128
+
+#define WOL_LENGTH_MSK		0x7f
+#define WOL_LENGTH_SHIFT	8
 
 
 /* Receive and Transmit Descriptors ******************************************/
@@ -1357,55 +1806,56 @@
 /* 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 RxD */
+	SK_U32	RxAdrLo;		/* Physical Rx Buffer Address lower dword */
+	SK_U32	RxAdrHi;		/* Physical Rx Buffer Address upper dword */
+	SK_U32	RxStat;			/* Receive Frame Status Word */
+	SK_U32	RxTiSt;			/* Receive Time Stamp (from XMAC on GENESIS) */
 #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;
 
 /*
  * Drivers which use the reverse descriptor feature (PCI_OUR_REG_2)
  * should set the define SK_USE_REV_DESC.
- * Structures are 'normaly' not endianess dependent. But in 
+ * Structures are 'normaly' not endianess dependent. But in
  * this case the SK_U16 fields are bound to bit positions inside the
  * descriptor. RxTcpSum1 e.g. must start at bit 0 within the 6.th DWord.
  * The bit positions inside a DWord are of course endianess dependent and
- * swaps if the DWord is swaped by the hardware.
+ * swaps if the DWord is swapped by the hardware.
  */
 
 
 /* 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*/
+/*	RxCtrl		Receive  Buffer Control Field */
+#define BMU_OWN			BIT_31	/* OWN bit: 0=host/1=BMU */
+#define BMU_STF			BIT_30	/* Start of Frame */
+#define BMU_EOF			BIT_29	/* End of Frame */
+#define BMU_IRQ_EOB		BIT_28	/* Req "End of Buffer" IRQ */
+#define BMU_IRQ_EOF		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		BIT_26	/* (Tx)	Store & Forward Frame */
+#define BMU_NO_FCS		BIT_25	/* (Tx) Disable MAC FCS (CRC) generation */
+#define BMU_SW			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_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 */
-#define	BMU_TCP_CHECK	0x00560000L	/* 		Descr with TCP ext */
-#define	BMU_BBC			0x0000FFFFL	/* Bit 15..0:	Buffer Byte Counter */
+#define BMU_DEV_0		BIT_26	/* (Rx)	Transfer data to Dev0 */
+#define BMU_STAT_VAL	BIT_25	/* (Rx)	Rx Status Valid */
+#define BMU_TIST_VAL	BIT_24	/* (Rx)	Rx TimeStamp Valid */
+								/* Bit 23..16:	BMU Check Opcodes */
+#define BMU_CHECK		(0x55L<<16)	/* Default BMU check */
+#define BMU_TCP_CHECK	(0x56L<<16)	/* Descr with TCP ext */
+#define BMU_UDP_CHECK	(0x57L<<16)	/* Descr with UDP ext (YUKON only) */
+#define BMU_BBC			0xFFFFL	/* Bit 15.. 0:	Buffer Byte Counter */
 
 /*	TxStat		Transmit Frame Status Word */
 /*	RxStat		Receive Frame Status Word */
@@ -1421,9 +1871,9 @@
 /*
  * 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_PAGES	0x20000L	/* Every byte has a single page */
+#define MAX_FADDR	1			/* 1 byte per page */
+#define SKFDDI_PSZ	8			/* address PROM size */
 
 /* macros ********************************************************************/
 
@@ -1440,59 +1890,67 @@
 /*
  *	Macro Q_ADDR()
  *
- *	Use this macro to address the Receive and Transmit Queue Registers.
+ *	Use this macro to access the Receive and Transmit Queue Registers.
  *
- * para	Queue	Queue to address.
- *			Values: Q_R1, Q_R2, Q_XS1, Q_XA1, Q_XS2, and Q_XA2
+ * para:	
+ *	Queue	Queue to access.
+ *				Values: Q_R1, Q_R2, Q_XS1, Q_XA1, Q_XS2, and Q_XA2
  *	Offs	Queue register offset.
- *			Values: Q_D, Q_DA_L ... Q_T2, Q_T3
+ *				Values: Q_D, Q_DA_L ... Q_T2, Q_T3
  *
- * usage	SK_IN32(pAC,Q_ADDR(Q_R2,Q_BC),pVal)
+ * usage	SK_IN32(pAC, Q_ADDR(Q_R2, Q_BC), pVal)
  */
-#define Q_ADDR(Queue,Offs)	(B8_Q_REGS + (Queue) + (Offs))
+#define Q_ADDR(Queue, Offs)	(B8_Q_REGS + (Queue) + (Offs))
 
 /*
  *	Macro RB_ADDR()
  *
- *	Use this macro to address the RAM Buffer Registers.
+ *	Use this macro to access the RAM Buffer Registers.
  *
- * para	Queue	Queue to address.
- *			Values: Q_R1, Q_R2, Q_XS1, Q_XA1, Q_XS2, and Q_XA2
+ * para:	
+ *	Queue	Queue to access.
+ *				Values: Q_R1, Q_R2, Q_XS1, Q_XA1, Q_XS2, and Q_XA2
  *	Offs	Queue register offset.
- *			Values: RB_START, RB_END ... RB_LEV, RB_CTRL
+ *				Values: RB_START, RB_END ... RB_LEV, RB_CTRL
  *
- * usage	SK_IN32(pAC,RB_ADDR(Q_R2,RB_RP),pVal)
+ * usage	SK_IN32(pAC, RB_ADDR(Q_R2, RB_RP), pVal)
  */
-#define RB_ADDR(Queue,Offs)	(B16_RAM_REGS + (Queue) + (Offs))
+#define RB_ADDR(Queue, Offs)	(B16_RAM_REGS + (Queue) + (Offs))
 
 
 /*
  * MAC Related Registers
  */
-#define	MAC_1		0	/* belongs to the port near the slot */
+#define MAC_1		0	/* belongs to the port near the slot */
 #define MAC_2		1	/* belongs to the port far away from the slot */
 
 /*
  *	Macro MR_ADDR()
  *
- *	Use this macro to address a MAC Related Registers in side the ASIC.
+ *	Use this macro to access a MAC Related Registers inside the ASIC.
  *
- * para	Queue	Queue to address.
- *			Values:	TXA_ITI_INI	...	TXA_TEST,
- *				RX_MFF_EA	...	RX_LED_TST,
- *				LNK_SYNC_INI	...	LNK_LED_REG, and
- *				TX_MFF_EA	...	TX_LED_TST
- *	Mac	MAC to address.
- *			Values: MAC_1, MAC_2
+ * para:	
+ *	Mac		MAC to access.
+ *				Values: MAC_1, MAC_2
+ *	Offs	MAC register offset.
+ *				Values: RX_MFF_EA, RX_MFF_WP ... LNK_LED_REG,
+ *						TX_MFF_EA, TX_MFF_WP ... TX_LED_TST
  *
- * usage	SK_IN32(pAC,MR_ADDR(MAC_1,TX_MFF_EA),pVal)
+ * usage	SK_IN32(pAC, MR_ADDR(MAC_1, TX_MFF_EA), pVal)
  */
-#define MR_ADDR(Mac,Offs)	(((Mac) << 7) + (Offs))
+#define MR_ADDR(Mac, Offs)	(((Mac) << 7) + (Offs))
 
+#ifdef	SK_LITTLE_ENDIAN
+#define XM_WORD_LO	0
+#define XM_WORD_HI	1
+#else	/* !SK_LITTLE_ENDIAN */
+#define XM_WORD_LO	1
+#define XM_WORD_HI	0
+#endif	/* !SK_LITTLE_ENDIAN */
 
 
 /*
- * macros to access the XMAC
+ * macros to access the XMAC (GENESIS only)
  *
  * XM_IN16(),		to read a 16 bit register (e.g. XM_MMU_CMD)
  * XM_OUT16(),		to write a 16 bit register (e.g. XM_MMU_CMD)
@@ -1503,43 +1961,37 @@
  * XM_INHASH(),		to read the XM_HSM_CHK register
  * XM_OUTHASH()		to write the XM_HSM_CHK register
  *
- * para:	Mac	XMAC to address		values: MAC_1 or MAC_2
- *		IoC	I/O context needed for SK IO macros
- *		Reg	XMAC Register to read or write
- *		(p)Val	Value or pointer to the value which should be read or
- *			written.
+ * para:
+ *	Mac		XMAC to access		values: MAC_1 or MAC_2
+ *	IoC		I/O context needed for SK I/O macros
+ *	Reg		XMAC Register to read or write
+ *	(p)Val	Value or pointer to the value which should be read or written
  *
  * usage:	XM_OUT16(IoC, MAC_1, XM_MMU_CMD, Value);
  */
 
-#ifdef	SK_LITTLE_ENDIAN
-#define	XM_WORD_LO	0
-#define XM_WORD_HI	1
-#else	/* !SK_LITTLE_ENDIAN */
-#define	XM_WORD_LO	1
-#define XM_WORD_HI	0
-#endif	/* !SK_LITTLE_ENDIAN */
+#define XMA(Mac, Reg)									\
+	((BASE_XMAC_1 + (Mac) * (BASE_XMAC_2 - BASE_XMAC_1)) | ((Reg) << 1))
 
-#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_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_OUT16(IoC, Mac, Reg, Val)					\
+	SK_OUT16((IoC), XMA((Mac), (Reg)), (Val))
 
-#define XM_IN32(IoC,Mac,Reg,pVal) {						\
+#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_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) & 0xffffL));			\
+	SK_OUT16((IoC), XMA((Mac), (Reg+2)), (SK_U16)(((Val) >> 16) & 0xffffL));\
 }
 
-/*
- * Remember: we are always writing to / reading from LITTLE ENDIAN memory
- */
+/* Remember: we are always writing to / reading from LITTLE ENDIAN memory */
 
 #define XM_INADDR(IoC, Mac, Reg, pVal) {				\
 	SK_U16	Word;										\
@@ -1606,32 +2058,150 @@
 }
 
 /*
+ * macros to access the GMAC (YUKON only)
+ *
+ * GM_IN16(),		to read  a 16 bit register (e.g. GM_GP_STAT)
+ * GM_OUT16(),		to write a 16 bit register (e.g. GM_GP_CTRL)
+ * GM_IN32(),		to read  a 32 bit register (e.g. GM_)
+ * GM_OUT32(),		to write a 32 bit register (e.g. GM_)
+ * GM_INADDR(),		to read  a network address register (e.g. GM_SRC_ADDR_1L)
+ * GM_OUTADDR(),	to write a network address register (e.g. GM_SRC_ADDR_2L)
+ * GM_INHASH(),		to read  the GM_MC_ADDR_H1 register
+ * GM_OUTHASH()		to write the GM_MC_ADDR_H1 register
+ *
+ * para:
+ *	Mac		GMAC to access		values: MAC_1 or MAC_2
+ *	IoC		I/O context needed for SK I/O macros
+ *	Reg		GMAC Register to read or write
+ *	(p)Val	Value or pointer to the value which should be read or written
+ *
+ * usage:	GM_OUT16(IoC, MAC_1, GM_GP_CTRL, Value);
+ */
+
+#define GMA(Mac, Reg)									\
+	((BASE_GMAC_1 + (Mac) * (BASE_GMAC_2 - BASE_GMAC_1)) | (Reg))
+
+#define GM_IN16(IoC, Mac, Reg, pVal)					\
+	SK_IN16((IoC), GMA((Mac), (Reg)), (pVal))
+
+#define GM_OUT16(IoC, Mac, Reg, Val)					\
+	SK_OUT16((IoC), GMA((Mac), (Reg)), (Val))
+
+#define GM_IN32(IoC, Mac, Reg, pVal) {					\
+	SK_IN16((IoC), GMA((Mac), (Reg)),					\
+		(SK_U16 *)&((SK_U16 *)(pVal))[XM_WORD_LO]);		\
+	SK_IN16((IoC), GMA((Mac), (Reg+4)),					\
+		(SK_U16 *)&((SK_U16 *)(pVal))[XM_WORD_HI]);		\
+}
+
+#define GM_OUT32(IoC, Mac, Reg, Val) {										\
+	SK_OUT16((IoC), GMA((Mac), (Reg)), (SK_U16)((Val) & 0xffffL));			\
+	SK_OUT16((IoC), GMA((Mac), (Reg+4)), (SK_U16)(((Val) >> 16) & 0xffffL));\
+}
+
+#define GM_INADDR(IoC, Mac, Reg, pVal) {				\
+	SK_U16	Word;										\
+	SK_U8	*pByte;										\
+	pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0];				\
+	SK_IN16((IoC), GMA((Mac), (Reg)), &Word);			\
+	pByte[0] = (SK_U8)(Word  & 0x00ff);					\
+	pByte[1] = (SK_U8)((Word >> 8) & 0x00ff);			\
+	SK_IN16((IoC), GMA((Mac), (Reg+4)), &Word);			\
+	pByte[2] = (SK_U8)(Word  & 0x00ff);					\
+	pByte[3] = (SK_U8)((Word >> 8) & 0x00ff);			\
+	SK_IN16((IoC), GMA((Mac), (Reg+8)), &Word);			\
+	pByte[4] = (SK_U8)(Word  & 0x00ff);					\
+	pByte[5] = (SK_U8)((Word >> 8) & 0x00ff);			\
+}
+
+#define GM_OUTADDR(IoC, Mac, Reg, pVal) {				\
+	SK_U8	*pByte;										\
+	pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0];				\
+	SK_OUT16((IoC), GMA((Mac), (Reg)), (SK_U16)			\
+		(((SK_U16)(pByte[0]) & 0x00ff) |				\
+		(((SK_U16)(pByte[1]) << 8) & 0xff00)));			\
+	SK_OUT16((IoC), GMA((Mac), (Reg+4)), (SK_U16)		\
+		(((SK_U16)(pByte[2]) & 0x00ff) |				\
+		(((SK_U16)(pByte[3]) << 8) & 0xff00)));			\
+	SK_OUT16((IoC), GMA((Mac), (Reg+8)), (SK_U16)		\
+		(((SK_U16)(pByte[4]) & 0x00ff) |				\
+		(((SK_U16)(pByte[5]) << 8) & 0xff00)));			\
+}
+
+#define GM_INHASH(IoC, Mac, Reg, pVal) {				\
+	SK_U16	Word;										\
+	SK_U8	*pByte;										\
+	pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0];				\
+	SK_IN16((IoC), GMA((Mac), (Reg)), &Word);			\
+	pByte[0] = (SK_U8)(Word  & 0x00ff);					\
+	pByte[1] = (SK_U8)((Word >> 8) & 0x00ff);			\
+	SK_IN16((IoC), GMA((Mac), (Reg+4)), &Word);			\
+	pByte[2] = (SK_U8)(Word  & 0x00ff);					\
+	pByte[3] = (SK_U8)((Word >> 8) & 0x00ff);			\
+	SK_IN16((IoC), GMA((Mac), (Reg+8)), &Word);			\
+	pByte[4] = (SK_U8)(Word  & 0x00ff);					\
+	pByte[5] = (SK_U8)((Word >> 8) & 0x00ff);			\
+	SK_IN16((IoC), GMA((Mac), (Reg+12)), &Word);		\
+	pByte[6] = (SK_U8)(Word  & 0x00ff);					\
+	pByte[7] = (SK_U8)((Word >> 8) & 0x00ff);			\
+}
+
+#define GM_OUTHASH(IoC, Mac, Reg, pVal) {				\
+	SK_U8	*pByte;										\
+	pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0];				\
+	SK_OUT16((IoC), GMA((Mac), (Reg)), (SK_U16)			\
+		(((SK_U16)(pByte[0]) & 0x00ff)|					\
+		(((SK_U16)(pByte[1]) << 8) & 0xff00)));			\
+	SK_OUT16((IoC), GMA((Mac), (Reg+4)), (SK_U16)		\
+		(((SK_U16)(pByte[2]) & 0x00ff)|					\
+		(((SK_U16)(pByte[3]) << 8) & 0xff00)));			\
+	SK_OUT16((IoC), GMA((Mac), (Reg+8)), (SK_U16)		\
+		(((SK_U16)(pByte[4]) & 0x00ff)|					\
+		(((SK_U16)(pByte[5]) << 8) & 0xff00)));			\
+	SK_OUT16((IoC), GMA((Mac), (Reg+12)), (SK_U16)		\
+		(((SK_U16)(pByte[6]) & 0x00ff)|					\
+		(((SK_U16)(pByte[7]) << 8) & 0xff00)));			\
+}
+
+/*
+ * Different MAC Types
+ */
+#define SK_MAC_XMAC		0	/* Xaqti XMAC II */
+#define SK_MAC_GMAC		1	/* Marvell GMAC */
+
+/*
  * Different PHY Types
  */
-#define SK_PHY_XMAC	0	/* integrated in Xmac II*/
-#define SK_PHY_BCOM	1	/* Broadcom BCM5400 */
-#define SK_PHY_LONE	2	/* Level One LXT1000 */
-#define SK_PHY_NAT	3	/* National DP83891 */ 
+#define SK_PHY_XMAC			0	/* integrated in XMAC II */
+#define SK_PHY_BCOM			1	/* Broadcom BCM5400 */
+#define SK_PHY_LONE			2	/* Level One LXT1000 */
+#define SK_PHY_NAT			3	/* National DP83891 */
+#define SK_PHY_MARV_COPPER	4	/* Marvell 88E1011S */
+#define SK_PHY_MARV_FIBER	5	/* Marvell 88E1011S working on fiber */
 
 /*
- * PHY addresses (bits 8..12 of PHY address reg)
+ * PHY addresses (bits 12..8 of PHY address reg)
  */
 #define PHY_ADDR_XMAC	(0<<8)
 #define PHY_ADDR_BCOM	(1<<8)
 #define PHY_ADDR_LONE	(3<<8)
 #define PHY_ADDR_NAT	(0<<8)
+		
+/* GPHY address (bits 15..11 of SMI control reg) */
+#define PHY_ADDR_MARV	0
 
 /*
  * macros to access the PHY
  *
  * PHY_READ()		read a 16 bit value from the PHY
- * PHY_WIRTE()		write a 16 bit value to the PHY
+ * PHY_WRITE()		write a 16 bit value to the PHY
  *
- * para:	IoC	I/O context needed for SK IO macros
- *		pPort	Pointer to port struct for PhyAddr
- * 		Mac	XMAC to address		values: MAC_1 or MAC_2
- *		PhyReg	PHY Register to read or write
- *		(p)Val	Value or pointer to the value which should be read or
+ * para:	
+ * 	IoC		I/O context needed for SK I/O macros
+ * 	pPort	Pointer to port struct for PhyAddr
+ * 	Mac		XMAC to access		values: MAC_1 or MAC_2
+ * 	PhyReg	PHY Register to read or write
+ * 	(p)Val	Value or pointer to the value which should be read or
  *			written.
  *
  * usage:	PHY_READ(IoC, pPort, MAC_1, PHY_CTRL, Value);
@@ -1672,7 +2242,7 @@
 		XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal));						\
 	}  																	\
 }
-#endif
+#endif /* DEBUG */
 
 #define PHY_WRITE(IoC, pPort, Mac, PhyReg, Val) {						\
 	SK_U16 Mmu;															\
@@ -1694,48 +2264,52 @@
 /*
  *	Macro PCI_C()
  *
- *	Use this macro to address PCI config register from the IO space.
+ *	Use this macro to access PCI config register from the I/O space.
  *
- * para	Addr	PCI configuration register to address.
+ * para:
+ *	Addr	PCI configuration register to access.
  *			Values:	PCI_VENDOR_ID	...	PCI_VPD_ADDR,
  *
- * usage	SK_IN16(pAC,PCI_C(PCI_VENDOR_ID),pVal);
+ * usage	SK_IN16(pAC, PCI_C(PCI_VENDOR_ID), pVal);
  */
 #define PCI_C(Addr)	(B7_CFG_SPC + (Addr))	/* PCI Config Space */
 
 /*
- *	Macro SK_ADDR(Base,Addr)
+ *	Macro SK_HW_ADDR(Base, Addr)
  *
  *	Calculates the effective HW address
  *
- * para Base	IO- or memory base address
+ * para:
+ *	Base	I/O or memory base address
  *	Addr	Address offset
  *
  * usage:	May be used in SK_INxx and SK_OUTxx macros
- *		#define SK_IN8(pAC,Addr,pVal) ...\
- *			*pVal = (SK_U8) inp(SK_ADDR(pAC->Hw.Iop,Addr)))
+ *		#define SK_IN8(pAC, Addr, pVal) ...\
+ *			*pVal = (SK_U8)inp(SK_HW_ADDR(pAC->Hw.Iop, Addr)))
  */
 #ifdef	SK_MEM_MAPPED_IO
-#define	SK_HW_ADDR(Base,Addr)	((Base)+(Addr))
+#define SK_HW_ADDR(Base, Addr)	((Base) + (Addr))
 #else	/* SK_MEM_MAPPED_IO */
-#define SK_HW_ADDR(Base,Addr)	((Base)+(((Addr)&0x7F)|((Addr)>>7 ? 0x80:0)))
+#define SK_HW_ADDR(Base, Addr)	\
+			((Base) + (((Addr) & 0x7f) | (((Addr) >> 7 > 0) ? 0x80 : 0)))
 #endif	/* SK_MEM_MAPPED_IO */
 
-#define	SZ_LONG	(sizeof(SK_U32))
+#define SZ_LONG	(sizeof(SK_U32))
 
 /*
  *	Macro SK_HWAC_LINK_LED()
  *
  *	Use this macro to set the link LED mode.
- * para pAC	Pointer to adapter context struct
- *	IoC	I/O context needed for SK IO macros
- *     	Port	Port number
+ * para:
+ *	pAC		Pointer to adapter context struct
+ *	IoC		I/O context needed for SK I/O macros
+ *  Port	Port number
  *	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 -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sk98lin/h/skgehwt.h linux-2.4.21-pre6/drivers/net/sk98lin/h/skgehwt.h
--- linux-2.4.20/drivers/net/sk98lin/h/skgehwt.h	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sk98lin/h/skgehwt.h	2003-03-26 23:49:29.000000000 +0000
@@ -1,32 +1,23 @@
 /******************************************************************************
  *
  * Name:	skhwt.h
- * Project:	Genesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.4 $
- * Date:	$Date: 1998/08/19 09:50:58 $
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.5 $
+ * Date:	$Date: 1999/11/22 13:54:24 $
  * Purpose:	Defines for the hardware timer functions
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1989-1998 SysKonnect,
+ *	(C)Copyright 1998,1999 SysKonnect,
  *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
- *	All Rights Reserved
  *
- *	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.
+ *	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.
  *
  ******************************************************************************/
@@ -36,6 +27,9 @@
  * 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 -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sk98lin/h/skgei2c.h linux-2.4.21-pre6/drivers/net/sk98lin/h/skgei2c.h
--- linux-2.4.20/drivers/net/sk98lin/h/skgei2c.h	2000-09-15 21:34:19.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sk98lin/h/skgei2c.h	2003-03-26 23:49:50.000000000 +0000
@@ -2,17 +2,15 @@
  *
  * Name:	skgei2c.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.17 $
- * Date:	$Date: 1999/11/22 13:55:25 $
- * Purpose:	Special genesis defines for I2C
- *		(taken from Monalisa (taken from Concentrator))
+ * Version:	$Revision: 1.23 $
+ * Date:	$Date: 2002/12/19 14:34:27 $
+ * Purpose:	Special GEnesis defines for TWSI
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998,1999 SysKonnect,
- *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *	(C)Copyright 1998-2002 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,6 +26,28 @@
  * History:
  *
  *	$Log: skgei2c.h,v $
+ *	Revision 1.23  2002/12/19 14:34:27  rschmidt
+ *	Added cast in macros SK_I2C_SET_BIT() and SK_I2C_CLR_BIT()
+ *	Editorial changes (TWSI)
+ *	
+ *	Revision 1.22  2002/10/14 16:45:56  rschmidt
+ *	Editorial changes (TWSI)
+ *	
+ *	Revision 1.21  2002/08/13 08:42:24  rschmidt
+ *	Changed define for SK_MIN_SENSORS back to 5
+ *	Merged defines for PHY PLL 3V3 voltage (A and B)
+ *	Editorial changes
+ *	
+ *	Revision 1.20  2002/08/06 09:43:56  jschmalz
+ *	Extensions and changes for Yukon
+ *	
+ *	Revision 1.19  2002/08/02 12:00:08  rschmidt
+ *	Added defines for YUKON sensors
+ *	Editorial changes
+ *	
+ *	Revision 1.18  2001/08/16 12:44:33  afischer
+ *	LM80 sensor init values corrected
+ *	
  *	Revision 1.17  1999/11/22 13:55:25  cgoos
  *	Changed license header to GPL.
  *	
@@ -70,7 +90,7 @@
  *	
  *	Revision 1.5  1998/08/17 06:52:21  malthoff
  *	Remove unrequired macros.
- *	Add macros for accessing I2C SW register.
+ *	Add macros for accessing TWSI SW register.
  *	
  *	Revision 1.4  1998/08/13 08:30:18  gklug
  *	add: conversion factors for read values
@@ -81,8 +101,8 @@
  *
  *	Revision 1.2  1998/08/11 07:54:38  gklug
  *	add: sensor states for GE sensors
- *	add: Macro to access I2c hardware register
- *	chg: Error messages for I2c errors
+ *	add: Macro to access TWSI hardware register
+ *	chg: Error messages for TWSI errors
  *
  *	Revision 1.1  1998/07/17 11:27:56  gklug
  *	Created.
@@ -92,7 +112,7 @@
  ******************************************************************************/
 
 /*
- * SKGEI2C.H	contains all SK-98xx specific defines for the I2C handling
+ * SKGEI2C.H	contains all SK-98xx specific defines for the TWSI handling
  */
 
 #ifndef _INC_SKGEI2C_H_
@@ -101,12 +121,12 @@
 /*
  * Macros to access the B2_I2C_CTRL
  */
-#define SK_I2C_CTL(IoC,flag,dev,reg,burst) \
-	SK_OUT32(IoC,B2_I2C_CTRL,\
-		(flag ? 0x80000000UL : 0x0L ) | \
+#define SK_I2C_CTL(IoC, flag, dev, reg, burst) \
+	SK_OUT32(IoC, B2_I2C_CTRL,\
+		(flag ? 0x80000000UL : 0x0L) | \
 		(((SK_U32) reg << 16) & I2C_ADDR) | \
 		(((SK_U32) dev << 9) & I2C_DEV_SEL) | \
-		(( burst << 4) & I2C_BURST_LEN) )
+		(( burst << 4) & I2C_BURST_LEN))
 
 #define SK_I2C_STOP(IoC) {				\
 	SK_U32	I2cCtrl;				\
@@ -114,29 +134,29 @@
 	SK_OUT32(IoC, B2_I2C_CTRL, I2cCtrl | I2C_STOP);	\
 }
 
-#define SK_I2C_GET_CTL(Ioc,pI2cCtrl)	SK_IN32(Ioc,B2_I2C_CTRL,pI2cCtrl)
+#define SK_I2C_GET_CTL(IoC, pI2cCtrl)	SK_IN32(IoC, B2_I2C_CTRL, pI2cCtrl)
 
 /*
- * Macros to access the I2C SW Registers
+ * Macros to access the TWSI SW Registers
  */
 #define SK_I2C_SET_BIT(IoC, SetBits) {			\
 	SK_U8	OrgBits;				\
 	SK_IN8(IoC, B2_I2C_SW, &OrgBits);		\
-	SK_OUT8(IoC, B2_I2C_SW, OrgBits | (SetBits));	\
+	SK_OUT8(IoC, B2_I2C_SW, OrgBits | (SK_U8)(SetBits));	\
 }
 
-#define SK_I2C_CLR_BIT(IoC,ClrBits) {			\
+#define SK_I2C_CLR_BIT(IoC, ClrBits) {			\
 	SK_U8	OrgBits;				\
 	SK_IN8(IoC, B2_I2C_SW, &OrgBits);		\
-	SK_OUT8(IoC, B2_I2C_SW, OrgBits & ~(ClrBits));	\
+	SK_OUT8(IoC, B2_I2C_SW, OrgBits & ~((SK_U8)(ClrBits)));	\
 }
 
-#define SK_I2C_GET_SW(IoC,pI2cSw)	SK_IN8(IoC,B2_I2C_SW,pI2cSw)
+#define SK_I2C_GET_SW(IoC, pI2cSw)	SK_IN8(IoC, B2_I2C_SW, pI2cSw)
 
 /*
  * define the possible sensor states
  */
-#define	SK_SEN_IDLE	0	/* Idle: sensor not read */
+#define	SK_SEN_IDLE		0	/* Idle: sensor not read */
 #define	SK_SEN_VALUE	1	/* Value Read cycle */
 #define	SK_SEN_VALEXT	2	/* Extended Value Read cycle */
 
@@ -147,7 +167,7 @@
 #define	SK_LM80_VT_LSB		22	/* 22mV LSB resolution */
 #define	SK_LM80_TEMP_LSB	10	/* 1 degree LSB resolution */
 #define	SK_LM80_TEMPEXT_LSB	5	/* 0.5 degree LSB resolution for the
-					 * extension value 
+					 * extension value
 					 */
 #define SK_LM80_FAN_FAKTOR	((22500L*60)/(1*2))
 /* formula: counter = (22500*60)/(rpm * divisor * pulses/2)
@@ -163,20 +183,27 @@
 #define	SK_MIN_SENSORS	5	/* minimal no. of installed sensors */
 
 /*
+ * To watch the statemachine (JS) use the timer in two ways instead of one as hitherto
+ */
+#define	SK_TIMER_WATCH_STATEMACHINE	0	/* Watch the statemachine to finish in a specific time */
+#define	SK_TIMER_NEW_GAUGING    	1	/* Start a new gauging when timer expires */
+
+
+/*
  * Defines for the individual Thresholds
  */
 
 /* Temperature sensor */
-#define	SK_SEN_ERRHIGH0		800	/* Temperature High Err Threshold */
-#define	SK_SEN_WARNHIGH0	700	/* Temperature High Warn Threshold */
-#define	SK_SEN_WARNLOW0		100	/* Temperature Low Err Threshold */
-#define	SK_SEN_ERRLOW0		0	/* Temperature Low Warn Threshold */
+#define	SK_SEN_TEMP_HIGH_ERR    800	/* Temperature High Err  Threshold */
+#define	SK_SEN_TEMP_HIGH_WARN	700	/* Temperature High Warn Threshold */
+#define	SK_SEN_TEMP_LOW_WARN	100	/* Temperature Low  Warn Threshold */
+#define	SK_SEN_TEMP_LOW_ERR       0	/* Temperature Low  Err  Threshold */
 
 /* VCC which should be 5 V */
-#define	SK_SEN_ERRHIGH1		5588	/* Voltage PCI High Err Threshold */
-#define	SK_SEN_WARNHIGH1	5346	/* Voltage PCI High Warn Threshold */
-#define	SK_SEN_WARNLOW1		4664	/* Voltage PCI Low Err Threshold */
-#define	SK_SEN_ERRLOW1		4422	/* Voltage PCI Low Warn Threshold */
+#define	SK_SEN_PCI_5V_HIGH_ERR  	5588	/* Voltage PCI High Err  Threshold */
+#define	SK_SEN_PCI_5V_HIGH_WARN     5346	/* Voltage PCI High Warn Threshold */
+#define	SK_SEN_PCI_5V_LOW_WARN		4664	/* Voltage PCI Low  Warn Threshold */
+#define	SK_SEN_PCI_5V_LOW_ERR		4422	/* Voltage PCI Low  Err  Threshold */
 
 /*
  * VIO may be 5 V or 3.3 V. Initialization takes two parts:
@@ -187,49 +214,66 @@
  * Warning limits are +-5% of the exepected voltage.
  * Error limits are +-10% of the expected voltage.
  */
-#define	SK_SEN_ERRHIGH2		5588	/* Voltage PCI-IO High Err Threshold */
-#define	SK_SEN_WARNHIGH2	5346	/* Voltage PCI-IO High Warn Threshold */
-#define	SK_SEN_WARNLOW2		3146	/* Voltage PCI-IO Low Err Threshold */
-#define	SK_SEN_ERRLOW2		2970	/* Voltage PCI-IO Low Warn Threshold */
+
+/* Bug fix AF: 16.Aug.2001: Correct the init base of LM80 sensor */
+
+#define	SK_SEN_PCI_IO_5V_HIGH_ERR	5566	/* + 10% V PCI-IO High Err Threshold */
+#define	SK_SEN_PCI_IO_5V_HIGH_WARN	5324	/* +  5% V PCI-IO High Warn Threshold */
+					/*		5000	mVolt */
+#define	SK_SEN_PCI_IO_5V_LOW_WARN	4686	/* -  5% V PCI-IO Low Warn Threshold */
+#define	SK_SEN_PCI_IO_5V_LOW_ERR	4444	/* - 10% V PCI-IO Low Err Threshold */
+
+#define	SK_SEN_PCI_IO_RANGE_LIMITER	4000	/* 4000 mV range delimiter */
 
 /* correction values for the second pass */
-#define	SK_SEN_ERRHIGH2C	3630	/* Voltage PCI-IO High Err Threshold */
-#define	SK_SEN_WARNHIGH2C	3476	/* Voltage PCI-IO High Warn Threshold */
-#define	SK_SEN_WARNLOW2C	4664	/* Voltage PCI-IO Low Err Threshold */
-#define	SK_SEN_ERRLOW2C		4422	/* Voltage PCI-IO Low Warn Threshold */
+#define	SK_SEN_PCI_IO_3V3_HIGH_ERR	3850	/* + 15% V PCI-IO High Err Threshold */
+#define	SK_SEN_PCI_IO_3V3_HIGH_WARN	3674	/* + 10% V PCI-IO High Warn Threshold */
+					/*		3300	mVolt */
+#define	SK_SEN_PCI_IO_3V3_LOW_WARN  2926	/* - 10% V PCI-IO Low Warn Threshold */
+#define	SK_SEN_PCI_IO_3V3_LOW_ERR   2772	/* - 15% V PCI-IO Low Err  Threshold */
+
 
 /*
  * VDD voltage
  */
-#define	SK_SEN_ERRHIGH3		3630	/* Voltage ASIC High Err Threshold */
-#define	SK_SEN_WARNHIGH3	3476	/* Voltage ASIC High Warn Threshold */
-#define	SK_SEN_WARNLOW3		3146	/* Voltage ASIC Low Err Threshold */
-#define	SK_SEN_ERRLOW3		2970	/* Voltage ASIC Low Warn Threshold */
+#define	SK_SEN_VDD_HIGH_ERR	    3630	/* Voltage ASIC High Err  Threshold */
+#define	SK_SEN_VDD_HIGH_WARN    3476	/* Voltage ASIC High Warn Threshold */
+#define	SK_SEN_VDD_LOW_WARN     3146	/* Voltage ASIC Low  Warn Threshold */
+#define	SK_SEN_VDD_LOW_ERR      2970	/* Voltage ASIC Low  Err  Threshold */
+
+/*
+ * PHY PLL 3V3 voltage
+ */
+#define	SK_SEN_PLL_3V3_HIGH_ERR		3630	/* Voltage PMA High Err  Threshold */
+#define	SK_SEN_PLL_3V3_HIGH_WARN	3476	/* Voltage PMA High Warn Threshold */
+#define	SK_SEN_PLL_3V3_LOW_WARN		3146	/* Voltage PMA Low  Warn Threshold */
+#define	SK_SEN_PLL_3V3_LOW_ERR		2970	/* Voltage PMA Low  Err  Threshold */
 
 /*
- * PLC_3V3 voltage
- * PHY_PLL_A_3V3 voltage
+ * VAUX (YUKON only)
  */
-#define	SK_SEN_ERRHIGH4		3630	/* Voltage PMA High Err Threshold */
-#define	SK_SEN_WARNHIGH4	3476	/* Voltage PMA High Warn Threshold */
-#define	SK_SEN_WARNLOW4		3146	/* Voltage PMA Low Err Threshold */
-#define	SK_SEN_ERRLOW4		2970	/* Voltage PMA Low Warn Threshold */
+#define	SK_SEN_VAUX_3V3_HIGH_ERR	3630	/* Voltage VAUX High Err Threshold */
+#define	SK_SEN_VAUX_3V3_HIGH_WARN	3476	/* Voltage VAUX High Warn Threshold */
+#define	SK_SEN_VAUX_3V3_LOW_WARN	3146	/* Voltage VAUX Low Warn Threshold */
+#define	SK_SEN_VAUX_3V3_LOW_ERR	    2970	/* Voltage VAUX Low Err Threshold */
+#define	SK_SEN_VAUX_0V_WARN_ERR	       0	/* if VAUX not present */
+#define	SK_SEN_VAUX_RANGE_LIMITER	1000	/* 1000 mV range delimiter */
 
 /*
- * PHY_2V5 voltage
+ * PHY 2V5 voltage
  */
-#define	SK_SEN_ERRHIGH5		2750	/* Voltage PHY High Err Threshold */
-#define	SK_SEN_WARNHIGH5	2640	/* Voltage PHY High Warn Threshold */
-#define	SK_SEN_WARNLOW5		2376	/* Voltage PHY Low Err Threshold */
-#define	SK_SEN_ERRLOW5		2222	/* Voltage PHY Low Warn Threshold */
+#define	SK_SEN_PHY_2V5_HIGH_ERR		2750	/* Voltage PHY High Err Threshold */
+#define	SK_SEN_PHY_2V5_HIGH_WARN	2640	/* Voltage PHY High Warn Threshold */
+#define	SK_SEN_PHY_2V5_LOW_WARN		2376	/* Voltage PHY Low Warn Threshold */
+#define	SK_SEN_PHY_2V5_LOW_ERR		2222	/* Voltage PHY Low Err Threshold */
 
 /*
- * PHY_PLL_B_3V3 voltage
+ * ASIC Core 1V5 voltage (YUKON only)
  */
-#define	SK_SEN_ERRHIGH6		3630	/* Voltage PMA High Err Threshold */
-#define	SK_SEN_WARNHIGH6	3476	/* Voltage PMA High Warn Threshold */
-#define	SK_SEN_WARNLOW6		3146	/* Voltage PMA Low Err Threshold */
-#define	SK_SEN_ERRLOW6		2970	/* Voltage PMA Low Warn Threshold */
+#define	SK_SEN_CORE_1V5_HIGH_ERR    1650	/* Voltage ASIC Core High Err Threshold */
+#define	SK_SEN_CORE_1V5_HIGH_WARN	1575	/* Voltage ASIC Core High Warn Threshold */
+#define	SK_SEN_CORE_1V5_LOW_WARN	1425	/* Voltage ASIC Core Low Warn Threshold */
+#define	SK_SEN_CORE_1V5_LOW_ERR 	1350	/* Voltage ASIC Core Low Err Threshold */
 
 /*
  * FAN 1 speed
@@ -239,10 +283,17 @@
  * error at:	70 %
  * no upper limit
  */
-#define	SK_SEN_ERRHIGH		20000	/* FAN Speed High Err Threshold */
-#define	SK_SEN_WARNHIGH		20000	/* FAN Speed High Warn Threshold */
-#define	SK_SEN_WARNLOW		5200	/* FAN Speed Low Err Threshold */
-#define	SK_SEN_ERRLOW		4550	/* FAN Speed Low Warn Threshold */
+#define	SK_SEN_FAN_HIGH_ERR		20000	/* FAN Speed High Err Threshold */
+#define	SK_SEN_FAN_HIGH_WARN	20000	/* FAN Speed High Warn Threshold */
+#define	SK_SEN_FAN_LOW_WARN 	5200	/* FAN Speed Low Warn Threshold */
+#define	SK_SEN_FAN_LOW_ERR		4550	/* FAN Speed Low Err Threshold */
+
+/*
+ * Some Voltages need dynamic thresholds
+ */
+#define	SK_SEN_DYN_INIT_NONE		 0  /* No dynamic init of thresholds */
+#define	SK_SEN_DYN_INIT_PCI_IO		10  /* Init PCI-IO with new thresholds */
+#define	SK_SEN_DYN_INIT_VAUX		11  /* Init VAUX with new thresholds */
 
 extern	int SkLm80ReadSensor(SK_AC *pAC, SK_IOC IoC, SK_SENSOR *pSen);
 #endif	/* n_INC_SKGEI2C_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sk98lin/h/skgeinit.h linux-2.4.21-pre6/drivers/net/sk98lin/h/skgeinit.h
--- linux-2.4.20/drivers/net/sk98lin/h/skgeinit.h	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sk98lin/h/skgeinit.h	2003-03-26 23:49:50.000000000 +0000
@@ -2,15 +2,15 @@
  *
  * Name:	skgeinit.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.51 $
- * Date:	$Date: 2001/02/09 12:26:38 $
+ * Version:	$Revision: 1.73 $
+ * Date:	$Date: 2002/11/15 12:47:25 $
  * Purpose:	Structures and prototypes for the GE Init Module
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998-2001 SysKonnect GmbH.
+ *	(C)Copyright 1998-2002 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 +26,115 @@
  * History:
  *
  *	$Log: skgeinit.h,v $
+ *	Revision 1.73  2002/11/15 12:47:25  rschmidt
+ *	Replaced error message SKERR_HWI_E024 for Cable Diagnostic with
+ *	Rx queue error in SkGeStopPort().
+ *	
+ *	Revision 1.72  2002/11/12 17:08:35  rschmidt
+ *	Added entries for Cable Diagnostic to Port structure
+ *	Added entries GIPciSlot64 and GIPciClock66 in s_GeInit structure
+ *	Added error message for Cable Diagnostic
+ *	Added prototypes for SkGmCableDiagStatus()
+ *	Editorial changes
+ *	
+ *	Revision 1.71  2002/10/21 11:26:10  mkarl
+ *	Changed interface of SkGeInitAssignRamToQueues().
+ *	
+ *	Revision 1.70  2002/10/14 08:21:32  rschmidt
+ *	Changed type of GICopperType, GIVauxAvail to SK_BOOL
+ *	Added entry PRxOverCnt to Port structure
+ *	Added entry GIYukon32Bit in s_GeInit structure
+ *	Editorial changes
+ *	
+ *	Revision 1.69  2002/10/09 16:57:15  mkarl
+ *	Added some constants and macros for SkGeInitAssignRamToQueues().
+ *	
+ *	Revision 1.68  2002/09/12 08:58:51  rwahl
+ *	Retrieve counters needed for XMAC errata workarounds directly because
+ *	PNMI returns corrected counter values (e.g. #10620).
+ *	
+ *	Revision 1.67  2002/08/16 14:40:30  rschmidt
+ *	Added entries GIGenesis and GICopperType in s_GeInit structure
+ *	Added prototypes for SkMacHashing()
+ *	Editorial changes
+ *	
+ *	Revision 1.66  2002/08/12 13:27:21  rschmidt
+ *	Added defines for Link speed capabilities
+ *	Added entry PLinkSpeedCap to Port structure
+ *	Added entry GIVauxAvail in s_GeInit structure
+ *	Added prototypes for SkMacPromiscMode()
+ *	Editorial changes
+ *	
+ *	Revision 1.65  2002/08/08 15:46:18  rschmidt
+ *	Added define SK_PHY_ACC_TO for PHY access timeout
+ *	Added define SK_XM_RX_HI_WM for XMAC Rx High Watermark
+ *	Added define SK_MIN_TXQ_SIZE for Min RAM Buffer Tx Queue Size
+ *	Added entry PhyId1 to Port structure
+ *	
+ *	Revision 1.64  2002/07/23 16:02:56  rschmidt
+ *	Added entry GIWolOffs in s_GeInit struct (HW-Bug in YUKON 1st rev.)
+ *	Added prototypes for: SkGePhyRead(), SkGePhyWrite()
+ *	
+ *	Revision 1.63  2002/07/18 08:17:38  rwahl
+ *	Corrected definitions for SK_LSPEED_xxx & SK_LSPEED_STAT_xxx.
+ *	
+ *	Revision 1.62  2002/07/17 18:21:55  rwahl
+ *	Added SK_LSPEED_INDETERMINATED define.
+ *	
+ *	Revision 1.61  2002/07/17 17:16:03  rwahl
+ *	- MacType now member of GIni struct.
+ *	- Struct alignment to 32bit.
+ *	- Editorial change.
+ *	
+ *	Revision 1.60  2002/07/15 18:23:39  rwahl
+ *	Added GeMacFunc to GE Init structure.
+ *	Added prototypes for SkXmUpdateStats(), SkGmUpdateStats(),
+ *	  SkXmMacStatistic(), SkGmMacStatistic(), SkXmResetCounter(),
+ *	  SkGmResetCounter(), SkXmOverflowStatus(), SkGmOverflowStatus().
+ *	Added defines for current link speed state.
+ *	Added ERRMSG defintions for MacUpdateStat() & MacStatistics().
+ *	
+ *	Revision 1.59  2002/07/15 15:40:22  rschmidt
+ *	Added entry PLinkSpeedUsed to Port structure
+ *	Editorial changes
+ *	
+ *	Revision 1.58  2002/06/10 09:36:30  rschmidt
+ *	Editorial changes.
+ *	
+ *	Revision 1.57  2002/06/05 08:18:00  rschmidt
+ *	Corrected alignment in Port Structure
+ *	Added new prototypes for GMAC
+ *	Editorial changes
+ *	
+ *	Revision 1.56  2002/04/25 11:38:12  rschmidt
+ *	Added defines for Link speed values
+ *	Added defines for Loopback parameters for MAC and PHY
+ *	Removed entry PRxCmd from Port structure
+ *	Added entry PLinkSpeed to Port structure
+ *	Added entries GIChipId and GIChipRev to GE Init structure
+ *	Removed entry GIAnyPortAct from GE Init structure
+ *	Added prototypes for: SkMacInit(), SkMacInitPhy(),
+ *	SkMacRxTxDisable(), SkMacSoftRst(), SkMacHardRst(), SkMacIrq(),
+ *	SkMacIrqDisable(), SkMacFlushTxFifo(), SkMacFlushRxFifo(),
+ *	SkMacAutoNegDone(), SkMacAutoNegLipaPhy(), SkMacSetRxTxEn(),
+ *	SkXmPhyRead(), SkXmPhyRead(), SkGmPhyWrite(), SkGmPhyWrite();
+ *	Removed prototypes for static functions in SkXmac2.c
+ *	Editorial changes
+ *	
+ *	Revision 1.55  2002/02/26 15:24:53  rwahl
+ *	Fix: no link with manual configuration (#10673). The previous fix for
+ *	#10639 was removed. So for RLMT mode = CLS the RLMT may switch to
+ *	misconfigured port. It should not occur for the other RLMT modes.
+ *	
+ *	Revision 1.54  2002/01/18 16:52:52  rwahl
+ *	Editorial corrections.
+ *	
+ *	Revision 1.53  2001/11/20 09:19:58  rwahl
+ *	Reworked bugfix #10639 (no dependency to RLMT mode).
+ *	
+ *	Revision 1.52  2001/10/26 07:52:23  afischer
+ *	Port switching bug in `check local link` mode
+ *	
  *	Revision 1.51  2001/02/09 12:26:38  cgoos
  *	Inserted #ifdef DIAG for half duplex workaround timer.
  *	
@@ -130,7 +239,7 @@
  *	Add GIRamOffs.
  *	
  *	Revision 1.20  1998/10/19 07:28:37  malthoff
- *	Add prototyp for SkGeInitRamIface().
+ *	Add prototype for SkGeInitRamIface().
  *	
  *	Revision 1.19  1998/10/14 14:47:48  malthoff
  *	SK_TIMER should not be defined for Diagnostics.
@@ -156,7 +265,7 @@
  *	Add some error log messages.
  *	
  *	Revision 1.13  1998/10/06 14:13:14  malthoff
- *	Add prototyp for SkGeLoadLnkSyncCnt().
+ *	Add prototype for SkGeLoadLnkSyncCnt().
  *
  *	Revision 1.12  1998/10/05 11:29:53  malthoff
  *	bug fix: A comment was not closed.
@@ -194,7 +303,7 @@
  *	Revision 1.4  1998/09/03 09:55:31  malthoff
  *	Add constants for parameters Dir and RstMode
  *	when calling SkGeStopPort().
- *	Rework the prototyp section.
+ *	Rework the prototype section.
  *	Add Queue Address offsets PRxQOff, PXsQOff, and PXaQOff.
  *	Remove Ioc with IoC.
  *
@@ -208,7 +317,6 @@
  *	Revision 1.1  1998/07/23 09:50:24  malthoff
  *	Created.
  *
- *
  ******************************************************************************/
 
 #ifndef __INC_SKGEINIT_H_
@@ -220,53 +328,49 @@
 
 /* defines ********************************************************************/
 
-/*
- * defines for modifying Link LED behaviour (has been used with SkGeLinkLED())
- */
-#define SK_LNK_OFF	LED_OFF
-#define SK_LNK_ON	(LED_ON | LED_BLK_OFF| LED_SYNC_OFF)	
-#define SK_LNK_BLINK	(LED_ON | LED_BLK_ON | LED_SYNC_ON)
-#define SK_LNK_PERM	(LED_ON | LED_BLK_OFF| LED_SYNC_ON)
-#define SK_LNK_TST	(LED_ON | LED_BLK_ON | LED_SYNC_OFF)
-
-/*
- * defines for parameter 'Mode' when calling SK_HWAC_LINK_LED()
- */
-#define SK_LED_OFF	LED_OFF
-#define SK_LED_ACTIVE	(LED_ON | LED_BLK_OFF| LED_SYNC_OFF)
-#define SK_LED_STANDBY	(LED_ON | LED_BLK_ON| LED_SYNC_OFF)
+/* modifying Link LED behaviour (used with SkGeLinkLED()) */
+#define SK_LNK_OFF		LED_OFF
+#define SK_LNK_ON		(LED_ON | LED_BLK_OFF | LED_SYNC_OFF)	
+#define SK_LNK_BLINK	(LED_ON | LED_BLK_ON  | LED_SYNC_ON)
+#define SK_LNK_PERM		(LED_ON | LED_BLK_OFF | LED_SYNC_ON)
+#define SK_LNK_TST		(LED_ON | LED_BLK_ON  | LED_SYNC_OFF)
+
+/* parameter 'Mode' when calling SK_HWAC_LINK_LED() */
+#define SK_LED_OFF		LED_OFF
+#define SK_LED_ACTIVE	(LED_ON | LED_BLK_OFF | LED_SYNC_OFF)
+#define SK_LED_STANDBY	(LED_ON | LED_BLK_ON  | LED_SYNC_OFF)
+
+/* addressing LED Registers in SkGeXmitLED() */
+#define XMIT_LED_INI	0
+#define XMIT_LED_CNT	(RX_LED_VAL - RX_LED_INI)
+#define XMIT_LED_CTRL	(RX_LED_CTRL- RX_LED_INI)
+#define XMIT_LED_TST	(RX_LED_TST - RX_LED_INI)
 
-/*
- * defines for parameter 'Mode' when calling SkGeXmitLED()
- */
+/* parameter 'Mode' when calling SkGeXmitLED() */
 #define SK_LED_DIS	0
 #define SK_LED_ENA	1
 #define SK_LED_TST	2
 
-/*
- * Counter and Timer constants, for a host clock of 62.5 MHz
- */
-#define SK_XMIT_DUR	0x002faf08L		/*  50 ms */
-#define SK_BLK_DUR	0x01dcd650L		/* 500 ms */
+/* Counter and Timer constants, for a host clock of 62.5 MHz */
+#define SK_XMIT_DUR		0x002faf08L		/*  50 ms */
+#define SK_BLK_DUR		0x01dcd650L		/* 500 ms */
 
 #define SK_DPOLL_DEF	0x00EE6B28L		/* 250 ms */
 #define SK_DPOLL_MAX	0x00FFFFFFL		/* ca. 268ms */
 
-#define SK_FACT_62	100			/* is given in percent */
-#define SK_FACT_53	 85
+#define SK_FACT_62		100			/* is given in percent */
+#define SK_FACT_53		 85
 
-/*
- * Timeout values
- */
-#define SK_MAC_TO_53	72		/* MAC arbiter timeout */
+/* Timeout values */
+#define SK_MAC_TO_53	72			/* MAC arbiter timeout */
 #define SK_PKT_TO_53	0x2000		/* Packet arbiter timeout */
 #define SK_PKT_TO_MAX	0xffff		/* Maximum value */
-#define SK_RI_TO_53	36		/* RAM interface timeout */
+#define SK_RI_TO_53		36			/* RAM interface timeout */
 
-/*
- * RAM Buffer High Pause Threshold values
- */
-#define SK_RB_ULPP	( 8 * 1024)	/* Upper Level in kB/8 */
+#define SK_PHY_ACC_TO	600000		/* PHY access timeout */
+
+/* RAM Buffer High Pause Threshold values */
+#define SK_RB_ULPP		( 8 * 1024)	/* Upper Level in kB/8 */
 #define SK_RB_LLPP_S	(10 * 1024)	/* Lower Level for small Queues */
 #define SK_RB_LLPP_B	(16 * 1024)	/* Lower Level for big Queues */
 
@@ -274,9 +378,12 @@
 #define SK_BMU_RX_WM	0x600		/* BMU Rx Watermark */
 #endif
 #ifndef SK_BMU_TX_WM
-#define SK_BMU_TX_WM	0x600		/* BMU Rx Watermark */
+#define SK_BMU_TX_WM	0x600		/* BMU Tx Watermark */
 #endif
 
+/* XMAC II Rx High Watermark */
+#define SK_XM_RX_HI_WM	0x05aa		/* 1450 */
+
 /* XMAC II Tx Threshold */
 #define SK_XM_THR_REDL	0x01fb		/* .. for redundant link usage */
 #define SK_XM_THR_SL	0x01fb		/* .. for single link adapters */
@@ -284,184 +391,218 @@
 #define SK_XM_THR_JUMBO	0x03fc		/* .. for jumbo frame usage */
 
 /* values for GIPortUsage */
-#define SK_RED_LINK	1		/* redundant link usage */
-#define SK_MUL_LINK	2		/* multiple link usage */
+#define SK_RED_LINK		1		/* redundant link usage */
+#define SK_MUL_LINK		2		/* multiple link usage */
 #define SK_JUMBO_LINK	3		/* driver uses jumbo frames */
 
-/* Minimum RAM Buffer Receive Queue Size */
-#define SK_MIN_RXQ_SIZE	16	/* 16 kB */
-/*
- * defines for parameter 'Dir' when calling SkGeStopPort()
- */
-#define	SK_STOP_TX	1	/* Stops the transmit path, resets the XMAC */
+/* Minimum RAM Buffer Rx Queue Size */
+#define SK_MIN_RXQ_SIZE	16		/* 16 kB */
+
+/* Minimum RAM Buffer Tx Queue Size */
+#define SK_MIN_TXQ_SIZE	16		/* 16 kB */
+
+/* Queue Size units */
+#define QZ_UNITS		0x7
+#define QZ_STEP			8
+
+/* Percentage of queue size from whole memory */
+/* 80 % for receive */
+#define RAM_QUOTA_RX	80L
+/* 0% for sync transfer */
+#define	RAM_QUOTA_SYNC	0L
+/* the rest (20%) is taken for async transfer */
+
+/* Get the rounded queue size in Bytes in 8k steps */
+#define ROUND_QUEUE_SIZE(SizeInBytes)					\
+	((((unsigned long) (SizeInBytes) + (QZ_STEP*1024L)-1) / 1024) &	\
+	~(QZ_STEP-1))
+
+/* Get the rounded queue size in KBytes in 8k steps */
+#define ROUND_QUEUE_SIZE_KB(Kilobytes) \
+	ROUND_QUEUE_SIZE((Kilobytes) * 1024L)
+
+/* Types of RAM Buffer Queues */
+#define SK_RX_SRAM_Q	1	/* small receive queue */
+#define SK_RX_BRAM_Q	2	/* big receive queue */
+#define SK_TX_RAM_Q		3	/* small or big transmit queue */
+
+/* parameter 'Dir' when calling SkGeStopPort() */
+#define SK_STOP_TX	1	/* Stops the transmit path, resets the XMAC */
 #define SK_STOP_RX	2	/* Stops the receive path */
-#define SK_STOP_ALL	3	/* Stops rx and tx path, resets the XMAC */
+#define SK_STOP_ALL	3	/* Stops Rx and Tx path, resets the XMAC */
 
-/*
- * defines for parameter 'RstMode' when calling SkGeStopPort()
- */
+/* parameter 'RstMode' when calling SkGeStopPort() */
 #define SK_SOFT_RST	1	/* perform a software reset */
 #define SK_HARD_RST	2	/* perform a hardware reset */
 
-/*
- * Define Init Levels
- */
-#define	SK_INIT_DATA	0	/* Init level 0: init data structures */
-#define	SK_INIT_IO	1	/* Init level 1: init with IOs */
-#define	SK_INIT_RUN	2	/* Init level 2: init for run time */
-
-/*
- * Set Link Mode Parameter
- */
-#define	SK_LMODE_HALF		1	/* Half Duplex Mode */
-#define	SK_LMODE_FULL		2	/* Full Duplex Mode */
-#define	SK_LMODE_AUTOHALF	3	/* AutoHalf Duplex Mode */
-#define	SK_LMODE_AUTOFULL	4	/* AutoFull Duplex Mode */
-#define	SK_LMODE_AUTOBOTH	5	/* AutoBoth Duplex Mode */
-#define	SK_LMODE_AUTOSENSE	6	/* configured mode auto sensing */
+/* Init Levels */
+#define SK_INIT_DATA	0	/* Init level 0: init data structures */
+#define SK_INIT_IO		1	/* Init level 1: init with IOs */
+#define SK_INIT_RUN		2	/* Init level 2: init for run time */
+
+/* Link Mode Parameter */
+#define SK_LMODE_HALF		1	/* Half Duplex Mode */
+#define SK_LMODE_FULL		2	/* Full Duplex Mode */
+#define SK_LMODE_AUTOHALF	3	/* AutoHalf Duplex Mode */
+#define SK_LMODE_AUTOFULL	4	/* AutoFull Duplex Mode */
+#define SK_LMODE_AUTOBOTH	5	/* AutoBoth Duplex Mode */
+#define SK_LMODE_AUTOSENSE	6	/* configured mode auto sensing */
 #define SK_LMODE_INDETERMINATED	7	/* Return value for virtual port if
-					 * multiple ports are differently
-					 * configured.
+								* multiple ports are differently configured.
+								*/
+
+/* Auto-negotiation timeout in 100ms granularity */
+#define SK_AND_MAX_TO		6	/* Wait 600 msec before link comes up */
+
+/* Auto-negotiation error codes */
+#define SK_AND_OK			0	/* no error */
+#define SK_AND_OTHER		1	/* other error than below */
+#define SK_AND_DUP_CAP		2	/* Duplex capabilities error */
+
+
+/* Link Speed Capabilities */
+#define SK_LSPEED_CAP_AUTO			(1<<0)	/* Automatic resolution */
+#define SK_LSPEED_CAP_10MBPS		(1<<1)	/* 10 Mbps */
+#define SK_LSPEED_CAP_100MBPS		(1<<2)	/* 100 Mbps */
+#define SK_LSPEED_CAP_1000MBPS		(1<<3)	/* 1000 Mbps */
+#define SK_LSPEED_CAP_INDETERMINATED (1<<4) /* Return value for virtual port if
+									  * multiple ports are differently configured.
+									  */
+
+/* Link Speed Parameter */
+#define SK_LSPEED_AUTO				1	/* Automatic resolution */
+#define SK_LSPEED_10MBPS			2	/* 10 Mbps */
+#define SK_LSPEED_100MBPS			3	/* 100 Mbps */
+#define SK_LSPEED_1000MBPS			4	/* 1000 Mbps */
+#define SK_LSPEED_INDETERMINATED	5	/* Return value for virtual port if
+					 * multiple ports are differently configured.
 					 */
 
-/*
- * Autonegotiation timeout in 100ms granularity.
- */
-#define	SK_AND_MAX_TO		6	/* Wait 600 msec before link comes up */
+/* Link Speed Current State */
+#define SK_LSPEED_STAT_UNKNOWN		1
+#define SK_LSPEED_STAT_10MBPS		2
+#define SK_LSPEED_STAT_100MBPS 		3
+#define SK_LSPEED_STAT_1000MBPS		4
+#define SK_LSPEED_STAT_INDETERMINATED 5	/* Return value for virtual port if
+					 * multiple ports are differently configured.
+					 */
 
-/*
- * Define Autonegotiation error codes here
- */
-#define	SK_AND_OK		0	/* no error */
-#define	SK_AND_OTHER		1	/* other error than below */
-#define	SK_AND_DUP_CAP		2	/* Duplex capabilities error */
 
-/*
- * Link Capability value
- */
-#define	SK_LMODE_CAP_HALF	(1<<0)	/* Half Duplex Mode */
-#define	SK_LMODE_CAP_FULL	(1<<1)	/* Full Duplex Mode */
-#define	SK_LMODE_CAP_AUTOHALF	(1<<2)	/* AutoHalf Duplex Mode */
-#define	SK_LMODE_CAP_AUTOFULL	(1<<3)	/* AutoFull Duplex Mode */
+/* Link Capability Parameter */
+#define SK_LMODE_CAP_HALF		(1<<0)	/* Half Duplex Mode */
+#define SK_LMODE_CAP_FULL		(1<<1)	/* Full Duplex Mode */
+#define SK_LMODE_CAP_AUTOHALF	(1<<2)	/* AutoHalf Duplex Mode */
+#define SK_LMODE_CAP_AUTOFULL	(1<<3)	/* AutoFull Duplex Mode */
 #define SK_LMODE_CAP_INDETERMINATED (1<<4) /* Return value for virtual port if
-					 * multiple ports are differently
-					 * configured.
+					 * multiple ports are differently configured.
 					 */
 
-/*
- * Link mode current state
- */
-#define	SK_LMODE_STAT_UNKNOWN	1	/* Unknown Duplex Mode */
-#define	SK_LMODE_STAT_HALF	2	/* Half Duplex Mode */
-#define	SK_LMODE_STAT_FULL	3	/* Full Duplex Mode */
+/* Link Mode Current State */
+#define SK_LMODE_STAT_UNKNOWN	1	/* Unknown Duplex Mode */
+#define SK_LMODE_STAT_HALF		2	/* Half Duplex Mode */
+#define SK_LMODE_STAT_FULL		3	/* Full Duplex Mode */
 #define SK_LMODE_STAT_AUTOHALF	4	/* Half Duplex Mode obtained by AutoNeg */
-#define SK_LMODE_STAT_AUTOFULL	5	/* Half Duplex Mode obtained by AutoNeg */
+#define SK_LMODE_STAT_AUTOFULL	5	/* Full Duplex Mode obtained by AutoNeg */
 #define SK_LMODE_STAT_INDETERMINATED 6	/* Return value for virtual port if
-					 * multiple ports are differently
-					 * configured.
+					 * multiple ports are differently configured.
 					 */
-/*
- * Set Flow Control Mode Parameter (and capabilities)
- */
-#define	SK_FLOW_MODE_NONE	1	/* No Flow Control */
-#define	SK_FLOW_MODE_LOC_SEND	2	/* Local station sends PAUSE */
-#define	SK_FLOW_MODE_SYMMETRIC	3	/* Both station may send PAUSE */
-#define	SK_FLOW_MODE_SYM_OR_REM	4	/* Both station may send PAUSE or
-					 * just the remote station may send
-					 * PAUSE
+/* Flow Control Mode Parameter (and capabilities) */
+#define SK_FLOW_MODE_NONE		1	/* No Flow Control */
+#define SK_FLOW_MODE_LOC_SEND	2	/* Local station sends PAUSE */
+#define SK_FLOW_MODE_SYMMETRIC	3	/* Both station may send PAUSE */
+#define SK_FLOW_MODE_SYM_OR_REM	4	/* Both station may send PAUSE or
+					 * just the remote station may send PAUSE
 					 */
 #define SK_FLOW_MODE_INDETERMINATED 5	/* Return value for virtual port if
-					 * multiple ports are differently
-					 * configured.
+					 * multiple ports are differently configured.
 					 */
 
-/*
- * Flow Control Status Parameter
- */
-#define	SK_FLOW_STAT_NONE	1	/* No Flow Control */
-#define	SK_FLOW_STAT_REM_SEND	2	/* Remote Station sends PAUSE */
-#define	SK_FLOW_STAT_LOC_SEND	3	/* Local station sends PAUSE */
-#define	SK_FLOW_STAT_SYMMETRIC	4	/* Both station may send PAUSE */
+/* Flow Control Status Parameter */
+#define SK_FLOW_STAT_NONE		1	/* No Flow Control */
+#define SK_FLOW_STAT_REM_SEND	2	/* Remote Station sends PAUSE */
+#define SK_FLOW_STAT_LOC_SEND	3	/* Local station sends PAUSE */
+#define SK_FLOW_STAT_SYMMETRIC	4	/* Both station may send PAUSE */
 #define SK_FLOW_STAT_INDETERMINATED 5	/* Return value for virtual port if
-					 * multiple ports are differently
-					 * configured.
+					 * multiple ports are differently configured.
 					 */
-/*
- * Master/Slave Mode capabilities
- */
-#define	SK_MS_CAP_AUTO		(1<<0)	/* Automatic resolution */
-#define	SK_MS_CAP_MASTER	(1<<1)	/* This station is master */
-#define	SK_MS_CAP_SLAVE		(1<<2)	/* This station is slave */
-#define	SK_MS_CAP_INDETERMINATED (1<<3)	/* Return value for virtual port if
-					 * multiple ports are differently
-					 * configured.
+/* Master/Slave Mode Capabilities */
+#define SK_MS_CAP_AUTO		(1<<0)	/* Automatic resolution */
+#define SK_MS_CAP_MASTER	(1<<1)	/* This station is master */
+#define SK_MS_CAP_SLAVE		(1<<2)	/* This station is slave */
+#define SK_MS_CAP_INDETERMINATED (1<<3)	/* Return value for virtual port if
+					 * multiple ports are differently configured.
 					 */
 
-/*
- * Set Master/Slave Mode Parameter (and capabilities)
- */
-#define	SK_MS_MODE_AUTO		1	/* Automatic resolution */
-#define	SK_MS_MODE_MASTER	2	/* This station is master */
-#define	SK_MS_MODE_SLAVE	3	/* This station is slave */
-#define SK_MS_MODE_INDETERMINATED 4	/* Return value for virtual port if 
+/* Set Master/Slave Mode Parameter (and capabilities) */
+#define SK_MS_MODE_AUTO		1	/* Automatic resolution */
+#define SK_MS_MODE_MASTER	2	/* This station is master */
+#define SK_MS_MODE_SLAVE	3	/* This station is slave */
+#define SK_MS_MODE_INDETERMINATED 4	/* Return value for virtual port if
 					 * multiple ports are differently
 					 */
 
-/*
- * Master/Slave Status Parameter
- */
-#define	SK_MS_STAT_UNSET	1	/* The MS status is never been determ*/
-#define	SK_MS_STAT_MASTER	2	/* This station is master */
-#define	SK_MS_STAT_SLAVE	3	/* This station is slave */
-#define	SK_MS_STAT_FAULT	4	/* MS resolution failed */
+/* Master/Slave Status Parameter */
+#define SK_MS_STAT_UNSET	1	/* The MS status is never been determ*/
+#define SK_MS_STAT_MASTER	2	/* This station is master */
+#define SK_MS_STAT_SLAVE	3	/* This station is slave */
+#define SK_MS_STAT_FAULT	4	/* MS resolution failed */
 #define SK_MS_STAT_INDETERMINATED 5	/* Return value for virtual port if
 					 * multiple ports are differently
 					 */
 
-/*
- * defines for parameter 'Mode' when calling SkXmSetRxCmd()
- */
-#define SK_STRIP_FCS_ON		(1<<0)	/* Enable FCS stripping of rx frames */
-#define SK_STRIP_FCS_OFF	(1<<1)	/* Disable FCS stripping of rx frames */
-#define SK_STRIP_PAD_ON		(1<<2)	/* Enable pad byte stripping of rx f */
-#define SK_STRIP_PAD_OFF	(1<<3)	/* Disable pad byte stripping of rx f */
-#define SK_LENERR_OK_ON		(1<<4)	/* Don't chk fr for in range len error*/
-#define SK_LENERR_OK_OFF	(1<<5)	/* Check frames for in range len error*/
+/* parameter 'Mode' when calling SkXmSetRxCmd() */
+#define SK_STRIP_FCS_ON		(1<<0)	/* Enable  FCS stripping of Rx frames */
+#define SK_STRIP_FCS_OFF	(1<<1)	/* Disable FCS stripping of Rx frames */
+#define SK_STRIP_PAD_ON		(1<<2)	/* Enable  pad byte stripping of Rx fr */
+#define SK_STRIP_PAD_OFF	(1<<3)	/* Disable pad byte stripping of Rx fr */
+#define SK_LENERR_OK_ON		(1<<4)	/* Don't chk fr for in range len error */
+#define SK_LENERR_OK_OFF	(1<<5)	/* Check frames for in range len error */
 #define SK_BIG_PK_OK_ON		(1<<6)	/* Don't set rcvError bit for big fr */
 #define SK_BIG_PK_OK_OFF	(1<<7)	/* Set rcvError bit for big frames */	
+#define SK_SELF_RX_ON		(1<<8)	/* Enable  Rx of own packets */
+#define SK_SELF_RX_OFF		(1<<9)	/* Disable Rx of own packets */
 
-/*
- * States of PState
- */
+/* parameter 'Para' when calling SkMacSetRxTxEn() */
+#define SK_MAC_LOOPB_ON		(1<<0)	/* Enable  MAC Loopback Mode */
+#define SK_MAC_LOOPB_OFF	(1<<1)	/* Disable MAC Loopback Mode */
+#define SK_PHY_LOOPB_ON		(1<<2)	/* Enable  PHY Loopback Mode */
+#define SK_PHY_LOOPB_OFF	(1<<3)	/* Disable PHY Loopback Mode */
+#define SK_PHY_FULLD_ON		(1<<4)	/* Enable  GMII Full Duplex */
+#define SK_PHY_FULLD_OFF	(1<<5)	/* Disable GMII Full Duplex */
+
+/* States of PState */
 #define SK_PRT_RESET	0	/* the port is reset */
-#define SK_PRT_STOP	1	/* the port is stopped (similar to sw reset) */
-#define SK_PRT_INIT	2	/* the port is initialized */
-#define SK_PRT_RUN	3	/* the port has an active link */
+#define SK_PRT_STOP		1	/* the port is stopped (similar to SW reset) */
+#define SK_PRT_INIT		2	/* the port is initialized */
+#define SK_PRT_RUN		3	/* the port has an active link */
+
+/* Default receive frame limit for Workaround of XMAC Errata */
+#define SK_DEF_RX_WA_LIM	SK_CONSTU64(100)
+
+/* Link Partner Status */
+#define SK_LIPA_UNKNOWN	0	/* Link partner is in unknown state */
+#define SK_LIPA_MANUAL	1	/* Link partner is in detected manual state */
+#define SK_LIPA_AUTO	2	/* Link partner is in auto-negotiation state */
 
-/*
- * Default receive frame limit for Workaround of XMAC Errata
- */
-#define	SK_DEF_RX_WA_LIM	SK_CONSTU64(100)
+/* Maximum Restarts before restart is ignored (3Com WA) */
+#define SK_MAX_LRESTART	3	/* Max. 3 times the link is restarted */
 
-/*
- * Define link partner Status
- */
-#define	SK_LIPA_UNKNOWN	0	/* Link partner is in unknown state */
-#define	SK_LIPA_MANUAL	1	/* Link partner is in detected manual state */
-#define	SK_LIPA_AUTO	2	/* Link partner is in autonegotiation state */
+/* Max. Auto-neg. timeouts before link detection in sense mode is reset */
+#define SK_MAX_ANEG_TO	10	/* Max. 10 times the sense mode is reset */
 
-/*
- * Define Maximum Restarts before restart is ignored (3com WA)
- */
-#define	SK_MAX_LRESTART	3	/* Max. 3 times the link is restarted */
+/* structures *****************************************************************/
 
 /*
- * define max. autonegotiation timeouts before link detection in sense mode is
- * reset.
+ * MAC specific functions
  */
-#define	SK_MAX_ANEG_TO	10	/* Max. 10 times the sense mode is reset */
-
-/* structures *****************************************************************/
+typedef struct s_GeMacFunc {
+	int  (*pFnMacUpdateStats)(SK_AC *pAC, SK_IOC IoC, unsigned int Port);
+	int  (*pFnMacStatistic)(SK_AC *pAC, SK_IOC IoC, unsigned int Port,
+							SK_U16 StatAddr, SK_U32 *pVal);
+	int  (*pFnMacResetCounter)(SK_AC *pAC, SK_IOC IoC, unsigned int Port);
+	int  (*pFnMacOverflow)(SK_AC *pAC, SK_IOC IoC, unsigned int Port,
+						   SK_U16 IStatus, SK_U64 *pVal);
+} SK_GEMACFUNC;
 
 /*
  * Port Structure
@@ -469,37 +610,35 @@
 typedef	struct s_GePort {
 #ifndef SK_DIAG
 	SK_TIMER	PWaTimer;	/* Workaround Timer */
-#endif
-	SK_U64	PPrevShorts;	/* Previous short Counter checking */
+	SK_TIMER	HalfDupChkTimer;
+#endif /* SK_DIAG */
+	SK_U32	PPrevShorts;	/* Previous short Counter checking */
+	SK_U32	PPrevFcs;		/* Previous FCS Error Counter checking */
 	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		PAutoNegTimeOut;/* Auto-negotiation timeout current value */
+	int		PAutoNegTOCt;	/* Auto-negotiation 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*/
+	int		PXSQSize;		/* Port Synchronous  Transmit Queue Size in kB */
+	int		PXAQSize;		/* Port Asynchronous Transmit Queue Size in kB */
 	SK_U32	PRxQRamStart;	/* Receive Queue RAM Buffer Start Address */
 	SK_U32	PRxQRamEnd;		/* Receive Queue RAM Buffer End Address */
 	SK_U32	PXsQRamStart;	/* Sync Tx Queue RAM Buffer Start Address */
 	SK_U32	PXsQRamEnd;		/* Sync Tx Queue RAM Buffer End Address */
 	SK_U32	PXaQRamStart;	/* Async Tx Queue RAM Buffer Start Address */
 	SK_U32	PXaQRamEnd;		/* Async Tx Queue RAM Buffer End Address */
+	SK_U32	PRxOverCnt;		/* Receive Overflow Counter */
 	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	PhyId1;			/* PHY Id1 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	PHWLinkUp;		/* The hardware Link is up (wiring) */
 	SK_BOOL	PState;			/* Is port initialized ? */
 	SK_BOOL	PLinkBroken;	/* Is Link broken ? */
 	SK_BOOL	PCheckPar;		/* Do we check for parity errors ? */
@@ -508,77 +647,102 @@
 	SK_U8	PLinkModeConf;	/* Link Mode configured */
 	SK_U8	PLinkMode;		/* Link Mode currently used */
 	SK_U8	PLinkModeStatus;/* Link Mode Status */
+	SK_U8	PLinkSpeedCap;	/* Link Speed Capabilities(10/100/1000 Mbps) */
+	SK_U8	PLinkSpeed;		/* configured Link Speed (10/100/1000 Mbps) */
+	SK_U8	PLinkSpeedUsed;	/* current Link Speed (10/100/1000 Mbps) */
 	SK_U8	PFlowCtrlCap;	/* Flow Control Capabilities */
 	SK_U8	PFlowCtrlMode;	/* Flow Control Mode */
 	SK_U8	PFlowCtrlStatus;/* Flow Control Status */
 	SK_U8	PMSCap;			/* Master/Slave Capabilities */
 	SK_U8	PMSMode;		/* Master/Slave Mode */
 	SK_U8	PMSStatus;		/* Master/Slave Status */
-	SK_U8	PAutoNegFail;	/* Autonegotiation fail flag */
-	SK_U8	PLipaAutoNeg;	/* Autonegotiation possible with Link Partner */
-	SK_U8	Align02;
+	SK_U8	PAutoNegFail;	/* Auto-negotiation fail flag */
+	SK_U8	PLipaAutoNeg;	/* Auto-negotiation possible with Link Partner */
+	SK_U8	PCableLen;		/* Cable Length */
+	SK_U8	PMdiPairLen[4];	/* MDI[0..3] Pair Length */
+	SK_U8	PMdiPairSts[4];	/* MDI[0..3] Pair Diagnostic Status */
 } SK_GEPORT;
 
 /*
- * Gigabit Ethernet Initalization Struct
+ * Gigabit Ethernet Initialization Struct
  * (has to be included in the adapter context)
  */
 typedef	struct s_GeInit {
+	SK_U8		GIPciHwRev;		/* PCI HW Revision Number */
+	SK_U8		GIChipId;		/* Chip Identification Number */
+	SK_U8		GIChipRev;		/* Chip Revision Number */
+	SK_BOOL		GIGenesis;		/* Genesis adapter ? */
+	SK_BOOL		GICopperType;	/* Copper Type adapter ? */
+	SK_BOOL		GIPciSlot64;	/* 64-bit PCI Slot */
+	SK_BOOL		GIPciClock66;	/* 66 MHz PCI Clock */
+	SK_BOOL		GIVauxAvail;	/* VAUX available (YUKON) */
+	SK_BOOL		GIYukon32Bit;	/* 32-Bit YUKON adapter */
 	int			GIMacsFound;	/* Number of MACs found on this adapter */
-	int			GIPciHwRev;		/* PCI HW Revision Number */
-	SK_U32		GIRamOffs;		/* RAM Address Offset for addr calculation */
-	int			GIRamSize;		/* The RAM size of the adapter in kB */
+	int			GIMacType;		/* MAC Type used on this adapter */
 	int			GIHstClkFact;	/* Host Clock Factor (62.5 / HstClk * 100) */
-	int			GIPortUsage;	/* driver port usage: SK_RED_LINK/SK_MUL_LINK */
+	int			GIPortUsage;	/* Driver Port Usage: SK_RED_LINK/SK_MUL_LINK */
+	int			GILevel;		/* Initialization Level completed */
+	int			GIRamSize;		/* The RAM size of the adapter in kB */
+	int			GIWolOffs;		/* WOL Register Offset (HW-Bug in 1st revision) */
+	SK_U32		GIRamOffs;		/* RAM Address Offset for addr calculation */
 	SK_U32		GIPollTimerVal;	/* Descriptor Poll Timer Init Val in clk ticks*/
-	int			GILevel;		/* Initialization Level Completed */
 	SK_GEPORT	GP[SK_MAX_MACS];/* Port Dependent Information */
-	SK_BOOL		GIAnyPortAct;	/* Is True if one or more port is initialized */
-	SK_U8		Align01;
-	SK_U16		Align02;
+	SK_GEMACFUNC GIFunc;		/* MAC depedent functions */
 } SK_GEINIT;
 
 /*
- * Define the error numbers and messages for xmac_ii.c and skgeinit.c
+ * Error numbers and messages for skxmac2.c and skgeinit.c
  */
-#define	SKERR_HWI_E001		(SK_ERRBASE_HWINIT)
-#define	SKERR_HWI_E001MSG	"SkXmClrExactAddr() has got illegal parameters"
-#define	SKERR_HWI_E002		(SKERR_HWI_E001+1)
-#define	SKERR_HWI_E002MSG	"SkGeInit() Level 1 call missing"
-#define	SKERR_HWI_E003		(SKERR_HWI_E002+1)
-#define	SKERR_HWI_E003MSG	"SkGeInit() called with illegal init Level"
-#define	SKERR_HWI_E004		(SKERR_HWI_E003+1)
-#define	SKERR_HWI_E004MSG	"SkGeInitPort() Queue size illegal configured"
-#define	SKERR_HWI_E005		(SKERR_HWI_E004+1)
-#define	SKERR_HWI_E005MSG	"SkGeInitPort() cannot init running ports"
-#define	SKERR_HWI_E006		(SKERR_HWI_E005+1)
-#define	SKERR_HWI_E006MSG	"SkGeXmInit(): PState does not match HW state"
-#define	SKERR_HWI_E007		(SKERR_HWI_E006+1)
-#define	SKERR_HWI_E007MSG	"SkXmInitDupMd() called with invalid Dup Mode"
-#define	SKERR_HWI_E008		(SKERR_HWI_E007+1)
-#define	SKERR_HWI_E008MSG	"SkXmSetRxCmd() called with invalid Mode"
-#define	SKERR_HWI_E009		(SKERR_HWI_E008+1)
-#define	SKERR_HWI_E009MSG	"SkGeCfgSync() called although PXSQSize zero"
-#define	SKERR_HWI_E010		(SKERR_HWI_E009+1)
-#define	SKERR_HWI_E010MSG	"SkGeCfgSync() called with invalid parameters"
-#define	SKERR_HWI_E011		(SKERR_HWI_E010+1)
-#define	SKERR_HWI_E011MSG	"SkGeInitPort() Receive Queue Size to small"
-#define	SKERR_HWI_E012		(SKERR_HWI_E011+1)
-#define	SKERR_HWI_E012MSG	"SkGeInitPort() invalid Queue Size specified"
-#define	SKERR_HWI_E013		(SKERR_HWI_E012+1)
-#define	SKERR_HWI_E013MSG	"SkGeInitPort() cfg changed for running queue"
-#define	SKERR_HWI_E014		(SKERR_HWI_E013+1)
-#define	SKERR_HWI_E014MSG	"SkGeInitPort() unknown GIPortUsage specified"
-#define	SKERR_HWI_E015		(SKERR_HWI_E014+1)
-#define	SKERR_HWI_E015MSG	"Illegal Link mode parameter"
-#define	SKERR_HWI_E016		(SKERR_HWI_E015+1)
-#define	SKERR_HWI_E016MSG	"Illegal Flow control mode parameter"
-#define	SKERR_HWI_E017		(SKERR_HWI_E016+1)
-#define	SKERR_HWI_E017MSG	"Illegal value specified for GIPollTimerVal"
-#define	SKERR_HWI_E018		(SKERR_HWI_E017+1)
-#define	SKERR_HWI_E018MSG	"FATAL: SkGeStopPort() does not terminate"
-#define	SKERR_HWI_E019		(SKERR_HWI_E018+1)
-#define	SKERR_HWI_E019MSG	""
+#define SKERR_HWI_E001		(SK_ERRBASE_HWINIT)
+#define SKERR_HWI_E001MSG	"SkXmClrExactAddr() has got illegal parameters"
+#define SKERR_HWI_E002		(SKERR_HWI_E001+1)
+#define SKERR_HWI_E002MSG	"SkGeInit(): Level 1 call missing"
+#define SKERR_HWI_E003		(SKERR_HWI_E002+1)
+#define SKERR_HWI_E003MSG	"SkGeInit() called with illegal init Level"
+#define SKERR_HWI_E004		(SKERR_HWI_E003+1)
+#define SKERR_HWI_E004MSG	"SkGeInitPort(): Queue Size illegal configured"
+#define SKERR_HWI_E005		(SKERR_HWI_E004+1)
+#define SKERR_HWI_E005MSG	"SkGeInitPort(): cannot init running ports"
+#define SKERR_HWI_E006		(SKERR_HWI_E005+1)
+#define SKERR_HWI_E006MSG	"SkGeMacInit(): PState does not match HW state"
+#define SKERR_HWI_E007		(SKERR_HWI_E006+1)
+#define SKERR_HWI_E007MSG	"SkXmInitDupMd() called with invalid Dup Mode"
+#define SKERR_HWI_E008		(SKERR_HWI_E007+1)
+#define SKERR_HWI_E008MSG	"SkXmSetRxCmd() called with invalid Mode"
+#define SKERR_HWI_E009		(SKERR_HWI_E008+1)
+#define SKERR_HWI_E009MSG	"SkGeCfgSync() called although PXSQSize zero"
+#define SKERR_HWI_E010		(SKERR_HWI_E009+1)
+#define SKERR_HWI_E010MSG	"SkGeCfgSync() called with invalid parameters"
+#define SKERR_HWI_E011		(SKERR_HWI_E010+1)
+#define SKERR_HWI_E011MSG	"SkGeInitPort(): Receive Queue Size to small"
+#define SKERR_HWI_E012		(SKERR_HWI_E011+1)
+#define SKERR_HWI_E012MSG	"SkGeInitPort(): invalid Queue Size specified"
+#define SKERR_HWI_E013		(SKERR_HWI_E012+1)
+#define SKERR_HWI_E013MSG	"SkGeInitPort(): cfg changed for running queue"
+#define SKERR_HWI_E014		(SKERR_HWI_E013+1)
+#define SKERR_HWI_E014MSG	"SkGeInitPort(): unknown GIPortUsage specified"
+#define SKERR_HWI_E015		(SKERR_HWI_E014+1)
+#define SKERR_HWI_E015MSG	"Illegal Link mode parameter"
+#define SKERR_HWI_E016		(SKERR_HWI_E015+1)
+#define SKERR_HWI_E016MSG	"Illegal Flow control mode parameter"
+#define SKERR_HWI_E017		(SKERR_HWI_E016+1)
+#define SKERR_HWI_E017MSG	"Illegal value specified for GIPollTimerVal"
+#define SKERR_HWI_E018		(SKERR_HWI_E017+1)
+#define SKERR_HWI_E018MSG	"FATAL: SkGeStopPort() does not terminate (Tx)"
+#define SKERR_HWI_E019		(SKERR_HWI_E018+1)
+#define SKERR_HWI_E019MSG	"Illegal Speed parameter"
+#define SKERR_HWI_E020		(SKERR_HWI_E019+1)
+#define SKERR_HWI_E020MSG	"Illegal Master/Slave parameter"
+#define SKERR_HWI_E021		(SKERR_HWI_E020+1)
+#define	SKERR_HWI_E021MSG	"MacUpdateStats(): cannot update statistic counter"
+#define	SKERR_HWI_E022		(SKERR_HWI_E021+1)
+#define	SKERR_HWI_E022MSG	"MacStatistic(): illegal statistic base address"
+#define SKERR_HWI_E023		(SKERR_HWI_E022+1)
+#define SKERR_HWI_E023MSG	"SkGeInitPort(): Transmit Queue Size to small"
+#define SKERR_HWI_E024		(SKERR_HWI_E023+1)
+#define SKERR_HWI_E024MSG	"FATAL: SkGeStopPort() does not terminate (Rx)"
+#define SKERR_HWI_E025		(SKERR_HWI_E024+1)
+#define SKERR_HWI_E025MSG	""
 
 /* function prototypes ********************************************************/
 
@@ -588,146 +752,301 @@
  * public functions in skgeinit.c
  */
 extern void	SkGePollRxD(
-	SK_AC		*pAC,
-	SK_IOC		IoC,
+	SK_AC	*pAC,
+	SK_IOC	IoC,
 	int		Port,
-	SK_BOOL		PollRxD);
+	SK_BOOL	PollRxD);
 
 extern void	SkGePollTxD(
-	SK_AC		*pAC,
-	SK_IOC		IoC,
+	SK_AC	*pAC,
+	SK_IOC	IoC,
 	int		Port,
-	SK_BOOL 	PollTxD);
+	SK_BOOL PollTxD);
 
 extern void	SkGeYellowLED(
-	SK_AC		*pAC,
-	SK_IOC		IoC,
+	SK_AC	*pAC,
+	SK_IOC	IoC,
 	int		State);
 
 extern int	SkGeCfgSync(
-	SK_AC		*pAC,
-	SK_IOC		IoC,
+	SK_AC	*pAC,
+	SK_IOC	IoC,
 	int		Port,
-	SK_U32		IntTime,
-	SK_U32		LimCount,
+	SK_U32	IntTime,
+	SK_U32	LimCount,
 	int		SyncMode);
 
 extern void	SkGeLoadLnkSyncCnt(
-	SK_AC		*pAC,
-	SK_IOC		IoC,
+	SK_AC	*pAC,
+	SK_IOC	IoC,
 	int		Port,
-	SK_U32		CntVal);
+	SK_U32	CntVal);
 
 extern void	SkGeStopPort(
-	SK_AC		*pAC,
-	SK_IOC		IoC,
+	SK_AC	*pAC,
+	SK_IOC	IoC,
 	int		Port,
 	int		Dir,
 	int		RstMode);
 
 extern int	SkGeInit(
-	SK_AC		*pAC,
-	SK_IOC		IoC,
+	SK_AC	*pAC,
+	SK_IOC	IoC,
 	int		Level);
 
 extern void	SkGeDeInit(
-	SK_AC		*pAC,
-	SK_IOC		IoC);
+	SK_AC	*pAC,
+	SK_IOC	IoC);
 
 extern int	SkGeInitPort(
-	SK_AC		*pAC,
-	SK_IOC		IoC,
+	SK_AC	*pAC,
+	SK_IOC	IoC,
 	int		Port);
 
 extern void	SkGeXmitLED(
-	SK_AC		*pAC,
-	SK_IOC		IoC,
+	SK_AC	*pAC,
+	SK_IOC	IoC,
 	int		Led,
 	int		Mode);
 
 extern void	SkGeInitRamIface(
-	SK_AC		*pAC,
-	SK_IOC		IoC);
+	SK_AC	*pAC,
+	SK_IOC	IoC);
+
+extern int	SkGeInitAssignRamToQueues(
+	SK_AC	*pAC,
+	int		ActivePort,
+	SK_BOOL	DualNet);
 
 /*
  * public functions in skxmac2.c
  */
-extern void	SkXmSetRxCmd(
-	SK_AC		*pAC,
-	SK_IOC		IoC,
-	int		Port,
-	int		Mode);
+extern void SkMacRxTxDisable(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port);
 
-extern void	SkXmClrExactAddr(
-	SK_AC		*pAC,
-	SK_IOC		IoC,
+extern void	SkMacSoftRst(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port);
+
+extern void	SkMacHardRst(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port);
+
+extern void	SkXmInitMac(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port);
+
+extern void	SkGmInitMac(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port);
+
+extern void SkMacInitPhy(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
 	int		Port,
-	int		StartNum,
-	int		StopNum);
+	SK_BOOL	DoLoop);
 
-extern void	SkXmFlushTxFifo(
-	SK_AC		*pAC,
-	SK_IOC		IoC,
+extern void SkMacIrqDisable(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
 	int		Port);
 
-extern void	SkXmFlushRxFifo(
-	SK_AC		*pAC,
-	SK_IOC		IoC,
+extern void	SkMacFlushTxFifo(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
 	int		Port);
 
-extern void	SkXmSoftRst(
-	SK_AC		*pAC,
-	SK_IOC		IoC,
+extern void	SkMacFlushRxFifo(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
 	int		Port);
 
-extern void	SkXmHardRst(
-	SK_AC		*pAC,
-	SK_IOC		IoC,
+extern void	SkMacIrq(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
 	int		Port);
 
-extern void	SkXmInitMac(
-	SK_AC		*pAC,
-	SK_IOC		IoC,
+extern int	SkMacAutoNegDone(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
 	int		Port);
 
-extern void	SkXmInitDupMd(
-	SK_AC		*pAC,
-	SK_IOC		IoC,
+extern void	SkMacAutoNegLipaPhy(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	SK_U16	IStatus);
+
+extern void  SkMacSetRxTxEn(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	int		Para);
+
+extern int  SkMacRxTxEnable(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
 	int		Port);
 
-extern void	SkXmInitPauseMd(
-	SK_AC		*pAC,
-	SK_IOC		IoC,
+extern void	SkMacPromiscMode(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	SK_BOOL	Enable);
+
+extern void	SkMacHashing(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	SK_BOOL	Enable);
+
+extern void	SkXmPhyRead(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	int		Addr,
+	SK_U16	*pVal);
+
+extern void	SkXmPhyWrite(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	int		Addr,
+	SK_U16	Val);
+
+extern void	SkGmPhyRead(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	int		Addr,
+	SK_U16	*pVal);
+
+extern void	SkGmPhyWrite(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	int		Addr,
+	SK_U16	Val);
+
+extern void	SkGePhyRead(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	int		Addr,
+	SK_U16	*pVal);
+
+extern void	SkGePhyWrite(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	int		Addr,
+	SK_U16	Val);
+
+extern void	SkXmClrExactAddr(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	int		StartNum,
+	int		StopNum);
+
+extern void	SkXmInitDupMd(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
 	int		Port);
 
-extern int	SkXmAutoNegDone(
-	SK_AC		*pAC,
-	SK_IOC		IoC,
+extern void	SkXmInitPauseMd(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
 	int		Port);
 
 extern void	SkXmAutoNegLipaXmac(
-	SK_AC		*pAC,
-	SK_IOC		IoC,
+	SK_AC	*pAC,
+	SK_IOC	IoC,
 	int		Port,
-	SK_U16		IStatus);
+	SK_U16	IStatus);
 
-extern void	SkXmAutoNegLipaBcom(
-	SK_AC		*pAC,
-	SK_IOC		IoC,
+extern int SkXmUpdateStats(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	unsigned int Port);
+
+extern int SkGmUpdateStats(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	unsigned int Port);
+
+extern int SkXmMacStatistic(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	unsigned int Port,
+	SK_U16	StatAddr,
+	SK_U32	*pVal);
+
+extern int SkGmMacStatistic(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	unsigned int Port,
+	SK_U16	StatAddr,
+	SK_U32	*pVal);
+
+extern int SkXmResetCounter(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	unsigned int Port);
+
+extern int SkGmResetCounter(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	unsigned int Port);
+
+extern int SkXmOverflowStatus(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	unsigned int Port,
+	SK_U16  IStatus,
+	SK_U64	*pStatus);
+
+extern int SkGmOverflowStatus(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	unsigned int Port,
+	SK_U16	MacStatus,
+	SK_U64	*pStatus);
+
+extern int SkGmCableDiagStatus(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
 	int		Port,
-	SK_U16		IStatus);
+	SK_BOOL	StartTest);
 
-extern void	SkXmAutoNegLipaLone(
-	SK_AC		*pAC,
-	SK_IOC		IoC,
+#ifdef SK_DIAG
+extern void	SkMacSetRxCmd(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
 	int		Port,
-	SK_U16		IStatus);
-
-extern void	SkXmIrq(
-	SK_AC		*pAC,
-	SK_IOC		IoC,
+	int		Mode);
+extern void	SkMacCrcGener(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
 	int		Port,
-	SK_U16		IStatus);
+	SK_BOOL	Enable);
+extern void	SkMacTimeStamp(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	SK_BOOL	Enable);
+extern void	SkXmSendCont(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	SK_BOOL	Enable);
+#endif /* SK_DIAG */
 
 #else	/* SK_KR_PROTO */
 
@@ -745,22 +1064,53 @@
 extern int	SkGeInitPort();
 extern void	SkGeXmitLED();
 extern void	SkGeInitRamIface();
+extern int	SkGeInitAssignRamToQueues();
 
 /*
  * public functions in skxmac2.c
  */
-extern void	SkXmSetRxCmd();
-extern void	SkXmClrExactAddr();
-extern void	SkXmFlushTxFifo();
-extern void	SkXmFlushRxFifo();
-extern void	SkXmSoftRst();
-extern void	SkXmHardRst();
+extern void SkMacRxTxDisable();
+extern void	SkMacSoftRst();
+extern void	SkMacHardRst();
+extern void SkMacInitPhy();
+extern int  SkMacRxTxEnable();
+extern void SkMacPromiscMode();
+extern void SkMacHashing();
+extern void SkMacIrqDisable();
+extern void	SkMacFlushTxFifo();
+extern void	SkMacFlushRxFifo();
+extern void	SkMacIrq();
+extern int	SkMacAutoNegDone();
+extern void	SkMacAutoNegLipaPhy();
+extern void SkMacSetRxTxEn();
+extern void	SkGePhyRead();
+extern void	SkGePhyWrite();
 extern void	SkXmInitMac();
+extern void	SkXmPhyRead();
+extern void	SkXmPhyWrite();
+extern void	SkGmInitMac();
+extern void	SkGmPhyRead();
+extern void	SkGmPhyWrite();
+extern void	SkXmClrExactAddr();
 extern void	SkXmInitDupMd();
 extern void	SkXmInitPauseMd();
-extern int	SkXmAutoNegDone();
-extern void	SkXmAutoNegLipa();
-extern void	SkXmIrq();
+extern void	SkXmAutoNegLipaXmac();
+extern int	SkXmUpdateStats();
+extern int	SkGmUpdateStats();
+extern int	SkXmMacStatistic();
+extern int	SkGmMacStatistic();
+extern int	SkXmResetCounter();
+extern int	SkGmResetCounter();
+extern int	SkXmOverflowStatus();
+extern int	SkGmOverflowStatus();
+extern int	SkGmCableDiagStatus();
+
+#ifdef SK_DIAG
+extern void	SkMacSetRxCmd();
+extern void	SkMacCrcGener();
+extern void	SkMacTimeStamp();
+extern void	SkXmSendCont();
+#endif /* SK_DIAG */
 
 #endif	/* SK_KR_PROTO */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sk98lin/h/skgepnm2.h linux-2.4.21-pre6/drivers/net/sk98lin/h/skgepnm2.h
--- linux-2.4.20/drivers/net/sk98lin/h/skgepnm2.h	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sk98lin/h/skgepnm2.h	2003-03-26 23:49:07.000000000 +0000
@@ -2,8 +2,8 @@
  *
  * Name:	skgepnm2.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.30 $
- * Date:	$Date: 2001/02/06 10:03:41 $
+ * Version:	$Revision: 1.34 $
+ * Date:	$Date: 2002/12/16 09:05:18 $
  * Purpose:	Defines for Private Network Management Interface
  *
  ****************************************************************************/
@@ -26,6 +26,21 @@
  * History:
  *
  *	$Log: skgepnm2.h,v $
+ *	Revision 1.34  2002/12/16 09:05:18  tschilli
+ *	Code for VCT handling added.
+ *	
+ *	Revision 1.33  2002/09/10 09:00:03  rwahl
+ *	Adapted boolean definitions according sktypes.
+ *	
+ *	Revision 1.32  2002/08/09 09:47:01  rwahl
+ *	Added write-only flag to oid access defines.
+ *	Editorial changes.
+ *	
+ *	Revision 1.31  2002/07/17 19:23:18  rwahl
+ *	- Replaced MAC counter definitions by enumeration.
+ *	- Added definition SK_PNMI_MAC_TYPES.
+ *	- Added chipset defnition for Yukon.
+ *	
  *	Revision 1.30  2001/02/06 10:03:41  mkunz
  *	- Pnmi V4 dual net support added. Interface functions and macros extended
  *	- Vpd bug fixed
@@ -140,26 +155,19 @@
 #ifndef _SKGEPNM2_H_
 #define _SKGEPNM2_H_
 
-#ifndef FALSE
-#define FALSE			0
-#endif
-
-#ifndef TRUE
-#define	TRUE			!(FALSE)
-#endif
-
 /*
  * General definitions
  */
-#define SK_PNMI_CHIPSET		1	/* XMAC11800FP */
+#define SK_PNMI_CHIPSET_XMAC	1	/* XMAC11800FP */
+#define SK_PNMI_CHIPSET_YUKON	2	/* YUKON */
 
 #define	SK_PNMI_BUS_PCI		1	/* PCI bus*/
 
 /*
  * Actions
  */
-#define SK_PNMI_ACT_IDLE	1
-#define SK_PNMI_ACT_RESET	2
+#define SK_PNMI_ACT_IDLE		1
+#define SK_PNMI_ACT_RESET		2
 #define SK_PNMI_ACT_SELFTEST	3
 #define SK_PNMI_ACT_RESETCNT	4
 
@@ -170,13 +178,13 @@
 #define SK_PNMI_VPD_RW		1
 #define SK_PNMI_VPD_RO		2
 
-#define SK_PNMI_VPD_OK		0
+#define SK_PNMI_VPD_OK			0
 #define SK_PNMI_VPD_NOTFOUND	1
-#define SK_PNMI_VPD_CUT		2
-#define SK_PNMI_VPD_TIMEOUT	3
-#define SK_PNMI_VPD_FULL	4
-#define SK_PNMI_VPD_NOWRITE	5
-#define SK_PNMI_VPD_FATAL	6
+#define SK_PNMI_VPD_CUT			2
+#define SK_PNMI_VPD_TIMEOUT		3
+#define SK_PNMI_VPD_FULL		4
+#define SK_PNMI_VPD_NOWRITE		5
+#define SK_PNMI_VPD_FATAL		6
 
 #define SK_PNMI_VPD_IGNORE	0
 #define SK_PNMI_VPD_CREATE	1
@@ -188,124 +196,137 @@
  */
 #define SK_PNMI_DEF_RLMT_CHG_THRES	240	/* 4 changes per minute */
 
+
+/*
+ * VCT internal status values
+ */
+#define SK_PNMI_VCT_PENDING	32
+#define SK_PNMI_VCT_TEST_DONE	64
+#define SK_PNMI_VCT_LINK	128
+
 /*
  * Internal table definitions
  */
 #define SK_PNMI_GET		0
-#define SK_PNMI_PRESET		1
+#define SK_PNMI_PRESET	1
 #define SK_PNMI_SET		2
 
 #define SK_PNMI_RO		0
 #define SK_PNMI_RW		1
+#define SK_PNMI_WO		2
 
 typedef struct s_OidTabEntry {
-	SK_U32		Id;
-	SK_U32		InstanceNo;
+	SK_U32			Id;
+	SK_U32			InstanceNo;
 	unsigned int	StructSize;
 	unsigned int	Offset;
-	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 NetNumber);
-	SK_U16		Param;
+	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 NetNumber);
+	SK_U16			Param;
 } SK_PNMI_TAB_ENTRY;
 
 
 /*
  * Trap lengths
  */
-#define SK_PNMI_TRAP_SIMPLE_LEN		17
+#define SK_PNMI_TRAP_SIMPLE_LEN			17
 #define SK_PNMI_TRAP_SENSOR_LEN_BASE	46
 #define SK_PNMI_TRAP_RLMT_CHANGE_LEN	23
-#define SK_PNMI_TRAP_RLMT_PORT_LEN	23
-
+#define SK_PNMI_TRAP_RLMT_PORT_LEN		23
 
 /*
- * MAC statistic data structures
- * Only for the first 64 counters: the number relates to the bit in the
- * XMAC overflow status register
- */
-#define SK_PNMI_HTX			0
-#define SK_PNMI_HTX_OCTET		1
-#define SK_PNMI_HTX_OCTETHIGH		1
-#define SK_PNMI_HTX_OCTETLOW		2
-#define SK_PNMI_HTX_BROADCAST		3
-#define SK_PNMI_HTX_MULTICAST		4
-#define SK_PNMI_HTX_UNICAST		5
-#define SK_PNMI_HTX_LONGFRAMES		6
-#define SK_PNMI_HTX_BURST		7
-#define SK_PNMI_HTX_PMACC		8
-#define SK_PNMI_HTX_MACC		9
-#define SK_PNMI_HTX_SINGLE_COL		10
-#define SK_PNMI_HTX_MULTI_COL		11
-#define SK_PNMI_HTX_EXCESS_COL		12
-#define SK_PNMI_HTX_LATE_COL		13
-#define SK_PNMI_HTX_DEFFERAL		14
-#define SK_PNMI_HTX_EXCESS_DEF		15
-#define SK_PNMI_HTX_UNDERRUN		16
-#define SK_PNMI_HTX_CARRIER		17
-#define SK_PNMI_HTX_UTILUNDER		18
-#define SK_PNMI_HTX_UTILOVER		19
-#define SK_PNMI_HTX_64			20
-#define SK_PNMI_HTX_127			21
-#define SK_PNMI_HTX_255			22
-#define SK_PNMI_HTX_511			23
-#define SK_PNMI_HTX_1023		24
-#define SK_PNMI_HTX_MAX			25
-#define SK_PNMI_HTX_RESERVED26		26
-#define SK_PNMI_HTX_RESERVED27		27
-#define SK_PNMI_HTX_RESERVED28		28
-#define SK_PNMI_HTX_RESERVED29		29
-#define SK_PNMI_HTX_RESERVED30		30
-#define SK_PNMI_HTX_RESERVED31		31
-#define SK_PNMI_HRX			(32 + 0)
-#define SK_PNMI_HRX_OCTET		(32 + 1)
-#define SK_PNMI_HRX_OCTETHIGH		(32 + 1)
-#define SK_PNMI_HRX_OCTETLOW		(32 + 2)
-#define SK_PNMI_HRX_BROADCAST		(32 + 3)
-#define SK_PNMI_HRX_MULTICAST		(32 + 4)
-#define SK_PNMI_HRX_UNICAST		(32 + 5)
-#define SK_PNMI_HRX_PMACC		(32 + 6)
-#define SK_PNMI_HRX_MACC		(32 + 7)
-#define SK_PNMI_HRX_PMACC_ERR		(32 + 8)
-#define SK_PNMI_HRX_MACC_UNKWN		(32 + 9)
-#define SK_PNMI_HRX_BURST		(32 + 10)
-#define SK_PNMI_HRX_MISSED		(32 + 11)
-#define SK_PNMI_HRX_FRAMING		(32 + 12)
-#define SK_PNMI_HRX_OVERFLOW		(32 + 13)
-#define SK_PNMI_HRX_JABBER		(32 + 14)
-#define SK_PNMI_HRX_CARRIER		(32 + 15)
-#define SK_PNMI_HRX_IRLENGTH		(32 + 16)
-#define SK_PNMI_HRX_SYMBOL		(32 + 17)
-#define SK_PNMI_HRX_SHORTS		(32 + 18)
-#define SK_PNMI_HRX_RUNT		(32 + 19)
-#define SK_PNMI_HRX_TOO_LONG		(32 + 20)
-#define SK_PNMI_HRX_FCS			(32 + 21)
-#define SK_PNMI_HRX_RESERVED22		(32 + 22)
-#define SK_PNMI_HRX_CEXT		(32 + 23)
-#define SK_PNMI_HRX_UTILUNDER		(32 + 24)
-#define SK_PNMI_HRX_UTILOVER		(32 + 25)
-#define SK_PNMI_HRX_64			(32 + 26)
-#define SK_PNMI_HRX_127			(32 + 27)
-#define SK_PNMI_HRX_255			(32 + 28)
-#define SK_PNMI_HRX_511			(32 + 29)
-#define SK_PNMI_HRX_1023		(32 + 30)
-#define SK_PNMI_HRX_MAX			(32 + 31)
-
-#define SK_PNMI_HTX_SYNC		64
-#define SK_PNMI_HTX_SYNC_OCTET		65
-
-#define SK_PNMI_HRX_LONGFRAMES		66
+ * Number of MAC types supported
+ */
+#define SK_PNMI_MAC_TYPES	(SK_MAC_GMAC + 1)
 
-#define SK_PNMI_MAX_IDX			(SK_PNMI_CNT_NO)
+/*
+ * MAC statistic data list (overall set for MAC types used)
+ */
+enum SK_MACSTATS {
+	SK_PNMI_HTX				= 0,
+	SK_PNMI_HTX_OCTET,
+	SK_PNMI_HTX_OCTETHIGH 	= SK_PNMI_HTX_OCTET,
+	SK_PNMI_HTX_OCTETLOW,
+	SK_PNMI_HTX_BROADCAST,
+	SK_PNMI_HTX_MULTICAST,
+	SK_PNMI_HTX_UNICAST,
+	SK_PNMI_HTX_BURST,
+	SK_PNMI_HTX_PMACC,
+	SK_PNMI_HTX_MACC,
+	SK_PNMI_HTX_COL,
+	SK_PNMI_HTX_SINGLE_COL,
+	SK_PNMI_HTX_MULTI_COL,
+	SK_PNMI_HTX_EXCESS_COL,
+	SK_PNMI_HTX_LATE_COL,
+	SK_PNMI_HTX_DEFFERAL,
+	SK_PNMI_HTX_EXCESS_DEF,
+	SK_PNMI_HTX_UNDERRUN,
+	SK_PNMI_HTX_CARRIER,
+	SK_PNMI_HTX_UTILUNDER,
+	SK_PNMI_HTX_UTILOVER,
+	SK_PNMI_HTX_64,
+	SK_PNMI_HTX_127,
+	SK_PNMI_HTX_255,
+	SK_PNMI_HTX_511,
+	SK_PNMI_HTX_1023,
+	SK_PNMI_HTX_MAX,
+	SK_PNMI_HTX_LONGFRAMES,
+	SK_PNMI_HTX_SYNC,
+	SK_PNMI_HTX_SYNC_OCTET,
+	SK_PNMI_HTX_RESERVED,
+	
+	SK_PNMI_HRX,
+	SK_PNMI_HRX_OCTET,
+	SK_PNMI_HRX_OCTETHIGH	= SK_PNMI_HRX_OCTET,
+	SK_PNMI_HRX_OCTETLOW,
+	SK_PNMI_HRX_BADOCTET,
+	SK_PNMI_HRX_BADOCTETHIGH = SK_PNMI_HRX_BADOCTET,
+	SK_PNMI_HRX_BADOCTETLOW,
+	SK_PNMI_HRX_BROADCAST,
+	SK_PNMI_HRX_MULTICAST,
+	SK_PNMI_HRX_UNICAST,
+	SK_PNMI_HRX_PMACC,
+	SK_PNMI_HRX_MACC,
+	SK_PNMI_HRX_PMACC_ERR,
+	SK_PNMI_HRX_MACC_UNKWN,
+	SK_PNMI_HRX_BURST,
+	SK_PNMI_HRX_MISSED,
+	SK_PNMI_HRX_FRAMING,
+	SK_PNMI_HRX_UNDERSIZE,
+	SK_PNMI_HRX_OVERFLOW,
+	SK_PNMI_HRX_JABBER,
+	SK_PNMI_HRX_CARRIER,
+	SK_PNMI_HRX_IRLENGTH,
+	SK_PNMI_HRX_SYMBOL,
+	SK_PNMI_HRX_SHORTS,
+	SK_PNMI_HRX_RUNT,
+	SK_PNMI_HRX_TOO_LONG,
+	SK_PNMI_HRX_FCS,
+	SK_PNMI_HRX_CEXT,
+	SK_PNMI_HRX_UTILUNDER,
+	SK_PNMI_HRX_UTILOVER,
+	SK_PNMI_HRX_64,
+	SK_PNMI_HRX_127,
+	SK_PNMI_HRX_255,
+	SK_PNMI_HRX_511,
+	SK_PNMI_HRX_1023,
+	SK_PNMI_HRX_MAX,
+	SK_PNMI_HRX_LONGFRAMES,
+	
+	SK_PNMI_HRX_RESERVED,
+	
+	SK_PNMI_MAX_IDX		/* NOTE: Ensure SK_PNMI_CNT_NO is set to this value */
+};
 
 /*
  * MAC specific data
  */
 typedef struct s_PnmiStatAddr {
-	SK_BOOL		GetOffset;	/* TRUE: Call GetStatVal function */
-	SK_U16		Param;		/* XMAC register containing value */
+	SK_U16		Reg;		/* MAC register containing the value */
+	SK_BOOL		GetOffset;	/* TRUE: Offset managed by PNMI (call GetStatVal())*/
 } SK_PNMI_STATADDR;
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sk98lin/h/skgepnmi.h linux-2.4.21-pre6/drivers/net/sk98lin/h/skgepnmi.h
--- linux-2.4.20/drivers/net/sk98lin/h/skgepnmi.h	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sk98lin/h/skgepnmi.h	2003-03-26 23:49:06.000000000 +0000
@@ -2,8 +2,8 @@
  *
  * Name:	skgepnmi.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.48 $
- * Date:	$Date: 2001/02/23 14:34:24 $
+ * Version:	$Revision: 1.59 $
+ * Date:	$Date: 2002/12/16 14:03:50 $
  * Purpose:	Defines for Private Network Management Interface
  *
  ****************************************************************************/
@@ -26,6 +26,43 @@
  * History:
  *
  *	$Log: skgepnmi.h,v $
+ *	Revision 1.59  2002/12/16 14:03:50  tschilli
+ *	New defines for VCT added.
+ *	
+ *	Revision 1.58  2002/12/16 09:04:59  tschilli
+ *	Code for VCT handling added.
+ *	
+ *	Revision 1.57  2002/09/26 12:41:05  tschilli
+ *	SK_PNMI_PORT BufPort entry in struct SK_PNMI added.
+ *	
+ *	Revision 1.56  2002/08/16 11:10:41  rwahl
+ *	- Replaced c++ comment.
+ *	
+ *	Revision 1.55  2002/08/09 15:40:21  rwahl
+ *	Editorial change (renamed ConfSpeedCap).
+ *	
+ *	Revision 1.54  2002/08/09 11:06:07  rwahl
+ *	Added OID_SKGE_SPEED_CAP.
+ *	
+ *	Revision 1.53  2002/08/09 09:45:28  rwahl
+ *	Added support for NDIS OID_PNP_xxx.
+ *	Editorial changes.
+ *	
+ *	Revision 1.52  2002/08/06 17:54:07  rwahl
+ *	- Added speed cap to PNMI config struct.
+ *	
+ *	Revision 1.51  2002/07/17 19:19:26  rwahl
+ *	- Added OID_SKGE_SPEED_MODE and OID_SKGE_SPEED_STATUS.
+ *	- Added SK_PNMI_CNT_RX_PMACC_ERR() & SK_PNMI_CNT_RX_LONGFRAMES().
+ *	- Added speed mode & status to PNMI config struct.
+ *	- Editorial changes.
+ *	
+ *	Revision 1.50  2002/05/22 08:59:37  rwahl
+ *	Added string definitions for error msgs.
+ *	
+ *	Revision 1.49  2001/11/20 09:23:50  rwahl
+ *	- pnmi struct: reordered and aligned to 32bit.
+ *	
  *	Revision 1.48  2001/02/23 14:34:24  mkunz
  *	Changed macro PHYS2INST. Added pAC to Interface
  *	
@@ -233,12 +270,14 @@
 #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 */
+#define SK_PNMI_EVT_VCT_RESET		17	/* VCT port reset timer event started with SET. */
+
 
 /*
  * Return values
  */
-#define SK_PNMI_ERR_OK			0
-#define SK_PNMI_ERR_GENERAL		1
+#define SK_PNMI_ERR_OK				0
+#define SK_PNMI_ERR_GENERAL			1
 #define SK_PNMI_ERR_TOO_SHORT		2
 #define SK_PNMI_ERR_BAD_VALUE		3
 #define SK_PNMI_ERR_READ_ONLY		4
@@ -290,11 +329,11 @@
  */
 #ifndef _NDIS_	/* Check, whether NDIS already included OIDs */
 
-#define OID_GEN_XMIT_OK			0x00020101
-#define OID_GEN_RCV_OK			0x00020102
-#define OID_GEN_XMIT_ERROR		0x00020103
-#define OID_GEN_RCV_ERROR		0x00020104
-#define OID_GEN_RCV_NO_BUFFER		0x00020105
+#define OID_GEN_XMIT_OK					0x00020101
+#define OID_GEN_RCV_OK					0x00020102
+#define OID_GEN_XMIT_ERROR				0x00020103
+#define OID_GEN_RCV_ERROR				0x00020104
+#define OID_GEN_RCV_NO_BUFFER			0x00020105
 
 /* #define OID_GEN_DIRECTED_BYTES_XMIT	0x00020201 */
 #define OID_GEN_DIRECTED_FRAMES_XMIT	0x00020202
@@ -303,211 +342,256 @@
 /* #define OID_GEN_BROADCAST_BYTES_XMIT	0x00020205 */
 #define OID_GEN_BROADCAST_FRAMES_XMIT	0x00020206
 /* #define OID_GEN_DIRECTED_BYTES_RCV	0x00020207 */
-#define OID_GEN_DIRECTED_FRAMES_RCV	0x00020208
+#define OID_GEN_DIRECTED_FRAMES_RCV		0x00020208
 /* #define OID_GEN_MULTICAST_BYTES_RCV	0x00020209 */
 #define OID_GEN_MULTICAST_FRAMES_RCV	0x0002020A
 /* #define OID_GEN_BROADCAST_BYTES_RCV	0x0002020B */
 #define OID_GEN_BROADCAST_FRAMES_RCV	0x0002020C
-#define OID_GEN_RCV_CRC_ERROR		0x0002020D
+#define OID_GEN_RCV_CRC_ERROR			0x0002020D
 #define OID_GEN_TRANSMIT_QUEUE_LENGTH	0x0002020E
 
-#define OID_802_3_PERMANENT_ADDRESS	0x01010101
-#define OID_802_3_CURRENT_ADDRESS	0x01010102
-/* #define OID_802_3_MULTICAST_LIST	0x01010103 */
+#define OID_802_3_PERMANENT_ADDRESS		0x01010101
+#define OID_802_3_CURRENT_ADDRESS		0x01010102
+/* #define OID_802_3_MULTICAST_LIST		0x01010103 */
 /* #define OID_802_3_MAXIMUM_LIST_SIZE	0x01010104 */
-/* #define OID_802_3_MAC_OPTIONS	0x01010105 */
+/* #define OID_802_3_MAC_OPTIONS		0x01010105 */
 			
 #define OID_802_3_RCV_ERROR_ALIGNMENT	0x01020101
 #define OID_802_3_XMIT_ONE_COLLISION	0x01020102
 #define OID_802_3_XMIT_MORE_COLLISIONS	0x01020103
-#define OID_802_3_XMIT_DEFERRED		0x01020201
+#define OID_802_3_XMIT_DEFERRED			0x01020201
 #define OID_802_3_XMIT_MAX_COLLISIONS	0x01020202
-#define OID_802_3_RCV_OVERRUN		0x01020203
-#define OID_802_3_XMIT_UNDERRUN		0x01020204
+#define OID_802_3_RCV_OVERRUN			0x01020203
+#define OID_802_3_XMIT_UNDERRUN			0x01020204
 #define OID_802_3_XMIT_TIMES_CRS_LOST	0x01020206
 #define OID_802_3_XMIT_LATE_COLLISIONS	0x01020207
 
+/*
+ * PnP and PM OIDs
+ */
+#ifdef SK_POWER_MGMT
+#define OID_PNP_CAPABILITIES			0xFD010100
+#define OID_PNP_SET_POWER				0xFD010101
+#define OID_PNP_QUERY_POWER				0xFD010102
+#define OID_PNP_ADD_WAKE_UP_PATTERN		0xFD010103
+#define OID_PNP_REMOVE_WAKE_UP_PATTERN	0xFD010104
+#define OID_PNP_ENABLE_WAKE_UP			0xFD010106
+#endif /* SK_POWER_MGMT */
+
 #endif /* _NDIS_ */
 
-#define OID_SKGE_MDB_VERSION		0xFF010100
-#define OID_SKGE_SUPPORTED_LIST		0xFF010101
-#define OID_SKGE_VPD_FREE_BYTES		0xFF010102
-#define OID_SKGE_VPD_ENTRIES_LIST	0xFF010103
-#define OID_SKGE_VPD_ENTRIES_NUMBER	0xFF010104
-#define OID_SKGE_VPD_KEY		0xFF010105
-#define OID_SKGE_VPD_VALUE		0xFF010106
-#define OID_SKGE_VPD_ACCESS		0xFF010107
-#define OID_SKGE_VPD_ACTION		0xFF010108
+#define OID_SKGE_MDB_VERSION			0xFF010100
+#define OID_SKGE_SUPPORTED_LIST			0xFF010101
+#define OID_SKGE_VPD_FREE_BYTES			0xFF010102
+#define OID_SKGE_VPD_ENTRIES_LIST		0xFF010103
+#define OID_SKGE_VPD_ENTRIES_NUMBER		0xFF010104
+#define OID_SKGE_VPD_KEY				0xFF010105
+#define OID_SKGE_VPD_VALUE				0xFF010106
+#define OID_SKGE_VPD_ACCESS				0xFF010107
+#define OID_SKGE_VPD_ACTION				0xFF010108
 			
-#define OID_SKGE_PORT_NUMBER		0xFF010110
-#define OID_SKGE_DEVICE_TYPE		0xFF010111
-#define OID_SKGE_DRIVER_DESCR		0xFF010112
-#define OID_SKGE_DRIVER_VERSION		0xFF010113
-#define OID_SKGE_HW_DESCR		0xFF010114
-#define OID_SKGE_HW_VERSION		0xFF010115
-#define OID_SKGE_CHIPSET		0xFF010116
-#define OID_SKGE_ACTION			0xFF010117
-#define OID_SKGE_RESULT			0xFF010118
-#define OID_SKGE_BUS_TYPE		0xFF010119
-#define OID_SKGE_BUS_SPEED		0xFF01011A
-#define OID_SKGE_BUS_WIDTH		0xFF01011B
-
-/*#define OID_SKGE_MULTICAST_LIST		0xFF01011C*/
-
-#define OID_SKGE_SENSOR_NUMBER		0xFF020100			
-#define OID_SKGE_SENSOR_INDEX		0xFF020101
-#define OID_SKGE_SENSOR_DESCR		0xFF020102
-#define OID_SKGE_SENSOR_TYPE		0xFF020103
-#define OID_SKGE_SENSOR_VALUE		0xFF020104
+#define OID_SKGE_PORT_NUMBER			0xFF010110
+#define OID_SKGE_DEVICE_TYPE			0xFF010111
+#define OID_SKGE_DRIVER_DESCR			0xFF010112
+#define OID_SKGE_DRIVER_VERSION			0xFF010113
+#define OID_SKGE_HW_DESCR				0xFF010114
+#define OID_SKGE_HW_VERSION				0xFF010115
+#define OID_SKGE_CHIPSET				0xFF010116
+#define OID_SKGE_ACTION					0xFF010117
+#define OID_SKGE_RESULT					0xFF010118
+#define OID_SKGE_BUS_TYPE				0xFF010119
+#define OID_SKGE_BUS_SPEED				0xFF01011A
+#define OID_SKGE_BUS_WIDTH				0xFF01011B
+/* 0xFF01011C unused */
+#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
+#define OID_SKGE_CONNECTOR				0xFF010123
+#define OID_SKGE_LINK_CAP				0xFF010124
+#define OID_SKGE_LINK_MODE				0xFF010125
+#define OID_SKGE_LINK_MODE_STATUS		0xFF010126
+#define OID_SKGE_LINK_STATUS			0xFF010127
+#define OID_SKGE_FLOWCTRL_CAP			0xFF010128
+#define OID_SKGE_FLOWCTRL_MODE			0xFF010129
+#define OID_SKGE_FLOWCTRL_STATUS		0xFF01012A
+#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
+
+#define OID_SKGE_RLMT_MODE				0xFF010140
+#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_SPEED_CAP				0xFF010170
+#define OID_SKGE_SPEED_MODE				0xFF010171
+#define OID_SKGE_SPEED_STATUS			0xFF010172
+
+#define OID_SKGE_SENSOR_NUMBER			0xFF020100			
+#define OID_SKGE_SENSOR_INDEX			0xFF020101
+#define OID_SKGE_SENSOR_DESCR			0xFF020102
+#define OID_SKGE_SENSOR_TYPE			0xFF020103
+#define OID_SKGE_SENSOR_VALUE			0xFF020104
 #define OID_SKGE_SENSOR_WAR_THRES_LOW	0xFF020105
 #define OID_SKGE_SENSOR_WAR_THRES_UPP	0xFF020106
 #define OID_SKGE_SENSOR_ERR_THRES_LOW	0xFF020107
 #define OID_SKGE_SENSOR_ERR_THRES_UPP	0xFF020108
-#define OID_SKGE_SENSOR_STATUS		0xFF020109
-#define OID_SKGE_SENSOR_WAR_CTS		0xFF02010A
-#define OID_SKGE_SENSOR_ERR_CTS		0xFF02010B
-#define OID_SKGE_SENSOR_WAR_TIME	0xFF02010C
-#define OID_SKGE_SENSOR_ERR_TIME	0xFF02010D
+#define OID_SKGE_SENSOR_STATUS			0xFF020109
+#define OID_SKGE_SENSOR_WAR_CTS			0xFF02010A
+#define OID_SKGE_SENSOR_ERR_CTS			0xFF02010B
+#define OID_SKGE_SENSOR_WAR_TIME		0xFF02010C
+#define OID_SKGE_SENSOR_ERR_TIME		0xFF02010D
 
-#define OID_SKGE_CHKSM_NUMBER		0xFF020110
-#define OID_SKGE_CHKSM_RX_OK_CTS	0xFF020111
+#define OID_SKGE_CHKSM_NUMBER			0xFF020110
+#define OID_SKGE_CHKSM_RX_OK_CTS		0xFF020111
 #define OID_SKGE_CHKSM_RX_UNABLE_CTS	0xFF020112
-#define OID_SKGE_CHKSM_RX_ERR_CTS	0xFF020113
-#define OID_SKGE_CHKSM_TX_OK_CTS	0xFF020114
+#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
-#define OID_SKGE_STAT_TX_MULTICAST	0xFF020123
-#define OID_SKGE_STAT_TX_UNICAST	0xFF020124
-#define OID_SKGE_STAT_TX_LONGFRAMES	0xFF020125
-#define OID_SKGE_STAT_TX_BURST		0xFF020126
-#define OID_SKGE_STAT_TX_PFLOWC		0xFF020127
-#define OID_SKGE_STAT_TX_FLOWC		0xFF020128
-#define OID_SKGE_STAT_TX_SINGLE_COL	0xFF020129
-#define OID_SKGE_STAT_TX_MULTI_COL	0xFF02012A
-#define OID_SKGE_STAT_TX_EXCESS_COL	0xFF02012B
-#define OID_SKGE_STAT_TX_LATE_COL	0xFF02012C
-#define OID_SKGE_STAT_TX_DEFFERAL	0xFF02012D
-#define OID_SKGE_STAT_TX_EXCESS_DEF	0xFF02012E
-#define OID_SKGE_STAT_TX_UNDERRUN	0xFF02012F
-#define OID_SKGE_STAT_TX_CARRIER	0xFF020130
+#define OID_SKGE_STAT_TX				0xFF020120
+#define OID_SKGE_STAT_TX_OCTETS			0xFF020121
+#define OID_SKGE_STAT_TX_BROADCAST		0xFF020122
+#define OID_SKGE_STAT_TX_MULTICAST		0xFF020123
+#define OID_SKGE_STAT_TX_UNICAST		0xFF020124
+#define OID_SKGE_STAT_TX_LONGFRAMES		0xFF020125
+#define OID_SKGE_STAT_TX_BURST			0xFF020126
+#define OID_SKGE_STAT_TX_PFLOWC			0xFF020127
+#define OID_SKGE_STAT_TX_FLOWC			0xFF020128
+#define OID_SKGE_STAT_TX_SINGLE_COL		0xFF020129
+#define OID_SKGE_STAT_TX_MULTI_COL		0xFF02012A
+#define OID_SKGE_STAT_TX_EXCESS_COL		0xFF02012B
+#define OID_SKGE_STAT_TX_LATE_COL		0xFF02012C
+#define OID_SKGE_STAT_TX_DEFFERAL		0xFF02012D
+#define OID_SKGE_STAT_TX_EXCESS_DEF		0xFF02012E
+#define OID_SKGE_STAT_TX_UNDERRUN		0xFF02012F
+#define OID_SKGE_STAT_TX_CARRIER		0xFF020130
 /* #define OID_SKGE_STAT_TX_UTIL		0xFF020131 */
-#define OID_SKGE_STAT_TX_64		0xFF020132
-#define OID_SKGE_STAT_TX_127		0xFF020133
-#define OID_SKGE_STAT_TX_255		0xFF020134
-#define OID_SKGE_STAT_TX_511		0xFF020135
-#define OID_SKGE_STAT_TX_1023		0xFF020136
-#define OID_SKGE_STAT_TX_MAX		0xFF020137
-#define OID_SKGE_STAT_TX_SYNC		0xFF020138
+#define OID_SKGE_STAT_TX_64				0xFF020132
+#define OID_SKGE_STAT_TX_127			0xFF020133
+#define OID_SKGE_STAT_TX_255			0xFF020134
+#define OID_SKGE_STAT_TX_511			0xFF020135
+#define OID_SKGE_STAT_TX_1023			0xFF020136
+#define OID_SKGE_STAT_TX_MAX			0xFF020137
+#define OID_SKGE_STAT_TX_SYNC			0xFF020138
 #define OID_SKGE_STAT_TX_SYNC_OCTETS	0xFF020139
-#define OID_SKGE_STAT_RX		0xFF02013A
-#define OID_SKGE_STAT_RX_OCTETS		0xFF02013B
-#define OID_SKGE_STAT_RX_BROADCAST	0xFF02013C
-#define OID_SKGE_STAT_RX_MULTICAST	0xFF02013D
-#define OID_SKGE_STAT_RX_UNICAST	0xFF02013E
-#define OID_SKGE_STAT_RX_PFLOWC		0xFF02013F
-#define OID_SKGE_STAT_RX_FLOWC		0xFF020140
-#define OID_SKGE_STAT_RX_PFLOWC_ERR	0xFF020141
+#define OID_SKGE_STAT_RX				0xFF02013A
+#define OID_SKGE_STAT_RX_OCTETS			0xFF02013B
+#define OID_SKGE_STAT_RX_BROADCAST		0xFF02013C
+#define OID_SKGE_STAT_RX_MULTICAST		0xFF02013D
+#define OID_SKGE_STAT_RX_UNICAST		0xFF02013E
+#define OID_SKGE_STAT_RX_PFLOWC			0xFF02013F
+#define OID_SKGE_STAT_RX_FLOWC			0xFF020140
+#define OID_SKGE_STAT_RX_PFLOWC_ERR		0xFF020141
 #define OID_SKGE_STAT_RX_FLOWC_UNKWN	0xFF020142
-#define OID_SKGE_STAT_RX_BURST		0xFF020143
-#define OID_SKGE_STAT_RX_MISSED		0xFF020144
-#define OID_SKGE_STAT_RX_FRAMING	0xFF020145
-#define OID_SKGE_STAT_RX_OVERFLOW	0xFF020146
-#define OID_SKGE_STAT_RX_JABBER		0xFF020147
-#define OID_SKGE_STAT_RX_CARRIER	0xFF020148
-#define OID_SKGE_STAT_RX_IR_LENGTH	0xFF020149
-#define OID_SKGE_STAT_RX_SYMBOL		0xFF02014A
-#define OID_SKGE_STAT_RX_SHORTS		0xFF02014B
-#define OID_SKGE_STAT_RX_RUNT		0xFF02014C
-#define OID_SKGE_STAT_RX_CEXT		0xFF02014D
-#define OID_SKGE_STAT_RX_TOO_LONG	0xFF02014E
-#define OID_SKGE_STAT_RX_FCS		0xFF02014F
+#define OID_SKGE_STAT_RX_BURST			0xFF020143
+#define OID_SKGE_STAT_RX_MISSED			0xFF020144
+#define OID_SKGE_STAT_RX_FRAMING		0xFF020145
+#define OID_SKGE_STAT_RX_OVERFLOW		0xFF020146
+#define OID_SKGE_STAT_RX_JABBER			0xFF020147
+#define OID_SKGE_STAT_RX_CARRIER		0xFF020148
+#define OID_SKGE_STAT_RX_IR_LENGTH		0xFF020149
+#define OID_SKGE_STAT_RX_SYMBOL			0xFF02014A
+#define OID_SKGE_STAT_RX_SHORTS			0xFF02014B
+#define OID_SKGE_STAT_RX_RUNT			0xFF02014C
+#define OID_SKGE_STAT_RX_CEXT			0xFF02014D
+#define OID_SKGE_STAT_RX_TOO_LONG		0xFF02014E
+#define OID_SKGE_STAT_RX_FCS			0xFF02014F
 /* #define OID_SKGE_STAT_RX_UTIL		0xFF020150 */
-#define OID_SKGE_STAT_RX_64		0xFF020151
-#define OID_SKGE_STAT_RX_127		0xFF020152
-#define OID_SKGE_STAT_RX_255		0xFF020153
-#define OID_SKGE_STAT_RX_511		0xFF020154
-#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
-#define OID_SKGE_CONNECTOR		0xFF010123
-#define OID_SKGE_LINK_CAP		0xFF010124
-#define OID_SKGE_LINK_MODE		0xFF010125
-#define OID_SKGE_LINK_MODE_STATUS	0xFF010126
-#define OID_SKGE_LINK_STATUS		0xFF010127
-#define OID_SKGE_FLOWCTRL_CAP		0xFF010128
-#define OID_SKGE_FLOWCTRL_MODE		0xFF010129
-#define OID_SKGE_FLOWCTRL_STATUS	0xFF01012A
-#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
-
-#define OID_SKGE_RLMT_MODE		0xFF010140
-#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
-#define OID_SKGE_RLMT_RX_HELLO_CTS	0xFF020167
-#define OID_SKGE_RLMT_TX_SP_REQ_CTS	0xFF020168
-#define OID_SKGE_RLMT_RX_SP_CTS		0xFF020169
+#define OID_SKGE_STAT_RX_64				0xFF020151
+#define OID_SKGE_STAT_RX_127			0xFF020152
+#define OID_SKGE_STAT_RX_255			0xFF020153
+#define OID_SKGE_STAT_RX_511			0xFF020154
+#define OID_SKGE_STAT_RX_1023			0xFF020155
+#define OID_SKGE_STAT_RX_MAX			0xFF020156
+#define OID_SKGE_STAT_RX_LONGFRAMES		0xFF020157
+
+#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
+#define OID_SKGE_RLMT_RX_HELLO_CTS		0xFF020167
+#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_INDEX	0xFF010151
-#define OID_SKGE_RLMT_MONITOR_ADDR	0xFF010152
-#define OID_SKGE_RLMT_MONITOR_ERRS	0xFF010153
+#define OID_SKGE_RLMT_MONITOR_INDEX		0xFF010151
+#define OID_SKGE_RLMT_MONITOR_ADDR		0xFF010152
+#define OID_SKGE_RLMT_MONITOR_ERRS		0xFF010153
 #define OID_SKGE_RLMT_MONITOR_TIMESTAMP	0xFF010154
-#define OID_SKGE_RLMT_MONITOR_ADMIN	0xFF010155
+#define OID_SKGE_RLMT_MONITOR_ADMIN		0xFF010155
 
-#define OID_SKGE_TX_SW_QUEUE_LEN	0xFF020170
-#define OID_SKGE_TX_SW_QUEUE_MAX	0xFF020171
-#define OID_SKGE_TX_RETRY		0xFF020172
-#define OID_SKGE_RX_INTR_CTS		0xFF020173
-#define OID_SKGE_TX_INTR_CTS		0xFF020174
-#define OID_SKGE_RX_NO_BUF_CTS		0xFF020175
-#define OID_SKGE_TX_NO_BUF_CTS		0xFF020176
-#define OID_SKGE_TX_USED_DESCR_NO	0xFF020177
-#define OID_SKGE_RX_DELIVERED_CTS	0xFF020178
+#define OID_SKGE_TX_SW_QUEUE_LEN		0xFF020170
+#define OID_SKGE_TX_SW_QUEUE_MAX		0xFF020171
+#define OID_SKGE_TX_RETRY				0xFF020172
+#define OID_SKGE_RX_INTR_CTS			0xFF020173
+#define OID_SKGE_TX_INTR_CTS			0xFF020174
+#define OID_SKGE_RX_NO_BUF_CTS			0xFF020175
+#define OID_SKGE_TX_NO_BUF_CTS			0xFF020176
+#define OID_SKGE_TX_USED_DESCR_NO		0xFF020177
+#define OID_SKGE_RX_DELIVERED_CTS		0xFF020178
 #define OID_SKGE_RX_OCTETS_DELIV_CTS	0xFF020179
-#define OID_SKGE_RX_HW_ERROR_CTS	0xFF02017A
-#define OID_SKGE_TX_HW_ERROR_CTS	0xFF02017B
-#define OID_SKGE_IN_ERRORS_CTS		0xFF02017C
-#define OID_SKGE_OUT_ERROR_CTS		0xFF02017D
-#define OID_SKGE_ERR_RECOVERY_CTS	0xFF02017E
-#define OID_SKGE_SYSUPTIME		0xFF02017F
-
-#define OID_SKGE_ALL_DATA		0xFF020190
-
-
-#define	OID_SKGE_TRAP_SEN_WAR_LOW	500
-#define OID_SKGE_TRAP_SEN_WAR_UPP	501
-#define	OID_SKGE_TRAP_SEN_ERR_LOW	502
-#define OID_SKGE_TRAP_SEN_ERR_UPP	503
+#define OID_SKGE_RX_HW_ERROR_CTS		0xFF02017A
+#define OID_SKGE_TX_HW_ERROR_CTS		0xFF02017B
+#define OID_SKGE_IN_ERRORS_CTS			0xFF02017C
+#define OID_SKGE_OUT_ERROR_CTS			0xFF02017D
+#define OID_SKGE_ERR_RECOVERY_CTS		0xFF02017E
+#define OID_SKGE_SYSUPTIME				0xFF02017F
+
+#define OID_SKGE_ALL_DATA				0xFF020190
+
+/* Defines for VCT. */
+#define OID_SKGE_VCT_GET			0xFF020200
+#define OID_SKGE_VCT_SET			0xFF020201
+#define OID_SKGE_VCT_STATUS			0xFF020202
+
+
+/* VCT struct to store a backup copy of VCT data after a port reset. */
+typedef struct s_PnmiVct {
+	SK_U8			VctStatus;
+	SK_U8			PCableLen;
+	SK_U32			PMdiPairLen[4];
+	SK_U8			PMdiPairSts[4];
+} SK_PNMI_VCT;
+
+
+/* VCT status values (to be given to CPA via OID_SKGE_VCT_STATUS). */
+#define SK_PNMI_VCT_NONE		0
+#define SK_PNMI_VCT_OLD_VCT_DATA	1
+#define SK_PNMI_VCT_NEW_VCT_DATA	2
+#define SK_PNMI_VCT_OLD_DSP_DATA	4
+#define SK_PNMI_VCT_NEW_DSP_DATA	8
+#define SK_PNMI_VCT_RUNNING		16
+
+
+/* VCT cable test status. */
+#define SK_PNMI_VCT_NORMAL_CABLE		0
+#define SK_PNMI_VCT_SHORT_CABLE			1
+#define SK_PNMI_VCT_OPEN_CABLE			2
+#define SK_PNMI_VCT_TEST_FAIL			3
+#define SK_PNMI_VCT_IMPEDANCE_MISMATCH		4
+
+#define	OID_SKGE_TRAP_SEN_WAR_LOW		500
+#define OID_SKGE_TRAP_SEN_WAR_UPP		501
+#define	OID_SKGE_TRAP_SEN_ERR_LOW		502
+#define OID_SKGE_TRAP_SEN_ERR_UPP		503
 #define OID_SKGE_TRAP_RLMT_CHANGE_THRES	520
 #define OID_SKGE_TRAP_RLMT_CHANGE_PORT	521
 #define OID_SKGE_TRAP_RLMT_PORT_DOWN	522
-#define OID_SKGE_TRAP_RLMT_PORT_UP	523
+#define OID_SKGE_TRAP_RLMT_PORT_UP		523
 #define OID_SKGE_TRAP_RLMT_SEGMENTATION	524
 
 
@@ -539,7 +623,7 @@
 #define SK_PNMI_ERR012		(SK_ERRBASE_PNMI + 12)
 #define SK_PNMI_ERR012MSG	"SensorStat: Unknown OID"
 #define SK_PNMI_ERR013		(SK_ERRBASE_PNMI + 13)
-#define SK_PNMI_ERR013MSG	"SensorStat: Unknown OID should be errored before"
+#define SK_PNMI_ERR013MSG	""
 #define SK_PNMI_ERR014		(SK_ERRBASE_PNMI + 14)
 #define SK_PNMI_ERR014MSG	"Vpd: Cannot read VPD keys"
 #define SK_PNMI_ERR015		(SK_ERRBASE_PNMI + 15)
@@ -583,7 +667,7 @@
 #define SK_PNMI_ERR035		(SK_ERRBASE_PNMI + 35)
 #define SK_PNMI_ERR035MSG	"Rlmt: Unknown OID"
 #define SK_PNMI_ERR036		(SK_ERRBASE_PNMI + 36)
-#define SK_PNMI_ERR036MSG	"Rlmt: Unknown OID should be errored before"
+#define SK_PNMI_ERR036MSG	""
 #define SK_PNMI_ERR037		(SK_ERRBASE_PNMI + 37)
 #define SK_PNMI_ERR037MSG	"Rlmt: SK_RLMT_MODE_CHANGE event return not 0"
 #define SK_PNMI_ERR038		(SK_ERRBASE_PNMI + 38)
@@ -591,17 +675,17 @@
 #define SK_PNMI_ERR039		(SK_ERRBASE_PNMI + 39)
 #define SK_PNMI_ERR039MSG	"RlmtStat: Unknown OID"
 #define SK_PNMI_ERR040		(SK_ERRBASE_PNMI + 40)
-#define SK_PNMI_ERR040MSG	"RlmtStat: Unknown OID should be errored before"
+#define SK_PNMI_ERR040MSG	"PowerManagement: Unknown OID"
 #define SK_PNMI_ERR041		(SK_ERRBASE_PNMI + 41)
 #define SK_PNMI_ERR041MSG	"MacPrivateConf: Unknown OID"
 #define SK_PNMI_ERR042		(SK_ERRBASE_PNMI + 42)
-#define SK_PNMI_ERR042MSG	"MacPrivateConf: Unknown OID should be errored before"
+#define SK_PNMI_ERR042MSG	"MacPrivateConf: SK_HWEV_SET_ROLE returned not 0"
 #define SK_PNMI_ERR043		(SK_ERRBASE_PNMI + 43)
 #define SK_PNMI_ERR043MSG	"MacPrivateConf: SK_HWEV_SET_LMODE returned not 0"
 #define SK_PNMI_ERR044		(SK_ERRBASE_PNMI + 44)
 #define SK_PNMI_ERR044MSG	"MacPrivateConf: SK_HWEV_SET_FLOWMODE returned not 0"
 #define SK_PNMI_ERR045		(SK_ERRBASE_PNMI + 45)
-#define SK_PNMI_ERR045MSG	"MacPrivateConf: Unknown OID in set action"
+#define SK_PNMI_ERR045MSG	"MacPrivateConf: SK_HWEV_SET_SPEED returned not 0"
 #define SK_PNMI_ERR046		(SK_ERRBASE_PNMI + 46)
 #define SK_PNMI_ERR046MSG	"Monitor: Unknown OID"
 #define SK_PNMI_ERR047		(SK_ERRBASE_PNMI + 47)
@@ -609,13 +693,13 @@
 #define SK_PNMI_ERR048		(SK_ERRBASE_PNMI + 48)
 #define SK_PNMI_ERR048MSG	"RlmtUpdate: Event function returns not 0"
 #define SK_PNMI_ERR049		(SK_ERRBASE_PNMI + 49)
-#define SK_PNMI_ERR049MSG	""
+#define SK_PNMI_ERR049MSG	"SkPnmiInit: Invalid size of 'CounterOffset' struct!!"
 #define SK_PNMI_ERR050		(SK_ERRBASE_PNMI + 50)
-#define SK_PNMI_ERR050MSG	"MacUpdate: Cannot update statistic counter"
+#define SK_PNMI_ERR050MSG	"SkPnmiInit: Invalid size of 'StatAddr' table!!"
 #define SK_PNMI_ERR051		(SK_ERRBASE_PNMI + 51)
 #define SK_PNMI_ERR051MSG	"SkPnmiEvent: Port switch suspicious"
 #define SK_PNMI_ERR052		(SK_ERRBASE_PNMI + 52)
-#define SK_PNMI_ERR052MSG	"MacPrivateConf: SK_HWEV_SET_ROLE returned not 0"
+#define SK_PNMI_ERR052MSG	""
 
 /*
  * Management counter macros called by the driver
@@ -659,7 +743,21 @@
 #define SK_PNMI_CNT_RX_LONGFRAMES(pAC,p) \
 	{ \
 		if ((p) < SK_MAX_MACS) { \
-			((pAC)->Pnmi.Port[p].StatRxLongFrameCts)++; \
+			((pAC)->Pnmi.Port[p].StatRxLongFrameCts++); \
+		} \
+	}
+
+#define SK_PNMI_CNT_RX_FRAMETOOLONG(pAC,p) \
+	{ \
+		if ((p) < SK_MAX_MACS) { \
+			((pAC)->Pnmi.Port[p].StatRxFrameTooLongCts++); \
+		} \
+	}
+
+#define SK_PNMI_CNT_RX_PMACC_ERR(pAC,p) \
+	{ \
+		if ((p) < SK_MAX_MACS) { \
+			((pAC)->Pnmi.Port[p].StatRxPMaccErr++); \
 		} \
 	}
 
@@ -685,12 +783,12 @@
 #define SK_PNMI_MULTICAST_LISTLEN	64
 #define SK_PNMI_SENSOR_ENTRIES		(SK_MAX_SENSORS)
 #define SK_PNMI_CHECKSUM_ENTRIES	3
-#define SK_PNMI_MAC_ENTRIES		(SK_MAX_MACS + 1)
+#define SK_PNMI_MAC_ENTRIES			(SK_MAX_MACS + 1)
 #define SK_PNMI_MONITOR_ENTRIES		20
 #define SK_PNMI_TRAP_ENTRIES		10
-#define SK_PNMI_TRAPLEN			128
-#define SK_PNMI_STRINGLEN1		80
-#define SK_PNMI_STRINGLEN2		25
+#define SK_PNMI_TRAPLEN				128
+#define SK_PNMI_STRINGLEN1			80
+#define SK_PNMI_STRINGLEN2			25
 #define SK_PNMI_TRAP_QUEUE_LEN		512
 
 typedef struct s_PnmiVpd {
@@ -798,6 +896,9 @@
 	SK_U8			ConfPhyOperationCapability;
 	SK_U8			ConfPhyOperationMode;
 	SK_U8			ConfPhyOperationStatus;
+	SK_U8			ConfSpeedCapability;
+	SK_U8			ConfSpeedMode;
+	SK_U8			ConfSpeedStatus;
 } SK_PNMI_CONF;
 
 typedef struct s_PnmiRlmt {
@@ -843,11 +944,11 @@
 	SK_U8			BusSpeed;
 	SK_U8			BusWidth;
 	SK_U8			SensorNumber;
-	SK_PNMI_SENSOR		Sensor[SK_PNMI_SENSOR_ENTRIES];
+	SK_PNMI_SENSOR	Sensor[SK_PNMI_SENSOR_ENTRIES];
 	SK_U8			ChecksumNumber;
 	SK_PNMI_CHECKSUM	Checksum[SK_PNMI_CHECKSUM_ENTRIES];
-	SK_PNMI_STAT		Stat[SK_PNMI_MAC_ENTRIES];
-	SK_PNMI_CONF		Conf[SK_PNMI_MAC_ENTRIES];
+	SK_PNMI_STAT	Stat[SK_PNMI_MAC_ENTRIES];
+	SK_PNMI_CONF	Conf[SK_PNMI_MAC_ENTRIES];
 	SK_U8			RlmtMode;
 	SK_U32			RlmtPortNumber;
 	SK_U8			RlmtPortActive;
@@ -856,7 +957,7 @@
 	SK_U64			RlmtChangeTime;
 	SK_U64			RlmtChangeEstimate;
 	SK_U64			RlmtChangeThreshold;
-	SK_PNMI_RLMT		Rlmt[SK_MAX_MACS];
+	SK_PNMI_RLMT	Rlmt[SK_MAX_MACS];
 	SK_U32			RlmtMonitorNumber;
 	SK_PNMI_RLMT_MONITOR	RlmtMonitor[SK_PNMI_MONITOR_ENTRIES];
 	SK_U32			TrapNumber;
@@ -882,25 +983,27 @@
 #define SK_PNMI_STRUCT_SIZE	(sizeof(SK_PNMI_STRUCT_DATA))
 #define SK_PNMI_MIN_STRUCT_SIZE	((unsigned int)(SK_UPTR)\
 				 &(((SK_PNMI_STRUCT_DATA *)0)->VpdFreeBytes))
-							/*
-							 * ReturnStatus field
-							 * must be located
-							 * before VpdFreeBytes
-							 */
+														/*
+														 * ReturnStatus field
+														 * must be located
+														 * before VpdFreeBytes
+														 */
 
 /*
  * Various definitions
  */
 #define SK_PNMI_MAX_PROTOS		3
 
-#define SK_PNMI_SCNT_NOT		64
-#define SK_PNMI_CNT_NO			67
+#define SK_PNMI_CNT_NO			66	/* Must have the value of the enum
+									 * SK_PNMI_MAX_IDX. Define SK_PNMI_CHECK
+									 * for check while init phase 1
+									 */
 
 /*
  * Estimate data structure
  */
 typedef struct s_PnmiEstimate {
-	unsigned int		EstValueIndex;
+	unsigned int	EstValueIndex;
 	SK_U64			EstValue[7];
 	SK_U64			Estimate;
 	SK_TIMER		EstTimer;
@@ -908,15 +1011,22 @@
 
 
 /*
- * PNMI specific adatper context structure
+ * VCT timer data structure
+ */
+typedef struct s_VctTimer {
+	SK_TIMER		VctTimer;
+} SK_PNMI_VCT_TIMER;
+
+
+/*
+ * PNMI specific adapter context structure
  */
 typedef struct s_PnmiPort {
-	SK_U32			CounterHigh[SK_PNMI_SCNT_NOT];
-	SK_U64			CounterOffset[SK_PNMI_CNT_NO];
 	SK_U64			StatSyncCts;
 	SK_U64			StatSyncOctetsCts;
 	SK_U64			StatRxLongFrameCts;
-	SK_BOOL			ActiveFlag;
+	SK_U64			StatRxFrameTooLongCts;
+	SK_U64			StatRxPMaccErr;
 	SK_U64			TxSwQueueLen;
 	SK_U64			TxSwQueueMax;
 	SK_U64			TxRetryCts;
@@ -932,41 +1042,53 @@
 	SK_U64			InErrorsCts;
 	SK_U64			OutErrorsCts;
 	SK_U64			ErrRecoveryCts;
+	SK_U64			RxShortZeroMark;
+	SK_U64			CounterOffset[SK_PNMI_CNT_NO];
+	SK_U32			CounterHigh[SK_PNMI_CNT_NO];
+	SK_BOOL			ActiveFlag;
+	SK_U8			Align[3];
 } SK_PNMI_PORT;
 
 
 typedef struct s_PnmiData {
-	SK_PNMI_PORT		Port[SK_MAX_MACS];
+	SK_PNMI_PORT	Port	[SK_MAX_MACS];
+	SK_PNMI_PORT	BufPort	[SK_MAX_MACS]; /* 2002-09-13 pweber  */
 	SK_U64			VirtualCounterOffset[SK_PNMI_CNT_NO];
 	SK_U32			TestResult;
 	char			HwVersion[10];
+	SK_U16			Align01;
 
 	char			*pDriverDescription;
 	char			*pDriverVersion;
 
-	char			TrapBuf[SK_PNMI_TRAP_QUEUE_LEN];
-	unsigned int		TrapBufFree;
-	unsigned int		TrapQueueBeg;
-	unsigned int		TrapQueueEnd;
-	unsigned int		TrapBufPad;
-	unsigned int		TrapUnique;
-
-	int			MacUpdatedFlag;
-	int			RlmtUpdatedFlag;
-	int			SirqUpdatedFlag;
+	int				MacUpdatedFlag;
+	int				RlmtUpdatedFlag;
+	int				SirqUpdatedFlag;
 
 	SK_U64			RlmtChangeCts;
 	SK_U64			RlmtChangeTime;
 	SK_PNMI_ESTIMATE	RlmtChangeEstimate;
 	SK_U64			RlmtChangeThreshold;
 
+	SK_U64			StartUpTime;
 	SK_U32			DeviceType;
 	char			PciBusSpeed;
 	char			PciBusWidth;
+	char			Chipset;
 	char			PMD;
 	char			Connector;
-	SK_U64			StartUpTime;
 	SK_BOOL			DualNetActiveFlag;
+	SK_U16			Align02;
+
+	char			TrapBuf[SK_PNMI_TRAP_QUEUE_LEN];
+	unsigned int	TrapBufFree;
+	unsigned int	TrapQueueBeg;
+	unsigned int	TrapQueueEnd;
+	unsigned int	TrapBufPad;
+	unsigned int	TrapUnique;
+	SK_U8		VctStatus[SK_MAX_MACS];
+	SK_PNMI_VCT	VctBackup[SK_MAX_MACS];
+	SK_PNMI_VCT_TIMER VctTimeout[SK_MAX_MACS];
 } SK_PNMI;
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sk98lin/h/skgesirq.h linux-2.4.21-pre6/drivers/net/sk98lin/h/skgesirq.h
--- linux-2.4.20/drivers/net/sk98lin/h/skgesirq.h	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sk98lin/h/skgesirq.h	2003-03-26 23:49:54.000000000 +0000
@@ -2,15 +2,15 @@
  *
  * Name:	skgesirq.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.22 $
- * Date:	$Date: 2000/11/09 11:30:10 $
+ * Version:	$Revision: 1.26 $
+ * Date:	$Date: 2002/10/14 09:52:36 $
  * Purpose:	SK specific Gigabit Ethernet special IRQ functions
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998-2000 SysKonnect GmbH.
+ *	(C)Copyright 1998-2002 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
@@ -25,6 +25,21 @@
  *
  * History:
  *	$Log: skgesirq.h,v $
+ *	Revision 1.26  2002/10/14 09:52:36  rschmidt
+ *	Added SKERR_SIRQ_E023 and SKERR_SIRQ_E023 for GPHY (Yukon)
+ *	Editorial changes
+ *	
+ *	Revision 1.25  2002/07/15 18:15:52  rwahl
+ *	Editorial changes.
+ *	
+ *	Revision 1.24  2002/07/15 15:39:21  rschmidt
+ *	Corrected define for SKERR_SIRQ_E022
+ *	Editorial changes
+ *	
+ *	Revision 1.23  2002/04/25 11:09:45  rschmidt
+ *	Removed declarations for SkXmInitPhy(), SkXmRxTxEnable()
+ *	Editorial changes
+ *	
  *	Revision 1.22  2000/11/09 11:30:10  rassmann
  *	WA: Waiting after releasing reset until BCom chip is accessible.
  *	
@@ -66,7 +81,7 @@
  *	defined in skgeinit.h now.
  *
  *	Revision 1.9  1998/10/14 14:00:39  gklug
- *	add: eroor logs for init phys
+ *	add: error logs for init phys
  *	
  *	Revision 1.8  1998/10/14 05:44:05  gklug
  *	add: E020
@@ -103,73 +118,76 @@
 /*
  * Define the Event the special IRQ/INI module can handle
  */
-#define SK_HWEV_WATIM		1	/* Timeout for WA errata #2 XMAC */
-#define SK_HWEV_PORT_START	2	/* Port Start Event by RLMT */
-#define SK_HWEV_PORT_STOP	3	/* Port Stop Event by RLMT */
-#define SK_HWEV_CLEAR_STAT	4	/* Clear Statistics by PNMI */
-#define SK_HWEV_UPDATE_STAT	5	/* Update Statistics by PNMI */
-#define SK_HWEV_SET_LMODE	6	/* Set Link Mode by PNMI */
+#define SK_HWEV_WATIM			1	/* Timeout for WA errata #2 XMAC */
+#define SK_HWEV_PORT_START		2	/* Port Start Event by RLMT */
+#define SK_HWEV_PORT_STOP		3	/* Port Stop Event by RLMT */
+#define SK_HWEV_CLEAR_STAT		4	/* Clear Statistics by PNMI */
+#define SK_HWEV_UPDATE_STAT		5	/* Update Statistics by PNMI */
+#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_HWEV_SET_ROLE		8	/* Set Master/Slave (Role) by PNMI */
+#define SK_HWEV_SET_SPEED		9	/* Set Link Speed by PNMI */
+#define SK_HWEV_HALFDUP_CHK		10	/* Half Duplex Hangup Workaround */
 
-#define	SK_WA_ACT_TIME		(5000000L)	/* 5 sec */
-#define	SK_WA_INA_TIME		(100000L)	/* 100 msec */
+#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 SK_HALFDUP_CHK_TIME	(10000L)	/* 10 msec */
 
 /*
  * Define the error numbers and messages
  */
-#define	SKERR_SIRQ_E001		(SK_ERRBASE_SIRQ+0)
-#define	SKERR_SIRQ_E001MSG	"Unknown event"
-#define	SKERR_SIRQ_E002		(SKERR_SIRQ_E001+1)
-#define	SKERR_SIRQ_E002MSG	"Packet timeout RX1"
-#define	SKERR_SIRQ_E003		(SKERR_SIRQ_E002+1)
-#define	SKERR_SIRQ_E003MSG	"Packet timeout RX2"
-#define	SKERR_SIRQ_E004		(SKERR_SIRQ_E003+1)
-#define	SKERR_SIRQ_E004MSG	"XMAC 1 not correctly initialized"
-#define	SKERR_SIRQ_E005		(SKERR_SIRQ_E004+1)
-#define	SKERR_SIRQ_E005MSG	"XMAC 2 not correctly initialized"
-#define	SKERR_SIRQ_E006		(SKERR_SIRQ_E005+1)
-#define	SKERR_SIRQ_E006MSG	"CHECK failure R1"
-#define	SKERR_SIRQ_E007		(SKERR_SIRQ_E006+1)
-#define	SKERR_SIRQ_E007MSG	"CHECK failure R2"
-#define	SKERR_SIRQ_E008		(SKERR_SIRQ_E007+1)
-#define	SKERR_SIRQ_E008MSG	"CHECK failure XS1"
-#define	SKERR_SIRQ_E009		(SKERR_SIRQ_E008+1)
-#define	SKERR_SIRQ_E009MSG	"CHECK failure XA1"
-#define	SKERR_SIRQ_E010		(SKERR_SIRQ_E009+1)
-#define	SKERR_SIRQ_E010MSG	"CHECK failure XS2"
-#define	SKERR_SIRQ_E011		(SKERR_SIRQ_E010+1)
-#define	SKERR_SIRQ_E011MSG	"CHECK failure XA2"
-#define	SKERR_SIRQ_E012		(SKERR_SIRQ_E011+1)
-#define	SKERR_SIRQ_E012MSG	"unexpected IRQ Master error"
-#define	SKERR_SIRQ_E013		(SKERR_SIRQ_E012+1)
-#define	SKERR_SIRQ_E013MSG	"unexpected IRQ Status error"
-#define	SKERR_SIRQ_E014		(SKERR_SIRQ_E013+1)
-#define	SKERR_SIRQ_E014MSG	"Parity error on RAM (read)"
-#define	SKERR_SIRQ_E015		(SKERR_SIRQ_E014+1)
-#define	SKERR_SIRQ_E015MSG	"Parity error on RAM (write)"
-#define	SKERR_SIRQ_E016		(SKERR_SIRQ_E015+1)
-#define	SKERR_SIRQ_E016MSG	"Parity error MAC 1"
-#define	SKERR_SIRQ_E017		(SKERR_SIRQ_E016+1)
-#define	SKERR_SIRQ_E017MSG	"Parity error MAC 2"
-#define	SKERR_SIRQ_E018		(SKERR_SIRQ_E017+1)
-#define	SKERR_SIRQ_E018MSG	"Parity error RX 1"
-#define	SKERR_SIRQ_E019		(SKERR_SIRQ_E018+1)
-#define	SKERR_SIRQ_E019MSG	"Parity error RX 2"
-#define	SKERR_SIRQ_E020		(SKERR_SIRQ_E019+1)
-#define	SKERR_SIRQ_E020MSG	"XMAC transmit FIFO underrun"
-#define	SKERR_SIRQ_E021		(SKERR_SIRQ_E020+1)
-#define	SKERR_SIRQ_E021MSG	"Spurious I2C interrupt"
-#define	SKERR_SIRQ_E022		(SKERR_SIRQ_E020+1)
-#define	SKERR_SIRQ_E022MSG	"Cable pair swap error"
+#define SKERR_SIRQ_E001		(SK_ERRBASE_SIRQ+0)
+#define SKERR_SIRQ_E001MSG	"Unknown event"
+#define SKERR_SIRQ_E002		(SKERR_SIRQ_E001+1)
+#define SKERR_SIRQ_E002MSG	"Packet timeout RX1"
+#define SKERR_SIRQ_E003		(SKERR_SIRQ_E002+1)
+#define SKERR_SIRQ_E003MSG	"Packet timeout RX2"
+#define SKERR_SIRQ_E004		(SKERR_SIRQ_E003+1)
+#define SKERR_SIRQ_E004MSG	"MAC 1 not correctly initialized"
+#define SKERR_SIRQ_E005		(SKERR_SIRQ_E004+1)
+#define SKERR_SIRQ_E005MSG	"MAC 2 not correctly initialized"
+#define SKERR_SIRQ_E006		(SKERR_SIRQ_E005+1)
+#define SKERR_SIRQ_E006MSG	"CHECK failure R1"
+#define SKERR_SIRQ_E007		(SKERR_SIRQ_E006+1)
+#define SKERR_SIRQ_E007MSG	"CHECK failure R2"
+#define SKERR_SIRQ_E008		(SKERR_SIRQ_E007+1)
+#define SKERR_SIRQ_E008MSG	"CHECK failure XS1"
+#define SKERR_SIRQ_E009		(SKERR_SIRQ_E008+1)
+#define SKERR_SIRQ_E009MSG	"CHECK failure XA1"
+#define SKERR_SIRQ_E010		(SKERR_SIRQ_E009+1)
+#define SKERR_SIRQ_E010MSG	"CHECK failure XS2"
+#define SKERR_SIRQ_E011		(SKERR_SIRQ_E010+1)
+#define SKERR_SIRQ_E011MSG	"CHECK failure XA2"
+#define SKERR_SIRQ_E012		(SKERR_SIRQ_E011+1)
+#define SKERR_SIRQ_E012MSG	"unexpected IRQ Master error"
+#define SKERR_SIRQ_E013		(SKERR_SIRQ_E012+1)
+#define SKERR_SIRQ_E013MSG	"unexpected IRQ Status error"
+#define SKERR_SIRQ_E014		(SKERR_SIRQ_E013+1)
+#define SKERR_SIRQ_E014MSG	"Parity error on RAM (read)"
+#define SKERR_SIRQ_E015		(SKERR_SIRQ_E014+1)
+#define SKERR_SIRQ_E015MSG	"Parity error on RAM (write)"
+#define SKERR_SIRQ_E016		(SKERR_SIRQ_E015+1)
+#define SKERR_SIRQ_E016MSG	"Parity error MAC 1"
+#define SKERR_SIRQ_E017		(SKERR_SIRQ_E016+1)
+#define SKERR_SIRQ_E017MSG	"Parity error MAC 2"
+#define SKERR_SIRQ_E018		(SKERR_SIRQ_E017+1)
+#define SKERR_SIRQ_E018MSG	"Parity error RX 1"
+#define SKERR_SIRQ_E019		(SKERR_SIRQ_E018+1)
+#define SKERR_SIRQ_E019MSG	"Parity error RX 2"
+#define SKERR_SIRQ_E020		(SKERR_SIRQ_E019+1)
+#define SKERR_SIRQ_E020MSG	"MAC transmit FIFO underrun"
+#define SKERR_SIRQ_E021		(SKERR_SIRQ_E020+1)
+#define SKERR_SIRQ_E021MSG	"Spurious TWSI interrupt"
+#define SKERR_SIRQ_E022		(SKERR_SIRQ_E021+1)
+#define SKERR_SIRQ_E022MSG	"Cable pair swap error"
+#define SKERR_SIRQ_E023		(SKERR_SIRQ_E022+1)
+#define SKERR_SIRQ_E023MSG	"Auto-negotiation error"
+#define SKERR_SIRQ_E024		(SKERR_SIRQ_E023+1)
+#define SKERR_SIRQ_E024MSG	"FIFO overflow error"
 
 extern void SkGeSirqIsr(SK_AC *pAC, SK_IOC IoC, SK_U32 Istatus);
 extern int  SkGeSirqEvent(SK_AC *pAC, SK_IOC IoC, SK_U32 Event, SK_EVPARA Para);
-extern void SkXmInitPhy( SK_AC *pAC, SK_IOC IoC, int Port, SK_BOOL DoLoop);
-extern int  SkXmRxTxEnable(SK_AC *pAC, SK_IOC IoC, int Port);
 extern void SkHWLinkUp(SK_AC *pAC, SK_IOC IoC, int Port);
 extern void SkHWLinkDown(SK_AC *pAC, SK_IOC IoC, int Port);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sk98lin/h/ski2c.h linux-2.4.21-pre6/drivers/net/sk98lin/h/ski2c.h
--- linux-2.4.20/drivers/net/sk98lin/h/ski2c.h	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sk98lin/h/ski2c.h	2003-03-26 23:49:21.000000000 +0000
@@ -2,8 +2,8 @@
  *
  * Name:	ski2c.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.30 $
- * Date:	$Date: 2001/04/05 11:38:09 $
+ * Version:	$Revision: 1.33 $
+ * Date:	$Date: 2002/10/14 16:40:50 $
  * Purpose:	Defines to access Voltage and Temperature Sensor
  *		(taken from Monalisa (taken from Concentrator))
  *
@@ -28,6 +28,15 @@
  * History:
  *
  *	$Log: ski2c.h,v $
+ *	Revision 1.33  2002/10/14 16:40:50  rschmidt
+ *	Editorial changes (TWSI)
+ *	
+ *	Revision 1.32  2002/08/13 08:55:07  rschmidt
+ *	Editorial changes
+ *	
+ *	Revision 1.31  2002/08/06 09:44:22  jschmalz
+ *	Extensions and changes for Yukon
+ *	
  *	Revision 1.30  2001/04/05 11:38:09  rassmann
  *	Set SenState to idle in SkI2cWaitIrq().
  *	Changed error message in SkI2cWaitIrq().
@@ -142,127 +151,131 @@
 #include "h/skgei2c.h"
 
 /*
- * Define the I2c events.
+ * Define the I2C events.
  */
 #define SK_I2CEV_IRQ	1	/* IRQ happened Event */
 #define SK_I2CEV_TIM	2	/* Timeout event */
-#define SK_I2CEV_CLEAR	3	/* Clear Mib Values */
+#define SK_I2CEV_CLEAR	3	/* Clear MIB Values */
 
 /*
  * Define READ and WRITE Constants.
  */
-#define	I2C_READ	0
-#define	I2C_WRITE	1
+#define I2C_READ	0
+#define I2C_WRITE	1
 #define I2C_BURST	1
 #define I2C_SIGLE	0
 
-#define	SKERR_I2C_E001		(SK_ERRBASE_I2C+0)
-#define	SKERR_I2C_E001MSG	"Sensor index unknown"
-#define	SKERR_I2C_E002		(SKERR_I2C_E001+1)
-#define	SKERR_I2C_E002MSG	"I2C: transfer does not complete.\n"
-#define	SKERR_I2C_E003		(SKERR_I2C_E002+1)
-#define	SKERR_I2C_E003MSG	"lm80: NAK on device send.\n"
-#define	SKERR_I2C_E004		(SKERR_I2C_E003+1)
-#define	SKERR_I2C_E004MSG	"lm80: NAK on register send.\n"
-#define	SKERR_I2C_E005		(SKERR_I2C_E004+1)
-#define	SKERR_I2C_E005MSG	"lm80: NAK on device (2) send.\n"
-#define	SKERR_I2C_E006		(SKERR_I2C_E005+1)
-#define	SKERR_I2C_E006MSG	"Unknown event"
-#define	SKERR_I2C_E007		(SKERR_I2C_E006+1)
-#define	SKERR_I2C_E007MSG	"LM80 read out of state"
-#define	SKERR_I2C_E008		(SKERR_I2C_E007+1)
-#define	SKERR_I2C_E008MSG	"unexpected sensor read completed"
-#define	SKERR_I2C_E009		(SKERR_I2C_E008+1)
-#define	SKERR_I2C_E009MSG	"WARNING: temperature sensor out of range"
-#define	SKERR_I2C_E010		(SKERR_I2C_E009+1)
-#define	SKERR_I2C_E010MSG	"WARNING: voltage sensor out of range"
-#define	SKERR_I2C_E011		(SKERR_I2C_E010+1)
-#define	SKERR_I2C_E011MSG	"ERROR: temperature sensor out of range"
-#define	SKERR_I2C_E012		(SKERR_I2C_E011+1)
-#define	SKERR_I2C_E012MSG	"ERROR: voltage sensor out of range"
-#define	SKERR_I2C_E013		(SKERR_I2C_E012+1)
-#define	SKERR_I2C_E013MSG	"ERROR: couldn't init sensor"
-#define	SKERR_I2C_E014		(SKERR_I2C_E013+1)
-#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 SKERR_I2C_E001		(SK_ERRBASE_I2C+0)
+#define SKERR_I2C_E001MSG	"Sensor index unknown"
+#define SKERR_I2C_E002		(SKERR_I2C_E001+1)
+#define SKERR_I2C_E002MSG	"TWSI: transfer does not complete"
+#define SKERR_I2C_E003		(SKERR_I2C_E002+1)
+#define SKERR_I2C_E003MSG	"LM80: NAK on device send"
+#define SKERR_I2C_E004		(SKERR_I2C_E003+1)
+#define SKERR_I2C_E004MSG	"LM80: NAK on register send"
+#define SKERR_I2C_E005		(SKERR_I2C_E004+1)
+#define SKERR_I2C_E005MSG	"LM80: NAK on device (2) send"
+#define SKERR_I2C_E006		(SKERR_I2C_E005+1)
+#define SKERR_I2C_E006MSG	"Unknown event"
+#define SKERR_I2C_E007		(SKERR_I2C_E006+1)
+#define SKERR_I2C_E007MSG	"LM80 read out of state"
+#define SKERR_I2C_E008		(SKERR_I2C_E007+1)
+#define SKERR_I2C_E008MSG	"Unexpected sensor read completed"
+#define SKERR_I2C_E009		(SKERR_I2C_E008+1)
+#define SKERR_I2C_E009MSG	"WARNING: temperature sensor out of range"
+#define SKERR_I2C_E010		(SKERR_I2C_E009+1)
+#define SKERR_I2C_E010MSG	"WARNING: voltage sensor out of range"
+#define SKERR_I2C_E011		(SKERR_I2C_E010+1)
+#define SKERR_I2C_E011MSG	"ERROR: temperature sensor out of range"
+#define SKERR_I2C_E012		(SKERR_I2C_E011+1)
+#define SKERR_I2C_E012MSG	"ERROR: voltage sensor out of range"
+#define SKERR_I2C_E013		(SKERR_I2C_E012+1)
+#define SKERR_I2C_E013MSG	"ERROR: couldn't init sensor"
+#define SKERR_I2C_E014		(SKERR_I2C_E013+1)
+#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	"TWSI: active transfer does not complete"
 
 /*
  * Define Timeout values
  */
-#define	SK_I2C_TIM_LONG		2000000L	/* 2 seconds */
-#define	SK_I2C_TIM_SHORT	 100000L	/* 100 milliseconds */
+#define SK_I2C_TIM_LONG		2000000L	/* 2 seconds */
+#define SK_I2C_TIM_SHORT	 100000L	/* 100 milliseconds */
+#define SK_I2C_TIM_WATCH	1000000L	/* 1 second */
 
 /*
  * 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)
+#define SK_SEN_WARN_LOG_HOLD	(15*60*SK_TICKS_PER_SEC)
 #endif
 
 /*
  * Defines for SenType
  */
-#define	SK_SEN_TEMP	1
-#define	SK_SEN_VOLT	2
-#define	SK_SEN_FAN	3
+#define SK_SEN_UNKNOWN	0
+#define SK_SEN_TEMP		1
+#define SK_SEN_VOLT		2
+#define SK_SEN_FAN		3
 
 /*
- * Define for the ErrorFlag
+ * Define for the SenErrorFlag
  */
-#define	SK_SEN_ERR_OK	1	/* Error Flag: O.K. */
-#define	SK_SEN_ERR_WARN	2	/* Error Flag: Warning */
-#define	SK_SEN_ERR_ERR	3	/* Error Flag: Error */
+#define SK_SEN_ERR_NOT_PRESENT	0	/* Error Flag: Sensor not present */
+#define SK_SEN_ERR_OK			1	/* Error Flag: O.K. */
+#define SK_SEN_ERR_WARN			2	/* Error Flag: Warning */
+#define SK_SEN_ERR_ERR			3	/* Error Flag: Error */
+#define SK_SEN_ERR_FAULTY		4	/* Error Flag: Faulty */
 
 /*
  * Define the Sensor struct
  */
 struct	s_Sensor {
-	char	*SenDesc;	/* Description */
-	int	SenType;	/* Voltage or Temperature */
-	SK_I32	SenValue;	/* Current value of the sensor */
-	SK_I32	SenThreErrHigh;	/* High error Threshhold of this sensor */
-	SK_I32	SenThreWarnHigh;/* High warning Threshhold of this sensor */
-	SK_I32	SenThreErrLow;	/* Lower error Threshold of the sensor */
-	SK_I32	SenThreWarnLow;	/* Lower warning Threshold of the sensor */
-	int	SenErrFlag;	/* Sensor indicated an error */
-	SK_BOOL	SenInit;	/* Is sensor initialized? */
-	SK_U64	SenErrCts;	/* Error  trap counter */
-	SK_U64	SenWarnCts;	/* Warning trap  counter */
-	SK_U64	SenBegErrTS;	/* Begin error timestamp */
-	SK_U64	SenBegWarnTS;	/* Begin warning timestamp */
+	char	*SenDesc;			/* Description */
+	int		SenType;			/* Voltage or Temperature */
+	SK_I32	SenValue;			/* Current value of the sensor */
+	SK_I32	SenThreErrHigh;		/* High error Threshhold of this sensor */
+	SK_I32	SenThreWarnHigh;	/* High warning Threshhold of this sensor */
+	SK_I32	SenThreErrLow;		/* Lower error Threshold of the sensor */
+	SK_I32	SenThreWarnLow;		/* Lower warning Threshold of the sensor */
+	int		SenErrFlag;			/* Sensor indicated an error */
+	SK_BOOL	SenInit;			/* Is sensor initialized ? */
+	SK_U64	SenErrCts;			/* Error  trap counter */
+	SK_U64	SenWarnCts;			/* Warning trap counter */
+	SK_U64	SenBegErrTS;		/* Begin error timestamp */
+	SK_U64	SenBegWarnTS;		/* Begin warning timestamp */
 	SK_U64	SenLastErrTrapTS;	/* Last error trap timestamp */
 	SK_U64	SenLastErrLogTS;	/* Last error log timestamp */
 	SK_U64	SenLastWarnTrapTS;	/* Last warning trap timestamp */
 	SK_U64	SenLastWarnLogTS;	/* Last warning log timestamp */
-	int	SenState;	/* Sensor State (see HW specific include) */
-	int	(*SenRead)(SK_AC *pAC, SK_IOC IoC,struct s_Sensor *pSen) ;
-				/* Sensors read function */
-	SK_U16	SenReg;		/* Register Address for this sensor */
-	SK_U8	SenDev;		/* DeviceSelection for this sensor */
-} ;
-
+	int		SenState;			/* Sensor State (see HW specific include) */
+	int		(*SenRead)(SK_AC *pAC, SK_IOC IoC, struct s_Sensor *pSen);
+								/* Sensors read function */
+	SK_U16	SenReg;				/* Register Address for this sensor */
+	SK_U8	SenDev;				/* Device Selection for this sensor */
+};
 
 typedef	struct	s_I2c {
 	SK_SENSOR	SenTable[SK_MAX_SENSORS];	/* Sensor Table */
-	int		CurrSens;	/* Which sensor is currently queried */
-	int		MaxSens;	/* Max. number of sensors */
-	int		InitLevel;	/* Initialized Level */
+	int			CurrSens;	/* Which sensor is currently queried */
+	int			MaxSens;	/* Max. number of sensors */
+	int			TimerMode;	/* Use the timer also to watch the state machine */
+	int			InitLevel;	/* Initialized Level */
 #ifndef SK_DIAG
-	int		DummyReads;	/* Number of non-checked dummy reads */
+	int			DummyReads;	/* Number of non-checked dummy reads */
 	SK_TIMER	SenTimer;	/* Sensors timer */
-#endif	/* !SK_DIAG */
+#endif /* !SK_DIAG */
 } SK_I2C;
 
 extern int SkI2cReadSensor(SK_AC *pAC, SK_IOC IoC, SK_SENSOR *pSen);
@@ -273,5 +286,5 @@
 extern void SkI2cIsr(SK_AC *pAC, SK_IOC IoC);
 
 #endif
-#endif	/* n_SKI2C_H */
+#endif /* n_SKI2C_H */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sk98lin/h/skqueue.h linux-2.4.21-pre6/drivers/net/sk98lin/h/skqueue.h
--- linux-2.4.20/drivers/net/sk98lin/h/skqueue.h	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sk98lin/h/skqueue.h	2003-03-26 23:49:55.000000000 +0000
@@ -1,32 +1,23 @@
 /******************************************************************************
  *
  * Name:	skqueue.h
- * Project:	Genesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.12 $
- * Date:	$Date: 1998/09/08 08:48:01 $
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.14 $
+ * Date:	$Date: 2002/03/15 10:52:13 $
  * Purpose:	Defines for the Event queue
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1989-1998 SysKonnect,
+ *	(C)Copyright 1998,1999 SysKonnect,
  *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
- *	All Rights Reserved
  *
- *	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.
+ *	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.
  *
  ******************************************************************************/
@@ -36,6 +27,12 @@
  * History:
  *
  *	$Log: skqueue.h,v $
+ *	Revision 1.14  2002/03/15 10:52:13  mkunz
+ *	Added event classes for link aggregation
+ *	
+ *	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
  *	
@@ -97,6 +94,12 @@
 #define	SKGE_CSUM	5	/* Checksum Event Class */
 #define	SKGE_HWAC	6	/* Hardware Access Event Class */
 
+#define	SKGE_SWT	9	/* Software Timer Event Class */
+#define	SKGE_LACP	10	/* LACP Aggregation Event Class */
+#define	SKGE_RSF	11	/* RSF Aggregation Event Class */
+#define	SKGE_MARKER	12	/* MARKER Aggregation Event Class */
+#define	SKGE_FD		13	/* FD Distributor Event Class */
+
 /*
  * define event queue as circular buffer
  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sk98lin/h/skrlmt.h linux-2.4.21-pre6/drivers/net/sk98lin/h/skrlmt.h
--- linux-2.4.20/drivers/net/sk98lin/h/skrlmt.h	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sk98lin/h/skrlmt.h	2003-03-26 23:49:39.000000000 +0000
@@ -2,8 +2,8 @@
  *
  * Name:	skrlmt.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.32 $
- * Date:	$Date: 2001/02/14 14:06:31 $
+ * Version:	$Revision: 1.33 $
+ * Date:	$Date: 2001/07/03 12:16:48 $
  * Purpose:	Header file for Redundant Link ManagemenT.
  *
  ******************************************************************************/
@@ -26,6 +26,9 @@
  * History:
  *
  *	$Log: skrlmt.h,v $
+ *	Revision 1.33  2001/07/03 12:16:48  mkunz
+ *	New Flag ChgBcPrio (Change priority of last broadcast received)
+ *	
  *	Revision 1.32  2001/02/14 14:06:31  rassmann
  *	Editorial changes.
  *	
@@ -468,6 +471,7 @@
 
 	/* For PNMI */
 
+	SK_U32			ChgBcPrio;			/* Change Priority of last broadcast received */
 	SK_U32			RlmtMode;			/* Check ... */
 	SK_U32			ActivePort;			/* Active port. */
 	SK_U32			Preference;		/* 0xFFFFFFFF: Automatic. */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sk98lin/h/sktimer.h linux-2.4.21-pre6/drivers/net/sk98lin/h/sktimer.h
--- linux-2.4.20/drivers/net/sk98lin/h/sktimer.h	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sk98lin/h/sktimer.h	2003-03-26 23:49:09.000000000 +0000
@@ -1,32 +1,23 @@
 /******************************************************************************
  *
  * Name:	sktimer.h
- * Project:	Genesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.8 $
- * Date:	$Date: 1998/09/08 08:48:02 $
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.9 $
+ * Date:	$Date: 1999/11/22 14:00:29 $
  * Purpose:	Defines for the timer functions
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1989-1998 SysKonnect,
+ *	(C)Copyright 1998,1999 SysKonnect,
  *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
- *	All Rights Reserved
  *
- *	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.
+ *	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.
  *
  ******************************************************************************/
@@ -36,6 +27,9 @@
  * 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 -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sk98lin/h/skversion.h linux-2.4.21-pre6/drivers/net/sk98lin/h/skversion.h
--- linux-2.4.20/drivers/net/sk98lin/h/skversion.h	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sk98lin/h/skversion.h	2003-03-26 23:48:58.000000000 +0000
@@ -2,15 +2,15 @@
  *
  * Name:	version.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.1 $
- * Date:	$Date: 2001/03/06 09:25:00 $
+ * Version:	$Revision: 1.1.2.1 $
+ * Date:	$Date: 2001/09/05 13:38:30 $
  * Purpose:	SK specific Error log support
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998,1999 SysKonnect,
+ *	(C)Copyright 1998-2002 SysKonnect,
  *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
  *
  *	This program is free software; you can redistribute it and/or modify
@@ -26,6 +26,9 @@
  *
  * History:
  *	$Log: skversion.h,v $
+ *	Revision 1.1.2.1  2001/09/05 13:38:30  mlindner
+ *	Removed FILE description
+ *	
  *	Revision 1.1  2001/03/06 09:25:00  mlindner
  *	first version
  *	
@@ -34,13 +37,13 @@
  ******************************************************************************/
  
  
-static const char SysKonnectFileId[] = "@(#)" __FILE__ " (C) SysKonnect GmbH.";
+static const char SysKonnectFileId[] = "@(#) (C) SysKonnect GmbH.";
 static const char SysKonnectBuildNumber[] =
-	"@(#)SK-BUILD: 4.06 PL: 01"; 
+	"@(#)SK-BUILD: 6.02 PL: 01"; 
 
-#define BOOT_STRING	"sk98lin: Network Device Driver v4.06\n" \
-			"Copyright (C) 2000-2001 SysKonnect GmbH."
+#define BOOT_STRING	"sk98lin: Network Device Driver v6.02\n" \
+			"Copyright (C) 2000-2002 SysKonnect GmbH."
 
-#define VER_STRING	"4.06"
+#define VER_STRING	"6.02"
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sk98lin/h/skvpd.h linux-2.4.21-pre6/drivers/net/sk98lin/h/skvpd.h
--- linux-2.4.20/drivers/net/sk98lin/h/skvpd.h	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sk98lin/h/skvpd.h	2003-03-26 23:49:25.000000000 +0000
@@ -2,16 +2,15 @@
  *
  * Name:	skvpd.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.9 $
- * Date:	$Date: 1999/11/22 14:02:27 $
+ * Version:	$Revision: 1.13 $
+ * Date:	$Date: 2002/10/14 15:58:18 $
  * Purpose:	Defines and Macros for VPD handling
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998,1999 SysKonnect,
- *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *	(C)Copyright 1998-2002 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: skvpd.h,v $
+ *	Revision 1.13  2002/10/14 15:58:18  rschmidt
+ *	Added entry in rom_size struct s_vpd
+ *	Editorial changes
+ *	
+ *	Revision 1.12  2002/09/09 14:43:51  mkarl
+ *	added PCI Id of Yukon for reading VPD in diag before the adapter has
+ *	been initialized
+ *	editorial changes
+ *	
+ *	Revision 1.11  2002/07/26 13:19:16  mkarl
+ *	added support for Yukon
+ *	added vpd_size to VPD struct
+ *	
+ *	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.
  *	
@@ -99,7 +117,12 @@
 /*
  * Define READ and WRITE Constants.
  */
-#define	VPD_SIZE	512
+
+#define VPD_PCI_ID_YUKON 	0x4320
+
+#define	VPD_SIZE_YUKON		256
+#define	VPD_SIZE_GENESIS	512
+#define	VPD_SIZE			512
 #define VPD_READ	0x0000
 #define VPD_WRITE	0x8000
 
@@ -115,40 +138,44 @@
 
 /* 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	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	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 */
 } 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 */
+	int				rom_size;			/* VPD ROM Size from PCI_OUR_REG_2 */
+	int				vpd_size;			/* saved VPD-size */
 } 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
+ * structure 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;
 
 
@@ -172,39 +199,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);		\
 		}
@@ -213,50 +240,52 @@
 /* function prototypes ********************************************************/
 
 #ifndef	SK_KR_PROTO
+#ifdef SKDIAG
 extern SK_U32	VpdReadDWord(
 	SK_AC		*pAC,
 	SK_IOC		IoC,
-	int		addr) ;
+	int			addr);
+#endif	/* SKDIAG */
 
 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) ;
+extern SK_BOOL	VpdMayWrite(
+	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,
@@ -265,34 +294,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 -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sk98lin/h/xmac_ii.h linux-2.4.21-pre6/drivers/net/sk98lin/h/xmac_ii.h
--- linux-2.4.20/drivers/net/sk98lin/h/xmac_ii.h	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sk98lin/h/xmac_ii.h	2003-03-26 23:49:53.000000000 +0000
@@ -2,15 +2,15 @@
  *
  * Name:	xmac_ii.h
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.28 $
- * Date:	$Date: 2000/11/09 12:32:49 $
- * Purpose:	Defines and Macros for XaQti's Gigabit Ethernet Controller
+ * Version:	$Revision: 1.45 $
+ * Date:	$Date: 2002/12/10 14:35:13 $
+ * Purpose:	Defines and Macros for Gigabit Ethernet Controller
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998-2000 SysKonnect GmbH.
+ *	(C)Copyright 1998-2002 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 +26,77 @@
  * History:
  *
  *	$Log: xmac_ii.h,v $
+ *	Revision 1.45  2002/12/10 14:35:13  rschmidt
+ *	Corrected defines for Extended PHY Specific Control
+ *	Added defines for Ext. PHY Specific Ctrl 2 Reg. (Fiber specific)
+ *	
+ *	Revision 1.44  2002/12/09 14:58:41  rschmidt
+ *	Added defines for Ext. PHY Specific Ctrl Reg. (downshift feature)
+ *	Added 'GMR_FS_UN_SIZE'-Bit to Rx GMAC FIFO Flush Mask
+ *	
+ *	Revision 1.43  2002/12/05 10:14:45  rschmidt
+ *	Added define for GMAC's Half Duplex Burst Mode
+ *	Added define for Rx GMAC FIFO Flush Mask (default)
+ *	
+ *	Revision 1.42  2002/11/12 16:48:19  rschmidt
+ *	Added defines for Cable Diagnostic Register (GPHY)
+ *	Editorial changes
+ *	
+ *	Revision 1.41  2002/10/21 11:20:22  rschmidt
+ *	Added bit GMR_FS_GOOD_FC to GMR_FS_ANY_ERR
+ *	Editorial changes
+ *	
+ *	Revision 1.40  2002/10/14 14:54:14  rschmidt
+ *	Added defines for GPHY Specific Status and GPHY Interrupt Status
+ *	Added bits PHY_M_IS_AN_ERROR and PHY_M_IS_FIFO_ERROR to PHY_M_DEF_MSK
+ *	Editorial changes
+ *	
+ *	Revision 1.39  2002/10/10 15:53:44  mkarl
+ *	added some bit definitions for link speed status and LED's
+ *	
+ *	Revision 1.38  2002/08/21 16:23:46  rschmidt
+ *	Added defines for PHY Specific Ctrl Reg
+ *	Editorial changes
+ *	
+ *	Revision 1.37  2002/08/16 14:50:33  rschmidt
+ *	Added defines for Auto-Neg. Advertisement YUKON Fiber (88E1011S only)
+ *	Changed define PHY_M_DEF_MSK for GPHY IRQ Mask
+ *	Editorial changes
+ *	
+ *	Revision 1.36  2002/08/12 13:21:10  rschmidt
+ *	Added defines for different Broadcom PHY Ids
+ *	
+ *	Revision 1.35  2002/08/08 15:58:01  rschmidt
+ *	Added defines for Manual LED Override register (YUKON)
+ *	Editorial changes
+ *	
+ *	Revision 1.34  2002/07/31 17:23:36  rwahl
+ *	Added define GMR_FS_ANY_ERR (analogous to XMR_FS_ANY_ERR).
+ *	
+ *	Revision 1.33  2002/07/23 16:03:37  rschmidt
+ *	Added defines for GPHY registers
+ *	Editorial changes
+ *	
+ *	Revision 1.32  2002/07/15 18:14:37  rwahl
+ *	Added GMAC MIB counters definitions.
+ *	Editorial changes.
+ *	
+ *	Revision 1.31  2002/07/15 15:42:50  rschmidt
+ *	Removed defines from PHY specific reg. which are
+ *	common to all PHYs
+ *	Added defines for GMAC MIB Counters
+ *	Editorial changes
+ *	
+ *	Revision 1.30  2002/06/05 08:22:12  rschmidt
+ *	Changed defines for GMAC Rx Control Register and Rx Status
+ *	Editorial changes
+ *	
+ *	Revision 1.29  2002/04/25 11:43:56  rschmidt
+ *	Added define PHY_B_AS_PAUSE_MSK for BCom Pause Res.
+ *	Added new registers and defines for YUKON (GMAC, GPHY)
+ *	Added Receive Frame Status Encoding for YUKON
+ *	Editorial changes
+ *	
  *	Revision 1.28  2000/11/09 12:32:49  rassmann
  *	Renamed variables.
  *	
@@ -82,7 +153,7 @@
  *	Changed shifted constant to ULONG.
  *
  *	Revision 1.11  1998/10/14 05:43:26  gklug
- *	add: shift pause codeing
+ *	add: shift pause coding
  *	fix: PAUSE bits definition
  *
  *	Revision 1.10  1998/10/13 09:19:21  malthoff
@@ -135,61 +206,61 @@
 /*
  * XMAC II registers
  *
- * The XMAC registers are 16 or 32 bits wide. The XMACs host processor
- * interface is set to 16 bit mode, therefore ALL registers will be
- * addressed with 16 bit accesses.
+ * The XMAC registers are 16 or 32 bits wide.
+ * The XMACs host processor interface is set to 16 bit mode,
+ * therefore ALL registers will be addressed with 16 bit accesses.
  *
  * The following macros are provided to access the XMAC registers
- * XM_IN16(), XM_OUT16, XM_IN32(), MX_OUT32(), XM_INADR(), XM_OUTADR(),
+ * XM_IN16(), XM_OUT16, XM_IN32(), XM_OUT32(), XM_INADR(), XM_OUTADR(),
  * XM_INHASH(), and XM_OUTHASH().
  * The macros are defined in SkGeHw.h.
  *
  * 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_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_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 */
 	/* 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 r/o	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 r/o	Tx Status LIFO Register */
 
-	/* 0x0080 - 0x00fc:	16 NA reg r/w	Exakt Match Address Registers */
-	/* 				use the XM_EMX() macro to address */
+	/* 0x0080 - 0x00fc:	16 NA reg r/w	Exact Match Address Registers */
+	/* 				use the XM_EXM() macro to address */
 #define XM_EXM_START	0x0080	/* r/w	Start Address of the EXM Regs */
 
 	/*
 	 * XM_EXM(Reg)
 	 *
-	 * returns the XMAC address offset off specified Exakt Match Addr Reg
+	 * returns the XMAC address offset of specified Exact Match Addr Reg
 	 *
 	 * para:	Reg	EXM register to addr	(0 .. 15)
 	 *
-	 * usage:	XM_INADDR(XMAC_1,pAC,XM_EXM(i),&val[i]) ;
+	 * usage:	XM_INADDR(IoC, MAC_1, XM_EXM(i), &val[i]);
 	 */
 #define XM_EXM(Reg)	(XM_EXM_START + ((Reg) << 3))
 
@@ -199,78 +270,78 @@
 #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_DEV_ID		0x0120	/* 32 bit r/o	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_LSA			0x0128	/* NA reg r/o	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 r/o	Time Stamp Read Register */
+#define XM_TS_LOAD		0x0134	/* 32 bit r/o	Time Stamp 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 */
-#define XM_TX_CNT_EV	0x0208	/* 32 bit ro	Tx Counter Event Register */
+#define XM_RX_CNT_EV	0x0204	/* 32 bit r/o	Rx Counter Event Register */
+#define XM_TX_CNT_EV	0x0208	/* 32 bit r/o	Tx Counter Event Register */
 #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_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_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 */
-#define XM_TXF_SNG_COL	0x02a8	/* 32 bit ro	Tx Single Colliosion Counter */
-#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_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_TXF_OK		0x0280	/* 32 bit r/o	Frames Transmitted OK Conuter */
+#define XM_TXO_OK_HI	0x0284	/* 32 bit r/o	Octets Transmitted OK High Cnt*/
+#define XM_TXO_OK_LO	0x0288	/* 32 bit r/o	Octets Transmitted OK Low Cnt */
+#define XM_TXF_BC_OK	0x028c	/* 32 bit r/o	Broadcast Frames Xmitted OK */
+#define XM_TXF_MC_OK	0x0290	/* 32 bit r/o	Multicast Frames Xmitted OK */
+#define XM_TXF_UC_OK	0x0294	/* 32 bit r/o	Unicast Frames Xmitted OK */
+#define XM_TXF_LONG		0x0298	/* 32 bit r/o	Tx Long Frame Counter */
+#define XM_TXE_BURST	0x029c	/* 32 bit r/o	Tx Burst Event Counter */
+#define XM_TXF_MPAUSE	0x02a0	/* 32 bit r/o	Tx Pause MAC Ctrl Frame Cnt */
+#define XM_TXF_MCTRL	0x02a4	/* 32 bit r/o	Tx MAC Ctrl Frame Counter */
+#define XM_TXF_SNG_COL	0x02a8	/* 32 bit r/o	Tx Single Collision Counter */
+#define XM_TXF_MUL_COL	0x02ac	/* 32 bit r/o	Tx Multiple Collision Counter */
+#define XM_TXF_ABO_COL	0x02b0	/* 32 bit r/o	Tx aborted due to Exces. Col. */
+#define XM_TXF_LAT_COL	0x02b4	/* 32 bit r/o	Tx Late Collision Counter */
+#define XM_TXF_DEF		0x02b8	/* 32 bit r/o	Tx Deferred Frame Counter */
+#define XM_TXF_EX_DEF	0x02bc	/* 32 bit r/o	Tx Excessive Deferall Counter */
+#define XM_TXE_FIFO_UR	0x02c0	/* 32 bit r/o	Tx FIFO Underrun Event Cnt */
+#define XM_TXE_CS_ERR	0x02c4	/* 32 bit r/o	Tx Carrier Sense Error Cnt */
+#define XM_TXP_UTIL		0x02c8	/* 32 bit r/o	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_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*/
+#define XM_TXF_64B		0x02d0	/* 32 bit r/o	64 Byte Tx Frame Counter */
+#define XM_TXF_127B		0x02d4	/* 32 bit r/o	65-127 Byte Tx Frame Counter */
+#define XM_TXF_255B		0x02d8	/* 32 bit r/o	128-255 Byte Tx Frame Counter */
+#define XM_TXF_511B		0x02dc	/* 32 bit r/o	256-511 Byte Tx Frame Counter */
+#define XM_TXF_1023B	0x02e0	/* 32 bit r/o	512-1023 Byte Tx Frame Counter*/
+#define XM_TXF_MAX_SZ	0x02e4	/* 32 bit r/o	1024-MaxSize Byte Tx Frame Cnt*/
 	/* 0x02e8 - 0x02fe:	reserved */
-#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 */
-#define XM_RXF_MC_OK	0x0310	/* 32 bit ro	Multicast Frames Received OK */
-#define XM_RXF_UC_OK	0x0314	/* 32 bit ro	Unicast Frames Received OK */
-#define XM_RXF_MPAUSE	0x0318	/* 32 bit ro	Rx Pause MAC Ctrl Frame Cnt */
-#define XM_RXF_MCTRL	0x031c	/* 32 bit ro	Rx MAC Ctrl Frame Counter */
-#define XM_RXF_INV_MP	0x0320	/* 32 bit ro	Rx invalid Pause Frame Cnt */
-#define XM_RXF_INV_MOC	0x0324	/* 32 bit ro	Rx Frames with inv. MAC Opcode*/
-#define XM_RXE_BURST	0x0328	/* 32 bit ro	Rx Burst Event Counter */
-#define XM_RXE_FMISS	0x032c	/* 32 bit ro	Rx Missed Frames Event Cnt */
-#define XM_RXF_FRA_ERR	0x0330	/* 32 bit ro	Rx Framing Error Counter */
-#define XM_RXE_FIFO_OV	0x0334	/* 32 bit ro	Rx FIFO overflow Event Cnt */
-#define XM_RXF_JAB_PKT	0x0338	/* 32 bit ro	Rx Jabber Packet Frame Cnt */
-#define XM_RXE_CAR_ERR	0x033c	/* 32 bit ro	Rx Carrier Event Error Cnt */
-#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_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 */
+#define XM_RXF_OK		0x0300	/* 32 bit r/o	Frames Received OK */
+#define XM_RXO_OK_HI	0x0304	/* 32 bit r/o	Octets Received OK High Cnt */
+#define XM_RXO_OK_LO	0x0308	/* 32 bit r/o	Octets Received OK Low Counter*/
+#define XM_RXF_BC_OK	0x030c	/* 32 bit r/o	Broadcast Frames Received OK */
+#define XM_RXF_MC_OK	0x0310	/* 32 bit r/o	Multicast Frames Received OK */
+#define XM_RXF_UC_OK	0x0314	/* 32 bit r/o	Unicast Frames Received OK */
+#define XM_RXF_MPAUSE	0x0318	/* 32 bit r/o	Rx Pause MAC Ctrl Frame Cnt */
+#define XM_RXF_MCTRL	0x031c	/* 32 bit r/o	Rx MAC Ctrl Frame Counter */
+#define XM_RXF_INV_MP	0x0320	/* 32 bit r/o	Rx invalid Pause Frame Cnt */
+#define XM_RXF_INV_MOC	0x0324	/* 32 bit r/o	Rx Frames with inv. MAC Opcode*/
+#define XM_RXE_BURST	0x0328	/* 32 bit r/o	Rx Burst Event Counter */
+#define XM_RXE_FMISS	0x032c	/* 32 bit r/o	Rx Missed Frames Event Cnt */
+#define XM_RXF_FRA_ERR	0x0330	/* 32 bit r/o	Rx Framing Error Counter */
+#define XM_RXE_FIFO_OV	0x0334	/* 32 bit r/o	Rx FIFO overflow Event Cnt */
+#define XM_RXF_JAB_PKT	0x0338	/* 32 bit r/o	Rx Jabber Packet Frame Cnt */
+#define XM_RXE_CAR_ERR	0x033c	/* 32 bit r/o	Rx Carrier Event Error Cnt */
+#define XM_RXF_LEN_ERR	0x0340	/* 32 bit r/o	Rx in Range Length Error */
+#define XM_RXE_SYM_ERR	0x0344	/* 32 bit r/o	Rx Symbol Error Counter */
+#define XM_RXE_SHT_ERR	0x0348	/* 32 bit r/o	Rx Short Event Error Cnt */
+#define XM_RXE_RUNT		0x034c	/* 32 bit r/o	Rx Runt Event Counter */
+#define XM_RXF_LNG_ERR	0x0350	/* 32 bit r/o	Rx Frame too Long Error Cnt */
+#define XM_RXF_FCS_ERR	0x0354	/* 32 bit r/o	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_RXF_CEX_ERR	0x035c	/* 32 bit r/o	Rx Carrier Ext Error Frame Cnt*/
+#define XM_RXP_UTIL		0x0360	/* 32 bit r/o	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_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*/
+#define XM_RXF_64B		0x0368	/* 32 bit r/o	64 Byte Rx Frame Counter */
+#define XM_RXF_127B		0x036c	/* 32 bit r/o	65-127 Byte Rx Frame Counter */
+#define XM_RXF_255B		0x0370	/* 32 bit r/o	128-255 Byte Rx Frame Counter */
+#define XM_RXF_511B		0x0374	/* 32 bit r/o	256-511 Byte Rx Frame Counter */
+#define XM_RXF_1023B	0x0378	/* 32 bit r/o	512-1023 Byte Rx Frame Counter*/
+#define XM_RXF_MAX_SZ	0x037c	/* 32 bit r/o	1024-MaxSize Byte Rx Frame Cnt*/
 	/* 0x02e8 - 0x02fe:	reserved */
 
 
@@ -279,104 +350,104 @@
  * XMAC Bit Definitions
  *
  * If the bit access behaviour differs from the register access behaviour
- * (r/w, ro) this is docomented after the bit number. The following bit
- * access behaviours are used:
+ * (r/w, r/o) this is documented 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 */
+/*	XM_MMU_CMD	16 bit r/w	MMU Command Register */
 								/* 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 */
-#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 */
-#define XM_MMU_GMII_FD	(1<<4)	/* Bit	4:	GMII uses Full Duplex */
-#define XM_MMU_RAT_CTRL	(1<<3)	/* Bit	3:	Enable Rate Control */
-#define XM_MMU_GMII_LOOP (1<<2)	/* Bit	2:	PHY is in Lookback Mode */
-#define XM_MMU_ENA_RX	(1<<1)	/* Bit	1:	Enable Receiver */
-#define XM_MMU_ENA_TX	(1<<0)	/* Bit	0:	Enable Transmitter */
+#define XM_MMU_MAC_LB	(1<<9)	/* Bit  9:	Enable MAC Loopback */
+								/* 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 */
+#define XM_MMU_GMII_FD	(1<<4)	/* Bit  4:	GMII uses Full Duplex */
+#define XM_MMU_RAT_CTRL	(1<<3)	/* Bit  3:	Enable Rate Control */
+#define XM_MMU_GMII_LOOP (1<<2)	/* Bit  2:	PHY is in Loopback Mode */
+#define XM_MMU_ENA_RX	(1<<1)	/* Bit  1:	Enable Receiver */
+#define XM_MMU_ENA_TX	(1<<0)	/* Bit  0:	Enable Transmitter */
 
 
 /*	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)*/
-#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 */
-#define XM_TX_NO_PRE	(1<<2)	/* Bit	2:	Disable Preamble Generation */
-#define XM_TX_NO_CRC	(1<<1)	/* Bit	1:	Disable CRC Generation */
-#define XM_TX_AUTO_PAD	(1<<0)	/* Bit	0:	Enable Automatic Padding */
+#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 */
+#define XM_TX_NO_PRE	(1<<2)	/* Bit  2:	Disable Preamble Generation */
+#define XM_TX_NO_CRC	(1<<1)	/* Bit  1:	Disable CRC Generation */
+#define XM_TX_AUTO_PAD	(1<<0)	/* Bit  0:	Enable Automatic Padding */
 
 
 /*	XM_TX_RT_LIM	16 bit r/w	Transmit Retry Limit Register */
 								/* Bit 15..5:	reserved */
-#define	XM_RT_LIM_MSK	0x1f	/* Bit	4..0:	Tx Retry Limit */
+#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 */
-#define XM_STIME_MSK	0x7f	/* Bit	6..0:	Tx Slottime bits */
+#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 */
+#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 */
-#define XM_RX_LENERR_OK (1<<8)	/* Bit	8	don't set Rx Err bit for */
+#define XM_RX_LENERR_OK (1<<8)	/* Bit  8	don't set Rx Err bit for */
 								/*		inrange error packets */
-#define XM_RX_BIG_PK_OK	(1<<7)	/* Bit	7	don't set Rx Err bit for */
+#define XM_RX_BIG_PK_OK	(1<<7)	/* Bit  7	don't set Rx Err bit for */
 								/*		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_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 */
-#define XM_RX_STRIP_PAD	(1<<1)	/* Bit	1:	Strip pad bytes of rx frames */
-#define XM_RX_DIS_CEXT	(1<<0)	/* Bit	0:	Disable carrier ext. check */
+#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_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 */
+#define XM_RX_STRIP_PAD	(1<<1)	/* Bit  1:	Strip pad bytes of Rx frames */
+#define XM_RX_DIS_CEXT	(1<<0)	/* Bit  0:	Disable carrier ext. check */
 
 
 /*	XM_PHY_ADDR	16 bit r/w	PHY Address Register */
 								/* Bit 15..5:	reserved */
-#define	XM_PHY_ADDR_SZ	0x1f	/* Bit	4..0:	PHY Address bits */
+#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 */
-#define XM_GP_FRC_INT	(1L<<5)	/* Bit	5: (sc)	Force Interrupt */
-								/* 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 */
-#define XM_GP_INP_ASS	(1L<<0)	/* Bit	0: (ro) GP Input Pin asserted */
+#define XM_GP_ANIP		(1L<<6)	/* Bit  6: (ro)	Auto-Neg. in progress */
+#define XM_GP_FRC_INT	(1L<<5)	/* Bit  5: (sc)	Force Interrupt */
+								/* 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 */
+#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 */
+/*	XM_ISRC		16 bit r/o	Interrupt Status Register */
 								/* 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 */
 #define XM_IS_INP_ASS	(1<<11)	/* Bit 11:	Input Asserted, GP bit 0 set */
 #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_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 */
-#define XM_IS_RXF_OV	(1<<3)	/* Bit	3:	Receive FIFO Overflow */
-#define XM_IS_TXF_UR	(1<<2)	/* Bit	2:	Transmit FIFO Underrun */
-#define XM_IS_TX_COMP	(1<<1)	/* Bit	1:	Frame Tx Complete */
-#define XM_IS_RX_COMP	(1<<0)	/* Bit	0:	Frame Rx Complete */
+#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_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 */
+#define XM_IS_RXF_OV	(1<<3)	/* Bit  3:	Receive FIFO Overflow */
+#define XM_IS_TXF_UR	(1<<2)	/* Bit  2:	Transmit FIFO Underrun */
+#define XM_IS_TX_COMP	(1<<1)	/* Bit  1:	Frame Tx Complete */
+#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))
@@ -384,50 +455,50 @@
 
 /*	XM_HW_CFG	16 bit r/w	Hardware Config Register */
 								/* 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 */
-#define XM_HW_GMII_MD	(1<<0)	/* Bit	0:	GMII Interface selected */
+#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 */
+#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 */
-#define	XM_TX_WM_MSK	0x01ff	/* Bit	9.. 0	Tx FIFO Watermark bits */
+#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 */
+/*	XM_RX_THR	16 bit r/w	Rx Request Threshold */
 								/* Bit 15..11	reserved */
-#define	XM_THR_MSK		0x03ff	/* Bit 10.. 0	Tx FIFO Watermark bits */
+#define XM_THR_MSK		0x03ff	/* Bit 10.. 0	Rx/Tx Request Threshold bits */
 
 
-/*	XM_TX_STAT	32 bit ro	Tx Status LIFO Register */
+/*	XM_TX_STAT	32 bit r/o	Tx Status LIFO Register */
 #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 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 */
-#define XM_ST_SGN_COL	(1L<<0)		/* Bit	0:	Single Collision */
+#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 */
+#define XM_ST_SGN_COL	(1L<<0)		/* Bit  0:	Single Collision */
 
 /*	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 */
+#define XM_RX_WM_MSK	0x03ff		/* Bit 11.. 0:	Rx FIFO Watermark bits */
 
 
-/*	XM_DEV_ID	32 bit ro	Device ID Register */
-#define	XM_DEV_OUI	(0x00ffffffUL<<8)	/* Bit 31..8:	Device OUI */
-#define XM_DEV_REV	(0x07L << 5)		/* Bit	7..5:	Chip Rev Num */
+/*	XM_DEV_ID	32 bit r/o	Device ID Register */
+#define XM_DEV_OUI	(0x00ffffffUL<<8)	/* Bit 31..8:	Device OUI */
+#define XM_DEV_REV	(0x07L << 5)		/* Bit  7..5:	Chip Rev Num */
 
 
 /*	XM_MODE		32 bit r/w	Mode Register */
@@ -435,10 +506,10 @@
 #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 */
-#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*/
+#define XM_MD_TX_REP	(1L<<24)	/* Bit 24:	Transmit Repeater Mode */
+#define XM_MD_SPOFF_I	(1L<<23)	/* Bit 23:	Send Pause on FIFO full */
 									/*		intern generated */
-#define XM_MD_LE_STW	(1L<<22)	/* Bit 22:	Rx Stat Word in Lit En*/
+#define XM_MD_LE_STW	(1L<<22)	/* Bit 22:	Rx Stat Word in Little Endian */
 #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 */
@@ -447,40 +518,40 @@
 #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 */
-#define XM_MD_ENA_HSH	(1L<<15)	/* Bit 15:	Enable Hashing */
+#define XM_MD_ENA_HASH	(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_RX_MCTRL	(1L<<12)	/* Bit 12:	Rx MAC Control Frames */
+#define XM_MD_RX_MCTRL	(1L<<12)	/* Bit 12:	Rx MAC Control Frame */
 #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 */
-#define XM_MD_RX_LONG	(1L<<9)		/* Bit	9:	Rx Long Frames */
-#define XM_MD_RX_CRCE	(1L<<8)		/* Bit	8:	Rx CRC Error Frames */
-#define XM_MD_RX_ERR	(1L<<7)		/* Bit	7:	Rx Error Frames */
-#define XM_MD_DIS_UC	(1L<<6)		/* Bit	6:	Disable Rx Unicast */
-#define XM_MD_DIS_MC	(1L<<5)		/* Bit	5:	Disable Rx Multicast */
-#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_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)
+#define XM_MD_RX_IRLE	(1L<<10)	/* Bit 10:	Rx in Range Len Err Frame */
+#define XM_MD_RX_LONG	(1L<<9)		/* Bit  9:	Rx Long Frame */
+#define XM_MD_RX_CRCE	(1L<<8)		/* Bit  8:	Rx CRC Error Frame */
+#define XM_MD_RX_ERR	(1L<<7)		/* Bit  7:	Rx Error Frame */
+#define XM_MD_DIS_UC	(1L<<6)		/* Bit  6:	Disable Rx Unicast */
+#define XM_MD_DIS_MC	(1L<<5)		/* Bit  5:	Disable Rx Multicast */
+#define XM_MD_DIS_BC	(1L<<4)		/* Bit  4:	Disable Rx Broadcast */
+#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_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_STAT_CMD	16 bit r/w	Statistics Command Register */
 								/* 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 */
-#define XM_SC_CP_TXC	(1<<2)	/* Bit	2:	Copy Tx Counters Continuously */
-#define XM_SC_CLR_RXC	(1<<1)	/* Bit	1: (sc)	Clear Rx Counters */
-#define XM_SC_CLR_TXC	(1<<0)	/* Bit	0: (sc) Clear Tx Counters */
+#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 */
+#define XM_SC_CP_TXC	(1<<2)	/* Bit  2:	Copy Tx Counters Continuously */
+#define XM_SC_CLR_RXC	(1<<1)	/* Bit  1: (sc)	Clear Rx Counters */
+#define XM_SC_CLR_TXC	(1<<0)	/* Bit  0: (sc) Clear Tx Counters */
 
 
-/*	XM_RX_CNT_EV	32 bit ro	Rx Counter Event Register */
+/*	XM_RX_CNT_EV	32 bit r/o	Rx Counter Event Register */
 /*	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_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*/
@@ -502,20 +573,20 @@
 #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_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*/
-#define XMR_MC_OK_OV	(1L<<4)		/* Bit	4:	Rx Multicast Cnt Ov */
-#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_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*/
+#define XMR_MC_OK_OV	(1L<<4)		/* Bit  4:	Rx Multicast Cnt Ov */
+#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_DEF_MSK	0x00000006L	/* all bits excepting 1 and 2 */
+#define XMR_DEF_MSK		(XMR_OK_LO_OV | XMR_OK_HI_OV)
 
-/*	XM_TX_CNT_EV	32 bit ro	Tx Counter Event Register */
+/*	XM_TX_CNT_EV	32 bit r/o	Tx Counter Event Register */
 /*	XM_TX_EV_MSK	32 bit r/w	Tx Counter Event Mask */
 									/* Bit 31..26:	reserved */
 #define XMT_MAX_SZ_OV	(1L<<25)	/* Bit 25:	1024-MaxSize Tx Cnt Ov*/
@@ -534,18 +605,18 @@
 #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_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_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_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_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_DEF_MSK	0x00000006L	/* all bits excepting 1 and 2 */
+#define XMT_DEF_MSK		(XMT_OK_LO_OV | XMT_OK_HI_OV)
 
 /*
  * Receive Frame Status Encoding
@@ -559,16 +630,16 @@
 									/* 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 */
-#define XMR_FS_COL_ERR	(1L<<8)		/* Bit	8:	Collision Error */
-#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_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_MCTRL	(1L<<0)		/* Bit	0:	MAC Control Packet */
+#define XMR_FS_802_3	(1L<<9)		/* Bit  9:	802.3 Frame */
+#define XMR_FS_COL_ERR	(1L<<8)		/* Bit  8:	Collision Error */
+#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 Frame */
+#define XMR_FS_LNG_ERR	(1L<<3)		/* Bit  3:	Giant (Jumbo) Frame */
+#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_MCTRL	(1L<<0)		/* Bit  0:	MAC Control Packet */
 
 /*
  * XMR_FS_ERR will be set if
@@ -584,102 +655,135 @@
 /*
  * XMAC-PHY Registers, indirect addressed over the XMAC
  */
-#define	PHY_XMAC_CTRL		0x00	/* 16 bit r/w	PHY Control Register */
-#define	PHY_XMAC_STAT		0x01	/* 16 bit r/w	PHY Status Register */
-#define	PHY_XMAC_ID0		0x02	/* 16 bit ro	PHY ID0 Register */
-#define	PHY_XMAC_ID1		0x03	/* 16 bit ro	PHY ID1 Register */
-#define	PHY_XMAC_AUNE_ADV	0x04	/* 16 bit r/w	Autoneg Advertisement */
-#define	PHY_XMAC_AUNE_LP	0x05	/* 16 bit ro	Link Partner Abi Reg */
-#define	PHY_XMAC_AUNE_EXP	0x06	/* 16 bit ro	Autoneg Expansion Reg */
-#define	PHY_XMAC_NEPG		0x07	/* 16 bit r/w	Next Page Register */
-#define	PHY_XMAC_NEPG_LP	0x08	/* 16 bit ro	Next Page Link P Reg */
+#define PHY_XMAC_CTRL		0x00	/* 16 bit r/w	PHY Control Register */
+#define PHY_XMAC_STAT		0x01	/* 16 bit r/w	PHY Status Register */
+#define PHY_XMAC_ID0		0x02	/* 16 bit r/o	PHY ID0 Register */
+#define PHY_XMAC_ID1		0x03	/* 16 bit r/o	PHY ID1 Register */
+#define PHY_XMAC_AUNE_ADV	0x04	/* 16 bit r/w	Auto-Neg. Advertisement */
+#define PHY_XMAC_AUNE_LP	0x05	/* 16 bit r/o	Link Partner Abi Reg */
+#define PHY_XMAC_AUNE_EXP	0x06	/* 16 bit r/o	Auto-Neg. Expansion Reg */
+#define PHY_XMAC_NEPG		0x07	/* 16 bit r/w	Next Page Register */
+#define PHY_XMAC_NEPG_LP	0x08	/* 16 bit r/o	Next Page Link P Reg */
 	/* 0x09 - 0x0e:		reserved */
-#define	PHY_XMAC_EXT_STAT	0x0f	/* 16 bit ro	Ext Status Register */
-#define	PHY_XMAC_RES_ABI	0x10	/* 16 bit ro	PHY Resolved Ability */
+#define PHY_XMAC_EXT_STAT	0x0f	/* 16 bit r/o	Ext Status Register */
+#define PHY_XMAC_RES_ABI	0x10	/* 16 bit r/o	PHY Resolved Ability */
 
 /*----------------------------------------------------------------------------*/
 /*
  * Broadcom-PHY Registers, indirect addressed over XMAC
  */
-#define	PHY_BCOM_CTRL		0x00	/* 16 bit r/w	PHY Control Register */
-#define	PHY_BCOM_STAT		0x01	/* 16 bit ro	PHY Status Register */
-#define	PHY_BCOM_ID0		0x02	/* 16 bit ro	PHY ID0 Register */
-#define	PHY_BCOM_ID1		0x03	/* 16 bit ro	PHY ID1 Register */
-#define	PHY_BCOM_AUNE_ADV	0x04	/* 16 bit r/w	Autoneg Advertisement */
-#define	PHY_BCOM_AUNE_LP	0x05	/* 16 bit ro	Link Part Ability Reg */
-#define	PHY_BCOM_AUNE_EXP	0x06	/* 16 bit ro	Autoneg Expansion Reg */
-#define	PHY_BCOM_NEPG		0x07	/* 16 bit r/w	Next Page Register */
-#define	PHY_BCOM_NEPG_LP	0x08	/* 16 bit ro	Next Page Link P Reg */
+#define PHY_BCOM_CTRL		0x00	/* 16 bit r/w	PHY Control Register */
+#define PHY_BCOM_STAT		0x01	/* 16 bit r/o	PHY Status Register */
+#define PHY_BCOM_ID0		0x02	/* 16 bit r/o	PHY ID0 Register */
+#define PHY_BCOM_ID1		0x03	/* 16 bit r/o	PHY ID1 Register */
+#define PHY_BCOM_AUNE_ADV	0x04	/* 16 bit r/w	Auto-Neg. Advertisement */
+#define PHY_BCOM_AUNE_LP	0x05	/* 16 bit r/o	Link Part Ability Reg */
+#define PHY_BCOM_AUNE_EXP	0x06	/* 16 bit r/o	Auto-Neg. Expansion Reg */
+#define PHY_BCOM_NEPG		0x07	/* 16 bit r/w	Next Page Register */
+#define PHY_BCOM_NEPG_LP	0x08	/* 16 bit r/o	Next Page Link P Reg */
 	/* Broadcom-specific registers */
-#define	PHY_BCOM_1000T_CTRL	0x09	/* 16 bit r/w	1000Base-T Ctrl Reg */
-#define	PHY_BCOM_1000T_STAT	0x0a	/* 16 bit ro	1000Base-T Status Reg */
+#define PHY_BCOM_1000T_CTRL	0x09	/* 16 bit r/w	1000Base-T Ctrl Reg */
+#define PHY_BCOM_1000T_STAT	0x0a	/* 16 bit r/o	1000Base-T Status Reg */
 	/* 0x0b - 0x0e:		reserved */
-#define	PHY_BCOM_EXT_STAT	0x0f	/* 16 bit ro	Extended Status Reg */
-#define	PHY_BCOM_P_EXT_CTRL	0x10	/* 16 bit r/w	PHY Extended Ctrl Reg */
-#define	PHY_BCOM_P_EXT_STAT	0x11	/* 16 bit ro	PHY Extended Stat Reg */
-#define	PHY_BCOM_RE_CTR		0x12	/* 16 bit r/w	Receive Error Counter */
-#define	PHY_BCOM_FC_CTR		0x13	/* 16 bit r/w	False Carr Sense Cnt */
-#define	PHY_BCOM_RNO_CTR	0x14	/* 16 bit r/w	Receiver NOT_OK Cnt */
+#define PHY_BCOM_EXT_STAT	0x0f	/* 16 bit r/o	Extended Status Reg */
+#define PHY_BCOM_P_EXT_CTRL	0x10	/* 16 bit r/w	PHY Extended Ctrl Reg */
+#define PHY_BCOM_P_EXT_STAT	0x11	/* 16 bit r/o	PHY Extended Stat Reg */
+#define PHY_BCOM_RE_CTR		0x12	/* 16 bit r/w	Receive Error Counter */
+#define PHY_BCOM_FC_CTR		0x13	/* 16 bit r/w	False Carr Sense Cnt */
+#define PHY_BCOM_RNO_CTR	0x14	/* 16 bit r/w	Receiver NOT_OK Cnt */
 	/* 0x15 - 0x17:		reserved */
-#define	PHY_BCOM_AUX_CTRL	0x18	/* 16 bit r/w	Auxiliary Control Reg */
-#define	PHY_BCOM_AUX_STAT	0x19	/* 16 bit ro	Auxiliary Stat Summary*/
-#define	PHY_BCOM_INT_STAT	0x1a	/* 16 bit ro	Interrupt Status Reg */
-#define	PHY_BCOM_INT_MASK	0x1b	/* 16 bit r/w	Interrupt Mask Reg */
+#define PHY_BCOM_AUX_CTRL	0x18	/* 16 bit r/w	Auxiliary Control Reg */
+#define PHY_BCOM_AUX_STAT	0x19	/* 16 bit r/o	Auxiliary Stat Summary */
+#define PHY_BCOM_INT_STAT	0x1a	/* 16 bit r/o	Interrupt Status Reg */
+#define PHY_BCOM_INT_MASK	0x1b	/* 16 bit r/w	Interrupt Mask Reg */
 	/* 0x1c:		reserved */
 	/* 0x1d - 0x1f:		test registers */
 
 /*----------------------------------------------------------------------------*/
 /*
+ * Marvel-PHY Registers, indirect addressed over GMAC
+ */
+#define PHY_MARV_CTRL		0x00	/* 16 bit r/w	PHY Control Register */
+#define PHY_MARV_STAT		0x01	/* 16 bit r/o	PHY Status Register */
+#define PHY_MARV_ID0		0x02	/* 16 bit r/o	PHY ID0 Register */
+#define PHY_MARV_ID1		0x03	/* 16 bit r/o	PHY ID1 Register */
+#define PHY_MARV_AUNE_ADV	0x04	/* 16 bit r/w	Auto-Neg. Advertisement */
+#define PHY_MARV_AUNE_LP	0x05	/* 16 bit r/o	Link Part Ability Reg */
+#define PHY_MARV_AUNE_EXP	0x06	/* 16 bit r/o	Auto-Neg. Expansion Reg */
+#define PHY_MARV_NEPG		0x07	/* 16 bit r/w	Next Page Register */
+#define PHY_MARV_NEPG_LP	0x08	/* 16 bit r/o	Next Page Link P Reg */
+	/* Marvel-specific registers */
+#define PHY_MARV_1000T_CTRL	0x09	/* 16 bit r/w	1000Base-T Ctrl Reg */
+#define PHY_MARV_1000T_STAT	0x0a	/* 16 bit r/o	1000Base-T Status Reg */
+	/* 0x0b - 0x0e:		reserved */
+#define PHY_MARV_EXT_STAT	0x0f	/* 16 bit r/o	Extended Status Reg */
+#define PHY_MARV_PHY_CTRL	0x10	/* 16 bit r/w	PHY Specific Ctrl Reg */
+#define PHY_MARV_PHY_STAT	0x11	/* 16 bit r/o	PHY Specific Stat Reg */
+#define PHY_MARV_INT_MASK	0x12	/* 16 bit r/w	Interrupt Mask Reg */
+#define PHY_MARV_INT_STAT	0x13	/* 16 bit r/o	Interrupt Status Reg */
+#define PHY_MARV_EXT_CTRL	0x14	/* 16 bit r/w	Ext. PHY Specific Ctrl */
+#define PHY_MARV_RXE_CNT	0x15	/* 16 bit r/w	Receive Error Counter */
+#define PHY_MARV_EXT_ADR	0x16	/* 16 bit r/w	Ext. Ad. for Cable Diag. */
+	/* 0x17:		reserved */
+#define PHY_MARV_LED_CTRL	0x18	/* 16 bit r/w	LED Control Reg */
+#define PHY_MARV_LED_OVER	0x19	/* 16 bit r/w	Manual LED Override Reg */
+#define PHY_MARV_EXT_CTRL_2	0x1a	/* 16 bit r/w	Ext. PHY Specific Ctrl 2 */
+#define PHY_MARV_EXT_P_STAT	0x1b	/* 16 bit r/w	Ext. PHY Spec. Stat Reg */
+#define PHY_MARV_CABLE_DIAG	0x1c	/* 16 bit r/o	Cable Diagnostic Reg */
+	/* 0x1d - 0x1f:		reserved */
+
+/*----------------------------------------------------------------------------*/
+/*
  * Level One-PHY Registers, indirect addressed over XMAC
  */
-#define	PHY_LONE_CTRL		0x00	/* 16 bit r/w	PHY Control Register */
-#define	PHY_LONE_STAT		0x01	/* 16 bit ro	PHY Status Register */
-#define	PHY_LONE_ID0		0x02	/* 16 bit ro	PHY ID0 Register */
-#define	PHY_LONE_ID1		0x03	/* 16 bit ro	PHY ID1 Register */
-#define	PHY_LONE_AUNE_ADV	0x04	/* 16 bit r/w	Autoneg Advertisement */
-#define	PHY_LONE_AUNE_LP	0x05	/* 16 bit ro	Link Part Ability Reg */
-#define	PHY_LONE_AUNE_EXP	0x06	/* 16 bit ro	Autoneg Expansion Reg */
-#define	PHY_LONE_NEPG		0x07	/* 16 bit r/w	Next Page Register */
-#define	PHY_LONE_NEPG_LP	0x08	/* 16 bit ro	Next Page Link Partner*/
+#define PHY_LONE_CTRL		0x00	/* 16 bit r/w	PHY Control Register */
+#define PHY_LONE_STAT		0x01	/* 16 bit r/o	PHY Status Register */
+#define PHY_LONE_ID0		0x02	/* 16 bit r/o	PHY ID0 Register */
+#define PHY_LONE_ID1		0x03	/* 16 bit r/o	PHY ID1 Register */
+#define PHY_LONE_AUNE_ADV	0x04	/* 16 bit r/w	Auto-Neg. Advertisement */
+#define PHY_LONE_AUNE_LP	0x05	/* 16 bit r/o	Link Part Ability Reg */
+#define PHY_LONE_AUNE_EXP	0x06	/* 16 bit r/o	Auto-Neg. Expansion Reg */
+#define PHY_LONE_NEPG		0x07	/* 16 bit r/w	Next Page Register */
+#define PHY_LONE_NEPG_LP	0x08	/* 16 bit r/o	Next Page Link Partner*/
 	/* Level One-specific registers */
-#define	PHY_LONE_1000T_CTRL	0x09	/* 16 bit r/w	1000Base-T Control Reg*/
-#define	PHY_LONE_1000T_STAT	0x0a	/* 16 bit ro	1000Base-T Status Reg */
+#define PHY_LONE_1000T_CTRL	0x09	/* 16 bit r/w	1000Base-T Control Reg*/
+#define PHY_LONE_1000T_STAT	0x0a	/* 16 bit r/o	1000Base-T Status Reg */
 	/* 0x0b -0x0e:		reserved */
-#define	PHY_LONE_EXT_STAT	0x0f	/* 16 bit ro	Extended Status Reg */
-#define	PHY_LONE_PORT_CFG	0x10	/* 16 bit r/w	Port Configuration Reg*/
-#define	PHY_LONE_Q_STAT		0x11	/* 16 bit ro	Quick Status Reg */
-#define	PHY_LONE_INT_ENAB	0x12	/* 16 bit r/w	Interrupt Enable Reg */
-#define	PHY_LONE_INT_STAT	0x13	/* 16 bit ro	Interrupt Status Reg */
-#define	PHY_LONE_LED_CFG	0x14	/* 16 bit r/w	LED Configuration Reg */
-#define	PHY_LONE_PORT_CTRL	0x15	/* 16 bit r/w	Port Control Reg */
-#define	PHY_LONE_CIM		0x16	/* 16 bit ro	CIM Reg */
+#define PHY_LONE_EXT_STAT	0x0f	/* 16 bit r/o	Extended Status Reg */
+#define PHY_LONE_PORT_CFG	0x10	/* 16 bit r/w	Port Configuration Reg*/
+#define PHY_LONE_Q_STAT		0x11	/* 16 bit r/o	Quick Status Reg */
+#define PHY_LONE_INT_ENAB	0x12	/* 16 bit r/w	Interrupt Enable Reg */
+#define PHY_LONE_INT_STAT	0x13	/* 16 bit r/o	Interrupt Status Reg */
+#define PHY_LONE_LED_CFG	0x14	/* 16 bit r/w	LED Configuration Reg */
+#define PHY_LONE_PORT_CTRL	0x15	/* 16 bit r/w	Port Control Reg */
+#define PHY_LONE_CIM		0x16	/* 16 bit r/o	CIM Reg */
 	/* 0x17 -0x1c:		reserved */
 
 /*----------------------------------------------------------------------------*/
 /*
  * National-PHY Registers, indirect addressed over XMAC
  */
-#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_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 */
-#define	PHY_NAT_NEPG		0x07	/* 16 bit r/w	Next Page Register */
-#define	PHY_NAT_NEPG_LP		0x08	/* 16 bit ro	Next Page Link Partner Reg */
+#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 r/o	PHY ID0 Register */
+#define PHY_NAT_ID1			0x03	/* 16 bit r/o	PHY ID1 Register */
+#define PHY_NAT_AUNE_ADV	0x04	/* 16 bit r/w	Auto-Neg. Advertisement */
+#define PHY_NAT_AUNE_LP		0x05	/* 16 bit r/o	Link Partner Ability Reg */
+#define PHY_NAT_AUNE_EXP	0x06	/* 16 bit r/o	Auto-Neg. Expansion Reg */
+#define PHY_NAT_NEPG		0x07	/* 16 bit r/w	Next Page Register */
+#define PHY_NAT_NEPG_LP		0x08	/* 16 bit r/o	Next Page Link Partner Reg */
 	/* National-specific registers */
-#define	PHY_NAT_1000T_CTRL	0x09	/* 16 bit r/w	1000Base-T Control Reg */
-#define	PHY_NAT_1000T_STAT	0x0a	/* 16 bit ro	1000Base-T Status Reg */
+#define PHY_NAT_1000T_CTRL	0x09	/* 16 bit r/w	1000Base-T Control Reg */
+#define PHY_NAT_1000T_STAT	0x0a	/* 16 bit r/o	1000Base-T Status Reg */
 	/* 0x0b -0x0e:		reserved */
-#define	PHY_NAT_EXT_STAT	0x0f	/* 16 bit ro	Extended Status Register */
-#define	PHY_NAT_EXT_CTRL1	0x10	/* 16 bit ro	Extended Control Reg1 */
-#define	PHY_NAT_Q_STAT1		0x11	/* 16 bit ro	Quick Status Reg1 */
-#define	PHY_NAT_10B_OP		0x12	/* 16 bit ro	10Base-T Operations Reg */
-#define	PHY_NAT_EXT_CTRL2	0x13	/* 16 bit ro	Extended Control Reg1 */
-#define	PHY_NAT_Q_STAT2		0x14	/* 16 bit ro	Quick Status Reg2 */
+#define PHY_NAT_EXT_STAT	0x0f	/* 16 bit r/o	Extended Status Register */
+#define PHY_NAT_EXT_CTRL1	0x10	/* 16 bit r/o	Extended Control Reg1 */
+#define PHY_NAT_Q_STAT1		0x11	/* 16 bit r/o	Quick Status Reg1 */
+#define PHY_NAT_10B_OP		0x12	/* 16 bit r/o	10Base-T Operations Reg */
+#define PHY_NAT_EXT_CTRL2	0x13	/* 16 bit r/o	Extended Control Reg1 */
+#define PHY_NAT_Q_STAT2		0x14	/* 16 bit r/o	Quick Status Reg2 */
 	/* 0x15 -0x18:		reserved */
-#define	PHY_NAT_PHY_ADDR	0x19	/* 16 bit ro	PHY Address Register */
+#define PHY_NAT_PHY_ADDR	0x19	/* 16 bit r/o	PHY Address Register */
 
 
 /*----------------------------------------------------------------------------*/
@@ -691,131 +795,135 @@
  * All other are general.
  */
 
-/*****	PHY_XMAC_CTRL	16 bit r/w	PHY Control Register *****/
-/*****	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 */
+/*****  PHY_XMAC_CTRL	16 bit r/w	PHY Control Register *****/
+/*****  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 related regs */
 #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:	Auto-Negotiation 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_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 */
-
-#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 */
-#define PHY_B_CT_SP10	(0)	/* Bit 6/13 not set,	speed of  10 MBit/s */
-
-#define PHY_L_CT_SP1000	(1<<6)	/* Bit  6:      enable speed of 1000 MBit/s */
-#define PHY_L_CT_SP100	(1<<13)	/* Bit 13:      enable speed of  100 MBit/s */
-#define PHY_L_CT_SP10	(0)	/* Bit 6/13 not set,    speed of  10 MBit/s */
-
-
-/*****	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 *****/
+#define PHY_CT_RE_CFG	(1<<9)	/* Bit  9: (sc) Restart Auto-Negotiation */
+#define PHY_CT_DUP_MD	(1<<8)	/* Bit  8:	Duplex Mode */
+#define PHY_CT_COL_TST	(1<<7)	/* Bit  7: (BC,L1) Collision Test enabled */
+#define PHY_CT_SPS_MSB	(1<<6)	/* Bit  6: (BC,L1) Speed select, upper bit */
+								/* Bit  5..0:	reserved */
+
+#define PHY_CT_SP1000	PHY_CT_SPS_MSB	/* enable speed of 1000 Mbps */
+#define PHY_CT_SP100	PHY_CT_SPS_LSB	/* enable speed of  100 Mbps */
+#define PHY_CT_SP10		(0)				/* enable speed of   10 Mbps */
+
+
+/*****  PHY_XMAC_STAT	16 bit r/w	PHY Status Register *****/
+/*****  PHY_BCOM_STAT	16 bit r/w	PHY Status Register *****/
+/*****  PHY_MARV_STAT	16 bit r/w	PHY Status Register *****/
+/*****  PHY_LONE_STAT	16 bit r/w	PHY Status Register *****/
 								/* 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 */
-#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*/
-#define PHY_ST_AN_CAP	(1<<3)	/* Bit	3:	Autonegotiation Capability */
-#define PHY_ST_LSYNC	(1<<2)	/* Bit	2:	Link Synchronized */
-#define PHY_ST_JAP_DET	(1<<1)	/* Bit	1: (BC/L1) Japper Detected */
-#define PHY_ST_EXT_REG	(1<<0)	/* Bit	0:	Extended Register available */
-
-
-/*	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_MOD_NUM	(0x3f<<4)	/* Bit	9.. 4:	Model Number */
-#define PHY_I1_REV		(0x0f<<0)	/* Bit	3.. 0:	Revision Number */
+				/*	(BC/L1) 100/10 Mbps cap bits ignored*/
+#define PHY_ST_EXT_ST	(1<<8)	/* Bit  8:	Extended Status Present */
+								/* Bit  7:	reserved */
+#define PHY_ST_PRE_SUP	(1<<6)	/* Bit  6: (BC/L1) preamble suppression */
+#define PHY_ST_AN_OVER	(1<<5)	/* Bit  5:	Auto-Negotiation Over */
+#define PHY_ST_REM_FLT	(1<<4)	/* Bit  4:	Remote Fault Condition Occured */
+#define PHY_ST_AN_CAP	(1<<3)	/* Bit  3:	Auto-Negotiation Capability */
+#define PHY_ST_LSYNC	(1<<2)	/* Bit  2:	Link Synchronized */
+#define PHY_ST_JAB_DET	(1<<1)	/* Bit  1: (BC/L1) Jabber Detected */
+#define PHY_ST_EXT_REG	(1<<0)	/* Bit  0:	Extended Register available */
+
+
+/*****	PHY_XMAC_ID1		16 bit r/o	PHY ID1 Register */
+/*****	PHY_BCOM_ID1		16 bit r/o	PHY ID1 Register */
+/*****	PHY_MARV_ID1		16 bit r/o	PHY ID1 Register */
+/*****	PHY_LONE_ID1		16 bit r/o	PHY ID1 Register */
+#define PHY_I1_OUI_MSK	(0x3f<<10)	/* Bit 15..10:	Organization Unique ID */
+#define PHY_I1_MOD_NUM	(0x3f<<4)	/* Bit  9.. 4:	Model Number */
+#define PHY_I1_REV_MSK	0x0f		/* Bit  3.. 0:	Revision Number */
+
+/* different Broadcom PHY Ids */
+#define PHY_BCOM_ID1_A1		0x6041
+#define PHY_BCOM_ID1_B2		0x6043
+#define PHY_BCOM_ID1_C0		0x6044
+#define PHY_BCOM_ID1_C5		0x6047
 
 
-/*****	PHY_XMAC_AUNE_ADV	16 bit r/w	Autoneg Advertisement *****/
-/*****	PHY_XMAC_AUNE_LP	16 bit ro	Link Partner Ability Reg *****/
+/*****  PHY_XMAC_AUNE_ADV	16 bit r/w	Auto-Negotiation Advertisement *****/
+/*****  PHY_XMAC_AUNE_LP	16 bit r/o	Link Partner Ability Reg *****/
 #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 */
+#define PHY_X_AN_RFB	(3<<12)	/* Bit 13..12:	Remote Fault Bits */
 								/* 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_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 */
 
-/*****	PHY_BCOM_AUNE_ADV	16 bit r/w	Autoneg Advertisement *****/
-/*****	PHY_BCOM_AUNE_LP	16 bit ro	Link Partner Ability Reg *****/
+/*****  PHY_BCOM_AUNE_ADV	16 bit r/w	Auto-Negotiation Advertisement *****/
+/*****  PHY_BCOM_AUNE_LP	16 bit r/o	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 */
-#define PHY_B_AN_ASP	(1<<11)	/* Bit 11:	Asymetric Pause */
+#define PHY_B_AN_ASP	(1<<11)	/* Bit 11:	Asymmetric 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_SEL	(0x1f<<0)/* Bit 4..0:	Selector Field, 00001=Ethernet*/
+								/* Bit  9..5:	100/10 BT cap bits ingnored */
+#define PHY_B_AN_SEL	0x1f	/* 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_LONE_AUNE_ADV	16 bit r/w	Auto-Negotiation Advertisement *****/
+/*****  PHY_LONE_AUNE_LP	16 bit r/o	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 */
-#define PHY_L_AN_ASP	(1<<11)	/* Bit 11:	Asymetric Pause */
+#define PHY_L_AN_ASP	(1<<11)	/* Bit 11:	Asymmetric 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_SEL	(0x1f<<0)/* Bit 4..0:	Selector Field, 00001=Ethernet*/
+								/* Bit  9..5:	100/10 BT cap bits ingnored */
+#define PHY_L_AN_SEL	0x1f	/* 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_NAT_AUNE_ADV	16 bit r/w	Auto-Negotiation Advertisement *****/
+/*****  PHY_NAT_AUNE_LP		16 bit r/o	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 */
 #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 */
-#define PHY_N_AN_SEL	(0x1f<<0)/* Bit 4..0:	Selector Field, 00001=Ethernet*/
+								/* Bit  9..5:	100/10 BT cap bits ingnored */
+#define PHY_N_AN_SEL	0x1f	/* Bit 4..0:	Selector Field, 00001=Ethernet*/
 
 /* field type definition for PHY_x_AN_SEL */
 #define PHY_SEL_TYPE	0x01	/* 00001 = Ethernet */
 
-/*****	PHY_XMAC_AUNE_EXP	16 bit ro	Autoneg Expansion Reg *****/
-				/* Bit 15..4:	reserved */
-#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 */
+/*****  PHY_XMAC_AUNE_EXP	16 bit r/o	Auto-Negotiation Expansion Reg *****/
+								/* Bit 15..4:	reserved */
+#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 */
 
-/*****	PHY_BCOM_AUNE_EXP	16 bit ro	Autoneg Expansion Reg *****/
+/*****  PHY_BCOM_AUNE_EXP	16 bit r/o	Auto-Negotiation Expansion Reg *****/
 								/* 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 */
-#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_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 */
-#define PHY_B_AN_LP_CAP	(1<<0)	/* Bit	0:	Link Partner Autoneg Cap. */ 	
-
-
-/*****	PHY_XMAC_NEPG		16 bit r/w	Next Page Register *****/
-/*****	PHY_BCOM_NEPG		16 bit r/w	Next Page Register *****/
-/*****	PHY_LONE_NEPG		16 bit r/w	Next Page Register *****/
-/*****	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_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 */
+#define PHY_B_AN_LP_CAP	(1<<0)	/* Bit  0:	Link Partner Auto-Neg. Cap. */ 	
+
+/*****  PHY_LONE_AUNE_EXP	16 bit r/o	Auto-Negotiation Expansion Reg *****/
+#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 */
+#define PHY_B_AN_LP_CAP	(1<<0)	/* Bit  0:	Link Partner Auto-Neg. Cap. */ 	
+
+
+/*****  PHY_XMAC_NEPG		16 bit r/w	Next Page Register *****/
+/*****  PHY_BCOM_NEPG		16 bit r/w	Next Page Register *****/
+/*****  PHY_LONE_NEPG		16 bit r/w	Next Page Register *****/
+/*****  PHY_XMAC_NEPG_LP	16 bit r/o	Next Page Link Partner *****/
+/*****  PHY_BCOM_NEPG_LP	16 bit r/o	Next Page Link Partner *****/
+/*****  PHY_LONE_NEPG_LP	16 bit r/o	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_MSG_VAL	(1<<13)	/* Bit 13:	Message Page valid */
@@ -826,66 +934,66 @@
 /*
  * XMAC-Specific
  */
-/*****	PHY_XMAC_EXT_STAT	16 bit r/w	Extended Status Register *****/
+/*****  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 */
 
-/*****	PHY_XMAC_RES_ABI	16 bit ro	PHY Resolved Ability *****/
+/*****  PHY_XMAC_RES_ABI	16 bit r/o	PHY Resolved Ability *****/
 								/* 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_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 */
+#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_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 */
 /*
  * 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_AN_ERR	(3<<12)	/* Bit 12..13	Autonegotiation Error */
+#define X_RFB_OK		(0<<12)	/* Bit 13..12	No errors, Link OK */
+#define X_RFB_LF		(1<<12)	/* Bit 13..12	Link Failure */
+#define X_RFB_OFF		(2<<12)	/* Bit 13..12	Offline */
+#define X_RFB_AN_ERR	(3<<12)	/* Bit 13..12	Auto-Negotiation Error */
 
 /*
  * Pause Bits (PHY_X_AN_PAUSE and PHY_X_RS_PAUSE) encoding
  */
-#define PHY_X_P_NO_PAUSE	(0<<7)	/* Bit	8..7:	no Pause Mode */
-#define PHY_X_P_SYM_MD		(1<<7)	/* Bit	8..7:	symmetric Pause Mode */
-#define PHY_X_P_ASYM_MD		(2<<7)	/* Bit	8..7:	asymmetric Pause Mode */
-#define PHY_X_P_BOTH_MD		(3<<7)	/* Bit	8..7:	both Pause Mode */
+#define PHY_X_P_NO_PAUSE	(0<<7)	/* Bit  8..7:	no Pause Mode */
+#define PHY_X_P_SYM_MD		(1<<7)	/* Bit  8..7:	symmetric Pause Mode */
+#define PHY_X_P_ASYM_MD		(2<<7)	/* Bit  8..7:	asymmetric Pause Mode */
+#define PHY_X_P_BOTH_MD		(3<<7)	/* Bit  8..7:	both Pause Mode */
 
 
 /*
  * Broadcom-Specific
  */
-/***** PHY_BCOM_1000T_CTRL	16 bit r/w	1000Base-T Control Reg *****/
-#define PHY_B_1000C_TEST	(7<<13)	/* Bit	15..13:	Test Modes */
-#define PHY_B_1000C_MSE		(1<<12)	/* Bit	12:	Master/Slave Enable */
-#define PHY_B_1000C_MSC		(1<<11)	/* Bit	11:	M/S Configuration */
-#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 */
-
-/***** PHY_BCOM_1000T_STAT	16 bit ro	1000Base-T Status Reg *****/
-#define PHY_B_1000S_MSF		(1<<15)	/* Bit	15:	Master/Slave Fault */
-#define PHY_B_1000S_MSR		(1<<14)	/* Bit	14:	Master/Slave Result */
-#define PHY_B_1000S_LRS		(1<<13)	/* Bit	13:	Local Receiver Status */
-#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 */
-#define PHY_B_1000S_IEC		(255<<0)/* Bit	7..0:	Idle Error Count */
+/*****  PHY_BCOM_1000T_CTRL	16 bit r/w	1000Base-T Control Reg *****/
+#define PHY_B_1000C_TEST	(7<<13)	/* Bit 15..13:	Test Modes */
+#define PHY_B_1000C_MSE		(1<<12)	/* Bit 12:	Master/Slave Enable */
+#define PHY_B_1000C_MSC		(1<<11)	/* Bit 11:	M/S Configuration */
+#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 */
+
+/*****  PHY_BCOM_1000T_STAT	16 bit r/o	1000Base-T Status Reg *****/
+#define PHY_B_1000S_MSF		(1<<15)	/* Bit 15:	Master/Slave Fault */
+#define PHY_B_1000S_MSR		(1<<14)	/* Bit 14:	Master/Slave Result */
+#define PHY_B_1000S_LRS		(1<<13)	/* Bit 13:	Local Receiver Status */
+#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 */
+#define PHY_B_1000S_IEC		0xff	/* Bit  7..0:	Idle Error Count */
 
-/*****	PHY_BCOM_EXT_STAT	16 bit ro	Extended Status Register *****/
+/*****  PHY_BCOM_EXT_STAT	16 bit r/o	Extended Status Register *****/
 #define PHY_B_ES_X_FD_CAP	(1<<15)	/* Bit 15:	1000Base-X FD capable */
 #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 */
 
-/*****	PHY_BCOM_P_EXT_CTRL	16 bit r/w	PHY Extended Control Reg *****/
+/*****  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 */
 #define PHY_B_PEC_DIS_CROSS	(1<<14)	/* Bit 14:	Disable MDI Crossover */
 #define PHY_B_PEC_TX_DIS	(1<<13)	/* Bit 13:	Tx output Disabled */
@@ -901,9 +1009,9 @@
 #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_HIGH_LA	(1<<0)	/* Bit  0:	GMII FIFO Elasticy */
 
-/*****	PHY_BCOM_P_EXT_STAT	16 bit ro	PHY Extended Status Reg *****/
+/*****  PHY_BCOM_P_EXT_STAT	16 bit r/o	PHY Extended Status Reg *****/
 									/* 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 */
@@ -920,20 +1028,20 @@
 #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 *****/
+/*****  PHY_BCOM_FC_CTR		16 bit r/w	False Carrier Counter *****/
 									/* Bit 15..8:	reserved */
-#define PHY_B_FC_CTR		(255<<0)/* Bit 7..0:	False Carrier Counter */
+#define PHY_B_FC_CTR		0xff	/* Bit  7..0:	False Carrier Counter */
 
-/*****	PHY_BCOM_RNO_CTR	16 bit r/w	Receive NOT_OK Counter *****/
-#define PHY_B_RC_LOC		(255<<8)/* Bit 15..8:	Local Rx NOT_OK cnt */
-#define PHY_B_RC_REM		(255<<0)/* Bit  7..0:	Remote Rx NOT_OK cnt */
+/*****  PHY_BCOM_RNO_CTR	16 bit r/w	Receive NOT_OK Counter *****/
+#define PHY_B_RC_LOC_MSK	0xff00	/* Bit 15..8:	Local Rx NOT_OK cnt */
+#define PHY_B_RC_REM_MSK	0x00ff	/* Bit  7..0:	Remote Rx NOT_OK cnt */
 
-/*****	PHY_BCOM_AUX_CTRL	16 bit r/w	Auxiliary Control Reg *****/
+/*****  PHY_BCOM_AUX_CTRL	16 bit r/w	Auxiliary Control Reg *****/
 #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 */
-#define PHY_B_AC_TX_TST		(1<<10) /* Bit 10:	tx test bit, always 1 */
+#define PHY_B_AC_TX_TST		(1<<10) /* Bit 10:	Tx test bit, always 1 */
 									/* Bit  9.. 8:	reserved */
 #define PHY_B_AC_DIS_PRF	(1<<7)	/* Bit  7:	dis part resp filter */
 									/* Bit  6:	reserved */
@@ -942,14 +1050,14 @@
 #define PHY_B_AC_DIAG		(1<<3)	/* Bit  3:	Diagnostic Mode */
 									/* Bit  2.. 0:	reserved */
 
-/*****	PHY_BCOM_AUX_STAT	16 bit ro	Auxiliary Status Reg *****/
+/*****  PHY_BCOM_AUX_STAT	16 bit r/o	Auxiliary Status Reg *****/
 #define PHY_B_AS_AN_C		(1<<15)	/* Bit 15:	AutoNeg complete */
 #define PHY_B_AS_AN_CA		(1<<14)	/* Bit 14:	AN Complete Ack */
 #define PHY_B_AS_ANACK_D	(1<<13)	/* Bit 13:	AN Ack Detect */
 #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_AN_RES_MSK	(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 */
@@ -958,8 +1066,10 @@
 #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 *****/
+#define PHY_B_AS_PAUSE_MSK	(PHY_B_AS_PRR | PHY_B_AS_PRT)
+
+/*****  PHY_BCOM_INT_STAT	16 bit r/o	Interrupt Status Reg *****/
+/*****  PHY_BCOM_INT_MASK	16 bit r/w	Interrupt Mask Reg *****/
 									/* 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 */
@@ -979,125 +1089,123 @@
 
 #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
- */
-#define PHY_B_P_NO_PAUSE	(0<<10)	/* Bit	11..10:	no Pause Mode */
-#define PHY_B_P_SYM_MD		(1<<10)	/* Bit	11..10:	symmetric Pause Mode */
-#define PHY_B_P_ASYM_MD		(2<<10)	/* Bit	11..10:	asymmetric Pause Mode */
-#define PHY_B_P_BOTH_MD		(3<<10)	/* Bit	11..10:	both Pause Mode */
+/* Pause Bits (PHY_B_AN_ASP and PHY_B_AN_PC) encoding */
+#define PHY_B_P_NO_PAUSE	(0<<10)	/* Bit 11..10:	no Pause Mode */
+#define PHY_B_P_SYM_MD		(1<<10)	/* Bit 11..10:	symmetric Pause Mode */
+#define PHY_B_P_ASYM_MD		(2<<10)	/* Bit 11..10:	asymmetric Pause Mode */
+#define PHY_B_P_BOTH_MD		(3<<10)	/* Bit 11..10:	both Pause Mode */
 
 /*
  * Resolved Duplex mode and Capabilities (Aux Status Summary Reg)
  */
-#define	PHY_B_RES_1000FD	(7<<8)	/* Bit	10..8:	1000Base-T Full Dup. */
-#define	PHY_B_RES_1000HD	(6<<8)	/* Bit	10..8:	1000Base-T Half Dup. */
+#define PHY_B_RES_1000FD	(7<<8)	/* Bit 10..8:	1000Base-T Full Dup. */
+#define PHY_B_RES_1000HD	(6<<8)	/* Bit 10..8:	1000Base-T Half Dup. */
 /* others: 100/10: invalid for us */
 
 /*
  * Level One-Specific
  */
-/*****	PHY_LONE_1000T_CTRL	16 bit r/w	1000Base-T Control Reg *****/
-#define PHY_L_1000C_TEST	(7<<13)	/* Bit	15..13:	Test Modes */
-#define PHY_L_1000C_MSE		(1<<12)	/* Bit	12:	Master/Slave Enable */
-#define PHY_L_1000C_MSC		(1<<11)	/* Bit	11:	M/S Configuration */
-#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 */
-
-/*****	PHY_LONE_1000T_STAT	16 bit ro	1000Base-T Status Reg *****/
-#define PHY_L_1000S_MSF		(1<<15)	/* Bit	15:	Master/Slave Fault */
-#define PHY_L_1000S_MSR		(1<<14)	/* Bit	14:	Master/Slave Result */
-#define PHY_L_1000S_LRS		(1<<13)	/* Bit	13:	Local Receiver Status */
-#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 */
-#define PHY_B_1000S_IEC		(255<<0)/* Bit	7..0:	Idle Error Count */
+/*****  PHY_LONE_1000T_CTRL	16 bit r/w	1000Base-T Control Reg *****/
+#define PHY_L_1000C_TEST	(7<<13)	/* Bit 15..13:	Test Modes */
+#define PHY_L_1000C_MSE		(1<<12)	/* Bit 12:	Master/Slave Enable */
+#define PHY_L_1000C_MSC		(1<<11)	/* Bit 11:	M/S Configuration */
+#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 */
+
+/*****  PHY_LONE_1000T_STAT	16 bit r/o	1000Base-T Status Reg *****/
+#define PHY_L_1000S_MSF		(1<<15)	/* Bit 15:	Master/Slave Fault */
+#define PHY_L_1000S_MSR		(1<<14)	/* Bit 14:	Master/Slave Result */
+#define PHY_L_1000S_LRS		(1<<13)	/* Bit 13:	Local Receiver Status */
+#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 */
+#define PHY_B_1000S_IEC		0xff	/* Bit  7..0:	Idle Error Count */
 
-/*****	PHY_LONE_EXT_STAT	16 bit ro	Extended Status Register *****/
+/*****  PHY_LONE_EXT_STAT	16 bit r/o	Extended Status Register *****/
 #define PHY_L_ES_X_FD_CAP	(1<<15)	/* Bit 15:	1000Base-X FD capable */
 #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 */
 
-/*****	PHY_LONE_PORT_CFG	16 bit r/w	Port Configuration Reg *****/
+/*****  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 */
 #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 */
 #define PHY_L_PC_JAB_DIS	(1<<10)	/* Bit 10:	Jabber Disabled */
-#define PHY_L_PC_SQE		(1<<9)	/* Bit 9:	Enable Heartbeat */
-#define PHY_L_PC_TP_LOOP	(1<<8)	/* Bit 8:	TP Loopback */
-#define PHY_L_PC_SSS		(1<<7)	/* Bit 7:	Smart Speed Selection */
-#define PHY_L_PC_FIFO_SIZE	(1<<6)	/* Bit 6:	FIFO Size */
-#define PHY_L_PC_PRE_EN		(1<<5)	/* Bit 5:	Preamble Enable */
-#define PHY_L_PC_CIM		(1<<4)	/* Bit 4:	Carrier Integrity Mon */
-#define PHY_L_PC_10_SER		(1<<3)	/* Bit 3:	Use Serial Output */
-#define PHY_L_PC_ANISOL		(1<<2)	/* Bit 2:	Unisolate Port */
-#define PHY_L_PC_TEN_BIT	(1<<1)	/* Bit 1:	10bit iface mode on */
-#define PHY_L_PC_ALTCLOCK	(1<<0)	/* Bit 0: (ro)	ALTCLOCK Mode on */
+#define PHY_L_PC_SQE		(1<<9)	/* Bit  9:	Enable Heartbeat */
+#define PHY_L_PC_TP_LOOP	(1<<8)	/* Bit  8:	TP Loopback */
+#define PHY_L_PC_SSS		(1<<7)	/* Bit  7:	Smart Speed Selection */
+#define PHY_L_PC_FIFO_SIZE	(1<<6)	/* Bit  6:	FIFO Size */
+#define PHY_L_PC_PRE_EN		(1<<5)	/* Bit  5:	Preamble Enable */
+#define PHY_L_PC_CIM		(1<<4)	/* Bit  4:	Carrier Integrity Mon */
+#define PHY_L_PC_10_SER		(1<<3)	/* Bit  3:	Use Serial Output */
+#define PHY_L_PC_ANISOL		(1<<2)	/* Bit  2:	Unisolate Port */
+#define PHY_L_PC_TEN_BIT	(1<<1)	/* Bit  1:	10bit iface mode on */
+#define PHY_L_PC_ALTCLOCK	(1<<0)	/* Bit  0: (ro)	ALTCLOCK Mode on */
 
-/*****	PHY_LONE_Q_STAT		16 bit ro	Quick Status Reg *****/
+/*****  PHY_LONE_Q_STAT		16 bit r/o	Quick Status Reg *****/
 #define PHY_L_QS_D_RATE		(3<<14)	/* Bit 15..14:	Data Rate */
 #define PHY_L_QS_TX_STAT	(1<<13)	/* Bit 13:	Transmitting */
 #define PHY_L_QS_RX_STAT	(1<<12)	/* Bit 12:	Receiving */
 #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_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 */
-#define PHY_L_QS_AS_PAUSE	(1<<2)	/* Bit 2:	LP adv. asym. Pause */
-#define PHY_L_QS_ISOLATE	(1<<1)	/* Bit 1:	CIM Isolated */
-#define PHY_L_QS_EVENT		(1<<0)	/* Bit 0:	Event has occurred */
+#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_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 */
+#define PHY_L_QS_AS_PAUSE	(1<<2)	/* Bit  2:	LP adv. asym. Pause */
+#define PHY_L_QS_ISOLATE	(1<<1)	/* Bit  1:	CIM Isolated */
+#define PHY_L_QS_EVENT		(1<<0)	/* Bit  0:	Event has occurred */
 
-/*****	PHY_LONE_INT_ENAB	16 bit r/w	Interrupt Enable Reg *****/
-/*****	PHY_LONE_INT_STAT	16 bit ro	Interrupt Status Reg *****/
+/*****  PHY_LONE_INT_ENAB	16 bit r/w	Interrupt Enable Reg *****/
+/*****  PHY_LONE_INT_STAT	16 bit r/o	Interrupt Status Reg *****/
 									/* Bit 15..14:	reserved */
-#define PHY_L_IS_AN_F		(1<<13)	/* Bit 13:	Autoneg fault */
+#define PHY_L_IS_AN_F		(1<<13)	/* Bit 13:	Auto-Negotiation fault */
 									/* 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_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_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_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_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 */
 
 /* 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 *****/
+/*****  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 */
 #define PHY_L_LC_LEDR		(3<<12)	/* Bit 13..12:	Rx/Blink/On/Off */
 #define PHY_L_LC_LEDT		(3<<10)	/* Bit 11..10:	Tx/Blink/On/Off */
-#define PHY_L_LC_LEDG		(3<<8)	/* Bit 9..8:	Giga/Blink/On/Off */
-#define PHY_L_LC_LEDS		(3<<6)	/* Bit 7..6:	10-100/Blink/On/Off */
-#define PHY_L_LC_LEDL		(3<<4)	/* Bit 5..4:	Link/Blink/On/Off */
-#define PHY_L_LC_LEDF		(3<<2)	/* Bit 3..2:	Duplex/Blink/On/Off */
-#define PHY_L_LC_PSTRECH	(1<<1)	/* Bit 1:	Strech LED Pulses */
-#define PHY_L_LC_FREQ		(1<<0)	/* Bit 0:	30/100 ms */
+#define PHY_L_LC_LEDG		(3<<8)	/* Bit  9..8:	Giga/Blink/On/Off */
+#define PHY_L_LC_LEDS		(3<<6)	/* Bit  7..6:	10-100/Blink/On/Off */
+#define PHY_L_LC_LEDL		(3<<4)	/* Bit  5..4:	Link/Blink/On/Off */
+#define PHY_L_LC_LEDF		(3<<2)	/* Bit  3..2:	Duplex/Blink/On/Off */
+#define PHY_L_LC_PSTRECH	(1<<1)	/* Bit  1:	Strech LED Pulses */
+#define PHY_L_LC_FREQ		(1<<0)	/* Bit  0:	30/100 ms */
 
-/*****	PHY_LONE_PORT_CTRL	16 bit r/w	Port Control Reg *****/
+/*****  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 */
 #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 */
 #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 *****/
+/*****  PHY_LONE_CIM		16 bit r/o	CIM Reg *****/
 #define PHY_L_CIM_ISOL		(255<<8)/* Bit 15..8:	Isolate Count */
 #define PHY_L_CIM_FALSE_CAR	(255<<0)/* Bit  7..0:	False Carrier Count */
 
@@ -1105,37 +1213,37 @@
 /*
  * Pause Bits (PHY_L_AN_ASP and PHY_L_AN_PC) encoding
  */
-#define PHY_L_P_NO_PAUSE	(0<<10)	/* Bit	11..10:	no Pause Mode */
-#define PHY_L_P_SYM_MD		(1<<10)	/* Bit	11..10:	symmetric Pause Mode */
-#define PHY_L_P_ASYM_MD		(2<<10)	/* Bit	11..10:	asymmetric Pause Mode */
-#define PHY_L_P_BOTH_MD		(3<<10)	/* Bit	11..10:	both Pause Mode */
+#define PHY_L_P_NO_PAUSE	(0<<10)	/* Bit 11..10:	no Pause Mode */
+#define PHY_L_P_SYM_MD		(1<<10)	/* Bit 11..10:	symmetric Pause Mode */
+#define PHY_L_P_ASYM_MD		(2<<10)	/* Bit 11..10:	asymmetric Pause Mode */
+#define PHY_L_P_BOTH_MD		(3<<10)	/* Bit 11..10:	both Pause Mode */
 
 
 /*
  * National-Specific
  */
-/***** PHY_NAT_1000T_CTRL	16 bit r/w	1000Base-T Control Reg *****/
-#define PHY_N_1000C_TEST	(7<<13)	/* Bit	15..13:	Test Modes */
-#define PHY_N_1000C_MSE		(1<<12)	/* Bit	12:	Master/Slave Enable */
-#define PHY_N_1000C_MSC		(1<<11)	/* Bit	11:	M/S Configuration */
-#define PHY_N_1000C_RD		(1<<10)	/* Bit	10:	Repeater/DTE */
-#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 */
-
-/***** PHY_NAT_1000T_STAT	16 bit ro	1000Base-T Status Reg *****/
-#define PHY_N_1000S_MSF		(1<<15)	/* Bit	15:	Master/Slave Fault */
-#define PHY_N_1000S_MSR		(1<<14)	/* Bit	14:	Master/Slave Result */
-#define PHY_N_1000S_LRS		(1<<13)	/* Bit	13:	Local Receiver Status */
-#define PHY_N_1000S_RRS		(1<<12)	/* Bit	12:	Remote Receiver Status*/
-#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 */
-#define PHY_N_1000S_IEC		(255<<0)/* Bit	7..0:	Idle Error Count */
+/*****  PHY_NAT_1000T_CTRL	16 bit r/w	1000Base-T Control Reg *****/
+#define PHY_N_1000C_TEST	(7<<13)	/* Bit 15..13:	Test Modes */
+#define PHY_N_1000C_MSE		(1<<12)	/* Bit 12:	Master/Slave Enable */
+#define PHY_N_1000C_MSC		(1<<11)	/* Bit 11:	M/S Configuration */
+#define PHY_N_1000C_RD		(1<<10)	/* Bit 10:	Repeater/DTE */
+#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:	Asymmetric Pause Cap. */
+									/* Bit  6..0:	reserved */
+
+/*****  PHY_NAT_1000T_STAT	16 bit r/o	1000Base-T Status Reg *****/
+#define PHY_N_1000S_MSF		(1<<15)	/* Bit 15:	Master/Slave Fault */
+#define PHY_N_1000S_MSR		(1<<14)	/* Bit 14:	Master/Slave Result */
+#define PHY_N_1000S_LRS		(1<<13)	/* Bit 13:	Local Receiver Status */
+#define PHY_N_1000S_RRS		(1<<12)	/* Bit 12:	Remote Receiver Status*/
+#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 */
+#define PHY_N_1000S_IEC		0xff	/* Bit  7..0:	Idle Error Count */
 
-/*****	PHY_NAT_EXT_STAT	16 bit ro	Extended Status Register *****/
+/*****  PHY_NAT_EXT_STAT	16 bit r/o	Extended Status Register *****/
 #define PHY_N_ES_X_FD_CAP	(1<<15)	/* Bit 15:	1000Base-X FD capable */
 #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 */
@@ -1143,12 +1251,461 @@
 									/* Bit 11..0:	reserved */
 
 /* todo: those are still missing */
-/*****	PHY_NAT_EXT_CTRL1	16 bit ro	Extended Control Reg1 *****/
-/*****	PHY_NAT_Q_STAT1		16 bit ro	Quick Status Reg1 *****/
-/*****	PHY_NAT_10B_OP		16 bit ro	10Base-T Operations Reg *****/
-/*****	PHY_NAT_EXT_CTRL2	16 bit ro	Extended Control Reg1 *****/
-/*****	PHY_NAT_Q_STAT2		16 bit ro	Quick Status Reg2 *****/
-/*****	PHY_NAT_PHY_ADDR	16 bit ro	PHY Address Register *****/
+/*****  PHY_NAT_EXT_CTRL1	16 bit r/o	Extended Control Reg1 *****/
+/*****  PHY_NAT_Q_STAT1		16 bit r/o	Quick Status Reg1 *****/
+/*****  PHY_NAT_10B_OP		16 bit r/o	10Base-T Operations Reg *****/
+/*****  PHY_NAT_EXT_CTRL2	16 bit r/o	Extended Control Reg1 *****/
+/*****  PHY_NAT_Q_STAT2		16 bit r/o	Quick Status Reg2 *****/
+/*****  PHY_NAT_PHY_ADDR	16 bit r/o	PHY Address Register *****/
+
+/*
+ * Marvell-Specific
+ */
+/*****  PHY_MARV_AUNE_ADV	16 bit r/w	Auto-Negotiation Advertisement *****/
+#define PHY_M_AN_NXT_PG		BIT_15	/* Request Next Page */
+									/* Bit 14:	reserved */
+#define PHY_M_AN_RF			BIT_13	/* Remote Fault */
+									/* Bit 12:	reserved */
+#define PHY_M_AN_ASP		BIT_11	/* Asymmetric Pause */
+#define PHY_M_AN_PC			BIT_10	/* MAC Pause implemented */
+#define PHY_M_AN_100_FD		BIT_8	/* Advertise 100Base-TX Full Duplex */
+#define PHY_M_AN_100_HD		BIT_7	/* Advertise 100Base-TX Half Duplex */
+#define PHY_M_AN_10_FD		BIT_6	/* Advertise 10Base-TX Full Duplex */
+#define PHY_M_AN_10_HD		BIT_5	/* Advertise 10Base-TX Half Duplex */
+
+/* special defines for FIBER (88E1011S only) */
+#define PHY_M_AN_ASP_X		BIT_8	/* Asymmetric Pause */
+#define PHY_M_AN_PC_X		BIT_7	/* MAC Pause implemented */
+#define PHY_M_AN_1000X_AHD	BIT_6	/* Advertise 10000Base-X Half Duplex */
+#define PHY_M_AN_1000X_AFD	BIT_5	/* Advertise 10000Base-X Full Duplex */
+
+/* Pause Bits (PHY_M_AN_ASP_X and PHY_M_AN_PC_X) encoding */
+#define PHY_M_P_NO_PAUSE_X	(0<<7)	/* Bit  8.. 7:	no Pause Mode */
+#define PHY_M_P_SYM_MD_X	(1<<7)	/* Bit  8.. 7:	symmetric Pause Mode */
+#define PHY_M_P_ASYM_MD_X	(2<<7)	/* Bit  8.. 7:	asymmetric Pause Mode */
+#define PHY_M_P_BOTH_MD_X	(3<<7)	/* Bit  8.. 7:	both Pause Mode */
+
+/*****  PHY_MARV_1000T_CTRL	16 bit r/w	1000Base-T Control Reg *****/
+#define PHY_M_1000C_TEST	(7<<13)	/* Bit 15..13:	Test Modes */
+#define PHY_M_1000C_MSE		(1<<12)	/* Bit 12:	Manual Master/Slave Enable */
+#define PHY_M_1000C_MSC		(1<<11)	/* Bit 11:	M/S Configuration (1=Master) */
+#define PHY_M_1000C_MPD		(1<<10)	/* Bit 10:	Multi-Port Device */
+#define PHY_M_1000C_AFD		(1<<9)	/* Bit  9:	Advertise Full Duplex */
+#define PHY_M_1000C_AHD		(1<<8)	/* Bit  8:	Advertise Half Duplex */
+									/* Bit  7..0:	reserved */
+
+/*****  PHY_MARV_PHY_CTRL	16 bit r/w	PHY Specific Ctrl Reg *****/
+
+#define PHY_M_PC_TX_FFD_MSK	(3<<14)	/* Bit 15..14:	Tx FIFO Depth Mask */
+#define PHY_M_PC_RX_FFD_MSK	(3<<12)	/* Bit 13..12:	Rx FIFO Depth Mask */
+#define PHY_M_PC_ASS_CRS_TX	(1<<11)	/* Bit 11:	Assert CRS on Transmit */
+#define PHY_M_PC_FL_GOOD	(1<<10)	/* Bit 10:	Force Link Good */
+#define PHY_M_PC_EN_DET_MSK	(3<<8)	/* Bit  9.. 8:	Energy Detect Mask */
+#define PHY_M_PC_ENA_EXT_D	(1<<7)	/* Bit  7:	Enable Ext. Distance (10BT) */
+#define PHY_M_PC_MDIX_MSK	(3<<5)	/* Bit  6.. 5:	MDI/MDIX Config. Mask */
+#define PHY_M_PC_DIS_125CLK	(1<<4)	/* Bit  4:	Disable 125 CLK */
+#define PHY_M_PC_MAC_POW_UP	(1<<3)	/* Bit  3:	MAC Power up */
+#define PHY_M_PC_SQE_T_ENA	(1<<2)	/* Bit  2:	SQE Test Enabled */
+#define PHY_M_PC_POL_R_DIS	(1<<1)	/* Bit  1:	Polarity Reversal Disabled */
+#define PHY_M_PC_DIS_JABBER	(1<<0)	/* Bit  0:	Disable Jabber */
+
+
+/*****  PHY_MARV_PHY_STAT	16 bit r/o	PHY Specific Status Reg *****/
+#define PHY_M_PS_SPEED_MSK	(3<<14)	/* Bit 15..14:	Speed Mask */
+#define PHY_M_PS_SPEED_1000	(1<<15)	/*       10 = 1000 Mbps */
+#define PHY_M_PS_SPEED_100	(1<<14)	/*       01 =  100 Mbps */
+#define PHY_M_PS_SPEED_10	0		/*       00 =   10 Mbps */
+#define PHY_M_PS_FULL_DUP	(1<<13)	/* Bit 13:	Full Duplex */
+#define PHY_M_PS_PAGE_REC	(1<<12)	/* Bit 12:	Page Received */
+#define PHY_M_PS_SPDUP_RES	(1<<11)	/* Bit 11:	Speed & Duplex Resolved */
+#define PHY_M_PS_LINK_UP	(1<<10)	/* Bit 10:	Link Up */
+#define PHY_M_PS_CABLE_MSK	(3<<7)	/* Bit  9.. 7:	Cable Length Mask */
+#define PHY_M_PS_MDI_X_STAT	(1<<6)	/* Bit  6:	MDI Crossover Stat (1=MDIX) */
+#define PHY_M_PS_DOWNS_STAT	(1<<5)	/* Bit  5:	Downshift Status (1=downsh.) */
+#define PHY_M_PS_ENDET_STAT	(1<<4)	/* Bit  4:	Energy Detect Status (1=act) */
+#define PHY_M_PS_TX_P_EN	(1<<3)	/* Bit  3:	Tx Pause Enabled */
+#define PHY_M_PS_RX_P_EN	(1<<2)	/* Bit  2:	Rx Pause Enabled */
+#define PHY_M_PS_POL_REV	(1<<1)	/* Bit  1:	Polarity Reversed */
+#define PHY_M_PC_JABBER		(1<<0)	/* Bit  0:	Jabber */
+
+#define PHY_M_PS_PAUSE_MSK	(PHY_M_PS_TX_P_EN | PHY_M_PS_RX_P_EN)
+
+/*****  PHY_MARV_INT_MASK	16 bit r/w	Interrupt Mask Reg *****/
+/*****  PHY_MARV_INT_STAT	16 bit r/o	Interrupt Status Reg *****/
+#define PHY_M_IS_AN_ERROR	(1<<15)	/* Bit 15:	Auto-Negotiation Error */
+#define PHY_M_IS_LSP_CHANGE	(1<<14)	/* Bit 14:	Link Speed Changed */
+#define PHY_M_IS_DUP_CHANGE	(1<<13)	/* Bit 13:	Duplex Mode Changed */
+#define PHY_M_IS_AN_PR		(1<<12)	/* Bit 12:	Page Received */
+#define PHY_M_IS_AN_COMPL	(1<<11)	/* Bit 11:	Auto-Negotiation Completed */
+#define PHY_M_IS_LST_CHANGE	(1<<10)	/* Bit 10:	Link Status Changed */
+#define PHY_M_IS_SYMB_ERROR	(1<<9)	/* Bit  9:	Symbol Error */
+#define PHY_M_IS_FALSE_CARR	(1<<8)	/* Bit  8:	False Carrier */
+#define PHY_M_IS_FIFO_ERROR	(1<<7)	/* Bit  7:	FIFO Overflow/Underrun Error */
+#define PHY_M_IS_MDI_CHANGE	(1<<6)	/* Bit  6:	MDI Crossover Changed */
+#define PHY_M_IS_DOWNSH_DET	(1<<5)	/* Bit  5:	Downshift Detected */
+#define PHY_M_IS_END_CHANGE	(1<<4)	/* Bit  4:	Energy Detect Changed */
+									/* Bit  3..2:	reserved */
+#define PHY_M_IS_POL_CHANGE	(1<<1)	/* Bit  1:	Polarity Changed */
+#define PHY_M_IS_JABBER		(1<<0)	/* Bit  0:	Jabber */
+
+#define PHY_M_DEF_MSK		(PHY_M_IS_AN_ERROR | PHY_M_IS_AN_PR | \
+							PHY_M_IS_LST_CHANGE | PHY_M_IS_FIFO_ERROR)
+
+/*****  PHY_MARV_EXT_CTRL	16 bit r/w	Ext. PHY Specific Ctrl *****/
+#define PHY_M_EC_M_DSC_MSK	(3<<10)	/* Bit 11..10:	Master downshift counter */
+#define PHY_M_EC_S_DSC_MSK	(3<<8)	/* Bit  9.. 8:	Slave  downshift counter */
+#define PHY_M_EC_MAC_S_MSK	(7<<4)	/* Bit  6.. 4:	Def. MAC interface speed */
+
+#define PHY_M_EC_M_DSC(x)		SHIFT10(x)	/* 00=1x; 01=2x; 10=3x; 11=4x */
+#define PHY_M_EC_S_DSC(x)		SHIFT8(x)	/* 00=dis; 01=1x; 10=2x; 11=3x */
+#define PHY_M_EC_MAC_S(x)		SHIFT4(x)	/* 01X=0; 110=2.5; 111=25 (MHz) */
+
+#define MAC_TX_CLK_0_MHZ	2
+#define MAC_TX_CLK_2_5_MHZ	6
+#define MAC_TX_CLK_25_MHZ	7
+
+/*****  PHY_MARV_LED_CTRL	16 bit r/w	LED Control Reg *****/
+#define PHY_M_LEDC_DIS_LED	(1<<15)	/* Bit 15:	Disable LED */
+
+#define PHY_M_LED_BL_RATE(x)	SHIFT12(x)	/* Bit 12..14:  Blink Rate */
+
+/* values for PHY_M_LED_BL_RATE() */
+#define	BL_DEFAULT	0		/* no pulse stretching */
+#define	BL_21MS		1		/* 21 ms to 42ms */
+#define BL_42MS		2		/* 42 ms to 84ms */
+#define BL_84MS		3		/* 84 ms to 170ms */
+#define BL_170MS	4		/* 170 ms to340ms */
+#define BL_340MS	5		/* 340 ms to670ms */
+#define BL_670MS	6		/* 670 ms to 1.3s */
+#define BL_1300MS	7		/* 1.3s to 2.7s */
+
+#define PHY_M_LEDC_F_INT	(1<<11)	/* Bit 11:	Force Interrupt */
+
+#define PHY_M_LEDC_LINK_MSK	(3<<3)	/* Bit  4..3:	Link Control */
+#define PHY_M_LEDC_DP_CTRL	(1<<2)	/* Bit  2:	Duplex Control */
+#define PHY_M_LEDC_RX_CTRL	(1<<1)	/* Bit  1:	Rx activity / Link */
+#define PHY_M_LEDC_TX_CTRL	(1<<0)	/* Bit  0:	Tx activity / Link */
+
+/*****  PHY_MARV_LED_OVER	16 bit r/w	Manual LED Override Reg *****/
+#define PHY_M_LED_MO_DUP(x)		SHIFT10(x)	/* Bit 11..10:  Duplex */
+#define PHY_M_LED_MO_10(x)		SHIFT8(x)	/* Bit  9.. 8:  Link 10 */
+#define PHY_M_LED_MO_100(x)		SHIFT6(x)	/* Bit  7.. 6:  Link 100 */
+#define PHY_M_LED_MO_1000(x)	SHIFT4(x)	/* Bit  5.. 4:  Link 1000 */
+#define PHY_M_LED_MO_RX(x)		SHIFT2(x)	/* Bit  3.. 2:  Rx */
+#define PHY_M_LED_MO_TX(x)		SHIFT0(x)	/* Bit  1.. 0:  Tx */
+
+#define MO_LED_NORM			0
+#define MO_LED_BLINK		1
+#define MO_LED_OFF			2
+#define MO_LED_ON			3
+
+/*****  PHY_MARV_EXT_CTRL_2	16 bit r/w	Ext. PHY Specific Ctrl 2 *****/
+									/* Bit 15.. 7:	reserved */
+#define PHY_M_EC2_FI_IMPED	(1<<6)	/* Bit  6:	Fiber Input  Impedance */
+#define PHY_M_EC2_FO_IMPED	(1<<5)	/* Bit  5:	Fiber Output Impedance */
+#define PHY_M_EC2_FO_M_CLK	(1<<4)	/* Bit  4:	Fiber Mode Clock Enable */
+#define PHY_M_EC2_FO_BOOST	(1<<3)	/* Bit  3:	Fiber Output Boost */
+#define PHY_M_EC2_FO_AM_MSK	7		/* Bit  2.. 0:	Fiber Output Amplitude */
+
+/*****  PHY_MARV_CABLE_DIAG	16 bit r/o	Cable Diagnostic Reg *****/
+#define PHY_M_CABD_ENA_TEST	(1<<15)	/* Bit 15:	Enable Test */
+#define PHY_M_CABD_STAT_MSK	(3<<13)	/* Bit 14..13:	Status */
+									/* Bit 12.. 8:	reserved */
+#define PHY_M_CABD_DIST_MSK	0xff	/* Bit  7.. 0:	Distance */
+
+/* values for Cable Diagnostic Status (11=fail; 00=OK; 10=open; 01=short) */
+#define CABD_STAT_NORMAL	0
+#define CABD_STAT_SHORT		1
+#define CABD_STAT_OPEN		2
+#define CABD_STAT_FAIL		3
+
+
+/*
+ * GMAC registers
+ *
+ * The GMAC registers are 16 or 32 bits wide.
+ * The GMACs host processor interface is 16 bits wide,
+ * therefore ALL registers will be addressed with 16 bit accesses.
+ *
+ * The following macros are provided to access the GMAC registers
+ * GM_IN16(), GM_OUT16, GM_IN32(), GM_OUT32(), GM_INADR(), GM_OUTADR(),
+ * GM_INHASH(), and GM_OUTHASH().
+ * The macros are defined in SkGeHw.h.
+ *
+ * Note:	NA reg	= Network Address e.g DA, SA etc.
+ *
+ */
+
+/* Port Registers */
+#define GM_GP_STAT		0x0000		/* 16 bit r/o	General Purpose Status */
+#define GM_GP_CTRL		0x0004		/* 16 bit r/w	General Purpose Control */
+#define GM_TX_CTRL		0x0008		/* 16 bit r/w	Transmit Control Reg. */
+#define GM_RX_CTRL		0x000c		/* 16 bit r/w	Receive Control Reg. */
+#define GM_TX_FLOW_CTRL	0x0010		/* 16 bit r/w	Transmit Flow Control */
+#define GM_TX_PARAM		0x0014		/* 16 bit r/w	Transmit Parameter Reg. */
+#define GM_SERIAL_MODE	0x0018		/* 16 bit r/w	Serial Mode Register */
+
+/* Source Address Registers */
+#define GM_SRC_ADDR_1L	0x001c		/* 16 bit r/w	Source Address 1 (low) */
+#define GM_SRC_ADDR_1M	0x0020		/* 16 bit r/w	Source Address 1 (middle) */
+#define GM_SRC_ADDR_1H	0x0024		/* 16 bit r/w	Source Address 1 (high) */
+#define GM_SRC_ADDR_2L	0x0028		/* 16 bit r/w	Source Address 2 (low) */
+#define GM_SRC_ADDR_2M	0x002c		/* 16 bit r/w	Source Address 2 (middle) */
+#define GM_SRC_ADDR_2H	0x0030		/* 16 bit r/w	Source Address 2 (high) */
+
+/* Multicast Address Hash Registers */
+#define GM_MC_ADDR_H1	0x0034		/* 16 bit r/w	Multicast Address Hash 1 */
+#define GM_MC_ADDR_H2	0x0038		/* 16 bit r/w	Multicast Address Hash 2 */
+#define GM_MC_ADDR_H3	0x003c		/* 16 bit r/w	Multicast Address Hash 3 */
+#define GM_MC_ADDR_H4	0x0040		/* 16 bit r/w	Multicast Address Hash 4 */
+
+/* Interrupt Source Registers */
+#define GM_TX_IRQ_SRC	0x0044		/* 16 bit r/o	Tx Overflow IRQ Source */
+#define GM_RX_IRQ_SRC	0x0048		/* 16 bit r/o	Rx Overflow IRQ Source */
+#define GM_TR_IRQ_SRC	0x004c		/* 16 bit r/o	Tx/Rx Over. IRQ Source */
+
+/* Interrupt Mask Registers */
+#define GM_TX_IRQ_MSK	0x0050		/* 16 bit r/w	Tx Overflow IRQ Mask */
+#define GM_RX_IRQ_MSK	0x0054		/* 16 bit r/w	Rx Overflow IRQ Mask */
+#define GM_TR_IRQ_MSK	0x0058		/* 16 bit r/w	Tx/Rx Over. IRQ Mask */
+
+/* Serial Management Interface (SMI) Registers */
+#define GM_SMI_CTRL		0x0080		/* 16 bit r/w	SMI Control Register */
+#define GM_SMI_DATA		0x0084		/* 16 bit r/w	SMI Data Register */
+#define GM_PHY_ADDR		0x0088		/* 16 bit r/w	GPHY Address Register */
+
+/* MIB Counters */
+#define GM_MIB_CNT_BASE	0x0100		/* Base Address of MIB Counters */
+#define GM_MIB_CNT_SIZE	44			/* Number of MIB Counters */
+
+/*
+ * MIB Counters base address definitions (low word) -
+ * use offset 4 for access to high word	(32 bit r/o)
+ */
+#define GM_RXF_UC_OK \
+			(GM_MIB_CNT_BASE + 0)	/* Unicast Frames Received OK */
+#define GM_RXF_BC_OK \
+			(GM_MIB_CNT_BASE + 8)	/* Broadcast Frames Received OK */
+#define GM_RXF_MPAUSE \
+			(GM_MIB_CNT_BASE + 16)	/* Pause MAC Ctrl Frames Received */
+#define GM_RXF_MC_OK \
+			(GM_MIB_CNT_BASE + 24)	/* Multicast Frames Received OK */
+#define GM_RXF_FCS_ERR \
+			(GM_MIB_CNT_BASE + 32)	/* Rx Frame Check Seq. Error */
+	/* GM_MIB_CNT_BASE + 40:	reserved */
+#define GM_RXO_OK_LO \
+			(GM_MIB_CNT_BASE + 48)	/* Octets Received OK Low */
+#define GM_RXO_OK_HI \
+			(GM_MIB_CNT_BASE + 56)	/* Octets Received OK High */
+#define GM_RXO_ERR_LO \
+			(GM_MIB_CNT_BASE + 64)	/* Octets Received Invalid Low */
+#define GM_RXO_ERR_HI \
+			(GM_MIB_CNT_BASE + 72)	/* Octets Received Invalid High */
+#define GM_RXF_SHT \
+			(GM_MIB_CNT_BASE + 80)	/* Frames <64 Byte Received OK */
+#define GM_RXE_FRAG \
+			(GM_MIB_CNT_BASE + 88)	/* Frames <64 Byte Receeived with FCS Err */
+#define GM_RXF_64B \
+			(GM_MIB_CNT_BASE + 96)	/* 64 Byte Rx Frame */
+#define GM_RXF_127B \
+			(GM_MIB_CNT_BASE + 104)	/* 65-127 Byte Rx Frame */
+#define GM_RXF_255B \
+			(GM_MIB_CNT_BASE + 112)	/* 128-255 Byte Rx Frame */
+#define GM_RXF_511B \
+			(GM_MIB_CNT_BASE + 120)	/* 256-511 Byte Rx Frame */
+#define GM_RXF_1023B \
+			(GM_MIB_CNT_BASE + 128)	/* 512-1023 Byte Rx Frame */
+#define GM_RXF_1518B \
+			(GM_MIB_CNT_BASE + 136)	/* 1024-1518 Byte Rx Frame */
+#define GM_RXF_MAX_SZ \
+			(GM_MIB_CNT_BASE + 144)	/* 1519-MaxSize Byte Rx Frame */
+#define GM_RXF_LNG_ERR \
+			(GM_MIB_CNT_BASE + 152)	/* Rx Frame too Long Error */
+#define GM_RXF_JAB_PKT \
+			(GM_MIB_CNT_BASE + 160)	/* Rx Jabber Packet Frame */
+	/* GM_MIB_CNT_BASE + 168:	reserved */
+#define GM_RXE_FIFO_OV \
+			(GM_MIB_CNT_BASE + 176)	/* Rx FIFO overflow Event */
+	/* GM_MIB_CNT_BASE + 184:	reserved */
+#define GM_TXF_UC_OK \
+			(GM_MIB_CNT_BASE + 192)	/* Unicast Frames Xmitted OK */
+#define GM_TXF_BC_OK \
+			(GM_MIB_CNT_BASE + 200)	/* Broadcast Frames Xmitted OK */
+#define GM_TXF_MPAUSE \
+			(GM_MIB_CNT_BASE + 208)	/* Pause MAC Ctrl Frames Xmitted */
+#define GM_TXF_MC_OK \
+			(GM_MIB_CNT_BASE + 216)	/* Multicast Frames Xmitted OK */
+#define GM_TXO_OK_LO \
+			(GM_MIB_CNT_BASE + 224)	/* Octets Transmitted OK Low */
+#define GM_TXO_OK_HI \
+			(GM_MIB_CNT_BASE + 232)	/* Octets Transmitted OK High */
+#define GM_TXF_64B \
+			(GM_MIB_CNT_BASE + 240)	/* 64 Byte Tx Frame */
+#define GM_TXF_127B \
+			(GM_MIB_CNT_BASE + 248)	/* 65-127 Byte Tx Frame */
+#define GM_TXF_255B \
+			(GM_MIB_CNT_BASE + 256)	/* 128-255 Byte Tx Frame */
+#define GM_TXF_511B \
+			(GM_MIB_CNT_BASE + 264)	/* 256-511 Byte Tx Frame */
+#define GM_TXF_1023B \
+			(GM_MIB_CNT_BASE + 272)	/* 512-1023 Byte Tx Frame */
+#define GM_TXF_1518B \
+			(GM_MIB_CNT_BASE + 280)	/* 1024-1518 Byte Tx Frame */
+#define GM_TXF_MAX_SZ \
+			(GM_MIB_CNT_BASE + 288)	/* 1519-MaxSize Byte Tx Frame */
+	/* GM_MIB_CNT_BASE + 296:	reserved */
+#define GM_TXF_COL \
+			(GM_MIB_CNT_BASE + 304)	/* Tx Collision */
+#define GM_TXF_LAT_COL \
+			(GM_MIB_CNT_BASE + 312)	/* Tx Late Collision */
+#define GM_TXF_ABO_COL \
+			(GM_MIB_CNT_BASE + 320)	/* Tx aborted due to Exces. Col. */
+#define GM_TXF_MUL_COL \
+			(GM_MIB_CNT_BASE + 328)	/* Tx Multiple Collision */
+#define GM_TXF_SNG_COL \
+			(GM_MIB_CNT_BASE + 336)	/* Tx Single Collision */
+#define GM_TXE_FIFO_UR \
+			(GM_MIB_CNT_BASE + 344)	/* Tx FIFO Underrun Event */
+
+/*----------------------------------------------------------------------------*/
+/*
+ * GMAC Bit Definitions
+ *
+ * If the bit access behaviour differs from the register access behaviour
+ * (r/w, r/o) this is documented after the bit number.
+ * The following bit access behaviours are used:
+ *	(sc)	self clearing
+ *	(r/o)	read only
+ */
+
+/*	GM_GP_STAT	16 bit r/o	General Purpose Status Register */
+
+#define GM_GPSR_SPEED		(1<<15) /* Bit 15:	Port Speed (1 = 100 Mbps) */
+#define GM_GPSR_DUPLEX		(1<<14) /* Bit 14:	Duplex Mode (1 = Full) */
+#define GM_GPSR_FC_TX_DIS	(1<<13) /* Bit 13:	Tx Flow Control Mode Disabled */
+#define GM_GPSR_LINK_UP		(1<<12)	/* Bit 12:	Link Up Status */
+#define GM_GPSR_PAUSE		(1<<11)	/* Bit 11:	Pause State */
+#define GM_GPSR_TX_ACTIVE	(1<<10)	/* Bit 10:	Tx in Progress */
+#define GM_GPSR_EXC_COL		(1<<9)	/* Bit  9:	Excessive Collisions Occured */
+#define GM_GPSR_LAT_COL		(1<<8)	/* Bit  8:	Late Collisions Occured */
+								/* Bit  7..6:	reserved */
+#define GM_GPSR_PHY_ST_CH	(1<<5)	/* Bit  5:	PHY Status Change */
+#define GM_GPSR_GIG_SPEED	(1<<4)	/* Bit  4:	Gigabit Speed (1 = 1000 Mbps) */
+#define GM_GPSR_PART_MODE	(1<<3)	/* Bit  3:	Partition mode */
+#define GM_GPSR_FC_RX_DIS	(1<<2)	/* Bit  2:	Rx Flow Control Mode Disabled */
+#define GM_GPSR_PROM_EN		(1<<1)	/* Bit  1:	Promiscuous Mode Enabled */
+								/* Bit  0:	reserved */
+	
+/*	GM_GP_CTRL	16 bit r/w	General Purpose Control Register */
+								/* Bit 15:	reserved */
+#define GM_GPCR_PROM_ENA	(1<<14)	/* Bit 14:	Enable Promiscuous Mode */
+#define GM_GPCR_FC_TX_DIS	(1<<13) /* Bit 13:	Disable Tx Flow Control Mode */
+#define GM_GPCR_TX_ENA		(1<<12) /* Bit 12:	Enable Transmit */
+#define GM_GPCR_RX_ENA		(1<<11) /* Bit 11:	Enable Receive */
+#define GM_GPCR_BURST_ENA	(1<<10)	/* Bit 10:	Enable Burst Mode */
+#define GM_GPCR_LOOP_ENA	(1<<9)	/* Bit  9:	Enable MAC Loopback Mode */
+#define GM_GPCR_PART_ENA	(1<<8)	/* Bit  8:	Enable Partition Mode */
+#define GM_GPCR_GIGS_ENA	(1<<7)	/* Bit  7:	Gigabit Speed (1000 Mbps) */
+#define GM_GPCR_FL_PASS		(1<<6)	/* Bit  6:	Force Link Pass */
+#define GM_GPCR_DUP_FULL	(1<<5)	/* Bit  5:	Full Duplex Mode */
+#define GM_GPCR_FC_RX_DIS	(1<<4)	/* Bit  4:	Disable Rx Flow Control Mode */
+#define GM_GPCR_SPEED_100	(1<<3)  /* Bit  3:	Port Speed 100 Mbps */
+#define GM_GPCR_AU_DUP_DIS	(1<<2)	/* Bit  2:	Disable Auto-Update for Duplex */
+#define GM_GPCR_AU_FCT_DIS	(1<<1)	/* Bit  1:	Disable Auto-Update for Flow-c. */
+#define GM_GPCR_AU_SPD_DIS	(1<<0)	/* Bit  0:	Disable Auto-Update for Speed */
+
+#define GM_GPCR_SPEED_1000	(GM_GPCR_GIGS_ENA | GM_GPCR_SPEED_100)
+#define GM_GPCR_AU_ALL_DIS	(GM_GPCR_AU_DUP_DIS | GM_GPCR_AU_FCT_DIS |\
+							 GM_GPCR_AU_SPD_DIS)
+	
+/*	GM_TX_CTRL				16 bit r/w	Transmit Control Register */
+
+#define GM_TXCR_FORCE_JAM	(1<<15)	/* Bit 15:	Force Jam / Flow-Control */
+#define GM_TXCR_CRC_DIS		(1<<14)	/* Bit 14:	Disable insertion of CRC */
+#define GM_TXCR_PAD_DIS		(1<<13)	/* Bit 13:	Disable padding of packets */
+#define GM_TXCR_COL_THR		(4<<10)	/* Bit 12..10:	Collision Threshold */
+	
+/*	GM_RX_CTRL				16 bit r/w	Receive Control Register */
+#define GM_RXCR_UCF_ENA		(1<<15)	/* Bit 15:	Enable Unicast filtering */
+#define GM_RXCR_MCF_ENA		(1<<14)	/* Bit 14:	Enable Multicast filtering */
+#define GM_RXCR_CRC_DIS		(1<<13)	/* Bit 13:	Remove 4-byte CRC */
+#define GM_RXCR_PASS_FC		(1<<12)	/* Bit 12:	Pass FC packets to FIFO */
+	
+/*	GM_TX_PARAM				16 bit r/w	Transmit Parameter Register */
+#define GM_TXPA_JAMLEN_MSK	(0x03<<14)	/* Bit 15..14:	Jam Length */
+#define GM_TXPA_JAMIPG_MSK	(0x1f<<9)	/* Bit 13..9:	Jam IPG */
+#define GM_TXPA_JAMDAT_MSK	(0x1f<<4)	/* Bit  8..4:	IPG Jam to Data */
+								/* Bit  3..0:	reserved */
+#define JAM_LEN_VAL(x)		SHIFT14(x)
+#define JAM_IPG_VAL(x)		SHIFT9(x)
+#define IPG_JAM_DATA(x)		SHIFT4(x)
+
+/*	GM_SERIAL_MODE			16 bit r/w	Serial Mode Register */
+#define GM_SMOD_DATABL_MSK	(0x1f<<11)	/* Bit 15..11:	Data Blinder */
+#define GM_SMOD_LIMIT_4		(1<<10)	/* Bit 10:	4 consecutive transmit trials */
+#define GM_SMOD_VLAN_ENA	(1<<9)	/* Bit  9:	Enable VLAN  (Max. Frame Length) */
+#define GM_SMOD_JUMBO_ENA	(1<<8)	/* Bit  8:	Enable Jumbo (Max. Frame Length) */
+								/* Bit  7..5:	reserved */
+#define GM_SMOD_IPG_MSK		0x1f	/* Bit 4..0:	Inter-Packet Gap (IPG) */
+	
+#define DATA_BLIND_VAL(x)	SHIFT11(x)
+#define DATA_BLIND_FAST_ETH	0x1c
+#define DATA_BLIND_GIGABIT	4
+
+#define IPG_VAL_FAST_ETH	0x1e
+#define IPG_VAL_GIGABIT		6
+
+/*	GM_SMI_CTRL				16 bit r/w	SMI Control Register */
+
+#define GM_SMI_CT_PHY_AD(x)	SHIFT11(x)
+#define GM_SMI_CT_REG_AD(x)	SHIFT6(x)
+#define GM_SMI_CT_OP_RD		(1<<5)	/* Bit  5:	OpCode Read (0=Write)*/
+#define GM_SMI_CT_RD_VAL	(1<<4)	/* Bit  4:	Read Valid (Read completed) */
+#define GM_SMI_CT_BUSY		(1<<3)	/* Bit  3:	Busy (Operation in progress) */
+								/* Bit   2..0:	reserved */
+	
+/*	GM_PHY_ADDR				16 bit r/w	GPHY Address Register */
+								/* Bit  15..6:	reserved */
+#define GM_PAR_MIB_CLR		(1<<5)	/* Bit  5:	Set MIB Clear Counter Mode */
+#define GM_PAR_MIB_TST		(1<<4)	/* Bit  4:	MIB Load Counter (Test Mode) */
+								/* Bit   3..0:	reserved */
+	
+/* Receive Frame Status Encoding */
+#define GMR_FS_LEN	(0xffffUL<<16)	/* Bit 31..16:	Rx Frame Length */
+								/* Bit  15..14:	reserved */
+#define GMR_FS_VLAN		(1L<<13)	/* Bit 13:	VLAN Packet */
+#define GMR_FS_JABBER	(1L<<12)	/* Bit 12:	Jabber Packet */
+#define GMR_FS_UN_SIZE	(1L<<11)	/* Bit 11:	Undersize Packet */
+#define GMR_FS_MC		(1L<<10)	/* Bit 10:	Multicast Packet */
+#define GMR_FS_BC		(1L<<9)		/* Bit  9:	Broadcast Packet */
+#define GMR_FS_RX_OK	(1L<<8)		/* Bit  8:	Receive OK (Good Packet) */
+#define GMR_FS_GOOD_FC	(1L<<7)		/* Bit  7:	Good Flow-Control Packet */
+#define GMR_FS_BAD_FC	(1L<<6)		/* Bit  6:	Bad  Flow-Control Packet */
+#define GMR_FS_MII_ERR	(1L<<5)		/* Bit  5:	MII Error */
+#define GMR_FS_LONG_ERR	(1L<<4)		/* Bit  4:	Too Long Packet */
+#define GMR_FS_FRAGMENT	(1L<<3)		/* Bit  3:	Fragment */
+								/* Bit  2:	reserved */
+#define GMR_FS_CRC_ERR	(1L<<1)		/* Bit  1:	CRC Error */
+#define GMR_FS_RX_FF_OV	(1L<<0)		/* Bit  0:	Rx FIFO Overflow */
+
+/*
+ * GMR_FS_ANY_ERR (analogous to XMR_FS_ANY_ERR)
+ */
+#define GMR_FS_ANY_ERR	(GMR_FS_CRC_ERR | \
+			GMR_FS_LONG_ERR | \
+			GMR_FS_MII_ERR | \
+			GMR_FS_BAD_FC | \
+			GMR_FS_GOOD_FC | \
+			GMR_FS_JABBER)
+
+/* Rx GMAC FIFO Flush Mask (default) */
+#define RX_FF_FL_DEF_MSK	(GMR_FS_CRC_ERR | \
+			GMR_FS_RX_FF_OV | \
+			GMR_FS_MII_ERR | \
+			GMR_FS_BAD_FC | \
+			GMR_FS_GOOD_FC | \
+			GMR_FS_UN_SIZE | \
+			GMR_FS_JABBER)
 
 /* typedefs *******************************************************************/
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sk98lin/skaddr.c linux-2.4.21-pre6/drivers/net/sk98lin/skaddr.c
--- linux-2.4.20/drivers/net/sk98lin/skaddr.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sk98lin/skaddr.c	2003-03-26 23:48:59.000000000 +0000
@@ -2,15 +2,15 @@
  *
  * Name:	skaddr.c
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.40 $
- * Date:	$Date: 2001/02/14 14:04:59 $
+ * Version:	$Revision: 1.47 $
+ * Date:	$Date: 2002/09/17 06:31:10 $
  * Purpose:	Manage Addresses (Multicast and Unicast) and Promiscuous Mode.
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998-2001 SysKonnect GmbH.
+ *	(C)Copyright 1998-2002 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 +26,39 @@
  * History:
  *
  *	$Log: skaddr.c,v $
+ *	Revision 1.47  2002/09/17 06:31:10  tschilli
+ *	Handling of SK_PROM_MODE_ALL_MC flag in SkAddrGmacMcUpdate()
+ *	and SkAddrGmacPromiscuousChange() fixed.
+ *	Editorial changes.
+ *	
+ *	Revision 1.46  2002/08/22 07:55:41  tschilli
+ *	New function SkGmacMcHash() for GMAC multicast hashing algorithm added.
+ *	Editorial changes.
+ *	
+ *	Revision 1.45  2002/08/15 12:29:35  tschilli
+ *	SkAddrGmacMcUpdate() and SkAddrGmacPromiscuousChange() changed.
+ *	
+ *	Revision 1.44  2002/08/14 12:18:03  rschmidt
+ *	Replaced direct handling of MAC Hashing (XMAC and GMAC)
+ *	with routine SkMacHashing().
+ *	Replaced wrong 3rd para 'i' with 'PortNumber' in SkMacPromiscMode().
+ *	
+ *	Revision 1.43  2002/08/13 09:37:43  rschmidt
+ *	Corrected some SK_DBG_MSG outputs.
+ *	Replaced wrong 2nd para pAC with IoC in SkMacPromiscMode().
+ *	Editorial changes.
+ *	
+ *	Revision 1.42  2002/08/12 11:24:36  rschmidt
+ *	Remove setting of logical MAC address GM_SRC_ADDR_2 in SkAddrInit().
+ *	Replaced direct handling of MAC Promiscuous Mode (XMAC and GMAC)
+ *	with routine SkMacPromiscMode().
+ *	Editorial changes.
+ *	
+ *	Revision 1.41  2002/06/10 13:52:18  tschilli
+ *	Changes for handling YUKON.
+ *	All changes are internally and not visible to the programmer
+ *	using this module.
+ *	
  *	Revision 1.40  2001/02/14 14:04:59  rassmann
  *	Editorial changes.
  *	
@@ -166,13 +199,13 @@
  * Description:
  *
  * This module is intended to manage multicast addresses, address override,
- * and promiscuous mode on GEnesis adapters.
+ * and promiscuous mode on GEnesis and Yukon adapters.
  *
  * Address Layout:
  *	port address:		physical MAC address
- *	1st exact match:	logical MAC address
- *	2nd exact match:	RLMT multicast
- *	exact match 3-13:	OS-specific multicasts
+ *	1st exact match:	logical MAC address (GEnesis only)
+ *	2nd exact match:	RLMT multicast (GEnesis only)
+ *	exact match 3-13:	OS-specific multicasts (GEnesis only)
  *
  * Include File Hierarchy:
  *
@@ -183,7 +216,7 @@
 
 #ifndef	lint
 static const char SysKonnectFileId[] =
-	"@(#) $Id: skaddr.c,v 1.40 2001/02/14 14:04:59 rassmann Exp $ (C) SysKonnect.";
+	"@(#) $Id: skaddr.c,v 1.47 2002/09/17 06:31:10 tschilli Exp $ (C) SysKonnect.";
 #endif	/* !defined(lint) */
 
 #define __SKADDR_C
@@ -199,6 +232,8 @@
 /* defines ********************************************************************/
 
 
+#define XMAC_POLY	0xEDB88320UL	/* CRC32-Poly - XMAC: Little Endian */
+#define GMAC_POLY	0x04C11DB7L	/* CRC16-Poly - GMAC: Little Endian */
 #define HASH_BITS	6				/* #bits in hash */
 #define	SK_MC_BIT	0x01
 
@@ -247,7 +282,7 @@
  *	All permanent MAC addresses are read from EPROM.
  *	If the current MAC addresses are not already set in software,
  *	they are set to the values of the permanent addresses.
- *	The current addresses are written to the corresponding XMAC.
+ *	The current addresses are written to the corresponding MAC.
  *
  *
  *	SK_INIT_RUN
@@ -266,38 +301,26 @@
 SK_IOC	IoC,	/* I/O context */
 int		Level)	/* initialization level */
 {
-	int				j;
-	SK_U32			i;
-	SK_U8			*InAddr;
-	SK_U16			*OutAddr;
+	int			j;
+	SK_U32		i;
+	SK_U8		*InAddr;
+	SK_U16		*OutAddr;
 	SK_ADDR_PORT	*pAPort;
 
 	switch (Level) {
 	case SK_INIT_DATA:
-		SK_MEMSET((char *)&pAC->Addr, 0, sizeof(SK_ADDR));
+		SK_MEMSET((char *) &pAC->Addr, 0, sizeof(SK_ADDR));
 
 		for (i = 0; i < SK_MAX_MACS; i++) {
 			pAPort = &pAC->Addr.Port[i];
 			pAPort->PromMode = SK_PROM_MODE_NONE;
-
-			pAPort->FirstExactMatchRlmt	= SK_ADDR_FIRST_MATCH_RLMT;
-			pAPort->FirstExactMatchDrv	= SK_ADDR_FIRST_MATCH_DRV;
-			pAPort->NextExactMatchRlmt	= SK_ADDR_FIRST_MATCH_RLMT;
-			pAPort->NextExactMatchDrv	= SK_ADDR_FIRST_MATCH_DRV;
-
-#if 0
-			/* Don't do this here ... */
-
-			/* Reset Promiscuous mode. */
-			(void)SkAddrPromiscuousChange(
-				pAC,
-				IoC,
-				i,
-				SK_PROM_MODE_NONE);
-#endif	/* 0 */
+			
+			pAPort->FirstExactMatchRlmt = SK_ADDR_FIRST_MATCH_RLMT;
+			pAPort->FirstExactMatchDrv = SK_ADDR_FIRST_MATCH_DRV;
+			pAPort->NextExactMatchRlmt = SK_ADDR_FIRST_MATCH_RLMT;
+			pAPort->NextExactMatchDrv = SK_ADDR_FIRST_MATCH_DRV;
 		}
-		
-#ifdef DEBUG
+#ifdef xDEBUG
 		for (i = 0; i < SK_MAX_MACS; i++) {
 			if (pAC->Addr.Port[i].NextExactMatchRlmt <
 				SK_ADDR_FIRST_MATCH_RLMT) {
@@ -305,7 +328,6 @@
 			}
 		}
 #endif	/* DEBUG */
-
 		/* pAC->Addr.InitDone = SK_INIT_DATA; */
 		break;
 
@@ -313,8 +335,7 @@
 		for (i = 0; i < SK_MAX_NETS; i++) {
 			pAC->Addr.Net[i].ActivePort = pAC->Rlmt.Net[i].ActivePort;
 		}
-		
-#ifdef DEBUG
+#ifdef xDEBUG
 		for (i = 0; i < SK_MAX_MACS; i++) {
 			if (pAC->Addr.Port[i].NextExactMatchRlmt <
 				SK_ADDR_FIRST_MATCH_RLMT) {
@@ -322,10 +343,10 @@
 			}
 		}
 #endif	/* DEBUG */
-
+		
 		/* Read permanent logical MAC address from Control Register File. */
 		for (j = 0; j < SK_MAC_ADDR_LEN; j++) {
-			InAddr = (SK_U8 *)&pAC->Addr.Net[0].PermanentMacAddress.a[j];
+			InAddr = (SK_U8 *) &pAC->Addr.Net[0].PermanentMacAddress.a[j];
 			SK_IN8(IoC, B2_MAC_1 + j, InAddr);
 		}
 
@@ -339,7 +360,6 @@
 		/* Set the current logical MAC address. */
 		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) {
@@ -353,43 +373,36 @@
 		}
 #endif	/* SK_MAX_NETS > 1 */
 
-#ifdef xDEBUG
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_ADDR,
-			SK_DBGCAT_INIT,
-			("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]))
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_ADDR,
-			SK_DBGCAT_INIT,
-			("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]))
+#ifdef DEBUG
+		for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
+			SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_INIT,
+				("Permanent MAC Address (Net%d): %02X %02X %02X %02X %02X %02X\n",
+					i,
+					pAC->Addr.Net[i].PermanentMacAddress.a[0],
+					pAC->Addr.Net[i].PermanentMacAddress.a[1],
+					pAC->Addr.Net[i].PermanentMacAddress.a[2],
+					pAC->Addr.Net[i].PermanentMacAddress.a[3],
+					pAC->Addr.Net[i].PermanentMacAddress.a[4],
+					pAC->Addr.Net[i].PermanentMacAddress.a[5]))
+			
+			SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_INIT,
+				("Logical MAC Address (Net%d): %02X %02X %02X %02X %02X %02X\n",
+					i,
+					pAC->Addr.Net[i].CurrentMacAddress.a[0],
+					pAC->Addr.Net[i].CurrentMacAddress.a[1],
+					pAC->Addr.Net[i].CurrentMacAddress.a[2],
+					pAC->Addr.Net[i].CurrentMacAddress.a[3],
+					pAC->Addr.Net[i].CurrentMacAddress.a[4],
+					pAC->Addr.Net[i].CurrentMacAddress.a[5]))
+		}
 #endif	/* DEBUG */
 
-#if 0
-		/* Don't do this here ... */
-
-		(void)SkAddrMcUpdate(pAC, IoC, pAC->Addr.ActivePort);
-#endif	/* 0 */
-
-		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+		for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
 			pAPort = &pAC->Addr.Port[i];
 
 			/* Read permanent port addresses from Control Register File. */
 			for (j = 0; j < SK_MAC_ADDR_LEN; j++) {
-				InAddr = (SK_U8 *)&pAPort->PermanentMacAddress.a[j];
+				InAddr = (SK_U8 *) &pAPort->PermanentMacAddress.a[j];
 				SK_IN8(IoC, B2_MAC_2 + 8 * i + j, InAddr);
 			}
 
@@ -403,27 +416,27 @@
 				pAPort->CurrentMacAddressSet = SK_TRUE;
 			}
 
-			/* Set port's current MAC addresses. */
-			OutAddr = (SK_U16 *)&pAPort->CurrentMacAddress.a[0];
-			XM_OUTADDR(IoC, i, XM_SA, OutAddr);
-
-#ifdef xDEBUG
-			SK_DBG_MSG(
-				pAC,
-				SK_DBGMOD_ADDR,
-				SK_DBGCAT_INIT,
-				("Permanent Physical MAC Address: %02X %02X %02X %02X %02X %02X\n",
+			/* Set port's current physical MAC address. */
+			OutAddr = (SK_U16 *) &pAPort->CurrentMacAddress.a[0];
+			
+			if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+				XM_OUTADDR(IoC, i, XM_SA, OutAddr);
+			}
+			else {
+				GM_OUTADDR(IoC, i, GM_SRC_ADDR_1L, OutAddr);
+			}
+#ifdef DEBUG
+			SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_INIT,
+				("SkAddrInit: Permanent Physical MAC Address: %02X %02X %02X %02X %02X %02X\n",
 					pAPort->PermanentMacAddress.a[0],
 					pAPort->PermanentMacAddress.a[1],
 					pAPort->PermanentMacAddress.a[2],
 					pAPort->PermanentMacAddress.a[3],
 					pAPort->PermanentMacAddress.a[4],
 					pAPort->PermanentMacAddress.a[5]))
-			SK_DBG_MSG(
-				pAC,
-				SK_DBGMOD_ADDR,
-				SK_DBGCAT_INIT,
-				("Phsical MAC Address: %02X %02X %02X %02X %02X %02X\n",
+			
+			SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_INIT,
+				("SkAddrInit: Physical MAC Address: %02X %02X %02X %02X %02X %02X\n",
 					pAPort->CurrentMacAddress.a[0],
 					pAPort->CurrentMacAddress.a[1],
 					pAPort->CurrentMacAddress.a[2],
@@ -436,7 +449,7 @@
 		break;
 
 	case SK_INIT_RUN:
-#ifdef DEBUG
+#ifdef xDEBUG
 		for (i = 0; i < SK_MAX_MACS; i++) {
 			if (pAC->Addr.Port[i].NextExactMatchRlmt <
 				SK_ADDR_FIRST_MATCH_RLMT) {
@@ -453,6 +466,7 @@
 	}
 
 	return (SK_ADDR_SUCCESS);
+	
 }	/* SkAddrInit */
 
 
@@ -461,11 +475,14 @@
  *	SkAddrMcClear - clear the multicast table
  *
  * Description:
- *	This routine clears the multicast table
- *	(either entry 2 or entries 3-16 and InexactFilter) of the given port.
+ *	This routine clears the multicast table.
+ *
  *	If not suppressed by Flag SK_MC_SW_ONLY, the hardware is updated
  *	immediately.
  *
+ *	It calls either SkAddrXmacMcClear or SkAddrGmacMcClear, according
+ *	to the adapter in use. The real work is done there.
+ *
  * Context:
  *	runtime, pageable
  *	may be called starting with SK_INIT_DATA with flag SK_MC_SW_ONLY
@@ -481,21 +498,59 @@
 SK_U32	PortNumber,	/* Index of affected port */
 int		Flags)		/* permanent/non-perm, sw-only */
 {
-	int i;
-
-	if (PortNumber >= (SK_U32)pAC->GIni.GIMacsFound) {
+	int ReturnCode;
+	
+	if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
 		return (SK_ADDR_ILLEGAL_PORT);
 	}
+	
+	if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+		ReturnCode = SkAddrXmacMcClear(pAC, IoC, PortNumber, Flags);
+	}
+	else {
+		ReturnCode = SkAddrGmacMcClear(pAC, IoC, PortNumber, Flags);
+	}
+
+	return (ReturnCode);
+
+}	/* SkAddrMcClear */
+
+
+/******************************************************************************
+ *
+ *	SkAddrXmacMcClear - clear the multicast table
+ *
+ * Description:
+ *	This routine clears the multicast table
+ *	(either entry 2 or entries 3-16 and InexactFilter) of the given port.
+ *	If not suppressed by Flag SK_MC_SW_ONLY, the hardware is updated
+ *	immediately.
+ *
+ * Context:
+ *	runtime, pageable
+ *	may be called starting with SK_INIT_DATA with flag SK_MC_SW_ONLY
+ *	may be called after SK_INIT_IO without limitation
+ *
+ * Returns:
+ *	SK_ADDR_SUCCESS
+ *	SK_ADDR_ILLEGAL_PORT
+ */
+int	SkAddrXmacMcClear(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* I/O context */
+SK_U32	PortNumber,	/* Index of affected port */
+int		Flags)		/* permanent/non-perm, sw-only */
+{
+	int i;
 
-	if (Flags & SK_ADDR_PERMANENT) {
+	if (Flags & SK_ADDR_PERMANENT) {	/* permanent => RLMT */
 
 		/* Clear RLMT multicast addresses. */
 		pAC->Addr.Port[PortNumber].NextExactMatchRlmt = SK_ADDR_FIRST_MATCH_RLMT;
 	}
 	else {	/* not permanent => DRV */
 
-		/* Clear InexactFilter. */
-
+		/* Clear InexactFilter */
 		for (i = 0; i < 8; i++) {
 			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0;
 		}
@@ -506,20 +561,114 @@
 	}
 
 	if (!(Flags & SK_MC_SW_ONLY)) {
-		(void)SkAddrMcUpdate(pAC, IoC, PortNumber);
+		(void) SkAddrXmacMcUpdate(pAC, IoC, PortNumber);
 	}
 
 	return (SK_ADDR_SUCCESS);
-}	/* SkAddrMcClear */
+	
+}	/* SkAddrXmacMcClear */
+
+
+/******************************************************************************
+ *
+ *	SkAddrGmacMcClear - clear the multicast table
+ *
+ * Description:
+ *	This routine clears the multicast hashing table (InexactFilter)
+ *	(either the RLMT or the driver bits) of the given port.
+ *
+ *	If not suppressed by Flag SK_MC_SW_ONLY, the hardware is updated
+ *	immediately.
+ *
+ * Context:
+ *	runtime, pageable
+ *	may be called starting with SK_INIT_DATA with flag SK_MC_SW_ONLY
+ *	may be called after SK_INIT_IO without limitation
+ *
+ * Returns:
+ *	SK_ADDR_SUCCESS
+ *	SK_ADDR_ILLEGAL_PORT
+ */
+int	SkAddrGmacMcClear(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* I/O context */
+SK_U32	PortNumber,	/* Index of affected port */
+int		Flags)		/* permanent/non-perm, sw-only */
+{
+	int i;
+
+#ifdef DEBUG
+	SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+		("GMAC InexactFilter (not cleared): %02X %02X %02X %02X %02X %02X %02X %02X\n",
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0],
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[1],
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[2],
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[3],
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[4],
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[5],
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[6],
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[7]))
+#endif	/* DEBUG */
+
+	/* Clear InexactFilter */
+	for (i = 0; i < 8; i++) {
+		pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0;
+	}
+	
+	if (Flags & SK_ADDR_PERMANENT) {	/* permanent => RLMT */
+		
+		/* Copy DRV bits to InexactFilter. */
+		for (i = 0; i < 8; i++) {
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] |=
+				pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[i];
+			
+			/* Clear InexactRlmtFilter. */
+			pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[i] = 0;
+
+		}		
+	}
+	else {	/* not permanent => DRV */
+		
+		/* Copy RLMT bits to InexactFilter. */
+		for (i = 0; i < 8; i++) {
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] |=
+				pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[i];
+			
+			/* Clear InexactDrvFilter. */
+			pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[i] = 0;
+		}
+	}
+	
+#ifdef DEBUG
+	SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+		("GMAC InexactFilter (cleared): %02X %02X %02X %02X %02X %02X %02X %02X\n",
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0],
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[1],
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[2],
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[3],
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[4],
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[5],
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[6],
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[7]))
+#endif	/* DEBUG */
+	
+	if (!(Flags & SK_MC_SW_ONLY)) {
+		(void) SkAddrGmacMcUpdate(pAC, IoC, PortNumber);
+	}
+	
+	return (SK_ADDR_SUCCESS);
+
+}	/* SkAddrGmacMcClear */
 
 #ifndef SK_ADDR_CHEAT
 
 /******************************************************************************
  *
- *	SkCrc32McHash - hash multicast address
+ *	SkXmacMcHash - hash multicast address
  *
  * Description:
  *	This routine computes the hash value for a multicast address.
+ *	A CRC32 algorithm is used.
  *
  * Notes:
  *	The code was adapted from the XaQti data sheet.
@@ -530,15 +679,84 @@
  * Returns:
  *	Hash value of multicast address.
  */
-unsigned SkCrc32McHash(
+SK_U32 SkXmacMcHash(
 unsigned char *pMc)	/* Multicast address */
 {
-	u32 Crc;
+	SK_U32 Idx;
+	SK_U32 Bit;
+	SK_U32 Data;
+	SK_U32 Crc;
+
+	Crc = 0xFFFFFFFFUL;
+	for (Idx = 0; Idx < SK_MAC_ADDR_LEN; Idx++) {
+		Data = *pMc++;
+		for (Bit = 0; Bit < 8; Bit++, Data >>= 1) {
+			Crc = (Crc >> 1) ^ (((Crc ^ Data) & 1) ? XMAC_POLY : 0);
+		}
+	}
 
-	Crc = ether_crc_le(SK_MAC_ADDR_LEN, pMc);
+	return (Crc & ((1 << HASH_BITS) - 1));
+
+}	/* SkXmacMcHash */
 
+
+/******************************************************************************
+ *
+ *	SkGmacMcHash - hash multicast address
+ *
+ * Description:
+ *	This routine computes the hash value for a multicast address.
+ *	A CRC16 algorithm is used.
+ *
+ * Notes:
+ *
+ *
+ * Context:
+ *	runtime, pageable
+ *
+ * Returns:
+ *	Hash value of multicast address.
+ */
+SK_U32 SkGmacMcHash(
+unsigned char *pMc)	/* Multicast address */
+{
+	SK_U32 Data;
+	SK_U32 TmpData;
+	SK_U32 Crc;
+	int Byte;
+	int Bit;
+
+	Crc = 0xFFFFFFFFUL;
+	for (Byte = 0; Byte < 6; Byte++) {
+		/* Get next byte. */
+		Data = (SK_U32) pMc[Byte];
+		
+		/* Change bit order in byte. */
+		TmpData = Data;
+		for (Bit = 0; Bit < 8; Bit++) {
+			if (TmpData & 1L) {
+				Data |=  1L << (7 - Bit);
+			}
+			else {
+				Data &= ~(1L << (7 - Bit));
+			}
+			TmpData >>= 1;
+		}
+		
+		Crc ^= (Data << 24);
+		for (Bit = 0; Bit < 8; Bit++) {
+			if (Crc & 0x80000000) {
+				Crc = (Crc << 1) ^ GMAC_POLY;
+			}
+			else {
+				Crc <<= 1;
+			}
+		}
+	}
+	
 	return (Crc & ((1 << HASH_BITS) - 1));
-}	/* SkCrc32McHash */
+
+}	/* SkGmacMcHash */
 
 #endif	/* not SK_ADDR_CHEAT */
 
@@ -549,11 +767,57 @@
  * Description:
  *	This routine enables reception for a given address on the given port.
  *
+ *	It calls either SkAddrXmacMcAdd or SkAddrGmacMcAdd, according to the
+ *	adapter in use. The real work is done there.
+ *
  * Notes:
  *	The return code is only valid for SK_PROM_MODE_NONE.
  *
- *	In the current version, only RLMT may add addresses to the non-active
- *	port.
+ * Context:
+ *	runtime, pageable
+ *	may be called after SK_INIT_DATA
+ *
+ * Returns:
+ *	SK_MC_FILTERING_EXACT
+ *	SK_MC_FILTERING_INEXACT
+ *	SK_MC_ILLEGAL_ADDRESS
+ *	SK_MC_ILLEGAL_PORT
+ *	SK_MC_RLMT_OVERFLOW
+ */
+int	SkAddrMcAdd(
+SK_AC		*pAC,		/* adapter context */
+SK_IOC		IoC,		/* I/O context */
+SK_U32		PortNumber,	/* Port Number */
+SK_MAC_ADDR	*pMc,		/* multicast address to be added */
+int			Flags)		/* permanent/non-permanent */
+{
+	int ReturnCode;
+	
+	if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
+		return (SK_ADDR_ILLEGAL_PORT);
+	}
+	
+	if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+		ReturnCode = SkAddrXmacMcAdd(pAC, IoC, PortNumber, pMc, Flags);
+	}
+	else {
+		ReturnCode = SkAddrGmacMcAdd(pAC, IoC, PortNumber, pMc, Flags);
+	}
+
+	return (ReturnCode);
+
+}	/* SkAddrMcAdd */
+
+
+/******************************************************************************
+ *
+ *	SkAddrXmacMcAdd - add a multicast address to a port
+ *
+ * Description:
+ *	This routine enables reception for a given address on the given port.
+ *
+ * Notes:
+ *	The return code is only valid for SK_PROM_MODE_NONE.
  *
  *	The multicast bit is only checked if there are no free exact match
  *	entries.
@@ -566,28 +830,23 @@
  *	SK_MC_FILTERING_EXACT
  *	SK_MC_FILTERING_INEXACT
  *	SK_MC_ILLEGAL_ADDRESS
- *	SK_MC_ILLEGAL_PORT
  *	SK_MC_RLMT_OVERFLOW
  */
-int	SkAddrMcAdd(
+int	SkAddrXmacMcAdd(
 SK_AC		*pAC,		/* adapter context */
 SK_IOC		IoC,		/* I/O context */
 SK_U32		PortNumber,	/* Port Number */
 SK_MAC_ADDR	*pMc,		/* multicast address to be added */
-int			Flags)		/* permanent/non-permanent */
+int		Flags)		/* permanent/non-permanent */
 {
 	int	i;
 	SK_U8	Inexact;
 #ifndef SK_ADDR_CHEAT
-	unsigned HashBit;
+	SK_U32 HashBit;
 #endif	/* !defined(SK_ADDR_CHEAT) */
 
-	if (PortNumber >= (SK_U32)pAC->GIni.GIMacsFound) {
-		return (SK_ADDR_ILLEGAL_PORT);
-	}
-
-	if (Flags & SK_ADDR_PERMANENT) {
-#ifdef DEBUG
+	if (Flags & SK_ADDR_PERMANENT) {	/* permanent => RLMT */
+#ifdef xDEBUG
 		if (pAC->Addr.Port[PortNumber].NextExactMatchRlmt <
 			SK_ADDR_FIRST_MATCH_RLMT) {
 			Next0[PortNumber] |= 1;
@@ -600,7 +859,7 @@
 			return (SK_MC_RLMT_OVERFLOW);
 		}
 
-		/* Set an RLMT multicast address. */
+		/* Set a RLMT multicast address. */
 
 		pAC->Addr.Port[PortNumber].Exact[
 			pAC->Addr.Port[PortNumber].NextExactMatchRlmt++] = *pMc;
@@ -608,15 +867,7 @@
 		return (SK_MC_FILTERING_EXACT);
 	}
 
-#if 0
-	/* Not PERMANENT => DRV */
-	if (PortNumber != pAC->Addr.ActivePort) {
-		/* Only RLMT is allowed to do this. */
-		return (SK_MC_ILLEGAL_PORT);
-	}
-#endif	/* 0 */
-
-#ifdef DEBUG
+#ifdef xDEBUG
 	if (pAC->Addr.Port[PortNumber].NextExactMatchDrv <
 		SK_ADDR_FIRST_MATCH_DRV) {
 			Next0[PortNumber] |= 2;
@@ -630,22 +881,19 @@
 		pAC->Addr.Port[PortNumber].Exact[
 			pAC->Addr.Port[PortNumber].NextExactMatchDrv++] = *pMc;
 
-		/* Clear InexactFilter. */
+		/* Clear InexactFilter */
 		for (i = 0; i < 8; i++) {
 			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0;
 		}
 	}
 	else {
 		if (!(pMc->a[0] & SK_MC_BIT)) {
-			/*
-			 * Hashing only possible with
-			 * multicast addresses.
-			 */
+			/* Hashing only possible with multicast addresses. */
 			return (SK_MC_ILLEGAL_ADDRESS);
 		}
 #ifndef SK_ADDR_CHEAT
 		/* Compute hash value of address. */
-		HashBit = 63 - SkCrc32McHash(&pMc->a[0]);
+		HashBit = 63 - SkXmacMcHash(&pMc->a[0]);
 
 		/* Add bit to InexactFilter. */
 		pAC->Addr.Port[PortNumber].InexactFilter.Bytes[HashBit / 8] |=
@@ -668,90 +916,223 @@
 	else {
 		return (SK_MC_FILTERING_INEXACT);
 	}
-}	/* SkAddrMcAdd */
+
+}	/* SkAddrXmacMcAdd */
 
 
 /******************************************************************************
  *
- *	SkAddrMcUpdate - update the HW MC address table and set the MAC address
+ *	SkAddrGmacMcAdd - add a multicast address to a port
  *
  * Description:
- *	This routine enables reception of the addresses contained in a local
- *	table for a given port.
- *	It also programs the port's current physical MAC address.
+ *	This routine enables reception for a given address on the given port.
  *
  * Notes:
  *	The return code is only valid for SK_PROM_MODE_NONE.
  *
  * Context:
  *	runtime, pageable
- *	may be called after SK_INIT_IO
+ *	may be called after SK_INIT_DATA
  *
  * Returns:
- *	SK_MC_FILTERING_EXACT
  *	SK_MC_FILTERING_INEXACT
- *	SK_ADDR_ILLEGAL_PORT
+ *	SK_MC_ILLEGAL_ADDRESS
  */
-int	SkAddrMcUpdate(
-SK_AC	*pAC,		/* adapter context */
-SK_IOC	IoC,		/* I/O context */
-SK_U32	PortNumber)	/* Port Number */
+int	SkAddrGmacMcAdd(
+SK_AC		*pAC,		/* adapter context */
+SK_IOC		IoC,		/* I/O context */
+SK_U32		PortNumber,	/* Port Number */
+SK_MAC_ADDR	*pMc,		/* multicast address to be added */
+int		Flags)		/* permanent/non-permanent */
 {
-	SK_U32			i;
-	SK_U8			Inexact;
-	SK_U16			*OutAddr;
-	SK_U16			LoMode;		/* Lower 16 bits of XMAC Mode Reg. */
-	SK_ADDR_PORT	*pAPort;
-
-	if (PortNumber >= (SK_U32)pAC->GIni.GIMacsFound) {
-		return (SK_ADDR_ILLEGAL_PORT);
+	int	i;
+#ifndef SK_ADDR_CHEAT
+	SK_U32 HashBit;
+#endif	/* !defined(SK_ADDR_CHEAT) */
+		
+	if (!(pMc->a[0] & SK_MC_BIT)) {
+		/* Hashing only possible with multicast addresses. */
+		return (SK_MC_ILLEGAL_ADDRESS);
 	}
-
-	SK_DBG_MSG(
-		pAC,
-		SK_DBGMOD_ADDR,
-		SK_DBGCAT_CTRL,
-		("SkAddrMcUpdate on Port %u.\n", PortNumber))
 	
-	pAPort = &pAC->Addr.Port[PortNumber];
-
+#ifndef SK_ADDR_CHEAT
+	
+	/* Compute hash value of address. */
+	HashBit = SkGmacMcHash(&pMc->a[0]);
+	
+	if (Flags & SK_ADDR_PERMANENT) {	/* permanent => RLMT */
+		
+		/* Add bit to InexactRlmtFilter. */
+		pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[HashBit / 8] |=
+			1 << (HashBit % 8);
+		
+		/* Copy bit to InexactFilter. */
+		for (i = 0; i < 8; i++) {
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] |=
+				pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[i];
+		}
 #ifdef DEBUG
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_ADDR,
-			SK_DBGCAT_CTRL,
-			("Next0 on Port %d: %d\n", PortNumber, Next0[PortNumber]))
+		SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+		("GMAC InexactRlmtFilter: %02X %02X %02X %02X %02X %02X %02X %02X\n",
+			pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[0],
+			pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[1],
+			pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[2],
+			pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[3],
+			pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[4],
+			pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[5],
+			pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[6],
+			pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[7]))
 #endif	/* DEBUG */
-
-	/* 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, PortNumber, XM_EXM(i), OutAddr);
+	}
+	else {	/* not permanent => DRV */
+		
+		/* Add bit to InexactDrvFilter. */
+		pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[HashBit / 8] |=
+			1 << (HashBit % 8);
+		
+		/* Copy bit to InexactFilter. */
+		for (i = 0; i < 8; i++) {
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] |=
+				pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[i];
+		}
+#ifdef DEBUG
+		SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+		("GMAC InexactDrvFilter: %02X %02X %02X %02X %02X %02X %02X %02X\n",
+			pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[0],
+			pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[1],
+			pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[2],
+			pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[3],
+			pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[4],
+			pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[5],
+			pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[6],
+			pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[7]))
+#endif	/* DEBUG */
+	}
+	
+#else	/* SK_ADDR_CHEAT */
+	
+	/* Set all bits in InexactFilter. */
+	for (i = 0; i < 8; i++) {
+		pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0xFF;
+	}
+#endif	/* SK_ADDR_CHEAT */
+		
+	return (SK_MC_FILTERING_INEXACT);
+	
+}	/* SkAddrGmacMcAdd */
+
+
+/******************************************************************************
+ *
+ *	SkAddrMcUpdate - update the HW MC address table and set the MAC address
+ *
+ * Description:
+ *	This routine enables reception of the addresses contained in a local
+ *	table for a given port.
+ *	It also programs the port's current physical MAC address.
+ *
+ *	It calls either SkAddrXmacMcUpdate or SkAddrGmacMcUpdate, according
+ *	to the adapter in use. The real work is done there.
+ *
+ * Notes:
+ *	The return code is only valid for SK_PROM_MODE_NONE.
+ *
+ * Context:
+ *	runtime, pageable
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	SK_MC_FILTERING_EXACT
+ *	SK_MC_FILTERING_INEXACT
+ *	SK_ADDR_ILLEGAL_PORT
+ */
+int	SkAddrMcUpdate(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* I/O context */
+SK_U32	PortNumber)	/* Port Number */
+{
+	int ReturnCode;
+	
+	if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
+		return (SK_ADDR_ILLEGAL_PORT);
+	}
+	
+	if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+		ReturnCode = SkAddrXmacMcUpdate(pAC, IoC, PortNumber);
+	}
+	else {
+		ReturnCode = SkAddrGmacMcUpdate(pAC, IoC, PortNumber);
+	}
+	
+	return (ReturnCode);
+
+}	/* SkAddrMcUpdate */
+
+
+/******************************************************************************
+ *
+ *	SkAddrXmacMcUpdate - update the HW MC address table and set the MAC address
+ *
+ * Description:
+ *	This routine enables reception of the addresses contained in a local
+ *	table for a given port.
+ *	It also programs the port's current physical MAC address.
+ *
+ * Notes:
+ *	The return code is only valid for SK_PROM_MODE_NONE.
+ *
+ * Context:
+ *	runtime, pageable
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	SK_MC_FILTERING_EXACT
+ *	SK_MC_FILTERING_INEXACT
+ *	SK_ADDR_ILLEGAL_PORT
+ */
+int	SkAddrXmacMcUpdate(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* I/O context */
+SK_U32	PortNumber)	/* Port Number */
+{
+	SK_U32		i;
+	SK_U8		Inexact;
+	SK_U16		*OutAddr;
+	SK_ADDR_PORT	*pAPort;
+
+	SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+		("SkAddrXmacMcUpdate on Port %u.\n", PortNumber))
+	
+	pAPort = &pAC->Addr.Port[PortNumber];
+
+#ifdef DEBUG
+	SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+		("Next0 on Port %d: %d\n", PortNumber, Next0[PortNumber]))
+#endif	/* DEBUG */
+
+	/* Start with 0 to also program the logical MAC address. */
+	for (i = 0; i < pAPort->NextExactMatchRlmt; i++) {
+		/* Set exact match address i on XMAC */
+		OutAddr = (SK_U16 *) &pAPort->Exact[i].a[0];
+		XM_OUTADDR(IoC, PortNumber, XM_EXM(i), OutAddr);
 	}
 
-	/* Clear other permanent exact match addresses on HW. */
+	/* Clear other permanent exact match addresses on XMAC */
 	if (pAPort->NextExactMatchRlmt <= SK_ADDR_LAST_MATCH_RLMT) {
-		SkXmClrExactAddr(
-			pAC,
-			IoC,
-			PortNumber,
-			pAPort->NextExactMatchRlmt,
+		
+		SkXmClrExactAddr(pAC, IoC, PortNumber, pAPort->NextExactMatchRlmt,
 			SK_ADDR_LAST_MATCH_RLMT);
 	}
 
 	for (i = pAPort->FirstExactMatchDrv; i < pAPort->NextExactMatchDrv; i++) {
-		OutAddr = (SK_U16 *)&pAPort->Exact[i].a[0];
+		OutAddr = (SK_U16 *) &pAPort->Exact[i].a[0];
 		XM_OUTADDR(IoC, PortNumber, XM_EXM(i), OutAddr);
 	}
 
-	/* Clear other non-permanent exact match addresses on HW. */
+	/* Clear other non-permanent exact match addresses on XMAC */
 	if (pAPort->NextExactMatchDrv <= SK_ADDR_LAST_MATCH_DRV) {
-		SkXmClrExactAddr(
-			pAC,
-			IoC,
-			PortNumber,
-			pAPort->NextExactMatchDrv,
+		
+		SkXmClrExactAddr(pAC, IoC, PortNumber, pAPort->NextExactMatchDrv,
 			SK_ADDR_LAST_MATCH_DRV);
 	}
 
@@ -760,36 +1141,33 @@
 	}
 
 	if (pAPort->PromMode & SK_PROM_MODE_ALL_MC) {
+		
 		/* Set all bits in 64-bit hash register. */
 		XM_OUTHASH(IoC, PortNumber, XM_HSM, &OnesHash);
-
-		/* Set bit 15 in mode register. */
-		XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
-		LoMode |= XM_MD_ENA_HSH;
-		XM_OUT16(IoC, PortNumber, XM_MODE, LoMode);
+		
+		/* Enable Hashing */
+		SkMacHashing(pAC, IoC, PortNumber, SK_TRUE);
 	}
 	else if (Inexact != 0) {
+		
 		/* Set 64-bit hash register to InexactFilter. */
 		XM_OUTHASH(IoC, PortNumber, XM_HSM, &pAPort->InexactFilter.Bytes[0]);
-
-		/* Set bit 15 in mode register. */
-		XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
-		LoMode |= XM_MD_ENA_HSH;
-		XM_OUT16(IoC, PortNumber, XM_MODE, LoMode);
+		
+		/* Enable Hashing */
+		SkMacHashing(pAC, IoC, PortNumber, SK_TRUE);
 	}
 	else {
-		/* Clear bit 15 in mode register. */
-		XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
-		LoMode &= ~XM_MD_ENA_HSH;
-		XM_OUT16(IoC, PortNumber, XM_MODE, LoMode);
+		/* Disable Hashing */
+		SkMacHashing(pAC, IoC, PortNumber, SK_FALSE);
 	}
 
 	if (pAPort->PromMode != SK_PROM_MODE_NONE) {
-		(void)SkAddrPromiscuousChange(pAC, IoC, PortNumber, pAPort->PromMode);
+		(void) SkAddrXmacPromiscuousChange(pAC, IoC, PortNumber, pAPort->PromMode);
 	}
 
-	/* Set port's current MAC address. */
-	OutAddr = (SK_U16 *)&pAPort->CurrentMacAddress.a[0];
+	/* Set port's current physical MAC address. */
+	OutAddr = (SK_U16 *) &pAPort->CurrentMacAddress.a[0];
+	
 	XM_OUTADDR(IoC, PortNumber, XM_SA, OutAddr);
 
 #ifdef xDEBUG
@@ -798,13 +1176,13 @@
 		SK_U16		*InAddr;
 
 		/* Get exact match address i from port PortNumber. */
-		InAddr = (SK_U16 *)&InAddr8[0];
+		InAddr = (SK_U16 *) &InAddr8[0];
+		
 		XM_INADDR(IoC, PortNumber, XM_EXM(i), InAddr);
-		SK_DBG_MSG(
-			pAC,
-			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",
+		
+		SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+			("SkAddrXmacMcUpdate: MC address %d on Port %u: ",
+			 "%02x %02x %02x %02x %02x %02x -- %02x %02x %02x %02x %02x %02x\n",
 				i,
 				PortNumber,
 				InAddr8[0],
@@ -829,7 +1207,113 @@
 	else {
 		return (SK_MC_FILTERING_INEXACT);
 	}
-}	/* SkAddrMcUpdate */
+	
+}	/* SkAddrXmacMcUpdate */
+
+
+/******************************************************************************
+ *
+ *	SkAddrGmacMcUpdate - update the HW MC address table and set the MAC address
+ *
+ * Description:
+ *	This routine enables reception of the addresses contained in a local
+ *	table for a given port.
+ *	It also programs the port's current physical MAC address.
+ *
+ * Notes:
+ *	The return code is only valid for SK_PROM_MODE_NONE.
+ *
+ * Context:
+ *	runtime, pageable
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	SK_MC_FILTERING_EXACT
+ *	SK_MC_FILTERING_INEXACT
+ *	SK_ADDR_ILLEGAL_PORT
+ */
+int	SkAddrGmacMcUpdate(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* I/O context */
+SK_U32	PortNumber)	/* Port Number */
+{
+	SK_U32		i;
+	SK_U8		Inexact;
+	SK_U16		*OutAddr;
+	SK_ADDR_PORT	*pAPort;
+
+	SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+		("SkAddrGmacMcUpdate on Port %u.\n", PortNumber))
+	
+	pAPort = &pAC->Addr.Port[PortNumber];
+
+#ifdef DEBUG
+	SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+		("Next0 on Port %d: %d\n", PortNumber, Next0[PortNumber]))
+#endif	/* DEBUG */
+	
+	for (Inexact = 0, i = 0; i < 8; i++) {
+		Inexact |= pAPort->InexactFilter.Bytes[i];
+	}
+	
+	/* Set 64-bit hash register to InexactFilter. */
+	GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1,
+		&pAPort->InexactFilter.Bytes[0]);
+	
+	if (pAPort->PromMode & SK_PROM_MODE_ALL_MC) {				
+		
+		/* Set all bits in 64-bit hash register. */
+		GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1, &OnesHash);
+		
+		/* Enable Hashing */
+		SkMacHashing(pAC, IoC, PortNumber, SK_TRUE);
+	}
+	else {	
+		/* Enable Hashing. */
+		SkMacHashing(pAC, IoC, PortNumber, SK_TRUE);
+	}
+	
+	if (pAPort->PromMode != SK_PROM_MODE_NONE) {
+		(void) SkAddrGmacPromiscuousChange(pAC, IoC, PortNumber, pAPort->PromMode);
+	}
+	
+	/* Set port's current physical MAC address. */
+	OutAddr = (SK_U16 *) &pAPort->CurrentMacAddress.a[0];
+	GM_OUTADDR(IoC, PortNumber, GM_SRC_ADDR_1L, OutAddr);
+	
+	/* Set port's current logical MAC address. */
+	OutAddr = (SK_U16 *) &pAPort->Exact[0].a[0];
+	GM_OUTADDR(IoC, PortNumber, GM_SRC_ADDR_2L, OutAddr);
+	
+#ifdef DEBUG
+	SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+		("SkAddrGmacMcUpdate: Permanent Physical MAC Address: %02X %02X %02X %02X %02X %02X\n",
+			pAPort->Exact[0].a[0],
+			pAPort->Exact[0].a[1],
+			pAPort->Exact[0].a[2],
+			pAPort->Exact[0].a[3],
+			pAPort->Exact[0].a[4],
+			pAPort->Exact[0].a[5]))
+	
+	SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+		("SkAddrGmacMcUpdate: Physical MAC Address: %02X %02X %02X %02X %02X %02X\n",
+			pAPort->CurrentMacAddress.a[0],
+			pAPort->CurrentMacAddress.a[1],
+			pAPort->CurrentMacAddress.a[2],
+			pAPort->CurrentMacAddress.a[3],
+			pAPort->CurrentMacAddress.a[4],
+			pAPort->CurrentMacAddress.a[5]))
+#endif	/* DEBUG */
+	
+	/* Determine return value. */
+	if (Inexact == 0 && pAPort->PromMode == 0) {
+		return (SK_MC_FILTERING_EXACT);
+	}
+	else {
+		return (SK_MC_FILTERING_INEXACT);
+	}
+	
+}	/* SkAddrGmacMcUpdate */
 
 
 /******************************************************************************
@@ -863,7 +1347,7 @@
 
 	NetNumber = pAC->Rlmt.Port[PortNumber].Net->NetNumber;
 
-	if (PortNumber >= (SK_U32)pAC->GIni.GIMacsFound) {
+	if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
 		return (SK_ADDR_ILLEGAL_PORT);
 	}
 
@@ -877,7 +1361,7 @@
 
 	if (Flags & SK_ADDR_SET_LOGICAL) {	/* Activate logical MAC address. */
 		/* Parameter *pNewAddr is ignored. */
-		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+		for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
 			if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
 				return (SK_ADDR_TOO_EARLY);
 			}
@@ -891,12 +1375,12 @@
 			pAC->Addr.Net[NetNumber].CurrentMacAddress;
 
 		/* Write address to first exact match entry of active port. */
-		(void)SkAddrMcUpdate(pAC, IoC, PortNumber);
+		(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++) {
+		for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
 			if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
 				return (SK_ADDR_TOO_EARLY);
 			}
@@ -911,7 +1395,7 @@
 		}
 
 		/* Write address to first exact match entry of active port. */
-		(void)SkAddrMcUpdate(pAC, IoC, PortNumber);
+		(void) SkAddrMcUpdate(pAC, IoC, PortNumber);
 	}
 	else if (Flags & SK_ADDR_PHYSICAL_ADDRESS) {	/* Physical MAC address. */
 		if (SK_ADDR_EQUAL(pNewAddr->a,
@@ -919,7 +1403,7 @@
 			return (SK_ADDR_DUPLICATE_ADDRESS);
 		}
 
-		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+		for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
 			if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
 				return (SK_ADDR_TOO_EARLY);
 			}
@@ -939,9 +1423,15 @@
 			pAC->Addr.Port[PortNumber].CurrentMacAddress;
 		pAC->Addr.Port[PortNumber].CurrentMacAddress = *pNewAddr;
 
-		/* Change port's address. */
-		OutAddr = (SK_U16 *)pNewAddr;
-		XM_OUTADDR(IoC, PortNumber, XM_SA, OutAddr);
+		/* Change port's physical MAC address. */
+		OutAddr = (SK_U16 *) pNewAddr;
+		
+		if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+			XM_OUTADDR(IoC, PortNumber, XM_SA, OutAddr);
+		}
+		else {
+			GM_OUTADDR(IoC, PortNumber, GM_SRC_ADDR_1L, OutAddr);
+		}
 
 		/* Report address change to RLMT. */
 		Para.Para32[0] = PortNumber;
@@ -954,7 +1444,7 @@
 			return (SK_ADDR_SUCCESS);
 		}
 		
-		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+		for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
 			if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
 				return (SK_ADDR_TOO_EARLY);
 			}
@@ -971,24 +1461,18 @@
 
 		pAC->Addr.Net[NetNumber].CurrentMacAddress = *pNewAddr;
 		pAC->Addr.Port[PortNumber].Exact[0] = *pNewAddr;
-
 #ifdef DEBUG
-		SK_DBG_MSG(
-			pAC,
-			SK_DBGMOD_ADDR,
-			SK_DBGCAT_CTRL,
-			("Permanent MAC Address: %02X %02X %02X %02X %02X %02X\n",
+		SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+			("SkAddrOverride: Permanent MAC Address: %02X %02X %02X %02X %02X %02X\n",
 				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",
+		
+		SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+			("SkAddrOverride: New logical MAC Address: %02X %02X %02X %02X %02X %02X\n",
 				pAC->Addr.Net[NetNumber].CurrentMacAddress.a[0],
 				pAC->Addr.Net[NetNumber].CurrentMacAddress.a[1],
 				pAC->Addr.Net[NetNumber].CurrentMacAddress.a[2],
@@ -998,10 +1482,11 @@
 #endif	/* DEBUG */
 
 		/* Write address to first exact match entry of active port. */
-		(void)SkAddrMcUpdate(pAC, IoC, PortNumber);
+		(void) SkAddrMcUpdate(pAC, IoC, PortNumber);
 	}
 
 	return (SK_ADDR_SUCCESS);
+	
 }	/* SkAddrOverride */
 
 
@@ -1015,6 +1500,10 @@
  *	- all LLC frames
  *	- all MC frames
  *
+ *	It calls either SkAddrXmacPromiscuousChange or
+ *	SkAddrGmacPromiscuousChange, according to the adapter in use.
+ *	The real work is done there.
+ *
  * Context:
  *	runtime, pageable
  *	may be called after SK_INIT_IO
@@ -1029,6 +1518,48 @@
 SK_U32	PortNumber,		/* port whose promiscuous mode changes */
 int		NewPromMode)	/* new promiscuous mode */
 {
+	int ReturnCode;
+	
+	if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
+		return (SK_ADDR_ILLEGAL_PORT);
+	}
+	
+	if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+		ReturnCode = SkAddrXmacPromiscuousChange(pAC, IoC, PortNumber, NewPromMode);
+	}
+	else {
+		ReturnCode = SkAddrGmacPromiscuousChange(pAC, IoC, PortNumber, NewPromMode);
+	}
+
+	return (ReturnCode);
+
+}	/* SkAddrPromiscuousChange */
+
+
+/******************************************************************************
+ *
+ *	SkAddrXmacPromiscuousChange - set promiscuous mode for given port
+ *
+ * Description:
+ *	This routine manages promiscuous mode:
+ *	- none
+ *	- all LLC frames
+ *	- all MC frames
+ *
+ * Context:
+ *	runtime, pageable
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	SK_ADDR_SUCCESS
+ *	SK_ADDR_ILLEGAL_PORT
+ */
+int	SkAddrXmacPromiscuousChange(
+SK_AC	*pAC,			/* adapter context */
+SK_IOC	IoC,			/* I/O context */
+SK_U32	PortNumber,		/* port whose promiscuous mode changes */
+int		NewPromMode)	/* new promiscuous mode */
+{
 	int			i;
 	SK_BOOL		InexactModeBit;
 	SK_U8		Inexact;
@@ -1037,14 +1568,11 @@
 	SK_U16		LoMode;		/* Lower 16 bits of XMAC Mode Register. */
 	int			CurPromMode = SK_PROM_MODE_NONE;
 
-	if (PortNumber >= (SK_U32)pAC->GIni.GIMacsFound) {
-		return (SK_ADDR_ILLEGAL_PORT);
-	}
-
 	/* Read CurPromMode from Hardware. */
 	XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
 
-	if (LoMode & XM_MD_ENA_PROM) {
+	if ((LoMode & XM_MD_ENA_PROM) != 0) {
+		/* Promiscuous mode! */
 		CurPromMode |= SK_PROM_MODE_LLC;
 	}
 	
@@ -1055,12 +1583,12 @@
 		CurPromMode |= (pAC->Addr.Port[PortNumber].PromMode & SK_PROM_MODE_ALL_MC);
 	}
 	else {
-		/* Read InexactModeBit (bit 15 in mode register). */
+		/* Get InexactModeBit (bit XM_MD_ENA_HASH in mode register) */
 		XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
 		
-		InexactModeBit = (LoMode & XM_MD_ENA_HSH) != 0;
+		InexactModeBit = (LoMode & XM_MD_ENA_HASH) != 0;
 
-		/* Read 64-bit hash register from HW. */
+		/* Read 64-bit hash register from XMAC */
 		XM_INHASH(IoC, PortNumber, XM_HSM, &HwInexactFilter.Bytes[0]);
 
 		for (HwInexact = 0xFF, i = 0; i < 8; i++) {
@@ -1080,13 +1608,12 @@
 
 	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, PortNumber, XM_HSM, &OnesHash);
 
-		/* Set bit 15 in mode register. */
-		XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
-		LoMode |= XM_MD_ENA_HSH;
-		XM_OUT16(IoC, PortNumber, XM_MODE, LoMode);
+		/* Enable Hashing */
+		SkMacHashing(pAC, IoC, PortNumber, SK_TRUE);
 	}
 	else if ((CurPromMode & SK_PROM_MODE_ALL_MC) &&
 		!(NewPromMode & SK_PROM_MODE_ALL_MC)) {	/* Norm MC. */
@@ -1094,55 +1621,118 @@
 			Inexact |= pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i];
 		}
 		if (Inexact == 0) {
-			/* Clear bit 15 in mode register. */
-			XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
-			LoMode &= ~XM_MD_ENA_HSH;
-			XM_OUT16(IoC, PortNumber, XM_MODE, LoMode);
+			/* Disable Hashing */
+			SkMacHashing(pAC, IoC, PortNumber, SK_FALSE);
 		}
 		else {
 			/* Set 64-bit hash register to InexactFilter. */
-			XM_OUTHASH(
-				IoC,
-				PortNumber,
-				XM_HSM,
+			XM_OUTHASH(IoC, PortNumber, XM_HSM,
 				&pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0]);
 
-			/* Set bit 15 in mode register. */
-			XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
-			LoMode |= XM_MD_ENA_HSH;
-			XM_OUT16(IoC, PortNumber, XM_MODE, LoMode);
+			/* Enable Hashing */
+			SkMacHashing(pAC, IoC, PortNumber, SK_TRUE);
 		}
 	}
 
 	if ((NewPromMode & SK_PROM_MODE_LLC) &&
 		!(CurPromMode & SK_PROM_MODE_LLC)) {	/* Prom. LLC */
-		/* Set promiscuous bit in mode register. */
-		XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
-
-#if 0
-		/* Receive MAC frames. */
-		LoMode |= XM_MD_RX_MCTRL;
-#endif	/* 0 */
-
-		LoMode |= XM_MD_ENA_PROM;
-		XM_OUT16(IoC, PortNumber, XM_MODE, LoMode);
+		/* Set the MAC in Promiscuous Mode */
+		SkMacPromiscMode(pAC, IoC, PortNumber, SK_TRUE);
 	}
 	else if ((CurPromMode & SK_PROM_MODE_LLC) &&
 		!(NewPromMode & SK_PROM_MODE_LLC)) {	/* Norm. LLC. */
-		/* Clear promiscuous bit in mode register. */
-		XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
+		/* Clear Promiscuous Mode */
+		SkMacPromiscMode(pAC, IoC, PortNumber, SK_FALSE);
+	}
+	
+	return (SK_ADDR_SUCCESS);
+	
+}	/* SkAddrXmacPromiscuousChange */
+
+
+/******************************************************************************
+ *
+ *	SkAddrGmacPromiscuousChange - set promiscuous mode for given port
+ *
+ * Description:
+ *	This routine manages promiscuous mode:
+ *	- none
+ *	- all LLC frames
+ *	- all MC frames
+ *
+ * Context:
+ *	runtime, pageable
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	SK_ADDR_SUCCESS
+ *	SK_ADDR_ILLEGAL_PORT
+ */
+int	SkAddrGmacPromiscuousChange(
+SK_AC	*pAC,			/* adapter context */
+SK_IOC	IoC,			/* I/O context */
+SK_U32	PortNumber,		/* port whose promiscuous mode changes */
+int		NewPromMode)	/* new promiscuous mode */
+{
+	SK_U16		ReceiveControl;	/* GMAC Receive Control Register */
+	int		CurPromMode = SK_PROM_MODE_NONE;
+
+	/* Read CurPromMode from Hardware. */
+	GM_IN16(IoC, PortNumber, GM_RX_CTRL, &ReceiveControl);
+
+	if ((ReceiveControl & (GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA)) == 0) {
+		/* Promiscuous mode! */
+		CurPromMode |= SK_PROM_MODE_LLC;
+	}
+
+	if ((ReceiveControl & GM_RXCR_MCF_ENA) == 0) {
+		/* All Multicast mode! */
+		CurPromMode |= (pAC->Addr.Port[PortNumber].PromMode & SK_PROM_MODE_ALL_MC);
+	}
 
-#if 0
-		/* Don't receive MAC frames. */
-		LoMode &= ~XM_MD_RX_MCTRL;
-#endif	/* 0 */
+	pAC->Addr.Port[PortNumber].PromMode = NewPromMode;
+
+	if (NewPromMode == CurPromMode) {
+		return (SK_ADDR_SUCCESS);
+	}
+	
+	if ((NewPromMode & SK_PROM_MODE_ALL_MC) &&
+		!(CurPromMode & SK_PROM_MODE_ALL_MC)) {	/* All MC */
 		
-		LoMode &= ~XM_MD_ENA_PROM;
-		XM_OUT16(IoC, PortNumber, XM_MODE, LoMode);
+		/* Set all bits in 64-bit hash register. */
+		GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1, &OnesHash);
+		
+		/* Enable Hashing */
+		SkMacHashing(pAC, IoC, PortNumber, SK_TRUE);
 	}
 	
+	if ((CurPromMode & SK_PROM_MODE_ALL_MC) &&
+		!(NewPromMode & SK_PROM_MODE_ALL_MC)) {	/* Norm. MC */
+
+		/* Set 64-bit hash register to InexactFilter. */
+		GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1,
+			&pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0]);
+
+		/* Enable Hashing. */
+		SkMacHashing(pAC, IoC, PortNumber, SK_TRUE);
+	}
+
+	if ((NewPromMode & SK_PROM_MODE_LLC) &&
+		!(CurPromMode & SK_PROM_MODE_LLC)) {	/* Prom. LLC */
+		
+		/* Set the MAC to Promiscuous Mode. */
+		SkMacPromiscMode(pAC, IoC, PortNumber, SK_TRUE);
+	}
+	else if ((CurPromMode & SK_PROM_MODE_LLC) &&
+		!(NewPromMode & SK_PROM_MODE_LLC)) {	/* Norm. LLC */
+		
+		/* Clear Promiscuous Mode. */
+		SkMacPromiscMode(pAC, IoC, PortNumber, SK_FALSE);
+	}
+
 	return (SK_ADDR_SUCCESS);
-}	/* SkAddrPromiscuousChange */
+	
+}	/* SkAddrGmacPromiscuousChange */
 
 
 /******************************************************************************
@@ -1163,7 +1753,7 @@
 int	SkAddrSwap(
 SK_AC	*pAC,			/* adapter context */
 SK_IOC	IoC,			/* I/O context */
-SK_U32	FromPortNumber,	/* Port1 Index */
+SK_U32	FromPortNumber,		/* Port1 Index */
 SK_U32	ToPortNumber)		/* Port2 Index */
 {
 	int			i;
@@ -1171,11 +1761,11 @@
 	SK_MAC_ADDR	MacAddr;
 	SK_U32		DWord;
 
-	if (FromPortNumber >= (SK_U32)pAC->GIni.GIMacsFound) {
+	if (FromPortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
 		return (SK_ADDR_ILLEGAL_PORT);
 	}
 
-	if (ToPortNumber >= (SK_U32)pAC->GIni.GIMacsFound) {
+	if (ToPortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
 		return (SK_ADDR_ILLEGAL_PORT);
 	}
 
@@ -1184,13 +1774,15 @@
 	}
 
 	/*
-	 * Swap
-	 * - Exact Match Entries
-	 * - FirstExactMatchRlmt;
-	 * - NextExactMatchRlmt;
-	 * - FirstExactMatchDrv;
-	 * - NextExactMatchDrv;
-	 * - 64-bit filter
+	 * Swap:
+	 * - Exact Match Entries (GEnesis and Yukon)
+	 *   Yukon uses first entry for the logical MAC
+	 *   address (stored in the second GMAC register).
+	 * - FirstExactMatchRlmt (GEnesis only)
+	 * - NextExactMatchRlmt (GEnesis only)
+	 * - FirstExactMatchDrv (GEnesis only)
+	 * - NextExactMatchDrv (GEnesis only)
+	 * - 64-bit filter (InexactFilter)
 	 * - Promiscuous Mode
 	 * of ports.
 	 */
@@ -1208,46 +1800,49 @@
 			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;
-
+	
+	if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+		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].
+	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, FromPortNumber);
-	(void)SkAddrMcUpdate(pAC, IoC, ToPortNumber);
+	
+	(void) SkAddrMcUpdate(pAC, IoC, FromPortNumber);
+	(void) SkAddrMcUpdate(pAC, IoC, ToPortNumber);
 
 	return (SK_ADDR_SUCCESS);
+	
 }	/* SkAddrSwap */
 
 #ifdef __cplusplus
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sk98lin/skcsum.c linux-2.4.21-pre6/drivers/net/sk98lin/skcsum.c
--- linux-2.4.20/drivers/net/sk98lin/skcsum.c	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sk98lin/skcsum.c	2003-03-26 23:48:58.000000000 +0000
@@ -2,8 +2,8 @@
  *
  * Name:	skcsum.c
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.8 $
- * Date:	$Date: 2001/02/06 11:15:36 $
+ * Version:	$Revision: 1.10 $
+ * Date:	$Date: 2002/04/11 10:02:04 $
  * Purpose:	Store/verify Internet checksum in send/receive packets.
  *
  ******************************************************************************/
@@ -26,6 +26,15 @@
  * History:
  *
  *	$Log: skcsum.c,v $
+ *	Revision 1.10  2002/04/11 10:02:04  rwahl
+ *	Fix in SkCsGetSendInfo():
+ *	- function did not return ProtocolFlags in every case.
+ *	- pseudo header csum calculated wrong for big endian.
+ *	
+ *	Revision 1.9  2001/06/13 07:42:08  gklug
+ *	fix: NetNumber was wrong in CLEAR_STAT event
+ *	add: check for good NetNumber in Clear STAT
+ *	
  *	Revision 1.8  2001/02/06 11:15:36  rassmann
  *	Supporting two nets on dual-port adapters.
  *	
@@ -65,7 +74,7 @@
 
 #ifndef lint
 static const char SysKonnectFileId[] = "@(#)"
-	"$Id: skcsum.c,v 1.8 2001/02/06 11:15:36 rassmann Exp $"
+	"$Id: skcsum.c,v 1.10 2002/04/11 10:02:04 rwahl Exp $"
 	" (C) SysKonnect.";
 #endif	/* !lint */
 
@@ -195,7 +204,7 @@
  *	zero.)
  *
  * Note:
- *	There is a bug in the ASIC whic may lead to wrong checksums.
+ *	There is a bug in the ASIC which may lead to wrong checksums.
  *
  * Arguments:
  *	pAc - A pointer to the adapter context struct.
@@ -411,9 +420,9 @@
 			SKCS_OFS_IP_DESTINATION_ADDRESS + 0) +
 		(unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader,
 			SKCS_OFS_IP_DESTINATION_ADDRESS + 2) +
-		(unsigned long) (NextLevelProtocol << 8) +
+		(unsigned long) SKCS_HTON16(NextLevelProtocol) +
 		(unsigned long) SKCS_HTON16(IpDataLength);
-
+	
 	/* Add-in any carries. */
 
 	SKCS_OC_ADD(PseudoHeaderChecksum, PseudoHeaderChecksum, 0);
@@ -422,6 +431,7 @@
 
 	SKCS_OC_ADD(pPacketInfo->PseudoHeaderChecksum, PseudoHeaderChecksum, 0);
 
+	pPacketInfo->ProtocolFlags = ProtocolFlags;
 	NextLevelProtoStats->TxOkCts++;	/* Success. */
 }	/* SkCsGetSendInfo */
 
@@ -889,11 +899,13 @@
 	 */
 	case SK_CSUM_EVENT_CLEAR_PROTO_STATS:
 
-		ProtoIndex = (int)Param.Para32[0];
-		NetNumber = (int)Param.Para32[1];
+		ProtoIndex = (int)Param.Para32[1];
+		NetNumber = (int)Param.Para32[0];
 		if (ProtoIndex < 0) {	/* Clear for all protocols. */
-			memset(&pAc->Csum.ProtoStats[NetNumber][0], 0,
-				sizeof(pAc->Csum.ProtoStats[NetNumber]));
+			if (NetNumber >= 0) {
+				memset(&pAc->Csum.ProtoStats[NetNumber][0], 0,
+					sizeof(pAc->Csum.ProtoStats[NetNumber]));
+			}
 		}
 		else {					/* Clear for individual protocol. */
 			memset(&pAc->Csum.ProtoStats[NetNumber][ProtoIndex], 0,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sk98lin/skge.c linux-2.4.21-pre6/drivers/net/sk98lin/skge.c
--- linux-2.4.20/drivers/net/sk98lin/skge.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sk98lin/skge.c	2003-03-26 23:49:08.000000000 +0000
@@ -2,18 +2,20 @@
  *
  * Name:    skge.c
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.29.2.6 $
- * Date:       	$Date: 2001/05/21 07:59:29 $
+ * Version:	$Revision: 1.43 $
+ * Date:       	$Date: 2002/11/29 08:42:41 $
  * Purpose:	The main driver source module
  *
  ******************************************************************************/
  
 /******************************************************************************
  *
- *	(C)Copyright 1998-2001 SysKonnect GmbH.
+ *	(C)Copyright 1998-2002 SysKonnect GmbH.
  *
  *	Driver for SysKonnect Gigabit Ethernet Server Adapters:
  *
+ *	SK-9871 (single link 1000Base-ZX)
+ *	SK-9872 (dual link   1000Base-ZX)
  *	SK-9861 (single link 1000Base-SX, VF45 Volition Plug)
  *	SK-9862 (dual link   1000Base-SX, VF45 Volition Plug)
  *	SK-9841 (single link 1000Base-LX)
@@ -22,6 +24,12 @@
  *	SK-9844 (dual link   1000Base-SX)
  *	SK-9821 (single link 1000Base-T)
  *	SK-9822 (dual link   1000Base-T)
+ *	SK-9881 (single link 1000Base-SX V2 LC)
+ *	SK-9871 (single link 1000Base-ZX V2)
+ *	SK-9861 (single link 1000Base-SX V2, VF45 Volition Plug)
+ *	SK-9841 (single link 1000Base-LX V2)
+ *	SK-9843 (single link 1000Base-SX V2)
+ *	SK-9821 (single link 1000Base-T V2)
  *
  *	Created 10-Feb-1999, based on Linux' acenic.c, 3c59x.c and 
  *	SysKonnects GEnesis Solaris driver
@@ -48,6 +56,62 @@
  * History:
  *
  *	$Log: skge.c,v $
+ *	Revision 1.43  2002/11/29 08:42:41  mlindner
+ *	Fix: Boot message
+ *	
+ *	Revision 1.42  2002/11/28 13:30:23  mlindner
+ *	Add: New frame check
+ *	
+ *	Revision 1.41  2002/11/27 13:55:18  mlindner
+ *	Fix: Drop wrong csum packets
+ *	Fix: Initialize proc_entry after hw check
+ *	
+ *	Revision 1.40  2002/10/31 07:50:37  tschilli
+ *	Function SkGeInitAssignRamToQueues() from common module inserted.
+ *	Autonegotiation is set to ON for all adapters.
+ *	LinkSpeedUsed is used in link up status report.
+ *	Role parameter will show up for 1000 Mbps links only.
+ *	GetConfiguration() inserted after init level 1 in SkGeChangeMtu().
+ *	All return values of SkGeInit() and SkGeInitPort() are checked.
+ *	
+ *	Revision 1.39  2002/10/02 12:56:05  mlindner
+ *	Add: Support for Yukon
+ *	Add: Support for ZEROCOPY, scatter-gather and hw checksum
+ *	Add: New transmit ring function (use SG and TCP/UDP hardware checksumming)
+ *	Add: New init function
+ *	Add: Speed check and setup
+ *	Add: Merge source for kernel 2.2.x and 2.4.x
+ *	Add: Opcode check for tcp
+ *	Add: Frame length check
+ *	Fix: Transmit complete interrupt
+ *	Fix: Interrupt moderation
+ *	
+ *	Revision 1.29.2.13  2002/01/14 12:44:52  mlindner
+ *	Fix: Rlmt modes
+ *	
+ *	Revision 1.29.2.12  2001/12/07 12:06:18  mlindner
+ *	Fix: malloc -> slab changes
+ *	
+ *	Revision 1.29.2.11  2001/12/06 15:19:20  mlindner
+ *	Add: DMA attributes
+ *	Fix: Module initialisation
+ *	Fix: pci_map_single and pci_unmap_single replaced
+ *	
+ *	Revision 1.29.2.10  2001/12/06 09:56:50  mlindner
+ *	Corrected some printk's
+ *	
+ *	Revision 1.29.2.9  2001/09/05 12:15:34  mlindner
+ *	Add: LBFO Changes
+ *	Fix: Counter Errors (Jumbo == to long errors)
+ *	Fix: Changed pAC->PciDev declaration
+ *	Fix: too short counters
+ *	
+ *	Revision 1.29.2.8  2001/06/25 12:10:44  mlindner
+ *	fix: ReceiveIrq() changed.
+ *	
+ *	Revision 1.29.2.7  2001/06/25 08:07:05  mlindner
+ *	fix: RLMT locking in ReceiveIrq() changed.
+ *	
  *	Revision 1.29.2.6  2001/05/21 07:59:29  mlindner
  *	fix: MTU init problems
  *	
@@ -266,24 +330,26 @@
  ******************************************************************************/
 
 #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 ******************************************************************/
 /* for debuging on x86 only */
 /* #define BREAKPOINT() asm(" int $3"); */
 
+/* use the scatter-gather functionality with sendfile() */
+#define SK_ZEROCOPY
+
 /* use of a transmit complete interrupt */
 #define USE_TX_COMPLETE
 
 /* use interrupt moderation (for tx complete only) */
-// #define USE_INT_MOD
-#define INTS_PER_SEC	1000
+#define USE_INT_MOD
+#define INTS_PER_SEC	1800
 
 /*
  * threshold for copying small receive frames
@@ -294,10 +360,13 @@
 /* number of adapters that can be configured via command line params */
 #define SK_MAX_CARD_PARAM	16
 
+
 /*
  * use those defines for a compile-in version of the driver instead 
  * of command line parameters
  */
+// #define LINK_SPEED_A	{"Auto", }
+// #define LINK_SPEED_B	{"Auto", }
 // #define AUTO_NEG_A	{"Sense", }
 // #define AUTO_NEG_B	{"Sense", }
 // #define DUP_CAP_A	{"Both", }
@@ -314,10 +383,8 @@
 #define DEV_KFREE_SKB_ANY(skb) dev_kfree_skb_any(skb)
 
 /* function prototypes ******************************************************/
-static void	FreeResources(struct net_device *dev);
-int		init_module(void);
-void		cleanup_module(void);
-static int	SkGeBoardInit(struct net_device *dev, SK_AC *pAC);
+static void	FreeResources(struct SK_NET_DEVICE *dev);
+static int	SkGeBoardInit(struct SK_NET_DEVICE *dev, SK_AC *pAC);
 static SK_BOOL	BoardAllocMem(SK_AC *pAC);
 static void	BoardFreeMem(SK_AC *pAC);
 static void	BoardInitMem(SK_AC *pAC);
@@ -326,66 +393,62 @@
 
 static void	SkGeIsr(int irq, void *dev_id, struct pt_regs *ptregs);
 static void	SkGeIsrOnePort(int irq, void *dev_id, struct pt_regs *ptregs);
-static int	SkGeOpen(struct net_device *dev);
-static int	SkGeClose(struct net_device *dev);
-static int	SkGeXmit(struct sk_buff *skb, struct net_device *dev);
-static int	SkGeSetMacAddr(struct net_device *dev, void *p);
-static void	SkGeSetRxMode(struct net_device *dev);
-static struct net_device_stats *SkGeStats(struct net_device *dev);
-static int	SkGeIoctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static int	SkGeOpen(struct SK_NET_DEVICE *dev);
+static int	SkGeClose(struct SK_NET_DEVICE *dev);
+static int	SkGeXmit(struct sk_buff *skb, struct SK_NET_DEVICE *dev);
+static int	SkGeSetMacAddr(struct SK_NET_DEVICE *dev, void *p);
+static void	SkGeSetRxMode(struct SK_NET_DEVICE *dev);
+static struct	net_device_stats *SkGeStats(struct SK_NET_DEVICE *dev);
+static int	SkGeIoctl(struct SK_NET_DEVICE *dev, struct ifreq *rq, int cmd);
 static void	GetConfiguration(SK_AC*);
 static void	ProductStr(SK_AC*);
 static int	XmitFrame(SK_AC*, TX_PORT*, struct sk_buff*);
 static void	FreeTxDescriptors(SK_AC*pAC, TX_PORT*);
 static void	FillRxRing(SK_AC*, RX_PORT*);
 static SK_BOOL	FillRxDescriptor(SK_AC*, RX_PORT*);
-static void	ReceiveIrq(SK_AC*, RX_PORT*);
-static void	ClearAndStartRx(SK_AC*, int);
+static void	ReceiveIrq(SK_AC*, RX_PORT*, SK_BOOL);
+static void ClearAndStartRx(SK_AC*, int);
 static void	ClearTxIrq(SK_AC*, int, int);
 static void	ClearRxRing(SK_AC*, RX_PORT*);
 static void	ClearTxRing(SK_AC*, TX_PORT*);
 static void	SetQueueSizes(SK_AC	*pAC);
-static int	SkGeChangeMtu(struct net_device *dev, int new_mtu);
+static int	SkGeChangeMtu(struct SK_NET_DEVICE *dev, int new_mtu);
 static void	PortReInitBmu(SK_AC*, int);
 static int	SkGeIocMib(DEV_NET*, unsigned int, int);
-
+static int	XmitFrameSG(SK_AC*, TX_PORT*, struct sk_buff*);
 
 /*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);
-
+/* external Proc function */
+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);
 static void	DumpLong(char*, int);
 #endif
-
+void dump_frag( SK_U8 *data, int length);
 
 /* global variables *********************************************************/
 static const char *BootString = BOOT_STRING;
-struct net_device *sk98lin_root_dev = NULL;
+struct SK_NET_DEVICE *SkGeRootDev = 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};
 
 
+/* local variables **********************************************************/
+const char SK_Root_Dir_entry[8];
 
-void proc_fill_inode(struct inode *inode, int fill)
-{
-	if (fill)
-		MOD_INC_USE_COUNT;
-	else
-		MOD_DEC_USE_COUNT;
-}
+static struct proc_dir_entry	*pSkRootDir;
 
 
 
@@ -405,51 +468,53 @@
 static int __init skge_probe (void)
 {
 	int			proc_root_initialized = 0;
-	int 		boards_found = 0;
-	int			version_disp = 0;
-	SK_AC		*pAC;
-	DEV_NET		*pNet = NULL;
-	struct 		pci_dev	*pdev = NULL;
-	unsigned long		base_address;
-	struct net_device *dev = NULL;
+	int			boards_found = 0;
+	SK_AC			*pAC;
+	DEV_NET			*pNet = NULL;
 	struct proc_dir_entry	*pProcFile;
+	struct pci_dev	*pdev = NULL;
+	unsigned long		base_address;
+	struct SK_NET_DEVICE *dev = NULL;
+	SK_BOOL DeviceFound = SK_FALSE;
+	SK_BOOL BootStringCount = SK_FALSE;
 
 	if (probed)
 		return -ENODEV;
 	probed++;
-	
-	/* display driver info */
-	if (!version_disp)
-	{
-		/* set display flag to TRUE so that */
-		/* we only display this string ONCE */
-		version_disp = 1;
-		printk("%s\n", BootString);
-	}
 
 	if (!pci_present())		/* is PCI support present? */
 		return -ENODEV;
 
-	while((pdev = pci_find_device(PCI_VENDOR_ID_SYSKONNECT,
-				      PCI_DEVICE_ID_SYSKONNECT_GE, pdev)) != NULL) {
+		while((pdev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET << 8, pdev)))
+		{
 
 		dev = NULL;
 		pNet = NULL;
 
-		if (pci_enable_device(pdev))
+		if ((pdev->vendor != PCI_VENDOR_ID_SYSKONNECT) && 
+			((pdev->device != PCI_DEVICE_ID_SYSKONNECT_GE) || 
+			(pdev->device != PCI_DEVICE_ID_SYSKONNECT_YU))){
 			continue;
+		}
 
 		/* Configure DMA attributes. */
 		if (pci_set_dma_mask(pdev, (u64) 0xffffffffffffffff) &&
-		    pci_set_dma_mask(pdev, (u64) 0xffffffff))
-				continue;
+			pci_set_dma_mask(pdev, (u64) 0xffffffff))
+			continue;
+
 
-		if ((dev = init_etherdev(dev, sizeof(DEV_NET))) == 0) {
+		if ((dev = init_etherdev(dev, sizeof(DEV_NET))) == NULL) {
 			printk(KERN_ERR "Unable to allocate etherdev "
 			       "structure!\n");
 			break;
 		}
 
+		if (dev->priv == NULL) {
+			printk(KERN_ERR "Unable to allocate adapter "
+			       "structure!\n");
+			break;
+		}
+
 		pNet = dev->priv;
 		pNet->pAC = kmalloc(sizeof(SK_AC), GFP_KERNEL);
 		if (pNet->pAC == NULL){
@@ -459,15 +524,23 @@
 			break;
 		}
 
+		/* Print message */
+		if (!BootStringCount) {
+			/* set display flag to TRUE so that */
+			/* we only display this string ONCE */
+			BootStringCount = SK_TRUE;
+			printk("%s\n", BootString);
+		}
+
 		memset(pNet->pAC, 0, sizeof(SK_AC));
 		pAC = pNet->pAC;
-		pAC->PciDev = *pdev;
+		pAC->PciDev = pdev;
 		pAC->PciDevId = pdev->device;
 		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;
@@ -480,28 +553,23 @@
 		dev->set_mac_address =	&SkGeSetMacAddr;
 		dev->do_ioctl =		&SkGeIoctl;
 		dev->change_mtu =	&SkGeChangeMtu;
+		dev->flags &= 		~IFF_RUNNING;
 
-		if(!proc_root_initialized) {
-			pSkRootDir = create_proc_entry("sk98lin",
-				S_IFDIR | S_IWUSR | S_IRUGO | S_IXUGO, proc_net);
-			pSkRootDir->owner = THIS_MODULE;
-
-			proc_root_initialized = 1;
+#ifdef SK_ZEROCOPY
+		if (pAC->GIni.GIChipId == CHIP_ID_YUKON) {
+			/* Use only if yukon hardware */
+			/* SK and ZEROCOPY - fly baby... */
+			dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
 		}
-
-		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;
+#endif
 
 		/*
 		 * Dummy value.
 		 */
 		dev->base_addr = 42;
 		pci_set_master(pdev);
+
+		pci_set_master(pdev);
 		base_address = pci_resource_start (pdev, 0);
 
 #ifdef SK_BIG_ENDIAN
@@ -515,13 +583,13 @@
 			our2 |= PCI_REV_DESC;
 			SkPciWriteCfgDWord(pAC, PCI_OUR_REG_2, our2);
 		}
-#endif /* BIG ENDIAN */
+#endif
 
 		/*
 		 * 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",
@@ -529,8 +597,8 @@
 			kfree(dev);
 			break;
 		}
-		pAC->Index = boards_found;
 
+		pAC->Index = boards_found;
 		if (SkGeBoardInit(dev, pAC)) {
 			FreeResources(dev);
 			kfree(dev);
@@ -540,9 +608,46 @@
 		memcpy((caddr_t) &dev->dev_addr,
 			(caddr_t) &pAC->Addr.Net[0].CurrentMacAddress, 6);
 
+		/* First adapter... Create proc and print message */
+		if (!DeviceFound) {
+			DeviceFound = SK_TRUE;
+			SK_MEMCPY(&SK_Root_Dir_entry, BootString,
+				sizeof(SK_Root_Dir_entry) - 1);
+
+			/*Create proc (directory)*/
+			if(!proc_root_initialized) {
+				pSkRootDir = create_proc_entry(SK_Root_Dir_entry,
+					S_IFDIR | S_IWUSR | S_IRUGO | S_IXUGO, proc_net);
+				proc_root_initialized = 1;
+			}
+
+			pSkRootDir->owner = THIS_MODULE;
+		}
+
+
+
+		/* Create proc file */
+		pProcFile = create_proc_entry(dev->name,
+			S_IFREG | S_IXUSR | S_IWGRP | S_IROTH,
+			pSkRootDir);
+
+		
+		pProcFile->read_proc = proc_read;
+		pProcFile->write_proc = NULL;
+		pProcFile->nlink = 1;
+		pProcFile->size = sizeof(dev->name + 1);
+		pProcFile->data = (void *)pProcFile;
+
 		pNet->PortNr = 0;
 		pNet->NetNr = 0;
 
+#ifdef SK_ZEROCOPY
+			if (pAC->GIni.GIChipId == CHIP_ID_YUKON) {
+				/* SG and ZEROCOPY - fly baby... */
+				dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
+			}
+#endif
+
 		boards_found++;
 
 		/* More then one port found */
@@ -569,24 +674,39 @@
 			dev->set_mac_address =	&SkGeSetMacAddr;
 			dev->do_ioctl =		&SkGeIoctl;
 			dev->change_mtu =	&SkGeChangeMtu;
+			dev->flags &= 		~IFF_RUNNING;
 
-			pProcFile = create_proc_entry(dev->name, 
-				S_IFREG | 0444, pSkRootDir);
+#ifdef SK_ZEROCOPY
+			if (pAC->GIni.GIChipId == CHIP_ID_YUKON) {
+				/* SG and ZEROCOPY - fly baby... */
+				dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
+			}
+#endif
+
+			pProcFile = create_proc_entry(dev->name,
+				S_IFREG | S_IXUSR | S_IWGRP | S_IROTH,
+				pSkRootDir);
+
+		
 			pProcFile->read_proc = proc_read;
 			pProcFile->write_proc = NULL;
 			pProcFile->nlink = 1;
-			pProcFile->size = sizeof(dev->name+1);
-			pProcFile->data = (void*)pProcFile;
+			pProcFile->size = sizeof(dev->name + 1);
+			pProcFile->data = (void *)pProcFile;
 
 			memcpy((caddr_t) &dev->dev_addr,
 			(caddr_t) &pAC->Addr.Net[1].CurrentMacAddress, 6);
 	
 			printk("%s: %s\n", dev->name, pAC->DeviceStr);
 			printk("      PrefPort:B  RlmtMode:Dual Check Link State\n");
-		
+
 		}
 
 
+		/* Save the hardware revision */
+		pAC->HWRevision = (((pAC->GIni.GIPciHwRev >> 4) & 0x0F)*10) +
+			(pAC->GIni.GIPciHwRev & 0x0F);
+
 		/*
 		 * This is bollocks, but we need to tell the net-init
 		 * code that it shall go for the next device.
@@ -617,7 +737,7 @@
  * Returns: N/A
  *	
  */
-static void FreeResources(struct net_device *dev)
+static void FreeResources(struct SK_NET_DEVICE *dev)
 {
 SK_U32 AllocFlag;
 DEV_NET		*pNet;
@@ -640,17 +760,19 @@
 	
 } /* FreeResources */
 
-MODULE_AUTHOR("Christoph Goos <cgoos@syskonnect.de>");
+MODULE_AUTHOR("Mirko Lindner <mlindner@syskonnect.de>");
 MODULE_DESCRIPTION("SysKonnect SK-NET Gigabit Ethernet SK-98xx driver");
 MODULE_LICENSE("GPL");
+MODULE_PARM(Speed_A,    "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s");
+MODULE_PARM(Speed_B,    "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s");
 MODULE_PARM(AutoNeg_A,  "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s");
 MODULE_PARM(AutoNeg_B,  "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s");
 MODULE_PARM(DupCap_A,   "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s");
 MODULE_PARM(DupCap_B,   "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s");
 MODULE_PARM(FlowCtrl_A, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s");
 MODULE_PARM(FlowCtrl_B, "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s");
-MODULE_PARM(Role_A,	"1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s");
-MODULE_PARM(Role_B,	"1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s");
+MODULE_PARM(Role_A,	    "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s");
+MODULE_PARM(Role_B,	    "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s");
 MODULE_PARM(PrefPort,   "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s");
 MODULE_PARM(RlmtMode,   "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s");
 /* not used, just there because every driver should have them: */
@@ -658,6 +780,18 @@
 MODULE_PARM(debug,      "i");
 
 
+#ifdef LINK_SPEED_A
+static char *Speed_A[SK_MAX_CARD_PARAM] = LINK_SPEED;
+#else
+static char *Speed_A[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef LINK_SPEED_B
+static char *Speed_B[SK_MAX_CARD_PARAM] = LINK_SPEED;
+#else
+static char *Speed_B[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
 #ifdef AUTO_NEG_A
 static char *AutoNeg_A[SK_MAX_CARD_PARAM] = AUTO_NEG_A;
 #else
@@ -718,7 +852,6 @@
 static char *RlmtMode[SK_MAX_CARD_PARAM] = {"", };
 #endif
 
-
 static int debug = 0; /* not used */
 static int options[SK_MAX_CARD_PARAM] = {0, }; /* not used */
 
@@ -737,7 +870,7 @@
 static int __init skge_init_module(void)
 {
 	int cards;
-	sk98lin_root_dev = NULL;
+	SkGeRootDev = NULL;
 	
 	/* just to avoid warnings ... */
 	debug = 0;
@@ -745,7 +878,7 @@
 
 	cards = skge_probe();
 	if (cards == 0) {
-		printk("No adapter found\n");
+		printk("No adapter found.\n");
 	}
 	return cards ? 0 : -ENODEV;
 } /* skge_init_module */
@@ -765,16 +898,16 @@
 {
 DEV_NET		*pNet;
 SK_AC		*pAC;
-struct net_device *next;
+struct SK_NET_DEVICE *next;
 unsigned long Flags;
 SK_EVPARA EvPara;
 
-	while (sk98lin_root_dev) {
-		pNet = (DEV_NET*) sk98lin_root_dev->priv;
+	while (SkGeRootDev) {
+		pNet = (DEV_NET*) SkGeRootDev->priv;
 		pAC = pNet->pAC;
 		next = pAC->Next;
 
-		netif_stop_queue(sk98lin_root_dev);
+		netif_stop_queue(SkGeRootDev);
 		SkGeYellowLED(pAC, pAC->IoBase, 0);
 
 		if(pAC->BoardLevel == 2) {
@@ -806,17 +939,17 @@
 			kfree(pAC->dev[1]);
 		}
 
-		FreeResources(sk98lin_root_dev);
+		FreeResources(SkGeRootDev);
 
-		sk98lin_root_dev->get_stats = NULL;
+		SkGeRootDev->get_stats = NULL;
 		/* 
 		 * otherwise unregister_netdev calls get_stats with
 		 * invalid IO ...  :-(
 		 */
-		unregister_netdev(sk98lin_root_dev);
-		kfree(sk98lin_root_dev);
+		unregister_netdev(SkGeRootDev);
+		kfree(SkGeRootDev);
 		kfree(pAC);
-		sk98lin_root_dev = next;
+		SkGeRootDev = next;
 	}
 
 	/* clear proc-dir */
@@ -840,13 +973,14 @@
  *	0, if everything is ok
  *	!=0, on error
  */
-static int __init SkGeBoardInit(struct net_device *dev, SK_AC *pAC)
+static int __init SkGeBoardInit(struct SK_NET_DEVICE *dev, SK_AC *pAC)
 {
 short	i;
 unsigned long Flags;
 char	*DescrString = "sk98lin: Driver for Linux"; /* this is given to PNMI */
 char	*VerStr	= VER_STRING;
 int	Ret;			/* return code of request_irq */
+SK_BOOL	DualNet;
 
 	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
 		("IoBase: %08lX\n", (unsigned long)pAC->IoBase));
@@ -858,7 +992,6 @@
 	}
 
 	/* Initialize the mutexes */
-
 	for (i=0; i<SK_MAX_MACS; i++) {
 		spin_lock_init(&pAC->TxPort[i][0].TxDesRingLock);
 		spin_lock_init(&pAC->RxPort[i].RxDesRingLock);
@@ -908,7 +1041,6 @@
 		pAC->GIni.GIPortUsage = SK_MUL_LINK;
 	}
 
-
 	pAC->BoardLevel = 1;
 	spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
 
@@ -918,12 +1050,13 @@
 		Ret = request_irq(dev->irq, SkGeIsrOnePort, SA_SHIRQ,
 			pAC->Name, dev);
 	} else {
-		printk(KERN_WARNING "%s: illegal number of ports: %d\n",
+		printk(KERN_WARNING "%s: Illegal number of ports: %d\n",
 		       dev->name, pAC->GIni.GIMacsFound);
 		return -EAGAIN;
 	}
+
 	if (Ret) {
-		printk(KERN_WARNING "%s: Requested IRQ %d is busy\n",
+		printk(KERN_WARNING "%s: Requested IRQ %d is busy.\n",
 		       dev->name, dev->irq);
 		return -EAGAIN;
 	}
@@ -931,7 +1064,7 @@
 
 	/* Alloc memory for this board (Mem for RxD/TxD) : */
 	if(!BoardAllocMem(pAC)) {
-		printk("No memory for descriptor rings\n");
+		printk("No memory for descriptor rings.\n");
        		return(-EAGAIN);
 	}
 
@@ -941,8 +1074,24 @@
 	pAC->CsOfs = (pAC->CsOfs2 << 16) | pAC->CsOfs1;
 
 	BoardInitMem(pAC);
-
+#if 0
 	SetQueueSizes(pAC);
+#else
+	/* tschilling: New common function with minimum size check. */
+	DualNet = SK_FALSE;
+	if (pAC->RlmtNets == 2) {
+		DualNet = SK_TRUE;
+	}
+	
+	if (SkGeInitAssignRamToQueues(
+		pAC,
+		pAC->ActivePort,
+		DualNet)) {
+		BoardFreeMem(pAC);
+		printk("SkGeInitAssignRamToQueues failed.\n");
+		return(-EAGAIN);
+	}
+#endif
 
 	/* Print adapter specific string from vpd */
 	ProductStr(pAC);
@@ -957,14 +1106,13 @@
 		((pAC->RlmtMode==7) ? "Check Segmentation" : 
 		((pAC->RlmtMode==17) ? "Dual Check Link State" :"Error")))));
 
-
 	SkGeYellowLED(pAC, pAC->IoBase, 1);
 
 	/*
 	 * Register the device here
 	 */
-	pAC->Next = sk98lin_root_dev;
-	sk98lin_root_dev = dev;
+	pAC->Next = SkGeRootDev;
+	SkGeRootDev = dev;
 
 	return (0);
 } /* SkGeBoardInit */
@@ -1001,17 +1149,19 @@
 	AllocLength = (RX_RING_SIZE + TX_RING_SIZE) * pAC->GIni.GIMacsFound
 		+ RX_RING_SIZE + 8;
 #endif
-	pDescrMem = pci_alloc_consistent(&pAC->PciDev, AllocLength,
+
+	pDescrMem = pci_alloc_consistent(pAC->PciDev, AllocLength,
 					 &pAC->pDescrMemDMA);
+
 	if (pDescrMem == NULL) {
 		return (SK_FALSE);
 	}
 	pAC->pDescrMem = pDescrMem;
+	BusAddr = (unsigned long) pAC->pDescrMemDMA;
 
 	/* Descriptors need 8 byte alignment, and this is ensured
 	 * by pci_alloc_consistent.
 	 */
-	BusAddr = (unsigned long) pAC->pDescrMemDMA;
 	for (i=0; i<pAC->GIni.GIMacsFound; i++) {
 		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS,
 			("TX%d/A: pDescrMem: %lX,   PhysDescrMem: %lX\n",
@@ -1059,7 +1209,8 @@
 	AllocLength = (RX_RING_SIZE + TX_RING_SIZE) * pAC->GIni.GIMacsFound
 		+ RX_RING_SIZE + 8;
 #endif
-	pci_free_consistent(&pAC->PciDev, AllocLength,
+
+	pci_free_consistent(pAC->PciDev, AllocLength,
 			    pAC->pDescrMem, pAC->pDescrMemDMA);
 	pAC->pDescrMem = NULL;
 } /* BoardFreeMem */
@@ -1146,8 +1297,7 @@
 		DescrSize = (((sizeof(TXD) - 1) / DESCR_ALIGN) + 1) *
 			DESCR_ALIGN;
 		DescrNum = TX_RING_SIZE / DescrSize;
-	}
-	else {
+	} else {
 		DescrSize = (((sizeof(RXD) - 1) / DESCR_ALIGN) + 1) *
 			DESCR_ALIGN;
 		DescrNum = RX_RING_SIZE / DescrSize;
@@ -1156,7 +1306,7 @@
 	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS,
 		("Descriptor size: %d   Descriptor Number: %d\n",
 		DescrSize,DescrNum));
-	
+
 	pDescr = (RXD*) pMemArea;
 	pPrevDescr = NULL;
 	pNextDescr = (RXD*) (((char*)pDescr) + DescrSize);
@@ -1166,7 +1316,8 @@
 		pDescr->VNextRxd = VNextDescr & 0xffffffffULL;
 		pDescr->pNextRxd = pNextDescr;
 		pDescr->TcpSumStarts = pAC->CsOfs;
-		/* advance on step */
+
+		/* advance one step */
 		pPrevDescr = pDescr;
 		pDescr = pNextDescr;
 		pNextDescr = (RXD*) (((char*)pDescr) + DescrSize);
@@ -1240,8 +1391,7 @@
  */
 static void SkGeIsr(int irq, void *dev_id, struct pt_regs *ptregs)
 {
-struct net_device *dev = (struct net_device *)dev_id;
-
+struct SK_NET_DEVICE *dev = (struct SK_NET_DEVICE *)dev_id;
 DEV_NET		*pNet;
 SK_AC		*pAC;
 SK_U32		IntSrc;		/* interrupts source register contents */	
@@ -1269,22 +1419,22 @@
 			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
 				SK_DBGCAT_DRV_INT_SRC,
 				("EOF RX1 IRQ\n"));
-			ReceiveIrq(pAC, &pAC->RxPort[0]);
-			SK_PNMI_CNT_RX_INTR(pAC,0);
+			ReceiveIrq(pAC, &pAC->RxPort[0], SK_TRUE);
+			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,1);
+			ReceiveIrq(pAC, &pAC->RxPort[1], SK_TRUE);
+			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,0);
+			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);
@@ -1293,7 +1443,7 @@
 			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
 				SK_DBGCAT_DRV_INT_SRC,
 				("EOF AS TX2 IRQ\n"));
-			SK_PNMI_CNT_TX_INTR(pAC,1);
+			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);
@@ -1303,7 +1453,7 @@
 			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
 				SK_DBGCAT_DRV_INT_SRC,
 				("EOF SY TX1 IRQ\n"));
-			SK_PNMI_CNT_TX_INTR(pAC,0);
+			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);
@@ -1313,14 +1463,14 @@
 			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
 				SK_DBGCAT_DRV_INT_SRC,
 				("EOF SY TX2 IRQ\n"));
-			SK_PNMI_CNT_TX_INTR(pAC,1);
+			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);
 			ClearTxIrq(pAC, 1, TX_PRIO_HIGH);
 		}
-#endif /* 0 */
-#endif /* USE_TX_COMPLETE */
+#endif
+#endif
 
 		/* do all IO at once */
 		if (IntSrc & IRQ_EOF_RX1)
@@ -1338,11 +1488,12 @@
 
 	if ((IntSrc & SPECIAL_IRQS) || pAC->CheckQueue) {
 		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_INT_SRC,
-			("SPECIAL IRQ\n"));
+			("SPECIAL IRQ DP-Cards => %x\n", IntSrc));
 		pAC->CheckQueue = SK_FALSE;
 		spin_lock(&pAC->SlowPathLock);
 		if (IntSrc & SPECIAL_IRQS)
 			SkGeSirqIsr(pAC, pAC->IoBase, IntSrc);
+
 		SkEventDispatcher(pAC, pAC->IoBase);
 		spin_unlock(&pAC->SlowPathLock);
 	}
@@ -1351,33 +1502,17 @@
 	 * 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[0]);
-	ReceiveIrq(pAC, &pAC->RxPort[1]);
-	
 
+	ReceiveIrq(pAC, &pAC->RxPort[0], SK_TRUE);
+	ReceiveIrq(pAC, &pAC->RxPort[1], SK_TRUE);
 
+	if (pAC->CheckQueue) {
+		pAC->CheckQueue = SK_FALSE;
+		spin_lock(&pAC->SlowPathLock);
+		SkEventDispatcher(pAC, pAC->IoBase);
+		spin_unlock(&pAC->SlowPathLock);
+	}
 
-#if 0
-// #ifdef USE_TX_COMPLETE /* only if tx complete interrupt used */
-	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);
-
-	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);
-
-#if 0	/* only if sync. queues used */
-	spin_lock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock);
-	FreeTxDescriptors(pAC, 0, TX_PRIO_HIGH);
-	spin_unlock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock);
-	
-	spin_lock(&pAC->TxPort[1][TX_PRIO_HIGH].TxDesRingLock);
-	FreeTxDescriptors(pAC, 1, TX_PRIO_HIGH);
-	spin_unlock(&pAC->TxPort[1][TX_PRIO_HIGH].TxDesRingLock);
-#endif /* 0 */
-#endif /* USE_TX_COMPLETE */
 
 	/* IRQ is processed - Enable IRQs again*/
 	SK_OUT32(pAC->IoBase, B0_IMSK, IRQ_MASK);
@@ -1401,7 +1536,7 @@
  */
 static void SkGeIsrOnePort(int irq, void *dev_id, struct pt_regs *ptregs)
 {
-struct net_device *dev = (struct net_device *)dev_id;
+struct SK_NET_DEVICE *dev = (struct SK_NET_DEVICE *)dev_id;
 DEV_NET		*pNet;
 SK_AC		*pAC;
 SK_U32		IntSrc;		/* interrupts source register contents */	
@@ -1416,7 +1551,7 @@
 	if (IntSrc == 0) {
 		return;
 	}
-
+	
 	while (((IntSrc & IRQ_MASK) & ~SPECIAL_IRQS) != 0) {
 #if 0 /* software irq currently not used */
 		if (IntSrc & IRQ_SW) {
@@ -1429,15 +1564,15 @@
 			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
 				SK_DBGCAT_DRV_INT_SRC,
 				("EOF RX1 IRQ\n"));
-			ReceiveIrq(pAC, &pAC->RxPort[0]);
-			SK_PNMI_CNT_RX_INTR(pAC,0);
+			ReceiveIrq(pAC, &pAC->RxPort[0], SK_TRUE);
+			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,0);
+			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);
@@ -1447,14 +1582,14 @@
 			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
 				SK_DBGCAT_DRV_INT_SRC,
 				("EOF SY TX1 IRQ\n"));
-			SK_PNMI_CNT_TX_INTR(pAC,1);
+			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);
 			ClearTxIrq(pAC, 0, TX_PRIO_HIGH);
 		}
-#endif /* 0 */
-#endif /* USE_TX_COMPLETE */
+#endif
+#endif
 
 		/* do all IO at once */
 		if (IntSrc & IRQ_EOF_RX1)
@@ -1468,11 +1603,12 @@
 	
 	if ((IntSrc & SPECIAL_IRQS) || pAC->CheckQueue) {
 		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_INT_SRC,
-			("SPECIAL IRQ\n"));
+			("SPECIAL IRQ SP-Cards => %x\n", IntSrc));
 		pAC->CheckQueue = SK_FALSE;
 		spin_lock(&pAC->SlowPathLock);
 		if (IntSrc & SPECIAL_IRQS)
 			SkGeSirqIsr(pAC, pAC->IoBase, IntSrc);
+
 		SkEventDispatcher(pAC, pAC->IoBase);
 		spin_unlock(&pAC->SlowPathLock);
 	}
@@ -1481,21 +1617,7 @@
 	 * came in after handling the ring (OUTs may be delayed
 	 * in hardware buffers, but are through after IN)
 	 */
-	ReceiveIrq(pAC, &pAC->RxPort[0]);
-
-#if 0
-// #ifdef USE_TX_COMPLETE /* only if tx complete interrupt used */
-	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);
-
-#if 0	/* only if sync. queues used */
-	spin_lock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock);
-	FreeTxDescriptors(pAC, 0, TX_PRIO_HIGH);
-	spin_unlock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock);
-	
-#endif /* 0 */
-#endif /* USE_TX_COMPLETE */
+	ReceiveIrq(pAC, &pAC->RxPort[0], SK_TRUE);
 
 	/* IRQ is processed - Enable IRQs again*/
 	SK_OUT32(pAC->IoBase, B0_IMSK, IRQ_MASK);
@@ -1521,13 +1643,13 @@
  *	!= 0 on error
  */
 static int SkGeOpen(
-struct net_device	*dev)
+struct SK_NET_DEVICE	*dev)
 {
-DEV_NET			*pNet;
-SK_AC			*pAC;
-unsigned long	Flags;		/* for spin lock */
-int		i;
-SK_EVPARA		EvPara;		/* an event parameter union */
+	DEV_NET			*pNet;
+	SK_AC			*pAC;
+	unsigned long	Flags;		/* for spin lock */
+	int				i;
+	SK_EVPARA		EvPara;		/* an event parameter union */
 
 	pNet = (DEV_NET*) dev->priv;
 	pAC = pNet->pAC;
@@ -1538,7 +1660,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[pNet->PortNr]->name);
+			printk("%s: HWInit (1) failed.\n", pAC->dev[pNet->PortNr]->name);
 			return (-1);
 		}
 		SkI2cInit	(pAC, pAC->IoBase, 1);
@@ -1551,8 +1673,11 @@
 	}
 
 	if (pAC->BoardLevel != 2) {
-		/* level 2 init modules here */
-		SkGeInit	(pAC, pAC->IoBase, 2);
+		/* tschilling: Level 2 init modules here, check return value. */
+		if (SkGeInit(pAC, pAC->IoBase, 2) != 0) {
+			printk("%s: HWInit (2) failed.\n", pAC->dev[pNet->PortNr]->name);
+			return (-1);
+		}
 		SkI2cInit	(pAC, pAC->IoBase, 2);
 		SkEventInit	(pAC, pAC->IoBase, 2);
 		SkPnmiInit	(pAC, pAC->IoBase, 2);
@@ -1561,6 +1686,7 @@
 		SkTimerInit	(pAC, pAC->IoBase, 2);
 		pAC->BoardLevel = 2;
 	}
+
 	for (i=0; i<pAC->GIni.GIMacsFound; i++) {
 		/* Enable transmit descriptor polling. */
 		SkGePollTxD(pAC, pAC->IoBase, i, SK_TRUE);
@@ -1627,18 +1753,17 @@
  *	error code - on error
  */
 static int SkGeClose(
-struct net_device	*dev)
+struct SK_NET_DEVICE	*dev)
 {
-DEV_NET		*pNet;
-SK_AC		*pAC;
+	DEV_NET			*pNet;
+	SK_AC			*pAC;
 
-unsigned long	Flags;		/* for spin lock */
-int				i;
-int				PortIdx;
-SK_EVPARA		EvPara;
+	unsigned long	Flags;		/* for spin lock */
+	int				i;
+	int				PortIdx;
+	SK_EVPARA		EvPara;
 
 	netif_stop_queue(dev);
-
 	pNet = (DEV_NET*) dev->priv;
 	pAC = pNet->pAC;
 
@@ -1653,7 +1778,6 @@
 	/* 
 	 * Clear multicast table, promiscuous mode ....
 	 */
-	 
 	SkAddrMcClear(pAC, pAC->IoBase, PortIdx, 0);
 	SkAddrPromiscuousChange(pAC, pAC->IoBase, PortIdx,
 		SK_PROM_MODE_NONE);
@@ -1688,16 +1812,17 @@
 		spin_unlock_irqrestore(&pAC->TxPort[pNet->PortNr]
 			[TX_PRIO_LOW].TxDesRingLock, Flags);
 	}
+
 	if (pAC->RlmtNets == 1) {
 		/* clear all descriptor rings */
 		for (i=0; i<pAC->GIni.GIMacsFound; i++) {
-			ReceiveIrq(pAC, &pAC->RxPort[i]);
+			ReceiveIrq(pAC, &pAC->RxPort[i], SK_TRUE);
 			ClearRxRing(pAC, &pAC->RxPort[i]);
 			ClearTxRing(pAC, &pAC->TxPort[i][TX_PRIO_LOW]);
 		}
 	} else {
 		/* clear port descriptor rings */
-		ReceiveIrq(pAC, &pAC->RxPort[pNet->PortNr]);
+		ReceiveIrq(pAC, &pAC->RxPort[pNet->PortNr], SK_TRUE);
 		ClearRxRing(pAC, &pAC->RxPort[pNet->PortNr]);
 		ClearTxRing(pAC, &pAC->TxPort[pNet->PortNr][TX_PRIO_LOW]);
 	}
@@ -1712,6 +1837,7 @@
 	return (0);
 } /* SkGeClose */
 
+
 /*****************************************************************************
  *
  * 	SkGeXmit - Linux frame transmit function
@@ -1727,23 +1853,47 @@
  * WARNING: returning 1 in 'tbusy' case caused system crashes (double
  *	allocated skb's) !!!
  */
-static int SkGeXmit(struct sk_buff *skb, struct net_device *dev)
+static int SkGeXmit(struct sk_buff *skb, struct SK_NET_DEVICE *dev)
 {
 DEV_NET		*pNet;
 SK_AC		*pAC;
 int			Rc;	/* return code of XmitFrame */
-	
+
 	pNet = (DEV_NET*) dev->priv;
 	pAC = pNet->pAC;
 
-	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);
+	if ((!skb_shinfo(skb)->nr_frags) || 
+		(pAC->GIni.GIChipId == CHIP_ID_GENESIS)) {
+		/* Don't activate scatter-gather and hardware checksum */
+
+		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);
+	} else {
+		/* scatter-gather and hardware TCP checksumming anabled*/
+		if (pAC->RlmtNets == 2)
+			Rc = XmitFrameSG(
+				pAC,
+				&pAC->TxPort[pNet->PortNr][TX_PRIO_LOW],
+				skb);
+		else
+			Rc = XmitFrameSG(
+				pAC,
+				&pAC->TxPort[pAC->ActivePort][TX_PRIO_LOW],
+				skb);
+	}
 
 	/* Transmitter out of resources? */
-	if (Rc <= 0)
+	if (Rc <= 0) {
 		netif_stop_queue(dev);
+	}
 
 	/* If not taken, give buffer ownership back to the
 	 * queueing layer.
@@ -1773,10 +1923,10 @@
  *	if necessary.
  *
  * Returns:
- *  > 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 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)
  */
 static int XmitFrame(
 SK_AC 		*pAC,		/* pointer to adapter context */
@@ -1792,7 +1942,9 @@
 		("X"));
 
 	spin_lock_irqsave(&pTxPort->TxDesRingLock, Flags);
-
+#ifndef USE_TX_COMPLETE
+	FreeTxDescriptors(pAC, pTxPort);
+#endif
 	if (pTxPort->TxdRingFree == 0) {
 		/* no enough free descriptors in ring at the moment */
 		FreeTxDescriptors(pAC, pTxPort);
@@ -1803,6 +1955,8 @@
 				SK_DBGCAT_DRV_TX_PROGRESS,
 				("XmitFrame failed\n"));
 			/* this message can not be sent now */
+			/* Because tbusy seems to be set, the message should not be freed here */
+			/* It will be used by the scheduler of the ethernet handler */
 			return (-1);
 		}
 	}
@@ -1821,12 +1975,12 @@
 #endif
 
 	/* set up descriptor and CONTROL dword */
-	PhysAddr = (SK_U64) pci_map_page(&pAC->PciDev,
-					 virt_to_page(pMessage->data),
-					 ((unsigned long) pMessage->data &
-					  ~PAGE_MASK),
-					 pMessage->len,
-					 PCI_DMA_TODEVICE);
+	PhysAddr = (SK_U64) pci_map_page(pAC->PciDev,
+		virt_to_page(pMessage->data),
+		((unsigned long) pMessage->data &
+		~PAGE_MASK),
+		pMessage->len,
+		PCI_DMA_TODEVICE);
 	pTxd->VDataLow = (SK_U32)  (PhysAddr & 0xffffffff);
 	pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32);
 	pTxd->pMBuf = pMessage;
@@ -1847,18 +2001,200 @@
 	
 	
 	BytesSend = pMessage->len;
+	spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags);
 	/* after releasing the lock, the skb may be immidiately freed */
-	if (pTxPort->TxdRingFree != 0) {
-		spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags);
+	if (pTxPort->TxdRingFree != 0)
 		return (BytesSend);
-	}
-	else {
-		/* ring full: set tbusy on return */
-		spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags);
+	else
 		return (0);
-	}
+
 } /* XmitFrame */
 
+/*****************************************************************************
+ *
+ * 	XmitFrameSG - fill one socket buffer into the transmit ring
+ *                (use SG and TCP/UDP hardware checksumming)
+ *
+ * Description:
+ *	This function puts a message into the transmit descriptor ring
+ *	if there is a descriptors left.
+ *
+ * Returns:
+ *	> 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)
+ */
+static int XmitFrameSG(
+SK_AC 		*pAC,			/* pointer to adapter context */
+TX_PORT		*pTxPort,		/* pointer to struct of port to send to */
+struct sk_buff	*pMessage)	/* pointer to send-message */
+{
+
+	int 		i;
+	int			BytesSend;
+	int			hlength;
+	int			protocol;
+	skb_frag_t		*sk_frag;
+	TXD			*pTxd;
+	TXD			*pTxdFst;
+	TXD			*pTxdLst;
+	SK_U64		PhysAddr;
+	unsigned long	Flags;
+
+	spin_lock_irqsave(&pTxPort->TxDesRingLock, Flags);
+#ifndef USE_TX_COMPLETE
+	FreeTxDescriptors(pAC, pTxPort);
+#endif
+	if ((skb_shinfo(pMessage)->nr_frags +1) > pTxPort->TxdRingFree) {
+		FreeTxDescriptors(pAC, pTxPort);
+		if ((skb_shinfo(pMessage)->nr_frags + 1) > pTxPort->TxdRingFree) {
+			spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags);
+			SK_PNMI_CNT_NO_TX_BUF(pAC, pTxPort->PortIndex);
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_TX_PROGRESS,
+				("XmitFrameSG failed - Ring full\n"));
+				/* this message can not be sent now */
+			return(-1);
+		}
+	}
+
+
+	pTxd = pTxPort->pTxdRingHead;
+	pTxdFst = pTxd;
+	pTxdLst = pTxd;
+	BytesSend = 0;
+	protocol = 0;
+
+	/* map first fragment (header) */
+	PhysAddr = (SK_U64) pci_map_page(pAC->PciDev,
+			virt_to_page(pMessage->data),
+			((unsigned long) pMessage->data & ~PAGE_MASK),
+			skb_headlen(pMessage),
+			PCI_DMA_TODEVICE);
+
+	pTxd->VDataLow = (SK_U32)  (PhysAddr & 0xffffffff);
+	pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32);
+
+	/* HW checksum? */
+	if (pMessage->ip_summed == CHECKSUM_HW) {
+		pTxd->TBControl = TX_CTRL_STF |
+				  TX_CTRL_ST_FWD |
+				  skb_headlen(pMessage);
+
+		/* We have to use the opcode for tcp here because the opcode for
+		udp is not working in the hardware yet (revision 2.0)*/
+		protocol = ((SK_U8)pMessage->data[23] & 0xf);
+		if ((protocol == 17) && (pAC->GIni.GIChipRev != 0))
+			pTxd->TBControl |=  BMU_UDP_CHECK;
+		else
+			pTxd->TBControl |= BMU_TCP_CHECK ;
+
+		hlength = ((SK_U8)pMessage->data[14] & 0xf) * 4;
+		pTxd->TcpSumOfs = 0; /* PH-Checksum already claculated */
+		pTxd->TcpSumSt = 14+hlength+16;
+		pTxd->TcpSumWr = 14+hlength;
+	
+	} else {
+		pTxd->TBControl = TX_CTRL_CHECK_DEFAULT | 
+				  TX_CTRL_SOFTWARE |
+				  TX_CTRL_STF |
+				  skb_headlen(pMessage);
+	}
+
+	pTxd = pTxd->pNextTxd;
+	pTxPort->TxdRingFree--;
+	BytesSend += skb_headlen(pMessage);
+
+
+	/* Map SG fragments */
+	for (i = 0; i < skb_shinfo(pMessage)->nr_frags; i++) {
+		sk_frag = &skb_shinfo(pMessage)->frags[i];
+		
+		/* we already have the proper value in entry */
+		PhysAddr = (SK_U64) pci_map_page(pAC->PciDev,
+						 sk_frag->page,
+						 sk_frag->page_offset,
+						 sk_frag->size,
+						 PCI_DMA_TODEVICE);
+
+		pTxd->VDataLow = (SK_U32)  (PhysAddr & 0xffffffff);
+		pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32);
+		pTxd->pMBuf = pMessage;
+		
+		/* HW checksum */
+		if (pMessage->ip_summed == CHECKSUM_HW) {
+			pTxd->TBControl = TX_CTRL_OWN_BMU | 
+				  	  TX_CTRL_SOFTWARE |
+					  TX_CTRL_ST_FWD;
+
+			/* We have to use the opcode for tcp here because the opcode for
+			udp is not working in the hardware yet (revision 2.0)*/
+			if ((protocol == 17) && (pAC->GIni.GIChipRev != 0))
+				pTxd->TBControl |= BMU_UDP_CHECK ;
+			else
+				pTxd->TBControl |= BMU_TCP_CHECK ;
+
+		} else {
+			pTxd->TBControl = TX_CTRL_CHECK_DEFAULT |
+					  TX_CTRL_SOFTWARE |
+					  TX_CTRL_OWN_BMU;
+		}
+
+		/* Last fragment  */
+		if( (i+1) == skb_shinfo(pMessage)->nr_frags )  {
+#ifdef USE_TX_COMPLETE
+			pTxd->TBControl |= TX_CTRL_EOF |
+					   TX_CTRL_EOF_IRQ |
+					   sk_frag->size;
+#else
+			pTxd->TBControl |= TX_CTRL_EOF |
+					   sk_frag->size;
+#endif
+			pTxdFst->TBControl |= TX_CTRL_OWN_BMU |
+					      TX_CTRL_SOFTWARE; 
+
+		} else {
+			pTxd->TBControl |= sk_frag->size;
+		}
+		pTxdLst = pTxd;
+		pTxd = pTxd->pNextTxd;
+		pTxPort->TxdRingFree--;
+		BytesSend += sk_frag->size;
+	}
+
+	if ((pTxPort->pTxdRingPrev->TBControl & TX_CTRL_OWN_BMU) == 0) {
+		/* previous descriptor already done, so give tx start cmd */
+		/* StartTx(pAC, pTxPort->HwAddr); */
+		SK_OUT8(pTxPort->HwAddr, TX_Q_CTRL, TX_Q_CTRL_START);
+	}
+
+	pTxPort->pTxdRingPrev = pTxdLst;
+	pTxPort->pTxdRingHead = pTxd;
+
+	spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags);
+
+	if (pTxPort->TxdRingFree > 0)
+		return (BytesSend);
+	else
+		return (0);
+}
+
+
+void dump_frag( SK_U8 *data, int length)
+{
+        int i;
+
+        printk("Length: %d\n", length);                
+        for( i=0; i < length; i++ ) {
+                printk(" %02x", (SK_U8)*(data + i) );
+                if( !((i+1) % 20) )
+                  printk("\n");
+        }
+        printk("\n\n");
+
+}
+
 
 /*****************************************************************************
  *
@@ -1889,7 +2225,6 @@
 
 	pNewTail = pTxPort->pTxdRingTail;
 	pTxd = pNewTail;
-	
 	/* 
 	 * loop forever; exits if TX_CTRL_SOFTWARE bit not set in start frame
 	 * or TX_CTRL_OWN_BMU bit set in any frame
@@ -1918,19 +2253,19 @@
 		/* release the DMA mapping */
 		PhysAddr = ((SK_U64) pTxd->VDataHigh) << (SK_U64) 32;
 		PhysAddr |= (SK_U64) pTxd->VDataLow;
-		pci_unmap_page(&pAC->PciDev, PhysAddr,
-			       pTxd->pMBuf->len,
-			       PCI_DMA_TODEVICE);
+		pci_unmap_page(pAC->PciDev, PhysAddr,
+				 pTxd->pMBuf->len,
+				 PCI_DMA_TODEVICE);
+
+		if (Control & TX_CTRL_EOF)
+			DEV_KFREE_SKB_ANY(pTxd->pMBuf);	/* free message */
 
-		/* free message */
-		DEV_KFREE_SKB_ANY(pTxd->pMBuf);
 		pTxPort->TxdRingFree++;
 		pTxd->TBControl &= ~TX_CTRL_SOFTWARE;
 		pTxd = pTxd->pNextTxd; /* point behind fragment with EOF */
 	} /* while(forever) */
 } /* FreeTxDescriptors */
 
-
 /*****************************************************************************
  *
  * 	FillRxRing - fill the receive ring with valid descriptors
@@ -1999,12 +2334,12 @@
 	pRxPort->pRxdRingTail = pRxd->pNextRxd;
 	pRxPort->RxdRingFree--;
 	Length = pAC->RxBufSize;
-	PhysAddr = (SK_U64) pci_map_page(&pAC->PciDev,
-					 virt_to_page(pMsgBlock->data),
-					 ((unsigned long) pMsgBlock->data &
-					  ~PAGE_MASK),
-					 pAC->RxBufSize - 2,
-					 PCI_DMA_FROMDEVICE);
+	PhysAddr = (SK_U64) pci_map_page(pAC->PciDev,
+		virt_to_page(pMsgBlock->data),
+		((unsigned long) pMsgBlock->data &
+		~PAGE_MASK),
+		pAC->RxBufSize - 2,
+		PCI_DMA_FROMDEVICE);
 	pRxd->VDataLow = (SK_U32) (PhysAddr & 0xffffffff);
 	pRxd->VDataHigh = (SK_U32) (PhysAddr >> 32);
 	pRxd->pMBuf = pMsgBlock;
@@ -2061,28 +2396,32 @@
  * Returns:	N/A
  */
 static void ReceiveIrq(
-SK_AC		*pAC,		/* pointer to adapter context */
-RX_PORT		*pRxPort)	/* pointer to receive port struct */
-{
-RXD		*pRxd;		/* pointer to receive descriptors */
-SK_U32		Control;	/* control field of descriptor */
-struct sk_buff	*pMsg;		/* pointer to message holding frame */
-struct sk_buff	*pNewMsg;	/* pointer to a new message for copying frame */
-int		FrameLength;	/* total length of received frame */
-SK_MBUF		*pRlmtMbuf;	/* ptr to a buffer for giving a frame to rlmt */
-SK_EVPARA	EvPara;		/* an event parameter union */	
-int		PortIndex = pRxPort->PortIndex;
+	SK_AC		*pAC,			/* pointer to adapter context */
+	RX_PORT		*pRxPort,		/* pointer to receive port struct */
+	SK_BOOL		SlowPathLock)	/* indicates if SlowPathLock is needed */
+{
+RXD				*pRxd;			/* pointer to receive descriptors */
+SK_U32			Control;		/* control field of descriptor */
+struct sk_buff	*pMsg;			/* pointer to message holding frame */
+struct sk_buff	*pNewMsg;		/* pointer to a new message for copying frame */
+int				FrameLength;	/* total length of received frame */
+SK_MBUF			*pRlmtMbuf;		/* ptr to a buffer for giving a frame to rlmt */
+SK_EVPARA		EvPara;			/* an event parameter union */	
+unsigned long	Flags;			/* for spin lock */
+int				PortIndex = pRxPort->PortIndex;
 unsigned int	Offset;
 unsigned int	NumBytes;
 unsigned int	ForRlmt;
-SK_BOOL		IsBc;
-SK_BOOL		IsMc;
-SK_U32		FrameStat;
+SK_BOOL			IsBc;
+SK_BOOL			IsMc;
+SK_BOOL  IsBadFrame; 			/* Bad frame */
+
+SK_U32			FrameStat;
 unsigned short	Csum1;
 unsigned short	Csum2;
 unsigned short	Type;
-int		Result;
-SK_U64		PhysAddr;
+int				Result;
+SK_U64			PhysAddr;
 
 rx_start:	
 	/* do forever; exit if RX_CTRL_OWN_BMU found */
@@ -2124,33 +2463,75 @@
 			(RX_CTRL_STF | RX_CTRL_EOF)) {
 			goto rx_failed;
 		}
-		
+
 		/* here we have a complete frame in the ring */
 		pMsg = pRxd->pMBuf;
 
 		FrameStat = pRxd->FrameStat;
+
+		/* check for frame length mismatch */
+#define XMR_FS_LEN_SHIFT        18
+#define GMR_FS_LEN_SHIFT        16
+		if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+			if (FrameLength != (SK_U32) (FrameStat >> XMR_FS_LEN_SHIFT)) {
+				SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+					SK_DBGCAT_DRV_RX_PROGRESS,
+					("skge: Frame length mismatch (%u/%u).\n",
+					FrameLength,
+					(SK_U32) (FrameStat >> XMR_FS_LEN_SHIFT)));
+				goto rx_failed;
+			}
+		}
+		else {
+			if (FrameLength != (SK_U32) (FrameStat >> GMR_FS_LEN_SHIFT)) {
+				SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+					SK_DBGCAT_DRV_RX_PROGRESS,
+					("skge: Frame length mismatch (%u/%u).\n",
+					FrameLength,
+					(SK_U32) (FrameStat >> XMR_FS_LEN_SHIFT)));
+				goto rx_failed;
+			}
+		}
+
+		/* Set Rx Status */
+		if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+			IsBc = (FrameStat & XMR_FS_BC) != 0;
+			IsMc = (FrameStat & XMR_FS_MC) != 0;
+			IsBadFrame = (FrameStat & 
+				(XMR_FS_ANY_ERR | XMR_FS_2L_VLAN)) != 0;
+		} else {
+			IsBc = (FrameStat & GMR_FS_BC) != 0;
+			IsMc = (FrameStat & GMR_FS_MC) != 0;
+			IsBadFrame = (((FrameStat & GMR_FS_ANY_ERR) != 0) ||
+							((FrameStat & GMR_FS_RX_OK) == 0));
+		}
+
 		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");	*/	
-		
+/* DumpMsg(pMsg, "Rx");	*/
+
 		if ((Control & RX_CTRL_STAT_VALID) != RX_CTRL_STAT_VALID ||
+			(IsBadFrame)) {
+#if 0
 			(FrameStat & (XMR_FS_ANY_ERR | XMR_FS_2L_VLAN)) != 0) {
+#endif
 			/* 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);
+			pci_dma_sync_single(pAC->PciDev,
+						(dma_addr_t) PhysAddr,
+						FrameLength,
+						PCI_DMA_FROMDEVICE);
 			ReQueueRxBuffer(pAC, pRxPort, pMsg,
 				pRxd->VDataHigh, pRxd->VDataLow);
 
@@ -2165,16 +2546,16 @@
 			/*
 			 * 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);
+			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);
 			eth_copy_and_sum(pNewMsg, pMsg->data,
 				FrameLength, 0);
 			ReQueueRxBuffer(pAC, pRxPort, pMsg,
@@ -2192,10 +2573,10 @@
 			PhysAddr |= (SK_U64) pRxd->VDataLow;
 
 			/* release the DMA mapping */
-			pci_unmap_page(&pAC->PciDev,
-				       PhysAddr,
-				       pAC->RxBufSize - 2,
-				       PCI_DMA_FROMDEVICE);
+			pci_unmap_single(pAC->PciDev,
+					 PhysAddr,
+					 pAC->RxBufSize - 2,
+					 PCI_DMA_FROMDEVICE);
 
 			/* set length in message */
 			skb_put(pMsg, FrameLength);
@@ -2204,11 +2585,13 @@
 			if (Type == 0x800) {
 				Csum1=le16_to_cpu(pRxd->TcpSums & 0xffff);
 				Csum2=le16_to_cpu((pRxd->TcpSums >> 16) & 0xffff);
-				if ((Csum1 & 0xfffe) && (Csum2 & 0xfffe)) {
+				if ((((Csum1 & 0xfffe) && (Csum2 & 0xfffe)) &&
+					(pAC->GIni.GIChipId == CHIP_ID_GENESIS)) ||
+					(pAC->GIni.GIChipId == CHIP_ID_YUKON)) {
 					Result = SkCsGetReceiveInfo(pAC,
 						&pMsg->data[14], 
 						Csum1, Csum2, pRxPort->PortIndex);
-					if (Result == 
+					if (Result ==
 						SKCS_STATUS_IP_FRAGMENT ||
 						Result ==
 						SKCS_STATUS_IP_CSUM_OK ||
@@ -2216,20 +2599,29 @@
 						SKCS_STATUS_TCP_CSUM_OK ||
 						Result ==
 						SKCS_STATUS_UDP_CSUM_OK) {
-						pMsg->ip_summed =
-						CHECKSUM_UNNECESSARY;
+							pMsg->ip_summed =
+							CHECKSUM_UNNECESSARY;
+					} else {
+						SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+						SK_DBGCAT_DRV_RX_PROGRESS,
+						("skge: CRC error. Frame dropped!\n"));
+						goto rx_failed;
 					}
-				} /* checksum calculation valid */
+				}/* checksumControl calculation valid */
 			} /* IP frame */
 		} /* frame > SK_COPY_TRESHOLD */
 		
 		SK_DBG_MSG(NULL, SK_DBGMOD_DRV,	1,("V"));
 		ForRlmt = SK_RLMT_RX_PROTOCOL;
+#if 0
 		IsBc = (FrameStat & XMR_FS_BC)==XMR_FS_BC;
+#endif
 		SK_RLMT_PRE_LOOKAHEAD(pAC, PortIndex, FrameLength,
 			IsBc, &Offset, &NumBytes);
 		if (NumBytes != 0) {
+#if 0
 			IsMc = (FrameStat & XMR_FS_MC)==XMR_FS_MC;
+#endif
 			SK_RLMT_LOOKAHEAD(pAC, PortIndex, 
 				&pMsg->data[Offset],
 				IsBc, IsMc, &ForRlmt);
@@ -2276,10 +2668,22 @@
 				memcpy((char*)(pRlmtMbuf->pData),
 					   (char*)(pMsg->data),
 					   FrameLength);
-				SkEventQueue(pAC, SKGE_RLMT,
-					SK_RLMT_PACKET_RECEIVED,
-					EvPara);
-				pAC->CheckQueue = SK_TRUE;
+
+				/* SlowPathLock needed? */
+				if (SlowPathLock == SK_TRUE) {
+					spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+					SkEventQueue(pAC, SKGE_RLMT,
+						SK_RLMT_PACKET_RECEIVED,
+						EvPara);
+					pAC->CheckQueue = SK_TRUE;
+					spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+				} else {
+					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"));
@@ -2315,12 +2719,13 @@
 		("Schrottdescriptor, length: 0x%x\n", FrameLength));
 
 	/* release the DMA mapping */
+
 	PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32;
 	PhysAddr |= (SK_U64) pRxd->VDataLow;
-	pci_unmap_page(&pAC->PciDev,
-		       PhysAddr,
-		       pAC->RxBufSize - 2,
-		       PCI_DMA_FROMDEVICE);
+	pci_unmap_page(pAC->PciDev,
+			 PhysAddr,
+			 pAC->RxBufSize - 2,
+			 PCI_DMA_FROMDEVICE);
 	DEV_KFREE_SKB_IRQ(pRxd->pMBuf);
 	pRxd->pMBuf = NULL;
 	pRxPort->RxdRingFree++;
@@ -2386,7 +2791,7 @@
 {
 RXD		*pRxd;	/* pointer to the current descriptor */
 unsigned long	Flags;
- SK_U64		PhysAddr;
+SK_U64		PhysAddr;
 
 	if (pRxPort->RxdRingFree == pAC->RxDescrPerRing) {
 		return;
@@ -2395,12 +2800,13 @@
 	pRxd = pRxPort->pRxdRingHead;
 	do {
 		if (pRxd->pMBuf != NULL) {
+
 			PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32;
 			PhysAddr |= (SK_U64) pRxd->VDataLow;
-			pci_unmap_page(&pAC->PciDev,
-				       PhysAddr,
-				       pAC->RxBufSize - 2,
-				       PCI_DMA_FROMDEVICE);
+			pci_unmap_page(pAC->PciDev,
+					 PhysAddr,
+					 pAC->RxBufSize - 2,
+					 PCI_DMA_FROMDEVICE);
 			DEV_KFREE_SKB(pRxd->pMBuf);
 			pRxd->pMBuf = NULL;
 		}
@@ -2549,7 +2955,7 @@
  *	0, if everything is ok
  *	!=0, on error
  */
-static int SkGeSetMacAddr(struct net_device *dev, void *p)
+static int SkGeSetMacAddr(struct SK_NET_DEVICE *dev, void *p)
 {
 
 DEV_NET *pNet = (DEV_NET*) dev->priv;
@@ -2557,12 +2963,12 @@
 
 struct sockaddr	*addr = p;
 unsigned long	Flags;
-
+	
 	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
 		("SkGeSetMacAddr starts now...\n"));
-	if(netif_running(dev)) {
+	if(netif_running(dev))
 		return -EBUSY;
-	}
+
 	memcpy(dev->dev_addr, addr->sa_data,dev->addr_len);
 	
 	spin_lock_irqsave(&pAC->SlowPathLock, Flags);
@@ -2595,7 +3001,7 @@
  *	0, if everything is ok
  *	!=0, on error
  */
-static void SkGeSetRxMode(struct net_device *dev)
+static void SkGeSetRxMode(struct SK_NET_DEVICE *dev)
 {
 
 DEV_NET		*pNet;
@@ -2649,7 +3055,6 @@
 				pMcList->dmi_addr[5]));
 		}
 		SkAddrMcUpdate(pAC, pAC->IoBase, PortIdx);
-	
 	}
 	spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
 	
@@ -2670,7 +3075,7 @@
  *	0, if everything is ok
  *	!=0, on error
  */
-static int SkGeChangeMtu(struct net_device *dev, int NewMtu)
+static int SkGeChangeMtu(struct SK_NET_DEVICE *dev, int NewMtu)
 {
 DEV_NET		*pNet;
 DEV_NET		*pOtherNet;
@@ -2689,6 +3094,10 @@
 		return -EINVAL;
 	}
 
+	if(pAC->BoardLevel != 2) {
+		return -EINVAL;
+	}
+
 	pNet->Mtu = NewMtu;
 	pOtherNet = (DEV_NET*)pAC->dev[1 - pNet->NetNr]->priv;
 	if ((pOtherNet->Mtu > 1500) && (NewMtu <= 1500) && (pOtherNet->Up==1)) {
@@ -2704,10 +3113,6 @@
 	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 */
@@ -2732,6 +3137,7 @@
 		spin_lock_irqsave(
 			&pAC->TxPort[i][TX_PRIO_LOW].TxDesRingLock, Flags);
 		netif_stop_queue(pAC->dev[i]);
+
 	}
 
 	/* 
@@ -2756,7 +3162,7 @@
 		}
 	}
 	else {
-		/* use normal anoumt of rx buffers */
+		/* use normal amount of rx buffers */
 		for (i=0; i<pAC->GIni.GIMacsFound; i++) {
 			/* Found more than one port */
 			if ((pAC->GIni.GIMacsFound == 2 ) && 
@@ -2780,10 +3186,6 @@
 	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 = 
-				XM_RX_STRIP_FCS | XM_RX_LENERR_OK;
-		}
 	}
 	else {
 		if ((pAC->GIni.GIMacsFound == 2 ) && 
@@ -2792,9 +3194,6 @@
 		} else {
 			pAC->GIni.GIPortUsage = SK_RED_LINK;
 		}
-		for (i=0; i<pAC->GIni.GIMacsFound; i++) {
-			pAC->GIni.GP[i].PRxCmd = XM_RX_STRIP_FCS;
-		}
 	}
 
 	SkGeInit(   pAC, pAC->IoBase, 1);
@@ -2805,6 +3204,12 @@
 	SkRlmtInit( pAC, pAC->IoBase, 1);
 	SkTimerInit(pAC, pAC->IoBase, 1);
 	
+	/*
+	 * tschilling:
+	 * Speed and others are set back to default in level 1 init!
+	 */
+	GetConfiguration(pAC);
+	
 	SkGeInit(   pAC, pAC->IoBase, 2);
 	SkI2cInit(  pAC, pAC->IoBase, 2);
 	SkEventInit(pAC, pAC->IoBase, 2);
@@ -2817,7 +3222,7 @@
 	 * clear and reinit the rx rings here
 	 */
 	for (i=0; i<pAC->GIni.GIMacsFound; i++) {
-		ReceiveIrq(pAC, &pAC->RxPort[i]);
+		ReceiveIrq(pAC, &pAC->RxPort[i], SK_TRUE);
 		ClearRxRing(pAC, &pAC->RxPort[i]);
 		FillRxRing(pAC, &pAC->RxPort[i]);
 
@@ -2891,12 +3296,13 @@
  * Returns:
  *	pointer to the statistic structure.
  */
-static struct net_device_stats *SkGeStats(struct net_device *dev)
+static struct net_device_stats *SkGeStats(struct SK_NET_DEVICE *dev)
 {
 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. */
+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 */
 unsigned long	Flags;			/* for spin lock */
 
@@ -2915,7 +3321,18 @@
 	pAC->stats.tx_packets = (SK_U32) pPnmiStat->StatTxOkCts & 0xFFFFFFFF;
 	pAC->stats.rx_bytes = (SK_U32) pPnmiStruct->RxOctetsDeliveredCts;
 	pAC->stats.tx_bytes = (SK_U32) pPnmiStat->StatTxOctetsOkCts;
-	pAC->stats.rx_errors = (SK_U32) pPnmiStruct->InErrorsCts & 0xFFFFFFFF;
+	
+        if (pNet->Mtu <= 1500) {
+                pAC->stats.rx_errors = (SK_U32) pPnmiStruct->InErrorsCts & 0xFFFFFFFF;
+        } else {
+                pAC->stats.rx_errors = (SK_U32) ((pPnmiStruct->InErrorsCts -
+                        pPnmiStat->StatRxTooLongCts) & 0xFFFFFFFF);
+	}
+
+
+	if (pAC->GIni.GP[0].PhyType == SK_PHY_XMAC && pAC->HWRevision < 12)
+		pAC->stats.rx_errors = pAC->stats.rx_errors - pPnmiStat->StatRxShortsCts;
+
 	pAC->stats.tx_errors = (SK_U32) pPnmiStat->StatTxSingleCollisionCts & 0xFFFFFFFF;
 	pAC->stats.rx_dropped = (SK_U32) pPnmiStruct->RxNoBufCts & 0xFFFFFFFF;
 	pAC->stats.tx_dropped = (SK_U32) pPnmiStruct->TxNoBufCts & 0xFFFFFFFF;
@@ -2954,7 +3371,7 @@
  *	0, if everything is ok
  *	!=0, on error
  */
-static int SkGeIoctl(struct net_device *dev, struct ifreq *rq, int cmd)
+static int SkGeIoctl(struct SK_NET_DEVICE *dev, struct ifreq *rq, int cmd)
 {
 DEV_NET		*pNet;
 SK_AC		*pAC;
@@ -3068,6 +3485,7 @@
 SK_AC	*pAC)	/* pointer to the adapter context structure */
 {
 SK_I32	Port;		/* preferred port */
+int	LinkSpeed;	/* Link speed */
 int	AutoNeg;	/* auto negotiation off (0) or on (1) */
 int	DuplexCap;	/* duplex capabilities (0=both, 1=full, 2=half */
 int	MSMode;		/* master / slave mode selection */
@@ -3097,7 +3515,44 @@
 #define AN_SENS	2
 
 	/* settings for port A */
-	AutoNeg = AN_SENS; /* default: do auto Sense */
+	/* settings link speed */
+	LinkSpeed = SK_LSPEED_AUTO; 	/* default: do auto select */
+	if (Speed_A != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+		Speed_A[pAC->Index] != NULL) {
+		if (strcmp(Speed_A[pAC->Index],"")==0) {
+			LinkSpeed = SK_LSPEED_AUTO;
+		}
+		else if (strcmp(Speed_A[pAC->Index],"Auto")==0) {
+			LinkSpeed = SK_LSPEED_AUTO;
+		}
+		else if (strcmp(Speed_A[pAC->Index],"10")==0) {
+			LinkSpeed = SK_LSPEED_10MBPS;
+		}
+		else if (strcmp(Speed_A[pAC->Index],"100")==0) {
+			LinkSpeed = SK_LSPEED_100MBPS;
+		}
+		else if (strcmp(Speed_A[pAC->Index],"1000")==0) {
+			LinkSpeed = SK_LSPEED_1000MBPS;
+		}
+		else printk("%s: Illegal value for Speed_A\n",
+			pAC->dev[0]->name);
+	}
+
+	/* Check speed parameter */
+	/* Only copper type adapter and GE V2 cards */
+	if (((pAC->GIni.GIChipId != CHIP_ID_YUKON) ||
+		(pAC->GIni.GICopperType != SK_TRUE)) &&
+		((LinkSpeed != SK_LSPEED_AUTO) && 
+		(LinkSpeed != SK_LSPEED_1000MBPS))) {
+		printk("%s: Illegal value for Speed_A. "
+			"Not a copper card or GE V2 card\n    Using "
+			"speed 1000\n", pAC->dev[0]->name);
+		LinkSpeed = SK_LSPEED_1000MBPS;
+	}
+	pAC->GIni.GP[0].PLinkSpeed = LinkSpeed;
+
+	/* Autonegotiation */
+	AutoNeg = AN_ON; /* tschilling: Default: Autonegotiation on! */
 	AutoSet = SK_FALSE;
 	if (AutoNeg_A != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
 		AutoNeg_A[pAC->Index] != NULL) {
@@ -3219,6 +3674,43 @@
 	
 	
 	/* settings for port B */
+	/* settings link speed */
+	LinkSpeed = SK_LSPEED_AUTO; 	/* default: do auto select */
+	if (Speed_B != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+		Speed_B[pAC->Index] != NULL) {
+		if (strcmp(Speed_B[pAC->Index],"")==0) {
+			LinkSpeed = SK_LSPEED_AUTO;
+		}
+		else if (strcmp(Speed_B[pAC->Index],"Auto")==0) {
+			LinkSpeed = SK_LSPEED_AUTO;
+		}
+		else if (strcmp(Speed_B[pAC->Index],"10")==0) {
+			LinkSpeed = SK_LSPEED_10MBPS;
+		}
+		else if (strcmp(Speed_B[pAC->Index],"100")==0) {
+			LinkSpeed = SK_LSPEED_100MBPS;
+		}
+		else if (strcmp(Speed_B[pAC->Index],"1000")==0) {
+			LinkSpeed = SK_LSPEED_1000MBPS;
+		}
+		else printk("%s: Illegal value for Speed_B\n",
+			pAC->dev[1]->name);
+	}
+
+	/* Check speed parameter */
+	/* Only copper type adapter and GE V2 cards */
+	if (((pAC->GIni.GIChipId != CHIP_ID_YUKON) ||
+		(pAC->GIni.GICopperType != SK_TRUE)) &&
+		((LinkSpeed != SK_LSPEED_AUTO) && 
+		(LinkSpeed != SK_LSPEED_1000MBPS))) {
+		printk("%s: Illegal value for Speed_B. "
+			"Not a copper card or GE V2 card\n    Using "
+			"speed 1000\n", pAC->dev[1]->name);
+		LinkSpeed = SK_LSPEED_1000MBPS;
+	}
+	pAC->GIni.GP[1].PLinkSpeed = LinkSpeed;
+
+	/* Auto negotiation */
 	AutoNeg = AN_SENS; /* default: do auto Sense */
 	AutoSet = SK_FALSE;
 	if (AutoNeg_B != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
@@ -3370,7 +3862,7 @@
 	}
 
 	pAC->RlmtNets = 1;
-	
+
 	if (RlmtMode != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
 		RlmtMode[pAC->Index] != NULL) {
 		if (strcmp(RlmtMode[pAC->Index], "") == 0) {
@@ -3396,10 +3888,6 @@
 		else {
 			printk("%s: Illegal value for"
 				" RlmtMode, using default\n", pAC->dev[0]->name);
-
-printk("MacFound = %d\nRlmtMode = %s", pAC->GIni.GIMacsFound, RlmtMode[pAC->Index]);
-	
-
 			pAC->RlmtMode = 0;
 		}
 	}
@@ -3551,7 +4039,7 @@
 int PciAddr,		/* PCI register address */
 SK_U32 *pVal)		/* pointer to store the read value */
 {
-	pci_read_config_dword(&pAC->PciDev, PciAddr, pVal);
+	pci_read_config_dword(pAC->PciDev, PciAddr, pVal);
 	return(0);
 } /* SkPciReadCfgDWord */
 
@@ -3573,7 +4061,7 @@
 int PciAddr,		/* PCI register address */
 SK_U16 *pVal)		/* pointer to store the read value */
 {
-	pci_read_config_word(&pAC->PciDev, PciAddr, pVal);
+	pci_read_config_word(pAC->PciDev, PciAddr, pVal);
 	return(0);
 } /* SkPciReadCfgWord */
 
@@ -3595,7 +4083,7 @@
 int PciAddr,		/* PCI register address */
 SK_U8 *pVal)		/* pointer to store the read value */
 {
-	pci_read_config_byte(&pAC->PciDev, PciAddr, pVal);
+	pci_read_config_byte(pAC->PciDev, PciAddr, pVal);
 	return(0);
 } /* SkPciReadCfgByte */
 
@@ -3617,7 +4105,7 @@
 int PciAddr,		/* PCI register address */
 SK_U32 Val)		/* pointer to store the read value */
 {
-	pci_write_config_dword(&pAC->PciDev, PciAddr, Val);
+	pci_write_config_dword(pAC->PciDev, PciAddr, Val);
 	return(0);
 } /* SkPciWriteCfgDWord */
 
@@ -3640,7 +4128,7 @@
 int PciAddr,		/* PCI register address */
 SK_U16 Val)		/* pointer to store the read value */
 {
-	pci_write_config_word(&pAC->PciDev, PciAddr, Val);
+	pci_write_config_word(pAC->PciDev, PciAddr, Val);
 	return(0);
 } /* SkPciWriteCfgWord */
 
@@ -3663,7 +4151,7 @@
 int PciAddr,		/* PCI register address */
 SK_U8 Val)		/* pointer to store the read value */
 {
-	pci_write_config_byte(&pAC->PciDev, PciAddr, Val);
+	pci_write_config_byte(pAC->PciDev, PciAddr, Val);
 	return(0);
 } /* SkPciWriteCfgByte */
 
@@ -3696,6 +4184,7 @@
 SK_EVPARA	NewPara;	/* parameter for further events */
 int		Stat;
 unsigned long	Flags;
+SK_BOOL		DualNet;
 
 	switch (Event) {
 	case SK_DRV_ADAP_FAIL:
@@ -3728,18 +4217,27 @@
 			&pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
 			Flags);
 		SkGeStopPort(pAC, IoC, FromPort, SK_STOP_ALL, SK_HARD_RST);
+		pAC->dev[Param.Para32[0]]->flags &= ~IFF_RUNNING;
 		spin_unlock_irqrestore(
 			&pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
 			Flags);
 		
 		/* clear rx ring from received frames */
-		ReceiveIrq(pAC, &pAC->RxPort[FromPort]);
+		ReceiveIrq(pAC, &pAC->RxPort[FromPort], SK_FALSE);
 		
 		ClearTxRing(pAC, &pAC->TxPort[FromPort][TX_PRIO_LOW]);
 		spin_lock_irqsave(
 			&pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
 			Flags);
-		SkGeInitPort(pAC, IoC, FromPort);
+		
+		/* tschilling: Handling of return value inserted. */
+		if (SkGeInitPort(pAC, IoC, FromPort)) {
+			if (FromPort == 0) {
+				printk("%s: SkGeInitPort A failed.\n", pAC->dev[0]->name);
+			} else {
+				printk("%s: SkGeInitPort B failed.\n", pAC->dev[1]->name);
+			}
+		}
 		SkAddrMcUpdate(pAC,IoC, FromPort);
 		PortReInitBmu(pAC, FromPort);
 		SkGePollTxD(pAC, IoC, FromPort, SK_TRUE);
@@ -3755,7 +4253,19 @@
 			("NET UP EVENT, Port: %d ", Param.Para32[0]));
 		printk("%s: network connection up using"
 			" port %c\n", pAC->dev[Param.Para32[0]]->name, 'A'+Param.Para32[0]);
-		printk("    speed:           1000\n");
+
+		/* tschilling: Values changed according to LinkSpeedUsed. */
+		Stat = pAC->GIni.GP[FromPort].PLinkSpeedUsed;
+		if (Stat == SK_LSPEED_STAT_10MBPS) {
+			printk("    speed:           10\n");
+		} else if (Stat == SK_LSPEED_STAT_100MBPS) {
+			printk("    speed:           100\n");
+		} else if (Stat == SK_LSPEED_STAT_1000MBPS) {
+			printk("    speed:           1000\n");
+		} else {
+			printk("    speed:           unknown\n");
+		}
+
 		Stat = pAC->GIni.GP[FromPort].PLinkModeStatus;
 		if (Stat == SK_LMODE_STAT_AUTOHALF ||
 			Stat == SK_LMODE_STAT_AUTOFULL) {
@@ -3784,8 +4294,12 @@
 		else {
 			printk("    flowctrl:        none\n");
 		}
-		if (pAC->GIni.GP[FromPort].PhyType != SK_PHY_XMAC) {
-		Stat = pAC->GIni.GP[FromPort].PMSStatus;
+		
+		/* tschilling: Check against CopperType now. */
+		if ((pAC->GIni.GICopperType == SK_TRUE) &&
+			(pAC->GIni.GP[FromPort].PLinkSpeedUsed ==
+			SK_LSPEED_STAT_1000MBPS)) {
+			Stat = pAC->GIni.GP[FromPort].PMSStatus;
 			if (Stat == SK_MS_STAT_MASTER ) {
 				printk("    role:            master\n");
 			}
@@ -3796,6 +4310,16 @@
 				printk("    role:            ???\n");
 			}
 		}
+
+#ifdef SK_ZEROCOPY
+		if (pAC->GIni.GIChipId == CHIP_ID_YUKON)
+			printk("    scatter-gather:  enabled\n");
+		else
+			printk("    scatter-gather:  disabled\n");
+
+#else
+			printk("    scatter-gather:  disabled\n");
+#endif
 		
 		if ((Param.Para32[0] != pAC->ActivePort) && 
 			(pAC->RlmtNets == 1)) {
@@ -3804,12 +4328,17 @@
 			SkEventQueue(pAC, SKGE_DRV, SK_DRV_SWITCH_INTERN,
 				NewPara);
 		}
+
+		/* Inform the world that link protocol is up. */
+		pAC->dev[Param.Para32[0]]->flags |= IFF_RUNNING;
+
 		break;
 	case SK_DRV_NET_DOWN:	 /* SK_U32 Reason */
 		/* 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[Param.Para32[1]]->name);
+		pAC->dev[Param.Para32[1]]->flags &= ~IFF_RUNNING;
 		break;
 	case SK_DRV_SWITCH_HARD: /* SK_U32 FromPortIdx SK_U32 ToPortIdx */
 		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
@@ -3841,8 +4370,8 @@
 			&pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
 			Flags);
 
-		ReceiveIrq(pAC, &pAC->RxPort[FromPort]); /* clears rx ring */
-		ReceiveIrq(pAC, &pAC->RxPort[ToPort]); /* clears rx ring */
+		ReceiveIrq(pAC, &pAC->RxPort[FromPort], SK_FALSE); /* clears rx ring */
+		ReceiveIrq(pAC, &pAC->RxPort[ToPort], SK_FALSE); /* clears rx ring */
 		
 		ClearTxRing(pAC, &pAC->TxPort[FromPort][TX_PRIO_LOW]);
 		ClearTxRing(pAC, &pAC->TxPort[ToPort][TX_PRIO_LOW]);
@@ -3852,13 +4381,37 @@
 		spin_lock_irqsave(
 			&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock, Flags);
 		pAC->ActivePort = ToPort;
+#if 0
 		SetQueueSizes(pAC);
-		SkGeInitPort(pAC, IoC, FromPort);
-		SkGeInitPort(pAC, IoC, ToPort);
+#else
+		/* tschilling: New common function with minimum size check. */
+		DualNet = SK_FALSE;
+		if (pAC->RlmtNets == 2) {
+			DualNet = SK_TRUE;
+		}
+		
+		if (SkGeInitAssignRamToQueues(
+			pAC,
+			pAC->ActivePort,
+			DualNet)) {
+			spin_unlock_irqrestore(
+				&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock, Flags);
+			spin_unlock_irqrestore(
+				&pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+				Flags);
+			printk("SkGeInitAssignRamToQueues failed.\n");
+			break;
+		}
+#endif
+		/* tschilling: Handling of return values inserted. */
+		if (SkGeInitPort(pAC, IoC, FromPort) ||
+			SkGeInitPort(pAC, IoC, ToPort)) {
+			printk("%s: SkGeInitPort failed.\n", pAC->dev[0]->name);
+		}
 		if (Event == SK_DRV_SWITCH_SOFT) {
-			SkXmRxTxEnable(pAC, IoC, FromPort);
+			SkMacRxTxEnable(pAC, IoC, FromPort);
 		}
-		SkXmRxTxEnable(pAC, IoC, ToPort);
+		SkMacRxTxEnable(pAC, IoC, ToPort);
 		SkAddrSwap(pAC, IoC, FromPort, ToPort);
 		SkAddrMcUpdate(pAC, IoC, FromPort);
 		SkAddrMcUpdate(pAC, IoC, ToPort);
@@ -3881,7 +4434,8 @@
 		pMsg = (struct sk_buff*) pRlmtMbuf->pOs;
 		skb_put(pMsg, pRlmtMbuf->Length);
 		if (XmitFrame(pAC, &pAC->TxPort[pRlmtMbuf->PortIdx][TX_PRIO_LOW],
-			      pMsg) < 0)
+			pMsg) < 0)
+
 			DEV_KFREE_SKB_ANY(pMsg);
 		break;
 	default:
@@ -3943,7 +4497,8 @@
 
 } /* SkErrorLog */
 
-#ifdef DEBUG /***************************************************************/
+#ifdef DEBUG
+/****************************************************************************/
 /* "debug only" section *****************************************************/
 /****************************************************************************/
 
@@ -4090,7 +4645,7 @@
 	printk("------------------------\n");
 } /* DumpLong */
 
-#endif /* DEBUG */
+#endif
 
 /*
  * Local variables:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sk98lin/skgehwt.c linux-2.4.21-pre6/drivers/net/sk98lin/skgehwt.c
--- linux-2.4.20/drivers/net/sk98lin/skgehwt.c	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sk98lin/skgehwt.c	2003-03-26 23:49:54.000000000 +0000
@@ -1,32 +1,23 @@
 /******************************************************************************
  *
  * Name:	skgehwt.c
- * Project:	PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.12 $
- * Date:	$Date: 1998/10/15 15:11:34 $
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.13 $
+ * Date:	$Date: 1999/11/22 13:31:12 $
  * Purpose:	Hardware Timer.
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1989-1998 SysKonnect,
+ *	(C)Copyright 1998,1999 SysKonnect,
  *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
- *	All Rights Reserved
  *
- *	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.
+ *	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.
  *
  ******************************************************************************/
@@ -36,6 +27,9 @@
  * 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
  *	
@@ -83,7 +77,7 @@
 	Event queue and dispatcher
 */
 static const char SysKonnectFileId[] =
-	"$Header: /usr56/projects/ge/schedule/skgehwt.c,v 1.12 1998/10/15 15:11:34 gklug Exp $" ;
+	"$Header: /usr56/projects/ge/schedule/skgehwt.c,v 1.13 1999/11/22 13:31:12 cgoos Exp $" ;
 
 #include "h/skdrv1st.h"		/* Driver Specific Definitions */
 #include "h/skdrv2nd.h"		/* Adapter Control- and Driver specific Def. */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sk98lin/skgeinit.c linux-2.4.21-pre6/drivers/net/sk98lin/skgeinit.c
--- linux-2.4.20/drivers/net/sk98lin/skgeinit.c	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sk98lin/skgeinit.c	2003-03-26 23:49:40.000000000 +0000
@@ -2,15 +2,15 @@
  *
  * Name:	skgeinit.c
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.63 $
- * Date:	$Date: 2001/04/05 11:02:09 $
+ * Version:	$Revision: 1.82 $
+ * Date:	$Date: 2002/12/05 13:40:21 $
  * Purpose:	Contains functions to initialize the GE HW
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998-2001 SysKonnect GmbH.
+ *	(C)Copyright 1998-2002 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 +26,108 @@
  * History:
  *
  *	$Log: skgeinit.c,v $
+ *	Revision 1.82  2002/12/05 13:40:21  rschmidt
+ *	Added setting of Rx GMAC FIFO Flush Mask register.
+ *	Corrected PhyType with new define SK_PHY_MARV_FIBER when
+ *	YUKON Fiber board was found.
+ *	Editorial changes.
+ *	
+ *	Revision 1.81  2002/11/15 12:48:35  rschmidt
+ *	Replaced message SKERR_HWI_E018 with SKERR_HWI_E024 for Rx queue error
+ *	in SkGeStopPort().
+ *	Added init for pAC->GIni.GIGenesis with SK_FALSE in YUKON-branch.
+ *	Editorial changes.
+ *	
+ *	Revision 1.80  2002/11/12 17:28:30  rschmidt
+ *	Initialized GIPciSlot64 and GIPciClock66 in SkGeInit1().
+ *	Reduced PCI FIFO watermarks for 32bit/33MHz bus in SkGeInitBmu().
+ *	Editorial changes.
+ *	
+ *	Revision 1.79  2002/10/21 09:31:02  mkarl
+ *	Changed SkGeInitAssignRamToQueues(), removed call to
+ *	SkGeInitAssignRamToQueues in SkGeInit1 and fixed compiler warning in
+ *	SkGeInit1.
+ *	
+ *	Revision 1.78  2002/10/16 15:55:07  mkarl
+ *	Fixed a bug in SkGeInitAssignRamToQueues.
+ *	
+ *	Revision 1.77  2002/10/14 15:07:22  rschmidt
+ *	Corrected timeout handling for Rx queue in SkGeStopPort() (#10748)
+ *	Editorial changes.
+ *	
+ *	Revision 1.76  2002/10/11 09:24:38  mkarl
+ *	Added check for HW self test results.
+ *	
+ *	Revision 1.75  2002/10/09 16:56:44  mkarl
+ *	Now call SkGeInitAssignRamToQueues() in Init Level 1 in order to assign
+ *	the adapter memory to the queues. This default assignment is not suitable
+ *	for dual net mode.
+ *	
+ *	Revision 1.74  2002/09/12 08:45:06  rwahl
+ *	Set defaults for PMSCap, PLinkSpeed & PLinkSpeedCap dependent on PHY.
+ *	
+ *	Revision 1.73  2002/08/16 15:19:45  rschmidt
+ *	Corrected check for Tx queues in SkGeCheckQSize().
+ *	Added init for new entry GIGenesis and GICopperType
+ *	Replaced all if(GIChipId == CHIP_ID_GENESIS) with new entry GIGenesis.
+ *	Replaced wrong 1st para pAC with IoC in SK_IN/OUT macros.
+ *	
+ *	Revision 1.72  2002/08/12 13:38:55  rschmidt
+ *	Added check if VAUX is available (stored in GIVauxAvail)
+ *	Initialized PLinkSpeedCap in Port struct with SK_LSPEED_CAP_1000MBPS
+ *	Editorial changes.
+ *	
+ *	Revision 1.71  2002/08/08 16:32:58  rschmidt
+ *	Added check for Tx queues in SkGeCheckQSize().
+ *	Added start of Time Stamp Timer (YUKON) in SkGeInit2().
+ *	Editorial changes.
+ *	
+ *	Revision 1.70  2002/07/23 16:04:26  rschmidt
+ *	Added init for GIWolOffs (HW-Bug in YUKON 1st rev.)
+ *	Minor changes
+ *	
+ *	Revision 1.69  2002/07/17 17:07:08  rwahl
+ *	- SkGeInit1(): fixed PHY type debug output; corrected init of GIFunc
+ *	  table & GIMacType.
+ *	- Editorial changes.
+ *	
+ *	Revision 1.68  2002/07/15 18:38:31  rwahl
+ *	Added initialization for MAC type dependent function table.
+ *	
+ *	Revision 1.67  2002/07/15 15:45:39  rschmidt
+ *	Added Tx Store & Forward for YUKON (GMAC Tx FIFO is only 1 kB)
+ *	Replaced SK_PHY_MARV by SK_PHY_MARV_COPPER
+ *	Editorial changes
+ *	
+ *	Revision 1.66  2002/06/10 09:35:08  rschmidt
+ *	Replaced C++ comments (//)
+ *	Editorial changes
+ *	
+ *	Revision 1.65  2002/06/05 08:33:37  rschmidt
+ *	Changed GIRamSize and Reset sequence for YUKON.
+ *	SkMacInit() replaced by SkXmInitMac() resp. SkGmInitMac()
+ *	
+ *	Revision 1.64  2002/04/25 13:03:20  rschmidt
+ *	Changes for handling YUKON.
+ *	Removed reference to xmac_ii.h (not necessary).
+ *	Moved all defines into header file.
+ *	Replaced all SkXm...() functions with SkMac...() to handle also
+ *	YUKON's GMAC.
+ *	Added handling for GMAC FIFO in SkGeInitMacFifo(), SkGeStopPort().
+ *	Removed 'goto'-directive from SkGeCfgSync(), SkGeCheckQSize().
+ *	Replaced all XMAC-access macros by functions: SkMacRxTxDisable(),
+ *	SkMacFlushTxFifo().
+ *	Optimized timeout handling in SkGeStopPort().
+ *	Initialized PLinkSpeed in Port struct with SK_LSPEED_AUTO.
+ *	Release of GMAC Link Control reset in SkGeInit1().
+ *	Initialized GIChipId and GIChipRev in GE Init structure.
+ *	Added GIRamSize and PhyType values for YUKON.
+ *	Removed use of PRxCmd to setup XMAC.
+ *	Moved setting of XM_RX_DIS_CEXT to SkXmInitMac().
+ *	Use of SkGeXmitLED() only for GENESIS.
+ *	Changes for V-CPU support.
+ *	Editorial changes.
+ *	
  *	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.
  *	
@@ -139,7 +241,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 stoped
+ *	fix: do NOT stop LED Timer when port should be stopped
  *
  *	Revision 1.30  1998/11/24 13:15:28  gklug
  *	add: Init PCkeckPar struct member
@@ -150,8 +252,8 @@
  *	transmit timeouts.
  *	Add TestStopBit() function to handle stop RX/TX
  *	problem with active descriptor poll timers.
- *	Bug Fix: Descriptor Poll Timer not started, beacuse
- *	GIPollTimerVal was initilaized with 0.
+ *	Bug Fix: Descriptor Poll Timer not started, because
+ *	GIPollTimerVal was initialized with 0.
  *
  *	Revision 1.28  1998/11/13 14:24:26  malthoff
  *	Bug Fix: SkGeStopPort() may hang if a Packet Arbiter Timout
@@ -181,7 +283,7 @@
  *
  *	Revision 1.21  1998/10/20 12:11:56  malthoff
  *	Don't dendy the Queue config if the size of the unused
- *	rx qeueu is zero.
+ *	Rx qeueu is zero.
  *
  *	Revision 1.20  1998/10/19 07:27:58  malthoff
  *	SkGeInitRamIface() is public to be called by diagnostics.
@@ -268,39 +370,21 @@
  *
  *	Revision 1.1  1998/07/23 09:48:57  malthoff
  *	Creation. First dummy 'C' file.
- *	SkGeInit(Level 0) is card_start for ML.
- *	SkGeDeInit() is card_stop for ML.
+ *	SkGeInit(Level 0) is card_start for GE.
+ *	SkGeDeInit() is card_stop for GE.
  *
  *
  ******************************************************************************/
 
 #include "h/skdrv1st.h"
-#include "h/xmac_ii.h"
 #include "h/skdrv2nd.h"
 
-/* defines ********************************************************************/
-
-/* defines for SkGeXmitLed() */
-#define XMIT_LED_INI	0
-#define XMIT_LED_CNT	(RX_LED_VAL - RX_LED_INI)
-#define XMIT_LED_CTRL	(RX_LED_CTRL- RX_LED_INI)
-#define XMIT_LED_TST	(RX_LED_TST - RX_LED_INI)
-
-/* Queue Size units */
-#define QZ_UNITS	0x7
-
-/* Types of RAM Buffer Queues */
-#define SK_RX_SRAM_Q	1	/* small receive queue */
-#define SK_RX_BRAM_Q	2	/* big receive queue */
-#define SK_TX_RAM_Q	3	/* small or big transmit queue */
-
-/* typedefs *******************************************************************/
 /* global variables ***********************************************************/
 
 /* local variables ************************************************************/
 
 static const char SysKonnectFileId[] =
-	"@(#)$Id: skgeinit.c,v 1.63 2001/04/05 11:02:09 rassmann Exp $ (C) SK ";
+	"@(#)$Id: skgeinit.c,v 1.82 2002/12/05 13:40:21 rschmidt Exp $ (C) SK ";
 
 struct s_QOffTab {
 	int	RxQOff;		/* Receive Queue Address Offset */
@@ -314,11 +398,11 @@
 
 /******************************************************************************
  *
- *	SkGePollRxD() - Enable/Disable Descriptor Polling of RxD Ring
+ *	SkGePollRxD() - Enable / Disable Descriptor Polling of RxD Ring
  *
  * Description:
  *	Enable or disable the descriptor polling the receive descriptor
- *	ring (RxD) of port 'port'.
+ *	ring (RxD) of port 'Port'.
  *	The new configuration is *not* saved over any SkGeStopPort() and
  *	SkGeInitPort() calls.
  *
@@ -335,22 +419,18 @@
 
 	pPrt = &pAC->GIni.GP[Port];
 
-	if (PollRxD) {
-		SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_CSR), CSR_ENA_POL);
-	}
-	else {
-		SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_CSR), CSR_DIS_POL);
-	}
+	SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_CSR), (PollRxD) ?
+		CSR_ENA_POL : CSR_DIS_POL);
 }	/* SkGePollRxD */
 
 
 /******************************************************************************
  *
- *	SkGePollTxD() - Enable/Disable Descriptor Polling of TxD Rings
+ *	SkGePollTxD() - Enable / Disable Descriptor Polling of TxD Rings
  *
  * Description:
  *	Enable or disable the descriptor polling the transmit descriptor
- *	ring(s) (RxD) of port 'port'.
+ *	ring(s) (TxD) of port 'Port'.
  *	The new configuration is *not* saved over any SkGeStopPort() and
  *	SkGeInitPort() calls.
  *
@@ -368,16 +448,12 @@
 
 	pPrt = &pAC->GIni.GP[Port];
 
-	if (PollTxD) {
-		DWord = CSR_ENA_POL;
-	}
-	else {
-		DWord = CSR_DIS_POL;
-	}
+	DWord = (PollTxD) ? CSR_ENA_POL : CSR_DIS_POL;
 
 	if (pPrt->PXSQSize != 0) {
 		SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), DWord);
 	}
+	
 	if (pPrt->PXAQSize != 0) {
 		SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), DWord);
 	}
@@ -397,7 +473,7 @@
  * Returns:
  *	nothing
  */
-void	SkGeYellowLED(
+void SkGeYellowLED(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
 int		State)		/* yellow LED state, 0 = OFF, 0 != ON */
@@ -430,7 +506,7 @@
  * Returns:
  *	nothing
  */
-void	SkGeXmitLED(
+void SkGeXmitLED(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
 int		Led,		/* offset to the LED Init Value register */
@@ -475,9 +551,8 @@
  *	DoCalcAddr() - Calculates the start and the end address of a queue.
  *
  * Description:
- *	This function calculates the start- end the end address
- *	of a queue. Afterwards the 'StartVal' is incremented to the
- *	next start position.
+ *	This function calculates the start and the end address of a queue.
+ *  Afterwards the 'StartVal' is incremented to the next start position.
  *	If the port is already initialized the calculated values
  *	will be checked against the configured values and an
  *	error will be returned, if they are not equal.
@@ -498,7 +573,7 @@
 {
 	SK_U32	EndVal;
 	SK_U32	NextStart;
-	int	Rtv;
+	int		Rtv;
 
 	Rtv = 0;
 	if (QuSize == 0) {
@@ -521,9 +596,125 @@
 	}
 
 	*StartVal = NextStart;
-	return (Rtv);
+	return(Rtv);
 }	/* DoCalcAddr */
 
+/******************************************************************************
+ *
+ *	SkGeInitAssignRamToQueues() - allocate default queue sizes
+ *
+ * Description:
+ *	This function assigns the memory to the different queues and ports.
+ *	When DualNet is set to SK_TRUE all ports get the same amount of memory.
+ *  Otherwise the first port gets most of the memory and all the
+ *	other ports just the required minimum.
+ *	This function can only be called when pAC->GIni.GIRamSize and
+ *	pAC->GIni.GIMacsFound have been initialized, usually this happens
+ *	at init level 1
+ *
+ * Returns:
+ *	0 - ok
+ *	1 - invalid input values
+ *	2 - not enough memory
+ */
+
+int SkGeInitAssignRamToQueues(
+SK_AC	*pAC,			/* Adapter context */
+int		ActivePort,		/* Active Port in RLMT mode */
+SK_BOOL	DualNet)		/* adapter context */
+{
+	int	i;
+	int	UsedKilobytes;			/* memory already assigned */
+	int	ActivePortKilobytes;	/* memory available for active port */
+	SK_GEPORT *pGePort;
+
+	UsedKilobytes = 0;
+
+	if (ActivePort >= pAC->GIni.GIMacsFound) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_INIT,
+			("SkGeInitAssignRamToQueues: ActivePort (%d) invalid\n",
+			ActivePort));
+		return(1);
+	}
+	if (((pAC->GIni.GIMacsFound * (SK_MIN_RXQ_SIZE + SK_MIN_TXQ_SIZE)) +
+		((RAM_QUOTA_SYNC == 0) ? 0 : SK_MIN_TXQ_SIZE)) > pAC->GIni.GIRamSize) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_INIT,
+			("SkGeInitAssignRamToQueues: Not enough memory (%d)\n",
+			 pAC->GIni.GIRamSize));
+		return(2);
+	}
+
+
+	if (DualNet) {
+		/* every port gets the same amount of memory */
+		ActivePortKilobytes = pAC->GIni.GIRamSize / pAC->GIni.GIMacsFound;
+		for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+
+			pGePort = &pAC->GIni.GP[i];
+			
+			/* take away the minimum memory for active queues */
+			ActivePortKilobytes -= (SK_MIN_RXQ_SIZE + SK_MIN_TXQ_SIZE);
+
+			/* receive queue gets the minimum + 80% of the rest */
+			pGePort->PRxQSize = (int) (ROUND_QUEUE_SIZE_KB((
+				ActivePortKilobytes * (unsigned long) RAM_QUOTA_RX) / 100))
+				+ SK_MIN_RXQ_SIZE;
+
+			ActivePortKilobytes -= (pGePort->PRxQSize - SK_MIN_RXQ_SIZE);
+
+			/* synchronous transmit queue */
+			pGePort->PXSQSize = 0;
+
+			/* asynchronous transmit queue */
+			pGePort->PXAQSize = (int) ROUND_QUEUE_SIZE_KB(ActivePortKilobytes +
+				SK_MIN_TXQ_SIZE);
+		}
+	}
+	else {	
+		/* Rlmt Mode or single link adapter */
+
+		/* Set standby queue size defaults for all standby ports */
+		for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+
+			if (i != ActivePort) {
+				pGePort = &pAC->GIni.GP[i];
+
+				pGePort->PRxQSize = SK_MIN_RXQ_SIZE;
+				pGePort->PXAQSize = SK_MIN_TXQ_SIZE;
+				pGePort->PXSQSize = 0;
+
+				/* Count used RAM */
+				UsedKilobytes += pGePort->PRxQSize + pGePort->PXAQSize;
+			}
+		}
+		/* what's left? */
+		ActivePortKilobytes = pAC->GIni.GIRamSize - UsedKilobytes;
+
+		/* assign it to the active port */
+		/* first take away the minimum memory */
+		ActivePortKilobytes -= (SK_MIN_RXQ_SIZE + SK_MIN_TXQ_SIZE);
+		pGePort = &pAC->GIni.GP[ActivePort];
+
+		/* receive queue get's the minimum + 80% of the rest */
+		pGePort->PRxQSize = (int) (ROUND_QUEUE_SIZE_KB((ActivePortKilobytes *
+			(unsigned long) RAM_QUOTA_RX) / 100)) + SK_MIN_RXQ_SIZE;
+
+		ActivePortKilobytes -= (pGePort->PRxQSize - SK_MIN_RXQ_SIZE);
+
+		/* synchronous transmit queue */
+		pGePort->PXSQSize = 0;
+
+		/* asynchronous transmit queue */
+		pGePort->PXAQSize = (int) ROUND_QUEUE_SIZE_KB(ActivePortKilobytes) +
+			SK_MIN_TXQ_SIZE;
+	}
+#ifdef VCPU
+	VCPUprintf(0, "PRxQSize=%u, PXSQSize=%u, PXAQSize=%u\n",
+		pGePort->PRxQSize, pGePort->PXSQSize, pGePort->PXAQSize);
+#endif /* VCPU */
+
+	return(0);
+}	/* SkGeInitAssignRamToQueues */
 
 /******************************************************************************
  *
@@ -531,18 +722,20 @@
  *
  * Description:
  *	This function verifies the Queue Size Configuration specified
- *	in the variabels PRxQSize, PXSQSize, and PXAQSize of all
+ *	in the variables PRxQSize, PXSQSize, and PXAQSize of all
  *	used ports.
  *	This requirements must be fullfilled to have a valid configuration:
  *		- The size of all queues must not exceed GIRamSize.
  *		- The queue sizes must be specified in units of 8 kB.
- *		- The size of rx queues of available ports must not be
- *		  smaller than 16kB.
+ *		- The size of Rx queues of available ports must not be
+ *		  smaller than 16 kB.
+ *		- The size of at least one Tx queue (synch. or asynch.)
+ *        of available ports must not be smaller than 16 kB
+ *        when Jumbo Frames are used.
  *		- The RAM start and end addresses must not be changed
  *		  for ports which are already initialized.
- *	Furthermore SkGeCheckQSize() defines the Start and End
- *	Addresses of all ports and stores them into the HWAC port
- *	structure.
+ *	Furthermore SkGeCheckQSize() defines the Start and End Addresses
+ *  of all ports and stores them into the HWAC port	structure.
  *
  * Returns:
  *	0:	Queue Size Configuration valid
@@ -553,7 +746,7 @@
 int		 Port)		/* port index */
 {
 	SK_GEPORT *pPrt;
-	int	UsedMem;
+	int	UsedMem;	/* total memory used (max. found ports) */
 	int	i;
 	int	Rtv;
 	int	Rtv2;
@@ -564,27 +757,37 @@
 	for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
 		pPrt = &pAC->GIni.GP[i];
 
-		if (( pPrt->PRxQSize & QZ_UNITS) ||
-			(pPrt->PXSQSize & QZ_UNITS) ||
-			(pPrt->PXAQSize & QZ_UNITS)) {
+		if ((pPrt->PRxQSize & QZ_UNITS) != 0 ||
+			(pPrt->PXSQSize & QZ_UNITS) != 0 ||
+			(pPrt->PXAQSize & QZ_UNITS) != 0) {
 
 			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E012, SKERR_HWI_E012MSG);
-			Rtv = 1;
-			goto CheckQSizeEnd;
+			return(1);
 		}
 
-		UsedMem += pPrt->PRxQSize + pPrt->PXSQSize + pPrt->PXAQSize;
-
 		if (i == Port && pPrt->PRxQSize < SK_MIN_RXQ_SIZE) {
 			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E011, SKERR_HWI_E011MSG);
-			Rtv = 1;
-			goto CheckQSizeEnd;
+			return(1);
 		}
+		
+		/*
+		 * the size of at least one Tx queue (synch. or asynch.) has to be > 0.
+		 * if Jumbo Frames are used, this size has to be >= 16 kB.
+		 */
+		if ((i == Port && pPrt->PXSQSize == 0 && pPrt->PXAQSize == 0) ||
+			(pAC->GIni.GIPortUsage == SK_JUMBO_LINK &&
+            ((pPrt->PXSQSize > 0 && pPrt->PXSQSize < SK_MIN_TXQ_SIZE) ||
+			 (pPrt->PXAQSize > 0 && pPrt->PXAQSize < SK_MIN_TXQ_SIZE)))) {
+				SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E023, SKERR_HWI_E023MSG);
+				return(1);
+		}
+		
+		UsedMem += pPrt->PRxQSize + pPrt->PXSQSize + pPrt->PXAQSize;
 	}
+	
 	if (UsedMem > pAC->GIni.GIRamSize) {
 		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E012, SKERR_HWI_E012MSG);
-		Rtv = 1;
-		goto CheckQSizeEnd;
+		return(1);
 	}
 
 	/* Now start address calculation */
@@ -597,24 +800,23 @@
 			&pPrt->PRxQRamStart, &pPrt->PRxQRamEnd);
 		Rtv |= Rtv2;
 
-		/* Calculate/Check values for the synchronous tx queue */
+		/* Calculate/Check values for the synchronous Tx queue */
 		Rtv2 = DoCalcAddr(pAC, pPrt, pPrt->PXSQSize, &StartAddr,
 			&pPrt->PXsQRamStart, &pPrt->PXsQRamEnd);
 		Rtv |= Rtv2;
 
-		/* Calculate/Check values for the asynchronous tx queue */
+		/* Calculate/Check values for the asynchronous Tx queue */
 		Rtv2 = DoCalcAddr(pAC, pPrt, pPrt->PXAQSize, &StartAddr,
 			&pPrt->PXaQRamStart, &pPrt->PXaQRamEnd);
 		Rtv |= Rtv2;
 
 		if (Rtv) {
 			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E013, SKERR_HWI_E013MSG);
-			break;
+			return(1);
 		}
 	}
 
-CheckQSizeEnd:
-	return (Rtv);
+	return(0);
 }	/* SkGeCheckQSize */
 
 
@@ -625,10 +827,10 @@
  * Description:
  *	This function initializes the MAC Arbiter.
  *	It must not be called if there is still an
- *	initilaized or active port.
+ *	initialized or active port.
  *
  * Returns:
- *	nothing:
+ *	nothing
  */
 static void SkGeInitMacArb(
 SK_AC	*pAC,		/* adapter context */
@@ -652,7 +854,7 @@
 	/* Fast Output Enable Mode was intended to use with Rev. B2, but now? */
 
 	/*
-	 * There is not start or enable buttom to push, therefore
+	 * There is not start or enable button to push, therefore
 	 * the MAC arbiter is configured and enabled now.
 	 */
 }	/* SkGeInitMacArb */
@@ -665,10 +867,10 @@
  * Description:
  *	This function initializes the Packet Arbiter.
  *	It must not be called if there is still an
- *	initilaized or active port.
+ *	initialized or active port.
  *
  * Returns:
- *	nothing:
+ *	nothing
  */
 static void SkGeInitPktArb(
 SK_AC	*pAC,		/* adapter context */
@@ -693,7 +895,7 @@
 			SK_OUT16(IoC, B3_PA_CTRL, PA_ENA_TO_TX1);
 		}
 		else {
-			SK_OUT16(IoC, B3_PA_CTRL,(PA_ENA_TO_TX1 | PA_ENA_TO_TX2));
+			SK_OUT16(IoC, B3_PA_CTRL, PA_ENA_TO_TX1 | PA_ENA_TO_TX2);
 		}
 	}
 }	/* SkGeInitPktArb */
@@ -714,6 +916,9 @@
 SK_IOC	IoC,		/* IO context */
 int		Port)		/* Port Index (MAC_1 + n) */
 {
+#ifdef VCPU
+	SK_U32	DWord;
+#endif /* VCPU */
 	/*
 	 * For each FIFO:
 	 *	- release local reset
@@ -721,19 +926,45 @@
 	 *	- setup defaults for the control register
 	 *	- enable the FIFO
 	 */
-	/* Configure RX MAC FIFO */
-	SK_OUT8(IoC, MR_ADDR(Port, RX_MFF_CTRL2), MFF_RST_CLR);
-	SK_OUT16(IoC, MR_ADDR(Port, RX_MFF_CTRL1), MFF_RX_CTRL_DEF);
-	SK_OUT8(IoC, MR_ADDR(Port, RX_MFF_CTRL2), MFF_ENA_OP_MD);
-
-	/* Configure TX MAC FIFO */
-	SK_OUT8(IoC, MR_ADDR(Port, TX_MFF_CTRL2), MFF_RST_CLR);
-	SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_TX_CTRL_DEF);
-	SK_OUT8(IoC, MR_ADDR(Port, TX_MFF_CTRL2), MFF_ENA_OP_MD);
-
-	/* Enable frame flushing if jumbo frames used */
-	if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) {
-		SK_OUT16(IoC, MR_ADDR(Port, RX_MFF_CTRL1), MFF_ENA_FLUSH);
+	
+	if (pAC->GIni.GIGenesis) {
+		/* Configure Rx MAC FIFO */
+		SK_OUT8(IoC, MR_ADDR(Port, RX_MFF_CTRL2), MFF_RST_CLR);
+		SK_OUT16(IoC, MR_ADDR(Port, RX_MFF_CTRL1), MFF_RX_CTRL_DEF);
+		SK_OUT8(IoC, MR_ADDR(Port, RX_MFF_CTRL2), MFF_ENA_OP_MD);
+	
+		/* Configure Tx MAC FIFO */
+		SK_OUT8(IoC, MR_ADDR(Port, TX_MFF_CTRL2), MFF_RST_CLR);
+		SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_TX_CTRL_DEF);
+		SK_OUT8(IoC, MR_ADDR(Port, TX_MFF_CTRL2), MFF_ENA_OP_MD);
+	
+		/* Enable frame flushing if jumbo frames used */
+		if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) {
+			SK_OUT16(IoC, MR_ADDR(Port, RX_MFF_CTRL1), MFF_ENA_FLUSH);
+		}
+	}
+	else {
+		/* Configure Rx MAC FIFO */
+		SK_OUT8(IoC, MR_ADDR(Port, RX_GMF_CTRL_T), (SK_U8)GMF_RST_CLR);
+		SK_OUT32(IoC, MR_ADDR(Port, RX_GMF_CTRL_T), GMF_RX_CTRL_DEF |
+			GMF_RX_F_FL_ON);		/* enable Rx GMAC FIFO Flush */
+	
+		/* set Rx GMAC FIFO Flush Mask */
+		SK_OUT16(IoC, MR_ADDR(Port, RX_GMF_FL_MSK), (SK_U16)RX_FF_FL_DEF_MSK);
+		
+		/* use Rx GMAC FIFO Flush Threshold default value (0x0a == 56 bytes) */
+		
+		/* Configure Tx MAC FIFO */
+		SK_OUT8(IoC, MR_ADDR(Port, TX_GMF_CTRL_T), (SK_U8)GMF_RST_CLR);
+		SK_OUT32(IoC, MR_ADDR(Port, TX_GMF_CTRL_T), GMF_TX_CTRL_DEF);
+		
+#ifdef VCPU
+		SK_IN32(IoC, MR_ADDR(Port, RX_GMF_AF_THR), &DWord);
+		SK_IN32(IoC, MR_ADDR(Port, TX_GMF_AE_THR), &DWord);
+#endif /* VCPU */
+		
+		/* set Tx GMAC FIFO Almost Empty Threshold */
+/*		SK_OUT32(IoC, MR_ADDR(Port, TX_GMF_AE_THR), 0); */
 	}
 }	/* SkGeInitMacFifo */
 
@@ -750,11 +981,11 @@
  *
  * Note:
  *	o To ensure receiving the Link Sync Event the LinkSyncCounter
- *	  should be initialized BEFORE clearing the XMACs reset!
+ *	  should be initialized BEFORE clearing the XMAC's reset!
  *	o Enable IS_LNK_SYNC_M1 and IS_LNK_SYNC_M2 after calling this
  *	  function.
  *
- * Retruns:
+ * Returns:
  *	nothing
  */
 void SkGeLoadLnkSyncCnt(
@@ -784,13 +1015,13 @@
 	SK_IN32(IoC, B0_IMSK, &OrgIMsk);
 	if (Port == MAC_1) {
 		NewIMsk = OrgIMsk & ~IS_LNK_SYNC_M1;
-		if (ISrc & IS_LNK_SYNC_M1) {
+		if ((ISrc & IS_LNK_SYNC_M1) != 0) {
 			IrqPend = SK_TRUE;
 		}
 	}
 	else {
 		NewIMsk = OrgIMsk & ~IS_LNK_SYNC_M2;
-		if (ISrc & IS_LNK_SYNC_M2) {
+		if ((ISrc & IS_LNK_SYNC_M2) != 0) {
 			IrqPend = SK_TRUE;
 		}
 	}
@@ -829,14 +1060,14 @@
  *	TXA_ENA_FSYNC. This means if the size of
  *	the synchronous queue is unequal zero but no specific
  *	synchronous bandwidth is configured, the synchronous queue
- *	will always have the 'unlimitted' transmit priority!
+ *	will always have the 'unlimited' transmit priority!
  *
  *	This mode will be restored if the synchronous bandwidth is
  *	deallocated ('IntTime' = 0 and 'LimCount' = 0).
  *
  * Returns:
  *	0:	success
- *	1:	paramter configuration error
+ *	1:	parameter configuration error
  *	2:	try to configure quality of service although no
  *		synchronous queue is configured
  */
@@ -855,59 +1086,59 @@
 	/* check the parameters */
 	if (LimCount > IntTime ||
 		(LimCount == 0 && IntTime != 0) ||
-		(LimCount !=0 && IntTime == 0)) {
+		(LimCount != 0 && IntTime == 0)) {
 
 		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E010, SKERR_HWI_E010MSG);
-		Rtv = 1;
-		goto CfgSyncEnd;
+		return(1);
 	}
-	if (pAC->GIni.GP[Port].PXSQSize != 0) {
-		/* calculate register values */
-		IntTime = (IntTime / 2) * pAC->GIni.GIHstClkFact / 100;
-		LimCount = LimCount / 8;
-		if (IntTime > TXA_MAX_VAL || LimCount > TXA_MAX_VAL) {
-			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E010, SKERR_HWI_E010MSG);
-			Rtv = 1;
-			goto CfgSyncEnd;
-		}
-
-		/*
-		 * - Enable 'Force Sync' to ensure the synchronous queue
-		 *   has the priority while configuring the new values.
-		 * - Also 'disable alloc' to ensure the settings complies
-		 *   to the SyncMode parameter.
-		 * - Disable 'Rate Control' to configure the new values.
-		 * - write IntTime and Limcount
-		 * - start 'Rate Control' and disable 'Force Sync'
-		 *   if Interval Timer or Limit Counter not zero.
-		 */
-		SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL),
-			TXA_ENA_FSYNC | TXA_DIS_ALLOC | TXA_STOP_RC);
-		SK_OUT32(IoC, MR_ADDR(Port, TXA_ITI_INI), IntTime);
-		SK_OUT32(IoC, MR_ADDR(Port, TXA_LIM_INI), LimCount);
-		SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL),
-			(SyncMode & (TXA_ENA_ALLOC|TXA_DIS_ALLOC)));
-		if (IntTime != 0 || LimCount != 0) {
-			SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL),
-				TXA_DIS_FSYNC|TXA_START_RC);
-		}
-	}
-	else {
+	
+	if (pAC->GIni.GP[Port].PXSQSize == 0) {
 		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E009, SKERR_HWI_E009MSG);
-		Rtv = 2;
+		return(2);
+	}
+	
+	/* calculate register values */
+	IntTime = (IntTime / 2) * pAC->GIni.GIHstClkFact / 100;
+	LimCount = LimCount / 8;
+	
+	if (IntTime > TXA_MAX_VAL || LimCount > TXA_MAX_VAL) {
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E010, SKERR_HWI_E010MSG);
+		return(1);
+	}
+
+	/*
+	 * - Enable 'Force Sync' to ensure the synchronous queue
+	 *   has the priority while configuring the new values.
+	 * - Also 'disable alloc' to ensure the settings complies
+	 *   to the SyncMode parameter.
+	 * - Disable 'Rate Control' to configure the new values.
+	 * - write IntTime and LimCount
+	 * - start 'Rate Control' and disable 'Force Sync'
+	 *   if Interval Timer or Limit Counter not zero.
+	 */
+	SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL),
+		TXA_ENA_FSYNC | TXA_DIS_ALLOC | TXA_STOP_RC);
+	
+	SK_OUT32(IoC, MR_ADDR(Port, TXA_ITI_INI), IntTime);
+	SK_OUT32(IoC, MR_ADDR(Port, TXA_LIM_INI), LimCount);
+	
+	SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL),
+		(SK_U8)(SyncMode & (TXA_ENA_ALLOC | TXA_DIS_ALLOC)));
+	
+	if (IntTime != 0 || LimCount != 0) {
+		SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL), TXA_DIS_FSYNC | TXA_START_RC);
 	}
 
-CfgSyncEnd:
-	return (Rtv);
+	return(0);
 }	/* SkGeCfgSync */
 
 
 /******************************************************************************
  *
- *	DoInitRamQueue() - Initilaize the RAM Buffer Address of a single Queue
+ *	DoInitRamQueue() - Initialize the RAM Buffer Address of a single Queue
  *
  * Desccription:
- *	If the queue is used, enable and initilaize it.
+ *	If the queue is used, enable and initialize it.
  *	Make sure the queue is still reset, if it is not used.
  *
  * Returns:
@@ -952,22 +1183,21 @@
 			/* write threshold for Rx Queue */
 
 			SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_RX_UTPP), RxUpThresVal);
-			SK_OUT32(IoC, RB_ADDR(QuIoOffs,RB_RX_LTPP), RxLoThresVal);
+			SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_RX_LTPP), RxLoThresVal);
 
 			/* the high priority threshold not used */
 			break;
 		case SK_TX_RAM_Q:
 			/*
-			 * Do NOT use Store and forward under normal
-			 * operation due to performance optimization.
-			 * But if Jumbo frames are configured we NEED
-			 * the store and forward of the RAM buffer.
+			 * Do NOT use Store & Forward under normal operation due to
+			 * performance optimization (GENESIS only).
+			 * But if Jumbo Frames are configured (XMAC Tx FIFO is only 4 kB)
+			 * or YUKON is used ((GMAC Tx FIFO is only 1 kB)
+			 * we NEED Store & Forward of the RAM buffer.
 			 */
-			if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) {
-				/*
-				 * enable Store & Forward Mode for the
-				 * Tx Side
-				 */
+			if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK ||
+				!pAC->GIni.GIGenesis) {
+				/* enable Store & Forward Mode for the Tx Side */
 				SK_OUT8(IoC, RB_ADDR(QuIoOffs, RB_CTRL), RB_ENA_STFWD);
 			}
 			break;
@@ -980,7 +1210,7 @@
 		/* ensure the queue is still disabled */
 		SK_OUT8(IoC, RB_ADDR(QuIoOffs, RB_CTRL), RB_RST_SET);
 	}
-}	/* DoInitRamQueue*/
+}	/* DoInitRamQueue */
 
 
 /******************************************************************************
@@ -1012,10 +1242,13 @@
 
 	DoInitRamQueue(pAC, IoC, pPrt->PRxQOff, pPrt->PRxQRamStart,
 		pPrt->PRxQRamEnd, RxQType);
+	
 	DoInitRamQueue(pAC, IoC, pPrt->PXsQOff, pPrt->PXsQRamStart,
 		pPrt->PXsQRamEnd, SK_TX_RAM_Q);
+	
 	DoInitRamQueue(pAC, IoC, pPrt->PXaQOff, pPrt->PXaQRamStart,
 		pPrt->PXaQRamEnd, SK_TX_RAM_Q);
+
 }	/* SkGeInitRamBufs */
 
 
@@ -1024,7 +1257,7 @@
  *	SkGeInitRamIface() - Initialize the RAM Interface
  *
  * Description:
- *	This function initializes the Adapbers RAM Interface.
+ *	This function initializes the Adapters RAM Interface.
  *
  * Note:
  *	This function is used in the diagnostics.
@@ -1052,6 +1285,7 @@
 	SK_OUT8(IoC, B3_RI_RTO_R2, SK_RI_TO_53);
 	SK_OUT8(IoC, B3_RI_RTO_XA2, SK_RI_TO_53);
 	SK_OUT8(IoC, B3_RI_RTO_XS2, SK_RI_TO_53);
+
 }	/* SkGeInitRamIface */
 
 
@@ -1070,25 +1304,37 @@
 SK_IOC	IoC,		/* IO context */
 int		Port)		/* Port Index (MAC_1 + n) */
 {
-	SK_GEPORT *pPrt;
+	SK_GEPORT	*pPrt;
+	SK_U32		RxWm;
+	SK_U32		TxWm;
 
 	pPrt = &pAC->GIni.GP[Port];
 
+	RxWm = SK_BMU_RX_WM;
+	TxWm = SK_BMU_TX_WM;
+	
+	if (!pAC->GIni.GIPciSlot64 && !pAC->GIni.GIPciClock66) {
+		/* for better performance */
+		RxWm /= 2;
+		TxWm /= 2;
+	}
+
 	/* Rx Queue: Release all local resets and set the watermark */
 	SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_CSR), CSR_CLR_RESET);
-	SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_F), SK_BMU_RX_WM);
+	SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_F), RxWm);
 
 	/*
-	 * Tx Queue: Release all local resets if the queue is used!
+	 * Tx Queue: Release all local resets if the queue is used !
 	 * 		set watermark
 	 */
 	if (pPrt->PXSQSize != 0) {
 		SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), CSR_CLR_RESET);
-		SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_F), SK_BMU_TX_WM);
+		SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_F), TxWm);
 	}
+	
 	if (pPrt->PXAQSize != 0) {
 		SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), CSR_CLR_RESET);
-		SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_F), SK_BMU_TX_WM);
+		SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_F), TxWm);
 	}
 	/*
 	 * Do NOT enable the descriptor poll timers here, because
@@ -1107,7 +1353,7 @@
  *	that RX/TX stop is done and SV idle is NOT set.
  *	In this case we have to issue another stop command.
  *
- * Retruns:
+ * Returns:
  *	The queues control status register
  */
 static SK_U32 TestStopBit(
@@ -1118,12 +1364,16 @@
 	SK_U32	QuCsr;	/* CSR contents */
 
 	SK_IN32(IoC, Q_ADDR(QuIoOffs, Q_CSR), &QuCsr);
-	if ((QuCsr & (CSR_STOP|CSR_SV_IDLE)) == 0) {
+	
+	if ((QuCsr & (CSR_STOP | CSR_SV_IDLE)) == 0) {
+		/* Stop Descriptor overridden by start command */
 		SK_OUT32(IoC, Q_ADDR(QuIoOffs, Q_CSR), CSR_STOP);
+
 		SK_IN32(IoC, Q_ADDR(QuIoOffs, Q_CSR), &QuCsr);
 	}
-	return (QuCsr);
-}	/* TestStopBit*/
+	
+	return(QuCsr);
+}	/* TestStopBit */
 
 
 /******************************************************************************
@@ -1131,31 +1381,31 @@
  *	SkGeStopPort() - Stop the Rx/Tx activity of the port 'Port'.
  *
  * Description:
- *	After calling this function the descriptor rings and rx and tx
+ *	After calling this function the descriptor rings and Rx and Tx
  *	queues of this port may be reconfigured.
  *
- *	It is possible to stop the receive and transmit path seperate or
+ *	It is possible to stop the receive and transmit path separate or
  *	both together.
  *
- *	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 transfered
+ *	Dir =	SK_STOP_TX 	Stops the transmit path only and resets the MAC.
+ *				The receive queue is still active and
+ *				the pending Rx frames may be still transferred
  *				into the RxD.
  *		SK_STOP_RX	Stop the receive path. The tansmit path
- *				has to be stoped once before.
+ *				has to be stopped once before.
  *		SK_STOP_ALL	SK_STOP_TX + SK_STOP_RX
  *
- *	RstMode=SK_SOFT_RST	Resets the XMAC. The PHY is still alive.
- *		SK_HARD_RST	Resets the XMAC and the PHY.
+ *	RstMode = SK_SOFT_RST	Resets the MAC. The PHY is still alive.
+ *			SK_HARD_RST	Resets the MAC and the PHY.
  *
  * Example:
  *	1) A Link Down event was signaled for a port. Therefore the activity
- *	of this port should be stoped and a hardware reset should be issued
+ *	of this port should be stopped and a hardware reset should be issued
  *	to enable the workaround of XMAC errata #2. But the received frames
  *	should not be discarded.
  *		...
  *		SkGeStopPort(pAC, IoC, Port, SK_STOP_TX, SK_HARD_RST);
- *		(transfer all pending rx frames)
+ *		(transfer all pending Rx frames)
  *		SkGeStopPort(pAC, IoC, Port, SK_STOP_RX, SK_HARD_RST);
  *		...
  *
@@ -1170,29 +1420,29 @@
  *
  * Extended Description:
  *	If SK_STOP_TX is set,
- *		o disable the XMACs receive and transmiter to prevent
+ *		o disable the MAC's receive and transmitter to prevent
  *		  from sending incomplete frames
  *		o stop the port's transmit queues before terminating the
  *		  BMUs to prevent from performing incomplete PCI cycles
  *		  on the PCI bus
- *		- The network rx and tx activity and PCI tx transfer is
+ *		- The network Rx and Tx activity and PCI Tx transfer is
  *		  disabled now.
- *		o reset the XMAC depending on the RstMode
+ *		o reset the MAC depending on the RstMode
  *		o Stop Interval Timer and Limit Counter of Tx Arbiter,
  *		  also disable Force Sync bit and Enable Alloc bit.
- *		o perform a local reset of the port's tx path
- *			- reset the PCI FIFO of the async tx queue
- *			- reset the PCI FIFO of the sync tx queue
- *			- reset the RAM Buffer async tx queue
- *			- reset the RAM Butter sync tx queue
+ *		o perform a local reset of the port's Tx path
+ *			- reset the PCI FIFO of the async Tx queue
+ *			- reset the PCI FIFO of the sync Tx queue
+ *			- reset the RAM Buffer async Tx queue
+ *			- reset the RAM Buffer sync Tx queue
  *			- reset the MAC Tx FIFO
  *		o switch Link and Tx LED off, stop the LED counters
  *
  *	If SK_STOP_RX is set,
  *		o stop the port's receive queue
  *		- The path data transfer activity is fully stopped now.
- *		o perform a local reset of the port's rx path
- *			- reset the PCI FIFO of the rx queue
+ *		o perform a local reset of the port's Rx path
+ *			- reset the PCI FIFO of the Rx queue
  *			- reset the RAM Buffer receive queue
  *			- reset the MAC Rx FIFO
  *		o switch Rx LED off, stop the LED counter
@@ -1204,36 +1454,30 @@
  *	o This function may be called during the driver states RESET_PORT and
  *	  SWITCH_PORT.
  */
-void	SkGeStopPort(
+void SkGeStopPort(
 SK_AC	*pAC,	/* adapter context */
 SK_IOC	IoC,	/* I/O context */
 int		Port,	/* port to stop (MAC_1 + n) */
 int		Dir,	/* Direction to Stop (SK_STOP_RX, SK_STOP_TX, SK_STOP_ALL) */
 int		RstMode)/* Reset Mode (SK_SOFT_RST, SK_HARD_RST) */
 {
-#ifndef	SK_DIAG
+#ifndef SK_DIAG
 	SK_EVPARA Para;
-#endif	/* !SK_DIAG */
+#endif /* !SK_DIAG */
 	SK_GEPORT *pPrt;
 	SK_U32	DWord;
-	SK_U16	Word;
 	SK_U32	XsCsr;
 	SK_U32	XaCsr;
 	int		i;
-	SK_BOOL	AllPortsDis;
 	SK_U64	ToutStart;
 	int		ToutCnt;
 
 	pPrt = &pAC->GIni.GP[Port];
 
-	if (Dir & SK_STOP_TX) {
-		/* disable the XMACs 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));
-
-		/* dummy read to ensure writing */
-		XM_IN16(IoC, Port, XM_MMU_CMD, &Word);
-
+	if ((Dir & SK_STOP_TX) != 0) {
+		/* disable receiver and transmitter */
+		SkMacRxTxDisable(pAC, IoC, Port);
+		
 		/* stop both transmit queues */
 		/*
 		 * If the BMU is in the reset state CSR_STOP will terminate
@@ -1249,21 +1493,14 @@
 			 * Clear packet arbiter timeout to make sure
 			 * this loop will terminate.
 			 */
-			if (Port == MAC_1) {
-				Word = PA_CLR_TO_TX1;
-			}
-			else {
-				Word = PA_CLR_TO_TX2;
-			}
-			SK_OUT16(IoC, B3_PA_CTRL, Word);
+			SK_OUT16(IoC, B3_PA_CTRL, (Port == MAC_1) ? PA_CLR_TO_TX1 :
+				PA_CLR_TO_TX2);
 
 			/*
-			 * If the transfer stucks at the XMAC the STOP command will not
-			 * terminate if we don't flush the XMAC's transmit FIFO!
+			 * If the transfer stucks at the MAC 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;
-			XM_OUT32(IoC, Port, XM_MODE, DWord);
+			SkMacFlushTxFifo(pAC, IoC, Port);
 
 			XsCsr = TestStopBit(pAC, IoC, pPrt->PXsQOff);
 			XaCsr = TestStopBit(pAC, IoC, pPrt->PXaQOff);
@@ -1274,40 +1511,32 @@
 				 * This needs to be checked at 1/18 sec only.
 				 */
 				ToutCnt++;
-				switch (ToutCnt) {
-				case 1:
-					/*
-					 * Cache Incoherency workaround: Assume a start command
-					 * has been lost while sending the frame. 
-					 */
-					ToutStart = SkOsGetTime(pAC);
-					if (XsCsr & CSR_STOP) {
-						SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), CSR_START);
-					}
-					if (XaCsr & CSR_STOP) {
-						SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), CSR_START);
-					}
-					break;
-				case 2:
-				default:
+				if (ToutCnt > 1) {
 					/* Might be a problem when the driver event handler
-					 * calls StopPort again.
-					 * XXX.
+					 * calls StopPort again. XXX.
 					 */
 
 					/* Fatal Error, Loop aborted */
-					/* Create an Error Log Entry */
-					SK_ERR_LOG(
-						pAC,
-						SK_ERRCL_HW,
-						SKERR_HWI_E018,
+					SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_HWI_E018,
 						SKERR_HWI_E018MSG);
 #ifndef SK_DIAG
 					Para.Para64 = Port;
 					SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
-#endif	/* !SK_DIAG */
+#endif /* !SK_DIAG */
 					return;
 				}
+				/*
+				 * Cache incoherency workaround: Assume a start command
+				 * has been lost while sending the frame.
+				 */
+				ToutStart = SkOsGetTime(pAC);
+
+				if ((XsCsr & CSR_STOP) != 0) {
+					SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), CSR_START);
+				}
+				if ((XaCsr & CSR_STOP) != 0) {
+					SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), CSR_START);
+				}
 			}
 
 			/*
@@ -1315,46 +1544,51 @@
 			 * 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);
+				 (XaCsr & (CSR_STOP | CSR_SV_IDLE)) != CSR_SV_IDLE);
 
-		/* reset the XMAC depending on the RstMode */
+		/* Reset the MAC depending on the RstMode */
 		if (RstMode == SK_SOFT_RST) {
-			SkXmSoftRst(pAC, IoC, Port);
+			SkMacSoftRst(pAC, IoC, Port);
 		}
 		else {
-			SkXmHardRst(pAC, IoC, Port);
+			SkMacHardRst(pAC, IoC, Port);
 		}
-
- 		/*
-		 * Stop Interval Timer and Limit Counter of Tx Arbiter,
- 		 * also disable Force Sync bit and Enable Alloc bit.
-		 */
+ 		
+		/* Disable Force Sync bit and Enable Alloc bit */
 		SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL),
 			TXA_DIS_FSYNC | TXA_DIS_ALLOC | TXA_STOP_RC);
-		SK_OUT32(IoC, MR_ADDR(Port, TXA_ITI_INI), 0x00000000L);
-		SK_OUT32(IoC, MR_ADDR(Port, TXA_LIM_INI), 0x00000000L);
+		
+		/* Stop Interval Timer and Limit Counter of Tx Arbiter */
+		SK_OUT32(IoC, MR_ADDR(Port, TXA_ITI_INI), 0L);
+		SK_OUT32(IoC, MR_ADDR(Port, TXA_LIM_INI), 0L);
 
-		/*
-		 * perform a local reset of the port's tx path
-		 *	- reset the PCI FIFO of the async tx queue
-		 *	- reset the PCI FIFO of the sync tx queue
-		 *	- reset the RAM Buffer async tx queue
-		 *	- reset the RAM Butter sync tx queue
-		 *	- reset the MAC Tx FIFO
-		 */
+		/* Perform a local reset of the port's Tx path */
+
+		/* Reset the PCI FIFO of the async Tx queue */
 		SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), CSR_SET_RESET);
+		/* Reset the PCI FIFO of the sync Tx queue */
 		SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), CSR_SET_RESET);
+		/* Reset the RAM Buffer async Tx queue */
 		SK_OUT8(IoC, RB_ADDR(pPrt->PXaQOff, RB_CTRL), RB_RST_SET);
+		/* Reset the RAM Buffer sync Tx queue */
 		SK_OUT8(IoC, RB_ADDR(pPrt->PXsQOff, RB_CTRL), RB_RST_SET);
-		/* Note: MFF_RST_SET does NOT reset the XMAC! */
-		SK_OUT8(IoC, MR_ADDR(Port, TX_MFF_CTRL2), MFF_RST_SET);
-
-		/* switch Link and Tx LED off, stop the LED counters */
-		/* Link LED is switched off by the RLMT and the Diag itself */
-		SkGeXmitLED(pAC, IoC, MR_ADDR(Port, TX_LED_INI), SK_LED_DIS);
+		
+		/* Reset Tx MAC FIFO */
+		if (pAC->GIni.GIGenesis) {
+			/* Note: MFF_RST_SET does NOT reset the XMAC ! */
+			SK_OUT8(IoC, MR_ADDR(Port, TX_MFF_CTRL2), MFF_RST_SET);
+
+			/* switch Link and Tx LED off, stop the LED counters */
+			/* Link LED is switched off by the RLMT and the Diag itself */
+			SkGeXmitLED(pAC, IoC, MR_ADDR(Port, TX_LED_INI), SK_LED_DIS);
+		}
+		else {
+			/* Reset TX MAC FIFO */
+			SK_OUT8(IoC, MR_ADDR(Port, TX_GMF_CTRL_T), (SK_U8)GMF_RST_SET);
+		}
 	}
 
-	if (Dir & SK_STOP_RX) {
+	if ((Dir & SK_STOP_RX) != 0) {
 		/*
 		 * The RX Stop Command will not terminate if no buffers
 		 * are queued in the RxD ring. But it will always reach
@@ -1363,64 +1597,52 @@
 		 */
 		/* stop the port's receive queue */
 		SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_CSR), CSR_STOP);
+		
 		i = 100;
 		do {
 			/*
 			 * Clear packet arbiter timeout to make sure
 			 * this loop will terminate
 			 */
-			if (Port == MAC_1) {
-				Word = PA_CLR_TO_RX1;
-			}
-			else {
-				Word = PA_CLR_TO_RX2;
-			}
-			SK_OUT16(IoC, B3_PA_CTRL, Word);
-
+			SK_OUT16(IoC, B3_PA_CTRL, (Port == MAC_1) ? PA_CLR_TO_RX1 :
+				PA_CLR_TO_RX2);
+			
 			DWord = TestStopBit(pAC, IoC, pPrt->PRxQOff);
-			if (i != 0) {
-				i--;
-			}
 
-			/* finish if CSR_STOP is done or CSR_SV_IDLE is true and i==0 */
+			/* timeout if i==0 (bug fix for #10748) */
+			if (--i == 0) {
+				SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_HWI_E024,
+					SKERR_HWI_E024MSG);
+				break;
+			}
 			/*
 			 * 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));
+		} while ((DWord & (CSR_STOP | CSR_SV_IDLE)) != CSR_SV_IDLE);
 
-		/* The path data transfer activity is fully stopped now. */
+		/* The path data transfer activity is fully stopped now */
 
-		/*
-		 * perform a local reset of the port's rx path
-		 *	- reset the PCI FIFO of the rx queue
-		 *	- reset the RAM Buffer receive queue
-		 *	- reset the MAC Rx FIFO
-		 */
+		/* Perform a local reset of the port's Rx path */
+
+		 /*	Reset the PCI FIFO of the Rx queue */
 		SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_CSR), CSR_SET_RESET);
+		/* Reset the RAM Buffer receive queue */
 		SK_OUT8(IoC, RB_ADDR(pPrt->PRxQOff, RB_CTRL), RB_RST_SET);
-		SK_OUT8(IoC, MR_ADDR(Port, RX_MFF_CTRL2), MFF_RST_SET);
-
-		/* switch Rx LED off, stop the LED counter */
-		SkGeXmitLED(pAC, IoC, MR_ADDR(Port, RX_LED_INI), SK_LED_DIS);
-
-	}
 
- 	/*
-	 * If all ports are stopped reset the RAM Interface.
-	 */
-	for (i = 0, AllPortsDis = SK_TRUE; i < pAC->GIni.GIMacsFound; i++) {
-		if (pAC->GIni.GP[i].PState != SK_PRT_RESET &&
-			pAC->GIni.GP[i].PState != SK_PRT_STOP) {
+		/* Reset Rx MAC FIFO */
+		if (pAC->GIni.GIGenesis) {
+			
+			SK_OUT8(IoC, MR_ADDR(Port, RX_MFF_CTRL2), MFF_RST_SET);
 
-			AllPortsDis = SK_FALSE;
-			break;
+			/* switch Rx LED off, stop the LED counter */
+			SkGeXmitLED(pAC, IoC, MR_ADDR(Port, RX_LED_INI), SK_LED_DIS);
+		}
+		else {
+			/* Reset Rx MAC FIFO */
+			SK_OUT8(IoC, MR_ADDR(Port, RX_GMF_CTRL_T), (SK_U8)GMF_RST_SET);
 		}
-	}
-	if (AllPortsDis) {
-		pAC->GIni.GIAnyPortAct = SK_FALSE;
 	}
 }	/* SkGeStopPort */
 
@@ -1444,12 +1666,12 @@
 
 	for (i = 0; i < SK_MAX_MACS; i++) {
 		pPrt = &pAC->GIni.GP[i];
+
 		pPrt->PState = SK_PRT_RESET;
 		pPrt->PRxQOff = QOffTab[i].RxQOff;
 		pPrt->PXsQOff = QOffTab[i].XsQOff;
 		pPrt->PXaQOff = QOffTab[i].XaQOff;
 		pPrt->PCheckPar = SK_FALSE;
-		pPrt->PRxCmd = XM_RX_STRIP_FCS | XM_RX_LENERR_OK;
 		pPrt->PIsave = 0;
 		pPrt->PPrevShorts = 0;
 		pPrt->PLinkResCt = 0;
@@ -1458,6 +1680,9 @@
 		pPrt->PPrevFcs = 0;
 		pPrt->PRxLim = SK_DEF_RX_WA_LIM;
 		pPrt->PLinkMode = SK_LMODE_AUTOFULL;
+		pPrt->PLinkSpeedCap = SK_LSPEED_CAP_1000MBPS;
+		pPrt->PLinkSpeed = SK_LSPEED_1000MBPS;
+		pPrt->PLinkSpeedUsed = SK_LSPEED_STAT_UNKNOWN;
 		pPrt->PLinkModeConf = SK_LMODE_AUTOSENSE;
 		pPrt->PFlowCtrlMode = SK_FLOW_MODE_SYM_OR_REM;
 		pPrt->PLinkBroken = SK_TRUE; /* See WA code */
@@ -1466,8 +1691,7 @@
 		pPrt->PLinkModeStatus = SK_LMODE_STAT_UNKNOWN;
 		pPrt->PFlowCtrlCap = SK_FLOW_MODE_SYM_OR_REM;
 		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE;
-		pPrt->PMSCap = (SK_MS_CAP_AUTO | SK_MS_CAP_MASTER | 
-				SK_MS_CAP_SLAVE);
+		pPrt->PMSCap = 0;
 		pPrt->PMSMode = SK_MS_MODE_AUTO;
 		pPrt->PMSStatus = SK_MS_STAT_UNSET;
 		pPrt->PAutoNegFail = SK_FALSE;
@@ -1476,7 +1700,7 @@
 	}
 
 	pAC->GIni.GIPortUsage = SK_RED_LINK;
-	pAC->GIni.GIAnyPortAct = SK_FALSE;
+
 }	/* SkGeInit0*/
 
 #ifdef SK_PCI_RESET
@@ -1520,42 +1744,39 @@
 	/* We know the RAM Interface Arbiter is enabled. */
 	SkPciWriteCfgWord(pAC, PCI_PM_CTL_STS, PCI_PM_STATE_D3);
 	SkPciReadCfgWord(pAC, PCI_PM_CTL_STS, &PmCtlSts);
-	if ((PmCtlSts & PCI_PM_STATE) != PCI_PM_STATE_D3) {
-		return (1);
+	
+	if ((PmCtlSts & PCI_PM_STATE_MSK) != PCI_PM_STATE_D3) {
+		return(1);
 	}
 
-	/*
-	 * Return to D0 state.
-	 */
+	/* Return to D0 state. */
 	SkPciWriteCfgWord(pAC, PCI_PM_CTL_STS, PCI_PM_STATE_D0);
 
 	/* Check for D0 state. */
 	SkPciReadCfgWord(pAC, PCI_PM_CTL_STS, &PmCtlSts);
-	if ((PmCtlSts & PCI_PM_STATE) != PCI_PM_STATE_D0) {
-		return (1);
+	
+	if ((PmCtlSts & PCI_PM_STATE_MSK) != PCI_PM_STATE_D0) {
+		return(1);
 	}
 
-	/*
-	 * Check PCI Config Registers.
-	 */
+	/* Check PCI Config Registers. */
 	SkPciReadCfgWord(pAC, PCI_COMMAND, &PciCmd);
 	SkPciReadCfgByte(pAC, PCI_CACHE_LSZ, &Cls);
 	SkPciReadCfgDWord(pAC, PCI_BASE_1ST, &Bp1);
 	SkPciReadCfgDWord(pAC, PCI_BASE_2ND, &Bp2);
-	SkPciReadCfgByte(pAC, PCI_LAT_TIM, &lat);
+	SkPciReadCfgByte(pAC, PCI_LAT_TIM, &Lat);
+	
 	if (PciCmd != 0 || Cls != 0 || (Bp1 & 0xfffffff0L) != 0 || Bp2 != 1 ||
-		Lat != 0 ) {
-		return (0);
+		Lat != 0) {
+		return(1);
 	}
 
-	/*
-	 * Restore Config Space.
-	 */
+	/* Restore PCI Config Space. */
 	for (i = 0; i < PCI_CFG_SIZE; i++) {
 		SkPciWriteCfgDWord(pAC, i*4, ConfigSpace[i]);
 	}
 
-	return (0);
+	return(0);
 }	/* SkGePciReset */
 
 #endif	/* SK_PCI_RESET */
@@ -1572,13 +1793,14 @@
  *	o Get the hardware configuration
  *		+ Read the number of MACs/Ports.
  *		+ Read the RAM size.
- *		+ Read the PCI Revision ID.
+ *		+ Read the PCI Revision Id.
  *		+ Find out the adapters host clock speed
  *		+ Read and check the PHY type
  *
  * Returns:
  *	0:	success
  *	5:	Unexpected PHY type detected
+ *	6:	HW self test failed
  */
 static int SkGeInit1(
 SK_AC	*pAC,		/* adapter context */
@@ -1595,56 +1817,113 @@
 	(void)SkGePciReset(pAC, IoC);
 #endif	/* SK_PCI_RESET */
 
-	/* Do the reset */
+	/* Do the SW-reset */
 	SK_OUT8(IoC, B0_CTST, CS_RST_SET);
 
-	/* Release the reset */
+	/* Release the SW-reset */
 	SK_OUT8(IoC, B0_CTST, CS_RST_CLR);
 
 	/* Reset all error bits in the PCI STATUS register */
 	/*
-	 * Note: Cfg cycles cannot be used, because they are not
+	 * Note: PCI Cfg cycles cannot be used, because they are not
 	 *		 available on some platforms after 'boot time'.
 	 */
-	SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON);
 	SK_IN16(IoC, PCI_C(PCI_STATUS), &Word);
+	
+	SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON);
 	SK_OUT16(IoC, PCI_C(PCI_STATUS), Word | PCI_ERRBITS);
 	SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
 
-	/* Release Master_Reset */
+	/* Release Master Reset */
 	SK_OUT8(IoC, B0_CTST, CS_MRST_CLR);
 
+	/* Read Chip Identification Number */
+	SK_IN8(IoC, B2_CHIP_ID, &Byte);
+	pAC->GIni.GIChipId = Byte;
+	
 	/* Read number of MACs */
 	SK_IN8(IoC, B2_MAC_CFG, &Byte);
-	if (Byte & CFG_SNG_MAC) {
-		pAC->GIni.GIMacsFound = 1;
-	}
-	else {
-		pAC->GIni.GIMacsFound = 2;
-	}
-	SK_IN8(IoC, PCI_C(PCI_REV_ID), &Byte);
-	pAC->GIni.GIPciHwRev = (int) Byte;
+	pAC->GIni.GIMacsFound = (Byte & CFG_SNG_MAC) ? 1 : 2;
+	
+	/* Get Chip Revision Number */
+	pAC->GIni.GIChipRev = (SK_U8)((Byte & CFG_CHIP_R_MSK) >> 4);
 
-	/* Read the adapters RAM size */
+	/* Read the adapters external SRAM size */
 	SK_IN8(IoC, B2_E_0, &Byte);
-	if (Byte == 3) {
-		pAC->GIni.GIRamSize = (int)(Byte-1) * 512;
-		pAC->GIni.GIRamOffs = (SK_U32)512 * 1024;
+	
+	if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+
+		pAC->GIni.GIGenesis = SK_TRUE;
+
+		if (Byte == 3) {						
+			/* special case: 4 x 64k x 36, offset = 0x80000 */
+			pAC->GIni.GIRamSize = 1024;
+			pAC->GIni.GIRamOffs = (SK_U32)512 * 1024;
+		}
+		else {
+			pAC->GIni.GIRamSize = (int)Byte * 512;
+			pAC->GIni.GIRamOffs = 0;
+		}
 	}
 	else {
-		pAC->GIni.GIRamSize = (int)Byte * 512;
+		
+		pAC->GIni.GIGenesis = SK_FALSE;
+
+#ifndef VCPU
+		pAC->GIni.GIRamSize = (Byte == 0) ? 128 : (int)Byte * 4;
+#else
+		pAC->GIni.GIRamSize = 128;
+#endif		
 		pAC->GIni.GIRamOffs = 0;
+		
+		pAC->GIni.GIWolOffs = (pAC->GIni.GIChipRev == 0) ? WOL_REG_OFFS : 0;
+		
+		for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+			/* set GMAC Link Control reset */
+			SK_OUT16(IoC, MR_ADDR(i, GMAC_LINK_CTRL), GMLC_RST_SET);
+
+			/* clear GMAC Link Control reset */
+			SK_OUT16(IoC, MR_ADDR(i, GMAC_LINK_CTRL), GMLC_RST_CLR);
+		}
 	}
 
-	/* All known GE Adapters works with 53.125 MHz host clock */
+	/* get diff. PCI parameters */
+	SK_IN16(IoC, B0_CTST, &Word);
+
+	/* Check if 64-bit PCI Slot is present */
+	pAC->GIni.GIPciSlot64 = (SK_BOOL)((Word & CS_BUS_SLOT_SZ) != 0);
+	
+	/* Check if 66 MHz PCI Clock is active */
+	pAC->GIni.GIPciClock66 = (SK_BOOL)((Word & CS_BUS_CLOCK) != 0);
+
+	/* Check if VAUX is available */
+	pAC->GIni.GIVauxAvail = (SK_BOOL)((Word & CS_VAUX_AVAIL) != 0);
+
+	/* Read PCI HW Revision Id. */
+	SK_IN8(IoC, PCI_C(PCI_REV_ID), &Byte);
+	pAC->GIni.GIPciHwRev = Byte;
+
+	/* All known GE Adapters work with 53.125 MHz host clock */
 	pAC->GIni.GIHstClkFact = SK_FACT_53;
 	pAC->GIni.GIPollTimerVal =
 		SK_DPOLL_DEF * (SK_U32)pAC->GIni.GIHstClkFact / 100;
 	
+	/* Read the PMD type */
+	SK_IN8(IoC, B2_PMD_TYP, &Byte);
+	pAC->GIni.GICopperType = (SK_U8)(Byte == 'T');
+
 	/* Read the PHY type */
 	SK_IN8(IoC, B2_E_1, &Byte);
+
+#ifdef VCPU
+	if (!pAC->GIni.GIGenesis) {
+		pAC->GIni.GICopperType = SK_TRUE;
+		Byte = SK_PHY_MARV_COPPER;		/* this field is not initialized */
+	}
+#endif
+
 	Byte &= 0x0f;	/* the PHY type is stored in the lower nibble */
-	for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+	for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
 		pAC->GIni.GP[i].PhyType = Byte;
 		switch (Byte) {
 		case SK_PHY_XMAC:
@@ -1652,25 +1931,71 @@
 			break;
 		case SK_PHY_BCOM:
 			pAC->GIni.GP[i].PhyAddr = PHY_ADDR_BCOM;
+			pAC->GIni.GP[i].PMSCap =
+				SK_MS_CAP_AUTO | SK_MS_CAP_MASTER | SK_MS_CAP_SLAVE;
 			break;
+		case SK_PHY_MARV_COPPER:
+			pAC->GIni.GP[i].PhyAddr = PHY_ADDR_MARV;
+			if (pAC->GIni.GICopperType) {
+				pAC->GIni.GP[i].PLinkSpeedCap = SK_LSPEED_CAP_AUTO |
+					SK_LSPEED_CAP_10MBPS | SK_LSPEED_CAP_100MBPS |
+					SK_LSPEED_CAP_1000MBPS;
+				pAC->GIni.GP[i].PLinkSpeed = SK_LSPEED_AUTO;
+				pAC->GIni.GP[i].PMSCap =
+					SK_MS_CAP_AUTO | SK_MS_CAP_MASTER | SK_MS_CAP_SLAVE;
+			}
+			else {
+				pAC->GIni.GP[i].PhyType = SK_PHY_MARV_FIBER;
+			}
+			break;
+#ifdef OTHER_PHY
 		case SK_PHY_LONE:
 			pAC->GIni.GP[i].PhyAddr = PHY_ADDR_LONE;
 			break;
 		case SK_PHY_NAT:
 			pAC->GIni.GP[i].PhyAddr = PHY_ADDR_NAT;
 			break;
+#endif /* OTHER_PHY */
 		default:
-			/* ERROR: unexpected PHY typ detected */
+			/* ERROR: unexpected PHY type detected */
 			RetVal = 5;
 			break;
 		}
+		
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_INIT,
+			("PHY type: %d  PHY addr: %04x\n", pAC->GIni.GP[i].PhyType,
+			pAC->GIni.GP[i].PhyAddr));
 	}
-	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_INIT,
-		("PHY type: %d  PHY addr: %x\n", pAC->GIni.GP[i].PhyType,
-		pAC->GIni.GP[i].PhyAddr));
+	
+	/* Get Mac Type & set function pointers dependent on */
+	if (pAC->GIni.GIGenesis) {
+		pAC->GIni.GIMacType = SK_MAC_XMAC;
+
+		pAC->GIni.GIFunc.pFnMacUpdateStats	= SkXmUpdateStats;
+		pAC->GIni.GIFunc.pFnMacStatistic	= SkXmMacStatistic;
+		pAC->GIni.GIFunc.pFnMacResetCounter	= SkXmResetCounter;
+		pAC->GIni.GIFunc.pFnMacOverflow		= SkXmOverflowStatus;
+	}
+	else {
+		pAC->GIni.GIMacType = SK_MAC_GMAC;
 
-	return (RetVal);
-}	/* SkGeInit1*/
+		pAC->GIni.GIFunc.pFnMacUpdateStats	= SkGmUpdateStats;
+		pAC->GIni.GIFunc.pFnMacStatistic	= SkGmMacStatistic;
+		pAC->GIni.GIFunc.pFnMacResetCounter	= SkGmResetCounter;
+		pAC->GIni.GIFunc.pFnMacOverflow		= SkGmOverflowStatus;
+		
+#ifndef VCPU
+		if (pAC->GIni.GIChipId == CHIP_ID_YUKON) {
+			/* check HW self test result */
+			SK_IN8(IoC, B2_E_3, &Byte);
+			if ((Byte & B2_E3_RES_MASK) != 0) {
+				RetVal = 6;
+			}
+		}
+#endif
+	}
+	return(RetVal);
+}	/* SkGeInit1 */
 
 
 /******************************************************************************
@@ -1692,64 +2017,48 @@
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC)		/* IO context */
 {
-	SK_GEPORT *pPrt;
 	SK_U32	DWord;
-	int	i;
-
-	/* start the Blink Source Counter */
-	DWord = SK_BLK_DUR * (SK_U32)pAC->GIni.GIHstClkFact / 100;
-	SK_OUT32(IoC, B2_BSC_INI, DWord);
-	SK_OUT8(IoC, B2_BSC_CTRL, BSC_START);
+	int		i;
 
 	/* start the Descriptor Poll Timer */
 	if (pAC->GIni.GIPollTimerVal != 0) {
 		if (pAC->GIni.GIPollTimerVal > SK_DPOLL_MAX) {
 			pAC->GIni.GIPollTimerVal = SK_DPOLL_MAX;
 
-			/* Create an Error Log Entry */
 			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E017, SKERR_HWI_E017MSG);
 		}
 		SK_OUT32(IoC, B28_DPT_INI, pAC->GIni.GIPollTimerVal);
 		SK_OUT8(IoC, B28_DPT_CTRL, DPT_START);
 	}
 
-	/*
-	 * Configure
-	 *	- the MAC-Arbiter and
-	 *	- the Paket Arbiter
-	 *
-	 * The MAC and the packet arbiter will be started once
-	 * and never be stopped.
-	 */
-	SkGeInitMacArb(pAC, IoC);
-	SkGeInitPktArb(pAC, IoC);
+	if (pAC->GIni.GIGenesis) {
+		/* start the Blink Source Counter */
+		DWord = SK_BLK_DUR * (SK_U32)pAC->GIni.GIHstClkFact / 100;
+
+		SK_OUT32(IoC, B2_BSC_INI, DWord);
+		SK_OUT8(IoC, B2_BSC_CTRL, BSC_START);
+
+		/*
+		 * Configure the MAC Arbiter and the Packet Arbiter.
+		 * They will be started once and never be stopped.
+		 */
+		SkGeInitMacArb(pAC, IoC);
+
+		SkGeInitPktArb(pAC, IoC);
+	}
+	else {
+		/* Start Time Stamp Timer */
+		SK_OUT8(IoC, GMAC_TI_ST_CTRL, (SK_U8)GMT_ST_START);
+	}
 
 	/* enable the Tx Arbiters */
-	SK_OUT8(IoC, MR_ADDR(MAC_1, TXA_CTRL), TXA_ENA_ARB);
-	if (pAC->GIni.GIMacsFound > 1) {
-		SK_OUT8(IoC, MR_ADDR(MAC_2, TXA_CTRL), TXA_ENA_ARB);
+	for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+		SK_OUT8(IoC, MR_ADDR(i, TXA_CTRL), TXA_ENA_ARB);
 	}
 
 	/* enable the RAM Interface Arbiter */
 	SkGeInitRamIface(pAC, IoC);
 
-	for (i = 0; i < SK_MAX_MACS; i++) {
-		pPrt = &pAC->GIni.GP[i];
-		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 */
 
 /******************************************************************************
@@ -1758,9 +2067,8 @@
  *
  * Description:
  *	Level	0:	Initialize the Module structures.
- *	Level	1:	Generic Hardware Initialization. The
- *			IOP/MemBase pointer has to be set before
- *			calling this level.
+ *	Level	1:	Generic Hardware Initialization. The IOP/MemBase pointer has
+ *				to be set before calling this level.
  *
  *			o Do a software reset.
  *			o Clear all reset bits.
@@ -1780,18 +2088,19 @@
  *
  * Returns:
  *	0:	success
- *	1:	Number of MACs exceeds SK_MAX_MACS	( after level 1)
- *	2:	Adapter not present or not accessable
+ *	1:	Number of MACs exceeds SK_MAX_MACS	(after level 1)
+ *	2:	Adapter not present or not accessible
  *	3:	Illegal initialization level
  *	4:	Initialization Level 1 Call missing
  *	5:	Unexpected PHY type detected
+ *	6:	HW self test failed
  */
 int	SkGeInit(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
 int		Level)		/* initialization level */
 {
-	int	RetVal;		/* return value */
+	int		RetVal;		/* return value */
 	SK_U32	DWord;
 
 	RetVal = 0;
@@ -1804,14 +2113,19 @@
 		SkGeInit0(pAC, IoC);
 		pAC->GIni.GILevel = SK_INIT_DATA;
 		break;
+	
 	case SK_INIT_IO:
 		/* Initialization Level 1 */
 		RetVal = SkGeInit1(pAC, IoC);
+		if (RetVal != 0) {
+			break;
+		}
 
-		/* Check if the adapter seems to be accessable */
+		/* Check if the adapter seems to be accessible */
 		SK_OUT32(IoC, B2_IRQM_INI, 0x11335577L);
 		SK_IN32(IoC, B2_IRQM_INI, &DWord);
-		SK_OUT32(IoC, B2_IRQM_INI, 0x00000000L);
+		SK_OUT32(IoC, B2_IRQM_INI, 0L);
+		
 		if (DWord != 0x11335577L) {
 			RetVal = 2;
 			break;
@@ -1826,12 +2140,13 @@
 		/* Level 1 successfully passed */
 		pAC->GIni.GILevel = SK_INIT_IO;
 		break;
+	
 	case SK_INIT_RUN:
 		/* Initialization Level 2 */
 		if (pAC->GIni.GILevel != SK_INIT_IO) {
-#ifndef	SK_DIAG
+#ifndef SK_DIAG
 			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E002, SKERR_HWI_E002MSG);
-#endif
+#endif /* !SK_DIAG */
 			RetVal = 4;
 			break;
 		}
@@ -1840,15 +2155,15 @@
 		/* Level 2 successfully passed */
 		pAC->GIni.GILevel = SK_INIT_RUN;
 		break;
+	
 	default:
-		/* Create an Error Log Entry */
 		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E003, SKERR_HWI_E003MSG);
 		RetVal = 3;
 		break;
 	}
 
-	return (RetVal);
-}	/* SkGeInit*/
+	return(RetVal);
+}	/* SkGeInit */
 
 
 /******************************************************************************
@@ -1862,15 +2177,17 @@
  * Returns:
  *	nothing
  */
-void	SkGeDeInit(
+void SkGeDeInit(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC)		/* IO context */
 {
 	int	i;
 	SK_U16	Word;
 
-	/* Ensure I2C is ready. */
+#ifndef VCPU
+	/* Ensure I2C is ready */
 	SkI2cWaitIrq(pAC, IoC);
+#endif
 
 	/* Stop all current transfer activity */
 	for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
@@ -1883,39 +2200,39 @@
 
 	/* Reset all bits in the PCI STATUS register */
 	/*
-	 * Note: Cfg cycles cannot be used, because they are not
+	 * Note: PCI Cfg cycles cannot be used, because they are not
 	 *	 available on some platforms after 'boot time'.
 	 */
-	SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON);
 	SK_IN16(IoC, PCI_C(PCI_STATUS), &Word);
+	
+	SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON);
 	SK_OUT16(IoC, PCI_C(PCI_STATUS), Word | PCI_ERRBITS);
 	SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
 
 	/* Do the reset, all LEDs are switched off now */
 	SK_OUT8(IoC, B0_CTST, CS_RST_SET);
-}	/* SkGeDeInit*/
+}	/* SkGeDeInit */
 
 
 /******************************************************************************
  *
- *	SkGeInitPort()	Initialize the specified prot.
+ *	SkGeInitPort()	Initialize the specified port.
  *
  * Description:
  *	PRxQSize, PXSQSize, and PXAQSize has to be
- *	configured for the specified port before calling this
- *	function. The descriptor rings has to be initialized, too.
+ *	configured for the specified port before calling this function.
+ *  The descriptor rings has to be initialized too.
  *
  *	o (Re)configure queues of the specified port.
- *	o configure the XMAC of the specified port.
- *	o put ASIC and XMAC(s) in operational mode.
+ *	o configure the MAC of the specified port.
+ *	o put ASIC and MAC(s) in operational mode.
  *	o initialize Rx/Tx and Sync LED
  *	o initialize RAM Buffers and MAC FIFOs
  *
  *	The port is ready to connect when returning.
  *
  * Note:
- *	The XMACs Rx and Tx state machine is still disabled when
- *	returning.
+ *	The MAC's Rx and Tx state machine is still disabled when returning.
  *
  * Returns:
  *	0:	success
@@ -1936,45 +2253,48 @@
 
 	if (SkGeCheckQSize(pAC, Port) != 0) {
 		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E004, SKERR_HWI_E004MSG);
-		return (1);
+		return(1);
 	}
+	
 	if (pPrt->PState == SK_PRT_INIT || pPrt->PState == SK_PRT_RUN) {
 		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E005, SKERR_HWI_E005MSG);
-		return (2);
+		return(2);
 	}
 
 	/* Configuration ok, initialize the Port now */
 
-	/* Initialize Rx, Tx and Link LED */
-	/*
-	 * If 1000BT Phy needs LED initialization than swap
-	 * LED and XMAC initialization order
-	 */
- 	SkGeXmitLED(pAC, IoC, MR_ADDR(Port, TX_LED_INI), SK_LED_ENA);
- 	SkGeXmitLED(pAC, IoC, MR_ADDR(Port, RX_LED_INI), SK_LED_ENA);
-	/* The Link LED is initialized by RLMT or Diagnostics itself */ 
+	if (pAC->GIni.GIGenesis) {
+		/* Initialize Rx, Tx and Link LED */
+		/*
+		 * If 1000BT Phy needs LED initialization than swap
+		 * LED and XMAC initialization order
+		 */
+		SkGeXmitLED(pAC, IoC, MR_ADDR(Port, TX_LED_INI), SK_LED_ENA);
+		SkGeXmitLED(pAC, IoC, MR_ADDR(Port, RX_LED_INI), SK_LED_ENA);
+		/* The Link LED is initialized by RLMT or Diagnostics itself */
+		
+		SkXmInitMac(pAC, IoC, Port);
+	}
+	else {
 
+		SkGmInitMac(pAC, IoC, Port);
+	}
+	
 	/* Do NOT initialize the Link Sync Counter */
 
-	/*
-	 * Configure
-	 *	- XMAC
-	 *	- MAC FIFOs
-	 *	- RAM Buffers
-	 *	- enable Force Sync bit if synchronous queue available
-	 *	- BMUs
-	 */
-	SkXmInitMac(pAC, IoC, Port);
 	SkGeInitMacFifo(pAC, IoC, Port);
+	
 	SkGeInitRamBufs(pAC, IoC, Port);
+	
 	if (pPrt->PXSQSize != 0) {
+		/* enable Force Sync bit if synchronous queue available */
 		SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL), TXA_ENA_FSYNC);
 	}
+	
 	SkGeInitBmu(pAC, IoC, Port);
 
-	/* Mark port as initialized. */
+	/* Mark port as initialized */
 	pPrt->PState = SK_PRT_INIT;
-	pAC->GIni.GIAnyPortAct = SK_TRUE;
 
-	return (0);
+	return(0);
 }	/* SkGeInitPort */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sk98lin/skgemib.c linux-2.4.21-pre6/drivers/net/sk98lin/skgemib.c
--- linux-2.4.20/drivers/net/sk98lin/skgemib.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sk98lin/skgemib.c	2003-03-26 23:49:27.000000000 +0000
@@ -0,0 +1,1056 @@
+/*****************************************************************************
+ *
+ * Name:	skgemib.c
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.7 $
+ * Date:	$Date: 2002/12/16 09:04:34 $
+ * Purpose:	Private Network Management Interface Management Database
+ *
+ ****************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 2002 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.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+ *
+ * History:
+ *
+ *	$Log: skgemib.c,v $
+ *	Revision 1.7  2002/12/16 09:04:34  tschilli
+ *	Code for VCT handling added.
+ *	
+ *	Revision 1.6  2002/08/09 15:40:21  rwahl
+ *	Editorial change (renamed ConfSpeedCap).
+ *	
+ *	Revision 1.5  2002/08/09 11:05:34  rwahl
+ *	Added oid handling for link speed cap.
+ *	
+ *	Revision 1.4  2002/08/09 09:40:27  rwahl
+ *	Added support for NDIS OID_PNP_xxx.
+ *	
+ *	Revision 1.3  2002/07/17 19:39:54  rwahl
+ *	Added handler for OID_SKGE_SPEED_MODE & OID_SKGE_SPEED_STATUS.
+ *	
+ *	Revision 1.2  2002/05/22 08:59:00  rwahl
+ *	- static functions only for release build.
+ *	- Source file must be included.
+ *	
+ *	Revision 1.1  2002/05/22 08:12:42  rwahl
+ *	Initial version.
+ *	
+ ****************************************************************************/
+
+/*
+ * PRIVATE OID handler function prototypes
+ */
+PNMI_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, SK_U32 NetIndex);
+PNMI_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, SK_U32 NetIndex);
+PNMI_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, SK_U32 NetIndex);
+PNMI_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, SK_U32 NetIndex);
+PNMI_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, SK_U32 NetIndex);
+PNMI_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, SK_U32 NetIndex);
+PNMI_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, SK_U32 NetIndex);
+PNMI_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, SK_U32 NetIndex);
+PNMI_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, SK_U32 NetIndex);
+PNMI_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, SK_U32 NetIndex);
+PNMI_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, SK_U32 NetIndex);
+PNMI_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, SK_U32 NetIndex);
+PNMI_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, SK_U32 NetIndex);
+PNMI_STATIC int Vct(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+	char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex, SK_U32 NetIndex);
+
+#ifdef SK_POWER_MGMT
+PNMI_STATIC int PowerManagement(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+	char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex, SK_U32 NetIndex);
+#endif
+
+
+
+/* defines *******************************************************************/
+#define ID_TABLE_SIZE (sizeof(IdTable)/sizeof(IdTable[0]))
+
+
+/* global variables **********************************************************/
+
+/*
+ * Table to correlate OID with handler function and index to
+ * hardware register stored in StatAddress if applicable.
+ */
+PNMI_STATIC const SK_PNMI_TAB_ENTRY IdTable[] = {
+	{OID_GEN_XMIT_OK,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX},
+	{OID_GEN_RCV_OK,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX},
+	{OID_GEN_XMIT_ERROR,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, General, 0},
+	{OID_GEN_RCV_ERROR,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, General, 0},
+	{OID_GEN_RCV_NO_BUFFER,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, General, 0},
+	{OID_GEN_DIRECTED_FRAMES_XMIT,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_UNICAST},
+	{OID_GEN_MULTICAST_FRAMES_XMIT,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_MULTICAST},
+	{OID_GEN_BROADCAST_FRAMES_XMIT,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_BROADCAST},
+	{OID_GEN_DIRECTED_FRAMES_RCV,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_UNICAST},
+	{OID_GEN_MULTICAST_FRAMES_RCV,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_MULTICAST},
+	{OID_GEN_BROADCAST_FRAMES_RCV,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_BROADCAST},
+	{OID_GEN_RCV_CRC_ERROR,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_FCS},
+	{OID_GEN_TRANSMIT_QUEUE_LENGTH,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, General, 0},
+	{OID_802_3_PERMANENT_ADDRESS,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, 0},
+	{OID_802_3_CURRENT_ADDRESS,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, 0},
+	{OID_802_3_RCV_ERROR_ALIGNMENT,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_FRAMING},
+	{OID_802_3_XMIT_ONE_COLLISION,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_SINGLE_COL},
+	{OID_802_3_XMIT_MORE_COLLISIONS,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_MULTI_COL},
+	{OID_802_3_XMIT_DEFERRED,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_DEFFERAL},
+	{OID_802_3_XMIT_MAX_COLLISIONS,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_EXCESS_COL},
+	{OID_802_3_RCV_OVERRUN,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_OVERFLOW},
+	{OID_802_3_XMIT_UNDERRUN,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_UNDERRUN},
+	{OID_802_3_XMIT_TIMES_CRS_LOST,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_CARRIER},
+	{OID_802_3_XMIT_LATE_COLLISIONS,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_LATE_COL},
+#ifdef SK_POWER_MGMT
+	{OID_PNP_CAPABILITIES,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, PowerManagement, 0},
+	{OID_PNP_SET_POWER,
+		0,
+		0,
+		0,
+		SK_PNMI_WO, PowerManagement, 0},
+	{OID_PNP_QUERY_POWER,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, PowerManagement, 0},
+	{OID_PNP_ADD_WAKE_UP_PATTERN,
+		0,
+		0,
+		0,
+		SK_PNMI_WO, PowerManagement, 0},
+	{OID_PNP_REMOVE_WAKE_UP_PATTERN,
+		0,
+		0,
+		0,
+		SK_PNMI_WO, PowerManagement, 0},
+	{OID_PNP_ENABLE_WAKE_UP,
+		0,
+		0,
+		0,
+		SK_PNMI_RW, PowerManagement, 0},
+#endif /* SK_POWER_MGMT */
+	{OID_SKGE_MDB_VERSION,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(MgmtDBVersion),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_SUPPORTED_LIST,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_ALL_DATA,
+		0,
+		0,
+		0,
+		SK_PNMI_RW, OidStruct, 0},
+	{OID_SKGE_VPD_FREE_BYTES,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(VpdFreeBytes),
+		SK_PNMI_RO, Vpd, 0},
+	{OID_SKGE_VPD_ENTRIES_LIST,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(VpdEntriesList),
+		SK_PNMI_RO, Vpd, 0},
+	{OID_SKGE_VPD_ENTRIES_NUMBER,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(VpdEntriesNumber),
+		SK_PNMI_RO, Vpd, 0},
+	{OID_SKGE_VPD_KEY,
+		SK_PNMI_VPD_ENTRIES,
+		sizeof(SK_PNMI_VPD),
+		SK_PNMI_OFF(Vpd) + SK_PNMI_VPD_OFF(VpdKey),
+		SK_PNMI_RO, Vpd, 0},
+	{OID_SKGE_VPD_VALUE,
+		SK_PNMI_VPD_ENTRIES,
+		sizeof(SK_PNMI_VPD),
+		SK_PNMI_OFF(Vpd) + SK_PNMI_VPD_OFF(VpdValue),
+		SK_PNMI_RO, Vpd, 0},
+	{OID_SKGE_VPD_ACCESS,
+		SK_PNMI_VPD_ENTRIES,
+		sizeof(SK_PNMI_VPD),
+		SK_PNMI_OFF(Vpd) + SK_PNMI_VPD_OFF(VpdAccess),
+		SK_PNMI_RO, Vpd, 0},
+	{OID_SKGE_VPD_ACTION,
+		SK_PNMI_VPD_ENTRIES,
+		sizeof(SK_PNMI_VPD),
+		SK_PNMI_OFF(Vpd) + SK_PNMI_VPD_OFF(VpdAction),
+		SK_PNMI_RW, Vpd, 0},
+	{OID_SKGE_PORT_NUMBER,		
+		1,
+		0,
+		SK_PNMI_MAI_OFF(PortNumber),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_DEVICE_TYPE,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(DeviceType),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_DRIVER_DESCR,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(DriverDescr),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_DRIVER_VERSION,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(DriverVersion),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_HW_DESCR,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(HwDescr),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_HW_VERSION,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(HwVersion),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_CHIPSET,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(Chipset),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_ACTION,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(Action),
+		SK_PNMI_RW, Perform, 0},
+	{OID_SKGE_RESULT,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(TestResult),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_BUS_TYPE,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(BusType),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_BUS_SPEED,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(BusSpeed),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_BUS_WIDTH,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(BusWidth),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_TX_SW_QUEUE_LEN,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(TxSwQueueLen),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_TX_SW_QUEUE_MAX,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(TxSwQueueMax),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_TX_RETRY,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(TxRetryCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_RX_INTR_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RxIntrCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_TX_INTR_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(TxIntrCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_RX_NO_BUF_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RxNoBufCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_TX_NO_BUF_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(TxNoBufCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_TX_USED_DESCR_NO,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(TxUsedDescrNo),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_RX_DELIVERED_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RxDeliveredCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_RX_OCTETS_DELIV_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RxOctetsDeliveredCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_RX_HW_ERROR_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RxHwErrorsCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_TX_HW_ERROR_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(TxHwErrorsCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_IN_ERRORS_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(InErrorsCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_OUT_ERROR_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(OutErrorsCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_ERR_RECOVERY_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(ErrRecoveryCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_SYSUPTIME,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(SysUpTime),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_SENSOR_NUMBER,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(SensorNumber),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_SENSOR_INDEX,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorIndex),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_DESCR,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorDescr),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_TYPE,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorType),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_VALUE,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorValue),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_WAR_THRES_LOW,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorWarningThresholdLow),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_WAR_THRES_UPP,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorWarningThresholdHigh),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_ERR_THRES_LOW,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorErrorThresholdLow),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_ERR_THRES_UPP,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorErrorThresholdHigh),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_STATUS,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorStatus),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_WAR_CTS,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorWarningCts),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_ERR_CTS,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorErrorCts),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_WAR_TIME,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorWarningTimestamp),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_ERR_TIME,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorErrorTimestamp),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_CHKSM_NUMBER,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(ChecksumNumber),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_CHKSM_RX_OK_CTS,
+		SKCS_NUM_PROTOCOLS,
+		sizeof(SK_PNMI_CHECKSUM),
+		SK_PNMI_OFF(Checksum) + SK_PNMI_CHK_OFF(ChecksumRxOkCts),
+		SK_PNMI_RO, CsumStat, 0},
+	{OID_SKGE_CHKSM_RX_UNABLE_CTS,
+		SKCS_NUM_PROTOCOLS,
+		sizeof(SK_PNMI_CHECKSUM),
+		SK_PNMI_OFF(Checksum) + SK_PNMI_CHK_OFF(ChecksumRxUnableCts),
+		SK_PNMI_RO, CsumStat, 0},
+	{OID_SKGE_CHKSM_RX_ERR_CTS,
+		SKCS_NUM_PROTOCOLS,
+		sizeof(SK_PNMI_CHECKSUM),
+		SK_PNMI_OFF(Checksum) + SK_PNMI_CHK_OFF(ChecksumRxErrCts),
+		SK_PNMI_RO, CsumStat, 0},
+	{OID_SKGE_CHKSM_TX_OK_CTS,
+		SKCS_NUM_PROTOCOLS,
+		sizeof(SK_PNMI_CHECKSUM),
+		SK_PNMI_OFF(Checksum) + SK_PNMI_CHK_OFF(ChecksumTxOkCts),
+		SK_PNMI_RO, CsumStat, 0},
+	{OID_SKGE_CHKSM_TX_UNABLE_CTS,
+		SKCS_NUM_PROTOCOLS,
+		sizeof(SK_PNMI_CHECKSUM),
+		SK_PNMI_OFF(Checksum) + SK_PNMI_CHK_OFF(ChecksumTxUnableCts),
+		SK_PNMI_RO, CsumStat, 0},
+	{OID_SKGE_STAT_TX,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxOkCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX},
+	{OID_SKGE_STAT_TX_OCTETS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxOctetsOkCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_OCTET},
+	{OID_SKGE_STAT_TX_BROADCAST,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxBroadcastOkCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_BROADCAST},
+	{OID_SKGE_STAT_TX_MULTICAST,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxMulticastOkCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_MULTICAST},
+	{OID_SKGE_STAT_TX_UNICAST,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxUnicastOkCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_UNICAST},
+	{OID_SKGE_STAT_TX_LONGFRAMES,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxLongFramesCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_LONGFRAMES},
+	{OID_SKGE_STAT_TX_BURST,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxBurstCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_BURST},
+	{OID_SKGE_STAT_TX_PFLOWC,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxPauseMacCtrlCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_PMACC},
+	{OID_SKGE_STAT_TX_FLOWC,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxMacCtrlCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_MACC},
+	{OID_SKGE_STAT_TX_SINGLE_COL,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxSingleCollisionCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_SINGLE_COL},
+	{OID_SKGE_STAT_TX_MULTI_COL,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxMultipleCollisionCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_MULTI_COL},
+	{OID_SKGE_STAT_TX_EXCESS_COL,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxExcessiveCollisionCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_EXCESS_COL},
+	{OID_SKGE_STAT_TX_LATE_COL,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxLateCollisionCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_LATE_COL},
+	{OID_SKGE_STAT_TX_DEFFERAL,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxDeferralCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_DEFFERAL},
+	{OID_SKGE_STAT_TX_EXCESS_DEF,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxExcessiveDeferralCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_EXCESS_DEF},
+	{OID_SKGE_STAT_TX_UNDERRUN,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxFifoUnderrunCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_UNDERRUN},
+	{OID_SKGE_STAT_TX_CARRIER,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxCarrierCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_CARRIER},
+/*	{OID_SKGE_STAT_TX_UTIL,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxUtilization),
+		SK_PNMI_RO, MacPrivateStat, (SK_U16)(-1)}, */
+	{OID_SKGE_STAT_TX_64,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTx64Cts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_64},
+	{OID_SKGE_STAT_TX_127,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTx127Cts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_127},
+	{OID_SKGE_STAT_TX_255,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTx255Cts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_255},
+	{OID_SKGE_STAT_TX_511,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTx511Cts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_511},
+	{OID_SKGE_STAT_TX_1023,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTx1023Cts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_1023},
+	{OID_SKGE_STAT_TX_MAX,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxMaxCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_MAX},
+	{OID_SKGE_STAT_TX_SYNC,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxSyncCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_SYNC},
+	{OID_SKGE_STAT_TX_SYNC_OCTETS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxSyncOctetsCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_SYNC_OCTET},
+	{OID_SKGE_STAT_RX,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxOkCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX},
+	{OID_SKGE_STAT_RX_OCTETS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxOctetsOkCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_OCTET},
+	{OID_SKGE_STAT_RX_BROADCAST,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxBroadcastOkCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_BROADCAST},
+	{OID_SKGE_STAT_RX_MULTICAST,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxMulticastOkCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_MULTICAST},
+	{OID_SKGE_STAT_RX_UNICAST,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxUnicastOkCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_UNICAST},
+	{OID_SKGE_STAT_RX_LONGFRAMES,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxLongFramesCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_LONGFRAMES},
+	{OID_SKGE_STAT_RX_PFLOWC,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxPauseMacCtrlCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_PMACC},
+	{OID_SKGE_STAT_RX_FLOWC,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxMacCtrlCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_MACC},
+	{OID_SKGE_STAT_RX_PFLOWC_ERR,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxPauseMacCtrlErrorCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_PMACC_ERR},
+	{OID_SKGE_STAT_RX_FLOWC_UNKWN,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxMacCtrlUnknownCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_MACC_UNKWN},
+	{OID_SKGE_STAT_RX_BURST,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxBurstCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_BURST},
+	{OID_SKGE_STAT_RX_MISSED,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxMissedCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_MISSED},
+	{OID_SKGE_STAT_RX_FRAMING,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxFramingCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_FRAMING},
+	{OID_SKGE_STAT_RX_OVERFLOW,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxFifoOverflowCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_OVERFLOW},
+	{OID_SKGE_STAT_RX_JABBER,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxJabberCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_JABBER},
+	{OID_SKGE_STAT_RX_CARRIER,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxCarrierCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_CARRIER},
+	{OID_SKGE_STAT_RX_IR_LENGTH,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxIRLengthCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_IRLENGTH},
+	{OID_SKGE_STAT_RX_SYMBOL,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxSymbolCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_SYMBOL},
+	{OID_SKGE_STAT_RX_SHORTS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxShortsCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_SHORTS},
+	{OID_SKGE_STAT_RX_RUNT,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxRuntCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_RUNT},
+	{OID_SKGE_STAT_RX_CEXT,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxCextCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_CEXT},
+	{OID_SKGE_STAT_RX_TOO_LONG,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxTooLongCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_TOO_LONG},
+	{OID_SKGE_STAT_RX_FCS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxFcsCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_FCS},
+/*	{OID_SKGE_STAT_RX_UTIL,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxUtilization),
+		SK_PNMI_RO, MacPrivateStat, (SK_U16)(-1)}, */
+	{OID_SKGE_STAT_RX_64,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRx64Cts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_64},
+	{OID_SKGE_STAT_RX_127,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRx127Cts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_127},
+	{OID_SKGE_STAT_RX_255,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRx255Cts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_255},
+	{OID_SKGE_STAT_RX_511,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRx511Cts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_511},
+	{OID_SKGE_STAT_RX_1023,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRx1023Cts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_1023},
+	{OID_SKGE_STAT_RX_MAX,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxMaxCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_MAX},
+	{OID_SKGE_PHYS_CUR_ADDR,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfMacCurrentAddr),
+		SK_PNMI_RW, Addr, 0},
+	{OID_SKGE_PHYS_FAC_ADDR,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfMacFactoryAddr),
+		SK_PNMI_RO, Addr, 0},
+	{OID_SKGE_PMD,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPMD),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_CONNECTOR,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfConnector),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_LINK_CAP,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfLinkCapability),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_LINK_MODE,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfLinkMode),
+		SK_PNMI_RW, MacPrivateConf, 0},
+	{OID_SKGE_LINK_MODE_STATUS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfLinkModeStatus),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_LINK_STATUS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfLinkStatus),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_FLOWCTRL_CAP,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfFlowCtrlCapability),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_FLOWCTRL_MODE,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfFlowCtrlMode),
+		SK_PNMI_RW, MacPrivateConf, 0},
+	{OID_SKGE_FLOWCTRL_STATUS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfFlowCtrlStatus),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_PHY_OPERATION_CAP,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPhyOperationCapability),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_PHY_OPERATION_MODE,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPhyOperationMode),
+		SK_PNMI_RW, MacPrivateConf, 0},
+	{OID_SKGE_PHY_OPERATION_STATUS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPhyOperationStatus),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_SPEED_CAP,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfSpeedCapability),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_SPEED_MODE,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfSpeedMode),
+		SK_PNMI_RW, MacPrivateConf, 0},
+	{OID_SKGE_SPEED_STATUS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfSpeedStatus),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_TRAP,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(Trap),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_TRAP_NUMBER,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(TrapNumber),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_RLMT_MODE,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RlmtMode),
+		SK_PNMI_RW, Rlmt, 0},
+	{OID_SKGE_RLMT_PORT_NUMBER,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RlmtPortNumber),
+		SK_PNMI_RO, Rlmt, 0},
+	{OID_SKGE_RLMT_PORT_ACTIVE,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RlmtPortActive),
+		SK_PNMI_RO, Rlmt, 0},
+	{OID_SKGE_RLMT_PORT_PREFERRED,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RlmtPortPreferred),
+		SK_PNMI_RW, Rlmt, 0},
+	{OID_SKGE_RLMT_CHANGE_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RlmtChangeCts),
+		SK_PNMI_RO, Rlmt, 0},
+	{OID_SKGE_RLMT_CHANGE_TIME,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RlmtChangeTime),
+		SK_PNMI_RO, Rlmt, 0},
+	{OID_SKGE_RLMT_CHANGE_ESTIM,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RlmtChangeEstimate),
+		SK_PNMI_RO, Rlmt, 0},
+	{OID_SKGE_RLMT_CHANGE_THRES,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RlmtChangeThreshold),
+		SK_PNMI_RW, Rlmt, 0},
+	{OID_SKGE_RLMT_PORT_INDEX,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_RLMT),
+		SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtIndex),
+		SK_PNMI_RO, RlmtStat, 0},
+	{OID_SKGE_RLMT_STATUS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_RLMT),
+		SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtStatus),
+		SK_PNMI_RO, RlmtStat, 0},
+	{OID_SKGE_RLMT_TX_HELLO_CTS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_RLMT),
+		SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtTxHelloCts),
+		SK_PNMI_RO, RlmtStat, 0},
+	{OID_SKGE_RLMT_RX_HELLO_CTS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_RLMT),
+		SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtRxHelloCts),
+		SK_PNMI_RO, RlmtStat, 0},
+	{OID_SKGE_RLMT_TX_SP_REQ_CTS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_RLMT),
+		SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtTxSpHelloReqCts),
+		SK_PNMI_RO, RlmtStat, 0},
+	{OID_SKGE_RLMT_RX_SP_CTS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_RLMT),
+		SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtRxSpHelloCts),
+		SK_PNMI_RO, RlmtStat, 0},
+	{OID_SKGE_RLMT_MONITOR_NUMBER,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RlmtMonitorNumber),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_RLMT_MONITOR_INDEX,
+		SK_PNMI_MONITOR_ENTRIES,
+		sizeof(SK_PNMI_RLMT_MONITOR),
+		SK_PNMI_OFF(RlmtMonitor) + SK_PNMI_MON_OFF(RlmtMonitorIndex),
+		SK_PNMI_RO, Monitor, 0},
+	{OID_SKGE_RLMT_MONITOR_ADDR,
+		SK_PNMI_MONITOR_ENTRIES,
+		sizeof(SK_PNMI_RLMT_MONITOR),
+		SK_PNMI_OFF(RlmtMonitor) + SK_PNMI_MON_OFF(RlmtMonitorAddr),
+		SK_PNMI_RO, Monitor, 0},
+	{OID_SKGE_RLMT_MONITOR_ERRS,
+		SK_PNMI_MONITOR_ENTRIES,
+		sizeof(SK_PNMI_RLMT_MONITOR),
+		SK_PNMI_OFF(RlmtMonitor) + SK_PNMI_MON_OFF(RlmtMonitorErrorCts),
+		SK_PNMI_RO, Monitor, 0},
+	{OID_SKGE_RLMT_MONITOR_TIMESTAMP,
+		SK_PNMI_MONITOR_ENTRIES,
+		sizeof(SK_PNMI_RLMT_MONITOR),
+		SK_PNMI_OFF(RlmtMonitor) + SK_PNMI_MON_OFF(RlmtMonitorTimestamp),
+		SK_PNMI_RO, Monitor, 0},
+	{OID_SKGE_RLMT_MONITOR_ADMIN,
+		SK_PNMI_MONITOR_ENTRIES,
+		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},
+	{OID_SKGE_VCT_GET,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Vct, 0},
+	{OID_SKGE_VCT_SET,
+		0,
+		0,
+		0,
+		SK_PNMI_WO, Vct, 0},
+	{OID_SKGE_VCT_STATUS,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Vct, 0},
+};
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sk98lin/skgepnmi.c linux-2.4.21-pre6/drivers/net/sk98lin/skgepnmi.c
--- linux-2.4.20/drivers/net/sk98lin/skgepnmi.c	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sk98lin/skgepnmi.c	2003-03-26 23:49:50.000000000 +0000
@@ -2,15 +2,15 @@
  *
  * Name:	skgepnmi.c
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.87 $
- * Date:	$Date: 2001/04/06 13:35:09 $
+ * Version:	$Revision: 1.102 $
+ * Date:	$Date: 2002/12/16 14:03:24 $
  * Purpose:	Private Network Management Interface
  *
  ****************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998-2001 SysKonnect GmbH.
+ *	(C)Copyright 1998-2002 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 +26,78 @@
  * History:
  *
  *	$Log: skgepnmi.c,v $
+ *	Revision 1.102  2002/12/16 14:03:24  tschilli
+ *	VCT code in Vct() changed.
+ *	
+ *	Revision 1.101  2002/12/16 09:04:10  tschilli
+ *	Code for VCT handling added.
+ *	
+ *	Revision 1.100  2002/09/26 14:28:13  tschilli
+ *	For XMAC the values in the SK_PNMI_PORT Port struct are copied to
+ *	the new SK_PNMI_PORT BufPort struct during a MacUpdate() call.
+ *	These values are used when GetPhysStatVal() is called. With this
+ *	mechanism you get the best results when software corrections for
+ *	counters are needed. Example: RX_LONGFRAMES.
+ *	
+ *	Revision 1.99  2002/09/17 12:31:19  tschilli
+ *	OID_SKGE_TX_HW_ERROR_CTS, OID_SKGE_OUT_ERROR_CTS, OID_GEN_XMIT_ERROR:
+ *	Double count of SK_PNMI_HTX_EXCESS_COL in function General() removed.
+ *	OID_PNP_CAPABILITIES: sizeof(SK_PM_WAKE_UP_CAPABILITIES) changed to
+ *	sizeof(SK_PNP_CAPABILITIES) in function PowerManagement().
+ *	
+ *	Revision 1.98  2002/09/10 09:00:03  rwahl
+ *	Adapted boolean definitions according sktypes.
+ *	
+ *	Revision 1.97  2002/09/05 15:07:03  rwahl
+ *	Editorial changes.
+ *	
+ *	Revision 1.96  2002/09/05 11:04:14  rwahl
+ *	- Rx/Tx packets statistics of virtual port were zero on link down (#10750)
+ *	- For GMAC the overflow IRQ for Rx longframe counter was not counted.
+ *	- Incorrect calculation for oids OID_SKGE_RX_HW_ERROR_CTS,
+ *	  OID_SKGE_IN_ERRORS_CTS,  OID_GEN_RCV_ERROR.
+ *	- Moved correction for OID_SKGE_STAT_RX_TOO_LONG to GetPhysStatVal().
+ *	- Editorial changes.
+ *	
+ *	Revision 1.95  2002/09/04 08:53:37  rwahl
+ *	- Incorrect statistics for Rx_too_long counter with jumbo frame (#10751)
+ *	- StatRxFrameTooLong & StatRxPMaccErr counters were not reset.
+ *	- Fixed compiler warning for debug msg arg types.
+ *	
+ *	Revision 1.94  2002/08/09 15:42:14  rwahl
+ *	- Fixed StatAddr table for GMAC.
+ *	- VirtualConf(): returned indeterminated status for speed oids if no
+ *	  active port.
+ *	
+ *	Revision 1.93  2002/08/09 11:04:59  rwahl
+ *	Added handler for link speed caps.
+ *	
+ *	Revision 1.92  2002/08/09 09:43:03  rwahl
+ *	- Added handler for NDIS OID_PNP_xxx ids.
+ *	
+ *	Revision 1.91  2002/07/17 19:53:03  rwahl
+ *	- Added StatOvrflwBit table for XMAC & GMAC.
+ *	- Extended StatAddr table for GMAC. Added check of number of counters
+ *	  in enumeration and size of StatAddr table on init level.
+ *	- Added use of GIFunc table.
+ *	- ChipSet is not static anymore,
+ *	- Extended SIRQ event handler for both mac types.
+ *	- Fixed rx short counter bug (#10620)
+ *	- Added handler for oids SKGE_SPEED_MODE & SKGE_SPEED_STATUS.
+ *	- Extendet GetPhysStatVal() for GMAC.
+ *	- Editorial changes.
+ *	
+ *	Revision 1.90  2002/05/22 08:56:25  rwahl
+ *	- Moved OID table to separate source file.
+ *	- Fix: TX_DEFFERAL counter incremented in full-duplex mode.
+ *	- Use string definitions for error msgs.
+ *	
+ *	Revision 1.89  2001/09/18 10:01:30  mkunz
+ *	some OID's fixed for dualnetmode
+ *	
+ *	Revision 1.88  2001/08/02 07:58:08  rwahl
+ *	- Fixed NetIndex to csum module at ResetCounter().
+ *	
  *	Revision 1.87  2001/04/06 13:35:09  mkunz
  *	-Bugs fixed in handling of OID_SKGE_MTU and the VPD OID's
  *	
@@ -37,7 +109,6 @@
  *	
  *	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
@@ -362,13 +433,12 @@
 
 
 static const char SysKonnectFileId[] =
-	"@(#) $Id: skgepnmi.c,v 1.87 2001/04/06 13:35:09 mkunz Exp $"
+	"@(#) $Id: skgepnmi.c,v 1.102 2002/12/16 14:03:24 tschilli Exp $"
 	" (C) SysKonnect.";
 
 #include "h/skdrv1st.h"
 #include "h/sktypes.h"
 #include "h/xmac_ii.h"
-
 #include "h/skdebug.h"
 #include "h/skqueue.h"
 #include "h/skgepnmi.h"
@@ -379,7 +449,16 @@
 #include "h/skgeinit.h"
 #include "h/skdrv2nd.h"
 #include "h/skgepnm2.h"
+#ifdef SK_POWER_MGMT
+#include "h/skgepmgt.h"
+#endif
+/* defines *******************************************************************/
 
+#ifndef DEBUG
+#define PNMI_STATIC	static
+#else	/* DEBUG */
+#define PNMI_STATIC
+#endif /* DEBUG */
 
 /*
  * Public Function prototypes
@@ -403,1037 +482,259 @@
 /*
  * Private Function prototypes
  */
-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, SK_U32 NetIndex);
-static SK_U8 CalculateLinkModeStatus(SK_AC *pAC, SK_IOC IoC, unsigned int
+
+PNMI_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
+PNMI_STATIC SK_U8 CalculateLinkStatus(SK_AC *pAC, SK_IOC IoC, unsigned int
 	PhysPortIndex);
-static void CopyMac(char *pDst, SK_MAC_ADDR *pMac);
-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, 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, SK_U32 NetIndex);
-static SK_U64 GetPhysStatVal(SK_AC *pAC, SK_IOC IoC,
+PNMI_STATIC void CopyMac(char *pDst, SK_MAC_ADDR *pMac);
+PNMI_STATIC void CopyTrapQueue(SK_AC *pAC, char *pDstBuf);
+PNMI_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,
+PNMI_STATIC SK_U64 GetStatVal(SK_AC *pAC, SK_IOC IoC, unsigned int LogPortIndex,
 	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,
+PNMI_STATIC char* GetTrapEntry(SK_AC *pAC, SK_U32 TrapId, unsigned int Size);
+PNMI_STATIC void GetTrapQueueLen(SK_AC *pAC, unsigned int *pLen,
 	unsigned int *pEntries);
-static int GetVpdKeyArr(SK_AC *pAC, SK_IOC IoC, char *pKeyArr,
+PNMI_STATIC int GetVpdKeyArr(SK_AC *pAC, SK_IOC IoC, char *pKeyArr,
 	unsigned int KeyArrLen, unsigned int *pKeyNo);
-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, 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, 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, SK_U32 NetIndex);
-static int MacUpdate(SK_AC *pAC, SK_IOC IoC, unsigned int FirstMac,
+PNMI_STATIC int LookupId(SK_U32 Id);
+PNMI_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, 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, 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, SK_U32 NetIndex);
-static int PnmiStruct(SK_AC *pAC, SK_IOC IoC, int Action, char *pBuf,
+PNMI_STATIC int PnmiStruct(SK_AC *pAC, SK_IOC IoC, int Action, char *pBuf,
 	unsigned int *pLen, SK_U32 NetIndex);
-static int PnmiVar(SK_AC *pAC, SK_IOC IoC, int Action, SK_U32 Id,
+PNMI_STATIC int PnmiVar(SK_AC *pAC, SK_IOC IoC, int Action, SK_U32 Id,
 	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,
+PNMI_STATIC void QueueRlmtNewMacTrap(SK_AC *pAC, unsigned int ActiveMac);
+PNMI_STATIC void QueueRlmtPortTrap(SK_AC *pAC, SK_U32 TrapId,
 	unsigned int PortIndex);
-static void QueueSensorTrap(SK_AC *pAC, SK_U32 TrapId,
+PNMI_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, 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, 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, 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, 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, SK_U32 NetIndex);
-
-
-/******************************************************************************
- *
- * Global variables
- */
+PNMI_STATIC void QueueSimpleTrap(SK_AC *pAC, SK_U32 TrapId);
+PNMI_STATIC void ResetCounter(SK_AC *pAC, SK_IOC IoC, SK_U32 NetIndex);
+PNMI_STATIC int RlmtUpdate(SK_AC *pAC, SK_IOC IoC, SK_U32 NetIndex);
+PNMI_STATIC int SirqUpdate(SK_AC *pAC, SK_IOC IoC);
+PNMI_STATIC void VirtualConf(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, char *pBuf);
+PNMI_STATIC int Vct(SK_AC *pAC, SK_IOC IoC, int Action, SK_U32 Id, char *pBuf,
+	unsigned int *pLen, SK_U32 Instance, unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC void CheckVctStatus(SK_AC *, SK_IOC, char *, SK_U32, SK_U32);
 
 /*
  * Table to correlate OID with handler function and index to
  * hardware register stored in StatAddress if applicable.
  */
-static const SK_PNMI_TAB_ENTRY IdTable[] = {
-	{OID_GEN_XMIT_OK,
-		0,
-		0,
-		0,
-		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX},
-	{OID_GEN_RCV_OK,
-		0,
-		0,
-		0,
-		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX},
-	{OID_GEN_XMIT_ERROR,
-		0,
-		0,
-		0,
-		SK_PNMI_RO, General, 0},
-	{OID_GEN_RCV_ERROR,
-		0,
-		0,
-		0,
-		SK_PNMI_RO, General, 0},
-	{OID_GEN_RCV_NO_BUFFER,
-		0,
-		0,
-		0,
-		SK_PNMI_RO, General, 0},
-	{OID_GEN_DIRECTED_FRAMES_XMIT,
-		0,
-		0,
-		0,
-		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_UNICAST},
-	{OID_GEN_MULTICAST_FRAMES_XMIT,
-		0,
-		0,
-		0,
-		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_MULTICAST},
-	{OID_GEN_BROADCAST_FRAMES_XMIT,
-		0,
-		0,
-		0,
-		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_BROADCAST},
-	{OID_GEN_DIRECTED_FRAMES_RCV,
-		0,
-		0,
-		0,
-		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_UNICAST},
-	{OID_GEN_MULTICAST_FRAMES_RCV,
-		0,
-		0,
-		0,
-		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_MULTICAST},
-	{OID_GEN_BROADCAST_FRAMES_RCV,
-		0,
-		0,
-		0,
-		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_BROADCAST},
-	{OID_GEN_RCV_CRC_ERROR,
-		0,
-		0,
-		0,
-		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_FCS},
-	{OID_GEN_TRANSMIT_QUEUE_LENGTH,
-		0,
-		0,
-		0,
-		SK_PNMI_RO, General, 0},
-	{OID_802_3_PERMANENT_ADDRESS,
-		0,
-		0,
-		0,
-		SK_PNMI_RO, Mac8023Stat, 0},
-	{OID_802_3_CURRENT_ADDRESS,
-		0,
-		0,
-		0,
-		SK_PNMI_RO, Mac8023Stat, 0},
-	{OID_802_3_RCV_ERROR_ALIGNMENT,
-		0,
-		0,
-		0,
-		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_FRAMING},
-	{OID_802_3_XMIT_ONE_COLLISION,
-		0,
-		0,
-		0,
-		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_SINGLE_COL},
-	{OID_802_3_XMIT_MORE_COLLISIONS,
-		0,
-		0,
-		0,
-		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_MULTI_COL},
-	{OID_802_3_XMIT_DEFERRED,
-		0,
-		0,
-		0,
-		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_DEFFERAL},
-	{OID_802_3_XMIT_MAX_COLLISIONS,
-		0,
-		0,
-		0,
-		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_EXCESS_COL},
-	{OID_802_3_RCV_OVERRUN,
-		0,
-		0,
-		0,
-		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_OVERFLOW},
-	{OID_802_3_XMIT_UNDERRUN,
-		0,
-		0,
-		0,
-		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_UNDERRUN},
-	{OID_802_3_XMIT_TIMES_CRS_LOST,
-		0,
-		0,
-		0,
-		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_CARRIER},
-	{OID_802_3_XMIT_LATE_COLLISIONS,
-		0,
-		0,
-		0,
-		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_LATE_COL},
-	{OID_SKGE_MDB_VERSION,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(MgmtDBVersion),
-		SK_PNMI_RO, General, 0},
-	{OID_SKGE_SUPPORTED_LIST,
-		0,
-		0,
-		0,
-		SK_PNMI_RO, General, 0},
-	{OID_SKGE_ALL_DATA,
-		0,
-		0,
-		0,
-		SK_PNMI_RW, OidStruct, 0},
-	{OID_SKGE_VPD_FREE_BYTES,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(VpdFreeBytes),
-		SK_PNMI_RO, Vpd, 0},
-	{OID_SKGE_VPD_ENTRIES_LIST,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(VpdEntriesList),
-		SK_PNMI_RO, Vpd, 0},
-	{OID_SKGE_VPD_ENTRIES_NUMBER,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(VpdEntriesNumber),
-		SK_PNMI_RO, Vpd, 0},
-	{OID_SKGE_VPD_KEY,
-		SK_PNMI_VPD_ENTRIES,
-		sizeof(SK_PNMI_VPD),
-		SK_PNMI_OFF(Vpd) + SK_PNMI_VPD_OFF(VpdKey),
-		SK_PNMI_RO, Vpd, 0},
-	{OID_SKGE_VPD_VALUE,
-		SK_PNMI_VPD_ENTRIES,
-		sizeof(SK_PNMI_VPD),
-		SK_PNMI_OFF(Vpd) + SK_PNMI_VPD_OFF(VpdValue),
-		SK_PNMI_RO, Vpd, 0},
-	{OID_SKGE_VPD_ACCESS,
-		SK_PNMI_VPD_ENTRIES,
-		sizeof(SK_PNMI_VPD),
-		SK_PNMI_OFF(Vpd) + SK_PNMI_VPD_OFF(VpdAccess),
-		SK_PNMI_RO, Vpd, 0},
-	{OID_SKGE_VPD_ACTION,
-		SK_PNMI_VPD_ENTRIES,
-		sizeof(SK_PNMI_VPD),
-		SK_PNMI_OFF(Vpd) + SK_PNMI_VPD_OFF(VpdAction),
-		SK_PNMI_RW, Vpd, 0},
-	{OID_SKGE_PORT_NUMBER,		
-		1,
-		0,
-		SK_PNMI_MAI_OFF(PortNumber),
-		SK_PNMI_RO, General, 0},
-	{OID_SKGE_DEVICE_TYPE,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(DeviceType),
-		SK_PNMI_RO, General, 0},
-	{OID_SKGE_DRIVER_DESCR,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(DriverDescr),
-		SK_PNMI_RO, General, 0},
-	{OID_SKGE_DRIVER_VERSION,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(DriverVersion),
-		SK_PNMI_RO, General, 0},
-	{OID_SKGE_HW_DESCR,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(HwDescr),
-		SK_PNMI_RO, General, 0},
-	{OID_SKGE_HW_VERSION,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(HwVersion),
-		SK_PNMI_RO, General, 0},
-	{OID_SKGE_CHIPSET,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(Chipset),
-		SK_PNMI_RO, General, 0},
-	{OID_SKGE_ACTION,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(Action),
-		SK_PNMI_RW, Perform, 0},
-	{OID_SKGE_RESULT,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(TestResult),
-		SK_PNMI_RO, General, 0},
-	{OID_SKGE_BUS_TYPE,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(BusType),
-		SK_PNMI_RO, General, 0},
-	{OID_SKGE_BUS_SPEED,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(BusSpeed),
-		SK_PNMI_RO, General, 0},
-	{OID_SKGE_BUS_WIDTH,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(BusWidth),
-		SK_PNMI_RO, General, 0},
-	{OID_SKGE_TX_SW_QUEUE_LEN,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(TxSwQueueLen),
-		SK_PNMI_RO, General, 0},
-	{OID_SKGE_TX_SW_QUEUE_MAX,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(TxSwQueueMax),
-		SK_PNMI_RO, General, 0},
-	{OID_SKGE_TX_RETRY,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(TxRetryCts),
-		SK_PNMI_RO, General, 0},
-	{OID_SKGE_RX_INTR_CTS,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(RxIntrCts),
-		SK_PNMI_RO, General, 0},
-	{OID_SKGE_TX_INTR_CTS,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(TxIntrCts),
-		SK_PNMI_RO, General, 0},
-	{OID_SKGE_RX_NO_BUF_CTS,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(RxNoBufCts),
-		SK_PNMI_RO, General, 0},
-	{OID_SKGE_TX_NO_BUF_CTS,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(TxNoBufCts),
-		SK_PNMI_RO, General, 0},
-	{OID_SKGE_TX_USED_DESCR_NO,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(TxUsedDescrNo),
-		SK_PNMI_RO, General, 0},
-	{OID_SKGE_RX_DELIVERED_CTS,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(RxDeliveredCts),
-		SK_PNMI_RO, General, 0},
-	{OID_SKGE_RX_OCTETS_DELIV_CTS,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(RxOctetsDeliveredCts),
-		SK_PNMI_RO, General, 0},
-	{OID_SKGE_RX_HW_ERROR_CTS,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(RxHwErrorsCts),
-		SK_PNMI_RO, General, 0},
-	{OID_SKGE_TX_HW_ERROR_CTS,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(TxHwErrorsCts),
-		SK_PNMI_RO, General, 0},
-	{OID_SKGE_IN_ERRORS_CTS,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(InErrorsCts),
-		SK_PNMI_RO, General, 0},
-	{OID_SKGE_OUT_ERROR_CTS,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(OutErrorsCts),
-		SK_PNMI_RO, General, 0},
-	{OID_SKGE_ERR_RECOVERY_CTS,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(ErrRecoveryCts),
-		SK_PNMI_RO, General, 0},
-	{OID_SKGE_SYSUPTIME,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(SysUpTime),
-		SK_PNMI_RO, General, 0},
-	{OID_SKGE_SENSOR_NUMBER,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(SensorNumber),
-		SK_PNMI_RO, General, 0},
-	{OID_SKGE_SENSOR_INDEX,
-		SK_PNMI_SENSOR_ENTRIES,
-		sizeof(SK_PNMI_SENSOR),
-		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorIndex),
-		SK_PNMI_RO, SensorStat, 0},
-	{OID_SKGE_SENSOR_DESCR,
-		SK_PNMI_SENSOR_ENTRIES,
-		sizeof(SK_PNMI_SENSOR),
-		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorDescr),
-		SK_PNMI_RO, SensorStat, 0},
-	{OID_SKGE_SENSOR_TYPE,
-		SK_PNMI_SENSOR_ENTRIES,
-		sizeof(SK_PNMI_SENSOR),
-		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorType),
-		SK_PNMI_RO, SensorStat, 0},
-	{OID_SKGE_SENSOR_VALUE,
-		SK_PNMI_SENSOR_ENTRIES,
-		sizeof(SK_PNMI_SENSOR),
-		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorValue),
-		SK_PNMI_RO, SensorStat, 0},
-	{OID_SKGE_SENSOR_WAR_THRES_LOW,
-		SK_PNMI_SENSOR_ENTRIES,
-		sizeof(SK_PNMI_SENSOR),
-		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorWarningThresholdLow),
-		SK_PNMI_RO, SensorStat, 0},
-	{OID_SKGE_SENSOR_WAR_THRES_UPP,
-		SK_PNMI_SENSOR_ENTRIES,
-		sizeof(SK_PNMI_SENSOR),
-		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorWarningThresholdHigh),
-		SK_PNMI_RO, SensorStat, 0},
-	{OID_SKGE_SENSOR_ERR_THRES_LOW,
-		SK_PNMI_SENSOR_ENTRIES,
-		sizeof(SK_PNMI_SENSOR),
-		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorErrorThresholdLow),
-		SK_PNMI_RO, SensorStat, 0},
-	{OID_SKGE_SENSOR_ERR_THRES_UPP,
-		SK_PNMI_SENSOR_ENTRIES,
-		sizeof(SK_PNMI_SENSOR),
-		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorErrorThresholdHigh),
-		SK_PNMI_RO, SensorStat, 0},
-	{OID_SKGE_SENSOR_STATUS,
-		SK_PNMI_SENSOR_ENTRIES,
-		sizeof(SK_PNMI_SENSOR),
-		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorStatus),
-		SK_PNMI_RO, SensorStat, 0},
-	{OID_SKGE_SENSOR_WAR_CTS,
-		SK_PNMI_SENSOR_ENTRIES,
-		sizeof(SK_PNMI_SENSOR),
-		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorWarningCts),
-		SK_PNMI_RO, SensorStat, 0},
-	{OID_SKGE_SENSOR_ERR_CTS,
-		SK_PNMI_SENSOR_ENTRIES,
-		sizeof(SK_PNMI_SENSOR),
-		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorErrorCts),
-		SK_PNMI_RO, SensorStat, 0},
-	{OID_SKGE_SENSOR_WAR_TIME,
-		SK_PNMI_SENSOR_ENTRIES,
-		sizeof(SK_PNMI_SENSOR),
-		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorWarningTimestamp),
-		SK_PNMI_RO, SensorStat, 0},
-	{OID_SKGE_SENSOR_ERR_TIME,
-		SK_PNMI_SENSOR_ENTRIES,
-		sizeof(SK_PNMI_SENSOR),
-		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorErrorTimestamp),
-		SK_PNMI_RO, SensorStat, 0},
-	{OID_SKGE_CHKSM_NUMBER,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(ChecksumNumber),
-		SK_PNMI_RO, General, 0},
-	{OID_SKGE_CHKSM_RX_OK_CTS,
-		SKCS_NUM_PROTOCOLS,
-		sizeof(SK_PNMI_CHECKSUM),
-		SK_PNMI_OFF(Checksum) + SK_PNMI_CHK_OFF(ChecksumRxOkCts),
-		SK_PNMI_RO, CsumStat, 0},
-	{OID_SKGE_CHKSM_RX_UNABLE_CTS,
-		SKCS_NUM_PROTOCOLS,
-		sizeof(SK_PNMI_CHECKSUM),
-		SK_PNMI_OFF(Checksum) + SK_PNMI_CHK_OFF(ChecksumRxUnableCts),
-		SK_PNMI_RO, CsumStat, 0},
-	{OID_SKGE_CHKSM_RX_ERR_CTS,
-		SKCS_NUM_PROTOCOLS,
-		sizeof(SK_PNMI_CHECKSUM),
-		SK_PNMI_OFF(Checksum) + SK_PNMI_CHK_OFF(ChecksumRxErrCts),
-		SK_PNMI_RO, CsumStat, 0},
-	{OID_SKGE_CHKSM_TX_OK_CTS,
-		SKCS_NUM_PROTOCOLS,
-		sizeof(SK_PNMI_CHECKSUM),
-		SK_PNMI_OFF(Checksum) + SK_PNMI_CHK_OFF(ChecksumTxOkCts),
-		SK_PNMI_RO, CsumStat, 0},
-	{OID_SKGE_CHKSM_TX_UNABLE_CTS,
-		SKCS_NUM_PROTOCOLS,
-		sizeof(SK_PNMI_CHECKSUM),
-		SK_PNMI_OFF(Checksum) + SK_PNMI_CHK_OFF(ChecksumTxUnableCts),
-		SK_PNMI_RO, CsumStat, 0},
-	{OID_SKGE_STAT_TX,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxOkCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX},
-	{OID_SKGE_STAT_TX_OCTETS,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxOctetsOkCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_OCTET},
-	{OID_SKGE_STAT_TX_BROADCAST,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxBroadcastOkCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_BROADCAST},
-	{OID_SKGE_STAT_TX_MULTICAST,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxMulticastOkCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_MULTICAST},
-	{OID_SKGE_STAT_TX_UNICAST,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxUnicastOkCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_UNICAST},
-	{OID_SKGE_STAT_TX_LONGFRAMES,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxLongFramesCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_LONGFRAMES},
-	{OID_SKGE_STAT_TX_BURST,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxBurstCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_BURST},
-	{OID_SKGE_STAT_TX_PFLOWC,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxPauseMacCtrlCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_PMACC},
-	{OID_SKGE_STAT_TX_FLOWC,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxMacCtrlCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_MACC},
-	{OID_SKGE_STAT_TX_SINGLE_COL,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxSingleCollisionCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_SINGLE_COL},
-	{OID_SKGE_STAT_TX_MULTI_COL,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxMultipleCollisionCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_MULTI_COL},
-	{OID_SKGE_STAT_TX_EXCESS_COL,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxExcessiveCollisionCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_EXCESS_COL},
-	{OID_SKGE_STAT_TX_LATE_COL,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxLateCollisionCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_LATE_COL},
-	{OID_SKGE_STAT_TX_DEFFERAL,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxDeferralCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_DEFFERAL},
-	{OID_SKGE_STAT_TX_EXCESS_DEF,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxExcessiveDeferralCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_EXCESS_DEF},
-	{OID_SKGE_STAT_TX_UNDERRUN,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxFifoUnderrunCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_UNDERRUN},
-	{OID_SKGE_STAT_TX_CARRIER,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxCarrierCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_CARRIER},
-/*	{OID_SKGE_STAT_TX_UTIL,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxUtilization),
-		SK_PNMI_RO, MacPrivateStat, (SK_U16)(-1)}, */
-	{OID_SKGE_STAT_TX_64,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTx64Cts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_64},
-	{OID_SKGE_STAT_TX_127,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTx127Cts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_127},
-	{OID_SKGE_STAT_TX_255,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTx255Cts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_255},
-	{OID_SKGE_STAT_TX_511,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTx511Cts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_511},
-	{OID_SKGE_STAT_TX_1023,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTx1023Cts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_1023},
-	{OID_SKGE_STAT_TX_MAX,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxMaxCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_MAX},
-	{OID_SKGE_STAT_TX_SYNC,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxSyncCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_SYNC},
-	{OID_SKGE_STAT_TX_SYNC_OCTETS,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxSyncOctetsCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_SYNC_OCTET},
-	{OID_SKGE_STAT_RX,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxOkCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX},
-	{OID_SKGE_STAT_RX_OCTETS,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxOctetsOkCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_OCTET},
-	{OID_SKGE_STAT_RX_BROADCAST,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxBroadcastOkCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_BROADCAST},
-	{OID_SKGE_STAT_RX_MULTICAST,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxMulticastOkCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_MULTICAST},
-	{OID_SKGE_STAT_RX_UNICAST,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxUnicastOkCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_UNICAST},
-	{OID_SKGE_STAT_RX_LONGFRAMES,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxLongFramesCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_LONGFRAMES},
-	{OID_SKGE_STAT_RX_PFLOWC,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxPauseMacCtrlCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_PMACC},
-	{OID_SKGE_STAT_RX_FLOWC,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxMacCtrlCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_MACC},
-	{OID_SKGE_STAT_RX_PFLOWC_ERR,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxPauseMacCtrlErrorCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_PMACC_ERR},
-	{OID_SKGE_STAT_RX_FLOWC_UNKWN,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxMacCtrlUnknownCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_MACC_UNKWN},
-	{OID_SKGE_STAT_RX_BURST,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxBurstCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_BURST},
-	{OID_SKGE_STAT_RX_MISSED,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxMissedCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_MISSED},
-	{OID_SKGE_STAT_RX_FRAMING,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxFramingCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_FRAMING},
-	{OID_SKGE_STAT_RX_OVERFLOW,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxFifoOverflowCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_OVERFLOW},
-	{OID_SKGE_STAT_RX_JABBER,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxJabberCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_JABBER},
-	{OID_SKGE_STAT_RX_CARRIER,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxCarrierCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_CARRIER},
-	{OID_SKGE_STAT_RX_IR_LENGTH,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxIRLengthCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_IRLENGTH},
-	{OID_SKGE_STAT_RX_SYMBOL,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxSymbolCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_SYMBOL},
-	{OID_SKGE_STAT_RX_SHORTS,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxShortsCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_SHORTS},
-	{OID_SKGE_STAT_RX_RUNT,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxRuntCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_RUNT},
-	{OID_SKGE_STAT_RX_CEXT,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxCextCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_CEXT},
-	{OID_SKGE_STAT_RX_TOO_LONG,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxTooLongCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_TOO_LONG},
-	{OID_SKGE_STAT_RX_FCS,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxFcsCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_FCS},
-/*	{OID_SKGE_STAT_RX_UTIL,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxUtilization),
-		SK_PNMI_RO, MacPrivateStat, (SK_U16)(-1)}, */
-	{OID_SKGE_STAT_RX_64,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRx64Cts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_64},
-	{OID_SKGE_STAT_RX_127,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRx127Cts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_127},
-	{OID_SKGE_STAT_RX_255,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRx255Cts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_255},
-	{OID_SKGE_STAT_RX_511,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRx511Cts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_511},
-	{OID_SKGE_STAT_RX_1023,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRx1023Cts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_1023},
-	{OID_SKGE_STAT_RX_MAX,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_STAT),
-		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxMaxCts),
-		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_MAX},
-	{OID_SKGE_PHYS_CUR_ADDR,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_CONF),
-		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfMacCurrentAddr),
-		SK_PNMI_RW, Addr, 0},
-	{OID_SKGE_PHYS_FAC_ADDR,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_CONF),
-		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfMacFactoryAddr),
-		SK_PNMI_RO, Addr, 0},
-	{OID_SKGE_PMD,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_CONF),
-		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPMD),
-		SK_PNMI_RO, MacPrivateConf, 0},
-	{OID_SKGE_CONNECTOR,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_CONF),
-		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfConnector),
-		SK_PNMI_RO, MacPrivateConf, 0},
-	{OID_SKGE_LINK_CAP,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_CONF),
-		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfLinkCapability),
-		SK_PNMI_RO, MacPrivateConf, 0},
-	{OID_SKGE_LINK_MODE,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_CONF),
-		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfLinkMode),
-		SK_PNMI_RW, MacPrivateConf, 0},
-	{OID_SKGE_LINK_MODE_STATUS,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_CONF),
-		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfLinkModeStatus),
-		SK_PNMI_RO, MacPrivateConf, 0},
-	{OID_SKGE_LINK_STATUS,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_CONF),
-		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfLinkStatus),
-		SK_PNMI_RO, MacPrivateConf, 0},
-	{OID_SKGE_FLOWCTRL_CAP,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_CONF),
-		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfFlowCtrlCapability),
-		SK_PNMI_RO, MacPrivateConf, 0},
-	{OID_SKGE_FLOWCTRL_MODE,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_CONF),
-		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfFlowCtrlMode),
-		SK_PNMI_RW, MacPrivateConf, 0},
-	{OID_SKGE_FLOWCTRL_STATUS,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_CONF),
-		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfFlowCtrlStatus),
-		SK_PNMI_RO, MacPrivateConf, 0},
-	{OID_SKGE_PHY_OPERATION_CAP,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_CONF),
-		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPhyOperationCapability),
-		SK_PNMI_RO, MacPrivateConf, 0},
-	{OID_SKGE_PHY_OPERATION_MODE,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_CONF),
-		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPhyOperationMode),
-		SK_PNMI_RW, MacPrivateConf, 0},
-	{OID_SKGE_PHY_OPERATION_STATUS,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_CONF),
-		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPhyOperationStatus),
-		SK_PNMI_RO, MacPrivateConf, 0},
-	{OID_SKGE_TRAP,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(Trap),
-		SK_PNMI_RO, General, 0},
-	{OID_SKGE_TRAP_NUMBER,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(TrapNumber),
-		SK_PNMI_RO, General, 0},
-	{OID_SKGE_RLMT_MODE,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(RlmtMode),
-		SK_PNMI_RW, Rlmt, 0},
-	{OID_SKGE_RLMT_PORT_NUMBER,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(RlmtPortNumber),
-		SK_PNMI_RO, Rlmt, 0},
-	{OID_SKGE_RLMT_PORT_ACTIVE,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(RlmtPortActive),
-		SK_PNMI_RO, Rlmt, 0},
-	{OID_SKGE_RLMT_PORT_PREFERRED,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(RlmtPortPreferred),
-		SK_PNMI_RW, Rlmt, 0},
-	{OID_SKGE_RLMT_CHANGE_CTS,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(RlmtChangeCts),
-		SK_PNMI_RO, Rlmt, 0},
-	{OID_SKGE_RLMT_CHANGE_TIME,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(RlmtChangeTime),
-		SK_PNMI_RO, Rlmt, 0},
-	{OID_SKGE_RLMT_CHANGE_ESTIM,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(RlmtChangeEstimate),
-		SK_PNMI_RO, Rlmt, 0},
-	{OID_SKGE_RLMT_CHANGE_THRES,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(RlmtChangeThreshold),
-		SK_PNMI_RW, Rlmt, 0},
-	{OID_SKGE_RLMT_PORT_INDEX,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_RLMT),
-		SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtIndex),
-		SK_PNMI_RO, RlmtStat, 0},
-	{OID_SKGE_RLMT_STATUS,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_RLMT),
-		SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtStatus),
-		SK_PNMI_RO, RlmtStat, 0},
-	{OID_SKGE_RLMT_TX_HELLO_CTS,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_RLMT),
-		SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtTxHelloCts),
-		SK_PNMI_RO, RlmtStat, 0},
-	{OID_SKGE_RLMT_RX_HELLO_CTS,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_RLMT),
-		SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtRxHelloCts),
-		SK_PNMI_RO, RlmtStat, 0},
-	{OID_SKGE_RLMT_TX_SP_REQ_CTS,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_RLMT),
-		SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtTxSpHelloReqCts),
-		SK_PNMI_RO, RlmtStat, 0},
-	{OID_SKGE_RLMT_RX_SP_CTS,
-		SK_PNMI_MAC_ENTRIES,
-		sizeof(SK_PNMI_RLMT),
-		SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtRxSpHelloCts),
-		SK_PNMI_RO, RlmtStat, 0},
-	{OID_SKGE_RLMT_MONITOR_NUMBER,
-		1,
-		0,
-		SK_PNMI_MAI_OFF(RlmtMonitorNumber),
-		SK_PNMI_RO, General, 0},
-	{OID_SKGE_RLMT_MONITOR_INDEX,
-		SK_PNMI_MONITOR_ENTRIES,
-		sizeof(SK_PNMI_RLMT_MONITOR),
-		SK_PNMI_OFF(RlmtMonitor) + SK_PNMI_MON_OFF(RlmtMonitorIndex),
-		SK_PNMI_RO, Monitor, 0},
-	{OID_SKGE_RLMT_MONITOR_ADDR,
-		SK_PNMI_MONITOR_ENTRIES,
-		sizeof(SK_PNMI_RLMT_MONITOR),
-		SK_PNMI_OFF(RlmtMonitor) + SK_PNMI_MON_OFF(RlmtMonitorAddr),
-		SK_PNMI_RO, Monitor, 0},
-	{OID_SKGE_RLMT_MONITOR_ERRS,
-		SK_PNMI_MONITOR_ENTRIES,
-		sizeof(SK_PNMI_RLMT_MONITOR),
-		SK_PNMI_OFF(RlmtMonitor) + SK_PNMI_MON_OFF(RlmtMonitorErrorCts),
-		SK_PNMI_RO, Monitor, 0},
-	{OID_SKGE_RLMT_MONITOR_TIMESTAMP,
-		SK_PNMI_MONITOR_ENTRIES,
-		sizeof(SK_PNMI_RLMT_MONITOR),
-		SK_PNMI_OFF(RlmtMonitor) + SK_PNMI_MON_OFF(RlmtMonitorTimestamp),
-		SK_PNMI_RO, Monitor, 0},
-	{OID_SKGE_RLMT_MONITOR_ADMIN,
-		SK_PNMI_MONITOR_ENTRIES,
-		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},
+#include "skgemib.c"
+
+/* global variables **********************************************************/
+
+/*
+ * Overflow status register bit table and corresponding counter
+ * dependent on MAC type - the number relates to the size of overflow
+ * mask returned by the pFnMacOverflow function 
+ */
+PNMI_STATIC const SK_U16 StatOvrflwBit[][SK_PNMI_MAC_TYPES] = {
+/* Bit0  */	{ SK_PNMI_HTX, 				SK_PNMI_HTX_UNICAST},
+/* Bit1  */	{ SK_PNMI_HTX_OCTETHIGH, 	SK_PNMI_HTX_BROADCAST},
+/* Bit2  */	{ SK_PNMI_HTX_OCTETLOW, 	SK_PNMI_HTX_PMACC},
+/* Bit3  */	{ SK_PNMI_HTX_BROADCAST, 	SK_PNMI_HTX_MULTICAST},
+/* Bit4  */	{ SK_PNMI_HTX_MULTICAST, 	SK_PNMI_HTX_OCTETLOW},
+/* Bit5  */	{ SK_PNMI_HTX_UNICAST, 		SK_PNMI_HTX_OCTETHIGH},
+/* Bit6  */	{ SK_PNMI_HTX_LONGFRAMES, 	SK_PNMI_HTX_64},
+/* Bit7  */	{ SK_PNMI_HTX_BURST, 		SK_PNMI_HTX_127},
+/* Bit8  */	{ SK_PNMI_HTX_PMACC, 		SK_PNMI_HTX_255},
+/* Bit9  */	{ SK_PNMI_HTX_MACC, 		SK_PNMI_HTX_511},
+/* Bit10 */	{ SK_PNMI_HTX_SINGLE_COL, 	SK_PNMI_HTX_1023},
+/* Bit11 */	{ SK_PNMI_HTX_MULTI_COL, 	SK_PNMI_HTX_MAX},
+/* Bit12 */	{ SK_PNMI_HTX_EXCESS_COL, 	SK_PNMI_HTX_LONGFRAMES},
+/* Bit13 */	{ SK_PNMI_HTX_LATE_COL, 	SK_PNMI_HTX_RESERVED},
+/* Bit14 */	{ SK_PNMI_HTX_DEFFERAL, 	SK_PNMI_HTX_COL},
+/* Bit15 */	{ SK_PNMI_HTX_EXCESS_DEF, 	SK_PNMI_HTX_LATE_COL},
+/* Bit16 */	{ SK_PNMI_HTX_UNDERRUN, 	SK_PNMI_HTX_EXCESS_COL},
+/* Bit17 */	{ SK_PNMI_HTX_CARRIER, 		SK_PNMI_HTX_MULTI_COL},
+/* Bit18 */	{ SK_PNMI_HTX_UTILUNDER, 	SK_PNMI_HTX_SINGLE_COL},
+/* Bit19 */	{ SK_PNMI_HTX_UTILOVER, 	SK_PNMI_HTX_UNDERRUN},
+/* Bit20 */	{ SK_PNMI_HTX_64, 			SK_PNMI_HTX_RESERVED},
+/* Bit21 */	{ SK_PNMI_HTX_127, 			SK_PNMI_HTX_RESERVED},
+/* Bit22 */	{ SK_PNMI_HTX_255, 			SK_PNMI_HTX_RESERVED},
+/* Bit23 */	{ SK_PNMI_HTX_511, 			SK_PNMI_HTX_RESERVED},
+/* Bit24 */	{ SK_PNMI_HTX_1023, 		SK_PNMI_HTX_RESERVED},
+/* Bit25 */	{ SK_PNMI_HTX_MAX, 			SK_PNMI_HTX_RESERVED},
+/* Bit26 */	{ SK_PNMI_HTX_RESERVED, 	SK_PNMI_HTX_RESERVED},
+/* Bit27 */	{ SK_PNMI_HTX_RESERVED, 	SK_PNMI_HTX_RESERVED},
+/* Bit28 */	{ SK_PNMI_HTX_RESERVED, 	SK_PNMI_HTX_RESERVED},
+/* Bit29 */	{ SK_PNMI_HTX_RESERVED, 	SK_PNMI_HTX_RESERVED},
+/* Bit30 */	{ SK_PNMI_HTX_RESERVED, 	SK_PNMI_HTX_RESERVED},
+/* Bit31 */	{ SK_PNMI_HTX_RESERVED, 	SK_PNMI_HTX_RESERVED},
+/* Bit32 */	{ SK_PNMI_HRX, 				SK_PNMI_HRX_UNICAST},
+/* Bit33 */	{ SK_PNMI_HRX_OCTETHIGH, 	SK_PNMI_HRX_BROADCAST},
+/* Bit34 */	{ SK_PNMI_HRX_OCTETLOW, 	SK_PNMI_HRX_PMACC},
+/* Bit35 */	{ SK_PNMI_HRX_BROADCAST, 	SK_PNMI_HRX_MULTICAST},
+/* Bit36 */	{ SK_PNMI_HRX_MULTICAST, 	SK_PNMI_HRX_FCS},
+/* Bit37 */	{ SK_PNMI_HRX_UNICAST, 		SK_PNMI_HRX_RESERVED},
+/* Bit38 */	{ SK_PNMI_HRX_PMACC, 		SK_PNMI_HRX_OCTETLOW},
+/* Bit39 */	{ SK_PNMI_HRX_MACC, 		SK_PNMI_HRX_OCTETHIGH},
+/* Bit40 */	{ SK_PNMI_HRX_PMACC_ERR, 	SK_PNMI_HRX_BADOCTETLOW},
+/* Bit41 */	{ SK_PNMI_HRX_MACC_UNKWN,	SK_PNMI_HRX_BADOCTETHIGH},
+/* Bit42 */	{ SK_PNMI_HRX_BURST, 		SK_PNMI_HRX_UNDERSIZE},
+/* Bit43 */	{ SK_PNMI_HRX_MISSED, 		SK_PNMI_HRX_RUNT},
+/* Bit44 */	{ SK_PNMI_HRX_FRAMING, 		SK_PNMI_HRX_64},
+/* Bit45 */	{ SK_PNMI_HRX_OVERFLOW, 	SK_PNMI_HRX_127},
+/* Bit46 */	{ SK_PNMI_HRX_JABBER, 		SK_PNMI_HRX_255},
+/* Bit47 */	{ SK_PNMI_HRX_CARRIER, 		SK_PNMI_HRX_511},
+/* Bit48 */	{ SK_PNMI_HRX_IRLENGTH, 	SK_PNMI_HRX_1023},
+/* Bit49 */	{ SK_PNMI_HRX_SYMBOL, 		SK_PNMI_HRX_MAX},
+/* Bit50 */	{ SK_PNMI_HRX_SHORTS, 		SK_PNMI_HRX_LONGFRAMES},
+/* Bit51 */	{ SK_PNMI_HRX_RUNT, 		SK_PNMI_HRX_TOO_LONG},
+/* Bit52 */	{ SK_PNMI_HRX_TOO_LONG, 	SK_PNMI_HRX_JABBER},
+/* Bit53 */	{ SK_PNMI_HRX_FCS, 			SK_PNMI_HRX_RESERVED},
+/* Bit54 */	{ SK_PNMI_HRX_RESERVED, 	SK_PNMI_HRX_OVERFLOW},
+/* Bit55 */	{ SK_PNMI_HRX_CEXT, 		SK_PNMI_HRX_RESERVED},
+/* Bit56 */	{ SK_PNMI_HRX_UTILUNDER, 	SK_PNMI_HRX_RESERVED},
+/* Bit57 */	{ SK_PNMI_HRX_UTILOVER, 	SK_PNMI_HRX_RESERVED},
+/* Bit58 */	{ SK_PNMI_HRX_64, 			SK_PNMI_HRX_RESERVED},
+/* Bit59 */	{ SK_PNMI_HRX_127, 			SK_PNMI_HRX_RESERVED},
+/* Bit60 */	{ SK_PNMI_HRX_255, 			SK_PNMI_HRX_RESERVED},
+/* Bit61 */	{ SK_PNMI_HRX_511, 			SK_PNMI_HRX_RESERVED},
+/* Bit62 */	{ SK_PNMI_HRX_1023, 		SK_PNMI_HRX_RESERVED},
+/* Bit63 */	{ SK_PNMI_HRX_MAX, 			SK_PNMI_HRX_RESERVED}
 };
 
 /*
  * 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},
-	/*  2 */	{FALSE, 0},
-	/*  3 */	{TRUE, XM_TXF_BC_OK},
-	/*  4 */	{TRUE, XM_TXF_MC_OK},
-	/*  5 */	{TRUE, XM_TXF_UC_OK},
-	/*  6 */	{TRUE, XM_TXF_LONG},
-	/*  7 */	{TRUE, XM_TXE_BURST},
-	/*  8 */	{TRUE, XM_TXF_MPAUSE},
-	/*  9 */	{TRUE, XM_TXF_MCTRL},
-	/* 10 */	{TRUE, XM_TXF_SNG_COL},
-	/* 11 */	{TRUE, XM_TXF_MUL_COL},
-	/* 12 */	{TRUE, XM_TXF_ABO_COL},
-	/* 13 */	{TRUE, XM_TXF_LAT_COL},
-	/* 14 */	{TRUE, XM_TXF_DEF},
-	/* 15 */	{TRUE, XM_TXF_EX_DEF},
-	/* 16 */	{TRUE, XM_TXE_FIFO_UR},
-	/* 17 */	{TRUE, XM_TXE_CS_ERR},
-	/* 18 */	{FALSE, 0},
-	/* 19 */	{FALSE, 0},
-	/* 20 */	{TRUE, XM_TXF_64B},
-	/* 21 */	{TRUE, XM_TXF_127B},
-	/* 22 */	{TRUE, XM_TXF_255B},
-	/* 23 */	{TRUE, XM_TXF_511B},
-	/* 24 */	{TRUE, XM_TXF_1023B},
-	/* 25 */	{TRUE, XM_TXF_MAX_SZ},
-	/* 26 */	{FALSE, 0},
-	/* 27 */	{FALSE, 0},
-	/* 28 */	{FALSE, 0},
-	/* 29 */	{FALSE, 0},
-	/* 30 */	{FALSE, 0},
-	/* 31 */	{FALSE, 0},
-	/* 32 */	{TRUE, XM_RXF_OK},
-	/* 33 */	{TRUE, 0},
-	/* 34 */	{FALSE, 0},
-	/* 35 */	{TRUE, XM_RXF_BC_OK},
-	/* 36 */	{TRUE, XM_RXF_MC_OK},
-	/* 37 */	{TRUE, XM_RXF_UC_OK},
-	/* 38 */	{TRUE, XM_RXF_MPAUSE},
-	/* 39 */	{TRUE, XM_RXF_MCTRL},
-	/* 40 */	{TRUE, XM_RXF_INV_MP},
-	/* 41 */	{TRUE, XM_RXF_INV_MOC},
-	/* 42 */	{TRUE, XM_RXE_BURST},
-	/* 43 */	{TRUE, XM_RXE_FMISS},
-	/* 44 */	{TRUE, XM_RXF_FRA_ERR},
-	/* 45 */	{TRUE, XM_RXE_FIFO_OV},
-	/* 46 */	{TRUE, XM_RXF_JAB_PKT},
-	/* 47 */	{TRUE, XM_RXE_CAR_ERR},
-	/* 48 */	{TRUE, XM_RXF_LEN_ERR},
-	/* 49 */	{TRUE, XM_RXE_SYM_ERR},
-	/* 50 */	{TRUE, XM_RXE_SHT_ERR},
-	/* 51 */	{TRUE, XM_RXE_RUNT},
-	/* 52 */	{TRUE, XM_RXF_LNG_ERR},
-	/* 53 */	{TRUE, XM_RXF_FCS_ERR},
-	/* 54 */	{FALSE, 0},
-	/* 55 */	{TRUE, XM_RXF_CEX_ERR},
-	/* 56 */	{FALSE, 0},
-	/* 57 */	{FALSE, 0},
-	/* 58 */	{TRUE, XM_RXF_64B},
-	/* 59 */	{TRUE, XM_RXF_127B},
-	/* 60 */	{TRUE, XM_RXF_255B},
-	/* 61 */	{TRUE, XM_RXF_511B},
-	/* 62 */	{TRUE, XM_RXF_1023B},
-	/* 63 */	{TRUE, XM_RXF_MAX_SZ},
-	/* 64 */	{FALSE, 0},
-	/* 65 */	{FALSE, 0},
-	/* 66 */	{TRUE, 0}
+PNMI_STATIC const SK_PNMI_STATADDR StatAddr[SK_PNMI_MAX_IDX][SK_PNMI_MAC_TYPES] = {
+	/* SK_PNMI_HTX */
+	{{XM_TXF_OK, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HTX_OCTETHIGH */
+	{{XM_TXO_OK_HI, SK_TRUE}, {GM_TXO_OK_HI, SK_TRUE}},
+	/* SK_PNMI_HTX_OCTETLOW */
+	{{XM_TXO_OK_LO, SK_FALSE}, {GM_TXO_OK_LO, SK_FALSE}},
+	/* SK_PNMI_HTX_BROADCAST */
+	{{XM_TXF_BC_OK, SK_TRUE}, {GM_TXF_BC_OK, SK_TRUE}},
+	/* SK_PNMI_HTX_MULTICAST */
+	{{XM_TXF_MC_OK, SK_TRUE}, {GM_TXF_MC_OK, SK_TRUE}},
+	/* SK_PNMI_HTX_UNICAST */
+	{{XM_TXF_UC_OK, SK_TRUE}, {GM_TXF_UC_OK, SK_TRUE}},
+	/* SK_PNMI_HTX_BURST */
+	{{XM_TXE_BURST, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HTX_PMACC */
+	{{XM_TXF_MPAUSE, SK_TRUE}, {GM_TXF_MPAUSE, SK_TRUE}},
+	/* SK_PNMI_HTX_MACC */
+	{{XM_TXF_MCTRL, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HTX_COL */
+	{{0, SK_FALSE}, {GM_TXF_COL, SK_TRUE}},
+	/* SK_PNMI_HTX_SINGLE_COL */
+	{{XM_TXF_SNG_COL, SK_TRUE}, {GM_TXF_SNG_COL, SK_TRUE}},
+	/* SK_PNMI_HTX_MULTI_COL */
+	{{XM_TXF_MUL_COL, SK_TRUE}, {GM_TXF_MUL_COL, SK_TRUE}},
+	/* SK_PNMI_HTX_EXCESS_COL */
+	{{XM_TXF_ABO_COL, SK_TRUE}, {GM_TXF_ABO_COL, SK_TRUE}},
+	/* SK_PNMI_HTX_LATE_COL */
+	{{XM_TXF_LAT_COL, SK_TRUE}, {GM_TXF_LAT_COL, SK_TRUE}},
+	/* SK_PNMI_HTX_DEFFERAL */
+	{{XM_TXF_DEF, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HTX_EXCESS_DEF */
+	{{XM_TXF_EX_DEF, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HTX_UNDERRUN */
+	{{XM_TXE_FIFO_UR, SK_TRUE}, {GM_TXE_FIFO_UR, SK_TRUE}},
+	/* SK_PNMI_HTX_CARRIER */
+	{{XM_TXE_CS_ERR, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HTX_UTILUNDER */
+	{{0, SK_FALSE}, {0, SK_FALSE}},
+	/* SK_PNMI_HTX_UTILOVER */
+	{{0, SK_FALSE}, {0, SK_FALSE}},
+	/* SK_PNMI_HTX_64 */
+	{{XM_TXF_64B, SK_TRUE}, {GM_TXF_64B, SK_TRUE}},
+	/* SK_PNMI_HTX_127 */
+	{{XM_TXF_127B, SK_TRUE}, {GM_TXF_127B, SK_TRUE}},
+	/* SK_PNMI_HTX_255 */
+	{{XM_TXF_255B, SK_TRUE}, {GM_TXF_255B, SK_TRUE}},
+	/* SK_PNMI_HTX_511 */
+	{{XM_TXF_511B, SK_TRUE}, {GM_TXF_511B, SK_TRUE}},
+	/* SK_PNMI_HTX_1023 */
+	{{XM_TXF_1023B, SK_TRUE}, {GM_TXF_1023B, SK_TRUE}},
+	/* SK_PNMI_HTX_MAX */
+	{{XM_TXF_MAX_SZ, SK_TRUE}, {GM_TXF_1518B, SK_TRUE}},
+	/* SK_PNMI_HTX_LONGFRAMES  */
+	{{XM_TXF_LONG, SK_TRUE}, {GM_TXF_MAX_SZ, SK_TRUE}},
+	/* SK_PNMI_HTX_SYNC */
+	{{0, SK_FALSE}, {0, SK_FALSE}},
+	/* SK_PNMI_HTX_SYNC_OCTET */
+	{{0, SK_FALSE}, {0, SK_FALSE}},
+	/* SK_PNMI_HTX_RESERVED */
+	{{0, SK_FALSE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX */
+	{{XM_RXF_OK, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX_OCTETHIGH */
+	{{XM_RXO_OK_HI, SK_TRUE}, {GM_RXO_OK_HI, SK_TRUE}},
+	/* SK_PNMI_HRX_OCTETLOW */
+	{{XM_RXO_OK_LO, SK_FALSE}, {GM_RXO_OK_LO, SK_FALSE}},
+	/* SK_PNMI_HRX_BADOCTETHIGH */
+	{{0, SK_FALSE}, {GM_RXO_ERR_HI, SK_TRUE}},
+	/* SK_PNMI_HRX_BADOCTETLOW */
+	{{0, SK_FALSE}, {GM_RXO_ERR_LO, SK_TRUE}},
+	/* SK_PNMI_HRX_BROADCAST */
+	{{XM_RXF_BC_OK, SK_TRUE}, {GM_RXF_BC_OK, SK_TRUE}},
+	/* SK_PNMI_HRX_MULTICAST */
+	{{XM_RXF_MC_OK, SK_TRUE}, {GM_RXF_MC_OK, SK_TRUE}},
+	/* SK_PNMI_HRX_UNICAST */
+	{{XM_RXF_UC_OK, SK_TRUE}, {GM_RXF_UC_OK, SK_TRUE}},
+	/* SK_PNMI_HRX_PMACC */
+	{{XM_RXF_MPAUSE, SK_TRUE}, {GM_RXF_MPAUSE, SK_TRUE}},
+	/* SK_PNMI_HRX_MACC */
+	{{XM_RXF_MCTRL, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX_PMACC_ERR */
+	{{XM_RXF_INV_MP, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX_MACC_UNKWN */
+	{{XM_RXF_INV_MOC, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX_BURST */
+	{{XM_RXE_BURST, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX_MISSED */
+	{{XM_RXE_FMISS, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX_FRAMING */
+	{{XM_RXF_FRA_ERR, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX_UNDERSIZE */
+	{{0, SK_FALSE},{GM_RXF_SHT, SK_TRUE}},
+	/* SK_PNMI_HRX_OVERFLOW */
+	{{XM_RXE_FIFO_OV, SK_TRUE}, {GM_RXE_FIFO_OV, SK_TRUE}},
+	/* SK_PNMI_HRX_JABBER */
+	{{XM_RXF_JAB_PKT, SK_TRUE}, {GM_RXF_JAB_PKT, SK_TRUE}},
+	/* SK_PNMI_HRX_CARRIER */
+	{{XM_RXE_CAR_ERR, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX_IRLENGTH */
+	{{XM_RXF_LEN_ERR, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX_SYMBOL */
+	{{XM_RXE_SYM_ERR, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX_SHORTS */
+	{{XM_RXE_SHT_ERR, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX_RUNT */
+	{{XM_RXE_RUNT, SK_TRUE}, {GM_RXE_FRAG, SK_TRUE}},
+	/* SK_PNMI_HRX_TOO_LONG */
+	{{XM_RXF_LNG_ERR, SK_TRUE}, {GM_RXF_LNG_ERR, SK_TRUE}},
+	/* SK_PNMI_HRX_FCS */
+	{{XM_RXF_FCS_ERR, SK_TRUE}, {GM_RXF_FCS_ERR, SK_TRUE}},
+	/* SK_PNMI_HRX_CEXT */
+	{{XM_RXF_CEX_ERR, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX_UTILUNDER */
+	{{0, SK_FALSE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX_UTILOVER */
+	{{0, SK_FALSE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX_64 */
+	{{XM_RXF_64B, SK_TRUE}, {GM_RXF_64B, SK_TRUE}},
+	/* SK_PNMI_HRX_127 */
+	{{XM_RXF_127B, SK_TRUE}, {GM_RXF_127B, SK_TRUE}},
+	/* SK_PNMI_HRX_255 */
+	{{XM_RXF_255B, SK_TRUE}, {GM_RXF_255B, SK_TRUE}},
+	/* SK_PNMI_HRX_511 */
+	{{XM_RXF_511B, SK_TRUE}, {GM_RXF_511B, SK_TRUE}},
+	/* SK_PNMI_HRX_1023 */
+	{{XM_RXF_1023B, SK_TRUE}, {GM_RXF_1023B, SK_TRUE}},
+	/* SK_PNMI_HRX_MAX */
+	{{XM_RXF_MAX_SZ, SK_TRUE}, {GM_RXF_1518B, SK_TRUE}},
+	/* SK_PNMI_HRX_LONGFRAMES */
+	{{0, SK_FALSE}, {GM_RXF_MAX_SZ, SK_TRUE}},
+	/* SK_PNMI_HRX_RESERVED */
+	{{0, SK_FALSE}, {0, SK_FALSE}}
 };
 
 
@@ -1457,7 +758,6 @@
  * Returns:
  *	Always 0
  */
-
 int SkPnmiInit(
 SK_AC *pAC,		/* Pointer to adapter context */
 SK_IOC IoC,		/* IO context handle */
@@ -1468,6 +768,8 @@
 	SK_U16		Val16;		/* Multiple purpose 16 bit variable */
 	SK_U8		Val8;		/* Mulitple purpose 8 bit variable */
 	SK_EVPARA	EventParam;	/* Event struct for timer event */
+	SK_GEPORT	*pPrt;
+	SK_PNMI_VCT	*pVctBackupData;
 
 
 	SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
@@ -1485,6 +787,33 @@
 			pAC->Pnmi.Port[PortIndex].ActiveFlag = SK_FALSE;
 			pAC->Pnmi.DualNetActiveFlag = SK_FALSE;
 		}
+
+#ifdef SK_PNMI_CHECK
+		if (SK_PNMI_MAX_IDX != SK_PNMI_CNT_NO) {
+			
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR049, SK_PNMI_ERR049MSG);
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_INIT | SK_DBGCAT_FATAL,
+					   ("CounterOffset struct size (%d) differs from"
+						"SK_PNMI_MAX_IDX (%d)\n",
+						SK_PNMI_CNT_NO, SK_PNMI_MAX_IDX));
+			BRK;
+		}
+
+		if (SK_PNMI_MAX_IDX !=
+			(sizeof(StatAddr) / (sizeof(SK_PNMI_STATADDR) * SK_PNMI_MAC_TYPES))) {
+			
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR050, SK_PNMI_ERR050MSG);
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_INIT | SK_DBGCAT_FATAL,
+					   ("StatAddr table size (%d) differs from "
+						"SK_PNMI_MAX_IDX (%d)\n",
+						(sizeof(StatAddr) / 
+						 (sizeof(SK_PNMI_STATADDR) * SK_PNMI_MAC_TYPES)),
+						 SK_PNMI_MAX_IDX));
+			BRK;
+		}
+#endif /* SK_PNMI_CHECK */
 		break;
 
 	case SK_INIT_IO:
@@ -1495,12 +824,17 @@
 
 		for (PortIndex = 0; PortIndex < PortMax; PortIndex ++) {
 
-			Val16 = XM_SC_CLR_RXC | XM_SC_CLR_TXC;
-			XM_OUT16(IoC, PortIndex, XM_STAT_CMD, Val16);
-			/* Clear two times according to Errata #3 */
-			XM_OUT16(IoC, PortIndex, XM_STAT_CMD, Val16);
+			pAC->GIni.GIFunc.pFnMacResetCounter(pAC, IoC, PortIndex);
 		}
-
+		
+		/* Initialize DSP variables for Vct() to 0xff => Never written! */		
+		for (PortIndex = 0; PortIndex < PortMax; PortIndex ++) {
+			pPrt = &pAC->GIni.GP[PortIndex];
+			pPrt->PCableLen =0xff;
+			pVctBackupData = &pAC->Pnmi.VctBackup[PortIndex];
+			pVctBackupData->PCableLen = 0xff;
+		}
+		
 		/*
 		 * Get pci bus speed
 		 */
@@ -1526,6 +860,22 @@
 		}
 
 		/*
+		 * Get chipset
+		 */
+		switch (pAC->GIni.GIChipId) {
+		case CHIP_ID_GENESIS:
+			pAC->Pnmi.Chipset = SK_PNMI_CHIPSET_XMAC;
+			break;
+
+		case CHIP_ID_YUKON:
+			pAC->Pnmi.Chipset = SK_PNMI_CHIPSET_YUKON;
+			break;
+
+		default:
+			break;
+		}
+
+		/*
 		 * Get PMD and DeviceType
 		 */
 		SK_IN8(IoC, B2_PMD_TYP, &Val8);
@@ -1608,14 +958,14 @@
 		default:
 			pAC->Pnmi.Connector = 1;
 			break;
-		}
+		}		
 		break;
-
+		
 	case SK_INIT_RUN:
 		/*
 		 * Start timer for RLMT change counter
 		 */
-		SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
+		SK_MEMSET((char *) &EventParam, 0, sizeof(EventParam));
 		SkTimerStart(pAC, IoC, &pAC->Pnmi.RlmtChangeEstimate.EstTimer,
 			28125000, SKGE_PNMI, SK_PNMI_EVT_CHG_EST_TIMER,
 			EventParam);
@@ -1647,7 +997,6 @@
  *                               exist (e.g. port instance 3 on a two port
  *	                         adapter.
  */
-
 int SkPnmiGetVar(
 SK_AC *pAC,		/* Pointer to adapter context */
 SK_IOC IoC,		/* IO context handle */
@@ -1690,7 +1039,6 @@
  *                               exist (e.g. port instance 3 on a two port
  *	                         adapter.
  */
-
 int SkPnmiPreSetVar(
 SK_AC *pAC,		/* Pointer to adapter context */
 SK_IOC IoC,		/* IO context handle */
@@ -1734,7 +1082,6 @@
  *                               exist (e.g. port instance 3 on a two port
  *	                         adapter.
  */
-
 int SkPnmiSetVar(
 SK_AC *pAC,		/* Pointer to adapter context */
 SK_IOC IoC,		/* IO context handle */
@@ -1771,7 +1118,6 @@
  *	                         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 */
@@ -1861,8 +1207,7 @@
 
 	/* Retrieve values */
 	SK_MEMSET((char *)pBuf, 0, SK_PNMI_STRUCT_SIZE);
-	for (TableIndex = 0; TableIndex < sizeof(IdTable)/sizeof(IdTable[0]);
-		TableIndex ++) {
+	for (TableIndex = 0; TableIndex < ID_TABLE_SIZE; TableIndex ++) {
 
 		InstanceNo = IdTable[TableIndex].InstanceNo;
 		for (InstanceCnt = 1; InstanceCnt <= InstanceNo;
@@ -1951,7 +1296,6 @@
  *	SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
  *	                         value range.
  */
-
 int SkPnmiPreSetStruct(
 SK_AC *pAC,		/* Pointer to adapter context */
 SK_IOC IoC,		/* IO context handle */
@@ -1990,7 +1334,6 @@
  *	SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
  *	                         value range.
  */
-
 int SkPnmiSetStruct(
 SK_AC *pAC,		/* Pointer to adapter context */
 SK_IOC IoC,		/* IO context handle */
@@ -2056,7 +1399,6 @@
  * Returns:
  *	Always 0
  */
-
 int SkPnmiEvent(
 SK_AC *pAC,		/* Pointer to adapter context */
 SK_IOC IoC,		/* IO context handle */
@@ -2064,14 +1406,15 @@
 SK_EVPARA Param)	/* Event dependent parameter */
 {
 	unsigned int	PhysPortIndex;
-    unsigned int	MaxNetNumber;
-	int		CounterIndex;
-	int		Ret;
+	unsigned int	MaxNetNumber;
+	int			CounterIndex;
+	int			Ret;
 	SK_U16		MacStatus;
 	SK_U64		OverflowStatus;
 	SK_U64		Mask;
-	SK_U32		MacCntEvent;
+	int			MacType;
 	SK_U64		Value;
+	SK_U32		Val32;
 	SK_U16		Register;
 	SK_EVPARA	EventParam;
 	SK_U64		NewestValue;
@@ -2079,6 +1422,11 @@
 	SK_U64		Delta;
 	SK_PNMI_ESTIMATE *pEst;
 	SK_U32		NetIndex;
+	SK_GEPORT	*pPrt;
+	SK_PNMI_VCT	*pVctBackupData;
+	SK_U32		RetCode;
+	int		i;
+	SK_U32		CableLength;
 
 
 #ifdef DEBUG
@@ -2086,11 +1434,13 @@
 
 		SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
 			("PNMI: SkPnmiEvent: Called, Event=0x%x, Param=0x%x\n",
-			(unsigned long)Event, (unsigned long)Param.Para64));
+			(unsigned int)Event, (unsigned int)Param.Para64));
 	}
 #endif
 	SK_PNMI_CHECKFLAGS("SkPnmiEvent: On call");
 
+	MacType = pAC->GIni.GIMacType;
+	
 	switch (Event) {
 
 	case SK_PNMI_EVT_SIRQ_OVERFLOW:
@@ -2100,7 +1450,8 @@
 		if (PhysPortIndex >= SK_MAX_MACS) {
 
 			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
-				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_SIRQ_OVERFLOW parameter wrong, PhysPortIndex=0x%x\n",
+				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_SIRQ_OVERFLOW parameter"
+				 " wrong, PhysPortIndex=0x%x\n",
 				PhysPortIndex));
 			return (0);
 		}
@@ -2108,28 +1459,14 @@
 		OverflowStatus = 0;
 
 		/*
-		 * Check which source caused an overflow interrupt. The
-		 * interrupt source is a self-clearing register. We only
-		 * need to check the interrupt source once. Another check
-		 * will be done by the SIRQ module to be sure that no
-		 * interrupt get lost during process time.
+		 * Check which source caused an overflow interrupt.
 		 */
-		if ((MacStatus & XM_IS_RXC_OV) == XM_IS_RXC_OV) {
-
-			XM_IN32(IoC, PhysPortIndex, XM_RX_CNT_EV,
-				&MacCntEvent);
-			OverflowStatus |= (SK_U64)MacCntEvent << 32;
-		}
-		if ((MacStatus & XM_IS_TXC_OV) == XM_IS_TXC_OV) {
-
-			XM_IN32(IoC, PhysPortIndex, XM_TX_CNT_EV,
-				&MacCntEvent);
-			OverflowStatus |= (SK_U64)MacCntEvent;
-		}
-		if (OverflowStatus == 0) {
+		if ((pAC->GIni.GIFunc.pFnMacOverflow(
+			 pAC, IoC, PhysPortIndex, MacStatus, &OverflowStatus) != 0) ||
+			(OverflowStatus == 0)) {
 
 			SK_PNMI_CHECKFLAGS("SkPnmiEvent: On return");
-			return (0);
+			return (0); 
 		}
 
 		/*
@@ -2145,7 +1482,7 @@
 				continue;
 			}
 
-			switch (CounterIndex) {
+			switch (StatOvrflwBit[CounterIndex][MacType]) {
 
 			case SK_PNMI_HTX_UTILUNDER:
 			case SK_PNMI_HTX_UTILOVER:
@@ -2167,23 +1504,24 @@
 
 			case SK_PNMI_HTX_OCTETHIGH:
 			case SK_PNMI_HTX_OCTETLOW:
-			case SK_PNMI_HTX_RESERVED26:
-			case SK_PNMI_HTX_RESERVED27:
-			case SK_PNMI_HTX_RESERVED28:
-			case SK_PNMI_HTX_RESERVED29:
-			case SK_PNMI_HTX_RESERVED30:
-			case SK_PNMI_HTX_RESERVED31:
+			case SK_PNMI_HTX_RESERVED:
 			case SK_PNMI_HRX_OCTETHIGH:
 			case SK_PNMI_HRX_OCTETLOW:
 			case SK_PNMI_HRX_IRLENGTH:
-			case SK_PNMI_HRX_RESERVED22:
+			case SK_PNMI_HRX_RESERVED:
 			
 			/*
 			 * the following counters aren't be handled (id > 63)
 			 */
 			case SK_PNMI_HTX_SYNC:
 			case SK_PNMI_HTX_SYNC_OCTET:
+				break;
+
 			case SK_PNMI_HRX_LONGFRAMES:
+				if (MacType == SK_MAC_GMAC) {
+					pAC->Pnmi.Port[PhysPortIndex].
+						CounterHigh[CounterIndex] ++;
+				}
 				break;
 
 			default:
@@ -2333,7 +1671,7 @@
 			(void)SK_DRIVER_SENDEVENT(pAC, IoC);
 		}
 
-		SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
+		SK_MEMSET((char *) &EventParam, 0, sizeof(EventParam));
 		SkTimerStart(pAC, IoC, &pAC->Pnmi.RlmtChangeEstimate.EstTimer,
 			28125000, SKGE_PNMI, SK_PNMI_EVT_CHG_EST_TIMER,
 			EventParam);
@@ -2396,10 +1734,10 @@
 		 */
 		pAC->Pnmi.MacUpdatedFlag ++;
 
-		for (CounterIndex = 0; CounterIndex < SK_PNMI_SCNT_NOT;
+		for (CounterIndex = 0; CounterIndex < SK_PNMI_MAX_IDX;
 			CounterIndex ++) {
 
-			if (!StatAddress[CounterIndex].GetOffset) {
+			if (!StatAddr[CounterIndex][MacType].GetOffset) {
 
 				continue;
 			}
@@ -2415,12 +1753,13 @@
 		break;
 
 	case SK_PNMI_EVT_RLMT_PORT_UP:
+		PhysPortIndex = (unsigned int)Param.Para32[0];
 #ifdef DEBUG
-		if ((unsigned int)Param.Para32[0] >= SK_MAX_MACS) {
+		if (PhysPortIndex >= SK_MAX_MACS) {
 
 			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
-				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_PORT_UP parameter wrong, PhysPortIndex=%d\n",
-				(unsigned int)Param.Para32[0]));
+				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_PORT_UP parameter"
+                 " wrong, PhysPortIndex=%d\n", PhysPortIndex));
 
 			return (0);
 		}
@@ -2429,18 +1768,35 @@
 		 * 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]);
+		QueueRlmtPortTrap(pAC, OID_SKGE_TRAP_RLMT_PORT_UP, PhysPortIndex);
 		(void)SK_DRIVER_SENDEVENT(pAC, IoC);
+
+		/* Bugfix for XMAC errata (#10620)*/
+		if (pAC->GIni.GIMacType == SK_MAC_XMAC){
+
+			/* Add incremental difference to offset (#10620)*/
+			(void)pAC->GIni.GIFunc.pFnMacStatistic(pAC, IoC, PhysPortIndex,
+				XM_RXE_SHT_ERR, &Val32);
+			
+			Value = (((SK_U64)pAC->Pnmi.Port[PhysPortIndex].
+				 CounterHigh[SK_PNMI_HRX_SHORTS] << 32) | (SK_U64)Val32);
+			pAC->Pnmi.Port[PhysPortIndex].CounterOffset[SK_PNMI_HRX_SHORTS] +=
+				Value - pAC->Pnmi.Port[PhysPortIndex].RxShortZeroMark;
+		}
+		
+		/* Tell VctStatus() that a link was up meanwhile. */
+		pAC->Pnmi.VctStatus[PhysPortIndex] |= SK_PNMI_VCT_LINK;		
 		break;
 
-	case SK_PNMI_EVT_RLMT_PORT_DOWN:
+    case SK_PNMI_EVT_RLMT_PORT_DOWN:
+		PhysPortIndex = (unsigned int)Param.Para32[0];
+
 #ifdef DEBUG
-		if ((unsigned int)Param.Para32[0] >= SK_MAX_MACS) {
+		if (PhysPortIndex >= SK_MAX_MACS) {
 
 			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
-				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_PORT_DOWN parameter wrong, PhysPortIndex=%d\n",
-				(unsigned int)Param.Para32[0]));
+				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_PORT_DOWN parameter"
+                 " wrong, PhysPortIndex=%d\n", PhysPortIndex));
 
 			return (0);
 		}
@@ -2449,14 +1805,24 @@
 		 * 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]);
+		QueueRlmtPortTrap(pAC, OID_SKGE_TRAP_RLMT_PORT_DOWN, PhysPortIndex);
 		(void)SK_DRIVER_SENDEVENT(pAC, IoC);
+        
+		/* Bugfix #10620 - get zero level for incremental difference */
+		if ((pAC->GIni.GIMacType == SK_MAC_XMAC)) {
+
+			(void)pAC->GIni.GIFunc.pFnMacStatistic(pAC, IoC, PhysPortIndex,
+				XM_RXE_SHT_ERR, &Val32);
+			pAC->Pnmi.Port[PhysPortIndex].RxShortZeroMark = 
+				(((SK_U64)pAC->Pnmi.Port[PhysPortIndex].
+				 CounterHigh[SK_PNMI_HRX_SHORTS] << 32) | (SK_U64)Val32);
+		}
 		break;
 
 	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) {
 
@@ -2512,7 +1878,7 @@
 		for (CounterIndex = 0; CounterIndex < SK_PNMI_MAX_IDX;
 			CounterIndex ++) {
 
-			if (!StatAddress[CounterIndex].GetOffset) {
+			if (!StatAddr[CounterIndex][MacType].GetOffset) {
 
 				continue;
 			}
@@ -2533,6 +1899,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) {
 
@@ -2599,7 +1966,7 @@
 		for (CounterIndex = 0; CounterIndex < SK_PNMI_MAX_IDX;
 			CounterIndex ++) {
 
-			if (!StatAddress[CounterIndex].GetOffset) {
+			if (!StatAddr[CounterIndex][MacType].GetOffset) {
 
 				continue;
 			}
@@ -2644,7 +2011,7 @@
 			return (SK_PNMI_ERR_UNKNOWN_NET);
 		}
 
-        if((unsigned int)Param.Para32[0] == 1){ /* single net mode */
+        if ((unsigned int)Param.Para32[0] == 1) { /* single net mode */
         	pAC->Pnmi.DualNetActiveFlag = SK_FALSE;
         }
         else { /* dual net mode */
@@ -2652,6 +2019,49 @@
         }
         break;
 
+    case SK_PNMI_EVT_VCT_RESET:
+	PhysPortIndex = Param.Para32[0];
+	pPrt = &pAC->GIni.GP[PhysPortIndex];
+	pVctBackupData = &pAC->Pnmi.VctBackup[PhysPortIndex];
+	
+	if (pAC->Pnmi.VctStatus[PhysPortIndex] & SK_PNMI_VCT_PENDING) {
+		RetCode = SkGmCableDiagStatus(pAC, IoC, PhysPortIndex, SK_FALSE);
+		if (RetCode == 2) {
+			/*
+			 * VCT test is still running.
+			 * Start VCT timer counter again.
+			 */
+			SK_MEMSET((char *) &Param, 0, sizeof(Param));
+			Param.Para32[0] = PhysPortIndex;
+			Param.Para32[1] = -1;
+			SkTimerStart(pAC, IoC, &pAC->Pnmi.VctTimeout[PhysPortIndex].VctTimer,
+				4000000, SKGE_PNMI, SK_PNMI_EVT_VCT_RESET, Param);
+			break;
+		}
+		pAC->Pnmi.VctStatus[PhysPortIndex] &= ~SK_PNMI_VCT_PENDING;
+		pAC->Pnmi.VctStatus[PhysPortIndex] |=
+			(SK_PNMI_VCT_NEW_VCT_DATA | SK_PNMI_VCT_TEST_DONE);
+		
+		/* Copy results for later use to PNMI struct. */
+		for (i = 0; i < 4; i++)  {
+			if (pPrt->PMdiPairLen[i] > 35) {
+				CableLength = 1000 * (((175 * pPrt->PMdiPairLen[i]) / 210) - 28);
+			}
+			else {
+				CableLength = 0;
+			}
+			pVctBackupData->PMdiPairLen[i] = CableLength;
+			pVctBackupData->PMdiPairSts[i] = pPrt->PMdiPairSts[i];
+		}
+		
+		Param.Para32[0] = PhysPortIndex;
+		Param.Para32[1] = -1;
+		SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_RESET, Param);
+		SkEventDispatcher(pAC, IoC);
+	}
+	
+	break;
+
 	default:
 		break;
 	}
@@ -2682,8 +2092,7 @@
  *	calling functions.
  *	SK_PNMI_ERR_UNKNOWN_NET  The requested NetIndex doesn't exist 
  */
-
-static int PnmiVar(
+PNMI_STATIC int PnmiVar(
 SK_AC *pAC,		/* Pointer to adapter context */
 SK_IOC IoC,		/* IO context handle */
 int Action,		/* Get/PreSet/Set action */
@@ -2738,8 +2147,7 @@
  *	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(
+PNMI_STATIC int PnmiStruct(
 SK_AC *pAC,		/* Pointer to adapter context */
 SK_IOC IoC,		/* IO context handle */
 int  Action,		/* Set action to be performed */
@@ -2802,10 +2210,10 @@
 	pAC->Pnmi.SirqUpdatedFlag ++;
 
 	/* Preset/Set values */
-	for (TableIndex = 0; TableIndex < sizeof(IdTable)/sizeof(IdTable[0]);
-		TableIndex ++) {
+	for (TableIndex = 0; TableIndex < ID_TABLE_SIZE; TableIndex ++) {
 
-		if (IdTable[TableIndex].Access != SK_PNMI_RW) {
+		if ((IdTable[TableIndex].Access != SK_PNMI_RW) &&
+			(IdTable[TableIndex].Access != SK_PNMI_WO)) {
 
 			continue;
 		}
@@ -2906,14 +2314,12 @@
  * Returns:
  *	The table index or -1 if not found.
  */
-
-static int LookupId(
+PNMI_STATIC int LookupId(
 SK_U32 Id)		/* Object identifier to be searched */
 {
 	int i;
-	int Len = sizeof(IdTable)/sizeof(IdTable[0]);
 
-	for (i=0; i<Len; i++) {
+	for (i = 0; i < ID_TABLE_SIZE; i++) {
 
 		if (IdTable[i].Id == Id) {
 
@@ -2945,8 +2351,7 @@
  *                               exist (e.g. port instance 3 on a two port
  *	                         adapter.
  */
-
-static int OidStruct(
+PNMI_STATIC int OidStruct(
 SK_AC *pAC,		/* Pointer to adapter context */
 SK_IOC IoC,		/* IO context handle */
 int Action,		/* Get/PreSet/Set action */
@@ -3013,8 +2418,7 @@
  *                               exist (e.g. port instance 3 on a two port
  *	                         adapter.
  */
-
-static int Perform(
+PNMI_STATIC int Perform(
 SK_AC *pAC,		/* Pointer to adapter context */
 SK_IOC IoC,		/* IO context handle */
 int Action,		/* Get/PreSet/Set action */
@@ -3145,8 +2549,7 @@
  *                               exist (e.g. port instance 3 on a two port
  *	                         adapter.
  */
-
-static int Mac8023Stat(
+PNMI_STATIC int Mac8023Stat(
 SK_AC *pAC,		/* Pointer to adapter context */
 SK_IOC IoC,		/* IO context handle */
 int Action,		/* Get/PreSet/Set action */
@@ -3157,8 +2560,9 @@
 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;
+	int     Ret;
+	SK_U64  StatVal;
+	SK_U32  StatVal32;
 	SK_BOOL Is64BitReq = SK_FALSE;
 
 	/*
@@ -3254,7 +2658,6 @@
 		 * by default 32bit values are evaluated
 		 */
 		if (!Is64BitReq) {
-			SK_U32	StatVal32;
 			StatVal32 = (SK_U32)StatVal;
 			SK_PNMI_STORE_U32(pBuf, StatVal32);
 			*pLen = sizeof(SK_U32);
@@ -3288,8 +2691,7 @@
  *                               exist (e.g. port instance 3 on a two port
  *	                         adapter.
  */
-
-static int MacPrivateStat(
+PNMI_STATIC int MacPrivateStat(
 SK_AC *pAC,		/* Pointer to adapter context */
 SK_IOC IoC,		/* IO context handle */
 int Action,		/* Get/PreSet/Set action */
@@ -3305,8 +2707,8 @@
 	unsigned int	PhysPortMax;
 	unsigned int	Limit;
 	unsigned int	Offset;
-	int		Ret;
-	SK_U64		StatVal;
+	int				Ret;
+	SK_U64			StatVal;
 
 
 	/*
@@ -3316,7 +2718,7 @@
 	PhysPortMax = pAC->GIni.GIMacsFound;
 	LogPortMax = SK_PNMI_PORT_PHYS2LOG(PhysPortMax);
 
-	if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){ /* Dual net mode */
+	if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { /* Dual net mode */
 		LogPortMax--;
 	}
 
@@ -3384,17 +2786,43 @@
 		case OID_SKGE_STAT_RX_UTIL:
 			return (SK_PNMI_ERR_GENERAL);
 */
-		/*
-		 * Frames longer than IEEE 802.3 frame max size are counted
-		 * by XMAC in frame_too_long counter even reception of long
-		 * frames was enabled and the frame was correct.
-		 * So correct the value by subtracting RxLongFrame counter.
-		 */
-		case OID_SKGE_STAT_RX_TOO_LONG:
-			StatVal = GetStatVal(pAC, IoC, LogPortIndex,
-					     IdTable[TableIndex].Param, NetIndex) -
-				GetStatVal(pAC, IoC, LogPortIndex,
-					   SK_PNMI_HRX_LONGFRAMES, NetIndex);
+		case OID_SKGE_STAT_RX:
+		case OID_SKGE_STAT_TX:
+			switch (pAC->GIni.GIMacType) {
+			case SK_MAC_XMAC:
+				StatVal = GetStatVal(pAC, IoC, LogPortIndex,
+					IdTable[TableIndex].Param, NetIndex);
+				break;
+
+			case SK_MAC_GMAC:
+				if (Id == OID_SKGE_STAT_TX) {
+
+					StatVal =
+						GetStatVal(pAC, IoC, LogPortIndex,
+								   SK_PNMI_HTX_BROADCAST, NetIndex) +
+						GetStatVal(pAC, IoC, LogPortIndex,
+								   SK_PNMI_HTX_MULTICAST, NetIndex) +
+						GetStatVal(pAC, IoC, LogPortIndex,
+								   SK_PNMI_HTX_UNICAST, NetIndex);
+				}
+				else {
+					StatVal =
+						GetStatVal(pAC, IoC, LogPortIndex,
+								   SK_PNMI_HRX_BROADCAST, NetIndex) +
+						GetStatVal(pAC, IoC, LogPortIndex,
+								   SK_PNMI_HRX_MULTICAST, NetIndex) +
+						GetStatVal(pAC, IoC, LogPortIndex,
+								   SK_PNMI_HRX_UNICAST, NetIndex) +
+						GetStatVal(pAC, IoC, LogPortIndex,
+								   SK_PNMI_HRX_UNDERSIZE, NetIndex);
+				}
+				break;
+
+			default:
+				StatVal = 0;
+				break;
+			}
+
 			SK_PNMI_STORE_U64(pBuf + Offset, StatVal);
 			break;
 
@@ -3438,8 +2866,7 @@
  *                               exist (e.g. port instance 3 on a two port
  *	                         adapter.
  */
-
-static int Addr(
+PNMI_STATIC int Addr(
 SK_AC *pAC,		/* Pointer to adapter context */
 SK_IOC IoC,		/* IO context handle */
 int Action,		/* Get/PreSet/Set action */
@@ -3458,8 +2885,6 @@
 	unsigned int	Limit;
 	unsigned int	Offset = 0;
 
-
-
 	/*
 	 * Calculate instance if wished. MAC index 0 is the virtual
 	 * MAC.
@@ -3467,7 +2892,7 @@
 	PhysPortMax = pAC->GIni.GIMacsFound;
 	LogPortMax = SK_PNMI_PORT_PHYS2LOG(PhysPortMax);
 
-	if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){ /* Dual net mode */
+	if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { /* Dual net mode */
 		LogPortMax--;
 	}
 
@@ -3647,8 +3072,7 @@
  *                               exist (e.g. port instance 3 on a two port
  *	                         adapter.
  */
-
-static int CsumStat(
+PNMI_STATIC int CsumStat(
 SK_AC *pAC,		/* Pointer to adapter context */
 SK_IOC IoC,		/* IO context handle */
 int Action,		/* Get/PreSet/Set action */
@@ -3766,8 +3190,7 @@
  *                               exist (e.g. port instance 3 on a two port
  *	                         adapter.
  */
-
-static int SensorStat(
+PNMI_STATIC int SensorStat(
 SK_AC *pAC,		/* Pointer to adapter context */
 SK_IOC IoC,		/* IO context handle */
 int Action,		/* Get/PreSet/Set action */
@@ -3976,8 +3399,8 @@
 			break;
 
 		default:
-			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR013,
-				SK_PNMI_ERR013MSG);
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_ERR,
+				("SensorStat: Unknown OID should be handled before"));
 
 			return (SK_PNMI_ERR_GENERAL);
 		}
@@ -4014,8 +3437,7 @@
  *                               exist (e.g. port instance 3 on a two port
  *	                         adapter.
  */
-
-static int Vpd(
+PNMI_STATIC int Vpd(
 SK_AC *pAC,		/* Pointer to adapter context */
 SK_IOC IoC,		/* IO context handle */
 int Action,		/* Get/PreSet/Set action */
@@ -4490,8 +3912,7 @@
  *                               exist (e.g. port instance 3 on a two port
  *	                         adapter.
  */
-
-static int General(
+PNMI_STATIC int General(
 SK_AC *pAC,		/* Pointer to adapter context */
 SK_IOC IoC,		/* IO context handle */
 int Action,		/* Get/PreSet/Set action */
@@ -4515,7 +3936,7 @@
 	SK_U64		Val64TxHwErrs = 0;
 	SK_BOOL		Is64BitReq = SK_FALSE;
 	char		Buf[256];
-
+	int			MacType;
 
 	/*
 	 * Check instance. We only handle single instance variables
@@ -4534,7 +3955,9 @@
 		*pLen = 0;
 		return (SK_PNMI_ERR_READ_ONLY);
 	}
-
+	
+	MacType = pAC->GIni.GIMacType;
+	
 	/*
 	 * Check length for the various supported OIDs
 	 */
@@ -4669,8 +4092,7 @@
 				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_TOO_LONG, NetIndex) +
 				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_FCS, NetIndex) +
 				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_CEXT, NetIndex);
 	        break;
@@ -4682,8 +4104,7 @@
 				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);
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_CARRIER, NetIndex);
 			break;
 		}
 	}
@@ -4694,7 +4115,7 @@
 	switch (Id) {
 
 	case OID_SKGE_SUPPORTED_LIST:
-		Len = sizeof(IdTable)/sizeof(IdTable[0]) * sizeof(SK_U32);
+		Len = ID_TABLE_SIZE * sizeof(SK_U32);
 		if (*pLen < Len) {
 
 			*pLen = Len;
@@ -4833,7 +4254,7 @@
 		break;
 
 	case OID_SKGE_CHIPSET:
-		Val16 = SK_PNMI_CHIPSET;
+		Val16 = pAC->Pnmi.Chipset;
 		SK_PNMI_STORE_U16(pBuf, Val16);
 		*pLen = sizeof(SK_U16);
 		break;
@@ -4895,141 +4316,281 @@
 		break;
 
 	case OID_SKGE_TX_SW_QUEUE_LEN:
-		/* Dual net mode */
-		if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){
-			Val64 = pAC->Pnmi.Port[NetIndex].TxSwQueueLen;
+		/* 2002-09-17 pweber: For XMAC, use the frozen sw counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.BufPort[NetIndex].TxSwQueueLen;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.BufPort[0].TxSwQueueLen +
+					pAC->Pnmi.BufPort[1].TxSwQueueLen;
+			}			
 		}
-		/* Single net mode */
 		else {
-			Val64 =  pAC->Pnmi.Port[0].TxSwQueueLen +
-				pAC->Pnmi.Port[1].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:
-		/* Dual net mode */
-		if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){
-			Val64 = pAC->Pnmi.Port[NetIndex].TxSwQueueMax;
+		/* 2002-09-17 pweber: For XMAC, use the frozen sw counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.BufPort[NetIndex].TxSwQueueMax;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.BufPort[0].TxSwQueueMax +
+					pAC->Pnmi.BufPort[1].TxSwQueueMax;
+			}
 		}
-		/* Single net mode */
 		else {
-			Val64 = pAC->Pnmi.Port[0].TxSwQueueMax +
-				pAC->Pnmi.Port[1].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:
-		/* Dual net mode */
-		if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){
-			Val64 = pAC->Pnmi.Port[NetIndex].TxRetryCts;
+		/* 2002-09-17 pweber: For XMAC, use the frozen sw counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.BufPort[NetIndex].TxRetryCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.BufPort[0].TxRetryCts +
+					pAC->Pnmi.BufPort[1].TxRetryCts;
+			}
 		}
-		/* Single net mode */
 		else {
-			Val64 = pAC->Pnmi.Port[0].TxRetryCts +
-				pAC->Pnmi.Port[1].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:
-		/* Dual net mode */
-		if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){
-			Val64 = pAC->Pnmi.Port[NetIndex].RxIntrCts;
+		/* 2002-09-17 pweber: For XMAC, use the frozen sw counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.BufPort[NetIndex].RxIntrCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.BufPort[0].RxIntrCts +
+					pAC->Pnmi.BufPort[1].RxIntrCts;
+			}
 		}
-		/* Single net mode */
 		else {
-			Val64 = pAC->Pnmi.Port[0].RxIntrCts +
-				pAC->Pnmi.Port[1].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:
-		/* Dual net mode */
-		if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){
-			Val64 = pAC->Pnmi.Port[NetIndex].TxIntrCts;
+		/* 2002-09-17 pweber: For XMAC, use the frozen sw counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.BufPort[NetIndex].TxIntrCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.BufPort[0].TxIntrCts +
+					pAC->Pnmi.BufPort[1].TxIntrCts;
+			}
 		}
-		/* Single net mode */
 		else {
-			Val64 = pAC->Pnmi.Port[0].TxIntrCts +
-				pAC->Pnmi.Port[1].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:
-		/* Dual net mode */
-		if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){
-			Val64 = pAC->Pnmi.Port[NetIndex].RxNoBufCts;
+		/* 2002-09-17 pweber: For XMAC, use the frozen sw counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.BufPort[NetIndex].RxNoBufCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.BufPort[0].RxNoBufCts +
+					pAC->Pnmi.BufPort[1].RxNoBufCts;
+			}
 		}
-		/* Single net mode */
 		else {
-			Val64 = pAC->Pnmi.Port[0].RxNoBufCts +
-				pAC->Pnmi.Port[1].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:
-		/* Dual net mode */
-		if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){
-			Val64 = pAC->Pnmi.Port[NetIndex].TxNoBufCts;
+		/* 2002-09-17 pweber: For XMAC, use the frozen sw counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.BufPort[NetIndex].TxNoBufCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.BufPort[0].TxNoBufCts +
+					pAC->Pnmi.BufPort[1].TxNoBufCts;
+			}
 		}
-		/* Single net mode */
 		else {
-			Val64 = pAC->Pnmi.Port[0].TxNoBufCts +
-				pAC->Pnmi.Port[1].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:
-		/* Dual net mode */
-		if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){
-			Val64 = pAC->Pnmi.Port[NetIndex].TxUsedDescrNo;
+		/* 2002-09-17 pweber: For XMAC, use the frozen sw counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.BufPort[NetIndex].TxUsedDescrNo;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.BufPort[0].TxUsedDescrNo +
+					pAC->Pnmi.BufPort[1].TxUsedDescrNo;
+			}
 		}
-		/* Single net mode */
 		else {
-			Val64 = pAC->Pnmi.Port[0].TxUsedDescrNo +
-				pAC->Pnmi.Port[1].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:
-		/* Dual net mode */
-		if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){
-			Val64 = pAC->Pnmi.Port[NetIndex].RxDeliveredCts;
+		/* 2002-09-17 pweber: For XMAC, use the frozen sw counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.BufPort[NetIndex].RxDeliveredCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.BufPort[0].RxDeliveredCts +
+					pAC->Pnmi.BufPort[1].RxDeliveredCts;
+			}
 		}
-		/* Single net mode */
 		else {
-			Val64 = pAC->Pnmi.Port[0].RxDeliveredCts +
-				pAC->Pnmi.Port[1].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:
-		/* Dual net mode */
-		if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){
-			Val64 = pAC->Pnmi.Port[NetIndex].RxOctetsDeliveredCts;
+		/* 2002-09-17 pweber: For XMAC, use the frozen sw counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.BufPort[NetIndex].RxOctetsDeliveredCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.BufPort[0].RxOctetsDeliveredCts +
+					pAC->Pnmi.BufPort[1].RxOctetsDeliveredCts;
+			}
 		}
-		/* Single net mode */
 		else {
-			Val64 = pAC->Pnmi.Port[0].RxOctetsDeliveredCts +
-				pAC->Pnmi.Port[1].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);
@@ -5046,44 +4607,88 @@
 		break;
 
 	case OID_SKGE_IN_ERRORS_CTS:
-		/* Dual net mode */
-		if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){
-			Val64 = Val64RxHwErrs + pAC->Pnmi.Port[NetIndex].RxNoBufCts;
+		/* 2002-09-17 pweber: For XMAC, use the frozen sw counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = Val64RxHwErrs + pAC->Pnmi.BufPort[NetIndex].RxNoBufCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = Val64RxHwErrs + 
+					pAC->Pnmi.BufPort[0].RxNoBufCts +
+					pAC->Pnmi.BufPort[1].RxNoBufCts;
+			}
 		}
-		/* Single net mode */
 		else {
-			Val64 = Val64RxHwErrs + 
-				pAC->Pnmi.Port[0].RxNoBufCts +
-				pAC->Pnmi.Port[1].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:
-		/* Dual net mode */
-		if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){
-			Val64 = Val64TxHwErrs + pAC->Pnmi.Port[NetIndex].TxNoBufCts;
+		/* 2002-09-17 pweber: For XMAC, use the frozen sw counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = Val64TxHwErrs + pAC->Pnmi.BufPort[NetIndex].TxNoBufCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = Val64TxHwErrs + 
+					pAC->Pnmi.BufPort[0].TxNoBufCts +
+					pAC->Pnmi.BufPort[1].TxNoBufCts;
+			}
 		}
-		/* Single net mode */
 		else {
-			Val64 = Val64TxHwErrs + 
-				pAC->Pnmi.Port[0].TxNoBufCts +
-				pAC->Pnmi.Port[1].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:
-		/* Dual net mode */
-		if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){
-			Val64 = pAC->Pnmi.Port[NetIndex].ErrRecoveryCts;
+		/* 2002-09-17 pweber: For XMAC, use the frozen sw counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.BufPort[NetIndex].ErrRecoveryCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.BufPort[0].ErrRecoveryCts +
+					pAC->Pnmi.BufPort[1].ErrRecoveryCts;
+			}
 		}
-		/* Single net mode */
 		else {
-			Val64 = pAC->Pnmi.Port[0].ErrRecoveryCts +
-				pAC->Pnmi.Port[1].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);
@@ -5103,7 +4708,13 @@
 		break;
 
 	case OID_GEN_RCV_ERROR:
-		Val64 = Val64RxHwErrs + pAC->Pnmi.Port[NetIndex].RxNoBufCts;
+		/* 2002-09-17 pweber: For XMAC, use the frozen sw counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			Val64 = Val64RxHwErrs + pAC->Pnmi.BufPort[NetIndex].RxNoBufCts;
+		}
+		else {
+			Val64 = Val64RxHwErrs + pAC->Pnmi.Port[NetIndex].RxNoBufCts;
+		}
 
 		/*
 		 * by default 32bit values are evaluated
@@ -5120,7 +4731,13 @@
 		break;
 
 	case OID_GEN_XMIT_ERROR:
-		Val64 = Val64TxHwErrs + pAC->Pnmi.Port[NetIndex].TxNoBufCts;
+		/* 2002-09-17 pweber: For XMAC, use the frozen sw counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			Val64 = Val64TxHwErrs + pAC->Pnmi.BufPort[NetIndex].TxNoBufCts;
+		}
+		else {
+			Val64 = Val64TxHwErrs + pAC->Pnmi.Port[NetIndex].TxNoBufCts;
+		}
 
 		/*
 		 * by default 32bit values are evaluated
@@ -5137,7 +4754,13 @@
 		break;
 
 	case OID_GEN_RCV_NO_BUFFER:
-		Val64 = pAC->Pnmi.Port[NetIndex].RxNoBufCts;
+		/* 2002-09-17 pweber: For XMAC, use the frozen sw counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			Val64 = pAC->Pnmi.BufPort[NetIndex].RxNoBufCts;
+		}
+		else {
+			Val64 = pAC->Pnmi.Port[NetIndex].RxNoBufCts;
+		}
 
 		/*
 		 * by default 32bit values are evaluated
@@ -5200,8 +4823,7 @@
  *                               exist (e.g. port instance 3 on a two port
  *	                         adapter.
  */
-
-static int Rlmt(
+PNMI_STATIC int Rlmt(
 SK_AC *pAC,		/* Pointer to adapter context */
 SK_IOC IoC,		/* IO context handle */
 int Action,		/* Get/PreSet/Set action */
@@ -5359,8 +4981,8 @@
 			break;
 
 		default:
-			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR036,
-				SK_PNMI_ERR036MSG);
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_ERR,
+				("Rlmt: Unknown OID should be handled before"));
 
 			pAC->Pnmi.RlmtUpdatedFlag --;
 			*pLen = 0;
@@ -5506,8 +5128,7 @@
  *                               exist (e.g. port instance 3 on a two port
  *	                         adapter.
  */
-
-static int RlmtStat(
+PNMI_STATIC int RlmtStat(
 SK_AC *pAC,		/* Pointer to adapter context */
 SK_IOC IoC,		/* IO context handle */
 int Action,		/* Get/PreSet/Set action */
@@ -5543,7 +5164,7 @@
 		PhysPortIndex = Instance - 1;
 
 		/* Dual net mode */
-		if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){
+		if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
 			PhysPortIndex = NetIndex;
 		}
 
@@ -5556,7 +5177,7 @@
 		Limit = PhysPortMax;
 
 		/* Dual net mode */
-		if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){
+		if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
 			PhysPortIndex = NetIndex;
 			Limit = PhysPortIndex + 1;
 		}
@@ -5674,8 +5295,8 @@
 			break;
 
 		default:
-			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR040,
-				SK_PNMI_ERR040MSG);
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_ERR,
+				("RlmtStat: Unknown OID should be errored before"));
 
 			pAC->Pnmi.RlmtUpdatedFlag --;
 			*pLen = 0;
@@ -5709,8 +5330,7 @@
  *                               exist (e.g. port instance 3 on a two port
  *	                         adapter.
  */
-
-static int MacPrivateConf(
+PNMI_STATIC int MacPrivateConf(
 SK_AC *pAC,		/* Pointer to adapter context */
 SK_IOC IoC,		/* IO context handle */
 int Action,		/* Get/PreSet/Set action */
@@ -5740,7 +5360,7 @@
 	PhysPortMax = pAC->GIni.GIMacsFound;
 	LogPortMax = SK_PNMI_PORT_PHYS2LOG(PhysPortMax);
 
-	if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){ /* Dual net mode */
+	if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { /* Dual net mode */
 		LogPortMax--;
 	}
 
@@ -5783,6 +5403,9 @@
 		case OID_SKGE_PHY_OPERATION_CAP:
 		case OID_SKGE_PHY_OPERATION_MODE:
 		case OID_SKGE_PHY_OPERATION_STATUS:
+		case OID_SKGE_SPEED_CAP:
+		case OID_SKGE_SPEED_MODE:
+		case OID_SKGE_SPEED_STATUS:
 			if (*pLen < (Limit - LogPortIndex) * sizeof(SK_U8)) {
 
 				*pLen = (Limit - LogPortIndex) *
@@ -5836,188 +5459,327 @@
 				break;
 
 			case OID_SKGE_LINK_CAP:
-				if (LogPortIndex == 0) {
+				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+					if (LogPortIndex == 0) {
+	
+						/* Get value for virtual port */
+						VirtualConf(pAC, IoC, Id, pBuf +
+							Offset);
+					}
+					else {
+						/* Get value for physical ports */
+						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+							pAC, LogPortIndex);
 
-					/* Get value for virtual port */
-					VirtualConf(pAC, IoC, Id, pBuf +
-						Offset);
+						*(pBuf + Offset) = pAC->GIni.GP[
+							PhysPortIndex].PLinkCap;
+					}
+					Offset += sizeof(char);
 				}
-				else {
-					/* Get value for physical ports */
-					PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
-						pAC, LogPortIndex);
-
-					*(pBuf + Offset) = pAC->GIni.GP[
-						PhysPortIndex].PLinkCap;
+				else { /* DualNetMode */
+					
+					*(pBuf + Offset) = pAC->GIni.GP[NetIndex].PLinkCap;
+					Offset += sizeof(char);
 				}
-				Offset += sizeof(char);
 				break;
 
 			case OID_SKGE_LINK_MODE:
-				if (LogPortIndex == 0) {
-
-					/* Get value for virtual port */
-					VirtualConf(pAC, IoC, Id, pBuf +
+				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+					if (LogPortIndex == 0) {
+	
+						/* Get value for virtual port */
+						VirtualConf(pAC, IoC, Id, pBuf +
 						Offset);
-				}
-				else {
-					/* Get value for physical ports */
-					PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
-						pAC, LogPortIndex);
+					}
+					else {
+						/* Get value for physical ports */
+						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+							pAC, LogPortIndex);
 
-					*(pBuf + Offset) = pAC->GIni.GP[
-						PhysPortIndex].PLinkModeConf;
+						*(pBuf + Offset) = pAC->GIni.GP[
+							PhysPortIndex].PLinkModeConf;
+					}
+					Offset += sizeof(char);
+				}
+				else { /* DualNetMode */ 
+				
+					*(pBuf + Offset) = pAC->GIni.GP[NetIndex].PLinkModeConf;
+					Offset += sizeof(char);
 				}
-
-				Offset += sizeof(char);
 				break;
 
 			case OID_SKGE_LINK_MODE_STATUS:
-				if (LogPortIndex == 0) {
-
-					/* Get value for virtual port */
-					VirtualConf(pAC, IoC, Id, pBuf +
-						Offset);
+				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+					if (LogPortIndex == 0) {
+	
+						/* Get value for virtual port */
+						VirtualConf(pAC, IoC, Id, pBuf +
+							Offset);
+					}
+					else {
+						/* Get value for physical port */
+						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+							pAC, LogPortIndex);
+
+						*(pBuf + Offset) =
+							CalculateLinkModeStatus(pAC,
+								IoC, PhysPortIndex);
+					}
+					Offset += sizeof(char);
 				}
-				else {
-					/* Get value for physical port */
-					PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
-						pAC, LogPortIndex);
-
-					*(pBuf + Offset) =
-						CalculateLinkModeStatus(pAC,
-							IoC, PhysPortIndex);
+				else { /* DualNetMode */
+					*(pBuf + Offset) = CalculateLinkModeStatus(pAC, IoC, NetIndex);
+					Offset += sizeof(char);
 				}
-				Offset += sizeof(char);
 				break;
 
 			case OID_SKGE_LINK_STATUS:
-				if (LogPortIndex == 0) {
-
-					/* Get value for virtual port */
-					VirtualConf(pAC, IoC, Id, pBuf +
-						Offset);
+				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+					if (LogPortIndex == 0) {
+	
+						/* Get value for virtual port */
+						VirtualConf(pAC, IoC, Id, pBuf +
+							Offset);
+					}
+					else {
+						/* Get value for physical ports */
+						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+							pAC, LogPortIndex);
+	
+						*(pBuf + Offset) =
+							CalculateLinkStatus(pAC,
+								IoC, PhysPortIndex);
+					}
+					Offset += sizeof(char);
 				}
-				else {
-					/* Get value for physical ports */
-					PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
-						pAC, LogPortIndex);
+				else { /* DualNetMode */
 
-					*(pBuf + Offset) =
-						CalculateLinkStatus(pAC,
-							IoC, PhysPortIndex);
+					*(pBuf + Offset) = CalculateLinkStatus(pAC, IoC, NetIndex);
+					Offset += sizeof(char);
 				}
-				Offset += sizeof(char);
 				break;
 
 			case OID_SKGE_FLOWCTRL_CAP:
-				if (LogPortIndex == 0) {
-
-					/* Get value for virtual port */
-					VirtualConf(pAC, IoC, Id, pBuf +
-						Offset);
+				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+					if (LogPortIndex == 0) {
+	
+						/* Get value for virtual port */
+						VirtualConf(pAC, IoC, Id, pBuf +
+							Offset);
+					}
+					else {
+						/* Get value for physical ports */
+						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+							pAC, LogPortIndex);
+	
+						*(pBuf + Offset) = pAC->GIni.GP[
+							PhysPortIndex].PFlowCtrlCap;
+					}
+					Offset += sizeof(char);
 				}
-				else {
-					/* Get value for physical ports */
-					PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
-						pAC, LogPortIndex);
-
-					*(pBuf + Offset) = pAC->GIni.GP[
-						PhysPortIndex].PFlowCtrlCap;
+				else { /* DualNetMode */
+				
+					*(pBuf + Offset) = pAC->GIni.GP[NetIndex].PFlowCtrlCap;
+					Offset += sizeof(char);
 				}
-				Offset += sizeof(char);
 				break;
 
 			case OID_SKGE_FLOWCTRL_MODE:
-				if (LogPortIndex == 0) {
-
-					/* Get value for virtual port */
-					VirtualConf(pAC, IoC, Id, pBuf +
-						Offset);
+				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+					if (LogPortIndex == 0) {
+	
+						/* Get value for virtual port */
+						VirtualConf(pAC, IoC, Id, pBuf +
+							Offset);
+					}
+					else {
+						/* Get value for physical port */
+						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+							pAC, LogPortIndex);
+	
+						*(pBuf + Offset) = pAC->GIni.GP[
+							PhysPortIndex].PFlowCtrlMode;
+					}
+					Offset += sizeof(char);
 				}
-				else {
-					/* Get value for physical port */
-					PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
-						pAC, LogPortIndex);
+				else { /* DualNetMode */
 
-					*(pBuf + Offset) = pAC->GIni.GP[
-						PhysPortIndex].PFlowCtrlMode;
+					*(pBuf + Offset) = pAC->GIni.GP[NetIndex].PFlowCtrlMode;
+					Offset += sizeof(char);
 				}
-				Offset += sizeof(char);
 				break;
 
 			case OID_SKGE_FLOWCTRL_STATUS:
-				if (LogPortIndex == 0) {
-
-					/* Get value for virtual port */
-					VirtualConf(pAC, IoC, Id, pBuf +
-						Offset);
+				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+					if (LogPortIndex == 0) {
+	
+						/* Get value for virtual port */
+						VirtualConf(pAC, IoC, Id, pBuf +
+							Offset);
+					}
+					else {
+						/* Get value for physical port */
+						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+							pAC, LogPortIndex);
+	
+						*(pBuf + Offset) = pAC->GIni.GP[
+							PhysPortIndex].PFlowCtrlStatus;
+					}
+					Offset += sizeof(char);
 				}
-				else {
-					/* Get value for physical port */
-					PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
-						pAC, LogPortIndex);
+				else { /* DualNetMode */
 
-					*(pBuf + Offset) = pAC->GIni.GP[
-						PhysPortIndex].PFlowCtrlStatus;
+					*(pBuf + Offset) = pAC->GIni.GP[NetIndex].PFlowCtrlStatus;
+					Offset += sizeof(char);
 				}
-				Offset += sizeof(char);
 				break;
 
 			case OID_SKGE_PHY_OPERATION_CAP:
-				if (LogPortIndex == 0) {
-
-					/* Get value for virtual port */
-					VirtualConf(pAC, IoC, Id, pBuf +
-						Offset);
+				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+					if (LogPortIndex == 0) {
+	
+						/* Get value for virtual port */
+						VirtualConf(pAC, IoC, Id, pBuf +
+							Offset);
+					}
+					else {
+						/* Get value for physical ports */
+						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+							pAC, LogPortIndex);
+	
+						*(pBuf + Offset) = pAC->GIni.GP[
+							PhysPortIndex].PMSCap;
+					}
+					Offset += sizeof(char);
 				}
-				else {
-					/* Get value for physical ports */
-					PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
-						pAC, LogPortIndex);
-
-					*(pBuf + Offset) = pAC->GIni.GP[
-						PhysPortIndex].PMSCap;
+				else { /* DualNetMode */
+				
+					*(pBuf + Offset) = pAC->GIni.GP[NetIndex].PMSCap;
+					Offset += sizeof(char);
 				}
-				Offset += sizeof(char);
 				break;
 
 			case OID_SKGE_PHY_OPERATION_MODE:
-				if (LogPortIndex == 0) {
+				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+					if (LogPortIndex == 0) {
 
-					/* Get value for virtual port */
-					VirtualConf(pAC, IoC, Id, pBuf +
-						Offset);
-				}
-				else {
-					/* Get value for physical port */
-					PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
-						pAC, LogPortIndex);
+						/* Get value for virtual port */
+						VirtualConf(pAC, IoC, Id, pBuf + Offset);
+					}
+					else {
+						/* Get value for physical port */
+						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+							pAC, LogPortIndex);
 
-					*(pBuf + Offset) = pAC->GIni.GP[
-						PhysPortIndex].PMSMode;
+						*(pBuf + Offset) = pAC->GIni.GP[
+							PhysPortIndex].PMSMode;
+					}
+					Offset += sizeof(char);
+				}
+				else { /* DualNetMode */
+				
+					*(pBuf + Offset) = pAC->GIni.GP[NetIndex].PMSMode;
+					Offset += sizeof(char);
 				}
-				Offset += sizeof(char);
 				break;
 
 			case OID_SKGE_PHY_OPERATION_STATUS:
-				if (LogPortIndex == 0) {
+				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+					if (LogPortIndex == 0) {
 
-					/* Get value for virtual port */
-					VirtualConf(pAC, IoC, Id, pBuf +
-						Offset);
+						/* Get value for virtual port */
+						VirtualConf(pAC, IoC, Id, pBuf + Offset);
+					}
+					else {
+						/* Get value for physical port */
+						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+							pAC, LogPortIndex);
+	
+						*(pBuf + Offset) = pAC->GIni.GP[
+							PhysPortIndex].PMSStatus;
+					}
+					Offset += sizeof(char);
 				}
 				else {
-					/* Get value for physical port */
-					PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
-						pAC, LogPortIndex);
+				
+					*(pBuf + Offset) = pAC->GIni.GP[NetIndex].PMSStatus;
+					Offset += sizeof(char);
+				}
+				break;
+
+			case OID_SKGE_SPEED_CAP:
+				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+					if (LogPortIndex == 0) {
+	
+						/* Get value for virtual port */
+						VirtualConf(pAC, IoC, Id, pBuf +
+							Offset);
+					}
+					else {
+						/* Get value for physical ports */
+						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+							pAC, LogPortIndex);
+	
+						*(pBuf + Offset) = pAC->GIni.GP[
+							PhysPortIndex].PLinkSpeedCap;
+					}
+					Offset += sizeof(char);
+				}
+				else { /* DualNetMode */
+				
+					*(pBuf + Offset) = pAC->GIni.GP[NetIndex].PLinkSpeedCap;
+					Offset += sizeof(char);
+				}
+				break;
+
+			case OID_SKGE_SPEED_MODE:
+				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+					if (LogPortIndex == 0) {
+	
+						/* Get value for virtual port */
+						VirtualConf(pAC, IoC, Id, pBuf + Offset);
+					}
+					else {
+						/* Get value for physical port */
+						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+							pAC, LogPortIndex);
+	
+						*(pBuf + Offset) = pAC->GIni.GP[
+							PhysPortIndex].PLinkSpeed;
+					}
+					Offset += sizeof(char);
+				}
+				else { /* DualNetMode */
 
-					*(pBuf + Offset) = pAC->GIni.GP[
-						PhysPortIndex].PMSStatus;
+					*(pBuf + Offset) = pAC->GIni.GP[NetIndex].PLinkSpeed;
+					Offset += sizeof(char);
 				}
-				Offset += sizeof(char);
 				break;
 
+			case OID_SKGE_SPEED_STATUS:
+				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+					if (LogPortIndex == 0) {
+	
+						/* Get value for virtual port */
+						VirtualConf(pAC, IoC, Id, pBuf + Offset);
+					}
+					else {
+						/* Get value for physical port */
+						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+							pAC, LogPortIndex);
+	
+						*(pBuf + Offset) = pAC->GIni.GP[
+							PhysPortIndex].PLinkSpeedUsed;
+					}
+					Offset += sizeof(char);
+				}
+				else { /* DualNetMode */
+
+					*(pBuf + Offset) = pAC->GIni.GP[NetIndex].PLinkSpeedUsed;
+					Offset += sizeof(char);
+				}
+				break;
+			
 			case OID_SKGE_MTU:
 				Val32 = SK_DRIVER_GET_MTU(pAC, IoC, NetIndex);
 				SK_PNMI_STORE_U32(pBuf + Offset, Val32);
@@ -6025,8 +5787,8 @@
 				break;
 
 			default:
-				SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR042,
-					SK_PNMI_ERR042MSG);
+				SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_ERR,
+					("MacPrivateConf: Unknown OID should be handled before"));
 
 				pAC->Pnmi.SirqUpdatedFlag --;
 				return (SK_PNMI_ERR_GENERAL);
@@ -6047,6 +5809,7 @@
 	case OID_SKGE_LINK_MODE:
 	case OID_SKGE_FLOWCTRL_MODE:
 	case OID_SKGE_PHY_OPERATION_MODE:
+	case OID_SKGE_SPEED_MODE:
 		if (*pLen < Limit - LogPortIndex) {
 
 			*pLen = Limit - LogPortIndex;
@@ -6284,8 +6047,8 @@
 						EventParam) > 0) {
 
 						SK_ERR_LOG(pAC, SK_ERRCL_SW,
-							SK_PNMI_ERR052,
-							SK_PNMI_ERR052MSG);
+							SK_PNMI_ERR042,
+							SK_PNMI_ERR042MSG);
 
 						*pLen = 0;
 						return (SK_PNMI_ERR_GENERAL);
@@ -6304,8 +6067,8 @@
 					SK_HWEV_SET_ROLE, EventParam) > 0) {
 
 					SK_ERR_LOG(pAC, SK_ERRCL_SW,
-						SK_PNMI_ERR052,
-						SK_PNMI_ERR052MSG);
+						SK_PNMI_ERR042,
+						SK_PNMI_ERR042MSG);
 
 					*pLen = 0;
 					return (SK_PNMI_ERR_GENERAL);
@@ -6315,6 +6078,82 @@
 			Offset += sizeof(char);
 			break;
 
+		case OID_SKGE_SPEED_MODE:
+			/* Check the value range */
+			Val8 = *(pBuf + Offset);
+			if (Val8 == 0) {
+
+				Offset += sizeof(char);
+				break;
+			}
+			if (Val8 < (SK_LSPEED_AUTO) ||
+				(LogPortIndex != 0 && Val8 > (SK_LSPEED_1000MBPS)) ||
+				(LogPortIndex == 0 && Val8 > (SK_LSPEED_INDETERMINATED))) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_BAD_VALUE);
+			}
+
+			/* The preset ends here */
+			if (Action == SK_PNMI_PRESET) {
+
+				return (SK_PNMI_ERR_OK);
+			}
+
+			if (LogPortIndex == 0) {
+
+				/*
+				 * The virtual port consists of all currently
+				 * active ports. Find them and send an event
+				 * with the new flow control mode to SIRQ.
+				 */
+				for (PhysPortIndex = 0;
+					PhysPortIndex < PhysPortMax;
+					PhysPortIndex ++) {
+
+					if (!pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {
+
+						continue;
+					}
+
+					EventParam.Para32[0] = PhysPortIndex;
+					EventParam.Para32[1] = (SK_U32)Val8;
+					if (SkGeSirqEvent(pAC, IoC,
+						SK_HWEV_SET_SPEED,
+						EventParam) > 0) {
+
+						SK_ERR_LOG(pAC, SK_ERRCL_SW,
+							SK_PNMI_ERR045,
+							SK_PNMI_ERR045MSG);
+
+						*pLen = 0;
+						return (SK_PNMI_ERR_GENERAL);
+					}
+				}
+			}
+			else {
+				/*
+				 * Send an event with the new flow control
+				 * mode to the SIRQ module.
+				 */
+				EventParam.Para32[0] = SK_PNMI_PORT_LOG2PHYS(
+					pAC, LogPortIndex);
+				EventParam.Para32[1] = (SK_U32)Val8;
+				if (SkGeSirqEvent(pAC, IoC,
+					SK_HWEV_SET_SPEED,
+					EventParam) > 0) {
+
+					SK_ERR_LOG(pAC, SK_ERRCL_SW,
+						SK_PNMI_ERR045,
+						SK_PNMI_ERR045MSG);
+
+					*pLen = 0;
+					return (SK_PNMI_ERR_GENERAL);
+				}
+			}
+			Offset += sizeof(char);
+			break;
+
 		case OID_SKGE_MTU :
 			/* Check the value range */
 			Val32 = *(SK_U32*)(pBuf + Offset);
@@ -6341,8 +6180,8 @@
 			break;
 
 		default:
-			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR045,
-				SK_PNMI_ERR045MSG);
+            SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_ERR,
+                ("MacPrivateConf: Unknown OID should be handled before set"));
 
 			*pLen = 0;
 			return (SK_PNMI_ERR_GENERAL);
@@ -6373,8 +6212,7 @@
  *                               exist (e.g. port instance 3 on a two port
  *	                         adapter.
  */
-
-static int Monitor(
+PNMI_STATIC int Monitor(
 SK_AC *pAC,		/* Pointer to adapter context */
 SK_IOC IoC,		/* IO context handle */
 int Action,		/* Get/PreSet/Set action */
@@ -6489,8 +6327,7 @@
  * Returns:
  *	Nothing
  */
-
-static void VirtualConf(
+PNMI_STATIC void VirtualConf(
 SK_AC *pAC,		/* Pointer to adapter context */
 SK_IOC IoC,		/* IO context handle */
 SK_U32 Id,		/* Object ID that is to be processed */
@@ -6534,8 +6371,7 @@
 			/* Check if it is the first active port */
 			if (*pBuf == 0) {
 
-				*pBuf = pAC->GIni.GP[PhysPortIndex].
-					PLinkModeConf;
+				*pBuf = pAC->GIni.GP[PhysPortIndex].PLinkModeConf;
 				continue;
 			}
 
@@ -6553,8 +6389,7 @@
 
 		case OID_SKGE_LINK_MODE_STATUS:
 			/* Get the link mode of the physical port */
-			Val8 = CalculateLinkModeStatus(pAC, IoC,
-				PhysPortIndex);
+			Val8 = CalculateLinkModeStatus(pAC, IoC, PhysPortIndex);
 
 			/* Check if it is the first active port */
 			if (*pBuf == 0) {
@@ -6602,8 +6437,7 @@
 			/* Check if it is the first active port */
 			if (*pBuf == 0) {
 
-				*pBuf = pAC->GIni.GP[PhysPortIndex].
-					PFlowCtrlCap;
+				*pBuf = pAC->GIni.GP[PhysPortIndex].PFlowCtrlCap;
 				continue;
 			}
 
@@ -6618,8 +6452,7 @@
 			/* Check if it is the first active port */
 			if (*pBuf == 0) {
 
-				*pBuf = pAC->GIni.GP[PhysPortIndex].
-					PFlowCtrlMode;
+				*pBuf = pAC->GIni.GP[PhysPortIndex].PFlowCtrlMode;
 				continue;
 			}
 
@@ -6628,8 +6461,7 @@
 			 * control mode than the first one, we return a value
 			 * that indicates that the mode is indeterminated.
 			 */
-			if (*pBuf != pAC->GIni.GP[PhysPortIndex].
-				PFlowCtrlMode) {
+			if (*pBuf != pAC->GIni.GP[PhysPortIndex].PFlowCtrlMode) {
 
 				*pBuf = SK_FLOW_MODE_INDETERMINATED;
 			}
@@ -6639,8 +6471,7 @@
 			/* Check if it is the first active port */
 			if (*pBuf == 0) {
 
-				*pBuf = pAC->GIni.GP[PhysPortIndex].
-					PFlowCtrlStatus;
+				*pBuf = pAC->GIni.GP[PhysPortIndex].PFlowCtrlStatus;
 				continue;
 			}
 
@@ -6650,18 +6481,17 @@
 			 * value that indicates that the status is
 			 * indeterminated.
 			 */
-			if (*pBuf != pAC->GIni.GP[PhysPortIndex].
-				PFlowCtrlStatus) {
+			if (*pBuf != pAC->GIni.GP[PhysPortIndex].PFlowCtrlStatus) {
 
 				*pBuf = SK_FLOW_STAT_INDETERMINATED;
 			}
 			break;
+		
 		case OID_SKGE_PHY_OPERATION_CAP:
 			/* Check if it is the first active port */
 			if (*pBuf == 0) {
 
-				*pBuf = pAC->GIni.GP[PhysPortIndex].
-					PMSCap;
+				*pBuf = pAC->GIni.GP[PhysPortIndex].PMSCap;
 				continue;
 			}
 
@@ -6676,8 +6506,7 @@
 			/* Check if it is the first active port */
 			if (*pBuf == 0) {
 
-				*pBuf = pAC->GIni.GP[PhysPortIndex].
-					PMSMode;
+				*pBuf = pAC->GIni.GP[PhysPortIndex].PMSMode;
 				continue;
 			}
 
@@ -6686,8 +6515,7 @@
 			 * slave mode than the first one, we return a value
 			 * that indicates that the mode is indeterminated.
 			 */
-			if (*pBuf != pAC->GIni.GP[PhysPortIndex].
-				PMSMode) {
+			if (*pBuf != pAC->GIni.GP[PhysPortIndex].PMSMode) {
 
 				*pBuf = SK_MS_MODE_INDETERMINATED;
 			}
@@ -6697,8 +6525,7 @@
 			/* Check if it is the first active port */
 			if (*pBuf == 0) {
 
-				*pBuf = pAC->GIni.GP[PhysPortIndex].
-					PMSStatus;
+				*pBuf = pAC->GIni.GP[PhysPortIndex].PMSStatus;
 				continue;
 			}
 
@@ -6708,12 +6535,50 @@
 			 * value that indicates that the status is
 			 * indeterminated.
 			 */
-			if (*pBuf != pAC->GIni.GP[PhysPortIndex].
-				PMSStatus) {
+			if (*pBuf != pAC->GIni.GP[PhysPortIndex].PMSStatus) {
 
 				*pBuf = SK_MS_STAT_INDETERMINATED;
 			}
 			break;
+		
+		case OID_SKGE_SPEED_MODE:
+			/* Check if it is the first active port */
+			if (*pBuf == 0) {
+
+				*pBuf = pAC->GIni.GP[PhysPortIndex].PLinkSpeed;
+				continue;
+			}
+
+			/*
+			 * If we find an active port with a different flow
+			 * control mode than the first one, we return a value
+			 * that indicates that the mode is indeterminated.
+			 */
+			if (*pBuf != pAC->GIni.GP[PhysPortIndex].PLinkSpeed) {
+
+				*pBuf = SK_LSPEED_INDETERMINATED;
+			}
+			break;
+		
+		case OID_SKGE_SPEED_STATUS:
+			/* Check if it is the first active port */
+			if (*pBuf == 0) {
+
+				*pBuf = pAC->GIni.GP[PhysPortIndex].PLinkSpeedUsed;
+				continue;
+			}
+
+			/*
+			 * If we find an active port with a different flow
+			 * control status than the first one, we return a
+			 * value that indicates that the status is
+			 * indeterminated.
+			 */
+			if (*pBuf != pAC->GIni.GP[PhysPortIndex].PLinkSpeedUsed) {
+
+				*pBuf = SK_LSPEED_STAT_INDETERMINATED;
+			}
+			break;
 		}
 	}
 
@@ -6760,6 +6625,17 @@
 		case OID_SKGE_PHY_OPERATION_STATUS:
 			*pBuf = SK_MS_STAT_INDETERMINATED;
 			break;
+		case OID_SKGE_SPEED_CAP:
+			*pBuf = SK_LSPEED_CAP_INDETERMINATED;
+			break;
+
+		case OID_SKGE_SPEED_MODE:
+			*pBuf = SK_LSPEED_INDETERMINATED;
+			break;
+
+		case OID_SKGE_SPEED_STATUS:
+			*pBuf = SK_LSPEED_STAT_INDETERMINATED;
+			break;
 		}
 	}
 }
@@ -6779,8 +6655,7 @@
  * Returns:
  *	Link status of physical port
  */
-
-static SK_U8 CalculateLinkStatus(
+PNMI_STATIC SK_U8 CalculateLinkStatus(
 SK_AC *pAC,			/* Pointer to adapter context */
 SK_IOC IoC,			/* IO context handle */
 unsigned int PhysPortIndex)	/* Physical port index */
@@ -6820,8 +6695,7 @@
  * Returns:
  *	The link mode status
  */
-
-static SK_U8 CalculateLinkModeStatus(
+PNMI_STATIC SK_U8 CalculateLinkModeStatus(
 SK_AC *pAC,			/* Pointer to adapter context */
 SK_IOC IoC,			/* IO context handle */
 unsigned int PhysPortIndex)	/* Physical port index */
@@ -6869,8 +6743,7 @@
  *	SK_PNMI_ERR_OK	     Task successfully performed.
  *	SK_PNMI_ERR_GENERAL  Something went wrong.
  */
-
-static int GetVpdKeyArr(
+PNMI_STATIC int GetVpdKeyArr(
 SK_AC *pAC,		/* Pointer to adapter context */
 SK_IOC IoC,		/* IO context handle */
 char *pKeyArr,		/* Ptr KeyArray */
@@ -6966,8 +6839,7 @@
  *	SK_PNMI_ERR_OK	     Task successfully performed.
  *	SK_PNMI_ERR_GENERAL  Something went wrong.
  */
-
-static int SirqUpdate(
+PNMI_STATIC int SirqUpdate(
 SK_AC *pAC,	/* Pointer to adapter context */
 SK_IOC IoC)	/* IO context handle */
 {
@@ -7006,8 +6878,7 @@
  *	SK_PNMI_ERR_OK	     Task successfully performed.
  *	SK_PNMI_ERR_GENERAL  Something went wrong.
  */
-
-static int RlmtUpdate(
+PNMI_STATIC int RlmtUpdate(
 SK_AC *pAC,	/* Pointer to adapter context */
 SK_IOC IoC,	/* IO context handle */
 SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
@@ -7042,24 +6913,20 @@
  *
  * Description:
  *	The XMAC holds its statistic internally. To obtain the current
- *	values we must send a command so that the statistic data will
- *	be written to a predefined memory area on the adapter. 
+ *	values we send a command so that the statistic data will
+ *	be written to apredefined memory area on the adapter. 
  *
  * Returns:
  *	SK_PNMI_ERR_OK	     Task successfully performed.
  *	SK_PNMI_ERR_GENERAL  Something went wrong.
  */
-
-static int MacUpdate(
+PNMI_STATIC int MacUpdate(
 SK_AC *pAC,		/* Pointer to adapter context */
 SK_IOC IoC,		/* IO context handle */
 unsigned int FirstMac,	/* Index of the first Mac to be updated */
 unsigned int LastMac)	/* Index of the last Mac to be updated */
 {
 	unsigned int	MacIndex;
-	SK_U16		StatReg;
-	unsigned int	WaitIndex;
-
 
 	/*
 	 * Were the statistics already updated during the
@@ -7070,31 +6937,21 @@
 		return (SK_PNMI_ERR_OK);
 	}
 
-	/* Send an update command to all XMACs specified */
+	/* Send an update command to all MACs specified */
 	for (MacIndex = FirstMac; MacIndex <= LastMac; MacIndex ++) {
 
-		StatReg = XM_SC_SNP_TXC | XM_SC_SNP_RXC;
-		XM_OUT16(IoC, MacIndex, XM_STAT_CMD, StatReg);
-
 		/*
-		 * It is an auto-clearing register. If the command bits
-		 * went to zero again, the statistics are transfered.
-		 * Normally the command should be executed immediately.
-		 * But just to be sure we execute a loop.
+		 * 2002-09-13 pweber:	Freeze the current sw counters. 
+		 *                      (That should be done as close as 
+		 *                      possible to the update of the 
+		 *                      hw counters)
 		 */
-		for (WaitIndex = 0; WaitIndex < 10; WaitIndex ++) {
-
-			XM_IN16(IoC, MacIndex, XM_STAT_CMD, &StatReg);
-			if ((StatReg & (XM_SC_SNP_TXC | XM_SC_SNP_RXC)) ==
-				0) {
-
-				break;
-			}
+		if (pAC->GIni.GIMacType == SK_MAC_XMAC) {
+			pAC->Pnmi.BufPort[MacIndex] = pAC->Pnmi.Port[MacIndex];
 		}
-		if (WaitIndex == 10 ) {
-
-			SK_ERR_LOG(pAC, SK_ERRCL_HW, SK_PNMI_ERR050,
-				SK_PNMI_ERR050MSG);
+			
+		/* 2002-09-13 pweber:  Update the hw counter  */
+		if (pAC->GIni.GIFunc.pFnMacUpdateStats(pAC, IoC, MacIndex) != 0) {
 
 			return (SK_PNMI_ERR_GENERAL);
 		}
@@ -7119,8 +6976,7 @@
  * Returns:
  *	Requested statistic value
  */
-
-static SK_U64 GetStatVal(
+PNMI_STATIC SK_U64 GetStatVal(
 SK_AC *pAC,					/* Pointer to adapter context */
 SK_IOC IoC,					/* IO context handle */
 unsigned int LogPortIndex,	/* Index of the logical Port to be processed */
@@ -7129,16 +6985,15 @@
 {
 	unsigned int	PhysPortIndex;
 	unsigned int	PhysPortMax;
-	SK_U64		Val = 0;
+	SK_U64			Val = 0;
 
 
-	if(pAC->Pnmi.DualNetActiveFlag == SK_TRUE){	/* Dual net mode */
+	if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {	/* Dual net mode */
 
 		PhysPortIndex = NetIndex;
 		Val = GetPhysStatVal(pAC, IoC, PhysPortIndex, StatIndex);
-    }	/* end of dual net mode */
-
-	else { /* single net mode */
+	}
+	else {	/* Single Net mode */
 
 		if (LogPortIndex == 0) {
 
@@ -7163,7 +7018,7 @@
 			PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(pAC, LogPortIndex);
 			Val = GetPhysStatVal(pAC, IoC, PhysPortIndex, StatIndex);
 		}
-	} /* end of single net mode */
+	}
 	return (Val);
 }
 
@@ -7183,52 +7038,261 @@
  * Returns:
  *	Counter value
  */
-
-static SK_U64 GetPhysStatVal(
+PNMI_STATIC SK_U64 GetPhysStatVal(
 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 */
 {
-	SK_U64		Val = 0;
-	SK_U32		LowVal;
-	SK_U32		HighVal;
-
+	SK_U64	Val = 0;
+	SK_U32	LowVal = 0;
+	SK_U32	HighVal = 0;
+	SK_U16	Word;
+	int		MacType;
+	
+	SK_PNMI_PORT	*pPnmiPrt;
+	SK_GEMACFUNC	*pFnMac;
+	
+	MacType = pAC->GIni.GIMacType;
+	
+	/* 2002-09-17 pweber: For XMAC, use the frozen sw counters (BufPort) */
+	if (pAC->GIni.GIMacType == SK_MAC_XMAC) {
+		pPnmiPrt = &pAC->Pnmi.BufPort[PhysPortIndex];
+	}
+	else {
+		pPnmiPrt = &pAC->Pnmi.Port[PhysPortIndex];
+	}
+	
+	pFnMac   = &pAC->GIni.GIFunc;
 
 	switch (StatIndex) {
-
-	case SK_PNMI_HTX_OCTET:
-		XM_IN32(IoC, PhysPortIndex, XM_TXO_OK_LO, &LowVal);
-		XM_IN32(IoC, PhysPortIndex, XM_TXO_OK_HI, &HighVal);
+	case SK_PNMI_HTX:
+	case SK_PNMI_HRX:
+		/* Not supported by GMAC */
+		if (MacType == SK_MAC_GMAC) {
+			return (Val); 
+		}
+			
+		(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+									  StatAddr[StatIndex][MacType].Reg,
+									  &LowVal);
+		HighVal = pPnmiPrt->CounterHigh[StatIndex];
 		break;
 
+	case SK_PNMI_HTX_OCTET:
 	case SK_PNMI_HRX_OCTET:
-		XM_IN32(IoC, PhysPortIndex, XM_RXO_OK_LO, &LowVal);
-		XM_IN32(IoC, PhysPortIndex, XM_RXO_OK_HI, &HighVal);
+		(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+									  StatAddr[StatIndex][MacType].Reg,
+									  &HighVal);
+		(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+									  StatAddr[StatIndex + 1][MacType].Reg,
+									  &LowVal);
 		break;
 
-	case SK_PNMI_HTX_OCTETLOW:
-	case SK_PNMI_HRX_OCTETLOW:
-		return (Val);
+	case SK_PNMI_HTX_BURST:
+	case SK_PNMI_HTX_EXCESS_DEF:
+	case SK_PNMI_HTX_CARRIER:
+		/* Not supported by GMAC */
+		if (MacType == SK_MAC_GMAC) {
+			return (Val);
+		}
 
-	case SK_PNMI_HTX_SYNC:
-		LowVal = (SK_U32)pAC->Pnmi.Port[PhysPortIndex].StatSyncCts;
-		HighVal = (SK_U32)
-			(pAC->Pnmi.Port[PhysPortIndex].StatSyncCts >> 32);
+		(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+									  StatAddr[StatIndex][MacType].Reg,
+									  &LowVal);
+		HighVal = pPnmiPrt->CounterHigh[StatIndex];
 		break;
 
-	case SK_PNMI_HTX_SYNC_OCTET:
-		LowVal = (SK_U32)pAC->Pnmi.Port[PhysPortIndex].
-			StatSyncOctetsCts;
-		HighVal = (SK_U32)
-			(pAC->Pnmi.Port[PhysPortIndex].StatSyncOctetsCts >>
-			32);
+	case SK_PNMI_HTX_MACC:
+		/* GMAC only supports PAUSE MAC control frames */
+		if (MacType == SK_MAC_GMAC) {
+			Val = GetPhysStatVal(pAC, IoC, PhysPortIndex, SK_PNMI_HTX_PMACC);
+
+			return (Val); 
+		}
+
+		(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+									  StatAddr[StatIndex][MacType].Reg,
+									  &LowVal);
+		HighVal = pPnmiPrt->CounterHigh[StatIndex];
+		break;
+
+	case SK_PNMI_HTX_COL:
+	case SK_PNMI_HRX_UNDERSIZE:
+		/* Not supported by XMAC */
+		if (MacType == SK_MAC_XMAC) {
+			return (Val);
+		}
+
+		(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+									  StatAddr[StatIndex][MacType].Reg,
+									  &LowVal);
+		HighVal = pPnmiPrt->CounterHigh[StatIndex];
+		break;
+
+
+
+	case SK_PNMI_HTX_DEFFERAL:
+		/* Not supported by GMAC */
+		if (MacType == SK_MAC_GMAC) {
+			return (Val); 
+		}
+		
+		/*
+		 * XMAC counts frames with deferred transmission
+		 * even in full-duplex mode.
+		 *
+		 * In full-duplex mode the counter remains constant!
+		 */
+		if ((pAC->GIni.GP[PhysPortIndex].PLinkModeStatus == SK_LMODE_STAT_AUTOFULL) ||
+			(pAC->GIni.GP[PhysPortIndex].PLinkModeStatus == SK_LMODE_STAT_FULL)) {
+
+			LowVal = 0;
+			HighVal = 0;
+		}
+		else {
+			/* Otherwise get contents of hardware register. */
+			(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+										  StatAddr[SK_PNMI_HTX_DEFFERAL][MacType].Reg,
+										  &LowVal);
+			HighVal = pPnmiPrt->CounterHigh[StatIndex];
+		}
+		break;
+
+	case SK_PNMI_HRX_BADOCTET:
+		/* Not supported by XMAC */
+		if (MacType == SK_MAC_XMAC) {
+			return (Val);
+		}
+
+		(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+									  StatAddr[StatIndex][MacType].Reg,
+									  &HighVal);
+		(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+									  StatAddr[StatIndex + 1][MacType].Reg,
+                                      &LowVal);
 		break;
 
+	case SK_PNMI_HTX_OCTETLOW:
+	case SK_PNMI_HRX_OCTETLOW:
+	case SK_PNMI_HRX_BADOCTETLOW:
+		return (Val);
+
 	case SK_PNMI_HRX_LONGFRAMES:
-		LowVal = (SK_U32)pAC->Pnmi.Port[PhysPortIndex].StatRxLongFrameCts;
-		HighVal = (SK_U32)
-			(pAC->Pnmi.Port[PhysPortIndex].StatRxLongFrameCts >> 32);
+		/* For XMAC the SW counter is managed by PNMI */
+		if (MacType == SK_MAC_XMAC) {
+			return (pPnmiPrt->StatRxLongFrameCts); 
+		}
+		
+		(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+									  StatAddr[StatIndex][MacType].Reg,
+									  &LowVal);
+		HighVal = pPnmiPrt->CounterHigh[StatIndex];
+		break;
+		
+	case SK_PNMI_HRX_TOO_LONG:
+		(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+						StatAddr[StatIndex][MacType].Reg,
+								&LowVal);
+		HighVal = pPnmiPrt->CounterHigh[StatIndex];
+		
+		Val = (((SK_U64)HighVal << 32) | (SK_U64)LowVal);
+
+		switch (MacType) {
+		case SK_MAC_GMAC:
+			/* For GMAC the SW counter is additionally managed by PNMI */
+			Val += pPnmiPrt->StatRxFrameTooLongCts;
+			break;
+
+		case SK_MAC_XMAC:
+			/*
+			 * Frames longer than IEEE 802.3 frame max size are counted
+			 * by XMAC in frame_too_long counter even reception of long
+			 * frames was enabled and the frame was correct.
+			 * So correct the value by subtracting RxLongFrame counter.
+			 */
+			Val -= pPnmiPrt->StatRxLongFrameCts;
+			break;
+
+		default:
+			break;
+		}
+
+		LowVal = (SK_U32)Val;
+		HighVal = (SK_U32)(Val >> 32);
+		break;
+		
+	case SK_PNMI_HRX_SHORTS:
+		/* Not supported by GMAC */
+		if (MacType == SK_MAC_GMAC) {
+			/* GM_RXE_FRAG?? */
+			return (Val); 
+		}
+		
+		/*
+		 * XMAC counts short frame errors even if link down (#10620)
+		 *
+		 * If link-down the counter remains constant
+		 */
+		if (pAC->GIni.GP[PhysPortIndex].PLinkModeStatus != SK_LMODE_STAT_UNKNOWN) {
+
+			/* Otherwise get incremental difference */
+			(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+										  StatAddr[StatIndex][MacType].Reg,
+										  &LowVal);
+			HighVal = pPnmiPrt->CounterHigh[StatIndex];
+
+			Val = (((SK_U64)HighVal << 32) | (SK_U64)LowVal);
+			Val -= pPnmiPrt->RxShortZeroMark;
+
+			LowVal = (SK_U32)Val;
+			HighVal = (SK_U32)(Val >> 32);
+		}
+		break;
+
+	case SK_PNMI_HRX_MACC:
+	case SK_PNMI_HRX_MACC_UNKWN:
+	case SK_PNMI_HRX_BURST:
+	case SK_PNMI_HRX_MISSED:
+	case SK_PNMI_HRX_FRAMING:
+	case SK_PNMI_HRX_CARRIER:
+	case SK_PNMI_HRX_IRLENGTH:
+	case SK_PNMI_HRX_SYMBOL:
+	case SK_PNMI_HRX_CEXT:
+		/* Not supported by GMAC */
+		if (MacType == SK_MAC_GMAC) {
+			/* GM_RXE_FRAG?? */
+			return (Val); 
+		}
+
+		(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+									  StatAddr[StatIndex][MacType].Reg,
+									  &LowVal);
+		HighVal = pPnmiPrt->CounterHigh[StatIndex];
+		break;
+
+	case SK_PNMI_HRX_PMACC_ERR:
+		/* For GMAC the SW counter is managed by PNMI */
+		if (MacType == SK_MAC_GMAC) {
+			return (pPnmiPrt->StatRxPMaccErr); 
+		}
+		
+		(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+									  StatAddr[StatIndex][MacType].Reg,
+									  &LowVal);
+		HighVal = pPnmiPrt->CounterHigh[StatIndex];
+		break;
+
+	/* SW counter managed by PNMI */
+	case SK_PNMI_HTX_SYNC:
+		LowVal = (SK_U32)pPnmiPrt->StatSyncCts;
+		HighVal = (SK_U32)(pPnmiPrt->StatSyncCts >> 32);
+		break;
+
+	/* SW counter managed by PNMI */
+	case SK_PNMI_HTX_SYNC_OCTET:
+		LowVal = (SK_U32)pPnmiPrt->StatSyncOctetsCts;
+		HighVal = (SK_U32)(pPnmiPrt->StatSyncOctetsCts >> 32);
 		break;
 
 	case SK_PNMI_HRX_FCS:
@@ -7240,30 +7304,33 @@
 			/* do not read while not initialized (PHY_READ hangs!)*/
 			if (pAC->GIni.GP[PhysPortIndex].PState) {
 				PHY_READ(IoC, &pAC->GIni.GP[PhysPortIndex],
-					 PhysPortIndex, PHY_BCOM_RE_CTR,
-					&LowVal);
-			}
-			else {
-				LowVal = 0;
+						 PhysPortIndex, PHY_BCOM_RE_CTR,
+						 &Word);
+				
+				LowVal = Word;
 			}
-			HighVal = pAC->Pnmi.Port[PhysPortIndex].CounterHigh[StatIndex];
+			HighVal = pPnmiPrt->CounterHigh[StatIndex];
 		}
 		else {
-			XM_IN32(IoC, PhysPortIndex,
-				StatAddress[StatIndex].Param, &LowVal);
-			HighVal = pAC->Pnmi.Port[PhysPortIndex].CounterHigh[StatIndex];
+			(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+										  StatAddr[StatIndex][MacType].Reg,
+										  &LowVal);
+			HighVal = pPnmiPrt->CounterHigh[StatIndex];
 		}
+		break;
+
 	default:
-		XM_IN32(IoC, PhysPortIndex, StatAddress[StatIndex].Param,
-			&LowVal);
-		HighVal = pAC->Pnmi.Port[PhysPortIndex].CounterHigh[StatIndex];
+		(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+									  StatAddr[StatIndex][MacType].Reg,
+									  &LowVal);
+		HighVal = pPnmiPrt->CounterHigh[StatIndex];
 		break;
 	}
 
 	Val = (((SK_U64)HighVal << 32) | (SK_U64)LowVal);
 
 	/* Correct value because of possible XMAC reset. XMAC Errata #2 */
-	Val += pAC->Pnmi.Port[PhysPortIndex].CounterOffset[StatIndex];
+	Val += pPnmiPrt->CounterOffset[StatIndex];
 
 	return (Val);
 }
@@ -7279,8 +7346,7 @@
  * Returns:
  *	Nothing
  */
-
-static void ResetCounter(
+PNMI_STATIC void ResetCounter(
 SK_AC *pAC,		/* Pointer to adapter context */
 SK_IOC IoC,		/* IO context handle */
 SK_U32 NetIndex)
@@ -7305,7 +7371,8 @@
 
 	/* Notify CSUM module */
 #ifdef SK_USE_CSUM
-	EventParam.Para64 = (SK_U64)(-1);
+	EventParam.Para32[0] = NetIndex;
+	EventParam.Para32[1] = (SK_U32)-1;
 	SkEventQueue(pAC, SKGE_CSUM, SK_CSUM_EVENT_CLEAR_PROTO_STATS,
 		EventParam);
 #endif
@@ -7314,11 +7381,7 @@
 	for (PhysPortIndex = 0; PhysPortIndex <
 		(unsigned int)pAC->GIni.GIMacsFound; PhysPortIndex ++) {
 
-		XM_OUT16(IoC, PhysPortIndex, XM_STAT_CMD,
-			XM_SC_CLR_RXC | XM_SC_CLR_TXC);
-		/* Clear two times according to Errata #3 */
-		XM_OUT16(IoC, PhysPortIndex, XM_STAT_CMD,
-			XM_SC_CLR_RXC | XM_SC_CLR_TXC);
+		(void)pAC->GIni.GIFunc.pFnMacResetCounter(pAC, IoC, PhysPortIndex);
 
 		SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].CounterHigh,
 			0, sizeof(pAC->Pnmi.Port[PhysPortIndex].CounterHigh));
@@ -7333,6 +7396,12 @@
 		SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].
 			StatRxLongFrameCts, 0, sizeof(pAC->Pnmi.Port[
 			PhysPortIndex].StatRxLongFrameCts));
+		SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].
+				  StatRxFrameTooLongCts, 0, sizeof(pAC->Pnmi.Port[
+			PhysPortIndex].StatRxFrameTooLongCts));
+		SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].
+				  StatRxPMaccErr, 0, sizeof(pAC->Pnmi.Port[
+			PhysPortIndex].StatRxPMaccErr));
 	}
 
 	/*
@@ -7373,8 +7442,7 @@
  * Returns:
  *	A pointer to the trap entry
  */
-
-static char* GetTrapEntry(
+PNMI_STATIC char* GetTrapEntry(
 SK_AC *pAC,		/* Pointer to adapter context */
 SK_U32 TrapId,		/* SNMP ID of the trap */
 unsigned int Size)	/* Space needed for trap entry */
@@ -7399,11 +7467,11 @@
 	if (Beg >= Size) {
 
 		NeededSpace = Size;
-		Wrap = FALSE;
+		Wrap = SK_FALSE;
 	}
 	else {
 		NeededSpace = Beg + Size;
-		Wrap = TRUE;
+		Wrap = SK_TRUE;
 	}
 
 	/*
@@ -7479,8 +7547,7 @@
  * Returns:
  *	Nothing
  */
-
-static void CopyTrapQueue(
+PNMI_STATIC void CopyTrapQueue(
 SK_AC *pAC,		/* Pointer to adapter context */
 char *pDstBuf)		/* Buffer to which the queued traps will be copied */
 {
@@ -7523,8 +7590,7 @@
  * Returns:
  *	Nothing
  */
-
-static void GetTrapQueueLen(
+PNMI_STATIC void GetTrapQueueLen(
 SK_AC *pAC,		/* Pointer to adapter context */
 unsigned int *pLen,	/* Length in Bytes of all queued traps */
 unsigned int *pEntries)	/* Returns number of trapes stored in queue */
@@ -7566,8 +7632,7 @@
  * Returns:
  *	Nothing
  */
-
-static void QueueSimpleTrap(
+PNMI_STATIC void QueueSimpleTrap(
 SK_AC *pAC,		/* Pointer to adapter context */
 SK_U32 TrapId)		/* Type of sensor trap */
 {
@@ -7585,8 +7650,7 @@
  * Returns:
  *	Nothing
  */
-
-static void QueueSensorTrap(
+PNMI_STATIC void QueueSensorTrap(
 SK_AC *pAC,			/* Pointer to adapter context */
 SK_U32 TrapId,			/* Type of sensor trap */
 unsigned int SensorIndex)	/* Index of sensor which caused the trap */
@@ -7641,8 +7705,7 @@
  * Returns:
  *	Nothing
  */
-
-static void QueueRlmtNewMacTrap(
+PNMI_STATIC void QueueRlmtNewMacTrap(
 SK_AC *pAC,		/* Pointer to adapter context */
 unsigned int ActiveMac)	/* Index (0..n) of the currently active port */
 {
@@ -7669,8 +7732,7 @@
  * Returns:
  *	Nothing
  */
-
-static void QueueRlmtPortTrap(
+PNMI_STATIC void QueueRlmtPortTrap(
 SK_AC *pAC,		/* Pointer to adapter context */
 SK_U32 TrapId,		/* Type of RLMT port trap */
 unsigned int PortIndex)	/* Index of the port, which changed its state */
@@ -7697,8 +7759,7 @@
  * Returns:
  *	Nothing
  */
-
-static void CopyMac(
+PNMI_STATIC void CopyMac(
 char *pDst,		/* Pointer to destination buffer */
 SK_MAC_ADDR *pMac)	/* Pointer of Source */
 {
@@ -7710,3 +7771,536 @@
 		*(pDst + i) = pMac->a[i];
 	}
 }
+
+
+#ifdef SK_POWER_MGMT
+/*****************************************************************************
+ *
+ * PowerManagement - OID handler function of PowerManagement OIDs
+ *
+ * Description:
+ *	The code is simple. No description necessary.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	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).
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                               exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+
+PNMI_STATIC int PowerManagement(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* Get/PreSet/Set action */
+SK_U32 Id,		/* Object ID that is to be processed */
+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 */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
+{
+	
+	SK_U32	RetCode = SK_PNMI_ERR_GENERAL;
+
+	/*
+	 * Check instance. We only handle single instance variables
+	 */
+	if (Instance != (SK_U32)(-1) && Instance != 1) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_UNKNOWN_INST);
+	}
+
+	/*
+	 * Perform action
+	 */
+	if (Action == SK_PNMI_GET) {
+
+		/*
+		 * Check length
+		 */
+		switch (Id) {
+
+		case OID_PNP_CAPABILITIES:
+			if (*pLen < sizeof(SK_PNP_CAPABILITIES)) {
+
+				*pLen = sizeof(SK_PNP_CAPABILITIES);
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			break;
+
+		case OID_PNP_QUERY_POWER:
+		case OID_PNP_ENABLE_WAKE_UP:
+			if (*pLen < sizeof(SK_U32)) {
+
+				*pLen = sizeof(SK_U32);
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			break;
+
+		case OID_PNP_SET_POWER:
+		case OID_PNP_ADD_WAKE_UP_PATTERN:
+		case OID_PNP_REMOVE_WAKE_UP_PATTERN:
+			break;
+		
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR040,
+				SK_PNMI_ERR040MSG);
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+
+		/*
+		 * Get value
+		 */
+		switch (Id) {
+
+		case OID_PNP_CAPABILITIES:
+			RetCode = SkPowerQueryPnPCapabilities(pAC, IoC, pBuf, pLen);
+			break;
+
+		case OID_PNP_QUERY_POWER:
+			/* The Windows DDK describes: An OID_PNP_QUERY_POWER requests
+			 the miniport to indicate whether it can transition its NIC 
+			 to the low-power state. 
+			 A miniport driver must always return NDIS_STATUS_SUCCESS
+			 to a query of OID_PNP_QUERY_POWER. */
+			RetCode = SK_PNMI_ERR_OK;
+			break;
+
+			/* NDIS handles these OIDs as write-only.
+			 * So in case of get action the buffer with written length = 0
+			 * is returned
+			 */
+		case OID_PNP_SET_POWER:
+		case OID_PNP_ADD_WAKE_UP_PATTERN:
+		case OID_PNP_REMOVE_WAKE_UP_PATTERN:
+			*pLen = 0;	
+			RetCode = SK_PNMI_ERR_OK;
+			break;
+
+		case OID_PNP_ENABLE_WAKE_UP:
+			RetCode = SkPowerGetEnableWakeUp(pAC, IoC, pBuf, pLen);
+			break;
+
+		default:
+			RetCode = SK_PNMI_ERR_GENERAL;
+			break;
+		}
+
+		return (RetCode); 
+	}
+	
+	/*
+	 * From here SET or PRESET action. Check if the passed
+	 * buffer length is plausible.
+	 */
+	switch (Id) {
+	case OID_PNP_SET_POWER:
+	case OID_PNP_ENABLE_WAKE_UP:
+		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;
+
+	case OID_PNP_ADD_WAKE_UP_PATTERN:
+	case OID_PNP_REMOVE_WAKE_UP_PATTERN:
+		if (*pLen < sizeof(SK_PM_PACKET_PATTERN)) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_BAD_VALUE); 
+		}
+		break;
+
+    default:
+		*pLen = 0;
+		return (SK_PNMI_ERR_READ_ONLY);
+	}
+
+	/*
+	 * Perform preset or set
+	 */
+	
+	/* POWER module does not support PRESET action */
+	if (Action == SK_PNMI_PRESET) {
+		return (SK_PNMI_ERR_OK); 
+	}
+
+	switch (Id) {
+	case OID_PNP_SET_POWER:
+		RetCode = SkPowerSetPower(pAC, IoC, pBuf, pLen);	
+		break;
+
+	case OID_PNP_ADD_WAKE_UP_PATTERN:
+		RetCode = SkPowerAddWakeUpPattern(pAC, IoC, pBuf, pLen);	
+		break;
+		
+	case OID_PNP_REMOVE_WAKE_UP_PATTERN:
+		RetCode = SkPowerRemoveWakeUpPattern(pAC, IoC, pBuf, pLen);	
+		break;
+		
+	case OID_PNP_ENABLE_WAKE_UP:
+		RetCode = SkPowerSetEnableWakeUp(pAC, IoC, pBuf, pLen);
+		break;
+		
+	default:
+		RetCode = SK_PNMI_ERR_GENERAL;
+	}
+	
+	return (RetCode);
+}
+#endif /* SK_POWER_MGMT */
+
+
+/*****************************************************************************
+ *
+ * Vct - OID handler function of  OIDs
+ *
+ * Description:
+ *	The code is simple. No description necessary.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was performed successfully.
+ *	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).
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                               exist (e.g. port instance 3 on a two port
+ *	                         adapter).
+ *	SK_PNMI_ERR_READ_ONLY	 Only the Get action is allowed.
+ *
+ */
+
+PNMI_STATIC int Vct(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* Get/PreSet/Set action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer to which the mgmt data will be copied */
+unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (-1,2..n) that is to be queried */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode always zero */
+{
+	SK_GEPORT	*pPrt;
+	SK_PNMI_VCT	*pVctBackupData;
+	SK_U32		LogPortMax;
+	SK_U32		PhysPortMax;
+	SK_U32		PhysPortIndex;
+	SK_U32		Limit;
+	SK_U32		Offset;
+
+	SK_BOOL		Link;
+	SK_U32		RetCode = SK_PNMI_ERR_GENERAL;
+	int		i;
+	SK_EVPARA	Para;
+	SK_U32		CableLength;
+	
+	/*
+	 * Calculate the port indexes from the instance.
+	 */
+	PhysPortMax = pAC->GIni.GIMacsFound;
+	LogPortMax = SK_PNMI_PORT_PHYS2LOG(PhysPortMax);
+	
+	/* Dual net mode? */
+	if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+		LogPortMax--;
+	}
+	
+	if ((Instance != (SK_U32) (-1))) {
+		/* Check instance range. */
+		if ((Instance < 2) || (Instance > LogPortMax)) {
+			*pLen = 0;
+			return (SK_PNMI_ERR_UNKNOWN_INST);
+		}
+		
+		if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+			PhysPortIndex = NetIndex;
+		}
+		else {
+			PhysPortIndex = Instance - 2;
+		}
+		Limit = PhysPortIndex + 1;
+	}
+	else {	/*
+		 * Instance == (SK_U32) (-1), get all Instances of that OID.
+		 *
+		 * Not implemented yet. May be used in future releases.
+		 */
+		PhysPortIndex = 0;
+		Limit = PhysPortMax;
+	}
+	
+	pPrt = &pAC->GIni.GP[PhysPortIndex];
+	if (pPrt->PHWLinkUp) {
+		Link = SK_TRUE;
+	}
+	else {
+		Link = SK_FALSE;
+	}
+	
+	/*
+	 * Check MAC type.
+	 */
+	if (pPrt->PhyType != SK_PHY_MARV_COPPER) {
+		*pLen = 0;
+		return (SK_PNMI_ERR_GENERAL);
+	}
+	
+	/* Initialize backup data pointer. */
+	pVctBackupData = &pAC->Pnmi.VctBackup[PhysPortIndex];
+	
+	/*
+	 * Check action type.
+	 */
+	if (Action == SK_PNMI_GET) {
+		/*
+		 * Check length.
+		 */
+		switch (Id) {
+		
+		case OID_SKGE_VCT_GET:
+			if (*pLen < (Limit - PhysPortIndex) * sizeof(SK_PNMI_VCT)) {
+				*pLen = (Limit - PhysPortIndex) * sizeof(SK_PNMI_VCT);
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			break;
+		
+		case OID_SKGE_VCT_STATUS:
+			if (*pLen < (Limit - PhysPortIndex) * sizeof(SK_U8)) {
+				*pLen = (Limit - PhysPortIndex) * sizeof(SK_U8);
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			break;
+		
+		default:
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}	
+		
+		/*
+		 * Get value.
+		 */
+		Offset = 0;
+		for (; PhysPortIndex < Limit; PhysPortIndex++) {
+			switch (Id) {
+			
+			case OID_SKGE_VCT_GET:		
+				if ((Link == SK_FALSE) &&
+					(pAC->Pnmi.VctStatus[PhysPortIndex] & SK_PNMI_VCT_PENDING)) {
+					RetCode = SkGmCableDiagStatus(pAC, IoC, PhysPortIndex, SK_FALSE);
+					if (RetCode == 0) {
+						pAC->Pnmi.VctStatus[PhysPortIndex] &= ~SK_PNMI_VCT_PENDING;
+						pAC->Pnmi.VctStatus[PhysPortIndex] |=
+							(SK_PNMI_VCT_NEW_VCT_DATA | SK_PNMI_VCT_TEST_DONE);
+						
+						/* Copy results for later use to PNMI struct. */
+						for (i = 0; i < 4; i++)  {
+							if (pPrt->PMdiPairSts[i] == SK_PNMI_VCT_NORMAL_CABLE) {
+								if ((pPrt->PMdiPairLen[i] > 35) && (pPrt->PMdiPairLen[i] < 0xff)) {
+									pPrt->PMdiPairSts[i] = SK_PNMI_VCT_IMPEDANCE_MISMATCH;
+								}
+							}
+							if ((pPrt->PMdiPairLen[i] > 35) && (pPrt->PMdiPairLen[i] != 0xff)) {
+								CableLength = 1000 * (((175 * pPrt->PMdiPairLen[i]) / 210) - 28);
+							}
+							else {
+								CableLength = 0;
+							}
+							pVctBackupData->PMdiPairLen[i] = CableLength;
+							pVctBackupData->PMdiPairSts[i] = pPrt->PMdiPairSts[i];
+						}
+
+						Para.Para32[0] = PhysPortIndex;
+						Para.Para32[1] = -1;
+						SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_RESET, Para);
+						SkEventDispatcher(pAC, IoC);
+					}
+					else {
+						; /* VCT test is running. */
+					}
+				}
+				
+				/* Get all results. */
+				CheckVctStatus(pAC, IoC, pBuf, Offset, PhysPortIndex);
+				Offset += sizeof(SK_U8);
+				*(pBuf + Offset) = pPrt->PCableLen;
+				Offset += sizeof(SK_U8);
+				for (i = 0; i < 4; i++)  {
+					SK_PNMI_STORE_U32((pBuf + Offset), pVctBackupData->PMdiPairLen[i]);
+					Offset += sizeof(SK_U32);
+				}
+				for (i = 0; i < 4; i++)  {
+					*(pBuf + Offset) = pVctBackupData->PMdiPairSts[i];
+					Offset += sizeof(SK_U8);
+				}
+				
+				RetCode = SK_PNMI_ERR_OK;
+				break;
+		
+			case OID_SKGE_VCT_STATUS:
+				CheckVctStatus(pAC, IoC, pBuf, Offset, PhysPortIndex);
+				Offset += sizeof(SK_U8);
+				RetCode = SK_PNMI_ERR_OK;
+				break;
+			
+			default:
+				*pLen = 0;
+				return (SK_PNMI_ERR_GENERAL);
+			}
+		} /* for */
+		*pLen = Offset;
+		return (RetCode);
+	
+	} /* if SK_PNMI_GET */
+	
+	/*
+	 * From here SET or PRESET action. Check if the passed
+	 * buffer length is plausible.
+	 */
+	
+	/*
+	 * Check length.
+	 */
+	switch (Id) {
+	case OID_SKGE_VCT_SET:
+		if (*pLen < (Limit - PhysPortIndex) * sizeof(SK_U32)) {
+			*pLen = (Limit - PhysPortIndex) * sizeof(SK_U32);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		break;
+	
+	default:
+		*pLen = 0;
+		return (SK_PNMI_ERR_GENERAL);
+	}
+	
+	/*
+	 * Perform preset or set.
+	 */
+	
+	/* VCT does not support PRESET action. */
+	if (Action == SK_PNMI_PRESET) {
+		return (SK_PNMI_ERR_OK);
+	}
+	
+	Offset = 0;
+	for (; PhysPortIndex < Limit; PhysPortIndex++) {
+		switch (Id) {
+		case OID_SKGE_VCT_SET: /* Start VCT test. */
+			if (Link == SK_FALSE) {
+				SkGeStopPort(pAC, IoC, PhysPortIndex, SK_STOP_ALL, SK_SOFT_RST);
+				
+				RetCode = SkGmCableDiagStatus(pAC, IoC, PhysPortIndex, SK_TRUE);
+				if (RetCode == 0) { /* RetCode: 0 => Start! */
+					pAC->Pnmi.VctStatus[PhysPortIndex] |= SK_PNMI_VCT_PENDING;
+					pAC->Pnmi.VctStatus[PhysPortIndex] &= ~SK_PNMI_VCT_NEW_VCT_DATA;
+					pAC->Pnmi.VctStatus[PhysPortIndex] &= ~SK_PNMI_VCT_LINK;
+					
+					/*
+					 * Start VCT timer counter.
+					 */
+					SK_MEMSET((char *) &Para, 0, sizeof(Para));
+					Para.Para32[0] = PhysPortIndex;
+					Para.Para32[1] = -1;
+					SkTimerStart(pAC, IoC, &pAC->Pnmi.VctTimeout[PhysPortIndex].VctTimer,
+						4000000, SKGE_PNMI, SK_PNMI_EVT_VCT_RESET, Para);
+					SK_PNMI_STORE_U32((pBuf + Offset), RetCode);
+					RetCode = SK_PNMI_ERR_OK;
+				}
+				else { /* RetCode: 2 => Running! */
+					SK_PNMI_STORE_U32((pBuf + Offset), RetCode);
+					RetCode = SK_PNMI_ERR_OK;
+				}
+			}
+			else { /* RetCode: 4 => Link! */
+				RetCode = 4;
+				SK_PNMI_STORE_U32((pBuf + Offset), RetCode);
+				RetCode = SK_PNMI_ERR_OK;
+			}
+			Offset += sizeof(SK_U32);
+			break;
+	
+		default:
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+	} /* for */
+	*pLen = Offset;
+	return (RetCode);
+
+} /* Vct */
+
+
+PNMI_STATIC void CheckVctStatus(
+SK_AC		*pAC,
+SK_IOC		IoC,
+char		*pBuf,
+SK_U32		Offset,
+SK_U32		PhysPortIndex)
+{
+	SK_GEPORT 	*pPrt;
+	SK_PNMI_VCT	*pVctData;
+	SK_U32		RetCode;
+	SK_U8		LinkSpeedUsed;
+	
+	pPrt = &pAC->GIni.GP[PhysPortIndex];
+	
+	pVctData = (SK_PNMI_VCT *) (pBuf + Offset);
+	pVctData->VctStatus = SK_PNMI_VCT_NONE;
+	
+	if (!pPrt->PHWLinkUp) {
+		
+		/* Was a VCT test ever made before? */
+		if (pAC->Pnmi.VctStatus[PhysPortIndex] & SK_PNMI_VCT_TEST_DONE) {
+			if ((pAC->Pnmi.VctStatus[PhysPortIndex] & SK_PNMI_VCT_LINK)) {
+				pVctData->VctStatus |= SK_PNMI_VCT_OLD_VCT_DATA;
+			}
+			else {
+				pVctData->VctStatus |= SK_PNMI_VCT_NEW_VCT_DATA;
+			}
+		}
+		
+		/* Check VCT test status. */
+		RetCode = SkGmCableDiagStatus(pAC,IoC, PhysPortIndex, SK_FALSE);
+		if (RetCode == 2) { /* VCT test is running. */
+			pVctData->VctStatus |= SK_PNMI_VCT_RUNNING;
+		}
+		else { /* VCT data was copied to pAC here. Check PENDING state. */
+			if (pAC->Pnmi.VctStatus[PhysPortIndex] & SK_PNMI_VCT_PENDING) {
+				pVctData->VctStatus |= SK_PNMI_VCT_NEW_VCT_DATA;
+			}
+		}
+		
+		if (pPrt->PCableLen != 0xff) { /* Old DSP value. */
+			pVctData->VctStatus |= SK_PNMI_VCT_OLD_DSP_DATA;
+		}
+	}
+	else {
+		
+		/* Was a VCT test ever made before? */
+		if (pAC->Pnmi.VctStatus[PhysPortIndex] & SK_PNMI_VCT_TEST_DONE) {
+			pVctData->VctStatus &= ~SK_PNMI_VCT_NEW_VCT_DATA;
+			pVctData->VctStatus |= SK_PNMI_VCT_OLD_VCT_DATA;
+		}
+		
+		/* DSP only valid in 100/1000 modes. */
+		LinkSpeedUsed = pAC->GIni.GP[PhysPortIndex].PLinkSpeedUsed;
+		if (LinkSpeedUsed != SK_LSPEED_STAT_10MBPS) {	
+			pVctData->VctStatus |= SK_PNMI_VCT_NEW_DSP_DATA;
+		}
+	}
+
+} /* CheckVctStatus */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sk98lin/skgesirq.c linux-2.4.21-pre6/drivers/net/sk98lin/skgesirq.c
--- linux-2.4.20/drivers/net/sk98lin/skgesirq.c	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sk98lin/skgesirq.c	2003-03-26 23:48:57.000000000 +0000
@@ -2,15 +2,15 @@
  *
  * Name:	skgesirq.c
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.65 $
- * Date:	$Date: 2001/02/23 13:41:51 $
+ * Version:	$Revision: 1.81 $
+ * Date:	$Date: 2002/12/05 10:49:51 $
  * Purpose:	Special IRQ module
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998-2000 SysKonnect GmbH.
+ *	(C)Copyright 1998-2002 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 +26,89 @@
  * History:
  *
  *	$Log: skgesirq.c,v $
+ *	Revision 1.81  2002/12/05 10:49:51  rschmidt
+ *	Fixed missing Link Down Event for fiber (Bug Id #10768)
+ *	Added reading of cable length when link is up
+ *	Removed testing of unused error bits in PHY ISR
+ *	Editorial changes.
+ *	
+ *	Revision 1.80  2002/11/12 17:15:21  rschmidt
+ *	Replaced SkPnmiGetVar() by ...MacStatistic() in SkMacParity().
+ *	Editorial changes.
+ *	
+ *	Revision 1.79  2002/10/14 15:14:51  rschmidt
+ *	Changed clearing of IS_M1_PAR_ERR (MAC 1 Parity Error) in
+ *	SkMacParity() depending on GIChipRev (HW-Bug #8).
+ *	Added error messages for GPHY Auto-Negotiation Error and
+ *	FIFO Overflow/Underrun in SkPhyIsrGmac().
+ *	Editorial changes.
+ *	
+ *	Revision 1.78  2002/10/10 15:54:29  mkarl
+ *	changes for PLinkSpeedUsed
+ *	
+ *	Revision 1.77  2002/09/12 08:58:51  rwahl
+ *	Retrieve counters needed for XMAC errata workarounds directly because
+ *	PNMI returns corrected counter values (e.g. #10620).
+ *	
+ *	Revision 1.76  2002/08/16 15:21:54  rschmidt
+ *	Replaced all if(GIChipId == CHIP_ID_GENESIS) with new entry GIGenesis.
+ *	Replaced wrong 1st para pAC with IoC in SK_IN/OUT macros.
+ *	Editorial changes.
+ *	
+ *	Revision 1.75  2002/08/12 13:50:47  rschmidt
+ *	Changed clearing of IS_M1_PAR_ERR (MAC 1 Parity Error) in
+ *	SkMacParity() by GMF_CLI_TX_FC instead of GMF_CLI_TX_PE (HW-Bug #8).
+ *	Added clearing of IS_IRQ_TIST_OV and IS_IRQ_SENSOR in SkGeHwErr().
+ *	Corrected handling of Link Up and Auto-Negotiation Over for GPHY.
+ *	in SkGePortCheckUpGmac().
+ *	Editorial changes.
+ *	
+ *	Revision 1.74  2002/08/08 16:17:04  rschmidt
+ *	Added PhyType check for SK_HWEV_SET_ROLE event (copper only)
+ *	Changed Link Up check reading PHY Specific Status (YUKON)
+ *	Editorial changes
+ *	
+ *	Revision 1.73  2002/07/15 18:36:53  rwahl
+ *	Editorial changes.
+ *	
+ *	Revision 1.72  2002/07/15 15:46:26  rschmidt
+ *	Added new event: SK_HWEV_SET_SPEED
+ *	Editorial changes
+ *	
+ *	Revision 1.71  2002/06/10 09:34:19  rschmidt
+ *	Editorial changes
+ *	
+ *	Revision 1.70  2002/06/05 08:29:18  rschmidt
+ *	SkXmRxTxEnable() replaced by SkMacRxTxEnable().
+ *	Editorial changes.
+ *	
+ *	Revision 1.69  2002/04/25 13:03:49  rschmidt
+ *	Changes for handling YUKON.
+ *	Use of #ifdef OTHER_PHY to eliminate code for unused Phy types.
+ *	Replaced all XMAC-access macros by functions: SkMacRxTxDisable(),
+ *	SkMacIrqDisable().
+ *	Added handling for GMAC FIFO in SkMacParity().
+ *	Replaced all SkXm...() functions with SkMac...() to handle also
+ *	YUKON's GMAC.
+ *	Macros for XMAC PHY access PHY_READ(), PHY_WRITE() replaced
+ *	by functions SkXmPhyRead(), SkXmPhyWrite().
+ *	Disabling all PHY interrupts moved to SkMacIrqDisable().
+ *	Added handling for GPHY IRQ in SkGeSirqIsr().
+ *	Removed status parameter from MAC IRQ handler SkMacIrq().
+ *	Added SkGePortCheckUpGmac(), SkPhyIsrGmac() for GMAC.
+ *	Editorial changes
+ *	
+ *	Revision 1.68  2002/02/26 15:24:53  rwahl
+ *	Fix: no link with manual configuration (#10673). The previous fix for
+ *	#10639 was removed. So for RLMT mode = CLS the RLMT may switch to
+ *	misconfigured port. It should not occur for the other RLMT modes.
+ *	
+ *	Revision 1.67  2001/11/20 09:19:58  rwahl
+ *	Reworked bugfix #10639 (no dependency to RLMT mode).
+ *	
+ *	Revision 1.66  2001/10/26 07:52:53  afischer
+ *	Port switching bug in `check local link` mode
+ *	
  *	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
@@ -254,49 +337,53 @@
  *
  *	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
+ *	The bits of the slow path mask are checked after that and then the
+ *	entry into the so-called "slow path" is prepared. It is an implementors
  *	decision whether this is executed directly or just scheduled by
- *	disabling the mask. In the interrupt service routine events may be
+ *	disabling the mask. In the interrupt service routine some 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
+ *	The Interrupt source register of the adapter is NOT read by this module.
+ *  SO if the drivers implementor needs a while loop around the
+ *	slow data paths interrupt bits, he needs to call the SkGeSirqIsr() for
  *	each loop entered.
  *
- *	However, the XMAC Interrupt status registers are read in a while loop.
+ *	However, the MAC Interrupt status registers are read in a while loop.
  *
  */
- 
+
 static const char SysKonnectFileId[] =
-	"$Id: skgesirq.c,v 1.65 2001/02/23 13:41:51 gklug Exp $" ;
+	"$Id: skgesirq.c,v 1.81 2002/12/05 10:49:51 rschmidt 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. */
+#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);
+static int	SkGePortCheckUpGmac(SK_AC*, SK_IOC, int);
+static void	SkPhyIsrBcom(SK_AC*, SK_IOC, int, SK_U16);
+static void	SkPhyIsrGmac(SK_AC*, SK_IOC, int, SK_U16);
+#ifdef OTHER_PHY
 static int	SkGePortCheckUpLone(SK_AC*, SK_IOC, int);
 static int	SkGePortCheckUpNat(SK_AC*, SK_IOC, int);
-static void	SkPhyIsrBcom(SK_AC*, SK_IOC, int, SK_U16);
 static void	SkPhyIsrLone(SK_AC*, SK_IOC, int, SK_U16);
+#endif /* OTHER_PHY */
 
 /*
- * Define an array of RX counter which are checked
- * in AutoSense mode to check whether a link is not able to autonegotiate.
+ * array of Rx counter from XMAC which are checked
+ * in AutoSense mode to check whether a link is not able to auto-negotiate.
  */
-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,
+static const SK_U16 SkGeRxRegs[]= {
+	XM_RXF_64B,
+	XM_RXF_127B,
+	XM_RXF_255B,
+	XM_RXF_511B,
+	XM_RXF_1023B,
+	XM_RXF_MAX_SZ
 } ;
 
 #ifdef __C2MAN__
@@ -310,7 +397,7 @@
 {}
 #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 */
@@ -320,17 +407,17 @@
  *	SkHWInitDefSense() - Default Autosensing mode initialization
  *
  * Description:
- *	This function handles the Hardware link down signal
+ *	This function sets the PLinkMode for HWInit
  *
  * Note:
  *
  */
-void	SkHWInitDefSense(
+static void SkHWInitDefSense(
 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_GEPORT	*pPrt;		/* GIni Port struct pointer */
 
 	pPrt = &pAC->GIni.GP[Port];
 
@@ -343,8 +430,7 @@
 
 	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
 		("AutoSensing: First mode %d on Port %d\n",
-		(int)SK_LMODE_AUTOFULL,
-		 Port));
+		(int)SK_LMODE_AUTOFULL, Port));
 
 	pPrt->PLinkMode = SK_LMODE_AUTOFULL;
 
@@ -362,12 +448,12 @@
  * Note:
  *
  */
-SK_U8	SkHWSenseGetNext(
+SK_U8 SkHWSenseGetNext(
 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_GEPORT	*pPrt;		/* GIni Port struct pointer */
 
 	pPrt = &pAC->GIni.GP[Port];
 
@@ -375,16 +461,16 @@
 
 	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 */
 
 
@@ -398,13 +484,13 @@
  * Note:
  *
  */
-void	SkHWSenseSetNext(
+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;
+	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
 
 	pPrt = &pAC->GIni.GP[Port];
 
@@ -415,7 +501,9 @@
 	}
 
 	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
-		("AutoSensing: next mode %d on Port %d\n", (int)NewMode, Port));
+		("AutoSensing: next mode %d on Port %d\n",
+		(int)NewMode, Port));
+
 	pPrt->PLinkMode = NewMode;
 
 	return;
@@ -432,73 +520,47 @@
  * Note:
  *
  */
-void	SkHWLinkDown(
+void SkHWLinkDown(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
 int		Port)		/* Port Index (MAC_1 + n) */
 {
-	SK_GEPORT	*pPrt;
-	SK_U16		Word;
+	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
 
 	pPrt = &pAC->GIni.GP[Port];
 
-	/* Disable all XMAC interrupts. */
-	XM_OUT16(IoC, Port, XM_IMSK, 0xffff);
+	/* Disable all MAC interrupts */
+	SkMacIrqDisable(pAC, IoC, Port);
 
-	/* 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));
+	/* Disable Receiver and Transmitter */
+	SkMacRxTxDisable(pAC, IoC, Port);
 	
-	/* Disable all PHY interrupts. */
-	switch (pPrt->PhyType) {
-		case SK_PHY_BCOM:
-			/* Make sure that PHY is initialized. */
-			if (pAC->GIni.GP[Port].PState) {
-				/* 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);
-			}
-			break;
-		case SK_PHY_LONE:
-			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); */
-			break;
-	}
-
-	/* Init default sense mode. */
+	/* Init default sense mode */
 	SkHWInitDefSense(pAC, IoC, Port);
 
 	if (!pPrt->PHWLinkUp) {
 		return;
-	} 
+	}
 
-	SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_IRQ,
+	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->PLinkSpeedUsed = SK_LSPEED_STAT_INDETERMINATED;
 
-	/*
-	 * Reinit Phy especially when the AutoSense default is set now.
-	 */
-	SkXmInitPhy(pAC, IoC, Port, SK_FALSE);
+	/* Re-init Phy especially when the AutoSense default is set now */
+	SkMacInitPhy(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. */
+	/* Do NOT start the timer here */
 }	/* SkHWLinkDown */
 
 
@@ -512,19 +574,19 @@
  * Note:
  *
  */
-void	SkHWLinkUp(
+void SkHWLinkUp(
 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_GEPORT	*pPrt;		/* GIni Port struct pointer */
 
 	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;
@@ -533,11 +595,14 @@
 	if (pPrt->PLinkMode != SK_LMODE_AUTOHALF &&
 	    pPrt->PLinkMode != SK_LMODE_AUTOFULL &&
 	    pPrt->PLinkMode != SK_LMODE_AUTOBOTH) {
-		/* Link is up and no Autonegotiation should be done */
+		/* Link is up and no Auto-negotiation should be done */
 
 		/* Configure Port */
+		
+		/* link speed should be the configured one */
+		pPrt->PLinkSpeedUsed = pPrt->PLinkSpeed;
 
-		/* Set Link Mode */
+		/* Set Link Mode Status */
 		if (pPrt->PLinkMode == SK_LMODE_FULL) {
 			pPrt->PLinkModeStatus = SK_LMODE_STAT_FULL;
 		}
@@ -545,11 +610,11 @@
 			pPrt->PLinkModeStatus = SK_LMODE_STAT_HALF;
 		}
 
-		/* No flow control without autonegotiation */
+		/* No flow control without auto-negotiation */
 		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE;
 
-		/* RX/TX enable */
-		SkXmRxTxEnable(pAC, IoC, Port);
+		/* enable Rx/Tx */
+		SkMacRxTxEnable(pAC, IoC, Port);
 	}
 }	/* SkHWLinkUp */
 
@@ -559,29 +624,33 @@
  * SkMacParity	- does everything to handle MAC parity errors correctly
  *
  */
-static	void	SkMacParity(
+static void SkMacParity(
 SK_AC	*pAC,	/* adapter context */
 SK_IOC	IoC,	/* IO context */
-int	Port)		/* Port Index of the port failed */
+int		Port)	/* Port Index of the port failed */
 {
 	SK_EVPARA	Para;
 	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
-	SK_U64		TxMax;		/* TxMax Counter */
-	unsigned	Len;
+	SK_U32		TxMax;		/* TxMax Counter */
 
 	pPrt = &pAC->GIni.GP[Port];
 
-	/* Clear IRQ */
-	SK_OUT16(IoC, MR_ADDR(Port,TX_MFF_CTRL1), MFF_CLR_PERR);
+	/* Clear IRQ Tx Parity Error */
+	if (pAC->GIni.GIGenesis) {
+		SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_CLR_PERR);
+	}
+	else {
+		/* HW-Bug #8: cleared by GMF_CLI_TX_FC instead of GMF_CLI_TX_PE */
+		SK_OUT8(IoC, MR_ADDR(Port, TX_GMF_CTRL_T),
+			(SK_U8)((pAC->GIni.GIChipRev == 0) ? GMF_CLI_TX_FC : GMF_CLI_TX_PE));
+	}
 
 	if (pPrt->PCheckPar) {
 		if (Port == MAC_1) {
-			SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E016,
-				SKERR_SIRQ_E016MSG);
+			SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E016, SKERR_SIRQ_E016MSG);
 		}
 		else {
-			SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E017,
-				SKERR_SIRQ_E017MSG);
+			SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E017, SKERR_SIRQ_E017MSG);
 		}
 		Para.Para64 = Port;
 		SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
@@ -592,11 +661,16 @@
 	}
 
 	/* 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(pAC, Port),
-		pAC->Rlmt.Port[Port].Net->NetNumber);
-
+	if (pAC->GIni.GIGenesis) {
+		/* Snap statistic counters */
+		(void)SkXmUpdateStats(pAC, IoC, Port);
+		
+		(void)SkXmMacStatistic(pAC, IoC, Port, XM_TXF_MAX_SZ, &TxMax);
+	}
+	else {
+		(void)SkGmMacStatistic(pAC, IoC, Port, GM_TXF_1518B, &TxMax);
+	}
+	
 	if (TxMax > 0) {
 		/* From now on check the parity */
 		pPrt->PCheckPar = SK_TRUE;
@@ -612,7 +686,7 @@
  *
  * Notes:
  */
-static	void	SkGeHwErr(
+static void SkGeHwErr(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
 SK_U32	HwStatus)	/* Interrupt status word */
@@ -620,17 +694,19 @@
 	SK_EVPARA	Para;
 	SK_U16		Word;
 
-	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);
+	if ((HwStatus & (IS_IRQ_MST_ERR | IS_IRQ_STAT)) != 0) {
+		/* PCI Errors occured */
+		if ((HwStatus & IS_IRQ_STAT) != 0) {
+			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);
+			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_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON);
 		SK_OUT16(IoC, PCI_C(PCI_STATUS), Word | PCI_ERRBITS);
 		SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
 
@@ -638,68 +714,82 @@
 		SkEventQueue(pAC, SKGE_DRV, SK_DRV_ADAP_FAIL, Para);
 	}
 
-	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);
-	}
-
-	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);
-	}
-
-	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);
+	if (pAC->GIni.GIGenesis) {
+		if ((HwStatus & IS_NO_STAT_M1) != 0) {
+			/* Ignore it */
+			/* This situation is also indicated in the descriptor */
+			SK_OUT16(IoC, MR_ADDR(MAC_1, RX_MFF_CTRL1), MFF_CLR_INSTAT);
+		}
+	
+		if ((HwStatus & IS_NO_STAT_M2) != 0) {
+			/* Ignore it */
+			/* This situation is also indicated in the descriptor */
+			SK_OUT16(IoC, MR_ADDR(MAC_2, RX_MFF_CTRL1), MFF_CLR_INSTAT);
+		}
+	
+		if ((HwStatus & IS_NO_TIST_M1) != 0) {
+			/* Ignore it */
+			/* This situation is also indicated in the descriptor */
+			SK_OUT16(IoC, MR_ADDR(MAC_1, RX_MFF_CTRL1), MFF_CLR_INTIST);
+		}
+	
+		if ((HwStatus & IS_NO_TIST_M2) != 0) {
+			/* Ignore it */
+			/* This situation is also indicated in the descriptor */
+			SK_OUT16(IoC, MR_ADDR(MAC_2, RX_MFF_CTRL1), MFF_CLR_INTIST);
+		}
 	}
+	else {	/* YUKON */
+		/* This is necessary only for Rx timing measurements */
+		if ((HwStatus & IS_IRQ_TIST_OV) != 0) {
+			/* Clear Time Stamp Timer IRQ */
+			SK_OUT8(IoC, GMAC_TI_ST_CTRL, (SK_U8)GMT_ST_CLR_IRQ);
+		}
 
-	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);
+		if ((HwStatus & IS_IRQ_SENSOR) != 0) {
+			/* Clear I2C IRQ */
+			SK_OUT32(IoC, B2_I2C_IRQ, I2C_CLR_IRQ);
+		}
 	}
 
-	if (HwStatus & IS_RAM_RD_PAR) {
+	if ((HwStatus & IS_RAM_RD_PAR) != 0) {
 		SK_OUT16(IoC, B3_RI_CTRL, RI_CLR_RD_PERR);
-		SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E014, SKERR_SIRQ_E014MSG);
+		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) {
+	if ((HwStatus & IS_RAM_WR_PAR) != 0) {
 		SK_OUT16(IoC, B3_RI_CTRL, RI_CLR_WR_PERR);
-		SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E015, SKERR_SIRQ_E015MSG);
+		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) {
+	if ((HwStatus & IS_M1_PAR_ERR) != 0) {
 		SkMacParity(pAC, IoC, MAC_1);
 	}
 
-	if (HwStatus & IS_M2_PAR_ERR) {
+	if ((HwStatus & IS_M2_PAR_ERR) != 0) {
 		SkMacParity(pAC, IoC, MAC_2);
 	}
 
-	if (HwStatus & IS_R1_PAR_ERR) {
+	if ((HwStatus & IS_R1_PAR_ERR) != 0) {
 		/* Clear IRQ */
 		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;
 		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
 	}
 
-	if (HwStatus & IS_R2_PAR_ERR) {
+	if ((HwStatus & IS_R2_PAR_ERR) != 0) {
 		/* Clear IRQ */
 		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;
@@ -716,126 +806,122 @@
  *
  * Notes:
  */
-void	SkGeSirqIsr(
+void SkGeSirqIsr(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
 SK_U32	Istatus)	/* Interrupt status word */
 {
 	SK_EVPARA	Para;
-	SK_U32		RegVal32;	/* Read register Value */
-	SK_U16		XmIsr;
+	SK_U32		RegVal32;	/* Read register value */
+	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
+	unsigned 	Len;
+	SK_U64		Octets;
+	SK_U16 		PhyInt;
+	SK_U16 		PhyIMsk;
+	int			i;
 
-	if (Istatus & IS_HW_ERR) {
+	if ((Istatus & IS_HW_ERR) != 0) {
+		/* read the HW Error Interrupt source */
 		SK_IN32(IoC, B0_HWE_ISRC, &RegVal32);
+		
 		SkGeHwErr(pAC, IoC, RegVal32);
 	}
 
 	/*
 	 * Packet Timeout interrupts
 	 */
-	/* 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 occured */
+	/* Check whether MACs are correctly initialized */
+	if (((Istatus & (IS_PA_TO_RX1 | IS_PA_TO_TX1)) != 0) &&
+		pAC->GIni.GP[MAC_1].PState == SK_PRT_RESET) {
+		/* MAC 1 was not initialized but Packet timeout occured */
 		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E004,
 			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 occured */
+	if (((Istatus & (IS_PA_TO_RX2 | IS_PA_TO_TX2)) != 0) &&
+	    pAC->GIni.GP[MAC_2].PState == SK_PRT_RESET) {
+		/* MAC 2 was not initialized but Packet timeout occured */
 		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E005,
 			SKERR_SIRQ_E005MSG);
 	}
 
-	if (Istatus & IS_PA_TO_RX1) {
+	if ((Istatus & IS_PA_TO_RX1) != 0) {
 		/* 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);
 	}
 
-	if (Istatus & IS_PA_TO_RX2) {
+	if ((Istatus & IS_PA_TO_RX2) != 0) {
 		/* 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);
 	}
 
-	if (Istatus & IS_PA_TO_TX1) {
-		unsigned int	Len;
-		SK_U64		Octets;
-		SK_GEPORT	*pPrt = &pAC->GIni.GP[0];
+	if ((Istatus & IS_PA_TO_TX1) != 0) {
+		
+		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);
 
 		/*
-		 * workaround: if in half duplex mode, check for tx hangup.
+		 * 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).
+		 * 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 || 
+		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,
+			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);
+			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];
+	if ((Istatus & IS_PA_TO_TX2) != 0) {
+		
+		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);
 
-		/*
-		 * workaround: see above
-		 */
-		if ((pPrt->PLinkModeStatus == SK_LMODE_STAT_HALF || 
-		    pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOHALF) &&
+		/* 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,
+			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);
+			SkTimerStart(pAC, IoC, &pPrt->HalfDupChkTimer, SK_HALFDUP_CHK_TIME,
+				SKGE_HWAC, SK_HWEV_HALFDUP_CHK, Para);
 		}
 	}
 
-	/*
-	 * Check interrupts of the particular queues.
-	 */
-	if (Istatus & IS_R1_C) {
+	/* Check interrupts of the particular queues */
+	if ((Istatus & IS_R1_C) != 0) {
 		/* Clear IRQ */
 		SK_OUT32(IoC, B0_R1_CSR, CSR_IRQ_CL_C);
 		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E006,
@@ -846,7 +932,7 @@
 		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
 	}
 
-	if (Istatus & IS_R2_C) {
+	if ((Istatus & IS_R2_C) != 0) {
 		/* Clear IRQ */
 		SK_OUT32(IoC, B0_R2_CSR, CSR_IRQ_CL_C);
 		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E007,
@@ -857,7 +943,7 @@
 		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
 	}
 
-	if (Istatus & IS_XS1_C) {
+	if ((Istatus & IS_XS1_C) != 0) {
 		/* Clear IRQ */
 		SK_OUT32(IoC, B0_XS1_CSR, CSR_IRQ_CL_C);
 		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E008,
@@ -868,7 +954,7 @@
 		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
 	}
 
-	if (Istatus & IS_XA1_C) {
+	if ((Istatus & IS_XA1_C) != 0) {
 		/* Clear IRQ */
 		SK_OUT32(IoC, B0_XA1_CSR, CSR_IRQ_CL_C);
 		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E009,
@@ -879,7 +965,7 @@
 		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
 	}
 
-	if (Istatus & IS_XS2_C) {
+	if ((Istatus & IS_XS2_C) != 0) {
 		/* Clear IRQ */
 		SK_OUT32(IoC, B0_XS2_CSR, CSR_IRQ_CL_C);
 		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E010,
@@ -890,7 +976,7 @@
 		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
 	}
 
-	if (Istatus & IS_XA2_C) {
+	if ((Istatus & IS_XA2_C) != 0) {
 		/* Clear IRQ */
 		SK_OUT32(IoC, B0_XA2_CSR, CSR_IRQ_CL_C);
 		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E011,
@@ -901,58 +987,55 @@
 		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
 	}
 
-	/*
-	 * External reg interrupt.
-	 */
-	if (Istatus & IS_EXT_REG) {
-		SK_U16 	PhyInt;
-		SK_U16 	PhyIMsk;
-		int		i;
-		SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
-
-		/* Test IRQs from PHY. */
+	/* External reg interrupt */
+	if ((Istatus & IS_EXT_REG) != 0) {
+		/* Test IRQs from PHY */
 		for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+			
 			pPrt = &pAC->GIni.GP[i];
+			
+			if (pPrt->PState == SK_PRT_RESET) {
+				continue;
+			}
+			
 			switch (pPrt->PhyType) {
+			
 			case SK_PHY_XMAC:
 				break;
+			
 			case SK_PHY_BCOM:
-				if (pPrt->PState) {
-					PHY_READ(IoC, pPrt, i, PHY_BCOM_INT_STAT, &PhyInt);
-					PHY_READ(IoC, pPrt, i, PHY_BCOM_INT_MASK, &PhyIMsk);
+				SkXmPhyRead(pAC, IoC, i, PHY_BCOM_INT_STAT, &PhyInt);
+				SkXmPhyRead(pAC, IoC, 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,
-							SK_DBGCAT_IRQ,
-							("Port %d Bcom Int: %x Mask: %x\n",
-								i, PhyInt, PhyIMsk));
-						SkPhyIsrBcom(pAC, IoC, i, PhyInt);
-					}
+				if ((PhyInt & ~PhyIMsk) != 0) {
+					SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+						("Port %d Bcom Int: 0x%04X Mask: 0x%04X\n",
+						i, PhyInt, PhyIMsk));
+					SkPhyIsrBcom(pAC, IoC, i, PhyInt);
+				}
+				break;
+			
+			case SK_PHY_MARV_COPPER:
+			case SK_PHY_MARV_FIBER:
+				SkGmPhyRead(pAC, IoC, i, PHY_MARV_INT_STAT, &PhyInt);
+				SkGmPhyRead(pAC, IoC, i, PHY_MARV_INT_MASK, &PhyIMsk);
+
+				if ((PhyInt & PhyIMsk) != 0) {
+					SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+						("Port %d Marv Int: 0x%04X Mask: 0x%04X\n",
+						i, PhyInt, PhyIMsk));
+					SkPhyIsrGmac(pAC, IoC, i, PhyInt);
 				}
 				break;
+
+#ifdef OTHER_PHY
 			case SK_PHY_LONE:
-				PHY_READ(IoC, pPrt, i, PHY_LONE_INT_STAT, &PhyInt);
-				PHY_READ(IoC, pPrt, i, PHY_LONE_INT_ENAB, &PhyIMsk);
+				SkXmPhyRead(pAC, IoC, i, PHY_LONE_INT_STAT, &PhyInt);
+				SkXmPhyRead(pAC, IoC, i, PHY_LONE_INT_ENAB, &PhyIMsk);
 				
-				if (PhyInt & PhyIMsk) {
-					SK_DBG_MSG(
-						pAC,
-						SK_DBGMOD_HWM,
-						SK_DBGCAT_IRQ,
-						("Port %d  Lone Int: %x Mask: %x\n",
+				if ((PhyInt & PhyIMsk) != 0) {
+					SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+						("Port %d Lone Int: %x Mask: %x\n",
 						i, PhyInt, PhyIMsk));
 					SkPhyIsrLone(pAC, IoC, i, PhyInt);
 				}
@@ -960,18 +1043,17 @@
 			case SK_PHY_NAT:
 				/* todo: National */
 				break;
+#endif /* OTHER_PHY */
 			}
 		}
 	}
 
-	/*
-	 * I2C Ready interrupt
-	 */
-	if (Istatus & IS_I2C_READY) {
+	/* I2C Ready interrupt */
+	if ((Istatus & IS_I2C_READY) != 0) {
 		SkI2cIsr(pAC, IoC);
 	}
 
-	if (Istatus & IS_LNK_SYNC_M1) {
+	if ((Istatus & IS_LNK_SYNC_M1) != 0) {
 		/*
 		 * We do NOT need the Link Sync interrupt, because it shows
 		 * us only a link going down.
@@ -981,31 +1063,28 @@
 	}
 
 	/* Check MAC after link sync counter */
-	if (Istatus & IS_MAC1) {
-		XM_IN16(IoC, MAC_1, XM_ISRC, &XmIsr);
-		SkXmIrq(pAC, IoC, MAC_1, XmIsr);
+	if ((Istatus & IS_MAC1) != 0) {
+		/* IRQ from MAC 1 */
+		SkMacIrq(pAC, IoC, MAC_1);
 	}
 
-	if (Istatus & IS_LNK_SYNC_M2) {
+	if ((Istatus & IS_LNK_SYNC_M2) != 0) {
 		/*
 		 * We do NOT need the Link Sync interrupt, because it shows
 		 * us only a link going down.
 		 */
 		/* clear interrupt */
-		SK_OUT8(IoC, MR_ADDR(MAC_2,LNK_SYNC_CTRL), LED_CLR_IRQ);
+		SK_OUT8(IoC, MR_ADDR(MAC_2, LNK_SYNC_CTRL), LED_CLR_IRQ);
 	}
 
 	/* Check MAC after link sync counter */
-	if (Istatus & IS_MAC2) {
-		XM_IN16(IoC, MAC_2, XM_ISRC, &XmIsr);
-		SkXmIrq(pAC, IoC, MAC_2, XmIsr);
+	if ((Istatus & IS_MAC2) != 0) {
+		/* IRQ from MAC 2 */
+		SkMacIrq(pAC, IoC, MAC_2);
 	}
 
-	/*
-	 * Timer interrupt
-	 *  To be served last
-	 */
-	if (Istatus & IS_TIMINT) {
+	/* Timer interrupt (served last) */
+	if ((Istatus & IS_TIMINT) != 0) {
 		SkHwtIsr(pAC, IoC);
 	}
 }	/* SkGeSirqIsr */
@@ -1013,24 +1092,23 @@
 
 /******************************************************************************
  *
- * SkGePortCheckShorts - Implementing of the Workaround Errata # 2
+ * SkGePortCheckShorts - Implementing XMAC Workaround Errata # 2
  *
  * return:
  *	0	o.k. nothing needed
  *	1	Restart needed on this port
  */
-int	SkGePortCheckShorts(
+static int	SkGePortCheckShorts(
 SK_AC	*pAC,		/* Adapter Context */
 SK_IOC	IoC,		/* IO Context */
 int		Port)		/* Which port should be checked */
 {
-	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_U32		Shorts;			/* Short Event Counter */
+	SK_U32		CheckShorts;	/* Check value for Short Event Counter */
+	SK_U64		RxCts;			/* Rx Counter (packets on network) */
+	SK_U32		RxTmp;			/* Rx temp. Counter */
+	SK_U32		FcsErrCts;		/* FCS Error Counter */
 	SK_GEPORT	*pPrt;			/* GIni Port struct pointer */
-	unsigned 	Len;
 	int			Rtv;			/* Return value */
 	int			i;
 
@@ -1039,48 +1117,35 @@
 	/* Default: no action */
 	Rtv = SK_HW_PS_NONE;
 
-	/*
-	 * 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(pAC, Port),
-		pAC->Rlmt.Port[Port].Net->NetNumber);
+	(void)SkXmUpdateStats(pAC, IoC, Port);
+
+	/* Extra precaution: check for short Event counter */
+	(void)SkXmMacStatistic(pAC, IoC, Port, XM_RXE_SHT_ERR, &Shorts);
 
 	/*
-	 * Read RX counter (packets seen on the network and not neccesarily
+	 * Read Rx counter (packets seen on the network and not necessarily
 	 * really received.
 	 */
-	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(pAC, Port),
-			pAC->Rlmt.Port[Port].Net->NetNumber);
-		RxCts += RxTmp;
+	for (i = 0; i < sizeof(SkGeRxRegs)/sizeof(SkGeRxRegs[0]); i++) {
+		(void)SkXmMacStatistic(pAC, IoC, Port, SkGeRxRegs[i], &RxTmp);
+		RxCts += (SK_U64)RxTmp;
 	}
 
 	/* On default: check shorts against zero */
 	CheckShorts = 0;
 
-	/*
-	 * Extra extra precaution on active links:
-	 */
+	/* Extra precaution on active links */
 	if (pPrt->PHWLinkUp) {
-		/*
-		 * Reset Link Restart counter
-		 */
+		/* 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(pAC, Port),
-			pAC->Rlmt.Port[Port].Net->NetNumber);
+		(void)SkXmMacStatistic(pAC, IoC, Port, XM_RXF_FCS_ERR, &FcsErrCts);
 		
 		if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE &&
 		    pPrt->PLipaAutoNeg == SK_LIPA_UNKNOWN &&
@@ -1091,13 +1156,11 @@
 			 * manual full/half duplex mode.
 			 */
 			if (RxCts == pPrt->PPrevRx) {
-				/*
-				 * Nothing received
-				 * restart link
-				 */
+				/* Nothing received, restart link */
 				pPrt->PPrevFcs = FcsErrCts;
 				pPrt->PPrevShorts = Shorts;
-				return (SK_HW_PS_RESTART);
+				
+				return(SK_HW_PS_RESTART);
 			}
 			else {
 				pPrt->PLipaAutoNeg = SK_LIPA_MANUAL;
@@ -1118,7 +1181,7 @@
 			pPrt->PPrevFcs = FcsErrCts;
 			pPrt->PPrevShorts = Shorts;
 
-			return (SK_HW_PS_NONE);
+			return(SK_HW_PS_NONE);
 		}
 
 		pPrt->PPrevFcs = FcsErrCts;
@@ -1134,8 +1197,8 @@
 	pPrt->PPrevShorts = Shorts;
 	pPrt->PPrevRx = RxCts;
 
-	return (Rtv);
-}	/* SkGePortCheckShorts*/
+	return(Rtv);
+}	/* SkGePortCheckShorts */
 
 
 /******************************************************************************
@@ -1147,22 +1210,27 @@
  *	1	Restart needed on this port
  *	2	Link came up
  */
-int	SkGePortCheckUp(
+static int	SkGePortCheckUp(
 SK_AC	*pAC,		/* Adapter Context */
 SK_IOC	IoC,		/* IO Context */
 int		Port)		/* Which port should be checked */
 {
 	switch (pAC->GIni.GP[Port].PhyType) {
 	case SK_PHY_XMAC:
-		return (SkGePortCheckUpXmac(pAC, IoC, Port));
+		return(SkGePortCheckUpXmac(pAC, IoC, Port));
 	case SK_PHY_BCOM:
-		return (SkGePortCheckUpBcom(pAC, IoC, Port));
+		return(SkGePortCheckUpBcom(pAC, IoC, Port));
+	case SK_PHY_MARV_COPPER:
+	case SK_PHY_MARV_FIBER:
+		return(SkGePortCheckUpGmac(pAC, IoC, Port));
+#ifdef OTHER_PHY
 	case SK_PHY_LONE:
-		return (SkGePortCheckUpLone(pAC, IoC, Port));
+		return(SkGePortCheckUpLone(pAC, IoC, Port));
 	case SK_PHY_NAT:
-		return (SkGePortCheckUpNat(pAC, IoC, Port));
+		return(SkGePortCheckUpNat(pAC, IoC, Port));
+#endif /* OTHER_PHY */
 	}
-	return (SK_HW_PS_NONE);
+	return(SK_HW_PS_NONE);
 }	/* SkGePortCheckUp */
 
 
@@ -1175,14 +1243,13 @@
  *	1	Restart needed on this port
  *	2	Link came up
  */
-static int	SkGePortCheckUpXmac(
+static int SkGePortCheckUpXmac(
 SK_AC	*pAC,		/* Adapter Context */
 SK_IOC	IoC,		/* IO Context */
 int		Port)		/* Which port should be checked */
 {
-	SK_U64		Shorts;		/* Short Event Counter */
+	SK_U32		Shorts;		/* Short Event Counter */
 	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
-	unsigned	Len;
 	int			Done;
 	SK_U32		GpReg;		/* General Purpose register value */
 	SK_U16		Isrc;		/* Interrupt source register */
@@ -1190,26 +1257,25 @@
 	SK_U16		LpAb;		/* Link Partner Ability */
 	SK_U16		ResAb;		/* Resolved Ability */
 	SK_U16		ExtStat;	/* Extended Status Register */
-	SK_BOOL		AutoNeg;	/* Is Autonegotiation used ? */
+	SK_BOOL		AutoNeg;	/* Is Auto-negotiation 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 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 {
@@ -1218,27 +1284,26 @@
 
 	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 */
+				/* 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));
 
-				/* 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(pAC, Port),
-					pAC->Rlmt.Port[Port].Net->NetNumber);
+				(void)SkXmUpdateStats(pAC, IoC, Port);
+
+				/* We now need to reinitialize the PrevShorts counter */
+				(void)SkXmMacStatistic(pAC, IoC, Port, XM_RXE_SHT_ERR, &Shorts);
 				pPrt->PPrevShorts = Shorts;
 
-				pAC->GIni.GP[Port].PLinkBroken = SK_FALSE;
+				pPrt->PLinkBroken = SK_FALSE;
 
 				/*
 				 * Link Restart Workaround:
@@ -1248,31 +1313,34 @@
 				 *  happening we check for a maximum number
 				 *  of consecutive restart. If those happens,
 				 *  we do NOT restart the active link and
-				 *  check whether the lionk is now o.k.
+				 *  check whether the link is now o.k.
 				 */
-				pAC->GIni.GP[Port].PLinkResCt ++;
+				pPrt->PLinkResCt++;
+				
 				pPrt->PAutoNegTimeOut = 0;
 
-				if (pAC->GIni.GP[Port].PLinkResCt < SK_MAX_LRESTART) {
-					return (SK_HW_PS_RESTART);
+				if (pPrt->PLinkResCt < SK_MAX_LRESTART) {
+					return(SK_HW_PS_RESTART);
 				}
 
-				SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+				pPrt->PLinkResCt = 0;
+				
+				SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
 					("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));
-				SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+				pPrt->PIsave = 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));
 
 				/* Do nothing more if link is broken */
-				return (SK_HW_PS_NONE);
+				return(SK_HW_PS_NONE);
 			}
 		}
 		else {
 			/* Do nothing more if link is broken */
-			return (SK_HW_PS_NONE);
+			return(SK_HW_PS_NONE);
 		}
 
 	}
@@ -1280,69 +1348,67 @@
 		/* Link was not broken, check if it is */
 		XM_IN16(IoC, Port, XM_ISRC, &Isrc);
 		IsrcSum |= Isrc;
-		if ((Isrc & XM_IS_INP_ASS) == XM_IS_INP_ASS) {
+		if ((Isrc & XM_IS_INP_ASS) != 0) {
 			XM_IN16(IoC, Port, XM_ISRC, &Isrc);
 			IsrcSum |= Isrc;
-			if ((Isrc & XM_IS_INP_ASS) == XM_IS_INP_ASS) {
+			if ((Isrc & XM_IS_INP_ASS) != 0) {
 				XM_IN16(IoC, Port, XM_ISRC, &Isrc);
 				IsrcSum |= Isrc;
-				if ((Isrc & XM_IS_INP_ASS) == XM_IS_INP_ASS) {
+				if ((Isrc & XM_IS_INP_ASS) != 0) {
 					pPrt->PLinkBroken = SK_TRUE;
-					/*
-					 * Re-Init Link partner Autoneg flag
-					 */
+					/* Re-Init Link partner Autoneg flag */
 					pPrt->PLipaAutoNeg = SK_LIPA_UNKNOWN;
-					SK_DBG_MSG(pAC,SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+					SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
 						("Link broken Port %d\n", Port));
 
-					/* Cable removed-> reinit sense mode. */
-					/* Init default sense mode. */
+					/* Cable removed-> reinit sense mode */
 					SkHWInitDefSense(pAC, IoC, Port);
 
-					return (SK_HW_PS_RESTART);
+					return(SK_HW_PS_RESTART);
 				}
 			}
 		}
 		else {
 			SkXmAutoNegLipaXmac(pAC, IoC, Port, Isrc);
 			if (SkGePortCheckShorts(pAC, IoC, Port) == SK_HW_PS_RESTART) {
-				return (SK_HW_PS_RESTART);
+				return(SK_HW_PS_RESTART);
 			}
 		}
 	}
 
 	/*
 	 * here we usually can check whether the link is in sync and
-	 * autonegotiation is done.
+	 * auto-negotiation is done.
 	 */
 	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 Auto-negotiation Done interrupt only if link is in sync */
+			pPrt->PIsave = IsrcSum & XM_IS_AND;
 		}
-#ifdef	DEBUG
-		if (pPrt->PIsave & (XM_IS_AND)) {
-			SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+#ifdef DEBUG
+		if ((pPrt->PIsave & XM_IS_AND) != 0) {
+			SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
 				("AutoNeg done rescheduled Port %d\n", Port));
 		}
-#endif
-		return (SK_HW_PS_NONE);
+#endif /* DEBUG */
+		return(SK_HW_PS_NONE);
 	}
 
 	if (AutoNeg) {
-		if (IsrcSum & XM_IS_AND) {
+		if ((IsrcSum & XM_IS_AND) != 0) {
 			SkHWLinkUp(pAC, IoC, Port);
-			Done = SkXmAutoNegDone(pAC,IoC,Port);
+			Done = SkMacAutoNegDone(pAC, IoC, Port);
 			if (Done != SK_AND_OK) {
-				/* 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,
+				/* Get PHY parameters, for debugging only */
+				SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_AUNE_LP, &LpAb);
+				SkXmPhyRead(pAC, IoC, 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));
 					
@@ -1354,44 +1420,30 @@
 					SkHWSenseSetNext(pAC, IoC, Port, NextMode);
 				}
 
-				return (SK_HW_PS_RESTART);
-			}
-			else {
-				/*
-				 * 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_RESTART);
 			}
-		} 
-		
-		/*
-		 * AutoNeg not done, but HW link is up. Check for timeouts
-		 */
-		pPrt->PAutoNegTimeOut ++;
-		if (pPrt->PAutoNegTimeOut >= SK_AND_MAX_TO) {
 			/*
-			 * Increase the Timeout counter.
+			 * Dummy Read extended status to prevent extra link down/ups
+			 * (clear Page Received bit if set)
 			 */
-			pPrt->PAutoNegTOCt ++;
+			SkXmPhyRead(pAC, IoC, 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);
+		}
+		
+		/* AutoNeg not done, but HW link is up. Check for timeouts */
+		pPrt->PAutoNegTimeOut++;
+		if (pPrt->PAutoNegTimeOut >= SK_AND_MAX_TO) {
+			/* Increase the Timeout counter */
+			pPrt->PAutoNegTOCt++;
 
-			/*
-			 * Timeout occured.
-			 * What do we need now?
-			 */
-			SK_DBG_MSG(pAC,SK_DBGMOD_HWM,
-				SK_DBGCAT_IRQ,
-				("AutoNeg timeout Port %d\n",
-				 Port));
+			/* Timeout occured */
+			SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+				("AutoNeg timeout Port %d\n", Port));
 			if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE &&
 				pPrt->PLipaAutoNeg != SK_LIPA_AUTO) {
-				/*
-				 * Timeout occured
-				 * Set Link manually up.
-				 */
+				/* 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));
@@ -1403,10 +1455,10 @@
 				/*
 				 * This is rather complicated.
 				 * we need to check here whether the LIPA_AUTO
-				 * we saw before is false alert. We saw at one 
+				 * 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.
+				 * just one auto-neg packet and does no further
+				 * auto-negotiation.
 				 * Solution: we restart the autosensing after
 				 * a few timeouts.
 				 */
@@ -1415,30 +1467,31 @@
 				SkHWInitDefSense(pAC, IoC, Port);
 			}
 
-			/*
-			 * Do the restart
-			 */
-			return (SK_HW_PS_RESTART);
+			/* Do the restart */
+			return(SK_HW_PS_RESTART);
 		}
 	}
 	else {
-		/*
-		 * Link is up and we don't need more.
-		 */
-#ifdef	DEBUG
+		/* 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));
 		}
-#endif
-
-		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_IRQ,
+#endif /* DEBUG */
+		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);
+		
+		/*
+		 * Link sync (GP) and so assume a good connection. But if not received
+		 * a bunch of frames received in a time slot (maybe broken tx cable)
+		 * the port is restart.
+		 */
+		return(SK_HW_PS_LINK);
 	}
 
-	return (SK_HW_PS_NONE);
+	return(SK_HW_PS_NONE);
 }	/* SkGePortCheckUpXmac */
 
 
@@ -1451,7 +1504,7 @@
  *	1	Restart needed on this port
  *	2	Link came up
  */
-static int	SkGePortCheckUpBcom(
+static int SkGePortCheckUpBcom(
 SK_AC	*pAC,	/* Adapter Context */
 SK_IOC	IoC,	/* IO Context */
 int		Port)	/* Which port should be checked */
@@ -1465,20 +1518,22 @@
 #ifdef DEBUG
 	SK_U16		LpAb;
 	SK_U16		ExtStat;
-#endif	/* DEBUG */
-	SK_BOOL		AutoNeg;	/* Is Autonegotiation used ? */
+#endif /* DEBUG */
+	SK_BOOL		AutoNeg;	/* Is Auto-negotiation used ? */
 
 	pPrt = &pAC->GIni.GP[Port];
 
 	/* Check for No HCD Link events (#10523) */
-	PHY_READ(IoC, pPrt, Port, PHY_BCOM_INT_STAT, &Isrc);
+	SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_INT_STAT, &Isrc);
 
 #ifdef xDEBUG
-	if ((Isrc & ~0x1800) == 0x70) {
+	if ((Isrc & ~(PHY_B_IS_HCT | PHY_B_IS_LCT) ==
+		(PHY_B_IS_SCR_S_ER | PHY_B_IS_RRS_CHANGE | PHY_B_IS_LRS_CHANGE)) {
+
 		SK_U32	Stat1, Stat2, Stat3;
 
 		Stat1 = 0;
-		PHY_READ(pAC, pPrt, Port, PHY_BCOM_INT_MASK, &Stat1);
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_INT_MASK, &Stat1);
 		CMSMPrintString(
 			pAC->pConfigTable,
 			MSG_TYPE_RUNTIME_INFO,
@@ -1487,14 +1542,14 @@
 			(void *)Stat1);
 
 		Stat1 = 0;
-		PHY_READ(pAC, pPrt, Port, PHY_BCOM_CTRL, &Stat1);
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_CTRL, &Stat1);
 		Stat2 = 0;
-		PHY_READ(pAC, pPrt, Port, PHY_BCOM_STAT, &Stat2);
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_STAT, &Stat2);
 		Stat1 = Stat1 << 16 | Stat2;
 		Stat2 = 0;
-		PHY_READ(pAC, pPrt, Port, PHY_BCOM_AUNE_ADV, &Stat2);
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_ADV, &Stat2);
 		Stat3 = 0;
-		PHY_READ(pAC, pPrt, Port, PHY_BCOM_AUNE_LP, &Stat3);
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_LP, &Stat3);
 		Stat2 = Stat2 << 16 | Stat3;
 		CMSMPrintString(
 			pAC->pConfigTable,
@@ -1504,14 +1559,14 @@
 			(void *)Stat2);
 
 		Stat1 = 0;
-		PHY_READ(pAC, pPrt, Port, PHY_BCOM_AUNE_EXP, &Stat1);
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_EXP, &Stat1);
 		Stat2 = 0;
-		PHY_READ(pAC, pPrt, Port, PHY_BCOM_EXT_STAT, &Stat2);
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_EXT_STAT, &Stat2);
 		Stat1 = Stat1 << 16 | Stat2;
 		Stat2 = 0;
-		PHY_READ(pAC, pPrt, Port, PHY_BCOM_1000T_CTRL, &Stat2);
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_CTRL, &Stat2);
 		Stat3 = 0;
-		PHY_READ(pAC, pPrt, Port, PHY_BCOM_1000T_STAT, &Stat3);
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_STAT, &Stat3);
 		Stat2 = Stat2 << 16 | Stat3;
 		CMSMPrintString(
 			pAC->pConfigTable,
@@ -1521,14 +1576,14 @@
 			(void *)Stat2);
 
 		Stat1 = 0;
-		PHY_READ(pAC, pPrt, Port, PHY_BCOM_P_EXT_CTRL, &Stat1);
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_P_EXT_CTRL, &Stat1);
 		Stat2 = 0;
-		PHY_READ(pAC, pPrt, Port, PHY_BCOM_P_EXT_STAT, &Stat2);
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_P_EXT_STAT, &Stat2);
 		Stat1 = Stat1 << 16 | Stat2;
 		Stat2 = 0;
-		PHY_READ(pAC, pPrt, Port, PHY_BCOM_AUX_CTRL, &Stat2);
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, &Stat2);
 		Stat3 = 0;
-		PHY_READ(pAC, pPrt, Port, PHY_BCOM_AUX_STAT, &Stat3);
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_STAT, &Stat3);
 		Stat2 = Stat2 << 16 | Stat3;
 		CMSMPrintString(
 			pAC->pConfigTable,
@@ -1537,16 +1592,18 @@
 			(void *)Stat1,
 			(void *)Stat2);
 	}
-#endif	/* DEBUG */
+#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);
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_CTRL, &Ctrl);
+		SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_CTRL,
+			(SK_U16)(Ctrl | PHY_CT_LOOP));
+		SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_CTRL,
+			(SK_U16)(Ctrl & ~PHY_CT_LOOP));
 		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
 			("No HCD Link event, Port %d\n", Port));
 #ifdef xDEBUG
@@ -1556,14 +1613,14 @@
 			"No HCD link event, port %d.",
 			(void *)Port,
 			(void *)NULL);
-#endif	/* DEBUG */
+#endif /* DEBUG */
 	}
 
 	/* Not obsolete: link status bit is latched to 0 and autoclearing! */
-	PHY_READ(IoC, pPrt, Port, PHY_BCOM_STAT, &PhyStat);
+	SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_STAT, &PhyStat);
 
 	if (pPrt->PHWLinkUp) {
-		return (SK_HW_PS_NONE);
+		return(SK_HW_PS_NONE);
 	}
 
 #ifdef xDEBUG
@@ -1571,7 +1628,7 @@
 		SK_U32	Stat1, Stat2, Stat3;
 
 		Stat1 = 0;
-		PHY_READ(pAC, pPrt, Port, PHY_BCOM_INT_MASK, &Stat1);
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_INT_MASK, &Stat1);
 		CMSMPrintString(
 			pAC->pConfigTable,
 			MSG_TYPE_RUNTIME_INFO,
@@ -1580,14 +1637,14 @@
 			(void *)Stat1);
 
 		Stat1 = 0;
-		PHY_READ(pAC, pPrt, Port, PHY_BCOM_CTRL, &Stat1);
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_CTRL, &Stat1);
 		Stat2 = 0;
-		PHY_READ(pAC, pPrt, Port, PHY_BCOM_STAT, &PhyStat);
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_STAT, &PhyStat);
 		Stat1 = Stat1 << 16 | PhyStat;
 		Stat2 = 0;
-		PHY_READ(pAC, pPrt, Port, PHY_BCOM_AUNE_ADV, &Stat2);
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_ADV, &Stat2);
 		Stat3 = 0;
-		PHY_READ(pAC, pPrt, Port, PHY_BCOM_AUNE_LP, &Stat3);
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_LP, &Stat3);
 		Stat2 = Stat2 << 16 | Stat3;
 		CMSMPrintString(
 			pAC->pConfigTable,
@@ -1597,14 +1654,14 @@
 			(void *)Stat2);
 
 		Stat1 = 0;
-		PHY_READ(pAC, pPrt, Port, PHY_BCOM_AUNE_EXP, &Stat1);
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_EXP, &Stat1);
 		Stat2 = 0;
-		PHY_READ(pAC, pPrt, Port, PHY_BCOM_EXT_STAT, &Stat2);
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_EXT_STAT, &Stat2);
 		Stat1 = Stat1 << 16 | Stat2;
 		Stat2 = 0;
-		PHY_READ(pAC, pPrt, Port, PHY_BCOM_1000T_CTRL, &Stat2);
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_CTRL, &Stat2);
 		Stat3 = 0;
-		PHY_READ(pAC, pPrt, Port, PHY_BCOM_1000T_STAT, &ResAb);
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_STAT, &ResAb);
 		Stat2 = Stat2 << 16 | ResAb;
 		CMSMPrintString(
 			pAC->pConfigTable,
@@ -1614,14 +1671,14 @@
 			(void *)Stat2);
 
 		Stat1 = 0;
-		PHY_READ(pAC, pPrt, Port, PHY_BCOM_P_EXT_CTRL, &Stat1);
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_P_EXT_CTRL, &Stat1);
 		Stat2 = 0;
-		PHY_READ(pAC, pPrt, Port, PHY_BCOM_P_EXT_STAT, &Stat2);
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_P_EXT_STAT, &Stat2);
 		Stat1 = Stat1 << 16 | Stat2;
 		Stat2 = 0;
-		PHY_READ(pAC, pPrt, Port, PHY_BCOM_AUX_CTRL, &Stat2);
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, &Stat2);
 		Stat3 = 0;
-		PHY_READ(pAC, pPrt, Port, PHY_BCOM_AUX_STAT, &Stat3);
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_STAT, &Stat3);
 		Stat2 = Stat2 << 16 | Stat3;
 		CMSMPrintString(
 			pAC->pConfigTable,
@@ -1630,9 +1687,9 @@
 			(void *)Stat1,
 			(void *)Stat2);
 	}
-#endif	/* DEBUG */
+#endif /* DEBUG */
 
-	/* Now wait for each port's link. */
+	/* Now wait for each port's link */
 	if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
 		AutoNeg = SK_FALSE;
 	}
@@ -1642,76 +1699,59 @@
 
 	/*
 	 * Here we usually can check whether the link is in sync and
-	 * autonegotiation is done.
+	 * auto-negotiation is done.
 	 */
-#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 */
+	SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_STAT, &PhyStat);
 
-	SkXmAutoNegLipaBcom(pAC, IoC, Port, PhyStat);
+	SkMacAutoNegLipaPhy(pAC, IoC, Port, PhyStat);
 	
 	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
-		("AutoNeg:%d, PhyStat: %Xh.\n", AutoNeg, PhyStat));
+		("AutoNeg: %d, PhyStat: 0x%04x\n", AutoNeg, PhyStat));
 
-	PHY_READ(IoC, pPrt, Port, PHY_BCOM_1000T_STAT, &ResAb);
+	SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_STAT, &ResAb);
 
-	if (ResAb & PHY_B_1000S_MSF) {
+	if ((ResAb & PHY_B_1000S_MSF) != 0) {
 		/* 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_HW_PS_RESTART);
+		
+		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 {
-		pPrt->PMSStatus = SK_MS_STAT_SLAVE;
+		return(SK_HW_PS_NONE);
 	}
 	
+	pPrt->PMSStatus = ((ResAb & PHY_B_1000S_MSR) != 0) ?
+		SK_MS_STAT_MASTER : SK_MS_STAT_SLAVE;
+	
 	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
-		("AutoNeg:%d, PhyStat: %Xh.\n", AutoNeg, PhyStat));
+		("AutoNeg: %d, PhyStat: 0x%04x\n", AutoNeg, PhyStat));
 
 	if (AutoNeg) {
-		if (PhyStat & PHY_ST_AN_OVER) {
+		if ((PhyStat & PHY_ST_AN_OVER) != 0) {
 			SkHWLinkUp(pAC, IoC, Port);
-			Done = SkXmAutoNegDone(pAC, IoC, Port);
+			Done = SkMacAutoNegDone(pAC, IoC, Port);
 			if (Done != SK_AND_OK) {
 #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);
+				/* Get PHY parameters, for debugging only */
+				SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_LP, &LpAb);
+				SkXmPhyRead(pAC, IoC, 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);
+#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);
+				/* Dummy read ISR to prevent extra link downs/ups */
+				SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_INT_STAT, &ExtStat);
 
-				if ((ExtStat & ~0x1800) != 0) {
+				if ((ExtStat & ~(PHY_B_IS_HCT | PHY_B_IS_LCT)) != 0) {
 					CMSMPrintString(
 						pAC->pConfigTable,
 						MSG_TYPE_RUNTIME_INFO,
@@ -1719,30 +1759,28 @@
 						(void *)ExtStat,
 						(void *)NULL);
 				}
-#endif	/* DEBUG */
+#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 {	/* !AutoNeg */
-		/*
-		 * Link is up and we don't need more.
-		 */
-#ifdef	DEBUG
+		/* 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));
 		}
-#endif
+#endif /* DEBUG */
 
 #ifdef xDEBUG
-		/* Dummy read ISR to prevent extra link downs/ups. */
-		PHY_READ(IoC, pPrt, Port, PHY_BCOM_INT_STAT, &ExtStat);
+		/* Dummy read ISR to prevent extra link downs/ups */
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_INT_STAT, &ExtStat);
 
-		if ((ExtStat & ~0x1800) != 0) {
+		if ((ExtStat & ~(PHY_B_IS_HCT | PHY_B_IS_LCT)) != 0) {
 			CMSMPrintString(
 				pAC->pConfigTable,
 				MSG_TYPE_RUNTIME_INFO,
@@ -1750,20 +1788,136 @@
 				(void *)ExtStat,
 				(void *)NULL);
 		}
-#endif	/* DEBUG */
+#endif /* DEBUG */
 		
 		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);
+		return(SK_HW_PS_LINK);
 	}
 
-	return (SK_HW_PS_NONE);
+	return(SK_HW_PS_NONE);
 }	/* SkGePortCheckUpBcom */
 
 
 /******************************************************************************
  *
+ * SkGePortCheckUpGmac - Check, if the link is up
+ *
+ * return:
+ *	0	o.k. nothing needed
+ *	1	Restart needed on this port
+ *	2	Link came up
+ */
+static int SkGePortCheckUpGmac(
+SK_AC	*pAC,	/* Adapter Context */
+SK_IOC	IoC,	/* IO Context */
+int		Port)	/* Which port should be checked */
+{
+	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
+	int			Done;
+	SK_U16		Isrc;		/* Interrupt source */
+	SK_U16		PhyStat;	/* Phy Status */
+	SK_U16		PhySpecStat;/* Phy Specific Status */
+	SK_U16		ResAb;		/* Master/Slave resolution */
+	SK_BOOL		AutoNeg;	/* Is Auto-negotiation used ? */
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* Read PHY Interrupt Status */
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_INT_STAT, &Isrc);
+
+	if ((Isrc & PHY_M_IS_AN_COMPL) != 0) {
+		/* TBD */
+	}
+
+	if (pPrt->PHWLinkUp) {
+		return(SK_HW_PS_NONE);
+	}
+
+	/* Now wait for each port's link */
+	if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
+		AutoNeg = SK_FALSE;
+	}
+	else {
+		AutoNeg = SK_TRUE;
+	}
+
+	/* Read PHY Status */
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_STAT, &PhyStat);
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("AutoNeg: %d, PhyStat: 0x%04x\n", AutoNeg, PhyStat));
+
+	SkMacAutoNegLipaPhy(pAC, IoC, Port, PhyStat);
+	
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_1000T_STAT, &ResAb);
+
+	if ((ResAb & PHY_B_1000S_MSF) != 0) {
+		/* 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_HW_PS_RESTART);
+	}
+
+	/* Read PHY Specific Status */
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_STAT, &PhySpecStat);
+	
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("AutoNeg: %d, PhySpecStat: 0x%04x\n", AutoNeg, PhySpecStat));
+
+	if ((PhySpecStat & PHY_M_PS_LINK_UP) == 0) {
+		return(SK_HW_PS_NONE);
+	}
+	
+	pPrt->PMSStatus = ((ResAb & PHY_B_1000S_MSR) != 0) ?
+		SK_MS_STAT_MASTER : SK_MS_STAT_SLAVE;
+	
+	pPrt->PCableLen = (SK_U8)((PhySpecStat & PHY_M_PS_CABLE_MSK) >> 7);
+	
+	if (AutoNeg) {
+		/* Auto-Negotiation Over ? */
+		if ((PhyStat & PHY_ST_AN_OVER) != 0) {
+			
+			SkHWLinkUp(pAC, IoC, Port);
+			
+			Done = SkMacAutoNegDone(pAC, IoC, Port);
+			
+			if (Done != SK_AND_OK) {
+				return(SK_HW_PS_RESTART);
+			}
+			
+			SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+				("AutoNeg done Port %d\n", Port));
+			return(SK_HW_PS_LINK);
+		}
+	}
+	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));
+		}
+#endif /* DEBUG */
+
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+			("Link sync, Port %d\n", Port));
+		SkHWLinkUp(pAC, IoC, Port);
+		
+		return(SK_HW_PS_LINK);
+	}
+
+	return(SK_HW_PS_NONE);
+}	/* SkGePortCheckUpGmac */
+
+
+#ifdef OTHER_PHY
+/******************************************************************************
+ *
  * SkGePortCheckUpLone - Check if the link is up
  *
  * return:
@@ -1771,33 +1925,32 @@
  *	1	Restart needed on this port
  *	2	Link came up
  */
-static int	SkGePortCheckUpLone(
+static int SkGePortCheckUpLone(
 SK_AC	*pAC,		/* Adapter Context */
 SK_IOC	IoC,		/* IO Context */
 int		Port)		/* Which port should be checked */
 {
 	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
-	int		Done;
+	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 */
 	SK_U16		StatSum;
-	SK_BOOL		AutoNeg;	/* Is Autonegotiation used ? */
+	SK_BOOL		AutoNeg;	/* Is Auto-negotiation 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;
 	pPrt->PIsave = 0;
 
 	/* Now wait for each ports link */
-	if (pPrt->PLinkMode == SK_LMODE_HALF ||
-	    pPrt->PLinkMode == SK_LMODE_FULL) {
+	if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
 		AutoNeg = SK_FALSE;
 	}
 	else {
@@ -1806,39 +1959,33 @@
 
 	/*
 	 * here we usually can check whether the link is in sync and
-	 * autonegotiation is done.
+	 * auto-negotiation is done.
 	 */
-	XM_IN16(IoC, Port, XM_ISRC, &Isrc);
-	PHY_READ(IoC, pPrt, Port, PHY_LONE_STAT, &PhyStat);
+	SkXmPhyRead(pAC, IoC, Port, PHY_LONE_STAT, &PhyStat);
 	StatSum |= PhyStat;
 
-	SkXmAutoNegLipaLone(pAC, IoC, Port, PhyStat);
-	if ((PhyStat & PHY_ST_LSYNC) == 0){
-		/*
-		 * Save Autonegotiation Done bit
-		 */
+	SkMacAutoNegLipaPhy(pAC, IoC, Port, PhyStat);
+	
+	if ((PhyStat & PHY_ST_LSYNC) == 0) {
+		/* Save Auto-negotiation Done bit */
 		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,
+		if ((pPrt->PIsave & PHY_ST_AN_OVER) != 0) {
+			SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
 				("AutoNeg done rescheduled Port %d\n", Port));
 		}
-#endif
-		return (SK_HW_PS_NONE);
+#endif /* DEBUG */
+		return(SK_HW_PS_NONE);
 	}
 
 	if (AutoNeg) {
-		if (StatSum & PHY_ST_AN_OVER) {
+		if ((StatSum & PHY_ST_AN_OVER) != 0) {
 			SkHWLinkUp(pAC, IoC, Port);
-			Done = SkXmAutoNegDone(pAC,IoC,Port);
+			Done = SkMacAutoNegDone(pAC, IoC, Port);
 			if (Done != SK_AND_OK) {
-				/* 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);
+				/* Get PHY parameters, for debugging only */
+				SkXmPhyRead(pAC, IoC, Port, PHY_LONE_AUNE_LP, &LpAb);
+				SkXmPhyRead(pAC, IoC, Port, PHY_LONE_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));
@@ -1851,7 +1998,7 @@
 					SkHWSenseSetNext(pAC, IoC, Port, NextMode);
 				}
 
-				return (SK_HW_PS_RESTART);
+				return(SK_HW_PS_RESTART);
 
 			}
 			else {
@@ -1859,71 +2006,54 @@
 				 * Dummy Read interrupt status to prevent
 				 * extra link down/ups
 				 */
-				PHY_READ(IoC, pPrt, Port, PHY_LONE_INT_STAT, &ExtStat);
+				SkXmPhyRead(pAC, IoC, 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);
 			}
-		} 
+		}
 		
-		/*
-		 * AutoNeg not done, but HW link is up. Check for timeouts
-		 */
-		pPrt->PAutoNegTimeOut ++;
+		/* AutoNeg not done, but HW link is up. Check for timeouts */
+		pPrt->PAutoNegTimeOut++;
 		if (pPrt->PAutoNegTimeOut >= SK_AND_MAX_TO) {
-			/*
-			 * Timeout occured.
-			 * What do we need now?
-			 */
-			SK_DBG_MSG(pAC,SK_DBGMOD_HWM,
-				SK_DBGCAT_IRQ,
-				("AutoNeg timeout Port %d\n",
-				 Port));
+			/* Timeout occured */
+			SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+				("AutoNeg timeout Port %d\n", Port));
 			if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE &&
 				pPrt->PLipaAutoNeg != SK_LIPA_AUTO) {
-				/*
-				 * 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));
+				/* 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));
 			}
 
-			/*
-			 * Do the restart
-			 */
-			return (SK_HW_PS_RESTART);
+			/* Do the restart */
+			return(SK_HW_PS_RESTART);
 		}
 	}
 	else {
-		/*
-		 * Link is up and we don't need more.
-		 */
-#ifdef	DEBUG
+		/* 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));
 		}
-#endif
+#endif /* DEBUG */
 
 		/*
 		 * Dummy Read interrupt status to prevent
 		 * extra link down/ups
 		 */
-		PHY_READ(IoC, pPrt, Port, PHY_LONE_INT_STAT, &ExtStat);
+		SkXmPhyRead(pAC, IoC, Port, PHY_LONE_INT_STAT, &ExtStat);
 		
 		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);
+		return(SK_HW_PS_LINK);
 	}
 
-	return (SK_HW_PS_NONE);
-}	/* SkGePortCheckUpLone*/
+	return(SK_HW_PS_NONE);
+}	/* SkGePortCheckUpLone */
 
 
 /******************************************************************************
@@ -1935,14 +2065,15 @@
  *	1	Restart needed on this port
  *	2	Link came up
  */
-static int	SkGePortCheckUpNat(
+static int SkGePortCheckUpNat(
 SK_AC	*pAC,		/* Adapter Context */
 SK_IOC	IoC,		/* IO Context */
 int		Port)		/* Which port should be checked */
 {
 	/* todo: National */
-	return (SK_HW_PS_NONE);
+	return(SK_HW_PS_NONE);
 }	/* SkGePortCheckUpNat */
+#endif /* OTHER_PHY */
 
 
 /******************************************************************************
@@ -1968,7 +2099,7 @@
 	SK_U8		Val8;
 
 	Port = Para.Para32[0];
-	pPrt = & pAC->GIni.GP[Port];
+	pPrt = &pAC->GIni.GP[Port];
 
 	switch (Event) {
 	case SK_HWEV_WATIM:
@@ -2010,9 +2141,9 @@
 		}
 
 		/* 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);
+		/* Start workaround Errata #2 timer */
+		SkTimerStart(pAC, IoC, &pPrt->PWaTimer, Time,
+			SKGE_HWAC, SK_HWEV_WATIM, Para);
 		break;
 
 	case SK_HWEV_PORT_START:
@@ -2035,7 +2166,7 @@
 		break;
 
 	case SK_HWEV_PORT_STOP:
-		if (pAC->GIni.GP[Port].PHWLinkUp) {
+		if (pPrt->PHWLinkUp) {
 			/*
 			 * Signal directly to RLMT to ensure correct
 			 * sequence of SWITCH and RESET event.
@@ -2087,6 +2218,10 @@
 		break;
 
 	case SK_HWEV_SET_ROLE:
+		/* not possible for fiber */
+		if (!pAC->GIni.GICopperType) {
+			break;
+		}
 		Val8 = (SK_U8)Para.Para32[1];
 		if (pPrt->PMSMode != Val8) {
 			/* Set New link mode */
@@ -2098,30 +2233,48 @@
 		}
 		break;
 
+	case SK_HWEV_SET_SPEED:
+		if (pPrt->PhyType != SK_PHY_MARV_COPPER) {
+			break;
+		}
+		Val8 = (SK_U8)Para.Para32[1];
+		if (pPrt->PLinkSpeed != Val8) {
+			/* Set New Speed parameter */
+			pPrt->PLinkSpeed = Val8;
+
+			/* Restart Port */
+			SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para);
+			SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_START, Para);
+		}
+		break;
+
 	case SK_HWEV_HALFDUP_CHK:
 		/*
-		 * half duplex hangup workaround. See packet arbiter timeout
-		 * interrupt for description
+		 * half duplex hangup workaround.
+		 * See packet arbiter timeout interrupt for description
 		 */
 		pPrt->HalfDupTimerActive = SK_FALSE;
-		if (pPrt->PLinkModeStatus == SK_LMODE_STAT_HALF || 
+		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);
+				/* Tx hanging, a FIFO flush restarts it */
+				SkMacFlushTxFifo(pAC, IoC, Port);
 			}
 		}
 		break;
+	
 	default:
 		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_SIRQ_E001, SKERR_SIRQ_E001MSG);
 		break;
 	}
 
-	return (0);
+	return(0);
 }	/* SkGeSirqEvent */
 
 
@@ -2144,25 +2297,13 @@
 
 	pPrt = &pAC->GIni.GP[Port];
 
-	if (IStatus & PHY_B_IS_PSE) {
-		/* Incorrectable pair swap error. */
+	if ((IStatus & PHY_B_IS_PSE) != 0) {
+		/* Incorrectable pair swap error */
 		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E022,
 			SKERR_SIRQ_E022MSG);
 	}
 	
-	if (IStatus & PHY_B_IS_MDXI_SC) {
-		/* not used */
-	}
-	
-	if (IStatus & PHY_B_IS_HCT) {
-		/* not used */
-	}
-	
-	if (IStatus & PHY_B_IS_LCT) {
-		/* not used */
-	}
-	
-	if (IStatus & (PHY_B_IS_AN_PR | PHY_B_IS_LST_CHANGE)) {
+	if ((IStatus & (PHY_B_IS_AN_PR | PHY_B_IS_LST_CHANGE)) != 0) {
 		Para.Para32[0] = (SK_U32)Port;
 
 		SkHWLinkDown(pAC, IoC, Port);
@@ -2171,47 +2312,58 @@
 		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
 
 		/* Start workaround Errata #2 timer */
-		SkTimerStart(pAC, IoC, &pPrt->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) {
-	}
+}	/* SkPhyIsrBcom */
 
-	if (IStatus & PHY_B_IS_NO_HDC) {
-		/* not used */
-	}
 
-	if (IStatus & PHY_B_IS_NEG_USHDC) {
-		/* not used */
-	}
+/******************************************************************************
+ *
+ *	SkPhyIsrGmac - PHY interrupt service routine
+ *
+ * Description: handle all interrupts from Marvell PHY
+ *
+ * Returns: N/A
+ */
+static void SkPhyIsrGmac(
+SK_AC		*pAC,		/* Adapter Context */
+SK_IOC		IoC,		/* Io Context */
+int			Port,		/* Port Num = PHY Num */
+SK_U16		IStatus)	/* Interrupt Status */
+{
+	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
+	SK_EVPARA	Para;
 
-	if (IStatus & PHY_B_IS_SCR_S_ER) {
-		/* not used */
-	}
+	pPrt = &pAC->GIni.GP[Port];
 
-	if (IStatus & PHY_B_IS_RRS_CHANGE) {
-		/* not used */
-	}
+	if ((IStatus & (PHY_M_IS_AN_PR | PHY_M_IS_LST_CHANGE)) != 0) {
+		Para.Para32[0] = (SK_U32)Port;
 
-	if (IStatus & PHY_B_IS_LRS_CHANGE) {
-		/* not used */
-	}
+		SkHWLinkDown(pAC, IoC, Port);
 
-	if (IStatus & PHY_B_IS_DUP_CHANGE) {
-		/* not used */
+		/* Signal to RLMT */
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
 	}
-
-	if (IStatus & PHY_B_IS_LSP_CHANGE) {
-		/* not used */
+	
+	if ((IStatus & PHY_M_IS_AN_ERROR) != 0) {
+		/* Auto-Negotiation Error */
+		SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E023, SKERR_SIRQ_E023MSG);
 	}
-
-	if (IStatus & PHY_B_IS_CRC_ER) {
-		/* not used */
+	
+	if ((IStatus & PHY_M_IS_LSP_CHANGE) != 0) {
+		/* TBD */
 	}
-}	/* SkPhyIsrBcom */
+	
+	if ((IStatus & PHY_M_IS_FIFO_ERROR) != 0) {
+		/* FIFO Overflow/Underrun Error */
+		SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E024, SKERR_SIRQ_E024MSG);
+	}
+}	/* SkPhyIsrGmac */
 
 
+#ifdef OTHER_PHY
 /******************************************************************************
  *
  *	SkPhyIsrLone - PHY interrupt service routine
@@ -2228,49 +2380,15 @@
 {
 	SK_EVPARA	Para;
 
-	if (IStatus & PHY_L_IS_CROSS) {
-		/* not used */
-	}
-	
-	if (IStatus & PHY_L_IS_POL) {
-		/* not used */
-	}
-	
-	if (IStatus & PHY_L_IS_SS) {
-		/* not used */
-	}
-	
-	if (IStatus & PHY_L_IS_CFULL) {
-		/* not used */
-	}
-	
-	if (IStatus & PHY_L_IS_AN_C) {
-		/* not used */
-	}
-	
-	if (IStatus & PHY_L_IS_SPEED) {
-		/* not used */
-	}
-	
-	if (IStatus & PHY_L_IS_CFULL) {
-		/* not used */
-	}
-	
 	if (IStatus & (PHY_L_IS_DUP | PHY_L_IS_ISOL)) {
 		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);
 	}
 
-	if (IStatus & PHY_L_IS_MDINT) {
-		/* not used */
-	}
 }	/* SkPhyIsrLone */
+#endif /* OTHER_PHY */
 
 /* End of File */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sk98lin/ski2c.c linux-2.4.21-pre6/drivers/net/sk98lin/ski2c.c
--- linux-2.4.20/drivers/net/sk98lin/ski2c.c	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sk98lin/ski2c.c	2003-03-26 23:48:57.000000000 +0000
@@ -2,16 +2,15 @@
  *
  * Name:	ski2c.c
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.47 $
- * Date:	$Date: 2001/04/05 11:38:09 $
+ * Version:	$Revision: 1.56 $
+ * Date:	$Date: 2002/12/19 14:20:41 $
  * Purpose:	Functions to access Voltage and Temperature Sensor
- *			(taken from Monalisa (taken from Concentrator))
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998-2001 SysKonnect GmbH.
+ *	(C)Copyright 1998-2002 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,43 @@
  * History:
  *
  *	$Log: ski2c.c,v $
+ *	Revision 1.56  2002/12/19 14:20:41  rschmidt
+ *	Added debugging code in SkI2cWait().
+ *	Replaced all I2C-write operations with function SkI2cWrite().
+ *	Fixed compiler warning because of uninitialized 'Time' in SkI2cEvent().
+ *	Editorial changes.
+ *	
+ *	Revision 1.55  2002/10/15 07:23:55  rschmidt
+ *	Added setting of the GIYukon32Bit bool variable to distinguish
+ *	32-bit adapters.
+ *	Editorial changes (TWSI).
+ *	
+ *	Revision 1.54  2002/08/13 09:05:06  rschmidt
+ *	Added new thresholds if VAUX is not available (GIVauxAvail).
+ *	Merged defines for PHY PLL 3V3 voltage (A and B).
+ *	Editorial changes.
+ *	
+ *	Revision 1.53  2002/08/08 11:04:53  rwahl
+ *	Added missing comment for revision 1.51
+ *	
+ *	Revision 1.52  2002/08/08 10:09:02  jschmalz
+ *	Sensor init state caused wrong error log entry
+ *	
+ *	Revision 1.51  2002/08/06 09:43:03  jschmalz
+ *	Extensions and changes for Yukon
+ *	
+ *	Revision 1.50  2002/08/02 12:09:22  rschmidt
+ *	Added support for YUKON sensors.
+ *	Editorial changes.
+ *	
+ *	Revision 1.49  2002/07/30 11:07:52  rschmidt
+ *	Replaced MaxSens init by update for Copper in SkI2cInit1(),
+ *	because it was already initialized in SkI2cInit0().
+ *	Editorial changes.
+ *	
+ *	Revision 1.48  2001/08/16 12:44:33  afischer
+ *	LM80 sensor init values corrected
+ *	
  *	Revision 1.47  2001/04/05 11:38:09  rassmann
  *	Set SenState to idle in SkI2cWaitIrq().
  *	Changed error message in SkI2cWaitIrq().
@@ -178,7 +214,7 @@
  *	Revision 1.2  1998/08/11 07:27:15  gklug
  *	add: functions of the interface
  *	adapt rest of source to C coding Conventions
- *	rmv: unneccessary code taken from Mona Lisa
+ *	rmv: unnecessary code taken from Mona Lisa
  *
  *	Revision 1.1  1998/06/19 14:28:43  malthoff
  *	Created. Sources taken from ML Projekt.
@@ -192,7 +228,7 @@
  *	I2C Protocol
  */
 static const char SysKonnectFileId[] =
-	"$Id: ski2c.c,v 1.47 2001/04/05 11:38:09 rassmann Exp $";
+	"$Id: ski2c.c,v 1.56 2002/12/19 14:20:41 rschmidt Exp $";
 
 #include "h/skdrv1st.h"		/* Driver Specific Definitions */
 #include "h/lm80.h"
@@ -280,21 +316,21 @@
 #ifndef I2C_SLOW_TIMING
 #define	T_CLK_LOW		1300L	/* clock low time in ns */
 #define	T_CLK_HIGH		 600L	/* clock high time in ns */
-#define T_DATA_IN_SETUP		 100L	/* data in Set-UP Time */
+#define T_DATA_IN_SETUP		 100L	/* data in Set-up Time */
 #define T_START_HOLD		 600L	/* start condition hold time */
 #define T_START_SETUP		 600L	/* start condition Set-up time */
 #define	T_STOP_SETUP		 600L	/* stop condition Set-up time */
-#define T_BUS_IDLE		1300L	/* time the bus must free after tx */
+#define T_BUS_IDLE		1300L	/* time the bus must free after Tx */
 #define	T_CLK_2_DATA_OUT	 900L	/* max. clock low to data output valid */
 #else	/* I2C_SLOW_TIMING */
 /* I2C Standard Mode Timing */
 #define	T_CLK_LOW		4700L	/* clock low time in ns */
 #define	T_CLK_HIGH		4000L	/* clock high time in ns */
-#define T_DATA_IN_SETUP		 250L	/* data in Set-UP Time */
+#define T_DATA_IN_SETUP		 250L	/* data in Set-up Time */
 #define T_START_HOLD		4000L	/* start condition hold time */
-#define T_START_SETUP		4700L	/* start condition Set_up time */
+#define T_START_SETUP		4700L	/* start condition Set-up time */
 #define	T_STOP_SETUP		4000L	/* stop condition Set-up time */
-#define T_BUS_IDLE		4700L	/* time the bus must free after tx */
+#define T_BUS_IDLE		4700L	/* time the bus must free after Tx */
 #endif	/* !I2C_SLOW_TIMING */
 
 #define NS2BCLK(x)	(((x)*125)/10000)
@@ -312,9 +348,9 @@
 #define I2C_DATA_HIGH(IoC)	SK_I2C_SET_BIT(IoC, I2C_DATA)
 #define	I2C_DATA_LOW(IoC)	SK_I2C_CLR_BIT(IoC, I2C_DATA)
 #define	I2C_DATA_OUT(IoC)	SK_I2C_SET_BIT(IoC, I2C_DATA_DIR)
-#define	I2C_DATA_IN(IoC)	SK_I2C_CLR_BIT(IoC, I2C_DATA_DIR|I2C_DATA)
+#define	I2C_DATA_IN(IoC)	SK_I2C_CLR_BIT(IoC, I2C_DATA_DIR | I2C_DATA)
 #define	I2C_CLK_HIGH(IoC)	SK_I2C_SET_BIT(IoC, I2C_CLK)
-#define	I2C_CLK_LOW(IoC)	SK_I2C_CLR_BIT(IoC, I2C_CLK|I2C_DATA_DIR)
+#define	I2C_CLK_LOW(IoC)	SK_I2C_CLR_BIT(IoC, I2C_CLK | I2C_DATA_DIR)
 #define	I2C_START_COND(IoC)	SK_I2C_CLR_BIT(IoC, I2C_CLK)
 
 #define NS2CLKT(x)	((x*125L)/10000)
@@ -331,7 +367,8 @@
 	I2C_DATA_OUT(IoC);
 	if (Bit) {
 		I2C_DATA_HIGH(IoC);
-	} else {
+	}
+	else {
 		I2C_DATA_LOW(IoC);
 	}
 	SkDgWaitTime(IoC, NS2BCLK(T_DATA_IN_SETUP));
@@ -428,11 +465,8 @@
 	SkDgWaitTime(IoC, NS2BCLK(T_CLK_HIGH));
 
 	SK_I2C_GET_SW(IoC, &I2cSwCtrl);
-	if (I2cSwCtrl & I2C_DATA) {
-		Bit = 1;
-	} else {
-		Bit = 0;
-	}
+	
+	Bit = (I2cSwCtrl & I2C_DATA) ? 1 : 0;
 
 	I2C_CLK_LOW(IoC);
 	SkDgWaitTime(IoC, NS2BCLK(T_CLK_LOW-T_CLK_2_DATA_OUT));
@@ -444,16 +478,16 @@
 /*
  * Receive an ACK.
  *
- * returns	0 If acknoledged
+ * returns	0 If acknowledged
  *		1 in case of an error
  */
 int SkI2cRcvAck(
-SK_IOC IoC)	/* I/O Context */
+SK_IOC	IoC)	/* I/O Context */
 {
 	/*
 	 * Received bit must be zero.
 	 */
-	return (SkI2cRcvBit(IoC) != 0);
+	return(SkI2cRcvBit(IoC) != 0);
 }	/* SkI2cRcvAck */
 
 
@@ -461,7 +495,7 @@
  * Send an NACK.
  */
 void SkI2cSndNAck(
-SK_IOC IoC)	/* I/O Context */
+SK_IOC	IoC)	/* I/O Context */
 {
 	/*
 	 * Received bit must be zero.
@@ -487,18 +521,19 @@
 /*
  * Send one byte to the I2C device and wait for ACK.
  *
- * Return acknoleged status.
+ * Return acknowleged status.
  */
 int SkI2cSndByte(
 SK_IOC	IoC,	/* I/O Context */
-int	Byte)		/* byte to send */
+int		Byte)	/* byte to send */
 {
 	int	i;
 
 	for (i = 0; i < 8; i++) {
 		if (Byte & (1<<(7-i))) {
 			SkI2cSndBit(IoC, 1);
-		} else {
+		}
+		else {
 			SkI2cSndBit(IoC, 0);
 		}
 	}
@@ -514,7 +549,7 @@
  */
 int SkI2cRcvByte(
 SK_IOC	IoC,	/* I/O Context */
-int	Last)		/* Last Byte Flag */
+int		Last)	/* Last Byte Flag */
 {
 	int	i;
 	int	Byte = 0;
@@ -526,7 +561,8 @@
 
 	if (Last) {
 		SkI2cSndNAck(IoC);
-	} else {
+	}
+	else {
 		SkI2cSndAck(IoC);
 	}
 
@@ -537,7 +573,7 @@
 /*
  * Start dialog and send device address
  *
- * Return 0 if acknoleged, 1 in case of an error
+ * Return 0 if acknowleged, 1 in case of an error
  */
 int	SkI2cSndDev(
 SK_IOC	IoC,	/* I/O Context */
@@ -545,7 +581,7 @@
 int		Rw)		/* Read / Write Flag */
 {
 	SkI2cStart(IoC);
-	Rw = ~Rw; 
+	Rw = ~Rw;
 	Rw &= I2C_WRITE;
 	return(SkI2cSndByte(IoC, (Addr<<1) | Rw));
 }	/* SkI2cSndDev */
@@ -567,18 +603,33 @@
 int		Event)	/* complete event to wait for (I2C_READ or I2C_WRITE) */
 {
 	SK_U64	StartTime;
+	SK_U64	CurrentTime;
 	SK_U32	I2cCtrl;
 
 	StartTime = SkOsGetTime(pAC);
+	
 	do {
-		if (SkOsGetTime(pAC) - StartTime > SK_TICKS_PER_SEC / 8) {
+		CurrentTime = SkOsGetTime(pAC);
+
+		if (CurrentTime - 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);
 #endif	/* !SK_DIAG */
 			return(1);
 		}
+		
 		SK_I2C_GET_CTL(IoC, &I2cCtrl);
+
+#ifdef xYUKON_DBG
+		printf("StartTime=%lu, CurrentTime=%lu\n",
+			StartTime, CurrentTime);
+		if (kbhit()) {
+			return(1);
+		}
+#endif /* YUKON_DBG */
+	
 	} while ((I2cCtrl & I2C_FLAG) == (SK_U32)Event << 31);
 
 	return(0);
@@ -591,7 +642,7 @@
  * Returns
  *	Nothing
  */
-void	SkI2cWaitIrq(
+void SkI2cWaitIrq(
 SK_AC	*pAC,	/* Adapter Context */
 SK_IOC	IoC)	/* I/O Context */
 {
@@ -621,8 +672,6 @@
 	return;
 }	/* SkI2cWaitIrq */
 
-#ifdef	SK_DIAG
-
 /*
  * writes a single byte or 4 bytes into the I2C device
  *
@@ -635,14 +684,17 @@
 SK_U32	I2cData,	/* I2C Data to write */
 int		I2cDev,		/* I2C Device Address */
 int		I2cReg,		/* I2C Device Register Address */
-int		I2cBurst)	/* I2C Burst Flag ( 0 || I2C_BURST ) */
+int		I2cBurst)	/* I2C Burst Flag */
 {
 	SK_OUT32(IoC, B2_I2C_DATA, I2cData);
 	SK_I2C_CTL(IoC, I2C_WRITE, I2cDev, I2cReg, I2cBurst);
+	
 	return(SkI2cWait(pAC, IoC, I2C_WRITE));
 }	/* SkI2cWrite*/
 
 
+#ifdef	SK_DIAG
+
 /*
  * reads a single byte or 4 bytes from the I2C device
  *
@@ -653,15 +705,17 @@
 SK_IOC	IoC,		/* I/O Context */
 int		I2cDev,		/* I2C Device Address */
 int		I2cReg,		/* I2C Device Register Address */
-int		I2cBurst)	/* I2C Burst Flag ( 0 || I2C_BURST ) */
+int		I2cBurst)	/* I2C Burst Flag */
 {
 	SK_U32	Data;
 
 	SK_OUT32(IoC, B2_I2C_DATA, 0);
 	SK_I2C_CTL(IoC, I2C_READ, I2cDev, I2cReg, I2cBurst);
-	if (SkI2cWait(pAC, IoC, I2C_READ)) {
-		w_print("I2C Transfer Timeout!\n"); 
+	
+	if (SkI2cWait(pAC, IoC, I2C_READ) != 0) {
+		w_print("%s\n", SKERR_I2C_E002MSG);
 	}
+	
 	SK_IN32(IoC, B2_I2C_DATA, &Data);
 	return(Data);
 }	/* SkI2cRead */
@@ -684,13 +738,17 @@
 SK_IOC		IoC,	/* I/O Context */
 SK_SENSOR	*pSen)	/* Sensor to be read */
 {
-	return((*pSen->SenRead)(pAC, IoC, pSen));
+    if (pSen->SenRead != NULL) {
+        return((*pSen->SenRead)(pAC, IoC, pSen));
+    }
+    else
+        return(0); /* no success */
 }	/* SkI2cReadSensor*/
 
 /*
  * Do the Init state 0 initialization
  */
-static	int	SkI2cInit0(
+static int SkI2cInit0(
 SK_AC	*pAC)	/* Adapter Context */
 {
 	int	i;
@@ -698,109 +756,33 @@
 	/* Begin with first sensor */
 	pAC->I2c.CurrSens = 0;
 	
-	/* Set to mimimum sensor number */
-	pAC->I2c.MaxSens = SK_MIN_SENSORS;
+	/* Begin with timeout control for state machine */
+	pAC->I2c.TimerMode = SK_TIMER_WATCH_STATEMACHINE;
+	
+	/* Set sensor number to zero */
+	pAC->I2c.MaxSens = 0;
 
 #ifndef	SK_DIAG
 	/* Initialize Number of Dummy Reads */
 	pAC->I2c.DummyReads = SK_MAX_SENSORS;
 #endif
 
-	for (i = 0; i < SK_MAX_SENSORS; i ++) {
-		switch (i) {
-		case 0:
-			pAC->I2c.SenTable[i].SenDesc = "Temperature";
-			pAC->I2c.SenTable[i].SenType = SK_SEN_TEMP;
-			pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_ERRHIGH0;
-			pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_ERRLOW0;
-			pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_WARNHIGH0;
-			pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_WARNLOW0;
-			pAC->I2c.SenTable[i].SenReg = LM80_TEMP_IN;
-			pAC->I2c.SenTable[i].SenInit = SK_TRUE;
-			break;
-		case 1:
-			pAC->I2c.SenTable[i].SenDesc = "Voltage PCI";
-			pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
-			pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_ERRHIGH1;
-			pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_ERRLOW1;
-			pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_WARNHIGH1;
-			pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_WARNLOW1;
-			pAC->I2c.SenTable[i].SenReg = LM80_VT0_IN;
-			pAC->I2c.SenTable[i].SenInit = SK_TRUE;
-			break;
-		case 2:
-			pAC->I2c.SenTable[i].SenDesc = "Voltage PCI-IO";
-			pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
-			pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_ERRHIGH2;
-			pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_ERRLOW2;
-			pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_WARNHIGH2;
-			pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_WARNLOW2;
-			pAC->I2c.SenTable[i].SenReg = LM80_VT1_IN;
-			pAC->I2c.SenTable[i].SenInit = SK_FALSE;
-			break;
-		case 3:
-			pAC->I2c.SenTable[i].SenDesc = "Voltage ASIC";
-			pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
-			pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_ERRHIGH3;
-			pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_ERRLOW3;
-			pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_WARNHIGH3;
-			pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_WARNLOW3;
-			pAC->I2c.SenTable[i].SenReg = LM80_VT2_IN;
-			pAC->I2c.SenTable[i].SenInit = SK_TRUE;
-			break;
-		case 4:
-			pAC->I2c.SenTable[i].SenDesc = "Voltage PMA";
-			pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
-			pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_ERRHIGH4;
-			pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_ERRLOW4;
-			pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_WARNHIGH4;
-			pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_WARNLOW4;
-			pAC->I2c.SenTable[i].SenReg = LM80_VT3_IN;
-			pAC->I2c.SenTable[i].SenInit = SK_TRUE;
-			break;
-		case 5:
-			pAC->I2c.SenTable[i].SenDesc = "Voltage PHY 2V5";
-			pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
-			pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_ERRHIGH5;
-			pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_ERRLOW5;
-			pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_WARNHIGH5;
-			pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_WARNLOW5;
-			pAC->I2c.SenTable[i].SenReg = LM80_VT4_IN;
-			pAC->I2c.SenTable[i].SenInit = SK_TRUE;
-			break;
-		case 6:
-			pAC->I2c.SenTable[i].SenDesc = "Voltage PHY B PLL";
-			pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
-			pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_ERRHIGH6;
-			pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_ERRLOW6;
-			pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_WARNHIGH6;
-			pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_WARNLOW6;
-			pAC->I2c.SenTable[i].SenReg = LM80_VT5_IN;
-			pAC->I2c.SenTable[i].SenInit = SK_TRUE;
-			break;
-		case 7:
-			pAC->I2c.SenTable[i].SenDesc = "Speed Fan";
-			pAC->I2c.SenTable[i].SenType = SK_SEN_FAN;
-			pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_ERRHIGH;
-			pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_ERRLOW;
-			pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_WARNHIGH;
-			pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_WARNLOW;
-			pAC->I2c.SenTable[i].SenReg = LM80_FAN2_IN;
-			pAC->I2c.SenTable[i].SenInit = SK_TRUE;
-			break;
-		default:
-			SK_ERR_LOG(pAC, SK_ERRCL_INIT | SK_ERRCL_SW,
-				SKERR_I2C_E001, SKERR_I2C_E001MSG);
-			break;
-		}
-
+	for (i = 0; i < SK_MAX_SENSORS; i++) {
+		pAC->I2c.SenTable[i].SenDesc = "unknown";
+		pAC->I2c.SenTable[i].SenType = SK_SEN_UNKNOWN;
+		pAC->I2c.SenTable[i].SenThreErrHigh = 0;
+		pAC->I2c.SenTable[i].SenThreErrLow = 0;
+		pAC->I2c.SenTable[i].SenThreWarnHigh = 0;
+		pAC->I2c.SenTable[i].SenThreWarnLow = 0;
+		pAC->I2c.SenTable[i].SenReg = LM80_FAN2_IN;
+		pAC->I2c.SenTable[i].SenInit = SK_SEN_DYN_INIT_NONE;
 		pAC->I2c.SenTable[i].SenValue = 0;
-		pAC->I2c.SenTable[i].SenErrFlag = SK_SEN_ERR_OK;
+		pAC->I2c.SenTable[i].SenErrFlag = SK_SEN_ERR_NOT_PRESENT;
 		pAC->I2c.SenTable[i].SenErrCts = 0;
 		pAC->I2c.SenTable[i].SenBegErrTS = 0;
 		pAC->I2c.SenTable[i].SenState = SK_SEN_IDLE;
-		pAC->I2c.SenTable[i].SenRead = SkLm80ReadSensor;
-		pAC->I2c.SenTable[i].SenDev = LM80_ADDR;
+		pAC->I2c.SenTable[i].SenRead = NULL;
+		pAC->I2c.SenTable[i].SenDev = 0;
 	}
 
 	/* Now we are "INIT data"ed */
@@ -829,68 +811,211 @@
  * - all 0s
  *
  */
-static	int	SkI2cInit1(
+static int SkI2cInit1(
 SK_AC	*pAC,	/* Adapter Context */
 SK_IOC	IoC)	/* I/O Context */
 {
+    int i;
+    SK_U8 I2cSwCtrl;
+	SK_GEPORT *pPrt;	/* GIni Port struct pointer */
+
 	if (pAC->I2c.InitLevel != SK_INIT_DATA) {
 		/* ReInit not needed in I2C module */
 		return(0);
 	}
 
-	SK_OUT32(IoC, B2_I2C_DATA, 0);
-	SK_I2C_CTL(IoC, I2C_WRITE, LM80_ADDR, LM80_CFG, 0);
-	(void)SkI2cWait(pAC, IoC, I2C_WRITE);
-
-	SK_OUT32(IoC, B2_I2C_DATA, 0xff);
-	SK_I2C_CTL(IoC, I2C_WRITE, LM80_ADDR, LM80_IMSK_1, 0);
-	(void)SkI2cWait(pAC, IoC, I2C_WRITE);
-
-	SK_OUT32(IoC, B2_I2C_DATA, 0xff);
-	SK_I2C_CTL(IoC, I2C_WRITE, LM80_ADDR, LM80_IMSK_2, 0);
-	(void)SkI2cWait(pAC, IoC, I2C_WRITE);
-
-	SK_OUT32(IoC, B2_I2C_DATA, 0x0);
-	SK_I2C_CTL(IoC, I2C_WRITE, LM80_ADDR, LM80_FAN_CTRL, 0);
-	(void)SkI2cWait(pAC, IoC, I2C_WRITE);
-
-	SK_OUT32(IoC, B2_I2C_DATA, 0);
-	SK_I2C_CTL(IoC, I2C_WRITE, LM80_ADDR, LM80_TEMP_CTRL, 0);
-	(void)SkI2cWait(pAC, IoC, I2C_WRITE);
+    /* Set the Direction of I2C-Data Pin to IN */
+    SK_I2C_CLR_BIT(IoC, I2C_DATA_DIR | I2C_DATA);
+    /* Check for 32-Bit Yukon with Low at I2C-Data Pin */
+	SK_I2C_GET_SW(IoC, &I2cSwCtrl);
 
-	SK_OUT32(IoC, B2_I2C_DATA, LM80_CFG_START);
-	SK_I2C_CTL(IoC, I2C_WRITE, LM80_ADDR, LM80_CFG, 0);
-	(void)SkI2cWait(pAC, IoC, I2C_WRITE);
+	if ((I2cSwCtrl & I2C_DATA) == 0) {
+		/* this is a 32-Bit board */
+		pAC->GIni.GIYukon32Bit = SK_TRUE;
+        return(0);
+    }
+
+	/* Check for 64 Bit Yukon without sensors */
+	if (SkI2cWrite(pAC, IoC, 0, LM80_ADDR, LM80_CFG, 0) != 0) {
+        return(0);
+    }
 
+	(void)SkI2cWrite(pAC, IoC, 0xff, LM80_ADDR, LM80_IMSK_1, 0);
+	
+	(void)SkI2cWrite(pAC, IoC, 0xff, LM80_ADDR, LM80_IMSK_2, 0);
+	
+	(void)SkI2cWrite(pAC, IoC, 0, LM80_ADDR, LM80_FAN_CTRL, 0);
+	
+	(void)SkI2cWrite(pAC, IoC, 0, LM80_ADDR, LM80_TEMP_CTRL, 0);
+	
+	(void)SkI2cWrite(pAC, IoC, LM80_CFG_START, LM80_ADDR, LM80_CFG, 0);
+	
 	/*
-	 * MaxSens has to be initialized here, because PhyType is not
-	 * set when performing Init Level 1
+	 * MaxSens has to be updated here, because PhyType is not
+	 * set when performing Init Level 0
 	 */
-	switch (pAC->GIni.GP[0].PhyType) {
-	case SK_PHY_XMAC:
-		pAC->I2c.MaxSens = 5;
-		break;
+    pAC->I2c.MaxSens = 5;
+	
+	pPrt = &pAC->GIni.GP[0];
+	
+    switch (pPrt->PhyType) {
 	case SK_PHY_BCOM:
-		pAC->I2c.SenTable[4].SenDesc = "Voltage PHY A PLL";
 		if (pAC->GIni.GIMacsFound == 1) {
-			pAC->I2c.MaxSens = 6;
-		} 
+			pAC->I2c.MaxSens += 1;
+		}
 		else {
-			pAC->I2c.MaxSens = 8;
+			pAC->I2c.MaxSens += 3;
 		}
 		break;
-	case SK_PHY_LONE:
-		pAC->I2c.MaxSens = 5;
+	case SK_PHY_MARV_COPPER:
+		pAC->I2c.MaxSens += 3;
 		break;
 	}
 	
+	for (i = 0; i < pAC->I2c.MaxSens; i++) {
+		switch (i) {
+		case 0:
+			pAC->I2c.SenTable[i].SenDesc = "Temperature";
+			pAC->I2c.SenTable[i].SenType = SK_SEN_TEMP;
+			pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_TEMP_HIGH_ERR;
+			pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_TEMP_HIGH_WARN;
+			pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_TEMP_LOW_WARN;
+			pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_TEMP_LOW_ERR;
+			pAC->I2c.SenTable[i].SenReg = LM80_TEMP_IN;
+			break;
+		case 1:
+			pAC->I2c.SenTable[i].SenDesc = "Voltage PCI";
+			pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
+			pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PCI_5V_HIGH_ERR;
+			pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PCI_5V_HIGH_WARN;
+			pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PCI_5V_LOW_WARN;
+			pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PCI_5V_LOW_ERR;
+			pAC->I2c.SenTable[i].SenReg = LM80_VT0_IN;
+			break;
+		case 2:
+			pAC->I2c.SenTable[i].SenDesc = "Voltage PCI-IO";
+			pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
+			pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PCI_IO_5V_HIGH_ERR;
+			pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PCI_IO_5V_HIGH_WARN;
+			pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PCI_IO_3V3_LOW_WARN;
+			pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PCI_IO_3V3_LOW_ERR;
+			pAC->I2c.SenTable[i].SenReg = LM80_VT1_IN;
+			pAC->I2c.SenTable[i].SenInit = SK_SEN_DYN_INIT_PCI_IO;
+			break;
+		case 3:
+			pAC->I2c.SenTable[i].SenDesc = "Voltage ASIC";
+			pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
+			pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_VDD_HIGH_ERR;
+			pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_VDD_HIGH_WARN;
+			pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_VDD_LOW_WARN;
+			pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_VDD_LOW_ERR;
+			pAC->I2c.SenTable[i].SenReg = LM80_VT2_IN;
+			break;
+		case 4:
+			if (pPrt->PhyType == SK_PHY_BCOM) {
+				pAC->I2c.SenTable[i].SenDesc = "Voltage PHY A PLL";
+				pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PLL_3V3_HIGH_ERR;
+				pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PLL_3V3_HIGH_WARN;
+				pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PLL_3V3_LOW_WARN;
+				pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PLL_3V3_LOW_ERR;
+			}
+			else if (pPrt->PhyType == SK_PHY_MARV_COPPER) {
+				pAC->I2c.SenTable[i].SenDesc = "Voltage VAUX";
+				pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_VAUX_3V3_HIGH_ERR;
+				pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_VAUX_3V3_HIGH_WARN;
+				if (pAC->GIni.GIVauxAvail) {
+					pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_VAUX_3V3_LOW_WARN;
+					pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_VAUX_3V3_LOW_ERR;
+				}
+				else {
+					pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_VAUX_0V_WARN_ERR;
+					pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_VAUX_0V_WARN_ERR;
+				}
+			}
+			else {
+				pAC->I2c.SenTable[i].SenDesc = "Voltage PMA";
+				pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PLL_3V3_HIGH_ERR;
+				pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PLL_3V3_HIGH_WARN;
+				pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PLL_3V3_LOW_WARN;
+				pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PLL_3V3_LOW_ERR;
+			}
+			pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
+			pAC->I2c.SenTable[i].SenReg = LM80_VT3_IN;
+			break;
+		case 5:
+			if (pPrt->PhyType == SK_PHY_MARV_COPPER) {
+				pAC->I2c.SenTable[i].SenDesc = "Voltage ASIC-Co 1V5";
+				pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_CORE_1V5_HIGH_ERR;
+				pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_CORE_1V5_HIGH_WARN;
+				pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_CORE_1V5_LOW_WARN;
+				pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_CORE_1V5_LOW_ERR;
+			}
+			else {
+				pAC->I2c.SenTable[i].SenDesc = "Voltage PHY 2V5";
+				pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PHY_2V5_HIGH_ERR;
+				pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PHY_2V5_HIGH_WARN;
+				pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PHY_2V5_LOW_WARN;
+				pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PHY_2V5_LOW_ERR;
+			}
+			pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
+			pAC->I2c.SenTable[i].SenReg = LM80_VT4_IN;
+			break;
+		case 6:
+			if (pPrt->PhyType == SK_PHY_MARV_COPPER) {
+				pAC->I2c.SenTable[i].SenDesc = "Voltage PHY 3V3";
+			}
+			else {
+				pAC->I2c.SenTable[i].SenDesc = "Voltage PHY B PLL";
+			}
+			pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
+			pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PLL_3V3_HIGH_ERR;
+			pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PLL_3V3_HIGH_WARN;
+			pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PLL_3V3_LOW_WARN;
+			pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PLL_3V3_LOW_ERR;
+			pAC->I2c.SenTable[i].SenReg = LM80_VT5_IN;
+			break;
+		case 7:
+			if (pPrt->PhyType == SK_PHY_MARV_COPPER) {
+				pAC->I2c.SenTable[i].SenDesc = "Voltage PHY 2V5";
+				pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
+				pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PHY_2V5_HIGH_ERR;
+				pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PHY_2V5_HIGH_WARN;
+				pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PHY_2V5_LOW_WARN;
+				pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PHY_2V5_LOW_ERR;
+				pAC->I2c.SenTable[i].SenReg = LM80_VT6_IN;
+			}
+			else {
+				pAC->I2c.SenTable[i].SenDesc = "Speed Fan";
+				pAC->I2c.SenTable[i].SenType = SK_SEN_FAN;
+				pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_FAN_HIGH_ERR;
+				pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_FAN_HIGH_WARN;
+				pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_FAN_LOW_WARN;
+				pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_FAN_LOW_ERR;
+				pAC->I2c.SenTable[i].SenReg = LM80_FAN2_IN;
+			}
+			break;
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_INIT | SK_ERRCL_SW,
+				SKERR_I2C_E001, SKERR_I2C_E001MSG);
+			break;
+		}
+
+		pAC->I2c.SenTable[i].SenValue = 0;
+		pAC->I2c.SenTable[i].SenErrFlag = SK_SEN_ERR_OK;
+		pAC->I2c.SenTable[i].SenErrCts = 0;
+		pAC->I2c.SenTable[i].SenBegErrTS = 0;
+		pAC->I2c.SenTable[i].SenState = SK_SEN_IDLE;
+		pAC->I2c.SenTable[i].SenRead = SkLm80ReadSensor;
+		pAC->I2c.SenTable[i].SenDev = LM80_ADDR;
+	}
+
 #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 */
 	
+	/* Clear I2C IRQ */
+	SK_OUT32(IoC, B2_I2C_IRQ, I2C_CLR_IRQ);
+	
 	/* Now we are I/O initialized */
 	pAC->I2c.InitLevel = SK_INIT_IO;
 	return(0);
@@ -900,7 +1025,7 @@
 /*
  * Init level 2: Start first sensor read.
  */
-static	int	SkI2cInit2(
+static int SkI2cInit2(
 SK_AC	*pAC,	/* Adapter Context */
 SK_IOC	IoC)	/* I/O Context */
 {
@@ -977,13 +1102,13 @@
  *
  * Starts the timer if necessary.
  */
-void	SkI2cIsr(
+void SkI2cIsr(
 SK_AC	*pAC,	/* Adapter Context */
 SK_IOC	IoC)	/* I/O Context */
 {
 	SK_EVPARA	Para;
 
-	/* Clear the interrupt source */
+	/* Clear I2C IRQ */
 	SK_OUT32(IoC, B2_I2C_IRQ, I2C_CLR_IRQ);
 
 	Para.Para64 = 0;
@@ -994,7 +1119,7 @@
 /*
  * Check this sensors Value against the threshold and send events.
  */
-static	void	SkI2cCheckSensor(
+static void SkI2cCheckSensor(
 SK_AC		*pAC,	/* Adapter Context */
 SK_SENSOR	*pSen)
 {
@@ -1008,7 +1133,7 @@
 
 	/* Check Dummy Reads first */
 	if (pAC->I2c.DummyReads > 0) {
-		pAC->I2c.DummyReads --;
+		pAC->I2c.DummyReads--;
 		return;
 	}
 
@@ -1016,7 +1141,7 @@
 	CurrTime = SkOsGetTime(pAC);
 
 	/* Set para to the most useful setting: The current sensor. */
-	ParaLocal.Para64 = (SK_U64) pAC->I2c.CurrSens;
+	ParaLocal.Para64 = (SK_U64)pAC->I2c.CurrSens;
 
 	/* Check the Value against the thresholds. First: Error Thresholds */
 	TooHigh = (pSen->SenValue > pSen->SenThreErrHigh);
@@ -1053,9 +1178,9 @@
 				 */
 				DoErrLog = SK_FALSE;
 			}
-		} else {
-			/* We came from a different state */
-			/* -> Set Begin Time Stamp */
+		}
+		else {
+			/* We came from a different state -> Set Begin Time Stamp */
 			pSen->SenBegErrTS = CurrTime;
 			pSen->SenErrFlag = SK_SEN_ERR_ERR;
 		}
@@ -1063,7 +1188,7 @@
 		if (DoTrapSend) {
 			/* Set current Time */
 			pSen->SenLastErrTrapTS = CurrTime;
-			pSen->SenErrCts ++;
+			pSen->SenErrCts++;
 
 			/* Queue PNMI Event */
 			SkEventQueue(pAC, SKGE_PNMI, (TooHigh ?
@@ -1095,7 +1220,6 @@
 	TooHigh = (pSen->SenValue > pSen->SenThreWarnHigh);
 	TooLow = (pSen->SenValue < pSen->SenThreWarnLow);
 		
-
 	if (!IsError && (TooHigh || TooLow)) {
 		/* Error condition is satisfied */
 		DoTrapSend = SK_TRUE;
@@ -1123,9 +1247,9 @@
 				 */
 				DoErrLog = SK_FALSE;
 			}
-		} else {
-			/* We came from a different state */
-			/* -> Set Begin Time Stamp */
+		}
+		else {
+			/* We came from a different state -> Set Begin Time Stamp */
 			pSen->SenBegWarnTS = CurrTime;
 			pSen->SenErrFlag = SK_SEN_ERR_WARN;
 		}
@@ -1133,7 +1257,7 @@
 		if (DoTrapSend) {
 			/* Set current Time */
 			pSen->SenLastWarnTrapTS = CurrTime;
-			pSen->SenWarnCts ++;
+			pSen->SenWarnCts++;
 
 			/* Queue PNMI Event */
 			SkEventQueue(pAC, SKGE_PNMI, (TooHigh ?
@@ -1168,6 +1292,43 @@
 
 	/* End of check against the thresholds */
 
+	/* Bug fix AF: 16.Aug.2001: Correct the init base
+	 * of LM80 sensor.
+	 */
+	if (pSen->SenInit == SK_SEN_DYN_INIT_PCI_IO) {
+
+        pSen->SenInit = SK_SEN_DYN_INIT_NONE;
+
+		if (pSen->SenValue > SK_SEN_PCI_IO_RANGE_LIMITER) {
+			/* 5V PCI-IO Voltage */
+			pSen->SenThreWarnLow = SK_SEN_PCI_IO_5V_LOW_WARN;
+			pSen->SenThreErrLow = SK_SEN_PCI_IO_5V_LOW_ERR;
+		}
+		else {
+			/* 3.3V PCI-IO Voltage */
+			pSen->SenThreWarnHigh = SK_SEN_PCI_IO_3V3_HIGH_WARN;
+			pSen->SenThreErrHigh = SK_SEN_PCI_IO_3V3_HIGH_ERR;
+		}
+	}
+	
+#if 0
+    /* Dynamic thresholds also for VAUX of LM80 sensor */
+	if (pSen->SenInit == SK_SEN_DYN_INIT_VAUX) {
+
+        pSen->SenInit = SK_SEN_DYN_INIT_NONE;
+
+		/* 3.3V VAUX Voltage */
+		if (pSen->SenValue > SK_SEN_VAUX_RANGE_LIMITER) {
+			pSen->SenThreWarnLow = SK_SEN_VAUX_3V3_LOW_WARN;
+			pSen->SenThreErrLow = SK_SEN_VAUX_3V3_LOW_ERR;
+		}
+		/* 0V VAUX Voltage */
+		else {
+			pSen->SenThreWarnHigh = SK_SEN_VAUX_0V_WARN_ERR;
+			pSen->SenThreErrHigh = SK_SEN_VAUX_0V_WARN_ERR;
+		}
+	}
+
 	/*
 	 * Check initialization state:
 	 * The VIO Thresholds need adaption
@@ -1175,20 +1336,21 @@
 	if (!pSen->SenInit && pSen->SenReg == LM80_VT1_IN &&
 	     pSen->SenValue > SK_SEN_WARNLOW2C &&
 	     pSen->SenValue < SK_SEN_WARNHIGH2) {
-		pSen->SenThreErrLow = SK_SEN_ERRLOW2C; 
-		pSen->SenThreWarnLow = SK_SEN_WARNLOW2C; 
+		pSen->SenThreErrLow = SK_SEN_ERRLOW2C;
+		pSen->SenThreWarnLow = SK_SEN_WARNLOW2C;
 		pSen->SenInit = SK_TRUE;
 	}
 
 	if (!pSen->SenInit && pSen->SenReg == LM80_VT1_IN &&
 	     pSen->SenValue > SK_SEN_WARNLOW2 &&
 	     pSen->SenValue < SK_SEN_WARNHIGH2C) {
-		pSen->SenThreErrHigh = SK_SEN_ERRHIGH2C; 
-		pSen->SenThreWarnHigh = SK_SEN_WARNHIGH2C; 
+		pSen->SenThreErrHigh = SK_SEN_ERRHIGH2C;
+		pSen->SenThreWarnHigh = SK_SEN_WARNHIGH2C;
 		pSen->SenInit = SK_TRUE;
 	}
+#endif
 
-	if (!pSen->SenInit) {
+	if (pSen->SenInit != SK_SEN_DYN_INIT_NONE) {
 		SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E013, SKERR_I2C_E013MSG);
 	}
 }	/* SkI2cCheckSensor*/
@@ -1210,9 +1372,13 @@
 	SK_EVPARA	ParaLocal;
 	int			i;
 
+	/* New case: no sensors */
+	if (pAC->I2c.MaxSens == 0) {
+		return(0);
+	}
+
 	switch (Event) {
 	case SK_I2CEV_IRQ:
-	case SK_I2CEV_TIM:
 		pSen = &pAC->I2c.SenTable[pAC->I2c.CurrSens];
 		ReadComplete = SkI2cReadSensor(pAC, IoC, pSen);
 
@@ -1220,23 +1386,92 @@
 			/* Check sensor against defined thresholds */
 			SkI2cCheckSensor (pAC, pSen);
 
-			/* Increment Current and set appropriate Timeout */
-			Time = SK_I2C_TIM_SHORT;
+			/* Increment Current sensor and set appropriate Timeout */
+			pAC->I2c.CurrSens++;
+			if (pAC->I2c.CurrSens >= pAC->I2c.MaxSens) {
+				pAC->I2c.CurrSens = 0;
+				Time = SK_I2C_TIM_LONG;
+			}
+			else {
+				Time = SK_I2C_TIM_SHORT;
+			}
+
+			/* Start Timer */
+			ParaLocal.Para64 = (SK_U64)0;
 
-			pAC->I2c.CurrSens ++;
+			pAC->I2c.TimerMode = SK_TIMER_NEW_GAUGING;
+			
+			SkTimerStart(pAC, IoC, &pAC->I2c.SenTimer, Time,
+				SKGE_I2C, SK_I2CEV_TIM, ParaLocal);
+		}
+        else {
+			/* Start Timer */
+			ParaLocal.Para64 = (SK_U64)0;
+
+			pAC->I2c.TimerMode = SK_TIMER_WATCH_STATEMACHINE;
+
+            SkTimerStart(pAC, IoC, &pAC->I2c.SenTimer, SK_I2C_TIM_WATCH,
+				SKGE_I2C, SK_I2CEV_TIM, ParaLocal);
+		}
+		break;
+	case SK_I2CEV_TIM:
+		if (pAC->I2c.TimerMode == SK_TIMER_NEW_GAUGING) {
+
+			ParaLocal.Para64 = (SK_U64)0;
+			SkTimerStop(pAC, IoC, &pAC->I2c.SenTimer);
+
+			pSen = &pAC->I2c.SenTable[pAC->I2c.CurrSens];
+			ReadComplete = SkI2cReadSensor(pAC, IoC, pSen);
+
+			if (ReadComplete) {
+				/* Check sensor against defined thresholds */
+				SkI2cCheckSensor (pAC, pSen);
+
+				/* Increment Current sensor and set appropriate Timeout */
+				pAC->I2c.CurrSens++;
+				if (pAC->I2c.CurrSens == pAC->I2c.MaxSens) {
+					pAC->I2c.CurrSens = 0;
+					Time = SK_I2C_TIM_LONG;
+				}
+				else {
+					Time = SK_I2C_TIM_SHORT;
+				}
+
+				/* Start Timer */
+				ParaLocal.Para64 = (SK_U64)0;
+
+				pAC->I2c.TimerMode = SK_TIMER_NEW_GAUGING;
+
+				SkTimerStart(pAC, IoC, &pAC->I2c.SenTimer, Time,
+					SKGE_I2C, SK_I2CEV_TIM, ParaLocal);
+			}
+		}
+		else {
+			pSen = &pAC->I2c.SenTable[pAC->I2c.CurrSens];
+			pSen->SenErrFlag = SK_SEN_ERR_FAULTY;
+			SK_I2C_STOP(IoC);
+
+			/* Increment Current sensor and set appropriate Timeout */
+			pAC->I2c.CurrSens++;
 			if (pAC->I2c.CurrSens == pAC->I2c.MaxSens) {
 				pAC->I2c.CurrSens = 0;
 				Time = SK_I2C_TIM_LONG;
 			}
+			else {
+				Time = SK_I2C_TIM_SHORT;
+			}
 
 			/* Start Timer */
-			ParaLocal.Para64 = (SK_U64) 0;
+			ParaLocal.Para64 = (SK_U64)0;
+
+			pAC->I2c.TimerMode = SK_TIMER_NEW_GAUGING;
+
 			SkTimerStart(pAC, IoC, &pAC->I2c.SenTimer, Time,
 				SKGE_I2C, SK_I2CEV_TIM, ParaLocal);
 		}
 		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;
@@ -1255,4 +1490,4 @@
 	return(0);
 }	/* SkI2cEvent*/
 
-#endif	/* !SK_DIAG */ 
+#endif	/* !SK_DIAG */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sk98lin/sklm80.c linux-2.4.21-pre6/drivers/net/sk98lin/sklm80.c
--- linux-2.4.20/drivers/net/sk98lin/sklm80.c	2000-09-15 21:34:19.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sk98lin/sklm80.c	2003-03-26 23:49:25.000000000 +0000
@@ -2,16 +2,15 @@
  *
  * Name:	sklm80.c
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.17 $
- * Date:	$Date: 1999/11/22 13:35:51 $
+ * Version:	$Revision: 1.20 $
+ * Date:	$Date: 2002/08/13 09:16:27 $
  * Purpose:	Funktions to access Voltage and Temperature Sensor (LM80)
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998,1999 SysKonnect,
- *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *	(C)Copyright 1998-2002 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,16 @@
  * History:
  *
  *	$Log: sklm80.c,v $
+ *	Revision 1.20  2002/08/13 09:16:27  rschmidt
+ *	Changed return value for SkLm80ReadSensor() back to 'int'
+ *	Editorial changes
+ *	
+ *	Revision 1.19  2002/08/06 09:43:31  jschmalz
+ *	Extensions and changes for Yukon
+ *	
+ *	Revision 1.18  2002/08/02 12:26:57  rschmidt
+ *	Editorial changes
+ *	
  *	Revision 1.17  1999/11/22 13:35:51  cgoos
  *	Changed license header to GPL.
  *	
@@ -93,7 +102,7 @@
 	LM80 functions
 */
 static const char SysKonnectFileId[] =
-	"$Id: sklm80.c,v 1.17 1999/11/22 13:35:51 cgoos Exp $" ;
+	"$Id: sklm80.c,v 1.20 2002/08/13 09:16:27 rschmidt Exp $" ;
 
 #include "h/skdrv1st.h"		/* Driver Specific Definitions */
 #include "h/lm80.h"
@@ -107,15 +116,15 @@
 
 #ifdef	SK_DIAG
 /*
- * read the regeister 'reg' from the device 'device'
+ * read the register 'Reg' from the device 'Dev'
  *
  * return 	read error	-1
  *		success		the read value
  */
 int	SkLm80RcvReg(
 SK_IOC	IoC,		/* Adapter Context */
-int	Dev,		/* I2C device address */
-int	Reg)		/* register to read */
+int		Dev,		/* I2C device address */
+int		Reg)		/* register to read */
 {
 	int	Val = 0;
 	int	TempExt;
@@ -134,9 +143,9 @@
 		return(-1);
 	}
 
-	switch(Reg) {
+	switch (Reg) {
 	case LM80_TEMP_IN:
-		Val = (int)SkI2cRcvByte(IoC, 1) ;
+		Val = (int)SkI2cRcvByte(IoC, 1);
 
 		/* First: correct the value: it might be negative */
 		if ((Val & 0x80) != 0) {
@@ -145,7 +154,9 @@
 		}
 		Val = Val * SK_LM80_TEMP_LSB;
 		SkI2cStop(IoC);
-		TempExt = (int) SkLm80RcvReg(IoC,LM80_ADDR,LM80_TEMP_CTRL);
+		
+		TempExt = (int)SkLm80RcvReg(IoC, LM80_ADDR, LM80_TEMP_CTRL);
+		
 		if (Val > 0) {
 			Val += ((TempExt >> 7) * SK_LM80_TEMPEXT_LSB);
 		}
@@ -158,10 +169,11 @@
 	case LM80_VT1_IN:
 	case LM80_VT2_IN:
 	case LM80_VT3_IN:
-		Val = (int) SkI2cRcvByte(IoC, 1) * SK_LM80_VT_LSB;
+		Val = (int)SkI2cRcvByte(IoC, 1) * SK_LM80_VT_LSB;
 		break;
+	
 	default:
-		Val = (int) SkI2cRcvByte(IoC, 1);
+		Val = (int)SkI2cRcvByte(IoC, 1);
 		break;
 	}
 
@@ -173,30 +185,32 @@
 /*
  * read a sensors value (LM80 specific)
  *
- * This function reads a sensors value from the I2c sensor chip LM80. The
- * sensor is defined by its index into the sensors database in the struct
+ * This function reads a sensors value from the I2C sensor chip LM80.
+ * The sensor is defined by its index into the sensors database in the struct
  * pAC points to.
  *
  * Returns	1 if the read is completed
- *		0 if the read must be continued (I2c Bus still allocated)
+ *		0 if the read must be continued (I2C Bus still allocated)
  */
-int	SkLm80ReadSensor(
+int SkLm80ReadSensor(
 SK_AC		*pAC,	/* Adapter Context */
-SK_IOC		IoC,	/* IoContext needed in level 1 and 2 */
+SK_IOC		IoC,	/* I/O Context needed in level 1 and 2 */
 SK_SENSOR	*pSen)	/* Sensor to be read */
 {
 	SK_I32		Value;
 
-	switch(pSen->SenState) {
+	switch (pSen->SenState) {
 	case SK_SEN_IDLE:
 		/* Send address to ADDR register */
-		SK_I2C_CTL(IoC,I2C_READ,pSen->SenDev,pSen->SenReg,0);
+		SK_I2C_CTL(IoC, I2C_READ, pSen->SenDev, pSen->SenReg, 0);
 
 		pSen->SenState = SK_SEN_VALUE ;
-		BREAK_OR_WAIT(pAC, IoC, I2C_READ) ;
+		BREAK_OR_WAIT(pAC, IoC, I2C_READ);
+	
 	case SK_SEN_VALUE:
 		/* Read value from data register */
-		SK_IN32(IoC,B2_I2C_DATA, ((SK_U32 *)&Value));
+		SK_IN32(IoC, B2_I2C_DATA, ((SK_U32 *)&Value));
+		
 		Value &= 0xff; /* only least significant byte is valid */
 
 		/* Do NOT check the Value against the thresholds */
@@ -228,10 +242,9 @@
 			Value = Value - 256;
 		}
 
-		/* We have a temperature sensor and need to get the signed
-		 * extension. For now we get the extension from the last
-		 * reading, so in the normal case we won't see flickering
-		 * temperatures.
+		/* We have a temperature sensor and need to get the signed extension.
+		 * For now we get the extension from the last reading, so in the normal
+		 * case we won't see flickering temperatures.
 		 */
 		pSen->SenValue = (Value * SK_LM80_TEMP_LSB) +
 			(pSen->SenValue % SK_LM80_TEMP_LSB);
@@ -240,32 +253,34 @@
 		SK_I2C_CTL(IoC, I2C_READ, pSen->SenDev, LM80_TEMP_CTRL, 0);
 
 		pSen->SenState = SK_SEN_VALEXT ;
-		BREAK_OR_WAIT(pAC, IoC, I2C_READ) ;
+		BREAK_OR_WAIT(pAC, IoC, I2C_READ);
+	
 	case SK_SEN_VALEXT:
 		/* Read value from data register */
-		SK_IN32(IoC,B2_I2C_DATA,((SK_U32 *)&Value));
+		SK_IN32(IoC, B2_I2C_DATA, ((SK_U32 *)&Value));
 		Value &= LM80_TEMP_LSB_9; /* only bit 7 is valid */
 
 		/* cut the LSB bit */
 		pSen->SenValue = ((pSen->SenValue / SK_LM80_TEMP_LSB) *
-			SK_LM80_TEMP_LSB) ;
+			SK_LM80_TEMP_LSB);
 
 		if (pSen->SenValue < 0) {
 			/* Value negative: The bit value must be subtracted */
 			pSen->SenValue -= ((Value >> 7) * SK_LM80_TEMPEXT_LSB);
-		} else {
+		}
+		else {
 			/* Value positive: The bit value must be added */
 			pSen->SenValue += ((Value >> 7) * SK_LM80_TEMPEXT_LSB);
 		}
 
 		pSen->SenState = SK_SEN_IDLE ;
 		return(1);
+	
 	default:
-		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_I2C_E007,
-			SKERR_I2C_E007MSG) ;
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_I2C_E007, SKERR_I2C_E007MSG);
 		return(1);
 	}
 
 	/* Not completed */
-	return(0) ;
+	return(0);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sk98lin/skproc.c linux-2.4.21-pre6/drivers/net/sk98lin/skproc.c
--- linux-2.4.20/drivers/net/sk98lin/skproc.c	2001-09-10 16:04:53.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sk98lin/skproc.c	2003-03-26 23:49:00.000000000 +0000
@@ -2,15 +2,15 @@
  *
  * Name:    skproc.c
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.2.2.2 $
- * Date:    $Date: 2001/03/15 12:50:13 $
+ * Version:	$Revision: 1.3 $
+ * Date:    $Date: 2002/10/02 12:59:51 $
  * Purpose:	Funktions to display statictic data
  *
  ******************************************************************************/
  
 /******************************************************************************
  *
- *	(C)Copyright 1998-2001 SysKonnect GmbH.
+ *	(C)Copyright 1998-2002 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,6 +28,31 @@
  * History:
  *
  *	$Log: skproc.c,v $
+ *	Revision 1.3  2002/10/02 12:59:51  mlindner
+ *	Add: Support for Yukon
+ *	Add: Speed check and setup
+ *	Add: Merge source for kernel 2.2.x and 2.4.x
+ *	Add: Read sensor names directly from VPD
+ *	Fix: Volt values
+ *	
+ *	Revision 1.2.2.7  2002/01/14 12:45:15  mlindner
+ *	Fix: Editorial changes
+ *	
+ *	Revision 1.2.2.6  2001/12/06 15:26:07  mlindner
+ *	Fix: Return value of proc_read
+ *	
+ *	Revision 1.2.2.5  2001/12/06 09:57:39  mlindner
+ *	New ProcFs entries
+ *	
+ *	Revision 1.2.2.4  2001/09/05 12:16:02  mlindner
+ *	Add: New ProcFs entries
+ *	Fix: Counter Errors (Jumbo == to long errors)
+ *	Fix: Kernel error compilation
+ *	Fix: too short counters
+ *	
+ *	Revision 1.2.2.3  2001/06/25 07:26:26  mlindner
+ *	Add: More error messages
+ *	
  *	Revision 1.2.2.2  2001/03/15 12:50:13  mlindner
  *	fix: ProcFS owner protection
  *	
@@ -46,36 +71,24 @@
 
 #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 *sk98lin_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
-};
+#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 SPECIALX	32		/* 0x */
+#define LARGE		64
+
+extern SK_AC				*pACList;
+extern struct net_device 	*SkGeRootDev;
+
+extern char * SkNumber(
+	char * str,
+	long long num,
+	int base,
+	int size,
+	int precision,
+	int type);
 
 
 /*****************************************************************************
@@ -100,13 +113,14 @@
 	int len = 0;
 	int t;
 	int i;
-	DEV_NET				*pNet;
-	SK_AC				*pAC;
-	char 				test_buf[100];
+	DEV_NET					*pNet;
+	SK_AC					*pAC;
+	char 					test_buf[100];
+	char					sens_msg[50];
 	unsigned long			Flags;		
 	unsigned int			Size;
-	struct net_device 		*next;
-	struct net_device 		*SkgeProcDev = sk98lin_root_dev;
+	struct SK_NET_DEVICE 		*next;
+	struct SK_NET_DEVICE 		*SkgeProcDev = SkGeRootDev;
 
 	SK_PNMI_STRUCT_DATA 	*pPnmiStruct;
 	SK_PNMI_STAT		*pPnmiStat;
@@ -122,7 +136,7 @@
 		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, 
@@ -135,151 +149,214 @@
 					"\nDetailed statistic for device %s\n",
 					pAC->dev[t-1]->name);
 				len += sprintf(buffer + len,
-					"==================================\n");
+					"=======================================\n");
 	
 				/* Board statistics */
 				len += sprintf(buffer + len, 
 					"\nBoard statistics\n\n");
 				len += sprintf(buffer + len,
-					"Active Port               %c\n",
+					"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",
+					"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",
+					"Bus speed (MHz)                %d\n",
 					pPnmiStruct->BusSpeed);
 
 				len += sprintf(buffer + len,
-					"Bus width (Bit)           %d\n",
+					"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,
+					"Hardware revision              v%d.%d\n",
+					(pAC->GIni.GIPciHwRev >> 4) & 0x0F,
+					pAC->GIni.GIPciHwRev & 0x0F);
+
+				/* Print sensor informations */
+				for (i=0; i < pAC->I2c.MaxSens; i ++) {
+					/* Check type */
+					switch (pAC->I2c.SenTable[i].SenType) {
+					case 1:
+						strcpy(sens_msg, pAC->I2c.SenTable[i].SenDesc);
+						strcat(sens_msg, " (C)");
 						len += sprintf(buffer + len,
-							"Temperature (C)           %d.%d\n",
+							"%-25s      %d.%02d\n",
+							sens_msg,
 							pAC->I2c.SenTable[i].SenValue / 10,
 							pAC->I2c.SenTable[i].SenValue % 10);
+
+						strcpy(sens_msg, pAC->I2c.SenTable[i].SenDesc);
+						strcat(sens_msg, " (F)");
 						len += sprintf(buffer + len,
-							"Temperature (F)           %d.%d\n",
+							"%-25s      %d.%02d\n",
+							sens_msg,
 							((((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 {
+						break;
+					case 2:
+						strcpy(sens_msg, pAC->I2c.SenTable[i].SenDesc);
+						strcat(sens_msg, " (V)");
 						len += sprintf(buffer + len,
-							"%-20s      %d.%d\n",
-							pAC->I2c.SenTable[i].SenDesc,
+							"%-25s      %d.%03d\n",
+							sens_msg,
 							pAC->I2c.SenTable[i].SenValue / 1000,
 							pAC->I2c.SenTable[i].SenValue % 1000);
+						break;
+					case 3:
+						strcpy(sens_msg, pAC->I2c.SenTable[i].SenDesc);
+						strcat(sens_msg, " (rpm)");
+						len += sprintf(buffer + len,
+							"%-25s      %d\n",
+							sens_msg,
+							pAC->I2c.SenTable[i].SenValue);
+						break;
+					default:
+						break;
 					}
 				}
 				
 				/*Receive statistics */
-				
 				len += sprintf(buffer + len, 
 				"\nReceive statistics\n\n");
 
 				len += sprintf(buffer + len,
-					"Received bytes            %s\n",
+					"Received bytes                 %s\n",
 					SkNumber(test_buf, pPnmiStat->StatRxOctetsOkCts,
 					10,0,-1,0));
 				len += sprintf(buffer + len,
-					"Received packets          %s\n",
+					"Received packets               %s\n",
 					SkNumber(test_buf, pPnmiStat->StatRxOkCts,
 					10,0,-1,0));
+#if 0
+				if (pAC->GIni.GP[0].PhyType == SK_PHY_XMAC && 
+					pAC->HWRevision < 12) {
+					pPnmiStruct->InErrorsCts = pPnmiStruct->InErrorsCts - 
+						pPnmiStat->StatRxShortsCts;
+					pPnmiStat->StatRxShortsCts = 0;
+				}
+#endif
+				if (pNet->Mtu > 1500) 
+					pPnmiStruct->InErrorsCts = pPnmiStruct->InErrorsCts -
+						pPnmiStat->StatRxTooLongCts;
+
 				len += sprintf(buffer + len,
-					"Received errors           %s\n",
-					SkNumber(test_buf, pPnmiStat->StatRxFcsCts,
+					"Receive errors                 %s\n",
+					SkNumber(test_buf, pPnmiStruct->InErrorsCts,
 					10,0,-1,0));
 				len += sprintf(buffer + len,
-					"Received dropped          %s\n",
+					"Receive drops                  %s\n",
 					SkNumber(test_buf, pPnmiStruct->RxNoBufCts,
 					10,0,-1,0));
 				len += sprintf(buffer + len,
-					"Received multicast        %s\n",
+					"Received multicast             %s\n",
 					SkNumber(test_buf, pPnmiStat->StatRxMulticastOkCts,
 					10,0,-1,0));
 				len += sprintf(buffer + len,
-					"Received errors types\n");
+					"Receive error types\n");
 				len += sprintf(buffer + len,
-					"   length errors          %s\n",
+					"   length                      %s\n",
 					SkNumber(test_buf, pPnmiStat->StatRxRuntCts,
 					10, 0, -1, 0));
 				len += sprintf(buffer + len,
-					"   over errors            %s\n",
+					"   buffer overflow             %s\n",
 					SkNumber(test_buf, pPnmiStat->StatRxFifoOverflowCts,
 					10, 0, -1, 0));
 				len += sprintf(buffer + len,
-					"   crc errors             %s\n",
+					"   bad crc                     %s\n",
 					SkNumber(test_buf, pPnmiStat->StatRxFcsCts,
 					10, 0, -1, 0));
 				len += sprintf(buffer + len,
-					"   frame errors           %s\n",
+					"   framing                     %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",
+					"   missed frames               %s\n",
 					SkNumber(test_buf, pPnmiStat->StatRxMissedCts,
 					10, 0, -1, 0));
-				
+
+				if (pNet->Mtu > 1500)
+					pPnmiStat->StatRxTooLongCts = 0;
+
+				len += sprintf(buffer + len,
+					"   too long                    %s\n",
+					SkNumber(test_buf, pPnmiStat->StatRxTooLongCts,
+					10, 0, -1, 0));					
+				len += sprintf(buffer + len,
+					"   carrier extension           %s\n",
+					SkNumber(test_buf, pPnmiStat->StatRxCextCts,
+					10, 0, -1, 0));				
+				len += sprintf(buffer + len,
+					"   too short                   %s\n",
+					SkNumber(test_buf, pPnmiStat->StatRxShortsCts,
+					10, 0, -1, 0));				
+				len += sprintf(buffer + len,
+					"   symbol                      %s\n",
+					SkNumber(test_buf, pPnmiStat->StatRxSymbolCts,
+					10, 0, -1, 0));				
+				len += sprintf(buffer + len,
+					"   LLC MAC size                %s\n",
+					SkNumber(test_buf, pPnmiStat->StatRxIRLengthCts,
+					10, 0, -1, 0));				
+				len += sprintf(buffer + len,
+					"   carrier event               %s\n",
+					SkNumber(test_buf, pPnmiStat->StatRxCarrierCts,
+					10, 0, -1, 0));				
+				len += sprintf(buffer + len,
+					"   jabber                      %s\n",
+					SkNumber(test_buf, pPnmiStat->StatRxJabberCts,
+					10, 0, -1, 0));				
+
+
 				/*Transmit statistics */
 				len += sprintf(buffer + len, 
 				"\nTransmit statistics\n\n");
 				
 				len += sprintf(buffer + len,
-					"Transmit bytes            %s\n",
+					"Transmited bytes               %s\n",
 					SkNumber(test_buf, pPnmiStat->StatTxOctetsOkCts,
 					10,0,-1,0));
 				len += sprintf(buffer + len,
-					"Transmit packets          %s\n",
+					"Transmited packets             %s\n",
 					SkNumber(test_buf, pPnmiStat->StatTxOkCts,
 					10,0,-1,0));
 				len += sprintf(buffer + len,
-					"Transmit errors           %s\n",
+					"Transmit errors                %s\n",
 					SkNumber(test_buf, pPnmiStat->StatTxSingleCollisionCts,
 					10,0,-1,0));
 				len += sprintf(buffer + len,
-					"Transmit dropped          %s\n",
+					"Transmit dropped               %s\n",
 					SkNumber(test_buf, pPnmiStruct->TxNoBufCts,
 					10,0,-1,0));
 				len += sprintf(buffer + len,
-					"Transmit collisions       %s\n",
+					"Transmit collisions            %s\n",
 					SkNumber(test_buf, pPnmiStat->StatTxSingleCollisionCts,
 					10,0,-1,0));
 				len += sprintf(buffer + len,
-					"Transmited errors types\n");
+					"Transmit errors types\n");
 				len += sprintf(buffer + len,
-					"   aborted errors         %ld\n",
+					"   excessive collision         %ld\n",
 					pAC->stats.tx_aborted_errors);
 				len += sprintf(buffer + len,
-					"   carrier errors         %s\n",
+					"   carrier                     %s\n",
 					SkNumber(test_buf, pPnmiStat->StatTxCarrierCts,
 					10, 0, -1, 0));
 				len += sprintf(buffer + len,
-					"   fifo errors            %s\n",
+					"   fifo underrun               %s\n",
 					SkNumber(test_buf, pPnmiStat->StatTxFifoUnderrunCts,
 					10, 0, -1, 0));
 				len += sprintf(buffer + len,
-					"   heartbeat errors       %s\n",
+					"   heartbeat                   %s\n",
 					SkNumber(test_buf, pPnmiStat->StatTxCarrierCts,
 					10, 0, -1, 0));
 				len += sprintf(buffer + len,
-					"   window errors          %ld\n",
+					"   window                      %ld\n",
 					pAC->stats.tx_window_errors);
+				
 			}
 		}
 		SkgeProcDev = next;
@@ -388,7 +465,7 @@
 			size--;
 		}
 	}
-	if (type & SPECIAL) {
+	if (type & SPECIALX) {
 		if (base == 16)
 			size -= 2;
 		else if (base == 8)
@@ -408,7 +485,7 @@
 			*str++ = ' ';
 	if (sign)
 		*str++ = sign;
-	if (type & SPECIAL) {
+	if (type & SPECIALX) {
 		if (base==8)
 			*str++ = '0';
 		else if (base==16) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sk98lin/skqueue.c linux-2.4.21-pre6/drivers/net/sk98lin/skqueue.c
--- linux-2.4.20/drivers/net/sk98lin/skqueue.c	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sk98lin/skqueue.c	2003-03-26 23:49:18.000000000 +0000
@@ -1,32 +1,23 @@
 /******************************************************************************
  *
  * Name:	skqueue.c
- * Project:	PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.14 $
- * Date:	$Date: 1998/10/15 15:11:35 $
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.18 $
+ * Date:	$Date: 2002/05/07 14:11:11 $
  * Purpose:	Management of an event queue.
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1989-1998 SysKonnect,
+ *	(C)Copyright 1998,1999 SysKonnect,
  *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
- *	All Rights Reserved
  *
- *	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.
+ *	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.
  *
  ******************************************************************************/
@@ -36,6 +27,18 @@
  * History:
  *
  *	$Log: skqueue.c,v $
+ *	Revision 1.18  2002/05/07 14:11:11  rwahl
+ *	Fixed Watcom Precompiler error.
+ *	
+ *	Revision 1.17  2002/03/25 10:06:41  mkunz
+ *	SkIgnoreEvent deleted
+ *	
+ *	Revision 1.16  2002/03/15 10:51:59  mkunz
+ *	Added event classes for link aggregation
+ *	
+ *	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
  *	
@@ -88,7 +91,7 @@
 	Event queue and dispatcher
 */
 static const char SysKonnectFileId[] =
-	"$Header: /usr56/projects/ge/schedule/skqueue.c,v 1.14 1998/10/15 15:11:35 gklug Exp $" ;
+	"$Header: /usr56/projects/ge/schedule/skqueue.c,v 1.18 2002/05/07 14:11:11 rwahl Exp $" ;
 
 #include "h/skdrv1st.h"		/* Driver Specific Definitions */
 #include "h/skqueue.h"		/* Queue Definitions */
@@ -168,9 +171,7 @@
 	while (pEv != pAC->Event.EvPut) {
 		PRINTF("dispatch Class %d Event %d\n",pEv->Class,pEv->Event) ;
 		switch(Class = pEv->Class) {
-		case SKGE_DRV :		/* Driver Event */
-			Rtv = SkDrvEvent(pAC,Ioc,pEv->Event,pEv->Para);
-			break ;
+#ifndef SK_USE_LAC_EV        
 		case SKGE_RLMT :	/* RLMT Event */
 			Rtv = SkRlmtEvent(pAC,Ioc,pEv->Event,pEv->Para);
 			break ;
@@ -180,9 +181,33 @@
 		case SKGE_PNMI :
 			Rtv = SkPnmiEvent(pAC,Ioc,pEv->Event,pEv->Para);
 			break ;
+#endif /* SK_USE_LAC_EV */
+		case SKGE_DRV :		/* Driver Event */
+			Rtv = SkDrvEvent(pAC,Ioc,pEv->Event,pEv->Para);
+			break ;
+#ifndef SK_USE_SW_TIMER        
 		case SKGE_HWAC :
 			Rtv = SkGeSirqEvent(pAC,Ioc,pEv->Event,pEv->Para);
 			break ;
+#else /* !SK_USE_SW_TIMER */
+        case SKGE_SWT : 
+			Rtv = SkSwtEvent(pAC,Ioc,pEv->Event,pEv->Para);
+			break ;
+#endif /* !SK_USE_SW_TIMER */
+#ifdef SK_USE_LAC_EV        
+		case SKGE_LACP :
+			Rtv = SkLacpEvent(pAC,Ioc,pEv->Event,pEv->Para);
+			break ;
+		case SKGE_RSF :
+			Rtv = SkRsfEvent(pAC,Ioc,pEv->Event,pEv->Para);
+			break ;
+		case SKGE_MARKER :
+			Rtv = SkMarkerEvent(pAC,Ioc,pEv->Event,pEv->Para);
+			break ;
+		case SKGE_FD :
+			Rtv = SkFdEvent(pAC,Ioc,pEv->Event,pEv->Para);
+			break ;
+#endif /* SK_USE_LAC_EV */
 #ifdef	SK_USE_CSUM
 		case SKGE_CSUM :
 			Rtv = SkCsEvent(pAC,Ioc,pEv->Event,pEv->Para);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sk98lin/skrlmt.c linux-2.4.21-pre6/drivers/net/sk98lin/skrlmt.c
--- linux-2.4.20/drivers/net/sk98lin/skrlmt.c	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sk98lin/skrlmt.c	2003-03-26 23:49:49.000000000 +0000
@@ -2,8 +2,8 @@
  *
  * Name:	skrlmt.c
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.61 $
- * Date:	$Date: 2001/03/14 12:52:08 $
+ * Version:	$Revision: 1.65 $
+ * Date:	$Date: 2002/07/22 14:29:48 $
  * Purpose:	Manage links on SK-NET Adapters, esp. redundant ones.
  *
  ******************************************************************************/
@@ -26,6 +26,23 @@
  * History:
  *
  *	$Log: skrlmt.c,v $
+ *	Revision 1.65  2002/07/22 14:29:48  rwahl
+ *	- Removed BRK statement from debug check.
+ *	
+ *	Revision 1.64  2001/11/28 19:36:14  rwahl
+ *	- RLMT Packets sent to an invalid MAC address in CLP/CLPSS mode
+ *	  (#10650).
+ *	- Reworked fix for port switching in CLS mode (#10639)
+ *	 (no dependency to RLMT module).
+ *	- Enabled dbg output for entry/exit of event functions.
+ *	- Editorial changes.
+ *	
+ *	Revision 1.63  2001/10/26 07:53:18  afischer
+ *	Port switching bug in `check local link` mode
+ *	
+ *	Revision 1.62  2001/07/03 12:16:30  mkunz
+ *	New Flag ChgBcPrio (Change priority of last broadcast received)
+ *	
  *	Revision 1.61  2001/03/14 12:52:08  rassmann
  *	Fixed reporting of active port up/down to PNMI.
  *	
@@ -255,7 +272,7 @@
 
 #ifndef	lint
 static const char SysKonnectFileId[] =
-	"@(#) $Id: skrlmt.c,v 1.61 2001/03/14 12:52:08 rassmann Exp $ (C) SysKonnect.";
+	"@(#) $Id: skrlmt.c,v 1.65 2002/07/22 14:29:48 rwahl Exp $ (C) SysKonnect.";
 #endif	/* !defined(lint) */
 
 #define __SKRLMT_C
@@ -585,8 +602,8 @@
 		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;
+			pAC->Rlmt.Net[i].Preference = 0xFFFFFFFF;	  /* Automatic. */
 			/* Just assuming. */
 			pAC->Rlmt.Net[i].ActivePort = pAC->Rlmt.Net[i].PrefPort;
 			pAC->Rlmt.Net[i].RlmtMode = SK_RLMT_DEF_MODE;
@@ -714,7 +731,7 @@
 				FirstMacUp = pAC->Rlmt.Net[NetIdx].Port[i];
 			}
 			else {
-				pAC->Rlmt.Net[NetIdx].Port[i]->PortCheck[
+				PrevMacUp->PortCheck[
 					pAC->Rlmt.Net[NetIdx].Port[i]->PortsChecked].CheckAddr =
 					pAC->Rlmt.Net[NetIdx].Port[i]->AddrPort->CurrentMacAddress;
 				PrevMacUp->PortCheck[
@@ -737,7 +754,7 @@
 #ifdef DEBUG
 	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,
+			("Port %d checks %d other ports: %2X.\n", i,
 				pAC->Rlmt.Net[NetIdx].Port[i]->PortsChecked,
 				pAC->Rlmt.Net[NetIdx].Port[i]->PortCheck[0].CheckAddr.a[5]))
 	}
@@ -773,6 +790,22 @@
 	SK_MBUF		*pMb;
 	SK_RLMT_PACKET	*pPacket;
 
+#ifdef DEBUG
+	SK_U8	CheckSrc  = 0;
+	SK_U8	CheckDest = 0;
+	
+	for (i = 0; i < SK_MAC_ADDR_LEN; ++i) {
+		CheckSrc  |= SrcAddr->a[i];
+		CheckDest |= DestAddr->a[i];
+	}
+
+	if ((CheckSrc == 0) || (CheckDest == 0)) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_ERR,
+			("SkRlmtBuildPacket: Invalid %s%saddr.\n",
+			 (CheckSrc == 0 ? "Src" : ""), (CheckDest == 0 ? "Dest" : "")))
+	}
+#endif
+
 	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++) {
@@ -1504,7 +1537,7 @@
 	
 	/* Select port with the latest TimeStamp. */
 	for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
-#ifdef xDEBUG
+#ifdef DEBUG
 		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
 			("TimeStamp Port %d: %08x %08x.\n",
 				i,
@@ -1521,10 +1554,8 @@
 	}
 
 	if (PortFound) {
-#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++) {
@@ -1537,7 +1568,7 @@
 				pAC->Rlmt.Port[i].BcTimeStamp +
 				 SK_RLMT_BC_DELTA > BcTimeStamp)) {
 				PortFound = SK_FALSE;
-#ifdef xDEBUG
+#ifdef DEBUG
 				SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
 					("Port %d received a broadcast at a similar time.\n", i))
 #endif	/* DEBUG */
@@ -1546,10 +1577,11 @@
 		}
 	}
 
-#ifdef xDEBUG
+#ifdef DEBUG
 	if (PortFound) {
 		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
-			("SK_RLMT_CHECK_SWITCH found Port %d receiving the substantially latest broadcast (%d).\n",
+			("SK_RLMT_CHECK_SWITCH found Port %d receiving the substantially "
+			 "latest broadcast (%d).\n",
 				*pSelect,
 				BcTimeStamp - pAC->Rlmt.Port[1 - *pSelect].BcTimeStamp))
 	}
@@ -1794,6 +1826,13 @@
 	PortFound = SK_FALSE;
 	pAC->Rlmt.CheckSwitch = SK_FALSE;
 
+#if 0	/* RW 2001/10/18 - active port becomes always prefered one */
+	if (pAC->Rlmt.Net[NetIdx].Preference == 0xFFFFFFFF) { /* Automatic */
+		/* disable auto-fail back */
+		PrefPort = Active;
+	}
+#endif
+
 	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;
@@ -1882,7 +1921,10 @@
 		 *		else
 		 *			SwitchSoft
 		 */
-		if (pAC->Rlmt.Net[0].RlmtMode != SK_RLMT_MODE_CLS) {
+		/* check of ChgBcPrio flag added */
+		if ((pAC->Rlmt.Net[0].RlmtMode != SK_RLMT_MODE_CLS) &&
+			(!pAC->Rlmt.Net[0].ChgBcPrio)) {
+			
 			if (!PortFound) {
 				PortFound = SkRlmtSelectBcRx(
 					pAC, IoC, Active, PrefPort, &Para.Para32[1]);
@@ -1894,6 +1936,20 @@
 			}
 		}	/* pAC->Rlmt.RlmtMode != SK_RLMT_MODE_CLS */
 
+		/* with changed priority for last broadcast received */
+		if ((pAC->Rlmt.Net[0].RlmtMode != SK_RLMT_MODE_CLS) &&
+			(pAC->Rlmt.Net[0].ChgBcPrio)) {
+			if (!PortFound) {
+				PortFound = SkRlmtSelectNotSuspect(
+					pAC, IoC, Active, PrefPort, &Para.Para32[1]);
+			}
+
+			if (!PortFound) {
+				PortFound = SkRlmtSelectBcRx(
+					pAC, IoC, Active, PrefPort, &Para.Para32[1]);
+			}
+		}	/* pAC->Rlmt.RlmtMode != SK_RLMT_MODE_CLS */
+
 		if (!PortFound) {
 			PortFound = SkRlmtSelectUp(
 				pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_SUCCESS);
@@ -1927,6 +1983,7 @@
 		}	/* pAC->Rlmt.RlmtMode != SK_RLMT_MODE_CLS */
 
 		if (PortFound) {
+
 			if (Para.Para32[1] != Active) {
 				SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
 					("Active: %d, Para1: %d.\n", Active, Para.Para32[1]))
@@ -2698,10 +2755,8 @@
 	SK_U32			PortNumber;
 	SK_U32			i;
 
-#if 0
 	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
 		("SK_RLMT_TIM Event BEGIN.\n"))
-#endif	/* 0 */
 
 	if (Para.Para32[1] != (SK_U32)-1) {
 		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
@@ -2778,10 +2833,8 @@
 			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 END.\n"))
-#endif	/* 0 */
 }	/* SkRlmtEvtTim */
 
 
@@ -2804,7 +2857,7 @@
 SK_IOC		IoC,	/* I/O Context */
 SK_EVPARA	Para)	/* SK_U32 NetNumber; SK_U32 -1 */
 {
-#ifdef XDEBUG
+#ifdef xDEBUG
 	int j;
 #endif	/* DEBUG */
 
@@ -2820,7 +2873,7 @@
 	}
 
 #ifdef xDEBUG
-	for (j = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; j++) {
+	for (j = 0; j < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; j++) {
 		SK_ADDR_PORT	*pAPort;
 		SK_U32			k;
 		SK_U16			*InAddr;
@@ -2842,7 +2895,7 @@
 					pAPort->Exact[k].a[4], pAPort->Exact[k].a[5]))
 		}
 	}
-#endif	/* DEBUG */
+#endif	/* xDEBUG */
 				   
 	SkRlmtCheckSeg(pAC, IoC, Para.Para32[0]);
 
@@ -2874,10 +2927,9 @@
 	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? */
 
@@ -2905,10 +2957,8 @@
 		}
 	}
 
-#if 0
 	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
 		("SK_RLMT_PACKET_RECEIVED Event END.\n"))
-#endif	/* 0 */
 }	/* SkRlmtEvtPacketRx */
 
 
@@ -2987,6 +3037,9 @@
 SK_IOC		IoC,	/* I/O Context */
 SK_EVPARA	Para)	/* SK_U32 NetNumber; SK_U32 -1 */
 {
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_STATS_UPDATE Event BEGIN.\n"))
+
 	if (Para.Para32[1] != (SK_U32)-1) {
 		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
 			("Bad Parameter.\n"))
@@ -3003,15 +3056,10 @@
 		return;
 	}
 
-#if 0
-	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 */
 }	/* SkRlmtEvtStatsUpdate */
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sk98lin/sktimer.c linux-2.4.21-pre6/drivers/net/sk98lin/sktimer.c
--- linux-2.4.20/drivers/net/sk98lin/sktimer.c	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sk98lin/sktimer.c	2003-03-26 23:49:06.000000000 +0000
@@ -1,32 +1,23 @@
 /******************************************************************************
  *
  * Name:	sktimer.c
- * Project:	PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.11 $
- * Date:	$Date: 1998/12/17 13:24:13 $
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.12 $
+ * Date:	$Date: 1999/11/22 13:38:51 $
  * Purpose:	High level timer functions.
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1989-1998 SysKonnect,
+ *	(C)Copyright 1998,1999 SysKonnect,
  *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
- *	All Rights Reserved
  *
- *	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 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 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.
  *
  ******************************************************************************/
@@ -36,6 +27,9 @@
  * 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
  *	
@@ -82,7 +76,7 @@
 	Event queue and dispatcher
 */
 static const char SysKonnectFileId[] =
-	"$Header: /usr56/projects/ge/schedule/sktimer.c,v 1.11 1998/12/17 13:24:13 gklug Exp $" ;
+	"$Header: /usr56/projects/ge/schedule/sktimer.c,v 1.12 1999/11/22 13:38:51 cgoos Exp $" ;
 
 #include "h/skdrv1st.h"		/* Driver Specific Definitions */
 #include "h/skdrv2nd.h"		/* Adapter Control- and Driver specific Def. */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sk98lin/skvpd.c linux-2.4.21-pre6/drivers/net/sk98lin/skvpd.c
--- linux-2.4.20/drivers/net/sk98lin/skvpd.c	2001-11-13 17:19:41.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sk98lin/skvpd.c	2003-03-26 23:49:40.000000000 +0000
@@ -2,16 +2,15 @@
  *
  * Name:	skvpd.c
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.26 $
- * Date:	$Date: 2000/06/13 08:00:01 $
+ * Version:	$Revision: 1.32 $
+ * Date:	$Date: 2002/10/14 16:04:29 $
  * Purpose:	Shared software to read and write VPD data
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998,1999 SysKonnect,
- *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *	(C)Copyright 1998-2002 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,32 @@
  * History:
  *
  *	$Log: skvpd.c,v $
+ *	Revision 1.32  2002/10/14 16:04:29  rschmidt
+ *	Added saving of VPD ROM Size from PCI_OUR_REG_2
+ *	Avoid reading of PCI_OUR_REG_2 in VpdTransferBlock()
+ *	Editorial changes
+ *	
+ *	Revision 1.31  2002/09/10 09:21:32  mkarl
+ *	Replaced all if(GIChipId == CHIP_ID_GENESIS) with new entry GIGenesis
+ *	
+ *	Revision 1.30  2002/09/09 14:43:03  mkarl
+ *	changes for diagnostics in order to read VPD data before the adapter
+ *	has been initialized
+ *	editorial changes
+ *	
+ *	Revision 1.29  2002/07/26 13:20:43  mkarl
+ *	added Yukon support
+ *	save size of VPD in pAC->vpd.vpd_size
+ *	
+ *	Revision 1.28  2002/04/02 15:31:47  afischer
+ *	Bug fix in VpdWait()
+ *	
+ *	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
  *	
@@ -66,7 +91,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 return SK_U32
+ *	fix: VpdRead/WriteDWord now returns 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
@@ -88,7 +113,7 @@
  *	Revision 1.9  1998/09/16 07:33:52  malthoff
  *	remove memcmp() by SK_MEMCMP and
  *	memcpy() by SK_MEMCPY() to be
- *	independant from the 'C' Standard Library.
+ *	independent from the 'C' Standard Library.
  *	
  *	Revision 1.8  1998/08/19 12:52:35  malthoff
  *	compiler fix: use SK_VPD_KEY instead of S_VPD.
@@ -124,7 +149,7 @@
 	Please refer skvpd.txt for infomation how to include this module
  */
 static const char SysKonnectFileId[] =
-	"@(#)$Id: skvpd.c,v 1.26 2000/06/13 08:00:01 mkarl Exp $ (C) SK" ;
+	"@(#)$Id: skvpd.c,v 1.32 2002/10/14 16:04:29 rschmidt Exp $ (C) SK";
 
 #include "h/skdrv1st.h"
 #include "h/sktypes.h"
@@ -137,46 +162,58 @@
 #ifndef SK_KR_PROTO
 static SK_VPD_PARA	*vpd_find_para(
 	SK_AC	*pAC,
-	char		*key,
-	SK_VPD_PARA *p) ;
+	char	*key,
+	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 */
 
 /*
- * waits for a completetion of a VPD transfer
+ * waits for a completion of a VPD transfer
  * The VPD transfer must complete within SK_TICKS_PER_SEC/16
  *
  * returns	0:	success, transfer completes
  *		error	exit(9) with a error message
  */
 static int	VpdWait(
-SK_AC		*pAC,	/* Adapters context */
-SK_IOC		IoC,	/* IO Context */
+SK_AC	*pAC,	/* Adapters context */
+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) ;
+	SK_DBG_MSG(pAC,SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+		("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) ;
-			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,
-				SK_DBGCAT_FATAL|SK_DBGCAT_ERR,
-				("ERROR:vpd wait timeout\n")) ;
-			return(1) ;
-		}
-		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) ;
 
-	return(0) ;
+			/* Bug fix AF: Thu Mar 28 2002
+			 * Do not call: VPD_STOP(pAC, IoC);
+			 * A pending VPD read cycle can not be aborted by writing
+			 * VPD_WRITE to the PCI_VPD_ADR_REG (VPD address register).
+			 * Although the write threshold in the OUR-register protects
+			 * VPD read only space from being overwritten this does not
+			 * protect a VPD read from being `converted` into a VPD write
+			 * operation (on the fly). As a consequence the VPD_STOP would
+			 * delete VPD read only data. In case of any problems with the
+			 * I2C bus we exit the loop here. The I2C read operation can
+			 * not be aborted except by a reset (->LR).
+			 */
+			SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_FATAL | SK_DBGCAT_ERR,
+				("ERROR:VPD wait timeout\n"));
+			return(1);
+		}
+		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);
+
+	return(0);
 }
 
+#ifdef SKDIAG
 
 /*
  * Read the dword at address 'addr' from the VPD EEPROM.
@@ -188,32 +225,37 @@
  *
  * Returns the data read.
  */
-SK_U32		VpdReadDWord(
-SK_AC		*pAC,	/* Adapters context */
-SK_IOC		IoC,	/* IO Context */
+SK_U32 VpdReadDWord(
+SK_AC	*pAC,	/* Adapters context */
+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 */
+	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_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) ;
-	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
-		("vpd read dword data = 0x%x\n",Rtv)) ;
-	return (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);
 }
 
+#endif	/* SKDIAG */
+
+#if 0
+
 /*
 	Write the dword 'data' at address 'addr' into the VPD EEPROM, and
 	verify that the data is written.
@@ -233,43 +275,43 @@
 
 
  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
 
  */
-#if 0 /* Unused at the moment */
-static int	VpdWriteDWord(
-SK_AC		*pAC,	/* pAC pointer */
-SK_IOC		IoC,	/* IO Context */
+static int VpdWriteDWord(
+SK_AC	*pAC,	/* pAC pointer */
+SK_IOC	IoC,	/* IO Context */
 int		addr,	/* VPD address */
-SK_U32		data)	/* VPD data to write */
+SK_U32	data)	/* VPD data to write */
 {
 	/* 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) ;
+	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);
 	/* 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) ;
-	} ;
+	if (VpdWait(pAC, IoC, VPD_WRITE)) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+			("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) ;
+	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);
 	}
-	return(0) ;
-}
-#endif
+	return(0);
+}	/* VpdWriteDWord */
+
+#endif	/* 0 */
 
 /*
  *	Read one Stream of 'len' bytes of VPD data, starting at 'addr' from
@@ -278,88 +320,85 @@
  * Returns number of bytes read / written.
  */
 static int	VpdWriteStream(
-SK_AC		*pAC,	/* Adapters context */
-SK_IOC		IoC,	/* IO Context */
-char		*buf,	/* data buffer */
+SK_AC	*pAC,	/* Adapters context */
+SK_IOC	IoC,	/* IO Context */
+char	*buf,	/* data buffer */
 int		Addr,	/* VPD start address */
 int		Len)	/* number of bytes to read / to write */
 {
-	int		i ;
-	int		j ;
-	SK_U16		AdrReg ;
-	int		Rtv ;
-	SK_U8		* pComp;	/* Compare pointer */
-	SK_U8		Data ;		/* Input Data for Compare */
+	int		i;
+	int		j;
+	SK_U16	AdrReg;
+	int		Rtv;
+	SK_U8	* pComp;	/* Compare pointer */
+	SK_U8	Data;		/* Input Data for Compare */
 
 	/* Init Compare Pointer */
 	pComp = (SK_U8 *) buf;
 
-	for (i=0; i < Len; i ++, buf++) {
+	for (i = 0; i < Len; i++, buf++) {
 		if ((i%sizeof(SK_U32)) == 0) {
 			/*
 			 * At the begin of each cycle read the Data Reg
 			 * 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) ;
+			/* Wait for termination */
+			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) ;
+		VPD_OUT8(pAC, IoC, PCI_VPD_DAT_REG + (i%sizeof(SK_U32)),
+				*(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))) ;
+				SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+					("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))) ;
+				SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+					("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) ;
+			for (j = 0; j <= (int)(i%sizeof(SK_U32)); j++, pComp++) {
+				VPD_IN8(pAC, IoC, PCI_VPD_DAT_REG + j, &Data);
 				if (Data != *pComp) {
 					/* Verify Error */
-					SK_DBG_MSG(pAC,SK_DBGMOD_VPD,
-						SK_DBGCAT_ERR,
+					SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
 						("WriteStream Verify Error\n"));
 					return(i - (i%sizeof(SK_U32)) + j);
 				}
 			}
-
 		}
 	}
 
@@ -374,85 +413,85 @@
  * Returns number of bytes read / written.
  */
 static int	VpdReadStream(
-SK_AC		*pAC,	/* Adapters context */
-SK_IOC		IoC,	/* IO Context */
-char		*buf,	/* data buffer */
+SK_AC	*pAC,	/* Adapters context */
+SK_IOC	IoC,	/* IO Context */
+char	*buf,	/* data buffer */
 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++) {
+	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) ;
+			/* Wait for termination */
+			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) ;
+		VPD_IN8(pAC, IoC, PCI_VPD_DAT_REG + (i%sizeof(SK_U32)),
+			(SK_U8 *)buf);
 	}
 
-	return(Len) ;
+	return(Len);
 }
 
 /*
- *	Read ore wirtes 'len' bytes of VPD data, starting at 'addr' from
+ *	Read ore writes 'len' bytes of VPD data, starting at 'addr' from
  *	or to the I2C EEPROM.
  *
  * Returns number of bytes read / written.
  */
 static int	VpdTransferBlock(
-SK_AC		*pAC,	/* Adapters context */
-SK_IOC		IoC,	/* IO Context */
-char		*buf,	/* data buffer */
+SK_AC	*pAC,	/* Adapters context */
+SK_IOC	IoC,	/* IO Context */
+char	*buf,	/* data buffer */
 int		addr,	/* VPD start address */
 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 ;
-
-	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
-		("vpd %s block, addr = 0x%x, len = %d\n",
-		dir?"write":"read",addr,len)) ;
+	int		Rtv;	/* Return value */
+	int		vpd_rom_size;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+		("VPD %s block, addr = 0x%x, len = %d\n",
+		dir ? "write" : "read", addr, len));
 
 	if (len == 0)
-		return (0) ;
+		return(0);
 
-	VPD_IN32(pAC,IoC,PCI_OUR_REG_2,&our_reg2) ;
-	vpd_rom_size = 256 << ((our_reg2 & PCI_VPD_ROM_SZ) >> 14);
+	vpd_rom_size = pAC->vpd.rom_size;
+	
 	if (addr > vpd_rom_size - 4) {
-		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR|SK_DBGCAT_FATAL,
+		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 ;
-		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
-			("Warning: len was cut to %d\n",len)) ;
+		len = vpd_rom_size - addr;
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+			("Warning: len was cut to %d\n", len));
 	}
 
 	if (dir == VPD_READ) {
 		Rtv = VpdReadStream(pAC, IoC, buf, addr, len);
-	} else {
+	}
+	else {
 		Rtv = VpdWriteStream(pAC, IoC, buf, addr, len);
 	}
 
-	return (Rtv) ;
+	return(Rtv);
 }
 
 #ifdef SKDIAG
@@ -463,13 +502,13 @@
  * Returns number of bytes read.
  */
 int		VpdReadBlock(
-SK_AC		*pAC,	/* pAC pointer */
-SK_IOC		IoC,	/* IO Context */
-char		*buf,	/* buffer were the data should be stored */
+SK_AC	*pAC,	/* pAC pointer */
+SK_IOC	IoC,	/* IO Context */
+char	*buf,	/* buffer were the data should be stored */
 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));
 }
 
 /*
@@ -478,13 +517,13 @@
  * Returns number of bytes writes.
  */
 int		VpdWriteBlock(
-SK_AC		*pAC,	/* pAC pointer */
-SK_IOC		IoC,	/* IO Context */
-char		*buf,	/* buffer, holds the data to write */
+SK_AC	*pAC,	/* pAC pointer */
+SK_IOC	IoC,	/* IO Context */
+char	*buf,	/* buffer, holds the data to write */
 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 */
 
@@ -498,72 +537,112 @@
  *		1:	fatal VPD error
  */
 static int	VpdInit(
-SK_AC		*pAC,	/* Adapters context */
-SK_IOC		IoC)	/* IO Context */
+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;
+	int		vpd_size;
+	SK_U16	word;
+	SK_U32	our_reg2;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_INIT, ("VpdInit .. "));
+	
+	VPD_IN16(pAC, IoC, PCI_DEVICE_ID, &word);
+	
+	VPD_IN32(pAC, IoC, PCI_OUR_REG_2, &our_reg2);
+	
+	pAC->vpd.rom_size = 256 << ((our_reg2 & PCI_VPD_ROM_SZ) >> 14);
+	
+	/*
+	 * this function might get used before the hardware is initialized
+	 * therefore we cannot always trust in GIChipId
+	 */
+	if (((pAC->vpd.v.vpd_status & VPD_VALID) == 0 &&
+		word == VPD_PCI_ID_YUKON) ||
+		((pAC->vpd.v.vpd_status & VPD_VALID) != 0 &&
+		!(pAC->GIni.GIGenesis))) {
+
+		/* for Yukon the VPD size is always 256 */
+		vpd_size = VPD_SIZE_YUKON;
+	}
+	else {
+		/* Genesis uses the maximum ROM size up to 512 for VPD */
+		if (pAC->vpd.rom_size > VPD_SIZE_GENESIS) {
+			vpd_size = VPD_SIZE_GENESIS;
+		}
+		else {
+			vpd_size = pAC->vpd.rom_size;
+		}
+	}
 
-	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) {
+	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) ;
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+			("Block Read Error\n"));
+		return(1);
 	}
+	
+	pAC->vpd.vpd_size = vpd_size;
 
 	/* 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) ;
+	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);
 	}
-	if (r->p_val + r->p_len > pAC->vpd.vpd_buf + VPD_SIZE/2) {
+	
+	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] ;
+	for (i = 0, x = 0; (unsigned)i<=(unsigned)vpd_size/2 - r->p_len; 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) ;
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+			("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) ;
+	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);
 	}
-	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) ;
+	
+	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);
 	}
-	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 ;
-	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_INIT,
+	if (pAC->GIni.GIChipId != 0) {
+		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);
 }
 
 /*
  *	find the Keyword 'key' in the VPD buffer and fills the
- *	parameter sturct 'p' with it's values
+ *	parameter struct 'p' with it's values
  *
  * returns	*p	success
  *		0:	parameter was not found or VPD encoding error
@@ -573,63 +652,64 @@
 char *key,		/* keyword to find (e.g. "MN") */
 SK_VPD_PARA *p)	/* parameter description struct */
 {
-	char *v	;	/* points to vpd buffer */
-	int max ;	/* Maximum Number of Iterations */
+	char *v	;	/* points to VPD buffer */
+	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)) ;
+	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+		("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) ;
-	}
-
-	if (strcmp(key,VPD_NAME) == 0) {
-		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) ;
+	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);
+	}
+
+	if (strcmp(key, VPD_NAME) == 0) {
+		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);
 	}
 
-	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) ;
-			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
-				("found, len = %d\n",p->p_len)) ;
-			return (p) ;
+			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);
 		}
 
 		/* 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 */
-		} else {
-			v += 3 + VPD_GET_VPD_LEN(v) ;
+			v += 3 + VPD_GET_VPD_LEN(v) + 3;	/* skip VPD-W */
 		}
-		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
-			("scanning '%c%c' len = %d\n",v[0],v[1],v[2])) ;
+		else {
+			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]));
 	}
 
 #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")) ;
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+			("Key/Len Encoding error\n"));
 	}
-#endif
-	return (0) ;
+#endif /* DEBUG */
+	return(0);
 }
 
 /*
@@ -643,24 +723,25 @@
 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 ;
+	}
+	else {
+		p = end + n;
 		while (i != 0) {
-			*p-- = *end-- ;
-			i-- ;
+			*p-- = *end--;
+			i--;
 		}
 	}
 }
@@ -676,13 +757,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);
 }
 
 /*
@@ -696,46 +777,50 @@
 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;
+	int	vpd_size;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+		("VPD modify endtag at 0x%x = '%c%c'\n",etp,etp[0],etp[1]));
 
-	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_size = pAC->vpd.vpd_size;
 
-	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) {
+	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 ;
-	} else {
+		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] ;
+		for (i = 0, x = 0; i < vpd_size/2 - p->p_len; 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);
 }
 
 /*
@@ -760,76 +845,81 @@
 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 */
+	int vpd_size;
 
-	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
-		("vpd setup para key = %s, val = %s\n",key,buf)) ;
+	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+		("VPD setup para key = %s, val = %s\n",key,buf));
+	
+	vpd_size = pAC->vpd.vpd_size;
 
-	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) ;
-	} else {
+		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,
+	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 ;
-			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
-				("Overwrite Key\n")) ;
-		} else {
-			op = ADD_KEY ;
-			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,
-				("Add Key\n")) ;
+		if (vpd_find_para(pAC, key, &vp)) {
+			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"));
+		}
+		else {
+			op = ADD_KEY;
+			SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+				("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,
+			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 ;
-		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
-			("VPD Buffer Full, Keyword was cut\n")) ;
+		len = free - 3;
+		rtv = 2;
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+			("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 ;
-		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
-			("VPD Encoding Error\n")) ;
-		return(6) ;
+		pAC->vpd.v.vpd_status &= ~VPD_VALID;
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+			("VPD Encoding Error\n"));
+		return(6);
 	}
 
-	return (rtv) ;
+	return(rtv);
 }
 
 
@@ -837,7 +927,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 contain
+ * return:	A pointer to the vpd_status structure. The structure contains
  *		this fields.
  */
 SK_VPD_STATUS	*VpdStat(
@@ -845,9 +935,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);
 }
 
 
@@ -880,67 +970,69 @@
 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 ;
-			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
-				("VPD Init Error, terminated\n")) ;
-			return(6) ;
+			*len = 0;
+			SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+				("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 ;
-		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX,
-			("'%c%c' ",v[0],v[1])) ;
-	} else {
-		*len = 0 ;
+		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]));
+	}
+	else {
+		*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_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX,
-				("'%c%c' ",v[0],v[1])) ;
-		} else {
-			*len = n ;
-			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
-				("buffer overflow\n")) ;
-			return (2) ;
+			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]));
+		}
+		else {
+			*len = n;
+			SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+				("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);
 }
 
 
@@ -964,34 +1056,35 @@
 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 ;
-			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
-				("vpd init error\n")) ;
-			return(6) ;
+			*len = 0;
+			SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+				("VPD init error\n"));
+			return(6);
 		}
 	}
 
-	if ((p = vpd_find_para(pAC,key,&vp))) {
+	if ((p = vpd_find_para(pAC, key, &vp)) != NULL) {
 		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_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX,
+		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)) ;
-	} else {
-		*len = 0 ;
-		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,("not found\n")) ;
-		return (1) ;
+			buf[0],buf[1],buf[2],buf[3],*len));
 	}
-	return (0) ;
+	else {
+		*len = 0;
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR, ("not found\n"));
+		return(1);
+	}
+	return(0);
 }
 
 
@@ -1009,9 +1102,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);
 }
 
 /*
@@ -1033,46 +1126,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;			/* length 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)) ;
+	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_TX,
+		("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) ;
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+			("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) ;
+			SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+				("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 ;
-		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
-			("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) ;
+		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));
+	}
+	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);
 	}
 
-	return (rtv) ;
+	return(rtv);
 }
 
 /*
@@ -1092,43 +1185,47 @@
 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;
+	int	vpd_size;
 
-	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("vpd delete key %s\n",key)) ;
+	vpd_size = pAC->vpd.vpd_size;
+
+	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) ;
+			SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+				("VPD init error\n"));
+			return(6);
 		}
 	}
 
-	if ((p = vpd_find_para(pAC,key,&vp))) {
-		if (p->p_val < pAC->vpd.vpd_buf + VPD_SIZE/2) {
+	if ((p = vpd_find_para(pAC, key, &vp)) != NULL) {
+		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) ;
+			SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+				("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 ;
-			SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
-				("vpd encoding error\n")) ;
-			return(6) ;
+			pAC->vpd.v.vpd_status &= ~VPD_VALID;
+			SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+				("VPD encoding error\n"));
+			return(6);
 		}
-	} else {
-		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
-			("keyword not found\n")) ;
-		return (1) ;
+	}
+	else {
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+			("keyword not found\n"));
+		return(1);
 	}
 
-	return (0) ;
+	return(0);
 }
 
 /*
@@ -1142,18 +1239,22 @@
 SK_AC		*pAC,	/* Adapters context */
 SK_IOC		IoC)	/* IO Context */
 {
-	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("vpd update .. ")) ;
+	int vpd_size;
+
+	vpd_size = pAC->vpd.vpd_size;
+
+	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) {
+		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) ;
+			SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+				("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);
 }
 
 
@@ -1173,32 +1274,33 @@
 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)) ;
+	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_TX,
+		("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 ;
+			SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+				("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)) != NULL) {
+		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);
 	}
-	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) ;
-	} 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) ;
+	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);
 	}
 
-	(void)VpdUpdate(pAC,IoC) ;
+	(void)VpdUpdate(pAC, IoC);
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sk98lin/skxmac2.c linux-2.4.21-pre6/drivers/net/sk98lin/skxmac2.c
--- linux-2.4.20/drivers/net/sk98lin/skxmac2.c	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sk98lin/skxmac2.c	2003-03-26 23:49:34.000000000 +0000
@@ -2,15 +2,15 @@
  *
  * Name:	skxmac2.c
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.61 $
- * Date:	$Date: 2001/02/09 15:40:59 $
- * Purpose:	Contains functions to initialize the XMAC II
+ * Version:	$Revision: 1.87 $
+ * Date:	$Date: 2002/12/10 14:39:05 $
+ * Purpose:	Contains functions to initialize the MACs and PHYs
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998-2001 SysKonnect GmbH.
+ *	(C)Copyright 1998-2002 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 +26,152 @@
  * History:
  *
  *	$Log: skxmac2.c,v $
+ *	Revision 1.87  2002/12/10 14:39:05  rschmidt
+ *	Improved initialization of GPHY in SkGmInitPhyMarv().
+ *	Editorial changes.
+ *	
+ *	Revision 1.86  2002/12/09 15:01:12  rschmidt
+ *	Added setup of Ext. PHY Specific Ctrl Reg (downshift feature).
+ *	
+ *	Revision 1.85  2002/12/05 14:09:16  rschmidt
+ *	Improved avoiding endless loop in SkGmPhyWrite(), SkGmPhyWrite().
+ *	Added additional advertising for 10Base-T when 100Base-T is selected.
+ *	Added case SK_PHY_MARV_FIBER for YUKON Fiber adapter.
+ *	Editorial changes.
+ *	
+ *	Revision 1.84  2002/11/15 12:50:09  rschmidt
+ *	Changed SkGmCableDiagStatus() when getting results.
+ *	
+ *	Revision 1.83  2002/11/13 10:28:29  rschmidt
+ *	Added some typecasts to avoid compiler warnings.
+ *	
+ *	Revision 1.82  2002/11/13 09:20:46  rschmidt
+ *	Replaced for(..) with do {} while (...) in SkXmUpdateStats().
+ *	Replaced 2 macros GM_IN16() with 1 GM_IN32() in SkGmMacStatistic().
+ *	Added SkGmCableDiagStatus() for Virtual Cable Test (VCT).
+ *	Editorial changes.
+ *	
+ *	Revision 1.81  2002/10/28 14:28:08  rschmidt
+ *	Changed MAC address setup for GMAC in SkGmInitMac().
+ *	Optimized handling of counter overflow IRQ in SkGmOverflowStatus().
+ *	Editorial changes.
+ *	
+ *	Revision 1.80  2002/10/14 15:29:44  rschmidt
+ *	Corrected disabling of all PHY IRQs.
+ *	Added WA for deviation #16 (address used for pause packets).
+ *	Set Pause Mode in SkMacRxTxEnable() only for Genesis.
+ *	Added IRQ and counter for Receive FIFO Overflow in DEBUG-mode.
+ *	SkXmTimeStamp() replaced by SkMacTimeStamp().
+ *	Added clearing of GMAC Tx FIFO Underrun IRQ in SkGmIrq().
+ *	Editorial changes.
+ *	
+ *	Revision 1.79  2002/10/10 15:55:36  mkarl
+ *	changes for PLinkSpeedUsed
+ *	
+ *	Revision 1.78  2002/09/12 09:39:51  rwahl
+ *	Removed deactivate code for SIRQ overflow event separate for TX/RX.
+ *	
+ *	Revision 1.77  2002/09/09 12:26:37  mkarl
+ *	added handling for Yukon to SkXmTimeStamp
+ *	
+ *	Revision 1.76  2002/08/21 16:41:16  rschmidt
+ *	Added bit GPC_ENA_XC (Enable MDI crossover) in HWCFG_MODE.
+ *	Added forced speed settings in SkGmInitPhyMarv().
+ *	Added settings of full/half duplex capabilities for YUKON Fiber.
+ *	Editorial changes.
+ *	
+ *	Revision 1.75  2002/08/16 15:12:01  rschmidt
+ *	Replaced all if(GIChipId == CHIP_ID_GENESIS) with new entry GIGenesis.
+ *	Added function SkMacHashing() for ADDR-Module.
+ *	Removed functions SkXmClrSrcCheck(), SkXmClrHashAddr() (calls replaced
+ *	with macros).
+ *	Removed functions SkGmGetMuxConfig().
+ *	Added HWCFG_MODE init for YUKON Fiber.
+ *	Changed initialization of GPHY in SkGmInitPhyMarv().
+ *	Changed check of parameter in SkXmMacStatistic().
+ *	Editorial changes.
+ *	
+ *	Revision 1.74  2002/08/12 14:00:17  rschmidt
+ *	Replaced usage of Broadcom PHY Ids with defines.
+ *	Corrected error messages in SkGmMacStatistic().
+ *	Made SkMacPromiscMode() public for ADDR-Modul.
+ *	Editorial changes.
+ *	
+ *	Revision 1.73  2002/08/08 16:26:24  rschmidt
+ *	Improved reset sequence for YUKON in SkGmHardRst() and SkGmInitMac().
+ *	Replaced XMAC Rx High Watermark init value with SK_XM_RX_HI_WM.
+ *	Editorial changes.
+ *	
+ *	Revision 1.72  2002/07/24 15:11:19  rschmidt
+ *	Fixed wrong placement of parenthesis.
+ *	Editorial changes.
+ *	
+ *	Revision 1.71  2002/07/23 16:05:18  rschmidt
+ *	Added global functions for PHY: SkGePhyRead(), SkGePhyWrite().
+ *	Fixed Tx Counter Overflow IRQ (Bug ID #10730).
+ *	Editorial changes.
+ *	
+ *	Revision 1.70  2002/07/18 14:27:27  rwahl
+ *	Fixed syntax error.
+ *	
+ *	Revision 1.69  2002/07/17 17:08:47  rwahl
+ *	Fixed check in SkXmMacStatistic().
+ *	
+ *	Revision 1.68  2002/07/16 07:35:24  rwahl
+ *	Removed check for cleared mib counter in SkGmResetCounter().
+ *	
+ *	Revision 1.67  2002/07/15 18:35:56  rwahl
+ *	Added SkXmUpdateStats(), SkGmUpdateStats(), SkXmMacStatistic(),
+ *	  SkGmMacStatistic(), SkXmResetCounter(), SkGmResetCounter(),
+ *	  SkXmOverflowStatus(), SkGmOverflowStatus().
+ *	Changes to SkXmIrq() & SkGmIrq(): Combined SIRQ Overflow for both
+ *	  RX & TX.
+ *	Changes to SkGmInitMac(): call to SkGmResetCounter().
+ *	Editorial changes.
+ *	
+ *	Revision 1.66  2002/07/15 15:59:30  rschmidt
+ *	Added PHY Address in SkXmPhyRead(), SkXmPhyWrite().
+ *	Added MIB Clear Counter in SkGmInitMac().
+ *	Added Duplex and Flow-Control settings.
+ *	Reset all Multicast filtering Hash reg. in SkGmInitMac().
+ *	Added new function: SkGmGetMuxConfig().
+ *	Editorial changes.
+ *	
+ *	Revision 1.65  2002/06/10 09:35:39  rschmidt
+ *	Replaced C++ comments (//).
+ *	Added #define VCPU around VCPUwaitTime.
+ *	Editorial changes.
+ *	
+ *	Revision 1.64  2002/06/05 08:41:10  rschmidt
+ *	Added function for XMAC2: SkXmTimeStamp().
+ *	Added function for YUKON: SkGmSetRxCmd().
+ *	Changed SkGmInitMac() resp. SkGmHardRst().
+ *	Fixed wrong variable in SkXmAutoNegLipaXmac() (debug mode).
+ *	SkXmRxTxEnable() replaced by SkMacRxTxEnable().
+ *	Editorial changes.
+ *	
+ *	Revision 1.63  2002/04/25 13:04:44  rschmidt
+ *	Changes for handling YUKON.
+ *	Use of #ifdef OTHER_PHY to eliminate code for unused Phy types.
+ *	Macros for XMAC PHY access PHY_READ(), PHY_WRITE() replaced
+ *	by functions SkXmPhyRead(), SkXmPhyWrite();
+ *	Removed use of PRxCmd to setup XMAC.
+ *	Added define PHY_B_AS_PAUSE_MSK for BCom Pause Res.
+ *	Added setting of XM_RX_DIS_CEXT in SkXmInitMac().
+ *	Removed status parameter from MAC IRQ handler SkMacIrq(),
+ *	SkXmIrq() and SkGmIrq().
+ *	SkXmAutoNegLipa...() for ext. Phy replaced by SkMacAutoNegLipaPhy().
+ *	Added SkMac...() functions to handle both XMAC and GMAC.
+ *	Added functions for YUKON: SkGmHardRst(), SkGmSoftRst(),
+ *	SkGmSetRxTxEn(), SkGmIrq(), SkGmInitMac(), SkGmInitPhyMarv(),
+ *	SkGmAutoNegDoneMarv(), SkGmPhyRead(), SkGmPhyWrite().
+ *	Changes for V-CPU support.
+ *	Editorial changes.
+ *	
+ *	Revision 1.62  2001/08/06 09:50:14  rschmidt
+ *	Workaround BCOM Errata #1 for the C5 type.
+ *	Editorial changes.
+ *	
  *	Revision 1.61  2001/02/09 15:40:59  rassmann
  *	Editorial changes.
  *	
@@ -194,7 +340,7 @@
  *
  *	Revision 1.12  1998/10/14 14:45:04  malthoff
  *	Remove SKERR_SIRQ_E0xx and SKERR_SIRQ_E0xxMSG by
- *	SKERR_HWI_Exx and SKERR_HWI_E0xxMSG to be independant
+ *	SKERR_HWI_Exx and SKERR_HWI_E0xxMSG to be independent
  *	from the Sirq module.
  *
  *	Revision 1.11  1998/10/14 13:59:01  gklug
@@ -203,17 +349,16 @@
  *	Revision 1.10  1998/10/14 11:20:57  malthoff
  *	Make SkXmAutoNegDone() public, because it's
  *	used in diagnostics, too.
- *	The Link Up event to the RLMT is issued in
- *	SkXmIrq(). SkXmIrq() is not available in
- *	diagnostics. Use PHY_READ when reading
- *	PHY registers.
+ *	The Link Up event to the RLMT is issued in SkXmIrq().
+ *  SkXmIrq() is not available in diagnostics.
+ *  Use PHY_READ when reading PHY registers.
  *
  *	Revision 1.9  1998/10/14 05:50:10  cgoos
  *	Added definition for Para.
  *
  *	Revision 1.8  1998/10/14 05:41:28  gklug
  *	add: Xmac IRQ
- *	add: auto negotiation done function
+ *	add: auto-negotiation done function
  *
  *	Revision 1.7  1998/10/09 06:55:20  malthoff
  *	The configuration of the XMACs Tx Request Threshold
@@ -246,17 +391,9 @@
  ******************************************************************************/
 
 #include "h/skdrv1st.h"
-#include "h/xmac_ii.h"
 #include "h/skdrv2nd.h"
 
-/* defines ********************************************************************/
 /* typedefs *******************************************************************/
-/* global variables ***********************************************************/
-
-/* local variables ************************************************************/
-
-static const char SysKonnectFileId[] =
-	"@(#)$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 {
@@ -264,6 +401,10 @@
 	SK_U16	PhyVal;		/* Value to write */
 } BCOM_HACK;
 
+/* local variables ************************************************************/
+static const char SysKonnectFileId[] =
+	"@(#)$Id: skxmac2.c,v 1.87 2002/12/10 14:39:05 rschmidt Exp $ (C) SK ";
+
 BCOM_HACK BcomRegA1Hack[] = {
  { 0x18, 0x0c20 }, { 0x17, 0x0012 }, { 0x15, 0x1104 }, { 0x17, 0x0013 },
  { 0x15, 0x0404 }, { 0x17, 0x8006 }, { 0x15, 0x0132 }, { 0x17, 0x8006 },
@@ -279,308 +420,797 @@
 /* function prototypes ********************************************************/
 static void	SkXmInitPhyXmac(SK_AC*, SK_IOC, int, SK_BOOL);
 static void	SkXmInitPhyBcom(SK_AC*, SK_IOC, int, SK_BOOL);
-static void	SkXmInitPhyLone(SK_AC*, SK_IOC, int, SK_BOOL);
-static void	SkXmInitPhyNat (SK_AC*, SK_IOC, int, SK_BOOL);
+static void	SkGmInitPhyMarv(SK_AC*, SK_IOC, int, SK_BOOL);
 static int	SkXmAutoNegDoneXmac(SK_AC*, SK_IOC, int);
 static int	SkXmAutoNegDoneBcom(SK_AC*, SK_IOC, int);
+static int	SkGmAutoNegDoneMarv(SK_AC*, SK_IOC, int);
+#ifdef OTHER_PHY
+static void	SkXmInitPhyLone(SK_AC*, SK_IOC, int, SK_BOOL);
+static void	SkXmInitPhyNat (SK_AC*, SK_IOC, int, SK_BOOL);
 static int	SkXmAutoNegDoneLone(SK_AC*, SK_IOC, int);
 static int	SkXmAutoNegDoneNat (SK_AC*, SK_IOC, int);
+#endif /* OTHER_PHY */
+
+
 
 /******************************************************************************
  *
- *	SkXmSetRxCmd() - Modify the value of the XMACs Rx Command Register
+ *	SkXmPhyRead() - Read from XMAC PHY register
  *
- * Description:
- *	The features
- *	 o FCS stripping,			SK_STRIP_FCS_ON/OFF
- *	 o pad byte stripping,			SK_STRIP_PAD_ON/OFF
- *	 o don't set XMR_FS_ERR in frame	SK_LENERR_OK_ON/OFF
- *	   status for inrange length error
- *	   frames, and
- *	 o don't set XMR_FS_ERR in frame	SK_BIG_PK_OK_ON/OFF
- *	   status for frames > 1514 bytes
- *
- *	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
- *	and is written to the Receive Command register immediatlely.
- *	The new configuration is saved over any SkGePortStop() and
- *	SkGeInitPort() calls. The configured value will be overwritten
- *	when SkGeInit(Level 0) is executed.
+ * Description:	reads a 16-bit word from XMAC PHY or ext. PHY
  *
  * Returns:
  *	nothing
  */
-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 */
+void SkXmPhyRead(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* I/O Context */
+int		Port,		/* Port Index (MAC_1 + n) */
+int		PhyReg,		/* Register Address (Offset) */
+SK_U16	*pVal)		/* Pointer to Value */
 {
+	SK_U16		Mmu;
 	SK_GEPORT	*pPrt;
-	SK_U16		OldRxMode;
 
 	pPrt = &pAC->GIni.GP[Port];
-	OldRxMode = pPrt->PRxCmd;
+	
+	/* write the PHY register's address */
+	XM_OUT16(IoC, Port, XM_PHY_ADDR, PhyReg | pPrt->PhyAddr);
+	
+	/* get the PHY register's value */
+	XM_IN16(IoC, Port, XM_PHY_DATA, pVal);
+	
+	if (pPrt->PhyType != SK_PHY_XMAC) {
+		do {
+			XM_IN16(IoC, Port, XM_MMU_CMD, &Mmu);
+			/* wait until 'Ready' is set */
+		} while ((Mmu & XM_MMU_PHY_RDY) == 0);
 
-	switch(Mode & (SK_STRIP_FCS_ON | SK_STRIP_FCS_OFF)) {
-	case SK_STRIP_FCS_ON:
-		pPrt->PRxCmd |= XM_RX_STRIP_FCS;
-		break;
-	case SK_STRIP_FCS_OFF:
-		pPrt->PRxCmd &= ~XM_RX_STRIP_FCS;
-		break;
+		/* get the PHY register's value */
+		XM_IN16(IoC, Port, XM_PHY_DATA, pVal);
 	}
+}	/* SkXmPhyRead */
 
-	switch(Mode & (SK_STRIP_PAD_ON | SK_STRIP_PAD_OFF)) {
-	case SK_STRIP_PAD_ON:
-		pPrt->PRxCmd |= XM_RX_STRIP_PAD;
-		break;
-	case SK_STRIP_PAD_OFF:
-		pPrt->PRxCmd &= ~XM_RX_STRIP_PAD;
-		break;
-	}
 
-	switch(Mode & (SK_LENERR_OK_ON | SK_LENERR_OK_OFF)) {
-	case SK_LENERR_OK_ON:
-		pPrt->PRxCmd |= XM_RX_LENERR_OK;
-		break;
-	case SK_LENERR_OK_OFF:
-		pPrt->PRxCmd &= ~XM_RX_LENERR_OK;
-		break;
-	}
+/******************************************************************************
+ *
+ *	SkXmPhyWrite() - Write to XMAC PHY register
+ *
+ * Description:	writes a 16-bit word to XMAC PHY or ext. PHY
+ *
+ * Returns:
+ *	nothing
+ */
+void SkXmPhyWrite(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* I/O Context */
+int		Port,		/* Port Index (MAC_1 + n) */
+int		PhyReg,		/* Register Address (Offset) */
+SK_U16	Val)		/* Value */
+{
+	SK_U16		Mmu;
+	SK_GEPORT	*pPrt;
 
-	switch(Mode & (SK_BIG_PK_OK_ON | SK_BIG_PK_OK_OFF)) {
-	case SK_BIG_PK_OK_ON:
-		pPrt->PRxCmd |= XM_RX_BIG_PK_OK;
-		break;
-	case SK_BIG_PK_OK_OFF:
-		pPrt->PRxCmd &= ~XM_RX_BIG_PK_OK;
-		break;
+	pPrt = &pAC->GIni.GP[Port];
+	
+	if (pPrt->PhyType != SK_PHY_XMAC) {
+		do {
+			XM_IN16(IoC, Port, XM_MMU_CMD, &Mmu);
+			/* wait until 'Busy' is cleared */
+		} while ((Mmu & XM_MMU_PHY_BUSY) != 0);
 	}
-
-	/* Write the new mode to the receive command register if required */
-	if (OldRxMode != pPrt->PRxCmd) {
-		XM_OUT16(IoC, Port, XM_RX_CMD, pPrt->PRxCmd);
+	
+	/* write the PHY register's address */
+	XM_OUT16(IoC, Port, XM_PHY_ADDR, PhyReg | pPrt->PhyAddr);
+	
+	/* write the PHY register's value */
+	XM_OUT16(IoC, Port, XM_PHY_DATA, Val);
+	
+	if (pPrt->PhyType != SK_PHY_XMAC) {
+		do {
+			XM_IN16(IoC, Port, XM_MMU_CMD, &Mmu);
+			/* wait until 'Busy' is cleared */
+		} while ((Mmu & XM_MMU_PHY_BUSY) != 0);
 	}
-}	/* SkXmSetRxCmd*/
+}	/* SkXmPhyWrite */
 
 
 /******************************************************************************
  *
- *	SkXmClrExactAddr() - Clear Exact Match Address Registers
+ *	SkGmPhyRead() - Read from GPHY register
  *
- * Description:
- *	All Exact Match Address registers of the XMAC 'Port' will be
- *	cleared starting with 'StartNum' up to (and including) the
- *	Exact Match address number of 'StopNum'.
+ * Description:	reads a 16-bit word from GPHY through MDIO
  *
  * Returns:
  *	nothing
  */
-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) */
+void SkGmPhyRead(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* I/O Context */
+int		Port,		/* Port Index (MAC_1 + n) */
+int		PhyReg,		/* Register Address (Offset) */
+SK_U16	*pVal)		/* Pointer to Value */
 {
-	int		i;
-	SK_U16	ZeroAddr[3] = {0x0000, 0x0000, 0x0000};
+	SK_U16	Ctrl;
+	SK_GEPORT	*pPrt;
+#ifdef VCPU
+	u_long SimCyle;
+	u_long SimLowTime;
+	
+	VCPUgetTime(&SimCyle, &SimLowTime);
+	VCPUprintf(0, "SkGmPhyRead(%u), SimCyle=%u, SimLowTime=%u\n",
+		PhyReg, SimCyle, SimLowTime);
+#endif /* VCPU */
+	
+	pPrt = &pAC->GIni.GP[Port];
+	
+	/* set PHY-Register offset and 'Read' OpCode (= 1) */
+	*pVal = GM_SMI_CT_PHY_AD(pPrt->PhyAddr) | GM_SMI_CT_REG_AD(PhyReg) |
+		GM_SMI_CT_OP_RD;
 
-	if ((unsigned)StartNum > 15 || (unsigned)StopNum > 15 ||
-		StartNum > StopNum) {
+	GM_OUT16(IoC, Port, GM_SMI_CTRL, *pVal);
 
-		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E001, SKERR_HWI_E001MSG);
+	GM_IN16(IoC, Port, GM_SMI_CTRL, &Ctrl);
+	
+	/* additional check for MDC/MDIO activity */
+	if ((Ctrl & GM_SMI_CT_BUSY) == 0) {
+		*pVal = 0;
 		return;
 	}
 
-	for (i = StartNum; i <= StopNum; i++) {
-		XM_OUTADDR(IoC, Port, XM_EXM(i), &ZeroAddr[0]);
+	*pVal |= GM_SMI_CT_BUSY;
+	
+	do {
+#ifdef VCPU
+		VCPUwaitTime(1000);
+#endif /* VCPU */
+
+		GM_IN16(IoC, Port, GM_SMI_CTRL, &Ctrl);
+
+	/* wait until 'ReadValid' is set */
+	} while (Ctrl == *pVal);
+	
+	/* get the PHY register's value */
+	GM_IN16(IoC, Port, GM_SMI_DATA, pVal);
+
+#ifdef VCPU
+	VCPUgetTime(&SimCyle, &SimLowTime);
+	VCPUprintf(0, "VCPUgetTime(), SimCyle=%u, SimLowTime=%u\n",
+		SimCyle, SimLowTime);
+#endif /* VCPU */
+}	/* SkGmPhyRead */
+
+
+/******************************************************************************
+ *
+ *	SkGmPhyWrite() - Write to GPHY register
+ *
+ * Description:	writes a 16-bit word to GPHY through MDIO
+ *
+ * Returns:
+ *	nothing
+ */
+void SkGmPhyWrite(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* I/O Context */
+int		Port,		/* Port Index (MAC_1 + n) */
+int		PhyReg,		/* Register Address (Offset) */
+SK_U16	Val)		/* Value */
+{
+	SK_U16	Ctrl;
+	SK_GEPORT	*pPrt;
+#ifdef VCPU
+	SK_U32	DWord;
+	u_long	SimCyle;
+	u_long	SimLowTime;
+	
+	VCPUgetTime(&SimCyle, &SimLowTime);
+	VCPUprintf(0, "SkGmPhyWrite(Reg=%u, Val=0x%04x), SimCyle=%u, SimLowTime=%u\n",
+		PhyReg, Val, SimCyle, SimLowTime);
+#endif /* VCPU */
+	
+	pPrt = &pAC->GIni.GP[Port];
+	
+	/* write the PHY register's value */
+	GM_OUT16(IoC, Port, GM_SMI_DATA, Val);
+	
+	/* set PHY-Register offset and 'Write' OpCode (= 0) */
+	Val = GM_SMI_CT_PHY_AD(pPrt->PhyAddr) | GM_SMI_CT_REG_AD(PhyReg);
+
+	GM_OUT16(IoC, Port, GM_SMI_CTRL, Val);
+
+	GM_IN16(IoC, Port, GM_SMI_CTRL, &Ctrl);
+	
+	/* additional check for MDC/MDIO activity */
+	if ((Ctrl & GM_SMI_CT_BUSY) == 0) {
+		return;
 	}
-}	/* SkXmClrExactAddr */
+	
+	Val |= GM_SMI_CT_BUSY;
+
+	do {
+#ifdef VCPU
+		/* read Timer value */
+		SK_IN32(IoC, B2_TI_VAL, &DWord);
+
+		VCPUwaitTime(1000);
+#endif /* VCPU */
+
+		GM_IN16(IoC, Port, GM_SMI_CTRL, &Ctrl);
+
+	/* wait until 'Busy' is cleared */
+	} while (Ctrl == Val);
+	
+#ifdef VCPU
+	VCPUgetTime(&SimCyle, &SimLowTime);
+	VCPUprintf(0, "VCPUgetTime(), SimCyle=%u, SimLowTime=%u\n",
+		SimCyle, SimLowTime);
+#endif /* VCPU */
+}	/* SkGmPhyWrite */
 
 
 /******************************************************************************
  *
- *	SkXmClrSrcCheck() - Clear Source Check Address Register
+ *	SkGePhyRead() - Read from PHY register
  *
- * Description:
- *	The Source Check Address Register of the XMAC 'Port' number
- *	will be cleared.
+ * Description:	calls a read PHY routine dep. on board type
  *
  * Returns:
  *	nothing
  */
-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) */
+void SkGePhyRead(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* I/O Context */
+int		Port,		/* Port Index (MAC_1 + n) */
+int		PhyReg,		/* Register Address (Offset) */
+SK_U16	*pVal)		/* Pointer to Value */
 {
-	SK_U16	ZeroAddr[3] = {0x0000, 0x0000, 0x0000};
+	void (*r_func)(SK_AC *pAC, SK_IOC IoC, int Port, int Reg, SK_U16 *pVal);
 
-	XM_OUTHASH(IoC, Port, XM_SRC_CHK, &ZeroAddr);
-}	/* SkXmClrSrcCheck */
+	if (pAC->GIni.GIGenesis) {
+		r_func = SkXmPhyRead;
+	}
+	else {
+		r_func = SkGmPhyRead;
+	}
+	
+	r_func(pAC, IoC, Port, PhyReg, pVal);
+}	/* SkGePhyRead */
 
 
 /******************************************************************************
  *
- *	SkXmClrHashAddr() - Clear Hash Address Registers
+ *	SkGePhyWrite() - Write to PHY register
  *
- * Description:
- *	The Hash Address Register of the XMAC 'Port' will be cleared.
+ * Description:	calls a write PHY routine dep. on board type
  *
  * Returns:
  *	nothing
  */
-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) */
+void SkGePhyWrite(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* I/O Context */
+int		Port,		/* Port Index (MAC_1 + n) */
+int		PhyReg,		/* Register Address (Offset) */
+SK_U16	Val)		/* Value */
 {
-	SK_U16	ZeroAddr[4] = {0x0000, 0x0000, 0x0000, 0x0000};
+	void (*w_func)(SK_AC *pAC, SK_IOC IoC, int Port, int Reg, SK_U16 Val);
 
-	XM_OUTHASH(IoC, Port, XM_HSM, &ZeroAddr);
-}	/* SkXmClrHashAddr*/
+	if (pAC->GIni.GIGenesis) {
+		w_func = SkXmPhyWrite;
+	}
+	else {
+		w_func = SkGmPhyWrite;
+	}
+	
+	w_func(pAC, IoC, Port, PhyReg, Val);
+}	/* SkGePhyWrite */
 
 
 /******************************************************************************
  *
- *	SkXmFlushTxFifo() - Flush the XMACs transmit FIFO
+ *	SkMacPromiscMode() - Enable / Disable Promiscuous Mode
  *
  * Description:
- *	Flush the transmit FIFO of the XMAC specified by the index 'Port'
+ *   enables / disables promiscuous mode by setting Mode Register (XMAC) or
+ *   Receive Control Register (GMAC) dep. on board type   	
  *
  * Returns:
  *	nothing
  */
-void SkXmFlushTxFifo(
+void SkMacPromiscMode(
 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,	/* Port Index (MAC_1 + n) */
+SK_BOOL	Enable)	/* Enable / Disable */
 {
+	SK_U16	RcReg;
 	SK_U32	MdReg;
 
-	XM_IN32(IoC, Port, XM_MODE, &MdReg);
-	MdReg |= XM_MD_FTF;
-	XM_OUT32(IoC, Port, XM_MODE, MdReg);
-}	/* SkXmFlushTxFifo */
+	if (pAC->GIni.GIGenesis) {
+		
+		XM_IN32(IoC, Port, XM_MODE, &MdReg);
+		/* enable or disable promiscuous mode */
+		if (Enable) {
+			MdReg |= XM_MD_ENA_PROM;
+		}
+		else {
+			MdReg &= ~XM_MD_ENA_PROM;
+		}
+		/* setup Mode Register */
+		XM_OUT32(IoC, Port, XM_MODE, MdReg);
+	}
+	else {
+		
+		GM_IN16(IoC, Port, GM_RX_CTRL, &RcReg);
+		
+		/* enable or disable unicast and multicast filtering */
+		if (Enable) {
+			RcReg &= ~(GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA);
+		}
+		else {
+			RcReg |= (GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA);
+		}
+		/* setup Receive Control Register */
+		GM_OUT16(IoC, Port, GM_RX_CTRL, RcReg);
+	}
+}	/* SkMacPromiscMode*/
 
 
 /******************************************************************************
  *
- *	SkXmFlushRxFifo() - Flush the XMACs receive FIFO
+ *	SkMacHashing() - Enable / Disable Hashing
  *
  * Description:
- *	Flush the receive FIFO of the XMAC specified by the index 'Port'
+ *   enables / disables hashing by setting Mode Register (XMAC) or
+ *   Receive Control Register (GMAC) dep. on board type		
  *
  * Returns:
  *	nothing
  */
-void SkXmFlushRxFifo(
+void SkMacHashing(
 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,	/* Port Index (MAC_1 + n) */
+SK_BOOL	Enable)	/* Enable / Disable */
 {
+	SK_U16	RcReg;
 	SK_U32	MdReg;
 
-	XM_IN32(IoC, Port, XM_MODE, &MdReg);
-	MdReg |= XM_MD_FRF;
-	XM_OUT32(IoC, Port, XM_MODE, MdReg);
-}	/* SkXmFlushRxFifo*/
+	if (pAC->GIni.GIGenesis) {
+		
+		XM_IN32(IoC, Port, XM_MODE, &MdReg);
+		/* enable or disable hashing */
+		if (Enable) {
+			MdReg |= XM_MD_ENA_HASH;
+		}
+		else {
+			MdReg &= ~XM_MD_ENA_HASH;
+		}
+		/* setup Mode Register */
+		XM_OUT32(IoC, Port, XM_MODE, MdReg);
+	}
+	else {
+		
+		GM_IN16(IoC, Port, GM_RX_CTRL, &RcReg);
+		
+		/* enable or disable multicast filtering */
+		if (Enable) {
+			RcReg |= GM_RXCR_MCF_ENA;
+		}
+		else {
+			RcReg &= ~GM_RXCR_MCF_ENA;
+		}
+		/* setup Receive Control Register */
+		GM_OUT16(IoC, Port, GM_RX_CTRL, RcReg);
+	}
+}	/* SkMacHashing*/
 
 
+#ifdef SK_DIAG
 /******************************************************************************
  *
- *	SkXmSoftRst() - Do a XMAC software reset
+ *	SkXmSetRxCmd() - Modify the value of the XMAC's Rx Command Register
  *
  * Description:
- *	The PHY registers should not be destroyed during this
- *	kind of software reset. Therefore the XMAC Software Reset
- *	(XM_GP_RES_MAC bit in XM_GP_PORT) must not be used!
- *
- *	The software reset is done by
- *		- disabling the Rx and Tx state maschine,
- *		- reseting the statistics module,
- *		- clear all other significant XMAC Mode,
- *		  Command, and Control Registers
- *		- clearing the Hash Register and the
- *		  Exact Match Address registers, and
- *		- flushing the XMAC's Rx and Tx FIFOs.
- *
- * Note:
- *	Another requirement when stopping the XMAC is to
- *	avoid sending corrupted frames on the network.
- *	Disabling the Tx state maschine will NOT interrupt
- *	the currently transmitted frame. But we must take care
- *	that the tx FIFO is cleared AFTER the current frame
- *	is complete sent to the network.
+ *	The features
+ *	 - FCS stripping,					SK_STRIP_FCS_ON/OFF
+ *	 - pad byte stripping,				SK_STRIP_PAD_ON/OFF
+ *	 - don't set XMR_FS_ERR in status	SK_LENERR_OK_ON/OFF
+ *	   for inrange length error frames
+ *	 - don't set XMR_FS_ERR in status	SK_BIG_PK_OK_ON/OFF
+ *	   for frames > 1514 bytes
+ *   - enable Rx of own packets         SK_SELF_RX_ON/OFF
  *
- *	It takes about 12ns to send a frame with 1538 bytes.
- *	One PCI clock goes at least 15ns (66MHz). Therefore
- *	after reading XM_GP_PORT back, we are sure that the
- *	transmitter is disabled AND idle. And this means
- *	we may flush the transmit FIFO now.
+ *	for incoming 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 written to the Rx Command register immediately.
  *
  * Returns:
  *	nothing
  */
-void SkXmSoftRst(
-SK_AC	*pAC,	/* adapter context */
-SK_IOC	IoC,	/* IO context */
-int		Port)	/* port to stop (MAC_1 + n) */
+static void SkXmSetRxCmd(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port,		/* Port Index (MAC_1 + n) */
+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		Word;
+	SK_U16	OldRxCmd;
+	SK_U16	RxCmd;
 
-	pPrt = &pAC->GIni.GP[Port];
-
-	/* disable the 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));
-
-	/* reset the statistics module */
-	XM_OUT32(IoC, Port, XM_GP_PORT, XM_GP_RES_STAT);
+	XM_IN16(IoC, Port, XM_RX_CMD, &OldRxCmd);
 
-	/*
-	 * clear all other significant XMAC Mode,
-	 * Command, and Control Registers
-	 */
-	XM_OUT16(IoC, Port, XM_IMSK, 0xffff);		/* disable all IRQs */
-	XM_OUT32(IoC, Port, XM_MODE, 0x00000000);	/* clear Mode Reg */
-	XM_OUT16(IoC, Port, XM_TX_CMD, 0x0000);		/* reset TX CMD Reg */
-	XM_OUT16(IoC, Port, XM_RX_CMD, 0x0000);		/* reset RX CMD Reg */
+	RxCmd = OldRxCmd;
+	
+	switch (Mode & (SK_STRIP_FCS_ON | SK_STRIP_FCS_OFF)) {
+	case SK_STRIP_FCS_ON:
+		RxCmd |= XM_RX_STRIP_FCS;
+		break;
+	case SK_STRIP_FCS_OFF:
+		RxCmd &= ~XM_RX_STRIP_FCS;
+		break;
+	}
+
+	switch (Mode & (SK_STRIP_PAD_ON | SK_STRIP_PAD_OFF)) {
+	case SK_STRIP_PAD_ON:
+		RxCmd |= XM_RX_STRIP_PAD;
+		break;
+	case SK_STRIP_PAD_OFF:
+		RxCmd &= ~XM_RX_STRIP_PAD;
+		break;
+	}
+
+	switch (Mode & (SK_LENERR_OK_ON | SK_LENERR_OK_OFF)) {
+	case SK_LENERR_OK_ON:
+		RxCmd |= XM_RX_LENERR_OK;
+		break;
+	case SK_LENERR_OK_OFF:
+		RxCmd &= ~XM_RX_LENERR_OK;
+		break;
+	}
+
+	switch (Mode & (SK_BIG_PK_OK_ON | SK_BIG_PK_OK_OFF)) {
+	case SK_BIG_PK_OK_ON:
+		RxCmd |= XM_RX_BIG_PK_OK;
+		break;
+	case SK_BIG_PK_OK_OFF:
+		RxCmd &= ~XM_RX_BIG_PK_OK;
+		break;
+	}
+
+	switch (Mode & (SK_SELF_RX_ON | SK_SELF_RX_OFF)) {
+	case SK_SELF_RX_ON:
+		RxCmd |= XM_RX_SELF_RX;
+		break;
+	case SK_SELF_RX_OFF:
+		RxCmd &= ~XM_RX_SELF_RX;
+		break;
+	}
+
+	/* Write the new mode to the Rx command register if required */
+	if (OldRxCmd != RxCmd) {
+		XM_OUT16(IoC, Port, XM_RX_CMD, RxCmd);
+	}
+}	/* SkXmSetRxCmd */
+
+
+/******************************************************************************
+ *
+ *	SkGmSetRxCmd() - Modify the value of the GMAC's Rx Control Register
+ *
+ * Description:
+ *	The features
+ *	 - FCS (CRC) stripping,				SK_STRIP_FCS_ON/OFF
+ *	 - don't set XMR_FS_ERR in status	SK_BIG_PK_OK_ON/OFF
+ *	   for frames > 1514 bytes
+ *   - enable Rx of own packets         SK_SELF_RX_ON/OFF
+ *
+ *	for incoming 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 written to the Rx Command register immediately.
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkGmSetRxCmd(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port,		/* Port Index (MAC_1 + n) */
+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_U16	OldRxCmd;
+	SK_U16	RxCmd;
+
+	if ((Mode & (SK_STRIP_FCS_ON | SK_STRIP_FCS_OFF)) != 0) {
+		
+		GM_IN16(IoC, Port, GM_RX_CTRL, &OldRxCmd);
+
+		RxCmd = OldRxCmd;
+
+		if ((Mode & SK_STRIP_FCS_ON) != 0) {
+			RxCmd |= GM_RXCR_CRC_DIS;
+		}
+		else {
+			RxCmd &= ~GM_RXCR_CRC_DIS;
+		}
+		/* Write the new mode to the Rx control register if required */
+		if (OldRxCmd != RxCmd) {
+			GM_OUT16(IoC, Port, GM_RX_CTRL, RxCmd);
+		}
+	}
+
+	if ((Mode & (SK_BIG_PK_OK_ON | SK_BIG_PK_OK_OFF)) != 0) {
+		
+		GM_IN16(IoC, Port, GM_SERIAL_MODE, &OldRxCmd);
+
+		RxCmd = OldRxCmd;
+
+		if ((Mode & SK_BIG_PK_OK_ON) != 0) {
+			RxCmd |= GM_SMOD_JUMBO_ENA;
+		}
+		else {
+			RxCmd &= ~GM_SMOD_JUMBO_ENA;
+		}
+		/* Write the new mode to the Rx control register if required */
+		if (OldRxCmd != RxCmd) {
+			GM_OUT16(IoC, Port, GM_SERIAL_MODE, RxCmd);
+		}
+	}
+}	/* SkGmSetRxCmd */
+
+
+/******************************************************************************
+ *
+ *	SkMacSetRxCmd() - Modify the value of the MAC's Rx Control Register
+ *
+ * Description:	modifies the MAC's Rx Control reg. dep. on board type
+ *
+ * Returns:
+ *	nothing
+ */
+void SkMacSetRxCmd(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port,		/* Port Index (MAC_1 + n) */
+int		Mode)		/* Rx Mode */
+{
+	if (pAC->GIni.GIGenesis) {
+		
+		SkXmSetRxCmd(pAC, IoC, Port, Mode);
+	}
+	else {
+		
+		SkGmSetRxCmd(pAC, IoC, Port, Mode);
+	}
+}	/* SkMacSetRxCmd */
+
+
+/******************************************************************************
+ *
+ *	SkMacCrcGener() - Enable / Disable CRC Generation
+ *
+ * Description:	enables / disables CRC generation dep. on board type
+ *
+ * Returns:
+ *	nothing
+ */
+void SkMacCrcGener(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port,	/* Port Index (MAC_1 + n) */
+SK_BOOL	Enable)	/* Enable / Disable */
+{
+	SK_U16	Word;
+
+	if (pAC->GIni.GIGenesis) {
+		
+		XM_IN16(IoC, Port, XM_TX_CMD, &Word);
+
+		if (Enable) {
+			Word &= ~XM_TX_NO_CRC;
+		}
+		else {
+			Word |= XM_TX_NO_CRC;
+		}
+		/* setup Tx Command Register */
+		XM_OUT16(pAC, Port, XM_TX_CMD, Word);
+	}
+	else {
+		
+		GM_IN16(IoC, Port, GM_TX_CTRL, &Word);
+		
+		if (Enable) {
+			Word &= ~GM_TXCR_CRC_DIS;
+		}
+		else {
+			Word |= GM_TXCR_CRC_DIS;
+		}
+		/* setup Tx Control Register */
+		GM_OUT16(IoC, Port, GM_TX_CTRL, Word);
+	}
+}	/* SkMacCrcGener*/
+
+#endif /* SK_DIAG */
+
+
+/******************************************************************************
+ *
+ *	SkXmClrExactAddr() - Clear Exact Match Address Registers
+ *
+ * Description:
+ *	All Exact Match Address registers of the XMAC 'Port' will be
+ *	cleared starting with 'StartNum' up to (and including) the
+ *	Exact Match address number of 'StopNum'.
+ *
+ * Returns:
+ *	nothing
+ */
+void SkXmClrExactAddr(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port,		/* Port Index (MAC_1 + n) */
+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};
+
+	if ((unsigned)StartNum > 15 || (unsigned)StopNum > 15 ||
+		StartNum > StopNum) {
+
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E001, SKERR_HWI_E001MSG);
+		return;
+	}
+
+	for (i = StartNum; i <= StopNum; i++) {
+		XM_OUTADDR(IoC, Port, XM_EXM(i), &ZeroAddr[0]);
+	}
+}	/* SkXmClrExactAddr */
+
+
+/******************************************************************************
+ *
+ *	SkMacFlushTxFifo() - Flush the MAC's transmit FIFO
+ *
+ * Description:
+ *	Flush the transmit FIFO of the MAC specified by the index 'Port'
+ *
+ * Returns:
+ *	nothing
+ */
+void SkMacFlushTxFifo(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port)	/* Port Index (MAC_1 + n) */
+{
+	SK_U32	MdReg;
+
+	if (pAC->GIni.GIGenesis) {
+		
+		XM_IN32(IoC, Port, XM_MODE, &MdReg);
+
+		XM_OUT32(IoC, Port, XM_MODE, MdReg | XM_MD_FTF);
+	}
+	else {
+		/* no way to flush the FIFO we have to issue a reset */
+		/* TBD */
+	}
+}	/* SkMacFlushTxFifo */
+
+
+/******************************************************************************
+ *
+ *	SkMacFlushRxFifo() - Flush the MAC's receive FIFO
+ *
+ * Description:
+ *	Flush the receive FIFO of the MAC specified by the index 'Port'
+ *
+ * Returns:
+ *	nothing
+ */
+void SkMacFlushRxFifo(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port)	/* Port Index (MAC_1 + n) */
+{
+	SK_U32	MdReg;
+
+	if (pAC->GIni.GIGenesis) {
+
+		XM_IN32(IoC, Port, XM_MODE, &MdReg);
+
+		XM_OUT32(IoC, Port, XM_MODE, MdReg | XM_MD_FRF);
+	}
+	else {
+		/* no way to flush the FIFO we have to issue a reset */
+		/* TBD */
+	}
+}	/* SkMacFlushRxFifo */
+
+
+/******************************************************************************
+ *
+ *	SkXmSoftRst() - Do a XMAC software reset
+ *
+ * Description:
+ *	The PHY registers should not be destroyed during this
+ *	kind of software reset. Therefore the XMAC Software Reset
+ *	(XM_GP_RES_MAC bit in XM_GP_PORT) must not be used!
+ *
+ *	The software reset is done by
+ *		- disabling the Rx and Tx state machine,
+ *		- resetting the statistics module,
+ *		- clear all other significant XMAC Mode,
+ *		  Command, and Control Registers
+ *		- clearing the Hash Register and the
+ *		  Exact Match Address registers, and
+ *		- flushing the XMAC's Rx and Tx FIFOs.
+ *
+ * Note:
+ *	Another requirement when stopping the XMAC is to
+ *	avoid sending corrupted frames on the network.
+ *	Disabling the Tx state machine will NOT interrupt
+ *	the currently transmitted frame. But we must take care
+ *	that the Tx FIFO is cleared AFTER the current frame
+ *	is complete sent to the network.
+ *
+ *	It takes about 12ns to send a frame with 1538 bytes.
+ *	One PCI clock goes at least 15ns (66MHz). Therefore
+ *	after reading XM_GP_PORT back, we are sure that the
+ *	transmitter is disabled AND idle. And this means
+ *	we may flush the transmit FIFO now.
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkXmSoftRst(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port)	/* Port Index (MAC_1 + n) */
+{
+	SK_U16	ZeroAddr[4] = {0x0000, 0x0000, 0x0000, 0x0000};
+	
+	/* reset the statistics module */
+	XM_OUT32(IoC, Port, XM_GP_PORT, XM_GP_RES_STAT);
+
+	/* disable all XMAC IRQs */
+	XM_OUT16(IoC, Port, XM_IMSK, 0xffff);
+	
+	XM_OUT32(IoC, Port, XM_MODE, 0);		/* clear Mode Reg */
+	
+	XM_OUT16(IoC, Port, XM_TX_CMD, 0);		/* reset TX CMD Reg */
+	XM_OUT16(IoC, Port, XM_RX_CMD, 0);		/* reset RX CMD Reg */
 	
 	/* disable all PHY IRQs */
 	switch (pAC->GIni.GP[Port].PhyType) {
 	case SK_PHY_BCOM:
-			PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_INT_MASK, 0xffff);
+			SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_INT_MASK, 0xffff);
 			break;
+#ifdef OTHER_PHY
 		case SK_PHY_LONE:
-			PHY_WRITE(IoC, pPrt, Port, PHY_LONE_INT_ENAB, 0x0);
+			SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_INT_ENAB, 0);
 			break;
 		case SK_PHY_NAT:
 			/* todo: National
-			 PHY_WRITE(IoC, pPrt, Port, PHY_NAT_INT_MASK, 
-				0xffff); */
+			 SkXmPhyWrite(pAC, IoC, Port, PHY_NAT_INT_MASK, 0xffff); */
 			break;
+#endif /* OTHER_PHY */
 	}
 
 	/* clear the Hash Register */
-	SkXmClrHashAddr(pAC, IoC, Port);
+	XM_OUTHASH(IoC, Port, XM_HSM, &ZeroAddr);
 
 	/* clear the Exact Match Address registers */
 	SkXmClrExactAddr(pAC, IoC, Port, 0, 15);
-	SkXmClrSrcCheck(pAC, IoC, Port);
-
-	/* flush the XMAC's Rx and Tx FIFOs */
-	SkXmFlushTxFifo(pAC, IoC, Port);
-	SkXmFlushRxFifo(pAC, IoC, Port);
+	
+	/* clear the Source Check Address registers */
+	XM_OUTHASH(IoC, Port, XM_SRC_CHK, &ZeroAddr);
 
-	pAC->GIni.GP[Port].PState = SK_PRT_STOP;
-}	/* SkXmSoftRst*/
+}	/* SkXmSoftRst */
 
 
 /******************************************************************************
@@ -589,23 +1219,21 @@
  *
  * Description:
  *	The XMAC of the specified 'Port' and all connected devices
- *	(PHY and SERDES) will receive a reset signal on its *Reset
- *	pins.
- *	External PHYs must be reset be clearing a bit in the GPIO
- *	register (Timing requirements: Broadcom: 400ns, Level One:
- *	none, National: 80ns).
+ *	(PHY and SERDES) will receive a reset signal on its *Reset pins.
+ *	External PHYs must be reset be clearing a bit in the GPIO register
+ *  (Timing requirements: Broadcom: 400ns, Level One: none, National: 80ns).
  *
  * ATTENTION:
- * 	It is absolutely neccessary to reset the SW_RST Bit first
+ * 	It is absolutely necessary to reset the SW_RST Bit first
  *	before calling this function.
  *
  * Returns:
  *	nothing
  */
-void SkXmHardRst(
+static void SkXmHardRst(
 SK_AC	*pAC,	/* adapter context */
 SK_IOC	IoC,	/* IO context */
-int		Port)	/* port to stop (MAC_1 + n) */
+int		Port)	/* Port Index (MAC_1 + n) */
 {
 	SK_U32	Reg;
 	int		i;
@@ -613,14 +1241,12 @@
 	SK_U16	Word;
 
 	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);
+		/* TX_MFF_CTRL1 has 32 bits, but only the lowest 16 bits are used */
+		SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_CLR_MAC_RST);
 
 		TOut = 0;
 		do {
-			TOut ++;
-			if (TOut > 10000) {
+			if (TOut++ > 10000) {
 				/*
 				 * Adapter seems to be in RESET state.
 				 * Registers cannot be written.
@@ -628,9 +1254,10 @@
 				return;
 			}
 
-			SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1),
-				(SK_U16) MFF_SET_MAC_RST);
-			SK_IN16(IoC,MR_ADDR(Port,TX_MFF_CTRL1), &Word);
+			SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_SET_MAC_RST);
+			
+			SK_IN16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), &Word);
+		
 		} while ((Word & MFF_SET_MAC_RST) == 0);
 	}
 
@@ -652,16 +1279,151 @@
 		SK_IN32(IoC, B2_GP_IO, &Reg);
 	}
 
-	pAC->GIni.GP[Port].PState = SK_PRT_RESET;
 }	/* SkXmHardRst */
 
 
 /******************************************************************************
  *
+ *	SkGmSoftRst() - Do a GMAC software reset
+ *
+ * Description:
+ *	The GPHY registers should not be destroyed during this
+ *	kind of software reset.
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkGmSoftRst(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port)	/* Port Index (MAC_1 + n) */
+{
+	SK_U16	EmptyHash[4] = {0x0000, 0x0000, 0x0000, 0x0000};
+	SK_U16  RxCtrl;
+
+	/* reset the statistics module */
+
+	/* disable all GMAC IRQs */
+	SK_OUT8(IoC, GMAC_IRQ_MSK, 0);
+	
+	/* disable all PHY IRQs */
+	SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_INT_MASK, 0);
+	
+	/* clear the Hash Register */
+	GM_OUTHASH(IoC, Port, GM_MC_ADDR_H1, &EmptyHash);
+
+	/* Enable Unicast and Multicast filtering */
+	GM_IN16(IoC, Port, GM_RX_CTRL, &RxCtrl);
+	
+	GM_OUT16(IoC, Port, GM_RX_CTRL,
+		RxCtrl | GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA);
+
+}	/* SkGmSoftRst */
+
+
+/******************************************************************************
+ *
+ *	SkGmHardRst() - Do a GMAC hardware reset
+ *
+ * Description:
+ *
+ * ATTENTION:
+ * 	It is absolutely necessary to reset the SW_RST Bit first
+ *	before calling this function.
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkGmHardRst(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port)	/* Port Index (MAC_1 + n) */
+{
+	/* set GPHY Control reset */
+	SK_OUT32(IoC, MR_ADDR(Port, GPHY_CTRL), GPC_RST_SET);
+
+	/* set GMAC Control reset */
+	SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_RST_SET);
+
+}	/* SkGmHardRst */
+
+
+/******************************************************************************
+ *
+ *	SkMacSoftRst() - Do a MAC software reset
+ *
+ * Description:	calls a MAC software reset routine dep. on board type
+ *
+ * Returns:
+ *	nothing
+ */
+void SkMacSoftRst(
+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];
+
+	/* disable receiver and transmitter */
+	SkMacRxTxDisable(pAC, IoC, Port);
+
+	if (pAC->GIni.GIGenesis) {
+		
+		SkXmSoftRst(pAC, IoC, Port);
+	}
+	else {
+		
+		SkGmSoftRst(pAC, IoC, Port);
+	}
+
+	/* flush the MAC's Rx and Tx FIFOs */
+	SkMacFlushTxFifo(pAC, IoC, Port);
+	
+	SkMacFlushRxFifo(pAC, IoC, Port);
+
+	pPrt->PState = SK_PRT_STOP;
+
+}	/* SkMacSoftRst */
+
+
+/******************************************************************************
+ *
+ *	SkMacHardRst() - Do a MAC hardware reset
+ *
+ * Description:	calls a MAC hardware reset routine dep. on board type
+ *
+ * Returns:
+ *	nothing
+ */
+void SkMacHardRst(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port)	/* Port Index (MAC_1 + n) */
+{
+	
+	if (pAC->GIni.GIGenesis) {
+		
+		SkXmHardRst(pAC, IoC, Port);
+	}
+	else {
+		
+		SkGmHardRst(pAC, IoC, Port);
+	}
+
+	pAC->GIni.GP[Port].PState = SK_PRT_RESET;
+
+}	/* SkMacHardRst */
+
+
+
+/******************************************************************************
+ *
  *	SkXmInitMac() - Initialize the XMAC II
  *
  * Description:
- *	Initialize all the XMAC of the specified port.
+ *	Initialize the XMAC of the specified port.
  *	The XMAC must be reset or stopped before calling this function.
  *
  * Note:
@@ -679,7 +1441,6 @@
 	SK_U32		Reg;
 	int			i;
 	SK_U16		SWord;
-	SK_U16		PhyId;
 
 	pPrt = &pAC->GIni.GP[Port];
 
@@ -687,10 +1448,11 @@
 		/* 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 & MFF_SET_MAC_RST) != 0) {
 			/* PState does not match HW state */
 			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E006, SKERR_HWI_E006MSG);
-			/* Correct it. */
+			/* Correct it */
 			pPrt->PState = SK_PRT_RESET;
 		}
 	}
@@ -701,115 +1463,84 @@
 		 * 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);
+		SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_CLR_MAC_RST);
 
-		/* Ensure that XMAC reset release is done (errata from LReinbold?). */
+		/* 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) {
+		/* Clear PHY reset */
+		if (pPrt->PhyType != SK_PHY_XMAC) {
+
 			SK_IN32(IoC, B2_GP_IO, &Reg);
+			
 			if (Port == 0) {
-				Reg |= GP_DIR_0; /* Set to output. */
-				Reg |= GP_IO_0;
+				Reg |= (GP_DIR_0 | GP_IO_0); /* set to output */
 			}
 			else {
-				Reg |= GP_DIR_2; /* Set to output. */
-				Reg |= GP_IO_2;
+				Reg |= (GP_DIR_2 | GP_IO_2); /* set to output */
 			}
 			SK_OUT32(IoC, B2_GP_IO, Reg);
 
-			/* Enable GMII interface. */
+			/* Enable GMII interface */
 			XM_OUT16(IoC, Port, XM_HW_CFG, XM_HW_GMII_MD);
 
-			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 */
+			/* read Id from external PHY (all have the same address) */
+			SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_ID1, &pPrt->PhyId1);
 
 			/*
 			 * 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);
 
-			if (PhyId == 0x6044) {
-				/* Workaround BCOM Errata for the C0 type. */
-				/* Write magic patterns to reserved registers. */
+			if (pPrt->PhyId1 == PHY_BCOM_ID1_C0) {
+				/*
+				 * Workaround BCOM Errata for the C0 type.
+				 * Write magic patterns to reserved registers.
+				 */
 				i = 0;
 				while (BcomRegC0Hack[i].PhyReg != 0) {
-					PHY_WRITE(IoC, pPrt, Port, BcomRegC0Hack[i].PhyReg,
+					SkXmPhyWrite(pAC, IoC, Port, BcomRegC0Hack[i].PhyReg,
 						BcomRegC0Hack[i].PhyVal);
 					i++;
 				}
 			}
-			else if (PhyId == 0x6041) {
-				/* Workaround BCOM Errata for the A1 type. */
-				/* Write magic patterns to reserved registers. */
+			else if (pPrt->PhyId1 == PHY_BCOM_ID1_A1) {
+				/*
+				 * Workaround BCOM Errata for the A1 type.
+				 * Write magic patterns to reserved registers.
+				 */
 				i = 0;
 				while (BcomRegA1Hack[i].PhyReg != 0) {
-					PHY_WRITE(IoC, pPrt, Port, BcomRegA1Hack[i].PhyReg,
+					SkXmPhyWrite(pAC, IoC, Port, BcomRegA1Hack[i].PhyReg,
 						BcomRegA1Hack[i].PhyVal);
 					i++;
 				}
 			}
 
-			/* 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);
+			/*
+			 * Workaround BCOM Errata (#10523) for all BCom PHYs.
+			 * Disable Power Management after reset.
+			 */
+			SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, &SWord);
+			
+			SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_AUX_CTRL,
+				(SK_U16)(SWord | PHY_B_AC_DIS_PM));
 
-			/* PHY LED initialization is done in SkGeXmitLED(), not here. */
+			/* PHY LED initialization is done in SkGeXmitLED() */
 		}
 
 		/* Dummy read the Interrupt source register */
 		XM_IN16(IoC, Port, XM_ISRC, &SWord);
 		
 		/*
-		 * The autonegotiation process starts immediately after
-		 * clearing the reset. The autonegotiation process should be
+		 * The auto-negotiation process starts immediately after
+		 * clearing the reset. The auto-negotiation process should be
 		 * started by the SIRQ, therefore stop it here immediately.
 		 */
-		SkXmInitPhy(pAC, IoC, Port, SK_FALSE);
+		SkMacInitPhy(pAC, IoC, Port, SK_FALSE);
 
 #if 0
 		/* temp. code: enable signal detect */
@@ -820,15 +1551,16 @@
 
 	/*
 	 * configure the XMACs Station Address
-	 * 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
+	 * 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
 	 */
 	for (i = 0; i < 3; i++) {
 		/*
 		 * The following 2 statements are together endianess
-		 * independant. Remember this when changing.
+		 * independent. Remember this when changing.
 		 */
 		SK_IN16(IoC, (B2_MAC_2 + Port * 8 + i * 2), &SWord);
+		
 		XM_OUT16(IoC, Port, (XM_SA + i * 2), SWord);
 	}
 
@@ -840,49 +1572,54 @@
 	/* Rx Low Water Mark (XM_RX_LO_WM):	use default */
 
 	/* configure Rx High Water Mark (XM_RX_HI_WM) */
-	XM_OUT16(IoC, Port, XM_RX_HI_WM, 0x05aa);
+	XM_OUT16(IoC, Port, XM_RX_HI_WM, SK_XM_RX_HI_WM);
+
+	/* Configure Tx Request Threshold */
+	SWord = SK_XM_THR_SL;				/* for single port */
 
 	if (pAC->GIni.GIMacsFound > 1) {
 		switch (pAC->GIni.GIPortUsage) {
 		case SK_RED_LINK:
-			/* Configure Tx Request Threshold for red. link */
-			XM_OUT16(IoC, Port, XM_TX_THR, SK_XM_THR_REDL);
+			SWord = SK_XM_THR_REDL;		/* redundant link */
 			break;
 		case SK_MUL_LINK:
-			/* Configure Tx Request Threshold for load bal. */
-			XM_OUT16(IoC, Port, XM_TX_THR, SK_XM_THR_MULL);
+			SWord = SK_XM_THR_MULL;		/* load balancing */
 			break;
 		case SK_JUMBO_LINK:
-			/* Configure Tx Request Threshold for jumbo frames */
-			XM_OUT16(IoC, Port, XM_TX_THR, SK_XM_THR_JUMBO);
+			SWord = SK_XM_THR_JUMBO;	/* jumbo frames */
 			break;
 		default:
-			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E014,
-				SKERR_HWI_E014MSG);
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E014, SKERR_HWI_E014MSG);
 			break;
 		}
 	}
-	else {
-		/* Configure Tx Request Threshold for single port */
-		XM_OUT16(IoC, Port, XM_TX_THR, SK_XM_THR_SL);
-	}
+	XM_OUT16(IoC, Port, XM_TX_THR, SWord);
 
-	/*
-	 * setup register defaults for the Rx Command Register
-	 *	- Enable Automatic Frame Padding on Tx side
-	 */
+	/* setup register defaults for the Tx Command Register */
 	XM_OUT16(IoC, Port, XM_TX_CMD, XM_TX_AUTO_PAD);
 
-	/*
-	 * setup register defaults for the Rx Command Register,
-	 * program value of PRxCmd
-	 */
-	XM_OUT16(IoC, Port, XM_RX_CMD, pPrt->PRxCmd);
+	/* setup register defaults for the Rx Command Register */
+	SWord = XM_RX_STRIP_FCS | XM_RX_LENERR_OK;
+
+	if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) {
+		SWord |= 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
+		 */
+		SWord |= XM_RX_DIS_CEXT;
+	}
+	
+	XM_OUT16(IoC, Port, XM_RX_CMD, SWord);
 
 	/*
 	 * setup register defaults for the Mode Register
 	 *	- Don't strip error frames to avoid Store & Forward
-	 *	  on the rx side.
+	 *	  on the Rx side.
 	 *	- Enable 'Check Station Address' bit
 	 *	- Enable 'Check Address Array' bit
 	 */
@@ -906,15 +1643,226 @@
 	 * Do NOT init XMAC interrupt mask here.
 	 * All interrupts remain disable until link comes up!
 	 */
-	pPrt->PState = SK_PRT_INIT;
 
 	/*
 	 * Any additional configuration changes may be done now.
-	 * The last action is to enable the rx and tx state machine.
-	 * This should be done after the autonegotiation process
+	 * The last action is to enable the Rx and Tx state machine.
+	 * This should be done after the auto-negotiation process
 	 * has been completed successfully.
 	 */
-}	/* SkXmInitMac*/
+}	/* SkXmInitMac */
+
+/******************************************************************************
+ *
+ *	SkGmInitMac() - Initialize the GMAC
+ *
+ * Description:
+ *	Initialize the GMAC of the specified port.
+ *	The GMAC must be reset or stopped before calling this function.
+ *
+ * Note:
+ *	The GMAC's Rx and Tx state machine is still disabled when returning.
+ *
+ * Returns:
+ *	nothing
+ */
+void SkGmInitMac(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+	int			i;
+	SK_U16		SWord;
+	SK_U32		DWord;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (pPrt->PState == SK_PRT_STOP) {
+		/* Port State: SK_PRT_STOP */
+		/* Verify that the reset bit is cleared */
+		SK_IN32(IoC, MR_ADDR(Port, GMAC_CTRL), &DWord);
+		
+		if ((DWord & GMC_RST_SET) != 0) {
+			/* PState does not match HW state */
+			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) {
+		/* set GPHY Control reset */
+		SK_OUT32(IoC, MR_ADDR(Port, GPHY_CTRL), GPC_RST_SET);
+
+		/* set GMAC Control reset */
+		SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_RST_SET);
+
+		/* clear GMAC Control reset */
+		SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_RST_CLR);
+
+		/* set GMAC Control reset */
+		SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_RST_SET);
+
+		/* set HWCFG_MODE */
+		DWord = GPC_INT_POL_HI | GPC_DIS_FC | GPC_DIS_SLEEP |
+			GPC_ENA_XC | GPC_ANEG_ADV_ALL_M | GPC_ENA_PAUSE |
+			(pAC->GIni.GICopperType ? GPC_HWCFG_GMII_COP :
+			GPC_HWCFG_GMII_FIB);
+
+		/* set GPHY Control reset */
+		SK_OUT32(IoC, MR_ADDR(Port, GPHY_CTRL), DWord | GPC_RST_SET);
+
+		/* release GPHY Control reset */
+		SK_OUT32(IoC, MR_ADDR(Port, GPHY_CTRL), DWord | GPC_RST_CLR);
+
+		/* clear GMAC Control reset */
+		SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_PAUSE_ON | GMC_RST_CLR);
+
+		/* Dummy read the Interrupt source register */
+		SK_IN16(IoC, GMAC_IRQ_SRC, &SWord);
+		
+#ifndef VCPU
+		/* read Id from PHY */
+		SkGmPhyRead(pAC, IoC, Port, PHY_MARV_ID1, &pPrt->PhyId1);
+		
+		SkGmInitPhyMarv(pAC, IoC, Port, SK_FALSE);
+#endif /* VCPU */
+	}
+
+	(void)SkGmResetCounter(pAC, IoC, Port);
+
+	SWord =  0;
+
+	/* speed settings */
+	switch (pPrt->PLinkSpeed) {
+	case SK_LSPEED_AUTO:
+		/* auto update for speed is already set */
+		break;
+	case SK_LSPEED_1000MBPS:
+		SWord |= GM_GPCR_SPEED_1000;
+		break;
+	case SK_LSPEED_100MBPS:
+		SWord |= GM_GPCR_SPEED_100;
+		break;
+	case SK_LSPEED_10MBPS:
+		break;
+	}
+	
+	/* duplex settings */
+	if (pPrt->PLinkModeConf == SK_LMODE_FULL ||
+		pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE) {
+		
+		SWord |= GM_GPCR_DUP_FULL;
+	}
+
+	/* flow control settings */
+	switch (pPrt->PFlowCtrlMode) {
+	case SK_FLOW_MODE_NONE:
+		/* disable auto-neg of flow control */
+		SWord |= GM_GPCR_FC_TX_DIS | GM_GPCR_FC_RX_DIS;
+		break;
+	case SK_FLOW_MODE_LOC_SEND:
+		SWord |= GM_GPCR_FC_RX_DIS;
+		break;
+	case SK_FLOW_MODE_SYMMETRIC:
+		/* TBD */
+	case SK_FLOW_MODE_SYM_OR_REM:
+		/* do nothing means to enable autoneg for flowcontrol and */
+		/* enable rx and tx of pause frames */
+		break;
+	}
+
+	/* setup General Purpose Control Register */
+	GM_OUT16(IoC, Port, GM_GP_CTRL, SWord);
+
+	/* setup Transmit Control Register */
+	GM_OUT16(IoC, Port, GM_TX_CTRL, GM_TXCR_COL_THR);
+
+	/* setup Receive Control Register */
+	GM_OUT16(IoC, Port, GM_RX_CTRL, GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA |
+		GM_RXCR_CRC_DIS);
+
+	/* setup Transmit Flow Control Register */
+	GM_OUT16(IoC, Port, GM_TX_FLOW_CTRL, 0xffff);
+
+	/* setup Transmit Parameter Register */
+#ifdef VCPU
+	GM_IN16(IoC, Port, GM_TX_PARAM, &SWord);
+#endif /* VCPU */
+
+	SWord = JAM_LEN_VAL(3) | JAM_IPG_VAL(11) | IPG_JAM_DATA(26);
+	
+	GM_OUT16(IoC, Port, GM_TX_PARAM, SWord);
+
+	/* configure the Serial Mode Register */
+#ifdef VCPU
+	GM_IN16(IoC, Port, GM_SERIAL_MODE, &SWord);
+#endif /* VCPU */
+	
+	SWord = GM_SMOD_VLAN_ENA | IPG_VAL_FAST_ETH;
+
+	if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) {
+		/* enable jumbo mode (Max. Frame Length = 9018) */
+		SWord |= GM_SMOD_JUMBO_ENA;
+	}
+	
+	GM_OUT16(IoC, Port, GM_SERIAL_MODE, SWord);
+	
+	/*
+	 * configure the GMACs Station Addresses
+	 * in PROM you can find our addresses at:
+	 * B2_MAC_1 = xx xx xx xx xx x0 virtual address
+	 * B2_MAC_2 = xx xx xx xx xx x1 is programmed to GMAC A
+	 * B2_MAC_3 = xx xx xx xx xx x2 is reserved for DualPort
+	 */
+
+	for (i = 0; i < 3; i++) {
+		/*
+		 * The following 2 statements are together endianess
+		 * independent. Remember this when changing.
+		 */
+		/* physical address: will be used for pause frames */
+		SK_IN16(IoC, (B2_MAC_2 + Port * 8 + i * 2), &SWord);
+
+#ifdef WA_DEV_16
+		/* WA for deviation #16 */
+		if (pAC->GIni.GIChipRev == 0) {
+			/* swap the address bytes */
+			SWord = ((SWord & 0xff00) >> 8)	| ((SWord & 0x00ff) << 8);
+
+			/* write to register in reversed order */
+			GM_OUT16(IoC, Port, (GM_SRC_ADDR_1L + (2 - i) * 4), SWord);
+		}
+		else {
+			GM_OUT16(IoC, Port, (GM_SRC_ADDR_1L + i * 4), SWord);
+		}
+#else		
+		GM_OUT16(IoC, Port, (GM_SRC_ADDR_1L + i * 4), SWord);
+#endif /* WA_DEV_16 */
+		
+		/* virtual address: will be used for data */
+		SK_IN16(IoC, (B2_MAC_1 + Port * 8 + i * 2), &SWord);
+
+		GM_OUT16(IoC, Port, (GM_SRC_ADDR_2L + i * 4), SWord);
+	}
+
+	/* reset all Multicast filtering Hash registers */
+	GM_OUT16(IoC, Port, GM_MC_ADDR_H1, 0);
+	GM_OUT16(IoC, Port, GM_MC_ADDR_H2, 0);
+	GM_OUT16(IoC, Port, GM_MC_ADDR_H3, 0);
+	GM_OUT16(IoC, Port, GM_MC_ADDR_H4, 0);
+
+	/* enable interrupt mask for counter overflows */
+	GM_OUT16(IoC, Port, GM_TX_IRQ_MSK, 0);
+	GM_OUT16(IoC, Port, GM_RX_IRQ_MSK, 0);
+	GM_OUT16(IoC, Port, GM_TR_IRQ_MSK, 0);
+
+#ifdef VCPU
+	/* read General Purpose Status */
+	GM_IN16(IoC, Port, GM_GP_STAT, &SWord);
+#endif /* VCPU */
+}	/* SkGmInitMac */
 
 
 /******************************************************************************
@@ -922,9 +1870,9 @@
  *	SkXmInitDupMd() - Initialize the XMACs Duplex Mode
  *
  * Description:
- *	This function initilaizes the XMACs Duplex Mode.
+ *	This function initializes the XMACs Duplex Mode.
  *	It should be called after successfully finishing
- *	the Autonegotiation Process
+ *	the Auto-negotiation Process
  *
  * Returns:
  *	nothing
@@ -939,9 +1887,9 @@
 	case SK_LMODE_STAT_HALF:
 		/* Configuration Actions for Half Duplex Mode */
 		/*
-		 * XM_BURST = default value. We are propable not quick
+		 * XM_BURST = default value. We are probable not quick
 		 * 	enough at the 'XMAC' bus to burst 8kB.
-		 *	The XMAC stopps bursting if no transmit frames
+		 *	The XMAC stops bursting if no transmit frames
 		 *	are available or the burst limit is exceeded.
 		 */
 		/* XM_TX_RT_LIM = default value (15) */
@@ -969,10 +1917,10 @@
  *	SkXmInitPauseMd() - initialize the Pause Mode to be used for this port
  *
  * Description:
- *	This function initilaizes the Pause Mode which should
+ *	This function initializes the Pause Mode which should
  *	be used for this port.
  *	It should be called after successfully finishing
- *	the Autonegotiation Process
+ *	the Auto-negotiation Process
  *
  * Returns:
  *	nothing
@@ -988,22 +1936,26 @@
 
 	pPrt = &pAC->GIni.GP[Port];
 
+	XM_IN16(IoC, Port, XM_MMU_CMD, &Word);
+	
 	if (pPrt->PFlowCtrlStatus == SK_FLOW_STAT_NONE ||
 		pPrt->PFlowCtrlStatus == SK_FLOW_STAT_LOC_SEND) {
 
 		/* Disable Pause Frame Reception */
-		XM_IN16(IoC, Port, XM_MMU_CMD, &Word);
-		XM_OUT16(IoC, Port, XM_MMU_CMD, Word | XM_MMU_IGN_PF);
+		Word |= XM_MMU_IGN_PF;
 	}
 	else {
 		/*
-		 * enabling pause frame reception is required for 1000BT 
+		 * enabling pause frame reception is required for 1000BT
 		 * because the XMAC is not reset if the link is going down
 		 */
 		/* Enable Pause Frame Reception */
-		XM_IN16(IoC, Port, XM_MMU_CMD, &Word);
-		XM_OUT16(IoC, Port, XM_MMU_CMD, Word & ~XM_MMU_IGN_PF);
+		Word &= ~XM_MMU_IGN_PF;
 	}	
+	
+	XM_OUT16(IoC, Port, XM_MMU_CMD, Word);
+
+	XM_IN32(IoC, Port, XM_MODE, &DWord);
 
 	if (pPrt->PFlowCtrlStatus == SK_FLOW_STAT_SYMMETRIC ||
 		pPrt->PFlowCtrlStatus == SK_FLOW_STAT_LOC_SEND) {
@@ -1011,11 +1963,10 @@
 		/*
 		 * Configure Pause Frame Generation
 		 * Use internal and external Pause Frame Generation.
-		 * Sending pause frames is edge triggert. Send a
-		 * Pause frame with the maximum pause time if
-		 * internal oder external FIFO full condition
-		 * occurs. Send a zero pause time frame to
-		 * start transmission again.
+		 * Sending pause frames is edge triggered.
+		 * Send a Pause frame with the maximum pause time if
+		 * internal oder external FIFO full condition occurs.
+		 * Send a zero pause time frame to re-start transmission.
 		 */
 
 		/* XM_PAUSE_DA = '010000C28001' (default) */
@@ -1025,71 +1976,32 @@
 		XM_OUT16(IoC, Port, XM_MAC_PTIME, 0xffff);
 
 		/* Set Pause Mode in Mode Register */
-		XM_IN32(IoC, Port, XM_MODE, &DWord);
-		XM_OUT32(IoC, Port, XM_MODE, DWord | XM_PAUSE_MODE);
+		DWord |= XM_PAUSE_MODE;
 
 		/* Set Pause Mode in MAC Rx FIFO */
-		SK_OUT16(IoC, MR_ADDR(Port,RX_MFF_CTRL1), MFF_ENA_PAUSE);
+		SK_OUT16(IoC, MR_ADDR(Port, RX_MFF_CTRL1), MFF_ENA_PAUSE);
 	}
 	else {
 		/*
-		 * disable pause frame generation is required for 1000BT 
+		 * disable pause frame generation is required for 1000BT
 		 * because the XMAC is not reset if the link is going down
 		 */
 		/* Disable Pause Mode in Mode Register */
-		XM_IN32(IoC, Port, XM_MODE, &DWord);
-		XM_OUT32(IoC, Port, XM_MODE, DWord & ~XM_PAUSE_MODE);
+		DWord &= ~XM_PAUSE_MODE;
 
 		/* Disable Pause Mode in MAC Rx FIFO */
-		SK_OUT16(IoC, MR_ADDR(Port,RX_MFF_CTRL1), MFF_DIS_PAUSE);
+		SK_OUT16(IoC, MR_ADDR(Port, RX_MFF_CTRL1), MFF_DIS_PAUSE);
 	}
+	
+	XM_OUT32(IoC, Port, XM_MODE, DWord);
 }	/* SkXmInitPauseMd*/
 
 
 /******************************************************************************
  *
- *	SkXmInitPhy() - Initialize the XMAC II Phy registers
- *
- * Description:
- *	Initialize all the XMACs Phy registers
- *
- * Note:
- *
- * Returns:
- *	nothing
- */
-void SkXmInitPhy(
-SK_AC	*pAC,		/* adapter context */
-SK_IOC	IoC,		/* IO context */
-int		Port,		/* Port Index (MAC_1 + n) */
-SK_BOOL	DoLoop)		/* Should a Phy LOOback be set-up? */
-{
-	SK_GEPORT	*pPrt;
-
-	pPrt = &pAC->GIni.GP[Port];
-	switch (pPrt->PhyType) {
-	case SK_PHY_XMAC:
-		SkXmInitPhyXmac(pAC, IoC, Port, DoLoop);
-		break;
-	case SK_PHY_BCOM:
-		SkXmInitPhyBcom(pAC, IoC, Port, DoLoop);
-		break;
-	case SK_PHY_LONE:
-		SkXmInitPhyLone(pAC, IoC, Port, DoLoop);
-		break;
-	case SK_PHY_NAT:
-		SkXmInitPhyNat(pAC, IoC, Port, DoLoop);
-		break;
-	}
-}	/* SkXmInitPhy*/
-
-
-/******************************************************************************
- *
- *	SkXmInitPhyXmac() - Initialize the XMAC II Phy registers
+ *	SkXmInitPhyXmac() - Initialize the XMAC Phy registers
  *
- * Description:
- *	Initialize all the XMACs Phy registers
+ * Description:	initializes all the XMACs Phy registers
  *
  * Note:
  *
@@ -1100,32 +2012,32 @@
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
 int		Port,		/* Port Index (MAC_1 + n) */
-SK_BOOL	DoLoop)		/* Should a Phy LOOback be set-up? */
+SK_BOOL	DoLoop)		/* Should a Phy LoopBack be set-up? */
 {
 	SK_GEPORT	*pPrt;
 	SK_U16		Ctrl;
 
 	pPrt = &pAC->GIni.GP[Port];
-
-	/* Autonegotiation ? */
-	if (pPrt->PLinkMode == SK_LMODE_HALF ||
-	    pPrt->PLinkMode == SK_LMODE_FULL) {
-		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
-			("InitPhyXmac: no autonegotiation Port %d\n", Port));
-		/* No Autonegiotiation */
+	Ctrl = 0;
+	
+	/* Auto-negotiation ? */
+	if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("InitPhyXmac: no auto-negotiation Port %d\n", Port));
 		/* Set DuplexMode in Config register */
-		Ctrl = (pPrt->PLinkMode == SK_LMODE_FULL ? PHY_CT_DUP_MD : 0);
+		if (pPrt->PLinkMode == SK_LMODE_FULL) {
+			Ctrl |= PHY_CT_DUP_MD;
+		}
 
 		/*
-		 * Do NOT enable Autonegotiation here. This would hold
-		 * the link down because no IDLES are transmitted
+		 * Do NOT enable Auto-negotiation here. This would hold
+		 * the link down because no IDLEs are transmitted
 		 */
 	}
 	else {
-		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
-			("InitPhyXmac: with autonegotiation Port %d\n", Port));
-		/* Set Autonegotiation advertisement */
-		Ctrl = 0;
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("InitPhyXmac: with auto-negotiation Port %d\n", Port));
+		/* Set Auto-negotiation advertisement */
 
 		/* Set Full/half duplex capabilities */
 		switch (pPrt->PLinkMode) {
@@ -1139,8 +2051,8 @@
 			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);
+			SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E015,
+				SKERR_HWI_E015MSG);
 		}
 
 		switch (pPrt->PFlowCtrlMode) {
@@ -1157,14 +2069,14 @@
 			Ctrl |= PHY_X_P_BOTH_MD;
 			break;
 		default:
-			SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT,
-				SKERR_HWI_E016, SKERR_HWI_E016MSG);
+			SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016,
+				SKERR_HWI_E016MSG);
 		}
 
 		/* Write AutoNeg Advertisement Register */
-		PHY_WRITE(IoC, pPrt, Port, PHY_XMAC_AUNE_ADV, Ctrl);
+		SkXmPhyWrite(pAC, IoC, Port, PHY_XMAC_AUNE_ADV, Ctrl);
 
-		/* Restart Autonegotiation */
+		/* Restart Auto-negotiation */
 		Ctrl = PHY_CT_ANE | PHY_CT_RE_CFG;
 	}
 
@@ -1174,16 +2086,15 @@
 	}
 
 	/* Write to the Phy control register */
-	PHY_WRITE(IoC, pPrt, Port, PHY_XMAC_CTRL, Ctrl);
-}	/* SkXmInitPhyXmac*/
+	SkXmPhyWrite(pAC, IoC, Port, PHY_XMAC_CTRL, Ctrl);
+}	/* SkXmInitPhyXmac */
 
 
 /******************************************************************************
  *
  *	SkXmInitPhyBcom() - Initialize the Broadcom Phy registers
  *
- * Description:
- *	Initialize all the Broadcom Phy registers
+ * Description:	initializes all the Broadcom Phy registers
  *
  * Note:
  *
@@ -1194,7 +2105,7 @@
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
 int		Port,		/* Port Index (MAC_1 + n) */
-SK_BOOL	DoLoop)		/* Should a Phy LOOback be set-up? */
+SK_BOOL	DoLoop)		/* Should a Phy LoopBack be set-up? */
 {
 	SK_GEPORT	*pPrt;
 	SK_U16		Ctrl1;
@@ -1203,7 +2114,7 @@
 	SK_U16		Ctrl4;
 	SK_U16		Ctrl5;
 
-	Ctrl1 = PHY_B_CT_SP1000;
+	Ctrl1 = PHY_CT_SP1000;
 	Ctrl2 = 0;
 	Ctrl3 = PHY_SEL_TYPE;
 	Ctrl4 = PHY_B_PEC_EN_LTR;
@@ -1213,120 +2124,452 @@
 
 	/* manually Master/Slave ? */
 	if (pPrt->PMSMode != SK_MS_MODE_AUTO) {
-		Ctrl2 |= PHY_B_1000C_MSE;
+		Ctrl2 |= PHY_B_1000C_MSE;
+		
+		if (pPrt->PMSMode == SK_MS_MODE_MASTER) {
+			Ctrl2 |= PHY_B_1000C_MSC;
+		}
+	}
+	/* Auto-negotiation ? */
+	if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("InitPhyBcom: no auto-negotiation Port %d\n", Port));
+		/* Set DuplexMode in Config register */
+		Ctrl1 |= (pPrt->PLinkMode == SK_LMODE_FULL ? PHY_CT_DUP_MD : 0);
+
+		/* Determine Master/Slave manually if not already done */
+		if (pPrt->PMSMode == SK_MS_MODE_AUTO) {
+			Ctrl2 |= PHY_B_1000C_MSE;	/* set it to Slave */
+		}
+
+		/*
+		 * Do NOT enable Auto-negotiation here. This would hold
+		 * the link down because no IDLES are transmitted
+		 */
+	}
+	else {
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("InitPhyBcom: with auto-negotiation Port %d\n", Port));
+		/* Set Auto-negotiation advertisement */
+
+		/*
+		 * Workaround BCOM Errata #1 for the C5 type.
+		 * 1000Base-T Link Acquisition Failure in Slave Mode
+		 * Set Repeater/DTE bit 10 of the 1000Base-T Control Register
+		 */
+		Ctrl2 |= PHY_B_1000C_RD;
+		
+		 /* Set Full/half duplex capabilities */
+		switch (pPrt->PLinkMode) {
+		case SK_LMODE_AUTOHALF:
+			Ctrl2 |= PHY_B_1000C_AHD;
+			break;
+		case SK_LMODE_AUTOFULL:
+			Ctrl2 |= PHY_B_1000C_AFD;
+			break;
+		case SK_LMODE_AUTOBOTH:
+			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);
+		}
+
+		switch (pPrt->PFlowCtrlMode) {
+		case SK_FLOW_MODE_NONE:
+			Ctrl3 |= PHY_B_P_NO_PAUSE;
+			break;
+		case SK_FLOW_MODE_LOC_SEND:
+			Ctrl3 |= PHY_B_P_ASYM_MD;
+			break;
+		case SK_FLOW_MODE_SYMMETRIC:
+			Ctrl3 |= PHY_B_P_SYM_MD;
+			break;
+		case SK_FLOW_MODE_SYM_OR_REM:
+			Ctrl3 |= PHY_B_P_BOTH_MD;
+			break;
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016,
+				SKERR_HWI_E016MSG);
+		}
+
+		/* Restart Auto-negotiation */
+		Ctrl1 |= PHY_CT_ANE | PHY_CT_RE_CFG;
+	}
+	
+	/* Initialize LED register here? */
+	/* No. Please do it in SkDgXmitLed() (if required) and swap
+	   init order of LEDs and XMAC. (MAl) */
+	
+	/* Write 1000Base-T Control Register */
+	SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_1000T_CTRL, Ctrl2);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("1000B-T Ctrl Reg=0x%04X\n", Ctrl2));
+	
+	/* Write AutoNeg Advertisement Register */
+	SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_AUNE_ADV, Ctrl3);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("Auto-Neg. Adv. Reg=0x%04X\n", Ctrl3));
+	
+	if (DoLoop) {
+		/* Set the Phy Loopback bit, too */
+		Ctrl1 |= PHY_CT_LOOP;
+	}
+
+	if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) {
+		/* configure FIFO to high latency for transmission of ext. packets */
+		Ctrl4 |= PHY_B_PEC_HIGH_LA;
+
+		/* configure reception of extended packets */
+		Ctrl5 |= PHY_B_AC_LONG_PACK;
+
+		SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, Ctrl5);
+	}
+
+	/* Configure LED Traffic Mode and Jumbo Frame usage if specified */
+	SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_P_EXT_CTRL, Ctrl4);
+	
+	/* Write to the Phy control register */
+	SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_CTRL, Ctrl1);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("PHY Control Reg=0x%04X\n", Ctrl1));
+}	/* SkXmInitPhyBcom */
+
+
+/******************************************************************************
+ *
+ *	SkGmInitPhyMarv() - Initialize the Marvell Phy registers
+ *
+ * Description:	initializes all the Marvell Phy registers
+ *
+ * Note:
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkGmInitPhyMarv(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port,		/* Port Index (MAC_1 + n) */
+SK_BOOL	DoLoop)		/* Should a Phy LoopBack be set-up? */
+{
+	SK_GEPORT	*pPrt;
+	SK_U16		PhyCtrl;
+	SK_U16		PhyStat;
+	SK_U16		PhyStat1;
+	SK_U16		PhySpec;
+	SK_U16		C1000BaseT;
+	SK_U16		AutoNegAdv;
+	SK_U16		ExtPhyCtrl;
+
+#ifdef VCPU
+	VCPUprintf(0, "SkGmInitPhyMarv(), Port=%u, DoLoop=%u\n",
+		Port, DoLoop);
+#else /* VCPU */
+	
+	if (!DoLoop) {
+		/* Read Ext. PHY Specific Control */
+		SkGmPhyRead(pAC, IoC, Port, PHY_MARV_EXT_CTRL, &ExtPhyCtrl);
+		
+		ExtPhyCtrl &= ~(PHY_M_EC_M_DSC_MSK | PHY_M_EC_S_DSC_MSK |
+			PHY_M_EC_MAC_S_MSK);
+		
+		ExtPhyCtrl |= PHY_M_EC_M_DSC(1) | PHY_M_EC_S_DSC(1) |
+			PHY_M_EC_MAC_S(MAC_TX_CLK_25_MHZ);
+	
+		SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_CTRL, ExtPhyCtrl);
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("Ext.PHYCtrl=0x%04X\n", ExtPhyCtrl));
+		
+		/* Read PHY Control */
+		SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CTRL, &PhyCtrl);
+		
+		/* Assert software reset */
+		SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, PhyCtrl | PHY_CT_RESET);
+	}
+#endif /* VCPU */
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	PhyCtrl = PHY_CT_COL_TST;
+	C1000BaseT = 0;
+	AutoNegAdv = PHY_SEL_TYPE;
+
+	/* manually Master/Slave ? */
+	if (pPrt->PMSMode != SK_MS_MODE_AUTO) {
+		/* enable Manual Master/Slave */
+		C1000BaseT |= PHY_M_1000C_MSE;
+		
 		if (pPrt->PMSMode == SK_MS_MODE_MASTER) {
-			Ctrl2 |= PHY_B_1000C_MSC;
+			C1000BaseT |= PHY_M_1000C_MSC;	/* set it to Master */
 		}
 	}
-	/* Autonegotiation ? */
-	if (pPrt->PLinkMode == SK_LMODE_HALF ||
-	    pPrt->PLinkMode == SK_LMODE_FULL) {
-		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
-			("InitPhyBcom: no autonegotiation Port %d\n", Port));
-		/* No Autonegiotiation */
-		/* Set DuplexMode in Config register */
-		Ctrl1 |= (pPrt->PLinkMode == SK_LMODE_FULL ? PHY_CT_DUP_MD : 0);
+	
+	/* Auto-negotiation ? */
+	if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("InitPhyMarv: no auto-negotiation Port %d\n", Port));
+		
+		if (pPrt->PLinkMode == SK_LMODE_FULL) {
+			/* Set Full Duplex Mode */
+			PhyCtrl |= PHY_CT_DUP_MD;
+		}
 
-		/* Determine Master/Slave manually if not already done. */
+		/* Set Master/Slave manually if not already done */
 		if (pPrt->PMSMode == SK_MS_MODE_AUTO) {
-			Ctrl2 |= PHY_B_1000C_MSE;	/* set it to Slave */
+			C1000BaseT |= PHY_M_1000C_MSE;	/* set it to Slave */
 		}
 
-		/*
-		 * Do NOT enable Autonegotiation here. This would hold
-		 * the link down because no IDLES are transmitted
-		 */
-	}
-	else {
-		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
-			("InitPhyBcom: with autonegotiation Port %d\n", Port));
-		/* Set Autonegotiation advertisement */
-
-		/* Set Full/half duplex capabilities */
-		switch (pPrt->PLinkMode) {
-		case SK_LMODE_AUTOHALF:
-			Ctrl2 |= PHY_B_1000C_AHD;
+		/* Set Speed */
+		switch (pPrt->PLinkSpeed) {
+		case SK_LSPEED_AUTO:
+		case SK_LSPEED_1000MBPS:
+			PhyCtrl |= PHY_CT_SP1000;
 			break;
-		case SK_LMODE_AUTOFULL:
-			Ctrl2 |= PHY_B_1000C_AFD;
+		case SK_LSPEED_100MBPS:
+			PhyCtrl |= PHY_CT_SP100;
 			break;
-		case SK_LMODE_AUTOBOTH:
-			Ctrl2 |= PHY_B_1000C_AFD | PHY_B_1000C_AHD;
+		case SK_LSPEED_10MBPS:
 			break;
 		default:
-			SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT,
-				SKERR_HWI_E015, SKERR_HWI_E015MSG);
+			SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E019,
+				SKERR_HWI_E019MSG);
 		}
 
-		switch (pPrt->PFlowCtrlMode) {
-		case SK_FLOW_MODE_NONE:
-			Ctrl3 |= PHY_B_P_NO_PAUSE;
-			break;
-		case SK_FLOW_MODE_LOC_SEND:
-			Ctrl3 |= PHY_B_P_ASYM_MD;
-			break;
-		case SK_FLOW_MODE_SYMMETRIC:
-			Ctrl3 |= PHY_B_P_SYM_MD;
-			break;
-		case SK_FLOW_MODE_SYM_OR_REM:
-			Ctrl3 |= PHY_B_P_BOTH_MD;
-			break;
-		default:
-			SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT,
-				SKERR_HWI_E016, SKERR_HWI_E016MSG);
+		if (!DoLoop) {
+			PhyCtrl |= PHY_CT_RESET;
 		}
+		/*
+		 * Do NOT enable Auto-negotiation here. This would hold
+		 * the link down because no IDLES are transmitted
+		 */
+	}
+	else {
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("InitPhyMarv: with auto-negotiation Port %d\n", Port));
+		
+		PhyCtrl |= PHY_CT_ANE;
+		
+		if (pAC->GIni.GICopperType) {
+			/* Set Speed capabilities */
+			switch (pPrt->PLinkSpeed) {
+			case SK_LSPEED_AUTO:
+				C1000BaseT |= PHY_M_1000C_AHD | PHY_M_1000C_AFD;
+				AutoNegAdv |= PHY_M_AN_100_FD | PHY_M_AN_100_HD |
+					PHY_M_AN_10_FD | PHY_M_AN_10_HD;
+				break;
+			case SK_LSPEED_1000MBPS:
+				C1000BaseT |= PHY_M_1000C_AHD | PHY_M_1000C_AFD;
+				break;
+			case SK_LSPEED_100MBPS:
+				AutoNegAdv |= PHY_M_AN_100_FD | PHY_M_AN_100_HD |
+					PHY_M_AN_10_FD | PHY_M_AN_10_HD;
+				break;
+			case SK_LSPEED_10MBPS:
+				AutoNegAdv |= PHY_M_AN_10_FD | PHY_M_AN_10_HD;
+				break;
+			default:
+				SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E019,
+					SKERR_HWI_E019MSG);
+			}
 
-		/* Restart Autonegotiation */
-		Ctrl1 |= PHY_CT_ANE | PHY_CT_RE_CFG;
+			/* Set Full/half duplex capabilities */
+			switch (pPrt->PLinkMode) {
+			case SK_LMODE_AUTOHALF:
+				C1000BaseT &= ~PHY_M_1000C_AFD;
+				AutoNegAdv &= ~(PHY_M_AN_100_FD | PHY_M_AN_10_FD);
+				break;
+			case SK_LMODE_AUTOFULL:
+				C1000BaseT &= ~PHY_M_1000C_AHD;
+				AutoNegAdv &= ~(PHY_M_AN_100_HD | PHY_M_AN_10_HD);
+				break;
+			case SK_LMODE_AUTOBOTH:
+				break;
+			default:
+				SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E015,
+					SKERR_HWI_E015MSG);
+			}
+			
+			/* Set Auto-negotiation advertisement */
+			switch (pPrt->PFlowCtrlMode) {
+			case SK_FLOW_MODE_NONE:
+				AutoNegAdv |= PHY_B_P_NO_PAUSE;
+				break;
+			case SK_FLOW_MODE_LOC_SEND:
+				AutoNegAdv |= PHY_B_P_ASYM_MD;
+				break;
+			case SK_FLOW_MODE_SYMMETRIC:
+				AutoNegAdv |= PHY_B_P_SYM_MD;
+				break;
+			case SK_FLOW_MODE_SYM_OR_REM:
+				AutoNegAdv |= PHY_B_P_BOTH_MD;
+				break;
+			default:
+				SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016,
+					SKERR_HWI_E016MSG);
+			}
+		}
+		else {	/* special defines for FIBER (88E1011S only) */
+			
+			/* Set Full/half duplex capabilities */
+			switch (pPrt->PLinkMode) {
+			case SK_LMODE_AUTOHALF:
+				AutoNegAdv |= PHY_M_AN_1000X_AHD;
+				break;
+			case SK_LMODE_AUTOFULL:
+				AutoNegAdv |= PHY_M_AN_1000X_AFD;
+				break;
+			case SK_LMODE_AUTOBOTH:
+				AutoNegAdv |= PHY_M_AN_1000X_AHD | PHY_M_AN_1000X_AFD;
+				break;
+			default:
+				SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E015,
+					SKERR_HWI_E015MSG);
+			}
+			
+			/* Set Auto-negotiation advertisement */
+			switch (pPrt->PFlowCtrlMode) {
+			case SK_FLOW_MODE_NONE:
+				AutoNegAdv |= PHY_M_P_NO_PAUSE_X;
+				break;
+			case SK_FLOW_MODE_LOC_SEND:
+				AutoNegAdv |= PHY_M_P_ASYM_MD_X;
+				break;
+			case SK_FLOW_MODE_SYMMETRIC:
+				AutoNegAdv |= PHY_M_P_SYM_MD_X;
+				break;
+			case SK_FLOW_MODE_SYM_OR_REM:
+				AutoNegAdv |= PHY_M_P_BOTH_MD_X;
+				break;
+			default:
+				SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016,
+					SKERR_HWI_E016MSG);
+			}
+		}
 
+		if (!DoLoop) {
+			/* Restart Auto-negotiation */
+			PhyCtrl |= PHY_CT_RE_CFG;
+		}
 	}
 	
-	/* Initialize LED register here? */
-	/* No. Please do it in SkDgXmitLed() (if required) and swap
-	   init order of LEDs and XMAC. (MAl) */
+#ifdef VCPU
+	/*
+	 * E-mail from Gu Lin (08-03-2002):
+	 */
+	
+	/* Program PHY register 30 as 16'h0708 for simulation speed up */
+	SkGmPhyWrite(pAC, IoC, Port, 30, 0x0708);
+	
+#if 0
+	/* Program PHY register 20 as 16'h2070 */
+	SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_CTRL, 0x2070);
+#endif /* 0 */
+	
+	VCpuWait(2000);
+
+#else /* VCPU */
 	
 	/* Write 1000Base-T Control Register */
-	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", Ctrl2));
+	SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_1000T_CTRL, C1000BaseT);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("1000B-T Ctrl=0x%04X\n", C1000BaseT));
 	
 	/* Write AutoNeg Advertisement Register */
-	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", Ctrl3));
+	SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_AUNE_ADV, AutoNegAdv);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("Auto-Neg.Ad.=0x%04X\n", AutoNegAdv));
+#endif /* VCPU */
 	
-
 	if (DoLoop) {
-		/* Set the Phy Loopback bit, too */
-		Ctrl1 |= PHY_CT_LOOP;
-	}
-
-	if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) {
-		/* configure fifo to high latency for xmission of ext. packets*/
-		Ctrl4 |= PHY_B_PEC_HIGH_LA;
+		/* Set the PHY Loopback bit */
+		PhyCtrl |= PHY_CT_LOOP;
 
-		/* configure reception of extended packets */
-		Ctrl5 |= PHY_B_AC_LONG_PACK;
+		/* Program PHY register 16 as 16'h0400 to force link good */
+		SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, PHY_M_PC_FL_GOOD);
 
-		PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_AUX_CTRL, Ctrl5);
+#if 0
+		if (pPrt->PLinkSpeed != SK_LSPEED_AUTO) {
+			/* Write Ext. PHY Specific Control */
+			SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_CTRL,
+				(SK_U16)((pPrt->PLinkSpeed + 2) << 4));
+		}
+	}
+	else if (pPrt->PLinkSpeed == SK_LSPEED_10MBPS) {
+			/* Write PHY Specific Control */
+			SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, PHY_M_PC_EN_DET_MSK);
+		}
+#endif /* 0 */
 	}
 
-	/* Configure LED Traffic Mode and Jumbo Frame usage if specified */
-	PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_P_EXT_CTRL, Ctrl4);
+	/* Write to the PHY Control register */
+	SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, PhyCtrl);
+
+#ifdef VCPU
+	VCpuWait(2000);
+#endif /* VCPU */
+
+#ifdef SK_DIAG
+	c_print("PHY Ctrl Val=0x%04X\n", PhyCtrl);
+	c_print("1000 B-T Val=0x%04X\n", C1000BaseT);
+	c_print("Auto-Neg Val=0x%04X\n", AutoNegAdv);
+	c_print("Ext Ctrl Val=0x%04X\n", ExtPhyCtrl);
+#endif /* SK_DIAG */
+
+#ifndef VCPU
+	/* Read PHY Control */
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CTRL, &PhyCtrl);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("PHY Ctrl Reg.=0x%04X\n", PhyCtrl));
 	
-	/* Write to the Phy control register */
-	PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_CTRL, Ctrl1);
-	SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
-		("PHY Control Reg = %x\n", Ctrl1));
-}	/* SkXmInitPhyBcom */
+	/* Read 1000Base-T Control Register */
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_1000T_CTRL, &C1000BaseT);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("1000B-T Ctrl =0x%04X\n", C1000BaseT));
+	
+	/* Read AutoNeg Advertisement Register */
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_AUNE_ADV, &AutoNegAdv);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("Auto-Neg. Ad.=0x%04X\n", AutoNegAdv));
+	
+	/* Read Ext. PHY Specific Control */
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_EXT_CTRL, &ExtPhyCtrl);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("Ext PHY Ctrl=0x%04X\n", ExtPhyCtrl));
+	
+	/* Read PHY Status */
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_STAT, &PhyStat);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("PHY Stat Reg.=0x%04X\n", PhyStat));
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_STAT, &PhyStat1);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("PHY Stat Reg.=0x%04X\n", PhyStat1));
+	
+	/* Read PHY Specific Status */
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_STAT, &PhySpec);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("PHY Spec Stat=0x%04X\n", PhySpec));
+#endif /* VCPU */
+
+#ifdef SK_DIAG
+	c_print("PHY Ctrl Reg=0x%04X\n", PhyCtrl);
+	c_print("PHY 1000 Reg=0x%04X\n", C1000BaseT);
+	c_print("PHY AnAd Reg=0x%04X\n", AutoNegAdv);
+	c_print("Ext Ctrl Reg=0x%04X\n", ExtPhyCtrl);
+	c_print("PHY Stat Reg=0x%04X\n", PhyStat);
+	c_print("PHY Stat Reg=0x%04X\n", PhyStat1);
+	c_print("PHY Spec Reg=0x%04X\n", PhySpec);
+#endif /* SK_DIAG */
+
+}	/* SkGmInitPhyMarv */
 
 
+#ifdef OTHER_PHY
 /******************************************************************************
  *
  *	SkXmInitPhyLone() - Initialize the Level One Phy registers
  *
- * Description:
- *	Initialize all the Level One Phy registers
+ * Description:	initializes all the Level One Phy registers
  *
  * Note:
  *
@@ -1337,14 +2580,14 @@
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
 int		Port,		/* Port Index (MAC_1 + n) */
-SK_BOOL	DoLoop)		/* Should a Phy LOOback be set-up? */
+SK_BOOL	DoLoop)		/* Should a Phy LoopBack be set-up? */
 {
 	SK_GEPORT	*pPrt;
 	SK_U16		Ctrl1;
 	SK_U16		Ctrl2;
 	SK_U16		Ctrl3;
 
-	Ctrl1 = PHY_L_CT_SP1000;
+	Ctrl1 = PHY_CT_SP1000;
 	Ctrl2 = 0;
 	Ctrl3 = PHY_SEL_TYPE;
 
@@ -1353,39 +2596,36 @@
 	/* manually Master/Slave ? */
 	if (pPrt->PMSMode != SK_MS_MODE_AUTO) {
 		Ctrl2 |= PHY_L_1000C_MSE;
+		
 		if (pPrt->PMSMode == SK_MS_MODE_MASTER) {
 			Ctrl2 |= PHY_L_1000C_MSC;
 		}
 	}
-	/* Autonegotiation ? */
-	if (pPrt->PLinkMode == SK_LMODE_HALF ||
-	    pPrt->PLinkMode == SK_LMODE_FULL) {
+	/* Auto-negotiation ? */
+	if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
 		/*
 		 * level one spec say: "1000Mbps: manual mode not allowed"
 		 * but lets see what happens...
 		 */
-		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT,
-			0, "Level One PHY only works with Autoneg");
-		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
-			("InitPhyLone: no autonegotiation Port %d\n", Port));
-		/* No Autonegiotiation */
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("InitPhyLone: no auto-negotiation Port %d\n", Port));
 		/* Set DuplexMode in Config register */
 		Ctrl1 = (pPrt->PLinkMode == SK_LMODE_FULL ? PHY_CT_DUP_MD : 0);
 
-		/* Determine Master/Slave manually if not already done. */
+		/* Determine Master/Slave manually if not already done */
 		if (pPrt->PMSMode == SK_MS_MODE_AUTO) {
 			Ctrl2 |= PHY_L_1000C_MSE;	/* set it to Slave */
 		}
 
 		/*
-		 * Do NOT enable Autonegotiation here. This would hold
+		 * Do NOT enable Auto-negotiation here. This would hold
 		 * the link down because no IDLES are transmitted
 		 */
 	}
 	else {
-		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
-			("InitPhyLone: with autonegotiation Port %d\n", Port));
-		/* Set Autonegotiation advertisement */
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("InitPhyLone: with auto-negotiation Port %d\n", Port));
+		/* Set Auto-negotiation advertisement */
 
 		/* Set Full/half duplex capabilities */
 		switch (pPrt->PLinkMode) {
@@ -1399,8 +2639,8 @@
 			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);
+			SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E015,
+				SKERR_HWI_E015MSG);
 		}
 
 		switch (pPrt->PFlowCtrlMode) {
@@ -1417,11 +2657,11 @@
 			Ctrl3 |= PHY_L_P_BOTH_MD;
 			break;
 		default:
-			SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT,
-				SKERR_HWI_E016, SKERR_HWI_E016MSG);
+			SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016,
+				SKERR_HWI_E016MSG);
 		}
 
-		/* Restart Autonegotiation */
+		/* Restart Auto-negotiation */
 		Ctrl1 = PHY_CT_ANE | PHY_CT_RE_CFG;
 
 	}
@@ -1431,14 +2671,14 @@
 	   init order of LEDs and XMAC. (MAl) */
 	
 	/* Write 1000Base-T Control Register */
-	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", Ctrl2));
+	SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_1000T_CTRL, Ctrl2);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("1000B-T Ctrl Reg=0x%04X\n", Ctrl2));
 	
 	/* Write AutoNeg Advertisement Register */
-	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", Ctrl3));
+	SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_AUNE_ADV, Ctrl3);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("Auto-Neg. Adv. Reg=0x%04X\n", Ctrl3));
 	
 
 	if (DoLoop) {
@@ -1446,26 +2686,18 @@
 		Ctrl1 |= PHY_CT_LOOP;
 	}
 
-	if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) {
-		/*
-		 * nothing to do for Level one.
-		 * PHY supports frames up to 10k.
-		 */
-	}
-	
 	/* Write to the Phy control register */
-	PHY_WRITE(IoC, pPrt, Port, PHY_LONE_CTRL, Ctrl1);
-	SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
-		("PHY Control Reg = %x\n", Ctrl1));
-}	/* SkXmInitPhyLone*/
+	SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_CTRL, Ctrl1);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("PHY Control Reg=0x%04X\n", Ctrl1));
+}	/* SkXmInitPhyLone */
 
 
 /******************************************************************************
  *
  *	SkXmInitPhyNat() - Initialize the National Phy registers
  *
- * Description:
- *	Initialize all the National Phy registers
+ * Description:	initializes all the National Phy registers
  *
  * Note:
  *
@@ -1476,103 +2708,96 @@
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
 int		Port,		/* Port Index (MAC_1 + n) */
-SK_BOOL	DoLoop)		/* Should a Phy LOOback be set-up? */
+SK_BOOL	DoLoop)		/* Should a Phy LoopBack be set-up? */
 {
 /* todo: National */
-}	/* SkXmInitPhyNat*/
+}	/* SkXmInitPhyNat */
+#endif /* OTHER_PHY */
 
 
 /******************************************************************************
  *
- *	SkXmAutoNegLipaXmac() - Decides whether Link Partner could do autoneg
+ *	SkMacInitPhy() - Initialize the PHY registers
  *
- *	This function analyses the Interrupt status word. If any of the
- *	Autonegotiating interrupt bits are set, the PLipaAutoNeg variable
- *	is set true.
- */
-void	SkXmAutoNegLipaXmac(
-SK_AC	*pAC,		/* adapter context */
-SK_IOC	IoC,		/* IO context */
-int		Port,		/* Port Index (MAC_1 + n) */
-SK_U16	IStatus)	/* Interrupt Status word to analyse */
-{
-	SK_GEPORT	*pPrt;
-
-	pPrt = &pAC->GIni.GP[Port];
-
-	if (pPrt->PLipaAutoNeg != SK_LIPA_AUTO &&
-		(IStatus & (XM_IS_LIPA_RC|XM_IS_RX_PAGE|XM_IS_AND))) {
-
-		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
-			("AutoNegLipa: AutoNeg detected on port %d %x\n", Port, IStatus));
-		pPrt->PLipaAutoNeg = SK_LIPA_AUTO;
-	}
-}	/* SkXmAutoNegLipaXmac*/
-
-
-/******************************************************************************
+ * Description:	calls the Init PHY routines dep. on board type
  *
- *	SkXmAutoNegLipaBcom() - Decides whether Link Partner could do autoneg
+ * Note:
  *
- *	This function analyses the PHY status word. If any of the
- *	Autonegotiating bits are set, The PLipaAutoNeg variable
- *	is set true.
+ * Returns:
+ *	nothing
  */
-void	SkXmAutoNegLipaBcom(
+void SkMacInitPhy(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
 int		Port,		/* Port Index (MAC_1 + n) */
-SK_U16	PhyStat)	/* PHY Status word to analyse */
+SK_BOOL	DoLoop)		/* Should a Phy LoopBack be set-up? */
 {
 	SK_GEPORT	*pPrt;
 
 	pPrt = &pAC->GIni.GP[Port];
 
-	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;
+	switch (pPrt->PhyType) {
+	case SK_PHY_XMAC:
+		SkXmInitPhyXmac(pAC, IoC, Port, DoLoop);
+		break;
+	case SK_PHY_BCOM:
+		SkXmInitPhyBcom(pAC, IoC, Port, DoLoop);
+		break;
+	case SK_PHY_MARV_COPPER:
+	case SK_PHY_MARV_FIBER:
+		SkGmInitPhyMarv(pAC, IoC, Port, DoLoop);
+		break;
+#ifdef OTHER_PHY
+	case SK_PHY_LONE:
+		SkXmInitPhyLone(pAC, IoC, Port, DoLoop);
+		break;
+	case SK_PHY_NAT:
+		SkXmInitPhyNat(pAC, IoC, Port, DoLoop);
+		break;
+#endif /* OTHER_PHY */
 	}
-}	/* SkXmAutoNegLipaBcom*/
+}	/* SkMacInitPhy */
 
 
+#ifndef SK_DIAG
 /******************************************************************************
  *
- *	SkXmAutoNegLipaLone() - Decides whether Link Partner could do autoneg
+ *	SkXmAutoNegLipaXmac() - Decides whether Link Partner could do auto-neg
  *
- *	This function analyses the PHY status word. If any of the
- *	Autonegotiating bits are set, The PLipaAutoNeg variable
+ *	This function analyses the Interrupt status word. If any of the
+ *	Auto-negotiating interrupt bits are set, the PLipaAutoNeg variable
  *	is set true.
  */
-void	SkXmAutoNegLipaLone(
+void SkXmAutoNegLipaXmac(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
-int	Port,		/* Port Index (MAC_1 + n) */
-SK_U16	PhyStat)	/* PHY Status word to analyse */
+int		Port,		/* Port Index (MAC_1 + n) */
+SK_U16	IStatus)	/* Interrupt Status word to analyse */
 {
 	SK_GEPORT	*pPrt;
 
 	pPrt = &pAC->GIni.GP[Port];
 
 	if (pPrt->PLipaAutoNeg != SK_LIPA_AUTO &&
-		(PhyStat & (PHY_ST_AN_OVER))) {
+		(IStatus & (XM_IS_LIPA_RC | XM_IS_RX_PAGE | XM_IS_AND)) != 0) {
 
-		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
-			("AutoNegLipa: AutoNeg detected on port %d %x\n", Port, PhyStat));
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("AutoNegLipa: AutoNeg detected on Port %d, IStatus=0x%04x\n",
+			Port, IStatus));
 		pPrt->PLipaAutoNeg = SK_LIPA_AUTO;
 	}
-}	/* SkXmAutoNegLipaLone*/
+}	/* SkXmAutoNegLipaXmac */
 
 
 /******************************************************************************
  *
- *	SkXmAutoNegLipaNat() - Decides whether Link Partner could do autoneg
+ *	SkMacAutoNegLipaPhy() - Decides whether Link Partner could do auto-neg
  *
- *	This function analyses the PHY status word. If any of the
- *	Autonegotiating bits are set, The PLipaAutoNeg variable
+ *	This function analyses the PHY status word.
+ *  If any of the Auto-negotiating bits are set, the PLipaAutoNeg variable
  *	is set true.
  */
-void	SkXmAutoNegLipaNat(
+void SkMacAutoNegLipaPhy(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
 int		Port,		/* Port Index (MAC_1 + n) */
@@ -1583,67 +2808,30 @@
 	pPrt = &pAC->GIni.GP[Port];
 
 	if (pPrt->PLipaAutoNeg != SK_LIPA_AUTO &&
-		(PhyStat & (PHY_ST_AN_OVER))) {
+		(PhyStat & PHY_ST_AN_OVER) != 0) {
 
-		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
-			("AutoNegLipa: AutoNeg detected on port %d %x\n", Port, PhyStat));
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("AutoNegLipa: AutoNeg detected on Port %d, PhyStat=0x%04x\n",
+			Port, PhyStat));
 		pPrt->PLipaAutoNeg = SK_LIPA_AUTO;
 	}
-}	/* SkXmAutoNegLipaNat*/
-
-
-/******************************************************************************
- *
- *	SkXmAutoNegDone() - Auto negotiation handling
- *
- * Description:
- *	This function handles the autonegotiation if the Done bit is set.
- *
- * Note:
- *	o The XMACs interrupt source register is NOT read here.
- *	o This function is public because it is used in the diagnostics
- *	  tool, too.
- *
- * Returns:
- *	SK_AND_OK	o.k.
- *	SK_AND_DUP_CAP 	Duplex capability error happened
- *	SK_AND_OTHER 	Other error happened
- */
-int	SkXmAutoNegDone(
-SK_AC	*pAC,		/* adapter context */
-SK_IOC	IoC,		/* IO context */
-int		Port)		/* Port Index (MAC_1 + n) */
-{
-	switch (pAC->GIni.GP[Port].PhyType) {
-	case SK_PHY_XMAC:
-		return (SkXmAutoNegDoneXmac(pAC, IoC, Port));
-	case SK_PHY_BCOM:
-		return (SkXmAutoNegDoneBcom(pAC, IoC, Port));
-	case SK_PHY_LONE:
-		return (SkXmAutoNegDoneLone(pAC, IoC, Port));
-	case SK_PHY_NAT:
-		return (SkXmAutoNegDoneNat(pAC, IoC, Port));
-	}
-	return (SK_AND_OTHER);
-}	/* SkXmAutoNegDone*/
+}	/* SkMacAutoNegLipaPhy */
+#endif /* SK_DIAG */
 
 
 /******************************************************************************
  *
- *	SkXmAutoNegDoneXmac() - Auto negotiation handling
+ *	SkXmAutoNegDoneXmac() - Auto-negotiation handling
  *
  * Description:
- *	This function handles the autonegotiation if the Done bit is set.
- *
- * Note:
- *	o The XMACs interrupt source register is NOT read here.
+ *	This function handles the auto-negotiation if the Done bit is set.
  *
  * Returns:
  *	SK_AND_OK	o.k.
  *	SK_AND_DUP_CAP 	Duplex capability error happened
  *	SK_AND_OTHER 	Other error happened
  */
-static int	SkXmAutoNegDoneXmac(
+static int SkXmAutoNegDoneXmac(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
 int		Port)		/* Port Index (MAC_1 + n) */
@@ -1652,22 +2840,22 @@
 	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));
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("AutoNegDoneXmac, Port %d\n",Port));
 
 	pPrt = &pAC->GIni.GP[Port];
 
 	/* Get PHY parameters */
-	PHY_READ(IoC, pPrt, Port, PHY_XMAC_AUNE_LP, &LPAb);
-	PHY_READ(IoC, pPrt, Port, PHY_XMAC_RES_ABI, &ResAb);
+	SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_AUNE_LP, &LPAb);
+	SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_RES_ABI, &ResAb);
 
-	if (LPAb & PHY_X_AN_RFB) {
+	if ((LPAb & PHY_X_AN_RFB) != 0) {
 		/* At least one of the remote fault bit is set */
 		/* Error */
-		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+		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);
+		return(SK_AND_OTHER);
 	}
 
 	/* Check Duplex mismatch */
@@ -1679,10 +2867,10 @@
 	}
 	else {
 		/* Error */
-		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
-			("AutoNegFail: Duplex mode mismatch port %d\n", Port));
+		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);
+		return(SK_AND_DUP_CAP);
 	}
 
 	/* Check PAUSE mismatch */
@@ -1690,7 +2878,7 @@
 	/* We are using IEEE 802.3z/D5.0 Table 37-4 */
 	if ((pPrt->PFlowCtrlMode == SK_FLOW_MODE_SYMMETRIC ||
 	     pPrt->PFlowCtrlMode == SK_FLOW_MODE_SYM_OR_REM) &&
-	    (LPAb & PHY_X_P_SYM_MD)) {
+	    (LPAb & PHY_X_P_SYM_MD) != 0) {
 		/* Symmetric PAUSE */
 		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC;
 	}
@@ -1708,31 +2896,25 @@
 		/* PAUSE mismatch -> no PAUSE */
 		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE;
 	}
+	pPrt->PLinkSpeedUsed = SK_LSPEED_STAT_1000MBPS;
 
-	/* We checked everything and may now enable the link */
-	pPrt->PAutoNegFail = SK_FALSE;
-
-	SkXmRxTxEnable(pAC, IoC, Port);
-	return (SK_AND_OK);
-}	/* SkXmAutoNegDoneXmac*/
+	return(SK_AND_OK);
+}	/* SkXmAutoNegDoneXmac */
 
 
 /******************************************************************************
  *
- *	SkXmAutoNegDoneBcom() - Auto negotiation handling
+ *	SkXmAutoNegDoneBcom() - Auto-negotiation handling
  *
  * Description:
- *	This function handles the autonegotiation if the Done bit is set.
- *
- * Note:
- *	o The XMACs interrupt source register is NOT read here.
+ *	This function handles the auto-negotiation if the Done bit is set.
  *
  * Returns:
  *	SK_AND_OK	o.k.
  *	SK_AND_DUP_CAP 	Duplex capability error happened
  *	SK_AND_OTHER 	Other error happened
  */
-static int	SkXmAutoNegDoneBcom(
+static int SkXmAutoNegDoneBcom(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
 int		Port)		/* Port Index (MAC_1 + n) */
@@ -1746,105 +2928,199 @@
 	SK_U16		ResAb;		/* Resolved Ability */
 #endif	/* 0 */
 
-	SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
 		("AutoNegDoneBcom, Port %d\n", Port));
 	pPrt = &pAC->GIni.GP[Port];
 
-	/* Get PHY parameters. */
-	PHY_READ(IoC, pPrt, Port, PHY_BCOM_AUNE_LP, &LPAb);
+	/* Get PHY parameters */
+	SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_LP, &LPAb);
 #if 0
 01-Sep-2000 RA;:;:
-	PHY_READ(IoC, pPrt, Port, PHY_BCOM_1000T_STAT, &ResAb);
+	SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_STAT, &ResAb);
 #endif	/* 0 */
-	PHY_READ(IoC, pPrt, Port, PHY_BCOM_AUX_STAT, &AuxStat);
+	
+	SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_STAT, &AuxStat);
 
-	if (LPAb & PHY_B_AN_RF) {
-		/* Remote fault bit is set: Error. */
+	if ((LPAb & PHY_B_AN_RF) != 0) {
+		/* 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);
+		return(SK_AND_OTHER);
 	}
 
-	/* Check Duplex mismatch. */
-	if ((AuxStat & PHY_B_AS_AN_RES) == PHY_B_RES_1000FD) {
+	/* Check Duplex mismatch */
+	if ((AuxStat & PHY_B_AS_AN_RES_MSK) == PHY_B_RES_1000FD) {
 		pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOFULL;
 	}
-	else if ((AuxStat & PHY_B_AS_AN_RES) == PHY_B_RES_1000HD) {
+	else if ((AuxStat & PHY_B_AS_AN_RES_MSK) == 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));
+		/* 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);
+		return(SK_AND_DUP_CAP);
 	}
 	
 #if 0
 01-Sep-2000 RA;:;:
-	/* Check Master/Slave resolution. */
-	if (ResAb & PHY_B_1000S_MSF) {
-		/* Error. */
+	/* Check Master/Slave resolution */
+	if ((ResAb & PHY_B_1000S_MSF) != 0) {
 		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
-			("Master/Slave Fault port %d\n", Port));
+			("Master/Slave Fault Port %d\n", Port));
 		pPrt->PAutoNegFail = SK_TRUE;
 		pPrt->PMSStatus = SK_MS_STAT_FAULT;
-		return (SK_AND_OTHER);
+		return(SK_AND_OTHER);
 	}
-	else if (ResAb & PHY_B_1000S_MSR) {
-		pPrt->PMSStatus = SK_MS_STAT_MASTER;
+	
+	pPrt->PMSStatus = ((ResAb & PHY_B_1000S_MSR) != 0) ?
+		SK_MS_STAT_MASTER : SK_MS_STAT_SLAVE;
+#endif	/* 0 */
+
+	/* Check PAUSE mismatch */
+	/* We are using IEEE 802.3z/D5.0 Table 37-4 */
+	if ((AuxStat & PHY_B_AS_PAUSE_MSK) == PHY_B_AS_PAUSE_MSK) {
+		/* Symmetric PAUSE */
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC;
+	}
+	else if ((AuxStat & PHY_B_AS_PAUSE_MSK) == PHY_B_AS_PRR) {
+		/* Enable PAUSE receive, disable PAUSE transmit */
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_REM_SEND;
+	}
+	else if ((AuxStat & PHY_B_AS_PAUSE_MSK) == PHY_B_AS_PRT) {
+		/* Disable PAUSE receive, enable PAUSE transmit */
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_LOC_SEND;
 	}
 	else {
-		pPrt->PMSStatus = SK_MS_STAT_SLAVE;
+		/* PAUSE mismatch -> no PAUSE */
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE;
+	}
+	pPrt->PLinkSpeedUsed = SK_LSPEED_STAT_1000MBPS;
+
+	return(SK_AND_OK);
+}	/* SkXmAutoNegDoneBcom */
+
+
+/******************************************************************************
+ *
+ *	SkGmAutoNegDoneMarv() - Auto-negotiation handling
+ *
+ * Description:
+ *	This function handles the auto-negotiation if the Done bit is set.
+ *
+ * Returns:
+ *	SK_AND_OK	o.k.
+ *	SK_AND_DUP_CAP 	Duplex capability error happened
+ *	SK_AND_OTHER 	Other error happened
+ */
+static int SkGmAutoNegDoneMarv(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+	SK_U16		LPAb;		/* Link Partner Ability */
+	SK_U16		ResAb;		/* Resolved Ability */
+	SK_U16		AuxStat;	/* Auxiliary Status */
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("AutoNegDoneMarv, Port %d\n", Port));
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* Get PHY parameters */
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_AUNE_LP, &LPAb);
+	
+	if ((LPAb & PHY_B_AN_RF) != 0) {
+		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);
+	}
+
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_1000T_STAT, &ResAb);
+	
+	/* Check Master/Slave resolution */
+	if ((ResAb & PHY_B_1000S_MSF) != 0) {
+		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);
+	}
+	
+	pPrt->PMSStatus = ((ResAb & PHY_B_1000S_MSR) != 0) ?
+		(SK_U8)SK_MS_STAT_MASTER : (SK_U8)SK_MS_STAT_SLAVE;
+	
+	/* Read PHY Specific Status */
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_STAT, &AuxStat);
+	
+	/* Check Speed & Duplex resolved */
+	if ((AuxStat & PHY_M_PS_SPDUP_RES) == 0) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("AutoNegFail: Speed & Duplex not resolved Port %d\n", Port));
+		pPrt->PAutoNegFail = SK_TRUE;
+		pPrt->PLinkModeStatus = SK_LMODE_STAT_UNKNOWN;
+		return(SK_AND_DUP_CAP);
+	}
+	
+	if ((AuxStat & PHY_M_PS_FULL_DUP) != 0) {
+		pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOFULL;
+	}
+	else {
+		pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOHALF;
 	}
-#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. */
-	if ((AuxStat & (PHY_B_AS_PRR | PHY_B_AS_PRT)) == 
-		(PHY_B_AS_PRR | PHY_B_AS_PRT)) {
-		/* Symmetric PAUSE. */
+	
+	/* Check PAUSE mismatch */
+	/* We are using IEEE 802.3z/D5.0 Table 37-4 */
+	if ((AuxStat & PHY_M_PS_PAUSE_MSK) == PHY_M_PS_PAUSE_MSK) {
+		/* 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_M_PS_PAUSE_MSK) == PHY_M_PS_RX_P_EN) {
+		/* 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_M_PS_PAUSE_MSK) == PHY_M_PS_TX_P_EN) {
+		/* Disable PAUSE receive, enable PAUSE transmit */
 		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_LOC_SEND;
 	}
 	else {
-		/* PAUSE mismatch -> no PAUSE. */
+		/* PAUSE mismatch -> no PAUSE */
 		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE;
 	}
+	
+	/* set used link speed */
+	switch ((unsigned)(AuxStat & PHY_M_PS_SPEED_MSK)) {
+	case (unsigned)PHY_M_PS_SPEED_1000:
+		pPrt->PLinkSpeedUsed = SK_LSPEED_STAT_1000MBPS;
+		break;
+	case PHY_M_PS_SPEED_100:
+		pPrt->PLinkSpeedUsed = SK_LSPEED_STAT_100MBPS;
+		break;
+	default:
+		pPrt->PLinkSpeedUsed = SK_LSPEED_STAT_10MBPS;
+	}
 
-	/* We checked everything and may now enable the link. */
-	pPrt->PAutoNegFail = SK_FALSE;
-
-	SkXmRxTxEnable(pAC, IoC, Port);
-	return (SK_AND_OK);
-}	/* SkXmAutoNegDoneBcom*/
+	return(SK_AND_OK);
+}	/* SkGmAutoNegDoneMarv */
 
 
+#ifdef OTHER_PHY
 /******************************************************************************
  *
- *	SkXmAutoNegDoneLone() - Auto negotiation handling
+ *	SkXmAutoNegDoneLone() - Auto-negotiation handling
  *
  * Description:
- *	This function handles the autonegotiation if the Done bit is set.
- *
- * Note:
- *	o The XMACs interrupt source register is NOT read here.
+ *	This function handles the auto-negotiation if the Done bit is set.
  *
  * Returns:
  *	SK_AND_OK	o.k.
  *	SK_AND_DUP_CAP 	Duplex capability error happened
  *	SK_AND_OTHER 	Other error happened
  */
-static int	SkXmAutoNegDoneLone(
+static int SkXmAutoNegDoneLone(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
 int		Port)		/* Port Index (MAC_1 + n) */
@@ -1854,26 +3130,26 @@
 	SK_U16		LPAb;		/* Link Partner Ability */
 	SK_U16		QuickStat;	/* Auxiliary Status */
 
-	SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, ("AutoNegDoneLone"
-		"Port %d\n",Port));
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("AutoNegDoneLone, Port %d\n",Port));
 	pPrt = &pAC->GIni.GP[Port];
 
 	/* Get PHY parameters */
-	PHY_READ(IoC, pPrt, Port, PHY_LONE_AUNE_LP, &LPAb);
-	PHY_READ(IoC, pPrt, Port, PHY_LONE_1000T_STAT, &ResAb);
-	PHY_READ(IoC, pPrt, Port, PHY_LONE_Q_STAT, &QuickStat);
+	SkXmPhyRead(pAC, IoC, Port, PHY_LONE_AUNE_LP, &LPAb);
+	SkXmPhyRead(pAC, IoC, Port, PHY_LONE_1000T_STAT, &ResAb);
+	SkXmPhyRead(pAC, IoC, Port, PHY_LONE_Q_STAT, &QuickStat);
 
-	if (LPAb & PHY_L_AN_RF) {
+	if ((LPAb & PHY_L_AN_RF) != 0) {
 		/* Remote fault bit is set */
 		/* Error */
-		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
+		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);
+		return(SK_AND_OTHER);
 	}
 
 	/* Check Duplex mismatch */
-	if (QuickStat & PHY_L_QS_DUP_MOD) {
+	if ((QuickStat & PHY_L_QS_DUP_MOD) != 0) {
 		pPrt->PLinkModeStatus = SK_LMODE_STAT_AUTOFULL;
 	}
 	else {
@@ -1881,13 +3157,13 @@
 	}
 	
 	/* Check Master/Slave resolution */
-	if (ResAb & (PHY_L_1000S_MSF)) {
+	if ((ResAb & PHY_L_1000S_MSF) != 0) {
 		/* Error */
-		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL,
-			("Master/Slave Fault port %d\n", Port));
+		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_AND_OTHER);
 	}
 	else if (ResAb & PHY_L_1000S_MSR) {
 		pPrt->PMSStatus = SK_MS_STAT_MASTER;
@@ -1897,7 +3173,6 @@
 	}
 
 	/* 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 */
 	/* we must manually resolve the abilities here */
 	pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE;
@@ -1913,7 +3188,7 @@
 		}
 		break;
 	case SK_FLOW_MODE_SYMMETRIC:
-		if ((QuickStat & PHY_L_QS_PAUSE) == PHY_L_QS_PAUSE) {
+		if ((QuickStat & PHY_L_QS_PAUSE) != 0) {
 			/* Symmetric PAUSE */
 			pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC;
 		}
@@ -1924,154 +3199,545 @@
 			/* Enable PAUSE receive, disable PAUSE transmit */
 			pPrt->PFlowCtrlStatus = SK_FLOW_STAT_REM_SEND;
 		}
-		else if ((QuickStat & PHY_L_QS_PAUSE) == PHY_L_QS_PAUSE) {
+		else if ((QuickStat & PHY_L_QS_PAUSE) != 0) {
 			/* Symmetric PAUSE */
 			pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC;
 		}
 		break;
 	default:
-		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT,
-			SKERR_HWI_E016, SKERR_HWI_E016MSG);
+		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016,
+			SKERR_HWI_E016MSG);
 	}
-
-	/* 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);
 }	/* SkXmAutoNegDoneLone */
 
 
 /******************************************************************************
  *
- *	SkXmAutoNegDoneNat() - Auto negotiation handling
+ *	SkXmAutoNegDoneNat() - Auto-negotiation handling
  *
  * Description:
- *	This function handles the autonegotiation if the Done bit is set.
- *
- * Note:
- *	o The XMACs interrupt source register is NOT read here.
- *	o This function is public because it is used in the diagnostics
- *	  tool, too.
+ *	This function handles the auto-negotiation if the Done bit is set.
  *
  * Returns:
  *	SK_AND_OK	o.k.
  *	SK_AND_DUP_CAP 	Duplex capability error happened
  *	SK_AND_OTHER 	Other error happened
  */
-static int	SkXmAutoNegDoneNat(
+static int SkXmAutoNegDoneNat(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
 int		Port)		/* Port Index (MAC_1 + n) */
 {
 /* todo: National */
-	return (SK_AND_OK);
-}	/* SkXmAutoNegDoneNat*/
+	return(SK_AND_OK);
+}	/* SkXmAutoNegDoneNat */
+#endif /* OTHER_PHY */
+
+
+/******************************************************************************
+ *
+ *	SkMacAutoNegDone() - Auto-negotiation handling
+ *
+ * Description:	calls the auto-negotiation done routines dep. on board type
+ *
+ * Returns:
+ *	SK_AND_OK	o.k.
+ *	SK_AND_DUP_CAP 	Duplex capability error happened
+ *	SK_AND_OTHER 	Other error happened
+ */
+int	SkMacAutoNegDone(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+	int	Rtv;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	switch (pPrt->PhyType) {
+	case SK_PHY_XMAC:
+		Rtv = SkXmAutoNegDoneXmac(pAC, IoC, Port);
+		break;
+	case SK_PHY_BCOM:
+		Rtv = SkXmAutoNegDoneBcom(pAC, IoC, Port);
+		break;
+	case SK_PHY_MARV_COPPER:
+	case SK_PHY_MARV_FIBER:
+		Rtv = SkGmAutoNegDoneMarv(pAC, IoC, Port);
+		break;
+#ifdef OTHER_PHY
+	case SK_PHY_LONE:
+		Rtv = SkXmAutoNegDoneLone(pAC, IoC, Port);
+		break;
+	case SK_PHY_NAT:
+		Rtv = SkXmAutoNegDoneNat(pAC, IoC, Port);
+		break;
+#endif /* OTHER_PHY */
+	default:
+		return(SK_AND_OTHER);
+	}
+	
+	if (Rtv != SK_AND_OK) {
+		return(Rtv);
+	}
+
+	/* We checked everything and may now enable the link */
+	pPrt->PAutoNegFail = SK_FALSE;
+
+	SkMacRxTxEnable(pAC, IoC, Port);
+	
+	return(SK_AND_OK);
+}	/* SkMacAutoNegDone */
 
 
 /******************************************************************************
  *
- *	SkXmRxTxEnable() - Enable RxTx activity if port is up
+ *	SkXmSetRxTxEn() - Special Set Rx/Tx Enable and some features in XMAC
  *
  * Description:
+ *  sets MAC or PHY LoopBack and Duplex Mode in the MMU Command Reg.
+ *  enables Rx/Tx
  *
- * Note:
- *	o The XMACs interrupt source register is NOT read here.
+ * Returns: N/A
+ */
+static void SkXmSetRxTxEn(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* IO context */
+int		Port,		/* Port Index (MAC_1 + n) */
+int		Para)		/* Parameter to set: MAC or PHY LoopBack, Duplex Mode */
+{
+	SK_U16	Word;
+
+	XM_IN16(IoC, Port, XM_MMU_CMD, &Word);
+
+	switch (Para & (SK_MAC_LOOPB_ON | SK_MAC_LOOPB_OFF)) {
+	case SK_MAC_LOOPB_ON:
+		Word |= XM_MMU_MAC_LB;
+		break;
+	case SK_MAC_LOOPB_OFF:
+		Word &= ~XM_MMU_MAC_LB;
+		break;
+	}
+
+	switch (Para & (SK_PHY_LOOPB_ON | SK_PHY_LOOPB_OFF)) {
+	case SK_PHY_LOOPB_ON:
+		Word |= XM_MMU_GMII_LOOP;
+		break;
+	case SK_PHY_LOOPB_OFF:
+		Word &= ~XM_MMU_GMII_LOOP;
+		break;
+	}
+	
+	switch (Para & (SK_PHY_FULLD_ON | SK_PHY_FULLD_OFF)) {
+	case SK_PHY_FULLD_ON:
+		Word |= XM_MMU_GMII_FD;
+		break;
+	case SK_PHY_FULLD_OFF:
+		Word &= ~XM_MMU_GMII_FD;
+		break;
+	}
+	
+	XM_OUT16(IoC, Port, XM_MMU_CMD, Word | XM_MMU_ENA_RX | XM_MMU_ENA_TX);
+
+	/* dummy read to ensure writing */
+	XM_IN16(IoC, Port, XM_MMU_CMD, &Word);
+
+}	/* SkXmSetRxTxEn */
+
+
+/******************************************************************************
+ *
+ *	SkGmSetRxTxEn() - Special Set Rx/Tx Enable and some features in GMAC
+ *
+ * Description:
+ *  sets MAC LoopBack and Duplex Mode in the General Purpose Control Reg.
+ *  enables Rx/Tx
+ *
+ * Returns: N/A
+ */
+static void SkGmSetRxTxEn(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* IO context */
+int		Port,		/* Port Index (MAC_1 + n) */
+int		Para)		/* Parameter to set: MAC LoopBack, Duplex Mode */
+{
+	SK_U16	Ctrl;
+	
+	GM_IN16(IoC, Port, GM_GP_CTRL, &Ctrl);
+
+	switch (Para & (SK_MAC_LOOPB_ON | SK_MAC_LOOPB_OFF)) {
+	case SK_MAC_LOOPB_ON:
+		Ctrl |= GM_GPCR_LOOP_ENA;
+		break;
+	case SK_MAC_LOOPB_OFF:
+		Ctrl &= ~GM_GPCR_LOOP_ENA;
+		break;
+	}
+
+	switch (Para & (SK_PHY_FULLD_ON | SK_PHY_FULLD_OFF)) {
+	case SK_PHY_FULLD_ON:
+		Ctrl |= GM_GPCR_DUP_FULL;
+		break;
+	case SK_PHY_FULLD_OFF:
+		Ctrl &= ~GM_GPCR_DUP_FULL;
+		break;
+	}
+	
+	GM_OUT16(IoC, Port, GM_GP_CTRL, Ctrl | GM_GPCR_RX_ENA | GM_GPCR_TX_ENA);
+
+	/* dummy read to ensure writing */
+	GM_IN16(IoC, Port, GM_GP_CTRL, &Ctrl);
+
+}	/* SkGmSetRxTxEn */
+
+
+/******************************************************************************
+ *
+ *	SkMacSetRxTxEn() - Special Set Rx/Tx Enable and parameters
+ *
+ * Description:	calls the Special Set Rx/Tx Enable routines dep. on board type
+ *
+ * Returns: N/A
+ */
+void SkMacSetRxTxEn(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* IO context */
+int		Port,		/* Port Index (MAC_1 + n) */
+int		Para)
+{
+	if (pAC->GIni.GIGenesis) {
+		
+		SkXmSetRxTxEn(pAC, IoC, Port, Para);
+	}
+	else {
+		
+		SkGmSetRxTxEn(pAC, IoC, Port, Para);
+	}
+
+}	/* SkMacSetRxTxEn */
+
+
+/******************************************************************************
+ *
+ *	SkMacRxTxEnable() - Enable Rx/Tx activity if port is up
+ *
+ * Description:	enables Rx/Tx dep. on board type
  *
  * Returns:
  *	0	o.k.
  *	!= 0	Error happened
  */
-int SkXmRxTxEnable(
+int SkMacRxTxEnable(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
 int		Port)		/* Port Index (MAC_1 + n) */
 {
 	SK_GEPORT	*pPrt;
-	SK_U16		Reg;		/* 16bit register value */
-	SK_U16		IntMask;	/* XMac interrupt mask */
+	SK_U16		Reg;		/* 16-bit register value */
+	SK_U16		IntMask;	/* MAC interrupt mask */
 	SK_U16		SWord;
 
 	pPrt = &pAC->GIni.GP[Port];
 
 	if (!pPrt->PHWLinkUp) {
 		/* The Hardware link is NOT up */
-		return (0);
+		return(0);
 	}
 
 	if ((pPrt->PLinkMode == SK_LMODE_AUTOHALF ||
 	     pPrt->PLinkMode == SK_LMODE_AUTOFULL ||
 	     pPrt->PLinkMode == SK_LMODE_AUTOBOTH) &&
 	     pPrt->PAutoNegFail) {
-		/* Autonegotiation is not done or failed */
-		return (0);
+		/* Auto-negotiation is not done or failed */
+		return(0);
 	}
 
-	/* Set Dup Mode and Pause Mode */
-	SkXmInitDupMd (pAC, IoC, Port);
-	SkXmInitPauseMd (pAC, IoC, Port);
-
-	/*
-	 * Initialize the Interrupt Mask Register. Default IRQs are...
-	 *	- Link Asynchronous Event
-	 *	- Link Partner requests config
-	 *	- Auto Negotiation Done
-	 *	- Rx Counter Event Overflow
-	 *	- Tx Counter Event Overflow
-	 *	- Transmit FIFO Underrun
-	 */
-	if (pPrt->PhyType == SK_PHY_XMAC) {
+	if (pAC->GIni.GIGenesis) {
+		/* set Duplex Mode and Pause Mode */
+		SkXmInitDupMd(pAC, IoC, Port);
+		
+		SkXmInitPauseMd(pAC, IoC, Port);
+	
+		/*
+		 * Initialize the Interrupt Mask Register. Default IRQs are...
+		 *	- Link Asynchronous Event
+		 *	- Link Partner requests config
+		 *	- Auto Negotiation Done
+		 *	- Rx Counter Event Overflow
+		 *	- Tx Counter Event Overflow
+		 *	- Transmit FIFO Underrun
+		 */
 		IntMask = XM_DEF_MSK;
+
+#ifdef DEBUG
+		/* add IRQ for Receive FIFO Overflow */
+		IntMask &= ~XM_IS_RXF_OV;
+#endif /* DEBUG */
+		
+		if (pPrt->PhyType != SK_PHY_XMAC) {
+			/* disable GP0 interrupt bit */
+			IntMask |= XM_IS_INP_ASS;
+		}
+		XM_OUT16(IoC, Port, XM_IMSK, IntMask);
+	
+		/* get MMU Command Reg. */
+		XM_IN16(IoC, Port, XM_MMU_CMD, &Reg);
+		
+		if (pPrt->PhyType != SK_PHY_XMAC &&
+			(pPrt->PLinkModeStatus == SK_LMODE_STAT_FULL ||
+			 pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOFULL)) {
+			/* set to Full Duplex */
+			Reg |= XM_MMU_GMII_FD;
+		}
+		
+		switch (pPrt->PhyType) {
+		case SK_PHY_BCOM:
+			/*
+			 * Workaround BCOM Errata (#10523) for all BCom Phys
+			 * Enable Power Management after link up
+			 */
+			SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, &SWord);
+			SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_AUX_CTRL,
+				(SK_U16)(SWord & ~PHY_B_AC_DIS_PM));
+			SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK);
+			break;
+#ifdef OTHER_PHY
+		case SK_PHY_LONE:
+			SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_INT_ENAB, PHY_L_DEF_MSK);
+			break;
+		case SK_PHY_NAT:
+			/* todo National:
+			SkXmPhyWrite(pAC, IoC, Port, PHY_NAT_INT_MASK, PHY_N_DEF_MSK); */
+			/* no interrupts possible from National ??? */
+			break;
+#endif /* OTHER_PHY */
+		}
+		
+		/* enable Rx/Tx */
+		XM_OUT16(IoC, Port, XM_MMU_CMD, Reg | XM_MMU_ENA_RX | XM_MMU_ENA_TX);
 	}
 	else {
-		/* disable GP0 interrupt bit */
-		IntMask = XM_DEF_MSK | XM_IS_INP_ASS;
+		/*
+		 * Initialize the Interrupt Mask Register. Default IRQs are...
+		 *	- Rx Counter Event Overflow
+		 *	- Tx Counter Event Overflow
+		 *	- Transmit FIFO Underrun
+		 */
+		IntMask = GMAC_DEF_MSK;
+
+#ifdef DEBUG
+		/* add IRQ for Receive FIFO Overrun */
+		IntMask |= GM_IS_RX_FF_OR;
+#endif /* DEBUG */
+		
+		SK_OUT8(IoC, GMAC_IRQ_MSK, (SK_U8)IntMask);
+		
+		/* get General Purpose Control */
+		GM_IN16(IoC, Port, GM_GP_CTRL, &Reg);
+		
+		if (pPrt->PLinkModeStatus == SK_LMODE_STAT_FULL ||
+			pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOFULL) {
+			/* set to Full Duplex */
+			Reg |= GM_GPCR_DUP_FULL;
+		}
+		
+		/* enable Rx/Tx */
+		GM_OUT16(IoC, Port, GM_GP_CTRL, Reg | GM_GPCR_RX_ENA | GM_GPCR_TX_ENA);
+
+#ifndef VCPU
+		/* Enable all PHY interrupts */
+		SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK);
+#endif /* VCPU */
 	}
-	XM_OUT16(IoC, Port, XM_IMSK, IntMask);
+					
+	return(0);
+
+}	/* SkMacRxTxEnable */
+
+
+/******************************************************************************
+ *
+ *	SkMacRxTxDisable() - Disable Receiver and Transmitter
+ *
+ * Description:	disables Rx/Tx dep. on board type
+ *
+ * Returns: N/A
+ */
+void SkMacRxTxDisable(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* IO context */
+int		Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_U16	Word;
 
-	/* RX/TX enable */
-	XM_IN16(IoC, Port, XM_MMU_CMD, &Reg);
-	if (pPrt->PhyType != SK_PHY_XMAC &&
-		(pPrt->PLinkModeStatus == SK_LMODE_STAT_FULL || 
-		 pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOFULL)) {
-		Reg |= XM_MMU_GMII_FD;
+	if (pAC->GIni.GIGenesis) {
+		
+		XM_IN16(IoC, Port, XM_MMU_CMD, &Word);
+		
+		XM_OUT16(IoC, Port, XM_MMU_CMD, Word & ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX));
+	
+		/* dummy read to ensure writing */
+		XM_IN16(IoC, Port, XM_MMU_CMD, &Word);
 	}
-	switch (pPrt->PhyType) {
-	case SK_PHY_BCOM:
-		/* 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);
-		break;
-	case SK_PHY_LONE:
-		PHY_WRITE(IoC, pPrt, Port, PHY_LONE_INT_ENAB, PHY_L_DEF_MSK);
-		break;
-	case SK_PHY_NAT:
-		/* todo National:
-		PHY_WRITE(IoC, pPrt, Port, PHY_NAT_INT_MASK, 
-			PHY_N_DEF_MSK); */
-		/* no interrupts possible from National ??? */
-		break;
+	else {
+		
+		GM_IN16(IoC, Port, GM_GP_CTRL, &Word);
+
+		GM_OUT16(IoC, Port, GM_GP_CTRL, Word & ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA));
+
+		/* dummy read to ensure writing */
+		GM_IN16(IoC, Port, GM_GP_CTRL, &Word);
+	}
+}	/* SkMacRxTxDisable */
+
+
+/******************************************************************************
+ *
+ *	SkMacIrqDisable() - Disable IRQ from MAC
+ *
+ * Description:	sets the IRQ-mask to disable IRQ dep. on board type
+ *
+ * Returns: N/A
+ */
+void SkMacIrqDisable(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* IO context */
+int		Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+	SK_U16		Word;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (pAC->GIni.GIGenesis) {
+		
+		/* disable all XMAC IRQs */
+		XM_OUT16(IoC, Port, XM_IMSK, 0xffff);	
+		
+		/* Disable all PHY interrupts */
+		switch (pPrt->PhyType) {
+			case SK_PHY_BCOM:
+				/* Make sure that PHY is initialized */
+				if (pPrt->PState != SK_PRT_RESET) {
+					/* NOT allowed if BCOM is in RESET state */
+					/* Workaround BCOM Errata (#10523) all BCom */
+					/* Disable Power Management if link is down */
+					SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, &Word);
+					SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_AUX_CTRL,
+						(SK_U16)(Word | PHY_B_AC_DIS_PM));
+					SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_INT_MASK, 0xffff);
+				}
+				break;
+#ifdef OTHER_PHY
+			case SK_PHY_LONE:
+				SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_INT_ENAB, 0);
+				break;
+			case SK_PHY_NAT:
+				/* todo: National
+				SkXmPhyWrite(pAC, IoC, Port, PHY_NAT_INT_MASK, 0xffff); */
+				break;
+#endif /* OTHER_PHY */
+		}
+	}
+	else {
+		/* disable all GMAC IRQs */
+		SK_OUT8(IoC, GMAC_IRQ_MSK, 0);
+		
+#ifndef VCPU
+		/* Disable all PHY interrupts */
+		SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_INT_MASK, 0);
+#endif /* VCPU */
+	}
+}	/* SkMacIrqDisable */
+
+
+#ifdef SK_DIAG
+/******************************************************************************
+ *
+ *	SkXmSendCont() - Enable / Disable Send Continuous Mode
+ *
+ * Description:	enable / disable Send Continuous Mode on XMAC
+ *
+ * Returns:
+ *	nothing
+ */
+void SkXmSendCont(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port,	/* Port Index (MAC_1 + n) */
+SK_BOOL	Enable)	/* Enable / Disable */
+{
+	SK_U32	MdReg;
+
+	XM_IN32(IoC, Port, XM_MODE, &MdReg);
+
+	if (Enable) {
+		MdReg |= XM_MD_TX_CONT;
+	}
+	else {
+		MdReg &= ~XM_MD_TX_CONT;
+	}
+	/* setup Mode Register */
+	XM_OUT32(IoC, Port, XM_MODE, MdReg);
+
+}	/* SkXmSendCont*/
+
+/******************************************************************************
+ *
+ *	SkMacTimeStamp() - Enable / Disable Time Stamp
+ *
+ * Description:	enable / disable Time Stamp generation for Rx packets
+ *
+ * Returns:
+ *	nothing
+ */
+void SkMacTimeStamp(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port,	/* Port Index (MAC_1 + n) */
+SK_BOOL	Enable)	/* Enable / Disable */
+{
+	SK_U32	MdReg;
+	SK_U8	TimeCtrl;
+
+	if (pAC->GIni.GIGenesis) {
+
+		XM_IN32(IoC, Port, XM_MODE, &MdReg);
+
+		if (Enable) {
+			MdReg |= XM_MD_ATS;
+		}
+		else {
+			MdReg &= ~XM_MD_ATS;
+		}
+		/* setup Mode Register */
+		XM_OUT32(IoC, Port, XM_MODE, MdReg);
+	}
+	else {
+		if (Enable) {
+			TimeCtrl = GMT_ST_START | GMT_ST_CLR_IRQ;
+		}
+		else {
+			TimeCtrl = GMT_ST_STOP | GMT_ST_CLR_IRQ;
+		}
+		/* Start/Stop Time Stamp Timer */
+		SK_OUT8(pAC, GMAC_TI_ST_CTRL, TimeCtrl);
 	}
-	XM_OUT16(IoC, Port, XM_MMU_CMD, Reg | XM_MMU_ENA_RX | XM_MMU_ENA_TX);
-				      
-	return (0);
-}	/* SkXmRxTxEnable*/
+}	/* SkMacTimeStamp*/
 
-#ifndef SK_DIAG
+#else /* SK_DIAG */
 
 /******************************************************************************
  *
- *	SkXmIrq() - Interrupt service routine
+ *	SkXmIrq() - Interrupt Service Routine
  *
- * Description:
- *	Services an Interrupt of the XMAC II
+ * Description:	services an Interrupt Request of the XMAC
  *
  * Note:
- *	The XMACs interrupt source register is NOT read here.
- *	With an external PHY, some interrupt bits are not meaningfull
- *	any more:
+ *	With an external PHY, some interrupt bits are not meaningfull any more:
  *	- LinkAsyncEvent (bit #14)              XM_IS_LNK_AE
  *	- LinkPartnerReqConfig (bit #10)	XM_IS_LIPA_RC
  *	- Page Received (bit #9)		XM_IS_RX_PAGE
@@ -2086,124 +3752,589 @@
 void SkXmIrq(
 SK_AC	*pAC,		/* adapter context */
 SK_IOC	IoC,		/* IO context */
-int		Port,		/* Port Index (MAC_1 + n) */
-SK_U16	IStatus)	/* Interrupt status read from the XMAC */
+int		Port)		/* Port Index (MAC_1 + n) */
 {
 	SK_GEPORT	*pPrt;
 	SK_EVPARA	Para;
+	SK_U16		IStatus;	/* Interrupt status read from the XMAC */
 	SK_U16		IStatus2;
 
 	pPrt = &pAC->GIni.GP[Port];
 	
-	if (pPrt->PhyType != SK_PHY_XMAC) {
+	XM_IN16(IoC, Port, XM_ISRC, &IStatus);
+	
+	/* LinkPartner Auto-negable? */
+	if (pPrt->PhyType == SK_PHY_XMAC) {
+		SkXmAutoNegLipaXmac(pAC, IoC, Port, IStatus);
+	}
+	else {
 		/* mask bits that are not used with ext. PHY */
 		IStatus &= ~(XM_IS_LNK_AE | XM_IS_LIPA_RC |
 			XM_IS_RX_PAGE | XM_IS_TX_PAGE |
 			XM_IS_AND | XM_IS_INP_ASS);
 	}
 	
-	/*
-	 * LinkPartner Autonegable?
-	 */
-	if (pPrt->PhyType == SK_PHY_XMAC) {
-		SkXmAutoNegLipaXmac(pAC, IoC, Port, IStatus);
-	}
-
 	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
-		("XmacIrq Port %d Isr %x\n", Port, IStatus));
+		("XmacIrq Port %d Isr 0x%04x\n", Port, IStatus));
 
 	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) {
+	if ((IStatus & XM_IS_INP_ASS) != 0) {
 		/* 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",
+			("SkXmIrq: Link async. Double check Port %d 0x%04x 0x%04x\n",
 			 Port, IStatus, IStatus2));
 		IStatus &= ~XM_IS_INP_ASS;
 		IStatus |= IStatus2;
-
 	}
 
-	if (IStatus & XM_IS_LNK_AE) {
-		/* not used GP0 is used instead */
+	if ((IStatus & XM_IS_LNK_AE) != 0) {
+		/* not used, GP0 is used instead */
 	}
 
-	if (IStatus & XM_IS_TX_ABORT) {
+	if ((IStatus & XM_IS_TX_ABORT) != 0) {
 		/* not used */
 	}
 
-	if (IStatus & XM_IS_FRC_INT) {
-		/* not used. use ASIC IRQ instead if needed */
+	if ((IStatus & XM_IS_FRC_INT) != 0) {
+		/* not used, use ASIC IRQ instead if needed */
 	}
 
-	if (IStatus & (XM_IS_INP_ASS | XM_IS_LIPA_RC | XM_IS_RX_PAGE)) {
+	if ((IStatus & (XM_IS_INP_ASS | XM_IS_LIPA_RC | XM_IS_RX_PAGE)) != 0) {
 		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);
+		SkTimerStart(pAC, IoC, &pPrt->PWaTimer, SK_WA_INA_TIME,
+			SKGE_HWAC, SK_HWEV_WATIM, Para);
 	}
 
-	if (IStatus & XM_IS_RX_PAGE) {
+	if ((IStatus & XM_IS_RX_PAGE) != 0) {
 		/* not used */
 	}
 
-	if (IStatus & XM_IS_TX_PAGE) {
+	if ((IStatus & XM_IS_TX_PAGE) != 0) {
 		/* not used */
 	}
 
-	if (IStatus & XM_IS_AND) {
-		SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_IRQ,
-			("SkXmIrq: AND on link that is up port %d\n", Port));
+	if ((IStatus & XM_IS_AND) != 0) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+			("SkXmIrq: AND on link that is up Port %d\n", Port));
 	}
 
-	if (IStatus & XM_IS_TSC_OV) {
+	if ((IStatus & XM_IS_TSC_OV) != 0) {
 		/* not used */
 	}
 
-	if (IStatus & XM_IS_RXC_OV) {
-		Para.Para32[0] = (SK_U32) Port;
-		Para.Para32[1] = (SK_U32) IStatus;
+	/* Combined Tx & Rx Counter Overflow SIRQ Event */
+	if ((IStatus & (XM_IS_RXC_OV | XM_IS_TXC_OV)) != 0) {
+		Para.Para32[0] = (SK_U32)Port;
+		Para.Para32[1] = (SK_U32)IStatus;
 		SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_SIRQ_OVERFLOW, Para);
 	}
 
-	if (IStatus & XM_IS_TXC_OV) {
-		Para.Para32[0] = (SK_U32) Port;
-		Para.Para32[1] = (SK_U32) IStatus;
+	if ((IStatus & XM_IS_RXF_OV) != 0) {
+		/* normal situation -> no effect */
+		pPrt->PRxOverCnt++;
+	}
+
+	if ((IStatus & XM_IS_TXF_UR) != 0) {
+		/* may NOT happen -> error log */
+		SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E020, SKERR_SIRQ_E020MSG);
+	}
+
+	if ((IStatus & XM_IS_TX_COMP) != 0) {
+		/* not served here */
+	}
+
+	if ((IStatus & XM_IS_RX_COMP) != 0) {
+		/* not served here */
+	}
+}	/* SkXmIrq */
+
+
+/******************************************************************************
+ *
+ *	SkGmIrq() - Interrupt Service Routine
+ *
+ * Description:	services an Interrupt Request of the GMAC
+ *
+ * Note:
+ *
+ * Returns:
+ *	nothing
+ */
+void SkGmIrq(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+	SK_EVPARA	Para;
+	SK_U8		IStatus;	/* Interrupt status */
+
+	pPrt = &pAC->GIni.GP[Port];
+	
+	SK_IN8(IoC, GMAC_IRQ_SRC, &IStatus);
+	
+	/* LinkPartner Auto-negable? */
+	SkMacAutoNegLipaPhy(pAC, IoC, Port, IStatus);
+	
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+		("GmacIrq Port %d Isr 0x%04x\n", Port, IStatus));
+
+	/* Combined Tx & Rx Counter Overflow SIRQ Event */
+	if (IStatus & (GM_IS_RX_CO_OV | GM_IS_TX_CO_OV)) {
+		/* these IRQs will be cleared by reading GMACs register */
+		Para.Para32[0] = (SK_U32)Port;
+		Para.Para32[1] = (SK_U32)IStatus;
 		SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_SIRQ_OVERFLOW, Para);
 	}
 
-	if (IStatus & XM_IS_RXF_OV) {
-		/* normal situation -> no effect */
+	if (IStatus & GM_IS_RX_FF_OR) {
+		/* clear GMAC Rx FIFO Overrun IRQ */
+		SK_OUT8(IoC, MR_ADDR(Port, RX_GMF_CTRL_T), (SK_U8)GMF_CLI_RX_FO);
+
+		pPrt->PRxOverCnt++;
 	}
 
-	if (IStatus & XM_IS_TXF_UR) {
+	if (IStatus & GM_IS_TX_FF_UR) {
+		/* clear GMAC Tx FIFO Underrun IRQ */
+		SK_OUT8(IoC, MR_ADDR(Port, TX_GMF_CTRL_T), (SK_U8)GMF_CLI_TX_FU);
 		/* may NOT happen -> error log */
-		SK_ERR_LOG(pAC, SK_ERRCL_HW , SKERR_SIRQ_E020,
-			SKERR_SIRQ_E020MSG);
+		SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E020, SKERR_SIRQ_E020MSG);
 	}
 
-	if (IStatus & XM_IS_TX_COMP) {
+	if (IStatus & GM_IS_TX_COMPL) {
 		/* not served here */
 	}
 
-	if (IStatus & XM_IS_RX_COMP) {
+	if (IStatus & GM_IS_RX_COMPL) {
 		/* not served here */
 	}
+}	/* SkGmIrq */
+
+/******************************************************************************
+ *
+ *	SkMacIrq() - Interrupt Service Routine for MAC
+ *
+ * Description:	calls the Interrupt Service Routine dep. on board type
+ *
+ * Returns:
+ *	nothing
+ */
+void SkMacIrq(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port)		/* Port Index (MAC_1 + n) */
+{
 
-}	/* SkXmIrq*/
+	if (pAC->GIni.GIGenesis) {
+		/* IRQ from XMAC */
+		SkXmIrq(pAC, IoC, Port);
+	}
+	else {
+		/* IRQ from GMAC */
+		SkGmIrq(pAC, IoC, Port);
+	}
+}	/* SkMacIrq */
 
 #endif /* !SK_DIAG */
 
+/******************************************************************************
+ *
+ *	SkXmUpdateStats() - Force the XMAC to output the current statistic
+ *
+ * Description:
+ *	The XMAC holds its statistic internally. To obtain the current
+ *	values a command must be sent so that the statistic data will
+ *	be written to a predefined memory area on the adapter.
+ *
+ * Returns:
+ *	0:  success
+ *	1:  something went wrong
+ */
+int SkXmUpdateStats(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+unsigned int Port)	/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+	SK_U16		StatReg;
+	int			WaitIndex;
+
+	pPrt = &pAC->GIni.GP[Port];
+	WaitIndex = 0;
+
+	/* Send an update command to XMAC specified */
+	XM_OUT16(IoC, Port, XM_STAT_CMD, XM_SC_SNP_TXC | XM_SC_SNP_RXC);
+
+	/*
+	 * It is an auto-clearing register. If the command bits
+	 * went to zero again, the statistics are transferred.
+	 * Normally the command should be executed immediately.
+	 * But just to be sure we execute a loop.
+	 */
+	do {
+
+		XM_IN16(IoC, Port, XM_STAT_CMD, &StatReg);
+		
+		if (++WaitIndex > 10) {
+
+			SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_HWI_E021, SKERR_HWI_E021MSG);
+
+			return(1);
+		}
+	} while ((StatReg & (XM_SC_SNP_TXC | XM_SC_SNP_RXC)) != 0);
+	
+	return(0);
+}	/* SkXmUpdateStats */
+
+/******************************************************************************
+ *
+ *	SkGmUpdateStats() - Force the GMAC to output the current statistic
+ *
+ * Description:
+ *	Empty function for GMAC. Statistic data is accessible in direct way.
+ *
+ * Returns:
+ *	0:  success
+ *	1:  something went wrong
+ */
+int SkGmUpdateStats(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+unsigned int Port)	/* Port Index (MAC_1 + n) */
+{
+	return(0);
+}
+
+/******************************************************************************
+ *
+ *	SkXmMacStatistic() - Get XMAC counter value
+ *
+ * Description:
+ *	Gets the 32bit counter value. Except for the octet counters
+ *	the lower 32bit are counted in hardware and the upper 32bit
+ *	must be counted in software by monitoring counter overflow interrupts.
+ *
+ * Returns:
+ *	0:  success
+ *	1:  something went wrong
+ */
+int SkXmMacStatistic(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+unsigned int Port,	/* Port Index (MAC_1 + n) */
+SK_U16	StatAddr,	/* MIB counter base address */
+SK_U32	*pVal)		/* ptr to return statistic value */
+{
+	if ((StatAddr < XM_TXF_OK) || (StatAddr > XM_RXF_MAX_SZ)) {
+		
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E022, SKERR_HWI_E022MSG);
+		
+		return(1);
+	}
+	
+	XM_IN32(IoC, Port, StatAddr, pVal);
+
+	return(0);
+}	/* SkXmMacStatistic */
+
+/******************************************************************************
+ *
+ *	SkGmMacStatistic() - Get GMAC counter value
+ *
+ * Description:
+ *	Gets the 32bit counter value. Except for the octet counters
+ *	the lower 32bit are counted in hardware and the upper 32bit
+ *	must be counted in software by monitoring counter overflow interrupts.
+ *
+ * Returns:
+ *	0:  success
+ *	1:  something went wrong
+ */
+int SkGmMacStatistic(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+unsigned int Port,	/* Port Index (MAC_1 + n) */
+SK_U16	StatAddr,	/* MIB counter base address */
+SK_U32	*pVal)		/* ptr to return statistic value */
+{
+
+	if ((StatAddr < GM_RXF_UC_OK) || (StatAddr > GM_TXE_FIFO_UR)) {
+		
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E022, SKERR_HWI_E022MSG);
+		
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("SkGmMacStat: wrong MIB counter 0x%04X\n", StatAddr));
+		return(1);
+	}
+		
+	GM_IN32(IoC, Port, StatAddr, pVal);
+
+	return(0);
+}	/* SkGmMacStatistic */
+
+/******************************************************************************
+ *
+ *	SkXmResetCounter() - Clear MAC statistic counter
+ *
+ * Description:
+ *	Force the XMAC to clear its statistic counter.
+ *
+ * Returns:
+ *	0:  success
+ *	1:  something went wrong
+ */
+int SkXmResetCounter(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+unsigned int Port)	/* Port Index (MAC_1 + n) */
+{
+	XM_OUT16(IoC, Port, XM_STAT_CMD, XM_SC_CLR_RXC | XM_SC_CLR_TXC);
+	/* Clear two times according to Errata #3 */
+	XM_OUT16(IoC, Port, XM_STAT_CMD, XM_SC_CLR_RXC | XM_SC_CLR_TXC);
+
+	return(0);
+}	/* SkXmResetCounter */
+
+/******************************************************************************
+ *
+ *	SkGmResetCounter() - Clear MAC statistic counter
+ *
+ * Description:
+ *	Force GMAC to clear its statistic counter.
+ *
+ * Returns:
+ *	0:  success
+ *	1:  something went wrong
+ */
+int SkGmResetCounter(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+unsigned int Port)	/* Port Index (MAC_1 + n) */
+{
+	SK_U16	Reg;	/* Phy Address Register */
+	SK_U16	Word;
+	int		i;
+
+	GM_IN16(IoC, Port, GM_PHY_ADDR, &Reg);
+
+#ifndef VCPU
+	/* set MIB Clear Counter Mode */
+	GM_OUT16(IoC, Port, GM_PHY_ADDR, Reg | GM_PAR_MIB_CLR);
+	
+	/* read all MIB Counters with Clear Mode set */
+	for (i = 0; i < GM_MIB_CNT_SIZE; i++) {
+		/* the reset is performed only when the lower 16 bits are read */
+		GM_IN16(IoC, Port, GM_MIB_CNT_BASE + 8*i, &Word);
+	}
+	
+	/* clear MIB Clear Counter Mode */
+	GM_OUT16(IoC, Port, GM_PHY_ADDR, Reg);
+#endif /* !VCPU */
+	
+	return(0);
+}	/* SkGmResetCounter */
+
+/******************************************************************************
+ *
+ *	SkXmOverflowStatus() - Gets the status of counter overflow interrupt
+ *
+ * Description:
+ *	Checks the source causing an counter overflow interrupt. On success the
+ *	resulting counter overflow status is written to <pStatus>, whereas the
+ *	upper dword stores the XMAC ReceiveCounterEvent register and the lower
+ *	dword the XMAC TransmitCounterEvent register.
+ *
+ * Note:
+ *	For XMAC the interrupt source is a self-clearing register, so the source
+ *	must be checked only once. SIRQ module does another check to be sure
+ *	that no interrupt get lost during process time.
+ *
+ * Returns:
+ *	0:  success
+ *	1:  something went wrong
+ */
+int SkXmOverflowStatus(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+unsigned int Port,	/* Port Index (MAC_1 + n) */
+SK_U16  IStatus,	/* Interupt Status from MAC */
+SK_U64	*pStatus)	/* ptr for return overflow status value */
+{
+	SK_U64	Status;	/* Overflow status */
+	SK_U32	RegVal;
+
+	Status = 0;
+
+	if ((IStatus & XM_IS_RXC_OV) != 0) {
+
+		XM_IN32(IoC, Port, XM_RX_CNT_EV, &RegVal);
+		Status |= (SK_U64)RegVal << 32;
+	}
+	
+	if ((IStatus & XM_IS_TXC_OV) != 0) {
+
+		XM_IN32(IoC, Port, XM_TX_CNT_EV, &RegVal);
+		Status |= (SK_U64)RegVal;
+	}
+
+	*pStatus = Status;
+
+	return(0);
+}	/* SkXmOverflowStatus */
+
+
+/******************************************************************************
+ *
+ *	SkGmOverflowStatus() - Gets the status of counter overflow interrupt
+ *
+ * Description:
+ *	Checks the source causing an counter overflow interrupt. On success the
+ *	resulting counter overflow status is written to <pStatus>, whereas the
+ *	the following bit coding is used:
+ *	63:56 - unused
+ *	55:48 - TxRx interrupt register bit7:0
+ *	32:47 - Rx interrupt register
+ *	31:24 - unused
+ *	23:16 - TxRx interrupt register bit15:8
+ *	15:0  - Tx interrupt register
+ *
+ * Returns:
+ *	0:  success
+ *	1:  something went wrong
+ */
+int SkGmOverflowStatus(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+unsigned int Port,	/* Port Index (MAC_1 + n) */
+SK_U16  IStatus,	/* Interupt Status from MAC */
+SK_U64	*pStatus)	/* ptr for return overflow status value */
+{
+	SK_U64	Status;		/* Overflow status */
+	SK_U16	RegVal;
+
+	Status = 0;
+
+	if ((IStatus & GM_IS_RX_CO_OV) != 0) {
+		/* this register is self-clearing after read */
+		GM_IN16(IoC, Port, GM_RX_IRQ_SRC, &RegVal);
+		Status |= (SK_U64)RegVal << 32;
+	}
+	
+	if ((IStatus & GM_IS_TX_CO_OV) != 0) {
+		/* this register is self-clearing after read */
+		GM_IN16(IoC, Port, GM_TX_IRQ_SRC, &RegVal);
+		Status |= (SK_U64)RegVal;
+	}
+	
+	/* this register is self-clearing after read */
+	GM_IN16(IoC, Port, GM_TR_IRQ_SRC, &RegVal);
+	/* Rx overflow interrupt register bits (LoByte)*/
+	Status |= (SK_U64)((SK_U8)RegVal) << 48;
+	/* Tx overflow interrupt register bits (HiByte)*/
+	Status |= (SK_U64)(RegVal >> 8) << 16;
+
+	*pStatus = Status;
+
+	return(0);
+}	/* SkGmOverflowStatus */
+
+/******************************************************************************
+ *
+ *	SkGmCableDiagStatus() - Starts / Gets status of cable diagnostic test
+ *
+ * Description:
+ *  starts the cable diagnostic test if 'StartTest' is true
+ *  gets the results if 'StartTest' is true
+ *
+ * NOTE:	this test is meaningful only when link is down
+ *	
+ * Returns:
+ *	0:  success
+ *	1:	no YUKON copper
+ *	2:	test in progress
+ */
+int SkGmCableDiagStatus(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,   		/* IO context */
+int		Port,		/* Port Index (MAC_1 + n) */
+SK_BOOL	StartTest)	/* flag for start / get result */
+{
+	int		i;
+	SK_U16	RegVal;
+	SK_GEPORT	*pPrt;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (pPrt->PhyType != SK_PHY_MARV_COPPER) {
+		
+		return(1);
+	}
+
+	if (StartTest) {
+		/* only start the cable test */
+		if ((pPrt->PhyId1 & PHY_I1_REV_MSK) < 4) {
+			/* apply TDR workaround from Marvell */
+			SkGmPhyWrite(pAC, IoC, Port, 29, 0x001e);
+			
+			SkGmPhyWrite(pAC, IoC, Port, 30, 0xcc00);
+			SkGmPhyWrite(pAC, IoC, Port, 30, 0xc800);
+			SkGmPhyWrite(pAC, IoC, Port, 30, 0xc400);
+			SkGmPhyWrite(pAC, IoC, Port, 30, 0xc000);
+			SkGmPhyWrite(pAC, IoC, Port, 30, 0xc100);
+		}
+
+		/* set address to 0 for MDI[0] */
+		SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_ADR, 0);
+
+		/* Read Cable Diagnostic Reg */
+		SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CABLE_DIAG, &RegVal);
+
+		/* start Cable Diagnostic Test */
+		SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CABLE_DIAG,
+			RegVal | PHY_M_CABD_ENA_TEST);
+	
+		return(0);
+	}
+	
+	/* Read Cable Diagnostic Reg */
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CABLE_DIAG, &RegVal);
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("PHY Cable Diag.=0x%04X\n", RegVal));
+
+	if ((RegVal & PHY_M_CABD_ENA_TEST) != 0) {
+		/* test is running */
+		return(2);
+	}
+
+	/* get the test results */
+	for (i = 0; i < 4; i++)  {
+		/* set address to i for MDI[i] */
+		SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_ADR, (SK_U16)i);
+
+		/* get Cable Diagnostic values */
+		SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CABLE_DIAG, &RegVal);
+
+		pPrt->PMdiPairLen[i] = (SK_U8)(RegVal & PHY_M_CABD_DIST_MSK);
+
+		pPrt->PMdiPairSts[i] = (SK_U8)((RegVal & PHY_M_CABD_STAT_MSK) >> 13);
+	}
+
+	return(0);
+}	/* SkGmCableDiagStatus */
+
 /* End of file */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sk_g16.c linux-2.4.21-pre6/drivers/net/sk_g16.c
--- linux-2.4.20/drivers/net/sk_g16.c	2001-10-17 04:56:29.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sk_g16.c	2003-03-26 23:49:56.000000000 +0000
@@ -1256,6 +1256,7 @@
 {
     struct priv *p = (struct priv *) dev->priv;
     struct tmd *tmdp;
+    static char pad[64];
 
     PRINTK2(("## %s: SK_send_packet() called, CSR0 %#04x.\n", 
 	    SK_NAME, SK_read_reg(CSR0)));
@@ -1280,6 +1281,8 @@
 	/* Copy data into dual ported ram */
 
 	memcpy_toio((tmdp->u.buffer & 0x00ffffff), skb->data, skb->len);
+	if(len != skb->len)
+		memcpy_toio((tmdp->u.buffer & 0x00ffffff) + sb->len, pad, len-skb->len);
 
 	writew(-len, &tmdp->blen);            /* set length to transmit */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/skfp/h/skfbi.h linux-2.4.21-pre6/drivers/net/skfp/h/skfbi.h
--- linux-2.4.20/drivers/net/skfp/h/skfbi.h	2001-03-26 02:24:31.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/skfp/h/skfbi.h	2003-03-26 23:49:31.000000000 +0000
@@ -1039,7 +1039,6 @@
 /*	PCI_VPD_NITEM		 8 bit (ML)	Next Item Ptr */
 /*	PCI_VPD_ADR_REG		16 bit (ML)	VPD Address Register */
 #define	PCI_VPD_FLAG	(1<<15)		/* Bit 15	starts VPD rd/wd cycle*/
-#define PCI_VPD_ADDR	(0x3fff<<0)	/* Bit  0..14	VPD address */
 
 /*	PCI_VPD_DAT_REG		32 bit (ML)	VPD Data Register */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/smc9194.c linux-2.4.21-pre6/drivers/net/smc9194.c
--- linux-2.4.20/drivers/net/smc9194.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/smc9194.c	2003-03-26 23:49:51.000000000 +0000
@@ -483,10 +483,20 @@
 		printk(CARDNAME": Bad Craziness - sent packet while busy.\n" );
 		return 1;
 	}
-	lp->saved_skb = skb;
 
-	length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+	length = skb->len;
 
+	if(length < ETH_ZLEN)
+	{
+		skb = skb_padto(skb, ETH_ZLEN);
+		if(skb == NULL)
+		{
+			netif_wake_queue(dev);
+			return 0;
+		}
+		length = ETH_ZLEN;
+	}
+	lp->saved_skb = skb;
 		
 	/*
 	** The MMU wants the number of pages to be the number of 256 bytes
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/starfire.c linux-2.4.21-pre6/drivers/net/starfire.c
--- linux-2.4.20/drivers/net/starfire.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/starfire.c	2003-03-26 23:49:19.000000000 +0000
@@ -101,15 +101,33 @@
 	- Better stats and error handling (Ion Badulescu)
 	- Use new pci_set_mwi() PCI API function (jgarzik)
 
-TODO:
-	- implement tx_timeout() properly
+	LK1.3.7 (Ion Badulescu)
+	- minimal implementation of tx_timeout()
+	- correctly shutdown the Rx/Tx engines in netdev_close()
+	- added calls to netif_carrier_on/off
+	(patch from Stefan Rompf <srompf@isg.de>)
 	- VLAN support
+
+	LK1.3.8 (Ion Badulescu)
+	- adjust DMA burst size on sparc64
+	- 64-bit support
+	- reworked zerocopy support for 64-bit buffers
+	- working and usable interrupt mitigation/latency
+	- reduced Tx interrupt frequency for lower interrupt overhead
+
+	LK1.3.9 (Ion Badulescu)
+	- bugfix for mcast filter
+	- enable the right kind of Tx interrupts (TxDMADone, not TxDone)
+
+TODO:
+	- full NAPI support
 */
 
 #define DRV_NAME	"starfire"
-#define DRV_VERSION	"1.03+LK1.3.6"
-#define DRV_RELDATE	"March 7, 2002"
+#define DRV_VERSION	"1.03+LK1.3.9"
+#define DRV_RELDATE	"December 13, 2002"
 
+#include <linux/config.h>
 #include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -118,7 +136,6 @@
 #include <linux/etherdevice.h>
 #include <linux/init.h>
 #include <linux/delay.h>
-#include <linux/crc32.h>
 #include <asm/processor.h>		/* Processor type for cache alignment. */
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -154,11 +171,16 @@
 #include "starfire_firmware.h"
 #endif /* HAS_FIRMWARE */
 
+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
+#define VLAN_SUPPORT
+#endif
+
 /* The user-configurable values.
    These may be modified when a driver module is loaded.*/
 
 /* Used for tuning interrupt latency vs. overhead. */
-static int interrupt_mitigation;
+static int intr_latency;
+static int small_frames;
 
 static int debug = 1;			/* 1 normal messages, 0 quiet .. 7 verbose. */
 static int max_interrupt_work = 20;
@@ -166,6 +188,12 @@
 /* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
    The Starfire has a 512 element hash table based on the Ethernet CRC. */
 static int multicast_filter_limit = 512;
+/* Whether to do TCP/UDP checksums in hardware */
+#ifdef HAS_FIRMWARE
+static int enable_hw_cksum = 1;
+#else
+static int enable_hw_cksum = 0;
+#endif
 
 #define PKT_BUF_SZ	1536		/* Size of each temporary Rx buffer.*/
 /*
@@ -178,7 +206,9 @@
  * packets as the starfire doesn't allow for misaligned DMAs ;-(
  * 23/10/2000 - Jes
  *
- * The Alpha and the Sparc don't allow unaligned loads, either. -Ion
+ * The Alpha and the Sparc don't like unaligned loads, either. On Sparc64,
+ * at least, having unaligned frames leads to a rather serious performance
+ * penalty. -Ion
  */
 #if defined(__ia64__) || defined(__alpha__) || defined(__sparc__)
 static int rx_copybreak = PKT_BUF_SZ;
@@ -186,9 +216,17 @@
 static int rx_copybreak /* = 0 */;
 #endif
 
+/* PCI DMA burst size -- on sparc64 we want to force it to 64 bytes, on the others the default of 128 is fine. */
+#ifdef __sparc__
+#define DMA_BURST_SIZE 64
+#else
+#define DMA_BURST_SIZE 128
+#endif
+
 /* Used to pass the media type, etc.
    Both 'options[]' and 'full_duplex[]' exist for driver interoperability.
    The media type is usually passed in 'options[]'.
+   These variables are deprecated, use ethtool instead. -Ion
 */
 #define MAX_UNITS 8		/* More are supported, limit only on options */
 static int options[MAX_UNITS] = {0, };
@@ -198,33 +236,55 @@
 
 /* The "native" ring sizes are either 256 or 2048.
    However in some modes a descriptor may be marked to wrap the ring earlier.
-   The driver allocates a single page for each descriptor ring, constraining
-   the maximum size in an architecture-dependent way.
 */
 #define RX_RING_SIZE	256
 #define TX_RING_SIZE	32
 /* The completion queues are fixed at 1024 entries i.e. 4K or 8KB. */
 #define DONE_Q_SIZE	1024
+/* All queues must be aligned on a 256-byte boundary */
+#define QUEUE_ALIGN	256
+
+#if RX_RING_SIZE > 256
+#define RX_Q_ENTRIES Rx2048QEntries
+#else
+#define RX_Q_ENTRIES Rx256QEntries
+#endif
 
 /* Operational parameters that usually are not changed. */
 /* Time in jiffies before concluding the transmitter is hung. */
 #define TX_TIMEOUT	(2 * HZ)
 
-#ifdef ZEROCOPY
-#if MAX_SKB_FRAGS <= 6
-#define MAX_STARFIRE_FRAGS 6
-#else  /* MAX_STARFIRE_FRAGS > 6 */
-#warning This driver will not work with more than 6 skb fragments.
-#warning Turning off zerocopy support.
-#undef ZEROCOPY
-#endif /* MAX_STARFIRE_FRAGS > 6 */
-#endif /* ZEROCOPY */
+/*
+ * This SUCKS.
+ * We need a much better method to determine if dma_addr_t is 64-bit.
+ */
+#if (defined(__i386__) && defined(CONFIG_HIGHMEM) && (LINUX_VERSION_CODE > 0x20500 || defined(CONFIG_HIGHMEM64G))) || defined(__x86_64__) || defined (__ia64__) || defined(__mips64__) || (defined(__mips__) && defined(CONFIG_HIGHMEM) && defined(CONFIG_64BIT_PHYS_ADDR))
+/* 64-bit dma_addr_t */
+#define ADDR_64BITS	/* This chip uses 64 bit addresses. */
+#define cpu_to_dma(x) cpu_to_le64(x)
+#define dma_to_cpu(x) le64_to_cpu(x)
+#define RX_DESC_Q_ADDR_SIZE RxDescQAddr64bit
+#define TX_DESC_Q_ADDR_SIZE TxDescQAddr64bit
+#define RX_COMPL_Q_ADDR_SIZE RxComplQAddr64bit
+#define TX_COMPL_Q_ADDR_SIZE TxComplQAddr64bit
+#define RX_DESC_ADDR_SIZE RxDescAddr64bit
+#else  /* 32-bit dma_addr_t */
+#define cpu_to_dma(x) cpu_to_le32(x)
+#define dma_to_cpu(x) le32_to_cpu(x)
+#define RX_DESC_Q_ADDR_SIZE RxDescQAddr32bit
+#define TX_DESC_Q_ADDR_SIZE TxDescQAddr32bit
+#define RX_COMPL_Q_ADDR_SIZE RxComplQAddr32bit
+#define TX_COMPL_Q_ADDR_SIZE TxComplQAddr32bit
+#define RX_DESC_ADDR_SIZE RxDescAddr32bit
+#endif
 
-#ifdef ZEROCOPY
+#ifdef MAX_SKB_FRAGS
 #define skb_first_frag_len(skb)	skb_headlen(skb)
-#else  /* not ZEROCOPY */
+#define skb_num_frags(skb) (skb_shinfo(skb)->nr_frags + 1)
+#else  /* not MAX_SKB_FRAGS */
 #define skb_first_frag_len(skb)	(skb->len)
-#endif /* not ZEROCOPY */
+#define skb_num_frags(skb) 1
+#endif /* not MAX_SKB_FRAGS */
 
 /* 2.2.x compatibility code */
 #if LINUX_VERSION_CODE < 0x20300
@@ -233,9 +293,12 @@
 
 #else  /* LINUX_VERSION_CODE > 0x20300 */
 
+#include <linux/crc32.h>
 #include <linux/ethtool.h>
 #include <linux/mii.h>
 
+#include <linux/if_vlan.h>
+
 #define COMPAT_MOD_INC_USE_COUNT
 #define COMPAT_MOD_DEC_USE_COUNT
 
@@ -266,15 +329,20 @@
 MODULE_PARM(mtu, "i");
 MODULE_PARM(debug, "i");
 MODULE_PARM(rx_copybreak, "i");
-MODULE_PARM(interrupt_mitigation, "i");
+MODULE_PARM(intr_latency, "i");
+MODULE_PARM(small_frames, "i");
 MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
-MODULE_PARM_DESC(max_interrupt_work, "Starfire maximum events handled per interrupt");
-MODULE_PARM_DESC(mtu, "Starfire MTU (all boards)");
-MODULE_PARM_DESC(debug, "Starfire debug level (0-6)");
-MODULE_PARM_DESC(rx_copybreak, "Starfire copy breakpoint for copy-only-tiny-frames");
-MODULE_PARM_DESC(options, "Starfire: Bits 0-3: media type, bit 17: full duplex");
-MODULE_PARM_DESC(full_duplex, "Starfire full duplex setting(s) (1)");
+MODULE_PARM(enable_hw_cksum, "i");
+MODULE_PARM_DESC(max_interrupt_work, "Maximum events handled per interrupt");
+MODULE_PARM_DESC(mtu, "MTU (all boards)");
+MODULE_PARM_DESC(debug, "Debug level (0-6)");
+MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy-only-tiny-frames");
+MODULE_PARM_DESC(intr_latency, "Maximum interrupt latency, in microseconds");
+MODULE_PARM_DESC(small_frames, "Maximum size of receive frames that bypass interrupt latency (0,64,128,256,512)");
+MODULE_PARM_DESC(options, "Deprecated: Bits 0-3: media type, bit 17: full duplex");
+MODULE_PARM_DESC(full_duplex, "Deprecated: Forced full-duplex setting (0/1)");
+MODULE_PARM_DESC(enable_hw_cksum, "Enable/disable hardware cksum support (0/1)");
 
 /*
 				Theory of Operation
@@ -303,14 +371,14 @@
 IIIb/c. Transmit/Receive Structure
 
 See the Adaptec manual for the many possible structures, and options for
-each structure.  There are far too many to document here.
+each structure.  There are far too many to document all of them here.
 
 For transmit this driver uses type 0/1 transmit descriptors (depending
-on the presence of the zerocopy infrastructure), and relies on automatic
+on the 32/64 bitness of the architecture), and relies on automatic
 minimum-length padding.  It does not use the completion queue
 consumer index, but instead checks for non-zero status entries.
 
-For receive this driver uses type 0 receive descriptors.  The driver
+For receive this driver uses type 0/1/2/3 receive descriptors.  The driver
 allocates full frame size skbuffs for the Rx ring buffers, so all frames
 should fit in a single descriptor.  The driver does not use the completion
 queue consumer index, but instead checks for non-zero status entries.
@@ -335,15 +403,15 @@
 dev->tbusy flag.  The other thread is the interrupt handler, which is single
 threaded by the hardware and interrupt handling software.
 
-The send packet thread has partial control over the Tx ring and 'dev->tbusy'
-flag.  It sets the tbusy flag whenever it's queuing a Tx packet. If the next
-queue slot is empty, it clears the tbusy flag when finished otherwise it sets
-the 'lp->tx_full' flag.
+The send packet thread has partial control over the Tx ring and the netif_queue
+status. If the number of free Tx slots in the ring falls below a certain number
+(currently hardcoded to 4), it signals the upper layer to stop the queue.
 
 The interrupt handler has exclusive control over the Rx ring and records stats
 from the Tx ring.  After reaping the stats, it marks the Tx queue entry as
-empty by incrementing the dirty_tx mark. Iff the 'lp->tx_full' flag is set, it
-clears both the tx_full and tbusy flags.
+empty by incrementing the dirty_tx mark. Iff the netif_queue is stopped and the
+number of free Tx slow is above the threshold, it signals the upper layer to
+restart the queue.
 
 IV. Notes
 
@@ -355,18 +423,15 @@
 
 IVc. Errata
 
+- StopOnPerr is broken, don't enable
+- Hardware ethernet padding exposes random data, perform software padding
+  instead (unverified -- works correctly for all the hardware I have)
+
 */
 
 
 
 enum chip_capability_flags {CanHaveMII=1, };
-#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR0)
-
-#if 0
-#define ADDR_64BITS 1			/* This chip uses 64 bit addresses. */
-#endif
-
-#define HAS_IP_COPYSUM 1
 
 enum chipset {
 	CH_6915 = 0,
@@ -398,7 +463,7 @@
 enum register_offsets {
 	PCIDeviceConfig=0x50040, GenCtrl=0x50070, IntrTimerCtrl=0x50074,
 	IntrClear=0x50080, IntrStatus=0x50084, IntrEnable=0x50088,
-	MIICtrl=0x52000, StationAddr=0x50120, EEPROMCtrl=0x51000,
+	MIICtrl=0x52000, TxStationAddr=0x50120, EEPROMCtrl=0x51000,
 	GPIOCtrl=0x5008C, TxDescCtrl=0x50090,
 	TxRingPtr=0x50098, HiPriTxRingPtr=0x50094, /* Low and High priority. */
 	TxRingHiAddr=0x5009C,		/* 64 bit address extension. */
@@ -409,11 +474,16 @@
 	CompletionQConsumerIdx=0x500C4, RxDMACtrl=0x500D0,
 	RxDescQCtrl=0x500D4, RxDescQHiAddr=0x500DC, RxDescQAddr=0x500E0,
 	RxDescQIdx=0x500E8, RxDMAStatus=0x500F0, RxFilterMode=0x500F4,
-	TxMode=0x55000, PerfFilterTable=0x56000, HashTable=0x56100,
+	TxMode=0x55000, VlanType=0x55064,
+	PerfFilterTable=0x56000, HashTable=0x56100,
 	TxGfpMem=0x58000, RxGfpMem=0x5a000,
 };
 
-/* Bits in the interrupt status/mask registers. */
+/*
+ * Bits in the interrupt status/mask registers.
+ * Warning: setting Intr[Ab]NormalSummary in the IntrEnable register
+ * enables all the interrupt sources that are or'ed into those status bits.
+ */
 enum intr_status_bits {
 	IntrLinkChange=0xf0000000, IntrStatsMax=0x08000000,
 	IntrAbnormalSummary=0x02000000, IntrGeneralTimer=0x01000000,
@@ -438,7 +508,16 @@
 /* Bits in the RxFilterMode register. */
 enum rx_mode_bits {
 	AcceptBroadcast=0x04, AcceptAllMulticast=0x02, AcceptAll=0x01,
-	AcceptMulticast=0x10, AcceptMyPhys=0xE040,
+	AcceptMulticast=0x10, PerfectFilter=0x40, HashFilter=0x30,
+	PerfectFilterVlan=0x80, MinVLANPrio=0xE000, VlanMode=0x0200,
+	WakeupOnGFP=0x0800,
+};
+
+/* Bits in the TxMode register */
+enum tx_mode_bits {
+	MiiSoftReset=0x8000, MIILoopback=0x4000,
+	TxFlowEnable=0x0800, RxFlowEnable=0x0400,
+	PadEnable=0x04, FullDuplex=0x02, HugeFrame=0x01,
 };
 
 /* Bits in the TxDescCtrl register. */
@@ -447,7 +526,8 @@
 	TxDescSpace128=0x30, TxDescSpace256=0x40,
 	TxDescType0=0x00, TxDescType1=0x01, TxDescType2=0x02,
 	TxDescType3=0x03, TxDescType4=0x04,
-	TxNoDMACompletion=0x08, TxDescQ64bit=0x80,
+	TxNoDMACompletion=0x08,
+	TxDescQAddr64bit=0x80, TxDescQAddr32bit=0,
 	TxHiPriFIFOThreshShift=24, TxPadLenShift=16,
 	TxDMABurstSizeShift=8,
 };
@@ -455,81 +535,144 @@
 /* Bits in the RxDescQCtrl register. */
 enum rx_ctrl_bits {
 	RxBufferLenShift=16, RxMinDescrThreshShift=0,
-	RxPrefetchMode=0x8000, Rx2048QEntries=0x4000,
-	RxVariableQ=0x2000, RxDesc64bit=0x1000,
-	RxDescQAddr64bit=0x0100,
+	RxPrefetchMode=0x8000, RxVariableQ=0x2000,
+	Rx2048QEntries=0x4000, Rx256QEntries=0,
+	RxDescAddr64bit=0x1000, RxDescAddr32bit=0,
+	RxDescQAddr64bit=0x0100, RxDescQAddr32bit=0,
 	RxDescSpace4=0x000, RxDescSpace8=0x100,
 	RxDescSpace16=0x200, RxDescSpace32=0x300,
 	RxDescSpace64=0x400, RxDescSpace128=0x500,
 	RxConsumerWrEn=0x80,
 };
 
+/* Bits in the RxDMACtrl register. */
+enum rx_dmactrl_bits {
+	RxReportBadFrames=0x80000000, RxDMAShortFrames=0x40000000,
+	RxDMABadFrames=0x20000000, RxDMACrcErrorFrames=0x10000000,
+	RxDMAControlFrame=0x08000000, RxDMAPauseFrame=0x04000000,
+	RxChecksumIgnore=0, RxChecksumRejectTCPUDP=0x02000000,
+	RxChecksumRejectTCPOnly=0x01000000,
+	RxCompletionQ2Enable=0x800000,
+	RxDMAQ2Disable=0, RxDMAQ2FPOnly=0x100000,
+	RxDMAQ2SmallPkt=0x200000, RxDMAQ2HighPrio=0x300000,
+	RxDMAQ2NonIP=0x400000,
+	RxUseBackupQueue=0x080000, RxDMACRC=0x040000,
+	RxEarlyIntThreshShift=12, RxHighPrioThreshShift=8,
+	RxBurstSizeShift=0,
+};
+
 /* Bits in the RxCompletionAddr register */
 enum rx_compl_bits {
-	RxComplQAddr64bit=0x80, TxComplProducerWrEn=0x40,
+	RxComplQAddr64bit=0x80, RxComplQAddr32bit=0,
+	RxComplProducerWrEn=0x40,
 	RxComplType0=0x00, RxComplType1=0x10,
 	RxComplType2=0x20, RxComplType3=0x30,
 	RxComplThreshShift=0,
 };
 
+/* Bits in the TxCompletionAddr register */
+enum tx_compl_bits {
+	TxComplQAddr64bit=0x80, TxComplQAddr32bit=0,
+	TxComplProducerWrEn=0x40,
+	TxComplIntrStatus=0x20,
+	CommonQueueMode=0x10,
+	TxComplThreshShift=0,
+};
+
+/* Bits in the GenCtrl register */
+enum gen_ctrl_bits {
+	RxEnable=0x05, TxEnable=0x0a,
+	RxGFPEnable=0x10, TxGFPEnable=0x20,
+};
+
+/* Bits in the IntrTimerCtrl register */
+enum intr_ctrl_bits {
+	Timer10X=0x800, EnableIntrMasking=0x60, SmallFrameBypass=0x100,
+	SmallFrame64=0, SmallFrame128=0x200, SmallFrame256=0x400, SmallFrame512=0x600,
+	IntrLatencyMask=0x1f,
+};
+
 /* The Rx and Tx buffer descriptors. */
 struct starfire_rx_desc {
-	u32 rxaddr;			/* Optionally 64 bits. */
+	dma_addr_t rxaddr;
 };
 enum rx_desc_bits {
 	RxDescValid=1, RxDescEndRing=2,
 };
 
-/* Completion queue entry.
-   You must update the page allocation, init_ring and the shift count in rx()
-   if using a larger format. */
-#ifdef HAS_FIRMWARE
-#define csum_rx_status
-#endif /* HAS_FIRMWARE */
-struct rx_done_desc {
+/* Completion queue entry. */
+struct short_rx_done_desc {
+	u32 status;			/* Low 16 bits is length. */
+};
+struct basic_rx_done_desc {
 	u32 status;			/* Low 16 bits is length. */
-#ifdef csum_rx_status
-	u32 status2;			/* Low 16 bits is csum */
-#endif /* csum_rx_status */
-#ifdef full_rx_status
-	u32 status2;
+	u16 vlanid;
+	u16 status2;
+};
+struct csum_rx_done_desc {
+	u32 status;			/* Low 16 bits is length. */
+	u16 csum;			/* Partial checksum */
+	u16 status2;
+};
+struct full_rx_done_desc {
+	u32 status;			/* Low 16 bits is length. */
+	u16 status3;
+	u16 status2;
 	u16 vlanid;
 	u16 csum;			/* partial checksum */
 	u32 timestamp;
-#endif /* full_rx_status */
 };
+/* XXX: this is ugly and I'm not sure it's worth the trouble -Ion */
+#ifdef HAS_FIRMWARE
+#ifdef VLAN_SUPPORT
+typedef struct full_rx_done_desc rx_done_desc;
+#define RxComplType RxComplType3
+#else  /* not VLAN_SUPPORT */
+typedef struct csum_rx_done_desc rx_done_desc;
+#define RxComplType RxComplType2
+#endif /* not VLAN_SUPPORT */
+#else  /* not HAS_FIRMWARE */
+#ifdef VLAN_SUPPORT
+typedef struct basic_rx_done_desc rx_done_desc;
+#define RxComplType RxComplType1
+#else  /* not VLAN_SUPPORT */
+typedef struct short_rx_done_desc rx_done_desc;
+#define RxComplType RxComplType0
+#endif /* not VLAN_SUPPORT */
+#endif /* not HAS_FIRMWARE */
+
 enum rx_done_bits {
 	RxOK=0x20000000, RxFIFOErr=0x10000000, RxBufQ2=0x08000000,
 };
 
-#ifdef ZEROCOPY
-/* Type 0 Tx descriptor. */
-/* If more fragments are needed, don't forget to change the
-   descriptor spacing as well! */
-struct starfire_tx_desc {
-	u32 status;
-	u32 nbufs;
-	u32 first_addr;
-	u16 first_len;
-	u16 total_len;
-	struct {
-		u32 addr;
-		u32 len;
-	} frag[MAX_STARFIRE_FRAGS];
-};
-#else  /* not ZEROCOPY */
 /* Type 1 Tx descriptor. */
-struct starfire_tx_desc {
+struct starfire_tx_desc_1 {
 	u32 status;			/* Upper bits are status, lower 16 length. */
-	u32 first_addr;
+	u32 addr;
 };
-#endif /* not ZEROCOPY */
+
+/* Type 2 Tx descriptor. */
+struct starfire_tx_desc_2 {
+	u32 status;			/* Upper bits are status, lower 16 length. */
+	u32 reserved;
+	u64 addr;
+};
+
+#ifdef ADDR_64BITS
+typedef struct starfire_tx_desc_2 starfire_tx_desc;
+#define TX_DESC_TYPE TxDescType2
+#else  /* not ADDR_64BITS */
+typedef struct starfire_tx_desc_1 starfire_tx_desc;
+#define TX_DESC_TYPE TxDescType1
+#endif /* not ADDR_64BITS */
+#define TX_DESC_SPACING TxDescSpaceUnlim
+
 enum tx_desc_bits {
 	TxDescID=0xB0000000,
 	TxCRCEn=0x01000000, TxDescIntr=0x08000000,
 	TxRingWrap=0x04000000, TxCalTCP=0x02000000,
 };
-struct tx_done_report {
+struct tx_done_desc {
 	u32 status;			/* timestamp, index. */
 #if 0
 	u32 intrstatus;			/* interrupt status */
@@ -542,45 +685,48 @@
 };
 struct tx_ring_info {
 	struct sk_buff *skb;
-	dma_addr_t first_mapping;
-#ifdef ZEROCOPY
-	dma_addr_t frag_mapping[MAX_STARFIRE_FRAGS];
-#endif /* ZEROCOPY */
+	dma_addr_t mapping;
+	unsigned int used_slots;
 };
 
 #define PHY_CNT		2
 struct netdev_private {
 	/* Descriptor rings first for alignment. */
 	struct starfire_rx_desc *rx_ring;
-	struct starfire_tx_desc *tx_ring;
+	starfire_tx_desc *tx_ring;
 	dma_addr_t rx_ring_dma;
 	dma_addr_t tx_ring_dma;
 	/* The addresses of rx/tx-in-place skbuffs. */
 	struct rx_ring_info rx_info[RX_RING_SIZE];
 	struct tx_ring_info tx_info[TX_RING_SIZE];
 	/* Pointers to completion queues (full pages). */
-	struct rx_done_desc *rx_done_q;
+	rx_done_desc *rx_done_q;
 	dma_addr_t rx_done_q_dma;
 	unsigned int rx_done;
-	struct tx_done_report *tx_done_q;
+	struct tx_done_desc *tx_done_q;
 	dma_addr_t tx_done_q_dma;
 	unsigned int tx_done;
 	struct net_device_stats stats;
 	struct pci_dev *pci_dev;
+#ifdef VLAN_SUPPORT
+	struct vlan_group *vlgrp;
+#endif
+	void *queue_mem;
+	dma_addr_t queue_mem_dma;
+	size_t queue_mem_size;
+
 	/* Frequently used values: keep some adjacent for cache effect. */
+	spinlock_t lock;
 	unsigned int cur_rx, dirty_rx;	/* Producer/consumer ring indices */
-	unsigned int cur_tx, dirty_tx;
+	unsigned int cur_tx, dirty_tx, reap_tx;
 	unsigned int rx_buf_sz;		/* Based on MTU+slack. */
-	unsigned int tx_full:1,		/* The Tx queue is full. */
 	/* These values keep track of the transceiver/media in use. */
-		autoneg:1,		/* Autonegotiation allowed. */
-		full_duplex:1,		/* Full-duplex operation. */
-		speed100:1;		/* Set if speed == 100MBit. */
-	unsigned int intr_mitigation;
+	int speed100;			/* Set if speed == 100MBit. */
 	u32 tx_mode;
+	u32 intr_timer_ctrl;
 	u8 tx_threshold;
 	/* MII transceiver section. */
-	u16 advertising;		/* NWay media advertisement */
+	struct mii_if_info mii_if;		/* MII lib hooks/info */
 	int phy_cnt;			/* MII device addresses. */
 	unsigned char phys[PHY_CNT];	/* MII device addresses. */
 };
@@ -604,6 +750,44 @@
 static void	netdev_media_change(struct net_device *dev);
 
 
+#ifdef VLAN_SUPPORT
+static void netdev_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
+{
+        struct netdev_private *np = dev->priv;
+
+        spin_lock(&np->lock);
+	if (debug > 2)
+		printk("%s: Setting vlgrp to %p\n", dev->name, grp);
+        np->vlgrp = grp;
+	set_rx_mode(dev);
+        spin_unlock(&np->lock);
+}
+
+static void netdev_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
+{
+	struct netdev_private *np = dev->priv;
+
+	spin_lock(&np->lock);
+	if (debug > 1)
+		printk("%s: Adding vlanid %d to vlan filter\n", dev->name, vid);
+	set_rx_mode(dev);
+	spin_unlock(&np->lock);
+}
+
+static void netdev_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
+{
+	struct netdev_private *np = dev->priv;
+
+	spin_lock(&np->lock);
+	if (debug > 1)
+		printk("%s: removing vlanid %d from vlan filter\n", dev->name, vid);
+	if (np->vlgrp)
+		np->vlgrp->vlan_devices[vid] = NULL;
+	set_rx_mode(dev);
+	spin_unlock(&np->lock);
+}
+#endif /* VLAN_SUPPORT */
+
 
 static int __devinit starfire_init_one(struct pci_dev *pdev,
 				       const struct pci_device_id *ent)
@@ -615,10 +799,6 @@
 	long ioaddr;
 	int drv_flags, io_size;
 	int boguscnt;
-#ifndef HAVE_PCI_SET_MWI
-	u16 cmd;
-	u8 cache;
-#endif
 
 /* when built into the kernel, we only print version if device is found */
 #ifndef MODULE
@@ -635,13 +815,13 @@
 	ioaddr = pci_resource_start(pdev, 0);
 	io_size = pci_resource_len(pdev, 0);
 	if (!ioaddr || ((pci_resource_flags(pdev, 0) & IORESOURCE_MEM) == 0)) {
-		printk (KERN_ERR DRV_NAME " %d: no PCI MEM resources, aborting\n", card_idx);
+		printk(KERN_ERR DRV_NAME " %d: no PCI MEM resources, aborting\n", card_idx);
 		return -ENODEV;
 	}
 
 	dev = alloc_etherdev(sizeof(*np));
 	if (!dev) {
-		printk (KERN_ERR DRV_NAME " %d: cannot alloc etherdev, aborting\n", card_idx);
+		printk(KERN_ERR DRV_NAME " %d: cannot alloc etherdev, aborting\n", card_idx);
 		return -ENOMEM;
 	}
 	SET_MODULE_OWNER(dev);
@@ -649,7 +829,7 @@
 	irq = pdev->irq;
 
 	if (pci_request_regions (pdev, dev->name)) {
-		printk (KERN_ERR DRV_NAME " %d: cannot reserve PCI resources, aborting\n", card_idx);
+		printk(KERN_ERR DRV_NAME " %d: cannot reserve PCI resources, aborting\n", card_idx);
 		goto err_out_free_netdev;
 	}
 
@@ -657,7 +837,7 @@
 #if !defined(CONFIG_SPARC64) || LINUX_VERSION_CODE > 0x20300
 	ioaddr = (long) ioremap(ioaddr, io_size);
 	if (!ioaddr) {
-		printk (KERN_ERR DRV_NAME " %d: cannot remap 0x%x @ 0x%lx, aborting\n",
+		printk(KERN_ERR DRV_NAME " %d: cannot remap %#x @ %#lx, aborting\n",
 			card_idx, io_size, ioaddr);
 		goto err_out_free_res;
 	}
@@ -665,29 +845,26 @@
 
 	pci_set_master(pdev);
 
-#ifdef HAVE_PCI_SET_MWI
-	pci_set_mwi(pdev);
-#else
 	/* enable MWI -- it vastly improves Rx performance on sparc64 */
-	pci_read_config_word(pdev, PCI_COMMAND, &cmd);
-	cmd |= PCI_COMMAND_INVALIDATE;
-	pci_write_config_word(pdev, PCI_COMMAND, cmd);
-
-	/* set PCI cache size */
-	pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache);
-	if ((cache << 2) != SMP_CACHE_BYTES) {
-		printk(KERN_INFO "  PCI cache line size set incorrectly "
-		       "(%i bytes) by BIOS/FW, correcting to %i\n",
-		       (cache << 2), SMP_CACHE_BYTES);
-		pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE,
-				      SMP_CACHE_BYTES >> 2);
-	}
-#endif
+	pci_set_mwi(pdev);
 
+#ifdef MAX_SKB_FRAGS
+	dev->features |= NETIF_F_SG;
+#endif /* MAX_SKB_FRAGS */
 #ifdef ZEROCOPY
-	/* Starfire can do SG and TCP/UDP checksumming */
-	dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
+	/* Starfire can do TCP/UDP checksumming */
+	if (enable_hw_cksum)
+		dev->features |= NETIF_F_IP_CSUM;
 #endif /* ZEROCOPY */
+#ifdef VLAN_SUPPORT
+	dev->features |= NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER;
+	dev->vlan_rx_register = netdev_vlan_rx_register;
+	dev->vlan_rx_add_vid = netdev_vlan_rx_add_vid;
+	dev->vlan_rx_kill_vid = netdev_vlan_rx_kill_vid;
+#endif /* VLAN_RX_KILL_VID */
+#ifdef ADDR_64BITS
+	dev->features |= NETIF_F_HIGHDMA;
+#endif /* ADDR_64BITS */
 
 	/* Serial EEPROM reads are hidden by the hardware. */
 	for (i = 0; i < 6; i++)
@@ -702,7 +879,7 @@
 #endif
 
 	/* Issue soft reset */
-	writel(0x8000, ioaddr + TxMode);
+	writel(MiiSoftReset, ioaddr + TxMode);
 	udelay(1000);
 	writel(0, ioaddr + TxMode);
 
@@ -723,9 +900,17 @@
 	dev->irq = irq;
 
 	np = dev->priv;
+	spin_lock_init(&np->lock);
 	pci_set_drvdata(pdev, dev);
 
 	np->pci_dev = pdev;
+
+	np->mii_if.dev = dev;
+	np->mii_if.mdio_read = mdio_read;
+	np->mii_if.mdio_write = mdio_write;
+	np->mii_if.phy_id_mask = 0x1f;
+	np->mii_if.reg_num_mask = 0x1f;
+
 	drv_flags = netdrv_tbl[chip_idx].drv_flags;
 
 	option = card_idx < MAX_UNITS ? options[card_idx] : 0;
@@ -734,17 +919,41 @@
 
 	/* The lower four bits are the media type. */
 	if (option & 0x200)
-		np->full_duplex = 1;
+		np->mii_if.full_duplex = 1;
 
 	if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0)
-		np->full_duplex = 1;
+		np->mii_if.full_duplex = 1;
 
-	if (np->full_duplex)
-		np->autoneg = 0;
+	if (np->mii_if.full_duplex)
+		np->mii_if.force_media = 1;
 	else
-		np->autoneg = 1;
+		np->mii_if.force_media = 0;
 	np->speed100 = 1;
 
+	/* timer resolution is 128 * 0.8us */
+	np->intr_timer_ctrl = (((intr_latency * 10) / 1024) & IntrLatencyMask) |
+		Timer10X | EnableIntrMasking;
+
+	if (small_frames > 0) {
+		np->intr_timer_ctrl |= SmallFrameBypass;
+		switch (small_frames) {
+		case 1 ... 64:
+			np->intr_timer_ctrl |= SmallFrame64;
+			break;
+		case 65 ... 128:
+			np->intr_timer_ctrl |= SmallFrame128;
+			break;
+		case 129 ... 256:
+			np->intr_timer_ctrl |= SmallFrame256;
+			break;
+		default:
+			np->intr_timer_ctrl |= SmallFrame512;
+			if (small_frames > 512)
+				printk("Adjusting small_frames down to 512\n");
+			break;
+		}
+	}
+
 	/* The chip-specific entries in the device structure. */
 	dev->open = &netdev_open;
 	dev->hard_start_xmit = &start_tx;
@@ -757,11 +966,10 @@
 	if (mtu)
 		dev->mtu = mtu;
 
-	i = register_netdev(dev);
-	if (i)
+	if (register_netdev(dev))
 		goto err_out_cleardev;
 
-	printk(KERN_INFO "%s: %s at 0x%lx, ",
+	printk(KERN_INFO "%s: %s at %#lx, ",
 		   dev->name, netdrv_tbl[chip_idx].name, ioaddr);
 	for (i = 0; i < 5; i++)
 		printk("%2.2x:", dev->dev_addr[i]);
@@ -784,25 +992,23 @@
 			mii_status = mdio_read(dev, phy, MII_BMSR);
 			if (mii_status != 0) {
 				np->phys[phy_idx++] = phy;
-				np->advertising = mdio_read(dev, phy, MII_ADVERTISE);
+				np->mii_if.advertising = mdio_read(dev, phy, MII_ADVERTISE);
 				printk(KERN_INFO "%s: MII PHY found at address %d, status "
-					   "0x%4.4x advertising %4.4x.\n",
-					   dev->name, phy, mii_status, np->advertising);
+					   "%#4.4x advertising %#4.4x.\n",
+					   dev->name, phy, mii_status, np->mii_if.advertising);
 				/* there can be only one PHY on-board */
 				break;
 			}
 		}
 		np->phy_cnt = phy_idx;
+		if (np->phy_cnt > 0)
+			np->mii_if.phy_id = np->phys[0];
+		else
+			memset(&np->mii_if, 0, sizeof(np->mii_if));
 	}
 
-#ifdef ZEROCOPY
-	printk(KERN_INFO "%s: scatter-gather and hardware TCP cksumming enabled.\n",
-	       dev->name);
-#else  /* not ZEROCOPY */
-	printk(KERN_INFO "%s: scatter-gather and hardware TCP cksumming disabled.\n",
-	       dev->name);
-#endif /* not ZEROCOPY */
-
+	printk(KERN_INFO "%s: scatter-gather and hardware TCP cksumming %s.\n",
+	       dev->name, enable_hw_cksum ? "enabled" : "disabled");
 	return 0;
 
 err_out_cleardev:
@@ -811,7 +1017,6 @@
 err_out_free_res:
 	pci_release_regions (pdev);
 err_out_free_netdev:
-	unregister_netdev(dev);
 	kfree(dev);
 	return -ENODEV;
 }
@@ -839,7 +1044,6 @@
 	long mdio_addr = dev->base_addr + MIICtrl + (phy_id<<7) + (location<<2);
 	writel(value, mdio_addr);
 	/* The busy-wait will occur before a read. */
-	return;
 }
 
 
@@ -848,6 +1052,7 @@
 	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
 	int i, retval;
+	size_t tx_done_q_size, rx_done_q_size, tx_ring_size, rx_ring_size;
 
 	/* Do we ever need to reset the chip??? */
 
@@ -865,61 +1070,61 @@
 	if (debug > 1)
 		printk(KERN_DEBUG "%s: netdev_open() irq %d.\n",
 		       dev->name, dev->irq);
-	/* Allocate the various queues, failing gracefully. */
-	if (np->tx_done_q == 0)
-		np->tx_done_q = pci_alloc_consistent(np->pci_dev, PAGE_SIZE, &np->tx_done_q_dma);
-	if (np->rx_done_q == 0)
-		np->rx_done_q = pci_alloc_consistent(np->pci_dev, sizeof(struct rx_done_desc) * DONE_Q_SIZE, &np->rx_done_q_dma);
-	if (np->tx_ring == 0)
-		np->tx_ring = pci_alloc_consistent(np->pci_dev, PAGE_SIZE, &np->tx_ring_dma);
-	if (np->rx_ring == 0)
-		np->rx_ring = pci_alloc_consistent(np->pci_dev, PAGE_SIZE, &np->rx_ring_dma);
-	if (np->tx_done_q == 0 || np->rx_done_q == 0
-		|| np->rx_ring == 0 || np->tx_ring == 0) {
-		if (np->tx_done_q)
-			pci_free_consistent(np->pci_dev, PAGE_SIZE,
-					    np->tx_done_q, np->tx_done_q_dma);
-		if (np->rx_done_q)
-			pci_free_consistent(np->pci_dev, sizeof(struct rx_done_desc) * DONE_Q_SIZE,
-					    np->rx_done_q, np->rx_done_q_dma);
-		if (np->tx_ring)
-			pci_free_consistent(np->pci_dev, PAGE_SIZE,
-					    np->tx_ring, np->tx_ring_dma);
-		if (np->rx_ring)
-			pci_free_consistent(np->pci_dev, PAGE_SIZE,
-					    np->rx_ring, np->rx_ring_dma);
-		COMPAT_MOD_DEC_USE_COUNT;
-		return -ENOMEM;
+
+	/* Allocate the various queues. */
+	if (np->queue_mem == 0) {
+		tx_done_q_size = ((sizeof(struct tx_done_desc) * DONE_Q_SIZE + QUEUE_ALIGN - 1) / QUEUE_ALIGN) * QUEUE_ALIGN;
+		rx_done_q_size = ((sizeof(rx_done_desc) * DONE_Q_SIZE + QUEUE_ALIGN - 1) / QUEUE_ALIGN) * QUEUE_ALIGN;
+		tx_ring_size = ((sizeof(starfire_tx_desc) * TX_RING_SIZE + QUEUE_ALIGN - 1) / QUEUE_ALIGN) * QUEUE_ALIGN;
+		rx_ring_size = sizeof(struct starfire_rx_desc) * RX_RING_SIZE;
+		np->queue_mem_size = tx_done_q_size + rx_done_q_size + tx_ring_size + rx_ring_size;
+		np->queue_mem = pci_alloc_consistent(np->pci_dev, np->queue_mem_size, &np->queue_mem_dma);
+		if (np->queue_mem == 0) {
+			COMPAT_MOD_DEC_USE_COUNT;
+			return -ENOMEM;
+		}
+
+		np->tx_done_q     = np->queue_mem;
+		np->tx_done_q_dma = np->queue_mem_dma;
+		np->rx_done_q     = (void *) np->tx_done_q + tx_done_q_size;
+		np->rx_done_q_dma = np->tx_done_q_dma + tx_done_q_size;
+		np->tx_ring       = (void *) np->rx_done_q + rx_done_q_size;
+		np->tx_ring_dma   = np->rx_done_q_dma + rx_done_q_size;
+		np->rx_ring       = (void *) np->tx_ring + tx_ring_size;
+		np->rx_ring_dma   = np->tx_ring_dma + tx_ring_size;
 	}
 
+	/* Start with no carrier, it gets adjusted later */
+	netif_carrier_off(dev);
 	init_ring(dev);
 	/* Set the size of the Rx buffers. */
 	writel((np->rx_buf_sz << RxBufferLenShift) |
 	       (0 << RxMinDescrThreshShift) |
 	       RxPrefetchMode | RxVariableQ |
+	       RX_Q_ENTRIES |
+	       RX_DESC_Q_ADDR_SIZE | RX_DESC_ADDR_SIZE |
 	       RxDescSpace4,
 	       ioaddr + RxDescQCtrl);
 
-#ifdef ZEROCOPY
-	/* Set Tx descriptor to type 0 and spacing to 64 bytes. */
-	writel((2 << TxHiPriFIFOThreshShift) |
-	       (0 << TxPadLenShift) |
-	       (4 << TxDMABurstSizeShift) |
-	       TxDescSpace64 | TxDescType0,
-	       ioaddr + TxDescCtrl);
-#else  /* not ZEROCOPY */
-	/* Set Tx descriptor to type 1 and padding to 0 bytes. */
+	/* Set up the Rx DMA controller. */
+	writel(RxChecksumIgnore |
+	       (0 << RxEarlyIntThreshShift) |
+	       (6 << RxHighPrioThreshShift) |
+	       ((DMA_BURST_SIZE / 32) << RxBurstSizeShift),
+	       ioaddr + RxDMACtrl);
+
+	/* Set Tx descriptor */
 	writel((2 << TxHiPriFIFOThreshShift) |
 	       (0 << TxPadLenShift) |
-	       (4 << TxDMABurstSizeShift) |
-	       TxDescSpaceUnlim | TxDescType1,
+	       ((DMA_BURST_SIZE / 32) << TxDMABurstSizeShift) |
+	       TX_DESC_Q_ADDR_SIZE |
+	       TX_DESC_SPACING | TX_DESC_TYPE,
 	       ioaddr + TxDescCtrl);
-#endif /* not ZEROCOPY */
 
-#if defined(ADDR_64BITS) && defined(__alpha__)
-	/* XXX We really need a 64-bit PCI dma interfaces too... -DaveM */
-	writel(np->rx_ring_dma >> 32, ioaddr + RxDescQHiAddr);
-	writel(np->tx_ring_dma >> 32, ioaddr + TxRingHiAddr);
+#if defined(ADDR_64BITS)
+	writel(np->queue_mem_dma >> 32, ioaddr + RxDescQHiAddr);
+	writel(np->queue_mem_dma >> 32, ioaddr + TxRingHiAddr);
+	writel(np->queue_mem_dma >> 32, ioaddr + CompletionHiAddr);
 #else
 	writel(0, ioaddr + RxDescQHiAddr);
 	writel(0, ioaddr + TxRingHiAddr);
@@ -929,32 +1134,23 @@
 	writel(np->tx_ring_dma, ioaddr + TxRingPtr);
 
 	writel(np->tx_done_q_dma, ioaddr + TxCompletionAddr);
-#ifdef full_rx_status
 	writel(np->rx_done_q_dma |
-	       RxComplType3 |
+	       RxComplType |
 	       (0 << RxComplThreshShift),
 	       ioaddr + RxCompletionAddr);
-#else  /* not full_rx_status */
-#ifdef csum_rx_status
-	writel(np->rx_done_q_dma |
-	       RxComplType2 |
-	       (0 << RxComplThreshShift),
-	       ioaddr + RxCompletionAddr);
-#else  /* not csum_rx_status */
-	writel(np->rx_done_q_dma |
-	       RxComplType0 |
-	       (0 << RxComplThreshShift),
-	       ioaddr + RxCompletionAddr);
-#endif /* not csum_rx_status */
-#endif /* not full_rx_status */
 
 	if (debug > 1)
 		printk(KERN_DEBUG "%s: Filling in the station address.\n", dev->name);
 
-	/* Fill both the unused Tx SA register and the Rx perfect filter. */
+	/* Fill both the Tx SA register and the Rx perfect filter. */
 	for (i = 0; i < 6; i++)
-		writeb(dev->dev_addr[i], ioaddr + StationAddr + 5 - i);
-	for (i = 0; i < 16; i++) {
+		writeb(dev->dev_addr[i], ioaddr + TxStationAddr + 5 - i);
+	/* The first entry is special because it bypasses the VLAN filter.
+	   Don't use it. */
+	writew(0, ioaddr + PerfFilterTable);
+	writew(0, ioaddr + PerfFilterTable + 4);
+	writew(0, ioaddr + PerfFilterTable + 8);
+	for (i = 1; i < 16; i++) {
 		u16 *eaddrs = (u16 *)dev->dev_addr;
 		long setup_frm = ioaddr + PerfFilterTable + i * 16;
 		writew(cpu_to_be16(eaddrs[2]), setup_frm); setup_frm += 4;
@@ -964,16 +1160,14 @@
 
 	/* Initialize other registers. */
 	/* Configure the PCI bus bursts and FIFO thresholds. */
-	np->tx_mode = 0x0C04;		/* modified when link is up. */
-	writel(0x8000 | np->tx_mode, ioaddr + TxMode);
+	np->tx_mode = TxFlowEnable|RxFlowEnable|PadEnable;	/* modified when link is up. */
+	writel(MiiSoftReset | np->tx_mode, ioaddr + TxMode);
 	udelay(1000);
 	writel(np->tx_mode, ioaddr + TxMode);
 	np->tx_threshold = 4;
 	writel(np->tx_threshold, ioaddr + TxThreshold);
 
-	interrupt_mitigation &= 0x1f;
-	np->intr_mitigation = interrupt_mitigation;
-	writel(np->intr_mitigation, ioaddr + IntrTimerCtrl);
+	writel(np->intr_timer_ctrl, ioaddr + IntrTimerCtrl);
 
 	netif_start_if(dev);
 	netif_start_queue(dev);
@@ -982,35 +1176,41 @@
 		printk(KERN_DEBUG "%s: Setting the Rx and Tx modes.\n", dev->name);
 	set_rx_mode(dev);
 
-	np->advertising = mdio_read(dev, np->phys[0], MII_ADVERTISE);
+	np->mii_if.advertising = mdio_read(dev, np->phys[0], MII_ADVERTISE);
 	check_duplex(dev);
 
 	/* Enable GPIO interrupts on link change */
 	writel(0x0f00ff00, ioaddr + GPIOCtrl);
 
-	/* Set the interrupt mask and enable PCI interrupts. */
+	/* Set the interrupt mask */
 	writel(IntrRxDone | IntrRxEmpty | IntrDMAErr |
-	       IntrTxDone | IntrStatsMax | IntrLinkChange |
-	       IntrNormalSummary | IntrAbnormalSummary |
+	       IntrTxDMADone | IntrStatsMax | IntrLinkChange |
 	       IntrRxGFPDead | IntrNoTxCsum | IntrTxBadID,
 	       ioaddr + IntrEnable);
+	/* Enable PCI interrupts. */
 	writel(0x00800000 | readl(ioaddr + PCIDeviceConfig),
 	       ioaddr + PCIDeviceConfig);
 
+#ifdef VLAN_SUPPORT
+	/* Set VLAN type to 802.1q */
+	writel(ETH_P_8021Q, ioaddr + VlanType);
+#endif /* VLAN_SUPPORT */
+
 #ifdef HAS_FIRMWARE
 	/* Load Rx/Tx firmware into the frame processors */
 	for (i = 0; i < FIRMWARE_RX_SIZE * 2; i++)
 		writel(firmware_rx[i], ioaddr + RxGfpMem + i * 4);
 	for (i = 0; i < FIRMWARE_TX_SIZE * 2; i++)
 		writel(firmware_tx[i], ioaddr + TxGfpMem + i * 4);
-	/* Enable the Rx and Tx units, and the Rx/Tx frame processors. */
-	writel(0x003F, ioaddr + GenCtrl);
-#else  /* not HAS_FIRMWARE */
-	/* Enable the Rx and Tx units only. */
-	writel(0x000F, ioaddr + GenCtrl);
-#endif /* not HAS_FIRMWARE */
+#endif /* HAS_FIRMWARE */
+	if (enable_hw_cksum)
+		/* Enable the Rx and Tx units, and the Rx/Tx frame processors. */
+		writel(TxEnable|TxGFPEnable|RxEnable|RxGFPEnable, ioaddr + GenCtrl);
+	else
+		/* Enable the Rx and Tx units only. */
+		writel(TxEnable|RxEnable, ioaddr + GenCtrl);
 
-	if (debug > 2)
+	if (debug > 1)
 		printk(KERN_DEBUG "%s: Done netdev_open().\n",
 		       dev->name);
 
@@ -1022,26 +1222,32 @@
 {
 	struct netdev_private *np = dev->priv;
 	u16 reg0;
+	int silly_count = 1000;
 
-	mdio_write(dev, np->phys[0], MII_ADVERTISE, np->advertising);
+	mdio_write(dev, np->phys[0], MII_ADVERTISE, np->mii_if.advertising);
 	mdio_write(dev, np->phys[0], MII_BMCR, BMCR_RESET);
 	udelay(500);
-	while (mdio_read(dev, np->phys[0], MII_BMCR) & BMCR_RESET);
+	while (--silly_count && mdio_read(dev, np->phys[0], MII_BMCR) & BMCR_RESET)
+		/* do nothing */;
+	if (!silly_count) {
+		printk("%s: MII reset failed!\n", dev->name);
+		return;
+	}
 
 	reg0 = mdio_read(dev, np->phys[0], MII_BMCR);
 
-	if (np->autoneg) {
+	if (!np->mii_if.force_media) {
 		reg0 |= BMCR_ANENABLE | BMCR_ANRESTART;
 	} else {
 		reg0 &= ~(BMCR_ANENABLE | BMCR_ANRESTART);
 		if (np->speed100)
 			reg0 |= BMCR_SPEED100;
-		if (np->full_duplex)
+		if (np->mii_if.full_duplex)
 			reg0 |= BMCR_FULLDPLX;
 		printk(KERN_DEBUG "%s: Link forced to %sMbit %s-duplex\n",
 		       dev->name,
 		       np->speed100 ? "100" : "10",
-		       np->full_duplex ? "full" : "half");
+		       np->mii_if.full_duplex ? "full" : "half");
 	}
 	mdio_write(dev, np->phys[0], MII_BMCR, reg0);
 }
@@ -1051,25 +1257,22 @@
 {
 	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
+	int old_debug;
 
-	printk(KERN_WARNING "%s: Transmit timed out, status %8.8x,"
-	       " resetting...\n", dev->name, (int)readl(ioaddr + IntrStatus));
-
-#ifndef __alpha__
-	{
-		int i;
-		printk(KERN_DEBUG "  Rx ring %p: ", np->rx_ring);
-		for (i = 0; i < RX_RING_SIZE; i++)
-			printk(" %8.8x", (unsigned int)le32_to_cpu(np->rx_ring[i].rxaddr));
-		printk("\n"KERN_DEBUG"  Tx ring %p: ", np->tx_ring);
-		for (i = 0; i < TX_RING_SIZE; i++)
-			printk(" %4.4x", le32_to_cpu(np->tx_ring[i].status));
-		printk("\n");
-	}
-#endif
+	printk(KERN_WARNING "%s: Transmit timed out, status %#8.8x, "
+	       "resetting...\n", dev->name, (int) readl(ioaddr + IntrStatus));
 
 	/* Perhaps we should reinitialize the hardware here. */
-	/* Stop and restart the chip's Tx processes . */
+
+	/*
+	 * Stop and restart the interface.
+	 * Cheat and increase the debug level temporarily.
+	 */
+	old_debug = debug;
+	debug = 2;
+	netdev_close(dev);
+	netdev_open(dev);
+	debug = old_debug;
 
 	/* Trigger an immediate transmit demand. */
 
@@ -1085,9 +1288,8 @@
 	struct netdev_private *np = dev->priv;
 	int i;
 
-	np->tx_full = 0;
-	np->cur_rx = np->cur_tx = 0;
-	np->dirty_rx = np->rx_done = np->dirty_tx = np->tx_done = 0;
+	np->cur_rx = np->cur_tx = np->reap_tx = 0;
+	np->dirty_rx = np->dirty_tx = np->rx_done = np->tx_done = 0;
 
 	np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
 
@@ -1100,7 +1302,7 @@
 		np->rx_info[i].mapping = pci_map_single(np->pci_dev, skb->tail, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
 		skb->dev = dev;			/* Mark as being used by this device. */
 		/* Grrr, we cannot offset to correctly align the IP header. */
-		np->rx_ring[i].rxaddr = cpu_to_le32(np->rx_info[i].mapping | RxDescValid);
+		np->rx_ring[i].rxaddr = cpu_to_dma(np->rx_info[i].mapping | RxDescValid);
 	}
 	writew(i - 1, dev->base_addr + RxDescQIdx);
 	np->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
@@ -1112,7 +1314,7 @@
 		np->rx_info[i].mapping = 0;
 	}
 	/* Mark the last entry as wrapping the ring. */
-	np->rx_ring[i-1].rxaddr |= cpu_to_le32(RxDescEndRing);
+	np->rx_ring[RX_RING_SIZE - 1].rxaddr |= cpu_to_dma(RxDescEndRing);
 
 	/* Clear the completion rings. */
 	for (i = 0; i < DONE_Q_SIZE; i++) {
@@ -1120,18 +1322,9 @@
 		np->tx_done_q[i].status = 0;
 	}
 
-	for (i = 0; i < TX_RING_SIZE; i++) {
-		np->tx_info[i].skb = NULL;
-		np->tx_info[i].first_mapping = 0;
-#ifdef ZEROCOPY
-		{
-			int j;
-			for (j = 0; j < MAX_STARFIRE_FRAGS; j++)
-				np->tx_info[i].frag_mapping[j] = 0;
-		}
-#endif /* ZEROCOPY */
-		np->tx_ring[i].status = 0;
-	}
+	for (i = 0; i < TX_RING_SIZE; i++)
+		memset(&np->tx_info[i], 0, sizeof(np->tx_info[i]));
+
 	return;
 }
 
@@ -1140,19 +1333,21 @@
 {
 	struct netdev_private *np = dev->priv;
 	unsigned int entry;
-#ifdef ZEROCOPY
+	u32 status;
 	int i;
-#endif
 
 	kick_tx_timer(dev, tx_timeout, TX_TIMEOUT);
 
-	/* Caution: the write order is important here, set the field
-	   with the "ownership" bits last. */
-
-	/* Calculate the next Tx descriptor entry. */
-	entry = np->cur_tx % TX_RING_SIZE;
+	/*
+	 * be cautious here, wrapping the queue has weird semantics
+	 * and we may not have enough slots even when it seems we do.
+	 */
+	if ((np->cur_tx - np->dirty_tx) + skb_num_frags(skb) * 2 > TX_RING_SIZE) {
+		netif_stop_queue(dev);
+		return 1;
+	}
 
-#if defined(ZEROCOPY) && defined(HAS_FIRMWARE) && defined(HAS_BROKEN_FIRMWARE)
+#if defined(ZEROCOPY) && defined(HAS_BROKEN_FIRMWARE)
 	{
 		int has_bad_length = 0;
 
@@ -1169,85 +1364,72 @@
 		if (has_bad_length)
 			skb_checksum_help(skb);
 	}
-#endif /* ZEROCOPY && HAS_FIRMWARE && HAS_BROKEN_FIRMWARE */
-
-	np->tx_info[entry].skb = skb;
-	np->tx_info[entry].first_mapping =
-		pci_map_single(np->pci_dev, skb->data, skb_first_frag_len(skb), PCI_DMA_TODEVICE);
-
-	np->tx_ring[entry].first_addr = cpu_to_le32(np->tx_info[entry].first_mapping);
-#ifdef ZEROCOPY
-	np->tx_ring[entry].first_len = cpu_to_le16(skb_first_frag_len(skb));
-	np->tx_ring[entry].total_len = cpu_to_le16(skb->len);
-	/* Add "| TxDescIntr" to generate Tx-done interrupts. */
-	np->tx_ring[entry].status = cpu_to_le32(TxDescID | TxCRCEn);
-	np->tx_ring[entry].nbufs = cpu_to_le32(skb_shinfo(skb)->nr_frags + 1);
-#else  /* not ZEROCOPY */
-	/* Add "| TxDescIntr" to generate Tx-done interrupts. */
-	np->tx_ring[entry].status = cpu_to_le32(skb->len | TxDescID | TxCRCEn | 1 << 16);
-#endif /* not ZEROCOPY */
-
-	if (entry >= TX_RING_SIZE-1)		 /* Wrap ring */
-		np->tx_ring[entry].status |= cpu_to_le32(TxRingWrap | TxDescIntr);
-
-#ifdef ZEROCOPY
-	if (skb->ip_summed == CHECKSUM_HW) {
-		np->tx_ring[entry].status |= cpu_to_le32(TxCalTCP);
-		np->stats.tx_compressed++;
-	}
-#endif /* ZEROCOPY */
+#endif /* ZEROCOPY && HAS_BROKEN_FIRMWARE */
 
-	if (debug > 5) {
-#ifdef ZEROCOPY
-		printk(KERN_DEBUG "%s: Tx #%d slot %d status %8.8x nbufs %d len %4.4x/%4.4x.\n",
-		       dev->name, np->cur_tx, entry,
-		       le32_to_cpu(np->tx_ring[entry].status),
-		       le32_to_cpu(np->tx_ring[entry].nbufs),
-		       le32_to_cpu(np->tx_ring[entry].first_len),
-		       le32_to_cpu(np->tx_ring[entry].total_len));
-#else  /* not ZEROCOPY */
-		printk(KERN_DEBUG "%s: Tx #%d slot %d status %8.8x.\n",
-		       dev->name, np->cur_tx, entry,
-		       le32_to_cpu(np->tx_ring[entry].status));
-#endif /* not ZEROCOPY */
-	}
-
-#ifdef ZEROCOPY
-	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
-		skb_frag_t *this_frag = &skb_shinfo(skb)->frags[i];
+	entry = np->cur_tx % TX_RING_SIZE;
+	for (i = 0; i < skb_num_frags(skb); i++) {
+		int wrap_ring = 0;
+		status = TxDescID;
+
+		if (i == 0) {
+			np->tx_info[entry].skb = skb;
+			status |= TxCRCEn;
+			if (entry >= TX_RING_SIZE - skb_num_frags(skb)) {
+				status |= TxRingWrap;
+				wrap_ring = 1;
+			}
+			if (np->reap_tx) {
+				status |= TxDescIntr;
+				np->reap_tx = 0;
+			}
+			if (skb->ip_summed == CHECKSUM_HW) {
+				status |= TxCalTCP;
+				np->stats.tx_compressed++;
+			}
+			status |= skb_first_frag_len(skb) | (skb_num_frags(skb) << 16);
 
-		/* we already have the proper value in entry */
-		np->tx_info[entry].frag_mapping[i] =
-			pci_map_single(np->pci_dev, page_address(this_frag->page) + this_frag->page_offset, this_frag->size, PCI_DMA_TODEVICE);
-
-		np->tx_ring[entry].frag[i].addr = cpu_to_le32(np->tx_info[entry].frag_mapping[i]);
-		np->tx_ring[entry].frag[i].len = cpu_to_le32(this_frag->size);
-		if (debug > 5) {
-			printk(KERN_DEBUG "%s: Tx #%d frag %d len %4.4x.\n",
-			       dev->name, np->cur_tx, i,
-			       le32_to_cpu(np->tx_ring[entry].frag[i].len));
-		}
+			np->tx_info[entry].mapping =
+				pci_map_single(np->pci_dev, skb->data, skb_first_frag_len(skb), PCI_DMA_TODEVICE);
+		} else {
+#ifdef MAX_SKB_FRAGS
+			skb_frag_t *this_frag = &skb_shinfo(skb)->frags[i - 1];
+			status |= this_frag->size;
+			np->tx_info[entry].mapping =
+				pci_map_single(np->pci_dev, page_address(this_frag->page) + this_frag->page_offset, this_frag->size, PCI_DMA_TODEVICE);
+#endif /* MAX_SKB_FRAGS */
+		}
+
+		np->tx_ring[entry].addr = cpu_to_dma(np->tx_info[entry].mapping);
+		np->tx_ring[entry].status = cpu_to_le32(status);
+		if (debug > 3)
+			printk(KERN_DEBUG "%s: Tx #%d/#%d slot %d status %#8.8x.\n",
+			       dev->name, np->cur_tx, np->dirty_tx,
+			       entry, status);
+		if (wrap_ring) {
+			np->tx_info[entry].used_slots = TX_RING_SIZE - entry;
+			np->cur_tx += np->tx_info[entry].used_slots;
+			entry = 0;
+		} else {
+			np->tx_info[entry].used_slots = 1;
+			np->cur_tx += np->tx_info[entry].used_slots;
+			entry++;
+		}
+		/* scavenge the tx descriptors twice per TX_RING_SIZE */
+		if (np->cur_tx % (TX_RING_SIZE / 2) == 0)
+			np->reap_tx = 1;
 	}
-#endif /* ZEROCOPY */
-
-	np->cur_tx++;
-
-	if (entry >= TX_RING_SIZE-1)		 /* Wrap ring */
-		entry = -1;
-	entry++;
 
 	/* Non-x86: explicitly flush descriptor cache lines here. */
-	/* Ensure everything is written back above before the transmit is
+	/* Ensure all descriptors are written back before the transmit is
 	   initiated. - Jes */
 	wmb();
 
 	/* Update the producer index. */
-	writel(entry * (sizeof(struct starfire_tx_desc) / 8), dev->base_addr + TxProducerIdx);
+	writel(entry * (sizeof(starfire_tx_desc) / 8), dev->base_addr + TxProducerIdx);
 
-	if (np->cur_tx - np->dirty_tx >= TX_RING_SIZE - 1) {
-		np->tx_full = 1;
+	/* 4 is arbitrary, but should be ok */
+	if ((np->cur_tx - np->dirty_tx) + 4 > TX_RING_SIZE)
 		netif_stop_queue(dev);
-	}
 
 	dev->trans_start = jiffies;
 
@@ -1259,20 +1441,13 @@
    after the Tx thread. */
 static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
 {
-	struct net_device *dev = (struct net_device *)dev_instance;
+	struct net_device *dev = dev_instance;
 	struct netdev_private *np;
 	long ioaddr;
 	int boguscnt = max_interrupt_work;
 	int consumer;
 	int tx_status;
 
-#ifndef final_version			/* Can never occur. */
-	if (dev == NULL) {
-		printk (KERN_ERR "Netdev interrupt handler(): IRQ %d for unknown device.\n", irq);
-		return;
-	}
-#endif
-
 	ioaddr = dev->base_addr;
 	np = dev->priv;
 
@@ -1280,83 +1455,69 @@
 		u32 intr_status = readl(ioaddr + IntrClear);
 
 		if (debug > 4)
-			printk(KERN_DEBUG "%s: Interrupt status %4.4x.\n",
+			printk(KERN_DEBUG "%s: Interrupt status %#8.8x.\n",
 			       dev->name, intr_status);
 
-		if (intr_status == 0)
+		if (intr_status == 0 || intr_status == (u32) -1)
 			break;
 
-		if (intr_status & IntrRxDone)
+		if (intr_status & (IntrRxDone | IntrRxEmpty))
 			netdev_rx(dev);
 
 		/* Scavenge the skbuff list based on the Tx-done queue.
 		   There are redundant checks here that may be cleaned up
 		   after the driver has proven to be reliable. */
 		consumer = readl(ioaddr + TxConsumerIdx);
-		if (debug > 4)
+		if (debug > 3)
 			printk(KERN_DEBUG "%s: Tx Consumer index is %d.\n",
 			       dev->name, consumer);
-#if 0
-		if (np->tx_done >= 250 || np->tx_done == 0)
-			printk(KERN_DEBUG "%s: Tx completion entry %d is %8.8x, %d is %8.8x.\n",
-			       dev->name, np->tx_done,
-			       le32_to_cpu(np->tx_done_q[np->tx_done].status),
-			       (np->tx_done+1) & (DONE_Q_SIZE-1),
-			       le32_to_cpu(np->tx_done_q[(np->tx_done+1)&(DONE_Q_SIZE-1)].status));
-#endif
 
 		while ((tx_status = le32_to_cpu(np->tx_done_q[np->tx_done].status)) != 0) {
-			if (debug > 4)
-				printk(KERN_DEBUG "%s: Tx completion entry %d is %8.8x.\n",
-				       dev->name, np->tx_done, tx_status);
+			if (debug > 3)
+				printk(KERN_DEBUG "%s: Tx completion #%d entry %d is %#8.8x.\n",
+				       dev->name, np->dirty_tx, np->tx_done, tx_status);
 			if ((tx_status & 0xe0000000) == 0xa0000000) {
 				np->stats.tx_packets++;
 			} else if ((tx_status & 0xe0000000) == 0x80000000) {
-				struct sk_buff *skb;
-#ifdef ZEROCOPY
-				int i;
-#endif /* ZEROCOPY */
-				u16 entry = tx_status;		/* Implicit truncate */
-				entry /= sizeof(struct starfire_tx_desc);
-
-				skb = np->tx_info[entry].skb;
+				u16 entry = (tx_status & 0x7fff) / sizeof(starfire_tx_desc);
+				struct sk_buff *skb = np->tx_info[entry].skb;
 				np->tx_info[entry].skb = NULL;
 				pci_unmap_single(np->pci_dev,
-						 np->tx_info[entry].first_mapping,
+						 np->tx_info[entry].mapping,
 						 skb_first_frag_len(skb),
 						 PCI_DMA_TODEVICE);
-				np->tx_info[entry].first_mapping = 0;
-
-#ifdef ZEROCOPY
-				for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
-					pci_unmap_single(np->pci_dev,
-							 np->tx_info[entry].frag_mapping[i],
-							 skb_shinfo(skb)->frags[i].size,
-							 PCI_DMA_TODEVICE);
-					np->tx_info[entry].frag_mapping[i] = 0;
+				np->tx_info[entry].mapping = 0;
+				np->dirty_tx += np->tx_info[entry].used_slots;
+				entry = (entry + np->tx_info[entry].used_slots) % TX_RING_SIZE;
+#ifdef MAX_SKB_FRAGS
+				{
+					int i;
+					for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+						pci_unmap_single(np->pci_dev,
+								 np->tx_info[entry].mapping,
+								 skb_shinfo(skb)->frags[i].size,
+								 PCI_DMA_TODEVICE);
+						np->dirty_tx++;
+						entry++;
+					}
 				}
-#endif /* ZEROCOPY */
-
-				/* Scavenge the descriptor. */
+#endif /* MAX_SKB_FRAGS */
 				dev_kfree_skb_irq(skb);
-
-				np->dirty_tx++;
 			}
 			np->tx_done_q[np->tx_done].status = 0;
-			np->tx_done = (np->tx_done+1) & (DONE_Q_SIZE-1);
+			np->tx_done = (np->tx_done + 1) % DONE_Q_SIZE;
 		}
 		writew(np->tx_done, ioaddr + CompletionQConsumerIdx + 2);
 
-		if (np->tx_full && np->cur_tx - np->dirty_tx < TX_RING_SIZE - 4) {
+		if (netif_queue_stopped(dev) &&
+		    (np->cur_tx - np->dirty_tx + 4 < TX_RING_SIZE)) {
 			/* The ring is no longer full, wake the queue. */
-			np->tx_full = 0;
 			netif_wake_queue(dev);
 		}
 
 		/* Stats overflow */
-		if (intr_status & IntrStatsMax) {
+		if (intr_status & IntrStatsMax)
 			get_stats(dev);
-		}
 
 		/* Media change interrupt. */
 		if (intr_status & IntrLinkChange)
@@ -1367,28 +1528,17 @@
 			netdev_error(dev, intr_status);
 
 		if (--boguscnt < 0) {
-			printk(KERN_WARNING "%s: Too much work at interrupt, "
-			       "status=0x%4.4x.\n",
-			       dev->name, intr_status);
+			if (debug > 1)
+				printk(KERN_WARNING "%s: Too much work at interrupt, "
+				       "status=%#8.8x.\n",
+				       dev->name, intr_status);
 			break;
 		}
 	} while (1);
 
 	if (debug > 4)
-		printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
-		       dev->name, (int)readl(ioaddr + IntrStatus));
-
-#ifndef final_version
-	/* Code that should never be run!  Remove after testing.. */
-	{
-		static int stopit = 10;
-		if (!netif_running(dev) && --stopit < 0) {
-			printk(KERN_ERR "%s: Emergency stop, looping startup interrupt.\n",
-			       dev->name);
-			free_irq(irq, dev);
-		}
-	}
-#endif
+		printk(KERN_DEBUG "%s: exiting interrupt, status=%#8.8x.\n",
+		       dev->name, (int) readl(ioaddr + IntrStatus));
 }
 
 
@@ -1400,26 +1550,21 @@
 	int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx;
 	u32 desc_status;
 
-	if (np->rx_done_q == 0) {
-		printk(KERN_ERR "%s:  rx_done_q is NULL!  rx_done is %d. %p.\n",
-		       dev->name, np->rx_done, np->tx_done_q);
-		return 0;
-	}
-
 	/* If EOP is set on the next entry, it's a new packet. Send it up. */
 	while ((desc_status = le32_to_cpu(np->rx_done_q[np->rx_done].status)) != 0) {
 		struct sk_buff *skb;
 		u16 pkt_len;
 		int entry;
+		rx_done_desc *desc = &np->rx_done_q[np->rx_done];
 
 		if (debug > 4)
-			printk(KERN_DEBUG "  netdev_rx() status of %d was %8.8x.\n", np->rx_done, desc_status);
+			printk(KERN_DEBUG "  netdev_rx() status of %d was %#8.8x.\n", np->rx_done, desc_status);
 		if (--boguscnt < 0)
 			break;
-		if ( ! (desc_status & RxOK)) {
+		if (!(desc_status & RxOK)) {
 			/* There was a error. */
 			if (debug > 2)
-				printk(KERN_DEBUG "  netdev_rx() Rx error was %8.8x.\n", desc_status);
+				printk(KERN_DEBUG "  netdev_rx() Rx error was %#8.8x.\n", desc_status);
 			np->stats.rx_errors++;
 			if (desc_status & RxFIFOErr)
 				np->stats.rx_fifo_errors++;
@@ -1429,10 +1574,8 @@
 		pkt_len = desc_status;	/* Implicitly Truncate */
 		entry = (desc_status >> 16) & 0x7ff;
 
-#ifndef final_version
 		if (debug > 4)
 			printk(KERN_DEBUG "  netdev_rx() normal Rx pkt length %d, bogus_cnt %d.\n", pkt_len, boguscnt);
-#endif
 		/* Check if the packet is long enough to accept without copying
 		   to a minimally-sized skbuff. */
 		if (pkt_len < rx_copybreak
@@ -1442,12 +1585,8 @@
 			pci_dma_sync_single(np->pci_dev,
 					    np->rx_info[entry].mapping,
 					    pkt_len, PCI_DMA_FROMDEVICE);
-#if HAS_IP_COPYSUM			/* Call copy + cksum if available. */
 			eth_copy_and_sum(skb, np->rx_info[entry].skb->tail, pkt_len, 0);
 			skb_put(skb, pkt_len);
-#else
-			memcpy(skb_put(skb, pkt_len), np->rx_info[entry].skb->tail, pkt_len);
-#endif
 		} else {
 			pci_unmap_single(np->pci_dev, np->rx_info[entry].mapping, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
 			skb = np->rx_info[entry].skb;
@@ -1459,44 +1598,54 @@
 		/* You will want this info for the initial debug. */
 		if (debug > 5)
 			printk(KERN_DEBUG "  Rx data %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:"
-			       "%2.2x %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x %2.2x%2.2x "
-			       "%d.%d.%d.%d.\n",
+			       "%2.2x %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x %2.2x%2.2x.\n",
 			       skb->data[0], skb->data[1], skb->data[2], skb->data[3],
 			       skb->data[4], skb->data[5], skb->data[6], skb->data[7],
 			       skb->data[8], skb->data[9], skb->data[10],
-			       skb->data[11], skb->data[12], skb->data[13],
-			       skb->data[14], skb->data[15], skb->data[16],
-			       skb->data[17]);
+			       skb->data[11], skb->data[12], skb->data[13]);
 #endif
+
 		skb->protocol = eth_type_trans(skb, dev);
-#if defined(full_rx_status) || defined(csum_rx_status)
-		if (le32_to_cpu(np->rx_done_q[np->rx_done].status2) & 0x01000000) {
+#if defined(HAS_FIRMWARE) || defined(VLAN_SUPPORT)
+		if (debug > 4)
+			printk(KERN_DEBUG "  netdev_rx() status2 of %d was %#4.4x.\n", np->rx_done, le16_to_cpu(desc->status2));
+#endif
+#ifdef HAS_FIRMWARE
+		if (le16_to_cpu(desc->status2) & 0x0100) {
 			skb->ip_summed = CHECKSUM_UNNECESSARY;
 			np->stats.rx_compressed++;
 		}
 		/*
 		 * This feature doesn't seem to be working, at least
 		 * with the two firmware versions I have. If the GFP sees
-		 * a fragment, it either ignores it completely, or reports
+		 * an IP fragment, it either ignores it completely, or reports
 		 * "bad checksum" on it.
 		 *
 		 * Maybe I missed something -- corrections are welcome.
 		 * Until then, the printk stays. :-) -Ion
 		 */
-		else if (le32_to_cpu(np->rx_done_q[np->rx_done].status2) & 0x00400000) {
+		else if (le16_to_cpu(desc->status2) & 0x0040) {
 			skb->ip_summed = CHECKSUM_HW;
-			skb->csum = le32_to_cpu(np->rx_done_q[np->rx_done].status2) & 0xffff;
-			printk(KERN_DEBUG "%s: checksum_hw, status2 = %x\n", dev->name, np->rx_done_q[np->rx_done].status2);
+			skb->csum = le16_to_cpu(desc->csum);
+			printk(KERN_DEBUG "%s: checksum_hw, status2 = %#x\n", dev->name, le16_to_cpu(desc->status2));
 		}
-#endif
-		netif_rx(skb);
+#endif /* HAS_FIRMWARE */
+#ifdef VLAN_SUPPORT
+		if (np->vlgrp && le16_to_cpu(desc->status2) & 0x0200) {
+			if (debug > 4)
+				printk(KERN_DEBUG "  netdev_rx() vlanid = %d\n", le16_to_cpu(desc->vlanid));
+			/* vlan_hwaccel_rx expects a packet with the VLAN tag stripped out */
+			vlan_hwaccel_rx(skb, np->vlgrp, le16_to_cpu(desc->vlanid) & VLAN_VID_MASK);
+		} else
+#endif /* VLAN_SUPPORT */
+			netif_rx(skb);
 		dev->last_rx = jiffies;
 		np->stats.rx_packets++;
 
-next_rx:
+	next_rx:
 		np->cur_rx++;
-		np->rx_done_q[np->rx_done].status = 0;
-		np->rx_done = (np->rx_done + 1) & (DONE_Q_SIZE-1);
+		desc->status = 0;
+		np->rx_done = (np->rx_done + 1) % DONE_Q_SIZE;
 	}
 	writew(np->rx_done, dev->base_addr + CompletionQConsumerIdx);
 
@@ -1513,16 +1662,16 @@
 				pci_map_single(np->pci_dev, skb->tail, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
 			skb->dev = dev;	/* Mark as being used by this device. */
 			np->rx_ring[entry].rxaddr =
-				cpu_to_le32(np->rx_info[entry].mapping | RxDescValid);
+				cpu_to_dma(np->rx_info[entry].mapping | RxDescValid);
 		}
 		if (entry == RX_RING_SIZE - 1)
-			np->rx_ring[entry].rxaddr |= cpu_to_le32(RxDescEndRing);
+			np->rx_ring[entry].rxaddr |= cpu_to_dma(RxDescEndRing);
 		/* We could defer this until later... */
 		writew(entry, dev->base_addr + RxDescQIdx);
 	}
 
 	if (debug > 5)
-		printk(KERN_DEBUG "  exiting netdev_rx() status of %d was %8.8x.\n",
+		printk(KERN_DEBUG "  exiting netdev_rx() status of %d was %#8.8x.\n",
 		       np->rx_done, desc_status);
 
 	/* Restart Rx engine if stopped. */
@@ -1536,6 +1685,7 @@
 	long ioaddr = dev->base_addr;
 	u16 reg0, reg1, reg4, reg5;
 	u32 new_tx_mode;
+	u32 new_intr_timer_ctrl;
 
 	/* reset status first */
 	mdio_read(dev, np->phys[0], MII_BMCR);
@@ -1552,16 +1702,16 @@
 			reg5 = mdio_read(dev, np->phys[0], MII_LPA);
 			if (reg4 & ADVERTISE_100FULL && reg5 & LPA_100FULL) {
 				np->speed100 = 1;
-				np->full_duplex = 1;
+				np->mii_if.full_duplex = 1;
 			} else if (reg4 & ADVERTISE_100HALF && reg5 & LPA_100HALF) {
 				np->speed100 = 1;
-				np->full_duplex = 0;
+				np->mii_if.full_duplex = 0;
 			} else if (reg4 & ADVERTISE_10FULL && reg5 & LPA_10FULL) {
 				np->speed100 = 0;
-				np->full_duplex = 1;
+				np->mii_if.full_duplex = 1;
 			} else {
 				np->speed100 = 0;
-				np->full_duplex = 0;
+				np->mii_if.full_duplex = 0;
 			}
 		} else {
 			/* autonegotiation is disabled */
@@ -1570,25 +1720,35 @@
 			else
 				np->speed100 = 0;
 			if (reg0 & BMCR_FULLDPLX)
-				np->full_duplex = 1;
+				np->mii_if.full_duplex = 1;
 			else
-				np->full_duplex = 0;
+				np->mii_if.full_duplex = 0;
 		}
+		netif_carrier_on(dev);
 		printk(KERN_DEBUG "%s: Link is up, running at %sMbit %s-duplex\n",
 		       dev->name,
 		       np->speed100 ? "100" : "10",
-		       np->full_duplex ? "full" : "half");
+		       np->mii_if.full_duplex ? "full" : "half");
 
-		new_tx_mode = np->tx_mode & ~0x2;	/* duplex setting */
-		if (np->full_duplex)
-			new_tx_mode |= 2;
+		new_tx_mode = np->tx_mode & ~FullDuplex;	/* duplex setting */
+		if (np->mii_if.full_duplex)
+			new_tx_mode |= FullDuplex;
 		if (np->tx_mode != new_tx_mode) {
 			np->tx_mode = new_tx_mode;
-			writel(np->tx_mode | 0x8000, ioaddr + TxMode);
+			writel(np->tx_mode | MiiSoftReset, ioaddr + TxMode);
 			udelay(1000);
 			writel(np->tx_mode, ioaddr + TxMode);
 		}
+
+		new_intr_timer_ctrl = np->intr_timer_ctrl & ~Timer10X;
+		if (np->speed100)
+			new_intr_timer_ctrl |= Timer10X;
+		if (np->intr_timer_ctrl != new_intr_timer_ctrl) {
+			np->intr_timer_ctrl = new_intr_timer_ctrl;
+			writel(new_intr_timer_ctrl, ioaddr + IntrTimerCtrl);
+		}
 	} else {
+		netif_carrier_off(dev);
 		printk(KERN_DEBUG "%s: Link is down\n", dev->name);
 	}
 }
@@ -1600,9 +1760,12 @@
 
 	/* Came close to underrunning the Tx FIFO, increase threshold. */
 	if (intr_status & IntrTxDataLow) {
-		writel(++np->tx_threshold, dev->base_addr + TxThreshold);
-		printk(KERN_NOTICE "%s: Increasing Tx FIFO threshold to %d bytes\n",
-		       dev->name, np->tx_threshold * 16);
+		if (np->tx_threshold <= PKT_BUF_SZ / 16) {
+			writel(++np->tx_threshold, dev->base_addr + TxThreshold);
+			printk(KERN_NOTICE "%s: PCI bus congestion, increasing Tx FIFO threshold to %d bytes\n",
+			       dev->name, np->tx_threshold * 16);
+		} else
+			printk(KERN_WARNING "%s: PCI Tx underflow -- adapter is probably malfunctioning\n", dev->name);
 	}
 	if (intr_status & IntrRxGFPDead) {
 		np->stats.rx_fifo_errors++;
@@ -1613,7 +1776,7 @@
 		np->stats.tx_errors++;
 	}
 	if ((intr_status & ~(IntrNormalMask | IntrAbnormalSummary | IntrLinkChange | IntrStatsMax | IntrTxDataLow | IntrRxGFPDead | IntrNoTxCsum | IntrPCIPad)) && debug)
-		printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n",
+		printk(KERN_ERR "%s: Something Wicked happened! %#8.8x.\n",
 		       dev->name, intr_status);
 }
 
@@ -1648,39 +1811,67 @@
 /* Chips may use the upper or lower CRC bits, and may reverse and/or invert
    them.  Select the endian-ness that results in minimal calculations.
 */
-
 static void set_rx_mode(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
-	u32 rx_mode;
+	u32 rx_mode = MinVLANPrio;
 	struct dev_mc_list *mclist;
 	int i;
+#ifdef VLAN_SUPPORT
+	struct netdev_private *np = dev->priv;
+
+	rx_mode |= VlanMode;
+	if (np->vlgrp) {
+		int vlan_count = 0;
+		long filter_addr = ioaddr + HashTable + 8;
+		for (i = 0; i < VLAN_VID_MASK; i++) {
+			if (np->vlgrp->vlan_devices[i]) {
+				if (vlan_count >= 32)
+					break;
+				writew(cpu_to_be16(i), filter_addr);
+				filter_addr += 16;
+				vlan_count++;
+			}
+		}
+		if (i == VLAN_VID_MASK) {
+			rx_mode |= PerfectFilterVlan;
+			while (vlan_count < 32) {
+				writew(0, filter_addr);
+				filter_addr += 16;
+				vlan_count++;
+			}
+		}
+	}
+#endif /* VLAN_SUPPORT */
 
 	if (dev->flags & IFF_PROMISC) {	/* Set promiscuous. */
-		rx_mode = AcceptBroadcast|AcceptAllMulticast|AcceptAll|AcceptMyPhys;
+		rx_mode |= AcceptAll;
 	} else if ((dev->mc_count > multicast_filter_limit)
 		   || (dev->flags & IFF_ALLMULTI)) {
 		/* Too many to match, or accept all multicasts. */
-		rx_mode = AcceptBroadcast|AcceptAllMulticast|AcceptMyPhys;
-	} else if (dev->mc_count <= 15) {
-		/* Use the 16 element perfect filter, skip first entry. */
-		long filter_addr = ioaddr + PerfFilterTable + 1 * 16;
-		for (i = 1, mclist = dev->mc_list; mclist && i <= dev->mc_count;
+		rx_mode |= AcceptBroadcast|AcceptAllMulticast|PerfectFilter;
+	} else if (dev->mc_count <= 14) {
+		/* Use the 16 element perfect filter, skip first two entries. */
+		long filter_addr = ioaddr + PerfFilterTable + 2 * 16;
+		u16 *eaddrs;
+		for (i = 2, mclist = dev->mc_list; mclist && i < dev->mc_count + 2;
 		     i++, mclist = mclist->next) {
-			u16 *eaddrs = (u16 *)mclist->dmi_addr;
+			eaddrs = (u16 *)mclist->dmi_addr;
 			writew(cpu_to_be16(eaddrs[2]), filter_addr); filter_addr += 4;
 			writew(cpu_to_be16(eaddrs[1]), filter_addr); filter_addr += 4;
 			writew(cpu_to_be16(eaddrs[0]), filter_addr); filter_addr += 8;
 		}
+		eaddrs = (u16 *)dev->dev_addr;
 		while (i++ < 16) {
-			writew(0xffff, filter_addr); filter_addr += 4;
-			writew(0xffff, filter_addr); filter_addr += 4;
-			writew(0xffff, filter_addr); filter_addr += 8;
+			writew(cpu_to_be16(eaddrs[0]), filter_addr); filter_addr += 4;
+			writew(cpu_to_be16(eaddrs[1]), filter_addr); filter_addr += 4;
+			writew(cpu_to_be16(eaddrs[2]), filter_addr); filter_addr += 8;
 		}
-		rx_mode = AcceptBroadcast | AcceptMyPhys;
+		rx_mode |= AcceptBroadcast|PerfectFilter;
 	} else {
 		/* Must use a multicast hash table. */
 		long filter_addr;
+		u16 *eaddrs;
 		u16 mc_filter[32] __attribute__ ((aligned(sizeof(long))));	/* Multicast hash filter */
 
 		memset(mc_filter, 0, sizeof(mc_filter));
@@ -1691,16 +1882,17 @@
 
 			*fptr |= cpu_to_le32(1 << (bit_nr & 31));
 		}
-		/* Clear the perfect filter list, skip first entry. */
-		filter_addr = ioaddr + PerfFilterTable + 1 * 16;
-		for (i = 1; i < 16; i++) {
-			writew(0xffff, filter_addr); filter_addr += 4;
-			writew(0xffff, filter_addr); filter_addr += 4;
-			writew(0xffff, filter_addr); filter_addr += 8;
+		/* Clear the perfect filter list, skip first two entries. */
+		filter_addr = ioaddr + PerfFilterTable + 2 * 16;
+		eaddrs = (u16 *)dev->dev_addr;
+		for (i = 2; i < 16; i++) {
+			writew(cpu_to_be16(eaddrs[0]), filter_addr); filter_addr += 4;
+			writew(cpu_to_be16(eaddrs[1]), filter_addr); filter_addr += 4;
+			writew(cpu_to_be16(eaddrs[2]), filter_addr); filter_addr += 8;
 		}
-		for (filter_addr = ioaddr + HashTable, i=0; i < 32; filter_addr+= 16, i++)
+		for (filter_addr = ioaddr + HashTable, i = 0; i < 32; filter_addr+= 16, i++)
 			writew(mc_filter[i], filter_addr);
-		rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
+		rx_mode |= AcceptBroadcast|PerfectFilter|HashFilter;
 	}
 	writel(rx_mode, ioaddr + RxFilterMode);
 }
@@ -1715,77 +1907,6 @@
 		return -EFAULT;
 
 	switch (ecmd.cmd) {
-	case ETHTOOL_GSET:
-		ecmd.supported =
-			SUPPORTED_10baseT_Half |
-			SUPPORTED_10baseT_Full |
-			SUPPORTED_100baseT_Half |
-			SUPPORTED_100baseT_Full |
-			SUPPORTED_Autoneg |
-			SUPPORTED_MII;
-
-		ecmd.advertising = ADVERTISED_MII;
-		if (np->advertising & ADVERTISE_10HALF)
-			ecmd.advertising |= ADVERTISED_10baseT_Half;
-		if (np->advertising & ADVERTISE_10FULL)
-			ecmd.advertising |= ADVERTISED_10baseT_Full;
-		if (np->advertising & ADVERTISE_100HALF)
-			ecmd.advertising |= ADVERTISED_100baseT_Half;
-		if (np->advertising & ADVERTISE_100FULL)
-			ecmd.advertising |= ADVERTISED_100baseT_Full;
-		if (np->autoneg) {
-			ecmd.advertising |= ADVERTISED_Autoneg;
-			ecmd.autoneg = AUTONEG_ENABLE;
-		} else
-			ecmd.autoneg = AUTONEG_DISABLE;
-
-		ecmd.port = PORT_MII;
-		ecmd.transceiver = XCVR_INTERNAL;
-		ecmd.phy_address = np->phys[0];
-		ecmd.speed = np->speed100 ? SPEED_100 : SPEED_10;
-		ecmd.duplex = np->full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
-		ecmd.maxtxpkt = TX_RING_SIZE;
-		ecmd.maxrxpkt = np->intr_mitigation; /* not 100% accurate */
-
-
-		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
-			return -EFAULT;
-		return 0;
-
-	case ETHTOOL_SSET: {
-		u16 autoneg, speed100, full_duplex;
-
-		autoneg = (ecmd.autoneg == AUTONEG_ENABLE);
-		speed100 = (ecmd.speed == SPEED_100);
-		full_duplex = (ecmd.duplex == DUPLEX_FULL);
-
-		np->autoneg = autoneg;
-		if (speed100 != np->speed100 ||
-		    full_duplex != np->full_duplex) {
-			np->speed100 = speed100;
-			np->full_duplex = full_duplex;
-			/* change advertising bits */
-			np->advertising &= ~(ADVERTISE_10HALF |
-					     ADVERTISE_10FULL |
-					     ADVERTISE_100HALF |
-					     ADVERTISE_100FULL |
-					     ADVERTISE_100BASE4);
-			if (speed100) {
-				if (full_duplex)
-					np->advertising |= ADVERTISE_100FULL;
-				else
-					np->advertising |= ADVERTISE_100HALF;
-			} else {
-				if (full_duplex)
-					np->advertising |= ADVERTISE_10FULL;
-				else
-					np->advertising |= ADVERTISE_10HALF;
-			}
-		}
-		check_duplex(dev);
-		return 0;
-	}
-
 	case ETHTOOL_GDRVINFO: {
 		struct ethtool_drvinfo info;
 		memset(&info, 0, sizeof(info));
@@ -1799,26 +1920,36 @@
 		return 0;
 	}
 
+	/* get settings */
+	case ETHTOOL_GSET: {
+		struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+		spin_lock_irq(&np->lock);
+		mii_ethtool_gset(&np->mii_if, &ecmd);
+		spin_unlock_irq(&np->lock);
+		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
+			return -EFAULT;
+		return 0;
+	}
+	/* set settings */
+	case ETHTOOL_SSET: {
+		int r;
+		struct ethtool_cmd ecmd;
+		if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
+			return -EFAULT;
+		spin_lock_irq(&np->lock);
+		r = mii_ethtool_sset(&np->mii_if, &ecmd);
+		spin_unlock_irq(&np->lock);
+		check_duplex(dev);
+		return r;
+	}
 	/* restart autonegotiation */
 	case ETHTOOL_NWAY_RST: {
-		int tmp;
-		int r = -EINVAL;
-		/* if autoneg is off, it's an error */
-		tmp = mdio_read(dev, np->phys[0], MII_BMCR);
-		if (tmp & BMCR_ANENABLE) {
-			tmp |= (BMCR_ANRESTART);
-			mdio_write(dev, np->phys[0], MII_BMCR, tmp);
-			r = 0;
-		}
-		return r;
+		return mii_nway_restart(&np->mii_if);
 	}
 	/* get link status */
 	case ETHTOOL_GLINK: {
 		struct ethtool_value edata = {ETHTOOL_GLINK};
-		if (mdio_read(dev, np->phys[0], MII_BMSR) & BMSR_LSTATUS)
-			edata.data = 1;
-		else
-			edata.data = 0;
+		edata.data = mii_link_ok(&np->mii_if);
 		if (copy_to_user(useraddr, &edata, sizeof(edata)))
 			return -EFAULT;
 		return 0;
@@ -1849,50 +1980,25 @@
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	struct netdev_private *np = dev->priv;
-	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data;
+	struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data;
+	int rc;
 
-	switch(cmd) {
-	case SIOCETHTOOL:
-		return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
-
-	/* Legacy mii-diag interface */
-	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
-	case SIOCDEVPRIVATE:		/* for binary compat, remove in 2.5 */
-		data->phy_id = np->phys[0] & 0x1f;
-		/* Fall Through */
-
-	case SIOCGMIIREG:		/* Read MII PHY register. */
-	case SIOCDEVPRIVATE+1:		/* for binary compat, remove in 2.5 */
-		data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f);
-		return 0;
+	if (!netif_running(dev))
+		return -EINVAL;
 
-	case SIOCSMIIREG:		/* Write MII PHY register. */
-	case SIOCDEVPRIVATE+2:		/* for binary compat, remove in 2.5 */
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		if (data->phy_id == np->phys[0]) {
-			u16 value = data->val_in;
-			switch (data->reg_num) {
-			case 0:
-				if (value & (BMCR_RESET | BMCR_ANENABLE))
-					/* Autonegotiation. */
-					np->autoneg = 1;
-				else {
-					np->full_duplex = (value & BMCR_FULLDPLX) ? 1 : 0;
-					np->autoneg = 0;
-				}
-				break;
-			case 4:
-				np->advertising = value;
-				break;
-			}
+	if (cmd == SIOCETHTOOL)
+		rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+
+	else {
+		spin_lock_irq(&np->lock);
+		rc = generic_mii_ioctl(&np->mii_if, data, cmd, NULL);
+		spin_unlock_irq(&np->lock);
+
+		if ((cmd == SIOCSMIIREG) && (data->phy_id == np->phys[0]))
 			check_duplex(dev);
-		}
-		mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
-		return 0;
-	default:
-		return -EOPNOTSUPP;
 	}
+
+	return rc;
 }
 
 static int netdev_close(struct net_device *dev)
@@ -1905,41 +2011,42 @@
 	netif_stop_if(dev);
 
 	if (debug > 1) {
-		printk(KERN_DEBUG "%s: Shutting down ethercard, Intr status %4.4x.\n",
-			   dev->name, (int)readl(ioaddr + IntrStatus));
-		printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d,  Rx %d / %d.\n",
-			   dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx);
+		printk(KERN_DEBUG "%s: Shutting down ethercard, Intr status %#8.8x.\n",
+			   dev->name, (int) readl(ioaddr + IntrStatus));
+		printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n",
+		       dev->name, np->cur_tx, np->dirty_tx,
+		       np->cur_rx, np->dirty_rx);
 	}
 
 	/* Disable interrupts by clearing the interrupt mask. */
 	writel(0, ioaddr + IntrEnable);
 
 	/* Stop the chip's Tx and Rx processes. */
+	writel(0, ioaddr + GenCtrl);
+	readl(ioaddr + GenCtrl);
 
-#ifdef __i386__
-	if (debug > 2) {
-		printk("\n"KERN_DEBUG"  Tx ring at %8.8x:\n",
-			   np->tx_ring_dma);
+	if (debug > 5) {
+		printk(KERN_DEBUG"  Tx ring at %#llx:\n",
+		       (long long) np->tx_ring_dma);
 		for (i = 0; i < 8 /* TX_RING_SIZE is huge! */; i++)
-			printk(KERN_DEBUG " #%d desc. %8.8x %8.8x -> %8.8x.\n",
+			printk(KERN_DEBUG " #%d desc. %#8.8x %#llx -> %#8.8x.\n",
 			       i, le32_to_cpu(np->tx_ring[i].status),
-			       le32_to_cpu(np->tx_ring[i].first_addr),
+			       (long long) dma_to_cpu(np->tx_ring[i].addr),
 			       le32_to_cpu(np->tx_done_q[i].status));
-		printk(KERN_DEBUG "  Rx ring at %8.8x -> %p:\n",
-		       np->rx_ring_dma, np->rx_done_q);
+		printk(KERN_DEBUG "  Rx ring at %#llx -> %p:\n",
+		       (long long) np->rx_ring_dma, np->rx_done_q);
 		if (np->rx_done_q)
 			for (i = 0; i < 8 /* RX_RING_SIZE */; i++) {
-				printk(KERN_DEBUG " #%d desc. %8.8x -> %8.8x\n",
-				       i, le32_to_cpu(np->rx_ring[i].rxaddr), le32_to_cpu(np->rx_done_q[i].status));
+				printk(KERN_DEBUG " #%d desc. %#llx -> %#8.8x\n",
+				       i, (long long) dma_to_cpu(np->rx_ring[i].rxaddr), le32_to_cpu(np->rx_done_q[i].status));
 		}
 	}
-#endif /* __i386__ debugging only */
 
 	free_irq(dev->irq, dev);
 
 	/* Free all the skbuffs in the Rx queue. */
 	for (i = 0; i < RX_RING_SIZE; i++) {
-		np->rx_ring[i].rxaddr = cpu_to_le32(0xBADF00D0); /* An invalid address. */
+		np->rx_ring[i].rxaddr = cpu_to_dma(0xBADF00D0); /* An invalid address. */
 		if (np->rx_info[i].skb != NULL) {
 			pci_unmap_single(np->pci_dev, np->rx_info[i].mapping, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
 			dev_kfree_skb(np->rx_info[i].skb);
@@ -1949,28 +2056,14 @@
 	}
 	for (i = 0; i < TX_RING_SIZE; i++) {
 		struct sk_buff *skb = np->tx_info[i].skb;
-#ifdef ZEROCOPY
-		int j;
-#endif /* ZEROCOPY */
 		if (skb == NULL)
 			continue;
 		pci_unmap_single(np->pci_dev,
-				 np->tx_info[i].first_mapping,
+				 np->tx_info[i].mapping,
 				 skb_first_frag_len(skb), PCI_DMA_TODEVICE);
-		np->tx_info[i].first_mapping = 0;
+		np->tx_info[i].mapping = 0;
 		dev_kfree_skb(skb);
 		np->tx_info[i].skb = NULL;
-#ifdef ZEROCOPY
-		for (j = 0; j < MAX_STARFIRE_FRAGS; j++)
-			if (np->tx_info[i].frag_mapping[j]) {
-				pci_unmap_single(np->pci_dev,
-						 np->tx_info[i].frag_mapping[j],
-						 skb_shinfo(skb)->frags[j].size,
-						 PCI_DMA_TODEVICE);
-				np->tx_info[i].frag_mapping[j] = 0;
-			} else
-				break;
-#endif /* ZEROCOPY */
 	}
 
 	COMPAT_MOD_DEC_USE_COUNT;
@@ -1988,19 +2081,8 @@
 		BUG();
 
 	np = dev->priv;
-	if (np->tx_done_q)
-		pci_free_consistent(pdev, PAGE_SIZE,
-				    np->tx_done_q, np->tx_done_q_dma);
-	if (np->rx_done_q)
-		pci_free_consistent(pdev,
-				    sizeof(struct rx_done_desc) * DONE_Q_SIZE,
-				    np->rx_done_q, np->rx_done_q_dma);
-	if (np->tx_ring)
-		pci_free_consistent(pdev, PAGE_SIZE,
-				    np->tx_ring, np->tx_ring_dma);
-	if (np->rx_ring)
-		pci_free_consistent(pdev, PAGE_SIZE,
-				    np->rx_ring, np->rx_ring_dma);
+	if (np->queue_mem)
+		pci_free_consistent(pdev, np->queue_mem_size, np->queue_mem, np->queue_mem_dma);
 
 	unregister_netdev(dev);
 	iounmap((char *)dev->base_addr);
@@ -2012,10 +2094,10 @@
 
 
 static struct pci_driver starfire_driver = {
-	name:		DRV_NAME,
-	probe:		starfire_init_one,
-	remove:		__devexit_p(starfire_remove_one),
-	id_table:	starfire_pci_tbl,
+	.name		= DRV_NAME,
+	.probe		= starfire_init_one,
+	.remove		= __devexit_p(starfire_remove_one),
+	.id_table	= starfire_pci_tbl,
 };
 
 
@@ -2025,6 +2107,17 @@
 #ifdef MODULE
 	printk(version);
 #endif
+#ifndef ADDR_64BITS
+	/* we can do this test only at run-time... sigh */
+	if (sizeof(dma_addr_t) == sizeof(u64)) {
+		printk("This driver has not been ported to this 64-bit architecture yet\n");
+		return -ENODEV;
+	}
+#endif /* not ADDR_64BITS */
+#ifndef HAS_FIRMWARE
+	/* unconditionally disable hw cksums if firmware is not present */
+	enable_hw_cksum = 0;
+#endif /* not HAS_FIRMWARE */
 	return pci_module_init (&starfire_driver);
 }
 
@@ -2041,8 +2134,6 @@
 
 /*
  * Local variables:
- *  compile-command: "gcc -DMODULE -Wall -Wstrict-prototypes -O2 -c starfire.c"
- *  simple-compile-command: "gcc -DMODULE -O2 -c starfire.c"
  *  c-basic-offset: 8
  *  tab-width: 8
  * End:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sun3_82586.c linux-2.4.21-pre6/drivers/net/sun3_82586.c
--- linux-2.4.20/drivers/net/sun3_82586.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sun3_82586.c	2003-03-26 23:49:09.000000000 +0000
@@ -279,7 +279,7 @@
 
 int __init sun3_82586_probe(struct net_device *dev)
 {
-	unsigned long ioaddr, iopte;
+ 	unsigned long ioaddr;
 	static int found = 0;
 	
 	/* check that this machine has an onboard 82586 */
@@ -296,22 +296,8 @@
 	if(found)
 		return -ENODEV;
 	
-	for(ioaddr = 0xfe00000; ioaddr < (0xfe00000 +
-	    SUN3_PMEG_SIZE); ioaddr += SUN3_PTE_SIZE) {
-
-		iopte = sun3_get_pte(ioaddr);
-		if(!(iopte & SUN3_PAGE_TYPE_IO)) /* this an io page? */
-			continue;
-
-		if(((iopte & SUN3_PAGE_PGNUM_MASK) << PAGE_SHIFT) ==
-		   IE_OBIO) {
-			found = 1;
-			break;
-		}
-	}
-	
-	if(!found)
-		return 0;
+	ioaddr = (unsigned long)ioremap(IE_OBIO, PAGE_SIZE);
+	found = 1;
 	
 	SET_MODULE_OWNER(dev);
 
@@ -1024,8 +1010,13 @@
 	else
 #endif
 	{
+		len = skb->len;
+		if(len < ETH_ZLEN)
+		{
+			memset((char *)p->xmit_cbuffs[p->xmit_count], 0, ETH_ZLEN);
+			len = ETH_ZLEN;
+		}
 		memcpy((char *)p->xmit_cbuffs[p->xmit_count],(char *)(skb->data),skb->len);
-		len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
 
 #if (NUM_XMIT_BUFFS == 1)
 #	ifdef NO_NOPCOMMANDS
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sun3lance.c linux-2.4.21-pre6/drivers/net/sun3lance.c
--- linux-2.4.20/drivers/net/sun3lance.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sun3lance.c	2003-03-26 23:49:25.000000000 +0000
@@ -280,7 +280,7 @@
 
 static int __init lance_probe( struct net_device *dev)
 {	
-	unsigned long ioaddr;
+ 	unsigned long ioaddr;
 	struct lance_private	*lp;
 	int 			i;
 	static int 		did_version;
@@ -288,26 +288,7 @@
 	unsigned short tmp1, tmp2;
 
 #ifdef CONFIG_SUN3
-	unsigned long iopte;
-	int found = 0;
-
-	/* LANCE_OBIO can be found within the IO pmeg with some effort */
-	for(ioaddr = 0xfe00000; ioaddr < (0xfe00000 +
-	    SUN3_PMEG_SIZE); ioaddr += SUN3_PTE_SIZE) {
-
-		iopte = sun3_get_pte(ioaddr);
-		if(!(iopte & SUN3_PAGE_TYPE_IO)) /* this an io page? */
-			continue;
-
-		if(((iopte & SUN3_PAGE_PGNUM_MASK) << PAGE_SHIFT) ==
-		   LANCE_OBIO) {
-			found = 1;
-			break;
-		}
-	}
-	
-	if(!found)
-		return 0;
+ 	ioaddr = (unsigned long)ioremap(LANCE_OBIO, PAGE_SIZE);
 #else
 	ioaddr = SUN3X_LANCE;
 #endif
@@ -616,6 +597,9 @@
 	head->misc = 0;
 
 	memcpy( PKTBUF_ADDR(head), (void *)skb->data, skb->len );
+	if(len != skb->len)
+		memset(PKTBUF_ADDR(head) + skb->len, 0, len-skb->len);
+
 	head->flag = TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP;
 	lp->new_tx = (lp->new_tx + 1) & TX_RING_MOD_MASK;
 	lp->stats.tx_bytes += skb->len;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sunhme.c linux-2.4.21-pre6/drivers/net/sunhme.c
--- linux-2.4.20/drivers/net/sunhme.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sunhme.c	2003-03-26 23:49:25.000000000 +0000
@@ -523,7 +523,7 @@
 	ASD(("happy_meal_tcvr_write: reg=0x%02x value=%04x\n", reg, value));
 
 	/* Welcome to Sun Microsystems, can I take your order please? */
-	if (!hp->happy_flags & HFLAG_FENABLE)
+	if (!(hp->happy_flags & HFLAG_FENABLE))
 		return happy_meal_bb_write(hp, tregs, reg, value);
 
 	/* Would you like fries with that? */
@@ -2701,7 +2701,6 @@
 	}
 
 	hp = dev->priv;
-	memset(hp, 0, sizeof(*hp));
 
 	hp->happy_dev = sdev;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sunlance.c linux-2.4.21-pre6/drivers/net/sunlance.c
--- linux-2.4.20/drivers/net/sunlance.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sunlance.c	2003-03-26 23:49:21.000000000 +0000
@@ -1502,6 +1502,7 @@
 #ifdef CONFIG_SUN4
 
 #include <asm/sun4paddr.h>
+#include <asm/machines.h>
 
 /* Find all the lance cards on the system and initialize them */
 static int __init sparc_lance_probe(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/sunqe.c linux-2.4.21-pre6/drivers/net/sunqe.c
--- linux-2.4.20/drivers/net/sunqe.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/sunqe.c	2003-03-26 23:49:29.000000000 +0000
@@ -929,7 +929,6 @@
 							     sizeof(struct sunqe_buffers),
 							     qe->buffers,
 							     qe->buffers_dvma);
-				kfree(qe_devs[i]->priv);
 			}
 			kfree(qe_devs[i]);
 		}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/tg3.c linux-2.4.21-pre6/drivers/net/tg3.c
--- linux-2.4.20/drivers/net/tg3.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/tg3.c	2003-03-26 23:49:34.000000000 +0000
@@ -1,8 +1,8 @@
-/* $Id: tg3.c,v 1.43.2.80 2002/03/14 00:10:04 davem Exp $
+/*
  * tg3.c: Broadcom Tigon3 ethernet driver.
  *
  * Copyright (C) 2001, 2002 David S. Miller (davem@redhat.com)
- * Copyright (C) 2001, 2002 Jeff Garzik (jgarzik@mandrakesoft.com)
+ * Copyright (C) 2001, 2002 Jeff Garzik (jgarzik@pobox.com)
  */
 
 #include <linux/config.h>
@@ -33,15 +33,6 @@
 #define PCI_DMA_BUS_IS_PHYS 1
 #endif
 
-/* Either I can't figure out how they secretly implemented it (ie. RXD flags
- * for mini ring, where it should go in NIC sram, and how many entries the NIC
- * firmware expects) or it isn't really fully implemented.  Perhaps Broadcom
- * wants people to pay for a "performance enhanced" version of their firmware +
- * binary-only driver that has the mini ring actually implemented.
- * These kids today... -DaveM
- */
-#define TG3_MINI_RING_WORKS 0
-
 #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
 #define TG3_VLAN_TAG_USED 1
 #else
@@ -59,8 +50,8 @@
 
 #define DRV_MODULE_NAME		"tg3"
 #define PFX DRV_MODULE_NAME	": "
-#define DRV_MODULE_VERSION	"1.2"
-#define DRV_MODULE_RELDATE	"Nov 14, 2002"
+#define DRV_MODULE_VERSION	"1.4c"
+#define DRV_MODULE_RELDATE	"Feb 18, 2003"
 
 #define TG3_DEF_MAC_MODE	0
 #define TG3_DEF_RX_MODE		0
@@ -90,10 +81,6 @@
  */
 #define TG3_RX_RING_SIZE		512
 #define TG3_DEF_RX_RING_PENDING		200
-#if TG3_MINI_RING_WORKS
-#define TG3_RX_MINI_RING_SIZE		256 /* ??? */
-#define TG3_DEF_RX_MINI_RING_PENDING	100
-#endif
 #define TG3_RX_JUMBO_RING_SIZE		256
 #define TG3_DEF_RX_JUMBO_RING_PENDING	100
 #define TG3_RX_RCB_RING_SIZE		1024
@@ -102,10 +89,6 @@
 
 #define TG3_RX_RING_BYTES	(sizeof(struct tg3_rx_buffer_desc) * \
 				 TG3_RX_RING_SIZE)
-#if TG3_MINI_RING_WORKS
-#define TG3_RX_MINI_RING_BYTES	(sizeof(struct tg3_rx_buffer_desc) * \
-				 TG3_RX_MINI_RING_SIZE)
-#endif
 #define TG3_RX_JUMBO_RING_BYTES	(sizeof(struct tg3_rx_buffer_desc) * \
 			         TG3_RX_JUMBO_RING_SIZE)
 #define TG3_RX_RCB_RING_BYTES	(sizeof(struct tg3_rx_buffer_desc) * \
@@ -121,9 +104,6 @@
 #define NEXT_TX(N)		(((N) + 1) & (TG3_TX_RING_SIZE - 1))
 
 #define RX_PKT_BUF_SZ		(1536 + tp->rx_offset + 64)
-#if TG3_MINI_RING_WORKS
-#define RX_MINI_PKT_BUF_SZ	(256 + tp->rx_offset + 64)
-#endif
 #define RX_JUMBO_PKT_BUF_SZ	(9046 + tp->rx_offset + 64)
 
 /* minimum number of free TX descriptors required to wake up TX process */
@@ -132,7 +112,7 @@
 static char version[] __devinitdata =
 	DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
 
-MODULE_AUTHOR("David S. Miller (davem@redhat.com) and Jeff Garzik (jgarzik@mandrakesoft.com)");
+MODULE_AUTHOR("David S. Miller (davem@redhat.com) and Jeff Garzik (jgarzik@pobox.com)");
 MODULE_DESCRIPTION("Broadcom Tigon3 ethernet driver");
 MODULE_LICENSE("GPL");
 MODULE_PARM(tg3_debug, "i");
@@ -157,6 +137,12 @@
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5703X,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5704S,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702A3,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5703A3,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 	{ PCI_VENDOR_ID_SYSKONNECT, 0x4400,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 	{ PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000,
@@ -179,6 +165,8 @@
 		spin_unlock_irqrestore(&tp->indirect_lock, flags);
 	} else {
 		writel(val, tp->regs + off);
+		if ((tp->tg3_flags & TG3_FLAG_5701_REG_WRITE_BUG) != 0)
+			readl(tp->regs + off);
 	}
 }
 
@@ -224,33 +212,68 @@
 	tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
 }
 
+static inline void tg3_cond_int(struct tg3 *tp)
+{
+	if (tp->hw_status->status & SD_STATUS_UPDATED)
+		tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | GRC_LCLCTRL_SETINT);
+}
+
 static void tg3_enable_ints(struct tg3 *tp)
 {
 	tw32(TG3PCI_MISC_HOST_CTRL,
 	     (tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT));
 	tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000000);
+	tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
 
-	if (tp->hw_status->status & SD_STATUS_UPDATED) {
-		tw32(GRC_LOCAL_CTRL,
-		     tp->grc_local_ctrl | GRC_LCLCTRL_SETINT);
+	tg3_cond_int(tp);
+}
+
+/* these netif_xxx funcs should be moved into generic net layer */
+static void netif_poll_disable(struct net_device *dev)
+{
+	while (test_and_set_bit(__LINK_STATE_RX_SCHED, &dev->state)) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(1);
 	}
-	tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
 }
 
-static inline void tg3_mask_ints(struct tg3 *tp)
+static inline void netif_poll_enable(struct net_device *dev)
 {
-	tw32(TG3PCI_MISC_HOST_CTRL,
-	     (tp->misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT));
+	clear_bit(__LINK_STATE_RX_SCHED, &dev->state);
 }
 
-static inline void tg3_unmask_ints(struct tg3 *tp)
+/* same as netif_rx_complete, except that local_irq_save(flags)
+ * has already been issued
+ */
+static inline void __netif_rx_complete(struct net_device *dev)
 {
-	tw32(TG3PCI_MISC_HOST_CTRL,
-	     (tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT));
-	if (tp->hw_status->status & SD_STATUS_UPDATED) {
-		tw32(GRC_LOCAL_CTRL,
-		     tp->grc_local_ctrl | GRC_LCLCTRL_SETINT);
-	}
+	if (!test_bit(__LINK_STATE_RX_SCHED, &dev->state)) BUG();
+	list_del(&dev->poll_list);
+	clear_bit(__LINK_STATE_RX_SCHED, &dev->state);
+}
+
+static inline void netif_tx_disable(struct net_device *dev)
+{
+	spin_lock_bh(&dev->xmit_lock);
+	netif_stop_queue(dev);
+	spin_unlock_bh(&dev->xmit_lock);
+}
+
+static inline void tg3_netif_stop(struct tg3 *tp)
+{
+	netif_poll_disable(tp->dev);
+	netif_tx_disable(tp->dev);
+}
+
+static inline void tg3_netif_start(struct tg3 *tp)
+{
+	netif_wake_queue(tp->dev);
+	/* NOTE: unconditional netif_wake_queue is only appropriate
+	 * so long as all callers are assured to have free tx slots
+	 * (such as after tg3_init_hw)
+	 */
+	netif_poll_enable(tp->dev);
+	tg3_cond_int(tp);
 }
 
 static void tg3_switch_clocks(struct tg3 *tp)
@@ -412,7 +435,6 @@
 }
 
 static int tg3_setup_phy(struct tg3 *);
-static int tg3_halt(struct tg3 *);
 
 static int tg3_set_power_state(struct tg3 *tp, int state)
 {
@@ -483,8 +505,6 @@
 		tg3_setup_phy(tp);
 	}
 
-	tg3_halt(tp);
-
 	pci_read_config_word(tp->pdev, pm + PCI_PM_PMC, &power_caps);
 
 	if (tp->tg3_flags & TG3_FLAG_WOL_ENABLE) {
@@ -916,6 +936,20 @@
 
 	tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x02);
 
+	/* Some third-party PHYs need to be reset on link going
+	 * down.
+	 *
+	 * XXX 5705 note: This workaround also applies to 5705_a0
+	 */
+	if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
+	     GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) &&
+	    netif_carrier_ok(tp->dev)) {
+		tg3_readphy(tp, MII_BMSR, &bmsr);
+		tg3_readphy(tp, MII_BMSR, &bmsr);
+		if (!(bmsr & BMSR_LSTATUS))
+			tg3_phy_reset(tp, 1);
+	}
+
 	if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401) {
 		tg3_readphy(tp, MII_BMSR, &bmsr);
 		tg3_readphy(tp, MII_BMSR, &bmsr);
@@ -1784,16 +1818,7 @@
 			src_map = &tp->rx_jumbo_buffers[src_idx];
 		skb_size = RX_JUMBO_PKT_BUF_SZ;
 		break;
-#if TG3_MINI_RING_WORKS
-	case RXD_OPAQUE_RING_MINI:
-		dest_idx = dest_idx_unmasked % TG3_RX_MINI_RING_SIZE;
-		desc = &tp->rx_mini[dest_idx];
-		map = &tp->rx_mini_buffers[dest_idx];
-		if (src_idx >= 0)
-			src_map = &tp->rx_mini_buffers[src_idx];
-		skb_size = RX_MINI_PKT_BUF_SZ;
-		break;
-#endif
+
 	default:
 		return -EINVAL;
 	};
@@ -1854,15 +1879,7 @@
 		src_desc = &tp->rx_jumbo[src_idx];
 		src_map = &tp->rx_jumbo_buffers[src_idx];
 		break;
-#if TG3_MINI_RING_WORKS
-	case RXD_OPAQUE_RING_MINI:
-		dest_idx = dest_idx_unmasked % TG3_RX_MINI_RING_SIZE;
-		dest_desc = &tp->rx_mini[dest_idx];
-		dest_map = &tp->rx_mini_buffers[dest_idx];
-		src_desc = &tp->rx_mini[src_idx];
-		src_map = &tp->rx_mini_buffers[src_idx];
-		break;
-#endif
+
 	default:
 		return;
 	};
@@ -1938,14 +1955,6 @@
 			skb = tp->rx_jumbo_buffers[desc_idx].skb;
 			post_ptr = &tp->rx_jumbo_ptr;
 		}
-#if TG3_MINI_RING_WORKS
-		else if (opaque_key == RXD_OPAQUE_RING_MINI) {
-			dma_addr = pci_unmap_addr(&tp->rx_mini_buffers[desc_idx],
-						  mapping);
-			skb = tp->rx_mini_buffers[desc_idx].skb;
-			post_ptr = &tp->rx_mini_ptr;
-		}
-#endif
 		else {
 			goto next_pkt_nopost;
 		}
@@ -1965,7 +1974,6 @@
 
 		len = ((desc->idx_len & RXD_LEN_MASK) >> RXD_LEN_SHIFT) - 4; /* omit crc */
 
-		/* Kill the copy case if we ever get the mini ring working. */
 		if (len > RX_COPY_THRESHOLD) {
 			int skb_size;
 
@@ -2000,13 +2008,12 @@
 		}
 
 		if ((tp->tg3_flags & TG3_FLAG_RX_CHECKSUMS) &&
-		    (desc->type_flags & RXD_FLAG_TCPUDP_CSUM)) {
-			skb->csum = htons((desc->ip_tcp_csum & RXD_TCPCSUM_MASK)
-					  >> RXD_TCPCSUM_SHIFT);
-			skb->ip_summed = CHECKSUM_HW;
-		} else {
+		    (desc->type_flags & RXD_FLAG_TCPUDP_CSUM) &&
+		    (((desc->ip_tcp_csum & RXD_TCPCSUM_MASK)
+		      >> RXD_TCPCSUM_SHIFT) == 0xffff))
+			skb->ip_summed = CHECKSUM_UNNECESSARY;
+		else
 			skb->ip_summed = CHECKSUM_NONE;
-		}
 
 		skb->protocol = eth_type_trans(skb, tp->dev);
 #if TG3_VLAN_TAG_USED
@@ -2051,15 +2058,6 @@
 		if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
 			tr32(MAILBOX_RCV_JUMBO_PROD_IDX + TG3_64BIT_REG_LOW);
 	}
-#if TG3_MINI_RING_WORKS
-	if (work_mask & RXD_OPAQUE_RING_MINI) {
-		sw_idx = tp->rx_mini_ptr % TG3_RX_MINI_RING_SIZE;
-		tw32_mailbox(MAILBOX_RCV_MINI_PROD_IDX + TG3_64BIT_REG_LOW,
-			     sw_idx);
-		if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
-			tr32(MAILBOX_RCV_MINI_PROD_IDX + TG3_64BIT_REG_LOW);
-	}
-#endif
 
 	return received;
 }
@@ -2068,10 +2066,12 @@
 {
 	struct tg3 *tp = netdev->priv;
 	struct tg3_hw_status *sblk = tp->hw_status;
+	unsigned long flags;
 	int done;
 
-	spin_lock_irq(&tp->lock);
+	spin_lock_irqsave(&tp->lock, flags);
 
+	/* handle link change and other phy events */
 	if (!(tp->tg3_flags &
 	      (TG3_FLAG_USE_LINKCHG_REG |
 	       TG3_FLAG_POLL_SERDES))) {
@@ -2082,12 +2082,19 @@
 		}
 	}
 
+	/* run TX completion thread */
 	if (sblk->idx[0].tx_consumer != tp->tx_cons) {
 		spin_lock(&tp->tx_lock);
 		tg3_tx(tp);
 		spin_unlock(&tp->tx_lock);
 	}
 
+	spin_unlock_irqrestore(&tp->lock, flags);
+
+	/* run RX thread, within the bounds set by NAPI.
+	 * All RX "locking" is done by ensuring outside
+	 * code synchronizes with dev->poll()
+	 */
 	done = 1;
 	if (sblk->idx[0].rx_producer != tp->rx_rcb_ptr) {
 		int orig_budget = *budget;
@@ -2105,44 +2112,35 @@
 			done = 0;
 	}
 
+	/* if no more work, tell net stack and NIC we're done */
 	if (done) {
-		netif_rx_complete(netdev);
-		tg3_unmask_ints(tp);
+		spin_lock_irqsave(&tp->lock, flags);
+		__netif_rx_complete(netdev);
+		tg3_enable_ints(tp);
+		spin_unlock_irqrestore(&tp->lock, flags);
 	}
 
-	spin_unlock_irq(&tp->lock);
-
 	return (done ? 0 : 1);
 }
 
-static __inline__ void tg3_interrupt_main_work(struct net_device *dev, struct tg3 *tp)
+static inline unsigned int tg3_has_work(struct net_device *dev, struct tg3 *tp)
 {
 	struct tg3_hw_status *sblk = tp->hw_status;
-	int work_exists = 0;
+	unsigned int work_exists = 0;
 
+	/* check for phy events */
 	if (!(tp->tg3_flags &
 	      (TG3_FLAG_USE_LINKCHG_REG |
 	       TG3_FLAG_POLL_SERDES))) {
 		if (sblk->status & SD_STATUS_LINK_CHG)
 			work_exists = 1;
 	}
+	/* check for RX/TX work to do */
 	if (sblk->idx[0].tx_consumer != tp->tx_cons ||
 	    sblk->idx[0].rx_producer != tp->rx_rcb_ptr)
 		work_exists = 1;
 
-	if (!work_exists)
-		return;
-
-	if (netif_rx_schedule_prep(dev)) {
-		/* NOTE: These writes are posted by the readback of
-		 *       the mailbox register done by our caller.
-		 */
-		tg3_mask_ints(tp);
-		__netif_rx_schedule(dev);
-	} else {
-		printk(KERN_ERR PFX "%s: Error, poll already scheduled\n",
-		       dev->name);
-	}
+	return work_exists;
 }
 
 static void tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
@@ -2155,15 +2153,32 @@
 	spin_lock_irqsave(&tp->lock, flags);
 
 	if (sblk->status & SD_STATUS_UPDATED) {
+		/*
+		 * writing any value to intr-mbox-0 clears PCI INTA# and
+		 * chip-internal interrupt pending events.
+		 * writing non-zero to intr-mbox-0 additional tells the
+		 * NIC to stop sending us irqs, engaging "in-intr-handler"
+		 * event coalescing.
+		 */
 		tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
 			     0x00000001);
+		/*
+		 * Flush PCI write.  This also guarantees that our
+		 * status block has been flushed to host memory.
+		 */
+		tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
 		sblk->status &= ~SD_STATUS_UPDATED;
 
-		tg3_interrupt_main_work(dev, tp);
-
-		tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
-			     0x00000000);
-		tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
+		if (likely(tg3_has_work(dev, tp)))
+			netif_rx_schedule(dev);		/* schedule NAPI poll */
+		else {
+			/* no work, shared interrupt perhaps?  re-enable
+			 * interrupts, and flush that PCI write
+			 */
+			tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
+			     	0x00000000);
+			tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
+		}
 	}
 
 	spin_unlock_irqrestore(&tp->lock, flags);
@@ -2171,17 +2186,21 @@
 
 static void tg3_init_rings(struct tg3 *);
 static int tg3_init_hw(struct tg3 *);
+static int tg3_halt(struct tg3 *);
 
-static void tg3_tx_timeout(struct net_device *dev)
+static void tg3_reset_task(void *_data)
 {
-	struct tg3 *tp = dev->priv;
+	struct tg3 *tp = _data;
+	unsigned int restart_timer;
 
-	printk(KERN_ERR PFX "%s: transmit timed out, resetting\n",
-	       dev->name);
+	tg3_netif_stop(tp);
 
 	spin_lock_irq(&tp->lock);
 	spin_lock(&tp->tx_lock);
 
+	restart_timer = tp->tg3_flags2 & TG3_FLG2_RESTART_TIMER;
+	tp->tg3_flags2 &= ~TG3_FLG2_RESTART_TIMER;
+
 	tg3_halt(tp);
 	tg3_init_rings(tp);
 	tg3_init_hw(tp);
@@ -2189,7 +2208,20 @@
 	spin_unlock(&tp->tx_lock);
 	spin_unlock_irq(&tp->lock);
 
-	netif_wake_queue(dev);
+	tg3_netif_start(tp);
+
+	if (restart_timer)
+		mod_timer(&tp->timer, jiffies + 1);
+}
+
+static void tg3_tx_timeout(struct net_device *dev)
+{
+	struct tg3 *tp = dev->priv;
+
+	printk(KERN_ERR PFX "%s: transmit timed out, resetting\n",
+	       dev->name);
+
+	schedule_task(&tp->reset_task);
 }
 
 #if !PCI_DMA_BUS_IS_PHYS
@@ -2264,11 +2296,6 @@
 		return -1;
 	}
 
-	/* NOTE: Broadcom's driver botches this case up really bad.
-	 *       This is especially true if any of the frag pages
-	 *       are in highmem.  It will instantly oops in that case.
-	 */
-
 	/* New SKB is guarenteed to be linear. */
 	entry = *start;
 	new_addr = pci_map_single(tp->pdev, new_skb->data, new_skb->len,
@@ -2674,6 +2701,17 @@
 	return 0;
 }
 
+static inline void tg3_set_mtu(struct net_device *dev, struct tg3 *tp,
+			       int new_mtu)
+{
+	dev->mtu = new_mtu;
+
+	if (new_mtu > ETH_DATA_LEN)
+		tp->tg3_flags |= TG3_FLAG_JUMBO_ENABLE;
+	else
+		tp->tg3_flags &= ~TG3_FLAG_JUMBO_ENABLE;
+}
+
 static int tg3_change_mtu(struct net_device *dev, int new_mtu)
 {
 	struct tg3 *tp = dev->priv;
@@ -2685,27 +2723,24 @@
 		/* We'll just catch it later when the
 		 * device is up'd.
 		 */
-		dev->mtu = new_mtu;
+		tg3_set_mtu(dev, tp, new_mtu);
 		return 0;
 	}
 
+	tg3_netif_stop(tp);
 	spin_lock_irq(&tp->lock);
 	spin_lock(&tp->tx_lock);
 
 	tg3_halt(tp);
 
-	dev->mtu = new_mtu;
-
-	if (new_mtu > ETH_DATA_LEN)
-		tp->tg3_flags |= TG3_FLAG_JUMBO_ENABLE;
-	else
-		tp->tg3_flags &= ~TG3_FLAG_JUMBO_ENABLE;
+	tg3_set_mtu(dev, tp, new_mtu);
 
 	tg3_init_rings(tp);
 	tg3_init_hw(tp);
 
 	spin_unlock(&tp->tx_lock);
 	spin_unlock_irq(&tp->lock);
+	tg3_netif_start(tp);
 
 	return 0;
 }
@@ -2734,20 +2769,7 @@
 		dev_kfree_skb_any(rxp->skb);
 		rxp->skb = NULL;
 	}
-#if TG3_MINI_RING_WORKS
-	for (i = 0; i < TG3_RX_MINI_RING_SIZE; i++) {
-		rxp = &tp->rx_mini_buffers[i];
 
-		if (rxp->skb == NULL)
-			continue;
-		pci_unmap_single(tp->pdev,
-				 pci_unmap_addr(rxp, mapping),
-				 RX_MINI_PKT_BUF_SZ - tp->rx_offset,
-				 PCI_DMA_FROMDEVICE);
-		dev_kfree_skb_any(rxp->skb);
-		rxp->skb = NULL;
-	}
-#endif
 	for (i = 0; i < TG3_RX_JUMBO_RING_SIZE; i++) {
 		rxp = &tp->rx_jumbo_buffers[i];
 
@@ -2812,9 +2834,6 @@
 
 	/* Zero out all descriptors. */
 	memset(tp->rx_std, 0, TG3_RX_RING_BYTES);
-#if TG3_MINI_RING_WORKS
-	memset(tp->rx_mini, 0, TG3_RX_MINI_RING_BYTES);
-#endif
 	memset(tp->rx_jumbo, 0, TG3_RX_JUMBO_RING_BYTES);
 	memset(tp->rx_rcb, 0, TG3_RX_RCB_RING_BYTES);
 
@@ -2847,19 +2866,7 @@
 		rxd->opaque = (RXD_OPAQUE_RING_STD |
 			       (i << RXD_OPAQUE_INDEX_SHIFT));
 	}
-#if TG3_MINI_RING_WORKS
-	for (i = 0; i < TG3_RX_MINI_RING_SIZE; i++) {
-		struct tg3_rx_buffer_desc *rxd;
 
-		rxd = &tp->rx_mini[i];
-		rxd->idx_len = (RX_MINI_PKT_BUF_SZ - tp->rx_offset - 64)
-			<< RXD_LEN_SHIFT;
-		rxd->type_flags = (RXD_FLAG_END << RXD_FLAGS_SHIFT) |
-			RXD_FLAG_MINI;
-		rxd->opaque = (RXD_OPAQUE_RING_MINI |
-			       (i << RXD_OPAQUE_INDEX_SHIFT));
-	}
-#endif
 	if (tp->tg3_flags & TG3_FLAG_JUMBO_ENABLE) {
 		for (i = 0; i < TG3_RX_JUMBO_RING_SIZE; i++) {
 			struct tg3_rx_buffer_desc *rxd;
@@ -2881,14 +2888,6 @@
 			break;
 	}
 
-#if TG3_MINI_RING_WORKS
-	for (i = 0; i < tp->rx_mini_pending; i++) {
-		if (tg3_alloc_rx_skb(tp, RXD_OPAQUE_RING_MINI,
-				     -1, i) < 0)
-			break;
-	}
-#endif
-
 	if (tp->tg3_flags & TG3_FLAG_JUMBO_ENABLE) {
 		for (i = 0; i < tp->rx_jumbo_pending; i++) {
 			if (tg3_alloc_rx_skb(tp, RXD_OPAQUE_RING_JUMBO,
@@ -2913,13 +2912,6 @@
 				    tp->rx_std, tp->rx_std_mapping);
 		tp->rx_std = NULL;
 	}
-#if TG3_MINI_RING_WORKS
-	if (tp->rx_mini) {
-		pci_free_consistent(tp->pdev, TG3_RX_MINI_RING_BYTES,
-				    tp->rx_mini, tp->rx_mini_mapping);
-		tp->rx_mini = NULL;
-	}
-#endif
 	if (tp->rx_jumbo) {
 		pci_free_consistent(tp->pdev, TG3_RX_JUMBO_RING_BYTES,
 				    tp->rx_jumbo, tp->rx_jumbo_mapping);
@@ -2955,9 +2947,6 @@
 {
 	tp->rx_std_buffers = kmalloc((sizeof(struct ring_info) *
 				      (TG3_RX_RING_SIZE +
-#if TG3_MINI_RING_WORKS
-				       TG3_RX_MINI_RING_SIZE +
-#endif
 				       TG3_RX_JUMBO_RING_SIZE)) +
 				     (sizeof(struct tx_ring_info) *
 				      TG3_TX_RING_SIZE),
@@ -2965,29 +2954,14 @@
 	if (!tp->rx_std_buffers)
 		return -ENOMEM;
 
-#if TG3_MINI_RING_WORKS
 	memset(tp->rx_std_buffers, 0,
 	       (sizeof(struct ring_info) *
 		(TG3_RX_RING_SIZE +
-		 TG3_RX_MINI_RING_SIZE +
 		 TG3_RX_JUMBO_RING_SIZE)) +
 	       (sizeof(struct tx_ring_info) *
 		TG3_TX_RING_SIZE));
-#else
-	memset(tp->rx_std_buffers, 0,
-	       (sizeof(struct ring_info) *
-		(TG3_RX_RING_SIZE +
-		 TG3_RX_JUMBO_RING_SIZE)) +
-	       (sizeof(struct tx_ring_info) *
-		TG3_TX_RING_SIZE));
-#endif
 
-#if TG3_MINI_RING_WORKS
-	tp->rx_mini_buffers = &tp->rx_std_buffers[TG3_RX_RING_SIZE];
-	tp->rx_jumbo_buffers = &tp->rx_mini_buffers[TG3_RX_MINI_RING_SIZE];
-#else
 	tp->rx_jumbo_buffers = &tp->rx_std_buffers[TG3_RX_RING_SIZE];
-#endif
 	tp->tx_buffers = (struct tx_ring_info *)
 		&tp->rx_jumbo_buffers[TG3_RX_JUMBO_RING_SIZE];
 
@@ -2996,14 +2970,6 @@
 	if (!tp->rx_std)
 		goto err_out;
 
-#if TG3_MINI_RING_WORKS
-	tp->rx_mini = pci_alloc_consistent(tp->pdev, TG3_RX_MINI_RING_BYTES,
-					   &tp->rx_mini_mapping);
-
-	if (!tp->rx_mini)
-		goto err_out;
-#endif
-
 	tp->rx_jumbo = pci_alloc_consistent(tp->pdev, TG3_RX_JUMBO_RING_BYTES,
 					    &tp->rx_jumbo_mapping);
 
@@ -3150,6 +3116,7 @@
 static void tg3_chip_reset(struct tg3 *tp)
 {
 	u32 val;
+	u32 flags_save;
 
 	/* Force NVRAM to settle.
 	 * This deals with a chip bug which can result in EEPROM
@@ -3166,8 +3133,21 @@
 		}
 	}
 
+	/*
+	 * We must avoid the readl() that normally takes place.
+	 * It locks machines, causes machine checks, and other
+	 * fun things.  So, temporarily disable the 5701
+	 * hardware workaround, while we do the reset.
+	 */
+	flags_save = tp->tg3_flags;
+	tp->tg3_flags &= ~TG3_FLAG_5701_REG_WRITE_BUG;
+
+	/* do the reset */
 	tw32(GRC_MISC_CFG, GRC_MISC_CFG_CORECLK_RESET);
 
+	/* restore 5701 hardware bug workaround flag */
+	tp->tg3_flags = flags_save;
+
 	/* Flush PCI posted writes.  The normal MMIO registers
 	 * are inaccessible at this time so this is the only
 	 * way to make this reliably.  I tried to use indirect
@@ -4119,8 +4099,6 @@
 	 * Standard receive ring @ NIC_SRAM_RX_BUFFER_DESC, 512 entries.
 	 * Jumbo receive ring @ NIC_SRAM_RX_JUMBO_BUFFER_DESC, 256 entries.
 	 *
-	 * ??? No space allocated for mini receive ring? :(
-	 *
 	 * The size of each ring is fixed in the firmware, but the location is
 	 * configurable.
 	 */
@@ -4133,19 +4111,8 @@
 	tw32(RCVDBDI_STD_BD + TG3_BDINFO_NIC_ADDR,
 	     NIC_SRAM_RX_BUFFER_DESC);
 
-#if TG3_MINI_RING_WORKS
-	tw32(RCVDBDI_MINI_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_HIGH,
-	     ((u64) tp->rx_mini_mapping >> 32));
-	tw32(RCVDBDI_MINI_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_LOW,
-	     ((u64) tp->rx_mini_mapping & 0xffffffff));
-	tw32(RCVDBDI_MINI_BD + TG3_BDINFO_MAXLEN_FLAGS,
-	     RX_MINI_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT);
-	tw32(RCVDBDI_MINI_BD + TG3_BDINFO_NIC_ADDR,
-	     NIC_SRAM_RX_MINI_BUFFER_DESC);
-#else
 	tw32(RCVDBDI_MINI_BD + TG3_BDINFO_MAXLEN_FLAGS,
 	     BDINFO_FLAGS_DISABLED);
-#endif
 
 	if (tp->tg3_flags & TG3_FLAG_JUMBO_ENABLE) {
 		tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_HIGH,
@@ -4163,9 +4130,6 @@
 
 	/* Setup replenish thresholds. */
 	tw32(RCVBDI_STD_THRESH, tp->rx_pending / 8);
-#if TG3_MINI_RING_WORKS
-	tw32(RCVBDI_MINI_THRESH, tp->rx_mini_pending / 8);
-#endif
 	tw32(RCVBDI_JUMBO_THRESH, tp->rx_jumbo_pending / 8);
 
 	/* Clear out send RCB ring in SRAM. */
@@ -4213,13 +4177,6 @@
 		     tp->rx_std_ptr);
 	if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
 		tr32(MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW);
-#if TG3_MINI_RING_WORKS
-	tp->rx_mini_ptr = tp->rx_mini_pending;
-	tw32_mailbox(MAILBOX_RCV_MINI_PROD_IDX + TG3_64BIT_REG_LOW,
-		     tp->rx_mini_ptr);
-	if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
-		tr32(MAILBOX_RCV_MINI_PROD_IDX + TG3_64BIT_REG_LOW);
-#endif
 
 	if (tp->tg3_flags & TG3_FLAG_JUMBO_ENABLE)
 		tp->rx_jumbo_ptr = tp->rx_jumbo_pending;
@@ -4400,6 +4357,12 @@
 	if (tp->pci_chip_rev_id == CHIPREV_ID_5703_A1)
 		tw32(MAC_SERDES_CFG, 0x616000);
 
+	/* Prevent chip from dropping frames when flow control
+	 * is enabled.
+	 */
+	tw32(MAC_LOW_WMARK_MAX_RX_FRAME, 2);
+	tr32(MAC_LOW_WMARK_MAX_RX_FRAME);
+
 	err = tg3_setup_phy(tp);
 	if (err)
 		return err;
@@ -4468,8 +4431,9 @@
 static void tg3_timer(unsigned long __opaque)
 {
 	struct tg3 *tp = (struct tg3 *) __opaque;
+	unsigned long flags;
 
-	spin_lock_irq(&tp->lock);
+	spin_lock_irqsave(&tp->lock, flags);
 	spin_lock(&tp->tx_lock);
 
 	/* All of this garbage is because when using non-tagged
@@ -4485,9 +4449,11 @@
 	}
 
 	if (!(tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) {
-		tg3_halt(tp);
-		tg3_init_rings(tp);
-		tg3_init_hw(tp);
+		tp->tg3_flags2 |= TG3_FLG2_RESTART_TIMER;
+		spin_unlock(&tp->tx_lock);
+		spin_unlock_irqrestore(&tp->lock, flags);
+		schedule_task(&tp->reset_task);
+		return;
 	}
 
 	/* This part only runs once per second. */
@@ -4551,7 +4517,7 @@
 	}
 
 	spin_unlock(&tp->tx_lock);
-	spin_unlock_irq(&tp->lock);
+	spin_unlock_irqrestore(&tp->lock, flags);
 
 	tp->timer.expires = jiffies + tp->timer_offset;
 	add_timer(&tp->timer);
@@ -4618,8 +4584,6 @@
 		return err;
 	}
 
-	netif_start_queue(dev);
-
 	spin_lock_irq(&tp->lock);
 	spin_lock(&tp->tx_lock);
 
@@ -4628,6 +4592,8 @@
 	spin_unlock(&tp->tx_lock);
 	spin_unlock_irq(&tp->lock);
 
+	netif_start_queue(dev);
+
 	return 0;
 }
 
@@ -4840,23 +4806,6 @@
 		       readl(rxd + 0x0), readl(rxd + 0x4),
 		       readl(rxd + 0x8), readl(rxd + 0xc));
 	}
-#if TG3_MINI_RING_WORKS
-	for (i = 0; i < 6; i++) {
-		unsigned long rxd;
-
-		rxd = tp->regs + NIC_SRAM_WIN_BASE + NIC_SRAM_RX_MINI_BUFFER_DESC
-			+ (i * sizeof(struct tg3_rx_buffer_desc));
-		printk("DEBUG: NIC RXD_MINI(%d)[0][%08x:%08x:%08x:%08x]\n",
-		       i,
-		       readl(rxd + 0x0), readl(rxd + 0x4),
-		       readl(rxd + 0x8), readl(rxd + 0xc));
-		rxd += (4 * sizeof(u32));
-		printk("DEBUG: NIC RXD_MINI(%d)[1][%08x:%08x:%08x:%08x]\n",
-		       i,
-		       readl(rxd + 0x0), readl(rxd + 0x4),
-		       readl(rxd + 0x8), readl(rxd + 0xc));
-	}
-#endif
 
 	for (i = 0; i < 6; i++) {
 		unsigned long rxd;
@@ -5387,19 +5336,11 @@
 		struct ethtool_ringparam ering = { ETHTOOL_GRINGPARAM };
 
 		ering.rx_max_pending = TG3_RX_RING_SIZE - 1;
-#if TG3_MINI_RING_WORKS
-		ering.rx_mini_max_pending = TG3_RX_MINI_RING_SIZE - 1;
-#else
 		ering.rx_mini_max_pending = 0;
-#endif
 		ering.rx_jumbo_max_pending = TG3_RX_JUMBO_RING_SIZE - 1;
 
 		ering.rx_pending = tp->rx_pending;
-#if TG3_MINI_RING_WORKS
-		ering.rx_mini_pending = tp->rx_mini_pending;
-#else
 		ering.rx_mini_pending = 0;
-#endif
 		ering.rx_jumbo_pending = tp->rx_jumbo_pending;
 		ering.tx_pending = tp->tx_pending;
 
@@ -5414,20 +5355,15 @@
 			return -EFAULT;
 
 		if ((ering.rx_pending > TG3_RX_RING_SIZE - 1) ||
-#if TG3_MINI_RING_WORKS
-		    (ering.rx_mini_pending > TG3_RX_MINI_RING_SIZE - 1) ||
-#endif
 		    (ering.rx_jumbo_pending > TG3_RX_JUMBO_RING_SIZE - 1) ||
 		    (ering.tx_pending > TG3_TX_RING_SIZE - 1))
 			return -EINVAL;
 
+		tg3_netif_stop(tp);
 		spin_lock_irq(&tp->lock);
 		spin_lock(&tp->tx_lock);
 
 		tp->rx_pending = ering.rx_pending;
-#if TG3_MINI_RING_WORKS
-		tp->rx_mini_pending = ering.rx_mini_pending;
-#endif
 		tp->rx_jumbo_pending = ering.rx_jumbo_pending;
 		tp->tx_pending = ering.tx_pending;
 
@@ -5437,6 +5373,7 @@
 		netif_wake_queue(tp->dev);
 		spin_unlock(&tp->tx_lock);
 		spin_unlock_irq(&tp->lock);
+		tg3_netif_start(tp);
 
 		return 0;
 	}
@@ -5459,6 +5396,7 @@
 		if (copy_from_user(&epause, useraddr, sizeof(epause)))
 			return -EFAULT;
 
+		tg3_netif_stop(tp);
 		spin_lock_irq(&tp->lock);
 		spin_lock(&tp->tx_lock);
 		if (epause.autoneg)
@@ -5478,6 +5416,7 @@
 		tg3_init_hw(tp);
 		spin_unlock(&tp->tx_lock);
 		spin_unlock_irq(&tp->lock);
+		tg3_netif_start(tp);
 
 		return 0;
 	}
@@ -5939,7 +5878,8 @@
 		tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x2aaa);
 	}
 
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
+	if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) &&
+	    (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0)) {
 		tg3_writephy(tp, 0x1c, 0x8d68);
 		tg3_writephy(tp, 0x1c, 0x8d68);
 	}
@@ -6145,15 +6085,33 @@
 			pci_write_config_word(tp->pdev, PCI_COMMAND, pci_cmd);
 		}
 	}
+
+	/* Back to back register writes can cause problems on this chip,
+	 * the workaround is to read back all reg writes except those to
+	 * mailbox regs.  See tg3_write_indirect_reg32().
+	 */
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)
+		tp->tg3_flags |= TG3_FLAG_5701_REG_WRITE_BUG;
+
 	if ((pci_state_reg & PCISTATE_BUS_SPEED_HIGH) != 0)
 		tp->tg3_flags |= TG3_FLAG_PCI_HIGH_SPEED;
 	if ((pci_state_reg & PCISTATE_BUS_32BIT) != 0)
 		tp->tg3_flags |= TG3_FLAG_PCI_32BIT;
 
+	/* Chip-specific fixup from Broadcom driver */
+	if ((tp->pci_chip_rev_id == CHIPREV_ID_5704_A0) &&
+	    (!(pci_state_reg & PCISTATE_RETRY_SAME_DMA))) {
+		pci_state_reg |= PCISTATE_RETRY_SAME_DMA;
+		pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, pci_state_reg);
+	}
+
 	/* Force the chip into D0. */
 	err = tg3_set_power_state(tp, 0);
-	if (err)
+	if (err) {
+		printk(KERN_ERR PFX "(%s) transition to D0 failed\n",
+		       tp->pdev->slot_name);
 		return err;
+	}
 
 	/* 5700 B0 chips do not support checksumming correctly due
 	 * to hardware bugs.
@@ -6161,18 +6119,14 @@
 	if (tp->pci_chip_rev_id == CHIPREV_ID_5700_B0)
 		tp->tg3_flags |= TG3_FLAG_BROKEN_CHECKSUMS;
 
-	/* Regardless of whether checksums work or not, we configure
-	 * the StrongARM chips to not compute the pseudo header checksums
-	 * in either direction.  Because of the way Linux checksum support
-	 * works we do not need the chips to do this, and taking the load
-	 * off of the TX/RX onboard StrongARM cpus means that they will not be
-	 * the bottleneck.  Whoever wrote Broadcom's driver did not
-	 * understand the situation at all.  He could have bothered
-	 * to read Jes's Acenic driver because the logic (and this part of
-	 * the Tigon2 hardware/firmware) is pretty much identical.
+	/* Pseudo-header checksum is done by hardware logic and not
+	 * the offload processers, so make the chip do the pseudo-
+	 * header checksums on receive.  For transmit it is more
+	 * convenient to do the pseudo-header checksum in software
+	 * as Linux does that on transmit for us in all cases.
 	 */
 	tp->tg3_flags |= TG3_FLAG_NO_TX_PSEUDO_CSUM;
-	tp->tg3_flags |= TG3_FLAG_NO_RX_PSEUDO_CSUM;
+	tp->tg3_flags &= ~TG3_FLAG_NO_RX_PSEUDO_CSUM;
 
 	/* Derive initial jumbo mode from MTU assigned in
 	 * ether_setup() via the alloc_etherdev() call
@@ -6250,19 +6204,8 @@
 	if (tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG)
 		tp->tg3_flags |= TG3_FLAG_HOST_TXDS;
 
-	/* Quick sanity check.  Make sure we see an expected
-	 * value here.
-	 */
 	grc_misc_cfg = tr32(GRC_MISC_CFG);
 	grc_misc_cfg &= GRC_MISC_CFG_BOARD_ID_MASK;
-	if (grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5700 &&
-	    grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5701 &&
-	    grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5702FE &&
-	    grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5703 &&
-	    grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5703S &&
-	    grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5704 &&
-	    grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_AC91002A1)
-		return -ENODEV;
 
 	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 &&
 	    grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5704CIOBE) {
@@ -6270,14 +6213,16 @@
 		tp->split_mode_max_reqs = SPLIT_MODE_5704_MAX_REQ;
 	}
 
-	/* ROFL, you should see Broadcom's driver code implementing
-	 * this, stuff like "if (a || b)" where a and b are always
-	 * mutually exclusive.  DaveM finds like 6 bugs today, hello!
-	 */
+	/* this one is limited to 10/100 only */
 	if (grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5702FE)
 		tp->tg3_flags |= TG3_FLAG_10_100_ONLY;
 
 	err = tg3_phy_probe(tp);
+	if (err) {
+		printk(KERN_ERR PFX "(%s) phy probe failed, err %d\n",
+		       tp->pdev->slot_name, err);
+		/* ... but do not return immediately ... */
+	}
 
 	tg3_read_partno(tp);
 
@@ -6331,17 +6276,10 @@
 	/* 5700 chips can get confused if TX buffers straddle the
 	 * 4GB address boundary in some cases.
 	 */
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) {
-		/* ROFL!  Latest Broadcom driver disables NETIF_F_HIGHDMA
-		 * in this case instead of fixing their workaround code.
-		 *
-		 * Like, hey, there is this skb_copy() thing guys,
-		 * use it.  Oh I can't stop laughing...
-		 */
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700)
 		tp->dev->hard_start_xmit = tg3_start_xmit_4gbug;
-	} else {
+	else
 		tp->dev->hard_start_xmit = tg3_start_xmit;
-	}
 
 	tp->rx_offset = 2;
 	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 &&
@@ -6507,6 +6445,7 @@
 			(0x7 << DMA_RWCTRL_WRITE_WATER_SHIFT) |
 			(0x7 << DMA_RWCTRL_READ_WATER_SHIFT) |
 			(0x0f << DMA_RWCTRL_MIN_DMA_SHIFT);
+		/* XXX 5705 note: set MIN_DMA to zero here */
 	} else {
 		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704)
 			tp->dma_rwctrl =
@@ -6524,13 +6463,20 @@
 				(0x0f << DMA_RWCTRL_MIN_DMA_SHIFT);
 
 		/* Wheee, some more chip bugs... */
-		if (tp->pci_chip_rev_id == CHIPREV_ID_5703_A1 ||
-		    tp->pci_chip_rev_id == CHIPREV_ID_5703_A2 ||
-		    tp->pci_chip_rev_id == CHIPREV_ID_5703_A3 ||
-		    tp->pci_chip_rev_id == CHIPREV_ID_5704_A0)
-			tp->dma_rwctrl |= DMA_RWCTRL_ONE_DMA;
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
+		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
+			u32 ccval = (tr32(TG3PCI_CLOCK_CTRL) & 0x1f);
+
+			if (ccval == 0x6 || ccval == 0x7)
+				tp->dma_rwctrl |= DMA_RWCTRL_ONE_DMA;
+		}
 	}
 
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704)
+		tp->dma_rwctrl &= ~(DMA_RWCTRL_MIN_DMA
+				    << DMA_RWCTRL_MIN_DMA_SHIFT);
+
 	/* We don't do this on x86 because it seems to hurt performace.
 	 * It does help things on other platforms though.
 	 */
@@ -6594,8 +6540,11 @@
 	}
 #endif
 
-	/* Remove this if it causes problems for some boards. */
-	tp->dma_rwctrl |= DMA_RWCTRL_USE_MEM_READ_MULT;
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) {
+		/* Remove this if it causes problems for some boards. */
+		tp->dma_rwctrl |= DMA_RWCTRL_USE_MEM_READ_MULT;
+	}
 
 	tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl);
 
@@ -6825,6 +6774,7 @@
 	spin_lock_init(&tp->lock);
 	spin_lock_init(&tp->tx_lock);
 	spin_lock_init(&tp->indirect_lock);
+	PREPARE_TQUEUE(&tp->reset_task, tg3_reset_task, tp);
 
 	tp->regs = (unsigned long) ioremap(tg3reg_base, tg3reg_len);
 	if (tp->regs == 0UL) {
@@ -6839,9 +6789,6 @@
 	tg3_init_bufmgr_config(tp);
 
 	tp->rx_pending = TG3_DEF_RX_RING_PENDING;
-#if TG3_MINI_RING_WORKS
-	tp->rx_mini_pending = TG3_DEF_RX_MINI_RING_PENDING;
-#endif
 	tp->rx_jumbo_pending = TG3_DEF_RX_JUMBO_RING_PENDING;
 	tp->tx_pending = TG3_DEF_TX_RING_PENDING;
 
@@ -6958,6 +6905,8 @@
 	if (!netif_running(dev))
 		return 0;
 
+	tg3_netif_stop(tp);
+
 	spin_lock_irq(&tp->lock);
 	spin_lock(&tp->tx_lock);
 	tg3_disable_ints(tp);
@@ -6984,6 +6933,7 @@
 		spin_unlock_irq(&tp->lock);
 
 		netif_device_attach(dev);
+		tg3_netif_start(tp);
 	}
 
 	return err;
@@ -7014,6 +6964,8 @@
 	spin_unlock(&tp->tx_lock);
 	spin_unlock_irq(&tp->lock);
 
+	tg3_netif_start(tp);
+
 	return 0;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/tg3.h linux-2.4.21-pre6/drivers/net/tg3.h
--- linux-2.4.20/drivers/net/tg3.h	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/tg3.h	2003-03-26 23:49:40.000000000 +0000
@@ -2,7 +2,7 @@
  * tg3.h: Definitions for Broadcom Tigon3 ethernet driver.
  *
  * Copyright (C) 2001, 2002 David S. Miller (davem@redhat.com)
- * Copyright (C) 2001 Jeff Garzik (jgarzik@mandrakesoft.com)
+ * Copyright (C) 2001 Jeff Garzik (jgarzik@pobox.com)
  */
 
 #ifndef _T3_H
@@ -25,9 +25,6 @@
 
 #define RX_STD_MAX_SIZE			1536
 #define RX_JUMBO_MAX_SIZE		0xdeadbeef /* XXX */
-#if TG3_MINI_RING_WORKS
-#define RX_MINI_MAX_SIZE		256
-#endif
 
 /* First 256 bytes are a mirror of PCI config space. */
 #define TG3PCI_VENDOR			0x00000000
@@ -116,6 +113,8 @@
 #define  CHIPREV_ID_5703_A2		 0x1002
 #define  CHIPREV_ID_5703_A3		 0x1003
 #define  CHIPREV_ID_5704_A0		 0x2000
+#define  CHIPREV_ID_5704_A1		 0x2001
+#define  CHIPREV_ID_5704_A2		 0x2002
 #define  GET_ASIC_REV(CHIP_REV_ID)	((CHIP_REV_ID) >> 12)
 #define   ASIC_REV_5700			 0x07
 #define   ASIC_REV_5701			 0x00
@@ -457,6 +456,7 @@
 #define  RCV_RULE_DISABLE_MASK		 0x7fffffff
 #define MAC_RCV_RULE_CFG		0x00000500
 #define  RCV_RULE_CFG_DEFAULT_CLASS	0x00000008
+#define MAC_LOW_WMARK_MAX_RX_FRAME	0x00000504
 /* 0x504 --> 0x590 unused */
 #define MAC_SERDES_CFG			0x00000590
 #define MAC_SERDES_STAT			0x00000594
@@ -1139,6 +1139,7 @@
 #define  GRC_MISC_CFG_BOARD_ID_5703S	0x00002000
 #define  GRC_MISC_CFG_BOARD_ID_5704	0x00000000
 #define  GRC_MISC_CFG_BOARD_ID_5704CIOBE 0x00004000
+#define  GRC_MISC_CFG_BOARD_ID_5704_A2	0x00008000
 #define  GRC_MISC_CFG_BOARD_ID_AC91002A1 0x00018000
 #define GRC_LOCAL_CTRL			0x00006808
 #define  GRC_LCLCTRL_INT_ACTIVE		0x00000001
@@ -1301,9 +1302,7 @@
 #define NIC_SRAM_MAC_ADDR_HIGH_MBOX	0x00000c14
 #define NIC_SRAM_MAC_ADDR_LOW_MBOX	0x00000c18
 
-#if TG3_MINI_RING_WORKS
 #define NIC_SRAM_RX_MINI_BUFFER_DESC	0x00001000
-#endif
 
 #define NIC_SRAM_DMA_DESC_POOL_BASE	0x00002000
 #define  NIC_SRAM_DMA_DESC_POOL_SIZE	 0x00002000
@@ -1453,9 +1452,7 @@
 #define RXD_FLAGS_SHIFT	0
 
 #define RXD_FLAG_END			0x0004
-#if TG3_MINI_RING_WORKS
 #define RXD_FLAG_MINI			0x0800
-#endif
 #define RXD_FLAG_JUMBO			0x0020
 #define RXD_FLAG_VLAN			0x0040
 #define RXD_FLAG_ERROR			0x0400
@@ -1490,9 +1487,7 @@
 #define RXD_OPAQUE_INDEX_SHIFT		0
 #define RXD_OPAQUE_RING_STD		0x00010000
 #define RXD_OPAQUE_RING_JUMBO		0x00020000
-#if TG3_MINI_RING_WORKS
 #define RXD_OPAQUE_RING_MINI		0x00040000
-#endif
 #define RXD_OPAQUE_RING_MASK		0x00070000
 };
 
@@ -1728,6 +1723,8 @@
 };
 
 struct tg3 {
+	/* begin "general, frequently-used members" cacheline section */
+
 	/* SMP locking strategy:
 	 *
 	 * lock: Held during all operations except TX packet
@@ -1741,18 +1738,51 @@
 	 * necessary for acquisition of 'tx_lock'.
 	 */
 	spinlock_t			lock;
-	spinlock_t			tx_lock;
+	spinlock_t			indirect_lock;
 
+	unsigned long			regs;
+	struct net_device		*dev;
+	struct pci_dev			*pdev;
+
+	struct tg3_hw_status		*hw_status;
+	dma_addr_t			status_mapping;
+
+	u32				msg_enable;
+
+	/* begin "tx thread" cacheline section */
 	u32				tx_prod;
 	u32				tx_cons;
+	u32				tx_pending;
+
+	spinlock_t			tx_lock;
+
+	/* TX descs are only used if TG3_FLAG_HOST_TXDS is set. */
+	struct tg3_tx_buffer_desc	*tx_ring;
+	struct tx_ring_info		*tx_buffers;
+	dma_addr_t			tx_desc_mapping;
+
+	/* begin "rx thread" cacheline section */
 	u32				rx_rcb_ptr;
 	u32				rx_std_ptr;
 	u32				rx_jumbo_ptr;
-#if TG3_MINI_RING_WORKS
-	u32				rx_mini_ptr;
+	u32				rx_pending;
+	u32				rx_jumbo_pending;
+#if TG3_VLAN_TAG_USED
+	struct vlan_group		*vlgrp;
 #endif
-	spinlock_t			indirect_lock;
 
+	struct tg3_rx_buffer_desc	*rx_std;
+	struct ring_info		*rx_std_buffers;
+	dma_addr_t			rx_std_mapping;
+
+	struct tg3_rx_buffer_desc	*rx_jumbo;
+	struct ring_info		*rx_jumbo_buffers;
+	dma_addr_t			rx_jumbo_mapping;
+
+	struct tg3_rx_buffer_desc	*rx_rcb;
+	dma_addr_t			rx_rcb_mapping;
+
+	/* begin "everything else" cacheline(s) section */
 	struct net_device_stats		net_stats;
 	struct net_device_stats		net_stats_prev;
 	unsigned long			phy_crc_errors;
@@ -1765,6 +1795,7 @@
 #define TG3_FLAG_USE_LINKCHG_REG	0x00000008
 #define TG3_FLAG_USE_MI_INTERRUPT	0x00000010
 #define TG3_FLAG_ENABLE_ASF		0x00000020
+#define TG3_FLAG_5701_REG_WRITE_BUG	0x00000040
 #define TG3_FLAG_POLL_SERDES		0x00000080
 #define TG3_FLAG_MBOX_WRITE_REORDER	0x00000100
 #define TG3_FLAG_PCIX_TARGET_HWBUG	0x00000200
@@ -1790,8 +1821,8 @@
 #define TG3_FLAG_GOT_SERDES_FLOWCTL	0x20000000
 #define TG3_FLAG_SPLIT_MODE		0x40000000
 #define TG3_FLAG_INIT_COMPLETE		0x80000000
-
-	u32				msg_enable;
+	u32				tg3_flags2;
+#define TG3_FLG2_RESTART_TIMER		0x00000001
 
 	u32				split_mode_max_reqs;
 #define SPLIT_MODE_5704_MAX_REQ		3
@@ -1806,13 +1837,6 @@
 	struct tg3_link_config		link_config;
 	struct tg3_bufmgr_config	bufmgr_config;
 
-	u32				rx_pending;
-#if TG3_MINI_RING_WORKS
-	u32				rx_mini_pending;
-#endif
-	u32				rx_jumbo_pending;
-	u32				tx_pending;
-
 	/* cache h/w values, often passed straight to h/w */
 	u32				rx_mode;
 	u32				tx_mode;
@@ -1865,38 +1889,9 @@
 	 (X) == PHY_ID_BCM5703 || (X) == PHY_ID_BCM5704 || \
 	 (X) == PHY_ID_BCM8002 || (X) == PHY_ID_SERDES)
 
-	unsigned long			regs;
-	struct pci_dev			*pdev;
-	struct net_device		*dev;
-#if TG3_VLAN_TAG_USED
-	struct vlan_group		*vlgrp;
-#endif
-
-	struct tg3_rx_buffer_desc	*rx_std;
-	struct ring_info		*rx_std_buffers;
-	dma_addr_t			rx_std_mapping;
-#if TG3_MINI_RING_WORKS
-	struct tg3_rx_buffer_desc	*rx_mini;
-	struct ring_info		*rx_mini_buffers;
-	dma_addr_t			rx_mini_mapping;
-#endif
-	struct tg3_rx_buffer_desc	*rx_jumbo;
-	struct ring_info		*rx_jumbo_buffers;
-	dma_addr_t			rx_jumbo_mapping;
-
-	struct tg3_rx_buffer_desc	*rx_rcb;
-	dma_addr_t			rx_rcb_mapping;
-
-	/* TX descs are only used if TG3_FLAG_HOST_TXDS is set. */
-	struct tg3_tx_buffer_desc	*tx_ring;
-	struct tx_ring_info		*tx_buffers;
-	dma_addr_t			tx_desc_mapping;
-
-	struct tg3_hw_status		*hw_status;
-	dma_addr_t			status_mapping;
-
 	struct tg3_hw_stats		*hw_stats;
 	dma_addr_t			stats_mapping;
+	struct tq_struct		reset_task;
 };
 
 #endif /* !(_T3_H) */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/tokenring/3c359.c linux-2.4.21-pre6/drivers/net/tokenring/3c359.c
--- linux-2.4.20/drivers/net/tokenring/3c359.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/tokenring/3c359.c	2003-03-26 23:49:39.000000000 +0000
@@ -1780,7 +1780,7 @@
 
 static void __devexit xl_remove_one (struct pci_dev *pdev)
 {
-	struct net_device *dev = pdev->driver_data;
+	struct net_device *dev = pci_get_drvdata(pdev);
 	struct xl_private *xl_priv=(struct xl_private *)dev->priv;
 	
 	unregister_trdev(dev);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/tokenring/lanstreamer.c linux-2.4.21-pre6/drivers/net/tokenring/lanstreamer.c
--- linux-2.4.20/drivers/net/tokenring/lanstreamer.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/tokenring/lanstreamer.c	2003-03-26 23:49:34.000000000 +0000
@@ -66,6 +66,8 @@
  *             the number of TX descriptors to 1, which together can prevent 
  *             the card from locking up the box - <yoder1@us.ibm.com>
  *  09/27/02 - New PCI interface + bug fix. - <yoder1@us.ibm.com>
+ *  11/13/02 - Removed free_irq calls which could cause a hang, added
+ *	       netif_carrier_{on|off} - <yoder1@us.ibm.com>
  *  
  *  To Do:
  *
@@ -137,7 +139,7 @@
  */
 
 static char version[] = "LanStreamer.c v0.4.0 03/08/01 - Mike Sullivan\n"
-                        "              v0.5.2 09/30/02 - Kent Yoder";
+                        "              v0.5.3 11/13/02 - Kent Yoder";
 
 static struct pci_device_id streamer_pci_tbl[] __initdata = {
 	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR, PCI_ANY_ID, PCI_ANY_ID,},
@@ -879,6 +881,7 @@
 #endif
 
 	netif_start_queue(dev);
+	netif_carrier_on(dev);
 	return 0;
 }
 
@@ -1102,7 +1105,9 @@
 			       ntohs(readw(streamer_mmio + LAPDINC)),
 			       ntohs(readw(streamer_mmio + LAPDINC)),
 			       ntohs(readw(streamer_mmio + LAPDINC)));
-			free_irq(dev->irq, dev);
+			netif_stop_queue(dev);
+			netif_carrier_off(dev);
+			printk(KERN_WARNING "%s: Adapter must be manually reset.\n", dev->name);
 		}
 
 		/* SISR_ADAPTER_CHECK */
@@ -1200,6 +1205,7 @@
 	int i;
 
 	netif_stop_queue(dev);
+	netif_carrier_off(dev);
 	writew(streamer_priv->srb, streamer_mmio + LAPA);
 	writew(htons(SRB_CLOSE_ADAPTER << 8),streamer_mmio+LAPDINC);
 	writew(htons(STREAMER_CLEAR_RET_CODE << 8), streamer_mmio+LAPDINC);
@@ -1670,11 +1676,10 @@
 			/* @TBD. no llc reset on autostreamer writel(readl(streamer_mmio+BCTL)|(3<<13),streamer_mmio+BCTL);
 			   udelay(1);
 			   writel(readl(streamer_mmio+BCTL)&~(3<<13),streamer_mmio+BCTL); */
-			netif_stop_queue(dev);
-			free_irq(dev->irq, dev);
-
-			printk(KERN_WARNING "%s: Adapter has been closed \n", dev->name);
 
+			netif_stop_queue(dev);
+			netif_carrier_off(dev);
+			printk(KERN_WARNING "%s: Adapter must be manually reset.\n", dev->name);
 		}
 		/* If serious error */
 		if (streamer_priv->streamer_message_level) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/tokenring/madgemc.c linux-2.4.21-pre6/drivers/net/tokenring/madgemc.c
--- linux-2.4.20/drivers/net/tokenring/madgemc.c	2001-09-13 23:04:43.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/tokenring/madgemc.c	2003-03-26 23:49:30.000000000 +0000
@@ -164,7 +164,7 @@
 
 	if (!MCA_bus)
 		return -1;	
-       
+ 
 	while (slot != MCA_NOTFOUND) {
 		/*
 		 * Currently we only support the MC16/32 (MCA ID 002d)
@@ -181,8 +181,11 @@
 
 		if ((dev = init_trdev(NULL, 0))==NULL) {
 			printk("madgemc: unable to allocate dev space\n");
+			if (madgemc_card_list)
+				return 0;
 			return -1;
 		}
+		SET_MODULE_OWNER(dev);
 		dev->dma = 0;
 
 		/*
@@ -194,6 +197,9 @@
 		card = kmalloc(sizeof(struct madgemc_card), GFP_KERNEL);
 		if (card==NULL) {
 			printk("madgemc: unable to allocate card struct\n");
+			kfree(dev); /* release_trdev? */
+			if (madgemc_card_list)
+				return 0;
 			return -1;
 		}
 		card->dev = dev;
@@ -224,19 +230,15 @@
 
 		if (dev->irq == 0) {
 			printk("%s: invalid IRQ\n", dev->name);
-			goto getout;
+			goto getout1;
 		}
 
-		request_region(dev->base_addr, MADGEMC_IO_EXTENT, "madgemc");
-#if 0
-		/* why is this not working? */
-		if (request_region(dev->base_addr, MADGEMC_IO_EXTENT, 
+		if (!request_region(dev->base_addr, MADGEMC_IO_EXTENT, 
 				   "madgemc")) {
 			printk(KERN_INFO "madgemc: unable to setup Smart MC in slot %d because of I/O base conflict at 0x%04lx\n", slot, dev->base_addr);
 			dev->base_addr += MADGEMC_SIF_OFFSET;
-			goto getout;
+			goto getout1;
 		}
-#endif
 		dev->base_addr += MADGEMC_SIF_OFFSET;
 		
 		/*
@@ -353,6 +355,14 @@
 		if (tmsdev_init(dev, ISA_MAX_ADDRESS, NULL)) {
 			printk("%s: unable to get memory for dev->priv.\n", 
 			       dev->name);
+			release_region(dev->base_addr-MADGEMC_SIF_OFFSET, 
+			       MADGEMC_IO_EXTENT); 
+			
+			kfree(card);
+			tmsdev_term(dev);
+			kfree(dev);
+			if (madgemc_card_list)
+				return 0;
 			return -1;
 		}
 		tp = (struct net_local *)dev->priv;
@@ -381,10 +391,14 @@
 			madgemc_card_list = card;
 		} else {
 			printk("madgemc: register_trdev() returned non-zero.\n");
+			release_region(dev->base_addr-MADGEMC_SIF_OFFSET, 
+			       MADGEMC_IO_EXTENT); 
 			
 			kfree(card);
 			tmsdev_term(dev);
 			kfree(dev);
+			if (madgemc_card_list)
+				return 0;
 			return -1;
 		}
 
@@ -394,6 +408,7 @@
 	getout:
 		release_region(dev->base_addr-MADGEMC_SIF_OFFSET, 
 			       MADGEMC_IO_EXTENT); 
+	getout1:
 		kfree(card);
 		kfree(dev); /* release_trdev? */
 		slot++;
@@ -519,7 +534,7 @@
  *
  * Register selection is normally done via three contiguous
  * bits.  However, some boards (such as the MC16/32) use only
- * two bits, plus a seperate bit in the glue chip.  This
+ * two bits, plus a separate bit in the glue chip.  This
  * sets the SRSX bit (the top bit).  See page 4-17 in the
  * Yellow Book for which registers are affected.
  *
@@ -634,7 +649,7 @@
 /*
  * Read the card type (MC16 or MC32) from the card.
  *
- * The configuration registers are stored in two seperate
+ * The configuration registers are stored in two separate
  * pages.  Pages are flipped by clearing bit 3 of CONTROL_REG0 (PAGE)
  * for page zero, or setting bit 3 for page one.
  *
@@ -701,7 +716,6 @@
 	 */
 	madgemc_chipset_init(dev);
 	tms380tr_open(dev);
-	MOD_INC_USE_COUNT;
 	return 0;
 }
 
@@ -709,7 +723,6 @@
 {
 	tms380tr_close(dev);
 	madgemc_chipset_close(dev);
-	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/tokenring/smctr.c linux-2.4.21-pre6/drivers/net/tokenring/smctr.c
--- linux-2.4.20/drivers/net/tokenring/smctr.c	2001-09-13 23:04:43.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/tokenring/smctr.c	2003-03-26 23:49:38.000000000 +0000
@@ -3101,28 +3101,12 @@
         unsigned int i;
         __u8 r;
 
-        /* Check if node address has been specified by user. (non-0) */
-        for(i = 0; ((i < 6) && (dev->dev_addr[i] == 0)); i++);
+        for(i = 0; i < 6; i++)
         {
-                if(i != 6)
-                {
-                        for(i = 0; i < 6; i++)
-                        {
-                                r = inb(ioaddr + LAR0 + i);
-                                dev->dev_addr[i] = (char)r;
-                        }
-                        dev->addr_len = 6;
-                }
-                else    /* Node addr. not given by user, read it from board. */
-                {
-                        for(i = 0; i < 6; i++)
-                        {
-                                r = inb(ioaddr + LAR0 + i);
-                                dev->dev_addr[i] = (char)r;
-                        }
-                        dev->addr_len = 6;
-                }
+                r = inb(ioaddr + LAR0 + i);
+                dev->dev_addr[i] = (char)r;
         }
+        dev->addr_len = 6;
 
         return (0);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/tulip/21142.c linux-2.4.21-pre6/drivers/net/tulip/21142.c
--- linux-2.4.20/drivers/net/tulip/21142.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/tulip/21142.c	2003-03-26 23:49:18.000000000 +0000
@@ -1,7 +1,7 @@
 /*
 	drivers/net/tulip/21142.c
 
-	Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
+	Maintained by Jeff Garzik <jgarzik@pobox.com>
 	Copyright 2000,2001  The Linux Kernel Team
 	Written/copyright 1994-2001 by Donald Becker.
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/tulip/ChangeLog linux-2.4.21-pre6/drivers/net/tulip/ChangeLog
--- linux-2.4.20/drivers/net/tulip/ChangeLog	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/tulip/ChangeLog	2003-03-26 23:49:10.000000000 +0000
@@ -14,12 +14,12 @@
 	* 21142.c (t21142_lnk_change): Revert earlier patch
 	to always reset phy; only conditionally do so now.
 
-2002-05-03  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2002-05-03  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core (tulip_pci_tbl): Add new "comet"
 	pci id.  Contributed by Ohta Kyuma.
 
-2002-03-07  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2002-03-07  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core (tulip_mwi_config): Use new PCI API functions
 	for enabling and disabled Memory-Write-Invalidate
@@ -98,30 +98,30 @@
 	Clear status for in-progress Tx's, and count
 	Tx errors for all packets being released.
 
-2001-06-16  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-06-16  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip.h, tulip_core.c:
 	Integrate MMIO support from devel branch, but default
 	it to off for stable kernel and driver series.
 
-2001-06-16  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-06-16  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c (tulip_init_one):
 	Free descriptor rings on error.
 
-2001-06-16  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-06-16  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c (tulip_mwi_config, tulip_init_one):
 	Large update to csr0 bus configuration code.  This is not stable
 	yet, so it is only conditionally enabled, via CONFIG_TULIP_MWI.
 
-2001-06-16  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-06-16  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c:
 	Initialize timer in tulip_init_one and tulip_down,
 	not in tulip_up.
 
-2001-06-14  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-06-14  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c:
 	- Update tulip_suspend, tulip_resume for new PCI PM API.
@@ -138,14 +138,14 @@
 	* tulip_core (set_rx_mode):  Do not use set_bit
 	on an integer variable.  Also fix endianness issue.
 
-2001-06-04  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-06-04  Jeff Garzik  <jgarzik@pobox.com>
 
 	* interrupt.c:
 	Simplify rx processing when CONFIG_NET_HW_FLOWCONTROL is
 	active, and in the process fix a bug where flow control
 	and low load caused rx not to be acknowledged properly.
 
-2001-06-01  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-06-01  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip.h:
 	- Remove tulip_outl_csr helper, redundant.
@@ -165,7 +165,7 @@
 	  convert tabs to spaces.
 	- Move tp->stats.rx_missed_errors update outside the ifdef.
 
-2001-05-18  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-05-18  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c: Added ethtool support.
 	  ETHTOOL_GDRVINFO ioctl only, for now.
@@ -184,22 +184,22 @@
 
 	* tulip_refill_rx prototype added to tulip.h
 
-2001-05-13  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-05-13  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c: Remove HAS_PCI_MWI flag from Comet, untested.
 
-2001-05-12  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-05-12  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c, tulip.h: Remove Conexant PCI id, no chip
 	docs are available to fix problems with support.
 
-2001-05-12  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-05-12  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c (tulip_init_one): Do not call
 	unregister_netdev in error cleanup.  Remnant of old
 	usage of init_etherdev.
 
-2001-05-12  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-05-12  Jeff Garzik  <jgarzik@pobox.com>
 
 	* media.c (tulip_find_mii): Simple write the updated BMCR
 	twice, as it seems the best thing to do for both broken and
@@ -210,36 +210,36 @@
 	Fill in tp->advertising for all cases.
 	Just to be safe, clear all unwanted bits.
 
-2001-05-12  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-05-12  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c (private_ioctl):  Fill in tp->advertising
 	when advertising value is changed by the user.
 
-2001-05-12  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-05-12  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c: Mark Comet chips as needed the updated MWI
 	csr0 configuration.
 
-2001-05-12  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-05-12  Jeff Garzik  <jgarzik@pobox.com>
 
 	* media.c, tulip_core.c:  Move MII scan into
 	from inlined inside tulip_init_one to new function
 	tulip_find_mii in media.c.
 
-2001-05-12  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-05-12  Jeff Garzik  <jgarzik@pobox.com>
 
 	* media.c (tulip_check_duplex):
 	Only restart Rx/Tx engines if they are active
 	(and csr6 changes)
 
-2001-05-12  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-05-12  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c (tulip_mwi_config):
 	Clamp values read from PCI cache line size register to
 	values acceptable to tulip chip.  Done for safety and
 	-almost- certainly unneeded.
 
-2001-05-11  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-05-11  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c (tulip_init_one):
 	Instead of unconditionally enabling autonegotiation, disable
@@ -253,7 +253,7 @@
 	to BMCR twice, to avoid setting unnecessarily changing
 	phy settings.
 
-2001-05-11  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-05-11  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip.h, tulip_core.c:  If HAS_PCI_MWI is set for a
 	given chip, adjust the csr0 values not according to
@@ -264,7 +264,7 @@
 	alignment and system cache size.  Currently MWI bit is set
 	only if the MWI bit is present in the PCI command register.
 
-2001-05-11  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-05-11  Jeff Garzik  <jgarzik@pobox.com>
 
 	* media.c (tulip_select_media):
 	For media types 1 and 3, only use the provided eeprom
@@ -274,7 +274,7 @@
 	ensures that the csr6 value is written if an update
 	is needed.
 
-2001-05-10  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-05-10  Jeff Garzik  <jgarzik@pobox.com>
 
 	Merge PNIC-II-specific stuff from Becker's tulip.c:
 
@@ -284,13 +284,13 @@
 	* tulip_core.c (tulip_tx_timeout): Add specific
 	debugging for PNIC2.
 
-2001-05-10  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-05-10  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c (tulip_init_one): Print out
 	tulip%d instead of PCI device number, for
 	consistency.
 
-2001-05-10  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-05-10  Jeff Garzik  <jgarzik@pobox.com>
 
 	* Merge changes from Becker's tulip.c:
 	Fix bugs in ioctl.
@@ -299,7 +299,7 @@
 	Set CSR14 autonegotiation bit for media types 2 and 4,
 	where the SIA CSR setup values are not provided.
 
-2001-05-10  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-05-10  Jeff Garzik  <jgarzik@pobox.com>
 
 	* media.c (tulip_select_media): Only update MII
 	advertising value if startup arg < 2.
@@ -313,7 +313,7 @@
 	value 2 as 'startup' arg to select_media, to avoid updating
 	MII advertising value.
 
-2001-05-10  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-05-10  Jeff Garzik  <jgarzik@pobox.com>
 
 	* pnic.c (pnic_check_duplex): remove
 	pnic.c (pnic_lnk_change, pnic_timer): use
@@ -326,13 +326,13 @@
 
 	(found by Manfred Spraul)
 
-2001-05-10  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-05-10  Jeff Garzik  <jgarzik@pobox.com>
 
 	* 21142.c, eeprom.c, tulip.h, tulip_core.c:
 	Remove DPRINTK as another, better method of
 	debug message printing is available.
 
-2001-05-09  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-05-09  Jeff Garzik  <jgarzik@pobox.com>
 
 	* 21142.c (t21142_lnk_change): Pass arg startup==1
 	to tulip_select_media, in order to force csr13 to be
@@ -344,32 +344,32 @@
 
 	* interrupt.c: Better PCI bus error reporting.
 
-2001-04-03  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-04-03  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c: Now that dev->name is only available late
 	  in the probe, insert a hack to replace a not-evaluated
 	  "eth%d" string with an evaluated "tulip%d" string.
 	  Also, remove obvious comment and an indentation cleanup.
 
-2001-04-03  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-04-03  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c: If we are a module, always print out the
 	  version string.  If we are built into the kernel, only print
 	  the version string if at least one tulip is detected.
 
-2001-04-03  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-04-03  Jeff Garzik  <jgarzik@pobox.com>
 
 	Merged from Becker's tulip.c 0.92t:
 
 	* tulip_core.c: Add support for Conexant LANfinity.
 
-2001-04-03  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-04-03  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c: Only suspend/resume if the interface
 	  is up and running.  Use alloc_etherdev and pci_request_regions.
 	  Spelling fix.
 
-2001-04-03  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-04-03  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c: Remove code that existed when one or more of
 	  the following defines existed.  These defines were never used
@@ -382,7 +382,7 @@
 	* media.c: Add barrier() to mdio_read/write's PNIC status check
 	  loops.
 
-2001-04-03  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-04-03  Jeff Garzik  <jgarzik@pobox.com>
 
 	Merged from Becker's tulip.c 0.92t:
 
@@ -399,20 +399,20 @@
 	  they are in mdio_read/write now.  Use mask to limit
 	  phy number in tulip_init_one's MII scan.
 
-2001-04-03  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-04-03  Jeff Garzik  <jgarzik@pobox.com>
 
 	Merged from Becker's tulip.c 0.92t:
 
 	* 21142.c, tulip_core.c: PNIC2 MAC address and NWay fixes.
 	* tulip.h: Add FullDuplex constant, used in above change.
 
-2001-04-03  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-04-03  Jeff Garzik  <jgarzik@pobox.com>
 
 	* timer.c: Do not call netif_carrier_{on,off}, it is not used in
 	  the main tree.  Leave code in, disabled, as markers for future
 	  carrier notification.
 
-2001-04-03  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-04-03  Jeff Garzik  <jgarzik@pobox.com>
 
 	Merged from Becker's tulip.c 0.92t, except for the tulip.h
 	whitespace cleanup:
@@ -431,14 +431,14 @@
 	  Prefer COMET_MAC_ADDR flag test to chip_id test in set_rx_mode.
 	  Store built mc_filter for later use in intr handler by Comets.
 
-2001-04-03  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-04-03  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c: Use tp->cur_tx when building the
 	  setup frame, instead of assuming that the setup
 	  frame is always built in slot zero.  This case is
 	  hit during PM resume.
 
-2001-04-03  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-04-03  Jeff Garzik  <jgarzik@pobox.com>
 
 	* *.c: Update file headers (copyright, urls, etc.)
 	* Makefile: re-order to that chip-specific modules on own line
@@ -446,7 +446,7 @@
 	* tulip_core.c: merge medianame[] update from tulip.c.
 	  Additional arch-specific rx_copybreak, csr0 values. (various)
 
-2001-02-20  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-02-20  Jeff Garzik  <jgarzik@pobox.com>
 
 	* media.c (tulip_select_media): No need to initialize
 	new_csr6, all cases initialize it properly.
@@ -465,7 +465,7 @@
 	interrupt handler, as PNIC doesn't support a h/w timer.
 	* tulip_core.c (tulip_tbl[]): Modify default csr6
 
-2001-02-11  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-02-11  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c (tulip_init_one): Call pci_enable_device
 	to ensure wakeup/resource assignment before checking those
@@ -474,30 +474,30 @@
 	(tulip_suspend, tulip_resume, tulip_remove_one): Call
 	pci_power_on/off (commented out for now).
 
-2001-02-10  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-02-10  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip.h: Add CFDD_xxx bits for Tulip power management
 	* tulip_core.c (tulip_set_power_state): New function,
 	manipulating Tulip chip power state where supported.
 	(tulip_up, tulip_down, tulip_init_one): Use it.
 
-2001-02-10  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-02-10  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c (tulip_tx_timeout): Call netif_wake_queue
 	to ensure the next Tx is always sent to us.
 
-2001-01-27  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-01-27  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c (tulip_remove_one): Fix mem leak by freeing
 	tp->media_tbl.  Add check for !dev, reformat code appropriately.
 
-2001-01-27  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-01-27  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_tbl[]: Comment all entries to make order and chip_id
 	relationship more clear.
 	* tulip_pci_tbl[]: Add new Accton PCI id (COMET chipset).
 
-2001-01-16  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-01-16  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c: static vars no longer explicitly
 	initialized to zero.
@@ -532,7 +532,7 @@
 	medianame[] and block_name[] arrays to avoid oops due
 	to bad values returned from hardware.
 
-2000-11-02  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2000-11-02  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c (set_rx_mode): This is synchronized via
 	dev->xmit_lock, so only the queueing of the setup frame needs to
@@ -547,13 +547,13 @@
 	* tulip_core.c (tulip_init_ring, tulip_start_xmit, set_rx_mode):
 	Likewise.
 
-2000-10-18  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2000-10-18  Jeff Garzik  <jgarzik@pobox.com>
 
 	* tulip_core.c: (tulip_init_one) Print out ethernet interface
 	on error.  Print out a message when pci_enable_device fails.
 	Handle DMA alloc failure.
 
-2000-10-18  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2000-10-18  Jeff Garzik  <jgarzik@pobox.com>
 
 	* Makefile: New file.
 	* tulip_core.c (tulip_init_one): Correct error messages
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/tulip/eeprom.c linux-2.4.21-pre6/drivers/net/tulip/eeprom.c
--- linux-2.4.20/drivers/net/tulip/eeprom.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/tulip/eeprom.c	2003-03-26 23:49:30.000000000 +0000
@@ -1,7 +1,7 @@
 /*
 	drivers/net/tulip/eeprom.c
 
-	Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
+	Maintained by Jeff Garzik <jgarzik@pobox.com>
 	Copyright 2000,2001  The Linux Kernel Team
 	Written/copyright 1994-2001 by Donald Becker.
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/tulip/interrupt.c linux-2.4.21-pre6/drivers/net/tulip/interrupt.c
--- linux-2.4.20/drivers/net/tulip/interrupt.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/tulip/interrupt.c	2003-03-26 23:49:19.000000000 +0000
@@ -1,7 +1,7 @@
 /*
 	drivers/net/tulip/interrupt.c
 
-	Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
+	Maintained by Jeff Garzik <jgarzik@pobox.com>
 	Copyright 2000,2001  The Linux Kernel Team
 	Written/copyright 1994-2001 by Donald Becker.
 
@@ -263,7 +263,7 @@
            This would turn on IM for devices that is not contributing
            to backlog congestion with unnecessary latency.
 
-           We monitor the the device RX-ring and have:
+           We monitor the device RX-ring and have:
 
            HW Interrupt Mitigation either ON or OFF.
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/tulip/media.c linux-2.4.21-pre6/drivers/net/tulip/media.c
--- linux-2.4.20/drivers/net/tulip/media.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/tulip/media.c	2003-03-26 23:49:19.000000000 +0000
@@ -1,7 +1,7 @@
 /*
 	drivers/net/tulip/media.c
 
-	Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
+	Maintained by Jeff Garzik <jgarzik@pobox.com>
 	Copyright 2000,2001  The Linux Kernel Team
 	Written/copyright 1994-2001 by Donald Becker.
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/tulip/pnic.c linux-2.4.21-pre6/drivers/net/tulip/pnic.c
--- linux-2.4.20/drivers/net/tulip/pnic.c	2001-11-09 21:45:35.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/tulip/pnic.c	2003-03-26 23:49:50.000000000 +0000
@@ -1,7 +1,7 @@
 /*
 	drivers/net/tulip/pnic.c
 
-	Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
+	Maintained by Jeff Garzik <jgarzik@pobox.com>
 	Copyright 2000,2001  The Linux Kernel Team
 	Written/copyright 1994-2001 by Donald Becker.
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/tulip/pnic2.c linux-2.4.21-pre6/drivers/net/tulip/pnic2.c
--- linux-2.4.20/drivers/net/tulip/pnic2.c	2001-11-09 21:45:35.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/tulip/pnic2.c	2003-03-26 23:49:06.000000000 +0000
@@ -1,7 +1,7 @@
 /*
 	drivers/net/tulip/pnic2.c
 
-	Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
+	Maintained by Jeff Garzik <jgarzik@pobox.com>
 	Copyright 2000,2001  The Linux Kernel Team
 	Written/copyright 1994-2001 by Donald Becker.
         Modified to hep support PNIC_II by Kevin B. Hendricks
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/tulip/timer.c linux-2.4.21-pre6/drivers/net/tulip/timer.c
--- linux-2.4.20/drivers/net/tulip/timer.c	2001-06-20 18:15:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/tulip/timer.c	2003-03-26 23:48:57.000000000 +0000
@@ -1,7 +1,7 @@
 /*
 	drivers/net/tulip/timer.c
 
-	Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
+	Maintained by Jeff Garzik <jgarzik@pobox.com>
 	Copyright 2000,2001  The Linux Kernel Team
 	Written/copyright 1994-2001 by Donald Becker.
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/tulip/tulip_core.c linux-2.4.21-pre6/drivers/net/tulip/tulip_core.c
--- linux-2.4.20/drivers/net/tulip/tulip_core.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/tulip/tulip_core.c	2003-03-26 23:49:40.000000000 +0000
@@ -1,7 +1,7 @@
 /* tulip_core.c: A DEC 21x4x-family ethernet driver for Linux. */
 
 /*
-	Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
+	Maintained by Jeff Garzik <jgarzik@pobox.com>
 	Copyright 2000-2002  The Linux Kernel Team
 	Written/copyright 1994-2001 by Donald Becker.
 
@@ -229,6 +229,7 @@
 	{ 0x1186, 0x1561, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
 	{ 0x1626, 0x8410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
 	{ 0x1737, 0xAB09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
+	{ 0x17B3, 0xAB08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
 	{ 0x14f1, 0x1803, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CONEXANT },
 	{ } /* terminate list */
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/typhoon-firmware.h linux-2.4.21-pre6/drivers/net/typhoon-firmware.h
--- linux-2.4.20/drivers/net/typhoon-firmware.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/typhoon-firmware.h	2003-03-26 23:49:19.000000000 +0000
@@ -0,0 +1,4108 @@
+/*
+ * Copyright 1999-2002 3Com Corporation.  All Rights Reserved.    
+ *
+ * Redistribution and use in source and binary forms of the 3CR990img.h
+ * microcode software are permitted provided that the following conditions
+ * are met:
+ * 1. Redistribution of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistribution 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 3Com may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY 3COM ``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.
+ *
+ * USER ACKNOWLEDGES AND AGREES THAT PURCHASE OR USE OF THE 3CR990img.h
+ * MICROCODE SOFTWARE WILL NOT CREATE OR GIVE GROUNDS FOR A LICENSE BY
+ * IMPLICATION, ESTOPPEL, OR OTHERWISE IN ANY INTELLECTUAL PROPERTY RIGHTS
+ * (PATENT, COPYRIGHT, TRADE SECRET, MASK WORK, OR OTHER PROPRIETARY RIGHT)
+ * EMBODIED IN ANY OTHER 3COM HARDWARE OR SOFTWARE EITHER SOLELY OR IN
+ * COMBINATION WITH THE 3CR990img.h microcode SOFTWARE
+ */ 
+const u8 typhoon_firmware_image[] = {
+0x54, 0x59, 0x50, 0x48, 0x4f, 0x4f, 0x4e, 0x00, 0x02, 0x00, 0x00, 0x00, 
+0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x40, 0x01, 0x00, 0x00, 
+0x6c, 0xef, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x39, 0x00, 0x00, 0xea, 
+0x05, 0x00, 0x00, 0xea, 0x04, 0x00, 0x00, 0xea, 0x03, 0x00, 0x00, 0xea, 
+0x02, 0x00, 0x00, 0xea, 0x01, 0x00, 0x00, 0xea, 0x32, 0x02, 0x00, 0xea, 
+0xa5, 0x14, 0x00, 0xea, 0x07, 0x00, 0x2d, 0xe9, 0x0e, 0x00, 0xa0, 0xe1, 
+0x00, 0x10, 0x0f, 0xe1, 0xd0, 0x20, 0x9f, 0xe5, 0x12, 0xff, 0x2f, 0xe1, 
+0xfe, 0xff, 0xff, 0xea, 0x01, 0x00, 0x80, 0xe0, 0x04, 0x20, 0x81, 0xe4, 
+0x01, 0x00, 0x50, 0xe1, 0xfc, 0xff, 0xff, 0x1a, 0x0e, 0xf0, 0xa0, 0xe1, 
+0x00, 0xa0, 0xa0, 0xe1, 0x0e, 0xb0, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe3, 
+0xa8, 0x10, 0x9f, 0xe5, 0x00, 0x00, 0x81, 0xe5, 0xa4, 0x10, 0x9f, 0xe5, 
+0x00, 0x00, 0x81, 0xe5, 0x01, 0x16, 0xa0, 0xe3, 0x00, 0x00, 0x91, 0xe5, 
+0x01, 0x00, 0x80, 0xe3, 0x00, 0x00, 0x81, 0xe5, 0xd7, 0x00, 0xa0, 0xe3, 
+0x00, 0xf0, 0x21, 0xe1, 0x88, 0xd0, 0x9f, 0xe5, 0xdb, 0x00, 0xa0, 0xe3, 
+0x00, 0xf0, 0x21, 0xe1, 0x7c, 0xd0, 0x9f, 0xe5, 0xd2, 0x00, 0xa0, 0xe3, 
+0x00, 0xf0, 0x21, 0xe1, 0x74, 0xd0, 0x9f, 0xe5, 0xd1, 0x00, 0xa0, 0xe3, 
+0x00, 0xf0, 0x21, 0xe1, 0x6c, 0xd0, 0x9f, 0xe5, 0x7b, 0x14, 0x00, 0xeb, 
+0xd3, 0x00, 0xa0, 0xe3, 0x00, 0xf0, 0x21, 0xe1, 0x60, 0xd0, 0x9f, 0xe5, 
+0x60, 0x00, 0x9f, 0xe5, 0x60, 0x10, 0x9f, 0xe5, 0x60, 0x20, 0x9f, 0xe5, 
+0xdb, 0xff, 0xff, 0xeb, 0x5c, 0x00, 0x9f, 0xe5, 0x5c, 0x10, 0x9f, 0xe5, 
+0x00, 0x20, 0xa0, 0xe3, 0xd7, 0xff, 0xff, 0xeb, 0x54, 0x00, 0x9f, 0xe5, 
+0x54, 0x10, 0x9f, 0xe5, 0xd4, 0xff, 0xff, 0xeb, 0x0a, 0x00, 0xa0, 0xe1, 
+0x0b, 0xf0, 0xa0, 0xe1, 0xd3, 0x10, 0xa0, 0xe3, 0x01, 0xf0, 0x21, 0xe1, 
+0xd4, 0xff, 0xff, 0xeb, 0x3c, 0xa0, 0x9f, 0xe5, 0x1a, 0xff, 0x2f, 0xe1, 
+0xc6, 0xff, 0xff, 0xea, 0xbd, 0x20, 0xff, 0xff, 0x0c, 0x00, 0x10, 0x00, 
+0x1c, 0x00, 0x10, 0x00, 0x3c, 0x38, 0x00, 0x80, 0xfc, 0x37, 0x00, 0x80, 
+0xfc, 0x3f, 0x00, 0x80, 0x7c, 0x34, 0x00, 0x80, 0x80, 0x0f, 0x00, 0x00, 
+0x80, 0x30, 0x00, 0x80, 0xad, 0xde, 0xad, 0xde, 0xa8, 0xbc, 0x00, 0x00, 
+0x24, 0xab, 0x20, 0x40, 0x34, 0x29, 0x00, 0x00, 0xa8, 0x04, 0x00, 0x80, 
+0x6d, 0xc8, 0x21, 0x40, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0xd8, 0x56, 0x00, 0x00, 0x06, 0x24, 0x00, 0x00, 
+0x60, 0x01, 0xff, 0xff, 0xb0, 0xb5, 0x07, 0x1c, 0x12, 0x4c, 0x00, 0x25, 
+0xe0, 0x6b, 0x00, 0x28, 0x1d, 0xd0, 0x38, 0x1c, 0x10, 0x49, 0x04, 0xf0, 
+0x37, 0xfd, 0xe1, 0x6b, 0xc0, 0x46, 0x08, 0x60, 0x00, 0x28, 0x14, 0xd0, 
+0x38, 0x01, 0x0d, 0x49, 0x40, 0x18, 0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18, 
+0x41, 0x6b, 0x80, 0x29, 0x0b, 0xd2, 0x01, 0x31, 0x41, 0x63, 0xe0, 0x6b, 
+0xc1, 0x69, 0xc0, 0x46, 0xe1, 0x63, 0x39, 0x07, 0x41, 0x60, 0xc7, 0x62, 
+0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x28, 0x1c, 0xfa, 0xe7, 0x00, 0x00, 
+0x28, 0x17, 0x00, 0x80, 0xee, 0x05, 0x00, 0x00, 0x1c, 0x1c, 0x00, 0x80, 
+0x02, 0x49, 0xca, 0x6b, 0xc0, 0x46, 0xc2, 0x61, 0xc8, 0x63, 0x70, 0x47, 
+0x28, 0x17, 0x00, 0x80, 0x70, 0x47, 0x00, 0x00, 0x70, 0x47, 0x00, 0x00, 
+0x70, 0x47, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe1, 
+0x00, 0x10, 0xa0, 0xe1, 0xc0, 0x10, 0x81, 0xe3, 0x01, 0xf0, 0x21, 0xe1, 
+0x1e, 0xff, 0x2f, 0xe1, 0x00, 0xf0, 0x21, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 
+0x00, 0x00, 0x0f, 0xe1, 0xc0, 0x00, 0x80, 0xe3, 0x00, 0xf0, 0x21, 0xe1, 
+0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x0f, 0xe1, 0xc0, 0x00, 0xc0, 0xe3, 
+0x00, 0xf0, 0x21, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x0f, 0xe1, 
+0x40, 0x00, 0x80, 0xe3, 0x00, 0xf0, 0x21, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 
+0x00, 0x00, 0x0f, 0xe1, 0x80, 0x00, 0x10, 0xe3, 0x80, 0x00, 0x80, 0xe3, 
+0x00, 0xf0, 0x21, 0xe1, 0x00, 0x00, 0x00, 0x12, 0x1e, 0xff, 0x2f, 0xe1, 
+0x00, 0x00, 0x50, 0xe3, 0x00, 0x00, 0x0f, 0xe1, 0x80, 0x00, 0xc0, 0x13, 
+0x00, 0xf0, 0x21, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x0f, 0xe1, 
+0x80, 0x00, 0xc0, 0xe3, 0x00, 0xf0, 0x21, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 
+0x91, 0x00, 0x00, 0xe0, 0x1e, 0xff, 0x2f, 0xe1, 0x01, 0x20, 0x80, 0xe0, 
+0x01, 0x00, 0x80, 0xe0, 0x1e, 0xff, 0x2f, 0xe1, 0x80, 0xb5, 0x08, 0x4f, 
+0x64, 0x28, 0x04, 0xd3, 0x64, 0x20, 0x38, 0x63, 0x00, 0x20, 0xc0, 0x43, 
+0x03, 0xe0, 0x38, 0x63, 0x04, 0x49, 0x05, 0xf0, 0xc1, 0xfa, 0x78, 0x63, 
+0xb8, 0x63, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xe8, 0x0d, 0x00, 0x80, 
+0x88, 0x13, 0x00, 0x00, 0x80, 0xb4, 0x10, 0x4b, 0x00, 0x22, 0x1f, 0x6b, 
+0x64, 0x2f, 0x03, 0xd2, 0x09, 0x68, 0x09, 0x68, 0x49, 0x08, 0x02, 0xd2, 
+0x10, 0x1c, 0x80, 0xbc, 0x70, 0x47, 0x19, 0x1c, 0xdb, 0x6b, 0x4f, 0x6b, 
+0xbb, 0x42, 0x05, 0xd2, 0x40, 0x68, 0x00, 0x04, 0x00, 0x0c, 0x18, 0x18, 
+0xc8, 0x63, 0xf1, 0xe7, 0x41, 0x68, 0x05, 0x4b, 0x19, 0x43, 0x41, 0x60, 
+0x04, 0x48, 0xc1, 0x6b, 0x01, 0x31, 0xc1, 0x63, 0x02, 0x20, 0xe8, 0xe7, 
+0xe8, 0x0d, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x78, 0x2a, 0x00, 0x80, 
+0x90, 0xb5, 0x07, 0x1c, 0x15, 0x4c, 0x00, 0x20, 0x21, 0x6b, 0x64, 0x29, 
+0x0b, 0xd2, 0xb9, 0x6e, 0x49, 0x08, 0x08, 0xd3, 0x21, 0x6c, 0xa2, 0x6b, 
+0x91, 0x42, 0x07, 0xd2, 0xfa, 0x1d, 0x39, 0x32, 0x52, 0x8b, 0x89, 0x18, 
+0x21, 0x64, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x78, 0x6a, 0x39, 0x6b, 
+0xc0, 0x46, 0x48, 0x62, 0x38, 0x6b, 0x02, 0xf0, 0xe7, 0xfd, 0x38, 0x1c, 
+0x02, 0xf0, 0xa4, 0xfa, 0x01, 0x20, 0xbb, 0x23, 0x1b, 0x01, 0xe1, 0x18, 
+0xc8, 0x72, 0x05, 0x49, 0x0a, 0x6c, 0x12, 0x18, 0x0a, 0x64, 0x04, 0x49, 
+0x8a, 0x6d, 0x12, 0x18, 0x8a, 0x65, 0xe4, 0xe7, 0xe8, 0x0d, 0x00, 0x80, 
+0x78, 0x2a, 0x00, 0x80, 0x10, 0x2a, 0x00, 0x80, 0x80, 0xb4, 0x0a, 0x48, 
+0xc0, 0x6d, 0x02, 0x23, 0x18, 0x40, 0x09, 0x4a, 0x00, 0x21, 0x00, 0x28, 
+0x03, 0xd0, 0xd1, 0x63, 0x11, 0x64, 0x80, 0xbc, 0x70, 0x47, 0x06, 0x48, 
+0x07, 0x68, 0x7b, 0x1c, 0x03, 0x60, 0x0a, 0x2f, 0xf7, 0xd3, 0x01, 0x60, 
+0xf3, 0xe7, 0x00, 0x00, 0x10, 0x2a, 0x00, 0x80, 0xe8, 0x0d, 0x00, 0x80, 
+0x60, 0x01, 0x00, 0x80, 0x70, 0x47, 0x02, 0x04, 0x12, 0x0c, 0x00, 0x0c, 
+0x10, 0x18, 0x0a, 0x04, 0x12, 0x0c, 0x09, 0x0c, 0x51, 0x18, 0x08, 0x18, 
+0x01, 0x0c, 0x05, 0xd0, 0x01, 0x04, 0x09, 0x0c, 0x00, 0x0c, 0x08, 0x18, 
+0x01, 0x0c, 0xf9, 0xd1, 0x00, 0x04, 0x00, 0x0c, 0x70, 0x47, 0x80, 0xb4, 
+0x00, 0x22, 0x00, 0x29, 0x18, 0xd0, 0x4f, 0x08, 0x7b, 0x1e, 0x00, 0x2f, 
+0x06, 0xd0, 0x07, 0x88, 0xba, 0x18, 0x02, 0x30, 0x1f, 0x1c, 0x01, 0x3b, 
+0x00, 0x2f, 0xf8, 0xd1, 0x49, 0x08, 0x03, 0xd3, 
+0x00, 0x88, 0x00, 0x06, 0x00, 0x0e, 0x82, 0x18, 0x10, 0x0c, 0x05, 0xd0, 
+0x10, 0x04, 0x00, 0x0c, 0x11, 0x0c, 0x42, 0x18, 0x10, 0x0c, 0xf9, 0xd1, 
+0x10, 0x04, 0x00, 0x0c, 0x80, 0xbc, 0x70, 0x47, 0x80, 0xb5, 0x83, 0x89, 
+0xc7, 0x89, 0xfb, 0x18, 0x07, 0x8a, 0xfb, 0x18, 0x47, 0x8a, 0xfb, 0x18, 
+0x40, 0x7a, 0x00, 0x02, 0xc7, 0x18, 0x38, 0x0c, 0x05, 0xd0, 0x38, 0x04, 
+0x00, 0x0c, 0x3b, 0x0c, 0xc7, 0x18, 0x38, 0x0c, 0xf9, 0xd1, 0x08, 0x1c, 
+0x11, 0x1c, 0xff, 0xf7, 0xc8, 0xff, 0x01, 0x1c, 0x38, 0x1c, 0xff, 0xf7, 
+0xb0, 0xff, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x90, 0xb5, 0x02, 0x23, 
+0x82, 0x68, 0x1a, 0x40, 0x00, 0x27, 0x00, 0x2a, 0x0f, 0xd0, 0x0a, 0x4a, 
+0x93, 0x69, 0x01, 0x33, 0x93, 0x61, 0x0a, 0x68, 0x8b, 0x68, 0x9a, 0x18, 
+0x00, 0x68, 0x1c, 0x18, 0x57, 0x81, 0x09, 0x69, 0x10, 0x1c, 0xff, 0xf7, 
+0xac, 0xff, 0xc0, 0x43, 0x60, 0x81, 0x38, 0x1c, 0x90, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x00, 0x78, 0x2a, 0x00, 0x80, 0x90, 0xb5, 0x04, 0x23, 
+0x82, 0x68, 0x1a, 0x40, 0x00, 0x27, 0x00, 0x2a, 0x11, 0xd0, 0x4a, 0x68, 
+0x52, 0x09, 0x0e, 0xd3, 0x09, 0x4a, 0x13, 0x6a, 0x01, 0x33, 0x13, 0x62, 
+0xcb, 0x68, 0x02, 0x68, 0x9c, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x3a, 
+0x1a, 0x43, 0x12, 0x68, 0x00, 0xf0, 0x2e, 0xf8, 0x20, 0x82, 0x38, 0x1c, 
+0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x78, 0x2a, 0x00, 0x80, 
+0x90, 0xb5, 0x80, 0x23, 0x82, 0x68, 0x1a, 0x40, 0x00, 0x24, 0x00, 0x2a, 
+0x15, 0xd0, 0x4a, 0x68, 0x92, 0x09, 0x12, 0xd3, 0x0b, 0x4a, 0xd3, 0x69, 
+0x01, 0x33, 0xd3, 0x61, 0xcb, 0x68, 0x02, 0x68, 0x9f, 0x18, 0x01, 0x23, 
+0x9b, 0x07, 0x08, 0x3a, 0x1a, 0x43, 0x12, 0x68, 0x00, 0xf0, 0x0e, 0xf8, 
+0x00, 0x28, 0x00, 0xd1, 0x04, 0x48, 0xc0, 0x46, 0xf8, 0x80, 0x20, 0x1c, 
+0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x78, 0x2a, 0x00, 0x80, 
+0xff, 0xff, 0x00, 0x00, 0xb0, 0xb5, 0x14, 0x1c, 0x05, 0x1c, 0x0f, 0x1c, 
+0x38, 0x69, 0xb9, 0x68, 0x41, 0x18, 0x38, 0x68, 0xff, 0xf7, 0x53, 0xff, 
+0xc0, 0x43, 0x01, 0x04, 0x09, 0x0c, 0x20, 0x1c, 0xff, 0xf7, 0x39, 0xff, 
+0x04, 0x1c, 0xb8, 0x68, 0x79, 0x69, 0x40, 0x18, 0x69, 0x68, 0x88, 0x42, 
+0x0c, 0xd2, 0x2a, 0x68, 0x12, 0x18, 0x09, 0x1a, 0x10, 0x1c, 0x00, 0xf0, 
+0x05, 0xf9, 0xc0, 0x43, 0x01, 0x04, 0x09, 0x0c, 0x20, 0x1c, 0xff, 0xf7, 
+0x26, 0xff, 0x04, 0x1c, 0xe0, 0x43, 0x00, 0x04, 0x00, 0x0c, 0xb0, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 0x07, 0x1c, 0xb8, 0x6b, 0xc0, 0x08, 
+0x1a, 0xd3, 0xb8, 0x6a, 0xf9, 0x6b, 0x40, 0x18, 0x79, 0x6c, 0x00, 0xf0, 
+0xed, 0xf8, 0xc0, 0x43, 0x01, 0x04, 0x09, 0x0c, 0x0a, 0x48, 0x07, 0xd0, 
+0x20, 0x23, 0xb9, 0x69, 0x19, 0x43, 0xb9, 0x61, 0x01, 0x6b, 0x01, 0x31, 
+0x01, 0x63, 0x07, 0xe0, 0xff, 0x23, 0x01, 0x33, 0xb9, 0x69, 0x19, 0x43, 
+0xb9, 0x61, 0x41, 0x6a, 0x01, 0x31, 0x41, 0x62, 0x00, 0x20, 0x80, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0x78, 0x2a, 0x00, 0x80, 0x80, 0xb5, 0x07, 0x1c, 
+0xb8, 0x6b, 0x41, 0x09, 0x1c, 0xd3, 0xc0, 0x08, 0x1a, 0xd3, 0xf8, 0x1d, 
+0x39, 0x30, 0x00, 0x7b, 0x06, 0x28, 0x15, 0xd1, 0x38, 0x1c, 0x00, 0xf0, 
+0x53, 0xf8, 0x01, 0x1c, 0x0a, 0x48, 0x07, 0xd0, 0x40, 0x23, 0xb9, 0x69, 
+0x19, 0x43, 0xb9, 0x61, 0x81, 0x6b, 0x01, 0x31, 0x81, 0x63, 0x07, 0xe0, 
+0x01, 0x23, 0x9b, 0x02, 0xb9, 0x69, 0x19, 0x43, 
+0xb9, 0x61, 0xc1, 0x6a, 0x01, 0x31, 0xc1, 0x62, 0x00, 0x20, 0x80, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0x78, 0x2a, 0x00, 0x80, 0xb0, 0xb5, 0x07, 0x1c, 
+0xb8, 0x6b, 0x81, 0x09, 0x2c, 0xd3, 0xc0, 0x08, 0x2a, 0xd3, 0xf8, 0x1d, 
+0x39, 0x30, 0x00, 0x7b, 0x11, 0x28, 0x25, 0xd1, 0xb8, 0x6a, 0x39, 0x6c, 
+0x40, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x06, 0x30, 0x18, 0x43, 0x00, 0x68, 
+0x05, 0x04, 0x2d, 0x0c, 0x0f, 0x4c, 0x11, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 
+0x1f, 0xf8, 0x00, 0x28, 0x0c, 0xd0, 0xa8, 0x42, 0x02, 0xd1, 0x0c, 0x4b, 
+0x98, 0x42, 0x07, 0xd0, 0x80, 0x23, 0xb8, 0x69, 0x18, 0x43, 0xb8, 0x61, 
+0x60, 0x6b, 0x01, 0x30, 0x60, 0x63, 0x07, 0xe0, 0x01, 0x23, 0x5b, 0x02, 
+0xb8, 0x69, 0x18, 0x43, 0xb8, 0x61, 0xa0, 0x6a, 0x01, 0x30, 0xa0, 0x62, 
+0x00, 0x20, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x78, 0x2a, 0x00, 0x80, 
+0xff, 0xff, 0x00, 0x00, 0xf0, 0xb5, 0xff, 0xb0, 0x99, 0xb0, 0x04, 0x1c, 
+0xe0, 0x6b, 0x61, 0x6c, 0x09, 0x18, 0x03, 0xaa, 0x85, 0x18, 0xa3, 0x6a, 
+0x00, 0x20, 0x8a, 0x08, 0x01, 0x32, 0x97, 0x92, 0x07, 0xd0, 0x82, 0x00, 
+0x9f, 0x58, 0x03, 0xae, 0xb7, 0x50, 0x97, 0x9a, 0x01, 0x30, 0x82, 0x42, 
+0xf7, 0xd8, 0x60, 0x6a, 0x01, 0x23, 0x9b, 0x07, 0x04, 0x30, 0x18, 0x43, 
+0x00, 0x68, 0xc0, 0x46, 0x02, 0x90, 0x02, 0xaf, 0x3f, 0x88, 0x03, 0xa8, 
+0xff, 0xf7, 0x87, 0xfe, 0xc0, 0x43, 0x01, 0x04, 0x09, 0x0c, 0x38, 0x1c, 
+0xff, 0xf7, 0x6d, 0xfe, 0x07, 0x1c, 0xe0, 0x6b, 0xa1, 0x6c, 0x40, 0x18, 
+0x61, 0x6a, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x31, 0x19, 0x43, 0x09, 0x68, 
+0xc0, 0x46, 0x01, 0x91, 0x01, 0xa9, 0x09, 0x88, 0x01, 0x31, 0x88, 0x42, 
+0x0c, 0xd2, 0xa2, 0x6a, 0x12, 0x18, 0x09, 0x1a, 0x10, 0x1c, 0x00, 0xf0, 
+0x2f, 0xf8, 0xc0, 0x43, 0x01, 0x04, 0x09, 0x0c, 0x38, 0x1c, 0xff, 0xf7, 
+0x50, 0xfe, 0x07, 0x1c, 0xa8, 0x89, 0xe9, 0x89, 0x08, 0x18, 0x29, 0x8a, 
+0x08, 0x18, 0x69, 0x8a, 0x08, 0x18, 0x69, 0x7a, 0x09, 0x02, 0x08, 0x18, 
+0xa1, 0x6c, 0x62, 0x6c, 0x89, 0x1a, 0x0a, 0x04, 0x12, 0x0c, 0x11, 0x02, 
+0x12, 0x0a, 0x11, 0x43, 0x09, 0x04, 0x09, 0x0c, 0x09, 0x18, 0x08, 0x0c, 
+0x05, 0xd0, 0x08, 0x04, 0x00, 0x0c, 0x09, 0x0c, 0x41, 0x18, 0x08, 0x0c, 
+0xf9, 0xd1, 0x38, 0x1c, 0xff, 0xf7, 0x2f, 0xfe, 0xc0, 0x43, 0x00, 0x04, 
+0x00, 0x0c, 0x7f, 0xb0, 0x19, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0xb0, 0xb4, 0x00, 0x22, 0x00, 0x29, 0x2e, 0xd0, 0x83, 0x07, 0x9b, 0x0f, 
+0xdc, 0x00, 0x47, 0x18, 0x04, 0x25, 0xef, 0x1b, 0xbf, 0x07, 0xbf, 0x0f, 
+0xff, 0x00, 0x80, 0x08, 0x80, 0x00, 0x59, 0x18, 0x03, 0x31, 0x89, 0x08, 
+0x4d, 0x1e, 0x02, 0xc8, 0xe1, 0x40, 0xa1, 0x40, 0x6b, 0x1e, 0x00, 0x2d, 
+0x09, 0xd0, 0x0c, 0x04, 0x24, 0x0c, 0xa2, 0x18, 0x09, 0x0c, 0x8a, 0x18, 
+0x02, 0xc8, 0x1c, 0x1c, 0x01, 0x3b, 0x00, 0x2c, 0xf5, 0xd1, 0xb9, 0x40, 
+0x08, 0x1c, 0xf8, 0x40, 0x01, 0x04, 0x09, 0x0c, 0x89, 0x18, 0x00, 0x0c, 
+0x42, 0x18, 0x10, 0x0c, 0x05, 0xd0, 0x10, 0x04, 0x00, 0x0c, 0x11, 0x0c, 
+0x42, 0x18, 0x10, 0x0c, 0xf9, 0xd1, 0x10, 0x04, 0x00, 0x0c, 0xb0, 0xbc, 
+0x70, 0x47, 0x00, 0x00, 0x90, 0xb4, 0x00, 0x20, 0x01, 0x27, 0x11, 0x49, 
+0x42, 0x00, 0x12, 0x18, 0xd2, 0x00, 0x53, 0x18, 0x9c, 0x68, 0x01, 0x23, 
+0x9b, 0x07, 0x23, 0x43, 0x1b, 0x68, 0x1b, 0x03, 0x1b, 0x0b, 0x8a, 0x58, 
+0x12, 0x03, 0x12, 0x0b, 0x93, 0x42, 0x0c, 0xd1, 
+0x01, 0x30, 0x04, 0x28, 0xec, 0xd3, 0x08, 0x48, 0xc0, 0x6a, 0x01, 0x03, 
+0x09, 0x0b, 0x07, 0x48, 0x00, 0x6f, 0x00, 0x03, 0x00, 0x0b, 0x81, 0x42, 
+0x02, 0xd0, 0x38, 0x1c, 0x90, 0xbc, 0x70, 0x47, 0x00, 0x20, 0xfb, 0xe7, 
+0x28, 0x03, 0x00, 0x80, 0x00, 0x40, 0x14, 0x40, 0xe8, 0x0d, 0x00, 0x80, 
+0x98, 0xb4, 0x14, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x83, 0x00, 0x13, 0x48, 
+0xc0, 0x58, 0x07, 0x03, 0x3f, 0x0b, 0x12, 0x48, 0xc0, 0x58, 0x02, 0x03, 
+0x12, 0x0b, 0x11, 0x48, 0xc0, 0x58, 0x00, 0x03, 0x00, 0x0b, 0x10, 0x4c, 
+0xe4, 0x58, 0x01, 0x23, 0x9b, 0x07, 0x23, 0x43, 0x1b, 0x68, 0x9b, 0x00, 
+0xcc, 0x00, 0x01, 0x21, 0x98, 0x42, 0x01, 0xd1, 0x08, 0x1c, 0x09, 0xe0, 
+0x98, 0x42, 0x03, 0xd9, 0x10, 0x1a, 0xda, 0x1b, 0x80, 0x18, 0x00, 0xe0, 
+0x18, 0x1a, 0x84, 0x42, 0xf4, 0xd3, 0x00, 0x20, 0x98, 0xbc, 0x70, 0x47, 
+0x55, 0x55, 0x55, 0x55, 0xa0, 0x03, 0x00, 0x80, 0xa8, 0x03, 0x00, 0x80, 
+0x88, 0x03, 0x00, 0x80, 0x98, 0x03, 0x00, 0x80, 0x80, 0xb4, 0x13, 0x04, 
+0x00, 0xd0, 0x01, 0x3a, 0x80, 0x00, 0x0b, 0x1c, 0x13, 0x49, 0x0f, 0x58, 
+0xc0, 0x46, 0x3b, 0x60, 0x0b, 0x58, 0xc0, 0x46, 0x5a, 0x60, 0x0a, 0x58, 
+0x08, 0x32, 0x10, 0x4b, 0x1b, 0x58, 0x9a, 0x42, 0x01, 0xd3, 0x0f, 0x4a, 
+0x12, 0x58, 0x0f, 0x4b, 0x1f, 0x58, 0x01, 0x23, 0x9b, 0x07, 0x3b, 0x43, 
+0x1b, 0x68, 0x9b, 0x00, 0x17, 0x03, 0x3f, 0x0b, 0x9f, 0x42, 0x06, 0xd1, 
+0x0a, 0x48, 0xc1, 0x68, 0x01, 0x31, 0xc1, 0x60, 0x01, 0x20, 0x80, 0xbc, 
+0x70, 0x47, 0x08, 0x4b, 0x1b, 0x58, 0xc0, 0x46, 0x1a, 0x60, 0x0a, 0x50, 
+0x00, 0x20, 0xf6, 0xe7, 0x88, 0x03, 0x00, 0x80, 0xa8, 0x03, 0x00, 0x80, 
+0xa0, 0x03, 0x00, 0x80, 0x98, 0x03, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, 
+0x90, 0x03, 0x00, 0x80, 0xff, 0x5f, 0x2d, 0xe9, 0x48, 0xfe, 0xff, 0xeb, 
+0x01, 0xb6, 0xa0, 0xe3, 0x01, 0xb1, 0x8b, 0xe2, 0x02, 0x8a, 0xa0, 0xe3, 
+0x01, 0x7a, 0xa0, 0xe3, 0x01, 0xa9, 0xa0, 0xe3, 0x01, 0x56, 0xa0, 0xe3, 
+0xc8, 0x60, 0x9f, 0xe5, 0xc8, 0x90, 0x9f, 0xe5, 0x14, 0x40, 0x9b, 0xe5, 
+0x00, 0x00, 0x54, 0xe3, 0x2c, 0x00, 0x00, 0x0a, 0x03, 0x0a, 0x14, 0xe3, 
+0x11, 0x00, 0x00, 0x0a, 0x0c, 0x00, 0x96, 0xe5, 0x00, 0x00, 0x50, 0xe3, 
+0x21, 0x00, 0x00, 0x0a, 0x01, 0x0a, 0x14, 0xe3, 0x05, 0x00, 0x00, 0x0a, 
+0x1c, 0x00, 0x96, 0xe5, 0x01, 0x0a, 0xc0, 0xe3, 0x1c, 0x00, 0x86, 0xe5, 
+0x1c, 0x00, 0x85, 0xe5, 0x14, 0x70, 0x85, 0xe5, 0x06, 0x00, 0x00, 0xea, 
+0x02, 0x0a, 0x14, 0xe3, 0x04, 0x00, 0x00, 0x0a, 0x1c, 0x00, 0x96, 0xe5, 
+0x02, 0x0a, 0xc0, 0xe3, 0x1c, 0x00, 0x86, 0xe5, 0x1c, 0x00, 0x85, 0xe5, 
+0x14, 0x80, 0x85, 0xe5, 0x01, 0x09, 0x14, 0xe3, 0x04, 0x00, 0x00, 0x0a, 
+0x1c, 0x00, 0x96, 0xe5, 0x01, 0x09, 0xc0, 0xe3, 0x1c, 0x00, 0x86, 0xe5, 
+0x1c, 0x00, 0x85, 0xe5, 0x14, 0xa0, 0x85, 0xe5, 0x02, 0x00, 0x14, 0xe3, 
+0x40, 0x00, 0x00, 0x1b, 0x01, 0x00, 0x14, 0xe3, 0x54, 0x00, 0x00, 0x1b, 
+0x02, 0x0b, 0x14, 0xe3, 0x67, 0x00, 0x00, 0x1b, 0x01, 0x0b, 0x14, 0xe3, 
+0x20, 0x00, 0x00, 0x1b, 0x18, 0x00, 0x99, 0xe5, 0x01, 0x00, 0x80, 0xe2, 
+0x18, 0x00, 0x89, 0xe5, 0xd5, 0xff, 0xff, 0xea, 0x1c, 0x00, 0x96, 0xe5, 
+0x01, 0x0a, 0xc0, 0xe3, 0x1c, 0x00, 0x86, 0xe5, 0x1c, 0x00, 0x85, 0xe5, 
+0x14, 0x70, 0x85, 0xe5, 0xe1, 0xff, 0xff, 0xea, 0xff, 0x5f, 0xbd, 0xe8, 
+0x04, 0xf0, 0x5e, 0xe2, 0xe8, 0x0d, 0x00, 0x80, 
+0x08, 0x83, 0x20, 0x40, 0x10, 0x10, 0x1f, 0xe5, 0x14, 0x30, 0x91, 0xe5, 
+0x00, 0x20, 0xc3, 0xe1, 0x14, 0x20, 0x81, 0xe5, 0x01, 0x16, 0xa0, 0xe3, 
+0x0c, 0x20, 0x81, 0xe5, 0x0b, 0x12, 0xa0, 0xe3, 0x00, 0x00, 0x81, 0xe5, 
+0x18, 0x10, 0x9f, 0xe5, 0xb0, 0x24, 0xd1, 0xe1, 0x01, 0x20, 0x82, 0xe2, 
+0xb0, 0x24, 0xc1, 0xe1, 0x3c, 0x20, 0x91, 0xe5, 0x00, 0x00, 0x82, 0xe1, 
+0x3c, 0x00, 0x81, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0xa0, 0x82, 0x20, 0x40, 
+0xff, 0xff, 0xff, 0xea, 0xfe, 0xff, 0xff, 0xea, 0x01, 0x0b, 0xa0, 0xe3, 
+0x01, 0x16, 0xa0, 0xe3, 0x14, 0x00, 0x81, 0xe5, 0x00, 0x1a, 0x81, 0xe1, 
+0x24, 0x20, 0x91, 0xe5, 0x70, 0x00, 0x1f, 0xe5, 0x00, 0x00, 0x00, 0x00, 
+0x24, 0x20, 0x80, 0xe5, 0x28, 0x10, 0x91, 0xe5, 0x00, 0x00, 0x00, 0x00, 
+0x28, 0x10, 0x80, 0xe5, 0x2c, 0x20, 0x90, 0xe5, 0x01, 0x20, 0x82, 0xe2, 
+0x2c, 0x20, 0x80, 0xe5, 0x3f, 0x00, 0x01, 0xe2, 0x3f, 0x00, 0x50, 0xe3, 
+0x1e, 0xff, 0x2f, 0x11, 0x18, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0x90, 0xe5, 
+0x01, 0x10, 0x81, 0xe2, 0x00, 0x10, 0x80, 0xe5, 0x02, 0x18, 0xa0, 0xe3, 
+0x0b, 0x02, 0xa0, 0xe3, 0x00, 0x10, 0x80, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 
+0xb0, 0x03, 0x00, 0x80, 0x01, 0x06, 0xa0, 0xe3, 0x01, 0x01, 0x80, 0xe2, 
+0x00, 0x10, 0x90, 0xe5, 0x01, 0x08, 0x11, 0xe3, 0x0b, 0x10, 0xa0, 0xe3, 
+0x02, 0x19, 0x81, 0xe2, 0x05, 0x00, 0x00, 0x1a, 0x00, 0x20, 0x90, 0xe5, 
+0x42, 0x28, 0xb0, 0xe1, 0x05, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x90, 0xe5, 
+0x02, 0x0c, 0x10, 0xe3, 0x02, 0x00, 0x00, 0x0a, 0x06, 0x07, 0xa0, 0xe3, 
+0x4c, 0x11, 0x80, 0xe5, 0x03, 0x00, 0x00, 0xea, 0x0c, 0x00, 0x9f, 0xe5, 
+0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x80, 0xe5, 0xff, 0xff, 0xff, 0xea, 
+0xfe, 0xff, 0xff, 0xea, 0x00, 0x00, 0x00, 0x80, 0x01, 0x06, 0xa0, 0xe3, 
+0x01, 0x01, 0x80, 0xe2, 0x00, 0x10, 0x90, 0xe5, 0x01, 0x08, 0x11, 0xe3, 
+0x0c, 0x10, 0xa0, 0xe3, 0x02, 0x19, 0x81, 0xe2, 0x05, 0x00, 0x00, 0x1a, 
+0x00, 0x20, 0x90, 0xe5, 0x42, 0x28, 0xb0, 0xe1, 0x05, 0x00, 0x00, 0x1a, 
+0x00, 0x00, 0x90, 0xe5, 0x02, 0x0c, 0x10, 0xe3, 0x02, 0x00, 0x00, 0x0a, 
+0x06, 0x07, 0xa0, 0xe3, 0x4c, 0x11, 0x80, 0xe5, 0x03, 0x00, 0x00, 0xea, 
+0x4c, 0x00, 0x1f, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x80, 0xe5, 
+0xff, 0xff, 0xff, 0xea, 0xfe, 0xff, 0xff, 0xea, 0x02, 0x1b, 0xa0, 0xe3, 
+0x01, 0x06, 0xa0, 0xe3, 0x14, 0x10, 0x80, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 
+0x80, 0x21, 0x1f, 0xe5, 0x14, 0x30, 0x92, 0xe5, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x30, 0x80, 0xe5, 0x1c, 0x00, 0x92, 0xe5, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x81, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x14, 0x10, 0x82, 0xe5, 
+0x01, 0x06, 0xa0, 0xe3, 0x1c, 0x10, 0x82, 0xe5, 0x0c, 0x10, 0x80, 0xe5, 
+0x1c, 0x10, 0x92, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x10, 0x80, 0xe5, 
+0x1e, 0xff, 0x2f, 0xe1, 0xc0, 0x21, 0x1f, 0xe5, 0x00, 0x00, 0x00, 0x00, 
+0x1c, 0x10, 0x82, 0xe5, 0x01, 0x16, 0xa0, 0xe3, 0x14, 0x00, 0x82, 0xe5, 
+0x0c, 0x00, 0x81, 0xe5, 0x1c, 0x00, 0x92, 0xe5, 0x00, 0x00, 0x00, 0x00, 
+0x1c, 0x00, 0x81, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0x80, 0xb5, 0x0f, 0x1c, 
+0x38, 0x1c, 0x00, 0xf0, 0x17, 0xf8, 0x00, 0x28, 0x02, 0xd0, 0x38, 0x1c, 
+0x00, 0xf0, 0x76, 0xf8, 0x00, 0x20, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x80, 0xb5, 0x0f, 0x1c, 0x38, 0x1c, 0x00, 0xf0, 
+0x09, 0xf8, 0x00, 0x28, 0x02, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 0x68, 0xf8, 
+0x00, 0x20, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb4, 0x07, 0x68, 
+0x3a, 0x78, 0xd2, 0x07, 0xd2, 0x0f, 0x00, 0x24, 0x00, 0x2a, 0x03, 0xd0, 
+0xff, 0x22, 0x01, 0x32, 0x42, 0x60, 0x00, 0xe0, 0x44, 0x60, 0x3a, 0x7b, 
+0x7b, 0x7b, 0x1b, 0x02, 0x1a, 0x43, 0x81, 0x2a, 0x08, 0xd1, 0x01, 0x23, 
+0x5b, 0x02, 0x42, 0x68, 0x1a, 0x43, 0x42, 0x60, 0x04, 0x22, 0xbf, 0x18, 
+0x82, 0x60, 0x00, 0xe0, 0x84, 0x60, 0x3a, 0x7b, 0x7b, 0x7b, 0x1b, 0x02, 
+0x1a, 0x43, 0x08, 0x2a, 0x06, 0xd1, 0x06, 0x23, 0x41, 0x68, 0x19, 0x43, 
+0x41, 0x60, 0x81, 0x68, 0x0e, 0x31, 0x2c, 0xe0, 0x13, 0x02, 0x12, 0x0a, 
+0x12, 0x06, 0x12, 0x0e, 0x1a, 0x43, 0x12, 0x04, 0x12, 0x0c, 0x2e, 0x3a, 
+0x16, 0x4b, 0x9a, 0x42, 0x24, 0xd8, 0x01, 0x25, 0x42, 0x68, 0x15, 0x43, 
+0x45, 0x60, 0xba, 0x7b, 0xfb, 0x7b, 0x1b, 0x02, 0x1a, 0x43, 0x12, 0x4b, 
+0x9a, 0x42, 0x19, 0xd1, 0xfb, 0x1d, 0x09, 0x33, 0x44, 0xcb, 0x9b, 0x07, 
+0xdb, 0x0e, 0xda, 0x40, 0x5b, 0x42, 0x20, 0x33, 0x9e, 0x40, 0x16, 0x43, 
+0x03, 0x2e, 0x0f, 0xd1, 0x39, 0x7d, 0x7b, 0x7d, 0x1b, 0x02, 0x19, 0x43, 
+0x08, 0x29, 0x07, 0xd1, 0x04, 0x21, 0x29, 0x43, 0x41, 0x60, 0x81, 0x68, 
+0x16, 0x31, 0x81, 0x60, 0x01, 0x21, 0x01, 0xe0, 0x00, 0x21, 0x84, 0x60, 
+0x08, 0x1c, 0xf0, 0xbc, 0x70, 0x47, 0x00, 0x00, 0xae, 0x05, 0x00, 0x00, 
+0xaa, 0xaa, 0x00, 0x00, 0x80, 0xb4, 0x42, 0x68, 0xd1, 0x08, 0x3f, 0xd3, 
+0x01, 0x68, 0x83, 0x68, 0x59, 0x18, 0x02, 0x39, 0x8f, 0x78, 0x3f, 0x07, 
+0x3f, 0x0f, 0x05, 0x2f, 0x03, 0xd1, 0xda, 0x1d, 0x0d, 0x32, 0xc2, 0x60, 
+0x05, 0xe0, 0xbf, 0x00, 0xdb, 0x19, 0xc3, 0x60, 0x08, 0x23, 0x1a, 0x43, 
+0x42, 0x60, 0x8a, 0x78, 0x12, 0x07, 0x12, 0x0f, 0x92, 0x00, 0x02, 0x61, 
+0x0a, 0x79, 0x4b, 0x79, 0x1b, 0x02, 0x1a, 0x43, 0x13, 0x02, 0x12, 0x0a, 
+0x12, 0x06, 0x12, 0x0e, 0x1a, 0x43, 0x12, 0x04, 0x12, 0x0c, 0x42, 0x61, 
+0xca, 0x7a, 0x06, 0x2a, 0x03, 0xd1, 0x10, 0x23, 0x42, 0x68, 0x1a, 0x43, 
+0x10, 0xe0, 0x11, 0x2a, 0x03, 0xd1, 0x20, 0x23, 0x42, 0x68, 0x1a, 0x43, 
+0x0a, 0xe0, 0x33, 0x2a, 0x03, 0xd1, 0x40, 0x23, 0x42, 0x68, 0x1a, 0x43, 
+0x04, 0xe0, 0x32, 0x2a, 0x03, 0xd1, 0x80, 0x23, 0x42, 0x68, 0x1a, 0x43, 
+0x42, 0x60, 0xc9, 0x7a, 0xc0, 0x46, 0x01, 0x76, 0x80, 0xbc, 0x70, 0x47, 
+0x0a, 0x78, 0xc0, 0x46, 0x02, 0x60, 0x4b, 0x78, 0x1b, 0x02, 0x1a, 0x43, 
+0x02, 0x60, 0x8b, 0x78, 0x1b, 0x04, 0x1a, 0x43, 0x02, 0x60, 0xc9, 0x78, 
+0x09, 0x06, 0x11, 0x43, 0x01, 0x60, 0x70, 0x47, 0x80, 0xb5, 0x07, 0x1c, 
+0x48, 0x68, 0x80, 0x09, 0x26, 0xd3, 0xb8, 0x6a, 0xc9, 0x68, 0x40, 0x18, 
+0x01, 0x23, 0x9b, 0x07, 0x02, 0x30, 0x18, 0x43, 0x00, 0x68, 0x00, 0x04, 
+0x00, 0x0c, 0x11, 0x23, 0x9b, 0x02, 0x98, 0x42, 0x18, 0xd1, 0x78, 0x6a, 
+0x39, 0x6b, 0xc0, 0x46, 0x48, 0x62, 0x38, 0x6b, 0x02, 0xf0, 0xb0, 0xf8, 
+0x38, 0x1c, 0x01, 0xf0, 0x6d, 0xfd, 0x01, 0x20, 0x07, 0x49, 0xc0, 0x46, 
+0xc8, 0x72, 0x07, 0x49, 0x4a, 0x6c, 0x12, 0x18, 0x4a, 0x64, 0x06, 0x49, 
+0x8a, 0x6d, 0x12, 0x18, 0x8a, 0x65, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x00, 0x20, 0xfa, 0xe7, 0x98, 0x19, 0x00, 0x80, 0x78, 0x2a, 0x00, 0x80, 
+0x10, 0x2a, 0x00, 0x80, 0x81, 0x07, 0x19, 0xd0, 0x80, 0x08, 0x80, 0x00, 
+0x01, 0x23, 0x9b, 0x07, 0x01, 0x1d, 0x18, 0x43, 
+0x00, 0x68, 0x19, 0x43, 0x09, 0x68, 0x02, 0x02, 0x12, 0x0e, 0x12, 0x06, 
+0x00, 0x0a, 0xff, 0x23, 0x1b, 0x04, 0x18, 0x40, 0x10, 0x43, 0x0a, 0x0a, 
+0x12, 0x06, 0x12, 0x0e, 0x10, 0x43, 0x09, 0x02, 0x1b, 0x0a, 0x19, 0x40, 
+0x08, 0x43, 0x70, 0x47, 0x01, 0x23, 0x9b, 0x07, 0x18, 0x43, 0x00, 0x68, 
+0x01, 0x06, 0x02, 0x02, 0xff, 0x23, 0x1b, 0x04, 0x1a, 0x40, 0x11, 0x43, 
+0x02, 0x0a, 0x1b, 0x0a, 0x1a, 0x40, 0x11, 0x43, 0x00, 0x0e, 0x08, 0x43, 
+0xed, 0xe7, 0x00, 0x00, 0xf0, 0xb5, 0x04, 0x23, 0x81, 0x6b, 0x19, 0x40, 
+0x00, 0x22, 0x00, 0x29, 0x46, 0xd0, 0xc7, 0x1d, 0x39, 0x37, 0x39, 0x7b, 
+0x33, 0x29, 0x01, 0xd0, 0x32, 0x29, 0x3f, 0xd1, 0x01, 0x6b, 0xc0, 0x46, 
+0x4a, 0x65, 0xc4, 0x1d, 0x2d, 0x34, 0xcd, 0x1d, 0x2d, 0x35, 0x00, 0x22, 
+0x93, 0x00, 0xe6, 0x58, 0xc0, 0x46, 0xee, 0x50, 0x01, 0x32, 0x07, 0x2a, 
+0xf8, 0xd3, 0x82, 0x6a, 0xc0, 0x46, 0x4a, 0x63, 0x82, 0x6a, 0xc0, 0x46, 
+0x8a, 0x62, 0x7a, 0x8b, 0xcb, 0x1d, 0x39, 0x33, 0x5a, 0x83, 0x40, 0x6a, 
+0xc0, 0x46, 0x48, 0x62, 0x12, 0x48, 0x01, 0x27, 0x42, 0x68, 0x00, 0x2a, 
+0x10, 0xd1, 0xc2, 0x68, 0x00, 0x2a, 0x13, 0xd1, 0x42, 0x69, 0x00, 0x2a, 
+0x0d, 0xd1, 0x01, 0x61, 0xc1, 0x60, 0x01, 0x6a, 0x02, 0x29, 0x02, 0xd3, 
+0x20, 0x30, 0x07, 0x71, 0x0c, 0xe0, 0x00, 0xf0, 0x13, 0xf8, 0x09, 0xe0, 
+0xc2, 0x68, 0x00, 0x2a, 0x02, 0xd1, 0x01, 0x61, 0xc1, 0x60, 0x03, 0xe0, 
+0x02, 0x69, 0xc0, 0x46, 0x51, 0x65, 0x01, 0x61, 0x38, 0x1c, 0xf0, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0x10, 0x1c, 0xfa, 0xe7, 0xec, 0x05, 0x00, 0x80, 
+0x80, 0xb5, 0x1e, 0x49, 0x00, 0x22, 0xcb, 0x68, 0x00, 0x2b, 0x34, 0xd0, 
+0xc8, 0x1d, 0xf9, 0x30, 0x83, 0x62, 0xcb, 0x68, 0x9b, 0x6a, 0xc0, 0x46, 
+0xc3, 0x62, 0xcf, 0x69, 0x7b, 0x00, 0xdf, 0x19, 0x7f, 0x02, 0x17, 0x4b, 
+0xff, 0x18, 0xff, 0x37, 0x65, 0x37, 0x83, 0x63, 0x07, 0x63, 0xcb, 0x1d, 
+0xff, 0x33, 0x5a, 0x33, 0x1a, 0x72, 0xcb, 0x69, 0x00, 0x2b, 0x01, 0xd0, 
+0xca, 0x61, 0x01, 0xe0, 0x01, 0x23, 0xcb, 0x61, 0x0f, 0x1c, 0xc9, 0x68, 
+0x49, 0x6a, 0x09, 0x89, 0x01, 0x31, 0x41, 0x63, 0xf8, 0x1d, 0xff, 0x30, 
+0x3a, 0x30, 0x42, 0x60, 0x02, 0x82, 0x82, 0x60, 0xc2, 0x60, 0x38, 0x1c, 
+0x00, 0xf0, 0xc4, 0xfa, 0x38, 0x6a, 0x01, 0x30, 0x38, 0x62, 0x38, 0x1c, 
+0x00, 0xf0, 0x0a, 0xf8, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x10, 0x1c, 
+0xfa, 0xe7, 0x00, 0x00, 0xec, 0x05, 0x00, 0x80, 0x1c, 0xad, 0x20, 0x40, 
+0xf0, 0xb5, 0x07, 0x1c, 0xf9, 0x1d, 0xf9, 0x31, 0x88, 0x6a, 0xc2, 0x1d, 
+0x2d, 0x32, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x32, 0x1a, 0x43, 0xc8, 0x6a, 
+0x12, 0x68, 0x12, 0x04, 0x12, 0x0c, 0x80, 0x18, 0x82, 0x79, 0xc3, 0x79, 
+0x1b, 0x02, 0x1a, 0x43, 0x13, 0x02, 0x12, 0x0a, 0x12, 0x06, 0x12, 0x0e, 
+0x1a, 0x43, 0x12, 0x04, 0x12, 0x0c, 0x02, 0x38, 0x92, 0x04, 0x92, 0x0c, 
+0x00, 0x26, 0x25, 0x4d, 0xec, 0x1d, 0xff, 0x34, 0x3a, 0x34, 0x00, 0x2a, 
+0x04, 0xd0, 0x20, 0x8a, 0x01, 0x23, 0x9b, 0x02, 0x18, 0x43, 0x2b, 0xe0, 
+0x01, 0x23, 0x9b, 0x07, 0xc2, 0x1d, 0x0d, 0x32, 0x1a, 0x43, 0x12, 0x68, 
+0x12, 0x04, 0x12, 0x30, 0x18, 0x43, 0x00, 0x68, 0x00, 0x04, 0x00, 0x0c, 
+0x10, 0x43, 0x03, 0x1c, 0xf8, 0x1d, 0xff, 0x30, 0x4a, 0x30, 0x82, 0x78, 
+0xc8, 0x6b, 0x19, 0x1c, 0x01, 0xf0, 0xd8, 0xff, 0x00, 0x28, 0x04, 0xda, 
+0x20, 0x8a, 0xff, 0x23, 0x01, 0x33, 0x18, 0x43, 
+0x0e, 0xe0, 0xf9, 0x1d, 0xff, 0x31, 0x3a, 0x31, 0x08, 0x60, 0x01, 0x04, 
+0x09, 0x0c, 0x38, 0x1c, 0x00, 0xf0, 0x1c, 0xf8, 0x00, 0x28, 0x14, 0xd1, 
+0x20, 0x8a, 0x01, 0x23, 0x5b, 0x02, 0x18, 0x43, 0x20, 0x82, 0x21, 0x8a, 
+0x38, 0x1c, 0x00, 0xf0, 0x98, 0xfb, 0xe8, 0x68, 0x01, 0x23, 0x9b, 0x07, 
+0x54, 0x30, 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0xe8, 0x60, 0x30, 0x1c, 
+0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x01, 0x20, 0xfa, 0xe7, 0x00, 0x00, 
+0xec, 0x05, 0x00, 0x80, 0xf8, 0xb5, 0x07, 0x1c, 0xfc, 0x1d, 0xf9, 0x34, 
+0xa0, 0x6b, 0xa6, 0x6a, 0xc5, 0x1d, 0x0d, 0x35, 0x33, 0x48, 0xc0, 0x6a, 
+0x4b, 0x00, 0x59, 0x18, 0x49, 0x01, 0x42, 0x18, 0x01, 0x20, 0x80, 0x07, 
+0x10, 0x43, 0x00, 0x68, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x90, 0x01, 0x23, 
+0x9b, 0x07, 0xd0, 0x1d, 0x05, 0x30, 0x18, 0x43, 0x00, 0x68, 0x38, 0x1c, 
+0x29, 0x1c, 0x00, 0xf0, 0xb8, 0xfa, 0xa8, 0x88, 0x40, 0x07, 0x01, 0xd0, 
+0x00, 0x20, 0x47, 0xe0, 0x00, 0x98, 0x01, 0x28, 0x25, 0xd1, 0xe0, 0x6a, 
+0xf1, 0x6b, 0x40, 0x18, 0x71, 0x6c, 0xfa, 0x1d, 0xcd, 0x32, 0x01, 0xf0, 
+0x2b, 0xf9, 0xfa, 0x1d, 0xff, 0x32, 0x3a, 0x32, 0xe0, 0x6a, 0x51, 0x69, 
+0x40, 0x18, 0xc3, 0x1d, 0x03, 0x33, 0x00, 0x20, 0x81, 0x00, 0x5e, 0x58, 
+0xc9, 0x19, 0xff, 0x31, 0x01, 0x31, 0x4e, 0x61, 0x01, 0x30, 0x04, 0x28, 
+0xf6, 0xd3, 0xe0, 0x6a, 0x51, 0x69, 0x40, 0x18, 0xc1, 0x1d, 0x05, 0x31, 
+0x00, 0x20, 0x00, 0x22, 0x43, 0x00, 0xca, 0x52, 0x01, 0x30, 0x06, 0x28, 
+0xfa, 0xd3, 0x29, 0x1c, 0x11, 0x4a, 0x00, 0x20, 0xff, 0xf7, 0xd4, 0xfb, 
+0x01, 0x22, 0x52, 0x04, 0x60, 0x6b, 0x02, 0x43, 0x01, 0x20, 0x21, 0x6b, 
+0xff, 0xf7, 0xcc, 0xfb, 0x01, 0x22, 0x52, 0x04, 0x60, 0x6b, 0x02, 0x43, 
+0x00, 0x20, 0xe1, 0x6a, 0xff, 0xf7, 0xc4, 0xfb, 0xa1, 0x6b, 0x08, 0x4a, 
+0x01, 0x20, 0xff, 0xf7, 0xbf, 0xfb, 0x03, 0x20, 0x06, 0x49, 0xc0, 0x46, 
+0x48, 0x62, 0x01, 0x20, 0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
+0xc8, 0x29, 0x00, 0x80, 0x54, 0x00, 0x03, 0x00, 0x14, 0x00, 0x0f, 0x00, 
+0xec, 0x06, 0x00, 0x80, 0xf0, 0xb5, 0x8d, 0xb0, 0x00, 0x20, 0xb5, 0x4a, 
+0xd5, 0x1d, 0xf9, 0x35, 0x68, 0x62, 0x01, 0x20, 0x00, 0x05, 0xb3, 0x49, 
+0xc0, 0x46, 0x08, 0x60, 0xa8, 0x6a, 0xc4, 0x1d, 0x2d, 0x34, 0xb1, 0x48, 
+0xc0, 0x6a, 0xd7, 0x1d, 0xff, 0x37, 0x3a, 0x37, 0x39, 0x68, 0x4b, 0x00, 
+0x59, 0x18, 0x49, 0x01, 0x40, 0x18, 0x01, 0x23, 0x9b, 0x07, 0xc1, 0x1d, 
+0x05, 0x31, 0x19, 0x43, 0x09, 0x68, 0x08, 0x30, 0x18, 0x43, 0x00, 0x68, 
+0xc0, 0x46, 0x09, 0x90, 0xff, 0x23, 0x1b, 0x02, 0x18, 0x40, 0x00, 0x0a, 
+0x0a, 0x90, 0x0a, 0x98, 0xa4, 0x4e, 0x01, 0x28, 0x59, 0xd1, 0x28, 0x6b, 
+0xa2, 0x68, 0x80, 0x18, 0xa2, 0x4a, 0x21, 0x69, 0x09, 0x04, 0x09, 0x0c, 
+0x01, 0xf0, 0x1e, 0xf9, 0x28, 0x6b, 0x79, 0x69, 0x40, 0x18, 0xc1, 0x1d, 
+0x05, 0x31, 0x00, 0x20, 0x82, 0x00, 0x98, 0x4b, 0xd3, 0x18, 0xff, 0x33, 
+0x01, 0x33, 0x5b, 0x69, 0xc0, 0x46, 0x8b, 0x50, 0x01, 0x30, 0x04, 0x28, 
+0xf4, 0xd3, 0x00, 0x20, 0x31, 0x1c, 0x82, 0x00, 0x56, 0x18, 0x01, 0x23, 
+0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 0x04, 0xae, 0xb3, 0x50, 0x01, 0x30, 
+0x03, 0x28, 0xf4, 0xd3, 0x00, 0x20, 0x08, 0x90, 0x90, 0x49, 0x42, 0x00, 
+0x8b, 0x5a, 0xb2, 0x5a, 0x93, 0x42, 0x13, 0xd0, 0x8e, 0x48, 0xc1, 0x89, 
+0x01, 0x31, 0xc1, 0x81, 0xb8, 0x68, 0x00, 0x28, 
+0x03, 0xd1, 0x38, 0x8a, 0x10, 0x23, 0x18, 0x43, 0x71, 0xe0, 0x38, 0x8a, 
+0x40, 0x23, 0x18, 0x43, 0x6d, 0xe0, 0x00, 0xf0, 0x11, 0xf9, 0x01, 0xf0, 
+0x47, 0xff, 0xf5, 0xe0, 0x01, 0x30, 0x06, 0x28, 0xe3, 0xd3, 0x08, 0x98, 
+0x00, 0x28, 0x0c, 0xd1, 0xb8, 0x68, 0x41, 0x1c, 0xb9, 0x60, 0x00, 0x28, 
+0x03, 0xd1, 0x38, 0x8a, 0x01, 0x23, 0x18, 0x43, 0x02, 0xe0, 0x38, 0x8a, 
+0x04, 0x23, 0x18, 0x43, 0x38, 0x82, 0x78, 0x68, 0x01, 0x30, 0x78, 0x60, 
+0x62, 0xe0, 0x0a, 0x98, 0x02, 0x28, 0x5f, 0xd1, 0x09, 0x98, 0x40, 0x0c, 
+0x73, 0xd3, 0x01, 0x23, 0x9b, 0x07, 0xe0, 0x1d, 0x01, 0x30, 0x18, 0x43, 
+0x00, 0x68, 0xe1, 0x1d, 0x0d, 0x31, 0x19, 0x43, 0x09, 0x68, 0x40, 0x18, 
+0x0c, 0x38, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x21, 0x8a, 0x00, 0x6b, 0x4b, 
+0xd6, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 0x04, 0xae, 
+0xb3, 0x50, 0x01, 0x31, 0x03, 0x29, 0xf3, 0xd3, 0x00, 0x21, 0x83, 0x1e, 
+0x0c, 0x93, 0x68, 0x4a, 0x16, 0x6b, 0xc0, 0x46, 0x0b, 0x96, 0x8a, 0x00, 
+0x0c, 0x9b, 0x9b, 0x18, 0x0b, 0x9e, 0x9e, 0x19, 0x01, 0x23, 0x9b, 0x07, 
+0x33, 0x43, 0x1b, 0x68, 0x6e, 0x46, 0xb3, 0x50, 0x01, 0x31, 0x04, 0x29, 
+0xf1, 0xd3, 0x69, 0x46, 0x8b, 0x1c, 0x07, 0x93, 0x00, 0x21, 0x08, 0x91, 
+0x04, 0xae, 0x4a, 0x00, 0x07, 0x9b, 0x9b, 0x5a, 0xb2, 0x5a, 0x93, 0x42, 
+0x11, 0xd0, 0x58, 0x48, 0xc1, 0x89, 0x01, 0x31, 0xc1, 0x81, 0xf8, 0x68, 
+0x41, 0x1c, 0xf9, 0x60, 0x00, 0x28, 0x03, 0xd1, 0x38, 0x8a, 0x20, 0x23, 
+0x18, 0x43, 0x02, 0xe0, 0x38, 0x8a, 0x80, 0x23, 0x18, 0x43, 0x38, 0x82, 
+0x8f, 0xe7, 0x01, 0x31, 0x06, 0x29, 0xe4, 0xd3, 0x08, 0x99, 0x00, 0x29, 
+0x0d, 0xd1, 0xf9, 0x68, 0x4a, 0x1c, 0xfa, 0x60, 0x00, 0x29, 0x04, 0xd1, 
+0x39, 0x8a, 0x02, 0x23, 0x19, 0x43, 0x03, 0xe0, 0x0c, 0xe0, 0x39, 0x8a, 
+0x08, 0x23, 0x19, 0x43, 0x39, 0x82, 0x29, 0x6b, 0x08, 0x18, 0x01, 0x23, 
+0x9b, 0x07, 0x01, 0x38, 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0x20, 0x76, 
+0x01, 0x23, 0x9b, 0x07, 0xe0, 0x1d, 0x11, 0x30, 0x18, 0x43, 0x00, 0x68, 
+0x01, 0x06, 0x09, 0x0e, 0x00, 0xe0, 0x19, 0xe0, 0x35, 0x48, 0x2a, 0x6b, 
+0xc0, 0x46, 0xea, 0x62, 0x04, 0x29, 0x4f, 0xd1, 0x01, 0x21, 0xc6, 0x1d, 
+0xff, 0x36, 0x5a, 0x36, 0x31, 0x72, 0x0a, 0x99, 0x02, 0x29, 0x1e, 0xd1, 
+0x09, 0x99, 0x09, 0x0e, 0x49, 0x06, 0x1a, 0xd1, 0xe1, 0x1d, 0x05, 0x31, 
+0x19, 0x43, 0x09, 0x68, 0x09, 0x06, 0x09, 0x0e, 0x08, 0x39, 0x1a, 0xe0, 
+0x01, 0x23, 0x9b, 0x07, 0xe0, 0x1d, 0x01, 0x30, 0x18, 0x43, 0x00, 0x68, 
+0xe1, 0x1d, 0x0d, 0x31, 0x19, 0x43, 0x09, 0x68, 0x40, 0x18, 0x00, 0x04, 
+0x00, 0x0c, 0xf9, 0x68, 0x4a, 0x1c, 0xfa, 0x60, 0x00, 0x29, 0xbc, 0xd1, 
+0xb6, 0xe7, 0x01, 0x23, 0x9b, 0x07, 0xe1, 0x1d, 0x05, 0x31, 0x19, 0x43, 
+0x09, 0x68, 0x09, 0x06, 0x09, 0x0e, 0xa1, 0x60, 0xe8, 0x6a, 0xc0, 0x46, 
+0x20, 0x60, 0x20, 0x1c, 0xff, 0xf7, 0x92, 0xfc, 0x20, 0x7e, 0x33, 0x28, 
+0x01, 0xd0, 0x32, 0x28, 0x11, 0xd1, 0x01, 0x21, 0x14, 0x4c, 0xc0, 0x46, 
+0xf9, 0x60, 0xb9, 0x60, 0x20, 0x1c, 0x00, 0xf0, 0x85, 0xf8, 0x28, 0x6b, 
+0xa9, 0x6a, 0xc0, 0x46, 0x88, 0x62, 0x20, 0x1c, 0xff, 0xf7, 0xca, 0xfd, 
+0x00, 0x28, 0x11, 0xd1, 0x0e, 0xe0, 0x00, 0x20, 0x30, 0x72, 0x11, 0xe0, 
+0x33, 0x29, 0x01, 0xd0, 0x32, 0x29, 0x0d, 0xd1, 0x07, 0x1c, 0x00, 0xf0, 
+0x71, 0xf8, 0x38, 0x1c, 0xff, 0xf7, 0xba, 0xfd, 
+0x00, 0x28, 0x01, 0xd1, 0x01, 0xf0, 0x50, 0xfe, 0x0d, 0xb0, 0xf0, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0x00, 0xf0, 0x12, 0xf8, 0xf6, 0xe7, 0x00, 0x00, 
+0xec, 0x05, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0, 0xc8, 0x29, 0x00, 0x80, 
+0x1c, 0xad, 0x20, 0x40, 0xc0, 0x06, 0x00, 0x80, 0x02, 0x07, 0x00, 0x80, 
+0x78, 0x2a, 0x00, 0x80, 0xec, 0x06, 0x00, 0x80, 0xf0, 0xb5, 0x25, 0x48, 
+0x41, 0x68, 0x01, 0x31, 0x41, 0x60, 0x24, 0x4f, 0xf9, 0x1d, 0xf9, 0x31, 
+0x00, 0x24, 0x88, 0x6a, 0xfa, 0x68, 0xc0, 0x46, 0x94, 0x61, 0x04, 0x22, 
+0xfb, 0x68, 0xc0, 0x46, 0xda, 0x60, 0x10, 0x22, 0xfb, 0x68, 0xc0, 0x46, 
+0x9a, 0x61, 0xfa, 0x1d, 0xff, 0x32, 0x5a, 0x32, 0x13, 0x7a, 0x1b, 0x4a, 
+0x00, 0x2b, 0x0b, 0xd0, 0x15, 0x8a, 0x2e, 0x0a, 0x36, 0x02, 0x33, 0x23, 
+0x2b, 0x40, 0x9b, 0x00, 0x1e, 0x43, 0xcc, 0x23, 0x2b, 0x40, 0x9b, 0x08, 
+0x33, 0x43, 0x13, 0x82, 0x12, 0x8a, 0xfb, 0x68, 0xc0, 0x46, 0xda, 0x83, 
+0x4a, 0x6b, 0xfb, 0x68, 0xc0, 0x46, 0xda, 0x81, 0x0a, 0x6b, 0xc0, 0x46, 
+0x82, 0x62, 0xc4, 0x62, 0xc3, 0x1d, 0x39, 0x33, 0x4a, 0x6b, 0xc0, 0x46, 
+0x5a, 0x83, 0x04, 0x23, 0x02, 0x68, 0x1a, 0x43, 0x02, 0x60, 0x88, 0x6a, 
+0x01, 0xf0, 0x14, 0xfa, 0xf8, 0x68, 0x01, 0x23, 0x9b, 0x07, 0x54, 0x30, 
+0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0xf8, 0x60, 0xf0, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x00, 0x78, 0x2a, 0x00, 0x80, 0xec, 0x05, 0x00, 0x80, 
+0x2c, 0x07, 0x00, 0x80, 0x80, 0xb5, 0xc1, 0x1d, 0xf9, 0x31, 0x8a, 0x6a, 
+0x01, 0x23, 0x9b, 0x07, 0xd1, 0x1d, 0x45, 0x31, 0x19, 0x43, 0x09, 0x68, 
+0x0b, 0x06, 0x1b, 0x0e, 0x01, 0x27, 0xc1, 0x1d, 0xff, 0x31, 0x4a, 0x31, 
+0x33, 0x2b, 0x05, 0xd1, 0x8b, 0x70, 0x01, 0x1c, 0x10, 0x1c, 0x00, 0xf0, 
+0x0f, 0xf8, 0x06, 0xe0, 0x32, 0x2b, 0x08, 0xd1, 0x8b, 0x70, 0x01, 0x1c, 
+0x10, 0x1c, 0x00, 0xf0, 0x3c, 0xf8, 0x38, 0x1c, 0x80, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x20, 0x88, 0x70, 0xf9, 0xe7, 0x90, 0xb4, 0xca, 0x1d, 
+0xf9, 0x32, 0x33, 0x27, 0xcc, 0x1d, 0xff, 0x34, 0x4a, 0x34, 0xd3, 0x6a, 
+0xc0, 0x46, 0xa7, 0x70, 0xff, 0x31, 0x41, 0x31, 0x07, 0x6c, 0xc0, 0x46, 
+0x4f, 0x61, 0xfb, 0x18, 0x39, 0x1c, 0x9f, 0x1e, 0x01, 0x23, 0x9b, 0x07, 
+0xfc, 0x1c, 0x23, 0x43, 0x1b, 0x68, 0x1b, 0x06, 0x1b, 0x0e, 0x9b, 0x00, 
+0x1b, 0x04, 0x1b, 0x0c, 0xc9, 0x18, 0x08, 0x31, 0x01, 0x64, 0x01, 0x23, 
+0x9b, 0x07, 0xb9, 0x1c, 0x19, 0x43, 0x09, 0x68, 0x34, 0x30, 0x01, 0x76, 
+0xf8, 0x1d, 0x01, 0x30, 0x18, 0x43, 0x00, 0x68, 0x00, 0x04, 0xb9, 0x1d, 
+0x19, 0x43, 0xd0, 0x63, 0x09, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x08, 0x43, 
+0xd0, 0x63, 0x90, 0xbc, 0x70, 0x47, 0xb0, 0xb5, 0xca, 0x1d, 0xf9, 0x32, 
+0xc5, 0x1d, 0x2d, 0x35, 0x32, 0x20, 0xcf, 0x1d, 0xff, 0x37, 0x4a, 0x37, 
+0xd3, 0x6a, 0xc0, 0x46, 0xb8, 0x70, 0xcc, 0x1d, 0xff, 0x34, 0x3a, 0x34, 
+0xe8, 0x68, 0xc0, 0x46, 0x60, 0x61, 0x10, 0x30, 0xe8, 0x60, 0x60, 0x69, 
+0xc0, 0x18, 0x87, 0x1e, 0x01, 0x23, 0x9b, 0x07, 0x38, 0x1d, 0x18, 0x43, 
+0x00, 0x68, 0x00, 0x04, 0xb9, 0x1c, 0x19, 0x43, 0xd0, 0x63, 0x09, 0x68, 
+0x09, 0x04, 0x09, 0x0c, 0x08, 0x43, 0xd0, 0x63, 0xf8, 0x1d, 0x03, 0x30, 
+0xff, 0xf7, 0x06, 0xfc, 0x20, 0x62, 0xf8, 0x1d, 0x07, 0x30, 0xff, 0xf7, 
+0x01, 0xfc, 0x60, 0x62, 0x00, 0x20, 0x28, 0x76, 0xb0, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0xf7, 0xb5, 0x81, 0xb0, 0x01, 0x98, 
+0xc7, 0x1d, 0xf9, 0x37, 0xb8, 0x6a, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d, 
+0x05, 0x34, 0x23, 0x43, 0x1c, 0x68, 0xff, 0x23, 0xfe, 0x33, 0x23, 0x40, 
+0x7f, 0x6b, 0x3f, 0x04, 0x3b, 0x43, 0x0b, 0x60, 0x34, 0x30, 0x1c, 0x1c, 
+0x80, 0x23, 0x23, 0x40, 0x01, 0x9f, 0xff, 0x37, 0x41, 0x37, 0x00, 0x2b, 
+0x3c, 0xd0, 0x0c, 0x23, 0x00, 0x93, 0x00, 0x23, 0x9d, 0x00, 0xae, 0x18, 
+0x36, 0x69, 0x6d, 0x18, 0x6e, 0x61, 0x01, 0x33, 0x05, 0x2b, 0xf7, 0xd3, 
+0x00, 0x23, 0x9d, 0x00, 0xae, 0x18, 0x76, 0x6a, 0x6d, 0x18, 0xae, 0x62, 
+0x01, 0x33, 0x05, 0x2b, 0xf7, 0xd3, 0x01, 0x9b, 0xff, 0x33, 0x51, 0x33, 
+0x9b, 0x78, 0x33, 0x2b, 0x0e, 0xd1, 0x01, 0x23, 0x9b, 0x07, 0xc5, 0x1d, 
+0x01, 0x35, 0x2b, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0x4b, 0x81, 0x01, 0x23, 
+0x9b, 0x07, 0xc5, 0x1d, 0x0d, 0x35, 0x2b, 0x43, 0x1b, 0x68, 0x16, 0xe0, 
+0x7b, 0x69, 0xc0, 0x46, 0x4b, 0x81, 0x01, 0x23, 0x9b, 0x07, 0xc5, 0x1d, 
+0x0d, 0x35, 0x2b, 0x43, 0x1b, 0x68, 0x7d, 0x69, 0x5d, 0x1b, 0x01, 0x23, 
+0x9b, 0x07, 0xc6, 0x1d, 0x01, 0x36, 0x33, 0x43, 0x1b, 0x68, 0xeb, 0x18, 
+0x0c, 0x3b, 0x02, 0xe0, 0x00, 0x23, 0x00, 0x93, 0x4b, 0x81, 0xcb, 0x80, 
+0x63, 0x09, 0x49, 0xd3, 0x01, 0x23, 0x9b, 0x07, 0xc4, 0x1d, 0x05, 0x34, 
+0x23, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0x0b, 0x81, 0x01, 0x23, 0x9b, 0x07, 
+0xc4, 0x1d, 0x0d, 0x34, 0x23, 0x43, 0x1b, 0x68, 0x0c, 0x89, 0x1b, 0x1b, 
+0x00, 0x9c, 0x1c, 0x1b, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x30, 0x18, 0x43, 
+0x00, 0x68, 0x20, 0x18, 0x88, 0x80, 0x38, 0x6a, 0x04, 0x0e, 0xff, 0x23, 
+0x1b, 0x04, 0x03, 0x40, 0x1b, 0x0a, 0x1c, 0x43, 0xff, 0x23, 0x1b, 0x02, 
+0x03, 0x40, 0x1b, 0x02, 0x23, 0x43, 0x00, 0x06, 0x18, 0x43, 0xc8, 0x60, 
+0x78, 0x6a, 0x07, 0x0e, 0xff, 0x23, 0x1b, 0x04, 0x03, 0x40, 0x1b, 0x0a, 
+0x1f, 0x43, 0xff, 0x23, 0x1b, 0x02, 0x03, 0x40, 0x1b, 0x02, 0x3b, 0x43, 
+0x00, 0x06, 0x18, 0x43, 0x08, 0x61, 0xd0, 0x6b, 0xc0, 0x46, 0xc8, 0x63, 
+0x90, 0x6b, 0xc0, 0x46, 0x08, 0x64, 0x50, 0x6c, 0xc0, 0x46, 0x48, 0x64, 
+0x10, 0x6c, 0xc0, 0x46, 0x88, 0x64, 0xd0, 0x6c, 0xc0, 0x46, 0xc8, 0x64, 
+0x90, 0x6c, 0xc0, 0x46, 0x08, 0x65, 0x02, 0xe0, 0x00, 0x23, 0x0b, 0x81, 
+0x8b, 0x80, 0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 
+0x0f, 0x4a, 0x93, 0x89, 0x01, 0x33, 0x93, 0x81, 0xc2, 0x1d, 0xf9, 0x32, 
+0x04, 0x23, 0x90, 0x6a, 0xc0, 0x46, 0xc3, 0x60, 0x10, 0x23, 0x83, 0x61, 
+0xcb, 0x0a, 0x01, 0xd3, 0x18, 0x23, 0x83, 0x61, 0xc1, 0x83, 0x51, 0x6b, 
+0xc0, 0x46, 0xc1, 0x81, 0x51, 0x6b, 0xc2, 0x1d, 0x39, 0x32, 0x51, 0x83, 
+0x04, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x01, 0xf0, 0xa4, 0xf8, 
+0x08, 0xbc, 0x18, 0x47, 0x78, 0x2a, 0x00, 0x80, 0xb0, 0xb5, 0x1b, 0x4c, 
+0x20, 0x6a, 0x02, 0x28, 0x1b, 0xd2, 0x00, 0x20, 0xe7, 0x1d, 0x19, 0x37, 
+0x38, 0x71, 0xe1, 0x68, 0xe0, 0x1d, 0xf9, 0x30, 0x00, 0x29, 0x15, 0xd0, 
+0x42, 0x6a, 0x00, 0x2a, 0x12, 0xd1, 0x01, 0x25, 0x0a, 0xe0, 0xff, 0xf7, 
+0x93, 0xfb, 0x00, 0x28, 0x09, 0xd1, 0x20, 0x6a, 0x02, 0x28, 0x00, 0xd3, 
+0x3d, 0x71, 0xe0, 0x68, 0x00, 0x28, 0x02, 0xd0, 0x38, 0x79, 0x00, 0x28, 
+0xf1, 0xd0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x40, 0x6a, 0x00, 0x28, 
+0xf9, 0xd1, 0x00, 0x29, 0xf7, 0xd1, 0x60, 0x69, 0x00, 0x28, 0x04, 0xd0, 
+0x06, 0x48, 0x00, 0x68, 0x03, 0xf0, 0x8e, 0xfc, 
+0xef, 0xe7, 0x60, 0x68, 0x00, 0x28, 0xec, 0xd0, 0x00, 0xf0, 0x50, 0xf8, 
+0xe9, 0xe7, 0x00, 0x00, 0xec, 0x05, 0x00, 0x80, 0xb4, 0x03, 0x00, 0x80, 
+0xb0, 0xb5, 0x07, 0x1c, 0x20, 0x23, 0xb8, 0x68, 0x18, 0x40, 0x00, 0x25, 
+0x00, 0x28, 0x03, 0xd1, 0x28, 0x1c, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0xc4, 0x23, 0x48, 0x68, 0x18, 0x40, 0x01, 0x24, 0x00, 0x28, 0x03, 0xd1, 
+0x38, 0x6a, 0x00, 0xf0, 0x0d, 0xfc, 0x2f, 0xe0, 0x38, 0x1c, 0x00, 0xf0, 
+0x1d, 0xfc, 0x38, 0x1c, 0x00, 0xf0, 0x7e, 0xfa, 0xb8, 0x68, 0xc0, 0x08, 
+0x02, 0xd3, 0x38, 0x6a, 0x00, 0xf0, 0xd2, 0xfb, 0xb8, 0x68, 0x39, 0x6a, 
+0xc0, 0x46, 0x88, 0x60, 0x38, 0x6a, 0xc0, 0x46, 0xc5, 0x60, 0x0f, 0x48, 
+0x41, 0x68, 0x00, 0x29, 0x11, 0xd1, 0xc1, 0x68, 0x00, 0x29, 0x09, 0xd1, 
+0x41, 0x69, 0x00, 0x29, 0x06, 0xd1, 0x39, 0x6a, 0xc0, 0x46, 0x81, 0x60, 
+0x41, 0x60, 0x00, 0xf0, 0x11, 0xf8, 0x0b, 0xe0, 0x39, 0x6a, 0xc0, 0x46, 
+0x81, 0x60, 0x41, 0x60, 0x06, 0xe0, 0x39, 0x6a, 0x82, 0x68, 0xc0, 0x46, 
+0xd1, 0x60, 0x39, 0x6a, 0xc0, 0x46, 0x81, 0x60, 0x20, 0x1c, 0xc0, 0xe7, 
+0xec, 0x05, 0x00, 0x80, 0x90, 0xb5, 0x0b, 0x4c, 0x67, 0x68, 0x00, 0x2f, 
+0x0f, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 0x12, 0xf8, 0x00, 0x28, 0x0a, 0xd1, 
+0x60, 0x68, 0xc0, 0x68, 0xc0, 0x46, 0x60, 0x60, 0x38, 0x1c, 0x00, 0xf0, 
+0xc7, 0xfb, 0x00, 0x20, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x01, 0x20, 
+0xfa, 0xe7, 0x00, 0x00, 0xec, 0x05, 0x00, 0x80, 0xf0, 0xb5, 0x07, 0x1c, 
+0xfe, 0x1d, 0x49, 0x36, 0x30, 0x78, 0x40, 0x00, 0xc0, 0x19, 0x85, 0x8b, 
+0x2d, 0x4b, 0x9d, 0x42, 0x56, 0xd0, 0x2d, 0x4c, 0x38, 0x1c, 0x21, 0x1c, 
+0x2a, 0x1c, 0x00, 0xf0, 0x23, 0xf9, 0xa0, 0x88, 0x40, 0x07, 0x4d, 0xd1, 
+0x29, 0x48, 0x80, 0x6a, 0x58, 0x21, 0x69, 0x43, 0x40, 0x18, 0x01, 0x23, 
+0x9b, 0x07, 0x18, 0x43, 0x00, 0x68, 0x00, 0x04, 0x00, 0x0c, 0x25, 0x4d, 
+0x01, 0x28, 0x1a, 0xd1, 0x30, 0x78, 0xc0, 0x19, 0xc1, 0x1d, 0x19, 0x31, 
+0x08, 0x7a, 0x3a, 0x68, 0x80, 0x18, 0x09, 0x7b, 0xea, 0x1d, 0x21, 0x32, 
+0x00, 0xf0, 0xe2, 0xfc, 0x30, 0x78, 0xc0, 0x19, 0x20, 0x30, 0x00, 0x79, 
+0x39, 0x68, 0x40, 0x18, 0xc1, 0x1d, 0x05, 0x31, 0x00, 0x20, 0x00, 0x22, 
+0x43, 0x00, 0xca, 0x52, 0x01, 0x30, 0x06, 0x28, 0xfa, 0xd3, 0x21, 0x1c, 
+0x16, 0x4a, 0x00, 0x20, 0xfe, 0xf7, 0x9a, 0xff, 0x01, 0x22, 0x52, 0x04, 
+0x78, 0x68, 0x02, 0x43, 0x01, 0x20, 0x39, 0x68, 0xfe, 0xf7, 0x92, 0xff, 
+0x01, 0x22, 0x52, 0x04, 0x78, 0x68, 0x02, 0x43, 0x00, 0x20, 0x39, 0x68, 
+0xfe, 0xf7, 0x8a, 0xff, 0x0d, 0x49, 0x0e, 0x4a, 0x01, 0x20, 0xfe, 0xf7, 
+0x85, 0xff, 0x01, 0x20, 0xe9, 0x1d, 0x19, 0x31, 0x48, 0x71, 0x02, 0x21, 
+0xea, 0x1d, 0xf9, 0x32, 0x51, 0x62, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x00, 0x20, 0xfa, 0xe7, 0xff, 0xff, 0x00, 0x00, 0x98, 0xad, 0x20, 0x40, 
+0xc8, 0x29, 0x00, 0x80, 0xec, 0x05, 0x00, 0x80, 0x54, 0x00, 0x03, 0x00, 
+0x84, 0xad, 0x20, 0x40, 0x14, 0x00, 0x07, 0x00, 0xf0, 0xb5, 0x83, 0xb0, 
+0x00, 0x21, 0x58, 0x48, 0xc2, 0x1d, 0xf9, 0x32, 0x51, 0x62, 0x01, 0x21, 
+0xc9, 0x04, 0x56, 0x4a, 0xc0, 0x46, 0x11, 0x60, 0xc1, 0x1d, 0x19, 0x31, 
+0x49, 0x79, 0x00, 0x29, 0x04, 0xd1, 0x53, 0x48, 0x00, 0x68, 0x03, 0xf0, 
+0x97, 0xfb, 0x98, 0xe0, 0x4e, 0x48, 0x47, 0x68, 0xfc, 0x1d, 0x49, 0x34, 
+0x22, 0x78, 0x50, 0x00, 0xc0, 0x19, 0x80, 0x8b, 
+0x4d, 0x49, 0x89, 0x6a, 0x58, 0x23, 0x58, 0x43, 0x0d, 0x18, 0x01, 0x23, 
+0x9b, 0x07, 0xe9, 0x1d, 0x05, 0x31, 0x19, 0x43, 0x09, 0x68, 0x08, 0x35, 
+0x2b, 0x43, 0x1d, 0x68, 0xff, 0x23, 0x1b, 0x02, 0x2b, 0x40, 0x1b, 0x0a, 
+0x45, 0x4d, 0x01, 0x2b, 0x24, 0xd1, 0xd0, 0x19, 0xc1, 0x1d, 0x19, 0x31, 
+0x08, 0x7a, 0x3a, 0x68, 0x80, 0x18, 0x42, 0x4a, 0x09, 0x7b, 0x00, 0xf0, 
+0xd3, 0xfc, 0x20, 0x78, 0xc0, 0x19, 0x20, 0x30, 0x00, 0x79, 0x39, 0x68, 
+0x41, 0x18, 0x00, 0x20, 0x82, 0x00, 0x53, 0x19, 0x9b, 0x6e, 0x6e, 0x46, 
+0xb3, 0x50, 0x01, 0x30, 0x03, 0x28, 0xf7, 0xd3, 0xca, 0x1d, 0x05, 0x32, 
+0x69, 0x46, 0x00, 0x20, 0x43, 0x00, 0xcd, 0x5a, 0xc0, 0x46, 0xd5, 0x52, 
+0x01, 0x30, 0x06, 0x28, 0xf8, 0xd3, 0x3e, 0xe0, 0x02, 0x2b, 0x3c, 0xd1, 
+0x09, 0x0a, 0x3a, 0xd3, 0x00, 0x21, 0x8a, 0x00, 0x53, 0x19, 0x9b, 0x6e, 
+0x6e, 0x46, 0xb3, 0x50, 0x01, 0x31, 0x03, 0x29, 0xf7, 0xd3, 0x21, 0x78, 
+0x49, 0x00, 0xc9, 0x19, 0x09, 0x8f, 0x3a, 0x68, 0x8b, 0x18, 0x6a, 0x46, 
+0x00, 0x21, 0x4d, 0x00, 0x56, 0x5b, 0xc0, 0x46, 0x5e, 0x53, 0x01, 0x31, 
+0x06, 0x29, 0xf8, 0xd3, 0x22, 0x49, 0x8a, 0x6a, 0x12, 0x18, 0x01, 0x23, 
+0x9b, 0x07, 0xd5, 0x1d, 0x49, 0x35, 0x2b, 0x43, 0x6e, 0x46, 0x1d, 0x68, 
+0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 0x6b, 0x40, 0x1e, 0x4d, 
+0xee, 0x68, 0x73, 0x40, 0x13, 0x65, 0x89, 0x6a, 0x08, 0x18, 0x01, 0x23, 
+0x9b, 0x07, 0xc1, 0x1d, 0x4d, 0x31, 0x19, 0x43, 0x09, 0x68, 0x6a, 0x46, 
+0x08, 0x32, 0x1a, 0x43, 0x12, 0x68, 0x51, 0x40, 0xaa, 0x69, 0x51, 0x40, 
+0x41, 0x65, 0x20, 0x78, 0x41, 0x1e, 0x21, 0x70, 0x00, 0x28, 0x0d, 0xd0, 
+0x38, 0x1c, 0xff, 0xf7, 0xef, 0xfe, 0x00, 0x28, 0x0d, 0xd1, 0x09, 0x4a, 
+0x50, 0x68, 0xc0, 0x68, 0xc0, 0x46, 0x50, 0x60, 0x38, 0x1c, 0x00, 0xf0, 
+0xa3, 0xfa, 0x02, 0xe0, 0x38, 0x1c, 0x00, 0xf0, 0x72, 0xfa, 0x01, 0xf0, 
+0xc3, 0xfa, 0x03, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
+0xec, 0x05, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0, 0xb8, 0x03, 0x00, 0x80, 
+0xc8, 0x29, 0x00, 0x80, 0x1c, 0xad, 0x20, 0x40, 0x14, 0x06, 0x00, 0x80, 
+0x08, 0x83, 0x20, 0x40, 0xf0, 0xb5, 0x82, 0xb0, 0x69, 0x4b, 0x9f, 0x6a, 
+0x58, 0x23, 0x5a, 0x43, 0xba, 0x18, 0xc3, 0x1d, 0x49, 0x33, 0x1f, 0x78, 
+0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d, 0x01, 0x34, 0x23, 0x43, 0x1d, 0x68, 
+0x43, 0x68, 0x1c, 0x04, 0x01, 0x23, 0x9b, 0x07, 0xd6, 0x1d, 0x05, 0x36, 
+0x33, 0x43, 0x1b, 0x68, 0x1c, 0x43, 0x42, 0x23, 0x1c, 0x43, 0x0c, 0x60, 
+0xff, 0x26, 0x36, 0x02, 0x2e, 0x40, 0x01, 0x23, 0x5b, 0x02, 0x9e, 0x42, 
+0x74, 0xd1, 0x6b, 0x0c, 0x2b, 0xd3, 0xc3, 0x19, 0x20, 0x33, 0x1b, 0x79, 
+0xc0, 0x46, 0x4b, 0x81, 0x7b, 0x00, 0x1b, 0x18, 0x1b, 0x8f, 0x4c, 0x89, 
+0x1b, 0x1b, 0xcb, 0x80, 0x00, 0x24, 0xa6, 0x00, 0x01, 0x96, 0xb3, 0x18, 
+0xde, 0x1d, 0x09, 0x36, 0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 
+0x01, 0x9e, 0x76, 0x18, 0x73, 0x61, 0x01, 0x34, 0x05, 0x2c, 0xf0, 0xd3, 
+0x00, 0x24, 0xa6, 0x00, 0x00, 0x96, 0xb3, 0x18, 0xde, 0x1d, 0x1d, 0x36, 
+0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 0x00, 0x9e, 0x76, 0x18, 
+0xb3, 0x62, 0x01, 0x34, 0x05, 0x2c, 0xf0, 0xd3, 0x06, 0xe0, 0x00, 0x23, 
+0x4b, 0x81, 0xcb, 0x80, 0x40, 0x23, 0x9c, 0x43, 0x0c, 0x60, 0x23, 0x1c, 
+0x6b, 0x0e, 0x4a, 0xd3, 0xc3, 0x19, 0x20, 0x33, 
+0x1b, 0x79, 0x10, 0x33, 0x0b, 0x81, 0x7b, 0x00, 0x1b, 0x18, 0x1b, 0x8f, 
+0x0f, 0x89, 0xdb, 0x1b, 0x8b, 0x80, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d, 
+0x35, 0x34, 0x23, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0xcb, 0x63, 0x01, 0x23, 
+0x9b, 0x07, 0xd4, 0x1d, 0x31, 0x34, 0x23, 0x43, 0x1b, 0x68, 0xc0, 0x46, 
+0x0b, 0x64, 0xab, 0x0e, 0x21, 0xd2, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d, 
+0x3d, 0x34, 0x23, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0x4b, 0x64, 0x01, 0x23, 
+0x9b, 0x07, 0xd4, 0x1d, 0x39, 0x34, 0x23, 0x43, 0x1b, 0x68, 0xc0, 0x46, 
+0x8b, 0x64, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d, 0x45, 0x34, 0x23, 0x43, 
+0x1b, 0x68, 0xc0, 0x46, 0xcb, 0x64, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d, 
+0x41, 0x34, 0x23, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0x0b, 0x65, 0x00, 0xe0, 
+0x0f, 0xe0, 0xfb, 0x1f, 0x01, 0x3b, 0x1b, 0x04, 0x1b, 0x0c, 0x07, 0x68, 
+0xff, 0x18, 0x03, 0x69, 0x08, 0x1c, 0x39, 0x1c, 0x00, 0xf0, 0x34, 0xf8, 
+0x2c, 0xe0, 0x00, 0x23, 0x0b, 0x81, 0x8b, 0x80, 0x28, 0xe0, 0x00, 0x23, 
+0x8b, 0x80, 0x0b, 0x81, 0xc3, 0x19, 0x20, 0x33, 0x1b, 0x7a, 0xc0, 0x46, 
+0x4b, 0x81, 0x7b, 0x00, 0x18, 0x18, 0x00, 0x8e, 0xc0, 0x46, 0xc8, 0x80, 
+0x00, 0x20, 0x87, 0x00, 0xbb, 0x18, 0xdc, 0x1d, 0x09, 0x34, 0x01, 0x23, 
+0x9b, 0x07, 0x23, 0x43, 0x1b, 0x68, 0x7f, 0x18, 0x7b, 0x61, 0x01, 0x30, 
+0x05, 0x28, 0xf2, 0xd3, 0x00, 0x20, 0x87, 0x00, 0xbb, 0x18, 0xdc, 0x1d, 
+0x1d, 0x34, 0x01, 0x23, 0x9b, 0x07, 0x23, 0x43, 0x1b, 0x68, 0x7f, 0x18, 
+0xbb, 0x62, 0x01, 0x30, 0x05, 0x28, 0xf2, 0xd3, 0x02, 0xb0, 0xf0, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0xc8, 0x29, 0x00, 0x80, 0x80, 0xb4, 0x1f, 0x1c, 
+0x3b, 0x0c, 0x18, 0xd2, 0x17, 0x6d, 0x11, 0x4b, 0xc0, 0x46, 0xdf, 0x60, 
+0x52, 0x6d, 0xc0, 0x46, 0x1a, 0x61, 0xc7, 0x60, 0x1a, 0x69, 0xc0, 0x46, 
+0x02, 0x61, 0xd8, 0x68, 0xc0, 0x46, 0x08, 0x80, 0xd8, 0x68, 0x00, 0x0c, 
+0x48, 0x80, 0x18, 0x69, 0xc0, 0x46, 0x88, 0x80, 0x18, 0x69, 0x00, 0x0c, 
+0xc8, 0x80, 0x80, 0xbc, 0x70, 0x47, 0x4a, 0x88, 0x12, 0x04, 0x0b, 0x88, 
+0x1a, 0x43, 0xc2, 0x60, 0x8a, 0x88, 0xc9, 0x88, 0x09, 0x04, 0x11, 0x43, 
+0x01, 0x61, 0xf2, 0xe7, 0xac, 0x06, 0x00, 0x80, 0xf1, 0xb5, 0x88, 0xb0, 
+0x00, 0x22, 0x08, 0x98, 0x00, 0x6a, 0x08, 0x9b, 0x99, 0x68, 0x49, 0x0a, 
+0x02, 0xd3, 0x01, 0x27, 0xff, 0x03, 0x00, 0xe0, 0x00, 0x27, 0x03, 0x8b, 
+0x00, 0x2b, 0x19, 0xd0, 0xa2, 0x49, 0x89, 0x6a, 0x1c, 0x1c, 0x58, 0x23, 
+0x63, 0x43, 0xc9, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x58, 0x39, 0x19, 0x43, 
+0x09, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x02, 0x29, 0x02, 0xd1, 0x08, 0x23, 
+0x1f, 0x43, 0x07, 0xe0, 0x41, 0x8b, 0x00, 0x29, 0x02, 0xd0, 0x0c, 0x23, 
+0x1f, 0x43, 0x01, 0xe0, 0x04, 0x23, 0x1f, 0x43, 0x83, 0x8a, 0x00, 0x2b, 
+0x18, 0xd0, 0x94, 0x49, 0x89, 0x6a, 0x1c, 0x1c, 0x58, 0x23, 0x63, 0x43, 
+0xc9, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x58, 0x39, 0x19, 0x43, 0x09, 0x68, 
+0x09, 0x04, 0x09, 0x0c, 0x02, 0x29, 0x01, 0xd1, 0x0f, 0x43, 0x07, 0xe0, 
+0xc1, 0x8a, 0x00, 0x29, 0x02, 0xd0, 0x03, 0x23, 0x1f, 0x43, 0x01, 0xe0, 
+0x01, 0x23, 0x1f, 0x43, 0xc1, 0x1d, 0x39, 0x31, 0x07, 0x91, 0x4b, 0x89, 
+0x0c, 0x89, 0x1c, 0x19, 0x24, 0x04, 0x24, 0x0c, 0x08, 0x9d, 0x2d, 0x68, 
+0xc0, 0x46, 0x01, 0x95, 0xc9, 0x88, 0x7d, 0x08, 0x1a, 0xd3, 0x1a, 0x1c, 
+0xc3, 0x1d, 0x19, 0x33, 0x1a, 0x72, 0x07, 0x9a, 
+0x92, 0x89, 0xc0, 0x46, 0x1a, 0x73, 0x07, 0x9a, 0x12, 0x89, 0xc0, 0x46, 
+0x02, 0x86, 0x04, 0x87, 0x82, 0x8a, 0x01, 0x3a, 0x82, 0x83, 0x01, 0x22, 
+0x19, 0x71, 0x08, 0x9b, 0x1b, 0x68, 0x5b, 0x18, 0x5b, 0x78, 0x9b, 0x00, 
+0x1b, 0x04, 0x1b, 0x0c, 0x08, 0x33, 0x59, 0x18, 0xbb, 0x08, 0x47, 0xd3, 
+0x07, 0x9b, 0x5b, 0x89, 0x85, 0x18, 0x06, 0x95, 0x20, 0x35, 0x2b, 0x72, 
+0x07, 0x9b, 0x9b, 0x89, 0xc0, 0x46, 0x2b, 0x73, 0x07, 0x9b, 0x1b, 0x89, 
+0x2e, 0x1c, 0x55, 0x00, 0x2d, 0x18, 0x05, 0x95, 0x2b, 0x86, 0x00, 0x2a, 
+0x01, 0xd0, 0xc3, 0x8a, 0x00, 0xe0, 0x83, 0x8a, 0x01, 0x3b, 0x05, 0x9d, 
+0xc0, 0x46, 0xab, 0x83, 0x31, 0x71, 0x64, 0x4b, 0x9d, 0x6a, 0x05, 0x9b, 
+0x9e, 0x8b, 0x58, 0x23, 0x73, 0x43, 0xeb, 0x18, 0xdd, 0x1d, 0x01, 0x35, 
+0x01, 0x23, 0x9b, 0x07, 0x2b, 0x43, 0x1d, 0x68, 0x2b, 0x0e, 0x5b, 0x06, 
+0x01, 0xd1, 0x08, 0x31, 0x00, 0xe0, 0x10, 0x31, 0x81, 0x23, 0x5b, 0x02, 
+0x1d, 0x40, 0x9d, 0x42, 0x03, 0xd1, 0xe3, 0x1f, 0x05, 0x3b, 0x1c, 0x04, 
+0x24, 0x0c, 0x05, 0x9b, 0xc0, 0x46, 0x1c, 0x87, 0x08, 0x9b, 0x1b, 0x68, 
+0x1b, 0x19, 0x10, 0x3b, 0x9b, 0x7b, 0x06, 0x9d, 0x40, 0x35, 0x2b, 0x70, 
+0x2b, 0x78, 0x02, 0x33, 0xe3, 0x1a, 0x1c, 0x04, 0x24, 0x0c, 0x01, 0x32, 
+0xbb, 0x08, 0x9b, 0x07, 0x6b, 0xd0, 0x83, 0x18, 0x20, 0x33, 0x04, 0x93, 
+0x19, 0x72, 0x01, 0x9b, 0x5d, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x2b, 0x43, 
+0x1b, 0x68, 0x1b, 0x07, 0x1b, 0x0f, 0x9b, 0x00, 0x04, 0x9e, 0xc0, 0x46, 
+0x33, 0x73, 0x00, 0x95, 0x2b, 0x78, 0x1b, 0x07, 0x1b, 0x0f, 0x9b, 0x00, 
+0x04, 0x9d, 0xc0, 0x46, 0x2b, 0x73, 0x00, 0x9d, 0xeb, 0x78, 0xad, 0x78, 
+0x1b, 0x02, 0x1d, 0x43, 0x2b, 0x02, 0x2d, 0x0a, 0x2d, 0x06, 0x2d, 0x0e, 
+0x2b, 0x43, 0x55, 0x00, 0x2d, 0x18, 0x2b, 0x86, 0x04, 0x9b, 0xc0, 0x46, 
+0x59, 0x72, 0x04, 0x9b, 0x1b, 0x7b, 0x2e, 0x1c, 0x04, 0x9d, 0xc0, 0x46, 
+0x6b, 0x73, 0x33, 0x8e, 0xc0, 0x46, 0x73, 0x86, 0x00, 0x9d, 0x2b, 0x78, 
+0x1b, 0x07, 0x1b, 0x0f, 0x9b, 0x00, 0x59, 0x18, 0x04, 0x25, 0x3d, 0x40, 
+0x0e, 0xd0, 0x34, 0x87, 0x03, 0x8b, 0x01, 0x3b, 0xb3, 0x83, 0x13, 0x1c, 
+0x1b, 0x18, 0x20, 0x33, 0x19, 0x71, 0x01, 0x9b, 0x5b, 0x18, 0x5b, 0x78, 
+0x9b, 0x00, 0x59, 0x18, 0x08, 0x31, 0x01, 0x32, 0x3b, 0x09, 0x37, 0xd3, 
+0x00, 0x2d, 0x01, 0xd0, 0x43, 0x8b, 0x00, 0xe0, 0x03, 0x8b, 0x55, 0x00, 
+0x2d, 0x18, 0x01, 0x3b, 0xab, 0x83, 0x83, 0x18, 0x03, 0x93, 0x20, 0x33, 
+0x19, 0x71, 0x20, 0x4b, 0x9d, 0x6a, 0x53, 0x00, 0x1b, 0x18, 0x02, 0x93, 
+0x9e, 0x8b, 0x58, 0x23, 0x73, 0x43, 0xeb, 0x18, 0xdd, 0x1d, 0x01, 0x35, 
+0x01, 0x23, 0x9b, 0x07, 0x2b, 0x43, 0x1d, 0x68, 0x2b, 0x0e, 0x5b, 0x06, 
+0x02, 0xd1, 0x08, 0x31, 0x01, 0xe0, 0x15, 0xe0, 0x10, 0x31, 0x81, 0x23, 
+0x5b, 0x02, 0x1d, 0x40, 0x9d, 0x42, 0x03, 0xd1, 0xe3, 0x1f, 0x05, 0x3b, 
+0x1c, 0x04, 0x24, 0x0c, 0x02, 0x9b, 0xc0, 0x46, 0x1c, 0x87, 0x08, 0x9b, 
+0x1b, 0x68, 0x1b, 0x19, 0x10, 0x3b, 0x9b, 0x7b, 0x03, 0x9c, 0x40, 0x34, 
+0x23, 0x70, 0x01, 0x32, 0x07, 0x9b, 0xc0, 0x46, 0xd9, 0x80, 0x51, 0x1e, 
+0xc3, 0x1d, 0x49, 0x33, 0x19, 0x70, 0x07, 0x61, 0x04, 0x2a, 0x06, 0xd2, 
+0x06, 0x49, 0x53, 0x00, 0x1b, 0x18, 0x99, 0x83, 0x01, 0x32, 0x04, 0x2a, 
+0xf9, 0xd3, 0x09, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
+0xc8, 0x29, 0x00, 0x80, 0xff, 0xff, 0x00, 0x00, 
+0x70, 0x47, 0x80, 0xb5, 0x8c, 0xb0, 0x07, 0x1c, 0x12, 0x48, 0x01, 0x68, 
+0x01, 0x31, 0x01, 0x60, 0x38, 0x68, 0xc0, 0x46, 0x00, 0x90, 0x78, 0x68, 
+0xc0, 0x46, 0x01, 0x90, 0xb8, 0x68, 0xc0, 0x46, 0x02, 0x90, 0x0d, 0x48, 
+0x41, 0x68, 0xc9, 0x68, 0xc0, 0x46, 0x41, 0x60, 0x38, 0x1c, 0x00, 0xf0, 
+0x4f, 0xf8, 0xb8, 0x68, 0x40, 0x09, 0x06, 0xd3, 0x10, 0x23, 0x02, 0x98, 
+0x18, 0x43, 0x02, 0x90, 0x68, 0x46, 0x02, 0xf0, 0xcd, 0xff, 0x68, 0x46, 
+0x02, 0xf0, 0x82, 0xfe, 0x0c, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x78, 0x2a, 0x00, 0x80, 0xec, 0x05, 0x00, 0x80, 0x00, 0xb5, 0x8c, 0xb0, 
+0x01, 0x68, 0xc0, 0x46, 0x00, 0x91, 0x41, 0x68, 0x05, 0x4b, 0x19, 0x43, 
+0x01, 0x91, 0x00, 0xf0, 0x2f, 0xf8, 0x68, 0x46, 0x02, 0xf0, 0x6c, 0xfe, 
+0x0c, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 
+0x02, 0x6a, 0x03, 0x68, 0xc0, 0x46, 0x13, 0x60, 0x40, 0x68, 0xc0, 0x46, 
+0x50, 0x60, 0x40, 0x32, 0x48, 0x68, 0xc0, 0x46, 0x90, 0x80, 0xc8, 0x68, 
+0xc0, 0x46, 0xd0, 0x80, 0x48, 0x69, 0xc0, 0x46, 0x10, 0x81, 0x88, 0x68, 
+0xc0, 0x46, 0x50, 0x81, 0x08, 0x7e, 0xc0, 0x46, 0x90, 0x73, 0x08, 0x69, 
+0xc0, 0x46, 0x90, 0x81, 0x70, 0x47, 0x04, 0x49, 0x08, 0x68, 0x00, 0x28, 
+0x00, 0xd1, 0x70, 0x47, 0xc2, 0x68, 0xc0, 0x46, 0x0a, 0x60, 0xfa, 0xe7, 
+0xec, 0x05, 0x00, 0x80, 0x02, 0x49, 0x0a, 0x68, 0xc0, 0x46, 0xc2, 0x60, 
+0x08, 0x60, 0x70, 0x47, 0xec, 0x05, 0x00, 0x80, 0xb0, 0xb4, 0x00, 0x22, 
+0x12, 0x4f, 0x3b, 0x7f, 0x01, 0x33, 0x3b, 0x77, 0x03, 0x23, 0xfc, 0x1d, 
+0x19, 0x34, 0x38, 0x62, 0x79, 0x62, 0x23, 0x72, 0x0e, 0x4c, 0x25, 0x68, 
+0x6b, 0x0c, 0x05, 0xd2, 0x23, 0x68, 0x1b, 0x0c, 0x10, 0xd1, 0x24, 0x68, 
+0xa3, 0x0a, 0x0d, 0xd3, 0x01, 0x23, 0x0a, 0x4f, 0xc0, 0x46, 0xfb, 0x62, 
+0x09, 0x4f, 0x0a, 0x4b, 0xc0, 0x46, 0xdf, 0x60, 0x99, 0x60, 0x58, 0x60, 
+0x10, 0x1c, 0x18, 0x60, 0x01, 0x32, 0xfb, 0xe7, 0x10, 0x1c, 0x38, 0x64, 
+0x01, 0x32, 0xfb, 0xe7, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x10, 0x40, 
+0xc0, 0x00, 0x18, 0x00, 0x02, 0x81, 0x00, 0x00, 0x40, 0x01, 0x18, 0x00, 
+0xf0, 0xb5, 0x47, 0x4f, 0x38, 0x68, 0x47, 0x4e, 0x47, 0x4d, 0x07, 0x23, 
+0x5b, 0x02, 0xec, 0x18, 0x00, 0x28, 0x1d, 0xd1, 0xe0, 0x6a, 0x01, 0x30, 
+0xe0, 0x62, 0x44, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x43, 0x48, 0x41, 0x69, 
+0x00, 0x29, 0x13, 0xd0, 0xc1, 0x1d, 0x69, 0x31, 0x09, 0x7b, 0x00, 0x29, 
+0x0e, 0xd0, 0x01, 0x23, 0x9b, 0x07, 0x01, 0x6d, 0x19, 0x43, 0x09, 0x68, 
+0xc0, 0x46, 0x81, 0x61, 0xc2, 0x69, 0x91, 0x42, 0x04, 0xd0, 0xf1, 0x6c, 
+0x01, 0x31, 0xf1, 0x64, 0x01, 0xf0, 0x3a, 0xfe, 0x38, 0x68, 0x01, 0x28, 
+0x17, 0xd1, 0x37, 0x48, 0x41, 0x69, 0x00, 0x29, 0x13, 0xd0, 0xc1, 0x1d, 
+0x69, 0x31, 0x09, 0x7b, 0x00, 0x29, 0x0e, 0xd0, 0x01, 0x23, 0x9b, 0x07, 
+0x01, 0x6d, 0x19, 0x43, 0x09, 0x68, 0xc0, 0x46, 0x81, 0x61, 0xc2, 0x69, 
+0x91, 0x42, 0x04, 0xd0, 0xf1, 0x6c, 0x01, 0x31, 0xf1, 0x64, 0x01, 0xf0, 
+0x1f, 0xfe, 0x38, 0x68, 0x02, 0x28, 0x2f, 0xd1, 0xbb, 0x23, 0x1b, 0x01, 
+0xee, 0x18, 0x70, 0x7a, 0x00, 0x28, 0x03, 0xd0, 0x00, 0x20, 0x70, 0x72, 
+0x00, 0xf0, 0x30, 0xfd, 0x30, 0x7a, 0x00, 0x28, 0x02, 0xd0, 0x78, 0x68, 
+0x02, 0xf0, 0x96, 0xff, 0x1b, 0x23, 0xdb, 0x01, 0xe8, 0x18, 0x40, 0x8b, 
+0x04, 0x26, 0x06, 0x40, 0xa0, 0x6a, 0xb0, 0x42, 
+0x14, 0xd0, 0xf8, 0x68, 0x01, 0x30, 0xf8, 0x60, 0x19, 0x28, 0x11, 0xd3, 
+0x1b, 0x48, 0x01, 0x7b, 0x00, 0x29, 0x0d, 0xd1, 0xff, 0x30, 0x41, 0x30, 
+0x40, 0x78, 0x00, 0x28, 0x08, 0xd1, 0xb8, 0x68, 0x02, 0xf0, 0x7c, 0xff, 
+0x00, 0x20, 0xf8, 0x60, 0xa6, 0x62, 0x01, 0xe0, 0x00, 0x20, 0xf8, 0x60, 
+0x38, 0x68, 0x03, 0x28, 0x0b, 0xd1, 0xec, 0x1d, 0x79, 0x34, 0xa0, 0x6b, 
+0x80, 0x08, 0x02, 0xd3, 0x02, 0x20, 0x02, 0xf0, 0xef, 0xfb, 0x02, 0x23, 
+0xa0, 0x6b, 0x98, 0x43, 0xa0, 0x63, 0x38, 0x68, 0x01, 0x30, 0x38, 0x60, 
+0x03, 0x28, 0x01, 0xd9, 0x00, 0x20, 0x38, 0x60, 0xf0, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x00, 0xbc, 0x03, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, 
+0xe8, 0x0d, 0x00, 0x80, 0x40, 0x01, 0x18, 0x00, 0xd0, 0x2c, 0x00, 0x80, 
+0x50, 0x2c, 0x00, 0x80, 0xa8, 0x04, 0x00, 0x80, 0x90, 0xb4, 0x1c, 0x48, 
+0x02, 0x8a, 0x1c, 0x49, 0x0f, 0x8a, 0x01, 0x23, 0xba, 0x42, 0x03, 0xd1, 
+0xc2, 0x89, 0x4f, 0x8a, 0xba, 0x42, 0x10, 0xd0, 0x02, 0x7b, 0x00, 0x2a, 
+0x0d, 0xd0, 0x42, 0x7b, 0x00, 0x2a, 0x0a, 0xd0, 0xc7, 0x8a, 0x8a, 0x8a, 
+0x97, 0x42, 0x04, 0xdc, 0x13, 0x4a, 0xc0, 0x46, 0x53, 0x60, 0x8b, 0x82, 
+0x01, 0xe0, 0x01, 0x32, 0x8a, 0x82, 0x42, 0x8b, 0x57, 0x1c, 0x47, 0x83, 
+0x07, 0x8b, 0xba, 0x42, 0x0e, 0xdb, 0x07, 0x8a, 0x84, 0x8a, 0x00, 0x22, 
+0xa7, 0x42, 0x05, 0xda, 0xc7, 0x89, 0x44, 0x8a, 0xa7, 0x42, 0x01, 0xda, 
+0x42, 0x73, 0x00, 0xe0, 0x43, 0x73, 0xc2, 0x81, 0x02, 0x82, 0x42, 0x83, 
+0xc2, 0x89, 0xc0, 0x46, 0x4a, 0x82, 0x00, 0x8a, 0xc0, 0x46, 0x08, 0x82, 
+0x90, 0xbc, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80, 0xbc, 0x03, 0x00, 0x80, 
+0x40, 0x01, 0x18, 0x00, 0xf7, 0xb5, 0x91, 0xb0, 0x6b, 0x46, 0x84, 0x1e, 
+0x12, 0x99, 0x14, 0x29, 0x1a, 0xd9, 0x00, 0x20, 0x81, 0x00, 0x67, 0x58, 
+0xc0, 0x46, 0x57, 0x50, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x10, 0x28, 
+0xf6, 0xd3, 0x00, 0x21, 0x05, 0x20, 0x87, 0x00, 0xd6, 0x59, 0x4f, 0x1c, 
+0x3d, 0x06, 0x2d, 0x0e, 0x0f, 0x1c, 0xbf, 0x00, 0xde, 0x51, 0x29, 0x1c, 
+0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x10, 0x28, 0xf1, 0xd3, 0x09, 0xe0, 
+0x00, 0x20, 0x81, 0x00, 0x63, 0x58, 0xc0, 0x46, 0x53, 0x50, 0x01, 0x30, 
+0x00, 0x06, 0x00, 0x0e, 0x06, 0x28, 0xf6, 0xd3, 0x00, 0x20, 0xe0, 0x70, 
+0x20, 0x72, 0x60, 0x72, 0xa0, 0x72, 0x20, 0x73, 0x60, 0x73, 0x12, 0x99, 
+0x14, 0x29, 0x37, 0xd9, 0x69, 0x46, 0x8e, 0x1c, 0x91, 0x78, 0x09, 0x07, 
+0x09, 0x0f, 0x89, 0x00, 0x14, 0x39, 0x0d, 0x06, 0x2d, 0x16, 0x00, 0x27, 
+0x00, 0x2d, 0x1b, 0xdd, 0xf0, 0x19, 0x10, 0xa9, 0x00, 0xf0, 0x3d, 0xf8, 
+0x00, 0x28, 0x0e, 0xd0, 0x00, 0x20, 0x10, 0xa9, 0x09, 0x78, 0x00, 0x29, 
+0x09, 0xdd, 0x00, 0x22, 0x39, 0x18, 0x72, 0x54, 0x01, 0x30, 0x00, 0x06, 
+0x00, 0x0e, 0x10, 0xa9, 0x09, 0x78, 0x88, 0x42, 0xf6, 0xdb, 0x10, 0xa8, 
+0x00, 0x78, 0x38, 0x18, 0x07, 0x06, 0x3f, 0x0e, 0xaf, 0x42, 0xe3, 0xdb, 
+0x68, 0x46, 0xe2, 0x1d, 0x0d, 0x32, 0x00, 0x21, 0xab, 0x08, 0x5f, 0x1c, 
+0x08, 0xd0, 0x8b, 0x00, 0xc4, 0x58, 0xc0, 0x46, 0xd4, 0x50, 0x01, 0x31, 
+0x09, 0x06, 0x09, 0x0e, 0x8f, 0x42, 0xf6, 0xd8, 0x14, 0xb0, 0xf0, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0x90, 0xb4, 0x87, 0x1e, 0x00, 0x20, 0x89, 0x08, 
+0x4b, 0x1c, 0x08, 0xd0, 0x81, 0x00, 0x54, 0x58, 0xc0, 0x46, 0x7c, 0x50, 
+0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x83, 0x42, 
+0xf6, 0xd8, 0x90, 0xbc, 0x70, 0x47, 0x80, 0xb4, 0x02, 0x78, 0xd2, 0x06, 
+0xd2, 0x0e, 0x00, 0x23, 0x01, 0x27, 0x01, 0x2a, 0x01, 0xdc, 0x0f, 0x70, 
+0x11, 0xe0, 0x40, 0x78, 0xc0, 0x46, 0x08, 0x70, 0x14, 0x2a, 0x04, 0xd1, 
+0x08, 0x48, 0x01, 0x7a, 0x01, 0x31, 0x01, 0x72, 0x07, 0xe0, 0x02, 0x2a, 
+0x05, 0xd0, 0x05, 0x2a, 0x03, 0xd0, 0x06, 0x2a, 0x01, 0xd0, 0x15, 0x2a, 
+0x02, 0xd1, 0x18, 0x1c, 0x80, 0xbc, 0x70, 0x47, 0x38, 0x1c, 0xfb, 0xe7, 
+0xe0, 0x82, 0x20, 0x40, 0x00, 0xb5, 0x0f, 0x48, 0x01, 0x23, 0x1b, 0x06, 
+0x41, 0x69, 0x99, 0x43, 0x1a, 0x09, 0x41, 0x61, 0xd1, 0x60, 0x00, 0x21, 
+0xa1, 0x22, 0x52, 0x03, 0x91, 0x61, 0x19, 0x1c, 0x09, 0x4a, 0xc0, 0x46, 
+0x11, 0x60, 0x1b, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x40, 0x69, 0x00, 0x28, 
+0x03, 0xd0, 0x02, 0xf0, 0x4f, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0x04, 0x48, 
+0x41, 0x88, 0x01, 0x31, 0x41, 0x80, 0xf8, 0xe7, 0xe8, 0x0d, 0x00, 0x80, 
+0x00, 0x00, 0x00, 0xb0, 0xe0, 0x82, 0x20, 0x40, 0x70, 0x47, 0x00, 0x00, 
+0xf0, 0xb5, 0x85, 0xb0, 0x94, 0x49, 0xc8, 0x68, 0xcf, 0x1d, 0x79, 0x37, 
+0x01, 0x28, 0x0b, 0xd1, 0xb8, 0x88, 0x00, 0x28, 0x08, 0xd1, 0xc3, 0x1e, 
+0xca, 0x6f, 0x1a, 0x40, 0xca, 0x67, 0x8f, 0x48, 0xc0, 0x46, 0x02, 0x60, 
+0x14, 0x20, 0xb8, 0x80, 0x8d, 0x4c, 0x62, 0x6a, 0x8d, 0x48, 0xc3, 0x6b, 
+0x9a, 0x18, 0xc2, 0x63, 0xa0, 0x6a, 0x19, 0x23, 0xdb, 0x01, 0xcc, 0x18, 
+0x60, 0x62, 0xe2, 0x69, 0x12, 0x03, 0x12, 0x0b, 0x82, 0x42, 0x05, 0xd1, 
+0x01, 0x20, 0x40, 0x04, 0x86, 0x49, 0xc0, 0x46, 0x08, 0x60, 0xef, 0xe0, 
+0x3b, 0x8a, 0x58, 0x1c, 0x38, 0x82, 0xbd, 0x8a, 0x01, 0x20, 0x00, 0x22, 
+0xab, 0x42, 0x02, 0xdb, 0x78, 0x73, 0x3a, 0x82, 0x7a, 0x83, 0x33, 0x23, 
+0x9b, 0x01, 0xcb, 0x18, 0x04, 0x93, 0x1b, 0x69, 0x0f, 0x2b, 0x73, 0xd2, 
+0x00, 0x22, 0x2f, 0x23, 0x9b, 0x01, 0xcf, 0x18, 0xfa, 0x60, 0xe1, 0x69, 
+0x8a, 0x68, 0x12, 0x04, 0x12, 0x0c, 0x4b, 0x68, 0x1e, 0x0c, 0x36, 0x04, 
+0x76, 0x4d, 0x05, 0xd1, 0x3b, 0x2a, 0x03, 0xd3, 0x01, 0x23, 0xdb, 0x02, 
+0x9a, 0x42, 0x01, 0xd9, 0xa8, 0x72, 0xc7, 0xe0, 0x01, 0x23, 0x9b, 0x07, 
+0x08, 0x31, 0x19, 0x43, 0x09, 0x68, 0xc0, 0x46, 0x03, 0x91, 0x03, 0xa9, 
+0x09, 0x88, 0x01, 0x31, 0x09, 0x04, 0x09, 0x0c, 0xf9, 0x81, 0x49, 0x09, 
+0x05, 0x31, 0x09, 0x06, 0x09, 0x0e, 0x6a, 0x4a, 0xc0, 0x46, 0x02, 0x92, 
+0x06, 0x1c, 0x69, 0x48, 0x43, 0x6a, 0xc0, 0x46, 0x01, 0x93, 0x83, 0x6a, 
+0xc0, 0x46, 0x00, 0x93, 0xc2, 0x1d, 0x11, 0x32, 0x80, 0x69, 0x00, 0x03, 
+0x00, 0x0b, 0x92, 0x68, 0x01, 0x23, 0x9b, 0x07, 0x1a, 0x43, 0x12, 0x68, 
+0x90, 0x42, 0x01, 0xd1, 0x30, 0x1c, 0x0d, 0xe0, 0x90, 0x42, 0x05, 0xd9, 
+0x00, 0x9b, 0x18, 0x1a, 0x01, 0x9b, 0xd2, 0x1a, 0x82, 0x18, 0x00, 0xe0, 
+0x12, 0x1a, 0x01, 0x20, 0x09, 0x01, 0x91, 0x42, 0x00, 0xd3, 0x00, 0x20, 
+0x01, 0x28, 0x62, 0xd1, 0xe0, 0x68, 0x00, 0x28, 0x60, 0xd0, 0x04, 0x99, 
+0x08, 0x69, 0x01, 0x30, 0x08, 0x61, 0x02, 0x20, 0xe1, 0x69, 0xc0, 0x46, 
+0x08, 0x60, 0x00, 0xf0, 0x8f, 0xfc, 0x38, 0x63, 0x4e, 0x49, 0xc0, 0x46, 
+0x79, 0x60, 0xe1, 0x69, 0x62, 0x6b, 0x8a, 0x18, 0x23, 0x6b, 0x9a, 0x42, 
+0x00, 0xd9, 0xe1, 0x6a, 0xc0, 0x46, 0x79, 0x62, 0x79, 0x6a, 0x0c, 0x31, 
+0xb9, 0x62, 0x00, 0x21, 0xb9, 0x61, 0x03, 0xa9, 0x49, 0x88, 0xc9, 0x09, 
+0x03, 0xd3, 0x00, 0xe0, 0x78, 0xe0, 0x31, 0x1c, 
+0x00, 0xe0, 0x00, 0x21, 0x39, 0x60, 0x39, 0x68, 0xc0, 0x46, 0x01, 0x60, 
+0xf8, 0x89, 0x41, 0x4e, 0x60, 0x28, 0x04, 0xdc, 0x30, 0x83, 0xf8, 0x89, 
+0xc0, 0x46, 0x70, 0x83, 0x08, 0xe0, 0x60, 0x20, 0x30, 0x83, 0xf9, 0x89, 
+0xb8, 0x6a, 0x42, 0x18, 0x23, 0x6b, 0x9a, 0x42, 0x03, 0xd8, 0x71, 0x83, 
+0x00, 0x21, 0xf9, 0x62, 0x05, 0xe0, 0xe1, 0x6a, 0xc0, 0x46, 0xf9, 0x62, 
+0x21, 0x6b, 0x08, 0x1a, 0x70, 0x83, 0x38, 0x6b, 0x41, 0x68, 0xc0, 0x46, 
+0x79, 0x60, 0x81, 0x68, 0xc0, 0x46, 0xb9, 0x60, 0x01, 0x69, 0xc0, 0x46, 
+0x39, 0x61, 0x40, 0x69, 0xc0, 0x46, 0x78, 0x61, 0x38, 0x1c, 0x00, 0xf0, 
+0x23, 0xf9, 0x38, 0x1c, 0x00, 0xf0, 0x88, 0xf8, 0x00, 0xf0, 0xe0, 0xfa, 
+0xf8, 0x89, 0x71, 0x8b, 0x88, 0x42, 0x04, 0xd1, 0xb9, 0x6a, 0x08, 0x18, 
+0x04, 0xe0, 0x38, 0xe0, 0x32, 0xe0, 0xfa, 0x6a, 0x10, 0x18, 0x40, 0x1a, 
+0x81, 0x07, 0x02, 0xd0, 0x80, 0x08, 0x80, 0x00, 0x04, 0x30, 0x21, 0x6b, 
+0x09, 0x1a, 0x62, 0x6b, 0x91, 0x42, 0x00, 0xd2, 0xe0, 0x6a, 0xc0, 0x46, 
+0xe0, 0x61, 0xe8, 0x7a, 0x00, 0x28, 0x08, 0xd0, 0x00, 0x21, 0xe9, 0x72, 
+0x04, 0x99, 0x08, 0x69, 0x01, 0x38, 0x08, 0x61, 0x38, 0x6b, 0x00, 0xf0, 
+0x5d, 0xfa, 0x18, 0x48, 0x80, 0x6a, 0x80, 0x06, 0x80, 0x0e, 0x01, 0x28, 
+0x0a, 0xd1, 0xe0, 0x69, 0x00, 0x03, 0x00, 0x0b, 0x0c, 0x4c, 0xa1, 0x6a, 
+0x88, 0x42, 0x03, 0xd0, 0x05, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x01, 0x20, 0x40, 0x04, 0x09, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x05, 0xe0, 
+0xa0, 0x68, 0x00, 0x28, 0x01, 0xd0, 0x00, 0xf0, 0x9f, 0xfa, 0xae, 0x72, 
+0xee, 0xe7, 0x00, 0x00, 0xe8, 0x0d, 0x00, 0x80, 0x00, 0x01, 0x11, 0x00, 
+0x00, 0x40, 0x14, 0x40, 0x10, 0x2a, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0, 
+0x98, 0x19, 0x00, 0x80, 0x55, 0x55, 0x55, 0x55, 0x28, 0x03, 0x00, 0x80, 
+0xe8, 0x19, 0x00, 0x80, 0x00, 0x00, 0x10, 0x40, 0x80, 0xb5, 0x07, 0x1c, 
+0x78, 0x6a, 0x40, 0x89, 0xff, 0x21, 0x01, 0x31, 0x01, 0x40, 0x10, 0x48, 
+0x02, 0xd1, 0x81, 0x6c, 0x01, 0x31, 0x81, 0x64, 0x79, 0x6a, 0x49, 0x89, 
+0x49, 0x0b, 0x02, 0xd2, 0x41, 0x6c, 0x01, 0x31, 0x41, 0x64, 0x0b, 0x48, 
+0x41, 0x6a, 0x01, 0x31, 0x41, 0x62, 0x78, 0x6a, 0x39, 0x6b, 0xc0, 0x46, 
+0x48, 0x62, 0x38, 0x6b, 0x00, 0xf0, 0xe2, 0xfb, 0x38, 0x1c, 0x00, 0xf0, 
+0x9f, 0xf8, 0x01, 0x20, 0x04, 0x49, 0xc0, 0x46, 0xc8, 0x72, 0x80, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0x10, 0x2a, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, 
+0x98, 0x19, 0x00, 0x80, 0xf8, 0xb5, 0x07, 0x1c, 0x00, 0x22, 0xf9, 0x1d, 
+0x61, 0x31, 0x0d, 0x1c, 0x78, 0x6a, 0xc0, 0x46, 0x00, 0x90, 0x40, 0x89, 
+0x03, 0x0c, 0x01, 0xd2, 0x40, 0x0a, 0x03, 0xd2, 0x38, 0x1c, 0xff, 0xf7, 
+0xc1, 0xff, 0x54, 0xe0, 0x2b, 0x48, 0x80, 0x6b, 0x00, 0x09, 0x1f, 0xd3, 
+0x08, 0x78, 0x40, 0x08, 0x1c, 0xd2, 0x00, 0x20, 0x43, 0x00, 0xcc, 0x5a, 
+0x27, 0x4e, 0x9e, 0x19, 0x65, 0x23, 0x5b, 0x01, 0xf3, 0x18, 0x9b, 0x8b, 
+0x9c, 0x42, 0x0e, 0xd0, 0xb8, 0x69, 0x39, 0x6b, 0xc0, 0x46, 0x88, 0x61, 
+0xf8, 0x68, 0x39, 0x6b, 0xc0, 0x46, 0xc8, 0x60, 0x38, 0x1c, 0x00, 0xf0, 
+0x13, 0xf9, 0x38, 0x1c, 0x00, 0xf0, 0x60, 0xf8, 0x33, 0xe0, 0x01, 0x30, 
+0x03, 0x28, 0xe3, 0xd3, 0x1a, 0x48, 0x0b, 0x23, 0x1b, 0x02, 0xc1, 0x18, 
+0x09, 0x69, 0x00, 0x29, 0x24, 0xd0, 0x7d, 0x63, 0x00, 0x99, 0x49, 0x89, 
+0x09, 0x0c, 0x1f, 0xd2, 0x00, 0x24, 0x2d, 0x23, 
+0x9b, 0x01, 0xc1, 0x18, 0x89, 0x6b, 0x00, 0x29, 0x18, 0xd0, 0x05, 0x1c, 
+0xfe, 0x1d, 0x2d, 0x36, 0xa2, 0x00, 0x52, 0x19, 0x2d, 0x23, 0x9b, 0x01, 
+0xd2, 0x18, 0x92, 0x6b, 0x38, 0x1c, 0x31, 0x1c, 0x02, 0xf0, 0x7e, 0xfc, 
+0x01, 0x28, 0x0e, 0xd0, 0x01, 0x34, 0xa0, 0x00, 0x40, 0x19, 0x2d, 0x23, 
+0x9b, 0x01, 0xc0, 0x18, 0x80, 0x6b, 0x00, 0x28, 0xea, 0xd1, 0x01, 0xe0, 
+0x01, 0x2a, 0x02, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 0x07, 0xf8, 0xf8, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0x68, 0x1a, 0x00, 0x80, 0xe8, 0x0d, 0x00, 0x80, 
+0x80, 0xb5, 0x07, 0x1c, 0xb8, 0x69, 0x39, 0x6b, 0xc0, 0x46, 0x88, 0x61, 
+0xf8, 0x68, 0x39, 0x6b, 0xc0, 0x46, 0xc8, 0x60, 0x78, 0x6a, 0x40, 0x89, 
+0x01, 0x0c, 0x0e, 0xd2, 0x40, 0x0a, 0x0c, 0xd3, 0x38, 0x68, 0x40, 0x08, 
+0x02, 0xd3, 0x38, 0x1c, 0x02, 0xf0, 0x10, 0xfc, 0x38, 0x1c, 0x00, 0xf0, 
+0xbb, 0xf8, 0x38, 0x1c, 0x00, 0xf0, 0x08, 0xf8, 0x02, 0xe0, 0x38, 0x1c, 
+0xff, 0xf7, 0x44, 0xff, 0x01, 0x20, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x01, 0x21, 0x00, 0x6b, 0x40, 0x6a, 0xc0, 0x46, 0x01, 0x60, 0x70, 0x47, 
+0xb0, 0xb4, 0xc1, 0x1d, 0x39, 0x31, 0x09, 0x8b, 0x89, 0x08, 0x09, 0x04, 
+0x09, 0x0c, 0x84, 0x6a, 0xc2, 0x1d, 0x61, 0x32, 0x00, 0x20, 0x00, 0x29, 
+0x0c, 0xdd, 0x87, 0x00, 0x3d, 0x19, 0x01, 0x23, 0x9b, 0x07, 0x2b, 0x43, 
+0x1b, 0x68, 0xc0, 0x46, 0xd3, 0x51, 0x01, 0x30, 0x00, 0x04, 0x00, 0x0c, 
+0x88, 0x42, 0xf2, 0xdb, 0xb0, 0xbc, 0x70, 0x47, 0xf0, 0xb5, 0xa0, 0xb0, 
+0x01, 0x23, 0x9b, 0x07, 0xc1, 0x1d, 0x21, 0x31, 0x19, 0x43, 0x09, 0x68, 
+0xc0, 0x46, 0x0b, 0x91, 0xc1, 0x1d, 0x53, 0x31, 0x19, 0x43, 0x1f, 0x91, 
+0x09, 0x68, 0x01, 0xaf, 0xfa, 0x1d, 0x39, 0x32, 0x1e, 0x92, 0x17, 0xab, 
+0x59, 0x80, 0x3a, 0x49, 0x01, 0x23, 0x9b, 0x07, 0x0a, 0x6a, 0x13, 0x43, 
+0xcc, 0x1d, 0x11, 0x34, 0x89, 0x69, 0x09, 0x03, 0x09, 0x0b, 0x22, 0x69, 
+0xe5, 0x68, 0xc0, 0x46, 0x1d, 0x95, 0xfc, 0x1d, 0x39, 0x34, 0x64, 0x8b, 
+0x64, 0x09, 0x05, 0x34, 0x24, 0x06, 0x24, 0x0e, 0x1c, 0x94, 0x56, 0x1a, 
+0x1b, 0x96, 0x1c, 0x9c, 0x2e, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x01, 0x26, 
+0x1d, 0x9d, 0x1a, 0x68, 0x91, 0x42, 0x01, 0xd1, 0x32, 0x1c, 0x0b, 0xe0, 
+0x91, 0x42, 0x03, 0xd9, 0x52, 0x1b, 0x1b, 0x9e, 0xb5, 0x18, 0x00, 0xe0, 
+0x55, 0x1a, 0x01, 0x22, 0x24, 0x01, 0xac, 0x42, 0x00, 0xd3, 0x00, 0x22, 
+0x01, 0x2a, 0xe6, 0xd1, 0x91, 0x07, 0x01, 0x43, 0x09, 0x68, 0xc0, 0x46, 
+0x39, 0x60, 0x93, 0x07, 0x01, 0x1d, 0x19, 0x43, 0x09, 0x68, 0xc0, 0x46, 
+0x79, 0x60, 0xc1, 0x1d, 0x01, 0x31, 0x19, 0x43, 0x09, 0x68, 0xc0, 0x46, 
+0xb9, 0x60, 0x1f, 0x99, 0x09, 0x68, 0x1e, 0x9a, 0xc0, 0x46, 0x51, 0x83, 
+0xc1, 0x1d, 0x1d, 0x31, 0x19, 0x43, 0x09, 0x68, 0xc0, 0x46, 0x38, 0x63, 
+0x79, 0x62, 0xc1, 0x1d, 0x11, 0x31, 0x19, 0x43, 0x09, 0x68, 0xc0, 0x46, 
+0xb9, 0x61, 0xc1, 0x1d, 0x05, 0x31, 0x19, 0x43, 0x09, 0x68, 0xc0, 0x46, 
+0xf9, 0x60, 0xc1, 0x1d, 0x17, 0x31, 0x19, 0x43, 0x09, 0x68, 0xc0, 0x46, 
+0xf9, 0x83, 0x0e, 0x30, 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0xf8, 0x81, 
+0x38, 0x68, 0x40, 0x08, 0x02, 0xd3, 0x38, 0x1c, 0x02, 0xf0, 0x60, 0xfb, 
+0x38, 0x1c, 0x00, 0xf0, 0x0b, 0xf8, 0x38, 0x1c, 0xff, 0xf7, 0x58, 0xff, 
+0x20, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x28, 0x03, 0x00, 0x80, 
+0x55, 0x55, 0x55, 0x55, 0xf8, 0xb5, 0x07, 0x1c, 
+0xf8, 0x1d, 0x39, 0x30, 0x41, 0x8b, 0x38, 0x4a, 0x91, 0x42, 0x00, 0xdd, 
+0x42, 0x83, 0x42, 0x8b, 0xc0, 0x46, 0x00, 0x92, 0x01, 0x20, 0x3a, 0x1d, 
+0x06, 0xca, 0xbb, 0x6a, 0x02, 0xf0, 0x12, 0xff, 0x32, 0x4a, 0xc0, 0x46, 
+0x00, 0x92, 0x32, 0x4e, 0x30, 0x6a, 0x32, 0x4c, 0xe1, 0x6d, 0x41, 0x18, 
+0x38, 0x6b, 0xc3, 0x1d, 0x05, 0x33, 0x01, 0x20, 0x72, 0x6a, 0x02, 0xf0, 
+0xff, 0xfe, 0xe0, 0x6d, 0x18, 0x30, 0xb1, 0x6a, 0x81, 0x42, 0x00, 0xd8, 
+0x00, 0x20, 0xe0, 0x65, 0x17, 0x23, 0xdb, 0x01, 0x20, 0x1c, 0xe1, 0x6d, 
+0xe4, 0x18, 0xe2, 0x6b, 0x92, 0x00, 0x27, 0x4b, 0xc0, 0x46, 0x99, 0x50, 
+0x26, 0x4d, 0xa8, 0x6b, 0x41, 0x08, 0x05, 0xd3, 0x40, 0x08, 0x40, 0x00, 
+0xa8, 0x63, 0x01, 0x20, 0x01, 0xf0, 0xd8, 0xff, 0x22, 0x4a, 0x1f, 0x48, 
+0x29, 0x7b, 0x00, 0x29, 0x02, 0xd0, 0x69, 0x7b, 0x00, 0x29, 0x00, 0xd1, 
+0x1f, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x05, 0x1c, 0xe0, 0x6b, 0x80, 0x00, 
+0x19, 0x4b, 0xc3, 0x18, 0x05, 0xce, 0xc1, 0x1d, 0x11, 0x31, 0x01, 0x20, 
+0x02, 0xf0, 0xce, 0xfe, 0xe0, 0x6b, 0x01, 0x30, 0xe0, 0x63, 0x17, 0x28, 
+0x01, 0xd3, 0x00, 0x20, 0xe0, 0x63, 0x00, 0x20, 0x39, 0x6b, 0xc0, 0x46, 
+0x08, 0x65, 0x78, 0x6a, 0x39, 0x6b, 0xc0, 0x46, 0x48, 0x62, 0x33, 0x23, 
+0x9b, 0x01, 0xe8, 0x18, 0x41, 0x68, 0x00, 0x29, 0x03, 0xd1, 0x39, 0x6b, 
+0xc0, 0x46, 0x41, 0x60, 0x04, 0xe0, 0x39, 0x6b, 0x82, 0x68, 0xc0, 0x46, 
+0x11, 0x65, 0x39, 0x6b, 0xc0, 0x46, 0x81, 0x60, 0xf8, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x00, 0xea, 0x05, 0x00, 0x00, 0x18, 0x00, 0x14, 0x02, 
+0xf8, 0x28, 0x00, 0x80, 0xe8, 0x0d, 0x00, 0x80, 0x44, 0x82, 0x20, 0x40, 
+0x68, 0x0e, 0x00, 0x80, 0x04, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00, 0x03, 
+0xf0, 0xb5, 0x11, 0x4e, 0xff, 0x25, 0x01, 0x35, 0x10, 0x4f, 0xc0, 0x46, 
+0x35, 0x60, 0x38, 0x69, 0x01, 0x38, 0x38, 0x61, 0x7c, 0x68, 0x00, 0x2c, 
+0x10, 0xd0, 0x20, 0x6d, 0xc0, 0x46, 0x78, 0x60, 0x20, 0x1c, 0x00, 0xf0, 
+0x21, 0xf8, 0x20, 0x1c, 0x00, 0xf0, 0x04, 0xfa, 0x08, 0x48, 0x80, 0x6a, 
+0x00, 0x0c, 0x00, 0x07, 0xe9, 0xd1, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x05, 0x48, 0xc1, 0x79, 0x01, 0x31, 0xc1, 0x71, 0xf7, 0xe7, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0xb0, 0xa8, 0x1a, 0x00, 0x80, 0x00, 0x00, 0x10, 0x40, 
+0xa0, 0x82, 0x20, 0x40, 0x01, 0x20, 0x80, 0x03, 0x01, 0x49, 0xc0, 0x46, 
+0x08, 0x60, 0x70, 0x47, 0x00, 0x00, 0x00, 0xb0, 0x90, 0xb5, 0x07, 0x1c, 
+0x38, 0x68, 0xc0, 0x08, 0x09, 0xd3, 0x1d, 0x48, 0x01, 0x6a, 0x01, 0x39, 
+0x01, 0x62, 0x20, 0x30, 0x00, 0x79, 0x00, 0x28, 0x01, 0xd0, 0xfe, 0xf7, 
+0x09, 0xfe, 0x01, 0x23, 0x9b, 0x07, 0xf8, 0x1d, 0x1d, 0x30, 0x18, 0x43, 
+0x00, 0x68, 0x16, 0x4c, 0x21, 0x6a, 0x81, 0x42, 0x21, 0xd1, 0x01, 0x1c, 
+0x19, 0x43, 0x09, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x01, 0x29, 0x1a, 0xd1, 
+0x00, 0xf0, 0x22, 0xf8, 0x20, 0x62, 0x20, 0x6a, 0xe1, 0x69, 0x88, 0x42, 
+0x05, 0xd0, 0x01, 0x21, 0x89, 0x07, 0x01, 0x43, 0x09, 0x68, 0x09, 0x04, 
+0xf2, 0xd0, 0x51, 0x21, 0x89, 0x03, 0x22, 0x6a, 0xe3, 0x6a, 0x9a, 0x42, 
+0x02, 0xd1, 0x20, 0x6b, 0x62, 0x6b, 0x80, 0x1a, 0x04, 0x38, 0xc8, 0x60, 
+0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x20, 0x79, 0x6a, 0xc0, 0x46, 
+0x08, 0x60, 0xf7, 0xe7, 0xec, 0x05, 0x00, 0x80, 0x68, 0x1a, 0x00, 0x80, 
+0x01, 0x23, 0x9b, 0x07, 0xc1, 0x1d, 0x01, 0x31, 
+0x19, 0x43, 0x09, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x08, 0x18, 0x0d, 0x30, 
+0x81, 0x07, 0x02, 0xd0, 0x80, 0x08, 0x80, 0x00, 0x04, 0x30, 0x04, 0x49, 
+0x4a, 0x6b, 0x12, 0x18, 0x0b, 0x6b, 0x9a, 0x42, 0x00, 0xd9, 0xc8, 0x6a, 
+0x70, 0x47, 0x00, 0x00, 0x68, 0x1a, 0x00, 0x80, 0x00, 0xb5, 0x04, 0x48, 
+0x80, 0x68, 0x10, 0x28, 0x01, 0xd3, 0x00, 0xf0, 0x05, 0xf8, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x00, 0x68, 0x1a, 0x00, 0x80, 0x88, 0xb5, 0x0c, 0x4f, 
+0x38, 0x78, 0x00, 0x28, 0x11, 0xd1, 0x0b, 0x49, 0x10, 0x20, 0x02, 0xf0, 
+0xfb, 0xfd, 0x00, 0x28, 0x0b, 0xd0, 0x01, 0x20, 0x38, 0x70, 0x08, 0x4a, 
+0xc0, 0x46, 0x00, 0x92, 0x07, 0x48, 0x42, 0x68, 0x07, 0x4b, 0x01, 0x68, 
+0x00, 0x20, 0x02, 0xf0, 0xe5, 0xfd, 0x88, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x78, 0x1a, 0x00, 0x80, 0x69, 0x2c, 0xff, 0xff, 0x10, 0x00, 0x35, 0x02, 
+0xf8, 0x28, 0x00, 0x80, 0x44, 0x80, 0x20, 0x40, 0x90, 0xb5, 0x01, 0x20, 
+0x40, 0x02, 0x10, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x0f, 0x4f, 0x10, 0x21, 
+0xf8, 0x1d, 0x3d, 0x30, 0x02, 0xf0, 0x52, 0xfc, 0x19, 0x23, 0xdb, 0x01, 
+0xfc, 0x18, 0xa0, 0x68, 0x00, 0x28, 0x01, 0xd0, 0x00, 0xf0, 0x14, 0xf8, 
+0x00, 0x20, 0xc9, 0x23, 0x1b, 0x01, 0xf9, 0x18, 0x08, 0x70, 0xa0, 0x68, 
+0x10, 0x28, 0x04, 0xd3, 0x01, 0x20, 0xbb, 0x23, 0x1b, 0x01, 0xf9, 0x18, 
+0x48, 0x72, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0xb0, 
+0xe8, 0x0d, 0x00, 0x80, 0xf8, 0xb5, 0x37, 0x48, 0x19, 0x23, 0xdb, 0x01, 
+0xc1, 0x18, 0x89, 0x68, 0x35, 0x4d, 0x10, 0x29, 0x00, 0xd9, 0x10, 0x21, 
+0x29, 0x62, 0x32, 0x48, 0xc1, 0x6c, 0x00, 0x6e, 0x81, 0x42, 0x07, 0xd9, 
+0x08, 0x1a, 0x07, 0x09, 0x00, 0x24, 0x28, 0x6a, 0xb8, 0x42, 0x12, 0xd2, 
+0x07, 0x1c, 0x10, 0xe0, 0x81, 0x42, 0x2a, 0xd2, 0x2c, 0x4a, 0x52, 0x6b, 
+0x10, 0x1a, 0x07, 0x09, 0x28, 0x6a, 0xb8, 0x42, 0x05, 0xd9, 0x0c, 0x09, 
+0x39, 0x19, 0x88, 0x42, 0x03, 0xd2, 0xc4, 0x1b, 0x01, 0xe0, 0x00, 0x24, 
+0x07, 0x1c, 0x3e, 0x19, 0x30, 0x01, 0x25, 0x49, 0x02, 0xf0, 0x8a, 0xfd, 
+0x00, 0x28, 0x3d, 0xd0, 0x23, 0x48, 0x00, 0x2c, 0x1a, 0xd1, 0x1e, 0x49, 
+0x3a, 0x01, 0x2f, 0x62, 0x09, 0x6e, 0x8c, 0x18, 0x1d, 0x4d, 0x6b, 0x6b, 
+0xa3, 0x42, 0x00, 0xd8, 0xe4, 0x1a, 0x1e, 0x4b, 0x1a, 0x43, 0x00, 0x92, 
+0xea, 0x6a, 0x51, 0x18, 0x2a, 0x6b, 0x03, 0x1c, 0x20, 0xe0, 0x1b, 0x48, 
+0x01, 0x6b, 0x01, 0x31, 0x01, 0x63, 0x00, 0x20, 0x28, 0x62, 0xf8, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0x10, 0x49, 0x24, 0x01, 0x3f, 0x01, 0x11, 0x22, 
+0x52, 0x05, 0x3a, 0x43, 0x2e, 0x62, 0x00, 0x92, 0x0e, 0x4d, 0xea, 0x6a, 
+0x09, 0x6e, 0x51, 0x18, 0x03, 0x1c, 0x06, 0x1c, 0x00, 0x20, 0x2a, 0x6b, 
+0x02, 0xf0, 0x50, 0xfd, 0x0c, 0x4a, 0x22, 0x43, 0x00, 0x92, 0xbb, 0x19, 
+0xe9, 0x6a, 0x2a, 0x6b, 0x00, 0x20, 0x02, 0xf0, 0x47, 0xfd, 0x03, 0x48, 
+0xc0, 0x46, 0x04, 0x66, 0x00, 0xf0, 0x10, 0xf8, 0x01, 0x20, 0xda, 0xe7, 
+0xe8, 0x0d, 0x00, 0x80, 0xa8, 0x1a, 0x00, 0x80, 0xf8, 0x28, 0x00, 0x80, 
+0xd1, 0x2d, 0xff, 0xff, 0x44, 0x80, 0x20, 0x40, 0x00, 0x00, 0x36, 0x02, 
+0xa0, 0x82, 0x20, 0x40, 0x04, 0x48, 0x01, 0x6e, 0x04, 0x4a, 0x80, 0x30, 
+0xd1, 0x60, 0x02, 0x23, 0x81, 0x6b, 0x19, 0x43, 0x81, 0x63, 0x70, 0x47, 
+0xe8, 0x0d, 0x00, 0x80, 0x3c, 0xef, 0x20, 0x40, 0xf0, 0xb5, 0x84, 0xb0, 
+0x01, 0x20, 0x80, 0x02, 0x1c, 0x49, 0xc0, 0x46, 
+0x08, 0x60, 0x00, 0x27, 0x1b, 0x4e, 0x33, 0x23, 0x9b, 0x01, 0xf5, 0x18, 
+0x28, 0x6a, 0x00, 0x28, 0x1d, 0xd9, 0x19, 0x4c, 0x68, 0x46, 0x10, 0x21, 
+0x02, 0xf0, 0x96, 0xfb, 0x68, 0x46, 0x00, 0xf0, 0x33, 0xf8, 0x00, 0x28, 
+0x04, 0xd0, 0x15, 0x49, 0x48, 0x69, 0x01, 0x30, 0x48, 0x61, 0x0a, 0xe0, 
+0x13, 0x49, 0x60, 0x7b, 0x01, 0x30, 0x60, 0x73, 0x88, 0x79, 0x01, 0x30, 
+0x88, 0x71, 0x11, 0x48, 0x00, 0x68, 0x02, 0xf0, 0x6b, 0xf9, 0x28, 0x6a, 
+0x01, 0x37, 0xb8, 0x42, 0xe2, 0xd8, 0xbb, 0x23, 0x1b, 0x01, 0xf0, 0x18, 
+0x81, 0x7a, 0x00, 0x29, 0x03, 0xd0, 0x00, 0x21, 0x81, 0x72, 0xff, 0xf7, 
+0x1d, 0xfb, 0xff, 0xf7, 0xe3, 0xfe, 0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xe8, 0x0d, 0x00, 0x80, 
+0xb0, 0x82, 0x20, 0x40, 0x08, 0x83, 0x20, 0x40, 0xa0, 0x82, 0x20, 0x40, 
+0xd8, 0x03, 0x00, 0x80, 0x90, 0xb4, 0x17, 0x4f, 0x19, 0x23, 0xdb, 0x01, 
+0xf9, 0x18, 0x00, 0x22, 0x8b, 0x68, 0x00, 0x2b, 0x23, 0xd0, 0x01, 0x3b, 
+0x8b, 0x60, 0x33, 0x23, 0x9b, 0x01, 0xff, 0x18, 0x7b, 0x69, 0x1c, 0x6d, 
+0xc0, 0x46, 0x7c, 0x61, 0x04, 0x68, 0xc0, 0x46, 0x5c, 0x60, 0x44, 0x68, 
+0xc0, 0x46, 0x9c, 0x60, 0x84, 0x68, 0xc0, 0x46, 0x1c, 0x61, 0xc0, 0x68, 
+0xc0, 0x46, 0x58, 0x61, 0x1a, 0x65, 0xc8, 0x68, 0x42, 0x1c, 0xca, 0x60, 
+0x00, 0x28, 0x03, 0xd0, 0xf8, 0x69, 0xc0, 0x46, 0x03, 0x65, 0x00, 0xe0, 
+0xbb, 0x61, 0xfb, 0x61, 0x18, 0x1c, 0x90, 0xbc, 0x70, 0x47, 0x10, 0x1c, 
+0xfb, 0xe7, 0x00, 0x00, 0xe8, 0x0d, 0x00, 0x80, 0x0a, 0x4a, 0x33, 0x23, 
+0x9b, 0x01, 0xd1, 0x18, 0x88, 0x69, 0x19, 0x23, 0xdb, 0x01, 0xd2, 0x18, 
+0xd3, 0x68, 0x00, 0x2b, 0x06, 0xd0, 0x01, 0x3b, 0xd3, 0x60, 0x8a, 0x69, 
+0x12, 0x6d, 0xc0, 0x46, 0x8a, 0x61, 0x70, 0x47, 0x00, 0x21, 0xd1, 0x60, 
+0xfb, 0xe7, 0x00, 0x00, 0xe8, 0x0d, 0x00, 0x80, 0x06, 0x4a, 0xd1, 0x68, 
+0x4b, 0x1c, 0xd3, 0x60, 0x40, 0x32, 0x00, 0x29, 0x01, 0xd0, 0x91, 0x69, 
+0x00, 0xe0, 0x00, 0x21, 0x01, 0x65, 0x90, 0x61, 0x70, 0x47, 0x00, 0x00, 
+0x68, 0x1a, 0x00, 0x80, 0x06, 0x4a, 0x91, 0x68, 0x4b, 0x1c, 0x93, 0x60, 
+0x40, 0x32, 0x00, 0x29, 0x01, 0xd0, 0x51, 0x69, 0x00, 0xe0, 0x00, 0x21, 
+0x01, 0x65, 0x50, 0x61, 0x70, 0x47, 0x00, 0x00, 0x68, 0x1a, 0x00, 0x80, 
+0x90, 0xb4, 0x00, 0x21, 0x0f, 0x4a, 0x97, 0x89, 0x92, 0x6a, 0x4b, 0x00, 
+0x1b, 0x18, 0x9b, 0x8a, 0x00, 0x2b, 0x12, 0xd0, 0xbb, 0x42, 0x10, 0xdc, 
+0x1c, 0x1c, 0x58, 0x23, 0x63, 0x43, 0xd3, 0x18, 0xdc, 0x1f, 0x49, 0x3c, 
+0x01, 0x23, 0x9b, 0x07, 0x23, 0x43, 0x1b, 0x68, 0x1b, 0x06, 0x1b, 0x0e, 
+0x03, 0x2b, 0x02, 0xd0, 0x00, 0x20, 0x90, 0xbc, 0x70, 0x47, 0x01, 0x31, 
+0x04, 0x29, 0xe4, 0xd3, 0x01, 0x20, 0xf8, 0xe7, 0xc8, 0x29, 0x00, 0x80, 
+0xf7, 0xb5, 0x86, 0xb0, 0x3d, 0x4a, 0x07, 0x1c, 0xd1, 0x69, 0x8f, 0x40, 
+0x03, 0x1c, 0x14, 0x6a, 0xe3, 0x40, 0x5f, 0x40, 0x07, 0x9e, 0x8e, 0x40, 
+0x77, 0x40, 0xcf, 0x40, 0x94, 0x69, 0xc0, 0x46, 0x05, 0x94, 0x03, 0x1c, 
+0xa3, 0x40, 0x00, 0x25, 0x14, 0x69, 0xc0, 0x46, 0x04, 0x94, 0x00, 0x2c, 
+0x5d, 0xd9, 0x1c, 0x1c, 0x32, 0x4e, 0x26, 0x43, 0x94, 0x69, 0xe6, 0x40, 
+0x33, 0x1c, 0x03, 0x96, 0x53, 0x6a, 0xc0, 0x46, 0x02, 0x93, 0xd2, 0x6a, 
+0xc0, 0x46, 0x01, 0x92, 0xbb, 0x00, 0x02, 0x9a, 0xd2, 0x58, 0x13, 0x1c, 
+0x05, 0x9c, 0xe3, 0x40, 0x03, 0x9c, 0xa3, 0x42, 
+0x3e, 0xd1, 0x8a, 0x40, 0xca, 0x40, 0x14, 0x1c, 0x63, 0x00, 0x1b, 0x19, 
+0x5b, 0x01, 0x01, 0x9a, 0xd2, 0x18, 0x01, 0x23, 0x9b, 0x07, 0xd6, 0x1d, 
+0x01, 0x36, 0x33, 0x43, 0x1b, 0x68, 0x1b, 0x06, 0x1b, 0x0e, 0x03, 0x2b, 
+0x2c, 0xd1, 0x01, 0x23, 0x9b, 0x07, 0xd6, 0x1d, 0x51, 0x36, 0x33, 0x43, 
+0x1b, 0x68, 0x07, 0x9e, 0x1e, 0x40, 0x00, 0x96, 0x01, 0x23, 0x9b, 0x07, 
+0xd6, 0x1d, 0x49, 0x36, 0x33, 0x43, 0x1b, 0x68, 0x83, 0x42, 0x1b, 0xd1, 
+0x01, 0x23, 0x9b, 0x07, 0xd6, 0x1d, 0x4d, 0x36, 0x33, 0x43, 0x1b, 0x68, 
+0x00, 0x9e, 0xb3, 0x42, 0x12, 0xd1, 0x01, 0x23, 0x9b, 0x07, 0x1a, 0x43, 
+0x12, 0x68, 0x12, 0x04, 0x12, 0x0c, 0x08, 0x9b, 0x32, 0x2b, 0x04, 0xd1, 
+0x02, 0x2a, 0x07, 0xd1, 0x20, 0x04, 0x00, 0x14, 0x0f, 0xe0, 0x08, 0x9b, 
+0x33, 0x2b, 0x01, 0xd1, 0x01, 0x2a, 0xf7, 0xd0, 0x04, 0x9a, 0x01, 0x37, 
+0x97, 0x42, 0x00, 0xd3, 0x00, 0x27, 0x04, 0x9a, 0x01, 0x35, 0xaa, 0x42, 
+0xae, 0xd8, 0x00, 0x20, 0xc0, 0x43, 0x09, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x00, 0xc8, 0x29, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 
+0xf0, 0xb5, 0x27, 0x4d, 0x68, 0x69, 0x00, 0x28, 0x06, 0xd0, 0x26, 0x48, 
+0x00, 0x68, 0x02, 0xf0, 0x31, 0xf8, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x23, 0x4c, 0x00, 0x26, 0xa0, 0x68, 0x23, 0x4f, 0x00, 0x28, 0x16, 0xd0, 
+0x0f, 0xe0, 0x28, 0x6a, 0x02, 0x28, 0x02, 0xd3, 0x01, 0x20, 0x38, 0x71, 
+0x0f, 0xe0, 0xa6, 0x60, 0xfd, 0xf7, 0x08, 0xff, 0x00, 0x28, 0xea, 0xd1, 
+0x28, 0x6a, 0x02, 0x28, 0x01, 0xd3, 0x01, 0x20, 0x38, 0x71, 0xe8, 0x68, 
+0x00, 0x28, 0x02, 0xd0, 0x38, 0x79, 0x00, 0x28, 0xe9, 0xd0, 0x68, 0x68, 
+0x00, 0x28, 0x1b, 0xd0, 0x01, 0x20, 0xa0, 0x60, 0xfe, 0xf7, 0xd2, 0xfb, 
+0x00, 0x28, 0xd6, 0xd1, 0x68, 0x68, 0x00, 0x28, 0xf6, 0xd1, 0x11, 0xe0, 
+0x00, 0x28, 0xd0, 0xd1, 0x28, 0x6a, 0x02, 0x28, 0x02, 0xd3, 0x01, 0x20, 
+0x38, 0x71, 0xca, 0xe7, 0xa6, 0x60, 0xfd, 0xf7, 0xe3, 0xfe, 0x00, 0x28, 
+0xc5, 0xd1, 0x28, 0x6a, 0x02, 0x28, 0x01, 0xd3, 0x01, 0x20, 0x38, 0x71, 
+0xe8, 0x68, 0x00, 0x28, 0xbd, 0xd0, 0x38, 0x79, 0x00, 0x28, 0xe7, 0xd0, 
+0xb9, 0xe7, 0x00, 0x00, 0xec, 0x05, 0x00, 0x80, 0xdc, 0x03, 0x00, 0x80, 
+0xc8, 0x29, 0x00, 0x80, 0x0c, 0x06, 0x00, 0x80, 0x70, 0x47, 0x00, 0x00, 
+0x70, 0x47, 0x00, 0x00, 0x70, 0x47, 0x00, 0x00, 0x90, 0xb5, 0x40, 0x20, 
+0x1d, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x01, 0xf0, 0x9f, 0xfc, 0x03, 0x23, 
+0x1b, 0x07, 0x41, 0x68, 0x19, 0x40, 0x0c, 0x0f, 0x61, 0x01, 0x09, 0x1b, 
+0x89, 0x00, 0x18, 0x4a, 0x8f, 0x18, 0x01, 0x21, 0x39, 0x80, 0x81, 0x6a, 
+0xc0, 0x46, 0x79, 0x65, 0x41, 0x6a, 0xc0, 0x46, 0x79, 0x67, 0xb9, 0x6c, 
+0xfa, 0x6c, 0x89, 0x18, 0xb9, 0x64, 0x00, 0x21, 0xf9, 0x64, 0xba, 0x6b, 
+0x3b, 0x6d, 0xd2, 0x18, 0xba, 0x63, 0x39, 0x65, 0x42, 0x6a, 0x20, 0x32, 
+0x51, 0x71, 0x79, 0x6d, 0x7a, 0x6f, 0xd2, 0x6d, 0xc0, 0x46, 0x11, 0x60, 
+0xfd, 0xf7, 0x10, 0xf8, 0x20, 0x01, 0x09, 0x49, 0x40, 0x18, 0x19, 0x23, 
+0xdb, 0x01, 0xc0, 0x18, 0x41, 0x6b, 0x01, 0x39, 0x41, 0x63, 0x78, 0x6f, 
+0x01, 0xf0, 0xc8, 0xfb, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0xb0, 0xc8, 0x2a, 0x00, 0x80, 0x1c, 0x1c, 0x00, 0x80, 
+0xf0, 0xb5, 0x40, 0x20, 0x12, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x01, 0xf0, 
+0x5b, 0xfc, 0x07, 0x1c, 0x40, 0x68, 0x03, 0x23, 
+0x1b, 0x07, 0x18, 0x40, 0x06, 0x0f, 0x70, 0x01, 0x80, 0x1b, 0x80, 0x00, 
+0x0c, 0x49, 0x44, 0x18, 0xb8, 0x6a, 0xc0, 0x46, 0x60, 0x65, 0x78, 0x6a, 
+0xc0, 0x46, 0x60, 0x67, 0x80, 0x6f, 0x05, 0x1d, 0xe5, 0x63, 0xb9, 0x69, 
+0x28, 0x1c, 0x02, 0xf0, 0x8f, 0xf9, 0x38, 0x1c, 0x21, 0x1c, 0x32, 0x1c, 
+0x2b, 0x1c, 0x00, 0xf0, 0x20, 0xf8, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x00, 0x00, 0x00, 0xb0, 0xc8, 0x2a, 0x00, 0x80, 0xf0, 0xb5, 0x4b, 0x6f, 
+0x9b, 0x6f, 0x1f, 0x1d, 0xcf, 0x63, 0x05, 0x68, 0x00, 0x23, 0x84, 0x69, 
+0xa4, 0x08, 0x08, 0xd0, 0x9c, 0x00, 0x2e, 0x59, 0xc0, 0x46, 0x3e, 0x51, 
+0x84, 0x69, 0xa4, 0x08, 0x01, 0x33, 0x9c, 0x42, 0xf6, 0xd8, 0x3b, 0x1c, 
+0x00, 0xf0, 0x03, 0xf8, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xff, 0xb5, 
+0x81, 0xb0, 0x04, 0x1c, 0x1d, 0x1c, 0x0f, 0x1c, 0x46, 0x48, 0x01, 0x69, 
+0x01, 0x31, 0x01, 0x61, 0xf9, 0x1d, 0x51, 0x31, 0xbd, 0x65, 0x00, 0x91, 
+0x20, 0x1c, 0xfd, 0xf7, 0xa3, 0xfc, 0xf8, 0x6d, 0x40, 0x09, 0x36, 0xd2, 
+0xb8, 0x6d, 0x06, 0x7b, 0x43, 0x7b, 0x1b, 0x02, 0x1e, 0x43, 0x17, 0x21, 
+0x49, 0x02, 0x01, 0x73, 0x0b, 0x0a, 0x43, 0x73, 0x00, 0x99, 0x20, 0x1c, 
+0xfd, 0xf7, 0x92, 0xfc, 0xb8, 0x6d, 0xc0, 0x46, 0x06, 0x73, 0x33, 0x0a, 
+0x43, 0x73, 0xf8, 0x6d, 0x40, 0x09, 0x20, 0xd2, 0x60, 0x68, 0x01, 0x04, 
+0x09, 0x0c, 0x03, 0x98, 0x01, 0xf0, 0xce, 0xfc, 0x60, 0x68, 0x32, 0x4b, 
+0x18, 0x43, 0x60, 0x60, 0x20, 0x1c, 0x01, 0xf0, 0x37, 0xfd, 0x00, 0x25, 
+0x7d, 0x60, 0xbd, 0x60, 0x3d, 0x64, 0x7d, 0x64, 0x20, 0x1c, 0xfc, 0xf7, 
+0x77, 0xff, 0x38, 0x88, 0x40, 0x23, 0x18, 0x43, 0x38, 0x80, 0x7d, 0x62, 
+0x29, 0x48, 0xc0, 0x46, 0xb8, 0x62, 0x38, 0x1c, 0x00, 0xf0, 0xa0, 0xfb, 
+0x44, 0xe0, 0x20, 0x68, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x38, 0x18, 0x43, 
+0x00, 0x68, 0xc0, 0x46, 0x78, 0x64, 0x60, 0x68, 0x02, 0x04, 0x12, 0x0c, 
+0x78, 0x6e, 0x01, 0x26, 0xc1, 0x1d, 0x0d, 0x31, 0x8a, 0x42, 0x02, 0xd2, 
+0x3a, 0x64, 0x08, 0x1c, 0x0e, 0xe0, 0x41, 0x19, 0x89, 0x89, 0xf0, 0x23, 
+0x19, 0x40, 0x09, 0x09, 0x89, 0x00, 0x40, 0x18, 0xf8, 0x60, 0xf9, 0x61, 
+0x61, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x81, 0x42, 0x16, 0xd2, 0x39, 0x64, 
+0x63, 0x68, 0x19, 0x04, 0x09, 0x0c, 0x40, 0x1a, 0x03, 0x30, 0x80, 0x08, 
+0x82, 0x00, 0xa0, 0x61, 0x20, 0x68, 0x09, 0x18, 0x9b, 0x18, 0x63, 0x60, 
+0xc3, 0x1f, 0x05, 0x3b, 0x38, 0x1c, 0x00, 0xf0, 0xb6, 0xfa, 0x7e, 0x80, 
+0x20, 0x1c, 0x00, 0xf0, 0xbf, 0xfb, 0x0b, 0xe0, 0xb9, 0x68, 0x08, 0x1a, 
+0x00, 0x25, 0x78, 0x62, 0xbd, 0x62, 0x38, 0x1c, 0x00, 0xf0, 0x3c, 0xfc, 
+0x20, 0x1c, 0x39, 0x1c, 0x00, 0xf0, 0x64, 0xf8, 0x05, 0xb0, 0xf0, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0x78, 0x2a, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 
+0x01, 0x00, 0x00, 0xc0, 0xf0, 0xb5, 0x04, 0x1c, 0x0f, 0x1c, 0x38, 0x6c, 
+0xf9, 0x6b, 0x0d, 0x18, 0x21, 0x68, 0x41, 0x18, 0x00, 0x20, 0xa2, 0x69, 
+0x00, 0x2a, 0x0b, 0xd9, 0x82, 0x00, 0x56, 0x18, 0x01, 0x23, 0x9b, 0x07, 
+0x33, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0xab, 0x50, 0xa2, 0x69, 0x01, 0x30, 
+0x82, 0x42, 0xf3, 0xd8, 0x78, 0x6e, 0xf9, 0x6b, 0x09, 0x18, 0x89, 0x89, 
+0xf0, 0x23, 0x19, 0x40, 0x09, 0x09, 0x89, 0x00, 0x40, 0x18, 0xf8, 0x60, 
+0xf9, 0x61, 0x20, 0x68, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x38, 0x18, 0x43, 
+0x01, 0x68, 0x78, 0x6c, 0xfc, 0xf7, 0xdb, 0xff, 
+0x78, 0x64, 0x60, 0x68, 0x01, 0x04, 0x09, 0x0c, 0xf8, 0x68, 0x81, 0x42, 
+0x19, 0xd2, 0x39, 0x64, 0x63, 0x68, 0x19, 0x04, 0x09, 0x0c, 0x40, 0x1a, 
+0x03, 0x30, 0x80, 0x08, 0x82, 0x00, 0xa0, 0x61, 0x20, 0x68, 0x09, 0x18, 
+0x9b, 0x18, 0x63, 0x60, 0xc3, 0x1f, 0x05, 0x3b, 0x38, 0x1c, 0x00, 0xf0, 
+0x56, 0xfa, 0x01, 0x20, 0x78, 0x80, 0x20, 0x1c, 0x00, 0xf0, 0x5e, 0xfb, 
+0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xb9, 0x68, 0x08, 0x1a, 0x78, 0x62, 
+0x00, 0x20, 0xb8, 0x62, 0x38, 0x1c, 0x00, 0xf0, 0xd9, 0xfb, 0x20, 0x1c, 
+0x39, 0x1c, 0x00, 0xf0, 0x01, 0xf8, 0xef, 0xe7, 0xf0, 0xb5, 0x84, 0xb0, 
+0x04, 0x1c, 0x0f, 0x1c, 0x8e, 0x48, 0x41, 0x69, 0x01, 0x31, 0x41, 0x61, 
+0x03, 0x20, 0x00, 0x07, 0x61, 0x68, 0x08, 0x40, 0x06, 0x0f, 0x0a, 0x04, 
+0x12, 0x0c, 0x20, 0x68, 0x11, 0x18, 0xfb, 0x68, 0xd2, 0x1a, 0x7b, 0x68, 
+0x9d, 0x1a, 0xc3, 0x1f, 0x05, 0x3b, 0x38, 0x1c, 0x2a, 0x1c, 0x00, 0xf0, 
+0x26, 0xfa, 0x00, 0x20, 0x78, 0x80, 0x20, 0x1c, 0x00, 0xf0, 0x2e, 0xfb, 
+0x60, 0x68, 0x40, 0x19, 0x01, 0x04, 0x09, 0x0c, 0x60, 0x60, 0x30, 0x1c, 
+0x01, 0xf0, 0xe2, 0xfb, 0x7d, 0x4e, 0x0b, 0x23, 0x1b, 0x02, 0xf0, 0x18, 
+0xc0, 0x68, 0x00, 0x28, 0x19, 0xd0, 0x00, 0x25, 0x2d, 0x23, 0x9b, 0x01, 
+0xf0, 0x18, 0x80, 0x68, 0x00, 0x28, 0x12, 0xd0, 0xaa, 0x00, 0x92, 0x19, 
+0x2d, 0x23, 0x9b, 0x01, 0xd2, 0x18, 0x92, 0x68, 0x20, 0x1c, 0x39, 0x1c, 
+0x01, 0xf0, 0x22, 0xfe, 0x01, 0x35, 0xa8, 0x00, 0x80, 0x19, 0x2d, 0x23, 
+0x9b, 0x01, 0xc0, 0x18, 0x80, 0x68, 0x00, 0x28, 0xec, 0xd1, 0xf8, 0x6b, 
+0x01, 0x1f, 0x8a, 0x1c, 0xfa, 0x63, 0xfa, 0x68, 0x7d, 0x6c, 0x00, 0xf0, 
+0xbb, 0xf9, 0xc0, 0x43, 0x01, 0x04, 0x09, 0x0c, 0x28, 0x1c, 0xfc, 0xf7, 
+0x56, 0xff, 0x03, 0x90, 0xf9, 0x6b, 0x3a, 0x6e, 0x8e, 0x18, 0x20, 0x68, 
+0x12, 0x18, 0x01, 0x92, 0x7a, 0x6e, 0x8d, 0x18, 0x11, 0x18, 0x02, 0x91, 
+0xc8, 0x1d, 0x09, 0x30, 0xe0, 0x60, 0xb1, 0x88, 0x08, 0x02, 0x09, 0x0a, 
+0x09, 0x06, 0x09, 0x0e, 0x08, 0x43, 0x00, 0x04, 0x00, 0x0c, 0x78, 0x61, 
+0x68, 0x68, 0x01, 0x0e, 0xff, 0x22, 0x12, 0x04, 0x02, 0x40, 0x12, 0x0a, 
+0x11, 0x43, 0xff, 0x22, 0x12, 0x02, 0x02, 0x40, 0x12, 0x02, 0x11, 0x43, 
+0x00, 0x06, 0x08, 0x43, 0x38, 0x61, 0xa8, 0x89, 0x09, 0x23, 0x1b, 0x02, 
+0x18, 0x40, 0xb8, 0x61, 0xa8, 0x89, 0x98, 0x43, 0xa8, 0x81, 0xa8, 0x89, 
+0x02, 0x99, 0xc0, 0x46, 0x88, 0x81, 0x00, 0x20, 0x70, 0x80, 0xb0, 0x80, 
+0x70, 0x81, 0x68, 0x60, 0x28, 0x82, 0xb9, 0x6e, 0x30, 0x1c, 0xfc, 0xf7, 
+0x2e, 0xff, 0x38, 0x86, 0xfa, 0x69, 0x30, 0x1c, 0x29, 0x1c, 0xfc, 0xf7, 
+0x49, 0xff, 0x78, 0x86, 0x3d, 0x8e, 0x78, 0x8e, 0x03, 0x99, 0xfc, 0xf7, 
+0x0e, 0xff, 0x00, 0x90, 0x60, 0x68, 0x00, 0x04, 0x00, 0x0c, 0x39, 0x6e, 
+0x41, 0x1a, 0x09, 0x04, 0x09, 0x0c, 0x7a, 0x6e, 0x82, 0x1a, 0x13, 0x04, 
+0x1b, 0x0c, 0x1a, 0x02, 0x1b, 0x0a, 0x1a, 0x43, 0x16, 0x04, 0x36, 0x0c, 
+0xba, 0x68, 0x82, 0x42, 0x01, 0xd2, 0x00, 0x20, 0x00, 0xe0, 0x10, 0x1a, 
+0xb8, 0x60, 0x08, 0x02, 0x09, 0x12, 0x09, 0x06, 0x09, 0x0e, 0x08, 0x43, 
+0x01, 0x04, 0x09, 0x0c, 0x01, 0x98, 0xc0, 0x46, 0x41, 0x80, 0x28, 0x1c, 
+0xfc, 0xf7, 0xe9, 0xfe, 0x05, 0x1c, 0x00, 0x98, 0x31, 0x1c, 0xfc, 0xf7, 
+0xe4, 0xfe, 0x06, 0x1c, 0x78, 0x69, 0x00, 0x04, 0x00, 0x0c, 0x01, 0x02, 
+0x00, 0x0a, 0x08, 0x43, 0x01, 0x04, 0x09, 0x0c, 
+0x01, 0x98, 0xc0, 0x46, 0x81, 0x80, 0x28, 0x1c, 0xfc, 0xf7, 0xd5, 0xfe, 
+0x79, 0x69, 0x01, 0x31, 0xc0, 0x43, 0x79, 0x61, 0x01, 0x9a, 0xc0, 0x46, 
+0x50, 0x81, 0x38, 0x69, 0x01, 0x0e, 0xff, 0x22, 0x12, 0x04, 0x02, 0x40, 
+0x12, 0x0a, 0x11, 0x43, 0xff, 0x22, 0x12, 0x02, 0x02, 0x40, 0x12, 0x02, 
+0x11, 0x43, 0x00, 0x06, 0x01, 0x43, 0x30, 0x1c, 0xfc, 0xf7, 0xbd, 0xfe, 
+0x39, 0x69, 0x7a, 0x68, 0x89, 0x18, 0x39, 0x61, 0xb9, 0x68, 0x00, 0x29, 
+0x09, 0xd1, 0x02, 0x99, 0x89, 0x89, 0xba, 0x69, 0x11, 0x43, 0x02, 0x9a, 
+0xc0, 0x46, 0x91, 0x81, 0xb9, 0x69, 0xfc, 0xf7, 0xac, 0xfe, 0x20, 0x82, 
+0x00, 0x20, 0x60, 0x82, 0xf8, 0x6d, 0x41, 0x08, 0x16, 0xd3, 0x80, 0x0a, 
+0x0a, 0xd3, 0x60, 0x68, 0x10, 0x38, 0x01, 0x04, 0x09, 0x0c, 0x08, 0x02, 
+0x09, 0x0a, 0x08, 0x43, 0x21, 0x68, 0xc0, 0x46, 0x08, 0x82, 0x09, 0xe0, 
+0x60, 0x68, 0x0c, 0x38, 0x01, 0x04, 0x09, 0x0c, 0x08, 0x02, 0x09, 0x0a, 
+0x08, 0x43, 0x21, 0x68, 0xc0, 0x46, 0x88, 0x81, 0x04, 0xb0, 0xf0, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0x78, 0x2a, 0x00, 0x80, 0xe8, 0x0d, 0x00, 0x80, 
+0xf1, 0xb5, 0x84, 0xb0, 0x6e, 0x4d, 0x28, 0x69, 0x01, 0x22, 0x04, 0x99, 
+0x8a, 0x40, 0x90, 0x43, 0x28, 0x61, 0x04, 0x98, 0x43, 0x01, 0x18, 0x1a, 
+0x80, 0x00, 0x16, 0x1c, 0x69, 0x49, 0x44, 0x18, 0xe0, 0x6b, 0xc0, 0x46, 
+0x00, 0x90, 0xa0, 0x68, 0x00, 0x28, 0x01, 0xd1, 0x00, 0x26, 0x26, 0xe0, 
+0x65, 0x48, 0x41, 0x69, 0x01, 0x31, 0x41, 0x61, 0x04, 0x98, 0xfc, 0xf7, 
+0x4f, 0xfd, 0x07, 0x1c, 0x03, 0xd1, 0x28, 0x69, 0x30, 0x43, 0x28, 0x61, 
+0xb5, 0xe0, 0xa0, 0x68, 0x65, 0x68, 0xa8, 0x42, 0x00, 0xd2, 0x05, 0x1c, 
+0xa1, 0x6c, 0xa9, 0x42, 0x16, 0xd2, 0x40, 0x1a, 0x62, 0x6a, 0x10, 0x1a, 
+0x00, 0x26, 0x60, 0x62, 0xa6, 0x60, 0xa6, 0x62, 0x20, 0x88, 0x48, 0x23, 
+0x18, 0x43, 0x20, 0x80, 0x0d, 0x1c, 0x09, 0xd1, 0x38, 0x1c, 0xfc, 0xf7, 
+0x5f, 0xfd, 0x03, 0x20, 0x60, 0x80, 0x66, 0x60, 0x20, 0x1c, 0x00, 0xf0, 
+0x8d, 0xf9, 0x96, 0xe0, 0xe1, 0x68, 0x38, 0x68, 0x09, 0x18, 0xc3, 0x1f, 
+0x05, 0x3b, 0x20, 0x1c, 0x02, 0x39, 0x2a, 0x1c, 0x00, 0xf0, 0xcd, 0xf8, 
+0x38, 0x1c, 0x00, 0xf0, 0xd7, 0xf9, 0xe0, 0x68, 0x46, 0x19, 0x78, 0x68, 
+0x30, 0x43, 0x78, 0x60, 0x04, 0x98, 0x31, 0x1c, 0x01, 0xf0, 0x8a, 0xfa, 
+0x21, 0x6e, 0x00, 0x98, 0x08, 0x18, 0x01, 0x90, 0x70, 0x1a, 0x00, 0x04, 
+0x00, 0x0c, 0x61, 0x6e, 0x71, 0x1a, 0x0a, 0x04, 0x12, 0x0c, 0x11, 0x02, 
+0x12, 0x0a, 0x11, 0x43, 0x09, 0x04, 0x09, 0x0c, 0x02, 0x91, 0x01, 0x02, 
+0x00, 0x0a, 0x08, 0x43, 0x01, 0x04, 0x09, 0x0c, 0x01, 0x98, 0xc0, 0x46, 
+0x41, 0x80, 0x20, 0x8e, 0xfc, 0xf7, 0x11, 0xfe, 0x06, 0x1c, 0x60, 0x8e, 
+0x02, 0x99, 0xfc, 0xf7, 0x0c, 0xfe, 0x03, 0x90, 0x60, 0x69, 0x01, 0x04, 
+0x09, 0x0c, 0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, 0x01, 0x04, 0x09, 0x0c, 
+0x01, 0x98, 0xc0, 0x46, 0x81, 0x80, 0x30, 0x1c, 0xfc, 0xf7, 0xfd, 0xfd, 
+0x61, 0x69, 0x01, 0x31, 0xc0, 0x43, 0x61, 0x61, 0x01, 0x99, 0xc0, 0x46, 
+0x48, 0x81, 0x60, 0x6e, 0x00, 0x99, 0x46, 0x18, 0x20, 0x69, 0x01, 0x0e, 
+0xff, 0x22, 0x12, 0x04, 0x02, 0x40, 0x12, 0x0a, 0x11, 0x43, 0xff, 0x22, 
+0x12, 0x02, 0x02, 0x40, 0x12, 0x02, 0x11, 0x43, 0x00, 0x06, 0x01, 0x43, 
+0x71, 0x60, 0x03, 0x98, 0xfc, 0xf7, 0xe1, 0xfd, 0x21, 0x69, 0x49, 0x19, 
+0x21, 0x61, 0xa1, 0x68, 0x49, 0x1b, 0xa1, 0x60, 
+0x06, 0xd1, 0xb1, 0x89, 0xa2, 0x69, 0x11, 0x43, 0xb1, 0x81, 0xa1, 0x69, 
+0xfc, 0xf7, 0xd3, 0xfd, 0x38, 0x82, 0x61, 0x6e, 0x38, 0x68, 0x09, 0x18, 
+0x0e, 0x31, 0xf9, 0x60, 0xe2, 0x68, 0x00, 0x99, 0x04, 0x38, 0x00, 0xf0, 
+0x4c, 0xf8, 0x02, 0x20, 0x78, 0x82, 0xe0, 0x6d, 0x41, 0x08, 0x16, 0xd3, 
+0x80, 0x0a, 0x0a, 0xd3, 0x78, 0x68, 0x10, 0x38, 0x01, 0x04, 0x09, 0x0c, 
+0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, 0x39, 0x68, 0xc0, 0x46, 0xc8, 0x81, 
+0x09, 0xe0, 0x78, 0x68, 0x0c, 0x38, 0x01, 0x04, 0x09, 0x0c, 0x08, 0x02, 
+0x09, 0x0a, 0x08, 0x43, 0x39, 0x68, 0xc0, 0x46, 0x48, 0x81, 0x05, 0xb0, 
+0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x3c, 0x2c, 0x00, 0x80, 
+0xc8, 0x2a, 0x00, 0x80, 0x78, 0x2a, 0x00, 0x80, 0xf7, 0xb5, 0x03, 0x1c, 
+0x0f, 0x1c, 0x00, 0x20, 0x1c, 0x68, 0x26, 0x04, 0x31, 0x1c, 0x1d, 0x1d, 
+0xfc, 0xf7, 0x97, 0xfd, 0x40, 0xc7, 0x02, 0x9a, 0xd1, 0x1c, 0x89, 0x08, 
+0x01, 0x39, 0x4a, 0x1e, 0x02, 0x92, 0x00, 0x29, 0x0d, 0xd0, 0x21, 0x0c, 
+0x10, 0xcd, 0x22, 0x04, 0x0a, 0x43, 0x11, 0x1c, 0x16, 0x1c, 0xfc, 0xf7, 
+0x86, 0xfd, 0x40, 0xc7, 0x02, 0x99, 0x4a, 0x1e, 0x02, 0x92, 0x00, 0x29, 
+0xf1, 0xd1, 0x03, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x80, 0x08, 
+0x80, 0x00, 0x89, 0x08, 0x89, 0x00, 0x03, 0x32, 0x93, 0x08, 0x5a, 0x1e, 
+0x00, 0x2b, 0x05, 0xd0, 0x08, 0xc9, 0x08, 0xc0, 0x13, 0x1c, 0x01, 0x3a, 
+0x00, 0x2b, 0xf9, 0xd1, 0x70, 0x47, 0xff, 0xb5, 0x86, 0xb0, 0x17, 0x1c, 
+0x00, 0x26, 0x06, 0x98, 0x80, 0x6c, 0xc0, 0x1b, 0x06, 0x99, 0xc0, 0x46, 
+0x88, 0x64, 0x01, 0x20, 0xc0, 0x05, 0x06, 0x99, 0x89, 0x6b, 0xc0, 0x46, 
+0x01, 0x91, 0x06, 0x99, 0x4c, 0x6b, 0x67, 0xe0, 0x21, 0x68, 0xc0, 0x46, 
+0x02, 0x91, 0x61, 0x68, 0xc0, 0x46, 0x03, 0x91, 0xa1, 0x68, 0xc0, 0x46, 
+0x04, 0x91, 0x02, 0xa9, 0x49, 0x88, 0xb9, 0x42, 0x08, 0xd2, 0x02, 0xad, 
+0x6d, 0x88, 0x02, 0xa9, 0x49, 0x88, 0x7f, 0x1a, 0x00, 0x21, 0x02, 0xab, 
+0x59, 0x80, 0x19, 0xe0, 0x02, 0xa9, 0x49, 0x88, 0xc9, 0x1b, 0x02, 0xab, 
+0x59, 0x80, 0x3d, 0x1c, 0x00, 0x27, 0x01, 0x21, 0x49, 0x06, 0x07, 0x9b, 
+0x9a, 0x07, 0x92, 0x0f, 0x0d, 0xd0, 0xeb, 0x06, 0xdb, 0x0e, 0x08, 0xd0, 
+0x1e, 0x2b, 0x08, 0xd3, 0x1e, 0x2b, 0x02, 0xd1, 0x03, 0x2a, 0x04, 0xd1, 
+0x01, 0xe0, 0x02, 0x2a, 0x01, 0xd3, 0x01, 0x26, 0x00, 0x21, 0x29, 0x43, 
+0x01, 0x43, 0x0a, 0x1c, 0x00, 0x91, 0x00, 0x20, 0x03, 0x99, 0x04, 0x9a, 
+0x07, 0x9b, 0x01, 0xf0, 0x61, 0xff, 0x07, 0x99, 0x49, 0x19, 0x07, 0x91, 
+0x00, 0x2e, 0x0a, 0xd0, 0x1d, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x1d, 0x48, 
+0x01, 0x6d, 0x42, 0x6d, 0x00, 0x20, 0x07, 0x9b, 0x01, 0xf0, 0x52, 0xff, 
+0x00, 0x26, 0x02, 0xa8, 0x40, 0x88, 0x00, 0x28, 0x0c, 0xd0, 0x03, 0x98, 
+0x40, 0x19, 0x03, 0x90, 0x02, 0x98, 0xc0, 0x46, 0x20, 0x60, 0x03, 0x98, 
+0xc0, 0x46, 0x60, 0x60, 0x04, 0x98, 0xc0, 0x46, 0xa0, 0x60, 0x03, 0xe0, 
+0x01, 0x98, 0x01, 0x38, 0x01, 0x90, 0x10, 0x34, 0x06, 0x98, 0xc0, 0x46, 
+0x44, 0x63, 0x01, 0x98, 0x06, 0x99, 0xc0, 0x46, 0x88, 0x63, 0x00, 0x20, 
+0x00, 0x2f, 0x02, 0xd0, 0x01, 0x99, 0x00, 0x29, 0x92, 0xd1, 0x09, 0x4a, 
+0xc0, 0x46, 0x00, 0x92, 0x06, 0x48, 0x01, 0x6d, 0x42, 0x6d, 0x00, 0x20, 
+0x09, 0x9b, 0x01, 0xf0, 0x25, 0xff, 0x0a, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 
+0xf8, 0x28, 0x00, 0x80, 0x04, 0x00, 0x53, 0x02, 0x90, 0xb5, 0x0c, 0x1c, 
+0x07, 0x1c, 0x38, 0x68, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x38, 0x18, 0x43, 
+0x01, 0x68, 0x38, 0x8a, 0xfc, 0xf7, 0xcb, 0xfc, 0xc0, 0x43, 0xf9, 0x68, 
+0xc0, 0x46, 0x08, 0x80, 0x78, 0x8a, 0x39, 0x68, 0x08, 0x1a, 0x38, 0x60, 
+0x38, 0x1c, 0x01, 0xf0, 0x8d, 0xf9, 0x38, 0x1c, 0xfc, 0xf7, 0xd2, 0xfb, 
+0x20, 0x1c, 0xff, 0xf7, 0x33, 0xfe, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x80, 0xb5, 0x01, 0x88, 0x8a, 0x09, 0x21, 0xd3, 0xca, 0x09, 0x1f, 0xd2, 
+0x8a, 0x08, 0x1d, 0xd3, 0x00, 0x21, 0x01, 0x80, 0x41, 0x80, 0x47, 0x6f, 
+0x40, 0x6d, 0xfa, 0x1d, 0x19, 0x32, 0x51, 0x71, 0xfa, 0x6d, 0xc0, 0x46, 
+0x10, 0x60, 0x3a, 0x6e, 0xc0, 0x46, 0x10, 0x60, 0x0c, 0x48, 0xc0, 0x46, 
+0x41, 0x63, 0x81, 0x6b, 0x49, 0x08, 0x49, 0x00, 0x81, 0x63, 0x01, 0x20, 
+0x00, 0xf0, 0xce, 0xff, 0x38, 0x1c, 0x00, 0xf0, 0x6d, 0xff, 0x80, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0x80, 0x23, 0x19, 0x43, 0x01, 0x80, 0x01, 0x88, 
+0x49, 0x09, 0xf6, 0xd2, 0x00, 0xf0, 0xb0, 0xf8, 0xf3, 0xe7, 0x00, 0x00, 
+0x68, 0x0e, 0x00, 0x80, 0xf0, 0xb5, 0x07, 0x1c, 0x10, 0x1c, 0x0d, 0x1c, 
+0x00, 0x24, 0x5e, 0x1e, 0x00, 0x2b, 0x19, 0xd0, 0x01, 0x68, 0xc0, 0x46, 
+0x39, 0x60, 0x41, 0x88, 0x0c, 0x19, 0x41, 0x68, 0xc0, 0x46, 0x79, 0x60, 
+0x81, 0x68, 0xc0, 0x46, 0xb9, 0x60, 0xc1, 0x68, 0xc0, 0x46, 0xf9, 0x60, 
+0x10, 0x30, 0x10, 0x37, 0xe9, 0x6a, 0x81, 0x42, 0x02, 0xd8, 0x28, 0x1c, 
+0x00, 0xf0, 0xee, 0xff, 0x31, 0x1c, 0x01, 0x3e, 0x00, 0x29, 0xe5, 0xd1, 
+0x20, 0x1c, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x21, 0xc1, 0x61, 
+0x05, 0x49, 0x0a, 0x68, 0x00, 0x2a, 0x01, 0xd1, 0x08, 0x60, 0x02, 0xe0, 
+0x4a, 0x68, 0xc0, 0x46, 0xd0, 0x61, 0x48, 0x60, 0x70, 0x47, 0x00, 0x00, 
+0x3c, 0x2c, 0x00, 0x80, 0x03, 0x49, 0x08, 0x68, 0x00, 0x28, 0x02, 0xd0, 
+0xc2, 0x69, 0xc0, 0x46, 0x0a, 0x60, 0x70, 0x47, 0x3c, 0x2c, 0x00, 0x80, 
+0x00, 0x21, 0x81, 0x67, 0x05, 0x49, 0x8a, 0x68, 0x00, 0x2a, 0x01, 0xd1, 
+0x88, 0x60, 0x02, 0xe0, 0xca, 0x68, 0xc0, 0x46, 0x90, 0x67, 0xc8, 0x60, 
+0x70, 0x47, 0x00, 0x00, 0x3c, 0x2c, 0x00, 0x80, 0x03, 0x49, 0x88, 0x68, 
+0x00, 0x28, 0x02, 0xd0, 0x82, 0x6f, 0xc0, 0x46, 0x8a, 0x60, 0x70, 0x47, 
+0x3c, 0x2c, 0x00, 0x80, 0x00, 0xb5, 0x80, 0x20, 0x13, 0x49, 0xc0, 0x46, 
+0x08, 0x60, 0xff, 0xf7, 0xd5, 0xff, 0x00, 0x28, 0x1b, 0xd0, 0x03, 0x23, 
+0x1b, 0x07, 0x41, 0x68, 0x19, 0x40, 0x0a, 0x0f, 0x51, 0x01, 0x89, 0x1a, 
+0x89, 0x00, 0x0d, 0x4b, 0xc9, 0x18, 0x4b, 0x88, 0x00, 0x2b, 0x04, 0xd1, 
+0x11, 0x1c, 0xff, 0xf7, 0x3b, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x01, 0x2b, 
+0x02, 0xd1, 0xff, 0xf7, 0x05, 0xfc, 0xf8, 0xe7, 0x02, 0x2b, 0xf6, 0xd1, 
+0xff, 0xf7, 0x4e, 0xfb, 0xf3, 0xe7, 0x04, 0x48, 0x01, 0x6d, 0x01, 0x31, 
+0x01, 0x65, 0xee, 0xe7, 0x00, 0x00, 0x00, 0xb0, 0xc8, 0x2a, 0x00, 0x80, 
+0xa0, 0x82, 0x20, 0x40, 0x00, 0xb5, 0x20, 0x20, 0x0d, 0x49, 0xc0, 0x46, 
+0x08, 0x60, 0xff, 0xf7, 0xbf, 0xff, 0x00, 0x28, 0x0e, 0xd0, 0x01, 0x88, 
+0x20, 0x23, 0x19, 0x43, 0x01, 0x80, 0x01, 0x88, 0x10, 0x23, 0x99, 0x43, 
+0x01, 0x80, 0x01, 0x88, 0x09, 0x0a, 0x01, 0xd3, 0xff, 0xf7, 0x2e, 0xff, 
+0x08, 0xbc, 0x18, 0x47, 0x03, 0x48, 0x01, 0x6d, 0x01, 0x31, 0x01, 0x65, 
+0xf8, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 
+0xa0, 0x82, 0x20, 0x40, 0x98, 0xb5, 0x07, 0x1c, 0x22, 0x48, 0xc0, 0x46, 
+0x00, 0x90, 0x22, 0x48, 0xc3, 0x1d, 0x41, 0x33, 0x41, 0x6d, 0x82, 0x6d, 
+0x80, 0x6c, 0x00, 0x03, 0x00, 0x0b, 0x9c, 0x68, 0x01, 0x23, 0x9b, 0x07, 
+0x23, 0x43, 0x1b, 0x68, 0x98, 0x42, 0x00, 0xd1, 0x0c, 0xe0, 0x98, 0x42, 
+0x03, 0xd9, 0x10, 0x1a, 0x59, 0x1a, 0x41, 0x18, 0x00, 0xe0, 0x19, 0x1a, 
+0x01, 0x20, 0x10, 0x29, 0x00, 0xd8, 0x00, 0x20, 0x00, 0x28, 0x1f, 0xd0, 
+0x78, 0x6a, 0xf9, 0x6a, 0xc0, 0x46, 0x08, 0x60, 0xb8, 0x6a, 0xf9, 0x6a, 
+0xc0, 0x46, 0x48, 0x60, 0x10, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0xfb, 0x6a, 
+0x0f, 0x48, 0x42, 0x6d, 0x03, 0x20, 0x39, 0x6a, 0x01, 0xf0, 0xe8, 0xfd, 
+0x38, 0x88, 0x10, 0x23, 0x18, 0x43, 0x38, 0x80, 0x38, 0x88, 0x40, 0x23, 
+0x98, 0x43, 0x38, 0x80, 0x38, 0x1c, 0xff, 0xf7, 0x55, 0xff, 0x98, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0x38, 0x88, 0x40, 0x23, 0x18, 0x43, 0x38, 0x80, 
+0xf7, 0xe7, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x28, 0x03, 0x00, 0x80, 
+0x08, 0x00, 0x11, 0x02, 0xf8, 0x28, 0x00, 0x80, 0xb0, 0xb5, 0x40, 0x20, 
+0x2c, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x00, 0xf0, 0xff, 0xfe, 0x07, 0x1c, 
+0x40, 0x68, 0x03, 0x23, 0x1b, 0x07, 0x18, 0x40, 0x05, 0x0f, 0x68, 0x01, 
+0x40, 0x1b, 0x80, 0x00, 0x26, 0x49, 0x44, 0x18, 0x20, 0x88, 0x02, 0x23, 
+0x18, 0x43, 0x20, 0x80, 0x20, 0x88, 0x41, 0x08, 0x34, 0xd3, 0x40, 0x08, 
+0x40, 0x00, 0x20, 0x80, 0xa0, 0x6c, 0xe1, 0x6c, 0x40, 0x18, 0xa0, 0x64, 
+0x00, 0x20, 0xe0, 0x64, 0xa1, 0x6b, 0x22, 0x6d, 0x89, 0x18, 0xa1, 0x63, 
+0x20, 0x65, 0xb8, 0x6a, 0xc0, 0x46, 0x60, 0x65, 0x03, 0x23, 0x1b, 0x07, 
+0x78, 0x68, 0x18, 0x40, 0x78, 0x60, 0x61, 0x68, 0x36, 0x31, 0x94, 0x29, 
+0x04, 0xd8, 0x38, 0x23, 0x18, 0x43, 0x78, 0x60, 0x38, 0x20, 0x03, 0xe0, 
+0x94, 0x23, 0x18, 0x43, 0x78, 0x60, 0x94, 0x20, 0xb8, 0x61, 0x39, 0x68, 
+0x78, 0x68, 0x02, 0x04, 0x12, 0x0c, 0x20, 0x1c, 0xcb, 0x1f, 0x05, 0x3b, 
+0xff, 0xf7, 0xd7, 0xfd, 0x02, 0x20, 0x60, 0x80, 0x38, 0x1c, 0xff, 0xf7, 
+0xdf, 0xfe, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x38, 0x1c, 0xfc, 0xf7, 
+0x4d, 0xfa, 0x28, 0x01, 0x06, 0x49, 0x40, 0x18, 0x19, 0x23, 0xdb, 0x01, 
+0xc0, 0x18, 0x41, 0x6b, 0x01, 0x39, 0x41, 0x63, 0xef, 0xe7, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0xb0, 0xc8, 0x2a, 0x00, 0x80, 0x1c, 0x1c, 0x00, 0x80, 
+0x90, 0xb5, 0x00, 0x27, 0x0f, 0x4c, 0x0d, 0xe0, 0x02, 0x6b, 0x01, 0x3a, 
+0x02, 0x63, 0x00, 0x2a, 0x05, 0xdc, 0xc2, 0x6a, 0xc0, 0x46, 0x02, 0x63, 
+0x80, 0x6a, 0x01, 0xf0, 0xcc, 0xf9, 0x01, 0x37, 0x0b, 0x2f, 0x07, 0xd2, 
+0x38, 0x01, 0x00, 0x19, 0x33, 0x23, 0x9b, 0x01, 0xc0, 0x18, 0x41, 0x6a, 
+0x00, 0x29, 0xe9, 0xd1, 0x01, 0x20, 0x40, 0x06, 0x03, 0x49, 0xc0, 0x46, 
+0x08, 0x60, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xe8, 0x0d, 0x00, 0x80, 
+0x00, 0x00, 0x00, 0xb0, 0x11, 0x48, 0xc1, 0x68, 0x01, 0x31, 0xc1, 0x60, 
+0x10, 0x49, 0xc8, 0x68, 0x01, 0x28, 0x19, 0xd1, 0xc8, 0x1d, 0x79, 0x30, 
+0x82, 0x88, 0x00, 0x2a, 0x14, 0xd0, 0x01, 0x3a, 0x82, 0x80, 0x82, 0x88, 
+0x00, 0x2a, 0x0f, 0xd1, 0xc2, 0x88, 0x00, 0x2a, 0x0a, 0xd1, 0x02, 0x23, 
+0xca, 0x6f, 0x1a, 0x43, 0xca, 0x67, 0x07, 0x49, 0xc0, 0x46, 0x0a, 0x60, 
+0x04, 0x21, 0x81, 0x80, 0x01, 0x21, 0x00, 0xe0, 0x00, 0x21, 0xc1, 0x80, 
+0x70, 0x47, 0x00, 0x00, 0x08, 0x83, 0x20, 0x40, 
+0xe8, 0x0d, 0x00, 0x80, 0x00, 0x01, 0x11, 0x00, 0xb0, 0xb5, 0x07, 0x1c, 
+0x01, 0x23, 0xf8, 0x1d, 0x69, 0x30, 0x03, 0x73, 0x1d, 0x49, 0xca, 0x1d, 
+0x79, 0x32, 0xd4, 0x89, 0x60, 0x1c, 0xd0, 0x81, 0x55, 0x8a, 0x00, 0x20, 
+0xac, 0x42, 0x02, 0xdb, 0x53, 0x73, 0xd0, 0x81, 0x50, 0x83, 0x01, 0x23, 
+0x9b, 0x07, 0x3a, 0x6d, 0x1a, 0x43, 0x12, 0x68, 0xc0, 0x46, 0xba, 0x61, 
+0xfb, 0x69, 0x9a, 0x42, 0x06, 0xd1, 0xf8, 0x6c, 0x12, 0x49, 0xc0, 0x46, 
+0x08, 0x60, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x78, 0x61, 0x48, 0x69, 
+0xfa, 0x6c, 0x90, 0x43, 0x48, 0x61, 0x01, 0x21, 0x09, 0x05, 0xc8, 0x60, 
+0x38, 0x69, 0x02, 0x28, 0xf1, 0xd0, 0xb8, 0x69, 0xf9, 0x69, 0x41, 0x1a, 
+0x01, 0xd5, 0x78, 0x6d, 0x41, 0x18, 0x38, 0x1c, 0x00, 0xf0, 0x0e, 0xf8, 
+0xf9, 0x69, 0x09, 0x18, 0xf9, 0x61, 0x78, 0x6d, 0x81, 0x42, 0xe2, 0xd3, 
+0x08, 0x1a, 0xf8, 0x61, 0xdf, 0xe7, 0x00, 0x00, 0xe8, 0x0d, 0x00, 0x80, 
+0x00, 0x00, 0x00, 0xb0, 0xf8, 0xb5, 0x04, 0x1c, 0x0f, 0x1c, 0xff, 0x23, 
+0x21, 0x33, 0x9f, 0x42, 0x01, 0xd9, 0xff, 0x27, 0x21, 0x37, 0xe1, 0x6e, 
+0x38, 0x1c, 0x01, 0xf0, 0xcf, 0xfc, 0x2d, 0x4d, 0x00, 0x28, 0x13, 0xd1, 
+0xe0, 0x1d, 0x49, 0x30, 0x01, 0x7a, 0x01, 0x23, 0x19, 0x43, 0x01, 0x72, 
+0x29, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x29, 0x48, 0x01, 0x6d, 0x42, 0x6d, 
+0x00, 0x20, 0x2b, 0x1c, 0x01, 0xf0, 0xb4, 0xfc, 0x00, 0x20, 0xf8, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0x20, 0x69, 0x01, 0x30, 0x20, 0x61, 0x23, 0x49, 
+0xc8, 0x1d, 0xb9, 0x30, 0xc2, 0x6a, 0x92, 0x00, 0x51, 0x18, 0xc0, 0x31, 
+0xcf, 0x60, 0xc1, 0x6a, 0x01, 0x31, 0x89, 0x07, 0x89, 0x0f, 0xc1, 0x62, 
+0x20, 0x6b, 0xc2, 0x19, 0x61, 0x6d, 0x8a, 0x42, 0x03, 0xd8, 0x23, 0x22, 
+0x12, 0x05, 0x3a, 0x43, 0x05, 0xe0, 0x09, 0x1a, 0x7e, 0x1a, 0x07, 0xd1, 
+0x23, 0x22, 0x12, 0x05, 0x0a, 0x43, 0x00, 0x92, 0x61, 0x6e, 0x09, 0x18, 
+0xa2, 0x6e, 0x10, 0xe0, 0x11, 0x22, 0x52, 0x05, 0x0a, 0x43, 0x00, 0x92, 
+0x61, 0x6e, 0x09, 0x18, 0x00, 0x20, 0xa2, 0x6e, 0x2b, 0x1c, 0x01, 0xf0, 
+0x81, 0xfc, 0x23, 0x22, 0x12, 0x05, 0x32, 0x43, 0x00, 0x92, 0x61, 0x6e, 
+0xa2, 0x6e, 0x00, 0x20, 0x2b, 0x1c, 0x01, 0xf0, 0x77, 0xfc, 0x20, 0x6b, 
+0xc0, 0x19, 0x00, 0x09, 0x00, 0x01, 0x61, 0x6d, 0x81, 0x42, 0x00, 0xd8, 
+0x40, 0x1a, 0x20, 0x63, 0x38, 0x1c, 0xb8, 0xe7, 0x44, 0x80, 0x20, 0x40, 
+0x04, 0x00, 0x1b, 0x02, 0xf8, 0x28, 0x00, 0x80, 0xe8, 0x0d, 0x00, 0x80, 
+0x80, 0xb5, 0x01, 0x20, 0xc0, 0x03, 0x0d, 0x49, 0xc0, 0x46, 0x08, 0x60, 
+0x0c, 0x49, 0xc8, 0x1d, 0x49, 0x30, 0x02, 0x7a, 0x00, 0x27, 0x00, 0x2a, 
+0x03, 0xd0, 0x07, 0x72, 0x08, 0x1c, 0xff, 0xf7, 0x39, 0xff, 0x08, 0x49, 
+0xc8, 0x1d, 0x49, 0x30, 0x02, 0x7a, 0x00, 0x2a, 0x03, 0xd0, 0x07, 0x72, 
+0x08, 0x1c, 0xff, 0xf7, 0x2f, 0xff, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x00, 0x00, 0x00, 0xb0, 0xd0, 0x2c, 0x00, 0x80, 0x50, 0x2c, 0x00, 0x80, 
+0x90, 0xb5, 0x07, 0x1c, 0x10, 0x20, 0x18, 0x49, 0xc0, 0x46, 0x08, 0x60, 
+0xf8, 0x68, 0x01, 0x30, 0xf8, 0x60, 0x16, 0x48, 0xc4, 0x1d, 0xb9, 0x34, 
+0x21, 0x6b, 0x89, 0x00, 0x09, 0x18, 0xc0, 0x31, 0xc9, 0x68, 0x7a, 0x68, 
+0x92, 0x00, 0xd2, 0x19, 0x51, 0x64, 0x21, 0x6b, 0x89, 0x00, 0x08, 0x18, 
+0xc0, 0x30, 0xc1, 0x68, 0x78, 0x68, 0x80, 0x00, 0xc0, 0x19, 0xc0, 0x6b, 
+0x01, 0xf0, 0xa6, 0xfa, 0x01, 0x23, 0x78, 0x68, 
+0x58, 0x40, 0x78, 0x60, 0x20, 0x6b, 0x01, 0x30, 0x80, 0x07, 0x80, 0x0f, 
+0x20, 0x63, 0xf8, 0x1d, 0x19, 0x30, 0x40, 0x79, 0x00, 0x28, 0x02, 0xd1, 
+0x38, 0x1c, 0x00, 0xf0, 0x07, 0xf8, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x00, 0x00, 0x00, 0xb0, 0xe8, 0x0d, 0x00, 0x80, 0x90, 0xb5, 0x07, 0x1c, 
+0x39, 0x48, 0x80, 0x68, 0x00, 0x28, 0x05, 0xd0, 0xb8, 0x6a, 0xc0, 0x68, 
+0x80, 0x09, 0x01, 0xd3, 0x02, 0x20, 0x00, 0xe0, 0x78, 0x6f, 0xfc, 0xf7, 
+0x9d, 0xf8, 0x04, 0x1c, 0x06, 0xd1, 0x01, 0x20, 0xf9, 0x1d, 0x19, 0x31, 
+0x08, 0x71, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf8, 0x6c, 0x2f, 0x49, 
+0xc0, 0x46, 0x08, 0x60, 0xba, 0x6a, 0x38, 0x1c, 0x21, 0x1c, 0x00, 0xf0, 
+0x59, 0xf8, 0x67, 0x62, 0x00, 0x28, 0x03, 0xd1, 0x20, 0x1c, 0x00, 0xf0, 
+0x0b, 0xfd, 0xec, 0xe7, 0xf9, 0x6d, 0x09, 0x68, 0x09, 0x18, 0x09, 0x09, 
+0x09, 0x01, 0x7a, 0x6d, 0x8a, 0x42, 0x00, 0xd8, 0x89, 0x1a, 0xa1, 0x62, 
+0xb9, 0x68, 0x89, 0x00, 0xc9, 0x19, 0x4a, 0x6c, 0x00, 0x2a, 0x07, 0xd0, 
+0x4a, 0x6c, 0x12, 0x1a, 0x4a, 0x64, 0x80, 0x08, 0x80, 0x00, 0xb9, 0x6a, 
+0x08, 0x18, 0xb8, 0x62, 0x38, 0x68, 0xb9, 0x6a, 0x80, 0x00, 0xc0, 0x19, 
+0x42, 0x6b, 0x91, 0x42, 0x0e, 0xd3, 0x00, 0x21, 0x41, 0x64, 0xb8, 0x6a, 
+0x39, 0x68, 0x89, 0x00, 0xc9, 0x19, 0x49, 0x6b, 0x40, 0x1a, 0xb8, 0x62, 
+0xb9, 0x68, 0x89, 0x00, 0xc9, 0x19, 0xc9, 0x6b, 0x40, 0x18, 0xb8, 0x62, 
+0xb8, 0x68, 0x81, 0x00, 0xc9, 0x19, 0x49, 0x6c, 0x00, 0x29, 0xb8, 0xd1, 
+0xb9, 0x6a, 0xfa, 0x6b, 0x91, 0x42, 0xb4, 0xd0, 0x3a, 0x6c, 0x91, 0x42, 
+0xb1, 0xd0, 0x01, 0x23, 0x58, 0x40, 0xb8, 0x60, 0x80, 0x00, 0xc0, 0x19, 
+0xc0, 0x6b, 0xc0, 0x46, 0xb8, 0x62, 0xf8, 0x68, 0x00, 0x28, 0x01, 0xd0, 
+0x01, 0x38, 0xf8, 0x60, 0x38, 0x69, 0x00, 0x28, 0xa1, 0xd0, 0x01, 0x38, 
+0x38, 0x61, 0x9e, 0xe7, 0xe8, 0x18, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0, 
+0xf7, 0xb5, 0x90, 0xb0, 0x04, 0x1c, 0x0d, 0x1c, 0x00, 0x20, 0x05, 0x90, 
+0x02, 0x90, 0x00, 0x22, 0x01, 0x92, 0xf9, 0x48, 0x80, 0x6a, 0xc0, 0x46, 
+0xa8, 0x61, 0xa0, 0x68, 0x81, 0x00, 0x09, 0x19, 0x49, 0x6b, 0xc0, 0x46, 
+0x20, 0x60, 0xe1, 0x62, 0x12, 0x9a, 0xd0, 0x68, 0xc0, 0x46, 0xa8, 0x60, 
+0x12, 0x9a, 0x51, 0x78, 0xc0, 0x46, 0x0c, 0x91, 0xf0, 0x48, 0xc0, 0x46, 
+0x03, 0x90, 0xd7, 0x1d, 0x09, 0x37, 0xe0, 0x6a, 0xc1, 0x1b, 0x09, 0x09, 
+0xe3, 0x1d, 0x19, 0x33, 0x0c, 0x9a, 0xc0, 0x46, 0x0f, 0x93, 0xeb, 0x4b, 
+0xc0, 0x46, 0x0e, 0x93, 0x91, 0x42, 0x01, 0xd3, 0xb8, 0x42, 0x21, 0xd8, 
+0xe1, 0x68, 0x02, 0x29, 0x1e, 0xd2, 0x01, 0x20, 0x0f, 0x99, 0xc0, 0x46, 
+0x48, 0x71, 0x00, 0x20, 0x03, 0x99, 0x01, 0xf0, 0x5b, 0xfb, 0x00, 0x28, 
+0x03, 0xd1, 0x0e, 0x9b, 0x98, 0x6b, 0x01, 0x30, 0x98, 0x63, 0x01, 0x20, 
+0x80, 0x06, 0x00, 0x27, 0x68, 0x60, 0xaf, 0x61, 0xdd, 0x4a, 0xc0, 0x46, 
+0x00, 0x92, 0xdd, 0x48, 0x01, 0x6d, 0x42, 0x6d, 0xdc, 0x4b, 0x00, 0x20, 
+0x01, 0xf0, 0x3e, 0xfb, 0x38, 0x1c, 0x5c, 0xe3, 0xb8, 0x42, 0x03, 0xd8, 
+0x20, 0x1c, 0x00, 0xf0, 0x7b, 0xfc, 0x07, 0x1c, 0xd7, 0x48, 0x80, 0x68, 
+0x00, 0x28, 0x64, 0xd0, 0x38, 0x78, 0x40, 0x07, 0x40, 0x0f, 0x03, 0x28, 
+0x60, 0xd1, 0x05, 0x98, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x05, 0x90, 
+0x38, 0x78, 0xf0, 0x23, 0x18, 0x40, 0x58, 0xd1, 0xe0, 0x6a, 0xc0, 0x1b, 
+0x00, 0x09, 0x0c, 0x99, 0x88, 0x42, 0x02, 0xd2, 
+0xe0, 0x68, 0x02, 0x28, 0x05, 0xd3, 0xcb, 0x49, 0x88, 0x68, 0x00, 0xf0, 
+0x87, 0xff, 0x06, 0x1c, 0x06, 0xd1, 0x03, 0x9b, 0x28, 0x1c, 0x39, 0x1c, 
+0x22, 0x1c, 0x00, 0xf0, 0x8b, 0xfc, 0x16, 0xe1, 0x2e, 0x62, 0xf8, 0x68, 
+0x00, 0x28, 0x0d, 0xd0, 0xb8, 0x89, 0x00, 0x28, 0x03, 0xd0, 0xc1, 0x49, 
+0xc9, 0x68, 0x00, 0xf0, 0x74, 0xff, 0xf8, 0x89, 0x00, 0x28, 0x03, 0xd0, 
+0xbd, 0x49, 0xc9, 0x68, 0x00, 0xf0, 0x6d, 0xff, 0x7a, 0x68, 0xc0, 0x46, 
+0x72, 0x61, 0xb9, 0x68, 0xc0, 0x46, 0xb1, 0x61, 0x30, 0x1c, 0xb8, 0x49, 
+0x09, 0x68, 0x00, 0xf0, 0x62, 0xff, 0x00, 0x28, 0x17, 0xd1, 0x30, 0x1c, 
+0xb4, 0x49, 0x49, 0x68, 0x00, 0xf0, 0x5b, 0xff, 0x10, 0x37, 0xe0, 0x6a, 
+0xb8, 0x42, 0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0x27, 0xfc, 0x07, 0x1c, 
+0x68, 0x68, 0xaf, 0x4b, 0x18, 0x43, 0x68, 0x60, 0x00, 0x20, 0xa8, 0x61, 
+0xac, 0x23, 0xa8, 0x68, 0x98, 0x43, 0xa8, 0x60, 0xb0, 0xe0, 0xa8, 0x69, 
+0xa8, 0x28, 0x01, 0xd2, 0xa8, 0x20, 0xa8, 0x61, 0x10, 0x37, 0xe0, 0x6a, 
+0xb8, 0x42, 0x6c, 0xd8, 0x9c, 0xe0, 0xa5, 0xe0, 0xa4, 0xe0, 0x10, 0x28, 
+0x68, 0xd1, 0x03, 0x23, 0x1b, 0x07, 0x68, 0x68, 0x18, 0x40, 0x01, 0x0f, 
+0x48, 0x01, 0x40, 0x1a, 0x80, 0x00, 0xa0, 0x4a, 0x82, 0x18, 0x01, 0x92, 
+0x78, 0x88, 0x42, 0x0b, 0x31, 0xd3, 0x82, 0x0b, 0x2f, 0xd3, 0x9d, 0x48, 
+0xc0, 0x46, 0x03, 0x90, 0x02, 0x20, 0x01, 0x9a, 0xc0, 0x46, 0x10, 0x80, 
+0x78, 0x88, 0x00, 0x05, 0x00, 0x0d, 0x01, 0x9a, 0xc0, 0x46, 0x50, 0x60, 
+0xb8, 0x68, 0x01, 0x9a, 0xc0, 0x46, 0x90, 0x60, 0x78, 0x68, 0x01, 0x9a, 
+0xc0, 0x46, 0x10, 0x62, 0x00, 0x20, 0x01, 0x9a, 0xc0, 0x46, 0x90, 0x64, 
+0x01, 0x9a, 0xc0, 0x46, 0x90, 0x63, 0x88, 0x02, 0x8f, 0x49, 0x40, 0x18, 
+0x01, 0x9a, 0xc0, 0x46, 0x50, 0x63, 0x01, 0x9a, 0x50, 0x68, 0x36, 0x30, 
+0x94, 0x28, 0x01, 0xd8, 0x38, 0x20, 0x00, 0xe0, 0x94, 0x20, 0xa8, 0x61, 
+0x10, 0x37, 0xe0, 0x6a, 0xb8, 0x42, 0x28, 0xd8, 0x58, 0xe0, 0x7a, 0x88, 
+0x92, 0x0b, 0x03, 0xd3, 0x85, 0x48, 0xc0, 0x46, 0x03, 0x90, 0x23, 0xe0, 
+0x01, 0x22, 0x12, 0x03, 0x02, 0x40, 0x83, 0x4b, 0x1d, 0xd0, 0x03, 0x93, 
+0x00, 0x05, 0x00, 0x0d, 0x01, 0x9a, 0xc0, 0x46, 0x50, 0x60, 0xb8, 0x68, 
+0x01, 0x9a, 0xc0, 0x46, 0x90, 0x60, 0x78, 0x68, 0x01, 0x9a, 0xc0, 0x46, 
+0x10, 0x62, 0x00, 0x20, 0x01, 0x9a, 0xc0, 0x46, 0x90, 0x64, 0x01, 0x9a, 
+0xc0, 0x46, 0x90, 0x63, 0x88, 0x02, 0x75, 0x49, 0x40, 0x18, 0x01, 0x9a, 
+0xc0, 0x46, 0x50, 0x63, 0x02, 0xe0, 0x33, 0xe0, 0x2a, 0xe0, 0x03, 0x93, 
+0x01, 0x20, 0x0f, 0x99, 0xc0, 0x46, 0x48, 0x71, 0x12, 0x9a, 0x50, 0x78, 
+0x05, 0x99, 0x43, 0x1a, 0x0b, 0x93, 0x10, 0x37, 0xe0, 0x6a, 0xb8, 0x42, 
+0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0x92, 0xfb, 0x07, 0x1c, 0x01, 0x9a, 
+0x50, 0x6b, 0x91, 0x6b, 0x09, 0x01, 0x40, 0x18, 0x0b, 0x9b, 0x21, 0x1c, 
+0x3a, 0x1c, 0xff, 0xf7, 0x7b, 0xfb, 0x01, 0x9a, 0xc0, 0x46, 0xd0, 0x64, 
+0x01, 0x9a, 0x0b, 0x9b, 0xc0, 0x46, 0x13, 0x65, 0x01, 0x23, 0x5b, 0x06, 
+0x68, 0x68, 0x18, 0x43, 0x68, 0x60, 0x00, 0x20, 0xa8, 0x61, 0x0d, 0xe0, 
+0x10, 0x37, 0xe0, 0x6a, 0xb8, 0x42, 0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 
+0x71, 0xfb, 0x07, 0x1c, 0x38, 0x78, 0x40, 0x07, 0x40, 0x0f, 0x03, 0x28, 
+0x00, 0xd1, 0xf8, 0xe6, 0xa8, 0x69, 0x03, 0x99, 0x01, 0xf0, 0x2a, 0xfa, 
+0x00, 0x28, 0x2a, 0xd1, 0x38, 0x1c, 0x21, 0x1c, 
+0x00, 0xf0, 0x79, 0xfb, 0xa8, 0x68, 0x80, 0x09, 0x04, 0xd3, 0x30, 0x1c, 
+0x49, 0x49, 0x49, 0x68, 0x00, 0xf0, 0x85, 0xfe, 0x41, 0x49, 0x00, 0x20, 
+0x01, 0xf0, 0x18, 0xfa, 0x00, 0x28, 0x04, 0xd1, 0x0e, 0x9b, 0x98, 0x6b, 
+0x01, 0x30, 0x98, 0x63, 0x11, 0xe0, 0x01, 0x20, 0x0f, 0x99, 0xc0, 0x46, 
+0x48, 0x71, 0x80, 0x06, 0x00, 0x27, 0x68, 0x60, 0xaf, 0x61, 0x3a, 0x4a, 
+0xc0, 0x46, 0x00, 0x92, 0x39, 0x48, 0x01, 0x6d, 0x42, 0x6d, 0x39, 0x4b, 
+0x00, 0x20, 0x01, 0xf0, 0xf7, 0xf9, 0x00, 0x20, 0x15, 0xe2, 0x05, 0x98, 
+0x0c, 0x99, 0x08, 0x1a, 0x00, 0x04, 0x00, 0x0c, 0x0c, 0x90, 0x0b, 0x90, 
+0x0c, 0x98, 0x00, 0x28, 0x03, 0xd0, 0x01, 0x20, 0x0f, 0x99, 0xc0, 0x46, 
+0x48, 0x71, 0x28, 0x68, 0xc0, 0x46, 0x04, 0x90, 0x00, 0x26, 0x00, 0x20, 
+0x08, 0x90, 0x00, 0x22, 0x0a, 0x92, 0x0c, 0x98, 0x01, 0x38, 0x0d, 0x90, 
+0xa3, 0xe0, 0x78, 0x88, 0x8a, 0x1b, 0x12, 0x04, 0x12, 0x0c, 0x90, 0x42, 
+0x05, 0xdd, 0x07, 0x92, 0x80, 0x1a, 0x00, 0x04, 0x00, 0x0c, 0x08, 0x90, 
+0x00, 0xe0, 0x07, 0x90, 0x08, 0x98, 0x00, 0x28, 0x07, 0xd1, 0x0d, 0x98, 
+0x0a, 0x9a, 0x90, 0x42, 0x07, 0xdd, 0x07, 0x98, 0x30, 0x18, 0x88, 0x42, 
+0x03, 0xd8, 0x01, 0x20, 0x40, 0x05, 0x06, 0x90, 0x1c, 0xe0, 0x11, 0x20, 
+0x40, 0x05, 0x06, 0x90, 0xa8, 0x68, 0x8c, 0x23, 0x18, 0x40, 0x02, 0xd1, 
+0x20, 0x48, 0xc0, 0x46, 0x06, 0x90, 0xb1, 0x07, 0x89, 0x0f, 0x0f, 0xd0, 
+0x07, 0x98, 0xc0, 0x06, 0xc0, 0x0e, 0x08, 0xd0, 0x1e, 0x28, 0x09, 0xdb, 
+0x1e, 0x28, 0x02, 0xd1, 0x03, 0x29, 0x05, 0xd1, 0x01, 0xe0, 0x02, 0x29, 
+0x02, 0xd3, 0x01, 0x20, 0x02, 0x90, 0xde, 0xe7, 0x0a, 0x9a, 0x00, 0x2a, 
+0x04, 0xd1, 0x01, 0x23, 0xdb, 0x05, 0x06, 0x98, 0x18, 0x43, 0x06, 0x90, 
+0x07, 0x98, 0x06, 0x99, 0x08, 0x43, 0x02, 0x1c, 0x00, 0x90, 0x04, 0x98, 
+0x83, 0x19, 0x1d, 0xe0, 0x68, 0x0e, 0x00, 0x80, 0x79, 0x48, 0xff, 0xff, 
+0xa8, 0x0e, 0x00, 0x80, 0x04, 0x00, 0x12, 0x02, 0xf8, 0x28, 0x00, 0x80, 
+0x44, 0x80, 0x20, 0x40, 0xe8, 0x18, 0x00, 0x80, 0xe0, 0x03, 0x00, 0x80, 
+0x00, 0x00, 0x00, 0x80, 0xc8, 0x2a, 0x00, 0x80, 0xc9, 0x31, 0xff, 0xff, 
+0x58, 0x5f, 0x21, 0x40, 0x81, 0x3c, 0xff, 0xff, 0x41, 0x31, 0xff, 0xff, 
+0x00, 0x00, 0x32, 0x02, 0x00, 0x20, 0x3a, 0x1d, 0x06, 0xca, 0x01, 0xf0, 
+0x6f, 0xf9, 0x07, 0x98, 0x36, 0x18, 0x02, 0x98, 0x00, 0x28, 0x16, 0xd0, 
+0xa8, 0x68, 0x8c, 0x23, 0x18, 0x40, 0x04, 0xd1, 0x09, 0x23, 0x5b, 0x04, 
+0x06, 0x98, 0x18, 0x43, 0x06, 0x90, 0x06, 0x98, 0xc2, 0x4a, 0x02, 0x43, 
+0x00, 0x92, 0x04, 0x98, 0x83, 0x19, 0xc1, 0x48, 0x01, 0x6d, 0x42, 0x6d, 
+0x00, 0x20, 0x01, 0xf0, 0x55, 0xf9, 0x00, 0x20, 0x02, 0x90, 0x08, 0x98, 
+0x00, 0x28, 0x0b, 0xd1, 0x0b, 0x9b, 0x01, 0x3b, 0x0b, 0x93, 0x10, 0x37, 
+0xe0, 0x6a, 0xb8, 0x42, 0x0c, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0x8a, 0xfa, 
+0x07, 0x1c, 0x07, 0xe0, 0x78, 0x68, 0x07, 0x9a, 0x80, 0x18, 0x78, 0x60, 
+0x78, 0x88, 0x07, 0x9a, 0x80, 0x1a, 0x78, 0x80, 0x0a, 0x9a, 0x50, 0x1c, 
+0x02, 0x04, 0x12, 0x0c, 0x0a, 0x92, 0x0c, 0x98, 0x0a, 0x9a, 0x82, 0x42, 
+0x03, 0xda, 0xa9, 0x69, 0xb1, 0x42, 0x00, 0xd9, 0x53, 0xe7, 0xa8, 0x69, 
+0xb0, 0x42, 0x6b, 0xd1, 0xa8, 0x68, 0x01, 0x09, 0x69, 0xd2, 0x08, 0x9a, 
+0x00, 0x2a, 0x56, 0xd0, 0x0c, 0x99, 0x0a, 0x9a, 0x8a, 0x42, 0x3e, 0xdb, 
+0xb1, 0x07, 0x89, 0x0f, 0x0c, 0xd0, 0x08, 0x9a, 
+0xd2, 0x06, 0xd2, 0x0e, 0x0b, 0xd0, 0x1e, 0x2a, 0x06, 0xdb, 0x1e, 0x2a, 
+0x02, 0xd1, 0x03, 0x29, 0x05, 0xd0, 0x01, 0xe0, 0x02, 0x29, 0x02, 0xd2, 
+0x02, 0x99, 0x00, 0x29, 0x21, 0xd0, 0x08, 0x9a, 0xc0, 0x46, 0x00, 0x92, 
+0x04, 0x98, 0x83, 0x19, 0x00, 0x20, 0x3a, 0x1d, 0x06, 0xca, 0x01, 0xf0, 
+0x05, 0xf9, 0x08, 0x98, 0x36, 0x18, 0xa8, 0x68, 0x8c, 0x23, 0x18, 0x40, 
+0x02, 0xd0, 0x01, 0x20, 0x40, 0x06, 0x00, 0xe0, 0x92, 0x48, 0x01, 0x22, 
+0x02, 0x43, 0x00, 0x92, 0x04, 0x98, 0x83, 0x19, 0x8e, 0x48, 0x01, 0x6d, 
+0x42, 0x6d, 0x00, 0x20, 0x01, 0xf0, 0xf0, 0xf8, 0x00, 0x20, 0x02, 0x90, 
+0x15, 0xe0, 0x8c, 0x23, 0x18, 0x40, 0x02, 0xd0, 0x01, 0x20, 0x40, 0x06, 
+0x00, 0xe0, 0x88, 0x48, 0x08, 0x9a, 0x02, 0x43, 0x00, 0xe0, 0x08, 0x9a, 
+0xc0, 0x46, 0x00, 0x92, 0x04, 0x98, 0x83, 0x19, 0x00, 0x20, 0x3a, 0x1d, 
+0x06, 0xca, 0x01, 0xf0, 0xd9, 0xf8, 0x08, 0x98, 0x36, 0x18, 0x10, 0x37, 
+0xe0, 0x6a, 0xb8, 0x42, 0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0x14, 0xfa, 
+0x07, 0x1c, 0x68, 0x68, 0x80, 0x0e, 0x6b, 0xd2, 0x0a, 0x98, 0xc0, 0x46, 
+0x09, 0x90, 0x0c, 0x99, 0x88, 0x42, 0x5c, 0xda, 0x0d, 0x98, 0x09, 0x99, 
+0x88, 0x42, 0x03, 0xd0, 0x7a, 0x88, 0x1e, 0xe0, 0x5f, 0xe0, 0x5e, 0xe0, 
+0x78, 0x88, 0x01, 0x22, 0x52, 0x06, 0x02, 0x43, 0xa9, 0x68, 0x8c, 0x23, 
+0x19, 0x40, 0x02, 0xd1, 0x09, 0x23, 0x5b, 0x04, 0x1a, 0x43, 0xb1, 0x07, 
+0x89, 0x0f, 0x0e, 0xd0, 0xc3, 0x06, 0xdb, 0x0e, 0x08, 0xd0, 0x1e, 0x2b, 
+0x09, 0xdb, 0x1e, 0x2b, 0x02, 0xd1, 0x03, 0x29, 0x05, 0xd1, 0x01, 0xe0, 
+0x02, 0x29, 0x02, 0xd3, 0x01, 0x21, 0x02, 0x91, 0x02, 0x1c, 0x09, 0x98, 
+0x00, 0x28, 0x02, 0xd1, 0x01, 0x23, 0xdb, 0x05, 0x1a, 0x43, 0x00, 0x92, 
+0x04, 0x98, 0x83, 0x19, 0x00, 0x20, 0x3a, 0x1d, 0x06, 0xca, 0x01, 0xf0, 
+0x93, 0xf8, 0x78, 0x88, 0x86, 0x19, 0x10, 0x37, 0x02, 0x98, 0x00, 0x28, 
+0x14, 0xd0, 0xa8, 0x68, 0x8c, 0x23, 0x18, 0x40, 0x02, 0xd0, 0x01, 0x20, 
+0x40, 0x06, 0x00, 0xe0, 0x57, 0x48, 0x01, 0x22, 0x02, 0x43, 0x00, 0x92, 
+0x04, 0x98, 0x83, 0x19, 0x53, 0x48, 0x01, 0x6d, 0x42, 0x6d, 0x00, 0x20, 
+0x01, 0xf0, 0x7a, 0xf8, 0x00, 0x20, 0x02, 0x90, 0xe0, 0x6a, 0xb8, 0x42, 
+0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0xb6, 0xf9, 0x07, 0x1c, 0x09, 0x98, 
+0x01, 0x30, 0x00, 0x04, 0x00, 0x0c, 0x09, 0x90, 0x0c, 0x99, 0x88, 0x42, 
+0xa2, 0xdb, 0x68, 0x68, 0x30, 0x43, 0x01, 0x04, 0x09, 0x0c, 0x68, 0x60, 
+0xe8, 0x6a, 0x00, 0xf0, 0x7b, 0xfa, 0x28, 0xe0, 0x27, 0xe0, 0xa8, 0x68, 
+0x00, 0x09, 0x14, 0xd3, 0x68, 0x68, 0x80, 0x0e, 0x15, 0xd2, 0x01, 0x9a, 
+0x00, 0x2a, 0x12, 0xd0, 0x01, 0x9a, 0x50, 0x6b, 0x0b, 0x9b, 0x21, 0x1c, 
+0x3a, 0x1c, 0xff, 0xf7, 0x87, 0xf9, 0x01, 0x9a, 0xc0, 0x46, 0x90, 0x64, 
+0x01, 0x9a, 0x0b, 0x9b, 0xc0, 0x46, 0x93, 0x63, 0x03, 0xe0, 0xe8, 0x6a, 
+0x31, 0x1c, 0x00, 0xf0, 0x5d, 0xfa, 0x68, 0x68, 0x30, 0x43, 0x68, 0x60, 
+0xa8, 0x69, 0xb0, 0x42, 0x05, 0xd9, 0x00, 0x04, 0x00, 0x0c, 0x80, 0x1b, 
+0x00, 0xf0, 0xee, 0xf9, 0xae, 0x61, 0xa8, 0x68, 0x8c, 0x23, 0x18, 0x40, 
+0x0b, 0xd0, 0x2f, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x04, 0x98, 0xc3, 0x1f, 
+0x05, 0x3b, 0x2a, 0x48, 0x01, 0x6d, 0x42, 0x6d, 0x00, 0x20, 0x01, 0xf0, 
+0x27, 0xf8, 0x01, 0x23, 0x9b, 0x07, 0x20, 0x6d, 0x18, 0x43, 0x00, 0x68, 
+0xc0, 0x46, 0xa0, 0x61, 0xe1, 0x69, 0x81, 0x42, 
+0x12, 0xd0, 0x22, 0x69, 0x02, 0x2a, 0x0f, 0xd2, 0x41, 0x1a, 0x01, 0xd5, 
+0x60, 0x6d, 0x41, 0x18, 0x20, 0x1c, 0xff, 0xf7, 0x3f, 0xfb, 0xe1, 0x69, 
+0x40, 0x18, 0xe0, 0x61, 0x61, 0x6d, 0x88, 0x42, 0x24, 0xd3, 0x40, 0x1a, 
+0xe0, 0x61, 0x21, 0xe0, 0x81, 0x42, 0x1f, 0xd1, 0x20, 0x69, 0x02, 0x28, 
+0x1c, 0xd2, 0x01, 0x20, 0x60, 0x61, 0x18, 0x48, 0x41, 0x69, 0xe2, 0x6c, 
+0x0a, 0x43, 0x42, 0x61, 0x81, 0x69, 0xe3, 0x6c, 0x99, 0x43, 0x81, 0x61, 
+0x01, 0x21, 0x09, 0x05, 0xca, 0x60, 0x80, 0x69, 0xc0, 0x46, 0x08, 0x61, 
+0x8b, 0x02, 0x20, 0x6d, 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0xa0, 0x61, 
+0xe1, 0x69, 0x81, 0x42, 0x02, 0xd0, 0x20, 0x1c, 0xff, 0xf7, 0xce, 0xfa, 
+0x28, 0x1c, 0x00, 0xf0, 0x0f, 0xf9, 0x0c, 0x98, 0x05, 0x99, 0x40, 0x18, 
+0x00, 0x01, 0x10, 0x30, 0x68, 0x61, 0x13, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0xf8, 0x28, 0x00, 0x80, 
+0x00, 0x00, 0x12, 0x02, 0x04, 0x00, 0x52, 0x02, 0xe8, 0x0d, 0x00, 0x80, 
+0xf0, 0xb5, 0x40, 0x20, 0x2d, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x00, 0xf0, 
+0x03, 0xf9, 0x07, 0x1c, 0x81, 0x69, 0x44, 0x6a, 0xa0, 0x6f, 0x00, 0xf0, 
+0x49, 0xfe, 0x00, 0x20, 0xe1, 0x1d, 0x19, 0x31, 0x48, 0x71, 0x79, 0x68, 
+0xc9, 0x0e, 0x09, 0xd3, 0xf8, 0x6a, 0x00, 0x01, 0x24, 0x49, 0x40, 0x18, 
+0x24, 0x4b, 0xc0, 0x18, 0x01, 0x68, 0x01, 0x39, 0x01, 0x60, 0x36, 0xe0, 
+0xe1, 0x6d, 0x09, 0x68, 0x22, 0x6e, 0xc0, 0x46, 0x11, 0x60, 0x20, 0x4e, 
+0xf5, 0x1d, 0x79, 0x35, 0x01, 0x23, 0xa9, 0x6b, 0x19, 0x43, 0xa9, 0x63, 
+0xb9, 0x6a, 0xe2, 0x6d, 0xc0, 0x46, 0x11, 0x60, 0xb9, 0x6a, 0x22, 0x6e, 
+0xc0, 0x46, 0x11, 0x60, 0x61, 0x69, 0x00, 0x29, 0x04, 0xd1, 0x69, 0x6b, 
+0x01, 0x31, 0x69, 0x63, 0x08, 0x29, 0x07, 0xd3, 0x68, 0x63, 0x01, 0x20, 
+0x00, 0xf0, 0x86, 0xf8, 0xa8, 0x6b, 0x40, 0x08, 0x40, 0x00, 0xa8, 0x63, 
+0x78, 0x68, 0x81, 0x0e, 0x0f, 0xd2, 0x0b, 0x23, 0x1b, 0x02, 0xf1, 0x18, 
+0x89, 0x68, 0x00, 0x29, 0x06, 0xd0, 0x00, 0x08, 0x04, 0xd2, 0x20, 0x1c, 
+0x39, 0x1c, 0x00, 0xf0, 0x43, 0xf8, 0x02, 0xe0, 0x38, 0x1c, 0x00, 0xf0, 
+0x05, 0xfa, 0x38, 0x1c, 0xfb, 0xf7, 0x4a, 0xfc, 0x20, 0x1c, 0x00, 0xf0, 
+0x0b, 0xf8, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0xb0, 
+0x1c, 0x1c, 0x00, 0x80, 0xb4, 0x0c, 0x00, 0x00, 0xe8, 0x0d, 0x00, 0x80, 
+0x80, 0xb5, 0x07, 0x1c, 0xf8, 0x1d, 0x19, 0x30, 0x01, 0x79, 0x00, 0x29, 
+0x04, 0xd0, 0x00, 0x21, 0x01, 0x71, 0x38, 0x1c, 0xff, 0xf7, 0x56, 0xfb, 
+0xf8, 0x68, 0x02, 0x28, 0x0d, 0xd0, 0xb8, 0x68, 0x80, 0x00, 0xc2, 0x19, 
+0x50, 0x6c, 0x00, 0x28, 0x11, 0xd0, 0xb8, 0x6a, 0x41, 0x78, 0x09, 0x01, 
+0x10, 0x31, 0x52, 0x6b, 0x10, 0x1a, 0x88, 0x42, 0x05, 0xd3, 0x38, 0x1c, 
+0xff, 0xf7, 0x42, 0xfb, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x38, 0x1c, 
+0xff, 0xf7, 0x2a, 0xfa, 0xf8, 0xe7, 0x78, 0x68, 0x80, 0x00, 0xc0, 0x19, 
+0xc0, 0x6b, 0xc0, 0x46, 0xb8, 0x62, 0xf1, 0xe7, 0xb0, 0xb5, 0x87, 0xb0, 
+0x0f, 0x1c, 0x80, 0x6f, 0xc0, 0x46, 0x00, 0x90, 0x00, 0x24, 0x13, 0x4d, 
+0x0b, 0x23, 0x1b, 0x02, 0xe8, 0x18, 0x40, 0x69, 0x00, 0x28, 0x17, 0xd0, 
+0x69, 0x46, 0xa2, 0x00, 0x52, 0x19, 0x0b, 0x23, 0x1b, 0x02, 0xd2, 0x18, 
+0x52, 0x69, 0x38, 0x1c, 0x00, 0xf0, 0x96, 0xfb, 0x00, 0x28, 0x09, 0xd1, 
+0x01, 0x34, 0xa0, 0x00, 0x40, 0x19, 0x0b, 0x23, 
+0x1b, 0x02, 0xc0, 0x18, 0x40, 0x69, 0x00, 0x28, 0xea, 0xd1, 0x01, 0xe0, 
+0x01, 0x28, 0x02, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 0x9d, 0xf9, 0x07, 0xb0, 
+0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xe8, 0x0d, 0x00, 0x80, 
+0xb8, 0xb5, 0xc2, 0x07, 0xd2, 0x0f, 0x16, 0x4c, 0x16, 0x49, 0x01, 0xd0, 
+0x08, 0x22, 0x08, 0xe0, 0x82, 0x08, 0x05, 0xd3, 0x0c, 0x22, 0xa4, 0x18, 
+0x0b, 0x68, 0xdf, 0x1d, 0x15, 0x37, 0x03, 0xe0, 0x1c, 0x22, 0x0b, 0x68, 
+0xdf, 0x1d, 0x09, 0x37, 0x0f, 0x4b, 0x1d, 0x7b, 0x00, 0x2d, 0x13, 0xd0, 
+0x5b, 0x7b, 0x00, 0x2b, 0x10, 0xd0, 0x01, 0x23, 0x5b, 0x06, 0x1a, 0x43, 
+0x00, 0x28, 0x01, 0xd1, 0x5b, 0x08, 0x1a, 0x43, 0x00, 0x92, 0x4a, 0x68, 
+0x01, 0x20, 0x39, 0x1c, 0x23, 0x1c, 0x00, 0xf0, 0xe3, 0xfe, 0xb8, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0x03, 0x23, 0x1b, 0x06, 0x1a, 0x43, 0xf1, 0xe7, 
+0x3c, 0xef, 0x20, 0x40, 0xf8, 0x28, 0x00, 0x80, 0x68, 0x0e, 0x00, 0x80, 
+0x00, 0x21, 0xc1, 0x61, 0x05, 0x49, 0x4a, 0x68, 0x00, 0x2a, 0x01, 0xd1, 
+0x48, 0x60, 0x02, 0xe0, 0x8a, 0x68, 0xc0, 0x46, 0xd0, 0x61, 0x88, 0x60, 
+0x70, 0x47, 0x00, 0x00, 0xa8, 0x0e, 0x00, 0x80, 0x03, 0x49, 0x48, 0x68, 
+0x00, 0x28, 0x02, 0xd0, 0xc2, 0x69, 0xc0, 0x46, 0x4a, 0x60, 0x70, 0x47, 
+0xa8, 0x0e, 0x00, 0x80, 0x01, 0x1c, 0x01, 0x23, 0x88, 0x68, 0x58, 0x40, 
+0x88, 0x60, 0xca, 0x68, 0x01, 0x3a, 0xca, 0x60, 0x0a, 0x69, 0x01, 0x3a, 
+0x80, 0x00, 0x0a, 0x61, 0x42, 0x18, 0xd0, 0x6b, 0x53, 0x6b, 0xc0, 0x46, 
+0xcb, 0x62, 0x0b, 0x68, 0x9b, 0x00, 0x59, 0x18, 0x49, 0x6c, 0x53, 0x6c, 
+0xc9, 0x18, 0x51, 0x64, 0x70, 0x47, 0x8a, 0x68, 0x92, 0x00, 0x52, 0x18, 
+0xd3, 0x6b, 0x83, 0x42, 0x17, 0xd1, 0xd0, 0x1d, 0x3d, 0x30, 0x0a, 0x68, 
+0x92, 0x00, 0x52, 0x18, 0x52, 0x6c, 0x03, 0x68, 0x9a, 0x1a, 0x02, 0x60, 
+0x01, 0x23, 0x88, 0x68, 0x58, 0x40, 0x88, 0x60, 0xca, 0x68, 0x01, 0x32, 
+0xca, 0x60, 0x0a, 0x69, 0x01, 0x32, 0x80, 0x00, 0x40, 0x18, 0x0a, 0x61, 
+0x40, 0x6b, 0xc0, 0x46, 0xc8, 0x62, 0x70, 0x47, 0xb8, 0xb5, 0x04, 0x1c, 
+0x1d, 0x1c, 0x17, 0x1c, 0x08, 0x1c, 0x39, 0x1c, 0xff, 0xf7, 0xd9, 0xff, 
+0x00, 0x20, 0x29, 0x1c, 0x00, 0xf0, 0x80, 0xfe, 0x01, 0x20, 0xf9, 0x1d, 
+0x19, 0x31, 0x48, 0x71, 0x80, 0x06, 0x60, 0x60, 0x00, 0x20, 0xa0, 0x61, 
+0x06, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x06, 0x48, 0x01, 0x6d, 0x42, 0x6d, 
+0x05, 0x4b, 0x00, 0x20, 0x00, 0xf0, 0x66, 0xfe, 0xb8, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x00, 0x04, 0x00, 0x12, 0x02, 0xf8, 0x28, 0x00, 0x80, 
+0x44, 0x80, 0x20, 0x40, 0x06, 0x49, 0x0a, 0x68, 0x10, 0x18, 0x08, 0x60, 
+0x01, 0x23, 0x5b, 0x02, 0x98, 0x42, 0x03, 0xd9, 0x03, 0x49, 0x0a, 0x79, 
+0x01, 0x32, 0x0a, 0x71, 0x70, 0x47, 0x00, 0x00, 0x50, 0x2d, 0x00, 0x80, 
+0xa0, 0x82, 0x20, 0x40, 0x80, 0x08, 0x80, 0x00, 0x06, 0x49, 0x0a, 0x68, 
+0x10, 0x18, 0x08, 0x60, 0x01, 0x23, 0x5b, 0x02, 0x98, 0x42, 0x03, 0xd9, 
+0x03, 0x49, 0x0a, 0x79, 0x01, 0x32, 0x0a, 0x71, 0x70, 0x47, 0x00, 0x00, 
+0x50, 0x2d, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, 0x03, 0x30, 0x80, 0x08, 
+0x80, 0x00, 0x06, 0x49, 0x0a, 0x68, 0x10, 0x18, 0x08, 0x60, 0x01, 0x23, 
+0x5b, 0x02, 0x98, 0x42, 0x03, 0xd9, 0x03, 0x49, 0x0a, 0x79, 0x01, 0x32, 
+0x0a, 0x71, 0x70, 0x47, 0x50, 0x2d, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, 
+0x02, 0x48, 0x41, 0x79, 0x01, 0x31, 0x41, 0x71, 
+0x70, 0x47, 0x00, 0x00, 0xa0, 0x82, 0x20, 0x40, 0x90, 0xb4, 0x82, 0x00, 
+0x17, 0x4b, 0x9a, 0x58, 0x8b, 0x07, 0x02, 0xd0, 0x89, 0x08, 0x0b, 0x1d, 
+0x01, 0xe0, 0x89, 0x08, 0xcb, 0x1c, 0x11, 0x69, 0xd7, 0x68, 0x12, 0x4c, 
+0x80, 0x00, 0x20, 0x58, 0x40, 0x68, 0xb9, 0x42, 0x03, 0xd1, 0x81, 0x42, 
+0x19, 0xd9, 0x11, 0x68, 0x17, 0xe0, 0x00, 0x24, 0xb9, 0x42, 0x09, 0xd9, 
+0x81, 0x42, 0x12, 0xd9, 0x11, 0x68, 0x78, 0x1a, 0x00, 0xd5, 0x03, 0x30, 
+0x80, 0x10, 0x98, 0x42, 0x0b, 0xd8, 0x07, 0xe0, 0x81, 0x42, 0x05, 0xd8, 
+0x78, 0x1a, 0x00, 0xd5, 0x03, 0x30, 0x80, 0x10, 0x98, 0x42, 0x02, 0xd8, 
+0x20, 0x1c, 0x90, 0xbc, 0x70, 0x47, 0xc8, 0x1d, 0x05, 0x30, 0xfa, 0xe7, 
+0xf0, 0x03, 0x00, 0x80, 0x80, 0xb5, 0x80, 0x00, 0x0f, 0x4a, 0x17, 0x58, 
+0x88, 0x07, 0x02, 0xd0, 0x88, 0x08, 0x04, 0x30, 0x01, 0xe0, 0x88, 0x08, 
+0x03, 0x30, 0x39, 0x69, 0x7a, 0x68, 0x91, 0x42, 0x09, 0xd9, 0x39, 0x68, 
+0xc0, 0x46, 0x39, 0x61, 0xf9, 0x68, 0x7a, 0x68, 0x91, 0x42, 0x02, 0xd9, 
+0x39, 0x68, 0xc0, 0x46, 0xf9, 0x60, 0x81, 0x00, 0x38, 0x69, 0x00, 0xf0, 
+0xd5, 0xfd, 0x38, 0x61, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
+0xf0, 0x03, 0x00, 0x80, 0x90, 0xb5, 0x03, 0x21, 0x09, 0x07, 0x01, 0x40, 
+0x0c, 0x0f, 0x01, 0x04, 0x09, 0x0c, 0x01, 0x22, 0x92, 0x07, 0x02, 0x40, 
+0xa3, 0x00, 0x1c, 0x4f, 0xff, 0x58, 0x89, 0x07, 0x89, 0x0f, 0x00, 0x04, 
+0x00, 0x0c, 0x80, 0x08, 0x00, 0x29, 0x00, 0xd0, 0x01, 0x30, 0x00, 0x2a, 
+0x01, 0xd0, 0x02, 0x30, 0x00, 0xe0, 0x03, 0x30, 0xf9, 0x68, 0x7a, 0x68, 
+0x91, 0x42, 0x02, 0xd9, 0x39, 0x68, 0xc0, 0x46, 0xf9, 0x60, 0x81, 0x00, 
+0xf8, 0x68, 0x00, 0xf0, 0xa9, 0xfd, 0xf8, 0x60, 0x0f, 0x48, 0x00, 0x69, 
+0x00, 0x28, 0x05, 0xd0, 0x01, 0x20, 0xa0, 0x40, 0x02, 0xd0, 0x20, 0x1c, 
+0xfe, 0xf7, 0xc8, 0xfc, 0x0b, 0x49, 0xc8, 0x1d, 0x19, 0x30, 0x03, 0x79, 
+0x00, 0x22, 0x00, 0x2b, 0x05, 0xd1, 0x09, 0x49, 0xc8, 0x1d, 0x19, 0x30, 
+0x03, 0x79, 0x00, 0x2b, 0x03, 0xd0, 0x02, 0x71, 0x08, 0x1c, 0xff, 0xf7, 
+0x79, 0xf9, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0x03, 0x00, 0x80, 
+0x3c, 0x2c, 0x00, 0x80, 0xd0, 0x2c, 0x00, 0x80, 0x50, 0x2c, 0x00, 0x80, 
+0xb0, 0xb5, 0x2b, 0x49, 0x09, 0x78, 0x00, 0x29, 0x03, 0xd1, 0x41, 0x68, 
+0x29, 0x4b, 0x19, 0x43, 0x41, 0x60, 0x81, 0x68, 0x49, 0x08, 0x02, 0xd3, 
+0x09, 0x21, 0x09, 0x04, 0x01, 0xe0, 0x0d, 0x21, 0x09, 0x04, 0x0c, 0xc8, 
+0x08, 0x38, 0x19, 0x43, 0x87, 0x68, 0xbb, 0x0a, 0x03, 0xd3, 0x43, 0x68, 
+0x5b, 0x08, 0x00, 0xd3, 0x01, 0x31, 0x40, 0x68, 0x03, 0x23, 0x1b, 0x07, 
+0x18, 0x40, 0x07, 0x0f, 0xf8, 0x00, 0x1d, 0x4c, 0x00, 0x19, 0x23, 0x68, 
+0xc0, 0x18, 0x50, 0x30, 0x00, 0x79, 0x01, 0x28, 0x10, 0xd1, 0x60, 0x68, 
+0x01, 0x28, 0x0d, 0xd0, 0x10, 0x1c, 0x00, 0xf0, 0x71, 0xf8, 0x38, 0x01, 
+0x00, 0x19, 0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x41, 0x6b, 0x01, 0x39, 
+0x41, 0x63, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x38, 0x01, 0x00, 0x19, 
+0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x03, 0x6b, 0x5d, 0x1c, 0x05, 0x63, 
+0xbd, 0x02, 0x2d, 0x19, 0xdb, 0x00, 0xeb, 0x18, 0x80, 0x33, 0x19, 0x63, 
+0xda, 0x62, 0x81, 0x6b, 0x01, 0x31, 0x81, 0x63, 0x01, 0x21, 0xb9, 0x40, 
+0x22, 0x68, 0x11, 0x43, 0x21, 0x60, 0x01, 0x6b, 0x80, 0x29, 0xe2, 0xd3, 
+0x00, 0x21, 0x01, 0x63, 0xdf, 0xe7, 0x00, 0x00, 
+0xa8, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x1c, 0x1c, 0x00, 0x80, 
+0xf0, 0xb5, 0x1f, 0x4e, 0x70, 0x68, 0x00, 0x28, 0x36, 0xd1, 0x00, 0x24, 
+0xb1, 0x68, 0x48, 0x1c, 0xc9, 0x00, 0x89, 0x19, 0xb0, 0x60, 0x32, 0x68, 
+0x89, 0x18, 0x60, 0x31, 0x0d, 0x7b, 0x08, 0x28, 0x00, 0xd3, 0xb4, 0x60, 
+0x28, 0x01, 0x80, 0x19, 0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x87, 0x6b, 
+0x00, 0x2f, 0x21, 0xd0, 0xc1, 0x6a, 0x4b, 0x1c, 0xaa, 0x02, 0x92, 0x19, 
+0xc9, 0x00, 0x51, 0x18, 0x80, 0x31, 0xc3, 0x62, 0xca, 0x6a, 0x09, 0x6b, 
+0x01, 0x3f, 0x87, 0x63, 0x80, 0x2b, 0x00, 0xd3, 0xc4, 0x62, 0x00, 0x2f, 
+0x06, 0xd1, 0x01, 0x27, 0xaf, 0x40, 0x3b, 0x1c, 0xdb, 0x43, 0x37, 0x68, 
+0x3b, 0x40, 0x33, 0x60, 0x43, 0x6b, 0x01, 0x3b, 0x43, 0x63, 0x10, 0x1c, 
+0x37, 0x1c, 0x00, 0xf0, 0x09, 0xf8, 0x78, 0x68, 0x00, 0x28, 0xc9, 0xd0, 
+0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x1c, 0x1c, 0x00, 0x80, 
+0xf0, 0xb5, 0xcd, 0x0f, 0xed, 0x07, 0x01, 0x24, 0x00, 0x27, 0x2f, 0x4b, 
+0x2f, 0x4a, 0x00, 0x2d, 0x1d, 0xd0, 0xd8, 0x6a, 0x01, 0x30, 0xd8, 0x62, 
+0x10, 0x1c, 0x52, 0x69, 0x00, 0x2a, 0x12, 0xd0, 0x02, 0x69, 0x53, 0x1c, 
+0x92, 0x00, 0x12, 0x18, 0x03, 0x61, 0x91, 0x61, 0x41, 0x69, 0x01, 0x31, 
+0x41, 0x61, 0x02, 0x69, 0x0f, 0x2a, 0x00, 0xd3, 0x07, 0x61, 0x0f, 0x29, 
+0x00, 0xd3, 0x44, 0x60, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x08, 0x1c, 
+0xff, 0xf7, 0xee, 0xfe, 0xf8, 0xe7, 0x15, 0x69, 0x6e, 0x1c, 0xad, 0x00, 
+0xad, 0x18, 0x16, 0x61, 0xa9, 0x61, 0x55, 0x69, 0x01, 0x35, 0x55, 0x61, 
+0x16, 0x69, 0x0f, 0x2e, 0x00, 0xd3, 0x17, 0x61, 0x0f, 0x2d, 0x00, 0xd3, 
+0x54, 0x60, 0x8c, 0x02, 0xa4, 0x0a, 0x17, 0x4f, 0x3a, 0x6f, 0xfd, 0x68, 
+0xf9, 0x1d, 0x79, 0x31, 0x01, 0x2d, 0x0e, 0xd1, 0xdb, 0x6d, 0x5b, 0x08, 
+0x0b, 0xd3, 0x8b, 0x88, 0x00, 0x2b, 0x08, 0xd1, 0x03, 0x3b, 0xfd, 0x6f, 
+0x2b, 0x40, 0xfb, 0x67, 0x0f, 0x4d, 0xc0, 0x46, 0x2b, 0x60, 0x14, 0x23, 
+0x8b, 0x80, 0x10, 0x60, 0x80, 0x07, 0x80, 0x0a, 0x20, 0x43, 0x03, 0x04, 
+0x00, 0xd0, 0x01, 0x38, 0x50, 0x60, 0xc9, 0x69, 0x08, 0x32, 0x91, 0x42, 
+0x00, 0xd8, 0x08, 0x4a, 0x00, 0x0d, 0x02, 0xd3, 0x51, 0x20, 0x80, 0x03, 
+0x82, 0x61, 0x3a, 0x67, 0xbc, 0xe7, 0x00, 0x00, 0x10, 0x2a, 0x00, 0x80, 
+0x1c, 0x1c, 0x00, 0x80, 0xe8, 0x0d, 0x00, 0x80, 0x00, 0x01, 0x11, 0x00, 
+0x24, 0xa7, 0x20, 0x40, 0xb0, 0xb5, 0x00, 0x28, 0x04, 0xd1, 0x01, 0x20, 
+0xc0, 0x05, 0x16, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x15, 0x4c, 0x00, 0x25, 
+0x67, 0x69, 0x00, 0x2f, 0x16, 0xd0, 0xe0, 0x68, 0x41, 0x1c, 0x80, 0x00, 
+0x00, 0x19, 0xe1, 0x60, 0x80, 0x69, 0x01, 0x3f, 0xff, 0xf7, 0x90, 0xfe, 
+0xe0, 0x68, 0x0f, 0x28, 0x00, 0xd3, 0xe5, 0x60, 0xe0, 0x68, 0x80, 0x00, 
+0x00, 0x19, 0x80, 0x69, 0x00, 0x08, 0x01, 0xd3, 0x00, 0x2f, 0xea, 0xd1, 
+0x67, 0x61, 0x03, 0xe0, 0x08, 0x48, 0x01, 0x6d, 0x01, 0x31, 0x01, 0x65, 
+0x65, 0x60, 0x20, 0x68, 0x00, 0x28, 0x01, 0xd0, 0xff, 0xf7, 0x22, 0xff, 
+0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 
+0x1c, 0x1c, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, 0x00, 0x20, 0x70, 0x47, 
+0xb0, 0xb4, 0x10, 0x23, 0x82, 0x68, 0x13, 0x40, 0x00, 0x21, 0x00, 0x2b, 
+0x15, 0xd0, 0x0c, 0x4b, 0x1a, 0x40, 0x12, 0x01, 0x81, 0x24, 0x14, 0x43, 
+0x02, 0x68, 0x15, 0x68, 0x13, 0x1d, 0x80, 0xcb, 
+0x1b, 0x68, 0x04, 0x3a, 0x02, 0x60, 0x20, 0xc2, 0x80, 0xc2, 0x08, 0xc2, 
+0x14, 0x60, 0x42, 0x68, 0x01, 0x23, 0x9b, 0x07, 0x04, 0x32, 0x1a, 0x43, 
+0x42, 0x60, 0x08, 0x1c, 0xb0, 0xbc, 0x70, 0x47, 0x00, 0xf0, 0xff, 0x0f, 
+0xf0, 0xb4, 0x82, 0x68, 0x53, 0x09, 0x34, 0xd3, 0x1b, 0x4b, 0x1a, 0x40, 
+0x12, 0x01, 0x81, 0x26, 0x16, 0x43, 0x03, 0x68, 0x1d, 0x68, 0x1f, 0x1d, 
+0x10, 0xcf, 0x3f, 0x68, 0x04, 0x3b, 0x03, 0x60, 0x20, 0xc3, 0x10, 0xc3, 
+0x80, 0xc3, 0x1e, 0x60, 0x43, 0x68, 0x1f, 0x1d, 0x01, 0x23, 0x9b, 0x07, 
+0x3b, 0x43, 0x43, 0x60, 0xcb, 0x6b, 0x18, 0x1f, 0xc8, 0x63, 0x80, 0xcb, 
+0x80, 0xc0, 0x1c, 0x68, 0x1f, 0x1d, 0x03, 0x1d, 0x04, 0x60, 0x38, 0x1c, 
+0x3f, 0x68, 0xc0, 0x46, 0x1f, 0x60, 0x1f, 0x1d, 0x43, 0x68, 0x1c, 0x04, 
+0x24, 0x0c, 0x81, 0x23, 0x23, 0x43, 0x3b, 0x60, 0x40, 0x68, 0x00, 0x0c, 
+0x00, 0x04, 0x10, 0x43, 0x78, 0x60, 0x08, 0x6e, 0x04, 0x30, 0x08, 0x66, 
+0x48, 0x6e, 0x04, 0x30, 0x48, 0x66, 0x00, 0x20, 0xf0, 0xbc, 0x70, 0x47, 
+0x00, 0xf0, 0xff, 0x0f, 0x80, 0xb4, 0x81, 0x6a, 0x01, 0x23, 0x9b, 0x07, 
+0xca, 0x1d, 0x05, 0x32, 0x1a, 0x43, 0x12, 0x68, 0xcf, 0x1d, 0x01, 0x37, 
+0x3b, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0xcb, 0x60, 0x01, 0x23, 0x9b, 0x07, 
+0x0f, 0x1d, 0x3b, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0x8b, 0x60, 0x01, 0x23, 
+0x9b, 0x07, 0x0b, 0x43, 0x1b, 0x68, 0x0c, 0xc1, 0x02, 0x62, 0x01, 0x6b, 
+0xc0, 0x46, 0x0a, 0x62, 0x04, 0x23, 0x81, 0x69, 0x19, 0x43, 0x81, 0x61, 
+0x02, 0x6b, 0xc0, 0x46, 0x91, 0x61, 0x81, 0x6a, 0x04, 0x31, 0x81, 0x62, 
+0x02, 0x6b, 0xc0, 0x46, 0x91, 0x62, 0xc1, 0x1d, 0x39, 0x31, 0x4a, 0x8b, 
+0x04, 0x3a, 0x4a, 0x83, 0x49, 0x8b, 0x02, 0x6b, 0x40, 0x32, 0x51, 0x83, 
+0xc1, 0x89, 0x04, 0x39, 0xc1, 0x81, 0xc1, 0x68, 0x00, 0x6b, 0xc0, 0x46, 
+0xc1, 0x60, 0x00, 0x20, 0x80, 0xbc, 0x70, 0x47, 0x00, 0x47, 0x08, 0x47, 
+0x10, 0x47, 0x18, 0x47, 0x20, 0x47, 0x28, 0x47, 0x30, 0x47, 0x38, 0x47, 
+0x30, 0x40, 0x2d, 0xe9, 0x0c, 0xc0, 0x9d, 0xe5, 0x0c, 0x48, 0xa0, 0xe1, 
+0x24, 0x48, 0xb0, 0xe1, 0x1e, 0x00, 0x00, 0x0a, 0x01, 0xc0, 0x4c, 0xe2, 
+0x18, 0x40, 0xa0, 0xe3, 0x64, 0x51, 0x9f, 0xe5, 0x94, 0x50, 0x20, 0xe0, 
+0x00, 0x50, 0x90, 0xe5, 0x14, 0x40, 0x90, 0xe5, 0x00, 0x30, 0x85, 0xe5, 
+0x04, 0xc0, 0x85, 0xe5, 0x08, 0x10, 0x85, 0xe5, 0x0c, 0x20, 0x85, 0xe5, 
+0x10, 0x10, 0x90, 0xe5, 0x10, 0x50, 0x85, 0xe2, 0x01, 0x00, 0x55, 0xe1, 
+0x0c, 0x50, 0x90, 0x55, 0x04, 0x00, 0x55, 0xe1, 0x05, 0x00, 0x00, 0x0a, 
+0x04, 0x10, 0x90, 0xe5, 0x00, 0x50, 0x80, 0xe5, 0x00, 0x50, 0x81, 0xe5, 
+0x00, 0x00, 0xa0, 0xe3, 0x30, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, 
+0x00, 0x30, 0x93, 0xe5, 0x08, 0x20, 0x90, 0xe5, 0x01, 0x31, 0x83, 0xe3, 
+0x02, 0x36, 0x83, 0xe3, 0x03, 0x00, 0x55, 0xe1, 0x14, 0x30, 0x80, 0xe5, 
+0xf2, 0xff, 0xff, 0x1a, 0x01, 0x00, 0xa0, 0xe3, 0xf4, 0xff, 0xff, 0xea, 
+0x01, 0x06, 0x1c, 0xe3, 0xf1, 0xff, 0xff, 0x0a, 0xec, 0x10, 0x9f, 0xe5, 
+0x02, 0xc6, 0xcc, 0xe3, 0x54, 0x20, 0x91, 0xe5, 0xe4, 0x30, 0x9f, 0xe5, 
+0x50, 0x10, 0x91, 0xe5, 0xd9, 0xff, 0xff, 0xea, 0xf0, 0x47, 0x2d, 0xe9, 
+0x20, 0xc0, 0x9d, 0xe5, 0x0c, 0x68, 0xa0, 0xe1, 0x26, 0x68, 0xb0, 0xe1, 
+0x25, 0x00, 0x00, 0x0a, 0x18, 0x40, 0xa0, 0xe3, 0xb8, 0x50, 0x9f, 0xe5, 
+0x94, 0x00, 0x00, 0xe0, 0x05, 0x00, 0x80, 0xe0, 
+0x08, 0x40, 0x90, 0xe5, 0x04, 0x80, 0x90, 0xe5, 0x00, 0x70, 0xa0, 0xe3, 
+0x1f, 0xc0, 0xa0, 0xe3, 0x02, 0xc4, 0x8c, 0xe3, 0x00, 0x50, 0x90, 0xe5, 
+0x10, 0x90, 0x90, 0xe5, 0x14, 0xa0, 0x90, 0xe5, 0x00, 0x30, 0x85, 0xe5, 
+0x04, 0xc0, 0x85, 0xe5, 0x08, 0x10, 0x85, 0xe5, 0x0c, 0x20, 0x85, 0xe5, 
+0x10, 0x50, 0x85, 0xe2, 0x09, 0x00, 0x55, 0xe1, 0x0c, 0x50, 0x90, 0x55, 
+0x0a, 0x00, 0x55, 0xe1, 0x15, 0x00, 0x00, 0x0a, 0x03, 0x70, 0x17, 0xe2, 
+0x20, 0x10, 0x81, 0xe2, 0x20, 0x30, 0x83, 0xe2, 0x0a, 0x00, 0x00, 0x0a, 
+0x00, 0x60, 0x96, 0xe2, 0x01, 0x70, 0x87, 0xe2, 0x09, 0x00, 0x00, 0x0a, 
+0x20, 0x60, 0x46, 0xe2, 0x20, 0x00, 0x56, 0xe3, 0xec, 0xff, 0xff, 0xca, 
+0x00, 0x70, 0xa0, 0xe3, 0x01, 0xc0, 0x46, 0xe2, 0x02, 0xc4, 0x8c, 0xe3, 
+0x00, 0x60, 0xa0, 0xe3, 0xe7, 0xff, 0xff, 0xea, 0x00, 0x50, 0x88, 0xe5, 
+0xf2, 0xff, 0xff, 0xea, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x50, 0x80, 0xe5, 
+0x01, 0x00, 0xa0, 0xe1, 0xf0, 0x47, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, 
+0x00, 0xa0, 0x94, 0xe5, 0x0a, 0x00, 0x55, 0xe1, 0x14, 0xa0, 0x80, 0xe5, 
+0xe5, 0xff, 0xff, 0x1a, 0x01, 0x10, 0xa0, 0xe3, 0xf5, 0xff, 0xff, 0xea, 
+0x28, 0x03, 0x00, 0x80, 0xf8, 0x28, 0x00, 0x80, 0x00, 0x80, 0x20, 0x40, 
+0x68, 0x82, 0x9f, 0xe5, 0x0b, 0x92, 0xa0, 0xe3, 0x64, 0xa2, 0x9f, 0xe5, 
+0x58, 0xb0, 0x9a, 0xe5, 0x0e, 0xf0, 0xa0, 0xe1, 0x54, 0xb0, 0x9a, 0xe5, 
+0x1e, 0xff, 0x2f, 0xe1, 0x3f, 0x40, 0x2d, 0xe9, 0x00, 0x00, 0x4f, 0xe1, 
+0x1f, 0x00, 0x00, 0xe2, 0x12, 0x00, 0x50, 0xe3, 0x54, 0x00, 0x00, 0x0a, 
+0x00, 0x00, 0x0f, 0xe1, 0x80, 0x00, 0xc0, 0xe3, 0x00, 0xf0, 0x21, 0xe1, 
+0x04, 0x50, 0xa0, 0xe3, 0x00, 0x40, 0x99, 0xe5, 0x09, 0x00, 0x00, 0xea, 
+0x02, 0x00, 0x14, 0xe3, 0x53, 0x00, 0x00, 0x1b, 0x80, 0x00, 0x14, 0xe3, 
+0x59, 0x00, 0x00, 0x1b, 0x20, 0x00, 0x14, 0xe3, 0x59, 0x00, 0x00, 0x1b, 
+0x02, 0x07, 0x14, 0xe3, 0x59, 0x00, 0x00, 0x1b, 0x01, 0x06, 0x14, 0xe3, 
+0x59, 0x00, 0x00, 0x1b, 0x08, 0x00, 0x14, 0xe3, 0x45, 0x00, 0x00, 0x1b, 
+0x02, 0x05, 0x14, 0xe3, 0x4a, 0x00, 0x00, 0x1b, 0x02, 0x08, 0x14, 0xe3, 
+0x4b, 0x00, 0x00, 0x1b, 0xe5, 0x0e, 0x14, 0xe3, 0x07, 0x00, 0x00, 0x0a, 
+0x04, 0x20, 0x98, 0xe5, 0x0c, 0x10, 0x98, 0xe5, 0x04, 0x30, 0x52, 0xe2, 
+0x3c, 0x30, 0xa0, 0xb3, 0x04, 0x30, 0x88, 0xe5, 0x02, 0x00, 0x91, 0xe7, 
+0x0f, 0xe0, 0xa0, 0xe1, 0x10, 0xff, 0x2f, 0xe1, 0x01, 0x50, 0x55, 0xe2, 
+0x03, 0x00, 0x00, 0x0a, 0x00, 0x40, 0x99, 0xe5, 0x0c, 0x00, 0x9a, 0xe5, 
+0x00, 0x00, 0x14, 0xe1, 0x1b, 0xff, 0x2f, 0x11, 0x08, 0x00, 0x9a, 0xe5, 
+0x00, 0x00, 0x14, 0xe1, 0x0b, 0x00, 0x00, 0x0a, 0x01, 0x0c, 0x14, 0xe3, 
+0x98, 0x01, 0x9f, 0x15, 0x0f, 0xe0, 0xa0, 0x11, 0x10, 0xff, 0x2f, 0x11, 
+0x02, 0x04, 0x14, 0xe3, 0x8c, 0x01, 0x9f, 0x15, 0x0f, 0xe0, 0xa0, 0x11, 
+0x10, 0xff, 0x2f, 0x11, 0x01, 0x09, 0x14, 0xe3, 0x80, 0x01, 0x9f, 0x15, 
+0x0f, 0xe0, 0xa0, 0x11, 0x10, 0xff, 0x2f, 0x11, 0x04, 0x00, 0x9a, 0xe5, 
+0x00, 0x00, 0x14, 0xe1, 0x16, 0x00, 0x00, 0x0a, 0x54, 0xe0, 0x8f, 0xe2, 
+0x04, 0x00, 0x14, 0xe3, 0x40, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, 
+0x02, 0x0a, 0x14, 0xe3, 0x44, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, 
+0x02, 0x09, 0x14, 0xe3, 0x48, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, 
+0x01, 0x02, 0x14, 0xe3, 0x4c, 0x00, 0x9a, 0x15, 
+0x10, 0xff, 0x2f, 0x11, 0x01, 0x04, 0x14, 0xe3, 0x50, 0x00, 0x9a, 0x15, 
+0x10, 0xff, 0x2f, 0x11, 0x01, 0x0a, 0x14, 0xe3, 0x21, 0x00, 0x00, 0x1b, 
+0x02, 0x00, 0x14, 0xe3, 0x0e, 0x00, 0x00, 0x1b, 0x10, 0x00, 0x9a, 0xe5, 
+0x00, 0x00, 0x14, 0xe1, 0x1c, 0x00, 0x00, 0x1b, 0x00, 0x40, 0x99, 0xe5, 
+0x04, 0x50, 0xa0, 0xe3, 0x00, 0x40, 0x94, 0xe2, 0x1b, 0xff, 0x2f, 0x11, 
+0x3f, 0x40, 0xbd, 0xe8, 0x04, 0xf0, 0x5e, 0xe2, 0xc0, 0x00, 0x80, 0xe3, 
+0x00, 0xf0, 0x61, 0xe1, 0xfa, 0xff, 0xff, 0xea, 0x18, 0x00, 0x9a, 0xe5, 
+0x1c, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, 0x54, 0xb0, 0x9a, 0xe5, 
+0x1c, 0x10, 0x9a, 0xe5, 0x14, 0x00, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, 
+0x20, 0x10, 0x9a, 0xe5, 0x00, 0x00, 0xa0, 0xe3, 0x11, 0xff, 0x2f, 0xe1, 
+0x24, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, 0x28, 0x10, 0x9a, 0xe5, 
+0x11, 0xff, 0x2f, 0xe1, 0x2c, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, 
+0x30, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, 0x34, 0x10, 0x9a, 0xe5, 
+0x11, 0xff, 0x2f, 0xe1, 0xfe, 0xff, 0xff, 0xea, 0x38, 0xe0, 0x9a, 0xe5, 
+0x3c, 0x10, 0x9a, 0xe5, 0x18, 0x00, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, 
+0x38, 0xe0, 0x9a, 0xe5, 0x3c, 0x10, 0x9a, 0xe5, 0x14, 0x00, 0x9a, 0xe5, 
+0x11, 0xff, 0x2f, 0xe1, 0x64, 0x20, 0x9f, 0xe5, 0x00, 0x30, 0x92, 0xe5, 
+0x00, 0x30, 0x53, 0xe0, 0x0a, 0x00, 0x00, 0xba, 0x00, 0x30, 0x82, 0xe5, 
+0x0c, 0x00, 0x92, 0xe5, 0x08, 0x30, 0x92, 0xe5, 0x00, 0x10, 0x91, 0xe2, 
+0x03, 0x00, 0x00, 0x0a, 0x03, 0x10, 0x80, 0xe7, 0x04, 0x30, 0x53, 0xe2, 
+0x3c, 0x30, 0xa0, 0xb3, 0x08, 0x30, 0x82, 0xe5, 0x01, 0x00, 0xa0, 0xe3, 
+0x1e, 0xff, 0x2f, 0xe1, 0x3c, 0x10, 0x9f, 0xe5, 0x00, 0x00, 0x91, 0xe5, 
+0x01, 0x00, 0x80, 0xe2, 0x00, 0x00, 0x81, 0xe5, 0x00, 0x00, 0xa0, 0xe3, 
+0xf8, 0xff, 0xff, 0xea, 0x10, 0x00, 0x9f, 0xe5, 0x08, 0x10, 0x90, 0xe5, 
+0x04, 0x10, 0x51, 0xe2, 0x3c, 0x10, 0xa0, 0xb3, 0x08, 0x10, 0x80, 0xe5, 
+0x1e, 0xff, 0x2f, 0xe1, 0x50, 0x2d, 0x00, 0x80, 0x4c, 0x04, 0x00, 0x80, 
+0xe5, 0x2a, 0xff, 0xff, 0x45, 0x3d, 0xff, 0xff, 0x3d, 0x2b, 0xff, 0xff, 
+0xa0, 0x82, 0x20, 0x40, 0xc9, 0x1c, 0x89, 0x08, 0x89, 0x00, 0x01, 0x23, 
+0x85, 0x4a, 0x5b, 0x07, 0x18, 0x43, 0x13, 0x68, 0x5b, 0x18, 0x13, 0x60, 
+0x00, 0x1f, 0x81, 0xa3, 0x5b, 0x1a, 0x18, 0x47, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 
+0x50, 0x2d, 0x00, 0x80, 0x98, 0x00, 0x9f, 0xe5, 0x98, 0x10, 0x9f, 0xe5, 
+0x01, 0x20, 0x40, 0xe0, 0x94, 0x30, 0x9f, 0xe5, 0x00, 0x00, 0x91, 0xe5, 
+0x03, 0x00, 0x50, 0xe1, 0x03, 0x00, 0x00, 0x1a, 0x04, 0x10, 0x81, 0xe2, 
+0x04, 0x20, 0x52, 0xe2, 0x00, 0x00, 0x00, 0x0a, 0xf8, 0xff, 0xff, 0xea, 
+0x78, 0x00, 0x9f, 0xe5, 0x00, 0x20, 0x80, 0xe5, 0x74, 0x00, 0x9f, 0xe5, 
+0x74, 0x10, 0x9f, 0xe5, 0x01, 0x20, 0x40, 0xe0, 0x60, 0x30, 0x9f, 0xe5, 
+0x00, 0x00, 0x91, 0xe5, 0x03, 0x00, 0x50, 0xe1, 0x03, 0x00, 0x00, 0x1a, 
+0x04, 0x10, 0x81, 0xe2, 0x04, 0x20, 0x52, 0xe2, 0x00, 0x00, 0x00, 0x0a, 
+0xf8, 0xff, 0xff, 0xea, 0x50, 0x00, 0x9f, 0xe5, 0x00, 0x20, 0x80, 0xe5, 
+0x4c, 0x00, 0x9f, 0xe5, 0x4c, 0x10, 0x9f, 0xe5, 0x01, 0x20, 0x40, 0xe0, 
+0x2c, 0x30, 0x9f, 0xe5, 0x00, 0x00, 0x91, 0xe5, 0x03, 0x00, 0x50, 0xe1, 
+0x03, 0x00, 0x00, 0x1a, 0x04, 0x10, 0x81, 0xe2, 0x04, 0x20, 0x52, 0xe2, 
+0x00, 0x00, 0x00, 0x0a, 0xf8, 0xff, 0xff, 0xea, 
+0x28, 0x00, 0x9f, 0xe5, 0x00, 0x20, 0x80, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 
+0x7c, 0x34, 0x00, 0x80, 0x80, 0x30, 0x00, 0x80, 0xad, 0xde, 0xad, 0xde, 
+0x40, 0x04, 0x00, 0x80, 0xfc, 0x37, 0x00, 0x80, 0x80, 0x34, 0x00, 0x80, 
+0x44, 0x04, 0x00, 0x80, 0xfc, 0x3f, 0x00, 0x80, 0x40, 0x38, 0x00, 0x80, 
+0x48, 0x04, 0x00, 0x80, 0x78, 0x47, 0x00, 0x00, 0x91, 0xea, 0xff, 0xea, 
+0x78, 0x47, 0x00, 0x00, 0x39, 0xfe, 0xff, 0xea, 0x78, 0x47, 0x00, 0x00, 
+0x63, 0xfe, 0xff, 0xea, 0x78, 0x47, 0x00, 0x00, 0x1b, 0xff, 0xff, 0xea, 
+0x78, 0x47, 0x00, 0x00, 0x8b, 0xea, 0xff, 0xea, 0x00, 0x00, 0x00, 0x00, 
+0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x28, 0x04, 0x00, 0x00, 
+0x61, 0x6d, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0xff, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0xb9, 0x0b, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 
+0xd5, 0x0b, 0xff, 0xff, 0x03, 0xff, 0x06, 0x54, 0x03, 0x00, 0x00, 0x00, 
+0x75, 0x04, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xa1, 0x05, 0xff, 0xff, 
+0x04, 0xff, 0x07, 0x54, 0x03, 0x00, 0x00, 0x00, 0xb5, 0x04, 0xff, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0xf1, 0x05, 0xff, 0xff, 0x05, 0xff, 0x05, 0x54, 
+0x03, 0x00, 0x00, 0x00, 0x39, 0x04, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 
+0x55, 0x05, 0xff, 0xff, 0x00, 0xff, 0x04, 0x00, 0x03, 0x00, 0x00, 0x00, 
+0xf5, 0x17, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x29, 0x0e, 0xff, 0xff, 
+0x01, 0xff, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00, 0xa1, 0x02, 0xff, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0xf1, 0x02, 0xff, 0xff, 0xff, 0xff, 0x01, 0x44, 
+0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x65, 0x0d, 0xff, 0xff, 0x06, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0xbd, 0x4f, 0xff, 0xff, 0x01, 0x50, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 
+0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x04, 0x00, 0x80, 
+0x19, 0x78, 0x21, 0x40, 0x23, 0x78, 0x21, 0x40, 0x39, 0x78, 0x21, 0x40, 
+0x51, 0x78, 0x21, 0x40, 0x5d, 0x78, 0x21, 0x40, 0x6b, 0x78, 0x21, 0x40, 
+0x85, 0x78, 0x21, 0x40, 0xb1, 0x78, 0x21, 0x40, 0x75, 0x79, 0x21, 0x40, 
+0xcd, 0x79, 0x21, 0x40, 0xdb, 0x79, 0x21, 0x40, 0xe5, 0x79, 0x21, 0x40, 
+0xef, 0x79, 0x21, 0x40, 0x81, 0x7a, 0x21, 0x40, 0x8f, 0x7a, 0x21, 0x40, 
+0x9d, 0x7a, 0x21, 0x40, 0x35, 0x7b, 0x21, 0x40, 0x03, 0x7f, 0x21, 0x40, 
+0x71, 0x7f, 0x21, 0x40, 0x19, 0x80, 0x21, 0x40, 0x4d, 0x81, 0x21, 0x40, 
+0x59, 0x81, 0x21, 0x40, 0xb9, 0x81, 0x21, 0x40, 0x1d, 0x82, 0x21, 0x40, 
+0x49, 0x82, 0x21, 0x40, 0x6d, 0x82, 0x21, 0x40, 0xad, 0x82, 0x21, 0x40, 
+0xd5, 0x82, 0x21, 0x40, 0x1d, 0x83, 0x21, 0x40, 0x2d, 0x83, 0x21, 0x40, 
+0x55, 0x83, 0x21, 0x40, 0x65, 0x83, 0x21, 0x40, 0xad, 0x83, 0x21, 0x40, 
+0xeb, 0x83, 0x21, 0x40, 0x41, 0x84, 0x21, 0x40, 0xa1, 0x84, 0x21, 0x40, 
+0xab, 0x84, 0x21, 0x40, 0xaf, 0x84, 0x21, 0x40, 0x1d, 0x85, 0x21, 0x40, 
+0x75, 0x85, 0x21, 0x40, 0xcd, 0x85, 0x21, 0x40, 
+0x09, 0x86, 0x21, 0x40, 0x6d, 0x86, 0x21, 0x40, 0xa5, 0x86, 0x21, 0x40, 
+0xb5, 0x86, 0x21, 0x40, 0xed, 0x86, 0x21, 0x40, 0xfd, 0x86, 0x21, 0x40, 
+0x11, 0x87, 0x21, 0x40, 0x39, 0x87, 0x21, 0x40, 0x43, 0x87, 0x21, 0x40, 
+0x4d, 0x87, 0x21, 0x40, 0x57, 0x87, 0x21, 0x40, 0xc1, 0x87, 0x21, 0x40, 
+0xcd, 0x87, 0x21, 0x40, 0x41, 0x88, 0x21, 0x40, 0x4b, 0x88, 0x21, 0x40, 
+0x55, 0x88, 0x21, 0x40, 0x5f, 0x88, 0x21, 0x40, 0x69, 0x88, 0x21, 0x40, 
+0x73, 0x88, 0x21, 0x40, 0x7d, 0x88, 0x21, 0x40, 0x87, 0x88, 0x21, 0x40, 
+0x91, 0x88, 0x21, 0x40, 0x9b, 0x88, 0x21, 0x40, 0xa5, 0x88, 0x21, 0x40, 
+0xaf, 0x88, 0x21, 0x40, 0xb9, 0x88, 0x21, 0x40, 0xc3, 0x88, 0x21, 0x40, 
+0xeb, 0x88, 0x21, 0x40, 0xf5, 0x88, 0x21, 0x40, 0x51, 0x89, 0x21, 0x40, 
+0x5b, 0x89, 0x21, 0x40, 0x65, 0x89, 0x21, 0x40, 0x6f, 0x89, 0x21, 0x40, 
+0x79, 0x89, 0x21, 0x40, 0xa5, 0x77, 0x21, 0x40, 0x83, 0x89, 0x21, 0x40, 
+0xe9, 0x89, 0x21, 0x40, 0x35, 0x8a, 0x21, 0x40, 0x81, 0x8a, 0x21, 0x40, 
+0x91, 0x8a, 0x21, 0x40, 0xa5, 0x77, 0x21, 0x40, 0xdd, 0x8a, 0x21, 0x40, 
+0xe1, 0x8a, 0x21, 0x40, 0xe5, 0x8a, 0x21, 0x40, 0x3d, 0x8b, 0x21, 0x40, 
+0x65, 0x8b, 0x21, 0x40, 0x71, 0x8b, 0x21, 0x40, 0x75, 0x8b, 0x21, 0x40, 
+0x79, 0x8b, 0x21, 0x40, 0xe9, 0x8b, 0x21, 0x40, 0xed, 0x8b, 0x21, 0x40, 
+0xf1, 0x8b, 0x21, 0x40, 0x7d, 0x8b, 0x21, 0x40, 0x05, 0x88, 0x21, 0x40, 
+0xa5, 0x77, 0x21, 0x40, 0xa5, 0x77, 0x21, 0x40, 0xf5, 0x8b, 0x21, 0x40, 
+0xe9, 0xc1, 0x21, 0x40, 0xe9, 0x77, 0x21, 0x40, 0xa5, 0x77, 0x21, 0x40, 
+0xa5, 0x77, 0x21, 0x40, 0xcd, 0xc2, 0x21, 0x40, 0x03, 0xc3, 0x21, 0x40, 
+0x35, 0xc3, 0x21, 0x40, 0x4d, 0x8c, 0x21, 0x40, 0x3f, 0x7b, 0x21, 0x40, 
+0x99, 0x7e, 0x21, 0x40, 0xd5, 0x7e, 0x21, 0x40, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x5c, 0x01, 0x18, 0x40, 0x58, 0x01, 0x18, 0x40, 0x24, 0xa3, 0x20, 0x40, 
+0x24, 0xa7, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x6c, 0x01, 0x18, 0x40, 0x68, 0x01, 0x18, 0x40, 0x24, 0x83, 0x20, 0x40, 
+0x24, 0xa3, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x7c, 0x01, 0x18, 0x40, 0x78, 0x01, 0x18, 0x40, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x8c, 0x01, 0x18, 0x40, 0x88, 0x01, 0x18, 0x40, 0x24, 0xa9, 0x20, 0x40, 
+0x24, 0xab, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x12, 0x00, 0x18, 0x00, 0x12, 0x00, 
+0x0c, 0x00, 0x12, 0x00, 0x1c, 0x00, 0x12, 0x00, 0x24, 0xa8, 0x20, 0x40, 
+0xa4, 0xa8, 0x20, 0x40, 0xa4, 0xa8, 0x20, 0x40, 0x24, 0xa9, 0x20, 0x40, 
+0x00, 0x00, 0x00, 0x00, 0x11, 0xb2, 0x21, 0x40, 0x6d, 0xb3, 0x21, 0x40, 
+0x00, 0x00, 0x00, 0x00, 0x91, 0x73, 0x21, 0x40, 0x89, 0xaa, 0x21, 0x40, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x67, 0x92, 0x21, 0x40, 0x11, 0xb2, 0x21, 0x40, 
+0x39, 0x2f, 0xff, 0xff, 0xad, 0x20, 0xff, 0xff, 0x97, 0x20, 0xff, 0xff, 
+0xe9, 0xb0, 0x21, 0x40, 0xa0, 0x2d, 0x00, 0x80, 0xb4, 0x2d, 0x00, 0x80, 
+0xc8, 0x2d, 0x00, 0x80, 0x30, 0x33, 0x3a, 0x31, 0x31, 0x3a, 0x31, 0x31, 
+0x00, 0x30, 0x37, 0x2f, 0x32, 0x33, 0x2f, 0x30, 
+0x31, 0x00, 0x30, 0x30, 0x30, 0x30, 0x31, 0x35, 0x36, 0x39, 0x00, 0x43, 
+0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x63, 0x29, 
+0x20, 0x32, 0x30, 0x30, 0x31, 0x20, 0x33, 0x43, 0x6f, 0x6d, 0x20, 0x43, 
+0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x00, 
+0x17, 0x40, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x0c, 0x53, 0xff, 0xff, 0x27, 0xf0, 0x7d, 0xfd, 
+0x00, 0x01, 0x00, 0x02, 0xda, 0x0e, 0x82, 0x00, 0x01, 0x40, 0x64, 0x04, 
+0xd0, 0x2c, 0x00, 0x80, 0x50, 0x2c, 0x00, 0x80, 0xe5, 0x3d, 0xff, 0xff, 
+0x49, 0x4f, 0xff, 0xff, 0x79, 0x24, 0xff, 0xff, 0x3d, 0x3b, 0xff, 0xff, 
+0x9d, 0x3b, 0xff, 0xff, 0xa1, 0x19, 0xff, 0xff, 0x19, 0x11, 0xff, 0xff, 
+0x4c, 0x53, 0xff, 0xff, 0x99, 0x3f, 0xff, 0xff, 0x91, 0x73, 0x21, 0x40, 
+0x51, 0x75, 0x21, 0x40, 0x51, 0x3f, 0xff, 0xff, 0x11, 0xa3, 0x21, 0x40, 
+0x29, 0x24, 0xff, 0xff, 0xe4, 0x52, 0xff, 0xff, 0x0c, 0x53, 0xff, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x80, 0x30, 0x00, 0x80, 
+0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x20, 0x40, 
+0xb8, 0x60, 0x00, 0x00, 0x74, 0x6c, 0x00, 0x00, 0x00, 0x6e, 0x21, 0x40, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
+0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 
+0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 
+0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 
+0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 
+0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 
+0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 
+0xfd, 0x92, 0x21, 0x40, 0x9b, 0x92, 0x21, 0x40, 0xc1, 0x95, 0x21, 0x40, 
+0x21, 0x96, 0x21, 0x40, 0xe9, 0x96, 0x21, 0x40, 0xa7, 0x94, 0x21, 0x40, 
+0xc5, 0x97, 0x21, 0x40, 0x31, 0x98, 0x21, 0x40, 0x85, 0x94, 0x21, 0x40, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 
+0xb5, 0xce, 0x21, 0x40, 0x00, 0x00, 0x00, 0x00, 0xa9, 0xc3, 0x21, 0x40, 
+0x45, 0xc5, 0x21, 0x40, 0x00, 0x00, 0x00, 0x00, 0xf1, 0xcc, 0x21, 0x40, 
+0x59, 0xcd, 0x21, 0x40, 0xc5, 0xcd, 0x21, 0x40, 0x09, 0x29, 0x09, 0xd1, 
+0x20, 0x28, 0x07, 0xd2, 0x04, 0x48, 0x01, 0x78, 0x00, 0x29, 0x03, 0xd1, 
+0x01, 0x21, 0x01, 0x70, 0x02, 0x48, 0x70, 0x47, 0x00, 0x20, 0xfc, 0xe7, 
+0x00, 0x6e, 0x21, 0x40, 0x24, 0xab, 0x20, 0x40, 0x03, 0x49, 0x88, 0x42, 
+0x03, 0xd1, 0x00, 0x20, 0x02, 0x49, 0xc0, 0x46, 0x08, 0x70, 0x70, 0x47, 
+0x24, 0xab, 0x20, 0x40, 0x00, 0x6e, 0x21, 0x40, 
+0x00, 0xb5, 0x00, 0x20, 0x0b, 0x4a, 0x0b, 0x23, 0x1b, 0x02, 0xd1, 0x18, 
+0x2d, 0x23, 0x9b, 0x01, 0xd3, 0x18, 0x48, 0x61, 0x98, 0x60, 0x98, 0x63, 
+0x80, 0x32, 0x88, 0x60, 0xc8, 0x60, 0x08, 0x61, 0x90, 0x62, 0x05, 0x48, 
+0xc0, 0x46, 0x08, 0x60, 0x48, 0x60, 0x05, 0xf0, 0xc3, 0xf9, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x00, 0xe8, 0x0d, 0x00, 0x80, 0xfe, 0x03, 0x00, 0x00, 
+0xf0, 0xb5, 0x84, 0xb0, 0x0c, 0x1c, 0x05, 0x1c, 0x00, 0x23, 0x00, 0x93, 
+0xff, 0xf7, 0xda, 0xff, 0x68, 0x49, 0x0b, 0x23, 0x1b, 0x02, 0xcf, 0x18, 
+0x38, 0x68, 0x28, 0x40, 0x00, 0x22, 0xb8, 0x60, 0xfa, 0x60, 0x7a, 0x68, 
+0x22, 0x40, 0x3a, 0x61, 0x0c, 0x1c, 0x41, 0x09, 0x03, 0xd2, 0x51, 0x09, 
+0x01, 0xd2, 0x80, 0x0a, 0x02, 0xd3, 0x60, 0x48, 0x00, 0xf0, 0xc2, 0xf8, 
+0x01, 0x20, 0xb9, 0x68, 0x49, 0x09, 0x03, 0xd2, 0x39, 0x69, 0x49, 0x09, 
+0x00, 0xd2, 0x00, 0x20, 0x00, 0x06, 0x00, 0x0e, 0x03, 0xf0, 0xf8, 0xfd, 
+0xb8, 0x68, 0x00, 0x28, 0x70, 0xd0, 0x00, 0x23, 0x02, 0x93, 0x01, 0x93, 
+0x54, 0x4a, 0x01, 0x23, 0x18, 0x43, 0xb8, 0x60, 0x00, 0x20, 0xd5, 0x1d, 
+0x79, 0x35, 0x03, 0x95, 0x01, 0x24, 0x00, 0x21, 0x4f, 0x4d, 0xba, 0x68, 
+0x22, 0x40, 0x39, 0xd0, 0x8a, 0x00, 0x52, 0x18, 0x92, 0x00, 0x4e, 0x4b, 
+0x9b, 0x5c, 0x1e, 0x1c, 0x83, 0x42, 0x04, 0xd0, 0x4b, 0x4b, 0xd3, 0x18, 
+0x5b, 0x78, 0x83, 0x42, 0x2c, 0xd1, 0x49, 0x4b, 0xd2, 0x18, 0xd3, 0x78, 
+0x03, 0x9d, 0xad, 0x6a, 0xab, 0x42, 0x02, 0xd9, 0x03, 0x9d, 0xc0, 0x46, 
+0xab, 0x62, 0x53, 0x68, 0x5b, 0x08, 0x01, 0xd3, 0x01, 0x23, 0x00, 0x93, 
+0x86, 0x42, 0x0a, 0xd1, 0x95, 0x68, 0x02, 0x9b, 0x5e, 0x1c, 0x02, 0x96, 
+0x9b, 0x00, 0x3c, 0x4e, 0x9e, 0x19, 0x0b, 0x23, 0x1b, 0x02, 0xf3, 0x18, 
+0x5d, 0x61, 0x53, 0x78, 0x83, 0x42, 0x0d, 0xd1, 0xd2, 0x68, 0x01, 0x9b, 
+0x5d, 0x1c, 0x01, 0x95, 0x9b, 0x00, 0x35, 0x4d, 0x5d, 0x19, 0x2d, 0x23, 
+0x9b, 0x01, 0xeb, 0x18, 0x9a, 0x60, 0xfa, 0x68, 0x01, 0x32, 0xfa, 0x60, 
+0x64, 0x00, 0x01, 0x31, 0x0b, 0x29, 0xbd, 0xd3, 0x01, 0x30, 0x09, 0x28, 
+0xb8, 0xd3, 0x00, 0x20, 0x02, 0x9b, 0x99, 0x00, 0x2b, 0x4a, 0x89, 0x18, 
+0x0b, 0x23, 0x1b, 0x02, 0xc9, 0x18, 0x48, 0x61, 0x01, 0x9b, 0x99, 0x00, 
+0x89, 0x18, 0x2d, 0x23, 0x9b, 0x01, 0xc9, 0x18, 0x88, 0x60, 0x00, 0x9b, 
+0x00, 0x2b, 0x0c, 0xd1, 0x81, 0x00, 0x89, 0x18, 0x0b, 0x23, 0x1b, 0x02, 
+0xc9, 0x18, 0x8b, 0x69, 0xc0, 0x46, 0x4b, 0x61, 0x01, 0x30, 0x0b, 0x28, 
+0xf4, 0xd3, 0x08, 0xe0, 0x07, 0xe0, 0x03, 0x9d, 0xa8, 0x6a, 0x30, 0x28, 
+0x03, 0xd2, 0x30, 0x20, 0x03, 0x9d, 0xc0, 0x46, 0xa8, 0x62, 0x19, 0x4a, 
+0x38, 0x69, 0x00, 0x28, 0x2a, 0xd0, 0x00, 0x21, 0x01, 0x23, 0x18, 0x43, 
+0x38, 0x61, 0x00, 0x20, 0x01, 0x24, 0x00, 0x22, 0x13, 0x4e, 0x3b, 0x69, 
+0x23, 0x40, 0x10, 0xd0, 0x93, 0x00, 0x9b, 0x18, 0x9b, 0x00, 0x12, 0x4d, 
+0x5b, 0x19, 0x9d, 0x78, 0x85, 0x42, 0x08, 0xd1, 0x1d, 0x69, 0x0b, 0x1c, 
+0x9b, 0x00, 0x9e, 0x19, 0x2d, 0x23, 0x9b, 0x01, 0xf3, 0x18, 0x9d, 0x63, 
+0x01, 0x31, 0x64, 0x00, 0x01, 0x32, 0x0b, 0x2a, 0xe6, 0xd3, 0x01, 0x30, 
+0x09, 0x28, 0xe1, 0xd3, 0x00, 0x20, 0x89, 0x00, 0x04, 0x4a, 0x89, 0x18, 
+0x2d, 0x23, 0x9b, 0x01, 0xc9, 0x18, 0x88, 0x63, 0x04, 0xb0, 0xf0, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0xe8, 0x0d, 0x00, 0x80, 0xb0, 0x52, 0xff, 0xff, 
+0x80, 0x00, 0x00, 0x80, 0x00, 0x47, 0x08, 0x47, 
+0x10, 0x47, 0x18, 0x47, 0x78, 0x47, 0xc0, 0x46, 0x34, 0xc0, 0x9f, 0xe5, 
+0x1c, 0xff, 0x2f, 0xe1, 0x78, 0x47, 0xc0, 0x46, 0x2c, 0xc0, 0x9f, 0xe5, 
+0x1c, 0xff, 0x2f, 0xe1, 0x78, 0x47, 0xc0, 0x46, 0x24, 0xc0, 0x9f, 0xe5, 
+0x1c, 0xff, 0x2f, 0xe1, 0xc0, 0x46, 0xff, 0xb4, 0x75, 0x46, 0x20, 0xb4, 
+0x01, 0x21, 0x08, 0x43, 0x01, 0xa4, 0xa6, 0x46, 0x00, 0x47, 0xc0, 0x46, 
+0x20, 0xbc, 0xae, 0x46, 0xff, 0xbc, 0xf7, 0x46, 0xb8, 0x51, 0xff, 0xff, 
+0x08, 0x51, 0xff, 0xff, 0xd7, 0xb7, 0x21, 0x40, 0xf0, 0xb5, 0x04, 0x20, 
+0x1a, 0x49, 0x01, 0x25, 0x08, 0x60, 0x1a, 0x4f, 0xbb, 0x23, 0x1b, 0x01, 
+0xf8, 0x18, 0x05, 0x72, 0x18, 0x48, 0x41, 0x6b, 0x2c, 0x05, 0x00, 0x20, 
+0x7a, 0x6e, 0x17, 0x4b, 0x8a, 0x42, 0x1d, 0xd0, 0x19, 0x7b, 0x00, 0x29, 
+0x17, 0xd1, 0xd9, 0x1d, 0xff, 0x31, 0x3a, 0x31, 0x49, 0x78, 0x1e, 0x1c, 
+0x00, 0x29, 0x10, 0xd1, 0xb0, 0x60, 0x10, 0x20, 0x70, 0x60, 0x10, 0x4a, 
+0x10, 0x49, 0xff, 0xf7, 0xb5, 0xff, 0x00, 0x28, 0x07, 0xd0, 0x35, 0x73, 
+0x04, 0x23, 0xb8, 0x69, 0x18, 0x43, 0xb8, 0x61, 0x20, 0x61, 0x00, 0xf0, 
+0x17, 0xf8, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x18, 0x73, 0x04, 0x23, 
+0xb8, 0x69, 0x98, 0x43, 0xb8, 0x61, 0x20, 0x61, 0xf5, 0xe7, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0xb0, 0xe8, 0x0d, 0x00, 0x80, 0x00, 0x01, 0x18, 0x40, 
+0xa8, 0x04, 0x00, 0x80, 0xa0, 0x54, 0xff, 0xff, 0x85, 0x74, 0x21, 0x40, 
+0xf8, 0xb5, 0x15, 0x4f, 0x39, 0x6c, 0x15, 0x48, 0x40, 0x6e, 0x0c, 0x1a, 
+0x14, 0x4e, 0x71, 0x68, 0x14, 0x4d, 0xa1, 0x42, 0x06, 0xd8, 0x14, 0x4a, 
+0x0a, 0x43, 0x00, 0x92, 0xb9, 0x6b, 0x09, 0x18, 0xfa, 0x6b, 0x11, 0xe0, 
+0x11, 0x22, 0x52, 0x05, 0x22, 0x43, 0x00, 0x92, 0xb9, 0x6b, 0x09, 0x18, 
+0x00, 0x20, 0xfa, 0x6b, 0x2b, 0x1c, 0xff, 0xf7, 0x7f, 0xff, 0x70, 0x68, 
+0x00, 0x1b, 0x0a, 0x4a, 0x02, 0x43, 0x00, 0x92, 0xb9, 0x6b, 0xfa, 0x6b, 
+0x00, 0x20, 0x2b, 0x1c, 0xff, 0xf7, 0x74, 0xff, 0xf8, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x00, 0xf8, 0x28, 0x00, 0x80, 0xe8, 0x0d, 0x00, 0x80, 
+0xa8, 0x04, 0x00, 0x80, 0x44, 0x80, 0x20, 0x40, 0x00, 0x00, 0x37, 0x02, 
+0xf0, 0xb5, 0x2b, 0x4f, 0xb8, 0x68, 0x79, 0x68, 0xc0, 0x19, 0x20, 0x30, 
+0x29, 0x4a, 0xff, 0xf7, 0x55, 0xff, 0x01, 0x20, 0xc0, 0x02, 0x28, 0x49, 
+0xc0, 0x46, 0x08, 0x60, 0xb9, 0x68, 0x38, 0x1c, 0x26, 0x4d, 0x00, 0x24, 
+0x26, 0x4e, 0xef, 0x1d, 0x79, 0x37, 0x00, 0x29, 0x31, 0xd1, 0x31, 0x68, 
+0x0a, 0x78, 0x12, 0x0a, 0x03, 0xd2, 0x04, 0x73, 0xf0, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x49, 0x78, 0x00, 0x29, 0x0c, 0xd1, 0x05, 0x1c, 0x40, 0x68, 
+0x00, 0xf0, 0x3e, 0xf9, 0x30, 0x68, 0x00, 0xf0, 0x67, 0xf8, 0x00, 0x28, 
+0x26, 0xd1, 0x2c, 0x73, 0xff, 0xf7, 0x58, 0xff, 0x22, 0xe0, 0x09, 0x01, 
+0x07, 0x1c, 0x41, 0x60, 0x08, 0x1c, 0x17, 0x4a, 0x17, 0x49, 0xff, 0xf7, 
+0x27, 0xff, 0x00, 0x28, 0x07, 0xd1, 0x3c, 0x73, 0x04, 0x23, 0xa8, 0x69, 
+0x98, 0x43, 0x99, 0x04, 0xa8, 0x61, 0x08, 0x61, 0xda, 0xe7, 0x10, 0x20, 
+0x00, 0xf0, 0x20, 0xf9, 0x10, 0x20, 0xb8, 0x60, 0xff, 0xf7, 0x82, 0xff, 
+0xd2, 0xe7, 0x05, 0x1c, 0x40, 0x68, 0x00, 0xf0, 0x17, 0xf9, 0x30, 0x68, 
+0x00, 0xf0, 0x40, 0xf8, 0x00, 0x28, 0xd8, 0xd0, 0x02, 0x23, 0xb8, 0x6b, 
+0x18, 0x43, 0xb8, 0x63, 0xc4, 0xe7, 0x00, 0x00, 0xa8, 0x04, 0x00, 0x80, 
+0x25, 0x55, 0xff, 0xff, 0x00, 0x00, 0x00, 0xb0, 
+0xe8, 0x0d, 0x00, 0x80, 0x64, 0x01, 0x00, 0x80, 0xa0, 0x54, 0xff, 0xff, 
+0x85, 0x74, 0x21, 0x40, 0x90, 0xb5, 0x01, 0x20, 0x40, 0x03, 0x10, 0x49, 
+0x00, 0x27, 0x08, 0x60, 0x0f, 0x4c, 0xe0, 0x1d, 0xff, 0x30, 0x3a, 0x30, 
+0x47, 0x70, 0xe0, 0x69, 0x80, 0x00, 0x00, 0x19, 0x00, 0x69, 0x00, 0xf0, 
+0xd7, 0xf8, 0xe0, 0x69, 0x00, 0x28, 0x01, 0xd0, 0xe7, 0x61, 0x01, 0xe0, 
+0x01, 0x20, 0xe0, 0x61, 0x07, 0x48, 0x02, 0x23, 0x81, 0x6b, 0x19, 0x43, 
+0x81, 0x63, 0x27, 0x73, 0xff, 0xf7, 0x00, 0xff, 0x90, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xa8, 0x04, 0x00, 0x80, 
+0x68, 0x0e, 0x00, 0x80, 0x80, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x78, 0x88, 
+0x6d, 0x28, 0x03, 0xdb, 0x38, 0x1c, 0x00, 0xf0, 0xf7, 0xf8, 0x17, 0xe0, 
+0x80, 0x00, 0x0d, 0x49, 0x09, 0x58, 0x38, 0x1c, 0xff, 0xf7, 0xbd, 0xfe, 
+0x00, 0x28, 0x0f, 0xd1, 0x39, 0x78, 0xc9, 0x09, 0x0c, 0xd3, 0x69, 0x46, 
+0x38, 0x1c, 0x00, 0xf0, 0xcf, 0xf8, 0x68, 0x46, 0x00, 0x21, 0x00, 0xf0, 
+0x0b, 0xf8, 0x00, 0x28, 0x01, 0xd1, 0x01, 0x20, 0x00, 0xe0, 0x00, 0x20, 
+0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x01, 0x00, 0x80, 
+0xf0, 0xb5, 0x82, 0xb0, 0x02, 0x1c, 0x41, 0x4b, 0xdd, 0x1d, 0xff, 0x35, 
+0x3a, 0x35, 0x2f, 0x78, 0x00, 0x2f, 0x01, 0xd0, 0x00, 0x27, 0x00, 0xe0, 
+0x01, 0x27, 0x2f, 0x70, 0x2f, 0x78, 0xfb, 0x00, 0xdb, 0x19, 0x5b, 0x01, 
+0x3a, 0x4f, 0xdc, 0x19, 0x40, 0x78, 0x00, 0x01, 0xc7, 0x1d, 0x09, 0x37, 
+0x00, 0x20, 0x83, 0x00, 0xd6, 0x58, 0xc0, 0x46, 0xe6, 0x50, 0x01, 0x30, 
+0x04, 0x28, 0xf8, 0xd3, 0x00, 0x29, 0x0f, 0xd0, 0x00, 0x22, 0xbb, 0x08, 
+0x01, 0x93, 0x83, 0x42, 0x0b, 0xd9, 0x13, 0x1c, 0x9b, 0x00, 0xcb, 0x58, 
+0x86, 0x00, 0xa3, 0x51, 0x01, 0x9b, 0x01, 0x30, 0x01, 0x32, 0x83, 0x42, 
+0xf5, 0xd8, 0x00, 0xe0, 0x10, 0x27, 0x2b, 0x48, 0x02, 0x6d, 0x80, 0x6e, 
+0x2a, 0x49, 0x82, 0x42, 0x03, 0xd8, 0x82, 0x1a, 0xcb, 0x6c, 0x9a, 0x1a, 
+0x00, 0xe0, 0x12, 0x1a, 0xba, 0x42, 0x05, 0xd8, 0x26, 0x48, 0x81, 0x6b, 
+0x01, 0x31, 0x81, 0x63, 0x01, 0x20, 0x37, 0xe0, 0xc3, 0x19, 0xca, 0x6c, 
+0x93, 0x42, 0x08, 0xd8, 0x22, 0x4a, 0x3a, 0x43, 0x00, 0x92, 0x0a, 0x1c, 
+0x49, 0x6c, 0x09, 0x18, 0x92, 0x6c, 0x23, 0x1c, 0x12, 0xe0, 0x16, 0x1a, 
+0x00, 0x96, 0x1b, 0x49, 0x49, 0x6c, 0x09, 0x18, 0x19, 0x48, 0x82, 0x6c, 
+0x03, 0x20, 0x23, 0x1c, 0xff, 0xf7, 0x50, 0xfe, 0xb8, 0x1b, 0x18, 0x4a, 
+0x02, 0x43, 0x00, 0x92, 0xa3, 0x19, 0x14, 0x48, 0x82, 0x6c, 0x41, 0x6c, 
+0x03, 0x20, 0xff, 0xf7, 0x45, 0xfe, 0x01, 0x20, 0x0d, 0x49, 0xc0, 0x46, 
+0x68, 0x70, 0x8a, 0x69, 0x92, 0x00, 0x52, 0x18, 0x17, 0x61, 0x8a, 0x69, 
+0x00, 0x2a, 0x02, 0xd0, 0x00, 0x27, 0x8f, 0x61, 0x00, 0xe0, 0x88, 0x61, 
+0x0c, 0x48, 0x02, 0x23, 0x81, 0x6b, 0x19, 0x43, 0x81, 0x63, 0x00, 0x20, 
+0x01, 0x27, 0x0a, 0x49, 0xc0, 0x46, 0x4f, 0x72, 0x02, 0xb0, 0xf0, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0xa8, 0x04, 0x00, 0x80, 0xfc, 0xba, 0x20, 0x40, 
+0xe8, 0x0d, 0x00, 0x80, 0xf8, 0x28, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, 
+0x00, 0x00, 0x19, 0x02, 0x68, 0x0e, 0x00, 0x80, 0x98, 0x19, 0x00, 0x80, 
+0x07, 0x49, 0x8a, 0x6e, 0x10, 0x18, 0x07, 0x4a, 0xd2, 0x6c, 0x13, 0x04, 
+0x1b, 0x0c, 0x83, 0x42, 0x00, 0xd8, 0x80, 0x1a, 0x88, 0x66, 0x88, 0x6e, 
+0x03, 0x49, 0xc0, 0x46, 0x48, 0x61, 0x70, 0x47, 
+0xe8, 0x0d, 0x00, 0x80, 0xf8, 0x28, 0x00, 0x80, 0x3c, 0xef, 0x20, 0x40, 
+0x06, 0x49, 0x4a, 0x6e, 0x10, 0x18, 0x06, 0x4a, 0x12, 0x6c, 0x82, 0x42, 
+0x00, 0xd8, 0x80, 0x1a, 0x48, 0x66, 0x48, 0x6e, 0x03, 0x49, 0xc0, 0x46, 
+0x08, 0x61, 0x70, 0x47, 0xe8, 0x0d, 0x00, 0x80, 0xf8, 0x28, 0x00, 0x80, 
+0x3c, 0xef, 0x20, 0x40, 0x05, 0x22, 0x0a, 0x60, 0x82, 0x88, 0xc0, 0x46, 
+0x8a, 0x80, 0x00, 0x22, 0x4a, 0x70, 0x40, 0x88, 0xc0, 0x46, 0x48, 0x80, 
+0xca, 0x80, 0x8a, 0x60, 0xca, 0x60, 0x70, 0x47, 0x05, 0x22, 0x02, 0x60, 
+0x00, 0x22, 0x82, 0x80, 0x42, 0x70, 0x41, 0x80, 0xc2, 0x80, 0x82, 0x60, 
+0xc2, 0x60, 0x70, 0x47, 0x80, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x0e, 0x48, 
+0x41, 0x6b, 0x01, 0x31, 0x41, 0x63, 0x69, 0x46, 0x38, 0x1c, 0xff, 0xf7, 
+0xdd, 0xff, 0x38, 0x68, 0xc0, 0x46, 0x00, 0x90, 0x45, 0x20, 0x00, 0xab, 
+0x18, 0x70, 0x01, 0x27, 0xdf, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 
+0x11, 0xff, 0x00, 0x28, 0x01, 0xd1, 0x38, 0x1c, 0x00, 0xe0, 0x00, 0x20, 
+0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xa0, 0x82, 0x20, 0x40, 
+0x00, 0xb5, 0x84, 0xb0, 0xc1, 0x88, 0x09, 0x4a, 0xc0, 0x46, 0x11, 0x81, 
+0x69, 0x46, 0xff, 0xf7, 0xbd, 0xff, 0x01, 0x20, 0x40, 0x02, 0x01, 0xab, 
+0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0xf5, 0xfe, 0x01, 0x20, 
+0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 
+0x00, 0xb5, 0xff, 0xf7, 0xc3, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x01, 0x20, 
+0x03, 0x49, 0xc0, 0x46, 0x08, 0x70, 0xa1, 0x21, 0x49, 0x03, 0x88, 0x60, 
+0x00, 0x20, 0x70, 0x47, 0xa8, 0x0e, 0x00, 0x80, 0x00, 0x20, 0x04, 0x49, 
+0xc0, 0x46, 0x08, 0x70, 0xff, 0x21, 0xa1, 0x22, 0x52, 0x03, 0x01, 0x31, 
+0x91, 0x60, 0x70, 0x47, 0xa8, 0x0e, 0x00, 0x80, 0x02, 0x20, 0xa1, 0x21, 
+0x49, 0x03, 0x88, 0x60, 0x00, 0x20, 0x70, 0x47, 0x01, 0x20, 0x40, 0x02, 
+0xa1, 0x21, 0x49, 0x03, 0x88, 0x60, 0x00, 0x20, 0x70, 0x47, 0xc0, 0x88, 
+0xc0, 0x06, 0xc0, 0x0e, 0xa1, 0x21, 0x49, 0x03, 0x48, 0x61, 0x02, 0x49, 
+0xc0, 0x46, 0x88, 0x63, 0x00, 0x20, 0x70, 0x47, 0x68, 0x1a, 0x00, 0x80, 
+0x80, 0xb5, 0x84, 0xb0, 0x08, 0x49, 0x0f, 0x6b, 0x69, 0x46, 0xff, 0xf7, 
+0x71, 0xff, 0xf8, 0x06, 0xc0, 0x0e, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 
+0x00, 0x21, 0xff, 0xf7, 0xa9, 0xfe, 0x01, 0x20, 0x04, 0xb0, 0x80, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0x80, 0x00, 0x14, 0x40, 0x80, 0xb5, 0x85, 0xb0, 
+0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c, 0xff, 0xf7, 0x5b, 0xff, 0xf8, 0x88, 
+0x04, 0xa9, 0x04, 0xf0, 0xef, 0xfd, 0x01, 0xab, 0x58, 0x80, 0x01, 0xa8, 
+0x40, 0x88, 0x00, 0x28, 0x0f, 0xd0, 0x01, 0xa8, 0x40, 0x88, 0x80, 0x08, 
+0x03, 0x38, 0x80, 0x08, 0x01, 0x30, 0x04, 0x3b, 0x58, 0x70, 0x04, 0x98, 
+0x01, 0x68, 0xc0, 0x46, 0x02, 0x91, 0x40, 0x68, 0xc0, 0x46, 0x03, 0x90, 
+0x05, 0xe0, 0x00, 0xa8, 0x00, 0x78, 0x40, 0x23, 0x18, 0x43, 0x00, 0xab, 
+0x18, 0x70, 0x04, 0x98, 0xc1, 0x1d, 0x01, 0x31, 0x68, 0x46, 0xff, 0xf7, 
+0x75, 0xfe, 0x01, 0x20, 0x05, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x90, 0xb5, 0x84, 0xb0, 0x14, 0x4f, 0x39, 0x7b, 0x00, 0x29, 0x20, 0xd1, 
+0xf9, 0x1d, 0xff, 0x31, 0x3a, 0x31, 0x49, 0x78, 0x00, 0x29, 0x1a, 0xd1, 
+0x10, 0x49, 0x05, 0x22, 0x00, 0x92, 0x08, 0x22, 0x00, 0xab, 0x5a, 0x80, 
+0x98, 0x80, 0x06, 0x20, 0x00, 0xab, 0x58, 0x70, 
+0x00, 0x24, 0xdc, 0x80, 0x08, 0x68, 0xc0, 0x46, 0x02, 0x90, 0x48, 0x68, 
+0xc0, 0x46, 0x03, 0x90, 0x01, 0x20, 0x38, 0x73, 0x68, 0x46, 0x08, 0x31, 
+0xff, 0xf7, 0x4c, 0xfe, 0x00, 0x28, 0x00, 0xd0, 0x3c, 0x73, 0x04, 0xb0, 
+0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xa8, 0x04, 0x00, 0x80, 
+0x10, 0x2a, 0x00, 0x80, 0x90, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x69, 0x46, 
+0x38, 0x1c, 0xff, 0xf7, 0xf9, 0xfe, 0xba, 0x68, 0x0d, 0x4c, 0x0e, 0x48, 
+0x00, 0x2a, 0x05, 0xd1, 0x0d, 0x49, 0xff, 0xf7, 0xd6, 0xfc, 0x00, 0x28, 
+0x0c, 0xda, 0x05, 0xe0, 0xb9, 0x88, 0x0b, 0x4b, 0xff, 0xf7, 0xd1, 0xfc, 
+0x00, 0x28, 0x05, 0xda, 0x01, 0xab, 0x5c, 0x80, 0x68, 0x46, 0x00, 0x21, 
+0xff, 0xf7, 0x22, 0xfe, 0x00, 0x20, 0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x15, 0x79, 0x21, 0x40, 
+0x59, 0xcd, 0x21, 0x40, 0xf1, 0xcc, 0x21, 0x40, 0x00, 0xb5, 0xc0, 0x88, 
+0x04, 0xf0, 0x54, 0xfd, 0x00, 0x20, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 
+0xff, 0xf7, 0xe2, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xff, 0xf7, 
+0xdd, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0x01, 0x1c, 0x02, 0x20, 
+0x00, 0xf0, 0x02, 0xf8, 0x08, 0xbc, 0x18, 0x47, 0xb0, 0xb5, 0xc6, 0xb0, 
+0x04, 0x1c, 0x08, 0x1c, 0x69, 0x46, 0xff, 0xf7, 0xb5, 0xfe, 0x1b, 0x48, 
+0xff, 0xf7, 0x96, 0xfc, 0x07, 0x1c, 0x00, 0x21, 0x20, 0x1c, 0x03, 0xf0, 
+0x4f, 0xff, 0x00, 0x28, 0x1c, 0xd0, 0x20, 0x1c, 0x04, 0xa9, 0x03, 0xf0, 
+0x2d, 0xfe, 0x04, 0x98, 0x04, 0x28, 0x05, 0xd9, 0x04, 0x98, 0x80, 0x08, 
+0x03, 0x38, 0x80, 0x08, 0x01, 0x30, 0x00, 0xe0, 0x00, 0x20, 0x00, 0xab, 
+0x58, 0x70, 0x06, 0xa8, 0x00, 0x78, 0xc0, 0x46, 0xd8, 0x80, 0x04, 0x98, 
+0xc0, 0x46, 0x02, 0x90, 0x07, 0x98, 0xc0, 0x46, 0x03, 0x90, 0x04, 0x33, 
+0x08, 0xad, 0x02, 0xe0, 0x45, 0x20, 0x00, 0xab, 0x18, 0x70, 0x07, 0x49, 
+0x38, 0x1c, 0xff, 0xf7, 0x6c, 0xfc, 0x68, 0x46, 0x29, 0x1c, 0xff, 0xf7, 
+0xc3, 0xfd, 0x01, 0x20, 0x46, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x24, 0x02, 0xff, 0xff, 0x3c, 0x02, 0xff, 0xff, 0x00, 0xb5, 0x01, 0x1c, 
+0x02, 0x20, 0x00, 0xf0, 0x10, 0xf8, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 
+0x01, 0x1c, 0x01, 0x20, 0xff, 0xf7, 0xb2, 0xff, 0x08, 0xbc, 0x18, 0x47, 
+0x00, 0xb5, 0x01, 0x1c, 0x01, 0x20, 0x00, 0xf0, 0x02, 0xf8, 0x08, 0xbc, 
+0x18, 0x47, 0xf3, 0xb5, 0xc6, 0xb0, 0x0f, 0x1c, 0x69, 0x46, 0x38, 0x1c, 
+0xff, 0xf7, 0x5e, 0xfe, 0x1c, 0x48, 0xff, 0xf7, 0x3f, 0xfc, 0xba, 0x68, 
+0x04, 0x1c, 0xfc, 0x2a, 0x1f, 0xd8, 0xfd, 0x88, 0xf8, 0x68, 0xc0, 0x46, 
+0x04, 0x90, 0xf9, 0x1d, 0x09, 0x31, 0x05, 0xab, 0x00, 0x20, 0x7e, 0x78, 
+0x00, 0x2e, 0x0d, 0xdd, 0x40, 0xc9, 0x40, 0xc3, 0x40, 0xc9, 0x40, 0xc3, 
+0x40, 0xc9, 0x40, 0xc3, 0x40, 0xc9, 0x40, 0xc3, 0x01, 0x30, 0x00, 0x04, 
+0x00, 0x0c, 0x7e, 0x78, 0x86, 0x42, 0xf1, 0xdc, 0x46, 0x98, 0x04, 0xa9, 
+0x2b, 0x1c, 0xff, 0xf7, 0x2d, 0xfc, 0x00, 0x28, 0x05, 0xd0, 0x00, 0xa8, 
+0x00, 0x78, 0x40, 0x23, 0x18, 0x43, 0x00, 0xab, 0x18, 0x70, 0x07, 0x49, 
+0x20, 0x1c, 0xff, 0xf7, 0x12, 0xfc, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 
+0x69, 0xfd, 0x01, 0x20, 0x48, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x24, 0x02, 0xff, 0xff, 0x3c, 0x02, 0xff, 0xff, 0x00, 0xb5, 0xff, 0xf7, 
+0x35, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb5, 
+0xc6, 0xb0, 0x07, 0x1c, 0xfc, 0x88, 0x25, 0x4d, 0x68, 0x68, 0x01, 0x30, 
+0x69, 0x46, 0x68, 0x60, 0x38, 0x1c, 0xff, 0xf7, 0x0f, 0xfe, 0x10, 0x2c, 
+0x08, 0xd3, 0x00, 0xa8, 0x00, 0x78, 0x40, 0x23, 0x18, 0x43, 0x00, 0xab, 
+0x18, 0x70, 0x02, 0x20, 0xd8, 0x80, 0x17, 0xe0, 0x78, 0x78, 0x82, 0x00, 
+0xfb, 0x1d, 0x09, 0x33, 0x00, 0x20, 0xb9, 0x68, 0x00, 0x2a, 0x15, 0xd9, 
+0x40, 0xcb, 0x0f, 0x1c, 0x01, 0x31, 0xbe, 0x42, 0x0d, 0xd0, 0x00, 0xaa, 
+0x12, 0x78, 0x40, 0x23, 0x1a, 0x43, 0x00, 0xab, 0x1a, 0x70, 0x04, 0x22, 
+0xda, 0x80, 0x02, 0x90, 0x03, 0x91, 0x04, 0x33, 0x68, 0x46, 0x00, 0x21, 
+0x15, 0xe0, 0x01, 0x30, 0x90, 0x42, 0xe9, 0xd3, 0x00, 0xab, 0x5c, 0x70, 
+0x02, 0x94, 0x69, 0x68, 0xc0, 0x46, 0x03, 0x91, 0xa2, 0x00, 0x00, 0x20, 
+0x10, 0x33, 0x00, 0x2a, 0x05, 0xd9, 0x0f, 0x1c, 0x80, 0xc3, 0x01, 0x30, 
+0x01, 0x31, 0x90, 0x42, 0xf9, 0xd3, 0x68, 0x46, 0x04, 0xa9, 0xff, 0xf7, 
+0x11, 0xfd, 0x01, 0x20, 0x46, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x1c, 0x03, 0x00, 0x80, 0x90, 0xb4, 0x22, 0x48, 0x00, 0x68, 0x01, 0x21, 
+0x42, 0x09, 0x00, 0xd3, 0x00, 0x21, 0x00, 0x27, 0x3a, 0x1c, 0x43, 0x0b, 
+0x00, 0xd2, 0x02, 0x22, 0x11, 0x43, 0x1d, 0x4a, 0x20, 0x24, 0xd3, 0x68, 
+0x01, 0x2b, 0x2c, 0xd1, 0x80, 0x0a, 0x00, 0xd2, 0x00, 0x24, 0x0c, 0x43, 
+0x20, 0x1c, 0x1b, 0x23, 0xdb, 0x01, 0xd1, 0x18, 0x09, 0x8b, 0x09, 0x0b, 
+0x00, 0xd2, 0x04, 0x27, 0x38, 0x43, 0xd1, 0x6f, 0x09, 0x0a, 0x06, 0xd2, 
+0xd1, 0x1d, 0x79, 0x31, 0x09, 0x68, 0x09, 0x0a, 0x01, 0xd3, 0x08, 0x23, 
+0x18, 0x43, 0xe3, 0x23, 0x1b, 0x01, 0xd1, 0x18, 0x89, 0x78, 0x03, 0x29, 
+0x02, 0xd1, 0xff, 0x23, 0x01, 0x33, 0x18, 0x43, 0x0b, 0x49, 0x09, 0x6a, 
+0x10, 0x22, 0x4b, 0x0a, 0x00, 0xd2, 0x00, 0x22, 0x10, 0x43, 0x89, 0x07, 
+0x89, 0x0f, 0x89, 0x01, 0x08, 0x43, 0x90, 0xbc, 0x70, 0x47, 0x40, 0x0c, 
+0x00, 0xd2, 0x00, 0x24, 0x0c, 0x43, 0x20, 0x1c, 0xec, 0xe7, 0x00, 0x00, 
+0x00, 0x00, 0x10, 0x40, 0xe8, 0x0d, 0x00, 0x80, 0xc0, 0x00, 0x18, 0x40, 
+0xf0, 0xb5, 0x33, 0x4d, 0x28, 0x1c, 0x05, 0xf0, 0x6b, 0xf8, 0x32, 0x49, 
+0xe3, 0x23, 0x1b, 0x01, 0xcf, 0x18, 0xba, 0x78, 0x30, 0x4e, 0x00, 0x20, 
+0xcc, 0x1d, 0x79, 0x34, 0x05, 0x2a, 0x53, 0xd2, 0x01, 0xa3, 0x9b, 0x5c, 
+0x5b, 0x00, 0x9f, 0x44, 0x02, 0x0e, 0x23, 0x3c, 0x3e, 0x00, 0x01, 0x21, 
+0xb9, 0x70, 0xb0, 0x60, 0xff, 0xf7, 0x98, 0xff, 0x04, 0x23, 0x98, 0x43, 
+0x00, 0xf0, 0x62, 0xf8, 0x14, 0x22, 0x28, 0x1c, 0x0e, 0xe0, 0xff, 0xf7, 
+0x8f, 0xff, 0xc0, 0x08, 0x06, 0xd3, 0xb1, 0x68, 0x48, 0x1c, 0xb0, 0x60, 
+0x0a, 0x29, 0x03, 0xd9, 0x04, 0x20, 0x00, 0xe0, 0x02, 0x20, 0xb8, 0x70, 
+0x02, 0x22, 0x28, 0x1c, 0x00, 0x21, 0x05, 0xf0, 0x07, 0xf8, 0xf0, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0x80, 0x23, 0xc8, 0x6f, 0x18, 0x43, 0xc8, 0x67, 
+0x18, 0x4e, 0xc0, 0x46, 0x30, 0x60, 0x03, 0x20, 0xb8, 0x70, 0x28, 0x1c, 
+0x16, 0x4a, 0x00, 0x21, 0x04, 0xf0, 0xf6, 0xff, 0x11, 0x48, 0x04, 0x23, 
+0xc1, 0x6f, 0x99, 0x43, 0xc1, 0x67, 0x31, 0x60, 0x20, 0x68, 0x18, 0x43, 
+0x20, 0x60, 0x70, 0x60, 0xe3, 0xe7, 0x05, 0x21, 0xb9, 0x70, 0x51, 0x21, 
+0x89, 0x03, 0x08, 0x62, 0x04, 0x23, 0x20, 0x68, 0x98, 0x43, 0x20, 0x60, 
+0x09, 0x4e, 0xc0, 0x46, 0x70, 0x60, 0xff, 0xf7, 0x55, 0xff, 0x04, 0x23, 
+0x18, 0x43, 0x00, 0xf0, 0x1f, 0xf8, 0xd0, 0xe7, 
+0x06, 0x20, 0xb8, 0x70, 0xcd, 0xe7, 0x00, 0x00, 0x79, 0x7c, 0x21, 0x40, 
+0xe8, 0x0d, 0x00, 0x80, 0x1c, 0x03, 0x00, 0x80, 0x00, 0x01, 0x11, 0x00, 
+0x88, 0x13, 0x00, 0x00, 0x00, 0xb5, 0x00, 0x20, 0x04, 0x49, 0xc0, 0x46, 
+0x88, 0x70, 0x04, 0x48, 0x01, 0x22, 0x00, 0x21, 0x04, 0xf0, 0xc0, 0xff, 
+0x08, 0xbc, 0x18, 0x47, 0x18, 0x1c, 0x00, 0x80, 0x79, 0x7c, 0x21, 0x40, 
+0x90, 0xb5, 0x07, 0x1c, 0x30, 0x48, 0x00, 0x68, 0x01, 0x1c, 0x7a, 0x08, 
+0x02, 0xd3, 0x10, 0x23, 0x98, 0x43, 0x01, 0xe0, 0x10, 0x23, 0x18, 0x43, 
+0xba, 0x08, 0x03, 0xd3, 0x01, 0x23, 0x1b, 0x03, 0x98, 0x43, 0x02, 0xe0, 
+0x01, 0x23, 0x1b, 0x03, 0x18, 0x43, 0x88, 0x42, 0x02, 0xd0, 0x01, 0x21, 
+0x09, 0x05, 0x08, 0x60, 0x25, 0x4c, 0xe0, 0x68, 0x01, 0x28, 0x1e, 0xd1, 
+0x1b, 0x23, 0xdb, 0x01, 0xe0, 0x18, 0x00, 0x8b, 0xf9, 0x08, 0x04, 0xd3, 
+0x01, 0x23, 0xdb, 0x02, 0x01, 0x1c, 0x99, 0x43, 0x01, 0xe0, 0x01, 0x21, 
+0xc9, 0x02, 0x81, 0x42, 0x02, 0xd0, 0x00, 0x20, 0x02, 0xf0, 0x20, 0xfe, 
+0x08, 0x21, 0x39, 0x40, 0x1a, 0x48, 0x03, 0xd0, 0x80, 0x23, 0xe1, 0x6f, 
+0x99, 0x43, 0x02, 0xe0, 0x80, 0x23, 0xe1, 0x6f, 0x19, 0x43, 0xe1, 0x67, 
+0x01, 0x60, 0x16, 0x48, 0x01, 0x6a, 0x78, 0x09, 0x03, 0xd3, 0xff, 0x20, 
+0x01, 0x30, 0x08, 0x43, 0x03, 0xe0, 0xff, 0x23, 0x08, 0x1c, 0x01, 0x33, 
+0x98, 0x43, 0x80, 0x08, 0x80, 0x00, 0xba, 0x09, 0x92, 0x07, 0x92, 0x0f, 
+0x10, 0x43, 0x88, 0x42, 0x02, 0xd0, 0x0d, 0x49, 0xc0, 0x46, 0x08, 0x62, 
+0xe1, 0x68, 0x01, 0x29, 0x08, 0xd1, 0x79, 0x0a, 0x06, 0xd3, 0xff, 0x23, 
+0x04, 0x33, 0x18, 0x40, 0x03, 0x28, 0x01, 0xd1, 0xff, 0xf7, 0x90, 0xff, 
+0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 
+0xe8, 0x0d, 0x00, 0x80, 0x00, 0x01, 0x11, 0x00, 0xc0, 0x00, 0x18, 0x40, 
+0xc0, 0x00, 0x18, 0x00, 0x80, 0xb5, 0xff, 0xf7, 0xc1, 0xfe, 0x80, 0x09, 
+0x12, 0xd2, 0x0b, 0x48, 0x41, 0x78, 0x00, 0x29, 0x0e, 0xd1, 0x01, 0x21, 
+0x41, 0x70, 0x00, 0x27, 0x08, 0x48, 0x06, 0xe0, 0x02, 0x20, 0x03, 0xf0, 
+0x03, 0xf8, 0x07, 0x20, 0x02, 0xf0, 0xd2, 0xff, 0x38, 0x1c, 0xff, 0xf7, 
+0x5b, 0xfa, 0xf5, 0xe7, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
+0x18, 0x1c, 0x00, 0x80, 0xf4, 0x01, 0xff, 0xff, 0x00, 0xb5, 0x84, 0xb0, 
+0x69, 0x46, 0xff, 0xf7, 0x69, 0xfc, 0xff, 0xf7, 0x9d, 0xfe, 0x01, 0xab, 
+0x58, 0x80, 0x08, 0x48, 0x00, 0x68, 0xc0, 0x46, 0x02, 0x90, 0x07, 0x48, 
+0x00, 0x6a, 0xc0, 0x46, 0x03, 0x90, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 
+0x99, 0xfb, 0x01, 0x20, 0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
+0x00, 0x00, 0x10, 0x40, 0xc0, 0x00, 0x18, 0x40, 0x80, 0xb5, 0x84, 0xb0, 
+0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c, 0xff, 0xf7, 0x49, 0xfc, 0xf8, 0x88, 
+0xff, 0xf7, 0x4a, 0xff, 0xff, 0xf7, 0x7a, 0xfe, 0x01, 0xab, 0x58, 0x80, 
+0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0x7e, 0xfb, 0x01, 0x20, 0x04, 0xb0, 
+0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xb0, 0xb5, 0xc6, 0xb0, 0xc7, 0x88, 
+0x69, 0x46, 0xff, 0xf7, 0x33, 0xfc, 0x01, 0x24, 0x63, 0x02, 0x9f, 0x42, 
+0x0a, 0xd3, 0x00, 0xa8, 0x00, 0x78, 0x40, 0x23, 0x18, 0x43, 0x00, 0xab, 
+0x18, 0x70, 0x02, 0x20, 0xd8, 0x80, 0x68, 0x46, 0x00, 0x21, 0x16, 0xe0, 
+0x0e, 0x48, 0xff, 0xf7, 0x05, 0xfa, 0x05, 0x1c, 0x38, 0x1c, 0x04, 0xa9, 
+0x03, 0xf0, 0xa2, 0xfb, 0x0b, 0x49, 0x28, 0x1c, 
+0xff, 0xf7, 0xfd, 0xf9, 0x10, 0x20, 0x00, 0xab, 0x58, 0x70, 0x04, 0x98, 
+0xc0, 0x46, 0x02, 0x90, 0x05, 0x98, 0xc0, 0x46, 0x03, 0x90, 0x68, 0x46, 
+0x06, 0xa9, 0xff, 0xf7, 0x4b, 0xfb, 0x20, 0x1c, 0x46, 0xb0, 0xb0, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0x24, 0x02, 0xff, 0xff, 0x3c, 0x02, 0xff, 0xff, 
+0xf0, 0xb5, 0xc6, 0xb0, 0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c, 0xff, 0xf7, 
+0xfb, 0xfb, 0xfc, 0x88, 0x78, 0x78, 0x01, 0x25, 0x10, 0x28, 0x02, 0xd1, 
+0x43, 0x01, 0x9c, 0x42, 0x09, 0xd3, 0x00, 0xa8, 0x00, 0x78, 0x40, 0x23, 
+0x18, 0x43, 0x00, 0xab, 0x18, 0x70, 0x02, 0x20, 0xd8, 0x80, 0x04, 0x33, 
+0x2c, 0xe0, 0xb8, 0x68, 0xc0, 0x46, 0x04, 0x90, 0xf8, 0x68, 0xc0, 0x46, 
+0x05, 0x90, 0x06, 0xaa, 0xfb, 0x1d, 0x09, 0x33, 0x00, 0x21, 0x78, 0x78, 
+0x00, 0x28, 0x0d, 0xdd, 0x00, 0x20, 0x40, 0xcb, 0x40, 0xc2, 0x01, 0x30, 
+0x00, 0x04, 0x00, 0x0c, 0x04, 0x28, 0xf8, 0xdb, 0x48, 0x1c, 0x01, 0x04, 
+0x09, 0x0c, 0x78, 0x78, 0x88, 0x42, 0xf1, 0xdc, 0x0d, 0x48, 0xff, 0xf7, 
+0xaf, 0xf9, 0x06, 0x1c, 0x20, 0x1c, 0x04, 0xa9, 0x03, 0xf0, 0x76, 0xfb, 
+0x0a, 0x49, 0x30, 0x1c, 0xff, 0xf7, 0xa7, 0xf9, 0x38, 0x68, 0xc0, 0x46, 
+0x00, 0x90, 0x00, 0x20, 0x00, 0xab, 0x58, 0x70, 0x68, 0x46, 0x00, 0x21, 
+0xff, 0xf7, 0xf8, 0xfa, 0x28, 0x1c, 0x46, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x00, 0x24, 0x02, 0xff, 0xff, 0x3c, 0x02, 0xff, 0xff, 
+0xf0, 0xb5, 0x84, 0xb0, 0x04, 0x1c, 0x00, 0x27, 0xe6, 0x88, 0xa2, 0x68, 
+0x47, 0x49, 0x08, 0x79, 0x00, 0x28, 0x08, 0xd0, 0x00, 0x2e, 0x01, 0xd0, 
+0x01, 0x2e, 0x01, 0xd1, 0x01, 0x27, 0x01, 0xe0, 0x04, 0x2e, 0x00, 0xd1, 
+0x03, 0x26, 0x01, 0x25, 0x41, 0x48, 0x05, 0x2e, 0x66, 0xd2, 0x02, 0xa3, 
+0x9b, 0x5d, 0x5b, 0x00, 0x9f, 0x44, 0x00, 0x1c, 0x03, 0x06, 0x08, 0x0c, 
+0x10, 0x00, 0x85, 0x83, 0x00, 0x23, 0x03, 0xe0, 0x85, 0x83, 0x05, 0xe0, 
+0x00, 0x23, 0x83, 0x83, 0xc3, 0x83, 0x06, 0xe0, 0x00, 0x23, 0x83, 0x83, 
+0xc5, 0x83, 0x02, 0xe0, 0xff, 0x23, 0x01, 0x33, 0x83, 0x83, 0xcb, 0x1d, 
+0x79, 0x33, 0x1e, 0x89, 0x01, 0x23, 0x5b, 0x02, 0x9e, 0x42, 0x02, 0xdb, 
+0xd2, 0x07, 0xd2, 0x0f, 0x00, 0xe0, 0x01, 0x22, 0x6d, 0x23, 0x5b, 0x01, 
+0xc9, 0x18, 0x09, 0x88, 0xff, 0x23, 0xe1, 0x33, 0x99, 0x43, 0x01, 0x23, 
+0x19, 0x43, 0x86, 0x8b, 0xff, 0x33, 0x9e, 0x42, 0x0d, 0xd1, 0xff, 0x20, 
+0xe1, 0x30, 0x08, 0x43, 0x00, 0x2a, 0x04, 0xd1, 0x01, 0x23, 0x9b, 0x02, 
+0x98, 0x43, 0x01, 0x1c, 0x20, 0xe0, 0x01, 0x21, 0x89, 0x02, 0x01, 0x43, 
+0x1c, 0xe0, 0x01, 0x2e, 0x0a, 0xd1, 0xc0, 0x8b, 0x01, 0x28, 0x04, 0xd1, 
+0x60, 0x23, 0x19, 0x43, 0x00, 0x2a, 0x13, 0xd0, 0x0c, 0xe0, 0x20, 0x23, 
+0x19, 0x43, 0x0f, 0xe0, 0x00, 0x2e, 0x0d, 0xd1, 0xc0, 0x8b, 0x01, 0x28, 
+0x08, 0xd1, 0xff, 0x23, 0x81, 0x33, 0x19, 0x43, 0x00, 0x2a, 0x05, 0xd0, 
+0x01, 0x23, 0x9b, 0x02, 0x19, 0x43, 0x01, 0xe0, 0x80, 0x23, 0x19, 0x43, 
+0x04, 0x20, 0x02, 0xf0, 0x8d, 0xfc, 0x09, 0x21, 0x49, 0x02, 0x00, 0x20, 
+0x02, 0xf0, 0x88, 0xfc, 0x00, 0x2f, 0x02, 0xd1, 0x00, 0x20, 0x12, 0xe0, 
+0xff, 0xe7, 0x69, 0x46, 0x20, 0x1c, 0xff, 0xf7, 0x2b, 0xfb, 0x00, 0xa8, 
+0x00, 0x78, 0x40, 0x23, 0x18, 0x43, 0x00, 0xab, 0x18, 0x70, 0x02, 0x20, 
+0xd8, 0x80, 0x68, 0x46, 0x00, 0x21, 0x04, 0x33, 0xff, 0xf7, 0x5e, 0xfa, 
+0x28, 0x1c, 0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x00, 0xe8, 0x0d, 0x00, 0x80, 0xe8, 0x1b, 0x00, 0x80, 
+0xc0, 0x88, 0x51, 0x21, 0x89, 0x03, 0x08, 0x62, 0x00, 0x20, 0x70, 0x47, 
+0x80, 0xb5, 0x16, 0x4f, 0xf8, 0x68, 0x01, 0x28, 0x07, 0xd1, 0x37, 0x23, 
+0x9b, 0x01, 0xf8, 0x18, 0xc0, 0x89, 0x80, 0x21, 0x01, 0x43, 0x1b, 0x20, 
+0x07, 0xe0, 0x6d, 0x23, 0x5b, 0x01, 0xf8, 0x18, 0x00, 0x8b, 0x01, 0x21, 
+0x49, 0x03, 0x01, 0x43, 0x10, 0x20, 0x02, 0xf0, 0x4b, 0xfc, 0x01, 0x20, 
+0x07, 0x23, 0x5b, 0x02, 0xf9, 0x18, 0x88, 0x83, 0xc8, 0x83, 0x1b, 0x23, 
+0xdb, 0x01, 0xf8, 0x18, 0x00, 0x8b, 0x01, 0x23, 0x1b, 0x03, 0x98, 0x43, 
+0x41, 0x21, 0x09, 0x02, 0x01, 0x43, 0x00, 0x20, 0x02, 0xf0, 0x38, 0xfc, 
+0x00, 0x20, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xe8, 0x0d, 0x00, 0x80, 
+0x80, 0xb5, 0x17, 0x4f, 0xf8, 0x68, 0x01, 0x28, 0x08, 0xd1, 0x37, 0x23, 
+0x9b, 0x01, 0xf8, 0x18, 0xc0, 0x89, 0x80, 0x23, 0x98, 0x43, 0x01, 0x1c, 
+0x1b, 0x20, 0x08, 0xe0, 0x6d, 0x23, 0x5b, 0x01, 0xf8, 0x18, 0x00, 0x8b, 
+0x01, 0x23, 0x5b, 0x03, 0x98, 0x43, 0x01, 0x1c, 0x10, 0x20, 0x02, 0xf0, 
+0x19, 0xfc, 0xff, 0x20, 0x07, 0x23, 0x5b, 0x02, 0xf9, 0x18, 0x01, 0x30, 
+0x88, 0x83, 0x1b, 0x23, 0xdb, 0x01, 0xf8, 0x18, 0x00, 0x8b, 0x41, 0x23, 
+0x1b, 0x02, 0x98, 0x43, 0x09, 0x21, 0x49, 0x02, 0x01, 0x43, 0x00, 0x20, 
+0x02, 0xf0, 0x06, 0xfc, 0x00, 0x20, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0xe8, 0x0d, 0x00, 0x80, 0x80, 0xb5, 0x84, 0xb0, 0x08, 0x49, 0xcf, 0x6a, 
+0x69, 0x46, 0xff, 0xf7, 0xa5, 0xfa, 0xb8, 0x05, 0x80, 0x0d, 0x01, 0xab, 
+0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0xdd, 0xf9, 0x01, 0x20, 
+0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x40, 0x00, 0x14, 0x40, 
+0xc0, 0x88, 0x9f, 0x23, 0x18, 0x40, 0x05, 0x49, 0xc9, 0x6a, 0x1b, 0x23, 
+0x5b, 0x01, 0x19, 0x40, 0x08, 0x43, 0x03, 0x49, 0xc0, 0x46, 0xc8, 0x62, 
+0x00, 0x20, 0x70, 0x47, 0x40, 0x00, 0x14, 0x40, 0x40, 0x00, 0x14, 0x00, 
+0x80, 0xb5, 0x84, 0xb0, 0x0d, 0x49, 0x0f, 0x6a, 0x01, 0x2f, 0x01, 0xd1, 
+0xff, 0x03, 0x07, 0xe0, 0x02, 0x2f, 0x01, 0xd1, 0x3f, 0x03, 0x03, 0xe0, 
+0x00, 0x2f, 0x01, 0xd1, 0x01, 0x27, 0xff, 0x02, 0x69, 0x46, 0xff, 0xf7, 
+0x71, 0xfa, 0x01, 0xab, 0x5f, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 
+0xab, 0xf9, 0x01, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x00, 0x20, 0x14, 0x40, 0xc2, 0x88, 0xa1, 0x20, 0x40, 0x03, 0x00, 0x21, 
+0x01, 0x23, 0x5b, 0x03, 0x9a, 0x42, 0x01, 0xd1, 0x02, 0x22, 0x04, 0xe0, 
+0x01, 0x23, 0xdb, 0x03, 0x9a, 0x42, 0x02, 0xd1, 0x01, 0x22, 0x02, 0x62, 
+0x00, 0xe0, 0x01, 0x62, 0x08, 0x1c, 0x70, 0x47, 0x90, 0xb5, 0x84, 0xb0, 
+0x07, 0x1c, 0x02, 0xf0, 0xb7, 0xfb, 0x69, 0x46, 0x04, 0x1c, 0x38, 0x1c, 
+0xff, 0xf7, 0x46, 0xfa, 0x01, 0xab, 0x5c, 0x80, 0x09, 0x4f, 0xf8, 0x6d, 
+0xc0, 0x46, 0x02, 0x90, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0x7c, 0xf9, 
+0xf8, 0x6d, 0xc0, 0x07, 0xc0, 0x0f, 0x05, 0x49, 0xc0, 0x46, 0x88, 0x62, 
+0x01, 0x20, 0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
+0x10, 0x2a, 0x00, 0x80, 0xe8, 0x1b, 0x00, 0x80, 0xc0, 0x88, 0x02, 0x49, 
+0xc0, 0x46, 0x48, 0x61, 0x00, 0x20, 0x70, 0x47, 0x80, 0x00, 0x14, 0x00, 
+0x00, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0xff, 0xf7, 0x1f, 0xfa, 0x06, 0x48, 
+0xc0, 0x68, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 
+0x00, 0x21, 0xff, 0xf7, 0x57, 0xf9, 0x01, 0x20, 0x04, 0xb0, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x00, 0x80, 0x00, 0x14, 0x40, 0xc0, 0x88, 0x02, 0x49, 
+0xc0, 0x46, 0xc8, 0x60, 0x00, 0x20, 0x70, 0x47, 0x80, 0x00, 0x14, 0x00, 
+0x80, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0x87, 0x68, 0xff, 0xf7, 0x02, 0xfa, 
+0x20, 0x2f, 0x07, 0xd2, 0x78, 0x00, 0x0c, 0x49, 0x40, 0x18, 0x1b, 0x23, 
+0xdb, 0x01, 0xc0, 0x18, 0x00, 0x8b, 0x06, 0xe0, 0x00, 0xa8, 0x00, 0x78, 
+0x40, 0x23, 0x18, 0x43, 0x00, 0xab, 0x18, 0x70, 0x02, 0x20, 0x01, 0xab, 
+0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0x2b, 0xf9, 0x01, 0x20, 
+0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xe8, 0x0d, 0x00, 0x80, 
+0x00, 0xb5, 0x84, 0xb0, 0xc1, 0x88, 0x82, 0x68, 0x20, 0x2a, 0x04, 0xd2, 
+0x10, 0x1c, 0x02, 0xf0, 0x2f, 0xfb, 0x00, 0x20, 0x10, 0xe0, 0x69, 0x46, 
+0xff, 0xf7, 0xd6, 0xf9, 0x00, 0xa8, 0x00, 0x78, 0x40, 0x23, 0x18, 0x43, 
+0x00, 0xab, 0x18, 0x70, 0x02, 0x20, 0xd8, 0x80, 0x68, 0x46, 0x00, 0x21, 
+0x04, 0x33, 0xff, 0xf7, 0x09, 0xf9, 0x01, 0x20, 0x04, 0xb0, 0x08, 0xbc, 
+0x18, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0xc7, 0x88, 0x69, 0x46, 0xff, 0xf7, 
+0xbf, 0xf9, 0x10, 0x48, 0xfe, 0xf7, 0xa0, 0xff, 0x02, 0x20, 0x39, 0x1c, 
+0x03, 0xf0, 0x5a, 0xfa, 0x00, 0x28, 0x06, 0xd0, 0x02, 0x20, 0x39, 0x1c, 
+0x03, 0xf0, 0x94, 0xf9, 0x01, 0xab, 0x58, 0x80, 0x02, 0xe0, 0x45, 0x20, 
+0x00, 0xab, 0x18, 0x70, 0x07, 0x49, 0x20, 0x1c, 0xfe, 0xf7, 0x8d, 0xff, 
+0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0xe4, 0xf8, 0x01, 0x20, 0x04, 0xb0, 
+0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x24, 0x02, 0xff, 0xff, 
+0x3c, 0x02, 0xff, 0xff, 0xb0, 0xb5, 0x84, 0xb0, 0xc7, 0x88, 0x69, 0x46, 
+0x84, 0x68, 0xff, 0xf7, 0x93, 0xf9, 0x10, 0x48, 0xfe, 0xf7, 0x74, 0xff, 
+0x0f, 0x4a, 0x02, 0x20, 0x39, 0x1c, 0xfe, 0xf7, 0x71, 0xff, 0x00, 0x28, 
+0x06, 0xd0, 0x0d, 0x4b, 0x02, 0x20, 0x39, 0x1c, 0x22, 0x1c, 0xfe, 0xf7, 
+0x6a, 0xff, 0x02, 0xe0, 0x45, 0x20, 0x00, 0xab, 0x18, 0x70, 0x09, 0x49, 
+0x28, 0x1c, 0xfe, 0xf7, 0x60, 0xff, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 
+0xb7, 0xf8, 0x01, 0x20, 0x04, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x24, 0x02, 0xff, 0xff, 0xb9, 0xb8, 0x21, 0x40, 0x7b, 0xb7, 0x21, 0x40, 
+0x3c, 0x02, 0xff, 0xff, 0x00, 0xb5, 0xff, 0xf7, 0x7f, 0xf9, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x20, 0x70, 0x47, 0x80, 0xb4, 0xc2, 0x88, 0x19, 0x4b, 
+0xa1, 0x21, 0x49, 0x03, 0x00, 0x2a, 0x03, 0xd1, 0x18, 0x6b, 0x10, 0x23, 
+0x98, 0x43, 0x04, 0xe0, 0x01, 0x2a, 0x04, 0xd1, 0x18, 0x6b, 0x10, 0x23, 
+0x18, 0x43, 0x48, 0x61, 0x1f, 0xe0, 0x02, 0x2a, 0x1d, 0xd1, 0xc2, 0x68, 
+0x87, 0x68, 0x00, 0x20, 0x3b, 0x1c, 0xc3, 0x40, 0xdb, 0x07, 0xdb, 0x0f, 
+0x9b, 0x02, 0x03, 0x43, 0x0b, 0x61, 0x01, 0x30, 0x00, 0x04, 0x00, 0x0c, 
+0x20, 0x28, 0xf3, 0xdb, 0x00, 0x20, 0x13, 0x1c, 0xc3, 0x40, 0xdb, 0x07, 
+0xdb, 0x0f, 0x9b, 0x02, 0xc7, 0x1d, 0x19, 0x37, 0x3b, 0x43, 0x0b, 0x61, 
+0x01, 0x30, 0x00, 0x04, 0x00, 0x0c, 0x20, 0x28, 0xf1, 0xdb, 0x00, 0x20, 
+0x80, 0xbc, 0x70, 0x47, 0x80, 0x00, 0x14, 0x40, 0x90, 0xb4, 0xc2, 0x88, 
+0x81, 0x68, 0x10, 0x02, 0x12, 0x0a, 0x10, 0x43, 0x02, 0x04, 0x12, 0x0c, 
+0x0f, 0x48, 0xc0, 0x46, 0x02, 0x60, 0x0f, 0x4f, 0x65, 0x23, 0x5b, 0x01, 
+0xfb, 0x18, 0x9a, 0x83, 0x0a, 0x0c, 0x14, 0x02, 
+0x12, 0x12, 0x22, 0x43, 0x12, 0x04, 0x12, 0x0c, 0x42, 0x60, 0xda, 0x83, 
+0x09, 0x04, 0x09, 0x0c, 0x0a, 0x02, 0x09, 0x0a, 0x11, 0x43, 0x09, 0x04, 
+0x09, 0x0c, 0x81, 0x60, 0x33, 0x23, 0x9b, 0x01, 0xf8, 0x18, 0x01, 0x80, 
+0x00, 0x20, 0x90, 0xbc, 0x70, 0x47, 0x00, 0x00, 0x40, 0x00, 0x14, 0x00, 
+0xe8, 0x0d, 0x00, 0x80, 0xb0, 0xb5, 0x84, 0xb0, 0x13, 0x49, 0x0a, 0x68, 
+0x12, 0x04, 0x12, 0x0c, 0x13, 0x02, 0x12, 0x12, 0x13, 0x43, 0x4a, 0x68, 
+0x12, 0x04, 0x12, 0x0c, 0x1f, 0x1c, 0x13, 0x02, 0x12, 0x12, 0x13, 0x43, 
+0x89, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x0a, 0x02, 0x09, 0x12, 0x11, 0x43, 
+0x0c, 0x04, 0x24, 0x0c, 0x69, 0x46, 0x1d, 0x1c, 0xff, 0xf7, 0xe4, 0xf8, 
+0x01, 0xab, 0x5f, 0x80, 0x28, 0x04, 0x20, 0x43, 0x02, 0x90, 0x68, 0x46, 
+0x00, 0x21, 0xff, 0xf7, 0x1b, 0xf8, 0x01, 0x20, 0x04, 0xb0, 0xb0, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0x40, 0x00, 0x14, 0x40, 0xc1, 0x88, 0x82, 0x68, 
+0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, 0x00, 0x04, 0x00, 0x0c, 0x0a, 0x49, 
+0xc0, 0x46, 0xc8, 0x60, 0x10, 0x0c, 0x03, 0x02, 0x00, 0x12, 0x18, 0x43, 
+0x00, 0x04, 0x00, 0x0c, 0x08, 0x61, 0x10, 0x04, 0x00, 0x0c, 0x02, 0x02, 
+0x00, 0x0a, 0x10, 0x43, 0x00, 0x04, 0x00, 0x0c, 0x48, 0x61, 0x00, 0x20, 
+0x70, 0x47, 0x00, 0x00, 0x40, 0x00, 0x14, 0x00, 0x90, 0xb5, 0x84, 0xb0, 
+0x16, 0x4b, 0xd9, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x0a, 0x02, 0x09, 0x12, 
+0x11, 0x43, 0x1a, 0x69, 0x12, 0x04, 0x12, 0x0c, 0x17, 0x02, 0x12, 0x12, 
+0x3a, 0x43, 0x5b, 0x69, 0x1b, 0x04, 0x1b, 0x0c, 0x1f, 0x02, 0x1b, 0x12, 
+0x3b, 0x43, 0x1f, 0x04, 0x3f, 0x0c, 0x05, 0x23, 0x00, 0x93, 0x84, 0x88, 
+0x01, 0xab, 0x1c, 0x80, 0x00, 0x24, 0x04, 0x3b, 0x5c, 0x70, 0x40, 0x88, 
+0x00, 0xab, 0x58, 0x80, 0xd9, 0x80, 0x10, 0x04, 0x38, 0x43, 0x02, 0x90, 
+0x03, 0x94, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0xcb, 0xff, 0x01, 0x20, 
+0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x40, 0x00, 0x14, 0x40, 
+0x00, 0xb5, 0x84, 0xb0, 0x0b, 0x49, 0x8a, 0x6a, 0x05, 0x21, 0x00, 0x91, 
+0x81, 0x88, 0x01, 0xab, 0x19, 0x80, 0x00, 0x21, 0x04, 0x3b, 0x59, 0x70, 
+0x40, 0x88, 0x00, 0xab, 0x58, 0x80, 0xda, 0x80, 0x02, 0x91, 0x03, 0x91, 
+0x68, 0x46, 0xfe, 0xf7, 0xaf, 0xff, 0x01, 0x20, 0x04, 0xb0, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x00, 0xc0, 0x00, 0x14, 0x40, 0xc0, 0x88, 0x02, 0x49, 
+0xc0, 0x46, 0x88, 0x62, 0x00, 0x20, 0x70, 0x47, 0xc0, 0x00, 0x14, 0x00, 
+0x00, 0xb5, 0x84, 0xb0, 0x0b, 0x49, 0x0a, 0x6a, 0x05, 0x21, 0x00, 0x91, 
+0x81, 0x88, 0x01, 0xab, 0x19, 0x80, 0x00, 0x21, 0x04, 0x3b, 0x59, 0x70, 
+0x40, 0x88, 0x00, 0xab, 0x58, 0x80, 0xda, 0x80, 0x02, 0x91, 0x03, 0x91, 
+0x68, 0x46, 0xfe, 0xf7, 0x8b, 0xff, 0x01, 0x20, 0x04, 0xb0, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x00, 0xc0, 0x00, 0x14, 0x40, 0xc0, 0x88, 0x02, 0x49, 
+0xc0, 0x46, 0x08, 0x62, 0x00, 0x20, 0x70, 0x47, 0xc0, 0x00, 0x14, 0x00, 
+0x00, 0xb5, 0xc0, 0x88, 0x02, 0x49, 0xfe, 0xf7, 0x1c, 0xfe, 0x00, 0x20, 
+0x08, 0xbc, 0x18, 0x47, 0x75, 0x02, 0xff, 0xff, 0x00, 0xb5, 0x84, 0xb0, 
+0x69, 0x46, 0xff, 0xf7, 0x2d, 0xf8, 0x06, 0x48, 0x00, 0x6b, 0x01, 0xab, 
+0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0x65, 0xff, 0x01, 0x20, 
+0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xe8, 0x0d, 0x00, 0x80, 
+0x00, 0xb5, 0xff, 0xf7, 0x33, 0xf8, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0xb5, 0xff, 0xf7, 0x2e, 0xf8, 0x08, 0xbc, 0x18, 0x47, 
+0x00, 0xb5, 0xff, 0xf7, 0x29, 0xf8, 0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 
+0x01, 0x20, 0x14, 0x4f, 0x71, 0x23, 0x5b, 0x01, 0xf9, 0x18, 0x08, 0x71, 
+0x12, 0x48, 0xfe, 0xf7, 0xe9, 0xfd, 0x01, 0x20, 0x40, 0x02, 0xa1, 0x21, 
+0x49, 0x03, 0x88, 0x60, 0x00, 0x20, 0xf9, 0x1d, 0xb9, 0x31, 0x08, 0x70, 
+0x0d, 0x4a, 0x01, 0x23, 0x1b, 0x04, 0x11, 0x68, 0x0b, 0x40, 0x12, 0x21, 
+0x00, 0x2b, 0x05, 0xd1, 0x13, 0x68, 0x1b, 0x0c, 0x08, 0xd1, 0x12, 0x68, 
+0x92, 0x0a, 0x05, 0xd3, 0x07, 0x4a, 0xc0, 0x46, 0xd1, 0x60, 0x80, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0x05, 0x4a, 0xc0, 0x46, 0x11, 0x64, 0xf8, 0xe7, 
+0xe8, 0x0d, 0x00, 0x80, 0xa9, 0x9d, 0x21, 0x40, 0x00, 0x00, 0x10, 0x40, 
+0x40, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0xb5, 0x02, 0xf0, 
+0x83, 0xfb, 0x01, 0x20, 0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 0x84, 0xb0, 
+0x07, 0x1c, 0xf8, 0x88, 0x02, 0xf0, 0x88, 0xfc, 0x00, 0x28, 0x0c, 0xd1, 
+0x69, 0x46, 0x38, 0x1c, 0xfe, 0xf7, 0xc8, 0xff, 0x06, 0x48, 0x01, 0xab, 
+0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0x01, 0xff, 0x01, 0x20, 
+0x00, 0xe0, 0x00, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0xff, 0xff, 0x00, 0x00, 0x00, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0xfe, 0xf7, 
+0xb3, 0xff, 0x03, 0xf0, 0x71, 0xfe, 0x01, 0xab, 0x58, 0x80, 0x09, 0x48, 
+0x81, 0x89, 0x09, 0x04, 0xc2, 0x89, 0x11, 0x43, 0x02, 0x91, 0x81, 0x88, 
+0x09, 0x04, 0xc0, 0x88, 0x08, 0x43, 0x03, 0x90, 0x68, 0x46, 0x00, 0x21, 
+0xfe, 0xf7, 0xe0, 0xfe, 0x01, 0x20, 0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 
+0xc8, 0x29, 0x00, 0x80, 0x00, 0xb5, 0xfe, 0xf7, 0xaf, 0xff, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0xaa, 0xff, 0x08, 0xbc, 0x18, 0x47, 
+0x00, 0xb5, 0xfe, 0xf7, 0xa5, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 
+0xfe, 0xf7, 0xa0, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 
+0x9b, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x96, 0xff, 
+0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x91, 0xff, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x8c, 0xff, 0x08, 0xbc, 0x18, 0x47, 
+0x00, 0xb5, 0xfe, 0xf7, 0x87, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 
+0xfe, 0xf7, 0x82, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 
+0x7d, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x78, 0xff, 
+0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x73, 0xff, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0xb5, 0x8c, 0xb0, 0x08, 0xa9, 0xfe, 0xf7, 0x54, 0xff, 
+0x69, 0x46, 0x08, 0xa8, 0x03, 0xf0, 0xba, 0xfe, 0x02, 0x20, 0x08, 0xab, 
+0x58, 0x70, 0x69, 0x46, 0x08, 0xa8, 0xfe, 0xf7, 0x89, 0xfe, 0x01, 0x20, 
+0x0c, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x5a, 0xff, 
+0x08, 0xbc, 0x18, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x69, 0x46, 
+0x38, 0x1c, 0xfe, 0xf7, 0x39, 0xff, 0xf9, 0x88, 0x10, 0x48, 0x01, 0x24, 
+0x00, 0x29, 0x0e, 0xd0, 0x04, 0x73, 0x44, 0x73, 0xb9, 0x68, 0x09, 0x0c, 
+0x41, 0x82, 0xb9, 0x68, 0xc0, 0x46, 0x81, 0x82, 0xf9, 0x68, 0x09, 0x0c, 
+0xc1, 0x82, 0xf9, 0x68, 0xc0, 0x46, 0x01, 0x83, 0x02, 0xe0, 0x00, 0x21, 
+0x01, 0x73, 0x41, 0x73, 0x06, 0x48, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 
+0x00, 0x21, 0xfe, 0xf7, 0x5b, 0xfe, 0x20, 0x1c, 
+0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 
+0xff, 0xff, 0x00, 0x00, 0x00, 0xb5, 0xfe, 0xf7, 0x27, 0xff, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x22, 0xff, 0x08, 0xbc, 0x18, 0x47, 
+0x00, 0xb5, 0xfe, 0xf7, 0x1d, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 
+0xfe, 0xf7, 0x18, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 
+0x13, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 
+0x69, 0x46, 0x38, 0x1c, 0xfe, 0xf7, 0xf2, 0xfe, 0xf8, 0x88, 0x03, 0x24, 
+0xe4, 0x04, 0x04, 0x43, 0x03, 0x23, 0xdb, 0x04, 0x9c, 0x42, 0x02, 0xd3, 
+0x0f, 0x4b, 0x9c, 0x42, 0x06, 0xd9, 0x0f, 0x48, 0x01, 0xab, 0x58, 0x80, 
+0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0x20, 0xfe, 0x01, 0x20, 0x80, 0x07, 
+0x20, 0x43, 0x00, 0x68, 0x00, 0x21, 0x00, 0xab, 0x59, 0x70, 0xfa, 0x88, 
+0xc0, 0x46, 0xda, 0x80, 0x02, 0x90, 0x03, 0x91, 0x68, 0x46, 0x04, 0x33, 
+0xfe, 0xf7, 0x10, 0xfe, 0x01, 0x20, 0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x00, 0xe0, 0x00, 0x18, 0x00, 0xff, 0xff, 0x00, 0x00, 
+0x80, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c, 0xfe, 0xf7, 
+0xbf, 0xfe, 0xf8, 0x88, 0x03, 0x23, 0xdb, 0x04, 0x18, 0x43, 0x98, 0x42, 
+0x02, 0xd3, 0x0a, 0x4b, 0x98, 0x42, 0x08, 0xd9, 0x09, 0x48, 0x01, 0xab, 
+0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0xef, 0xfd, 0x01, 0x20, 
+0x03, 0xe0, 0xb9, 0x68, 0xc0, 0x46, 0x01, 0x60, 0x00, 0x20, 0x04, 0xb0, 
+0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xe0, 0x00, 0x18, 0x00, 
+0xff, 0xff, 0x00, 0x00, 0x80, 0xb5, 0x86, 0xb0, 0x07, 0x1c, 0x03, 0xf0, 
+0x5b, 0xfd, 0x38, 0x1c, 0x02, 0xa9, 0xfe, 0xf7, 0x97, 0xfe, 0x01, 0x27, 
+0x02, 0xab, 0x5f, 0x70, 0x00, 0x20, 0xd8, 0x80, 0x0a, 0x48, 0x01, 0x68, 
+0xc0, 0x46, 0x04, 0x91, 0x41, 0x68, 0xc0, 0x46, 0x05, 0x91, 0x81, 0x68, 
+0xc0, 0x46, 0x00, 0x91, 0x00, 0x69, 0xc0, 0x46, 0x01, 0x90, 0x69, 0x46, 
+0x02, 0xa8, 0xfe, 0xf7, 0xc1, 0xfd, 0x38, 0x1c, 0x06, 0xb0, 0x80, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0xe8, 0x18, 0x00, 0x80, 0x00, 0xb5, 0xc1, 0x68, 
+0x80, 0x68, 0xfe, 0xf7, 0x79, 0xfb, 0x00, 0x20, 0x08, 0xbc, 0x18, 0x47, 
+0x00, 0x20, 0x70, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0x04, 0x1c, 0x0f, 0x1c, 
+0x68, 0x46, 0x50, 0x21, 0xfe, 0xf7, 0x76, 0xfe, 0x01, 0xab, 0x5c, 0x80, 
+0x02, 0x97, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0xa1, 0xfd, 0x04, 0xb0, 
+0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 
+0x68, 0x46, 0x51, 0x21, 0xfe, 0xf7, 0x64, 0xfe, 0x01, 0xab, 0x5f, 0x80, 
+0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0x90, 0xfd, 0x04, 0xb0, 0x80, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 
+0x90, 0xb5, 0x84, 0xb0, 0x00, 0x27, 0x12, 0x49, 0x09, 0x68, 0x12, 0x4a, 
+0x12, 0x6b, 0x10, 0x23, 0x1a, 0x40, 0x01, 0x24, 0x00, 0x2a, 0x00, 0xd0, 
+0x01, 0x27, 0x8a, 0x0c, 0x03, 0xd3, 0x3a, 0x04, 0x12, 0x0c, 0x02, 0x27, 
+0x17, 0x43, 0xc9, 0x0c, 0x03, 0xd3, 0x39, 0x04, 0x09, 0x0c, 0x04, 0x27, 
+0x0f, 0x43, 0x69, 0x46, 0xfe, 0xf7, 0x2c, 0xfe, 0x01, 0xab, 0x5f, 0x80, 
+0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0x66, 0xfd, 0x20, 0x1c, 0x04, 0xb0, 
+0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 
+0xc0, 0x00, 0x18, 0x40, 0x00, 0xb5, 0x84, 0xb0, 
+0x69, 0x46, 0xfe, 0xf7, 0x17, 0xfe, 0x06, 0x48, 0xc0, 0x6d, 0x01, 0xab, 
+0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0x4f, 0xfd, 0x01, 0x20, 
+0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x10, 0x2a, 0x00, 0x80, 
+0x00, 0xb5, 0xfe, 0xf7, 0x1d, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0x70, 0x47, 
+0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 
+0x80, 0xb5, 0x01, 0x20, 0x14, 0x4f, 0x71, 0x23, 0x5b, 0x01, 0xf9, 0x18, 
+0x48, 0x71, 0x13, 0x48, 0xfe, 0xf7, 0xd6, 0xfb, 0x01, 0x20, 0x40, 0x02, 
+0xa1, 0x21, 0x49, 0x03, 0x88, 0x60, 0x00, 0x20, 0xf9, 0x1d, 0xb9, 0x31, 
+0x08, 0x70, 0x0e, 0x4a, 0x01, 0x23, 0x1b, 0x04, 0x11, 0x68, 0x0b, 0x40, 
+0x15, 0x21, 0x00, 0x2b, 0x05, 0xd1, 0x13, 0x68, 0x1b, 0x0c, 0x08, 0xd1, 
+0x12, 0x68, 0x92, 0x0a, 0x05, 0xd3, 0x08, 0x4a, 0xc0, 0x46, 0xd1, 0x60, 
+0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x06, 0x4a, 0xc0, 0x46, 0x11, 0x64, 
+0xf8, 0xe7, 0x00, 0x00, 0xe8, 0x0d, 0x00, 0x80, 0xa9, 0x9d, 0x21, 0x40, 
+0x00, 0x00, 0x10, 0x40, 0x40, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, 0x80, 
+0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 
+0x80, 0xb5, 0x85, 0xb0, 0x01, 0xa9, 0xfe, 0xf7, 0xbb, 0xfd, 0x00, 0x20, 
+0x01, 0xab, 0x58, 0x70, 0x10, 0x49, 0xc9, 0x68, 0x01, 0x27, 0x01, 0x29, 
+0x0a, 0xd1, 0x03, 0xf0, 0xb9, 0xfc, 0x03, 0x90, 0x04, 0x97, 0x03, 0x98, 
+0x00, 0x28, 0x06, 0xd0, 0x68, 0x46, 0x02, 0xf0, 0x15, 0xf8, 0x04, 0xe0, 
+0x03, 0x97, 0x04, 0x90, 0xf8, 0xe7, 0x00, 0x20, 0x00, 0x90, 0x02, 0xab, 
+0x00, 0x98, 0xc0, 0x46, 0x58, 0x80, 0x00, 0x21, 0x01, 0xa8, 0xfe, 0xf7, 
+0xdb, 0xfc, 0x38, 0x1c, 0x05, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0xe8, 0x0d, 0x00, 0x80, 0x90, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x69, 0x46, 
+0x38, 0x1c, 0xfe, 0xf7, 0x8d, 0xfd, 0x00, 0x20, 0x00, 0xab, 0x58, 0x70, 
+0x01, 0x24, 0x20, 0x1c, 0x12, 0x49, 0xc9, 0x68, 0x01, 0x29, 0x00, 0xd0, 
+0x00, 0x20, 0x00, 0x06, 0x00, 0x0e, 0x13, 0xd0, 0xf8, 0x88, 0x0f, 0x4a, 
+0x90, 0x42, 0x02, 0xd0, 0x0e, 0x4b, 0x98, 0x42, 0x08, 0xd1, 0xb9, 0x68, 
+0x27, 0x1c, 0x90, 0x42, 0x00, 0xd0, 0x00, 0x27, 0x38, 0x06, 0x00, 0x0e, 
+0x03, 0xf0, 0xa0, 0xfc, 0x03, 0xf0, 0x76, 0xfc, 0x02, 0x90, 0x00, 0xe0, 
+0x02, 0x94, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0xa7, 0xfc, 0x20, 0x1c, 
+0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xe8, 0x0d, 0x00, 0x80, 
+0xed, 0xfe, 0x00, 0x00, 0xfe, 0xca, 0x00, 0x00, 0x90, 0xb5, 0x07, 0x1c, 
+0x00, 0x24, 0x00, 0x2f, 0x04, 0xd3, 0x04, 0xf0, 0x9b, 0xf8, 0x01, 0x34, 
+0xbc, 0x42, 0xfa, 0xd9, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb5, 
+0x14, 0x1c, 0x0d, 0x1c, 0x06, 0x1c, 0x1f, 0x1c, 0x1b, 0x4b, 0x32, 0x04, 
+0x12, 0x0c, 0x3c, 0x21, 0x02, 0x20, 0xfe, 0xf7, 0x2a, 0xfb, 0x32, 0x0c, 
+0x17, 0x4b, 0x3e, 0x21, 0x02, 0x20, 0xfe, 0xf7, 0x24, 0xfb, 0x15, 0x4b, 
+0x2a, 0x04, 0x12, 0x0c, 0x40, 0x21, 0x02, 0x20, 0xfe, 0xf7, 0x1d, 0xfb, 
+0x2a, 0x0c, 0x11, 0x4b, 0x42, 0x21, 0x02, 0x20, 0xfe, 0xf7, 0x17, 0xfb, 
+0x0e, 0x4b, 0x22, 0x04, 0x12, 0x0c, 0x44, 0x21, 0x02, 0x20, 0xfe, 0xf7, 
+0x10, 0xfb, 0x22, 0x0c, 0x0a, 0x4b, 0x46, 0x21, 0x02, 0x20, 0xfe, 0xf7, 
+0x0a, 0xfb, 0x08, 0x4b, 0x3a, 0x04, 0x12, 0x0c, 0x48, 0x21, 0x02, 0x20, 
+0xfe, 0xf7, 0x03, 0xfb, 0x3a, 0x0c, 0x04, 0x4b, 
+0x4a, 0x21, 0x02, 0x20, 0xfe, 0xf7, 0xfd, 0xfa, 0xf0, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x00, 0x7b, 0xb7, 0x21, 0x40, 0x88, 0xb5, 0x11, 0x27, 
+0x3f, 0x04, 0x38, 0x62, 0x79, 0x62, 0xba, 0x62, 0xfb, 0x62, 0x04, 0x20, 
+0xff, 0xf7, 0xaa, 0xff, 0x07, 0x48, 0x40, 0x6b, 0xc0, 0x46, 0x00, 0x90, 
+0x00, 0x98, 0x80, 0x07, 0x80, 0x0f, 0x03, 0x28, 0x01, 0xd1, 0x01, 0x20, 
+0x00, 0xe0, 0x00, 0x20, 0x88, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
+0x00, 0x00, 0x11, 0x40, 0xf0, 0xb5, 0x8a, 0xb0, 0x00, 0x24, 0x05, 0x94, 
+0x69, 0x49, 0xc9, 0x68, 0xc0, 0x46, 0x00, 0x91, 0x68, 0x4a, 0x11, 0x68, 
+0x01, 0x22, 0x12, 0x04, 0x0a, 0x40, 0x17, 0x21, 0x66, 0x4e, 0x00, 0x2a, 
+0x06, 0xd1, 0x64, 0x4a, 0x13, 0x68, 0x1b, 0x0c, 0x04, 0xd1, 0x12, 0x68, 
+0x92, 0x0a, 0x01, 0xd3, 0xf1, 0x60, 0x02, 0xe0, 0x61, 0x4a, 0xc0, 0x46, 
+0x11, 0x64, 0x61, 0x49, 0x89, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x03, 0x29, 
+0x54, 0xd1, 0xe9, 0x21, 0x01, 0x91, 0x02, 0x99, 0xc0, 0x46, 0xb1, 0x60, 
+0x06, 0x94, 0x06, 0x99, 0x8a, 0x00, 0x5b, 0x49, 0x8a, 0x58, 0x00, 0x2a, 
+0x73, 0xd0, 0x80, 0x20, 0x02, 0x90, 0x06, 0x98, 0x81, 0x00, 0x57, 0x48, 
+0x41, 0x58, 0x02, 0x9a, 0x11, 0x43, 0x02, 0x91, 0x00, 0x24, 0x00, 0x27, 
+0x25, 0x02, 0x28, 0x1c, 0x38, 0x43, 0x09, 0x90, 0x09, 0x98, 0x00, 0x04, 
+0x51, 0x4b, 0x18, 0x43, 0x04, 0x90, 0x09, 0x98, 0xef, 0x23, 0xdb, 0x05, 
+0x18, 0x43, 0x03, 0x90, 0x06, 0x98, 0x80, 0x00, 0x4b, 0x49, 0x08, 0x58, 
+0x00, 0x04, 0x03, 0x99, 0x08, 0x43, 0x03, 0x90, 0x00, 0x2f, 0x02, 0xd1, 
+0x03, 0x98, 0xc0, 0x46, 0x70, 0x60, 0x01, 0x9b, 0x03, 0x9a, 0x02, 0x99, 
+0x04, 0x98, 0xff, 0xf7, 0x89, 0xff, 0x00, 0x28, 0x06, 0xd0, 0x02, 0x99, 
+0xc0, 0x46, 0xb1, 0x60, 0x03, 0x99, 0xc0, 0x46, 0x71, 0x60, 0x5c, 0xe0, 
+0x79, 0x1c, 0x0f, 0x04, 0x3f, 0x0c, 0x17, 0x2f, 0xd1, 0xdd, 0x61, 0x1c, 
+0x0c, 0x04, 0x24, 0x0c, 0x16, 0x2c, 0xca, 0xdd, 0x06, 0x99, 0x01, 0x31, 
+0x06, 0x91, 0x06, 0x99, 0x89, 0x00, 0x37, 0x4a, 0x51, 0x58, 0x00, 0x29, 
+0xb7, 0xd1, 0x48, 0xe0, 0xbf, 0x21, 0xc9, 0x43, 0x04, 0x91, 0xff, 0x21, 
+0x02, 0x91, 0x97, 0x21, 0x01, 0x91, 0x06, 0x94, 0x06, 0x99, 0x89, 0x00, 
+0x31, 0x4f, 0x79, 0x58, 0x00, 0x29, 0x1c, 0xd0, 0x09, 0x94, 0x08, 0x94, 
+0x06, 0x98, 0x80, 0x00, 0x38, 0x58, 0xc0, 0x46, 0x07, 0x90, 0x07, 0x98, 
+0x00, 0x04, 0x26, 0xe0, 0x05, 0x98, 0x15, 0x23, 0x1b, 0x06, 0x18, 0x43, 
+0x03, 0x90, 0x01, 0x9b, 0x03, 0x9a, 0x02, 0x99, 0x04, 0x98, 0xff, 0xf7, 
+0x49, 0xff, 0x00, 0x28, 0x23, 0xd1, 0x09, 0x99, 0x01, 0x31, 0x09, 0x91, 
+0x17, 0x29, 0x06, 0xd8, 0x00, 0xe0, 0x1c, 0xe0, 0x08, 0x98, 0x00, 0x02, 
+0x09, 0x99, 0x08, 0x43, 0x07, 0xe0, 0x08, 0x99, 0x01, 0x31, 0x08, 0x91, 
+0x17, 0x29, 0x0a, 0xd8, 0x09, 0x94, 0x08, 0x98, 0x00, 0x02, 0x07, 0x99, 
+0x09, 0x04, 0x08, 0x43, 0x15, 0x23, 0x1b, 0x06, 0x18, 0x43, 0x05, 0x90, 
+0xd6, 0xe7, 0x06, 0x99, 0x01, 0x31, 0x06, 0x91, 0x06, 0x99, 0x89, 0x00, 
+0x79, 0x58, 0x00, 0x29, 0xc4, 0xd1, 0x0c, 0x4a, 0x11, 0x68, 0x49, 0x0c, 
+0x05, 0xd2, 0x11, 0x68, 0x09, 0x0c, 0x06, 0xd1, 0x11, 0x68, 0x89, 0x0a, 
+0x03, 0xd3, 0x00, 0x99, 0xc0, 0x46, 0xf1, 0x60, 0x03, 0xe0, 0x00, 0x99, 
+0x06, 0x4a, 0xc0, 0x46, 0x11, 0x64, 0x0a, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x00, 0x40, 0x01, 0x18, 0x40, 
+0x00, 0x00, 0x10, 0x40, 0x40, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, 0x80, 
+0x00, 0x00, 0x18, 0x40, 0x30, 0x6e, 0x21, 0x40, 0x43, 0xff, 0x00, 0x00, 
+0x0c, 0x6e, 0x21, 0x40, 0x80, 0xb5, 0x82, 0xb0, 0x00, 0x20, 0x01, 0x90, 
+0x1e, 0x48, 0xc1, 0x68, 0x01, 0x29, 0x1b, 0xd1, 0x40, 0x88, 0x00, 0x28, 
+0x18, 0xd1, 0x68, 0x46, 0x01, 0xf0, 0x6a, 0xfe, 0x00, 0x28, 0x13, 0xd1, 
+0xa8, 0x20, 0x01, 0xf0, 0xab, 0xfe, 0x18, 0x4f, 0x00, 0x28, 0x11, 0xd0, 
+0x04, 0x20, 0xff, 0xf7, 0x97, 0xfe, 0x78, 0x6b, 0xc0, 0x46, 0x01, 0x90, 
+0x01, 0x98, 0x80, 0x07, 0x80, 0x0f, 0x03, 0x28, 0x06, 0xd1, 0x00, 0x20, 
+0x01, 0xf0, 0x9a, 0xfe, 0x02, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x00, 0x23, 0x00, 0x22, 0x00, 0x21, 0x00, 0x20, 0xff, 0xf7, 0x8f, 0xfe, 
+0x00, 0x23, 0xdb, 0x43, 0x18, 0x1c, 0x19, 0x1c, 0x1a, 0x1c, 0xff, 0xf7, 
+0xc7, 0xfe, 0x00, 0x28, 0x03, 0xd1, 0xff, 0xf7, 0xdf, 0xfe, 0x00, 0x28, 
+0xe5, 0xd0, 0x38, 0x6a, 0x79, 0x6a, 0xba, 0x6a, 0xfb, 0x6a, 0xff, 0xf7, 
+0x7c, 0xfe, 0xde, 0xe7, 0xe8, 0x0d, 0x00, 0x80, 0x00, 0x00, 0x11, 0x40, 
+0xff, 0xb5, 0x85, 0xb0, 0x14, 0x1c, 0x1f, 0x1c, 0x00, 0x20, 0x01, 0x90, 
+0x01, 0x23, 0x5b, 0x04, 0x9f, 0x42, 0x01, 0xd9, 0x0f, 0x20, 0x82, 0xe0, 
+0x26, 0x1c, 0x43, 0x4d, 0xaf, 0x42, 0x00, 0xd2, 0x3d, 0x1c, 0x21, 0x0d, 
+0x09, 0x05, 0x41, 0x48, 0x41, 0x4b, 0x99, 0x42, 0x04, 0xd0, 0x80, 0x25, 
+0x06, 0x1c, 0x80, 0x2f, 0x00, 0xd8, 0x3d, 0x1c, 0x3e, 0x4a, 0x51, 0x69, 
+0xc0, 0x46, 0x03, 0x91, 0x92, 0x69, 0xc0, 0x46, 0x02, 0x92, 0xff, 0x23, 
+0x01, 0x33, 0x19, 0x43, 0x39, 0x4b, 0xc0, 0x46, 0x59, 0x61, 0xff, 0x23, 
+0x01, 0x33, 0x9a, 0x43, 0x36, 0x4b, 0xc0, 0x46, 0x9a, 0x61, 0x01, 0x22, 
+0x12, 0x05, 0xd1, 0x60, 0x33, 0x4a, 0x91, 0x69, 0x01, 0x22, 0x12, 0x05, 
+0x11, 0x61, 0x31, 0x4a, 0xff, 0x23, 0x01, 0x33, 0x91, 0x69, 0x19, 0x43, 
+0x91, 0x61, 0x01, 0x22, 0x12, 0x05, 0x11, 0x61, 0x85, 0x21, 0x89, 0x04, 
+0x04, 0x91, 0x00, 0x2f, 0x34, 0xd0, 0x28, 0x48, 0x86, 0x42, 0x04, 0xd1, 
+0x30, 0x1c, 0x21, 0x1c, 0x2a, 0x1c, 0x03, 0xf0, 0xd5, 0xfe, 0x2a, 0x1c, 
+0x04, 0x98, 0x02, 0x43, 0x00, 0x92, 0x01, 0x20, 0x06, 0x99, 0x05, 0x9a, 
+0x33, 0x1c, 0xfe, 0xf7, 0x5d, 0xf9, 0x22, 0x48, 0x22, 0x49, 0x4a, 0x68, 
+0x52, 0x0a, 0x09, 0xd3, 0xff, 0x21, 0x01, 0x31, 0x20, 0x4a, 0xc0, 0x46, 
+0x11, 0x60, 0x00, 0x28, 0x05, 0xd1, 0x11, 0x20, 0x01, 0x90, 0x13, 0xe0, 
+0x01, 0x38, 0xf0, 0xd1, 0xf9, 0xe7, 0x7f, 0x1b, 0x0e, 0xd0, 0x15, 0x48, 
+0x86, 0x42, 0x01, 0xd1, 0x64, 0x19, 0x00, 0xe0, 0x76, 0x19, 0x06, 0x99, 
+0x49, 0x19, 0x06, 0x91, 0x38, 0x1c, 0xaf, 0x42, 0x00, 0xd3, 0x28, 0x1c, 
+0x05, 0x1c, 0xca, 0xe7, 0x0f, 0x48, 0x41, 0x69, 0x03, 0x9b, 0x19, 0x43, 
+0x41, 0x61, 0x82, 0x69, 0x03, 0x9b, 0x9a, 0x43, 0x82, 0x61, 0x01, 0x22, 
+0x12, 0x05, 0xd1, 0x60, 0x81, 0x69, 0xc0, 0x46, 0x11, 0x61, 0x81, 0x69, 
+0x02, 0x9b, 0x19, 0x43, 0x81, 0x61, 0x11, 0x61, 0x01, 0x98, 0x09, 0xb0, 
+0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00, 
+0x50, 0xab, 0x20, 0x40, 0x00, 0x00, 0x20, 0x40, 0xe8, 0x0d, 0x00, 0x80, 
+0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x00, 0xb0, 
+0xff, 0xb5, 0x85, 0xb0, 0x04, 0x1c, 0x1f, 0x1c, 0x00, 0x20, 0x01, 0x90, 
+0x01, 0x23, 0x5b, 0x04, 0x9f, 0x42, 0x01, 0xd9, 
+0x0f, 0x20, 0x7d, 0xe0, 0x26, 0x1c, 0x40, 0x4d, 0xaf, 0x42, 0x00, 0xd2, 
+0x3d, 0x1c, 0x21, 0x0d, 0x09, 0x05, 0x3e, 0x48, 0x3e, 0x4b, 0x99, 0x42, 
+0x04, 0xd0, 0x80, 0x25, 0x06, 0x1c, 0x80, 0x2f, 0x00, 0xd8, 0x3d, 0x1c, 
+0x3b, 0x4a, 0x51, 0x69, 0xc0, 0x46, 0x03, 0x91, 0x92, 0x69, 0xc0, 0x46, 
+0x02, 0x92, 0x10, 0x23, 0x19, 0x43, 0x37, 0x4b, 0xc0, 0x46, 0x59, 0x61, 
+0x10, 0x23, 0x9a, 0x43, 0x34, 0x4b, 0xc0, 0x46, 0x9a, 0x61, 0x01, 0x22, 
+0x12, 0x05, 0xd1, 0x60, 0x31, 0x4a, 0x91, 0x69, 0x01, 0x22, 0x12, 0x05, 
+0x11, 0x61, 0x2f, 0x4a, 0x10, 0x23, 0x91, 0x69, 0x19, 0x43, 0x91, 0x61, 
+0x1a, 0x04, 0x11, 0x61, 0x21, 0x21, 0x09, 0x05, 0x04, 0x91, 0x00, 0x2f, 
+0x33, 0xd0, 0x2a, 0x1c, 0x04, 0x98, 0x02, 0x43, 0x00, 0x92, 0x00, 0x20, 
+0x06, 0x99, 0x07, 0x9a, 0x33, 0x1c, 0xfe, 0xf7, 0xc7, 0xf8, 0x25, 0x48, 
+0x25, 0x49, 0x4a, 0x68, 0x52, 0x09, 0x08, 0xd3, 0x10, 0x21, 0x24, 0x4a, 
+0xc0, 0x46, 0x11, 0x60, 0x00, 0x28, 0x05, 0xd1, 0x11, 0x20, 0x01, 0x90, 
+0x1b, 0xe0, 0x01, 0x38, 0xf1, 0xd1, 0xf9, 0xe7, 0x19, 0x48, 0x86, 0x42, 
+0x04, 0xd1, 0x20, 0x1c, 0x31, 0x1c, 0x2a, 0x1c, 0x03, 0xf0, 0x1c, 0xfe, 
+0x7f, 0x1b, 0x0e, 0xd0, 0x14, 0x48, 0x86, 0x42, 0x01, 0xd0, 0x76, 0x19, 
+0x00, 0xe0, 0x64, 0x19, 0x06, 0x99, 0x49, 0x19, 0x06, 0x91, 0x38, 0x1c, 
+0xaf, 0x42, 0x00, 0xd3, 0x28, 0x1c, 0x05, 0x1c, 0xcb, 0xe7, 0x0f, 0x48, 
+0x41, 0x69, 0x03, 0x9b, 0x19, 0x43, 0x41, 0x61, 0x82, 0x69, 0x03, 0x9b, 
+0x9a, 0x43, 0x82, 0x61, 0x01, 0x22, 0x12, 0x05, 0xd1, 0x60, 0x81, 0x69, 
+0xc0, 0x46, 0x11, 0x61, 0x81, 0x69, 0x02, 0x9b, 0x19, 0x43, 0x81, 0x61, 
+0x11, 0x61, 0x01, 0x98, 0x09, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0xf0, 0xff, 0x00, 0x00, 0x50, 0xab, 0x20, 0x40, 0x00, 0x00, 0x20, 0x40, 
+0xe8, 0x0d, 0x00, 0x80, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 
+0x00, 0x00, 0x00, 0xb0, 0x70, 0x47, 0x04, 0x49, 0x00, 0x20, 0x00, 0x22, 
+0x0a, 0x70, 0x01, 0x30, 0x01, 0x31, 0x68, 0x28, 0xfa, 0xd3, 0x70, 0x47, 
+0xa0, 0x82, 0x20, 0x40, 0x00, 0x22, 0x88, 0x42, 0x03, 0xd3, 0x40, 0x1a, 
+0x01, 0x32, 0x88, 0x42, 0xfb, 0xd2, 0x10, 0x1c, 0x70, 0x47, 0x88, 0x42, 
+0x02, 0xd3, 0x40, 0x1a, 0x88, 0x42, 0xfc, 0xd2, 0x70, 0x47, 0x90, 0xb4, 
+0x01, 0x1c, 0xff, 0x27, 0x04, 0x29, 0x27, 0xda, 0x00, 0x20, 0x14, 0x4a, 
+0x43, 0x00, 0x1b, 0x18, 0xdb, 0x00, 0xd4, 0x58, 0x63, 0x0c, 0x1a, 0xd2, 
+0x4b, 0x00, 0x59, 0x18, 0xc9, 0x00, 0x57, 0x58, 0x43, 0x00, 0x1b, 0x18, 
+0xdb, 0x00, 0xd7, 0x50, 0x89, 0x18, 0x9a, 0x18, 0x4f, 0x68, 0xc0, 0x46, 
+0x57, 0x60, 0x8b, 0x68, 0xc0, 0x46, 0x93, 0x60, 0x0b, 0x69, 0xc0, 0x46, 
+0x13, 0x61, 0x4b, 0x69, 0xc0, 0x46, 0x53, 0x61, 0xc9, 0x68, 0xc0, 0x46, 
+0xd1, 0x60, 0x90, 0xbc, 0x70, 0x47, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 
+0x04, 0x28, 0xd9, 0xdb, 0x38, 0x1c, 0xf6, 0xe7, 0xd0, 0xab, 0x20, 0x40, 
+0xf7, 0xb5, 0xc5, 0xb0, 0x14, 0x1c, 0x00, 0x20, 0x11, 0x21, 0x21, 0x40, 
+0x5f, 0xd0, 0x00, 0x27, 0x79, 0x00, 0xc9, 0x19, 0xc9, 0x00, 0x5b, 0x4a, 
+0x51, 0x58, 0x49, 0x0c, 0x03, 0xd2, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 
+0x04, 0xe0, 0x79, 0x1c, 0x0f, 0x06, 0x3f, 0x0e, 0x04, 0x2f, 0xef, 0xdb, 
+0x00, 0x28, 0x4c, 0xd0, 0x00, 0x22, 0x01, 0x92, 0x00, 0x92, 0x40, 0x23, 
+0x00, 0x21, 0x00, 0x20, 0x03, 0xaa, 0x00, 0xf0, 
+0x8f, 0xfa, 0x05, 0xa9, 0x00, 0x20, 0x82, 0x00, 0x8a, 0x58, 0x12, 0x06, 
+0x12, 0x0e, 0x45, 0x9b, 0x9a, 0x42, 0x05, 0xd1, 0x01, 0x9a, 0x01, 0x32, 
+0x12, 0x06, 0x12, 0x0e, 0x01, 0x92, 0x04, 0xe0, 0x01, 0x30, 0x00, 0x06, 
+0x00, 0x0e, 0x10, 0x28, 0xed, 0xdb, 0x01, 0x9a, 0x00, 0x2a, 0x4f, 0xd0, 
+0x45, 0x9b, 0x04, 0x2b, 0x3e, 0xd1, 0x80, 0x00, 0x08, 0x58, 0x40, 0x01, 
+0x80, 0x0d, 0x00, 0x22, 0x00, 0x92, 0x10, 0x23, 0x00, 0x21, 0x03, 0xaa, 
+0x00, 0xf0, 0x6a, 0xfa, 0x00, 0x21, 0x01, 0x91, 0x03, 0xa8, 0x06, 0x99, 
+0x49, 0x0c, 0x89, 0x05, 0x2a, 0xd0, 0xc1, 0x68, 0x0a, 0x06, 0x12, 0x0e, 
+0x46, 0x9b, 0x9a, 0x42, 0x12, 0xd1, 0xc0, 0x68, 0x40, 0x01, 0x86, 0x0d, 
+0x00, 0x22, 0x00, 0x92, 0x0c, 0x23, 0x00, 0x21, 0x30, 0x1c, 0x03, 0xaa, 
+0x00, 0xf0, 0x52, 0xfa, 0x01, 0x99, 0x03, 0x9d, 0x48, 0x1c, 0x01, 0x06, 
+0x09, 0x0e, 0x01, 0x91, 0x0f, 0xe0, 0x57, 0xe0, 0x48, 0x01, 0x86, 0x0d, 
+0x00, 0x22, 0x00, 0x92, 0x10, 0x23, 0x00, 0x21, 0x30, 0x1c, 0x03, 0xaa, 
+0x00, 0xf0, 0x40, 0xfa, 0x03, 0xa8, 0x06, 0x99, 0x49, 0x0c, 0x89, 0x05, 
+0xd7, 0xd1, 0x01, 0x99, 0x00, 0x29, 0x11, 0xd1, 0xff, 0x20, 0x3f, 0xe0, 
+0x80, 0x00, 0x08, 0x58, 0x40, 0x01, 0x86, 0x0d, 0x00, 0x22, 0x00, 0x92, 
+0x0c, 0x23, 0x00, 0x21, 0x30, 0x1c, 0x03, 0xaa, 0x00, 0xf0, 0x2a, 0xfa, 
+0x03, 0x9d, 0x01, 0xe0, 0x20, 0x0a, 0xed, 0xd2, 0x01, 0x20, 0x00, 0x04, 
+0x20, 0x43, 0x79, 0x00, 0xc9, 0x19, 0xc9, 0x00, 0x17, 0x4a, 0xc0, 0x46, 
+0x50, 0x50, 0x30, 0x1c, 0x8e, 0x18, 0x70, 0x60, 0x10, 0x20, 0x45, 0x9b, 
+0x04, 0x2b, 0x00, 0xd0, 0x0c, 0x20, 0x02, 0x90, 0xb0, 0x60, 0x00, 0x20, 
+0x20, 0x21, 0x21, 0x40, 0x20, 0x29, 0x00, 0xd0, 0x28, 0x1c, 0x30, 0x61, 
+0x02, 0x98, 0x28, 0x18, 0xff, 0x21, 0xff, 0x30, 0x08, 0x30, 0x09, 0x31, 
+0xff, 0xf7, 0x12, 0xff, 0x43, 0x01, 0x18, 0x18, 0xc0, 0x00, 0x02, 0x99, 
+0x40, 0x1a, 0x70, 0x61, 0x00, 0x20, 0x50, 0x21, 0x21, 0x40, 0x50, 0x29, 
+0x00, 0xd1, 0x28, 0x1c, 0xf0, 0x60, 0x38, 0x1c, 0x48, 0xb0, 0xf0, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0xff, 0x20, 0xf9, 0xe7, 0xd0, 0xab, 0x20, 0x40, 
+0x80, 0xb4, 0x00, 0x23, 0x00, 0x22, 0x00, 0x29, 0x06, 0xd9, 0x87, 0x5c, 
+0x7b, 0x40, 0x1b, 0x06, 0x1b, 0x0e, 0x01, 0x32, 0x8a, 0x42, 0xf8, 0xd3, 
+0xd8, 0x43, 0x00, 0x06, 0x00, 0x0e, 0x80, 0xbc, 0x70, 0x47, 0xf0, 0xb5, 
+0xc6, 0xb0, 0x04, 0x28, 0x07, 0xda, 0x41, 0x00, 0x09, 0x18, 0xc9, 0x00, 
+0x45, 0x91, 0x41, 0x4a, 0x51, 0x58, 0x4b, 0x0c, 0x02, 0xd2, 0x00, 0x20, 
+0xc0, 0x43, 0x76, 0xe0, 0x01, 0x23, 0x5b, 0x04, 0x19, 0x40, 0x43, 0x00, 
+0x18, 0x18, 0xc0, 0x00, 0x3a, 0x4a, 0x14, 0x18, 0x00, 0x29, 0x61, 0xd0, 
+0x00, 0x21, 0x02, 0x91, 0x20, 0x69, 0xa1, 0x68, 0x45, 0x18, 0x30, 0xd0, 
+0xff, 0x21, 0x68, 0x1e, 0x09, 0x31, 0xff, 0xf7, 0xc7, 0xfe, 0x61, 0x68, 
+0x40, 0x18, 0x01, 0x90, 0x01, 0x98, 0x81, 0x42, 0x02, 0xd1, 0xa6, 0x68, 
+0xaf, 0x1b, 0x09, 0xe0, 0x00, 0x26, 0xff, 0x21, 0x28, 0x1c, 0x09, 0x31, 
+0xff, 0xf7, 0xc1, 0xfe, 0x07, 0x1c, 0x01, 0xd1, 0xff, 0x27, 0x09, 0x37, 
+0x00, 0x22, 0x00, 0x92, 0x01, 0x98, 0x31, 0x1c, 0x03, 0xaa, 0x3b, 0x1c, 
+0x00, 0xf0, 0x9e, 0xf9, 0x03, 0xa8, 0x39, 0x1c, 0xff, 0xf7, 0xac, 0xff, 
+0xc0, 0x43, 0x02, 0x99, 0x48, 0x40, 0x01, 0x06, 0x09, 0x0e, 0x02, 0x91, 
+0xed, 0x1b, 0xa0, 0x68, 0xa8, 0x42, 0x00, 0xd1, 
+0x00, 0x25, 0x00, 0x2d, 0xce, 0xd8, 0x02, 0x99, 0xcf, 0x43, 0x00, 0x22, 
+0x00, 0x92, 0x0c, 0x23, 0x00, 0x21, 0x60, 0x68, 0x03, 0xaa, 0x00, 0xf0, 
+0x83, 0xf9, 0x20, 0x69, 0xc0, 0x46, 0x03, 0x90, 0x05, 0x98, 0x00, 0x0a, 
+0x00, 0x02, 0x39, 0x06, 0x09, 0x0e, 0x08, 0x43, 0x05, 0x90, 0xff, 0x23, 
+0x1b, 0x02, 0x98, 0x43, 0x05, 0x90, 0x0c, 0x21, 0x03, 0xa8, 0xff, 0xf7, 
+0x83, 0xff, 0xff, 0x23, 0x1b, 0x02, 0x05, 0x99, 0x99, 0x43, 0x00, 0x06, 
+0x00, 0x0e, 0x00, 0x02, 0x08, 0x43, 0x05, 0x90, 0x0c, 0x23, 0x00, 0x21, 
+0x60, 0x68, 0x03, 0xaa, 0x00, 0xf0, 0xbb, 0xf9, 0x00, 0x20, 0x45, 0x99, 
+0x06, 0x4a, 0xc0, 0x46, 0x50, 0x50, 0xc1, 0x43, 0x61, 0x60, 0xa1, 0x60, 
+0xe1, 0x60, 0x21, 0x61, 0x61, 0x61, 0x46, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x00, 0xd0, 0xab, 0x20, 0x40, 0xb0, 0xb4, 0x4c, 0x42, 
+0x00, 0x29, 0x00, 0xdb, 0x0c, 0x1c, 0x00, 0x27, 0xff, 0x43, 0x04, 0x28, 
+0x21, 0xda, 0x12, 0x4d, 0x43, 0x00, 0x18, 0x18, 0xc0, 0x00, 0x40, 0x19, 
+0x01, 0x2a, 0x05, 0xd0, 0x02, 0x2a, 0x09, 0xd0, 0x03, 0x2a, 0x16, 0xd1, 
+0x01, 0x69, 0x0b, 0xe0, 0x00, 0x29, 0x12, 0xdb, 0x02, 0x69, 0x8a, 0x42, 
+0x0f, 0xd3, 0x05, 0xe0, 0x00, 0x29, 0x07, 0xda, 0xc1, 0x68, 0xa1, 0x42, 
+0x09, 0xd3, 0x09, 0x1b, 0xc1, 0x60, 0xc0, 0x68, 0xb0, 0xbc, 0x70, 0x47, 
+0xc1, 0x68, 0x09, 0x19, 0x02, 0x69, 0x91, 0x42, 0xf6, 0xd9, 0x38, 0x1c, 
+0xf6, 0xe7, 0x00, 0x00, 0xd0, 0xab, 0x20, 0x40, 0xf0, 0xb5, 0x84, 0xb0, 
+0x17, 0x1c, 0x0d, 0x1c, 0x00, 0x21, 0x02, 0x91, 0x42, 0x00, 0x12, 0x18, 
+0xd2, 0x00, 0x2c, 0x49, 0x8b, 0x58, 0x1b, 0x06, 0x1b, 0x0e, 0x01, 0x93, 
+0x00, 0x23, 0xdb, 0x43, 0x04, 0x28, 0x02, 0xda, 0x01, 0x98, 0x40, 0x08, 
+0x01, 0xd2, 0x18, 0x1c, 0x46, 0xe0, 0x54, 0x18, 0xe0, 0x68, 0xc2, 0x19, 
+0x21, 0x69, 0x8a, 0x42, 0x00, 0xd9, 0x0f, 0x1a, 0x00, 0x2f, 0x3c, 0xd9, 
+0xa0, 0x68, 0xe1, 0x68, 0x40, 0x18, 0xff, 0x21, 0x09, 0x31, 0xff, 0xf7, 
+0x07, 0xfe, 0x61, 0x68, 0x46, 0x18, 0xa0, 0x68, 0xe1, 0x68, 0x40, 0x18, 
+0xff, 0x21, 0x09, 0x31, 0xff, 0xf7, 0x07, 0xfe, 0xc2, 0x19, 0xff, 0x21, 
+0x09, 0x31, 0x8a, 0x42, 0x14, 0xd9, 0x01, 0x9a, 0xc0, 0x46, 0x00, 0x92, 
+0x0b, 0x1a, 0x03, 0x93, 0x01, 0x1c, 0x30, 0x1c, 0x2a, 0x1c, 0x00, 0xf0, 
+0xe1, 0xf8, 0xe0, 0x68, 0x03, 0x9b, 0xc0, 0x18, 0xe0, 0x60, 0x03, 0x9b, 
+0x5d, 0x19, 0xff, 0x1a, 0x02, 0x98, 0x18, 0x18, 0x02, 0x90, 0x10, 0xe0, 
+0x01, 0x9a, 0xc0, 0x46, 0x00, 0x92, 0x01, 0x1c, 0x30, 0x1c, 0x2a, 0x1c, 
+0x3b, 0x1c, 0x00, 0xf0, 0xcd, 0xf8, 0xe0, 0x68, 0xc0, 0x19, 0xed, 0x19, 
+0xe0, 0x60, 0x02, 0x98, 0xc0, 0x19, 0x02, 0x90, 0x00, 0x27, 0x00, 0x2f, 
+0xc2, 0xd8, 0x02, 0x98, 0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0xd0, 0xab, 0x20, 0x40, 0xf0, 0xb5, 0x83, 0xb0, 0x17, 0x1c, 0x0d, 0x1c, 
+0x00, 0x21, 0x01, 0x91, 0x42, 0x00, 0x12, 0x18, 0xd2, 0x00, 0x02, 0x92, 
+0x30, 0x49, 0x8a, 0x58, 0x12, 0x06, 0x12, 0x0e, 0x00, 0x24, 0xe4, 0x43, 
+0x04, 0x28, 0x01, 0xda, 0x50, 0x09, 0x01, 0xd2, 0x20, 0x1c, 0x51, 0xe0, 
+0x02, 0x9a, 0x54, 0x18, 0xe0, 0x68, 0xc2, 0x19, 0x60, 0x69, 0x82, 0x42, 
+0x01, 0xd9, 0x22, 0x69, 0x87, 0x1a, 0x00, 0x2f, 0x45, 0xd9, 0x25, 0x4e, 
+0xa0, 0x68, 0xe1, 0x68, 0x40, 0x18, 0xff, 0x21, 0x09, 0x31, 0xff, 0xf7, 
+0xa1, 0xfd, 0x61, 0x68, 0x40, 0x18, 0x00, 0x90, 
+0xa0, 0x68, 0xe1, 0x68, 0x40, 0x18, 0xff, 0x21, 0x09, 0x31, 0xff, 0xf7, 
+0xa0, 0xfd, 0x02, 0x9a, 0xb1, 0x58, 0x01, 0x23, 0x5b, 0x04, 0x19, 0x43, 
+0xb1, 0x50, 0xc1, 0x19, 0xff, 0x22, 0x09, 0x32, 0x91, 0x42, 0x13, 0xd9, 
+0x13, 0x1a, 0x01, 0x1c, 0x00, 0x98, 0x2a, 0x1c, 0x1e, 0x1c, 0x00, 0xf0, 
+0xd0, 0xf8, 0xe0, 0x68, 0x80, 0x19, 0x75, 0x19, 0xe0, 0x60, 0x21, 0x69, 
+0x88, 0x42, 0x00, 0xd9, 0x20, 0x61, 0xbf, 0x1b, 0x01, 0x98, 0x30, 0x18, 
+0x01, 0x90, 0x12, 0xe0, 0x01, 0x1c, 0x00, 0x9e, 0x30, 0x1c, 0x2a, 0x1c, 
+0x3b, 0x1c, 0x00, 0xf0, 0xbc, 0xf8, 0xe0, 0x68, 0xc0, 0x19, 0xed, 0x19, 
+0xe0, 0x60, 0x21, 0x69, 0x88, 0x42, 0x00, 0xd9, 0x20, 0x61, 0x01, 0x98, 
+0xc0, 0x19, 0x01, 0x90, 0x00, 0x27, 0x00, 0x2f, 0xb9, 0xd8, 0x01, 0x98, 
+0x03, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xd0, 0xab, 0x20, 0x40, 
+0xb0, 0xb5, 0xc3, 0xb0, 0x0c, 0x1c, 0x00, 0x27, 0xfa, 0x43, 0x04, 0x28, 
+0x06, 0xda, 0x41, 0x00, 0x09, 0x18, 0xc9, 0x00, 0x14, 0x48, 0x45, 0x58, 
+0x6b, 0x0c, 0x04, 0xd2, 0x10, 0x1c, 0x43, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x62, 0x09, 0x1b, 0xd3, 0x00, 0x22, 0x00, 0x92, 0x08, 0x18, 
+0x40, 0x68, 0x0c, 0x23, 0x00, 0x21, 0x01, 0xaa, 0x00, 0xf0, 0x30, 0xf8, 
+0x11, 0x2c, 0x0d, 0xd0, 0x12, 0x2c, 0x0d, 0xd0, 0x13, 0x2c, 0x05, 0xd0, 
+0x14, 0x2c, 0x0a, 0xd1, 0x03, 0x98, 0x00, 0x04, 0x07, 0x0e, 0x06, 0xe0, 
+0x03, 0x98, 0x07, 0x06, 0x3f, 0x0e, 0x02, 0xe0, 0x01, 0x9f, 0x00, 0xe0, 
+0x02, 0x9f, 0x38, 0x1c, 0xdb, 0xe7, 0x00, 0x00, 0xd0, 0xab, 0x20, 0x40, 
+0x03, 0x49, 0x00, 0x20, 0x00, 0x22, 0x0a, 0x54, 0x01, 0x30, 0x60, 0x28, 
+0xfb, 0xd3, 0x70, 0x47, 0xd0, 0xab, 0x20, 0x40, 0x00, 0xb5, 0x02, 0xf0, 
+0x9f, 0xf9, 0x57, 0x20, 0x02, 0xf0, 0xfc, 0xf8, 0x02, 0xf0, 0x70, 0xf8, 
+0x00, 0x0a, 0xfb, 0xd3, 0x02, 0xf0, 0x7e, 0xf9, 0x08, 0xbc, 0x18, 0x47, 
+0xf0, 0xb5, 0x82, 0xb0, 0x14, 0x1c, 0x07, 0x9a, 0x1f, 0x1c, 0xff, 0x23, 
+0x01, 0x33, 0x1a, 0x40, 0x40, 0x02, 0x08, 0x43, 0x05, 0x0a, 0x06, 0x1c, 
+0x00, 0x0c, 0x01, 0x90, 0x00, 0x2a, 0x20, 0xd0, 0x02, 0xf0, 0x82, 0xf9, 
+0x53, 0x20, 0x02, 0xf0, 0xdf, 0xf8, 0x01, 0x98, 0xc0, 0x46, 0x00, 0x90, 
+0x02, 0xf0, 0xda, 0xf8, 0x28, 0x1c, 0x02, 0xf0, 0xd7, 0xf8, 0x30, 0x1c, 
+0x02, 0xf0, 0xd4, 0xf8, 0x02, 0xf0, 0x5a, 0xf9, 0xff, 0xf7, 0xce, 0xff, 
+0x02, 0xf0, 0x6e, 0xf9, 0x54, 0x20, 0x02, 0xf0, 0xcb, 0xf8, 0x00, 0x98, 
+0x02, 0xf0, 0xc8, 0xf8, 0x28, 0x1c, 0x02, 0xf0, 0xc5, 0xf8, 0x30, 0x1c, 
+0x14, 0xe0, 0x02, 0xf0, 0x61, 0xf9, 0x52, 0x20, 0x02, 0xf0, 0xbe, 0xf8, 
+0x01, 0x98, 0x02, 0xf0, 0xbb, 0xf8, 0x28, 0x1c, 0x02, 0xf0, 0xb8, 0xf8, 
+0x30, 0x1c, 0x02, 0xf0, 0xb5, 0xf8, 0x00, 0x20, 0x02, 0xf0, 0xb2, 0xf8, 
+0x00, 0x20, 0x02, 0xf0, 0xaf, 0xf8, 0x00, 0x20, 0x02, 0xf0, 0xac, 0xf8, 
+0x00, 0x20, 0x02, 0xf0, 0xa9, 0xf8, 0x00, 0x2f, 0x05, 0xd9, 0x02, 0xf0, 
+0x1b, 0xf8, 0x20, 0x70, 0x01, 0x34, 0x01, 0x3f, 0xf9, 0xd1, 0x02, 0xf0, 
+0x27, 0xf9, 0x02, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb5, 
+0x82, 0xb0, 0x14, 0x1c, 0x1f, 0x1c, 0x40, 0x02, 0x08, 0x43, 0x05, 0x1c, 
+0x02, 0xf0, 0x32, 0xf9, 0x53, 0x20, 0x02, 0xf0, 0x8f, 0xf8, 0x28, 0x0c, 
+0x06, 0x1c, 0x02, 0xf0, 0x8b, 0xf8, 0x28, 0x0a, 0x01, 0x90, 0x00, 0x90, 
+0x02, 0xf0, 0x86, 0xf8, 0x28, 0x1c, 0x02, 0xf0, 
+0x83, 0xf8, 0x02, 0xf0, 0x09, 0xf9, 0xff, 0xf7, 0x7d, 0xff, 0x02, 0xf0, 
+0x1d, 0xf9, 0x84, 0x20, 0x02, 0xf0, 0x7a, 0xf8, 0x30, 0x1c, 0x02, 0xf0, 
+0x77, 0xf8, 0x00, 0x98, 0x02, 0xf0, 0x74, 0xf8, 0x28, 0x1c, 0x02, 0xf0, 
+0x71, 0xf8, 0x00, 0x2f, 0x05, 0xd9, 0x20, 0x78, 0x01, 0x34, 0x02, 0xf0, 
+0x6b, 0xf8, 0x01, 0x3f, 0xf9, 0xd1, 0x02, 0xf0, 0xef, 0xf8, 0x02, 0xf0, 
+0x05, 0xf9, 0x83, 0x20, 0x02, 0xf0, 0x62, 0xf8, 0x30, 0x1c, 0x02, 0xf0, 
+0x5f, 0xf8, 0x01, 0x98, 0x02, 0xf0, 0x5c, 0xf8, 0x28, 0x1c, 0x02, 0xf0, 
+0x59, 0xf8, 0x02, 0xf0, 0xdf, 0xf8, 0xff, 0xf7, 0x53, 0xff, 0x02, 0xb0, 
+0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x70, 0x47, 0x00, 0x00, 
+0x80, 0xb5, 0x01, 0xf0, 0x89, 0xf8, 0x06, 0x4f, 0xc0, 0x46, 0xf8, 0x60, 
+0x01, 0xf0, 0xe4, 0xf8, 0x78, 0x80, 0x01, 0xf0, 0xa5, 0xf8, 0x38, 0x71, 
+0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xe8, 0x0d, 0x00, 0x80, 
+0x00, 0xb5, 0x01, 0xf0, 0xf7, 0xf8, 0x02, 0x49, 0xc0, 0x46, 0x08, 0x80, 
+0x08, 0xbc, 0x18, 0x47, 0xe8, 0x0d, 0x00, 0x80, 0x0b, 0x48, 0xc1, 0x68, 
+0x01, 0x29, 0x11, 0xd1, 0x02, 0x22, 0xc1, 0x6f, 0x0a, 0x43, 0xc2, 0x67, 
+0x08, 0x49, 0xc0, 0x46, 0x0a, 0x60, 0x80, 0x23, 0xc2, 0x6f, 0x1a, 0x43, 
+0xc2, 0x67, 0x0a, 0x60, 0x82, 0x22, 0x80, 0x30, 0x02, 0x60, 0x4a, 0x60, 
+0x00, 0x21, 0x81, 0x80, 0x70, 0x47, 0x00, 0x00, 0xe8, 0x0d, 0x00, 0x80, 
+0x00, 0x01, 0x11, 0x00, 0xf0, 0xb4, 0x49, 0x49, 0xca, 0x1d, 0x99, 0x32, 
+0x00, 0x20, 0x00, 0x27, 0x83, 0x00, 0xd7, 0x50, 0x01, 0x30, 0x17, 0x28, 
+0xfa, 0xd3, 0x45, 0x4c, 0x00, 0x20, 0x82, 0x00, 0xa7, 0x50, 0x01, 0x30, 
+0x20, 0x28, 0xfa, 0xd3, 0x42, 0x4a, 0x00, 0x20, 0x83, 0x00, 0xd7, 0x50, 
+0x01, 0x30, 0x20, 0x28, 0xfa, 0xd3, 0xa7, 0x61, 0x97, 0x61, 0x4f, 0x65, 
+0x8f, 0x65, 0x3e, 0x4d, 0xc0, 0x46, 0x2f, 0x60, 0x6f, 0x60, 0xaf, 0x60, 
+0xaf, 0x61, 0xef, 0x60, 0x2f, 0x61, 0x6f, 0x61, 0x00, 0x20, 0xc1, 0x00, 
+0x09, 0x18, 0x49, 0x01, 0x34, 0x4b, 0xc9, 0x18, 0x86, 0x00, 0xcb, 0x1d, 
+0xf5, 0x33, 0x33, 0x4c, 0x34, 0x19, 0xe3, 0x63, 0x87, 0x23, 0x9b, 0x00, 
+0xcb, 0x18, 0x63, 0x63, 0xcf, 0x23, 0x9b, 0x00, 0xcb, 0x18, 0xb4, 0x18, 
+0xe3, 0x63, 0x30, 0x4b, 0xc9, 0x18, 0x61, 0x63, 0x01, 0x30, 0x02, 0x28, 
+0xe5, 0xdb, 0x29, 0x48, 0xc1, 0x1d, 0xf5, 0x31, 0x28, 0x4c, 0xc0, 0x46, 
+0xa1, 0x62, 0x61, 0x6b, 0xcf, 0x23, 0x9b, 0x00, 0xe1, 0x62, 0xc1, 0x18, 
+0x91, 0x62, 0x51, 0x6b, 0xc0, 0x46, 0xd1, 0x62, 0x08, 0x21, 0xe1, 0x64, 
+0x25, 0x49, 0xc0, 0x46, 0x21, 0x65, 0x25, 0x49, 0x0b, 0x69, 0xc0, 0x46, 
+0x63, 0x65, 0xc3, 0x1d, 0x4d, 0x33, 0xe3, 0x65, 0x25, 0x66, 0x8b, 0x68, 
+0xc0, 0x46, 0x63, 0x66, 0xcb, 0x68, 0xc0, 0x46, 0xa3, 0x66, 0x1f, 0x4b, 
+0xc0, 0x46, 0xe3, 0x66, 0x27, 0x67, 0x67, 0x67, 0x1d, 0x4b, 0xc3, 0x18, 
+0x01, 0x26, 0xa3, 0x67, 0x66, 0x61, 0xe7, 0x61, 0xe3, 0x1d, 0x69, 0x33, 
+0x1f, 0x73, 0x02, 0x23, 0xd3, 0x64, 0x19, 0x4b, 0xc0, 0x46, 0x13, 0x65, 
+0xcb, 0x69, 0xc0, 0x46, 0x53, 0x65, 0xc3, 0x1d, 0x51, 0x33, 0xd3, 0x65, 
+0x2b, 0x1d, 0x13, 0x66, 0x4b, 0x69, 0xc0, 0x46, 0x53, 0x66, 0x89, 0x69, 
+0xc0, 0x46, 0x91, 0x66, 0x11, 0x49, 0xc0, 0x46, 0xd1, 0x66, 0x16, 0x67, 
+0x56, 0x67, 0x10, 0x4b, 0xc0, 0x18, 0x90, 0x67, 0x56, 0x61, 0xd7, 0x61, 
+0xd0, 0x1d, 0x69, 0x30, 0x07, 0x73, 0xf0, 0xbc, 
+0x70, 0x47, 0x00, 0x00, 0xe8, 0x0d, 0x00, 0x80, 0x50, 0x2c, 0x00, 0x80, 
+0xd0, 0x2c, 0x00, 0x80, 0x3c, 0xef, 0x20, 0x40, 0x5c, 0x04, 0x00, 0x00, 
+0x30, 0x01, 0x18, 0x00, 0xf8, 0x28, 0x00, 0x80, 0x80, 0x54, 0xff, 0xff, 
+0x7c, 0x05, 0x00, 0x00, 0x38, 0x01, 0x18, 0x00, 0x90, 0x54, 0xff, 0xff, 
+0x7c, 0x07, 0x00, 0x00, 0x90, 0xb4, 0x00, 0x21, 0x1c, 0x4a, 0xbb, 0x23, 
+0x1b, 0x01, 0xd7, 0x18, 0xf9, 0x72, 0x19, 0x23, 0xdb, 0x01, 0xd0, 0x18, 
+0x33, 0x23, 0x9b, 0x01, 0xd3, 0x18, 0x81, 0x61, 0x59, 0x60, 0xb9, 0x72, 
+0x01, 0x27, 0x1f, 0x73, 0x19, 0x61, 0x17, 0x23, 0xdb, 0x01, 0xd3, 0x18, 
+0xd9, 0x63, 0x13, 0x4b, 0x51, 0x27, 0xbf, 0x03, 0xc3, 0x62, 0x3b, 0x60, 
+0x44, 0x69, 0xe4, 0x18, 0x04, 0x63, 0x04, 0x3c, 0x7c, 0x60, 0x01, 0x24, 
+0xe4, 0x02, 0x44, 0x63, 0x0d, 0x4c, 0xc0, 0x46, 0xbc, 0x60, 0xc4, 0x6a, 
+0xc0, 0x46, 0x04, 0x62, 0x44, 0x69, 0xe4, 0x18, 0x0a, 0x4b, 0xe3, 0x18, 
+0xfb, 0x60, 0xc3, 0x6a, 0xc0, 0x46, 0x43, 0x62, 0x03, 0x6a, 0xc0, 0x46, 
+0xc3, 0x61, 0x81, 0x63, 0x51, 0x64, 0x91, 0x64, 0xd1, 0x65, 0xd1, 0x66, 
+0x90, 0xbc, 0x70, 0x47, 0xe8, 0x0d, 0x00, 0x80, 0x00, 0x00, 0x20, 0x40, 
+0xfc, 0x07, 0x00, 0x00, 0xfc, 0xf7, 0xff, 0xff, 0x90, 0xb4, 0x00, 0x22, 
+0x1c, 0x49, 0xc9, 0x23, 0x1b, 0x01, 0xc8, 0x18, 0x02, 0x70, 0x01, 0x20, 
+0xbb, 0x23, 0x1b, 0x01, 0xcb, 0x18, 0x58, 0x72, 0x18, 0x48, 0x03, 0x1c, 
+0x00, 0x27, 0xdc, 0x1d, 0xc1, 0x34, 0x1c, 0x65, 0x23, 0x1c, 0x01, 0x37, 
+0x3f, 0x2f, 0xf8, 0xd3, 0x1a, 0x65, 0x19, 0x23, 0xdb, 0x01, 0xcf, 0x18, 
+0x33, 0x23, 0x9b, 0x01, 0xcc, 0x18, 0xfa, 0x60, 0x60, 0x61, 0x40, 0x20, 
+0xb8, 0x60, 0xa2, 0x61, 0xe2, 0x61, 0xca, 0x64, 0x0a, 0x66, 0x0d, 0x48, 
+0xc0, 0x46, 0xc2, 0x60, 0x0c, 0x48, 0x00, 0x6b, 0xc0, 0x06, 0xc0, 0x0e, 
+0xb8, 0x63, 0x0b, 0x48, 0x65, 0x23, 0x5b, 0x01, 0xc9, 0x18, 0x02, 0x68, 
+0xc0, 0x46, 0x8a, 0x83, 0x42, 0x68, 0xc0, 0x46, 0xca, 0x83, 0x80, 0x68, 
+0xc0, 0x46, 0x20, 0x80, 0x90, 0xbc, 0x70, 0x47, 0xe8, 0x0d, 0x00, 0x80, 
+0x3c, 0xbd, 0x20, 0x40, 0x3c, 0xef, 0x20, 0x40, 0x80, 0x00, 0x14, 0x40, 
+0x40, 0x00, 0x14, 0x40, 0x00, 0x20, 0x0a, 0x49, 0xc0, 0x46, 0x08, 0x73, 
+0xcb, 0x1d, 0xff, 0x33, 0x3a, 0x33, 0x88, 0x61, 0xc8, 0x61, 0x18, 0x70, 
+0x06, 0x4a, 0xc0, 0x46, 0x10, 0x65, 0x50, 0x66, 0x90, 0x66, 0x08, 0x70, 
+0x58, 0x70, 0xbb, 0x23, 0x1b, 0x01, 0xd1, 0x18, 0x08, 0x72, 0x70, 0x47, 
+0xa8, 0x04, 0x00, 0x80, 0xe8, 0x0d, 0x00, 0x80, 0xf0, 0xb4, 0x2f, 0x49, 
+0x2f, 0x4a, 0xc0, 0x46, 0x11, 0x61, 0x01, 0x23, 0x9b, 0x02, 0xc8, 0x18, 
+0x50, 0x61, 0x2d, 0x48, 0xc0, 0x46, 0x10, 0x62, 0xdb, 0x00, 0xc3, 0x18, 
+0x53, 0x62, 0x00, 0x23, 0x13, 0x63, 0x53, 0x63, 0x29, 0x4a, 0x2a, 0x4f, 
+0xd4, 0x1d, 0xff, 0x34, 0xfa, 0x34, 0x14, 0xc7, 0x08, 0x3f, 0x3b, 0x61, 
+0x1c, 0x1f, 0x7c, 0x61, 0x26, 0x4f, 0xc0, 0x46, 0x39, 0x60, 0xb8, 0x61, 
+0x79, 0x61, 0xf8, 0x62, 0x3b, 0x63, 0x7b, 0x64, 0xba, 0x64, 0xfa, 0x65, 
+0x22, 0x4f, 0xfe, 0x1d, 0xf9, 0x36, 0x22, 0x4d, 0xec, 0x1d, 0x79, 0x34, 
+0xe6, 0x61, 0x51, 0x26, 0xb6, 0x03, 0x37, 0x61, 0xe4, 0x69, 0xc0, 0x46, 
+0x74, 0x61, 0x2f, 0x67, 0x1d, 0x4d, 0x09, 0x27, 0x7f, 0x04, 0xec, 0x1d, 
+0x75, 0x34, 0x7c, 0x60, 0x3d, 0x60, 0x1b, 0x4c, 0xc0, 0x46, 0x3c, 0x61, 
+0xe6, 0x1d, 0x75, 0x36, 0x7e, 0x61, 0x19, 0x4f, 
+0xc0, 0x46, 0x7c, 0x60, 0x3d, 0x60, 0x0f, 0x1c, 0x00, 0x21, 0xff, 0x24, 
+0x01, 0x34, 0x1d, 0x1c, 0x8b, 0x00, 0xfd, 0x50, 0x01, 0x31, 0xa1, 0x42, 
+0xfa, 0xd3, 0x01, 0x1c, 0x00, 0x20, 0x01, 0x27, 0xff, 0x02, 0x83, 0x00, 
+0xcd, 0x50, 0x01, 0x30, 0xb8, 0x42, 0xfa, 0xd3, 0x00, 0x20, 0x81, 0x00, 
+0x55, 0x50, 0x01, 0x30, 0x80, 0x28, 0xfa, 0xd3, 0xf0, 0xbc, 0x70, 0x47, 
+0x24, 0xa3, 0x20, 0x40, 0x40, 0x01, 0x18, 0x00, 0x24, 0x83, 0x20, 0x40, 
+0x24, 0xa9, 0x20, 0x40, 0x80, 0x01, 0x18, 0x00, 0x28, 0x03, 0x00, 0x80, 
+0x24, 0xa7, 0x20, 0x40, 0xe8, 0x0d, 0x00, 0x80, 0x24, 0xa8, 0x20, 0x40, 
+0xa4, 0xa8, 0x20, 0x40, 0x88, 0x03, 0x00, 0x80, 0xb8, 0xb5, 0x2d, 0x48, 
+0xfd, 0xf7, 0xc6, 0xfa, 0x01, 0x20, 0x2c, 0x49, 0x0a, 0x68, 0x52, 0x0c, 
+0x06, 0xd2, 0x0a, 0x68, 0x12, 0x0c, 0x02, 0xd1, 0x0a, 0x68, 0x92, 0x0a, 
+0x00, 0xd2, 0x00, 0x20, 0x04, 0x06, 0x24, 0x0e, 0x26, 0x4a, 0xd7, 0x1d, 
+0x0d, 0x37, 0x00, 0x23, 0x00, 0x20, 0x9d, 0x00, 0x78, 0x51, 0x01, 0x33, 
+0x04, 0x2b, 0xfa, 0xd3, 0x01, 0x27, 0x3f, 0x05, 0x50, 0x61, 0xf8, 0x60, 
+0xd0, 0x61, 0xf8, 0x61, 0x00, 0x23, 0xdb, 0x43, 0x93, 0x61, 0x3b, 0x61, 
+0x13, 0x62, 0x3b, 0x62, 0x00, 0x27, 0x1c, 0x4b, 0x8d, 0x68, 0xc0, 0x46, 
+0x00, 0x95, 0x8d, 0x69, 0xc0, 0x46, 0x00, 0x95, 0x00, 0x2c, 0x0b, 0xd0, 
+0xdd, 0x6b, 0xc0, 0x46, 0x00, 0x95, 0x9d, 0x6b, 0xc0, 0x46, 0x00, 0x95, 
+0x5d, 0x6b, 0xc0, 0x46, 0x00, 0x95, 0x1d, 0x6b, 0xc0, 0x46, 0x00, 0x95, 
+0x01, 0x37, 0x40, 0x2f, 0xe8, 0xd3, 0x00, 0x27, 0x6c, 0x46, 0x01, 0x23, 
+0x5b, 0x07, 0x1c, 0x43, 0x01, 0xe0, 0x20, 0x60, 0x01, 0x37, 0x0d, 0x68, 
+0x2b, 0x09, 0x02, 0xd2, 0x80, 0x2f, 0xf8, 0xd3, 0x01, 0xe0, 0x80, 0x2f, 
+0x03, 0xd3, 0x09, 0x49, 0x4b, 0x6e, 0x01, 0x33, 0x4b, 0x66, 0xd0, 0x62, 
+0x07, 0x48, 0xfd, 0xf7, 0x71, 0xfa, 0xb8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0xf4, 0x01, 0xff, 0xff, 0x00, 0x00, 0x10, 0x40, 0xe8, 0x0d, 0x00, 0x80, 
+0x00, 0x01, 0x18, 0x40, 0xa0, 0x82, 0x20, 0x40, 0x04, 0x02, 0xff, 0xff, 
+0x90, 0xb4, 0x00, 0x21, 0x0e, 0x4f, 0x0f, 0x4a, 0x00, 0x20, 0x4c, 0x01, 
+0x64, 0x1a, 0xa4, 0x00, 0xa3, 0x18, 0x58, 0x60, 0x98, 0x60, 0x18, 0x64, 
+0x58, 0x64, 0x10, 0x53, 0x58, 0x80, 0xcc, 0x00, 0xe4, 0x19, 0x98, 0x67, 
+0xdc, 0x62, 0x01, 0x31, 0x03, 0x29, 0xee, 0xd3, 0x06, 0x49, 0xc0, 0x46, 
+0x08, 0x60, 0x48, 0x60, 0x88, 0x60, 0xc8, 0x60, 0x08, 0x61, 0x90, 0xbc, 
+0x70, 0x47, 0x00, 0x00, 0x58, 0x67, 0x21, 0x40, 0xc8, 0x2a, 0x00, 0x80, 
+0x3c, 0x2c, 0x00, 0x80, 0x00, 0xb5, 0x64, 0x21, 0x07, 0x48, 0xc0, 0x46, 
+0x01, 0x63, 0x00, 0x21, 0xc9, 0x43, 0x41, 0x63, 0x81, 0x63, 0x00, 0x21, 
+0xc1, 0x63, 0x01, 0x64, 0x03, 0x48, 0x28, 0x22, 0x02, 0xf0, 0x06, 0xff, 
+0x08, 0xbc, 0x18, 0x47, 0xe8, 0x0d, 0x00, 0x80, 0x59, 0x03, 0xff, 0xff, 
+0x80, 0xb4, 0x01, 0x20, 0x40, 0x02, 0x0a, 0x49, 0xc0, 0x46, 0x08, 0x60, 
+0x3c, 0x20, 0x48, 0x60, 0x88, 0x60, 0x08, 0x48, 0xc0, 0x46, 0xc8, 0x60, 
+0x00, 0x20, 0x07, 0x4a, 0x87, 0x00, 0xcb, 0x68, 0xc0, 0x46, 0xda, 0x51, 
+0x01, 0x30, 0x10, 0x28, 0xf8, 0xd3, 0x80, 0xbc, 0x70, 0x47, 0x00, 0x00, 
+0x50, 0x2d, 0x00, 0x80, 0x60, 0x2d, 0x00, 0x80, 0xd5, 0x4b, 0xff, 0xff, 
+0x12, 0x49, 0x13, 0x48, 0x67, 0x23, 0x9b, 0x01, 0xca, 0x18, 0x06, 0xc0, 
+0x08, 0x38, 0x11, 0x4b, 0xca, 0x18, 0xc1, 0x60, 
+0x82, 0x60, 0x01, 0x61, 0x0f, 0x49, 0x10, 0x48, 0xa7, 0x23, 0x9b, 0x01, 
+0xca, 0x18, 0x06, 0xc0, 0x08, 0x38, 0x0e, 0x4b, 0xca, 0x18, 0xc1, 0x60, 
+0x82, 0x60, 0x01, 0x61, 0x0c, 0x48, 0x0d, 0x49, 0x67, 0x23, 0x9b, 0x01, 
+0xc2, 0x18, 0x05, 0xc1, 0x08, 0x39, 0x05, 0x4b, 0xc2, 0x18, 0xc8, 0x60, 
+0x8a, 0x60, 0x08, 0x61, 0x70, 0x47, 0x00, 0x00, 0x58, 0x1f, 0x21, 0x40, 
+0xb4, 0x2d, 0x00, 0x80, 0xfc, 0x1f, 0x00, 0x00, 0x58, 0xef, 0x20, 0x40, 
+0xa0, 0x2d, 0x00, 0x80, 0xfc, 0x2f, 0x00, 0x00, 0x58, 0x3f, 0x21, 0x40, 
+0xc8, 0x2d, 0x00, 0x80, 0x90, 0xb4, 0x00, 0x21, 0x40, 0x4c, 0x00, 0x20, 
+0x0a, 0x01, 0x12, 0x19, 0x19, 0x23, 0xdb, 0x01, 0xd2, 0x18, 0xd0, 0x62, 
+0x10, 0x63, 0x50, 0x63, 0x90, 0x63, 0x01, 0x31, 0x03, 0x29, 0xf3, 0xd3, 
+0x3a, 0x49, 0xc0, 0x46, 0xc8, 0x62, 0x08, 0x63, 0x48, 0x63, 0x20, 0x60, 
+0x01, 0x21, 0xe3, 0x1d, 0x59, 0x33, 0x60, 0x60, 0x19, 0x71, 0x18, 0x72, 
+0x98, 0x71, 0x98, 0x72, 0x59, 0x71, 0x58, 0x72, 0xd8, 0x71, 0xd8, 0x72, 
+0xe2, 0x1d, 0x49, 0x32, 0x11, 0x73, 0x19, 0x70, 0x90, 0x73, 0x98, 0x70, 
+0x51, 0x73, 0x59, 0x70, 0xd0, 0x73, 0xd8, 0x70, 0x11, 0x71, 0x11, 0x72, 
+0x90, 0x71, 0x90, 0x72, 0x50, 0x71, 0x50, 0x72, 0xd0, 0x71, 0xd0, 0x72, 
+0x18, 0x73, 0x02, 0x22, 0xe7, 0x1d, 0x69, 0x37, 0x3a, 0x70, 0x99, 0x73, 
+0xba, 0x70, 0x58, 0x73, 0x78, 0x70, 0xd8, 0x73, 0xf8, 0x70, 0x39, 0x71, 
+0x3a, 0x72, 0xb9, 0x71, 0xb9, 0x72, 0x78, 0x71, 0x7a, 0x72, 0xf9, 0x71, 
+0xf9, 0x72, 0x39, 0x73, 0xe3, 0x1d, 0x79, 0x33, 0x1a, 0x70, 0xb9, 0x73, 
+0x99, 0x70, 0x78, 0x73, 0x5a, 0x70, 0xf9, 0x73, 0xd9, 0x70, 0x1a, 0x71, 
+0x1a, 0x72, 0x99, 0x71, 0x9a, 0x72, 0x58, 0x71, 0x5a, 0x72, 0xd9, 0x71, 
+0xda, 0x72, 0x19, 0x73, 0xe7, 0x1d, 0x89, 0x37, 0x3a, 0x70, 0x99, 0x73, 
+0xb9, 0x70, 0x58, 0x73, 0x7a, 0x70, 0xd9, 0x73, 0xf9, 0x70, 0x39, 0x71, 
+0x3a, 0x72, 0xb9, 0x71, 0xb9, 0x72, 0x78, 0x71, 0x7a, 0x72, 0xf9, 0x71, 
+0xf9, 0x72, 0x3a, 0x73, 0xe3, 0x1d, 0x99, 0x33, 0x1a, 0x70, 0xb9, 0x73, 
+0x9a, 0x70, 0x78, 0x73, 0x5a, 0x70, 0xf9, 0x73, 0xda, 0x70, 0x19, 0x71, 
+0x1a, 0x72, 0x99, 0x71, 0x99, 0x72, 0x58, 0x71, 0x5a, 0x72, 0xd9, 0x71, 
+0xd9, 0x72, 0x20, 0x61, 0xe0, 0x60, 0x60, 0x61, 0xa0, 0x60, 0x90, 0xbc, 
+0x70, 0x47, 0x00, 0x00, 0x1c, 0x1c, 0x00, 0x80, 0x68, 0x19, 0x00, 0x80, 
+0x81, 0x20, 0x00, 0x02, 0x01, 0x49, 0xc0, 0x46, 0x88, 0x62, 0x70, 0x47, 
+0xc0, 0x00, 0x14, 0x00, 0x0a, 0x49, 0x13, 0x23, 0xdb, 0x01, 0xc8, 0x18, 
+0x25, 0x23, 0x9b, 0x01, 0xc9, 0x18, 0xc8, 0x63, 0x00, 0x21, 0xc2, 0x1d, 
+0x29, 0x32, 0xc2, 0x61, 0x10, 0x1c, 0x01, 0x31, 0x08, 0x29, 0xf8, 0xd3, 
+0xc1, 0x1f, 0x29, 0x39, 0x00, 0x20, 0xc8, 0x61, 0x70, 0x47, 0x00, 0x00, 
+0xe8, 0x0d, 0x00, 0x80, 0x06, 0x48, 0x07, 0x49, 0xc0, 0x46, 0x08, 0x80, 
+0x48, 0x80, 0x00, 0x20, 0x88, 0x80, 0xc8, 0x80, 0x88, 0x60, 0x04, 0x49, 
+0xc0, 0x46, 0x48, 0x61, 0x88, 0x61, 0x70, 0x47, 0xff, 0xff, 0x00, 0x00, 
+0xc8, 0x29, 0x00, 0x80, 0xec, 0x05, 0x00, 0x80, 0x00, 0x21, 0x06, 0x48, 
+0xc2, 0x1d, 0x19, 0x32, 0xc1, 0x60, 0x01, 0x61, 0xc1, 0x61, 0x01, 0x62, 
+0x11, 0x71, 0xff, 0x30, 0x01, 0x30, 0x41, 0x62, 0x70, 0x47, 0x00, 0x00, 
+0xec, 0x05, 0x00, 0x80, 0x09, 0x48, 0x0a, 0x4b, 0xc0, 0x46, 0x18, 0x60, 
+0x00, 0x21, 0xc2, 0x1d, 0x4d, 0x32, 0xc2, 0x60, 
+0x10, 0x1c, 0x01, 0x31, 0x14, 0x29, 0xf8, 0xd3, 0xc1, 0x1f, 0x4d, 0x39, 
+0x00, 0x20, 0xc8, 0x60, 0x58, 0x60, 0x98, 0x60, 0x70, 0x47, 0x00, 0x00, 
+0x58, 0x07, 0x00, 0x80, 0xec, 0x05, 0x00, 0x80, 0x00, 0xb5, 0x0c, 0x49, 
+0x0c, 0x48, 0xfd, 0xf7, 0xea, 0xf8, 0x0c, 0x48, 0x00, 0x6a, 0x01, 0x23, 
+0xdb, 0x03, 0x98, 0x43, 0x0a, 0x49, 0xc0, 0x46, 0x08, 0x62, 0x0a, 0x48, 
+0xc1, 0x68, 0x01, 0x29, 0x06, 0xd1, 0x80, 0x23, 0xc1, 0x6f, 0x19, 0x43, 
+0xc1, 0x67, 0x07, 0x48, 0xc0, 0x46, 0x01, 0x60, 0x08, 0xbc, 0x18, 0x47, 
+0x59, 0xcd, 0x21, 0x40, 0x61, 0xa1, 0x21, 0x40, 0xc0, 0x00, 0x18, 0x40, 
+0xc0, 0x00, 0x18, 0x00, 0xe8, 0x0d, 0x00, 0x80, 0x00, 0x01, 0x11, 0x00, 
+0x00, 0xb5, 0x10, 0x48, 0xc1, 0x68, 0x01, 0x29, 0x06, 0xd1, 0x80, 0x23, 
+0xc1, 0x6f, 0x99, 0x43, 0xc1, 0x67, 0x0d, 0x48, 0xc0, 0x46, 0x01, 0x60, 
+0x0c, 0x4b, 0x0d, 0x48, 0x0d, 0x4a, 0x00, 0x21, 0xfd, 0xf7, 0xb9, 0xf8, 
+0x0c, 0x48, 0x41, 0x8d, 0x01, 0x31, 0x41, 0x85, 0x00, 0x21, 0xc1, 0x85, 
+0x0a, 0x48, 0x00, 0x6a, 0x01, 0x23, 0xdb, 0x03, 0x18, 0x43, 0x09, 0x49, 
+0xc0, 0x46, 0x08, 0x62, 0x08, 0xbc, 0x18, 0x47, 0xe8, 0x0d, 0x00, 0x80, 
+0x00, 0x01, 0x11, 0x00, 0xf1, 0xcc, 0x21, 0x40, 0x61, 0xa1, 0x21, 0x40, 
+0xb8, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0x00, 0x18, 0x40, 
+0xc0, 0x00, 0x18, 0x00, 0xf0, 0xb5, 0xfe, 0xf7, 0xa3, 0xfe, 0x19, 0x4c, 
+0x10, 0x26, 0xe0, 0x68, 0x01, 0x28, 0x05, 0xd1, 0x60, 0x88, 0x00, 0x28, 
+0x02, 0xd1, 0x19, 0x20, 0xa0, 0x67, 0x00, 0xe0, 0xa6, 0x67, 0x00, 0x20, 
+0x07, 0x23, 0x5b, 0x02, 0xe5, 0x18, 0xc1, 0x43, 0xa8, 0x61, 0x29, 0x62, 
+0x59, 0x08, 0xa1, 0x27, 0x7f, 0x03, 0x79, 0x60, 0x0f, 0x21, 0x79, 0x60, 
+0xe1, 0x1d, 0xb9, 0x31, 0x08, 0x70, 0x01, 0x20, 0xb8, 0x60, 0x40, 0x02, 
+0xb8, 0x60, 0x00, 0xf0, 0x47, 0xfa, 0x00, 0xf0, 0xd9, 0xfa, 0x04, 0x20, 
+0xb8, 0x60, 0x07, 0x20, 0x78, 0x61, 0x7e, 0x60, 0x1b, 0x23, 0xdb, 0x01, 
+0xe0, 0x18, 0x40, 0x8b, 0x04, 0x23, 0x18, 0x40, 0xa8, 0x62, 0xf0, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0xe8, 0x0d, 0x00, 0x80, 0x80, 0xb4, 0x02, 0x1c, 
+0x00, 0x20, 0xff, 0x23, 0x01, 0x33, 0x9a, 0x42, 0x08, 0xd0, 0x01, 0x29, 
+0x00, 0xd1, 0x01, 0x20, 0x00, 0x2a, 0x01, 0xd1, 0x02, 0x23, 0x18, 0x43, 
+0x80, 0xbc, 0x70, 0x47, 0x18, 0x49, 0xca, 0x68, 0x18, 0x4b, 0x01, 0x2a, 
+0x0b, 0xd1, 0x4a, 0x88, 0x00, 0x2a, 0x08, 0xd1, 0xd9, 0x8a, 0x0a, 0x09, 
+0x00, 0xd3, 0x02, 0x20, 0x49, 0x09, 0xef, 0xd3, 0x01, 0x23, 0x18, 0x43, 
+0xec, 0xe7, 0x0a, 0x79, 0x00, 0x2a, 0x03, 0xd0, 0x18, 0x8a, 0x80, 0x07, 
+0x80, 0x0f, 0xe5, 0xe7, 0x6d, 0x23, 0x5b, 0x01, 0xc9, 0x18, 0x0a, 0x88, 
+0xff, 0x27, 0x01, 0x37, 0x17, 0x40, 0x0b, 0x49, 0x49, 0x88, 0x03, 0xd0, 
+0x4b, 0x0a, 0x01, 0xd3, 0x03, 0x20, 0xd7, 0xe7, 0x13, 0x0a, 0x03, 0xd3, 
+0x0b, 0x0a, 0x01, 0xd3, 0x02, 0x20, 0xd1, 0xe7, 0xd2, 0x09, 0xcf, 0xd3, 
+0xc9, 0x09, 0xcd, 0xd3, 0x01, 0x20, 0xcb, 0xe7, 0xe8, 0x0d, 0x00, 0x80, 
+0xa8, 0x1b, 0x00, 0x80, 0x88, 0x1b, 0x00, 0x80, 0xf0, 0xb5, 0xc1, 0xb0, 
+0x01, 0x20, 0x00, 0x07, 0x52, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x52, 0x48, 
+0x42, 0x69, 0x40, 0x0d, 0xa1, 0x21, 0x49, 0x03, 0x48, 0x60, 0x50, 0x48, 
+0xc0, 0x6a, 0x50, 0x4b, 0x18, 0x43, 0x00, 0x21, 0x03, 0x03, 0x1b, 0x0b, 
+0x4e, 0x4c, 0x27, 0x6f, 0x3d, 0x03, 0x2d, 0x0b, 
+0xe7, 0x1d, 0x79, 0x37, 0xab, 0x42, 0x1c, 0xd0, 0xe3, 0x1d, 0x79, 0x33, 
+0xdb, 0x69, 0xc0, 0x46, 0x40, 0x93, 0x01, 0x23, 0x9b, 0x07, 0x03, 0x43, 
+0x1b, 0x68, 0xcc, 0x00, 0x6e, 0x46, 0x33, 0x51, 0x01, 0x23, 0x9b, 0x07, 
+0x06, 0x1d, 0x33, 0x43, 0x1b, 0x68, 0x6c, 0x44, 0x63, 0x60, 0x08, 0x30, 
+0x01, 0x31, 0x40, 0x9b, 0x83, 0x42, 0x00, 0xd8, 0x3f, 0x48, 0x03, 0x03, 
+0x1b, 0x0b, 0xab, 0x42, 0xe7, 0xd1, 0x00, 0x20, 0x01, 0x23, 0x1b, 0x03, 
+0x13, 0x40, 0x3c, 0x4c, 0x03, 0xd0, 0x63, 0x6a, 0x01, 0x33, 0x63, 0x62, 
+0x09, 0xe0, 0x13, 0x0b, 0x03, 0xd3, 0x23, 0x6a, 0x01, 0x33, 0x23, 0x62, 
+0x03, 0xe0, 0x37, 0x4b, 0x5c, 0x6d, 0x01, 0x34, 0x5c, 0x65, 0x00, 0x29, 
+0x09, 0xd0, 0x03, 0x1c, 0xdc, 0x00, 0x23, 0x1c, 0x6b, 0x44, 0x5c, 0x68, 
+0x01, 0x30, 0x23, 0x0d, 0x01, 0xd2, 0x88, 0x42, 0xf5, 0xd1, 0x30, 0x4c, 
+0x25, 0x68, 0x6b, 0x0c, 0x05, 0xd2, 0x23, 0x68, 0x1b, 0x0c, 0x08, 0xd1, 
+0x24, 0x68, 0xa3, 0x0a, 0x05, 0xd3, 0x20, 0x24, 0x2b, 0x4b, 0xc0, 0x46, 
+0x5c, 0x62, 0x00, 0x24, 0x5c, 0x62, 0x25, 0x4b, 0x23, 0x4c, 0x51, 0x26, 
+0xb6, 0x03, 0x23, 0x67, 0x33, 0x61, 0xfd, 0x69, 0xc0, 0x46, 0x75, 0x61, 
+0x02, 0x25, 0xa1, 0x26, 0x76, 0x03, 0x75, 0x60, 0x01, 0x25, 0xb5, 0x60, 
+0xe6, 0x1d, 0xb9, 0x36, 0x35, 0x70, 0x88, 0x42, 0x21, 0xd0, 0x25, 0x1c, 
+0xc3, 0x00, 0x6c, 0x46, 0xe4, 0x58, 0x2e, 0x6f, 0x6b, 0x44, 0x34, 0x60, 
+0x5b, 0x68, 0x2c, 0x6f, 0xc0, 0x46, 0x63, 0x60, 0x2b, 0x6f, 0x08, 0x33, 
+0x2b, 0x67, 0xfc, 0x69, 0xa3, 0x42, 0x02, 0xd3, 0x12, 0x4b, 0xc0, 0x46, 
+0x2b, 0x67, 0x03, 0x1c, 0xdb, 0x00, 0x6b, 0x44, 0x5c, 0x68, 0x01, 0x30, 
+0x23, 0x0d, 0x04, 0xd3, 0x51, 0x24, 0xa4, 0x03, 0x2b, 0x6f, 0xc0, 0x46, 
+0xa3, 0x61, 0x88, 0x42, 0xde, 0xd1, 0x10, 0x0b, 0x03, 0xd3, 0x0e, 0x49, 
+0x01, 0x20, 0xfc, 0xf7, 0x72, 0xff, 0x41, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x01, 0x14, 0x40, 
+0x00, 0x40, 0x14, 0x40, 0x00, 0x00, 0x20, 0x40, 0xe8, 0x0d, 0x00, 0x80, 
+0x24, 0xa7, 0x20, 0x40, 0x10, 0x2a, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, 
+0x00, 0x00, 0x10, 0x40, 0xc0, 0x00, 0x18, 0x00, 0x49, 0x4f, 0xff, 0xff, 
+0xf0, 0xb4, 0x00, 0x21, 0x00, 0x23, 0x07, 0x22, 0x06, 0x24, 0x47, 0x4f, 
+0xc0, 0x46, 0x3c, 0x61, 0x3a, 0x61, 0x01, 0x33, 0x20, 0x2b, 0xf9, 0xd3, 
+0x04, 0x25, 0x3d, 0x61, 0x05, 0x23, 0x3b, 0x61, 0x3c, 0x61, 0x3a, 0x61, 
+0x3c, 0x61, 0x3a, 0x61, 0x3d, 0x61, 0x3b, 0x61, 0x3f, 0x4d, 0xab, 0x6f, 
+0xde, 0x08, 0x02, 0x23, 0x1e, 0x40, 0x04, 0x23, 0x33, 0x43, 0x3b, 0x61, 
+0x05, 0x23, 0x33, 0x43, 0x3b, 0x61, 0xab, 0x6f, 0x9e, 0x08, 0x02, 0x23, 
+0x1e, 0x40, 0x04, 0x23, 0x33, 0x43, 0x3b, 0x61, 0x05, 0x23, 0x33, 0x43, 
+0x3b, 0x61, 0xab, 0x6f, 0x5e, 0x08, 0x02, 0x23, 0x1e, 0x40, 0x04, 0x23, 
+0x33, 0x43, 0x3b, 0x61, 0x05, 0x23, 0x33, 0x43, 0x3b, 0x61, 0x02, 0x23, 
+0xae, 0x6f, 0x1e, 0x40, 0x04, 0x23, 0x33, 0x43, 0x3b, 0x61, 0x05, 0x23, 
+0x33, 0x43, 0x3b, 0x61, 0xab, 0x6f, 0x5d, 0x00, 0x02, 0x23, 0x1d, 0x40, 
+0x04, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x05, 0x23, 0x2b, 0x43, 0x3b, 0x61, 
+0xc5, 0x08, 0x02, 0x23, 0x1d, 0x40, 0x04, 0x23, 0x2b, 0x43, 0x3b, 0x61, 
+0x05, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x85, 0x08, 0x02, 0x23, 0x1d, 0x40, 
+0x04, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x05, 0x23, 
+0x2b, 0x43, 0x3b, 0x61, 0x45, 0x08, 0x02, 0x23, 0x1d, 0x40, 0x04, 0x23, 
+0x2b, 0x43, 0x3b, 0x61, 0x05, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x02, 0x25, 
+0x05, 0x40, 0x04, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x05, 0x23, 0x2b, 0x43, 
+0x3b, 0x61, 0x40, 0x00, 0x02, 0x23, 0x18, 0x40, 0x04, 0x23, 0x03, 0x43, 
+0x3b, 0x61, 0x05, 0x23, 0x18, 0x43, 0x38, 0x61, 0x00, 0x25, 0x3d, 0x61, 
+0x01, 0x23, 0x3b, 0x61, 0x3d, 0x61, 0x3b, 0x61, 0x00, 0x20, 0x3d, 0x61, 
+0x0d, 0x4b, 0x1b, 0x69, 0x49, 0x00, 0x1e, 0x1c, 0x02, 0x23, 0x33, 0x40, 
+0x19, 0x43, 0x01, 0x23, 0x3b, 0x61, 0x01, 0x30, 0x10, 0x28, 0xf2, 0xd3, 
+0x02, 0x20, 0x38, 0x61, 0x03, 0x20, 0x38, 0x61, 0x3c, 0x61, 0x3a, 0x61, 
+0x3c, 0x61, 0x3a, 0x61, 0x38, 0x61, 0x48, 0x08, 0xf0, 0xbc, 0x70, 0x47, 
+0x80, 0x00, 0x14, 0x00, 0xe8, 0x0d, 0x00, 0x80, 0x80, 0x00, 0x14, 0x40, 
+0xf0, 0xb4, 0x00, 0x24, 0x07, 0x23, 0x06, 0x27, 0x44, 0x4a, 0xc0, 0x46, 
+0x17, 0x61, 0x13, 0x61, 0x01, 0x34, 0x20, 0x2c, 0xf9, 0xd3, 0x04, 0x26, 
+0x16, 0x61, 0x05, 0x24, 0x14, 0x61, 0x17, 0x61, 0x07, 0x23, 0x13, 0x61, 
+0x16, 0x61, 0x14, 0x61, 0x17, 0x61, 0x13, 0x61, 0x3c, 0x4b, 0x9b, 0x6f, 
+0xdd, 0x08, 0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61, 
+0x25, 0x43, 0x15, 0x61, 0x37, 0x4b, 0x9b, 0x6f, 0x9d, 0x08, 0x02, 0x23, 
+0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61, 0x25, 0x43, 0x15, 0x61, 
+0x32, 0x4b, 0x9b, 0x6f, 0x5d, 0x08, 0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c, 
+0x33, 0x43, 0x13, 0x61, 0x25, 0x43, 0x15, 0x61, 0x2d, 0x4b, 0x9d, 0x6f, 
+0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61, 0x25, 0x43, 
+0x15, 0x61, 0x29, 0x4b, 0x9b, 0x6f, 0x5d, 0x00, 0x02, 0x23, 0x1d, 0x40, 
+0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61, 0x25, 0x43, 0x15, 0x61, 0xc5, 0x08, 
+0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61, 0x25, 0x43, 
+0x15, 0x61, 0x85, 0x08, 0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43, 
+0x13, 0x61, 0x25, 0x43, 0x15, 0x61, 0x45, 0x08, 0x02, 0x23, 0x1d, 0x40, 
+0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61, 0x25, 0x43, 0x15, 0x61, 0x02, 0x25, 
+0x05, 0x40, 0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61, 0x25, 0x43, 0x15, 0x61, 
+0x40, 0x00, 0x02, 0x23, 0x18, 0x40, 0x03, 0x1c, 0x33, 0x43, 0x13, 0x61, 
+0x20, 0x43, 0x10, 0x61, 0x17, 0x61, 0x07, 0x23, 0x13, 0x61, 0x16, 0x61, 
+0x14, 0x61, 0x4c, 0x00, 0x00, 0x20, 0x0f, 0x21, 0x25, 0x1c, 0xcd, 0x40, 
+0x02, 0x23, 0x1d, 0x40, 0x04, 0x23, 0x2b, 0x43, 0x13, 0x61, 0x05, 0x23, 
+0x2b, 0x43, 0x13, 0x61, 0x01, 0x30, 0x01, 0x39, 0x10, 0x28, 0xf1, 0xd3, 
+0x17, 0x61, 0x07, 0x23, 0x13, 0x61, 0x17, 0x61, 0x13, 0x61, 0x03, 0x20, 
+0x10, 0x61, 0xf0, 0xbc, 0x70, 0x47, 0x00, 0x00, 0x80, 0x00, 0x14, 0x00, 
+0xe8, 0x0d, 0x00, 0x80, 0xf0, 0xb5, 0x47, 0x48, 0x01, 0x89, 0x47, 0x4d, 
+0x07, 0x23, 0x5b, 0x02, 0xef, 0x18, 0xb9, 0x83, 0x40, 0x8b, 0xc0, 0x46, 
+0xf8, 0x83, 0x28, 0x79, 0x00, 0x28, 0x01, 0xd0, 0x00, 0x20, 0xb8, 0x83, 
+0xe8, 0x68, 0x01, 0x28, 0x06, 0xd1, 0x68, 0x88, 0x00, 0x28, 0x03, 0xd1, 
+0xf9, 0x21, 0x12, 0x20, 0xff, 0xf7, 0x54, 0xff, 0x01, 0x21, 0xc9, 0x03, 
+0x00, 0x20, 0xff, 0xf7, 0x4f, 0xff, 0x00, 0x24, 0x7d, 0x26, 0xf6, 0x00, 
+0x00, 0xe0, 0x01, 0x34, 0x00, 0x20, 0xff, 0xf7, 0xad, 0xfe, 0x00, 0x0c, 
+0x01, 0xd3, 0xb4, 0x42, 0xf7, 0xd3, 0x00, 0x24, 
+0x05, 0xe0, 0x03, 0x21, 0x09, 0x03, 0x00, 0x20, 0xff, 0xf7, 0x3c, 0xff, 
+0x01, 0x34, 0x00, 0x20, 0xff, 0xf7, 0x9e, 0xfe, 0x40, 0x0b, 0x01, 0xd2, 
+0xb4, 0x42, 0xf2, 0xd3, 0x04, 0x20, 0xff, 0xf7, 0x97, 0xfe, 0xff, 0x23, 
+0xe1, 0x33, 0x98, 0x43, 0x01, 0x21, 0x01, 0x43, 0xb8, 0x8b, 0xff, 0x23, 
+0x01, 0x33, 0x98, 0x42, 0x03, 0xd1, 0x2f, 0x23, 0x5b, 0x01, 0x19, 0x43, 
+0x16, 0xe0, 0x01, 0x28, 0x09, 0xd1, 0xf8, 0x8b, 0x01, 0x28, 0x03, 0xd1, 
+0x23, 0x23, 0x5b, 0x01, 0x19, 0x43, 0x0d, 0xe0, 0x20, 0x23, 0x19, 0x43, 
+0x0a, 0xe0, 0x00, 0x28, 0x08, 0xd1, 0xf8, 0x8b, 0x01, 0x28, 0x03, 0xd1, 
+0x0b, 0x23, 0xdb, 0x01, 0x19, 0x43, 0x01, 0xe0, 0x80, 0x23, 0x19, 0x43, 
+0x04, 0x20, 0xff, 0xf7, 0x09, 0xff, 0x09, 0x21, 0x49, 0x02, 0x00, 0x20, 
+0xff, 0xf7, 0x04, 0xff, 0xe8, 0x68, 0x00, 0x28, 0x0c, 0xd1, 0x00, 0x21, 
+0x1b, 0x20, 0xff, 0xf7, 0xfd, 0xfe, 0x1a, 0x20, 0xff, 0xf7, 0x60, 0xfe, 
+0x01, 0x21, 0xc9, 0x03, 0x01, 0x43, 0x1a, 0x20, 0xff, 0xf7, 0xf4, 0xfe, 
+0x00, 0x27, 0x03, 0xe0, 0x08, 0x2f, 0x01, 0xd3, 0x0f, 0x2f, 0x08, 0xd9, 
+0x38, 0x1c, 0xff, 0xf7, 0x51, 0xfe, 0x79, 0x00, 0x49, 0x19, 0x1b, 0x23, 
+0xdb, 0x01, 0xc9, 0x18, 0x08, 0x83, 0x01, 0x37, 0x20, 0x2f, 0xef, 0xd3, 
+0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x70, 0x67, 0x21, 0x40, 
+0xe8, 0x0d, 0x00, 0x80, 0x81, 0xb0, 0x13, 0x48, 0x01, 0x68, 0xc0, 0x46, 
+0x00, 0x91, 0x41, 0x68, 0xc0, 0x46, 0x00, 0x91, 0x81, 0x68, 0xc0, 0x46, 
+0x00, 0x91, 0xc1, 0x68, 0xc0, 0x46, 0x00, 0x91, 0x01, 0x69, 0xc0, 0x46, 
+0x00, 0x91, 0x41, 0x69, 0xc0, 0x46, 0x00, 0x91, 0x81, 0x69, 0xc0, 0x46, 
+0x00, 0x91, 0xc1, 0x69, 0xc0, 0x46, 0x00, 0x91, 0x01, 0x6a, 0xc0, 0x46, 
+0x00, 0x91, 0x41, 0x6a, 0xc0, 0x46, 0x00, 0x91, 0x81, 0x6a, 0xc0, 0x46, 
+0x00, 0x91, 0xc0, 0x6a, 0xc0, 0x46, 0x00, 0x90, 0x01, 0xb0, 0x70, 0x47, 
+0x00, 0x08, 0x14, 0x40, 0xf0, 0xb5, 0x83, 0xb0, 0x66, 0x4e, 0x1b, 0x23, 
+0xdb, 0x01, 0xf7, 0x18, 0x78, 0x8b, 0x04, 0x22, 0x02, 0x40, 0x02, 0x92, 
+0x07, 0x23, 0x5b, 0x02, 0xf4, 0x18, 0xa0, 0x8b, 0xc0, 0x46, 0x01, 0x90, 
+0xe0, 0x8b, 0xc0, 0x46, 0x00, 0x90, 0x00, 0x25, 0x03, 0xe0, 0x08, 0x2d, 
+0x01, 0xd3, 0x0f, 0x2d, 0x08, 0xd9, 0x28, 0x1c, 0xff, 0xf7, 0xfa, 0xfd, 
+0x69, 0x00, 0x89, 0x19, 0x1b, 0x23, 0xdb, 0x01, 0xc9, 0x18, 0x08, 0x83, 
+0x01, 0x35, 0x20, 0x2d, 0xef, 0xd3, 0xa0, 0x69, 0x00, 0x28, 0x15, 0xd0, 
+0x54, 0x4e, 0x20, 0x25, 0x01, 0x3d, 0x52, 0x49, 0xa0, 0x69, 0x30, 0x40, 
+0x0b, 0xd0, 0x68, 0x00, 0x40, 0x18, 0x37, 0x23, 0x9b, 0x01, 0xc0, 0x18, 
+0x01, 0x8b, 0x28, 0x1c, 0xff, 0xf7, 0x78, 0xfe, 0xa0, 0x69, 0xb0, 0x43, 
+0xa0, 0x61, 0x76, 0x08, 0x00, 0x2d, 0xeb, 0xd1, 0x01, 0x20, 0xff, 0xf7, 
+0xd5, 0xfd, 0x01, 0x1c, 0x46, 0x48, 0xc0, 0x46, 0x79, 0x83, 0x79, 0x8b, 
+0xca, 0x08, 0x22, 0xd3, 0xc2, 0x68, 0x01, 0x2a, 0x10, 0xd1, 0x40, 0x88, 
+0x00, 0x28, 0x1c, 0xd1, 0x01, 0x98, 0x42, 0x4a, 0x00, 0x28, 0x05, 0xd0, 
+0x01, 0x28, 0x16, 0xd1, 0xd0, 0x8a, 0xc0, 0x08, 0x13, 0xd2, 0x0f, 0xe0, 
+0xd0, 0x8a, 0x00, 0x09, 0x0f, 0xd2, 0x0b, 0xe0, 0x02, 0x79, 0x00, 0x2a, 
+0x0b, 0xd1, 0x6d, 0x23, 0x5b, 0x01, 0xc0, 0x18, 0x02, 0x88, 0x40, 0x88, 
+0x10, 0x40, 0x40, 0x09, 0x00, 0x07, 0x02, 0xd1, 0x04, 0x23, 0x99, 0x43, 
+0x79, 0x83, 0x78, 0x8b, 0x04, 0x21, 0x01, 0x40, 
+0x02, 0x9a, 0x1f, 0xd0, 0x39, 0x8b, 0x4a, 0x0b, 0x27, 0xd3, 0x80, 0x09, 
+0x25, 0xd3, 0xff, 0x23, 0x01, 0x98, 0x01, 0x33, 0x98, 0x42, 0x20, 0xd0, 
+0x00, 0x25, 0x00, 0x98, 0x01, 0x28, 0x00, 0xd1, 0x05, 0x02, 0x01, 0x98, 
+0x00, 0x28, 0x02, 0xd1, 0x01, 0x23, 0x5b, 0x03, 0x1d, 0x43, 0xa9, 0x42, 
+0x13, 0xd0, 0x00, 0x20, 0x29, 0x1c, 0xff, 0xf7, 0x25, 0xfe, 0x3d, 0x83, 
+0x00, 0x20, 0xc0, 0x43, 0x20, 0x62, 0x0a, 0xe0, 0x38, 0x8b, 0x40, 0x0b, 
+0x07, 0xd2, 0x09, 0x21, 0x49, 0x02, 0x00, 0x20, 0xff, 0xf7, 0x18, 0xfe, 
+0x09, 0x20, 0x40, 0x02, 0x38, 0x83, 0x78, 0x8b, 0xc0, 0x08, 0x2d, 0xd3, 
+0x1b, 0x48, 0xc7, 0x6a, 0x01, 0x98, 0x00, 0x99, 0xff, 0xf7, 0x6a, 0xfc, 
+0xc2, 0x07, 0xd2, 0x0f, 0x18, 0x49, 0x03, 0xd0, 0x04, 0x23, 0xcd, 0x6d, 
+0x2b, 0x43, 0x03, 0xe0, 0x04, 0x23, 0xcd, 0x6d, 0x9d, 0x43, 0x2b, 0x1c, 
+0xcb, 0x65, 0x83, 0x08, 0x03, 0xd3, 0x02, 0x23, 0xcd, 0x6d, 0x2b, 0x43, 
+0x03, 0xe0, 0x02, 0x23, 0xcd, 0x6d, 0x9d, 0x43, 0x2b, 0x1c, 0xcb, 0x65, 
+0x21, 0x6a, 0x81, 0x42, 0x0c, 0xd0, 0x20, 0x62, 0x0c, 0x48, 0x00, 0x2a, 
+0x03, 0xd0, 0xff, 0x21, 0x21, 0x31, 0x39, 0x43, 0x03, 0xe0, 0xff, 0x23, 
+0x21, 0x33, 0x9f, 0x43, 0x39, 0x1c, 0xc1, 0x62, 0x03, 0xb0, 0xf0, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0xe8, 0x0d, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 
+0xa8, 0x1b, 0x00, 0x80, 0x40, 0x00, 0x14, 0x40, 0x10, 0x2a, 0x00, 0x80, 
+0x40, 0x00, 0x14, 0x00, 0x90, 0xb4, 0x01, 0x22, 0x20, 0x28, 0x0f, 0xd2, 
+0x43, 0x00, 0x0f, 0x1c, 0x07, 0x49, 0x5c, 0x18, 0x37, 0x23, 0x9b, 0x01, 
+0xe3, 0x18, 0x1f, 0x83, 0x82, 0x40, 0x07, 0x23, 0x5b, 0x02, 0xc9, 0x18, 
+0x10, 0x1c, 0x8a, 0x69, 0x10, 0x43, 0x88, 0x61, 0x90, 0xbc, 0x70, 0x47, 
+0xe8, 0x0d, 0x00, 0x80, 0x0b, 0x48, 0x40, 0x69, 0x0b, 0x49, 0x49, 0x8b, 
+0x04, 0x22, 0x0a, 0x40, 0x0a, 0x49, 0x06, 0xd0, 0x01, 0x23, 0xdb, 0x02, 
+0x98, 0x43, 0x01, 0x23, 0xca, 0x6d, 0x1a, 0x43, 0x05, 0xe0, 0x01, 0x23, 
+0xdb, 0x02, 0x18, 0x43, 0xca, 0x6d, 0x52, 0x08, 0x52, 0x00, 0xca, 0x65, 
+0x70, 0x47, 0x00, 0x00, 0x80, 0x00, 0x14, 0x40, 0x68, 0x1b, 0x00, 0x80, 
+0x10, 0x2a, 0x00, 0x80, 0x00, 0xb5, 0x84, 0xb0, 0xff, 0xf7, 0xde, 0xff, 
+0x01, 0x1c, 0x05, 0x20, 0x00, 0x90, 0x00, 0x20, 0x01, 0xab, 0x18, 0x80, 
+0x04, 0x3b, 0x58, 0x70, 0x1b, 0x22, 0x00, 0xab, 0x5a, 0x80, 0xd9, 0x80, 
+0x05, 0x49, 0xc9, 0x6d, 0xc0, 0x46, 0x02, 0x91, 0x03, 0x90, 0x68, 0x46, 
+0x00, 0x21, 0xfc, 0xf7, 0x9d, 0xfd, 0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 
+0x10, 0x2a, 0x00, 0x80, 0x0d, 0x48, 0x01, 0x68, 0x49, 0x0c, 0x05, 0xd2, 
+0x01, 0x68, 0x09, 0x0c, 0x06, 0xd1, 0x00, 0x68, 0x80, 0x0a, 0x03, 0xd3, 
+0x09, 0x48, 0x00, 0x68, 0x00, 0x0c, 0x01, 0xe0, 0x08, 0x48, 0x80, 0x6c, 
+0x00, 0x04, 0x00, 0x0c, 0x07, 0x4b, 0x98, 0x42, 0x02, 0xd0, 0x02, 0x33, 
+0x98, 0x42, 0x01, 0xd1, 0x01, 0x20, 0x70, 0x47, 0x00, 0x20, 0xfc, 0xe7, 
+0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00, 0x80, 
+0x04, 0x99, 0x00, 0x00, 0x90, 0xb4, 0x01, 0x24, 0x21, 0x1c, 0x17, 0x48, 
+0x02, 0x68, 0x52, 0x0c, 0x06, 0xd2, 0x02, 0x68, 0x12, 0x0c, 0x02, 0xd1, 
+0x00, 0x68, 0x80, 0x0a, 0x00, 0xd2, 0x00, 0x21, 0x09, 0x06, 0x09, 0x0e, 
+0x11, 0x4f, 0x12, 0x4a, 0x02, 0xd0, 0x38, 0x68, 0x00, 0x0c, 0x00, 0xe0, 
+0x90, 0x6c, 0x00, 0x04, 0x00, 0x0c, 0x0f, 0x4b, 
+0x98, 0x42, 0x05, 0xd0, 0x02, 0x33, 0x98, 0x42, 0x02, 0xd0, 0x0d, 0x4b, 
+0x98, 0x42, 0x0c, 0xd1, 0x00, 0x29, 0x02, 0xd0, 0xf8, 0x6a, 0x00, 0x0c, 
+0x00, 0xe0, 0xd0, 0x6c, 0x40, 0x0a, 0x00, 0xd2, 0x00, 0x24, 0x20, 0x06, 
+0x00, 0x0e, 0x90, 0xbc, 0x70, 0x47, 0x00, 0x20, 0xfb, 0xe7, 0x00, 0x00, 
+0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00, 0x80, 
+0x04, 0x99, 0x00, 0x00, 0x05, 0x99, 0x00, 0x00, 0x0c, 0x48, 0x01, 0x68, 
+0x49, 0x0c, 0x05, 0xd2, 0x01, 0x68, 0x09, 0x0c, 0x05, 0xd1, 0x00, 0x68, 
+0x80, 0x0a, 0x02, 0xd3, 0x08, 0x48, 0x80, 0x68, 0x01, 0xe0, 0x08, 0x48, 
+0x40, 0x6c, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x21, 0x03, 0x28, 0x03, 0xd0, 
+0x40, 0x08, 0x01, 0xd3, 0x01, 0x20, 0x70, 0x47, 0x08, 0x1c, 0xfc, 0xe7, 
+0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00, 0x80, 
+0xf0, 0xb5, 0x01, 0x27, 0x1a, 0x4c, 0x25, 0x68, 0xff, 0xf7, 0x7a, 0xff, 
+0x03, 0x1c, 0x19, 0x4a, 0x02, 0x21, 0x01, 0x26, 0x18, 0x48, 0x01, 0x2b, 
+0x1b, 0xd1, 0xcb, 0x04, 0x1e, 0x60, 0x55, 0x23, 0x03, 0x60, 0x00, 0x23, 
+0x43, 0x60, 0x06, 0x68, 0x55, 0x2e, 0x1b, 0xd1, 0xaa, 0x26, 0x06, 0x60, 
+0x43, 0x60, 0x03, 0x68, 0xaa, 0x2b, 0x15, 0xd1, 0x09, 0x23, 0x03, 0x60, 
+0x05, 0x23, 0x0f, 0x4f, 0xc0, 0x46, 0x3b, 0x60, 0x03, 0x23, 0x0e, 0x4f, 
+0xc0, 0x46, 0x3b, 0x60, 0x11, 0x60, 0x07, 0x68, 0x08, 0xe0, 0x08, 0x23, 
+0x23, 0x60, 0x04, 0x23, 0x0a, 0x4f, 0xc0, 0x46, 0x3b, 0x60, 0x11, 0x60, 
+0x06, 0x60, 0x27, 0x68, 0xc0, 0x46, 0x25, 0x60, 0x38, 0x1c, 0xf0, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x20, 0x40, 0x00, 0x00, 0x24, 0x40, 
+0x00, 0x00, 0x22, 0x40, 0x00, 0x00, 0x2a, 0x40, 0x00, 0x00, 0x26, 0x40, 
+0x00, 0x00, 0x28, 0x40, 0x80, 0xb5, 0x07, 0x1c, 0xff, 0xf7, 0x38, 0xff, 
+0x01, 0x28, 0x05, 0xd1, 0x19, 0x48, 0x00, 0x68, 0x19, 0x49, 0x49, 0x6b, 
+0x08, 0x40, 0x22, 0xe0, 0x18, 0x48, 0x01, 0x68, 0x49, 0x0c, 0x05, 0xd2, 
+0x01, 0x68, 0x09, 0x0c, 0x06, 0xd1, 0x00, 0x68, 0x80, 0x0a, 0x03, 0xd3, 
+0x14, 0x48, 0x00, 0x68, 0x00, 0x0c, 0x01, 0xe0, 0x13, 0x48, 0x80, 0x6c, 
+0x00, 0x04, 0x00, 0x0c, 0x12, 0x4b, 0xc0, 0x18, 0x08, 0x28, 0x0b, 0xd2, 
+0x01, 0xa3, 0x1b, 0x5c, 0x5b, 0x00, 0x9f, 0x44, 0x05, 0x03, 0x07, 0x03, 
+0x07, 0x07, 0x05, 0x03, 0x03, 0x20, 0x02, 0xe0, 0x01, 0x20, 0x00, 0xe0, 
+0x00, 0x20, 0x01, 0x21, 0x38, 0x60, 0x80, 0x07, 0x00, 0xd1, 0x00, 0x21, 
+0x08, 0x06, 0x00, 0x0e, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
+0x98, 0x6e, 0x21, 0x40, 0x00, 0x00, 0x11, 0x40, 0x00, 0x00, 0x10, 0x40, 
+0x00, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00, 0x80, 0xfe, 0x66, 0xff, 0xff, 
+0xf0, 0xb5, 0x83, 0xb0, 0x07, 0x1c, 0x01, 0x20, 0x02, 0x90, 0x01, 0x25, 
+0x02, 0x24, 0x10, 0x26, 0x20, 0x21, 0x00, 0x91, 0xff, 0xf7, 0xea, 0xfe, 
+0x01, 0x28, 0x4d, 0xd1, 0x38, 0x2f, 0x01, 0xd0, 0xa8, 0x2f, 0x3a, 0xd1, 
+0x2e, 0x4e, 0x3c, 0x21, 0x02, 0x20, 0x32, 0x1c, 0xfc, 0xf7, 0x1c, 0xfb, 
+0x3e, 0x21, 0x05, 0x1c, 0x02, 0x20, 0x32, 0x1c, 0xfc, 0xf7, 0x16, 0xfb, 
+0x00, 0x04, 0x05, 0x43, 0x40, 0x21, 0x02, 0x20, 0x32, 0x1c, 0xfc, 0xf7, 
+0x0f, 0xfb, 0x01, 0x90, 0x42, 0x21, 0x02, 0x20, 0x32, 0x1c, 0xfc, 0xf7, 
+0x09, 0xfb, 0x00, 0x04, 0x01, 0x99, 0x08, 0x43, 0x06, 0x1c, 0xa8, 0x2f, 
+0x1b, 0xd1, 0x1f, 0x4a, 0x44, 0x21, 0x02, 0x20, 
+0xfc, 0xf7, 0xfe, 0xfa, 0x04, 0x1c, 0x1c, 0x4a, 0x46, 0x21, 0x02, 0x20, 
+0xfc, 0xf7, 0xf8, 0xfa, 0x00, 0x04, 0x04, 0x43, 0x18, 0x4a, 0x48, 0x21, 
+0x02, 0x20, 0xfc, 0xf7, 0xf1, 0xfa, 0x00, 0x90, 0x15, 0x4a, 0x4a, 0x21, 
+0x02, 0x20, 0xfc, 0xf7, 0xeb, 0xfa, 0x00, 0x04, 0x00, 0x99, 0x01, 0x43, 
+0x00, 0x91, 0x28, 0x1c, 0x30, 0x43, 0x20, 0x43, 0x00, 0x99, 0x08, 0x43, 
+0x00, 0xd1, 0x16, 0xe0, 0x11, 0x20, 0x00, 0x04, 0x05, 0x62, 0x46, 0x62, 
+0x84, 0x62, 0x00, 0x99, 0xc0, 0x46, 0xc1, 0x62, 0x00, 0x21, 0x0a, 0x48, 
+0xc0, 0x46, 0x01, 0x60, 0x38, 0x2f, 0x01, 0xd0, 0xa8, 0x2f, 0x05, 0xd1, 
+0x01, 0x21, 0x01, 0x60, 0xa8, 0x2f, 0x01, 0xd1, 0x03, 0x21, 0x01, 0x60, 
+0x02, 0x98, 0x03, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
+0x39, 0xb7, 0x21, 0x40, 0x98, 0x6e, 0x21, 0x40, 0x80, 0xb5, 0x07, 0x1c, 
+0xff, 0xf7, 0x7e, 0xfe, 0x01, 0x28, 0x19, 0xd1, 0x01, 0x05, 0x11, 0x48, 
+0x00, 0x2f, 0x18, 0xd0, 0x0b, 0x0a, 0x02, 0x68, 0x9a, 0x43, 0x0a, 0x60, 
+0x01, 0x68, 0x49, 0x0c, 0x05, 0xd2, 0x01, 0x68, 0x09, 0x0c, 0x0b, 0xd1, 
+0x00, 0x68, 0x80, 0x0a, 0x08, 0xd3, 0x0a, 0x48, 0x40, 0x6a, 0xff, 0x22, 
+0x01, 0x32, 0x02, 0x43, 0x08, 0x49, 0xc0, 0x46, 0x4a, 0x62, 0x48, 0x62, 
+0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x68, 0x01, 0x23, 0x1b, 0x03, 
+0x18, 0x43, 0x08, 0x60, 0xf6, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 
+0xc0, 0x00, 0x18, 0x40, 0xc0, 0x00, 0x18, 0x00, 0x70, 0x47, 0x00, 0x00, 
+0x90, 0xb5, 0x07, 0x1c, 0x12, 0x4c, 0x21, 0x68, 0x12, 0x48, 0x81, 0x42, 
+0x0b, 0xd0, 0x00, 0x23, 0x21, 0x1c, 0xe2, 0x1d, 0x6d, 0x32, 0x00, 0xe0, 
+0x08, 0xc1, 0x91, 0x42, 0xfc, 0xd3, 0x20, 0x60, 0x74, 0x20, 0xa0, 0x80, 
+0x67, 0x72, 0x38, 0x01, 0x00, 0xf0, 0x18, 0xf8, 0x27, 0x72, 0x0a, 0x48, 
+0xc0, 0x46, 0xe0, 0x60, 0x08, 0x2f, 0x00, 0xdb, 0x00, 0x27, 0xe0, 0x19, 
+0x01, 0x7d, 0x01, 0x31, 0x01, 0x75, 0xe0, 0x88, 0x01, 0x30, 0xe0, 0x80, 
+0x01, 0x20, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x80, 
+0xfe, 0xca, 0x01, 0x20, 0x17, 0x40, 0x00, 0x02, 0x80, 0xb4, 0x08, 0x4a, 
+0xd1, 0x1d, 0x49, 0x31, 0x0b, 0x78, 0x20, 0x2b, 0x01, 0xd3, 0x00, 0x23, 
+0x0b, 0x70, 0x07, 0x1c, 0x08, 0x78, 0x43, 0x1c, 0x0b, 0x70, 0x80, 0x18, 
+0x50, 0x30, 0x47, 0x70, 0x80, 0xbc, 0x70, 0x47, 0x00, 0x00, 0x00, 0x80, 
+0x07, 0x49, 0x01, 0x22, 0x12, 0x04, 0x08, 0x68, 0x02, 0x40, 0x01, 0x20, 
+0x00, 0x2a, 0x06, 0xd1, 0x0a, 0x68, 0x12, 0x0c, 0x02, 0xd1, 0x09, 0x68, 
+0x89, 0x0a, 0x00, 0xd2, 0x00, 0x20, 0x70, 0x47, 0x00, 0x00, 0x10, 0x40, 
+0x90, 0xb5, 0x07, 0x1c, 0x09, 0x4c, 0x38, 0x1c, 0x21, 0x1c, 0xfc, 0xf7, 
+0x4d, 0xfc, 0x38, 0x1c, 0x00, 0xf0, 0x0e, 0xf8, 0x01, 0x23, 0xd8, 0x42, 
+0x01, 0xd1, 0x00, 0x0c, 0xe0, 0x80, 0x00, 0x21, 0x20, 0x1c, 0xfc, 0xf7, 
+0x81, 0xfb, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xbc, 0x67, 0x21, 0x40, 
+0xf8, 0xb5, 0x07, 0x1c, 0x79, 0x7a, 0x76, 0x48, 0x00, 0x23, 0x76, 0x4c, 
+0x01, 0x29, 0x5d, 0xd1, 0xa2, 0x88, 0xc0, 0x46, 0x00, 0x92, 0xa1, 0x89, 
+0x8a, 0x42, 0x74, 0xda, 0xfa, 0x7a, 0x00, 0x2a, 0x15, 0xd0, 0x7a, 0x6c, 
+0x00, 0x2a, 0x12, 0xd0, 0x8a, 0x42, 0x10, 0xd8, 0x00, 0x9a, 0x51, 0x1c, 
+0xa1, 0x80, 0xa1, 0x88, 0xc0, 0x46, 0x41, 0x81, 0x78, 0x6c, 0x6b, 0x4e, 
+0xc0, 0x46, 0xf0, 0x80, 0xa0, 0x6a, 0x58, 0x23, 
+0x79, 0x6c, 0x59, 0x43, 0x40, 0x18, 0xc1, 0x1a, 0x28, 0xe0, 0x22, 0x88, 
+0x01, 0x32, 0x12, 0x04, 0x12, 0x0c, 0x22, 0x80, 0x8a, 0x42, 0x00, 0xdb, 
+0x23, 0x80, 0x00, 0x22, 0x00, 0x29, 0x69, 0xdd, 0x5f, 0x4c, 0xa4, 0x6a, 
+0x5e, 0x4b, 0x1d, 0x88, 0x58, 0x23, 0x6b, 0x43, 0xe3, 0x18, 0xde, 0x1d, 
+0x01, 0x36, 0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 0x1b, 0x06, 
+0x15, 0xd1, 0x58, 0x49, 0x00, 0x9a, 0x01, 0x32, 0x8a, 0x80, 0x8a, 0x88, 
+0xc0, 0x46, 0x42, 0x81, 0x08, 0x88, 0x01, 0x30, 0x54, 0x4e, 0xc0, 0x46, 
+0xf0, 0x80, 0x58, 0x20, 0x68, 0x43, 0x21, 0x18, 0x38, 0x1c, 0x00, 0xf0, 
+0x65, 0xfa, 0xf0, 0x88, 0x00, 0x04, 0x00, 0x14, 0x95, 0xe0, 0x4d, 0x4b, 
+0x01, 0x35, 0x2d, 0x04, 0x2d, 0x0c, 0x1d, 0x80, 0x8d, 0x42, 0x01, 0xdb, 
+0x00, 0x25, 0x1d, 0x80, 0x01, 0x32, 0x12, 0x04, 0x12, 0x14, 0x91, 0x42, 
+0xce, 0xdc, 0x81, 0xe0, 0xe1, 0x88, 0xe2, 0x89, 0x91, 0x42, 0x18, 0xda, 
+0xf9, 0x7a, 0x00, 0x29, 0x2f, 0xd0, 0x79, 0x6c, 0x49, 0x04, 0x49, 0x0c, 
+0x79, 0x64, 0x2a, 0xd0, 0xe2, 0x89, 0x91, 0x42, 0x27, 0xd8, 0xe1, 0x88, 
+0x01, 0x31, 0xe1, 0x80, 0xe1, 0x88, 0xc0, 0x46, 0x81, 0x81, 0x01, 0x23, 
+0xdb, 0x03, 0x78, 0x6c, 0x18, 0x43, 0x3a, 0x4e, 0xc0, 0x46, 0xf0, 0x80, 
+0x00, 0xe0, 0x63, 0xe0, 0xe0, 0x6a, 0x79, 0x6c, 0x4b, 0x00, 0x59, 0x18, 
+0x49, 0x01, 0x40, 0x18, 0xc1, 0x1f, 0x59, 0x39, 0x38, 0x1c, 0x00, 0xf0, 
+0x4b, 0xfa, 0xe0, 0x6a, 0x79, 0x6c, 0x4a, 0x00, 0x52, 0x18, 0x52, 0x01, 
+0x80, 0x18, 0x01, 0x39, 0x09, 0x04, 0x09, 0x0c, 0x60, 0x38, 0x00, 0xf0, 
+0xc5, 0xfa, 0xb6, 0xe7, 0x4a, 0xe0, 0x61, 0x88, 0x01, 0x31, 0x09, 0x04, 
+0x09, 0x0c, 0x61, 0x80, 0xe2, 0x89, 0x91, 0x42, 0x00, 0xdb, 0x63, 0x80, 
+0x00, 0x21, 0x00, 0x2a, 0x3e, 0xdd, 0x24, 0x4c, 0xe4, 0x6a, 0x23, 0x4b, 
+0x5d, 0x88, 0x6b, 0x00, 0x5b, 0x19, 0x5b, 0x01, 0xe3, 0x18, 0xde, 0x1d, 
+0x01, 0x36, 0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 0x1b, 0x06, 
+0x20, 0xd1, 0x1c, 0x4e, 0xf1, 0x88, 0x01, 0x31, 0xf1, 0x80, 0xf1, 0x88, 
+0xc0, 0x46, 0x81, 0x81, 0x70, 0x88, 0x01, 0x23, 0xdb, 0x03, 0x01, 0x30, 
+0x18, 0x43, 0x17, 0x49, 0xc0, 0x46, 0xc8, 0x80, 0x68, 0x00, 0x40, 0x19, 
+0x40, 0x01, 0x21, 0x18, 0x38, 0x1c, 0x00, 0xf0, 0x0b, 0xfa, 0x71, 0x88, 
+0x4a, 0x00, 0x52, 0x18, 0x52, 0x01, 0xf0, 0x6a, 0x80, 0x18, 0x00, 0xf0, 
+0x89, 0xfa, 0x0e, 0x49, 0xc8, 0x88, 0x79, 0xe7, 0x0b, 0x4b, 0x01, 0x35, 
+0x2d, 0x04, 0x2d, 0x0c, 0x5d, 0x80, 0x95, 0x42, 0x01, 0xdb, 0x00, 0x25, 
+0x5d, 0x80, 0x01, 0x31, 0x09, 0x04, 0x09, 0x14, 0x8a, 0x42, 0xc2, 0xdc, 
+0x01, 0x89, 0x01, 0x31, 0x01, 0x81, 0x00, 0x20, 0xc0, 0x43, 0xf8, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0xb8, 0x2a, 0x00, 0x80, 0xc8, 0x29, 0x00, 0x80, 
+0xbc, 0x67, 0x21, 0x40, 0xf0, 0xb4, 0x06, 0x1c, 0x01, 0x23, 0xdb, 0x03, 
+0x33, 0x40, 0x01, 0x24, 0x30, 0x4f, 0x00, 0x20, 0x30, 0x4a, 0x31, 0x4d, 
+0xd1, 0x1d, 0x39, 0x31, 0x00, 0x2b, 0x2f, 0xd0, 0xe3, 0x03, 0xf3, 0x1a, 
+0x51, 0xd0, 0xee, 0x89, 0x9e, 0x42, 0x4e, 0xd3, 0xee, 0x88, 0x00, 0x2e, 
+0x4b, 0xd0, 0xee, 0x6a, 0x5d, 0x1e, 0x6b, 0x00, 0x5d, 0x19, 0x6d, 0x01, 
+0x73, 0x19, 0x9e, 0x68, 0x36, 0x06, 0x36, 0x0e, 0x03, 0x2e, 0x02, 0xd0, 
+0xce, 0x89, 0x01, 0x36, 0xce, 0x81, 0x40, 0x33, 0x9b, 0x8b, 0x9b, 0x00, 
+0x21, 0x4e, 0x76, 0x6a, 0xc0, 0x46, 0xf0, 0x50, 
+0x53, 0x89, 0x01, 0x33, 0x53, 0x81, 0x1e, 0x4e, 0xf2, 0x6a, 0x52, 0x19, 
+0x90, 0x60, 0xf0, 0x88, 0x01, 0x38, 0xf0, 0x80, 0xf0, 0x88, 0xc0, 0x46, 
+0x88, 0x81, 0x19, 0x49, 0x00, 0x28, 0x23, 0xd1, 0x4f, 0x80, 0x21, 0xe0, 
+0x00, 0x2e, 0x22, 0xd9, 0xab, 0x89, 0xb3, 0x42, 0x1f, 0xd3, 0xab, 0x88, 
+0x00, 0x2b, 0x1c, 0xd0, 0x53, 0x89, 0x01, 0x33, 0x53, 0x81, 0x58, 0x23, 
+0x01, 0x3e, 0x73, 0x43, 0xaa, 0x6a, 0xd2, 0x18, 0x93, 0x68, 0x1b, 0x06, 
+0x1b, 0x0e, 0x03, 0x2b, 0x02, 0xd0, 0xcb, 0x89, 0x01, 0x33, 0xcb, 0x81, 
+0x90, 0x60, 0xa8, 0x88, 0x01, 0x38, 0xa8, 0x80, 0xa8, 0x88, 0xc0, 0x46, 
+0x48, 0x81, 0x00, 0x28, 0x00, 0xd1, 0x2f, 0x80, 0x20, 0x1c, 0xf0, 0xbc, 
+0x70, 0x47, 0xca, 0x89, 0x01, 0x32, 0xca, 0x81, 0xf9, 0xe7, 0x00, 0x00, 
+0xff, 0xff, 0x00, 0x00, 0x78, 0x2a, 0x00, 0x80, 0xc8, 0x29, 0x00, 0x80, 
+0x00, 0xb5, 0x00, 0x21, 0x41, 0x60, 0x10, 0x49, 0x4a, 0x68, 0x00, 0x2a, 
+0x10, 0xd1, 0xca, 0x68, 0x00, 0x2a, 0x04, 0xd0, 0xca, 0x1d, 0x19, 0x32, 
+0x12, 0x79, 0x00, 0x2a, 0x08, 0xd0, 0x4a, 0x69, 0x00, 0x2a, 0x0b, 0xd1, 
+0x88, 0x61, 0x48, 0x61, 0x00, 0xf0, 0x10, 0xf8, 0x08, 0xbc, 0x18, 0x47, 
+0x4a, 0x69, 0x00, 0x2a, 0x02, 0xd1, 0x88, 0x61, 0x48, 0x61, 0xf7, 0xe7, 
+0x8a, 0x69, 0xc0, 0x46, 0x50, 0x60, 0x88, 0x61, 0xf2, 0xe7, 0x00, 0x00, 
+0xec, 0x05, 0x00, 0x80, 0xb0, 0xb5, 0x2a, 0x48, 0x40, 0x69, 0x00, 0x28, 
+0x4c, 0xd0, 0x08, 0x22, 0xc1, 0x68, 0x0a, 0x40, 0x00, 0x27, 0x27, 0x4b, 
+0xd9, 0x1d, 0xb9, 0x31, 0x00, 0x2a, 0x11, 0xd0, 0x04, 0x22, 0x25, 0x4c, 
+0xc0, 0x46, 0x0c, 0x61, 0x24, 0x4c, 0xc0, 0x46, 0x4c, 0x62, 0x24, 0x4c, 
+0xc0, 0x46, 0x8c, 0x62, 0x23, 0x4c, 0xc0, 0x46, 0xcc, 0x62, 0x23, 0x4c, 
+0xc0, 0x46, 0x0c, 0x63, 0x4f, 0x63, 0x12, 0xe0, 0x05, 0x22, 0x21, 0x4c, 
+0xc0, 0x46, 0x0c, 0x61, 0x20, 0x4c, 0xc0, 0x46, 0x4c, 0x62, 0x20, 0x4c, 
+0xc0, 0x46, 0x8c, 0x62, 0x1f, 0x4c, 0xc0, 0x46, 0xcc, 0x62, 0x1f, 0x4c, 
+0xc0, 0x46, 0x0c, 0x63, 0x1e, 0x4c, 0xc0, 0x46, 0x4c, 0x63, 0x40, 0x24, 
+0xcc, 0x82, 0x4f, 0x83, 0x1c, 0x4f, 0x00, 0x21, 0x00, 0x2a, 0x0c, 0xd9, 
+0x8c, 0x00, 0x05, 0x19, 0x6d, 0x6a, 0x7d, 0x40, 0xe4, 0x18, 0xff, 0x34, 
+0x01, 0x34, 0x65, 0x62, 0x01, 0x31, 0x91, 0x42, 0xf4, 0xd3, 0x10, 0x29, 
+0x07, 0xd2, 0x8a, 0x00, 0xd2, 0x18, 0xff, 0x32, 0x01, 0x32, 0x57, 0x62, 
+0x01, 0x31, 0x10, 0x29, 0xf7, 0xd3, 0x11, 0x49, 0x00, 0xf0, 0x22, 0xf8, 
+0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xec, 0x05, 0x00, 0x80, 
+0x1c, 0xad, 0x20, 0x40, 0x28, 0x01, 0x40, 0x00, 0x01, 0x23, 0x45, 0x67, 
+0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 
+0x20, 0x01, 0x40, 0x00, 0x67, 0x45, 0x23, 0x01, 0xef, 0xcd, 0xab, 0x89, 
+0x98, 0xba, 0xdc, 0xfe, 0x10, 0x32, 0x54, 0x76, 0xc3, 0xd2, 0xe1, 0xf0, 
+0x36, 0x36, 0x36, 0x36, 0x30, 0x80, 0x20, 0x40, 0xb0, 0xb5, 0x0f, 0x1c, 
+0x15, 0x4d, 0xe9, 0x1d, 0xc9, 0x31, 0x15, 0x4c, 0x23, 0x1c, 0x15, 0x4a, 
+0x00, 0x20, 0xfc, 0xf7, 0x1a, 0xf8, 0xe9, 0x1d, 0xff, 0x31, 0x1e, 0x31, 
+0x23, 0x1c, 0x0d, 0x1c, 0x11, 0x4a, 0x01, 0x20, 0xfc, 0xf7, 0x11, 0xf8, 
+0x29, 0x1c, 0x23, 0x1c, 0x0e, 0x4a, 0x00, 0x20, 0xfc, 0xf7, 0x0b, 0xf8, 
+0x39, 0x1c, 0x23, 0x1c, 0x0c, 0x4a, 0x01, 0x20, 0xfc, 0xf7, 0x05, 0xf8, 
+0x00, 0x21, 0x0b, 0x48, 0xc2, 0x1d, 0x19, 0x32, 
+0x51, 0x71, 0x01, 0x21, 0xff, 0x30, 0x01, 0x30, 0x41, 0x62, 0x08, 0x1c, 
+0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x1c, 0xad, 0x20, 0x40, 
+0x75, 0x08, 0xff, 0xff, 0x28, 0x00, 0x03, 0x00, 0x40, 0x00, 0x02, 0x00, 
+0x14, 0x00, 0x07, 0x00, 0xec, 0x05, 0x00, 0x80, 0xf0, 0xb5, 0x37, 0x4a, 
+0x50, 0x69, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x30, 0x18, 0x43, 0x00, 0x68, 
+0x01, 0x06, 0x09, 0x0e, 0x33, 0x4b, 0x01, 0x29, 0x49, 0xd1, 0x1f, 0x68, 
+0x19, 0x1c, 0x32, 0x4b, 0x9f, 0x42, 0x04, 0xd1, 0xff, 0xf7, 0x3e, 0xff, 
+0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x23, 0x9f, 0x00, 0xcc, 0x59, 
+0x55, 0x69, 0xef, 0x19, 0x3c, 0x61, 0x01, 0x33, 0x05, 0x2b, 0xf7, 0xd3, 
+0x00, 0x0a, 0x00, 0x02, 0x02, 0x23, 0x18, 0x43, 0x53, 0x69, 0xc0, 0x46, 
+0x98, 0x60, 0x50, 0x69, 0x08, 0x23, 0xc2, 0x68, 0x13, 0x40, 0x25, 0x4f, 
+0xfa, 0x1d, 0xb9, 0x32, 0x00, 0x2b, 0x02, 0xd0, 0x04, 0x23, 0x23, 0x4c, 
+0x01, 0xe0, 0x05, 0x23, 0x22, 0x4c, 0xc0, 0x46, 0x14, 0x61, 0x40, 0x24, 
+0xd4, 0x82, 0x00, 0x24, 0x54, 0x83, 0x20, 0x4c, 0x00, 0x22, 0x00, 0x2b, 
+0x0c, 0xd9, 0x95, 0x00, 0x46, 0x19, 0x76, 0x6a, 0x66, 0x40, 0xed, 0x19, 
+0xff, 0x35, 0x01, 0x35, 0x6e, 0x62, 0x01, 0x32, 0x9a, 0x42, 0xf4, 0xd3, 
+0x10, 0x2a, 0x07, 0xd2, 0x93, 0x00, 0xdb, 0x19, 0xff, 0x33, 0x01, 0x33, 
+0x5c, 0x62, 0x01, 0x32, 0x10, 0x2a, 0xf7, 0xd3, 0xff, 0xf7, 0x70, 0xff, 
+0xbc, 0xe7, 0x00, 0x21, 0x8f, 0x00, 0xdc, 0x59, 0x55, 0x69, 0xef, 0x19, 
+0x7c, 0x62, 0x01, 0x31, 0x05, 0x29, 0xf7, 0xd3, 0x00, 0x0a, 0x00, 0x02, 
+0x03, 0x23, 0x18, 0x43, 0x51, 0x69, 0xc0, 0x46, 0x88, 0x60, 0x50, 0x69, 
+0x40, 0x68, 0xc0, 0x46, 0x50, 0x61, 0x09, 0x48, 0xfb, 0xf7, 0x7a, 0xff, 
+0xa4, 0xe7, 0x00, 0x00, 0xec, 0x05, 0x00, 0x80, 0x30, 0x80, 0x20, 0x40, 
+0x67, 0x45, 0x23, 0x01, 0x1c, 0xad, 0x20, 0x40, 0x28, 0x01, 0x40, 0x00, 
+0x20, 0x01, 0x40, 0x00, 0x5c, 0x5c, 0x5c, 0x5c, 0x85, 0x30, 0xff, 0xff, 
+0x80, 0xb5, 0x0f, 0x1c, 0x39, 0x1c, 0x00, 0xf0, 0x43, 0xf8, 0xb9, 0x6b, 
+0x0b, 0x48, 0xc2, 0x68, 0x12, 0x04, 0x51, 0x40, 0x82, 0x69, 0x51, 0x40, 
+0x39, 0x65, 0xf9, 0x6b, 0x82, 0x69, 0x12, 0x04, 0xd2, 0x43, 0x51, 0x40, 
+0xc0, 0x68, 0xc0, 0x43, 0x48, 0x40, 0x78, 0x65, 0x04, 0x48, 0x01, 0x89, 
+0x01, 0x31, 0x01, 0x81, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
+0x08, 0x83, 0x20, 0x40, 0x78, 0x2a, 0x00, 0x80, 0x90, 0xb5, 0x04, 0x1c, 
+0x0f, 0x1c, 0x20, 0x1c, 0x39, 0x1c, 0x00, 0xf0, 0x1f, 0xf8, 0xe0, 0x68, 
+0x01, 0x0e, 0xff, 0x22, 0x12, 0x04, 0x02, 0x40, 0x12, 0x0a, 0x11, 0x43, 
+0xff, 0x22, 0x12, 0x02, 0x02, 0x40, 0x12, 0x02, 0x11, 0x43, 0x00, 0x06, 
+0x08, 0x43, 0x38, 0x65, 0x20, 0x69, 0xc0, 0x46, 0x78, 0x65, 0x60, 0x69, 
+0xc0, 0x46, 0xb8, 0x65, 0x03, 0x48, 0x01, 0x89, 0x01, 0x31, 0x01, 0x81, 
+0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x78, 0x2a, 0x00, 0x80, 
+0x90, 0xb5, 0x00, 0x22, 0x93, 0x00, 0x1f, 0x18, 0xbf, 0x69, 0x5b, 0x18, 
+0x5f, 0x62, 0x01, 0x32, 0x05, 0x2a, 0xf7, 0xd3, 0x07, 0x7a, 0xfb, 0x08, 
+0x03, 0xd3, 0x00, 0x23, 0x92, 0x00, 0x52, 0x18, 0x13, 0x62, 0x07, 0x6b, 
+0xc0, 0x46, 0x8f, 0x63, 0xc7, 0x6a, 0xc0, 0x46, 0xcf, 0x63, 0x87, 0x6b, 
+0xc0, 0x46, 0x0f, 0x64, 0x47, 0x6b, 0xc0, 0x46, 0x4f, 0x64, 0x07, 0x6c, 
+0xc0, 0x46, 0x8f, 0x64, 0xc2, 0x6b, 0xc0, 0x46, 
+0xca, 0x64, 0xc2, 0x88, 0xc0, 0x46, 0x0a, 0x80, 0x82, 0x7a, 0x12, 0x06, 
+0x03, 0x7a, 0x1b, 0x04, 0x1a, 0x43, 0xc3, 0x88, 0x1b, 0x02, 0x1a, 0x43, 
+0x43, 0x7a, 0xdb, 0x07, 0x1a, 0x43, 0x8a, 0x60, 0x17, 0x1c, 0x83, 0x7a, 
+0x5a, 0x08, 0x05, 0xd3, 0x14, 0x22, 0x1c, 0x1c, 0xa3, 0x08, 0x02, 0xd2, 
+0x15, 0x22, 0x00, 0xe0, 0x00, 0x22, 0x00, 0x7a, 0x43, 0x08, 0x10, 0xd3, 
+0xc0, 0x08, 0x02, 0xd3, 0x88, 0x20, 0x10, 0x43, 0x01, 0xe0, 0x80, 0x20, 
+0x10, 0x43, 0x3a, 0x0a, 0x12, 0x02, 0x01, 0x23, 0x1a, 0x43, 0xc8, 0x60, 
+0x8a, 0x60, 0x08, 0x1c, 0xff, 0xf7, 0x14, 0xfe, 0x05, 0xe0, 0x38, 0x0a, 
+0x00, 0x02, 0x03, 0x23, 0x18, 0x43, 0x88, 0x60, 0xca, 0x60, 0x03, 0x48, 
+0x01, 0x89, 0x01, 0x31, 0x01, 0x81, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x78, 0x2a, 0x00, 0x80, 0xf0, 0xb4, 0x02, 0x6d, 0x14, 0x4c, 0x15, 0x1c, 
+0xe7, 0x69, 0xbd, 0x40, 0x13, 0x1c, 0x26, 0x6a, 0xf3, 0x40, 0x5d, 0x40, 
+0x2e, 0x1c, 0x45, 0x6d, 0xbd, 0x40, 0x6e, 0x40, 0x2b, 0x1c, 0x35, 0x1c, 
+0xfd, 0x40, 0x2f, 0x1c, 0xbb, 0x00, 0x65, 0x6a, 0xeb, 0x58, 0x00, 0x2b, 
+0x08, 0xd0, 0x23, 0x69, 0x01, 0x37, 0x9f, 0x42, 0x00, 0xd3, 0x00, 0x27, 
+0xbe, 0x00, 0xae, 0x59, 0x00, 0x2e, 0xf7, 0xd1, 0xa4, 0x69, 0xa2, 0x40, 
+0x11, 0x43, 0x05, 0x4b, 0x19, 0x43, 0xba, 0x00, 0xa9, 0x50, 0x40, 0x30, 
+0x87, 0x83, 0xf0, 0xbc, 0x70, 0x47, 0x00, 0x00, 0xc8, 0x29, 0x00, 0x80, 
+0x00, 0x00, 0x00, 0x80, 0x90, 0xb5, 0x04, 0x1c, 0x0f, 0x1c, 0x00, 0xf0, 
+0xb1, 0xfa, 0x20, 0x1c, 0x00, 0xf0, 0x0e, 0xfa, 0x38, 0x0c, 0x00, 0xf0, 
+0x0b, 0xfa, 0x38, 0x0a, 0x00, 0xf0, 0x08, 0xfa, 0x38, 0x1c, 0x00, 0xf0, 
+0x05, 0xfa, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 0x07, 0x1c, 
+0x00, 0xf0, 0x9e, 0xfa, 0x54, 0x20, 0x00, 0xf0, 0xfb, 0xf9, 0x38, 0x0c, 
+0x00, 0xf0, 0xf8, 0xf9, 0x38, 0x0a, 0x00, 0xf0, 0xf5, 0xf9, 0x38, 0x1c, 
+0x00, 0xf0, 0xf2, 0xf9, 0x00, 0x20, 0x00, 0xf0, 0xef, 0xf9, 0x80, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0x00, 0xf0, 0x89, 0xfa, 0x57, 0x20, 
+0x00, 0xf0, 0xe6, 0xf9, 0x08, 0xbc, 0x18, 0x47, 0xf3, 0xb5, 0x81, 0xb0, 
+0x41, 0x02, 0x53, 0x20, 0xff, 0xf7, 0xc8, 0xff, 0x00, 0xf0, 0x64, 0xfa, 
+0x00, 0xf0, 0xf5, 0xf8, 0x00, 0x24, 0x00, 0x26, 0x00, 0x25, 0x00, 0x27, 
+0x30, 0x1c, 0x01, 0x36, 0xff, 0xf7, 0xd0, 0xff, 0x00, 0xf0, 0x46, 0xf9, 
+0x00, 0x90, 0x00, 0xf0, 0x55, 0xfa, 0xf8, 0x00, 0x00, 0x99, 0x81, 0x40, 
+0x0d, 0x43, 0x01, 0x34, 0x01, 0x37, 0x04, 0x2f, 0xee, 0xd3, 0x02, 0x99, 
+0x20, 0xc1, 0x02, 0x91, 0xff, 0x23, 0x09, 0x33, 0x9c, 0x42, 0xe5, 0xd3, 
+0x03, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb5, 0x04, 0x1c, 
+0x0f, 0x1c, 0x00, 0x26, 0x20, 0xcf, 0xb1, 0x00, 0x84, 0x20, 0xff, 0xf7, 
+0x9b, 0xff, 0x28, 0x1c, 0x00, 0xf0, 0xae, 0xf9, 0x28, 0x0a, 0x00, 0xf0, 
+0xab, 0xf9, 0x28, 0x0c, 0x00, 0xf0, 0xa8, 0xf9, 0x28, 0x0e, 0x00, 0xf0, 
+0xa5, 0xf9, 0x00, 0xf0, 0x2b, 0xfa, 0x01, 0x36, 0x42, 0x2e, 0xe9, 0xd3, 
+0x61, 0x02, 0x83, 0x20, 0xff, 0xf7, 0x86, 0xff, 0x00, 0xf0, 0x22, 0xfa, 
+0x00, 0xf0, 0xb3, 0xf8, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 
+0x41, 0x02, 0x60, 0x20, 0xff, 0xf7, 0x7a, 0xff, 0x00, 0xf0, 0x16, 0xfa, 
+0x00, 0xf0, 0xa7, 0xf8, 0x38, 0x1c, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x90, 0xb5, 0x0f, 0x1c, 0x41, 0x02, 0x53, 0x20, 
+0xff, 0xf7, 0x6c, 0xff, 0x00, 0xf0, 0x08, 0xfa, 0x00, 0xf0, 0x99, 0xf8, 
+0xf8, 0x1d, 0x05, 0x30, 0x44, 0x1c, 0xff, 0xf7, 0x77, 0xff, 0x00, 0xf0, 
+0xed, 0xf8, 0x07, 0x1c, 0x00, 0xf0, 0xfc, 0xf9, 0x20, 0x1c, 0xff, 0xf7, 
+0x6f, 0xff, 0x00, 0xf0, 0xe5, 0xf8, 0x04, 0x1c, 0x00, 0xf0, 0xf4, 0xf9, 
+0x20, 0x02, 0x38, 0x43, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xb0, 0xb5, 
+0xc2, 0xb0, 0x04, 0x1c, 0x0d, 0x1c, 0x17, 0x1c, 0x61, 0x02, 0x53, 0x20, 
+0xff, 0xf7, 0x48, 0xff, 0x00, 0xf0, 0xe4, 0xf9, 0x00, 0xf0, 0x75, 0xf8, 
+0x68, 0x46, 0x00, 0xf0, 0x5c, 0xf8, 0x6a, 0x46, 0xe8, 0x1d, 0x05, 0x30, 
+0x17, 0x54, 0x39, 0x0a, 0x68, 0x44, 0x41, 0x70, 0x68, 0x46, 0x00, 0x99, 
+0x0c, 0x30, 0x00, 0xf0, 0x73, 0xf8, 0x02, 0xab, 0x18, 0x70, 0x00, 0x20, 
+0x58, 0x70, 0x68, 0x46, 0x0c, 0x21, 0x00, 0xf0, 0x6b, 0xf8, 0x02, 0xab, 
+0x58, 0x70, 0x69, 0x46, 0x20, 0x1c, 0xff, 0xf7, 0x83, 0xff, 0x42, 0xb0, 
+0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb5, 0xc2, 0xb0, 0x04, 0x1c, 
+0x1f, 0x1c, 0x6b, 0x46, 0x00, 0x20, 0xc5, 0x43, 0x20, 0xc3, 0x01, 0x30, 
+0x42, 0x28, 0xfb, 0xd3, 0x68, 0x46, 0x0c, 0x30, 0x03, 0x1c, 0x00, 0x25, 
+0x00, 0x2a, 0x0a, 0xd9, 0x0e, 0x88, 0xc0, 0x46, 0x06, 0x70, 0x0e, 0x88, 
+0x36, 0x12, 0x46, 0x70, 0x02, 0x30, 0x02, 0x31, 0x02, 0x35, 0x95, 0x42, 
+0xf4, 0xd3, 0x00, 0x92, 0x18, 0x1c, 0x11, 0x1c, 0x00, 0xf0, 0x40, 0xf8, 
+0x00, 0x26, 0x01, 0x96, 0x02, 0xab, 0x18, 0x70, 0x5e, 0x70, 0x9e, 0x70, 
+0xde, 0x70, 0x05, 0x1c, 0x68, 0x46, 0x0c, 0x21, 0x00, 0xf0, 0x34, 0xf8, 
+0x02, 0xab, 0x58, 0x70, 0x38, 0x06, 0x00, 0x0e, 0x85, 0x42, 0x05, 0xd1, 
+0x69, 0x46, 0x20, 0x1c, 0xff, 0xf7, 0x48, 0xff, 0x30, 0x1c, 0x00, 0xe0, 
+0x01, 0x20, 0x42, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb5, 
+0x07, 0x1c, 0x00, 0x24, 0xff, 0x26, 0x09, 0x36, 0x20, 0x1c, 0xff, 0xf7, 
+0xf1, 0xfe, 0x00, 0xf0, 0x67, 0xf8, 0x05, 0x1c, 0x00, 0xf0, 0x76, 0xf9, 
+0x3d, 0x70, 0x28, 0x1c, 0x01, 0x37, 0x01, 0x34, 0xb4, 0x42, 0xf1, 0xd3, 
+0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 0xff, 0xf7, 0xf6, 0xfe, 
+0x00, 0xf0, 0x56, 0xf8, 0x07, 0x1c, 0x00, 0xf0, 0x65, 0xf9, 0x38, 0x0a, 
+0xf6, 0xd3, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x80, 0xb4, 0x00, 0x22, 
+0x00, 0x23, 0x00, 0x29, 0x05, 0xd9, 0x07, 0x78, 0x7a, 0x40, 0x01, 0x30, 
+0x01, 0x33, 0x8b, 0x42, 0xf9, 0xd3, 0xd0, 0x43, 0x00, 0x06, 0x00, 0x0e, 
+0x80, 0xbc, 0x70, 0x47, 0xb0, 0xb5, 0xc2, 0xb0, 0x0f, 0x1c, 0x41, 0x02, 
+0x53, 0x20, 0xff, 0xf7, 0xab, 0xfe, 0x00, 0xf0, 0x47, 0xf9, 0xff, 0xf7, 
+0xd8, 0xff, 0x68, 0x46, 0xff, 0xf7, 0xbf, 0xff, 0x02, 0xad, 0x6d, 0x78, 
+0x00, 0x24, 0x02, 0xab, 0x5c, 0x70, 0x68, 0x46, 0x0c, 0x21, 0xff, 0xf7, 
+0xd9, 0xff, 0xa8, 0x42, 0x02, 0xd1, 0x00, 0x98, 0x87, 0x42, 0x01, 0xd3, 
+0x20, 0x1c, 0x00, 0xe0, 0x01, 0x20, 0x42, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x80, 0xb5, 0xc2, 0xb0, 0x69, 0x46, 0x02, 0x20, 0xff, 0xf7, 
+0xbb, 0xfe, 0x68, 0x46, 0xc1, 0x1d, 0x05, 0x31, 0x00, 0x20, 0x07, 0x4a, 
+0x0f, 0x88, 0x43, 0x00, 0xd7, 0x52, 0x02, 0x31, 0x01, 0x30, 0x00, 0x04, 
+0x00, 0x0c, 0x25, 0x28, 0xf6, 0xdb, 0x42, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x00, 0x70, 0x67, 0x21, 0x40, 0xfc, 0x46, 0x60, 0x47, 
+0x00, 0x00, 0xa0, 0xe3, 0xb4, 0x22, 0x9f, 0xe5, 
+0xb4, 0x32, 0x9f, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5, 0x81, 0x03, 0x80, 0xe1, 
+0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 
+0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 
+0x00, 0x10, 0x93, 0xe5, 0x01, 0x03, 0x80, 0xe1, 0x01, 0x10, 0xa0, 0xe3, 
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5, 
+0x81, 0x02, 0x80, 0xe1, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5, 0x01, 0x02, 0x80, 0xe1, 
+0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 
+0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 
+0x00, 0x10, 0x93, 0xe5, 0x81, 0x01, 0x80, 0xe1, 0x01, 0x10, 0xa0, 0xe3, 
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5, 
+0x01, 0x01, 0x80, 0xe1, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5, 0x81, 0x00, 0x80, 0xe1, 
+0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 
+0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 
+0x00, 0x10, 0x93, 0xe5, 0x01, 0x00, 0x80, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 
+0xfc, 0x46, 0x60, 0x47, 0xa4, 0x21, 0x9f, 0xe5, 0xa8, 0x31, 0x9f, 0xe5, 
+0xa0, 0x13, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x20, 0x13, 0xa0, 0xe1, 
+0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 
+0x00, 0x10, 0x82, 0xe5, 0xa0, 0x12, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5, 
+0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 
+0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 
+0x20, 0x12, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0xa0, 0x11, 0xa0, 0xe1, 
+0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 
+0x00, 0x10, 0x82, 0xe5, 0x20, 0x11, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5, 
+0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 
+0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 
+0xa0, 0x10, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe1, 
+0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 
+0xfc, 0x46, 0x60, 0x47, 0xa0, 0x30, 0x9f, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 
+0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 
+0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 
+0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 
+0xfc, 0x46, 0x60, 0x47, 0x70, 0x30, 0x9f, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 
+0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 
+0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 
+0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 
+0xfc, 0x46, 0x60, 0x47, 0x34, 0x20, 0x9f, 0xe5, 0x3c, 0x30, 0x9f, 0xe5, 
+0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 
+0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 
+0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 
+0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 
+0x1e, 0xff, 0x2f, 0xe1, 0xf8, 0x00, 0x18, 0x40, 0x04, 0x01, 0x18, 0x40, 
+0x00, 0x01, 0x18, 0x40, 0xfc, 0x00, 0x18, 0x40, 0x02, 0x1c, 0x00, 0x20, 
+0x00, 0x29, 0x07, 0xdd, 0x13, 0x78, 0xc0, 0x18, 0x00, 0x06, 0x00, 0x0e, 
+0x01, 0x32, 0x01, 0x39, 0x00, 0x29, 0xf7, 0xdc, 0x70, 0x47, 0x09, 0x4b, 
+0xc9, 0x18, 0x04, 0x29, 0x08, 0xd8, 0x8c, 0x22, 0x4a, 0x43, 0x07, 0x4b, 
+0xd2, 0x18, 0x13, 0x7a, 0x09, 0x06, 0x09, 0x0e, 0x8b, 0x42, 0x01, 0xd0, 
+0x14, 0x20, 0x70, 0x47, 0x02, 0x60, 0x00, 0x20, 0xfb, 0xe7, 0x00, 0x00, 
+0xf3, 0x0f, 0x01, 0x35, 0xb0, 0x6e, 0x21, 0x40, 0x01, 0x1c, 0x00, 0x22, 
+0x06, 0x48, 0x03, 0x7a, 0xff, 0x2b, 0x04, 0xd0, 0x8c, 0x30, 0x01, 0x32, 
+0x04, 0x2a, 0xf8, 0xd3, 0x01, 0xe0, 0x04, 0x2a, 0x00, 0xd3, 0x00, 0x20, 
+0x0a, 0x60, 0x70, 0x47, 0xb0, 0x6e, 0x21, 0x40, 0xf0, 0xb5, 0x07, 0x1c, 
+0x00, 0x24, 0x00, 0x2f, 0x21, 0xd0, 0x00, 0x26, 0xf8, 0x79, 0x00, 0x28, 
+0x1b, 0xdd, 0x30, 0x01, 0xc0, 0x19, 0xc5, 0x1d, 0x05, 0x35, 0x00, 0x7b, 
+0x00, 0x06, 0x00, 0x16, 0x00, 0xf0, 0x92, 0xfb, 0x01, 0x1c, 0x8b, 0x68, 
+0x00, 0x2b, 0x08, 0xd0, 0x68, 0x68, 0x00, 0x28, 0x05, 0xd0, 0xca, 0x68, 
+0xa9, 0x68, 0xfb, 0xf7, 0x4a, 0xfb, 0x00, 0x20, 0x68, 0x60, 0x70, 0x1c, 
+0x06, 0x06, 0x36, 0x0e, 0xf8, 0x79, 0xb0, 0x42, 0xe3, 0xdc, 0xff, 0x20, 
+0x38, 0x72, 0x20, 0x1c, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf3, 0xb5, 
+0x81, 0xb0, 0x0f, 0x1c, 0x68, 0x46, 0xff, 0xf7, 0xbd, 0xff, 0x00, 0x28, 
+0x01, 0xd1, 0x0d, 0x20, 0x37, 0xe0, 0xb9, 0x88, 0xc0, 0x46, 0x01, 0x80, 
+0xf9, 0x88, 0xc0, 0x46, 0x41, 0x80, 0xb9, 0x7a, 0xc0, 0x46, 0x41, 0x71, 
+0xf9, 0x7a, 0xc0, 0x46, 0x81, 0x71, 0x8c, 0x21, 0x01, 0x71, 0x3d, 0x7e, 
+0x00, 0x21, 0x00, 0x23, 0x00, 0x2d, 0x1f, 0xdd, 0x1a, 0x01, 0xd2, 0x19, 
+0x1c, 0x32, 0x16, 0x78, 0x05, 0x2e, 0x0d, 0xdc, 0x0c, 0x01, 0x24, 0x18, 
+0x26, 0x73, 0x96, 0x68, 0xc0, 0x46, 0x66, 0x61, 0xd6, 0x68, 0xc0, 0x46, 
+0x26, 0x61, 0x00, 0x24, 0x01, 0x31, 0x09, 0x06, 0x09, 0x0e, 0xd4, 0x60, 
+0x5a, 0x1c, 0x13, 0x06, 0x1b, 0x0e, 0xab, 0x42, 0xe6, 0xdb, 0x00, 0x29, 
+0x04, 0xd0, 0xc1, 0x71, 0x00, 0x99, 0xc0, 0x46, 
+0x01, 0x72, 0x00, 0xe0, 0x00, 0x20, 0x01, 0x99, 0xc0, 0x46, 0x08, 0x60, 
+0x00, 0x20, 0x03, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb5, 
+0x07, 0x1c, 0x38, 0x7e, 0x00, 0x28, 0x28, 0xd0, 0x01, 0x38, 0x05, 0x06, 
+0x2d, 0x0e, 0x00, 0x26, 0xff, 0x2d, 0x21, 0xd0, 0x28, 0x01, 0xc0, 0x19, 
+0xc4, 0x1d, 0x15, 0x34, 0x00, 0x7f, 0x00, 0x06, 0x00, 0x16, 0x00, 0xf0, 
+0x1f, 0xfb, 0x01, 0x1c, 0x11, 0xd0, 0x8a, 0x68, 0x00, 0x2a, 0x0c, 0xd0, 
+0xe0, 0x68, 0x00, 0x28, 0x09, 0xd0, 0x00, 0x23, 0xcb, 0x56, 0x05, 0x2b, 
+0x05, 0xdc, 0x13, 0x1c, 0xca, 0x68, 0xa1, 0x68, 0xfb, 0xf7, 0xd1, 0xfa, 
+0xe6, 0x60, 0xff, 0x20, 0x20, 0x70, 0x68, 0x1e, 0x05, 0x06, 0x2d, 0x0e, 
+0xff, 0x2d, 0xdd, 0xd1, 0x3e, 0x76, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x13, 0x20, 0x70, 0x47, 0xf0, 0xb5, 0x82, 0xb0, 0x07, 0x1c, 0xf8, 0x1d, 
+0xd5, 0x30, 0x39, 0x1c, 0xff, 0xf7, 0x7f, 0xff, 0x00, 0x90, 0x00, 0x98, 
+0x00, 0x28, 0x3b, 0xd1, 0x38, 0x7e, 0xc0, 0x46, 0x01, 0x90, 0x00, 0x26, 
+0x01, 0x98, 0x00, 0x28, 0x2d, 0xdd, 0x30, 0x01, 0xc0, 0x19, 0xc5, 0x1d, 
+0x15, 0x35, 0x00, 0x7f, 0x00, 0x06, 0x00, 0x16, 0x00, 0xf0, 0xe4, 0xfa, 
+0x04, 0x1c, 0x20, 0x69, 0x00, 0x28, 0x17, 0xd0, 0x28, 0x78, 0x05, 0x28, 
+0x0d, 0xdd, 0xe9, 0x68, 0xaa, 0x68, 0x60, 0x68, 0x40, 0x08, 0x40, 0x00, 
+0x01, 0xf0, 0x0e, 0xf8, 0x09, 0x22, 0xe8, 0x68, 0xa9, 0x68, 0xfb, 0xf7, 
+0x87, 0xf9, 0x00, 0x20, 0xe8, 0x60, 0x21, 0x69, 0x28, 0x1c, 0xfb, 0xf7, 
+0x8c, 0xfa, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x90, 0x00, 0x98, 0x00, 0x28, 
+0x0c, 0xd1, 0x70, 0x1c, 0x06, 0x06, 0x36, 0x0e, 0x01, 0x98, 0x86, 0x42, 
+0xd1, 0xdb, 0x00, 0x20, 0x38, 0x76, 0x00, 0x98, 0x02, 0xb0, 0xf0, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0x38, 0x1c, 0xff, 0xf7, 0x82, 0xff, 0xf6, 0xe7, 
+0xc1, 0x1d, 0x79, 0x31, 0x4a, 0x6b, 0xc0, 0x46, 0xca, 0x63, 0xc1, 0x1d, 
+0xb9, 0x31, 0x0a, 0x60, 0x00, 0x22, 0x8a, 0x60, 0x04, 0x4a, 0xc0, 0x46, 
+0x4a, 0x61, 0x8a, 0x61, 0x01, 0x21, 0xd0, 0x30, 0x41, 0x70, 0x08, 0x1c, 
+0x70, 0x47, 0x00, 0x00, 0xb9, 0xbd, 0x21, 0x40, 0xf8, 0xb5, 0x07, 0x1c, 
+0x00, 0x20, 0x00, 0x90, 0xfe, 0x1d, 0xc9, 0x36, 0x30, 0x78, 0x00, 0x01, 
+0xc0, 0x19, 0xc4, 0x1d, 0x15, 0x34, 0x80, 0x6a, 0x45, 0x08, 0x6d, 0x00, 
+0x04, 0x21, 0x38, 0x1c, 0xff, 0xf7, 0xb2, 0xfe, 0x31, 0x78, 0x40, 0x18, 
+0x01, 0x06, 0x09, 0x0e, 0x00, 0x20, 0xa2, 0x68, 0x00, 0x2a, 0x0a, 0xd9, 
+0x2a, 0x78, 0x4a, 0x40, 0x2a, 0x70, 0x01, 0x30, 0x09, 0x18, 0x09, 0x06, 
+0x09, 0x0e, 0xa2, 0x68, 0x01, 0x35, 0x82, 0x42, 0xf4, 0xd8, 0xe0, 0x68, 
+0xa1, 0x68, 0x40, 0x08, 0x40, 0x00, 0xff, 0xf7, 0x99, 0xfe, 0x61, 0x78, 
+0x81, 0x42, 0x0a, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 0x0f, 0xf8, 0xf8, 0x1d, 
+0x79, 0x30, 0x80, 0x6b, 0xf9, 0x1d, 0xb9, 0x31, 0xc8, 0x60, 0x0c, 0x20, 
+0x00, 0x90, 0x30, 0x78, 0x01, 0x30, 0x30, 0x70, 0x00, 0x98, 0xf8, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0xc2, 0x1d, 0xc9, 0x32, 0x11, 0x78, 0x09, 0x01, 
+0x09, 0x18, 0x09, 0x6a, 0xc3, 0x1d, 0x79, 0x33, 0xd9, 0x63, 0x13, 0x78, 
+0x1b, 0x01, 0x1b, 0x18, 0x5b, 0x6a, 0xcb, 0x18, 0xc1, 0x1d, 0xb9, 0x31, 
+0x0b, 0x60, 0x13, 0x78, 0x1b, 0x01, 0x1b, 0x18, 0x9b, 0x6a, 0xc0, 0x46, 
+0x8b, 0x60, 0x07, 0x4b, 0xc0, 0x46, 0x4b, 0x61, 0x12, 0x78, 0x00, 0x7e, 
+0x01, 0x32, 0x82, 0x42, 0x01, 0xdb, 0x04, 0x48, 
+0x00, 0xe0, 0x04, 0x48, 0xc0, 0x46, 0x88, 0x61, 0x00, 0x20, 0x70, 0x47, 
+0x81, 0xbe, 0x21, 0x40, 0x55, 0xbe, 0x21, 0x40, 0x01, 0xbf, 0x21, 0x40, 
+0xf8, 0xb5, 0x04, 0x1c, 0x00, 0x20, 0x00, 0x90, 0x25, 0x7e, 0x29, 0x01, 
+0xe0, 0x1d, 0x15, 0x30, 0xff, 0xf7, 0x4e, 0xfe, 0xa1, 0x7e, 0x81, 0x42, 
+0x0a, 0xd0, 0x20, 0x1c, 0x00, 0xf0, 0x61, 0xf8, 0xe0, 0x1d, 0x79, 0x30, 
+0x80, 0x6b, 0xe1, 0x1d, 0xb9, 0x31, 0xc8, 0x60, 0x0b, 0x20, 0x55, 0xe0, 
+0x00, 0x27, 0x00, 0x2d, 0x0f, 0xdd, 0x38, 0x01, 0x00, 0x19, 0x00, 0x7f, 
+0x00, 0x06, 0x00, 0x16, 0x00, 0xf0, 0x10, 0xfa, 0x00, 0x28, 0x01, 0xd1, 
+0x09, 0x20, 0x47, 0xe0, 0x78, 0x1c, 0x07, 0x06, 0x3f, 0x0e, 0xaf, 0x42, 
+0xef, 0xdb, 0x00, 0x26, 0x00, 0x2d, 0x38, 0xdd, 0x30, 0x01, 0x00, 0x19, 
+0xc7, 0x1d, 0x15, 0x37, 0x00, 0x7f, 0x00, 0x06, 0x00, 0x16, 0x00, 0xf0, 
+0xfb, 0xf9, 0x00, 0x23, 0xc1, 0x56, 0x05, 0x29, 0x0c, 0xdc, 0x42, 0x68, 
+0x00, 0x2a, 0x04, 0xd0, 0xc1, 0x68, 0xb8, 0x68, 0xfb, 0xf7, 0xb2, 0xf9, 
+0xf8, 0x60, 0xf8, 0x68, 0x00, 0x28, 0x1b, 0xd1, 0x0e, 0x20, 0x17, 0xe0, 
+0xc0, 0x68, 0x00, 0x28, 0x07, 0xd0, 0xfb, 0xf7, 0xa5, 0xf9, 0x00, 0x28, 
+0x05, 0xda, 0x40, 0x42, 0xb9, 0x68, 0x81, 0x42, 0x04, 0xd0, 0x05, 0x20, 
+0x0a, 0xe0, 0xb9, 0x68, 0x81, 0x42, 0xfa, 0xd8, 0x09, 0x21, 0xb8, 0x68, 
+0xfb, 0xf7, 0x7a, 0xf8, 0xf8, 0x60, 0x00, 0x28, 0x02, 0xd1, 0x06, 0x20, 
+0x00, 0x90, 0x07, 0xe0, 0x70, 0x1c, 0x06, 0x06, 0x36, 0x0e, 0xae, 0x42, 
+0xc6, 0xdb, 0x00, 0x98, 0x00, 0x28, 0x02, 0xd0, 0x20, 0x1c, 0xff, 0xf7, 
+0x92, 0xfe, 0x00, 0x98, 0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xc2, 0x1d, 
+0x79, 0x32, 0x41, 0x69, 0xc0, 0x46, 0xd1, 0x63, 0x02, 0x7e, 0x12, 0x01, 
+0x8a, 0x18, 0xc1, 0x1d, 0xb9, 0x31, 0x0a, 0x60, 0xc2, 0x1d, 0x15, 0x32, 
+0x8a, 0x60, 0x05, 0x4a, 0xc0, 0x46, 0x4a, 0x61, 0x04, 0x4a, 0xc0, 0x46, 
+0x8a, 0x61, 0x00, 0x21, 0xd0, 0x30, 0x01, 0x70, 0x08, 0x1c, 0x70, 0x47, 
+0x59, 0xbf, 0x21, 0x40, 0x01, 0xbf, 0x21, 0x40, 0x90, 0xb5, 0x07, 0x1c, 
+0x38, 0x68, 0x1d, 0x4b, 0x98, 0x42, 0x03, 0xd0, 0x03, 0x20, 0x90, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0x1c, 0x21, 0x38, 0x1c, 0xff, 0xf7, 0xbc, 0xfd, 
+0xfc, 0x1d, 0x79, 0x34, 0x00, 0x28, 0x09, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 
+0x2d, 0xf8, 0xf9, 0x1d, 0xb9, 0x31, 0xa0, 0x6b, 0xc0, 0x46, 0xc8, 0x60, 
+0x0a, 0x20, 0xea, 0xe7, 0x38, 0x7a, 0x1c, 0x28, 0x04, 0xd0, 0x78, 0x7a, 
+0x10, 0x28, 0x01, 0xd0, 0x04, 0x20, 0xe2, 0xe7, 0xb8, 0x7a, 0x01, 0x28, 
+0x01, 0xd0, 0x07, 0x20, 0xdd, 0xe7, 0x60, 0x6b, 0xf9, 0x68, 0x88, 0x42, 
+0x01, 0xd0, 0x05, 0x20, 0xd7, 0xe7, 0x38, 0x69, 0x00, 0x28, 0x04, 0xd0, 
+0x06, 0x4b, 0x98, 0x42, 0x01, 0xd0, 0x08, 0x20, 0xcf, 0xe7, 0x38, 0x7e, 
+0x08, 0x28, 0x01, 0xdd, 0x12, 0x20, 0xca, 0xe7, 0x00, 0x20, 0xc8, 0xe7, 
+0x73, 0x6e, 0x69, 0x70, 0x17, 0x40, 0x00, 0x02, 0xb8, 0xb5, 0x07, 0x1c, 
+0x38, 0x1c, 0xff, 0xf7, 0x2a, 0xfe, 0x00, 0x25, 0xf8, 0x1d, 0xc9, 0x30, 
+0x45, 0x70, 0xfc, 0x1d, 0xb9, 0x34, 0xe5, 0x61, 0x68, 0x46, 0xff, 0xf7, 
+0x9d, 0xfd, 0x00, 0x28, 0x01, 0xd1, 0x0d, 0x20, 0x0d, 0xe0, 0xf8, 0x1d, 
+0x79, 0x30, 0x85, 0x63, 0xc5, 0x63, 0x1b, 0x20, 0x20, 0x60, 0xa7, 0x60, 
+0x04, 0x48, 0xc0, 0x46, 0x60, 0x61, 0x04, 0x48, 0xc0, 0x46, 0xa0, 0x61, 
+0x28, 0x1c, 0xb8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0x75, 0xc0, 0x21, 0x40, 0x3b, 0xc0, 0x21, 0x40, 0xf0, 0xb5, 0x82, 0xb0, 
+0x07, 0x1c, 0x00, 0x20, 0xfd, 0x1d, 0x79, 0x35, 0xfc, 0x1d, 0xb9, 0x34, 
+0xe9, 0x6a, 0xc0, 0x46, 0x61, 0x60, 0x62, 0x68, 0xe9, 0x6b, 0x8a, 0x42, 
+0x03, 0xd2, 0x61, 0x60, 0x2a, 0x6b, 0x91, 0x42, 0x34, 0xd2, 0x66, 0x68, 
+0xc0, 0x46, 0x01, 0x96, 0xe9, 0x6b, 0x73, 0x1a, 0xe9, 0x6a, 0x71, 0x1a, 
+0x26, 0x68, 0x2a, 0x6b, 0x96, 0x42, 0x00, 0xd2, 0x32, 0x1c, 0x01, 0x9e, 
+0x96, 0x1b, 0xa2, 0x68, 0xc0, 0x46, 0x00, 0x92, 0x00, 0x2a, 0x09, 0xd0, 
+0x28, 0x6a, 0x6a, 0x6a, 0x41, 0x18, 0x00, 0x98, 0xc0, 0x18, 0x33, 0x1c, 
+0xfc, 0xf7, 0xc4, 0xff, 0x00, 0x28, 0x1b, 0xd1, 0x61, 0x68, 0x89, 0x19, 
+0x61, 0x60, 0x22, 0x68, 0x91, 0x42, 0x0d, 0xd1, 0x61, 0x69, 0x38, 0x1c, 
+0xfb, 0xf7, 0xc1, 0xf8, 0x00, 0x06, 0x00, 0x0e, 0x0e, 0xd1, 0xa1, 0x69, 
+0x38, 0x1c, 0xfb, 0xf7, 0xba, 0xf8, 0x00, 0x06, 0x00, 0x0e, 0x07, 0xd1, 
+0x61, 0x68, 0x2a, 0x6b, 0x91, 0x42, 0xc2, 0xd3, 0xa9, 0x6b, 0xaa, 0x6a, 
+0x89, 0x18, 0xa9, 0x63, 0x02, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0xb0, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c, 0xfb, 0xf7, 
+0xbf, 0xfa, 0xfa, 0x1d, 0x09, 0x32, 0x32, 0x48, 0x00, 0x21, 0xc9, 0x43, 
+0xc4, 0x1d, 0xb9, 0x34, 0xe1, 0x60, 0xf9, 0x88, 0xc3, 0x1d, 0x89, 0x33, 
+0x19, 0x73, 0xc1, 0x1d, 0x79, 0x31, 0xbd, 0x68, 0xc0, 0x46, 0x0d, 0x62, 
+0xff, 0x68, 0xc0, 0x46, 0x4f, 0x62, 0x17, 0x68, 0xc0, 0x46, 0x8f, 0x62, 
+0x57, 0x68, 0xc0, 0x46, 0xcf, 0x62, 0x92, 0x68, 0xc0, 0x46, 0x4a, 0x63, 
+0xca, 0x6a, 0x8f, 0x6a, 0xd2, 0x19, 0x0a, 0x63, 0x1a, 0x7b, 0x01, 0x2a, 
+0x0d, 0xd0, 0x02, 0x2a, 0x1a, 0xd0, 0x03, 0x2a, 0x2e, 0xd1, 0xc2, 0x1d, 
+0xc9, 0x32, 0x52, 0x78, 0x00, 0x2a, 0x07, 0xd1, 0x10, 0x20, 0x89, 0x6b, 
+0xc0, 0x46, 0xe1, 0x60, 0x25, 0xe0, 0xff, 0xf7, 0x4d, 0xff, 0x22, 0xe0, 
+0xff, 0xf7, 0xac, 0xfd, 0x00, 0x28, 0x1e, 0xd1, 0xe1, 0x69, 0x00, 0x29, 
+0x1b, 0xd0, 0x09, 0x7a, 0x15, 0x4b, 0xc9, 0x18, 0x02, 0x91, 0x16, 0xe0, 
+0x8a, 0x6a, 0xcb, 0x6a, 0x9f, 0x18, 0x4d, 0x6b, 0xaf, 0x42, 0x05, 0xd8, 
+0x00, 0x2a, 0x03, 0xd0, 0x9f, 0x07, 0x01, 0xd1, 0x92, 0x07, 0x01, 0xd0, 
+0x0f, 0x20, 0x08, 0xe0, 0x89, 0x6b, 0x99, 0x42, 0x01, 0xd0, 0xe1, 0x60, 
+0xf8, 0xe7, 0xff, 0xf7, 0x53, 0xff, 0x00, 0xe0, 0x10, 0x20, 0x01, 0xab, 
+0x58, 0x80, 0xe0, 0x68, 0xc0, 0x46, 0x03, 0x90, 0x68, 0x46, 0x00, 0x21, 
+0xfb, 0xf7, 0x9e, 0xf9, 0x01, 0x20, 0x04, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x00, 0x3c, 0xac, 0x20, 0x40, 0x0d, 0xf0, 0xfe, 0xca, 
+0x80, 0xb5, 0x85, 0xb0, 0x07, 0x1c, 0x38, 0x1c, 0x01, 0xa9, 0xfb, 0xf7, 
+0x4d, 0xfa, 0x68, 0x46, 0xb9, 0x68, 0xff, 0xf7, 0xa0, 0xfc, 0x00, 0x28, 
+0x02, 0xd1, 0x00, 0x98, 0xff, 0xf7, 0xc4, 0xfc, 0x02, 0xab, 0x58, 0x80, 
+0x00, 0x21, 0x01, 0xa8, 0xfb, 0xf7, 0x7e, 0xf9, 0x01, 0x20, 0x05, 0xb0, 
+0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 0x85, 0xb0, 0x07, 0x1c, 
+0x38, 0x1c, 0x01, 0xa9, 0xfb, 0xf7, 0x32, 0xfa, 0x68, 0x46, 0xb9, 0x68, 
+0xff, 0xf7, 0x85, 0xfc, 0x00, 0x28, 0x00, 0xd1, 0x02, 0x20, 0x02, 0xab, 
+0x58, 0x80, 0x00, 0x21, 0x01, 0xa8, 0xfb, 0xf7, 0x65, 0xf9, 0x01, 0x20, 
+0x05, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x90, 0xb5, 0x85, 0xb0, 
+0x07, 0x1c, 0x38, 0x1c, 0x01, 0xa9, 0xfb, 0xf7, 
+0x19, 0xfa, 0x3c, 0x69, 0x38, 0x1c, 0x01, 0xa9, 0xfb, 0xf7, 0x14, 0xfa, 
+0x68, 0x46, 0x21, 0x1c, 0xff, 0xf7, 0x67, 0xfc, 0x8c, 0x24, 0x00, 0x28, 
+0x0e, 0xd1, 0xb9, 0x68, 0x00, 0x29, 0x02, 0xd1, 0xfa, 0x68, 0x00, 0x2a, 
+0x08, 0xd0, 0xf8, 0x88, 0x23, 0x1c, 0x8c, 0x28, 0x00, 0xd8, 0x03, 0x1c, 
+0xf8, 0x68, 0x00, 0x9a, 0xfc, 0xf7, 0x38, 0xfe, 0x02, 0xab, 0x58, 0x80, 
+0x03, 0x94, 0x00, 0x21, 0x01, 0xa8, 0xfb, 0xf7, 0x37, 0xf9, 0x01, 0x20, 
+0x05, 0xb0, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x21, 0x04, 0x48, 
+0xff, 0x22, 0x02, 0x72, 0x8c, 0x30, 0x01, 0x31, 0x04, 0x29, 0xfa, 0xd3, 
+0x70, 0x47, 0x00, 0x00, 0xb0, 0x6e, 0x21, 0x40, 0x02, 0x48, 0x03, 0x49, 
+0x40, 0x1a, 0x40, 0x42, 0x70, 0x47, 0x00, 0x00, 0xb9, 0xce, 0x21, 0x40, 
+0xb5, 0xce, 0x21, 0x40, 0x00, 0x21, 0x08, 0x4a, 0x8b, 0x00, 0x5b, 0x18, 
+0x9b, 0x00, 0xd3, 0x56, 0x83, 0x42, 0x04, 0xd1, 0x88, 0x00, 0x40, 0x18, 
+0x80, 0x00, 0x80, 0x18, 0x70, 0x47, 0x01, 0x31, 0x01, 0x29, 0xf1, 0xd3, 
+0x00, 0x20, 0xf9, 0xe7, 0xe0, 0x70, 0x21, 0x40, 0x80, 0xb5, 0x00, 0xf0, 
+0x0c, 0xf8, 0x00, 0x27, 0x38, 0x1c, 0x00, 0xf0, 0x45, 0xf8, 0x78, 0x1c, 
+0x07, 0x04, 0x3f, 0x0c, 0x0c, 0x2f, 0xf7, 0xdd, 0x80, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x1c, 0x48, 0x02, 0x68, 0x1c, 0x49, 0x8b, 0x69, 0xd2, 0x18, 
+0x02, 0x60, 0x8a, 0x6a, 0x43, 0x68, 0x9b, 0x18, 0x43, 0x60, 0x93, 0x42, 
+0x02, 0xd2, 0x82, 0x68, 0x01, 0x32, 0x82, 0x60, 0xc2, 0x68, 0x0b, 0x6a, 
+0xd2, 0x18, 0xc2, 0x60, 0x42, 0x69, 0xcb, 0x68, 0xd2, 0x18, 0x42, 0x61, 
+0xc2, 0x69, 0x8b, 0x68, 0xd2, 0x18, 0xc2, 0x61, 0x02, 0x69, 0x0b, 0x69, 
+0xd2, 0x18, 0x02, 0x61, 0x82, 0x69, 0x0b, 0x68, 0xd2, 0x18, 0x82, 0x61, 
+0x02, 0x6b, 0xcb, 0x69, 0xd2, 0x18, 0x02, 0x63, 0x4a, 0x6a, 0x43, 0x6b, 
+0x9b, 0x18, 0x43, 0x63, 0x93, 0x42, 0x02, 0xd2, 0x82, 0x6b, 0x01, 0x32, 
+0x82, 0x63, 0xc2, 0x6b, 0x4b, 0x69, 0xd2, 0x18, 0xc2, 0x63, 0x02, 0x6c, 
+0xc9, 0x6a, 0x51, 0x18, 0x01, 0x64, 0x70, 0x47, 0x10, 0x2a, 0x00, 0x80, 
+0x00, 0x08, 0x14, 0x40, 0x88, 0xb5, 0x69, 0x46, 0x00, 0xf0, 0x17, 0xf8, 
+0x81, 0x08, 0x0a, 0xd0, 0x00, 0x20, 0x00, 0x29, 0x07, 0xd9, 0x00, 0x22, 
+0x83, 0x00, 0x00, 0x9f, 0xc0, 0x46, 0xfa, 0x50, 0x01, 0x30, 0x88, 0x42, 
+0xf8, 0xd3, 0x88, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0x00, 0xf0, 
+0x04, 0xf8, 0x00, 0x04, 0x00, 0x0c, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x22, 
+0x00, 0x28, 0x0a, 0xd0, 0x01, 0x28, 0x0a, 0xd0, 0x02, 0x28, 0x0c, 0xd0, 
+0x03, 0x28, 0x02, 0xd1, 0x07, 0x48, 0x1c, 0x22, 0x08, 0x60, 0x10, 0x1c, 
+0x70, 0x47, 0x06, 0x48, 0x04, 0xe0, 0x06, 0x48, 0x50, 0x22, 0x08, 0x60, 
+0xf7, 0xe7, 0x05, 0x48, 0x68, 0x22, 0x08, 0x60, 0xf3, 0xe7, 0x00, 0x00, 
+0x08, 0x83, 0x20, 0x40, 0x10, 0x2a, 0x00, 0x80, 0x78, 0x2a, 0x00, 0x80, 
+0xa0, 0x82, 0x20, 0x40, 0x98, 0xb5, 0x00, 0x27, 0x68, 0x46, 0xfe, 0xf7, 
+0xa7, 0xfb, 0x10, 0x4c, 0x00, 0x28, 0x0b, 0xd0, 0x00, 0xf0, 0x3e, 0xf8, 
+0x00, 0x28, 0x07, 0xd0, 0x01, 0x27, 0x10, 0x23, 0x20, 0x68, 0x18, 0x43, 
+0x20, 0x60, 0x60, 0x68, 0x18, 0x43, 0x0b, 0xe0, 0x10, 0x23, 0xa0, 0x68, 
+0x98, 0x43, 0xa0, 0x60, 0x20, 0x69, 0x98, 0x43, 0x20, 0x61, 0x20, 0x68, 
+0x98, 0x43, 0x20, 0x60, 0x60, 0x68, 0x98, 0x43, 0x60, 0x60, 0x38, 0x1c, 
+0x98, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 
+0xe8, 0x18, 0x00, 0x80, 0x00, 0xb5, 0x00, 0xf0, 0xb5, 0xfc, 0xfe, 0xf7, 
+0xc5, 0xfb, 0x00, 0x20, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb5, 0x14, 0x24, 
+0x00, 0x25, 0x00, 0x27, 0x08, 0x4e, 0x02, 0x20, 0x21, 0x1c, 0x32, 0x1c, 
+0xfa, 0xf7, 0xec, 0xfe, 0x78, 0x40, 0x07, 0x04, 0x3f, 0x0c, 0x02, 0x34, 
+0x01, 0x35, 0x03, 0x2d, 0xf3, 0xd3, 0x38, 0x1c, 0xf0, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x00, 0x39, 0xb7, 0x21, 0x40, 0x90, 0xb5, 0x01, 0x24, 
+0x20, 0x1c, 0x10, 0x49, 0xc9, 0x68, 0x01, 0x29, 0x00, 0xd0, 0x00, 0x20, 
+0x00, 0x06, 0x00, 0x0e, 0x16, 0xd0, 0x0d, 0x4a, 0x3a, 0x21, 0x02, 0x20, 
+0xfa, 0xf7, 0xce, 0xfe, 0x07, 0x04, 0x3f, 0x0c, 0x03, 0xd1, 0x00, 0x20, 
+0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xff, 0xf7, 0xcf, 0xff, 0xc0, 0x43, 
+0x00, 0x04, 0x00, 0x0c, 0xb8, 0x42, 0x00, 0xd0, 0x00, 0x24, 0x20, 0x06, 
+0x00, 0x0e, 0xf1, 0xe7, 0x20, 0x1c, 0xef, 0xe7, 0xe8, 0x0d, 0x00, 0x80, 
+0x39, 0xb7, 0x21, 0x40, 0xb0, 0xb5, 0x01, 0x27, 0x3a, 0x1c, 0x18, 0x4b, 
+0xdb, 0x68, 0x01, 0x2b, 0x00, 0xd0, 0x00, 0x22, 0x12, 0x06, 0x12, 0x0e, 
+0x00, 0x24, 0x00, 0x2a, 0x23, 0xd0, 0x14, 0x4a, 0x53, 0x68, 0x1b, 0x04, 
+0x1b, 0x0c, 0x1d, 0x02, 0x1b, 0x12, 0x2b, 0x43, 0x92, 0x68, 0x12, 0x04, 
+0x12, 0x0c, 0x15, 0x02, 0x12, 0x12, 0x2a, 0x43, 0x12, 0x04, 0x12, 0x0c, 
+0x1b, 0x04, 0x1a, 0x43, 0x51, 0x40, 0x01, 0x31, 0x0f, 0xd1, 0x00, 0x28, 
+0x02, 0xd0, 0xff, 0xf7, 0x9b, 0xff, 0xc4, 0x43, 0x22, 0x04, 0x12, 0x0c, 
+0x07, 0x4b, 0x3a, 0x21, 0x02, 0x20, 0xfa, 0xf7, 0x8a, 0xfe, 0x38, 0x1c, 
+0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x20, 0x1c, 0xfa, 0xe7, 0x00, 0x00, 
+0xe8, 0x0d, 0x00, 0x80, 0x40, 0x00, 0x14, 0x40, 0x7b, 0xb7, 0x21, 0x40, 
+0x80, 0xb4, 0x03, 0x22, 0xc2, 0x80, 0x15, 0x4a, 0xc0, 0x46, 0x82, 0x60, 
+0x14, 0x4a, 0x12, 0x88, 0x01, 0x32, 0xc2, 0x60, 0x00, 0x20, 0x13, 0x4a, 
+0x13, 0x5c, 0xc0, 0x46, 0x0b, 0x70, 0x01, 0x30, 0x01, 0x31, 0x08, 0x28, 
+0xf8, 0xd3, 0x20, 0x22, 0x0a, 0x70, 0x01, 0x31, 0x00, 0x20, 0x0e, 0x4b, 
+0x1f, 0x5c, 0xc0, 0x46, 0x0f, 0x70, 0x01, 0x30, 0x01, 0x31, 0x08, 0x28, 
+0xf8, 0xd3, 0x0a, 0x70, 0x01, 0x31, 0x00, 0x20, 0x09, 0x4a, 0x13, 0x5c, 
+0xc0, 0x46, 0x0b, 0x70, 0x01, 0x30, 0x01, 0x31, 0x08, 0x28, 0xf8, 0xd3, 
+0x00, 0x20, 0x08, 0x70, 0x80, 0xbc, 0x70, 0x47, 0x17, 0x40, 0x00, 0x02, 
+0xe8, 0x0d, 0x00, 0x80, 0xfc, 0x03, 0x00, 0x80, 0x05, 0x04, 0x00, 0x80, 
+0x0e, 0x04, 0x00, 0x80, 0xf0, 0xb5, 0x01, 0x21, 0x45, 0x4d, 0xe8, 0x1d, 
+0x79, 0x30, 0x41, 0x73, 0x01, 0x73, 0x64, 0x22, 0x42, 0x82, 0x82, 0x82, 
+0xc1, 0x82, 0x7d, 0x21, 0xc9, 0x00, 0x01, 0x83, 0x00, 0x21, 0x41, 0x83, 
+0x3f, 0x48, 0x01, 0x22, 0x00, 0xf0, 0x08, 0xfb, 0x00, 0x26, 0xf6, 0x43, 
+0x3d, 0x4c, 0xe7, 0x1d, 0x39, 0x37, 0xb0, 0x42, 0x07, 0xd1, 0xf8, 0x88, 
+0x01, 0x30, 0xf8, 0x80, 0xa0, 0x79, 0x01, 0x30, 0xa0, 0x71, 0xfc, 0xf7, 
+0xb3, 0xfd, 0x38, 0x48, 0x02, 0x22, 0x00, 0x21, 0x00, 0xf0, 0xf4, 0xfa, 
+0xb0, 0x42, 0x07, 0xd1, 0xf8, 0x88, 0x01, 0x30, 0xf8, 0x80, 0xa0, 0x79, 
+0x01, 0x30, 0xa0, 0x71, 0xfc, 0xf7, 0xa4, 0xfd, 0xe8, 0x68, 0x2f, 0x1c, 
+0x01, 0x28, 0x05, 0xd1, 0x2f, 0x48, 0x7d, 0x22, 0xd2, 0x00, 0x00, 0x21, 
+0x00, 0xf0, 0xe0, 0xfa, 0x2d, 0x4d, 0x28, 0x1c, 0xfa, 0xf7, 0x02, 0xfe, 
+0x2c, 0x48, 0xfa, 0xf7, 0xff, 0xfd, 0x2c, 0x48, 
+0xfa, 0xf7, 0xfc, 0xfd, 0x2b, 0x4e, 0x71, 0x23, 0x5b, 0x01, 0xfc, 0x18, 
+0x2a, 0x4f, 0x20, 0x79, 0x00, 0x28, 0x0f, 0xd0, 0x28, 0x1c, 0xfa, 0xf7, 
+0xf1, 0xfd, 0x38, 0x1c, 0xfa, 0xf7, 0xee, 0xfd, 0x00, 0x28, 0x04, 0xd0, 
+0x38, 0x1c, 0xfa, 0xf7, 0xe9, 0xfd, 0x00, 0x28, 0xfa, 0xd1, 0x30, 0x1c, 
+0xfa, 0xf7, 0xe4, 0xfd, 0x60, 0x79, 0x00, 0x28, 0x23, 0xd0, 0x28, 0x1c, 
+0xfa, 0xf7, 0xde, 0xfd, 0x38, 0x1c, 0xfa, 0xf7, 0xdb, 0xfd, 0x00, 0x28, 
+0x04, 0xd0, 0x38, 0x1c, 0xfa, 0xf7, 0xd6, 0xfd, 0x00, 0x28, 0xfa, 0xd1, 
+0x19, 0x49, 0x01, 0x22, 0x12, 0x04, 0x08, 0x68, 0x02, 0x40, 0x14, 0x20, 
+0x00, 0x2a, 0x05, 0xd1, 0x0a, 0x68, 0x12, 0x0c, 0x06, 0xd1, 0x09, 0x68, 
+0x89, 0x0a, 0x03, 0xd3, 0x13, 0x49, 0xc0, 0x46, 0xc8, 0x60, 0x03, 0xe0, 
+0x12, 0x49, 0xc0, 0x46, 0x08, 0x64, 0xff, 0xe7, 0xfe, 0xe7, 0xff, 0xf7, 
+0x1e, 0xfe, 0x10, 0x48, 0xfa, 0xf7, 0xb8, 0xfd, 0x0f, 0x48, 0xfa, 0xf7, 
+0xb5, 0xfd, 0xbc, 0xe7, 0xe8, 0x0d, 0x00, 0x80, 0x5d, 0x22, 0xff, 0xff, 
+0xa0, 0x82, 0x20, 0x40, 0x21, 0x21, 0xff, 0xff, 0x59, 0x7e, 0x21, 0x40, 
+0xf4, 0x01, 0xff, 0xff, 0x09, 0x2c, 0xff, 0xff, 0x04, 0x02, 0xff, 0xff, 
+0x00, 0x00, 0xff, 0xff, 0xb5, 0x07, 0xff, 0xff, 0x00, 0x00, 0x10, 0x40, 
+0x40, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, 0x80, 0x65, 0xa8, 0x21, 0x40, 
+0x48, 0x57, 0xff, 0xff, 0x00, 0xb5, 0x10, 0x20, 0x0f, 0x49, 0xc0, 0x46, 
+0x08, 0x60, 0x0f, 0x4a, 0x0f, 0x48, 0x64, 0x21, 0xfa, 0xf7, 0x8e, 0xfd, 
+0x0e, 0x48, 0x01, 0x22, 0x12, 0x04, 0x01, 0x68, 0x0a, 0x40, 0x08, 0x21, 
+0x00, 0x2a, 0x05, 0xd1, 0x02, 0x68, 0x12, 0x0c, 0x07, 0xd1, 0x00, 0x68, 
+0x80, 0x0a, 0x04, 0xd3, 0x08, 0x48, 0xc0, 0x46, 0xc1, 0x60, 0x08, 0xbc, 
+0x18, 0x47, 0x07, 0x48, 0xc0, 0x46, 0x01, 0x64, 0xf9, 0xe7, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0xb0, 0x25, 0x55, 0xff, 0xff, 0xf8, 0x28, 0x00, 0x80, 
+0x00, 0x00, 0x10, 0x40, 0x40, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, 0x80, 
+0xb0, 0xb5, 0x24, 0x4f, 0x01, 0x21, 0x09, 0x04, 0x38, 0x68, 0x01, 0x40, 
+0x06, 0x20, 0x22, 0x4d, 0x22, 0x4c, 0x00, 0x29, 0x05, 0xd1, 0x39, 0x68, 
+0x09, 0x0c, 0x04, 0xd1, 0x39, 0x68, 0x89, 0x0a, 0x01, 0xd3, 0xe8, 0x60, 
+0x00, 0xe0, 0x20, 0x64, 0x03, 0x20, 0xfe, 0xf7, 0xc5, 0xfa, 0xfb, 0xf7, 
+0xa1, 0xf9, 0x01, 0x23, 0x18, 0x43, 0xfb, 0xf7, 0x6b, 0xfa, 0x00, 0xf0, 
+0x31, 0xf8, 0x01, 0x21, 0x09, 0x04, 0x38, 0x68, 0x01, 0x40, 0x07, 0x20, 
+0x00, 0x29, 0x05, 0xd1, 0x39, 0x68, 0x09, 0x0c, 0x04, 0xd1, 0x39, 0x68, 
+0x89, 0x0a, 0x01, 0xd3, 0xe8, 0x60, 0x00, 0xe0, 0x20, 0x64, 0x00, 0xf0, 
+0x89, 0xf8, 0x00, 0xf0, 0x69, 0xf8, 0x00, 0xf0, 0xd3, 0xf8, 0x01, 0x21, 
+0x09, 0x04, 0x38, 0x68, 0x01, 0x40, 0x09, 0x20, 0x00, 0x29, 0x05, 0xd1, 
+0x39, 0x68, 0x09, 0x0c, 0x04, 0xd1, 0x39, 0x68, 0x89, 0x0a, 0x01, 0xd3, 
+0xe8, 0x60, 0x00, 0xe0, 0x20, 0x64, 0xff, 0xf7, 0xdf, 0xfe, 0xb0, 0xbc, 
+0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x10, 0x40, 0x40, 0x01, 0x18, 0x00, 
+0x00, 0x00, 0x00, 0x80, 0x00, 0xb5, 0x21, 0x48, 0xfa, 0xf7, 0x14, 0xfd, 
+0xfd, 0xf7, 0x4a, 0xf8, 0x00, 0xf0, 0xa6, 0xf8, 0xfd, 0xf7, 0x58, 0xf8, 
+0x00, 0xf0, 0xc0, 0xf8, 0xfc, 0xf7, 0x9f, 0xfc, 0xff, 0xf7, 0x5c, 0xfd, 
+0xfd, 0xf7, 0x3c, 0xfa, 0xfd, 0xf7, 0xc4, 0xf9, 0xfd, 0xf7, 0xdc, 0xfa, 
+0xfd, 0xf7, 0x60, 0xf9, 0xfd, 0xf7, 0x1a, 0xf9, 
+0xfd, 0xf7, 0xa2, 0xf9, 0x00, 0xf0, 0x8a, 0xf9, 0xfd, 0xf7, 0xb6, 0xfb, 
+0xfd, 0xf7, 0x24, 0xfb, 0xfd, 0xf7, 0xec, 0xfa, 0xfd, 0xf7, 0x46, 0xf8, 
+0xfa, 0xf7, 0xf2, 0xfb, 0xff, 0xf7, 0x18, 0xfd, 0x00, 0x20, 0xff, 0xf7, 
+0xef, 0xfd, 0x00, 0xf0, 0x29, 0xf8, 0x00, 0x20, 0x0a, 0x49, 0x71, 0x23, 
+0x5b, 0x01, 0xca, 0x18, 0x10, 0x71, 0x50, 0x71, 0x07, 0x23, 0x5b, 0x02, 
+0xc9, 0x18, 0xc8, 0x62, 0x06, 0x49, 0xc0, 0x46, 0x48, 0x62, 0x00, 0xf0, 
+0x87, 0xf9, 0x05, 0x48, 0xfa, 0xf7, 0xd6, 0xfc, 0x08, 0xbc, 0x18, 0x47, 
+0xff, 0xb8, 0x21, 0x40, 0xe8, 0x0d, 0x00, 0x80, 0xc0, 0x00, 0x18, 0x00, 
+0x31, 0x98, 0x21, 0x40, 0x00, 0xb5, 0x04, 0x48, 0xfa, 0xf7, 0xc8, 0xfc, 
+0xfd, 0xf7, 0x7c, 0xfb, 0xfd, 0xf7, 0x34, 0xf8, 0x08, 0xbc, 0x18, 0x47, 
+0x11, 0xa2, 0x21, 0x40, 0x00, 0xb5, 0xfd, 0xf7, 0x81, 0xfa, 0x06, 0x48, 
+0xfa, 0xf7, 0xba, 0xfc, 0xfd, 0xf7, 0x56, 0xfa, 0xfd, 0xf7, 0x8c, 0xfb, 
+0xfd, 0xf7, 0x9e, 0xfb, 0xfd, 0xf7, 0xac, 0xfb, 0x08, 0xbc, 0x18, 0x47, 
+0x91, 0x03, 0xff, 0xff, 0xf8, 0xb5, 0x1a, 0x48, 0xc1, 0x6b, 0xff, 0x29, 
+0xfc, 0xd1, 0x81, 0x6b, 0x42, 0x6b, 0x0d, 0x1c, 0x16, 0x1c, 0x17, 0x4c, 
+0x10, 0x23, 0x60, 0x69, 0x18, 0x43, 0x60, 0x61, 0xa1, 0x69, 0x99, 0x43, 
+0x1f, 0x04, 0xa1, 0x61, 0xf8, 0x60, 0xa0, 0x69, 0xc0, 0x46, 0x38, 0x61, 
+0x11, 0x4a, 0x12, 0x49, 0x64, 0x20, 0xfa, 0xf7, 0x95, 0xfc, 0x11, 0x4a, 
+0xc0, 0x46, 0x00, 0x92, 0x10, 0x4b, 0x00, 0x20, 0x29, 0x1c, 0x32, 0x1c, 
+0xfa, 0xf7, 0x94, 0xfc, 0x0e, 0x48, 0xc1, 0x68, 0x08, 0x29, 0xfc, 0xd1, 
+0x10, 0x23, 0x60, 0x69, 0x98, 0x43, 0x60, 0x61, 0xf8, 0x60, 0x01, 0x20, 
+0xe3, 0x23, 0x1b, 0x01, 0xe1, 0x18, 0xc8, 0x70, 0xf8, 0xbc, 0x08, 0xbc, 
+0x18, 0x47, 0x00, 0x00, 0x00, 0x01, 0x18, 0x40, 0xe8, 0x0d, 0x00, 0x80, 
+0xa0, 0x54, 0xff, 0xff, 0x11, 0xc8, 0x21, 0x40, 0x64, 0x00, 0x30, 0x02, 
+0x44, 0x80, 0x20, 0x40, 0x40, 0x01, 0x18, 0x40, 0xfa, 0x21, 0x03, 0x48, 
+0xc0, 0x46, 0x41, 0x62, 0x40, 0x21, 0x41, 0x62, 0x70, 0x47, 0x00, 0x00, 
+0xc0, 0x00, 0x18, 0x00, 0x07, 0x48, 0x41, 0x69, 0x07, 0x4b, 0x19, 0x43, 
+0x41, 0x61, 0x82, 0x69, 0x9a, 0x43, 0x82, 0x61, 0x01, 0x22, 0x12, 0x05, 
+0xd1, 0x60, 0x80, 0x69, 0xc0, 0x46, 0x10, 0x61, 0x70, 0x47, 0x00, 0x00, 
+0xe8, 0x0d, 0x00, 0x80, 0xfe, 0xaf, 0x9a, 0x10, 0xf0, 0xb4, 0x4b, 0x4a, 
+0x4b, 0x48, 0x00, 0x68, 0x00, 0x0c, 0x4b, 0x4d, 0x4b, 0x4b, 0x98, 0x42, 
+0x02, 0xd0, 0x01, 0x33, 0x98, 0x42, 0x01, 0xd1, 0x01, 0x20, 0x28, 0x80, 
+0x01, 0x21, 0xc9, 0x03, 0x19, 0x23, 0xdb, 0x01, 0xec, 0x18, 0x61, 0x61, 
+0x28, 0x88, 0x40, 0x04, 0x44, 0x4b, 0xc0, 0x18, 0x87, 0x1a, 0x06, 0x20, 
+0xaf, 0x60, 0x43, 0x4e, 0xc0, 0x46, 0xb0, 0x61, 0x20, 0x20, 0xc8, 0x23, 
+0x43, 0x43, 0xbb, 0x42, 0x21, 0xd9, 0x41, 0x00, 0x3e, 0x4e, 0xc0, 0x46, 
+0x31, 0x61, 0xb6, 0x69, 0x20, 0x23, 0x9b, 0x1b, 0x3b, 0x4e, 0xc0, 0x46, 
+0xf3, 0x61, 0x10, 0x3b, 0x33, 0x62, 0x8b, 0x00, 0xff, 0x1a, 0x40, 0x08, 
+0x81, 0x42, 0x17, 0xd3, 0xb8, 0x23, 0x43, 0x43, 0xbb, 0x42, 0x08, 0xd9, 
+0x41, 0x1e, 0x34, 0x4b, 0xc0, 0x46, 0x99, 0x81, 0xd9, 0x81, 0x40, 0x00, 
+0x02, 0x38, 0x58, 0x61, 0x0a, 0xe0, 0x01, 0x30, 0x81, 0x42, 0xef, 0xd2, 
+0x06, 0xe0, 0x2e, 0x4e, 0xb3, 0x69, 0x01, 0x33, 0xb3, 0x61, 0x40, 0x00, 
+0x88, 0x42, 0xd2, 0xd9, 0x2b, 0x49, 0x00, 0x20, 
+0x63, 0x69, 0x9b, 0x08, 0x07, 0xd0, 0x2a, 0x4b, 0x87, 0x00, 0xcb, 0x51, 
+0x67, 0x69, 0xbf, 0x08, 0x01, 0x30, 0x87, 0x42, 0xf8, 0xd8, 0x24, 0x49, 
+0xc0, 0x46, 0x8a, 0x62, 0x8c, 0x89, 0x58, 0x20, 0x60, 0x43, 0x87, 0x18, 
+0x00, 0x20, 0x00, 0x22, 0x00, 0x2c, 0x0a, 0xdd, 0x58, 0x23, 0x43, 0x43, 
+0x8c, 0x6a, 0xe3, 0x18, 0x01, 0x30, 0x00, 0x04, 0x00, 0x0c, 0x9a, 0x60, 
+0x8b, 0x89, 0x83, 0x42, 0xf4, 0xdc, 0xcf, 0x62, 0xcc, 0x89, 0x60, 0x00, 
+0x00, 0x19, 0x40, 0x01, 0xc7, 0x19, 0x00, 0x20, 0x00, 0x2c, 0x0b, 0xdd, 
+0x43, 0x00, 0x1b, 0x18, 0x5b, 0x01, 0xcc, 0x6a, 0xe3, 0x18, 0x01, 0x30, 
+0x00, 0x04, 0x00, 0x0c, 0x9a, 0x60, 0xcb, 0x89, 0x83, 0x42, 0xf3, 0xdc, 
+0x4f, 0x62, 0x00, 0x20, 0x0b, 0x69, 0x00, 0x2b, 0x07, 0xd9, 0x87, 0x00, 
+0x4b, 0x6a, 0xc0, 0x46, 0xda, 0x51, 0x0b, 0x69, 0x01, 0x30, 0x83, 0x42, 
+0xf7, 0xd8, 0x49, 0x6a, 0x80, 0x00, 0x08, 0x18, 0x04, 0x38, 0x28, 0x61, 
+0xf0, 0xbc, 0x70, 0x47, 0xb8, 0xce, 0x21, 0x40, 0x00, 0x00, 0x18, 0x40, 
+0xe8, 0x0d, 0x00, 0x80, 0x02, 0x99, 0x00, 0x00, 0x00, 0x00, 0x20, 0x40, 
+0xc8, 0x29, 0x00, 0x80, 0x00, 0x00, 0x20, 0x40, 0x00, 0xad, 0xde, 0x00, 
+0x0a, 0x48, 0x01, 0x23, 0x1b, 0x06, 0x41, 0x69, 0x99, 0x43, 0x1a, 0x09, 
+0x41, 0x61, 0xd1, 0x60, 0x00, 0x21, 0xa1, 0x22, 0x52, 0x03, 0x91, 0x61, 
+0x1b, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x41, 0x61, 0x01, 0x20, 0x00, 0x06, 
+0x59, 0x05, 0x08, 0x60, 0x70, 0x47, 0x00, 0x00, 0xe8, 0x0d, 0x00, 0x80, 
+0x80, 0xb4, 0x02, 0x1c, 0x0b, 0x48, 0x1b, 0x23, 0xdb, 0x01, 0xc3, 0x18, 
+0x5a, 0x61, 0x01, 0x23, 0x1b, 0x06, 0x42, 0x69, 0x1a, 0x43, 0x42, 0x61, 
+0x87, 0x69, 0x9f, 0x43, 0x01, 0x23, 0x1b, 0x05, 0x87, 0x61, 0xda, 0x60, 
+0x80, 0x69, 0xc0, 0x46, 0x18, 0x61, 0xa1, 0x20, 0x40, 0x03, 0x81, 0x61, 
+0x80, 0xbc, 0x70, 0x47, 0xe8, 0x0d, 0x00, 0x80, 0x80, 0xb5, 0xff, 0xf7, 
+0xc9, 0xff, 0x00, 0x20, 0x00, 0xf0, 0x20, 0xf8, 0x00, 0x20, 0x09, 0x49, 
+0x00, 0x22, 0x03, 0x01, 0x5f, 0x18, 0x33, 0x23, 0x9b, 0x01, 0xfb, 0x18, 
+0x5a, 0x62, 0x01, 0x30, 0x0b, 0x28, 0xf6, 0xd3, 0x04, 0x48, 0x01, 0x22, 
+0x00, 0x21, 0x00, 0xf0, 0x33, 0xf8, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 
+0xe8, 0x0d, 0x00, 0x80, 0x91, 0x3d, 0xff, 0xff, 0x00, 0xb5, 0x02, 0x48, 
+0x00, 0xf0, 0x04, 0xf8, 0x08, 0xbc, 0x18, 0x47, 0xa8, 0x61, 0x00, 0x00, 
+0x80, 0xb4, 0x01, 0x22, 0x12, 0x05, 0x0f, 0x4b, 0xa1, 0x21, 0x49, 0x03, 
+0x00, 0x28, 0x0e, 0xd0, 0xc8, 0x61, 0x18, 0x1c, 0x59, 0x69, 0x53, 0x01, 
+0x19, 0x43, 0x41, 0x61, 0x87, 0x69, 0x9f, 0x43, 0x87, 0x61, 0xd1, 0x60, 
+0x80, 0x69, 0xc0, 0x46, 0x10, 0x61, 0x80, 0xbc, 0x70, 0x47, 0x18, 0x1c, 
+0x5f, 0x69, 0x01, 0x23, 0x5b, 0x06, 0x9f, 0x43, 0x47, 0x61, 0xd7, 0x60, 
+0x00, 0x20, 0xc8, 0x61, 0xf3, 0xe7, 0x00, 0x00, 0xe8, 0x0d, 0x00, 0x80, 
+0xb0, 0xb4, 0x07, 0x1c, 0x00, 0x20, 0x17, 0x4c, 0x03, 0x01, 0x1d, 0x19, 
+0x33, 0x23, 0x9b, 0x01, 0xeb, 0x18, 0x5d, 0x6a, 0xbd, 0x42, 0x05, 0xd1, 
+0xdd, 0x6a, 0x95, 0x42, 0x02, 0xd1, 0x9b, 0x6a, 0x8b, 0x42, 0x1c, 0xd0, 
+0x01, 0x30, 0x0b, 0x28, 0xee, 0xd3, 0x00, 0x20, 0x03, 0x01, 0x1d, 0x19, 
+0x33, 0x23, 0x9b, 0x01, 0xeb, 0x18, 0x5b, 0x6a, 0x00, 0x2b, 0x09, 0xd1, 
+0x03, 0x01, 0x1c, 0x19, 0x33, 0x23, 0x9b, 0x01, 0xe3, 0x18, 0xda, 0x62, 
+0x99, 0x62, 0x1a, 0x63, 0x5f, 0x62, 0x02, 0xe0, 
+0x01, 0x30, 0x0b, 0x28, 0xea, 0xd3, 0x0b, 0x28, 0x01, 0xd1, 0x00, 0x20, 
+0xc0, 0x43, 0xb0, 0xbc, 0x70, 0x47, 0x00, 0x00, 0xe8, 0x0d, 0x00, 0x80, 
+0x90, 0xb4, 0x01, 0x1c, 0x00, 0x22, 0x01, 0x20, 0x16, 0x4f, 0x01, 0xe0, 
+0x00, 0x2a, 0x07, 0xd1, 0x03, 0x01, 0xdc, 0x19, 0x33, 0x23, 0x9b, 0x01, 
+0xe3, 0x18, 0x5b, 0x69, 0x8b, 0x42, 0x11, 0xd1, 0x02, 0x01, 0xd2, 0x19, 
+0x33, 0x23, 0x9b, 0x01, 0xd2, 0x18, 0x53, 0x6a, 0xc0, 0x46, 0x53, 0x61, 
+0x93, 0x6a, 0xc0, 0x46, 0x93, 0x61, 0xd3, 0x6a, 0xc0, 0x46, 0xd3, 0x61, 
+0x13, 0x6b, 0xc0, 0x46, 0x13, 0x62, 0x01, 0x22, 0x01, 0x30, 0x0b, 0x28, 
+0xe0, 0xd3, 0x07, 0x4b, 0x00, 0x2a, 0x02, 0xd1, 0x5a, 0x68, 0x8a, 0x42, 
+0x03, 0xd1, 0x00, 0x21, 0x59, 0x60, 0x90, 0xbc, 0x70, 0x47, 0x00, 0x20, 
+0xc0, 0x43, 0xfa, 0xe7, 0xe8, 0x0d, 0x00, 0x80, 0x68, 0x1b, 0x00, 0x80, 
+0x0b, 0x28, 0x17, 0xda, 0x0c, 0x49, 0x01, 0x23, 0x5b, 0x06, 0x8a, 0x69, 
+0x13, 0x43, 0x01, 0x22, 0x12, 0x05, 0x8b, 0x61, 0x13, 0x61, 0x00, 0x01, 
+0x40, 0x18, 0x33, 0x23, 0x9b, 0x01, 0xc0, 0x18, 0xc3, 0x6a, 0xc0, 0x46, 
+0x03, 0x63, 0x53, 0x01, 0x88, 0x69, 0x98, 0x43, 0x88, 0x61, 0x10, 0x61, 
+0x01, 0x20, 0x70, 0x47, 0x00, 0x20, 0xfc, 0xe7, 0xe8, 0x0d, 0x00, 0x80, 
+0x90, 0xb4, 0x08, 0x4a, 0xd0, 0x69, 0x00, 0x21, 0x07, 0x4f, 0xd3, 0x69, 
+0x83, 0x42, 0x02, 0xd9, 0xfc, 0x1a, 0x20, 0x18, 0x00, 0xe0, 0xc0, 0x1a, 
+0x09, 0x18, 0x18, 0x1c, 0xb9, 0x42, 0xf4, 0xd9, 0x90, 0xbc, 0x70, 0x47, 
+0x00, 0x20, 0x14, 0x40, 0xa8, 0x61, 0x00, 0x00, 0x43, 0x1a, 0x93, 0x42, 
+0x30, 0xd3, 0x84, 0x46, 0x8b, 0x07, 0x07, 0xd0, 0x52, 0x1e, 0x29, 0xd3, 
+0x0b, 0x78, 0x03, 0x70, 0x40, 0x1c, 0x49, 0x1c, 0x8b, 0x07, 0xf7, 0xd1, 
+0x83, 0x07, 0x17, 0xd1, 0x10, 0x3a, 0x05, 0xd3, 0xb0, 0xb4, 0xb8, 0xc9, 
+0xb8, 0xc0, 0x10, 0x3a, 0xfb, 0xd2, 0xb0, 0xbc, 0x0c, 0x32, 0x0f, 0xd3, 
+0x08, 0xc9, 0x08, 0xc0, 0x12, 0x1f, 0xfb, 0xd2, 0x0a, 0xe0, 0x08, 0xc9, 
+0x03, 0x70, 0x1b, 0x0a, 0x43, 0x70, 0x1b, 0x0a, 0x83, 0x70, 0x1b, 0x0a, 
+0xc3, 0x70, 0x00, 0x1d, 0x12, 0x1f, 0xf4, 0xd2, 0xd2, 0x1c, 0x05, 0xd3, 
+0x0b, 0x78, 0x03, 0x70, 0x49, 0x1c, 0x40, 0x1c, 0x52, 0x1e, 0xf9, 0xd2, 
+0x60, 0x46, 0x70, 0x47, 0x03, 0x1c, 0x0b, 0x43, 0x13, 0x43, 0x9b, 0x07, 
+0x04, 0xd1, 0x12, 0x1f, 0x8b, 0x58, 0x83, 0x50, 0xfb, 0xd1, 0x70, 0x47, 
+0x52, 0x1e, 0x8b, 0x5c, 0x83, 0x54, 0xfb, 0xd1, 0x70, 0x47, 0x00, 0x00, 
+0x00, 0x20, 0x70, 0x47, 
+};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/typhoon.c linux-2.4.21-pre6/drivers/net/typhoon.c
--- linux-2.4.20/drivers/net/typhoon.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/typhoon.c	2003-03-26 23:49:19.000000000 +0000
@@ -0,0 +1,2505 @@
+/* typhoon.c: A Linux Ethernet device driver for 3Com 3CR990 family of NICs */
+/*
+	Written 2002-2003 by David Dillow <dave@thedillows.org>
+	Based on code written 1998-2000 by Donald Becker <becker@scyld.com> and
+	Linux 2.2.x driver by David P. McLean <davidpmclean@yahoo.com>.
+
+	This software may be used and distributed according to the terms of
+	the GNU General Public License (GPL), incorporated herein by reference.
+	Drivers based on or derived from this code fall under the GPL and must
+	retain the authorship, copyright and license notice.  This file is not
+	a complete program and may only be used when the entire operating
+	system is licensed under the GPL.
+
+	This software is available on a public web site. It may enable
+	cryptographic capabilities of the 3Com hardware, and may be
+	exported from the United States under License Exception "TSU"
+	pursuant to 15 C.F.R. Section 740.13(e).
+
+	This work was funded by the National Library of Medicine under
+	the Department of Energy project number 0274DD06D1 and NLM project
+	number Y1-LM-2015-01.
+
+	This driver is designed for the 3Com 3CR990 Family of cards with the
+	3XP Processor. It has been tested on x86 and sparc64.
+
+	KNOWN ISSUES:
+	*) The current firmware always strips the VLAN tag off, even if
+		we tell it not to. You should filter VLANs at the switch
+		as a workaround (good practice in any event) until we can
+		get this fixed.
+	*) Cannot DMA Rx packets to a 2 byte aligned address. Also firmware
+		issue. Hopefully 3Com will fix it.
+	*) Waiting for a command response takes 8ms due to non-preemptable
+		polling. Only significant for getting stats and creating
+		SAs, but an ugly wart never the less.
+	*) I've not tested multicast. I think it works, but reports welcome.
+	*) Doesn't do IPSEC offloading. Yet. Keep yer pants on, it's coming.
+*/
+
+/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
+ * Setting to > 1518 effectively disables this feature.
+ */
+static int rx_copybreak = 0;
+
+/* end user-configurable values */
+
+/* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
+ */
+static const int multicast_filter_limit = 32;
+
+/* Operational parameters that are set at compile time. */
+
+/* Keep the ring sizes a power of two for compile efficiency.
+ * The compiler will convert <unsigned>'%'<2^N> into a bit mask.
+ * Making the Tx ring too large decreases the effectiveness of channel
+ * bonding and packet priority.
+ * There are no ill effects from too-large receive rings.
+ *
+ * We don't currently use the Hi Tx ring so, don't make it very big.
+ *
+ * Beware that if we start using the Hi Tx ring, we will need to change
+ * typhoon_num_free_tx() and typhoon_tx_complete() to account for that.
+ */
+#define TXHI_ENTRIES		2
+#define TXLO_ENTRIES		128
+#define RX_ENTRIES		32
+#define COMMAND_ENTRIES		16
+#define RESPONSE_ENTRIES	32
+
+#define COMMAND_RING_SIZE	(COMMAND_ENTRIES * sizeof(struct cmd_desc))
+#define RESPONSE_RING_SIZE	(RESPONSE_ENTRIES * sizeof(struct resp_desc))
+
+/* The 3XP will preload and remove 64 entries from the free buffer
+ * list, and we need one entry to keep the ring from wrapping, so 
+ * to keep this a power of two, we use 128 entries.
+ */
+#define RXFREE_ENTRIES		128
+#define RXENT_ENTRIES		(RXFREE_ENTRIES - 1)
+
+/* Operational parameters that usually are not changed. */
+
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT  (2*HZ)
+
+#define PKT_BUF_SZ		1536
+
+#define DRV_MODULE_NAME		"typhoon"
+#define DRV_MODULE_VERSION 	"1.0"
+#define DRV_MODULE_RELDATE	"03/02/14"
+#define PFX			DRV_MODULE_NAME ": "
+#define ERR_PFX			KERN_ERR PFX
+
+#if !defined(__OPTIMIZE__)  ||  !defined(__KERNEL__)
+#warning  You must compile this file with the correct options!
+#warning  See the last lines of the source file.
+#error  You must compile this driver with "-O".
+#endif
+
+#include <linux/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 <linux/delay.h>
+#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
+#include <linux/crc32.h>
+#include <asm/processor.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/in6.h>
+#include <asm/checksum.h>
+#include <linux/version.h>
+
+#include "typhoon.h"
+#include "typhoon-firmware.h"
+
+static char version[] __devinitdata =
+    "typhoon.c: version " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
+
+MODULE_AUTHOR("David Dillow <dillowd@y12.doe.gov>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("3Com Typhoon Family (3C990, 3CR990, and variants)");
+MODULE_PARM(rx_copybreak, "i");
+
+#if defined(NETIF_F_TSO) && MAX_SKB_FRAGS > 32
+#warning Typhoon only supports 32 entries in its SG list for TSO, disabling TSO
+#undef NETIF_F_TSO
+#endif
+
+#if TXLO_ENTRIES <= (2 * MAX_SKB_FRAGS)
+#error TX ring too small!
+#endif
+
+struct typhoon_card_info {
+	char *name;
+	int capabilities;
+};
+
+#define TYPHOON_CRYPTO_NONE		0
+#define TYPHOON_CRYPTO_DES		1
+#define TYPHOON_CRYPTO_3DES		2
+#define	TYPHOON_CRYPTO_VARIABLE		4
+#define TYPHOON_FIBER			5
+
+enum typhoon_cards {
+	TYPHOON_TX = 0, TYPHOON_TX95, TYPHOON_TX97, TYPHOON_SVR,
+	TYPHOON_SVR95, TYPHOON_SVR97, TYPHOON_TXM, TYPHOON_BSVR,
+	TYPHOON_FX95, TYPHOON_FX97, TYPHOON_FX95SVR, TYPHOON_FX97SVR,
+};
+
+/* directly indexed by enum typhoon_cards, above */
+static struct typhoon_card_info typhoon_card_info[] __devinitdata = {
+	{ "3Com Typhoon (3C990-TX)",
+		TYPHOON_CRYPTO_NONE},
+	{ "3Com Typhoon (3CR990-TX-95)",
+		TYPHOON_CRYPTO_DES},
+	{ "3Com Typhoon (3CR990-TX-97)",
+	 	TYPHOON_CRYPTO_DES | TYPHOON_CRYPTO_3DES},
+	{ "3Com Typhoon (3C990SVR)",
+		TYPHOON_CRYPTO_NONE},
+	{ "3Com Typhoon (3CR990SVR95)",
+		TYPHOON_CRYPTO_DES},
+	{ "3Com Typhoon (3CR990SVR97)",
+	 	TYPHOON_CRYPTO_DES | TYPHOON_CRYPTO_3DES},
+	{ "3Com Typhoon2 (3C990B-TX-M)",
+		TYPHOON_CRYPTO_VARIABLE},
+	{ "3Com Typhoon2 (3C990BSVR)",
+		TYPHOON_CRYPTO_VARIABLE},
+	{ "3Com Typhoon (3CR990-FX-95)",
+		TYPHOON_CRYPTO_DES | TYPHOON_FIBER},
+	{ "3Com Typhoon (3CR990-FX-97)",
+	 	TYPHOON_CRYPTO_DES | TYPHOON_CRYPTO_3DES | TYPHOON_FIBER},
+	{ "3Com Typhoon (3CR990-FX-95 Server)",
+	 	TYPHOON_CRYPTO_DES | TYPHOON_FIBER},
+	{ "3Com Typhoon (3CR990-FX-97 Server)",
+	 	TYPHOON_CRYPTO_DES | TYPHOON_CRYPTO_3DES | TYPHOON_FIBER},
+};
+
+/* Notes on the new subsystem numbering scheme:
+ * bits 0-1 indicate crypto capabilites: (0) variable, (1) DES, or (2) 3DES
+ * bit 4 indicates if this card has secured firmware (we don't support it)
+ * bit 8 indicates if this is a (0) copper or (1) fiber card
+ * bits 12-16 indicate card type: (0) client and (1) server
+ */
+static struct pci_device_id typhoon_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0,TYPHOON_TX },
+	{ PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990_TX_95,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPHOON_TX95 },
+	{ PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990_TX_97,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPHOON_TX97 },
+	{ PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990B,
+	  PCI_ANY_ID, 0x1000, 0, 0, TYPHOON_TXM },
+	{ PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990B,
+	  PCI_ANY_ID, 0x2000, 0, 0, TYPHOON_BSVR },
+	{ PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990_FX,
+	  PCI_ANY_ID, 0x1101, 0, 0, TYPHOON_FX95 },
+	{ PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990_FX,
+	  PCI_ANY_ID, 0x1102, 0, 0, TYPHOON_FX97 },
+	{ PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990_FX,
+	  PCI_ANY_ID, 0x2101, 0, 0, TYPHOON_FX95SVR },
+	{ PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990_FX,
+	  PCI_ANY_ID, 0x2102, 0, 0, TYPHOON_FX97SVR },
+	{ PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990SVR95,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPHOON_SVR95 },
+	{ PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990SVR97,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPHOON_SVR97 },
+	{ PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990SVR,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPHOON_SVR },
+	{ 0, }
+};
+MODULE_DEVICE_TABLE(pci, typhoon_pci_tbl);
+
+/* Define the shared memory area
+ * Align everything the 3XP will normally be using.
+ * We'll need to move/align txHi if we start using that ring.
+ */
+#define __3xp_aligned	____cacheline_aligned
+struct typhoon_shared {
+	struct typhoon_interface	iface;
+	struct typhoon_indexes		indexes			__3xp_aligned;
+	struct tx_desc			txLo[TXLO_ENTRIES] 	__3xp_aligned;
+	struct rx_desc			rxLo[RX_ENTRIES]	__3xp_aligned;
+	struct rx_desc			rxHi[RX_ENTRIES]	__3xp_aligned;
+	struct cmd_desc			cmd[COMMAND_ENTRIES]	__3xp_aligned;
+	struct resp_desc		resp[RESPONSE_ENTRIES]	__3xp_aligned;
+	struct rx_free			rxBuff[RXFREE_ENTRIES]	__3xp_aligned;
+	u32				zeroWord;
+	struct tx_desc			txHi[TXHI_ENTRIES];
+} __attribute__ ((packed));
+
+struct rxbuff_ent {
+	struct sk_buff *skb;
+	dma_addr_t	dma_addr;
+};
+
+struct typhoon {
+	/* Tx cache line section */
+	struct transmit_ring 	txLoRing	____cacheline_aligned;	
+	struct pci_dev *	tx_pdev;
+	unsigned long		tx_ioaddr;
+	u32			txlo_dma_addr;
+
+	/* Irq/Rx cache line section */
+	unsigned long		ioaddr		____cacheline_aligned;
+	struct typhoon_indexes *indexes;
+	u8			awaiting_resp;
+	u8			duplex;
+	u8			speed;
+	u8			card_state;
+	struct basic_ring	rxLoRing;
+	struct pci_dev *	pdev;
+	struct net_device *	dev;
+	spinlock_t		state_lock;
+	struct vlan_group *	vlgrp;
+	struct basic_ring	rxHiRing;
+	struct basic_ring	rxBuffRing;
+	struct rxbuff_ent	rxbuffers[RXENT_ENTRIES];
+
+	/* general section */
+	spinlock_t		command_lock	____cacheline_aligned;
+	struct basic_ring	cmdRing;
+	struct basic_ring	respRing;
+	struct net_device_stats	stats;
+	struct net_device_stats	stats_saved;
+	const char *		name;
+	struct typhoon_shared *	shared;
+	dma_addr_t		shared_dma;
+	u16			xcvr_select;
+	u16			wol_events;
+	u32			offload;
+	u32			pci_state[16];
+
+	/* unused stuff (future use) */
+	int			capabilities;
+	struct transmit_ring 	txHiRing;
+};
+
+enum completion_wait_values {
+	NoWait = 0, WaitNoSleep, WaitSleep,
+};
+
+/* These are the values for the typhoon.card_state variable.
+ * These determine where the statistics will come from in get_stats().
+ * The sleep image does not support the statistics we need.
+ */
+enum state_values {
+	Sleeping = 0, Running,
+};
+
+/* PCI writes are not guaranteed to be posted in order, but outstanding writes
+ * cannot pass a read, so this forces current writes to post.
+ */
+#define typhoon_post_pci_writes(x) \
+	do { readl(x + TYPHOON_REG_HEARTBEAT); } while(0)
+
+/* We'll wait up to six seconds for a reset, and half a second normally.
+ */
+#define TYPHOON_UDELAY			50
+#define TYPHOON_RESET_TIMEOUT		(6 * HZ)
+#define TYPHOON_WAIT_TIMEOUT		((1000000 / 2) / TYPHOON_UDELAY)
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 28)
+#define typhoon_synchronize_irq(x) synchronize_irq()
+#else
+#define typhoon_synchronize_irq(x) synchronize_irq(x)
+#endif
+
+#if defined(NETIF_F_TSO)
+#define skb_tso_size(x)		(skb_shinfo(x)->tso_size)
+#define TSO_NUM_DESCRIPTORS	2
+#define TSO_OFFLOAD_ON		TYPHOON_OFFLOAD_TCP_SEGMENT
+#else
+#define NETIF_F_TSO 		0
+#define skb_tso_size(x) 	0
+#define TSO_NUM_DESCRIPTORS	0
+#define TSO_OFFLOAD_ON		0
+#endif
+
+static inline void
+typhoon_inc_index(u32 *index, const int count, const int num_entries)
+{
+	/* Increment a ring index -- we can use this for all rings execept
+	 * the Rx rings, as they use different size descriptors
+	 * otherwise, everything is the same size as a cmd_desc
+	 */
+	*index += count * sizeof(struct cmd_desc);
+	*index %= num_entries * sizeof(struct cmd_desc);
+}
+
+static inline void
+typhoon_inc_cmd_index(u32 *index, const int count)
+{
+	typhoon_inc_index(index, count, COMMAND_ENTRIES);
+}
+
+static inline void
+typhoon_inc_resp_index(u32 *index, const int count)
+{
+	typhoon_inc_index(index, count, RESPONSE_ENTRIES);
+}
+
+static inline void
+typhoon_inc_rxfree_index(u32 *index, const int count)
+{
+	typhoon_inc_index(index, count, RXFREE_ENTRIES);
+}
+
+static inline void
+typhoon_inc_tx_index(u32 *index, const int count)
+{
+	/* if we start using the Hi Tx ring, this needs updateing */
+	typhoon_inc_index(index, count, TXLO_ENTRIES);
+}
+
+static inline void
+typhoon_inc_rx_index(u32 *index, const int count)
+{
+	/* sizeof(struct rx_desc) != sizeof(struct cmd_desc) */
+	*index += count * sizeof(struct rx_desc);
+	*index %= RX_ENTRIES * sizeof(struct rx_desc);
+}
+
+static int
+typhoon_reset(unsigned long ioaddr, int wait_type)
+{
+	int i, err = 0;
+	int timeout = TYPHOON_RESET_TIMEOUT;
+
+	if(wait_type == WaitNoSleep)
+		timeout = (timeout * 1000000) / (HZ * TYPHOON_UDELAY);
+
+	writel(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_MASK);
+	writel(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_STATUS);
+
+	writel(TYPHOON_RESET_ALL, ioaddr + TYPHOON_REG_SOFT_RESET);
+	typhoon_post_pci_writes(ioaddr);
+	udelay(1);
+	writel(TYPHOON_RESET_NONE, ioaddr + TYPHOON_REG_SOFT_RESET);
+
+	if(wait_type != NoWait) {
+		for(i = 0; i < timeout; i++) {
+			if(readl(ioaddr + TYPHOON_REG_STATUS) ==
+			   TYPHOON_STATUS_WAITING_FOR_HOST)
+				goto out;
+
+			if(wait_type == WaitSleep) {
+				set_current_state(TASK_UNINTERRUPTIBLE);
+				schedule_timeout(1);
+			} else
+				udelay(TYPHOON_UDELAY);
+		}
+
+		err = -ETIMEDOUT;
+	}
+
+out:
+	writel(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_MASK);
+	writel(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_STATUS);
+	udelay(100);
+	return err;
+
+	/* The 3XP seems to need a little extra time to complete the load
+	 * of the sleep image before we can reliably boot it. Failure to
+	 * do this occasionally results in a hung adapter after boot in
+	 * typhoon_init_one() while trying to read the MAC address or
+	 * putting the card to sleep. 3Com's driver waits 5ms, but
+	 * that seems to be overkill -- with a 50usec delay, it survives
+	 * 35000 typhoon_init_one() calls, where it only make it 25-100
+	 * without it.
+	 *
+	 * As it turns out, still occasionally getting a hung adapter,
+	 * so I'm bumping it to 100us.
+	 */
+}
+
+static int
+typhoon_wait_status(unsigned long ioaddr, u32 wait_value)
+{
+	int i, err = 0;
+
+	for(i = 0; i < TYPHOON_WAIT_TIMEOUT; i++) {
+		if(readl(ioaddr + TYPHOON_REG_STATUS) == wait_value)
+			goto out;
+		udelay(TYPHOON_UDELAY);
+	}
+
+	err = -ETIMEDOUT;
+
+out:
+	return err;
+}
+
+static inline void
+typhoon_media_status(struct net_device *dev, struct resp_desc *resp)
+{
+	if(resp->parm1 & TYPHOON_MEDIA_STAT_NO_LINK)
+		netif_carrier_off(dev);
+	else
+		netif_carrier_on(dev);
+}
+
+static inline void
+typhoon_hello(struct typhoon *tp)
+{
+	struct basic_ring *ring = &tp->cmdRing;
+	struct cmd_desc *cmd;
+
+	/* We only get a hello request if we've not sent anything to the
+	 * card in a long while. If the lock is held, then we're in the
+	 * process of issuing a command, so we don't need to respond.
+	 */
+	if(spin_trylock(&tp->command_lock)) {
+		cmd = (struct cmd_desc *)(ring->ringBase + ring->lastWrite);
+		typhoon_inc_cmd_index(&ring->lastWrite, 1);
+
+		INIT_COMMAND_NO_RESPONSE(cmd, TYPHOON_CMD_HELLO_RESP);
+		smp_wmb();
+		writel(ring->lastWrite, tp->ioaddr + TYPHOON_REG_CMD_READY);
+		spin_unlock(&tp->command_lock);
+	}
+}
+
+static int
+typhoon_process_response(struct typhoon *tp, int resp_size,
+				struct resp_desc *resp_save)
+{
+	struct typhoon_indexes *indexes = tp->indexes;
+	struct resp_desc *resp;
+	u8 *base = tp->respRing.ringBase;
+	int count, len, wrap_len;
+	u32 cleared;
+	u32 ready;
+
+	cleared = le32_to_cpu(indexes->respCleared);
+	ready = le32_to_cpu(indexes->respReady);
+	while(cleared != ready) {
+		resp = (struct resp_desc *)(base + cleared);
+		count = resp->numDesc + 1;
+		if(resp_save && resp->seqNo) {
+			if(count > resp_size) {
+				resp_save->flags = TYPHOON_RESP_ERROR;
+				goto cleanup;
+			}
+
+			wrap_len = 0;
+			len = count * sizeof(*resp);
+			if(unlikely(cleared + len > RESPONSE_RING_SIZE)) {
+				wrap_len = cleared + len - RESPONSE_RING_SIZE;
+				len = RESPONSE_RING_SIZE - cleared;
+			}
+
+			memcpy(resp_save, resp, len);
+			if(unlikely(wrap_len)) {
+				resp_save += len / sizeof(*resp);
+				memcpy(resp_save, base, wrap_len);
+			}
+
+			resp_save = NULL;
+		} else if(resp->cmd == TYPHOON_CMD_READ_MEDIA_STATUS) {
+			typhoon_media_status(tp->dev, resp);
+		} else if(resp->cmd == TYPHOON_CMD_HELLO_RESP) {
+			typhoon_hello(tp);
+		} else {
+			printk(KERN_ERR "%s: dumping unexpected response "
+			       "0x%04x:%d:0x%02x:0x%04x:%08x:%08x\n",
+			       tp->name, le16_to_cpu(resp->cmd),
+			       resp->numDesc, resp->flags,
+			       le16_to_cpu(resp->parm1),
+			       le32_to_cpu(resp->parm2),
+			       le32_to_cpu(resp->parm3));
+		}
+
+cleanup:
+		typhoon_inc_resp_index(&cleared, count);
+	}
+
+	indexes->respCleared = cpu_to_le32(cleared);
+	wmb();
+	return (resp_save == NULL);
+}
+
+static inline int
+typhoon_num_free(int lastWrite, int lastRead, int ringSize)
+{
+	/* this works for all descriptors but rx_desc, as they are a
+	 * different size than the cmd_desc -- everyone else is the same
+	 */
+	lastWrite /= sizeof(struct cmd_desc);
+	lastRead /= sizeof(struct cmd_desc);
+	return (ringSize + lastRead - lastWrite - 1) % ringSize;
+}
+
+static inline int
+typhoon_num_free_cmd(struct typhoon *tp)
+{
+	int lastWrite = tp->cmdRing.lastWrite;
+	int cmdCleared = le32_to_cpu(tp->indexes->cmdCleared);
+
+	return typhoon_num_free(lastWrite, cmdCleared, COMMAND_ENTRIES);
+}
+
+static inline int
+typhoon_num_free_resp(struct typhoon *tp)
+{
+	int respReady = le32_to_cpu(tp->indexes->respReady);
+	int respCleared = le32_to_cpu(tp->indexes->respCleared);
+
+	return typhoon_num_free(respReady, respCleared, RESPONSE_ENTRIES);
+}
+
+static inline int
+typhoon_num_free_tx(struct transmit_ring *ring)
+{
+	/* if we start using the Hi Tx ring, this needs updating */
+	return typhoon_num_free(ring->lastWrite, ring->lastRead, TXLO_ENTRIES);
+}
+
+static int
+typhoon_issue_command(struct typhoon *tp, int num_cmd, struct cmd_desc *cmd,
+		      int num_resp, struct resp_desc *resp)
+{
+	struct typhoon_indexes *indexes = tp->indexes;
+	struct basic_ring *ring = &tp->cmdRing;
+	struct resp_desc local_resp;
+	int i, err = 0;
+	int got_resp;
+	int freeCmd, freeResp;
+	int len, wrap_len;
+
+	spin_lock(&tp->command_lock);
+
+	freeCmd = typhoon_num_free_cmd(tp);
+	freeResp = typhoon_num_free_resp(tp);
+
+	if(freeCmd < num_cmd || freeResp < num_resp) {
+		printk("%s: no descs for cmd, had (needed) %d (%d) cmd, "
+			"%d (%d) resp\n", tp->name, freeCmd, num_cmd,
+			freeResp, num_resp);
+		err = -ENOMEM;
+		goto out;
+	}
+
+	if(cmd->flags & TYPHOON_CMD_RESPOND) {
+		/* If we're expecting a response, but the caller hasn't given
+		 * us a place to put it, we'll provide one.
+		 */
+		tp->awaiting_resp = 1;
+		if(resp == NULL) {
+			resp = &local_resp;
+			num_resp = 1;
+		}
+	}
+
+	wrap_len = 0;
+	len = num_cmd * sizeof(*cmd);
+	if(unlikely(ring->lastWrite + len > COMMAND_RING_SIZE)) {
+		wrap_len = ring->lastWrite + len - COMMAND_RING_SIZE;
+		len = COMMAND_RING_SIZE - ring->lastWrite;
+	}
+
+	memcpy(ring->ringBase + ring->lastWrite, cmd, len);
+	if(unlikely(wrap_len)) {
+		struct cmd_desc *wrap_ptr = cmd;
+		wrap_ptr += len / sizeof(*cmd);
+		memcpy(ring->ringBase, wrap_ptr, wrap_len);
+	}
+
+	typhoon_inc_cmd_index(&ring->lastWrite, num_cmd);
+
+	/* "I feel a presence... another warrior is on the the mesa."
+	 */
+	wmb();
+	writel(ring->lastWrite, tp->ioaddr + TYPHOON_REG_CMD_READY);
+	typhoon_post_pci_writes(tp->ioaddr);
+
+	if((cmd->flags & TYPHOON_CMD_RESPOND) == 0)
+		goto out;
+
+	/* Ugh. We'll be here about 8ms, spinning our thumbs, unable to
+	 * preempt or do anything other than take interrupts. So, don't
+	 * wait for a response unless you have to.
+	 *
+	 * I've thought about trying to sleep here, but we're called
+	 * from many contexts that don't allow that. Also, given the way
+	 * 3Com has implemented irq coalescing, we would likely timeout --
+	 * this has been observed in real life!
+	 *
+	 * The big killer is we have to wait to get stats from the card,
+	 * though we could go to a periodic refresh of those if we don't
+	 * mind them getting somewhat stale. The rest of the waiting
+	 * commands occur during open/close/suspend/resume, so they aren't
+	 * time critical. Creating SAs in the future will also have to
+	 * wait here.
+	 */
+	got_resp = 0;
+	for(i = 0; i < TYPHOON_WAIT_TIMEOUT && !got_resp; i++) {
+		if(indexes->respCleared != indexes->respReady)
+			got_resp = typhoon_process_response(tp, num_resp,
+								resp);
+		udelay(TYPHOON_UDELAY);
+	}
+
+	if(!got_resp) {
+		err = -ETIMEDOUT;
+		goto out;
+	}
+
+	/* Collect the error response even if we don't care about the
+	 * rest of the response
+	 */
+	if(resp->flags & TYPHOON_RESP_ERROR)
+		err = -EIO;
+
+out:
+	if(tp->awaiting_resp) {
+		tp->awaiting_resp = 0;
+		smp_wmb();
+
+		/* Ugh. If a response was added to the ring between
+		 * the call to typhoon_process_response() and the clearing
+		 * of tp->awaiting_resp, we could have missed the interrupt
+		 * and it could hang in the ring an indeterminate amount of
+		 * time. So, check for it, and interrupt ourselves if this
+		 * is the case.
+		 */
+		if(indexes->respCleared != indexes->respReady)
+			writel(1, tp->ioaddr + TYPHOON_REG_SELF_INTERRUPT);
+	}
+
+	spin_unlock(&tp->command_lock);
+	return err;
+}
+
+static void
+typhoon_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
+{
+	struct typhoon *tp = (struct typhoon *) dev->priv;
+	struct cmd_desc xp_cmd;
+	int err;
+
+	spin_lock_bh(&tp->state_lock);
+	if(!tp->vlgrp != !grp) {
+		/* We've either been turned on for the first time, or we've
+		 * been turned off. Update the 3XP.
+		 */
+		if(grp)
+			tp->offload |= TYPHOON_OFFLOAD_VLAN;
+		else
+			tp->offload &= ~TYPHOON_OFFLOAD_VLAN;
+
+		/* If the interface is up, the runtime is running -- and we
+		 * must be up for the vlan core to call us.
+		 *
+		 * Do the command outside of the spin lock, as it is slow.
+		 */
+		INIT_COMMAND_WITH_RESPONSE(&xp_cmd,
+					TYPHOON_CMD_SET_OFFLOAD_TASKS);
+		xp_cmd.parm2 = tp->offload;
+		xp_cmd.parm3 = tp->offload;
+		spin_unlock_bh(&tp->state_lock);
+		err = typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
+		if(err < 0)
+			printk("%s: vlan offload error %d\n", tp->name, -err);
+		spin_lock_bh(&tp->state_lock);
+	}
+
+	/* now make the change visible */
+	tp->vlgrp = grp;
+	spin_unlock_bh(&tp->state_lock);
+}
+
+static void
+typhoon_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
+{
+	struct typhoon *tp = (struct typhoon *) dev->priv;
+	spin_lock_bh(&tp->state_lock);
+	if(tp->vlgrp)
+		tp->vlgrp->vlan_devices[vid] = NULL;
+	spin_unlock_bh(&tp->state_lock);
+}
+
+static inline void
+typhoon_tso_fill(struct sk_buff *skb, struct transmit_ring *txRing,
+			u32 ring_dma)
+{
+	struct tcpopt_desc *tcpd;
+	u32 tcpd_offset = ring_dma;
+
+	tcpd = (struct tcpopt_desc *) (txRing->ringBase + txRing->lastWrite);
+	tcpd_offset += txRing->lastWrite;
+	tcpd_offset += offsetof(struct tcpopt_desc, bytesTx);
+	typhoon_inc_tx_index(&txRing->lastWrite, 1);
+
+	tcpd->flags = TYPHOON_OPT_DESC | TYPHOON_OPT_TCP_SEG;
+	tcpd->numDesc = 1;
+	tcpd->mss_flags = cpu_to_le16(skb_tso_size(skb));
+	tcpd->mss_flags |= TYPHOON_TSO_FIRST | TYPHOON_TSO_LAST;
+	tcpd->respAddrLo = cpu_to_le32(tcpd_offset);
+	tcpd->bytesTx = cpu_to_le32(skb->len);
+	tcpd->status = 0;
+}
+
+static int
+typhoon_start_tx(struct sk_buff *skb, struct net_device *dev)
+{
+	struct typhoon *tp = (struct typhoon *) dev->priv;
+	struct transmit_ring *txRing;
+	struct tx_desc *txd, *first_txd;
+	dma_addr_t skb_dma;
+	int numDesc;
+
+	/* we have two rings to choose from, but we only use txLo for now
+	 * If we start using the Hi ring as well, we'll need to update
+	 * typhoon_stop_runtime(), typhoon_interrupt(), typhoon_num_free_tx(),
+	 * and TXHI_ENTIRES to match, as well as update the TSO code below
+	 * to get the right DMA address
+	 */
+	txRing = &tp->txLoRing;
+
+	/* We need one descriptor for each fragment of the sk_buff, plus the
+	 * one for the ->data area of it.
+	 *
+	 * The docs say a maximum of 16 fragment descriptors per TCP option
+	 * descriptor, then make a new packet descriptor and option descriptor
+	 * for the next 16 fragments. The engineers say just an option
+	 * descriptor is needed. I've tested up to 26 fragments with a single
+	 * packet descriptor/option descriptor combo, so I use that for now.
+	 *
+	 * If problems develop with TSO, check this first.
+	 */
+	numDesc = skb_shinfo(skb)->nr_frags + 1;
+	if(skb_tso_size(skb))
+		numDesc++;
+
+	/* When checking for free space in the ring, we need to also
+	 * account for the initial Tx descriptor, and we always must leave
+	 * at least one descriptor unused in the ring so that it doesn't
+	 * wrap and look empty.
+	 *
+	 * The only time we should loop here is when we hit the race
+	 * between marking the queue awake and updating the cleared index.
+	 * Just loop and it will appear. This comes from the acenic driver.
+	 */
+	while(unlikely(typhoon_num_free_tx(txRing) < (numDesc + 2)))
+		smp_rmb();
+
+	first_txd = (struct tx_desc *) (txRing->ringBase + txRing->lastWrite);
+	typhoon_inc_tx_index(&txRing->lastWrite, 1);
+
+	first_txd->flags = TYPHOON_TX_DESC | TYPHOON_DESC_VALID;
+	first_txd->numDesc = 0;
+	first_txd->len = 0;
+	first_txd->addr = (u64)((unsigned long) skb) & 0xffffffff;
+	first_txd->addrHi = (u64)((unsigned long) skb) >> 32;
+	first_txd->processFlags = 0;
+
+	if(skb->ip_summed == CHECKSUM_HW) {
+		/* The 3XP will figure out if this is UDP/TCP */
+		first_txd->processFlags |= TYPHOON_TX_PF_TCP_CHKSUM;
+		first_txd->processFlags |= TYPHOON_TX_PF_UDP_CHKSUM;
+		first_txd->processFlags |= TYPHOON_TX_PF_IP_CHKSUM;
+	}
+
+	if(vlan_tx_tag_present(skb)) {
+		first_txd->processFlags |=
+		    TYPHOON_TX_PF_INSERT_VLAN | TYPHOON_TX_PF_VLAN_PRIORITY;
+		first_txd->processFlags |=
+		    cpu_to_le32(htons(vlan_tx_tag_get(skb)) <<
+				TYPHOON_TX_PF_VLAN_TAG_SHIFT);
+	}
+
+	if(skb_tso_size(skb)) {
+		first_txd->processFlags |= TYPHOON_TX_PF_TCP_SEGMENT;
+		first_txd->numDesc++;
+
+		typhoon_tso_fill(skb, txRing, tp->txlo_dma_addr);
+	}
+
+	txd = (struct tx_desc *) (txRing->ringBase + txRing->lastWrite);
+	typhoon_inc_tx_index(&txRing->lastWrite, 1);
+
+	/* No need to worry about padding packet -- the firmware pads
+	 * it with zeros to ETH_ZLEN for us.
+	 */
+	if(skb_shinfo(skb)->nr_frags == 0) {
+		skb_dma = pci_map_single(tp->tx_pdev, skb->data, skb->len,
+				       PCI_DMA_TODEVICE);
+		txd->flags = TYPHOON_FRAG_DESC | TYPHOON_DESC_VALID;
+		txd->len = cpu_to_le16(skb->len);
+		txd->addr = cpu_to_le32(skb_dma);
+		txd->addrHi = 0;
+		first_txd->numDesc++;
+	} else {
+		int i, len;
+
+		len = skb->len - skb->data_len;
+		skb_dma = pci_map_single(tp->tx_pdev, skb->data, len,
+				         PCI_DMA_TODEVICE);
+		txd->flags = TYPHOON_FRAG_DESC | TYPHOON_DESC_VALID;
+		txd->len = cpu_to_le16(len);
+		txd->addr = cpu_to_le32(skb_dma);
+		txd->addrHi = 0;
+		first_txd->numDesc++;
+
+		for(i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+			skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+			void *frag_addr;
+
+			txd = (struct tx_desc *) (txRing->ringBase +
+						txRing->lastWrite);
+			typhoon_inc_tx_index(&txRing->lastWrite, 1);
+
+			len = frag->size;
+			frag_addr = (void *) page_address(frag->page) +
+						frag->page_offset;
+			skb_dma = pci_map_single(tp->tx_pdev, frag_addr, len,
+					 PCI_DMA_TODEVICE);
+			txd->flags = TYPHOON_FRAG_DESC | TYPHOON_DESC_VALID;
+			txd->len = cpu_to_le16(len);
+			txd->addr = cpu_to_le32(skb_dma);
+			txd->addrHi = 0;
+			first_txd->numDesc++;
+		}
+	}
+
+	/* Kick the 3XP
+	 */
+	wmb();
+	writel(txRing->lastWrite, tp->tx_ioaddr + txRing->writeRegister);
+
+	dev->trans_start = jiffies;
+
+	/* If we don't have room to put the worst case packet on the
+	 * queue, then we must stop the queue. We need 2 extra
+	 * descriptors -- one to prevent ring wrap, and one for the
+	 * Tx header.
+	 */
+	numDesc = MAX_SKB_FRAGS + TSO_NUM_DESCRIPTORS + 1;
+
+	if(typhoon_num_free_tx(txRing) < (numDesc + 2)) {
+		netif_stop_queue(dev);
+
+		/* A Tx complete IRQ could have gotten inbetween, making
+		 * the ring free again. Only need to recheck here, since
+		 * Tx is serialized.
+		 */
+		if(typhoon_num_free_tx(txRing) >= (numDesc + 2))
+			netif_wake_queue(dev);
+	}
+
+	return 0;
+}
+
+static void
+typhoon_set_rx_mode(struct net_device *dev)
+{
+	struct typhoon *tp = (struct typhoon *) dev->priv;
+	struct cmd_desc xp_cmd;
+	u32 mc_filter[2];
+	u16 filter;
+
+	filter = TYPHOON_RX_FILTER_DIRECTED | TYPHOON_RX_FILTER_BROADCAST;
+	if(dev->flags & IFF_PROMISC) {
+		printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n",
+		       dev->name);
+		filter |= TYPHOON_RX_FILTER_PROMISCOUS;
+	} else if((dev->mc_count > multicast_filter_limit) ||
+		  (dev->flags & IFF_ALLMULTI)) {
+		/* Too many to match, or accept all multicasts. */
+		filter |= TYPHOON_RX_FILTER_ALL_MCAST;
+	} else if(dev->mc_count) {
+		struct dev_mc_list *mclist;
+		int i;
+
+		memset(mc_filter, 0, sizeof(mc_filter));
+		for(i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+		    i++, mclist = mclist->next) {
+			int bit = ether_crc(ETH_ALEN, mclist->dmi_addr) & 0x3f;
+			mc_filter[bit >> 5] |= 1 << (bit & 0x1f);
+		}
+
+		INIT_COMMAND_NO_RESPONSE(&xp_cmd,
+					 TYPHOON_CMD_SET_MULTICAST_HASH);
+		xp_cmd.parm1 = TYPHOON_MCAST_HASH_SET;
+		xp_cmd.parm2 = cpu_to_le32(mc_filter[0]);
+		xp_cmd.parm3 = cpu_to_le32(mc_filter[1]);
+		typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
+
+		filter |= TYPHOON_RX_FILTER_MCAST_HASH;
+	}
+
+	INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_SET_RX_FILTER);
+	xp_cmd.parm1 = filter;
+	typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
+}
+
+static int
+typhoon_do_get_stats(struct typhoon *tp)
+{
+	struct net_device_stats *stats = &tp->stats;
+	struct net_device_stats *saved = &tp->stats_saved;
+	struct cmd_desc xp_cmd;
+	struct resp_desc xp_resp[7];
+	struct stats_resp *s = (struct stats_resp *) xp_resp;
+	int err;
+
+	INIT_COMMAND_WITH_RESPONSE(&xp_cmd, TYPHOON_CMD_READ_STATS);
+	err = typhoon_issue_command(tp, 1, &xp_cmd, 7, xp_resp);
+	if(err < 0)
+		return err;
+
+	/* 3Com's Linux driver uses txMultipleCollisions as it's
+	 * collisions value, but there is some other collision info as well...
+	 */
+	stats->tx_packets = le32_to_cpu(s->txPackets);
+	stats->tx_bytes = le32_to_cpu(s->txBytes);
+	stats->tx_errors = le32_to_cpu(s->txCarrierLost);
+	stats->tx_carrier_errors = le32_to_cpu(s->txCarrierLost);
+	stats->collisions = le32_to_cpu(s->txMultipleCollisions);
+	stats->rx_packets = le32_to_cpu(s->rxPacketsGood);
+	stats->rx_bytes = le32_to_cpu(s->rxBytesGood);
+	stats->rx_fifo_errors = le32_to_cpu(s->rxFifoOverruns);
+	stats->rx_errors = le32_to_cpu(s->rxFifoOverruns) +
+			le32_to_cpu(s->BadSSD) + le32_to_cpu(s->rxCrcErrors);
+	stats->rx_crc_errors = le32_to_cpu(s->rxCrcErrors);
+	stats->rx_length_errors = le32_to_cpu(s->rxOversized);
+	tp->speed = (s->linkStatus & TYPHOON_LINK_100MBPS) ?
+			SPEED_100 : SPEED_10;
+	tp->duplex = (s->linkStatus & TYPHOON_LINK_FULL_DUPLEX) ?
+			DUPLEX_FULL : DUPLEX_HALF;
+
+	/* add in the saved statistics
+	 */
+	stats->tx_packets += saved->tx_packets;
+	stats->tx_bytes += saved->tx_bytes;
+	stats->tx_errors += saved->tx_errors;
+	stats->collisions += saved->collisions;
+	stats->rx_packets += saved->rx_packets;
+	stats->rx_bytes += saved->rx_bytes;
+	stats->rx_fifo_errors += saved->rx_fifo_errors;
+	stats->rx_errors += saved->rx_errors;
+	stats->rx_crc_errors += saved->rx_crc_errors;
+	stats->rx_length_errors += saved->rx_length_errors;
+
+	return 0;
+}
+
+static struct net_device_stats *
+typhoon_get_stats(struct net_device *dev)
+{
+	struct typhoon *tp = (struct typhoon *) dev->priv;
+	struct net_device_stats *stats = &tp->stats;
+	struct net_device_stats *saved = &tp->stats_saved;
+
+	smp_rmb();
+	if(tp->card_state == Sleeping)
+		return saved;
+
+	if(typhoon_do_get_stats(tp) < 0) {
+		printk(KERN_ERR "%s: error getting stats\n", dev->name);
+		return saved;
+	}
+
+	return stats;
+}
+
+static int
+typhoon_set_mac_address(struct net_device *dev, void *addr)
+{
+	struct sockaddr *saddr = (struct sockaddr *) addr;
+
+	if(netif_running(dev))
+		return -EBUSY;
+
+	memcpy(dev->dev_addr, saddr->sa_data, dev->addr_len);
+	return 0;
+}
+
+static inline void
+typhoon_ethtool_gdrvinfo(struct typhoon *tp, struct ethtool_drvinfo *info)
+{
+	struct pci_dev *pci_dev = tp->pdev;
+	struct cmd_desc xp_cmd;
+	struct resp_desc xp_resp[3];
+
+	smp_rmb();
+	if(tp->card_state == Sleeping) {
+		strcpy(info->fw_version, "Sleep image");
+	} else {
+		INIT_COMMAND_WITH_RESPONSE(&xp_cmd, TYPHOON_CMD_READ_VERSIONS);
+		if(typhoon_issue_command(tp, 1, &xp_cmd, 3, xp_resp) < 0) {
+			strcpy(info->fw_version, "Unknown runtime");
+		} else {
+			strncpy(info->fw_version, (char *) &xp_resp[1], 32);
+			info->fw_version[31] = 0;
+		}
+	}
+
+	strcpy(info->driver, DRV_MODULE_NAME);
+	strcpy(info->version, DRV_MODULE_VERSION);
+	strcpy(info->bus_info, pci_dev->slot_name);
+}
+
+static inline void
+typhoon_ethtool_gset(struct typhoon *tp, struct ethtool_cmd *cmd)
+{
+	cmd->supported = SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
+				SUPPORTED_Autoneg;
+
+	switch (tp->xcvr_select) {
+	case TYPHOON_XCVR_10HALF:
+		cmd->advertising = ADVERTISED_10baseT_Half;
+		break;
+	case TYPHOON_XCVR_10FULL:
+		cmd->advertising = ADVERTISED_10baseT_Full;
+		break;
+	case TYPHOON_XCVR_100HALF:
+		cmd->advertising = ADVERTISED_100baseT_Half;
+		break;
+	case TYPHOON_XCVR_100FULL:
+		cmd->advertising = ADVERTISED_100baseT_Full;
+		break;
+	case TYPHOON_XCVR_AUTONEG:
+		cmd->advertising = ADVERTISED_10baseT_Half |
+					    ADVERTISED_10baseT_Full |
+					    ADVERTISED_100baseT_Half |
+					    ADVERTISED_100baseT_Full |
+					    ADVERTISED_Autoneg;
+		break;
+	}
+
+	if(tp->capabilities & TYPHOON_FIBER) {
+		cmd->supported |= SUPPORTED_FIBRE;
+		cmd->advertising |= ADVERTISED_FIBRE;
+		cmd->port = PORT_FIBRE;
+	} else {
+		cmd->supported |= SUPPORTED_10baseT_Half |
+		    			SUPPORTED_10baseT_Full |
+					SUPPORTED_TP;
+		cmd->advertising |= ADVERTISED_TP;
+		cmd->port = PORT_TP;
+	}
+
+	/* need to get stats to make these link speed/duplex valid */
+	typhoon_do_get_stats(tp);
+	cmd->speed = tp->speed;
+	cmd->duplex = tp->duplex;
+	cmd->phy_address = 0;
+	cmd->transceiver = XCVR_INTERNAL;
+	if(tp->xcvr_select == TYPHOON_XCVR_AUTONEG)
+		cmd->autoneg = AUTONEG_ENABLE;
+	else
+		cmd->autoneg = AUTONEG_DISABLE;
+	cmd->maxtxpkt = 1;
+	cmd->maxrxpkt = 1;
+}
+
+static inline int
+typhoon_ethtool_sset(struct typhoon *tp, struct ethtool_cmd *cmd)
+{
+	struct cmd_desc xp_cmd;
+	int xcvr;
+	int err;
+
+	if(cmd->autoneg == AUTONEG_ENABLE) {
+		xcvr = TYPHOON_XCVR_AUTONEG;
+	} else {
+		if(cmd->duplex == DUPLEX_HALF) {
+			if(cmd->speed == SPEED_10)
+				xcvr = TYPHOON_XCVR_10HALF;
+			else if(cmd->speed == SPEED_100)
+				xcvr = TYPHOON_XCVR_100HALF;
+			else
+				return -EINVAL;
+		} else if(cmd->duplex == DUPLEX_FULL) {
+			if(cmd->speed == SPEED_10)
+				xcvr = TYPHOON_XCVR_10FULL;
+			else if(cmd->speed == SPEED_100)
+				xcvr = TYPHOON_XCVR_100FULL;
+			else
+				return -EINVAL;
+		} else
+			return -EINVAL;
+	}
+
+	INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_XCVR_SELECT);
+	xp_cmd.parm1 = cpu_to_le16(xcvr);
+	err = typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
+	if(err < 0)
+		return err;
+
+	tp->xcvr_select = xcvr;
+	if(cmd->autoneg == AUTONEG_ENABLE) {
+		tp->speed = 0xff;	/* invalid */
+		tp->duplex = 0xff;	/* invalid */
+	} else {
+		tp->speed = cmd->speed;
+		tp->duplex = cmd->duplex;
+	}
+
+	return 0;
+}
+
+static inline int
+typhoon_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+	struct typhoon *tp = (struct typhoon *) dev->priv;
+	u32 ethcmd;
+
+	if(copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
+		return -EFAULT;
+
+	switch (ethcmd) {
+	case ETHTOOL_GDRVINFO: {
+			struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+
+			typhoon_ethtool_gdrvinfo(tp, &info);
+			if(copy_to_user(useraddr, &info, sizeof(info)))
+				return -EFAULT;
+			return 0;
+		}
+	case ETHTOOL_GSET: {
+			struct ethtool_cmd cmd = { ETHTOOL_GSET };
+
+			typhoon_ethtool_gset(tp, &cmd);
+			if(copy_to_user(useraddr, &cmd, sizeof(cmd)))
+				return -EFAULT;
+			return 0;
+		}
+	case ETHTOOL_SSET: {
+			struct ethtool_cmd cmd;
+			if(copy_from_user(&cmd, useraddr, sizeof(cmd)))
+				return -EFAULT;
+
+			return typhoon_ethtool_sset(tp, &cmd);
+		}
+	case ETHTOOL_GLINK:{
+			struct ethtool_value edata = { ETHTOOL_GLINK };
+
+			edata.data = netif_carrier_ok(dev) ? 1 : 0;
+			if(copy_to_user(useraddr, &edata, sizeof(edata)))
+				return -EFAULT;
+			return 0;
+		}
+	case ETHTOOL_GWOL: {
+			struct ethtool_wolinfo wol = { ETHTOOL_GWOL };
+
+			if(tp->wol_events & TYPHOON_WAKE_LINK_EVENT)
+				wol.wolopts |= WAKE_PHY;
+			if(tp->wol_events & TYPHOON_WAKE_MAGIC_PKT)
+				wol.wolopts |= WAKE_MAGIC;
+			if(copy_to_user(useraddr, &wol, sizeof(wol)))
+				return -EFAULT;
+			return 0;
+	}
+	case ETHTOOL_SWOL: {
+			struct ethtool_wolinfo wol;
+
+			if(copy_from_user(&wol, useraddr, sizeof(wol)))
+				return -EFAULT;
+			tp->wol_events = 0;
+			if(wol.wolopts & WAKE_PHY)
+				tp->wol_events |= TYPHOON_WAKE_LINK_EVENT;
+			if(wol.wolopts & WAKE_MAGIC)
+				tp->wol_events |= TYPHOON_WAKE_MAGIC_PKT;
+			return 0;
+	}
+	default:
+		break;
+	}
+
+	return -EOPNOTSUPP;
+}
+
+static int
+typhoon_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	switch (cmd) {
+	case SIOCETHTOOL:
+		return typhoon_ethtool_ioctl(dev, (void *) ifr->ifr_data);
+	default:
+		break;
+	}
+
+	return -EOPNOTSUPP;
+}
+
+static int
+typhoon_wait_interrupt(unsigned long ioaddr)
+{
+	int i, err = 0;
+
+	for(i = 0; i < TYPHOON_WAIT_TIMEOUT; i++) {
+		if(readl(ioaddr + TYPHOON_REG_INTR_STATUS) &
+		   TYPHOON_INTR_BOOTCMD)
+			goto out;
+		udelay(TYPHOON_UDELAY);
+	}
+
+	err = -ETIMEDOUT;
+
+out:
+	writel(TYPHOON_INTR_BOOTCMD, ioaddr + TYPHOON_REG_INTR_STATUS);
+	return err;
+}
+
+#define shared_offset(x)	offsetof(struct typhoon_shared, x)
+
+static void
+typhoon_init_interface(struct typhoon *tp)
+{
+	struct typhoon_interface *iface = &tp->shared->iface;
+	dma_addr_t shared_dma;
+
+	memset(tp->shared, 0, sizeof(struct typhoon_shared));
+
+	/* The *Hi members of iface are all init'd to zero by the memset().
+	 */
+	shared_dma = tp->shared_dma + shared_offset(indexes);
+	iface->ringIndex = cpu_to_le32(shared_dma);
+
+	shared_dma = tp->shared_dma + shared_offset(txLo);
+	iface->txLoAddr = cpu_to_le32(shared_dma);
+	iface->txLoSize = cpu_to_le32(TXLO_ENTRIES * sizeof(struct tx_desc));
+
+	shared_dma = tp->shared_dma + shared_offset(txHi);
+	iface->txHiAddr = cpu_to_le32(shared_dma);
+	iface->txHiSize = cpu_to_le32(TXHI_ENTRIES * sizeof(struct tx_desc));
+
+	shared_dma = tp->shared_dma + shared_offset(rxBuff);
+	iface->rxBuffAddr = cpu_to_le32(shared_dma);
+	iface->rxBuffSize = cpu_to_le32(RXFREE_ENTRIES *
+					sizeof(struct rx_free));
+
+	shared_dma = tp->shared_dma + shared_offset(rxLo);
+	iface->rxLoAddr = cpu_to_le32(shared_dma);
+	iface->rxLoSize = cpu_to_le32(RX_ENTRIES * sizeof(struct rx_desc));
+
+	shared_dma = tp->shared_dma + shared_offset(rxHi);
+	iface->rxHiAddr = cpu_to_le32(shared_dma);
+	iface->rxHiSize = cpu_to_le32(RX_ENTRIES * sizeof(struct rx_desc));
+
+	shared_dma = tp->shared_dma + shared_offset(cmd);
+	iface->cmdAddr = cpu_to_le32(shared_dma);
+	iface->cmdSize = cpu_to_le32(COMMAND_RING_SIZE);
+
+	shared_dma = tp->shared_dma + shared_offset(resp);
+	iface->respAddr = cpu_to_le32(shared_dma);
+	iface->respSize = cpu_to_le32(RESPONSE_RING_SIZE);
+
+	shared_dma = tp->shared_dma + shared_offset(zeroWord);
+	iface->zeroAddr = cpu_to_le32(shared_dma);
+
+	tp->indexes = &tp->shared->indexes;
+	tp->txLoRing.ringBase = (u8 *) tp->shared->txLo;
+	tp->txHiRing.ringBase = (u8 *) tp->shared->txHi;
+	tp->rxLoRing.ringBase = (u8 *) tp->shared->rxLo;
+	tp->rxHiRing.ringBase = (u8 *) tp->shared->rxHi;
+	tp->rxBuffRing.ringBase = (u8 *) tp->shared->rxBuff;
+	tp->cmdRing.ringBase = (u8 *) tp->shared->cmd;
+	tp->respRing.ringBase = (u8 *) tp->shared->resp;;
+
+	tp->txLoRing.writeRegister = TYPHOON_REG_TX_LO_READY;
+	tp->txHiRing.writeRegister = TYPHOON_REG_TX_HI_READY;
+
+	tp->txlo_dma_addr = iface->txLoAddr;
+	tp->card_state = Sleeping;
+	smp_wmb();
+
+	tp->offload = TYPHOON_OFFLOAD_IP_CHKSUM | TYPHOON_OFFLOAD_TCP_CHKSUM;
+	tp->offload |= TYPHOON_OFFLOAD_UDP_CHKSUM | TSO_OFFLOAD_ON;
+
+	spin_lock_init(&tp->command_lock);
+	spin_lock_init(&tp->state_lock);
+}
+
+static void
+typhoon_init_rings(struct typhoon *tp)
+{
+	memset(tp->indexes, 0, sizeof(struct typhoon_indexes));
+
+	tp->txLoRing.lastWrite = 0;
+	tp->txHiRing.lastWrite = 0;
+	tp->rxLoRing.lastWrite = 0;
+	tp->rxHiRing.lastWrite = 0;
+	tp->rxBuffRing.lastWrite = 0;
+	tp->cmdRing.lastWrite = 0;
+	tp->cmdRing.lastWrite = 0;
+
+	tp->txLoRing.lastRead = 0;
+	tp->txHiRing.lastRead = 0;
+}
+
+static int
+typhoon_download_firmware(struct typhoon *tp)
+{
+	unsigned long ioaddr = tp->ioaddr;
+	struct pci_dev *pdev = tp->pdev;
+	struct typhoon_file_header *fHdr;
+	struct typhoon_section_header *sHdr;
+	u8 *image_data;
+	void *dpage;
+	dma_addr_t dpage_dma;
+	unsigned int csum;
+	u32 irqEnabled;
+	u32 irqMasked;
+	u32 numSections;
+	u32 section_len;
+	u32 len;
+	u32 load_addr;
+	int i;
+	int err;
+
+	err = -EINVAL;
+	fHdr = (struct typhoon_file_header *) typhoon_firmware_image;
+	image_data = (u8 *) fHdr;
+
+	if(memcmp(fHdr->tag, "TYPHOON", 8)) {
+		printk(KERN_ERR "%s: Invalid firmware image!\n", tp->name);
+		goto err_out;
+	}
+
+	/* Cannot just map the firmware image using pci_map_single() as
+	 * the firmware is part of the kernel/module image, so we allocate
+	 * some consistent memory to copy the sections into, as it is simpler,
+	 * and short-lived. If we ever split out and require a userland
+	 * firmware loader, then we can revisit this.
+	 */
+	err = -ENOMEM;
+	dpage = pci_alloc_consistent(pdev, PAGE_SIZE, &dpage_dma);
+	if(!dpage) {
+		printk(KERN_ERR "%s: no DMA mem for firmware\n", tp->name);
+		goto err_out;
+	}
+
+	irqEnabled = readl(ioaddr + TYPHOON_REG_INTR_ENABLE);
+	writel(irqEnabled | TYPHOON_INTR_BOOTCMD,
+	       ioaddr + TYPHOON_REG_INTR_ENABLE);
+	irqMasked = readl(ioaddr + TYPHOON_REG_INTR_MASK);
+	writel(irqMasked | TYPHOON_INTR_BOOTCMD,
+	       ioaddr + TYPHOON_REG_INTR_MASK);
+
+	err = -ETIMEDOUT;
+	if(typhoon_wait_status(ioaddr, TYPHOON_STATUS_WAITING_FOR_HOST) < 0) {
+		printk(KERN_ERR "%s: card ready timeout\n", tp->name);
+		goto err_out_irq;
+	}
+
+	numSections = le32_to_cpu(fHdr->numSections);
+	load_addr = le32_to_cpu(fHdr->startAddr);
+
+	writel(TYPHOON_INTR_BOOTCMD, ioaddr + TYPHOON_REG_INTR_STATUS);
+	writel(load_addr, ioaddr + TYPHOON_REG_DOWNLOAD_BOOT_ADDR);
+	typhoon_post_pci_writes(ioaddr);
+	writel(TYPHOON_BOOTCMD_RUNTIME_IMAGE, ioaddr + TYPHOON_REG_COMMAND);
+
+	image_data += sizeof(struct typhoon_file_header);
+
+	/* The readl() in typhoon_wait_interrupt() will force the
+	 * last write to the command register to post, so
+	 * we don't need a typhoon_post_pci_writes() after it.
+	 */
+	for(i = 0; i < numSections; i++) {
+		sHdr = (struct typhoon_section_header *) image_data;
+		image_data += sizeof(struct typhoon_section_header);
+		load_addr = le32_to_cpu(sHdr->startAddr);
+		section_len = le32_to_cpu(sHdr->len);
+
+		while(section_len) {
+			len = min_t(u32, section_len, PAGE_SIZE);
+
+			if(typhoon_wait_interrupt(ioaddr) < 0 ||
+			   readl(ioaddr + TYPHOON_REG_STATUS) !=
+			   TYPHOON_STATUS_WAITING_FOR_SEGMENT) {
+				printk(KERN_ERR "%s: segment ready timeout\n",
+				       tp->name);
+				goto err_out_irq;
+			}
+
+			/* Do an pseudo IPv4 checksum on the data -- first
+			 * need to convert each u16 to cpu order before
+			 * summing. Fortunately, due to the properties of
+			 * the checksum, we can do this once, at the end.
+			 */
+			csum = csum_partial_copy_nocheck(image_data, dpage,
+							 len, 0);
+			csum = csum_fold(csum);
+			csum = le16_to_cpu(csum);
+
+			writel(len, ioaddr + TYPHOON_REG_BOOT_LENGTH);
+			writel(csum, ioaddr + TYPHOON_REG_BOOT_CHECKSUM);
+			writel(load_addr, ioaddr + TYPHOON_REG_BOOT_DEST_ADDR);
+			writel(0, ioaddr + TYPHOON_REG_BOOT_DATA_HI);
+			writel(dpage_dma, ioaddr + TYPHOON_REG_BOOT_DATA_LO);
+			typhoon_post_pci_writes(ioaddr);
+			writel(TYPHOON_BOOTCMD_SEG_AVAILABLE,
+			       ioaddr + TYPHOON_REG_COMMAND);
+
+			image_data += len;
+			load_addr += len;
+			section_len -= len;
+		}
+	}
+
+	if(typhoon_wait_interrupt(ioaddr) < 0 ||
+	   readl(ioaddr + TYPHOON_REG_STATUS) !=
+	   TYPHOON_STATUS_WAITING_FOR_SEGMENT) {
+		printk(KERN_ERR "%s: final segment ready timeout\n", tp->name);
+		goto err_out_irq;
+	}
+
+	writel(TYPHOON_BOOTCMD_DNLD_COMPLETE, ioaddr + TYPHOON_REG_COMMAND);
+
+	if(typhoon_wait_status(ioaddr, TYPHOON_STATUS_WAITING_FOR_BOOT) < 0) {
+		printk(KERN_ERR "%s: boot ready timeout, status 0x%0x\n",
+		       tp->name, readl(ioaddr + TYPHOON_REG_STATUS));
+		goto err_out_irq;
+	}
+
+	err = 0;
+
+err_out_irq:
+	writel(irqMasked, ioaddr + TYPHOON_REG_INTR_MASK);
+	writel(irqEnabled, ioaddr + TYPHOON_REG_INTR_ENABLE);
+
+	pci_free_consistent(pdev, PAGE_SIZE, dpage, dpage_dma);
+
+err_out:
+	return err;
+}
+
+static int
+typhoon_boot_3XP(struct typhoon *tp, u32 initial_status)
+{
+	unsigned long ioaddr = tp->ioaddr;
+
+	if(typhoon_wait_status(ioaddr, initial_status) < 0) {
+		printk(KERN_ERR "%s: boot ready timeout\n", tp->name);
+		goto out_timeout;
+	}
+
+	writel(0, ioaddr + TYPHOON_REG_BOOT_RECORD_ADDR_HI);
+	writel(tp->shared_dma, ioaddr + TYPHOON_REG_BOOT_RECORD_ADDR_LO);
+	typhoon_post_pci_writes(ioaddr);
+	writel(TYPHOON_BOOTCMD_REG_BOOT_RECORD, ioaddr + TYPHOON_REG_COMMAND);
+
+	if(typhoon_wait_status(ioaddr, TYPHOON_STATUS_RUNNING) < 0) {
+		printk(KERN_ERR "%s: boot finish timeout (status 0x%x)\n",
+		       tp->name, readl(ioaddr + TYPHOON_REG_STATUS));
+		goto out_timeout;
+	}
+
+	/* Clear the Transmit and Command ready registers
+	 */
+	writel(0, ioaddr + TYPHOON_REG_TX_HI_READY);
+	writel(0, ioaddr + TYPHOON_REG_CMD_READY);
+	writel(0, ioaddr + TYPHOON_REG_TX_LO_READY);
+	typhoon_post_pci_writes(ioaddr);
+	writel(TYPHOON_BOOTCMD_BOOT, ioaddr + TYPHOON_REG_COMMAND);
+
+	return 0;
+
+out_timeout:
+	return -ETIMEDOUT;
+}
+
+static u32
+typhoon_clean_tx(struct typhoon *tp, struct transmit_ring *txRing,
+			volatile u32 * index)
+{
+	u32 lastRead = txRing->lastRead;
+	struct tx_desc *tx;
+	dma_addr_t skb_dma;
+	int dma_len;
+	int type;
+
+	while(lastRead != le32_to_cpu(*index)) {
+		tx = (struct tx_desc *) (txRing->ringBase + lastRead);
+		type = tx->flags & TYPHOON_TYPE_MASK;
+
+		if(type == TYPHOON_TX_DESC) {
+			/* This tx_desc describes a packet.
+			 */
+			unsigned long ptr = tx->addr | ((u64)tx->addrHi << 32);
+			struct sk_buff *skb = (struct sk_buff *) ptr;
+			dev_kfree_skb_irq(skb);
+		} else if(type == TYPHOON_FRAG_DESC) {
+			/* This tx_desc describes a memory mapping. Free it.
+			 */
+			skb_dma = (dma_addr_t) le32_to_cpu(tx->addr);
+			dma_len = le16_to_cpu(tx->len);
+			pci_unmap_single(tp->pdev, skb_dma, dma_len,
+				       PCI_DMA_TODEVICE);
+		}
+
+		tx->flags = 0;
+		typhoon_inc_tx_index(&lastRead, 1);
+	}
+
+	return lastRead;
+}
+
+static void
+typhoon_tx_complete(struct typhoon *tp, struct transmit_ring *txRing,
+			volatile u32 * index)
+{
+	u32 lastRead;
+	int numDesc = MAX_SKB_FRAGS + 1;
+
+	/* This will need changing if we start to use the Hi Tx ring. */
+	lastRead = typhoon_clean_tx(tp, txRing, index);
+	if(netif_queue_stopped(tp->dev) && typhoon_num_free(txRing->lastWrite,
+				lastRead, TXLO_ENTRIES) > (numDesc + 2))
+		netif_wake_queue(tp->dev);
+
+	txRing->lastRead = lastRead;
+	smp_wmb();
+}
+
+static void
+typhoon_recycle_rx_skb(struct typhoon *tp, u32 idx)
+{
+	struct typhoon_indexes *indexes = tp->indexes;
+	struct rxbuff_ent *rxb = &tp->rxbuffers[idx];
+	struct basic_ring *ring = &tp->rxBuffRing;
+	struct rx_free *r;
+
+	if((ring->lastWrite + sizeof(*r)) % (RXFREE_ENTRIES * sizeof(*r)) ==
+				indexes->rxBuffCleared) {
+		/* no room in ring, just drop the skb
+		 */
+		dev_kfree_skb_any(rxb->skb);
+		rxb->skb = NULL;
+		return;
+	}
+
+	r = (struct rx_free *) (ring->ringBase + ring->lastWrite);
+	typhoon_inc_rxfree_index(&ring->lastWrite, 1);
+	r->virtAddr = idx;
+	r->physAddr = cpu_to_le32(rxb->dma_addr);
+
+	/* Tell the card about it */
+	wmb();
+	indexes->rxBuffReady = cpu_to_le32(ring->lastWrite);
+}
+
+static int
+typhoon_alloc_rx_skb(struct typhoon *tp, u32 idx)
+{
+	struct typhoon_indexes *indexes = tp->indexes;
+	struct rxbuff_ent *rxb = &tp->rxbuffers[idx];
+	struct basic_ring *ring = &tp->rxBuffRing;
+	struct rx_free *r;
+	struct sk_buff *skb;
+	dma_addr_t dma_addr;
+
+	rxb->skb = NULL;
+
+	if((ring->lastWrite + sizeof(*r)) % (RXFREE_ENTRIES * sizeof(*r)) ==
+				indexes->rxBuffCleared)
+		return -ENOMEM;
+
+	skb = dev_alloc_skb(PKT_BUF_SZ);
+	if(!skb)
+		return -ENOMEM;
+
+#if 0
+	/* Please, 3com, fix the firmware to allow DMA to a unaligned
+	 * address! Pretty please?
+	 */
+	skb_reserve(skb, 2);
+#endif
+
+	skb->dev = tp->dev;
+	dma_addr = pci_map_single(tp->pdev, skb->tail,
+				  PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
+
+	/* Since no card does 64 bit DAC, the high bits will never
+	 * change from zero.
+	 */
+	r = (struct rx_free *) (ring->ringBase + ring->lastWrite);
+	typhoon_inc_rxfree_index(&ring->lastWrite, 1);
+	r->virtAddr = idx;
+	r->physAddr = cpu_to_le32(dma_addr);
+	rxb->skb = skb;
+	rxb->dma_addr = dma_addr;
+
+	/* Tell the card about it */
+	wmb();
+	indexes->rxBuffReady = cpu_to_le32(ring->lastWrite);
+	return 0;
+}
+
+static int
+typhoon_rx(struct typhoon *tp, struct basic_ring *rxRing, volatile u32 * ready,
+	   volatile u32 * cleared, int budget)
+{
+	struct rx_desc *rx;
+	struct sk_buff *skb, *new_skb;
+	struct rxbuff_ent *rxb;
+	dma_addr_t dma_addr;
+	u32 local_ready;
+	u32 rxaddr;
+	int pkt_len;
+	u32 idx;
+	u32 csum_bits;
+	int received;
+
+	received = 0;
+	local_ready = le32_to_cpu(*ready);
+	rxaddr = le32_to_cpu(*cleared);
+	while(rxaddr != local_ready && budget > 0) {
+		rx = (struct rx_desc *) (rxRing->ringBase + rxaddr);
+		idx = rx->addr;
+		rxb = &tp->rxbuffers[idx];
+		skb = rxb->skb;
+		dma_addr = rxb->dma_addr;
+
+		rxaddr += sizeof(struct rx_desc);
+		rxaddr %= RX_ENTRIES * sizeof(struct rx_desc);
+
+		if(rx->flags & TYPHOON_RX_ERROR) {
+			typhoon_recycle_rx_skb(tp, idx);
+			continue;
+		}
+
+		pkt_len = le16_to_cpu(rx->frameLen);
+
+		if(pkt_len < rx_copybreak &&
+		   (new_skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
+			new_skb->dev = tp->dev;
+			skb_reserve(new_skb, 2);
+			pci_dma_sync_single(tp->pdev, dma_addr, PKT_BUF_SZ,
+					    PCI_DMA_FROMDEVICE);
+			eth_copy_and_sum(new_skb, skb->tail, pkt_len, 0);
+			skb_put(new_skb, pkt_len);
+			typhoon_recycle_rx_skb(tp, idx);
+		} else {
+			new_skb = skb;
+			skb_put(new_skb, pkt_len);
+			pci_unmap_single(tp->pdev, dma_addr, PKT_BUF_SZ,
+				       PCI_DMA_FROMDEVICE);
+			typhoon_alloc_rx_skb(tp, idx);
+		}
+		new_skb->protocol = eth_type_trans(new_skb, tp->dev);
+		csum_bits = rx->rxStatus & (TYPHOON_RX_IP_CHK_GOOD |
+			TYPHOON_RX_UDP_CHK_GOOD | TYPHOON_RX_TCP_CHK_GOOD);
+		if(csum_bits ==
+		   (TYPHOON_RX_IP_CHK_GOOD | TYPHOON_RX_TCP_CHK_GOOD)
+		   || csum_bits ==
+		   (TYPHOON_RX_IP_CHK_GOOD | TYPHOON_RX_UDP_CHK_GOOD)) {
+			new_skb->ip_summed = CHECKSUM_UNNECESSARY;
+		} else
+			new_skb->ip_summed = CHECKSUM_NONE;
+
+		spin_lock(&tp->state_lock);
+		if(tp->vlgrp != NULL && rx->rxStatus & TYPHOON_RX_VLAN)
+			vlan_hwaccel_receive_skb(new_skb, tp->vlgrp,
+						 ntohl(rx->vlanTag) & 0xffff);
+		else
+			netif_receive_skb(new_skb);
+		spin_unlock(&tp->state_lock);
+
+		tp->dev->last_rx = jiffies;
+		received++;
+		budget--;
+	}
+	*cleared = cpu_to_le32(rxaddr);
+
+	return received;
+}
+
+static void
+typhoon_fill_free_ring(struct typhoon *tp)
+{
+	u32 i;
+
+	for(i = 0; i < RXENT_ENTRIES; i++) {
+		struct rxbuff_ent *rxb = &tp->rxbuffers[i];
+		if(rxb->skb)
+			continue;
+		if(typhoon_alloc_rx_skb(tp, i) < 0)
+			break;
+	}
+}
+
+static int
+typhoon_poll(struct net_device *dev, int *total_budget)
+{
+	struct typhoon *tp = (struct typhoon *) dev->priv;
+	struct typhoon_indexes *indexes = tp->indexes;
+	int orig_budget = *total_budget;
+	int budget, work_done, done;
+
+	rmb();
+	if(!tp->awaiting_resp && indexes->respReady != indexes->respCleared)
+			typhoon_process_response(tp, 0, NULL);
+
+	if(le32_to_cpu(indexes->txLoCleared) != tp->txLoRing.lastRead)
+		typhoon_tx_complete(tp, &tp->txLoRing, &indexes->txLoCleared);
+
+	if(orig_budget > dev->quota)
+		orig_budget = dev->quota;
+
+	budget = orig_budget;
+	work_done = 0;
+	done = 1;
+
+	if(indexes->rxHiCleared != indexes->rxHiReady) {
+		work_done = typhoon_rx(tp, &tp->rxHiRing, &indexes->rxHiReady,
+			   		&indexes->rxHiCleared, budget);
+		budget -= work_done;
+	}
+
+	if(indexes->rxLoCleared != indexes->rxLoReady) {
+		work_done += typhoon_rx(tp, &tp->rxLoRing, &indexes->rxLoReady,
+			   		&indexes->rxLoCleared, budget);
+	}
+
+	if(work_done) {
+		*total_budget -= work_done;
+		dev->quota -= work_done;
+
+		if(work_done >= orig_budget)
+			done = 0;
+	}
+
+	if(le32_to_cpu(indexes->rxBuffCleared) == tp->rxBuffRing.lastWrite) {
+		/* rxBuff ring is empty, try to fill it. */
+		typhoon_fill_free_ring(tp);
+	}
+
+	if(done) {
+		netif_rx_complete(dev);
+		writel(TYPHOON_INTR_NONE, tp->ioaddr + TYPHOON_REG_INTR_MASK);
+		typhoon_post_pci_writes(tp->ioaddr);
+	}
+
+	return (done ? 0 : 1);
+}
+
+static void
+typhoon_interrupt(int irq, void *dev_instance, struct pt_regs *rgs)
+{
+	struct net_device *dev = (struct net_device *) dev_instance;
+	unsigned long ioaddr = dev->base_addr;
+	u32 intr_status;
+
+	intr_status = readl(ioaddr + TYPHOON_REG_INTR_STATUS);
+	if(!intr_status)
+		return;
+
+	writel(intr_status, ioaddr + TYPHOON_REG_INTR_STATUS);
+
+	if(netif_rx_schedule_prep(dev)) {
+		writel(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_MASK);
+		typhoon_post_pci_writes(ioaddr);
+		__netif_rx_schedule(dev);
+	} else {
+		printk(KERN_ERR "%s: Error, poll already scheduled\n",
+                       dev->name);
+	}
+}
+
+static void
+typhoon_free_rx_rings(struct typhoon *tp)
+{
+	u32 i;
+
+	for(i = 0; i < RXENT_ENTRIES; i++) {
+		struct rxbuff_ent *rxb = &tp->rxbuffers[i];
+		if(rxb->skb) {
+			pci_unmap_single(tp->pdev, rxb->dma_addr, PKT_BUF_SZ,
+				       PCI_DMA_FROMDEVICE);
+			dev_kfree_skb(rxb->skb);
+			rxb->skb = NULL;
+		}
+	}
+}
+
+static int
+typhoon_sleep(struct typhoon *tp, int state, u16 events)
+{
+	struct pci_dev *pdev = tp->pdev;
+	unsigned long ioaddr = tp->ioaddr;
+	struct cmd_desc xp_cmd;
+	int err;
+
+	INIT_COMMAND_WITH_RESPONSE(&xp_cmd, TYPHOON_CMD_ENABLE_WAKE_EVENTS);
+	xp_cmd.parm1 = events;
+	err = typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
+	if(err < 0) {
+		printk(KERN_ERR "%s: typhoon_sleep(): wake events cmd err %d\n",
+				tp->name, err);
+		return err;
+	}
+
+	INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_GOTO_SLEEP);
+	err = typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
+	if(err < 0) {
+		printk(KERN_ERR "%s: typhoon_sleep(): sleep cmd err %d\n",
+				tp->name, err);
+		return err;
+	}
+
+	if(typhoon_wait_status(ioaddr, TYPHOON_STATUS_SLEEPING) < 0)
+		return -ETIMEDOUT;
+
+	pci_enable_wake(tp->pdev, state, 1);
+	pci_disable_device(pdev);
+	return pci_set_power_state(pdev, state);
+}
+
+static int
+typhoon_wakeup(struct typhoon *tp, int wait_type)
+{
+	struct pci_dev *pdev = tp->pdev;
+	unsigned long ioaddr = tp->ioaddr;
+
+	pci_set_power_state(pdev, 0);
+	pci_restore_state(pdev, tp->pci_state);
+
+	writel(TYPHOON_BOOTCMD_WAKEUP, ioaddr + TYPHOON_REG_COMMAND);
+	if(typhoon_wait_status(ioaddr, TYPHOON_STATUS_WAITING_FOR_HOST) < 0)
+		return typhoon_reset(ioaddr, wait_type);
+
+	return 0;
+}
+
+static int
+typhoon_start_runtime(struct typhoon *tp)
+{
+	struct net_device *dev = tp->dev;
+	unsigned long ioaddr = tp->ioaddr;
+	struct cmd_desc xp_cmd;
+	int err;
+
+	typhoon_init_rings(tp);
+	typhoon_fill_free_ring(tp);
+
+	err = typhoon_download_firmware(tp);
+	if(err < 0) {
+		printk("%s: cannot load runtime on 3XP\n", tp->name);
+		goto error_out;
+	}
+
+	if(typhoon_boot_3XP(tp, TYPHOON_STATUS_WAITING_FOR_BOOT) < 0) {
+		printk("%s: cannot boot 3XP\n", tp->name);
+		err = -EIO;
+		goto error_out;
+	}
+
+	INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_SET_MAX_PKT_SIZE);
+	xp_cmd.parm1 = cpu_to_le16(PKT_BUF_SZ);
+	err = typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
+	if(err < 0)
+		goto error_out;
+
+	INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_SET_MAC_ADDRESS);
+	xp_cmd.parm1 = cpu_to_le16(ntohs(*(u16 *)&dev->dev_addr[0]));
+	xp_cmd.parm2 = cpu_to_le32(ntohl(*(u32 *)&dev->dev_addr[2]));
+	err = typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
+	if(err < 0)
+		goto error_out;
+
+	/* Disable IRQ coalescing -- we can reenable it when 3Com gives
+	 * us some more information on how to control it.
+	 */
+	INIT_COMMAND_WITH_RESPONSE(&xp_cmd, TYPHOON_CMD_IRQ_COALESCE_CTRL);
+	xp_cmd.parm1 = 0;
+	err = typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
+	if(err < 0)
+		goto error_out;
+
+	INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_XCVR_SELECT);
+	xp_cmd.parm1 = tp->xcvr_select;
+	err = typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
+	if(err < 0)
+		goto error_out;
+
+	INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_VLAN_TYPE_WRITE);
+	xp_cmd.parm1 = __constant_cpu_to_le16(ETH_P_8021Q);
+	err = typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
+	if(err < 0)
+		goto error_out;
+
+	INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_SET_OFFLOAD_TASKS);
+	spin_lock_bh(&tp->state_lock);
+	xp_cmd.parm2 = tp->offload;
+	xp_cmd.parm3 = tp->offload;
+	err = typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
+	spin_unlock_bh(&tp->state_lock);
+	if(err < 0)
+		goto error_out;
+
+	typhoon_set_rx_mode(dev);
+
+	INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_TX_ENABLE);
+	err = typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
+	if(err < 0)
+		goto error_out;
+
+	INIT_COMMAND_WITH_RESPONSE(&xp_cmd, TYPHOON_CMD_RX_ENABLE);
+	err = typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
+	if(err < 0)
+		goto error_out;
+
+	tp->card_state = Running;
+	smp_wmb();
+
+	writel(TYPHOON_INTR_ENABLE_ALL, ioaddr + TYPHOON_REG_INTR_ENABLE);
+	writel(TYPHOON_INTR_NONE, ioaddr + TYPHOON_REG_INTR_MASK);
+	typhoon_post_pci_writes(ioaddr);
+
+	return 0;
+
+error_out:
+	typhoon_reset(ioaddr, WaitNoSleep);
+	typhoon_free_rx_rings(tp);
+	typhoon_init_rings(tp);
+	return err;
+}
+
+static int
+typhoon_stop_runtime(struct typhoon *tp, int wait_type)
+{
+	struct typhoon_indexes *indexes = tp->indexes;
+	struct transmit_ring *txLo = &tp->txLoRing;
+	unsigned long ioaddr = tp->ioaddr;
+	struct cmd_desc xp_cmd;
+	int i;
+
+	/* Disable interrupts early, since we can't schedule a poll
+	 * when called with !netif_running(). This will be posted
+	 * when we force the posting of the command.
+	 */
+	writel(TYPHOON_INTR_NONE, ioaddr + TYPHOON_REG_INTR_ENABLE);
+
+	INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_RX_DISABLE);
+	typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
+
+	/* Wait 1/2 sec for any outstanding transmits to occur
+	 * We'll cleanup after the reset if this times out.
+	 */
+	for(i = 0; i < TYPHOON_WAIT_TIMEOUT; i++) {
+		if(indexes->txLoCleared == cpu_to_le32(txLo->lastWrite))
+			break;
+		udelay(TYPHOON_UDELAY);
+	}
+
+	if(i == TYPHOON_WAIT_TIMEOUT)
+		printk(KERN_ERR
+		       "%s: halt timed out waiting for Tx to complete\n",
+		       tp->name);
+
+	INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_TX_DISABLE);
+	typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
+
+	/* save the statistics so when we bring the interface up again,
+	 * the values reported to userspace are correct.
+	 */
+	tp->card_state = Sleeping;
+	smp_wmb();
+	typhoon_do_get_stats(tp);
+	memcpy(&tp->stats_saved, &tp->stats, sizeof(struct net_device_stats));
+
+	INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_HALT);
+	typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
+
+	if(typhoon_wait_status(ioaddr, TYPHOON_STATUS_HALTED) < 0)
+		printk(KERN_ERR "%s: timed out waiting for 3XP to halt\n",
+		       tp->name);
+
+	if(typhoon_reset(ioaddr, wait_type) < 0) {
+		printk(KERN_ERR "%s: unable to reset 3XP\n", tp->name);
+		return -ETIMEDOUT;
+	}
+
+	/* cleanup any outstanding Tx packets */
+	if(indexes->txLoCleared != cpu_to_le32(txLo->lastWrite)) {
+		indexes->txLoCleared = cpu_to_le32(txLo->lastWrite);
+		typhoon_clean_tx(tp, &tp->txLoRing, &indexes->txLoCleared);
+	}
+
+	return 0;
+}
+
+static void
+typhoon_tx_timeout(struct net_device *dev)
+{
+	struct typhoon *tp = (struct typhoon *) dev->priv;
+
+	if(typhoon_reset(dev->base_addr, WaitNoSleep) < 0) {
+		printk(KERN_WARNING "%s: could not reset in tx timeout\n",
+					dev->name);
+		goto truely_dead;
+	}
+
+	/* If we ever start using the Hi ring, it will need cleaning too */
+	typhoon_clean_tx(tp, &tp->txLoRing, &tp->indexes->txLoCleared);
+	typhoon_free_rx_rings(tp);
+
+	if(typhoon_start_runtime(tp) < 0) {
+		printk(KERN_ERR "%s: could not start runtime in tx timeout\n",
+					dev->name);
+		goto truely_dead;
+        }
+
+	netif_wake_queue(dev);
+	return;
+
+truely_dead:
+	/* Reset the hardware, and turn off carrier to avoid more timeouts */
+	typhoon_reset(dev->base_addr, NoWait);
+	netif_carrier_off(dev);
+}
+
+static int
+typhoon_open(struct net_device *dev)
+{
+	struct typhoon *tp = (struct typhoon *) dev->priv;
+	int err;
+
+	err = typhoon_wakeup(tp, WaitSleep);
+	if(err < 0) {
+		printk(KERN_ERR "%s: unable to wakeup device\n", dev->name);
+		goto out_sleep;
+	}
+
+	err = request_irq(dev->irq, &typhoon_interrupt, SA_SHIRQ,
+				dev->name, dev);
+	if(err < 0)
+		goto out_sleep;
+
+	err = typhoon_start_runtime(tp);
+	if(err < 0)
+		goto out_irq;
+
+	netif_start_queue(dev);
+	return 0;
+
+out_irq:
+	free_irq(dev->irq, dev);
+
+out_sleep:
+	if(typhoon_boot_3XP(tp, TYPHOON_STATUS_WAITING_FOR_HOST) < 0) {
+		printk(KERN_ERR "%s: unable to reboot into sleep img\n",
+				dev->name);
+		typhoon_reset(dev->base_addr, NoWait);
+		goto out;
+	}
+
+	if(typhoon_sleep(tp, 3, 0) < 0) 
+		printk(KERN_ERR "%s: unable to go back to sleep\n", dev->name);
+
+out:
+	return err;
+}
+
+static int
+typhoon_close(struct net_device *dev)
+{
+	struct typhoon *tp = (struct typhoon *) dev->priv;
+
+	netif_stop_queue(dev);
+
+	if(typhoon_stop_runtime(tp, WaitSleep) < 0)
+		printk(KERN_ERR "%s: unable to stop runtime\n", dev->name);
+
+	/* Make sure there is no irq handler running on a different CPU. */
+	typhoon_synchronize_irq(dev->irq);
+	free_irq(dev->irq, dev);
+
+	typhoon_free_rx_rings(tp);
+	typhoon_init_rings(tp);
+
+	if(typhoon_boot_3XP(tp, TYPHOON_STATUS_WAITING_FOR_HOST) < 0)
+		printk(KERN_ERR "%s: unable to boot sleep image\n", dev->name);
+
+	if(typhoon_sleep(tp, 3, 0) < 0)
+		printk(KERN_ERR "%s: unable to put card to sleep\n", dev->name);
+
+	return 0;
+}
+
+#if CONFIG_PM
+static int
+typhoon_resume(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct typhoon *tp = (struct typhoon *) dev->priv;
+
+	/* If we're down, resume when we are upped.
+	 */
+	if(!netif_running(dev))
+		return 0;
+
+	if(typhoon_wakeup(tp, WaitNoSleep) < 0) {
+		printk(KERN_ERR "%s: critical: could not wake up in resume\n",
+				dev->name);
+		goto reset;
+	}
+
+	if(typhoon_start_runtime(tp) < 0) {
+		printk(KERN_ERR "%s: critical: could not start runtime in "
+				"resume\n", dev->name);
+		goto reset;
+	}
+
+	netif_device_attach(dev);
+	netif_start_queue(dev);
+	return 0;
+
+reset:
+	typhoon_reset(dev->base_addr, NoWait);
+	return -EBUSY;
+}
+
+static int
+typhoon_suspend(struct pci_dev *pdev, u32 state)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct typhoon *tp = (struct typhoon *) dev->priv;
+	struct cmd_desc xp_cmd;
+
+	/* If we're down, we're already suspended.
+	 */
+	if(!netif_running(dev))
+		return 0;
+
+	spin_lock_bh(&tp->state_lock);
+	if(tp->vlgrp && tp->wol_events & TYPHOON_WAKE_MAGIC_PKT) {
+		spin_unlock_bh(&tp->state_lock);
+		printk(KERN_ERR "%s: cannot do WAKE_MAGIC with VLANS\n",
+				dev->name);
+		return -EBUSY;
+	}
+	spin_unlock_bh(&tp->state_lock);
+
+	netif_device_detach(dev);
+
+	if(typhoon_stop_runtime(tp, WaitNoSleep) < 0) {
+		printk(KERN_ERR "%s: unable to stop runtime\n", dev->name);
+		goto need_resume;
+	}
+
+	typhoon_free_rx_rings(tp);
+	typhoon_init_rings(tp);
+
+	if(typhoon_boot_3XP(tp, TYPHOON_STATUS_WAITING_FOR_HOST) < 0) {
+		printk(KERN_ERR "%s: unable to boot sleep image\n", dev->name);
+		goto need_resume;
+	}
+
+	INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_SET_MAC_ADDRESS);
+	xp_cmd.parm1 = cpu_to_le16(ntohs(*(u16 *)&dev->dev_addr[0]));
+	xp_cmd.parm2 = cpu_to_le32(ntohl(*(u32 *)&dev->dev_addr[2]));
+	if(typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL) < 0) {
+		printk(KERN_ERR "%s: unable to set mac address in suspend\n",
+				dev->name);
+		goto need_resume;
+	}
+
+	INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_SET_RX_FILTER);
+	xp_cmd.parm1 = TYPHOON_RX_FILTER_DIRECTED | TYPHOON_RX_FILTER_BROADCAST;
+	if(typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL) < 0) {
+		printk(KERN_ERR "%s: unable to set rx filter in suspend\n",
+				dev->name);
+		goto need_resume;
+	}
+
+	if(typhoon_sleep(tp, state, tp->wol_events) < 0) {
+		printk(KERN_ERR "%s: unable to put card to sleep\n", dev->name);
+		goto need_resume;
+	}
+
+	return 0;
+
+need_resume:
+	typhoon_resume(pdev);
+	return -EBUSY;
+}
+
+static int
+typhoon_enable_wake(struct pci_dev *pdev, u32 state, int enable)
+{
+	return pci_enable_wake(pdev, state, enable);
+}
+#endif
+
+static int __devinit
+typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	static int did_version = 0;
+	struct net_device *dev;
+	struct typhoon *tp;
+	int card_id = (int) ent->driver_data;
+	unsigned long ioaddr;
+	void *shared;
+	dma_addr_t shared_dma;
+	struct cmd_desc xp_cmd;
+	struct resp_desc xp_resp;
+	int i;
+	int err = 0;
+
+	if(!did_version++)
+		printk(KERN_INFO "%s", version);
+
+	dev = alloc_etherdev(sizeof(*tp));
+	if(dev == NULL) {
+		printk(ERR_PFX "%s: unable to alloc new net device\n",
+		       pdev->slot_name);
+		err = -ENOMEM;
+		goto error_out;
+	}
+	SET_MODULE_OWNER(dev);
+
+	err = pci_enable_device(pdev);
+	if(err < 0) {
+		printk(ERR_PFX "%s: unable to enable device\n",
+		       pdev->slot_name);
+		goto error_out_dev;
+	}
+
+	/* If we transitioned from D3->D0 in pci_enable_device(),
+	 * we lost our configuration and need to restore it to the
+	 * conditions at boot.
+	 */
+	pci_restore_state(pdev, NULL);
+
+	err = pci_set_dma_mask(pdev, 0xffffffffULL);
+	if(err < 0) {
+		printk(ERR_PFX "%s: No usable DMA configuration\n",
+		       pdev->slot_name);
+		goto error_out_dev;
+	}
+
+	/* sanity checks, resource #1 is our mmio area
+	 */
+	if(!(pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) {
+		printk(ERR_PFX
+		       "%s: region #1 not a PCI MMIO resource, aborting\n",
+		       pdev->slot_name);
+		err = -ENODEV;
+		goto error_out_dev;
+	}
+	if(pci_resource_len(pdev, 1) < 128) {
+		printk(ERR_PFX "%s: Invalid PCI MMIO region size, aborting\n",
+		       pdev->slot_name);
+		err = -ENODEV;
+		goto error_out_dev;
+	}
+
+	err = pci_request_regions(pdev, "typhoon");
+	if(err < 0) {
+		printk(ERR_PFX "%s: could not request regions\n",
+		       pdev->slot_name);
+		goto error_out_dev;
+	}
+
+	pci_set_master(pdev);
+	pci_set_mwi(pdev);
+
+	/* map our MMIO region
+	 */
+	ioaddr = pci_resource_start(pdev, 1);
+	ioaddr = (unsigned long) ioremap(ioaddr, 128);
+	if(!ioaddr) {
+		printk(ERR_PFX "%s: cannot remap MMIO, aborting\n",
+		       pdev->slot_name);
+		err = -EIO;
+		goto error_out_regions;
+	}
+	dev->base_addr = ioaddr;
+
+	/* allocate pci dma space for rx and tx descriptor rings
+	 */
+	shared = pci_alloc_consistent(pdev, sizeof(struct typhoon_shared),
+				      &shared_dma);
+	if(!shared) {
+		printk(ERR_PFX "%s: could not allocate DMA memory\n",
+		       pdev->slot_name);
+		err = -ENOMEM;
+		goto error_out_remap;
+	}
+
+	dev->irq = pdev->irq;
+	tp = dev->priv;
+	tp->shared = (struct typhoon_shared *) shared;
+	tp->shared_dma = shared_dma;
+	tp->pdev = pdev;
+	tp->tx_pdev = pdev;
+	tp->ioaddr = dev->base_addr;
+	tp->tx_ioaddr = dev->base_addr;
+	tp->dev = dev;
+
+	/* need to be able to restore PCI state after a suspend */
+	pci_save_state(pdev, tp->pci_state);
+
+	/* Init sequence:
+	 * 1) Reset the adapter to clear any bad juju
+	 * 2) Reload the sleep image
+	 * 3) Boot the sleep image
+	 * 4) Get the hardware address.
+	 * 5) Put the card to sleep.
+	 */
+	if(typhoon_reset(ioaddr, WaitSleep) < 0) {
+		printk(ERR_PFX "%s: could not reset 3XP\n", pdev->slot_name);
+		err = -EIO;
+		goto error_out_dma;
+	}
+
+	/* dev->name is not valid until we register, but we need to
+	 * use some common routines to initialize the card. So that those
+	 * routines print the right name, we keep our oun pointer to the name
+	 */
+	tp->name = pdev->slot_name;
+
+	typhoon_init_interface(tp);
+	typhoon_init_rings(tp);
+
+	if(typhoon_boot_3XP(tp, TYPHOON_STATUS_WAITING_FOR_HOST) < 0) {
+		printk(ERR_PFX "%s: cannot boot 3XP sleep image\n",
+		       pdev->slot_name);
+		err = -EIO;
+		goto error_out_reset;
+	}
+
+	INIT_COMMAND_WITH_RESPONSE(&xp_cmd, TYPHOON_CMD_READ_MAC_ADDRESS);
+	if(typhoon_issue_command(tp, 1, &xp_cmd, 1, &xp_resp) < 0) {
+		printk(ERR_PFX "%s: cannot read MAC address\n",
+		       pdev->slot_name);
+		err = -EIO;
+		goto error_out_reset;
+	}
+
+	*(u16 *)&dev->dev_addr[0] = htons(le16_to_cpu(xp_resp.parm1));
+	*(u32 *)&dev->dev_addr[2] = htonl(le32_to_cpu(xp_resp.parm2));
+
+	if(!is_valid_ether_addr(dev->dev_addr)) {
+		printk(ERR_PFX "%s: Could not obtain valid ethernet address, "
+		       "aborting\n", pdev->slot_name);
+		goto error_out_reset;
+	}
+
+	if(typhoon_sleep(tp, 3, 0) < 0) {
+		printk(ERR_PFX "%s: cannot put adapter to sleep\n",
+		       pdev->slot_name);
+		err = -EIO;
+		goto error_out_reset;
+	}
+
+	tp->capabilities = typhoon_card_info[card_id].capabilities;
+	tp->xcvr_select = TYPHOON_XCVR_AUTONEG;
+
+	/* The chip-specific entries in the device structure. */
+	dev->open		= typhoon_open;
+	dev->hard_start_xmit	= typhoon_start_tx;
+	dev->stop		= typhoon_close;
+	dev->set_multicast_list	= typhoon_set_rx_mode;
+	dev->tx_timeout		= typhoon_tx_timeout;
+	dev->poll		= typhoon_poll;
+	dev->weight		= 16;
+	dev->watchdog_timeo	= TX_TIMEOUT;
+	dev->get_stats		= typhoon_get_stats;
+	dev->set_mac_address	= typhoon_set_mac_address;
+	dev->do_ioctl		= typhoon_ioctl;
+	dev->vlan_rx_register	= typhoon_vlan_rx_register;
+	dev->vlan_rx_kill_vid	= typhoon_vlan_rx_kill_vid;
+
+	/* We can handle scatter gather, up to 16 entries, and
+	 * we can do IP checksumming (only version 4, doh...)
+	 */
+	dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
+	dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+	dev->features |= NETIF_F_TSO;
+
+	if(register_netdev(dev) < 0)
+		goto error_out_reset;
+
+	/* fixup our local name */
+	tp->name = dev->name;
+
+	pci_set_drvdata(pdev, dev);
+
+	printk(KERN_INFO "%s: %s at 0x%lx, ",
+	       dev->name, typhoon_card_info[card_id].name, ioaddr);
+	for(i = 0; i < 5; i++)
+		printk("%2.2x:", dev->dev_addr[i]);
+	printk("%2.2x\n", dev->dev_addr[i]);
+
+	return 0;
+
+error_out_reset:
+	typhoon_reset(ioaddr, NoWait);
+
+error_out_dma:
+	pci_free_consistent(pdev, sizeof(struct typhoon_shared),
+			    shared, shared_dma);
+error_out_remap:
+	iounmap((void *) ioaddr);
+error_out_regions:
+	pci_release_regions(pdev);
+error_out_dev:
+	kfree(dev);
+error_out:
+	return err;
+}
+
+static void __devexit
+typhoon_remove_one(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct typhoon *tp = (struct typhoon *) (dev->priv);
+
+	unregister_netdev(dev);
+	pci_set_power_state(pdev, 0);
+	pci_restore_state(pdev, tp->pci_state);
+	typhoon_reset(dev->base_addr, NoWait);
+	iounmap((char *) (dev->base_addr));
+	pci_free_consistent(pdev, sizeof(struct typhoon_shared),
+			    tp->shared, tp->shared_dma);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+	kfree(dev);
+}
+
+static struct pci_driver typhoon_driver = {
+	.name		= DRV_MODULE_NAME,
+	.id_table	= typhoon_pci_tbl,
+	.probe		= typhoon_init_one,
+	.remove		= __devexit_p(typhoon_remove_one),
+#if CONFIG_PM
+	.suspend	= typhoon_suspend,
+	.resume		= typhoon_resume,
+	.enable_wake	= typhoon_enable_wake,
+#endif
+};
+
+static int __init
+typhoon_init(void)
+{
+	return pci_module_init(&typhoon_driver);
+}
+
+static void __exit
+typhoon_cleanup(void)
+{
+	pci_unregister_driver(&typhoon_driver);
+}
+
+module_init(typhoon_init);
+module_exit(typhoon_cleanup);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/typhoon.h linux-2.4.21-pre6/drivers/net/typhoon.h
--- linux-2.4.20/drivers/net/typhoon.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/typhoon.h	2003-03-26 23:49:20.000000000 +0000
@@ -0,0 +1,613 @@
+/* typhoon.h:	chip info for the 3Com 3CR990 family of controllers */
+/*
+	Written 2002-2003 by David Dillow <dave@thedillows.org>
+
+	This software may be used and distributed according to the terms of
+	the GNU General Public License (GPL), incorporated herein by reference.
+	Drivers based on or derived from this code fall under the GPL and must
+	retain the authorship, copyright and license notice.  This file is not
+	a complete program and may only be used when the entire operating
+	system is licensed under the GPL.
+
+	This software is available on a public web site. It may enable
+	cryptographic capabilities of the 3Com hardware, and may be
+	exported from the United States under License Exception "TSU"
+	pursuant to 15 C.F.R. Section 740.13(e).
+
+	This work was funded by the National Library of Medicine under
+	the Department of Energy project number 0274DD06D1 and NLM project
+	number Y1-LM-2015-01.
+*/
+
+/* All Typhoon ring positions are specificed in bytes, and point to the
+ * first "clean" entry in the ring -- ie the next entry we use for whatever
+ * purpose.
+ */
+
+/* The Typhoon basic ring
+ * ringBase:  where this ring lives (our virtual address)
+ * lastWrite: the next entry we'll use
+ */
+struct basic_ring {
+	u8 *ringBase;
+	u32 lastWrite;
+};
+
+/* The Typoon transmit ring -- same as a basic ring, plus:
+ * lastRead:      where we're at in regard to cleaning up the ring
+ * writeRegister: register to use for writing (different for Hi & Lo rings)
+ */
+struct transmit_ring {
+	u8 *ringBase;
+	u32 lastWrite;
+	u32 lastRead;
+	int writeRegister;
+};
+
+/* The host<->Typhoon ring index structure
+ * This indicates the current positions in the rings
+ * 
+ * All values must be in little endian format for the 3XP
+ *
+ * rxHiCleared:   entry we've cleared to in the Hi receive ring
+ * rxLoCleared:   entry we've cleared to in the Lo receive ring
+ * rxBuffReady:   next entry we'll put a free buffer in
+ * respCleared:   entry we've cleared to in the response ring
+ *
+ * txLoCleared:   entry the NIC has cleared to in the Lo transmit ring
+ * txHiCleared:   entry the NIC has cleared to in the Hi transmit ring
+ * rxLoReady:     entry the NIC has filled to in the Lo receive ring
+ * rxBuffCleared: entry the NIC has cleared in the free buffer ring
+ * cmdCleared:    entry the NIC has cleared in the command ring
+ * respReady:     entry the NIC has filled to in the response ring
+ * rxHiReady:     entry the NIC has filled to in the Hi receive ring
+ */
+struct typhoon_indexes {
+	/* The first four are written by the host, and read by the NIC */
+	volatile u32 rxHiCleared;
+	volatile u32 rxLoCleared;
+	volatile u32 rxBuffReady;
+	volatile u32 respCleared;
+
+	/* The remaining are written by the NIC, and read by the host */
+	volatile u32 txLoCleared;
+	volatile u32 txHiCleared;
+	volatile u32 rxLoReady;
+	volatile u32 rxBuffCleared;
+	volatile u32 cmdCleared;
+	volatile u32 respReady;
+	volatile u32 rxHiReady;
+} __attribute__ ((packed));
+
+/* The host<->Typhoon interface
+ * Our means of communicating where things are
+ *
+ * All values must be in little endian format for the 3XP
+ *
+ * ringIndex:   64 bit bus address of the index structure
+ * txLoAddr:    64 bit bus address of the Lo transmit ring
+ * txLoSize:    size (in bytes) of the Lo transmit ring
+ * txHi*:       as above for the Hi priority transmit ring
+ * rxLo*:       as above for the Lo priority receive ring
+ * rxBuff*:     as above for the free buffer ring
+ * cmd*:        as above for the command ring
+ * resp*:       as above for the response ring
+ * zeroAddr:    64 bit bus address of a zero word (for DMA)
+ * rxHi*:       as above for the Hi Priority receive ring
+ *
+ * While there is room for 64 bit addresses, current versions of the 3XP
+ * only do 32 bit addresses, so the *Hi for each of the above will always
+ * be zero.
+ */
+struct typhoon_interface {
+	u32 ringIndex;
+	u32 ringIndexHi;
+	u32 txLoAddr;
+	u32 txLoAddrHi;
+	u32 txLoSize;
+	u32 txHiAddr;
+	u32 txHiAddrHi;
+	u32 txHiSize;
+	u32 rxLoAddr;
+	u32 rxLoAddrHi;
+	u32 rxLoSize;
+	u32 rxBuffAddr;
+	u32 rxBuffAddrHi;
+	u32 rxBuffSize;
+	u32 cmdAddr;
+	u32 cmdAddrHi;
+	u32 cmdSize;
+	u32 respAddr;
+	u32 respAddrHi;
+	u32 respSize;
+	u32 zeroAddr;
+	u32 zeroAddrHi;
+	u32 rxHiAddr;
+	u32 rxHiAddrHi;
+	u32 rxHiSize;
+} __attribute__ ((packed));
+
+/* The Typhoon transmit/fragment descriptor
+ *
+ * A packet is described by a packet descriptor, followed by option descriptors,
+ * if any, then one or more fragment descriptors.
+ * 
+ * Packet descriptor:
+ * flags:	Descriptor type
+ * len:i	zero, or length of this packet
+ * addr*:	8 bytes of opaque data to the firmware -- for skb pointer
+ * processFlags: Determine offload tasks to perform on this packet.
+ *
+ * Fragment descriptor:
+ * flags:	Descriptor type
+ * len:i	length of this fragment
+ * addr:	low bytes of DMA address for this part of the packet
+ * addrHi:	hi bytes of DMA address for this part of the packet
+ * processFlags: must be zero
+ *
+ * TYPHOON_DESC_VALID is not mentioned in their docs, but their Linux
+ * driver uses it.
+ */
+struct tx_desc {
+	u8  flags;
+#define TYPHOON_TYPE_MASK	0x07
+#define 	TYPHOON_FRAG_DESC	0x00
+#define 	TYPHOON_TX_DESC		0x01
+#define 	TYPHOON_CMD_DESC	0x02
+#define 	TYPHOON_OPT_DESC	0x03
+#define 	TYPHOON_RX_DESC		0x04
+#define 	TYPHOON_RESP_DESC	0x05
+#define TYPHOON_OPT_TYPE_MASK	0xf0
+#define 	TYPHOON_OPT_IPSEC	0x00
+#define 	TYPHOON_OPT_TCP_SEG	0x10
+#define TYPHOON_CMD_RESPOND	0x40
+#define TYPHOON_RESP_ERROR	0x40
+#define TYPHOON_RX_ERROR	0x40
+#define TYPHOON_DESC_VALID	0x80
+	u8  numDesc;
+	u16 len;
+	u32 addr;
+	u32 addrHi;
+	u32 processFlags;
+#define TYPHOON_TX_PF_NO_CRC		__constant_cpu_to_le32(0x00000001)
+#define TYPHOON_TX_PF_IP_CHKSUM		__constant_cpu_to_le32(0x00000002)
+#define TYPHOON_TX_PF_TCP_CHKSUM	__constant_cpu_to_le32(0x00000004)
+#define TYPHOON_TX_PF_TCP_SEGMENT	__constant_cpu_to_le32(0x00000008)
+#define TYPHOON_TX_PF_INSERT_VLAN	__constant_cpu_to_le32(0x00000010)
+#define TYPHOON_TX_PF_IPSEC		__constant_cpu_to_le32(0x00000020)
+#define TYPHOON_TX_PF_VLAN_PRIORITY	__constant_cpu_to_le32(0x00000040)
+#define TYPHOON_TX_PF_UDP_CHKSUM	__constant_cpu_to_le32(0x00000080)
+#define TYPHOON_TX_PF_PAD_FRAME		__constant_cpu_to_le32(0x00000100)
+#define TYPHOON_TX_PF_RESERVED		__constant_cpu_to_le32(0x00000e00)
+#define TYPHOON_TX_PF_VLAN_MASK		__constant_cpu_to_le32(0x0ffff000)
+#define TYPHOON_TX_PF_INTERNAL		__constant_cpu_to_le32(0xf0000000)
+#define TYPHOON_TX_PF_VLAN_TAG_SHIFT	12
+} __attribute__ ((packed));
+
+/* The TCP Segmentation offload option descriptor
+ *
+ * flags:	descriptor type
+ * numDesc:	must be 1
+ * mss_flags:	bits 0-11 (little endian) are MSS, 12 is first TSO descriptor
+ *			13 is list TSO descriptor, set both if only one TSO
+ * respAddrLo:	low bytes of address of the bytesTx field of this descriptor
+ * bytesTx:	total number of bytes in this TSO request
+ * status:	0 on completion
+ */
+struct tcpopt_desc {
+	u8  flags;
+	u8  numDesc;
+	u16 mss_flags;
+#define TYPHOON_TSO_FIRST		__constant_cpu_to_le16(0x1000)
+#define TYPHOON_TSO_LAST		__constant_cpu_to_le16(0x2000)
+	u32 respAddrLo;
+	u32 bytesTx;
+	u32 status;
+} __attribute__ ((packed));
+
+/* The IPSEC Offload descriptor
+ *
+ * flags:	descriptor type
+ * numDesc:	must be 1
+ * ipsecFlags:	bit 0: 0 -- generate IV, 1 -- use supplied IV
+ * sa1, sa2:	Security Association IDs for this packet
+ * reserved:	set to 0
+ */
+struct ipsec_desc {
+	u8  flags;
+	u8  numDesc;
+	u16 ipsecFlags;
+#define TYPHOON_IPSEC_GEN_IV	__constant_cpu_to_le16(0x0000)
+#define TYPHOON_IPSEC_USE_IV	__constant_cpu_to_le16(0x0001)
+	u32 sa1;
+	u32 sa2;
+	u32 reserved;
+} __attribute__ ((packed));
+
+/* The Typhoon receive descriptor (Updated by NIC)
+ *
+ * flags:         Descriptor type, error indication
+ * numDesc:       Always zero
+ * frameLen:      the size of the packet received
+ * addr:          low 32 bytes of the virtual addr passed in for this buffer
+ * addrHi:        high 32 bytes of the virtual addr passed in for this buffer
+ * rxStatus:      Error if set in flags, otherwise result of offload processing
+ * filterResults: results of filtering on packet, not used
+ * ipsecResults:  Results of IPSEC processing
+ * vlanTag:       the 801.2q TCI from the packet
+ */
+struct rx_desc {
+	u8  flags;
+	u8  numDesc;
+	u16 frameLen;
+	u32 addr;
+	u32 addrHi;
+	u32 rxStatus;
+#define TYPHOON_RX_ERR_INTERNAL		__constant_cpu_to_le32(0x00000000)
+#define TYPHOON_RX_ERR_FIFO_UNDERRUN	__constant_cpu_to_le32(0x00000001)
+#define TYPHOON_RX_ERR_BAD_SSD		__constant_cpu_to_le32(0x00000002)
+#define TYPHOON_RX_ERR_RUNT		__constant_cpu_to_le32(0x00000003)
+#define TYPHOON_RX_ERR_CRC		__constant_cpu_to_le32(0x00000004)
+#define TYPHOON_RX_ERR_OVERSIZE		__constant_cpu_to_le32(0x00000005)
+#define TYPHOON_RX_ERR_ALIGN		__constant_cpu_to_le32(0x00000006)
+#define TYPHOON_RX_ERR_DRIBBLE		__constant_cpu_to_le32(0x00000007)
+#define TYPHOON_RX_PROTO_MASK		__constant_cpu_to_le32(0x00000003)
+#define TYPHOON_RX_PROTO_UNKNOWN	__constant_cpu_to_le32(0x00000000)
+#define TYPHOON_RX_PROTO_IP		__constant_cpu_to_le32(0x00000001)
+#define TYPHOON_RX_PROTO_IPX		__constant_cpu_to_le32(0x00000002)
+#define TYPHOON_RX_VLAN			__constant_cpu_to_le32(0x00000004)
+#define TYPHOON_RX_IP_FRAG		__constant_cpu_to_le32(0x00000008)
+#define TYPHOON_RX_IPSEC		__constant_cpu_to_le32(0x00000010)
+#define TYPHOON_RX_IP_CHK_FAIL		__constant_cpu_to_le32(0x00000020)
+#define TYPHOON_RX_TCP_CHK_FAIL		__constant_cpu_to_le32(0x00000040)
+#define TYPHOON_RX_UDP_CHK_FAIL		__constant_cpu_to_le32(0x00000080)
+#define TYPHOON_RX_IP_CHK_GOOD		__constant_cpu_to_le32(0x00000100)
+#define TYPHOON_RX_TCP_CHK_GOOD		__constant_cpu_to_le32(0x00000200)
+#define TYPHOON_RX_UDP_CHK_GOOD		__constant_cpu_to_le32(0x00000400)
+	u16 filterResults;
+#define TYPHOON_RX_FILTER_MASK		__constant_cpu_to_le16(0x7fff)
+#define TYPHOON_RX_FILTERED		__constant_cpu_to_le16(0x8000)
+	u16 ipsecResults;
+#define TYPHOON_RX_OUTER_AH_GOOD	__constant_cpu_to_le16(0x0001)
+#define TYPHOON_RX_OUTER_ESP_GOOD	__constant_cpu_to_le16(0x0002)
+#define TYPHOON_RX_INNER_AH_GOOD	__constant_cpu_to_le16(0x0004)
+#define TYPHOON_RX_INNER_ESP_GOOD	__constant_cpu_to_le16(0x0008)
+#define TYPHOON_RX_OUTER_AH_FAIL	__constant_cpu_to_le16(0x0010)
+#define TYPHOON_RX_OUTER_ESP_FAIL	__constant_cpu_to_le16(0x0020)
+#define TYPHOON_RX_INNER_AH_FAIL	__constant_cpu_to_le16(0x0040)
+#define TYPHOON_RX_INNER_ESP_FAIL	__constant_cpu_to_le16(0x0080)
+#define TYPHOON_RX_UNKNOWN_SA		__constant_cpu_to_le16(0x0100)
+#define TYPHOON_RX_ESP_FORMAT_ERR	__constant_cpu_to_le16(0x0200)
+	u32 vlanTag;
+} __attribute__ ((packed));
+
+/* The Typhoon free buffer descriptor, used to give a buffer to the NIC
+ *
+ * physAddr:    low 32 bits of the bus address of the buffer
+ * physAddrHi:  high 32 bits of the bus address of the buffer, always zero
+ * virtAddr:    low 32 bits of the skb address
+ * virtAddrHi:  high 32 bits of the skb address, always zero
+ *
+ * the virt* address is basically two 32 bit cookies, just passed back
+ * from the NIC
+ */
+struct rx_free {
+	u32 physAddr;
+	u32 physAddrHi;
+	u32 virtAddr;
+	u32 virtAddrHi;
+} __attribute__ ((packed));
+
+/* The Typhoon command descriptor, used for commands and responses
+ *
+ * flags:   descriptor type
+ * numDesc: number of descriptors following in this command/response,
+ *				ie, zero for a one descriptor command
+ * cmd:     the command
+ * seqNo:   sequence number (unused)
+ * parm1:   use varies by command
+ * parm2:   use varies by command
+ * parm3:   use varies by command
+ */
+struct cmd_desc {
+	u8  flags;
+	u8  numDesc;
+	u16 cmd;
+#define TYPHOON_CMD_TX_ENABLE		__constant_cpu_to_le16(0x0001)
+#define TYPHOON_CMD_TX_DISABLE		__constant_cpu_to_le16(0x0002)
+#define TYPHOON_CMD_RX_ENABLE		__constant_cpu_to_le16(0x0003)
+#define TYPHOON_CMD_RX_DISABLE		__constant_cpu_to_le16(0x0004)
+#define TYPHOON_CMD_SET_RX_FILTER	__constant_cpu_to_le16(0x0005)
+#define TYPHOON_CMD_READ_STATS		__constant_cpu_to_le16(0x0007)
+#define TYPHOON_CMD_XCVR_SELECT		__constant_cpu_to_le16(0x0013)
+#define TYPHOON_CMD_SET_MAX_PKT_SIZE	__constant_cpu_to_le16(0x001a)
+#define TYPHOON_CMD_READ_MEDIA_STATUS	__constant_cpu_to_le16(0x001b)
+#define TYPHOON_CMD_GOTO_SLEEP		__constant_cpu_to_le16(0x0023)
+#define TYPHOON_CMD_SET_MULTICAST_HASH	__constant_cpu_to_le16(0x0025)
+#define TYPHOON_CMD_SET_MAC_ADDRESS	__constant_cpu_to_le16(0x0026)
+#define TYPHOON_CMD_READ_MAC_ADDRESS	__constant_cpu_to_le16(0x0027)
+#define TYPHOON_CMD_VLAN_TYPE_WRITE	__constant_cpu_to_le16(0x002b)
+#define TYPHOON_CMD_CREATE_SA		__constant_cpu_to_le16(0x0034)
+#define TYPHOON_CMD_DELETE_SA		__constant_cpu_to_le16(0x0035)
+#define TYPHOON_CMD_READ_VERSIONS	__constant_cpu_to_le16(0x0043)
+#define TYPHOON_CMD_IRQ_COALESCE_CTRL	__constant_cpu_to_le16(0x0045)
+#define TYPHOON_CMD_ENABLE_WAKE_EVENTS	__constant_cpu_to_le16(0x0049)
+#define TYPHOON_CMD_SET_OFFLOAD_TASKS	__constant_cpu_to_le16(0x004f)
+#define TYPHOON_CMD_HELLO_RESP		__constant_cpu_to_le16(0x0057)
+#define TYPHOON_CMD_HALT		__constant_cpu_to_le16(0x005d)
+#define TYPHOON_CMD_READ_IPSEC_INFO	__constant_cpu_to_le16(0x005e)
+#define TYPHOON_CMD_GET_IPSEC_ENABLE	__constant_cpu_to_le16(0x0067)
+#define TYPHOON_CMD_GET_CMD_LVL		__constant_cpu_to_le16(0x0069)
+	u16 seqNo;
+	u16 parm1;
+	u32 parm2;
+	u32 parm3;
+} __attribute__ ((packed));
+
+/* The Typhoon response descriptor, see command descriptor for details
+ */
+struct resp_desc {
+	u8  flags;
+	u8  numDesc;
+	u16 cmd;
+	u16 seqNo;
+	u16 parm1;
+	u32 parm2;
+	u32 parm3;
+} __attribute__ ((packed));
+
+#define INIT_COMMAND_NO_RESPONSE(x, command)				\
+	do { struct cmd_desc *_ptr = (x);				\
+		memset(_ptr, 0, sizeof(struct cmd_desc));		\
+		_ptr->flags = TYPHOON_CMD_DESC | TYPHOON_DESC_VALID;	\
+		_ptr->cmd = command;					\
+	} while(0)
+
+/* We set seqNo to 1 if we're expecting a response from this command */
+#define INIT_COMMAND_WITH_RESPONSE(x, command)				\
+	do { struct cmd_desc *_ptr = (x);				\
+		memset(_ptr, 0, sizeof(struct cmd_desc));		\
+		_ptr->flags = TYPHOON_CMD_RESPOND | TYPHOON_CMD_DESC;	\
+		_ptr->flags |= TYPHOON_DESC_VALID; 			\
+		_ptr->cmd = command;					\
+		_ptr->seqNo = 1;					\
+	} while(0)
+
+/* TYPHOON_CMD_SET_RX_FILTER filter bits (cmd.parm1)
+ */
+#define TYPHOON_RX_FILTER_DIRECTED	__constant_cpu_to_le16(0x0001)
+#define TYPHOON_RX_FILTER_ALL_MCAST	__constant_cpu_to_le16(0x0002)
+#define TYPHOON_RX_FILTER_BROADCAST	__constant_cpu_to_le16(0x0004)
+#define TYPHOON_RX_FILTER_PROMISCOUS	__constant_cpu_to_le16(0x0008)
+#define TYPHOON_RX_FILTER_MCAST_HASH	__constant_cpu_to_le16(0x0010)
+
+/* TYPHOON_CMD_READ_STATS response format
+ */
+struct stats_resp {
+	u8  flags;
+	u8  numDesc;
+	u16 cmd;
+	u16 seqNo;
+	u16 unused;
+	u32 txPackets;
+	u64 txBytes;
+	u32 txDeferred;
+	u32 txLateCollisions;
+	u32 txCollisions;
+	u32 txCarrierLost;
+	u32 txMultipleCollisions;
+	u32 txExcessiveCollisions;
+	u32 txFifoUnderruns;
+	u32 txMulticastTxOverflows;
+	u32 txFiltered;
+	u32 rxPacketsGood;
+	u64 rxBytesGood;
+	u32 rxFifoOverruns;
+	u32 BadSSD;
+	u32 rxCrcErrors;
+	u32 rxOversized;
+	u32 rxBroadcast;
+	u32 rxMulticast;
+	u32 rxOverflow;
+	u32 rxFiltered;
+	u32 linkStatus;
+#define TYPHOON_LINK_STAT_MASK		__constant_cpu_to_le32(0x00000001)
+#define TYPHOON_LINK_GOOD		__constant_cpu_to_le32(0x00000001)
+#define TYPHOON_LINK_BAD		__constant_cpu_to_le32(0x00000000)
+#define TYPHOON_LINK_SPEED_MASK		__constant_cpu_to_le32(0x00000002)
+#define TYPHOON_LINK_100MBPS		__constant_cpu_to_le32(0x00000002)
+#define TYPHOON_LINK_10MBPS		__constant_cpu_to_le32(0x00000000)
+#define TYPHOON_LINK_DUPLEX_MASK	__constant_cpu_to_le32(0x00000004)
+#define TYPHOON_LINK_FULL_DUPLEX	__constant_cpu_to_le32(0x00000004)
+#define TYPHOON_LINK_HALF_DUPLEX	__constant_cpu_to_le32(0x00000000)
+	u32 unused2;
+	u32 unused3;
+} __attribute__ ((packed));
+
+/* TYPHOON_CMD_XCVR_SELECT xcvr values (resp.parm1)
+ */
+#define TYPHOON_XCVR_10HALF	__constant_cpu_to_le16(0x0000)
+#define TYPHOON_XCVR_10FULL	__constant_cpu_to_le16(0x0001)
+#define TYPHOON_XCVR_100HALF	__constant_cpu_to_le16(0x0002)
+#define TYPHOON_XCVR_100FULL	__constant_cpu_to_le16(0x0003)
+#define TYPHOON_XCVR_AUTONEG	__constant_cpu_to_le16(0x0004)
+
+/* TYPHOON_CMD_READ_MEDIA_STATUS (resp.parm1)
+ */
+#define TYPHOON_MEDIA_STAT_CRC_STRIP_DISABLE	__constant_cpu_to_le16(0x0004)
+#define TYPHOON_MEDIA_STAT_COLLISION_DETECT	__constant_cpu_to_le16(0x0010)
+#define TYPHOON_MEDIA_STAT_CARRIER_SENSE	__constant_cpu_to_le16(0x0020)
+#define TYPHOON_MEDIA_STAT_POLARITY_REV		__constant_cpu_to_le16(0x0400)
+#define TYPHOON_MEDIA_STAT_NO_LINK		__constant_cpu_to_le16(0x0800)
+
+/* TYPHOON_CMD_SET_MULTICAST_HASH enable values (cmd.parm1)
+ */
+#define TYPHOON_MCAST_HASH_DISABLE	__constant_cpu_to_le16(0x0000)
+#define TYPHOON_MCAST_HASH_ENABLE	__constant_cpu_to_le16(0x0001)
+#define TYPHOON_MCAST_HASH_SET		__constant_cpu_to_le16(0x0002)
+
+/* TYPHOON_CMD_CREATE_SA descriptor and settings
+ */
+struct sa_descriptor {
+	u8  flags;
+	u8  numDesc;
+	u16 cmd;
+	u16 seqNo;
+	u16 mode;
+#define TYPHOON_SA_MODE_NULL		__constant_cpu_to_le16(0x0000)
+#define TYPHOON_SA_MODE_AH		__constant_cpu_to_le16(0x0001)
+#define TYPHOON_SA_MODE_ESP		__constant_cpu_to_le16(0x0002)
+	u8  hashFlags;
+#define TYPHOON_SA_HASH_ENABLE		0x01
+#define TYPHOON_SA_HASH_SHA1		0x02
+#define TYPHOON_SA_HASH_MD5		0x04
+	u8  direction;
+#define TYPHOON_SA_DIR_RX		0x00
+#define TYPHOON_SA_DIR_TX		0x01
+	u8  encryptionFlags;
+#define TYPHOON_SA_ENCRYPT_ENABLE	0x01
+#define TYPHOON_SA_ENCRYPT_DES		0x02
+#define TYPHOON_SA_ENCRYPT_3DES		0x00
+#define TYPHOON_SA_ENCRYPT_3DES_2KEY	0x00
+#define TYPHOON_SA_ENCRYPT_3DES_3KEY	0x04
+#define TYPHOON_SA_ENCRYPT_CBC		0x08
+#define TYPHOON_SA_ENCRYPT_ECB		0x00
+	u8  specifyIndex;
+#define TYPHOON_SA_SPECIFY_INDEX	0x01
+#define TYPHOON_SA_GENERATE_INDEX	0x00
+	u32 SPI;
+	u32 destAddr;
+	u32 destMask;
+	u8  integKey[20];
+	u8  confKey[24];
+	u32 index;
+	u32 unused;
+	u32 unused2;
+} __attribute__ ((packed));
+
+/* TYPHOON_CMD_SET_OFFLOAD_TASKS bits (cmd.parm2 (Tx) & cmd.parm3 (Rx))
+ * This is all for IPv4.
+ */
+#define TYPHOON_OFFLOAD_TCP_CHKSUM	__constant_cpu_to_le32(0x00000002)
+#define TYPHOON_OFFLOAD_UDP_CHKSUM	__constant_cpu_to_le32(0x00000004)
+#define TYPHOON_OFFLOAD_IP_CHKSUM	__constant_cpu_to_le32(0x00000008)
+#define TYPHOON_OFFLOAD_IPSEC		__constant_cpu_to_le32(0x00000010)
+#define TYPHOON_OFFLOAD_BCAST_THROTTLE	__constant_cpu_to_le32(0x00000020)
+#define TYPHOON_OFFLOAD_DHCP_PREVENT	__constant_cpu_to_le32(0x00000040)
+#define TYPHOON_OFFLOAD_VLAN		__constant_cpu_to_le32(0x00000080)
+#define TYPHOON_OFFLOAD_FILTERING	__constant_cpu_to_le32(0x00000100)
+#define TYPHOON_OFFLOAD_TCP_SEGMENT	__constant_cpu_to_le32(0x00000200)
+
+/* TYPHOON_CMD_ENABLE_WAKE_EVENTS bits (cmd.parm1)
+ */
+#define TYPHOON_WAKE_MAGIC_PKT		__constant_cpu_to_le16(0x01)
+#define TYPHOON_WAKE_LINK_EVENT		__constant_cpu_to_le16(0x02)
+#define TYPHOON_WAKE_ICMP_ECHO		__constant_cpu_to_le16(0x04)
+#define TYPHOON_WAKE_ARP		__constant_cpu_to_le16(0x08)
+
+/* These are used to load the firmware image on the NIC
+ */
+struct typhoon_file_header {
+	u8  tag[8];
+	u32 version;
+	u32 numSections;
+	u32 startAddr;
+} __attribute__ ((packed));
+
+struct typhoon_section_header {
+	u32 len;
+	u16 checksum;
+	u16 reserved;
+	u32 startAddr;
+} __attribute__ ((packed));
+
+/* The Typhoon Register offsets
+ */
+#define TYPHOON_REG_SOFT_RESET			0x00
+#define TYPHOON_REG_INTR_STATUS			0x04
+#define TYPHOON_REG_INTR_ENABLE			0x08
+#define TYPHOON_REG_INTR_MASK			0x0c
+#define TYPHOON_REG_SELF_INTERRUPT		0x10
+#define TYPHOON_REG_HOST2ARM7			0x14
+#define TYPHOON_REG_HOST2ARM6			0x18
+#define TYPHOON_REG_HOST2ARM5			0x1c
+#define TYPHOON_REG_HOST2ARM4			0x20
+#define TYPHOON_REG_HOST2ARM3			0x24
+#define TYPHOON_REG_HOST2ARM2			0x28
+#define TYPHOON_REG_HOST2ARM1			0x2c
+#define TYPHOON_REG_HOST2ARM0			0x30
+#define TYPHOON_REG_ARM2HOST3			0x34
+#define TYPHOON_REG_ARM2HOST2			0x38
+#define TYPHOON_REG_ARM2HOST1			0x3c
+#define TYPHOON_REG_ARM2HOST0			0x40
+
+#define TYPHOON_REG_BOOT_DATA_LO		TYPHOON_REG_HOST2ARM5
+#define TYPHOON_REG_BOOT_DATA_HI		TYPHOON_REG_HOST2ARM4
+#define TYPHOON_REG_BOOT_DEST_ADDR		TYPHOON_REG_HOST2ARM3
+#define TYPHOON_REG_BOOT_CHECKSUM		TYPHOON_REG_HOST2ARM2
+#define TYPHOON_REG_BOOT_LENGTH			TYPHOON_REG_HOST2ARM1
+
+#define TYPHOON_REG_DOWNLOAD_BOOT_ADDR		TYPHOON_REG_HOST2ARM1
+
+#define TYPHOON_REG_BOOT_RECORD_ADDR_HI		TYPHOON_REG_HOST2ARM2
+#define TYPHOON_REG_BOOT_RECORD_ADDR_LO		TYPHOON_REG_HOST2ARM1
+
+#define TYPHOON_REG_TX_LO_READY			TYPHOON_REG_HOST2ARM3
+#define TYPHOON_REG_CMD_READY			TYPHOON_REG_HOST2ARM2
+#define TYPHOON_REG_TX_HI_READY			TYPHOON_REG_HOST2ARM1
+
+#define TYPHOON_REG_COMMAND			TYPHOON_REG_HOST2ARM0
+#define TYPHOON_REG_HEARTBEAT			TYPHOON_REG_ARM2HOST3
+#define TYPHOON_REG_STATUS			TYPHOON_REG_ARM2HOST0
+
+/* 3XP Reset values (TYPHOON_REG_SOFT_RESET)
+ */
+#define TYPHOON_RESET_ALL	0x7f
+#define TYPHOON_RESET_NONE	0x00
+
+/* 3XP irq bits (TYPHOON_REG_INTR{STATUS,ENABLE,MASK})
+ *
+ * Some of these came from OpenBSD, as the 3Com docs have it wrong
+ * (INTR_SELF) or don't list it at all (INTR_*_ABORT)
+ *
+ * Enabling irqs on the Heartbeat reg (ArmToHost3) gets you an irq
+ * about every 8ms, so don't do it.
+ */
+#define TYPHOON_INTR_HOST_INT		0x00000001
+#define TYPHOON_INTR_ARM2HOST0		0x00000002
+#define TYPHOON_INTR_ARM2HOST1		0x00000004
+#define TYPHOON_INTR_ARM2HOST2		0x00000008
+#define TYPHOON_INTR_ARM2HOST3		0x00000010
+#define TYPHOON_INTR_DMA0		0x00000020
+#define TYPHOON_INTR_DMA1		0x00000040
+#define TYPHOON_INTR_DMA2		0x00000080
+#define TYPHOON_INTR_DMA3		0x00000100
+#define TYPHOON_INTR_MASTER_ABORT	0x00000200
+#define TYPHOON_INTR_TARGET_ABORT	0x00000400
+#define TYPHOON_INTR_SELF		0x00000800
+#define TYPHOON_INTR_RESERVED		0xfffff000
+
+#define TYPHOON_INTR_BOOTCMD		TYPHOON_INTR_ARM2HOST0
+
+#define TYPHOON_INTR_ENABLE_ALL		0xffffffef
+#define TYPHOON_INTR_ALL		0xffffffff
+#define TYPHOON_INTR_NONE		0x00000000
+
+/* The commands for the 3XP chip (TYPHOON_REG_COMMAND)
+ */
+#define TYPHOON_BOOTCMD_BOOT			0x00
+#define TYPHOON_BOOTCMD_WAKEUP			0xfa
+#define TYPHOON_BOOTCMD_DNLD_COMPLETE		0xfb
+#define TYPHOON_BOOTCMD_SEG_AVAILABLE		0xfc
+#define TYPHOON_BOOTCMD_RUNTIME_IMAGE		0xfd
+#define TYPHOON_BOOTCMD_REG_BOOT_RECORD		0xff
+
+/* 3XP Status values (TYPHOON_REG_STATUS)
+ */
+#define TYPHOON_STATUS_WAITING_FOR_BOOT		0x07
+#define TYPHOON_STATUS_SECOND_INIT		0x08
+#define TYPHOON_STATUS_RUNNING			0x09
+#define TYPHOON_STATUS_WAITING_FOR_HOST		0x0d
+#define TYPHOON_STATUS_WAITING_FOR_SEGMENT	0x10
+#define TYPHOON_STATUS_SLEEPING			0x11
+#define TYPHOON_STATUS_HALTED			0x14
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/via-rhine.c linux-2.4.21-pre6/drivers/net/via-rhine.c
--- linux-2.4.20/drivers/net/via-rhine.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/via-rhine.c	2003-03-26 23:49:34.000000000 +0000
@@ -98,11 +98,21 @@
  	- location of collision counter is chip specific
  	- allow selecting backoff algorithm (module parameter)
 
+	LK1.1.15 (jgarzik):
+	- Use new MII lib helper generic_mii_ioctl
+
+	LK1.1.16 (Roger Luethi)
+	- Etherleak fix
+	- Handle Tx buffer underrun
+	- Fix bugs in full duplex handling
+	- New reset code uses "force reset" cmd on Rhine-II
+	- Various clean ups
+
 */
 
 #define DRV_NAME	"via-rhine"
-#define DRV_VERSION	"1.1.14"
-#define DRV_RELDATE	"May-3-2002"
+#define DRV_VERSION	"1.1.16"
+#define DRV_RELDATE	"February-15-2003"
 
 
 /* A few user-configurable values.
@@ -392,7 +402,7 @@
 	MIIPhyAddr=0x6C, MIIStatus=0x6D, PCIBusConfig=0x6E,
 	MIICmd=0x70, MIIRegAddr=0x71, MIIData=0x72, MACRegEEcsr=0x74,
 	ConfigA=0x78, ConfigB=0x79, ConfigC=0x7A, ConfigD=0x7B,
-	RxMissed=0x7C, RxCRCErrs=0x7E,
+	RxMissed=0x7C, RxCRCErrs=0x7E, MiscCmd=0x81,
 	StickyHW=0x83, WOLcrClr=0xA4, WOLcgClr=0xA7, PwrcsrClr=0xAC,
 };
 
@@ -413,29 +423,15 @@
 /* Bits in the interrupt status/mask registers. */
 enum intr_status_bits {
 	IntrRxDone=0x0001, IntrRxErr=0x0004, IntrRxEmpty=0x0020,
-	IntrTxDone=0x0002, IntrTxError=0x0008, IntrTxUnderrun=0x0010,
+	IntrTxDone=0x0002, IntrTxError=0x0008, IntrTxUnderrun=0x0210,
 	IntrPCIErr=0x0040,
-	IntrStatsMax=0x0080, IntrRxEarly=0x0100, IntrMIIChange=0x0200,
+	IntrStatsMax=0x0080, IntrRxEarly=0x0100,
 	IntrRxOverflow=0x0400, IntrRxDropped=0x0800, IntrRxNoBuf=0x1000,
 	IntrTxAborted=0x2000, IntrLinkChange=0x4000,
 	IntrRxWakeUp=0x8000,
 	IntrNormalSummary=0x0003, IntrAbnormalSummary=0xC260,
 };
 
-/* MII interface, status flags.
-   Not to be confused with the MIIStatus register ... */
-enum mii_status_bits {
-	MIICap100T4			= 0x8000,
-	MIICap10100HdFd		= 0x7800,
-	MIIPreambleSupr		= 0x0040,
-	MIIAutoNegCompleted	= 0x0020,
-	MIIRemoteFault		= 0x0010,
-	MIICapAutoNeg		= 0x0008,
-	MIILink				= 0x0004,
-	MIIJabber			= 0x0002,
-	MIIExtended			= 0x0001
-};
-
 /* The Rx and Tx buffer descriptors. */
 struct rx_desc {
 	s32 rx_status;
@@ -530,30 +526,29 @@
 static struct net_device_stats *via_rhine_get_stats(struct net_device *dev);
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static int  via_rhine_close(struct net_device *dev);
-static inline void clear_tally_counters(long ioaddr);
-static inline void via_restart_tx(struct net_device *dev);
 
 static void wait_for_reset(struct net_device *dev, int chip_id, char *name)
 {
 	long ioaddr = dev->base_addr;
-	int i;
 
-	/* VT86C100A may need long delay after reset (dlink) */
-	if (chip_id == VT86C100A)
+	udelay(5);
+
+	if (readw(ioaddr + ChipCmd) & CmdReset) {
+		printk(KERN_INFO "%s: Reset did not complete in 5 us. "
+			"Trying harder.\n", name);
+
+		/* Rhine-II needs to be forced sometimes */
+		if (chip_id == VT6102)
+			writeb(0x40, ioaddr + MiscCmd);
+
+		/* VT86C100A may need long delay after reset (dlink) */
+		/* Seen on Rhine-II as well (rl) */
 		udelay(100);
+	}
 
-	i = 0;
-	do {
-		udelay(5);
-		i++;
-		if(i > 2000) {
-			printk(KERN_ERR "%s: reset did not complete in 10 ms.\n", name);
-			break;
-		}
-	} while(readw(ioaddr + ChipCmd) & CmdReset);
 	if (debug > 1)
-		printk(KERN_INFO "%s: reset finished after %d microseconds.\n",
-			   name, 5*i);
+		printk(KERN_INFO "%s: Reset %s.\n", name,
+			(readw(ioaddr + ChipCmd) & CmdReset) ? "failed" : "succeeded");
 }
 
 #ifdef USE_MEM
@@ -739,21 +734,6 @@
 	if (dev->mem_start)
 		option = dev->mem_start;
 
-	/* The lower four bits are the media type. */
-	if (option > 0) {
-		if (option & 0x200)
-			np->mii_if.full_duplex = 1;
-		np->default_port = option & 15;
-	}
-	if (card_idx < MAX_UNITS  &&  full_duplex[card_idx] > 0)
-		np->mii_if.full_duplex = 1;
-
-	if (np->mii_if.full_duplex) {
-		printk(KERN_INFO "%s: Set to forced full duplex, autonegotiation"
-			   " disabled.\n", dev->name);
-		np->mii_if.force_media = 1;
-	}
-
 	/* The chip-specific entries in the device structure. */
 	dev->open = via_rhine_open;
 	dev->hard_start_xmit = via_rhine_start_tx;
@@ -765,11 +745,27 @@
 	dev->watchdog_timeo = TX_TIMEOUT;
 	if (np->drv_flags & ReqTxAlign)
 		dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM;
-	
+
+	/* dev->name not defined before register_netdev()! */
 	i = register_netdev(dev);
 	if (i)
 		goto err_out_unmap;
 
+	/* The lower four bits are the media type. */
+	if (option > 0) {
+		if (option & 0x220)
+			np->mii_if.full_duplex = 1;
+		np->default_port = option & 15;
+	}
+	if (card_idx < MAX_UNITS  &&  full_duplex[card_idx] > 0)
+		np->mii_if.full_duplex = 1;
+
+	if (np->mii_if.full_duplex) {
+		printk(KERN_INFO "%s: Set to forced full duplex, autonegotiation"
+			   " disabled.\n", dev->name);
+		np->mii_if.force_media = 1;
+	}
+
 	printk(KERN_INFO "%s: %s at 0x%lx, ",
 		   dev->name, via_rhine_chip_info[chip_id].name,
 		   (pci_flags & PCI_USES_IO) ? ioaddr : memaddr);
@@ -794,7 +790,7 @@
 					   mdio_read(dev, phy, 5));
 
 				/* set IFF_RUNNING */
-				if (mii_status & MIILink)
+				if (mii_status & BMSR_LSTATUS)
 					netif_carrier_on(dev);
 				else
 					netif_carrier_off(dev);
@@ -1005,6 +1001,7 @@
 	writeb(0x20, ioaddr + TxConfig);
 	np->tx_thresh = 0x20;
 	np->rx_thresh = 0x60;			/* Written in via_rhine_set_rx_mode(). */
+	np->mii_if.full_duplex = 0;
 
 	if (dev->if_port == 0)
 		dev->if_port = np->default_port;
@@ -1018,7 +1015,7 @@
 	writew(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow |
 		   IntrRxDropped | IntrRxNoBuf | IntrTxAborted |
 		   IntrTxDone | IntrTxError | IntrTxUnderrun |
-		   IntrPCIErr | IntrStatsMax | IntrLinkChange | IntrMIIChange,
+		   IntrPCIErr | IntrStatsMax | IntrLinkChange,
 		   ioaddr + IntrEnable);
 
 	np->chip_cmd = CmdStart|CmdTxOn|CmdRxOn|CmdNoTxPoll;
@@ -1172,8 +1169,8 @@
 
 	/* make IFF_RUNNING follow the MII status bit "Link established" */
 	mii_status = mdio_read(dev, np->phys[0], MII_BMSR);
-	if ( (mii_status & MIILink) != (np->mii_status & MIILink) ) {
-		if (mii_status & MIILink)
+	if ( (mii_status & BMSR_LSTATUS) != (np->mii_status & BMSR_LSTATUS) ) {
+		if (mii_status & BMSR_LSTATUS)
 			netif_carrier_on(dev);
 		else
 			netif_carrier_off(dev);
@@ -1236,6 +1233,12 @@
 	/* Calculate the next Tx descriptor entry. */
 	entry = np->cur_tx % TX_RING_SIZE;
 
+	if (skb->len < ETH_ZLEN) {
+		skb = skb_padto(skb, ETH_ZLEN);
+		if(skb == NULL)
+			return 0;
+	}
+
 	np->tx_skbuff[entry] = skb;
 
 	if ((np->drv_flags & ReqTxAlign) &&
@@ -1317,7 +1320,7 @@
 			via_rhine_tx(dev);
 
 		/* Abnormal error summary/uncommon events handlers. */
-		if (intr_status & (IntrPCIErr | IntrLinkChange | IntrMIIChange |
+		if (intr_status & (IntrPCIErr | IntrLinkChange |
 				   IntrStatsMax | IntrTxError | IntrTxAborted |
 				   IntrTxUnderrun))
 			via_rhine_error(dev, intr_status);
@@ -1405,8 +1408,8 @@
 	int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx;
 
 	if (debug > 4) {
-		printk(KERN_DEBUG " In via_rhine_rx(), entry %d status %8.8x.\n",
-			   entry, le32_to_cpu(np->rx_head_desc->rx_status));
+		printk(KERN_DEBUG "%s: via_rhine_rx(), entry %d status %8.8x.\n",
+			   dev->name, entry, le32_to_cpu(np->rx_head_desc->rx_status));
 	}
 
 	/* If EOP is set on the next entry, it's a new packet. Send it up. */
@@ -1512,7 +1515,18 @@
 	writew(CmdRxDemand | np->chip_cmd, dev->base_addr + ChipCmd);
 }
 
-static inline void via_restart_tx(struct net_device *dev) {
+/* Clears the "tally counters" for CRC errors and missed frames(?).
+   It has been reported that some chips need a write of 0 to clear
+   these, for others the counters are set to 1 when written to and
+   instead cleared when read. So we clear them both ways ... */
+static inline void clear_tally_counters(const long ioaddr)
+{
+	writel(0, ioaddr + RxMissed);
+	readw(ioaddr + RxCRCErrs);
+	readw(ioaddr + RxMissed);
+}
+
+static inline void via_rhine_restart_tx(struct net_device *dev) {
 	struct netdev_private *np = dev->priv;
 	int entry = np->dirty_tx % TX_RING_SIZE;
 
@@ -1530,7 +1544,7 @@
 
 	spin_lock (&np->lock);
 
-	if (intr_status & (IntrMIIChange | IntrLinkChange)) {
+	if (intr_status & (IntrLinkChange)) {
 		if (readb(ioaddr + MIIStatus) & 0x02) {
 			/* Link failed, restart autonegotiation. */
 			if (np->drv_flags & HasDavicomPhy)
@@ -1548,11 +1562,11 @@
 		np->stats.rx_missed_errors	+= readw(ioaddr + RxMissed);
 		clear_tally_counters(ioaddr);
 	}
-	if (intr_status & IntrTxError) {
+	if (intr_status & IntrTxAborted) {
 		if (debug > 1)
 			printk(KERN_INFO "%s: Abort %4.4x, frame dropped.\n",
 				   dev->name, intr_status);
-		via_restart_tx(dev);
+		via_rhine_restart_tx(dev);
 	}
 	if (intr_status & IntrTxUnderrun) {
 		if (np->tx_thresh < 0xE0)
@@ -1561,9 +1575,9 @@
 			printk(KERN_INFO "%s: Transmitter underrun, Tx "
 				   "threshold now %2.2x.\n",
 				   dev->name, np->tx_thresh);
-		via_restart_tx(dev);
+		via_rhine_restart_tx(dev);
 	}
-	if (intr_status & ~( IntrLinkChange | IntrStatsMax |
+	if (intr_status & ~( IntrLinkChange | IntrStatsMax | IntrTxUnderrun |
  						 IntrTxError | IntrTxAborted | IntrNormalSummary)) {
 		if (debug > 1)
 			printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n",
@@ -1590,17 +1604,6 @@
 	return &np->stats;
 }
 
-/* Clears the "tally counters" for CRC errors and missed frames(?).
-   It has been reported that some chips need a write of 0 to clear
-   these, for others the counters are set to 1 when written to and
-   instead cleared when read. So we clear them both ways ... */
-static inline void clear_tally_counters(const long ioaddr)
-{
-	writel(0, ioaddr + RxMissed);
-	readw(ioaddr + RxCRCErrs);
-	readw(ioaddr + RxMissed);
-}
-
 static void via_rhine_set_rx_mode(struct net_device *dev)
 {
 	struct netdev_private *np = dev->priv;
@@ -1794,10 +1797,10 @@
 
 
 static struct pci_driver via_rhine_driver = {
-	name:		"via-rhine",
-	id_table:	via_rhine_pci_tbl,
-	probe:		via_rhine_init_one,
-	remove:		__devexit_p(via_rhine_remove_one),
+	.name		= "via-rhine",
+	.id_table	= via_rhine_pci_tbl,
+	.probe		= via_rhine_init_one,
+	.remove		= __devexit_p(via_rhine_remove_one),
 };
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/wan/8253x/8253xtty.c linux-2.4.21-pre6/drivers/net/wan/8253x/8253xtty.c
--- linux-2.4.20/drivers/net/wan/8253x/8253xtty.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/wan/8253x/8253xtty.c	2003-03-26 23:49:40.000000000 +0000
@@ -2131,7 +2131,7 @@
 	/* Check whether or not the port is open in SYNC mode */
 	if(port->open_type == OPEN_SYNC_NET)
 	{
-		if(port->dev && netif_carrier_ok(port->dev));
+		if(port->dev && netif_carrier_ok(port->dev))
 		{
 			port->tty= NULL;	/* Don't bother with open counting here
 						   but make sure the tty field is NULL*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/wan/Config.in linux-2.4.21-pre6/drivers/net/wan/Config.in
--- linux-2.4.20/drivers/net/wan/Config.in	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/wan/Config.in	2003-03-26 23:49:07.000000000 +0000
@@ -44,9 +44,6 @@
 
    dep_tristate '  Etinc PCISYNC serial board support (EXPERIMENTAL)' CONFIG_DSCC4 m
 
-# FarSite Communications' cards
-
-   tristate '  FarSync T-Series X.21 (and V.35/V.24) cards' CONFIG_FARSYNC
 
 #
 # Lan Media's board. Currently 1000, 1200, 5200, 5245
@@ -66,8 +63,13 @@
 
    tristate '  SyncLink HDLC/SYNCPPP support' CONFIG_SYNCLINK_SYNCPPP
 
-   tristate '  Generic HDLC driver' CONFIG_HDLC
+# Generic HDLC
+
+   tristate '  Generic HDLC layer' CONFIG_HDLC
    if [ "$CONFIG_HDLC" != "n" ]; then
+      bool '    Raw HDLC support' CONFIG_HDLC_RAW
+      bool '    Cisco HDLC support' CONFIG_HDLC_CISCO
+      bool '    Frame Relay support' CONFIG_HDLC_FR
       bool '    Synchronous Point-to-Point Protocol (PPP) support' CONFIG_HDLC_PPP
       if [ "$CONFIG_LAPB" = "m" -a "$CONFIG_HDLC" = "m" -o "$CONFIG_LAPB" = "y" ]; then
 	 bool '    X.25 protocol support' CONFIG_HDLC_X25
@@ -76,6 +78,11 @@
       fi
       dep_tristate '    SDL RISCom/N2 support' CONFIG_N2 $CONFIG_HDLC
       dep_tristate '    Moxa C101 support' CONFIG_C101 $CONFIG_HDLC
+      dep_tristate '    FarSync T-Series support' CONFIG_FARSYNC $CONFIG_HDLC
+      bool '    Debug received/transmitted packets' CONFIG_HDLC_DEBUG_PKT
+      bool '    Debug hard_header routines' CONFIG_HDLC_DEBUG_HARD_HEADER
+      bool '    Debug FECN/BECN conditions' CONFIG_HDLC_DEBUG_ECN
+      bool '    Debug RX/TX packet rings' CONFIG_HDLC_DEBUG_RINGS
    fi
 
    tristate '  Frame relay DLCI support' CONFIG_DLCI
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/wan/Makefile linux-2.4.21-pre6/drivers/net/wan/Makefile
--- linux-2.4.20/drivers/net/wan/Makefile	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/wan/Makefile	2003-03-26 23:49:40.000000000 +0000
@@ -9,7 +9,7 @@
 
 O_TARGET := wan.o
 
-export-objs =	z85230.o syncppp.o comx.o sdladrv.o cycx_drv.o hdlc.o
+export-objs =	z85230.o syncppp.o comx.o sdladrv.o cycx_drv.o hdlc_generic.o
 list-multi =	wanpipe.o cyclomx.o
 
 wanpipe-objs = sdlamain.o sdla_ft1.o $(wanpipe-y)
@@ -22,6 +22,13 @@
 cyclomx-objs = cycx_main.o $(cyclomx-y)  
 cyclomx-$(CONFIG_CYCLOMX_X25)	+= cycx_x25.o
 
+hdlc-y				:= hdlc_generic.o
+hdlc-$(CONFIG_HDLC_RAW)		+= hdlc_raw.o
+hdlc-$(CONFIG_HDLC_CISCO)	+= hdlc_cisco.o
+hdlc-$(CONFIG_HDLC_FR)		+= hdlc_fr.o
+hdlc-$(CONFIG_HDLC_PPP)		+= hdlc_ppp.o
+hdlc-$(CONFIG_HDLC_X25)		+= hdlc_x25.o
+hdlc-objs			:= $(hdlc-y)
 
 obj-$(CONFIG_HOSTESS_SV11)	+= z85230.o	syncppp.o	hostess_sv11.o
 obj-$(CONFIG_SEALEVEL_4021)	+= z85230.o	syncppp.o	sealevel.o
@@ -64,12 +71,17 @@
 obj-$(CONFIG_LAPBETHER)		+= lapbether.o
 obj-$(CONFIG_SBNI)		+= sbni.o
 obj-$(CONFIG_HDLC)		+= hdlc.o
-obj-$(CONFIG_HDLC_PPP)		+= syncppp.o
+ifeq ($(CONFIG_HDLC_PPP),y)
+  obj-$(CONFIG_HDLC)		+= syncppp.o
+endif
 obj-$(CONFIG_N2)		+= n2.o
 obj-$(CONFIG_C101)		+= c101.o
 
 include $(TOPDIR)/Rules.make
 
+hdlc.o: $(hdlc-objs)
+	$(LD) -r -o $@ $(hdlc-objs)
+
 wanpipe.o: $(wanpipe-objs)
 	$(LD) -r -o $@ $(wanpipe-objs)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/wan/c101.c linux-2.4.21-pre6/drivers/net/wan/c101.c
--- linux-2.4.20/drivers/net/wan/c101.c	2001-09-13 23:04:43.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/wan/c101.c	2003-03-26 23:49:16.000000000 +0000
@@ -1,7 +1,7 @@
 /*
  * Moxa C101 synchronous serial card driver for Linux
  *
- * Copyright (C) 2000 Krzysztof Halasa <khc@pm.waw.pl>
+ * Copyright (C) 2000-2002 Krzysztof Halasa <khc@pm.waw.pl>
  *
  * 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
@@ -15,6 +15,7 @@
  *    Moxa C101 User's Manual
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
@@ -29,10 +30,8 @@
 
 #include "hd64570.h"
 
-#define DEBUG_RINGS
-/* #define DEBUG_PKT */
 
-static const char* version = "Moxa C101 driver revision: 1.02 for Linux 2.4";
+static const char* version = "Moxa C101 driver version: 1.10";
 static const char* devname = "C101";
 
 #define C101_PAGE 0x1D00
@@ -51,12 +50,12 @@
 typedef struct card_s {
 	hdlc_device hdlc;	/* HDLC device struct - must be first */
 	spinlock_t lock;	/* TX lock */
-	int clkmode;		/* clock mode */
-	int clkrate;		/* clock speed */
-	int line;		/* loopback only */
 	u8 *win0base;		/* ISA window base address */
 	u32 phy_winbase;	/* ISA physical base address */
 	u16 buff_offset;	/* offset of first buffer of first channel */
+	sync_serial_settings settings;
+	unsigned short encoding;
+	unsigned short parity;
 	u8 rxs, txs, tmc;	/* SCA registers */
 	u8 irq;			/* IRQ (3-15) */
 	u8 ring_buffers;	/* number of buffers in a ring */
@@ -72,6 +71,9 @@
 
 typedef card_t port_t;
 
+static card_t *first_card;
+static card_t **new_card = &first_card;
+
 
 #define sca_in(reg, card)	   readb((card)->win0base + C101_SCA + (reg))
 #define sca_out(value, reg, card)  writeb(value, (card)->win0base + C101_SCA + (reg))
@@ -105,18 +107,13 @@
 #include "hd6457x.c"
 
 
-static int c101_set_clock(port_t *port, int value)
+static void c101_set_iface(port_t *port)
 {
 	u8 msci = get_msci(port);
 	u8 rxs = port->rxs & CLK_BRG_MASK;
 	u8 txs = port->txs & CLK_BRG_MASK;
 
-	switch(value) {
-	case CLOCK_EXT:
-		rxs |= CLK_LINE_RX; /* RXC input */
-		txs |= CLK_LINE_TX; /* TXC input */
-		break;
-
+	switch(port->settings.clock_type) {
 	case CLOCK_INT:
 		rxs |= CLK_BRG_RX; /* TX clock */
 		txs |= CLK_RXCLK_TX; /* BRG output */
@@ -132,84 +129,100 @@
 		txs |= CLK_RXCLK_TX; /* RX clock */
 		break;
 
-	default:
-		return -EINVAL;
+	default:	/* EXTernal clock */
+		rxs |= CLK_LINE_RX; /* RXC input */
+		txs |= CLK_LINE_TX; /* TXC input */
 	}
 
 	port->rxs = rxs;
 	port->txs = txs;
 	sca_out(rxs, msci + RXS, port);
 	sca_out(txs, msci + TXS, port);
-	port->clkmode = value;
-	return 0;
+	sca_set_port(port);
 }
 
 
-static int c101_open(hdlc_device *hdlc)
+static int c101_open(struct net_device *dev)
 {
+	hdlc_device *hdlc = dev_to_hdlc(dev);
 	port_t *port = hdlc_to_port(hdlc);
+	int result = hdlc_open(hdlc);
+	if (result)
+		return result;
 
 	MOD_INC_USE_COUNT;
 	writeb(1, port->win0base + C101_DTR);
 	sca_out(0, MSCI1_OFFSET + CTL, port); /* RTS uses ch#2 output */
 	sca_open(hdlc);
-	c101_set_clock(port, port->clkmode);
+	c101_set_iface(port);
 	return 0;
 }
 
 
-static void c101_close(hdlc_device *hdlc)
+static int c101_close(struct net_device *dev)
 {
+	hdlc_device *hdlc = dev_to_hdlc(dev);
 	port_t *port = hdlc_to_port(hdlc);
 
 	sca_close(hdlc);
 	writeb(0, port->win0base + C101_DTR);
 	sca_out(CTL_NORTS, MSCI1_OFFSET + CTL, port);
+	hdlc_close(hdlc);
 	MOD_DEC_USE_COUNT;
+	return 0;
 }
 
 
-static int c101_ioctl(hdlc_device *hdlc, struct ifreq *ifr, int cmd)
+static int c101_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
-	int value = ifr->ifr_ifru.ifru_ivalue;
-	int result = 0;
+	const size_t size = sizeof(sync_serial_settings);
+	sync_serial_settings new_line, *line = ifr->ifr_settings.ifs_ifsu.sync;
+	hdlc_device *hdlc = dev_to_hdlc(dev);
 	port_t *port = hdlc_to_port(hdlc);
 
-	if(!capable(CAP_NET_ADMIN))
-		return -EPERM;
+#ifdef CONFIG_HDLC_DEBUG_RINGS
+	if (cmd == SIOCDEVPRIVATE) {
+		sca_dump_rings(hdlc);
+		return 0;
+	}
+#endif
+	if (cmd != SIOCWANDEV)
+		return hdlc_ioctl(dev, ifr, cmd);
 
-	switch(cmd) {
-	case HDLCSCLOCK:
-		result = c101_set_clock(port, value);
-	case HDLCGCLOCK:
-		value = port->clkmode;
-		break;
+	switch(ifr->ifr_settings.type) {
+	case IF_GET_IFACE:
+		ifr->ifr_settings.type = IF_IFACE_SYNC_SERIAL;
+		if (ifr->ifr_settings.size < size) {
+			ifr->ifr_settings.size = size; /* data size wanted */
+			return -ENOBUFS;
+		}
+		if (copy_to_user(line, &port->settings, size))
+			return -EFAULT;
+		return 0;
 
-	case HDLCSCLOCKRATE:
-		port->clkrate = value;
-		sca_set_clock(port);
-	case HDLCGCLOCKRATE:
-		value = port->clkrate;
-		break;
+	case IF_IFACE_SYNC_SERIAL:
+		if(!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
+		if (copy_from_user(&new_line, line, size))
+			return -EFAULT;
+
+		if (new_line.clock_type != CLOCK_EXT &&
+		    new_line.clock_type != CLOCK_TXFROMRX &&
+		    new_line.clock_type != CLOCK_INT &&
+		    new_line.clock_type != CLOCK_TXINT)
+		return -EINVAL;	/* No such clock setting */
 
-	case HDLCSLINE:
-		result = sca_set_loopback(port, value);
-	case HDLCGLINE:
-		value = port->line;
-		break;
+		if (new_line.loopback != 0 && new_line.loopback != 1)
+			return -EINVAL;
 
-#ifdef DEBUG_RINGS
-	case HDLCRUN:
-		sca_dump_rings(hdlc);
+		memcpy(&port->settings, &new_line, size); /* Update settings */
+		c101_set_iface(port);
 		return 0;
-#endif /* DEBUG_RINGS */
 
 	default:
-		return -EINVAL;
+		return hdlc_ioctl(dev, ifr, cmd);
 	}
-
-	ifr->ifr_ifru.ifru_ivalue = value;
-	return result;
 }
 
 
@@ -231,6 +244,7 @@
 
 static int c101_run(unsigned long irq, unsigned long winbase)
 {
+	struct net_device *dev;
 	card_t *card;
 	int result;
 
@@ -284,15 +298,19 @@
 
 	sca_init(card, 0);
 
+	dev = hdlc_to_dev(&card->hdlc);
+
 	spin_lock_init(&card->lock);
-	hdlc_to_dev(&card->hdlc)->irq = irq;
-	hdlc_to_dev(&card->hdlc)->mem_start = winbase;
-	hdlc_to_dev(&card->hdlc)->mem_end = winbase + C101_MAPPED_RAM_SIZE - 1;
-	hdlc_to_dev(&card->hdlc)->tx_queue_len = 50;
-	card->hdlc.ioctl = c101_ioctl;
-	card->hdlc.open = c101_open;
-	card->hdlc.close = c101_close;
+	dev->irq = irq;
+	dev->mem_start = winbase;
+	dev->mem_end = winbase + C101_MAPPED_RAM_SIZE - 1;
+	dev->tx_queue_len = 50;
+	dev->do_ioctl = c101_ioctl;
+	dev->open = c101_open;
+	dev->stop = c101_close;
+	card->hdlc.attach = sca_attach;
 	card->hdlc.xmit = sca_xmit;
+	card->settings.clock_type = CLOCK_EXT;
 
 	result = register_hdlc_device(&card->hdlc);
 	if (result) {
@@ -319,7 +337,7 @@
 		return -ENOSYS;	/* no parameters specified, abort */
 	}
 
-	printk(KERN_INFO "%s\n", version);
+	printk(KERN_INFO "%s (SCA-%s)\n", version, sca_version);
 
 	do {
 		unsigned long irq, ram;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/wan/comx-hw-mixcom.c linux-2.4.21-pre6/drivers/net/wan/comx-hw-mixcom.c
--- linux-2.4.20/drivers/net/wan/comx-hw-mixcom.c	2001-12-21 17:41:54.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/wan/comx-hw-mixcom.c	2003-03-26 23:49:34.000000000 +0000
@@ -102,7 +102,7 @@
 	unsigned char cec;
 	unsigned delay = 0;
 
-	while ((cec = (rd_hscx(dev, HSCX_STAR) & HSCX_CEC) != 0) && 
+	while ((cec = (rd_hscx(dev, HSCX_STAR) & HSCX_CEC)) != 0 && 
 	    (jiffs + HZ > jiffies)) {
 		udelay(1);
 		if (++delay > (100000 / HZ)) break;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/wan/comx-hw-munich.c linux-2.4.21-pre6/drivers/net/wan/comx-hw-munich.c
--- linux-2.4.20/drivers/net/wan/comx-hw-munich.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/wan/comx-hw-munich.c	2003-03-26 23:49:39.000000000 +0000
@@ -269,7 +269,7 @@
 				   - Path Code Violations >1, but <320
 				   - not a Severely Errored Second
 				   - no AIS
-				   - not incremented during an Unavailabla Second                       */
+				   - not incremented during an Unavailable Second                       */
       severely_err_secs,	/* Severely Errored Second:
 				   - CRC4: >=832 Path COde Violations || >0 Out Of Frame defects
 				   - noCRC4: >=2048 Line Code Violations
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/wan/dscc4.c linux-2.4.21-pre6/drivers/net/wan/dscc4.c
--- linux-2.4.20/drivers/net/wan/dscc4.c	2001-11-09 21:41:42.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/wan/dscc4.c	2003-03-26 23:49:19.000000000 +0000
@@ -1,8 +1,8 @@
 /*
- * drivers/net/wan/dscc4/dscc4_main.c: a DSCC4 HDLC driver for Linux
+ * drivers/net/wan/dscc4/dscc4.c: a DSCC4 HDLC driver for Linux
  *
- * This software may be used and distributed according to the terms of the 
- * GNU General Public License. 
+ * This software may be used and distributed according to the terms of the
+ * GNU General Public License.
  *
  * The author may be reached as romieu@cogenit.fr.
  * Specific bug reports/asian food will be welcome.
@@ -16,11 +16,12 @@
  * I. Board Compatibility
  *
  * This device driver is designed for the Siemens PEB20534 4 ports serial
- * controller as found on Etinc PCISYNC cards. The documentation for the 
+ * controller as found on Etinc PCISYNC cards. The documentation for the
  * chipset is available at http://www.infineon.com:
  * - Data Sheet "DSCC4, DMA Supported Serial Communication Controller with
  * 4 Channels, PEB 20534 Version 2.1, PEF 20534 Version 2.1";
  * - Application Hint "Management of DSCC4 on-chip FIFO resources".
+ * - Errata sheet DS5 (courtesy of Michael Skerritt).
  * Jens David has built an adapter based on the same chipset. Take a look
  * at http://www.afthd.tu-darmstadt.de/~dg1kjd/pciscc4 for a specific
  * driver.
@@ -37,15 +38,13 @@
  *
  * III. Driver operation
  *
- * The rx/tx operations are based on a linked list of descriptor. I haven't
- * tried the start/stop descriptor method as this one looks like the cheapest
- * in terms of PCI manipulation.
+ * The rx/tx operations are based on a linked list of descriptors. The driver
+ * doesn't use HOLD mode any more. HOLD mode is definitely buggy and the more
+ * I tried to fix it, the more it started to look like (convoluted) software
+ * mutation of LxDA method. Errata sheet DS5 suggests to use LxDA: consider
+ * this a rfc2119 MUST.
  *
  * Tx direction
- * Once the data section of the current descriptor processed, the next linked
- * descriptor is loaded if the HOLD bit isn't set in the current descriptor.
- * If HOLD is met, the transmission is stopped until the host unsets it and
- * signals the change via TxPOLL.
  * When the tx ring is full, the xmit routine issues a call to netdev_stop.
  * The device is supposed to be enabled again during an ALLS irq (we could
  * use HI but as it's easy to loose events, it's fscked).
@@ -55,12 +54,6 @@
  * I may implement it some day but it isn't the highest ranked item.
  *
  * IV. Notes
- * The chipset is buggy. Typically, under some specific load patterns (I
- * wouldn't call them "high"), the irq queues and the descriptors look like
- * some event has been lost. Even assuming some fancy PCI feature, it won't 
- * explain the reproductible missing "C" bit in the descriptors. Faking an 
- * irq in the periodic timer isn't really elegant but at least it seems 
- * reliable.
  * The current error (XDU, RFO) recovery code is untested.
  * So far, RDO takes his RX channel down and the right sequence to enable it
  * again is still a mistery. If RDO happens, plan a reboot. More details
@@ -69,21 +62,29 @@
  * suggest it for DCE either but at least one can get some messages instead
  * of a complete instant freeze.
  * Tests are done on Rev. 20 of the silicium. The RDO handling changes with
- * the documentation/chipset releases. An on-line errata would be welcome.
+ * the documentation/chipset releases.
  *
  * TODO:
- * - some trivial error lurk,
- * - the stats are fscked,
+ * - test X25.
  * - use polling at high irq/s,
  * - performance analysis,
  * - endianness.
  *
+ * 2001/12/10	Daniela Squassoni  <daniela@cyclades.com>
+ * - Contribution to support the new generic HDLC layer.
+ *
+ * 2002/01	Ueimor
+ * - old style interface removal
+ * - dscc4_release_ring fix (related to DMA mapping)
+ * - hard_start_xmit fix (hint: TxSizeMax)
+ * - misc crapectomy.
  */
 
 #include <linux/version.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/errno.h>
+#include <linux/list.h>
 #include <linux/ioport.h>
 #include <linux/pci.h>
 #include <linux/kernel.h>
@@ -107,23 +108,37 @@
 #include <linux/hdlc.h>
 
 /* Version */
-static const char version[] = "$Id: dscc4.c,v 1.130 2001/02/25 15:27:34 romieu Exp $\n";
+static const char version[] = "$Id: dscc4.c,v 1.159 2002/04/10 22:05:17 romieu Exp $ for Linux\n";
 static int debug;
+static int quartz;
+
+#define	DRV_NAME	"dscc4"
 
+#undef DSCC4_POLLING
 
 /* Module parameters */
+
 MODULE_AUTHOR("Maintainer: Francois Romieu <romieu@cogenit.fr>");
-MODULE_DESCRIPTION("Siemens PEB20534 PCI Controller");
+MODULE_DESCRIPTION("Siemens PEB20534 PCI Controler");
 MODULE_LICENSE("GPL");
 MODULE_PARM(debug,"i");
+MODULE_PARM_DESC(debug,"Enable/disable extra messages");
+MODULE_PARM(quartz,"i");
+MODULE_PARM_DESC(quartz,"If present, on-board quartz frequency (Hz)");
 
 /* Structures */
+
+struct thingie {
+	int define;
+	u32 bits;
+};
+
 struct TxFD {
 	u32 state;
 	u32 next;
 	u32 data;
 	u32 complete;
-	u32 jiffies; /* more hack to come :o) */
+	u32 jiffies; /* Allows sizeof(TxFD) == sizeof(RxFD) + extra hack */
 };
 
 struct RxFD {
@@ -134,22 +149,24 @@
 	u32 end;
 };
 
-#define DEBUG
-#define DEBUG_PARANOID
-#define TX_RING_SIZE    32
-#define RX_RING_SIZE    32
-#define IRQ_RING_SIZE   64 /* Keep it A multiple of 32 */
-#define TX_TIMEOUT      (HZ/10)
-#define BRR_DIVIDER_MAX 64*0x00008000
-#define dev_per_card	4
-
-#define SOURCE_ID(flags) ((flags >> 28 ) & 0x03)
-#define TO_SIZE(state) ((state >> 16) & 0x1fff)
-#define TO_STATE(len) cpu_to_le32((len & TxSizeMax) << 16)
-#define RX_MAX(len) ((((len) >> 5) + 1) << 5)
-#define SCC_REG_START(id) SCC_START+(id)*SCC_OFFSET
-
-#undef DEBUG
+#define DUMMY_SKB_SIZE		64
+#define TX_LOW			8
+#define TX_RING_SIZE		32
+#define RX_RING_SIZE		32
+#define TX_TOTAL_SIZE		TX_RING_SIZE*sizeof(struct TxFD)
+#define RX_TOTAL_SIZE		RX_RING_SIZE*sizeof(struct RxFD)
+#define IRQ_RING_SIZE		64		/* Keep it a multiple of 32 */
+#define TX_TIMEOUT		(HZ/10)
+#define DSCC4_HZ_MAX		33000000
+#define BRR_DIVIDER_MAX		64*0x00004000	/* Cf errata DS5 p.10 */
+#define dev_per_card		4
+#define SCC_REGISTERS_MAX	23		/* Cf errata DS5 p.4 */
+
+#define SOURCE_ID(flags)	(((flags) >> 28) & 0x03)
+#define TO_SIZE(state)		(((state) >> 16) & 0x1fff)
+#define TO_STATE(len)		cpu_to_le32(((len) & TxSizeMax) << 16)
+#define RX_MAX(len)		((((len) >> 5) + 1) << 5)
+#define SCC_REG_START(dpriv)	(SCC_START+(dpriv->dev_id)*SCC_OFFSET)
 
 struct dscc4_pci_priv {
         u32 *iqcfg;
@@ -157,7 +174,7 @@
         spinlock_t lock;
         struct pci_dev *pdev;
 
-        struct net_device *root;
+        struct dscc4_dev_priv *root;
         dma_addr_t iqcfg_dma;
 	u32 xtal_hz;
 };
@@ -171,34 +188,38 @@
         u32 *iqrx;
         u32 *iqtx;
 
+	/* FIXME: check all the volatile are required */
+        volatile u32 tx_current;
         u32 rx_current;
-        u32 tx_current;
-        u32 iqrx_current;
         u32 iqtx_current;
+        u32 iqrx_current;
 
-        u32 tx_dirty;
-	int bad_tx_frame;
-	int bad_rx_frame;
-	int rx_needs_refill;
+        volatile u32 tx_dirty;
+        volatile u32 ltda;
+        u32 rx_dirty;
+        u32 lrda;
 
         dma_addr_t tx_fd_dma;
         dma_addr_t rx_fd_dma;
         dma_addr_t iqtx_dma;
         dma_addr_t iqrx_dma;
 
-        struct net_device_stats stats;
+	u32 scc_regs[SCC_REGISTERS_MAX]; /* Cf errata DS5 p.4 */
+
 	struct timer_list timer;
 
         struct dscc4_pci_priv *pci_priv;
         spinlock_t lock;
 
         int dev_id;
-	u32 flags;
+	volatile u32 flags;
 	u32 timer_help;
-	u32 hi_expected;
 
-	struct hdlc_device_struct hdlc;
-	int usecount;
+	unsigned short encoding;
+	unsigned short parity;
+	hdlc_device hdlc;
+	sync_serial_settings settings;
+	u32 __pad __attribute__ ((aligned (4)));
 };
 
 /* GLOBAL registers definitions */
@@ -217,6 +238,10 @@
 #define CH0CFG  0x50
 #define CH0BRDA 0x54
 #define CH0BTDA 0x58
+#define CH0FRDA 0x98
+#define CH0FTDA 0xb0
+#define CH0LRDA 0xc8
+#define CH0LTDA 0xe0
 
 /* SCC registers definitions */
 #define SCC_START	0x0100
@@ -232,8 +257,11 @@
 #define ISR     0x58
 
 /* Bit masks */
-#define IntRxScc0       0x10000000
-#define IntTxScc0       0x01000000
+#define EncodingMask	0x00700000
+#define CrcMask		0x00000003
+
+#define IntRxScc0	0x10000000
+#define IntTxScc0	0x01000000
 
 #define TxPollCmd	0x00000400
 #define RxActivate	0x08000000
@@ -242,22 +270,24 @@
 #define Rdt		0x00200000
 #define Idr		0x00100000
 #define Idt		0x00080000
-#define TxSccRes       0x01000000
-#define RxSccRes       0x00010000
-#define TxSizeMax	0x1ffc
-#define RxSizeMax	0x1ffc
+#define TxSccRes	0x01000000
+#define RxSccRes	0x00010000
+#define TxSizeMax	0x1fff
 
 #define Ccr0ClockMask	0x0000003f
 #define Ccr1LoopMask	0x00000200
+#define IsrMask		0x000fffff
 #define BrrExpMask	0x00000f00
 #define BrrMultMask	0x0000003f
 #define EncodingMask	0x00700000
 #define Hold		0x40000000
 #define SccBusy		0x10000000
+#define PowerUp		0x80000000
 #define FrameOk		(FrameVfr | FrameCrc)
 #define FrameVfr	0x80
 #define FrameRdo	0x40
 #define FrameCrc	0x20
+#define FrameRab	0x10
 #define FrameAborted	0x00000200
 #define FrameEnd	0x80000000
 #define DataComplete	0x40000000
@@ -272,10 +302,12 @@
 #define TxEvt		0x0f000000
 #define Alls		0x00040000
 #define Xdu		0x00010000
+#define Cts		0x00004000
 #define Xmr		0x00002000
 #define Xpr		0x00001000
 #define Rdo		0x00000080
 #define Rfs		0x00000040
+#define Cd		0x00000004
 #define Rfo		0x00000002
 #define Flex		0x00000001
 
@@ -293,184 +325,350 @@
 #define RdoSet		0x00000004
 
 /* Functions prototypes */
-static __inline__ void dscc4_rx_irq(struct dscc4_pci_priv *, struct net_device *);
-static __inline__ void dscc4_tx_irq(struct dscc4_pci_priv *, struct net_device *);
+static inline void dscc4_rx_irq(struct dscc4_pci_priv *, struct dscc4_dev_priv *);
+static inline void dscc4_tx_irq(struct dscc4_pci_priv *, struct dscc4_dev_priv *);
 static int dscc4_found1(struct pci_dev *, unsigned long ioaddr);
 static int dscc4_init_one(struct pci_dev *, const struct pci_device_id *ent);
 static int dscc4_open(struct net_device *);
 static int dscc4_start_xmit(struct sk_buff *, struct net_device *);
 static int dscc4_close(struct net_device *);
 static int dscc4_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static int dscc4_change_mtu(struct net_device *dev, int mtu);
 static int dscc4_init_ring(struct net_device *);
 static void dscc4_release_ring(struct dscc4_dev_priv *);
 static void dscc4_timer(unsigned long);
 static void dscc4_tx_timeout(struct net_device *);
 static void dscc4_irq(int irq, void *dev_id, struct pt_regs *ptregs);
-static struct net_device_stats *dscc4_get_stats(struct net_device *);
-static int dscc4_attach_hdlc_device(struct net_device *);
-static void dscc4_unattach_hdlc_device(struct net_device *);
-static int dscc4_hdlc_open(struct hdlc_device_struct *);
-static void dscc4_hdlc_close(struct hdlc_device_struct *);
-static int dscc4_hdlc_ioctl(struct hdlc_device_struct *, struct ifreq *, int);
-static int dscc4_hdlc_xmit(hdlc_device *, struct sk_buff *);
-#ifdef EXPERIMENTAL_POLLING
+static int dscc4_hdlc_attach(hdlc_device *, unsigned short, unsigned short);
+static int dscc4_set_iface(struct dscc4_dev_priv *, struct net_device *);
+static inline int dscc4_set_quartz(struct dscc4_dev_priv *, int);
+#ifdef DSCC4_POLLING
 static int dscc4_tx_poll(struct dscc4_dev_priv *, struct net_device *);
 #endif
 
-void inline reset_TxFD(struct TxFD *tx_fd) {
-	/* FIXME: test with the last arg (size specification) = 0 */
-	tx_fd->state = FrameEnd | Hold | 0x00100000;
-	tx_fd->complete = 0x00000000;
+static inline struct dscc4_dev_priv *dscc4_priv(struct net_device *dev)
+{
+	return list_entry(dev, struct dscc4_dev_priv, hdlc.netdev);
 }
 
-void inline dscc4_release_ring_skbuff(struct sk_buff **p, int n)
+static void scc_patchl(u32 mask, u32 value, struct dscc4_dev_priv *dpriv,
+			struct net_device *dev, int offset)
 {
-	for(; n > 0; n--) {
-		if (*p)
-			dev_kfree_skb(*p);
-		p++;
+	u32 state;
+
+	/* Cf scc_writel for concern regarding thread-safety */
+	state = dpriv->scc_regs[offset >> 2];
+	state &= ~mask;
+	state |= value;
+	dpriv->scc_regs[offset >> 2] = state;
+	writel(state, dev->base_addr + SCC_REG_START(dpriv) + offset);
+}
+
+static void scc_writel(u32 bits, struct dscc4_dev_priv *dpriv,
+		       struct net_device *dev, int offset)
+{
+	/*
+	 * Thread-UNsafe.
+	 * As of 2002/02/16, there are no thread racing for access.
+	 */
+	dpriv->scc_regs[offset >> 2] = bits;
+	writel(bits, dev->base_addr + SCC_REG_START(dpriv) + offset);
+}
+
+static inline u32 scc_readl(struct dscc4_dev_priv *dpriv, int offset)
+{
+	return dpriv->scc_regs[offset >> 2];
+}
+
+static u32 scc_readl_star(struct dscc4_dev_priv *dpriv, struct net_device *dev)
+{
+	/* Cf errata DS5 p.4 */
+	readl(dev->base_addr + SCC_REG_START(dpriv) + STAR);
+	return readl(dev->base_addr + SCC_REG_START(dpriv) + STAR);
+}
+
+static inline void dscc4_do_tx(struct dscc4_dev_priv *dpriv,
+			       struct net_device *dev)
+{
+	dpriv->ltda = dpriv->tx_fd_dma +
+                      ((dpriv->tx_current-1)%TX_RING_SIZE)*sizeof(struct TxFD);
+	writel(dpriv->ltda, dev->base_addr + CH0LTDA + dpriv->dev_id*4);
+	/* Flush posted writes *NOW* */
+	readl(dev->base_addr + CH0LTDA + dpriv->dev_id*4);
+}
+
+static inline void dscc4_rx_update(struct dscc4_dev_priv *dpriv,
+				   struct net_device *dev)
+{
+	dpriv->lrda = dpriv->rx_fd_dma +
+		      ((dpriv->rx_dirty - 1)%RX_RING_SIZE)*sizeof(struct RxFD);
+	writel(dpriv->lrda, dev->base_addr + CH0LRDA + dpriv->dev_id*4);
+}
+
+static inline unsigned int dscc4_tx_done(struct dscc4_dev_priv *dpriv)
+{
+	return dpriv->tx_current == dpriv->tx_dirty;
+}
+
+static inline unsigned int dscc4_tx_quiescent(struct dscc4_dev_priv *dpriv,
+					      struct net_device *dev)
+{
+	return readl(dev->base_addr + CH0FTDA + dpriv->dev_id*4) == dpriv->ltda;
+}
+
+int state_check(u32 state, struct dscc4_dev_priv *dpriv, struct net_device *dev,
+		const char *msg)
+{
+	int ret = 0;
+
+	if (debug > 1) {
+	if (SOURCE_ID(state) != dpriv->dev_id) {
+		printk(KERN_DEBUG "%s (%s): Source Id=%d, state=%08x\n",
+		       dev->name, msg, SOURCE_ID(state), state );
+			ret = -1;
+	}
+	if (state & 0x0df80c00) {
+		printk(KERN_DEBUG "%s (%s): state=%08x (UFO alert)\n",
+		       dev->name, msg, state);
+			ret = -1;
 	}
+	}
+	return ret;
+}
+
+void dscc4_tx_print(struct net_device *dev, struct dscc4_dev_priv *dpriv,
+		    char *msg)
+{
+	printk(KERN_DEBUG "%s: tx_current=%02d tx_dirty=%02d (%s)\n",
+	       dev->name, dpriv->tx_current, dpriv->tx_dirty, msg);
 }
 
 static void dscc4_release_ring(struct dscc4_dev_priv *dpriv)
 {
 	struct pci_dev *pdev = dpriv->pci_priv->pdev;
+	struct TxFD *tx_fd = dpriv->tx_fd;
+	struct RxFD *rx_fd = dpriv->rx_fd;
+	struct sk_buff **skbuff;
+	int i;
+
+	pci_free_consistent(pdev, TX_TOTAL_SIZE, tx_fd, dpriv->tx_fd_dma);
+	pci_free_consistent(pdev, RX_TOTAL_SIZE, rx_fd, dpriv->rx_fd_dma);
+
+	skbuff = dpriv->tx_skbuff;
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		if (*skbuff) {
+			pci_unmap_single(pdev, tx_fd->data, (*skbuff)->len,
+				PCI_DMA_TODEVICE);
+			dev_kfree_skb(*skbuff);
+		}
+		skbuff++;
+		tx_fd++;
+	}
 
-	pci_free_consistent(pdev, TX_RING_SIZE*sizeof(struct TxFD),
-			    dpriv->tx_fd, dpriv->tx_fd_dma);
-	pci_free_consistent(pdev, RX_RING_SIZE*sizeof(struct RxFD),
-			    dpriv->rx_fd, dpriv->rx_fd_dma);
-	dscc4_release_ring_skbuff(dpriv->tx_skbuff, TX_RING_SIZE);
-	dscc4_release_ring_skbuff(dpriv->rx_skbuff, RX_RING_SIZE);
+	skbuff = dpriv->rx_skbuff;
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		if (*skbuff) {
+			pci_unmap_single(pdev, rx_fd->data,
+				RX_MAX(HDLC_MAX_MRU), PCI_DMA_FROMDEVICE);
+			dev_kfree_skb(*skbuff);
+		}
+		skbuff++;
+		rx_fd++;
+	}
 }
 
-void inline try_get_rx_skb(struct dscc4_dev_priv *priv, int cur, struct net_device *dev)
+inline int try_get_rx_skb(struct dscc4_dev_priv *dpriv, struct net_device *dev)
 {
+	unsigned int dirty = dpriv->rx_dirty%RX_RING_SIZE;
+	struct RxFD *rx_fd = dpriv->rx_fd + dirty;
+	const int len = RX_MAX(HDLC_MAX_MRU);
 	struct sk_buff *skb;
+	int ret = 0;
 
-	skb = dev_alloc_skb(RX_MAX(HDLC_MAX_MRU+2));
-	priv->rx_skbuff[cur] = skb;
-	if (!skb) {
-		priv->rx_fd[cur--].data = (u32) NULL;
-		priv->rx_fd[cur%RX_RING_SIZE].state1 |= Hold;
-		priv->rx_needs_refill++;
-		return;
-	}
+	skb = dev_alloc_skb(len);
+	dpriv->rx_skbuff[dirty] = skb;
+	if (skb) {
 	skb->dev = dev;
-	skb->protocol = htons(ETH_P_IP);
+		skb->protocol = htons(ETH_P_HDLC);
 	skb->mac.raw = skb->data;
-	priv->rx_fd[cur].data = pci_map_single(priv->pci_priv->pdev, skb->data,
-					       skb->len, PCI_DMA_FROMDEVICE);
+		rx_fd->data = pci_map_single(dpriv->pci_priv->pdev, skb->data,
+					     len, PCI_DMA_FROMDEVICE);
+	} else {
+		rx_fd->data = (u32) NULL;
+		ret = -1;
+	}
+	return ret;
 }
 
 /*
  * IRQ/thread/whatever safe
  */
-static int dscc4_wait_ack_cec(u32 ioaddr, struct net_device *dev, char *msg)
+static int dscc4_wait_ack_cec(struct dscc4_dev_priv *dpriv,
+			      struct net_device *dev, char *msg)
 {
-	s16 i = 0;
+	s8 i = 0;
 
-	while (readl(ioaddr + STAR) & SccBusy) {
-		if (i++ < 0)  {
-			printk(KERN_ERR "%s: %s timeout\n", dev->name, msg);
-			return -1;
-		}
-	}
-	printk(KERN_DEBUG "%s: %s ack (%d try)\n", dev->name, msg, i);
-	return 0;
+	do {
+		if (!(scc_readl_star(dpriv, dev) & SccBusy)) {
+			printk(KERN_DEBUG "%s: %s ack (%d try)\n", dev->name,
+			       msg, i);
+			goto done;
+		}
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(10);
+		rmb();
+	} while (++i > 0);
+	printk(KERN_ERR "%s: %s timeout\n", dev->name, msg);
+done:
+	return (i >= 0) ? i : -EAGAIN;
 }
 
 static int dscc4_do_action(struct net_device *dev, char *msg)
 {
 	unsigned long ioaddr = dev->base_addr;
-	u32 state;
-	s16 i;
+	s16 i = 0;
 
 	writel(Action, ioaddr + GCMDR);
 	ioaddr += GSTAR;
-	for (i = 0; i >= 0; i++) {
-		state = readl(ioaddr);
-		if (state & Arf) {
+	do {
+		u32 state = readl(ioaddr);
+
+		if (state & ArAck) {
+			printk(KERN_DEBUG "%s: %s ack\n", dev->name, msg);
+			writel(ArAck, ioaddr);
+			goto done;
+		} else if (state & Arf) {
 			printk(KERN_ERR "%s: %s failed\n", dev->name, msg);
 			writel(Arf, ioaddr);
-			return -1;
-		} else if (state & ArAck) {
-			printk(KERN_DEBUG "%s: %s ack (%d try)\n",
-			       dev->name, msg, i);
-			writel(ArAck, ioaddr);
-			return 0;
-		}
+			i = -1;
+			goto done;
 	}
+		rmb();
+	} while (++i > 0);
 	printk(KERN_ERR "%s: %s timeout\n", dev->name, msg);
-	return -1;
+done:
+	return i;
 }
 
-static __inline__ int dscc4_xpr_ack(struct dscc4_dev_priv *dpriv)
+static inline int dscc4_xpr_ack(struct dscc4_dev_priv *dpriv)
 {
-	int cur;
-	s16 i;
+	int cur = dpriv->iqtx_current%IRQ_RING_SIZE;
+	s8 i = 0;
 
-	cur = dpriv->iqtx_current%IRQ_RING_SIZE;
-	for (i = 0; i >= 0; i++) {
+	do {
 		if (!(dpriv->flags & (NeedIDR | NeedIDT)) ||
 		    (dpriv->iqtx[cur] & Xpr))
-			return 0;
+			break;
+		smp_rmb();
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(10);
+	} while (++i > 0);
+
+	return (i >= 0 ) ? i : -EAGAIN;
+}
+
+/* Requires protection against interrupt */
+static void dscc4_rx_reset(struct dscc4_dev_priv *dpriv, struct net_device *dev)
+{
+	/* Cf errata DS5 p.6 */
+	writel(0x00000000, dev->base_addr + CH0LRDA + dpriv->dev_id*4);
+	scc_writel(~PowerUp & scc_readl(dpriv, CCR0), dpriv, dev, CCR0);
+	readl(dev->base_addr + CH0LRDA + dpriv->dev_id*4);
+	writel(MTFi|Rdr, dev->base_addr + dpriv->dev_id*0x0c + CH0CFG);
+	writel(Action, dev->base_addr + GCMDR);
+}
+
+static void dscc4_tx_reset(struct dscc4_dev_priv *dpriv, struct net_device *dev)
+{
+	u16 i = 0;
+
+	/* Cf errata DS5 p.7 */
+	scc_writel(~PowerUp & scc_readl(dpriv, CCR0), dpriv, dev, CCR0);
+	scc_writel(0x00050000, dpriv, dev, CCR2);
+	/*
+	 * Must be longer than the time required to fill the fifo.
+	 */
+	while (!dscc4_tx_quiescent(dpriv, dev) && ++i) {
+		udelay(1);
+		wmb();
 	}
-	printk(KERN_ERR "%s: %s timeout\n", "dscc4", "XPR");
-	return -1;
+
+	writel(MTFi|Rdt, dev->base_addr + dpriv->dev_id*0x0c + CH0CFG);
+	if (dscc4_do_action(dev, "Rdt") < 0)
+		printk(KERN_ERR "%s: Tx reset failed\n", dev->name);
 }
 
-static __inline__ void dscc4_rx_skb(struct dscc4_dev_priv *dpriv, int cur,
-	struct RxFD *rx_fd, struct net_device *dev)
+/* TODO: (ab)use this function to refill a completely depleted RX ring. */
+static inline void dscc4_rx_skb(struct dscc4_dev_priv *dpriv,
+				struct net_device *dev)
 {
+	struct RxFD *rx_fd = dpriv->rx_fd + dpriv->rx_current%RX_RING_SIZE;
+	struct net_device_stats *stats = &dpriv->hdlc.stats;
 	struct pci_dev *pdev = dpriv->pci_priv->pdev;
 	struct sk_buff *skb;
 	int pkt_len;
 
-	skb = dpriv->rx_skbuff[cur];
-	pkt_len = TO_SIZE(rx_fd->state2) - 1;
-	pci_dma_sync_single(pdev, rx_fd->data, pkt_len + 1, PCI_DMA_FROMDEVICE);
-	if((skb->data[pkt_len] & FrameOk) == FrameOk) {
-		pci_unmap_single(pdev, rx_fd->data, skb->len, PCI_DMA_FROMDEVICE);
-		dpriv->stats.rx_packets++;
-		dpriv->stats.rx_bytes += pkt_len;
-		skb->tail += pkt_len;
-		skb->len = pkt_len;
-       		if (netif_running(hdlc_to_dev(&dpriv->hdlc)))
-			hdlc_netif_rx(&dpriv->hdlc, skb);
-		else
-			netif_rx(skb);
-		try_get_rx_skb(dpriv, cur, dev);
+	skb = dpriv->rx_skbuff[dpriv->rx_current++%RX_RING_SIZE];
+	if (!skb) {
+		printk(KERN_DEBUG "%s: skb=0 (%s)\n", dev->name, __FUNCTION__);
+		goto refill;
+	}
+	pkt_len = TO_SIZE(rx_fd->state2);
+	pci_dma_sync_single(pdev, rx_fd->data, pkt_len, PCI_DMA_FROMDEVICE);
+	pci_unmap_single(pdev, rx_fd->data, RX_MAX(HDLC_MAX_MRU), PCI_DMA_FROMDEVICE);
+	if ((skb->data[--pkt_len] & FrameOk) == FrameOk) {
+		stats->rx_packets++;
+		stats->rx_bytes += pkt_len;
+		skb_put(skb, pkt_len);
+		skb->dev->last_rx = jiffies;
+		netif_rx(skb);
 	} else {
-		if(skb->data[pkt_len] & FrameRdo)
-			dpriv->stats.rx_fifo_errors++;
-		else if(!(skb->data[pkt_len] | ~FrameCrc))
-			dpriv->stats.rx_crc_errors++;
-		else if(!(skb->data[pkt_len] | ~FrameVfr))
-			dpriv->stats.rx_length_errors++;
+		if (skb->data[pkt_len] & FrameRdo)
+			stats->rx_fifo_errors++;
+		else if (!(skb->data[pkt_len] | ~FrameCrc))
+			stats->rx_crc_errors++;
+		else if (!(skb->data[pkt_len] | ~(FrameVfr | FrameRab)))
+			stats->rx_length_errors++;
 		else
-			dpriv->stats.rx_errors++;
+			stats->rx_errors++;
+		dev_kfree_skb_irq(skb);
+	}
+refill:
+	while ((dpriv->rx_dirty - dpriv->rx_current) % RX_RING_SIZE) {
+		if (try_get_rx_skb(dpriv, dev) < 0)
+			break;
+		dpriv->rx_dirty++;
 	}
-	rx_fd->state1 |= Hold;
+	dscc4_rx_update(dpriv, dev);
 	rx_fd->state2 = 0x00000000;
 	rx_fd->end = 0xbabeface;
-	if (!rx_fd->data)
-		return;
-	rx_fd--;
-	if (!cur)
-		rx_fd += RX_RING_SIZE;
-	rx_fd->state1 &= ~Hold;
 }
 
-static int __init dscc4_init_one (struct pci_dev *pdev,
+static void dscc4_free1(struct pci_dev *pdev)
+{
+	struct dscc4_pci_priv *ppriv;
+	struct dscc4_dev_priv *root;
+	int i;
+
+	ppriv = pci_get_drvdata(pdev);
+	root = ppriv->root;
+
+	for (i = 0; i < dev_per_card; i++)
+		unregister_hdlc_device(&root[i].hdlc);
+
+	pci_set_drvdata(pdev, NULL);
+
+	kfree(root);
+	kfree(ppriv);
+}
+
+static int __init dscc4_init_one(struct pci_dev *pdev,
 				  const struct pci_device_id *ent)
 {
 	struct dscc4_pci_priv *priv;
 	struct dscc4_dev_priv *dpriv;
-	int i;
 	static int cards_found = 0;
 	unsigned long ioaddr;
+	int i;
 
 	printk(KERN_DEBUG "%s", version);
 
@@ -478,27 +676,30 @@
 		goto err_out;
 	if (!request_mem_region(pci_resource_start(pdev, 0),
 	                	pci_resource_len(pdev, 0), "registers")) {
-	        printk (KERN_ERR "dscc4: can't reserve MMIO region (regs)\n");
+	        printk(KERN_ERR "%s: can't reserve MMIO region (regs)\n",
+			DRV_NAME);
 	        goto err_out;
 	}
 	if (!request_mem_region(pci_resource_start(pdev, 1),
 	                        pci_resource_len(pdev, 1), "LBI interface")) {
-	        printk (KERN_ERR "dscc4: can't reserve MMIO region (lbi)\n");
+	        printk(KERN_ERR "%s: can't reserve MMIO region (lbi)\n",
+			DRV_NAME);
 	        goto err_out_free_mmio_region0;
 	}
 	ioaddr = (unsigned long)ioremap(pci_resource_start(pdev, 0),
 					pci_resource_len(pdev, 0));
 	if (!ioaddr) {
-		printk(KERN_ERR "dscc4: cannot remap MMIO region %lx @ %lx\n",
-	                pci_resource_len(pdev, 0), pci_resource_start(pdev, 0));
+		printk(KERN_ERR "%s: cannot remap MMIO region %lx @ %lx\n",
+			DRV_NAME, pci_resource_len(pdev, 0),
+			pci_resource_start(pdev, 0));
 		goto err_out_free_mmio_region;
 	}
-	printk(KERN_DEBUG "Siemens DSCC4, MMIO at %#lx (regs), %#lx (lbi), IRQ %d.\n",
+	printk(KERN_DEBUG "Siemens DSCC4, MMIO at %#lx (regs), %#lx (lbi), IRQ %d\n",
 	        pci_resource_start(pdev, 0),
 	        pci_resource_start(pdev, 1), pdev->irq);
 
-	/* High PCI latency useless. Cf app. note. */
-	pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x10);
+	/* Cf errata DS5 p.2 */
+	pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xf8);
 	pci_set_master(pdev);
 
 	if (dscc4_found1(pdev, ioaddr))
@@ -506,14 +707,13 @@
 
 	priv = (struct dscc4_pci_priv *)pci_get_drvdata(pdev);
 
-	if (request_irq(pdev->irq, &dscc4_irq, SA_SHIRQ, "dscc4", priv->root)) {
-		printk(KERN_WARNING "dscc4: IRQ %d is busy\n", pdev->irq);
-		goto err_out_iounmap;
+	if (request_irq(pdev->irq, &dscc4_irq, SA_SHIRQ, DRV_NAME, priv->root)){
+		printk(KERN_WARNING "%s: IRQ %d busy\n", DRV_NAME, pdev->irq);
+		goto err_out_free1;
 	}
-	priv->pdev = pdev;
 
-	/* power up/little endian/dma core controlled via hold bit */
-	writel(0x00000000, ioaddr + GMODE);
+	/* power up/little endian/dma core controlled via lrda/ltda */
+	writel(0x00000001, ioaddr + GMODE);
 	/* Shared interrupt queue */
 	{
 		u32 bits;
@@ -532,20 +732,20 @@
 		goto err_out_free_irq;
 	writel(priv->iqcfg_dma, ioaddr + IQCFG);
 
-	/* 
-	 * SCC 0-3 private rx/tx irq structures 
+	/*
+	 * SCC 0-3 private rx/tx irq structures
 	 * IQRX/TXi needs to be set soon. Learned it the hard way...
 	 */
-	for(i = 0; i < dev_per_card; i++) {
-		dpriv = (struct dscc4_dev_priv *)(priv->root + i)->priv;
+	for (i = 0; i < dev_per_card; i++) {
+		dpriv = priv->root + i;
 		dpriv->iqtx = (u32 *) pci_alloc_consistent(pdev,
 			IRQ_RING_SIZE*sizeof(u32), &dpriv->iqtx_dma);
 		if (!dpriv->iqtx)
 			goto err_out_free_iqtx;
 		writel(dpriv->iqtx_dma, ioaddr + IQTX0 + i*4);
 	}
-	for(i = 0; i < dev_per_card; i++) {
-		dpriv = (struct dscc4_dev_priv *)(priv->root + i)->priv;
+	for (i = 0; i < dev_per_card; i++) {
+		dpriv = priv->root + i;
 		dpriv->iqrx = (u32 *) pci_alloc_consistent(pdev,
 			IRQ_RING_SIZE*sizeof(u32), &dpriv->iqrx_dma);
 		if (!dpriv->iqrx)
@@ -553,10 +753,7 @@
 		writel(dpriv->iqrx_dma, ioaddr + IQRX0 + i*4);
 	}
 
-	/* 
-	 * Cf application hint. Beware of hard-lock condition on 
-	 * threshold .
-	 */
+	/* Cf application hint. Beware of hard-lock condition on threshold. */
 	writel(0x42104000, ioaddr + FIFOCR1);
 	//writel(0x9ce69800, ioaddr + FIFOCR2);
 	writel(0xdef6d800, ioaddr + FIFOCR2);
@@ -572,21 +769,23 @@
 
 err_out_free_iqrx:
 	while (--i >= 0) {
-		dpriv = (struct dscc4_dev_priv *)(priv->root + i)->priv;
-		pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32), 
+		dpriv = priv->root + i;
+		pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32),
 				    dpriv->iqrx, dpriv->iqrx_dma);
 	}
 	i = dev_per_card;
 err_out_free_iqtx:
 	while (--i >= 0) {
-		dpriv = (struct dscc4_dev_priv *)(priv->root + i)->priv;
-		pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32), 
+		dpriv = priv->root + i;
+		pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32),
 				    dpriv->iqtx, dpriv->iqtx_dma);
 	}
-	pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32), priv->iqcfg, 
+	pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32), priv->iqcfg,
 			    priv->iqcfg_dma);
 err_out_free_irq:
 	free_irq(pdev->irq, priv->root);
+err_out_free1:
+	dscc4_free1(pdev);
 err_out_iounmap:
 	iounmap ((void *)ioaddr);
 err_out_free_mmio_region:
@@ -599,140 +798,118 @@
 	return -ENODEV;
 };
 
+/*
+ * Let's hope the default values are decent enough to protect my
+ * feet from the user's gun - Ueimor
+ */
+static void dscc4_init_registers(struct dscc4_dev_priv *dpriv,
+				 struct net_device *dev)
+{
+	scc_writel(0x80001000, dpriv, dev, CCR0);
+
+	scc_writel(LengthCheck | (HDLC_MAX_MRU >> 5), dpriv, dev, RLCR);
+
+	/*
+	 * No address recognition/crc-CCITT/cts enabled
+	 * Shared flags transmission disabled - cf errata DS5 p.11
+	 * Carrier detect disabled - cf errata p.14
+	 */
+	scc_writel(0x021c8000, dpriv, dev, CCR1);
+
+	/* crc not forwarded - Cf errata DS5 p.11 */
+	scc_writel(0x00050008 & ~RxActivate, dpriv, dev, CCR2);
+	// crc forwarded
+	//scc_writel(0x00250008 & ~RxActivate, dpriv, dev, CCR2);
+
+	/* Don't mask RDO. Ever. */
+#ifdef DSCC4_POLLING
+	scc_writel(0xfffeef7f, dpriv, dev, IMR); /* Interrupt mask */
+#else
+	//scc_writel(0xfffaef7f, dpriv, dev, IMR); /* Interrupt mask */
+	//scc_writel(0xfffaef7e, dpriv, dev, IMR); /* Interrupt mask */
+	scc_writel(0xfffa8f7a, dpriv, dev, IMR); /* Interrupt mask */
+#endif
+}
+
 static int dscc4_found1(struct pci_dev *pdev, unsigned long ioaddr)
 {
 	struct dscc4_pci_priv *ppriv;
-	struct dscc4_dev_priv *dpriv;
-	struct net_device *dev;
+	struct dscc4_dev_priv *root;
 	int i = 0;
 
-	dpriv = (struct dscc4_dev_priv *)
-		kmalloc(dev_per_card*sizeof(struct dscc4_dev_priv), GFP_KERNEL);
-	if (!dpriv) {
-		printk(KERN_ERR "dscc4: can't allocate data\n");
+	root = (struct dscc4_dev_priv *)
+		kmalloc(dev_per_card*sizeof(*root), GFP_KERNEL);
+	if (!root) {
+		printk(KERN_ERR "%s: can't allocate data\n", DRV_NAME);
 		goto err_out;
 	}
-	memset(dpriv, 0, dev_per_card*sizeof(struct dscc4_dev_priv));
-
-	dev = (struct net_device *)
-	      kmalloc(dev_per_card*sizeof(struct net_device), GFP_KERNEL);
-	if (!dev) {
-		printk(KERN_ERR "dscc4: can't allocate net_device\n");
-		goto err_dealloc_priv;
-	}
-	memset(dev, 0, dev_per_card*sizeof(struct net_device));
+	memset(root, 0, dev_per_card*sizeof(*root));
 
-	ppriv = (struct dscc4_pci_priv *)
-		kmalloc(sizeof(struct dscc4_pci_priv), GFP_KERNEL);
+	ppriv = (struct dscc4_pci_priv *) kmalloc(sizeof(*ppriv), GFP_KERNEL);
 	if (!ppriv) {
-		printk(KERN_ERR "dscc4: can't allocate pci private data.\n");
-		goto err_dealloc_dev;
+		printk(KERN_ERR "%s: can't allocate private data\n", DRV_NAME);
+		goto err_free_dev;
 	}
 	memset(ppriv, 0, sizeof(struct dscc4_pci_priv));
 
 	for (i = 0; i < dev_per_card; i++) {
-		struct dscc4_dev_priv *p;
-		struct net_device *d;
+		struct dscc4_dev_priv *dpriv = root + i;
+		hdlc_device *hdlc = &dpriv->hdlc;
+		struct net_device *d = hdlc_to_dev(hdlc);
 
-	        d = dev + i;
 	        d->base_addr = ioaddr;
 		d->init = NULL;
 	        d->irq = pdev->irq;
-		/* The card adds the crc */
-		d->type = ARPHRD_RAWHDLC;
 	        d->open = dscc4_open;
 	        d->stop = dscc4_close;
-	        d->hard_start_xmit = dscc4_start_xmit;
 		d->set_multicast_list = NULL;
 	        d->do_ioctl = dscc4_ioctl;
-		d->get_stats = dscc4_get_stats;
-		d->change_mtu = dscc4_change_mtu;
-	        d->mtu = HDLC_MAX_MTU;
-	        d->flags = IFF_MULTICAST|IFF_POINTOPOINT|IFF_NOARP;
 		d->tx_timeout = dscc4_tx_timeout;
 		d->watchdog_timeo = TX_TIMEOUT;
 
-		p = dpriv + i;
-		p->dev_id = i;
-		p->pci_priv = ppriv;
-		spin_lock_init(&p->lock);
-		d->priv = p;
-
-		if (dev_alloc_name(d, "scc%d")<0) {
-			printk(KERN_ERR "dev_alloc_name failed for scc.\n");
-			goto err_dealloc_dev;
-		}
-	        if (register_netdev(d)) {
-			printk(KERN_ERR "%s: register_netdev != 0.\n", d->name);
-			goto err_dealloc_dev;
+		dpriv->dev_id = i;
+		dpriv->pci_priv = ppriv;
+		spin_lock_init(&dpriv->lock);
+
+		hdlc->xmit = dscc4_start_xmit;
+		hdlc->attach = dscc4_hdlc_attach;
+
+	        if (register_hdlc_device(hdlc)) {
+			printk(KERN_ERR "%s: unable to register\n", DRV_NAME);
+			goto err_unregister;
 	        }
-		dscc4_attach_hdlc_device(d);
+		hdlc->proto = IF_PROTO_HDLC;
 		SET_MODULE_OWNER(d);
-	}
-	ppriv->root = dev;
-	ppriv->pdev = pdev;
+		dscc4_init_registers(dpriv, d);
+		dpriv->parity = PARITY_CRC16_PR0_CCITT;
+		dpriv->encoding = ENCODING_NRZ;
+	}
+	if (dscc4_set_quartz(root, quartz) < 0)
+		goto err_unregister;
+	ppriv->root = root;
 	spin_lock_init(&ppriv->lock);
 	pci_set_drvdata(pdev, ppriv);
 	return 0;
 
-err_dealloc_dev:
+err_unregister:
 	while (--i >= 0)
-		unregister_netdev(dev + i);
-	kfree(dev);
-err_dealloc_priv:
-	kfree(dpriv);
+		unregister_hdlc_device(&root[i].hdlc);
+	kfree(ppriv);
+err_free_dev:
+	kfree(root);
 err_out:
 	return -1;
 };
 
+/* FIXME: get rid of the unneeded code */
 static void dscc4_timer(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *)data;
-	struct dscc4_dev_priv *dpriv;
-	struct dscc4_pci_priv *ppriv;
-
-	dpriv = dev->priv;
-	if (netif_queue_stopped(dev) && 
-	   ((jiffies - dev->trans_start) > TX_TIMEOUT)) {
-		ppriv = dpriv->pci_priv;
-		if (dpriv->iqtx[dpriv->iqtx_current%IRQ_RING_SIZE]) {
-			u32 flags;
-
-			printk(KERN_DEBUG "%s: pending events\n", dev->name);
-			dev->trans_start = jiffies;
-			spin_lock_irqsave(&ppriv->lock, flags);
-			dscc4_tx_irq(ppriv, dev);
-			spin_unlock_irqrestore(&ppriv->lock, flags);
-		} else {
-			struct TxFD *tx_fd;
-			struct sk_buff *skb;
-			int i,j;
+	struct dscc4_dev_priv *dpriv = dscc4_priv(dev);
+//	struct dscc4_pci_priv *ppriv;
 
-			printk(KERN_DEBUG "%s: missing events\n", dev->name);
-			i = dpriv->tx_dirty%TX_RING_SIZE; 
-			j = dpriv->tx_current - dpriv->tx_dirty;
-			dpriv->stats.tx_dropped += j;
-			while(j--) {
-				skb = dpriv->tx_skbuff[i];
-				tx_fd = dpriv->tx_fd + i;
-				if (skb) {
-					dpriv->tx_skbuff[i] = NULL;
-					pci_unmap_single(ppriv->pdev, tx_fd->data, skb->len,
-						 	 PCI_DMA_TODEVICE);
-					dev_kfree_skb_irq(skb);
-				} else 
-					printk(KERN_INFO "%s: hardware on drugs!\n", dev->name);
-				tx_fd->data = 0; /* DEBUG */
-				tx_fd->complete &= ~DataComplete;
-				i++;	
-				i %= TX_RING_SIZE; 
-			}
-			dpriv->tx_dirty = dpriv->tx_current;
-			dev->trans_start = jiffies;
-			netif_wake_queue(dev);
-			printk(KERN_DEBUG "%s: re-enabled\n", dev->name);	
-		}
-	}
+	goto done;
+done:
         dpriv->timer.expires = jiffies + TX_TIMEOUT;
         add_timer(&dpriv->timer);
 }
@@ -740,41 +917,41 @@
 static void dscc4_tx_timeout(struct net_device *dev)
 {
 	/* FIXME: something is missing there */
-};
+}
 
-static int dscc4_open(struct net_device *dev)
+static int dscc4_loopback_check(struct dscc4_dev_priv *dpriv)
 {
-	struct dscc4_dev_priv *dpriv = (struct dscc4_dev_priv *)dev->priv;
-	struct dscc4_pci_priv *ppriv;
-	u32 ioaddr = 0;
+	sync_serial_settings *settings = &dpriv->settings;
 
-	MOD_INC_USE_COUNT;
+	if (settings->loopback && (settings->clock_type != CLOCK_INT)) {
+		struct net_device *dev = hdlc_to_dev(&dpriv->hdlc);
 
-	ppriv = dpriv->pci_priv;
+		printk(KERN_INFO "%s: loopback requires clock\n", dev->name);
+		return -1;
+	}
+	return 0;
+}
 
-	if (dscc4_init_ring(dev))
-		goto err_out;
+static int dscc4_open(struct net_device *dev)
+{
+	struct dscc4_dev_priv *dpriv = dscc4_priv(dev);
+	hdlc_device *hdlc = &dpriv->hdlc;
+	struct dscc4_pci_priv *ppriv;
+	int ret = -EAGAIN;
 
-	ioaddr = dev->base_addr + SCC_REG_START(dpriv->dev_id);
+	if ((dscc4_loopback_check(dpriv) < 0) || !dev->hard_start_xmit)
+		goto err;
 
-	/* FIXME: VIS */
-	writel(readl(ioaddr + CCR0) | 0x80001000, ioaddr + CCR0);
+	if ((ret = hdlc_open(hdlc)))
+		goto err;
 
-	writel(LengthCheck | (HDLC_MAX_MRU >> 5), ioaddr + RLCR);
+	MOD_INC_USE_COUNT;
 
-	/* no address recognition/crc-CCITT/cts enabled */
-	writel(readl(ioaddr + CCR1) | 0x021c8000, ioaddr + CCR1);
+	ppriv = dpriv->pci_priv;
 
-	/* Ccr2.Rac = 0 */
-	writel(0x00050008 & ~RxActivate, ioaddr + CCR2);
+	if ((ret = dscc4_init_ring(dev)))
+		goto err_out;
 
-#ifdef EXPERIMENTAL_POLLING
-	writel(0xfffeef7f, ioaddr + IMR); /* Interrupt mask */
-#else
-	/* Don't mask RDO. Ever. */
-	//writel(0xfffaef7f, ioaddr + IMR); /* Interrupt mask */
-	writel(0xfffaef7e, ioaddr + IMR); /* Interrupt mask */
-#endif
 	/* IDT+IDR during XPR */
 	dpriv->flags = NeedIDR | NeedIDT;
 
@@ -785,26 +962,34 @@
 	 * power-down mode or..." and CCR2.RAC = 1 are two different
 	 * situations.
 	 */
-	if (readl(ioaddr + STAR) & SccBusy) {
+	if (scc_readl_star(dpriv, dev) & SccBusy) {
 		printk(KERN_ERR "%s busy. Try later\n", dev->name);
+		ret = -EAGAIN;
 		goto err_free_ring;
-	}
-	writel(TxSccRes | RxSccRes, ioaddr + CMDR);
+	} else
+		printk(KERN_INFO "%s: available. Good\n", dev->name);
+
+	/* Posted write is flushed in the wait_ack loop */
+	scc_writel(TxSccRes | RxSccRes, dpriv, dev, CMDR);
 
-	/* ... the following isn't */
-	if (dscc4_wait_ack_cec(ioaddr, dev, "Cec"))
+	if ((ret = dscc4_wait_ack_cec(dpriv, dev, "Cec")) < 0)
 		goto err_free_ring;
 
-	/* 
+	/*
 	 * I would expect XPR near CE completion (before ? after ?).
 	 * At worst, this code won't see a late XPR and people
-	 * will have to re-issue an ifconfig (this is harmless). 
-	 * WARNING, a really missing XPR usually means a hardware 
+	 * will have to re-issue an ifconfig (this is harmless).
+	 * WARNING, a really missing XPR usually means a hardware
 	 * reset is needed. Suggestions anyone ?
 	 */
-	if (dscc4_xpr_ack(dpriv))
+	if ((ret = dscc4_xpr_ack(dpriv)) < 0) {
+		printk(KERN_ERR "%s: %s timeout\n", DRV_NAME, "XPR");
 		goto err_free_ring;
+	}
 	
+	if (debug > 2)
+		dscc4_tx_print(dev, dpriv, "Open");
+
 	netif_start_queue(dev);
 
         init_timer(&dpriv->timer);
@@ -819,97 +1004,105 @@
 err_free_ring:
 	dscc4_release_ring(dpriv);
 err_out:
+	hdlc_close(hdlc);
 	MOD_DEC_USE_COUNT;
-	return -EAGAIN;
+err:
+	return ret;
 }
 
-#ifdef EXPERIMENTAL_POLLING
+#ifdef DSCC4_POLLING
 static int dscc4_tx_poll(struct dscc4_dev_priv *dpriv, struct net_device *dev)
 {
 	/* FIXME: it's gonna be easy (TM), for sure */
 }
-#endif /* EXPERIMENTAL_POLLING */
+#endif /* DSCC4_POLLING */
 
 static int dscc4_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct dscc4_dev_priv *dpriv = dev->priv;
-	struct dscc4_pci_priv *ppriv;
+	struct dscc4_dev_priv *dpriv = dscc4_priv(dev);
+	struct dscc4_pci_priv *ppriv = dpriv->pci_priv;
 	struct TxFD *tx_fd;
-	int cur, next;
+	int next;
 
-	ppriv = dpriv->pci_priv;
-	cur = dpriv->tx_current++%TX_RING_SIZE;
 	next = dpriv->tx_current%TX_RING_SIZE;
 	dpriv->tx_skbuff[next] = skb;
 	tx_fd = dpriv->tx_fd + next;
-	tx_fd->state = FrameEnd | Hold | TO_STATE(skb->len & TxSizeMax);
+	tx_fd->state = FrameEnd | TO_STATE(skb->len);
 	tx_fd->data = pci_map_single(ppriv->pdev, skb->data, skb->len,
 				     PCI_DMA_TODEVICE);
 	tx_fd->complete = 0x00000000;
-	mb(); // FIXME: suppress ?
+	tx_fd->jiffies = jiffies;
+	mb();
 
-#ifdef EXPERIMENTAL_POLLING
+#ifdef DSCC4_POLLING
 	spin_lock(&dpriv->lock);
-	while(dscc4_tx_poll(dpriv, dev));
+	while (dscc4_tx_poll(dpriv, dev));
 	spin_unlock(&dpriv->lock);
 #endif
-	/*
-	 * I know there's a window for a race in the following lines but
-	 * dscc4_timer will take good care of it. The chipset eats events
-	 * (especially the net_dev re-enabling ones) thus there is no
-	 * reason to try and be smart.
-	 */
-	if ((dpriv->tx_dirty + 16) < dpriv->tx_current) {
-			netif_stop_queue(dev);
-			dpriv->hi_expected = 2;
-	}
-	tx_fd = dpriv->tx_fd + cur;
-	tx_fd->state &= ~Hold;
-	mb(); // FIXME: suppress ?
-
-	/* 
-	 * One may avoid some pci transactions during intense TX periods.
-	 * Not sure it's worth the pain...
-	 */
-	writel((TxPollCmd << dpriv->dev_id) | NoAck, dev->base_addr + GCMDR);
+
 	dev->trans_start = jiffies;
+
+	if (debug > 2)
+		dscc4_tx_print(dev, dpriv, "Xmit");
+	/* To be cleaned(unsigned int)/optimized. Later, ok ? */
+	if (!((++dpriv->tx_current - dpriv->tx_dirty)%TX_RING_SIZE))
+		netif_stop_queue(dev);
+
+	if (dscc4_tx_quiescent(dpriv, dev))
+		dscc4_do_tx(dpriv, dev);
+
 	return 0;
 }
 
 static int dscc4_close(struct net_device *dev)
 {
-	struct dscc4_dev_priv *dpriv = (struct dscc4_dev_priv *)dev->priv;
-	u32 ioaddr = dev->base_addr;
-	int dev_id;
+	struct dscc4_dev_priv *dpriv = dscc4_priv(dev);
+	hdlc_device *hdlc = dev_to_hdlc(dev);
+	unsigned long flags;
 
 	del_timer_sync(&dpriv->timer);
 	netif_stop_queue(dev);
 
-	dev_id = dpriv->dev_id;
+	spin_lock_irqsave(&dpriv->pci_priv->lock, flags);
+	dscc4_rx_reset(dpriv, dev);
+	spin_unlock_irqrestore(&dpriv->pci_priv->lock, flags);
 
-	writel(0x00050000, ioaddr + SCC_REG_START(dev_id) + CCR2);
-	writel(MTFi|Rdr|Rdt, ioaddr + CH0CFG + dev_id*0x0c); /* Reset Rx/Tx */
-	writel(0x00000001, ioaddr + GCMDR);
+	dscc4_tx_reset(dpriv, dev);
 
+	hdlc_close(hdlc);
 	dscc4_release_ring(dpriv);
 
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
+static inline int dscc4_check_clock_ability(int port)
+{
+	int ret = 0;
+
+#ifdef CONFIG_DSCC4_CLOCK_ON_TWO_PORTS_ONLY
+	if (port >= 2)
+		ret = -1;
+#endif
+	return ret;
+}
+
 static int dscc4_set_clock(struct net_device *dev, u32 *bps, u32 *state)
 {
-	struct dscc4_dev_priv *dpriv = (struct dscc4_dev_priv *)dev->priv;
+	struct dscc4_dev_priv *dpriv = dscc4_priv(dev);
+	int ret = -1;
 	u32 brr;
 
 	*state &= ~Ccr0ClockMask;
-	if (*bps) { /* DCE */
+	if (*bps) { /* Clock generated - required for DCE */
 		u32 n = 0, m = 0, divider;
 		int xtal;
 
 		xtal = dpriv->pci_priv->xtal_hz;
 		if (!xtal)
-			return -1;
+			goto done;
+		if (dscc4_check_clock_ability(dpriv->dev_id) < 0)
+			goto done;
 		divider = xtal / *bps;
 		if (divider > BRR_DIVIDER_MAX) {
 			divider >>= 4;
@@ -933,226 +1126,205 @@
 		if (!(*state & 0x00000001)) /* Clock mode 6b */
 			divider <<= 4;
 		*bps = xtal / divider;
-	} else { /* DTE */
-		/* 
-		 * "state" already reflects Clock mode 0a. 
-		 * Nothing more to be done 
+	} else {
+		/*
+		 * External clock - DTE
+		 * "state" already reflects Clock mode 0a.
+		 * Nothing more to be done
 		 */
 		brr = 0;
 	}
-	writel(brr, dev->base_addr + BRR + SCC_REG_START(dpriv->dev_id));
-
-	return 0;
+	scc_writel(brr, dpriv, dev, BRR);
+	ret = 0;
+done:
+	return ret;
 }
 
-#ifdef LATER_PLEASE
-/*
- * -*- [RFC] Configuring Synchronous Interfaces in Linux -*-
- */
+static int dscc4_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	sync_serial_settings *line = ifr->ifr_settings.ifs_ifsu.sync;
+	struct dscc4_dev_priv *dpriv = dscc4_priv(dev);
+	const size_t size = sizeof(dpriv->settings);
+	int ret = 0;
 
-// FIXME: MEDIA already defined in linux/hdlc.h
-#define HDLC_MEDIA_V35		0
-#define HDLC_MEDIA_RS232	1
-#define HDLC_MEDIA_X21		2
-#define HDLC_MEDIA_E1		3
-#define HDLC_MEDIA_HSSI		4
-
-#define HDLC_CODING_NRZ		0
-#define HDLC_CODING_NRZI	1
-#define HDLC_CODING_FM0		2
-#define HDLC_CODING_FM1		3
-#define HDLC_CODING_MANCHESTER	4
-
-#define HDLC_CRC_NONE		0
-#define HDLC_CRC_16		1
-#define HDLC_CRC_32		2
-#define HDLC_CRC_CCITT		3
-
-/* RFC: add the crc reset value ? */
-struct hdlc_physical {
-	u8 media;
-	u8 coding;
-	u32 rate;
-	u8 crc;
-	u8 crc_siz;		/* 2 or 4 bytes */
-	u8 shared_flags;	/* Discouraged on the DSCC4 */
-};
+        if (dev->flags & IFF_UP)
+                return -EBUSY;
 
-// FIXME: PROTO already defined in linux/hdlc.h
-#define HDLC_PROTO_RAW		0
-#define HDLC_PROTO_FR		1
-#define HDLC_PROTO_X25		2
-#define HDLC_PROTO_PPP		3
-#define HDLC_PROTO_CHDLC	4
+	if (cmd != SIOCWANDEV)
+		return -EOPNOTSUPP;
 
-struct hdlc_protocol {
-	u8 proto; 
-	
-	union {
-	} u;
-};
+	switch(ifr->ifr_settings.type) {
+	case IF_GET_IFACE:
+		ifr->ifr_settings.type = IF_IFACE_SYNC_SERIAL;
+		if (ifr->ifr_settings.size < size) {
+			ifr->ifr_settings.size = size; /* data size wanted */
+			return -ENOBUFS;
+		}
+		if (copy_to_user(line, &dpriv->settings, size))
+			return -EFAULT;
+		break;
 
-struct screq {
-	u16 media_group;
+	case IF_IFACE_SYNC_SERIAL:
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
 
-	union {
-		struct hdlc_physical hdlc_phy;
-		struct hdlc_protocol hdlc_proto;
-	} u;
-};
+		if (copy_from_user(&dpriv->settings, line, size))
+			return -EFAULT;
+		ret = dscc4_set_iface(dpriv, dev);
+		break;
 
-// FIXME: go sub-module 
-static struct {
-	u16 coding;
-	u16 bits;
-} map[] = {
-	{HDLC_CODING_NRZ,		0x00},
-	{HDLC_CODING_NRZI,		0x20},
-	{HDLC_CODING_FM0,		0x40},
-	{HDLC_CODING_FM1,		0x50},
-	{HDLC_CODING_MANCHESTER,	0x60},
-	{65535,	0x00}
-};
-#endif /* LATER_PLEASE */
+	default:
+		ret = hdlc_ioctl(dev, ifr, cmd);
+		break;
+	}
 
-static int dscc4_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+	return ret;
+}
+
+static inline int dscc4_set_quartz(struct dscc4_dev_priv *dpriv, int hz)
 {
-	struct dscc4_dev_priv *dpriv = dev->priv;
-	u32 state, ioaddr;
+	int ret = 0;
 
-        if (dev->flags & IFF_UP)
-                return -EBUSY;
+	if ((hz < 0) || (hz > DSCC4_HZ_MAX))
+		ret = -EOPNOTSUPP;
+	else
+		dpriv->pci_priv->xtal_hz = hz;
 
-	switch (cmd) {
-		/* Set built-in quartz frequency */
-		case SIOCDEVPRIVATE: {
-			u32 hz;
-
-			hz = ifr->ifr_ifru.ifru_ivalue;
-			if (hz >= 33000000) /* 33 MHz */
-				return -EOPNOTSUPP;
-			dpriv->pci_priv->xtal_hz = hz;
-			return 0;
-		}
-		/* Set/unset loopback */
-		case SIOCDEVPRIVATE+1: {
-			u32 flags;
-	
-			ioaddr = dev->base_addr + CCR1 +
-				 SCC_REG_START(dpriv->dev_id);
-			state = readl(ioaddr);
-			flags = ifr->ifr_ifru.ifru_ivalue;
-			if (flags & 0x00000001) {
-				printk(KERN_DEBUG "%s: loopback\n", dev->name);
-				state |= 0x00000100;
-			} else {
-				printk(KERN_DEBUG "%s: normal\n", dev->name);
-				state &= ~0x00000100;
-			}
-			writel(state, ioaddr);
-			return 0;
-		}
+	return ret;
+}
 
-#ifdef LATER_PLEASE
-		case SIOCDEVPRIVATE+2: {
-		{
-			struct screq scr;
-
-			err = copy_from_user(&scr, ifr->ifr_ifru.ifru_data, sizeof(struct screq));
-			if (err)
-				return err;
-			do {
-				if (scr.u.hdlc_phy.coding == map[i].coding)
-					break;
-			} while (map[++i].coding != 65535);
-			if (!map[i].coding)
-				return -EOPNOTSUPP;
-			
-			ioaddr = dev->base_addr + CCR0 +
-				 SCC_REG_START(dpriv->dev_id);
-			state = readl(ioaddr) & ~EncodingMask;
-			state |= (u32)map[i].bits << 16;
-			writel(state, ioaddr);	
-			printk("state: %08x\n", state); /* DEBUG */
-			return 0;
-		}
-		case SIOCDEVPRIVATE+3: {
-			struct screq *scr = (struct screq *)ifr->ifr_ifru.ifru_data;
-
-			ioaddr = dev->base_addr + CCR0 +
-				 SCC_REG_START(dpriv->dev_id);
-			state = (readl(ioaddr) & EncodingMask) >> 16;
-			do {
-				if (state == map[i].bits)
-					break;
-			} while (map[++i].coding);
-			return put_user(map[i].coding, (u16 *)scr->u.hdlc_phy.coding);
-		}
-#endif /* LATER_PLEASE */
+static int dscc4_match(struct thingie *p, int value)
+{
+	int i;
 
-		case HDLCSCLOCKRATE:
-		{
-			u32 state, bps;
- 
-			bps = ifr->ifr_ifru.ifru_ivalue;
-			ioaddr = dev->base_addr + CCR0 +
-				 SCC_REG_START(dpriv->dev_id);
-			state = readl(ioaddr);
-			if(dscc4_set_clock(dev, &bps, &state) < 0)
-				return -EOPNOTSUPP;
-			if (bps) { /* DCE */
-				printk(KERN_DEBUG "%s: generated RxClk (DCE)\n",
-				       dev->name);
-				ifr->ifr_ifru.ifru_ivalue = bps;
-			} else { /* DTE */
-				state = 0x80001000;
-				printk(KERN_DEBUG "%s: external RxClk (DTE)\n",
-				       dev->name);
-			}
-			writel(state, ioaddr);	
-			return 0;
+	for (i = 0; p[i].define != -1; i++) {
+		if (value == p[i].define)
+			break;
+	}
+	if (p[i].define == -1)
+		return -1;
+	else
+		return i;
+}
+
+static int dscc4_clock_setting(struct dscc4_dev_priv *dpriv,
+			       struct net_device *dev)
+{
+	sync_serial_settings *settings = &dpriv->settings;
+	int ret = -EOPNOTSUPP;
+	u32 bps, state;
+
+	bps = settings->clock_rate;
+	state = scc_readl(dpriv, CCR0);
+	if (dscc4_set_clock(dev, &bps, &state) < 0)
+		goto done;
+	if (bps) { /* DCE */
+		printk(KERN_DEBUG "%s: generated RxClk (DCE)\n", dev->name);
+		if (settings->clock_rate != bps) {
+			settings->clock_rate = bps;
+			printk(KERN_DEBUG "%s: clock adjusted (%08d -> %08d)\n",
+				dev->name, dpriv->settings.clock_rate, bps);
 		}
-		case HDLCGCLOCKRATE: {
-			u32 brr;
-			int bps;
+	} else { /* DTE */
+		state = 0x80001000;
+		printk(KERN_DEBUG "%s: external RxClk (DTE)\n", dev->name);
+	}
+	scc_writel(state, dpriv, dev, CCR0);
+	ret = 0;
+done:
+	return ret;
+}
+
+static int dscc4_encoding_setting(struct dscc4_dev_priv *dpriv,
+				  struct net_device *dev)
+{
+	struct thingie encoding[] = {
+		{ ENCODING_NRZ,		0x00000000 },
+		{ ENCODING_NRZI,	0x00200000 },
+		{ ENCODING_FM_MARK,	0x00400000 },
+		{ ENCODING_FM_SPACE,	0x00500000 },
+		{ ENCODING_MANCHESTER,	0x00600000 },
+		{ -1,			0}
+	};
+	int i, ret = 0;
+
+	i = dscc4_match(encoding, dpriv->encoding);
+	if (i >= 0)
+		scc_patchl(EncodingMask, encoding[i].bits, dpriv, dev, CCR0);
+	else
+		ret = -EOPNOTSUPP;
+	return ret;
+}
 
-			brr = readl(dev->base_addr + BRR + 
-				    SCC_REG_START(dpriv->dev_id));
-			bps = dpriv->pci_priv->xtal_hz >> (brr >> 8);
-			bps /= (brr & 0x3f) + 1;
-			ifr->ifr_ifru.ifru_ivalue = bps;
-			return 0;
-		}
+static int dscc4_loopback_setting(struct dscc4_dev_priv *dpriv,
+				  struct net_device *dev)
+{
+	sync_serial_settings *settings = &dpriv->settings;
+	u32 state;
 
-		default:
-			return -EOPNOTSUPP;
+	state = scc_readl(dpriv, CCR1);
+	if (settings->loopback) {
+		printk(KERN_DEBUG "%s: loopback\n", dev->name);
+		state |= 0x00000100;
+	} else {
+		printk(KERN_DEBUG "%s: normal\n", dev->name);
+		state &= ~0x00000100;
 	}
+	scc_writel(state, dpriv, dev, CCR1);
+	return 0;
 }
 
-static int dscc4_change_mtu(struct net_device *dev, int mtu)
+static int dscc4_crc_setting(struct dscc4_dev_priv *dpriv,
+			     struct net_device *dev)
 {
-	/* FIXME: chainsaw coded... */
-	if ((mtu <= 3) || (mtu > 65531))
-		return -EINVAL;
-        if(dev->flags & IFF_UP)
-                return -EBUSY;
-	dev->mtu = mtu;
-        return(0);
+	struct thingie crc[] = {
+		{ PARITY_CRC16_PR0_CCITT,	0x00000010 },
+		{ PARITY_CRC16_PR1_CCITT,	0x00000000 },
+		{ PARITY_CRC32_PR0_CCITT,	0x00000011 },
+		{ PARITY_CRC32_PR1_CCITT,	0x00000001 }
+	};
+	int i, ret = 0;
+
+	i = dscc4_match(crc, dpriv->parity);
+	if (i >= 0)
+		scc_patchl(CrcMask, crc[i].bits, dpriv, dev, CCR1);
+	else
+		ret = -EOPNOTSUPP;
+	return ret;
+}
+
+static int dscc4_set_iface(struct dscc4_dev_priv *dpriv, struct net_device *dev)
+{
+	struct {
+		int (*action)(struct dscc4_dev_priv *, struct net_device *);
+	} *p, do_setting[] = {
+		{ dscc4_encoding_setting },
+		{ dscc4_clock_setting },
+		{ dscc4_loopback_setting },
+		{ dscc4_crc_setting },
+		{ NULL }
+	};
+	int ret = 0;
+
+	for (p = do_setting; p->action; p++) {
+		if ((ret = p->action(dpriv, dev)) < 0)
+			break;
+	}
+	return ret;
 }
 
-static void dscc4_irq(int irq, void *dev_instance, struct pt_regs *ptregs)
+static void dscc4_irq(int irq, void *token, struct pt_regs *ptregs)
 {
-	struct net_device *dev = dev_instance;
+	struct dscc4_dev_priv *root = token;
 	struct dscc4_pci_priv *priv;
+	struct net_device *dev;
 	u32 ioaddr, state;
 	unsigned long flags;
 	int i;
 
-	priv = ((struct dscc4_dev_priv *)dev->priv)->pci_priv;
-	/* 
-	 * FIXME: shorten the protected area (set some bit telling we're
-	 * in an interrupt or increment some work-to-do counter etc...)
-	 */
+	priv = root->pci_priv;
+	dev = hdlc_to_dev(&root->hdlc);
+
 	spin_lock_irqsave(&priv->lock, flags);
 
 	ioaddr = dev->base_addr;
@@ -1162,15 +1334,15 @@
 		goto out;
 	writel(state, ioaddr + GSTAR);
 
-	if (state & Arf) { 
+	if (state & Arf) {
 		printk(KERN_ERR "%s: failure (Arf). Harass the maintener\n",
 		       dev->name);
 		goto out;
 	}
 	state &= ~ArAck;
 	if (state & Cfg) {
-		if (debug)
-			printk(KERN_DEBUG "CfgIV\n");
+		if (debug > 0)
+			printk(KERN_DEBUG "%s: CfgIV\n", DRV_NAME);
 		if (priv->iqcfg[priv->cfg_cur++%IRQ_RING_SIZE] & Arf)
 			printk(KERN_ERR "%s: %s failed\n", dev->name, "CFG");
 		if (!(state &= ~Cfg))
@@ -1179,14 +1351,14 @@
 	if (state & RxEvt) {
 		i = dev_per_card - 1;
 		do {
-			dscc4_rx_irq(priv, dev + i);
+			dscc4_rx_irq(priv, root + i);
 		} while (--i >= 0);
 		state &= ~RxEvt;
 	}
 	if (state & TxEvt) {
 		i = dev_per_card - 1;
 		do {
-			dscc4_tx_irq(priv, dev + i);
+			dscc4_tx_irq(priv, root + i);
 		} while (--i >= 0);
 		state &= ~TxEvt;
 	}
@@ -1194,10 +1366,10 @@
 	spin_unlock_irqrestore(&priv->lock, flags);
 }
 
-static __inline__ void dscc4_tx_irq(struct dscc4_pci_priv *ppriv, 
-				    struct net_device *dev)
+static inline void dscc4_tx_irq(struct dscc4_pci_priv *ppriv,
+				struct dscc4_dev_priv *dpriv)
 {
-	struct dscc4_dev_priv *dpriv = dev->priv;
+	struct net_device *dev = hdlc_to_dev(&dpriv->hdlc);
 	u32 state;
 	int cur, loop = 0;
 
@@ -1205,161 +1377,154 @@
 	cur = dpriv->iqtx_current%IRQ_RING_SIZE;
 	state = dpriv->iqtx[cur];
 	if (!state) {
-#ifdef DEBUG
-		if (loop > 1)
+		if ((debug > 1) && (loop > 1))
 			printk(KERN_DEBUG "%s: Tx irq loop=%d\n", dev->name, loop);
-#endif
 		if (loop && netif_queue_stopped(dev))
-			if ((dpriv->tx_dirty + 8) >= dpriv->tx_current)
+			if ((dpriv->tx_current - dpriv->tx_dirty)%TX_RING_SIZE)
 				netif_wake_queue(dev);
+
+		if (netif_running(dev) && dscc4_tx_quiescent(dpriv, dev) &&
+		    !dscc4_tx_done(dpriv))
+				dscc4_do_tx(dpriv, dev);
 		return;
 	}
 	loop++;
 	dpriv->iqtx[cur] = 0;
 	dpriv->iqtx_current++;
 
-#ifdef DEBUG_PARANOID
-	if (SOURCE_ID(state) != dpriv->dev_id) {
-		printk(KERN_DEBUG "%s (Tx): Source Id=%d, state=%08x\n",
-		       dev->name, SOURCE_ID(state), state );
+	if (state_check(state, dpriv, dev, "Tx") < 0)
 		return;
-	}
-	if (state & 0x0df80c00) {
-		printk(KERN_DEBUG "%s (Tx): state=%08x (UFO alert)\n",
-		       dev->name, state);
-		return;
-	}
-#endif
-	// state &= 0x0fffffff; /* Tracking the analyzed bits */
+
 	if (state & SccEvt) {
 		if (state & Alls) {
-			struct TxFD *tx_fd;
+			struct net_device_stats *stats = &dpriv->hdlc.stats;
 			struct sk_buff *skb;
+			struct TxFD *tx_fd;
 
+			if (debug > 2)
+				dscc4_tx_print(dev, dpriv, "Alls");
+			/*
+			 * DataComplete can't be trusted for Tx completion.
+			 * Cf errata DS5 p.8
+			 */
 			cur = dpriv->tx_dirty%TX_RING_SIZE;
 			tx_fd = dpriv->tx_fd + cur;
-
 			skb = dpriv->tx_skbuff[cur];
-
-			/* XXX: hideous kludge - to be removed "later" */
-			if (!skb) {
-				printk(KERN_ERR "%s: NULL skb in tx_irq at index %d\n", dev->name, cur);
-				goto try;
-			}
-			dpriv->tx_dirty++; // MUST be after skb test
-
-			/* Happens sometime. Don't know what triggers it */
-			if (!(tx_fd->complete & DataComplete)) {
-				u32 ioaddr, isr;
-
-				ioaddr = dev->base_addr + 
-					 SCC_REG_START(dpriv->dev_id) + ISR;
-				isr = readl(ioaddr);
-				printk(KERN_DEBUG 
-				       "%s: DataComplete=0 cur=%d isr=%08x state=%08x\n",
-				       dev->name, cur, isr, state);
-				writel(isr, ioaddr);
-				dpriv->stats.tx_dropped++;
-			} else {
-				tx_fd->complete &= ~DataComplete;
+			if (skb) {
+				pci_unmap_single(ppriv->pdev, tx_fd->data,
+						 skb->len, PCI_DMA_TODEVICE);
 				if (tx_fd->state & FrameEnd) {
-					dpriv->stats.tx_packets++;
-					dpriv->stats.tx_bytes += skb->len;
+					stats->tx_packets++;
+					stats->tx_bytes += skb->len;
 				}
+				dev_kfree_skb_irq(skb);
+				dpriv->tx_skbuff[cur] = NULL;
+				++dpriv->tx_dirty;
+			} else {
+				if (debug > 1)
+					printk(KERN_ERR "%s Tx: NULL skb %d\n",
+						dev->name, cur);
 			}
+			/*
+			 * If the driver ends sending crap on the wire, it
+			 * will be way easier to diagnose than the (not so)
+			 * random freeze induced by null sized tx frames.
+			 */
+			tx_fd->data = tx_fd->next;
+			tx_fd->state = FrameEnd | TO_STATE(2*DUMMY_SKB_SIZE);
+			tx_fd->complete = 0x00000000;
+			tx_fd->jiffies = 0;
 
-			dpriv->tx_skbuff[cur] = NULL;
-			pci_unmap_single(ppriv->pdev, tx_fd->data, skb->len,
-					 PCI_DMA_TODEVICE);
-			tx_fd->data = 0; /* DEBUG */
-			dev_kfree_skb_irq(skb);
-{ // DEBUG
-			cur = (dpriv->tx_dirty-1)%TX_RING_SIZE;
-			tx_fd = dpriv->tx_fd + cur;
-			tx_fd->state |= Hold;
-}
 			if (!(state &= ~Alls))
 				goto try;
 		}
-		/* 
+		/*
 		 * Transmit Data Underrun
 		 */
 		if (state & Xdu) {
-			printk(KERN_ERR "dscc4: XDU. Contact maintainer\n");
-			dpriv->flags = NeedIDT; 
+			printk(KERN_ERR "%s: XDU. Ask maintainer\n", DRV_NAME);
+			dpriv->flags = NeedIDT;
 			/* Tx reset */
-			writel(MTFi | Rdt, 
+			writel(MTFi | Rdt,
 			       dev->base_addr + 0x0c*dpriv->dev_id + CH0CFG);
-			writel(0x00000001, dev->base_addr + GCMDR);
+			writel(Action, dev->base_addr + GCMDR);
 			return;
 		}
+		if (state & Cts) {
+			printk(KERN_INFO "%s: CTS transition\n", dev->name);
+			if (!(state &= ~Cts)) /* DEBUG */
+				goto try;
+		}
 		if (state & Xmr) {
 			/* Frame needs to be sent again - FIXME */
-			//dscc4_start_xmit(dpriv->tx_skbuff[dpriv->tx_dirty], dev);
-			if (!(state &= ~0x00002000)) /* DEBUG */
+			printk(KERN_ERR "%s: Xmr. Ask maintainer\n", DRV_NAME);
+			if (!(state &= ~Xmr)) /* DEBUG */
 				goto try;
 		}
 		if (state & Xpr) {
-			unsigned long ioaddr = dev->base_addr;
-			unsigned long scc_offset;
-			u32 scc_addr;
+			u32 scc_addr, ring;
 
-			scc_offset = ioaddr + SCC_REG_START(dpriv->dev_id);
-			scc_addr = ioaddr + 0x0c*dpriv->dev_id;
-			if (readl(scc_offset + STAR) & SccBusy)
-				printk(KERN_DEBUG "%s busy. Fatal\n", 
-				       dev->name);
-			/*
-			 * Keep this order: IDT before IDR
-			 */
+			if (scc_readl_star(dpriv, dev) & SccBusy)
+				printk(KERN_ERR "%s busy. Fatal\n", dev->name);
+			scc_addr = dev->base_addr + 0x0c*dpriv->dev_id;
+			/* Keep this order: IDT before IDR */
 			if (dpriv->flags & NeedIDT) {
-				writel(MTFi | Idt, scc_addr + CH0CFG);
-				writel(dpriv->tx_fd_dma + 
+				if (debug > 2)
+					dscc4_tx_print(dev, dpriv, "Xpr");
+				ring = dpriv->tx_fd_dma +
 				       (dpriv->tx_dirty%TX_RING_SIZE)*
-				       sizeof(struct TxFD), scc_addr + CH0BTDA);
-				if(dscc4_do_action(dev, "IDT"))
+				       sizeof(struct TxFD);
+				writel(ring, scc_addr + CH0BTDA);
+				dscc4_do_tx(dpriv, dev);
+				writel(MTFi | Idt, scc_addr + CH0CFG);
+				if (dscc4_do_action(dev, "IDT") < 0)
 					goto err_xpr;
 				dpriv->flags &= ~NeedIDT;
-				mb();
 			}
 			if (dpriv->flags & NeedIDR) {
-				writel(MTFi | Idr, scc_addr + CH0CFG);
-				writel(dpriv->rx_fd_dma + 
+				ring = dpriv->rx_fd_dma +
 				       (dpriv->rx_current%RX_RING_SIZE)*
-				       sizeof(struct RxFD), scc_addr + CH0BRDA);
-				if(dscc4_do_action(dev, "IDR"))
+				       sizeof(struct RxFD);
+				writel(ring, scc_addr + CH0BRDA);
+				dscc4_rx_update(dpriv, dev);
+				writel(MTFi | Idr, scc_addr + CH0CFG);
+				if (dscc4_do_action(dev, "IDR") < 0)
 					goto err_xpr;
 				dpriv->flags &= ~NeedIDR;
-				mb();
+				smp_wmb();
 				/* Activate receiver and misc */
-				writel(0x08050008, scc_offset + CCR2);
+				scc_writel(0x08050008, dpriv, dev, CCR2);
 			}
 		err_xpr:
 			if (!(state &= ~Xpr))
 				goto try;
 		}
+		if (state & Cd) {
+			printk(KERN_INFO "%s: CD transition\n", dev->name);
+			if (!(state &= ~Cd)) /* DEBUG */
+				goto try;
+		}
 	} else { /* ! SccEvt */
 		if (state & Hi) {
-#ifdef EXPERIMENTAL_POLLING
-			while(!dscc4_tx_poll(dpriv, dev));
+#ifdef DSCC4_POLLING
+			while (!dscc4_tx_poll(dpriv, dev));
 #endif
+			printk(KERN_INFO "%s: Tx Hi\n", dev->name);
 			state &= ~Hi;
 		}
-		/*
-		 * FIXME: it may be avoided. Re-re-re-read the manual.
-		 */
 		if (state & Err) {
-			printk(KERN_ERR "%s: Tx ERR\n", dev->name);
-			dpriv->stats.tx_errors++;
+			printk(KERN_INFO "%s: Tx ERR\n", dev->name);
+			dev_to_hdlc(dev)->stats.tx_errors++;
 			state &= ~Err;
 		}
 	}
 	goto try;
 }
 
-static __inline__ void dscc4_rx_irq(struct dscc4_pci_priv *priv, struct net_device *dev)
+static inline void dscc4_rx_irq(struct dscc4_pci_priv *priv,
+				    struct dscc4_dev_priv *dpriv)
 {
-	struct dscc4_dev_priv *dpriv = dev->priv;
+	struct net_device *dev = hdlc_to_dev(&dpriv->hdlc);
 	u32 state;
 	int cur;
 
@@ -1371,117 +1536,107 @@
 	dpriv->iqrx[cur] = 0;
 	dpriv->iqrx_current++;
 
-#ifdef DEBUG_PARANOID
-	if (SOURCE_ID(state) != dpriv->dev_id) {
-		printk(KERN_DEBUG "%s (Rx): Source Id=%d, state=%08x\n",
-		       dev->name, SOURCE_ID(state), state);
-		goto try;
-	}
-	if (state & 0x0df80c00) {
-		printk(KERN_DEBUG "%s (Rx): state=%08x (UFO alert)\n",
-		       dev->name, state);
-		goto try;
-	}
-#endif
+	if (state_check(state, dpriv, dev, "Rx") < 0)
+		return;
+
 	if (!(state & SccEvt)){
 		struct RxFD *rx_fd;
 
 		state &= 0x00ffffff;
 		if (state & Err) { /* Hold or reset */
-			printk(KERN_DEBUG "%s (Rx): ERR\n", dev->name);
-			cur = dpriv->rx_current;
+			printk(KERN_DEBUG "%s: Rx ERR\n", dev->name);
+			cur = dpriv->rx_current%RX_RING_SIZE;
 			rx_fd = dpriv->rx_fd + cur;
 			/*
-			 * Presume we're not facing a DMAC receiver reset. 
-			 * As We use the rx size-filtering feature of the 
-			 * DSCC4, the beginning of a new frame is waiting in 
-			 * the rx fifo. I bet a Receive Data Overflow will 
+			 * Presume we're not facing a DMAC receiver reset.
+			 * As We use the rx size-filtering feature of the
+			 * DSCC4, the beginning of a new frame is waiting in
+			 * the rx fifo. I bet a Receive Data Overflow will
 			 * happen most of time but let's try and avoid it.
 			 * Btw (as for RDO) if one experiences ERR whereas
-			 * the system looks rather idle, there may be a 
+			 * the system looks rather idle, there may be a
 			 * problem with latency. In this case, increasing
 			 * RX_RING_SIZE may help.
 			 */
-			while (dpriv->rx_needs_refill) {
-				while(!(rx_fd->state1 & Hold)) {
+			//while (dpriv->rx_needs_refill) {
+				while (!(rx_fd->state1 & Hold)) {
 					rx_fd++;
 					cur++;
 					if (!(cur = cur%RX_RING_SIZE))
 						rx_fd = dpriv->rx_fd;
 				}
-				dpriv->rx_needs_refill--;
-				try_get_rx_skb(dpriv, cur, dev);
+				//dpriv->rx_needs_refill--;
+				try_get_rx_skb(dpriv, dev);
 				if (!rx_fd->data)
 					goto try;
 				rx_fd->state1 &= ~Hold;
 				rx_fd->state2 = 0x00000000;
 				rx_fd->end = 0xbabeface;
-			}
+			//}
 			goto try;
 		}
 		if (state & Fi) {
-			cur = dpriv->rx_current%RX_RING_SIZE;
-			rx_fd = dpriv->rx_fd + cur;
-			dscc4_rx_skb(dpriv, cur, rx_fd, dev);
-			dpriv->rx_current++;
+			dscc4_rx_skb(dpriv, dev);
 			goto try;
 		}
 		if (state & Hi ) { /* HI bit */
+			printk(KERN_INFO "%s: Rx Hi\n", dev->name);
 			state &= ~Hi;
 			goto try;
 		}
-	} else { /* ! SccEvt */
-#ifdef DEBUG_PARANOIA
-		int i;
+	} else { /* SccEvt */
+		if (debug > 1) {
+			//FIXME: verifier la presence de tous les evenements
 		static struct {
 			u32 mask;
 			const char *irq_name;
 		} evts[] = {
 			{ 0x00008000, "TIN"},
-			{ 0x00004000, "CSC"},
 			{ 0x00000020, "RSC"},
 			{ 0x00000010, "PCE"},
 			{ 0x00000008, "PLLA"},
-			{ 0x00000004, "CDSC"},
 			{ 0, NULL}
-		};
-#endif /* DEBUG_PARANOIA */
-		state &= 0x00ffffff;
-#ifdef DEBUG_PARANOIA
-		for (i = 0; evts[i].irq_name; i++) {
-			if (state & evts[i].mask) {
-				printk(KERN_DEBUG "dscc4(%s): %s\n",
-					dev->name, evts[i].irq_name);
-				if (!(state &= ~evts[i].mask))
+		}, *evt;
+
+		for (evt = evts; evt->irq_name; evt++) {
+			if (state & evt->mask) {
+					printk(KERN_DEBUG "%s: %s\n",
+						dev->name, evt->irq_name);
+				if (!(state &= ~evt->mask))
 					goto try;
 			}
 		}
-#endif /* DEBUG_PARANOIA */
+		} else {
+			if (!(state &= ~0x0000c03c))
+				goto try;
+		}
+		if (state & Cts) {
+			printk(KERN_INFO "%s: CTS transition\n", dev->name);
+			if (!(state &= ~Cts)) /* DEBUG */
+				goto try;
+		}
 		/*
-		 * Receive Data Overflow (FIXME: untested)
+		 * Receive Data Overflow (FIXME: fscked)
 		 */
 		if (state & Rdo) {
-			u32 ioaddr, scc_offset, scc_addr;
 			struct RxFD *rx_fd;
+			u32 scc_addr;
 			int cur;
 
 			//if (debug)
 			//	dscc4_rx_dump(dpriv);
-			ioaddr = dev->base_addr;
-			scc_addr = ioaddr + 0x0c*dpriv->dev_id;
-			scc_offset = ioaddr + SCC_REG_START(dpriv->dev_id);
+			scc_addr = dev->base_addr + 0x0c*dpriv->dev_id;
 
-			writel(readl(scc_offset + CCR2) & ~RxActivate, 
-			       scc_offset + CCR2);
+			scc_patchl(RxActivate, 0, dpriv, dev, CCR2);
 			/*
 			 * This has no effect. Why ?
 			 * ORed with TxSccRes, one sees the CFG ack (for
 			 * the TX part only).
-			 */	
-			writel(RxSccRes, scc_offset + CMDR);
+			 */
+			scc_writel(RxSccRes, dpriv, dev, CMDR);
 			dpriv->flags |= RdoSet;
 
-			/* 
+			/*
 			 * Let's try and save something in the received data.
 			 * rx_current must be incremented at least once to
 			 * avoid HOLD in the BRDA-to-be-pointed desc.
@@ -1492,180 +1647,170 @@
 				if (!(rx_fd->state2 & DataComplete))
 					break;
 				if (rx_fd->state2 & FrameAborted) {
-					dpriv->stats.rx_over_errors++;
+					dev_to_hdlc(dev)->stats.rx_over_errors++;
 					rx_fd->state1 |= Hold;
 					rx_fd->state2 = 0x00000000;
 					rx_fd->end = 0xbabeface;
-				} else 
-					dscc4_rx_skb(dpriv, cur, rx_fd, dev);
+				} else
+					dscc4_rx_skb(dpriv, dev);
 			} while (1);
 
-			if (debug) {
+			if (debug > 0) {
 				if (dpriv->flags & RdoSet)
-					printk(KERN_DEBUG 
-					       "dscc4: no RDO in Rx data\n");
+					printk(KERN_DEBUG
+					       "%s: no RDO in Rx data\n", DRV_NAME);
 			}
 #ifdef DSCC4_RDO_EXPERIMENTAL_RECOVERY
 			/*
 			 * FIXME: must the reset be this violent ?
 			 */
-			writel(dpriv->rx_fd_dma + 
+#warning "FIXME: CH0BRDA"
+			writel(dpriv->rx_fd_dma +
 			       (dpriv->rx_current%RX_RING_SIZE)*
 			       sizeof(struct RxFD), scc_addr + CH0BRDA);
 			writel(MTFi|Rdr|Idr, scc_addr + CH0CFG);
-			if(dscc4_do_action(dev, "RDR")) {
+			if (dscc4_do_action(dev, "RDR") < 0) {
 				printk(KERN_ERR "%s: RDO recovery failed(%s)\n",
 				       dev->name, "RDR");
 				goto rdo_end;
 			}
 			writel(MTFi|Idr, scc_addr + CH0CFG);
-			if(dscc4_do_action(dev, "IDR")) {
+			if (dscc4_do_action(dev, "IDR") < 0) {
 				printk(KERN_ERR "%s: RDO recovery failed(%s)\n",
 				       dev->name, "IDR");
 				goto rdo_end;
 			}
 		rdo_end:
 #endif
-			writel(readl(scc_offset + CCR2) | RxActivate, 
-			       scc_offset + CCR2);
+			scc_patchl(0, RxActivate, dpriv, dev, CCR2);
 			goto try;
 		}
-		/* These will be used later */
-		if (state & Rfs) {
-			if (!(state &= ~Rfs))
-				goto try;
-		}
-		if (state & Rfo) {
-			if (!(state &= ~Rfo))
+		if (state & Cd) {
+			printk(KERN_INFO "%s: CD transition\n", dev->name);
+			if (!(state &= ~Cd)) /* DEBUG */
 				goto try;
 		}
 		if (state & Flex) {
+			printk(KERN_DEBUG "%s: Flex. Ttttt...\n", DRV_NAME);
 			if (!(state &= ~Flex))
 				goto try;
 		}
 	}
 }
 
+/*
+ * I had expected the following to work for the first descriptor
+ * (tx_fd->state = 0xc0000000)
+ * - Hold=1 (don't try and branch to the next descripto);
+ * - No=0 (I want an empty data section, i.e. size=0);
+ * - Fe=1 (required by No=0 or we got an Err irq and must reset).
+ * It failed and locked solid. Thus the introduction of a dummy skb.
+ * Problem is acknowledged in errata sheet DS5. Joy :o/
+ */
+struct sk_buff *dscc4_init_dummy_skb(struct dscc4_dev_priv *dpriv)
+{
+	struct sk_buff *skb;
+
+	skb = dev_alloc_skb(DUMMY_SKB_SIZE);
+	if (skb) {
+		int last = dpriv->tx_dirty%TX_RING_SIZE;
+		struct TxFD *tx_fd = dpriv->tx_fd + last;
+
+		skb->len = DUMMY_SKB_SIZE;
+		memcpy(skb->data, version, strlen(version)%DUMMY_SKB_SIZE);
+		tx_fd->state = FrameEnd | TO_STATE(DUMMY_SKB_SIZE);
+		tx_fd->data = pci_map_single(dpriv->pci_priv->pdev, skb->data,
+					     DUMMY_SKB_SIZE, PCI_DMA_TODEVICE);
+		dpriv->tx_skbuff[last] = skb;
+	}
+	return skb;
+}
+
 static int dscc4_init_ring(struct net_device *dev)
 {
-	struct dscc4_dev_priv *dpriv = (struct dscc4_dev_priv *)dev->priv;
+	struct dscc4_dev_priv *dpriv = dscc4_priv(dev);
+	struct pci_dev *pdev = dpriv->pci_priv->pdev;
 	struct TxFD *tx_fd;
 	struct RxFD *rx_fd;
+	void *ring;
 	int i;
 
-	tx_fd = (struct TxFD *) pci_alloc_consistent(dpriv->pci_priv->pdev,
-		TX_RING_SIZE*sizeof(struct TxFD), &dpriv->tx_fd_dma);
-	if (!tx_fd)
+	ring = pci_alloc_consistent(pdev, RX_TOTAL_SIZE, &dpriv->rx_fd_dma);
+	if (!ring)
 		goto err_out;
-	rx_fd = (struct RxFD *) pci_alloc_consistent(dpriv->pci_priv->pdev,
-		RX_RING_SIZE*sizeof(struct RxFD), &dpriv->rx_fd_dma);
-	if (!rx_fd)
-		goto err_free_dma_tx;
+	dpriv->rx_fd = rx_fd = (struct RxFD *) ring;
 
-	dpriv->tx_fd = tx_fd;
-	dpriv->rx_fd = rx_fd;
-	dpriv->rx_current = 0;
-	dpriv->tx_current = 0;
-	dpriv->tx_dirty = 0;
-
-	/* the dma core of the dscc4 will be locked on the first desc */
-	for(i = 0; i < TX_RING_SIZE; ) {
-		reset_TxFD(tx_fd);
+	ring = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &dpriv->tx_fd_dma);
+	if (!ring)
+		goto err_free_dma_rx;
+	dpriv->tx_fd = tx_fd = (struct TxFD *) ring;
+
+	memset(dpriv->tx_skbuff, 0, sizeof(struct sk_buff *)*TX_RING_SIZE);
+	dpriv->tx_dirty = 0xffffffff;
+	i = dpriv->tx_current = 0;
+	do {
+		tx_fd->state = FrameEnd | TO_STATE(2*DUMMY_SKB_SIZE);
+		tx_fd->complete = 0x00000000;
 	        /* FIXME: NULL should be ok - to be tried */
 	        tx_fd->data = dpriv->tx_fd_dma;
-	        dpriv->tx_skbuff[i] = NULL;
-		i++;
-		tx_fd->next = (u32)(dpriv->tx_fd_dma + i*sizeof(struct TxFD));
-		tx_fd++;
-	}
-	(--tx_fd)->next = (u32)dpriv->tx_fd_dma;
-{
-	/*
-	 * XXX: I would expect the following to work for the first descriptor
-	 * (tx_fd->state = 0xc0000000)
-	 * - Hold=1 (don't try and branch to the next descripto);
-	 * - No=0 (I want an empty data section, i.e. size=0);
-	 * - Fe=1 (required by No=0 or we got an Err irq and must reset).
-	 * Alas, it fails (and locks solid). Thus the introduction of a dummy
-	 * skb to avoid No=0 (choose one: Ugly [ ] Tasteless [ ] VMS [ ]).
-	 * TODO: fiddle the tx threshold when time permits.
-	 */
-	struct sk_buff *skb;
+		(tx_fd++)->next = (u32)(dpriv->tx_fd_dma +
+					(++i%TX_RING_SIZE)*sizeof(*tx_fd));
+	} while (i < TX_RING_SIZE);
 
-	skb = dev_alloc_skb(32);
-	if (!skb)
+	if (dscc4_init_dummy_skb(dpriv) < 0)
 		goto err_free_dma_tx;
-	skb->len = 32;
-	memset(skb->data, 0xaa, 16);
-	tx_fd -= (TX_RING_SIZE - 1);
-	tx_fd->state = 0xc0000000;
-	tx_fd->state |= ((u32)(skb->len & TxSizeMax)) << 16;
-	tx_fd->data = pci_map_single(dpriv->pci_priv->pdev, skb->data, 
-				     skb->len, PCI_DMA_TODEVICE);
-	dpriv->tx_skbuff[0] = skb;
-}
-	for (i = 0; i < RX_RING_SIZE;) {
+
+	memset(dpriv->rx_skbuff, 0, sizeof(struct sk_buff *)*RX_RING_SIZE);
+	i = dpriv->rx_dirty = dpriv->rx_current = 0;
+	do {
 		/* size set by the host. Multiple of 4 bytes please */
-	        rx_fd->state1 = HiDesc; /* Hi, no Hold */
+	        rx_fd->state1 = HiDesc;
 	        rx_fd->state2 = 0x00000000;
 	        rx_fd->end = 0xbabeface;
-	        rx_fd->state1 |= ((u32)(HDLC_MAX_MRU & RxSizeMax)) << 16;
-		try_get_rx_skb(dpriv, i, dev);
-		i++;
-		rx_fd->next = (u32)(dpriv->rx_fd_dma + i*sizeof(struct RxFD));
-		rx_fd++;
-	}
-	(--rx_fd)->next = (u32)dpriv->rx_fd_dma;
-	rx_fd->state1 |= 0x40000000; /* Hold */
+	        rx_fd->state1 |= TO_STATE(RX_MAX(HDLC_MAX_MRU));
+		// FIXME: return value verifiee mais traitement suspect
+		if (try_get_rx_skb(dpriv, dev) >= 0)
+			dpriv->rx_dirty++;
+		(rx_fd++)->next = (u32)(dpriv->rx_fd_dma +
+					(++i%RX_RING_SIZE)*sizeof(*rx_fd));
+	} while (i < RX_RING_SIZE);
 
 	return 0;
 
 err_free_dma_tx:
-	pci_free_consistent(dpriv->pci_priv->pdev, TX_RING_SIZE*sizeof(*tx_fd),
-			    tx_fd, dpriv->tx_fd_dma);
+	pci_free_consistent(pdev, TX_TOTAL_SIZE, ring, dpriv->tx_fd_dma);
+err_free_dma_rx:
+	pci_free_consistent(pdev, RX_TOTAL_SIZE, rx_fd, dpriv->rx_fd_dma);
 err_out:
-	return -1;
-}
-
-static struct net_device_stats *dscc4_get_stats(struct net_device *dev)
-{
-	struct dscc4_dev_priv *priv = (struct dscc4_dev_priv *)dev->priv;
-
-	return &priv->stats;
+	return -ENOMEM;
 }
 
 static void __exit dscc4_remove_one(struct pci_dev *pdev)
 {
 	struct dscc4_pci_priv *ppriv;
-	struct net_device *root;
+	struct dscc4_dev_priv *root;
+	u32 ioaddr;
 	int i;
 
 	ppriv = pci_get_drvdata(pdev);
 	root = ppriv->root;
 
+	ioaddr = hdlc_to_dev(&root->hdlc)->base_addr;
 	free_irq(pdev->irq, root);
-	pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32), ppriv->iqcfg, 
+	pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32), ppriv->iqcfg,
 			    ppriv->iqcfg_dma);
-	for (i=0; i < dev_per_card; i++) {
-		struct dscc4_dev_priv *dpriv;
-		struct net_device *dev;
-
-		dev = ppriv->root + i;
-		dscc4_unattach_hdlc_device(dev);
+	for (i = 0; i < dev_per_card; i++) {
+		struct dscc4_dev_priv *dpriv = root + i;
 
-		dpriv = (struct dscc4_dev_priv *)dev->priv;
-		pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32), 
+		pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32),
 				    dpriv->iqrx, dpriv->iqrx_dma);
-		pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32), 
+		pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32),
 				    dpriv->iqtx, dpriv->iqtx_dma);
-		unregister_netdev(dev);
 	}
-	kfree(root->priv);
 
-	iounmap((void *)root->base_addr);
-	kfree(root);
+	dscc4_free1(pdev);
 
-	kfree(ppriv);
+	iounmap((void *)ioaddr);
 
 	release_mem_region(pci_resource_start(pdev, 1),
 			   pci_resource_len(pdev, 1));
@@ -1673,73 +1818,41 @@
 			   pci_resource_len(pdev, 0));
 }
 
-static int dscc4_hdlc_ioctl(struct hdlc_device_struct *hdlc, struct ifreq *ifr, int cmd)
-{
-	struct net_device *dev = (struct net_device *)hdlc->netdev.base_addr;
-	int result;
-
-	/* FIXME: locking ? */
-	result = dscc4_ioctl(dev, ifr, cmd);
-	return result;
-}
-
-static int dscc4_hdlc_open(struct hdlc_device_struct *hdlc)
+static int dscc4_hdlc_attach(hdlc_device *hdlc, unsigned short encoding,
+	unsigned short parity)
 {
-	struct net_device *dev = (struct net_device *)(hdlc->netdev.base_addr);
+	struct net_device *dev = hdlc_to_dev(hdlc);
+	struct dscc4_dev_priv *dpriv = dscc4_priv(dev);
 
-        if (netif_running(dev)) {
-		printk(KERN_DEBUG "%s: already running\n", dev->name); // DEBUG
-		return 0;
-	}
-	return dscc4_open(dev);
-}
-
-static int dscc4_hdlc_xmit(hdlc_device *hdlc, struct sk_buff *skb)
-{
-	struct net_device *dev = (struct net_device *)hdlc->netdev.base_addr;
-
-	return dscc4_start_xmit(skb, dev);
-}
+	if (encoding != ENCODING_NRZ &&
+	    encoding != ENCODING_NRZI &&
+	    encoding != ENCODING_FM_MARK &&
+	    encoding != ENCODING_FM_SPACE &&
+	    encoding != ENCODING_MANCHESTER)
+		return -EINVAL;
 
-static void dscc4_hdlc_close(struct hdlc_device_struct *hdlc)
-{
-	struct net_device *dev = (struct net_device *)hdlc->netdev.base_addr;
-	struct dscc4_dev_priv *dpriv;
+	if (parity != PARITY_NONE &&
+	    parity != PARITY_CRC16_PR0_CCITT &&
+	    parity != PARITY_CRC16_PR1_CCITT &&
+	    parity != PARITY_CRC32_PR0_CCITT &&
+	    parity != PARITY_CRC32_PR1_CCITT)
+		return -EINVAL;
 
-	dpriv = dev->priv;
-	--dpriv->usecount;
+        dpriv->encoding = encoding;
+        dpriv->parity = parity;
+	return 0;
 }
 
-/* Operated under dev lock */
-static int dscc4_attach_hdlc_device(struct net_device *dev) 
+static int __init dscc4_setup(char *str)
 {
-	struct dscc4_dev_priv *dpriv = dev->priv;
-	struct hdlc_device_struct *hdlc;
-	int result;
+	int *args[] = { &debug, &quartz, NULL }, **p = args;
 
-	hdlc = &dpriv->hdlc;
-	/* XXX: Don't look at the next line */
-	hdlc->netdev.base_addr = (unsigned long)dev;
-	hdlc->set_mode = NULL;
-	hdlc->open = dscc4_hdlc_open;
-	hdlc->close = dscc4_hdlc_close;
-	hdlc->ioctl = dscc4_hdlc_ioctl;
-	hdlc->xmit = dscc4_hdlc_xmit;
-
-	result = register_hdlc_device(hdlc);
-	if (!result)
-		dpriv->usecount++;
-	return result;
+	while (*p && (get_option(&str, *p) == 2))
+		p++;
+	return 1;
 }
 
-/* Operated under dev lock */
-static void dscc4_unattach_hdlc_device(struct net_device *dev) 
-{
-	struct dscc4_dev_priv *dpriv = dev->priv;
-
-	unregister_hdlc_device(&dpriv->hdlc);
-	dpriv->usecount--;
-}
+__setup("dscc4.setup=", dscc4_setup);
 
 static struct pci_device_id dscc4_pci_tbl[] __devinitdata = {
 	{ PCI_VENDOR_ID_SIEMENS, PCI_DEVICE_ID_SIEMENS_DSCC4,
@@ -1749,10 +1862,10 @@
 MODULE_DEVICE_TABLE(pci, dscc4_pci_tbl);
 
 static struct pci_driver dscc4_driver = {
-	name:           "dscc4",
-	id_table:       dscc4_pci_tbl,
-	probe:          dscc4_init_one,
-	remove:         dscc4_remove_one,
+	.name		= DRV_NAME,
+	.id_table	= dscc4_pci_tbl,
+	.probe		= dscc4_init_one,
+	.remove		= dscc4_remove_one,
 };
 
 static int __init dscc4_init_module(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/wan/farsync.c linux-2.4.21-pre6/drivers/net/wan/farsync.c
--- linux-2.4.20/drivers/net/wan/farsync.c	2001-12-21 17:41:55.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/wan/farsync.c	2003-03-26 23:49:08.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- *      FarSync X21 driver for Linux (2.4.x kernel version)
+ *      FarSync X21 driver for Linux (generic HDLC version)
  *
  *      Actually sync driver for X.21, V.35 and V.24 on FarSync T-series cards
  *
@@ -18,11 +18,10 @@
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/ioport.h>
-#include <linux/netdevice.h>
 #include <linux/init.h>
-#include <linux/if_arp.h>
 #include <asm/uaccess.h>
-#include <net/syncppp.h>
+#include <linux/if.h>
+#include <linux/hdlc.h>
 
 #include "farsync.h"
 
@@ -32,6 +31,7 @@
  */
 MODULE_AUTHOR("R.J.Dunlop <bob.dunlop@farsite.co.uk>");
 MODULE_DESCRIPTION("FarSync T-Series X21 driver. FarSite Communications Ltd.");
+MODULE_LICENSE("GPL");
 
 EXPORT_NO_SYMBOLS;
 
@@ -331,26 +331,15 @@
 /*      Per port (line or channel) information
  */
 struct fst_port_info {
-        void                   *if_ptr; /* Some drivers describe this as a
-                                         * general purpose pointer. However if
-                                         * using syncPPP it has a very specific
-                                         * purpose: it must be the first item in
-                                         * the structure pointed to by dev->priv
-                                         * and must in turn point to the
-                                         * associated ppp_device structure.
-                                         */
+        hdlc_device             hdlc;   /* HDLC device struct - must be first */
         struct fst_card_info   *card;   /* Card we're associated with */
         int                     index;  /* Port index on the card */
-        int                     proto;  /* Protocol we are running */
         int                     hwif;   /* Line hardware (lineInterface copy) */
         int                     run;    /* Port is running */
         int                     rxpos;  /* Next Rx buffer to use */
         int                     txpos;  /* Next Tx buffer to use */
         int                     txipos; /* Next Tx buffer to check for free */
         int                     txcnt;  /* Count of Tx buffers in use */
-        struct net_device      *dev;    /* Kernel network device entry */
-        struct net_device_stats stats;  /* Standard statistics */
-        struct ppp_device       pppdev; /* Link to syncPPP */
 };
 
 /*      Per card information
@@ -370,6 +359,11 @@
         struct fst_port_info ports[ FST_MAX_PORTS ];
 };
 
+/* Convert an HDLC device pointer into a port info pointer and similar */
+#define hdlc_to_port(H) ((struct fst_port_info *)(H))
+#define dev_to_port(D)  hdlc_to_port(dev_to_hdlc(D))
+#define port_to_dev(P)  hdlc_to_dev(&(P)->hdlc)
+
 
 /*
  *      Shared memory window access macros
@@ -632,25 +626,18 @@
 
         if ( signals & (( port->hwif == X21 ) ? IPSTS_INDICATE : IPSTS_DCD ))
         {
-                if ( ! netif_carrier_ok ( port->dev ))
+                if ( ! netif_carrier_ok ( port_to_dev ( port )))
                 {
                         dbg ( DBG_INTR,"DCD active\n");
-
-                        /* Poke sPPP to renegotiate */
-                        if ( port->proto == FST_HDLC || port->proto == FST_PPP )
-                        {
-                                sppp_reopen ( port->dev );
-                        }
-
-                        netif_carrier_on ( port->dev );
+                        netif_carrier_on ( port_to_dev ( port ));
                 }
         }
         else
         {
-                if ( netif_carrier_ok ( port->dev ))
+                if ( netif_carrier_ok ( port_to_dev ( port )))
                 {
                         dbg ( DBG_INTR,"DCD lost\n");
-                        netif_carrier_off ( port->dev );
+                        netif_carrier_off ( port_to_dev ( port ));
                 }
         }
 }
@@ -693,24 +680,24 @@
                                         len );
         if ( dmabits != ( RX_STP | RX_ENP ) || len > LEN_RX_BUFFER - 2 )
         {
-                port->stats.rx_errors++;
+                port->hdlc.stats.rx_errors++;
 
                 /* Update error stats and discard buffer */
                 if ( dmabits & RX_OFLO )
                 {
-                        port->stats.rx_fifo_errors++;
+                        port->hdlc.stats.rx_fifo_errors++;
                 }
                 if ( dmabits & RX_CRC )
                 {
-                        port->stats.rx_crc_errors++;
+                        port->hdlc.stats.rx_crc_errors++;
                 }
                 if ( dmabits & RX_FRAM )
                 {
-                        port->stats.rx_frame_errors++;
+                        port->hdlc.stats.rx_frame_errors++;
                 }
                 if ( dmabits == ( RX_STP | RX_ENP ))
                 {
-                        port->stats.rx_length_errors++;
+                        port->hdlc.stats.rx_length_errors++;
                 }
 
                 /* Discard buffer descriptors until we see the end of packet
@@ -747,7 +734,7 @@
         {
                 dbg ( DBG_RX,"intr_rx: can't allocate buffer\n");
 
-                port->stats.rx_dropped++;
+                port->hdlc.stats.rx_dropped++;
 
                 /* Return descriptor to card */
                 FST_WRB ( card, rxDescrRing[pi][rxp].bits, DMA_OWN );
@@ -771,29 +758,16 @@
                 port->rxpos = rxp;
 
         /* Update stats */
-        port->stats.rx_packets++;
-        port->stats.rx_bytes += len;
+        port->hdlc.stats.rx_packets++;
+        port->hdlc.stats.rx_bytes += len;
 
         /* Push upstream */
-        if ( port->proto == FST_HDLC || port->proto == FST_PPP )
-        {
-                /* Mark for further processing by sPPP module */
-                skb->protocol = htons ( ETH_P_WAN_PPP );
-        }
-        else
-        {
-                /* DEC customer specific protocol (since nothing defined for
-                 * marking raw data), at least one other driver uses this value
-                 * for this purpose.
-                 */
-                skb->protocol = htons ( ETH_P_CUST );
-                skb->pkt_type = PACKET_HOST;
-        }
         skb->mac.raw = skb->data;
-        skb->dev = port->dev;
+        skb->dev = hdlc_to_dev ( &port->hdlc );
+        skb->protocol = htons ( ETH_P_HDLC );
         netif_rx ( skb );
 
-        port->dev->last_rx = jiffies;
+        port_to_dev ( port )->last_rx = jiffies;
 }
 
 
@@ -844,7 +818,7 @@
                 case CTLB_CHG:
                 case CTLC_CHG:
                 case CTLD_CHG:
-                        if ( port->run && port->dev != NULL )
+                        if ( port->run )
                                 fst_intr_ctlchg ( card, port );
                         break;
 
@@ -863,9 +837,8 @@
                          * always load up the entire packet for DMA.
                          */
                         dbg ( DBG_TX,"Tx underflow port %d\n", event & 0x03 );
-
-                        port->stats.tx_errors++;
-                        port->stats.tx_fifo_errors++;
+                        port->hdlc.stats.tx_errors++;
+                        port->hdlc.stats.tx_fifo_errors++;
                         break;
 
                 case INIT_CPLT:
@@ -890,7 +863,7 @@
 
         for ( pi = 0, port = card->ports ; pi < card->nports ; pi++, port++ )
         {
-                if ( port->dev == NULL || ! port->run )
+                if ( ! port->run )
                         continue;
 
                 /* Check for rx completions */
@@ -907,7 +880,7 @@
                         --port->txcnt;
                         if ( ++port->txipos >= NUM_TX_BUFFER )
                                 port->txipos = 0;
-                        netif_wake_queue ( port->dev );
+                        netif_wake_queue ( port_to_dev ( port ));
                 }
         }
 
@@ -969,145 +942,28 @@
 
 
 static int
-fst_change_mtu ( struct net_device *dev, int new_mtu )
-{
-        if ( new_mtu < 128 || new_mtu > FST_MAX_MTU )
-                return -EINVAL;
-        dev->mtu = new_mtu;
-        return 0;
-}
-
-
-/* Sooner or later you can't avoid a forward declaration */
-static int fst_ioctl ( struct net_device *dev, struct ifreq *ifr, int cmd );
-
-static int
-switch_proto ( struct fst_port_info *port, int new_proto )
-{
-        int err;
-        int orig_mtu;
-        struct net_device *dev;
-
-        dev = port->dev;
-
-        /* Turn off sPPP module ? */
-        if (( new_proto != FST_HDLC && new_proto != FST_PPP )
-                && ( port->proto == FST_HDLC || port->proto == FST_PPP ))
-        {
-                sppp_close ( port->pppdev.dev );
-                sppp_detach ( port->pppdev.dev );
-
-                /* Reset some fields overwritten by sPPP */
-                dev->hard_header     = NULL;
-                dev->rebuild_header  = NULL;
-                dev->tx_queue_len    = FST_TX_QUEUE_LEN;
-                dev->type            = ARPHRD_MYTYPE;
-                dev->addr_len        = 0;
-                dev->hard_header_len = 0;
-                dev->do_ioctl        = fst_ioctl;
-                dev->change_mtu      = fst_change_mtu;
-                dev->flags           = IFF_POINTOPOINT|IFF_NOARP;
-
-                return 0;
-        }
-
-        /* Turn on sPPP ? */
-        if (( new_proto == FST_HDLC || new_proto == FST_PPP )
-                && ( port->proto != FST_HDLC && port->proto != FST_PPP ))
-        {
-                orig_mtu = dev->mtu;
-
-                /* Attach to sync PPP module */
-                port->pppdev.dev = dev;
-                sppp_attach ( &port->pppdev );
-
-                if ( orig_mtu < dev->mtu )
-                        dev->change_mtu ( dev, orig_mtu );
-
-                /* Claw back the ioctl routine. We promise to be good and call
-                 * the sync PPP routines once we've eliminated our functions.
-                 */
-                dev->do_ioctl = fst_ioctl;
-
-                /* Set the mode */
-                if ( new_proto == FST_HDLC )
-                {
-                        err = sppp_do_ioctl ( port->pppdev.dev, NULL,
-                                                                SPPPIOCCISCO );
-                }
-                else
-                {
-                        err = sppp_do_ioctl ( port->pppdev.dev, NULL,
-                                                                SPPPIOCPPP );
-                }
-
-                /* Open the device */
-                if ( err == 0 )
-                {
-                        (void) sppp_open ( port->dev );
-                }
-
-                return err;
-        }
-
-        /* Switch sPPP mode to that desired */
-        err = 0;
-        if ( new_proto == FST_HDLC && port->pppdev.dev != NULL )
-        {
-                err = sppp_do_ioctl ( port->pppdev.dev, NULL, SPPPIOCCISCO );
-        }
-        else if ( new_proto == FST_PPP && port->pppdev.dev != NULL )
-        {
-                err = sppp_do_ioctl ( port->pppdev.dev, NULL, SPPPIOCPPP );
-        }
-
-        /* Anything else is switching from one raw mode to another which is
-         * basically a NOP
-         */
-
-        return err;
-}
-
-
-static int
 set_conf_from_info ( struct fst_card_info *card, struct fst_port_info *port,
                 struct fstioc_info *info )
 {
         int err;
 
-        /* Set things according to the user set valid flags */
+        /* Set things according to the user set valid flags.
+         * Several of the old options have been invalidated/replaced by the
+         * generic HDLC package.
+         */
         err = 0;
         if ( info->valid & FSTVAL_PROTO )
-        {
-                if ( port->proto != info->proto )
-                {
-                        err = switch_proto ( port, info->proto );
-                        if ( err == 0 )
-                                port->proto = info->proto;
-                }
-        }
+                err = -EINVAL;
         if ( info->valid & FSTVAL_CABLE )
-        {
-                FST_WRB ( card, portConfig[port->index].lineInterface,
-                                        info->lineInterface );
-                port->hwif = info->lineInterface;
-        }
+                err = -EINVAL;
         if ( info->valid & FSTVAL_SPEED )
-        {
-                FST_WRL ( card, portConfig[port->index].lineSpeed,
-                                        info->lineSpeed );
-                FST_WRB ( card, portConfig[port->index].internalClock,
-                                        info->internalClock );
-        }
+                err = -EINVAL;
+
         if ( info->valid & FSTVAL_MODE )
-        {
                 FST_WRW ( card, cardMode, info->cardMode );
-        }
 #if FST_DEBUG
         if ( info->valid & FSTVAL_DEBUG )
-        {
                 fst_debug_mask = info->debug;
-        }
 #endif
 
         return err;
@@ -1125,7 +981,7 @@
         info->nports = card->nports;
         info->type   = card->type;
         info->state  = card->state;
-        info->proto  = port->proto;
+        info->proto  = FST_GEN_HDLC;
         info->index  = i;
 #if FST_DEBUG
         info->debug  = fst_debug_mask;
@@ -1154,6 +1010,107 @@
 
 
 static int
+fst_set_iface ( struct fst_card_info *card, struct fst_port_info *port,
+                struct ifreq *ifr )
+{
+        sync_serial_settings sync;
+        int i;
+
+        if (copy_from_user (&sync, ifr->ifr_settings.ifs_ifsu.sync,
+			    sizeof (sync)))
+                return -EFAULT;
+
+        if ( sync.loopback )
+                return -EINVAL;
+
+        i = port->index;
+
+        switch (ifr->ifr_settings.type)
+        {
+        case IF_IFACE_V35:
+                FST_WRW ( card, portConfig[i].lineInterface, V35 );
+                port->hwif = V35;
+                break;
+
+        case IF_IFACE_V24:
+                FST_WRW ( card, portConfig[i].lineInterface, V24 );
+                port->hwif = V24;
+                break;
+
+        case IF_IFACE_X21:
+                FST_WRW ( card, portConfig[i].lineInterface, X21 );
+                port->hwif = X21;
+                break;
+
+        case IF_IFACE_SYNC_SERIAL:
+                break;
+
+        default:
+                return -EINVAL;
+        }
+
+        switch ( sync.clock_type )
+        {
+        case CLOCK_EXT:
+                FST_WRB ( card, portConfig[i].internalClock, EXTCLK );
+                break;
+
+        case CLOCK_INT:
+                FST_WRB ( card, portConfig[i].internalClock, INTCLK );
+                break;
+
+        default:
+                return -EINVAL;
+        }
+        FST_WRL ( card, portConfig[i].lineSpeed, sync.clock_rate );
+        return 0;
+}
+
+static int
+fst_get_iface ( struct fst_card_info *card, struct fst_port_info *port,
+                struct ifreq *ifr )
+{
+        sync_serial_settings sync;
+        int i;
+
+        /* First check what line type is set, we'll default to reporting X.21
+         * if nothing is set as IF_IFACE_SYNC_SERIAL implies it can't be
+         * changed
+         */
+        switch ( port->hwif )
+        {
+        case V35:
+                ifr->ifr_settings.type = IF_IFACE_V35;
+                break;
+        case V24:
+                ifr->ifr_settings.type = IF_IFACE_V24;
+                break;
+        case X21:
+        default:
+                ifr->ifr_settings.type = IF_IFACE_X21;
+                break;
+        }
+
+	if (ifr->ifr_settings.size < sizeof(sync)) {
+		ifr->ifr_settings.size = sizeof(sync); /* data size wanted */
+		return -ENOBUFS;
+	}
+
+        i = port->index;
+        sync.clock_rate = FST_RDL ( card, portConfig[i].lineSpeed );
+        /* Lucky card and linux use same encoding here */
+        sync.clock_type = FST_RDB ( card, portConfig[i].internalClock );
+        sync.loopback = 0;
+
+        if (copy_to_user (ifr->ifr_settings.ifs_ifsu.sync, &sync,
+			  sizeof(sync)))
+                return -EFAULT;
+
+        return 0;
+}
+
+
+static int
 fst_ioctl ( struct net_device *dev, struct ifreq *ifr, int cmd )
 {
         struct fst_card_info *card;
@@ -1164,7 +1121,7 @@
 
         dbg ( DBG_IOCTL,"ioctl: %x, %p\n", cmd, ifr->ifr_data );
 
-        port = dev->priv;
+        port = dev_to_port ( dev );
         card = port->card;
 
         if ( !capable ( CAP_NET_ADMIN ))
@@ -1201,7 +1158,7 @@
                  * when going over the top
                  */
                 if ( wrthdr.size > FST_MEMSIZE || wrthdr.offset > FST_MEMSIZE
-                                || wrthdr.size + wrthdr.offset > FST_MEMSIZE )
+				|| wrthdr.size + wrthdr.offset > FST_MEMSIZE )
                 {
                         return -ENXIO;
                 }
@@ -1261,6 +1218,9 @@
 
         case FSTSETCONF:
 
+                /* Most of the setting have been moved to the generic ioctls
+                 * this just covers debug and board ident mode now
+                 */
                 if ( copy_from_user ( &info,  ifr->ifr_data, sizeof ( info )))
                 {
                         return -EFAULT;
@@ -1268,12 +1228,25 @@
 
                 return set_conf_from_info ( card, port, &info );
 
+        case SIOCWANDEV:
+                switch (ifr->ifr_settings.type)
+                {
+                case IF_GET_IFACE:
+                        return fst_get_iface ( card, port, ifr );
+
+                case IF_IFACE_SYNC_SERIAL:
+                case IF_IFACE_V35:
+                case IF_IFACE_V24:
+                case IF_IFACE_X21:
+                        return fst_set_iface ( card, port, ifr );
+
+                default:
+                        return hdlc_ioctl ( dev, ifr, cmd );
+                }
+
         default:
-                /* Not one of ours. Pass it through to sPPP package */
-                if ( port->proto == FST_HDLC || port->proto == FST_PPP )
-                        return sppp_do_ioctl ( dev, ifr, cmd );
-                else
-                        return -EINVAL;
+                /* Not one of ours. Pass through to HDLC package */
+                return hdlc_ioctl ( dev, ifr, cmd );
         }
 }
 
@@ -1306,9 +1279,9 @@
                 signals = FST_RDL ( port->card, v24DebouncedSts[port->index]);
                 if ( signals & (( port->hwif == X21 ) ? IPSTS_INDICATE
                                                       : IPSTS_DCD ))
-                        netif_carrier_on ( port->dev );
+                        netif_carrier_on ( port_to_dev ( port ));
                 else
-                        netif_carrier_off ( port->dev );
+                        netif_carrier_off ( port_to_dev ( port ));
         }
 }
 
@@ -1335,64 +1308,15 @@
 static int
 fst_open ( struct net_device *dev )
 {
-        struct fst_card_info *card;
-        struct fst_port_info *port;
-        int orig_mtu;
         int err;
 
-        MOD_INC_USE_COUNT;
-
-        port = dev->priv;
-        card = port->card;
-
-        switch ( port->proto )
-        {
-        case FST_HDLC:
-        case FST_PPP:
-
-                orig_mtu = dev->mtu;
-
-                /* Attach to sync PPP module */
-                port->pppdev.dev = dev;
-                sppp_attach ( &port->pppdev );
-
-                if ( orig_mtu < dev->mtu )
-                        dev->change_mtu ( dev, orig_mtu );
-
-                /* Claw back the ioctl routine. We promise to be good and call
-                 * the sync PPP routines once we've eliminated our functions.
-                 */
-                dev->do_ioctl = fst_ioctl;
-
-                err = sppp_do_ioctl ( dev, NULL, port->proto == FST_HDLC
-                                                ? SPPPIOCCISCO : SPPPIOCPPP );
-                if ( err )
-		{
-			sppp_detach ( dev );
-			MOD_DEC_USE_COUNT;
-			return err;
-		}
-
-                err = sppp_open ( dev );
-                if ( err )
-		{
-			sppp_detach ( dev );
-			MOD_DEC_USE_COUNT;
-			return err;
-		}
-                break;
-
-        case FST_MONITOR:
-        case FST_RAW:
-                break;
-
-        default:
-                dbg ( DBG_OPEN,"open: Unknown proto %d\n", port->proto );
-                break;
-        }
+        err = hdlc_open ( dev_to_hdlc ( dev ));
+        if ( err )
+                return err;
 
-        fst_openport ( port );
+        MOD_INC_USE_COUNT;
 
+        fst_openport ( dev_to_port ( dev ));
         netif_wake_queue ( dev );
         return 0;
 }
@@ -1400,34 +1324,22 @@
 static int
 fst_close ( struct net_device *dev )
 {
-        struct fst_port_info *port;
-
-        port = dev->priv;
-
         netif_stop_queue ( dev );
-        switch ( port->proto )
-        {
-        case FST_HDLC:
-        case FST_PPP:
-                sppp_close ( dev );
-                sppp_detach ( dev );
-                break;
-
-        case FST_MONITOR:
-        case FST_RAW:
-                break;
-
-        default:
-                dbg ( DBG_OPEN,"close: Unknown proto %d\n", port->proto );
-                break;
-        }
-
-        fst_closeport ( port );
-
+        fst_closeport ( dev_to_port ( dev ));
+        hdlc_close ( dev_to_hdlc  ( dev ));
         MOD_DEC_USE_COUNT;
         return 0;
 }
 
+static int
+fst_attach ( hdlc_device *hdlc, unsigned short encoding, unsigned short parity )
+{
+        /* Setting currently fixed in FarSync card so we check and forget */
+        if ( encoding != ENCODING_NRZ || parity != PARITY_CRC16_PR1_CCITT )
+                return -EINVAL;
+        return 0;
+}
+
 
 static void
 fst_tx_timeout ( struct net_device *dev )
@@ -1436,10 +1348,10 @@
 
         dbg ( DBG_INTR | DBG_TX,"tx_timeout\n");
 
-        port = dev->priv;
+        port = dev_to_port ( dev );
 
-        port->stats.tx_errors++;
-        port->stats.tx_aborted_errors++;
+        port->hdlc.stats.tx_errors++;
+        port->hdlc.stats.tx_aborted_errors++;
 
         if ( port->txcnt > 0 )
                 fst_issue_cmd ( port, ABORTTX );
@@ -1459,22 +1371,15 @@
         int pi;
         int txp;
 
-        port = dev->priv;
+        port = dev_to_port ( dev );
         card = port->card;
 
-        /* Drop packet if in monitor (rx only) mode */
-        if ( port->proto == FST_MONITOR )
-        {
-                dev_kfree_skb ( skb );
-                return 0;
-        }
-
         /* Drop packet with error if we don't have carrier */
         if ( ! netif_carrier_ok ( dev ))
         {
                 dev_kfree_skb ( skb );
-                port->stats.tx_errors++;
-                port->stats.tx_carrier_errors++;
+                port->hdlc.stats.tx_errors++;
+                port->hdlc.stats.tx_carrier_errors++;
                 return 0;
         }
 
@@ -1484,7 +1389,7 @@
                 dbg ( DBG_TX,"Packet too large %d vs %d\n", skb->len,
                                                 LEN_TX_BUFFER );
                 dev_kfree_skb ( skb );
-                port->stats.tx_errors++;
+                port->hdlc.stats.tx_errors++;
                 return 0;
         }
 
@@ -1498,7 +1403,7 @@
                 spin_unlock_irqrestore ( &card->card_lock, flags );
                 dbg ( DBG_TX,"Out of Tx buffers\n");
                 dev_kfree_skb ( skb );
-                port->stats.tx_errors++;
+                port->hdlc.stats.tx_errors++;
                 return 0;
         }
         if ( ++port->txpos >= NUM_TX_BUFFER )
@@ -1518,8 +1423,8 @@
         FST_WRW ( card, txDescrRing[pi][txp].bcnt, cnv_bcnt ( skb->len ));
         FST_WRB ( card, txDescrRing[pi][txp].bits, DMA_OWN | TX_STP | TX_ENP );
 
-        port->stats.tx_packets++;
-        port->stats.tx_bytes += skb->len;
+        port->hdlc.stats.tx_packets++;
+        port->hdlc.stats.tx_bytes += skb->len;
 
         dev_kfree_skb ( skb );
 
@@ -1528,18 +1433,6 @@
 }
 
 
-static struct net_device_stats *
-fst_get_stats ( struct net_device *dev )
-{
-        struct fst_port_info *port;
-
-        if (( port = dev->priv ) != NULL )
-                return &port->stats;
-        else
-                return NULL;
-}
-
-
 /*
  *      Card setup having checked hardware resources.
  *      Should be pretty bizarre if we get an error here (kernel memory
@@ -1566,34 +1459,13 @@
          */
         for ( i = 0 ; i < card->nports ; i++ )
         {
-                card->ports[i].if_ptr = &card->ports[i].pppdev;
                 card->ports[i].card   = card;
                 card->ports[i].index  = i;
-                card->ports[i].proto  = FST_HDLC;
                 card->ports[i].run    = 0;
 
-                dev = kmalloc ( sizeof ( struct net_device ), GFP_KERNEL );
-                if ( dev == NULL )
-                {
-                        printk_err ("Cannot allocate net_device for port %d\n",
-                                        i );
-                        /* No point going any further */
-                        card->nports = i;
-                        break;
-                }
-                memset ( dev, 0, sizeof ( struct net_device ));
-                card->ports[i].dev = dev;
-
-                if ( dev_alloc_name ( dev, FST_NDEV_NAME "%d") < 0 )
-                {
-                        printk_err ("Cannot allocate i/f name for port %d\n",
-                                        i );
-                        kfree ( dev );
-                        card->nports = i;
-                        break;
-                }
+                dev = hdlc_to_dev ( &card->ports[i].hdlc );
 
-                /* Fill in remainder of the net device info */
+                /* Fill in the net device info */
                                 /* Since this is a PCI setup this is purely
                                  * informational. Give them the buffer addresses
                                  * and basic card I/O.
@@ -1609,26 +1481,19 @@
                 dev->base_addr   = card->pci_conf;
                 dev->irq         = card->irq;
 
-                dev->get_stats          = fst_get_stats;
-                dev->mtu                = FST_DEF_MTU;
-                dev->change_mtu         = fst_change_mtu;
-                dev->priv               = &card->ports[i];
-                dev->tx_queue_len       = FST_TX_QUEUE_LEN;
-                dev->type               = ARPHRD_MYTYPE;
-                dev->addr_len           = 0;
-                dev->open               = fst_open;
-                dev->stop               = fst_close;
-                dev->hard_start_xmit    = fst_start_xmit;
-                dev->do_ioctl           = fst_ioctl;
-                dev->watchdog_timeo     = FST_TX_TIMEOUT;
-                dev->tx_timeout         = fst_tx_timeout;
-                dev->flags              = IFF_POINTOPOINT|IFF_NOARP;
-
-                if (( err = register_netdev ( dev )) < 0 )
-                {
-                        printk_err ("Cannot register %s (errno %d)\n",
-                                        dev->name, -err );
-                        kfree ( dev );
+                dev->tx_queue_len          = FST_TX_QUEUE_LEN;
+                dev->open                  = fst_open;
+                dev->stop                  = fst_close;
+                dev->do_ioctl              = fst_ioctl;
+                dev->watchdog_timeo        = FST_TX_TIMEOUT;
+                dev->tx_timeout            = fst_tx_timeout;
+                card->ports[i].hdlc.attach = fst_attach;
+                card->ports[i].hdlc.xmit   = fst_start_xmit;
+
+                if (( err = register_hdlc_device ( &card->ports[i].hdlc )) < 0 )
+                {
+                        printk_err ("Cannot register HDLC device for port %d"
+                                    " (errno %d)\n", i, -err );
                         card->nports = i;
                         break;
                 }
@@ -1637,8 +1502,8 @@
         spin_lock_init ( &card->card_lock );
 
         printk ( KERN_INFO "%s-%s: %s IRQ%d, %d ports\n",
-                        card->ports[0].dev->name,
-                        card->ports[card->nports-1].dev->name,
+                        hdlc_to_dev(&card->ports[0].hdlc)->name,
+                        hdlc_to_dev(&card->ports[card->nports-1].hdlc)->name,
                         type_strings[card->type], card->irq, card->nports );
 }
 
@@ -1789,8 +1654,7 @@
 
         for ( i = 0 ; i < card->nports ; i++ )
         {
-                unregister_netdev ( card->ports[i].dev );
-                kfree ( card->ports[i].dev );
+                unregister_hdlc_device ( &card->ports[i].hdlc );
         }
 
         fst_disable_intr ( card );
@@ -1830,4 +1694,3 @@
 module_init ( fst_init );
 module_exit ( fst_cleanup_module );
 
-MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/wan/farsync.h linux-2.4.21-pre6/drivers/net/wan/farsync.h
--- linux-2.4.20/drivers/net/wan/farsync.h	2001-08-12 17:38:48.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/wan/farsync.h	2003-03-26 23:49:40.000000000 +0000
@@ -32,13 +32,8 @@
  *      A short common prefix is useful for routines within the driver to avoid
  *      conflict with other similar drivers and I chosen to use "fst_" for this
  *      purpose (FarSite T-series).
- *
- *      Finally the device driver needs a short network interface name. Since
- *      "hdlc" is already in use I've chosen the even less informative "sync"
- *      for the present.
  */
 #define FST_NAME                "fst"           /* In debug/info etc */
-#define FST_NDEV_NAME           "sync"          /* For net interface */
 #define FST_DEV_NAME            "farsync"       /* For misc interfaces */
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/wan/hd64570.h linux-2.4.21-pre6/drivers/net/wan/hd64570.h
--- linux-2.4.20/drivers/net/wan/hd64570.h	2001-03-07 03:44:36.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/wan/hd64570.h	2003-03-26 23:49:24.000000000 +0000
@@ -152,7 +152,7 @@
 	u32 bp;			/* Buffer Pointer (24 bits) */
 	u16 len;		/* Data Length */
 	u8 stat;		/* Status */
-	u8 unused2;
+	u8 unused;		/* pads to 2-byte boundary */
 }__attribute__ ((packed)) pkt_desc;
 
 
@@ -202,7 +202,11 @@
 #define MD0_CRC_ITU_0 0x06
 #define MD0_CRC_ITU   0x07
 
-#define MD2_NRZI      0x20	/* NRZI mode */
+#define MD2_NRZ	      0x00
+#define MD2_NRZI      0x20
+#define MD2_MANCHESTER 0x80
+#define MD2_FM_MARK   0xA0
+#define MD2_FM_SPACE  0xC0
 #define MD2_LOOPBACK  0x03      /* Local data Loopback */
 
 #define CTL_NORTS     0x01
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/wan/hd6457x.c linux-2.4.21-pre6/drivers/net/wan/hd6457x.c
--- linux-2.4.20/drivers/net/wan/hd6457x.c	2001-03-07 03:44:36.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/wan/hd6457x.c	2003-03-26 23:49:15.000000000 +0000
@@ -42,13 +42,7 @@
 #error Either hd64570.h or hd64572.h must be included
 #endif
 
-
-static card_t *first_card;
-static card_t **new_card = &first_card;
-
-
-/* Maximum events to handle at each interrupt - should I increase it? */
-#define INTR_WORK 4
+static char sca_version[]="1.09";
 
 #define get_msci(port)	  (phy_node(port) ?   MSCI1_OFFSET :   MSCI0_OFFSET)
 #define get_dmac_rx(port) (phy_node(port) ? DMAC1RX_OFFSET : DMAC0RX_OFFSET)
@@ -63,11 +57,19 @@
 #define sca_ina(reg, card)		sca_inw(reg, card)
 #define writea(value, ptr)		writew(value, ptr)
 
+#else /* HD64572 */
+#define sca_outa(value, reg, card)	sca_outl(value, reg, card)
+#define sca_ina(reg, card)		sca_inl(reg, card)
+#define writea(value, ptr)		writel(value, ptr)
+#endif
+
 static inline int sca_intr_status(card_t *card)
 {
+	u8 result = 0;
+
+#ifdef __HD64570_H /* HD64570 */
 	u8 isr0 = sca_in(ISR0, card);
 	u8 isr1 = sca_in(ISR1, card);
-	u8 result = 0;
 
 	if (isr1 & 0x03) result |= SCA_INTR_DMAC_RX(0);
 	if (isr1 & 0x0C) result |= SCA_INTR_DMAC_TX(0);
@@ -76,19 +78,8 @@
 	if (isr0 & 0x0F) result |= SCA_INTR_MSCI(0);
 	if (isr0 & 0xF0) result |= SCA_INTR_MSCI(1);
 
-	return result;
-}
-
 #else /* HD64572 */
-#define sca_outa(value, reg, card)	sca_outl(value, reg, card)
-#define sca_ina(reg, card)		sca_inl(reg, card)
-#define writea(value, ptr)		writel(value, ptr)
-
-
-static inline int sca_intr_status(card_t *card)
-{
 	u32 isr0 = sca_inl(ISR0, card);
-	u8 result = 0;
 
 	if (isr0 & 0x0000000F) result |= SCA_INTR_DMAC_RX(0);
 	if (isr0 & 0x000000F0) result |= SCA_INTR_DMAC_TX(0);
@@ -97,11 +88,17 @@
 	if (isr0 & 0x003E0000) result |= SCA_INTR_MSCI(0);
 	if (isr0 & 0x3E000000) result |= SCA_INTR_MSCI(1);
 
-	return result;
-}
-
 #endif /* HD64570 vs HD64572 */
 
+	if (!(result & SCA_INTR_DMAC_TX(0)))
+		if (sca_in(DSR_TX(0), card) & DSR_EOM)
+			result |= SCA_INTR_DMAC_TX(0);
+	if (!(result & SCA_INTR_DMAC_TX(1)))
+		if (sca_in(DSR_TX(1), card) & DSR_EOM)
+			result |= SCA_INTR_DMAC_TX(1);
+
+	return result;
+}
 
 
 
@@ -250,8 +247,7 @@
 
 
 
-static inline void sca_rx(card_t *card, port_t *port, pkt_desc *desc,
-			      u8 rxin)
+static inline void sca_rx(card_t *card, port_t *port, pkt_desc *desc, u8 rxin)
 {
 	struct sk_buff *skb;
 	u16 len;
@@ -289,13 +285,17 @@
 	openwin(card, 0);
 #endif
 	skb_put(skb, len);
-#ifdef DEBUG_PKT
+#ifdef CONFIG_HDLC_DEBUG_PKT
 	printk(KERN_DEBUG "%s RX(%i):", hdlc_to_name(&port->hdlc), skb->len);
 	debug_frame(skb);
 #endif
 	port->hdlc.stats.rx_packets++;
 	port->hdlc.stats.rx_bytes += skb->len;
-	hdlc_netif_rx(&port->hdlc, skb);
+	skb->mac.raw = skb->data;
+	skb->dev = hdlc_to_dev(&port->hdlc);
+	skb->dev->last_rx = jiffies;
+	skb->protocol = htons(ETH_P_HDLC);
+	netif_rx(skb);
 }
 
 
@@ -320,14 +320,9 @@
 		pkt_desc *desc;
 		u32 cda = sca_ina(dmac + CDAL, card);
 
-		if (cda == desc_off)
+		if ((cda >= desc_off) && (cda < desc_off + sizeof(pkt_desc)))
 			break;	/* No frame received */
 
-#ifdef __HD64572_H
-		if (cda == desc_off + 8)
-			break;	/* SCA-II updates CDA in 2 steps */
-#endif
-
 		desc = desc_address(port, port->rxin, 0);
 		stat = readb(&desc->stat);
 		if (!(stat & ST_RX_EOM))
@@ -371,20 +366,17 @@
 		DSR_TX(phy_node(port)), card);
 
 	while (1) {
-		u32 desc_off = desc_offset(port, port->txlast, 1);
 		pkt_desc *desc;
-		u16 len;
 
-		if (sca_ina(dmac + CDAL, card) == desc_off)
+		u32 desc_off = desc_offset(port, port->txlast, 1);
+		u32 cda = sca_ina(dmac + CDAL, card);
+		if ((cda >= desc_off) && (cda < desc_off + sizeof(pkt_desc)))
 			break;	/* Transmitter is/will_be sending this frame */
 
 		desc = desc_address(port, port->txlast, 1);
-		len = readw(&desc->len);
-
 		port->hdlc.stats.tx_packets++;
-		port->hdlc.stats.tx_bytes += len;
+		port->hdlc.stats.tx_bytes += readw(&desc->len);
 		writeb(0, &desc->stat);	/* Free descriptor */
-
 		port->txlast = (port->txlast + 1) %
 			port_to_card(port)->ring_buffers;
 	}
@@ -398,7 +390,8 @@
 static void sca_intr(int irq, void* dev_id, struct pt_regs *regs)
 {
 	card_t *card = dev_id;
-	int boguscnt = INTR_WORK;
+/* Maximum events to handle at each interrupt - should I increase it? */
+	int boguscnt = 4;
 	int i;
 	u8 stat;
 
@@ -421,9 +414,11 @@
 			}
 
 			if (--boguscnt < 0) {
+#if 0
 				printk(KERN_ERR "%s: too much work at "
 				       "interrupt\n",
 				       hdlc_to_name(&port->hdlc));
+#endif
 				goto exit;
 			}
 		}
@@ -433,51 +428,27 @@
 #ifndef ALL_PAGES_ALWAYS_MAPPED
 	openwin(card, page);		/* Restore original page */
 #endif
+	return;
 }
 
 
 
-static inline int sca_set_loopback(port_t *port, int line)
+static void sca_set_port(port_t *port)
 {
 	card_t* card = port_to_card(port);
 	u8 msci = get_msci(port);
 	u8 md2 = sca_in(msci + MD2, card);
-
-	switch(line) {
-	case LINE_DEFAULT:
-		md2 &= ~MD2_LOOPBACK;
-		port->line &= ~LINE_LOOPBACK;
-		break;
-
-	case LINE_LOOPBACK:
-		md2 |= MD2_LOOPBACK;
-		port->line |= LINE_LOOPBACK;
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	sca_out(md2, msci + MD2, card);
-	return 0;
-}
-
-
-
-static void sca_set_clock(port_t *port)
-{
-	card_t *card = port_to_card(port);
-	u8 msci = get_msci(port);
 	unsigned int tmc, br = 10, brv = 1024;
 
-	if (port->clkrate > 0) {
+
+	if (port->settings.clock_rate > 0) {
 		/* Try lower br for better accuracy*/
 		do {
 			br--;
 			brv >>= 1; /* brv = 2^9 = 512 max in specs */
 
 			/* Baud Rate = CLOCK_BASE / TMC / 2^BR */
-			tmc = CLOCK_BASE / (brv * port->clkrate);
+			tmc = CLOCK_BASE / (brv * port->settings.clock_rate);
 		}while(br > 1 && tmc <= 128);
 
 		if (tmc < 1) {
@@ -487,11 +458,11 @@
 		} else if (tmc > 255)
 			tmc = 256; /* tmc=0 means 256 - low baud rates */
 
-		port->clkrate = CLOCK_BASE / (brv * tmc);
+		port->settings.clock_rate = CLOCK_BASE / (brv * tmc);
 	} else {
 		br = 9; /* Minimum clock rate */
 		tmc = 256;	/* 8bit = 0 */
-		port->clkrate = CLOCK_BASE / (256 * 512);
+		port->settings.clock_rate = CLOCK_BASE / (256 * 512);
 	}
 
 	port->rxs = (port->rxs & ~CLK_BRG_MASK) | br;
@@ -509,27 +480,59 @@
 	/* Set BRG bits */
 	sca_out(port->rxs, msci + RXS, card);
 	sca_out(port->txs, msci + TXS, card);
+
+	if (port->settings.loopback)
+		md2 |= MD2_LOOPBACK;
+	else
+		md2 &= ~MD2_LOOPBACK;
+
+	sca_out(md2, msci + MD2, card);
+
 }
 
 
 
-static void sca_set_hdlc_mode(port_t *port, u8 idle, u8 crc, u8 nrzi)
+static void sca_open(hdlc_device *hdlc)
 {
+	port_t *port = hdlc_to_port(hdlc);
 	card_t* card = port_to_card(port);
 	u8 msci = get_msci(port);
-	u8 md2 = (nrzi ? MD2_NRZI : 0) |
-		((port->line & LINE_LOOPBACK) ? MD2_LOOPBACK : 0);
-	u8 ctl = (idle ? CTL_IDLE : 0);
-#ifdef __HD64572_H
-	ctl |= CTL_URCT | CTL_URSKP; /* Skip the rest of underrun frame */
-#endif
+	u8 md0, md2;
+
+	switch(port->encoding) {
+	case ENCODING_NRZ:	md2 = MD2_NRZ;		break;
+	case ENCODING_NRZI:	md2 = MD2_NRZI;		break;
+	case ENCODING_FM_MARK:	md2 = MD2_FM_MARK;	break;
+	case ENCODING_FM_SPACE:	md2 = MD2_FM_SPACE;	break;
+	default:		md2 = MD2_MANCHESTER;
+	}
+
+	if (port->settings.loopback)
+		md2 |= MD2_LOOPBACK;
+
+	switch(port->parity) {
+	case PARITY_CRC16_PR0:	     md0 = MD0_HDLC | MD0_CRC_16_0;  break;
+	case PARITY_CRC16_PR1:	     md0 = MD0_HDLC | MD0_CRC_16;    break;
+#ifdef __HD64570_H
+	case PARITY_CRC16_PR0_CCITT: md0 = MD0_HDLC | MD0_CRC_ITU_0; break;
+#else
+	case PARITY_CRC32_PR1_CCITT: md0 = MD0_HDLC | MD0_CRC_ITU32; break;
+#endif	
+	case PARITY_CRC16_PR1_CCITT: md0 = MD0_HDLC | MD0_CRC_ITU;   break;
+	default:		     md0 = MD0_HDLC | MD0_CRC_NONE;
+	}
 
 	sca_out(CMD_RESET, msci + CMD, card);
-	sca_out(MD0_HDLC | crc, msci + MD0, card);
+	sca_out(md0, msci + MD0, card);
 	sca_out(0x00, msci + MD1, card); /* no address field check */
 	sca_out(md2, msci + MD2, card);
 	sca_out(0x7E, msci + IDL, card); /* flag character 0x7E */
-	sca_out(ctl, msci + CTL, card);
+#ifdef __HD64570_H
+	sca_out(CTL_IDLE, msci + CTL, card);
+#else
+	/* Skip the rest of underrun frame */
+	sca_out(CTL_IDLE | CTL_URCT | CTL_URSKP, msci + CTL, card);
+#endif
 
 #ifdef __HD64570_H
 	/* Allow at least 8 bytes before requesting RX DMA operation */
@@ -539,24 +542,28 @@
 	sca_out(0x14, msci + TRC1, card); /* +1=TXRDY/DMA deactiv condition */
 #else
 	sca_out(0x0F, msci + RNR, card); /* +1=RX DMA activation condition */
-	/* Setting than to larger value may cause Illegal Access */
-	sca_out(0x20, msci + TNR0, card); /* =TX DMA activation condition */
-	sca_out(0x30, msci + TNR1, card); /* +1=TX DMA deactivation condition*/
-	sca_out(0x04, msci + TCR, card); /* =Critical TX DMA activ condition */
+	sca_out(0x3C, msci + TFS, card); /* +1 = TX start */
+	sca_out(0x38, msci + TCR, card); /* =Critical TX DMA activ condition */
+	sca_out(0x38, msci + TNR0, card); /* =TX DMA activation condition */
+	sca_out(0x3F, msci + TNR1, card); /* +1=TX DMA deactivation condition*/
 #endif
 
+/* We're using the following interrupts:
+   - TXINT (DMAC completed all transmisions, underflow or CTS change)
+   - all DMA interrupts
+*/
 
 #ifdef __HD64570_H
 	/* MSCI TX INT IRQ enable */
 	sca_out(IE0_TXINT, msci + IE0, card);
-	sca_out(IE1_UDRN, msci + IE1, card); /* TX underrun IRQ */
+	sca_out(IE1_UDRN, msci + IE1, card); /* TX underrun -> TXINT */
 	sca_out(sca_in(IER0, card) | (phy_node(port) ? 0x80 : 0x08),
 		IER0, card);
 	/* DMA IRQ enable */
 	sca_out(sca_in(IER1, card) | (phy_node(port) ? 0xF0 : 0x0F),
 		IER1, card);
 #else
-	/* MSCI TX INT and underrrun IRQ enable */
+	/* MSCI TX INT IRQ enable */
 	sca_outl(IE0_TXINT | IE0_UDRN, msci + IE0, card);
 	/* DMA & MSCI IRQ enable */
 	sca_outl(sca_in(IER0, card) |
@@ -573,11 +580,52 @@
 	sca_out(port->txs, msci + TXS, card);
 	sca_out(CMD_TX_ENABLE, msci + CMD, card);
 	sca_out(CMD_RX_ENABLE, msci + CMD, card);
+
+	netif_start_queue(hdlc_to_dev(hdlc));
+}
+
+
+
+static void sca_close(hdlc_device *hdlc)
+{
+	port_t *port = hdlc_to_port(hdlc);
+
+	/* reset channel */
+	netif_stop_queue(hdlc_to_dev(hdlc));
+	sca_out(CMD_RESET, get_msci(port) + CMD, port_to_card(port));
 }
 
 
 
-#ifdef DEBUG_RINGS
+static int sca_attach(hdlc_device *hdlc, unsigned short encoding,
+		      unsigned short parity)
+{
+	if (encoding != ENCODING_NRZ &&
+	    encoding != ENCODING_NRZI &&
+	    encoding != ENCODING_FM_MARK &&
+	    encoding != ENCODING_FM_SPACE &&
+	    encoding != ENCODING_MANCHESTER)
+		return -EINVAL;
+
+	if (parity != PARITY_NONE &&
+	    parity != PARITY_CRC16_PR0 &&
+	    parity != PARITY_CRC16_PR1 &&
+#ifdef __HD64570_H
+	    parity != PARITY_CRC16_PR0_CCITT &&
+#else
+	    parity != PARITY_CRC32_PR1_CCITT &&
+#endif	
+	    parity != PARITY_CRC16_PR1_CCITT)
+		return -EINVAL;
+
+	hdlc_to_port(hdlc)->encoding = encoding;
+	hdlc_to_port(hdlc)->parity = parity;
+	return 0;
+}
+
+
+
+#ifdef CONFIG_HDLC_DEBUG_RINGS
 static void sca_dump_rings(hdlc_device *hdlc)
 {
 	port_t *port = hdlc_to_port(hdlc);
@@ -644,34 +692,14 @@
 	openwin(card, page); /* Restore original page */
 #endif
 }
-#endif /* DEBUG_RINGS */
-
-
-
-static void sca_open(hdlc_device *hdlc)
-{
-	port_t *port = hdlc_to_port(hdlc);
-
-	sca_set_hdlc_mode(port, 1, MD0_CRC_ITU, 0);
-	netif_start_queue(hdlc_to_dev(hdlc));
-}
-
-
-static void sca_close(hdlc_device *hdlc)
-{
-	port_t *port = hdlc_to_port(hdlc);
-
-	/* reset channel */
-	netif_stop_queue(hdlc_to_dev(hdlc));
-	sca_out(CMD_RESET, get_msci(port) + CMD, port_to_card(port));
-}
+#endif /* CONFIG_HDLC_DEBUG_RINGS */
 
 
 
-static int sca_xmit(hdlc_device *hdlc, struct sk_buff *skb)
+static int sca_xmit(struct sk_buff *skb, struct net_device *dev)
 {
+	hdlc_device *hdlc = dev_to_hdlc(dev);
 	port_t *port = hdlc_to_port(hdlc);
-	struct net_device *dev = hdlc_to_dev(hdlc);
 	card_t *card = port_to_card(port);
 	pkt_desc *desc;
 	u32 buff, len;
@@ -685,7 +713,7 @@
 	desc = desc_address(port, port->txin + 1, 1);
 	if (readb(&desc->stat)) { /* allow 1 packet gap */
 		/* should never happen - previous xmit should stop queue */
-#ifdef DEBUG_PKT
+#ifdef CONFIG_HDLC_DEBUG_PKT
 		printk(KERN_DEBUG "%s: transmitter buffer full\n", dev->name);
 #endif
 		netif_stop_queue(dev);
@@ -693,7 +721,7 @@
 		return 1;	/* request packet to be queued */
 	}
 
-#ifdef DEBUG_PKT
+#ifdef CONFIG_HDLC_DEBUG_PKT
 	printk(KERN_DEBUG "%s TX(%i):", hdlc_to_name(hdlc), skb->len);
 	debug_frame(skb);
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/wan/hdlc.c linux-2.4.21-pre6/drivers/net/wan/hdlc.c
--- linux-2.4.20/drivers/net/wan/hdlc.c	2001-09-13 23:04:43.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/wan/hdlc.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,1453 +0,0 @@
-/*
- * Generic HDLC support routines for Linux
- *
- * Copyright (C) 1999, 2000 Krzysztof Halasa <khc@pm.waw.pl>
- *
- * 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.
- *
- * Current status:
- *    - this is work in progress
- *    - not heavily tested on SMP
- *    - currently supported:
- *	* raw IP-in-HDLC
- *	* Cisco HDLC
- *	* Frame Relay with ANSI or CCITT LMI (both user and network side)
- *	* PPP (using syncppp.c)
- *	* X.25
- *
- * Use sethdlc utility to set line parameters, protocol and PVCs
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/if_arp.h>
-#include <linux/init.h>
-#include <linux/skbuff.h>
-#include <linux/pkt_sched.h>
-#include <linux/inetdevice.h>
-#include <linux/lapb.h>
-#include <linux/rtnetlink.h>
-#include <linux/hdlc.h>
-
-/* #define DEBUG_PKT */
-/* #define DEBUG_HARD_HEADER */
-/* #define DEBUG_FECN */
-/* #define DEBUG_BECN */
-
-static const char* version = "HDLC support module revision 1.02 for Linux 2.4";
-
-
-#define CISCO_MULTICAST		0x8F	/* Cisco multicast address */
-#define CISCO_UNICAST		0x0F	/* Cisco unicast address */
-#define CISCO_KEEPALIVE		0x8035	/* Cisco keepalive protocol */
-#define CISCO_SYS_INFO		0x2000	/* Cisco interface/system info */
-#define CISCO_ADDR_REQ		0	/* Cisco address request */
-#define CISCO_ADDR_REPLY	1	/* Cisco address reply */
-#define CISCO_KEEPALIVE_REQ	2	/* Cisco keepalive request */
-
-static int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
-
-/********************************************************
- *
- * Cisco HDLC support
- *
- *******************************************************/
-
-static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev,
-			     u16 type, void *daddr, void *saddr,
-			     unsigned int len)
-{
-	hdlc_header *data;
-#ifdef DEBUG_HARD_HEADER
-	printk(KERN_DEBUG "%s: cisco_hard_header called\n", dev->name);
-#endif
-
-	skb_push(skb, sizeof(hdlc_header));
-	data = (hdlc_header*)skb->data;
-	if (type == CISCO_KEEPALIVE)
-		data->address = CISCO_MULTICAST;
-	else
-		data->address = CISCO_UNICAST;
-	data->control = 0;
-	data->protocol = htons(type);
-
-	return sizeof(hdlc_header);
-}
-
-
-
-static void cisco_keepalive_send(hdlc_device *hdlc, u32 type,
-				 u32 par1, u32 par2)
-{
-	struct sk_buff *skb;
-	cisco_packet *data;
-
-	skb = dev_alloc_skb(sizeof(hdlc_header)+sizeof(cisco_packet));
-	if (!skb) {
-		printk(KERN_WARNING "%s: Memory squeeze on cisco_keepalive_send()\n",
-			       hdlc_to_name(hdlc));
-		return;
-	}
-	skb_reserve(skb, 4);
-	cisco_hard_header(skb, hdlc_to_dev(hdlc), CISCO_KEEPALIVE,
-			  NULL, NULL, 0);
-	data = (cisco_packet*)skb->tail;
-
-	data->type = htonl(type);
-	data->par1 = htonl(par1);
-	data->par2 = htonl(par2);
-	data->rel = 0xFFFF;
-	data->time = htonl(jiffies * 1000 / HZ);
-
-	skb_put(skb, sizeof(cisco_packet));
-	skb->priority = TC_PRIO_CONTROL;
-	skb->dev = hdlc_to_dev(hdlc);
-
-	dev_queue_xmit(skb);
-}
-
-
-
-static void cisco_netif(hdlc_device *hdlc, struct sk_buff *skb)
-{
-	hdlc_header *data = (hdlc_header*)skb->data;
-	cisco_packet *cisco_data;
-	struct in_device *in_dev;
-	u32 addr, mask;
-
-	if (skb->len<sizeof(hdlc_header))
-		goto rx_error;
-
-	if (data->address != CISCO_MULTICAST &&
-	    data->address != CISCO_UNICAST)
-		goto rx_error;
-
-	skb_pull(skb, sizeof(hdlc_header));
-
-	switch(ntohs(data->protocol)) {
-	case ETH_P_IP:
-	case ETH_P_IPX:
-	case ETH_P_IPV6:
-		skb->protocol = data->protocol;
-		skb->dev = hdlc_to_dev(hdlc);
-		netif_rx(skb);
-		return;
-
-	case CISCO_SYS_INFO:
-		/* Packet is not needed, drop it. */
-		dev_kfree_skb_any(skb);
-		return;
-
-	case CISCO_KEEPALIVE:
-		if (skb->len != CISCO_PACKET_LEN &&
-		    skb->len != CISCO_BIG_PACKET_LEN) {
-			printk(KERN_INFO "%s: Invalid length of Cisco "
-			       "control packet (%d bytes)\n",
-			       hdlc_to_name(hdlc), skb->len);
-			goto rx_error;
-		}
-
-		cisco_data = (cisco_packet*)skb->data;
-
-		switch(ntohl (cisco_data->type)) {
-		case CISCO_ADDR_REQ: /* Stolen from syncppp.c :-) */
-			in_dev = hdlc_to_dev(hdlc)->ip_ptr;
-			addr = 0;
-			mask = ~0; /* is the mask correct? */
-
-			if (in_dev != NULL) {
-				struct in_ifaddr **ifap = &in_dev->ifa_list;
-
-				while (*ifap != NULL) {
-					if (strcmp(hdlc_to_name(hdlc),
-						   (*ifap)->ifa_label) == 0) {
-						addr = (*ifap)->ifa_local;
-						mask = (*ifap)->ifa_mask;
-						break;
-					}
-					ifap = &(*ifap)->ifa_next;
-				}
-
-				cisco_keepalive_send(hdlc, CISCO_ADDR_REPLY,
-						     addr, mask);
-			}
-			dev_kfree_skb_any(skb);
-			return;
-
-		case CISCO_ADDR_REPLY:
-			printk(KERN_INFO "%s: Unexpected Cisco IP address "
-			       "reply\n", hdlc_to_name(hdlc));
-			goto rx_error;
-
-		case CISCO_KEEPALIVE_REQ:
-			hdlc->lmi.rxseq = ntohl(cisco_data->par1);
-			if (ntohl(cisco_data->par2) == hdlc->lmi.txseq) {
-				hdlc->lmi.last_poll = jiffies;
-				if (!(hdlc->lmi.state & LINK_STATE_RELIABLE)) {
-					u32 sec, min, hrs, days;
-					sec = ntohl(cisco_data->time) / 1000;
-					min = sec / 60; sec -= min * 60;
-					hrs = min / 60; min -= hrs * 60;
-					days = hrs / 24; hrs -= days * 24;
-					printk(KERN_INFO "%s: Link up (peer "
-					       "uptime %ud%uh%um%us)\n",
-					       hdlc_to_name(hdlc), days, hrs,
-					       min, sec);
-				}
-				hdlc->lmi.state |= LINK_STATE_RELIABLE;
-			}
-
-			dev_kfree_skb_any(skb);
-			return;
-		} /* switch(keepalive type) */
-	} /* switch(protocol) */
-
-	printk(KERN_INFO "%s: Unsupported protocol %x\n", hdlc_to_name(hdlc),
-	       data->protocol);
-	dev_kfree_skb_any(skb);
-	return;
-
- rx_error:
-	hdlc->stats.rx_errors++; /* Mark error */
-	dev_kfree_skb_any(skb);
-}
-
-
-
-static void cisco_timer(unsigned long arg)
-{
-	hdlc_device *hdlc = (hdlc_device*)arg;
-
-	if ((hdlc->lmi.state & LINK_STATE_RELIABLE) &&
-	    (jiffies - hdlc->lmi.last_poll >= hdlc->lmi.T392 * HZ)) {
-		hdlc->lmi.state &= ~LINK_STATE_RELIABLE;
-		printk(KERN_INFO "%s: Link down\n", hdlc_to_name(hdlc));
-	}
-
-	cisco_keepalive_send(hdlc, CISCO_KEEPALIVE_REQ, ++hdlc->lmi.txseq,
-			     hdlc->lmi.rxseq);
-	hdlc->timer.expires = jiffies + hdlc->lmi.T391*HZ;
-
-	hdlc->timer.function = cisco_timer;
-	hdlc->timer.data = arg;
-	add_timer(&hdlc->timer);
-}
-
-
-
-/******************************************************************
- *
- *     generic Frame Relay routines
- *
- *****************************************************************/
-
-
-static int fr_hard_header(struct sk_buff *skb, struct net_device *dev,
-			  u16 type, void *daddr, void *saddr, unsigned int len)
-{
-	u16 head_len;
-
-	if (!daddr)
-		daddr = dev->broadcast;
-
-#ifdef DEBUG_HARD_HEADER
-	printk(KERN_DEBUG "%s: fr_hard_header called\n", dev->name);
-#endif
-
-	switch(type) {
-	case ETH_P_IP:
-		head_len = 4;
-		skb_push(skb, head_len);
-		skb->data[3] = NLPID_IP;
-		break;
-
-	case ETH_P_IPV6:
-		head_len = 4;
-		skb_push(skb, head_len);
-		skb->data[3] = NLPID_IPV6;
-		break;
-
-	case LMI_PROTO:
-		head_len = 4;
-		skb_push(skb, head_len);
-		skb->data[3] = LMI_PROTO;
-		break;
-
-	default:
-		head_len = 10;
-		skb_push(skb, head_len);
-		skb->data[3] = FR_PAD;
-		skb->data[4] = NLPID_SNAP;
-		skb->data[5] = FR_PAD;
-		skb->data[6] = FR_PAD;
-		skb->data[7] = FR_PAD;
-		skb->data[8] = type>>8;
-		skb->data[9] = (u8)type;
-	}
-
-	memcpy(skb->data, daddr, 2);
-	skb->data[2] = FR_UI;
-
-	return head_len;
-}
-
-
-
-static inline void fr_log_dlci_active(pvc_device *pvc)
-{
-	printk(KERN_INFO "%s: %sactive%s\n", pvc_to_name(pvc),
-	       pvc->state & PVC_STATE_ACTIVE ? "" : "in",
-	       pvc->state & PVC_STATE_NEW ? " new" : "");
-}
-
-
-
-static inline u8 fr_lmi_nextseq(u8 x)
-{
-	x++;
-	return x ? x : 1;
-}
-
-
-
-static void fr_lmi_send(hdlc_device *hdlc, int fullrep)
-{
-	struct sk_buff *skb;
-	pvc_device *pvc = hdlc->first_pvc;
-	int len = mode_is(hdlc, MODE_FR_ANSI) ? LMI_ANSI_LENGTH : LMI_LENGTH;
-	int stat_len = 3;
-	u8 *data;
-	int i = 0;
-
-	if (mode_is(hdlc, MODE_DCE) && fullrep) {
-		len += hdlc->pvc_count * (2 + stat_len);
-		if (len > HDLC_MAX_MTU) {
-			printk(KERN_WARNING "%s: Too many PVCs while sending "
-			       "LMI full report\n", hdlc_to_name(hdlc));
-			return;
-		}
-	}
-
-	skb = dev_alloc_skb(len);
-	if (!skb) {
-		printk(KERN_WARNING "%s: Memory squeeze on fr_lmi_send()\n",
-			       hdlc_to_name(hdlc));
-		return;
-	}
-	memset(skb->data, 0, len);
-	skb_reserve(skb, 4);
-	fr_hard_header(skb, hdlc_to_dev(hdlc), LMI_PROTO, NULL, NULL, 0);
-	data = skb->tail;
-	data[i++] = LMI_CALLREF;
-	data[i++] = mode_is(hdlc, MODE_DCE) ? LMI_STATUS : LMI_STATUS_ENQUIRY;
-	if (mode_is(hdlc, MODE_FR_ANSI))
-		data[i++] = LMI_ANSI_LOCKSHIFT;
-	data[i++] = mode_is(hdlc, MODE_FR_CCITT) ? LMI_CCITT_REPTYPE :
-		LMI_REPTYPE;
-	data[i++] = LMI_REPT_LEN;
-	data[i++] = fullrep ? LMI_FULLREP : LMI_INTEGRITY;
-
-	data[i++] = mode_is(hdlc, MODE_FR_CCITT) ? LMI_CCITT_ALIVE : LMI_ALIVE;
-	data[i++] = LMI_INTEG_LEN;
-	data[i++] = hdlc->lmi.txseq = fr_lmi_nextseq(hdlc->lmi.txseq);
-	data[i++] = hdlc->lmi.rxseq;
-
-	if (mode_is(hdlc, MODE_DCE) && fullrep) {
-		while (pvc) {
-			data[i++] = mode_is(hdlc, MODE_FR_CCITT) ?
-				LMI_CCITT_PVCSTAT:LMI_PVCSTAT;
-			data[i++] = stat_len;
-
-			if ((hdlc->lmi.state & LINK_STATE_RELIABLE) &&
-			    (pvc->netdev.flags & IFF_UP) &&
-			    !(pvc->state & (PVC_STATE_ACTIVE|PVC_STATE_NEW))) {
-				pvc->state |= PVC_STATE_NEW;
-				fr_log_dlci_active(pvc);
-			}
-
-			dlci_to_status(hdlc, netdev_dlci(&pvc->netdev),
-				       data+i, pvc->state);
-			i += stat_len;
-			pvc = pvc->next;
-		}
-	}
-
-	skb_put(skb, i);
-	skb->priority = TC_PRIO_CONTROL;
-	skb->dev = hdlc_to_dev(hdlc);
-
-	dev_queue_xmit(skb);
-}
-
-
-
-static void fr_timer(unsigned long arg)
-{
-	hdlc_device *hdlc = (hdlc_device*)arg;
-	int i, cnt = 0, reliable;
-	u32 list;
-
-	if (mode_is(hdlc, MODE_DCE))
-		reliable = (jiffies - hdlc->lmi.last_poll < hdlc->lmi.T392*HZ);
-	else {
-		hdlc->lmi.last_errors <<= 1; /* Shift the list */
-		if (hdlc->lmi.state & LINK_STATE_REQUEST) {
-			printk(KERN_INFO "%s: No LMI status reply received\n",
-			       hdlc_to_name(hdlc));
-			hdlc->lmi.last_errors |= 1;
-		}
-
-		for (i = 0, list = hdlc->lmi.last_errors; i < hdlc->lmi.N393;
-		     i++, list >>= 1)
-			cnt += (list & 1);	/* errors count */
-
-		reliable = (cnt < hdlc->lmi.N392);
-	}
-
-	if ((hdlc->lmi.state & LINK_STATE_RELIABLE) !=
-	    (reliable ? LINK_STATE_RELIABLE : 0)) {
-		pvc_device *pvc = hdlc->first_pvc;
-
-		while (pvc) {/* Deactivate all PVCs */
-			pvc->state &= ~(PVC_STATE_NEW | PVC_STATE_ACTIVE);
-			pvc = pvc->next;
-		}
-
-		hdlc->lmi.state ^= LINK_STATE_RELIABLE;
-		printk(KERN_INFO "%s: Link %sreliable\n", hdlc_to_name(hdlc),
-		       reliable ? "" : "un");
-
-		if (reliable) {
-			hdlc->lmi.N391cnt = 0; /* Request full status */
-			hdlc->lmi.state |= LINK_STATE_CHANGED;
-		}
-	}
-
-	if (mode_is(hdlc, MODE_DCE))
-		hdlc->timer.expires = jiffies + hdlc->lmi.T392*HZ;
-	else {
-		if (hdlc->lmi.N391cnt)
-			hdlc->lmi.N391cnt--;
-
-		fr_lmi_send(hdlc, hdlc->lmi.N391cnt == 0);
-
-		hdlc->lmi.state |= LINK_STATE_REQUEST;
-		hdlc->timer.expires = jiffies + hdlc->lmi.T391*HZ;
-	}
-
-	hdlc->timer.function = fr_timer;
-	hdlc->timer.data = arg;
-	add_timer(&hdlc->timer);
-}
-
-
-
-static int fr_lmi_recv(hdlc_device *hdlc, struct sk_buff *skb)
-{
-	int stat_len;
-	pvc_device *pvc;
-	int reptype = -1, error;
-	u8 rxseq, txseq;
-	int i;
-
-	if (skb->len < (mode_is(hdlc, MODE_FR_ANSI) ?
-			LMI_ANSI_LENGTH : LMI_LENGTH)) {
-		printk(KERN_INFO "%s: Short LMI frame\n", hdlc_to_name(hdlc));
-		return 1;
-	}
-
-	if (skb->data[5] != (!mode_is(hdlc, MODE_DCE) ?
-			     LMI_STATUS : LMI_STATUS_ENQUIRY)) {
-		printk(KERN_INFO "%s: LMI msgtype=%x, Not LMI status %s\n",
-		       hdlc_to_name(hdlc), skb->data[2],
-		       mode_is(hdlc, MODE_DCE) ? "enquiry" : "reply");
-		return 1;
-	}
-
-	i = mode_is(hdlc, MODE_FR_ANSI) ? 7 : 6;
-
-	if (skb->data[i] !=
-	    (mode_is(hdlc, MODE_FR_CCITT) ? LMI_CCITT_REPTYPE : LMI_REPTYPE)) {
-		printk(KERN_INFO "%s: Not a report type=%x\n",
-		       hdlc_to_name(hdlc), skb->data[i]);
-		return 1;
-	}
-	i++;
-
-	i++;				/* Skip length field */
-
-	reptype = skb->data[i++];
-
-	if (skb->data[i]!=
-	    (mode_is(hdlc, MODE_FR_CCITT) ? LMI_CCITT_ALIVE : LMI_ALIVE)) {
-		printk(KERN_INFO "%s: Unsupported status element=%x\n",
-		       hdlc_to_name(hdlc), skb->data[i]);
-		return 1;
-	}
-	i++;
-
-	i++;			/* Skip length field */
-
-	hdlc->lmi.rxseq = skb->data[i++]; /* TX sequence from peer */
-	rxseq = skb->data[i++];	/* Should confirm our sequence */
-
-	txseq = hdlc->lmi.txseq;
-
-	if (mode_is(hdlc, MODE_DCE)) {
-		if (reptype != LMI_FULLREP && reptype != LMI_INTEGRITY) {
-			printk(KERN_INFO "%s: Unsupported report type=%x\n",
-			       hdlc_to_name(hdlc), reptype);
-			return 1;
-		}
-	}
-
-	error = 0;
-	if (!(hdlc->lmi.state & LINK_STATE_RELIABLE))
-		error = 1;
-
-	if (rxseq == 0 || rxseq != txseq) {
-		hdlc->lmi.N391cnt = 0; /* Ask for full report next time */
-		error = 1;
-	}
-
-	if (mode_is(hdlc, MODE_DCE)) {
-		if ((hdlc->lmi.state & LINK_STATE_FULLREP_SENT) && !error) {
-/* Stop sending full report - the last one has been confirmed by DTE */
-			hdlc->lmi.state &= ~LINK_STATE_FULLREP_SENT;
-			pvc = hdlc->first_pvc;
-			while (pvc) {
-				if (pvc->state & PVC_STATE_NEW) {
-					pvc->state &= ~PVC_STATE_NEW;
-					pvc->state |= PVC_STATE_ACTIVE;
-					fr_log_dlci_active(pvc);
-
-/* Tell DTE that new PVC is now active */
-					hdlc->lmi.state |= LINK_STATE_CHANGED;
-				}
-				pvc = pvc->next;
-			}
-		}
-
-		if (hdlc->lmi.state & LINK_STATE_CHANGED) {
-			reptype = LMI_FULLREP;
-			hdlc->lmi.state |= LINK_STATE_FULLREP_SENT;
-			hdlc->lmi.state &= ~LINK_STATE_CHANGED;
-		}
-
-		fr_lmi_send(hdlc, reptype == LMI_FULLREP ? 1 : 0);
-		return 0;
-	}
-
-	/* DTE */
-
-	if (reptype != LMI_FULLREP || error)
-		return 0;
-
-	stat_len = 3;
-	pvc = hdlc->first_pvc;
-
-	while (pvc) {
-		pvc->newstate = 0;
-		pvc = pvc->next;
-	}
-
-	while (skb->len >= i + 2 + stat_len) {
-		u16 dlci;
-		u8 state = 0;
-
-		if (skb->data[i] != (mode_is(hdlc, MODE_FR_CCITT) ?
-				     LMI_CCITT_PVCSTAT : LMI_PVCSTAT)) {
-			printk(KERN_WARNING "%s: Invalid PVCSTAT ID: %x\n",
-			       hdlc_to_name(hdlc), skb->data[i]);
-			return 1;
-		}
-		i++;
-
-		if (skb->data[i] != stat_len) {
-			printk(KERN_WARNING "%s: Invalid PVCSTAT length: %x\n",
-			       hdlc_to_name(hdlc), skb->data[i]);
-			return 1;
-		}
-		i++;
-
-		dlci = status_to_dlci(hdlc, skb->data+i, &state);
-		pvc = find_pvc(hdlc, dlci);
-
-		if (pvc)
-			pvc->newstate = state;
-		else if (state == PVC_STATE_NEW)
-			printk(KERN_INFO "%s: new PVC available, DLCI=%u\n",
-			       hdlc_to_name(hdlc), dlci);
-
-		i += stat_len;
-	}
-
-	pvc = hdlc->first_pvc;
-
-	while (pvc) {
-		if (pvc->newstate == PVC_STATE_NEW)
-			pvc->newstate = PVC_STATE_ACTIVE;
-
-		pvc->newstate |= (pvc->state &
-				  ~(PVC_STATE_NEW|PVC_STATE_ACTIVE));
-		if (pvc->state != pvc->newstate) {
-			pvc->state = pvc->newstate;
-			fr_log_dlci_active(pvc);
-		}
-		pvc = pvc->next;
-	}
-
-	/* Next full report after N391 polls */
-	hdlc->lmi.N391cnt = hdlc->lmi.N391;
-
-	return 0;
-}
-
-
-
-static void fr_netif(hdlc_device *hdlc, struct sk_buff *skb)
-{
-	fr_hdr *fh = (fr_hdr*)skb->data;
-	u8 *data = skb->data;
-	u16 dlci;
-	pvc_device *pvc;
-
-	if (skb->len<4 || fh->ea1 || data[2] != FR_UI)
-		goto rx_error;
-
-	dlci = q922_to_dlci(skb->data);
-
-	if (dlci == LMI_DLCI) {
-		if (data[3] == LMI_PROTO) {
-			if (fr_lmi_recv(hdlc, skb))
-				goto rx_error;
-			else {
-				/* No request pending */
-				hdlc->lmi.state &= ~LINK_STATE_REQUEST;
-				hdlc->lmi.last_poll = jiffies;
-				dev_kfree_skb_any(skb);
-				return;
-			}
-		}
-
-		printk(KERN_INFO "%s: Received non-LMI frame with LMI DLCI\n",
-		       hdlc_to_name(hdlc));
-		goto rx_error;
-	}
-
-	pvc = find_pvc(hdlc, dlci);
-	if (!pvc) {
-#ifdef DEBUG_PKT
-		printk(KERN_INFO "%s: No PVC for received frame's DLCI %d\n",
-		       hdlc_to_name(hdlc), dlci);
-#endif
-		goto rx_error;
-	}
-
-	if ((pvc->netdev.flags & IFF_UP) == 0) {
-#ifdef DEBUG_PKT
-		printk(KERN_INFO "%s: PVC for received frame's DLCI %d is down\n",
-		       hdlc_to_name(hdlc), dlci);
-#endif
-		goto rx_error;
-	}
-
-	pvc->stats.rx_packets++; /* PVC traffic */
-	pvc->stats.rx_bytes += skb->len;
-
-	if ((pvc->state & PVC_STATE_FECN) != (fh->fecn ? PVC_STATE_FECN : 0)) {
-#ifdef DEBUG_FECN
-		printk(KERN_DEBUG "%s: FECN O%s\n", pvc_to_name(pvc),
-		       fh->fecn ? "N" : "FF");
-#endif
-		pvc->state ^= PVC_STATE_FECN;
-	}
-
-	if ((pvc->state & PVC_STATE_BECN) != (fh->becn ? PVC_STATE_BECN : 0)) {
-#ifdef DEBUG_FECN
-		printk(KERN_DEBUG "%s: BECN O%s\n", pvc_to_name(pvc),
-		       fh->becn ? "N" : "FF");
-#endif
-		pvc->state ^= PVC_STATE_BECN;
-	}
-
-	if (pvc->state & PVC_STATE_BECN)
-		pvc->stats.rx_compressed++;
-
-	if (data[3] == NLPID_IP) {
-		skb_pull(skb, 4); /* Remove 4-byte header (hdr, UI, NLPID) */
-		skb->protocol = htons(ETH_P_IP);
-		skb->dev = &pvc->netdev;
-		netif_rx(skb);
-		return;
-	}
-
-
-	if (data[3] == NLPID_IPV6) {
-		skb_pull(skb, 4); /* Remove 4-byte header (hdr, UI, NLPID) */
-		skb->protocol = htons(ETH_P_IPV6);
-		skb->dev = &pvc->netdev;
-		netif_rx(skb);
-		return;
-	}
-
-	if (data[3] == FR_PAD && data[4] == NLPID_SNAP && data[5] == FR_PAD &&
-	    data[6] == FR_PAD && data[7] == FR_PAD &&
-	    ((data[8]<<8) | data[9]) == ETH_P_ARP) {
-		skb_pull(skb, 10);
-		skb->protocol = htons(ETH_P_ARP);
-		skb->dev = &pvc->netdev;
-		netif_rx(skb);
-		return;
-	}
-
-	printk(KERN_INFO "%s: Unusupported protocol %x\n",
-	       hdlc_to_name(hdlc), data[3]);
-	dev_kfree_skb_any(skb);
-	return;
-
- rx_error:
-	hdlc->stats.rx_errors++; /* Mark error */
-	dev_kfree_skb_any(skb);
-}
-
-
-
-static void fr_cisco_open(hdlc_device *hdlc)
-{
-	hdlc->lmi.state = LINK_STATE_CHANGED;
-	hdlc->lmi.txseq = hdlc->lmi.rxseq = 0;
-	hdlc->lmi.last_errors = 0xFFFFFFFF;
-	hdlc->lmi.N391cnt = 0;
-
-	init_timer(&hdlc->timer);
-	hdlc->timer.expires = jiffies + HZ; /* First poll after 1 second */
-	hdlc->timer.function = mode_is(hdlc, MODE_FR) ? fr_timer : cisco_timer;
-	hdlc->timer.data = (unsigned long)hdlc;
-	add_timer(&hdlc->timer);
-}
-
-
-
-static void fr_cisco_close(hdlc_device *hdlc)
-{
-	pvc_device *pvc = hdlc->first_pvc;
-
-	del_timer_sync(&hdlc->timer);
-
-	while(pvc) {		/* NULL in Cisco mode */
-		dev_close(&pvc->netdev); /* Shutdown all PVCs for this FRAD */
-		pvc = pvc->next;
-	}
-}
-
-
-
-/******************************************************************
- *
- *     generic HDLC routines
- *
- *****************************************************************/
-
-
-
-static int hdlc_change_mtu(struct net_device *dev, int new_mtu)
-{
-	if ((new_mtu < 68) || (new_mtu > HDLC_MAX_MTU))
-		return -EINVAL;
-	dev->mtu = new_mtu;
-	return 0;
-}
-
-
-
-/********************************************************
- *
- * PVC device routines
- *
- *******************************************************/
-
-static int pvc_open(struct net_device *dev)
-{
-	pvc_device *pvc = dev_to_pvc(dev);
-	int result = 0;
-
-	if ((hdlc_to_dev(pvc->master)->flags & IFF_UP) == 0)
-		return -EIO;  /* Master must be UP in order to activate PVC */
-
-	memset(&(pvc->stats), 0, sizeof(struct net_device_stats));
-	pvc->state = 0;
-
-	if (!mode_is(pvc->master, MODE_SOFT) && pvc->master->open_pvc)
-		result = pvc->master->open_pvc(pvc);
-	if (result)
-		return result;
-
-	pvc->master->lmi.state |= LINK_STATE_CHANGED;
-	return 0;
-}
-
-
-
-static int pvc_close(struct net_device *dev)
-{
-	pvc_device *pvc = dev_to_pvc(dev);
-	pvc->state = 0;
-
-	if (!mode_is(pvc->master, MODE_SOFT) && pvc->master->close_pvc)
-		pvc->master->close_pvc(pvc);
-
-	pvc->master->lmi.state |= LINK_STATE_CHANGED;
-	return 0;
-}
-
-
-
-static int pvc_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-	pvc_device *pvc = dev_to_pvc(dev);
-
-	if (pvc->state & PVC_STATE_ACTIVE) {
-		skb->dev = hdlc_to_dev(pvc->master);
-		pvc->stats.tx_bytes += skb->len;
-		pvc->stats.tx_packets++;
-		if (pvc->state & PVC_STATE_FECN)
-			pvc->stats.tx_compressed++; /* TX Congestion counter */
-		dev_queue_xmit(skb);
-	} else {
-		pvc->stats.tx_dropped++;
-		dev_kfree_skb(skb);
-	}
-
-	return 0;
-}
-
-
-
-static struct net_device_stats *pvc_get_stats(struct net_device *dev)
-{
-	pvc_device *pvc = dev_to_pvc(dev);
-	return &pvc->stats;
-}
-
-
-
-static int pvc_change_mtu(struct net_device *dev, int new_mtu)
-{
-	if ((new_mtu < 68) || (new_mtu > HDLC_MAX_MTU))
-		return -EINVAL;
-	dev->mtu = new_mtu;
-	return 0;
-}
-
-
-
-static void destroy_pvc_list(hdlc_device *hdlc)
-{
-	pvc_device *pvc = hdlc->first_pvc;
-	while(pvc) {
-		pvc_device *next = pvc->next;
-		unregister_netdevice(&pvc->netdev);
-		kfree(pvc);
-		pvc = next;
-	}
-
-	hdlc->first_pvc = NULL;	/* All PVCs destroyed */
-	hdlc->pvc_count = 0;
-	hdlc->lmi.state |= LINK_STATE_CHANGED;
-}
-
-
-
-/********************************************************
- *
- * X.25 protocol support routines
- *
- *******************************************************/
-
-#ifdef CONFIG_HDLC_X25
-/* These functions are callbacks called by LAPB layer */
-
-void x25_connect_disconnect(void *token, int reason, int code)
-{
-	hdlc_device *hdlc = token;
-	struct sk_buff *skb;
-	unsigned char *ptr;
-
-	if ((skb = dev_alloc_skb(1)) == NULL) {
-		printk(KERN_ERR "%s: out of memory\n", hdlc_to_name(hdlc));
-		return;
-	}
-
-	ptr = skb_put(skb, 1);
-	*ptr = code;
-
-	skb->dev = hdlc_to_dev(hdlc);
-	skb->protocol = htons(ETH_P_X25);
-	skb->mac.raw = skb->data;
-	skb->pkt_type = PACKET_HOST;
-
-	netif_rx(skb);
-}
-
-void x25_connected(void *token, int reason)
-{
-	x25_connect_disconnect(token, reason, 1);
-}
-
-void x25_disconnected(void *token, int reason)
-{
-	x25_connect_disconnect(token, reason, 2);
-}
-
-
-int x25_data_indication(void *token, struct sk_buff *skb)
-{
-	hdlc_device *hdlc = token;
-	unsigned char *ptr;
-
-	ptr = skb_push(skb, 1);
-	*ptr = 0;
-
-	skb->dev = hdlc_to_dev(hdlc);
-	skb->protocol = htons(ETH_P_X25);
-	skb->mac.raw = skb->data;
-	skb->pkt_type = PACKET_HOST;
-
-	return netif_rx(skb);
-}
-
-
-void x25_data_transmit(void *token, struct sk_buff *skb)
-{
-	hdlc_device *hdlc = token;
-	hdlc->xmit(hdlc, skb);	/* Ignore return value :-( */
-}
-#endif /* CONFIG_HDLC_X25 */
-
-
-/********************************************************
- *
- * HDLC device routines
- *
- *******************************************************/
-
-static int hdlc_open(struct net_device *dev)
-{
-	hdlc_device *hdlc = dev_to_hdlc(dev);
-	int result;
-
-	if (hdlc->mode == MODE_NONE)
-		return -ENOSYS;
-
-	memset(&(hdlc->stats), 0, sizeof(struct net_device_stats));
-
-	if (mode_is(hdlc, MODE_FR | MODE_SOFT) ||
-	    mode_is(hdlc, MODE_CISCO | MODE_SOFT))
-		fr_cisco_open(hdlc);
-#ifdef CONFIG_HDLC_PPP
-	else if (mode_is(hdlc, MODE_PPP | MODE_SOFT)) {
-		sppp_attach(&hdlc->pppdev);
-		/* sppp_attach nukes them. We don't need syncppp's ioctl */
-		dev->do_ioctl = hdlc_ioctl;
-		hdlc->pppdev.sppp.pp_flags &= ~PP_CISCO;
-		dev->type = ARPHRD_PPP;
-		result = sppp_open(dev);
-		if (result) {
-			sppp_detach(dev);
-			return result;
-		}
-	}
-#endif
-#ifdef CONFIG_HDLC_X25
-	else if (mode_is(hdlc, MODE_X25)) {
-		struct lapb_register_struct cb;
-
-		cb.connect_confirmation = x25_connected;
-		cb.connect_indication = x25_connected;
-		cb.disconnect_confirmation = x25_disconnected;
-		cb.disconnect_indication = x25_disconnected;
-		cb.data_indication = x25_data_indication;
-		cb.data_transmit = x25_data_transmit;
-
-		result = lapb_register(hdlc, &cb);
-		if (result != LAPB_OK)
-			return result;
-	}
-#endif
-	result = hdlc->open(hdlc);
-	if (result) {
-		if (mode_is(hdlc, MODE_FR | MODE_SOFT) ||
-		    mode_is(hdlc, MODE_CISCO | MODE_SOFT))
-			fr_cisco_close(hdlc);
-#ifdef CONFIG_HDLC_PPP
-		else if (mode_is(hdlc, MODE_PPP | MODE_SOFT)) {
-			sppp_close(dev);
-			sppp_detach(dev);
-			dev->rebuild_header = NULL;
-			dev->change_mtu = hdlc_change_mtu;
-			dev->mtu = HDLC_MAX_MTU;
-			dev->hard_header_len = 16;
-		}
-#endif
-#ifdef CONFIG_HDLC_X25
-		else if (mode_is(hdlc, MODE_X25))
-			lapb_unregister(hdlc);
-#endif
-	}
-
-	return result;
-}
-
-
-
-static int hdlc_close(struct net_device *dev)
-{
-	hdlc_device *hdlc = dev_to_hdlc(dev);
-
-	hdlc->close(hdlc);
-
-	if (mode_is(hdlc, MODE_FR | MODE_SOFT) ||
-	    mode_is(hdlc, MODE_CISCO | MODE_SOFT))
-		fr_cisco_close(hdlc);
-#ifdef CONFIG_HDLC_PPP
-	else if (mode_is(hdlc, MODE_PPP | MODE_SOFT)) {
-		sppp_close(dev);
-		sppp_detach(dev);
-		dev->rebuild_header = NULL;
-		dev->change_mtu = hdlc_change_mtu;
-		dev->mtu = HDLC_MAX_MTU;
-		dev->hard_header_len = 16;
-	}
-#endif
-#ifdef CONFIG_HDLC_X25
-	else if (mode_is(hdlc, MODE_X25))
-		lapb_unregister(hdlc);
-#endif
-	return 0;
-}
-
-
-
-static int hdlc_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-	hdlc_device *hdlc = dev_to_hdlc(dev);
-
-#ifdef CONFIG_HDLC_X25
-	if (mode_is(hdlc, MODE_X25 | MODE_SOFT)) {
-		int result;
-
-
-		/* X.25 to LAPB */
-		switch (skb->data[0]) {
-		case 0:		/* Data to be transmitted */
-			skb_pull(skb, 1);
-			if ((result = lapb_data_request(hdlc, skb)) != LAPB_OK)
-				dev_kfree_skb(skb);
-			return 0;
-
-		case 1:
-			if ((result = lapb_connect_request(hdlc))!= LAPB_OK) {
-				if (result == LAPB_CONNECTED) {
-				/* Send connect confirm. msg to level 3 */
-					x25_connected(hdlc, 0);
-				} else {
-					printk(KERN_ERR "%s: LAPB connect "
-					       "request failed, error code = "
-					       "%i\n", hdlc_to_name(hdlc),
-					       result);
-				}
-			}
-			break;
-
-		case 2:
-			if ((result=lapb_disconnect_request(hdlc))!=LAPB_OK) {
-				if (result == LAPB_NOTCONNECTED) {
-				/* Send disconnect confirm. msg to level 3 */
-					x25_disconnected(hdlc, 0);
-				} else {
-					printk(KERN_ERR "%s: LAPB disconnect "
-					       "request failed, error code = "
-					       "%i\n", hdlc_to_name(hdlc),
-					       result);
-				}
-			}
-			break;
-
-		default:
-			/* to be defined */
-			break;
-		}
-
-		dev_kfree_skb(skb);
-		return 0;
-	} /* MODE_X25 */
-#endif /* CONFIG_HDLC_X25 */
-
-	return hdlc->xmit(hdlc, skb);
-}
-
-
-
-void hdlc_netif_rx(hdlc_device *hdlc, struct sk_buff *skb)
-{
-/* skb contains raw HDLC frame, in both hard- and software modes */
-	skb->mac.raw = skb->data;
-
-	switch(hdlc->mode & MODE_MASK) {
-	case MODE_HDLC:
-		skb->protocol = htons(ETH_P_IP);
-		skb->dev = hdlc_to_dev(hdlc);
-		netif_rx(skb);
-		return;
-
-	case MODE_FR:
-		fr_netif(hdlc, skb);
-		return;
-
-	case MODE_CISCO:
-		cisco_netif(hdlc, skb);
-		return;
-
-#ifdef CONFIG_HDLC_PPP
-	case MODE_PPP:
-#if 0
-		sppp_input(hdlc_to_dev(hdlc), skb);
-#else
-		skb->protocol = htons(ETH_P_WAN_PPP);
-		skb->dev = hdlc_to_dev(hdlc);
-		netif_rx(skb);
-#endif
-		return;
-#endif
-#ifdef CONFIG_HDLC_X25
-	case MODE_X25:
-		skb->dev = hdlc_to_dev(hdlc);
-		if (lapb_data_received(hdlc, skb) == LAPB_OK)
-			return;
-		break;
-#endif
-	}
-
-	hdlc->stats.rx_errors++;
-	dev_kfree_skb_any(skb);
-}
-
-
-
-static struct net_device_stats *hdlc_get_stats(struct net_device *dev)
-{
-	return &dev_to_hdlc(dev)->stats;
-}
-
-
-
-static int hdlc_set_mode(hdlc_device *hdlc, int mode)
-{
-	int result = -1;	/* Default to soft modes */
-	struct net_device *dev = hdlc_to_dev(hdlc);
-
-	if(!capable(CAP_NET_ADMIN))
-		return -EPERM;
-
-	if(dev->flags & IFF_UP)
-		return -EBUSY;
-
-	dev->addr_len = 0;
-	dev->hard_header = NULL;
-	hdlc->mode = MODE_NONE;
-
-	if (!(mode & MODE_SOFT))
-		switch(mode & MODE_MASK) {
-		case MODE_HDLC:
-			result = hdlc->set_mode ?
-				hdlc->set_mode(hdlc, MODE_HDLC) : 0;
-			break;
-
-		case MODE_CISCO: /* By card */
-#ifdef CONFIG_HDLC_PPP
-		case MODE_PPP:
-#endif
-#ifdef CONFIG_HDLC_X25
-		case MODE_X25:
-#endif
-		case MODE_FR:
-			result = hdlc->set_mode ?
-				hdlc->set_mode(hdlc, mode) : -ENOSYS;
-			break;
-
-		default:
-			return -EINVAL;
-		}
-
-	if (result) {
-		mode |= MODE_SOFT; /* Try "host software" protocol */
-
-		switch(mode & MODE_MASK) {
-		case MODE_CISCO:
-			dev->hard_header = cisco_hard_header;
-			break;
-
-#ifdef CONFIG_HDLC_PPP
-		case MODE_PPP:
-			break;
-#endif
-#ifdef CONFIG_HDLC_X25
-		case MODE_X25:
-			break;
-#endif
-
-		case MODE_FR:
-			dev->hard_header = fr_hard_header;
-			dev->addr_len = 2;
-			*(u16*)dev->dev_addr = htons(LMI_DLCI);
-			dlci_to_q922(dev->broadcast, LMI_DLCI);
-			break;
-
-		default:
-			return -EINVAL;
-		}
-
-		result = hdlc->set_mode ?
-			hdlc->set_mode(hdlc, MODE_HDLC) : 0;
-	}
-
-	if (result)
-		return result;
-
-	hdlc->mode = mode;
-	switch(mode & MODE_MASK) {
-#ifdef CONFIG_HDLC_PPP
-	case MODE_PPP:   dev->type = ARPHRD_PPP;   break;
-#endif
-#ifdef CONFIG_HDLC_X25
-	case MODE_X25:   dev->type = ARPHRD_X25;   break;
-#endif
-	case MODE_FR:    dev->type = ARPHRD_FRAD;  break;
-	case MODE_CISCO: dev->type = ARPHRD_CISCO; break;
-	default:         dev->type = ARPHRD_RAWHDLC;
-	}
-
-	memset(&(hdlc->stats), 0, sizeof(struct net_device_stats));
-	destroy_pvc_list(hdlc);
-	return 0;
-}
-
-
-
-static int hdlc_fr_pvc(hdlc_device *hdlc, int dlci)
-{
-	pvc_device **pvc_p = &hdlc->first_pvc;
-	pvc_device *pvc;
-	int result, create = 1;	/* Create or delete PVC */
-
-	if(!capable(CAP_NET_ADMIN))
-		return -EPERM;
-
-	if(dlci<0) {
-		dlci = -dlci;
-		create = 0;
-	}
-
-	if(dlci <= 0 || dlci >= 1024)
-		return -EINVAL;	/* Only 10 bits for DLCI, DLCI=0 is reserved */
-
-	if(!mode_is(hdlc, MODE_FR))
-		return -EINVAL;	/* Only meaningfull on FR */
-
-	while(*pvc_p) {
-		if (netdev_dlci(&(*pvc_p)->netdev) == dlci)
-			break;
-		pvc_p = &(*pvc_p)->next;
-	}
-
-	if (create) {		/* Create PVC */
-		if (*pvc_p != NULL)
-			return -EEXIST;
-
-		pvc = *pvc_p = kmalloc(sizeof(pvc_device), GFP_KERNEL);
-		if (!pvc) {
-			printk(KERN_WARNING "%s: Memory squeeze on "
-			       "hdlc_fr_pvc()\n", hdlc_to_name(hdlc));
-			return -ENOBUFS;
-		}
-		memset(pvc, 0, sizeof(pvc_device));
-
-		pvc->netdev.hard_start_xmit = pvc_xmit;
-		pvc->netdev.get_stats = pvc_get_stats;
-		pvc->netdev.open = pvc_open;
-		pvc->netdev.stop = pvc_close;
-		pvc->netdev.change_mtu = pvc_change_mtu;
-		pvc->netdev.mtu = HDLC_MAX_MTU;
-
-		pvc->netdev.type = ARPHRD_DLCI;
-		pvc->netdev.hard_header_len = 16;
-		pvc->netdev.hard_header = fr_hard_header;
-		pvc->netdev.tx_queue_len = 0;
-		pvc->netdev.flags = IFF_POINTOPOINT;
-
-		pvc->master = hdlc;
-		*(u16*)pvc->netdev.dev_addr = htons(dlci);
-		dlci_to_q922(pvc->netdev.broadcast, dlci);
-		pvc->netdev.addr_len = 2;
-		pvc->netdev.irq = hdlc_to_dev(hdlc)->irq;
-
-		result = dev_alloc_name(&pvc->netdev, "pvc%d");
-		if (result < 0) {
-			kfree(pvc);
-			*pvc_p = NULL;
-			return result;
-		}
-
-		if (register_netdevice(&pvc->netdev) != 0) {
-			kfree(pvc);
-			*pvc_p = NULL;
-			return -EIO;
-		}
-
-		if (!mode_is(hdlc, MODE_SOFT) && hdlc->create_pvc) {
-			result = hdlc->create_pvc(pvc);
-			if (result) {
-				unregister_netdevice(&pvc->netdev);
-				kfree(pvc);
-				*pvc_p = NULL;
-				return result;
-			}
-		}
-
-		hdlc->lmi.state |= LINK_STATE_CHANGED;
-		hdlc->pvc_count++;
-		return 0;
-	}
-
-	if (*pvc_p == NULL)		/* Delete PVC */
-		return -ENOENT;
-
-	pvc = *pvc_p;
-
-	if (pvc->netdev.flags & IFF_UP)
-		return -EBUSY;		/* PVC in use */
-
-	if (!mode_is(hdlc, MODE_SOFT) && hdlc->destroy_pvc)
-		hdlc->destroy_pvc(pvc);
-
-	hdlc->lmi.state |= LINK_STATE_CHANGED;
-	hdlc->pvc_count--;
-	*pvc_p = pvc->next;
-	unregister_netdevice(&pvc->netdev);
-	kfree(pvc);
-	return 0;
-}
-
-
-
-static int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
-	hdlc_device *hdlc = dev_to_hdlc(dev);
-
-	switch(cmd) {
-	case HDLCGMODE:
-		ifr->ifr_ifru.ifru_ivalue = hdlc->mode;
-		return 0;
-
-	case HDLCSMODE:
-		return hdlc_set_mode(hdlc, ifr->ifr_ifru.ifru_ivalue);
-
-	case HDLCPVC:
-		return hdlc_fr_pvc(hdlc, ifr->ifr_ifru.ifru_ivalue);
-
-	default:
-		if (hdlc->ioctl != NULL)
-			return hdlc->ioctl(hdlc, ifr, cmd);
-	}
-
-	return -EINVAL;
-}
-
-
-
-static int hdlc_init(struct net_device *dev)
-{
-	hdlc_device *hdlc = dev_to_hdlc(dev);
-
-	memset(&(hdlc->stats), 0, sizeof(struct net_device_stats));
-
-	dev->get_stats = hdlc_get_stats;
-	dev->open = hdlc_open;
-	dev->stop = hdlc_close;
-	dev->hard_start_xmit = hdlc_xmit;
-	dev->do_ioctl = hdlc_ioctl;
-	dev->change_mtu = hdlc_change_mtu;
-	dev->mtu = HDLC_MAX_MTU;
-
-	dev->type = ARPHRD_RAWHDLC;
-	dev->hard_header_len = 16;
-
-	dev->flags = IFF_POINTOPOINT | IFF_NOARP;
-
-	return 0;
-}
-
-
-
-int register_hdlc_device(hdlc_device *hdlc)
-{
-	int result;
-	struct net_device *dev = hdlc_to_dev(hdlc);
-
-	dev->init = hdlc_init;
-	dev->priv = &hdlc->syncppp_ptr;
-	hdlc->syncppp_ptr = &hdlc->pppdev;
-	hdlc->pppdev.dev = dev;
-	hdlc->mode = MODE_NONE;
-	hdlc->lmi.T391 = 10;	/* polling verification timer */
-	hdlc->lmi.T392 = 15;	/* link integrity verification polling timer */
-	hdlc->lmi.N391 = 6;	/* full status polling counter */
-	hdlc->lmi.N392 = 3;	/* error threshold */
-	hdlc->lmi.N393 = 4;	/* monitored events count */
-
-	result = dev_alloc_name(dev, "hdlc%d");
-	if (result<0)
-		return result;
-
-	result = register_netdev(dev);
-	if (result != 0)
-		return -EIO;
-
-	MOD_INC_USE_COUNT;
-	return 0;
-}
-
-
-
-void unregister_hdlc_device(hdlc_device *hdlc)
-{
-	destroy_pvc_list(hdlc);
-	unregister_netdev(hdlc_to_dev(hdlc));
-	MOD_DEC_USE_COUNT;
-}
-
-MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
-MODULE_DESCRIPTION("HDLC support module");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(hdlc_netif_rx);
-EXPORT_SYMBOL(register_hdlc_device);
-EXPORT_SYMBOL(unregister_hdlc_device);
-
-static int __init hdlc_module_init(void)
-{
-	printk(KERN_INFO "%s\n", version);
-	return 0;
-}
-
-
-module_init(hdlc_module_init);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/wan/hdlc_cisco.c linux-2.4.21-pre6/drivers/net/wan/hdlc_cisco.c
--- linux-2.4.20/drivers/net/wan/hdlc_cisco.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/wan/hdlc_cisco.c	2003-03-26 23:49:08.000000000 +0000
@@ -0,0 +1,300 @@
+/*
+ * Generic HDLC support routines for Linux
+ * Cisco HDLC support
+ *
+ * Copyright (C) 2000 - 2001 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * 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/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/errno.h>
+#include <linux/if_arp.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/pkt_sched.h>
+#include <linux/inetdevice.h>
+#include <linux/lapb.h>
+#include <linux/rtnetlink.h>
+#include <linux/hdlc.h>
+
+
+#define CISCO_MULTICAST		0x8F	/* Cisco multicast address */
+#define CISCO_UNICAST		0x0F	/* Cisco unicast address */
+#define CISCO_KEEPALIVE		0x8035	/* Cisco keepalive protocol */
+#define CISCO_SYS_INFO		0x2000	/* Cisco interface/system info */
+#define CISCO_ADDR_REQ		0	/* Cisco address request */
+#define CISCO_ADDR_REPLY	1	/* Cisco address reply */
+#define CISCO_KEEPALIVE_REQ	2	/* Cisco keepalive request */
+
+
+static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev,
+			     u16 type, void *daddr, void *saddr,
+			     unsigned int len)
+{
+	hdlc_header *data;
+#ifdef CONFIG_HDLC_DEBUG_HARD_HEADER
+	printk(KERN_DEBUG "%s: cisco_hard_header called\n", dev->name);
+#endif
+
+	skb_push(skb, sizeof(hdlc_header));
+	data = (hdlc_header*)skb->data;
+	if (type == CISCO_KEEPALIVE)
+		data->address = CISCO_MULTICAST;
+	else
+		data->address = CISCO_UNICAST;
+	data->control = 0;
+	data->protocol = htons(type);
+
+	return sizeof(hdlc_header);
+}
+
+
+
+static void cisco_keepalive_send(hdlc_device *hdlc, u32 type,
+				 u32 par1, u32 par2)
+{
+	struct sk_buff *skb;
+	cisco_packet *data;
+
+	skb = dev_alloc_skb(sizeof(hdlc_header) + sizeof(cisco_packet));
+	if (!skb) {
+		printk(KERN_WARNING
+		       "%s: Memory squeeze on cisco_keepalive_send()\n",
+		       hdlc_to_name(hdlc));
+		return;
+	}
+	skb_reserve(skb, 4);
+	cisco_hard_header(skb, hdlc_to_dev(hdlc), CISCO_KEEPALIVE,
+			  NULL, NULL, 0);
+	data = (cisco_packet*)skb->tail;
+
+	data->type = htonl(type);
+	data->par1 = htonl(par1);
+	data->par2 = htonl(par2);
+	data->rel = 0xFFFF;
+	data->time = htonl(jiffies * 1000 / HZ);
+
+	skb_put(skb, sizeof(cisco_packet));
+	skb->priority = TC_PRIO_CONTROL;
+	skb->dev = hdlc_to_dev(hdlc);
+
+	dev_queue_xmit(skb);
+}
+
+
+
+static void cisco_rx(struct sk_buff *skb)
+{
+	hdlc_device *hdlc = dev_to_hdlc(skb->dev);
+	hdlc_header *data = (hdlc_header*)skb->data;
+	cisco_packet *cisco_data;
+	struct in_device *in_dev;
+	u32 addr, mask;
+
+	if (skb->len < sizeof(hdlc_header))
+		goto rx_error;
+
+	if (data->address != CISCO_MULTICAST &&
+	    data->address != CISCO_UNICAST)
+		goto rx_error;
+
+	skb_pull(skb, sizeof(hdlc_header));
+
+	switch(ntohs(data->protocol)) {
+	case ETH_P_IP:
+	case ETH_P_IPX:
+	case ETH_P_IPV6:
+		skb->protocol = data->protocol;
+		skb->dev = hdlc_to_dev(hdlc);
+		netif_rx(skb);
+		return;
+
+	case CISCO_SYS_INFO:
+		/* Packet is not needed, drop it. */
+		dev_kfree_skb_any(skb);
+		return;
+
+	case CISCO_KEEPALIVE:
+		if (skb->len != CISCO_PACKET_LEN &&
+		    skb->len != CISCO_BIG_PACKET_LEN) {
+			printk(KERN_INFO "%s: Invalid length of Cisco "
+			       "control packet (%d bytes)\n",
+			       hdlc_to_name(hdlc), skb->len);
+			goto rx_error;
+		}
+
+		cisco_data = (cisco_packet*)skb->data;
+
+		switch(ntohl (cisco_data->type)) {
+		case CISCO_ADDR_REQ: /* Stolen from syncppp.c :-) */
+			in_dev = hdlc_to_dev(hdlc)->ip_ptr;
+			addr = 0;
+			mask = ~0; /* is the mask correct? */
+
+			if (in_dev != NULL) {
+				struct in_ifaddr **ifap = &in_dev->ifa_list;
+
+				while (*ifap != NULL) {
+					if (strcmp(hdlc_to_name(hdlc),
+						   (*ifap)->ifa_label) == 0) {
+						addr = (*ifap)->ifa_local;
+						mask = (*ifap)->ifa_mask;
+						break;
+					}
+					ifap = &(*ifap)->ifa_next;
+				}
+
+				cisco_keepalive_send(hdlc, CISCO_ADDR_REPLY,
+						     addr, mask);
+			}
+			dev_kfree_skb_any(skb);
+			return;
+
+		case CISCO_ADDR_REPLY:
+			printk(KERN_INFO "%s: Unexpected Cisco IP address "
+			       "reply\n", hdlc_to_name(hdlc));
+			goto rx_error;
+
+		case CISCO_KEEPALIVE_REQ:
+			hdlc->state.cisco.rxseq = ntohl(cisco_data->par1);
+			if (ntohl(cisco_data->par2) == hdlc->state.cisco.txseq) {
+				hdlc->state.cisco.last_poll = jiffies;
+				if (!hdlc->state.cisco.up) {
+					u32 sec, min, hrs, days;
+					sec = ntohl(cisco_data->time) / 1000;
+					min = sec / 60; sec -= min * 60;
+					hrs = min / 60; min -= hrs * 60;
+					days = hrs / 24; hrs -= days * 24;
+					printk(KERN_INFO "%s: Link up (peer "
+					       "uptime %ud%uh%um%us)\n",
+					       hdlc_to_name(hdlc), days, hrs,
+					       min, sec);
+				}
+				hdlc->state.cisco.up = 1;
+			}
+
+			dev_kfree_skb_any(skb);
+			return;
+		} /* switch(keepalive type) */
+	} /* switch(protocol) */
+
+	printk(KERN_INFO "%s: Unsupported protocol %x\n", hdlc_to_name(hdlc),
+	       data->protocol);
+	dev_kfree_skb_any(skb);
+	return;
+
+ rx_error:
+	hdlc->stats.rx_errors++; /* Mark error */
+	dev_kfree_skb_any(skb);
+}
+
+
+
+static void cisco_timer(unsigned long arg)
+{
+	hdlc_device *hdlc = (hdlc_device*)arg;
+
+	if (hdlc->state.cisco.up &&
+	    jiffies - hdlc->state.cisco.last_poll >=
+	    hdlc->state.cisco.settings.timeout * HZ) {
+		hdlc->state.cisco.up = 0;
+		printk(KERN_INFO "%s: Link down\n", hdlc_to_name(hdlc));
+	}
+
+	cisco_keepalive_send(hdlc, CISCO_KEEPALIVE_REQ,
+			     ++hdlc->state.cisco.txseq,
+			     hdlc->state.cisco.rxseq);
+	hdlc->state.cisco.timer.expires = jiffies +
+		hdlc->state.cisco.settings.interval * HZ;
+	hdlc->state.cisco.timer.function = cisco_timer;
+	hdlc->state.cisco.timer.data = arg;
+	add_timer(&hdlc->state.cisco.timer);
+}
+
+
+
+static int cisco_open(hdlc_device *hdlc)
+{
+	hdlc->state.cisco.last_poll = 0;
+	hdlc->state.cisco.up = 0;
+	hdlc->state.cisco.txseq = hdlc->state.cisco.rxseq = 0;
+
+	init_timer(&hdlc->state.cisco.timer);
+	hdlc->state.cisco.timer.expires = jiffies + HZ; /*First poll after 1s*/
+	hdlc->state.cisco.timer.function = cisco_timer;
+	hdlc->state.cisco.timer.data = (unsigned long)hdlc;
+	add_timer(&hdlc->state.cisco.timer);
+	return 0;
+}
+
+
+
+static void cisco_close(hdlc_device *hdlc)
+{
+	del_timer_sync(&hdlc->state.cisco.timer);
+}
+
+
+
+int hdlc_cisco_ioctl(hdlc_device *hdlc, struct ifreq *ifr)
+{
+	cisco_proto *cisco_s = ifr->ifr_settings.ifs_ifsu.cisco;
+	const size_t size = sizeof(cisco_proto);
+	cisco_proto new_settings;
+	struct net_device *dev = hdlc_to_dev(hdlc);
+	int result;
+
+	switch (ifr->ifr_settings.type) {
+	case IF_GET_PROTO:
+		ifr->ifr_settings.type = IF_PROTO_CISCO;
+		if (ifr->ifr_settings.size < size) {
+			ifr->ifr_settings.size = size; /* data size wanted */
+			return -ENOBUFS;
+		}
+		if (copy_to_user(cisco_s, &hdlc->state.cisco.settings, size))
+			return -EFAULT;
+		return 0;
+
+	case IF_PROTO_CISCO:
+		if(!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
+		if(dev->flags & IFF_UP)
+			return -EBUSY;
+
+		if (copy_from_user(&new_settings, cisco_s, size))
+			return -EFAULT;
+
+		if (new_settings.interval < 1 ||
+		    new_settings.timeout < 2)
+			return -EINVAL;
+
+		result=hdlc->attach(hdlc, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
+
+		if (result)
+			return result;
+
+		hdlc_proto_detach(hdlc);
+		memcpy(&hdlc->state.cisco.settings, &new_settings, size);
+
+		hdlc->open = cisco_open;
+		hdlc->stop = cisco_close;
+		hdlc->netif_rx = cisco_rx;
+		hdlc->proto = IF_PROTO_CISCO;
+		dev->hard_start_xmit = hdlc->xmit;
+		dev->hard_header = cisco_hard_header;
+		dev->type = ARPHRD_CISCO;
+		dev->addr_len = 0;
+		return 0;
+	}
+
+	return -EINVAL;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/wan/hdlc_fr.c linux-2.4.21-pre6/drivers/net/wan/hdlc_fr.c
--- linux-2.4.20/drivers/net/wan/hdlc_fr.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/wan/hdlc_fr.c	2003-03-26 23:48:59.000000000 +0000
@@ -0,0 +1,862 @@
+/*
+ * Generic HDLC support routines for Linux
+ * Frame Relay support
+ *
+ * Copyright (C) 1999 - 2001 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * 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/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/errno.h>
+#include <linux/if_arp.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/pkt_sched.h>
+#include <linux/inetdevice.h>
+#include <linux/lapb.h>
+#include <linux/rtnetlink.h>
+#include <linux/hdlc.h>
+
+
+__inline__ pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci)
+{
+	pvc_device *pvc=hdlc->state.fr.first_pvc;
+	
+	while (pvc) {
+		if (netdev_dlci(&pvc->netdev) == dlci)
+			return pvc;
+		pvc = pvc->next;
+	}
+
+	return NULL;
+}
+
+
+
+__inline__ u16 status_to_dlci(hdlc_device *hdlc, u8 *status,
+			      int *active, int *new)
+{
+	*new = (status[2] & 0x08);
+	*active = (!*new && (status[2] & 0x02));
+
+	return ((status[0] & 0x3F)<<4) | ((status[1] & 0x78)>>3);
+}
+
+
+__inline__ void dlci_to_status(hdlc_device *hdlc, u16 dlci, u8 *status,
+			       int active, int new)
+{
+	status[0] = (dlci>>4) & 0x3F;
+	status[1] = ((dlci<<3) & 0x78) | 0x80;
+	status[2] = 0x80;
+
+	if (new)
+		status[2] |= 0x08;
+	else if (active)
+		status[2] |= 0x02;
+}
+
+
+
+static int fr_hard_header(struct sk_buff *skb, struct net_device *dev,
+			  u16 type, void *daddr, void *saddr, unsigned int len)
+{
+	u16 head_len;
+
+	if (!daddr)
+		daddr = dev->broadcast;
+
+#ifdef CONFIG_HDLC_DEBUG_HARD_HEADER
+	printk(KERN_DEBUG "%s: fr_hard_header called\n", dev->name);
+#endif
+
+	switch(type) {
+	case ETH_P_IP:
+		head_len = 4;
+		skb_push(skb, head_len);
+		skb->data[3] = NLPID_IP;
+		break;
+
+	case ETH_P_IPV6:
+		head_len = 4;
+		skb_push(skb, head_len);
+		skb->data[3] = NLPID_IPV6;
+		break;
+
+	case LMI_PROTO:
+		head_len = 4;
+		skb_push(skb, head_len);
+		skb->data[3] = LMI_PROTO;
+		break;
+
+	default:
+		head_len = 10;
+		skb_push(skb, head_len);
+		skb->data[3] = FR_PAD;
+		skb->data[4] = NLPID_SNAP;
+		skb->data[5] = FR_PAD;
+		skb->data[6] = FR_PAD;
+		skb->data[7] = FR_PAD;
+		skb->data[8] = type>>8;
+		skb->data[9] = (u8)type;
+	}
+
+	memcpy(skb->data, daddr, 2);
+	skb->data[2] = FR_UI;
+
+	return head_len;
+}
+
+
+
+static int pvc_open(struct net_device *dev)
+{
+	pvc_device *pvc = dev_to_pvc(dev);
+
+	if ((hdlc_to_dev(pvc->master)->flags & IFF_UP) == 0)
+		return -EIO;  /* Master must be UP in order to activate PVC */
+
+	if (pvc->master->state.fr.settings.lmi != LMI_NONE)
+		pvc->state.active = 0;
+	else
+		pvc->state.active = 1;
+
+	pvc->state.new = 0;
+	pvc->master->state.fr.changed = 1;
+	return 0;
+}
+
+
+
+static int pvc_close(struct net_device *dev)
+{
+	pvc_device *pvc = dev_to_pvc(dev);
+	pvc->state.active = pvc->state.new = 0;
+	pvc->master->state.fr.changed = 1;
+	return 0;
+}
+
+
+
+static int pvc_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	pvc_device *pvc = dev_to_pvc(dev);
+
+	if (pvc->state.active) {
+		skb->dev = hdlc_to_dev(pvc->master);
+		pvc->stats.tx_bytes += skb->len;
+		pvc->stats.tx_packets++;
+		if (pvc->state.fecn)
+			pvc->stats.tx_compressed++; /* TX Congestion counter */
+		dev_queue_xmit(skb);
+	} else {
+		pvc->stats.tx_dropped++;
+		dev_kfree_skb(skb);
+	}
+
+	return 0;
+}
+
+
+
+static struct net_device_stats *pvc_get_stats(struct net_device *dev)
+{
+	pvc_device *pvc = dev_to_pvc(dev);
+	return &pvc->stats;
+}
+
+
+
+static int pvc_change_mtu(struct net_device *dev, int new_mtu)
+{
+	if ((new_mtu < 68) || (new_mtu > HDLC_MAX_MTU))
+		return -EINVAL;
+	dev->mtu = new_mtu;
+	return 0;
+}
+
+
+
+static inline void fr_log_dlci_active(pvc_device *pvc)
+{
+	printk(KERN_INFO "%s: %sactive%s\n", pvc_to_name(pvc),
+	       pvc->state.active ? "" : "in",
+	       pvc->state.new ? " new" : "");
+}
+
+
+
+static inline u8 fr_lmi_nextseq(u8 x)
+{
+	x++;
+	return x ? x : 1;
+}
+
+
+
+static void fr_lmi_send(hdlc_device *hdlc, int fullrep)
+{
+	struct sk_buff *skb;
+	pvc_device *pvc = hdlc->state.fr.first_pvc;
+	int len = (hdlc->state.fr.settings.lmi == LMI_ANSI) ? LMI_ANSI_LENGTH
+		: LMI_LENGTH;
+	int stat_len = 3;
+	u8 *data;
+	int i = 0;
+
+	if (hdlc->state.fr.settings.dce && fullrep) {
+		len += hdlc->state.fr.pvc_count * (2 + stat_len);
+		if (len > HDLC_MAX_MTU) {
+			printk(KERN_WARNING "%s: Too many PVCs while sending "
+			       "LMI full report\n", hdlc_to_name(hdlc));
+			return;
+		}
+	}
+
+	skb = dev_alloc_skb(len);
+	if (!skb) {
+		printk(KERN_WARNING "%s: Memory squeeze on fr_lmi_send()\n",
+			       hdlc_to_name(hdlc));
+		return;
+	}
+	memset(skb->data, 0, len);
+	skb_reserve(skb, 4);
+	fr_hard_header(skb, hdlc_to_dev(hdlc), LMI_PROTO, NULL, NULL, 0);
+	data = skb->tail;
+	data[i++] = LMI_CALLREF;
+	data[i++] = hdlc->state.fr.settings.dce
+		? LMI_STATUS : LMI_STATUS_ENQUIRY;
+	if (hdlc->state.fr.settings.lmi == LMI_ANSI)
+		data[i++] = LMI_ANSI_LOCKSHIFT;
+	data[i++] = (hdlc->state.fr.settings.lmi == LMI_CCITT)
+		? LMI_CCITT_REPTYPE : LMI_REPTYPE;
+	data[i++] = LMI_REPT_LEN;
+	data[i++] = fullrep ? LMI_FULLREP : LMI_INTEGRITY;
+
+	data[i++] = (hdlc->state.fr.settings.lmi == LMI_CCITT)
+		? LMI_CCITT_ALIVE : LMI_ALIVE;
+	data[i++] = LMI_INTEG_LEN;
+	data[i++] = hdlc->state.fr.txseq =fr_lmi_nextseq(hdlc->state.fr.txseq);
+	data[i++] = hdlc->state.fr.rxseq;
+
+	if (hdlc->state.fr.settings.dce && fullrep) {
+		while (pvc) {
+			data[i++] = (hdlc->state.fr.settings.lmi == LMI_CCITT)
+				? LMI_CCITT_PVCSTAT : LMI_PVCSTAT;
+			data[i++] = stat_len;
+
+			if (hdlc->state.fr.reliable &&
+			    (pvc->netdev.flags & IFF_UP) &&
+			    !pvc->state.active &&
+			    !pvc->state.new) {
+				pvc->state.new = 1;
+				fr_log_dlci_active(pvc);
+			}
+
+			dlci_to_status(hdlc, netdev_dlci(&pvc->netdev),
+				       data + i,
+				       pvc->state.active, pvc->state.new);
+			i += stat_len;
+			pvc = pvc->next;
+		}
+	}
+
+	skb_put(skb, i);
+	skb->priority = TC_PRIO_CONTROL;
+	skb->dev = hdlc_to_dev(hdlc);
+
+	dev_queue_xmit(skb);
+}
+
+
+
+static void fr_timer(unsigned long arg)
+{
+	hdlc_device *hdlc = (hdlc_device*)arg;
+	int i, cnt = 0, reliable;
+	u32 list;
+
+	if (hdlc->state.fr.settings.dce)
+		reliable = (jiffies - hdlc->state.fr.last_poll <
+			    hdlc->state.fr.settings.t392 * HZ);
+	else {
+		hdlc->state.fr.last_errors <<= 1; /* Shift the list */
+		if (hdlc->state.fr.request) {
+			if (hdlc->state.fr.reliable)
+				printk(KERN_INFO "%s: No LMI status reply "
+				       "received\n", hdlc_to_name(hdlc));
+			hdlc->state.fr.last_errors |= 1;
+		}
+
+		list = hdlc->state.fr.last_errors;
+		for (i = 0; i < hdlc->state.fr.settings.n393; i++, list >>= 1)
+			cnt += (list & 1);	/* errors count */
+
+		reliable = (cnt < hdlc->state.fr.settings.n392);
+	}
+
+	if (hdlc->state.fr.reliable != reliable) {
+		pvc_device *pvc = hdlc->state.fr.first_pvc;
+
+		hdlc->state.fr.reliable = reliable;
+		printk(KERN_INFO "%s: Link %sreliable\n", hdlc_to_name(hdlc),
+		       reliable ? "" : "un");
+
+		if (reliable) {
+			hdlc->state.fr.n391cnt = 0; /* Request full status */
+			hdlc->state.fr.changed = 1;
+		} else {
+			while (pvc) {	/* Deactivate all PVCs */
+				pvc->state.new = pvc->state.active = 0;
+				pvc = pvc->next;
+			}
+		}
+	}
+
+	if (hdlc->state.fr.settings.dce)
+		hdlc->state.fr.timer.expires = jiffies +
+			hdlc->state.fr.settings.t392 * HZ;
+	else {
+		if (hdlc->state.fr.n391cnt)
+			hdlc->state.fr.n391cnt--;
+
+		fr_lmi_send(hdlc, hdlc->state.fr.n391cnt == 0);
+
+		hdlc->state.fr.request = 1;
+		hdlc->state.fr.timer.expires = jiffies +
+			hdlc->state.fr.settings.t391 * HZ;
+	}
+
+	hdlc->state.fr.timer.function = fr_timer;
+	hdlc->state.fr.timer.data = arg;
+	add_timer(&hdlc->state.fr.timer);
+}
+
+
+
+static int fr_lmi_recv(hdlc_device *hdlc, struct sk_buff *skb)
+{
+	int stat_len;
+	pvc_device *pvc;
+	int reptype = -1, error;
+	u8 rxseq, txseq;
+	int i;
+
+	if (skb->len < ((hdlc->state.fr.settings.lmi == LMI_ANSI)
+			? LMI_ANSI_LENGTH : LMI_LENGTH)) {
+		printk(KERN_INFO "%s: Short LMI frame\n", hdlc_to_name(hdlc));
+		return 1;
+	}
+
+	if (skb->data[5] != (!hdlc->state.fr.settings.dce ?
+			     LMI_STATUS : LMI_STATUS_ENQUIRY)) {
+		printk(KERN_INFO "%s: LMI msgtype=%x, Not LMI status %s\n",
+		       hdlc_to_name(hdlc), skb->data[2],
+		       hdlc->state.fr.settings.dce ? "enquiry" : "reply");
+		return 1;
+	}
+
+	i = (hdlc->state.fr.settings.lmi == LMI_ANSI) ? 7 : 6;
+
+	if (skb->data[i] !=
+	    ((hdlc->state.fr.settings.lmi == LMI_CCITT)
+	     ? LMI_CCITT_REPTYPE : LMI_REPTYPE)) {
+		printk(KERN_INFO "%s: Not a report type=%x\n",
+		       hdlc_to_name(hdlc), skb->data[i]);
+		return 1;
+	}
+	i++;
+
+	i++;				/* Skip length field */
+
+	reptype = skb->data[i++];
+
+	if (skb->data[i]!=
+	    ((hdlc->state.fr.settings.lmi == LMI_CCITT)
+	     ? LMI_CCITT_ALIVE : LMI_ALIVE)) {
+		printk(KERN_INFO "%s: Unsupported status element=%x\n",
+		       hdlc_to_name(hdlc), skb->data[i]);
+		return 1;
+	}
+	i++;
+
+	i++;			/* Skip length field */
+
+	hdlc->state.fr.rxseq = skb->data[i++]; /* TX sequence from peer */
+	rxseq = skb->data[i++];	/* Should confirm our sequence */
+
+	txseq = hdlc->state.fr.txseq;
+
+	if (hdlc->state.fr.settings.dce) {
+		if (reptype != LMI_FULLREP && reptype != LMI_INTEGRITY) {
+			printk(KERN_INFO "%s: Unsupported report type=%x\n",
+			       hdlc_to_name(hdlc), reptype);
+			return 1;
+		}
+	}
+
+	error = 0;
+	if (!hdlc->state.fr.reliable)
+		error = 1;
+
+	if (rxseq == 0 || rxseq != txseq) {
+		hdlc->state.fr.n391cnt = 0; /* Ask for full report next time */
+		error = 1;
+	}
+
+	if (hdlc->state.fr.settings.dce) {
+		if (hdlc->state.fr.fullrep_sent && !error) {
+/* Stop sending full report - the last one has been confirmed by DTE */
+			hdlc->state.fr.fullrep_sent = 0;
+			pvc = hdlc->state.fr.first_pvc;
+			while (pvc) {
+				if (pvc->state.new) {
+					pvc->state.new = 0;
+					pvc->state.active = 1;
+					fr_log_dlci_active(pvc);
+
+/* Tell DTE that new PVC is now active */
+					hdlc->state.fr.changed = 1;
+				}
+				pvc = pvc->next;
+			}
+		}
+
+		if (hdlc->state.fr.changed) {
+			reptype = LMI_FULLREP;
+			hdlc->state.fr.fullrep_sent = 1;
+			hdlc->state.fr.changed = 0;
+		}
+
+		fr_lmi_send(hdlc, reptype == LMI_FULLREP ? 1 : 0);
+		return 0;
+	}
+
+	/* DTE */
+
+	if (reptype != LMI_FULLREP || error)
+		return 0;
+
+	stat_len = 3;
+	pvc = hdlc->state.fr.first_pvc;
+
+	while (pvc) {
+		pvc->state.deleted = pvc->state.active; /* mark active PVCs */
+		pvc = pvc->next;
+	}
+
+	while (skb->len >= i + 2 + stat_len) {
+		u16 dlci;
+		int active, new;
+
+		if (skb->data[i] != ((hdlc->state.fr.settings.lmi == LMI_CCITT)
+				     ? LMI_CCITT_PVCSTAT : LMI_PVCSTAT)) {
+			printk(KERN_WARNING "%s: Invalid PVCSTAT ID: %x\n",
+			       hdlc_to_name(hdlc), skb->data[i]);
+			return 1;
+		}
+		i++;
+
+		if (skb->data[i] != stat_len) {
+			printk(KERN_WARNING "%s: Invalid PVCSTAT length: %x\n",
+			       hdlc_to_name(hdlc), skb->data[i]);
+			return 1;
+		}
+		i++;
+
+		dlci = status_to_dlci(hdlc, skb->data + i, &active, &new);
+		pvc = find_pvc(hdlc, dlci);
+
+		active |= new;
+		if (pvc) {
+			if (active && !pvc->state.active &&
+			    (pvc->netdev.flags & IFF_UP)) {
+				pvc->state.active = active;
+				fr_log_dlci_active(pvc);
+			}
+			pvc->state.deleted = 0;
+		}
+		else if (new)
+			printk(KERN_INFO "%s: new PVC available, DLCI=%u\n",
+			       hdlc_to_name(hdlc), dlci);
+
+		i += stat_len;
+	}
+
+	pvc = hdlc->state.fr.first_pvc;
+
+	while (pvc) {
+		if (pvc->state.deleted) {
+			pvc->state.active = pvc->state.new = 0;
+			fr_log_dlci_active(pvc);
+			pvc->state.deleted = 0;
+		}
+		pvc = pvc->next;
+	}
+
+	/* Next full report after N391 polls */
+	hdlc->state.fr.n391cnt = hdlc->state.fr.settings.n391;
+
+	return 0;
+}
+
+
+
+static void fr_rx(struct sk_buff *skb)
+{
+	hdlc_device *hdlc = dev_to_hdlc(skb->dev);
+	fr_hdr *fh = (fr_hdr*)skb->data;
+	u8 *data = skb->data;
+	u16 dlci;
+	pvc_device *pvc;
+
+	if (skb->len<4 || fh->ea1 || data[2] != FR_UI)
+		goto rx_error;
+
+	dlci = q922_to_dlci(skb->data);
+
+	if (dlci == LMI_DLCI) {
+		if (hdlc->state.fr.settings.lmi == LMI_NONE)
+			goto rx_error; /* LMI packet with no LMI? */
+
+		if (data[3] == LMI_PROTO) {
+			if (fr_lmi_recv(hdlc, skb))
+				goto rx_error;
+			else {
+				/* No request pending */
+				hdlc->state.fr.request = 0;
+				hdlc->state.fr.last_poll = jiffies;
+				dev_kfree_skb_any(skb);
+				return;
+			}
+		}
+
+		printk(KERN_INFO "%s: Received non-LMI frame with LMI DLCI\n",
+		       hdlc_to_name(hdlc));
+		goto rx_error;
+	}
+
+	pvc = find_pvc(hdlc, dlci);
+	if (!pvc) {
+#ifdef CONFIG_HDLC_DEBUG_PKT
+		printk(KERN_INFO "%s: No PVC for received frame's DLCI %d\n",
+		       hdlc_to_name(hdlc), dlci);
+#endif
+		goto rx_error;
+	}
+
+	if ((pvc->netdev.flags & IFF_UP) == 0) {
+#ifdef CONFIG_HDLC_DEBUG_PKT
+		printk(KERN_INFO "%s: PVC for received frame's DLCI %d is down\n",
+		       hdlc_to_name(hdlc), dlci);
+#endif
+		goto rx_error;
+	}
+
+	pvc->stats.rx_packets++; /* PVC traffic */
+	pvc->stats.rx_bytes += skb->len;
+
+	if (pvc->state.fecn != (fh->fecn ? PVC_STATE_FECN : 0)) {
+#ifdef CONFIG_HDLC_DEBUG_ECN
+		printk(KERN_DEBUG "%s: FECN O%s\n", pvc_to_name(pvc),
+		       fh->fecn ? "N" : "FF");
+#endif
+		pvc->state.fecn ^= 1;
+	}
+
+	if (pvc->state.becn != (fh->becn ? PVC_STATE_BECN : 0)) {
+#ifdef CONFIG_HDLC_DEBUG_ECN
+		printk(KERN_DEBUG "%s: BECN O%s\n", pvc_to_name(pvc),
+		       fh->becn ? "N" : "FF");
+#endif
+		pvc->state.becn ^= 1;
+	}
+
+	if (pvc->state.becn)
+		pvc->stats.rx_compressed++;
+
+	skb->dev = &pvc->netdev;
+
+	if (data[3] == NLPID_IP) {
+		skb_pull(skb, 4); /* Remove 4-byte header (hdr, UI, NLPID) */
+		skb->protocol = htons(ETH_P_IP);
+		netif_rx(skb);
+		return;
+	}
+
+
+	if (data[3] == NLPID_IPV6) {
+		skb_pull(skb, 4); /* Remove 4-byte header (hdr, UI, NLPID) */
+		skb->protocol = htons(ETH_P_IPV6);
+		netif_rx(skb);
+		return;
+	}
+
+	if (data[3] == FR_PAD && data[4] == NLPID_SNAP && data[5] == FR_PAD) {
+		u16 oui = ntohs(*(u16*)(data + 6));
+		u16 pid = ntohs(*(u16*)(data + 8));
+		skb_pull(skb, 10);
+
+		switch ((((u32)oui) << 16) | pid) {
+		case ETH_P_ARP: /* routed frame with SNAP */
+		case ETH_P_IPX:
+		case ETH_P_IP:	/* a long variant */
+		case ETH_P_IPV6:
+			skb->protocol = htons(pid);
+			break;
+
+		default:
+			printk(KERN_INFO "%s: Unsupported protocol, OUI=%x "
+			       "PID=%x\n", hdlc_to_name(hdlc), oui, pid);
+			dev_kfree_skb_any(skb);
+			return;
+		}
+
+		netif_rx(skb);
+		return;
+	}
+
+	printk(KERN_INFO "%s: Unsupported protocol, NLPID=%x\n",
+	       hdlc_to_name(hdlc), data[3]);
+	dev_kfree_skb_any(skb);
+	return;
+
+ rx_error:
+	hdlc->stats.rx_errors++; /* Mark error */
+	dev_kfree_skb_any(skb);
+}
+
+
+
+static int fr_open(hdlc_device *hdlc)
+{
+	if (hdlc->state.fr.settings.lmi != LMI_NONE) {
+		hdlc->state.fr.last_poll = 0;
+		hdlc->state.fr.reliable = 0;
+		hdlc->state.fr.changed = 1;
+		hdlc->state.fr.request = 0;
+		hdlc->state.fr.fullrep_sent = 0;
+		hdlc->state.fr.last_errors = 0xFFFFFFFF;
+		hdlc->state.fr.n391cnt = 0;
+		hdlc->state.fr.txseq = hdlc->state.fr.rxseq = 0;
+
+		init_timer(&hdlc->state.fr.timer);
+		/* First poll after 1 s */
+		hdlc->state.fr.timer.expires = jiffies + HZ;
+		hdlc->state.fr.timer.function = fr_timer;
+		hdlc->state.fr.timer.data = (unsigned long)hdlc;
+		add_timer(&hdlc->state.fr.timer);
+	} else
+		hdlc->state.fr.reliable = 1;
+
+	return 0;
+}
+
+
+
+static void fr_close(hdlc_device *hdlc)
+{
+	pvc_device *pvc = hdlc->state.fr.first_pvc;
+
+	if (hdlc->state.fr.settings.lmi != LMI_NONE)
+		del_timer_sync(&hdlc->state.fr.timer);
+
+	while(pvc) {
+		dev_close(&pvc->netdev); /* Shutdown all PVCs for this FRAD */
+		pvc = pvc->next;
+	}
+}
+
+
+
+static int fr_pvc(hdlc_device *hdlc, unsigned int dlci, int create)
+{
+	pvc_device **pvc_p = &hdlc->state.fr.first_pvc;
+	pvc_device *pvc;
+	int result;
+
+	if(dlci <= 0 || dlci >= 1024)
+		return -EINVAL;	/* Only 10 bits for DLCI, DLCI 0 reserved */
+
+	while(*pvc_p) {
+		if (netdev_dlci(&(*pvc_p)->netdev) == dlci)
+			break;
+		pvc_p = &(*pvc_p)->next;
+	}
+
+	if (create) {		/* Create PVC */
+		if (*pvc_p != NULL)
+			return -EEXIST;
+
+		pvc = *pvc_p = kmalloc(sizeof(pvc_device), GFP_KERNEL);
+		if (!pvc) {
+			printk(KERN_WARNING "%s: Memory squeeze on fr_pvc()\n",
+			       hdlc_to_name(hdlc));
+			return -ENOBUFS;
+		}
+		memset(pvc, 0, sizeof(pvc_device));
+
+		pvc->netdev.hard_start_xmit = pvc_xmit;
+		pvc->netdev.get_stats = pvc_get_stats;
+		pvc->netdev.open = pvc_open;
+		pvc->netdev.stop = pvc_close;
+		pvc->netdev.change_mtu = pvc_change_mtu;
+		pvc->netdev.mtu = HDLC_MAX_MTU;
+
+		pvc->netdev.type = ARPHRD_DLCI;
+		pvc->netdev.hard_header_len = 16;
+		pvc->netdev.hard_header = fr_hard_header;
+		pvc->netdev.tx_queue_len = 0;
+		pvc->netdev.flags = IFF_POINTOPOINT;
+
+		pvc->master = hdlc;
+		*(u16*)pvc->netdev.dev_addr = htons(dlci);
+		dlci_to_q922(pvc->netdev.broadcast, dlci);
+		pvc->netdev.addr_len = 2;
+
+		result = dev_alloc_name(&pvc->netdev, "pvc%d");
+		if (result < 0) {
+			kfree(pvc);
+			*pvc_p = NULL;
+			return result;
+		}
+
+		if (register_netdevice(&pvc->netdev) != 0) {
+			kfree(pvc);
+			*pvc_p = NULL;
+			return -EIO;
+		}
+
+		hdlc->state.fr.changed = 1;
+		hdlc->state.fr.pvc_count++;
+		return 0;
+	}
+
+	if (*pvc_p == NULL)		/* Delete PVC */
+		return -ENOENT;
+
+	pvc = *pvc_p;
+
+	if (pvc->netdev.flags & IFF_UP)
+		return -EBUSY;		/* PVC in use */
+
+	hdlc->state.fr.changed = 1;
+	hdlc->state.fr.pvc_count--;
+	*pvc_p = pvc->next;
+	unregister_netdevice(&pvc->netdev);
+	kfree(pvc);
+	return 0;
+}
+
+
+
+static void fr_destroy(hdlc_device *hdlc)
+{
+	pvc_device *pvc = hdlc->state.fr.first_pvc;
+	while(pvc) {
+		pvc_device *next = pvc->next;
+		unregister_netdev(&pvc->netdev);
+		kfree(pvc);
+		pvc = next;
+	}
+
+	hdlc->state.fr.first_pvc = NULL; /* All PVCs destroyed */
+	hdlc->state.fr.pvc_count = 0;
+	hdlc->state.fr.changed = 1;
+}
+
+
+
+int hdlc_fr_ioctl(hdlc_device *hdlc, struct ifreq *ifr)
+{
+	fr_proto *fr_s = ifr->ifr_settings.ifs_ifsu.fr;
+	const size_t size = sizeof(fr_proto);
+	fr_proto new_settings;
+	struct net_device *dev = hdlc_to_dev(hdlc);
+	fr_proto_pvc pvc;
+	int result;
+
+	switch (ifr->ifr_settings.type) {
+	case IF_GET_PROTO:
+		ifr->ifr_settings.type = IF_PROTO_FR;
+		if (ifr->ifr_settings.size < size) {
+			ifr->ifr_settings.size = size; /* data size wanted */
+			return -ENOBUFS;
+		}
+		if (copy_to_user(fr_s, &hdlc->state.fr.settings, size))
+			return -EFAULT;
+		return 0;
+
+	case IF_PROTO_FR:
+		if(!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
+		if(dev->flags & IFF_UP)
+			return -EBUSY;
+
+		if (copy_from_user(&new_settings, fr_s, size))
+			return -EFAULT;
+
+		if (new_settings.lmi == LMI_DEFAULT)
+			new_settings.lmi = LMI_ANSI;
+
+		if ((new_settings.lmi != LMI_NONE &&
+		     new_settings.lmi != LMI_ANSI &&
+		     new_settings.lmi != LMI_CCITT) ||
+		    new_settings.t391 < 1 ||
+		    new_settings.t392 < 2 ||
+		    new_settings.n391 < 1 ||
+		    new_settings.n392 < 1 ||
+		    new_settings.n393 < new_settings.n392 ||
+		    new_settings.n393 > 32 ||
+		    (new_settings.dce != 0 &&
+		     new_settings.dce != 1))
+			return -EINVAL;
+
+		result=hdlc->attach(hdlc, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
+		if (result)
+			return result;
+
+		if (hdlc->proto != IF_PROTO_FR) {
+			hdlc_proto_detach(hdlc);
+			hdlc->state.fr.first_pvc = NULL;
+			hdlc->state.fr.pvc_count = 0;
+		}
+		memcpy(&hdlc->state.fr.settings, &new_settings, size);
+
+		hdlc->open = fr_open;
+		hdlc->stop = fr_close;
+		hdlc->netif_rx = fr_rx;
+		hdlc->proto_detach = fr_destroy;
+		hdlc->proto = IF_PROTO_FR;
+		dev->hard_start_xmit = hdlc->xmit;
+		dev->hard_header = fr_hard_header;
+		dev->type = ARPHRD_FRAD;
+		dev->addr_len = 2;
+		*(u16*)dev->dev_addr = htons(LMI_DLCI);
+		dlci_to_q922(dev->broadcast, LMI_DLCI);
+		return 0;
+
+	case IF_PROTO_FR_ADD_PVC:
+	case IF_PROTO_FR_DEL_PVC:
+		if(!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
+		if (copy_from_user(&pvc, ifr->ifr_settings.ifs_ifsu.fr_pvc,
+				   sizeof(fr_proto_pvc)))
+			return -EFAULT;
+
+		return fr_pvc(hdlc, pvc.dlci,
+			      ifr->ifr_settings.type == IF_PROTO_FR_ADD_PVC);
+	}
+
+	return -EINVAL;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/wan/hdlc_generic.c linux-2.4.21-pre6/drivers/net/wan/hdlc_generic.c
--- linux-2.4.20/drivers/net/wan/hdlc_generic.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/wan/hdlc_generic.c	2003-03-26 23:49:20.000000000 +0000
@@ -0,0 +1,197 @@
+/*
+ * Generic HDLC support routines for Linux
+ *
+ * Copyright (C) 1999 - 2001 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * 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.
+ *
+ * Current status:
+ *    - this is work in progress
+ *    - not heavily tested on SMP
+ *    - currently supported:
+ *	* raw IP-in-HDLC
+ *	* Cisco HDLC
+ *	* Frame Relay with ANSI or CCITT LMI (both user and network side)
+ *	* PPP
+ *	* X.25
+ *
+ * Use sethdlc utility to set line parameters, protocol and PVCs
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/errno.h>
+#include <linux/if_arp.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/pkt_sched.h>
+#include <linux/inetdevice.h>
+#include <linux/lapb.h>
+#include <linux/rtnetlink.h>
+#include <linux/hdlc.h>
+
+
+static const char* version = "HDLC support module revision 1.11";
+
+
+static int hdlc_change_mtu(struct net_device *dev, int new_mtu)
+{
+	if ((new_mtu < 68) || (new_mtu > HDLC_MAX_MTU))
+		return -EINVAL;
+	dev->mtu = new_mtu;
+	return 0;
+}
+
+
+
+static struct net_device_stats *hdlc_get_stats(struct net_device *dev)
+{
+	return &dev_to_hdlc(dev)->stats;
+}
+
+
+
+static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev,
+		    struct packet_type *p)
+{
+	dev_to_hdlc(dev)->netif_rx(skb);
+	return 0;
+}
+
+
+#ifndef CONFIG_HDLC_RAW
+#define hdlc_raw_ioctl(hdlc, ifr)	-ENOSYS
+#endif
+
+#ifndef CONFIG_HDLC_PPP
+#define hdlc_ppp_ioctl(hdlc, ifr)	-ENOSYS
+#endif
+
+#ifndef CONFIG_HDLC_CISCO
+#define hdlc_cisco_ioctl(hdlc, ifr)	-ENOSYS
+#endif
+
+#ifndef CONFIG_HDLC_FR
+#define hdlc_fr_ioctl(hdlc, ifr)	-ENOSYS
+#endif
+
+#ifndef CONFIG_HDLC_X25
+#define hdlc_x25_ioctl(hdlc, ifr)	-ENOSYS
+#endif
+
+
+int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	hdlc_device *hdlc = dev_to_hdlc(dev);
+	unsigned int proto;
+
+	if (cmd != SIOCWANDEV)
+		return -EINVAL;
+
+	switch(ifr->ifr_settings.type) {
+	case IF_PROTO_HDLC:
+	case IF_PROTO_PPP:
+	case IF_PROTO_CISCO:
+	case IF_PROTO_FR:
+	case IF_PROTO_X25:
+		proto = ifr->ifr_settings.type;
+		break;
+
+	default:
+		proto = hdlc->proto;
+	}
+
+	switch(proto) {
+	case IF_PROTO_HDLC:	return hdlc_raw_ioctl(hdlc, ifr);
+	case IF_PROTO_PPP:	return hdlc_ppp_ioctl(hdlc, ifr);
+	case IF_PROTO_CISCO:	return hdlc_cisco_ioctl(hdlc, ifr);
+	case IF_PROTO_FR:	return hdlc_fr_ioctl(hdlc, ifr);
+	case IF_PROTO_X25:	return hdlc_x25_ioctl(hdlc, ifr);
+	default:		return -EINVAL;
+	}
+}
+
+
+
+int register_hdlc_device(hdlc_device *hdlc)
+{
+	int result;
+	struct net_device *dev = hdlc_to_dev(hdlc);
+
+	dev->get_stats = hdlc_get_stats;
+	dev->change_mtu = hdlc_change_mtu;
+	dev->mtu = HDLC_MAX_MTU;
+
+	dev->type = ARPHRD_RAWHDLC;
+	dev->hard_header_len = 16;
+
+	dev->flags = IFF_POINTOPOINT | IFF_NOARP;
+
+	hdlc->proto = -1;
+	hdlc->proto_detach = NULL;
+
+	result = dev_alloc_name(dev, "hdlc%d");
+	if (result<0)
+		return result;
+
+	result = register_netdev(dev);
+	if (result != 0)
+		return -EIO;
+
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+
+
+void unregister_hdlc_device(hdlc_device *hdlc)
+{
+	hdlc_proto_detach(hdlc);
+
+	unregister_netdev(hdlc_to_dev(hdlc));
+	MOD_DEC_USE_COUNT;
+}
+
+
+
+MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
+MODULE_DESCRIPTION("HDLC support module");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(hdlc_ioctl);
+EXPORT_SYMBOL(register_hdlc_device);
+EXPORT_SYMBOL(unregister_hdlc_device);
+
+struct packet_type hdlc_packet_type=
+{
+        __constant_htons(ETH_P_HDLC),
+        NULL,
+        hdlc_rcv,
+        NULL,
+        NULL
+};
+
+
+static int __init hdlc_module_init(void)
+{
+	printk(KERN_INFO "%s\n", version);
+        dev_add_pack(&hdlc_packet_type);
+	return 0;
+}
+
+
+
+static void __exit hdlc_module_exit(void)
+{
+	dev_remove_pack(&hdlc_packet_type);
+}
+
+
+module_init(hdlc_module_init);
+module_exit(hdlc_module_exit);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/wan/hdlc_ppp.c linux-2.4.21-pre6/drivers/net/wan/hdlc_ppp.c
--- linux-2.4.20/drivers/net/wan/hdlc_ppp.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/wan/hdlc_ppp.c	2003-03-26 23:49:08.000000000 +0000
@@ -0,0 +1,116 @@
+/*
+ * Generic HDLC support routines for Linux
+ * Point-to-point protocol support
+ *
+ * Copyright (C) 1999 - 2001 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * 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/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/errno.h>
+#include <linux/if_arp.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/pkt_sched.h>
+#include <linux/inetdevice.h>
+#include <linux/lapb.h>
+#include <linux/rtnetlink.h>
+#include <linux/hdlc.h>
+
+
+static int ppp_open(hdlc_device *hdlc)
+{
+	struct net_device *dev = hdlc_to_dev(hdlc);
+	void *old_ioctl;
+	int result;
+
+	dev->priv = &hdlc->state.ppp.syncppp_ptr;
+	hdlc->state.ppp.syncppp_ptr = &hdlc->state.ppp.pppdev;
+	hdlc->state.ppp.pppdev.dev = dev;
+
+	old_ioctl = dev->do_ioctl;
+	hdlc->state.ppp.old_change_mtu = dev->change_mtu;
+	sppp_attach(&hdlc->state.ppp.pppdev);
+	/* sppp_attach nukes them. We don't need syncppp's ioctl */
+	dev->do_ioctl = old_ioctl;
+	hdlc->state.ppp.pppdev.sppp.pp_flags &= ~PP_CISCO;
+	dev->type = ARPHRD_PPP;
+	result = sppp_open(dev);
+	if (result) {
+		sppp_detach(dev);
+		return result;
+	}
+
+	return 0;
+}
+
+
+
+static void ppp_close(hdlc_device *hdlc)
+{
+	struct net_device *dev = hdlc_to_dev(hdlc);
+
+	sppp_close(dev);
+	sppp_detach(dev);
+	dev->rebuild_header = NULL;
+	dev->change_mtu = hdlc->state.ppp.old_change_mtu;
+	dev->mtu = HDLC_MAX_MTU;
+	dev->hard_header_len = 16;
+}
+
+
+
+static void ppp_rx(struct sk_buff *skb)
+{
+	skb->protocol = htons(ETH_P_WAN_PPP);
+	netif_rx(skb);
+}
+
+
+
+int hdlc_ppp_ioctl(hdlc_device *hdlc, struct ifreq *ifr)
+{
+	struct net_device *dev = hdlc_to_dev(hdlc);
+	int result;
+
+	switch (ifr->ifr_settings.type) {
+	case IF_GET_PROTO:
+		ifr->ifr_settings.type = IF_PROTO_PPP;
+		return 0; /* return protocol only, no settable parameters */
+
+	case IF_PROTO_PPP:
+		if(!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
+		if(dev->flags & IFF_UP)
+			return -EBUSY;
+
+		/* no settable parameters */
+
+		result=hdlc->attach(hdlc, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
+		if (result)
+			return result;
+
+		hdlc_proto_detach(hdlc);
+
+		hdlc->open = ppp_open;
+		hdlc->stop = ppp_close;
+		hdlc->netif_rx = ppp_rx;
+		hdlc->proto = IF_PROTO_PPP;
+		dev->hard_start_xmit = hdlc->xmit;
+		dev->hard_header = NULL;
+		dev->type = ARPHRD_PPP;
+		dev->addr_len = 0;
+		return 0;
+	}
+
+	return -EINVAL;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/wan/hdlc_raw.c linux-2.4.21-pre6/drivers/net/wan/hdlc_raw.c
--- linux-2.4.20/drivers/net/wan/hdlc_raw.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/wan/hdlc_raw.c	2003-03-26 23:49:05.000000000 +0000
@@ -0,0 +1,92 @@
+/*
+ * Generic HDLC support routines for Linux
+ * HDLC support
+ *
+ * Copyright (C) 1999 - 2001 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * 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/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/errno.h>
+#include <linux/if_arp.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/pkt_sched.h>
+#include <linux/inetdevice.h>
+#include <linux/lapb.h>
+#include <linux/rtnetlink.h>
+#include <linux/hdlc.h>
+
+
+static void raw_rx(struct sk_buff *skb)
+{
+	skb->protocol = htons(ETH_P_IP);
+	netif_rx(skb);
+}
+
+
+
+int hdlc_raw_ioctl(hdlc_device *hdlc, struct ifreq *ifr)
+{
+	raw_hdlc_proto *raw_s = ifr->ifr_settings.ifs_ifsu.raw_hdlc;
+	const size_t size = sizeof(raw_hdlc_proto);
+	raw_hdlc_proto new_settings;
+	struct net_device *dev = hdlc_to_dev(hdlc);
+	int result;
+
+	switch (ifr->ifr_settings.type) {
+	case IF_GET_PROTO:
+		ifr->ifr_settings.type = IF_PROTO_HDLC;
+		if (ifr->ifr_settings.size < size) {
+			ifr->ifr_settings.size = size; /* data size wanted */
+			return -ENOBUFS;
+		}
+		if (copy_to_user(raw_s, &hdlc->state.raw_hdlc.settings, size))
+			return -EFAULT;
+		return 0;
+
+	case IF_PROTO_HDLC:
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
+		if (dev->flags & IFF_UP)
+			return -EBUSY;
+
+		if (copy_from_user(&new_settings, raw_s, size))
+			return -EFAULT;
+
+		if (new_settings.encoding == ENCODING_DEFAULT)
+			new_settings.encoding = ENCODING_NRZ;
+
+		if (new_settings.parity == PARITY_DEFAULT)
+			new_settings.parity = PARITY_NONE;
+
+		result = hdlc->attach(hdlc, new_settings.encoding,
+				      new_settings.parity);
+		if (result)
+			return result;
+
+		hdlc_proto_detach(hdlc);
+		memcpy(&hdlc->state.raw_hdlc.settings, &new_settings, size);
+
+		hdlc->open = NULL;
+		hdlc->stop = NULL;
+		hdlc->netif_rx = raw_rx;
+		hdlc->proto = IF_PROTO_HDLC;
+		dev->hard_start_xmit = hdlc->xmit;
+		dev->hard_header = NULL;
+		dev->type = ARPHRD_RAWHDLC;
+		dev->addr_len = 0;
+		return 0;
+	}
+
+	return -EINVAL;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/wan/hdlc_x25.c linux-2.4.21-pre6/drivers/net/wan/hdlc_x25.c
--- linux-2.4.20/drivers/net/wan/hdlc_x25.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/wan/hdlc_x25.c	2003-03-26 23:49:25.000000000 +0000
@@ -0,0 +1,216 @@
+/*
+ * Generic HDLC support routines for Linux
+ * X.25 support
+ *
+ * Copyright (C) 1999 - 2001 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * 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/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/errno.h>
+#include <linux/if_arp.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/pkt_sched.h>
+#include <linux/inetdevice.h>
+#include <linux/lapb.h>
+#include <linux/rtnetlink.h>
+#include <linux/hdlc.h>
+
+/* These functions are callbacks called by LAPB layer */
+
+static void x25_connect_disconnect(void *token, int reason, int code)
+{
+	hdlc_device *hdlc = token;
+	struct sk_buff *skb;
+	unsigned char *ptr;
+
+	if ((skb = dev_alloc_skb(1)) == NULL) {
+		printk(KERN_ERR "%s: out of memory\n", hdlc_to_name(hdlc));
+		return;
+	}
+
+	ptr = skb_put(skb, 1);
+	*ptr = code;
+
+	skb->dev = hdlc_to_dev(hdlc);
+	skb->protocol = htons(ETH_P_X25);
+	skb->mac.raw = skb->data;
+	skb->pkt_type = PACKET_HOST;
+
+	netif_rx(skb);
+}
+
+
+
+static void x25_connected(void *token, int reason)
+{
+	x25_connect_disconnect(token, reason, 1);
+}
+
+
+
+static void x25_disconnected(void *token, int reason)
+{
+	x25_connect_disconnect(token, reason, 2);
+}
+
+
+
+static int x25_data_indication(void *token, struct sk_buff *skb)
+{
+	hdlc_device *hdlc = token;
+	unsigned char *ptr;
+
+	ptr = skb_push(skb, 1);
+	*ptr = 0;
+
+	skb->dev = hdlc_to_dev(hdlc);
+	skb->protocol = htons(ETH_P_X25);
+	skb->mac.raw = skb->data;
+	skb->pkt_type = PACKET_HOST;
+
+	return netif_rx(skb);
+}
+
+
+
+static void x25_data_transmit(void *token, struct sk_buff *skb)
+{
+	hdlc_device *hdlc = token;
+	hdlc->xmit(skb, hdlc_to_dev(hdlc)); /* Ignore return value :-( */
+}
+
+
+
+static int x25_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	hdlc_device *hdlc = dev_to_hdlc(dev);
+	int result;
+
+
+	/* X.25 to LAPB */
+	switch (skb->data[0]) {
+	case 0:		/* Data to be transmitted */
+		skb_pull(skb, 1);
+		if ((result = lapb_data_request(hdlc, skb)) != LAPB_OK)
+			dev_kfree_skb(skb);
+		return 0;
+
+	case 1:
+		if ((result = lapb_connect_request(hdlc))!= LAPB_OK) {
+			if (result == LAPB_CONNECTED)
+				/* Send connect confirm. msg to level 3 */
+				x25_connected(hdlc, 0);
+			else
+				printk(KERN_ERR "%s: LAPB connect request "
+				       "failed, error code = %i\n",
+				       hdlc_to_name(hdlc), result);
+		}
+		break;
+
+	case 2:
+		if ((result = lapb_disconnect_request(hdlc)) != LAPB_OK) {
+			if (result == LAPB_NOTCONNECTED)
+				/* Send disconnect confirm. msg to level 3 */
+				x25_disconnected(hdlc, 0);
+			else
+				printk(KERN_ERR "%s: LAPB disconnect request "
+				       "failed, error code = %i\n",
+				       hdlc_to_name(hdlc), result);
+		}
+		break;
+
+	default:		/* to be defined */
+		break;
+	}
+
+	dev_kfree_skb(skb);
+	return 0;
+}
+
+
+
+static int x25_open(hdlc_device *hdlc)
+{
+	struct lapb_register_struct cb;
+	int result;
+
+	cb.connect_confirmation = x25_connected;
+	cb.connect_indication = x25_connected;
+	cb.disconnect_confirmation = x25_disconnected;
+	cb.disconnect_indication = x25_disconnected;
+	cb.data_indication = x25_data_indication;
+	cb.data_transmit = x25_data_transmit;
+
+	result = lapb_register(hdlc, &cb);
+	if (result != LAPB_OK)
+		return result;
+	return 0;
+}
+
+
+
+static void x25_close(hdlc_device *hdlc)
+{
+	lapb_unregister(hdlc);
+}
+
+
+
+static void x25_rx(struct sk_buff *skb)
+{
+	hdlc_device *hdlc = dev_to_hdlc(skb->dev);
+
+	if (lapb_data_received(hdlc, skb) == LAPB_OK)
+		return;
+	hdlc->stats.rx_errors++;
+	dev_kfree_skb_any(skb);
+}
+
+
+
+int hdlc_x25_ioctl(hdlc_device *hdlc, struct ifreq *ifr)
+{
+	struct net_device *dev = hdlc_to_dev(hdlc);
+	int result;
+
+	switch (ifr->ifr_settings.type) {
+	case IF_GET_PROTO:
+		ifr->ifr_settings.type = IF_PROTO_X25;
+		return 0; /* return protocol only, no settable parameters */
+
+	case IF_PROTO_X25:
+		if(!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
+		if(dev->flags & IFF_UP)
+			return -EBUSY;
+
+		result=hdlc->attach(hdlc, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
+		if (result)
+			return result;
+
+		hdlc_proto_detach(hdlc);
+
+		hdlc->open = x25_open;
+		hdlc->stop = x25_close;
+		hdlc->netif_rx = x25_rx;
+		hdlc->proto = IF_PROTO_X25;
+		dev->hard_start_xmit = x25_xmit;
+		dev->hard_header = NULL;
+		dev->type = ARPHRD_X25;
+		dev->addr_len = 0;
+		return 0;
+	}
+
+	return -EINVAL;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/wan/n2.c linux-2.4.21-pre6/drivers/net/wan/n2.c
--- linux-2.4.20/drivers/net/wan/n2.c	2001-09-13 23:04:43.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/wan/n2.c	2003-03-26 23:49:18.000000000 +0000
@@ -1,7 +1,7 @@
 /*
  * SDL Inc. RISCom/N2 synchronous serial card driver for Linux
  *
- * Copyright (C) 1998-2000 Krzysztof Halasa <khc@pm.waw.pl>
+ * Copyright (C) 1998-2002 Krzysztof Halasa <khc@pm.waw.pl>
  *
  * 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
@@ -17,10 +17,10 @@
  *    SDL Inc. PPP/HDLC/CISCO driver
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
-#include <linux/sched.h>
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/in.h>
@@ -33,10 +33,8 @@
 #include <asm/io.h>
 #include "hd64570.h"
 
-#define DEBUG_RINGS
-/* #define DEBUG_PKT */
 
-static const char* version = "SDL RISCom/N2 driver revision: 1.02 for Linux 2.4";
+static const char* version = "SDL RISCom/N2 driver version: 1.10";
 static const char* devname = "RISCom/N2";
 
 #define USE_WINDOWSIZE 16384
@@ -87,9 +85,9 @@
 	hdlc_device hdlc;	/* HDLC device struct - must be first */
 	struct card_s *card;
 	spinlock_t lock;	/* TX lock */
-	int clkmode;		/* clock mode */
-	int clkrate;		/* clock rate */
-	int line;		/* loopback only */
+	sync_serial_settings settings;
+	unsigned short encoding;
+	unsigned short parity;
 	u8 rxs, txs, tmc;	/* SCA registers */
 	u8 valid;		/* port enabled */
 	u8 phy_node;		/* physical port # - 0 or 1 */
@@ -116,6 +114,9 @@
 }card_t;
 
 
+static card_t *first_card;
+static card_t **new_card = &first_card;
+
 
 #define sca_reg(reg, card) (0x8000 | (card)->io | \
 			    ((reg) & 0x0F) | (((reg) & 0xF0) << 6))
@@ -157,7 +158,7 @@
 
 
 
-static int n2_set_clock(port_t *port, int value)
+static void n2_set_iface(port_t *port)
 {
 	card_t *card = port->card;
 	int io = card->io;
@@ -166,13 +167,7 @@
 	u8 rxs = port->rxs & CLK_BRG_MASK;
 	u8 txs = port->txs & CLK_BRG_MASK;
 
-	switch(value) {
-	case CLOCK_EXT:
-		mcr &= port->phy_node ? ~CLOCK_OUT_PORT1 : ~CLOCK_OUT_PORT0;
-		rxs |= CLK_LINE_RX; /* RXC input */
-		txs |= CLK_LINE_TX; /* TXC input */
-		break;
-
+	switch(port->settings.clock_type) {
 	case CLOCK_INT:
 		mcr |= port->phy_node ? CLOCK_OUT_PORT1 : CLOCK_OUT_PORT0;
 		rxs |= CLK_BRG_RX; /* BRG output */
@@ -191,8 +186,10 @@
 		txs |= CLK_RXCLK_TX; /* RX clock */
 		break;
 
-	default:
-		return -EINVAL;
+	default:		/* Clock EXTernal */
+		mcr &= port->phy_node ? ~CLOCK_OUT_PORT1 : ~CLOCK_OUT_PORT0;
+		rxs |= CLK_LINE_RX; /* RXC input */
+		txs |= CLK_LINE_TX; /* TXC input */
 	}
 
 	outb(mcr, io + N2_MCR);
@@ -200,17 +197,21 @@
 	port->txs = txs;
 	sca_out(rxs, msci + RXS, card);
 	sca_out(txs, msci + TXS, card);
-	port->clkmode = value;
-	return 0;
+	sca_set_port(port);
 }
 
 
 
-static int n2_open(hdlc_device *hdlc)
+static int n2_open(struct net_device *dev)
 {
+	hdlc_device *hdlc = dev_to_hdlc(dev);
 	port_t *port = hdlc_to_port(hdlc);
 	int io = port->card->io;
-	u8 mcr = inb(io + N2_MCR) | (port->phy_node ? TX422_PORT1 : TX422_PORT0);
+	u8 mcr = inb(io + N2_MCR) | (port->phy_node ? TX422_PORT1:TX422_PORT0);
+
+	int result = hdlc_open(hdlc);
+	if (result)
+		return result;
 
 	MOD_INC_USE_COUNT;
 	mcr &= port->phy_node ? ~DTR_PORT1 : ~DTR_PORT0; /* set DTR ON */
@@ -219,14 +220,15 @@
 	outb(inb(io + N2_PCR) | PCR_ENWIN, io + N2_PCR); /* open window */
 	outb(inb(io + N2_PSR) | PSR_DMAEN, io + N2_PSR); /* enable dma */
 	sca_open(hdlc);
-	n2_set_clock(port, port->clkmode);
+	n2_set_iface(port);
 	return 0;
 }
 
 
 
-static void n2_close(hdlc_device *hdlc)
+static int n2_close(struct net_device *dev)
 {
+	hdlc_device *hdlc = dev_to_hdlc(dev);
 	port_t *port = hdlc_to_port(hdlc);
 	int io = port->card->io;
 	u8 mcr = inb(io+N2_MCR) | (port->phy_node ? TX422_PORT1 : TX422_PORT0);
@@ -234,52 +236,63 @@
 	sca_close(hdlc);
 	mcr |= port->phy_node ? DTR_PORT1 : DTR_PORT0; /* set DTR OFF */
 	outb(mcr, io + N2_MCR);
+	hdlc_close(hdlc);
 	MOD_DEC_USE_COUNT;
+	return 0;
 }
 
 
 
-static int n2_ioctl(hdlc_device *hdlc, struct ifreq *ifr, int cmd)
+static int n2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
-	int value = ifr->ifr_ifru.ifru_ivalue;
-	int result = 0;
+	const size_t size = sizeof(sync_serial_settings);
+	sync_serial_settings new_line, *line = ifr->ifr_settings.ifs_ifsu.sync;
+	hdlc_device *hdlc = dev_to_hdlc(dev);
 	port_t *port = hdlc_to_port(hdlc);
 
-	if(!capable(CAP_NET_ADMIN))
-		return -EPERM;
+#ifdef CONFIG_HDLC_DEBUG_RINGS
+	if (cmd == SIOCDEVPRIVATE) {
+		sca_dump_rings(hdlc);
+		return 0;
+	}
+#endif
+	if (cmd != SIOCWANDEV)
+		return hdlc_ioctl(dev, ifr, cmd);
 
-	switch(cmd) {
-	case HDLCSCLOCK:
-		result = n2_set_clock(port, value);
-	case HDLCGCLOCK:
-		value = port->clkmode;
-		break;
+	switch(ifr->ifr_settings.type) {
+	case IF_GET_IFACE:
+		ifr->ifr_settings.type = IF_IFACE_SYNC_SERIAL;
+		if (ifr->ifr_settings.size < size) {
+			ifr->ifr_settings.size = size; /* data size wanted */
+			return -ENOBUFS;
+		}
+		if (copy_to_user(line, &port->settings, size))
+			return -EFAULT;
+		return 0;
 
-	case HDLCSCLOCKRATE:
-		port->clkrate = value;
-		sca_set_clock(port);
-	case HDLCGCLOCKRATE:
-		value = port->clkrate;
-		break;
+	case IF_IFACE_SYNC_SERIAL:
+		if(!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
+		if (copy_from_user(&new_line, line, size))
+			return -EFAULT;
+
+		if (new_line.clock_type != CLOCK_EXT &&
+		    new_line.clock_type != CLOCK_TXFROMRX &&
+		    new_line.clock_type != CLOCK_INT &&
+		    new_line.clock_type != CLOCK_TXINT)
+		return -EINVAL;	/* No such clock setting */
 
-	case HDLCSLINE:
-		result = sca_set_loopback(port, value);
-	case HDLCGLINE:
-		value = port->line;
-		break;
+		if (new_line.loopback != 0 && new_line.loopback != 1)
+			return -EINVAL;
 
-#ifdef DEBUG_RINGS
-	case HDLCRUN:
-		sca_dump_rings(hdlc);
+		memcpy(&port->settings, &new_line, size); /* Update settings */
+		n2_set_iface(port);
 		return 0;
-#endif /* DEBUG_RINGS */
 
 	default:
-		return -EINVAL;
+		return hdlc_ioctl(dev, ifr, cmd);
 	}
-
-	ifr->ifr_ifru.ifru_ivalue = value;
-	return result;
 }
 
 
@@ -465,6 +478,7 @@
 	sca_init(card, 0);
 	for (cnt = 0; cnt < 2; cnt++) {
 		port_t *port = &card->ports[cnt];
+		struct net_device *dev = hdlc_to_dev(&port->hdlc);
 
 		if ((cnt == 0 && !valid0) || (cnt == 1 && !valid1))
 			continue;
@@ -476,14 +490,16 @@
 			port->log_node = 1;
 
 		spin_lock_init(&port->lock);
-		hdlc_to_dev(&port->hdlc)->irq = irq;
-		hdlc_to_dev(&port->hdlc)->mem_start = winbase;
-		hdlc_to_dev(&port->hdlc)->mem_end = winbase + USE_WINDOWSIZE-1;
-		hdlc_to_dev(&port->hdlc)->tx_queue_len = 50;
-		port->hdlc.ioctl = n2_ioctl;
-		port->hdlc.open = n2_open;
-		port->hdlc.close = n2_close;
+		dev->irq = irq;
+		dev->mem_start = winbase;
+		dev->mem_end = winbase + USE_WINDOWSIZE-1;
+		dev->tx_queue_len = 50;
+		dev->do_ioctl = n2_ioctl;
+		dev->open = n2_open;
+		dev->stop = n2_close;
+		port->hdlc.attach = sca_attach;
 		port->hdlc.xmit = sca_xmit;
+		port->settings.clock_type = CLOCK_EXT;
 
 		if (register_hdlc_device(&port->hdlc)) {
 			printk(KERN_WARNING "n2: unable to register hdlc "
@@ -515,7 +531,7 @@
 		return -ENOSYS;	/* no parameters specified, abort */
 	}
 
-	printk(KERN_INFO "%s\n", version);
+	printk(KERN_INFO "%s (SCA-%s)\n", version, sca_version);
 
 	do {
 		unsigned long io, irq, ram;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/wan/sdla_x25.c linux-2.4.21-pre6/drivers/net/wan/sdla_x25.c
--- linux-2.4.20/drivers/net/wan/sdla_x25.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/wan/sdla_x25.c	2003-03-26 23:49:08.000000000 +0000
@@ -4721,7 +4721,7 @@
 /*===============================================================
  * api_incoming_call 
  *
- *	Pass an incoming call request up the the listening
+ *	Pass an incoming call request up the listening
  *      sock.  If the API sock is not listening reject the
  *      call.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/wavelan.c linux-2.4.21-pre6/drivers/net/wavelan.c
--- linux-2.4.20/drivers/net/wavelan.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/wavelan.c	2003-03-26 23:49:27.000000000 +0000
@@ -2825,6 +2825,13 @@
 	       (unsigned) skb);
 #endif
 
+	if(skb->len < ETH_ZLEN)
+	{
+		skb = skb_padto(skb, ETH_ZLEN);
+		if(skb == NULL)
+			return 0;
+	}
+
 	/*
 	 * Block a timer-based transmit from overlapping.
 	 * In other words, prevent reentering this routine.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/wireless/airo.c linux-2.4.21-pre6/drivers/net/wireless/airo.c
--- linux-2.4.20/drivers/net/wireless/airo.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/wireless/airo.c	2003-03-26 23:49:07.000000000 +0000
@@ -4008,6 +4008,10 @@
 {
 	struct net_device *dev;
 
+	if (pci_enable_device(pdev))
+		return -ENODEV;
+	pci_set_master(pdev);
+
 	dev = init_airo_card(pdev->irq,	pdev->resource[2].start, 0);
 	if (!dev)
 		return -ENODEV;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/wireless/airport.c linux-2.4.21-pre6/drivers/net/wireless/airport.c
--- linux-2.4.20/drivers/net/wireless/airport.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/wireless/airport.c	2003-03-26 23:49:34.000000000 +0000
@@ -1,4 +1,4 @@
-/* airport.c 0.11b
+/* airport.c 0.13b
  *
  * A driver for "Hermes" chipset based Apple Airport wireless
  * card.
@@ -25,12 +25,10 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/system.h>
-#include <linux/proc_fs.h>
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/etherdevice.h>
 #include <linux/wireless.h>
-#include <linux/list.h>
 #include <linux/adb.h>
 #include <linux/pmu.h>
 
@@ -39,23 +37,15 @@
 #include <asm/pmac_feature.h>
 #include <asm/irq.h>
 
-#include "hermes.h"
 #include "orinoco.h"
 
-static char version[] __initdata = "airport.c 0.11b (Benjamin Herrenschmidt <benh@kernel.crashing.org>)";
-MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
-MODULE_DESCRIPTION("Driver for the Apple Airport wireless card.");
-MODULE_LICENSE("Dual MPL/GPL");
-EXPORT_NO_SYMBOLS;
-
 #define AIRPORT_IO_LEN	(0x1000)	/* one page */
 
 struct airport {
-	struct device_node* node;
+	struct device_node *node;
 	void *vaddr;
 	int irq_requested;
 	int ndev_registered;
-	int open;
 };
 
 #ifdef CONFIG_PMAC_PBOOK
@@ -71,109 +61,99 @@
 
 static struct net_device *airport_attach(struct device_node *of_node);
 static void airport_detach(struct net_device *dev);
-static int airport_open(struct net_device *dev);
-static int airport_stop(struct net_device *dev);
-
-/*
-   A linked list of "instances" of the dummy device.  Each actual
-   PCMCIA card corresponds to one device instance, and is described
-   by one dev_link_t structure (defined in ds.h).
-
-   You may not want to use a linked list for this -- for example, the
-   memory card driver uses an array of dev_link_t pointers, where minor
-   device numbers are used to derive the corresponding array index.
-*/
 
 static struct net_device *airport_dev;
 
-static int
-airport_open(struct net_device *dev)
-{
-	struct orinoco_private *priv = dev->priv;
-	struct airport* card = (struct airport *)priv->card;
-	int rc;
-
-	TRACE_ENTER(dev->name);
-
-	netif_device_attach(dev);
-
-	rc = orinoco_reset(priv);
-	if (rc)
-		airport_stop(dev);
-	else {
-		card->open = 1;
-		netif_start_queue(dev);
-	}
-
-	TRACE_EXIT(dev->name);
-
-	return rc;
-}
-
-static int
-airport_stop(struct net_device *dev)
-{
-	struct orinoco_private *priv = dev->priv;
-	struct airport* card = (struct airport *)priv->card;
-
-	TRACE_ENTER(dev->name);
-
-	netif_stop_queue(dev);
-	orinoco_shutdown(priv);
-	card->open = 0;
-
-	TRACE_EXIT(dev->name);
-
-	return 0;
-}
-
 #ifdef CONFIG_PMAC_PBOOK
 static int
 airport_sleep_notify(struct pmu_sleep_notifier *self, int when)
 {
 	struct net_device *dev = airport_dev;
-	struct orinoco_private *priv = (struct orinoco_private *)dev->priv;
-	struct hermes *hw = &priv->hw;
-	struct airport* card = (struct airport *)priv->card;
-	int rc;
+	struct orinoco_private *priv = dev->priv;
+	struct airport *card = priv->card;
+	unsigned long flags;
+	int err;
 	
 	if (! airport_dev)
 		return PBOOK_SLEEP_OK;
 
 	switch (when) {
-	case PBOOK_SLEEP_REQUEST:
-		break;
-	case PBOOK_SLEEP_REJECT:
-		break;
 	case PBOOK_SLEEP_NOW:
-		printk(KERN_INFO "%s: Airport entering sleep mode\n", dev->name);
-		if (card->open) {
-			netif_stop_queue(dev);
-			orinoco_shutdown(priv);
-			netif_device_detach(dev);
+		printk(KERN_DEBUG "%s: Airport entering sleep mode\n", dev->name);
+
+		err = orinoco_lock(priv, &flags);
+		if (err) {
+			printk(KERN_ERR "%s: hw_unavailable on PBOOK_SLEEP_NOW\n",
+			       dev->name);
+			break;
 		}
+
+		err = __orinoco_down(dev);
+		if (err)
+			printk(KERN_WARNING "%s: PBOOK_SLEEP_NOW: Error %d downing interface\n",
+			       dev->name, err);
+
+		netif_device_detach(dev);
+
+		priv->hw_unavailable = 1;
+
+		orinoco_unlock(priv, &flags);
+
 		disable_irq(dev->irq);
 		pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 0);
 		break;
+
 	case PBOOK_WAKE:
-		printk(KERN_INFO "%s: Airport waking up\n", dev->name);
+		printk(KERN_DEBUG "%s: Airport waking up\n", dev->name);
 		pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 1);
 		mdelay(200);
-		hermes_reset(hw);
-		rc = orinoco_reset(priv);
-		if (rc)
-			printk(KERN_ERR "airport: Error %d re-initing card !\n", rc);
-		else if (card->open)
-			netif_device_attach(dev);
+
 		enable_irq(dev->irq);
+
+		err = orinoco_reinit_firmware(dev);
+		if (err) {
+			printk(KERN_ERR "%s: Error %d re-initializing firmware on PBOOK_WAKE\n",
+			       dev->name, err);
+			break;
+		}
+
+		spin_lock_irqsave(&priv->lock, flags);
+
+		netif_device_attach(dev);
+
+		if (priv->open) {
+			err = __orinoco_up(dev);
+			if (err)
+				printk(KERN_ERR "%s: Error %d restarting card on PBOOK_WAKE\n",
+				       dev->name, err);
+		}
+
+		priv->hw_unavailable = 0;
+
+		spin_unlock_irqrestore(&priv->lock, flags);
+
 		break;
 	}
 	return PBOOK_SLEEP_OK;
 }
 #endif /* CONFIG_PMAC_PBOOK */
 
+static int airport_hard_reset(struct orinoco_private *priv)
+{
+	struct airport *card = priv->card;
+
+	pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 0);
+	current->state = TASK_UNINTERRUPTIBLE;
+	schedule_timeout(HZ);
+	pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 1);
+	current->state = TASK_UNINTERRUPTIBLE;
+	schedule_timeout(HZ);
+
+	return 0;
+}
+
 static struct net_device *
-airport_attach(struct device_node* of_node)
+airport_attach(struct device_node *of_node)
 {
 	struct orinoco_private *priv;
 	struct net_device *dev;
@@ -181,15 +161,13 @@
 	unsigned long phys_addr;
 	hermes_t *hw;
 
-	TRACE_ENTER("orinoco");
-
 	if (of_node->n_addrs < 1 || of_node->n_intrs < 1) {
 		printk(KERN_ERR "airport: wrong interrupt/addresses in OF tree\n");
 		return NULL;
 	}
 
 	/* Allocate space for private device-specific data */
-	dev = alloc_orinocodev(sizeof(*card));
+	dev = alloc_orinocodev(sizeof(*card), airport_hard_reset);
 	if (! dev) {
 		printk(KERN_ERR "airport: can't allocate device datas\n");
 		return NULL;
@@ -205,17 +183,14 @@
 		kfree(dev);
 		return NULL;
 	}
-	
+
 	dev->name[0] = '\0';	/* register_netdev will give us an ethX name */
 	SET_MODULE_OWNER(dev);
 
-	/* Overrides */
-	dev->open = airport_open;
-	dev->stop = airport_stop;
-
 	/* Setup interrupts & base address */
 	dev->irq = of_node->intrs[0].line;
-	phys_addr = of_node->addrs[0].address; /* Physical address */
+	phys_addr = of_node->addrs[0].address;  /* Physical address */
+	printk(KERN_DEBUG "Airport at physical address %lx\n", phys_addr);
 	dev->base_addr = phys_addr;
 	card->vaddr = ioremap(phys_addr, AIRPORT_IO_LEN);
 	if (! card->vaddr) {
@@ -232,14 +207,14 @@
 	schedule_timeout(HZ);
 
 	/* Reset it before we get the interrupt */
-	hermes_reset(hw);
+	hermes_init(hw);
 
 	if (request_irq(dev->irq, orinoco_interrupt, 0, "Airport", (void *)priv)) {
 		printk(KERN_ERR "airport: Couldn't get IRQ %d\n", dev->irq);
 		goto failed;
 	}
 	card->irq_requested = 1;
-	
+
 	/* Tell the stack we exist */
 	if (register_netdev(dev) != 0) {
 		printk(KERN_ERR "airport: register_netdev() failed\n");
@@ -248,17 +223,12 @@
 	printk(KERN_DEBUG "airport: card registered for interface %s\n", dev->name);
 	card->ndev_registered = 1;
 
-	/* And give us the proc nodes for debugging */
-	if (orinoco_proc_dev_init(priv) != 0)
-		printk(KERN_ERR "airport: Failed to create /proc node for %s\n",
-		       dev->name);
-
 #ifdef CONFIG_PMAC_PBOOK
 	pmu_register_sleep_notifier(&airport_sleep_notifier);
 #endif
 	return dev;
 	
-failed:
+ failed:
 	airport_detach(dev);
 	return NULL;
 }				/* airport_attach */
@@ -273,16 +243,13 @@
 	struct orinoco_private *priv = dev->priv;
 	struct airport *card = priv->card;
 
-	/* Unregister proc entry */
-	orinoco_proc_dev_cleanup(priv);
-
 #ifdef CONFIG_PMAC_PBOOK
 	pmu_unregister_sleep_notifier(&airport_sleep_notifier);
 #endif
 	if (card->ndev_registered)
 		unregister_netdev(dev);
 	card->ndev_registered = 0;
-	
+
 	if (card->irq_requested)
 		free_irq(dev->irq, priv);
 	card->irq_requested = 0;
@@ -290,22 +257,28 @@
 	if (card->vaddr)
 		iounmap(card->vaddr);
 	card->vaddr = 0;
-	
+
 	dev->base_addr = 0;
 
 	release_OF_resource(card->node, 0);
-	
+
 	pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 0);
 	current->state = TASK_UNINTERRUPTIBLE;
 	schedule_timeout(HZ);
-	
+
 	kfree(dev);
 }				/* airport_detach */
 
+static char version[] __initdata = "airport.c 0.13b (Benjamin Herrenschmidt <benh@kernel.crashing.org>)";
+MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
+MODULE_DESCRIPTION("Driver for the Apple Airport wireless card.");
+MODULE_LICENSE("Dual MPL/GPL");
+EXPORT_NO_SYMBOLS;
+
 static int __init
 init_airport(void)
 {
-	struct device_node* airport_node;
+	struct device_node *airport_node;
 
 	printk(KERN_DEBUG "%s\n", version);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/wireless/hermes.c linux-2.4.21-pre6/drivers/net/wireless/hermes.c
--- linux-2.4.20/drivers/net/wireless/hermes.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/wireless/hermes.c	2003-03-26 23:49:09.000000000 +0000
@@ -45,7 +45,6 @@
 #include <linux/threads.h>
 #include <linux/smp.h>
 #include <asm/io.h>
-#include <linux/ptrace.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -53,7 +52,7 @@
 
 #include "hermes.h"
 
-static char version[] __initdata = "hermes.c: 5 Apr 2002 David Gibson <hermes@gibson.dropbear.id.au>";
+static char version[] __initdata = "hermes.c: 4 Dec 2002 David Gibson <hermes@gibson.dropbear.id.au>";
 MODULE_DESCRIPTION("Low-level driver helper for Lucent Hermes chipset and Prism II HFA384x wireless MAC controller");
 MODULE_AUTHOR("David Gibson <hermes@gibson.dropbear.id.au>");
 #ifdef MODULE_LICENSE
@@ -70,14 +69,14 @@
  * Debugging helpers
  */
 
+#define IO_TYPE(hw)	((hw)->io_space ? "IO " : "MEM ")
+#define DMSG(stuff...) do {printk(KERN_DEBUG "hermes @ %s0x%x: " , IO_TYPE(hw), hw->iobase); \
+			printk(stuff);} while (0)
+
 #undef HERMES_DEBUG
 #ifdef HERMES_DEBUG
-
 #include <stdarg.h>
 
-#define DMSG(stuff...) do {printk(KERN_DEBUG "hermes @ 0x%x: " , hw->iobase); \
-			printk(stuff);} while (0)
-
 #define DEBUG(lvl, stuff...) if ( (lvl) <= HERMES_DEBUG) DMSG(stuff)
 
 #else /* ! HERMES_DEBUG */
@@ -86,7 +85,6 @@
 
 #endif /* ! HERMES_DEBUG */
 
-#define IO_TYPE(hw)	((hw)->io_space ? "IO " : "MEM ")
 
 /*
  * Internal functions
@@ -111,7 +109,6 @@
 		udelay(1);
 		reg = hermes_read_regn(hw, CMD);
 	}
-	DEBUG(3, "hermes_issue_cmd: did %d retries.\n", CMD_BUSY_TIMEOUT-k);
 	if (reg & HERMES_CMD_BUSY) {
 		return -EBUSY;
 	}
@@ -143,7 +140,7 @@
 #endif
 }
 
-int hermes_reset(hermes_t *hw)
+int hermes_init(hermes_t *hw)
 {
 	u16 status, reg;
 	int err = 0;
@@ -195,8 +192,6 @@
 		reg = hermes_read_regn(hw, EVSTAT);
 	}
 
-	DEBUG(0, "Reset completed in %d iterations\n", CMD_INIT_TIMEOUT - k);
-
 	hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC);
 
 	if (! hermes_present(hw)) {
@@ -303,9 +298,6 @@
 
 	err = hermes_docmd_wait(hw, HERMES_CMD_ALLOC, size, NULL);
 	if (err) {
-		printk(KERN_WARNING "hermes @ %s0x%lx: "
-		       "Frame allocation command failed (0x%X).\n",
-		       IO_TYPE(hw), hw->iobase, err);
 		return err;
 	}
 
@@ -393,12 +385,10 @@
 	}
 
 	if (reg & HERMES_OFFSET_BUSY) {
-		DEBUG(1,"hermes_bap_seek: timeout\n");
 		return -ETIMEDOUT;
 	}
 
 	if (reg & HERMES_OFFSET_ERR) {
-		DEBUG(1,"hermes_bap_seek: BAP error\n");
 		return -EIO;
 	}
 
@@ -412,7 +402,7 @@
  *
  * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware
  */
-int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len,
+int hermes_bap_pread(hermes_t *hw, int bap, void *buf, unsigned len,
 		     u16 id, u16 offset)
 {
 	int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
@@ -438,7 +428,7 @@
  *
  * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware
  */
-int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len,
+int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, unsigned len,
 		      u16 id, u16 offset)
 {
 	int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
@@ -466,12 +456,13 @@
  * practice.
  *
  * Callable from user or bh context.  */
-int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, int bufsize,
+int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned bufsize,
 		    u16 *length, void *buf)
 {
 	int err = 0;
 	int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
 	u16 rlength, rtype;
+	unsigned nwords;
 
 	if ( (bufsize < 0) || (bufsize % 2) )
 		return -EINVAL;
@@ -500,10 +491,9 @@
 		       "(rid=0x%04x, len=0x%04x)\n",
 		       IO_TYPE(hw), hw->iobase,
 		       HERMES_RECLEN_TO_BYTES(rlength), bufsize, rid, rlength);
-	
-	/* FIXME: we should read the min of the requested length and
-           the actual record length */
-	hermes_read_words(hw, dreg, buf, bufsize / 2);
+
+	nwords = min((unsigned)rlength - 1, bufsize / 2);
+	hermes_read_words(hw, dreg, buf, nwords);
 
  out:
 	return err;
@@ -514,10 +504,10 @@
 {
 	int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
 	int err = 0;
-	int count;
-	
-	DEBUG(3, "write_ltv(): bap=%d rid=0x%04x length=%d (value=0x%04x)\n",
-	      bap, rid, length, * ((u16 *)value));
+	unsigned count;
+
+	if (length == 0)
+		return -EINVAL;
 
 	err = hermes_bap_seek(hw, bap, rid, 0);
 	if (err)
@@ -538,7 +528,7 @@
 }
 
 EXPORT_SYMBOL(hermes_struct_init);
-EXPORT_SYMBOL(hermes_reset);
+EXPORT_SYMBOL(hermes_init);
 EXPORT_SYMBOL(hermes_docmd_wait);
 EXPORT_SYMBOL(hermes_allocate);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/wireless/hermes.h linux-2.4.21-pre6/drivers/net/wireless/hermes.h
--- linux-2.4.20/drivers/net/wireless/hermes.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/wireless/hermes.h	2003-03-26 23:49:00.000000000 +0000
@@ -171,6 +171,7 @@
 #define	HERMES_RXSTAT_BADCRC		(0x0001)
 #define	HERMES_RXSTAT_UNDECRYPTABLE	(0x0002)
 #define	HERMES_RXSTAT_MACPORT		(0x0700)
+#define HERMES_RXSTAT_PCF		(0x1000)	/* Frame was received in CF period */
 #define	HERMES_RXSTAT_MSGTYPE		(0xE000)
 #define	HERMES_RXSTAT_1042		(0x2000)	/* RFC-1042 frame */
 #define	HERMES_RXSTAT_TUNNEL		(0x4000)	/* bridge-tunnel encoded frame */
@@ -250,6 +251,18 @@
 	struct hermes_scan_apinfo aps[35];        /* Scan result */
 } __attribute__ ((packed));
 
+#define HERMES_LINKSTATUS_NOT_CONNECTED   (0x0000)  
+#define HERMES_LINKSTATUS_CONNECTED       (0x0001)
+#define HERMES_LINKSTATUS_DISCONNECTED    (0x0002)
+#define HERMES_LINKSTATUS_AP_CHANGE       (0x0003)
+#define HERMES_LINKSTATUS_AP_OUT_OF_RANGE (0x0004)
+#define HERMES_LINKSTATUS_AP_IN_RANGE     (0x0005)
+#define HERMES_LINKSTATUS_ASSOC_FAILED    (0x0006)
+  
+struct hermes_linkstatus {
+	u16 linkstatus;         /* Link status */
+} __attribute__ ((packed));
+
 // #define HERMES_DEBUG_BUFFER 1
 #define HERMES_DEBUG_BUFSIZE 4096
 struct hermes_debug_entry {
@@ -299,15 +312,15 @@
 
 /* Function prototypes */
 void hermes_struct_init(hermes_t *hw, ulong address, int io_space, int reg_spacing);
-int hermes_reset(hermes_t *hw);
+int hermes_init(hermes_t *hw);
 int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0, hermes_response_t *resp);
 int hermes_allocate(hermes_t *hw, u16 size, u16 *fid);
 
-int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len,
+int hermes_bap_pread(hermes_t *hw, int bap, void *buf, unsigned len,
 		       u16 id, u16 offset);
-int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len,
+int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, unsigned len,
 			u16 id, u16 offset);
-int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, int buflen,
+int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned buflen,
 		    u16 *length, void *buf);
 int hermes_write_ltv(hermes_t *hw, int bap, u16 rid,
 		      u16 length, const void *value);
@@ -319,12 +332,6 @@
 	return hermes_read_regn(hw, SWSUPPORT0) == HERMES_MAGIC;
 }
 
-static inline void hermes_enable_interrupt(hermes_t *hw, u16 events)
-{
-	hw->inten |= events;
-	hermes_write_regn(hw, INTEN, hw->inten);
-}
-
 static inline void hermes_set_irqmask(hermes_t *hw, u16 events)
 {
 	hw->inten = events;
@@ -350,11 +357,11 @@
 	return hermes_docmd_wait(hw, HERMES_CMD_INQUIRE, rid, NULL);
 }
 
-#define HERMES_BYTES_TO_RECLEN(n) ( ((n) % 2) ? (((n)+1)/2)+1 : ((n)/2)+1 )
+#define HERMES_BYTES_TO_RECLEN(n) ( (((n)+1)/2) + 1 )
 #define HERMES_RECLEN_TO_BYTES(n) ( ((n)-1) * 2 )
 
 /* Note that for the next two, the count is in 16-bit words, not bytes */
-static inline void hermes_read_words(struct hermes *hw, int off, void *buf, int count)
+static inline void hermes_read_words(struct hermes *hw, int off, void *buf, unsigned count)
 {
 	off = off << hw->reg_spacing;;
 
@@ -364,15 +371,17 @@
 		int i;
 		u16 *p;
 
-		/* This need to *not* byteswap (like insw()) but
-		 * readw() does byteswap hence the conversion */
+		/* This needs to *not* byteswap (like insw()) but
+		 * readw() does byteswap hence the conversion.  I hope
+		 * gcc is smart enough to fold away the two swaps on
+		 * big-endian platforms. */
 		for (i = 0, p = buf; i < count; i++) {
 			*p++ = cpu_to_le16(readw(hw->iobase + off));
 		}
 	}
 }
 
-static inline void hermes_write_words(struct hermes *hw, int off, const void *buf, int count)
+static inline void hermes_write_words(struct hermes *hw, int off, const void *buf, unsigned count)
 {
 	off = off << hw->reg_spacing;;
 
@@ -382,8 +391,10 @@
 		int i;
 		const u16 *p;
 
-		/* This need to *not* byteswap (like outsw()) but
-		 * writew() does byteswap hence the conversion */
+		/* This needs to *not* byteswap (like outsw()) but
+		 * writew() does byteswap hence the conversion.  I
+		 * hope gcc is smart enough to fold away the two swaps
+		 * on big-endian platforms. */
 		for (i = 0, p = buf; i < count; i++) {
 			writew(le16_to_cpu(*p++), hw->iobase + off);
 		}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/wireless/ieee802_11.h linux-2.4.21-pre6/drivers/net/wireless/ieee802_11.h
--- linux-2.4.20/drivers/net/wireless/ieee802_11.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/wireless/ieee802_11.h	2003-03-26 23:49:54.000000000 +0000
@@ -2,9 +2,13 @@
 #define _IEEE802_11_H
 
 #define IEEE802_11_DATA_LEN		2304
-/* Actually, the standard seems to be inconsistent about what the
-   maximum frame size really is.  S6.2.1.1.2 says 2304 octets, but the
-   figure in section 7.1.2 says 2312 octects. */
+/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section
+   6.2.1.1.2.
+
+   The figure in section 7.1.2 suggests a body size of up to 2312
+   bytes is allowed, which is a bit confusing, I suspect this
+   represents the 2304 bytes of real data, plus a possible 8 bytes of
+   WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */
 #define IEEE802_11_HLEN			30
 #define IEEE802_11_FRAME_LEN		(IEEE802_11_DATA_LEN + IEEE802_11_HLEN)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/wireless/orinoco.c linux-2.4.21-pre6/drivers/net/wireless/orinoco.c
--- linux-2.4.20/drivers/net/wireless/orinoco.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/wireless/orinoco.c	2003-03-26 23:49:39.000000000 +0000
@@ -1,4 +1,4 @@
-/* orinoco.c 0.11b	- (formerly known as dldwd_cs.c and orinoco_cs.c)
+/* orinoco.c 0.13b	- (formerly known as dldwd_cs.c and orinoco_cs.c)
  *
  * A driver for Hermes or Prism 2 chipset based PCMCIA wireless
  * adaptors, with Lucent/Agere, Intersil or Symbol firmware.
@@ -240,7 +240,7 @@
  *	  was never very useful.
  *	o Make Rx errors less noisy.
  *
- * v0.10 -> v0.11 - 5 Apr Mar 2002 - David Gibson
+ * v0.10 -> v0.11 - 5 Apr 2002 - David Gibson
  *	o Laid the groundwork in hermes.[ch] for devices which map
  *	  into PCI memory space rather than IO space.
  *	o Fixed bug in multicast handling (cleared multicast list when
@@ -256,7 +256,7 @@
  *	o Fixes for recent Symbol firmwares which lack AP density
  *	  (Pavel Roskin).
  *
- * v0.11 -> v0.11b - 29 Apr 2002 - David Gibson
+ * v0.11 -> v0.11a - 29 Apr 2002 - David Gibson
  *	o Handle different register spacing, necessary for Prism 2.5
  *	  PCI adaptors (Steve Hill).
  *	o Cleaned up initialization of card structures in orinoco_cs
@@ -279,44 +279,101 @@
  *	o Fixed multiple bad kfree() bugs introduced by the
  *	  alloc_orinocodev() changes.
  *
+ * v0.11b -> v0.12 - 19 Jun 2002 - David Gibson
+ *	o Support changing the MAC address.
+ *	o Correct display of Intersil firmware revision numbers.
+ *	o Entirely revised locking scheme.  Should be both simpler and
+ *	   better.
+ *	o Merged some common code in orinoco_plx, orinoco_pci and
+ *	  airport by creating orinoco_default_{open,stop,reset}()
+ *	  which are used as the dev->open, dev->stop, priv->reset
+ *	  callbacks if none are specified when alloc_orinocodev() is
+ *	  called.
+ *	o Removed orinoco_plx_interupt() and orinoco_pci_interrupt().
+ *	  They didn't do anything.
+ *
+ * v0.12 -> v0.12a - 4 Jul 2002 - David Gibson
+ *	o Some rearrangement of code.
+ *	o Numerous fixups to locking and rest handling, particularly
+ *	  for PCMCIA.
+ *	o This allows open and stop net_device methods to be in
+ *	  orinoco.c now, rather than in the init modules.
+ *	o In orinoco_cs.c link->priv now points to the struct
+ *	  net_device not to the struct orinoco_private.
+ *	o Added a check for undersized SNAP frames, which could cause
+ *	  crashes.
+ *
+ * v0.12a -> v0.12b - 11 Jul 2002 - David Gibson
+ *	o Fix hw->num_init testing code, so num_init is actually
+ *	  incremented.
+ *	o Fix very stupid bug in orinoco_cs which broke compile with
+ *	  CONFIG_SMP.
+ *	o Squashed a warning.
+ *
+ * v0.12b -> v0.12c - 26 Jul 2002 - David Gibson
+ *	o Change to C9X style designated initializers.
+ *	o Add support for 3Com AirConnect PCI.
+ *	o No longer ignore the hard_reset argument to
+ *	  alloc_orinocodev().  Oops.
+ *
+ * v0.12c -> v0.13beta1 - 13 Sep 2002 - David Gibson
+ *	o Revert the broken 0.12* locking scheme and go to a new yet
+ *	  simpler scheme.
+ *	o Do firmware resets only in orinoco_init() and when waking
+ *	  the card from hard sleep.
+ *
+ * v0.13beta1 -> v0.13 - 27 Sep 2002 - David Gibson
+ *	o Re-introduced full resets (via schedule_task()) on Tx
+ *	  timeout.
+ *
+ * v0.13 -> v0.13a - 30 Sep 2002 - David Gibson
+ *	o Minor cleanups to info frame handling.  Add basic support
+ *	  for linkstatus info frames.
+ *	o Include required kernel headers in orinoco.h, to avoid
+ *	  compile problems.
+ *
+ * v0.13a -> v0.13b - 10 Feb 2003 - David Gibson
+ *	o Implemented hard reset for Airport cards
+ *	o Experimental suspend/resume implementation for orinoco_pci
+ *	o Abolished /proc debugging support, replaced with a debugging
+ *	  iwpriv.  Now it's ugly and simple instead of ugly and complex.
+ *	o Bugfix in hermes.c if the firmware returned a record length
+ *	  of 0, we could go clobbering memory.
+ *	o Bugfix in orinoco_stop() - it used to fail if hw_unavailable
+ *	  was set, which was usually true on PCMCIA hot removes.
+ * 	o Track LINKSTATUS messages, silently drop Tx packets before
+ * 	  we are connected (avoids cofusing the firmware), and only
+ * 	  give LINKSTATUS printk()s if the status has changed.
+ *
  * TODO
- *	o New wireless extensions API
+
+ *	o New wireless extensions API (patch from Moustafa
+ *	  Youssef, updated by Jim Carter).
+ *	o Fix PCMCIA hard resets with pcmcia-cs.
  *	o Handle de-encapsulation within network layer, provide 802.11
- *	  headers
+ *	  headers (patch from Thomas 'Dent' Mirlacher)
  *	o Fix possible races in SPY handling.
  *	o Disconnect wireless extensions from fundamental configuration.
- *
- *	o Convert /proc debugging stuff to seqfile
- *	o Use multiple Tx buffers
- */
-/* Notes on locking:
- *
- * The basic principle of operation is that everything except the
- * interrupt handler is serialized through a single spinlock in the
- * struct orinoco_private structure, using orinoco_lock() and
- * orinoco_unlock() (which in turn use spin_lock_bh() and
- * spin_unlock_bh()).
- *
- * The kernel's IRQ handling stuff ensures that the interrupt handler
- * does not re-enter itself. The interrupt handler is written such
- * that everything it does is safe without a lock: chiefly this means
- * that the Rx path uses one of the Hermes chipset's BAPs while
- * everything else uses the other.
- *
- * Actually, strictly speaking, the updating of the statistics from
- * the interrupt handler isn't safe without a lock.  However the worst
- * that can happen is that we perturb the packet/byte counts slightly.
- * We could fix this to use atomic types, but it's probably not worth
- * it.
- *
- * The big exception is that that we don't want the irq handler
- * running when we actually reset or shut down the card, because
- * strange things might happen (probably the worst would be one packet
- * of garbage, but you can't be too careful). For this we use
- * __orinoco_stop_irqs() which will set a flag to disable the interrupt
- * handler, and wait for any outstanding instances of the handler to
- * complete. THIS WILL LOSE INTERRUPTS! so it shouldn't be used except
- * for resets, where losing a few interrupts is acceptable. */
+ *	o (maybe) Software WEP support (patch from Stano Meduna).
+ *	o (maybe) Use multiple Tx buffers - driver handling queue
+ *	  rather than firmware. */
+
+/* Locking and synchronization:
+ *
+ * The basic principle is that everything is serialized through a
+ * single spinlock, priv->lock.  The lock is used in user, bh and irq
+ * context, so when taken outside hardirq context it should always be
+ * taken with interrupts disabled.  The lock protects both the
+ * hardware and the struct orinoco_private.
+ *
+ * Another flag, priv->hw_unavailable indicates that the hardware is
+ * unavailable for an extended period of time (e.g. suspended, or in
+ * the middle of a hard reset).  This flag is protected by the
+ * spinlock.  All code which touches the hardware should check the
+ * flag after taking the lock, and if it is set, give up on whatever
+ * they are doing and drop the lock again.  The orinoco_lock()
+ * function handles this (it unlocks and returns -EBUSY if
+ * hw_unavailable is true). */
 
 #include <linux/config.h>
 
@@ -332,32 +389,20 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/system.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/etherdevice.h>
 #include <linux/wireless.h>
-#include <linux/list.h>
 
 #include "hermes.h"
 #include "hermes_rid.h"
 #include "orinoco.h"
 #include "ieee802_11.h"
 
-/* Wireless extensions backwards compatibility */
-#ifndef SIOCIWFIRSTPRIV
-#define SIOCIWFIRSTPRIV		SIOCDEVPRIVATE
-#endif /* SIOCIWFIRSTPRIV */
-
-/* We do this this way to avoid ifdefs in the actual code */
-#ifdef WIRELESS_SPY
-#define SPY_NUMBER(priv)	(priv->spy_number)
-#else
-#define SPY_NUMBER(priv)	0
-#endif /* WIRELESS_SPY */
+/********************************************************************/
+/* Module information                                               */
+/********************************************************************/
 
-static char version[] __initdata = "orinoco.c 0.11b (David Gibson <hermes@gibson.dropbear.id.au> and others)";
 MODULE_AUTHOR("David Gibson <hermes@gibson.dropbear.id.au>");
 MODULE_DESCRIPTION("Driver for Lucent Orinoco, Prism II based and similar wireless cards");
 #ifdef MODULE_LICENSE
@@ -371,6 +416,26 @@
 EXPORT_SYMBOL(orinoco_debug);
 #endif
 
+/********************************************************************/
+/* Compile time configuration and compatibility stuff               */
+/********************************************************************/
+
+/* Wireless extensions backwards compatibility */
+#ifndef SIOCIWFIRSTPRIV
+#define SIOCIWFIRSTPRIV		SIOCDEVPRIVATE
+#endif /* SIOCIWFIRSTPRIV */
+
+/* We do this this way to avoid ifdefs in the actual code */
+#ifdef WIRELESS_SPY
+#define SPY_NUMBER(priv)	(priv->spy_number)
+#else
+#define SPY_NUMBER(priv)	0
+#endif /* WIRELESS_SPY */
+
+/********************************************************************/
+/* Internal constants                                               */
+/********************************************************************/
+
 #define ORINOCO_MIN_MTU		256
 #define ORINOCO_MAX_MTU		(IEEE802_11_DATA_LEN - ENCAPS_OVERHEAD)
 
@@ -379,13 +444,15 @@
 #define IRQ_BAP			1
 #define MAX_IRQLOOPS_PER_IRQ	10
 #define MAX_IRQLOOPS_PER_JIFFY	(20000/HZ)	/* Based on a guestimate of how many events the
-						   device can legitimately generate */
+						   device could legitimately generate */
 #define SMALL_KEY_SIZE		5
 #define LARGE_KEY_SIZE		13
 #define TX_NICBUF_SIZE_BUG	1585		/* Bug in Symbol firmware */
 
 #define DUMMY_FID		0xFFFF
 
+#define RUP_EVEN(a) (((a) + 1) & (~1))
+
 /*#define MAX_MULTICAST(priv)	(priv->firmware_type == FIRMWARE_TYPE_AGERE ? \
   HERMES_MAX_MULTICAST : 0)*/
 #define MAX_MULTICAST(priv)	(HERMES_MAX_MULTICAST)
@@ -403,7 +470,7 @@
 
 /* This tables gives the actual meanings of the bitrate IDs returned by the firmware. */
 struct {
-	int bitrate; /* in 100s of kilbits */
+	int bitrate; /* in 100s of kilobits */
 	int automatic;
 	u16 agere_txratectrl;
 	u16 intersil_txratectrl;
@@ -419,6 +486,10 @@
 };
 #define BITRATE_TABLE_SIZE (sizeof(bitrate_table) / sizeof(bitrate_table[0]))
 
+/********************************************************************/
+/* Data types                                                       */
+/********************************************************************/
+
 struct header_struct {
 	/* 802.3 */
 	u8 dest[ETH_ALEN];
@@ -438,27 +509,29 @@
 
 #define ENCAPS_OVERHEAD		(sizeof(encaps_hdr) + 2)
 
-/*
- * Function prototypes
- */
+/********************************************************************/
+/* Function prototypes                                              */
+/********************************************************************/
 
 static void orinoco_stat_gather(struct net_device *dev,
-			      struct sk_buff *skb,
-			      struct hermes_rx_descriptor *desc);
+				struct sk_buff *skb,
+				struct hermes_rx_descriptor *desc);
 
 static struct net_device_stats *orinoco_get_stats(struct net_device *dev);
 static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev);
 
 /* Hardware control routines */
 
+static int __orinoco_program_rids(struct orinoco_private *priv);
+
 static int __orinoco_hw_set_bitrate(struct orinoco_private *priv);
 static int __orinoco_hw_setup_wep(struct orinoco_private *priv);
 static int orinoco_hw_get_bssid(struct orinoco_private *priv, char buf[ETH_ALEN]);
 static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
-			      char buf[IW_ESSID_MAX_SIZE+1]);
+				char buf[IW_ESSID_MAX_SIZE+1]);
 static long orinoco_hw_get_freq(struct orinoco_private *priv);
 static int orinoco_hw_get_bitratelist(struct orinoco_private *priv, int *numrates,
-				    s32 *rates, int max);
+				      s32 *rates, int max);
 static void __orinoco_set_multicast_list(struct net_device *dev);
 
 /* Interrupt handling routines */
@@ -471,6 +544,7 @@
 static void __orinoco_ev_tx(struct orinoco_private *priv, hermes_t *hw);
 static void __orinoco_ev_alloc(struct orinoco_private *priv, hermes_t *hw);
 
+/* ioctl() routines */
 static int orinoco_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq);
 static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq);
 static int orinoco_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq);
@@ -491,164 +565,168 @@
 static int orinoco_ioctl_setport3(struct net_device *dev, struct iwreq *wrq);
 static int orinoco_ioctl_getport3(struct net_device *dev, struct iwreq *wrq);
 
-/* /proc debugging stuff */
-static int orinoco_proc_init(void);
-static void orinoco_proc_cleanup(void);
+static int orinoco_debug_dump_recs(struct orinoco_private *priv);
 
-/*
- * Inline functions
- */
-static inline void
-orinoco_lock(struct orinoco_private *priv)
-{
-	spin_lock_bh(&priv->lock);
-}
+/********************************************************************/
+/* Function prototypes                                              */
+/********************************************************************/
 
-static inline void
-orinoco_unlock(struct orinoco_private *priv)
+int __orinoco_up(struct net_device *dev)
 {
-	spin_unlock_bh(&priv->lock);
-}
+	struct orinoco_private *priv = dev->priv;
+	struct hermes *hw = &priv->hw;
+	int err;
 
-static inline int
-orinoco_irqs_allowed(struct orinoco_private *priv)
-{
-	return test_bit(ORINOCO_STATE_DOIRQ, &priv->state);
-}
+	err = __orinoco_program_rids(priv);
+	if (err) {
+		printk(KERN_ERR "%s: Error %d configuring card\n",
+		       dev->name, err);
+		return err;
+	}
 
-static inline void
-__orinoco_stop_irqs(struct orinoco_private *priv)
-{
-	hermes_t *hw = &priv->hw;
+	/* Fire things up again */
+	hermes_set_irqmask(hw, ORINOCO_INTEN);
+	err = hermes_enable_port(hw, 0);
+	if (err) {
+		printk(KERN_ERR "%s: Error %d enabling MAC port\n",
+		       dev->name, err);
+		return err;
+	}
 
-	hermes_set_irqmask(hw, 0);
-	clear_bit(ORINOCO_STATE_DOIRQ, &priv->state);
-	while (test_bit(ORINOCO_STATE_INIRQ, &priv->state))
-		;
+	netif_start_queue(dev);
+
+	return 0;
 }
 
-static inline void
-__orinoco_start_irqs(struct orinoco_private *priv, u16 irqmask)
+int __orinoco_down(struct net_device *dev)
 {
-	hermes_t *hw = &priv->hw;
+	struct orinoco_private *priv = dev->priv;
+	struct hermes *hw = &priv->hw;
+	int err;
 
-	TRACE_ENTER(priv->ndev->name);
+	netif_stop_queue(dev);
 
-	__cli(); /* FIXME: is this necessary? */
-	set_bit(ORINOCO_STATE_DOIRQ, &priv->state);
-	hermes_set_irqmask(hw, irqmask);
-	__sti();
+	err = hermes_disable_port(hw, 0);
+	if (err) {
+		printk(KERN_ERR "%s: Error %d disabling MAC port\n",
+		       dev->name, err);
+		return err;
+	}
+	hermes_set_irqmask(hw, 0);
+	hermes_write_regn(hw, EVACK, 0xffff);
 
-	TRACE_EXIT(priv->ndev->name);
+	return 0;
 }
 
-static inline void
-set_port_type(struct orinoco_private *priv)
+int orinoco_reinit_firmware(struct net_device *dev)
 {
-	switch (priv->iw_mode) {
-	case IW_MODE_INFRA:
-		priv->port_type = 1;
-		priv->allow_ibss = 0;
-		break;
-	case IW_MODE_ADHOC:
-		if (priv->prefer_port3) {
-			priv->port_type = 3;
-			priv->allow_ibss = 0;
-		} else {
-			priv->port_type = priv->ibss_port;
-			priv->allow_ibss = 1;
-		}
-		break;
-	default:
-		printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n",
-		       priv->ndev->name);
+	struct orinoco_private *priv = dev->priv;
+	struct hermes *hw = &priv->hw;
+	int err;
+
+	err = hermes_init(hw);
+	if (err)
+		return err;
+
+	err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
+	if (err == -EIO) {
+		/* Try workaround for old Symbol firmware bug */
+		printk(KERN_WARNING "%s: firmware ALLOC bug detected "
+		       "(old Symbol firmware?). Trying to work around... ",
+		       dev->name);
+		
+		priv->nicbuf_size = TX_NICBUF_SIZE_BUG;
+		err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
+		if (err)
+			printk("failed!\n");
+		else
+			printk("ok.\n");
 	}
-}
 
-static inline int
-is_snap(struct header_struct *hdr)
-{
-	return (hdr->dsap == 0xAA) && (hdr->ssap == 0xAA) && (hdr->ctrl == 0x3);
+	return err;
 }
 
-static void
-orinoco_set_multicast_list(struct net_device *dev)
+static int orinoco_open(struct net_device *dev)
 {
 	struct orinoco_private *priv = dev->priv;
+	unsigned long flags;
+	int err;
 
-	orinoco_lock(priv);
-	__orinoco_set_multicast_list(dev);
-	orinoco_unlock(priv);
-}
+	err = orinoco_lock(priv, &flags);
+	if (err)
+		return err;
 
-/*
- * Hardware control routines
- */
+        priv->open = 1;
 
-void
-orinoco_shutdown(struct orinoco_private *priv)
+	err = __orinoco_up(dev);
+
+	orinoco_unlock(priv, &flags);
+
+	return err;
+}
+
+static int orinoco_stop(struct net_device *dev)
 {
+	struct orinoco_private *priv = dev->priv;
 	int err = 0;
 
-	TRACE_ENTER(priv->ndev->name);
+	/* We mustn't use orinoco_lock() here, because we need to be
+	   able to close the interface, even if hw_unavailable is set
+	   (e.g. as we're released after a PC Card removal) */
+	spin_lock_irq(&priv->lock);
 
-	orinoco_lock(priv);
-	__orinoco_stop_irqs(priv);
+	priv->open = 0;
 
-	err = hermes_reset(&priv->hw);
-	if (err && err != -ENODEV) /* If the card is gone, we don't care about shutting it down */
-		printk(KERN_ERR "%s: Error %d shutting down Hermes chipset\n", priv->ndev->name, err);
+	if (! priv->hw_unavailable)
+		err = __orinoco_down(dev);
 
-	orinoco_unlock(priv);
+	spin_unlock_irq(&priv->lock);
 
-	TRACE_EXIT(priv->ndev->name);
+	return err;
 }
 
-int
-orinoco_reset(struct orinoco_private *priv)
+static int __orinoco_program_rids(struct orinoco_private *priv)
 {
 	struct net_device *dev = priv->ndev;
 	hermes_t *hw = &priv->hw;
-	int err = 0;
+	int err;
 	struct hermes_idstring idbuf;
 
-	TRACE_ENTER(priv->ndev->name);
-
-	/* Stop other people bothering us */
-	orinoco_lock(priv);
-	__orinoco_stop_irqs(priv);
-
-	/* Check if we need a card reset */
-	if (priv->hard_reset)
-		priv->hard_reset(priv);
-
-	/* Do standard firmware reset if we can */
-	err = hermes_reset(hw);
-	if (err)
-		goto out;
-
-	err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
-	if (err == -EIO) {
-		/* Try workaround for old Symbol firmware bug */
-		priv->nicbuf_size = TX_NICBUF_SIZE_BUG;
-		err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
-		if (err)
-			goto out;
+	/* Set the MAC address */
+	err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
+			       HERMES_BYTES_TO_RECLEN(ETH_ALEN), dev->dev_addr);
+	if (err) {
+		printk(KERN_ERR "%s: Error %d setting MAC address\n", dev->name, err);
+		return err;
 	}
 
-	/* Now set up all the parameters on the card */
-	
 	/* Set up the link mode */
-	
 	err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE, priv->port_type);
-	if (err)
-		goto out;
+	if (err) {
+		printk(KERN_ERR "%s: Error %d setting port type\n", dev->name, err);
+		return err;
+	}
+	/* Set the channel/frequency */
+	if (priv->channel == 0) {
+		printk(KERN_DEBUG "%s: Channel is 0 in __orinoco_program_rids()\n", dev->name);
+		if (priv->createibss)
+			priv->channel = 10;
+	}
+	err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFOWNCHANNEL, priv->channel);
+	if (err) {
+		printk(KERN_ERR "%s: Error %d setting channel\n", dev->name, err);
+		return err;
+	}
+
 	if (priv->has_ibss) {
 		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFCREATEIBSS,
-					   priv->allow_ibss);
-		if (err)
-			goto out;
-		if((strlen(priv->desired_essid) == 0) && (priv->allow_ibss)
+					   priv->createibss);
+		if (err) {
+			printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n", dev->name, err);
+			return err;
+		}
+
+		if ((strlen(priv->desired_essid) == 0) && (priv->createibss)
 		   && (!priv->has_ibss_any)) {
 			printk(KERN_WARNING "%s: This firmware requires an \
 ESSID in IBSS-Ad-Hoc mode.\n", dev->name);
@@ -665,13 +743,17 @@
 	err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID,
 			       HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
 			       &idbuf);
-	if (err)
-		goto out;
+	if (err) {
+		printk(KERN_ERR "%s: Error %d setting OWNSSID\n", dev->name, err);
+		return err;
+	}
 	err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID,
 			       HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
 			       &idbuf);
-	if (err)
-		goto out;
+	if (err) {
+		printk(KERN_ERR "%s: Error %d setting DESIREDSSID\n", dev->name, err);
+		return err;
+	}
 
 	/* Set the station name */
 	idbuf.len = cpu_to_le16(strlen(priv->nick));
@@ -679,26 +761,29 @@
 	err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
 			       HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2),
 			       &idbuf);
-	if (err)
-		goto out;
-
-	/* Set the channel/frequency */
-	err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFOWNCHANNEL, priv->channel);
-	if (err)
-		goto out;
+	if (err) {
+		printk(KERN_ERR "%s: Error %d setting nickname\n", dev->name, err);
+		return err;
+	}
 
 	/* Set AP density */
 	if (priv->has_sensitivity) {
 		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE,
 					   priv->ap_density);
-		if (err)
+		if (err) {
+			printk(KERN_WARNING "%s: Error %d setting SYSTEMSCALE.  "
+			       "Disabling sensitivity control\n", dev->name, err);
+
 			priv->has_sensitivity = 0;
+		}
 	}
 
 	/* Set RTS threshold */
 	err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, priv->rts_thresh);
-	if (err)
-		goto out;
+	if (err) {
+		printk(KERN_ERR "%s: Error %d setting RTS threshold\n", dev->name, err);
+		return err;
+	}
 
 	/* Set fragmentation threshold or MWO robustness */
 	if (priv->has_mwo)
@@ -709,35 +794,52 @@
 		err = hermes_write_wordrec(hw, USER_BAP,
 					   HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
 					   priv->frag_thresh);
-	if (err)
-		goto out;
+	if (err) {
+		printk(KERN_ERR "%s: Error %d setting framentation\n", dev->name, err);
+		return err;
+	}
 
 	/* Set bitrate */
 	err = __orinoco_hw_set_bitrate(priv);
-	if (err)
-		goto out;
+	if (err) {
+		printk(KERN_ERR "%s: Error %d setting bitrate\n", dev->name, err);
+		return err;
+	}
 
 	/* Set power management */
 	if (priv->has_pm) {
 		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPMENABLED,
 					   priv->pm_on);
-		if (err)
-			goto out;
+		if (err) {
+			printk(KERN_ERR "%s: Error %d setting up PM\n",
+			       dev->name, err);
+			return err;
+		}
+
 		err = hermes_write_wordrec(hw, USER_BAP,
 					   HERMES_RID_CNFMULTICASTRECEIVE,
 					   priv->pm_mcast);
-		if (err)
-			goto out;
+		if (err) {
+			printk(KERN_ERR "%s: Error %d setting up PM\n",
+			       dev->name, err);
+			return err;
+		}
 		err = hermes_write_wordrec(hw, USER_BAP,
 					   HERMES_RID_CNFMAXSLEEPDURATION,
 					   priv->pm_period);
-		if (err)
-			goto out;
+		if (err) {
+			printk(KERN_ERR "%s: Error %d setting up PM\n",
+			       dev->name, err);
+			return err;
+		}
 		err = hermes_write_wordrec(hw, USER_BAP,
 					   HERMES_RID_CNFPMHOLDOVERDURATION,
 					   priv->pm_timeout);
-		if (err)
-			goto out;
+		if (err) {
+			printk(KERN_ERR "%s: Error %d setting up PM\n",
+			       dev->name, err);
+			return err;
+		}
 	}
 
 	/* Set preamble - only for Symbol so far... */
@@ -746,8 +848,9 @@
 					   HERMES_RID_CNFPREAMBLE_SYMBOL,
 					   priv->preamble);
 		if (err) {
-			printk(KERN_WARNING "%s: Can't set preamble!\n", dev->name);
-			goto out;
+			printk(KERN_ERR "%s: Error %d setting preamble\n",
+			       dev->name, err);
+			return err;
 		}
 	}
 
@@ -755,41 +858,159 @@
 	if (priv->has_wep) {
 		err = __orinoco_hw_setup_wep(priv);
 		if (err) {
-			printk(KERN_ERR "%s: Error %d activating WEP.\n",
+			printk(KERN_ERR "%s: Error %d activating WEP\n",
 			       dev->name, err);
-			goto out;
+			return err;
 		}
 	}
 
 	/* Set promiscuity / multicast*/
 	priv->promiscuous = 0;
 	priv->mc_count = 0;
-	__orinoco_set_multicast_list(dev);
-	
-	__orinoco_start_irqs(priv, HERMES_EV_RX | HERMES_EV_ALLOC |
-			   HERMES_EV_TX | HERMES_EV_TXEXC |
-			   HERMES_EV_WTERR | HERMES_EV_INFO |
-			   HERMES_EV_INFDROP);
+	__orinoco_set_multicast_list(dev); /* FIXME: what about the xmit_lock */
 
-	err = hermes_enable_port(hw, 0);
+	return 0;
+}
+
+/* xyzzy */
+static int orinoco_reconfigure(struct orinoco_private *priv)
+{
+	struct hermes *hw = &priv->hw;
+	unsigned long flags;
+	int err = 0;
+
+	orinoco_lock(priv, &flags);
+
+	err = hermes_disable_port(hw, 0);
+	if (err) {
+		printk(KERN_ERR "%s: Unable to disable port in orinco_reconfigure()\n",
+		       priv->ndev->name);
+		goto out;
+	}
+
+	err = __orinoco_program_rids(priv);
 	if (err)
 		goto out;
 
+	err = hermes_enable_port(hw, 0);
+	if (err) {
+		printk(KERN_ERR "%s: Unable to enable port in orinco_reconfigure()\n",
+		       priv->ndev->name);
+		goto out;
+	}
+
  out:
-	orinoco_unlock(priv);
+	orinoco_unlock(priv, &flags);
+	return err;
 
-	TRACE_EXIT(priv->ndev->name);
+}
 
-	return err;
+/* This must be called from user context, without locks held - use
+ * schedule_task() */
+static void orinoco_reset(struct net_device *dev)
+{
+	struct orinoco_private *priv = dev->priv;
+	int err;
+	unsigned long flags;
+
+	err = orinoco_lock(priv, &flags);
+	if (err)
+		return;
+
+	priv->hw_unavailable = 1;
+	orinoco_unlock(priv, &flags);
+
+	if (priv->hard_reset)
+		err = (*priv->hard_reset)(priv);
+	if (err) {
+		printk(KERN_ERR "%s: orinoco_reset: Error %d performing hard reset\n",
+		       dev->name, err);
+		/* FIXME: shutdown of some sort */
+		return;
+	}
+
+	err = orinoco_reinit_firmware(dev);
+	if (err) {
+		printk(KERN_ERR "%s: orinoco_reset: Error %d re-initializing firmware\n",
+		       dev->name, err);
+		return;
+	}
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	priv->hw_unavailable = 0;
+
+	err = __orinoco_up(dev);
+	if (err) {
+		printk(KERN_ERR "%s: orinoco_reset: Error %d reenabling card\n",
+		       dev->name, err);
+	} else
+		dev->trans_start = jiffies;
+
+	orinoco_unlock(priv, &flags);
+
+	return;
+}
+
+/********************************************************************/
+/* Internal helper functions                                        */
+/********************************************************************/
+
+static inline void
+set_port_type(struct orinoco_private *priv)
+{
+	switch (priv->iw_mode) {
+	case IW_MODE_INFRA:
+		priv->port_type = 1;
+		priv->createibss = 0;
+		break;
+	case IW_MODE_ADHOC:
+		if (priv->prefer_port3) {
+			priv->port_type = 3;
+			priv->createibss = 0;
+		} else {
+			priv->port_type = priv->ibss_port;
+			priv->createibss = 1;
+		}
+		break;
+	default:
+		printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n",
+		       priv->ndev->name);
+	}
+}
+
+static inline int
+is_snap(struct header_struct *hdr)
+{
+	return (hdr->dsap == 0xAA) && (hdr->ssap == 0xAA) && (hdr->ctrl == 0x3);
 }
 
+static void
+orinoco_set_multicast_list(struct net_device *dev)
+{
+	struct orinoco_private *priv = dev->priv;
+	unsigned long flags;
+
+	if (orinoco_lock(priv, &flags) != 0) {
+		printk(KERN_DEBUG "%s: orinoco_set_multicast_list() "
+		       "called when hw_unavailable\n", dev->name);
+		return;
+	}
+
+	__orinoco_set_multicast_list(dev);
+	orinoco_unlock(priv, &flags);
+}
+
+/********************************************************************/
+/* Hardware control functions                                       */
+/********************************************************************/
+
+
 static int __orinoco_hw_set_bitrate(struct orinoco_private *priv)
 {
 	hermes_t *hw = &priv->hw;
 	int err = 0;
 
-	TRACE_ENTER(priv->ndev->name);
-
 	if (priv->bitratemode >= BITRATE_TABLE_SIZE) {
 		printk(KERN_ERR "%s: BUG: Invalid bitrate mode %d\n",
 		       priv->ndev->name, priv->bitratemode);
@@ -812,8 +1033,6 @@
 		BUG();
 	}
 
-	TRACE_EXIT(priv->ndev->name);
-
 	return err;
 }
 
@@ -825,8 +1044,6 @@
 	int	master_wep_flag;
 	int	auth_flag;
 
-	TRACE_ENTER(priv->ndev->name);
-
 	switch (priv->firmware_type) {
 	case FIRMWARE_TYPE_AGERE: /* Agere style WEP */
 		if (priv->wep_on) {
@@ -920,8 +1137,6 @@
 		}
 	}
 
-	TRACE_EXIT(priv->ndev->name);
-
 	return 0;
 }
 
@@ -929,13 +1144,16 @@
 {
 	hermes_t *hw = &priv->hw;
 	int err = 0;
+	unsigned long flags;
 
-	orinoco_lock(priv);
+	err = orinoco_lock(priv, &flags);
+	if (err)
+		return err;
 
 	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
 			      ETH_ALEN, NULL, buf);
 
-	orinoco_unlock(priv);
+	orinoco_unlock(priv, &flags);
 
 	return err;
 }
@@ -948,10 +1166,11 @@
 	struct hermes_idstring essidbuf;
 	char *p = (char *)(&essidbuf.val);
 	int len;
+	unsigned long flags;
 
-	TRACE_ENTER(priv->ndev->name);
-
-	orinoco_lock(priv);
+	err = orinoco_lock(priv, &flags);
+	if (err)
+		return err;
 
 	if (strlen(priv->desired_essid) > 0) {
 		/* We read the desired SSID from the hardware rather
@@ -988,9 +1207,7 @@
 	buf[len] = '\0';
 
  fail_unlock:
-	orinoco_unlock(priv);
-
-	TRACE_EXIT(priv->ndev->name);
+	orinoco_unlock(priv, &flags);
 
 	return err;       
 }
@@ -1002,13 +1219,22 @@
 	int err = 0;
 	u16 channel;
 	long freq = 0;
+	unsigned long flags;
 
-	orinoco_lock(priv);
+	err = orinoco_lock(priv, &flags);
+	if (err)
+		return err;
 	
 	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENTCHANNEL, &channel);
 	if (err)
 		goto out;
 
+	/* Intersil firmware 1.3.5 returns 0 when the interface is down */
+	if (channel == 0) {
+		err = -EBUSY;
+		goto out;
+	}
+
 	if ( (channel < 1) || (channel > NUM_CHANNELS) ) {
 		struct net_device *dev = priv->ndev;
 
@@ -1020,7 +1246,7 @@
 	freq = channel_frequency[channel-1] * 100000;
 
  out:
-	orinoco_unlock(priv);
+	orinoco_unlock(priv, &flags);
 
 	if (err > 0)
 		err = -EBUSY;
@@ -1036,11 +1262,15 @@
 	int err = 0;
 	int num;
 	int i;
+	unsigned long flags;
+
+	err = orinoco_lock(priv, &flags);
+	if (err)
+		return err;
 
-	orinoco_lock(priv);
 	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_SUPPORTEDDATARATES,
 			      sizeof(list), NULL, &list);
-	orinoco_unlock(priv);
+	orinoco_unlock(priv, &flags);
 
 	if (err)
 		return err;
@@ -1122,7 +1352,7 @@
 /*
  * Interrupt handler
  */
-void orinoco_interrupt(int irq, void * dev_id, struct pt_regs *regs)
+void orinoco_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct orinoco_private *priv = (struct orinoco_private *) dev_id;
 	hermes_t *hw = &priv->hw;
@@ -1134,38 +1364,26 @@
 	 * we panic and shut down the hardware */
 	static int last_irq_jiffy = 0; /* jiffies value the last time we were called */
 	static int loops_this_jiffy = 0;
+	unsigned long flags;
 
-	if (test_and_set_bit(ORINOCO_STATE_INIRQ, &priv->state))
-		BUG();
-
-	if (! orinoco_irqs_allowed(priv)) {
-		clear_bit(ORINOCO_STATE_INIRQ, &priv->state);
+	if (orinoco_lock(priv, &flags) != 0) {
+		/* If hw is unavailable */
 		return;
 	}
 
-	DEBUG(3, "%s: orinoco_interrupt()\n", priv->ndev->name);
-
 	evstat = hermes_read_regn(hw, EVSTAT);
 	events = evstat & hw->inten;
 	
-/*  	if (! events) { */
-/*  		printk(KERN_WARNING "%s: Null event\n", dev->name); */
-/*  	} */
-
 	if (jiffies != last_irq_jiffy)
 		loops_this_jiffy = 0;
 	last_irq_jiffy = jiffies;
 
 	while (events && count--) {
-		DEBUG(3, "__orinoco_interrupt(): count=%d EVSTAT=0x%04x\n",
-		      count, evstat);
-		
 		if (++loops_this_jiffy > MAX_IRQLOOPS_PER_JIFFY) {
 			printk(KERN_CRIT "%s: IRQ handler is looping too \
 much! Shutting down.\n",
 			       dev->name);
 			/* Perform an emergency shutdown */
-			clear_bit(ORINOCO_STATE_DOIRQ, &priv->state);
 			hermes_set_irqmask(hw, 0);
 			break;
 		}
@@ -1199,7 +1417,7 @@
 		events = evstat & hw->inten;
 	};
 
-	clear_bit(ORINOCO_STATE_INIRQ, &priv->state);
+	orinoco_unlock(priv, &flags);
 }
 
 static void __orinoco_ev_tick(struct orinoco_private *priv, hermes_t *hw)
@@ -1211,8 +1429,8 @@
 {
 	/* This seems to happen a fair bit under load, but ignoring it
 	   seems to work fine...*/
-	DEBUG(1, "%s: MAC controller error (WTERR). Ignoring.\n",
-	      priv->ndev->name);
+	printk(KERN_DEBUG "%s: MAC controller error (WTERR). Ignoring.\n",
+	       priv->ndev->name);
 }
 
 static void __orinoco_ev_infdrop(struct orinoco_private *priv, hermes_t *hw)
@@ -1220,6 +1438,40 @@
 	printk(KERN_WARNING "%s: Information frame lost.\n", priv->ndev->name);
 }
 
+static void print_linkstatus(struct net_device *dev, u16 status)
+{
+	char * s;
+
+	switch (status) {
+	case HERMES_LINKSTATUS_NOT_CONNECTED:
+		s = "Not Connected";
+		break;
+	case HERMES_LINKSTATUS_CONNECTED:
+		s = "Connected";
+		break;
+	case HERMES_LINKSTATUS_DISCONNECTED:
+		s = "Disconnected";
+		break;
+	case HERMES_LINKSTATUS_AP_CHANGE:
+		s = "AP Changed";
+		break;
+	case HERMES_LINKSTATUS_AP_OUT_OF_RANGE:
+		s = "AP Out of Range";
+		break;
+	case HERMES_LINKSTATUS_AP_IN_RANGE:
+		s = "AP In Range";
+		break;
+	case HERMES_LINKSTATUS_ASSOC_FAILED:
+		s = "Association Failed";
+		break;
+	default:
+		s = "UNKNOWN";
+	}
+	
+	printk(KERN_INFO "%s: New link status: %s (%04x)\n",
+	       dev->name, s, status);
+}
+
 static void __orinoco_ev_info(struct orinoco_private *priv, hermes_t *hw)
 {
 	struct net_device *dev = priv->ndev;
@@ -1228,6 +1480,7 @@
 		u16 len;
 		u16 type;
 	} __attribute__ ((packed)) info;
+	int len, type;
 	int err;
 
 	/* This is an answer to an INQUIRE command that we did earlier,
@@ -1235,8 +1488,6 @@
 	 * The controller return to us a pseudo frame containing
 	 * the information in question - Jean II */
 	infofid = hermes_read_regn(hw, INFOFID);
-	DEBUG(3, "%s: __orinoco_ev_info(): INFOFID=0x%04x\n", dev->name,
-	      infofid);
 
 	/* Read the info frame header - don't try too hard */
 	err = hermes_bap_pread(hw, IRQ_BAP, &info, sizeof(info),
@@ -1247,25 +1498,29 @@
 		return;
 	}
 	
-	switch (le16_to_cpu(info.type)) {
+	len = HERMES_RECLEN_TO_BYTES(le16_to_cpu(info.len));
+	type = le16_to_cpu(info.type);
+
+	switch (type) {
 	case HERMES_INQ_TALLIES: {
 		struct hermes_tallies_frame tallies;
 		struct iw_statistics *wstats = &priv->wstats;
-		int len = le16_to_cpu(info.len) - 1;
 		
-		if (len > (sizeof(tallies) / 2)) {
-			DEBUG(1, "%s: tallies frame too long.\n", dev->name);
-			len = sizeof(tallies) / 2;
+		if (len > sizeof(tallies)) {
+			printk(KERN_WARNING "%s: Tallies frame too long (%d bytes)\n",
+			       dev->name, len);
+			len = sizeof(tallies);
 		}
 		
 		/* Read directly the data (no seek) */
-		hermes_read_words(hw, HERMES_DATA1, (void *) &tallies, len);
+		hermes_read_words(hw, HERMES_DATA1, (void *) &tallies,
+				  len / 2); /* FIXME: blech! */
 		
 		/* Increment our various counters */
 		/* wstats->discard.nwid - no wrong BSSID stuff */
 		wstats->discard.code +=
 			le16_to_cpu(tallies.RxWEPUndecryptable);
-		if (len == (sizeof(tallies) / 2))  
+		if (len == sizeof(tallies))  
 			wstats->discard.code +=
 				le16_to_cpu(tallies.RxDiscards_WEPICVError) +
 				le16_to_cpu(tallies.RxDiscards_WEPExcluded);
@@ -1277,17 +1532,42 @@
 		wstats->discard.retries +=
 			le16_to_cpu(tallies.TxRetryLimitExceeded);
 		/* wstats->miss.beacon - no match */
-#if ORINOCO_DEBUG > 3
-		/* Hack for debugging - should not be taken as an example */
-		wstats->discard.nwid += le16_to_cpu(tallies.TxUnicastFrames);
-		wstats->miss.beacon += le16_to_cpu(tallies.RxUnicastFrames);
-#endif
 #endif /* WIRELESS_EXT > 11 */
 	}
 	break;
+	case HERMES_INQ_LINKSTATUS: {
+		struct hermes_linkstatus linkstatus;
+		u16 newstatus;
+		
+		if (len != sizeof(linkstatus)) {
+			printk(KERN_WARNING "%s: Unexpected size for linkstatus frame (%d bytes)\n",
+			       dev->name, len);
+			break;
+		}
+
+		hermes_read_words(hw, HERMES_DATA1, (void *) &linkstatus,
+				  len / 2);
+		newstatus = le16_to_cpu(linkstatus.linkstatus);
+
+		if ( (newstatus == HERMES_LINKSTATUS_CONNECTED)
+		     || (newstatus == HERMES_LINKSTATUS_AP_CHANGE)
+		     || (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE) )
+			priv->connected = 1;
+		else if ( (newstatus == HERMES_LINKSTATUS_NOT_CONNECTED)
+			  || (newstatus == HERMES_LINKSTATUS_DISCONNECTED)
+			  || (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE)
+			  || (newstatus == HERMES_LINKSTATUS_ASSOC_FAILED) )
+			priv->connected = 0;
+
+		if (newstatus != priv->last_linkstatus)
+			print_linkstatus(dev, newstatus);
+
+		priv->last_linkstatus = newstatus;
+	}
+	break;
 	default:
-		DEBUG(1, "%s: Unknown information frame received (type %04x).\n",
-		      priv->ndev->name, le16_to_cpu(info.type));
+		printk(KERN_DEBUG "%s: Unknown information frame received (type %04x).\n",
+		      dev->name, type);
 		/* We don't actually do anything about it */
 		break;
 	}
@@ -1308,7 +1588,6 @@
 	int err;
 
 	rxfid = hermes_read_regn(hw, RXFID);
-	DEBUG(3, "__orinoco_ev_rx(): RXFID=0x%04x\n", rxfid);
 
 	err = hermes_bap_pread(hw, IRQ_BAP, &desc, sizeof(desc),
 			       rxfid, 0);
@@ -1349,11 +1628,11 @@
 	length = ntohs(hdr.len);
 	
 	/* Sanity checks */
-	if (length < sizeof(struct header_struct)) {
-		printk(KERN_WARNING "%s: Undersized frame received (%d bytes)\n",
-		       dev->name, length);
-		stats->rx_length_errors++;
-		stats->rx_errors++;
+	if (length < 3) { /* No for even an 802.2 LLC header */
+		/* At least on Symbol firmware with PCF we get quite a
+                   lot of these legitimately - Poll frames with no
+                   data. */
+		stats->rx_dropped++;
 		goto drop;
 	}
 	if (length > IEEE802_11_DATA_LEN) {
@@ -1373,7 +1652,6 @@
 	if (!skb) {
 		printk(KERN_WARNING "%s: Can't allocate skb for Rx\n",
 		       dev->name);
-		stats->rx_dropped++;
 		goto drop;
 	}
 
@@ -1383,8 +1661,7 @@
 	 * In most cases, the firmware tell us about SNAP frames.
 	 * For some reason, the SNAP frames sent by LinkSys APs
 	 * are not properly recognised by most firmwares.
-	 * So, check ourselves (note : only 3 bytes out of 6).
-	 */
+	 * So, check ourselves */
 	if(((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) ||
 	   ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) ||
 	   is_snap(&hdr)) {
@@ -1392,7 +1669,7 @@
 		   802.11 frame which we'll need to de-encapsulate to
 		   the original EthernetII frame. */
 
-		if (length < ENCAPS_OVERHEAD) {
+		if (length < ENCAPS_OVERHEAD) { /* No room for full LLC+SNAP */
 			stats->rx_length_errors++;
 			stats->rx_dropped++;
 			goto drop;
@@ -1420,7 +1697,7 @@
 	err = hermes_bap_pread(hw, IRQ_BAP, p, RUP_EVEN(data_len),
 			       rxfid, data_off);
 	if (err) {
-		printk(KERN_ERR "%s: error %d reading frame header. "
+		printk(KERN_ERR "%s: error %d reading frame. "
 		       "Frame dropped.\n", dev->name, err);
 		stats->rx_errors++;
 		goto drop;
@@ -1442,6 +1719,8 @@
 	return;
 
  drop:	
+	stats->rx_dropped++;
+
 	if (skb)
 		dev_kfree_skb_irq(skb);
 	return;
@@ -1475,11 +1754,7 @@
 
 static void __orinoco_ev_tx(struct orinoco_private *priv, hermes_t *hw)
 {
-/*  	struct net_device *dev = priv->ndev; */
 	struct net_device_stats *stats = &priv->stats;
-/*  	u16 fid = hermes_read_regn(hw, TXCOMPLFID); */
-
-/*  	DEBUG(2, "%s: Transmit completed (FID=%04X)\n", priv->ndev->name, fid); */
 
 	stats->tx_packets++;
 
@@ -1491,8 +1766,6 @@
 	struct net_device *dev = priv->ndev;
 	u16 fid = hermes_read_regn(hw, ALLOCFID);
 
-	DEBUG(3, "%s: Allocation complete FID=0x%04x\n", priv->ndev->name, fid);
-
 	if (fid != priv->txfid) {
 		if (fid != DUMMY_FID)
 			printk(KERN_WARNING "%s: Allocate event on unexpected fid (%04X)\n",
@@ -1506,16 +1779,17 @@
 }
 
 struct sta_id {
-	u16 id, vendor, major, minor;
+	u16 id, variant, major, minor;
 } __attribute__ ((packed));
 
 static int determine_firmware_type(struct net_device *dev, struct sta_id *sta_id)
 {
-	u32 firmver = ((u32)sta_id->major << 16) | sta_id->minor;
+	/* FIXME: this is fundamentally broken */
+	unsigned int firmver = ((u32)sta_id->major << 16) | sta_id->minor;
 	
-	if (sta_id->vendor == 1)
+	if (sta_id->variant == 1)
 		return FIRMWARE_TYPE_AGERE;
-	else if ((sta_id->vendor == 2) &&
+	else if ((sta_id->variant == 2) &&
 		   ((firmver == 0x10001) || (firmver == 0x20001)))
 		return FIRMWARE_TYPE_SYMBOL;
 	else
@@ -1528,7 +1802,7 @@
 	hermes_t *hw = &priv->hw;
 	int err;
 	struct sta_id sta_id;
-	u32 firmver;
+	unsigned int firmver;
 	char tmp[SYMBOL_MAX_VER_LEN+1];
 
 	/* Get the firmware version */
@@ -1539,14 +1813,12 @@
 		memset(&sta_id, 0, sizeof(sta_id));
 	}
 	le16_to_cpus(&sta_id.id);
-	le16_to_cpus(&sta_id.vendor);
+	le16_to_cpus(&sta_id.variant);
 	le16_to_cpus(&sta_id.major);
 	le16_to_cpus(&sta_id.minor);
 
-	firmver = ((u32)sta_id.major << 16) | sta_id.minor;
-
 	printk(KERN_DEBUG "%s: Station identity %04x:%04x:%04x:%04x\n",
-	       dev->name, sta_id.id, sta_id.vendor,
+	       dev->name, sta_id.id, sta_id.variant,
 	       sta_id.major, sta_id.minor);
 
 	if (! priv->firmware_type)
@@ -1561,7 +1833,6 @@
 	priv->has_ibss_any = 0;
 	priv->has_wep = 0;
 	priv->has_big_wep = 0;
-	priv->broken_cor_reset = 0;
 
 	/* Determine capabilities from the firmware version */
 	switch (priv->firmware_type) {
@@ -1572,6 +1843,8 @@
 		       "version %d.%02d\n", dev->name,
 		       sta_id.major, sta_id.minor);
 
+		firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor;
+
 		priv->has_ibss = (firmver >= 0x60006);
 		priv->has_ibss_any = (firmver >= 0x60010);
 		priv->has_wep = (firmver >= 0x40020);
@@ -1581,8 +1854,6 @@
 		priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */
 		priv->ibss_port = 1;
 
-		/* FIXME: Which firmware really do have a broken reset */
-		priv->broken_cor_reset = (firmver < 0x60000);
 		/* Tested with Agere firmware :
 		 *	1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
 		 * Tested CableTron firmware : 4.32 => Anton */
@@ -1634,18 +1905,21 @@
 		/* D-Link MAC : 00:40:05:* */
 		/* Addtron MAC : 00:90:D1:* */
 		printk(KERN_DEBUG "%s: Looks like an Intersil firmware "
-		       "version %d.%02d\n", dev->name,
-		       sta_id.major, sta_id.minor);
+		       "version %d.%d.%d\n", dev->name,
+		       sta_id.major, sta_id.minor, sta_id.variant);
 
-		priv->has_ibss = (firmver >= 0x00007); /* FIXME */
-		priv->has_big_wep = priv->has_wep = (firmver >= 0x00008);
-		priv->has_pm = (firmver >= 0x00007);
+		firmver = ((unsigned long)sta_id.major << 16) |
+			((unsigned long)sta_id.minor << 8) | sta_id.variant;
 
-		if (firmver >= 0x00008)
+		priv->has_ibss = (firmver >= 0x000700); /* FIXME */
+		priv->has_big_wep = priv->has_wep = (firmver >= 0x000800);
+		priv->has_pm = (firmver >= 0x000700);
+
+		if (firmver >= 0x000800)
 			priv->ibss_port = 0;
 		else {
 			printk(KERN_NOTICE "%s: Intersil firmware earlier "
-			       "than v0.08 - several features not supported\n",
+			       "than v0.8.x - several features not supported\n",
 			       dev->name);
 			priv->ibss_port = 1;
 		}
@@ -1669,16 +1943,16 @@
 	u16 reclen;
 	int len;
 
-	TRACE_ENTER("orinoco");
-
-	orinoco_lock(priv);
+	TRACE_ENTER(dev->name);
 
+	/* No need to lock, the resetting flag is already set in
+	 * alloc_orinocodev() */
 	priv->nicbuf_size = IEEE802_11_FRAME_LEN + ETH_HLEN;
 
-	/* Do standard firmware reset */
-	err = hermes_reset(hw);
+	/* Initialize the firmware */
+	err = hermes_init(hw);
 	if (err != 0) {
-		printk(KERN_ERR "%s: failed to reset hardware (err = %d)\n",
+		printk(KERN_ERR "%s: failed to initialize firmware (err = %d)\n",
 		       dev->name, err);
 		goto out;
 	}
@@ -1807,20 +2081,38 @@
 	priv->wep_on = 0;
 	priv->tx_key = 0;
 
-	printk(KERN_DEBUG "%s: ready\n", dev->name);
+	priv->hw_unavailable = 0;
 
- out:
-	orinoco_unlock(priv);
+	err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
+	if (err == -EIO) {
+		/* Try workaround for old Symbol firmware bug */
+		printk(KERN_WARNING "%s: firmware ALLOC bug detected "
+		       "(old Symbol firmware?). Trying to work around... ",
+		       dev->name);
+		
+		priv->nicbuf_size = TX_NICBUF_SIZE_BUG;
+		err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
+		if (err)
+			printk("failed!\n");
+		else
+			printk("ok.\n");
+	}
+	if (err) {
+		printk("%s: Error %d allocating Tx buffer\n", dev->name, err);
+		goto out;
+	}
 
-	TRACE_EXIT("orinoco");
+	printk(KERN_DEBUG "%s: ready\n", dev->name);
 
+ out:
+	TRACE_EXIT(dev->name);
 	return err;
 }
 
 struct net_device_stats *
 orinoco_get_stats(struct net_device *dev)
 {
-	struct orinoco_private *priv = (struct orinoco_private *)dev->priv;
+	struct orinoco_private *priv = dev->priv;
 	
 	return &priv->stats;
 }
@@ -1828,15 +2120,22 @@
 struct iw_statistics *
 orinoco_get_wireless_stats(struct net_device *dev)
 {
-	struct orinoco_private *priv = (struct orinoco_private *)dev->priv;
+	struct orinoco_private *priv = dev->priv;
 	hermes_t *hw = &priv->hw;
 	struct iw_statistics *wstats = &priv->wstats;
 	int err = 0;
+	unsigned long flags;
 
-	if (! netif_device_present(dev))
-		return NULL; /* FIXME: We may be able to do better than this */
+	if (! netif_device_present(dev)) {
+		printk(KERN_WARNING "%s: get_wireless_stats() called while device not present\n",
+		       dev->name);
+		return NULL; /* FIXME: Can we do better than this? */
+	}
 
-	orinoco_lock(priv);
+	err = orinoco_lock(priv, &flags);
+	if (err)
+		return NULL; /* FIXME: Erg, we've been signalled, how
+			      * do we propagate this back up? */
 
 	if (priv->iw_mode == IW_MODE_ADHOC) {
 		memset(&wstats->qual, 0, sizeof(wstats->qual));
@@ -1856,9 +2155,6 @@
 		err = HERMES_READ_RECORD(hw, USER_BAP,
 					 HERMES_RID_COMMSQUALITY, &cq);
 		
-		DEBUG(3, "%s: Global stats = %X-%X-%X\n", dev->name,
-		      cq.qual, cq.signal, cq.noise);
-
 		wstats->qual.qual = (int)le16_to_cpu(cq.qual);
 		wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95;
 		wstats->qual.noise = (int)le16_to_cpu(cq.noise) - 0x95;
@@ -1868,11 +2164,11 @@
 	/* We can't really wait for the tallies inquiry command to
 	 * complete, so we just use the previous results and trigger
 	 * a new tallies inquiry command for next time - Jean II */
-	/* FIXME: Hmm.. seems a bit ugly, I wonder if there's a way to
-	   do better - dgibson */
+	/* FIXME: We're in user context (I think?), so we should just
+           wait for the tallies to come through */
 	err = hermes_inquire(hw, HERMES_INQ_TALLIES);
                
-	orinoco_unlock(priv);
+	orinoco_unlock(priv, &flags);
 
 	if (err)
 		return NULL;
@@ -1932,21 +2228,42 @@
 	struct ethhdr *eh;
 	int len, data_len, data_off;
 	struct hermes_tx_descriptor desc;
+	unsigned long flags;
+
+	TRACE_ENTER(dev->name);
 
 	if (! netif_running(dev)) {
 		printk(KERN_ERR "%s: Tx on stopped device!\n",
 		       dev->name);
+		TRACE_EXIT(dev->name);
 		return 1;
-
 	}
 	
 	if (netif_queue_stopped(dev)) {
-		printk(KERN_ERR "%s: Tx while transmitter busy!\n", 
+		printk(KERN_DEBUG "%s: Tx while transmitter busy!\n", 
 		       dev->name);
+		TRACE_EXIT(dev->name);
 		return 1;
 	}
 	
-	orinoco_lock(priv);
+	if (orinoco_lock(priv, &flags) != 0) {
+		printk(KERN_ERR "%s: orinoco_xmit() called while hw_unavailable\n",
+		       dev->name);
+		TRACE_EXIT(dev->name);
+/*  		BUG(); */
+		return 1;
+	}
+
+	if (! priv->connected) {
+		/* Oops, the firmware hasn't established a connection,
+                   silently drop the packet (this seems to be the
+                   safest approach). */
+		stats->tx_errors++;
+		orinoco_unlock(priv, &flags);
+		dev_kfree_skb(skb);
+		TRACE_EXIT(dev->name);
+		return 0;
+	}
 
 	/* Length of the packet body */
 	/* FIXME: what if the skb is smaller than this? */
@@ -2017,14 +2334,17 @@
 	dev->trans_start = jiffies;
 	stats->tx_bytes += data_off + data_len;
 
-	orinoco_unlock(priv);
+	orinoco_unlock(priv, &flags);
 
 	dev_kfree_skb(skb);
 
+	TRACE_EXIT(dev->name);
+
 	return 0;
  fail:
+	TRACE_EXIT(dev->name);
 
-	orinoco_unlock(priv);
+	orinoco_unlock(priv, &flags);
 	return err;
 }
 
@@ -2034,27 +2354,21 @@
 	struct orinoco_private *priv = (struct orinoco_private *)dev->priv;
 	struct net_device_stats *stats = &priv->stats;
 	struct hermes *hw = &priv->hw;
-	int err = 0;
 
-	printk(KERN_WARNING "%s: Tx timeout! Resetting card. ALLOCFID=%04x, TXCOMPLFID=%04x, EVSTAT=%04x\n", dev->name, hermes_read_regn(hw, ALLOCFID), hermes_read_regn(hw, TXCOMPLFID), hermes_read_regn(hw, EVSTAT));
+	printk(KERN_WARNING "%s: Tx timeout! "
+	       "ALLOCFID=%04x, TXCOMPLFID=%04x, EVSTAT=%04x\n",
+	       dev->name, hermes_read_regn(hw, ALLOCFID),
+	       hermes_read_regn(hw, TXCOMPLFID), hermes_read_regn(hw, EVSTAT));
 
 	stats->tx_errors++;
 
-	err = orinoco_reset(priv);
-	if (err)
-		printk(KERN_ERR "%s: Error %d resetting card on Tx timeout!\n",
-		       dev->name, err);
-	else {
-		dev->trans_start = jiffies;
-		netif_wake_queue(dev);
-	}
+	schedule_task(&priv->timeout_task);
 }
 
 static int
 orinoco_change_mtu(struct net_device *dev, int new_mtu)
 {
 	struct orinoco_private *priv = dev->priv;
-	TRACE_ENTER(dev->name);
 
 	if ( (new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU) )
 		return -EINVAL;
@@ -2065,11 +2379,10 @@
 
 	dev->mtu = new_mtu;
 
-	TRACE_EXIT(dev->name);
-
 	return 0;
 }
 
+/* FIXME: return int? */
 static void
 __orinoco_set_multicast_list(struct net_device *dev)
 {
@@ -2078,17 +2391,6 @@
 	int err = 0;
 	int promisc, mc_count;
 
-	/* We'll wait until it's ready. Anyway, the network doesn't call us
-	 * here until we are open - Jean II */
-	/* FIXME: do we need this test at all? */
-	if (! netif_device_present(dev)) {
-		printk(KERN_WARNING "%s: __orinoco_set_multicast_list() called while device "
-		       "not present.\n", dev->name);
-		return;
-	}
-
-	TRACE_ENTER(dev->name);
-
 	/* The Hermes doesn't seem to have an allmulti mode, so we go
 	 * into promiscuous mode and let the upper levels deal. */
 	if ( (dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) ||
@@ -2146,8 +2448,6 @@
 		dev->flags |= IFF_PROMISC;
 	else
 		dev->flags &= ~IFF_PROMISC;
-
-	TRACE_EXIT(dev->name);
 }
 
 /********************************************************************/
@@ -2162,6 +2462,7 @@
 	struct iw_range range;
 	int numrates;
 	int i, k;
+	unsigned long flags;
 
 	TRACE_ENTER(dev->name);
 
@@ -2171,9 +2472,12 @@
 
 	rrq->length = sizeof(range);
 
-	orinoco_lock(priv);
+	err = orinoco_lock(priv, &flags);
+	if (err)
+		return err;
+
 	mode = priv->iw_mode;
-	orinoco_unlock(priv);
+	orinoco_unlock(priv, &flags);
 
 	memset(&range, 0, sizeof(range));
 
@@ -2246,7 +2550,9 @@
 	range.min_frag = 256;
 	range.max_frag = 2346;
 
-	orinoco_lock(priv);
+	err = orinoco_lock(priv, &flags);
+	if (err)
+		return err;
 	if (priv->has_wep) {
 		range.max_encoding_tokens = ORINOCO_MAX_KEYS;
 
@@ -2261,7 +2567,7 @@
 		range.num_encoding_sizes = 0;
 		range.max_encoding_tokens = 0;
 	}
-	orinoco_unlock(priv);
+	orinoco_unlock(priv, &flags);
 		
 	range.min_pmp = 0;
 	range.max_pmp = 65535000;
@@ -2303,6 +2609,7 @@
 	u16 xlen = 0;
 	int err = 0;
 	char keybuf[ORINOCO_MAX_KEY_SIZE];
+	unsigned long flags;
 	
 	if (erq->pointer) {
 		/* We actually have a key to set */
@@ -2313,7 +2620,9 @@
 			return -EFAULT;
 	}
 	
-	orinoco_lock(priv);
+	err = orinoco_lock(priv, &flags);
+	if (err)
+		return err;
 	
 	if (erq->pointer) {
 		if (erq->length > ORINOCO_MAX_KEY_SIZE) {
@@ -2377,9 +2686,10 @@
 	priv->tx_key = setindex;
 	priv->wep_on = enable;
 	priv->wep_restrict = restricted;
+
 	
  out:
-	orinoco_unlock(priv);
+	orinoco_unlock(priv, &flags);
 
 	return err;
 }
@@ -2390,9 +2700,12 @@
 	int index = (erq->flags & IW_ENCODE_INDEX) - 1;
 	u16 xlen = 0;
 	char keybuf[ORINOCO_MAX_KEY_SIZE];
-
+	int err;
+	unsigned long flags;
 	
-	orinoco_lock(priv);
+	err = orinoco_lock(priv, &flags);
+	if (err)
+		return err;
 
 	if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
 		index = priv->tx_key;
@@ -2418,7 +2731,7 @@
 		memcpy(keybuf, priv->keys[index].data, ORINOCO_MAX_KEY_SIZE);
 	}
 	
-	orinoco_unlock(priv);
+	orinoco_unlock(priv, &flags);
 
 	if (erq->pointer) {
 		if (copy_to_user(erq->pointer, keybuf, xlen))
@@ -2432,6 +2745,8 @@
 {
 	struct orinoco_private *priv = dev->priv;
 	char essidbuf[IW_ESSID_MAX_SIZE+1];
+	int err;
+	unsigned long flags;
 
 	/* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it
 	 * anyway... - Jean II */
@@ -2448,11 +2763,13 @@
 		essidbuf[erq->length] = '\0';
 	}
 
-	orinoco_lock(priv);
+	err = orinoco_lock(priv, &flags);
+	if (err)
+		return err;
 
 	memcpy(priv->desired_essid, essidbuf, sizeof(priv->desired_essid));
 
-	orinoco_unlock(priv);
+	orinoco_unlock(priv, &flags);
 
 	return 0;
 }
@@ -2463,6 +2780,7 @@
 	char essidbuf[IW_ESSID_MAX_SIZE+1];
 	int active;
 	int err = 0;
+	unsigned long flags;
 
 	TRACE_ENTER(dev->name);
 
@@ -2471,9 +2789,11 @@
 		if (err)
 			return err;
 	} else {
-		orinoco_lock(priv);
+		err = orinoco_lock(priv, &flags);
+		if (err)
+			return err;
 		memcpy(essidbuf, priv->desired_essid, sizeof(essidbuf));
-		orinoco_unlock(priv);
+		orinoco_unlock(priv, &flags);
 	}
 
 	erq->flags = 1;
@@ -2491,6 +2811,8 @@
 {
 	struct orinoco_private *priv = dev->priv;
 	char nickbuf[IW_ESSID_MAX_SIZE+1];
+	int err;
+	unsigned long flags;
 
 	if (nrq->length > IW_ESSID_MAX_SIZE)
 		return -E2BIG;
@@ -2502,11 +2824,13 @@
 
 	nickbuf[nrq->length] = '\0';
 	
-	orinoco_lock(priv);
+	err = orinoco_lock(priv, &flags);
+	if (err)
+		return err;
 
 	memcpy(priv->nick, nickbuf, sizeof(priv->nick));
 
-	orinoco_unlock(priv);
+	orinoco_unlock(priv, &flags);
 
 	return 0;
 }
@@ -2515,10 +2839,15 @@
 {
 	struct orinoco_private *priv = dev->priv;
 	char nickbuf[IW_ESSID_MAX_SIZE+1];
+	int err;
+	unsigned long flags;
+
+	err = orinoco_lock(priv, &flags);
+	if (err)
+		return err;
 
-	orinoco_lock(priv);
 	memcpy(nickbuf, priv->nick, IW_ESSID_MAX_SIZE+1);
-	orinoco_unlock(priv);
+	orinoco_unlock(priv, &flags);
 
 	nrq->length = strlen(nickbuf)+1;
 
@@ -2532,6 +2861,8 @@
 {
 	struct orinoco_private *priv = dev->priv;
 	int chan = -1;
+	int err;
+	unsigned long flags;
 
 	/* We can only use this in Ad-Hoc demo mode to set the operating
 	 * frequency, or in IBSS mode to set the frequency where the IBSS
@@ -2559,9 +2890,11 @@
 	     ! (priv->channel_mask & (1 << (chan-1)) ) )
 		return -EINVAL;
 
-	orinoco_lock(priv);
+	err = orinoco_lock(priv, &flags);
+	if (err)
+		return err;
 	priv->channel = chan;
-	orinoco_unlock(priv);
+	orinoco_unlock(priv, &flags);
 
 	return 0;
 }
@@ -2572,13 +2905,16 @@
 	hermes_t *hw = &priv->hw;
 	u16 val;
 	int err;
+	unsigned long flags;
 
 	if (!priv->has_sensitivity)
 		return -EOPNOTSUPP;
 
-	orinoco_lock(priv);
+	err = orinoco_lock(priv, &flags);
+	if (err)
+		return err;
 	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE, &val);
-	orinoco_unlock(priv);
+	orinoco_unlock(priv, &flags);
 
 	if (err)
 		return err;
@@ -2593,6 +2929,8 @@
 {
 	struct orinoco_private *priv = dev->priv;
 	int val = srq->value;
+	int err;
+	unsigned long flags;
 
 	if (!priv->has_sensitivity)
 		return -EOPNOTSUPP;
@@ -2600,9 +2938,11 @@
 	if ((val < 1) || (val > 3))
 		return -EINVAL;
 	
-	orinoco_lock(priv);
+	err = orinoco_lock(priv, &flags);
+	if (err)
+		return err;
 	priv->ap_density = val;
-	orinoco_unlock(priv);
+	orinoco_unlock(priv, &flags);
 
 	return 0;
 }
@@ -2611,6 +2951,8 @@
 {
 	struct orinoco_private *priv = dev->priv;
 	int val = rrq->value;
+	int err;
+	unsigned long flags;
 
 	if (rrq->disabled)
 		val = 2347;
@@ -2618,9 +2960,12 @@
 	if ( (val < 0) || (val > 2347) )
 		return -EINVAL;
 
-	orinoco_lock(priv);
+	err = orinoco_lock(priv, &flags);
+	if (err)
+		return err;
+
 	priv->rts_thresh = val;
-	orinoco_unlock(priv);
+	orinoco_unlock(priv, &flags);
 
 	return 0;
 }
@@ -2629,8 +2974,11 @@
 {
 	struct orinoco_private *priv = dev->priv;
 	int err = 0;
+	unsigned long flags;
 
-	orinoco_lock(priv);
+	err = orinoco_lock(priv, &flags);
+	if (err)
+		return err;
 
 	if (priv->has_mwo) {
 		if (frq->disabled)
@@ -2652,7 +3000,7 @@
 		}
 	}
 
-	orinoco_unlock(priv);
+	orinoco_unlock(priv, &flags);
 
 	return err;
 }
@@ -2663,8 +3011,11 @@
 	hermes_t *hw = &priv->hw;
 	int err = 0;
 	u16 val;
+	unsigned long flags;
 
-	orinoco_lock(priv);
+	err = orinoco_lock(priv, &flags);
+	if (err)
+		return err;
 	
 	if (priv->has_mwo) {
 		err = hermes_read_wordrec(hw, USER_BAP,
@@ -2687,7 +3038,7 @@
 		frq->fixed = 1;
 	}
 
-	orinoco_unlock(priv);
+	orinoco_unlock(priv, &flags);
 	
 	return err;
 }
@@ -2699,6 +3050,7 @@
 	int ratemode = -1;
 	int bitrate; /* 100s of kilobits */
 	int i;
+	unsigned long flags;
 	
 	/* As the user space doesn't know our highest rate, it uses -1
 	 * to ask us to set the highest rate.  Test it using "iwconfig
@@ -2725,9 +3077,11 @@
 	if (ratemode == -1)
 		return -EINVAL;
 
-	orinoco_lock(priv);
+	err = orinoco_lock(priv, &flags);
+	if (err)
+		return err;
 	priv->bitratemode = ratemode;
-	orinoco_unlock(priv);
+	orinoco_unlock(priv, &flags);
 
 	return err;
 }
@@ -2740,12 +3094,15 @@
 	int ratemode;
 	int i;
 	u16 val;
+	unsigned long flags;
 
-	orinoco_lock(priv);
+	err = orinoco_lock(priv, &flags);
+	if (err)
+		return err;
 
 	ratemode = priv->bitratemode;
 
-	if ( (ratemode < 0) || (ratemode > BITRATE_TABLE_SIZE) )
+	if ( (ratemode < 0) || (ratemode >= BITRATE_TABLE_SIZE) )
 		BUG();
 
 	rrq->value = bitrate_table[ratemode].bitrate * 100000;
@@ -2791,7 +3148,7 @@
 	}
 
  out:
-	orinoco_unlock(priv);
+	orinoco_unlock(priv, &flags);
 
 	return err;
 }
@@ -2800,9 +3157,11 @@
 {
 	struct orinoco_private *priv = dev->priv;
 	int err = 0;
+	unsigned long flags;
 
-
-	orinoco_lock(priv);
+	err = orinoco_lock(priv, &flags);
+	if (err)
+		return err;
 
 	if (prq->disabled) {
 		priv->pm_on = 0;
@@ -2842,7 +3201,7 @@
 	}
 
  out:
-	orinoco_unlock(priv);
+	orinoco_unlock(priv, &flags);
 
 	return err;
 }
@@ -2853,8 +3212,11 @@
 	hermes_t *hw = &priv->hw;
 	int err = 0;
 	u16 enable, period, timeout, mcast;
+	unsigned long flags;
 
-	orinoco_lock(priv);
+	err = orinoco_lock(priv, &flags);
+	if (err)
+		return err;
 	
 	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFPMENABLED, &enable);
 	if (err)
@@ -2888,7 +3250,7 @@
 		prq->flags |= IW_POWER_UNICAST_R;
 
  out:
-	orinoco_unlock(priv);
+	orinoco_unlock(priv, &flags);
 
 	return err;
 }
@@ -2900,8 +3262,11 @@
 	hermes_t *hw = &priv->hw;
 	int err = 0;
 	u16 short_limit, long_limit, lifetime;
+	unsigned long flags;
 
-	orinoco_lock(priv);
+	err = orinoco_lock(priv, &flags);
+	if (err)
+		return err;
 	
 	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_SHORTRETRYLIMIT,
 				  &short_limit);
@@ -2938,7 +3303,7 @@
 	}
 
  out:
-	orinoco_unlock(priv);
+	orinoco_unlock(priv, &flags);
 
 	return err;
 }
@@ -2948,14 +3313,19 @@
 {
 	struct orinoco_private *priv = dev->priv;
 	int val = *( (int *) wrq->u.name );
+	int err;
+	unsigned long flags;
+
+	err = orinoco_lock(priv, &flags);
+	if (err)
+		return err;
 
-	orinoco_lock(priv);
 	priv->ibss_port = val ;
 
 	/* Actually update the mode we are using */
 	set_port_type(priv);
 
-	orinoco_unlock(priv);
+	orinoco_unlock(priv, &flags);
 	return 0;
 }
 
@@ -2963,10 +3333,15 @@
 {
 	struct orinoco_private *priv = dev->priv;
 	int *val = (int *)wrq->u.name;
+	int err;
+	unsigned long flags;
+
+	err = orinoco_lock(priv, &flags);
+	if (err)
+		return err;
 
-	orinoco_lock(priv);
 	*val = priv->ibss_port;
-	orinoco_unlock(priv);
+	orinoco_unlock(priv, &flags);
 
 	return 0;
 }
@@ -2976,15 +3351,18 @@
 	struct orinoco_private *priv = dev->priv;
 	int val = *( (int *) wrq->u.name );
 	int err = 0;
+	unsigned long flags;
+
+	err = orinoco_lock(priv, &flags);
+	if (err)
+		return err;
 
-	orinoco_lock(priv);
 	switch (val) {
 	case 0: /* Try to do IEEE ad-hoc mode */
 		if (! priv->has_ibss) {
 			err = -EINVAL;
 			break;
 		}
-		DEBUG(2, "%s: Prefer IBSS Ad-Hoc mode\n", dev->name);
 		priv->prefer_port3 = 0;
 			
 		break;
@@ -2994,7 +3372,6 @@
 			err = -EINVAL;
 			break;
 		}
-		DEBUG(2, "%s: Prefer Ad-Hoc demo mode\n", dev->name);
 		priv->prefer_port3 = 1;
 		break;
 
@@ -3006,7 +3383,7 @@
 		/* Actually update the mode we are using */
 		set_port_type(priv);
 
-	orinoco_unlock(priv);
+	orinoco_unlock(priv, &flags);
 
 	return err;
 }
@@ -3015,10 +3392,15 @@
 {
 	struct orinoco_private *priv = dev->priv;
 	int *val = (int *)wrq->u.name;
+	int err;
+	unsigned long flags;
+
+	err = orinoco_lock(priv, &flags);
+	if (err)
+		return err;
 
-	orinoco_lock(priv);
 	*val = priv->prefer_port3;
-	orinoco_unlock(priv);
+	orinoco_unlock(priv, &flags);
 
 	return 0;
 }
@@ -3032,6 +3414,7 @@
 	int number = srq->length;
 	int i;
 	int err = 0;
+	unsigned long flags;
 
 	/* Check the number of addresses */
 	if (number > IW_MAX_SPY)
@@ -3045,7 +3428,9 @@
 	}
 
 	/* Make sure nobody mess with the structure while we do */
-	orinoco_lock(priv);
+	err = orinoco_lock(priv, &flags);
+	if (err)
+		return err;
 
 	/* orinoco_lock() doesn't disable interrupts, so make sure the
 	 * interrupt rx path don't get confused while we copy */
@@ -3063,18 +3448,8 @@
 		priv->spy_number = number;
 	}
 
-	/* Time to show what we have done... */
-	DEBUG(0, "%s: New spy list:\n", dev->name);
-	for (i = 0; i < number; i++) {
-		DEBUG(0, "%s: %d - %02x:%02x:%02x:%02x:%02x:%02x\n",
-		      dev->name, i+1,
-		      priv->spy_address[i][0], priv->spy_address[i][1],
-		      priv->spy_address[i][2], priv->spy_address[i][3],
-		      priv->spy_address[i][4], priv->spy_address[i][5]);
-	}
-
 	/* Now, let the others play */
-	orinoco_unlock(priv);
+	orinoco_unlock(priv, &flags);
 
 	return err;
 }
@@ -3086,8 +3461,12 @@
 	struct iw_quality spy_stat[IW_MAX_SPY];
 	int number;
 	int i;
+	int err;
+	unsigned long flags;
 
-	orinoco_lock(priv);
+	err = orinoco_lock(priv, &flags);
+	if (err)
+		return err;
 
 	number = priv->spy_number;
 	if ((number > 0) && (srq->pointer)) {
@@ -3107,7 +3486,7 @@
 			priv->spy_stat[i].updated = 0;
 	}
 
-	orinoco_unlock(priv);
+	orinoco_unlock(priv, &flags);
 
 	/* Push stuff to user space */
 	srq->length = number;
@@ -3127,39 +3506,39 @@
 	struct orinoco_private *priv = dev->priv;
 	struct iwreq *wrq = (struct iwreq *)rq;
 	int err = 0;
+	int tmp;
 	int changed = 0;
+	unsigned long flags;
 
 	TRACE_ENTER(dev->name);
 
 	/* In theory, we could allow most of the the SET stuff to be
-	 * done In practice, the laps of time at startup when the card
-	 * is not ready is very short, so why bother...  Note that
-	 * netif_device_present is different from up/down (ifconfig),
-	 * when the device is not yet up, it is usually already
-	 * ready...  Jean II */
+	 * done. In practice, the lapse of time at startup when the
+	 * card is not ready is very short, so why bother...  Note
+	 * that netif_device_present is different from up/down
+	 * (ifconfig), when the device is not yet up, it is usually
+	 * already ready...  Jean II */
 	if (! netif_device_present(dev))
 		return -ENODEV;
 
 	switch (cmd) {
 	case SIOCGIWNAME:
-		DEBUG(1, "%s: SIOCGIWNAME\n", dev->name);
 		strcpy(wrq->u.name, "IEEE 802.11-DS");
 		break;
 		
 	case SIOCGIWAP:
-		DEBUG(1, "%s: SIOCGIWAP\n", dev->name);
 		wrq->u.ap_addr.sa_family = ARPHRD_ETHER;
 		err = orinoco_hw_get_bssid(priv, wrq->u.ap_addr.sa_data);
 		break;
 
 	case SIOCGIWRANGE:
-		DEBUG(1, "%s: SIOCGIWRANGE\n", dev->name);
 		err = orinoco_ioctl_getiwrange(dev, &wrq->u.data);
 		break;
 
 	case SIOCSIWMODE:
-		DEBUG(1, "%s: SIOCSIWMODE\n", dev->name);
-		orinoco_lock(priv);
+		err = orinoco_lock(priv, &flags);
+		if (err)
+			return err;
 		switch (wrq->u.mode) {
 		case IW_MODE_ADHOC:
 			if (! (priv->has_ibss || priv->has_port3) )
@@ -3180,18 +3559,18 @@
 			break;
 		}
 		set_port_type(priv);
-		orinoco_unlock(priv);
+		orinoco_unlock(priv, &flags);
 		break;
 
 	case SIOCGIWMODE:
-		DEBUG(1, "%s: SIOCGIWMODE\n", dev->name);
-		orinoco_lock(priv);
+		err = orinoco_lock(priv, &flags);
+		if (err)
+			return err;
 		wrq->u.mode = priv->iw_mode;
-		orinoco_unlock(priv);
+		orinoco_unlock(priv, &flags);
 		break;
 
 	case SIOCSIWENCODE:
-		DEBUG(1, "%s: SIOCSIWENCODE\n", dev->name);
 		if (! priv->has_wep) {
 			err = -EOPNOTSUPP;
 			break;
@@ -3203,7 +3582,6 @@
 		break;
 
 	case SIOCGIWENCODE:
-		DEBUG(1, "%s: SIOCGIWENCODE\n", dev->name);
 		if (! priv->has_wep) {
 			err = -EOPNOTSUPP;
 			break;
@@ -3218,106 +3596,94 @@
 		break;
 
 	case SIOCSIWESSID:
-		DEBUG(1, "%s: SIOCSIWESSID\n", dev->name);
 		err = orinoco_ioctl_setessid(dev, &wrq->u.essid);
 		if (! err)
 			changed = 1;
 		break;
 
 	case SIOCGIWESSID:
-		DEBUG(1, "%s: SIOCGIWESSID\n", dev->name);
 		err = orinoco_ioctl_getessid(dev, &wrq->u.essid);
 		break;
 
 	case SIOCSIWNICKN:
-		DEBUG(1, "%s: SIOCSIWNICKN\n", dev->name);
 		err = orinoco_ioctl_setnick(dev, &wrq->u.data);
 		if (! err)
 			changed = 1;
 		break;
 
 	case SIOCGIWNICKN:
-		DEBUG(1, "%s: SIOCGIWNICKN\n", dev->name);
 		err = orinoco_ioctl_getnick(dev, &wrq->u.data);
 		break;
 
 	case SIOCGIWFREQ:
-		DEBUG(1, "%s: SIOCGIWFREQ\n", dev->name);
-		wrq->u.freq.m = orinoco_hw_get_freq(priv);
-		wrq->u.freq.e = 1;
+		tmp = orinoco_hw_get_freq(priv);
+		if (tmp < 0) {
+			err = tmp;
+		} else {
+			wrq->u.freq.m = tmp;
+			wrq->u.freq.e = 1;
+		}
 		break;
 
 	case SIOCSIWFREQ:
-		DEBUG(1, "%s: SIOCSIWFREQ\n", dev->name);
 		err = orinoco_ioctl_setfreq(dev, &wrq->u.freq);
 		if (! err)
 			changed = 1;
 		break;
 
 	case SIOCGIWSENS:
-		DEBUG(1, "%s: SIOCGIWSENS\n", dev->name);
 		err = orinoco_ioctl_getsens(dev, &wrq->u.sens);
 		break;
 
 	case SIOCSIWSENS:
-		DEBUG(1, "%s: SIOCSIWSENS\n", dev->name);
 		err = orinoco_ioctl_setsens(dev, &wrq->u.sens);
 		if (! err)
 			changed = 1;
 		break;
 
 	case SIOCGIWRTS:
-		DEBUG(1, "%s: SIOCGIWRTS\n", dev->name);
 		wrq->u.rts.value = priv->rts_thresh;
 		wrq->u.rts.disabled = (wrq->u.rts.value == 2347);
 		wrq->u.rts.fixed = 1;
 		break;
 
 	case SIOCSIWRTS:
-		DEBUG(1, "%s: SIOCSIWRTS\n", dev->name);
 		err = orinoco_ioctl_setrts(dev, &wrq->u.rts);
 		if (! err)
 			changed = 1;
 		break;
 
 	case SIOCSIWFRAG:
-		DEBUG(1, "%s: SIOCSIWFRAG\n", dev->name);
 		err = orinoco_ioctl_setfrag(dev, &wrq->u.frag);
 		if (! err)
 			changed = 1;
 		break;
 
 	case SIOCGIWFRAG:
-		DEBUG(1, "%s: SIOCGIWFRAG\n", dev->name);
 		err = orinoco_ioctl_getfrag(dev, &wrq->u.frag);
 		break;
 
 	case SIOCSIWRATE:
-		DEBUG(1, "%s: SIOCSIWRATE\n", dev->name);
 		err = orinoco_ioctl_setrate(dev, &wrq->u.bitrate);
 		if (! err)
 			changed = 1;
 		break;
 
 	case SIOCGIWRATE:
-		DEBUG(1, "%s: SIOCGIWRATE\n", dev->name);
 		err = orinoco_ioctl_getrate(dev, &wrq->u.bitrate);
 		break;
 
 	case SIOCSIWPOWER:
-		DEBUG(1, "%s: SIOCSIWPOWER\n", dev->name);
 		err = orinoco_ioctl_setpower(dev, &wrq->u.power);
 		if (! err)
 			changed = 1;
 		break;
 
 	case SIOCGIWPOWER:
-		DEBUG(1, "%s: SIOCGIWPOWER\n", dev->name);
 		err = orinoco_ioctl_getpower(dev, &wrq->u.power);
 		break;
 
 	case SIOCGIWTXPOW:
-		DEBUG(1, "%s: SIOCGIWTXPOW\n", dev->name);
 		/* The card only supports one tx power, so this is easy */
 		wrq->u.txpower.value = 15; /* dBm */
 		wrq->u.txpower.fixed = 1;
@@ -3327,30 +3693,23 @@
 
 #if WIRELESS_EXT > 10
 	case SIOCSIWRETRY:
-		DEBUG(1, "%s: SIOCSIWRETRY\n", dev->name);
 		err = -EOPNOTSUPP;
 		break;
 
 	case SIOCGIWRETRY:
-		DEBUG(1, "%s: SIOCGIWRETRY\n", dev->name);
 		err = orinoco_ioctl_getretry(dev, &wrq->u.retry);
 		break;
 #endif /* WIRELESS_EXT > 10 */
 
 	case SIOCSIWSPY:
-		DEBUG(1, "%s: SIOCSIWSPY\n", dev->name);
-
 		err = orinoco_ioctl_setspy(dev, &wrq->u.data);
 		break;
 
 	case SIOCGIWSPY:
-		DEBUG(1, "%s: SIOCGIWSPY\n", dev->name);
-
 		err = orinoco_ioctl_getspy(dev, &wrq->u.data);
 		break;
 
 	case SIOCGIWPRIV:
-		DEBUG(1, "%s: SIOCGIWPRIV\n", dev->name);
 		if (wrq->u.data.pointer) {
 			struct iw_priv_args privtab[] = {
 				{ SIOCIWFIRSTPRIV + 0x0, 0, 0, "force_reset" },
@@ -3372,7 +3731,8 @@
 				  0, "set_ibssport" },
 				{ SIOCIWFIRSTPRIV + 0x7, 0,
 				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-				  "get_ibssport" }
+				  "get_ibssport" },
+				{ SIOCIWLASTPRIV, 0, 0, "dump_recs" },
 			};
 
 			err = verify_area(VERIFY_WRITE, wrq->u.data.pointer, sizeof(privtab));
@@ -3387,25 +3747,17 @@
 	       
 	case SIOCIWFIRSTPRIV + 0x0: /* force_reset */
 	case SIOCIWFIRSTPRIV + 0x1: /* card_reset */
-		DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x0 (force_reset)\n",
-		      dev->name);
 		if (! capable(CAP_NET_ADMIN)) {
 			err = -EPERM;
 			break;
 		}
 		
-		printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name);
+		printk(KERN_DEBUG "%s: Force scheduling reset!\n", dev->name);
 
-		/* We need the xmit lock because it protects the
-		   multicast list which orinoco_reset() reads */
-		spin_lock_bh(&dev->xmit_lock);
-		orinoco_reset(priv);
-		spin_unlock_bh(&dev->xmit_lock);
+		schedule_task(&priv->timeout_task);
 		break;
 
 	case SIOCIWFIRSTPRIV + 0x2: /* set_port3 */
-		DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x2 (set_port3)\n",
-		      dev->name);
 		if (! capable(CAP_NET_ADMIN)) {
 			err = -EPERM;
 			break;
@@ -3417,14 +3769,10 @@
 		break;
 
 	case SIOCIWFIRSTPRIV + 0x3: /* get_port3 */
-		DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x3 (get_port3)\n",
-		      dev->name);
 		err = orinoco_ioctl_getport3(dev, wrq);
 		break;
 
 	case SIOCIWFIRSTPRIV + 0x4: /* set_preamble */
-		DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x4 (set_preamble)\n",
-		      dev->name);
 		if (! capable(CAP_NET_ADMIN)) {
 			err = -EPERM;
 			break;
@@ -3438,32 +3786,32 @@
 		if(priv->has_preamble) {
 			int val = *( (int *) wrq->u.name );
 
-			orinoco_lock(priv);
-			if(val)
+			err = orinoco_lock(priv, &flags);
+			if (err)
+				return err;
+			if (val)
 				priv->preamble = 1;
 			else
 				priv->preamble = 0;
-			orinoco_unlock(priv);
+			orinoco_unlock(priv, &flags);
 			changed = 1;
 		} else
 			err = -EOPNOTSUPP;
 		break;
 
 	case SIOCIWFIRSTPRIV + 0x5: /* get_preamble */
-		DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x5 (get_preamble)\n",
-		      dev->name);
 		if(priv->has_preamble) {
 			int *val = (int *)wrq->u.name;
 
-			orinoco_lock(priv);
+			err = orinoco_lock(priv, &flags);
+			if (err)
+				return err;
 			*val = priv->preamble;
-			orinoco_unlock(priv);
+			orinoco_unlock(priv, &flags);
 		} else
 			err = -EOPNOTSUPP;
 		break;
 	case SIOCIWFIRSTPRIV + 0x6: /* set_ibssport */
-		DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x6 (set_ibssport)\n",
-		      dev->name);
 		if (! capable(CAP_NET_ADMIN)) {
 			err = -EPERM;
 			break;
@@ -3475,109 +3823,28 @@
 		break;
 
 	case SIOCIWFIRSTPRIV + 0x7: /* get_ibssport */
-		DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x7 (get_ibssport)\n",
-		      dev->name);
 		err = orinoco_ioctl_getibssport(dev, wrq);
 		break;
 
+	case SIOCIWLASTPRIV:
+		err = orinoco_debug_dump_recs(priv);
+		if (err)
+			printk(KERN_ERR "%s: Unable to dump records (%d)\n",
+			       dev->name, err);
+		break;
+
 
 	default:
 		err = -EOPNOTSUPP;
 	}
 	
 	if (! err && changed && netif_running(dev)) {
-		/* We need the xmit lock because it protects the
-		   multicast list which orinoco_reset() reads */
-		spin_lock_bh(&dev->xmit_lock);
-		err = orinoco_reset(priv);
-		spin_unlock_bh(&dev->xmit_lock);
-		if (err) {
-			/* Ouch ! What are we supposed to do ? */
-			printk(KERN_ERR "orinoco_cs: Failed to set parameters on %s\n",
-			       dev->name);
-			netif_device_detach(dev);
-			orinoco_shutdown(priv);
-		}
+		err = orinoco_reconfigure(priv);
 	}		
 
 	TRACE_EXIT(dev->name);
-		
-	return err;
-}
-
-/********************************************************************/
-/* procfs stuff                                                     */
-/********************************************************************/
-
-static struct proc_dir_entry *dir_base = NULL;
-
-#define PROC_LTV_SIZE		128
-
-/*
- * This function updates the total amount of data printed so far. It then
- * determines if the amount of data printed into a buffer  has reached the
- * offset requested. If it hasn't, then the buffer is shifted over so that
- * the next bit of data can be printed over the old bit. If the total
- * amount printed so far exceeds the total amount requested, then this
- * function returns 1, otherwise 0.
- */
-static int 
-shift_buffer(char *buffer, int requested_offset, int requested_len,
-	     int *total, int *slop, char **buf)
-{
-	int printed;
-	
-	printed = *buf - buffer;
-	if (*total + printed <= requested_offset) {
-		*total += printed;
-		*buf = buffer;
-	}
-	else {
-		if (*total < requested_offset) {
-			*slop = requested_offset - *total;
-		}
-		*total = requested_offset + printed - *slop;
-	}
-	if (*total > requested_offset + requested_len) {
-		return 1;
-	}
-	else {
-		return 0;
-	}
-}
-
-/*
- * This function calculates the actual start of the requested data
- * in the buffer. It also calculates actual length of data returned,
- * which could be less that the amount of data requested.
- */
-#define PROC_BUFFER_SIZE 4096
-#define PROC_SAFE_SIZE 3072
 
-static int
-calc_start_len(char *buffer, char **start, int requested_offset,
-	       int requested_len, int total, char *buf)
-{
-	int return_len, buffer_len;
-	
-	buffer_len = buf - buffer;
-	if (buffer_len >= PROC_BUFFER_SIZE - 1) {
-		printk(KERN_ERR "calc_start_len: exceeded /proc buffer size\n");
-	}
-	
-	/*
-	 * There may be bytes before and after the
-	 * chunk that was actually requested.
-	 */
-	return_len = total - requested_offset;
-	if (return_len < 0) {
-		return_len = 0;
-	}
-	*start = buf - return_len;
-	if (return_len > requested_len) {
-		return_len = requested_len;
-	}
-	return return_len;
+	return err;
 }
 
 struct {
@@ -3589,140 +3856,134 @@
 #define DISPLAY_STRING	2
 #define DISPLAY_XSTRING	3
 } record_table[] = {
-#define PROC_REC(name,type) { HERMES_RID_##name, #name, DISPLAY_##type }
-	PROC_REC(CNFPORTTYPE,WORDS),
-	PROC_REC(CNFOWNMACADDR,BYTES),
-	PROC_REC(CNFDESIREDSSID,STRING),
-	PROC_REC(CNFOWNCHANNEL,WORDS),
-	PROC_REC(CNFOWNSSID,STRING),
-	PROC_REC(CNFOWNATIMWINDOW,WORDS),
-	PROC_REC(CNFSYSTEMSCALE,WORDS),
-	PROC_REC(CNFMAXDATALEN,WORDS),
-	PROC_REC(CNFPMENABLED,WORDS),
-	PROC_REC(CNFPMEPS,WORDS),
-	PROC_REC(CNFMULTICASTRECEIVE,WORDS),
-	PROC_REC(CNFMAXSLEEPDURATION,WORDS),
-	PROC_REC(CNFPMHOLDOVERDURATION,WORDS),
-	PROC_REC(CNFOWNNAME,STRING),
-	PROC_REC(CNFOWNDTIMPERIOD,WORDS),
-	PROC_REC(CNFMULTICASTPMBUFFERING,WORDS),
-	PROC_REC(CNFWEPENABLED_AGERE,WORDS),
-	PROC_REC(CNFMANDATORYBSSID_SYMBOL,WORDS),
-	PROC_REC(CNFWEPDEFAULTKEYID,WORDS),
-	PROC_REC(CNFDEFAULTKEY0,BYTES),
-	PROC_REC(CNFDEFAULTKEY1,BYTES),
-	PROC_REC(CNFMWOROBUST_AGERE,WORDS),
-	PROC_REC(CNFDEFAULTKEY2,BYTES),
-	PROC_REC(CNFDEFAULTKEY3,BYTES),
-	PROC_REC(CNFWEPFLAGS_INTERSIL,WORDS),
-	PROC_REC(CNFWEPKEYMAPPINGTABLE,WORDS),
-	PROC_REC(CNFAUTHENTICATION,WORDS),
-	PROC_REC(CNFMAXASSOCSTA,WORDS),
-	PROC_REC(CNFKEYLENGTH_SYMBOL,WORDS),
-	PROC_REC(CNFTXCONTROL,WORDS),
-	PROC_REC(CNFROAMINGMODE,WORDS),
-	PROC_REC(CNFHOSTAUTHENTICATION,WORDS),
-	PROC_REC(CNFRCVCRCERROR,WORDS),
-	PROC_REC(CNFMMLIFE,WORDS),
-	PROC_REC(CNFALTRETRYCOUNT,WORDS),
-	PROC_REC(CNFBEACONINT,WORDS),
-	PROC_REC(CNFAPPCFINFO,WORDS),
-	PROC_REC(CNFSTAPCFINFO,WORDS),
-	PROC_REC(CNFPRIORITYQUSAGE,WORDS),
-	PROC_REC(CNFTIMCTRL,WORDS),
-	PROC_REC(CNFTHIRTY2TALLY,WORDS),
-	PROC_REC(CNFENHSECURITY,WORDS),
-	PROC_REC(CNFGROUPADDRESSES,BYTES),
-	PROC_REC(CNFCREATEIBSS,WORDS),
-	PROC_REC(CNFFRAGMENTATIONTHRESHOLD,WORDS),
-	PROC_REC(CNFRTSTHRESHOLD,WORDS),
-	PROC_REC(CNFTXRATECONTROL,WORDS),
-	PROC_REC(CNFPROMISCUOUSMODE,WORDS),
-	PROC_REC(CNFBASICRATES_SYMBOL,WORDS),
-	PROC_REC(CNFPREAMBLE_SYMBOL,WORDS),
-	PROC_REC(CNFSHORTPREAMBLE,WORDS),
-	PROC_REC(CNFWEPKEYS_AGERE,BYTES),
-	PROC_REC(CNFEXCLUDELONGPREAMBLE,WORDS),
-	PROC_REC(CNFTXKEY_AGERE,WORDS),
-	PROC_REC(CNFAUTHENTICATIONRSPTO,WORDS),
-	PROC_REC(CNFBASICRATES,WORDS),
-	PROC_REC(CNFSUPPORTEDRATES,WORDS),
-	PROC_REC(CNFTICKTIME,WORDS),
-	PROC_REC(CNFSCANREQUEST,WORDS),
-	PROC_REC(CNFJOINREQUEST,WORDS),
-	PROC_REC(CNFAUTHENTICATESTATION,WORDS),
-	PROC_REC(CNFCHANNELINFOREQUEST,WORDS),
-	PROC_REC(MAXLOADTIME,WORDS),
-	PROC_REC(DOWNLOADBUFFER,WORDS),
-	PROC_REC(PRIID,WORDS),
-	PROC_REC(PRISUPRANGE,WORDS),
-	PROC_REC(CFIACTRANGES,WORDS),
-	PROC_REC(NICSERNUM,WORDS),
-	PROC_REC(NICID,WORDS),
-	PROC_REC(MFISUPRANGE,WORDS),
-	PROC_REC(CFISUPRANGE,WORDS),
-	PROC_REC(CHANNELLIST,WORDS),
-	PROC_REC(REGULATORYDOMAINS,WORDS),
-	PROC_REC(TEMPTYPE,WORDS),
-/*  	PROC_REC(CIS,BYTES), */
-	PROC_REC(STAID,WORDS),
-	PROC_REC(CURRENTSSID,STRING),
-	PROC_REC(CURRENTBSSID,BYTES),
-	PROC_REC(COMMSQUALITY,WORDS),
-	PROC_REC(CURRENTTXRATE,WORDS),
-	PROC_REC(CURRENTBEACONINTERVAL,WORDS),
-	PROC_REC(CURRENTSCALETHRESHOLDS,WORDS),
-	PROC_REC(PROTOCOLRSPTIME,WORDS),
-	PROC_REC(SHORTRETRYLIMIT,WORDS),
-	PROC_REC(LONGRETRYLIMIT,WORDS),
-	PROC_REC(MAXTRANSMITLIFETIME,WORDS),
-	PROC_REC(MAXRECEIVELIFETIME,WORDS),
-	PROC_REC(CFPOLLABLE,WORDS),
-	PROC_REC(AUTHENTICATIONALGORITHMS,WORDS),
-	PROC_REC(PRIVACYOPTIONIMPLEMENTED,WORDS),
-	PROC_REC(OWNMACADDR,BYTES),
-	PROC_REC(SCANRESULTSTABLE,WORDS),
-	PROC_REC(PHYTYPE,WORDS),
-	PROC_REC(CURRENTCHANNEL,WORDS),
-	PROC_REC(CURRENTPOWERSTATE,WORDS),
-	PROC_REC(CCAMODE,WORDS),
-	PROC_REC(SUPPORTEDDATARATES,WORDS),
-	PROC_REC(BUILDSEQ,BYTES),
-	PROC_REC(FWID,XSTRING)
-#undef PROC_REC
+#define DEBUG_REC(name,type) { HERMES_RID_##name, #name, DISPLAY_##type }
+	DEBUG_REC(CNFPORTTYPE,WORDS),
+	DEBUG_REC(CNFOWNMACADDR,BYTES),
+	DEBUG_REC(CNFDESIREDSSID,STRING),
+	DEBUG_REC(CNFOWNCHANNEL,WORDS),
+	DEBUG_REC(CNFOWNSSID,STRING),
+	DEBUG_REC(CNFOWNATIMWINDOW,WORDS),
+	DEBUG_REC(CNFSYSTEMSCALE,WORDS),
+	DEBUG_REC(CNFMAXDATALEN,WORDS),
+	DEBUG_REC(CNFPMENABLED,WORDS),
+	DEBUG_REC(CNFPMEPS,WORDS),
+	DEBUG_REC(CNFMULTICASTRECEIVE,WORDS),
+	DEBUG_REC(CNFMAXSLEEPDURATION,WORDS),
+	DEBUG_REC(CNFPMHOLDOVERDURATION,WORDS),
+	DEBUG_REC(CNFOWNNAME,STRING),
+	DEBUG_REC(CNFOWNDTIMPERIOD,WORDS),
+	DEBUG_REC(CNFMULTICASTPMBUFFERING,WORDS),
+	DEBUG_REC(CNFWEPENABLED_AGERE,WORDS),
+	DEBUG_REC(CNFMANDATORYBSSID_SYMBOL,WORDS),
+	DEBUG_REC(CNFWEPDEFAULTKEYID,WORDS),
+	DEBUG_REC(CNFDEFAULTKEY0,BYTES),
+	DEBUG_REC(CNFDEFAULTKEY1,BYTES),
+	DEBUG_REC(CNFMWOROBUST_AGERE,WORDS),
+	DEBUG_REC(CNFDEFAULTKEY2,BYTES),
+	DEBUG_REC(CNFDEFAULTKEY3,BYTES),
+	DEBUG_REC(CNFWEPFLAGS_INTERSIL,WORDS),
+	DEBUG_REC(CNFWEPKEYMAPPINGTABLE,WORDS),
+	DEBUG_REC(CNFAUTHENTICATION,WORDS),
+	DEBUG_REC(CNFMAXASSOCSTA,WORDS),
+	DEBUG_REC(CNFKEYLENGTH_SYMBOL,WORDS),
+	DEBUG_REC(CNFTXCONTROL,WORDS),
+	DEBUG_REC(CNFROAMINGMODE,WORDS),
+	DEBUG_REC(CNFHOSTAUTHENTICATION,WORDS),
+	DEBUG_REC(CNFRCVCRCERROR,WORDS),
+	DEBUG_REC(CNFMMLIFE,WORDS),
+	DEBUG_REC(CNFALTRETRYCOUNT,WORDS),
+	DEBUG_REC(CNFBEACONINT,WORDS),
+	DEBUG_REC(CNFAPPCFINFO,WORDS),
+	DEBUG_REC(CNFSTAPCFINFO,WORDS),
+	DEBUG_REC(CNFPRIORITYQUSAGE,WORDS),
+	DEBUG_REC(CNFTIMCTRL,WORDS),
+	DEBUG_REC(CNFTHIRTY2TALLY,WORDS),
+	DEBUG_REC(CNFENHSECURITY,WORDS),
+	DEBUG_REC(CNFGROUPADDRESSES,BYTES),
+	DEBUG_REC(CNFCREATEIBSS,WORDS),
+	DEBUG_REC(CNFFRAGMENTATIONTHRESHOLD,WORDS),
+	DEBUG_REC(CNFRTSTHRESHOLD,WORDS),
+	DEBUG_REC(CNFTXRATECONTROL,WORDS),
+	DEBUG_REC(CNFPROMISCUOUSMODE,WORDS),
+	DEBUG_REC(CNFBASICRATES_SYMBOL,WORDS),
+	DEBUG_REC(CNFPREAMBLE_SYMBOL,WORDS),
+	DEBUG_REC(CNFSHORTPREAMBLE,WORDS),
+	DEBUG_REC(CNFWEPKEYS_AGERE,BYTES),
+	DEBUG_REC(CNFEXCLUDELONGPREAMBLE,WORDS),
+	DEBUG_REC(CNFTXKEY_AGERE,WORDS),
+	DEBUG_REC(CNFAUTHENTICATIONRSPTO,WORDS),
+	DEBUG_REC(CNFBASICRATES,WORDS),
+	DEBUG_REC(CNFSUPPORTEDRATES,WORDS),
+	DEBUG_REC(CNFTICKTIME,WORDS),
+	DEBUG_REC(CNFSCANREQUEST,WORDS),
+	DEBUG_REC(CNFJOINREQUEST,WORDS),
+	DEBUG_REC(CNFAUTHENTICATESTATION,WORDS),
+	DEBUG_REC(CNFCHANNELINFOREQUEST,WORDS),
+	DEBUG_REC(MAXLOADTIME,WORDS),
+	DEBUG_REC(DOWNLOADBUFFER,WORDS),
+	DEBUG_REC(PRIID,WORDS),
+	DEBUG_REC(PRISUPRANGE,WORDS),
+	DEBUG_REC(CFIACTRANGES,WORDS),
+	DEBUG_REC(NICSERNUM,WORDS),
+	DEBUG_REC(NICID,WORDS),
+	DEBUG_REC(MFISUPRANGE,WORDS),
+	DEBUG_REC(CFISUPRANGE,WORDS),
+	DEBUG_REC(CHANNELLIST,WORDS),
+	DEBUG_REC(REGULATORYDOMAINS,WORDS),
+	DEBUG_REC(TEMPTYPE,WORDS),
+/*  	DEBUG_REC(CIS,BYTES), */
+	DEBUG_REC(STAID,WORDS),
+	DEBUG_REC(CURRENTSSID,STRING),
+	DEBUG_REC(CURRENTBSSID,BYTES),
+	DEBUG_REC(COMMSQUALITY,WORDS),
+	DEBUG_REC(CURRENTTXRATE,WORDS),
+	DEBUG_REC(CURRENTBEACONINTERVAL,WORDS),
+	DEBUG_REC(CURRENTSCALETHRESHOLDS,WORDS),
+	DEBUG_REC(PROTOCOLRSPTIME,WORDS),
+	DEBUG_REC(SHORTRETRYLIMIT,WORDS),
+	DEBUG_REC(LONGRETRYLIMIT,WORDS),
+	DEBUG_REC(MAXTRANSMITLIFETIME,WORDS),
+	DEBUG_REC(MAXRECEIVELIFETIME,WORDS),
+	DEBUG_REC(CFPOLLABLE,WORDS),
+	DEBUG_REC(AUTHENTICATIONALGORITHMS,WORDS),
+	DEBUG_REC(PRIVACYOPTIONIMPLEMENTED,WORDS),
+	DEBUG_REC(OWNMACADDR,BYTES),
+	DEBUG_REC(SCANRESULTSTABLE,WORDS),
+	DEBUG_REC(PHYTYPE,WORDS),
+	DEBUG_REC(CURRENTCHANNEL,WORDS),
+	DEBUG_REC(CURRENTPOWERSTATE,WORDS),
+	DEBUG_REC(CCAMODE,WORDS),
+	DEBUG_REC(SUPPORTEDDATARATES,WORDS),
+	DEBUG_REC(BUILDSEQ,BYTES),
+	DEBUG_REC(FWID,XSTRING)
+#undef DEBUG_REC
 };
-#define NUM_RIDS ( sizeof(record_table) / sizeof(record_table[0]) )
 
-static int
-orinoco_proc_get_hermes_recs(char *page, char **start, off_t requested_offset,
-			   int requested_len, int *eof, void *data)
+#define DEBUG_LTV_SIZE		128
+
+static int orinoco_debug_dump_recs(struct orinoco_private *priv)
 {
-	struct orinoco_private *priv = (struct orinoco_private *)data;
-	struct net_device *dev = priv->ndev;
 	hermes_t *hw = &priv->hw;
-	char *buf = page;
-	int total = 0, slop = 0;
 	u8 *val8;
 	u16 *val16;
 	int i,j;
 	u16 length;
 	int err;
 
-	if (! netif_device_present(dev))
-		return -ENODEV;
-
-	val8 = kmalloc(PROC_LTV_SIZE + 2, GFP_KERNEL);
+	/* I'm not sure: we might have a lock here, so we'd better go
+           atomic, just in case. */
+	val8 = kmalloc(DEBUG_LTV_SIZE + 2, GFP_ATOMIC);
 	if (! val8)
 		return -ENOMEM;
 	val16 = (u16 *)val8;
 
-	for (i = 0; i < NUM_RIDS; i++) {
+	for (i = 0; i < ARRAY_SIZE(record_table); i++) {
 		u16 rid = record_table[i].rid;
 		int len;
 
-		memset(val8, 0, PROC_LTV_SIZE + 2);
+		memset(val8, 0, DEBUG_LTV_SIZE + 2);
 
-		err = hermes_read_ltv(hw, USER_BAP, rid, PROC_LTV_SIZE,
+		err = hermes_read_ltv(hw, USER_BAP, rid, DEBUG_LTV_SIZE,
 				      &length, val8);
 		if (err) {
 			DEBUG(0, "Error %d reading RID 0x%04x\n", err, rid);
@@ -3732,210 +3993,46 @@
 		if (length == 0)
 			continue;
 
-		buf += sprintf(buf, "%-15s (0x%04x): length=%d (%d bytes)\tvalue=", record_table[i].name,
-			       rid, length, (length-1)*2);
-		len = min(((int)length-1)*2, PROC_LTV_SIZE);
+		printk(KERN_DEBUG "%-15s (0x%04x): length=%d (%d bytes)\tvalue=",
+		       record_table[i].name,
+		       rid, length, (length-1)*2);
+		len = min(((int)length-1)*2, DEBUG_LTV_SIZE);
 
 		switch (record_table[i].displaytype) {
 		case DISPLAY_WORDS:
-			for (j = 0; j < len / 2; j++) {
-				buf += sprintf(buf, "%04X-", le16_to_cpu(val16[j]));
-			}
-			buf--;
+			for (j = 0; j < len / 2; j++)
+				printk("%04X-", le16_to_cpu(val16[j]));
 			break;
 
 		case DISPLAY_BYTES:
 		default:
-			for (j = 0; j < len; j++) {
-				buf += sprintf(buf, "%02X:", val8[j]);
-			}
-			buf--;
+			for (j = 0; j < len; j++)
+				printk("%02X:", val8[j]);
 			break;
 
 		case DISPLAY_STRING:
 			len = min(len, le16_to_cpu(val16[0])+2);
 			val8[len] = '\0';
-			buf += sprintf(buf, "\"%s\"", (char *)&val16[1]);
+			printk("\"%s\"", (char *)&val16[1]);
 			break;
 
 		case DISPLAY_XSTRING:
-			buf += sprintf(buf, "'%s'", (char *)val8);
+			printk("'%s'", (char *)val8);
 		}
 
-		buf += sprintf(buf, "\n");
-
-		if (shift_buffer(page, requested_offset, requested_len,
-				 &total, &slop, &buf))
-			break;
-
-		if ( (buf - page) > PROC_SAFE_SIZE )
-			break;
+		printk("\n");
 	}
 
 	kfree(val8);
 
-	return calc_start_len(page, start, requested_offset, requested_len,
-			      total, buf);
-}
-
-#ifdef HERMES_DEBUG_BUFFER
-static int
-orinoco_proc_get_hermes_buf(char *page, char **start, off_t requested_offset,
-			    int requested_len, int *eof, void *data)
-{
-	struct orinoco_private *priv = (struct orinoco_private *)data;
-	hermes_t *hw = &priv->hw;
-	char *buf = page;
-	int total = 0, slop = 0;
-	int i;
-
-	for (i = 0; i < min_t(int,hw->dbufp, HERMES_DEBUG_BUFSIZE); i++) {
-		memcpy(buf, &hw->dbuf[i], sizeof(hw->dbuf[i]));
-		buf += sizeof(hw->dbuf[i]);
-
-		if (shift_buffer(page, requested_offset, requested_len,
-				 &total, &slop, &buf))
-			break;
-
-		if ( (buf - page) > PROC_SAFE_SIZE )
-			break;
-	}
-
-	return calc_start_len(page, start, requested_offset, requested_len,
-			      total, buf);
-}
-
-static int
-orinoco_proc_get_hermes_prof(char *page, char **start, off_t requested_offset,
-			    int requested_len, int *eof, void *data)
-{
-	struct orinoco_private *priv = (struct orinoco_private *)data;
-	hermes_t *hw = &priv->hw;
-	char *buf = page;
-	int total = 0, slop = 0;
-	int i;
-
-	for (i = 0; i < (HERMES_BAP_BUSY_TIMEOUT+1); i++) {
-		memcpy(buf, &hw->profile[i], sizeof(hw->profile[i]));
-		buf += sizeof(hw->profile[i]);
-
-		if (shift_buffer(page, requested_offset, requested_len,
-				 &total, &slop, &buf))
-			break;
-
-		if ( (buf - page) > PROC_SAFE_SIZE )
-			break;
-	}
-
-	return calc_start_len(page, start, requested_offset, requested_len,
-			      total, buf);
-}
-#endif /* HERMES_DEBUG_BUFFER */
-
-/* initialise the /proc subsystem for the hermes driver, creating the
- * separate entries */
-static int
-orinoco_proc_init(void)
-{
-	int err = 0;
-
-	TRACE_ENTER("orinoco");
-
-	/* create the directory for it to sit in */
-	dir_base = create_proc_entry("hermes", S_IFDIR, &proc_root);
-	if (dir_base == NULL) {
-		printk(KERN_ERR "Unable to initialise /proc/hermes.\n");
-		orinoco_proc_cleanup();
-		err = -ENOMEM;
-	}
-
-	TRACE_EXIT("orinoco");
-
-	return err;
-}
-
-int
-orinoco_proc_dev_init(struct orinoco_private *priv)
-{
-	struct net_device *dev = priv->ndev;
-	struct proc_dir_entry *e;
-
-	priv->dir_dev = NULL;
-
-	/* create the directory for it to sit in */
-	priv->dir_dev = create_proc_entry(dev->name, S_IFDIR | S_IRUGO | S_IXUGO,
-					  dir_base);
-	if (! priv->dir_dev) {
-		printk(KERN_ERR "Unable to initialize /proc/hermes/%s\n",  dev->name);
-		goto fail;
-	}
-
-	e = create_proc_read_entry("recs", S_IFREG | S_IRUGO,
-			       priv->dir_dev, orinoco_proc_get_hermes_recs, priv);
-	if (! e) {
-		printk(KERN_ERR "Unable to initialize /proc/hermes/%s/recs\n",  dev->name);
-		goto fail;
-	}
-
-#ifdef HERMES_DEBUG_BUFFER
-	e = create_proc_read_entry("buf", S_IFREG | S_IRUGO,
-					       priv->dir_dev, orinoco_proc_get_hermes_buf, priv);
-	if (! e) {
-		printk(KERN_ERR "Unable to intialize /proc/hermes/%s/buf\n", dev->name);
-		goto fail;
-	}
-
-	e = create_proc_read_entry("prof", S_IFREG | S_IRUGO,
-					       priv->dir_dev, orinoco_proc_get_hermes_prof, priv);
-	if (! e) {
-		printk(KERN_ERR "Unable to intialize /proc/hermes/%s/prof\n", dev->name);
-		goto fail;
-	}
-#endif /* HERMES_DEBUG_BUFFER */
-
 	return 0;
- fail:
-	orinoco_proc_dev_cleanup(priv);
-	return -ENOMEM;
-}
-
-void
-orinoco_proc_dev_cleanup(struct orinoco_private *priv)
-{
-	struct net_device *dev = priv->ndev;
-
-	TRACE_ENTER(priv->ndev->name);
-
-	if (priv->dir_dev) {
-		remove_proc_entry("prof", priv->dir_dev);
-		remove_proc_entry("buf", priv->dir_dev);
-		remove_proc_entry("recs", priv->dir_dev);
-		remove_proc_entry(dev->name, dir_base);
-		priv->dir_dev = NULL;
-	}
-
-	TRACE_EXIT(priv->ndev->name);
-}
-
-static void
-orinoco_proc_cleanup(void)
-{
-	TRACE_ENTER("orinoco");
-
-	if (dir_base) {
-		remove_proc_entry("hermes", &proc_root);
-		dir_base = NULL;
-	}
-	
-	TRACE_EXIT("orinoco");
 }
 
-struct net_device *alloc_orinocodev(int sizeof_card)
+struct net_device *alloc_orinocodev(int sizeof_card, int (*hard_reset)(struct orinoco_private *))
 {
 	struct net_device *dev;
 	struct orinoco_private *priv;
 
-	TRACE_ENTER("orinoco");
 	dev = alloc_etherdev(sizeof(struct orinoco_private) + sizeof_card);
 	priv = (struct orinoco_private *)dev->priv;
 	priv->ndev = dev;
@@ -3955,39 +4052,49 @@
 	dev->change_mtu = orinoco_change_mtu;
 	dev->set_multicast_list = orinoco_set_multicast_list;
 
-	dev->open = NULL;		/* Caller *must* override  these */
-	dev->stop = NULL;
-
-	/* Setup the private structure */
+	/* Set up default callbacks */
+	dev->open = orinoco_open;
+	dev->stop = orinoco_stop;
+	priv->hard_reset = hard_reset;
 
 	spin_lock_init(&priv->lock);
-	priv->hard_reset = NULL;	/* Caller may override */
-	
-	TRACE_EXIT("orinoco");
+	priv->open = 0;
+	priv->hw_unavailable = 1; /* orinoco_init() must clear this
+				   * before anything else touches the
+				   * hardware */
+	INIT_TQUEUE(&priv->timeout_task, (void (*)(void *))orinoco_reset, dev);
+
+	priv->last_linkstatus = 0xffff;
+	priv->connected = 0;
+
 	return dev;
 
 }
 
 /********************************************************************/
-/* module bookkeeping                                               */
+/* Module initialization                                            */
 /********************************************************************/
 
 EXPORT_SYMBOL(alloc_orinocodev);
-EXPORT_SYMBOL(orinoco_shutdown);
-EXPORT_SYMBOL(orinoco_reset);
-EXPORT_SYMBOL(orinoco_proc_dev_init);
-EXPORT_SYMBOL(orinoco_proc_dev_cleanup);
+
+EXPORT_SYMBOL(__orinoco_up);
+EXPORT_SYMBOL(__orinoco_down);
+EXPORT_SYMBOL(orinoco_reinit_firmware);
+
 EXPORT_SYMBOL(orinoco_interrupt);
 
+/* Can't be declared "const" or the whole __initdata section will
+ * become const */
+static char version[] __initdata = "orinoco.c 0.13b (David Gibson <hermes@gibson.dropbear.id.au> and others)";
+
 static int __init init_orinoco(void)
 {
 	printk(KERN_DEBUG "%s\n", version);
-	return orinoco_proc_init();
+	return 0;
 }
 
 static void __exit exit_orinoco(void)
 {
-	orinoco_proc_cleanup();
 }
 
 module_init(init_orinoco);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/wireless/orinoco.h linux-2.4.21-pre6/drivers/net/wireless/orinoco.h
--- linux-2.4.20/drivers/net/wireless/orinoco.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/wireless/orinoco.h	2003-03-26 23:49:24.000000000 +0000
@@ -7,6 +7,13 @@
 #ifndef _ORINOCO_H
 #define _ORINOCO_H
 
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <linux/tqueue.h>
+#include "hermes.h"
+
 /* To enable debug messages */
 //#define ORINOCO_DEBUG		3
 
@@ -18,24 +25,29 @@
 #define ORINOCO_MAX_KEY_SIZE	14
 #define ORINOCO_MAX_KEYS	4
 
-typedef struct orinoco_key {
-	u16 len;	/* always store little-endian */
+struct orinoco_key {
+	u16 len;	/* always stored as little-endian */
 	char data[ORINOCO_MAX_KEY_SIZE];
-} __attribute__ ((packed)) orinoco_key_t;
+} __attribute__ ((packed));
 
-typedef orinoco_key_t orinoco_keys_t[ORINOCO_MAX_KEYS];
+#define ORINOCO_INTEN	 	( HERMES_EV_RX | HERMES_EV_ALLOC | HERMES_EV_TX | \
+				HERMES_EV_TXEXC | HERMES_EV_WTERR | HERMES_EV_INFO | \
+				HERMES_EV_INFDROP )
 
-/*====================================================================*/
 
 struct orinoco_private {
 	void *card;	/* Pointer to card dependant structure */
-	/* card dependant extra reset code (i.e. bus/interface specific */
 	int (*hard_reset)(struct orinoco_private *);
 
+	/* Synchronisation stuff */
 	spinlock_t lock;
-	long state;
-#define ORINOCO_STATE_INIRQ 0
-#define ORINOCO_STATE_DOIRQ 1
+	int hw_unavailable;
+	struct tq_struct timeout_task;
+
+	/* driver state */
+	int open;
+	u16 last_linkstatus;
+	int connected;
 
 	/* Net device stuff */
 	struct net_device *ndev;
@@ -46,6 +58,7 @@
 	hermes_t hw;
 	u16 txfid;
 
+
 	/* Capabilities of the hardware/firmware */
 	int firmware_type;
 #define FIRMWARE_TYPE_AGERE 1
@@ -58,14 +71,13 @@
 	int has_preamble;
 	int has_sensitivity;
 	int nicbuf_size;
-	int broken_cor_reset;
 	u16 channel_mask;
 
 	/* Configuration paramaters */
 	u32 iw_mode;
 	int prefer_port3;
 	u16 wep_on, wep_restrict, tx_key;
-	orinoco_keys_t keys;
+	struct orinoco_key keys[ORINOCO_MAX_KEYS];
 	int bitratemode;
  	char nick[IW_ESSID_MAX_SIZE+1];
 	char desired_essid[IW_ESSID_MAX_SIZE+1];
@@ -81,38 +93,53 @@
 #endif
 
 	/* Configuration dependent variables */
-	int port_type, allow_ibss;
+	int port_type, createibss;
 	int promiscuous, mc_count;
-
-
-	/* /proc based debugging stuff */
-	struct proc_dir_entry *dir_dev;
 };
 
-/*====================================================================*/
-
-extern struct list_head orinoco_instances;
-
 #ifdef ORINOCO_DEBUG
 extern int orinoco_debug;
 #define DEBUG(n, args...) do { if (orinoco_debug>(n)) printk(KERN_DEBUG args); } while(0)
-#define DEBUGMORE(n, args...) do { if (orinoco_debug>(n)) printk(args); } while (0)
 #else
 #define DEBUG(n, args...) do { } while (0)
-#define DEBUGMORE(n, args...) do { } while (0)
 #endif	/* ORINOCO_DEBUG */
 
 #define TRACE_ENTER(devname) DEBUG(2, "%s: -> " __FUNCTION__ "()\n", devname);
 #define TRACE_EXIT(devname)  DEBUG(2, "%s: <- " __FUNCTION__ "()\n", devname);
 
-#define RUP_EVEN(a) ( (a) % 2 ? (a) + 1 : (a) )
+extern struct net_device *alloc_orinocodev(int sizeof_card,
+					   int (*hard_reset)(struct orinoco_private *));
+extern int __orinoco_up(struct net_device *dev);
+extern int __orinoco_down(struct net_device *dev);
+int orinoco_reinit_firmware(struct net_device *dev);
 
-/* utility routines */
-struct net_device *alloc_orinocodev(int sizeof_card);
-extern void orinoco_shutdown(struct orinoco_private *dev);
-extern int orinoco_reset(struct orinoco_private *dev);
-extern int orinoco_proc_dev_init(struct orinoco_private *dev);
-extern void orinoco_proc_dev_cleanup(struct orinoco_private *priv);
 extern void orinoco_interrupt(int irq, void * dev_id, struct pt_regs *regs);
 
+/********************************************************************/
+/* Locking and synchronization functions                            */
+/********************************************************************/
+
+/* These functions *must* be inline or they will break horribly on
+ * SPARC, due to its weird semantics for save/restore flags. extern
+ * inline should prevent the kernel from linking or module from
+ * loading if they are not inlined. */
+extern inline int orinoco_lock(struct orinoco_private *priv,
+			       unsigned long *flags)
+{
+	spin_lock_irqsave(&priv->lock, *flags);
+	if (priv->hw_unavailable) {
+		printk(KERN_DEBUG "orinoco_lock() called with hw_unavailable (dev=%p)\n",
+		       priv->ndev);
+		spin_unlock_irqrestore(&priv->lock, *flags);
+		return -EBUSY;
+	}
+	return 0;
+}
+
+extern inline void orinoco_unlock(struct orinoco_private *priv,
+				  unsigned long *flags)
+{
+	spin_unlock_irqrestore(&priv->lock, *flags);
+}
+
 #endif /* _ORINOCO_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/wireless/orinoco_cs.c linux-2.4.21-pre6/drivers/net/wireless/orinoco_cs.c
--- linux-2.4.20/drivers/net/wireless/orinoco_cs.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/wireless/orinoco_cs.c	2003-03-26 23:49:54.000000000 +0000
@@ -1,4 +1,4 @@
-/* orinoco_cs.c 0.11b	- (formerly known as dldwd_cs.c)
+/* orinoco_cs.c 0.13b	- (formerly known as dldwd_cs.c)
  *
  * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such
  * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/
@@ -27,12 +27,10 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/system.h>
-#include <linux/proc_fs.h>
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/etherdevice.h>
 #include <linux/wireless.h>
-#include <linux/list.h>
 
 #include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
@@ -42,12 +40,11 @@
 #include <pcmcia/ds.h>
 #include <pcmcia/bus_ops.h>
 
-#include "hermes.h"
 #include "orinoco.h"
 
-/*====================================================================*/
-
-static char version[] __initdata = "orinoco_cs.c 0.11b (David Gibson <hermes@gibson.dropbear.id.au> and others)";
+/********************************************************************/
+/* Module stuff							    */
+/********************************************************************/
 
 MODULE_AUTHOR("David Gibson <hermes@gibson.dropbear.id.au>");
 MODULE_DESCRIPTION("Driver for PCMCIA Lucent Orinoco, Prism II based and similar wireless cards");
@@ -55,235 +52,132 @@
 MODULE_LICENSE("Dual MPL/GPL");
 #endif
 
-/* Parameters that can be set with 'insmod' */
+/* Module parameters */
 
 /* The old way: bit map of interrupts to choose from */
 /* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */
 static uint irq_mask = 0xdeb8;
 /* Newer, simpler way of listing specific interrupts */
 static int irq_list[4] = { -1 };
-/* Do a Pcmcia soft reset (may help some cards) */
-static int reset_cor = -1;
+
 /* Some D-Link cards have buggy CIS. They do work at 5v properly, but
  * don't have any CIS entry for it. This workaround it... */
 static int ignore_cis_vcc; /* = 0 */
 
 MODULE_PARM(irq_mask, "i");
 MODULE_PARM(irq_list, "1-4i");
-MODULE_PARM(reset_cor, "i");
 MODULE_PARM(ignore_cis_vcc, "i");
 
-/* Pcmcia specific structure */
+/********************************************************************/
+/* Magic constants						    */
+/********************************************************************/
+
+/*
+ * The dev_info variable is the "key" that is used to match up this
+ * device driver with appropriate cards, through the card
+ * configuration database.
+ */
+static dev_info_t dev_info = "orinoco_cs";
+
+/********************************************************************/
+/* Data structures						    */
+/********************************************************************/
+
+/* PCMCIA specific device information (goes in the card field of
+ * struct orinoco_private */
 struct orinoco_pccard {
 	dev_link_t link;
 	dev_node_t node;
+
+	/* Used to handle hard reset */
+	/* yuck, we need this hack to work around the insanity of the
+         * PCMCIA layer */
+	unsigned long hard_reset_in_progress; 
 };
 
 /*
- * Function prototypes
+ * A linked list of "instances" of the device.  Each actual PCMCIA
+ * card corresponds to one device instance, and is described by one
+ * dev_link_t structure (defined in ds.h).
  */
+static dev_link_t *dev_list; /* = NULL */
+
+/********************************************************************/
+/* Function prototypes						    */
+/********************************************************************/
 
-/* struct net_device methods */
-static int orinoco_cs_open(struct net_device *dev);
-static int orinoco_cs_stop(struct net_device *dev);
+/* device methods */
+static int orinoco_cs_hard_reset(struct orinoco_private *priv);
 
 /* PCMCIA gumpf */
 static void orinoco_cs_config(dev_link_t * link);
 static void orinoco_cs_release(u_long arg);
 static int orinoco_cs_event(event_t event, int priority,
-		       event_callback_args_t * args);
+			    event_callback_args_t * args);
 
 static dev_link_t *orinoco_cs_attach(void);
 static void orinoco_cs_detach(dev_link_t *);
 
-/*
-   The dev_info variable is the "key" that is used to match up this
-   device driver with appropriate cards, through the card configuration
-   database.
-*/
-static dev_info_t dev_info = "orinoco_cs";
-
-/*
-   A linked list of "instances" of the dummy device.  Each actual
-   PCMCIA card corresponds to one device instance, and is described
-   by one dev_link_t structure (defined in ds.h).
-
-   You may not want to use a linked list for this -- for example, the
-   memory card driver uses an array of dev_link_t pointers, where minor
-   device numbers are used to derive the corresponding array index.
-*/
-
-static dev_link_t *dev_list; /* = NULL */
-
-/*====================================================================*/
-
-static void
-cs_error(client_handle_t handle, int func, int ret)
-{
-	error_info_t err = { func, ret };
-	CardServices(ReportError, handle, &err);
-}
+/********************************************************************/
+/* Device methods     						    */
+/********************************************************************/
 
 static int
-orinoco_cs_open(struct net_device *dev)
+orinoco_cs_hard_reset(struct orinoco_private *priv)
 {
-	struct orinoco_private *priv = (struct orinoco_private *)dev->priv;
-	struct orinoco_pccard* card = (struct orinoco_pccard *)priv->card;
+	struct orinoco_pccard *card = priv->card;
 	dev_link_t *link = &card->link;
 	int err;
-	
-	TRACE_ENTER(dev->name);
-
-	link->open++;
-	netif_device_attach(dev);
-	
-	err = orinoco_reset(priv);
-	if (err)
-		orinoco_cs_stop(dev);
-	else
-		netif_start_queue(dev);
-
-	TRACE_EXIT(dev->name);
 
-	return err;
-}
-
-static int
-orinoco_cs_stop(struct net_device *dev)
-{
-	struct orinoco_private *priv = (struct orinoco_private *)dev->priv;
-	struct orinoco_pccard* card = (struct orinoco_pccard *)priv->card;
-	dev_link_t *link = &card->link;
+	/* We need atomic ops here, because we're not holding the lock */
+	set_bit(0, &card->hard_reset_in_progress);
 
-	TRACE_ENTER(dev->name);
+	err = CardServices(ResetCard, link->handle, NULL);
+	if (err)
+		return err;
 
-	netif_stop_queue(dev);
+	clear_bit(0, &card->hard_reset_in_progress);
 
-	orinoco_shutdown(priv);
-	
-	link->open--;
-
-	if (link->state & DEV_STALE_CONFIG)
-		mod_timer(&link->release, jiffies + HZ/20);
-	
-	TRACE_EXIT(dev->name);
-	
 	return 0;
 }
 
-/*
- * Do a soft reset of the Pcmcia card using the Configuration Option Register
- * Can't do any harm, and actually may do some good on some cards...
- * In fact, this seem necessary for Spectrum cards...
- */
-static int
-orinoco_cs_cor_reset(struct orinoco_private *priv)
-{
-	struct orinoco_pccard* card = (struct orinoco_pccard *)priv->card;
-	dev_link_t *link = &card->link;
-	conf_reg_t reg;
-	u_int default_cor; 
-
-	TRACE_ENTER(priv->ndev->name);
-
-	/* Doing it if hardware is gone is guaranteed crash */
-	if(! (link->state & DEV_CONFIG) )
-		return -ENODEV;
-
-	/* Save original COR value */
-	reg.Function = 0;
-	reg.Action = CS_READ;
-	reg.Offset = CISREG_COR;
-	reg.Value = 0;
-	CardServices(AccessConfigurationRegister, link->handle, &reg);
-	default_cor = reg.Value;
-
-	DEBUG(2, "orinoco : orinoco_cs_cor_reset() : cor=0x%X\n", default_cor);
-
-	/* Soft-Reset card */
-	reg.Action = CS_WRITE;
-	reg.Offset = CISREG_COR;
-	reg.Value = (default_cor | COR_SOFT_RESET);
-	CardServices(AccessConfigurationRegister, link->handle, &reg);
-
-	/* Wait until the card has acknowledged our reset */
-	/* FIXME: mdelay() is deprecated -dgibson */
-	mdelay(1);
-
-#if 0 /* This seems to help on Symbol cards, but we're not sure why,
-       and we don't know what it will do to other cards */
-	reg.Action = CS_READ;
-	reg.Offset = CISREG_CCSR;
-	CardServices(AccessConfigurationRegister, link->handle, &reg);
-
-	/* Write 7 (RUN) to CCSR, but preserve the original bit 4 */
-	reg.Action = CS_WRITE;
-	reg.Offset = CISREG_CCSR;
-	reg.Value = 7 | (reg.Value & 0x10);
-	CardServices(AccessConfigurationRegister, link->handle, &reg);
-	mdelay(1);
-#endif
-
-	/* Restore original COR configuration index */
-	reg.Action = CS_WRITE;
-	reg.Offset = CISREG_COR;
-	reg.Value = (default_cor & ~COR_SOFT_RESET);
-	CardServices(AccessConfigurationRegister, link->handle, &reg);
-
-	/* Wait until the card has finished restarting */
-	/* FIXME: mdelay() is deprecated -dgibson */
-	mdelay(1);
-
-	TRACE_EXIT(priv->ndev->name);
-
-	return 0;
-}
+/********************************************************************/
+/* PCMCIA stuff     						    */
+/********************************************************************/
 
-static int
-orinoco_cs_hard_reset(struct orinoco_private *priv)
+static void
+cs_error(client_handle_t handle, int func, int ret)
 {
-	if (! priv->broken_cor_reset)
-		return orinoco_cs_cor_reset(priv);
-	else
-		return 0;
-
-#if 0 /* We'd like to use ResetCard, but we can't for the moment - it sleeps */
-	/* Not sure what the second parameter is supposed to be - the 
-	   PCMCIA code doesn't actually use it */
-	if (in_interrupt()) {
-		printk("Not resetting card, in_interrupt() is true\n");
-		return 0;
-	} else {
-		printk("Doing ResetCard\n");
-		return CardServices(ResetCard, link->handle, NULL);
-	}
-#endif
+	error_info_t err = { func, ret };
+	CardServices(ReportError, handle, &err);
 }
 
+
 /* Remove zombie instances (card removed, detach pending) */
 static void
 flush_stale_links(void)
 {
 	dev_link_t *link, *next;
-	TRACE_ENTER("orinoco");
+
+	TRACE_ENTER("");
+
 	for (link = dev_list; link; link = next) {
 		next = link->next;
-		if (link->state & DEV_STALE_LINK)
+		if (link->state & DEV_STALE_LINK) {
 			orinoco_cs_detach(link);
+		}
 	}
-	TRACE_EXIT("orinoco");
+	TRACE_EXIT("");
 }
 
-/*======================================================================
-  orinoco_cs_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.
-  ======================================================================*/
-
+/*
+ * This 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 *
 orinoco_cs_attach(void)
 {
@@ -294,23 +188,18 @@
 	client_reg_t client_reg;
 	int ret, i;
 
-	TRACE_ENTER("orinoco");
 	/* A bit of cleanup */
 	flush_stale_links();
 
-	dev = alloc_orinocodev(sizeof(*card));
+	dev = alloc_orinocodev(sizeof(*card), orinoco_cs_hard_reset);
 	if (! dev)
 		return NULL;
 	priv = dev->priv;
 	card = priv->card;
-	/* Overrides */
-	dev->open = orinoco_cs_open;
-	dev->stop = orinoco_cs_stop;
-	priv->hard_reset = orinoco_cs_hard_reset;
 
 	/* Link both structures together */
 	link = &card->link;
-	link->priv = priv;
+	link->priv = dev;
 
 	/* Initialize the dev_link_t structure */
 	link->release.function = &orinoco_cs_release;
@@ -326,63 +215,59 @@
 			link->irq.IRQInfo2 |= 1 << irq_list[i];
 	link->irq.Handler = NULL;
 
-	/*
-	   General socket configuration defaults can go here.  In this
-	   client, we assume very little, and rely on the CIS for almost
-	   everything.  In most clients, many details (i.e., number, sizes,
-	   and attributes of IO windows) are fixed by the nature of the
-	   device, and can be hard-wired here.
-	 */
+	/* General socket configuration defaults can go here.  In this
+	 * client, we assume very little, and rely on the CIS for
+	 * almost everything.  In most clients, many details (i.e.,
+	 * number, sizes, and attributes of IO windows) are fixed by
+	 * the nature of the device, and can be hard-wired here. */
 	link->conf.Attributes = 0;
 	link->conf.IntType = INT_MEMORY_AND_IO;
 
 	/* Register with Card Services */
+	/* FIXME: need a lock? */
 	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;
+		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 = &orinoco_cs_event;
-	client_reg.Version = 0x0210;
+	client_reg.Version = 0x0210; /* FIXME: what does this mean? */
 	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);
 		orinoco_cs_detach(link);
-		link = NULL;
-		goto out;
+		return NULL;
 	}
 
- out:
-	TRACE_EXIT("orinoco");
 	return link;
 }				/* orinoco_cs_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.
-  ======================================================================*/
-
+/*
+ * 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
 orinoco_cs_detach(dev_link_t * link)
 {
 	dev_link_t **linkp;
-	struct orinoco_private *priv = link->priv;
-	struct net_device *dev = priv->ndev;
-
-	TRACE_ENTER("orinoco");
+	struct net_device *dev = link->priv;
 
 	/* Locate device structure */
 	for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
 		if (*linkp == link)
 			break;
-	if (*linkp == NULL)
-		goto out;
+	if (*linkp == NULL) {
+		BUG();
+		return;
+	}
 
 	/*
 	   If the device is currently configured and active, we won't
@@ -396,7 +281,7 @@
 		       "still locked\n", link->dev->dev_name);
 #endif
 		link->state |= DEV_STALE_LINK;
-		goto out;
+		return;
 	}
 
 	/* Break the link with Card Services */
@@ -408,50 +293,44 @@
 	DEBUG(0, "orinoco_cs: detach: link=%p link->dev=%p\n", link, link->dev);
 	if (link->dev) {
 		DEBUG(0, "orinoco_cs: About to unregister net device %p\n",
-		      priv->ndev);
+		      dev);
 		unregister_netdev(dev);
 	}
 	kfree(dev);
-
- out:
-	TRACE_EXIT("orinoco");
 }				/* orinoco_cs_detach */
 
-/*======================================================================
-  orinoco_cs_config() is scheduled to run after a CARD_INSERTION event
-  is received, to configure the PCMCIA socket, and to make the
-  device available to the system.
-  ======================================================================*/
+/*
+ * orinoco_cs_config() is scheduled to run after a CARD_INSERTION
+ * event is received, to configure the PCMCIA socket, and to make the
+ * device available to the system.
+ */
 
 #define CS_CHECK(fn, args...) \
-while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed
+	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
+	if (CardServices(fn, args) != 0) goto next_entry
 
 static void
-orinoco_cs_config(dev_link_t * link)
+orinoco_cs_config(dev_link_t *link)
 {
+	struct net_device *dev = link->priv;
 	client_handle_t handle = link->handle;
-	struct orinoco_private *priv = link->priv;
-	struct orinoco_pccard *card = (struct orinoco_pccard *)priv->card;
+	struct orinoco_private *priv = dev->priv;
+	struct orinoco_pccard *card = priv->card;
 	hermes_t *hw = &priv->hw;
-	struct net_device *ndev = priv->ndev;
-	tuple_t tuple;
-	cisparse_t parse;
 	int last_fn, last_ret;
 	u_char buf[64];
 	config_info_t conf;
-	cistpl_cftable_entry_t dflt = { 0 };
 	cisinfo_t info;
-
-	TRACE_ENTER("orinoco");
+	tuple_t tuple;
+	cisparse_t parse;
 
 	CS_CHECK(ValidateCIS, handle, &info);
 
 	/*
-	   This reads the card's CONFIG tuple to find its configuration
-	   registers.
+	 * This reads the card's CONFIG tuple to find its
+	 * configuration registers.
 	 */
 	tuple.DesiredTuple = CISTPL_CONFIG;
 	tuple.Attributes = 0;
@@ -471,31 +350,29 @@
 	CS_CHECK(GetConfigurationInfo, handle, &conf);
 	link->conf.Vcc = conf.Vcc;
 
-	DEBUG(0, "orinoco_cs_config: ConfigBase = 0x%x link->conf.Vcc = %d\n", 
-	      link->conf.ConfigBase, link->conf.Vcc);
-
 	/*
-	   In this loop, we scan the CIS for configuration table entries,
-	   each of which describes a valid card configuration, including
-	   voltage, IO window, memory window, and interrupt settings.
-
-	   We make no assumptions about the card to be configured: we use
-	   just the information available in the CIS.  In an ideal world,
-	   this would work for any PCMCIA card, but it requires a complete
-	   and accurate CIS.  In practice, a driver usually "knows" most of
-	   these things without consulting the CIS, and most client drivers
-	   will only use the CIS to fill in implementation-defined details.
+	 * In this loop, we scan the CIS for configuration table
+	 * entries, each of which describes a valid card
+	 * configuration, including voltage, IO window, memory window,
+	 * and interrupt settings.
+	 *
+	 * We make no assumptions about the card to be configured: we
+	 * use just the information available in the CIS.  In an ideal
+	 * world, this would work for any PCMCIA card, but it requires
+	 * a complete and accurate CIS.  In practice, a driver usually
+	 * "knows" most of these things without consulting the CIS,
+	 * and most client drivers will only use the CIS to fill in
+	 * implementation-defined details.
 	 */
 	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
 	CS_CHECK(GetFirstTuple, handle, &tuple);
 	while (1) {
 		cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
+		cistpl_cftable_entry_t dflt = { index: 0 };
+
 		CFG_CHECK(GetTupleData, handle, &tuple);
 		CFG_CHECK(ParseTuple, handle, &tuple, &parse);
 
-		DEBUG(0, "orinoco_cs_config: index = 0x%x, flags = 0x%x\n",
-		      cfg->index, cfg->flags);
-
 		if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
 			dflt = *cfg;
 		if (cfg->index == 0)
@@ -509,7 +386,7 @@
 		}
 
 		/* Use power settings for Vcc and Vpp if present */
-		/*  Note that the CIS values need to be rescaled */
+		/* Note that the CIS values need to be rescaled */
 		if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
 			if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) {
 				DEBUG(2, "orinoco_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n",  conf.Vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000);
@@ -531,8 +408,6 @@
 			link->conf.Vpp1 = link->conf.Vpp2 =
 			    dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
 		
-		DEBUG(0, "orinoco_cs_config: We seem to have configured Vcc and Vpp\n");
-
 		/* Do we need to allocate an interrupt? */
 		if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1)
 			link->conf.Attributes |= CONF_ENABLE_IRQ;
@@ -581,9 +456,9 @@
 	}
 
 	/*
-	   Allocate an interrupt line.  Note that this does not assign a
-	   handler to the interrupt, unless the 'Handler' member of the
-	   irq structure is initialized.
+	 * Allocate an interrupt line.  Note that this does not assign
+	 * a handler to the interrupt, unless the 'Handler' member of
+	 * the irq structure is initialized.
 	 */
 	if (link->conf.Attributes & CONF_ENABLE_IRQ) {
 		int i;
@@ -603,33 +478,43 @@
 	}
 
 	/* We initialize the hermes structure before completing PCMCIA
-	   configuration just in case the interrupt handler gets
-	   called. */
+	 * configuration just in case the interrupt handler gets
+	 * called. */
 	hermes_struct_init(hw, link->io.BasePort1,
 				HERMES_IO, HERMES_16BIT_REGSPACING);
 
 	/*
-	   This actually configures the PCMCIA socket -- setting up
-	   the I/O windows and the interrupt mapping, and putting the
-	   card and host interface into "Memory and IO" mode.
+	 * This actually configures the PCMCIA socket -- setting up
+	 * the I/O windows and the interrupt mapping, and putting the
+	 * card and host interface into "Memory and IO" mode.
 	 */
 	CS_CHECK(RequestConfiguration, link->handle, &link->conf);
 
-	ndev->base_addr = link->io.BasePort1;
-	ndev->irq = link->irq.AssignedIRQ;
+	/* Ok, we have the configuration, prepare to register the netdev */
+	dev->base_addr = link->io.BasePort1;
+	dev->irq = link->irq.AssignedIRQ;
+	SET_MODULE_OWNER(dev);
+	card->node.major = card->node.minor = 0;
 
 	/* register_netdev will give us an ethX name */
-	ndev->name[0] = '\0';
+	dev->name[0] = '\0';
 	/* Tell the stack we exist */
-	if (register_netdev(ndev) != 0) {
+	if (register_netdev(dev) != 0) {
 		printk(KERN_ERR "orinoco_cs: register_netdev() failed\n");
 		goto failed;
 	}
-	strcpy(card->node.dev_name, ndev->name);
+
+	/* At this point, the dev_node_t structure(s) needs to be
+	 * initialized and arranged in a linked list at link->dev. */
+	strcpy(card->node.dev_name, dev->name);
+	link->dev = &card->node; /* link->dev being non-NULL is also
+                                    used to indicate that the
+                                    net_device has been registered */
+	link->state &= ~DEV_CONFIG_PENDING;
 
 	/* Finally, report what we've done */
 	printk(KERN_DEBUG "%s: index 0x%02x: Vcc %d.%d",
-	       ndev->name, link->conf.ConfigIndex,
+	       dev->name, link->conf.ConfigIndex,
 	       link->conf.Vcc / 10, link->conf.Vcc % 10);
 	if (link->conf.Vpp1)
 		printk(", Vpp %d.%d", link->conf.Vpp1 / 10,
@@ -644,69 +529,39 @@
 		       link->io.BasePort2 + link->io.NumPorts2 - 1);
 	printk("\n");
 
-	/* And give us the proc nodes for debugging */
-	if (orinoco_proc_dev_init(priv) != 0) {
-		printk(KERN_ERR "orinoco_cs: Failed to create /proc node for %s\n",
-		       ndev->name);
-		goto failed;
-	}
-	
-	/* Note to myself : this replace MOD_INC_USE_COUNT/MOD_DEC_USE_COUNT */
-	SET_MODULE_OWNER(ndev);
-	
-	/* Let reset_cor parameter override determine_firmware()'s guess */
-	if (reset_cor != -1)
-		priv->broken_cor_reset = ! reset_cor;
-
-	/*
-	   At this point, the dev_node_t structure(s) need to be
-	   initialized and arranged in a linked list at link->dev.
-	 */
-	card->node.major = card->node.minor = 0;
-	link->dev = &card->node;
-	link->state &= ~DEV_CONFIG_PENDING;
-
-	TRACE_EXIT("orinoco");
-
 	return;
 
  cs_failed:
 	cs_error(link->handle, last_fn, last_ret);
+
  failed:
 	orinoco_cs_release((u_long) link);
-
-	TRACE_EXIT("orinoco");
 }				/* orinoco_cs_config */
 
-/*======================================================================
-  After a card is removed, orinoco_cs_release() will unregister the
-  device, and release the PCMCIA configuration.  If the device is
-  still open, this will be postponed until it is closed.
-  ======================================================================*/
-
+/*
+ * After a card is removed, orinoco_cs_release() will unregister the
+ * device, and release the PCMCIA configuration.  If the device is
+ * still open, this will be postponed until it is closed.
+ */
 static void
 orinoco_cs_release(u_long arg)
 {
 	dev_link_t *link = (dev_link_t *) arg;
-	struct orinoco_private *priv = link->priv;
-
-	TRACE_ENTER(link->dev->dev_name);
+	struct net_device *dev = link->priv;
+	struct orinoco_private *priv = dev->priv;
 
 	/*
 	   If the device is currently in use, we won't release until it
 	   is actually closed, because until then, we can't be sure that
 	   no one will try to access the device or its data structures.
 	 */
-	if (link->open) {
+	if (priv->open) {
 		DEBUG(0, "orinoco_cs: release postponed, '%s' still open\n",
 		      link->dev->dev_name);
 		link->state |= DEV_STALE_CONFIG;
 		return;
 	}
 
-	/* Unregister proc entry */
-	orinoco_proc_dev_cleanup(priv);
-
 	/* Don't bother checking to see if these succeed or not */
 	CardServices(ReleaseConfiguration, link->handle);
 	if (link->io.NumPorts1)
@@ -714,100 +569,137 @@
 	if (link->irq.AssignedIRQ)
 		CardServices(ReleaseIRQ, link->handle, &link->irq);
 	link->state &= ~DEV_CONFIG;
-
-	TRACE_EXIT(link->dev->dev_name);
 }				/* orinoco_cs_release */
 
-/*======================================================================
-  The card status event handler.  Mostly, this schedules other
-  stuff to run after an event is received.
-
-  When a CARD_REMOVAL event is received, we immediately set a
-  private flag to block future accesses to this device.  All the
-  functions that actually access the device should check this flag
-  to make sure the card is still present.
-  ======================================================================*/
-
+/*
+ * The card status event handler.  Mostly, this schedules other stuff
+ * to run after an event is received.
+ */
 static int
 orinoco_cs_event(event_t event, int priority,
 		       event_callback_args_t * args)
 {
 	dev_link_t *link = args->client_data;
-	struct orinoco_private *priv = (struct orinoco_private *)link->priv;
-	struct net_device *dev = priv->ndev;
-
-	TRACE_ENTER("orinoco");
+	struct net_device *dev = link->priv;
+	struct orinoco_private *priv = dev->priv;
+	struct orinoco_pccard *card = priv->card;
+	int err = 0;
+	unsigned long flags;
 
 	switch (event) {
 	case CS_EVENT_CARD_REMOVAL:
 		link->state &= ~DEV_PRESENT;
 		if (link->state & DEV_CONFIG) {
-			netif_stop_queue(dev);
-		}
-		orinoco_shutdown(priv);
-		if (link->state & DEV_CONFIG) {
+			orinoco_lock(priv, &flags);
+
 			netif_device_detach(dev);
+			priv->hw_unavailable = 1;
+
+			orinoco_unlock(priv, &flags);
+
+/*  			if (link->open) */
+/*  				orinoco_cs_stop(dev); */
+
 			mod_timer(&link->release, jiffies + HZ / 20);
 		}
 		break;
+
 	case CS_EVENT_CARD_INSERTION:
 		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
 		orinoco_cs_config(link);
 		break;
-	case CS_EVENT_PM_SUSPEND:
 
+	case CS_EVENT_PM_SUSPEND:
 		link->state |= DEV_SUSPEND;
 		/* Fall through... */
 	case CS_EVENT_RESET_PHYSICAL:
-		orinoco_shutdown(priv);
 		/* Mark the device as stopped, to block IO until later */
-
 		if (link->state & DEV_CONFIG) {
-			if (link->open) {
-				netif_stop_queue(dev);
+			/* This is probably racy, but I can't think of
+                           a better way, short of rewriting the PCMCIA
+                           layer to not suck :-( */
+			if (! test_bit(0, &card->hard_reset_in_progress)) {
+				err = orinoco_lock(priv, &flags);
+				if (err) {
+					printk(KERN_ERR "%s: hw_unavailable on SUSPEND/RESET_PHYSICAL\n",
+					       dev->name);
+					break;
+				}
+				
+				err = __orinoco_down(dev);
+				if (err)
+					printk(KERN_WARNING "%s: %s: Error %d downing interface\n",
+					       dev->name,
+					       event == CS_EVENT_PM_SUSPEND ? "SUSPEND" : "RESET_PHYSICAL",
+					       err);
+				
 				netif_device_detach(dev);
+				priv->hw_unavailable = 1;
+				
+				orinoco_unlock(priv, &flags);
 			}
+
 			CardServices(ReleaseConfiguration, link->handle);
 		}
 		break;
+
 	case CS_EVENT_PM_RESUME:
 		link->state &= ~DEV_SUSPEND;
 		/* Fall through... */
 	case CS_EVENT_CARD_RESET:
 		if (link->state & DEV_CONFIG) {
+			/* FIXME: should we double check that this is
+			 * the same card as we had before */
 			CardServices(RequestConfiguration, link->handle,
 				     &link->conf);
 
-			if (link->open) {
-				if (orinoco_reset(priv) == 0) {
-					netif_device_attach(dev);
-					netif_start_queue(dev);
-				} else {
-					printk(KERN_ERR "%s: Error resetting device on PCMCIA event\n",
-					       dev->name);
-					orinoco_cs_stop(dev);
+			/* If we're only getting these events because
+                           of the ResetCard in the hard reset, we
+                           don't need to do anything - orinoco_reset()
+                           will handle reinitialization. */
+			if (! test_bit(0, &card->hard_reset_in_progress)) {
+				err = orinoco_reinit_firmware(dev);
+				if (err) {
+					printk(KERN_ERR "%s: Error %d re-initializing firmware\n",
+					       dev->name, err);
+					break;
+				}
+				
+				spin_lock_irqsave(&priv->lock, flags);
+				
+				netif_device_attach(dev);
+				priv->hw_unavailable = 0;
+				
+				if (priv->open) {
+					err = __orinoco_up(dev);
+					if (err)
+						printk(KERN_ERR "%s: Error %d restarting card\n",
+						       dev->name, err);
+					
 				}
+
+				orinoco_unlock(priv, &flags);
 			}
 		}
-		/*
-		   In a normal driver, additional code may go here to restore
-		   the device state and restart IO. 
-		 */
 		break;
 	}
 
-	TRACE_EXIT("orinoco");
-
-	return 0;
+	return err;
 }				/* orinoco_cs_event */
 
+/********************************************************************/
+/* Module initialization					    */
+/********************************************************************/
+
+/* Can't be declared "const" or the whole __initdata section will
+ * become const */
+static char version[] __initdata = "orinoco_cs.c 0.13b (David Gibson <hermes@gibson.dropbear.id.au> and others)";
+
 static int __init
 init_orinoco_cs(void)
 {
 	servinfo_t serv;
 
-	TRACE_ENTER("orinoco");
-
 	printk(KERN_DEBUG "%s\n", version);
 
 	CardServices(GetCardServicesInfo, &serv);
@@ -819,16 +711,12 @@
 
 	register_pccard_driver(&dev_info, &orinoco_cs_attach, &orinoco_cs_detach);
 
-
-	TRACE_EXIT("orinoco");
 	return 0;
 }
 
 static void __exit
 exit_orinoco_cs(void)
 {
-	TRACE_ENTER("orinoco");
-
 	unregister_pccard_driver(&dev_info);
 
 	if (dev_list)
@@ -839,9 +727,8 @@
 			orinoco_cs_release((u_long) dev_list);
 		orinoco_cs_detach(dev_list);
 	}
-
-	TRACE_EXIT("orinoco");
 }
 
 module_init(init_orinoco_cs);
 module_exit(exit_orinoco_cs);
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/wireless/orinoco_pci.c linux-2.4.21-pre6/drivers/net/wireless/orinoco_pci.c
--- linux-2.4.20/drivers/net/wireless/orinoco_pci.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/wireless/orinoco_pci.c	2003-03-26 23:49:30.000000000 +0000
@@ -1,4 +1,4 @@
-/* orinoco_pci.c 0.01
+/* orinoco_pci.c 0.13b
  * 
  * Driver for Prism II devices that have a direct PCI interface
  * (i.e., not in a Pcmcia or PLX bridge)
@@ -10,8 +10,10 @@
  * Some of this code is "inspired" by linux-wlan-ng-0.1.10, but nothing
  * has been copied from it. linux-wlan-ng-0.1.10 is originally :
  *	Copyright (C) 1999 AbsoluteValue Systems, Inc.  All Rights Reserved.
- * The rest is :
+ * This file originally written by:
  *	Copyright (C) 2001 Jean Tourrilhes <jt@hpl.hp.com>
+ * And is now maintained by:
+ *	Copyright (C) 2002 David Gibson, IBM Corporation <herme@gibson.dropbear.id.au>
  *
  * The contents of this file are subject to the Mozilla Public License
  * Version 1.1 (the "License"); you may not use this file except in
@@ -97,7 +99,6 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/system.h>
-#include <linux/proc_fs.h>
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/etherdevice.h>
@@ -122,41 +123,6 @@
 #define HERMES_PCI_COR_OFFT	(500)		/* ms */
 #define HERMES_PCI_COR_BUSYT	(500)		/* ms */
 
-MODULE_AUTHOR("Jean Tourrilhes <jt@hpl.hp.com>");
-MODULE_DESCRIPTION("Driver for wireless LAN cards using direct PCI interface");
-MODULE_LICENSE("Dual MPL/GPL");
-
-static int orinoco_pci_open(struct net_device *dev)
-{
-	struct orinoco_private *priv = (struct orinoco_private *) dev->priv;
-	int err;
-
-	netif_device_attach(dev);
-
-	err = orinoco_reset(priv);
-	if (err)
-		printk(KERN_ERR "%s: orinoco_reset failed in orinoco_pci_open()",
-		       dev->name);
-	else
-		netif_start_queue(dev);
-
-	return err;
-}
-
-static int orinoco_pci_stop(struct net_device *dev)
-{
-	struct orinoco_private *priv = (struct orinoco_private *) dev->priv;
-	netif_stop_queue(dev);
-	orinoco_shutdown(priv);
-	return 0;
-}
-
-static void
-orinoco_pci_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	orinoco_interrupt(irq, (struct orinoco_private *)dev_id, regs);
-}
-
 /*
  * Do a soft reset of the PCI card using the Configuration Option Register
  * We need this to get going...
@@ -179,7 +145,6 @@
 
 	TRACE_ENTER(priv->ndev->name);
 
-
 	/* Assert the reset until the card notice */
 	hermes_write_regn(hw, PCI_COR, HERMES_PCI_COR_MASK);
 	printk(KERN_NOTICE "Reset done");
@@ -235,8 +200,6 @@
 	struct net_device *dev = NULL;
 	int netdev_registered = 0;
 
-	TRACE_ENTER("orinoco_pci");
-
 	err = pci_enable_device(pdev);
 	if (err)
 		return -EIO;
@@ -249,7 +212,7 @@
 		goto fail;
 
 	/* Usual setup of structures */
-	dev = alloc_orinocodev(0);
+	dev = alloc_orinocodev(0, NULL);
 	if (! dev) {
 		err = -ENOMEM;
 		goto fail;
@@ -259,9 +222,6 @@
 	dev->base_addr = (int) pci_ioaddr;
         dev->mem_start = (unsigned long) pci_iorange;
         dev->mem_end = ((unsigned long) pci_iorange) + pci_iolen - 1;
-	dev->open = orinoco_pci_open;
-	dev->stop = orinoco_pci_stop;
-/*  	priv->card_reset_handler = orinoco_pci_cor_reset; */
 
 	SET_MODULE_OWNER(dev);
 
@@ -272,7 +232,7 @@
 	hermes_struct_init(&(priv->hw), dev->base_addr, HERMES_MEM, HERMES_32BIT_REGSPACING);
 	pci_set_drvdata(pdev, dev);
 
-	err = request_irq(pdev->irq, orinoco_pci_interrupt, SA_SHIRQ, dev->name, priv);
+	err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, dev->name, priv);
 	if (err) {
 		printk(KERN_ERR "orinoco_pci: Error allocating IRQ %d.\n", pdev->irq);
 		err = -EBUSY;
@@ -291,25 +251,15 @@
 	priv->firmware_type = FIRMWARE_TYPE_INTERSIL;
 
 	err = register_netdev(dev);
-	if (err)
-		goto fail;
-	netdev_registered = 1;
-
-	err = orinoco_proc_dev_init(priv);
 	if (err) {
-		printk(KERN_ERR "%s: Failed to create /proc node\n", dev->name);
-		err = -EIO;
+		printk(KERN_ERR "%s: Failed to register net device\n", dev->name);
 		goto fail;
 	}
-
-	TRACE_EXIT("orinoco_pci");
+	netdev_registered = 1;
 
         return 0;               /* succeeded */
  fail:
-	printk(KERN_DEBUG "orinoco_pci: init_one(), FAIL!\n");
-
 	if (dev) {
-		orinoco_proc_dev_cleanup(priv);
 		if (netdev_registered)
 			unregister_netdev(dev);
 
@@ -330,13 +280,9 @@
 	struct net_device *dev = pci_get_drvdata(pdev);
 	struct orinoco_private *priv = dev->priv;
 
-	TRACE_ENTER("orinoco_pci");
-
 	if (! dev)
 		BUG();
 
-	orinoco_proc_dev_cleanup(priv);
-
 	unregister_netdev(dev);
 
         if (dev->irq)
@@ -345,13 +291,76 @@
 	if (priv->hw.iobase)
 		iounmap((unsigned char *) priv->hw.iobase);
 
+	pci_set_drvdata(pdev, NULL);
 	kfree(dev);
 
 	pci_disable_device(pdev);
+}
+
+static int orinoco_pci_suspend(struct pci_dev *pdev, u32 state)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct orinoco_private *priv = dev->priv;
+	unsigned long flags;
+	int err;
+	
+	printk(KERN_DEBUG "%s: Orinoco-PCI entering sleep mode (state=%d)\n",
+	       dev->name, state);
+
+	err = orinoco_lock(priv, &flags);
+	if (err) {
+		printk(KERN_ERR "%s: hw_unavailable on orinoco_pci_suspend\n",
+		       dev->name);
+		return err;
+	}
+
+	err = __orinoco_down(dev);
+	if (err)
+		printk(KERN_WARNING "%s: orinoco_pci_suspend(): Error %d downing interface\n",
+		       dev->name, err);
+	
+	netif_device_detach(dev);
+
+	priv->hw_unavailable = 1;
+	
+	orinoco_unlock(priv, &flags);
 
-	TRACE_EXIT("orinoco_pci");
+	return 0;
 }
 
+static int orinoco_pci_resume(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct orinoco_private *priv = dev->priv;
+	unsigned long flags;
+	int err;
+
+	printk(KERN_DEBUG "%s: Orinoco-PCI waking up\n", dev->name);
+
+	err = orinoco_reinit_firmware(dev);
+	if (err) {
+		printk(KERN_ERR "%s: Error %d re-initializing firmware on orinoco_pci_resume()\n",
+		       dev->name, err);
+		return err;
+	}
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	netif_device_attach(dev);
+
+	if (priv->open) {
+		err = __orinoco_up(dev);
+		if (err)
+			printk(KERN_ERR "%s: Error %d restarting card on orinoco_pci_resume()\n",
+			       dev->name, err);
+	}
+	
+	priv->hw_unavailable = 0;
+	
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	return 0;
+}
 
 static struct pci_device_id orinoco_pci_pci_id_table[] __devinitdata = {
 	{0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID,},
@@ -361,16 +370,22 @@
 MODULE_DEVICE_TABLE(pci, orinoco_pci_pci_id_table);
 
 static struct pci_driver orinoco_pci_driver = {
-	name:"orinoco_pci",
-	id_table:orinoco_pci_pci_id_table,
-	probe:orinoco_pci_init_one,
-	remove:__devexit_p(orinoco_pci_remove_one),
-	suspend:0,
-	resume:0
+	.name		= "orinoco_pci",
+	.id_table	= orinoco_pci_pci_id_table,
+	.probe		= orinoco_pci_init_one,
+	.remove		= __devexit_p(orinoco_pci_remove_one),
+	.suspend	= orinoco_pci_suspend,
+	.resume		= orinoco_pci_resume,
 };
 
+static char version[] __initdata = "orinoco_pci.c 0.13b (David Gibson <hermes@gibson.dropbear.id.au> & Jean Tourrilhes <jt@hpl.hp.com>)";
+MODULE_AUTHOR("David Gibson <hermes@gibson.dropbear.id.au>");
+MODULE_DESCRIPTION("Driver for wireless LAN cards using direct PCI interface");
+MODULE_LICENSE("Dual MPL/GPL");
+
 static int __init orinoco_pci_init(void)
 {
+	printk(KERN_DEBUG "%s\n", version);
 	return pci_module_init(&orinoco_pci_driver);
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/wireless/orinoco_plx.c linux-2.4.21-pre6/drivers/net/wireless/orinoco_plx.c
--- linux-2.4.20/drivers/net/wireless/orinoco_plx.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/wireless/orinoco_plx.c	2003-03-26 23:49:55.000000000 +0000
@@ -1,4 +1,4 @@
-/* orinoco_plx.c 0.11b
+/* orinoco_plx.c 0.13b
  * 
  * Driver for Prism II devices which would usually be driven by orinoco_cs,
  * but are connected to the PCI bus by a PLX9052. 
@@ -119,7 +119,6 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/system.h>
-#include <linux/proc_fs.h>
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/etherdevice.h>
@@ -134,13 +133,6 @@
 #include "hermes.h"
 #include "orinoco.h"
 
-static char version[] __initdata = "orinoco_plx.c 0.11b (Daniel Barlow <dan@telent.net>)";
-MODULE_AUTHOR("Daniel Barlow <dan@telent.net>");
-MODULE_DESCRIPTION("Driver for wireless LAN cards using the PLX9052 PCI bridge");
-#ifdef MODULE_LICENSE
-MODULE_LICENSE("Dual MPL/GPL");
-#endif
-
 static char dev_info[] = "orinoco_plx";
 
 #define COR_OFFSET    (0x3e0 / 2)	/* COR attribute offset of Prism2 PC card */
@@ -149,37 +141,6 @@
 #define PLX_INTCSR       0x4c /* Interrupt Control and Status Register */
 #define PLX_INTCSR_INTEN (1<<6) /* Interrupt Enable bit */
 
-static int orinoco_plx_open(struct net_device *dev)
-{
-	struct orinoco_private *priv = (struct orinoco_private *) dev->priv;
-	int err;
-
-	netif_device_attach(dev);
-
-	err = orinoco_reset(priv);
-	if (err)
-		printk(KERN_ERR "%s: orinoco_reset failed in orinoco_plx_open()",
-		       dev->name);
-	else
-		netif_start_queue(dev);
-
-	return err;
-}
-
-static int orinoco_plx_stop(struct net_device *dev)
-{
-	struct orinoco_private *priv = (struct orinoco_private *) dev->priv;
-	netif_stop_queue(dev);
-	orinoco_shutdown(priv);
-	return 0;
-}
-
-static void
-orinoco_plx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	orinoco_interrupt(irq, (struct orinoco_private *)dev_id, regs);
-}
-
 static const u16 cis_magic[] = {
 	0x0001, 0x0003, 0x0000, 0x0000, 0x00ff, 0x0017, 0x0004, 0x0067
 };
@@ -197,8 +158,6 @@
 	int netdev_registered = 0;
 	int i;
 
-	TRACE_ENTER("orinoco_plx");
-
 	err = pci_enable_device(pdev);
 	if (err)
 		return -EIO;
@@ -266,7 +225,7 @@
 		goto fail;
 	}
 
-	dev = alloc_orinocodev(0);
+	dev = alloc_orinocodev(0, NULL);
 	if (! dev) {
 		err = -ENOMEM;
 		goto fail;
@@ -274,8 +233,6 @@
 
 	priv = dev->priv;
 	dev->base_addr = pccard_ioaddr;
-	dev->open = orinoco_plx_open;
-	dev->stop = orinoco_plx_stop;
 	SET_MODULE_OWNER(dev);
 
 	printk(KERN_DEBUG
@@ -286,7 +243,7 @@
 			HERMES_IO, HERMES_16BIT_REGSPACING);
 	pci_set_drvdata(pdev, dev);
 
-	err = request_irq(pdev->irq, orinoco_plx_interrupt, SA_SHIRQ, dev->name, priv);
+	err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, dev->name, priv);
 	if (err) {
 		printk(KERN_ERR "orinoco_plx: Error allocating IRQ %d.\n", pdev->irq);
 		err = -EBUSY;
@@ -299,20 +256,12 @@
 		goto fail;
 	netdev_registered = 1;
 
-	err = orinoco_proc_dev_init(priv);
-	if (err)
-		goto fail;
-
-	TRACE_EXIT("orinoco_plx");
-
 	return 0;		/* succeeded */
 
  fail:	
 	printk(KERN_DEBUG "orinoco_plx: init_one(), FAIL!\n");
 
 	if (priv) {
-		orinoco_proc_dev_cleanup(priv);
-
 		if (netdev_registered)
 			unregister_netdev(dev);
 		
@@ -330,8 +279,6 @@
 
 	pci_disable_device(pdev);
 
-	TRACE_EXIT("orinoco_plx");
-	
 	return err;
 }
 
@@ -340,30 +287,25 @@
 	struct net_device *dev = pci_get_drvdata(pdev);
 	struct orinoco_private *priv = dev->priv;
 
-	TRACE_ENTER("orinoco_plx");
-
 	if (! dev)
 		BUG();
 
-	orinoco_proc_dev_cleanup(priv);
-
 	unregister_netdev(dev);
 		
 	if (dev->irq)
 		free_irq(dev->irq, priv);
 		
+	pci_set_drvdata(pdev, NULL);
+
 	kfree(dev);
 
 	release_region(pci_resource_start(pdev, 3), pci_resource_len(pdev, 3));
 
 	pci_disable_device(pdev);
-
-	TRACE_EXIT("orinoco_plx");
 }
 
 
 static struct pci_device_id orinoco_plx_pci_id_table[] __devinitdata = {
-	{0x10b7, 0x7770, PCI_ANY_ID, PCI_ANY_ID,},	/* 3ComAirConnect */
 	{0x111a, 0x1023, PCI_ANY_ID, PCI_ANY_ID,},	/* Siemens SpeedStream SS1023 */
 	{0x1385, 0x4100, PCI_ANY_ID, PCI_ANY_ID,},	/* Netgear MA301 */
 	{0x15e8, 0x0130, PCI_ANY_ID, PCI_ANY_ID,},	/* Correga  - does this work? */
@@ -376,21 +318,29 @@
 	{0x16ec, 0x3685, PCI_ANY_ID, PCI_ANY_ID,},	/* USR 2415 */
 	{0xec80, 0xec00, PCI_ANY_ID, PCI_ANY_ID,},	/* Belkin F5D6000 tested by
 							   Brendan W. McAdams <rit@jacked-in.org> */
-	{0x126c, 0x8030, PCI_ANY_ID, PCI_ANY_ID,},	/* Nortel emobility */
+	{0x10b7, 0x7770, PCI_ANY_ID, PCI_ANY_ID,},	/* 3Com AirConnect PCI tested by
+							   Damien Persohn <damien@persohn.net> */
 	{0,},
 };
 
 MODULE_DEVICE_TABLE(pci, orinoco_plx_pci_id_table);
 
 static struct pci_driver orinoco_plx_driver = {
-	name:"orinoco_plx",
-	id_table:orinoco_plx_pci_id_table,
-	probe:orinoco_plx_init_one,
-	remove:__devexit_p(orinoco_plx_remove_one),
-	suspend:0,
-	resume:0
+	.name		= "orinoco_plx",
+	.id_table	= orinoco_plx_pci_id_table,
+	.probe		= orinoco_plx_init_one,
+	.remove		= __devexit_p(orinoco_plx_remove_one),
+	.suspend	= 0,
+	.resume		= 0,
 };
 
+static char version[] __initdata = "orinoco_plx.c 0.13b (Daniel Barlow <dan@telent.net>, David Gibson <hermes@gibson.dropbear.id.au>)";
+MODULE_AUTHOR("Daniel Barlow <dan@telent.net>");
+MODULE_DESCRIPTION("Driver for wireless LAN cards using the PLX9052 PCI bridge");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("Dual MPL/GPL");
+#endif
+
 static int __init orinoco_plx_init(void)
 {
 	printk(KERN_DEBUG "%s\n", version);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/yellowfin.c linux-2.4.21-pre6/drivers/net/yellowfin.c
--- linux-2.4.20/drivers/net/yellowfin.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/yellowfin.c	2003-03-26 23:49:29.000000000 +0000
@@ -857,6 +857,7 @@
 {
 	struct yellowfin_private *yp = dev->priv;
 	unsigned entry;
+	int len = skb->len;
 
 	netif_stop_queue (dev);
 
@@ -872,27 +873,37 @@
 		int cacheline_end = ((unsigned long)skb->data + skb->len) % 32;
 		/* Fix GX chipset errata. */
 		if (cacheline_end > 24  || cacheline_end == 0)
-			skb->len += 32 - cacheline_end + 1;
+		{
+			len = skb->len + 32 - cacheline_end + 1;
+			if(len != skb->len)
+				skb = skb_padto(skb, len);
+		}
+		if(skb == NULL)
+		{
+			yp->tx_skbuff[entry] = NULL;
+			netif_wake_queue(dev);
+			return 0;
+		}
 	}
 #ifdef NO_TXSTATS
 	yp->tx_ring[entry].addr = cpu_to_le32(pci_map_single(yp->pci_dev, 
-		skb->data, skb->len, PCI_DMA_TODEVICE));
+		skb->data, len, PCI_DMA_TODEVICE));
 	yp->tx_ring[entry].result_status = 0;
 	if (entry >= TX_RING_SIZE-1) {
 		/* New stop command. */
 		yp->tx_ring[0].dbdma_cmd = cpu_to_le32(CMD_STOP);
 		yp->tx_ring[TX_RING_SIZE-1].dbdma_cmd =
-			cpu_to_le32(CMD_TX_PKT|BRANCH_ALWAYS | skb->len);
+			cpu_to_le32(CMD_TX_PKT|BRANCH_ALWAYS | len);
 	} else {
 		yp->tx_ring[entry+1].dbdma_cmd = cpu_to_le32(CMD_STOP);
 		yp->tx_ring[entry].dbdma_cmd =
-			cpu_to_le32(CMD_TX_PKT | BRANCH_IFTRUE | skb->len);
+			cpu_to_le32(CMD_TX_PKT | BRANCH_IFTRUE | len);
 	}
 	yp->cur_tx++;
 #else
-	yp->tx_ring[entry<<1].request_cnt = skb->len;
+	yp->tx_ring[entry<<1].request_cnt = len;
 	yp->tx_ring[entry<<1].addr = cpu_to_le32(pci_map_single(yp->pci_dev, 
-		skb->data, skb->len, PCI_DMA_TODEVICE));
+		skb->data, len, PCI_DMA_TODEVICE));
 	/* The input_last (status-write) command is constant, but we must 
 	   rewrite the subsequent 'stop' command. */
 
@@ -905,7 +916,7 @@
 
 	yp->tx_ring[entry<<1].dbdma_cmd =
 		cpu_to_le32( ((entry % 6) == 0 ? CMD_TX_PKT|INTR_ALWAYS|BRANCH_IFTRUE :
-					  CMD_TX_PKT | BRANCH_IFTRUE) | skb->len);
+					  CMD_TX_PKT | BRANCH_IFTRUE) | len);
 #endif
 
 	/* Non-x86 Todo: explicitly flush cache lines here. */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/net/znet.c linux-2.4.21-pre6/drivers/net/znet.c
--- linux-2.4.20/drivers/net/znet.c	2001-07-18 01:53:55.000000000 +0000
+++ linux-2.4.21-pre6/drivers/net/znet.c	2003-03-26 23:48:57.000000000 +0000
@@ -348,10 +348,19 @@
 	int ioaddr = dev->base_addr;
 	struct net_local *lp = (struct net_local *)dev->priv;
 	unsigned long flags;
+	short length = skb->len;
 
 	if (znet_debug > 4)
 		printk(KERN_DEBUG "%s: ZNet_send_packet.\n", dev->name);
 
+	if(length < ETH_ZLEN)
+	{
+		skb = skb_padto(skb, ETH_ZLEN);
+		if(skb == NULL)
+			return 0;
+		length = ETH_ZLEN;
+	}
+	
 	netif_stop_queue (dev);
 	
 	/* Check that the part hasn't reset itself, probably from suspend. */
@@ -362,7 +371,6 @@
 	  hardware_init(dev);
 
 	if (1) {
-		short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
 		unsigned char *buf = (void *)skb->data;
 		ushort *tx_link = zn.tx_cur - 1;
 		ushort rnd_len = (length + 1)>>1;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/parport/ChangeLog linux-2.4.21-pre6/drivers/parport/ChangeLog
--- linux-2.4.20/drivers/parport/ChangeLog	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/parport/ChangeLog	2003-03-26 23:49:50.000000000 +0000
@@ -1,3 +1,7 @@
+2002-11-29  Tim Waugh  <twaugh@redhat.com>
+
+	* parport_pc.c: Fix ECP hang on Aladdin card.
+
 2002-04-25  Tim Waugh  <twaugh@redhat.com>
 
 	* parport_serial.c, parport_pc.c: Move some SIIG cards around.
@@ -278,7 +282,7 @@
 	* parport_pc.c (parport_pc_probe_port): Remove __devinit
 	attribute.  Export unconditionally.
 
-2001-04-14  Jeff Garzik  <jgarzik@mandrakesoft.com>
+2001-04-14  Jeff Garzik  <jgarzik@pobox.com>
 
 	Merged:  2001-03-30  Tim Waugh  <twaugh@redhat.com>
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/parport/parport_cs.c linux-2.4.21-pre6/drivers/parport/parport_cs.c
--- linux-2.4.20/drivers/parport/parport_cs.c	2001-12-21 17:41:55.000000000 +0000
+++ linux-2.4.21-pre6/drivers/parport/parport_cs.c	2003-03-26 23:49:55.000000000 +0000
@@ -5,7 +5,7 @@
     (specifically, for the Quatech SPP-100 EPP card: other cards will
     probably require driver tweaks)
     
-    parport_cs.c 1.24 2001/10/13 14:04:05
+    parport_cs.c 1.29 2002/10/11 06:57:41
 
     The contents of this file are subject to the Mozilla Public
     License Version 1.1 (the "License"); you may not use this file
@@ -34,9 +34,7 @@
     
 ======================================================================*/
 
-
 #include <linux/kernel.h>
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/sched.h>
@@ -78,7 +76,7 @@
 INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
 static char *version =
-"parport_cs.c 1.24 2001/10/13 14:04:05 (David Hinds)";
+"parport_cs.c 1.29 2002/10/11 06:57:41 (David Hinds)";
 #else
 #define DEBUG(n, args...)
 #endif
@@ -224,12 +222,6 @@
 #define CFG_CHECK(fn, args...) \
 if (CardServices(fn, args) != 0) goto next_entry
 
-static struct { u_int flag; char *name; } mode[] = {
-    { PARPORT_MODE_TRISTATE, "PS2" },
-    { PARPORT_MODE_EPP, "EPP" },
-    { PARPORT_MODE_ECP, "ECP" },
-};
-
 void parport_config(dev_link_t *link)
 {
     client_handle_t handle = link->handle;
@@ -241,7 +233,7 @@
     cistpl_cftable_entry_t *cfg = &parse.cftable_entry;
     cistpl_cftable_entry_t dflt = { 0 };
     struct parport *p;
-    int i, last_ret, last_fn;
+    int last_ret, last_fn;
     
     DEBUG(0, "parport_config(0x%p)\n", link);
     
@@ -293,6 +285,9 @@
     CS_CHECK(RequestIRQ, handle, &link->irq);
     CS_CHECK(RequestConfiguration, handle, &link->conf);
 
+    release_region(link->io.BasePort1, link->io.NumPorts1);
+    if (link->io.NumPorts2)
+	release_region(link->io.BasePort2, link->io.NumPorts2);
     p = parport_pc_probe_port(link->io.BasePort1, link->io.BasePort2,
 			      link->irq.AssignedIRQ, PARPORT_DMA_NONE,
 			      NULL);
@@ -312,15 +307,7 @@
     info->port = p;
     strcpy(info->node.dev_name, p->name);
     link->dev = &info->node;
-    printk(KERN_INFO "%s: PC-style PCMCIA at %#x", p->name,
-	   link->io.BasePort1);
-    if (link->io.NumPorts2)
-	printk(" & %#x", link->io.BasePort2);
-    printk(", irq %u [SPP", link->irq.AssignedIRQ);
-    for (i = 0; i < 5; i++)
-	if (p->modes & mode[i].flag) printk(",%s", mode[i].name);
-    printk("]\n");
-    
+
     link->state &= ~DEV_CONFIG_PENDING;
     return;
     
@@ -328,6 +315,7 @@
     cs_error(link->handle, last_fn, last_ret);
 failed:
     parport_cs_release((u_long)link);
+    link->state &= ~DEV_CONFIG_PENDING;
 
 } /* parport_config */
 
@@ -348,9 +336,12 @@
 
     if (info->ndev) {
 	struct parport *p = info->port;
-	parport_proc_unregister(p);
-	kfree(p->private_data);
-	parport_unregister_port(p);
+	parport_pc_unregister_port(p);
+	request_region(link->io.BasePort1, link->io.NumPorts1,
+		       info->node.dev_name);
+	if (link->io.NumPorts2)
+	    request_region(link->io.BasePort2, link->io.NumPorts2,
+			   info->node.dev_name);
     }
     info->ndev = 0;
     link->dev = NULL;
@@ -415,9 +406,8 @@
     if (serv.Revision != CS_RELEASE_CODE) {
 	printk(KERN_NOTICE "parport_cs: Card Services release "
 	       "does not match!\n");
-	return -1;
+	return -EINVAL;
     }
-
     register_pccard_driver(&dev_info, &parport_attach, &parport_detach);
     return 0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/parport/parport_pc.c linux-2.4.21-pre6/drivers/parport/parport_pc.c
--- linux-2.4.20/drivers/parport/parport_pc.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/parport/parport_pc.c	2003-03-26 23:49:34.000000000 +0000
@@ -2533,7 +2533,7 @@
 	return 0;
 }
 
-/* Via support maintained by Jeff Garzik <jgarzik@mandrakesoft.com> */
+/* Via support maintained by Jeff Garzik <jgarzik@pobox.com> */
 static int __devinit sio_via_686a_probe (struct pci_dev *pdev, int autoirq,
 					 int autodma)
 {
@@ -2766,7 +2766,7 @@
 	 * and 840 locks up if you write 1 to bit 2! */
 	/* oxsemi_954 */		{ 1, { { 0, -1 }, } },
 	/* oxsemi_840 */		{ 1, { { 0, -1 }, } },
-	/* aks_0100 */			{ 1, { { 0, 1 }, } },
+	/* aks_0100 */			{ 1, { { 0, -1 }, } },
 	/* mobility_pp */		{ 1, { { 0, 1 }, } },
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/pci/pci.c linux-2.4.21-pre6/drivers/pci/pci.c
--- linux-2.4.20/drivers/pci/pci.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/pci/pci.c	2003-03-26 23:49:20.000000000 +0000
@@ -163,6 +163,8 @@
  *  %PCI_CAP_ID_MSI          Message Signalled Interrupts
  *
  *  %PCI_CAP_ID_CHSWP        CompactPCI HotSwap 
+ *
+ *  %PCI_CAP_ID_PCIX         PCI-X
  */
 int
 pci_find_capability(struct pci_dev *dev, int cap)
@@ -930,14 +932,13 @@
 	pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &cache_size);
 	cache_size <<= 2;
 	if (cache_size != SMP_CACHE_BYTES) {
-		printk(KERN_WARNING "PCI: %s PCI cache line size set incorrectly "
-		       "(%i bytes) by BIOS/FW, ",
+		printk(KERN_WARNING "PCI: %s PCI cache line size set incorrectly (%i bytes) by BIOS/FW.\n",
 		       dev->slot_name, cache_size);
 		if (cache_size > SMP_CACHE_BYTES) {
-			printk("expecting %i\n", SMP_CACHE_BYTES);
+			printk("PCI: %s cache line size too large - expecting %i.\n", dev->slot_name, SMP_CACHE_BYTES);
 			rc = -EINVAL;
 		} else {
-			printk("correcting to %i\n", SMP_CACHE_BYTES);
+			printk("PCI: %s PCI cache line size corrected to %i.\n", dev->slot_name, SMP_CACHE_BYTES);
 			pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
 					      SMP_CACHE_BYTES >> 2);
 		}
@@ -1037,13 +1038,20 @@
 }
 
 /*
- * Find the extent of a PCI decode..
+ * Find the extent of a PCI decode, do sanity checks.
  */
-static u32 pci_size(u32 base, unsigned long mask)
+static u32 pci_size(u32 base, u32 maxbase, unsigned long mask)
 {
-	u32 size = mask & base;		/* Find the significant bits */
+	u32 size = mask & maxbase;	/* Find the significant bits */
+	if (!size)
+		return 0;
 	size = size & ~(size-1);	/* Get the lowest of them to find the decode size */
-	return size-1;			/* extent = size - 1 */
+	size -= 1;			/* extent = size - 1 */
+	if (base == maxbase && ((base | size) & mask) != mask)
+		return 0;		/* base == maxbase can be valid only
+					   if the BAR has been already
+					   programmed with all 1s */
+	return size;
 }
 
 static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
@@ -1066,13 +1074,17 @@
 		if (l == 0xffffffff)
 			l = 0;
 		if ((l & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) {
+			sz = pci_size(l, sz, PCI_BASE_ADDRESS_MEM_MASK);
+			if (!sz)
+				continue;
 			res->start = l & PCI_BASE_ADDRESS_MEM_MASK;
 			res->flags |= l & ~PCI_BASE_ADDRESS_MEM_MASK;
-			sz = pci_size(sz, PCI_BASE_ADDRESS_MEM_MASK);
 		} else {
+			sz = pci_size(l, sz, PCI_BASE_ADDRESS_IO_MASK & 0xffff);
+			if (!sz)
+				continue;
 			res->start = l & PCI_BASE_ADDRESS_IO_MASK;
 			res->flags |= l & ~PCI_BASE_ADDRESS_IO_MASK;
-			sz = pci_size(sz, PCI_BASE_ADDRESS_IO_MASK & 0xffff);
 		}
 		res->end = res->start + (unsigned long) sz;
 		res->flags |= pci_calc_resource_flags(l);
@@ -1102,6 +1114,7 @@
 	if (rom) {
 		dev->rom_base_reg = rom;
 		res = &dev->resource[PCI_ROM_RESOURCE];
+		res->name = dev->name;
 		pci_read_config_dword(dev, rom, &l);
 		pci_write_config_dword(dev, rom, ~PCI_ROM_ADDRESS_ENABLE);
 		pci_read_config_dword(dev, rom, &sz);
@@ -1109,13 +1122,14 @@
 		if (l == 0xffffffff)
 			l = 0;
 		if (sz && sz != 0xffffffff) {
+			sz = pci_size(l, sz, PCI_ROM_ADDRESS_MASK);
+			if (!sz)
+				return;
 			res->flags = (l & PCI_ROM_ADDRESS_ENABLE) |
 			  IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_READONLY | IORESOURCE_CACHEABLE;
 			res->start = l & PCI_ROM_ADDRESS_MASK;
-			sz = pci_size(sz, PCI_ROM_ADDRESS_MASK);
 			res->end = res->start + (unsigned long) sz;
 		}
-		res->name = dev->name;
 	}
 }
 
@@ -2153,6 +2167,8 @@
 EXPORT_SYMBOL(pci_do_scan_bus);
 EXPORT_SYMBOL(pci_scan_slot);
 EXPORT_SYMBOL(pci_scan_bus);
+EXPORT_SYMBOL(pci_scan_device);
+EXPORT_SYMBOL(pci_read_bridge_bases);
 #ifdef CONFIG_PROC_FS
 EXPORT_SYMBOL(pci_proc_attach_device);
 EXPORT_SYMBOL(pci_proc_detach_device);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/pci/pci.ids linux-2.4.21-pre6/drivers/pci/pci.ids
--- linux-2.4.20/drivers/pci/pci.ids	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/pci/pci.ids	2003-03-26 23:49:39.000000000 +0000
@@ -582,6 +582,7 @@
 	6003  CS 4614/22/24 [CrystalClear SoundFusion Audio Accelerator]
 		1013 4280  Crystal SoundFusion PCI Audio Accelerator
 		1681 0050  Hercules Game Theater XP
+		1681 a011  Hercules Fortissimo III 7.1
 	6004  CS 4614/22/24 [CrystalClear SoundFusion Audio Accelerator]
 	6005  Crystal CS4281 PCI Audio
 		1013 4281  Crystal CS4281 PCI Audio
@@ -2617,6 +2618,7 @@
 10fc  I-O Data Device, Inc.
 # What's in the cardbus end of a Sony ACR-A01 card, comes with newer Vaio CD-RW drives
 	0003  Cardbus IDE Controller
+	0005  Cardbus SCSI CBSC II
 10fd  Soyo Computer, Inc
 10fe  Fast Multimedia AG
 10ff  NCube
@@ -2678,6 +2680,7 @@
 	0505  VT82C505
 	0561  VT82C561
 	0571  VT82C586B PIPC Bus Master IDE
+		1458 5002 GA-7VAX Mainboard
 	0576  VT82C576 3V [Apollo Master]
 	0585  VT82C585VP [Apollo VP1/VPX]
 	0586  VT82C586/A/B PCI-to-ISA [Apollo VP]
@@ -2726,6 +2729,7 @@
 		1462 3091  MS-6309 Onboard Audio
 		15dd 7609  Onboard Audio
 	3059  VT8233 AC97 Audio Controller
+		1458 a002  GA-7VAX Onboard Audio (Realtek ALC650) 
 	3065  VT6102 [Rhine-II]
 		1186 1400  DFE-530TX rev A
 		1186 1401  DFE-530TX rev B
@@ -2739,6 +2743,7 @@
 	3102  VT8662 Host Bridge
 	3103  VT8615 Host Bridge
 	3104  USB 2.0
+		1458 5004  GA-7VAX Mainboard
 	3109  VT8233C PCI to ISA Bridge
 	3112  VT8361 [KLE133] Host Bridge
 	3128  VT8753 [P4X266 AGP]
@@ -2747,6 +2752,9 @@
 	3148  P4M266 Host Bridge
 	3156  P/KN266 Host Bridge
 	3177  VT8233A ISA Bridge
+		1458 5001 GA-7VAX Mainboard
+	3189  VT8377 [KT400 AGP] Host Bridge
+		1458 5000 GA-7VAX Mainboard
 	5030  VT82C596 ACPI [Apollo PRO]
 	6100  VT85C100A [Rhine II]
 	8231  VT8231 [PCI-to-ISA Bridge]
@@ -2767,6 +2775,7 @@
 	b102  VT8362 AGP Bridge
 	b103  VT8615 AGP Bridge
 	b112  VT8361 [KLE133] AGP Bridge
+	b168  VT8235 PCI Bridge
 1107  Stratus Computers
 	0576  VIA VT82C570MV [Apollo] (Wrong vendor ID!)
 1108  Proteon, Inc.
@@ -3027,9 +3036,15 @@
 1144  Cincinnati Milacron
 	0001  Noservo controller
 1145  Workbit Corporation
+	f007  NinjaSCSI-32 KME
+	8007  NinjaSCSI-32 Workbit
+	f010  NinjaSCSI-32 Workbit
+	f012  NinjaSCSI-32 Logitec
+	f013  NinjaSCSI-32 Logitec
+	f015  NinjaSCSI-32 Melco
 1146  Force Computers
 1147  Interface Corp
-1148  Syskonnect (Schneider & Koch)
+1148  SysKonnect
 	4000  FDDI Adapter
 		0e11 b03b  Netelligent 100 FDDI DAS Fibre SC
 		0e11 b03c  Netelligent 100 FDDI SAS Fibre SC
@@ -3047,15 +3062,25 @@
 		1148 5843  FDDI SK-5843 (SK-NET FDDI-LP64)
 		1148 5844  FDDI SK-5844 (SK-NET FDDI-LP64 DAS)
 	4200  Token Ring adapter
-	4300  Gigabit Ethernet
-		1148 9821  SK-9821 (1000Base-T single link)
-		1148 9822  SK-9822 (1000Base-T dual link)
-		1148 9841  SK-9841 (1000Base-LX single link)
-		1148 9842  SK-9842 (1000Base-LX dual link)
-		1148 9843  SK-9843 (1000Base-SX single link)
-		1148 9844  SK-9844 (1000Base-SX dual link)
-		1148 9861  SK-9861 (1000Base-SX VF45 single link)
-		1148 9862  SK-9862 (1000Base-SX VF45 dual link)
+	4300  SK-98xx Gigabit Ethernet Server Adapter
+		1148 9821  SK-9821 Gigabit Ethernet 1000Base-T Server Adapter
+		1148 9822  SK-9822 Gigabit Ethernet 1000Base-T Dual Port Server Adapter
+		1148 9841  SK-9841 Gigabit Ethernet 1000Base-LX Server Adapter
+		1148 9842  SK-9842 Gigabit Ethernet 1000Base-LX Dual Port Server Adapter
+		1148 9843  SK-9843 Gigabit Ethernet 1000Base-SX Server Adapter
+		1148 9844  SK-9844 Gigabit Ethernet 1000Base-SX Dual Port Server Adapter
+		1148 9861  SK-9861 Gigabit Ethernet 1000Base-SX Server Adapter
+		1148 9862  SK-9862 Gigabit Ethernet 1000Base-SX Dual Port Server Adapter
+		1148 9871  SK-9871 Gigabit Ethernet 1000Base-ZX Server Adapter
+		1148 9872  SK-9872 Gigabit Ethernet 1000Base-ZX Dual Port Server Adapter
+	4320  SK-98xx Gigabit Ethernet Server Adapter
+		1148 9521  SK-9521 10/100/1000Base-T Adapter
+		1148 5021  SK-9821 V2.0 Gigabit Ethernet 10/100/1000Base-T Adapter
+		1148 5041  SK-9841 V2.0 Gigabit Ethernet 1000Base-LX Adapter
+		1148 5043  SK-9843 V2.0 Gigabit Ethernet 1000Base-SX Adapter
+		1148 5051  SK-9851 V2.0 Gigabit Ethernet 1000Base-SX Adapter
+		1148 5061  SK-9861 V2.0 Gigabit Ethernet 1000Base-SX Adapter
+		1148 5071  SK-9871 V2.0 Gigabit Ethernet 1000Base-ZX Adapter
 	4400  Gigabit Ethernet
 1149  Win System Corporation
 114a  VMIC
@@ -5063,6 +5088,9 @@
 	164d  NetXtreme BCM5702FE Gigabit Ethernet
 	16a6  NetXtreme BCM5702X Gigabit Ethernet
 	16a7  NetXtreme BCM5703X Gigabit Ethernet
+	16a8  NetXtreme BCM5704S Gigabit Ethernet
+	16c6  NetXtreme BCM5702A3 Gigabit Ethernet
+	16c7  NetXtreme BCM5703A3 Gigabit Ethernet
 	4212  BCM v.90 56k modem
 	5820  BCM5820 Crypto Accelerator
 	5821  BCM5821 Crypto Accelerator
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/pci/quirks.c linux-2.4.21-pre6/drivers/pci/quirks.c
--- linux-2.4.20/drivers/pci/quirks.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/pci/quirks.c	2003-03-26 23:48:58.000000000 +0000
@@ -167,6 +167,21 @@
 	}
 }
 
+/*
+ *	Ali Magik requires workarounds to be used by the drivers
+ *	that DMA to AGP space. Latency must be set to 0xA and triton
+ *	workaround applied too
+ *	[Info kindly provided by ALi]
+ */	
+ 
+static void __init quirk_alimagik(struct pci_dev *dev)
+{
+	if((pci_pci_problems&PCIPCI_ALIMAGIK)==0)
+	{
+		printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n");
+		pci_pci_problems|=PCIPCI_ALIMAGIK|PCIPCI_TRITON;
+	}
+}
 
 /*
  *	Natoma has some interesting boundary conditions with Zoran stuff
@@ -212,6 +227,18 @@
 }	
 
 /*
+ *	ATI Northbridge setups MCE the processor if you even
+ *	read somewhere between 0x3b0->0x3bb or read 0x3d3
+ */
+ 
+static void __devinit quirk_ati_exploding_mce(struct pci_dev *dev)
+{
+	printk(KERN_INFO "ATI Northbridge, reserving I/O ports 0x3b0 to 0x3bb.\n");
+	request_region(0x3b0, 0x0C, "RadeonIGP");
+	request_region(0x3d3, 0x01, "RadeonIGP");
+}
+
+/*
  * Let's make the southbridge information explicit instead
  * of having to worry about people probing the ACPI areas,
  * for example.. (Yes, it happens, and if you read the wrong
@@ -456,6 +483,31 @@
 	}
 }
 
+#ifdef CONFIG_X86_IO_APIC
+
+#define AMD8131_revA0        0x01
+#define AMD8131_revB0        0x11
+#define AMD8131_MISC         0x40
+#define AMD8131_NIOAMODE_BIT 0
+
+static void __init quirk_amd_8131_ioapic(struct pci_dev *dev) 
+{ 
+	unsigned char revid, tmp;
+	
+	if (nr_ioapics == 0) 
+		return;
+
+	pci_read_config_byte(dev, PCI_REVISION_ID, &revid);
+	if (revid == AMD8131_revA0 || revid == AMD8131_revB0) {
+		printk(KERN_INFO "Fixing up AMD8131 IOAPIC mode\n"); 
+		pci_read_config_byte( dev, AMD8131_MISC, &tmp);
+		tmp &= ~(1 << AMD8131_NIOAMODE_BIT);
+		pci_write_config_byte( dev, AMD8131_MISC, tmp);
+	}
+} 
+#endif
+
+
 /*
  *	DreamWorks provided workaround for Dunord I-3000 problem
  *
@@ -495,6 +547,91 @@
 }
 
 /*
+ * As per PCI spec, ignore base address registers 0-3 of the IDE controllers
+ * running in Compatible mode (bits 0 and 2 in the ProgIf for primary and
+ * secondary channels respectively). If the device reports Compatible mode
+ * but does use BAR0-3 for address decoding, we assume that firmware has
+ * programmed these BARs with standard values (0x1f0,0x3f4 and 0x170,0x374).
+ * Exceptions (if they exist) must be handled in chip/architecture specific
+ * fixups.
+ *
+ * Note: for non x86 people. You may need an arch specific quirk to handle
+ * moving IDE devices to native mode as well. Some plug in card devices power
+ * up in compatible mode and assume the BIOS will adjust them.
+ *
+ * Q: should we load the 0x1f0,0x3f4 into the registers or zap them as
+ * we do now ? We don't want is pci_enable_device to come along
+ * and assign new resources. Both approaches work for that.
+ */ 
+
+static void __devinit quirk_ide_bases(struct pci_dev *dev)
+{
+       struct resource *res;
+       int first_bar = 2, last_bar = 0;
+
+       if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE)
+               return;
+
+       res = &dev->resource[0];
+
+       /* primary channel: ProgIf bit 0, BAR0, BAR1 */
+       if (!(dev->class & 1) && (res[0].flags || res[1].flags)) { 
+               res[0].start = res[0].end = res[0].flags = 0;
+               res[1].start = res[1].end = res[1].flags = 0;
+               first_bar = 0;
+               last_bar = 1;
+       }
+
+       /* secondary channel: ProgIf bit 2, BAR2, BAR3 */
+       if (!(dev->class & 4) && (res[2].flags || res[3].flags)) { 
+               res[2].start = res[2].end = res[2].flags = 0;
+               res[3].start = res[3].end = res[3].flags = 0;
+               last_bar = 3;
+       }
+
+       if (!last_bar)
+               return;
+
+       printk(KERN_INFO "PCI: Ignoring BAR%d-%d of IDE controller %s\n",
+              first_bar, last_bar, dev->slot_name);
+}
+
+/*
+ *	Ensure C0 rev restreaming is off. This is normally done by
+ *	the BIOS but in the odd case it is not the results are corruption
+ *	hence the presence of a Linux check
+ */
+ 
+static void __init quirk_disable_pxb(struct pci_dev *pdev)
+{
+	u16 config;
+	u8 rev;
+	
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
+	if(rev != 0x04)		/* Only C0 requires this */
+		return;
+	pci_read_config_word(pdev, 0x40, &config);
+	if(config & (1<<6))
+	{
+		config &= ~(1<<6);
+		pci_write_config_word(pdev, 0x40, config);
+		printk(KERN_INFO "PCI: C0 revision 450NX. Disabling PCI restreaming.\n");
+	}
+}
+
+/*
+ *	VIA northbridges care about PCI_INTERRUPT_LINE
+ */
+ 
+int interrupt_line_quirk;
+
+static void __init quirk_via_bridge(struct pci_dev *pdev)
+{
+	if(pdev->devfn == 0)
+		interrupt_line_quirk = 1;
+}
+	
+/*
  *  The main table of quirks.
  */
 
@@ -509,6 +646,7 @@
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C586_0,	quirk_isa_dma_hangs },
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C596,	quirk_isa_dma_hangs },
 	{ PCI_FIXUP_FINAL,      PCI_VENDOR_ID_INTEL,    PCI_DEVICE_ID_INTEL_82371SB_0,  quirk_isa_dma_hangs },
+	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82454NX,	quirk_disable_pxb },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_S3,	PCI_DEVICE_ID_S3_868,		quirk_s3_64M },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_S3,	PCI_DEVICE_ID_S3_968,		quirk_s3_64M },
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82437, 	quirk_triton }, 
@@ -521,6 +659,8 @@
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82443BX_0, 	quirk_natoma }, 
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82443BX_1, 	quirk_natoma }, 
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82443BX_2, 	quirk_natoma },
+	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_AL, 	PCI_DEVICE_ID_AL_M1647, 	quirk_alimagik },
+	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_AL, 	PCI_DEVICE_ID_AL_M1651, 	quirk_alimagik },
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_5597,		quirk_nopcipci },
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_496,		quirk_nopcipci },
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8363_0,	quirk_vialatency },
@@ -535,6 +675,8 @@
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_AL,	PCI_DEVICE_ID_AL_M7101,		quirk_ali7101_acpi },
  	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82371SB_2,	quirk_piix3_usb },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82371AB_2,	quirk_piix3_usb },
+	{ PCI_FIXUP_HEADER,     PCI_ANY_ID,             PCI_ANY_ID,                     quirk_ide_bases },
+	{ PCI_FIXUP_HEADER,     PCI_VENDOR_ID_VIA,	PCI_ANY_ID,                     quirk_via_bridge },
 	{ PCI_FIXUP_FINAL,	PCI_ANY_ID,		PCI_ANY_ID,			quirk_cardbus_legacy },
 
 #ifdef CONFIG_X86_IO_APIC 
@@ -548,6 +690,7 @@
 
 	{ PCI_FIXUP_FINAL, 	PCI_VENDOR_ID_AMD,	PCI_DEVICE_ID_AMD_VIPER_7410,	quirk_amd_ioapic },
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_AMD,	PCI_DEVICE_ID_AMD_FE_GATE_700C, quirk_amd_ordering },
+	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_ATI,	PCI_DEVICE_ID_ATI_RADEON_IGP,   quirk_ati_exploding_mce },
 	/*
 	 * i82380FB mobile docking controller: its PCI-to-PCI bridge
 	 * is subtractive decoding (transparent), and does indicate this
@@ -555,9 +698,15 @@
 	 * instead of 0x01.
 	 */
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82380FB,	quirk_transparent_bridge },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_TOSHIBA,	0x605,				quirk_transparent_bridge },
 
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_CYRIX,	PCI_DEVICE_ID_CYRIX_PCI_MASTER, quirk_mediagx_master },
 
+#ifdef CONFIG_X86_IO_APIC
+	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_AMD,      PCI_DEVICE_ID_AMD_8131_APIC, 
+	  quirk_amd_8131_ioapic }, 
+#endif
+
 	{ 0 }
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/pcmcia/cardbus.c linux-2.4.21-pre6/drivers/pcmcia/cardbus.c
--- linux-2.4.20/drivers/pcmcia/cardbus.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/pcmcia/cardbus.c	2003-03-26 23:49:19.000000000 +0000
@@ -2,7 +2,7 @@
   
     Cardbus device configuration
     
-    cardbus.c 1.63 1999/11/08 20:47:02
+    cardbus.c 1.87 2002/10/24 06:11:41
 
     The contents of this file are subject to the Mozilla Public
     License Version 1.1 (the "License"); you may not use this file
@@ -175,8 +175,8 @@
     
 =====================================================================*/
 
-void read_cb_mem(socket_info_t * s, u_char fn, int space,
-		 u_int addr, u_int len, void *ptr)
+int read_cb_mem(socket_info_t * s, u_char fn, int space,
+		u_int addr, u_int len, void *ptr)
 {
 	struct pci_dev *dev;
 	struct resource *res;
@@ -194,7 +194,7 @@
 			goto fail;
 		for (; len; addr++, ptr++, len--)
 			pci_readb(dev, addr, (u_char *) ptr);
-		return;
+		return 0;
 	}
 
 	res = dev->resource + space - 1;
@@ -214,13 +214,197 @@
 		goto fail;
 
 	memcpy_fromio(ptr, s->cb_cis_virt + addr, len);
-	return;
+	return 0;
 
 fail:
 	memset(ptr, 0xff, len);
-	return;
+	return -1;
 }
 
+struct pci_dev *cb_scan_slot(struct pci_dev *temp, struct list_head *list)
+{
+	struct pci_bus *bus = temp->bus;
+	struct pci_dev *dev;
+	struct pci_dev *first_dev = NULL;
+	int func = 0;
+	int is_multi = 0;
+	u8 hdr_type;
+
+	for (func = 0; func < 8; func++, temp->devfn++) {
+		if (func && !is_multi)		/* not a multi-function device */
+			continue;
+		if (pci_read_config_byte(temp, PCI_HEADER_TYPE, &hdr_type))
+			continue;
+		temp->hdr_type = hdr_type & 0x7f;
+
+		dev = pci_scan_device(temp);
+		if (!dev)
+			continue;
+		sprintf(dev->name, "PCI device %04x:%04x", dev->vendor, dev->device);
+		if (!func) {
+			is_multi = hdr_type & 0x80;
+			first_dev = dev;
+		}
+
+		list_add_tail(&dev->global_list, list);
+		/* Fix up broken headers */
+//FIXME		pci_fixup_device(PCI_FIXUP_HEADER, dev);
+	}
+	return first_dev;
+}
+
+static unsigned int cb_scan_new_bus(struct pci_bus *bus, int irq);
+
+static int cb_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int irq)
+{
+	unsigned int buses;
+	unsigned short cr;
+	struct pci_bus *child;
+	int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS);
+
+	pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses);
+	printk("Scanning behind PCI bridge %s, config %06x\n", dev->slot_name, buses & 0xffffff);
+	/*
+	 * We need to assign a number to this bus which we always
+	 * do in the second pass. We also keep all address decoders
+	 * on the bridge disabled during scanning.  FIXME: Why?
+	 */
+	pci_read_config_word(dev, PCI_COMMAND, &cr);
+	pci_write_config_word(dev, PCI_COMMAND, 0x0000);
+	pci_write_config_word(dev, PCI_STATUS, 0xffff);
+
+	child = pci_add_new_bus(bus, dev, ++max);
+	buses = (buses & 0xff000000)
+	      | ((unsigned int)(child->primary)     <<  0)
+	      | ((unsigned int)(child->secondary)   <<  8)
+	      | ((unsigned int)(child->subordinate) << 16);
+	/*
+	 * We need to blast all three values with a single write.
+	 */
+	pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses);
+	if (!is_cardbus) {
+		/* Now we can scan all subordinate buses... */
+		max = cb_scan_new_bus(child, irq);
+	} else {
+		/*
+		 * For CardBus bridges, we leave 4 bus numbers
+		 * as cards with a PCI-to-PCI bridge can be
+		 * inserted later.
+		 */
+		max += 3;
+	}
+	/*
+	 * Set the subordinate bus number to its real value.
+	 */
+	child->subordinate = max;
+	pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, max);
+	pci_write_config_word(dev, PCI_COMMAND, cr);
+	sprintf(child->name, (is_cardbus ? "PCI CardBus #%02x" : "PCI Bus #%02x"), child->number);
+	return max;
+}
+
+static unsigned int cb_scan_new_bus(struct pci_bus *bus, int irq)
+{
+	unsigned int devfn, max;
+	struct list_head *ln, *ln_tmp;
+	struct pci_dev *dev, dev0;
+	struct list_head found;
+	
+	INIT_LIST_HEAD(&found);
+	
+	printk("Scanning bus %02x\n", bus->number);
+	max = bus->secondary;
+
+	/* Create a device template */
+	memset(&dev0, 0, sizeof(dev0));
+	dev0.bus = bus;
+	dev0.sysdata = bus->sysdata;
+
+	/* Go find them, Rover! */
+	for (devfn = 0; devfn < 0x100; devfn += 8) {
+		dev0.devfn = devfn;
+		cb_scan_slot(&dev0, &found);
+	}
+
+	/*
+	 * After performing arch-dependent fixup of the bus, look behind
+	 * all PCI-to-PCI bridges on this bus.
+	 */
+	printk("Fixups for bus %02x\n", bus->number);
+	pci_read_bridge_bases(bus);
+
+	list_for_each_safe(ln, ln_tmp, &found)
+	{
+		int i;
+		u8 irq_pin;
+		dev = pci_dev_g(ln);
+		pci_set_power_state(dev, 0);
+		for(i=0;i<6;i++)
+		{
+			struct resource *r = dev->resource + i;
+			if(!r->start && r->end)
+				pci_assign_resource(dev, i);
+		}
+		/* Does this function have an interrupt at all? */
+		pci_readb(dev, PCI_INTERRUPT_PIN, &irq_pin);
+		if (irq_pin) {
+			dev->irq = irq;
+			pci_writeb(dev, PCI_INTERRUPT_LINE, irq);
+		}
+
+		pci_enable_device(dev); /* XXX check return */
+		pci_insert_device(dev, bus);
+		if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
+			max = cb_scan_bridge(bus, dev, max, irq);
+	}
+
+	/*
+	 * We've scanned the bus and so we know all about what's on
+	 * the other side of any bridges that may be on this bus plus
+	 * any devices.
+	 *
+	 * Return how far we've got finding sub-buses.
+	 */
+	printk("Bus scan for %02x returning with max=%02x\n", bus->number, max);
+	return max;
+}
+
+static int program_bridge(struct pci_dev *bridge)
+{
+	u32 l;
+	
+	/* Set up the top and bottom of the PCI I/O segment for this bus. */
+	pci_read_config_dword(bridge, PCI_IO_BASE, &l);
+	l &= 0xffff0000;
+	l |= (bridge->resource[7].start >> 8) & 0x00f0;
+	l |= bridge->resource[7].end & 0xf000;
+	pci_write_config_dword(bridge, PCI_IO_BASE, l);
+
+	/* Clear upper 16 bits of I/O base/limit. */
+	pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0);
+
+	/* Clear out the upper 32 bits of PREF base/limit. */
+	pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, 0);
+	pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0);
+
+	/* Set up the top and bottom of the PCI Memory segment
+	   for this bus. */
+	l = (bridge->resource[8].start >> 16) & 0xfff0;
+	l |= bridge->resource[8].end & 0xfff00000;
+	pci_write_config_dword(bridge, PCI_MEMORY_BASE, l);
+
+	/* Set up PREF base/limit. */
+	l = (bridge->resource[9].start >> 16) & 0xfff0;
+	l |= bridge->resource[9].end & 0xfff00000;
+	pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l);
+
+	/* FIXME - 0x0c if our ISA VGA is behind it. It looks like X
+	   can handle this itself - CHECK */
+	l = 0x04;
+	pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, l);
+}
+
+
 /*=====================================================================
 
     cb_alloc() and cb_free() allocate and free the kernel data
@@ -280,14 +464,57 @@
 		dev->hdr_type = hdr & 0x7f;
 
 		pci_setup_device(dev);
-
-		/* FIXME: Do we need to enable the expansion ROM? */
-		for (r = 0; r < 7; r++) {
-			struct resource *res = dev->resource + r;
-			if (res->flags)
-				pci_assign_resource(dev, r);
+		
+		if(dev->hdr_type == 1)
+		{
+			int max = bus->secondary;
+			int idx;
+			struct resource *res, *pres;
+			printk(KERN_INFO "Cardbus: Bridge found - we suck.\n");
+			pci_read_bridge_bases(bus);
+			for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_BRIDGE_RESOURCES + 3; idx++) {
+				res = &dev->resource[idx];
+				/* This is ugly - pci_read_bridge_bases should have
+				   done it for us. Need to find out why it doesnt
+				   before fixing it */
+				if(idx == PCI_BRIDGE_RESOURCES) 
+					res->flags = IORESOURCE_IO | PCI_IO_RANGE_TYPE_32;
+				if(idx == PCI_BRIDGE_RESOURCES+1)
+					res->flags |= IORESOURCE_MEM;
+				if(idx == PCI_BRIDGE_RESOURCES+2)
+					res->flags |= IORESOURCE_MEM|IORESOURCE_PREFETCH;
+				/* Ignore any existing values in the chip */
+				res->start = 0;
+				/* Find the parent resource */
+				pres = pci_find_parent_resource(dev, res);
+				if(!pres)
+				{
+					printk(KERN_ERR "No parent resource for %lx\n", res->flags);
+					continue;
+				}
+				printk(KERN_ERR "Allocating for type %lx, in bus resource.\n", res->flags);
+				/* Hog the entire space */
+				res->start = pres->start;
+				if(idx != PCI_BRIDGE_RESOURCES)
+					res->end = pres->end;
+				else	/* Still working this out - FIXME */
+					res->end = res->start + 255;
+				if (!pres || request_resource(pres, res) < 0)
+					printk(KERN_ERR "PCI: Cannot allocate resource region %d of bridge %s\n", idx, dev->slot_name);
+			}
+			program_bridge(dev);
+			max = cb_scan_bridge(bus, dev, max, irq);
+			printk(KERN_INFO "Cardbus: Bridge scanned.\n");
+		}
+		else
+		{			
+			/* FIXME: Do we need to enable the expansion ROM? */
+			for (r = 0; r < 7; r++) {
+				struct resource *res = dev->resource + r;
+				if (res->flags)
+					pci_assign_resource(dev, r);
+			}
 		}
-
 		/* Does this function have an interrupt at all? */
 		pci_readb(dev, PCI_INTERRUPT_PIN, &irq_pin);
 		if (irq_pin) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/pcmcia/cistpl.c linux-2.4.21-pre6/drivers/pcmcia/cistpl.c
--- linux-2.4.20/drivers/pcmcia/cistpl.c	2001-12-21 17:41:55.000000000 +0000
+++ linux-2.4.21-pre6/drivers/pcmcia/cistpl.c	2003-03-26 23:49:25.000000000 +0000
@@ -2,7 +2,7 @@
 
     PCMCIA Card Information Structure parser
 
-    cistpl.c 1.97 2001/10/04 03:33:49
+    cistpl.c 1.99 2002/10/24 06:11:48
 
     The contents of this file are subject to the Mozilla Public
     License Version 1.1 (the "License"); you may not use this file
@@ -109,8 +109,8 @@
     }
 }
 
-void read_cis_mem(socket_info_t *s, int attr, u_int addr,
-		  u_int len, void *ptr)
+int read_cis_mem(socket_info_t *s, int attr, u_int addr,
+		 u_int len, void *ptr)
 {
     pccard_mem_map *mem = &s->cis_mem;
     u_char *sys, *buf = ptr;
@@ -118,7 +118,7 @@
     DEBUG(3, "cs: read_cis_mem(%d, %#x, %u)\n", attr, addr, len);
     if (setup_cis_mem(s) != 0) {
 	memset(ptr, 0xff, len);
-	return;
+	return -1;
     }
     mem->flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0);
 
@@ -156,6 +156,7 @@
     DEBUG(3, "cs:  %#2.2x %#2.2x %#2.2x %#2.2x ...\n",
 	  *(u_char *)(ptr+0), *(u_char *)(ptr+1),
 	  *(u_char *)(ptr+2), *(u_char *)(ptr+3));
+    return 0;
 }
 
 void write_cis_mem(socket_info_t *s, int attr, u_int addr,
@@ -270,7 +271,7 @@
 	if (find_mem_region(&s->cis_mem.sys_start, s->cap.map_size,
 			    s->cap.map_size, low, "card services", s)) {
 	    printk(KERN_NOTICE "cs: unable to map card memory!\n");
-	    return CS_OUT_OF_RESOURCE;
+	    return -1;
 	}
 	s->cis_mem.sys_stop = s->cis_mem.sys_start+s->cap.map_size-1;
 	s->cis_virt = bus_ioremap(s->cap.bus, s->cis_mem.sys_start,
@@ -303,7 +304,7 @@
 static void read_cis_cache(socket_info_t *s, int attr, u_int addr,
 			   u_int len, void *ptr)
 {
-    int i;
+    int i, ret;
     char *caddr;
 
     if (s->fake_cis) {
@@ -326,12 +327,12 @@
     }
 #ifdef CONFIG_CARDBUS
     if (s->state & SOCKET_CARDBUS)
-	read_cb_mem(s, 0, attr, addr, len, ptr);
+	ret = read_cb_mem(s, 0, attr, addr, len, ptr);
     else
 #endif
-	read_cis_mem(s, attr, addr, len, ptr);
+	ret = read_cis_mem(s, attr, addr, len, ptr);
     /* Copy data into the cache, if there is room */
-    if ((i < MAX_CIS_TABLE) &&
+    if ((ret == 0) && (i < MAX_CIS_TABLE) &&
 	(caddr+len < s->cis_cache+MAX_CIS_DATA)) {
 	s->cis_table[i].addr = addr;
 	s->cis_table[i].len = len;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/pcmcia/cs_internal.h linux-2.4.21-pre6/drivers/pcmcia/cs_internal.h
--- linux-2.4.20/drivers/pcmcia/cs_internal.h	2001-12-21 17:41:55.000000000 +0000
+++ linux-2.4.21-pre6/drivers/pcmcia/cs_internal.h	2003-03-26 23:48:57.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * cs_internal.h 1.54 2000/10/26 20:10:55
+ * cs_internal.h 1.57 2002/10/24 06:11:43
  *
  * The contents of this file are subject to the Mozilla Public License
  * Version 1.1 (the "License"); you may not use this file except in
@@ -202,13 +202,13 @@
 void cb_release(socket_info_t *s);
 void cb_enable(socket_info_t *s);
 void cb_disable(socket_info_t *s);
-void read_cb_mem(socket_info_t *s, u_char fn, int space,
-		 u_int addr, u_int len, void *ptr);
+int read_cb_mem(socket_info_t *s, u_char fn, int space,
+		u_int addr, u_int len, void *ptr);
 void cb_release_cis_mem(socket_info_t *s);
 
 /* In cistpl.c */
-void read_cis_mem(socket_info_t *s, int attr,
-		  u_int addr, u_int len, void *ptr);
+int read_cis_mem(socket_info_t *s, int attr,
+		 u_int addr, u_int len, void *ptr);
 void write_cis_mem(socket_info_t *s, int attr,
 		   u_int addr, u_int len, void *ptr);
 void release_cis_mem(socket_info_t *s);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/pcmcia/ricoh.h linux-2.4.21-pre6/drivers/pcmcia/ricoh.h
--- linux-2.4.20/drivers/pcmcia/ricoh.h	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/pcmcia/ricoh.h	2003-03-26 23:49:35.000000000 +0000
@@ -75,6 +75,12 @@
 #define RL5C46X_BCR_3E0_ENA		0x0800
 #define RL5C46X_BCR_3E2_ENA		0x1000
 
+/* Bridge Configuration Register */
+#define RL5C4XX_CONFIG			0x80	/* 16 bit */
+#define  RL5C4XX_CONFIG_IO_1_MODE	0x0200
+#define  RL5C4XX_CONFIG_IO_0_MODE	0x0100
+#define  RL5C4XX_CONFIG_PREFETCH	0x0001
+
 /* Misc Control Register */
 #define RL5C4XX_MISC			0x0082	/* 16 bit */
 #define  RL5C4XX_MISC_HW_SUSPEND_ENA	0x0002
@@ -119,6 +125,7 @@
 #define rl_ctl(socket)		((socket)->private[1])
 #define rl_io(socket)		((socket)->private[2])
 #define rl_mem(socket)		((socket)->private[3])
+#define rl_config(socket)	((socket)->private[4])
 
 /*
  * Magic Ricoh initialization code.. Save state at
@@ -130,9 +137,17 @@
 	rl_ctl(socket) = config_readw(socket, RL5C4XX_16BIT_CTL);
 	rl_io(socket) = config_readw(socket, RL5C4XX_16BIT_IO_0);
 	rl_mem(socket) = config_readw(socket, RL5C4XX_16BIT_MEM_0);
+	rl_config(socket) = config_readw(socket, RL5C4XX_CONFIG);
 
 	/* Set the default timings, don't trust the original values */
 	rl_ctl(socket) = RL5C4XX_16CTL_IO_TIMING | RL5C4XX_16CTL_MEM_TIMING;
+
+	if(socket->dev->device < PCI_DEVICE_ID_RICOH_RL5C475) {
+		rl_ctl(socket) |= RL5C46X_16CTL_LEVEL_1 | RL5C46X_16CTL_LEVEL_2;
+	} else {
+		rl_config(socket) |= RL5C4XX_CONFIG_PREFETCH;
+	}
+
 	return 0;
 }
 
@@ -174,6 +189,7 @@
 	config_writew(socket, RL5C4XX_16BIT_CTL, rl_ctl(socket));
 	config_writew(socket, RL5C4XX_16BIT_IO_0, rl_io(socket));
 	config_writew(socket, RL5C4XX_16BIT_MEM_0, rl_mem(socket));
+	config_writew(socket, RL5C4XX_CONFIG, rl_config(socket));
 
 	return 0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/pcmcia/sa1100_generic.c linux-2.4.21-pre6/drivers/pcmcia/sa1100_generic.c
--- linux-2.4.20/drivers/pcmcia/sa1100_generic.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/pcmcia/sa1100_generic.c	2003-03-26 23:49:40.000000000 +0000
@@ -47,7 +47,6 @@
 #include <linux/notifier.h>
 #include <linux/proc_fs.h>
 #include <linux/version.h>
-#include <linux/cpufreq.h>
 
 #include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/pcmcia/yenta.c linux-2.4.21-pre6/drivers/pcmcia/yenta.c
--- linux-2.4.20/drivers/pcmcia/yenta.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/pcmcia/yenta.c	2003-03-26 23:49:40.000000000 +0000
@@ -2,6 +2,11 @@
  * Regular lowlevel cardbus driver ("yenta")
  *
  * (C) Copyright 1999, 2000 Linus Torvalds
+ *
+ * Changelog:
+ * Aug 2002: Manfred Spraul <manfred@colorfullife.com>
+ * 	Dynamically adjust the size of the bridge resource
+ * 	
  */
 #include <linux/init.h>
 #include <linux/pci.h>
@@ -704,6 +709,15 @@
 	return 0;
 }
 
+/*
+ * Use an adaptive allocation for the memory resource,
+ * sometimes the size behind pci bridges is limited:
+ * 1/8 of the size of the io window of the parent.
+ * max 4 MB, min 16 kB.
+ */
+#define BRIDGE_SIZE_MAX	4*1024*1024
+#define BRIDGE_SIZE_MIN	16*1024
+
 static void yenta_allocate_res(pci_socket_t *socket, int nr, unsigned type)
 {
 	struct pci_bus *bus;
@@ -735,21 +749,42 @@
 	if (start && end > start) {
 		res->start = start;
 		res->end = end;
-		request_resource(root, res);
-		return;
+		if (request_resource(root, res) == 0)
+			return;
+		printk(KERN_INFO "yenta %s: Preassigned resource %d busy, reconfiguring...\n",
+				socket->dev->slot_name, nr);
+		res->start = res->end = 0;
 	}
 
-	align = size = 4*1024*1024;
-	min = PCIBIOS_MIN_MEM; max = ~0U;
 	if (type & IORESOURCE_IO) {
 		align = 1024;
 		size = 256;
 		min = 0x4000;
 		max = 0xffff;
+	} else {
+		unsigned long avail = root->end - root->start;
+		int i;
+		align = size = BRIDGE_SIZE_MAX;
+		if (size > avail/8) {
+			size=(avail+1)/8;
+			/* round size down to next power of 2 */
+			i = 0;
+			while ((size /= 2) != 0)
+				i++;
+			size = 1 << i;
+		}
+		if (size < BRIDGE_SIZE_MIN)
+			size = BRIDGE_SIZE_MIN;
+		align = size;
+		min = PCIBIOS_MIN_MEM; max = ~0U;
 	}
 		
-	if (allocate_resource(root, res, size, min, max, align, NULL, NULL) < 0)
+	if (allocate_resource(root, res, size, min, max, align, NULL, NULL) < 0) {
+		printk(KERN_INFO "yenta %s: no resource of type %x available, trying to continue...\n",
+				socket->dev->slot_name, type);
+		res->start = res->end = 0;
 		return;
+	}
 
 	config_writel(socket, offset, res->start);
 	config_writel(socket, offset+4, res->end);
@@ -767,6 +802,20 @@
 }
 
 /*
+ * Free the bridge mappings for the device..
+ */
+static void yenta_free_resources(pci_socket_t *socket)
+{
+	int i;
+	for (i=0;i<4;i++) {
+		struct resource *res;
+		res = socket->dev->resource + PCI_BRIDGE_RESOURCES + i;
+		if (res->start != 0 && res->end != 0)
+			release_resource(res);
+		res->start = res->end = 0;
+	}
+}
+/*
  * Close it down - release our resources and go home..
  */
 static void yenta_close(pci_socket_t *sock)
@@ -782,6 +831,7 @@
 
 	if (sock->base)
 		iounmap(sock->base);
+	yenta_free_resources(sock);
 }
 
 #include "ti113x.h"
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/s390/Makefile linux-2.4.21-pre6/drivers/s390/Makefile
--- linux-2.4.20/drivers/s390/Makefile	2002-02-25 19:38:03.000000000 +0000
+++ linux-2.4.21-pre6/drivers/s390/Makefile	2003-03-26 23:49:39.000000000 +0000
@@ -7,8 +7,8 @@
 subdir-y := block char misc net
 subdir-m := $(subdir-y)
 
-obj-y := s390io.o s390mach.o s390dyn.o idals.o ccwcache.o sysinfo.o
-export-objs += ccwcache.o idals.o s390dyn.o s390io.o
+obj-y := s390io.o s390mach.o s390dyn.o ccwcache.o sysinfo.o
+export-objs += ccwcache.o s390dyn.o s390io.o
 
 obj-y += $(foreach dir,$(subdir-y),$(dir)/s390-$(dir).o)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/s390/block/dasd.c linux-2.4.21-pre6/drivers/s390/block/dasd.c
--- linux-2.4.20/drivers/s390/block/dasd.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/s390/block/dasd.c	2003-03-26 23:49:35.000000000 +0000
@@ -1315,9 +1315,9 @@
 /*
  * DASD_TERM_IO
  *
- * attempts to terminate the the current IO and set it to failed if termination
+ * Attempts to terminate the current IO and set it to failed if termination
  * was successful.
- * returns an appropriate return code
+ * Returns an appropriate return code.
  */
 int
 dasd_term_IO (ccw_req_t * cqr)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/s390/block/dasd_3990_erp.c linux-2.4.21-pre6/drivers/s390/block/dasd_3990_erp.c
--- linux-2.4.20/drivers/s390/block/dasd_3990_erp.c	2002-02-25 19:38:03.000000000 +0000
+++ linux-2.4.21-pre6/drivers/s390/block/dasd_3990_erp.c	2003-03-26 23:49:53.000000000 +0000
@@ -2712,10 +2712,10 @@
  * DASD_3990_ERP_ERROR_MATCH
  *
  * DESCRIPTION
- *   check if the the device status of the given cqr is the same.
+ *   Check if the device status of the given cqr is the same.
  *   This means that the failed CCW and the relevant sense data
  *   must match.
- *   I don't distinguish between 24 and 32 byte sense becaus in case of
+ *   I don't distinguish between 24 and 32 byte sense because in case of
  *   24 byte sense byte 25 and 27 is set as well.
  *
  * PARAMETER
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/s390/block/xpram.c linux-2.4.21-pre6/drivers/s390/block/xpram.c
--- linux-2.4.20/drivers/s390/block/xpram.c	2001-10-25 20:58:35.000000000 +0000
+++ linux-2.4.21-pre6/drivers/s390/block/xpram.c	2003-03-26 23:49:50.000000000 +0000
@@ -171,7 +171,7 @@
 int xpram_devs, xpram_rahead;
 int xpram_blksize, xpram_hardsect;
 int xpram_mem_avail = 0;
-unsigned long xpram_sizes[XPRAM_MAX_DEVS];
+unsigned int xpram_sizes[XPRAM_MAX_DEVS];
 
 
 MODULE_PARM(devs,"i");
@@ -184,7 +184,9 @@
 		 "All devices with size 0 equally partition the "
 		 "remaining space on the expanded strorage not "
 		 "claimed by explicit sizes\n");
-
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,12))
+MODULE_LICENSE ("GPL");
+#endif
 
 
 /* The following items are obtained through kmalloc() in init_module() */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/s390/char/tuball.c linux-2.4.21-pre6/drivers/s390/char/tuball.c
--- linux-2.4.20/drivers/s390/char/tuball.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/s390/char/tuball.c	2003-03-26 23:49:20.000000000 +0000
@@ -29,6 +29,9 @@
 MODULE_PARM(tubdebug, "i");
 MODULE_PARM(tubscrolltime, "i");
 MODULE_PARM(tubxcorrect, "i");
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,12))
+MODULE_LICENSE ("GPL");
+#endif
 #endif
 /*
  * Values for tubdebug and their effects:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/s390/char/tubfs.c linux-2.4.21-pre6/drivers/s390/char/tubfs.c
--- linux-2.4.20/drivers/s390/char/tubfs.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/s390/char/tubfs.c	2003-03-26 23:49:40.000000000 +0000
@@ -241,19 +241,13 @@
 {
 	long flags;
 	tub_t *tubp;
-	addr_t *ip;
 
 	tubp = data;
 	TUBLOCK(tubp->irq, flags);
 	tubp->flags &= ~TUB_BHPENDING;
 
 	if (tubp->wbuf) {       /* if we were writing */
-		for (ip = tubp->wbuf; ip < tubp->wbuf+33; ip++) {
-			if (*ip == 0)
-				break;
-			kfree(phys_to_virt(*ip));
-		}
-		kfree(tubp->wbuf);
+		idal_buffer_free(tubp->wbuf);
 		tubp->wbuf = NULL;
 	}
 
@@ -373,14 +367,10 @@
 fs3270_read(struct file *fp, char *dp, size_t len, loff_t *off)
 {
 	tub_t *tubp;
-	char *kp;
 	ccw1_t *cp;
 	int rc;
 	long flags;
-	addr_t *idalp, *ip;
-	char *tp;
-	int count, piece;
-	int size;
+	struct idal_buffer *idal_buffer;
 
 	if (len == 0 || len > 65535) {
 		return -EINVAL;
@@ -389,19 +379,9 @@
 	if ((tubp = INODE2TUB((struct inode *)fp->private_data)) == NULL)
 		return -ENODEV;
 
-	if ((ip = idalp = idal_alloc(33)) == NULL)
-		return -EFAULT;
-	memset(idalp, 0, 33 * sizeof *idalp);
-	count = len;
-	while (count) {
-		piece = MIN(count, 0x800);
-		size = count == len? piece: 0x800;
-		if ((kp = kmalloc(size, GFP_KERNEL|GFP_DMA)) == NULL) {
-			len = -ENOMEM;
-			goto do_cleanup;
-		}
-		*ip++ = virt_to_phys(kp);
-		count -= piece;
+	if((idal_buffer = idal_buffer_alloc(len, 0)) == NULL) {
+		len = -ENOMEM;
+		goto do_cleanup;
 	}
 
 	if ((rc = fs3270_wait(tubp, &flags)) != 0) {
@@ -412,9 +392,8 @@
 	cp = &tubp->rccw;
 	if (tubp->icmd == 0 && tubp->ocmd != 0)  tubp->icmd = 6;
 	cp->cmd_code = tubp->icmd?:2;
-	cp->flags = CCW_FLAG_SLI | CCW_FLAG_IDA;
-	cp->count = len;
-	cp->cda = virt_to_phys(idalp);
+	idal_buffer_set_cda(idal_buffer, cp);
+	cp->flags |= CCW_FLAG_SLI;
 	tubp->flags |= TUB_RDPENDING;
 	TUBUNLOCK(tubp->irq, flags);
 
@@ -427,27 +406,14 @@
 	TUBUNLOCK(tubp->irq, flags);
 
 	len -= tubp->cswl;
-	count = len;
-	tp = dp;
-	ip = idalp;
-	while (count) {
-		piece = MIN(count, 0x800);
-		if (copy_to_user(tp, phys_to_virt(*ip), piece) != 0) {
-			len = -EFAULT;
-			goto do_cleanup;
-		}
-		count -= piece;
-		tp += piece;
-		ip++;
+	if (idal_buffer_to_user(idal_buffer, dp, len) != 0) {
+		len = -EFAULT;
+		goto do_cleanup;
 	}
 
 do_cleanup:
-	for (ip = idalp; ip < idalp+33; ip++) {
-		if (*ip == 0)
-			break;
-		kfree(phys_to_virt(*ip));
-	}
-	idal_free(idalp);
+	idal_buffer_free(idal_buffer);
+
 	return len;
 }
 
@@ -461,11 +427,7 @@
 	ccw1_t *cp;
 	int rc;
 	long flags;
-	void *kb;
-	addr_t *idalp, *ip;
-	int count, piece;
-	int index;
-	int size;
+	struct idal_buffer *idal_buffer;
 
 	if (len > 65535 || len == 0)
 		return -EINVAL;
@@ -474,26 +436,12 @@
 	if ((tubp = INODE2TUB((struct inode *)fp->private_data)) == NULL)
 		return -ENODEV;
 
-	if ((ip = idalp = idal_alloc(33)) == NULL)
-		return -EFAULT;
-	memset(idalp, 0, 33 * sizeof *idalp);
-
-	count = len;
-	index = 0;
-	while (count) {
-		piece = MIN(count, 0x800);
-		size = count == len? piece: 0x800;
-		if ((kb = kmalloc(size, GFP_KERNEL|GFP_DMA)) == NULL) {
-			len = -ENOMEM;
-			goto do_cleanup;
-		}
-		*ip++ = virt_to_phys(kb);
-		if (copy_from_user(kb, &dp[index], piece) != 0) {
-			len = -EFAULT;
-			goto do_cleanup;
-		}
-		count -= piece;
-		index += piece;
+	if ((idal_buffer = idal_buffer_alloc(len, 0)) == NULL)
+		return -ENOMEM;
+
+	if (idal_buffer_from_user(idal_buffer, dp, len) != 0) {
+		len = -EFAULT;
+		goto do_cleanup;
 	}
 
 	/* Wait till tube's not working or signal is pending */
@@ -504,22 +452,18 @@
 	}
 
 	/* Make CCW and start I/O.  Back end will free buffers & idal. */
-	tubp->wbuf = idalp;
 	cp = &tubp->wccw;
 	cp->cmd_code = tubp->ocmd? tubp->ocmd == 5? 13: tubp->ocmd: 1;
-	cp->flags = CCW_FLAG_SLI | CCW_FLAG_IDA;
-	cp->count = len;
-	cp->cda = virt_to_phys(tubp->wbuf);
+	tubp->wbuf = idal_buffer;
+	idal_buffer_set_cda(idal_buffer, cp);
+	cp->flags |= CCW_FLAG_SLI;
 	fs3270_io(tubp, cp);
 	TUBUNLOCK(tubp->irq, flags);
+
 	return len;
 
 do_cleanup:
-	for (ip = idalp; ip < idalp+33; ip++) {
-		if (*ip == 0)
-			break;
-		kfree(phys_to_virt(*ip));
-	}
-	idal_free(idalp);
+	idal_buffer_free(idal_buffer);
+
 	return len;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/s390/char/tubio.h linux-2.4.21-pre6/drivers/s390/char/tubio.h
--- linux-2.4.20/drivers/s390/char/tubio.h	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/s390/char/tubio.h	2003-03-26 23:48:57.000000000 +0000
@@ -227,7 +227,7 @@
 	devstat_t       devstat;
 	ccw1_t          rccw;
 	ccw1_t          wccw;
-	addr_t		*wbuf;
+	struct idal_buffer *wbuf;
 	int             cswl;
 	void            (*intv)(struct tub_s *, devstat_t *);
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/s390/idals.c linux-2.4.21-pre6/drivers/s390/idals.c
--- linux-2.4.20/drivers/s390/idals.c	2001-07-25 21:12:02.000000000 +0000
+++ linux-2.4.21-pre6/drivers/s390/idals.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,43 +0,0 @@
-/* 
-   * File...........: linux/drivers/s390x/idals.c
-   * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
-   * Bugreports.to..: <Linux390@de.ibm.com>
-   * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000a
-   
-   * History of changes
-   * 07/24/00 new file
-   * 12/13/00 changed IDALs to 4kByte-IDALs
- */
-
-#include <linux/module.h>
-#include <linux/config.h>
-#include <linux/slab.h>
-
-#include <asm/irq.h>
-#include <asm/idals.h>
-
-#ifdef CONFIG_ARCH_S390X
-
-unsigned long __create_idal (unsigned long address, int count)
-{
-	int nridaws;
-	unsigned long *idal, *tmp;
-
-        nridaws = ((address & (IDA_BLOCK_SIZE-1)) + count + 
-		   (IDA_BLOCK_SIZE-1)) >> IDA_SIZE_LOG;
-	idal = idal_alloc(nridaws);
-	if (idal != NULL) {
-		tmp = idal;
-		*tmp++ = address;
-		address &= -IDA_BLOCK_SIZE;
-		while (--nridaws > 0) {
-			address += IDA_BLOCK_SIZE;
-			*tmp++ = address;
-		}
-	}
-	return (unsigned long) idal;
-}
-
-EXPORT_SYMBOL (__create_idal);
-
-#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/s390/misc/chandev.c linux-2.4.21-pre6/drivers/s390/misc/chandev.c
--- linux-2.4.20/drivers/s390/misc/chandev.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/s390/misc/chandev.c	2003-03-26 23:49:30.000000000 +0000
@@ -2800,6 +2800,7 @@
 	struct stat statbuf;
 	char        *buff;
 	int         curr,left,len,fd;
+	mm_segment_t oldfs;
 
 	/* if called from chandev_register_and_probe & 
 	   the driver is compiled into the kernel the
@@ -2810,6 +2811,7 @@
 	if(in_interrupt()||current->fs->root==NULL)
 		return;
 	atomic_set(&chandev_conf_read,TRUE);
+	oldfs = get_fs();
 	set_fs(KERNEL_DS);
 	if(stat(CHANDEV_FILE,&statbuf)==0)
 	{
@@ -2834,7 +2836,7 @@
 			vfree(buff);
 		}
 	}
-	set_fs(USER_DS);
+	set_fs(oldfs);
 }
 
 static void chandev_read_conf_if_necessary(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/s390/net/iucv.c linux-2.4.21-pre6/drivers/s390/net/iucv.c
--- linux-2.4.20/drivers/s390/net/iucv.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/s390/net/iucv.c	2003-03-26 23:49:05.000000000 +0000
@@ -418,7 +418,7 @@
 /**
  * grab_param: - Get a parameter buffer from the pre-allocated pool.
  *
- * This function searches for an unused element in the the pre-allocated pool
+ * This function searches for an unused element in the pre-allocated pool
  * of parameter buffers. If one is found, it marks it "in use" and returns
  * a pointer to it. The calling function is responsible for releasing it
  * when it has finished its usage.
@@ -1525,7 +1525,7 @@
  *        buflen - length of reply buffer
  * Output: ipbfadr2 - Address of buffer updated by the number
  *                    of bytes you have moved.
- *         ipbfln2f - Contains on the the following values
+ *         ipbfln2f - Contains one of the following values:
  *              If the answer buffer is the same length as the reply, this field
  *               contains zero.
  *              If the answer buffer is longer than the reply, this field contains
@@ -1590,7 +1590,7 @@
  *        buffer - address of array of reply buffers
  *        buflen - total length of reply buffers
  * Output: ipbfadr2 - Address of buffer which IUCV is currently working on.
- *         ipbfln2f - Contains on the the following values
+ *         ipbfln2f - Contains one of the following values:
  *              If the answer buffer is the same length as the reply, this field
  *               contains zero.
  *              If the answer buffer is longer than the reply, this field contains
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/s390/s390io.c linux-2.4.21-pre6/drivers/s390/s390io.c
--- linux-2.4.20/drivers/s390/s390io.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/s390/s390io.c	2003-03-26 23:49:18.000000000 +0000
@@ -8607,7 +8607,7 @@
 cio_ignore_proc_write (struct file *file, const char *user_buf,
 		       size_t user_len, loff_t * offset)
 {
-	char *buffer
+	char *buffer;
 	
 	if(user_len > 65536)
 		user_len = 65536;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/sbus/char/display7seg.c linux-2.4.21-pre6/drivers/sbus/char/display7seg.c
--- linux-2.4.20/drivers/sbus/char/display7seg.c	2001-10-11 06:42:47.000000000 +0000
+++ linux-2.4.21-pre6/drivers/sbus/char/display7seg.c	2003-03-26 23:49:50.000000000 +0000
@@ -198,6 +198,7 @@
 	if (0 != iTmp) {
 		printk("%s: unable to acquire miscdevice minor %i\n",
 		       D7S_DEVNAME, D7S_MINOR);
+		iounmap(d7s_regs);
 		return iTmp;
 	}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/3w-xxxx.c linux-2.4.21-pre6/drivers/scsi/3w-xxxx.c
--- linux-2.4.20/drivers/scsi/3w-xxxx.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/3w-xxxx.c	2003-03-26 23:49:30.000000000 +0000
@@ -6,7 +6,7 @@
    		     Arnaldo Carvalho de Melo <acme@conectiva.com.br>
                      Brad Strand <linux@3ware.com>
 
-   Copyright (C) 1999-2002 3ware Inc.
+   Copyright (C) 1999-2003 3ware Inc.
 
    Kernel compatablity By: 	Andre Hedrick <andre@suse.com>
    Non-Copyright (C) 2000	Andre Hedrick <andre@suse.com>
@@ -160,6 +160,11 @@
                  Add support for mode sense opcode.
                  Add support for cache mode page.
                  Add support for synchronize cache opcode.
+   1.02.00.032 - Fix small multicard rollcall bug.
+                 Make driver stay loaded with no units for hot add/swap.
+                 Add support for "twe" character device for ioctls.
+                 Clean up request_id queueing code.
+                 Fix tw_scsi_queue() spinlocks.
 */
 
 #include <linux/module.h>
@@ -202,6 +207,9 @@
 MODULE_LICENSE("GPL");
 #endif
 
+static int tw_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+static int tw_chrdev_open(struct inode *inode, struct file *file);
+static int tw_chrdev_release(struct inode *inode, struct file *file);
 static int tw_copy_info(TW_Info *info, char *fmt, ...);
 static void tw_copy_mem_info(TW_Info *info, char *data, int len);
 static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
@@ -215,10 +223,19 @@
 	tw_halt, NULL, 0
 };
 
+/* File operations struct for character device */
+static struct file_operations tw_fops = {
+	owner: THIS_MODULE,
+	ioctl: tw_chrdev_ioctl,
+	open: tw_chrdev_open,
+	release: tw_chrdev_release
+};
+
 /* Globals */
-char *tw_driver_version="1.02.00.031";
+char *tw_driver_version="1.02.00.032";
 TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];
 int tw_device_extension_count = 0;
+static int twe_major = -1;
 
 /* Functions */
 
@@ -608,6 +625,209 @@
 	return 0;
 } /* End tw_check_errors() */
 
+/* This function handles ioctl for the character device */
+static int tw_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	int error, request_id;
+	dma_addr_t dma_handle;
+	unsigned short tw_aen_code;
+	struct timeval before, timeout;
+	unsigned long flags = 0x0;
+	unsigned int data_buffer_length = 0;
+	unsigned long data_buffer_length_adjusted = 0;
+	unsigned long *cpu_addr;
+	TW_New_Ioctl *tw_ioctl;
+	TW_Passthru *passthru;
+	TW_Device_Extension *tw_dev = tw_device_extension_list[MINOR(inode->i_rdev)];
+
+	dprintk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl()\n");
+
+	/* Only let one of these through at a time */
+	if (test_and_set_bit(TW_IN_CHRDEV_IOCTL, &tw_dev->flags)) {
+		return -EBUSY;
+	}
+
+	/* First copy down the buffer length */
+	error = copy_from_user(&data_buffer_length, (void *)arg, sizeof(unsigned int));
+	if (error) {
+		printk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): Error copying buffer length from userspace.\n");
+		clear_bit(TW_IN_CHRDEV_IOCTL, &tw_dev->flags);
+		return -EFAULT;
+	}
+
+	/* Check size */
+	if (data_buffer_length > TW_MAX_SECTORS * 512) {
+		printk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): Invalid buffer size (%d).\n", data_buffer_length);
+		clear_bit(TW_IN_CHRDEV_IOCTL, &tw_dev->flags);
+		return -EFAULT;
+	}
+
+	/* Hardware can only do multiple of 512 byte transfers */
+	if (data_buffer_length % 512)
+		data_buffer_length_adjusted = data_buffer_length + 512 - (data_buffer_length % 512);
+	else
+		data_buffer_length_adjusted = data_buffer_length;
+
+	/* Now allocate ioctl buf memory */
+	cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_New_Ioctl) - 1, &dma_handle);
+	if (cpu_addr == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): Error allocating memory.\n");
+		clear_bit(TW_IN_CHRDEV_IOCTL, &tw_dev->flags);
+		return -ENOMEM;
+	}
+
+	tw_ioctl = (TW_New_Ioctl *)cpu_addr;
+
+	/* Now copy down the entire ioctl */
+	error = copy_from_user(tw_ioctl, (void *)arg, data_buffer_length + sizeof(TW_New_Ioctl) - 1);
+	if (error) {
+		printk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): Error copying data from userspace.\n");
+		pci_free_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_New_Ioctl) - 1, cpu_addr, dma_handle);
+		clear_bit(TW_IN_CHRDEV_IOCTL, &tw_dev->flags);
+		return -EFAULT;
+	}
+
+	passthru = (TW_Passthru *)&tw_ioctl->firmware_command;
+
+	/* See which ioctl we are doing */
+	switch (cmd) {
+		case TW_OP_NOP:
+			dprintk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): caught TW_OP_NOP.\n");
+			break;
+		case TW_OP_AEN_LISTEN:
+			dprintk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): caught TW_AEN_LISTEN.\n");
+			memset(tw_ioctl->data_buffer, 0, tw_ioctl->data_buffer_length);
+			if (tw_dev->aen_head == tw_dev->aen_tail) {
+				tw_aen_code = TW_AEN_QUEUE_EMPTY;
+			} else {
+				tw_aen_code = tw_dev->aen_queue[tw_dev->aen_head];
+				if (tw_dev->aen_head == TW_Q_LENGTH - 1) {
+					tw_dev->aen_head = TW_Q_START;
+				} else {
+					tw_dev->aen_head = tw_dev->aen_head + 1;
+				}
+			}
+			memcpy(tw_ioctl->data_buffer, &tw_aen_code, sizeof(tw_aen_code));
+			break;
+		case TW_CMD_PACKET_WITH_DATA:
+			dprintk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): caught TW_CMD_PACKET_WITH_DATA.\n");
+			spin_lock_irqsave(&tw_dev->tw_lock, flags);
+
+			tw_state_request_start(tw_dev, &request_id);
+
+			/* Flag internal command */
+			tw_dev->srb[request_id] = 0;
+
+			/* Flag chrdev ioctl */
+			tw_dev->chrdev_request_id = request_id;
+
+			tw_ioctl->firmware_command.request_id = request_id;
+
+			/* Load the sg list */
+			switch (tw_ioctl->firmware_command.byte0.sgl_offset) {
+			case 2:
+				tw_ioctl->firmware_command.byte8.param.sgl[0].address = dma_handle + sizeof(TW_New_Ioctl) - 1;
+				tw_ioctl->firmware_command.byte8.param.sgl[0].length = data_buffer_length_adjusted;
+				break;
+			case 3:
+				tw_ioctl->firmware_command.byte8.io.sgl[0].address = dma_handle + sizeof(TW_New_Ioctl) - 1;
+				tw_ioctl->firmware_command.byte8.io.sgl[0].length = data_buffer_length_adjusted;
+				break;
+			case 5:
+				passthru->sg_list[0].address = dma_handle + sizeof(TW_New_Ioctl) - 1;
+				passthru->sg_list[0].length = data_buffer_length_adjusted;
+				break;
+			}
+
+			memcpy(tw_dev->command_packet_virtual_address[request_id], &(tw_ioctl->firmware_command), sizeof(TW_Command));
+
+			/* Now post the command packet to the controller */
+			tw_post_command_packet(tw_dev, request_id);
+			spin_unlock_irqrestore(&tw_dev->tw_lock, flags);
+
+			/* Now wait for the command to complete */
+			do_gettimeofday(&before);
+
+	tw_ioctl_chrdev_retry:
+
+			if (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE) {
+				interruptible_sleep_on_timeout(&tw_dev->ioctl_wqueue, 1);
+				do_gettimeofday(&timeout);
+				if (before.tv_sec + TW_IOCTL_CHRDEV_TIMEOUT < timeout.tv_sec) {
+					/* Now we need to reset the board */
+					printk(KERN_WARNING "3w-xxxx: scsi%d: Character ioctl (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, cmd);
+					spin_lock_irqsave(&tw_dev->tw_lock, flags);
+					tw_dev->state[request_id] = TW_S_COMPLETED;
+					tw_state_request_finish(tw_dev, request_id);
+					pci_free_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_New_Ioctl) - 1, cpu_addr, dma_handle);
+					tw_dev->posted_request_count--;
+					if (tw_reset_device_extension(tw_dev)) {
+						printk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): Reset failed for card %d.\n", tw_dev->host->host_no);
+					}
+					spin_unlock_irqrestore(&tw_dev->tw_lock, flags);
+					clear_bit(TW_IN_CHRDEV_IOCTL, &tw_dev->flags);
+					if (signal_pending(current))
+						return -EINTR;
+					else
+						return -EIO;
+				} else {
+					goto tw_ioctl_chrdev_retry;
+				}
+			}
+
+			/* Now copy in the command packet response */
+			memcpy(&(tw_ioctl->firmware_command), tw_dev->command_packet_virtual_address[request_id], sizeof(TW_Command));
+
+			/* Now complete the io */
+			spin_lock_irqsave(&tw_dev->tw_lock, flags);
+			tw_dev->posted_request_count--;
+			tw_dev->state[request_id] = TW_S_COMPLETED;
+			tw_state_request_finish(tw_dev, request_id);
+			spin_unlock_irqrestore(&tw_dev->tw_lock, flags);
+			break;
+		default:
+			printk(KERN_WARNING "3w-xxxx: Unknown chrdev ioctl 0x%x.\n", cmd);
+	}
+
+	/* Now copy the entire response to userspace */
+	error = copy_to_user((void *)arg, tw_ioctl, sizeof(TW_New_Ioctl) + tw_ioctl->data_buffer_length - 1);
+	if (error) {
+		printk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): Error copying data to userspace.\n");
+		pci_free_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_New_Ioctl) - 1, cpu_addr, dma_handle);
+		clear_bit(TW_IN_CHRDEV_IOCTL, &tw_dev->flags);
+		return -EFAULT;
+	}
+
+	/* Now free ioctl buf memory */
+	pci_free_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_New_Ioctl) - 1, cpu_addr, dma_handle);
+
+	clear_bit(TW_IN_CHRDEV_IOCTL, &tw_dev->flags);
+
+	return 0;
+} /* End tw_chrdev_ioctl() */
+
+/* This function handles open for the character device */
+static int tw_chrdev_open(struct inode *inode, struct file *file)
+{
+	unsigned int minor_number;
+
+	dprintk(KERN_WARNING "3w-xxxx: tw_ioctl_open()\n");
+
+	minor_number = MINOR(inode->i_rdev);
+	if (minor_number >= tw_device_extension_count)
+		return -ENODEV;
+
+	return 0;
+} /* End tw_chrdev_open() */
+
+/* This function handles close for the character device */
+static int tw_chrdev_release(struct inode *inode, struct file *file)
+{
+	dprintk(KERN_WARNING "3w-xxxx: tw_ioctl_release()\n");
+
+	return 0;
+} /* End tw_chrdev_release() */
+
 /* This function will clear all interrupts on the controller */
 void tw_clear_all_interrupts(TW_Device_Extension *tw_dev)
 {
@@ -878,7 +1098,9 @@
 
 			/* Disable interrupts on the card */
 			tw_disable_interrupts(tw_dev);
-			
+
+			tries = 0;
+
 			while (tries < TW_MAX_RESET_TRIES) {
 				/* Do soft reset */
 				tw_soft_reset(tw_dev);
@@ -924,10 +1146,6 @@
 			error = tw_initialize_units(tw_dev);
 			if (error) {
 				printk(KERN_WARNING "3w-xxxx: No valid units for card %d.\n", j);
-				release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
-				tw_free_device_extension(tw_dev);
-				kfree(tw_dev);
-				continue;
 			}
 
 			error = tw_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS);
@@ -945,14 +1163,15 @@
 			/* Calculate max cmds per lun, and setup queues */
 			if (tw_dev->num_units > 0) {
 				if ((tw_dev->num_raid_five > 0) && (tw_dev->tw_pci_dev->device == TW_DEVICE_ID)) {
-					tw_host->cmd_per_lun = (TW_MAX_BOUNCEBUF-1)/tw_dev->num_units;
+					tw_host->cmd_per_lun = (TW_MAX_BOUNCEBUF-2)/tw_dev->num_units;
 					tw_dev->free_head = TW_Q_START;
-					tw_dev->free_tail = TW_MAX_BOUNCEBUF - 1;
+					tw_dev->free_tail = TW_Q_START;
 					tw_dev->free_wrap = TW_MAX_BOUNCEBUF - 1;
 				} else {
 					/* Use SHT cmd_per_lun here */
+					tw_host->cmd_per_lun = TW_MAX_CMDS_PER_LUN;
 					tw_dev->free_head = TW_Q_START;
-					tw_dev->free_tail = TW_Q_LENGTH - 1;
+					tw_dev->free_tail = TW_Q_START;
 					tw_dev->free_wrap = TW_Q_LENGTH - 1;
 				}
 			}
@@ -1013,13 +1232,7 @@
 			/* Tell the firmware we support shutdown notification*/
 			error = tw_setfeature(tw_dev2, 2, 1, &c);
 			if (error) {
-				printk(KERN_WARNING "3w-xxxx: tw_setfeature(): Error setting features for card %d.\n", j);
-				scsi_unregister(host);
-				release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
-				tw_free_device_extension(tw_dev);
-				kfree(tw_dev);
-				numcards--;
-				continue;
+				printk(KERN_WARNING "3w-xxxx: Unable to set features for card %d, old firmware or card.\n", j);
 			}
 
 			/* Now setup the interrupt handler */
@@ -1044,10 +1257,14 @@
 		}
 	}
 
-	if (numcards == 0) 
-		printk(KERN_WARNING "3w-xxxx: No cards with valid units found.\n");
-	else
-	  register_reboot_notifier(&tw_notifier);
+	if (numcards == 0) {
+		printk(KERN_WARNING "3w-xxxx: No cards found.\n");
+	} else {
+		register_reboot_notifier(&tw_notifier);
+		if ((twe_major = register_chrdev (0, "twe", &tw_fops)) < 0) {
+			printk(KERN_WARNING "3w-xxxx: Unable to register \"twe\" character device, error = %d.\n", twe_major);
+		}
+	}
 
 	return numcards;
 } /* End tw_findcards() */
@@ -1179,6 +1396,8 @@
 	tw_dev->pending_head = TW_Q_START;
 	tw_dev->pending_tail = TW_Q_START;
 	spin_lock_init(&tw_dev->tw_lock);
+	tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
+	init_waitqueue_head(&tw_dev->ioctl_wqueue);
 
 	return 0;
 } /* End tw_initialize_device_extension() */
@@ -1510,9 +1729,14 @@
 				/* Check for internal command completion */
 				if (tw_dev->srb[request_id] == 0) {
 					dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Found internally posted command.\n");
-					retval = tw_aen_complete(tw_dev, request_id);
-					if (retval) {
-						printk(KERN_WARNING "3w-xxxx: scsi%d: Error completing aen.\n", tw_dev->host->host_no);
+					/* Check for chrdev ioctl completion */
+					if (request_id != tw_dev->chrdev_request_id) {
+						retval = tw_aen_complete(tw_dev, request_id);
+						if (retval) {
+							printk(KERN_WARNING "3w-xxxx: scsi%d: Error completing aen.\n", tw_dev->host->host_no);
+						}
+					} else {
+						tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
 					}
 				} else {
 				switch (tw_dev->srb[request_id]->cmnd[0]) {
@@ -1524,6 +1748,10 @@
 					case WRITE_6:
 						dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught WRITE_10/WRITE_6\n");
 						break;
+					case TEST_UNIT_READY:
+						dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught TEST_UNIT_READY\n");
+						error = tw_scsiop_test_unit_ready_complete(tw_dev, request_id);
+						break;
 					case INQUIRY:
 						dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught INQUIRY\n");
 						error = tw_scsiop_inquiry_complete(tw_dev, request_id);
@@ -2187,12 +2415,13 @@
 		tw_dev->state[i] = TW_S_INITIAL;
 	}
 	tw_dev->free_head = TW_Q_START;
-	tw_dev->free_tail = TW_Q_LENGTH - 1;
+	tw_dev->free_tail = TW_Q_START;
 	tw_dev->posted_request_count = 0;
 	tw_dev->pending_request_count = 0;
 	tw_dev->pending_head = TW_Q_START;
 	tw_dev->pending_tail = TW_Q_START;
 	tw_dev->reset_print = 0;
+	tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
 
 	return 0;
 } /* End tw_reset_device_extension() */
@@ -2475,7 +2704,6 @@
 	unsigned char *command = SCpnt->cmnd;
 	int request_id = 0;
 	int error = 0;
-	unsigned long flags = 0;
 	TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->host->hostdata;
 
 	if (tw_dev == NULL) {
@@ -2485,14 +2713,14 @@
 		return 0;
 	}
 
-	spin_lock_irqsave(&tw_dev->tw_lock, flags);
+	spin_lock(&tw_dev->tw_lock);
 	dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue()\n");
 
 	/* Skip scsi command if it isn't for us */
-	if ((tw_dev->is_unit_present[SCpnt->target] == FALSE) || (SCpnt->lun != 0)) {
+	if ((SCpnt->channel != 0) || (SCpnt->lun != 0)) {
 		SCpnt->result = (DID_BAD_TARGET << 16);
 		done(SCpnt);
-		spin_unlock_irqrestore(&tw_dev->tw_lock, flags);
+		spin_unlock(&tw_dev->tw_lock);
 		return 0;
 	}
 	
@@ -2505,6 +2733,9 @@
 	/* Save the scsi command for use by the ISR */
 	tw_dev->srb[request_id] = SCpnt;
 
+	/* Initialize phase to zero */
+	SCpnt->SCp.phase = 0;
+
 	switch (*command) {
 		case READ_10:
 		case READ_6:
@@ -2554,7 +2785,7 @@
 		SCpnt->result = (DID_ERROR << 16);
 		done(SCpnt);
 	}
-	spin_unlock_irqrestore(&tw_dev->tw_lock, flags);
+	spin_unlock(&tw_dev->tw_lock);
 
 	return 0;
 } /* End tw_scsi_queue() */
@@ -2578,6 +2809,12 @@
 	/* Free up the IRQ */
 	free_irq(tw_dev->tw_pci_dev->irq, tw_dev);
 
+	/* Unregister character device */
+	if (twe_major >= 0) {
+		unregister_chrdev(twe_major, "twe");
+		twe_major = -1;
+	}
+
 	/* Free up device extension resources */
 	tw_free_device_extension(tw_dev);
 
@@ -2651,7 +2888,6 @@
 {
 	unsigned char *is_unit_present;
 	unsigned char *request_buffer;
-	int i;
 	TW_Param *param;
 
 	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_inquiry_complete()\n");
@@ -2663,12 +2899,12 @@
 	}
 	request_buffer = tw_dev->srb[request_id]->request_buffer;
 	memset(request_buffer, 0, tw_dev->srb[request_id]->request_bufflen);
-	request_buffer[0] = TYPE_DISK;									 /* Peripheral device type */
-	request_buffer[1] = 0;													 /* Device type modifier */
-	request_buffer[2] = 0;													 /* No ansi/iso compliance */
-	request_buffer[4] = 31;													/* Additional length */
+	request_buffer[0] = TYPE_DISK; /* Peripheral device type */
+	request_buffer[1] = 0;	       /* Device type modifier */
+	request_buffer[2] = 0;	       /* No ansi/iso compliance */
+	request_buffer[4] = 31;	       /* Additional length */
 	memcpy(&request_buffer[8], "3ware   ", 8);	 /* Vendor ID */
-	memcpy(&request_buffer[16], "3w-xxxx         ", 16); /* Product ID */
+	sprintf(&request_buffer[16], "Logical Disk %-2d ", tw_dev->srb[request_id]->target);
 	memcpy(&request_buffer[32], tw_driver_version, 3);
 
 	param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
@@ -2678,15 +2914,12 @@
 	}
 	is_unit_present = &(param->data[0]);
 
-	for (i=0 ; i<TW_MAX_UNITS; i++) {
-		if (is_unit_present[i] == 0) {
-			tw_dev->is_unit_present[i] = FALSE;
-		} else {
-		  if (is_unit_present[i] & TW_UNIT_ONLINE) {
-			tw_dev->is_unit_present[i] = TRUE;
-			dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_inquiry_complete: Unit %d found.\n", i);
-		  }
-		}
+	if (is_unit_present[tw_dev->srb[request_id]->target] & TW_UNIT_ONLINE) {
+		tw_dev->is_unit_present[tw_dev->srb[request_id]->target] = TRUE;
+	} else {
+		tw_dev->is_unit_present[tw_dev->srb[request_id]->target] = FALSE;
+		tw_dev->srb[request_id]->result = (DID_BAD_TARGET << 16);
+		return TW_ISR_DONT_RESULT;
 	}
 
 	return 0;
@@ -2993,7 +3226,11 @@
                 /* Do this if there are no sg list entries for raid 5 */
                 if (tw_dev->srb[request_id]->use_sg == 0) {
 			dprintk(KERN_WARNING "doing raid 5 write use_sg = 0, bounce_buffer[%d] = 0x%p\n", request_id, tw_dev->bounce_buffer[request_id]);
-			memcpy(tw_dev->bounce_buffer[request_id], tw_dev->srb[request_id]->request_buffer, tw_dev->srb[request_id]->request_bufflen);
+			buffaddr = tw_map_scsi_single_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
+			if (buffaddr == 0)
+				return 1;
+
+			memcpy(tw_dev->bounce_buffer[request_id], bus_to_virt(buffaddr), tw_dev->srb[request_id]->request_bufflen);
 			command_packet->byte8.io.sgl[0].address = tw_dev->bounce_buffer_phys[request_id];
 			command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen;
 			command_packet->size+=2;
@@ -3002,9 +3239,13 @@
                 /* Do this if we have multiple sg list entries for raid 5 */
                 if (tw_dev->srb[request_id]->use_sg > 0) {
                         dprintk(KERN_WARNING "doing raid 5 write use_sg = %d, sglist[0].length = %d\n", tw_dev->srb[request_id]->use_sg, sglist[0].length);
-                        for (i=0;i<tw_dev->srb[request_id]->use_sg; i++) {
-                                memcpy((char *)(tw_dev->bounce_buffer[request_id])+count, sglist[i].address, sglist[i].length);
-				count+=sglist[i].length;
+			use_sg = tw_map_scsi_sg_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
+			if (use_sg == 0)
+				return 1;
+
+			for (i=0;i<use_sg; i++) {
+				memcpy((char *)tw_dev->bounce_buffer[request_id]+count, bus_to_virt(sg_dma_address(&sglist[i])), sg_dma_len(&sglist[i]));
+				count+=sg_dma_len(&sglist[i]);
                         }
                         command_packet->byte8.io.sgl[0].address = tw_dev->bounce_buffer_phys[request_id];
                         command_packet->byte8.io.sgl[0].length = count;
@@ -3088,17 +3329,89 @@
 /* This function will handle test unit ready scsi command */
 int tw_scsiop_test_unit_ready(TW_Device_Extension *tw_dev, int request_id)
 {
+
+	TW_Param *param;
+	TW_Command *command_packet;
+	unsigned long command_que_value;
+	u32 command_que_addr;
+	unsigned long param_value;
+
 	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_test_unit_ready()\n");
 
-	/* Tell the scsi layer were done */
-	tw_dev->state[request_id] = TW_S_COMPLETED;
-	tw_state_request_finish(tw_dev, request_id);
-	tw_dev->srb[request_id]->result = (DID_OK << 16);
-	tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+	/* Initialize command packet */
+	command_que_addr = tw_dev->registers.command_que_addr;
+	command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+	if (command_packet == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready(): Bad command packet virtual address.\n");
+		return 1;
+	}
+	memset(command_packet, 0, sizeof(TW_Sector));
+	command_packet->byte0.opcode = TW_OP_GET_PARAM;
+	command_packet->byte0.sgl_offset = 2;
+	command_packet->size = 4;
+	command_packet->request_id = request_id;
+	command_packet->byte3.unit = 0;
+	command_packet->byte3.host_id = 0;
+	command_packet->status = 0;
+	command_packet->flags = 0;
+	command_packet->byte6.parameter_count = 1;
+
+	/* Now setup the param */
+	if (tw_dev->alignment_virtual_address[request_id] == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready(): Bad alignment virtual address.\n");
+		return 1;
+	}
+	param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+	memset(param, 0, sizeof(TW_Sector));
+	param->table_id = 3;	 /* unit summary table */
+	param->parameter_id = 3; /* unitsstatus parameter */
+	param->parameter_size_bytes = TW_MAX_UNITS;
+	param_value = tw_dev->alignment_physical_address[request_id];
+	if (param_value == 0) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready(): Bad alignment physical address.\n");
+		return 1;
+	}
+
+	command_packet->byte8.param.sgl[0].address = param_value;
+	command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
+	command_que_value = tw_dev->command_packet_physical_address[request_id];
+	if (command_que_value == 0) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready(): Bad command packet physical address.\n");
+		return 1;
+	}
+
+	/* Now try to post the command packet */
+	tw_post_command_packet(tw_dev, request_id);
 
 	return 0;
 } /* End tw_scsiop_test_unit_ready() */
 
+/* This function is called by the isr to complete a testunitready command */
+int tw_scsiop_test_unit_ready_complete(TW_Device_Extension *tw_dev, int request_id)
+{
+	unsigned char *is_unit_present;
+	TW_Param *param;
+
+	dprintk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready_complete()\n");
+
+	param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+	if (param == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready_complete(): Bad alignment virtual address.\n");
+		return 1;
+	}
+	is_unit_present = &(param->data[0]);
+
+	if (is_unit_present[tw_dev->srb[request_id]->target] & TW_UNIT_ONLINE) {
+		tw_dev->is_unit_present[tw_dev->srb[request_id]->target] = TRUE;
+	} else {
+		tw_dev->is_unit_present[tw_dev->srb[request_id]->target] = FALSE;
+		tw_dev->srb[request_id]->result = (DID_BAD_TARGET << 16);
+		return TW_ISR_DONT_RESULT;
+	}
+
+	return 0;
+} /* End tw_scsiop_test_unit_ready_complete() */
+
 /* Set a value in the features table */
 int tw_setfeature(TW_Device_Extension *tw_dev, int parm, int param_size,
                   unsigned char *val)
@@ -3233,17 +3546,13 @@
 {
 	dprintk(KERN_NOTICE "3w-xxxx: tw_state_request_finish()\n");
   
-	do {    
-		if (tw_dev->free_tail == tw_dev->free_wrap) {
-			tw_dev->free_tail = TW_Q_START;
-		} else {
-			tw_dev->free_tail = tw_dev->free_tail + 1;
-		}
-	} while ((tw_dev->state[tw_dev->free_queue[tw_dev->free_tail]] != TW_S_COMPLETED));
-
 	tw_dev->free_queue[tw_dev->free_tail] = request_id;
-
 	tw_dev->state[request_id] = TW_S_FINISHED;
+	if (tw_dev->free_tail == tw_dev->free_wrap)
+		tw_dev->free_tail = TW_Q_START;
+	else
+		tw_dev->free_tail++;
+
 	dprintk(KERN_NOTICE "3w-xxxx: tw_state_request_finish(): Freeing request_id %d\n", request_id);
 
 	return 0;
@@ -3257,20 +3566,16 @@
 	dprintk(KERN_NOTICE "3w-xxxx: tw_state_request_start()\n");
 	
 	/* Obtain next free request_id */
-	do {
-		if (tw_dev->free_head == tw_dev->free_wrap) {
-			tw_dev->free_head = TW_Q_START;
-		} else {
-			tw_dev->free_head = tw_dev->free_head + 1;
-		}
-	} while (tw_dev->state[tw_dev->free_queue[tw_dev->free_head]] & TW_START_MASK);
-
 	id = tw_dev->free_queue[tw_dev->free_head];
+	if (tw_dev->free_head == tw_dev->free_wrap)
+		tw_dev->free_head = TW_Q_START;
+	else
+		tw_dev->free_head++;
 
-	dprintk(KERN_NOTICE "3w-xxxx: tw_state_request_start(): id = %d.\n", id);
 	*request_id = id;
 	tw_dev->state[id] = TW_S_STARTED;
 
+	dprintk(KERN_NOTICE "3w-xxxx: tw_state_request_start(): id = %d.\n", id);
 	return 0;
 } /* End tw_state_request_start() */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/3w-xxxx.h linux-2.4.21-pre6/drivers/scsi/3w-xxxx.h
--- linux-2.4.20/drivers/scsi/3w-xxxx.h	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/3w-xxxx.h	2003-03-26 23:49:19.000000000 +0000
@@ -6,7 +6,7 @@
    		     Arnaldo Carvalho de Melo <acme@conectiva.com.br>
                      Brad Strand <linux@3ware.com>
 
-   Copyright (C) 1999-2002 3ware Inc.
+   Copyright (C) 1999-2003 3ware Inc.
 
    Kernel compatablity By:	Andre Hedrick <andre@suse.com>
    Non-Copyright (C) 2000	Andre Hedrick <andre@suse.com>
@@ -114,11 +114,11 @@
   {0x84, 0x0b, 0x47, 0x00}, // Data CRC error               SCSI parity error
   {0xd0, 0x0b, 0x00, 0x00}, // Device busy                  Aborted command
   {0xd1, 0x0b, 0x00, 0x00}, // Device busy                  Aborted command
+  {0x37, 0x02, 0x04, 0x00}, // Unit offline                 Not ready
 
   /* Codes for older firmware */
                             // 3ware Error                  SCSI Error
   {0x09, 0x0b, 0x00, 0x00}, // Unrecovered disk error       Aborted command
-  {0x37, 0x0b, 0x04, 0x00}, // Unit offline                 Logical unit not ready
   {0x51, 0x0b, 0x00, 0x00}  // Unspecified                  Aborted command
 };
 
@@ -221,12 +221,15 @@
 #define TW_MAX_PCI_BUSES		      255
 #define TW_MAX_RESET_TRIES		      3
 #define TW_UNIT_INFORMATION_TABLE_BASE	      0x300
-#define TW_MAX_CMDS_PER_LUN		      255
+#define TW_MAX_CMDS_PER_LUN		      254 /* 254 for io, 1 for 
+                                                     chrdev ioctl, one for
+                                                     internal aen post */
 #define TW_BLOCK_SIZE			      0x200 /* 512-byte blocks */
 #define TW_IOCTL                              0x80
 #define TW_UNIT_ONLINE                        1
 #define TW_IN_INTR                            1
 #define TW_IN_IOCTL                           2
+#define TW_IN_CHRDEV_IOCTL                    3
 #define TW_MAX_SECTORS                        256
 #define TW_MAX_BOUNCE_SECTORS                 128
 #define TW_AEN_WAIT_TIME                      1000
@@ -235,6 +238,8 @@
 #define TW_ISR_DONT_COMPLETE                  2
 #define TW_ISR_DONT_RESULT                    3
 #define TW_IOCTL_TIMEOUT                      25 /* 25 seconds */
+#define TW_IOCTL_CHRDEV_TIMEOUT               25 /* 25 seconds */
+#define TW_IOCTL_CHRDEV_FREE                  -1
 
 /* Macros */
 #define TW_STATUS_ERRORS(x) \
@@ -250,6 +255,8 @@
 #define dprintk(msg...) do { } while(0)
 #endif
 
+#pragma pack(1)
+
 /* Scatter Gather List Entry */
 typedef struct TAG_TW_SG_Entry {
 	u32 address;
@@ -299,6 +306,8 @@
 	} byte8;
 } TW_Command;
 
+#pragma pack()
+
 typedef struct TAG_TW_Ioctl {
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,15)
 	int buffer;
@@ -311,6 +320,16 @@
 	unsigned char data[1];
 } TW_Ioctl;
 
+#pragma pack(1)
+
+/* Structure for new chardev ioctls */
+typedef struct TAG_TW_New_Ioctl {
+	unsigned int data_buffer_length;
+	unsigned char padding [508];
+	TW_Command firmware_command;
+	char data_buffer[1];
+} TW_New_Ioctl;
+
 /* GetParam descriptor */
 typedef struct {
 	unsigned short	table_id;
@@ -425,8 +444,12 @@
 	unsigned long		*ioctl_data[TW_Q_LENGTH];
 	int			reset_print;
 	char                    online;
+	volatile int		chrdev_request_id;
+	wait_queue_head_t       ioctl_wqueue;
 } TW_Device_Extension;
 
+#pragma pack()
+
 /* Function prototypes */
 int tw_aen_complete(TW_Device_Extension *tw_dev, int request_id);
 int tw_aen_drain_queue(TW_Device_Extension *tw_dev);
@@ -473,6 +496,7 @@
 int tw_scsiop_request_sense(TW_Device_Extension *tw_dev, int request_id);
 int tw_scsiop_synchronize_cache(TW_Device_Extension *tw_dev, int request_id);
 int tw_scsiop_test_unit_ready(TW_Device_Extension *tw_dev, int request_id);
+int tw_scsiop_test_unit_ready_complete(TW_Device_Extension *tw_dev, int request_id);
 int tw_setfeature(TW_Device_Extension *tw_dev, int parm, int param_size, 
 		  unsigned char *val);
 int tw_setup_irq(TW_Device_Extension *tw_dev);
@@ -505,7 +529,7 @@
 	reset : NULL,					\
 	slave_attach : NULL,				\
 	bios_param : tw_scsi_biosparam,			\
-	can_queue : TW_Q_LENGTH-1,			\
+	can_queue : TW_Q_LENGTH-2,			\
 	this_id: -1,					\
 	sg_tablesize : TW_MAX_SGL_LENGTH,		\
 	cmd_per_lun: TW_MAX_CMDS_PER_LUN,		\
@@ -538,7 +562,7 @@
 	reset : NULL,					\
 	slave_attach : NULL,				\
 	bios_param : tw_scsi_biosparam,			\
-	can_queue : TW_Q_LENGTH-1,			\
+	can_queue : TW_Q_LENGTH-2,			\
 	this_id: -1,					\
 	sg_tablesize : TW_MAX_SGL_LENGTH,		\
 	cmd_per_lun: TW_MAX_CMDS_PER_LUN,		\
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/53c7xx.c linux-2.4.21-pre6/drivers/scsi/53c7xx.c
--- linux-2.4.20/drivers/scsi/53c7xx.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/53c7xx.c	2003-03-26 23:49:39.000000000 +0000
@@ -1466,9 +1466,9 @@
     patch_abs_32 (hostdata->script, 0, test_src, 
 	virt_to_bus(&hostdata->test_source));
     patch_abs_32 (hostdata->script, 0, saved_dsa,
-	virt_to_bus(&hostdata->saved2_dsa));
+	virt_to_bus((void *)&hostdata->saved2_dsa));
     patch_abs_32 (hostdata->script, 0, emulfly,
-	virt_to_bus(&hostdata->emulated_intfly));
+	virt_to_bus((void *)&hostdata->emulated_intfly));
 
     patch_abs_rwri_data (hostdata->script, 0, dsa_check_reselect, 
 	(unsigned char)(Ent_dsa_code_check_reselect - Ent_dsa_zero));
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/ChangeLog.ips linux-2.4.21-pre6/drivers/scsi/ChangeLog.ips
--- linux-2.4.20/drivers/scsi/ChangeLog.ips	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/ChangeLog.ips	2003-03-26 23:49:30.000000000 +0000
@@ -1,6 +1,14 @@
 IBM ServeRAID driver Change Log
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
+        6.00.00  - Add 6x Adapters and Battery Flash 
+        
+        5.30.00  - use __devexit_p()
+	
+        5.10.15  - remove unused code (sem, macros, etc.)                         
+
+        5.10.12  - use pci_dma interfaces, update for 2.5 kernel changes  
+	      
         5.00.01  - Sarasota ( 5i ) adapters must always be scanned first  
                  - Get rid on IOCTL_NEW_COMMAND code  
                  - Add Extended DCDB Commands for Tape Support in 5I                  
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/Config.in linux-2.4.21-pre6/drivers/scsi/Config.in
--- linux-2.4.20/drivers/scsi/Config.in	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/Config.in	2003-03-26 23:49:34.000000000 +0000
@@ -204,6 +204,7 @@
 if [ "$CONFIG_X86" = "y" ]; then
    dep_tristate 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR $CONFIG_SCSI
 fi
+dep_tristate 'Workbit NinjaSCSI-32Bi/UDE support' CONFIG_SCSI_NSP32 $CONFIG_SCSI
 #
 # Note - this is a very special 'host' adapter that simulates the presence of some disks.
 # It can come in very handy for troubleshooting.  Anyone else is welcome to use it - all
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/Makefile linux-2.4.21-pre6/drivers/scsi/Makefile
--- linux-2.4.20/drivers/scsi/Makefile	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/Makefile	2003-03-26 23:49:19.000000000 +0000
@@ -50,7 +50,7 @@
 obj-$(CONFIG_ATARI_SCSI)	+= atari_scsi.o
 obj-$(CONFIG_MAC_SCSI)		+= mac_scsi.o
 obj-$(CONFIG_SCSI_MAC_ESP)	+= mac_esp.o	NCR53C9x.o
-obj-$(CONFIG_SUN3_SCSI)		+= sun3_scsi.o
+obj-$(CONFIG_SUN3_SCSI)		+= sun3_scsi.o  sun3_scsi_vme.o
 obj-$(CONFIG_MVME16x_SCSI)	+= mvme16x.o	53c7xx.o
 obj-$(CONFIG_BVME6000_SCSI)	+= bvme6000.o	53c7xx.o
 obj-$(CONFIG_SCSI_SIM710)	+= sim710.o
@@ -127,6 +127,7 @@
 obj-$(CONFIG_SCSI_FCAL)		+= fcal.o
 obj-$(CONFIG_SCSI_CPQFCTS)	+= cpqfc.o
 obj-$(CONFIG_SCSI_LASI700)	+= lasi700.o 53c700.o
+obj-$(CONFIG_SCSI_NSP32)	+= nsp32.o
 
 subdir-$(CONFIG_ARCH_ACORN)	+= ../acorn/scsi
 obj-$(CONFIG_ARCH_ACORN)	+= ../acorn/scsi/acorn-scsi.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/NCR5380.c linux-2.4.21-pre6/drivers/scsi/NCR5380.c
--- linux-2.4.20/drivers/scsi/NCR5380.c	2002-02-25 19:38:04.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/NCR5380.c	2003-03-26 23:49:19.000000000 +0000
@@ -2460,8 +2460,9 @@
 						    hostdata->issue_queue;
 						hostdata->issue_queue = (Scsi_Cmnd *) cmd;
 						dprintk(NDEBUG_QUEUES, ("scsi%d : REQUEST SENSE added to head of issue queue\n", instance->host_no));
-					} else {
+					} else
 #endif				/* def AUTOSENSE */
+					{
 						collect_stats(hostdata, cmd);
 						cmd->scsi_done(cmd);
 					}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/aacraid/linit.c linux-2.4.21-pre6/drivers/scsi/aacraid/linit.c
--- linux-2.4.20/drivers/scsi/aacraid/linit.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/aacraid/linit.c	2003-03-26 23:48:59.000000000 +0000
@@ -59,7 +59,7 @@
 #define AAC_DRIVERNAME	"aacraid"
 
 MODULE_AUTHOR("Red Hat Inc and Adaptec");
-MODULE_DESCRIPTION("Supports Dell PERC2, 2/Si, 3/Si, 3/Di, Adaptec 2120S, 2200S, 5400S, and HP NetRAID-4M devices. http://domsch.com/linux/ or http://linux.adaptec.com");
+MODULE_DESCRIPTION("Supports Dell PERC2, 2/Si, 3/Si, 3/Di, PERC 320/DC, Adaptec 2120S, 2200S, 5400S, and HP NetRAID-4M devices. http://domsch.com/linux/ or http://linux.adaptec.com");
 MODULE_LICENSE("GPL");
 MODULE_PARM(nondasd, "i");
 MODULE_PARM_DESC(nondasd, "Control scanning of hba for nondasd devices. 0=off, 1=on");
@@ -95,6 +95,7 @@
 	{ 0x9005, 0x0285, 0x9005, 0x0286, aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2120S   ", 1 }, /* Adaptec 2120S (Crusader)*/
 	{ 0x9005, 0x0285, 0x9005, 0x0285, aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2200S   ", 2 }, /* Adaptec 2200S (Vulcan)*/
 	{ 0x9005, 0x0285, 0x9005, 0x0287, aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2200S   ", 2 }, /* Adaptec 2200S (Vulcan-2m)*/
+	{ 0x9005, 0x0285, 0x1028, 0x0287, aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2 }, /* Dell PERC 320/DC */
 	{ 0x1011, 0x0046, 0x9005, 0x0365, aac_sa_init, "aacraid",  "ADAPTEC ", "Adaptec 5400S   ", 4 }, /* Adaptec 5400S (Mustang)*/
 	{ 0x1011, 0x0046, 0x9005, 0x0364, aac_sa_init, "aacraid",  "ADAPTEC ", "AAC-364         ", 4 }, /* Adaptec 5400S (Mustang)*/
 	{ 0x1011, 0x0046, 0x9005, 0x1364, aac_sa_init, "percraid", "DELL    ", "PERCRAID        ", 4 }, /* Dell PERC2 "Quad Channel" */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/advansys.c linux-2.4.21-pre6/drivers/scsi/advansys.c
--- linux-2.4.20/drivers/scsi/advansys.c	2001-11-09 22:05:06.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/advansys.c	2003-03-26 23:49:23.000000000 +0000
@@ -5131,7 +5131,6 @@
                 ep->adapter_info[3] = asc_dvc_varp->cfg->adapter_info[3];
                 ep->adapter_info[4] = asc_dvc_varp->cfg->adapter_info[4];
                 ep->adapter_info[5] = asc_dvc_varp->cfg->adapter_info[5];
-                ep->adapter_info[6] = asc_dvc_varp->cfg->adapter_info[6];
 
                /*
                 * Modify board configuration.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/aic7xxx/aic7xxx.h linux-2.4.21-pre6/drivers/scsi/aic7xxx/aic7xxx.h
--- linux-2.4.20/drivers/scsi/aic7xxx/aic7xxx.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/aic7xxx/aic7xxx.h	2003-03-26 23:49:40.000000000 +0000
@@ -362,7 +362,7 @@
 
 /*
  * The driver keeps up to MAX_SCB scb structures per card in memory.  The SCB
- * consists of a "hardware SCB" mirroring the fields availible on the card
+ * consists of a "hardware SCB" mirroring the fields available on the card
  * and additional information the kernel stores for each transaction.
  *
  * To minimize space utilization, a portion of the hardware scb stores
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/aic7xxx/aic7xxx_core.c linux-2.4.21-pre6/drivers/scsi/aic7xxx/aic7xxx_core.c
--- linux-2.4.20/drivers/scsi/aic7xxx/aic7xxx_core.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/aic7xxx/aic7xxx_core.c	2003-03-26 23:49:35.000000000 +0000
@@ -388,7 +388,7 @@
 
 	ahc_dump_card_state(ahc);
 
-	/* Tell everyone that this HBA is no longer availible */
+	/* Tell everyone that this HBA is no longer available */
 	ahc_abort_scbs(ahc, CAM_TARGET_WILDCARD, ALL_CHANNELS,
 		       CAM_LUN_WILDCARD, SCB_LIST_NULL, ROLE_UNKNOWN,
 		       CAM_NO_HBA);
@@ -2748,9 +2748,9 @@
 	targ_scsirate = tinfo->scsirate;
 
 	/*
-	 * Parse as much of the message as is availible,
+	 * Parse as much of the message as is available,
 	 * rejecting it if we don't support it.  When
-	 * the entire message is availible and has been
+	 * the entire message is available and has been
 	 * handled, return MSGLOOP_MSGCOMPLETE, indicating
 	 * that we have parsed an entire message.
 	 *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/aic7xxx_old.c linux-2.4.21-pre6/drivers/scsi/aic7xxx_old.c
--- linux-2.4.20/drivers/scsi/aic7xxx_old.c	2001-11-21 22:05:29.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/aic7xxx_old.c	2003-03-26 23:49:31.000000000 +0000
@@ -5435,9 +5435,9 @@
   target_mask = (0x01 << tindex);
 
   /*
-   * Parse as much of the message as is availible,
+   * Parse as much of the message as is available,
    * rejecting it if we don't support it.  When
-   * the entire message is availible and has been
+   * the entire message is available and has been
    * handled, return TRUE indicating that we have
    * parsed an entire message.
    */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/amiga7xx.c linux-2.4.21-pre6/drivers/scsi/amiga7xx.c
--- linux-2.4.20/drivers/scsi/amiga7xx.c	2001-10-25 20:53:49.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/amiga7xx.c	2003-03-26 23:49:29.000000000 +0000
@@ -86,7 +86,7 @@
 #ifdef CONFIG_WARPENGINE_SCSI
     	    case ZORRO_PROD_MACROSYSTEMS_WARP_ENGINE_40xx:
 		if (request_mem_region(address+0x40000, 0x1000, "ncr53c710")) {
-		    address = (unsigned long)ioremap(address, size);
+		    address = (unsigned long)z_ioremap(address, size);
 		    options = OPTION_MEMORY_MAPPED | OPTION_DEBUG_TEST1 |
 			      OPTION_INTFLY | OPTION_SYNCHRONOUS |
 			      OPTION_ALWAYS_SYNCHRONOUS | OPTION_DISCONNECT;
@@ -102,7 +102,7 @@
 	    case ZORRO_PROD_CBM_A4091_1:
 	    case ZORRO_PROD_CBM_A4091_2:
 		if (request_mem_region(address+0x800000, 0x1000, "ncr53c710")) {
-		    address = (unsigned long)ioremap(address, size);
+		    address = (unsigned long)z_ioremap(address, size);
 		    options = OPTION_MEMORY_MAPPED | OPTION_DEBUG_TEST1 |
 			      OPTION_INTFLY | OPTION_SYNCHRONOUS |
 			      OPTION_ALWAYS_SYNCHRONOUS | OPTION_DISCONNECT;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/atari_NCR5380.c linux-2.4.21-pre6/drivers/scsi/atari_NCR5380.c
--- linux-2.4.20/drivers/scsi/atari_NCR5380.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/atari_NCR5380.c	2003-03-26 23:49:40.000000000 +0000
@@ -309,13 +309,8 @@
 #undef TAG_NONE
 #define TAG_NONE 0xff
 
-/* For the m68k, the number of bits in 'allocated' must be a multiple of 32! */
-#if (MAX_TAGS % 32) != 0
-#error "MAX_TAGS must be a multiple of 32!"
-#endif
-
 typedef struct {
-    char	allocated[MAX_TAGS/8];
+    DECLARE_BITMAP(allocated, MAX_TAGS);
     int		nr_allocated;
     int		queue_size;
 } TAG_ALLOC;
@@ -334,7 +329,7 @@
     for( target = 0; target < 8; ++target ) {
 	for( lun = 0; lun < 8; ++lun ) {
 	    ta = &TagAlloc[target][lun];
-	    memset( &ta->allocated, 0, MAX_TAGS/8 );
+	    CLEAR_BITMAP( ta->allocated, MAX_TAGS );
 	    ta->nr_allocated = 0;
 	    /* At the beginning, assume the maximum queue size we could
 	     * support (MAX_TAGS). This value will be decreased if the target
@@ -394,8 +389,8 @@
     else {
 	TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun];
 
-	cmd->tag = find_first_zero_bit( &ta->allocated, MAX_TAGS );
-	set_bit( cmd->tag, &ta->allocated );
+	cmd->tag = find_first_zero_bit( ta->allocated, MAX_TAGS );
+	set_bit( cmd->tag, ta->allocated );
 	ta->nr_allocated++;
 	TAG_PRINTK( "scsi%d: using tag %d for target %d lun %d "
 		    "(now %d tags in use)\n",
@@ -424,7 +419,7 @@
     }
     else {
 	TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun];
-	clear_bit( cmd->tag, &ta->allocated );
+	clear_bit( cmd->tag, ta->allocated );
 	ta->nr_allocated--;
 	TAG_PRINTK( "scsi%d: freed tag %d for target %d lun %d\n",
 		    H_NO(cmd), cmd->tag, cmd->target, cmd->lun );
@@ -443,7 +438,7 @@
     for( target = 0; target < 8; ++target ) {
 	for( lun = 0; lun < 8; ++lun ) {
 	    ta = &TagAlloc[target][lun];
-	    memset( &ta->allocated, 0, MAX_TAGS/8 );
+	    CLEAR_BITMAP( ta->allocated, MAX_TAGS );
 	    ta->nr_allocated = 0;
 	}
     }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/blz1230.c linux-2.4.21-pre6/drivers/scsi/blz1230.c
--- linux-2.4.20/drivers/scsi/blz1230.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/blz1230.c	2003-03-26 23:49:07.000000000 +0000
@@ -131,8 +131,8 @@
 		esp->eregs = eregs;
 
 		/* Set the command buffer */
-		esp->esp_command = (volatile unsigned char*) cmd_buffer;
-		esp->esp_command_dvma = virt_to_bus(cmd_buffer);
+		esp->esp_command = cmd_buffer;
+		esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer);
 
 		esp->irq = IRQ_AMIGA_PORTS;
 		esp->slot = board+REAL_BLZ1230_ESP_ADDR;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/blz2060.c linux-2.4.21-pre6/drivers/scsi/blz2060.c
--- linux-2.4.20/drivers/scsi/blz2060.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/blz2060.c	2003-03-26 23:49:35.000000000 +0000
@@ -110,8 +110,8 @@
 		esp->eregs = (struct ESP_regs *)(address + BLZ2060_ESP_ADDR);
 		
 		/* Set the command buffer */
-		esp->esp_command = (volatile unsigned char*) cmd_buffer;
-		esp->esp_command_dvma = virt_to_bus(cmd_buffer);
+		esp->esp_command = cmd_buffer;
+		esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer);
 
 		esp->irq = IRQ_AMIGA_PORTS;
 		request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/cpqfc.Readme linux-2.4.21-pre6/drivers/scsi/cpqfc.Readme
--- linux-2.4.20/drivers/scsi/cpqfc.Readme	2001-10-25 20:53:50.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/cpqfc.Readme	2003-03-26 23:49:37.000000000 +0000
@@ -22,6 +22,9 @@
    * Makefile changes to bring cpqfc into line w/ rest of SCSI drivers
      (thanks to Keith Owens)
 
+Ver 2.1.2  Jul 22, 2002
+   * initialize DumCmnd.lun (used as LUN index in fcFindLoggedInPort())
+
 Ver 2.0.5  Aug 06, 2001
    * Reject non-existent luns in the driver rather than letting the 
      hardware do it.  (some HW behaves differently than others in this area.)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/cpqfcTS.h linux-2.4.21-pre6/drivers/scsi/cpqfcTS.h
--- linux-2.4.20/drivers/scsi/cpqfcTS.h	2001-08-05 20:12:41.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/cpqfcTS.h	2003-03-26 23:49:30.000000000 +0000
@@ -5,40 +5,40 @@
 // These functions are required by the Linux SCSI layers
 extern int cpqfcTS_detect(Scsi_Host_Template *);
 extern int cpqfcTS_release(struct Scsi_Host *);
-extern const char * cpqfcTS_info(struct Scsi_Host *);
+extern const char *cpqfcTS_info(struct Scsi_Host *);
 extern int cpqfcTS_proc_info(char *, char **, off_t, int, int, int);
-extern int cpqfcTS_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
+extern int cpqfcTS_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
 extern int cpqfcTS_abort(Scsi_Cmnd *);
 extern int cpqfcTS_reset(Scsi_Cmnd *, unsigned int);
-extern int cpqfcTS_eh_abort(Scsi_Cmnd *Cmnd);
+extern int cpqfcTS_eh_abort(Scsi_Cmnd * Cmnd);
 extern int cpqfcTS_eh_device_reset(Scsi_Cmnd *);
 extern int cpqfcTS_biosparam(Disk *, kdev_t, int[]);
-extern int cpqfcTS_ioctl( Scsi_Device *ScsiDev, int Cmnd, void *arg);
+extern int cpqfcTS_ioctl(Scsi_Device * ScsiDev, int Cmnd, void *arg);
 
 // note: since Tachyon TS supports an extended scatter/gather
 // linked list of infinite length (with linked Ext S/G pages,
 // limited only by available physical memory) we use SG_ALL.
 
 #define CPQFCTS {                                \
- detect:                 cpqfcTS_detect,         \
- release:                cpqfcTS_release,        \
- info:                   cpqfcTS_info,           \
- proc_info:              cpqfcTS_proc_info,      \
- ioctl:                  cpqfcTS_ioctl,          \
- queuecommand:           cpqfcTS_queuecommand,   \
- eh_device_reset_handler:   cpqfcTS_eh_device_reset,   \
- eh_abort_handler:       cpqfcTS_eh_abort,       \
- reset:                  cpqfcTS_reset,          \
- abort:                  cpqfcTS_abort,		 \
- bios_param:             cpqfcTS_biosparam,      \
- can_queue:              CPQFCTS_REQ_QUEUE_LEN,  \
- this_id:                -1,                     \
- sg_tablesize:           SG_ALL,                 \
- cmd_per_lun:            CPQFCTS_CMD_PER_LUN,    \
- present:                0,                      \
- unchecked_isa_dma:      0,                      \
- use_clustering:         ENABLE_CLUSTERING,      \
- use_new_eh_code:        1			 \
+	detect:                 cpqfcTS_detect,         \
+	release:                cpqfcTS_release,        \
+	info:                   cpqfcTS_info,           \
+	proc_info:              cpqfcTS_proc_info,      \
+	ioctl:                  cpqfcTS_ioctl,          \
+	queuecommand:           cpqfcTS_queuecommand,   \
+	eh_device_reset_handler:   cpqfcTS_eh_device_reset,   \
+	eh_abort_handler:       cpqfcTS_eh_abort,       \
+	reset:                  cpqfcTS_reset,    	\
+	abort:                  cpqfcTS_abort,		\
+	bios_param:             cpqfcTS_biosparam,	\
+	can_queue:              CPQFCTS_REQ_QUEUE_LEN,	\
+	this_id:                -1,               	\
+	sg_tablesize:           SG_ALL,           	\
+	cmd_per_lun:            CPQFCTS_CMD_PER_LUN,	\
+	present:                0,              	\
+	unchecked_isa_dma:      0,              	\
+	use_clustering:         ENABLE_CLUSTERING,	\
+	use_new_eh_code:        1			\
 }
 
-#endif /* CPQFCTS_H */ 
+#endif				/* CPQFCTS_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/cpqfcTSchip.h linux-2.4.21-pre6/drivers/scsi/cpqfcTSchip.h
--- linux-2.4.20/drivers/scsi/cpqfcTSchip.h	2000-09-19 15:01:34.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/cpqfcTSchip.h	2003-03-26 23:49:38.000000000 +0000
@@ -18,6 +18,7 @@
  * General Public License for more details.
  * Written by Don Zimmerman
 */
+
 #ifndef CPQFCTSCHIP_H
 #define CPQFCTSCHIP_H
 #ifndef TACHYON_CHIP_INC
@@ -29,210 +30,211 @@
 #define FC_PH43			0x09
 #define FC_PH3			0x20
 
-#define TACHLITE_TS_RX_SIZE     1024  // max inbound frame size
+#define TACHLITE_TS_RX_SIZE     1024	// max inbound frame size
 // "I" prefix is for Include
 
-#define IVENDID    0x00  // word
-#define IDEVID     0x02
-#define ITLCFGCMD 0x04
-#define IMEMBASE   0x18    // Tachyon
-#define ITLMEMBASE   0x1C  // Tachlite
-#define IIOBASEL   0x10    // Tachyon I/O base address, lower 256 bytes
-#define IIOBASEU   0x14    // Tachyon I/O base address, upper 256 bytes
-#define ITLIOBASEL   0x14  // TachLite I/O base address, lower 256 bytes
-#define ITLIOBASEU   0x18  // TachLite I/O base address, upper 256 bytes
-#define ITLRAMBASE   0x20  // TL on-board RAM start
-#define ISROMBASE  0x24
-#define IROMBASE   0x30
-
-#define ICFGCMD    0x04    // PCI config - PCI config access (word)
-#define ICFGSTAT   0x06    // PCI status (R - word)
-#define IRCTR_WCTR 0x1F2   // ROM control / pre-fetch wait counter
-#define IPCIMCTR   0x1F3   // PCI master control register
-#define IINTPEND   0x1FD   // Interrupt pending (I/O Upper - Tachyon & TL)
-#define IINTEN     0x1FE   // Interrupt enable  (I/O Upper - Tachyon & TL)
-#define IINTSTAT   0x1FF   // Interrupt status  (I/O Upper - Tachyon & TL)
+#define IVENDID		0x00	// word
+#define IDEVID		0x02
+#define ITLCFGCMD	0x04
+#define IMEMBASE	0x18	// Tachyon
+#define ITLMEMBASE	0x1C	// Tachlite
+#define IIOBASEL	0x10	// Tachyon I/O base address, lower 256 bytes
+#define IIOBASEU	0x14	// Tachyon I/O base address, upper 256 bytes
+#define ITLIOBASEL	0x14	// TachLite I/O base address, lower 256 bytes
+#define ITLIOBASEU	0x18	// TachLite I/O base address, upper 256 bytes
+#define ITLRAMBASE	0x20	// TL on-board RAM start
+#define ISROMBASE	0x24
+#define IROMBASE	0x30
+
+#define ICFGCMD		0x04	// PCI config - PCI config access (word)
+#define ICFGSTAT	0x06	// PCI status (R - word)
+#define IRCTR_WCTR	0x1F2	// ROM control / pre-fetch wait counter
+#define IPCIMCTR	0x1F3	// PCI master control register
+#define IINTPEND	0x1FD	// Interrupt pending (I/O Upper - Tachyon & TL)
+#define IINTEN		0x1FE	// Interrupt enable  (I/O Upper - Tachyon & TL)
+#define IINTSTAT	0x1FF	// Interrupt status  (I/O Upper - Tachyon & TL)
 
 #define IMQ_BASE            0x80
 #define IMQ_LENGTH          0x84
 #define IMQ_CONSUMER_INDEX  0x88
-#define IMQ_PRODUCER_INDEX  0x8C   // Tach copies its INDX to bits 0-7 of value
+#define IMQ_PRODUCER_INDEX  0x8C 	// Tach copies its INDX to bits 0-7 of value
 
 /*
 // IOBASE UPPER
-#define SFSBQ_BASE            0x00   // single-frame sequences
+#define SFSBQ_BASE            0x00	// single-frame sequences
 #define SFSBQ_LENGTH          0x04
 #define SFSBQ_PRODUCER_INDEX  0x08
-#define SFSBQ_CONSUMER_INDEX  0x0C   // (R)
+#define SFSBQ_CONSUMER_INDEX  0x0C	// (R)
 #define SFS_BUFFER_LENGTH     0X10
-                              // SCSI-FCP hardware assists
-#define SEST_BASE             0x40   // SSCI Exchange State Table
+	                          	// SCSI-FCP hardware assists
+#define SEST_BASE             0x40	// SSCI Exchange State Table
 #define SEST_LENGTH           0x44
 #define SCSI_BUFFER_LENGTH    0x48
 #define SEST_LINKED_LIST      0x4C
 
 #define TACHYON_My_ID         0x6C
-#define TACHYON_CONFIGURATION 0x84   // (R/W) reset val 2
+#define TACHYON_CONFIGURATION 0x84	// (R/W) reset val 2
 #define TACHYON_CONTROL       0x88
-#define TACHYON_STATUS        0x8C   // (R)
-#define TACHYON_FLUSH_SEST    0x90   // (R/W)
-#define TACHYON_EE_CREDIT_TMR 0x94   // (R)
-#define TACHYON_BB_CREDIT_TMR 0x98   // (R)
-#define TACHYON_RCV_FRAME_ERR 0x9C   // (R)
-#define FRAME_MANAGER_CONFIG  0xC0   // (R/W)
+#define TACHYON_STATUS        0x8C	// (R)
+#define TACHYON_FLUSH_SEST    0x90	// (R/W)
+#define TACHYON_EE_CREDIT_TMR 0x94	// (R)
+#define TACHYON_BB_CREDIT_TMR 0x98	// (R)
+#define TACHYON_RCV_FRAME_ERR 0x9C	// (R)
+#define FRAME_MANAGER_CONFIG  0xC0	// (R/W)
 #define FRAME_MANAGER_CONTROL 0xC4
-#define FRAME_MANAGER_STATUS  0xC8   // (R)
+#define FRAME_MANAGER_STATUS  0xC8	// (R)
 #define FRAME_MANAGER_ED_TOV  0xCC
-#define FRAME_MANAGER_LINK_ERR1 0xD0   // (R)
-#define FRAME_MANAGER_LINK_ERR2 0xD4   // (R)
-#define FRAME_MANAGER_TIMEOUT2  0xD8   // (W)
-#define FRAME_MANAGER_BB_CREDIT 0xDC   // (R)
-#define FRAME_MANAGER_WWN_HI    0xE0   // (R/W)
-#define FRAME_MANAGER_WWN_LO    0xE4   // (R/W)
-#define FRAME_MANAGER_RCV_AL_PA 0xE8   // (R)
-#define FRAME_MANAGER_PRIMITIVE 0xEC   // {K28.5} byte1 byte2 byte3
+#define FRAME_MANAGER_LINK_ERR1 0xD0	// (R)
+#define FRAME_MANAGER_LINK_ERR2 0xD4	// (R)
+#define FRAME_MANAGER_TIMEOUT2  0xD8	// (W)
+#define FRAME_MANAGER_BB_CREDIT 0xDC	// (R)
+#define FRAME_MANAGER_WWN_HI    0xE0	// (R/W)
+#define FRAME_MANAGER_WWN_LO    0xE4	// (R/W)
+#define FRAME_MANAGER_RCV_AL_PA 0xE8	// (R)
+#define FRAME_MANAGER_PRIMITIVE 0xEC	// {K28.5} byte1 byte2 byte3
 */
-		    
-#define TL_MEM_ERQ_BASE                    0x0 //ERQ Base
-#define TL_IO_ERQ_BASE                     0x0 //ERQ base
 
-#define TL_MEM_ERQ_LENGTH                  0x4 //ERQ Length
-#define TL_IO_ERQ_LENGTH                   0x4 //ERQ Length
+#define TL_MEM_ERQ_BASE                 0x0	//ERQ Base
+#define TL_IO_ERQ_BASE                  0x0	//ERQ base
+
+#define TL_MEM_ERQ_LENGTH               0x4	//ERQ Length
+#define TL_IO_ERQ_LENGTH                0x4	//ERQ Length
 
-#define TL_MEM_ERQ_PRODUCER_INDEX          0x8 //ERQ Producer Index  register
-#define TL_IO_ERQ_PRODUCER_INDEX           0x8 //ERQ Producer Index  register
+#define TL_MEM_ERQ_PRODUCER_INDEX       0x8	//ERQ Producer Index  register
+#define TL_IO_ERQ_PRODUCER_INDEX	0x8	//ERQ Producer Index  register
 
-#define TL_MEM_ERQ_CONSUMER_INDEX_ADR 0xC //ERQ Consumer Index address register
-#define TL_IO_ERQ_CONSUMER_INDEX_ADR  0xC //ERQ Consumer Index address register
+#define TL_MEM_ERQ_CONSUMER_INDEX_ADR	0xC	//ERQ Consumer Index address register
+#define TL_IO_ERQ_CONSUMER_INDEX_ADR	0xC	//ERQ Consumer Index address register
 
-#define TL_MEM_ERQ_CONSUMER_INDEX     0xC //ERQ Consumer Index 
-#define TL_IO_ERQ_CONSUMER_INDEX      0xC //ERQ Consumer Index 
+#define TL_MEM_ERQ_CONSUMER_INDEX     	0xC	//ERQ Consumer Index
+#define TL_IO_ERQ_CONSUMER_INDEX      	0xC	//ERQ Consumer Index
 
-#define TL_MEM_SFQ_BASE               0x50 //SFQ Base
-#define TL_IO_SFQ_BASE                0x50 //SFQ base
+#define TL_MEM_SFQ_BASE               	0x50	//SFQ Base
+#define TL_IO_SFQ_BASE                	0x50	//SFQ base
 
-#define TL_MEM_SFQ_LENGTH             0x54 //SFQ Length
-#define TL_IO_SFQ_LENGTH              0x54 //SFQ Length
+#define TL_MEM_SFQ_LENGTH             	0x54	//SFQ Length
+#define TL_IO_SFQ_LENGTH              	0x54	//SFQ Length
 
-#define TL_MEM_SFQ_CONSUMER_INDEX     0x58 //SFQ Consumer Index
-#define TL_IO_SFQ_CONSUMER_INDEX      0x58 //SFQ Consumer Index
+#define TL_MEM_SFQ_CONSUMER_INDEX     	0x58	//SFQ Consumer Index
+#define TL_IO_SFQ_CONSUMER_INDEX      	0x58	//SFQ Consumer Index
 
-#define TL_MEM_IMQ_BASE               0x80 //IMQ Base
-#define TL_IO_IMQ_BASE                0x80 //IMQ base
+#define TL_MEM_IMQ_BASE               	0x80	//IMQ Base
+#define TL_IO_IMQ_BASE                	0x80	//IMQ base
 
-#define TL_MEM_IMQ_LENGTH             0x84 //IMQ Length
-#define TL_IO_IMQ_LENGTH              0x84 //IMQ Length
+#define TL_MEM_IMQ_LENGTH             	0x84	//IMQ Length
+#define TL_IO_IMQ_LENGTH              	0x84	//IMQ Length
 
-#define TL_MEM_IMQ_CONSUMER_INDEX     0x88 //IMQ Consumer Index
-#define TL_IO_IMQ_CONSUMER_INDEX      0x88 //IMQ Consumer Index
+#define TL_MEM_IMQ_CONSUMER_INDEX     	0x88	//IMQ Consumer Index
+#define TL_IO_IMQ_CONSUMER_INDEX      	0x88	//IMQ Consumer Index
 
-#define TL_MEM_IMQ_PRODUCER_INDEX_ADR 0x8C //IMQ Producer Index address register
-#define TL_IO_IMQ_PRODUCER_INDEX_ADR  0x8C //IMQ Producer Index address register
+#define TL_MEM_IMQ_PRODUCER_INDEX_ADR 	0x8C	//IMQ Producer Index address register
+#define TL_IO_IMQ_PRODUCER_INDEX_ADR  	0x8C	//IMQ Producer Index address register
 
-#define TL_MEM_SEST_BASE              0x140 //SFQ Base
-#define TL_IO_SEST_BASE               0x40 //SFQ base
+#define TL_MEM_SEST_BASE              	0x140	//SFQ Base
+#define TL_IO_SEST_BASE               	0x40	//SFQ base
 
-#define TL_MEM_SEST_LENGTH            0x144 //SFQ Length
-#define TL_IO_SEST_LENGTH             0x44 //SFQ Length
+#define TL_MEM_SEST_LENGTH            	0x144	//SFQ Length
+#define TL_IO_SEST_LENGTH             	0x44	//SFQ Length
 
-#define TL_MEM_SEST_LINKED_LIST       0x14C
+#define TL_MEM_SEST_LINKED_LIST       	0x14C
 
-#define TL_MEM_SEST_SG_PAGE           0x168  // Extended Scatter/Gather page size
+#define TL_MEM_SEST_SG_PAGE           	0x168	// Extended Scatter/Gather page size
 
-#define TL_MEM_TACH_My_ID             0x16C
-#define TL_IO_TACH_My_ID              0x6C //My AL_PA ID
+#define TL_MEM_TACH_My_ID             	0x16C
+#define TL_IO_TACH_My_ID              	0x6C	//My AL_PA ID
 
-#define TL_MEM_TACH_CONFIG            0x184 //Tachlite Configuration register
-#define TL_IO_CONFIG                  0x84 //Tachlite Configuration register
+#define TL_MEM_TACH_CONFIG            	0x184	//Tachlite Configuration register
+#define TL_IO_CONFIG                  	0x84	//Tachlite Configuration register
 
-#define TL_MEM_TACH_CONTROL           0x188 //Tachlite Control register
-#define TL_IO_CTR                     0x88 //Tachlite Control register
+#define TL_MEM_TACH_CONTROL           	0x188	//Tachlite Control register
+#define TL_IO_CTR                     	0x88	//Tachlite Control register
 
-#define TL_MEM_TACH_STATUS            0x18C //Tachlite Status register
-#define TL_IO_STAT                    0x8C //Tachlite Status register
+#define TL_MEM_TACH_STATUS            	0x18C	//Tachlite Status register
+#define TL_IO_STAT                    	0x8C	//Tachlite Status register
 
-#define TL_MEM_FM_CONFIG        0x1C0 //Frame Manager Configuration register
-#define TL_IO_FM_CONFIG         0xC0 //Frame Manager Configuration register
+#define TL_MEM_FM_CONFIG        	0x1C0	//Frame Manager Configuration register
+#define TL_IO_FM_CONFIG         	0xC0	//Frame Manager Configuration register
 
-#define TL_MEM_FM_CONTROL       0x1C4 //Frame Manager Control
-#define TL_IO_FM_CTL            0xC4 //Frame Manager Control
+#define TL_MEM_FM_CONTROL       	0x1C4	//Frame Manager Control
+#define TL_IO_FM_CTL            	0xC4	//Frame Manager Control
 
-#define TL_MEM_FM_STATUS        0x1C8 //Frame Manager Status
-#define TL_IO_FM_STAT           0xC8 //Frame Manager Status
+#define TL_MEM_FM_STATUS        	0x1C8	//Frame Manager Status
+#define TL_IO_FM_STAT           	0xC8	//Frame Manager Status
 
-#define TL_MEM_FM_LINK_STAT1    0x1D0 //Frame Manager Link Status 1
-#define TL_IO_FM_LINK_STAT1     0xD0 //Frame Manager Link Status 1
+#define TL_MEM_FM_LINK_STAT1    	0x1D0	//Frame Manager Link Status 1
+#define TL_IO_FM_LINK_STAT1     	0xD0	//Frame Manager Link Status 1
 
-#define TL_MEM_FM_LINK_STAT2    0x1D4 //Frame Manager Link Status 2
-#define TL_IO_FM_LINK_STAT2     0xD4 //Frame Manager Link Status 2
+#define TL_MEM_FM_LINK_STAT2    	0x1D4	//Frame Manager Link Status 2
+#define TL_IO_FM_LINK_STAT2     	0xD4	//Frame Manager Link Status 2
 
-#define TL_MEM_FM_TIMEOUT2      0x1D8   // (W)
+#define TL_MEM_FM_TIMEOUT2      	0x1D8	// (W)
 
-#define TL_MEM_FM_BB_CREDIT0    0x1DC
+#define TL_MEM_FM_BB_CREDIT0    	0x1DC
 
-#define TL_MEM_FM_WWN_HI        0x1E0 //Frame Manager World Wide Name High
-#define TL_IO_FM_WWN_HI         0xE0 //Frame Manager World Wide Name High
+#define TL_MEM_FM_WWN_HI        	0x1E0	//Frame Manager World Wide Name High
+#define TL_IO_FM_WWN_HI         	0xE0	//Frame Manager World Wide Name High
 
-#define TL_MEM_FM_WWN_LO        0x1E4 //Frame Manager World Wide Name LOW
-#define TL_IO_FM_WWN_LO         0xE4 //Frame Manager World Wide Name Low
+#define TL_MEM_FM_WWN_LO        	0x1E4	//Frame Manager World Wide Name LOW
+#define TL_IO_FM_WWN_LO         	0xE4	//Frame Manager World Wide Name Low
 
-#define TL_MEM_FM_RCV_AL_PA     0x1E8 //Frame Manager AL_PA Received register
-#define TL_IO_FM_ALPA           0xE8 //Frame Manager AL_PA Received register
+#define TL_MEM_FM_RCV_AL_PA     	0x1E8	//Frame Manager AL_PA Received register
+#define TL_IO_FM_ALPA           	0xE8	//Frame Manager AL_PA Received register
 
-#define TL_MEM_FM_ED_TOV           0x1CC
+#define TL_MEM_FM_ED_TOV        	0x1CC
 
-#define TL_IO_ROMCTR            0xFA //TL PCI ROM Control Register
-#define TL_IO_PCIMCTR           0xFB //TL PCI Master Control Register
-#define TL_IO_SOFTRST           0xFC //Tachlite Configuration register
-#define TL_MEM_SOFTRST          0x1FC //Tachlite Configuration register
+#define TL_IO_ROMCTR            	0xFA	//TL PCI ROM Control Register
+#define TL_IO_PCIMCTR           	0xFB	//TL PCI Master Control Register
+#define TL_IO_SOFTRST           	0xFC	//Tachlite Configuration register
+#define TL_MEM_SOFTRST          	0x1FC	//Tachlite Configuration register
 
 // completion message types (bit 8 set means Interrupt generated)
 // CM_Type
-#define OUTBOUND_COMPLETION        0
-#define ERROR_IDLE_COMPLETION   0x01
-#define OUT_HI_PRI_COMPLETION   0x01
-#define INBOUND_MFS_COMPLETION  0x02
-#define INBOUND_000_COMPLETION  0x03
-#define INBOUND_SFS_COMPLETION  0x04  // Tachyon & TachLite
-#define ERQ_FROZEN_COMPLETION   0x06  // TachLite
-#define INBOUND_C1_TIMEOUT      0x05
-#define INBOUND_BUSIED_FRAME    0x06
-#define SFS_BUF_WARN            0x07
-#define FCP_FROZEN_COMPLETION   0x07  // TachLite
-#define MFS_BUF_WARN            0x08
-#define IMQ_BUF_WARN            0x09
-#define FRAME_MGR_INTERRUPT     0x0A
-#define READ_STATUS             0x0B
-#define INBOUND_SCSI_DATA_COMPLETION  0x0C
-#define INBOUND_FCP_XCHG_COMPLETION   0x0C  // TachLite
-#define INBOUND_SCSI_DATA_COMMAND     0x0D
-#define BAD_SCSI_FRAME                0x0E
-#define INB_SCSI_STATUS_COMPLETION    0x0F
-#define BUFFER_PROCESSED_COMPLETION   0x11
+
+#define OUTBOUND_COMPLETION     	   0
+#define ERROR_IDLE_COMPLETION   	0x01
+#define OUT_HI_PRI_COMPLETION   	0x01
+#define INBOUND_MFS_COMPLETION  	0x02
+#define INBOUND_000_COMPLETION  	0x03
+#define INBOUND_SFS_COMPLETION  	0x04	// Tachyon & TachLite
+#define ERQ_FROZEN_COMPLETION   	0x06	// TachLite
+#define INBOUND_C1_TIMEOUT      	0x05
+#define INBOUND_BUSIED_FRAME    	0x06
+#define SFS_BUF_WARN            	0x07
+#define FCP_FROZEN_COMPLETION   	0x07	// TachLite
+#define MFS_BUF_WARN            	0x08
+#define IMQ_BUF_WARN            	0x09
+#define FRAME_MGR_INTERRUPT     	0x0A
+#define READ_STATUS             	0x0B
+#define INBOUND_SCSI_DATA_COMPLETION  	0x0C
+#define INBOUND_FCP_XCHG_COMPLETION   	0x0C	// TachLite
+#define INBOUND_SCSI_DATA_COMMAND     	0x0D
+#define BAD_SCSI_FRAME                	0x0E
+#define INB_SCSI_STATUS_COMPLETION    	0x0F
+#define BUFFER_PROCESSED_COMPLETION   	0x11
 
 // FC-AL (Tachyon) Loop Port State Machine defs
 // (loop "Up" states)
-#define MONITORING 0x0
-#define ARBITRATING 0x1
-#define ARBITRAT_WON 0x2
-#define OPEN 0x3
-#define OPENED 0x4
-#define XMITTD_CLOSE 0x5
-#define RCVD_CLOSE 0x6
-#define TRANSFER 0x7
+#define MONITORING			0x0
+#define ARBITRATING			0x1
+#define ARBITRAT_WON			0x2
+#define OPEN				0x3
+#define OPENED				0x4
+#define XMITTD_CLOSE			0x5
+#define RCVD_CLOSE			0x6
+#define TRANSFER			0x7
 
 // (loop "Down" states)
-#define INITIALIZING 0x8
-#define O_I_INIT 0x9
-#define O_I_PROTOCOL 0xa
-#define O_I_LIP_RCVD 0xb
-#define HOST_CONTROL 0xc
-#define LOOP_FAIL 0xd
+#define INITIALIZING			0x8
+#define O_I_INIT			0x9
+#define O_I_PROTOCOL			0xa
+#define O_I_LIP_RCVD			0xb
+#define HOST_CONTROL			0xc
+#define LOOP_FAIL			0xd
 // (no 0xe)
-#define OLD_PORT 0xf
+#define OLD_PORT			0xf
 
 
 
 #define TACHYON_CHIP_INC
 #endif
-#endif /* CPQFCTSCHIP_H */
+#endif				/* CPQFCTSCHIP_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/cpqfcTScontrol.c linux-2.4.21-pre6/drivers/scsi/cpqfcTScontrol.c
--- linux-2.4.20/drivers/scsi/cpqfcTScontrol.c	2001-10-25 20:53:50.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/cpqfcTScontrol.c	2003-03-26 23:49:03.000000000 +0000
@@ -28,46 +28,40 @@
    Hewlitt Packard Manual Part Number 5968-1083E.
 */
 
-#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
-
 #include <linux/blk.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
-#include <linux/ioport.h>  // request_region() prototype
+#include <linux/ioport.h>	// request_region() prototype
 #include <linux/sched.h>
-#include <linux/slab.h>  // need "kfree" for ext. S/G pages
+#include <linux/slab.h>		// need "kfree" for ext. S/G pages
 #include <linux/types.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/unistd.h>
-#include <asm/io.h>  // struct pt_regs for IRQ handler & Port I/O
+#include <asm/io.h>		// struct pt_regs for IRQ handler & Port I/O
 #include <asm/irq.h>
 #include <linux/spinlock.h>
 
 #include "sd.h"
-#include "hosts.h"   // Scsi_Host definition for INT handler
+#include "hosts.h"		// Scsi_Host definition for INT handler
 #include "cpqfcTSchip.h"
 #include "cpqfcTSstructs.h"
 
 //#define IMQ_DEBUG 1
 
 static void fcParseLinkStatusCounters(TACHYON * fcChip);
-static void CpqTsGetSFQEntry(TACHYON * fcChip, 
-	      USHORT pi, ULONG * buffr, BOOLEAN UpdateChip); 
+static void CpqTsGetSFQEntry(TACHYON * fcChip, u16 pi, u32 * buffr, u8 UpdateChip);
 
-static void 
-cpqfc_free_dma_consistent(CPQFCHBA *cpqfcHBAdata)
+static void cpqfc_free_dma_consistent(CPQFCHBA * cpqfcHBAdata)
 {
-  	// free up the primary EXCHANGES struct and Link Q
+	// free up the primary EXCHANGES struct and Link Q
 	PTACHYON fcChip = &cpqfcHBAdata->fcChip;
 
 	if (fcChip->Exchanges != NULL)
-		pci_free_consistent(cpqfcHBAdata->PciDev, sizeof(FC_EXCHANGES),
-			fcChip->Exchanges, fcChip->exch_dma_handle);
+		pci_free_consistent(cpqfcHBAdata->PciDev, sizeof(FC_EXCHANGES), fcChip->Exchanges, fcChip->exch_dma_handle);
 	fcChip->Exchanges = NULL;
 	if (cpqfcHBAdata->fcLQ != NULL)
-		pci_free_consistent(cpqfcHBAdata->PciDev, sizeof(FC_LINK_QUE),
-			cpqfcHBAdata->fcLQ, cpqfcHBAdata->fcLQ_dma_handle);
+		pci_free_consistent(cpqfcHBAdata->PciDev, sizeof(FC_LINK_QUE), cpqfcHBAdata->fcLQ, cpqfcHBAdata->fcLQ_dma_handle);
 	cpqfcHBAdata->fcLQ = NULL;
 }
 
@@ -76,281 +70,236 @@
 // in non-symbolic (i.e. memory dump) debugging
 // opcode defines placement of Queues (e.g. local/external RAM)
 
-int CpqTsCreateTachLiteQues( void* pHBA, int opcode)
+int CpqTsCreateTachLiteQues(void *pHBA, int opcode)
 {
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+	CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *) pHBA;
+	PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+
+	int iStatus = 0;
+	unsigned long ulAddr;
+	dma_addr_t ERQdma, IMQdma, SPQdma, SESTdma;
+	int i;
+
+	// NOTE! fcMemManager() will return system virtual addresses.
+	// System (kernel) virtual addresses, though non-paged, still
+	// aren't physical addresses.  Convert to PHYSICAL_ADDRESS for Tachyon's
+	// DMA use.
+	ENTER("CreateTachLiteQues");
+
+
+	// Allocate primary EXCHANGES array...
+	fcChip->Exchanges = NULL;
+	cpqfcHBAdata->fcLQ = NULL;
+
+	printk("Allocating %u for %u Exchanges ", (u32) sizeof(FC_EXCHANGES), TACH_MAX_XID);
+	fcChip->Exchanges = pci_alloc_consistent(cpqfcHBAdata->PciDev, sizeof(FC_EXCHANGES), &fcChip->exch_dma_handle);
+	printk("@ %p\n", fcChip->Exchanges);
 
-  int iStatus=0;
-  unsigned long ulAddr;
-  dma_addr_t ERQdma, IMQdma, SPQdma, SESTdma;
-  int i;
-
-  // NOTE! fcMemManager() will return system virtual addresses.
-  // System (kernel) virtual addresses, though non-paged, still
-  // aren't physical addresses.  Convert to PHYSICAL_ADDRESS for Tachyon's
-  // DMA use.
-  ENTER("CreateTachLiteQues");
-
-
-  // Allocate primary EXCHANGES array...
-  fcChip->Exchanges = NULL;
-  cpqfcHBAdata->fcLQ = NULL;
-  
-  printk("Allocating %u for %u Exchanges ", 
-	  (ULONG)sizeof(FC_EXCHANGES), TACH_MAX_XID);
-  fcChip->Exchanges = pci_alloc_consistent(cpqfcHBAdata->PciDev, 
-			sizeof(FC_EXCHANGES), &fcChip->exch_dma_handle);
-  printk("@ %p\n", fcChip->Exchanges);
-
-  if( fcChip->Exchanges == NULL ) // fatal error!!
-  {
-    printk("pci_alloc_consistent failure on Exchanges: fatal error\n");
-    return -1;
-  }
-  // zero out the entire EXCHANGE space
-  memset( fcChip->Exchanges, 0, sizeof( FC_EXCHANGES));  
-
-
-  printk("Allocating %u for LinkQ ", (ULONG)sizeof(FC_LINK_QUE));
-  cpqfcHBAdata->fcLQ = pci_alloc_consistent(cpqfcHBAdata->PciDev,
-				 sizeof( FC_LINK_QUE), &cpqfcHBAdata->fcLQ_dma_handle);
-  printk("@ %p (%u elements)\n", cpqfcHBAdata->fcLQ, FC_LINKQ_DEPTH);
-  memset( cpqfcHBAdata->fcLQ, 0, sizeof( FC_LINK_QUE));
-
-  if( cpqfcHBAdata->fcLQ == NULL ) // fatal error!!
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk("pci_alloc_consistent() failure on fc Link Que: fatal error\n");
-    return -1;
-  }
-  // zero out the entire EXCHANGE space
-  memset( cpqfcHBAdata->fcLQ, 0, sizeof( FC_LINK_QUE));  
-  
-  // Verify that basic Tach I/O registers are not NULL  
-  if( !fcChip->Registers.ReMapMemBase )
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk("HBA base address NULL: fatal error\n");
-    return -1;
-  }
-
-
-  // Initialize the fcMemManager memory pairs (stores allocated/aligned
-  // pairs for future freeing)
-  memset( cpqfcHBAdata->dynamic_mem, 0, sizeof(cpqfcHBAdata->dynamic_mem));
-  
-
-  // Allocate Tach's Exchange Request Queue (each ERQ entry 32 bytes)
-  
-  fcChip->ERQ = fcMemManager( cpqfcHBAdata->PciDev, 
-			&cpqfcHBAdata->dynamic_mem[0], 
-			sizeof( TachLiteERQ ), 32*(ERQ_LEN), 0L, &ERQdma);
-  if( !fcChip->ERQ )
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk("pci_alloc_consistent/alignment failure on ERQ: fatal error\n");
-    return -1;
-  }
-  fcChip->ERQ->length = ERQ_LEN-1;
-  ulAddr = (ULONG) ERQdma; 
+	if (fcChip->Exchanges == NULL)	// fatal error!!
+	{
+		printk("pci_alloc_consistent failure on Exchanges: fatal error\n");
+		return -1;
+	}
+	// zero out the entire EXCHANGE space
+	memset(fcChip->Exchanges, 0, sizeof(FC_EXCHANGES));
+
+
+	printk("Allocating %u for LinkQ ", (u32) sizeof(FC_LINK_QUE));
+	cpqfcHBAdata->fcLQ = pci_alloc_consistent(cpqfcHBAdata->PciDev, sizeof(FC_LINK_QUE), &cpqfcHBAdata->fcLQ_dma_handle);
+	printk("@ %p (%u elements)\n", cpqfcHBAdata->fcLQ, FC_LINKQ_DEPTH);
+	memset(cpqfcHBAdata->fcLQ, 0, sizeof(FC_LINK_QUE));
+
+	if (cpqfcHBAdata->fcLQ == NULL)	// fatal error!!
+	{
+		cpqfc_free_dma_consistent(cpqfcHBAdata);
+		printk("pci_alloc_consistent() failure on fc Link Que: fatal error\n");
+		return -1;
+	}
+	// zero out the entire EXCHANGE space
+	memset(cpqfcHBAdata->fcLQ, 0, sizeof(FC_LINK_QUE));
+
+	// Verify that basic Tach I/O registers are not NULL  
+	if (!fcChip->Registers.ReMapMemBase) {
+		cpqfc_free_dma_consistent(cpqfcHBAdata);
+		printk("HBA base address NULL: fatal error\n");
+		return -1;
+	}
+
+	// Initialize the fcMemManager memory pairs (stores allocated/aligned
+	// pairs for future freeing)
+	memset(cpqfcHBAdata->dynamic_mem, 0, sizeof(cpqfcHBAdata->dynamic_mem));
+
+
+	// Allocate Tach's Exchange Request Queue (each ERQ entry 32 bytes)
+
+	fcChip->ERQ = fcMemManager(cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0], sizeof(TachLiteERQ), 32 * (ERQ_LEN), 0L, &ERQdma);
+	if (!fcChip->ERQ) {
+		cpqfc_free_dma_consistent(cpqfcHBAdata);
+		printk("pci_alloc_consistent/alignment failure on ERQ: fatal error\n");
+		return -1;
+	}
+	fcChip->ERQ->length = ERQ_LEN - 1;
+	ulAddr = (u32) ERQdma;
 #if BITS_PER_LONG > 32
-  if( (ulAddr >> 32) )
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk(" FATAL! ERQ ptr %p exceeds Tachyon's 32-bit register size\n",
-		    (void*)ulAddr);
-    return -1;  // failed
-  }
+	if ((ulAddr >> 32)) {
+		cpqfc_free_dma_consistent(cpqfcHBAdata);
+		printk(" FATAL! ERQ ptr %p exceeds Tachyon's 32-bit register size\n", (void *) ulAddr);
+		return -1;	// failed
+	}
 #endif
-  fcChip->ERQ->base = (ULONG)ulAddr;  // copy for quick reference
+	fcChip->ERQ->base = (u32) ulAddr;	// copy for quick reference
 
 
-  // Allocate Tach's Inbound Message Queue (32 bytes per entry)
-  
-  fcChip->IMQ = fcMemManager( cpqfcHBAdata->PciDev, 
-		  &cpqfcHBAdata->dynamic_mem[0],
-		  sizeof( TachyonIMQ ), 32*(IMQ_LEN), 0L, &IMQdma );
-  if( !fcChip->IMQ )
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk("pci_alloc_consistent/alignment failure on IMQ: fatal error\n");
-    return -1;
-  }
-  fcChip->IMQ->length = IMQ_LEN-1;
+	// Allocate Tach's Inbound Message Queue (32 bytes per entry)
 
-  ulAddr = IMQdma;
+	fcChip->IMQ = fcMemManager(cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0], sizeof(TachyonIMQ), 32 * (IMQ_LEN), 0L, &IMQdma);
+	if (!fcChip->IMQ) {
+		cpqfc_free_dma_consistent(cpqfcHBAdata);
+		printk("pci_alloc_consistent/alignment failure on IMQ: fatal error\n");
+		return -1;
+	}
+	fcChip->IMQ->length = IMQ_LEN - 1;
+
+	ulAddr = IMQdma;
 #if BITS_PER_LONG > 32
-  if( (ulAddr >> 32) )
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk(" FATAL! IMQ ptr %p exceeds Tachyon's 32-bit register size\n",
-		    (void*)ulAddr);
-    return -1;  // failed
-  }
+	if ((ulAddr >> 32)) {
+		cpqfc_free_dma_consistent(cpqfcHBAdata);
+		printk(" FATAL! IMQ ptr %p exceeds Tachyon's 32-bit register size\n", (void *) ulAddr);
+		return -1;	// failed
+	}
 #endif
-  fcChip->IMQ->base = (ULONG)ulAddr;  // copy for quick reference
+	fcChip->IMQ->base = (u32) ulAddr;	// copy for quick reference
 
 
-  // Allocate Tach's  Single Frame Queue (64 bytes per entry)
-  fcChip->SFQ = fcMemManager( cpqfcHBAdata->PciDev, 
-		  &cpqfcHBAdata->dynamic_mem[0],
-		  sizeof( TachLiteSFQ ), 64*(SFQ_LEN),0L, &SPQdma );
-  if( !fcChip->SFQ )
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk("pci_alloc_consistent/alignment failure on SFQ: fatal error\n");
-    return -1;
-  }
-  fcChip->SFQ->length = SFQ_LEN-1;      // i.e. Que length [# entries -
-                                       // min. 32; max.  4096 (0xffff)]
-  
-  ulAddr = SPQdma;
+	// Allocate Tach's  Single Frame Queue (64 bytes per entry)
+	fcChip->SFQ = fcMemManager(cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0], sizeof(TachLiteSFQ), 64 * (SFQ_LEN), 0L, &SPQdma);
+	if (!fcChip->SFQ) {
+		cpqfc_free_dma_consistent(cpqfcHBAdata);
+		printk("pci_alloc_consistent/alignment failure on SFQ: fatal error\n");
+		return -1;
+	}
+	fcChip->SFQ->length = SFQ_LEN - 1;	// i.e. Que length [# entries -
+	// min. 32; max.  4096 (0xffff)]
+
+	ulAddr = SPQdma;
 #if BITS_PER_LONG > 32
-  if( (ulAddr >> 32) )
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk(" FATAL! SFQ ptr %p exceeds Tachyon's 32-bit register size\n",
-		    (void*)ulAddr);
-    return -1;  // failed
-  }
+	if ((ulAddr >> 32)) {
+		cpqfc_free_dma_consistent(cpqfcHBAdata);
+		printk(" FATAL! SFQ ptr %p exceeds Tachyon's 32-bit register size\n", (void *) ulAddr);
+		return -1;	// failed
+	}
 #endif
-  fcChip->SFQ->base = (ULONG)ulAddr;  // copy for quick reference
+	fcChip->SFQ->base = (u32) ulAddr;	// copy for quick reference
 
 
-  // Allocate SCSI Exchange State Table; aligned nearest @sizeof
-  // power-of-2 boundary
-  // LIVE DANGEROUSLY!  Assume the boundary for SEST mem will
-  // be on physical page (e.g. 4k) boundary.
-  printk("Allocating %u for TachSEST for %u Exchanges\n", 
-		 (ULONG)sizeof(TachSEST), TACH_SEST_LEN);
-  fcChip->SEST = fcMemManager( cpqfcHBAdata->PciDev,
-		  &cpqfcHBAdata->dynamic_mem[0],
-		  sizeof(TachSEST),  4, 0L, &SESTdma );
-//		  sizeof(TachSEST),  64*TACH_SEST_LEN, 0L );
-  if( !fcChip->SEST )
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk("pci_alloc_consistent/alignment failure on SEST: fatal error\n");
-    return -1;
-  }
+	// Allocate SCSI Exchange State Table; aligned nearest @sizeof
+	// power-of-2 boundary
+	// LIVE DANGEROUSLY!  Assume the boundary for SEST mem will
+	// be on physical page (e.g. 4k) boundary.
+	printk("Allocating %u for TachSEST for %u Exchanges\n", (u32) sizeof(TachSEST), TACH_SEST_LEN);
+	fcChip->SEST = fcMemManager(cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0], sizeof(TachSEST), 4, 0L, &SESTdma);
+//                sizeof(TachSEST),  64*TACH_SEST_LEN, 0L );
+	if (!fcChip->SEST) {
+		cpqfc_free_dma_consistent(cpqfcHBAdata);
+		printk("pci_alloc_consistent/alignment failure on SEST: fatal error\n");
+		return -1;
+	}
 
-  for( i=0; i < TACH_SEST_LEN; i++)  // for each exchange
-      fcChip->SEST->sgPages[i] = NULL;
+	for (i = 0; i < TACH_SEST_LEN; i++)	// for each exchange
+		fcChip->SEST->sgPages[i] = NULL;
 
-  fcChip->SEST->length = TACH_SEST_LEN;  // e.g. DON'T subtract one 
-                                       // (TL/TS UG, pg 153)
+	fcChip->SEST->length = TACH_SEST_LEN;	// e.g. DON'T subtract one 
+	// (TL/TS UG, pg 153)
 
-  ulAddr = SESTdma; 
+	ulAddr = SESTdma;
 #if BITS_PER_LONG > 32
-  if( (ulAddr >> 32) )
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk(" FATAL! SFQ ptr %p exceeds Tachyon's 32-bit register size\n",
-		    (void*)ulAddr);
-    return -1;  // failed
-  }
+	if ((ulAddr >> 32)) {
+		cpqfc_free_dma_consistent(cpqfcHBAdata);
+		printk(" FATAL! SFQ ptr %p exceeds Tachyon's 32-bit register size\n", (void *) ulAddr);
+		return -1;	// failed
+	}
 #endif
-  fcChip->SEST->base = (ULONG)ulAddr;  // copy for quick reference
+	fcChip->SEST->base = (u32) ulAddr;	// copy for quick reference
+
+
+	// Now that structures are defined,
+	// fill in Tachyon chip registers...
+
+	// EEEEEEEE  EXCHANGE REQUEST QUEUE
 
+	writel(fcChip->ERQ->base, (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_BASE));
 
-			      // Now that structures are defined,
-			      // fill in Tachyon chip registers...
+	writel(fcChip->ERQ->length, (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_LENGTH));
 
-			      // EEEEEEEE  EXCHANGE REQUEST QUEUE
 
-  writel( fcChip->ERQ->base, 
-    (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_BASE));
-      
-  writel( fcChip->ERQ->length,
-    (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_LENGTH));
-     
+	fcChip->ERQ->producerIndex = 0L;
+	writel(fcChip->ERQ->producerIndex, (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_PRODUCER_INDEX));
 
-  fcChip->ERQ->producerIndex = 0L;
-  writel( fcChip->ERQ->producerIndex,
-    (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_PRODUCER_INDEX));
-      
 
-		// NOTE! write consumer index last, since the write
-		// causes Tachyon to process the other registers
+	// NOTE! write consumer index last, since the write
+	// causes Tachyon to process the other registers
 
-  ulAddr = ((unsigned long)&fcChip->ERQ->consumerIndex - 
-		(unsigned long)fcChip->ERQ) + (unsigned long) ERQdma;
+	ulAddr = ((unsigned long) &fcChip->ERQ->consumerIndex - (unsigned long) fcChip->ERQ) + (unsigned long) ERQdma;
 
-  // NOTE! Tachyon DMAs to the ERQ consumer Index host
-		// address; must be correctly aligned
-  writel( (ULONG)ulAddr,
-    (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_CONSUMER_INDEX_ADR));
+	// NOTE! Tachyon DMAs to the ERQ consumer Index host
+	// address; must be correctly aligned
+	writel((u32) ulAddr, (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_CONSUMER_INDEX_ADR));
 
 
 
-				 // IIIIIIIIIIIII  INBOUND MESSAGE QUEUE
-				 // Tell Tachyon where the Que starts
+	// IIIIIIIIIIIII  INBOUND MESSAGE QUEUE
+	// Tell Tachyon where the Que starts
 
-  // set the Host's pointer for Tachyon to access
+	// set the Host's pointer for Tachyon to access
 
-  printk("  cpqfcTS: writing IMQ BASE %Xh  ", fcChip->IMQ->base );
-  writel( fcChip->IMQ->base, 
-    (fcChip->Registers.ReMapMemBase + IMQ_BASE));
+	printk("  cpqfcTS: writing IMQ BASE %Xh  ", fcChip->IMQ->base);
+	writel(fcChip->IMQ->base, (fcChip->Registers.ReMapMemBase + IMQ_BASE));
 
-  writel( fcChip->IMQ->length,
-    (fcChip->Registers.ReMapMemBase + IMQ_LENGTH));
+	writel(fcChip->IMQ->length, (fcChip->Registers.ReMapMemBase + IMQ_LENGTH));
 
-  writel( fcChip->IMQ->consumerIndex,
-    (fcChip->Registers.ReMapMemBase + IMQ_CONSUMER_INDEX));
+	writel(fcChip->IMQ->consumerIndex, (fcChip->Registers.ReMapMemBase + IMQ_CONSUMER_INDEX));
 
 
-		// NOTE: TachLite DMAs to the producerIndex host address
-		// must be correctly aligned with address bits 1-0 cleared
-    // Writing the BASE register clears the PI register, so write it last
-  ulAddr = ((unsigned long)&fcChip->IMQ->producerIndex - 
-		(unsigned long)fcChip->IMQ) + (unsigned long) IMQdma;
+	// NOTE: TachLite DMAs to the producerIndex host address
+	// must be correctly aligned with address bits 1-0 cleared
+	// Writing the BASE register clears the PI register, so write it last
+	ulAddr = ((unsigned long) &fcChip->IMQ->producerIndex - (unsigned long) fcChip->IMQ) + (unsigned long) IMQdma;
 
 #if BITS_PER_LONG > 32
-  if( (ulAddr >> 32) )
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk(" FATAL! IMQ ptr %p exceeds Tachyon's 32-bit register size\n",
-		    (void*)ulAddr);
-    return -1;  // failed
-  }
+	if ((ulAddr >> 32)) {
+		cpqfc_free_dma_consistent(cpqfcHBAdata);
+		printk(" FATAL! IMQ ptr %p exceeds Tachyon's 32-bit register size\n", (void *) ulAddr);
+		return -1;	// failed
+	}
 #endif
 //#if DBG
-  printk("  PI %Xh\n", (ULONG)ulAddr );
+	printk("  PI %Xh\n", (u32) ulAddr);
 //#endif
-  writel( (ULONG)ulAddr, 
-    (fcChip->Registers.ReMapMemBase + IMQ_PRODUCER_INDEX));
+	writel((u32) ulAddr, (fcChip->Registers.ReMapMemBase + IMQ_PRODUCER_INDEX));
+
 
 
+	// SSSSSSSSSSSSSSS SINGLE FRAME SEQUENCE
+	// Tell TachLite where the Que starts
 
-				 // SSSSSSSSSSSSSSS SINGLE FRAME SEQUENCE
-				 // Tell TachLite where the Que starts
+	writel(fcChip->SFQ->base, (fcChip->Registers.ReMapMemBase + TL_MEM_SFQ_BASE));
 
-  writel( fcChip->SFQ->base, 
-    (fcChip->Registers.ReMapMemBase + TL_MEM_SFQ_BASE));
+	writel(fcChip->SFQ->length, (fcChip->Registers.ReMapMemBase + TL_MEM_SFQ_LENGTH));
 
-  writel( fcChip->SFQ->length,
-    (fcChip->Registers.ReMapMemBase + TL_MEM_SFQ_LENGTH));
 
+	// tell TachLite where SEST table is & how long
+	writel(fcChip->SEST->base, (fcChip->Registers.ReMapMemBase + TL_MEM_SEST_BASE));
 
-         // tell TachLite where SEST table is & how long
-  writel( fcChip->SEST->base,
-    (fcChip->Registers.ReMapMemBase + TL_MEM_SEST_BASE));
+	printk("  cpqfcTS: SEST %p(virt): Wrote base %Xh @ %p\n", fcChip->SEST, fcChip->SEST->base, fcChip->Registers.ReMapMemBase + TL_MEM_SEST_BASE);
 
-  printk("  cpqfcTS: SEST %p(virt): Wrote base %Xh @ %p\n",
-    fcChip->SEST, fcChip->SEST->base, 
-    fcChip->Registers.ReMapMemBase + TL_MEM_SEST_BASE);
+	writel(fcChip->SEST->length, (fcChip->Registers.ReMapMemBase + TL_MEM_SEST_LENGTH));
 
-  writel( fcChip->SEST->length,
-    (fcChip->Registers.ReMapMemBase + TL_MEM_SEST_LENGTH));
-      
-  writel( (TL_EXT_SG_PAGE_COUNT-1),
-    (fcChip->Registers.ReMapMemBase + TL_MEM_SEST_SG_PAGE));
+	writel((TL_EXT_SG_PAGE_COUNT - 1), (fcChip->Registers.ReMapMemBase + TL_MEM_SEST_SG_PAGE));
 
 
-  LEAVE("CreateTachLiteQues");
+	LEAVE("CreateTachLiteQues");
 
-  return iStatus;
+	return iStatus;
 }
 
 
@@ -361,83 +310,79 @@
 
 int CpqTsResetTachLite(void *pHBA, int type)
 {
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  ULONG ulBuff, i;
-  int ret_status=0; // def. success
-
-  ENTER("ResetTach");
-  
-  switch(type)
-  {
-
-    case CLEAR_FCPORTS:
-
-      // in case he was running previously, mask Tach's interrupt
-      writeb( 0, (fcChip->Registers.ReMapMemBase + IINTEN));
-      
-     // de-allocate mem for any Logged in ports
-      // (e.g., our module is unloading)
-      // search the forward linked list, de-allocating
-      // the memory we allocated when the port was initially logged in
-      {
-        PFC_LOGGEDIN_PORT pLoggedInPort = fcChip->fcPorts.pNextPort;
-        PFC_LOGGEDIN_PORT ptr;
+	CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *) pHBA;
+	PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+	u32 ulBuff, i;
+	int ret_status = 0;	// def. success
+
+	ENTER("ResetTach");
+
+	switch (type) {
+
+	case CLEAR_FCPORTS:
+
+		// in case he was running previously, mask Tach's interrupt
+		writeb(0, (fcChip->Registers.ReMapMemBase + IINTEN));
+
+		// de-allocate mem for any Logged in ports
+		// (e.g., our module is unloading)
+		// search the forward linked list, de-allocating
+		// the memory we allocated when the port was initially logged in
+		{
+			PFC_LOGGEDIN_PORT pLoggedInPort = fcChip->fcPorts.pNextPort;
+			PFC_LOGGEDIN_PORT ptr;
 //        printk("checking for allocated LoggedInPorts...\n");
-			
-        while( pLoggedInPort )
-        {
-          ptr = pLoggedInPort;
-          pLoggedInPort = ptr->pNextPort;
-//	  printk("kfree(%p) on FC LoggedInPort port_id 0x%06lX\n",
-//			  ptr, ptr->port_id);
-          kfree( ptr );
-        }
-      }
-      // (continue resetting hardware...)
-
-    case 1:                   // RESTART Tachyon (power-up state)
-
-      // in case he was running previously, mask Tach's interrupt
-      writeb( 0, (fcChip->Registers.ReMapMemBase + IINTEN));
-			      // turn OFF laser (NOTE: laser is turned
-                              // off during reset, because GPIO4 is cleared
-                              // to 0 by reset action - see TLUM, sec 7.22)
-                              // However, CPQ 64-bit HBAs have a "health
-                              // circuit" which keeps laser ON for a brief
-                              // period after it is turned off ( < 1s)
-      
-      fcChip->LaserControl( fcChip->Registers.ReMapMemBase, 0);
-  
-
-
-            // soft reset timing constraints require:
-            //   1. set RST to 1
-            //   2. read SOFTRST register 
-            //      (128 times per R. Callison code)
-            //   3. clear PCI ints
-            //   4. clear RST to 0
-      writel( 0xff000001L,
-        (fcChip->Registers.ReMapMemBase + TL_MEM_SOFTRST));
-        
-      for( i=0; i<128; i++)
-        ulBuff = readl( fcChip->Registers.ReMapMemBase + TL_MEM_SOFTRST);
-
-        // clear the soft reset
-      for( i=0; i<8; i++)
-  	writel( 0, (fcChip->Registers.ReMapMemBase + TL_MEM_SOFTRST));
-
-               
-
-			       // clear out our copy of Tach regs,
-			       // because they must be invalid now,
-			       // since TachLite reset all his regs.
-      CpqTsDestroyTachLiteQues(cpqfcHBAdata,0); // remove Host-based Que structs
-      cpqfcTSClearLinkStatusCounters(fcChip);  // clear our s/w accumulators
-                               // lower bits give GBIC info
-      fcChip->Registers.TYstatus.value = 
-	              readl( fcChip->Registers.TYstatus.address );
-      break;
+
+			while (pLoggedInPort) {
+				ptr = pLoggedInPort;
+				pLoggedInPort = ptr->pNextPort;
+//        printk("kfree(%p) on FC LoggedInPort port_id 0x%06lX\n",
+//                        ptr, ptr->port_id);
+				kfree(ptr);
+			}
+		}
+		// (continue resetting hardware...)
+
+	case 1:		// RESTART Tachyon (power-up state)
+
+		// in case he was running previously, mask Tach's interrupt
+		writeb(0, (fcChip->Registers.ReMapMemBase + IINTEN));
+		// turn OFF laser (NOTE: laser is turned
+		// off during reset, because GPIO4 is cleared
+		// to 0 by reset action - see TLUM, sec 7.22)
+		// However, CPQ 64-bit HBAs have a "health
+		// circuit" which keeps laser ON for a brief
+		// period after it is turned off ( < 1s)
+
+		fcChip->LaserControl(fcChip->Registers.ReMapMemBase, 0);
+
+
+
+		// soft reset timing constraints require:
+		//   1. set RST to 1
+		//   2. read SOFTRST register 
+		//      (128 times per R. Callison code)
+		//   3. clear PCI ints
+		//   4. clear RST to 0
+		writel(0xff000001L, (fcChip->Registers.ReMapMemBase + TL_MEM_SOFTRST));
+
+		for (i = 0; i < 128; i++)
+			ulBuff = readl(fcChip->Registers.ReMapMemBase + TL_MEM_SOFTRST);
+
+		// clear the soft reset
+		for (i = 0; i < 8; i++)
+			writel(0, (fcChip->Registers.ReMapMemBase + TL_MEM_SOFTRST));
+
+
+
+		// clear out our copy of Tach regs,
+		// because they must be invalid now,
+		// since TachLite reset all his regs.
+		CpqTsDestroyTachLiteQues(cpqfcHBAdata, 0);	// remove Host-based Que structs
+		cpqfcTSClearLinkStatusCounters(fcChip);	// clear our s/w accumulators
+		// lower bits give GBIC info
+		fcChip->Registers.TYstatus.value = readl(fcChip->Registers.TYstatus.address);
+		break;
 
 /*
     case 2:                   // freeze SCSI
@@ -447,12 +392,12 @@
 
     break;
 */
-    default:
-      ret_status = -1;  // invalid option passed to RESET function
-      break;
-  }
-  LEAVE("ResetTach");
-  return ret_status;
+	default:
+		ret_status = -1;	// invalid option passed to RESET function
+		break;
+	}
+	LEAVE("ResetTach");
+	return ret_status;
 }
 
 
@@ -461,18 +406,18 @@
 
 
 // 'addrBase' is IOBaseU for both TachLite and (older) Tachyon
-int CpqTsLaserControl( void* addrBase, int opcode )
+int CpqTsLaserControl(void *addrBase, int opcode)
 {
-  ULONG dwBuff;
+	u32 dwBuff;
 
-  dwBuff = readl((addrBase + TL_MEM_TACH_CONTROL) ); // read TL Control reg
-                                                    // (change only bit 4)
-  if( opcode == 1)
-    dwBuff |= ~0xffffffefL; // set - ON
-  else
-    dwBuff &= 0xffffffefL;  // clear - OFF
-  writel( dwBuff, (addrBase + TL_MEM_TACH_CONTROL)); // write TL Control reg
-  return 0;
+	dwBuff = readl((addrBase + TL_MEM_TACH_CONTROL));	// read TL Control reg
+	// (change only bit 4)
+	if (opcode == 1)
+		dwBuff |= ~0xffffffefL;	// set - ON
+	else
+		dwBuff &= 0xffffffefL;	// clear - OFF
+	writel(dwBuff, (addrBase + TL_MEM_TACH_CONTROL));	// write TL Control reg
+	return 0;
 }
 
 
@@ -484,102 +429,93 @@
 //   external loopback (GBIC - no FC loop)
 //   no loopback: L_PORT, external cable from GBIC required
 
-int CpqTsInitializeFrameManager( void *pChip, int opcode)
+int CpqTsInitializeFrameManager(void *pChip, int opcode)
 {
-  PTACHYON fcChip;
-  int iStatus;
-  ULONG wwnLo, wwnHi; // for readback verification
-
-  ENTER("InitializeFrameManager");
-  fcChip = (PTACHYON)pChip;
-  if( !fcChip->Registers.ReMapMemBase )   // undefined controller?
-    return -1;
-
-  // TL/TS UG, pg. 184
-  // 0x0065 = 100ms for RT_TOV
-  // 0x01f5 = 500ms for ED_TOV
-  // 0x07D1 = 2000ms 
-  fcChip->Registers.ed_tov.value = 0x006507D1; 
-  writel( fcChip->Registers.ed_tov.value,
-    (fcChip->Registers.ed_tov.address));
-      
-
-  // Set LP_TOV to the FC-AL2 specified 2 secs.
-  // TL/TS UG, pg. 185
-  writel( 0x07d00010, fcChip->Registers.ReMapMemBase +TL_MEM_FM_TIMEOUT2);
-
-
-  // Now try to read the WWN from the adapter's NVRAM
-  iStatus = CpqTsReadWriteWWN( fcChip, 1); // '1' for READ
-
-  if( iStatus )   // NVRAM read failed?
-  {
-    printk(" WARNING! HBA NVRAM WWN read failed - make alias\n");
-    // make up a WWN.  If NULL or duplicated on loop, FC loop may hang!
-
-
-    fcChip->Registers.wwn_hi = (__u32)jiffies;
-    fcChip->Registers.wwn_hi |= 0x50000000L;
-    fcChip->Registers.wwn_lo = 0x44556677L;
-  }
-
-  
-  writel( fcChip->Registers.wwn_hi, 
-	  fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_HI);
-  
-  writel( fcChip->Registers.wwn_lo, 
-	  fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_LO);
-	  
-
-  // readback for verification:
-  wwnHi = readl( fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_HI ); 
-          
-  wwnLo = readl( fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_LO);
-  // test for correct chip register WRITE/READ
-  DEBUG_PCI( printk("  WWN %08X%08X\n",
-    fcChip->Registers.wwn_hi, fcChip->Registers.wwn_lo ) );
-    
-  if( wwnHi != fcChip->Registers.wwn_hi ||
-      wwnLo != fcChip->Registers.wwn_lo )
-  {
-    printk( "cpqfcTS: WorldWideName register load failed\n");
-    return -1; // FAILED!
-  }
-
-
-
-			// set Frame Manager Initialize command
-  fcChip->Registers.FMcontrol.value = 0x06;
-
-  // Note: for test/debug purposes, we may use "Hard" address,
-  // but we completely support "soft" addressing, including
-  // dynamically changing our address.
-  if( fcChip->Options.intLoopback == 1 )            // internal loopback
-    fcChip->Registers.FMconfig.value = 0x0f002080L;
-  else if( fcChip->Options.extLoopback == 1 )            // internal loopback
-    fcChip->Registers.FMconfig.value = 0x0f004080L;
-  else                  // L_Port
-    fcChip->Registers.FMconfig.value = 0x55000100L; // hard address (55h start)
+	PTACHYON fcChip;
+	int iStatus;
+	u32 wwnLo, wwnHi;	// for readback verification
+
+	ENTER("InitializeFrameManager");
+	fcChip = (PTACHYON) pChip;
+	if (!fcChip->Registers.ReMapMemBase)	// undefined controller?
+		return -1;
+
+	// TL/TS UG, pg. 184
+	// 0x0065 = 100ms for RT_TOV
+	// 0x01f5 = 500ms for ED_TOV
+	// 0x07D1 = 2000ms 
+	fcChip->Registers.ed_tov.value = 0x006507D1;
+	writel(fcChip->Registers.ed_tov.value, (fcChip->Registers.ed_tov.address));
+
+
+	// Set LP_TOV to the FC-AL2 specified 2 secs.
+	// TL/TS UG, pg. 185
+	writel(0x07d00010, fcChip->Registers.ReMapMemBase + TL_MEM_FM_TIMEOUT2);
+
+
+	// Now try to read the WWN from the adapter's NVRAM
+	iStatus = CpqTsReadWriteWWN(fcChip, 1);	// '1' for READ
+
+	if (iStatus)		// NVRAM read failed?
+	{
+		printk(" WARNING! HBA NVRAM WWN read failed - make alias\n");
+		// make up a WWN.  If NULL or duplicated on loop, FC loop may hang!
+
+
+		fcChip->Registers.wwn_hi = (__u32) jiffies;
+		fcChip->Registers.wwn_hi |= 0x50000000L;
+		fcChip->Registers.wwn_lo = 0x44556677L;
+	}
+
+
+	writel(fcChip->Registers.wwn_hi, fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_HI);
+
+	writel(fcChip->Registers.wwn_lo, fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_LO);
+
+
+	// readback for verification:
+	wwnHi = readl(fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_HI);
+
+	wwnLo = readl(fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_LO);
+	// test for correct chip register WRITE/READ
+	DEBUG_PCI(printk("  WWN %08X%08X\n", fcChip->Registers.wwn_hi, fcChip->Registers.wwn_lo));
+
+	if (wwnHi != fcChip->Registers.wwn_hi || wwnLo != fcChip->Registers.wwn_lo) {
+		printk("cpqfcTS: WorldWideName register load failed\n");
+		return -1;	// FAILED!
+	}
+
+
+	// set Frame Manager Initialize command
+	fcChip->Registers.FMcontrol.value = 0x06;
+
+	// Note: for test/debug purposes, we may use "Hard" address,
+	// but we completely support "soft" addressing, including
+	// dynamically changing our address.
+	if (fcChip->Options.intLoopback == 1)	// internal loopback
+		fcChip->Registers.FMconfig.value = 0x0f002080L;
+	else if (fcChip->Options.extLoopback == 1)	// internal loopback
+		fcChip->Registers.FMconfig.value = 0x0f004080L;
+	else			// L_Port
+		fcChip->Registers.FMconfig.value = 0x55000100L;	// hard address (55h start)
 //    fcChip->Registers.FMconfig.value = 0x01000080L; // soft address (can't pick)
 //    fcChip->Registers.FMconfig.value = 0x55000100L; // hard address (55h start)
-		
-  // write config to FM
 
-  if( !fcChip->Options.intLoopback && !fcChip->Options.extLoopback )
-                               // (also need LASER for real LOOP)
-    fcChip->LaserControl( fcChip->Registers.ReMapMemBase, 1); // turn on LASER
-
-  writel( fcChip->Registers.FMconfig.value,
-    fcChip->Registers.FMconfig.address);
-    
-
-			       // issue INITIALIZE command to FM - ACTION!
-  writel( fcChip->Registers.FMcontrol.value,
-    fcChip->Registers.FMcontrol.address);
-    
-  LEAVE("InitializeFrameManager");
-  
-  return 0;
+	// write config to FM
+
+	if (!fcChip->Options.intLoopback && !fcChip->Options.extLoopback)
+		// (also need LASER for real LOOP)
+		fcChip->LaserControl(fcChip->Registers.ReMapMemBase, 1);	// turn on LASER
+
+	writel(fcChip->Registers.FMconfig.value, fcChip->Registers.FMconfig.address);
+
+
+	// issue INITIALIZE command to FM - ACTION!
+	writel(fcChip->Registers.FMcontrol.value, fcChip->Registers.FMcontrol.address);
+
+	LEAVE("InitializeFrameManager");
+
+	return 0;
 }
 
 
@@ -588,102 +524,94 @@
 
 // This "look ahead" function examines the IMQ for occurence of
 // "type".  Returns 1 if found, 0 if not.
-static int PeekIMQEntry( PTACHYON fcChip, ULONG type)
+static int PeekIMQEntry(PTACHYON fcChip, u32 type)
 {
-  ULONG CI = fcChip->IMQ->consumerIndex;
-  ULONG PI = fcChip->IMQ->producerIndex; // snapshot of IMQ indexes
-  
-  while( CI != PI )
-  {                             // proceed with search
-    if( (++CI) >= IMQ_LEN ) CI = 0; // rollover check
-    
-    switch( type )
-    {
-      case ELS_LILP_FRAME:
-      {
-      // first, we need to find an Inbound Completion message,
-      // If we find it, check the incoming frame payload (1st word)
-      // for LILP frame
-        if( (fcChip->IMQ->QEntry[CI].type & 0x1FF) == 0x104 )
-        { 
-          TachFCHDR_GCMND* fchs;
-          ULONG ulFibreFrame[2048/4];  // max DWORDS in incoming FC Frame
-	  USHORT SFQpi = (USHORT)(fcChip->IMQ->QEntry[CI].word[0] & 0x0fffL);
-
-	  CpqTsGetSFQEntry( fcChip,
-            SFQpi,        // SFQ producer ndx         
-	    ulFibreFrame, // contiguous dest. buffer
-	    FALSE);       // DON'T update chip--this is a "lookahead"
-          
-	  fchs = (TachFCHDR_GCMND*)&ulFibreFrame;
-          if( fchs->pl[0] == ELS_LILP_FRAME)
-	  {
-            return 1; // found the LILP frame!
-	  }
-	  else
-	  {
-	    // keep looking...
-	  }
-	}  
-      }
-      break;
+	u32 CI = fcChip->IMQ->consumerIndex;
+	u32 PI = fcChip->IMQ->producerIndex;	// snapshot of IMQ indexes
 
-      case OUTBOUND_COMPLETION:
-        if( (fcChip->IMQ->QEntry[CI].type & 0x1FF) == 0x00 )
-	{
+	while (CI != PI) {	// proceed with search
+		if ((++CI) >= IMQ_LEN)
+			CI = 0;	// rollover check
+
+		switch (type) {
+		case ELS_LILP_FRAME:
+			{
+				// first, we need to find an Inbound Completion message,
+				// If we find it, check the incoming frame payload (1st word)
+				// for LILP frame
+				if ((fcChip->IMQ->QEntry[CI].type & 0x1FF) == 0x104) {
+					TachFCHDR_GCMND *fchs;
+					u32 ulFibreFrame[2048 / 4];	// max DWORDS in incoming FC Frame
+					u16 SFQpi = (u16) (fcChip->IMQ->QEntry[CI].word[0] & 0x0fffL);
+
+					CpqTsGetSFQEntry(fcChip, SFQpi,	// SFQ producer ndx         
+							 ulFibreFrame,	// contiguous dest. buffer
+							 FALSE);	// DON'T update chip--this is a "lookahead"
+
+					fchs = (TachFCHDR_GCMND *) & ulFibreFrame;
+					if (fchs->pl[0] == ELS_LILP_FRAME) {
+						return 1;	// found the LILP frame!
+					} else {
+						// keep looking...
+					}
+				}
+			}
+			break;
+
+		case OUTBOUND_COMPLETION:
+			if ((fcChip->IMQ->QEntry[CI].type & 0x1FF) == 0x00) {
+
+				// any OCM errors?
+				if (fcChip->IMQ->QEntry[CI].word[2] & 0x7a000000L)
+					return 1;	// found OCM error
+			}
+			break;
 
-          // any OCM errors?
-          if( fcChip->IMQ->QEntry[CI].word[2] & 0x7a000000L )
-            return 1;   	    // found OCM error
-	}
-      break;
 
 
-      
-      default:
-      break;
-    }
-  }
-  return 0; // failed to find "type"
+		default:
+			break;
+		}
+	}
+	return 0;		// failed to find "type"
 }
 
-			
-static void SetTachTOV( CPQFCHBA* cpqfcHBAdata)
+
+static void SetTachTOV(CPQFCHBA * cpqfcHBAdata)
 {
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip; 
-  
-  // TL/TS UG, pg. 184
-  // 0x0065 = 100ms for RT_TOV
-  // 0x01f5 = 500ms for ED_TOV
-  // 0x07d1 = 2000ms for ED_TOV
-
-  // SANMark Level 1 requires an "initialization backoff"
-  // (See "SANMark Test Suite Level 1":
-  // initialization_timeout.fcal.SANMark-1.fc)
-  // We have to use 2sec, 24sec, then 128sec when login/
-  // port discovery processes fail to complete.
-  
-  // when port discovery completes (logins done), we set
-  // ED_TOV to 500ms -- this is the normal operational case
-  // On the first Link Down, we'll move to 2 secs (7D1 ms)
-  if( (fcChip->Registers.ed_tov.value &0xFFFF) <= 0x1f5)
-    fcChip->Registers.ed_tov.value = 0x006507D1; 
-  
-  // If we get another LST after we moved TOV to 2 sec,
-  // increase to 24 seconds (5DC1 ms) per SANMark!
-  else if( (fcChip->Registers.ed_tov.value &0xFFFF) <= 0x7D1)
-    fcChip->Registers.ed_tov.value = 0x00655DC1; 
-
-  // If we get still another LST, set the max TOV (Tachyon
-  // has only 16 bits for ms timer, so the max is 65.5 sec)
-  else if( (fcChip->Registers.ed_tov.value &0xFFFF) <= 0x5DC1)
-    fcChip->Registers.ed_tov.value = 0x0065FFFF; 
-
-  writel( fcChip->Registers.ed_tov.value,
-    (fcChip->Registers.ed_tov.address));
-  // keep the same 2sec LP_TOV 
-  writel( 0x07D00010, fcChip->Registers.ReMapMemBase +TL_MEM_FM_TIMEOUT2);
-}	
+	PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+
+	// TL/TS UG, pg. 184
+	// 0x0065 = 100ms for RT_TOV
+	// 0x01f5 = 500ms for ED_TOV
+	// 0x07d1 = 2000ms for ED_TOV
+
+	// SANMark Level 1 requires an "initialization backoff"
+	// (See "SANMark Test Suite Level 1":
+	// initialization_timeout.fcal.SANMark-1.fc)
+	// We have to use 2sec, 24sec, then 128sec when login/
+	// port discovery processes fail to complete.
+
+	// when port discovery completes (logins done), we set
+	// ED_TOV to 500ms -- this is the normal operational case
+	// On the first Link Down, we'll move to 2 secs (7D1 ms)
+	if ((fcChip->Registers.ed_tov.value & 0xFFFF) <= 0x1f5)
+		fcChip->Registers.ed_tov.value = 0x006507D1;
+
+	// If we get another LST after we moved TOV to 2 sec,
+	// increase to 24 seconds (5DC1 ms) per SANMark!
+	else if ((fcChip->Registers.ed_tov.value & 0xFFFF) <= 0x7D1)
+		fcChip->Registers.ed_tov.value = 0x00655DC1;
+
+	// If we get still another LST, set the max TOV (Tachyon
+	// has only 16 bits for ms timer, so the max is 65.5 sec)
+	else if ((fcChip->Registers.ed_tov.value & 0xFFFF) <= 0x5DC1)
+		fcChip->Registers.ed_tov.value = 0x0065FFFF;
+
+	writel(fcChip->Registers.ed_tov.value, (fcChip->Registers.ed_tov.address));
+	// keep the same 2sec LP_TOV 
+	writel(0x07D00010, fcChip->Registers.ReMapMemBase + TL_MEM_FM_TIMEOUT2);
+}
 
 
 // The IMQ is an array with IMQ_LEN length, each element (QEntry)
@@ -709,924 +637,844 @@
 
 int CpqTsProcessIMQEntry(void *host)
 {
-  struct Scsi_Host *HostAdapter = (struct Scsi_Host *)host;
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip; 
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  int iStatus;
-  USHORT i, RPCset, DPCset;
-  ULONG x_ID;
-  ULONG ulBuff, dwStatus;
-  TachFCHDR_GCMND* fchs;
-  ULONG ulFibreFrame[2048/4];  // max number of DWORDS in incoming Fibre Frame
-  UCHAR ucInboundMessageType;  // Inbound CM, dword 3 "type" field
-
-  ENTER("ProcessIMQEntry");
-   
-
-				// check TachLite's IMQ producer index -
-				// is a new message waiting for us?
-				// equal indexes means empty que
+	struct Scsi_Host *HostAdapter = (struct Scsi_Host *) host;
+	CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *) HostAdapter->hostdata;
+	PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	int iStatus;
+	u16 i, RPCset, DPCset;
+	u32 x_ID;
+	u32 ulBuff, dwStatus;
+	TachFCHDR_GCMND *fchs;
+	u32 ulFibreFrame[2048 / 4];	// max number of DWORDS in incoming Fibre Frame
+	u8 ucInboundMessageType;	// Inbound CM, dword 3 "type" field
+
+	ENTER("ProcessIMQEntry");
+
+
+	// check TachLite's IMQ producer index -
+	// is a new message waiting for us?
+	// equal indexes means empty que
 
-  if( fcChip->IMQ->producerIndex != fcChip->IMQ->consumerIndex )
-  {                             // need to process message
+	if (fcChip->IMQ->producerIndex != fcChip->IMQ->consumerIndex) {	// need to process message
 
 
 #ifdef IMQ_DEBUG
-    printk("PI %X, CI %X  type: %X\n", 
-      fcChip->IMQ->producerIndex,fcChip->IMQ->consumerIndex,
-      fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].type);
-#endif                                
-    // Examine Completion Messages in IMQ
-    // what CM_Type?
-    switch( (UCHAR)(fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].type
-                    & 0xffL) )
-    {
-    case OUTBOUND_COMPLETION:
-
-      // Remarks:
-      // x_IDs (OX_ID, RX_ID) are partitioned by SEST entries
-      // (starting at 0), and SFS entries (starting at
-      // SEST_LEN -- outside the SEST space).
-      // Psuedo code:
-      // x_ID (OX_ID or RX_ID) from message is Trans_ID or SEST index
-      // range check - x_ID
-      //   if x_ID outside 'Transactions' length, error - exit
-      // if any OCM error, copy error status to Exchange slot
-      // if FCP ASSIST transaction (x_ID within SEST),
-      //   call fcComplete (to App)
-      // ...
-
-
-      ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1];
-      x_ID = ulBuff & 0x7fffL;     // lower 14 bits SEST_Index/Trans_ID
-                                     // Range check CM OX/RX_ID value...
-      if( x_ID < TACH_MAX_XID )   // don't go beyond array space
-      {
-
-
-	if( ulBuff & 0x20000000L ) // RPC -Response Phase Complete?
-          RPCset = 1;              // (SEST transactions only)
-        else
-          RPCset = 0;
-
-        if( ulBuff & 0x40000000L ) // DPC -Data Phase Complete?
-          DPCset = 1;              // (SEST transactions only)
-        else
-          DPCset = 0;
-                // set the status for this Outbound transaction's ID
-        dwStatus = 0L;
-        if( ulBuff & 0x10000000L ) // SPE? (SEST Programming Error)
-            dwStatus |= SESTPROG_ERR;
-
-        ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2];
-        if( ulBuff & 0x7a000000L ) // any other errs?
-        {
-          if( ulBuff & 0x40000000L )
-            dwStatus |= INV_ENTRY;
-          if( ulBuff & 0x20000000L )
-            dwStatus |= FRAME_TO;        // FTO
-          if( ulBuff & 0x10000000L )
-            dwStatus |= HOSTPROG_ERR;
-          if( ulBuff & 0x08000000L )
-            dwStatus |= LINKFAIL_TX;
-          if( ulBuff & 0x02000000L )
-            dwStatus |= ABORTSEQ_NOTIFY;  // ASN
-        }
-
-	  
-	if( dwStatus )          // any errors?
-        {
-                  // set the Outbound Completion status
-          Exchanges->fcExchange[ x_ID ].status |= dwStatus;
-
-          // if this Outbound frame was for a SEST entry, automatically
-          // reque it in the case of LINKFAIL (it will restart on PDISC)
-          if( x_ID < TACH_SEST_LEN )
-          {
-
-            printk(" #OCM error %Xh x_ID %X# ", 
-		    dwStatus, x_ID);
-
-	    Exchanges->fcExchange[x_ID].timeOut = 30000; // seconds default
-                                                 
-
-	    // We Q ABTS for each exchange.
-	    // NOTE: We can get FRAME_TO on bad alpa (device gone).  Since
-	    // bad alpa is reported before FRAME_TO, examine the status
-	    // flags to see if the device is removed.  If so, DON'T
-	    // post an ABTS, since it will be terminated by the bad alpa
-	    // message.
-	    if( dwStatus & FRAME_TO ) // check for device removed...
-	    {
-	      if( !(Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED) )
-	      { 
-		// presumes device is still there: send ABTS.
-  
-                cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID);
-	      }
-	    }
-	    else  // Abort all other errors
-	    {
-              cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID);
-	    }
-
-            // if the HPE bit is set, we have to CLose the LOOP
-            // (see TL/TS UG, pg. 239)
-
-            if( dwStatus &= HOSTPROG_ERR )
-            // set CL bit (see TL/TS UG, pg. 172)
-              writel( 4, fcChip->Registers.FMcontrol.address);
-          }
-        }
-          // NOTE: we don't necessarily care about ALL completion messages...
-                                      // SCSI resp. complete OR
-        if( ((x_ID < TACH_SEST_LEN) && RPCset)|| 
-             (x_ID >= TACH_SEST_LEN) )  // non-SCSI command
-        {
-              // exchange done; complete to upper levels with status
-              // (if necessary) and free the exchange slot
-            
-
-          if( x_ID >= TACH_SEST_LEN ) // Link Service Outbound frame?
-                                    // A Request or Reply has been sent
-          {                         // signal waiting WorkerThread
-
-            up( cpqfcHBAdata->TYOBcomplete);   // frame is OUT of Tach
-
-                                    // WorkerThread will complete Xchng
-          }
-          else  // X_ID is for FCP assist (SEST)
-          {
-              // TBD (target mode)
+		printk("PI %X, CI %X  type: %X\n", fcChip->IMQ->producerIndex, fcChip->IMQ->consumerIndex, fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].type);
+#endif
+		// Examine Completion Messages in IMQ
+		// what CM_Type?
+		switch ((u8) (fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].type & 0xffL)) {
+		case OUTBOUND_COMPLETION:
+
+			// Remarks:
+			// x_IDs (OX_ID, RX_ID) are partitioned by SEST entries
+			// (starting at 0), and SFS entries (starting at
+			// SEST_LEN -- outside the SEST space).
+			// Psuedo code:
+			// x_ID (OX_ID or RX_ID) from message is Trans_ID or SEST index
+			// range check - x_ID
+			//   if x_ID outside 'Transactions' length, error - exit
+			// if any OCM error, copy error status to Exchange slot
+			// if FCP ASSIST transaction (x_ID within SEST),
+			//   call fcComplete (to App)
+			// ...
+
+
+			ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1];
+			x_ID = ulBuff & 0x7fffL;	// lower 14 bits SEST_Index/Trans_ID
+			// Range check CM OX/RX_ID value...
+			if (x_ID < TACH_MAX_XID)	// don't go beyond array space
+			{
+
+
+				if (ulBuff & 0x20000000L)	// RPC -Response Phase Complete?
+					RPCset = 1;	// (SEST transactions only)
+				else
+					RPCset = 0;
+
+				if (ulBuff & 0x40000000L)	// DPC -Data Phase Complete?
+					DPCset = 1;	// (SEST transactions only)
+				else
+					DPCset = 0;
+				// set the status for this Outbound transaction's ID
+				dwStatus = 0L;
+				if (ulBuff & 0x10000000L)	// SPE? (SEST Programming Error)
+					dwStatus |= SESTPROG_ERR;
+
+				ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2];
+				if (ulBuff & 0x7a000000L)	// any other errs?
+				{
+					if (ulBuff & 0x40000000L)
+						dwStatus |= INV_ENTRY;
+					if (ulBuff & 0x20000000L)
+						dwStatus |= FRAME_TO;	// FTO
+					if (ulBuff & 0x10000000L)
+						dwStatus |= HOSTPROG_ERR;
+					if (ulBuff & 0x08000000L)
+						dwStatus |= LINKFAIL_TX;
+					if (ulBuff & 0x02000000L)
+						dwStatus |= ABORTSEQ_NOTIFY;	// ASN
+				}
+
+
+				if (dwStatus)	// any errors?
+				{
+					// set the Outbound Completion status
+					Exchanges->fcExchange[x_ID].status |= dwStatus;
+
+					// if this Outbound frame was for a SEST entry, automatically
+					// reque it in the case of LINKFAIL (it will restart on PDISC)
+					if (x_ID < TACH_SEST_LEN) {
+
+						printk(" #OCM error %Xh x_ID %X# ", dwStatus, x_ID);
+
+						Exchanges->fcExchange[x_ID].timeOut = 30000;	// seconds default
+
+
+						// We Q ABTS for each exchange.
+						// NOTE: We can get FRAME_TO on bad alpa (device gone).  Since
+						// bad alpa is reported before FRAME_TO, examine the status
+						// flags to see if the device is removed.  If so, DON'T
+						// post an ABTS, since it will be terminated by the bad alpa
+						// message.
+						if (dwStatus & FRAME_TO)	// check for device removed...
+						{
+							if (!(Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED)) {
+								// presumes device is still there: send ABTS.
+
+								cpqfcTSPutLinkQue(cpqfcHBAdata, BLS_ABTS, &x_ID);
+							}
+						} else	// Abort all other errors
+						{
+							cpqfcTSPutLinkQue(cpqfcHBAdata, BLS_ABTS, &x_ID);
+						}
+
+						// if the HPE bit is set, we have to CLose the LOOP
+						// (see TL/TS UG, pg. 239)
+
+						if (dwStatus &= HOSTPROG_ERR)
+							// set CL bit (see TL/TS UG, pg. 172)
+							writel(4, fcChip->Registers.FMcontrol.address);
+					}
+				}
+				// NOTE: we don't necessarily care about ALL completion messages...
+				// SCSI resp. complete OR
+				if (((x_ID < TACH_SEST_LEN) && RPCset) || (x_ID >= TACH_SEST_LEN))	// non-SCSI command
+				{
+					// exchange done; complete to upper levels with status
+					// (if necessary) and free the exchange slot
+
+
+					if (x_ID >= TACH_SEST_LEN)	// Link Service Outbound frame?
+						// A Request or Reply has been sent
+					{	// signal waiting WorkerThread
+
+						up(cpqfcHBAdata->TYOBcomplete);	// frame is OUT of Tach
+
+						// WorkerThread will complete Xchng
+					} else	// X_ID is for FCP assist (SEST)
+					{
+						// TBD (target mode)
 //            fcCompleteExchange( fcChip, x_ID); // TRE completed
-          }
-        }
-      }
-      else  // ERROR CONDITION!  bogus x_ID in completion message
-      {
-
-        printk(" ProcessIMQ (OBCM) x_id out of range %Xh\n", x_ID);
-
-      }
+					}
+				}
+			} else	// ERROR CONDITION!  bogus x_ID in completion message
+			{
 
+				printk(" ProcessIMQ (OBCM) x_id out of range %Xh\n", x_ID);
 
+			}
 
-          // Load the Frame Manager's error counters.  We check them here
-          // because presumably the link is up and healthy enough for the
-          // counters to be meaningful (i.e., don't check them while loop
-          // is initializing).
-      fcChip->Registers.FMLinkStatus1.value =    // get TL's counter
-        readl(fcChip->Registers.FMLinkStatus1.address);
-                  
-      fcChip->Registers.FMLinkStatus2.value =    // get TL's counter
-        readl(fcChip->Registers.FMLinkStatus2.address);
-            
 
-      fcParseLinkStatusCounters( fcChip); // load into 6 s/w accumulators
-    break;
 
+			// Load the Frame Manager's error counters.  We check them here
+			// because presumably the link is up and healthy enough for the
+			// counters to be meaningful (i.e., don't check them while loop
+			// is initializing).
+			fcChip->Registers.FMLinkStatus1.value =	// get TL's counter
+			    readl(fcChip->Registers.FMLinkStatus1.address);
 
+			fcChip->Registers.FMLinkStatus2.value =	// get TL's counter
+			    readl(fcChip->Registers.FMLinkStatus2.address);
 
-    case ERROR_IDLE_COMPLETION:  // TachLite Error Idle...
-    
-    // We usually get this when the link goes down during heavy traffic.
-    // For now, presume that if SEST Exchanges are open, we will
-    // get this as our cue to INVALIDATE all SEST entries
-    // (and we OWN all the SEST entries).
-    // See TL/TS UG, pg. 53
-    
-      for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
-      {
-
-        // Does this VALid SEST entry need to be invalidated for Abort?
-        fcChip->SEST->u[ x_ID].IWE.Hdr_Len &= 0x7FFFFFFF; 
-      }
-      
-      CpqTsUnFreezeTachlite( fcChip, 2); // unfreeze Tachyon, if Link OK
 
-    break;
+			fcParseLinkStatusCounters(fcChip);	// load into 6 s/w accumulators
+			break;
+
+
+
+		case ERROR_IDLE_COMPLETION:	// TachLite Error Idle...
+
+			// We usually get this when the link goes down during heavy traffic.
+			// For now, presume that if SEST Exchanges are open, we will
+			// get this as our cue to INVALIDATE all SEST entries
+			// (and we OWN all the SEST entries).
+			// See TL/TS UG, pg. 53
+
+			for (x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++) {
+
+				// Does this VALid SEST entry need to be invalidated for Abort?
+				fcChip->SEST->u[x_ID].IWE.Hdr_Len &= 0x7FFFFFFF;
+			}
+
+			CpqTsUnFreezeTachlite(fcChip, 2);	// unfreeze Tachyon, if Link OK
+
+			break;
+
+
+		case INBOUND_SFS_COMPLETION:	//0x04
+			// NOTE! we must process this SFQ message to avoid SFQ filling
+			// up and stopping TachLite.  Incoming commands are placed here,
+			// as well as 'unknown' frames (e.g. LIP loop position data)
+			// write this CM's producer index to global...
+			// TL/TS UG, pg 234:
+			// Type: 0 - reserved
+			//       1 - Unassisted FCP
+			//       2 - BAD FCP
+			//       3 - Unkown Frame
+			//       4-F reserved
+
 
+			fcChip->SFQ->producerIndex = (u16)
+			    (fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0] & 0x0fffL);
 
-    case INBOUND_SFS_COMPLETION:  //0x04
-          // NOTE! we must process this SFQ message to avoid SFQ filling
-          // up and stopping TachLite.  Incoming commands are placed here,
-          // as well as 'unknown' frames (e.g. LIP loop position data)
-          // write this CM's producer index to global...
-          // TL/TS UG, pg 234:
-          // Type: 0 - reserved
-          //       1 - Unassisted FCP
-          //       2 - BAD FCP
-          //       3 - Unkown Frame
-          //       4-F reserved
-
-
-      fcChip->SFQ->producerIndex = (USHORT)
-        (fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0] & 0x0fffL);
-
-
-      ucInboundMessageType = 0;  // default to useless frame
-
-        // we can only process two Types: 1, Unassisted FCP, and 3, Unknown
-        // Also, we aren't interested in processing frame fragments
-        // so don't Que anything with 'LKF' bit set
-      if( !(fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2] 
-        & 0x40000000) )  // 'LKF' link failure bit clear?
-      {
-        ucInboundMessageType = (UCHAR)  // ICM DWord3, "Type"
-        (fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2] & 0x0fL);
-      }
-      else
-      {
-	fcChip->fcStats.linkFailRX++;
+
+			ucInboundMessageType = 0;	// default to useless frame
+
+			// we can only process two Types: 1, Unassisted FCP, and 3, Unknown
+			// Also, we aren't interested in processing frame fragments
+			// so don't Que anything with 'LKF' bit set
+			if (!(fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2]
+			      & 0x40000000))	// 'LKF' link failure bit clear?
+			{
+				ucInboundMessageType = (u8)	// ICM DWord3, "Type"
+				    (fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2] & 0x0fL);
+			} else {
+				fcChip->fcStats.linkFailRX++;
 //        printk("LKF (link failure) bit set on inbound message\n");
-      }
+			}
+
+			// clears SFQ entry from Tachyon buffer; copies to contiguous ulBuff
+			CpqTsGetSFQEntry(fcChip,	// i.e. this Device Object
+					 (u16) fcChip->SFQ->producerIndex,	// SFQ producer ndx         
+					 ulFibreFrame, TRUE);	// contiguous destination buffer, update chip
+
+			// analyze the incoming frame outside the INT handler...
+			// (i.e., Worker)
+
+			if (ucInboundMessageType == 1) {
+				fchs = (TachFCHDR_GCMND *) ulFibreFrame;	// cast to examine IB frame
+				// don't fill up our Q with garbage - only accept FCP-CMND  
+				// or XRDY frames
+				if ((fchs->d_id & 0xFF000000) == 0x06000000)	// CMND
+				{
+					// someone sent us a SCSI command
 
-          // clears SFQ entry from Tachyon buffer; copies to contiguous ulBuff
-      CpqTsGetSFQEntry(
-        fcChip,                  // i.e. this Device Object
-        (USHORT)fcChip->SFQ->producerIndex,  // SFQ producer ndx         
-        ulFibreFrame, TRUE);    // contiguous destination buffer, update chip
-                     
-        // analyze the incoming frame outside the INT handler...
-        // (i.e., Worker)
-
-      if( ucInboundMessageType == 1 )
-      {
-        fchs = (TachFCHDR_GCMND*)ulFibreFrame; // cast to examine IB frame
-        // don't fill up our Q with garbage - only accept FCP-CMND  
-        // or XRDY frames
-        if( (fchs->d_id & 0xFF000000) == 0x06000000 ) // CMND
-        {
-	  // someone sent us a SCSI command
-	  
 //          fcPutScsiQue( cpqfcHBAdata, 
 //                        SFQ_UNASSISTED_FCP, ulFibreFrame); 
-	}
-	else if( ((fchs->d_id & 0xFF000000) == 0x07000000) || // RSP (status)
-            (fchs->d_id & 0xFF000000) == 0x05000000 )  // XRDY  
-	{
-	  ULONG x_ID;
-	  // Unfortunately, ABTS requires a Freeze on the chip so
-	  // we can modify the shared memory SEST.  When frozen,
-	  // any received Exchange frames cannot be processed by
-	  // Tachyon, so they will be dumped in here.  It is too
-	  // complex to attempt the reconstruct these frames in
-	  // the correct Exchange context, so we simply seek to
-	  // find status or transfer ready frames, and cause the
-	  // exchange to complete with errors before the timeout
-	  // expires.  We use a Linux Scsi Cmnd result code that
-	  // causes immediate retry.
-	  
-
-	  // Do we have an open exchange that matches this s_id
-	  // and ox_id?
-	  for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
-	  {
-            if( (fchs->s_id & 0xFFFFFF) == 
-                 (Exchanges->fcExchange[x_ID].fchs.d_id & 0xFFFFFF) 
-		       &&
-                (fchs->ox_rx_id & 0xFFFF0000) == 
-                 (Exchanges->fcExchange[x_ID].fchs.ox_rx_id & 0xFFFF0000) )
-	    {
-    //          printk(" #R/X frame x_ID %08X# ", fchs->ox_rx_id );
-              // simulate the anticipated error - since the
-	      // SEST was frozen, frames were lost...
-              Exchanges->fcExchange[ x_ID ].status |= SFQ_FRAME;
-              
-	      // presumes device is still there: send ABTS.
-              cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID);
-	      break;  // done
-	    }
-	  }
-	}
-	  
-      }
-          
-      else if( ucInboundMessageType == 3)
-      {
-        // FC Link Service frames (e.g. PLOGI, ACC) come in here.  
-        cpqfcTSPutLinkQue( cpqfcHBAdata, SFQ_UNKNOWN, ulFibreFrame); 
-                          
-      }
+				} else if (((fchs->d_id & 0xFF000000) == 0x07000000) ||	// RSP (status)
+					   (fchs->d_id & 0xFF000000) == 0x05000000)	// XRDY  
+				{
+					u32 x_ID;
+					// Unfortunately, ABTS requires a Freeze on the chip so
+					// we can modify the shared memory SEST.  When frozen,
+					// any received Exchange frames cannot be processed by
+					// Tachyon, so they will be dumped in here.  It is too
+					// complex to attempt the reconstruct these frames in
+					// the correct Exchange context, so we simply seek to
+					// find status or transfer ready frames, and cause the
+					// exchange to complete with errors before the timeout
+					// expires.  We use a Linux Scsi Cmnd result code that
+					// causes immediate retry.
+
+
+					// Do we have an open exchange that matches this s_id
+					// and ox_id?
+					for (x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++) {
+						if ((fchs->s_id & 0xFFFFFF) == (Exchanges->fcExchange[x_ID].fchs.d_id & 0xFFFFFF)
+						    && (fchs->ox_rx_id & 0xFFFF0000) == (Exchanges->fcExchange[x_ID].fchs.ox_rx_id & 0xFFFF0000)) {
+							//          printk(" #R/X frame x_ID %08X# ", fchs->ox_rx_id );
+							// simulate the anticipated error - since the
+							// SEST was frozen, frames were lost...
+							Exchanges->fcExchange[x_ID].status |= SFQ_FRAME;
+
+							// presumes device is still there: send ABTS.
+							cpqfcTSPutLinkQue(cpqfcHBAdata, BLS_ABTS, &x_ID);
+							break;	// done
+						}
+					}
+				}
+
+			}
+
+			else if (ucInboundMessageType == 3) {
+				// FC Link Service frames (e.g. PLOGI, ACC) come in here.  
+				cpqfcTSPutLinkQue(cpqfcHBAdata, SFQ_UNKNOWN, ulFibreFrame);
+
+			}
 
-      else if( ucInboundMessageType == 2 ) // "bad FCP"?
-      {
+			else if (ucInboundMessageType == 2)	// "bad FCP"?
+			{
 #ifdef IMQ_DEBUG
-        printk("Bad FCP incoming frame discarded\n");
+				printk("Bad FCP incoming frame discarded\n");
 #endif
-      }
+			}
 
-      else // don't know this type
-      {
-#ifdef IMQ_DEBUG 
-        printk("Incoming frame discarded, type: %Xh\n", ucInboundMessageType);
+			else	// don't know this type
+			{
+#ifdef IMQ_DEBUG
+				printk("Incoming frame discarded, type: %Xh\n", ucInboundMessageType);
 #endif
-      }
-        
-        // Check the Frame Manager's error counters.  We check them here
-        // because presumably the link is up and healthy enough for the
-        // counters to be meaningful (i.e., don't check them while loop
-        // is initializing).
-      fcChip->Registers.FMLinkStatus1.value =    // get TL's counter
-        readl(fcChip->Registers.FMLinkStatus1.address);
-                  
-
-      fcChip->Registers.FMLinkStatus2.value =    // get TL's counter
-        readl(fcChip->Registers.FMLinkStatus2.address);
-                
-
-      break;
+			}
 
+			// Check the Frame Manager's error counters.  We check them here
+			// because presumably the link is up and healthy enough for the
+			// counters to be meaningful (i.e., don't check them while loop
+			// is initializing).
+			fcChip->Registers.FMLinkStatus1.value =	// get TL's counter
+			    readl(fcChip->Registers.FMLinkStatus1.address);
 
 
+			fcChip->Registers.FMLinkStatus2.value =	// get TL's counter
+			    readl(fcChip->Registers.FMLinkStatus2.address);
 
-                    // We get this CM because we issued a freeze
-                    // command to stop outbound frames.  We issue the
-                    // freeze command at Link Up time; when this message
-                    // is received, the ERQ base can be switched and PDISC
-                    // frames can be sent.
-
-      
-    case ERQ_FROZEN_COMPLETION:  // note: expect ERQ followed immediately
-                                 // by FCP when freezing TL
-      fcChip->Registers.TYstatus.value =         // read what's frozen
-        readl(fcChip->Registers.TYstatus.address);
-      // (do nothing; wait for FCP frozen message)
-      break;
-    case FCP_FROZEN_COMPLETION:
-      
-      fcChip->Registers.TYstatus.value =         // read what's frozen
-        readl(fcChip->Registers.TYstatus.address);
-      
-      // Signal the kernel thread to proceed with SEST modification
-      up( cpqfcHBAdata->TachFrozen);
-
-      break;
 
+			break;
 
 
-    case INBOUND_C1_TIMEOUT:
-    case MFS_BUF_WARN:
-    case IMQ_BUF_WARN:
-    break;
 
 
+			// We get this CM because we issued a freeze
+			// command to stop outbound frames.  We issue the
+			// freeze command at Link Up time; when this message
+			// is received, the ERQ base can be switched and PDISC
+			// frames can be sent.
 
 
+		case ERQ_FROZEN_COMPLETION:	// note: expect ERQ followed immediately
+			// by FCP when freezing TL
+			fcChip->Registers.TYstatus.value =	// read what's frozen
+			    readl(fcChip->Registers.TYstatus.address);
+			// (do nothing; wait for FCP frozen message)
+			break;
+		case FCP_FROZEN_COMPLETION:
 
-        // In older Tachyons, we 'clear' the internal 'core' interrupt state
-        // by reading the FMstatus register.  In newer TachLite (Tachyon),
-        // we must WRITE the register
-        // to clear the condition (TL/TS UG, pg 179)
-    case FRAME_MGR_INTERRUPT:
-    {
-      PFC_LOGGEDIN_PORT pLoggedInPort; 
-
-      fcChip->Registers.FMstatus.value = 
-        readl( fcChip->Registers.FMstatus.address );
-                
-      // PROBLEM: It is possible, especially with "dumb" hubs that
-      // don't automatically LIP on by-pass of ports that are going
-      // away, for the hub by-pass process to destroy critical 
-      // ordered sets of a frame.  The result of this is a hung LPSM
-      // (Loop Port State Machine), which on Tachyon results in a
-      // (default 2 sec) Loop State Timeout (LST) FM message.  We 
-      // want to avoid this relatively huge timeout by detecting
-      // likely scenarios which will result in LST.
-      // To do this, we could examine FMstatus for Loss of Synchronization
-      // and/or Elastic Store (ES) errors.  Of these, Elastic Store is better
-      // because we get this indication more quickly than the LOS.
-      // Not all ES errors are harmfull, so we don't want to LIP on every
-      // ES.  Instead, on every ES, detect whether our LPSM in in one
-      // of the LST states: ARBITRATING, OPEN, OPENED, XMITTED CLOSE,
-      // or RECEIVED CLOSE.  (See TL/TS UG, pg. 181)
-      // If any of these LPSM states are detected
-      // in combination with the LIP while LDn is not set, 
-      // send an FM init (LIP F7,F7 for loops)!
-      // It is critical to the physical link stability NOT to reset (LIP)
-      // more than absolutely necessary; this is a basic premise of the
-      // SANMark level 1 spec.
-      {
-	ULONG Lpsm = (fcChip->Registers.FMstatus.value & 0xF0) >>4;
-	
-	if( (fcChip->Registers.FMstatus.value & 0x400)  // ElasticStore?
-                      &&
-            !(fcChip->Registers.FMstatus.value & 0x100) // NOT LDn
-	              &&
-            !(fcChip->Registers.FMstatus.value & 0x1000)) // NOT LF
-	{
-	  if( (Lpsm != 0) || // not MONITORING? or
-	      !(Lpsm & 0x8) )// not already offline?
-	  {
-	  // now check the particular LST states...
-            if( (Lpsm == ARBITRATING) || (Lpsm == OPEN) ||
-	      (Lpsm == OPENED)      || (Lpsm == XMITTD_CLOSE) ||
-	      (Lpsm == RCVD_CLOSE) )
-	    {
-	      // re-init the loop before it hangs itself!
-              printk(" #req FMinit on E-S: LPSM %Xh# ",Lpsm);
-
-
-	      fcChip->fcStats.FMinits++;
-              writel( 6, fcChip->Registers.FMcontrol.address); // LIP
-	    }
-	  }
-	}
-	else if( fcChip->Registers.FMstatus.value & 0x40000 ) // LST?
-	{
-          printk(" #req FMinit on LST, LPSM %Xh# ",Lpsm);
-	 
-          fcChip->fcStats.FMinits++;
-          writel( 6, fcChip->Registers.FMcontrol.address);  // LIP
-	}  
-      }
-
-
-      // clear only the 'interrupting' type bits for this REG read
-      writel( (fcChip->Registers.FMstatus.value & 0xff3fff00L),
-        fcChip->Registers.FMstatus.address);
-                          
-
-               // copy frame manager status to unused ULONG slot
-      fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0] =
-          fcChip->Registers.FMstatus.value; // (for debugging)
-
-
-          // Load the Frame Manager's error counters.  We check them here
-          // because presumably the link is up and healthy enough for the
-          // counters to be meaningful (i.e., don't check them while loop
-          // is initializing).
-      fcChip->Registers.FMLinkStatus1.value =   // get TL's counter
-        readl(fcChip->Registers.FMLinkStatus1.address);
-            
-      fcChip->Registers.FMLinkStatus2.value =   // get TL's counter
-        readl(fcChip->Registers.FMLinkStatus2.address);
-          
-          // Get FM BB_Credit Zero Reg - does not clear on READ
-      fcChip->Registers.FMBB_CreditZero.value =   // get TL's counter
-        readl(fcChip->Registers.FMBB_CreditZero.address);
-            
-
-
-      fcParseLinkStatusCounters( fcChip); // load into 6 s/w accumulators
-
-
-               // LINK DOWN
-
-      if( fcChip->Registers.FMstatus.value & 0x100L ) // Link DOWN bit
-      {                                 
-	
-#ifdef IMQ_DEBUG
-        printk("LinkDn\n");
-#endif
-        printk(" #LDn# ");
-        
-        fcChip->fcStats.linkDown++;
-        
-	SetTachTOV( cpqfcHBAdata);  // must set according to SANMark
+			fcChip->Registers.TYstatus.value =	// read what's frozen
+			    readl(fcChip->Registers.TYstatus.address);
 
-	// Check the ERQ - force it to be "empty" to prevent Tach
-	// from sending out frames before we do logins.
+			// Signal the kernel thread to proceed with SEST modification
+			up(cpqfcHBAdata->TachFrozen);
 
+			break;
+
+
+
+		case INBOUND_C1_TIMEOUT:
+		case MFS_BUF_WARN:
+		case IMQ_BUF_WARN:
+			break;
+
+
+
+
+
+			// In older Tachyons, we 'clear' the internal 'core' interrupt state
+			// by reading the FMstatus register.  In newer TachLite (Tachyon),
+			// we must WRITE the register
+			// to clear the condition (TL/TS UG, pg 179)
+		case FRAME_MGR_INTERRUPT:
+			{
+				PFC_LOGGEDIN_PORT pLoggedInPort;
+
+				fcChip->Registers.FMstatus.value = readl(fcChip->Registers.FMstatus.address);
+
+				// PROBLEM: It is possible, especially with "dumb" hubs that
+				// don't automatically LIP on by-pass of ports that are going
+				// away, for the hub by-pass process to destroy critical 
+				// ordered sets of a frame.  The result of this is a hung LPSM
+				// (Loop Port State Machine), which on Tachyon results in a
+				// (default 2 sec) Loop State Timeout (LST) FM message.  We 
+				// want to avoid this relatively huge timeout by detecting
+				// likely scenarios which will result in LST.
+				// To do this, we could examine FMstatus for Loss of Synchronization
+				// and/or Elastic Store (ES) errors.  Of these, Elastic Store is better
+				// because we get this indication more quickly than the LOS.
+				// Not all ES errors are harmfull, so we don't want to LIP on every
+				// ES.  Instead, on every ES, detect whether our LPSM in in one
+				// of the LST states: ARBITRATING, OPEN, OPENED, XMITTED CLOSE,
+				// or RECEIVED CLOSE.  (See TL/TS UG, pg. 181)
+				// If any of these LPSM states are detected
+				// in combination with the LIP while LDn is not set, 
+				// send an FM init (LIP F7,F7 for loops)!
+				// It is critical to the physical link stability NOT to reset (LIP)
+				// more than absolutely necessary; this is a basic premise of the
+				// SANMark level 1 spec.
+				{
+					u32 Lpsm = (fcChip->Registers.FMstatus.value & 0xF0) >> 4;
+
+					if ((fcChip->Registers.FMstatus.value & 0x400)	// ElasticStore?
+					    && !(fcChip->Registers.FMstatus.value & 0x100)	// NOT LDn
+					    && !(fcChip->Registers.FMstatus.value & 0x1000))	// NOT LF
+					{
+						if ((Lpsm != 0) ||	// not MONITORING? or
+						    !(Lpsm & 0x8))	// not already offline?
+						{
+							// now check the particular LST states...
+							if ((Lpsm == ARBITRATING) || (Lpsm == OPEN) || (Lpsm == OPENED) || (Lpsm == XMITTD_CLOSE) || (Lpsm == RCVD_CLOSE)) {
+								// re-init the loop before it hangs itself!
+								printk(" #req FMinit on E-S: LPSM %Xh# ", Lpsm);
+
+
+								fcChip->fcStats.FMinits++;
+								writel(6, fcChip->Registers.FMcontrol.address);	// LIP
+							}
+						}
+					} else if (fcChip->Registers.FMstatus.value & 0x40000)	// LST?
+					{
+						printk(" #req FMinit on LST, LPSM %Xh# ", Lpsm);
+
+						fcChip->fcStats.FMinits++;
+						writel(6, fcChip->Registers.FMcontrol.address);	// LIP
+					}
+				}
+
+
+				// clear only the 'interrupting' type bits for this REG read
+				writel((fcChip->Registers.FMstatus.value & 0xff3fff00L), fcChip->Registers.FMstatus.address);
+
+
+				// copy frame manager status to unused u32 slot
+				fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0] = fcChip->Registers.FMstatus.value;	// (for debugging)
+
+
+				// Load the Frame Manager's error counters.  We check them here
+				// because presumably the link is up and healthy enough for the
+				// counters to be meaningful (i.e., don't check them while loop
+				// is initializing).
+				fcChip->Registers.FMLinkStatus1.value =	// get TL's counter
+				    readl(fcChip->Registers.FMLinkStatus1.address);
+
+				fcChip->Registers.FMLinkStatus2.value =	// get TL's counter
+				    readl(fcChip->Registers.FMLinkStatus2.address);
+
+				// Get FM BB_Credit Zero Reg - does not clear on READ
+				fcChip->Registers.FMBB_CreditZero.value =	// get TL's counter
+				    readl(fcChip->Registers.FMBB_CreditZero.address);
+
+
+
+				fcParseLinkStatusCounters(fcChip);	// load into 6 s/w accumulators
+
+
+				// LINK DOWN
+
+				if (fcChip->Registers.FMstatus.value & 0x100L)	// Link DOWN bit
+				{
 
-  	if( fcChip->ERQ->producerIndex != fcChip->ERQ->consumerIndex)
-	{
-//	  printk("#ERQ PI != CI#");
-          CpqTsFreezeTachlite( fcChip, 1); // freeze ERQ only	  
-	  fcChip->ERQ->producerIndex = fcChip->ERQ->consumerIndex = 0;
- 	  writel( fcChip->ERQ->base, 
-	    (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_BASE));
-          // re-writing base forces ERQ PI to equal CI
-  
-	}
-		
-	// link down transition occurred -- port_ids can change
-        // on next LinkUp, so we must invalidate current logins
-        // (and any I/O in progress) until PDISC or PLOGI/PRLI
-        // completes
-        {
-          pLoggedInPort = &fcChip->fcPorts; 
-          while( pLoggedInPort ) // for all ports which are expecting
-                                 // PDISC after the next LIP, set the
-                                 // logoutTimer
-          {
-
-	    if( pLoggedInPort->pdisc) // expecting PDISC within 2 sec?
-            {
-              pLoggedInPort->LOGO_timer = 3;  // we want 2 seconds
-                                              // but Timer granularity
-                                              // is 1 second
-            }
-                                // suspend any I/O in progress until
-                                // PDISC received...
-            pLoggedInPort->prli = FALSE;   // block FCP-SCSI commands
-	    
-            pLoggedInPort = pLoggedInPort->pNextPort;
-          }  // ... all Previously known ports checked
-        }
-        
-	// since any hot plugging device may NOT support LILP frames
-	// (such as early Tachyon chips), clear this flag indicating
-	// we shouldn't use (our copy of) a LILP map.
-	// If we receive an LILP frame, we'll set it again.
-	fcChip->Options.LILPin = 0; // our LILPmap is invalid
-        cpqfcHBAdata->PortDiscDone = 0; // must re-validate FC ports!
-
-          // also, we want to invalidate (i.e. INITIATOR_ABORT) any
-          // open Login exchanges, in case the LinkDown happened in the
-          // middle of logins.  It's possible that some ports already
-          // ACCepted login commands which we have not processed before
-          // another LinkDown occurred.  Any accepted Login exhanges are
-          // invalidated by LinkDown, even before they are acknowledged.
-          // It's also possible for a port to have a Queued Reply or Request
-          // for login which was interrupted by LinkDown; it may come later,
-          // but it will be unacceptable to us.
-
-          // we must scan the entire exchange space, find every Login type
-          // originated by us, and abort it. This is NOT an abort due to
-          // timeout, so we don't actually send abort to the other port -
-          // we just complete it to free up the fcExchange slot.
-
-        for( i=TACH_SEST_LEN; i< TACH_MAX_XID; i++)
-        {                     // looking for Extended Link Serv.Exchanges
-          if( Exchanges->fcExchange[i].type == ELS_PDISC ||
-              Exchanges->fcExchange[i].type == ELS_PLOGI ||
-              Exchanges->fcExchange[i].type == ELS_PRLI ) 
-          {
-              // ABORT the exchange!
 #ifdef IMQ_DEBUG
-            printk("Originator ABORT x_id %Xh, type %Xh, port_id %Xh on LDn\n",
-              i, Exchanges->fcExchange[i].type,
-            Exchanges->fcExchange[i].fchs.d_id);
+					printk("LinkDn\n");
 #endif
+					printk(" #LDn# ");
 
-            Exchanges->fcExchange[i].status |= INITIATOR_ABORT;
-            cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, i); // abort on LDn
-          }
-        }
-
-      }
-
-             // ################   LINK UP   ##################
-      if( fcChip->Registers.FMstatus.value & 0x200L ) // Link Up bit
-      {                                 // AL_PA could have changed
-
-          // We need the following code, duplicated from LinkDn condition,
-          // because it's possible for the Tachyon to re-initialize (hard
-          // reset) without ever getting a LinkDn indication.
-        pLoggedInPort = &fcChip->fcPorts; 
-        while( pLoggedInPort )   // for all ports which are expecting
-                                 // PDISC after the next LIP, set the
-                                 // logoutTimer
-        {
-          if( pLoggedInPort->pdisc) // expecting PDISC within 2 sec?
-          {
-            pLoggedInPort->LOGO_timer = 3;  // we want 2 seconds
-                                              // but Timer granularity
-                                              // is 1 second
-             
-                                  // suspend any I/O in progress until
-                                  // PDISC received...
-
-          }
-          pLoggedInPort = pLoggedInPort->pNextPort;
-        }  // ... all Previously known ports checked
- 
-          // CpqTs acquired AL_PA in register AL_PA (ACQ_ALPA)
-        fcChip->Registers.rcv_al_pa.value = 
-          readl(fcChip->Registers.rcv_al_pa.address);
- 
-	// Now, if our acquired address is DIFFERENT from our
-        // previous one, we are not allow to do PDISC - we
-        // must go back to PLOGI, which will terminate I/O in
-        // progress for ALL logged in FC devices...
-	// (This is highly unlikely).
+					fcChip->fcStats.linkDown++;
 
-	if( (fcChip->Registers.my_al_pa & 0xFF) != 
-	    ((fcChip->Registers.rcv_al_pa.value >> 16) &0xFF) )
-	{
+					SetTachTOV(cpqfcHBAdata);	// must set according to SANMark
 
-//	  printk(" #our HBA port_id changed!# "); // FC port_id changed!!	
+					// Check the ERQ - force it to be "empty" to prevent Tach
+					// from sending out frames before we do logins.
 
-	  pLoggedInPort = &fcChip->fcPorts; 
-          while( pLoggedInPort ) // for all ports which are expecting
-                                 // PDISC after the next LIP, set the
-                                 // logoutTimer
-          {
-	    pLoggedInPort->pdisc  = FALSE;
-            pLoggedInPort->prli = FALSE;
-            pLoggedInPort = pLoggedInPort->pNextPort;
-          }  // ... all Previously known ports checked
-
-	  // when the port_id changes, we must terminate
-	  // all open exchanges.
-          cpqfcTSTerminateExchange( cpqfcHBAdata, NULL, PORTID_CHANGED);
-
-	}
-	               
-	// Replace the entire 24-bit port_id.  We only know the
-	// lower 8 bits (alpa) from Tachyon; if a FLOGI is done,
-	// we'll get the upper 16-bits from the FLOGI ACC frame.
-	// If someone plugs into Fabric switch, we'll do FLOGI and
-	// get full 24-bit port_id; someone could then remove and
-	// hot-plug us into a dumb hub.  If we send a 24-bit PLOGI
-	// to a "private" loop device, it might blow up.
-	// Consequently, we force the upper 16-bits of port_id to
-	// be re-set on every LinkUp transition
-        fcChip->Registers.my_al_pa =
-          (fcChip->Registers.rcv_al_pa.value >> 16) & 0xFF;
-
-              
-              // copy frame manager status to unused ULONG slot
-        fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1] =
-          fcChip->Registers.my_al_pa; // (for debugging)
-
-              // for TachLite, we need to write the acquired al_pa
-              // back into the FMconfig register, because after
-              // first initialization, the AQ (prev. acq.) bit gets
-              // set, causing TL FM to use the AL_PA field in FMconfig.
-              // (In Tachyon, FM writes the acquired AL_PA for us.)
-        ulBuff = readl( fcChip->Registers.FMconfig.address);
-        ulBuff &= 0x00ffffffL;  // mask out current al_pa
-        ulBuff |= ( fcChip->Registers.my_al_pa << 24 ); // or in acq. al_pa
-        fcChip->Registers.FMconfig.value = ulBuff; // copy it back
-        writel( fcChip->Registers.FMconfig.value,  // put in TachLite
-          fcChip->Registers.FMconfig.address);
-            
 
+					if (fcChip->ERQ->producerIndex != fcChip->ERQ->consumerIndex) {
+//        printk("#ERQ PI != CI#");
+						CpqTsFreezeTachlite(fcChip, 1);	// freeze ERQ only     
+						fcChip->ERQ->producerIndex = fcChip->ERQ->consumerIndex = 0;
+						writel(fcChip->ERQ->base, (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_BASE));
+						// re-writing base forces ERQ PI to equal CI
+
+					}
+					// link down transition occurred -- port_ids can change
+					// on next LinkUp, so we must invalidate current logins
+					// (and any I/O in progress) until PDISC or PLOGI/PRLI
+					// completes
+					{
+						pLoggedInPort = &fcChip->fcPorts;
+						while (pLoggedInPort)	// for all ports which are expecting
+							// PDISC after the next LIP, set the
+							// logoutTimer
+						{
+
+							if (pLoggedInPort->pdisc)	// expecting PDISC within 2 sec?
+							{
+								pLoggedInPort->LOGO_timer = 3;	// we want 2 seconds
+								// but Timer granularity
+								// is 1 second
+							}
+							// suspend any I/O in progress until
+							// PDISC received...
+							pLoggedInPort->prli = FALSE;	// block FCP-SCSI commands
+
+							pLoggedInPort = pLoggedInPort->pNextPort;
+						}	// ... all Previously known ports checked
+					}
+
+					// since any hot plugging device may NOT support LILP frames
+					// (such as early Tachyon chips), clear this flag indicating
+					// we shouldn't use (our copy of) a LILP map.
+					// If we receive an LILP frame, we'll set it again.
+					fcChip->Options.LILPin = 0;	// our LILPmap is invalid
+					cpqfcHBAdata->PortDiscDone = 0;	// must re-validate FC ports!
+
+					// also, we want to invalidate (i.e. INITIATOR_ABORT) any
+					// open Login exchanges, in case the LinkDown happened in the
+					// middle of logins.  It's possible that some ports already
+					// ACCepted login commands which we have not processed before
+					// another LinkDown occurred.  Any accepted Login exhanges are
+					// invalidated by LinkDown, even before they are acknowledged.
+					// It's also possible for a port to have a Queued Reply or Request
+					// for login which was interrupted by LinkDown; it may come later,
+					// but it will be unacceptable to us.
+
+					// we must scan the entire exchange space, find every Login type
+					// originated by us, and abort it. This is NOT an abort due to
+					// timeout, so we don't actually send abort to the other port -
+					// we just complete it to free up the fcExchange slot.
+
+					for (i = TACH_SEST_LEN; i < TACH_MAX_XID; i++) {	// looking for Extended Link Serv.Exchanges
+						if (Exchanges->fcExchange[i].type == ELS_PDISC || Exchanges->fcExchange[i].type == ELS_PLOGI || Exchanges->fcExchange[i].type == ELS_PRLI) {
+							// ABORT the exchange!
 #ifdef IMQ_DEBUG
-        printk("#LUp %Xh, FMstat 0x%08X#", 
-		fcChip->Registers.my_al_pa, fcChip->Registers.FMstatus.value);
+							printk("Originator ABORT x_id %Xh, type %Xh, port_id %Xh on LDn\n", i, Exchanges->fcExchange[i].type, Exchanges->fcExchange[i].fchs.d_id);
 #endif
 
-              // also set the WRITE-ONLY My_ID Register (for Fabric
-              // initialization)
-        writel( fcChip->Registers.my_al_pa,
-          fcChip->Registers.ReMapMemBase +TL_MEM_TACH_My_ID);
-          
-
-        fcChip->fcStats.linkUp++;
-
-                                     // reset TL statistics counters
-                                     // (we ignore these error counters
-                                     // while link is down)
-        ulBuff =                     // just reset TL's counter
-                 readl( fcChip->Registers.FMLinkStatus1.address);
-          
-        ulBuff =                     // just reset TL's counter
-                 readl( fcChip->Registers.FMLinkStatus2.address);
-
-          // for initiator, need to start verifying ports (e.g. PDISC)
+							Exchanges->fcExchange[i].status |= INITIATOR_ABORT;
+							cpqfcTSCompleteExchange(cpqfcHBAdata->PciDev, fcChip, i);	// abort on LDn
+						}
+					}
+
+				}
+				// ################   LINK UP   ##################
+				if (fcChip->Registers.FMstatus.value & 0x200L)	// Link Up bit
+				{	// AL_PA could have changed
+
+					// We need the following code, duplicated from LinkDn condition,
+					// because it's possible for the Tachyon to re-initialize (hard
+					// reset) without ever getting a LinkDn indication.
+					pLoggedInPort = &fcChip->fcPorts;
+					while (pLoggedInPort)	// for all ports which are expecting
+						// PDISC after the next LIP, set the
+						// logoutTimer
+					{
+						if (pLoggedInPort->pdisc)	// expecting PDISC within 2 sec?
+						{
+							pLoggedInPort->LOGO_timer = 3;	// we want 2 seconds
+							// but Timer granularity
+							// is 1 second
+
+							// suspend any I/O in progress until
+							// PDISC received...
+
+						}
+						pLoggedInPort = pLoggedInPort->pNextPort;
+					}	// ... all Previously known ports checked
+
+					// CpqTs acquired AL_PA in register AL_PA (ACQ_ALPA)
+					fcChip->Registers.rcv_al_pa.value = readl(fcChip->Registers.rcv_al_pa.address);
+
+					// Now, if our acquired address is DIFFERENT from our
+					// previous one, we are not allow to do PDISC - we
+					// must go back to PLOGI, which will terminate I/O in
+					// progress for ALL logged in FC devices...
+					// (This is highly unlikely).
+
+					if ((fcChip->Registers.my_al_pa & 0xFF) != ((fcChip->Registers.rcv_al_pa.value >> 16) & 0xFF)) {
+
+//        printk(" #our HBA port_id changed!# "); // FC port_id changed!!       
+
+						pLoggedInPort = &fcChip->fcPorts;
+						while (pLoggedInPort)	// for all ports which are expecting
+							// PDISC after the next LIP, set the
+							// logoutTimer
+						{
+							pLoggedInPort->pdisc = FALSE;
+							pLoggedInPort->prli = FALSE;
+							pLoggedInPort = pLoggedInPort->pNextPort;
+						}	// ... all Previously known ports checked
+
+						// when the port_id changes, we must terminate
+						// all open exchanges.
+						cpqfcTSTerminateExchange(cpqfcHBAdata, NULL, PORTID_CHANGED);
+
+					}
+					// Replace the entire 24-bit port_id.  We only know the
+					// lower 8 bits (alpa) from Tachyon; if a FLOGI is done,
+					// we'll get the upper 16-bits from the FLOGI ACC frame.
+					// If someone plugs into Fabric switch, we'll do FLOGI and
+					// get full 24-bit port_id; someone could then remove and
+					// hot-plug us into a dumb hub.  If we send a 24-bit PLOGI
+					// to a "private" loop device, it might blow up.
+					// Consequently, we force the upper 16-bits of port_id to
+					// be re-set on every LinkUp transition
+					fcChip->Registers.my_al_pa = (fcChip->Registers.rcv_al_pa.value >> 16) & 0xFF;
+
+
+					// copy frame manager status to unused u32 slot
+					fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1] = fcChip->Registers.my_al_pa;	// (for debugging)
+
+					// for TachLite, we need to write the acquired al_pa
+					// back into the FMconfig register, because after
+					// first initialization, the AQ (prev. acq.) bit gets
+					// set, causing TL FM to use the AL_PA field in FMconfig.
+					// (In Tachyon, FM writes the acquired AL_PA for us.)
+					ulBuff = readl(fcChip->Registers.FMconfig.address);
+					ulBuff &= 0x00ffffffL;	// mask out current al_pa
+					ulBuff |= (fcChip->Registers.my_al_pa << 24);	// or in acq. al_pa
+					fcChip->Registers.FMconfig.value = ulBuff;	// copy it back
+					writel(fcChip->Registers.FMconfig.value,	// put in TachLite
+					       fcChip->Registers.FMconfig.address);
 
 
+#ifdef IMQ_DEBUG
+					printk("#LUp %Xh, FMstat 0x%08X#", fcChip->Registers.my_al_pa, fcChip->Registers.FMstatus.value);
+#endif
 
-         
-      
-      
-	CpqTsUnFreezeTachlite( fcChip, 2); // unfreeze Tachlite, if Link OK
-	
-	// Tachyon creates an interesting problem for us on LILP frames.
-	// Instead of writing the incoming LILP frame into the SFQ before
-	// indicating LINK UP (the actual order of events), Tachyon tells
-	// us LINK UP, and later us the LILP.  So we delay, then examine the
-	// IMQ for an Inbound CM (x04); if found, we can set
-	// LINKACTIVE after processing the LILP.  Otherwise, just proceed.
-	// Since Tachyon imposes this time delay (and doesn't tell us
-	// what it is), we have to impose a delay before "Peeking" the IMQ
-	// for Tach hardware (DMA) delivery.
-	// Processing LILP is required by SANMark
-	udelay( 1000);  // microsec delay waiting for LILP (if it comes)
-        if( PeekIMQEntry( fcChip, ELS_LILP_FRAME) )
-	{  // found SFQ LILP, which will post LINKACTIVE	  
-//	  printk("skipping LINKACTIVE post\n");
+					// also set the WRITE-ONLY My_ID Register (for Fabric
+					// initialization)
+					writel(fcChip->Registers.my_al_pa, fcChip->Registers.ReMapMemBase + TL_MEM_TACH_My_ID);
+
+
+					fcChip->fcStats.linkUp++;
+
+					// reset TL statistics counters
+					// (we ignore these error counters
+					// while link is down)
+					ulBuff =	// just reset TL's counter
+					    readl(fcChip->Registers.FMLinkStatus1.address);
+
+					ulBuff =	// just reset TL's counter
+					    readl(fcChip->Registers.FMLinkStatus2.address);
+
+					// for initiator, need to start verifying ports (e.g. PDISC)
 
-	}
-	else
-          cpqfcTSPutLinkQue( cpqfcHBAdata, LINKACTIVE, ulFibreFrame);  
-      }
 
 
 
-      // ******* Set Fabric Login indication ********
-      if( fcChip->Registers.FMstatus.value & 0x2000 )
-      {
-	printk(" #Fabric# ");
-        fcChip->Options.fabric = 1;
-      }
-      else
-        fcChip->Options.fabric = 0;
-
-      
-      
-                             // ******* LIP(F8,x) or BAD AL_PA? ********
-      if( fcChip->Registers.FMstatus.value & 0x30000L )
-      {
-                        // copy the error AL_PAs
-        fcChip->Registers.rcv_al_pa.value = 
-          readl(fcChip->Registers.rcv_al_pa.address);
-            
-                        // Bad AL_PA?
-        if( fcChip->Registers.FMstatus.value & 0x10000L )
-        {
-          PFC_LOGGEDIN_PORT pLoggedInPort;
-        
-                       // copy "BAD" al_pa field
-          fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1] =
-              (fcChip->Registers.rcv_al_pa.value & 0xff00L) >> 8;
-
-	  pLoggedInPort = fcFindLoggedInPort( fcChip,
-            NULL,     // DON'T search Scsi Nexus
-            fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1], // port id
-            NULL,     // DON'T search linked list for FC WWN
-            NULL);    // DON'T care about end of list
- 
-	  if( pLoggedInPort )
-	  {
-            // Just in case we got this BAD_ALPA because a device
-	    // quietly disappeared (can happen on non-managed hubs such 
-	    // as the Vixel Rapport 1000),
-	    // do an Implicit Logout.  We never expect this on a Logged
-	    // in port (but do expect it on port discovery).
-	    // (As a reasonable alternative, this could be changed to 
-	    // simply start the implicit logout timer, giving the device
-	    // several seconds to "come back".)
-	    // 
-	    printk(" #BAD alpa %Xh# ",
-		   fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1]);
-            cpqfcTSImplicitLogout( cpqfcHBAdata, pLoggedInPort);
-	  }
-        }
-                        // LIP(f8,x)?
-        if( fcChip->Registers.FMstatus.value & 0x20000L )
-        {
-                        // for debugging, copy al_pa field
-          fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2] =
-              (fcChip->Registers.rcv_al_pa.value & 0xffL);
-                        // get the other port's al_pa
-                        // (one that sent LIP(F8,?) )
-        }
-      }
-
-                             // Elastic store err
-      if( fcChip->Registers.FMstatus.value & 0x400L )
-      {
-            // don't count e-s if loop is down!
-        if( !(USHORT)(fcChip->Registers.FMstatus.value & 0x80) )
-          fcChip->fcStats.e_stores++;
-          
-      }
-    }
-    break;
-
 
-    case INBOUND_FCP_XCHG_COMPLETION:  // 0x0C
 
-    // Remarks:
-    // On Tachlite TL/TS, we get this message when the data phase
-    // of a SEST inbound transfer is complete.  For example, if a WRITE command
-    // was received with OX_ID 0, we might respond with XFER_RDY with
-    // RX_ID 8001.  This would start the SEST controlled data phases.  When
-    // all data frames are received, we get this inbound completion. This means
-    // we should send a status frame to complete the status phase of the 
-    // FCP-SCSI exchange, using the same OX_ID,RX_ID that we used for data
-    // frames.
-    // See Outbound CM discussion of x_IDs
-    // Psuedo Code
-    //   Get SEST index (x_ID)
-    //     x_ID out of range, return (err condition)
-    //   set status bits from 2nd dword
-    //   free transactionID & SEST entry
-    //   call fcComplete with transactionID & status
-
-      ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0];
-      x_ID = ulBuff & 0x7fffL;  // lower 14 bits SEST_Index/Trans_ID
-                                // (mask out MSB "direction" bit)
-                                // Range check CM OX/RX_ID value...
-      if( x_ID < TACH_SEST_LEN )  // don't go beyond SEST array space
-      {
+					CpqTsUnFreezeTachlite(fcChip, 2);	// unfreeze Tachlite, if Link OK
+
+					// Tachyon creates an interesting problem for us on LILP frames.
+					// Instead of writing the incoming LILP frame into the SFQ before
+					// indicating LINK UP (the actual order of events), Tachyon tells
+					// us LINK UP, and later us the LILP.  So we delay, then examine the
+					// IMQ for an Inbound CM (x04); if found, we can set
+					// LINKACTIVE after processing the LILP.  Otherwise, just proceed.
+					// Since Tachyon imposes this time delay (and doesn't tell us
+					// what it is), we have to impose a delay before "Peeking" the IMQ
+					// for Tach hardware (DMA) delivery.
+					// Processing LILP is required by SANMark
+					udelay(1000);	// microsec delay waiting for LILP (if it comes)
+					if (PeekIMQEntry(fcChip, ELS_LILP_FRAME)) {	// found SFQ LILP, which will post LINKACTIVE          
+//        printk("skipping LINKACTIVE post\n");
+
+					} else
+						cpqfcTSPutLinkQue(cpqfcHBAdata, LINKACTIVE, ulFibreFrame);
+				}
+
+
+				// ******* Set Fabric Login indication ********
+				if (fcChip->Registers.FMstatus.value & 0x2000) {
+					printk(" #Fabric# ");
+					fcChip->Options.fabric = 1;
+				} else
+					fcChip->Options.fabric = 0;
+
+
+
+				// ******* LIP(F8,x) or BAD AL_PA? ********
+				if (fcChip->Registers.FMstatus.value & 0x30000L) {
+					// copy the error AL_PAs
+					fcChip->Registers.rcv_al_pa.value = readl(fcChip->Registers.rcv_al_pa.address);
+
+					// Bad AL_PA?
+					if (fcChip->Registers.FMstatus.value & 0x10000L) {
+						PFC_LOGGEDIN_PORT pLoggedInPort;
+
+						// copy "BAD" al_pa field
+						fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1] = (fcChip->Registers.rcv_al_pa.value & 0xff00L) >> 8;
+
+						pLoggedInPort = fcFindLoggedInPort(fcChip, NULL,	// DON'T search Scsi Nexus
+										   fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1],	// port id
+										   NULL,	// DON'T search linked list for FC WWN
+										   NULL);	// DON'T care about end of list
+
+						if (pLoggedInPort) {
+							// Just in case we got this BAD_ALPA because a device
+							// quietly disappeared (can happen on non-managed hubs such 
+							// as the Vixel Rapport 1000),
+							// do an Implicit Logout.  We never expect this on a Logged
+							// in port (but do expect it on port discovery).
+							// (As a reasonable alternative, this could be changed to 
+							// simply start the implicit logout timer, giving the device
+							// several seconds to "come back".)
+							// 
+							printk(" #BAD alpa %Xh# ", fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1]);
+							cpqfcTSImplicitLogout(cpqfcHBAdata, pLoggedInPort);
+						}
+					}
+					// LIP(f8,x)?
+					if (fcChip->Registers.FMstatus.value & 0x20000L) {
+						// for debugging, copy al_pa field
+						fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2] = (fcChip->Registers.rcv_al_pa.value & 0xffL);
+						// get the other port's al_pa
+						// (one that sent LIP(F8,?) )
+					}
+				}
+				// Elastic store err
+				if (fcChip->Registers.FMstatus.value & 0x400L) {
+					// don't count e-s if loop is down!
+					if (!(u16) (fcChip->Registers.FMstatus.value & 0x80))
+						fcChip->fcStats.e_stores++;
+
+				}
+			}
+			break;
+
+
+		case INBOUND_FCP_XCHG_COMPLETION:	// 0x0C
+
+			// Remarks:
+			// On Tachlite TL/TS, we get this message when the data phase
+			// of a SEST inbound transfer is complete.  For example, if a WRITE command
+			// was received with OX_ID 0, we might respond with XFER_RDY with
+			// RX_ID 8001.  This would start the SEST controlled data phases.  When
+			// all data frames are received, we get this inbound completion. This means
+			// we should send a status frame to complete the status phase of the 
+			// FCP-SCSI exchange, using the same OX_ID,RX_ID that we used for data
+			// frames.
+			// See Outbound CM discussion of x_IDs
+			// Psuedo Code
+			//   Get SEST index (x_ID)
+			//     x_ID out of range, return (err condition)
+			//   set status bits from 2nd dword
+			//   free transactionID & SEST entry
+			//   call fcComplete with transactionID & status
+
+			ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0];
+			x_ID = ulBuff & 0x7fffL;	// lower 14 bits SEST_Index/Trans_ID
+			// (mask out MSB "direction" bit)
+			// Range check CM OX/RX_ID value...
+			if (x_ID < TACH_SEST_LEN)	// don't go beyond SEST array space
+			{
 
 //#define FCP_COMPLETION_DBG 1
 #ifdef FCP_COMPLETION_DBG
-        printk(" FCP_CM x_ID %Xh, status %Xh, Cmnd %p\n", 
-          x_ID, ulBuff, Exchanges->fcExchange[x_ID].Cmnd);
+				printk(" FCP_CM x_ID %Xh, status %Xh, Cmnd %p\n", x_ID, ulBuff, Exchanges->fcExchange[x_ID].Cmnd);
 #endif
-        if( ulBuff & 0x08000000L ) // RPC -Response Phase Complete - or -
-                                   // time to send response frame?
-          RPCset = 1;             // (SEST transaction)
-        else
-          RPCset = 0;
-                // set the status for this Inbound SCSI transaction's ID
-        dwStatus = 0L;
-        if( ulBuff & 0x70000000L ) // any errs?
-        {
-          
-          if( ulBuff & 0x40000000L )
-            dwStatus |= LINKFAIL_RX;
-          
-	  if( ulBuff & 0x20000000L )
-            dwStatus |= COUNT_ERROR;
-          
-          if( ulBuff & 0x10000000L )
-            dwStatus |= OVERFLOW;
-        }
-      
-	
-	  // FCP transaction done - copy status
-        Exchanges->fcExchange[ x_ID ].status = dwStatus;
-
-
-        // Did the exchange get an FCP-RSP response frame?
-        // (Note the little endian/big endian FC payload difference)
-
-        if( RPCset )             // SEST transaction Response frame rec'd
-        {
-    	  // complete the command in our driver...
-          cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev,fcChip, x_ID);
-
-        }  // end "RPCset"
-	
-        else  // ("target" logic)
-        {
-            // Tachlite says all data frames have been received - now it's time
-            // to analyze data transfer (successful?), then send a response 
-            // frame for this exchange
-
-          ulFibreFrame[0] = x_ID; // copy for later reference
-
-          // if this was a TWE, we have to send satus response
-          if( Exchanges->fcExchange[ x_ID].type == SCSI_TWE )
-	  {
+				if (ulBuff & 0x08000000L)	// RPC -Response Phase Complete - or -
+					// time to send response frame?
+					RPCset = 1;	// (SEST transaction)
+				else
+					RPCset = 0;
+				// set the status for this Inbound SCSI transaction's ID
+				dwStatus = 0L;
+				if (ulBuff & 0x70000000L)	// any errs?
+				{
+
+					if (ulBuff & 0x40000000L)
+						dwStatus |= LINKFAIL_RX;
+
+					if (ulBuff & 0x20000000L)
+						dwStatus |= COUNT_ERROR;
+
+					if (ulBuff & 0x10000000L)
+						dwStatus |= OVERFLOW;
+				}
+
+				// FCP transaction done - copy status
+				Exchanges->fcExchange[x_ID].status = dwStatus;
+
+
+				// Did the exchange get an FCP-RSP response frame?
+				// (Note the little endian/big endian FC payload difference)
+
+				if (RPCset)	// SEST transaction Response frame rec'd
+				{
+					// complete the command in our driver...
+					cpqfcTSCompleteExchange(cpqfcHBAdata->PciDev, fcChip, x_ID);
+
+				}	// end "RPCset"
+
+				else	// ("target" logic)
+				{
+					// Tachlite says all data frames have been received - now it's time
+					// to analyze data transfer (successful?), then send a response 
+					// frame for this exchange
+
+					ulFibreFrame[0] = x_ID;	// copy for later reference
+
+					// if this was a TWE, we have to send satus response
+					if (Exchanges->fcExchange[x_ID].type == SCSI_TWE) {
 //            fcPutScsiQue( cpqfcHBAdata, 
 //                NEED_FCP_RSP, ulFibreFrame);  // (ulFibreFrame not used here)
-	  }
-        }
-      }
-      else  // ERROR CONDITION!  bogus x_ID in completion message
-      {
-        printk("IN FCP_XCHG: bad x_ID: %Xh\n", x_ID);
-      }
+					}
+				}
+			} else	// ERROR CONDITION!  bogus x_ID in completion message
+			{
+				printk("IN FCP_XCHG: bad x_ID: %Xh\n", x_ID);
+			}
 
-    break;
+			break;
 
 
 
 
-    case INBOUND_SCSI_DATA_COMMAND:
-    case BAD_SCSI_FRAME:
-    case INB_SCSI_STATUS_COMPLETION:
-    case BUFFER_PROCESSED_COMPLETION:
-    break;
-    }
+		case INBOUND_SCSI_DATA_COMMAND:
+		case BAD_SCSI_FRAME:
+		case INB_SCSI_STATUS_COMPLETION:
+		case BUFFER_PROCESSED_COMPLETION:
+			break;
+		}
+
+		// Tachyon is producing;
+		// we are consuming
+		fcChip->IMQ->consumerIndex++;	// increment OUR consumerIndex
+		if (fcChip->IMQ->consumerIndex >= IMQ_LEN)	// check for rollover
+			fcChip->IMQ->consumerIndex = 0L;	// reset it
+
+
+		if (fcChip->IMQ->producerIndex == fcChip->IMQ->consumerIndex) {	// all Messages are processed -
+			iStatus = 0;	// no more messages to process
+
+		} else
+			iStatus = 1;	// more messages to process
+
+		// update TachLite's ConsumerIndex... (clears INTA_L)
+		// NOTE: according to TL/TS UG, the 
+		// "host must return completion messages in sequential order".
+		// Does this mean one at a time, in the order received?  We
+		// presume so.
+
+		writel(fcChip->IMQ->consumerIndex, (fcChip->Registers.ReMapMemBase + IMQ_CONSUMER_INDEX));
 
-					   // Tachyon is producing;
-					   // we are consuming
-    fcChip->IMQ->consumerIndex++;             // increment OUR consumerIndex
-    if( fcChip->IMQ->consumerIndex >= IMQ_LEN)// check for rollover
-      fcChip->IMQ->consumerIndex = 0L;        // reset it
-
-
-    if( fcChip->IMQ->producerIndex == fcChip->IMQ->consumerIndex )
-    {                           // all Messages are processed -
-      iStatus = 0;              // no more messages to process
-
-    }
-    else
-      iStatus = 1;              // more messages to process
-
-    // update TachLite's ConsumerIndex... (clears INTA_L)
-    // NOTE: according to TL/TS UG, the 
-    // "host must return completion messages in sequential order".
-    // Does this mean one at a time, in the order received?  We
-    // presume so.
-
-    writel( fcChip->IMQ->consumerIndex,
-      (fcChip->Registers.ReMapMemBase + IMQ_CONSUMER_INDEX));
-		    
 #if IMQ_DEBUG
-    printk("Process IMQ: writing consumer ndx %d\n ", 
-      fcChip->IMQ->consumerIndex);
-    printk("PI %X, CI %X\n", 
-    fcChip->IMQ->producerIndex,fcChip->IMQ->consumerIndex );
+		printk("Process IMQ: writing consumer ndx %d\n ", fcChip->IMQ->consumerIndex);
+		printk("PI %X, CI %X\n", fcChip->IMQ->producerIndex, fcChip->IMQ->consumerIndex);
 #endif
-  
 
 
-  }
-  else
-  {
-   // hmmm... why did we get interrupted/called with no message?
-    iStatus = -1;               // nothing to process
+
+	} else {
+		// hmmm... why did we get interrupted/called with no message?
+		iStatus = -1;	// nothing to process
 #if IMQ_DEBUG
-    printk("Process IMQ: no message PI %Xh  CI %Xh", 
-      fcChip->IMQ->producerIndex,
-      fcChip->IMQ->consumerIndex);
+		printk("Process IMQ: no message PI %Xh  CI %Xh", fcChip->IMQ->producerIndex, fcChip->IMQ->consumerIndex);
 #endif
-  }
+	}
 
-  LEAVE("ProcessIMQEntry");
-  
-  return iStatus;
+	LEAVE("ProcessIMQEntry");
+
+	return iStatus;
 }
 
 
@@ -1648,31 +1496,29 @@
 //  -1 on fatal error
 //   0 on success
 
-int CpqTsInitializeTachLite( void *pHBA, int opcode1, int opcode2)
+int CpqTsInitializeTachLite(void *pHBA, int opcode1, int opcode2)
 {
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  ULONG ulBuff;
-  UCHAR bBuff;
-  int iStatus=-1;  // assume failure
+	CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *) pHBA;
+	PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+	u32 ulBuff;
+	u8 bBuff;
+	int iStatus = -1;	// assume failure
 
-  ENTER("InitializeTachLite");
+	ENTER("InitializeTachLite");
 
-  // verify board's base address (sanity check)
+	// verify board's base address (sanity check)
 
-  if( !fcChip->Registers.ReMapMemBase)                // NULL address for card?
-    return -1;                         // FATAL error!
+	if (!fcChip->Registers.ReMapMemBase)	// NULL address for card?
+		return -1;	// FATAL error!
 
 
 
-  switch( opcode1 )
-  {
-    case 1:       // restore hardware to power-on (hard) restart
+	switch (opcode1) {
+	case 1:		// restore hardware to power-on (hard) restart
 
 
-      iStatus = fcChip->ResetTachyon( 
-		  cpqfcHBAdata, opcode2); // laser off, reset hardware
-				      // de-allocate aligned buffers
+		iStatus = fcChip->ResetTachyon(cpqfcHBAdata, opcode2);	// laser off, reset hardware
+		// de-allocate aligned buffers
 
 
 /* TBD      // reset FC link Q (producer and consumer = 0)
@@ -1680,17 +1526,17 @@
 
 */
 
-      if( iStatus )
-        break;
+		if (iStatus)
+			break;
 
-    case 2:       // Config PCI/Tachyon registers
-      // NOTE: For Tach TL/TS, bit 31 must be set to 1.  For TS chips, a read
-      // of bit 31 indicates state of M66EN signal; if 1, chip may run at 
-      // 33-66MHz  (see TL/TS UG, pg 159)
+	case 2:		// Config PCI/Tachyon registers
+		// NOTE: For Tach TL/TS, bit 31 must be set to 1.  For TS chips, a read
+		// of bit 31 indicates state of M66EN signal; if 1, chip may run at 
+		// 33-66MHz  (see TL/TS UG, pg 159)
 
-      ulBuff = 0x80000000;  // TachLite Configuration Register
+		ulBuff = 0x80000000;	// TachLite Configuration Register
 
-      writel( ulBuff, fcChip->Registers.TYconfig.address);
+		writel(ulBuff, fcChip->Registers.TYconfig.address);
 //      ulBuff = 0x0147L;  // CpqTs PCI CFGCMD register
 //      WritePCIConfiguration( fcChip->Backplane.bus,
 //                           fcChip->Backplane.slot, TLCFGCMD, ulBuff, 4);
@@ -1698,80 +1544,70 @@
 //      ReadPCIConfiguration( fcChip->Backplane.bus,
 //                           fcChip->Backplane.slot, TLCFGCMD, &ulBuff, 4);
 
-      // read back for reference...
-      fcChip->Registers.TYconfig.value = 
-         readl( fcChip->Registers.TYconfig.address );
-
-      // what is the PCI bus width?
-      pci_read_config_byte( cpqfcHBAdata->PciDev,
-                                0x43, // PCIMCTR offset
-                                &bBuff);
-      
-      fcChip->Registers.PCIMCTR = bBuff;
-
-      // set string identifying the chip on the circuit board
-
-      fcChip->Registers.TYstatus.value =
-        readl( fcChip->Registers.TYstatus.address);
-      
-      {
+		// read back for reference...
+		fcChip->Registers.TYconfig.value = readl(fcChip->Registers.TYconfig.address);
+
+		// what is the PCI bus width?
+		pci_read_config_byte(cpqfcHBAdata->PciDev, 0x43,	// PCIMCTR offset
+				     &bBuff);
+
+		fcChip->Registers.PCIMCTR = bBuff;
+
+		// set string identifying the chip on the circuit board
+
+		fcChip->Registers.TYstatus.value = readl(fcChip->Registers.TYstatus.address);
+
+		{
 // Now that we are supporting multiple boards, we need to change
 // this logic to check for PCI vendor/device IDs...
 // for now, quick & dirty is simply checking Chip rev
-	
-	ULONG RevId = (fcChip->Registers.TYstatus.value &0x3E0)>>5;
-	UCHAR Minor = (UCHAR)(RevId & 0x3);
-	UCHAR Major = (UCHAR)((RevId & 0x1C) >>2);
-  
-        printk("  HBA Tachyon RevId %d.%d\n", Major, Minor);
-  	if( (Major == 1) && (Minor == 2) )
-        {
-	  sprintf( cpqfcHBAdata->fcChip.Name, STACHLITE66_TS12);
-
-	}
-	else if( (Major == 1) && (Minor == 3) )
-        {
-	  sprintf( cpqfcHBAdata->fcChip.Name, STACHLITE66_TS13);
-	}
-	else if( (Major == 2) && (Minor == 1) )
-        {
-	  sprintf( cpqfcHBAdata->fcChip.Name, SAGILENT_XL2_21);
-	}
-	else
-	  sprintf( cpqfcHBAdata->fcChip.Name, STACHLITE_UNKNOWN);
-      }
+
+			u32 RevId = (fcChip->Registers.TYstatus.value & 0x3E0) >> 5;
+			u8 Minor = (u8) (RevId & 0x3);
+			u8 Major = (u8) ((RevId & 0x1C) >> 2);
+
+			printk("  HBA Tachyon RevId %d.%d\n", Major, Minor);
+			if ((Major == 1) && (Minor == 2)) {
+				sprintf(cpqfcHBAdata->fcChip.Name, STACHLITE66_TS12);
+
+			} else if ((Major == 1) && (Minor == 3)) {
+				sprintf(cpqfcHBAdata->fcChip.Name, STACHLITE66_TS13);
+			} else if ((Major == 2) && (Minor == 1)) {
+				sprintf(cpqfcHBAdata->fcChip.Name, SAGILENT_XL2_21);
+			} else
+				sprintf(cpqfcHBAdata->fcChip.Name, STACHLITE_UNKNOWN);
+		}
 
 
 
-    case 3:       // allocate mem, set Tachyon Que registers
-      iStatus = CpqTsCreateTachLiteQues( cpqfcHBAdata, opcode2);
+	case 3:		// allocate mem, set Tachyon Que registers
+		iStatus = CpqTsCreateTachLiteQues(cpqfcHBAdata, opcode2);
+
+		if (iStatus)
+			break;
+
+		// now that the Queues exist, Tach can DMA to them, so
+		// we can begin processing INTs
+		// INTEN register - enable INT (TachLite interrupt)
+		writeb(0x1F, fcChip->Registers.ReMapMemBase + IINTEN);
+
+		// Fall through
+	case 4:		// Config Fame Manager, Init Loop Command, laser on
+
+		// L_PORT or loopback
+		// depending on Options
+		iStatus = CpqTsInitializeFrameManager(fcChip, 0);
+		if (iStatus) {
+			// failed to initialize Frame Manager
+			break;
+		}
 
-      if( iStatus )
-        break;
-
-      // now that the Queues exist, Tach can DMA to them, so
-      // we can begin processing INTs
-      // INTEN register - enable INT (TachLite interrupt)
-      writeb( 0x1F, fcChip->Registers.ReMapMemBase + IINTEN);
-
-	// Fall through
-    case 4:       // Config Fame Manager, Init Loop Command, laser on
-
-                 // L_PORT or loopback
-                 // depending on Options
-      iStatus = CpqTsInitializeFrameManager( fcChip,0 );
-      if( iStatus )
-      {
-           // failed to initialize Frame Manager
-	      break;
-      }
-
-    default:
-      break;
-  }
-  LEAVE("InitializeTachLite");
-  
-  return iStatus;
+	default:
+		break;
+	}
+	LEAVE("InitializeTachLite");
+
+	return iStatus;
 }
 
 
@@ -1782,101 +1618,86 @@
 // Order of allocation: see other function
 
 
-int CpqTsDestroyTachLiteQues( void *pHBA, int opcode)
+int CpqTsDestroyTachLiteQues(void *pHBA, int opcode)
 {
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  USHORT i, iStatus=0;
-  void* vPtr;  // mem Align manager sets this to the freed address on success
-  unsigned long ulPtr;  // for 64-bit pointer cast (e.g. Alpa machine)
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  PSGPAGES j, next;
-
-  ENTER("DestroyTachLiteQues");
-
-  if( fcChip->SEST )
-  {
-                // search out and free Pool for Extended S/G list pages
-
-    for( i=0; i < TACH_SEST_LEN; i++)  // for each exchange
-    {
-      // It's possible that extended S/G pages were allocated, mapped, and
-      // not cleared due to error conditions or O/S driver termination.
-      // Make sure they're all gone.
-      if (Exchanges->fcExchange[i].Cmnd != NULL) 
-      	cpqfc_pci_unmap(cpqfcHBAdata->PciDev, Exchanges->fcExchange[i].Cmnd, 
-			fcChip, i); // undo DMA mappings.
-
-      for (j=fcChip->SEST->sgPages[i] ; j != NULL ; j = next) {
-		next = j->next;
-		kfree(j);
-      }
-      fcChip->SEST->sgPages[i] = NULL;
-    }
-    ulPtr = (unsigned long)fcChip->SEST;
-    vPtr = fcMemManager( cpqfcHBAdata->PciDev, 
-		    &cpqfcHBAdata->dynamic_mem[0],
-		    0,0, (ULONG)ulPtr, NULL ); // 'free' mem
-    fcChip->SEST = 0L;  // null invalid ptr
-    if( !vPtr )
-    {
-      printk("SEST mem not freed\n");
-      iStatus = -1;
-    }
-  }
-
-  if( fcChip->SFQ )
-  {
-
-    ulPtr = (unsigned long)fcChip->SFQ;
-    vPtr = fcMemManager( cpqfcHBAdata->PciDev, 
-		    &cpqfcHBAdata->dynamic_mem[0],
-		    0,0, (ULONG)ulPtr, NULL ); // 'free' mem
-    fcChip->SFQ = 0L;  // null invalid ptr
-    if( !vPtr )
-    {
-      printk("SFQ mem not freed\n");
-      iStatus = -2;
-    }
-  }
-
-
-  if( fcChip->IMQ )
-  {
-      // clear Indexes to show empty Queue
-    fcChip->IMQ->producerIndex = 0;
-    fcChip->IMQ->consumerIndex = 0;
-
-    ulPtr = (unsigned long)fcChip->IMQ;
-    vPtr = fcMemManager( cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0],
-		    0,0, (ULONG)ulPtr, NULL ); // 'free' mem
-    fcChip->IMQ = 0L;  // null invalid ptr
-    if( !vPtr )
-    {
-      printk("IMQ mem not freed\n");
-      iStatus = -3;
-    }
-  }
-
-  if( fcChip->ERQ )         // release memory blocks used by the queues
-  {
-    ulPtr = (unsigned long)fcChip->ERQ;
-    vPtr = fcMemManager( cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0],
-		    0,0, (ULONG)ulPtr, NULL ); // 'free' mem
-    fcChip->ERQ = 0L;  // null invalid ptr
-    if( !vPtr )
-    {
-      printk("ERQ mem not freed\n");
-      iStatus = -4;
-    }
-  }
-    
-  // free up the primary EXCHANGES struct and Link Q
-  cpqfc_free_dma_consistent(cpqfcHBAdata);
-  
-  LEAVE("DestroyTachLiteQues");
-  
-  return iStatus;     // non-zero (failed) if any memory not freed
+	CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *) pHBA;
+	PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+	u16 i, iStatus = 0;
+	void *vPtr;		// mem Align manager sets this to the freed address on success
+	unsigned long ulPtr;	// for 64-bit pointer cast (e.g. Alpa machine)
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	PSGPAGES j, next;
+
+	ENTER("DestroyTachLiteQues");
+
+	if (fcChip->SEST) {
+		// search out and free Pool for Extended S/G list pages
+
+		for (i = 0; i < TACH_SEST_LEN; i++)	// for each exchange
+		{
+			// It's possible that extended S/G pages were allocated, mapped, and
+			// not cleared due to error conditions or O/S driver termination.
+			// Make sure they're all gone.
+			if (Exchanges->fcExchange[i].Cmnd != NULL)
+				cpqfc_pci_unmap(cpqfcHBAdata->PciDev, Exchanges->fcExchange[i].Cmnd, fcChip, i);	// undo DMA mappings.
+
+			for (j = fcChip->SEST->sgPages[i]; j != NULL; j = next) {
+				next = j->next;
+				kfree(j);
+			}
+			fcChip->SEST->sgPages[i] = NULL;
+		}
+		ulPtr = (unsigned long) fcChip->SEST;
+		vPtr = fcMemManager(cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0], 0, 0, (u32) ulPtr, NULL);	// 'free' mem
+		fcChip->SEST = 0L;	// null invalid ptr
+		if (!vPtr) {
+			printk("SEST mem not freed\n");
+			iStatus = -1;
+		}
+	}
+
+	if (fcChip->SFQ) {
+
+		ulPtr = (unsigned long) fcChip->SFQ;
+		vPtr = fcMemManager(cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0], 0, 0, (u32) ulPtr, NULL);	// 'free' mem
+		fcChip->SFQ = 0L;	// null invalid ptr
+		if (!vPtr) {
+			printk("SFQ mem not freed\n");
+			iStatus = -2;
+		}
+	}
+
+
+	if (fcChip->IMQ) {
+		// clear Indexes to show empty Queue
+		fcChip->IMQ->producerIndex = 0;
+		fcChip->IMQ->consumerIndex = 0;
+
+		ulPtr = (unsigned long) fcChip->IMQ;
+		vPtr = fcMemManager(cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0], 0, 0, (u32) ulPtr, NULL);	// 'free' mem
+		fcChip->IMQ = 0L;	// null invalid ptr
+		if (!vPtr) {
+			printk("IMQ mem not freed\n");
+			iStatus = -3;
+		}
+	}
+
+	if (fcChip->ERQ)	// release memory blocks used by the queues
+	{
+		ulPtr = (unsigned long) fcChip->ERQ;
+		vPtr = fcMemManager(cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0], 0, 0, (u32) ulPtr, NULL);	// 'free' mem
+		fcChip->ERQ = 0L;	// null invalid ptr
+		if (!vPtr) {
+			printk("ERQ mem not freed\n");
+			iStatus = -4;
+		}
+	}
+	// free up the primary EXCHANGES struct and Link Q
+	cpqfc_free_dma_consistent(cpqfcHBAdata);
+
+	LEAVE("DestroyTachLiteQues");
+
+	return iStatus;		// non-zero (failed) if any memory not freed
 }
 
 
@@ -1896,44 +1717,35 @@
 //   length from the completion message.  The caller passes a buffer large
 //   enough for the complete message (max 2k).
 
-static void CpqTsGetSFQEntry(
-         PTACHYON fcChip,
-         USHORT producerNdx,
-         ULONG *ulDestPtr,            // contiguous destination buffer
-	 BOOLEAN UpdateChip)
+static void CpqTsGetSFQEntry(PTACHYON fcChip, u16 producerNdx, u32 * ulDestPtr,	// contiguous destination buffer
+			     u8 UpdateChip)
 {
-  ULONG total_bytes=0;
-  ULONG consumerIndex = fcChip->SFQ->consumerIndex;
-  
-				// check passed copy of SFQ producer index -
-				// is a new message waiting for us?
-				// equal indexes means SFS is copied
-
-  while( producerNdx != consumerIndex )
-  {                             // need to process message
-    total_bytes += 64;   // maintain count to prevent writing past buffer
-                   // don't allow copies over Fibre Channel defined length!
-    if( total_bytes <= 2048 )
-    {
-      memcpy( ulDestPtr, 
-              &fcChip->SFQ->QEntry[consumerIndex],
-              64 );  // each SFQ entry is 64 bytes
-      ulDestPtr += 16;   // advance pointer to next 64 byte block
-    }
-		         // Tachyon is producing,
-                         // and we are consuming
-
-    if( ++consumerIndex >= SFQ_LEN)// check for rollover
-      consumerIndex = 0L;        // reset it
-  }
-
-  // if specified, update the Tachlite chip ConsumerIndex...
-  if( UpdateChip )
-  {
-    fcChip->SFQ->consumerIndex = consumerIndex;
-    writel( fcChip->SFQ->consumerIndex,
-      fcChip->Registers.SFQconsumerIndex.address);
-  }
+	u32 total_bytes = 0;
+	u32 consumerIndex = fcChip->SFQ->consumerIndex;
+
+	// check passed copy of SFQ producer index -
+	// is a new message waiting for us?
+	// equal indexes means SFS is copied
+
+	while (producerNdx != consumerIndex) {	// need to process message
+		total_bytes += 64;	// maintain count to prevent writing past buffer
+		// don't allow copies over Fibre Channel defined length!
+		if (total_bytes <= 2048) {
+			memcpy(ulDestPtr, &fcChip->SFQ->QEntry[consumerIndex], 64);	// each SFQ entry is 64 bytes
+			ulDestPtr += 16;	// advance pointer to next 64 byte block
+		}
+		// Tachyon is producing,
+		// and we are consuming
+
+		if (++consumerIndex >= SFQ_LEN)	// check for rollover
+			consumerIndex = 0L;	// reset it
+	}
+
+	// if specified, update the Tachlite chip ConsumerIndex...
+	if (UpdateChip) {
+		fcChip->SFQ->consumerIndex = consumerIndex;
+		writel(fcChip->SFQ->consumerIndex, fcChip->Registers.SFQconsumerIndex.address);
+	}
 }
 
 
@@ -1944,42 +1756,38 @@
 // we routinely RESUME by clearing these bits, but only if the loop is up
 // to avoid ERROR IDLE messages forever.
 
-void CpqTsUnFreezeTachlite( void *pChip, int type )
+void CpqTsUnFreezeTachlite(void *pChip, int type)
 {
-  PTACHYON fcChip = (PTACHYON)pChip;
-  fcChip->Registers.TYcontrol.value = 
-    readl(fcChip->Registers.TYcontrol.address);
-            
-  // (bit 4 of value is GBIC LASER)
-  // if we 'unfreeze' the core machines before the loop is healthy
-  // (i.e. FLT, OS, LS failure bits set in FMstatus)
-  // we can get 'error idle' messages forever.  Verify that
-  // FMstatus (Link Status) is OK before unfreezing.
-
-  if( !(fcChip->Registers.FMstatus.value & 0x07000000L) && // bits clear?
-      !(fcChip->Registers.FMstatus.value & 0x80  ))  // Active LPSM?
-  {
-    fcChip->Registers.TYcontrol.value &=  ~0x300L; // clear FEQ, FFA
-    if( type == 1 )  // unfreeze ERQ only
-    {
+	PTACHYON fcChip = (PTACHYON) pChip;
+	fcChip->Registers.TYcontrol.value = readl(fcChip->Registers.TYcontrol.address);
+
+	// (bit 4 of value is GBIC LASER)
+	// if we 'unfreeze' the core machines before the loop is healthy
+	// (i.e. FLT, OS, LS failure bits set in FMstatus)
+	// we can get 'error idle' messages forever.  Verify that
+	// FMstatus (Link Status) is OK before unfreezing.
+
+	if (!(fcChip->Registers.FMstatus.value & 0x07000000L) &&	// bits clear?
+	    !(fcChip->Registers.FMstatus.value & 0x80))	// Active LPSM?
+	{
+		fcChip->Registers.TYcontrol.value &= ~0x300L;	// clear FEQ, FFA
+		if (type == 1)	// unfreeze ERQ only
+		{
 //      printk("Unfreezing ERQ\n");
-      fcChip->Registers.TYcontrol.value |= 0x10000L; // set REQ
-    }
-    else             // unfreeze both ERQ and FCP-ASSIST (SEST)
-    {
+			fcChip->Registers.TYcontrol.value |= 0x10000L;	// set REQ
+		} else		// unfreeze both ERQ and FCP-ASSIST (SEST)
+		{
 //      printk("Unfreezing ERQ & FCP-ASSIST\n");
 
-                     // set ROF, RIF, REQ - resume Outbound FCP, Inbnd FCP, ERQ
-      fcChip->Registers.TYcontrol.value |= 0x70000L; // set ROF, RIF, REQ
-    }
-
-    writel( fcChip->Registers.TYcontrol.value,
-      fcChip->Registers.TYcontrol.address);
-              
-  }
-          // readback for verify (TachLite still frozen?)
-  fcChip->Registers.TYstatus.value = 
-    readl(fcChip->Registers.TYstatus.address);
+			// set ROF, RIF, REQ - resume Outbound FCP, Inbnd FCP, ERQ
+			fcChip->Registers.TYcontrol.value |= 0x70000L;	// set ROF, RIF, REQ
+		}
+
+		writel(fcChip->Registers.TYcontrol.value, fcChip->Registers.TYcontrol.address);
+
+	}
+	// readback for verify (TachLite still frozen?)
+	fcChip->Registers.TYstatus.value = readl(fcChip->Registers.TYstatus.address);
 }
 
 
@@ -1990,21 +1798,19 @@
 // This freeze function will result in FCP & ERQ FROZEN completion
 // messages (per argument "type").
 
-void CpqTsFreezeTachlite( void *pChip, int type )
+void CpqTsFreezeTachlite(void *pChip, int type)
 {
-  PTACHYON fcChip = (PTACHYON)pChip;
-  fcChip->Registers.TYcontrol.value = 
-    readl(fcChip->Registers.TYcontrol.address);
-    
-                     //set FFA, FEQ - freezes SCSI assist and ERQ
-  if( type == 1)    // freeze ERQ only
-    fcChip->Registers.TYcontrol.value |= 0x100L; // (bit 4 is laser)
-  else              // freeze both FCP assists (SEST) and ERQ
-    fcChip->Registers.TYcontrol.value |= 0x300L; // (bit 4 is laser)
-  
-  writel( fcChip->Registers.TYcontrol.value,
-    fcChip->Registers.TYcontrol.address);
-              
+	PTACHYON fcChip = (PTACHYON) pChip;
+	fcChip->Registers.TYcontrol.value = readl(fcChip->Registers.TYcontrol.address);
+
+	//set FFA, FEQ - freezes SCSI assist and ERQ
+	if (type == 1)		// freeze ERQ only
+		fcChip->Registers.TYcontrol.value |= 0x100L;	// (bit 4 is laser)
+	else			// freeze both FCP assists (SEST) and ERQ
+		fcChip->Registers.TYcontrol.value |= 0x300L;	// (bit 4 is laser)
+
+	writel(fcChip->Registers.TYcontrol.value, fcChip->Registers.TYcontrol.address);
+
 }
 
 
@@ -2018,8 +1824,8 @@
 
 void fcParseLinkStatusCounters(PTACHYON fcChip)
 {
-  UCHAR bBuff;
-  ULONG ulBuff;
+	u8 bBuff;
+	u32 ulBuff;
 
 
 // The BB0 timer usually increments when TL is initialized, resulting
@@ -2028,61 +1834,58 @@
 // Also, reading the register does not clear it, so we have to keep an
 // additional static counter to detect rollover (yuk).
 
-  if( fcChip->fcStats.lastBB0timer == 0L)  // TL was reset? (ignore 1st values)
-  {
-                           // get TL's register counter - the "last" count
-    fcChip->fcStats.lastBB0timer = 
-      fcChip->Registers.FMBB_CreditZero.value & 0x00ffffffL;
-  }
-  else  // subsequent pass - check for rollover
-  {
-                              // "this" count
-    ulBuff = fcChip->Registers.FMBB_CreditZero.value & 0x00ffffffL;
-    if( fcChip->fcStats.lastBB0timer > ulBuff ) // rollover happened
-    {
-                                // counter advanced to max...
-      fcChip->fcStats.BB0_Timer += (0x00FFFFFFL - fcChip->fcStats.lastBB0timer);
-      fcChip->fcStats.BB0_Timer += ulBuff;  // plus some more
-
-
-    }
-    else // no rollover -- more counts or no change
-    {
-      fcChip->fcStats.BB0_Timer +=  (ulBuff - fcChip->fcStats.lastBB0timer);
+	if (fcChip->fcStats.lastBB0timer == 0L)	// TL was reset? (ignore 1st values)
+	{
+		// get TL's register counter - the "last" count
+		fcChip->fcStats.lastBB0timer = fcChip->Registers.FMBB_CreditZero.value & 0x00ffffffL;
+	} else			// subsequent pass - check for rollover
+	{
+		// "this" count
+		ulBuff = fcChip->Registers.FMBB_CreditZero.value & 0x00ffffffL;
+		if (fcChip->fcStats.lastBB0timer > ulBuff)	// rollover happened
+		{
+			// counter advanced to max...
+			fcChip->fcStats.BB0_Timer += (0x00FFFFFFL - fcChip->fcStats.lastBB0timer);
+			fcChip->fcStats.BB0_Timer += ulBuff;	// plus some more
+
+
+		} else		// no rollover -- more counts or no change
+		{
+			fcChip->fcStats.BB0_Timer += (ulBuff - fcChip->fcStats.lastBB0timer);
 
-    }
+		}
 
-    fcChip->fcStats.lastBB0timer = ulBuff;
-  }
+		fcChip->fcStats.lastBB0timer = ulBuff;
+	}
 
 
 
-  bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus1.value >> 24);
-  fcChip->fcStats.LossofSignal += bBuff;
+	bBuff = (u8) (fcChip->Registers.FMLinkStatus1.value >> 24);
+	fcChip->fcStats.LossofSignal += bBuff;
 
-  bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus1.value >> 16);
-  fcChip->fcStats.BadRXChar += bBuff;
+	bBuff = (u8) (fcChip->Registers.FMLinkStatus1.value >> 16);
+	fcChip->fcStats.BadRXChar += bBuff;
 
-  bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus1.value >> 8);
-  fcChip->fcStats.LossofSync += bBuff;
+	bBuff = (u8) (fcChip->Registers.FMLinkStatus1.value >> 8);
+	fcChip->fcStats.LossofSync += bBuff;
 
 
-  bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus2.value >> 24);
-  fcChip->fcStats.Rx_EOFa += bBuff;
+	bBuff = (u8) (fcChip->Registers.FMLinkStatus2.value >> 24);
+	fcChip->fcStats.Rx_EOFa += bBuff;
 
-  bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus2.value >> 16);
-  fcChip->fcStats.Dis_Frm += bBuff;
+	bBuff = (u8) (fcChip->Registers.FMLinkStatus2.value >> 16);
+	fcChip->fcStats.Dis_Frm += bBuff;
 
-  bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus2.value >> 8);
-  fcChip->fcStats.Bad_CRC += bBuff;
+	bBuff = (u8) (fcChip->Registers.FMLinkStatus2.value >> 8);
+	fcChip->fcStats.Bad_CRC += bBuff;
 }
 
 
 void cpqfcTSClearLinkStatusCounters(PTACHYON fcChip)
 {
-  ENTER("ClearLinkStatusCounters");
-  memset( &fcChip->fcStats, 0, sizeof( FCSTATS));
-  LEAVE("ClearLinkStatusCounters");
+	ENTER("ClearLinkStatusCounters");
+	memset(&fcChip->fcStats, 0, sizeof(FCSTATS));
+	LEAVE("ClearLinkStatusCounters");
 
 }
 
@@ -2110,77 +1913,74 @@
 // be correctly loaded by Tachyon silicon.  In the login payload, bytes
 // must be correctly swapped for Big Endian format.
 
-int CpqTsReadWriteWWN( PVOID pChip, int Read)
+int CpqTsReadWriteWWN(void * pChip, int Read)
 {
-  PTACHYON fcChip = (PTACHYON)pChip;
+	PTACHYON fcChip = (PTACHYON) pChip;
 #define NVRAM_SIZE 512
-  unsigned short i, count = NVRAM_SIZE;
-  UCHAR nvRam[NVRAM_SIZE], WWNbuf[8];
-  ULONG ulBuff;
-  int iStatus=-1;  // assume failure
-  int WWNoffset;
-
-  ENTER("ReadWriteWWN");
-  // Now try to read the WWN from the adapter's NVRAM
-
-  if( Read )  // READing NVRAM WWN?
-  {
-    ulBuff = cpqfcTS_ReadNVRAM( fcChip->Registers.TYstatus.address,
-                              fcChip->Registers.TYcontrol.address,
-                              count, &nvRam[0] );
-
-    if( ulBuff )   // NVRAM read successful?
-    {
-      iStatus = 0; // success!
-      
-                   // for engineering/ prototype boards, the data may be
-                   // invalid (GIGO, usually all "FF"); this prevents the
-                   // parse routine from working correctly, which means
-                   // nothing will be written to our passed buffer.
-
-      WWNoffset = cpqfcTS_GetNVRAM_data( WWNbuf, nvRam );
-
-      if( !WWNoffset ) // uninitialized NVRAM -- copy bytes directly
-      {
-        printk( "CAUTION: Copying NVRAM data on fcChip\n");
-        for( i= 0; i < 8; i++)
-          WWNbuf[i] = nvRam[i +0x2f]; // dangerous! some formats won't work
-      }
-      
-      fcChip->Registers.wwn_hi = 0L;
-      fcChip->Registers.wwn_lo = 0L;
-      for( i=0; i<4; i++)  // WWN bytes are big endian in NVRAM
-      {
-        ulBuff = 0L;
-        ulBuff = (ULONG)(WWNbuf[i]) << (8 * (3-i));
-        fcChip->Registers.wwn_hi |= ulBuff;
-      }
-      for( i=0; i<4; i++)  // WWN bytes are big endian in NVRAM
-      {
-        ulBuff = 0L;
-        ulBuff = (ULONG)(WWNbuf[i+4]) << (8 * (3-i));
-        fcChip->Registers.wwn_lo |= ulBuff;
-      }
-    }  // done reading
-    else
-    {
-
-      printk( "cpqfcTS: NVRAM read failed\n");
-
-    }
-  }
-
-  else  // WRITE
-  {
-
-    // NOTE: WRITE not supported & not used in released driver.
-
-   
-    printk("ReadWriteNRAM: can't write NVRAM; aborting write\n");
-  }
-  
-  LEAVE("ReadWriteWWN");
-  return iStatus;
+	unsigned short i, count = NVRAM_SIZE;
+	u8 nvRam[NVRAM_SIZE], WWNbuf[8];
+	u32 ulBuff;
+	int iStatus = -1;	// assume failure
+	int WWNoffset;
+
+	ENTER("ReadWriteWWN");
+	// Now try to read the WWN from the adapter's NVRAM
+
+	if (Read)		// READing NVRAM WWN?
+	{
+		ulBuff = cpqfcTS_ReadNVRAM(fcChip->Registers.TYstatus.address, fcChip->Registers.TYcontrol.address, count, &nvRam[0]);
+
+		if (ulBuff)	// NVRAM read successful?
+		{
+			iStatus = 0;	// success!
+
+			// for engineering/ prototype boards, the data may be
+			// invalid (GIGO, usually all "FF"); this prevents the
+			// parse routine from working correctly, which means
+			// nothing will be written to our passed buffer.
+
+			WWNoffset = cpqfcTS_GetNVRAM_data(WWNbuf, nvRam);
+
+			if (!WWNoffset)	// uninitialized NVRAM -- copy bytes directly
+			{
+				printk("CAUTION: Copying NVRAM data on fcChip\n");
+				for (i = 0; i < 8; i++)
+					WWNbuf[i] = nvRam[i + 0x2f];	// dangerous! some formats won't work
+			}
+
+			fcChip->Registers.wwn_hi = 0L;
+			fcChip->Registers.wwn_lo = 0L;
+			for (i = 0; i < 4; i++)	// WWN bytes are big endian in NVRAM
+			{
+				ulBuff = 0L;
+				ulBuff = (u32) (WWNbuf[i]) << (8 * (3 - i));
+				fcChip->Registers.wwn_hi |= ulBuff;
+			}
+			for (i = 0; i < 4; i++)	// WWN bytes are big endian in NVRAM
+			{
+				ulBuff = 0L;
+				ulBuff = (u32) (WWNbuf[i + 4]) << (8 * (3 - i));
+				fcChip->Registers.wwn_lo |= ulBuff;
+			}
+		}		// done reading
+		else {
+
+			printk("cpqfcTS: NVRAM read failed\n");
+
+		}
+	}
+
+	else			// WRITE
+	{
+
+		// NOTE: WRITE not supported & not used in released driver.
+
+
+		printk("ReadWriteNRAM: can't write NVRAM; aborting write\n");
+	}
+
+	LEAVE("ReadWriteWWN");
+	return iStatus;
 }
 
 
@@ -2192,39 +1992,36 @@
 // adapter does not use the NM24C03 chip, so this function only works on
 // Compaq's adapters.
 
-int CpqTsReadWriteNVRAM( PVOID pChip, PVOID buf, int Read)
+int CpqTsReadWriteNVRAM(void * pChip, void * buf, int Read)
 {
-  PTACHYON fcChip = (PTACHYON)pChip;
+	PTACHYON fcChip = (PTACHYON) pChip;
 #define NVRAM_SIZE 512
-  ULONG ulBuff;
-  UCHAR *ucPtr = buf; // cast caller's void ptr to UCHAR array
-  int iStatus=-1;  // assume failure
-
-     
-  if( Read )  // READing NVRAM?
-  {
-    ulBuff = cpqfcTS_ReadNVRAM(   // TRUE on success
-                fcChip->Registers.TYstatus.address,
-                fcChip->Registers.TYcontrol.address,
-                256,            // bytes to write
-                ucPtr );        // source ptr
-
-
-    if( ulBuff )
-      iStatus = 0; // success
-    else
-    {
+	u32 ulBuff;
+	u8 *ucPtr = buf;	// cast caller's void ptr to u8 array
+	int iStatus = -1;	// assume failure
+
+
+	if (Read)		// READing NVRAM?
+	{
+		ulBuff = cpqfcTS_ReadNVRAM(	// TRUE on success
+						  fcChip->Registers.TYstatus.address, fcChip->Registers.TYcontrol.address, 256,	// bytes to write
+						  ucPtr);	// source ptr
+
+
+		if (ulBuff)
+			iStatus = 0;	// success
+		else {
 #ifdef DBG
-      printk( "CAUTION: NVRAM read failed\n");
+			printk("CAUTION: NVRAM read failed\n");
 #endif
-    }
-  }  // done reading
+		}
+	}			// done reading
 
-  else  // WRITING NVRAM 
-  {
+	else			// WRITING NVRAM 
+	{
+
+		printk("cpqfcTS: WRITE of FC Controller's NVRAM disabled\n");
+	}
 
-    printk("cpqfcTS: WRITE of FC Controller's NVRAM disabled\n");
-  }
-    
-  return iStatus;
+	return iStatus;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/cpqfcTSi2c.c linux-2.4.21-pre6/drivers/scsi/cpqfcTSi2c.c
--- linux-2.4.20/drivers/scsi/cpqfcTSi2c.c	2000-09-21 20:22:05.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/cpqfcTSi2c.c	2003-03-26 23:49:20.000000000 +0000
@@ -25,121 +25,105 @@
 // Orignal source author unknown
 
 #include <linux/types.h>
-enum boolean { FALSE, TRUE } ;
-
-
-#ifndef UCHAR
-typedef __u8 UCHAR;
-#endif
-#ifndef BOOLEAN
-typedef __u8 BOOLEAN;
-#endif
-#ifndef USHORT
-typedef __u16 USHORT;
-#endif
-#ifndef ULONG
-typedef __u32 ULONG;
-#endif
-
-
 #include <linux/string.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/sched.h>
-#include <asm/io.h>  // struct pt_regs for IRQ handler & Port I/O
+#include <asm/io.h>		// struct pt_regs for IRQ handler & Port I/O
 
 #include "cpqfcTSchip.h"
 
-static void tl_i2c_tx_byte( void* GPIOout, UCHAR data );
-/*static BOOLEAN tl_write_i2c_page_portion( void* GPIOin, void* GPIOout,
-  USHORT startOffset,  // e.g. 0x2f for WWN start
-  USHORT count,
-  UCHAR *buf );
-*/
+static void tl_i2c_tx_byte(void *GPIOout, u8 data);
 
-//
-// Tachlite GPIO2, GPIO3 (I2C) DEFINES
-// The NVRAM chip NM24C03 defines SCL (serial clock) and SDA (serial data)
-// GPIO2 drives SDA, and GPIO3 drives SCL
-// 
-// Since Tachlite inverts the state of the GPIO 0-3 outputs, SET writes 0
-// and clear writes 1. The input lines (read in TL status) is NOT inverted
-// This really helps confuse the code and debugging.
+/*
+ * Tachlite GPIO2, GPIO3 (I2C) DEFINES
+ * The NVRAM chip NM24C03 defines SCL (serial clock) and SDA (serial data)
+ * GPIO2 drives SDA, and GPIO3 drives SCL
+ * 
+ * Since Tachlite inverts the state of the GPIO 0-3 outputs, SET writes 0
+ * and clear writes 1. The input lines (read in TL status) is NOT inverted
+ * This really helps confuse the code and debugging.
+ */
+ 
+#define SET_DATA_HI		0x0
+#define SET_DATA_LO		0x8
+#define SET_CLOCK_HI		0x0
+#define SET_CLOCK_LO		0x4
 
-#define SET_DATA_HI  0x0
-#define SET_DATA_LO  0x8
-#define SET_CLOCK_HI 0x0
-#define SET_CLOCK_LO 0x4
+#define SENSE_DATA_HI		0x8
+#define SENSE_DATA_LO		0x0
+#define SENSE_CLOCK_HI		0x4
+#define SENSE_CLOCK_LO		0x0
 
-#define SENSE_DATA_HI  0x8
-#define SENSE_DATA_LO  0x0
-#define SENSE_CLOCK_HI 0x4
-#define SENSE_CLOCK_LO 0x0
+#define SLAVE_READ_ADDRESS	0xA1
+#define SLAVE_WRITE_ADDRESS	0xA0
 
-#define SLAVE_READ_ADDRESS    0xA1
-#define SLAVE_WRITE_ADDRESS   0xA0
-					      
 
-static void i2c_delay(ULONG mstime);
-static void tl_i2c_clock_pulse( UCHAR , void* GPIOout);
-static UCHAR tl_read_i2c_data( void* );
+static void i2c_delay(u32 mstime);
+static void tl_i2c_clock_pulse(u8, void *GPIOout);
+static u8 tl_read_i2c_data(void *);
 
 
 //-----------------------------------------------------------------------------
 //
-//      Name:   I2C_RX_ACK
+//      Name:   tl_i2c_rx_ack
 //
 //      This routine receives an acknowledge over the I2C bus.
 //
 //-----------------------------------------------------------------------------
-static unsigned short tl_i2c_rx_ack( void* GPIOin, void* GPIOout )
+static unsigned short tl_i2c_rx_ack(void *GPIOin, void *GPIOout)
 {
-  unsigned long value;
+	unsigned long value;
 
 	// do clock pulse, let data line float high
-  tl_i2c_clock_pulse( SET_DATA_HI, GPIOout );
+	tl_i2c_clock_pulse(SET_DATA_HI, GPIOout);
 
 	// slave must drive data low for acknowledge
-  value = tl_read_i2c_data( GPIOin);
-  if (value & SENSE_DATA_HI )
-    return( FALSE );
+	value = tl_read_i2c_data(GPIOin);
+	if (value & SENSE_DATA_HI)
+		return 0;
 
-  return( TRUE );
+	return 1;
 }
+
 //-----------------------------------------------------------------------------
 //
-//      Name:   READ_I2C_REG
+//      Name:   tl_read_i2c_reg
 //
 //      This routine reads the I2C control register using the global
 //      IO address stored in gpioreg.
 //
 //-----------------------------------------------------------------------------
-static UCHAR tl_read_i2c_data( void* gpioreg )
+static u8 tl_read_i2c_data(void *gpioreg)
 {
-  return( (UCHAR)(readl( gpioreg ) & 0x08L) ); // GPIO3
+	return ((u8) (readl(gpioreg) & 0x08L));	// GPIO3
 }
+
 //-----------------------------------------------------------------------------
 //
-//      Name:   WRITE_I2C_REG
+//      Name:   tl_write_i2c_reg
 //
 //      This routine writes the I2C control register using the global
 //      IO address stored in gpioreg.
 //      In Tachlite, we don't want to modify other bits in TL Control reg.
 //
 //-----------------------------------------------------------------------------
-static void tl_write_i2c_reg( void* gpioregOUT, UCHAR value )
+static void tl_write_i2c_reg(void *gpioregOUT, u8 value)
 {
-  ULONG  temp;
+	u32 temp;
 
 	// First read the register and clear out the old bits
-  temp = readl( gpioregOUT ) & 0xfffffff3L;
+	temp = readl(gpioregOUT) & 0xfffffff3L;
 
 	// Now or in the new data and send it back out
-  writel( temp | value, gpioregOUT);
+	writel(temp | value, gpioregOUT);
+	
+	/* PCI posting ???? */
 }
+
 //-----------------------------------------------------------------------------
 //
-//      Name:   I2C_TX_START
+//      Name:   tl_i2c_tx_start
 //
 //      This routine transmits a start condition over the I2C bus.
 //      1. Set SCL (clock, GPIO2) HIGH, set SDA (data, GPIO3) HIGH,
@@ -149,165 +133,162 @@
 //      NOTE! In TL control reg., output 1 means chip sees LOW
 //
 //-----------------------------------------------------------------------------
-static unsigned short tl_i2c_tx_start( void* GPIOin, void* GPIOout )
+static unsigned short tl_i2c_tx_start(void *GPIOin, void *GPIOout)
 {
-  unsigned short i;
-  ULONG value;
+	unsigned short i;
+	u32 value;
 
-  if ( !(tl_read_i2c_data(GPIOin) & SENSE_DATA_HI))
-  {
-    // start with clock high, let data float high
-    tl_write_i2c_reg(  GPIOout, SET_DATA_HI | SET_CLOCK_HI );
-
-    // keep sending clock pulses if slave is driving data line
-    for (i = 0; i < 10; i++)
-    {
-      tl_i2c_clock_pulse( SET_DATA_HI, GPIOout );
-
-      if ( tl_read_i2c_data(GPIOin) & SENSE_DATA_HI )
-	break;
-    }
+	if (!(tl_read_i2c_data(GPIOin) & SENSE_DATA_HI)) {
+		// start with clock high, let data float high
+		tl_write_i2c_reg(GPIOout, SET_DATA_HI | SET_CLOCK_HI);
+
+		// keep sending clock pulses if slave is driving data line
+		for (i = 0; i < 10; i++) {
+			tl_i2c_clock_pulse(SET_DATA_HI, GPIOout);
+
+			if (tl_read_i2c_data(GPIOin) & SENSE_DATA_HI)
+				break;
+		}
 
 		// if he's still driving data low after 10 clocks, abort
-    value = tl_read_i2c_data( GPIOin ); // read status
-    if (!(value & 0x08) )
-      return( FALSE );
-  }
-
+		value = tl_read_i2c_data(GPIOin);	// read status
+		if (!(value & 0x08))
+			return 0;
+	}
 
 	// To START, bring data low while clock high
-  tl_write_i2c_reg(  GPIOout, SET_CLOCK_HI | SET_DATA_LO );
+	tl_write_i2c_reg(GPIOout, SET_CLOCK_HI | SET_DATA_LO);
 
-  i2c_delay(0);
+	udelay(5);
 
-  return( TRUE );                           // TX start successful
+	return 1;		// TX start successful
 }
+
 //-----------------------------------------------------------------------------
 //
-//      Name:   I2C_TX_STOP
+//      Name:   tl_i2c_tx_stop
 //
 //      This routine transmits a stop condition over the I2C bus.
 //
 //-----------------------------------------------------------------------------
 
-static unsigned short tl_i2c_tx_stop( void* GPIOin, void* GPIOout )
+static unsigned short tl_i2c_tx_stop(void *GPIOin, void *GPIOout)
 {
-  int i;
+	int i;
 
-  for (i = 0; i < 10; i++) 
-  {
-  // Send clock pulse, drive data line low
-    tl_i2c_clock_pulse( SET_DATA_LO, GPIOout );
+	for (i = 0; i < 10; i++) {
+		// Send clock pulse, drive data line low
+		tl_i2c_clock_pulse(SET_DATA_LO, GPIOout);
 
-  // To STOP, bring data high while clock high
-    tl_write_i2c_reg(  GPIOout, SET_DATA_HI | SET_CLOCK_HI );
+		// To STOP, bring data high while clock high
+		tl_write_i2c_reg(GPIOout, SET_DATA_HI | SET_CLOCK_HI);
 
-  // Give the data line time to float high
-    i2c_delay(0);
+		// Give the data line time to float high
+		udelay(5);
 
-  // If slave is driving data line low, there's a problem; retry
-    if ( tl_read_i2c_data(GPIOin) & SENSE_DATA_HI )
-      return( TRUE );  // TX STOP successful!
-  }
+		// If slave is driving data line low, there's a problem; retry
+		if (tl_read_i2c_data(GPIOin) & SENSE_DATA_HI)
+			return 1;	// TX STOP successful!
+	}
 
-  return( FALSE );                      // error
+	return 0;		// error
 }
+
 //-----------------------------------------------------------------------------
 //
-//      Name:   I2C_TX_uchar
+//      Name:   tl_i2c_tx_byte
 //
 //      This routine transmits a byte across the I2C bus.
 //
 //-----------------------------------------------------------------------------
-static void tl_i2c_tx_byte( void* GPIOout, UCHAR data )
+static void tl_i2c_tx_byte(void *GPIOout, u8 data)
 {
-  UCHAR bit;
+	u8 bit;
 
-  for (bit = 0x80; bit; bit >>= 1)
-  {
-    if( data & bit )
-      tl_i2c_clock_pulse( (UCHAR)SET_DATA_HI, GPIOout);
-    else
-      tl_i2c_clock_pulse( (UCHAR)SET_DATA_LO, GPIOout);
-  }  
+	for (bit = 0x80; bit; bit >>= 1) {
+		if (data & bit)
+			tl_i2c_clock_pulse((u8) SET_DATA_HI, GPIOout);
+		else
+			tl_i2c_clock_pulse((u8) SET_DATA_LO, GPIOout);
+	}
 }
+
 //-----------------------------------------------------------------------------
 //
-//      Name:   I2C_RX_uchar
+//      Name:   tl_i2c_rx_byte
 //
 //      This routine receives a byte across the I2C bus.
 //
 //-----------------------------------------------------------------------------
-static UCHAR tl_i2c_rx_byte( void* GPIOin, void* GPIOout )
+static u8 tl_i2c_rx_byte(void *GPIOin, void *GPIOout)
 {
-  UCHAR bit;
-  UCHAR data = 0;
+	u8 bit;
+	u8 data = 0;
 
 
-  for (bit = 0x80; bit; bit >>= 1) {
-    // do clock pulse, let data line float high
-    tl_i2c_clock_pulse( SET_DATA_HI, GPIOout );
+	for (bit = 0x80; bit; bit >>= 1) {
+		// do clock pulse, let data line float high
+		tl_i2c_clock_pulse(SET_DATA_HI, GPIOout);
 
-    // read data line
-    if ( tl_read_i2c_data( GPIOin) & 0x08 )
-      data |= bit;
-  }
+		// read data line
+		if (tl_read_i2c_data(GPIOin) & 0x08)
+			data |= bit;
+	}
 
-  return (data);
+	return (data);
 }
+
 //*****************************************************************************
 //*****************************************************************************
 // Function:   read_i2c_nvram
-// Arguments:  UCHAR count     number of bytes to read
-//             UCHAR *buf      area to store the bytes read
+// Arguments:  u8 count     number of bytes to read
+//             u8 *buf      area to store the bytes read
 // Returns:    0 - failed
 //             1 - success
 //*****************************************************************************
 //*****************************************************************************
-unsigned long cpqfcTS_ReadNVRAM( void* GPIOin, void* GPIOout , USHORT count,
-	UCHAR *buf )
+unsigned long cpqfcTS_ReadNVRAM(void *GPIOin, void *GPIOout, u16 count, u8 * buf)
 {
-  unsigned short i;
+	unsigned short i;
 
-  if( !( tl_i2c_tx_start(GPIOin, GPIOout) ))
-    return FALSE;
+	if (!(tl_i2c_tx_start(GPIOin, GPIOout)))
+		return 0;
 
-  // Select the NVRAM for "dummy" write, to set the address
-  tl_i2c_tx_byte( GPIOout , SLAVE_WRITE_ADDRESS );
-  if ( !tl_i2c_rx_ack(GPIOin, GPIOout ) )
-    return( FALSE );
-
-  // Now send the address where we want to start reading  
-  tl_i2c_tx_byte( GPIOout , 0 );
-  if ( !tl_i2c_rx_ack(GPIOin, GPIOout ) )
-    return( FALSE );
-
-  // Send a repeated start condition and select the
-  //  slave for reading now.
-  if( tl_i2c_tx_start(GPIOin, GPIOout) )
-    tl_i2c_tx_byte( GPIOout, SLAVE_READ_ADDRESS );
-
-  if ( !tl_i2c_rx_ack(GPIOin, GPIOout) )
-    return( FALSE );
-
-  // this loop will now read out the data and store it
-  //  in the buffer pointed to by buf
-  for ( i=0; i<count; i++) 
-  {
-    *buf++ = tl_i2c_rx_byte(GPIOin, GPIOout);
-
-    // Send ACK by holding data line low for 1 clock
-    if ( i < (count-1) )
-      tl_i2c_clock_pulse( 0x08, GPIOout );
-    else {
-	// Don't send ack for final byte
-      tl_i2c_clock_pulse( SET_DATA_HI, GPIOout );
-    }
-  }
+	// Select the NVRAM for "dummy" write, to set the address
+	tl_i2c_tx_byte(GPIOout, SLAVE_WRITE_ADDRESS);
+	if (!tl_i2c_rx_ack(GPIOin, GPIOout))
+		return 0;
+
+	// Now send the address where we want to start reading  
+	tl_i2c_tx_byte(GPIOout, 0);
+	if (!tl_i2c_rx_ack(GPIOin, GPIOout))
+		return 0;
+
+	// Send a repeated start condition and select the
+	//  slave for reading now.
+	if (tl_i2c_tx_start(GPIOin, GPIOout))
+		tl_i2c_tx_byte(GPIOout, SLAVE_READ_ADDRESS);
+
+	if (!tl_i2c_rx_ack(GPIOin, GPIOout))
+		return 0;
+
+	// this loop will now read out the data and store it
+	//  in the buffer pointed to by buf
+	for (i = 0; i < count; i++) {
+		*buf++ = tl_i2c_rx_byte(GPIOin, GPIOout);
+
+		// Send ACK by holding data line low for 1 clock
+		if (i < (count - 1))
+			tl_i2c_clock_pulse(0x08, GPIOout);
+		else {
+			// Don't send ack for final byte
+			tl_i2c_clock_pulse(SET_DATA_HI, GPIOout);
+		}
+	}
 
-  tl_i2c_tx_stop(GPIOin, GPIOout);
+	tl_i2c_tx_stop(GPIOin, GPIOout);
 
-  return( TRUE );
+	return 1;
 }
 
 //****************************************************************
@@ -320,22 +301,22 @@
 //
 //****************************************************************
 
-static void tl_set_clock(void* gpioreg)
+static void tl_set_clock(void *gpioreg)
 {
-  ULONG ret_val;
+	u32 ret_val;
 
-  ret_val = readl( gpioreg );
-  ret_val &= 0xffffffFBL;  // clear GPIO2 (SCL)
-  writel( ret_val, gpioreg);
+	ret_val = readl(gpioreg);
+	ret_val &= 0xffffffFBL;	// clear GPIO2 (SCL)
+	writel(ret_val, gpioreg);
 }
 
-static void tl_clr_clock(void* gpioreg)
+static void tl_clr_clock(void *gpioreg)
 {
-  ULONG ret_val;
+	u32 ret_val;
 
-  ret_val = readl( gpioreg );
-  ret_val |= SET_CLOCK_LO;
-  writel( ret_val, gpioreg);
+	ret_val = readl(gpioreg);
+	ret_val |= SET_CLOCK_LO;
+	writel(ret_val, gpioreg);
 }
 
 //*****************************************************************
@@ -345,33 +326,33 @@
 //
 //
 //*****************************************************************
-static void tl_i2c_clock_pulse( UCHAR value, void* GPIOout  )
+static void tl_i2c_clock_pulse(u8 value, void *GPIOout)
 {
-  ULONG ret_val;
+	u32 ret_val;
 
-  // clear the clock bit
-  tl_clr_clock( GPIOout );
+	// clear the clock bit
+	tl_clr_clock(GPIOout);
 
-  i2c_delay(0);
+	udelay(5);
 
 
-  // read the port to preserve non-I2C bits
-  ret_val = readl( GPIOout );
+	// read the port to preserve non-I2C bits
+	ret_val = readl(GPIOout);
 
-  // clear the data & clock bits
-  ret_val &= 0xFFFFFFf3;
+	// clear the data & clock bits
+	ret_val &= 0xFFFFFFf3;
 
-  // write the value passed in...
-  // data can only change while clock is LOW!
-  ret_val |= value;           // the data
-  ret_val |= SET_CLOCK_LO;    // the clock
-  writel( ret_val, GPIOout );
+	// write the value passed in...
+	// data can only change while clock is LOW!
+	ret_val |= value;	// the data
+	ret_val |= SET_CLOCK_LO;	// the clock
+	writel(ret_val, GPIOout);
 
-  i2c_delay(0);
+	udelay(5);
 
 
-  //set clock bit
-  tl_set_clock( GPIOout);
+	//set clock bit
+	tl_set_clock(GPIOout);
 }
 
 
@@ -384,110 +365,71 @@
 //
 //
 //*****************************************************************
-int cpqfcTS_GetNVRAM_data( UCHAR *wwnbuf, UCHAR *buf )
+int cpqfcTS_GetNVRAM_data(u8 * wwnbuf, u8 * buf)
 {
-  ULONG len;
-  ULONG sub_len;
-  ULONG ptr_inc;
-  ULONG i;
-  ULONG j;
-  UCHAR *data_ptr;
-  UCHAR  z;
-  UCHAR  name;
-  UCHAR  sub_name;
-  UCHAR  done;
-  int iReturn=0;  // def. 0 offset is failure to find WWN field
-  
-
-	  
-  data_ptr = (UCHAR *)buf;
-
-  done = FALSE;
-  i = 0;
-
-  while ( (i < 128) && (!done) ) 
-  {
-    z = data_ptr[i];\
-    if ( !(z & 0x80) )  
-    {	
-      len  = 1 + (z & 0x07);
-
-      name = (z & 0x78) >> 3;
-      if (name == 0x0F)
-        done = TRUE;
-    }
-    else 
-    {
-      name = z & 0x7F;
-      len  = 3 + data_ptr[i+1] + (data_ptr[i+2] << 8);
-           
-      switch (name) 
-      {
-      case 0x0D:
-	//
-	  j = i + 3;
-	  //
-	  if ( data_ptr[j] == 0x3b ) {
-	    len = 6;
-	    break;
-	  }
-
-	  while ( j<(i+len) ) {
-	    sub_name = (data_ptr[j] & 0x3f);
-	    sub_len  = data_ptr[j+1] + 
-	               (data_ptr[j+2] << 8);
-            ptr_inc  = sub_len + 3; 
-	    switch (sub_name) 
-	    {
-	    case 0x3C:
-              memcpy( wwnbuf, &data_ptr[j+3], 8);
-              iReturn = j+3;
-              break;
-            default:
-              break;
-	    }
-	    j += ptr_inc;
-          }
-	  break;
-        default:
-	  break;
-      }  
-    }  
-  //
-    i += len;
-  }  // end while 
-  return iReturn;
+	u32 len;
+	u32 sub_len;
+	u32 ptr_inc;
+	u32 i;
+	u32 j;
+	u8 *data_ptr;
+	u8 z;
+	u8 name;
+	u8 sub_name;
+	u8 done;
+	int ret = 0;	// def. 0 offset is failure to find WWN field
+
+
+
+	data_ptr = (u8 *) buf;
+
+	done = 0;
+	i = 0;
+
+	while (i < 128 && !done) {
+		z = data_ptr[i];
+		if (!(z & 0x80)) {
+			len = 1 + (z & 0x07);
+
+			name = (z & 0x78) >> 3;
+			if (name == 0x0F)
+				done = 1;
+		} else {
+			name = z & 0x7F;
+			len = 3 + data_ptr[i + 1] + (data_ptr[i + 2] << 8);
+
+			switch (name) {
+			case 0x0D:
+				//
+				j = i + 3;
+				//
+				if (data_ptr[j] == 0x3b) {
+					len = 6;
+					break;
+				}
+
+				while (j < (i + len)) {
+					sub_name = (data_ptr[j] & 0x3f);
+					sub_len = data_ptr[j + 1] + (data_ptr[j + 2] << 8);
+					ptr_inc = sub_len + 3;
+					switch (sub_name) {
+					case 0x3C:
+						memcpy(wwnbuf, &data_ptr[j + 3], 8);
+						ret = j + 3;
+						break;
+					default:
+						break;
+					}
+					j += ptr_inc;
+				}
+				break;
+			default:
+				break;
+			}
+		}
+		//
+		i += len;
+	}			// end while 
+	return ret;
 }
 
-
-
-
-
-// define a short 5 micro sec delay, and longer (ms) delay
-
-static void i2c_delay(ULONG mstime)
-{
-  ULONG i;
-  
-// NOTE: we only expect to use these delays when reading
-// our adapter's NVRAM, which happens only during adapter reset.
-// Delay technique from "Linux Device Drivers", A. Rubini 
-// (1st Ed.) pg 137.
-
-//  printk(" delay %lx  ", mstime);
-  if( mstime ) // ms delay?
-  {
-    // delay technique
-    for( i=0; i < mstime; i++)
-      udelay(1000); // 1ms per loop
-	
-  }
-  else  // 5 micro sec delay
-  
-    udelay( 5 ); // micro secs
-  
-//  printk("done\n");
-}
-
-
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/cpqfcTSinit.c linux-2.4.21-pre6/drivers/scsi/cpqfcTSinit.c
--- linux-2.4.20/drivers/scsi/cpqfcTSinit.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/cpqfcTSinit.c	2003-03-26 23:49:00.000000000 +0000
@@ -29,8 +29,6 @@
 */
 
 
-#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
-
 #include <linux/blk.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
@@ -39,17 +37,17 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/timer.h>
-#include <linux/ioport.h>  // request_region() prototype
-#include <linux/vmalloc.h> // ioremap()
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,7)
+#include <linux/ioport.h>	// request_region() prototype
+#include <linux/slab.h>
+#include <linux/vmalloc.h>	// ioremap()
 #include <linux/completion.h>
-#endif
+#include <linux/init.h>
 #ifdef __alpha__
 #define __KERNEL_SYSCALLS__
 #endif
 #include <asm/unistd.h>
 #include <asm/io.h>
-#include <asm/uaccess.h>   // ioctl related
+#include <asm/uaccess.h>	// ioctl related
 #include <asm/irq.h>
 #include <linux/spinlock.h>
 #include "sd.h"
@@ -61,48 +59,21 @@
 
 #include "cpqfcTS.h"
 
-#include <linux/config.h>  
+#include <linux/config.h>
 #include <linux/module.h>
-#include <linux/version.h> 
+#include <linux/version.h>
 
 /* Embedded module documentation macros - see module.h */
 MODULE_AUTHOR("Compaq Computer Corporation");
-MODULE_DESCRIPTION("Driver for Compaq 64-bit/66Mhz PCI Fibre Channel HBA v. 2.1.1");
+MODULE_DESCRIPTION("Driver for Compaq 64-bit/66Mhz PCI Fibre Channel HBA v. 2.1.2");
 MODULE_LICENSE("GPL");
-  
-int cpqfcTS_TargetDeviceReset( Scsi_Device *ScsiDev, unsigned int reset_flags);
-
-// This struct was originally defined in 
-// /usr/src/linux/include/linux/proc_fs.h
-// since it's only partially implemented, we only use first
-// few fields...
-// NOTE: proc_fs changes in 2.4 kernel
-
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27)
-static struct proc_dir_entry proc_scsi_cpqfcTS =
-{
-  PROC_SCSI_CPQFCTS,           // ushort low_ino (enumerated list)
-  7,                           // ushort namelen
-  DEV_NAME,                    // const char* name
-  S_IFDIR | S_IRUGO | S_IXUGO, // mode_t mode
-  2                            // nlink_t nlink
-	                       // etc. ...
-};
 
+int cpqfcTS_TargetDeviceReset(Scsi_Device * ScsiDev, unsigned int reset_flags);
 
-#endif
-
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,7)
-#  define CPQFC_DECLARE_COMPLETION(x) DECLARE_COMPLETION(x)
-#  define CPQFC_WAITING waiting
-#  define CPQFC_COMPLETE(x) complete(x)
-#  define CPQFC_WAIT_FOR_COMPLETION(x) wait_for_completion(x);
-#else
-#  define CPQFC_DECLARE_COMPLETION(x) DECLARE_MUTEX_LOCKED(x)
-#  define CPQFC_WAITING sem
-#  define CPQFC_COMPLETE(x) up(x)
-#  define CPQFC_WAIT_FOR_COMPLETION(x) down(x)
-#endif
+#define CPQFC_DECLARE_COMPLETION(x) DECLARE_COMPLETION(x)
+#define CPQFC_WAITING waiting
+#define CPQFC_COMPLETE(x) complete(x)
+#define CPQFC_WAIT_FOR_COMPLETION(x) wait_for_completion(x);
 
 /* local function to load our per-HBA (local) data for chip
    registers, FC link state, all FC exchanges, etc.
@@ -112,120 +83,86 @@
    Name) are not necessary.
    
 */
-static void Cpqfc_initHBAdata( CPQFCHBA *cpqfcHBAdata, struct pci_dev *PciDev )
+static void Cpqfc_initHBAdata(CPQFCHBA * cpqfcHBAdata, struct pci_dev *PciDev)
 {
-             
-  cpqfcHBAdata->PciDev = PciDev; // copy PCI info ptr
 
-  // since x86 port space is 64k, we only need the lower 16 bits
-  cpqfcHBAdata->fcChip.Registers.IOBaseL = 
-    PciDev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK;
-  
-  cpqfcHBAdata->fcChip.Registers.IOBaseU = 
-    PciDev->resource[2].start & PCI_BASE_ADDRESS_IO_MASK;
-  
-  // 32-bit memory addresses
-  cpqfcHBAdata->fcChip.Registers.MemBase = 
-    PciDev->resource[3].start & PCI_BASE_ADDRESS_MEM_MASK;
-
-  cpqfcHBAdata->fcChip.Registers.ReMapMemBase = 
-    ioremap( PciDev->resource[3].start & PCI_BASE_ADDRESS_MEM_MASK,
-             0x200);
-  
-  cpqfcHBAdata->fcChip.Registers.RAMBase = 
-    PciDev->resource[4].start;
-  
-  cpqfcHBAdata->fcChip.Registers.SROMBase =  // NULL for HP TS adapter
-    PciDev->resource[5].start;
-  
-  // now the Tachlite chip registers
-  // the REGISTER struct holds both the physical address & last
-  // written value (some TL registers are WRITE ONLY)
-
-  cpqfcHBAdata->fcChip.Registers.SFQconsumerIndex.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_SFQ_CONSUMER_INDEX;
-
-  cpqfcHBAdata->fcChip.Registers.ERQproducerIndex.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_ERQ_PRODUCER_INDEX;
-      
-  // TL Frame Manager
-  cpqfcHBAdata->fcChip.Registers.FMconfig.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_CONFIG;
-  cpqfcHBAdata->fcChip.Registers.FMcontrol.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_CONTROL;
-  cpqfcHBAdata->fcChip.Registers.FMstatus.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_STATUS;
-  cpqfcHBAdata->fcChip.Registers.FMLinkStatus1.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_LINK_STAT1;
-  cpqfcHBAdata->fcChip.Registers.FMLinkStatus2.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_LINK_STAT2;
-  cpqfcHBAdata->fcChip.Registers.FMBB_CreditZero.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_BB_CREDIT0;
-      
-      // TL Control Regs
-  cpqfcHBAdata->fcChip.Registers.TYconfig.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_TACH_CONFIG;
-  cpqfcHBAdata->fcChip.Registers.TYcontrol.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_TACH_CONTROL;
-  cpqfcHBAdata->fcChip.Registers.TYstatus.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_TACH_STATUS;
-  cpqfcHBAdata->fcChip.Registers.rcv_al_pa.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_RCV_AL_PA;
-  cpqfcHBAdata->fcChip.Registers.ed_tov.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_ED_TOV;
-
-
-  cpqfcHBAdata->fcChip.Registers.INTEN.address = 
-	        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + IINTEN;
-  cpqfcHBAdata->fcChip.Registers.INTPEND.address = 
-	        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + IINTPEND;
-  cpqfcHBAdata->fcChip.Registers.INTSTAT.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + IINTSTAT;
-
-  DEBUG_PCI(printk("  cpqfcHBAdata->fcChip.Registers. :\n"));
-  DEBUG_PCI(printk("    IOBaseL = %x\n", 
-    cpqfcHBAdata->fcChip.Registers.IOBaseL));
-  DEBUG_PCI(printk("    IOBaseU = %x\n", 
-    cpqfcHBAdata->fcChip.Registers.IOBaseU));
-  
-  printk(" ioremap'd Membase: %p\n", cpqfcHBAdata->fcChip.Registers.ReMapMemBase);
-  
-  DEBUG_PCI(printk("    SFQconsumerIndex.address = %p\n", 
-    cpqfcHBAdata->fcChip.Registers.SFQconsumerIndex.address));
-  DEBUG_PCI(printk("    ERQproducerIndex.address = %p\n", 
-    cpqfcHBAdata->fcChip.Registers.ERQproducerIndex.address));
-  DEBUG_PCI(printk("    TYconfig.address = %p\n", 
-    cpqfcHBAdata->fcChip.Registers.TYconfig.address));
-  DEBUG_PCI(printk("    FMconfig.address = %p\n", 
-    cpqfcHBAdata->fcChip.Registers.FMconfig.address));
-  DEBUG_PCI(printk("    FMcontrol.address = %p\n", 
-    cpqfcHBAdata->fcChip.Registers.FMcontrol.address));
-
-  // set default options for FC controller (chip)
-  cpqfcHBAdata->fcChip.Options.initiator = 1;  // default: SCSI initiator
-  cpqfcHBAdata->fcChip.Options.target = 0;     // default: SCSI target
-  cpqfcHBAdata->fcChip.Options.extLoopback = 0;// default: no loopback @GBIC
-  cpqfcHBAdata->fcChip.Options.intLoopback = 0;// default: no loopback inside chip
-
-  // set highest and lowest FC-PH version the adapter/driver supports
-  // (NOT strict compliance)
-  cpqfcHBAdata->fcChip.highest_FCPH_ver = FC_PH3;
-  cpqfcHBAdata->fcChip.lowest_FCPH_ver = FC_PH43;
-
-  // set function points for this controller / adapter
-  cpqfcHBAdata->fcChip.ResetTachyon = CpqTsResetTachLite;
-  cpqfcHBAdata->fcChip.FreezeTachyon = CpqTsFreezeTachlite;
-  cpqfcHBAdata->fcChip.UnFreezeTachyon = CpqTsUnFreezeTachlite;
-  cpqfcHBAdata->fcChip.CreateTachyonQues = CpqTsCreateTachLiteQues;
-  cpqfcHBAdata->fcChip.DestroyTachyonQues = CpqTsDestroyTachLiteQues;
-  cpqfcHBAdata->fcChip.InitializeTachyon = CpqTsInitializeTachLite;  
-  cpqfcHBAdata->fcChip.LaserControl = CpqTsLaserControl;  
-  cpqfcHBAdata->fcChip.ProcessIMQEntry = CpqTsProcessIMQEntry;
-  cpqfcHBAdata->fcChip.InitializeFrameManager = CpqTsInitializeFrameManager;;  
-  cpqfcHBAdata->fcChip.ReadWriteWWN = CpqTsReadWriteWWN;
-  cpqfcHBAdata->fcChip.ReadWriteNVRAM = CpqTsReadWriteNVRAM;
+	cpqfcHBAdata->PciDev = PciDev;	// copy PCI info ptr
+
+	// since x86 port space is 64k, we only need the lower 16 bits
+	cpqfcHBAdata->fcChip.Registers.IOBaseL = PciDev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK;
+	cpqfcHBAdata->fcChip.Registers.IOBaseU = PciDev->resource[2].start & PCI_BASE_ADDRESS_IO_MASK;
+
+	// 32-bit memory addresses
+	cpqfcHBAdata->fcChip.Registers.MemBase = PciDev->resource[3].start & PCI_BASE_ADDRESS_MEM_MASK;
+	cpqfcHBAdata->fcChip.Registers.ReMapMemBase = ioremap(PciDev->resource[3].start & PCI_BASE_ADDRESS_MEM_MASK, 0x200);
+	cpqfcHBAdata->fcChip.Registers.RAMBase = PciDev->resource[4].start;
+	cpqfcHBAdata->fcChip.Registers.SROMBase = PciDev->resource[5].start; // NULL for HP TS adapter
+
+	// now the Tachlite chip registers
+	// the REGISTER struct holds both the physical address & last
+	// written value (some TL registers are WRITE ONLY)
+
+	cpqfcHBAdata->fcChip.Registers.SFQconsumerIndex.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_SFQ_CONSUMER_INDEX;
+
+	cpqfcHBAdata->fcChip.Registers.ERQproducerIndex.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_ERQ_PRODUCER_INDEX;
+
+	// TL Frame Manager
+	cpqfcHBAdata->fcChip.Registers.FMconfig.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_CONFIG;
+	cpqfcHBAdata->fcChip.Registers.FMcontrol.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_CONTROL;
+	cpqfcHBAdata->fcChip.Registers.FMstatus.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_STATUS;
+	cpqfcHBAdata->fcChip.Registers.FMLinkStatus1.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_LINK_STAT1;
+	cpqfcHBAdata->fcChip.Registers.FMLinkStatus2.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_LINK_STAT2;
+	cpqfcHBAdata->fcChip.Registers.FMBB_CreditZero.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_BB_CREDIT0;
+
+	// TL Control Regs
+	cpqfcHBAdata->fcChip.Registers.TYconfig.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_TACH_CONFIG;
+	cpqfcHBAdata->fcChip.Registers.TYcontrol.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_TACH_CONTROL;
+	cpqfcHBAdata->fcChip.Registers.TYstatus.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_TACH_STATUS;
+	cpqfcHBAdata->fcChip.Registers.rcv_al_pa.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_RCV_AL_PA;
+	cpqfcHBAdata->fcChip.Registers.ed_tov.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_ED_TOV;
+
+
+	cpqfcHBAdata->fcChip.Registers.INTEN.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + IINTEN;
+	cpqfcHBAdata->fcChip.Registers.INTPEND.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + IINTPEND;
+	cpqfcHBAdata->fcChip.Registers.INTSTAT.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + IINTSTAT;
+
+	DEBUG_PCI(printk("  cpqfcHBAdata->fcChip.Registers. :\n"));
+	DEBUG_PCI(printk("    IOBaseL = %x\n", cpqfcHBAdata->fcChip.Registers.IOBaseL));
+	DEBUG_PCI(printk("    IOBaseU = %x\n", cpqfcHBAdata->fcChip.Registers.IOBaseU));
+
+	printk(" ioremap'd Membase: %p\n", cpqfcHBAdata->fcChip.Registers.ReMapMemBase);
+
+	DEBUG_PCI(printk("    SFQconsumerIndex.address = %p\n", cpqfcHBAdata->fcChip.Registers.SFQconsumerIndex.address));
+	DEBUG_PCI(printk("    ERQproducerIndex.address = %p\n", cpqfcHBAdata->fcChip.Registers.ERQproducerIndex.address));
+	DEBUG_PCI(printk("    TYconfig.address = %p\n", cpqfcHBAdata->fcChip.Registers.TYconfig.address));
+	DEBUG_PCI(printk("    FMconfig.address = %p\n", cpqfcHBAdata->fcChip.Registers.FMconfig.address));
+	DEBUG_PCI(printk("    FMcontrol.address = %p\n", cpqfcHBAdata->fcChip.Registers.FMcontrol.address));
+
+	// set default options for FC controller (chip)
+	cpqfcHBAdata->fcChip.Options.initiator = 1;	// default: SCSI initiator
+	cpqfcHBAdata->fcChip.Options.target = 0;	// default: SCSI target
+	cpqfcHBAdata->fcChip.Options.extLoopback = 0;	// default: no loopback @GBIC
+	cpqfcHBAdata->fcChip.Options.intLoopback = 0;	// default: no loopback inside chip
+
+	// set highest and lowest FC-PH version the adapter/driver supports
+	// (NOT strict compliance)
+	cpqfcHBAdata->fcChip.highest_FCPH_ver = FC_PH3;
+	cpqfcHBAdata->fcChip.lowest_FCPH_ver = FC_PH43;
+
+	// set function points for this controller / adapter
+	cpqfcHBAdata->fcChip.ResetTachyon = CpqTsResetTachLite;
+	cpqfcHBAdata->fcChip.FreezeTachyon = CpqTsFreezeTachlite;
+	cpqfcHBAdata->fcChip.UnFreezeTachyon = CpqTsUnFreezeTachlite;
+	cpqfcHBAdata->fcChip.CreateTachyonQues = CpqTsCreateTachLiteQues;
+	cpqfcHBAdata->fcChip.DestroyTachyonQues = CpqTsDestroyTachLiteQues;
+	cpqfcHBAdata->fcChip.InitializeTachyon = CpqTsInitializeTachLite;
+	cpqfcHBAdata->fcChip.LaserControl = CpqTsLaserControl;
+	cpqfcHBAdata->fcChip.ProcessIMQEntry = CpqTsProcessIMQEntry;
+	cpqfcHBAdata->fcChip.InitializeFrameManager = CpqTsInitializeFrameManager;;
+	cpqfcHBAdata->fcChip.ReadWriteWWN = CpqTsReadWriteWWN;
+	cpqfcHBAdata->fcChip.ReadWriteNVRAM = CpqTsReadWriteNVRAM;
+
 
- 
 
 }
 
@@ -233,28 +170,27 @@
 /* (borrowed from linux/drivers/scsi/hosts.c) */
 static void launch_FCworker_thread(struct Scsi_Host *HostAdapter)
 {
-  DECLARE_MUTEX_LOCKED(sem);
+	DECLARE_MUTEX_LOCKED(sem);
+
+	CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *) HostAdapter->hostdata;
+
+	ENTER("launch_FC_worker_thread");
 
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
+	cpqfcHBAdata->notify_wt = &sem;
 
-  ENTER("launch_FC_worker_thread");
-             
-  cpqfcHBAdata->notify_wt = &sem;
-
-  /* must unlock before kernel_thread(), for it may cause a reschedule. */
-  spin_unlock_irq(&io_request_lock);
-  kernel_thread((int (*)(void *))cpqfcTSWorkerThread, 
-                          (void *) HostAdapter, 0);
-  /*
-   * Now wait for the kernel error thread to initialize itself
-
-   */
-  down (&sem);
-  spin_lock_irq(&io_request_lock);
-  cpqfcHBAdata->notify_wt = NULL;
+	/* must unlock before kernel_thread(), for it may cause a reschedule. */
+	spin_unlock_irq(&io_request_lock);
+	kernel_thread((int (*)(void *)) cpqfcTSWorkerThread, (void *) HostAdapter, 0);
+	/*
+	 * Now wait for the kernel error thread to initialize itself
+
+	 */
+	down(&sem);
+	spin_lock_irq(&io_request_lock);
+	cpqfcHBAdata->notify_wt = NULL;
+
+	LEAVE("launch_FC_worker_thread");
 
-  LEAVE("launch_FC_worker_thread");
- 
 }
 
 
@@ -279,436 +215,396 @@
 };
 
 
-int cpqfcTS_detect(Scsi_Host_Template *ScsiHostTemplate)
+int cpqfcTS_detect(Scsi_Host_Template * ScsiHostTemplate)
 {
-  int NumberOfAdapters=0; // how many of our PCI adapters are found?
-  struct pci_dev *PciDev = NULL;
-  struct Scsi_Host *HostAdapter = NULL;
-  CPQFCHBA *cpqfcHBAdata = NULL; 
-  struct timer_list *cpqfcTStimer = NULL;
-  int i;
+	int NumberOfAdapters = 0;	// how many of our PCI adapters are found?
+	struct pci_dev *PciDev = NULL;
+	struct Scsi_Host *HostAdapter = NULL;
+	CPQFCHBA *cpqfcHBAdata = NULL;
+	struct timer_list *cpqfcTStimer = NULL;
+	int i;
 
-  ENTER("cpqfcTS_detect");
+	ENTER("cpqfcTS_detect");
 
 #if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27)
-  ScsiHostTemplate->proc_dir = &proc_scsi_cpqfcTS;
+	ScsiHostTemplate->proc_dir = &proc_scsi_cpqfcTS;
 #else
-  ScsiHostTemplate->proc_name = "cpqfcTS";
+	ScsiHostTemplate->proc_name = "cpqfcTS";
 #endif
 
-  if( pci_present() == 0) // no PCI busses?
-  {
-    printk( "  no PCI bus?@#!\n");
-    return NumberOfAdapters;
-  }
-
-  for( i=0; i < HBA_TYPES; i++)
-  {
-    // look for all HBAs of each type
-
-    while((PciDev = pci_find_device(cpqfc_boards[i].vendor_id,
-				    cpqfc_boards[i].device_id, PciDev)))
-    {
-
-      if (pci_set_dma_mask(PciDev, CPQFCTS_DMA_MASK) != 0) {
-	printk(KERN_WARNING 
-		"cpqfc: HBA cannot support required DMA mask, skipping.\n");
-	continue;
-      }
-
-      // NOTE: (kernel 2.2.12-32) limits allocation to 128k bytes...
-      printk(" scsi_register allocating %d bytes for FC HBA\n",
-		      (ULONG)sizeof(CPQFCHBA));
-
-      HostAdapter = scsi_register( ScsiHostTemplate, sizeof( CPQFCHBA ) );
-      
-      if(HostAdapter == NULL)
-      	continue;
-      DEBUG_PCI( printk("  HBA found!\n"));
-      DEBUG_PCI( printk("  HostAdapter->PciDev->irq = %u\n", PciDev->irq) );
-      DEBUG_PCI(printk("  PciDev->baseaddress[0]= %lx\n", 
-				PciDev->resource[0].start));
-      DEBUG_PCI(printk("  PciDev->baseaddress[1]= %lx\n", 
-				PciDev->resource[1].start));
-      DEBUG_PCI(printk("  PciDev->baseaddress[2]= %lx\n", 
-				PciDev->resource[2].start));
-      DEBUG_PCI(printk("  PciDev->baseaddress[3]= %lx\n", 
-				PciDev->resource[3].start));
-
-      scsi_set_pci_device(HostAdapter, PciDev);      
-      HostAdapter->irq = PciDev->irq;  // copy for Scsi layers
-      
-      // HP Tachlite uses two (255-byte) ranges of Port I/O (lower & upper),
-      // for a total I/O port address space of 512 bytes.
-      // mask out the I/O port address (lower) & record
-      HostAdapter->io_port = (unsigned int)
-	     PciDev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK;
-      HostAdapter->n_io_port = 0xff;
-      
-      // i.e., expect 128 targets (arbitrary number), while the
-      //  RA-4000 supports 32 LUNs
-      HostAdapter->max_id =  0;   // incremented as devices log in    
-      HostAdapter->max_lun = CPQFCTS_MAX_LUN;         // LUNs per FC device
-      HostAdapter->max_channel = CPQFCTS_MAX_CHANNEL; // multiple busses?
-      
-      // get the pointer to our HBA specific data... (one for
-      // each HBA on the PCI bus(ses)).
-      cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
-      
-      // make certain our data struct is clear
-      memset( cpqfcHBAdata, 0, sizeof( CPQFCHBA ) );
-
-
-      // initialize our HBA info
-      cpqfcHBAdata->HBAnum = NumberOfAdapters;
-
-      cpqfcHBAdata->HostAdapter = HostAdapter; // back ptr
-      Cpqfc_initHBAdata( cpqfcHBAdata, PciDev ); // fill MOST fields
-     
-      cpqfcHBAdata->HBAnum = NumberOfAdapters;
-      cpqfcHBAdata->hba_spinlock = SPIN_LOCK_UNLOCKED;
-
-      // request necessary resources and check for conflicts
-      if( request_irq( HostAdapter->irq,
-		       cpqfcTS_intr_handler,
-	               SA_INTERRUPT | SA_SHIRQ,
-	               DEV_NAME,
-		       HostAdapter) )
-      {
-	printk(" IRQ %u already used\n", HostAdapter->irq);
-        scsi_unregister( HostAdapter);
-	continue;
-      }
-
-      // Since we have two 256-byte I/O port ranges (upper
-      // and lower), check them both
-      if( check_region( cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff) )
-      {
-	printk("  cpqfcTS address in use: %x\n", 
-			cpqfcHBAdata->fcChip.Registers.IOBaseU);
-	free_irq( HostAdapter->irq, HostAdapter);
-        scsi_unregister( HostAdapter);
-	continue;
-      }	
-      
-      if( check_region( cpqfcHBAdata->fcChip.Registers.IOBaseL, 0xff) )
-      {
-  	printk("  cpqfcTS address in use: %x\n", 
-	      			cpqfcHBAdata->fcChip.Registers.IOBaseL);
-	free_irq( HostAdapter->irq, HostAdapter);
-        scsi_unregister( HostAdapter);
-	continue;
-      }	
-      
-      // OK, we should be able to grab everything we need now.
-      request_region( cpqfcHBAdata->fcChip.Registers.IOBaseL, 0xff, DEV_NAME);
-      request_region( cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff, DEV_NAME);
-      DEBUG_PCI(printk("  Requesting 255 I/O addresses @ %x\n",
-        cpqfcHBAdata->fcChip.Registers.IOBaseL ));
-      DEBUG_PCI(printk("  Requesting 255 I/O addresses @ %x\n",
-        cpqfcHBAdata->fcChip.Registers.IOBaseU ));
-
-      
-      // start our kernel worker thread
-
-      launch_FCworker_thread(HostAdapter);
-
-
-      // start our TimerTask...
-
-      cpqfcTStimer = &cpqfcHBAdata->cpqfcTStimer;
-
-      init_timer( cpqfcTStimer); // Linux clears next/prev values
-      cpqfcTStimer->expires = jiffies + HZ; // one second
-      cpqfcTStimer->data = (unsigned long)cpqfcHBAdata; // this adapter
-      cpqfcTStimer->function = cpqfcTSheartbeat; // handles timeouts, housekeeping
-
-      add_timer( cpqfcTStimer);  // give it to Linux
-
-
-      // now initialize our hardware...
-      if (cpqfcHBAdata->fcChip.InitializeTachyon( cpqfcHBAdata, 1,1)) {
-	printk(KERN_WARNING "cpqfc: initialization of HBA hardware failed.\n");
-	// FIXME: might want to do something better than nothing here.
-      }
-
-      cpqfcHBAdata->fcStatsTime = jiffies;  // (for FC Statistics delta)
-      
-      // give our HBA time to initialize and login current devices...
-      {
-	// The Brocade switch (e.g. 2400, 2010, etc.) as of March 2000,
-	// has the following algorithm for FL_Port startup:
-	// Time(sec) Action
-	// 0:        Device Plugin and LIP(F7,F7) transmission
-	// 1.0       LIP incoming
-        // 1.027     LISA incoming, no CLS! (link not up)
-	// 1.028     NOS incoming (switch test for N_Port)
-        // 1.577     ED_TOV expired, transmit LIPs again	
-	// 3.0       LIP(F8,F7) incoming (switch passes Tach Prim.Sig)
-	// 3.028     LILP received, link up, FLOGI starts
-	// slowest(worst) case, measured on 1Gb Finisar GT analyzer
-	
-	unsigned long stop_time;
-
-        spin_unlock_irq(&io_request_lock);
-	stop_time = jiffies + 4*HZ;
-        while ( time_before(jiffies, stop_time) ) 
-	  	schedule();  // (our worker task needs to run)
+	if (pci_present() == 0)	// no PCI busses?
+	{
+		printk("  no PCI bus?@#!\n");
+		return NumberOfAdapters;
+	}
 
-	spin_lock_irq(&io_request_lock);
-      }
-      
-      NumberOfAdapters++; 
-    } // end of while()
-  }
-
-  LEAVE("cpqfcTS_detect");
- 
-  return NumberOfAdapters;
-}
-
-static void my_ioctl_done (Scsi_Cmnd * SCpnt)
-{
-    struct request * req;
-    
-    req = &SCpnt->request;
-    req->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */
-  
-    if (req->CPQFC_WAITING != NULL)
-	CPQFC_COMPLETE(req->CPQFC_WAITING);
-}   
-
-
-
-int cpqfcTS_ioctl( Scsi_Device *ScsiDev, int Cmnd, void *arg)
-{
-  int result = 0;
-  struct Scsi_Host *HostAdapter = ScsiDev->host;
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  PFC_LOGGEDIN_PORT pLoggedInPort;
-  Scsi_Cmnd DumCmnd;
-  int i, j;
-  VENDOR_IOCTL_REQ ioc;
-  cpqfc_passthru_t *vendor_cmd;
-  Scsi_Device *SDpnt;
-  Scsi_Cmnd *ScsiPassThruCmnd;
-
-  ENTER("cpqfcTS_ioctl ");
-  
-  // can we find an FC device mapping to this SCSI target?
-  DumCmnd.channel = ScsiDev->channel;		// For searching
-  DumCmnd.target  = ScsiDev->id;
-  pLoggedInPort = fcFindLoggedInPort( fcChip,
-    &DumCmnd, // search Scsi Nexus
-    0,        // DON'T search linked list for FC port id
-    NULL,     // DON'T search linked list for FC WWN
-    NULL);    // DON'T care about end of list
- 
-  if( pLoggedInPort == NULL )      // not found!
-  {
-    result = -ENXIO;
-  }
- 
-  else  // we know what FC device to operate on...
-  {
-	// printk("ioctl CMND %d", Cmnd);
-    switch (Cmnd) 
-    {
-      // Passthrough provides a mechanism to bypass the RAID
-      // or other controller and talk directly to the devices
-      // (e.g. physical disk drive)
-      // Passthrough commands, unfortunately, tend to be vendor
-      // specific; this is tailored to COMPAQ's RAID (RA4x00)
-      case CPQFCTS_SCSI_PASSTHRU:
-      {
-	void *buf = NULL; // for kernel space buffer for user data
-	
-	if( !arg)
-	  return -EINVAL;
-
-	// must be super user to send stuff directly to the
-	// controller and/or physical drives...
-	if( !suser() )
-	  return -EPERM;
-
-	// copy the caller's struct to our space.
-        if( copy_from_user( &ioc, arg, sizeof( VENDOR_IOCTL_REQ)))
-		return( -EFAULT);
+	for (i = 0; i < HBA_TYPES; i++) {
+		// look for all HBAs of each type
 
-	vendor_cmd = ioc.argp;  // i.e., CPQ specific command struct
+		while ((PciDev = pci_find_device(cpqfc_boards[i].vendor_id, cpqfc_boards[i].device_id, PciDev))) {
 
-	// If necessary, grab a kernel/DMA buffer
-	if( vendor_cmd->len)
-	{
-  	  buf = kmalloc( vendor_cmd->len, GFP_KERNEL);
-	  if( !buf)
-	    return -ENOMEM;
-	}
-
-        // Now build a SCSI_CMND to pass down...
-	// This function allocates and sets Scsi_Cmnd ptrs such as
-	//  ->channel, ->target, ->host
-        ScsiPassThruCmnd = scsi_allocate_device(ScsiDev, 1, 1);
-
-        // Need data from user?
-	// make sure caller's buffer is in kernel space.
-	if( (vendor_cmd->rw_flag == VENDOR_WRITE_OPCODE) &&
-	    vendor_cmd->len)
-        if(  copy_from_user( buf, vendor_cmd->bufp, vendor_cmd->len))
-		return( -EFAULT);
-	    
-	// copy the CDB (if/when MAX_COMMAND_SIZE is 16, remove copy below)
-        memcpy( &ScsiPassThruCmnd->cmnd[0], 
-		&vendor_cmd->cdb[0], 
-		MAX_COMMAND_SIZE);  
-        // we want to copy all 16 bytes into the FCP-SCSI CDB,
-	// although the actual passthru only uses up to the
-	// first 12.
-	
-	ScsiPassThruCmnd->cmd_len = 16; // sizeof FCP-SCSI CDB
-
-	// Unfortunately, the SCSI command cmnd[] field has only
-	// 12 bytes.  Ideally the MAX_COMMAND_SIZE should be increased
-	// to 16 for newer Fibre Channel and SCSI-3 larger CDBs.
-	// However, to avoid a mandatory kernel rebuild, we use the SCp
-	// spare field to store the extra 4 bytes ( ugly :-(
+			if (pci_enable_device(PciDev) != 0) {
+				printk(KERN_WARNING "cpqfc: pci_enable_devive failed, skipping.\n");
+				continue;
+			}
+			if (pci_set_dma_mask(PciDev, CPQFCTS_DMA_MASK) != 0) {
+				printk(KERN_WARNING "cpqfc: HBA cannot support required DMA mask, skipping.\n");
+				continue;
+			}
+			// NOTE: (kernel 2.2.12-32) limits allocation to 128k bytes...
+			printk(" scsi_register allocating %d bytes for FC HBA\n", (u32) sizeof(CPQFCHBA));
+
+			HostAdapter = scsi_register(ScsiHostTemplate, sizeof(CPQFCHBA));
+
+			if (HostAdapter == NULL)
+				continue;
+			DEBUG_PCI(printk("  HBA found!\n"));
+			DEBUG_PCI(printk("  HostAdapter->PciDev->irq = %u\n", PciDev->irq));
+			DEBUG_PCI(printk("  PciDev->baseaddress[0]= %lx\n", PciDev->resource[0].start));
+			DEBUG_PCI(printk("  PciDev->baseaddress[1]= %lx\n", PciDev->resource[1].start));
+			DEBUG_PCI(printk("  PciDev->baseaddress[2]= %lx\n", PciDev->resource[2].start));
+			DEBUG_PCI(printk("  PciDev->baseaddress[3]= %lx\n", PciDev->resource[3].start));
+
+			scsi_set_pci_device(HostAdapter, PciDev);
+			HostAdapter->irq = PciDev->irq;	// copy for Scsi layers
+
+			// HP Tachlite uses two (255-byte) ranges of Port I/O (lower & upper),
+			// for a total I/O port address space of 512 bytes.
+			// mask out the I/O port address (lower) & record
+			HostAdapter->io_port = (unsigned int)
+			    PciDev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK;
+			HostAdapter->n_io_port = 0xff;
+
+			// i.e., expect 128 targets (arbitrary number), while the
+			//  RA-4000 supports 32 LUNs
+			HostAdapter->max_id = 0;	// incremented as devices log in    
+			HostAdapter->max_lun = CPQFCTS_MAX_LUN;	// LUNs per FC device
+			HostAdapter->max_channel = CPQFCTS_MAX_CHANNEL;	// multiple busses?
+
+			// get the pointer to our HBA specific data... (one for
+			// each HBA on the PCI bus(ses)).
+			cpqfcHBAdata = (CPQFCHBA *) HostAdapter->hostdata;
+
+			// make certain our data struct is clear
+			memset(cpqfcHBAdata, 0, sizeof(CPQFCHBA));
+
+
+			// initialize our HBA info
+			cpqfcHBAdata->HBAnum = NumberOfAdapters;
+
+			cpqfcHBAdata->HostAdapter = HostAdapter;	// back ptr
+			Cpqfc_initHBAdata(cpqfcHBAdata, PciDev);	// fill MOST fields
+
+			cpqfcHBAdata->HBAnum = NumberOfAdapters;
+			cpqfcHBAdata->hba_spinlock = SPIN_LOCK_UNLOCKED;
+
+			// request necessary resources and check for conflicts
+			if (request_irq(HostAdapter->irq, cpqfcTS_intr_handler, SA_INTERRUPT | SA_SHIRQ, DEV_NAME, HostAdapter)) {
+				printk(" IRQ %u already used\n", HostAdapter->irq);
+				scsi_unregister(HostAdapter);
+				continue;
+			}
+			// Since we have two 256-byte I/O port ranges (upper
+			// and lower), check them both
+			if (check_region(cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff)) {
+				printk("  cpqfcTS address in use: %x\n", cpqfcHBAdata->fcChip.Registers.IOBaseU);
+				free_irq(HostAdapter->irq, HostAdapter);
+				scsi_unregister(HostAdapter);
+				continue;
+			}
+
+			if (check_region(cpqfcHBAdata->fcChip.Registers.IOBaseL, 0xff)) {
+				printk("  cpqfcTS address in use: %x\n", cpqfcHBAdata->fcChip.Registers.IOBaseL);
+				free_irq(HostAdapter->irq, HostAdapter);
+				scsi_unregister(HostAdapter);
+				continue;
+			}
+			// OK, we should be able to grab everything we need now.
+			request_region(cpqfcHBAdata->fcChip.Registers.IOBaseL, 0xff, DEV_NAME);
+			request_region(cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff, DEV_NAME);
+			DEBUG_PCI(printk("  Requesting 255 I/O addresses @ %x\n", cpqfcHBAdata->fcChip.Registers.IOBaseL));
+			DEBUG_PCI(printk("  Requesting 255 I/O addresses @ %x\n", cpqfcHBAdata->fcChip.Registers.IOBaseU));
+
+
+			// start our kernel worker thread
+
+			launch_FCworker_thread(HostAdapter);
+
+
+			// start our TimerTask...
+
+			cpqfcTStimer = &cpqfcHBAdata->cpqfcTStimer;
+
+			init_timer(cpqfcTStimer);	// Linux clears next/prev values
+			cpqfcTStimer->expires = jiffies + HZ;	// one second
+			cpqfcTStimer->data = (unsigned long) cpqfcHBAdata;	// this adapter
+			cpqfcTStimer->function = cpqfcTSheartbeat;	// handles timeouts, housekeeping
+
+			add_timer(cpqfcTStimer);	// give it to Linux
+
+
+			// now initialize our hardware...
+			if (cpqfcHBAdata->fcChip.InitializeTachyon(cpqfcHBAdata, 1, 1)) {
+				printk(KERN_WARNING "cpqfc: initialization of HBA hardware failed.\n");
+				// FIXME: might want to do something better than nothing here.
+			}
+
+			cpqfcHBAdata->fcStatsTime = jiffies;	// (for FC Statistics delta)
+
+			// give our HBA time to initialize and login current devices...
+			{
+				// The Brocade switch (e.g. 2400, 2010, etc.) as of March 2000,
+				// has the following algorithm for FL_Port startup:
+				// Time(sec) Action
+				// 0:        Device Plugin and LIP(F7,F7) transmission
+				// 1.0       LIP incoming
+				// 1.027     LISA incoming, no CLS! (link not up)
+				// 1.028     NOS incoming (switch test for N_Port)
+				// 1.577     ED_TOV expired, transmit LIPs again        
+				// 3.0       LIP(F8,F7) incoming (switch passes Tach Prim.Sig)
+				// 3.028     LILP received, link up, FLOGI starts
+				// slowest(worst) case, measured on 1Gb Finisar GT analyzer
+
+				unsigned long stop_time;
+
+				spin_unlock_irq(&io_request_lock);
+				stop_time = jiffies + 4 * HZ;
+				while (time_before(jiffies, stop_time))
+					schedule();	// (our worker task needs to run)
 
-	if( MAX_COMMAND_SIZE < 16)
+				spin_lock_irq(&io_request_lock);
+			}
+
+			NumberOfAdapters++;
+		}		// end of while()
+	}
+
+	LEAVE("cpqfcTS_detect");
+
+	return NumberOfAdapters;
+}
+
+static void my_ioctl_done(Scsi_Cmnd * SCpnt)
+{
+	struct request *req;
+
+	req = &SCpnt->request;
+	req->rq_status = RQ_SCSI_DONE;	/* Busy, but indicate request done */
+
+	if (req->CPQFC_WAITING != NULL)
+		CPQFC_COMPLETE(req->CPQFC_WAITING);
+}
+
+
+
+int cpqfcTS_ioctl(Scsi_Device * ScsiDev, int Cmnd, void *arg)
+{
+	int result = 0;
+	struct Scsi_Host *HostAdapter = ScsiDev->host;
+	CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *) HostAdapter->hostdata;
+	PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+	PFC_LOGGEDIN_PORT pLoggedInPort;
+	Scsi_Cmnd DumCmnd;
+	int i, j;
+	VENDOR_IOCTL_REQ ioc;
+	cpqfc_passthru_t *vendor_cmd;
+	Scsi_Device *SDpnt;
+	Scsi_Cmnd *ScsiPassThruCmnd;
+
+	ENTER("cpqfcTS_ioctl ");
+
+	// can we find an FC device mapping to this SCSI target?
+	DumCmnd.channel = ScsiDev->channel;	// For searching
+	DumCmnd.target = ScsiDev->id;
+	DumCmnd.lun = ScsiDev->lun;
+	pLoggedInPort = fcFindLoggedInPort(fcChip, &DumCmnd,	// search Scsi Nexus
+					   0,	// DON'T search linked list for FC port id
+					   NULL,	// DON'T search linked list for FC WWN
+					   NULL);	// DON'T care about end of list
+
+	if (pLoggedInPort == NULL)	// not found!
 	{
-          memcpy( &ScsiPassThruCmnd->SCp.buffers_residual,
-		  &vendor_cmd->cdb[12], 4);
-	}	  
-                  
-	
-        ScsiPassThruCmnd->SCp.sent_command = 1; // PASSTHRU!
-	                                        // suppress LUN masking
-	                                        // and VSA logic
-
-	// Use spare fields to copy FCP-SCSI LUN address info...
-        ScsiPassThruCmnd->SCp.phase = vendor_cmd->bus;
-	ScsiPassThruCmnd->SCp.have_data_in = vendor_cmd->pdrive;
-
-        // We copy the scheme used by scsi.c to submit commands
-	// to our own HBA.  We do this in order to stall the
-	// thread calling the IOCTL until it completes, and use
-	// the same "_quecommand" function for synchronizing
-	// FC Link events with our "worker thread".
-
-        {
-          CPQFC_DECLARE_COMPLETION(wait);
-          ScsiPassThruCmnd->request.CPQFC_WAITING = &wait;
-          // eventually gets us to our own _quecommand routine
-          scsi_do_cmd( ScsiPassThruCmnd, &vendor_cmd->cdb[0], 
-	       buf, 
-	       vendor_cmd->len, 
-	       my_ioctl_done, 
-	       10*HZ, 1);// timeout,retries
-          // Other I/Os can now resume; we wait for our ioctl
-	  // command to complete
-	  CPQFC_WAIT_FOR_COMPLETION(&wait);
-          ScsiPassThruCmnd->request.CPQFC_WAITING = NULL;
-        }
-	
-        result = ScsiPassThruCmnd->result;
+		result = -ENXIO;
+	}
 
-        // copy any sense data back to caller
-        if( result != 0 )
+	else			// we know what FC device to operate on...
 	{
-	  memcpy( vendor_cmd->sense_data, // see struct def - size=40
-		  ScsiPassThruCmnd->sense_buffer, 
-		  sizeof(ScsiPassThruCmnd->sense_buffer)); 
-	}
-        SDpnt = ScsiPassThruCmnd->device;
-        scsi_release_command(ScsiPassThruCmnd); // "de-allocate"
-        ScsiPassThruCmnd = NULL;
-
-        // if (!SDpnt->was_reset && SDpnt->scsi_request_fn)
-        //  (*SDpnt->scsi_request_fn)();
-
-        wake_up(&SDpnt->scpnt_wait);
-
-	// need to pass data back to user (space)?
-	if( (vendor_cmd->rw_flag == VENDOR_READ_OPCODE) &&
-	     vendor_cmd->len )
-        if(  copy_to_user( vendor_cmd->bufp, buf, vendor_cmd->len))
-		return( -EFAULT);
-
-        if( buf) 
-	  kfree( buf);
-
-        return result;
-      }
-      
-      case CPQFCTS_GETPCIINFO:
-      {
-	cpqfc_pci_info_struct pciinfo;
-	
-	if( !arg)
-	  return -EINVAL;
-
-         	
-	
-        pciinfo.bus = cpqfcHBAdata->PciDev->bus->number;
-        pciinfo.dev_fn = cpqfcHBAdata->PciDev->devfn;  
-	pciinfo.board_id = cpqfcHBAdata->PciDev->device |
-			  (cpqfcHBAdata->PciDev->vendor <<16); 
-	      
-        if(copy_to_user( arg, &pciinfo, sizeof(cpqfc_pci_info_struct)))
-		return( -EFAULT);
-        return 0;
-      }
-
-      case CPQFCTS_GETDRIVVER:
-      {
-	DriverVer_type DriverVer = 
-		CPQFCTS_DRIVER_VER( VER_MAJOR,VER_MINOR,VER_SUBMINOR);
-	
-	if( !arg)
-	  return -EINVAL;
-
-        if(copy_to_user( arg, &DriverVer, sizeof(DriverVer)))
-		return( -EFAULT);
-        return 0;
-      }
-
-
-
-      case CPQFC_IOCTL_FC_TARGET_ADDRESS:
-      result = 
-        verify_area(VERIFY_WRITE, arg, sizeof(Scsi_FCTargAddress));
-      if (result) 
-	break;
- 
-      put_user(pLoggedInPort->port_id,
-		&((Scsi_FCTargAddress *) arg)->host_port_id);
- 
-      for( i=3,j=0; i>=0; i--)   	// copy the LOGIN port's WWN
-        put_user(pLoggedInPort->u.ucWWN[i], 
-		&((Scsi_FCTargAddress *) arg)->host_wwn[j++]);
-      for( i=7; i>3; i--)		// copy the LOGIN port's WWN
-        put_user(pLoggedInPort->u.ucWWN[i], 
-		&((Scsi_FCTargAddress *) arg)->host_wwn[j++]);
-        break;
-
-
-      case CPQFC_IOCTL_FC_TDR:
-          
-        result = cpqfcTS_TargetDeviceReset( ScsiDev, 0);
-
-        break;
-
-
-
-
-    default:
-      result = -EINVAL;
-      break;
-    }
-  }
+		// printk("ioctl CMND %d", Cmnd);
+		switch (Cmnd) {
+			// Passthrough provides a mechanism to bypass the RAID
+			// or other controller and talk directly to the devices
+			// (e.g. physical disk drive)
+			// Passthrough commands, unfortunately, tend to be vendor
+			// specific; this is tailored to COMPAQ's RAID (RA4x00)
+		case CPQFCTS_SCSI_PASSTHRU:
+			{
+				void *buf = NULL;	// for kernel space buffer for user data
+
+				if (!arg)
+					return -EINVAL;
+
+				// must be super user to send stuff directly to the
+				// controller and/or physical drives...
+				if (!suser())
+					return -EPERM;
+
+				// copy the caller's struct to our space.
+				if (copy_from_user(&ioc, arg, sizeof(VENDOR_IOCTL_REQ)))
+					return (-EFAULT);
+
+				vendor_cmd = ioc.argp;	// i.e., CPQ specific command struct
+
+				// If necessary, grab a kernel/DMA buffer
+				if (vendor_cmd->len) {
+					buf = kmalloc(vendor_cmd->len, GFP_KERNEL);
+					if (!buf)
+						return -ENOMEM;
+				}
+				// Now build a SCSI_CMND to pass down...
+				// This function allocates and sets Scsi_Cmnd ptrs such as
+				//  ->channel, ->target, ->host
+				ScsiPassThruCmnd = scsi_allocate_device(ScsiDev, 1, 1);
+
+				// Need data from user?
+				// make sure caller's buffer is in kernel space.
+				if ((vendor_cmd->rw_flag == VENDOR_WRITE_OPCODE) && vendor_cmd->len)
+					if (copy_from_user(buf, vendor_cmd->bufp, vendor_cmd->len))
+						return (-EFAULT);
+
+				// copy the CDB (if/when MAX_COMMAND_SIZE is 16, remove copy below)
+				memcpy(&ScsiPassThruCmnd->cmnd[0], &vendor_cmd->cdb[0], MAX_COMMAND_SIZE);
+				// we want to copy all 16 bytes into the FCP-SCSI CDB,
+				// although the actual passthru only uses up to the
+				// first 12.
+
+				ScsiPassThruCmnd->cmd_len = 16;	// sizeof FCP-SCSI CDB
+
+				// Unfortunately, the SCSI command cmnd[] field has only
+				// 12 bytes.  Ideally the MAX_COMMAND_SIZE should be increased
+				// to 16 for newer Fibre Channel and SCSI-3 larger CDBs.
+				// However, to avoid a mandatory kernel rebuild, we use the SCp
+				// spare field to store the extra 4 bytes ( ugly :-(
+
+				if (MAX_COMMAND_SIZE < 16) {
+					memcpy(&ScsiPassThruCmnd->SCp.buffers_residual, &vendor_cmd->cdb[12], 4);
+				}
+
+
+				ScsiPassThruCmnd->SCp.sent_command = 1;	// PASSTHRU!
+				// suppress LUN masking
+				// and VSA logic
+
+				// Use spare fields to copy FCP-SCSI LUN address info...
+				ScsiPassThruCmnd->SCp.phase = vendor_cmd->bus;
+				ScsiPassThruCmnd->SCp.have_data_in = vendor_cmd->pdrive;
+
+				// We copy the scheme used by scsi.c to submit commands
+				// to our own HBA.  We do this in order to stall the
+				// thread calling the IOCTL until it completes, and use
+				// the same "_quecommand" function for synchronizing
+				// FC Link events with our "worker thread".
+
+				{
+					CPQFC_DECLARE_COMPLETION(wait);
+					ScsiPassThruCmnd->request.CPQFC_WAITING = &wait;
+					// eventually gets us to our own _quecommand routine
+					scsi_do_cmd(ScsiPassThruCmnd, &vendor_cmd->cdb[0], buf, vendor_cmd->len, my_ioctl_done, 10 * HZ, 1);	// timeout,retries
+					// Other I/Os can now resume; we wait for our ioctl
+					// command to complete
+					CPQFC_WAIT_FOR_COMPLETION(&wait);
+					ScsiPassThruCmnd->request.CPQFC_WAITING = NULL;
+				}
+
+				result = ScsiPassThruCmnd->result;
+
+				// copy any sense data back to caller
+				if (result != 0) {
+					memcpy(vendor_cmd->sense_data,	// see struct def - size=40
+					       ScsiPassThruCmnd->sense_buffer, sizeof(ScsiPassThruCmnd->sense_buffer));
+				}
+				SDpnt = ScsiPassThruCmnd->device;
+				scsi_release_command(ScsiPassThruCmnd);	// "de-allocate"
+				ScsiPassThruCmnd = NULL;
+
+				// if (!SDpnt->was_reset && SDpnt->scsi_request_fn)
+				//  (*SDpnt->scsi_request_fn)();
 
-  LEAVE("cpqfcTS_ioctl");
-  return result;
+				wake_up(&SDpnt->scpnt_wait);
+
+				// need to pass data back to user (space)?
+				if ((vendor_cmd->rw_flag == VENDOR_READ_OPCODE) && vendor_cmd->len)
+					if (copy_to_user(vendor_cmd->bufp, buf, vendor_cmd->len))
+						return (-EFAULT);
+
+				if (buf)
+					kfree(buf);
+
+				return result;
+			}
+
+		case CPQFCTS_GETPCIINFO:
+			{
+				cpqfc_pci_info_struct pciinfo;
+
+				if (!arg)
+					return -EINVAL;
+
+
+
+				pciinfo.bus = cpqfcHBAdata->PciDev->bus->number;
+				pciinfo.dev_fn = cpqfcHBAdata->PciDev->devfn;
+				pciinfo.board_id = cpqfcHBAdata->PciDev->device | (cpqfcHBAdata->PciDev->vendor << 16);
+
+				if (copy_to_user(arg, &pciinfo, sizeof(cpqfc_pci_info_struct)))
+					return (-EFAULT);
+				return 0;
+			}
+
+		case CPQFCTS_GETDRIVVER:
+			{
+				DriverVer_type DriverVer = CPQFCTS_DRIVER_VER(VER_MAJOR, VER_MINOR, VER_SUBMINOR);
+
+				if (!arg)
+					return -EINVAL;
+
+				if (copy_to_user(arg, &DriverVer, sizeof(DriverVer)))
+					return (-EFAULT);
+				return 0;
+			}
+
+
+
+		case CPQFC_IOCTL_FC_TARGET_ADDRESS:
+			result = verify_area(VERIFY_WRITE, arg, sizeof(Scsi_FCTargAddress));
+			if (result)
+				break;
+
+			put_user(pLoggedInPort->port_id, &((Scsi_FCTargAddress *) arg)->host_port_id);
+
+			for (i = 3, j = 0; i >= 0; i--)	// copy the LOGIN port's WWN
+				put_user(pLoggedInPort->u.ucWWN[i], &((Scsi_FCTargAddress *) arg)->host_wwn[j++]);
+			for (i = 7; i > 3; i--)	// copy the LOGIN port's WWN
+				put_user(pLoggedInPort->u.ucWWN[i], &((Scsi_FCTargAddress *) arg)->host_wwn[j++]);
+			break;
+
+
+		case CPQFC_IOCTL_FC_TDR:
+
+			result = cpqfcTS_TargetDeviceReset(ScsiDev, 0);
+
+			break;
+
+
+
+
+		default:
+			result = -EINVAL;
+			break;
+		}
+	}
+
+	LEAVE("cpqfcTS_ioctl");
+	return result;
 }
 
 
@@ -718,84 +614,73 @@
 
 int cpqfcTS_release(struct Scsi_Host *HostAdapter)
 {
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata; 
+	CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *) HostAdapter->hostdata;
 
 
-  ENTER("cpqfcTS_release");
-	
-  DEBUG_PCI( printk(" cpqfcTS: delete timer...\n"));
-  del_timer( &cpqfcHBAdata->cpqfcTStimer);  
-    
-  // disable the hardware...
-  DEBUG_PCI( printk(" disable hardware, destroy queues, free mem\n"));
-  cpqfcHBAdata->fcChip.ResetTachyon( cpqfcHBAdata, CLEAR_FCPORTS);
-
-  // kill kernel thread
-  if( cpqfcHBAdata->worker_thread ) // (only if exists)
-  {
-    DECLARE_MUTEX_LOCKED(sem);  // synchronize thread kill
-
-    cpqfcHBAdata->notify_wt = &sem;
-    DEBUG_PCI( printk(" killing kernel thread\n"));
-    send_sig( SIGKILL, cpqfcHBAdata->worker_thread, 1);
-    down( &sem);
-    cpqfcHBAdata->notify_wt = NULL;
-    
-  }
-
-  // free Linux resources
-  DEBUG_PCI( printk(" cpqfcTS: freeing resources...\n"));
-  free_irq( HostAdapter->irq, HostAdapter);
-  scsi_unregister( HostAdapter);
-  release_region( cpqfcHBAdata->fcChip.Registers.IOBaseL, 0xff);
-  release_region( cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff);
- /* we get "vfree: bad address" executing this - need to investigate... 
-  if( (void*)((unsigned long)cpqfcHBAdata->fcChip.Registers.MemBase) !=
-      cpqfcHBAdata->fcChip.Registers.ReMapMemBase)
-    vfree( cpqfcHBAdata->fcChip.Registers.ReMapMemBase);
-*/
+	ENTER("cpqfcTS_release");
+
+	DEBUG_PCI(printk(" cpqfcTS: delete timer...\n"));
+	del_timer(&cpqfcHBAdata->cpqfcTStimer);
 
-  LEAVE("cpqfcTS_release");
-  return 0;
+	// disable the hardware...
+	DEBUG_PCI(printk(" disable hardware, destroy queues, free mem\n"));
+	cpqfcHBAdata->fcChip.ResetTachyon(cpqfcHBAdata, CLEAR_FCPORTS);
+
+	// kill kernel thread
+	if (cpqfcHBAdata->worker_thread)	// (only if exists)
+	{
+		DECLARE_MUTEX_LOCKED(sem);	// synchronize thread kill
+
+		cpqfcHBAdata->notify_wt = &sem;
+		DEBUG_PCI(printk(" killing kernel thread\n"));
+		send_sig(SIGKILL, cpqfcHBAdata->worker_thread, 1);
+		down(&sem);
+		cpqfcHBAdata->notify_wt = NULL;
+
+	}
+	// free Linux resources
+	DEBUG_PCI(printk(" cpqfcTS: freeing resources...\n"));
+	free_irq(HostAdapter->irq, HostAdapter);
+	scsi_unregister(HostAdapter);
+	release_region(cpqfcHBAdata->fcChip.Registers.IOBaseL, 0xff);
+	release_region(cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff);
+	/* we get "vfree: bad address" executing this - need to investigate... 
+	   if( (void*)((unsigned long)cpqfcHBAdata->fcChip.Registers.MemBase) !=
+	   cpqfcHBAdata->fcChip.Registers.ReMapMemBase)
+	   vfree( cpqfcHBAdata->fcChip.Registers.ReMapMemBase);
+	 */
+
+	LEAVE("cpqfcTS_release");
+	return 0;
 }
 
 
-const char * cpqfcTS_info(struct Scsi_Host *HostAdapter)
+const char *cpqfcTS_info(struct Scsi_Host *HostAdapter)
 {
-  static char buf[300];
-  CPQFCHBA *cpqfcHBA;
-  int BusSpeed, BusWidth;
-  
-  // get the pointer to our Scsi layer HBA buffer  
-  cpqfcHBA = (CPQFCHBA *)HostAdapter->hostdata;
-
-  BusWidth = (cpqfcHBA->fcChip.Registers.PCIMCTR &0x4) > 0 ?
-               64 : 32;
-
-  if( cpqfcHBA->fcChip.Registers.TYconfig.value & 0x80000000)
-    BusSpeed = 66;
-  else
-    BusSpeed = 33;
-
-  sprintf(buf, 
-"%s: WWN %08X%08X\n on PCI bus %d device 0x%02x irq %d IObaseL 0x%x, MEMBASE 0x%x\nPCI bus width %d bits, bus speed %d MHz\nFCP-SCSI Driver v%d.%d.%d",
-      cpqfcHBA->fcChip.Name, 
-      cpqfcHBA->fcChip.Registers.wwn_hi,
-      cpqfcHBA->fcChip.Registers.wwn_lo,
-      cpqfcHBA->PciDev->bus->number,
-      cpqfcHBA->PciDev->device,  
-      HostAdapter->irq,
-      cpqfcHBA->fcChip.Registers.IOBaseL,
-      cpqfcHBA->fcChip.Registers.MemBase,
-      BusWidth,
-      BusSpeed,
-      VER_MAJOR, VER_MINOR, VER_SUBMINOR
-);
-
-  
-  cpqfcTSDecodeGBICtype( &cpqfcHBA->fcChip, &buf[ strlen(buf)]);
-  cpqfcTSGetLPSM( &cpqfcHBA->fcChip, &buf[ strlen(buf)]);
-  return buf;
+	static char buf[300];
+	CPQFCHBA *cpqfcHBA;
+	int BusSpeed, BusWidth;
+
+	// get the pointer to our Scsi layer HBA buffer  
+	cpqfcHBA = (CPQFCHBA *) HostAdapter->hostdata;
+
+	BusWidth = (cpqfcHBA->fcChip.Registers.PCIMCTR & 0x4) > 0 ? 64 : 32;
+
+	if (cpqfcHBA->fcChip.Registers.TYconfig.value & 0x80000000)
+		BusSpeed = 66;
+	else
+		BusSpeed = 33;
+
+	sprintf(buf,
+		"%s: WWN %08X%08X\n on PCI bus %d device 0x%02x irq %d IObaseL 0x%x, MEMBASE 0x%x\nPCI bus width %d bits, bus speed %d MHz\nFCP-SCSI Driver v%d.%d.%d",
+		cpqfcHBA->fcChip.Name,
+		cpqfcHBA->fcChip.Registers.wwn_hi,
+		cpqfcHBA->fcChip.Registers.wwn_lo, cpqfcHBA->PciDev->bus->number, cpqfcHBA->PciDev->device, HostAdapter->irq, cpqfcHBA->fcChip.Registers.IOBaseL, cpqfcHBA->fcChip.Registers.MemBase, BusWidth, BusSpeed, VER_MAJOR, VER_MINOR, VER_SUBMINOR);
+
+
+	cpqfcTSDecodeGBICtype(&cpqfcHBA->fcChip, &buf[strlen(buf)]);
+	cpqfcTSGetLPSM(&cpqfcHBA->fcChip, &buf[strlen(buf)]);
+	return buf;
 }
 
 //
@@ -806,178 +691,167 @@
 // programming to use it to make programming a little simpler. This piece
 // of coding is borrowed from ncr53c8xx.c with some modifications 
 //
-struct info_str
-{
-        char *buffer;			// Pointer to output buffer
-        int buflength;			// It's length
-        int bufoffset;			// File offset corresponding with buf[0]
-	int buffillen;			// Current filled length 
-        int filpos;			// Current file offset
+struct info_str {
+	char *buffer;		// Pointer to output buffer
+	int buflength;		// It's length
+	int bufoffset;		// File offset corresponding with buf[0]
+	int buffillen;		// Current filled length 
+	int filpos;		// Current file offset
 };
 
 static void copy_mem_info(struct info_str *info, char *data, int datalen)
 {
 
-  if (info->filpos < info->bufoffset) {	// Current offset before buffer offset
-    if (info->filpos + datalen <= info->bufoffset) {
-      info->filpos += datalen; 		// Discard if completely before buffer
-      return;
-    } else {				// Partial copy, set to begin
-      data += (info->bufoffset - info->filpos);
-      datalen  -= (info->bufoffset - info->filpos);
-      info->filpos = info->bufoffset;
-    }
-  }
-
-  info->filpos += datalen;		// Update current offset
+	if (info->filpos < info->bufoffset) {	// Current offset before buffer offset
+		if (info->filpos + datalen <= info->bufoffset) {
+			info->filpos += datalen;	// Discard if completely before buffer
+			return;
+		} else {	// Partial copy, set to begin
+			data += (info->bufoffset - info->filpos);
+			datalen -= (info->bufoffset - info->filpos);
+			info->filpos = info->bufoffset;
+		}
+	}
+
+	info->filpos += datalen;	// Update current offset
 
-  if (info->buffillen == info->buflength) // Buffer full, discard
-    return;
+	if (info->buffillen == info->buflength)	// Buffer full, discard
+		return;
 
-  if (info->buflength - info->buffillen < datalen)  // Overflows buffer ?
-    datalen = info->buflength - info->buffillen;
+	if (info->buflength - info->buffillen < datalen)	// Overflows buffer ?
+		datalen = info->buflength - info->buffillen;
 
-  memcpy(info->buffer + info->buffillen, data, datalen);
-  info->buffillen += datalen;
+	memcpy(info->buffer + info->buffillen, data, datalen);
+	info->buffillen += datalen;
 }
 
 static int copy_info(struct info_str *info, char *fmt, ...)
 {
-        va_list args;
-        char buf[400];
-        int len;
-
-        va_start(args, fmt);
-        len = vsprintf(buf, fmt, args);
-        va_end(args);
+	va_list args;
+	char buf[400];
+	int len;
+
+	va_start(args, fmt);
+	len = vsprintf(buf, fmt, args);
+	va_end(args);
 
-        copy_mem_info(info, buf, len);
-        return len;
+	copy_mem_info(info, buf, len);
+	return len;
 }
 
 
 // Routine to get data for /proc RAM filesystem
 //
-int cpqfcTS_proc_info (char *buffer, char **start, off_t offset, int length, 
-		       int hostno, int inout)
+int cpqfcTS_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout)
 {
-  struct Scsi_Host *host;
-  Scsi_Cmnd DumCmnd;
-  int Chan, Targ, i;
-  struct info_str info;
-  CPQFCHBA *cpqfcHBA;
-  PTACHYON fcChip;
-  PFC_LOGGEDIN_PORT pLoggedInPort;
-  char buf[81];
-
-  // Search the Scsi host list for our controller
-  for (host=scsi_hostlist; host; host=host->next)
-    if (host->host_no == hostno)
-      break;
-
-  if (!host) return -ESRCH;
-
-  if (inout) return -EINVAL;
-
-  // get the pointer to our Scsi layer HBA buffer  
-  cpqfcHBA = (CPQFCHBA *)host->hostdata;
-  fcChip = &cpqfcHBA->fcChip;
-  
-  *start 	  = buffer;
-
-  info.buffer     = buffer;
-  info.buflength  = length;
-  info.bufoffset  = offset;
-  info.filpos     = 0;
-  info.buffillen  = 0;
-  copy_info(&info, "Driver version = %d.%d.%d", VER_MAJOR, VER_MINOR, VER_SUBMINOR); 
-  cpqfcTSDecodeGBICtype( &cpqfcHBA->fcChip, &buf[0]);
-  cpqfcTSGetLPSM( &cpqfcHBA->fcChip, &buf[ strlen(buf)]);
-  copy_info(&info, "%s\n", buf); 
+	struct Scsi_Host *host;
+	Scsi_Cmnd DumCmnd;
+	int Chan, Targ, i;
+	struct info_str info;
+	CPQFCHBA *cpqfcHBA;
+	PTACHYON fcChip;
+	PFC_LOGGEDIN_PORT pLoggedInPort;
+	char buf[81];
+
+	// Search the Scsi host list for our controller
+	for (host = scsi_hostlist; host; host = host->next)
+		if (host->host_no == hostno)
+			break;
+
+	if (!host)
+		return -ESRCH;
+
+	if (inout)
+		return -EINVAL;
+
+	// get the pointer to our Scsi layer HBA buffer  
+	cpqfcHBA = (CPQFCHBA *) host->hostdata;
+	fcChip = &cpqfcHBA->fcChip;
+
+	*start = buffer;
+
+	info.buffer = buffer;
+	info.buflength = length;
+	info.bufoffset = offset;
+	info.filpos = 0;
+	info.buffillen = 0;
+	copy_info(&info, "Driver version = %d.%d.%d", VER_MAJOR, VER_MINOR, VER_SUBMINOR);
+	cpqfcTSDecodeGBICtype(&cpqfcHBA->fcChip, &buf[0]);
+	cpqfcTSGetLPSM(&cpqfcHBA->fcChip, &buf[strlen(buf)]);
+	copy_info(&info, "%s\n", buf);
 
 #define DISPLAY_WWN_INFO
 #ifdef DISPLAY_WWN_INFO
-  copy_info(&info, "WWN database: (\"port_id: 000000\" means disconnected)\n");
-  for ( Chan=0; Chan <= host->max_channel; Chan++) {
-    DumCmnd.channel = Chan;
-    for (Targ=0; Targ <= host->max_id; Targ++) {
-      DumCmnd.target = Targ;
-      if ((pLoggedInPort = fcFindLoggedInPort( fcChip,
-	    			&DumCmnd, // search Scsi Nexus
-    				0,        // DON'T search list for FC port id
-    				NULL,     // DON'T search list for FC WWN
-    				NULL))){   // DON'T care about end of list
-	copy_info(&info, "Host: scsi%d Channel: %02d TargetId: %02d -> WWN: ",
-			   hostno, Chan, Targ);
-        for( i=3; i>=0; i--)        // copy the LOGIN port's WWN
-          copy_info(&info, "%02X", pLoggedInPort->u.ucWWN[i]);
-        for( i=7; i>3; i--)             // copy the LOGIN port's WWN
-          copy_info(&info, "%02X", pLoggedInPort->u.ucWWN[i]);
-	copy_info(&info, " port_id: %06X\n", pLoggedInPort->port_id); 
-      }
-    }
-  }
+	copy_info(&info, "WWN database: (\"port_id: 000000\" means disconnected)\n");
+	for (Chan = 0; Chan <= host->max_channel; Chan++) {
+		DumCmnd.channel = Chan;
+		for (Targ = 0; Targ <= host->max_id; Targ++) {
+			DumCmnd.target = Targ;
+			if ((pLoggedInPort = fcFindLoggedInPort(fcChip, &DumCmnd,	// search Scsi Nexus
+								0,	// DON'T search list for FC port id
+								NULL,	// DON'T search list for FC WWN
+								NULL))) {	// DON'T care about end of list
+				copy_info(&info, "Host: scsi%d Channel: %02d TargetId: %02d -> WWN: ", hostno, Chan, Targ);
+				for (i = 3; i >= 0; i--)	// copy the LOGIN port's WWN
+					copy_info(&info, "%02X", pLoggedInPort->u.ucWWN[i]);
+				for (i = 7; i > 3; i--)	// copy the LOGIN port's WWN
+					copy_info(&info, "%02X", pLoggedInPort->u.ucWWN[i]);
+				copy_info(&info, " port_id: %06X\n", pLoggedInPort->port_id);
+			}
+		}
+	}
 #endif
 
 
 
-  
-  
+
+
 // Unfortunately, the proc_info buffer isn't big enough
 // for everything we would like...
 // For FC stats, compile this and turn off WWN stuff above  
 //#define DISPLAY_FC_STATS
 #ifdef DISPLAY_FC_STATS
 // get the Fibre Channel statistics
-  {
-    int DeltaSecs = (jiffies - cpqfcHBA->fcStatsTime) / HZ;
-    int days,hours,minutes,secs;
-    
-    days = DeltaSecs / (3600*24); // days
-    hours = (DeltaSecs% (3600*24)) / 3600; // hours
-    minutes = (DeltaSecs%3600 /60); // minutes
-    secs =  DeltaSecs%60;  // secs
-copy_info( &info, "Fibre Channel Stats (time dd:hh:mm:ss %02u:%02u:%02u:%02u\n",
-      days, hours, minutes, secs);
-  }
-    
-  cpqfcHBA->fcStatsTime = jiffies;  // (for next delta)
-
-  copy_info( &info, "  LinkUp           %9u     LinkDown      %u\n",
-        fcChip->fcStats.linkUp, fcChip->fcStats.linkDown);
-        
-  copy_info( &info, "  Loss of Signal   %9u     Loss of Sync  %u\n",
-    fcChip->fcStats.LossofSignal, fcChip->fcStats.LossofSync);
-		  
-  copy_info( &info, "  Discarded Frames %9u     Bad CRC Frame %u\n",
-    fcChip->fcStats.Dis_Frm, fcChip->fcStats.Bad_CRC);
-
-  copy_info( &info, "  TACH LinkFailTX  %9u     TACH LinkFailRX     %u\n",
-    fcChip->fcStats.linkFailTX, fcChip->fcStats.linkFailRX);
-  
-  copy_info( &info, "  TACH RxEOFa      %9u     TACH Elastic Store  %u\n",
-    fcChip->fcStats.Rx_EOFa, fcChip->fcStats.e_stores);
-
-  copy_info( &info, "  BufferCreditWait %9uus   TACH FM Inits %u\n",
-    fcChip->fcStats.BB0_Timer*10, fcChip->fcStats.FMinits );
-	
-  copy_info( &info, "  FC-2 Timeouts    %9u     FC-2 Logouts  %u\n",
-    fcChip->fcStats.timeouts, fcChip->fcStats.logouts); 
-        
-  copy_info( &info, "  FC-2 Aborts      %9u     FC-4 Aborts   %u\n",
-    fcChip->fcStats.FC2aborted, fcChip->fcStats.FC4aborted);
-   
-  // clear the counters
-  cpqfcTSClearLinkStatusCounters( fcChip);
+	{
+		int DeltaSecs = (jiffies - cpqfcHBA->fcStatsTime) / HZ;
+		int days, hours, minutes, secs;
+
+		days = DeltaSecs / (3600 * 24);	// days
+		hours = (DeltaSecs % (3600 * 24)) / 3600;	// hours
+		minutes = (DeltaSecs % 3600 / 60);	// minutes
+		secs = DeltaSecs % 60;	// secs
+		copy_info(&info, "Fibre Channel Stats (time dd:hh:mm:ss %02u:%02u:%02u:%02u\n", days, hours, minutes, secs);
+	}
+
+	cpqfcHBA->fcStatsTime = jiffies;	// (for next delta)
+
+	copy_info(&info, "  LinkUp           %9u     LinkDown      %u\n", fcChip->fcStats.linkUp, fcChip->fcStats.linkDown);
+
+	copy_info(&info, "  Loss of Signal   %9u     Loss of Sync  %u\n", fcChip->fcStats.LossofSignal, fcChip->fcStats.LossofSync);
+
+	copy_info(&info, "  Discarded Frames %9u     Bad CRC Frame %u\n", fcChip->fcStats.Dis_Frm, fcChip->fcStats.Bad_CRC);
+
+	copy_info(&info, "  TACH LinkFailTX  %9u     TACH LinkFailRX     %u\n", fcChip->fcStats.linkFailTX, fcChip->fcStats.linkFailRX);
+
+	copy_info(&info, "  TACH RxEOFa      %9u     TACH Elastic Store  %u\n", fcChip->fcStats.Rx_EOFa, fcChip->fcStats.e_stores);
+
+	copy_info(&info, "  BufferCreditWait %9uus   TACH FM Inits %u\n", fcChip->fcStats.BB0_Timer * 10, fcChip->fcStats.FMinits);
+
+	copy_info(&info, "  FC-2 Timeouts    %9u     FC-2 Logouts  %u\n", fcChip->fcStats.timeouts, fcChip->fcStats.logouts);
+
+	copy_info(&info, "  FC-2 Aborts      %9u     FC-4 Aborts   %u\n", fcChip->fcStats.FC2aborted, fcChip->fcStats.FC4aborted);
+
+	// clear the counters
+	cpqfcTSClearLinkStatusCounters(fcChip);
 #endif
-	
-  return info.buffillen;
+
+	return info.buffillen;
 }
 
 
 #if DEBUG_CMND
 
-UCHAR *ScsiToAscii( UCHAR ScsiCommand)
+u8 *ScsiToAscii(u8 ScsiCommand)
 {
 
 /*++
@@ -1000,152 +874,148 @@
 --*/
 
 
-   switch (ScsiCommand)
-   {
-      case 0x00:
-         return( "Test Unit Ready" );
+	switch (ScsiCommand) {
+	case 0x00:
+		return ("Test Unit Ready");
 
-      case 0x01:
-         return( "Rezero Unit or Rewind" );
+	case 0x01:
+		return ("Rezero Unit or Rewind");
 
-      case 0x02:
-         return( "Request Block Address" );
+	case 0x02:
+		return ("Request Block Address");
 
-      case 0x03:
-         return( "Requese Sense" );
+	case 0x03:
+		return ("Requese Sense");
 
-      case 0x04:
-         return( "Format Unit" );
+	case 0x04:
+		return ("Format Unit");
 
-      case 0x05:
-         return( "Read Block Limits" );
+	case 0x05:
+		return ("Read Block Limits");
 
-      case 0x07:
-         return( "Reassign Blocks" );
+	case 0x07:
+		return ("Reassign Blocks");
 
-      case 0x08:
-         return( "Read (6)" );
+	case 0x08:
+		return ("Read (6)");
 
-      case 0x0a:
-         return( "Write (6)" );
+	case 0x0a:
+		return ("Write (6)");
 
-      case 0x0b:
-         return( "Seek (6)" );
+	case 0x0b:
+		return ("Seek (6)");
 
-      case 0x12:
-         return( "Inquiry" );
+	case 0x12:
+		return ("Inquiry");
 
-      case 0x15:
-         return( "Mode Select (6)" );
+	case 0x15:
+		return ("Mode Select (6)");
 
-      case 0x16:
-         return( "Reserve" );
+	case 0x16:
+		return ("Reserve");
 
-      case 0x17:
-         return( "Release" );
+	case 0x17:
+		return ("Release");
 
-      case 0x1a:
-         return( "ModeSen(6)" );
+	case 0x1a:
+		return ("ModeSen(6)");
 
-      case 0x1b:
-         return( "Start/Stop Unit" );
+	case 0x1b:
+		return ("Start/Stop Unit");
 
-      case 0x1c:
-         return( "Receive Diagnostic Results" );
+	case 0x1c:
+		return ("Receive Diagnostic Results");
 
-      case 0x1d:
-         return( "Send Diagnostic" );
+	case 0x1d:
+		return ("Send Diagnostic");
 
-      case 0x25:
-         return( "Read Capacity" );
+	case 0x25:
+		return ("Read Capacity");
 
-      case 0x28:
-         return( "Read (10)" );
+	case 0x28:
+		return ("Read (10)");
 
-      case 0x2a:
-         return( "Write (10)" );
+	case 0x2a:
+		return ("Write (10)");
 
-      case 0x2b:
-         return( "Seek (10)" );
+	case 0x2b:
+		return ("Seek (10)");
 
-      case 0x2e:
-         return( "Write and Verify" );
+	case 0x2e:
+		return ("Write and Verify");
 
-      case 0x2f:
-         return( "Verify" );
+	case 0x2f:
+		return ("Verify");
 
-      case 0x34:
-         return( "Pre-Fetch" );
+	case 0x34:
+		return ("Pre-Fetch");
 
-      case 0x35:
-         return( "Synchronize Cache" );
+	case 0x35:
+		return ("Synchronize Cache");
 
-      case 0x37:
-         return( "Read Defect Data (10)" );
+	case 0x37:
+		return ("Read Defect Data (10)");
 
-      case 0x3b:
-         return( "Write Buffer" );
+	case 0x3b:
+		return ("Write Buffer");
 
-      case 0x3c:
-         return( "Read Buffer" );
+	case 0x3c:
+		return ("Read Buffer");
 
-      case 0x3e:
-         return( "Read Long" );
+	case 0x3e:
+		return ("Read Long");
 
-      case 0x3f:
-         return( "Write Long" );
+	case 0x3f:
+		return ("Write Long");
 
-      case 0x41:
-         return( "Write Same" );
+	case 0x41:
+		return ("Write Same");
 
-      case 0x4c:
-         return( "Log Select" );
+	case 0x4c:
+		return ("Log Select");
 
-      case 0x4d:
-         return( "Log Sense" );
+	case 0x4d:
+		return ("Log Sense");
 
-      case 0x56:
-         return( "Reserve (10)" );
+	case 0x56:
+		return ("Reserve (10)");
 
-      case 0x57:
-         return( "Release (10)" );
+	case 0x57:
+		return ("Release (10)");
 
-      case 0xa0:
-         return( "ReportLuns" );
+	case 0xa0:
+		return ("ReportLuns");
 
-      case 0xb7:
-         return( "Read Defect Data (12)" );
+	case 0xb7:
+		return ("Read Defect Data (12)");
 
-      case 0xca:
-         return( "Peripheral Device Addressing SCSI Passthrough" );
+	case 0xca:
+		return ("Peripheral Device Addressing SCSI Passthrough");
 
-      case 0xcb:
-         return( "Compaq Array Firmware Passthrough" );
+	case 0xcb:
+		return ("Compaq Array Firmware Passthrough");
 
-      default:
-         return( NULL );
-   }
+	default:
+		return (NULL);
+	}
 
-} // end ScsiToAscii()
+}				// end ScsiToAscii()
 
 void cpqfcTS_print_scsi_cmd(Scsi_Cmnd * cmd)
 {
 
-printk("cpqfcTS: (%s) chnl 0x%02x, trgt = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n", 
-    ScsiToAscii( cmd->cmnd[0]), cmd->channel, cmd->target, cmd->lun, cmd->cmd_len);
+	printk("cpqfcTS: (%s) chnl 0x%02x, trgt = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n", ScsiToAscii(cmd->cmnd[0]), cmd->channel, cmd->target, cmd->lun, cmd->cmd_len);
 
-if( cmd->cmnd[0] == 0)   // Test Unit Ready?
-{
-  int i;
+	if (cmd->cmnd[0] == 0)	// Test Unit Ready?
+	{
+		int i;
 
-  printk("Cmnd->request_bufflen = 0x%X, ->use_sg = %d, ->bufflen = %d\n",
-    cmd->request_bufflen, cmd->use_sg, cmd->bufflen);
-  printk("Cmnd->request_buffer = %p, ->sglist_len = %d, ->buffer = %p\n",
-    cmd->request_buffer, cmd->sglist_len, cmd->buffer);
-  for (i = 0; i < cmd->cmd_len; i++)
-    printk("0x%02x ", cmd->cmnd[i]);
-  printk("\n");
-}
+		printk("Cmnd->request_bufflen = 0x%X, ->use_sg = %d, ->bufflen = %d\n", cmd->request_bufflen, cmd->use_sg, cmd->bufflen);
+		printk("Cmnd->request_buffer = %p, ->sglist_len = %d, ->buffer = %p\n", cmd->request_buffer, cmd->sglist_len, cmd->buffer);
+		for (i = 0; i < cmd->cmd_len; i++)
+			printk("0x%02x ", cmd->cmnd[i]);
+		printk("\n");
+	}
 
 }
 
@@ -1154,51 +1024,48 @@
 
 
 
-static void QueCmndOnBoardLock( CPQFCHBA *cpqfcHBAdata, Scsi_Cmnd *Cmnd)
+static void QueCmndOnBoardLock(CPQFCHBA * cpqfcHBAdata, Scsi_Cmnd * Cmnd)
 {
-  int i;
+	int i;
 
-  for( i=0; i< CPQFCTS_REQ_QUEUE_LEN; i++)
-  {    // find spare slot
-    if( cpqfcHBAdata->BoardLockCmnd[i] == NULL )
-    {
-      cpqfcHBAdata->BoardLockCmnd[i] = Cmnd;
+	for (i = 0; i < CPQFCTS_REQ_QUEUE_LEN; i++) {	// find spare slot
+		if (cpqfcHBAdata->BoardLockCmnd[i] == NULL) {
+			cpqfcHBAdata->BoardLockCmnd[i] = Cmnd;
 //      printk(" BoardLockCmnd[%d] %p Queued, chnl/target/lun %d/%d/%d\n",
 //        i,Cmnd, Cmnd->channel, Cmnd->target, Cmnd->lun);
-      break;
-    }
-  }
-  if( i >= CPQFCTS_REQ_QUEUE_LEN)
-  {
-    printk(" cpqfcTS WARNING: Lost Cmnd %p on BoardLock Q full!", Cmnd);
-  }
+			break;
+		}
+	}
+	if (i >= CPQFCTS_REQ_QUEUE_LEN) {
+		printk(" cpqfcTS WARNING: Lost Cmnd %p on BoardLock Q full!", Cmnd);
+	}
 
 }
 
 
-static void QueLinkDownCmnd( CPQFCHBA *cpqfcHBAdata, Scsi_Cmnd *Cmnd)
+static void QueLinkDownCmnd(CPQFCHBA * cpqfcHBAdata, Scsi_Cmnd * Cmnd)
 {
-  int indx;
+	int indx;
 
-  // Remember the command ptr so we can return; we'll complete when
-  // the device comes back, causing immediate retry
-  for( indx=0; indx < CPQFCTS_REQ_QUEUE_LEN; indx++)//, SCptr++)
-  {
-    if( cpqfcHBAdata->LinkDnCmnd[indx] == NULL ) // available?
-    {
+	// Remember the command ptr so we can return; we'll complete when
+	// the device comes back, causing immediate retry
+	for (indx = 0; indx < CPQFCTS_REQ_QUEUE_LEN; indx++)	//, SCptr++)
+	{
+		if (cpqfcHBAdata->LinkDnCmnd[indx] == NULL)	// available?
+		{
 #ifdef DUMMYCMND_DBG
-      printk(" @add Cmnd %p to LnkDnCmnd[%d]@ ", Cmnd,indx);
+			printk(" @add Cmnd %p to LnkDnCmnd[%d]@ ", Cmnd, indx);
 #endif
-      cpqfcHBAdata->LinkDnCmnd[indx] = Cmnd;
-      break;
-    }
-  }
-
-  if( indx >= CPQFCTS_REQ_QUEUE_LEN ) // no space for Cmnd??
-  {
-    // this will result in an _abort call later (with possible trouble)
-    printk("no buffer for LinkDnCmnd!! %p\n", Cmnd);
-  }
+			cpqfcHBAdata->LinkDnCmnd[indx] = Cmnd;
+			break;
+		}
+	}
+
+	if (indx >= CPQFCTS_REQ_QUEUE_LEN)	// no space for Cmnd??
+	{
+		// this will result in an _abort call later (with possible trouble)
+		printk("no buffer for LinkDnCmnd!! %p\n", Cmnd);
+	}
 }
 
 
@@ -1211,185 +1078,162 @@
 // for cases that don't go to the hardware like scsi cmds destined
 // for LUNs we know don't exist, so this code might be simplified...)
 
-static void QueBadTargetCmnd( CPQFCHBA *cpqfcHBAdata, Scsi_Cmnd *Cmnd)
+static void QueBadTargetCmnd(CPQFCHBA * cpqfcHBAdata, Scsi_Cmnd * Cmnd)
 {
-  int i;
-    //    printk(" can't find target %d\n", Cmnd->target);
+	int i;
+	//    printk(" can't find target %d\n", Cmnd->target);
 
-  for( i=0; i< CPQFCTS_MAX_TARGET_ID; i++)
-  {    // find spare slot
-    if( cpqfcHBAdata->BadTargetCmnd[i] == NULL )
-    {
-      cpqfcHBAdata->BadTargetCmnd[i] = Cmnd;
+	for (i = 0; i < CPQFCTS_MAX_TARGET_ID; i++) {	// find spare slot
+		if (cpqfcHBAdata->BadTargetCmnd[i] == NULL) {
+			cpqfcHBAdata->BadTargetCmnd[i] = Cmnd;
 //      printk(" BadTargetCmnd[%d] %p Queued, chnl/target/lun %d/%d/%d\n",
 //          i,Cmnd, Cmnd->channel, Cmnd->target, Cmnd->lun);
-      break;
-    }
-  }
+			break;
+		}
+	}
 }
 
 
 // This is the "main" entry point for Linux Scsi commands --
 // it all starts here.
 
-int cpqfcTS_queuecommand(Scsi_Cmnd *Cmnd, void (* done)(Scsi_Cmnd *))
+int cpqfcTS_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *))
 {
-  struct Scsi_Host *HostAdapter = Cmnd->host;
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  TachFCHDR_GCMND fchs;  // only use for FC destination id field  
-  PFC_LOGGEDIN_PORT pLoggedInPort;
-  ULONG ulStatus, SESTtype;
-  LONG ExchangeID;
+	struct Scsi_Host *HostAdapter = Cmnd->host;
+	CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *) HostAdapter->hostdata;
+	PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+	TachFCHDR_GCMND fchs;	// only use for FC destination id field  
+	PFC_LOGGEDIN_PORT pLoggedInPort;
+	u32 ulStatus, SESTtype;
+	s32 ExchangeID;
+
+
 
 
+	ENTER("cpqfcTS_queuecommand");
 
+	PCI_TRACEO((u32) Cmnd, 0x98)
 
-  ENTER("cpqfcTS_queuecommand");
-      
-  PCI_TRACEO( (ULONG)Cmnd, 0x98)
-      
-  
-  Cmnd->scsi_done = done;
-#ifdef DEBUG_CMND  
-  cpqfcTS_print_scsi_cmd( Cmnd);
+
+	    Cmnd->scsi_done = done;
+#ifdef DEBUG_CMND
+	cpqfcTS_print_scsi_cmd(Cmnd);
 #endif
 
-  // prevent board contention with kernel thread...  
-  
-   if( cpqfcHBAdata->BoardLock )
-  {
+	// prevent board contention with kernel thread...  
+
+	if (cpqfcHBAdata->BoardLock) {
 //    printk(" @BrdLck Hld@ ");
-    QueCmndOnBoardLock( cpqfcHBAdata, Cmnd);
-  }
-  
-  else
-  {
-
-    // in the current system (2.2.12), this routine is called
-    // after spin_lock_irqsave(), so INTs are disabled. However,
-    // we might have something pending in the LinkQ, which
-    // might cause the WorkerTask to run.  In case that
-    // happens, make sure we lock it out.
-    
-    
-    
-    PCI_TRACE( 0x98) 
-    CPQ_SPINLOCK_HBA( cpqfcHBAdata)
-    PCI_TRACE( 0x98) 
-	    
-  // can we find an FC device mapping to this SCSI target?
-    pLoggedInPort = fcFindLoggedInPort( fcChip,
-      Cmnd,     // search Scsi Nexus
-      0,        // DON'T search linked list for FC port id
-      NULL,     // DON'T search linked list for FC WWN
-      NULL);    // DON'T care about end of list
- 
-    if( pLoggedInPort == NULL )      // not found!
-    {
+		QueCmndOnBoardLock(cpqfcHBAdata, Cmnd);
+	}
+
+	else {
+
+		// in the current system (2.2.12), this routine is called
+		// after spin_lock_irqsave(), so INTs are disabled. However,
+		// we might have something pending in the LinkQ, which
+		// might cause the WorkerTask to run.  In case that
+		// happens, make sure we lock it out.
+
+
+
+		PCI_TRACE(0x98)
+		    CPQ_SPINLOCK_HBA(cpqfcHBAdata)
+		    PCI_TRACE(0x98)
+		    // can we find an FC device mapping to this SCSI target?
+		    pLoggedInPort = fcFindLoggedInPort(fcChip, Cmnd,	// search Scsi Nexus
+						       0,	// DON'T search linked list for FC port id
+						       NULL,	// DON'T search linked list for FC WWN
+						       NULL);	// DON'T care about end of list
+
+		if (pLoggedInPort == NULL)	// not found!
+		{
 //    printk(" @Q bad targ cmnd %p@ ", Cmnd);
-      QueBadTargetCmnd( cpqfcHBAdata, Cmnd);
-    }
-    else if (Cmnd->lun >= CPQFCTS_MAX_LUN)
-    {
-      printk(KERN_WARNING "cpqfc: Invalid LUN: %d\n", Cmnd->lun);
-      QueBadTargetCmnd( cpqfcHBAdata, Cmnd);
-    } 
-
-    else  // we know what FC device to send to...
-    {
-
-      // does this device support FCP target functions?
-      // (determined by PRLI field)
-
-      if( !(pLoggedInPort->fcp_info & TARGET_FUNCTION) )
-      {
-        printk(" Doesn't support TARGET functions port_id %Xh\n",
-          pLoggedInPort->port_id );
-        QueBadTargetCmnd( cpqfcHBAdata, Cmnd);
-      }
-
-    // In this case (previous login OK), the device is temporarily
-    // unavailable waiting for re-login, in which case we expect it
-    // to be back in between 25 - 500ms.  
-    // If the FC port doesn't log back in within several seconds
-    // (i.e. implicit "logout"), or we get an explicit logout,
-    // we set "device_blocked" in Scsi_Device struct; in this
-    // case 30 seconds will elapse before Linux/Scsi sends another
-    // command to the device.
-      else if( pLoggedInPort->prli != TRUE )
-      {
+			QueBadTargetCmnd(cpqfcHBAdata, Cmnd);
+		} else if (Cmnd->lun >= CPQFCTS_MAX_LUN) {
+			printk(KERN_WARNING "cpqfc: Invalid LUN: %d\n", Cmnd->lun);
+			QueBadTargetCmnd(cpqfcHBAdata, Cmnd);
+		}
+
+		else		// we know what FC device to send to...
+		{
+
+			// does this device support FCP target functions?
+			// (determined by PRLI field)
+
+			if (!(pLoggedInPort->fcp_info & TARGET_FUNCTION)) {
+				printk(" Doesn't support TARGET functions port_id %Xh\n", pLoggedInPort->port_id);
+				QueBadTargetCmnd(cpqfcHBAdata, Cmnd);
+			}
+			// In this case (previous login OK), the device is temporarily
+			// unavailable waiting for re-login, in which case we expect it
+			// to be back in between 25 - 500ms.  
+			// If the FC port doesn't log back in within several seconds
+			// (i.e. implicit "logout"), or we get an explicit logout,
+			// we set "device_blocked" in Scsi_Device struct; in this
+			// case 30 seconds will elapse before Linux/Scsi sends another
+			// command to the device.
+			else if (pLoggedInPort->prli != TRUE) {
 //      printk("Device (Chnl/Target %d/%d) invalid PRLI, port_id %06lXh\n",
 //        Cmnd->channel, Cmnd->target, pLoggedInPort->port_id);
-        QueLinkDownCmnd( cpqfcHBAdata, Cmnd);
-//    Need to use "blocked" flag??   	
-//	Cmnd->device->device_blocked = TRUE; // just let it timeout
-      }
-      else  // device supports TARGET functions, and is logged in...
-      {
-      // (context of fchs is to "reply" to...)
-        fchs.s_id = pLoggedInPort->port_id; // destination FC address
-
-      // what is the data direction?  For data TO the device,
-      // we need IWE (Intiator Write Entry).  Otherwise, IRE.
-
-        if( Cmnd->cmnd[0] == WRITE_10 ||
-  	  Cmnd->cmnd[0] == WRITE_6 ||
-	  Cmnd->cmnd[0] == WRITE_BUFFER ||      
-	  Cmnd->cmnd[0] == VENDOR_WRITE_OPCODE ||  // CPQ specific 
-	  Cmnd->cmnd[0] == MODE_SELECT )
-        {
-          SESTtype = SCSI_IWE; // data from HBA to Device
-        }
-        else
-          SESTtype = SCSI_IRE; // data from Device to HBA
-    	  
-        ulStatus = cpqfcTSBuildExchange(
-          cpqfcHBAdata,
-          SESTtype,     // e.g. Initiator Read Entry (IRE)
-          &fchs,        // we are originator; only use d_id
-          Cmnd,         // Linux SCSI command (with scatter/gather list)
-          &ExchangeID );// fcController->fcExchanges index, -1 if failed
+				QueLinkDownCmnd(cpqfcHBAdata, Cmnd);
+//    Need to use "blocked" flag??      
+//      Cmnd->device->device_blocked = TRUE; // just let it timeout
+			} else	// device supports TARGET functions, and is logged in...
+			{
+				// (context of fchs is to "reply" to...)
+				fchs.s_id = pLoggedInPort->port_id;	// destination FC address
+
+				// what is the data direction?  For data TO the device,
+				// we need IWE (Intiator Write Entry).  Otherwise, IRE.
+
+				if (Cmnd->cmnd[0] == WRITE_10 || Cmnd->cmnd[0] == WRITE_6 || Cmnd->cmnd[0] == WRITE_BUFFER || Cmnd->cmnd[0] == VENDOR_WRITE_OPCODE ||	// CPQ specific 
+				    Cmnd->cmnd[0] == MODE_SELECT) {
+					SESTtype = SCSI_IWE;	// data from HBA to Device
+				} else
+					SESTtype = SCSI_IRE;	// data from Device to HBA
+
+				ulStatus = cpqfcTSBuildExchange(cpqfcHBAdata, SESTtype,	// e.g. Initiator Read Entry (IRE)
+								&fchs,	// we are originator; only use d_id
+								Cmnd,	// Linux SCSI command (with scatter/gather list)
+								&ExchangeID);	// fcController->fcExchanges index, -1 if failed
+
+				if (!ulStatus)	// Exchange setup?
+
+				{
+					if (cpqfcHBAdata->BoardLock) {
+						TriggerHBA(fcChip->Registers.ReMapMemBase, 0);
+						printk(" @bl! %d, xID %Xh@ ", current->pid, ExchangeID);
+					}
+
+					ulStatus = cpqfcTSStartExchange(cpqfcHBAdata, ExchangeID);
+					if (!ulStatus) {
+						PCI_TRACEO(ExchangeID, 0xB8)
+						    // submitted to Tach's Outbound Que (ERQ PI incremented)
+						    // waited for completion for ELS type (Login frames issued
+						    // synchronously)
+					} else
+						// check reason for Exchange not being started - we might
+						// want to Queue and start later, or fail with error
+					{
+						printk("quecommand: cpqfcTSStartExchange failed: %Xh\n", ulStatus);
+					}
+				}	// end good BuildExchange status
+
+				else	// SEST table probably full  -- why? hardware hang?
+				{
+					printk("quecommand: cpqfcTSBuildExchange faild: %Xh\n", ulStatus);
+				}
+			}	// end can't do FCP-SCSI target functions
+		}		// end can't find target (FC device)
 
-        if( !ulStatus ) // Exchange setup?
-   
-        {
-          if( cpqfcHBAdata->BoardLock )
-          {
-    TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
-	    printk(" @bl! %d, xID %Xh@ ", current->pid, ExchangeID);
-          }
-
-	  ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
-	  if( !ulStatus )
-          {
-            PCI_TRACEO( ExchangeID, 0xB8) 
-          // submitted to Tach's Outbound Que (ERQ PI incremented)
-          // waited for completion for ELS type (Login frames issued
-          // synchronously)
-	  }
-          else
-            // check reason for Exchange not being started - we might
-            // want to Queue and start later, or fail with error
-          {
-            printk("quecommand: cpqfcTSStartExchange failed: %Xh\n", ulStatus );
-          }
-        }            // end good BuildExchange status
-        
-        else  // SEST table probably full  -- why? hardware hang?
-        {
-	  printk("quecommand: cpqfcTSBuildExchange faild: %Xh\n", ulStatus);
-        }
-      }  // end can't do FCP-SCSI target functions
-    } // end can't find target (FC device)
-
-    CPQ_SPINUNLOCK_HBA( cpqfcHBAdata)
-  }
-	
-  PCI_TRACEO( (ULONG)Cmnd, 0x9C) 
-  LEAVE("cpqfcTS_queuecommand");
-  return 0;
-}    
+		CPQ_SPINUNLOCK_HBA(cpqfcHBAdata)
+	}
+
+	PCI_TRACEO((u32) Cmnd, 0x9C)
+	    LEAVE("cpqfcTS_queuecommand");
+	return 0;
+}
 
 
 // Entry point for upper Scsi layer intiated abort.  Typically
@@ -1403,148 +1247,140 @@
 // errors, it should be considered a driver error and reported to
 // the author.
 
-int cpqfcTS_abort(Scsi_Cmnd *Cmnd)
+int cpqfcTS_abort(Scsi_Cmnd * Cmnd)
 {
-//	printk(" cpqfcTS_abort called?? \n");
- 	return 0;
+//      printk(" cpqfcTS_abort called?? \n");
+	return 0;
 }
- 
-int cpqfcTS_eh_abort(Scsi_Cmnd *Cmnd)
+
+int cpqfcTS_eh_abort(Scsi_Cmnd * Cmnd)
 {
 
-  struct Scsi_Host *HostAdapter = Cmnd->host;
-  // get the pointer to our Scsi layer HBA buffer  
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  int i;
-  ENTER("cpqfcTS_eh_abort");
-
-  Cmnd->result = DID_ABORT <<16;  // assume we'll find it
-
-  printk(" @Linux _abort Scsi_Cmnd %p ", Cmnd);
-  // See if we can find a Cmnd pointer that matches...
-  // The most likely case is we accepted the command
-  // from Linux Scsi (e.g. ceated a SEST entry) and it
-  // got lost somehow.  If we can't find any reference
-  // to the passed pointer, we can only presume it
-  // got completed as far as our driver is concerned.
-  // If we found it, we will try to abort it through
-  // common mechanism.  If FC ABTS is successful (ACC)
-  // or is rejected (RJT) by target, we will call
-  // Scsi "done" quickly.  Otherwise, the ABTS will timeout
-  // and we'll call "done" later.
-
-  // Search the SEST exchanges for a matching Cmnd ptr.
-  for( i=0; i< TACH_SEST_LEN; i++)
-  {
-    if( Exchanges->fcExchange[i].Cmnd == Cmnd )
-    {
-      
-      // found it!
-      printk(" x_ID %Xh, type %Xh\n", i, Exchanges->fcExchange[i].type);
-
-      Exchanges->fcExchange[i].status = INITIATOR_ABORT; // seconds default
-      Exchanges->fcExchange[i].timeOut = 10; // seconds default (changed later)
-
-      // Since we need to immediately return the aborted Cmnd to Scsi 
-      // upper layers, we can't make future reference to any of it's 
-      // fields (e.g the Nexus).
-
-      cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &i);
-
-      break;
-    }
-  }
-
-  if( i >= TACH_SEST_LEN ) // didn't find Cmnd ptr in chip's SEST?
-  {
-    // now search our non-SEST buffers (i.e. Cmnd waiting to
-    // start on the HBA or waiting to complete with error for retry).
-    
-    // first check BadTargetCmnd
-    for( i=0; i< CPQFCTS_MAX_TARGET_ID; i++)
-    { 
-      if( cpqfcHBAdata->BadTargetCmnd[i] == Cmnd )
-      {
-        cpqfcHBAdata->BadTargetCmnd[i] = NULL;
-	printk("in BadTargetCmnd Q\n");
-	goto Done; // exit
-      }
-    }
-
-    // if not found above...
-
-    for( i=0; i < CPQFCTS_REQ_QUEUE_LEN; i++)
-    {
-      if( cpqfcHBAdata->LinkDnCmnd[i] == Cmnd ) 
-      {
-	cpqfcHBAdata->LinkDnCmnd[i] = NULL;
-	printk("in LinkDnCmnd Q\n");
-	goto Done;
-      }
-    }
-
-
-    for( i=0; i< CPQFCTS_REQ_QUEUE_LEN; i++)
-    {    // find spare slot
-      if( cpqfcHBAdata->BoardLockCmnd[i] == Cmnd )
-      {
-        cpqfcHBAdata->BoardLockCmnd[i] = NULL;
-	printk("in BoardLockCmnd Q\n");
-	goto Done;
-      }
-    }
-    
-    Cmnd->result = DID_ERROR <<16;  // Hmmm...
-    printk("Not found! ");
+	struct Scsi_Host *HostAdapter = Cmnd->host;
+	// get the pointer to our Scsi layer HBA buffer  
+	CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *) HostAdapter->hostdata;
+	PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	int i;
+	ENTER("cpqfcTS_eh_abort");
+
+	Cmnd->result = DID_ABORT << 16;	// assume we'll find it
+
+	printk(" @Linux _abort Scsi_Cmnd %p ", Cmnd);
+	// See if we can find a Cmnd pointer that matches...
+	// The most likely case is we accepted the command
+	// from Linux Scsi (e.g. ceated a SEST entry) and it
+	// got lost somehow.  If we can't find any reference
+	// to the passed pointer, we can only presume it
+	// got completed as far as our driver is concerned.
+	// If we found it, we will try to abort it through
+	// common mechanism.  If FC ABTS is successful (ACC)
+	// or is rejected (RJT) by target, we will call
+	// Scsi "done" quickly.  Otherwise, the ABTS will timeout
+	// and we'll call "done" later.
+
+	// Search the SEST exchanges for a matching Cmnd ptr.
+	for (i = 0; i < TACH_SEST_LEN; i++) {
+		if (Exchanges->fcExchange[i].Cmnd == Cmnd) {
+
+			// found it!
+			printk(" x_ID %Xh, type %Xh\n", i, Exchanges->fcExchange[i].type);
+
+			Exchanges->fcExchange[i].status = INITIATOR_ABORT;	// seconds default
+			Exchanges->fcExchange[i].timeOut = 10;	// seconds default (changed later)
+
+			// Since we need to immediately return the aborted Cmnd to Scsi 
+			// upper layers, we can't make future reference to any of it's 
+			// fields (e.g the Nexus).
+
+			cpqfcTSPutLinkQue(cpqfcHBAdata, BLS_ABTS, &i);
+
+			break;
+		}
+	}
+
+	if (i >= TACH_SEST_LEN)	// didn't find Cmnd ptr in chip's SEST?
+	{
+		// now search our non-SEST buffers (i.e. Cmnd waiting to
+		// start on the HBA or waiting to complete with error for retry).
+
+		// first check BadTargetCmnd
+		for (i = 0; i < CPQFCTS_MAX_TARGET_ID; i++) {
+			if (cpqfcHBAdata->BadTargetCmnd[i] == Cmnd) {
+				cpqfcHBAdata->BadTargetCmnd[i] = NULL;
+				printk("in BadTargetCmnd Q\n");
+				goto Done;	// exit
+			}
+		}
+
+		// if not found above...
+
+		for (i = 0; i < CPQFCTS_REQ_QUEUE_LEN; i++) {
+			if (cpqfcHBAdata->LinkDnCmnd[i] == Cmnd) {
+				cpqfcHBAdata->LinkDnCmnd[i] = NULL;
+				printk("in LinkDnCmnd Q\n");
+				goto Done;
+			}
+		}
+
+
+		for (i = 0; i < CPQFCTS_REQ_QUEUE_LEN; i++) {	// find spare slot
+			if (cpqfcHBAdata->BoardLockCmnd[i] == Cmnd) {
+				cpqfcHBAdata->BoardLockCmnd[i] = NULL;
+				printk("in BoardLockCmnd Q\n");
+				goto Done;
+			}
+		}
+
+		Cmnd->result = DID_ERROR << 16;	// Hmmm...
+		printk("Not found! ");
 //    panic("_abort");
-  }
-  
-Done:
-  
+	}
+
+      Done:
+
 //    panic("_abort");
-  LEAVE("cpqfcTS_eh_abort");
-  return 0;  // (see scsi.h)
-}    
+	LEAVE("cpqfcTS_eh_abort");
+	return 0;		// (see scsi.h)
+}
 
 
 // FCP-SCSI Target Device Reset
 // See dpANS Fibre Channel Protocol for SCSI
 // X3.269-199X revision 12, pg 25
 
-int cpqfcTS_TargetDeviceReset( Scsi_Device *ScsiDev, 
-                               unsigned int reset_flags)
+int cpqfcTS_TargetDeviceReset(Scsi_Device * ScsiDev, unsigned int reset_flags)
 {
-  int timeout = 10*HZ;
-  int retries = 1;
-  char scsi_cdb[12];
-  int result;
-  Scsi_Cmnd * SCpnt;
-  Scsi_Device * SDpnt;
-
-
-  // printk("   ENTERING cpqfcTS_TargetDeviceReset() - flag=%d \n",reset_flags);
-
-  if (ScsiDev->host->eh_active) return FAILED;
-
-  memset( scsi_cdb, 0, sizeof( scsi_cdb));
-
-  scsi_cdb[0] = RELEASE;
-
-  // allocate with wait = true, interruptible = false 
-  SCpnt = scsi_allocate_device(ScsiDev, 1, 0);
-  {
-    CPQFC_DECLARE_COMPLETION(wait);
-        
-    SCpnt->SCp.buffers_residual = FCP_TARGET_RESET;
-
-	SCpnt->request.CPQFC_WAITING = &wait;
-	scsi_do_cmd(SCpnt,  scsi_cdb, NULL,  0, my_ioctl_done,  timeout, retries);
-	CPQFC_WAIT_FOR_COMPLETION(&wait);
-	SCpnt->request.CPQFC_WAITING = NULL;
-  }
-    
+	int timeout = 10 * HZ;
+	int retries = 1;
+	char scsi_cdb[12];
+	int result;
+	Scsi_Cmnd *SCpnt;
+	Scsi_Device *SDpnt;
+
+
+	// printk("   ENTERING cpqfcTS_TargetDeviceReset() - flag=%d \n",reset_flags);
+
+	if (ScsiDev->host->eh_active)
+		return FAILED;
+
+	memset(scsi_cdb, 0, sizeof(scsi_cdb));
+
+	scsi_cdb[0] = RELEASE;
+
+	// allocate with wait = true, interruptible = false 
+	SCpnt = scsi_allocate_device(ScsiDev, 1, 0);
+	{
+		CPQFC_DECLARE_COMPLETION(wait);
+
+		SCpnt->SCp.buffers_residual = FCP_TARGET_RESET;
+
+		SCpnt->request.CPQFC_WAITING = &wait;
+		scsi_do_cmd(SCpnt, scsi_cdb, NULL, 0, my_ioctl_done, timeout, retries);
+		CPQFC_WAIT_FOR_COMPLETION(&wait);
+		SCpnt->request.CPQFC_WAITING = NULL;
+	}
+
 /*
       if(driver_byte(SCpnt->result) != 0)
 	  switch(SCpnt->sense_buffer[2] & 0xf) {
@@ -1577,41 +1413,41 @@
 		   SCpnt->sense_buffer[2] & 0xf);
 	    
       };
-*/    
-  result = SCpnt->result;
+*/
+	result = SCpnt->result;
 
-  SDpnt = SCpnt->device;
-  scsi_release_command(SCpnt);
-  SCpnt = NULL;
+	SDpnt = SCpnt->device;
+	scsi_release_command(SCpnt);
+	SCpnt = NULL;
 
-  // if (!SDpnt->was_reset && SDpnt->scsi_request_fn)
-  // 	(*SDpnt->scsi_request_fn)();
+	// if (!SDpnt->was_reset && SDpnt->scsi_request_fn)
+	//    (*SDpnt->scsi_request_fn)();
 
-  wake_up(&SDpnt->scpnt_wait);
-  // printk("   LEAVING cpqfcTS_TargetDeviceReset() - return SUCCESS \n");
-  return SUCCESS;
+	wake_up(&SDpnt->scpnt_wait);
+	// printk("   LEAVING cpqfcTS_TargetDeviceReset() - return SUCCESS \n");
+	return SUCCESS;
 }
 
 
-int cpqfcTS_eh_device_reset(Scsi_Cmnd *Cmnd)
+int cpqfcTS_eh_device_reset(Scsi_Cmnd * Cmnd)
 {
-  int retval;
-  Scsi_Device *SDpnt = Cmnd->device;
-  // printk("   ENTERING cpqfcTS_eh_device_reset() \n");
-  spin_unlock_irq(&io_request_lock);
-  retval = cpqfcTS_TargetDeviceReset( SDpnt, 0);
-  spin_lock_irq(&io_request_lock);
-  return retval;
+	int retval;
+	Scsi_Device *SDpnt = Cmnd->device;
+	// printk("   ENTERING cpqfcTS_eh_device_reset() \n");
+	spin_unlock_irq(&io_request_lock);
+	retval = cpqfcTS_TargetDeviceReset(SDpnt, 0);
+	spin_lock_irq(&io_request_lock);
+	return retval;
 }
 
-	
-int cpqfcTS_reset(Scsi_Cmnd *Cmnd, unsigned int reset_flags)
+
+int cpqfcTS_reset(Scsi_Cmnd * Cmnd, unsigned int reset_flags)
 {
 
-  ENTER("cpqfcTS_reset");
+	ENTER("cpqfcTS_reset");
 
-  LEAVE("cpqfcTS_reset");
-  return SCSI_RESET_ERROR;      /* Bus Reset Not supported */
+	LEAVE("cpqfcTS_reset");
+	return SCSI_RESET_ERROR;	/* Bus Reset Not supported */
 }
 
 /* This function determines the bios parameters for a given
@@ -1621,228 +1457,210 @@
    (from hosts.h)
 */
 
-int cpqfcTS_biosparam(Disk *disk, kdev_t n, int ip[])
+int cpqfcTS_biosparam(Disk * disk, kdev_t n, int ip[])
 {
-  int size = disk->capacity;
-  
-  ENTER("cpqfcTS_biosparam");
-  ip[0] = 64;
-  ip[1] = 32;
-  ip[2] = size >> 11;
-  
-  if( ip[2] > 1024 )
-  {
-    ip[0] = 255;
-    ip[1] = 63;
-    ip[2] = size / (ip[0] * ip[1]);
-  }
-
-  LEAVE("cpqfcTS_biosparam");
-  return 0;
-}    
+	int size = disk->capacity;
 
+	ENTER("cpqfcTS_biosparam");
+	ip[0] = 64;
+	ip[1] = 32;
+	ip[2] = size >> 11;
+
+	if (ip[2] > 1024) {
+		ip[0] = 255;
+		ip[1] = 63;
+		ip[2] = size / (ip[0] * ip[1]);
+	}
 
+	LEAVE("cpqfcTS_biosparam");
+	return 0;
+}
 
-void cpqfcTS_intr_handler( int irq, 
-		void *dev_id, 
-		struct pt_regs *regs)
-{
-
-  unsigned long flags, InfLoopBrk=0;
-  struct Scsi_Host *HostAdapter = dev_id;
-  CPQFCHBA *cpqfcHBA = (CPQFCHBA *)HostAdapter->hostdata;
-  int MoreMessages = 1; // assume we have something to do
-  UCHAR IntPending;
-  
-  ENTER("intr_handler");
-
-  spin_lock_irqsave( &io_request_lock, flags);
-  // is this our INT?
-  IntPending = readb( cpqfcHBA->fcChip.Registers.INTPEND.address);
 
-  // broken boards can generate messages forever, so
-  // prevent the infinite loop
+
+void cpqfcTS_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+
+	unsigned long flags, InfLoopBrk = 0;
+	struct Scsi_Host *HostAdapter = dev_id;
+	CPQFCHBA *cpqfcHBA = (CPQFCHBA *) HostAdapter->hostdata;
+	int MoreMessages = 1;	// assume we have something to do
+	u8 IntPending;
+
+	ENTER("intr_handler");
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	// is this our INT?
+	IntPending = readb(cpqfcHBA->fcChip.Registers.INTPEND.address);
+
+	// broken boards can generate messages forever, so
+	// prevent the infinite loop
 #define INFINITE_IMQ_BREAK 10000
-  if( IntPending )
-  {
-    
-    // mask our HBA interrupts until we handle it...
-    writeb( 0, cpqfcHBA->fcChip.Registers.INTEN.address);
-
-    if( IntPending & 0x4) // "INT" - Tach wrote to IMQ
-    {
-      while( (++InfLoopBrk < INFINITE_IMQ_BREAK) && (MoreMessages ==1) ) 
-      {
-        MoreMessages = CpqTsProcessIMQEntry( HostAdapter); // ret 0 when done
-      }
-      if( InfLoopBrk >= INFINITE_IMQ_BREAK )
-      {
-        printk("WARNING: Compaq FC adapter generating excessive INTs -REPLACE\n");
-        printk("or investigate alternate causes (e.g. physical FC layer)\n");
-      }
-
-      else  // working normally - re-enable INTs and continue
-        writeb( 0x1F, cpqfcHBA->fcChip.Registers.INTEN.address);
-    
-    }  // (...ProcessIMQEntry() clears INT by writing IMQ consumer)
-    else  // indications of errors or problems...
-          // these usually indicate critical system hardware problems.
-    {
-      if( IntPending & 0x10 )
-  	printk(" cpqfcTS adapter external memory parity error detected\n");
-      if( IntPending & 0x8 )
-  	printk(" cpqfcTS adapter PCI master address crossed 45-bit boundary\n");
-      if( IntPending & 0x2 )
-	printk(" cpqfcTS adapter DMA error detected\n");
-      if( IntPending & 0x1 ) {
-  	UCHAR IntStat;
-  	printk(" cpqfcTS adapter PCI error detected\n");
-  	IntStat = readb( cpqfcHBA->fcChip.Registers.INTSTAT.address);
-	if (IntStat & 0x4) printk("(INT)\n");
-	if (IntStat & 0x8) 
-		printk("CRS: PCI master address crossed 46 bit bouandary\n");
-	if (IntStat & 0x10) printk("MRE: external memory parity error.\n");
-      }
-    }      
-  }
-  spin_unlock_irqrestore( &io_request_lock, flags);
-  LEAVE("intr_handler");
+	if (IntPending) {
+
+		// mask our HBA interrupts until we handle it...
+		writeb(0, cpqfcHBA->fcChip.Registers.INTEN.address);
+
+		if (IntPending & 0x4)	// "INT" - Tach wrote to IMQ
+		{
+			while ((++InfLoopBrk < INFINITE_IMQ_BREAK) && (MoreMessages == 1)) {
+				MoreMessages = CpqTsProcessIMQEntry(HostAdapter);	// ret 0 when done
+			}
+			if (InfLoopBrk >= INFINITE_IMQ_BREAK) {
+				printk("WARNING: Compaq FC adapter generating excessive INTs -REPLACE\n");
+				printk("or investigate alternate causes (e.g. physical FC layer)\n");
+			}
+
+			else	// working normally - re-enable INTs and continue
+				writeb(0x1F, cpqfcHBA->fcChip.Registers.INTEN.address);
+
+		}		// (...ProcessIMQEntry() clears INT by writing IMQ consumer)
+		else		// indications of errors or problems...
+			// these usually indicate critical system hardware problems.
+		{
+			if (IntPending & 0x10)
+				printk(" cpqfcTS adapter external memory parity error detected\n");
+			if (IntPending & 0x8)
+				printk(" cpqfcTS adapter PCI master address crossed 45-bit boundary\n");
+			if (IntPending & 0x2)
+				printk(" cpqfcTS adapter DMA error detected\n");
+			if (IntPending & 0x1) {
+				u8 IntStat;
+				printk(" cpqfcTS adapter PCI error detected\n");
+				IntStat = readb(cpqfcHBA->fcChip.Registers.INTSTAT.address);
+				if (IntStat & 0x4)
+					printk("(INT)\n");
+				if (IntStat & 0x8)
+					printk("CRS: PCI master address crossed 46 bit bouandary\n");
+				if (IntStat & 0x10)
+					printk("MRE: external memory parity error.\n");
+			}
+		}
+	}
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	LEAVE("intr_handler");
 }
 
 
 
 
-int cpqfcTSDecodeGBICtype( PTACHYON fcChip, char cErrorString[])
-{
-        // Verify GBIC type (if any) and correct Tachyon Port State Machine
-        // (GBIC) module definition is:
-        // GPIO1, GPIO0, GPIO4 for MD2, MD1, MD0.  The input states appear
-        // to be inverted -- i.e., a setting of 111 is read when there is NO
-        // GBIC present.  The Module Def (MD) spec says 000 is "no GBIC"
-        // Hard code the bit states to detect Copper, 
-        // Long wave (single mode), Short wave (multi-mode), and absent GBIC
-
-  ULONG ulBuff;
-
-  sprintf( cErrorString, "\nGBIC detected: ");
-
-  ulBuff = fcChip->Registers.TYstatus.value & 0x13; 
-  switch( ulBuff )
-  {
-  case 0x13:  // GPIO4, GPIO1, GPIO0 = 111; no GBIC!
-    sprintf( &cErrorString[ strlen( cErrorString)],
-            "NONE! ");
-    return FALSE;          
-          
-       
-  case 0x11:   // Copper GBIC detected
-    sprintf( &cErrorString[ strlen( cErrorString)],
-            "Copper. ");
-    break;
-
-  case 0x10:   // Long-wave (single mode) GBIC detected
-    sprintf( &cErrorString[ strlen( cErrorString)],
-        "Long-wave. ");
-    break;
-  case 0x1:    // Short-wave (multi mode) GBIC detected
-    sprintf( &cErrorString[ strlen( cErrorString)],
-        "Short-wave. ");
-    break;
-  default:     // unknown GBIC - presumably it will work (?)
-    sprintf( &cErrorString[ strlen( cErrorString)],
-            "Unknown. ");
-          
-    break;
-  }  // end switch GBIC detection
-
-  return TRUE;
-}
+int cpqfcTSDecodeGBICtype(PTACHYON fcChip, char cErrorString[])
+{
+	// Verify GBIC type (if any) and correct Tachyon Port State Machine
+	// (GBIC) module definition is:
+	// GPIO1, GPIO0, GPIO4 for MD2, MD1, MD0.  The input states appear
+	// to be inverted -- i.e., a setting of 111 is read when there is NO
+	// GBIC present.  The Module Def (MD) spec says 000 is "no GBIC"
+	// Hard code the bit states to detect Copper, 
+	// Long wave (single mode), Short wave (multi-mode), and absent GBIC
 
+	u32 ulBuff;
 
+	sprintf(cErrorString, "\nGBIC detected: ");
 
+	ulBuff = fcChip->Registers.TYstatus.value & 0x13;
+	switch (ulBuff) {
+	case 0x13:		// GPIO4, GPIO1, GPIO0 = 111; no GBIC!
+		sprintf(&cErrorString[strlen(cErrorString)], "NONE! ");
+		return FALSE;
 
 
+	case 0x11:		// Copper GBIC detected
+		sprintf(&cErrorString[strlen(cErrorString)], "Copper. ");
+		break;
+
+	case 0x10:		// Long-wave (single mode) GBIC detected
+		sprintf(&cErrorString[strlen(cErrorString)], "Long-wave. ");
+		break;
+	case 0x1:		// Short-wave (multi mode) GBIC detected
+		sprintf(&cErrorString[strlen(cErrorString)], "Short-wave. ");
+		break;
+	default:		// unknown GBIC - presumably it will work (?)
+		sprintf(&cErrorString[strlen(cErrorString)], "Unknown. ");
 
-int cpqfcTSGetLPSM( PTACHYON fcChip, char cErrorString[])
-{
-  // Tachyon's Frame Manager LPSM in LinkDown state?
-  // (For non-loop port, check PSM instead.)
-  // return string with state and FALSE is Link Down
-
-  int LinkUp;
-
-  if( fcChip->Registers.FMstatus.value & 0x80 ) 
-    LinkUp = FALSE;
-  else
-    LinkUp = TRUE;
-
-  sprintf( &cErrorString[ strlen( cErrorString)],
-    " LPSM %Xh ", 
-     (fcChip->Registers.FMstatus.value >>4) & 0xf );
-
-
-  switch( fcChip->Registers.FMstatus.value & 0xF0)
-  {
-                    // bits set in LPSM
-    case 0x10:
-      sprintf( &cErrorString[ strlen( cErrorString)], "ARB");
-      break;
-    case 0x20:
-      sprintf( &cErrorString[ strlen( cErrorString)], "ARBwon");
-      break;
-    case 0x30:
-      sprintf( &cErrorString[ strlen( cErrorString)], "OPEN");
-      break;
-    case 0x40:
-      sprintf( &cErrorString[ strlen( cErrorString)], "OPENed");
-      break;
-    case 0x50:
-      sprintf( &cErrorString[ strlen( cErrorString)], "XmitCLS");
-      break;
-    case 0x60:
-      sprintf( &cErrorString[ strlen( cErrorString)], "RxCLS");
-      break;
-    case 0x70:
-      sprintf( &cErrorString[ strlen( cErrorString)], "Xfer");
-      break;
-    case 0x80:
-      sprintf( &cErrorString[ strlen( cErrorString)], "Init");
-      break;
-    case 0x90:
-      sprintf( &cErrorString[ strlen( cErrorString)], "O-IInitFin");
-      break;
-    case 0xa0:
-      sprintf( &cErrorString[ strlen( cErrorString)], "O-IProtocol");
-      break;
-    case 0xb0:
-      sprintf( &cErrorString[ strlen( cErrorString)], "O-ILipRcvd");
-      break;
-    case 0xc0:
-      sprintf( &cErrorString[ strlen( cErrorString)], "HostControl");
-      break;
-    case 0xd0:
-      sprintf( &cErrorString[ strlen( cErrorString)], "LoopFail");
-      break;
-    case 0xe0:
-      sprintf( &cErrorString[ strlen( cErrorString)], "Offline");
-      break;
-    case 0xf0:
-      sprintf( &cErrorString[ strlen( cErrorString)], "OldPort");
-      break;
-    case 0:
-    default:
-      sprintf( &cErrorString[ strlen( cErrorString)], "Monitor");
-      break;
-
-  }
+		break;
+	}			// end switch GBIC detection
 
-  return LinkUp;
+	return TRUE;
 }
 
 
 
 
-#include "linux/slab.h"
+
+
+int cpqfcTSGetLPSM(PTACHYON fcChip, char cErrorString[])
+{
+	// Tachyon's Frame Manager LPSM in LinkDown state?
+	// (For non-loop port, check PSM instead.)
+	// return string with state and FALSE is Link Down
+
+	int LinkUp;
+
+	if (fcChip->Registers.FMstatus.value & 0x80)
+		LinkUp = FALSE;
+	else
+		LinkUp = TRUE;
+
+	sprintf(&cErrorString[strlen(cErrorString)], " LPSM %Xh ", (fcChip->Registers.FMstatus.value >> 4) & 0xf);
+
+
+	switch (fcChip->Registers.FMstatus.value & 0xF0) {
+		// bits set in LPSM
+	case 0x10:
+		sprintf(&cErrorString[strlen(cErrorString)], "ARB");
+		break;
+	case 0x20:
+		sprintf(&cErrorString[strlen(cErrorString)], "ARBwon");
+		break;
+	case 0x30:
+		sprintf(&cErrorString[strlen(cErrorString)], "OPEN");
+		break;
+	case 0x40:
+		sprintf(&cErrorString[strlen(cErrorString)], "OPENed");
+		break;
+	case 0x50:
+		sprintf(&cErrorString[strlen(cErrorString)], "XmitCLS");
+		break;
+	case 0x60:
+		sprintf(&cErrorString[strlen(cErrorString)], "RxCLS");
+		break;
+	case 0x70:
+		sprintf(&cErrorString[strlen(cErrorString)], "Xfer");
+		break;
+	case 0x80:
+		sprintf(&cErrorString[strlen(cErrorString)], "Init");
+		break;
+	case 0x90:
+		sprintf(&cErrorString[strlen(cErrorString)], "O-IInitFin");
+		break;
+	case 0xa0:
+		sprintf(&cErrorString[strlen(cErrorString)], "O-IProtocol");
+		break;
+	case 0xb0:
+		sprintf(&cErrorString[strlen(cErrorString)], "O-ILipRcvd");
+		break;
+	case 0xc0:
+		sprintf(&cErrorString[strlen(cErrorString)], "HostControl");
+		break;
+	case 0xd0:
+		sprintf(&cErrorString[strlen(cErrorString)], "LoopFail");
+		break;
+	case 0xe0:
+		sprintf(&cErrorString[strlen(cErrorString)], "Offline");
+		break;
+	case 0xf0:
+		sprintf(&cErrorString[strlen(cErrorString)], "OldPort");
+		break;
+	case 0:
+	default:
+		sprintf(&cErrorString[strlen(cErrorString)], "Monitor");
+		break;
+
+	}
+
+	return LinkUp;
+}
 
 // Dynamic memory allocation alignment routines
 // HP's Tachyon Fibre Channel Controller chips require
@@ -1885,96 +1703,86 @@
 // we need about 8 allocations per HBA.  Figuring at most 10 HBAs per server
 // size the dynamic_mem array at 80.
 
-void* fcMemManager( struct pci_dev *pdev, ALIGNED_MEM *dynamic_mem, 
-		   ULONG n_alloc, ULONG ab, ULONG u32_AlignedAddress,
-			dma_addr_t *dma_handle)
-{
-  USHORT allocBoundary=1;   // compiler specific - worst case 1
-                                  // best case - replace malloc() call
-                                  // with function that allocates exactly
-                                  // at desired boundary
-
-  unsigned long ulAddress;
-  ULONG t_alloc, i;
-  void *alloc_address = 0;  // def. error code / address not found
-  LONG mask;                // must be 32-bits wide!
-
-  ENTER("fcMemManager");
-  if( u32_AlignedAddress )          // are we freeing existing memory?
-  {
+void *fcMemManager(struct pci_dev *pdev, ALIGNED_MEM * dynamic_mem, u32 n_alloc, u32 ab, u32 u32_AlignedAddress, dma_addr_t * dma_handle)
+{
+	u16 allocBoundary = 1;	// compiler specific - worst case 1
+	// best case - replace malloc() call
+	// with function that allocates exactly
+	// at desired boundary
+
+	unsigned long ulAddress;
+	u32 t_alloc, i;
+	void *alloc_address = 0;	// def. error code / address not found
+	s32 mask;		// must be 32-bits wide!
+
+	ENTER("fcMemManager");
+	if (u32_AlignedAddress)	// are we freeing existing memory?
+	{
 //    printk(" freeing AlignedAddress %Xh\n", u32_AlignedAddress);
-    for( i=0; i<DYNAMIC_ALLOCATIONS; i++) // look for the base address
-    {
+		for (i = 0; i < DYNAMIC_ALLOCATIONS; i++)	// look for the base address
+		{
 //    printk("dynamic_mem[%u].AlignedAddress %lX\n", i, dynamic_mem[i].AlignedAddress);
-      if( dynamic_mem[i].AlignedAddress == u32_AlignedAddress )
-      {
-        alloc_address = dynamic_mem[i].BaseAllocated; // 'success' status
-	pci_free_consistent(pdev,dynamic_mem[i].size, 
-				alloc_address, 
-				dynamic_mem[i].dma_handle);
-        dynamic_mem[i].BaseAllocated = 0;   // clear for next use
-        dynamic_mem[i].AlignedAddress = 0;
-        dynamic_mem[i].size = 0;
-        break;                        // quit for loop; done
-      }
-    }
-  }
-  else if( n_alloc )                   // want new memory?
-  {
-    dma_addr_t handle;
-    t_alloc = n_alloc + (ab - allocBoundary); // pad bytes for alignment
+			if (dynamic_mem[i].AlignedAddress == u32_AlignedAddress) {
+				alloc_address = dynamic_mem[i].BaseAllocated;	// 'success' status
+				pci_free_consistent(pdev, dynamic_mem[i].size, alloc_address, dynamic_mem[i].dma_handle);
+				dynamic_mem[i].BaseAllocated = 0;	// clear for next use
+				dynamic_mem[i].AlignedAddress = 0;
+				dynamic_mem[i].size = 0;
+				break;	// quit for loop; done
+			}
+		}
+	} else if (n_alloc)	// want new memory?
+	{
+		dma_addr_t handle;
+		t_alloc = n_alloc + (ab - allocBoundary);	// pad bytes for alignment
 //    printk("pci_alloc_consistent() for Tach alignment: %ld bytes\n", t_alloc);
 
 // (would like to) allow thread block to free pages 
-    alloc_address =                  // total bytes (NumberOfBytes)
-      pci_alloc_consistent(pdev, t_alloc, &handle); 
+		alloc_address =	// total bytes (NumberOfBytes)
+		    pci_alloc_consistent(pdev, t_alloc, &handle);
 
-                                  // now mask off least sig. bits of address
-    if( alloc_address )           // (only if non-NULL)
-    {
-                                  // find place to store ptr, so we
-                                  // can free it later...
-
-      mask = (LONG)(ab - 1);            // mask all low-order bits
-      mask = ~mask;                            // invert bits
-      for( i=0; i<DYNAMIC_ALLOCATIONS; i++) // look for free slot
-      {
-        if( dynamic_mem[i].BaseAllocated == 0) // take 1st available
-        {
-          dynamic_mem[i].BaseAllocated = alloc_address;// address from O/S
-          dynamic_mem[i].dma_handle = handle;
-	  if (dma_handle != NULL) 
-	  {
+		// now mask off least sig. bits of address
+		if (alloc_address)	// (only if non-NULL)
+		{
+			// find place to store ptr, so we
+			// can free it later...
+
+			mask = (s32) (ab - 1);	// mask all low-order bits
+			mask = ~mask;	// invert bits
+			for (i = 0; i < DYNAMIC_ALLOCATIONS; i++)	// look for free slot
+			{
+				if (dynamic_mem[i].BaseAllocated == 0)	// take 1st available
+				{
+					dynamic_mem[i].BaseAllocated = alloc_address;	// address from O/S
+					dynamic_mem[i].dma_handle = handle;
+					if (dma_handle != NULL) {
 //             printk("handle = %p, ab=%d, boundary = %d, mask=0x%08x\n", 
-//			handle, ab, allocBoundary, mask);
-	    *dma_handle = (dma_addr_t) 
-		((((ULONG)handle) + (ab - allocBoundary)) & mask);
-	  }
-          dynamic_mem[i].size = t_alloc;
-          break;
-        }
-      }
-      ulAddress = (unsigned long)alloc_address;
-      
-      ulAddress += (ab - allocBoundary);    // add the alignment bytes-
-                                            // then truncate address...
-      alloc_address = (void*)(ulAddress & mask);
-      
-      dynamic_mem[i].AlignedAddress = 
-	(ULONG)(ulAddress & mask); // 32bit Tach address
-      memset( alloc_address, 0, n_alloc );  // clear new memory
-    }
-    else  // O/S dynamic mem alloc failed!
-      alloc_address = 0;  // (for debugging breakpt)
+//                      handle, ab, allocBoundary, mask);
+						*dma_handle = (dma_addr_t)
+						    ((((u32) handle) + (ab - allocBoundary)) & mask);
+					}
+					dynamic_mem[i].size = t_alloc;
+					break;
+				}
+			}
+			ulAddress = (unsigned long) alloc_address;
+
+			ulAddress += (ab - allocBoundary);	// add the alignment bytes-
+			// then truncate address...
+			alloc_address = (void *) (ulAddress & mask);
+
+			dynamic_mem[i].AlignedAddress = (u32) (ulAddress & mask);	// 32bit Tach address
+			memset(alloc_address, 0, n_alloc);	// clear new memory
+		} else		// O/S dynamic mem alloc failed!
+			alloc_address = 0;	// (for debugging breakpt)
 
-  }
+	}
 
-  LEAVE("fcMemManager");
-  return alloc_address;  // good (or NULL) address
+	LEAVE("fcMemManager");
+	return alloc_address;	// good (or NULL) address
 }
 
 
 static Scsi_Host_Template driver_template = CPQFCTS;
 
 #include "scsi_module.c"
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/cpqfcTSioctl.h linux-2.4.21-pre6/drivers/scsi/cpqfcTSioctl.h
--- linux-2.4.20/drivers/scsi/cpqfcTSioctl.h	2001-10-25 20:53:50.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/cpqfcTSioctl.h	2003-03-26 23:48:58.000000000 +0000
@@ -4,71 +4,38 @@
 
 #define CCPQFCTS_IOC_MAGIC 'Z'
 
-typedef struct 
-{
-  __u8 bus;
-  __u8 dev_fn;
-  __u32 board_id;
+typedef struct {
+	__u8 bus;
+	__u8 dev_fn;
+	__u32 board_id;
 } cpqfc_pci_info_struct;
 
 typedef __u32 DriverVer_type;
-/*
-typedef union
-{
-  struct  // Peripheral Unit Device
-  { 
-    __u8 Bus:6;
-    __u8 Mode:2;  // b00
-    __u8 Dev;
-  } PeripDev;
-  struct  // Volume Set Address
-  { 
-    __u8 DevMSB:6;
-    __u8 Mode:2;  // b01
-    __u8 DevLSB;
-  } LogDev;
-  struct  // Logical Unit Device (SCSI-3, SCC-2 defined)
-  { 
-    __u8 Targ:6;
-    __u8 Mode:2;  // b10
-    __u8 Dev:5;
-    __u8 Bus:3;
-
-  } LogUnit;
-} SCSI3Addr_struct;
-
-
-typedef struct
-{
-  SCSI3Addr_struct FCP_Nexus;
-  __u8 cdb[16];
-} PassThru_Command_struct;
-*/
 
 /* this is nearly duplicated in idashare.h */
 typedef struct {
-  int	lc;    		/* Controller number */
-  int	node;		/* Node (box) number */
-  int	ld;		/* Logical Drive on this box, if required */
-  __u32 nexus;          /* SCSI Nexus */
-  void	*argp;		/* Argument pointer */
+	int lc;			/* Controller number */
+	int node;		/* Node (box) number */
+	int ld;			/* Logical Drive on this box, if required */
+	__u32 nexus;		/* SCSI Nexus */
+	void *argp;		/* Argument pointer */
 } VENDOR_IOCTL_REQ;
 
 
 typedef struct {
-  char	cdb[16];	/* SCSI CDB for the pass-through */
-  ushort bus;		/* Target bus on the box */
-  ushort pdrive;	/* Physical drive on the box */
-  int len;              /* Length of the data area of the CDB */
-  int sense_len;	/* Length of the sense data */
-  char sense_data[40];  /* Sense data */
-  void *bufp;		/* Data area for the CDB */
-  char rw_flag;		/* Read CDB or Write CDB */
+	char cdb[16];		/* SCSI CDB for the pass-through */
+	ushort bus;		/* Target bus on the box */
+	ushort pdrive;		/* Physical drive on the box */
+	int len;		/* Length of the data area of the CDB */
+	int sense_len;		/* Length of the sense data */
+	char sense_data[40];	/* Sense data */
+	void *bufp;		/* Data area for the CDB */
+	char rw_flag;		/* Read CDB or Write CDB */
 } cpqfc_passthru_t;
 
 /*
-** Defines for the IOCTLS.
-*/
+ * Defines for the IOCTLS.
+ */
 
 #define VENDOR_READ_OPCODE			0x26
 #define VENDOR_WRITE_OPCODE			0x27
@@ -78,17 +45,22 @@
 
 #define CPQFCTS_SCSI_PASSTHRU _IOWR( CCPQFCTS_IOC_MAGIC,11, VENDOR_IOCTL_REQ)
 
-/* We would rather have equivalent generic, low-level driver agnostic 
-ioctls that do what CPQFC_IOCTL_FC_TARGET_ADDRESS and 
-CPQFC_IOCTL_FC_TDR 0x5388 do, but currently, we do not have them, 
-consequently applications would have to know they are talking to cpqfc. */
-   
-/* Used to get Fibre Channel WWN and port_id from device */
-// #define CPQFC_IOCTL_FC_TARGET_ADDRESS 0x5387
+/*
+ *	We would rather have equivalent generic, low-level driver agnostic 
+ *	ioctls that do what CPQFC_IOCTL_FC_TARGET_ADDRESS and 
+ *	CPQFC_IOCTL_FC_TDR 0x5388 do, but currently, we do not have them, 
+ *	consequently applications would have to know they are talking to cpqfc.
+ */
+
+/*
+ *	Used to get Fibre Channel WWN and port_id from device
+ */
+
 #define CPQFC_IOCTL_FC_TARGET_ADDRESS \
 	_IOR( CCPQFCTS_IOC_MAGIC, 13, Scsi_FCTargAddress)
 
-/* Used to invoke Target Defice Reset for Fibre Channel */
-// #define CPQFC_IOCTL_FC_TDR 0x5388
+/*
+ *	Used to invoke Target Defice Reset for Fibre Channel
+ */
+ 
 #define CPQFC_IOCTL_FC_TDR _IO( CCPQFCTS_IOC_MAGIC, 15)
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/cpqfcTSstructs.h linux-2.4.21-pre6/drivers/scsi/cpqfcTSstructs.h
--- linux-2.4.20/drivers/scsi/cpqfcTSstructs.h	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/cpqfcTSstructs.h	2003-03-26 23:49:34.000000000 +0000
@@ -17,77 +17,83 @@
  * General Public License for more details.
  * Written by Don Zimmerman
 */
+
 #ifndef CPQFCTSSTRUCTS_H
 #define CPQFCTSSTRUCTS_H
 
-#include <linux/timer.h>  // timer declaration in our host data
-#include <linux/tqueue.h> // task queue sched
+#include <linux/timer.h>	// timer declaration in our host data
+#include <linux/tqueue.h>	// task queue sched
 #include <asm/atomic.h>
 #include "cpqfcTSioctl.h"
 
+/* FIXME - this is crap */
 #define DbgDelay(secs) { int wait_time; printk( " DbgDelay %ds ", secs); \
                          for( wait_time=jiffies + (secs*HZ); \
 		         time_before(jiffies, wait_time) ;) ; }
 
 #define CPQFCTS_DRIVER_VER(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
-// don't forget to also change MODULE_DESCRIPTION in cpqfcTSinit.c
+/* don't forget to also change MODULE_DESCRIPTION in cpqfcTSinit.c */
 #define VER_MAJOR 2
 #define VER_MINOR 1
-#define VER_SUBMINOR 1
+#define VER_SUBMINOR 2
 
-// Macros for kernel (esp. SMP) tracing using a PCI analyzer
-// (e.g. x86).
+/*
+ *	Macros for kernel (esp. SMP) tracing using a PCI analyzer
+ *	(e.g. x86).
+ */
+ 
 //#define PCI_KERNEL_TRACE
 #ifdef PCI_KERNEL_TRACE
-#define PCI_TRACE(x) inl( fcChip->Registers.IOBaseL +x);
-#define PCI_TRACEO(x,y) outl( x, (fcChip->Registers.IOBaseL +y));
+#define PCI_TRACE(x)		inl( fcChip->Registers.IOBaseL +x);
+#define PCI_TRACEO(x,y) 	outl( x, (fcChip->Registers.IOBaseL +y));
 #else
 
-#define PCI_TRACE(x) 
+#define PCI_TRACE(x)
 #define PCI_TRACEO(x,y)
 #endif
 
-			 
-//#define DEBUG_CMND 1   // debug output for Linux Scsi CDBs
-//#define DUMMYCMND_DBG 1
+
+//#define DEBUG_CMND		1   // debug output for Linux Scsi CDBs
+//#define DUMMYCMND_DBG		1
 
 //#define DEBUG_CPQFCTS 1
 //#undef DEBUG_CPQFCTS 
 #ifdef DEBUG_CPQFCTS
-#define ENTER(x)	printk("cpqfcts : entering %s()\n", x);
-#define LEAVE(x)	printk("cpqfcts : leaving %s()\n", x);
-#define DEBUG(x)	x
+#define ENTER(x)		printk("cpqfcts : entering %s()\n", x);
+#define LEAVE(x)		printk("cpqfcts : leaving %s()\n", x);
+#define DEBUG(x)		x
 #else
 #define ENTER(x)
 #define LEAVE(x)
 #define DEBUG(x)
 #endif				/* DEBUG_CPQFCTS */
 
-//#define DEBUG_CPQFCTS_PCI 1
+//#define DEBUG_CPQFCTS_PCI	1
 //#undef DEBUG_CPQFCTS_PCI
 #if DEBUG_CPQFCTS_PCI
-#define DEBUG_PCI(x)	x
+#define DEBUG_PCI(x)		x
 #else
 #define DEBUG_PCI(x)
 #endif				/* DEBUG_CPQFCTS_PCI */
 
-#define STACHLITE66_TS12  "Compaq FibreChannel HBA Tachyon TS HPFC-5166A/1.2"
-#define STACHLITE66_TS13  "Compaq FibreChannel HBA Tachyon TS HPFC-5166A/1.3"
-#define STACHLITE_UNKNOWN "Compaq FibreChannel HBA Tachyon Chip/Board Ver??"
-#define SAGILENT_XL2_21   "Agilent FC HBA, Tachyon XL2 HPFC-5200B/2.1"
+#define STACHLITE66_TS12	"Compaq FibreChannel HBA Tachyon TS HPFC-5166A/1.2"
+#define STACHLITE66_TS13	"Compaq FibreChannel HBA Tachyon TS HPFC-5166A/1.3"
+#define STACHLITE_UNKNOWN	"Compaq FibreChannel HBA Tachyon Chip/Board Ver??"
+#define SAGILENT_XL2_21		"Agilent FC HBA, Tachyon XL2 HPFC-5200B/2.1"
 
 // PDA is Peripheral Device Address, VSA is Volume Set Addressing
 // Linux SCSI parameters
-#define CPQFCTS_MAX_TARGET_ID 64
+#define CPQFCTS_MAX_TARGET_ID	64
 
 // Note, changing CPQFCTS_MAX_LUN to less than 32 (e.g, 8) will result in
 // strange behavior if a box with more than, e.g. 8, is on the loop.
-#define CPQFCTS_MAX_LUN 32    // The RA-4x00 supports 32 (Linux SCSI supports 8)
-#define CPQFCTS_MAX_CHANNEL 0 // One FC port on cpqfcTS HBA
+#define CPQFCTS_MAX_LUN		32	// The RA-4x00 supports 32 (Linux SCSI supports 8)
+#define CPQFCTS_MAX_CHANNEL 	0	// One FC port on cpqfcTS HBA
 
-#define CPQFCTS_CMD_PER_LUN 15 // power of 2 -1, must be >0 
-#define CPQFCTS_REQ_QUEUE_LEN (TACH_SEST_LEN/2) // must be < TACH_SEST_LEN
+#define CPQFCTS_CMD_PER_LUN	15	// power of 2 -1, must be >0
+#define CPQFCTS_REQ_QUEUE_LEN	(TACH_SEST_LEN/2)	// must be < TACH_SEST_LEN
 
+/* FIMXME - these are crpa too */
 #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
 #ifndef DECLARE_MUTEX_LOCKED
 #define DECLARE_MUTEX_LOCKED(sem) struct semaphore sem = MUTEX_LOCKED
@@ -95,205 +101,194 @@
 
 #define DEV_NAME "cpqfcTS"
 
-struct SupportedPCIcards
-{
-  __u16 vendor_id;
-  __u16 device_id;
+struct SupportedPCIcards {
+	__u16 vendor_id;
+	__u16 device_id;
 };
-			 
-// nn:nn denotes bit field
-                            // TachyonHeader struct def.
-                            // the fields shared with ODB
-                            // need to have same value
-
-
-
-
-#ifndef BYTE
-//typedef UCHAR BYTE;
-typedef __u8 BYTE;
-#endif
-#ifndef UCHAR
-typedef __u8 UCHAR;
-#endif
-#ifndef LONG
-typedef __s32 LONG;
-#endif
-#ifndef ULONG
-typedef __u32 ULONG;
-#endif
-#ifndef PVOID
-typedef void * PVOID;
-#endif
-#ifndef USHORT
-typedef __u16 USHORT;
-#endif
-#ifndef BOOLEAN
-typedef __u8 BOOLEAN;
-#endif
-
-
-// macro for FC-PH reject codes
-// payload format for LS_RJT (FC payloads are big endian):
-//     byte  0         1         2         3  (MSB)
-// DWORD 0   01        00        00        00
-// DWORD 1   resvd     code      expl.     vendor
 
+/*
+ *	nn:nn denotes bit field
+ *	TachyonHeader struct def.
+ *	the fields shared with ODB
+ *	need to have same value
+ */
+ 
+/*
+ * macro for FC-PH reject codes
+ * payload format for LS_RJT (FC payloads are big endian):
+ *     byte  0         1         2         3  (MSB)
+ * DWORD 0   01        00        00        00
+ * DWORD 1   resvd     code      expl.     vendor
+ */
 #define LS_RJT_REASON( code, expl) (( code<<8) | (expl <<16))
 
-
 #define TachLiteSTATUS 0x12
 
-// Fibre Channel EXCHANGE status codes for Tachyon chips/ driver software
-// 32-bit ERROR word defines
-#define INVALID_ARGS 0x1
-#define LNKDWN_OSLS  0x2
-#define LNKDWN_LASER 0x4
-#define OUTQUE_FULL  0x8
-#define DRIVERQ_FULL 0x10
-#define SEST_FULL    0x20
-#define BAD_ALPA     0x40
-#define OVERFLOW     0x80  // inbound CM
-#define COUNT_ERROR     0x100  // inbound CM
-#define LINKFAIL_RX     0x200  // inbound CM
-#define ABORTSEQ_NOTIFY 0x400  // outbound CM
-#define LINKFAIL_TX     0x800  // outbound CM
-#define HOSTPROG_ERR     0x1000  // outbound CM
-#define FRAME_TO         0x2000  // outbound CM
-#define INV_ENTRY        0x4000  // outbound CM
-#define SESTPROG_ERR     0x8000  // outbound CM
-#define OUTBOUND_TIMEOUT 0x10000L // timeout waiting for Tachyon outbound CM
-#define INITIATOR_ABORT  0x20000L // initiator exchange timeout or O/S ABORT
-#define MEMPOOL_FAIL     0x40000L // O/S memory pool allocation failed
-#define FC2_TIMEOUT      0x80000L // driver timeout for lost frames
-#define TARGET_ABORT     0x100000L // ABTS received from FC port
-#define EXCHANGE_QUEUED  0x200000L // e.g. Link State was LDn on fcStart
-#define PORTID_CHANGED   0x400000L // fc Port address changed
-#define DEVICE_REMOVED   0x800000L // fc Port address changed
-// Several error scenarios result in SEST Exchange frames 
-// unexpectedly arriving in the SFQ
-#define SFQ_FRAME        0x1000000L // SFQ frames from open Exchange
-
-// Maximum number of Host Bus Adapters (HBA) / controllers supported
-// only important for mem allocation dimensions - increase as necessary
-
+/*
+ *	Fibre Channel EXCHANGE status codes for Tachyon chips/ driver software
+ *	32-bit ERROR word defines
+ */
+#define INVALID_ARGS 		0x1
+#define LNKDWN_OSLS  		0x2
+#define LNKDWN_LASER 		0x4
+#define OUTQUE_FULL  		0x8
+#define DRIVERQ_FULL 		0x10
+#define SEST_FULL    		0x20
+#define BAD_ALPA     		0x40
+#define OVERFLOW     		0x80		// inbound CM
+#define COUNT_ERROR     	0x100		// inbound CM
+#define LINKFAIL_RX     	0x200		// inbound CM
+#define ABORTSEQ_NOTIFY 	0x400		// outbound CM
+#define LINKFAIL_TX     	0x800		// outbound CM
+#define HOSTPROG_ERR     	0x1000		// outbound CM
+#define FRAME_TO         	0x2000		// outbound CM
+#define INV_ENTRY        	0x4000		// outbound CM
+#define SESTPROG_ERR     	0x8000		// outbound CM
+#define OUTBOUND_TIMEOUT 	0x10000L	// timeout waiting for Tachyon outbound CM
+#define INITIATOR_ABORT  	0x20000L	// initiator exchange timeout or O/S ABORT
+#define MEMPOOL_FAIL     	0x40000L	// O/S memory pool allocation failed
+#define FC2_TIMEOUT      	0x80000L	// driver timeout for lost frames
+#define TARGET_ABORT     	0x100000L	// ABTS received from FC port
+#define EXCHANGE_QUEUED  	0x200000L	// e.g. Link State was LDn on fcStart
+#define PORTID_CHANGED   	0x400000L	// fc Port address changed
+#define DEVICE_REMOVED   	0x800000L	// fc Port address changed
+/*
+ *	Several error scenarios result in SEST Exchange frames 
+ *	unexpectedly arriving in the SFQ
+ */
+#define SFQ_FRAME		0x1000000L	// SFQ frames from open Exchange
+
+/*
+ *	Maximum number of Host Bus Adapters (HBA) / controllers supported
+ *	only important for mem allocation dimensions - increase as necessary
+ */
+ 
 #define MAX_ADAPTERS 8
-#define MAX_RX_PAYLOAD 1024  // hardware dependent max frame payload
-// Tach header struc defines
-#define SOFi3 0x7
-#define SOFf  0x8
-#define SOFn3 0xB
-#define EOFn  0x5
-#define EOFt  0x6
+#define MAX_RX_PAYLOAD 1024			// hardware dependent max frame payload
+
+/*
+ *	Tach header struct defines
+ */
+
+#define SOFi3			0x7
+#define SOFf			0x8
+#define SOFn3			0xB
+#define EOFn			0x5
+#define EOFt			0x6
 
 // FCP R_CTL defines
-#define FCP_CMND 0x6
-#define FCP_XFER_RDY 0x5
-#define FCP_RSP 0x7
-#define FCP_RESPONSE 0x777 // (arbitrary #)
-#define NEED_FCP_RSP 0x77  // (arbitrary #)
-#define FCP_DATA 0x1
-
-#define RESET_TACH 0x100 // Reset Tachyon/TachLite
-#define SCSI_IWE 0x2000  // initiator write entry (for SEST)
-#define SCSI_IRE 0x3000  // initiator read entry (for SEST)
-#define SCSI_TRE 0x400  // target read entry (for SEST)
-#define SCSI_TWE 0x500  // target write entry (for SEST)
-#define TOGGLE_LASER 0x800
-#define LIP 0x900
-#define CLEAR_FCPORTS 99 // (arbitrary #) free mem for Logged in ports
-#define FMINIT 0x707     // (arbitrary) for Frame Manager Init command
-
-// BLS == Basic Link Service
-// ELS == Extended Link Service
-#define BLS_NOP 4
-#define BLS_ABTS 0x10   // FC-PH Basic Link Service Abort Sequence
-#define BLS_ABTS_ACC 0x100  // FC-PH Basic Link Service Abort Sequence Accept
-#define BLS_ABTS_RJT 0x101  // FC-PH Basic Link Service Abort Sequence Reject
-#define ELS_PLOGI 0x03  // FC-PH Port Login (arbitrary assign)
-#define ELS_SCR   0x70  // (arb assign) State Change Registration (Fabric)
-#define FCS_NSR   0x72  // (arb assign) Name Service Request (Fabric)
-#define ELS_FLOGI 0x44  // (arb assign) Fabric Login
-#define ELS_FDISC 0x41  // (arb assign) Fabric Discovery (Login)
-#define ELS_PDISC 0x50  // FC-PH2 Port Discovery
-#define ELS_ABTX  0x06  // FC-PH Abort Exchange 
-#define ELS_LOGO 0x05   // FC-PH Port Logout
-#define ELS_PRLI 0x20   // FCP-SCSI Process Login
-#define ELS_PRLO 0x21   // FCP-SCSI Process Logout
-#define ELS_LOGO_ACC 0x07   // {FC-PH} Port Logout Accept
-#define ELS_PLOGI_ACC 0x08  // {FC-PH} Port Login Accept
-#define ELS_ACC 0x18        // {FC-PH} (generic) ACCept
-#define ELS_PRLI_ACC 0x22  // {FCP-SCSI} Process Login Accept
-#define ELS_RJT 0x1000000
-#define SCSI_REPORT_LUNS 0x0A0
-#define REPORT_LUNS 0xA0 // SCSI-3 command op-code
-#define FCP_TARGET_RESET 0x200
-
-#define ELS_LILP_FRAME 0x00000711 // 1st payload word of LILP frame
-
-#define SFQ_UNASSISTED_FCP  1  // ICM, DWord3, "Type" unassisted FCP
-#define SFQ_UNKNOWN         0x31 // (arbitrary) ICM, DWord3, "Type" unknown
-
-// these "LINK" bits refer to loop or non-loop
-#define LINKACTIVE 0x2    // fcLinkQ type - LINK UP Tachyon FM 'Lup' bit set
-#define LINKDOWN 0xf2     // fcLinkQ type - LINK DOWN Tachyon FM 'Ldn' bit set
+#define FCP_CMND		0x6
+#define FCP_XFER_RDY		0x5
+#define FCP_RSP			0x7
+#define FCP_RESPONSE		0x777		// (arbitrary #)
+#define NEED_FCP_RSP		0x77		// (arbitrary #)
+#define FCP_DATA		0x1
+
+#define RESET_TACH 		0x100		// Reset Tachyon/TachLite
+#define SCSI_IWE 		0x2000		// initiator write entry (for SEST)
+#define SCSI_IRE 		0x3000		// initiator read entry (for SEST)
+#define SCSI_TRE 		0x400		// target read entry (for SEST)
+#define SCSI_TWE 		0x500		// target write entry (for SEST)
+#define TOGGLE_LASER 		0x800
+#define LIP			0x900
+#define CLEAR_FCPORTS		99		// (arbitrary #) free mem for Logged in ports
+#define FMINIT			0x707		// (arbitrary) for Frame Manager Init command
+
+/*
+ *	BLS == Basic Link Service
+ *	ELS == Extended Link Service
+ */
+ 
+#define BLS_NOP 		4
+#define BLS_ABTS		0x10		// FC-PH Basic Link Service Abort Sequence
+#define BLS_ABTS_ACC		0x100		// FC-PH Basic Link Service Abort Sequence Accept
+#define BLS_ABTS_RJT		0x101		// FC-PH Basic Link Service Abort Sequence Reject
+#define ELS_PLOGI		0x03		// FC-PH Port Login (arbitrary assign)
+#define ELS_SCR			0x70		// (arb assign) State Change Registration (Fabric)
+#define FCS_NSR			0x72		// (arb assign) Name Service Request (Fabric)
+#define ELS_FLOGI		0x44		// (arb assign) Fabric Login
+#define ELS_FDISC		0x41		// (arb assign) Fabric Discovery (Login)
+#define ELS_PDISC		0x50		// FC-PH2 Port Discovery
+#define ELS_ABTX		0x06		// FC-PH Abort Exchange
+#define ELS_LOGO		0x05		// FC-PH Port Logout
+#define ELS_PRLI		0x20		// FCP-SCSI Process Login
+#define ELS_PRLO		0x21		// FCP-SCSI Process Logout
+#define ELS_LOGO_ACC		0x07		// {FC-PH} Port Logout Accept
+#define ELS_PLOGI_ACC		0x08		// {FC-PH} Port Login Accept
+#define ELS_ACC			0x18		// {FC-PH} (generic) ACCept
+#define ELS_PRLI_ACC		0x22		// {FCP-SCSI} Process Login Accept
+#define ELS_RJT			0x1000000
+#define SCSI_REPORT_LUNS	0x0A0
+#define REPORT_LUNS		0xA0		// SCSI-3 command op-code
+#define FCP_TARGET_RESET	0x200
+
+#define ELS_LILP_FRAME		0x00000711	// 1st payload word of LILP frame
+
+#define SFQ_UNASSISTED_FCP	1		// ICM, DWord3, "Type" unassisted FCP
+#define SFQ_UNKNOWN      	0x31		// (arbitrary) ICM, DWord3, "Type" unknown
+
+/*
+ * These "LINK" bits refer to loop or non-loop
+ */
+#define LINKACTIVE		0x2		// fcLinkQ type - LINK UP Tachyon FM 'Lup' bit set
+#define LINKDOWN		0xf2		// fcLinkQ type - LINK DOWN Tachyon FM 'Ldn' bit set
 
 //#define VOLUME_SET_ADDRESSING 1 // "channel" or "bus" 1
 
-typedef struct      // 32 bytes hdr ONLY (e.g. FCP_DATA buffer for SEST)
+typedef struct			// 32 bytes hdr ONLY (e.g. FCP_DATA buffer for SEST)
 {
-  ULONG reserved;   // dword 0 (don't use)
-  ULONG sof_eof;
-  ULONG d_id;       // dword 2 - 31:24 R_CTL, 23:0 D_ID
-  ULONG s_id;       // dword 3 - 31:24 CS_CTL, 23:0 S_ID
-  ULONG f_ctl;      // dword 4 - 31:24 Type,  23:0 F_CTL
-  ULONG seq_cnt;    // dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT
-  ULONG ox_rx_id;   // dword 6 - 31:16 OX_ID,  15:0 RX_ID
-  ULONG ro;         // dword 7 - relative offset
+	__u32 reserved;		// dword 0 (don't use)
+	__u32 sof_eof;
+	__u32 d_id;		// dword 2 - 31:24 R_CTL, 23:0 D_ID
+	__u32 s_id;		// dword 3 - 31:24 CS_CTL, 23:0 S_ID
+	__u32 f_ctl;		// dword 4 - 31:24 Type,  23:0 F_CTL
+	__u32 seq_cnt;		// dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT
+	__u32 ox_rx_id;		// dword 6 - 31:16 OX_ID,  15:0 RX_ID
+	__u32 ro;		// dword 7 - relative offset
 } TachFCHDR;
 
-                    // NOTE!! the following struct MUST be 64 bytes.
-typedef struct      // 32 bytes hdr + 32 bytes payload
+				// NOTE!! the following struct MUST be 64 bytes.
+typedef struct			// 32 bytes hdr + 32 bytes payload
 {
-  ULONG reserved;   // dword 0 (don't use - must clear to 0)
-  ULONG sof_eof;    // dword 1 - 31:24 SOF:EOF, UAM,CLS, LCr, TFV, TimeStamp
-  ULONG d_id;       // dword 2 - 31:24 R_CTL, 23:0 D_ID
-  ULONG s_id;       // dword 3 - 31:24 CS_CTL, 23:0 S_ID
-  ULONG f_ctl;      // dword 4 - 31:24 Type,  23:0 F_CTL
-  ULONG seq_cnt;    // dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT
-  ULONG ox_rx_id;   // dword 6 - 31:16 OX_ID,  15:0 RX_ID
-  ULONG ro;  // dword 7 - relative offset
+	__u32 reserved;		// dword 0 (don't use - must clear to 0)
+	__u32 sof_eof;		// dword 1 - 31:24 SOF:EOF, UAM,CLS, LCr, TFV, TimeStamp
+	__u32 d_id;		// dword 2 - 31:24 R_CTL, 23:0 D_ID
+	__u32 s_id;		// dword 3 - 31:24 CS_CTL, 23:0 S_ID
+	__u32 f_ctl;		// dword 4 - 31:24 Type,  23:0 F_CTL
+	__u32 seq_cnt;		// dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT
+	__u32 ox_rx_id;		// dword 6 - 31:16 OX_ID,  15:0 RX_ID
+	__u32 ro;		// dword 7 - relative offset
 //---------
-  __u32 pl[8];              // dwords 8-15 frame data payload
+	__u32 pl[8];		// dwords 8-15 frame data payload
 } TachFCHDR_CMND;
 
 
-typedef struct      // 32 bytes hdr + 120 bytes payload
+typedef struct			// 32 bytes hdr + 120 bytes payload
 {
-  ULONG reserved;   // dword 0 (don't use - must clear to 0)
-  ULONG sof_eof;    // dword 1 - 31:24 SOF:EOF, UAM,CLS, LCr, TFV, TimeStamp
-  ULONG d_id;       // dword 2 - 31:24 R_CTL, 23:0 D_ID
-  ULONG s_id;       // dword 3 - 31:24 CS_CTL, 23:0 S_ID
-  ULONG f_ctl;      // dword 4 - 31:24 Type,  23:0 F_CTL
-  ULONG seq_cnt;    // dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT
-  ULONG ox_rx_id;   // dword 6 - 31:16 OX_ID,  15:0 RX_ID
-  ULONG ro;  // dword 7 - relative offset
+	__u32 reserved;		// dword 0 (don't use - must clear to 0)
+	__u32 sof_eof;		// dword 1 - 31:24 SOF:EOF, UAM,CLS, LCr, TFV, TimeStamp
+	__u32 d_id;		// dword 2 - 31:24 R_CTL, 23:0 D_ID
+	__u32 s_id;		// dword 3 - 31:24 CS_CTL, 23:0 S_ID
+	__u32 f_ctl;		// dword 4 - 31:24 Type,  23:0 F_CTL
+	__u32 seq_cnt;		// dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT
+	__u32 ox_rx_id;		// dword 6 - 31:16 OX_ID,  15:0 RX_ID
+	__u32 ro;		// dword 7 - relative offset
 //---------
-  __u32 pl[30];              // largest necessary payload (for LOGIN cmnds)
+	__u32 pl[30];		// largest necessary payload (for LOGIN cmnds)
 } TachFCHDR_GCMND;
 
-typedef struct      // 32 bytes hdr + 64 bytes payload
+typedef struct			// 32 bytes hdr + 64 bytes payload
 {
-  ULONG reserved;   // dword 0 (don't use)
-  ULONG sof_eof;
-  ULONG d_id;       // dword 2 - 31:24 R_CTL, 23:0 D_ID
-  ULONG s_id;       // dword 3 - 31:24 CS_CTL, 23:0 S_ID
-  ULONG f_ctl;      // dword 4 - 31:24 Type,  23:0 F_CTL
-  ULONG seq_cnt;    // dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT
-  ULONG ox_rx_id;   // dword 6 - 31:16 OX_ID,  15:0 RX_ID
-  ULONG ro;  // dword 7 - relative offset
+	__u32 reserved;		// dword 0 (don't use)
+	__u32 sof_eof;
+	__u32 d_id;		// dword 2 - 31:24 R_CTL, 23:0 D_ID
+	__u32 s_id;		// dword 3 - 31:24 CS_CTL, 23:0 S_ID
+	__u32 f_ctl;		// dword 4 - 31:24 Type,  23:0 F_CTL
+	__u32 seq_cnt;		// dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT
+	__u32 ox_rx_id;		// dword 6 - 31:16 OX_ID,  15:0 RX_ID
+	__u32 ro;		// dword 7 - relative offset
 //---------
-  __u32 pl[18]; // payload for FCP-RSP (response buffer) RA-4x00 is 72bytes
+	__u32 pl[18];		// payload for FCP-RSP (response buffer) RA-4x00 is 72bytes
 } TachFCHDR_RSP;
 
 
@@ -302,11 +297,11 @@
 
 
 // Inbound Message Queue structures...
-typedef struct              // each entry 8 words (32 bytes)
+typedef struct			// each entry 8 words (32 bytes)
 {
-  ULONG type;               // IMQ completion message types
-  ULONG word[7];            // remainder of structure
-                            // interpreted by IMQ type
+	__u32 type;		// IMQ completion message types
+	__u32 word[7];		// remainder of structure
+				// interpreted by IMQ type
 } TachyonIMQE;
 
 
@@ -314,114 +309,114 @@
 // ERQ       - Exchange Request Queue (for outbound commands)
 // SFQ       - Single Frame Queue (for incoming frames)
 
-                            // Define Tachyon Outbound Command Que
-                            // (Since many Tachyon registers are Read
-                            // only, maintain copies for debugging)
-                            // most Tach ques need power-of-2 sizes,
-                            // where registers are loaded with po2 -1
-#define TACH_SEST_LEN 512   // TachLite SEST
+				// Define Tachyon Outbound Command Que
+				// (Since many Tachyon registers are Read
+				// only, maintain copies for debugging)
+				// most Tach ques need power-of-2 sizes,
+				// where registers are loaded with po2 -1
+#define TACH_SEST_LEN 512	// TachLite SEST
 
-#define ELS_EXCHANGES 64    // e.g. PLOGI, RSCN, ...
+#define ELS_EXCHANGES 64	// e.g. PLOGI, RSCN, ...
 // define the total number of outstanding (simultaneous) exchanges
-#define TACH_MAX_XID (TACH_SEST_LEN + ELS_EXCHANGES)  // ELS exchanges
+#define TACH_MAX_XID (TACH_SEST_LEN + ELS_EXCHANGES)	// ELS exchanges
 
-#define ERQ_LEN 128         // power of 2, max 4096
+#define ERQ_LEN 128		// power of 2, max 4096
 
 // Inbound Message Queue structures...
-#define IMQ_LEN 512              // minimum 4 entries [(power of 2) - 1]
-typedef struct                   // 8 words - 32 bytes
+#define IMQ_LEN 512		// minimum 4 entries [(power of 2) - 1]
+typedef struct			// 8 words - 32 bytes
 {
-  TachyonIMQE QEntry[IMQ_LEN];
-  ULONG producerIndex;   // IMQ Producer Index register
-                                 // @32 byte align
-  ULONG consumerIndex;   // Consumer Index register (in Tachyon)
-  ULONG length;          // Length register
-  ULONG base;
-} TachyonIMQ;                    // @ 32 * IMQ_LEN align
+	TachyonIMQE QEntry[IMQ_LEN];
+	__u32 producerIndex;	// IMQ Producer Index register
+	// @32 byte align
+	__u32 consumerIndex;	// Consumer Index register (in Tachyon)
+	__u32 length;		// Length register
+	__u32 base;
+} TachyonIMQ;			// @ 32 * IMQ_LEN align
 
 
 
-typedef struct           // inbound completion message
+typedef struct			// inbound completion message
 {
-  ULONG Type;
-  ULONG Index;
-  ULONG TransferLength;
+	__u32 Type;
+	__u32 Index;
+	__u32 TransferLength;
 } TachyonInbCM;
 
 
 
 // arbitrary numeric tags for TL structures
-#define TL_FCHS 1  // TachLite Fibre Channel Header Structure
-#define TL_IWE 2  // initiator write entry (for SEST)
-#define TL_TWE 3  // target write entry (for SEST)
-#define TL_IRE 4  // initiator read entry (for SEST)
-#define TL_TRE 5  // target read entry (for SEST)
-#define TL_IRB 6  // I/O request block
-
-                                // for INCOMING frames
-#define SFQ_LEN 32              // minimum 32 entries, max 4096
-
-typedef struct                  // Single Frame Que
-{
-  TachFCHDR_CMND QEntry[SFQ_LEN]; // must be 64 bytes!!
-  ULONG producerIndex;   // IMQ Producer Index register
-                                 // @32 byte align
-  ULONG consumerIndex;   // Consumer Index register (in Tachyon)
-  ULONG length;          // Length register
-  ULONG base;
+#define TL_FCHS 1		// TachLite Fibre Channel Header Structure
+#define TL_IWE 2		// initiator write entry (for SEST)
+#define TL_TWE 3		// target write entry (for SEST)
+#define TL_IRE 4		// initiator read entry (for SEST)
+#define TL_TRE 5		// target read entry (for SEST)
+#define TL_IRB 6		// I/O request block
+
+				// for INCOMING frames
+#define SFQ_LEN 32		// minimum 32 entries, max 4096
+
+typedef struct			// Single Frame Que
+{
+	TachFCHDR_CMND QEntry[SFQ_LEN];	// must be 64 bytes!!
+	__u32 producerIndex;	// IMQ Producer Index register
+	// @32 byte align
+	__u32 consumerIndex;	// Consumer Index register (in Tachyon)
+	__u32 length;		// Length register
+	__u32 base;
 } TachLiteSFQ;
 
 
-typedef struct                 // I/O Request Block flags
+typedef struct			// I/O Request Block flags
 {
-  UCHAR  BRD : 1;
-  UCHAR      : 1; // reserved
-  UCHAR  SFA : 1;
-  UCHAR  DNC : 1;
-  UCHAR  DIN : 1;
-  UCHAR  DCM : 1;
-  UCHAR  CTS : 1;
-  UCHAR  SBV : 1;  // IRB entry valid - IRB'B' only
+	__u8 BRD:1;
+	 __u8:1;		// reserved
+	__u8 SFA:1;
+	__u8 DNC:1;
+	__u8 DIN:1;
+	__u8 DCM:1;
+	__u8 CTS:1;
+	__u8 SBV:1;		// IRB entry valid - IRB'B' only
 } IRBflags;
 
-typedef struct                  // I/O Request Block
-{                          // Request 'A'
-  ULONG Req_A_SFS_Len;     // total frame len (hdr + payload), min 32
-  ULONG Req_A_SFS_Addr;    // 32-bit pointer to FCHS struct (to be sent)
-  ULONG Req_A_SFS_D_ID;    // 24-bit FC destination (i.e. 8 bit al_pa)
-  ULONG Req_A_Trans_ID;    // X_ID (OX_ID or RX_ID) and/or Index in SEST
-                           // Request 'B'
-  ULONG Req_B_SFS_Len;     // total frame len (hdr + payload), min 32
-  ULONG Req_B_SFS_Addr;    // 32-bit pointer to FCHS struct (to be sent)
-  ULONG Req_B_SFS_D_ID;    // 24-bit FC destination (i.e. 8 bit al_pa)
-  ULONG Req_B_Trans_ID;    // X_ID (OX_ID or RX_ID) and/or Index in SEST
+typedef struct			// I/O Request Block
+{				// Request 'A'
+	__u32 Req_A_SFS_Len;	// total frame len (hdr + payload), min 32
+	__u32 Req_A_SFS_Addr;	// 32-bit pointer to FCHS struct (to be sent)
+	__u32 Req_A_SFS_D_ID;	// 24-bit FC destination (i.e. 8 bit al_pa)
+	__u32 Req_A_Trans_ID;	// X_ID (OX_ID or RX_ID) and/or Index in SEST
+	// Request 'B'
+	__u32 Req_B_SFS_Len;	// total frame len (hdr + payload), min 32
+	__u32 Req_B_SFS_Addr;	// 32-bit pointer to FCHS struct (to be sent)
+	__u32 Req_B_SFS_D_ID;	// 24-bit FC destination (i.e. 8 bit al_pa)
+	__u32 Req_B_Trans_ID;	// X_ID (OX_ID or RX_ID) and/or Index in SEST
 } TachLiteIRB;
 
 
-typedef struct           // TachLite placeholder for IRBs
-{                        // aligned @sizeof(ERQ) for TachLite
-                         // MAX commands is sum of SEST len and ERQ
-                         // we know that each SEST entry requires an
-                         // IRB (ERQ) entry; in addition, we provide
-                         // ERQ_LEN
-  TachLiteIRB QEntry[ERQ_LEN]; // Base register; entries 32 bytes ea.
-  ULONG consumerIndex;   // Consumer Index register
-  ULONG producerIndex;   // ERQ Producer Index register
-  ULONG length;          // Length register
-  ULONG base;            // copy of base ptr for debug
-                         // struct is sized for largest expected cmnd (LOGIN)
+typedef struct			// TachLite placeholder for IRBs
+{				// aligned @sizeof(ERQ) for TachLite
+	// MAX commands is sum of SEST len and ERQ
+	// we know that each SEST entry requires an
+	// IRB (ERQ) entry; in addition, we provide
+	// ERQ_LEN
+	TachLiteIRB QEntry[ERQ_LEN];	// Base register; entries 32 bytes ea.
+	__u32 consumerIndex;	// Consumer Index register
+	__u32 producerIndex;	// ERQ Producer Index register
+	__u32 length;		// Length register
+	__u32 base;		// copy of base ptr for debug
+	// struct is sized for largest expected cmnd (LOGIN)
 } TachLiteERQ;
 
 // for now, just 32 bit DMA, eventually 40something, with code changes
 #define CPQFCTS_DMA_MASK ((unsigned long) (0x00000000FFFFFFFF))
 
-#define TL_MAX_SG_ELEM_LEN 0x7ffff  // Max buffer length a single S/G entry
-				// may represent (a hardware limitation).  The
-				// only reason to ever change this is if you
-				// want to exercise very-hard-to-reach code in
-				// cpqfcTSworker.c:build_SEST_sglist().
+#define TL_MAX_SG_ELEM_LEN 0x7ffff	// Max buffer length a single S/G entry
+					// may represent (a hardware limitation).  The
+					// only reason to ever change this is if you
+					// want to exercise very-hard-to-reach code in
+					// cpqfcTSworker.c:build_SEST_sglist().
 
-#define TL_DANGER_SGPAGES 7  // arbitrary high water mark for # of S/G pages
+#define TL_DANGER_SGPAGES 7	// arbitrary high water mark for # of S/G pages
 				// we must exceed to elicit a warning indicative
 				// of EXTREMELY large data transfers or 
 				// EXTREME memory fragmentation.
@@ -429,236 +424,230 @@
 				// Never seen this is real life, only in 
 				// testing with tricked up driver.)
 
-#define TL_EXT_SG_PAGE_COUNT 256  // Number of Extended Scatter/Gather a/l PAIRS
-                                  // Tachyon register (IOBaseU 0x68)
-                                  // power-of-2 value ONLY!  4 min, 256 max
+#define TL_EXT_SG_PAGE_COUNT 256	// Number of Extended Scatter/Gather a/l PAIRS
+					// Tachyon register (IOBaseU 0x68)
+					// power-of-2 value ONLY!  4 min, 256 max
 
-                          // byte len is #Pairs * 2 ULONG/Pair * 4 bytes/ULONG
+			  // byte len is #Pairs * 2 __u32/Pair * 4 bytes/__u32
 #define TL_EXT_SG_PAGE_BYTELEN (TL_EXT_SG_PAGE_COUNT *2 *4)
 
 
 
 // SEST entry types: IWE, IRE, TWE, TRE
-typedef struct 
-{
-  ULONG Hdr_Len;
-  ULONG Hdr_Addr;
-  ULONG RSP_Len;
-  ULONG RSP_Addr;
-  ULONG Buff_Off;
+typedef struct {
+	__u32 Hdr_Len;
+	__u32 Hdr_Addr;
+	__u32 RSP_Len;
+	__u32 RSP_Addr;
+	__u32 Buff_Off;
 #define USES_EXTENDED_SGLIST(this_sest, x_ID) \
 	(!((this_sest)->u[ x_ID ].IWE.Buff_Off & 0x80000000))
-  ULONG Link;
-  ULONG RX_ID;
-  ULONG Data_Len;
-  ULONG Exp_RO;
-  ULONG Exp_Byte_Cnt;
-   // --- extended/local Gather Len/Address pairs
-  ULONG GLen1;
-  ULONG GAddr1;
-  ULONG GLen2;
-  ULONG GAddr2;
-  ULONG GLen3;
-  ULONG GAddr3;
+	__u32 Link;
+	__u32 RX_ID;
+	__u32 Data_Len;
+	__u32 Exp_RO;
+	__u32 Exp_Byte_Cnt;
+	// --- extended/local Gather Len/Address pairs
+	__u32 GLen1;
+	__u32 GAddr1;
+	__u32 GLen2;
+	__u32 GAddr2;
+	__u32 GLen3;
+	__u32 GAddr3;
 } TachLiteIWE;
 
 
-typedef struct 
-{
-  ULONG Seq_Accum;
-  ULONG reserved;       // must clear to 0
-  ULONG RSP_Len;
-  ULONG RSP_Addr;
-  ULONG Buff_Off;
-  ULONG Buff_Index;           // ULONG 5
-  ULONG Exp_RO;
-  ULONG Byte_Count;
-  ULONG reserved_;      // ULONG 8
-  ULONG Exp_Byte_Cnt;
-   // --- extended/local Scatter Len/Address pairs
-  ULONG SLen1;
-  ULONG SAddr1;
-  ULONG SLen2;
-  ULONG SAddr2;
-  ULONG SLen3;
-  ULONG SAddr3;
+typedef struct {
+	__u32 Seq_Accum;
+	__u32 reserved;		// must clear to 0
+	__u32 RSP_Len;
+	__u32 RSP_Addr;
+	__u32 Buff_Off;
+	__u32 Buff_Index;	// __u32 5
+	__u32 Exp_RO;
+	__u32 Byte_Count;
+	__u32 reserved_;	// __u32 8
+	__u32 Exp_Byte_Cnt;
+	// --- extended/local Scatter Len/Address pairs
+	__u32 SLen1;
+	__u32 SAddr1;
+	__u32 SLen2;
+	__u32 SAddr2;
+	__u32 SLen3;
+	__u32 SAddr3;
 } TachLiteIRE;
 
 
-typedef struct          // Target Write Entry
+typedef struct			// Target Write Entry
 {
-  ULONG Seq_Accum;      // dword 0
-  ULONG reserved;       // dword 1  must clear to 0
-  ULONG Remote_Node_ID;
-  ULONG reserved1;      // dword 3  must clear to 0
-  ULONG Buff_Off;
-  ULONG Buff_Index;     // ULONG 5
-  ULONG Exp_RO;
-  ULONG Byte_Count;
-  ULONG reserved_;      // ULONG 8
-  ULONG Exp_Byte_Cnt;
-   // --- extended/local Scatter Len/Address pairs
-  ULONG SLen1;
-  ULONG SAddr1;
-  ULONG SLen2;
-  ULONG SAddr2;
-  ULONG SLen3;
-  ULONG SAddr3;
+	__u32 Seq_Accum;	// dword 0
+	__u32 reserved;		// dword 1  must clear to 0
+	__u32 Remote_Node_ID;
+	__u32 reserved1;	// dword 3  must clear to 0
+	__u32 Buff_Off;
+	__u32 Buff_Index;	// __u32 5
+	__u32 Exp_RO;
+	__u32 Byte_Count;
+	__u32 reserved_;	// __u32 8
+	__u32 Exp_Byte_Cnt;
+	// --- extended/local Scatter Len/Address pairs
+	__u32 SLen1;
+	__u32 SAddr1;
+	__u32 SLen2;
+	__u32 SAddr2;
+	__u32 SLen3;
+	__u32 SAddr3;
 } TachLiteTWE;
 
-typedef struct      
-{
-  ULONG Hdr_Len;
-  ULONG Hdr_Addr;
-  ULONG RSP_Len;        // DWord 2
-  ULONG RSP_Addr;
-  ULONG Buff_Off;
-  ULONG Buff_Index;     // DWord 5
-  ULONG reserved;
-  ULONG Data_Len;
-  ULONG reserved_;
-  ULONG reserved__;
-   // --- extended/local Gather Len/Address pairs
-  ULONG GLen1;          // DWord A
-  ULONG GAddr1;
-  ULONG GLen2;
-  ULONG GAddr2;
-  ULONG GLen3;
-  ULONG GAddr3;
+typedef struct {
+	__u32 Hdr_Len;
+	__u32 Hdr_Addr;
+	__u32 RSP_Len;		// DWord 2
+	__u32 RSP_Addr;
+	__u32 Buff_Off;
+	__u32 Buff_Index;	// DWord 5
+	__u32 reserved;
+	__u32 Data_Len;
+	__u32 reserved_;
+	__u32 reserved__;
+	// --- extended/local Gather Len/Address pairs
+	__u32 GLen1;		// DWord A
+	__u32 GAddr1;
+	__u32 GLen2;
+	__u32 GAddr2;
+	__u32 GLen3;
+	__u32 GAddr3;
 } TachLiteTRE;
 
 typedef struct ext_sg_page_ptr_t *PSGPAGES;
-typedef struct ext_sg_page_ptr_t 
-{
-  unsigned char page[TL_EXT_SG_PAGE_BYTELEN * 2]; // 2x for alignment
-  dma_addr_t busaddr; 	// need the bus addresses and
-  unsigned int maplen;  // lengths for later pci unmapping.
-  PSGPAGES next;
-} SGPAGES; // linked list of S/G pairs, by Exchange
-
-typedef struct                  // SCSI Exchange State Table
-{
-  union                         // Entry can be IWE, IRE, TWE, TRE
-  {                             // 64 bytes per entry
-    TachLiteIWE IWE;
-    TachLiteIRE IRE;
-    TachLiteTWE TWE;
-    TachLiteTRE TRE;
-  } u[TACH_SEST_LEN];
-
-  TachFCHDR DataHDR[TACH_SEST_LEN]; // for SEST FCP_DATA frame hdr (no pl)
-  TachFCHDR_RSP RspHDR[TACH_SEST_LEN]; // space for SEST FCP_RSP frame
-  PSGPAGES sgPages[TACH_SEST_LEN]; // head of linked list of Pool-allocations
-  ULONG length;          // Length register
-  ULONG base;            // copy of base ptr for debug
+typedef struct ext_sg_page_ptr_t {
+	unsigned char page[TL_EXT_SG_PAGE_BYTELEN * 2];	// 2x for alignment
+	dma_addr_t busaddr;	// need the bus addresses and
+	unsigned int maplen;	// lengths for later pci unmapping.
+	PSGPAGES next;
+} SGPAGES;			// linked list of S/G pairs, by Exchange
+
+typedef struct			// SCSI Exchange State Table
+{
+	union			// Entry can be IWE, IRE, TWE, TRE
+	{			// 64 bytes per entry
+		TachLiteIWE IWE;
+		TachLiteIRE IRE;
+		TachLiteTWE TWE;
+		TachLiteTRE TRE;
+	} u[TACH_SEST_LEN];
+
+	TachFCHDR DataHDR[TACH_SEST_LEN];	// for SEST FCP_DATA frame hdr (no pl)
+	TachFCHDR_RSP RspHDR[TACH_SEST_LEN];	// space for SEST FCP_RSP frame
+	PSGPAGES sgPages[TACH_SEST_LEN];	// head of linked list of Pool-allocations
+	__u32 length;		// Length register
+	__u32 base;		// copy of base ptr for debug
 } TachSEST;
 
 
 
-typedef struct                  // each register has it's own address
-                                // and value (used for write-only regs)
+typedef struct			// each register has it's own address
+				// and value (used for write-only regs)
 {
-  void* address;
-  volatile ULONG value;
+	void *address;
+	volatile __u32 value;
 } FCREGISTER;
 
-typedef struct         // Host copy - TachLite Registers
+typedef struct			// Host copy - TachLite Registers
 {
-  ULONG IOBaseL, IOBaseU;  // I/O port lower and upper TL register addresses
-  ULONG MemBase;           // memory mapped register addresses
-  void* ReMapMemBase;      // O/S VM reference for MemBase
-  ULONG wwn_hi;            // WWN is set once at startup
-  ULONG wwn_lo;
-  ULONG my_al_pa;          // al_pa received after LIP()
-  ULONG ROMCTR;            // flags for on-board RAM/ROM
-  ULONG RAMBase;           // on-board RAM (i.e. some Tachlites)
-  ULONG SROMBase;          // on-board EEPROM (some Tachlites)
-  ULONG PCIMCTR;           // PCI Master Control Reg (has bus width)
-
-  FCREGISTER INTEN;        // copy of interrupt enable mask
-  FCREGISTER INTPEND;      // interrupt pending
-  FCREGISTER INTSTAT;      // interrupt status
-  FCREGISTER SFQconsumerIndex; 
-  FCREGISTER ERQproducerIndex; 
-  FCREGISTER TYconfig;   // TachYon (chip level)
-  FCREGISTER TYcontrol;
-  FCREGISTER TYstatus;
-  FCREGISTER FMconfig;   // Frame Manager (FC loop level)
-  FCREGISTER FMcontrol;
-  FCREGISTER FMstatus;
-  FCREGISTER FMLinkStatus1;
-  FCREGISTER FMLinkStatus2;
-  FCREGISTER FMBB_CreditZero;
-  FCREGISTER status;
-  FCREGISTER ed_tov;     // error detect time-out value
-  FCREGISTER rcv_al_pa;  // received arb. loop physical address
-  FCREGISTER primitive;  // e.g. LIP(), OPN(), ...
+	__u32 IOBaseL, IOBaseU;	// I/O port lower and upper TL register addresses
+	__u32 MemBase;		// memory mapped register addresses
+	void *ReMapMemBase;	// O/S VM reference for MemBase
+	__u32 wwn_hi;		// WWN is set once at startup
+	__u32 wwn_lo;
+	__u32 my_al_pa;		// al_pa received after LIP()
+	__u32 ROMCTR;		// flags for on-board RAM/ROM
+	__u32 RAMBase;		// on-board RAM (i.e. some Tachlites)
+	__u32 SROMBase;		// on-board EEPROM (some Tachlites)
+	__u32 PCIMCTR;		// PCI Master Control Reg (has bus width)
+
+	FCREGISTER INTEN;	// copy of interrupt enable mask
+	FCREGISTER INTPEND;	// interrupt pending
+	FCREGISTER INTSTAT;	// interrupt status
+	FCREGISTER SFQconsumerIndex;
+	FCREGISTER ERQproducerIndex;
+	FCREGISTER TYconfig;	// TachYon (chip level)
+	FCREGISTER TYcontrol;
+	FCREGISTER TYstatus;
+	FCREGISTER FMconfig;	// Frame Manager (FC loop level)
+	FCREGISTER FMcontrol;
+	FCREGISTER FMstatus;
+	FCREGISTER FMLinkStatus1;
+	FCREGISTER FMLinkStatus2;
+	FCREGISTER FMBB_CreditZero;
+	FCREGISTER status;
+	FCREGISTER ed_tov;	// error detect time-out value
+	FCREGISTER rcv_al_pa;	// received arb. loop physical address
+	FCREGISTER primitive;	// e.g. LIP(), OPN(), ...
 } TL_REGISTERS;
 
 
 
-typedef struct 
-{
-  ULONG ok;
-  ULONG invalidArgs;
-  ULONG linkDown;
-  ULONG linkUp;
-  ULONG outQueFull;
-  ULONG SESTFull;
-  ULONG hpe;    // host programming err (from Tach)
-  ULONG FC4aborted; // aborts from Application or upper driver layer
-  ULONG FC2aborted; // aborts from our driver's timeouts
-  ULONG timeouts;   // our driver timeout (on individual exchanges)
-  ULONG logouts;    // explicit - sent LOGO; implicit - device removed
-  ULONG retries;
-  ULONG linkFailTX;
-  ULONG linkFailRX;
-  ULONG CntErrors;  // byte count expected != count received (typ. SEST)
-  ULONG e_stores;   // elastic store errs
-  ULONG resets;     // hard or soft controller resets
-  ULONG FMinits;    // TACH Frame Manager Init (e.g. LIPs)
-  ULONG lnkQueFull;  // too many LOGIN, loop commands
-  ULONG ScsiQueFull; // too many FCP-SCSI inbound frames
-  ULONG LossofSignal;   // FM link status 1 regs
-  ULONG BadRXChar;   // FM link status 1 regs
-  ULONG LossofSync;   // FM link status 1 regs
-  ULONG Rx_EOFa;   // FM link status 2 regs (received EOFa)
-  ULONG Dis_Frm;   // FM link status 2 regs (discarded frames)
-  ULONG Bad_CRC;   // FM link status 2 regs
-  ULONG BB0_Timer; //  FM BB_Credit Zero Timer Reg
-  ULONG loopBreaks; // infinite loop exits
-  ULONG lastBB0timer;  // static accum. buffer needed by Tachlite
+typedef struct {
+	__u32 ok;
+	__u32 invalidArgs;
+	__u32 linkDown;
+	__u32 linkUp;
+	__u32 outQueFull;
+	__u32 SESTFull;
+	__u32 hpe;		// host programming err (from Tach)
+	__u32 FC4aborted;	// aborts from Application or upper driver layer
+	__u32 FC2aborted;	// aborts from our driver's timeouts
+	__u32 timeouts;		// our driver timeout (on individual exchanges)
+	__u32 logouts;		// explicit - sent LOGO; implicit - device removed
+	__u32 retries;
+	__u32 linkFailTX;
+	__u32 linkFailRX;
+	__u32 CntErrors;	// byte count expected != count received (typ. SEST)
+	__u32 e_stores;		// elastic store errs
+	__u32 resets;		// hard or soft controller resets
+	__u32 FMinits;		// TACH Frame Manager Init (e.g. LIPs)
+	__u32 lnkQueFull;	// too many LOGIN, loop commands
+	__u32 ScsiQueFull;	// too many FCP-SCSI inbound frames
+	__u32 LossofSignal;	// FM link status 1 regs
+	__u32 BadRXChar;	// FM link status 1 regs
+	__u32 LossofSync;	// FM link status 1 regs
+	__u32 Rx_EOFa;		// FM link status 2 regs (received EOFa)
+	__u32 Dis_Frm;		// FM link status 2 regs (discarded frames)
+	__u32 Bad_CRC;		// FM link status 2 regs
+	__u32 BB0_Timer;	//  FM BB_Credit Zero Timer Reg
+	__u32 loopBreaks;	// infinite loop exits
+	__u32 lastBB0timer;	// static accum. buffer needed by Tachlite
 } FCSTATS;
 
 
-typedef struct               // Config Options
-{                            // LS Bit first
-  USHORT        : 1;           // bit0:
-  USHORT  flogi : 1;           // bit1: We sent FLOGI - wait for Fabric logins
-  USHORT  fabric: 1;           // bit2: Tachyon detected Fabric (FM stat LG)
-  USHORT  LILPin: 1;           // bit3: We can use an FC-AL LILP frame
-  USHORT  target: 1;           // bit4: this Port has SCSI target capability
-  USHORT  initiator:    1;     // bit5: this Port has SCSI initiator capability
-  USHORT  extLoopback:  1;     // bit6: loopback at GBIC
-  USHORT  intLoopback:  1;     // bit7: loopback in HP silicon
-  USHORT        : 1;           // bit8:
-  USHORT        : 1;           // bit9:
-  USHORT        : 1;           // bit10:
-  USHORT        : 1;           // bit11:
-  USHORT        : 1;           // bit12:
-  USHORT        : 1;           // bit13:
-  USHORT        : 1;           // bit14:
-  USHORT        : 1;           // bit15:
+typedef struct			// Config Options
+{				// LS Bit first
+	__u16:1;		// bit0:
+	__u16 flogi:1;		// bit1: We sent FLOGI - wait for Fabric logins
+	__u16 fabric:1;	// bit2: Tachyon detected Fabric (FM stat LG)
+	__u16 LILPin:1;	// bit3: We can use an FC-AL LILP frame
+	__u16 target:1;	// bit4: this Port has SCSI target capability
+	__u16 initiator:1;	// bit5: this Port has SCSI initiator capability
+	__u16 extLoopback:1;	// bit6: loopback at GBIC
+	__u16 intLoopback:1;	// bit7: loopback in HP silicon
+	 __u16:1;		// bit8:
+	 __u16:1;		// bit9:
+	 __u16:1;		// bit10:
+	 __u16:1;		// bit11:
+	 __u16:1;		// bit12:
+	 __u16:1;		// bit13:
+	 __u16:1;		// bit14:
+	 __u16:1;		// bit15:
 } FC_OPTIONS;
 
 
 
-typedef struct dyn_mem_pair
-{
-  void *BaseAllocated;  // address as allocated from O/S;
-  unsigned long AlignedAddress; // aligned address (used by Tachyon DMA)
-  dma_addr_t dma_handle;
-  size_t size;
+typedef struct dyn_mem_pair {
+	void *BaseAllocated;	// address as allocated from O/S;
+	unsigned long AlignedAddress;	// aligned address (used by Tachyon DMA)
+	dma_addr_t dma_handle;
+	size_t size;
 } ALIGNED_MEM;
 
 
@@ -675,66 +664,63 @@
 #define IMPLICIT_LOGOUT 1
 #define EXPLICIT_LOGOUT 2
 
-typedef struct 
-{
-  UCHAR channel; // SCSI "bus"
-  UCHAR target;
-  UCHAR InqDeviceType;  // byte 0 from SCSI Inquiry response
-  UCHAR VolumeSetAddressing;  // FCP-SCSI LUN coding (40h for VSA)
-  UCHAR LunMasking;     // True if selective presentation supported
-  UCHAR lun[CPQFCTS_MAX_LUN];
+typedef struct {
+	__u8 channel;		// SCSI "bus"
+	__u8 target;
+	__u8 InqDeviceType;	// byte 0 from SCSI Inquiry response
+	__u8 VolumeSetAddressing;	// FCP-SCSI LUN coding (40h for VSA)
+	__u8 LunMasking;	// True if selective presentation supported
+	__u8 lun[CPQFCTS_MAX_LUN];
 } SCSI_NEXUS;
 
 
-typedef struct        
-{
-  union 
-  {
-    UCHAR ucWWN[8];  // a FC 64-bit World Wide Name/ PortID of target
-                     // addressing of single target on single loop...
-    u64 liWWN;
-  } u;
-
-  ULONG port_id;     // a FC 24-bit address of port (lower 8 bits = al_pa)
-
-  Scsi_Cmnd ScsiCmnd;   // command buffer for Report Luns
-#define REPORT_LUNS_PL 256  
-  UCHAR ReportLunsPayload[REPORT_LUNS_PL];
-  
-  SCSI_NEXUS ScsiNexus; // LUNs per FC device
-
-  ULONG LOGO_counter; // might try several times before logging out for good
-  ULONG LOGO_timer;   // after LIP, ports expecting PDISC must time-out and
-                      // LOGOut if successful PDISC not completed in 2 secs
-
-  ULONG concurrent_seq;  // must be 1 or greater
-  ULONG rx_data_size;    // e.g. 128, 256, 1024, 2048 per FC-PH spec
-  ULONG BB_credit;
-  ULONG EE_credit;
-
-  ULONG fcp_info;        // from PRLI (i.e. INITIATOR/ TARGET flags)
-                         // flags for login process
-  BOOLEAN Originator;    // Login sequence Originated (if false, we
-                         // responded to another port's login sequence)
-  BOOLEAN plogi;         // PLOGI frame ACCepted (originated or responded)
-  BOOLEAN pdisc;         // PDISC frame was ORIGINATED (self-login logic)
-  BOOLEAN prli;          // PRLI frame ACCepted (originated or responded)
-  BOOLEAN flogi;         // FLOGI frame ACCepted (originated or responded)
-  BOOLEAN logo;          // port permanently logged out (invalid login param)
-  BOOLEAN flogiReq;      // Fabric login required (set in LIP process)
-  UCHAR highest_ver;
-  UCHAR lowest_ver;
-
-  
-  // when the "target" (actually FC Port) is waiting for login
-  // (e.g. after Link reset), set the device_blocked bit;
-  // after Port completes login, un-block target.
-  UCHAR device_blocked; // see Scsi_Device struct
-
-                    // define singly-linked list of logged-in ports
-                    // once a port_id is identified, it is remembered,
-                    // even if the port is removed indefinitely
-  PVOID pNextPort;  // actually, type PFC_LOGGEDIN_PORT; void for Compiler
+typedef struct {
+	union {
+		__u8 ucWWN[8];	// a FC 64-bit World Wide Name/ PortID of target
+		// addressing of single target on single loop...
+		u64 liWWN;
+	} u;
+
+	__u32 port_id;		// a FC 24-bit address of port (lower 8 bits = al_pa)
+
+	Scsi_Cmnd ScsiCmnd;	// command buffer for Report Luns
+#define REPORT_LUNS_PL 256
+	__u8 ReportLunsPayload[REPORT_LUNS_PL];
+
+	SCSI_NEXUS ScsiNexus;	// LUNs per FC device
+
+	__u32 LOGO_counter;	// might try several times before logging out for good
+	__u32 LOGO_timer;	// after LIP, ports expecting PDISC must time-out and
+	// LOGOut if successful PDISC not completed in 2 secs
+
+	__u32 concurrent_seq;	// must be 1 or greater
+	__u32 rx_data_size;	// e.g. 128, 256, 1024, 2048 per FC-PH spec
+	__u32 BB_credit;
+	__u32 EE_credit;
+
+	__u32 fcp_info;		// from PRLI (i.e. INITIATOR/ TARGET flags)
+	// flags for login process
+	__u8 Originator;	// Login sequence Originated (if false, we
+	// responded to another port's login sequence)
+	__u8 plogi;		// PLOGI frame ACCepted (originated or responded)
+	__u8 pdisc;		// PDISC frame was ORIGINATED (self-login logic)
+	__u8 prli;		// PRLI frame ACCepted (originated or responded)
+	__u8 flogi;		// FLOGI frame ACCepted (originated or responded)
+	__u8 logo;		// port permanently logged out (invalid login param)
+	__u8 flogiReq;	// Fabric login required (set in LIP process)
+	__u8 highest_ver;
+	__u8 lowest_ver;
+
+
+	// when the "target" (actually FC Port) is waiting for login
+	// (e.g. after Link reset), set the device_blocked bit;
+	// after Port completes login, un-block target.
+	__u8 device_blocked;	// see Scsi_Device struct
+
+	// define singly-linked list of logged-in ports
+	// once a port_id is identified, it is remembered,
+	// even if the port is removed indefinitely
+	void * pNextPort;	// actually, type PFC_LOGGEDIN_PORT; void for Compiler
 
 } FC_LOGGEDIN_PORT, *PFC_LOGGEDIN_PORT;
 
@@ -742,16 +728,15 @@
 
 // This serves as the ESB (Exchange Status Block),
 // and has timeout counter; used for ABORTs
-typedef struct                
-{                                  // FC-1 X_IDs
-  ULONG type;            // ELS_PLOGI, SCSI_IWE, ... (0 if free)
-  PFC_LOGGEDIN_PORT pLoggedInPort; // FC device on other end of Exchange
-  Scsi_Cmnd *Cmnd;       // Linux SCSI command packet includes S/G list
-  ULONG timeOut;         // units of ??, DEC by driver, Abort when 0
-  ULONG reTries;         // need one or more retries?
-  ULONG status;          // flags indicating errors (0 if none)
-  TachLiteIRB IRB;       // I/O Request Block, gets copied to ERQ
-  TachFCHDR_GCMND fchs;  // location of IRB's Req_A_SFS_Addr
+typedef struct {		// FC-1 X_IDs
+	__u32 type;		// ELS_PLOGI, SCSI_IWE, ... (0 if free)
+	PFC_LOGGEDIN_PORT pLoggedInPort;	// FC device on other end of Exchange
+	Scsi_Cmnd *Cmnd;	// Linux SCSI command packet includes S/G list
+	__u32 timeOut;		// units of ??, DEC by driver, Abort when 0
+	__u32 reTries;		// need one or more retries?
+	__u32 status;		// flags indicating errors (0 if none)
+	TachLiteIRB IRB;	// I/O Request Block, gets copied to ERQ
+	TachFCHDR_GCMND fchs;	// location of IRB's Req_A_SFS_Addr
 } FC_EXCHANGE, *PFC_EXCHANGE;
 
 // Unfortunately, Linux limits our kmalloc() allocations to 128k.
@@ -761,9 +746,9 @@
 // (In other words, this cumbersome indirection is necessary
 // because of kernel memory allocation constraints!)
 
-typedef struct // we will allocate this dynamically
+typedef struct			// we will allocate this dynamically
 {
-  FC_EXCHANGE fcExchange[ TACH_MAX_XID ];
+	FC_EXCHANGE fcExchange[TACH_MAX_XID];
 } FC_EXCHANGES;
 
 
@@ -776,95 +761,89 @@
 
 
 
-typedef struct
-{
-  char Name[64]; // name of controller ("HP Tachlite TL Rev2.0, 33MHz, 64bit bus")
-  //PVOID  pAdapterDevExt; // back pointer to device object/extension
-  ULONG ChipType;        // local numeric key for Tachyon Type / Rev.
-  ULONG status;              // our Driver - logical status
-  
-  TL_REGISTERS Registers;    // reg addresses & host memory copies
-                             // FC-4 mapping of 'transaction' to X_IDs
-  UCHAR LILPmap[32*4];       // Loop Position Map of ALPAs (late FC-AL only)
-  FC_OPTIONS Options;        // e.g. Target, Initiator, loopback...
-  UCHAR highest_FCPH_ver;    // FC-PH version limits
-  UCHAR lowest_FCPH_ver;     // FC-PH version limits
-
-  FC_EXCHANGES *Exchanges;  
-  ULONG fcLsExchangeLRU;       // Least Recently Used counter (Link Service)
-  ULONG fcSestExchangeLRU;       // Least Recently Used counter (FCP-SCSI)
-  FC_LOGGEDIN_PORT fcPorts;  // linked list of every FC port ever seen
-  FCSTATS fcStats;           // FC comm err counters
-
-                             // Host memory QUEUE pointers
-  TachLiteERQ *ERQ;          // Exchange Request Que 
-  TachyonIMQ *IMQ;           // Inbound Message Que 
-  TachLiteSFQ *SFQ;          // Single Frame Queue
-  TachSEST *SEST;            // SCSI Exchange State Table
-
-  dma_addr_t exch_dma_handle;
-
-  // these function pointers are for "generic" functions, which are
-  // replaced with Host Bus Adapter types at
-  // runtime.
-  int (*CreateTachyonQues)( void* , int);
-  int (*DestroyTachyonQues)( void* , int);
-  int (*LaserControl)(void*, int );   // e.g. On/Off
-  int (*ResetTachyon)(void*, int );
-  void (*FreezeTachyon)(void*, int );
-  void (*UnFreezeTachyon)(void*, int );
-  int (*InitializeTachyon)(void*, int, int );
-  int (*InitializeFrameManager)(void*, int );
-  int (*ProcessIMQEntry)(void*);
-  int (*ReadWriteWWN)(void*, int ReadWrite);
-  int (*ReadWriteNVRAM)(void*, void*, int ReadWrite);
+typedef struct {
+	char Name[64];		// name of controller ("HP Tachlite TL Rev2.0, 33MHz, 64bit bus")
+	//void *  pAdapterDevExt; // back pointer to device object/extension
+	__u32 ChipType;		// local numeric key for Tachyon Type / Rev.
+	__u32 status;		// our Driver - logical status
+
+	TL_REGISTERS Registers;	// reg addresses & host memory copies
+	// FC-4 mapping of 'transaction' to X_IDs
+	__u8 LILPmap[32 * 4];	// Loop Position Map of ALPAs (late FC-AL only)
+	FC_OPTIONS Options;	// e.g. Target, Initiator, loopback...
+	__u8 highest_FCPH_ver;	// FC-PH version limits
+	__u8 lowest_FCPH_ver;	// FC-PH version limits
+
+	FC_EXCHANGES *Exchanges;
+	__u32 fcLsExchangeLRU;	// Least Recently Used counter (Link Service)
+	__u32 fcSestExchangeLRU;	// Least Recently Used counter (FCP-SCSI)
+	FC_LOGGEDIN_PORT fcPorts;	// linked list of every FC port ever seen
+	FCSTATS fcStats;	// FC comm err counters
+
+	// Host memory QUEUE pointers
+	TachLiteERQ *ERQ;	// Exchange Request Que 
+	TachyonIMQ *IMQ;	// Inbound Message Que 
+	TachLiteSFQ *SFQ;	// Single Frame Queue
+	TachSEST *SEST;		// SCSI Exchange State Table
+
+	dma_addr_t exch_dma_handle;
+
+	// these function pointers are for "generic" functions, which are
+	// replaced with Host Bus Adapter types at
+	// runtime.
+	int (*CreateTachyonQues) (void *, int);
+	int (*DestroyTachyonQues) (void *, int);
+	int (*LaserControl) (void *, int);	// e.g. On/Off
+	int (*ResetTachyon) (void *, int);
+	void (*FreezeTachyon) (void *, int);
+	void (*UnFreezeTachyon) (void *, int);
+	int (*InitializeTachyon) (void *, int, int);
+	int (*InitializeFrameManager) (void *, int);
+	int (*ProcessIMQEntry) (void *);
+	int (*ReadWriteWWN) (void *, int ReadWrite);
+	int (*ReadWriteNVRAM) (void *, void *, int ReadWrite);
 
 } TACHYON, *PTACHYON;
 
 
 void cpqfcTSClearLinkStatusCounters(TACHYON * fcChip);
 
-int CpqTsCreateTachLiteQues( void* pHBA, int opcode);
-int CpqTsDestroyTachLiteQues( void* , int);
-int CpqTsInitializeTachLite( void *pHBA, int opcode1, int opcode2);
+int CpqTsCreateTachLiteQues(void *pHBA, int opcode);
+int CpqTsDestroyTachLiteQues(void *, int);
+int CpqTsInitializeTachLite(void *pHBA, int opcode1, int opcode2);
 
-int CpqTsProcessIMQEntry(void* pHBA);
+int CpqTsProcessIMQEntry(void *pHBA);
 int CpqTsResetTachLite(void *pHBA, int type);
 void CpqTsFreezeTachlite(void *pHBA, int type);
 void CpqTsUnFreezeTachlite(void *pHBA, int type);
 int CpqTsInitializeFrameManager(void *pHBA, int);
-int CpqTsLaserControl( void* addrBase, int opcode );
-int CpqTsReadWriteWWN(void*, int ReadWrite);
-int CpqTsReadWriteNVRAM(void*, void* data, int ReadWrite);
-
-void cpqfcTS_WorkTask( struct Scsi_Host *HostAdapter);
-void cpqfcTSWorkerThread( void *host);
-
-int cpqfcTS_GetNVRAM_data( UCHAR *wwnbuf, UCHAR *buf );
-ULONG cpqfcTS_ReadNVRAM( void* GPIOin, void* GPIOout , USHORT count,
-	UCHAR *buf );
-
-BOOLEAN tl_write_i2c_nvram( void* GPIOin, void* GPIOout,
-  USHORT startOffset,  // e.g. 0x2f for WWN start
-  USHORT count,
-  UCHAR *buf );
+int CpqTsLaserControl(void *addrBase, int opcode);
+int CpqTsReadWriteWWN(void *, int ReadWrite);
+int CpqTsReadWriteNVRAM(void *, void *data, int ReadWrite);
+
+void cpqfcTS_WorkTask(struct Scsi_Host *HostAdapter);
+void cpqfcTSWorkerThread(void *host);
+
+int cpqfcTS_GetNVRAM_data(__u8 * wwnbuf, __u8 * buf);
+__u32 cpqfcTS_ReadNVRAM(void *GPIOin, void *GPIOout, __u16 count, __u8 * buf);
+
+__u8 tl_write_i2c_nvram(void *GPIOin, void *GPIOout, __u16 startOffset,	// e.g. 0x2f for WWN start
+			   __u16 count, __u8 * buf);
 
 
 // define misc functions 
-int cpqfcTSGetLPSM( PTACHYON fcChip, char cErrorString[]);
-int cpqfcTSDecodeGBICtype( PTACHYON fcChip, char cErrorString[]);
-void* fcMemManager( struct pci_dev *pdev,
-		ALIGNED_MEM *dyn_mem_pair, ULONG n_alloc, ULONG ab,
-                   ULONG ulAlignedAddress, dma_addr_t *dma_handle);
+int cpqfcTSGetLPSM(PTACHYON fcChip, char cErrorString[]);
+int cpqfcTSDecodeGBICtype(PTACHYON fcChip, char cErrorString[]);
+void *fcMemManager(struct pci_dev *pdev, ALIGNED_MEM * dyn_mem_pair, __u32 n_alloc, __u32 ab, __u32 ulAlignedAddress, dma_addr_t * dma_handle);
 
-void BigEndianSwap(  UCHAR *source, UCHAR *dest,  USHORT cnt);
+void BigEndianSwap(__u8 * source, __u8 * dest, __u16 cnt);
+
+//__u32 virt_to_phys( void * virtaddr );
 
-//ULONG virt_to_phys( PVOID virtaddr );
-                  
 
 // Linux interrupt handler
-void cpqfcTS_intr_handler( int irq,void *dev_id,struct pt_regs *regs);
-void cpqfcTSheartbeat( unsigned long ptr );
+void cpqfcTS_intr_handler(int irq, void *dev_id, struct pt_regs *regs);
+void cpqfcTSheartbeat(unsigned long ptr);
 
 
 
@@ -872,19 +851,17 @@
 // need 4 bytes for x_ID, and a Scsi_Cmnd (~284 bytes)
 //#define LINKQ_ITEM_SIZE ((4+sizeof(Scsi_Cmnd)+3)/4)
 #define LINKQ_ITEM_SIZE (3*16)
-typedef struct
-{
-  ULONG Type;              // e.g. LINKUP, SFQENTRY, PDISC, BLS_ABTS, ...
-  ULONG ulBuff[ LINKQ_ITEM_SIZE ];
+typedef struct {
+	__u32 Type;		// e.g. LINKUP, SFQENTRY, PDISC, BLS_ABTS, ...
+	__u32 ulBuff[LINKQ_ITEM_SIZE];
 } LINKQ_ITEM;
 
 #define FC_LINKQ_DEPTH TACH_MAX_XID
-typedef struct
-{
-  ULONG producer;
-  ULONG consumer;  // when producer equals consumer, Q empty
+typedef struct {
+	__u32 producer;
+	__u32 consumer;		// when producer equals consumer, Q empty
 
-  LINKQ_ITEM Qitem[ FC_LINKQ_DEPTH ];
+	LINKQ_ITEM Qitem[FC_LINKQ_DEPTH];
 
 } FC_LINK_QUE, *PFC_LINK_QUE;
 
@@ -893,18 +870,16 @@
      // User thread processes
 #define FC_SCSIQ_DEPTH 32
 
-typedef struct
-{
-  int Type;              // e.g. SCSI
-  ULONG ulBuff[ 3*16 ];
+typedef struct {
+	int Type;		// e.g. SCSI
+	__u32 ulBuff[3 * 16];
 } SCSIQ_ITEM;
 
-typedef struct
-{
-  ULONG producer;
-  ULONG consumer;  // when producer equals consumer, Q empty
+typedef struct {
+	__u32 producer;
+	__u32 consumer;		// when producer equals consumer, Q empty
 
-  SCSIQ_ITEM Qitem[ FC_SCSIQ_DEPTH ];
+	SCSIQ_ITEM Qitem[FC_SCSIQ_DEPTH];
 
 } FC_SCSI_QUE, *PFC_SCSI_QUE;
 
@@ -912,44 +887,43 @@
 
 
 
-#define DYNAMIC_ALLOCATIONS 4  // Tachyon aligned allocations: ERQ,IMQ,SFQ,SEST
+#define DYNAMIC_ALLOCATIONS 4	// Tachyon aligned allocations: ERQ,IMQ,SFQ,SEST
 
 // Linux space allocated per HBA (chip state, etc.)
-typedef struct 
-{
-  struct Scsi_Host *HostAdapter; // back pointer to Linux Scsi struct
+typedef struct {
+	struct Scsi_Host *HostAdapter;	// back pointer to Linux Scsi struct
+
+	TACHYON fcChip;		// All Tachyon registers, Queues, functions
+	ALIGNED_MEM dynamic_mem[DYNAMIC_ALLOCATIONS];
+
+	struct pci_dev *PciDev;
+	dma_addr_t fcLQ_dma_handle;
+
+	Scsi_Cmnd *LinkDnCmnd[CPQFCTS_REQ_QUEUE_LEN];	// collects Cmnds during LDn
+	// (for Acceptable targets)
+	Scsi_Cmnd *BoardLockCmnd[CPQFCTS_REQ_QUEUE_LEN];	// SEST was full
+
+	Scsi_Cmnd *BadTargetCmnd[CPQFCTS_MAX_TARGET_ID];	// missing targets
+
+	u_char HBAnum;		// 0-based host number
+
 
-  TACHYON fcChip;    // All Tachyon registers, Queues, functions
-  ALIGNED_MEM dynamic_mem[DYNAMIC_ALLOCATIONS];
+	struct timer_list cpqfcTStimer;	// FC utility timer for implicit
+	// logouts, FC protocol timeouts, etc.
+	int fcStatsTime;	// Statistics delta reporting time
 
-  struct pci_dev *PciDev;
-  dma_addr_t fcLQ_dma_handle;
+	struct task_struct *worker_thread;	// our kernel thread
+	int PortDiscDone;	// set by SendLogins(), cleared by LDn
 
-  Scsi_Cmnd *LinkDnCmnd[CPQFCTS_REQ_QUEUE_LEN]; // collects Cmnds during LDn
-                                                // (for Acceptable targets)
-  Scsi_Cmnd *BoardLockCmnd[CPQFCTS_REQ_QUEUE_LEN]; // SEST was full
-  
-  Scsi_Cmnd *BadTargetCmnd[CPQFCTS_MAX_TARGET_ID]; // missing targets
-
-  u_char HBAnum;     // 0-based host number
-
-
-  struct timer_list cpqfcTStimer; // FC utility timer for implicit
-                                  // logouts, FC protocol timeouts, etc.
-  int fcStatsTime;  // Statistics delta reporting time
-
-  struct task_struct *worker_thread; // our kernel thread
-  int PortDiscDone;    // set by SendLogins(), cleared by LDn
-  
-  struct semaphore *TachFrozen;
-  struct semaphore *TYOBcomplete;    // handshake for Tach outbound frames
-  struct semaphore *fcQueReady;      // FibreChannel work for our kernel thread
-  struct semaphore *notify_wt;       // synchronizes kernel thread kill
-  struct semaphore *BoardLock;
-  
-  PFC_LINK_QUE fcLQ;             // the WorkerThread operates on this
+	struct semaphore *TachFrozen;
+	struct semaphore *TYOBcomplete;	// handshake for Tach outbound frames
+	struct semaphore *fcQueReady;	// FibreChannel work for our kernel thread
+	struct semaphore *notify_wt;	// synchronizes kernel thread kill
+	struct semaphore *BoardLock;
 
-  spinlock_t hba_spinlock;           // held/released by WorkerThread
+	PFC_LINK_QUE fcLQ;	// the WorkerThread operates on this
+
+	spinlock_t hba_spinlock;	// held/released by WorkerThread
 
 } CPQFCHBA;
 
@@ -958,69 +932,41 @@
 
 
 
-void cpqfcTSImplicitLogout( CPQFCHBA* cpqfcHBAdata,
-		PFC_LOGGEDIN_PORT pFcPort);
+void cpqfcTSImplicitLogout(CPQFCHBA * cpqfcHBAdata, PFC_LOGGEDIN_PORT pFcPort);
+
+
+void cpqfcTSTerminateExchange(CPQFCHBA *, SCSI_NEXUS * target, int);
+
+PFC_LOGGEDIN_PORT fcPortLoggedIn(CPQFCHBA * cpqfcHBAdata, TachFCHDR_GCMND * fchs, __u8, __u8);
+void fcProcessLoggedIn(CPQFCHBA * cpqfcHBAdata, TachFCHDR_GCMND * fchs);
+
+
+__u32 cpqfcTSBuildExchange(CPQFCHBA * cpqfcHBAdata, __u32 type,	// e.g. PLOGI
+			   TachFCHDR_GCMND * InFCHS,	// incoming FCHS
+			   void *Data,	// the CDB, scatter/gather, etc.  
+			   __s32 * ExchangeID);	// allocated exchange ID
+
+__u32 cpqfcTSStartExchange(CPQFCHBA * cpqfcHBAdata, __s32 ExchangeID);
+
+void cpqfcTSCompleteExchange(struct pci_dev *pcidev, PTACHYON fcChip, __u32 exchange_ID);
+
+
+PFC_LOGGEDIN_PORT fcFindLoggedInPort(PTACHYON fcChip, Scsi_Cmnd * Cmnd,	// (We want the channel/target/lun Nexus from Cmnd)
+				     __u32 port_id,	// search linked list for al_pa, or
+				     __u8 wwn[8],	// search linked list for WWN, or...
+				     PFC_LOGGEDIN_PORT * pLastLoggedInPort);
 
+void cpqfcTSPutLinkQue(CPQFCHBA * cpqfcHBAdata, int Type, void *QueContent);
 
-void cpqfcTSTerminateExchange( CPQFCHBA*, SCSI_NEXUS *target, int );
+void fcPutScsiQue(CPQFCHBA * cpqfcHBAdata, int Type, void *QueContent);
 
-PFC_LOGGEDIN_PORT fcPortLoggedIn( 
-   CPQFCHBA *cpqfcHBAdata, 
-   TachFCHDR_GCMND* fchs, 
-   BOOLEAN, 
-   BOOLEAN);
-void fcProcessLoggedIn( 
-   CPQFCHBA *cpqfcHBAdata, TachFCHDR_GCMND* fchs);
-
-
-ULONG cpqfcTSBuildExchange( 
-  CPQFCHBA *cpqfcHBAdata,
-  ULONG type, // e.g. PLOGI
-  TachFCHDR_GCMND* InFCHS,  // incoming FCHS
-  void *Data,               // the CDB, scatter/gather, etc.  
-  LONG *ExchangeID );       // allocated exchange ID
-
-ULONG cpqfcTSStartExchange( 
-  CPQFCHBA *cpqfcHBAdata,
-  LONG ExchangeID );
-
-void cpqfcTSCompleteExchange( 
-       struct pci_dev *pcidev,
-       PTACHYON fcChip, 
-       ULONG exchange_ID);
-
-
-PFC_LOGGEDIN_PORT  fcFindLoggedInPort( 
-  PTACHYON fcChip, 
-  Scsi_Cmnd *Cmnd,  // (We want the channel/target/lun Nexus from Cmnd)
-  ULONG port_id,  // search linked list for al_pa, or
-  UCHAR wwn[8],    // search linked list for WWN, or...
-  PFC_LOGGEDIN_PORT *pLastLoggedInPort
-);
-
-void cpqfcTSPutLinkQue( 
-  CPQFCHBA *cpqfcHBAdata, 
-  int Type, 
-  void *QueContent);
-
-void fcPutScsiQue( 
-  CPQFCHBA *cpqfcHBAdata, 
-  int Type, 
-  void *QueContent);
-
-void fcLinkQReset(
-   CPQFCHBA *);
-void fcScsiQReset(
-   CPQFCHBA *);
-void fcSestReset(
-   CPQFCHBA *);
-
-void cpqfc_pci_unmap(struct pci_dev *pcidev, 
-	Scsi_Cmnd *cmd, 
-	PTACHYON fcChip, 
-	ULONG x_ID);
+void fcLinkQReset(CPQFCHBA *);
+void fcScsiQReset(CPQFCHBA *);
+void fcSestReset(CPQFCHBA *);
 
-extern const UCHAR valid_al_pa[];
+void cpqfc_pci_unmap(struct pci_dev *pcidev, Scsi_Cmnd * cmd, PTACHYON fcChip, __u32 x_ID);
+
+extern const __u8 valid_al_pa[];
 extern const int number_of_al_pa;
 
 #define FCP_RESID_UNDER   0x80000
@@ -1036,37 +982,35 @@
 #define FCP_TASKFUNCTION_FAIL      0x5000000
 
 // FCP-SCSI response status struct
-typedef struct  // see "TachFCHDR_RSP" definition - 64 bytes
+typedef struct			// see "TachFCHDR_RSP" definition - 64 bytes
 {
-  __u32 reserved;
-  __u32 reserved1;
-  __u32 fcp_status;    // field validity and SCSI status
-  __u32 fcp_resid;
-  __u32 fcp_sns_len;   // length of FCP_SNS_INFO field
-  __u32 fcp_rsp_len;   // length of FCP_RSP_INFO field (expect 8)
-  __u32 fcp_rsp_info;  // 4 bytes of FCP protocol response information
-  __u32 fcp_rsp_info2; // (4 more bytes, since most implementations use 8)
-  __u8  fcp_sns_info[36]; // bytes for SCSI sense (ASC, ASCQ)
+	__u32 reserved;
+	__u32 reserved1;
+	__u32 fcp_status;	// field validity and SCSI status
+	__u32 fcp_resid;
+	__u32 fcp_sns_len;	// length of FCP_SNS_INFO field
+	__u32 fcp_rsp_len;	// length of FCP_RSP_INFO field (expect 8)
+	__u32 fcp_rsp_info;	// 4 bytes of FCP protocol response information
+	__u32 fcp_rsp_info2;	// (4 more bytes, since most implementations use 8)
+	__u8 fcp_sns_info[36];	// bytes for SCSI sense (ASC, ASCQ)
 
 } FCP_STATUS_RESPONSE, *PFCP_STATUS_RESPONSE;
 
 
 // Fabric State Change Registration
-typedef struct scrpl
-{
-  __u32 command;
-  __u32 function;
+typedef struct scrpl {
+	__u32 command;
+	__u32 function;
 } SCR_PL;
 
 // Fabric Name Service Request
-typedef struct nsrpl
-{
-  __u32 CT_Rev;  // (& IN_ID)   WORD 0
-  __u32 FCS_Type;            // WORD 1
-  __u32 Command_code;        // WORD 2
-  __u32 reason_code;         // WORD 3
-  __u32 FCP;                 // WORD 4 (lower byte)
-  
+typedef struct nsrpl {
+	__u32 CT_Rev;		// (& IN_ID)   WORD 0
+	__u32 FCS_Type;		// WORD 1
+	__u32 Command_code;	// WORD 2
+	__u32 reason_code;	// WORD 3
+	__u32 FCP;		// WORD 4 (lower byte)
+
 } NSR_PL;
 
 
@@ -1089,12 +1033,12 @@
 					// PDISC after a LIP.
 #define E_D_TOV			2	// Minimum Time to wait for Sequence
 					// Completion.
-#define R_A_TOV			0	// Minimum Time for Target to wait 
+#define R_A_TOV			0	// Minimum Time for Target to wait
 					// before reclaiming resources.
 //
-//	R_CTL Field
+//      R_CTL Field
 //
-//	Routing Bits (31-28)
+//      Routing Bits (31-28)
 //
 #define FC4_DEVICE_DATA		0x00000000
 #define EXT_LINK_DATA		0x20000000
@@ -1105,7 +1049,7 @@
 #define ROUTING_MASK		0xF0000000
 
 //
-//	Information Bits (27-24)
+//      Information Bits (27-24)
 //
 #define UNCAT_INFORMATION	0x00000000
 #define SOLICITED_DATA		0x01000000
@@ -1117,20 +1061,20 @@
 #define COMMAND_STATUS		0x07000000
 #define INFO_MASK		0x0F000000
 //
-//	(Link Control Codes)
+//      (Link Control Codes)
 //
 #define ACK_1			0x00000000
 #define ACK_0_OR_N		0x01000000
-#define P_RJT			0x02000000 
-#define F_RJT			0x03000000 
+#define P_RJT			0x02000000
+#define F_RJT			0x03000000
 #define P_BSY			0x04000000
 #define FABRIC_BUSY_TO_DF	0x05000000	// Fabric Busy to Data Frame
 #define FABRIC_BUSY_TO_LC	0x06000000	// Fabric Busy to Link Ctl Frame
 #define LINK_CREDIT_RESET	0x07000000
 //
-//	(Link Service Command Codes)
+//      (Link Service Command Codes)
 //
-//#define LS_RJT			0x01000000	// LS Reject
+//#define LS_RJT                        0x01000000      // LS Reject
 
 #define LS_ACC			0x02000000	// LS Accept
 #define LS_PLOGI		0x03000000	// N_PORT Login
@@ -1156,11 +1100,11 @@
 #define LS_FDISC		0x51000000	// Fabric Discovery
 #define LS_ADISC		0x52000000	// Discover Address
 #define LS_RNC			0x53000000	// Report Node Capability
-#define LS_SCR                  0x62000000      // State Change Registration
-#define LS_MASK			0xFF000000	
+#define LS_SCR                  0x62000000	// State Change Registration
+#define LS_MASK			0xFF000000
 
 //
-// 	TYPE Bit Masks
+//      TYPE Bit Masks
 //
 #define BASIC_LINK_SERVICE	0x00000000
 #define EXT_LINK_SERVICE	0x01000000
@@ -1186,35 +1130,35 @@
 #define TYPE_MASK		0xFF000000
 
 typedef struct {
-	UCHAR seq_id_valid;
-	UCHAR seq_id;
-	USHORT reserved;  // 2 bytes reserved
-	ULONG ox_rx_id;
-	USHORT low_seq_cnt;
-	USHORT high_seq_cnt;
+	__u8 seq_id_valid;
+	__u8 seq_id;
+	__u16 reserved;	// 2 bytes reserved
+	__u32 ox_rx_id;
+	__u16 low_seq_cnt;
+	__u16 high_seq_cnt;
 } BA_ACC_PAYLOAD;
 
 typedef struct {
-	UCHAR reserved;
-	UCHAR reason_code;
-	UCHAR reason_explain;
-	UCHAR vendor_unique;
+	__u8 reserved;
+	__u8 reason_code;
+	__u8 reason_explain;
+	__u8 vendor_unique;
 } BA_RJT_PAYLOAD;
 
 
 typedef struct {
-	ULONG 	command_code;
-	ULONG 	sid;
-	USHORT	ox_id;
-	USHORT	rx_id;
+	__u32 command_code;
+	__u32 sid;
+	__u16 ox_id;
+	__u16 rx_id;
 } RRQ_MESSAGE;
 
 typedef struct {
-	ULONG command_code;
-	UCHAR vendor;
-	UCHAR explain;
-	UCHAR reason;
-	UCHAR reserved;
+	__u32 command_code;
+	__u8 vendor;
+	__u8 explain;
+	__u8 reason;
+	__u8 reserved;
 } REJECT_MESSAGE;
 
 
@@ -1244,9 +1188,9 @@
 
 #define X_ID_INTERLOCK		0x2000
 
-#define ERROR_POLICY		0x1800		// Error Policy Supported
-#define ERROR_DISCARD		0x00		// Only Discard Supported
-#define ERROR_DISC_PROCESS	0x02		// Discard and process supported
+#define ERROR_POLICY		0x1800	// Error Policy Supported
+#define ERROR_DISCARD		0x00	// Only Discard Supported
+#define ERROR_DISC_PROCESS	0x02	// Discard and process supported
 
 #define NODE_ID			0x01
 #define IEEE_EXT		0x20
@@ -1255,88 +1199,87 @@
 // Categories Supported Per Sequence
 //
 #define	CATEGORIES_PER_SEQUENCE	0x300
-#define ONE_CATEGORY_SEQUENCE	0x00		// 1 Category per Sequence
-#define TWO_CATEGORY_SEQUENCE	0x01		// 2 Categories per Sequence
-#define MANY_CATEGORY_SEQUENCE	0x03		// > 2 Categories/Sequence
+#define ONE_CATEGORY_SEQUENCE	0x00	// 1 Category per Sequence
+#define TWO_CATEGORY_SEQUENCE	0x01	// 2 Categories per Sequence
+#define MANY_CATEGORY_SEQUENCE	0x03	// > 2 Categories/Sequence
 
 typedef struct {
 
-	USHORT initiator_control;
-	USHORT service_options;
+	__u16 initiator_control;
+	__u16 service_options;
 
-	USHORT rx_data_size;
-	USHORT recipient_control;
+	__u16 rx_data_size;
+	__u16 recipient_control;
 
-	USHORT ee_credit;
-	USHORT concurrent_sequences;
+	__u16 ee_credit;
+	__u16 concurrent_sequences;
 
-	USHORT reserved;
-	USHORT open_sequences;
+	__u16 reserved;
+	__u16 open_sequences;
 
 } CLASS_PARAMETERS;
 
 typedef struct {
-	ULONG	login_cmd;
+	__u32 login_cmd;
 	//
 	// Common Service Parameters
 	//
 	struct {
 
-		USHORT bb_credit;
-		UCHAR lowest_ver;
-		UCHAR highest_ver;
+		__u16 bb_credit;
+		__u8 lowest_ver;
+		__u8 highest_ver;
 
-		USHORT bb_rx_size;
-		USHORT common_features;
+		__u16 bb_rx_size;
+		__u16 common_features;
 
-		USHORT rel_offset;
-		USHORT concurrent_seq;
+		__u16 rel_offset;
+		__u16 concurrent_seq;
 
 
-		ULONG e_d_tov;
+		__u32 e_d_tov;
 	} cmn_services;
 
 	//
 	// Port Name
 	//
-	UCHAR port_name[8];
+	__u8 port_name[8];
 
 	//
 	// Node/Fabric Name
 	//
-	UCHAR node_name[8];
+	__u8 node_name[8];
 
 	//
 	// Class 1, 2 and 3 Service Parameters
 	//
-	CLASS_PARAMETERS	class1;
-	CLASS_PARAMETERS	class2;
-	CLASS_PARAMETERS	class3;
+	CLASS_PARAMETERS class1;
+	CLASS_PARAMETERS class2;
+	CLASS_PARAMETERS class3;
 
-	ULONG reserved[4];
+	__u32 reserved[4];
 
 	//
 	// Vendor Version Level
 	//
-	UCHAR		vendor_id[2];
-	UCHAR		vendor_version[6];
-	ULONG		buffer_size;
-	USHORT		rxid_start;
-	USHORT		total_rxids;
+	__u8 vendor_id[2];
+	__u8 vendor_version[6];
+	__u32 buffer_size;
+	__u16 rxid_start;
+	__u16 total_rxids;
 } LOGIN_PAYLOAD;
 
 
-typedef struct
-{
-  ULONG cmd;  // 4 bytes
-  UCHAR n_port_identifier[3];
-  UCHAR reserved;
-  UCHAR port_name[8];
+typedef struct {
+	__u32 cmd;		// 4 bytes
+	__u8 n_port_identifier[3];
+	__u8 reserved;
+	__u8 port_name[8];
 } LOGOUT_PAYLOAD;
 
 
 //
-//	PRLI Request Service Parameter Defines
+//      PRLI Request Service Parameter Defines
 //
 #define PRLI_ACC			0x01
 #define PRLI_REQ			0x02
@@ -1361,54 +1304,54 @@
 #define NO_MULTI_PAGE		0x700
 
 typedef struct {
-	USHORT	payload_length;
-	UCHAR	page_length;
-	UCHAR	cmd;
+	__u16 payload_length;
+	__u8 page_length;
+	__u8 cmd;
+
 
+	__u32 valid;
 
-	ULONG	valid;
+	__u32 orig_process_associator;
 
-	ULONG	orig_process_associator;
+	__u32 resp_process_associator;
 
-	ULONG	resp_process_associator;
-	
-	ULONG	fcp_info;
+	__u32 fcp_info;
 } PRLI_REQUEST;
 
 typedef struct {
 
-	USHORT	payload_length;
-	UCHAR	page_length;
-	UCHAR	cmd;
+	__u16 payload_length;
+	__u8 page_length;
+	__u8 cmd;
 
-	ULONG	valid;
-	ULONG	orig_process_associator;
+	__u32 valid;
+	__u32 orig_process_associator;
 
-	ULONG	resp_process_associator;
-	ULONG	reserved;
+	__u32 resp_process_associator;
+	__u32 reserved;
 } PRLO_REQUEST;
 
 typedef struct {
-	ULONG	cmd;
+	__u32 cmd;
+
+	__u32 hard_address;
 
-	ULONG	hard_address;
-	
-	UCHAR	port_name[8];
+	__u8 port_name[8];
 
-	UCHAR	node_name[8];
+	__u8 node_name[8];
 
-	ULONG	s_id;
+	__u32 s_id;
 } ADISC_PAYLOAD;
 
 struct ext_sg_entry_t {
 	__u32 len:18;		/* buffer length, bits 0-17 */
 	__u32 uba:13;		/* upper bus address bits 18-31 */
 	__u32 lba;		/* lower bus address bits 0-31 */
-}; 
+};
 
 // J. McCarty's LINK.H
 //
-//	LS_RJT Reason Codes
+//      LS_RJT Reason Codes
 //
 
 #define INVALID_COMMAND_CODE	0x01
@@ -1420,7 +1363,7 @@
 #define LS_VENDOR_UNIQUE	0xFF
 
 //
-// 	LS_RJT Reason Codes Explanations
+//      LS_RJT Reason Codes Explanations
 //
 #define NO_REASON		0x00
 #define OPTIONS_ERROR		0x01
@@ -1439,38 +1382,38 @@
 #define CMD_IN_PROCESS		0x19
 #define INVALID_IDENTIFIER	0x1F	// Invalid N_PORT Identifier
 #define INVALID_SEQ_ID		0x21
-#define ABT_INVALID_XCHNG	0x23 	// Attempt to Abort an invalid Exchange
-#define ABT_INACTIVE_XCHNG	0x25 	// Attempt to Abort an inactive Exchange
+#define ABT_INVALID_XCHNG	0x23	// Attempt to Abort an invalid Exchange
+#define ABT_INACTIVE_XCHNG	0x25	// Attempt to Abort an inactive Exchange
 #define NEED_REC_QUAL		0x27	// Recovery Qualifier required
 #define NO_LOGIN_RESOURCES	0x29	// No resources to support login
 #define NO_DATA			0x2A	// Unable to supply requested data
 #define	REQUEST_NOT_SUPPORTED	0x2C	// Request Not Supported
 
 //
-//	Link Control Codes
+//      Link Control Codes
 //
 
 //
-//	P_BSY Action Codes
+//      P_BSY Action Codes
 //
 #define SEQUENCE_TERMINATED	0x01000000
 #define SEQUENCE_ACTIVE		0x02000000
 
 //
-//	P_BSY Reason Codes
+//      P_BSY Reason Codes
 //
 #define PHYS_NPORT_BUSY		0x010000
 #define NPORT_RESOURCE_BUSY	0x020000
 
 //
-// 	P_RJT, F_RJT Action Codes
+//      P_RJT, F_RJT Action Codes
 //
 
 #define RETRYABLE_ERROR		0x01000000
 #define NON_RETRYABLE_ERROR	0x02000000
 
 //
-// 	P_RJT, F_RJT Reason Codes
+//      P_RJT, F_RJT Reason Codes
 //
 #define INVALID_D_ID		0x010000
 #define INVALID_S_ID		0x020000
@@ -1500,7 +1443,7 @@
 #define P_VENDOR_UNIQUE		0xFF0000
 
 //
-// 	BA_RJT Reason Codes
+//      BA_RJT Reason Codes
 //
 #define BA_INVALID_COMMAND	0x00010000
 #define BA_LOGICAL_ERROR	0x00030000
@@ -1509,7 +1452,7 @@
 #define BA_UNABLE_TO_PERFORM	0x00090000
 
 //
-// 	BA_RJT Reason Explanation Codes
+//      BA_RJT Reason Explanation Codes
 //
 #define BA_NO_REASON		0x00000000
 #define BA_INVALID_OX_RX	0x00000300
@@ -1517,5 +1460,4 @@
 
 
 
-#endif /* CPQFCTSSTRUCTS_H	*/
-
+#endif				/* CPQFCTSSTRUCTS_H      */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/cpqfcTStrigger.c linux-2.4.21-pre6/drivers/scsi/cpqfcTStrigger.c
--- linux-2.4.20/drivers/scsi/cpqfcTStrigger.c	2001-08-12 17:51:41.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/cpqfcTStrigger.c	2003-03-26 23:49:20.000000000 +0000
@@ -12,22 +12,22 @@
 #include <linux/pci.h>
 #include <asm/io.h>
 
-void TriggerHBA( void* IOBaseUpper, int Print)
+void TriggerHBA(void *io_upper, int print)
 {
-  __u32 long value;
+	__u32 long value;
 
-  // get initial value in hopes of not modifying any other GPIO line
-  IOBaseUpper += 0x188;  // TachTL/TS Control reg
-  
-  value = readl( IOBaseUpper);
-  // set HIGH to trigger external analyzer (tested on Dolche Finisar 1Gb GTA)
-  // The Finisar anaylzer triggers on low-to-high TTL transition
-  value |= 0x01; // set bit 0
+	// get initial value in hopes of not modifying any other GPIO line
+	io_upper += 0x188;	// TachTL/TS Control reg
 
-  writel( value, IOBaseUpper);
+	value = readl(io_upper);
+	// set HIGH to trigger external analyzer (tested on Dolche Finisar 1Gb GTA)
+	// The Finisar anaylzer triggers on low-to-high TTL transition
+	value |= 0x01;		// set bit 0
 
-  if( Print)
-    printk( " -GPIO0 set- ");
+	writel(value, io_upper);
+
+	if (print)
+		printk(" -GPIO0 set- ");
 }
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/cpqfcTStrigger.h linux-2.4.21-pre6/drivers/scsi/cpqfcTStrigger.h
--- linux-2.4.20/drivers/scsi/cpqfcTStrigger.h	2001-08-12 17:51:41.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/cpqfcTStrigger.h	2003-03-26 23:49:35.000000000 +0000
@@ -1,8 +1,7 @@
 // don't do this unless you have the right hardware!
 #define TRIGGERABLE_HBA 0
 #if TRIGGERABLE_HBA
-void TriggerHBA( void*, int);
+void TriggerHBA(void *, int);
 #else
 #define TriggerHBA(x, y)
 #endif
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/cpqfcTSworker.c linux-2.4.21-pre6/drivers/scsi/cpqfcTSworker.c
--- linux-2.4.20/drivers/scsi/cpqfcTSworker.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/cpqfcTSworker.c	2003-03-26 23:49:51.000000000 +0000
@@ -44,7 +44,7 @@
 
 
 #include "sd.h"
-#include "hosts.h"   // struct Scsi_Host definition for T handler
+#include "hosts.h"		// struct Scsi_Host definition for T handler
 #include "cpqfcTSchip.h"
 #include "cpqfcTSstructs.h"
 #include "cpqfcTStrigger.h"
@@ -116,724 +116,579 @@
 
 // local functions
 
-static void SetLoginFields(
-  PFC_LOGGEDIN_PORT pLoggedInPort,
-  TachFCHDR_GCMND* fchs,
-  BOOLEAN PDisc,
-  BOOLEAN Originator);
+static void SetLoginFields(PFC_LOGGEDIN_PORT pLoggedInPort, TachFCHDR_GCMND * fchs, u8 PDisc, u8 Originator);
 
-static void AnalyzeIncomingFrame( 
-       CPQFCHBA *cpqfcHBAdata,
-       ULONG QNdx );
+static void AnalyzeIncomingFrame(CPQFCHBA * dev, u32 QNdx);
 
-static void SendLogins( CPQFCHBA *cpqfcHBAdata, __u32 *FabricPortIds );
+static void SendLogins(CPQFCHBA * dev, __u32 * FabricPortIds);
 
-static int verify_PLOGI( PTACHYON fcChip,
-      TachFCHDR_GCMND* fchs, ULONG* reject_explain);
-static int verify_PRLI( TachFCHDR_GCMND* fchs, ULONG* reject_explain);
+static int verify_PLOGI(PTACHYON fcChip, TachFCHDR_GCMND * fchs, u32 * reject_explain);
+static int verify_PRLI(TachFCHDR_GCMND * fchs, u32 * reject_explain);
 
-static void LoadWWN( PTACHYON fcChip, UCHAR* dest, UCHAR type);
-static void BuildLinkServicePayload( 
-              PTACHYON fcChip, ULONG type, void* payload);
+static void LoadWWN(PTACHYON fcChip, u8 * dest, u8 type);
+static void BuildLinkServicePayload(PTACHYON fcChip, u32 type, void *payload);
 
-static void UnblockScsiDevice( struct Scsi_Host *HostAdapter, 
-        PFC_LOGGEDIN_PORT pLoggedInPort);
+static void UnblockScsiDevice(struct Scsi_Host *HostAdapter, PFC_LOGGEDIN_PORT pLoggedInPort);
 
-static void cpqfcTSCheckandSnoopFCP( PTACHYON fcChip, ULONG x_ID);
+static void cpqfcTSCheckandSnoopFCP(PTACHYON fcChip, u32 x_ID);
 
-static void CompleteBoardLockCmnd( CPQFCHBA *cpqfcHBAdata);
+static void CompleteBoardLockCmnd(CPQFCHBA * dev);
 
-static void RevalidateSEST( struct Scsi_Host *HostAdapter, 
-		        PFC_LOGGEDIN_PORT pLoggedInPort);
+static void RevalidateSEST(struct Scsi_Host *HostAdapter, PFC_LOGGEDIN_PORT pLoggedInPort);
 
-static void IssueReportLunsCommand( 
-              CPQFCHBA* cpqfcHBAdata, 
-	      TachFCHDR_GCMND* fchs);
+static void IssueReportLunsCommand(CPQFCHBA * dev, TachFCHDR_GCMND * fchs);
 
 // (see scsi_error.c comments on kernel task creation)
 
-void cpqfcTSWorkerThread( void *host)
+void cpqfcTSWorkerThread(void *host)
 {
-  struct Scsi_Host *HostAdapter = (struct Scsi_Host*)host;
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata; 
+	struct Scsi_Host *shpnt = (struct Scsi_Host *) host;
+	CPQFCHBA *dev = (CPQFCHBA *) shpnt->hostdata;
 #ifdef PCI_KERNEL_TRACE
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+	PTACHYON fcChip = &dev->fcChip;
 #endif
-  struct fs_struct *fs;
-  DECLARE_MUTEX_LOCKED(fcQueReady);
-  DECLARE_MUTEX_LOCKED(fcTYOBcomplete); 
-  DECLARE_MUTEX_LOCKED(TachFrozen);  
-  DECLARE_MUTEX_LOCKED(BoardLock);  
+	struct fs_struct *fs;
+	DECLARE_MUTEX_LOCKED(fcQueReady);
+	DECLARE_MUTEX_LOCKED(fcTYOBcomplete);
+	DECLARE_MUTEX_LOCKED(TachFrozen);
+	DECLARE_MUTEX_LOCKED(BoardLock);
 
-  ENTER("WorkerThread");
+	ENTER("WorkerThread");
 
-  lock_kernel();
+	lock_kernel();
 	/*
 	 * If we were started as result of loading a module, close all of the
 	 * user space pages.  We don't need them, and if we didn't close them
 	 * they would be locked into memory.
+	 *
+	 * FIXME: should use daemonize!
 	 */
-  exit_mm(current);
+	exit_mm(current);
 
-  current->session = 1;
-  current->pgrp = 1;
-	
-  /* Become as one with the init task */
-	
-  exit_fs(current);	/* current->fs->count--; */
-  fs = init_task.fs;
-  // Some kernels compiled for SMP, while actually running
-  // on a uniproc machine, will return NULL for this call
-  if( !fs)
-  {
-    printk(" cpqfcTS FATAL: fs is NULL! Is this an SMP kernel on uniproc machine?\n ");
-  }
- 
-  else
-  { 
-    current->fs = fs;
-    atomic_inc(&fs->count);
-  }
+	current->session = 1;
+	current->pgrp = 1;
 
-  siginitsetinv(&current->blocked, SHUTDOWN_SIGS);
+	/* Become as one with the init task */
 
+	exit_fs(current);	/* current->fs->count--; */
+	fs = init_task.fs;
+	current->fs = fs;
+	atomic_inc(&fs->count);
 
-  /*
-   * Set the name of this process.
-   */
-  sprintf(current->comm, "cpqfcTS_wt_%d", HostAdapter->host_no);
+	siginitsetinv(&current->blocked, SHUTDOWN_SIGS);
 
-  cpqfcHBAdata->fcQueReady = &fcQueReady;  // primary wait point
-  cpqfcHBAdata->TYOBcomplete = &fcTYOBcomplete;
-  cpqfcHBAdata->TachFrozen = &TachFrozen;
-    
- 
-  cpqfcHBAdata->worker_thread = current;
-  
-  unlock_kernel();
 
-  if( cpqfcHBAdata->notify_wt != NULL )
-    up( cpqfcHBAdata->notify_wt); // OK to continue
+	/*
+	 * Set the name of this process.
+	 */
+	sprintf(current->comm, "cpqfcTS_wt_%d", shpnt->host_no);
 
-  while(1)
-  {
-    unsigned long flags;
+	dev->fcQueReady = &fcQueReady;	// primary wait point
+	dev->TYOBcomplete = &fcTYOBcomplete;
+	dev->TachFrozen = &TachFrozen;
 
-    down_interruptible( &fcQueReady);  // wait for something to do
 
-    if (signal_pending(current) )
-      break;
-    
-    PCI_TRACE( 0x90)
-    // first, take the IO lock so the SCSI upper layers can't call
-    // into our _quecommand function (this also disables INTs)
-    spin_lock_irqsave( &io_request_lock, flags); // STOP _que function
-    PCI_TRACE( 0x90)
-         
-    CPQ_SPINLOCK_HBA( cpqfcHBAdata)
-    // next, set this pointer to indicate to the _quecommand function
-    // that the board is in use, so it should que the command and 
-    // immediately return (we don't actually require the semaphore function
-    // in this driver rev)
+	dev->worker_thread = current;
 
-    cpqfcHBAdata->BoardLock = &BoardLock;
+	unlock_kernel();
 
-    PCI_TRACE( 0x90)
+	if (dev->notify_wt != NULL)
+		up(dev->notify_wt);	// OK to continue
 
-    // release the IO lock (and re-enable interrupts)
-    spin_unlock_irqrestore( &io_request_lock, flags);
+	while (1) {
+		unsigned long flags;
 
-    // disable OUR HBA interrupt (keep them off as much as possible
-    // during error recovery)
-    disable_irq( cpqfcHBAdata->HostAdapter->irq);
+		down_interruptible(&fcQueReady);	// wait for something to do
 
-    // OK, let's process the Fibre Channel Link Q and do the work
-    cpqfcTS_WorkTask( HostAdapter);
+		if (signal_pending(current))
+			break;
 
-    // hopefully, no more "work" to do;
-    // re-enable our INTs for "normal" completion processing
-    enable_irq( cpqfcHBAdata->HostAdapter->irq);
- 
+		PCI_TRACE(0x90)
+		// first, take the IO lock so the SCSI upper layers can't call
+		// into our _quecommand function (this also disables INTs)
+		spin_lock_irqsave(&io_request_lock, flags);	// STOP _que function
+		PCI_TRACE(0x90)
 
-    cpqfcHBAdata->BoardLock = NULL; // allow commands to be queued
-    CPQ_SPINUNLOCK_HBA( cpqfcHBAdata)
+		CPQ_SPINLOCK_HBA(dev)
+		// next, set this pointer to indicate to the _quecommand function
+		// that the board is in use, so it should que the command and 
+		// immediately return (we don't actually require the semaphore function
+		// in this driver rev)
+		dev->BoardLock = &BoardLock;
 
+		PCI_TRACE(0x90)
+		// release the IO lock (and re-enable interrupts)
+		spin_unlock_irqrestore(&io_request_lock, flags);
 
-    // Now, complete any Cmnd we Q'd up while BoardLock was held
+		// disable OUR HBA interrupt (keep them off as much as possible
+		// during error recovery)
+		disable_irq(dev->HostAdapter->irq);
 
-    CompleteBoardLockCmnd( cpqfcHBAdata);
-  
+		// OK, let's process the Fibre Channel Link Q and do the work
+		cpqfcTS_WorkTask(shpnt);
 
-  }
-  // hopefully, the signal was for our module exit...
-  if( cpqfcHBAdata->notify_wt != NULL )
-    up( cpqfcHBAdata->notify_wt); // yep, we're outta here
+		// hopefully, no more "work" to do;
+		// re-enable our INTs for "normal" completion processing
+		enable_irq(dev->HostAdapter->irq);
+
+
+		dev->BoardLock = NULL;	// allow commands to be queued
+		CPQ_SPINUNLOCK_HBA(dev)
+
+		// Now, complete any Cmnd we Q'd up while BoardLock was held
+		CompleteBoardLockCmnd(dev);
+
+
+	}
+	// hopefully, the signal was for our module exit...
+	if (dev->notify_wt != NULL)
+		up(dev->notify_wt);	// yep, we're outta here
 }
 
 
 // Freeze Tachyon routine.
-// If Tachyon is already frozen, return FALSE
-// If Tachyon is not frozen, call freeze function, return TRUE
+// If Tachyon is already frozen, return 0
+// If Tachyon is not frozen, call freeze function, return 1
 //
-static BOOLEAN FreezeTach( CPQFCHBA *cpqfcHBAdata)
+static u8 FreezeTach(CPQFCHBA * dev)
 {
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  BOOLEAN FrozeTach = FALSE;
-  // It's possible that the chip is already frozen; if so,
-  // "Freezing" again will NOT! generate another Freeze
-  // Completion Message.
-
-  if( (fcChip->Registers.TYstatus.value & 0x70000) != 0x70000)
-  {  // (need to freeze...)
-    fcChip->FreezeTachyon( fcChip, 2);  // both ERQ and FCP assists
-
-    // 2. Get Tach freeze confirmation
-    // (synchronize SEST manipulation with Freeze Completion Message)
-    // we need INTs on so semaphore can be set.	
-    enable_irq( cpqfcHBAdata->HostAdapter->irq); // only way to get Semaphore
-    down_interruptible( cpqfcHBAdata->TachFrozen); // wait for INT handler sem.
-    // can we TIMEOUT semaphore wait?? TBD
-    disable_irq( cpqfcHBAdata->HostAdapter->irq); 
-
-    FrozeTach = TRUE;
-  }  // (else, already frozen)
- 
-  return FrozeTach;
-}  
-
-
-
+	PTACHYON fcChip = &dev->fcChip;
+	u8 FrozeTach = 0;
+	// It's possible that the chip is already frozen; if so,
+	// "Freezing" again will NOT! generate another Freeze
+	// Completion Message.
+
+	if ((fcChip->Registers.TYstatus.value & 0x70000) != 0x70000) {	// (need to freeze...)
+		fcChip->FreezeTachyon(fcChip, 2);	// both ERQ and FCP assists
+		// 2. Get Tach freeze confirmation
+		// (synchronize SEST manipulation with Freeze Completion Message)
+		// we need INTs on so semaphore can be set. 
+		enable_irq(dev->HostAdapter->irq);	// only way to get Semaphore
+		down_interruptible(dev->TachFrozen);	// wait for INT handler sem.
+		// can we TIMEOUT semaphore wait?? TBD
+		disable_irq(dev->HostAdapter->irq);
+		FrozeTach = 1;
+	}			// (else, already frozen)
+	return FrozeTach;
+}
 
 // This is the kernel worker thread task, which processes FC
 // tasks which were queued by the Interrupt handler or by
 // other WorkTask functions.
 
 #define DBG 1
+
 //#undef DBG
-void cpqfcTS_WorkTask( struct Scsi_Host *HostAdapter)
+void cpqfcTS_WorkTask(struct Scsi_Host *shpnt)
 {
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  ULONG QconsumerNdx;
-  LONG ExchangeID;
-  ULONG ulStatus=0;
-  TachFCHDR_GCMND fchs;
-  PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
-
-  ENTER("WorkTask");
-
-  // copy current index to work on
-  QconsumerNdx = fcLQ->consumer;
-
-  PCI_TRACEO( fcLQ->Qitem[QconsumerNdx].Type, 0x90)
-  
-
-  // NOTE: when this switch completes, we will "consume" the Que item
-//  printk("Que type %Xh\n", fcLQ->Qitem[QconsumerNdx].Type);
-  switch( fcLQ->Qitem[QconsumerNdx].Type )
-  {
-      // incoming frame - link service (ACC, UNSOL REQ, etc.)
-      // or FCP-SCSI command
-    case SFQ_UNKNOWN:  
-      AnalyzeIncomingFrame( cpqfcHBAdata, QconsumerNdx );
+	CPQFCHBA *dev = (CPQFCHBA *) shpnt->hostdata;
+	PTACHYON fcChip = &dev->fcChip;
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	u32 QconsumerNdx;
+	s32 ExchangeID;
+	u32 ulStatus = 0;
+	TachFCHDR_GCMND fchs;
+	PFC_LINK_QUE fcLQ = dev->fcLQ;
+
+	ENTER("WorkTask");
+
+	// copy current index to work on
+	QconsumerNdx = fcLQ->consumer;
+
+	PCI_TRACEO(fcLQ->Qitem[QconsumerNdx].Type, 0x90)
+
+	// NOTE: when this switch completes, we will "consume" the Que item
+	//  printk("Que type %Xh\n", fcLQ->Qitem[QconsumerNdx].Type);
+	switch (fcLQ->Qitem[QconsumerNdx].Type) 
+	{
+		// incoming frame - link service (ACC, UNSOL REQ, etc.)
+		// or FCP-SCSI command
+	case SFQ_UNKNOWN:
+		AnalyzeIncomingFrame(dev, QconsumerNdx);
+		break;
 
-      break;
-  
-    
-    
-    case EXCHANGE_QUEUED:  // an Exchange (i.e. FCP-SCSI) was previously
-                           // Queued because the link was down.  The  
-                           // heartbeat timer detected it and Queued it here.
-                           // We attempt to start it again, and if
-                           // successful we clear the EXCHANGE_Q flag.
-                           // If the link doesn't come up, the Exchange
-                           // will eventually time-out.
-
-      ExchangeID = (LONG)  // x_ID copied from DPC timeout function
-                   fcLQ->Qitem[QconsumerNdx].ulBuff[0];
-
-      // It's possible that a Q'd exchange could have already
-      // been started by other logic (e.g. ABTS process)
-      // Don't start if already started (Q'd flag clear)
-
-      if( Exchanges->fcExchange[ExchangeID].status & EXCHANGE_QUEUED )
-      {
-//        printk(" *Start Q'd x_ID %Xh: type %Xh ", 
-//          ExchangeID, Exchanges->fcExchange[ExchangeID].type);
-      
-        ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID);
-        if( !ulStatus )
-        {
-//          printk("success* ");
-        }	
-        else
-        {
+	case EXCHANGE_QUEUED:	
+		// an Exchange (i.e. FCP-SCSI) was previously
+		// Queued because the link was down.  The  
+		// heartbeat timer detected it and Queued it here.
+		// We attempt to start it again, and if
+		// successful we clear the EXCHANGE_Q flag.
+		// If the link doesn't come up, the Exchange
+		// will eventually time-out.
+
+		ExchangeID = (s32) fcLQ->Qitem[QconsumerNdx].ulBuff[0]; // x_ID copied from DPC timeout function
+
+		// It's possible that a Q'd exchange could have already
+		// been started by other logic (e.g. ABTS process)
+		// Don't start if already started (Q'd flag clear)
+
+		if (Exchanges->fcExchange[ExchangeID].status & EXCHANGE_QUEUED) {
+//      		printk(" *Start Q'd x_ID %Xh: type %Xh ", 
+//				ExchangeID, Exchanges->fcExchange[ExchangeID].type);
+
+			ulStatus = cpqfcTSStartExchange(dev, ExchangeID);
+			if (!ulStatus) {
+//				printk("success* ");
+			} else {
 #ifdef DBG
-      
-          if( ulStatus == EXCHANGE_QUEUED)
-            printk("Queued* ");
-          else
-            printk("failed* ");
-		
+				if (ulStatus == EXCHANGE_QUEUED)
+					printk("Queued* ");
+				else
+					printk("failed* ");
 #endif
-	} 
-      }
-      break;
+			}
+		}
+		break;
 
+	case LINKDOWN:
+		// (lots of things already done in INT handler) future here?
+		break;
 
-    case LINKDOWN:  
-      // (lots of things already done in INT handler) future here?
-      break;
-    
-    
-    case LINKACTIVE:   // Tachyon set the Lup bit in FM status
-                       // NOTE: some misbehaving FC ports (like Tach2.1)
-                       // can re-LIP immediately after a LIP completes.
-      
-      // if "initiator", need to verify LOGs with ports
-//      printk("\n*LNKUP* ");
+	case LINKACTIVE:	// Tachyon set the Lup bit in FM status
+		// NOTE: some misbehaving FC ports (like Tach2.1)
+		// can re-LIP immediately after a LIP completes.
+		// if "initiator", need to verify LOGs with ports
+//		printk("\n*LNKUP* ");
+
+		if (fcChip->Options.initiator)
+			SendLogins(dev, NULL);	// PLOGI or PDISC, based on fcPort data
+		// if SendLogins successfully completes, PortDiscDone
+		// will be set.
+		// If SendLogins was successful, then we expect to get incoming
+		// ACCepts or REJECTs, which are handled below.
+		break;
 
-      if( fcChip->Options.initiator )
-        SendLogins( cpqfcHBAdata, NULL ); // PLOGI or PDISC, based on fcPort data
-                  // if SendLogins successfully completes, PortDiscDone
-                  // will be set.
-      
-      
-      // If SendLogins was successful, then we expect to get incoming
-      // ACCepts or REJECTs, which are handled below.
+		// LinkService and Fabric request/reply processing
+	case ELS_FDISC:	// need to send Fabric Discovery (Login)
+	case ELS_FLOGI:	// need to send Fabric Login
+	case ELS_SCR:		// need to send State Change Registration
+	case FCS_NSR:		// need to send Name Service Request
+	case ELS_PLOGI:	// need to send PLOGI
+	case ELS_ACC:		// send generic ACCept
+	case ELS_PLOGI_ACC:	// need to send ELS ACCept frame to recv'd PLOGI
+	case ELS_PRLI_ACC:	// need to send ELS ACCept frame to recv'd PRLI
+	case ELS_LOGO:		// need to send ELS LOGO (logout)
+	case ELS_LOGO_ACC:	// need to send ELS ACCept frame to recv'd PLOGI
+	case ELS_RJT:		// ReJecT reply
+	case ELS_PRLI:		// need to send ELS PRLI
+
+
+//		printk(" *ELS %Xh* ", fcLQ->Qitem[QconsumerNdx].Type);
+		// if PortDiscDone is not set, it means the SendLogins routine
+		// failed to complete -- assume that LDn occurred, so login frames
+		// are invalid
+		if (!dev->PortDiscDone)	// cleared by LDn
+		{
+			printk("Discard Q'd ELS login frame\n");
+			break;
+		}
 
-      break;
+		ulStatus = cpqfcTSBuildExchange(dev, fcLQ->Qitem[QconsumerNdx].Type,	// e.g. PLOGI
+						(TachFCHDR_GCMND *)
+						fcLQ->Qitem[QconsumerNdx].ulBuff,	// incoming fchs
+						NULL,	// no data (no scatter/gather list)
+						&ExchangeID);	// fcController->fcExchanges index, -1 if failed
+
+		if (!ulStatus)	// Exchange setup?
+		{
+			ulStatus = cpqfcTSStartExchange(dev, ExchangeID);
+			if (!ulStatus) {
+				// submitted to Tach's Outbound Que (ERQ PI incremented)
+				// waited for completion for ELS type (Login frames issued
+				// synchronously)
+			} else
+				// check reason for Exchange not being started - we might
+				// want to Queue and start later, or fail with error
+			{
 
-    // LinkService and Fabric request/reply processing
-    case ELS_FDISC:      // need to send Fabric Discovery (Login)
-    case ELS_FLOGI:      // need to send Fabric Login
-    case ELS_SCR:        // need to send State Change Registration
-    case FCS_NSR:        // need to send Name Service Request
-    case ELS_PLOGI:      // need to send PLOGI
-    case ELS_ACC:        // send generic ACCept
-    case ELS_PLOGI_ACC:  // need to send ELS ACCept frame to recv'd PLOGI
-    case ELS_PRLI_ACC:   // need to send ELS ACCept frame to recv'd PRLI
-    case ELS_LOGO:      // need to send ELS LOGO (logout)
-    case ELS_LOGO_ACC:  // need to send ELS ACCept frame to recv'd PLOGI
-    case ELS_RJT:         // ReJecT reply
-    case ELS_PRLI:       // need to send ELS PRLI
- 
-    
-//      printk(" *ELS %Xh* ", fcLQ->Qitem[QconsumerNdx].Type);
-      // if PortDiscDone is not set, it means the SendLogins routine
-      // failed to complete -- assume that LDn occurred, so login frames
-      // are invalid
-      if( !cpqfcHBAdata->PortDiscDone) // cleared by LDn
-      {
-        printk("Discard Q'd ELS login frame\n");
-        break;  
-      }
-
-      ulStatus = cpqfcTSBuildExchange(
-          cpqfcHBAdata,
-          fcLQ->Qitem[QconsumerNdx].Type, // e.g. PLOGI
-          (TachFCHDR_GCMND*)
-            fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs
-          NULL,         // no data (no scatter/gather list)
-          &ExchangeID );// fcController->fcExchanges index, -1 if failed
-
-      if( !ulStatus ) // Exchange setup?
-      {
-        ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
-        if( !ulStatus )
-        {
-          // submitted to Tach's Outbound Que (ERQ PI incremented)
-          // waited for completion for ELS type (Login frames issued
-          // synchronously)
-        }
-        else
-          // check reason for Exchange not being started - we might
-          // want to Queue and start later, or fail with error
-        {
-
-        }
-      }
-
-      else   // Xchange setup failed...
-        printk(" cpqfcTSBuildExchange failed: %Xh\n", ulStatus );
-
-      break;
-
-    case SCSI_REPORT_LUNS:
-      // pass the incoming frame (actually, it's a PRLI frame)
-      // so we can send REPORT_LUNS, in order to determine VSA/PDU
-      // FCP-SCSI Lun address mode
-      IssueReportLunsCommand( cpqfcHBAdata, (TachFCHDR_GCMND*)
-            fcLQ->Qitem[QconsumerNdx].ulBuff); 
+			}
+		}
 
-      break;
-      
+		else		// Xchange setup failed...
+			printk(" cpqfcTSBuildExchange failed: %Xh\n", ulStatus);
 
+		break;
 
+	case SCSI_REPORT_LUNS:
+		// pass the incoming frame (actually, it's a PRLI frame)
+		// so we can send REPORT_LUNS, in order to determine VSA/PDU
+		// FCP-SCSI Lun address mode
+		IssueReportLunsCommand(dev, (TachFCHDR_GCMND *)
+				       fcLQ->Qitem[QconsumerNdx].ulBuff);
 
-    case BLS_ABTS:       // need to ABORT one or more exchanges
-    {
-      LONG x_ID = fcLQ->Qitem[QconsumerNdx].ulBuff[0];
-      BOOLEAN FrozeTach = FALSE;   
-     
-      if( x_ID > TACH_SEST_LEN )  // (in)sanity check
-      {
-//	printk( " cpqfcTS ERROR! BOGUS x_ID %Xh", x_ID);
-	break;
-      }
-
-
-      if( Exchanges->fcExchange[ x_ID].Cmnd == NULL ) // should be RARE
-      {
-//	printk(" ABTS %Xh Scsi Cmnd null! ", x_ID);
-	
-       break;  // nothing to abort!
-      }
+		break;
 
+	case BLS_ABTS:		// need to ABORT one or more exchanges
+		{
+			s32 x_ID = fcLQ->Qitem[QconsumerNdx].ulBuff[0];
+			u8 FrozeTach = 0;
+
+			if (x_ID > TACH_SEST_LEN)	// (in)sanity check
+			{
+//				printk( " cpqfcTS ERROR! BOGUS x_ID %Xh", x_ID);
+				break;
+			}
+			if (Exchanges->fcExchange[x_ID].Cmnd == NULL)	// should be RARE
+			{
+//				printk(" ABTS %Xh Scsi Cmnd null! ", x_ID);
+				break;	// nothing to abort!
+			}
 //#define ABTS_DBG
 #ifdef ABTS_DBG
-      printk("INV SEST[%X] ", x_ID); 
-      if( Exchanges->fcExchange[x_ID].status & FC2_TIMEOUT)
-      {
-        printk("FC2TO");
-      }
-      if( Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT)
-      {
-        printk("IA");
-      }
-      if( Exchanges->fcExchange[x_ID].status & PORTID_CHANGED)
-      {
-        printk("PORTID");
-      }
-      if( Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED)
-      {
-        printk("DEVRM");
-      }
-      if( Exchanges->fcExchange[x_ID].status & LINKFAIL_TX)
-      {
-        printk("LKF");
-      }
-      if( Exchanges->fcExchange[x_ID].status & FRAME_TO)
-      {
-        printk("FRMTO");
-      }
-      if( Exchanges->fcExchange[x_ID].status & ABORTSEQ_NOTIFY)
-      {
-        printk("ABSQ");
-      }
-      if( Exchanges->fcExchange[x_ID].status & SFQ_FRAME)
-      {
-        printk("SFQFR");
-      }
-
-      if( Exchanges->fcExchange[ x_ID].type == 0x2000)
-        printk(" WR");
-      else if( Exchanges->fcExchange[ x_ID].type == 0x3000)
-        printk(" RD");
-      else if( Exchanges->fcExchange[ x_ID].type == 0x10)
-        printk(" ABTS");
-      else
-        printk(" %Xh", Exchanges->fcExchange[ x_ID].type); 
-
-      if( !(Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT))
-      {
-	printk(" Cmd %p, ", 
-          Exchanges->fcExchange[ x_ID].Cmnd);
-
-        printk(" brd/chn/trg/lun %d/%d/%d/%d port_id %06X\n", 
-          cpqfcHBAdata->HBAnum,
-          Exchanges->fcExchange[ x_ID].Cmnd->channel,
-          Exchanges->fcExchange[ x_ID].Cmnd->target,
-          Exchanges->fcExchange[ x_ID].Cmnd->lun,
-          Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF);
-      }
-      else  // assume that Cmnd ptr is invalid on _abort()
-      {
-	printk(" Cmd ptr invalid\n");
-      }
-     
-#endif      
-
-      
-      // Steps to ABORT a SEST exchange:
-      // 1. Freeze TL SCSI assists & ERQ (everything)
-      // 2. Receive FROZEN inbound CM (must succeed!)
-      // 3. Invalidate x_ID SEST entry 
-      // 4. Resume TL SCSI assists & ERQ (everything)
-      // 5. Build/start on exchange - change "type" to BLS_ABTS,
-      //    timeout to X sec (RA_TOV from PLDA is actually 0)
-      // 6. Set Exchange Q'd status if ABTS cannot be started,
-      //    or simply complete Exchange in "Terminate" condition
-
-  PCI_TRACEO( x_ID, 0xB4)
-      
-      // 1 & 2 . Freeze Tach & get confirmation of freeze
-      FrozeTach = FreezeTach( cpqfcHBAdata);
-
-      // 3. OK, Tachyon is frozen, so we can invalidate SEST exchange.
-      // FC2_TIMEOUT means we are originating the abort, while
-      // TARGET_ABORT means we are ACCepting an abort.
-      // LINKFAIL_TX, ABORTSEQ_NOFITY, INV_ENTRY or FRAME_TO are 
-      // all from Tachyon:
-      // Exchange was corrupted by LDn or other FC physical failure
-      // INITIATOR_ABORT means the upper layer driver/application
-      // requested the abort.
-
-
-	  
-      // clear bit 31 (VALid), to invalidate & take control from TL
-      fcChip->SEST->u[ x_ID].IWE.Hdr_Len &= 0x7FFFFFFF;
-
-
-      // examine and Tach's "Linked List" for IWEs that 
-      // received (nearly) simultaneous transfer ready (XRDY) 
-      // repair linked list if necessary (TBD!)
-      // (If we ignore the "Linked List", we will time out
-      // WRITE commands where we received the FCP-SCSI XFRDY
-      // frame (because Tachyon didn't processes it).  Linked List
-      // management should be done as an optimization.
-
-//       readl( fcChip->Registers.ReMapMemBase+TL_MEM_SEST_LINKED_LIST ));
-
-
-      
-
-      // 4. Resume all Tachlite functions (for other open Exchanges)
-      // as quickly as possible to allow other exchanges to other ports
-      // to resume.  Freezing Tachyon may cause cascading errors, because
-      // any received SEST frame cannot be processed by the SEST.
-      // Don't "unfreeze" unless Link is operational
-      if( FrozeTach )  // did we just freeze it (above)?
-        fcChip->UnFreezeTachyon( fcChip, 2);  // both ERQ and FCP assists
-      
-
-  PCI_TRACEO( x_ID, 0xB4)
-
-      // Note there is no confirmation that the chip is "unfrozen".  Also,
-      // if the Link is down when unfreeze is called, it has no effect.
-      // Chip will unfreeze when the Link is back up.
-
-      // 5. Now send out Abort commands if possible
-      // Some Aborts can't be "sent" (Port_id changed or gone);
-      // if the device is gone, there is no port_id to send the ABTS to.
-
-      if( !(Exchanges->fcExchange[ x_ID].status & PORTID_CHANGED)
-			  &&
-          !(Exchanges->fcExchange[ x_ID].status & DEVICE_REMOVED) )
-      {
-        Exchanges->fcExchange[ x_ID].type = BLS_ABTS;
-        fchs.s_id = Exchanges->fcExchange[ x_ID].fchs.d_id;
-        ulStatus = cpqfcTSBuildExchange(
-          cpqfcHBAdata,
-          BLS_ABTS,
-          &fchs,        // (uses only s_id)
-          NULL,         // (no scatter/gather list for ABTS)
-          &x_ID );// ABTS on this Exchange ID
-
-        if( !ulStatus ) // Exchange setup build OK?
-        {
-
-            // ABTS may be needed because an Exchange was corrupted
-            // by a Link disruption.  If the Link is UP, we can
-	    // presume that this ABTS can start immediately; otherwise,
-	    // set Que'd status so the Login functions
-            // can restart it when the FC physical Link is restored
-          if( ((fcChip->Registers.FMstatus.value &0xF0) &0x80)) // loop init?
-          {			    
-//                printk(" *set Q status x_ID %Xh on LDn* ", x_ID);
-                Exchanges->fcExchange[ x_ID].status |= EXCHANGE_QUEUED;
-          }
-
-          else  // what FC device (port_id) does the Cmd belong to?
-          {
-            PFC_LOGGEDIN_PORT pLoggedInPort = 
-              Exchanges->fcExchange[ x_ID].pLoggedInPort;
-            
-            // if Port is logged in, we might start the abort.
-	
-            if( (pLoggedInPort != NULL) 
-			      &&
-                (pLoggedInPort->prli == TRUE) ) 
-            {
-              // it's possible that an Exchange has already been Queued
-              // to start after Login completes.  Check and don't
-	      // start it (again) here if Q'd status set
-//	    printk(" ABTS xchg %Xh ", x_ID);            
- 	      if( Exchanges->fcExchange[x_ID].status & EXCHANGE_QUEUED)
-	      {
-//		    printk("already Q'd ");
-	      }
-	      else
-	      {
-//	            printk("starting ");
-		
-                fcChip->fcStats.FC2aborted++; 
-                ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, x_ID );
-                if( !ulStatus )
-                {
-                    // OK
-                    // submitted to Tach's Outbound Que (ERQ PI incremented)
-                }
-                else
-                {
-/*                   printk("ABTS exchange start failed -status %Xh, x_ID %Xh ",
-                        ulStatus, x_ID);
-*/
-                } 
-	      }
-	    }
-	    else
-	    {
-/*         	  printk(" ABTS NOT starting xchg %Xh, %p ",
-			       x_ID, pLoggedInPort);
-	          if( pLoggedInPort )
-	            printk("prli %d ", pLoggedInPort->prli);
-*/
-	    }		
- 	  }
-        }
-        else  // what the #@!
-        {  // how do we fail to build an Exchange for ABTS??
-              printk("ABTS exchange build failed -status %Xh, x_ID %Xh\n",
-                ulStatus, x_ID);
-        }
-      }
-      else   // abort without ABTS -- just complete exchange/Cmnd to Linux
-      {
-//            printk(" *Terminating x_ID %Xh on %Xh* ", 
-//		    x_ID, Exchanges->fcExchange[x_ID].status);
-        cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, x_ID);
-
-      }
-    } // end of ABTS case
-      break;
-
-
-
-    case BLS_ABTS_ACC:   // need to ACCept one ABTS
-                         // (NOTE! this code not updated for Linux yet..)
-      
-
-      printk(" *ABTS_ACC* ");
-      // 1. Freeze TL
-
-      fcChip->FreezeTachyon( fcChip, 2);  // both ERQ and FCP assists
+			printk("INV SEST[%X] ", x_ID);
+			if (Exchanges->fcExchange[x_ID].status & FC2_TIMEOUT) {
+				printk("FC2TO");
+			}
+			if (Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT) {
+				printk("IA");
+			}
+			if (Exchanges->fcExchange[x_ID].status & PORTID_CHANGED) {
+				printk("PORTID");
+			}
+			if (Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED) {
+				printk("DEVRM");
+			}
+			if (Exchanges->fcExchange[x_ID].status & LINKFAIL_TX) {
+				printk("LKF");
+			}
+			if (Exchanges->fcExchange[x_ID].status & FRAME_TO) {
+				printk("FRMTO");
+			}
+			if (Exchanges->fcExchange[x_ID].status & ABORTSEQ_NOTIFY) {
+				printk("ABSQ");
+			}
+			if (Exchanges->fcExchange[x_ID].status & SFQ_FRAME) {
+				printk("SFQFR");
+			}
 
-      memcpy(  // copy the incoming ABTS frame
-        &fchs,
-        fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs
-        sizeof( fchs));
-
-      // 3. OK, Tachyon is frozen so we can invalidate SEST entry 
-      // (if necessary)
-      // Status FC2_TIMEOUT means we are originating the abort, while
-      // TARGET_ABORT means we are ACCepting an abort
-      
-      ExchangeID = fchs.ox_rx_id & 0x7FFF; // RX_ID for exchange
-//      printk("ABTS ACC for Target ExchangeID %Xh\n", ExchangeID);
+			if (Exchanges->fcExchange[x_ID].type == 0x2000)
+				printk(" WR");
+			else if (Exchanges->fcExchange[x_ID].type == 0x3000)
+				printk(" RD");
+			else if (Exchanges->fcExchange[x_ID].type == 0x10)
+				printk(" ABTS");
+			else
+				printk(" %Xh", Exchanges->fcExchange[x_ID].type);
+
+			if (!(Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT)) {
+				printk(" Cmd %p, ", Exchanges->fcExchange[x_ID].Cmnd);
+
+				printk(" brd/chn/trg/lun %d/%d/%d/%d port_id %06X\n",
+				       dev->HBAnum, Exchanges->fcExchange[x_ID].Cmnd->channel, Exchanges->fcExchange[x_ID].Cmnd->target, Exchanges->fcExchange[x_ID].Cmnd->lun, Exchanges->fcExchange[x_ID].fchs.d_id & 0xFFFFFF);
+			} else	// assume that Cmnd ptr is invalid on _abort()
+			{
+				printk(" Cmd ptr invalid\n");
+			}
+#endif
+			// Steps to ABORT a SEST exchange:
+			// 1. Freeze TL SCSI assists & ERQ (everything)
+			// 2. Receive FROZEN inbound CM (must succeed!)
+			// 3. Invalidate x_ID SEST entry 
+			// 4. Resume TL SCSI assists & ERQ (everything)
+			// 5. Build/start on exchange - change "type" to BLS_ABTS,
+			//    timeout to X sec (RA_TOV from PLDA is actually 0)
+			// 6. Set Exchange Q'd status if ABTS cannot be started,
+			//    or simply complete Exchange in "Terminate" condition
+
+			PCI_TRACEO(x_ID, 0xB4)
+			    // 1 & 2 . Freeze Tach & get confirmation of freeze
+			    FrozeTach = FreezeTach(dev);
+
+			// 3. OK, Tachyon is frozen, so we can invalidate SEST exchange.
+			// FC2_TIMEOUT means we are originating the abort, while
+			// TARGET_ABORT means we are ACCepting an abort.
+			// LINKFAIL_TX, ABORTSEQ_NOFITY, INV_ENTRY or FRAME_TO are 
+			// all from Tachyon:
+			// Exchange was corrupted by LDn or other FC physical failure
+			// INITIATOR_ABORT means the upper layer driver/application
+			// requested the abort.
+
+			// clear bit 31 (VALid), to invalidate & take control from TL
+			fcChip->SEST->u[x_ID].IWE.Hdr_Len &= 0x7FFFFFFF;
+
+			// examine and Tach's "Linked List" for IWEs that 
+			// received (nearly) simultaneous transfer ready (XRDY) 
+			// repair linked list if necessary (TBD!)
+			// (If we ignore the "Linked List", we will time out
+			// WRITE commands where we received the FCP-SCSI XFRDY
+			// frame (because Tachyon didn't processes it).  Linked List
+			// management should be done as an optimization.
+
+//			readl( fcChip->Registers.ReMapMemBase+TL_MEM_SEST_LINKED_LIST ));
+
+			// 4. Resume all Tachlite functions (for other open Exchanges)
+			// as quickly as possible to allow other exchanges to other ports
+			// to resume.  Freezing Tachyon may cause cascading errors, because
+			// any received SEST frame cannot be processed by the SEST.
+			// Don't "unfreeze" unless Link is operational
+			if (FrozeTach)	// did we just freeze it (above)?
+				fcChip->UnFreezeTachyon(fcChip, 2);	// both ERQ and FCP assists
+
+			PCI_TRACEO(x_ID, 0xB4)
+			    // Note there is no confirmation that the chip is "unfrozen".  Also,
+			    // if the Link is down when unfreeze is called, it has no effect.
+			    // Chip will unfreeze when the Link is back up.
+			    // 5. Now send out Abort commands if possible
+			    // Some Aborts can't be "sent" (Port_id changed or gone);
+			    // if the device is gone, there is no port_id to send the ABTS to.
+			if (!(Exchanges->fcExchange[x_ID].status & PORTID_CHANGED)
+				&& !(Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED)) {
+				Exchanges->fcExchange[x_ID].type = BLS_ABTS;
+				fchs.s_id = Exchanges->fcExchange[x_ID].fchs.d_id;
+				ulStatus = cpqfcTSBuildExchange(dev, BLS_ABTS, &fchs,	// (uses only s_id)
+								NULL,	// (no scatter/gather list for ABTS)
+								&x_ID);	// ABTS on this Exchange ID
+
+				if (!ulStatus)	// Exchange setup build OK?
+				{
+
+					// ABTS may be needed because an Exchange was corrupted
+					// by a Link disruption.  If the Link is UP, we can
+					// presume that this ABTS can start immediately; otherwise,
+					// set Que'd status so the Login functions
+					// can restart it when the FC physical Link is restored
+					if (((fcChip->Registers.FMstatus.value & 0xF0) & 0x80))	// loop init?
+					{
+//						printk(" *set Q status x_ID %Xh on LDn* ", x_ID);
+						Exchanges->fcExchange[x_ID].status |= EXCHANGE_QUEUED;
+					}
+
+					else	// what FC device (port_id) does the Cmd belong to?
+					{
+						PFC_LOGGEDIN_PORT pLoggedInPort = Exchanges->fcExchange[x_ID].pLoggedInPort;
+
+						// if Port is logged in, we might start the abort.
+
+						if ((pLoggedInPort != NULL)
+						    && (pLoggedInPort->prli == 1)) {
+							// it's possible that an Exchange has already been Queued
+							// to start after Login completes.  Check and don't
+							// start it (again) here if Q'd status set
+//							printk(" ABTS xchg %Xh ", x_ID);            
+							if (Exchanges->fcExchange[x_ID].status & EXCHANGE_QUEUED) {
+//								printk("already Q'd ");
+							} else {
+//								printk("starting ");
+								fcChip->fcStats.FC2aborted++;
+								ulStatus = cpqfcTSStartExchange(dev, x_ID);
+								if (!ulStatus) {
+									// OK
+									// submitted to Tach's Outbound Que (ERQ PI incremented)
+								} else {
+//									printk("ABTS exchange start failed -status %Xh, x_ID %Xh ", ulStatus, x_ID);
+								}
+							}
+						}
+					}
+				} else	// what the #@!
+				{	// how do we fail to build an Exchange for ABTS??
+					printk("ABTS exchange build failed -status %Xh, x_ID %Xh\n", ulStatus, x_ID);
+				}
+			} else	// abort without ABTS -- just complete exchange/Cmnd to Linux
+			{
+//				printk(" *Terminating x_ID %Xh on %Xh* ", 
+//					x_ID, Exchanges->fcExchange[x_ID].status);
+				cpqfcTSCompleteExchange(dev->PciDev, fcChip, x_ID);
 
+			}
+		}		// end of ABTS case
+		break;
 
-      // sanity check on received ExchangeID
-      if( Exchanges->fcExchange[ ExchangeID].status == TARGET_ABORT )
-      {
-          // clear bit 31 (VALid), to invalidate & take control from TL
-//          printk("Invalidating SEST exchange %Xh\n", ExchangeID);
-          fcChip->SEST->u[ ExchangeID].IWE.Hdr_Len &= 0x7FFFFFFF;
-      }
-
-
-      // 4. Resume all Tachlite functions (for other open Exchanges)
-      // as quickly as possible to allow other exchanges to other ports
-      // to resume.  Freezing Tachyon for too long may royally screw
-      // up everything!
-      fcChip->UnFreezeTachyon( fcChip, 2);  // both ERQ and FCP assists
-      
-      // Note there is no confirmation that the chip is "unfrozen".  Also,
-      // if the Link is down when unfreeze is called, it has no effect.
-      // Chip will unfreeze when the Link is back up.
+	case BLS_ABTS_ACC:	// need to ACCept one ABTS
+		// (NOTE! this code not updated for Linux yet..)
+		printk(" *ABTS_ACC* ");
+		// 1. Freeze TL
+
+		fcChip->FreezeTachyon(fcChip, 2);	// both ERQ and FCP assists
+		memcpy(		// copy the incoming ABTS frame
+			      &fchs, fcLQ->Qitem[QconsumerNdx].ulBuff,	// incoming fchs
+			      sizeof(fchs));
+
+		// 3. OK, Tachyon is frozen so we can invalidate SEST entry 
+		// (if necessary)
+		// Status FC2_TIMEOUT means we are originating the abort, while
+		// TARGET_ABORT means we are ACCepting an abort
+
+		ExchangeID = fchs.ox_rx_id & 0x7FFF;	// RX_ID for exchange
+//		printk("ABTS ACC for Target ExchangeID %Xh\n", ExchangeID);
+
+		// sanity check on received ExchangeID
+		if (Exchanges->fcExchange[ExchangeID].status == TARGET_ABORT) {
+			// clear bit 31 (VALid), to invalidate & take control from TL
+//			printk("Invalidating SEST exchange %Xh\n", ExchangeID);
+			fcChip->SEST->u[ExchangeID].IWE.Hdr_Len &= 0x7FFFFFFF;
+		}
 
-      // 5. Now send out Abort ACC reply for this exchange
-      Exchanges->fcExchange[ ExchangeID].type = BLS_ABTS_ACC;
-      
-      fchs.s_id = Exchanges->fcExchange[ ExchangeID].fchs.d_id;
-      ulStatus = cpqfcTSBuildExchange(
-            cpqfcHBAdata,
-            BLS_ABTS_ACC,
-            &fchs,
-            NULL,         // no data (no scatter/gather list)
-            &ExchangeID );// fcController->fcExchanges index, -1 if failed
-
-      if( !ulStatus ) // Exchange setup?
-      {
-        ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
-        if( !ulStatus )
-        {
-          // submitted to Tach's Outbound Que (ERQ PI incremented)
-          // waited for completion for ELS type (Login frames issued
-          // synchronously)
-        }
-        else
-          // check reason for Exchange not being started - we might
-          // want to Queue and start later, or fail with error
-        {
-
-        } 
-      }
-      break;
-
-
-    case BLS_ABTS_RJT:   // need to ReJecT one ABTS; reject implies the
-                         // exchange doesn't exist in the TARGET context.
-                         // ExchangeID has to come from LinkService space.
-
-      printk(" *ABTS_RJT* ");
-      ulStatus = cpqfcTSBuildExchange(
-            cpqfcHBAdata,
-            BLS_ABTS_RJT,
-            (TachFCHDR_GCMND*)
-              fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs
-            NULL,         // no data (no scatter/gather list)
-            &ExchangeID );// fcController->fcExchanges index, -1 if failed
-
-      if( !ulStatus ) // Exchange setup OK?
-      {
-        ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
-        // If it fails, we aren't required to retry.
-      }
-      if( ulStatus )
-      {
-        printk("Failed to send BLS_RJT for ABTS, X_ID %Xh\n", ExchangeID);
-      }
-      else
-      {
-        printk("Sent BLS_RJT for ABTS, X_ID %Xh\n", ExchangeID);
-      
-      }
+		// 4. Resume all Tachlite functions (for other open Exchanges)
+		// as quickly as possible to allow other exchanges to other ports
+		// to resume.  Freezing Tachyon for too long may royally screw
+		// up everything!
+		fcChip->UnFreezeTachyon(fcChip, 2);	// both ERQ and FCP assists
+
+		// Note there is no confirmation that the chip is "unfrozen".  Also,
+		// if the Link is down when unfreeze is called, it has no effect.
+		// Chip will unfreeze when the Link is back up.
+
+		// 5. Now send out Abort ACC reply for this exchange
+		Exchanges->fcExchange[ExchangeID].type = BLS_ABTS_ACC;
+
+		fchs.s_id = Exchanges->fcExchange[ExchangeID].fchs.d_id;
+		ulStatus = cpqfcTSBuildExchange(dev, BLS_ABTS_ACC, &fchs, NULL,	// no data (no scatter/gather list)
+						&ExchangeID);	// fcController->fcExchanges index, -1 if failed
+
+		if (!ulStatus)	// Exchange setup?
+		{
+			ulStatus = cpqfcTSStartExchange(dev, ExchangeID);
+			if (!ulStatus) {
+				// submitted to Tach's Outbound Que (ERQ PI incremented)
+				// waited for completion for ELS type (Login frames issued
+				// synchronously)
+			} else
+				// check reason for Exchange not being started - we might
+				// want to Queue and start later, or fail with error
+			{
 
-      break;
+			}
+		}
+		break;
 
+	case BLS_ABTS_RJT:	// need to ReJecT one ABTS; reject implies the
+		// exchange doesn't exist in the TARGET context.
+		// ExchangeID has to come from LinkService space.
+
+		printk(" *ABTS_RJT* ");
+		ulStatus = cpqfcTSBuildExchange(dev, BLS_ABTS_RJT, (TachFCHDR_GCMND *)
+						fcLQ->Qitem[QconsumerNdx].ulBuff,	// incoming fchs
+						NULL,	// no data (no scatter/gather list)
+						&ExchangeID);	// fcController->fcExchanges index, -1 if failed
+
+		if (!ulStatus)	// Exchange setup OK?
+		{
+			ulStatus = cpqfcTSStartExchange(dev, ExchangeID);
+			// If it fails, we aren't required to retry.
+		}
+		if (ulStatus) {
+			printk("Failed to send BLS_RJT for ABTS, X_ID %Xh\n", ExchangeID);
+		} else {
+			printk("Sent BLS_RJT for ABTS, X_ID %Xh\n", ExchangeID);
 
+		}
+		break;
 
-    default:
-      break;
-  }                   // end switch
-//doNothing:
-    // done with this item - now set the NEXT index
+	default:
+		break;
+	}			// end switch
+	// done with this item - now set the NEXT index
 
-  if( QconsumerNdx+1 >= FC_LINKQ_DEPTH ) // rollover test
-  {
-    fcLQ->consumer = 0;
-  }
-  else
-  { 
-    fcLQ->consumer++;
-  }
+	if (QconsumerNdx + 1 >= FC_LINKQ_DEPTH)	// rollover test
+		fcLQ->consumer = 0;
+	else
+		fcLQ->consumer++;
 
-  PCI_TRACEO( fcLQ->Qitem[QconsumerNdx].Type, 0x94)
+	PCI_TRACEO(fcLQ->Qitem[QconsumerNdx].Type, 0x94)
 
-  LEAVE("WorkTask");
-  return;
+	LEAVE("WorkTask");
+	return;
 }
 
 
@@ -845,115 +700,89 @@
 // This circular Q works like Tachyon's que - the producer points to the next
 // (unused) entry.  Called by Interrupt handler, WorkerThread, Timer
 // sputlinkq
-void cpqfcTSPutLinkQue( CPQFCHBA *cpqfcHBAdata,
-  int Type, 
-  void *QueContent)
-{
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-//  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
-  ULONG ndx;
-  
-  ENTER("cpqfcTSPutLinkQ");
-
-  ndx = fcLQ->producer;
-  
-  ndx += 1;  // test for Que full
-
-
-  
-  if( ndx >= FC_LINKQ_DEPTH ) // rollover test
-    ndx = 0;
+void cpqfcTSPutLinkQue(CPQFCHBA * dev, int Type, void *QueContent)
+{
+	PTACHYON fcChip = &dev->fcChip;
+//	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	PFC_LINK_QUE fcLQ = dev->fcLQ;
+	u32 ndx;
 
-  if( ndx == fcLQ->consumer )   // QUE full test
-  {
-                       // QUE was full! lost LK command (fatal to logic)
-    fcChip->fcStats.lnkQueFull++;
+	ENTER("cpqfcTSPutLinkQ");
 
-    printk("*LinkQ Full!*");
-    TriggerHBA( fcChip->Registers.ReMapMemBase, 1);
-/*
-    {
-      int i;
-      printk("LinkQ PI %d, CI %d\n", fcLQ->producer,
-        fcLQ->consumer);
-		      
-      for( i=0; i< FC_LINKQ_DEPTH; )
-      {
-	printk(" [%d]%Xh ", i, fcLQ->Qitem[i].Type);
-	if( (++i %8) == 0) printk("\n");
-      }
-  
-    }
-*/    
-    printk( "cpqfcTS: WARNING!! PutLinkQue - FULL!\n"); // we're hung
-  }
-  else                        // QUE next element
-  {
-    // Prevent certain multiple (back-to-back) requests.
-    // This is important in that we don't want to issue multiple
-    // ABTS for the same Exchange, or do multiple FM inits, etc.
-    // We can never be sure of the timing of events reported to
-    // us by Tach's IMQ, which can depend on system/bus speeds,
-    // FC physical link circumstances, etc.
-     
-    if( (fcLQ->producer != fcLQ->consumer)
-	    && 
-        (Type == FMINIT)  )
-    {
-      LONG lastNdx;  // compute previous producer index
-      if( fcLQ->producer)
-        lastNdx = fcLQ->producer- 1;
-      else
-	lastNdx = FC_LINKQ_DEPTH-1;
+	ndx = fcLQ->producer;
 
+	ndx += 1;		// test for Que full
 
-      if( fcLQ->Qitem[lastNdx].Type == FMINIT)
-      {
-//        printk(" *skip FMINIT Q post* ");
-//        goto DoneWithPutQ;
-      }
 
-    }
 
-    // OK, add the Q'd item...
-    
-    fcLQ->Qitem[fcLQ->producer].Type = Type;
-   
-    memcpy(
-        fcLQ->Qitem[fcLQ->producer].ulBuff,
-        QueContent, 
-        sizeof(fcLQ->Qitem[fcLQ->producer].ulBuff));
+	if (ndx >= FC_LINKQ_DEPTH)	// rollover test
+		ndx = 0;
 
-    fcLQ->producer = ndx;  // increment Que producer
+	if (ndx == fcLQ->consumer)	// QUE full test
+	{
+		// QUE was full! lost LK command (fatal to logic)
+		fcChip->fcStats.lnkQueFull++;
 
-    // set semaphore to wake up Kernel (worker) thread
-    // 
-    up( cpqfcHBAdata->fcQueReady );
-  }
+		printk("*LinkQ Full!*");
+		TriggerHBA(fcChip->Registers.ReMapMemBase, 1);
+/*
+		{
+			int i;
+			printk("LinkQ PI %d, CI %d\n", fcLQ->producer, fcLQ->consumer);
+		      
+			for( i=0; i< FC_LINKQ_DEPTH; )
+			{
+				printk(" [%d]%Xh ", i, fcLQ->Qitem[i].Type);
+				if( (++i %8) == 0)
+					printk("\n");
+			}
+		}
+*/
+		printk("cpqfcTS: WARNING!! PutLinkQue - FULL!\n");	// we're hung
+	}
+	else			// QUE next element
+	{
+		// Prevent certain multiple (back-to-back) requests.
+		// This is important in that we don't want to issue multiple
+		// ABTS for the same Exchange, or do multiple FM inits, etc.
+		// We can never be sure of the timing of events reported to
+		// us by Tach's IMQ, which can depend on system/bus speeds,
+		// FC physical link circumstances, etc.
+
+		if ((fcLQ->producer != fcLQ->consumer)
+		    && (Type == FMINIT)) {
+			s32 lastNdx;	// compute previous producer index
+			if (fcLQ->producer)
+				lastNdx = fcLQ->producer - 1;
+			else
+				lastNdx = FC_LINKQ_DEPTH - 1;
+
+
+			if (fcLQ->Qitem[lastNdx].Type == FMINIT) {
+//      			printk(" *skip FMINIT Q post* ");
+//        			goto DoneWithPutQ;
+			}
 
+		}
+		// OK, add the Q'd item...
+		fcLQ->Qitem[fcLQ->producer].Type = Type;
+		memcpy(fcLQ->Qitem[fcLQ->producer].ulBuff, QueContent, sizeof(fcLQ->Qitem[fcLQ->producer].ulBuff));
+		fcLQ->producer = ndx;	// increment Que producer
+		// set semaphore to wake up Kernel (worker) thread
+		up(dev->fcQueReady);
+	}
 //DoneWithPutQ:
-
-  LEAVE("cpqfcTSPutLinkQ");
+	LEAVE("cpqfcTSPutLinkQ");
 }
 
-
-
-
 // reset device ext FC link Q
-void cpqfcTSLinkQReset( CPQFCHBA *cpqfcHBAdata)
-   
+void cpqfcTSLinkQReset(CPQFCHBA * dev)
 {
-  PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
-  fcLQ->producer = 0;
-  fcLQ->consumer = 0;
-
+	PFC_LINK_QUE fcLQ = dev->fcLQ;
+	fcLQ->producer = 0;
+	fcLQ->consumer = 0;
 }
 
-
-
-
-
 // When Tachyon gets an unassisted FCP-SCSI frame, post here so
 // an arbitrary context thread (e.g. IOCTL loopback test function)
 // can process it.
@@ -961,17 +790,15 @@
 // (NOTE: Not revised for Linux)
 // This Q works like Tachyon's que - the producer points to the next
 // (unused) entry.
-void cpqfcTSPutScsiQue( CPQFCHBA *cpqfcHBAdata,
-  int Type, 
-  void *QueContent)
+void cpqfcTSPutScsiQue(CPQFCHBA * dev, int Type, void *QueContent)
 {
-//  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
-//  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+//  CPQFCHBA *dev = (CPQFCHBA *)shpnt->hostdata;
+//  PTACHYON fcChip = &dev->fcChip;
 
-//  ULONG ndx;
+//  u32 ndx;
 
-//  ULONG *pExchangeID;
-//  LONG ExchangeID;
+//  u32 *pExchangeID;
+//  s32 ExchangeID;
 
 /*
   KeAcquireSpinLockAtDpcLevel( &pDevExt->fcScsiQueLock);
@@ -999,7 +826,7 @@
       // copied an FCP response frame into a buffer pointed to by the SEST
       // entry.  That buffer is allocated in the SEST structure at ->RspHDR.
       // Copy the RspHDR for use by the Que handler.
-      pExchangeID = (ULONG *)QueContent;
+      pExchangeID = (u32 *)QueContent;
       
       memcpy(
 	      pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].ulBuff,
@@ -1020,175 +847,127 @@
 
     KeSetEvent( &pDevExt->TYIBscsi,  // signal any waiting thread
        0,                    // no priority boost
-		   FALSE );              // no waiting later for this event
+		   0 );              // no waiting later for this event
   }
   KeReleaseSpinLockFromDpcLevel( &pDevExt->fcScsiQueLock);
 */
 }
 
+static void ProcessELS_Request(CPQFCHBA *, TachFCHDR_GCMND *);
+static void ProcessELS_Reply(CPQFCHBA *, TachFCHDR_GCMND *);
+static void ProcessFCS_Reply(CPQFCHBA *, TachFCHDR_GCMND *);
 
-
-
-
-
-
-static void ProcessELS_Request( CPQFCHBA*,TachFCHDR_GCMND*);
-
-static void ProcessELS_Reply( CPQFCHBA*,TachFCHDR_GCMND*);
-
-static void ProcessFCS_Reply( CPQFCHBA*,TachFCHDR_GCMND*);
-
-void cpqfcTSImplicitLogout( CPQFCHBA* cpqfcHBAdata,
-		PFC_LOGGEDIN_PORT pFcPort)
+void cpqfcTSImplicitLogout(CPQFCHBA * dev, PFC_LOGGEDIN_PORT pFcPort)
 {
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+	PTACHYON fcChip = &dev->fcChip;
 
-  if( pFcPort->port_id != 0xFFFC01 ) // don't care about Fabric
-  {
-    fcChip->fcStats.logouts++;
-    printk("cpqfcTS: Implicit logout of WWN %08X%08X, port_id %06X\n", 
-        (ULONG)pFcPort->u.liWWN,
-        (ULONG)(pFcPort->u.liWWN >>32),
-	pFcPort->port_id);
-
-  // Terminate I/O with this (Linux) Scsi target
-    cpqfcTSTerminateExchange( cpqfcHBAdata, 
-                            &pFcPort->ScsiNexus,
-	                    DEVICE_REMOVED);
-  }
-			
-  // Do an "implicit logout" - we can't really Logout the device
-  // (i.e. with LOGOut Request) because of port_id confusion
-  // (i.e. the Other port has no port_id).
-  // A new login for that WWN will have to re-write port_id (0 invalid)
-  pFcPort->port_id = 0;  // invalid!
-  pFcPort->pdisc = FALSE;
-  pFcPort->prli = FALSE;
-  pFcPort->plogi = FALSE;
-  pFcPort->flogi = FALSE;
-  pFcPort->LOGO_timer = 0;
-  pFcPort->device_blocked = TRUE; // block Scsi Requests
-  pFcPort->ScsiNexus.VolumeSetAddressing=0;	
+	if (pFcPort->port_id != 0xFFFC01)	// don't care about Fabric
+	{
+		fcChip->fcStats.logouts++;
+		printk("cpqfcTS: Implicit logout of WWN %08X%08X, port_id %06X\n", (u32) pFcPort->u.liWWN, (u32) (pFcPort->u.liWWN >> 32), pFcPort->port_id);
+
+		// Terminate I/O with this (Linux) Scsi target
+		cpqfcTSTerminateExchange(dev, &pFcPort->ScsiNexus, DEVICE_REMOVED);
+	}
+	// Do an "implicit logout" - we can't really Logout the device
+	// (i.e. with LOGOut Request) because of port_id confusion
+	// (i.e. the Other port has no port_id).
+	// A new login for that WWN will have to re-write port_id (0 invalid)
+	pFcPort->port_id = 0;	// invalid!
+	pFcPort->pdisc = 0;
+	pFcPort->prli = 0;
+	pFcPort->plogi = 0;
+	pFcPort->flogi = 0;
+	pFcPort->LOGO_timer = 0;
+	pFcPort->device_blocked = 1;	// block Scsi Requests
+	pFcPort->ScsiNexus.VolumeSetAddressing = 0;
 }
 
-  
+
 // On FC-AL, there is a chance that a previously known device can
 // be quietly removed (e.g. with non-managed hub), 
 // while a NEW device (with different WWN) took the same alpa or
 // even 24-bit port_id.  This chance is unlikely but we must always
 // check for it.
-static void TestDuplicatePortId( CPQFCHBA* cpqfcHBAdata,
-		PFC_LOGGEDIN_PORT pLoggedInPort)
+
+static void TestDuplicatePortId(CPQFCHBA * dev, PFC_LOGGEDIN_PORT pLoggedInPort)
 {
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  // set "other port" at beginning of fcPorts list
-  PFC_LOGGEDIN_PORT pOtherPortWithPortId = fcChip->fcPorts.pNextPort;
-  while( pOtherPortWithPortId ) 
-  {
-    if( (pOtherPortWithPortId->port_id == 
-         pLoggedInPort->port_id) 
-		    &&
-         (pOtherPortWithPortId != pLoggedInPort) )
-    {
-      // trouble!  (Implicitly) Log the other guy out
-      printk(" *port_id %Xh is duplicated!* ", 
-        pOtherPortWithPortId->port_id);
-      cpqfcTSImplicitLogout( cpqfcHBAdata, pOtherPortWithPortId); 
-   }
-    pOtherPortWithPortId = pOtherPortWithPortId->pNextPort;
-  }
+	PTACHYON fcChip = &dev->fcChip;
+	// set "other port" at beginning of fcPorts list
+	PFC_LOGGEDIN_PORT pOtherPortWithPortId = fcChip->fcPorts.pNextPort;
+	while (pOtherPortWithPortId) {
+		if ((pOtherPortWithPortId->port_id == pLoggedInPort->port_id)
+		    && (pOtherPortWithPortId != pLoggedInPort)) {
+			// trouble!  (Implicitly) Log the other guy out
+			printk(" *port_id %Xh is duplicated!* ", pOtherPortWithPortId->port_id);
+			cpqfcTSImplicitLogout(dev, pOtherPortWithPortId);
+		}
+		pOtherPortWithPortId = pOtherPortWithPortId->pNextPort;
+	}
 }
 
-
-
-
-
-
 // Dynamic Memory Allocation for newly discovered FC Ports.
 // For simplicity, maintain fcPorts structs for ALL
 // for discovered devices, including those we never do I/O with
 // (e.g. Fabric addresses)
 
-static PFC_LOGGEDIN_PORT CreateFcPort( 
-	  CPQFCHBA* cpqfcHBAdata, 
-	  PFC_LOGGEDIN_PORT pLastLoggedInPort, 
-	  TachFCHDR_GCMND* fchs,
-	  LOGIN_PAYLOAD* plogi)
-{
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  PFC_LOGGEDIN_PORT pNextLoggedInPort = NULL;
-  int i;
-
-
-  printk("cpqfcTS: New FC port %06Xh WWN: ", fchs->s_id);
-  for( i=3; i>=0; i--)   // copy the LOGIN port's WWN
-    printk("%02X", plogi->port_name[i]);
-  for( i=7; i>3; i--)   // copy the LOGIN port's WWN
-    printk("%02X", plogi->port_name[i]);
-
-
-  // allocate mem for new port
-  // (these are small and rare allocations...)
-  pNextLoggedInPort = kmalloc( sizeof( FC_LOGGEDIN_PORT), GFP_ATOMIC );
-
-    
-  // allocation succeeded?  Fill out NEW PORT
-  if( pNextLoggedInPort )
-  {    
-                              // clear out any garbage (sometimes exists)
-    memset( pNextLoggedInPort, 0, sizeof( FC_LOGGEDIN_PORT));
-
-
-    // If we login to a Fabric, we don't want to treat it
-    // as a SCSI device...
-    if( (fchs->s_id & 0xFFF000) != 0xFFF000)
-    {
-      int i;
-      
-      // create a unique "virtual" SCSI Nexus (for now, just a
-      // new target ID) -- we will update channel/target on REPORT_LUNS
-      // special case for very first SCSI target...
-      if( cpqfcHBAdata->HostAdapter->max_id == 0)
-      {
-        pNextLoggedInPort->ScsiNexus.target = 0;
-        fcChip->fcPorts.ScsiNexus.target = -1; // don't use "stub"
-      }
-      else
-      {
-        pNextLoggedInPort->ScsiNexus.target =
-          cpqfcHBAdata->HostAdapter->max_id;
-      }
-
-      // initialize the lun[] Nexus struct for lun masking      
-      for( i=0; i< CPQFCTS_MAX_LUN; i++)
-        pNextLoggedInPort->ScsiNexus.lun[i] = 0xFF; // init to NOT USED
-      
-      pNextLoggedInPort->ScsiNexus.channel = 0; // cpqfcTS has 1 FC port
-      
-      printk(" SCSI Chan/Trgt %d/%d", 
-          pNextLoggedInPort->ScsiNexus.channel,
-          pNextLoggedInPort->ScsiNexus.target);
- 
-      // tell Scsi layers about the new target...
-      cpqfcHBAdata->HostAdapter->max_id++; 
-//    printk("HostAdapter->max_id = %d\n",
-//      cpqfcHBAdata->HostAdapter->max_id);		    
-    }                          
-    else
-    {
-      // device is NOT SCSI (in case of Fabric)
-      pNextLoggedInPort->ScsiNexus.target = -1;  // invalid
-    }
+static PFC_LOGGEDIN_PORT CreateFcPort(CPQFCHBA * dev, PFC_LOGGEDIN_PORT pLastLoggedInPort, TachFCHDR_GCMND * fchs, LOGIN_PAYLOAD * plogi)
+{
+	PTACHYON fcChip = &dev->fcChip;
+	PFC_LOGGEDIN_PORT pNextLoggedInPort = NULL;
+	int i;
+
+	printk("cpqfcTS: New FC port %06Xh WWN: ", fchs->s_id);
+	for (i = 3; i >= 0; i--)	// copy the LOGIN port's WWN
+		printk("%02X", plogi->port_name[i]);
+	for (i = 7; i > 3; i--)	// copy the LOGIN port's WWN
+		printk("%02X", plogi->port_name[i]);
+
+	// allocate mem for new port
+	// (these are small and rare allocations...)
+	pNextLoggedInPort = kmalloc(sizeof(FC_LOGGEDIN_PORT), GFP_ATOMIC);
+
+	// allocation succeeded?  Fill out NEW PORT
+	if (pNextLoggedInPort) {
+		// clear out any garbage (sometimes exists)
+		memset(pNextLoggedInPort, 0, sizeof(FC_LOGGEDIN_PORT));
+		// If we login to a Fabric, we don't want to treat it
+		// as a SCSI device...
+		if ((fchs->s_id & 0xFFF000) != 0xFFF000) {
+			int i;
+
+			// create a unique "virtual" SCSI Nexus (for now, just a
+			// new target ID) -- we will update channel/target on REPORT_LUNS
+			// special case for very first SCSI target...
+			if (dev->HostAdapter->max_id == 0) {
+				pNextLoggedInPort->ScsiNexus.target = 0;
+				fcChip->fcPorts.ScsiNexus.target = -1;	// don't use "stub"
+			} else {
+				pNextLoggedInPort->ScsiNexus.target = dev->HostAdapter->max_id;
+			}
 
-	  // create forward link to new port
-    pLastLoggedInPort->pNextPort = pNextLoggedInPort;
-    printk("\n");
-
-  }     
-  return pNextLoggedInPort;  // NULL on allocation failure
-}   // end NEW PORT (WWN) logic
+			// initialize the lun[] Nexus struct for lun masking      
+			for (i = 0; i < CPQFCTS_MAX_LUN; i++)
+				pNextLoggedInPort->ScsiNexus.lun[i] = 0xFF;	// init to NOT USED
+
+			pNextLoggedInPort->ScsiNexus.channel = 0;	// cpqfcTS has 1 FC port
+			printk(" SCSI Chan/Trgt %d/%d", pNextLoggedInPort->ScsiNexus.channel, pNextLoggedInPort->ScsiNexus.target);
+			// tell Scsi layers about the new target...
+			dev->HostAdapter->max_id++;
+//			printk("HostAdapter->max_id = %d\n",
+//				dev->HostAdapter->max_id);                 
+		} else {
+			// device is NOT SCSI (in case of Fabric)
+			pNextLoggedInPort->ScsiNexus.target = -1;	// invalid
+		}
 
+		// create forward link to new port
+		pLastLoggedInPort->pNextPort = pNextLoggedInPort;
+		printk("\n");
 
+	}
+	return pNextLoggedInPort;	// NULL on allocation failure
+}				// end NEW PORT (WWN) logic
 
 // For certain cases, we want to terminate exchanges without
 // sending ABTS to the device.  Examples include when an FC
@@ -1200,870 +979,620 @@
 // Since we must ensure that Tachyon is not operating on the
 // exchange, we have to freeze the chip
 // sterminateex
-void cpqfcTSTerminateExchange( 
-  CPQFCHBA* cpqfcHBAdata, SCSI_NEXUS *ScsiNexus, int TerminateStatus)
+
+void cpqfcTSTerminateExchange(CPQFCHBA * dev, SCSI_NEXUS * ScsiNexus, int TerminateStatus)
 {
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  ULONG x_ID;
+	PTACHYON fcChip = &dev->fcChip;
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	u32 x_ID;
+
+	if (ScsiNexus) {
+//		printk("TerminateExchange: ScsiNexus chan/target %d/%d\n",
+//			ScsiNexus->channel, ScsiNexus->target);
+	}
+	for (x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++) {
+		if (Exchanges->fcExchange[x_ID].type)	// in use?
+		{
+			if (ScsiNexus == NULL)	// our HBA changed - term. all
+			{
+				Exchanges->fcExchange[x_ID].status = TerminateStatus;
+				cpqfcTSPutLinkQue(dev, BLS_ABTS, &x_ID);
+			} else {
+				// If a device, according to WWN, has been removed, it's
+				// port_id may be used by another working device, so we
+				// have to terminate by SCSI target, NOT port_id.
+				if (Exchanges->fcExchange[x_ID].Cmnd)	// Cmnd in progress?
+				{
+					if ((Exchanges->fcExchange[x_ID].Cmnd->target == ScsiNexus->target)
+					    && (Exchanges->fcExchange[x_ID].Cmnd->channel == ScsiNexus->channel)) {
+						Exchanges->fcExchange[x_ID].status = TerminateStatus;
+						cpqfcTSPutLinkQue(dev, BLS_ABTS, &x_ID);	// timed-out
+					}
+				}
+				// (in case we ever need it...)
+				// all SEST structures have a remote node ID at SEST DWORD 2
+				//          if( (fcChip->SEST->u[ x_ID ].TWE.Remote_Node_ID >> 8)
+				//                ==  port_id)
+			}
+		}
+	}
+}
 
-  if( ScsiNexus )
-  {
-//    printk("TerminateExchange: ScsiNexus chan/target %d/%d\n",
-//		    ScsiNexus->channel, ScsiNexus->target);
+static void ProcessELS_Request(CPQFCHBA * dev, TachFCHDR_GCMND * fchs)
+{
+	PTACHYON fcChip = &dev->fcChip;
+//	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+//	u32 ox_id = (fchs->ox_rx_id >>16);
+	PFC_LOGGEDIN_PORT pLoggedInPort = NULL, pLastLoggedInPort;
+	u8 NeedReject = 0;
+	u32 ls_reject_code = 0;	// default don'n know??
 
-  } 
-  
-  for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
-  {
-    if( Exchanges->fcExchange[x_ID].type )  // in use?
-    {
-      if( ScsiNexus == NULL ) // our HBA changed - term. all
-      {
-	Exchanges->fcExchange[x_ID].status = TerminateStatus;
-        cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID ); 
-      }
-      else
-      {
-	// If a device, according to WWN, has been removed, it's
-	// port_id may be used by another working device, so we
-	// have to terminate by SCSI target, NOT port_id.
-        if( Exchanges->fcExchange[x_ID].Cmnd) // Cmnd in progress?
-	{	                 
-	  if( (Exchanges->fcExchange[x_ID].Cmnd->target == ScsiNexus->target)
-			&&
-            (Exchanges->fcExchange[x_ID].Cmnd->channel == ScsiNexus->channel)) 
-          {
-            Exchanges->fcExchange[x_ID].status = TerminateStatus;
-            cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID ); // timed-out
-          }
-	}
-
-	// (in case we ever need it...)
-	// all SEST structures have a remote node ID at SEST DWORD 2
-        //          if( (fcChip->SEST->u[ x_ID ].TWE.Remote_Node_ID >> 8)
-        //                ==  port_id)
-      } 
-    }
-  }
-}
 
+	// Check the incoming frame for a supported ELS type
+	switch (fchs->pl[0] & 0xFFFF) 
+	{
+	case 0x0050:	
+		//  PDISC?
+		// Payload for PLOGI and PDISC is identical (request & reply)
+		if (!verify_PLOGI(fcChip, fchs, &ls_reject_code))	// valid payload?
+		{
+			LOGIN_PAYLOAD logi;	// FC-PH Port Login
+
+			// PDISC payload OK. If critical login fields
+			// (e.g. WWN) matches last login for this port_id,
+			// we may resume any prior exchanges
+			// with the other port
+
+			BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & logi, sizeof(logi));
+
+			pLoggedInPort = fcFindLoggedInPort(fcChip, NULL,	// don't search Scsi Nexus
+							   0,	// don't search linked list for port_id
+							   &logi.port_name[0],	// search linked list for WWN
+							   &pLastLoggedInPort);	// must return non-NULL; when a port_id
+			// is not found, this pointer marks the
+			// end of the singly linked list
+
+			if (pLoggedInPort != NULL)	// WWN found (prior login OK)
+			{
+				if ((fchs->s_id & 0xFFFFFF) == pLoggedInPort->port_id) {
+					// Yes.  We were expecting PDISC?
+					if (pLoggedInPort->pdisc) {
+						// Yes; set fields accordingly.     (PDISC, not Originator)
+						SetLoginFields(pLoggedInPort, fchs, 1, 0);
+						// send 'ACC' reply 
+						cpqfcTSPutLinkQue(dev, ELS_PLOGI_ACC,	// (PDISC same as PLOGI ACC)
+								  fchs);
+						// OK to resume I/O...
+					} else {
+						printk("Not expecting PDISC (pdisc=0)\n");
+						NeedReject = 1;
+						// set reject reason code 
+						ls_reject_code = LS_RJT_REASON(PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
+					}
+				} else {
+					if (pLoggedInPort->port_id != 0) {
+						printk("PDISC PortID change: old %Xh, new %Xh\n", pLoggedInPort->port_id, fchs->s_id & 0xFFFFFF);
+					}
+					NeedReject = 1;
+					// set reject reason code 
+					ls_reject_code = LS_RJT_REASON(PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
+				}
+			} else {
+				printk("PDISC Request from unknown WWN\n");
+				NeedReject = 1;
+				// set reject reason code 
+				ls_reject_code = LS_RJT_REASON(LOGICAL_ERROR, INVALID_PORT_NAME);
+			}
 
-static void ProcessELS_Request( 
-              CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs)
-{
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-//  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-//  ULONG ox_id = (fchs->ox_rx_id >>16);
-  PFC_LOGGEDIN_PORT pLoggedInPort=NULL, pLastLoggedInPort;
-  BOOLEAN NeedReject = FALSE;
-  ULONG ls_reject_code = 0; // default don'n know??
+		}
+		else		// Payload unacceptable
+		{
+			printk("payload unacceptable\n");
+			NeedReject = 1;	// reject code already set
 
+		}
+		if (NeedReject) {
+			u32 port_id;
+			// The PDISC failed.  Set login struct flags accordingly,
+			// terminate any I/O to this port, and Q a PLOGI
+			if (pLoggedInPort) {
+				pLoggedInPort->pdisc = 0;
+				pLoggedInPort->prli = 0;
+				pLoggedInPort->plogi = 0;
+
+				cpqfcTSTerminateExchange(dev, &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
+				port_id = pLoggedInPort->port_id;
+			} else {
+				port_id = fchs->s_id & 0xFFFFFF;
+			}
+			fchs->reserved = ls_reject_code;	// borrow this (unused) field
+			cpqfcTSPutLinkQue(dev, ELS_RJT, fchs);
+		}
+		break;
 
-  // Check the incoming frame for a supported ELS type
-  switch( fchs->pl[0] & 0xFFFF)
-  {
-  case 0x0050: //  PDISC?
+	case 0x0003:
+		//  PLOGI?
+		// Payload for PLOGI and PDISC is identical (request & reply)
+		if (!verify_PLOGI(fcChip, fchs, &ls_reject_code))	// valid payload?
+		{
+			LOGIN_PAYLOAD logi;	// FC-PH Port Login
+			u8 NeedReject = 0;
+
+			// PDISC payload OK. If critical login fields
+			// (e.g. WWN) matches last login for this port_id,
+			// we may resume any prior exchanges
+			// with the other port
+
+			BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & logi, sizeof(logi));
+			pLoggedInPort = fcFindLoggedInPort(fcChip, NULL,	// don't search Scsi Nexus
+							   0,	// don't search linked list for port_id
+							   &logi.port_name[0],	// search linked list for WWN
+							   &pLastLoggedInPort);	// must return non-NULL; when a port_id
+			// is not found, this pointer marks the
+			// end of the singly linked list
+			if (pLoggedInPort == NULL)	// WWN not found -New Port
+			{
+				pLoggedInPort = CreateFcPort(dev, pLastLoggedInPort, fchs, &logi);
+				if (pLoggedInPort == NULL) {
+					printk(" cpqfcTS: New port allocation failed - lost FC device!\n");
+					// Now Q a LOGOut Request, since we won't be talking to that device
+					NeedReject = 1;
+					// set reject reason code 
+					ls_reject_code = LS_RJT_REASON(LOGICAL_ERROR, NO_LOGIN_RESOURCES);
+				}
+			}
+			if (!NeedReject) {
+				// OK - we have valid fcPort ptr; set fields accordingly.   
+				//                         (not PDISC, not Originator)
+				SetLoginFields(pLoggedInPort, fchs, 0, 0);
+				// send 'ACC' reply 
+				cpqfcTSPutLinkQue(dev, ELS_PLOGI_ACC,	// (PDISC same as PLOGI ACC)
+						  fchs);
+			}
+		}
+		else		// Payload unacceptable
+		{
+			printk("payload unacceptable\n");
+			NeedReject = 1;	// reject code already set
+		}
+		if (NeedReject) {
+			// The PDISC failed.  Set login struct flags accordingly,
+			// terminate any I/O to this port, and Q a PLOGI
+			pLoggedInPort->pdisc = 0;
+			pLoggedInPort->prli = 0;
+			pLoggedInPort->plogi = 0;
 
-    // Payload for PLOGI and PDISC is identical (request & reply)
-    if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) ) // valid payload?
-    {
-      LOGIN_PAYLOAD logi;       // FC-PH Port Login
-      
-      // PDISC payload OK. If critical login fields
-      // (e.g. WWN) matches last login for this port_id,
-      // we may resume any prior exchanges
-      // with the other port
+			fchs->reserved = ls_reject_code;	// borrow this (unused) field
 
-      
-      BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
-   
-      pLoggedInPort = fcFindLoggedInPort( 
-             fcChip, 
-	     NULL,     // don't search Scsi Nexus
-	     0,        // don't search linked list for port_id
-             &logi.port_name[0],     // search linked list for WWN
-             &pLastLoggedInPort);  // must return non-NULL; when a port_id
-                                   // is not found, this pointer marks the
-                                   // end of the singly linked list
-    
-      if( pLoggedInPort != NULL)   // WWN found (prior login OK)
-      { 
-           
- 	if( (fchs->s_id & 0xFFFFFF) == pLoggedInPort->port_id)
-	{
-          // Yes.  We were expecting PDISC?
-          if( pLoggedInPort->pdisc )
-	  {
-	    // Yes; set fields accordingly.     (PDISC, not Originator)
-            SetLoginFields( pLoggedInPort, fchs, TRUE, FALSE);
-       
-            // send 'ACC' reply 
-            cpqfcTSPutLinkQue( cpqfcHBAdata, 
-                          ELS_PLOGI_ACC, // (PDISC same as PLOGI ACC)
-                          fchs );
-
-	    // OK to resume I/O...
-	  }
-	  else
- 	  {
-	    printk("Not expecting PDISC (pdisc=FALSE)\n");
-	    NeedReject = TRUE;
-	    // set reject reason code 
-            ls_reject_code = 
-              LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
-	  }
-	}
-	else
-	{
-	  if( pLoggedInPort->port_id != 0)
-	  {
-  	    printk("PDISC PortID change: old %Xh, new %Xh\n",
-              pLoggedInPort->port_id, fchs->s_id &0xFFFFFF);
-	  }
-          NeedReject = TRUE;
-          // set reject reason code 
-          ls_reject_code = 
-	    LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
-		  
-	}
-      }
-      else
-      {
-	printk("PDISC Request from unknown WWN\n");
-        NeedReject = TRUE;
-          
-	// set reject reason code 
-        ls_reject_code = 
-          LS_RJT_REASON( LOGICAL_ERROR, INVALID_PORT_NAME);
-      }
+			// send 'RJT' reply 
+			cpqfcTSPutLinkQue(dev, ELS_RJT, fchs);
+		}
+		// terminate any exchanges with this device...
+		if (pLoggedInPort) {
+			cpqfcTSTerminateExchange(dev, &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
+		}
+		break;
 
-    }
-    else // Payload unacceptable
-    {
-      printk("payload unacceptable\n");
-      NeedReject = TRUE;  // reject code already set
-      
-    }
+	case 0x1020:		// PRLI?
+		{
+			u8 NeedReject = 1;
+			pLoggedInPort = fcFindLoggedInPort(fcChip, NULL,	// don't search Scsi Nexus
+							   (fchs->s_id & 0xFFFFFF),	// search linked list for port_id
+							   NULL,	// DON'T search linked list for WWN
+							   NULL);	// don't care
+
+			if (pLoggedInPort == NULL) {
+				// huh?
+				printk(" Unexpected PRLI Request -not logged in!\n");
+				// set reject reason code 
+				ls_reject_code = LS_RJT_REASON(PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
+				// Q a LOGOut here?
+			} else {
+				// verify the PRLI ACC payload
+				if (!verify_PRLI(fchs, &ls_reject_code)) {
+					// PRLI Reply is acceptable; were we expecting it?
+					if (pLoggedInPort->plogi) {
+						// yes, we expected the PRLI ACC  (not PDISC; not Originator)
+						SetLoginFields(pLoggedInPort, fchs, 0, 0);
+						// Q an ACCept Reply
+						cpqfcTSPutLinkQue(dev, ELS_PRLI_ACC, fchs);
+						NeedReject = 0;
+					} else {
+						// huh?
+						printk(" (unexpected) PRLI REQEST with plogi 0\n");
+						// set reject reason code 
+						ls_reject_code = LS_RJT_REASON(PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
+						// Q a LOGOut here?
+					}
+				} else {
+					printk(" PRLI REQUEST payload failed verify\n");
+					// (reject code set by "verify")
+					// Q a LOGOut here?
+				}
+			}
 
-    if( NeedReject)
-    {
-      ULONG port_id;
-      // The PDISC failed.  Set login struct flags accordingly,
-      // terminate any I/O to this port, and Q a PLOGI
-      if( pLoggedInPort )
-      {
-        pLoggedInPort->pdisc = FALSE;
-        pLoggedInPort->prli = FALSE;
-        pLoggedInPort->plogi = FALSE;
-	
-        cpqfcTSTerminateExchange( cpqfcHBAdata, 
-          &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
-	port_id = pLoggedInPort->port_id;
-      }
-      else
-      {
-	port_id = fchs->s_id &0xFFFFFF;
-      }
-      fchs->reserved = ls_reject_code; // borrow this (unused) field
-      cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_RJT, fchs );
-    }
-   
-    break;
+			if (NeedReject) {
+				// Q a ReJecT Reply with reason code
+				fchs->reserved = ls_reject_code;
+				cpqfcTSPutLinkQue(dev, ELS_RJT,	// Q Type
+						  fchs);
+			}
+		}
+		break;
 
+	case 0x0005:		// LOGOut?
+		{
+			// was this LOGOUT because we sent a ELS_PDISC to an FC device
+			// with changed (or new) port_id, or does the port refuse 
+			// to communicate to us?
+			// We maintain a logout counter - if we get 3 consecutive LOGOuts,
+			// give up!
+			LOGOUT_PAYLOAD logo;
+			u8 GiveUpOnDevice = 0;
+			u32 ls_reject_code = 0;
+
+			BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & logo, sizeof(logo));
+			pLoggedInPort = fcFindLoggedInPort(fcChip, NULL,	// don't search Scsi Nexus
+							   0,	// don't search linked list for port_id
+							   &logo.port_name[0],	// search linked list for WWN
+							   NULL);	// don't care about end of list
+
+			if (pLoggedInPort)	// found the device?
+			{
+				// Q an ACC reply 
+				cpqfcTSPutLinkQue(dev, ELS_LOGO_ACC,	// Q Type
+						  fchs);	// device to respond to
+				// set login struct fields (LOGO_counter increment)
+				SetLoginFields(pLoggedInPort, fchs, 0, 0);
+				// are we an Initiator?
+				if (fcChip->Options.initiator) {
+					// we're an Initiator, so check if we should 
+					// try (another?) login
+					// Fabrics routinely log out from us after
+					// getting device info - don't try to log them
+					// back in.
+					if ((fchs->s_id & 0xFFF000) == 0xFFF000) {
+						;	// do nothing
+					} else if (pLoggedInPort->LOGO_counter <= 3) {
+						// try (another) login (PLOGI request)
+						cpqfcTSPutLinkQue(dev, ELS_PLOGI,	// Q Type
+								  fchs);
+						// Terminate I/O with "retry" potential
+						cpqfcTSTerminateExchange(dev, &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
+					} else {
+						printk(" Got 3 LOGOuts - terminating comm. with port_id %Xh\n", fchs->s_id && 0xFFFFFF);
+						GiveUpOnDevice = 1;
+					}
+				} else {
+					GiveUpOnDevice = 1;
+				}
+
+				if (GiveUpOnDevice == 1) {
+					cpqfcTSTerminateExchange(dev, &pLoggedInPort->ScsiNexus, DEVICE_REMOVED);
+				}
+			} else	// we don't know this WWN!
+			{
+				// Q a ReJecT Reply with reason code
+				fchs->reserved = ls_reject_code;
+				cpqfcTSPutLinkQue(dev, ELS_RJT,	// Q Type
+						  fchs);
+			}
+		}
+		break;
 
+			// FABRIC only case
+	case 0x0461:	// ELS RSCN (Registered State Change Notification)?
+		{
+			int Ports;
+			int i;
+			__u32 Buff;
+			// Typically, one or more devices have been added to or dropped
+			// from the Fabric.
+			// The format of this frame is defined in FC-FLA (Rev 2.7, Aug 1997)
+			// The first 32-bit word has a 2-byte Payload Length, which
+			// includes the 4 bytes of the first word.  Consequently,
+			// this PL len must never be less than 4, must be a multiple of 4,
+			// and has a specified max value 256.
+			// (Endianess!)
+			Ports = ((fchs->pl[0] >> 24) - 4) / 4;
+			Ports = Ports > 63 ? 63 : Ports;
+
+			printk(" RSCN ports: %d\n", Ports);
+			if (Ports <= 0)	// huh?
+			{
+				// ReJecT the command
+				fchs->reserved = LS_RJT_REASON(UNABLE_TO_PERFORM, 0);
+
+				cpqfcTSPutLinkQue(dev, ELS_RJT,	// Q Type
+						  fchs);
+
+				break;
+			} else	// Accept the command
+			{
+				cpqfcTSPutLinkQue(dev, ELS_ACC,	// Q Type
+						  fchs);
+			}
 
-  case 0x0003: //  PLOGI?
+			// Check the "address format" to determine action.
+			// We have 3 cases:
+			// 0 = Port Address; 24-bit address of affected device
+			// 1 = Area Address; MS 16 bits valid
+			// 2 = Domain Address; MS 8 bits valid
+			for (i = 0; i < Ports; i++) {
+				BigEndianSwap((u8 *) & fchs->pl[i + 1], (u8 *) & Buff, 4);
+				switch (Buff & 0xFF000000) {
+				case 0:	// Port Address?
+				case 0x01000000:	// Area Domain?
+				case 0x02000000:	// Domain Address
+					// For example, "port_id" 0x201300 
+					// OK, let's try a Name Service Request (Query)
+					fchs->s_id = 0xFFFFFC;	// Name Server Address
+					cpqfcTSPutLinkQue(dev, FCS_NSR, fchs);
+					break;
+				default:	// huh? new value on version change?
+					break;
+				}
+			}
+		}
+		break;
+	default:
+		// don't support this request (yet)
+		// set reject reason code 
+		fchs->reserved = LS_RJT_REASON(UNABLE_TO_PERFORM, REQUEST_NOT_SUPPORTED);
+		cpqfcTSPutLinkQue(dev, ELS_RJT,	fchs);	// Q Type
+		break;
+	}
+}
 
-    // Payload for PLOGI and PDISC is identical (request & reply)
-    if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) ) // valid payload?
-    {
-      LOGIN_PAYLOAD logi;       // FC-PH Port Login
-      BOOLEAN NeedReject = FALSE;
-      
-      // PDISC payload OK. If critical login fields
-      // (e.g. WWN) matches last login for this port_id,
-      // we may resume any prior exchanges
-      // with the other port
 
-      
-      BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
-   
-      pLoggedInPort = fcFindLoggedInPort( 
-             fcChip, 
-	     NULL,       // don't search Scsi Nexus
-	     0,        // don't search linked list for port_id
-             &logi.port_name[0],     // search linked list for WWN
-             &pLastLoggedInPort);  // must return non-NULL; when a port_id
-                                   // is not found, this pointer marks the
-                                   // end of the singly linked list
-    
-      if( pLoggedInPort == NULL)   // WWN not found -New Port
-      { 
-      	pLoggedInPort = CreateFcPort( 
-			  cpqfcHBAdata, 
-			  pLastLoggedInPort, 
-			  fchs,
-			  &logi);
-        if( pLoggedInPort == NULL )
-        {
-          printk(" cpqfcTS: New port allocation failed - lost FC device!\n");
-          // Now Q a LOGOut Request, since we won't be talking to that device
-	
-          NeedReject = TRUE;  
-	  
-          // set reject reason code 
-          ls_reject_code = 
-            LS_RJT_REASON( LOGICAL_ERROR, NO_LOGIN_RESOURCES);
-	    
+static void ProcessELS_Reply(CPQFCHBA * dev, TachFCHDR_GCMND * fchs)
+{
+	PTACHYON fcChip = &dev->fcChip;
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	u32 ox_id = (fchs->ox_rx_id >> 16);
+	u32 ls_reject_code;
+	PFC_LOGGEDIN_PORT pLoggedInPort, pLastLoggedInPort;
+
+	// If this is a valid reply, then we MUST have sent a request.
+	// Verify that we can find a valid request OX_ID corresponding to
+	// this reply
+
+	if (Exchanges->fcExchange[(fchs->ox_rx_id >> 16)].type == 0) {
+		printk(" *Discarding ACC/RJT frame, xID %04X/%04X* ", ox_id, fchs->ox_rx_id & 0xffff);
+		goto Quit;	// exit this routine
 	}
-      }
-      if( !NeedReject )
-      {
-      
-        // OK - we have valid fcPort ptr; set fields accordingly.   
-	//                         (not PDISC, not Originator)
-        SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE); 
-
-        // send 'ACC' reply 
-        cpqfcTSPutLinkQue( cpqfcHBAdata, 
-                      ELS_PLOGI_ACC, // (PDISC same as PLOGI ACC)
-                      fchs );
-      }
-    }
-    else // Payload unacceptable
-    {
-      printk("payload unacceptable\n");
-      NeedReject = TRUE;  // reject code already set
-    }
 
-    if( NeedReject)
-    {
-      // The PDISC failed.  Set login struct flags accordingly,
-      // terminate any I/O to this port, and Q a PLOGI
-      pLoggedInPort->pdisc = FALSE;
-      pLoggedInPort->prli = FALSE;
-      pLoggedInPort->plogi = FALSE;
-	
-      fchs->reserved = ls_reject_code; // borrow this (unused) field
+	// Is the reply a RJT (reject)?
+	if ((fchs->pl[0] & 0xFFFFL) == 0x01)	// Reject reply?
+	{
+		//  ******  REJECT REPLY  ********
+		switch (Exchanges->fcExchange[ox_id].type) {
+		case ELS_FDISC:	// we sent out Fabric Discovery
+		case ELS_FLOGI:	// we sent out FLOGI
+			printk("RJT received on Fabric Login from %Xh, reason %Xh\n", fchs->s_id, fchs->pl[1]);
+			break;
+		default:
+			break;
+		}
+		goto Done;
+	}
+	// OK, we have an ACCept...
+	// What's the ACC type? (according to what we sent)
+	switch (Exchanges->fcExchange[ox_id].type) {
+	case ELS_PLOGI:	// we sent out PLOGI
+		if (!verify_PLOGI(fcChip, fchs, &ls_reject_code)) {
+			LOGIN_PAYLOAD logi;	// FC-PH Port Login
+			// login ACC payload acceptable; search for WWN in our list
+			// of fcPorts
+			BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & logi, sizeof(logi));
+			pLoggedInPort = fcFindLoggedInPort(fcChip, NULL,	// don't search Scsi Nexus
+						   0,	// don't search linked list for port_id
+						   &logi.port_name[0],	// search linked list for WWN
+						   &pLastLoggedInPort);	// must return non-NULL; when a port_id
+			// is not found, this pointer marks the
+			// end of the singly linked list
+			if (pLoggedInPort == NULL)	// WWN not found - new port
+			{
+				pLoggedInPort = CreateFcPort(dev, pLastLoggedInPort, fchs, &logi);
+				if (pLoggedInPort == NULL) {
+					printk(" cpqfcTS: New port allocation failed - lost FC device!\n");
+					// Now Q a LOGOut Request, since we won't be talking to that device
+					goto Done;	// exit with error! dropped login frame
+				}
+			} else	// WWN was already known.  Ensure that any open
+				// exchanges for this WWN are terminated.
+				// NOTE: It's possible that a device can change its 
+				// 24-bit port_id after a Link init or Fabric change 
+				// (e.g. LIP or Fabric RSCN).  In that case, the old
+				// 24-bit port_id may be duplicated, or no longer exist.
+			{
+				cpqfcTSTerminateExchange(dev, &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
+			}
 
-      // send 'RJT' reply 
-      cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_RJT, fchs );
-    }
-   
-    // terminate any exchanges with this device...
-    if( pLoggedInPort )
-    {
-      cpqfcTSTerminateExchange( cpqfcHBAdata, 
-        &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
-    }
-    break;
+			// We have an fcPort struct - set fields accordingly
+			// not PDISC, originator 
+			SetLoginFields(pLoggedInPort, fchs, 0, 1);
+			// We just set a "port_id"; is it duplicated?
+			TestDuplicatePortId(dev, pLoggedInPort);
+			// For Fabric operation, we issued PLOGI to 0xFFFFFC
+			// so we can send SCR (State Change Registration) 
+			// Check for this special case...
+			if (fchs->s_id == 0xFFFFFC) {
+				// PLOGI ACC was a Fabric response... issue SCR
+				fchs->s_id = 0xFFFFFD;	// address for SCR
+				cpqfcTSPutLinkQue(dev, ELS_SCR, fchs);
+			}
+			else {
+				// Now we need a PRLI to enable FCP-SCSI operation
+				// set flags and Q up a ELS_PRLI
+				cpqfcTSPutLinkQue(dev, ELS_PRLI, fchs);
+			}
+		} else {
+			// login payload unacceptable - reason in ls_reject_code
+			// Q up a Logout Request
+			printk("Login Payload unacceptable\n");
+		}
+		break;
 
+		// PDISC logic very similar to PLOGI, except we never want
+		// to allocate mem for "new" port, and we set flags differently
+		// (might combine later with PLOGI logic for efficiency)  
+	case ELS_PDISC:	// we sent out PDISC
+		if (!verify_PLOGI(fcChip, fchs, &ls_reject_code)) {
+			LOGIN_PAYLOAD logi;	// FC-PH Port Login
+			u8 NeedLogin = 0;
+
+			// login payload acceptable; search for WWN in our list
+			// of (previously seen) fcPorts
+			BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & logi, sizeof(logi));
+
+			pLoggedInPort = fcFindLoggedInPort(fcChip, NULL,	// don't search Scsi Nexus
+							   0,	// don't search linked list for port_id
+							   &logi.port_name[0],	// search linked list for WWN
+							   &pLastLoggedInPort);	// must return non-NULL; when a port_id
+			// is not found, this pointer marks the
+			// end of the singly linked list
+			if (pLoggedInPort != NULL)	// WWN found?
+			{
+				// WWN has same port_id as last login?  (Of course, a properly
+				// working FC device should NEVER ACCept a PDISC if it's
+				// port_id changed, but check just in case...)
+				if ((fchs->s_id & 0xFFFFFF) == pLoggedInPort->port_id) {
+					// Yes.  We were expecting PDISC?
+					if (pLoggedInPort->pdisc) {
+						int i;
+
+
+						// PDISC expected -- set fields.  (PDISC, Originator)
+						SetLoginFields(pLoggedInPort, fchs, 1, 1);
+
+						// We are ready to resume FCP-SCSI to this device...
+						// Do we need to start anything that was Queued?
+
+						for (i = 0; i < TACH_SEST_LEN; i++) {
+							// see if any exchange for this PDISC'd port was queued
+							if (((fchs->s_id & 0xFFFFFF) == (Exchanges->fcExchange[i].fchs.d_id & 0xFFFFFF))
+							    && (Exchanges->fcExchange[i].status & EXCHANGE_QUEUED)) {
+								fchs->reserved = i;	// copy ExchangeID
+//						                printk(" *Q x_ID %Xh after PDISC* ",i);
+
+								cpqfcTSPutLinkQue(dev, EXCHANGE_QUEUED, fchs);
+							}
+						}
+						// Complete commands Q'd while we were waiting for Login
+						UnblockScsiDevice(dev->HostAdapter, pLoggedInPort);
+					} else {
+						printk("Not expecting PDISC (pdisc=0)\n");
+						NeedLogin = 1;
+					}
+				} else {
+					printk("PDISC PortID change: old %Xh, new %Xh\n", pLoggedInPort->port_id, fchs->s_id & 0xFFFFFF);
+					NeedLogin = 1;
+				}
+			} else {
+				printk("PDISC ACC from unknown WWN\n");
+				NeedLogin = 1;
+			}
 
+			if (NeedLogin) {
+				// The PDISC failed.  Set login struct flags accordingly,
+				// terminate any I/O to this port, and Q a PLOGI
+				if (pLoggedInPort)	// FC device previously known?
+				{
+					cpqfcTSPutLinkQue(dev, ELS_LOGO, fchs);	// Qtype has port_id to send to 
+					// There are a variety of error scenarios which can result
+					// in PDISC failure, so as a catchall, add the check for
+					// duplicate port_id.
+					TestDuplicatePortId(dev, pLoggedInPort);
+
+					// TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
+					pLoggedInPort->pdisc = 0;
+					pLoggedInPort->prli = 0;
+					pLoggedInPort->plogi = 0;
+
+					cpqfcTSTerminateExchange(dev, &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
+				}
+				cpqfcTSPutLinkQue(dev, ELS_PLOGI, fchs);
+			}
+		} else {
+			// login payload unacceptable - reason in ls_reject_code
+			// Q up a Logout Request
+			printk("ERROR: Login Payload unacceptable!\n");
 
-  case 0x1020:  // PRLI?
-  {
-    BOOLEAN NeedReject = TRUE;
-    pLoggedInPort = fcFindLoggedInPort( 
-           fcChip, 
-           NULL,       // don't search Scsi Nexus
-	   (fchs->s_id & 0xFFFFFF),  // search linked list for port_id
-           NULL,     // DON'T search linked list for WWN
-           NULL);    // don't care
-      
-    if( pLoggedInPort == NULL ) 
-    {
-      // huh?
-      printk(" Unexpected PRLI Request -not logged in!\n");
-
-      // set reject reason code 
-      ls_reject_code = LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
-      
-      // Q a LOGOut here?
-    }
-    else
-    {
-      // verify the PRLI ACC payload
-      if( !verify_PRLI( fchs, &ls_reject_code) )
-      {
-        // PRLI Reply is acceptable; were we expecting it?
-        if( pLoggedInPort->plogi ) 
-        { 
-  	  // yes, we expected the PRLI ACC  (not PDISC; not Originator)
-          SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE);
-
-          // Q an ACCept Reply
-	  cpqfcTSPutLinkQue( cpqfcHBAdata,
-                        ELS_PRLI_ACC, 
-                        fchs );   
-	  
-	  NeedReject = FALSE;
-	}
-        else
-        {
-          // huh?
-          printk(" (unexpected) PRLI REQEST with plogi FALSE\n");
-
-          // set reject reason code 
-          ls_reject_code = LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
-    
-    	  // Q a LOGOut here?
-	  
-        }
-      }
-      else
-      {
-        printk(" PRLI REQUEST payload failed verify\n");
-        // (reject code set by "verify")
-
-        // Q a LOGOut here?
-      }
-    }
-
-    if( NeedReject )
-    {
-      // Q a ReJecT Reply with reason code
-      fchs->reserved = ls_reject_code;
-      cpqfcTSPutLinkQue( cpqfcHBAdata,
-                    ELS_RJT, // Q Type
-                    fchs );  
-    }
-  }
-    break;
- 
-
-    
-
-  case  0x0005:  // LOGOut?
-  {
-  // was this LOGOUT because we sent a ELS_PDISC to an FC device
-  // with changed (or new) port_id, or does the port refuse 
-  // to communicate to us?
-  // We maintain a logout counter - if we get 3 consecutive LOGOuts,
-  // give up!
-    LOGOUT_PAYLOAD logo;
-    BOOLEAN GiveUpOnDevice = FALSE;
-    ULONG ls_reject_code = 0;
-    
-    BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logo, sizeof(logo));
-
-    pLoggedInPort = fcFindLoggedInPort( 
-           fcChip, 
-           NULL,     // don't search Scsi Nexus
-	   0,        // don't search linked list for port_id
-           &logo.port_name[0],     // search linked list for WWN
-           NULL);    // don't care about end of list
-    
-    if( pLoggedInPort ) // found the device?
-    {
-      // Q an ACC reply 
-      cpqfcTSPutLinkQue( cpqfcHBAdata,
-                    ELS_LOGO_ACC, // Q Type
-                    fchs );       // device to respond to
-
-      // set login struct fields (LOGO_counter increment)
-      SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE);
-      
-      // are we an Initiator?
-      if( fcChip->Options.initiator)  
-      {
-        // we're an Initiator, so check if we should 
-	// try (another?) login
-
-	// Fabrics routinely log out from us after
-	// getting device info - don't try to log them
-	// back in.
-	if( (fchs->s_id & 0xFFF000) == 0xFFF000 )
-	{
-	  ; // do nothing
-	}
-	else if( pLoggedInPort->LOGO_counter <= 3)
-	{
-	  // try (another) login (PLOGI request)
-	  
-          cpqfcTSPutLinkQue( cpqfcHBAdata,
-                    ELS_PLOGI, // Q Type
-                    fchs );  
-	
-	  // Terminate I/O with "retry" potential
-	  cpqfcTSTerminateExchange( cpqfcHBAdata, 
-			            &pLoggedInPort->ScsiNexus,
-				    PORTID_CHANGED);
-	}
-	else
-	{
-	  printk(" Got 3 LOGOuts - terminating comm. with port_id %Xh\n",
-			  fchs->s_id &&0xFFFFFF);
-	  GiveUpOnDevice = TRUE;
-	}
-      }
-      else
-      {
-	GiveUpOnDevice = TRUE;
-      }
-
-
-      if( GiveUpOnDevice == TRUE )
-      {
-        cpqfcTSTerminateExchange( cpqfcHBAdata, 
-	                          &pLoggedInPort->ScsiNexus,
-		                  DEVICE_REMOVED);
-      }
-    }  
-    else  // we don't know this WWN!
-    {
-      // Q a ReJecT Reply with reason code
-      fchs->reserved = ls_reject_code;
-      cpqfcTSPutLinkQue( cpqfcHBAdata,
-                    ELS_RJT, // Q Type
-                    fchs );  
-    }
-  }
-    break;
-
-
-
-
-  // FABRIC only case
-  case 0x0461:  // ELS RSCN (Registered State Change Notification)?
-  {
-    int Ports;
-    int i;
-    __u32 Buff;
-    // Typically, one or more devices have been added to or dropped
-    // from the Fabric.
-    // The format of this frame is defined in FC-FLA (Rev 2.7, Aug 1997)
-    // The first 32-bit word has a 2-byte Payload Length, which
-    // includes the 4 bytes of the first word.  Consequently,
-    // this PL len must never be less than 4, must be a multiple of 4,
-    // and has a specified max value 256.
-    // (Endianess!)
-    Ports = ((fchs->pl[0] >>24) - 4) / 4;
-    Ports = Ports > 63 ? 63 : Ports;
-    
-    printk(" RSCN ports: %d\n", Ports);
-    if( Ports <= 0 )  // huh?
-    {
-      // ReJecT the command
-      fchs->reserved = LS_RJT_REASON( UNABLE_TO_PERFORM, 0);
-    
-      cpqfcTSPutLinkQue( cpqfcHBAdata,
-                    ELS_RJT, // Q Type
-                    fchs ); 
-      
-      break;
-    }
-    else  // Accept the command
-    {
-       cpqfcTSPutLinkQue( cpqfcHBAdata,
-                    ELS_ACC, // Q Type
-                    fchs ); 
-    }
-    
-      // Check the "address format" to determine action.
-      // We have 3 cases:
-      // 0 = Port Address; 24-bit address of affected device
-      // 1 = Area Address; MS 16 bits valid
-      // 2 = Domain Address; MS 8 bits valid
-    for( i=0; i<Ports; i++)
-    { 
-      BigEndianSwap( (UCHAR*)&fchs->pl[i+1],(UCHAR*)&Buff, 4);
-      switch( Buff & 0xFF000000)
-      {
-
-      case 0:  // Port Address?
-	
-      case 0x01000000: // Area Domain?
-      case 0x02000000: // Domain Address
-        // For example, "port_id" 0x201300 
-	// OK, let's try a Name Service Request (Query)
-      fchs->s_id = 0xFFFFFC;  // Name Server Address
-      cpqfcTSPutLinkQue( cpqfcHBAdata, FCS_NSR, fchs);
-
-      break;
-	
-	
-      default:  // huh? new value on version change?
-      break;
-      }
-    }
-  }    
-  break;    
-
-
-
-    
-  default:  // don't support this request (yet)
-    // set reject reason code 
-    fchs->reserved = LS_RJT_REASON( UNABLE_TO_PERFORM, 
-		                    REQUEST_NOT_SUPPORTED);
-    
-    cpqfcTSPutLinkQue( cpqfcHBAdata,
-                    ELS_RJT, // Q Type
-                    fchs );     
-    break;  
-  }
-}
-
-
-static void ProcessELS_Reply( 
-		CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs)
-{
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  ULONG ox_id = (fchs->ox_rx_id >>16);
-  ULONG ls_reject_code;
-  PFC_LOGGEDIN_PORT pLoggedInPort, pLastLoggedInPort;
-  
-  // If this is a valid reply, then we MUST have sent a request.
-  // Verify that we can find a valid request OX_ID corresponding to
-  // this reply
-
-  
-  if( Exchanges->fcExchange[(fchs->ox_rx_id >>16)].type == 0)
-  {
-    printk(" *Discarding ACC/RJT frame, xID %04X/%04X* ", 
-		    ox_id, fchs->ox_rx_id & 0xffff);
-    goto Quit;  // exit this routine
-  }
-
-
-  // Is the reply a RJT (reject)?
-  if( (fchs->pl[0] & 0xFFFFL) == 0x01) // Reject reply?
-  {
-//  ******  REJECT REPLY  ********
-    switch( Exchanges->fcExchange[ox_id].type )
-    {
-	  
-    case ELS_FDISC:  // we sent out Fabric Discovery
-    case ELS_FLOGI:  // we sent out FLOGI
-
-      printk("RJT received on Fabric Login from %Xh, reason %Xh\n", 
-        fchs->s_id, fchs->pl[1]);    
-
-    break;
-
-    default:
-    break;
-    }
-      
-    goto Done;
-  }
-
-  // OK, we have an ACCept...
-  // What's the ACC type? (according to what we sent)
-  switch( Exchanges->fcExchange[ox_id].type )
-  {
-	  
-  case ELS_PLOGI:  // we sent out PLOGI
-    if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) )
-    {
-      LOGIN_PAYLOAD logi;       // FC-PH Port Login
-      
-      // login ACC payload acceptable; search for WWN in our list
-      // of fcPorts
-      
-      BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
-   
-      pLoggedInPort = fcFindLoggedInPort( 
-             fcChip, 
-	     NULL,     // don't search Scsi Nexus
-	     0,        // don't search linked list for port_id
-             &logi.port_name[0],     // search linked list for WWN
-             &pLastLoggedInPort);  // must return non-NULL; when a port_id
-                                   // is not found, this pointer marks the
-                                   // end of the singly linked list
-    
-      if( pLoggedInPort == NULL)         // WWN not found - new port
-      {
+		}
+		break;
 
-	pLoggedInPort = CreateFcPort( 
-			  cpqfcHBAdata, 
-			  pLastLoggedInPort, 
-			  fchs,
-			  &logi);
-
-        if( pLoggedInPort == NULL )
-        {
-          printk(" cpqfcTS: New port allocation failed - lost FC device!\n");
-          // Now Q a LOGOut Request, since we won't be talking to that device
-	
-          goto Done;  // exit with error! dropped login frame
-	}
-      }
-      else      // WWN was already known.  Ensure that any open
-	        // exchanges for this WWN are terminated.
-      	// NOTE: It's possible that a device can change its 
-	// 24-bit port_id after a Link init or Fabric change 
-	// (e.g. LIP or Fabric RSCN).  In that case, the old
-	// 24-bit port_id may be duplicated, or no longer exist.
-      {
-
-        cpqfcTSTerminateExchange( cpqfcHBAdata, 
-          &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
-      }
-
-      // We have an fcPort struct - set fields accordingly
-                                    // not PDISC, originator 
-      SetLoginFields( pLoggedInPort, fchs, FALSE, TRUE);
-			
-      // We just set a "port_id"; is it duplicated?
-      TestDuplicatePortId( cpqfcHBAdata, pLoggedInPort);
-
-      // For Fabric operation, we issued PLOGI to 0xFFFFFC
-      // so we can send SCR (State Change Registration) 
-      // Check for this special case...
-      if( fchs->s_id == 0xFFFFFC ) 
-      {
-        // PLOGI ACC was a Fabric response... issue SCR
-	fchs->s_id = 0xFFFFFD;  // address for SCR
-        cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_SCR, fchs);
-      }
-
-      else
-      {
-      // Now we need a PRLI to enable FCP-SCSI operation
-      // set flags and Q up a ELS_PRLI
-        cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PRLI, fchs);
-      }
-    }
-    else
-    {
-      // login payload unacceptable - reason in ls_reject_code
-      // Q up a Logout Request
-      printk("Login Payload unacceptable\n");
+	case ELS_PRLI:		// we sent out PRLI
+		pLoggedInPort = fcFindLoggedInPort(fcChip, NULL,	// don't search Scsi Nexus
+						   (fchs->s_id & 0xFFFFFF),	// search linked list for port_id
+						   NULL,	// DON'T search linked list for WWN
+						   NULL);	// don't care
+
+		if (pLoggedInPort == NULL) {
+			// huh?
+			printk(" Unexpected PRLI ACCept frame!\n");
+			// Q a LOGOut here?
+			goto Done;
+		}
+		// verify the PRLI ACC payload
+		if (!verify_PRLI(fchs, &ls_reject_code)) {
+			// PRLI Reply is acceptable; were we expecting it?
+			if (pLoggedInPort->plogi) {
+				// yes, we expected the PRLI ACC  (not PDISC; Originator)
+				SetLoginFields(pLoggedInPort, fchs, 0, 1);
+				// OK, let's send a REPORT_LUNS command to determine
+				// whether VSA or PDA FCP-LUN addressing is used.
+				cpqfcTSPutLinkQue(dev, SCSI_REPORT_LUNS, fchs);
+				// It's possible that a device we were talking to changed 
+				// port_id, and has logged back in.  This function ensures
+				// that I/O will resume.
+				UnblockScsiDevice(dev->HostAdapter, pLoggedInPort);
+			} else {
+				// huh?
+				printk(" (unexpected) PRLI ACCept with plogi 0\n");
+				// Q a LOGOut here?
+				goto Done;
+			}
+		} else {
+			printk(" PRLI ACCept payload failed verify\n");
+			// Q a LOGOut here?
+		}
+		break;
 
-    }
-    break;
+	case ELS_FLOGI:	// we sent out FLOGI (Fabric Login)
+		// update the upper 16 bits of our port_id in Tachyon
+		// the switch adds those upper 16 bits when responding
+		// to us (i.e. we are the destination_id)
+		fcChip->Registers.my_al_pa = (fchs->d_id & 0xFFFFFF);
+		writel(fcChip->Registers.my_al_pa, fcChip->Registers.ReMapMemBase + TL_MEM_TACH_My_ID);
+
+		// now send out a PLOGI to the well known port_id 0xFFFFFC
+		fchs->s_id = 0xFFFFFC;
+		cpqfcTSPutLinkQue(dev, ELS_PLOGI, fchs);
+		break;
 
 
-  // PDISC logic very similar to PLOGI, except we never want
-  // to allocate mem for "new" port, and we set flags differently
-  // (might combine later with PLOGI logic for efficiency)  
-  case ELS_PDISC:  // we sent out PDISC
-    if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) )
-    {
-      LOGIN_PAYLOAD logi;       // FC-PH Port Login
-      BOOLEAN NeedLogin = FALSE;
-      
-      // login payload acceptable; search for WWN in our list
-      // of (previously seen) fcPorts
-      
-      BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
-   
-      pLoggedInPort = fcFindLoggedInPort( 
-             fcChip, 
-	     NULL,     // don't search Scsi Nexus
-	     0,        // don't search linked list for port_id
-             &logi.port_name[0],     // search linked list for WWN
-             &pLastLoggedInPort);  // must return non-NULL; when a port_id
-                                   // is not found, this pointer marks the
-                                   // end of the singly linked list
-    
-      if( pLoggedInPort != NULL)   // WWN found?
-      {
-        // WWN has same port_id as last login?  (Of course, a properly
-	// working FC device should NEVER ACCept a PDISC if it's
-	// port_id changed, but check just in case...)
-	if( (fchs->s_id & 0xFFFFFF) == pLoggedInPort->port_id)
-	{
-          // Yes.  We were expecting PDISC?
-          if( pLoggedInPort->pdisc )
-	  {
-            int i;
-	    
-	    
-	    // PDISC expected -- set fields.  (PDISC, Originator)
-            SetLoginFields( pLoggedInPort, fchs, TRUE, TRUE);
+	case ELS_FDISC:	// we sent out FDISC (Fabric Discovery (Login))
+		printk(" ELS_FDISC success ");
+		break;
 
-	    // We are ready to resume FCP-SCSI to this device...
-            // Do we need to start anything that was Queued?
+	case ELS_SCR:		// we sent out State Change Registration
+		// now we can issue Name Service Request to find any
+		// Fabric-connected devices we might want to login to.
+		fchs->s_id = 0xFFFFFC;	// Name Server Address
+		cpqfcTSPutLinkQue(dev, FCS_NSR, fchs);
+		break;
 
-            for( i=0; i< TACH_SEST_LEN; i++)
-            {
-              // see if any exchange for this PDISC'd port was queued
-              if( ((fchs->s_id &0xFFFFFF) == 
-                   (Exchanges->fcExchange[i].fchs.d_id & 0xFFFFFF))
-                      &&
-                  (Exchanges->fcExchange[i].status & EXCHANGE_QUEUED))
-              {
-                fchs->reserved = i; // copy ExchangeID
-//                printk(" *Q x_ID %Xh after PDISC* ",i);
-
-                cpqfcTSPutLinkQue( cpqfcHBAdata, EXCHANGE_QUEUED, fchs );
-              }
-            }
-
-	    // Complete commands Q'd while we were waiting for Login
-
-	    UnblockScsiDevice( cpqfcHBAdata->HostAdapter, pLoggedInPort);
-	  }
-	  else
-	  {
-	    printk("Not expecting PDISC (pdisc=FALSE)\n");
-	    NeedLogin = TRUE;
-	  }
+	default:
+		printk(" *Discarding unknown ACC frame, xID %04X/%04X* ", ox_id, fchs->ox_rx_id & 0xffff);
+		break;
 	}
-	else
-	{
-	  printk("PDISC PortID change: old %Xh, new %Xh\n",
-            pLoggedInPort->port_id, fchs->s_id &0xFFFFFF);
-          NeedLogin = TRUE;
-		  
-	}
-      }
-      else
-      {
-	printk("PDISC ACC from unknown WWN\n");
-        NeedLogin = TRUE;
-      }
-
-      if( NeedLogin)
-      {
-	
-        // The PDISC failed.  Set login struct flags accordingly,
-	// terminate any I/O to this port, and Q a PLOGI
-	if( pLoggedInPort )  // FC device previously known?
-	{
-
-          cpqfcTSPutLinkQue( cpqfcHBAdata,
-                    ELS_LOGO, // Q Type
-                    fchs );   // has port_id to send to 
-
-	  // There are a variety of error scenarios which can result
-  	  // in PDISC failure, so as a catchall, add the check for
-	  // duplicate port_id.
-	  TestDuplicatePortId( cpqfcHBAdata, pLoggedInPort);
-
-//    TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
-          pLoggedInPort->pdisc = FALSE;
-          pLoggedInPort->prli = FALSE;
-          pLoggedInPort->plogi = FALSE;
-	
-          cpqfcTSTerminateExchange( cpqfcHBAdata, 
-	    &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
-        }
-        cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PLOGI, fchs );
-      }
-    }
-    else
-    {
-      // login payload unacceptable - reason in ls_reject_code
-      // Q up a Logout Request
-      printk("ERROR: Login Payload unacceptable!\n");
-
-    }
-   
-    break;
-    
-
-
-  case ELS_PRLI:  // we sent out PRLI
-
-
-    pLoggedInPort = fcFindLoggedInPort( 
-           fcChip, 
-           NULL,       // don't search Scsi Nexus
-	   (fchs->s_id & 0xFFFFFF),  // search linked list for port_id
-           NULL,     // DON'T search linked list for WWN
-           NULL);    // don't care
-      
-    if( pLoggedInPort == NULL ) 
-    {
-      // huh?
-      printk(" Unexpected PRLI ACCept frame!\n");
-
-      // Q a LOGOut here?
-
-      goto Done;
-    }
-
-    // verify the PRLI ACC payload
-    if( !verify_PRLI( fchs, &ls_reject_code) )
-    {
-      // PRLI Reply is acceptable; were we expecting it?
-      if( pLoggedInPort->plogi ) 
-      { 
-	// yes, we expected the PRLI ACC  (not PDISC; Originator)
-	SetLoginFields( pLoggedInPort, fchs, FALSE, TRUE);
-
-        // OK, let's send a REPORT_LUNS command to determine
-	// whether VSA or PDA FCP-LUN addressing is used.
-	
-        cpqfcTSPutLinkQue( cpqfcHBAdata, SCSI_REPORT_LUNS, fchs );
-	
-	// It's possible that a device we were talking to changed 
-	// port_id, and has logged back in.  This function ensures
-	// that I/O will resume.
-        UnblockScsiDevice( cpqfcHBAdata->HostAdapter, pLoggedInPort);
-
-      }
-      else
-      {
-        // huh?
-        printk(" (unexpected) PRLI ACCept with plogi FALSE\n");
-
-        // Q a LOGOut here?
-        goto Done;
-      }
-    }
-    else
-    {
-      printk(" PRLI ACCept payload failed verify\n");
-
-      // Q a LOGOut here?
-    }
-
-    break;
- 
-  case ELS_FLOGI:  // we sent out FLOGI (Fabric Login)
-
-    // update the upper 16 bits of our port_id in Tachyon
-    // the switch adds those upper 16 bits when responding
-    // to us (i.e. we are the destination_id)
-    fcChip->Registers.my_al_pa = (fchs->d_id & 0xFFFFFF);
-    writel( fcChip->Registers.my_al_pa,  
-      fcChip->Registers.ReMapMemBase + TL_MEM_TACH_My_ID);
-
-    // now send out a PLOGI to the well known port_id 0xFFFFFC
-    fchs->s_id = 0xFFFFFC;
-    cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PLOGI, fchs);
-  
-   break; 
-
-
-  case ELS_FDISC:  // we sent out FDISC (Fabric Discovery (Login))
-
-   printk( " ELS_FDISC success ");
-   break;
-   
-
-  case ELS_SCR:  // we sent out State Change Registration
-    // now we can issue Name Service Request to find any
-    // Fabric-connected devices we might want to login to.
-   
-	
-    fchs->s_id = 0xFFFFFC;  // Name Server Address
-    cpqfcTSPutLinkQue( cpqfcHBAdata, FCS_NSR, fchs);
-    
-
-    break;
-
-    
-  default:
-    printk(" *Discarding unknown ACC frame, xID %04X/%04X* ", 
-   		    ox_id, fchs->ox_rx_id & 0xffff);
-    break;
-  }
-
-  
 Done:
-  // Regardless of whether the Reply is valid or not, the
-  // the exchange is done - complete
-  cpqfcTSCompleteExchange(cpqfcHBAdata->PciDev, fcChip, (fchs->ox_rx_id >>16)); 
-	  
-Quit:    
-  return;
+	// Regardless of whether the Reply is valid or not, the
+	// the exchange is done - complete
+	cpqfcTSCompleteExchange(dev->PciDev, fcChip, (fchs->ox_rx_id >> 16));
+Quit:
+	return;
 }
 
 
@@ -2075,352 +1604,263 @@
 // This is where we process the Directory (Name) Service Reply
 // to know which devices are on the Fabric
 
-static void ProcessFCS_Reply( 
-	CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs)
+static void ProcessFCS_Reply(CPQFCHBA * dev, TachFCHDR_GCMND * fchs)
 {
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  ULONG ox_id = (fchs->ox_rx_id >>16);
-//  ULONG ls_reject_code;
-//  PFC_LOGGEDIN_PORT pLoggedInPort, pLastLoggedInPort;
-  
-  // If this is a valid reply, then we MUST have sent a request.
-  // Verify that we can find a valid request OX_ID corresponding to
-  // this reply
-
-  if( Exchanges->fcExchange[(fchs->ox_rx_id >>16)].type == 0)
-  {
-    printk(" *Discarding Reply frame, xID %04X/%04X* ", 
-		    ox_id, fchs->ox_rx_id & 0xffff);
-    goto Quit;  // exit this routine
-  }
-
+	PTACHYON fcChip = &dev->fcChip;
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	u32 ox_id = (fchs->ox_rx_id >> 16);
+//	u32 ls_reject_code;
+//	PFC_LOGGEDIN_PORT pLoggedInPort, pLastLoggedInPort;
+
+	// If this is a valid reply, then we MUST have sent a request.
+	// Verify that we can find a valid request OX_ID corresponding to
+	// this reply
+
+	if (Exchanges->fcExchange[(fchs->ox_rx_id >> 16)].type == 0) {
+		printk(" *Discarding Reply frame, xID %04X/%04X* ", ox_id, fchs->ox_rx_id & 0xffff);
+		goto Quit;	// exit this routine
+	}
 
-  // OK, we were expecting it.  Now check to see if it's a
-  // "Name Service" Reply, and if so force a re-validation of
-  // Fabric device logins (i.e. Start the login timeout and
-  // send PDISC or PLOGI)
-  // (Endianess Byte Swap?)
-  if( fchs->pl[1] == 0x02FC )  // Name Service
-  {
-    // got a new (or NULL) list of Fabric attach devices... 
-    // Invalidate current logins
-    
-    PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts;
-    while( pLoggedInPort ) // for all ports which are expecting
-                           // PDISC after the next LIP, set the
-                           // logoutTimer
-    {
+	// OK, we were expecting it.  Now check to see if it's a
+	// "Name Service" Reply, and if so force a re-validation of
+	// Fabric device logins (i.e. Start the login timeout and
+	// send PDISC or PLOGI)
+	// (Endianess Byte Swap?)
+	if (fchs->pl[1] == 0x02FC)	// Name Service
+	{
+		// got a new (or NULL) list of Fabric attach devices... 
+		// Invalidate current logins
 
-      if( (pLoggedInPort->port_id & 0xFFFF00)  // Fabric device?
-		      &&
-          (pLoggedInPort->port_id != 0xFFFFFC) ) // NOT the F_Port
-      {
-        pLoggedInPort->LOGO_timer = 6;  // what's the Fabric timeout??
-                                // suspend any I/O in progress until
-                                // PDISC received...
-        pLoggedInPort->prli = FALSE;   // block FCP-SCSI commands
-      }
-	    
-      pLoggedInPort = pLoggedInPort->pNextPort;
-    }
-    
-    if( fchs->pl[2] == 0x0280)  // ACCept?
-    {
-      // Send PLOGI or PDISC to these Fabric devices
-      SendLogins( cpqfcHBAdata, &fchs->pl[4] );  
-    }
+		PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts;
+		while (pLoggedInPort)	// for all ports which are expecting
+			// PDISC after the next LIP, set the
+			// logoutTimer
+		{
+
+			if ((pLoggedInPort->port_id & 0xFFFF00)	// Fabric device?
+			    && (pLoggedInPort->port_id != 0xFFFFFC))	// NOT the F_Port
+			{
+				pLoggedInPort->LOGO_timer = 6;	// what's the Fabric timeout??
+				// suspend any I/O in progress until
+				// PDISC received...
+				pLoggedInPort->prli = 0;	// block FCP-SCSI commands
+			}
 
+			pLoggedInPort = pLoggedInPort->pNextPort;
+		}
 
-    // As of this writing, the only reason to reject is because NO
-    // devices are left on the Fabric.  We already started
-    // "logged out" timers; if the device(s) don't come
-    // back, we'll do the implicit logout in the heart beat 
-    // timer routine
-    else  // ReJecT
-    {
-      // this just means no Fabric device is visible at this instant
-    } 
-  }
+		if (fchs->pl[2] == 0x0280)	// ACCept?
+		{
+			// Send PLOGI or PDISC to these Fabric devices
+			SendLogins(dev, &fchs->pl[4]);
+		}
+		// As of this writing, the only reason to reject is because NO
+		// devices are left on the Fabric.  We already started
+		// "logged out" timers; if the device(s) don't come
+		// back, we'll do the implicit logout in the heart beat 
+		// timer routine
+		else		// ReJecT
+		{
+			// this just means no Fabric device is visible at this instant
+		}
+	}
+	// Regardless of whether the Reply is valid or not, the
+	// the exchange is done - complete
+	cpqfcTSCompleteExchange(dev->PciDev, fcChip, (fchs->ox_rx_id >> 16));
 
-  // Regardless of whether the Reply is valid or not, the
-  // the exchange is done - complete
-  cpqfcTSCompleteExchange(cpqfcHBAdata->PciDev, fcChip, (fchs->ox_rx_id >>16));
-	  
-Quit:    
-  return;
+Quit:
+	return;
 }
 
-
-
-
-
-
-
-static void AnalyzeIncomingFrame( 
-        CPQFCHBA *cpqfcHBAdata,
-        ULONG QNdx )
+static void AnalyzeIncomingFrame(CPQFCHBA * dev, u32 QNdx)
 {
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
-  TachFCHDR_GCMND* fchs = 
-    (TachFCHDR_GCMND*)fcLQ->Qitem[QNdx].ulBuff;
-//  ULONG ls_reject_code;  // reason for rejecting login
-  LONG ExchangeID;
-//  FC_LOGGEDIN_PORT *pLoggedInPort;
-  BOOLEAN AbortAccept;  
-
-  ENTER("AnalyzeIncomingFrame");
-
-
-
-  switch( fcLQ->Qitem[QNdx].Type) // FCP or Unknown
-  {
+	PTACHYON fcChip = &dev->fcChip;
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	PFC_LINK_QUE fcLQ = dev->fcLQ;
+	TachFCHDR_GCMND *fchs = (TachFCHDR_GCMND *) fcLQ->Qitem[QNdx].ulBuff;
+//	u32 ls_reject_code;  // reason for rejecting login
+	s32 ExchangeID;
+//	FC_LOGGEDIN_PORT *pLoggedInPort;
+	u8 AbortAccept;
 
-  case SFQ_UNKNOWN:  // unknown frame (e.g. LIP position frame, NOP, etc.)
- 
+	ENTER("AnalyzeIncomingFrame");
 
-      // *********  FC-4 Device Data/ Fibre Channel Service *************
-    if( ((fchs->d_id &0xF0000000) == 0)   // R_CTL (upper nibble) 0x0?
-                &&   
-      (fchs->f_ctl & 0x20000000) )  // TYPE 20h is Fibre Channel Service
-    {
-
-      // ************** FCS Reply **********************
-
-      if( (fchs->d_id & 0xff000000L) == 0x03000000L)  // (31:23 R_CTL)
-      {
-	ProcessFCS_Reply( cpqfcHBAdata, fchs );
-
-      }  // end of  FCS logic
-
-    }
-    
-
-      // ***********  Extended Link Service **************
-
-    else if( fchs->d_id & 0x20000000   // R_CTL 0x2?
-                  &&   
-      (fchs->f_ctl & 0x01000000) )  // TYPE = 1
-    {
-
-                           // these frames are either a response to
-                           // something we sent (0x23) or "unsolicited"
-                           // frames (0x22).
-
-
-      // **************Extended Link REPLY **********************
-                           // R_CTL Solicited Control Reply
-
-      if( (fchs->d_id & 0xff000000L) == 0x23000000L)  // (31:23 R_CTL)
-      {
-
-	ProcessELS_Reply( cpqfcHBAdata, fchs );
-
-      }  // end of  "R_CTL Solicited Control Reply"
-
-
-
-
-       // **************Extended Link REQUEST **********************
-       // (unsolicited commands from another port or task...)
-
-                           // R_CTL Ext Link REQUEST
-      else if( (fchs->d_id & 0xff000000L) == 0x22000000L &&
-              (fchs->ox_rx_id != 0xFFFFFFFFL) ) // (ignore LIP frame)
-      {
-
-
-
-	ProcessELS_Request( cpqfcHBAdata, fchs );
-
-      }
-
-
-
-        // ************** LILP **********************
-      else if( (fchs->d_id & 0xff000000L) == 0x22000000L &&
-               (fchs->ox_rx_id == 0xFFFFFFFFL)) // (e.g., LIP frames)
-
-      {
-        // SANMark specifies that when available, we must use
-	// the LILP frame to determine which ALPAs to send Port Discovery
-	// to...
-
-        if( fchs->pl[0] == 0x0711L) //  ELS_PLOGI?
+	switch (fcLQ->Qitem[QNdx].Type)	// FCP or Unknown
 	{
-//	  UCHAR *ptr = (UCHAR*)&fchs->pl[1];
-//	  printk(" %d ALPAs found\n", *ptr);
-	  memcpy( fcChip->LILPmap, &fchs->pl[1], 32*4); // 32 DWORDs
-	  fcChip->Options.LILPin = 1; // our LILPmap is valid!
-	  // now post to make Port Discovery happen...
-          cpqfcTSPutLinkQue( cpqfcHBAdata, LINKACTIVE, fchs);  
-	}
-      }
-    }
-
-     
-    // *****************  BASIC LINK SERVICE *****************
-    
-    else if( fchs->d_id & 0x80000000  // R_CTL:
-                    &&           // Basic Link Service Request
-           !(fchs->f_ctl & 0xFF000000) )  // type=0 for BLS
-    {
+	case SFQ_UNKNOWN:	// unknown frame (e.g. LIP position frame, NOP, etc.)
+		// *********  FC-4 Device Data/ Fibre Channel Service *************
+		if (((fchs->d_id & 0xF0000000) == 0)	// R_CTL (upper nibble) 0x0?
+		    && (fchs->f_ctl & 0x20000000))	// TYPE 20h is Fibre Channel Service
+		{
+			// ************** FCS Reply **********************
+			if ((fchs->d_id & 0xff000000L) == 0x03000000L)	// (31:23 R_CTL)
+			{
+				ProcessFCS_Reply(dev, fchs);
+			}	// end of  FCS logic
+		}
+		// ***********  Extended Link Service **************
+		else if (fchs->d_id & 0x20000000	// R_CTL 0x2?
+			 && (fchs->f_ctl & 0x01000000))	// TYPE = 1
+		{
+			// these frames are either a response to
+			// something we sent (0x23) or "unsolicited"
+			// frames (0x22).
+			// **************Extended Link REPLY **********************
+			// R_CTL Solicited Control Reply
+			if ((fchs->d_id & 0xff000000L) == 0x23000000L)	// (31:23 R_CTL)
+			{
+				ProcessELS_Reply(dev, fchs);
+			}	// end of  "R_CTL Solicited Control Reply"
+			// **************Extended Link REQUEST **********************
+			// (unsolicited commands from another port or task...)
+			// R_CTL Ext Link REQUEST
+			else if ((fchs->d_id & 0xff000000L) == 0x22000000L && (fchs->ox_rx_id != 0xFFFFFFFFL))	// (ignore LIP frame)
+			{
+				ProcessELS_Request(dev, fchs);
+			}
+			// ************** LILP **********************
+			else if ((fchs->d_id & 0xff000000L) == 0x22000000L && (fchs->ox_rx_id == 0xFFFFFFFFL))	// (e.g., LIP frames)
+			{
+				// SANMark specifies that when available, we must use
+				// the LILP frame to determine which ALPAs to send Port Discovery
+				// to...
+				if (fchs->pl[0] == 0x0711L)	//  ELS_PLOGI?
+				{
+//					u8 *ptr = (u8*)&fchs->pl[1];
+//					printk(" %d ALPAs found\n", *ptr);
+					memcpy(fcChip->LILPmap, &fchs->pl[1], 32 * 4);	// 32 DWORDs
+					fcChip->Options.LILPin = 1;	// our LILPmap is valid!
+					// now post to make Port Discovery happen...
+					cpqfcTSPutLinkQue(dev, LINKACTIVE, fchs);
+				}
+			}
+		}
+		// *****************  BASIC LINK SERVICE *****************
+		else if (fchs->d_id & 0x80000000	// R_CTL:
+			 &&	// Basic Link Service Request
+			 !(fchs->f_ctl & 0xFF000000))	// type=0 for BLS
+		{
+			// Check for ABTS (Abort Sequence)
+			if ((fchs->d_id & 0x8F000000) == 0x81000000) {
+				// look for OX_ID, S_ID pair that matches in our
+				// fcExchanges table; if found, reply with ACCept and complete
+				// the exchange
+
+				// Per PLDA, an ABTS is sent by an initiator; therefore
+				// assume that if we have an exhange open to the port who
+				// sent ABTS, it will be the d_id of what we sent.  
+				for (ExchangeID = 0, AbortAccept = 0; ExchangeID < TACH_SEST_LEN; ExchangeID++) {
+					// Valid "target" exchange 24-bit port_id matches? 
+					// NOTE: For the case of handling Intiator AND Target
+					// functions on the same chip, we can have TWO Exchanges
+					// with the same OX_ID -- OX_ID/FFFF for the CMND, and
+					// OX_ID/RX_ID for the XRDY or DATA frame(s).  Ideally,
+					// we would like to support ABTS from Initiators or Targets,
+					// but it's not clear that can be supported on Tachyon for
+					// all cases (requires more investigation).
+
+					if ((Exchanges->fcExchange[ExchangeID].type == SCSI_TWE || Exchanges->fcExchange[ExchangeID].type == SCSI_TRE)
+					    && ((Exchanges->fcExchange[ExchangeID].fchs.d_id & 0xFFFFFF) == (fchs->s_id & 0xFFFFFF))) {
+
+						// target xchnge port_id matches -- how about OX_ID?
+						if ((Exchanges->fcExchange[ExchangeID].fchs.ox_rx_id & 0xFFFF0000)
+						    == (fchs->ox_rx_id & 0xFFFF0000))
+							// yes! post ACCept response; will be completed by fcStart
+						{
+							Exchanges->fcExchange[ExchangeID].status = TARGET_ABORT;
+
+							// copy (add) rx_id field for simplified ACCept reply
+							fchs->ox_rx_id = Exchanges->fcExchange[ExchangeID].fchs.ox_rx_id;
+
+							cpqfcTSPutLinkQue(dev, BLS_ABTS_ACC,	// Q Type 
+									  fchs);	// void QueContent
+							AbortAccept = 1;
+							printk("ACCepting ABTS for x_ID %8.8Xh, SEST pair %8.8Xh\n", fchs->ox_rx_id, Exchanges->fcExchange[ExchangeID].fchs.ox_rx_id);
+							break;	// ABTS can affect only ONE exchange -exit loop
+						}
+					}
+				}	// end of FOR loop
+				if (!AbortAccept)	// can't ACCept ABTS - send Reject
+				{
+					printk("ReJecTing: can't find ExchangeID %8.8Xh for ABTS command\n", fchs->ox_rx_id);
+					if (Exchanges->fcExchange[ExchangeID].type && !(fcChip->SEST->u[ExchangeID].IWE.Hdr_Len & 0x80000000)) {
+						cpqfcTSCompleteExchange(dev->PciDev, fcChip, ExchangeID);
+					} else {
+						printk("Unexpected ABTS ReJecT! SEST[%X] Dword 0: %Xh\n", ExchangeID, fcChip->SEST->u[ExchangeID].IWE.Hdr_Len);
+					}
+				}
+			}
+			// Check for BLS {ABTS? (Abort Sequence)} ACCept
+			else if ((fchs->d_id & 0x8F000000) == 0x84000000) {
+				// target has responded with ACC for our ABTS;
+				// complete the indicated exchange with ABORTED status 
+				// Make no checks for correct RX_ID, since
+				// all we need to conform ABTS ACC is the OX_ID.
+				// Verify that the d_id matches!
 
-      // Check for ABTS (Abort Sequence)
-      if( (fchs->d_id & 0x8F000000) == 0x81000000)
-      {
-        // look for OX_ID, S_ID pair that matches in our
-        // fcExchanges table; if found, reply with ACCept and complete
-        // the exchange
-
-        // Per PLDA, an ABTS is sent by an initiator; therefore
-        // assume that if we have an exhange open to the port who
-        // sent ABTS, it will be the d_id of what we sent.  
-        for( ExchangeID = 0, AbortAccept=FALSE;
-             ExchangeID < TACH_SEST_LEN; ExchangeID++)
-        {
-            // Valid "target" exchange 24-bit port_id matches? 
-            // NOTE: For the case of handling Intiator AND Target
-            // functions on the same chip, we can have TWO Exchanges
-            // with the same OX_ID -- OX_ID/FFFF for the CMND, and
-            // OX_ID/RX_ID for the XRDY or DATA frame(s).  Ideally,
-            // we would like to support ABTS from Initiators or Targets,
-            // but it's not clear that can be supported on Tachyon for
-            // all cases (requires more investigation).
-            
-          if( (Exchanges->fcExchange[ ExchangeID].type == SCSI_TWE ||
-               Exchanges->fcExchange[ ExchangeID].type == SCSI_TRE)
-                  &&
-             ((Exchanges->fcExchange[ ExchangeID].fchs.d_id & 0xFFFFFF) ==
-             (fchs->s_id & 0xFFFFFF)) )
-          {
-              
-              // target xchnge port_id matches -- how about OX_ID?
-            if( (Exchanges->fcExchange[ ExchangeID].fchs.ox_rx_id &0xFFFF0000)
-                    == (fchs->ox_rx_id & 0xFFFF0000) )
-                    // yes! post ACCept response; will be completed by fcStart
-            {
-              Exchanges->fcExchange[ ExchangeID].status = TARGET_ABORT;
-                
-                // copy (add) rx_id field for simplified ACCept reply
-              fchs->ox_rx_id = 
-                Exchanges->fcExchange[ ExchangeID].fchs.ox_rx_id;
-                
-              cpqfcTSPutLinkQue( cpqfcHBAdata,
-                            BLS_ABTS_ACC, // Q Type 
-                            fchs );    // void QueContent
-              AbortAccept = TRUE;
-      printk("ACCepting ABTS for x_ID %8.8Xh, SEST pair %8.8Xh\n", 
-             fchs->ox_rx_id, Exchanges->fcExchange[ ExchangeID].fchs.ox_rx_id);
-              break;      // ABTS can affect only ONE exchange -exit loop
-            }
-          }
-        }  // end of FOR loop
-        if( !AbortAccept ) // can't ACCept ABTS - send Reject
-        {
-      printk("ReJecTing: can't find ExchangeID %8.8Xh for ABTS command\n", 
-            fchs->ox_rx_id);
-          if( Exchanges->fcExchange[ ExchangeID].type 
-                &&
-              !(fcChip->SEST->u[ ExchangeID].IWE.Hdr_Len
-               & 0x80000000))
-          {
-            cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID);
-          }
-          else
-          {
-            printk("Unexpected ABTS ReJecT! SEST[%X] Dword 0: %Xh\n", 
-              ExchangeID, fcChip->SEST->u[ ExchangeID].IWE.Hdr_Len);
-          }
-        }
-      }
-
-      // Check for BLS {ABTS? (Abort Sequence)} ACCept
-      else if( (fchs->d_id & 0x8F000000) == 0x84000000)
-      {
-        // target has responded with ACC for our ABTS;
-	// complete the indicated exchange with ABORTED status 
-        // Make no checks for correct RX_ID, since
-	// all we need to conform ABTS ACC is the OX_ID.
-        // Verify that the d_id matches!
- 
-        ExchangeID = (fchs->ox_rx_id >> 16) & 0x7FFF; // x_id from ACC
-//	printk("ABTS ACC x_ID 0x%04X 0x%04X, status %Xh\n", 
+				ExchangeID = (fchs->ox_rx_id >> 16) & 0x7FFF;	// x_id from ACC
+//      printk("ABTS ACC x_ID 0x%04X 0x%04X, status %Xh\n", 
 //          fchs->ox_rx_id >> 16, fchs->ox_rx_id & 0xffff,
 //          Exchanges->fcExchange[ExchangeID].status);
+				if (ExchangeID < TACH_SEST_LEN)	// x_ID makes sense
+				{
+					// Does "target" exchange 24-bit port_id match? 
+					// (See "NOTE" above for handling Intiator AND Target in
+					// the same device driver)
+					// First, if this is a target response, then we originated
+					// (initiated) it with BLS_ABTS:
+
+					if ((Exchanges->fcExchange[ExchangeID].type == BLS_ABTS) &&
+					    // Second, does the source of this ACC match the destination
+					    // of who we originally sent it to?
+					    ((Exchanges->fcExchange[ExchangeID].fchs.d_id & 0xFFFFFF) == (fchs->s_id & 0xFFFFFF))) {
+						cpqfcTSCompleteExchange(dev->PciDev, fcChip, ExchangeID);
+					}
+				}
+			}
+			// Check for BLS {ABTS? (Abort Sequence)} ReJecT
+			else if ((fchs->d_id & 0x8F000000) == 0x85000000) {
+				// target has responded with RJT for our ABTS;
+				// complete the indicated exchange with ABORTED status 
+				// Make no checks for correct RX_ID, since
+				// all we need to conform ABTS ACC is the OX_ID.
+				// Verify that the d_id matches!
+
+				ExchangeID = (fchs->ox_rx_id >> 16) & 0x7FFF;	// x_id from ACC
+//				printk("BLS_ABTS RJT on Exchange 0x%04X 0x%04X\n", 
+//					fchs->ox_rx_id >> 16, fchs->ox_rx_id & 0xffff);
+
+				if (ExchangeID < TACH_SEST_LEN)	// x_ID makes sense
+				{
+					// Does "target" exchange 24-bit port_id match? 
+					// (See "NOTE" above for handling Intiator AND Target in
+					// the same device driver)
+					// First, if this is a target response, then we originated
+					// (initiated) it with BLS_ABTS:
+
+					if ((Exchanges->fcExchange[ExchangeID].type == BLS_ABTS)
+
+					    &&
+					    // Second, does the source of this ACC match the destination
+					    // of who we originally sent it to?
+					    ((Exchanges->fcExchange[ExchangeID].fchs.d_id & 0xFFFFFF) == (fchs->s_id & 0xFFFFFF))) {
+						// YES! NOTE: There is a bug in CPQ's RA-4000 box 
+						// where the "reason code" isn't returned in the payload
+						// For now, simply presume the reject is because the target
+						// already completed the exchange...
+
+//						printk("complete x_ID %Xh on ABTS RJT\n", ExchangeID);
+						cpqfcTSCompleteExchange(dev->PciDev, fcChip, ExchangeID);
+					}
+				}
+			}	// end of ABTS check
+		}		// end of Basic Link Service Request
+		break;
 
-
-	
-        if( ExchangeID < TACH_SEST_LEN ) // x_ID makes sense
-        {
-            // Does "target" exchange 24-bit port_id match? 
-            // (See "NOTE" above for handling Intiator AND Target in
-            // the same device driver)
-            // First, if this is a target response, then we originated
-	    // (initiated) it with BLS_ABTS:
-	  
-          if( (Exchanges->fcExchange[ ExchangeID].type == BLS_ABTS)
-
-                  &&
-	    // Second, does the source of this ACC match the destination
-            // of who we originally sent it to?
-             ((Exchanges->fcExchange[ ExchangeID].fchs.d_id & 0xFFFFFF) ==
-             (fchs->s_id & 0xFFFFFF)) )
-          {
-            cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID );
-	  }
-        }              
-      }
-      // Check for BLS {ABTS? (Abort Sequence)} ReJecT
-      else if( (fchs->d_id & 0x8F000000) == 0x85000000)
-      {
-        // target has responded with RJT for our ABTS;
-	// complete the indicated exchange with ABORTED status 
-        // Make no checks for correct RX_ID, since
-	// all we need to conform ABTS ACC is the OX_ID.
-        // Verify that the d_id matches!
- 
-        ExchangeID = (fchs->ox_rx_id >> 16) & 0x7FFF; // x_id from ACC
-//	printk("BLS_ABTS RJT on Exchange 0x%04X 0x%04X\n", 
-//          fchs->ox_rx_id >> 16, fchs->ox_rx_id & 0xffff);
-
-        if( ExchangeID < TACH_SEST_LEN ) // x_ID makes sense
-	{  
-            // Does "target" exchange 24-bit port_id match? 
-            // (See "NOTE" above for handling Intiator AND Target in
-            // the same device driver)
-            // First, if this is a target response, then we originated
-	    // (initiated) it with BLS_ABTS:
-		  
-          if( (Exchanges->fcExchange[ ExchangeID].type == BLS_ABTS)
-
-                  &&
-	    // Second, does the source of this ACC match the destination
-            // of who we originally sent it to?
-             ((Exchanges->fcExchange[ ExchangeID].fchs.d_id & 0xFFFFFF) ==
-             (fchs->s_id & 0xFFFFFF)) )
-          {
-	    // YES! NOTE: There is a bug in CPQ's RA-4000 box 
-	    // where the "reason code" isn't returned in the payload
-	    // For now, simply presume the reject is because the target
-	    // already completed the exchange...
-	    
-//            printk("complete x_ID %Xh on ABTS RJT\n", ExchangeID);
-            cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID );
-	  }
-	} 
-      }  // end of ABTS check
-    }  // end of Basic Link Service Request
-    break;
-  
-    default:
-      printk("AnalyzeIncomingFrame: unknown type: %Xh(%d)\n",
-        fcLQ->Qitem[QNdx].Type,
-        fcLQ->Qitem[QNdx].Type);
-    break;
-  }
+	default:
+		printk("AnalyzeIncomingFrame: unknown type: %Xh(%d)\n", fcLQ->Qitem[QNdx].Type, fcLQ->Qitem[QNdx].Type);
+		break;
+	}
 }
 
 
@@ -2428,506 +1868,433 @@
 // initialization (e.g. LIP).
 // Also may be called if from Fabric Name Service logic.
 
-static void SendLogins( CPQFCHBA *cpqfcHBAdata, __u32 *FabricPortIds )
+static void SendLogins(CPQFCHBA * dev, __u32 * FabricPortIds)
 {
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  ULONG ulStatus=0;
-  TachFCHDR_GCMND fchs;  // copy fields for transmission
-  int i;
-  ULONG loginType;
-  LONG ExchangeID;
-  PFC_LOGGEDIN_PORT pLoggedInPort;
-  __u32 PortIds[ number_of_al_pa];
-  int NumberOfPorts=0;
-
-  // We're going to presume (for now) that our limit of Fabric devices
-  // is the same as the number of alpa on a private loop (126 devices).
-  // (Of course this could be changed to support however many we have
-  // memory for).
-  memset( &PortIds[0], 0, sizeof(PortIds));
-   
-  // First, check if this login is for our own Link Initialization
-  // (e.g. LIP on FC-AL), or if we have knowledge of Fabric devices
-  // from a switch.  If we are logging into Fabric devices, we'll
-  // have a non-NULL FabricPortId pointer
-  
-  if( FabricPortIds != NULL) // may need logins
-  {
-    int LastPort=FALSE;
-    i = 0;
-    while( !LastPort)
-    {
-      // port IDs From NSR payload; byte swap needed?
-      BigEndianSwap( (UCHAR*)FabricPortIds, (UCHAR*)&PortIds[i], 4);
- 
-//      printk("FPortId[%d] %Xh ", i, PortIds[i]);
-      if( PortIds[i] & 0x80000000)
-	LastPort = TRUE;
-      
-      PortIds[i] &= 0xFFFFFF; // get 24-bit port_id
-      // some non-Fabric devices (like the Crossroads Fibre/Scsi bridge)
-      // erroneously use ALPA 0.
-      if( PortIds[i]  ) // need non-zero port_id...
-        i++;
-      
-      if( i >= number_of_al_pa ) // (in)sanity check
-	break;
-      FabricPortIds++;  // next...
-    }
-
-    NumberOfPorts = i;
-//    printk("NumberOf Fabric ports %d", NumberOfPorts);
-  }
-  
-  else  // need to send logins on our "local" link
-  {
-  
-    // are we a loop port?  If so, check for reception of LILP frame,
-    // and if received use it (SANMark requirement)
-    if( fcChip->Options.LILPin )
-    {
-      int j=0;
-      // sanity check on number of ALPAs from LILP frame...
-      // For format of LILP frame, see FC-AL specs or 
-      // "Fibre Channel Bench Reference", J. Stai, 1995 (ISBN 1-879936-17-8)
-      // First byte is number of ALPAs
-      i = fcChip->LILPmap[0] >= (32*4) ? 32*4 : fcChip->LILPmap[0];
-      NumberOfPorts = i;
-//      printk(" LILP alpa count %d ", i);
-      while( i > 0)
-      {
-	PortIds[j] = fcChip->LILPmap[1+ j];
-	j++; i--;
-      }
-    }
-    else  // have to send login to everybody
-    {
-      int j=0;
-      i = number_of_al_pa;
-      NumberOfPorts = i;
-      while( i > 0)
-      {
-        PortIds[j] = valid_al_pa[j]; // all legal ALPAs
-	j++; i--;
-      }
-    }
-  }
-
-
-  // Now we have a copy of the port_ids (and how many)...
-  for( i = 0; i < NumberOfPorts; i++)
-  {
-    // 24-bit FC Port ID
-    fchs.s_id = PortIds[i];  // note: only 8-bits used for ALPA
+	PTACHYON fcChip = &dev->fcChip;
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	u32 ulStatus = 0;
+	TachFCHDR_GCMND fchs;	// copy fields for transmission
+	int i;
+	u32 loginType;
+	s32 ExchangeID;
+	PFC_LOGGEDIN_PORT pLoggedInPort;
+	__u32 PortIds[number_of_al_pa];
+	int NumberOfPorts = 0;
+
+	// We're going to presume (for now) that our limit of Fabric devices
+	// is the same as the number of alpa on a private loop (126 devices).
+	// (Of course this could be changed to support however many we have
+	// memory for).
+	memset(&PortIds[0], 0, sizeof(PortIds));
+
+	// First, check if this login is for our own Link Initialization
+	// (e.g. LIP on FC-AL), or if we have knowledge of Fabric devices
+	// from a switch.  If we are logging into Fabric devices, we'll
+	// have a non-NULL FabricPortId pointer
 
-
-    // don't log into ourselves (Linux Scsi disk scan will stop on
-    // no TARGET support error on us, and quit trying for rest of devices)
-    if( (fchs.s_id & 0xFF ) == (fcChip->Registers.my_al_pa & 0xFF) )
-      continue;
-
-    // fabric login needed?
-    if( (fchs.s_id == 0) || 
-        (fcChip->Options.fabric == 1) )
-    {
-      fcChip->Options.flogi = 1;  // fabric needs longer for login
-      // Do we need FLOGI or FDISC?
-      pLoggedInPort = fcFindLoggedInPort( 
-             fcChip, 
-             NULL,           // don't search SCSI Nexus
-             0xFFFFFC,       // search linked list for Fabric port_id
-             NULL,           // don't search WWN
-             NULL);          // (don't care about end of list)
-
-      if( pLoggedInPort )    // If found, we have prior experience with
-                             // this port -- check whether PDISC is needed
-      {
-        if( pLoggedInPort->flogi )
+	if (FabricPortIds != NULL)	// may need logins
 	{
-	  // does the switch support FDISC?? (FLOGI for now...)
-          loginType = ELS_FLOGI;  // prior FLOGI still valid
-	}
-        else
-          loginType = ELS_FLOGI;  // expired FLOGI
-      }
-      else                      // first FLOGI?
-        loginType = ELS_FLOGI;  
-
-
-      fchs.s_id = 0xFFFFFE;   // well known F_Port address
-
-      // Fabrics are not required to support FDISC, and
-      // it's not clear if that helps us anyway, since
-      // we'll want a Name Service Request to re-verify
-      // visible devices...
-      // Consequently, we always want our upper 16 bit
-      // port_id to be zero (we'll be rejected if we
-      // use our prior port_id if we've been plugged into
-      // a different switch port).
-      // Trick Tachyon to send to ALPA 0 (see TL/TS UG, pg 87)
-      // If our ALPA is 55h for instance, we want the FC frame
-      // s_id to be 0x000055, while Tach's my_al_pa register
-      // must be 0x000155, to force an OPN at ALPA 0 
-      // (the Fabric port)
-      fcChip->Registers.my_al_pa &= 0xFF; // only use ALPA for FLOGI
-      writel( fcChip->Registers.my_al_pa | 0x0100,  
-        fcChip->Registers.ReMapMemBase + TL_MEM_TACH_My_ID);
-    }
+		int LastPort = 0;
+		i = 0;
+		while (!LastPort) {
+			// port IDs From NSR payload; byte swap needed?
+			BigEndianSwap((u8 *) FabricPortIds, (u8 *) & PortIds[i], 4);
+
+//			printk("FPortId[%d] %Xh ", i, PortIds[i]);
+			if (PortIds[i] & 0x80000000)
+				LastPort = 1;
+
+			PortIds[i] &= 0xFFFFFF;	// get 24-bit port_id
+			// some non-Fabric devices (like the Crossroads Fibre/Scsi bridge)
+			// erroneously use ALPA 0.
+			if (PortIds[i])	// need non-zero port_id...
+				i++;
+
+			if (i >= number_of_al_pa)	// (in)sanity check
+				break;
+			FabricPortIds++;	// next...
+		}
 
-    else // not FLOGI...
-    {
-      // should we send PLOGI or PDISC?  Check if any prior port_id
-      // (e.g. alpa) completed a PLOGI/PRLI exchange by checking 
-      // the pdisc flag.
-
-      pLoggedInPort = fcFindLoggedInPort( 
-             fcChip, 
-             NULL,           // don't search SCSI Nexus
-             fchs.s_id,      // search linked list for al_pa
-             NULL,           // don't search WWN
-             NULL);          // (don't care about end of list)
-
-             
-
-      if( pLoggedInPort )      // If found, we have prior experience with
-                             // this port -- check whether PDISC is needed
-      {
-        if( pLoggedInPort->pdisc )
+		NumberOfPorts = i;
+//    printk("NumberOf Fabric ports %d", NumberOfPorts);
+	}
+	else			// need to send logins on our "local" link
 	{
-          loginType = ELS_PDISC;  // prior PLOGI and PRLI maybe still valid
-           
+		// are we a loop port?  If so, check for reception of LILP frame,
+		// and if received use it (SANMark requirement)
+		if (fcChip->Options.LILPin) {
+			int j = 0;
+			// sanity check on number of ALPAs from LILP frame...
+			// For format of LILP frame, see FC-AL specs or 
+			// "Fibre Channel Bench Reference", J. Stai, 1995 (ISBN 1-879936-17-8)
+			// First byte is number of ALPAs
+			i = fcChip->LILPmap[0] >= (32 * 4) ? 32 * 4 : fcChip->LILPmap[0];
+			NumberOfPorts = i;
+//			printk(" LILP alpa count %d ", i);
+			while (i > 0) {
+				PortIds[j] = fcChip->LILPmap[1 + j];
+				j++;
+				i--;
+			}
+		}
+		else		// have to send login to everybody
+		{
+			int j = 0;
+			i = number_of_al_pa;
+			NumberOfPorts = i;
+			while (i > 0) {
+				PortIds[j] = valid_al_pa[j];	// all legal ALPAs
+				j++;
+				i--;
+			}
+		}
 	}
-        else
-          loginType = ELS_PLOGI;  // prior knowledge, but can't use PDISC
-      }
-      else                      // never talked to this port_id before
-        loginType = ELS_PLOGI;  // prior knowledge, but can't use PDISC
-    }
-
-
-    
-    ulStatus = cpqfcTSBuildExchange(
-          cpqfcHBAdata,
-          loginType,            // e.g. PLOGI
-          &fchs,        // no incoming frame (we are originator)
-          NULL,         // no data (no scatter/gather list)
-          &ExchangeID );// fcController->fcExchanges index, -1 if failed
 
-    if( !ulStatus ) // Exchange setup OK?
-    {
-      ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
-      if( !ulStatus )
-      {
-          // submitted to Tach's Outbound Que (ERQ PI incremented)
-          // waited for completion for ELS type (Login frames issued
-          // synchronously)
+	// Now we have a copy of the port_ids (and how many)...
+	for (i = 0; i < NumberOfPorts; i++) {
+		// 24-bit FC Port ID
+		fchs.s_id = PortIds[i];	// note: only 8-bits used for ALPA
+		// don't log into ourselves (Linux Scsi disk scan will stop on
+		// no TARGET support error on us, and quit trying for rest of devices)
+		if ((fchs.s_id & 0xFF) == (fcChip->Registers.my_al_pa & 0xFF))
+			continue;
+		// fabric login needed?
+		if ((fchs.s_id == 0) || (fcChip->Options.fabric == 1)) {
+			fcChip->Options.flogi = 1;	// fabric needs longer for login
+			// Do we need FLOGI or FDISC?
+			pLoggedInPort = fcFindLoggedInPort(fcChip, NULL,	// don't search SCSI Nexus
+							   0xFFFFFC,	// search linked list for Fabric port_id
+							   NULL,	// don't search WWN
+							   NULL);	// (don't care about end of list)
+
+			if (pLoggedInPort)	// If found, we have prior experience with
+				// this port -- check whether PDISC is needed
+			{
+				if (pLoggedInPort->flogi) {
+					// does the switch support FDISC?? (FLOGI for now...)
+					loginType = ELS_FLOGI;	// prior FLOGI still valid
+				} else
+					loginType = ELS_FLOGI;	// expired FLOGI
+			} else	// first FLOGI?
+				loginType = ELS_FLOGI;
+
+			fchs.s_id = 0xFFFFFE;	// well known F_Port address
+
+			// Fabrics are not required to support FDISC, and
+			// it's not clear if that helps us anyway, since
+			// we'll want a Name Service Request to re-verify
+			// visible devices...
+			// Consequently, we always want our upper 16 bit
+			// port_id to be zero (we'll be rejected if we
+			// use our prior port_id if we've been plugged into
+			// a different switch port).
+			// Trick Tachyon to send to ALPA 0 (see TL/TS UG, pg 87)
+			// If our ALPA is 55h for instance, we want the FC frame
+			// s_id to be 0x000055, while Tach's my_al_pa register
+			// must be 0x000155, to force an OPN at ALPA 0 
+			// (the Fabric port)
+			fcChip->Registers.my_al_pa &= 0xFF;	// only use ALPA for FLOGI
+			writel(fcChip->Registers.my_al_pa | 0x0100, fcChip->Registers.ReMapMemBase + TL_MEM_TACH_My_ID);
+		}
+		else		// not FLOGI...
+		{
+			// should we send PLOGI or PDISC?  Check if any prior port_id
+			// (e.g. alpa) completed a PLOGI/PRLI exchange by checking 
+			// the pdisc flag.
+
+			pLoggedInPort = fcFindLoggedInPort(fcChip, NULL,	// don't search SCSI Nexus
+							   fchs.s_id,	// search linked list for al_pa
+							   NULL,	// don't search WWN
+							   NULL);	// (don't care about end of list)
+
+			if (pLoggedInPort)	// If found, we have prior experience with
+				// this port -- check whether PDISC is needed
+			{
+				if (pLoggedInPort->pdisc) {
+					loginType = ELS_PDISC;	// prior PLOGI and PRLI maybe still valid
+				} else
+					loginType = ELS_PLOGI;	// prior knowledge, but can't use PDISC
+			} else	// never talked to this port_id before
+				loginType = ELS_PLOGI;	// prior knowledge, but can't use PDISC
+		}
 
-	if( loginType == ELS_PDISC )
-	{
-	  // now, we really shouldn't Revalidate SEST exchanges until
-	  // we get an ACC reply from our target and verify that
-	  // the target address/WWN is unchanged.  However, when a fast
-	  // target gets the PDISC, they can send SEST Exchange data
-	  // before we even get around to processing the PDISC ACC.
-	  // Consequently, we lose the I/O.
-	  // To avoid this, go ahead and Revalidate when the PDISC goes
-	  // out, anticipating that the ACC will be truly acceptable
-	  // (this happens 99.9999....% of the time).
-	  // If we revalidate a SEST write, and write data goes to a
-	  // target that is NOT the one we originated the WRITE to,
-	  // that target is required (FCP-SCSI specs, etc) to discard 
-	  // our WRITE data.
-
-          // Re-validate SEST entries (Tachyon hardware assists)
-          RevalidateSEST( cpqfcHBAdata->HostAdapter, pLoggedInPort); 
-    //TriggerHBA( fcChip->Registers.ReMapMemBase, 1);
-	}
-      }
-      else  // give up immediately on error
-      {
+		ulStatus = cpqfcTSBuildExchange(dev, loginType,	// e.g. PLOGI
+						&fchs,	// no incoming frame (we are originator)
+						NULL,	// no data (no scatter/gather list)
+						&ExchangeID);	// fcController->fcExchanges index, -1 if failed
+
+		if (!ulStatus)	// Exchange setup OK?
+		{
+			ulStatus = cpqfcTSStartExchange(dev, ExchangeID);
+			if (!ulStatus) {
+				// submitted to Tach's Outbound Que (ERQ PI incremented)
+				// waited for completion for ELS type (Login frames issued
+				// synchronously)
+
+				if (loginType == ELS_PDISC) {
+					// now, we really shouldn't Revalidate SEST exchanges until
+					// we get an ACC reply from our target and verify that
+					// the target address/WWN is unchanged.  However, when a fast
+					// target gets the PDISC, they can send SEST Exchange data
+					// before we even get around to processing the PDISC ACC.
+					// Consequently, we lose the I/O.
+					// To avoid this, go ahead and Revalidate when the PDISC goes
+					// out, anticipating that the ACC will be truly acceptable
+					// (this happens 99.9999....% of the time).
+					// If we revalidate a SEST write, and write data goes to a
+					// target that is NOT the one we originated the WRITE to,
+					// that target is required (FCP-SCSI specs, etc) to discard 
+					// our WRITE data.
+
+					// Re-validate SEST entries (Tachyon hardware assists)
+					RevalidateSEST(dev->HostAdapter, pLoggedInPort);
+					//TriggerHBA( fcChip->Registers.ReMapMemBase, 1);
+				}
+			} else	// give up immediately on error
+			{
 #ifdef LOGIN_DBG
-        printk("SendLogins: fcStartExchange failed: %Xh\n", ulStatus );
+				printk("SendLogins: fcStartExchange failed: %Xh\n", ulStatus);
 #endif
-        break;
-      }
+				break;
+			}
+
 
-              
-      if( fcChip->Registers.FMstatus.value & 0x080 ) // LDn during Port Disc.
-      {
-        ulStatus = LNKDWN_OSLS;
+			if (fcChip->Registers.FMstatus.value & 0x080)	// LDn during Port Disc.
+			{
+				ulStatus = LNKDWN_OSLS;
 #ifdef LOGIN_DBG
-        printk("SendLogins: PortDisc aborted (LDn) @alpa %Xh\n", fchs.s_id);
+				printk("SendLogins: PortDisc aborted (LDn) @alpa %Xh\n", fchs.s_id);
 #endif
-        break;
-      }
-        // Check the exchange for bad status (i.e. FrameTimeOut),
-        // and complete on bad status (most likely due to BAD_ALPA)
-        // on LDn, DPC function may already complete (ABORT) a started
-        // exchange, so check type first (type = 0 on complete).
-      if( Exchanges->fcExchange[ExchangeID].status )
-      {
-#ifdef LOGIN_DBG 
- 	printk("completing x_ID %X on status %Xh\n", 
-          ExchangeID, Exchanges->fcExchange[ExchangeID].status);
+				break;
+			}
+			// Check the exchange for bad status (i.e. FrameTimeOut),
+			// and complete on bad status (most likely due to BAD_ALPA)
+			// on LDn, DPC function may already complete (ABORT) a started
+			// exchange, so check type first (type = 0 on complete).
+			if (Exchanges->fcExchange[ExchangeID].status) {
+#ifdef LOGIN_DBG
+				printk("completing x_ID %X on status %Xh\n", ExchangeID, Exchanges->fcExchange[ExchangeID].status);
 #endif
-        cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID);
-      }
-    }
-    else   // Xchange setup failed...
-    {
+				cpqfcTSCompleteExchange(dev->PciDev, fcChip, ExchangeID);
+			}
+		} else		// Xchange setup failed...
+		{
 #ifdef LOGIN_DBG
-      printk("FC: cpqfcTSBuildExchange failed: %Xh\n", ulStatus );
+			printk("FC: cpqfcTSBuildExchange failed: %Xh\n", ulStatus);
 #endif
-      break;
-    }
-  }
-  if( !ulStatus )
-  {
-    // set the event signifying that all ALPAs were sent out.
+			break;
+		}
+	}
+	if (!ulStatus) {
+		// set the event signifying that all ALPAs were sent out.
 #ifdef LOGIN_DBG
-    printk("SendLogins: PortDiscDone\n");
+		printk("SendLogins: PortDiscDone\n");
 #endif
-    cpqfcHBAdata->PortDiscDone = 1;
-
-
-    // TL/TS UG, pg. 184
-    // 0x0065 = 100ms for RT_TOV
-    // 0x01f5 = 500ms for ED_TOV
-    fcChip->Registers.ed_tov.value = 0x006501f5L; 
-    writel( fcChip->Registers.ed_tov.value,
-      (fcChip->Registers.ed_tov.address));
-
-    // set the LP_TOV back to ED_TOV (i.e. 500 ms)
-    writel( 0x00000010, fcChip->Registers.ReMapMemBase +TL_MEM_FM_TIMEOUT2);
-  }
-  else
-  {
-    printk("SendLogins: failed at xchng %Xh, alpa %Xh, status %Xh\n", 
-      ExchangeID, fchs.s_id, ulStatus);
-  }
-  LEAVE("SendLogins");
+		dev->PortDiscDone = 1;
+		// TL/TS UG, pg. 184
+		// 0x0065 = 100ms for RT_TOV
+		// 0x01f5 = 500ms for ED_TOV
+		fcChip->Registers.ed_tov.value = 0x006501f5L;
+		writel(fcChip->Registers.ed_tov.value, (fcChip->Registers.ed_tov.address));
+
+		// set the LP_TOV back to ED_TOV (i.e. 500 ms)
+		writel(0x00000010, fcChip->Registers.ReMapMemBase + TL_MEM_FM_TIMEOUT2);
+	} else {
+		printk("SendLogins: failed at xchng %Xh, alpa %Xh, status %Xh\n", ExchangeID, fchs.s_id, ulStatus);
+	}
+	LEAVE("SendLogins");
 
 }
 
-
 // for REPORT_LUNS documentation, see "In-Depth Exploration of Scsi",
 // D. Deming, 1994, pg 7-19 (ISBN 1-879936-08-9)
-static void ScsiReportLunsDone(Scsi_Cmnd *Cmnd)
+static void ScsiReportLunsDone(Scsi_Cmnd * Cmnd)
 {
-  struct Scsi_Host *HostAdapter = Cmnd->host;
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  PFC_LOGGEDIN_PORT pLoggedInPort; 
-  int LunListLen=0;
-  int i;
-  ULONG x_ID = 0xFFFFFFFF;
-  UCHAR *ucBuff = Cmnd->request_buffer;
-
-//  printk("cpqfcTS: ReportLunsDone \n");
-  // first, we need to find the Exchange for this command,
-  // so we can find the fcPort struct to make the indicated
-  // changes.
-  for( i=0; i< TACH_SEST_LEN; i++)
-  {
-    if( Exchanges->fcExchange[i].type   // exchange defined?
-                   &&
-       (Exchanges->fcExchange[i].Cmnd == Cmnd) ) // matches?
-	      
-    {
-      x_ID = i;  // found exchange!
-      break;
-    }
-  }
-  if( x_ID == 0xFFFFFFFF)
-  {
-//    printk("cpqfcTS: ReportLuns failed - no FC Exchange\n");
-    goto Done;  // Report Luns FC Exchange gone; 
-                // exchange probably Terminated by Implicit logout
-  }
+	struct Scsi_Host *shpnt = Cmnd->host;
+	CPQFCHBA *dev = (CPQFCHBA *) shpnt->hostdata;
+	PTACHYON fcChip = &dev->fcChip;
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	PFC_LOGGEDIN_PORT pLoggedInPort;
+	int LunListLen = 0;
+	int i;
+	u32 x_ID = 0xFFFFFFFF;
+	u8 *ucBuff = Cmnd->request_buffer;
+
+	//  printk("cpqfcTS: ReportLunsDone \n");
+	// first, we need to find the Exchange for this command,
+	// so we can find the fcPort struct to make the indicated
+	// changes.
+	for (i = 0; i < TACH_SEST_LEN; i++) {
+		if (Exchanges->fcExchange[i].type	// exchange defined?
+		    && (Exchanges->fcExchange[i].Cmnd == Cmnd))	// matches?
+
+		{
+			x_ID = i;	// found exchange!
+			break;
+		}
+	}
+	if (x_ID == 0xFFFFFFFF) {
+//		printk("cpqfcTS: ReportLuns failed - no FC Exchange\n");
+		goto Done;	// Report Luns FC Exchange gone; 
+		// exchange probably Terminated by Implicit logout
+	}
 
+	// search linked list for the port_id we sent INQUIRY to
+	pLoggedInPort = fcFindLoggedInPort(fcChip, NULL,	// DON'T search Scsi Nexus (we will set it)
+					   Exchanges->fcExchange[x_ID].fchs.d_id & 0xFFFFFF, NULL,	// DON'T search linked list for FC WWN
+					   NULL);	// DON'T care about end of list
+
+	if (!pLoggedInPort) {
+//		printk("cpqfcTS: ReportLuns failed - device gone\n");
+		goto Done;	// error! can't find logged in Port
+	}
+	LunListLen = ucBuff[3];
+	LunListLen += ucBuff[2] >> 8;
 
-  // search linked list for the port_id we sent INQUIRY to
-  pLoggedInPort = fcFindLoggedInPort( fcChip,
-    NULL,     // DON'T search Scsi Nexus (we will set it)
-    Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF,        
-    NULL,     // DON'T search linked list for FC WWN
-    NULL);    // DON'T care about end of list
- 
-  if( !pLoggedInPort )
-  {
-//    printk("cpqfcTS: ReportLuns failed - device gone\n");
-    goto Done; // error! can't find logged in Port
-  }    
-  LunListLen = ucBuff[3];
-  LunListLen += ucBuff[2]>>8;
+	if (!LunListLen)	// failed
+	{
+		// generically speaking, a soft error means we should retry...
+		if ((Cmnd->result >> 16) == DID_SOFT_ERROR) {
+			if (((Cmnd->sense_buffer[2] & 0xF) == 0x6) && (Cmnd->sense_buffer[12] == 0x29))	// Sense Code "reset"
+			{
+				TachFCHDR_GCMND *fchs = &Exchanges->fcExchange[x_ID].fchs;
+				// did we fail because of "check condition, device reset?"
+				// e.g. the device was reset (i.e., at every power up)
+				// retry the Report Luns
+
+				// who are we sending it to?
+				// we know this because we have a copy of the command
+				// frame from the original Report Lun command -
+				// switch the d_id/s_id fields, because the Exchange Build
+				// context is "reply to source".
 
-  if( !LunListLen )  // failed
-  {
-    // generically speaking, a soft error means we should retry...
-    if( (Cmnd->result >> 16) == DID_SOFT_ERROR )
-    {
-      if( ((Cmnd->sense_buffer[2] & 0xF) == 0x6) &&
-	        (Cmnd->sense_buffer[12] == 0x29) ) // Sense Code "reset"
-      {
-        TachFCHDR_GCMND *fchs = &Exchanges->fcExchange[ x_ID].fchs;
-      // did we fail because of "check condition, device reset?"
-      // e.g. the device was reset (i.e., at every power up)
-      // retry the Report Luns
-      
-      // who are we sending it to?
-      // we know this because we have a copy of the command
-      // frame from the original Report Lun command -
-      // switch the d_id/s_id fields, because the Exchange Build
-      // context is "reply to source".
-      
-        fchs->s_id = fchs->d_id; // (temporarily re-use the struct)
-        cpqfcTSPutLinkQue( cpqfcHBAdata, SCSI_REPORT_LUNS, fchs );
-      }
-    }
-    else  // probably, the device doesn't support Report Luns
-      pLoggedInPort->ScsiNexus.VolumeSetAddressing = 0;  
-  }
-  else  // we have LUN info - check VSA mode
-  {
-    // for now, assume all LUNs will have same addr mode
-    // for VSA, payload byte 8 will be 0x40; otherwise, 0
-    pLoggedInPort->ScsiNexus.VolumeSetAddressing = ucBuff[8];  
-      
-    // Since we got a Report Luns answer, set lun masking flag
-    pLoggedInPort->ScsiNexus.LunMasking = 1;
+				fchs->s_id = fchs->d_id;	// (temporarily re-use the struct)
+				cpqfcTSPutLinkQue(dev, SCSI_REPORT_LUNS, fchs);
+			}
+		} else		// probably, the device doesn't support Report Luns
+			pLoggedInPort->ScsiNexus.VolumeSetAddressing = 0;
+	} else			// we have LUN info - check VSA mode
+	{
+		// for now, assume all LUNs will have same addr mode
+		// for VSA, payload byte 8 will be 0x40; otherwise, 0
+		pLoggedInPort->ScsiNexus.VolumeSetAddressing = ucBuff[8];
 
-    if( LunListLen > 8*CPQFCTS_MAX_LUN)   // We expect CPQFCTS_MAX_LUN max
-      LunListLen = 8*CPQFCTS_MAX_LUN;
+		// Since we got a Report Luns answer, set lun masking flag
+		pLoggedInPort->ScsiNexus.LunMasking = 1;
+
+		if (LunListLen > 8 * CPQFCTS_MAX_LUN)	// We expect CPQFCTS_MAX_LUN max
+			LunListLen = 8 * CPQFCTS_MAX_LUN;
 
 /*   
-    printk("Device WWN %08X%08X Reports Luns @: ", 
-          (ULONG)(pLoggedInPort->u.liWWN &0xFFFFFFFF), 
-          (ULONG)(pLoggedInPort->u.liWWN>>32));
+		printk("Device WWN %08X%08X Reports Luns @: ", 
+			(u32)(pLoggedInPort->u.liWWN &0xFFFFFFFF), 
+			(u32)(pLoggedInPort->u.liWWN>>32));
 	    
-    for( i=8; i<LunListLen+8; i+=8)
-    {  
-      printk("%02X%02X ", ucBuff[i], ucBuff[i+1] );
-    }
-    printk("\n");
+		for( i=8; i<LunListLen+8; i+=8)
+		{  
+			printk("%02X%02X ", ucBuff[i], ucBuff[i+1] );
+		}
+		printk("\n");
 */
-    
-    // Since the device was kind enough to tell us where the
-    // LUNs are, lets ensure they are contiguous for Linux's
-    // SCSI driver scan, which expects them to start at 0.
-    // Since Linux only supports 8 LUNs, only copy the first
-    // eight from the report luns command
-
-    // e.g., the Compaq RA4x00 f/w Rev 2.54 and above may report
-    // LUNs 4001, 4004, etc., because other LUNs are masked from
-    // this HBA (owned by someone else).  We'll make those appear as
-    // LUN 0, 1... to Linux
-    {
-      int j;
-      int AppendLunList = 0;
-      // Walk through the LUN list.  The 'j' array number is
-      // Linux's lun #, while the value of .lun[j] is the target's
-      // lun #.
-      // Once we build a LUN list, it's possible for a known device 
-      // to go offline while volumes (LUNs) are added.  Later,
-      // the device will do another PLOGI ... Report Luns command,
-      // and we must not alter the existing Linux Lun map.
-      // (This will be very rare).
-      for( j=0; j < CPQFCTS_MAX_LUN; j++)
-      {
-        if( pLoggedInPort->ScsiNexus.lun[j] != 0xFF )
-	{
-	  AppendLunList = 1;
-	  break;
-	}
-      }
-      if( AppendLunList )
-      {
-	int k;
-        int FreeLunIndex;
-//        printk("cpqfcTS: AppendLunList\n");
-
-	// If we get a new Report Luns, we cannot change
-	// any existing LUN mapping! (Only additive entry)
-	// For all LUNs in ReportLun list
-	// if RL lun != ScsiNexus lun
-	//   if RL lun present in ScsiNexus lun[], continue
-	//   else find ScsiNexus lun[]==FF and add, continue
-	
-        for( i=8, j=0; i<LunListLen+8 && j< CPQFCTS_MAX_LUN; i+=8, j++)
-	{
-          if( pLoggedInPort->ScsiNexus.lun[j] != ucBuff[i+1] )
-	  {
-	    // something changed from the last Report Luns
-	    printk(" cpqfcTS: Report Lun change!\n");
-	    for( k=0, FreeLunIndex=CPQFCTS_MAX_LUN; 
-                 k < CPQFCTS_MAX_LUN; k++)
-            {
-	      if( pLoggedInPort->ScsiNexus.lun[k] == 0xFF)
-	      {
-		FreeLunIndex = k;
-		break;
-	      }
-              if( pLoggedInPort->ScsiNexus.lun[k] == ucBuff[i+1] )
-		break; // we already masked this lun
-	    }
-	    if( k >= CPQFCTS_MAX_LUN )
-	    {
-	      printk(" no room for new LUN %d\n", ucBuff[i+1]);
-	    }
-	    else if( k == FreeLunIndex )  // need to add LUN
-	    {
-	      pLoggedInPort->ScsiNexus.lun[k] = ucBuff[i+1];
-//	      printk("add [%d]->%02d\n", k, pLoggedInPort->ScsiNexus.lun[k]);
-	      
-	    }
-	    else
-	    {
-	      // lun already known
-	    }
-	    break;
-	  }
-	}
-	// print out the new list...
-	for( j=0; j< CPQFCTS_MAX_LUN; j++)
-	{
-	  if( pLoggedInPort->ScsiNexus.lun[j] == 0xFF)
-	    break; // done
-//	  printk("[%d]->%02d ", j, pLoggedInPort->ScsiNexus.lun[j]);
-	}
-      }
-      else
-      {
-//	  printk("Linux SCSI LUNs[] -> Device LUNs: ");
-	// first time - this is easy
-        for( i=8, j=0; i<LunListLen+8 && j< CPQFCTS_MAX_LUN; i+=8, j++)
-	{
-          pLoggedInPort->ScsiNexus.lun[j] = ucBuff[i+1];
-//	  printk("[%d]->%02d ", j, pLoggedInPort->ScsiNexus.lun[j]);
+
+		// Since the device was kind enough to tell us where the
+		// LUNs are, lets ensure they are contiguous for Linux's
+		// SCSI driver scan, which expects them to start at 0.
+		// Since Linux only supports 8 LUNs, only copy the first
+		// eight from the report luns command
+
+		// e.g., the Compaq RA4x00 f/w Rev 2.54 and above may report
+		// LUNs 4001, 4004, etc., because other LUNs are masked from
+		// this HBA (owned by someone else).  We'll make those appear as
+		// LUN 0, 1... to Linux
+		{
+			int j;
+			int AppendLunList = 0;
+			// Walk through the LUN list.  The 'j' array number is
+			// Linux's lun #, while the value of .lun[j] is the target's
+			// lun #.
+			// Once we build a LUN list, it's possible for a known device 
+			// to go offline while volumes (LUNs) are added.  Later,
+			// the device will do another PLOGI ... Report Luns command,
+			// and we must not alter the existing Linux Lun map.
+			// (This will be very rare).
+			for (j = 0; j < CPQFCTS_MAX_LUN; j++) {
+				if (pLoggedInPort->ScsiNexus.lun[j] != 0xFF) {
+					AppendLunList = 1;
+					break;
+				}
+			}
+			if (AppendLunList) {
+				int k;
+				int FreeLunIndex;
+//				printk("cpqfcTS: AppendLunList\n");
+
+				// If we get a new Report Luns, we cannot change
+				// any existing LUN mapping! (Only additive entry)
+				// For all LUNs in ReportLun list
+				// if RL lun != ScsiNexus lun
+				//   if RL lun present in ScsiNexus lun[], continue
+				//   else find ScsiNexus lun[]==FF and add, continue
+
+				for (i = 8, j = 0; i < LunListLen + 8 && j < CPQFCTS_MAX_LUN; i += 8, j++) {
+					if (pLoggedInPort->ScsiNexus.lun[j] != ucBuff[i + 1]) {
+						// something changed from the last Report Luns
+						printk(" cpqfcTS: Report Lun change!\n");
+						for (k = 0, FreeLunIndex = CPQFCTS_MAX_LUN; k < CPQFCTS_MAX_LUN; k++) {
+							if (pLoggedInPort->ScsiNexus.lun[k] == 0xFF) {
+								FreeLunIndex = k;
+								break;
+							}
+							if (pLoggedInPort->ScsiNexus.lun[k] == ucBuff[i + 1])
+								break;	// we already masked this lun
+						}
+						if (k >= CPQFCTS_MAX_LUN) {
+							printk(" no room for new LUN %d\n", ucBuff[i + 1]);
+						} else if (k == FreeLunIndex)	// need to add LUN
+						{
+							pLoggedInPort->ScsiNexus.lun[k] = ucBuff[i + 1];
+//							printk("add [%d]->%02d\n", k, pLoggedInPort->ScsiNexus.lun[k]);
+
+						} else {
+							// lun already known
+						}
+						break;
+					}
+				}
+				// print out the new list...
+				for (j = 0; j < CPQFCTS_MAX_LUN; j++) {
+					if (pLoggedInPort->ScsiNexus.lun[j] == 0xFF)
+						break;	// done
+//					printk("[%d]->%02d ", j, pLoggedInPort->ScsiNexus.lun[j]);
+				}
+			} else {
+//				printk("Linux SCSI LUNs[] -> Device LUNs: ");
+				// first time - this is easy
+				for (i = 8, j = 0; i < LunListLen + 8 && j < CPQFCTS_MAX_LUN; i += 8, j++) {
+					pLoggedInPort->ScsiNexus.lun[j] = ucBuff[i + 1];
+//					printk("[%d]->%02d ", j, pLoggedInPort->ScsiNexus.lun[j]);
+				}
+//				printk("\n");
+			}
+		}
 	}
-//	printk("\n");
-      }
-    }
-  }
 
-Done:  ;
+      Done:;
 }
 
-static void 
-call_scsi_done(Scsi_Cmnd *Cmnd)
+static void call_scsi_done(Scsi_Cmnd * Cmnd)
 {
 	// We have to reinitialize sent_command here, so the scsi-mid
 	// layer won't re-use the scsi command leaving it set incorrectly.
 	// (incorrectly for our purposes...it's normally unused.)
 
-        if (Cmnd->SCp.sent_command != 0) {	// was it a passthru?
+	if (Cmnd->SCp.sent_command != 0) {	// was it a passthru?
 		Cmnd->SCp.sent_command = 0;
 		Cmnd->result &= 0xff00ffff;
-		Cmnd->result |= (DID_PASSTHROUGH << 16);  // prevents retry
+		Cmnd->result |= (DID_PASSTHROUGH << 16);	// prevents retry
 	}
 	if (Cmnd->scsi_done != NULL)
-		(*Cmnd->scsi_done)(Cmnd);
+		(*Cmnd->scsi_done) (Cmnd);
 }
 
 // After successfully getting a "Process Login" (PRLI) from an
@@ -2939,361 +2306,301 @@
 // driver model, which expects a contiguous LUNs starting at 0,
 // will use the ReportLuns info to map from "device" to "Linux" 
 // LUNs.
-static void IssueReportLunsCommand( 
-              CPQFCHBA* cpqfcHBAdata, 
-	      TachFCHDR_GCMND* fchs)
-{
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  PFC_LOGGEDIN_PORT pLoggedInPort; 
-  Scsi_Cmnd *Cmnd;
-  LONG x_ID;
-  ULONG ulStatus;
-  UCHAR *ucBuff;
-
-  if( !cpqfcHBAdata->PortDiscDone) // cleared by LDn
-  {
-    printk("Discard Q'd ReportLun command\n");
-    goto Done;
-  }
-
-  // find the device (from port_id) we're talking to
-  pLoggedInPort = fcFindLoggedInPort( fcChip,
-        NULL,     // DON'T search Scsi Nexus 
-  	fchs->s_id & 0xFFFFFF,        
-	NULL,     // DON'T search linked list for FC WWN
-        NULL);    // DON'T care about end of list
-  if( pLoggedInPort ) // we'd BETTER find it!
-  {
-
-
-    if( !(pLoggedInPort->fcp_info & TARGET_FUNCTION) )
-      goto Done;  // forget it - FC device not a "target"
-
-    // now use the port's Scsi Command buffer for the 
-    // Report Luns Command
- 
-    Cmnd = &pLoggedInPort->ScsiCmnd; 
-    ucBuff = pLoggedInPort->ReportLunsPayload;
-    
-    memset( Cmnd, 0, sizeof(Scsi_Cmnd));
-    memset( ucBuff, 0, REPORT_LUNS_PL);
-    
-    Cmnd->scsi_done = ScsiReportLunsDone;
-    Cmnd->host = cpqfcHBAdata->HostAdapter;
-
-    Cmnd->request_buffer = pLoggedInPort->ReportLunsPayload; 
-    Cmnd->request_bufflen = REPORT_LUNS_PL; 
-	    
-    Cmnd->cmnd[0] = 0xA0;
-    Cmnd->cmnd[8] = REPORT_LUNS_PL >> 8;
-    Cmnd->cmnd[9] = (UCHAR)REPORT_LUNS_PL;
-    Cmnd->cmd_len = 12;
-
-    Cmnd->channel = pLoggedInPort->ScsiNexus.channel;
-    Cmnd->target = pLoggedInPort->ScsiNexus.target;
+static void IssueReportLunsCommand(CPQFCHBA * dev, TachFCHDR_GCMND * fchs)
+{
+	PTACHYON fcChip = &dev->fcChip;
+	PFC_LOGGEDIN_PORT pLoggedInPort;
+	Scsi_Cmnd *Cmnd;
+	s32 x_ID;
+	u32 ulStatus;
+	u8 *ucBuff;
 
-	    
-    ulStatus = cpqfcTSBuildExchange(
-      cpqfcHBAdata,
-      SCSI_IRE, 
-      fchs,
-      Cmnd,         // buffer for Report Lun data
-      &x_ID );// fcController->fcExchanges index, -1 if failed
+	if (!dev->PortDiscDone)	// cleared by LDn
+	{
+		printk("Discard Q'd ReportLun command\n");
+		goto Done;
+	}
+	// find the device (from port_id) we're talking to
+	pLoggedInPort = fcFindLoggedInPort(fcChip, NULL,	// DON'T search Scsi Nexus 
+					   fchs->s_id & 0xFFFFFF, NULL,	// DON'T search linked list for FC WWN
+					   NULL);	// DON'T care about end of list
+	if (pLoggedInPort)	// we'd BETTER find it!
+	{
 
-    if( !ulStatus ) // Exchange setup?
-    {
-      ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, x_ID );
-      if( !ulStatus )
-      {
-        // submitted to Tach's Outbound Que (ERQ PI incremented)
-        // waited for completion for ELS type (Login frames issued
-        // synchronously)
-      }
-      else
-        // check reason for Exchange not being started - we might
-        // want to Queue and start later, or fail with error
-      {
-  
-      }
-    }
 
-    else   // Xchange setup failed...
-      printk(" cpqfcTSBuildExchange failed: %Xh\n", ulStatus );
-  }
-  else     // like, we just got a PRLI ACC, and now the port is gone?
-  {
-    printk(" can't send ReportLuns - no login for port_id %Xh\n",
-	    fchs->s_id & 0xFFFFFF);
-  }
+		if (!(pLoggedInPort->fcp_info & TARGET_FUNCTION))
+			goto Done;	// forget it - FC device not a "target"
 
+		// now use the port's Scsi Command buffer for the 
+		// Report Luns Command
 
+		Cmnd = &pLoggedInPort->ScsiCmnd;
+		ucBuff = pLoggedInPort->ReportLunsPayload;
 
-Done: ;
+		memset(Cmnd, 0, sizeof(Scsi_Cmnd));
+		memset(ucBuff, 0, REPORT_LUNS_PL);
+
+		Cmnd->scsi_done = ScsiReportLunsDone;
+		Cmnd->host = dev->HostAdapter;
+
+		Cmnd->request_buffer = pLoggedInPort->ReportLunsPayload;
+		Cmnd->request_bufflen = REPORT_LUNS_PL;
+
+		Cmnd->cmnd[0] = 0xA0;
+		Cmnd->cmnd[8] = REPORT_LUNS_PL >> 8;
+		Cmnd->cmnd[9] = (u8) REPORT_LUNS_PL;
+		Cmnd->cmd_len = 12;
+
+		Cmnd->channel = pLoggedInPort->ScsiNexus.channel;
+		Cmnd->target = pLoggedInPort->ScsiNexus.target;
+
+
+		ulStatus = cpqfcTSBuildExchange(dev, SCSI_IRE, fchs, Cmnd,	// buffer for Report Lun data
+						&x_ID);	// fcController->fcExchanges index, -1 if failed
+
+		if (!ulStatus)	// Exchange setup?
+		{
+			ulStatus = cpqfcTSStartExchange(dev, x_ID);
+			if (!ulStatus) {
+				// submitted to Tach's Outbound Que (ERQ PI incremented)
+				// waited for completion for ELS type (Login frames issued
+				// synchronously)
+			} else
+				// check reason for Exchange not being started - we might
+				// want to Queue and start later, or fail with error
+			{
+			}
+		}
 
+		else		// Xchange setup failed...
+			printk(" cpqfcTSBuildExchange failed: %Xh\n", ulStatus);
+	} else			// like, we just got a PRLI ACC, and now the port is gone?
+	{
+		printk(" can't send ReportLuns - no login for port_id %Xh\n", fchs->s_id & 0xFFFFFF);
+	}
+Done:;
 }
 
-
-
-
-
-
-
-static void CompleteBoardLockCmnd( CPQFCHBA *cpqfcHBAdata)
+static void CompleteBoardLockCmnd(CPQFCHBA * dev)
 {
-  int i;
-  for( i = CPQFCTS_REQ_QUEUE_LEN-1; i>= 0; i--)
-  {
-    if( cpqfcHBAdata->BoardLockCmnd[i] != NULL )
-    {
-      Scsi_Cmnd *Cmnd = cpqfcHBAdata->BoardLockCmnd[i];
-      cpqfcHBAdata->BoardLockCmnd[i] = NULL;
-      Cmnd->result = (DID_SOFT_ERROR << 16);  // ask for retry
-//      printk(" BoardLockCmnd[%d] %p Complete, chnl/target/lun %d/%d/%d\n",
-//        i,Cmnd, Cmnd->channel, Cmnd->target, Cmnd->lun);
-      call_scsi_done(Cmnd);
-    }
-  }
+	int i;
+	for (i = CPQFCTS_REQ_QUEUE_LEN - 1; i >= 0; i--) {
+		if (dev->BoardLockCmnd[i] != NULL) {
+			Scsi_Cmnd *Cmnd = dev->BoardLockCmnd[i];
+			dev->BoardLockCmnd[i] = NULL;
+			Cmnd->result = (DID_SOFT_ERROR << 16);	// ask for retry
+//			printk(" BoardLockCmnd[%d] %p Complete, chnl/target/lun %d/%d/%d\n",
+//				i,Cmnd, Cmnd->channel, Cmnd->target, Cmnd->lun);
+			call_scsi_done(Cmnd);
+		}
+	}
 }
 
+// runs every 1 second for FC exchange timeouts and implicit FC device logouts
 
+void cpqfcTSheartbeat(unsigned long ptr)
+{
+	CPQFCHBA *dev = (CPQFCHBA *) ptr;
+	PTACHYON fcChip = &dev->fcChip;
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts;
+	u32 i;
+	unsigned long flags;
+	DECLARE_MUTEX_LOCKED(BoardLock);
 
+	PCI_TRACE(0xA8)
 
+	if (dev->BoardLock)	// Worker Task Running?
+		goto Skip;
 
+	spin_lock_irqsave(&io_request_lock, flags);	// STOP _que function
 
-// runs every 1 second for FC exchange timeouts and implicit FC device logouts
-
-void cpqfcTSheartbeat( unsigned long ptr )
-{
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)ptr;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts; 
-  ULONG i;
-  unsigned long flags;
-  DECLARE_MUTEX_LOCKED(BoardLock);
-  
-  PCI_TRACE( 0xA8)
-
-  if( cpqfcHBAdata->BoardLock) // Worker Task Running?
-    goto Skip;
-
-  spin_lock_irqsave( &io_request_lock, flags); // STOP _que function
-
-  PCI_TRACE( 0xA8)
-
-
-  cpqfcHBAdata->BoardLock = &BoardLock; // stop Linux SCSI command queuing
-  
-  // release the IO lock (and re-enable interrupts)
-  spin_unlock_irqrestore( &io_request_lock, flags);
-  
-  // Ensure no contention from  _quecommand or Worker process 
-  CPQ_SPINLOCK_HBA( cpqfcHBAdata)
-  
-  PCI_TRACE( 0xA8)
-  
-
-  disable_irq( cpqfcHBAdata->HostAdapter->irq);  // our IRQ
-
-  // Complete the "bad target" commands (normally only used during
-  // initialization, since we aren't supposed to call "scsi_done"
-  // inside the queuecommand() function).  (this is overly contorted,
-  // scsi_done can be safely called from queuecommand for
-  // this bad target case.  May want to simplify this later)
+	PCI_TRACE(0xA8)
 
-  for( i=0; i< CPQFCTS_MAX_TARGET_ID; i++)
-  {
-    if( cpqfcHBAdata->BadTargetCmnd[i] )
-    {
-      Scsi_Cmnd *Cmnd = cpqfcHBAdata->BadTargetCmnd[i];
-      cpqfcHBAdata->BadTargetCmnd[i] = NULL;
-      Cmnd->result = (DID_BAD_TARGET << 16);
-      call_scsi_done(Cmnd);
-    }
-    else
-      break;
-  }
+	dev->BoardLock = &BoardLock;	// stop Linux SCSI command queuing
 
-  
-  // logged in ports -- re-login check (ports required to verify login with
-  // PDISC after LIP within 2 secs)
-
-  // prevent contention
-  while( pLoggedInPort ) // for all ports which are expecting
-                         // PDISC after the next LIP, check to see if
-                         // time is up!
-  {
-      // Important: we only detect "timeout" condition on TRANSITION
-      // from non-zero to zero
-    if( pLoggedInPort->LOGO_timer )  // time-out "armed"?
-    {
-      if( !(--pLoggedInPort->LOGO_timer) ) // DEC from 1 to 0?
-      {
-          // LOGOUT time!  Per PLDA, PDISC hasn't complete in 2 secs, so
-          // issue LOGO request and destroy all I/O with other FC port(s).
-        
-/*          
-        printk(" ~cpqfcTS heartbeat: LOGOut!~ ");
-        printk("Linux SCSI Chanl/Target %d/%d (port_id %06Xh) WWN %08X%08X\n", 
-        pLoggedInPort->ScsiNexus.channel, 
-        pLoggedInPort->ScsiNexus.target, 
-	pLoggedInPort->port_id,
-          (ULONG)(pLoggedInPort->u.liWWN &0xFFFFFFFF), 
-          (ULONG)(pLoggedInPort->u.liWWN>>32));
+	// release the IO lock (and re-enable interrupts)
+	spin_unlock_irqrestore(&io_request_lock, flags);
 
-*/
-        cpqfcTSImplicitLogout( cpqfcHBAdata, pLoggedInPort);
+	// Ensure no contention from  _quecommand or Worker process 
+	CPQ_SPINLOCK_HBA(dev)
 
-      }
-      // else simply decremented - maybe next time...
-    }
-    pLoggedInPort = pLoggedInPort->pNextPort;
-  }
+	PCI_TRACE(0xA8)
 
+	disable_irq(dev->HostAdapter->irq);	// our IRQ
 
+	// Complete the "bad target" commands (normally only used during
+	// initialization, since we aren't supposed to call "scsi_done"
+	// inside the queuecommand() function).  (this is overly contorted,
+	// scsi_done can be safely called from queuecommand for
+	// this bad target case.  May want to simplify this later)
 
-  
-  
-  // ************  FC EXCHANGE TIMEOUT CHECK **************
-  
-  for( i=0; i< TACH_MAX_XID; i++)
-  {
-    if( Exchanges->fcExchange[i].type )  // exchange defined?
-    {
+	for (i = 0; i < CPQFCTS_MAX_TARGET_ID; i++) {
+		if (dev->BadTargetCmnd[i]) {
+			Scsi_Cmnd *Cmnd = dev->BadTargetCmnd[i];
+			dev->BadTargetCmnd[i] = NULL;
+			Cmnd->result = (DID_BAD_TARGET << 16);
+			call_scsi_done(Cmnd);
+		} else
+			break;
+	}
 
-      if( !Exchanges->fcExchange[i].timeOut ) // time expired
-      {
-        // Set Exchange timeout status
-        Exchanges->fcExchange[i].status |= FC2_TIMEOUT;
-
-        if( i >= TACH_SEST_LEN ) // Link Service Exchange
-        {
-          cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, i);  // Don't "abort" LinkService
-        }
-        
-        else  // SEST Exchange TO -- may post ABTS to Worker Thread Que
-        {
-	  // (Make sure we don't keep timing it out; let other functions
-	  // complete it or set the timeOut as needed)
-	  Exchanges->fcExchange[i].timeOut = 30000; // seconds default
-
-          if( Exchanges->fcExchange[i].type 
-                  & 
-              (BLS_ABTS | BLS_ABTS_ACC )  )
-          {
-	    // For BLS_ABTS*, an upper level might still have
-	    // an outstanding command waiting for low-level completion.
-	    // Also, in the case of a WRITE, we MUST get confirmation
-	    // of either ABTS ACC or RJT before re-using the Exchange.
-	    // It's possible that the RAID cache algorithm can hang
-	    // if we fail to complete a WRITE to a LBA, when a READ
-	    // comes later to that same LBA.  Therefore, we must
-	    // ensure that the target verifies receipt of ABTS for
-	    // the exchange
-	   
-	    printk("~TO Q'd ABTS (x_ID %Xh)~ ", i); 
-//            TriggerHBA( fcChip->Registers.ReMapMemBase);
-
-	    // On timeout of a ABTS exchange, check to
-	    // see if the FC device has a current valid login.
-	    // If so, restart it.
-	    pLoggedInPort = fcFindLoggedInPort( fcChip,
-              Exchanges->fcExchange[i].Cmnd, // find Scsi Nexus
-              0,        // DON'T search linked list for FC port id
-	      NULL,     // DON'T search linked list for FC WWN
-              NULL);    // DON'T care about end of list
-
-	    // device exists?
-	    if( pLoggedInPort ) // device exists?
-	    {
-	      if( pLoggedInPort->prli ) // logged in for FCP-SCSI?
-	      {
-		// attempt to restart the ABTS
-		printk(" ~restarting ABTS~ ");
-                cpqfcTSStartExchange( cpqfcHBAdata, i );
-
-	      }
-	    }
-          }
-	  else  // not an ABTS
-	  { 
-           
-            // We expect the WorkerThread to change the xchng type to
-            // abort and set appropriate timeout.
-            cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &i ); // timed-out
-	  }
-        }
-      }
-      else  // time not expired...
-      {
-        // decrement timeout: 1 or more seconds left
-        --Exchanges->fcExchange[i].timeOut;
-      }
-    }
-  }
 
+	// logged in ports -- re-login check (ports required to verify login with
+	// PDISC after LIP within 2 secs)
 
-  enable_irq( cpqfcHBAdata->HostAdapter->irq);
- 
+	// prevent contention
+	while (pLoggedInPort)	// for all ports which are expecting
+				// PDISC after the next LIP, check to see if
+				// time is up!
+	{
+		// Important: we only detect "timeout" condition on TRANSITION
+		// from non-zero to zero
+		if (pLoggedInPort->LOGO_timer)	// time-out "armed"?
+		{
+			if (!(--pLoggedInPort->LOGO_timer))	// DEC from 1 to 0?
+			{
+				// LOGOUT time!  Per PLDA, PDISC hasn't complete in 2 secs, so
+				// issue LOGO request and destroy all I/O with other FC port(s).
 
-  CPQ_SPINUNLOCK_HBA( cpqfcHBAdata)
+/*          
+			        printk(" ~cpqfcTS heartbeat: LOGOut!~ ");
+        			printk("Linux SCSI Chanl/Target %d/%d (port_id %06Xh) WWN %08X%08X\n", 
+				        pLoggedInPort->ScsiNexus.channel, 
+				        pLoggedInPort->ScsiNexus.target, 
+					pLoggedInPort->port_id,
+				        (u32)(pLoggedInPort->u.liWWN &0xFFFFFFFF), 
+				        (u32)(pLoggedInPort->u.liWWN>>32));
+*/
+				cpqfcTSImplicitLogout(dev, pLoggedInPort);
 
-  cpqfcHBAdata->BoardLock = NULL; // Linux SCSI commands may be queued
+			}
+			// else simply decremented - maybe next time...
+		}
+		pLoggedInPort = pLoggedInPort->pNextPort;
+	}
 
-  // Now, complete any Cmnd we Q'd up while BoardLock was held
+	// ************  FC EXCHANGE TIMEOUT CHECK **************
 
-  CompleteBoardLockCmnd( cpqfcHBAdata);
- 
+	for (i = 0; i < TACH_MAX_XID; i++) {
+		if (Exchanges->fcExchange[i].type)	// exchange defined?
+		{
+
+			if (!Exchanges->fcExchange[i].timeOut)	// time expired
+			{
+				// Set Exchange timeout status
+				Exchanges->fcExchange[i].status |= FC2_TIMEOUT;
+
+				if (i >= TACH_SEST_LEN)	// Link Service Exchange
+				{
+					cpqfcTSCompleteExchange(dev->PciDev, fcChip, i);	// Don't "abort" LinkService
+				}
+				else	// SEST Exchange TO -- may post ABTS to Worker Thread Que
+				{
+					// (Make sure we don't keep timing it out; let other functions
+					// complete it or set the timeOut as needed)
+					Exchanges->fcExchange[i].timeOut = 30000;	// seconds default
+
+					if (Exchanges->fcExchange[i].type & (BLS_ABTS | BLS_ABTS_ACC)) {
+						// For BLS_ABTS*, an upper level might still have
+						// an outstanding command waiting for low-level completion.
+						// Also, in the case of a WRITE, we MUST get confirmation
+						// of either ABTS ACC or RJT before re-using the Exchange.
+						// It's possible that the RAID cache algorithm can hang
+						// if we fail to complete a WRITE to a LBA, when a READ
+						// comes later to that same LBA.  Therefore, we must
+						// ensure that the target verifies receipt of ABTS for
+						// the exchange
+
+						printk("~TO Q'd ABTS (x_ID %Xh)~ ", i);
+//						TriggerHBA( fcChip->Registers.ReMapMemBase);
+
+						// On timeout of a ABTS exchange, check to
+						// see if the FC device has a current valid login.
+						// If so, restart it.
+						pLoggedInPort = fcFindLoggedInPort(fcChip, Exchanges->fcExchange[i].Cmnd,	// find Scsi Nexus
+										   0,	// DON'T search linked list for FC port id
+										   NULL,	// DON'T search linked list for FC WWN
+										   NULL);	// DON'T care about end of list
+						// device exists?
+						if (pLoggedInPort)	// device exists?
+						{
+							if (pLoggedInPort->prli)	// logged in for FCP-SCSI?
+							{
+								// attempt to restart the ABTS
+								printk(" ~restarting ABTS~ ");
+								cpqfcTSStartExchange(dev, i);
+
+							}
+						}
+					} else	// not an ABTS
+					{
+
+						// We expect the WorkerThread to change the xchng type to
+						// abort and set appropriate timeout.
+						cpqfcTSPutLinkQue(dev, BLS_ABTS, &i);	// timed-out
+					}
+				}
+			} else	// time not expired...
+			{
+				// decrement timeout: 1 or more seconds left
+				--Exchanges->fcExchange[i].timeOut;
+			}
+		}
+	}
 
-  // restart the timer to run again (1 sec later)
+	enable_irq(dev->HostAdapter->irq);
+	CPQ_SPINUNLOCK_HBA(dev)
+	dev->BoardLock = NULL;	// Linux SCSI commands may be queued
+	// Now, complete any Cmnd we Q'd up while BoardLock was held
+	CompleteBoardLockCmnd(dev);
+	// restart the timer to run again (1 sec later)
 Skip:
-  mod_timer( &cpqfcHBAdata->cpqfcTStimer, jiffies + HZ);
-  
-  PCI_TRACEO( i, 0xA8)
-  return;
+	mod_timer(&dev->cpqfcTStimer, jiffies + HZ);
+	PCI_TRACEO(i, 0xA8)
+	return;
 }
 
 
 // put valid FC-AL physical address in spec order
-static const UCHAR valid_al_pa[]={
-    0xef, 0xe8, 0xe4, 0xe2, 
-    0xe1, 0xE0, 0xDC, 0xDA, 
-    0xD9, 0xD6, 0xD5, 0xD4, 
-    0xD3, 0xD2, 0xD1, 0xCe, 
-    0xCd, 0xCc, 0xCb, 0xCa, 
-    0xC9, 0xC7, 0xC6, 0xC5, 
-    0xC3, 0xBc, 0xBa, 0xB9,
-    0xB6, 0xB5, 0xB4, 0xB3, 
-    0xB2, 0xB1, 0xae, 0xad,
-    0xAc, 0xAb, 0xAa, 0xA9, 
-
-    0xA7, 0xA6, 0xA5, 0xA3, 
-    0x9f, 0x9e, 0x9d, 0x9b, 
-    0x98, 0x97, 0x90, 0x8f, 
-    0x88, 0x84, 0x82, 0x81, 
-    0x80, 0x7c, 0x7a, 0x79, 
-    0x76, 0x75, 0x74, 0x73, 
-    0x72, 0x71, 0x6e, 0x6d, 
-    0x6c, 0x6b, 0x6a, 0x69, 
-    0x67, 0x66, 0x65, 0x63, 
-    0x5c, 0x5a, 0x59, 0x56, 
-    
-    0x55, 0x54, 0x53, 0x52, 
-    0x51, 0x4e, 0x4d, 0x4c, 
-    0x4b, 0x4a, 0x49, 0x47, 
-    0x46, 0x45, 0x43, 0x3c,
-    0x3a, 0x39, 0x36, 0x35, 
-    0x34, 0x33, 0x32, 0x31, 
-    0x2e, 0x2d, 0x2c, 0x2b, 
-    0x2a, 0x29, 0x27, 0x26, 
-    0x25, 0x23, 0x1f, 0x1E,
-    0x1d, 0x1b, 0x18, 0x17, 
-
-    0x10, 0x0f, 8, 4, 2, 1 }; // ALPA 0 (Fabric) is special case
-
-const int number_of_al_pa = (sizeof(valid_al_pa) );
+static const u8 valid_al_pa[] = {
+	0xef, 0xe8, 0xe4, 0xe2,
+	0xe1, 0xE0, 0xDC, 0xDA,
+	0xD9, 0xD6, 0xD5, 0xD4,
+	0xD3, 0xD2, 0xD1, 0xCe,
+	0xCd, 0xCc, 0xCb, 0xCa,
+	0xC9, 0xC7, 0xC6, 0xC5,
+	0xC3, 0xBc, 0xBa, 0xB9,
+	0xB6, 0xB5, 0xB4, 0xB3,
+	0xB2, 0xB1, 0xae, 0xad,
+	0xAc, 0xAb, 0xAa, 0xA9,
+
+	0xA7, 0xA6, 0xA5, 0xA3,
+	0x9f, 0x9e, 0x9d, 0x9b,
+	0x98, 0x97, 0x90, 0x8f,
+	0x88, 0x84, 0x82, 0x81,
+	0x80, 0x7c, 0x7a, 0x79,
+	0x76, 0x75, 0x74, 0x73,
+	0x72, 0x71, 0x6e, 0x6d,
+	0x6c, 0x6b, 0x6a, 0x69,
+	0x67, 0x66, 0x65, 0x63,
+	0x5c, 0x5a, 0x59, 0x56,
+
+	0x55, 0x54, 0x53, 0x52,
+	0x51, 0x4e, 0x4d, 0x4c,
+	0x4b, 0x4a, 0x49, 0x47,
+	0x46, 0x45, 0x43, 0x3c,
+	0x3a, 0x39, 0x36, 0x35,
+	0x34, 0x33, 0x32, 0x31,
+	0x2e, 0x2d, 0x2c, 0x2b,
+	0x2a, 0x29, 0x27, 0x26,
+	0x25, 0x23, 0x1f, 0x1E,
+	0x1d, 0x1b, 0x18, 0x17,
 
+	0x10, 0x0f, 8, 4, 2, 1
+};				// ALPA 0 (Fabric) is special case
 
+const int number_of_al_pa = (sizeof(valid_al_pa));
 
 // this function looks up an al_pa from the table of valid al_pa's
 // we decrement from the last decimal loop ID, because soft al_pa
@@ -3306,16 +2613,16 @@
 //  -1      - invalid al_pa (not all 8 bit values are legal)
 
 #if (0)
-static int GetLoopID( ULONG al_pa )
+static int GetLoopID(u32 al_pa)
 {
-  int i;
+	int i;
 
-  for( i = number_of_al_pa -1; i >= 0; i--)  // dec.
-  {
-    if( valid_al_pa[i] == (UCHAR)al_pa )  // take lowest 8 bits
-      return i;  // success - found valid al_pa; return decimal LoopID
-  }
-  return -1; // failed - not found
+	for (i = number_of_al_pa - 1; i >= 0; i--)	// dec.
+	{
+		if (valid_al_pa[i] == (u8) al_pa)	// take lowest 8 bits
+			return i;	// success - found valid al_pa; return decimal LoopID
+	}
+	return -1;		// failed - not found
 }
 #endif
 
@@ -3330,739 +2637,620 @@
 //     (NULL if not found)
 //   pLastLoggedInPort - ptr to last struct (for adding new ones)
 // 
-PFC_LOGGEDIN_PORT  fcFindLoggedInPort( 
-  PTACHYON fcChip, 
-  Scsi_Cmnd *Cmnd, // search linked list for Scsi Nexus (channel/target/lun)
-  ULONG port_id,   // search linked list for al_pa, or
-  UCHAR wwn[8],    // search linked list for WWN, or...
-  PFC_LOGGEDIN_PORT *pLastLoggedInPort )
-             
-{
-  PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts; 
-  BOOLEAN target_id_valid=FALSE;
-  BOOLEAN port_id_valid=FALSE;
-  BOOLEAN wwn_valid=FALSE;
-  int i;
-
-
-  if( Cmnd != NULL )
-    target_id_valid = TRUE;
-  
-  else if( port_id ) // note! 24-bit NULL address is illegal
-    port_id_valid = TRUE;
+PFC_LOGGEDIN_PORT fcFindLoggedInPort(PTACHYON fcChip, Scsi_Cmnd * Cmnd,	// search linked list for Scsi Nexus (channel/target/lun)
+				     u32 port_id,	// search linked list for al_pa, or
+				     u8 wwn[8],	// search linked list for WWN, or...
+				     PFC_LOGGEDIN_PORT * pLastLoggedInPort)
+{
+	PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts;
+	u8 target_id_valid = 0;
+	u8 port_id_valid = 0;
+	u8 wwn_valid = 0;
+	int i;
+
+
+	if (Cmnd != NULL)
+		target_id_valid = 1;
+
+	else if (port_id)	// note! 24-bit NULL address is illegal
+		port_id_valid = 1;
+
+	else {
+		if (wwn)	// non-null arg? (OK to pass NULL when not searching WWN)
+		{
+			for (i = 0; i < 8; i++)	// valid WWN passed?  NULL WWN invalid
+			{
+				if (wwn[i] != 0)
+					wwn_valid = 1;	// any non-zero byte makes (presumably) valid
+			}
+		}
+	}
+	// check other options ...
 
-  else
-  {
-    if( wwn ) // non-null arg? (OK to pass NULL when not searching WWN)
-    {
-      for( i=0; i<8; i++)  // valid WWN passed?  NULL WWN invalid
-      {
-        if( wwn[i] != 0 )
-          wwn_valid = TRUE;  // any non-zero byte makes (presumably) valid
-      }
-    }
-  }
-                // check other options ...
 
+	// In case multiple search options are given, we use a priority
+	// scheme:
+	// While valid pLoggedIn Ptr
+	//   If port_id is valid
+	//     if port_id matches, return Ptr
+	//   If wwn is valid
+	//     if wwn matches, return Ptr
+	//   Next Ptr in list
+	//
+	// Return NULL (not found)
 
-  // In case multiple search options are given, we use a priority
-  // scheme:
-  // While valid pLoggedIn Ptr
-  //   If port_id is valid
-  //     if port_id matches, return Ptr
-  //   If wwn is valid
-  //     if wwn matches, return Ptr
-  //   Next Ptr in list
-  //
-  // Return NULL (not found)
- 
-      
-  while( pLoggedInPort ) // NULL marks end of list (1st ptr always valid)
-  {
-    if( pLastLoggedInPort ) // caller's pointer valid?
-      *pLastLoggedInPort = pLoggedInPort;  // end of linked list
-    
-    if( target_id_valid )
-    {
-      // check Linux Scsi Cmnd for channel/target Nexus match
-      // (all luns are accessed through matching "pLoggedInPort")
-      if( (pLoggedInPort->ScsiNexus.target == Cmnd->target)
-                &&
-          (pLoggedInPort->ScsiNexus.channel == Cmnd->channel))
-      {
-        // For "passthru" modes, the IOCTL caller is responsible
-	// for setting the FCP-LUN addressing
-	if( !Cmnd->SCp.sent_command ) // NOT passthru?
+
+	while (pLoggedInPort)	// NULL marks end of list (1st ptr always valid)
 	{
-	
-          // set the FCP-LUN addressing type
-          Cmnd->SCp.phase = pLoggedInPort->ScsiNexus.VolumeSetAddressing;	
-
-          // set the Device Type we got from the snooped INQUIRY string
-	  Cmnd->SCp.Message = pLoggedInPort->ScsiNexus.InqDeviceType;
-
-	  // handle LUN masking; if not "default" (illegal) lun value,
-	  // the use it.  These lun values are set by a successful
-	  // Report Luns command
-          if( pLoggedInPort->ScsiNexus.LunMasking == 1) 
-	  {
-            // we KNOW all the valid LUNs... 0xFF is invalid!
-            Cmnd->SCp.have_data_in = pLoggedInPort->ScsiNexus.lun[Cmnd->lun];
-	    if (pLoggedInPort->ScsiNexus.lun[Cmnd->lun] == 0xFF)
-		return NULL;
-	    // printk("xlating lun %d to 0x%02x\n", Cmnd->lun, 
-            //	pLoggedInPort->ScsiNexus.lun[Cmnd->lun]);
-	  }
-	  else
-	    Cmnd->SCp.have_data_in = Cmnd->lun; // Linux & target luns match
-	}
-	break; // found it!
-      }
-    }
-    
-    if( port_id_valid ) // look for alpa first
-    {
-      if( pLoggedInPort->port_id == port_id )
-          break;  // found it!
-    }
-    if( wwn_valid ) // look for wwn second
-    {
+		if (pLastLoggedInPort)	// caller's pointer valid?
+			*pLastLoggedInPort = pLoggedInPort;	// end of linked list
 
-      if( !memcmp( &pLoggedInPort->u.ucWWN[0], &wwn[0], 8))
-      {  
-                 // all 8 bytes of WWN match
-        break;   // found it!
-      }
-    }
-                
-    pLoggedInPort = pLoggedInPort->pNextPort; // try next port
-  }
+		if (target_id_valid) {
+			// check Linux Scsi Cmnd for channel/target Nexus match
+			// (all luns are accessed through matching "pLoggedInPort")
+			if ((pLoggedInPort->ScsiNexus.target == Cmnd->target)
+			    && (pLoggedInPort->ScsiNexus.channel == Cmnd->channel)) {
+				// For "passthru" modes, the IOCTL caller is responsible
+				// for setting the FCP-LUN addressing
+				if (!Cmnd->SCp.sent_command)	// NOT passthru?
+				{
+
+					// set the FCP-LUN addressing type
+					Cmnd->SCp.phase = pLoggedInPort->ScsiNexus.VolumeSetAddressing;
+
+					// set the Device Type we got from the snooped INQUIRY string
+					Cmnd->SCp.Message = pLoggedInPort->ScsiNexus.InqDeviceType;
+
+					// handle LUN masking; if not "default" (illegal) lun value,
+					// the use it.  These lun values are set by a successful
+					// Report Luns command
+					if (pLoggedInPort->ScsiNexus.LunMasking == 1) {
+						// we KNOW all the valid LUNs... 0xFF is invalid!
+						if (Cmnd->lun > sizeof(pLoggedInPort->ScsiNexus.lun)){
+							// printk("cpqfcTS FATAL: Invalid LUN index !!!!\n ");
+							return NULL;
+						}
+						Cmnd->SCp.have_data_in = pLoggedInPort->ScsiNexus.lun[Cmnd->lun];
+						if (pLoggedInPort->ScsiNexus.lun[Cmnd->lun] == 0xFF)
+							return NULL;
+						// printk("xlating lun %d to 0x%02x\n", Cmnd->lun, 
+						//  pLoggedInPort->ScsiNexus.lun[Cmnd->lun]);
+					} else
+						Cmnd->SCp.have_data_in = Cmnd->lun;	// Linux & target luns match
+				}
+				break;	// found it!
+			}
+		}
 
-  return pLoggedInPort;
-}
+		if (port_id_valid)	// look for alpa first
+		{
+			if (pLoggedInPort->port_id == port_id)
+				break;	// found it!
+		}
+		if (wwn_valid)	// look for wwn second
+		{
 
+			if (!memcmp(&pLoggedInPort->u.ucWWN[0], &wwn[0], 8)) {
+				// all 8 bytes of WWN match
+				break;	// found it!
+			}
+		}
 
+		pLoggedInPort = pLoggedInPort->pNextPort;	// try next port
+	}
 
+	return pLoggedInPort;
+}
 
 // 
 // We need to examine the SEST table and re-validate
 // any open Exchanges for this LoggedInPort
 // To make Tachyon pay attention, Freeze FCP assists,
 // set VAL bits, Unfreeze FCP assists
-static void RevalidateSEST( struct Scsi_Host *HostAdapter, 
-		        PFC_LOGGEDIN_PORT pLoggedInPort)
+static void RevalidateSEST(struct Scsi_Host *shpnt, PFC_LOGGEDIN_PORT pLoggedInPort)
 {
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  ULONG x_ID;
-  BOOLEAN TachFroze = FALSE;
-  
-  
-  // re-validate any SEST exchanges that are permitted
-  // to survive the link down (e.g., good PDISC performed)
-  for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
-  {
-
-    // If the SEST entry port_id matches the pLoggedInPort,
-    // we need to re-validate
-    if( (Exchanges->fcExchange[ x_ID].type == SCSI_IRE)
-         || 
-	(Exchanges->fcExchange[ x_ID].type == SCSI_IWE))
-    {
-		     
-      if( (Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF)  // (24-bit port ID)
-            == pLoggedInPort->port_id) 
-      {
-//	printk(" re-val xID %Xh ", x_ID);
-        if( !TachFroze )  // freeze if not already frozen
-          TachFroze |= FreezeTach( cpqfcHBAdata);
-        fcChip->SEST->u[ x_ID].IWE.Hdr_Len |= 0x80000000; // set VAL bit
-      }
-    } 
-  }
-
-  if( TachFroze) 
-  { 
-    fcChip->UnFreezeTachyon( fcChip, 2);  // both ERQ and FCP assists
-  }
-} 
+	CPQFCHBA *dev = (CPQFCHBA *) shpnt->hostdata;
+	PTACHYON fcChip = &dev->fcChip;
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	u32 x_ID;
+	u8 TachFroze = 0;
+
+
+	// re-validate any SEST exchanges that are permitted
+	// to survive the link down (e.g., good PDISC performed)
+	for (x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++) {
+
+		// If the SEST entry port_id matches the pLoggedInPort,
+		// we need to re-validate
+		if ((Exchanges->fcExchange[x_ID].type == SCSI_IRE)
+		    || (Exchanges->fcExchange[x_ID].type == SCSI_IWE)) {
+			if ((Exchanges->fcExchange[x_ID].fchs.d_id & 0xFFFFFF) == pLoggedInPort->port_id) 	// (24-bit port ID)
+			{
+//				printk(" re-val xID %Xh ", x_ID);
+				if (!TachFroze)	// freeze if not already frozen
+					TachFroze |= FreezeTach(dev);
+				fcChip->SEST->u[x_ID].IWE.Hdr_Len |= 0x80000000;	// set VAL bit
+			}
+		}
+	}
+	if (TachFroze) {
+		fcChip->UnFreezeTachyon(fcChip, 2);	// both ERQ and FCP assists
+	}
+}
 
 
 // Complete an Linux Cmnds that we Queued because
 // our FC link was down (cause immediate retry)
 
-static void UnblockScsiDevice( struct Scsi_Host *HostAdapter, 
-		        PFC_LOGGEDIN_PORT pLoggedInPort)
+static void UnblockScsiDevice(struct Scsi_Host *shpnt, PFC_LOGGEDIN_PORT pLoggedInPort)
 {
-//  Scsi_Device *sdev = HostAdapter->host_queue;
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
-  Scsi_Cmnd* *SCptr = &cpqfcHBAdata->LinkDnCmnd[0];
-  Scsi_Cmnd *Cmnd;
-  int indx;
-
- 
-  
-  // if the device was previously "blocked", make sure
-  // we unblock it so Linux SCSI will resume
-
-  pLoggedInPort->device_blocked = FALSE; // clear our flag
-
-  // check the Link Down command ptr buffer;
-  // we can complete now causing immediate retry
-  for( indx=0; indx < CPQFCTS_REQ_QUEUE_LEN; indx++, SCptr++)
-  {
-    if( *SCptr != NULL ) // scsi command to complete?
-    {
+//  Scsi_Device *sdev = shpnt->host_queue;
+	CPQFCHBA *dev = (CPQFCHBA *) shpnt->hostdata;
+	Scsi_Cmnd **SCptr = &dev->LinkDnCmnd[0];
+	Scsi_Cmnd *Cmnd;
+	int indx;
+
+	// if the device was previously "blocked", make sure
+	// we unblock it so Linux SCSI will resume
+
+	pLoggedInPort->device_blocked = 0;	// clear our flag
+
+	// check the Link Down command ptr buffer;
+	// we can complete now causing immediate retry
+	for (indx = 0; indx < CPQFCTS_REQ_QUEUE_LEN; indx++, SCptr++) {
+		if (*SCptr != NULL)	// scsi command to complete?
+		{
 #ifdef DUMMYCMND_DBG
-      printk("complete Cmnd %p in LinkDnCmnd[%d]\n", *SCptr,indx);
+			printk("complete Cmnd %p in LinkDnCmnd[%d]\n", *SCptr, indx);
 #endif
-      Cmnd = *SCptr;
-
+			Cmnd = *SCptr;
 
-      // Are there any Q'd commands for this target?
-      if( (Cmnd->target == pLoggedInPort->ScsiNexus.target)
-	       &&
-          (Cmnd->channel == pLoggedInPort->ScsiNexus.channel) )
-      {
-        Cmnd->result = (DID_SOFT_ERROR <<16); // force retry
-        if( Cmnd->scsi_done == NULL) 
-	{
-          printk("LinkDnCmnd scsi_done ptr null, port_id %Xh\n",
-		  pLoggedInPort->port_id);
-	  Cmnd->SCp.sent_command = 0;
+			// Are there any Q'd commands for this target?
+			if ((Cmnd->target == pLoggedInPort->ScsiNexus.target)
+			    && (Cmnd->channel == pLoggedInPort->ScsiNexus.channel)) {
+				Cmnd->result = (DID_SOFT_ERROR << 16);	// force retry
+				if (Cmnd->scsi_done == NULL) {
+					printk("LinkDnCmnd scsi_done ptr null, port_id %Xh\n", pLoggedInPort->port_id);
+					Cmnd->SCp.sent_command = 0;
+				} else
+					call_scsi_done(Cmnd);
+				*SCptr = NULL;	// free this slot for next use
+			}
+		}
 	}
-	else
-	  call_scsi_done(Cmnd);
-        *SCptr = NULL;  // free this slot for next use
-      }
-    }
-  }
 }
 
-  
+
 //#define WWN_DBG 1
 
-static void SetLoginFields(
-  PFC_LOGGEDIN_PORT pLoggedInPort,
-  TachFCHDR_GCMND* fchs,
-  BOOLEAN PDisc,
-  BOOLEAN Originator)
-{
-  LOGIN_PAYLOAD logi;       // FC-PH Port Login
-  PRLI_REQUEST prli;  // copy for BIG ENDIAN switch
-  int i;
+static void SetLoginFields(PFC_LOGGEDIN_PORT pLoggedInPort, TachFCHDR_GCMND * fchs, u8 PDisc, u8 Originator)
+{
+	LOGIN_PAYLOAD logi;	// FC-PH Port Login
+	PRLI_REQUEST prli;	// copy for BIG ENDIAN switch
+	int i;
 #ifdef WWN_DBG
-  ULONG ulBuff;
+	u32 ulBuff;
 #endif
 
-  BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
+	BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & logi, sizeof(logi));
 
-  pLoggedInPort->Originator = Originator;
-  pLoggedInPort->port_id = fchs->s_id & 0xFFFFFF;
-  
-  switch( fchs->pl[0] & 0xffff )
-  {
-  case 0x00000002:  //  PLOGI or PDISC ACCept?
-    if( PDisc )     // PDISC accept
-      goto PDISC_case;
-
-  case 0x00000003:  //  ELS_PLOGI or ELS_PLOGI_ACC
-
-  // Login BB_credit typically 0 for Tachyons
-    pLoggedInPort->BB_credit = logi.cmn_services.bb_credit;
-
-    // e.g. 128, 256, 1024, 2048 per FC-PH spec
-    // We have to use this when setting up SEST Writes,
-    // since that determines frame size we send.
-    pLoggedInPort->rx_data_size = logi.class3.rx_data_size;
-    pLoggedInPort->plogi = TRUE;
-    pLoggedInPort->pdisc = FALSE;
-    pLoggedInPort->prli = FALSE;    // ELS_PLOGI resets
-    pLoggedInPort->flogi = FALSE;   // ELS_PLOGI resets
-    pLoggedInPort->logo = FALSE;    // ELS_PLOGI resets
-    pLoggedInPort->LOGO_counter = 0;// ELS_PLOGI resets
-    pLoggedInPort->LOGO_timer = 0;// ELS_PLOGI resets
-
-    // was this PLOGI to a Fabric?
-    if( pLoggedInPort->port_id == 0xFFFFFC ) // well know address
-      pLoggedInPort->flogi = TRUE;
+	pLoggedInPort->Originator = Originator;
+	pLoggedInPort->port_id = fchs->s_id & 0xFFFFFF;
+
+	switch (fchs->pl[0] & 0xffff) {
+	case 0x00000002:	//  PLOGI or PDISC ACCept?
+		if (PDisc)	// PDISC accept
+			goto PDISC_case;
+
+	case 0x00000003:	//  ELS_PLOGI or ELS_PLOGI_ACC
+
+		// Login BB_credit typically 0 for Tachyons
+		pLoggedInPort->BB_credit = logi.cmn_services.bb_credit;
+
+		// e.g. 128, 256, 1024, 2048 per FC-PH spec
+		// We have to use this when setting up SEST Writes,
+		// since that determines frame size we send.
+		pLoggedInPort->rx_data_size = logi.class3.rx_data_size;
+		pLoggedInPort->plogi = 1;
+		pLoggedInPort->pdisc = 0;
+		pLoggedInPort->prli = 0;	// ELS_PLOGI resets
+		pLoggedInPort->flogi = 0;	// ELS_PLOGI resets
+		pLoggedInPort->logo = 0;	// ELS_PLOGI resets
+		pLoggedInPort->LOGO_counter = 0;	// ELS_PLOGI resets
+		pLoggedInPort->LOGO_timer = 0;	// ELS_PLOGI resets
+
+		// was this PLOGI to a Fabric?
+		if (pLoggedInPort->port_id == 0xFFFFFC)	// well know address
+			pLoggedInPort->flogi = 1;
 
 
-    for( i=0; i<8; i++)   // copy the LOGIN port's WWN
-      pLoggedInPort->u.ucWWN[i] = logi.port_name[i];  
+		for (i = 0; i < 8; i++)	// copy the LOGIN port's WWN
+			pLoggedInPort->u.ucWWN[i] = logi.port_name[i];
 
 #ifdef WWN_DBG
-    ulBuff = (ULONG)pLoggedInPort->u.liWWN;
-    if( pLoggedInPort->Originator)
-      printk("o");
-    else
-      printk("r");
-    printk("PLOGI port_id %Xh, WWN %08X",
-      pLoggedInPort->port_id, ulBuff);
+		ulBuff = (u32) pLoggedInPort->u.liWWN;
+		if (pLoggedInPort->Originator)
+			printk("o");
+		else
+			printk("r");
+		printk("PLOGI port_id %Xh, WWN %08X", pLoggedInPort->port_id, ulBuff);
 
-    ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
-    printk("%08Xh fcPort %p\n", ulBuff, pLoggedInPort);
+		ulBuff = (u32) (pLoggedInPort->u.liWWN >> 32);
+		printk("%08Xh fcPort %p\n", ulBuff, pLoggedInPort);
 #endif
-    break;
-
-
-
-  
-  case 0x00000005:  //  ELS_LOGO (logout)
-
+		break;
 
-    pLoggedInPort->plogi = FALSE;
-    pLoggedInPort->pdisc = FALSE;
-    pLoggedInPort->prli = FALSE;   // ELS_PLOGI resets
-    pLoggedInPort->flogi = FALSE;  // ELS_PLOGI resets
-    pLoggedInPort->logo = TRUE;    // ELS_PLOGI resets
-    pLoggedInPort->LOGO_counter++; // ELS_PLOGI resets
-    pLoggedInPort->LOGO_timer = 0;
+	case 0x00000005:	//  ELS_LOGO (logout)
+		pLoggedInPort->plogi = 0;
+		pLoggedInPort->pdisc = 0;
+		pLoggedInPort->prli = 0;	// ELS_PLOGI resets
+		pLoggedInPort->flogi = 0;	// ELS_PLOGI resets
+		pLoggedInPort->logo = 1;	// ELS_PLOGI resets
+		pLoggedInPort->LOGO_counter++;	// ELS_PLOGI resets
+		pLoggedInPort->LOGO_timer = 0;
 #ifdef WWN_DBG
-    ulBuff = (ULONG)pLoggedInPort->u.liWWN;
-    if( pLoggedInPort->Originator)
-      printk("o");
-    else
-      printk("r");
-    printk("LOGO port_id %Xh, WWN %08X",
-      pLoggedInPort->port_id, ulBuff);
+		ulBuff = (u32) pLoggedInPort->u.liWWN;
+		if (pLoggedInPort->Originator)
+			printk("o");
+		else
+			printk("r");
+		printk("LOGO port_id %Xh, WWN %08X", pLoggedInPort->port_id, ulBuff);
 
-    ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
-    printk("%08Xh\n", ulBuff);
+		ulBuff = (u32) (pLoggedInPort->u.liWWN >> 32);
+		printk("%08Xh\n", ulBuff);
 #endif
-    break;
-
-
+		break;
 
-PDISC_case:
-  case 0x00000050: //  ELS_PDISC or ELS_PDISC_ACC
-    pLoggedInPort->LOGO_timer = 0;  // stop the time-out
-      
-    pLoggedInPort->prli = TRUE;     // ready to accept FCP-SCSI I/O
-    
+	PDISC_case:
+	case 0x00000050:	//  ELS_PDISC or ELS_PDISC_ACC
+		pLoggedInPort->LOGO_timer = 0;	// stop the time-out
 
-      
+		pLoggedInPort->prli = 1;	// ready to accept FCP-SCSI I/O
 #ifdef WWN_DBG
-    ulBuff = (ULONG)pLoggedInPort->u.liWWN;
-    if( pLoggedInPort->Originator)
-      printk("o");
-    else
-      printk("r");
-    printk("PDISC port_id %Xh, WWN %08X",
-      pLoggedInPort->port_id, ulBuff);
+		ulBuff = (u32) pLoggedInPort->u.liWWN;
+		if (pLoggedInPort->Originator)
+			printk("o");
+		else
+			printk("r");
+		printk("PDISC port_id %Xh, WWN %08X", pLoggedInPort->port_id, ulBuff);
 
-    ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
-    printk("%08Xh\n", ulBuff);
+		ulBuff = (u32) (pLoggedInPort->u.liWWN >> 32);
+		printk("%08Xh\n", ulBuff);
 #endif
+		break;
 
-
-    
-    break;
-
-
-    
-  case  0x1020L: //  PRLI?
-  case  0x1002L: //  PRLI ACCept?
-    BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&prli, sizeof(prli));
-
-    pLoggedInPort->fcp_info = prli.fcp_info; // target/initiator flags
-    pLoggedInPort->prli = TRUE;  // PLOGI resets, PDISC doesn't
-
-    pLoggedInPort->pdisc = TRUE;  // expect to send (or receive) PDISC
-                                  // next time
-    pLoggedInPort->LOGO_timer = 0;  // will be set next LinkDown
+	case 0x1020L:		//  PRLI?
+	case 0x1002L:		//  PRLI ACCept?
+		BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & prli, sizeof(prli));
+
+		pLoggedInPort->fcp_info = prli.fcp_info;	// target/initiator flags
+		pLoggedInPort->prli = 1;	// PLOGI resets, PDISC doesn't
+
+		pLoggedInPort->pdisc = 1;	// expect to send (or receive) PDISC
+		// next time
+		pLoggedInPort->LOGO_timer = 0;	// will be set next LinkDown
 #ifdef WWN_DBG
-    ulBuff = (ULONG)pLoggedInPort->u.liWWN;
-    if( pLoggedInPort->Originator)
-      printk("o");
-    else
-      printk("r");
-    printk("PRLI port_id %Xh, WWN %08X",
-      pLoggedInPort->port_id, ulBuff);
+		ulBuff = (u32) pLoggedInPort->u.liWWN;
+		if (pLoggedInPort->Originator)
+			printk("o");
+		else
+			printk("r");
+		printk("PRLI port_id %Xh, WWN %08X", pLoggedInPort->port_id, ulBuff);
 
-    ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
-      printk("%08Xh\n", ulBuff);
+		ulBuff = (u32) (pLoggedInPort->u.liWWN >> 32);
+		printk("%08Xh\n", ulBuff);
 #endif
-
-    break;
-
-  }
-
-  return;
+		break;
+	}
+	return;
 }
 
-
-
-
-
-
-static void BuildLinkServicePayload( PTACHYON fcChip, ULONG type, void* payload)
+static void BuildLinkServicePayload(PTACHYON fcChip, u32 type, void *payload)
 {
-  LOGIN_PAYLOAD *plogi;  // FC-PH Port Login
-  LOGIN_PAYLOAD PlogiPayload;   // copy for BIG ENDIAN switch
-  PRLI_REQUEST  *prli;          // FCP-SCSI Process Login
-  PRLI_REQUEST  PrliPayload;    // copy for BIG ENDIAN switch
-  LOGOUT_PAYLOAD  *logo;
-  LOGOUT_PAYLOAD  LogoutPayload;
-//  PRLO_REQUEST  *prlo;
-//  PRLO_REQUEST  PrloPayload;
-  REJECT_MESSAGE rjt, *prjt;
-
-  memset( &PlogiPayload, 0, sizeof( PlogiPayload));
-  plogi = &PlogiPayload;    // load into stack buffer,
-                                // then BIG-ENDIAN switch a copy to caller
-
-
-  switch( type )  // payload type can be ELS_PLOGI, ELS_PRLI, ADISC, ...
-  {
-    case ELS_FDISC:
-    case ELS_FLOGI:
-    case ELS_PLOGI_ACC:   // FC-PH PORT Login Accept
-    case ELS_PLOGI:   // FC-PH PORT Login
-    case ELS_PDISC:   // FC-PH2 Port Discovery - same payload as ELS_PLOGI
-      plogi->login_cmd = LS_PLOGI;
-      if( type == ELS_PDISC)
-        plogi->login_cmd = LS_PDISC;
-      else if( type == ELS_PLOGI_ACC )
-        plogi->login_cmd = LS_ACC;
-
-      plogi->cmn_services.bb_credit = 0x00;
-      plogi->cmn_services.lowest_ver = fcChip->lowest_FCPH_ver;
-      plogi->cmn_services.highest_ver = fcChip->highest_FCPH_ver;
-      plogi->cmn_services.bb_rx_size = TACHLITE_TS_RX_SIZE;
-      plogi->cmn_services.common_features = CONTINUOSLY_INCREASING |
-              RANDOM_RELATIVE_OFFSET;
-
-             // fill in with World Wide Name based Port Name - 8 UCHARs
-             // get from Tach registers WWN hi & lo
-      LoadWWN( fcChip, plogi->port_name, 0);
-             // fill in with World Wide Name based Node/Fabric Name - 8 UCHARs
-             // get from Tach registers WWN hi & lo
-      LoadWWN( fcChip, plogi->node_name, 1);
-
-	// For Seagate Drives.
-	//
-      plogi->cmn_services.common_features |= 0x800;
-      plogi->cmn_services.rel_offset = 0xFE;
-      plogi->cmn_services.concurrent_seq = 1;
-      plogi->class1.service_options = 0x00;
-      plogi->class2.service_options = 0x00;
-      plogi->class3.service_options = CLASS_VALID;
-      plogi->class3.initiator_control = 0x00;
-      plogi->class3.rx_data_size = MAX_RX_PAYLOAD;
-      plogi->class3.recipient_control =
-             ERROR_DISCARD | ONE_CATEGORY_SEQUENCE;
-      plogi->class3.concurrent_sequences = 1;
-      plogi->class3.open_sequences = 1;
-      plogi->vendor_id[0] = 'C'; plogi->vendor_id[1] = 'Q';
-      plogi->vendor_version[0] = 'C'; plogi->vendor_version[1] = 'Q';
-      plogi->vendor_version[2] = ' '; plogi->vendor_version[3] = '0';
-      plogi->vendor_version[4] = '0'; plogi->vendor_version[5] = '0';
-
-
-      // FLOGI specific fields... (see FC-FLA, Rev 2.7, Aug 1999, sec 5.1)
-      if( (type == ELS_FLOGI) || (type == ELS_FDISC) )
-      {
-        if( type == ELS_FLOGI )
-  	  plogi->login_cmd = LS_FLOGI;  
-	else
-  	  plogi->login_cmd = LS_FDISC;  
-
-        plogi->cmn_services.lowest_ver = 0x20;
-        plogi->cmn_services.common_features = 0x0800;
-        plogi->cmn_services.rel_offset = 0;
-        plogi->cmn_services.concurrent_seq = 0;
-
-        plogi->class3.service_options = 0x8800;
-        plogi->class3.rx_data_size = 0;
-        plogi->class3.recipient_control = 0;
-        plogi->class3.concurrent_sequences = 0;
-        plogi->class3.open_sequences = 0;
-      }
-      
-              // copy back to caller's buff, w/ BIG ENDIAN swap
-      BigEndianSwap( (UCHAR*)&PlogiPayload, payload,  sizeof(PlogiPayload));
-      break;
-
-    
-    case ELS_ACC:       // generic Extended Link Service ACCept	    
-      plogi->login_cmd = LS_ACC;
-              // copy back to caller's buff, w/ BIG ENDIAN swap
-      BigEndianSwap( (UCHAR*)&PlogiPayload, payload,  4);
-      break;
-
-
-      
-    case ELS_SCR:    // Fabric State Change Registration
-    {
-      SCR_PL scr;     // state change registration
-
-      memset( &scr, 0, sizeof(scr));
-
-      scr.command = LS_SCR;  // 0x62000000
-                             // see FC-FLA, Rev 2.7, Table A.22 (pg 82)
-      scr.function = 3;      // 1 = Events detected by Fabric
-                             // 2 = N_Port detected registration
-                             // 3 = Full registration
-      
-      // copy back to caller's buff, w/ BIG ENDIAN swap
-      BigEndianSwap( (UCHAR*)&scr, payload,  sizeof(SCR_PL));
-    }
-    
-    break;
-
-    
-    case FCS_NSR:    // Fabric Name Service Request
-    {
-      NSR_PL nsr;    // Name Server Req. payload
-
-      memset( &nsr, 0, sizeof(NSR_PL));
-
-                             // see Brocade Fabric Programming Guide,
-                             // Rev 1.3, pg 4-44
-      nsr.CT_Rev = 0x01000000;
-      nsr.FCS_Type = 0xFC020000;
-      nsr.Command_code = 0x01710000;
-      nsr.FCP = 8;
-     
-      // copy back to caller's buff, w/ BIG ENDIAN swap
-      BigEndianSwap( (UCHAR*)&nsr, payload,  sizeof(NSR_PL));
-    }
-    
-    break;
-
-
-
-    
-    case ELS_LOGO:   // FC-PH PORT LogOut
-      logo = &LogoutPayload;    // load into stack buffer,
-                                // then BIG-ENDIAN switch a copy to caller
-      logo->cmd = LS_LOGO;
-                                // load the 3 UCHARs of the node name
-                                // (if private loop, upper two UCHARs 0)
-      logo->reserved = 0;
-
-      logo->n_port_identifier[0] = (UCHAR)(fcChip->Registers.my_al_pa);
-      logo->n_port_identifier[1] =
-                     (UCHAR)(fcChip->Registers.my_al_pa>>8);
-      logo->n_port_identifier[2] =
-                     (UCHAR)(fcChip->Registers.my_al_pa>>16);
-             // fill in with World Wide Name based Port Name - 8 UCHARs
-             // get from Tach registers WWN hi & lo
-      LoadWWN( fcChip, logo->port_name, 0);
-
-      BigEndianSwap( (UCHAR*)&LogoutPayload,
-                     payload,  sizeof(LogoutPayload) );  // 16 UCHAR struct
-      break;
-
-
-    case ELS_LOGO_ACC:     // Logout Accept (FH-PH pg 149, table 74)
-      logo = &LogoutPayload;    // load into stack buffer,
-                                // then BIG-ENDIAN switch a copy to caller
-      logo->cmd = LS_ACC;
-      BigEndianSwap( (UCHAR*)&LogoutPayload, payload, 4 );  // 4 UCHAR cmnd
-      break;
-      
-
-    case ELS_RJT:          // ELS_RJT link service reject (FH-PH pg 155)
-
-      prjt = (REJECT_MESSAGE*)payload;  // pick up passed data
-      rjt.command_code = ELS_RJT;
-                       // reverse fields, because of Swap that follows...
-      rjt.vendor = prjt->reserved; // vendor specific
-      rjt.explain = prjt->reason; //
-      rjt.reason = prjt->explain; //
-      rjt.reserved = prjt->vendor; //
-                       // BIG-ENDIAN switch a copy to caller
-      BigEndianSwap( (UCHAR*)&rjt, payload, 8 );  // 8 UCHAR cmnd
-      break;
+	LOGIN_PAYLOAD *plogi;	// FC-PH Port Login
+	LOGIN_PAYLOAD PlogiPayload;	// copy for BIG ENDIAN switch
+	PRLI_REQUEST *prli;	// FCP-SCSI Process Login
+	PRLI_REQUEST PrliPayload;	// copy for BIG ENDIAN switch
+	LOGOUT_PAYLOAD *logo;
+	LOGOUT_PAYLOAD LogoutPayload;
+//	PRLO_REQUEST  *prlo;
+//	PRLO_REQUEST  PrloPayload;
+	REJECT_MESSAGE rjt, *prjt;
+
+	memset(&PlogiPayload, 0, sizeof(PlogiPayload));
+	plogi = &PlogiPayload;	// load into stack buffer,
+	// then BIG-ENDIAN switch a copy to caller
 
+	switch (type)		// payload type can be ELS_PLOGI, ELS_PRLI, ADISC, ...
+	{
+	case ELS_FDISC:
+	case ELS_FLOGI:
+	case ELS_PLOGI_ACC:	// FC-PH PORT Login Accept
+	case ELS_PLOGI:	// FC-PH PORT Login
+	case ELS_PDISC:	// FC-PH2 Port Discovery - same payload as ELS_PLOGI
+		plogi->login_cmd = LS_PLOGI;
+		if (type == ELS_PDISC)
+			plogi->login_cmd = LS_PDISC;
+		else if (type == ELS_PLOGI_ACC)
+			plogi->login_cmd = LS_ACC;
+
+		plogi->cmn_services.bb_credit = 0x00;
+		plogi->cmn_services.lowest_ver = fcChip->lowest_FCPH_ver;
+		plogi->cmn_services.highest_ver = fcChip->highest_FCPH_ver;
+		plogi->cmn_services.bb_rx_size = TACHLITE_TS_RX_SIZE;
+		plogi->cmn_services.common_features = CONTINUOSLY_INCREASING | RANDOM_RELATIVE_OFFSET;
+
+		// fill in with World Wide Name based Port Name - 8 u8s
+		// get from Tach registers WWN hi & lo
+		LoadWWN(fcChip, plogi->port_name, 0);
+		// fill in with World Wide Name based Node/Fabric Name - 8 u8s
+		// get from Tach registers WWN hi & lo
+		LoadWWN(fcChip, plogi->node_name, 1);
+
+		// For Seagate Drives.
+		//
+		plogi->cmn_services.common_features |= 0x800;
+		plogi->cmn_services.rel_offset = 0xFE;
+		plogi->cmn_services.concurrent_seq = 1;
+		plogi->class1.service_options = 0x00;
+		plogi->class2.service_options = 0x00;
+		plogi->class3.service_options = CLASS_VALID;
+		plogi->class3.initiator_control = 0x00;
+		plogi->class3.rx_data_size = MAX_RX_PAYLOAD;
+		plogi->class3.recipient_control = ERROR_DISCARD | ONE_CATEGORY_SEQUENCE;
+		plogi->class3.concurrent_sequences = 1;
+		plogi->class3.open_sequences = 1;
+		plogi->vendor_id[0] = 'C';
+		plogi->vendor_id[1] = 'Q';
+		plogi->vendor_version[0] = 'C';
+		plogi->vendor_version[1] = 'Q';
+		plogi->vendor_version[2] = ' ';
+		plogi->vendor_version[3] = '0';
+		plogi->vendor_version[4] = '0';
+		plogi->vendor_version[5] = '0';
+
+		// FLOGI specific fields... (see FC-FLA, Rev 2.7, Aug 1999, sec 5.1)
+		if ((type == ELS_FLOGI) || (type == ELS_FDISC)) {
+			if (type == ELS_FLOGI)
+				plogi->login_cmd = LS_FLOGI;
+			else
+				plogi->login_cmd = LS_FDISC;
+
+			plogi->cmn_services.lowest_ver = 0x20;
+			plogi->cmn_services.common_features = 0x0800;
+			plogi->cmn_services.rel_offset = 0;
+			plogi->cmn_services.concurrent_seq = 0;
+
+			plogi->class3.service_options = 0x8800;
+			plogi->class3.rx_data_size = 0;
+			plogi->class3.recipient_control = 0;
+			plogi->class3.concurrent_sequences = 0;
+			plogi->class3.open_sequences = 0;
+		}
+		// copy back to caller's buff, w/ BIG ENDIAN swap
+		BigEndianSwap((u8 *) & PlogiPayload, payload, sizeof(PlogiPayload));
+		break;
 
+	case ELS_ACC:		// generic Extended Link Service ACCept     
+		plogi->login_cmd = LS_ACC;
+		// copy back to caller's buff, w/ BIG ENDIAN swap
+		BigEndianSwap((u8 *) & PlogiPayload, payload, 4);
+		break;
 
+	case ELS_SCR:		// Fabric State Change Registration
+		{
+			SCR_PL scr;	// state change registration
+
+			memset(&scr, 0, sizeof(scr));
+
+			scr.command = LS_SCR;	// 0x62000000
+			// see FC-FLA, Rev 2.7, Table A.22 (pg 82)
+			scr.function = 3;	// 1 = Events detected by Fabric
+			// 2 = N_Port detected registration
+			// 3 = Full registration
 
+			// copy back to caller's buff, w/ BIG ENDIAN swap
+			BigEndianSwap((u8 *) & scr, payload, sizeof(SCR_PL));
+		}
+		break;
 
-    case ELS_PRLI_ACC:  // Process Login ACCept
-    case ELS_PRLI:  // Process Login
-    case ELS_PRLO:  // Process Logout
-      memset( &PrliPayload, 0, sizeof( PrliPayload));
-      prli = &PrliPayload;      // load into stack buffer,
+	case FCS_NSR:		// Fabric Name Service Request
+		{
+			NSR_PL nsr;	// Name Server Req. payload
+
+			memset(&nsr, 0, sizeof(NSR_PL));
+
+			// see Brocade Fabric Programming Guide,
+			// Rev 1.3, pg 4-44
+			nsr.CT_Rev = 0x01000000;
+			nsr.FCS_Type = 0xFC020000;
+			nsr.Command_code = 0x01710000;
+			nsr.FCP = 8;
 
-      if( type == ELS_PRLI )
-        prli->cmd = 0x20;  // Login
-      else if( type == ELS_PRLO )
-        prli->cmd = 0x21;  // Logout
-      else if( type == ELS_PRLI_ACC )
-      {
-        prli->cmd = 0x02;  // Login ACCept
-        prli->valid = REQUEST_EXECUTED;
-      }
+			// copy back to caller's buff, w/ BIG ENDIAN swap
+			BigEndianSwap((u8 *) & nsr, payload, sizeof(NSR_PL));
+		}
+		break;
 
+	case ELS_LOGO:		// FC-PH PORT LogOut
+		logo = &LogoutPayload;	// load into stack buffer,
+		// then BIG-ENDIAN switch a copy to caller
+		logo->cmd = LS_LOGO;
+		// load the 3 u8s of the node name
+		// (if private loop, upper two u8s 0)
+		logo->reserved = 0;
+
+		logo->n_port_identifier[0] = (u8) (fcChip->Registers.my_al_pa);
+		logo->n_port_identifier[1] = (u8) (fcChip->Registers.my_al_pa >> 8);
+		logo->n_port_identifier[2] = (u8) (fcChip->Registers.my_al_pa >> 16);
+		// fill in with World Wide Name based Port Name - 8 u8s
+		// get from Tach registers WWN hi & lo
+		LoadWWN(fcChip, logo->port_name, 0);
 
-      prli->valid |= SCSI_FCP | ESTABLISH_PAIR;
-      prli->fcp_info = READ_XFER_RDY;
-      prli->page_length = 0x10;
-      prli->payload_length = 20;
-                                // Can be initiator AND target
+		BigEndianSwap((u8 *) & LogoutPayload, payload, sizeof(LogoutPayload));	// 16 u8 struct
+		break;
 
-      if( fcChip->Options.initiator )
-        prli->fcp_info |= INITIATOR_FUNCTION;
-      if( fcChip->Options.target )
-        prli->fcp_info |= TARGET_FUNCTION;
+	case ELS_LOGO_ACC:	// Logout Accept (FH-PH pg 149, table 74)
+		logo = &LogoutPayload;	// load into stack buffer,
+		// then BIG-ENDIAN switch a copy to caller
+		logo->cmd = LS_ACC;
+		BigEndianSwap((u8 *) & LogoutPayload, payload, 4);	// 4 u8 cmnd
+		break;
 
-      BigEndianSwap( (UCHAR*)&PrliPayload, payload,  prli->payload_length);
-      break;
+	case ELS_RJT:		// ELS_RJT link service reject (FH-PH pg 155)
+		prjt = (REJECT_MESSAGE *) payload;	// pick up passed data
+		rjt.command_code = ELS_RJT;
+		// reverse fields, because of Swap that follows...
+		rjt.vendor = prjt->reserved;	// vendor specific
+		rjt.explain = prjt->reason;	//
+		rjt.reason = prjt->explain;	//
+		rjt.reserved = prjt->vendor;	//
+		// BIG-ENDIAN switch a copy to caller
+		BigEndianSwap((u8 *) & rjt, payload, 8);	// 8 u8 cmnd
+		break;
 
+	case ELS_PRLI_ACC:	// Process Login ACCept
+	case ELS_PRLI:		// Process Login
+	case ELS_PRLO:		// Process Logout
+		memset(&PrliPayload, 0, sizeof(PrliPayload));
+		prli = &PrliPayload;	// load into stack buffer,
+
+		if (type == ELS_PRLI)
+			prli->cmd = 0x20;	// Login
+		else if (type == ELS_PRLO)
+			prli->cmd = 0x21;	// Logout
+		else if (type == ELS_PRLI_ACC) {
+			prli->cmd = 0x02;	// Login ACCept
+			prli->valid = REQUEST_EXECUTED;
+		}
+		prli->valid |= SCSI_FCP | ESTABLISH_PAIR;
+		prli->fcp_info = READ_XFER_RDY;
+		prli->page_length = 0x10;
+		prli->payload_length = 20;
+		// Can be initiator AND target
+
+		if (fcChip->Options.initiator)
+			prli->fcp_info |= INITIATOR_FUNCTION;
+		if (fcChip->Options.target)
+			prli->fcp_info |= TARGET_FUNCTION;
 
+		BigEndianSwap((u8 *) & PrliPayload, payload, prli->payload_length);
+		break;
 
-    default:  // no can do - programming error
-      printk(" BuildLinkServicePayload unknown!\n");
-      break;
-  }
+	default:		// no can do - programming error
+		printk(" BuildLinkServicePayload unknown!\n");
+		break;
+	}
 }
 
-// loads 8 UCHARs for PORT name or NODE name base on
+// loads 8 u8s for PORT name or NODE name base on
 // controller's WWN.
-void LoadWWN( PTACHYON fcChip, UCHAR* dest, UCHAR type)
+void LoadWWN(PTACHYON fcChip, u8 * dest, u8 type)
 {
-  UCHAR* bPtr, i;
-
-  switch( type )
-  {
-    case 0:  // Port_Name
-      bPtr = (UCHAR*)&fcChip->Registers.wwn_hi;
-      for( i =0; i<4; i++)
-        dest[i] = *bPtr++;
-      bPtr = (UCHAR*)&fcChip->Registers.wwn_lo;
-      for( i =4; i<8; i++)
-        dest[i] = *bPtr++;
-      break;
-    case 1:  // Node/Fabric _Name
-      bPtr = (UCHAR*)&fcChip->Registers.wwn_hi;
-      for( i =0; i<4; i++)
-        dest[i] = *bPtr++;
-      bPtr = (UCHAR*)&fcChip->Registers.wwn_lo;
-      for( i =4; i<8; i++)
-        dest[i] = *bPtr++;
-      break;
-  }
-  
-}
+	u8 *bPtr, i;
 
+	switch (type) {
+	case 0:		// Port_Name
+		bPtr = (u8 *) & fcChip->Registers.wwn_hi;
+		for (i = 0; i < 4; i++)
+			dest[i] = *bPtr++;
+		bPtr = (u8 *) & fcChip->Registers.wwn_lo;
+		for (i = 4; i < 8; i++)
+			dest[i] = *bPtr++;
+		break;
+	case 1:		// Node/Fabric _Name
+		bPtr = (u8 *) & fcChip->Registers.wwn_hi;
+		for (i = 0; i < 4; i++)
+			dest[i] = *bPtr++;
+		bPtr = (u8 *) & fcChip->Registers.wwn_lo;
+		for (i = 4; i < 8; i++)
+			dest[i] = *bPtr++;
+		break;
+	}
 
+}
 
 // We check the Port Login payload for required values.  Note that
 // ELS_PLOGI and ELS_PDISC (Port DISCover) use the same payload.
 
+int verify_PLOGI(PTACHYON fcChip, TachFCHDR_GCMND * fchs, u32 * reject_explain)
+{
+	LOGIN_PAYLOAD login;
 
-int verify_PLOGI( PTACHYON fcChip,
-                  TachFCHDR_GCMND* fchs, 
-                  ULONG* reject_explain)
-{
-  LOGIN_PAYLOAD	login;
-
-                  // source, dest, len (should be mult. of 4)
-  BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&login,  sizeof(login));
-
-                            // check FC version
-                            // if other port's highest supported version
-                            // is less than our lowest, and 
-                            // if other port's lowest
-  if( login.cmn_services.highest_ver < fcChip->lowest_FCPH_ver ||
-      login.cmn_services.lowest_ver > fcChip->highest_FCPH_ver )
-  {
-    *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, OPTIONS_ERROR);
-    return LOGICAL_ERROR;
-  }
-
-                            // Receive Data Field Size must be >=128
-                            // per FC-PH
-  if (login.cmn_services.bb_rx_size < 128)
-  {
-    *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, DATA_FIELD_SIZE_ERROR);
-    return LOGICAL_ERROR;
-  }
+	// source, dest, len (should be mult. of 4)
+	BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & login, sizeof(login));
 
-                            // Only check Class 3 params
-  if( login.class3.service_options & CLASS_VALID)
-  {
-    if (login.class3.rx_data_size < 128)
-    {
-      *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, INVALID_CSP);
-      return LOGICAL_ERROR;
-    }
-    if( login.class3.initiator_control & XID_REQUIRED)
-    {
-      *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, INITIATOR_CTL_ERROR);
-      return LOGICAL_ERROR;
-    }
-  }
-  return 0;   // success
+	// check FC version
+	// if other port's highest supported version
+	// is less than our lowest, and 
+	// if other port's lowest
+	if (login.cmn_services.highest_ver < fcChip->lowest_FCPH_ver || login.cmn_services.lowest_ver > fcChip->highest_FCPH_ver) {
+		*reject_explain = LS_RJT_REASON(LOGICAL_ERROR, OPTIONS_ERROR);
+		return LOGICAL_ERROR;
+	}
+	// Receive Data Field Size must be >=128
+	// per FC-PH
+	if (login.cmn_services.bb_rx_size < 128) {
+		*reject_explain = LS_RJT_REASON(LOGICAL_ERROR, DATA_FIELD_SIZE_ERROR);
+		return LOGICAL_ERROR;
+	}
+	// Only check Class 3 params
+	if (login.class3.service_options & CLASS_VALID) {
+		if (login.class3.rx_data_size < 128) {
+			*reject_explain = LS_RJT_REASON(LOGICAL_ERROR, INVALID_CSP);
+			return LOGICAL_ERROR;
+		}
+		if (login.class3.initiator_control & XID_REQUIRED) {
+			*reject_explain = LS_RJT_REASON(LOGICAL_ERROR, INITIATOR_CTL_ERROR);
+			return LOGICAL_ERROR;
+		}
+	}
+	return 0;		// success
 }
 
-
-
-
-int verify_PRLI( TachFCHDR_GCMND* fchs, ULONG* reject_explain)
+int verify_PRLI(TachFCHDR_GCMND * fchs, u32 * reject_explain)
 {
-  PRLI_REQUEST prli;  // buffer for BIG ENDIAN
+	PRLI_REQUEST prli;	// buffer for BIG ENDIAN
 
-                  // source, dest, len (should be mult. of 4)
-  BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&prli,  sizeof(prli));
+	// source, dest, len (should be mult. of 4)
+	BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & prli, sizeof(prli));
 
-  if( prli.fcp_info == 0 )  // i.e., not target or initiator?
-  {
-    *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, OPTIONS_ERROR);
-    return LOGICAL_ERROR;
-  }
+	if (prli.fcp_info == 0)	// i.e., not target or initiator?
+	{
+		*reject_explain = LS_RJT_REASON(LOGICAL_ERROR, OPTIONS_ERROR);
+		return LOGICAL_ERROR;
+	}
 
-  return 0;  // success
+	return 0;		// success
 }
 
-
-// SWAP UCHARs as required by Fibre Channel (i.e. BIG ENDIAN)
+// SWAP u8s as required by Fibre Channel (i.e. BIG ENDIAN)
 // INPUTS:
-//   source   - ptr to LITTLE ENDIAN ULONGS
-//   cnt      - number of UCHARs to switch (should be mult. of ULONG)
+//   source   - ptr to LITTLE ENDIAN u32S
+//   cnt      - number of u8s to switch (should be mult. of u32)
 // OUTPUTS:
 //   dest     - ptr to BIG ENDIAN copy
 // RETURN:
 //   none
 //
-void BigEndianSwap( UCHAR *source, UCHAR *dest,  USHORT cnt)
+void BigEndianSwap(u8 * source, u8 * dest, u16 cnt)
 {
-  int i,j;
+	int i, j;
 
-  source+=3;   // start at MSB of 1st ULONG
-  for( j=0; j < cnt; j+=4, source+=4, dest+=4)  // every ULONG
-  {
-    for( i=0; i<4; i++)  // every UCHAR in ULONG
-          *(dest+i) = *(source-i);
-  }
+	source += 3;		// start at MSB of 1st u32
+	for (j = 0; j < cnt; j += 4, source += 4, dest += 4)	// every u32
+	{
+		for (i = 0; i < 4; i++)	// every u8 in u32
+			*(dest + i) = *(source - i);
+	}
 }
 
-
-
-
 // Build FC Exchanges............
 
-static void  buildFCPstatus( 
-  PTACHYON fcChip, 
-  ULONG ExchangeID);
-
-static LONG FindFreeExchange( PTACHYON fcChip, ULONG type );
-
-static ULONG build_SEST_sgList( 
-  struct pci_dev *pcidev,
-  ULONG *SESTalPairStart,
-  Scsi_Cmnd *Cmnd,
-  ULONG *sgPairs,
-  PSGPAGES *sgPages_head  // link list of TL Ext. S/G pages from O/S Pool
-);
-
-static int build_FCP_payload( Scsi_Cmnd *Cmnd, 
-  UCHAR* payload, ULONG type, ULONG fcp_dl );
-
+static void buildFCPstatus(PTACHYON fcChip, u32 ExchangeID);
+static s32 FindFreeExchange(PTACHYON fcChip, u32 type);
+static u32 build_SEST_sgList(struct pci_dev *pcidev, u32 * SESTalPairStart, Scsi_Cmnd * Cmnd, u32 * sgPairs, PSGPAGES * sgPages_head);	// link list of TL Ext. S/G pages from O/S Pool
+static int build_FCP_payload(Scsi_Cmnd * Cmnd, u8 * payload, u32 type, u32 fcp_dl);
 
 /*
                              IRB
@@ -4118,7 +3306,7 @@
 // SEST entry, and several frame headers and data buffers all
 // logically linked together.
 // Inputs:
-//   cpqfcHBAdata  - controller struct
+//   dev  - controller struct
 //   type          - PLOGI, SCSI_IWE, etc.
 //   InFCHS        - Incoming Tachlite FCHS which prompted this exchange
 //                   (only s_id set if we are originating)
@@ -4143,990 +3331,807 @@
 // return success
 
 //sbuildex
-ULONG cpqfcTSBuildExchange(
-  CPQFCHBA *cpqfcHBAdata,
-  ULONG type, // e.g. PLOGI
-  TachFCHDR_GCMND* InFCHS,  // incoming FCHS
-  void *Data,               // the CDB, scatter/gather, etc.  
-  LONG *fcExchangeIndex )   // points to allocated exchange, 
-{
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  ULONG ulStatus = 0;  // assume OK
-  USHORT ox_ID, rx_ID=0xFFFF;
-  ULONG SfsLen=0L;
-  TachLiteIRB* pIRB;
-  IRBflags IRB_flags;
-  UCHAR *pIRB_flags = (UCHAR*)&IRB_flags;
-  TachFCHDR_GCMND* CMDfchs;
-  TachFCHDR* dataHDR;     // 32 byte HEADER ONLY FCP-DATA buffer
-  TachFCHDR_RSP* rspHDR;     // 32 byte header + RSP payload
-  Scsi_Cmnd *Cmnd = (Scsi_Cmnd*)Data;   // Linux Scsi CDB, S/G, ...
-  TachLiteIWE* pIWE;
-  TachLiteIRE* pIRE;
-  TachLiteTWE* pTWE;
-  TachLiteTRE* pTRE;
-  ULONG fcp_dl;           // total byte length of DATA transferred
-  ULONG fl;               // frame length (FC frame size, 128, 256, 512, 1024)
-  ULONG sgPairs;          // number of valid scatter/gather pairs
-  int FCP_SCSI_command;
-  BA_ACC_PAYLOAD *ba_acc;
-  BA_RJT_PAYLOAD *ba_rjt;
-
-                          // check passed ARGS
-  if( !fcChip->ERQ )      // NULL ptr means uninitialized Tachlite chip
-    return INVALID_ARGS;
-
-
-  if( type == SCSI_IRE ||
-      type == SCSI_TRE ||
-      type == SCSI_IWE ||
-      type == SCSI_TWE)
-    FCP_SCSI_command = 1;
-
-  else
-    FCP_SCSI_command = 0;
-
-
-                     // for commands that pass payload data (e.g. SCSI write)
-                     // examine command struct - verify that the
-                     // length of s/g buffers is adequate for total payload
-                     // length (end of list is NULL address)
-
-  if( FCP_SCSI_command )
-  {
-    if( Data )     // must have data descriptor (S/G list -- at least
-                   // one address with at least 1 byte of data)
-    {
-      // something to do (later)?
-    }
-
-    else
-      return INVALID_ARGS;  // invalid DATA ptr
-  }
-
-    
-
-         // we can build an Exchange for later Queuing (on the TL chip)
-         // if an empty slot is available in the DevExt for this controller
-         // look for available Exchange slot...
-
-  if( type != FCP_RESPONSE &&
-      type != BLS_ABTS &&
-      type != BLS_ABTS_ACC )  // already have Exchange slot!
-    *fcExchangeIndex = FindFreeExchange( fcChip, type );
-
-  if( *fcExchangeIndex != -1 )   // Exchange is available?
-  {
-                     // assign tmp ptr (shorthand)
-    CMDfchs = &Exchanges->fcExchange[ *fcExchangeIndex].fchs; 
-
-    if( Cmnd != NULL ) // (necessary for ABTS cases)
-    {
-      Exchanges->fcExchange[ *fcExchangeIndex].Cmnd = Cmnd; // Linux Scsi
-      Exchanges->fcExchange[ *fcExchangeIndex].pLoggedInPort = 
-	fcFindLoggedInPort( fcChip,
-          Exchanges->fcExchange[ *fcExchangeIndex].Cmnd, // find Scsi Nexus
-          0,        // DON'T search linked list for FC port id
-	  NULL,     // DON'T search linked list for FC WWN
-          NULL);    // DON'T care about end of list
-
-    }
-
-
-                     // Build the command frame header (& data) according
-                     // to command type
-
-                     // fields common for all SFS frame types
-    CMDfchs->reserved = 0L; // must clear
-    CMDfchs->sof_eof = 0x75000000L;  // SOFi3:EOFn  no UAM; LCr=0, no TS
-    
-             // get the destination port_id from incoming FCHS
-             // (initialized before calling if we're Originator)
-             // Frame goes to port it was from - the source_id
-    
-    CMDfchs->d_id = InFCHS->s_id &0xFFFFFF; // destination (add R_CTL later)
-    CMDfchs->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
+u32 cpqfcTSBuildExchange(CPQFCHBA * dev, u32 type,	// e.g. PLOGI
+			   TachFCHDR_GCMND * InFCHS,	// incoming FCHS
+			   void *Data,	// the CDB, scatter/gather, etc.  
+			   s32 * fcExchangeIndex)	// points to allocated exchange, 
+{
+	PTACHYON fcChip = &dev->fcChip;
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	u32 ulStatus = 0;	// assume OK
+	u16 ox_ID, rx_ID = 0xFFFF;
+	u32 SfsLen = 0L;
+	TachLiteIRB *pIRB;
+	IRBflags IRB_flags;
+	u8 *pIRB_flags = (u8 *) & IRB_flags;
+	TachFCHDR_GCMND *CMDfchs;
+	TachFCHDR *dataHDR;	// 32 byte HEADER ONLY FCP-DATA buffer
+	TachFCHDR_RSP *rspHDR;	// 32 byte header + RSP payload
+	Scsi_Cmnd *Cmnd = (Scsi_Cmnd *) Data;	// Linux Scsi CDB, S/G, ...
+	TachLiteIWE *pIWE;
+	TachLiteIRE *pIRE;
+	TachLiteTWE *pTWE;
+	TachLiteTRE *pTRE;
+	u32 fcp_dl;		// total byte length of DATA transferred
+	u32 fl;		// frame length (FC frame size, 128, 256, 512, 1024)
+	u32 sgPairs;		// number of valid scatter/gather pairs
+	int FCP_SCSI_command;
+	BA_ACC_PAYLOAD *ba_acc;
+	BA_RJT_PAYLOAD *ba_rjt;
+
+	// check passed ARGS
+	if (!fcChip->ERQ)	// NULL ptr means uninitialized Tachlite chip
+		return INVALID_ARGS;
 
-
-    // now enter command-specific fields
-    switch( type )
-    {
-
-    case BLS_NOP:   // FC defined basic link service command NO-OP
-                // ensure unique X_IDs! (use tracking function)
-
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS (not SEST index)
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      SfsLen += 32L;        // add len to LSB (header only - no payload)
-
-                   // TYPE[31-24] 00 Basic Link Service
-                   // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
-      CMDfchs->d_id |= 0x80000000L;  // R_CTL = 80 for NOP (Basic Link Ser.)
-      CMDfchs->f_ctl = 0x00310000L;  // xchng originator, 1st seq,....
-      CMDfchs->seq_cnt = 0x0L;
-      CMDfchs->ox_rx_id = 0xFFFF;        // RX_ID for now; OX_ID on start
-      CMDfchs->ro = 0x0L;    // relative offset (n/a)
-      CMDfchs->pl[0] = 0xaabbccddL;   // words 8-15 frame data payload (n/a)
-      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 1; // seconds
-                                      // (NOP should complete ~instantly)
-      break;
-
-
-    
-    
-    case BLS_ABTS_ACC:  // Abort Sequence ACCept
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS (not SEST index)
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      SfsLen += 32 + 12;    // add len to LSB (header + 3 DWORD payload)
-
-      CMDfchs->d_id |= 0x84000000L;  // R_CTL = 84 for BASIC ACCept
-                   // TYPE[31-24] 00 Basic Link Service
-                   // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
-      CMDfchs->f_ctl = 0x00910000L;  // xchnge responder, last seq, xfer SI
-                   // CMDfchs->seq_id & count might be set from DataHdr?
-      CMDfchs->ro = 0x0L;    // relative offset (n/a)
-      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 5; // seconds
-                        // (Timeout in case of weird error)
-      
-      // now set the ACCept payload...
-      ba_acc = (BA_ACC_PAYLOAD*)&CMDfchs->pl[0];
-      memset( ba_acc, 0, sizeof( BA_ACC_PAYLOAD));
-      // Since PLDA requires (only) entire Exchange aborts, we don't need
-      // to worry about what the last sequence was.
-
-      // We expect that a "target" task is accepting the abort, so we
-      // can use the OX/RX ID pair 
-      ba_acc->ox_rx_id = CMDfchs->ox_rx_id;
- 
-      // source, dest, #bytes
-      BigEndianSwap((UCHAR *)&CMDfchs->ox_rx_id, (UCHAR *)&ba_acc->ox_rx_id, 4);
-
-      ba_acc->low_seq_cnt = 0;
-      ba_acc->high_seq_cnt = 0xFFFF;
-
-
-      break;
-    
-
-    case BLS_ABTS_RJT:  // Abort Sequence ACCept
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS (not SEST index)
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      SfsLen += 32 + 12;    // add len to LSB (header + 3 DWORD payload)
-
-      CMDfchs->d_id |= 0x85000000L;  // R_CTL = 85 for BASIC ReJecT
-                   // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
-                   // TYPE[31-24] 00 Basic Link Service
-      CMDfchs->f_ctl = 0x00910000L;  // xchnge responder, last seq, xfer SI
-                   // CMDfchs->seq_id & count might be set from DataHdr?
-      CMDfchs->ro = 0x0L;    // relative offset (n/a)
-      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 5; // seconds
-                        // (Timeout in case of weird error)
-      
-      CMDfchs->ox_rx_id = InFCHS->ox_rx_id; // copy from sender!
-      
-      // now set the ReJecT payload...
-      ba_rjt = (BA_RJT_PAYLOAD*)&CMDfchs->pl[0];
-      memset( ba_rjt, 0, sizeof( BA_RJT_PAYLOAD));
-
-      // We expect that a "target" task couldn't find the Exhange in the
-      // array of active exchanges, so we use a new LinkService X_ID.
-      // See Reject payload description in FC-PH (Rev 4.3), pg. 140
-      ba_rjt->reason_code = 0x09; // "unable to perform command request"
-      ba_rjt->reason_explain = 0x03; // invalid OX/RX ID pair
-
-
-      break;
-    
-    
-    case BLS_ABTS:   // FC defined basic link service command ABTS 
-                     // Abort Sequence
-                     
-
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS (not SEST index)
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      SfsLen += 32L;        // add len to LSB (header only - no payload)
-
-                   // TYPE[31-24] 00 Basic Link Service
-                   // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
-      CMDfchs->d_id |= 0x81000000L;  // R_CTL = 81 for ABTS
-      CMDfchs->f_ctl = 0x00110000L;  // xchnge originator, last seq, xfer SI
-                   // CMDfchs->seq_id & count might be set from DataHdr?
-      CMDfchs->ro = 0x0L;    // relative offset (n/a)
-      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 2; // seconds
-                        // (ABTS must timeout when responder is gone)
-      break;
-
-    
-    
-    case FCS_NSR:    // Fabric Name Service Request
-       Exchanges->fcExchange[ *fcExchangeIndex].reTries = 2;
-
-
-      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 2; // seconds
-                         // OX_ID, linked to Driver Transaction ID
-                         // (fix-up at Queing time)
-      CMDfchs->ox_rx_id = 0xFFFF; // RX_ID - Responder (target) to modify
-                                    // OX_ID set at ERQueing time
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS (not SEST index)
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      SfsLen += (32L + sizeof(NSR_PL)); // add len (header & NSR payload)
-
-      CMDfchs->d_id |= 0x02000000L;  // R_CTL = 02 for -
-                                   // Name Service Request: Unsolicited 
-                   // TYPE[31-24] 01 Extended Link Service
-                   // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
-      CMDfchs->f_ctl = 0x20210000L;
-                   // OX_ID will be fixed-up at Tachyon enqueing time
-      CMDfchs->seq_cnt = 0; // seq ID, DF_ctl, seq cnt
-      CMDfchs->ro = 0x0L;    // relative offset (n/a)
-
-      BuildLinkServicePayload( fcChip, type, &CMDfchs->pl[0]);
-
-   
-    
-    
-    
-    
-      break;
-    
-    
-    
-    
-    case ELS_PLOGI:  // FC-PH extended link service command Port Login
-      // (May, 2000)
-      // NOTE! This special case facilitates SANMark testing.  The SANMark
-      // test script for initialization-timeout.fcal.SANMark-1.fc
-      // "eats" the OPN() primitive without issuing an R_RDY, causing
-      // Tachyon to report LST (loop state timeout), which causes a
-      // LIP.  To avoid this, simply send out the frame (i.e. assuming a
-      // buffer credit of 1) without waiting for R_RDY.  Many FC devices
-      // (other than Tachyon) have been doing this for years.  We don't
-      // ever want to do this for non-Link Service frames unless the
-      // other device really did report non-zero login BB credit (i.e.
-      // in the PLOGI ACCept frame).
-//      CMDfchs->sof_eof |= 0x00000400L;  // LCr=1
-    
-    case ELS_FDISC:  // Fabric Discovery (Login)
-    case ELS_FLOGI:  // Fabric Login
-    case ELS_SCR:    // Fabric State Change Registration
-    case ELS_LOGO:   // FC-PH extended link service command Port Logout
-    case ELS_PDISC:  // FC-PH extended link service cmnd Port Discovery
-    case ELS_PRLI:   // FC-PH extended link service cmnd Process Login
-
-      Exchanges->fcExchange[ *fcExchangeIndex].reTries = 2;
-
-
-      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 2; // seconds
-                         // OX_ID, linked to Driver Transaction ID
-                         // (fix-up at Queing time)
-      CMDfchs->ox_rx_id = 0xFFFF; // RX_ID - Responder (target) to modify
-                                    // OX_ID set at ERQueing time
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS (not SEST index)
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      if( type == ELS_LOGO )
-        SfsLen += (32L + 16L); //  add len (header & PLOGI payload)
-      else if( type == ELS_PRLI )
-        SfsLen += (32L + 20L); //  add len (header & PRLI payload)
-      else if( type == ELS_SCR )
-        SfsLen += (32L + sizeof(SCR_PL)); //  add len (header & SCR payload)
-      else
-        SfsLen += (32L + 116L); //  add len (header & PLOGI payload)
-
-      CMDfchs->d_id |= 0x22000000L;  // R_CTL = 22 for -
-                                   // Extended Link_Data: Unsolicited Control
-                   // TYPE[31-24] 01 Extended Link Service
-                   // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
-      CMDfchs->f_ctl = 0x01210000L;
-                   // OX_ID will be fixed-up at Tachyon enqueing time
-      CMDfchs->seq_cnt = 0; // seq ID, DF_ctl, seq cnt
-      CMDfchs->ro = 0x0L;    // relative offset (n/a)
-
-      BuildLinkServicePayload( fcChip, type, &CMDfchs->pl[0]);
-
-      break;
-
-
-
-    case ELS_LOGO_ACC: // FC-PH extended link service logout accept
-    case ELS_RJT:          // extended link service reject (add reason)
-    case ELS_ACC:      // ext. link service generic accept
-    case ELS_PLOGI_ACC:// ext. link service login accept (PLOGI or PDISC)
-    case ELS_PRLI_ACC: // ext. link service process login accept
-
-
-      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 1; // assume done
-                // ensure unique X_IDs! (use tracking function)
-                // OX_ID from initiator cmd
-      ox_ID = (USHORT)(InFCHS->ox_rx_id >> 16); 
-      rx_ID = 0xFFFF; // RX_ID, linked to Driver Exchange ID
-
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS (not SEST index)
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      if( type == ELS_RJT )
-      {
-        SfsLen += (32L + 8L); //  add len (header + payload)
-
-        // ELS_RJT reason codes (utilize unused "reserved" field)
-        CMDfchs->pl[0] = 1;
-        CMDfchs->pl[1] = InFCHS->reserved;  
-          
-      }
-      else if( (type == ELS_LOGO_ACC) || (type == ELS_ACC)  )
-        SfsLen += (32L + 4L); //  add len (header + payload)
-      else if( type == ELS_PLOGI_ACC )
-        SfsLen += (32L + 116L); //  add len (header + payload)
-      else if( type == ELS_PRLI_ACC )
-        SfsLen += (32L + 20L); //  add len (header + payload)
-
-      CMDfchs->d_id |= 0x23000000L;  // R_CTL = 23 for -
-                                   // Extended Link_Data: Control Reply
-                   // TYPE[31-24] 01 Extended Link Service
-                   // f_ctl[23:0] exchg responder, last seq, e_s, tsi
-      CMDfchs->f_ctl = 0x01990000L;
-      CMDfchs->seq_cnt = 0x0L;
-      CMDfchs->ox_rx_id = 0L;        // clear
-      CMDfchs->ox_rx_id = ox_ID; // load upper 16 bits
-      CMDfchs->ox_rx_id <<= 16;      // shift them
-
-      CMDfchs->ro = 0x0L;    // relative offset (n/a)
-
-      BuildLinkServicePayload( fcChip, type, &CMDfchs->pl[0]);
-
-      break;
-
-
-                         // Fibre Channel SCSI 'originator' sequences...
-                         // (originator means 'initiator' in FCP-SCSI)
-
-    case SCSI_IWE: // TachLite Initiator Write Entry
-    {
-      PFC_LOGGEDIN_PORT pLoggedInPort = 
-        Exchanges->fcExchange[ *fcExchangeIndex].pLoggedInPort;
-
-      Exchanges->fcExchange[ *fcExchangeIndex].reTries = 1;
-      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 7; // FC2 timeout
-                       
-      // first, build FCP_CMND
-      // unique X_ID fix-ups in StartExchange 
-
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS FCP-CMND (not SEST index)
-
-      // NOTE: unlike FC LinkService login frames, normal
-      // SCSI commands are sent without outgoing verification
-      IRB_flags.DCM = 1;    // Disable completion message for Cmnd frame
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      SfsLen += 64L;        // add len to LSB (header & CMND payload)
-
-      CMDfchs->d_id |= (0x06000000L);  // R_CTL = 6 for command
-
-                   // TYPE[31-24] 8 for FCP SCSI
-                   // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
-                   //             valid RO
-      CMDfchs->f_ctl = 0x08210008L;
-      CMDfchs->seq_cnt = 0x0L;
-      CMDfchs->ox_rx_id = 0L;        // clear for now (-or- in later)
-      CMDfchs->ro = 0x0L;    // relative offset (n/a)
-
-                   // now, fill out FCP-DATA header
-                   // (use buffer inside SEST object)
-      dataHDR = &fcChip->SEST->DataHDR[ *fcExchangeIndex ];
-      dataHDR->reserved = 0L; // must clear
-      dataHDR->sof_eof = 0x75002000L;  // SOFi3:EOFn  no UAM; no CLS, noLCr, no TS
-      dataHDR->d_id = (InFCHS->s_id | 0x01000000L); // R_CTL= FCP_DATA
-      dataHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
-                   // TYPE[31-24] 8 for FCP SCSI
-                   // f_ctl[23:0] xfer S.I.| valid RO
-      dataHDR->f_ctl = 0x08010008L;
-      dataHDR->seq_cnt = 0x02000000L;  // sequence ID: df_ctl : seqence count
-      dataHDR->ox_rx_id = 0L;        // clear; fix-up dataHDR fields later
-      dataHDR->ro = 0x0L;    // relative offset (n/a)
-
-                   // Now setup the SEST entry
-      pIWE = &fcChip->SEST->u[ *fcExchangeIndex ].IWE;
-      
-                   // fill out the IWE:
-
-                // VALid entry:Dir outbound:DCM:enable CM:enal INT: FC frame len
-      pIWE->Hdr_Len = 0x8e000020L; // data frame Len always 32 bytes
-      
-      
-      // from login parameters with other port, what's the largest frame
-      // we can send? 
-      if( pLoggedInPort == NULL) 
-      {
-	ulStatus = INVALID_ARGS;  // failed! give up
-	break;
-      }
-      if( pLoggedInPort->rx_data_size  >= 2048)
-        fl = 0x00020000;  // 2048 code (only support 1024!)
-      else if( pLoggedInPort->rx_data_size  >= 1024)
-        fl = 0x00020000;  // 1024 code
-      else if( pLoggedInPort->rx_data_size  >= 512)
-        fl = 0x00010000;  // 512 code
-      else
-	fl = 0;  // 128 bytes -- should never happen
-      
-      
-      pIWE->Hdr_Len |= fl; // add xmit FC frame len for data phase
-      pIWE->Hdr_Addr = fcChip->SEST->base + 
-		((unsigned long)&fcChip->SEST->DataHDR[*fcExchangeIndex] - 
-			(unsigned long)fcChip->SEST);
-
-      pIWE->RSP_Len = sizeof(TachFCHDR_RSP) ; // hdr+data (recv'd RSP frame)
-      pIWE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
-      
-      memset( &fcChip->SEST->RspHDR[ *fcExchangeIndex].pl, 0, 
-        sizeof( FCP_STATUS_RESPONSE) );  // clear out previous status
- 
-      pIWE->RSP_Addr = fcChip->SEST->base + 
-		((unsigned long)&fcChip->SEST->RspHDR[*fcExchangeIndex] - 
-			(unsigned long)fcChip->SEST);
-
-                   // Do we need local or extended gather list?
-                   // depends on size - we can handle 3 len/addr pairs
-                   // locally.
-
-      fcp_dl = build_SEST_sgList( 
-	cpqfcHBAdata->PciDev,
-        &pIWE->GLen1, 
-        Cmnd,       // S/G list
-        &sgPairs,   // return # of pairs in S/G list (from "Data" descriptor)
-        &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
-
-      if( !fcp_dl ) // error building S/G list?
-      {
-        ulStatus = MEMPOOL_FAIL;
-        break;      // give up
-      }
-
-                             // Now that we know total data length in
-                             // the passed S/G buffer, set FCP CMND frame
-      build_FCP_payload( Cmnd, (UCHAR*)&CMDfchs->pl[0], type, fcp_dl );
-
-
-      
-      if( sgPairs > 3 )  // need extended s/g list
-        pIWE->Buff_Off = 0x78000000L; // extended data | (no offset)
-      else               // local data pointers (in SEST)
-        pIWE->Buff_Off = 0xf8000000L; // local data | (no offset)
-
-                              // ULONG 5
-      pIWE->Link = 0x0000ffffL;   // Buff_Index | Link
-
-      pIWE->RX_ID = 0x0L;     // DWord 6: RX_ID set by target XFER_RDY
-
-                                      // DWord 7
-      pIWE->Data_Len = 0L;    // TL enters rcv'd XFER_RDY BURST_LEN
-      pIWE->Exp_RO = 0L;      // DWord 8
-                              // DWord 9
-      pIWE->Exp_Byte_Cnt = fcp_dl;  // sum of gather buffers
-    }
-    break;
-
-
-
-
-
-    case SCSI_IRE: // TachLite Initiator Read Entry
-
-      if( Cmnd->timeout != 0)
-      {
-//	printk("Cmnd->timeout %d\n", Cmnd->timeout);
-	// per Linux Scsi
-        Exchanges->fcExchange[ *fcExchangeIndex].timeOut = Cmnd->timeout;
-      }
-      else  // use our best guess, based on FC & device
-      {
-
-        if( Cmnd->SCp.Message == 1 ) // Tape device? (from INQUIRY)	
-	{
-	  // turn off our timeouts (for now...)
-          Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 0xFFFFFFFF; 
-	}
+	if (type == SCSI_IRE || type == SCSI_TRE || type == SCSI_IWE || type == SCSI_TWE)
+		FCP_SCSI_command = 1;
 	else
-	{
-          Exchanges->fcExchange[ *fcExchangeIndex].reTries = 1;
-          Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 7; // per SCSI req.
-	}
-      }
-
-  
-      // first, build FCP_CMND
-
-
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS FCP-CMND (not SEST index)
-                            // NOTE: unlike FC LinkService login frames,
-                            // normal SCSI commands are sent "open loop"
-      IRB_flags.DCM = 1;    // Disable completion message for Cmnd frame
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      SfsLen += 64L;        // add len to LSB (header & CMND payload)
-
-      CMDfchs->d_id |= (0x06000000L);  // R_CTL = 6 for command
-
-             // TYPE[31-24] 8 for FCP SCSI
-             // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
-             //             valid RO
-      CMDfchs->f_ctl = 0x08210008L;
-      CMDfchs->seq_cnt = 0x0L;
-      // x_ID & data direction bit set later
-      CMDfchs->ox_rx_id = 0xFFFF;        // clear
-      CMDfchs->ro = 0x0L;    // relative offset (n/a)
-
-
-
-                   // Now setup the SEST entry
-      pIRE = &fcChip->SEST->u[ *fcExchangeIndex ].IRE;
-
-      // fill out the IRE:
-      // VALid entry:Dir outbound:enable CM:enal INT:
-      pIRE->Seq_Accum = 0xCE000000L; // VAL,DIR inbound,DCM| INI,DAT,RSP
-
-      pIRE->reserved = 0L;
-      pIRE->RSP_Len = sizeof(TachFCHDR_RSP) ; // hdr+data (recv'd RSP frame)
-      pIRE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
-
-      pIRE->RSP_Addr = fcChip->SEST->base + 
-		((unsigned long)&fcChip->SEST->RspHDR[*fcExchangeIndex] - 
-			(unsigned long)fcChip->SEST);
-      
-                   // Do we need local or extended gather list?
-                   // depends on size - we can handle 3 len/addr pairs
-                   // locally.
-
-      fcp_dl = build_SEST_sgList( 
-	cpqfcHBAdata->PciDev,
-        &pIRE->SLen1, 
-        Cmnd,       // SCSI command Data desc. with S/G list
-        &sgPairs,   // return # of pairs in S/G list (from "Data" descriptor)
-        &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
-      
-      
-      if( !fcp_dl ) // error building S/G list?
-      {
-	// It is permissible to have a ZERO LENGTH Read command.
-	// If there is the case, simply set fcp_dl (and Exp_Byte_Cnt)
-	// to 0 and continue.
-	if( Cmnd->request_bufflen == 0 )
-	{
-	  fcp_dl = 0; // no FC DATA frames expected
+		FCP_SCSI_command = 0;
 
+	// for commands that pass payload data (e.g. SCSI write)
+	// examine command struct - verify that the
+	// length of s/g buffers is adequate for total payload
+	// length (end of list is NULL address)
+
+	if (FCP_SCSI_command) {
+		if (Data)	// must have data descriptor (S/G list -- at least
+			// one address with at least 1 byte of data)
+		{
+			// something to do (later)?
+		}
+		else
+			return INVALID_ARGS;	// invalid DATA ptr
 	}
-	else
-	{
-          ulStatus = MEMPOOL_FAIL;
-          break;      // give up
-	}
-      }
-
-      // now that we know the S/G length, build CMND payload
-      build_FCP_payload( Cmnd, (UCHAR*)&CMDfchs->pl[0], type, fcp_dl );
-
-      
-      if( sgPairs > 3 )  // need extended s/g list
-        pIRE->Buff_Off = 0x00000000; // DWord 4: extended s/g list, no offset
-      else
-        pIRE->Buff_Off = 0x80000000; // local data, no offset
-      
-      pIRE->Buff_Index = 0x0L;    // DWord 5: Buff_Index | Reserved
-
-      pIRE->Exp_RO  = 0x0L;       // DWord 6: Expected Rel. Offset
-
-      pIRE->Byte_Count = 0;  // DWord 7: filled in by TL on err
-      pIRE->reserved_ = 0;   // DWord 8: reserved
-                             // NOTE: 0 length READ is OK.
-      pIRE->Exp_Byte_Cnt = fcp_dl;// DWord 9: sum of scatter buffers
-      
-      break;
-
-
-
-
-                         // Fibre Channel SCSI 'responder' sequences...
-                         // (originator means 'target' in FCP-SCSI)
-    case SCSI_TWE: // TachLite Target Write Entry
-
-      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 10; // per SCSI req.
-
-                       // first, build FCP_CMND
-
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS (XFER_RDY)
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      SfsLen += (32L + 12L);// add SFS len (header & XFER_RDY payload)
-
-      CMDfchs->d_id |= (0x05000000L);  // R_CTL = 5 for XFER_RDY
-
-                   // TYPE[31-24] 8 for FCP SCSI
-                   // f_ctl[23:0] exchg responder, 1st seq, xfer S.I.
-                //             valid RO
-      CMDfchs->f_ctl = 0x08810008L;
-      CMDfchs->seq_cnt = 0x01000000; // sequence ID: df_ctl: sequence count
-                       // use originator (other port's) OX_ID
-      CMDfchs->ox_rx_id = InFCHS->ox_rx_id;     // we want upper 16 bits
-      CMDfchs->ro = 0x0L;    // relative offset (n/a)
-
-                   // now, fill out FCP-RSP header
-                   // (use buffer inside SEST object)
-
-      rspHDR = &fcChip->SEST->RspHDR[ *fcExchangeIndex ];
-      rspHDR->reserved = 0L; // must clear
-      rspHDR->sof_eof = 0x75000000L;  // SOFi3:EOFn  no UAM; no CLS, noLCr, no TS
-      rspHDR->d_id = (InFCHS->s_id | 0x07000000L); // R_CTL= FCP_RSP
-      rspHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
-                   // TYPE[31-24] 8 for FCP SCSI
-                   // f_ctl[23:0] responder|last seq| xfer S.I.
-      rspHDR->f_ctl = 0x08910000L;
-      rspHDR->seq_cnt = 0x03000000;  // sequence ID
-      rspHDR->ox_rx_id = InFCHS->ox_rx_id; // gives us OX_ID
-      rspHDR->ro = 0x0L;    // relative offset (n/a)
-
-
-                   // Now setup the SEST entry
-                   
-      pTWE = &fcChip->SEST->u[ *fcExchangeIndex ].TWE;
-
-      // fill out the TWE:
-
-      // VALid entry:Dir outbound:enable CM:enal INT:
-      pTWE->Seq_Accum = 0xC4000000L;  // upper word flags
-      pTWE->reserved = 0L;
-      pTWE->Remote_Node_ID = 0L; // no more auto RSP frame! (TL/TS change)
-      pTWE->Remote_Node_ID |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
-      
-
-                   // Do we need local or extended gather list?
-                   // depends on size - we can handle 3 len/addr pairs
-                   // locally.
-
-      fcp_dl = build_SEST_sgList( 
-	cpqfcHBAdata->PciDev,
-        &pTWE->SLen1, 
-        Cmnd,       // S/G list
-        &sgPairs,   // return # of pairs in S/G list (from "Data" descriptor)
-        &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
-      
-      
-      if( !fcp_dl ) // error building S/G list?
-      {
-        ulStatus = MEMPOOL_FAIL;
-        break;      // give up
-      }
-
-      // now that we know the S/G length, build CMND payload
-      build_FCP_payload( Cmnd, (UCHAR*)&CMDfchs->pl[0], type, fcp_dl );
-
-      
-      if( sgPairs > 3 )  // need extended s/g list
-        pTWE->Buff_Off = 0x00000000; // extended s/g list, no offset
-      else
-        pTWE->Buff_Off = 0x80000000; // local data, no offset
-      
-      pTWE->Buff_Index = 0;     // Buff_Index | Link
-      pTWE->Exp_RO = 0;
-      pTWE->Byte_Count = 0;  // filled in by TL on err
-      pTWE->reserved_ = 0;
-      pTWE->Exp_Byte_Cnt = fcp_dl;// sum of scatter buffers
-      
-      break;
-
-
-
-
-
-
-    case SCSI_TRE: // TachLite Target Read Entry
-
-      // It doesn't make much sense for us to "time-out" a READ,
-      // but we'll use it for design consistency and internal error recovery.
-      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 10; // per SCSI req.
-
-      // I/O request block settings...
-      *pIRB_flags = 0;      // clear IRB flags
-                                  // check PRLI (process login) info
-                                  // to see if Initiator Requires XFER_RDY
-                                  // if not, don't send one!
-                                  // { PRLI check...}
-      IRB_flags.SFA = 0;    // don't send XFER_RDY - start data
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      SfsLen += (32L + 12L);// add SFS len (header & XFER_RDY payload)
-
 
-      
-      // now, fill out FCP-DATA header
-                   // (use buffer inside SEST object)
-      dataHDR = &fcChip->SEST->DataHDR[ *fcExchangeIndex ];
-
-      dataHDR->reserved = 0L; // must clear
-      dataHDR->sof_eof = 0x75000000L;  // SOFi3:EOFn no UAM; no CLS,noLCr,no TS
-      dataHDR->d_id = (InFCHS->s_id | 0x01000000L); // R_CTL= FCP_DATA
-      dataHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
-
-
-                   // TYPE[31-24] 8 for FCP SCSI
-                   // f_ctl[23:0] exchg responder, not 1st seq, xfer S.I.
-                   //             valid RO
-      dataHDR->f_ctl = 0x08810008L;
-      dataHDR->seq_cnt = 0x01000000;  // sequence ID (no XRDY)
-      dataHDR->ox_rx_id = InFCHS->ox_rx_id & 0xFFFF0000; // we want upper 16 bits
-      dataHDR->ro = 0x0L;    // relative offset (n/a)
-
-                   // now, fill out FCP-RSP header
-                   // (use buffer inside SEST object)
-      rspHDR = &fcChip->SEST->RspHDR[ *fcExchangeIndex ];
-
-      rspHDR->reserved = 0L; // must clear
-      rspHDR->sof_eof = 0x75000000L;  // SOFi3:EOFn  no UAM; no CLS, noLCr, no TS
-      rspHDR->d_id = (InFCHS->s_id | 0x07000000L); // R_CTL= FCP_RSP
-      rspHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
-                   // TYPE[31-24] 8 for FCP SCSI
-                   // f_ctl[23:0] responder|last seq| xfer S.I.
-      rspHDR->f_ctl = 0x08910000L;
-      rspHDR->seq_cnt = 0x02000000;  // sequence ID: df_ctl: sequence count
-
-      rspHDR->ro = 0x0L;    // relative offset (n/a)
-
-
-      // Now setup the SEST entry
-      pTRE = &fcChip->SEST->u[ *fcExchangeIndex ].TRE;
-
-
-      // VALid entry:Dir outbound:enable CM:enal INT:
-      pTRE->Hdr_Len = 0x86010020L; // data frame Len always 32 bytes
-      pTRE->Hdr_Addr =  // bus address of dataHDR;
-            fcChip->SEST->base + 
-		((unsigned long)&fcChip->SEST->DataHDR[ *fcExchangeIndex ] -
-			(unsigned long)fcChip->SEST);
-	
-      pTRE->RSP_Len = 64L; // hdr+data (TL assisted RSP frame)
-      pTRE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
-      pTRE->RSP_Addr = // bus address of rspHDR
-		fcChip->SEST->base + 
-			((unsigned long)&fcChip->SEST->RspHDR[ *fcExchangeIndex ] -
-				(unsigned long)fcChip->SEST);
-
-                   // Do we need local or extended gather list?
-                   // depends on size - we can handle 3 len/addr pairs
-                   // locally.
-
-      fcp_dl = build_SEST_sgList( 
-	cpqfcHBAdata->PciDev,
-        &pTRE->GLen1, 
-        Cmnd,       // S/G list
-        &sgPairs,   // return # of pairs in S/G list (from "Data" descriptor)
-        &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
-      
-      
-      if( !fcp_dl ) // error building S/G list?
-      {
-        ulStatus = MEMPOOL_FAIL;
-        break;      // give up
-      }
-
-      // no payload or command to build -- READ doesn't need XRDY
-
-      
-      if( sgPairs > 3 )  // need extended s/g list
-        pTRE->Buff_Off = 0x78000000L; // extended data | (no offset)
-      else               // local data pointers (in SEST)
-        pTRE->Buff_Off = 0xf8000000L; // local data | (no offset)
-
-                                            // ULONG 5
-      pTRE->Buff_Index = 0L;   // Buff_Index | reserved
-      pTRE->reserved = 0x0L;   // DWord 6
-
-                                     // DWord 7: NOTE: zero length will
-                                     // hang TachLite!
-      pTRE->Data_Len = fcp_dl; // e.g. sum of scatter buffers
-
-      pTRE->reserved_ = 0L;     // DWord 8
-      pTRE->reserved__ = 0L;    // DWord 9
-
-      break;
+	// we can build an Exchange for later Queuing (on the TL chip)
+	// if an empty slot is available in the DevExt for this controller
+	// look for available Exchange slot...
 
+	if (type != FCP_RESPONSE && type != BLS_ABTS && type != BLS_ABTS_ACC)	// already have Exchange slot!
+		*fcExchangeIndex = FindFreeExchange(fcChip, type);
 
+	if (*fcExchangeIndex != -1)	// Exchange is available?
+	{
+		// assign tmp ptr (shorthand)
+		CMDfchs = &Exchanges->fcExchange[*fcExchangeIndex].fchs;
 
+		if (Cmnd != NULL)	// (necessary for ABTS cases)
+		{
+			Exchanges->fcExchange[*fcExchangeIndex].Cmnd = Cmnd;	// Linux Scsi
+			Exchanges->fcExchange[*fcExchangeIndex].pLoggedInPort = fcFindLoggedInPort(fcChip, Exchanges->fcExchange[*fcExchangeIndex].Cmnd,	// find Scsi Nexus
+												   0,	// DON'T search linked list for FC port id
+												   NULL,	// DON'T search linked list for FC WWN
+												   NULL);	// DON'T care about end of list
+		}
 
+		// Build the command frame header (& data) according
+		// to command type
 
-    
-
-    case FCP_RESPONSE: 
-                  // Target response frame: this sequence uses an OX/RX ID
-                  // pair from a completed SEST exchange.  We built most
-                  // of the response frame when we created the TWE/TRE.
-
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS (RSP)
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      SfsLen += sizeof(TachFCHDR_RSP);// add SFS len (header & RSP payload)
-      
-
-      Exchanges->fcExchange[ *fcExchangeIndex].type = 
-        FCP_RESPONSE; // change Exchange type to "response" phase
-
-      // take advantage of prior knowledge of OX/RX_ID pair from
-      // previous XFER outbound frame (still in fchs of exchange)
-      fcChip->SEST->RspHDR[ *fcExchangeIndex ].ox_rx_id = 
-        CMDfchs->ox_rx_id;
-
-      // Check the status of the DATA phase of the exchange so we can report
-      // status to the initiator
-      buildFCPstatus( fcChip, *fcExchangeIndex); // set RSP payload fields
-
-      memcpy(
-        CMDfchs,  // re-use same XFER fchs for Response frame
-        &fcChip->SEST->RspHDR[ *fcExchangeIndex ],
-        sizeof( TachFCHDR_RSP ));
-      
-        
-      break;
+		// fields common for all SFS frame types
+		CMDfchs->reserved = 0L;	// must clear
+		CMDfchs->sof_eof = 0x75000000L;	// SOFi3:EOFn  no UAM; LCr=0, no TS
+
+		// get the destination port_id from incoming FCHS
+		// (initialized before calling if we're Originator)
+		// Frame goes to port it was from - the source_id
+
+		CMDfchs->d_id = InFCHS->s_id & 0xFFFFFF;	// destination (add R_CTL later)
+		CMDfchs->s_id = fcChip->Registers.my_al_pa;	// CS_CTL = 0
+
+		// now enter command-specific fields
+		switch (type) {
+		case BLS_NOP:	// FC defined basic link service command NO-OP
+			// ensure unique X_IDs! (use tracking function)
+			*pIRB_flags = 0;	// clear IRB flags
+			IRB_flags.SFA = 1;	// send SFS (not SEST index)
+			SfsLen = *pIRB_flags;
+
+			SfsLen <<= 24;	// shift flags to MSB
+			SfsLen += 32L;	// add len to LSB (header only - no payload)
+
+			// TYPE[31-24] 00 Basic Link Service
+			// f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
+			CMDfchs->d_id |= 0x80000000L;	// R_CTL = 80 for NOP (Basic Link Ser.)
+			CMDfchs->f_ctl = 0x00310000L;	// xchng originator, 1st seq,....
+			CMDfchs->seq_cnt = 0x0L;
+			CMDfchs->ox_rx_id = 0xFFFF;	// RX_ID for now; OX_ID on start
+			CMDfchs->ro = 0x0L;	// relative offset (n/a)
+			CMDfchs->pl[0] = 0xaabbccddL;	// words 8-15 frame data payload (n/a)
+			Exchanges->fcExchange[*fcExchangeIndex].timeOut = 1;	// seconds
+			// (NOP should complete ~instantly)
+			break;
+
+		case BLS_ABTS_ACC:	// Abort Sequence ACCept
+			*pIRB_flags = 0;	// clear IRB flags
+			IRB_flags.SFA = 1;	// send SFS (not SEST index)
+			SfsLen = *pIRB_flags;
+
+			SfsLen <<= 24;	// shift flags to MSB
+			SfsLen += 32 + 12;	// add len to LSB (header + 3 DWORD payload)
+
+			CMDfchs->d_id |= 0x84000000L;	// R_CTL = 84 for BASIC ACCept
+			// TYPE[31-24] 00 Basic Link Service
+			// f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
+			CMDfchs->f_ctl = 0x00910000L;	// xchnge responder, last seq, xfer SI
+			// CMDfchs->seq_id & count might be set from DataHdr?
+			CMDfchs->ro = 0x0L;	// relative offset (n/a)
+			Exchanges->fcExchange[*fcExchangeIndex].timeOut = 5;	// seconds
+			// (Timeout in case of weird error)
+
+			// now set the ACCept payload...
+			ba_acc = (BA_ACC_PAYLOAD *) & CMDfchs->pl[0];
+			memset(ba_acc, 0, sizeof(BA_ACC_PAYLOAD));
+			// Since PLDA requires (only) entire Exchange aborts, we don't need
+			// to worry about what the last sequence was.
+
+			// We expect that a "target" task is accepting the abort, so we
+			// can use the OX/RX ID pair 
+			ba_acc->ox_rx_id = CMDfchs->ox_rx_id;
+
+			// source, dest, #bytes
+			BigEndianSwap((u8 *) & CMDfchs->ox_rx_id, (u8 *) & ba_acc->ox_rx_id, 4);
+
+			ba_acc->low_seq_cnt = 0;
+			ba_acc->high_seq_cnt = 0xFFFF;
+			break;
+
+		case BLS_ABTS_RJT:	// Abort Sequence ACCept
+			*pIRB_flags = 0;	// clear IRB flags
+			IRB_flags.SFA = 1;	// send SFS (not SEST index)
+			SfsLen = *pIRB_flags;
+
+			SfsLen <<= 24;	// shift flags to MSB
+			SfsLen += 32 + 12;	// add len to LSB (header + 3 DWORD payload)
+
+			CMDfchs->d_id |= 0x85000000L;	// R_CTL = 85 for BASIC ReJecT
+			// f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
+			// TYPE[31-24] 00 Basic Link Service
+			CMDfchs->f_ctl = 0x00910000L;	// xchnge responder, last seq, xfer SI
+			// CMDfchs->seq_id & count might be set from DataHdr?
+			CMDfchs->ro = 0x0L;	// relative offset (n/a)
+			Exchanges->fcExchange[*fcExchangeIndex].timeOut = 5;	// seconds
+			// (Timeout in case of weird error)
+
+			CMDfchs->ox_rx_id = InFCHS->ox_rx_id;	// copy from sender!
+
+			// now set the ReJecT payload...
+			ba_rjt = (BA_RJT_PAYLOAD *) & CMDfchs->pl[0];
+			memset(ba_rjt, 0, sizeof(BA_RJT_PAYLOAD));
+
+			// We expect that a "target" task couldn't find the Exhange in the
+			// array of active exchanges, so we use a new LinkService X_ID.
+			// See Reject payload description in FC-PH (Rev 4.3), pg. 140
+			ba_rjt->reason_code = 0x09;	// "unable to perform command request"
+			ba_rjt->reason_explain = 0x03;	// invalid OX/RX ID pair
+			break;
+
+		case BLS_ABTS:	// FC defined basic link service command ABTS 
+			// Abort Sequence
+			*pIRB_flags = 0;	// clear IRB flags
+			IRB_flags.SFA = 1;	// send SFS (not SEST index)
+			SfsLen = *pIRB_flags;
+
+			SfsLen <<= 24;	// shift flags to MSB
+			SfsLen += 32L;	// add len to LSB (header only - no payload)
+
+			// TYPE[31-24] 00 Basic Link Service
+			// f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
+			CMDfchs->d_id |= 0x81000000L;	// R_CTL = 81 for ABTS
+			CMDfchs->f_ctl = 0x00110000L;	// xchnge originator, last seq, xfer SI
+			// CMDfchs->seq_id & count might be set from DataHdr?
+			CMDfchs->ro = 0x0L;	// relative offset (n/a)
+			Exchanges->fcExchange[*fcExchangeIndex].timeOut = 2;	// seconds
+			// (ABTS must timeout when responder is gone)
+			break;
+
+		case FCS_NSR:	// Fabric Name Service Request
+			Exchanges->fcExchange[*fcExchangeIndex].reTries = 2;
+			Exchanges->fcExchange[*fcExchangeIndex].timeOut = 2;	// seconds
+			// OX_ID, linked to Driver Transaction ID
+			// (fix-up at Queing time)
+			CMDfchs->ox_rx_id = 0xFFFF;	// RX_ID - Responder (target) to modify
+			// OX_ID set at ERQueing time
+			*pIRB_flags = 0;	// clear IRB flags
+			IRB_flags.SFA = 1;	// send SFS (not SEST index)
+			SfsLen = *pIRB_flags;
+			SfsLen <<= 24;	// shift flags to MSB
+			SfsLen += (32L + sizeof(NSR_PL));	// add len (header & NSR payload)
+			CMDfchs->d_id |= 0x02000000L;	// R_CTL = 02 for -
+			// Name Service Request: Unsolicited 
+			// TYPE[31-24] 01 Extended Link Service
+			// f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
+			CMDfchs->f_ctl = 0x20210000L;
+			// OX_ID will be fixed-up at Tachyon enqueing time
+			CMDfchs->seq_cnt = 0;	// seq ID, DF_ctl, seq cnt
+			CMDfchs->ro = 0x0L;	// relative offset (n/a)
+			BuildLinkServicePayload(fcChip, type, &CMDfchs->pl[0]);
+			break;
+
+		case ELS_PLOGI:	// FC-PH extended link service command Port Login
+			// (May, 2000)
+			// NOTE! This special case facilitates SANMark testing.  The SANMark
+			// test script for initialization-timeout.fcal.SANMark-1.fc
+			// "eats" the OPN() primitive without issuing an R_RDY, causing
+			// Tachyon to report LST (loop state timeout), which causes a
+			// LIP.  To avoid this, simply send out the frame (i.e. assuming a
+			// buffer credit of 1) without waiting for R_RDY.  Many FC devices
+			// (other than Tachyon) have been doing this for years.  We don't
+			// ever want to do this for non-Link Service frames unless the
+			// other device really did report non-zero login BB credit (i.e.
+			// in the PLOGI ACCept frame).
+//			CMDfchs->sof_eof |= 0x00000400L;  // LCr=1
+
+		case ELS_FDISC:	// Fabric Discovery (Login)
+		case ELS_FLOGI:	// Fabric Login
+		case ELS_SCR:	// Fabric State Change Registration
+		case ELS_LOGO:	// FC-PH extended link service command Port Logout
+		case ELS_PDISC:	// FC-PH extended link service cmnd Port Discovery
+		case ELS_PRLI:	// FC-PH extended link service cmnd Process Login
+			Exchanges->fcExchange[*fcExchangeIndex].reTries = 2;
+			Exchanges->fcExchange[*fcExchangeIndex].timeOut = 2;	// seconds
+			// OX_ID, linked to Driver Transaction ID
+			// (fix-up at Queing time)
+			CMDfchs->ox_rx_id = 0xFFFF;	// RX_ID - Responder (target) to modify
+			// OX_ID set at ERQueing time
+			*pIRB_flags = 0;	// clear IRB flags
+			IRB_flags.SFA = 1;	// send SFS (not SEST index)
+			SfsLen = *pIRB_flags;
+			SfsLen <<= 24;	// shift flags to MSB
+			if (type == ELS_LOGO)
+				SfsLen += (32L + 16L);	//  add len (header & PLOGI payload)
+			else if (type == ELS_PRLI)
+				SfsLen += (32L + 20L);	//  add len (header & PRLI payload)
+			else if (type == ELS_SCR)
+				SfsLen += (32L + sizeof(SCR_PL));	//  add len (header & SCR payload)
+			else
+				SfsLen += (32L + 116L);	//  add len (header & PLOGI payload)
+
+			CMDfchs->d_id |= 0x22000000L;	// R_CTL = 22 for -
+			// Extended Link_Data: Unsolicited Control
+			// TYPE[31-24] 01 Extended Link Service
+			// f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
+			CMDfchs->f_ctl = 0x01210000L;
+			// OX_ID will be fixed-up at Tachyon enqueing time
+			CMDfchs->seq_cnt = 0;	// seq ID, DF_ctl, seq cnt
+			CMDfchs->ro = 0x0L;	// relative offset (n/a)
+
+			BuildLinkServicePayload(fcChip, type, &CMDfchs->pl[0]);
+			break;
+
+		case ELS_LOGO_ACC:	// FC-PH extended link service logout accept
+		case ELS_RJT:	// extended link service reject (add reason)
+		case ELS_ACC:	// ext. link service generic accept
+		case ELS_PLOGI_ACC:	// ext. link service login accept (PLOGI or PDISC)
+		case ELS_PRLI_ACC:	// ext. link service process login accept
+			Exchanges->fcExchange[*fcExchangeIndex].timeOut = 1;	// assume done
+			// ensure unique X_IDs! (use tracking function)
+			// OX_ID from initiator cmd
+			ox_ID = (u16) (InFCHS->ox_rx_id >> 16);
+			rx_ID = 0xFFFF;	// RX_ID, linked to Driver Exchange ID
+
+			*pIRB_flags = 0;	// clear IRB flags
+			IRB_flags.SFA = 1;	// send SFS (not SEST index)
+			SfsLen = *pIRB_flags;
+
+			SfsLen <<= 24;	// shift flags to MSB
+			if (type == ELS_RJT) {
+				SfsLen += (32L + 8L);	//  add len (header + payload)
+
+				// ELS_RJT reason codes (utilize unused "reserved" field)
+				CMDfchs->pl[0] = 1;
+				CMDfchs->pl[1] = InFCHS->reserved;
+
+			} else if ((type == ELS_LOGO_ACC) || (type == ELS_ACC))
+				SfsLen += (32L + 4L);	//  add len (header + payload)
+			else if (type == ELS_PLOGI_ACC)
+				SfsLen += (32L + 116L);	//  add len (header + payload)
+			else if (type == ELS_PRLI_ACC)
+				SfsLen += (32L + 20L);	//  add len (header + payload)
+
+			CMDfchs->d_id |= 0x23000000L;	// R_CTL = 23 for -
+			// Extended Link_Data: Control Reply
+			// TYPE[31-24] 01 Extended Link Service
+			// f_ctl[23:0] exchg responder, last seq, e_s, tsi
+			CMDfchs->f_ctl = 0x01990000L;
+			CMDfchs->seq_cnt = 0x0L;
+			CMDfchs->ox_rx_id = 0L;	// clear
+			CMDfchs->ox_rx_id = ox_ID;	// load upper 16 bits
+			CMDfchs->ox_rx_id <<= 16;	// shift them
+
+			CMDfchs->ro = 0x0L;	// relative offset (n/a)
+
+			BuildLinkServicePayload(fcChip, type, &CMDfchs->pl[0]);
+			break;
+
+			// Fibre Channel SCSI 'originator' sequences...
+			// (originator means 'initiator' in FCP-SCSI)
+		case SCSI_IWE:	// TachLite Initiator Write Entry
+			{
+				PFC_LOGGEDIN_PORT pLoggedInPort = Exchanges->fcExchange[*fcExchangeIndex].pLoggedInPort;
+
+				Exchanges->fcExchange[*fcExchangeIndex].reTries = 1;
+				Exchanges->fcExchange[*fcExchangeIndex].timeOut = 7;	// FC2 timeout
+
+				// first, build FCP_CMND
+				// unique X_ID fix-ups in StartExchange 
+
+				*pIRB_flags = 0;	// clear IRB flags
+				IRB_flags.SFA = 1;	// send SFS FCP-CMND (not SEST index)
+
+				// NOTE: unlike FC LinkService login frames, normal
+				// SCSI commands are sent without outgoing verification
+				IRB_flags.DCM = 1;	// Disable completion message for Cmnd frame
+				SfsLen = *pIRB_flags;
+
+				SfsLen <<= 24;	// shift flags to MSB
+				SfsLen += 64L;	// add len to LSB (header & CMND payload)
+
+				CMDfchs->d_id |= (0x06000000L);	// R_CTL = 6 for command
+
+				// TYPE[31-24] 8 for FCP SCSI
+				// f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
+				//             valid RO
+				CMDfchs->f_ctl = 0x08210008L;
+				CMDfchs->seq_cnt = 0x0L;
+				CMDfchs->ox_rx_id = 0L;	// clear for now (-or- in later)
+				CMDfchs->ro = 0x0L;	// relative offset (n/a)
+
+				// now, fill out FCP-DATA header
+				// (use buffer inside SEST object)
+				dataHDR = &fcChip->SEST->DataHDR[*fcExchangeIndex];
+				dataHDR->reserved = 0L;	// must clear
+				dataHDR->sof_eof = 0x75002000L;	// SOFi3:EOFn  no UAM; no CLS, noLCr, no TS
+				dataHDR->d_id = (InFCHS->s_id | 0x01000000L);	// R_CTL= FCP_DATA
+				dataHDR->s_id = fcChip->Registers.my_al_pa;	// CS_CTL = 0
+				// TYPE[31-24] 8 for FCP SCSI
+				// f_ctl[23:0] xfer S.I.| valid RO
+				dataHDR->f_ctl = 0x08010008L;
+				dataHDR->seq_cnt = 0x02000000L;	// sequence ID: df_ctl : seqence count
+				dataHDR->ox_rx_id = 0L;	// clear; fix-up dataHDR fields later
+				dataHDR->ro = 0x0L;	// relative offset (n/a)
+
+				// Now setup the SEST entry
+				pIWE = &fcChip->SEST->u[*fcExchangeIndex].IWE;
+
+				// fill out the IWE:
+
+				// VALid entry:Dir outbound:DCM:enable CM:enal INT: FC frame len
+				pIWE->Hdr_Len = 0x8e000020L;	// data frame Len always 32 bytes
+
+
+				// from login parameters with other port, what's the largest frame
+				// we can send? 
+				if (pLoggedInPort == NULL) {
+					ulStatus = INVALID_ARGS;	// failed! give up
+					break;
+				}
+				if (pLoggedInPort->rx_data_size >= 2048)
+					fl = 0x00020000;	// 2048 code (only support 1024!)
+				else if (pLoggedInPort->rx_data_size >= 1024)
+					fl = 0x00020000;	// 1024 code
+				else if (pLoggedInPort->rx_data_size >= 512)
+					fl = 0x00010000;	// 512 code
+				else
+					fl = 0;	// 128 bytes -- should never happen
+
+
+				pIWE->Hdr_Len |= fl;	// add xmit FC frame len for data phase
+				pIWE->Hdr_Addr = fcChip->SEST->base + ((unsigned long) &fcChip->SEST->DataHDR[*fcExchangeIndex] - (unsigned long) fcChip->SEST);
+
+				pIWE->RSP_Len = sizeof(TachFCHDR_RSP);	// hdr+data (recv'd RSP frame)
+				pIWE->RSP_Len |= (InFCHS->s_id << 8);	// MS 24 bits Remote_ID
+
+				memset(&fcChip->SEST->RspHDR[*fcExchangeIndex].pl, 0, sizeof(FCP_STATUS_RESPONSE));	// clear out previous status
+
+				pIWE->RSP_Addr = fcChip->SEST->base + ((unsigned long) &fcChip->SEST->RspHDR[*fcExchangeIndex] - (unsigned long) fcChip->SEST);
+
+				// Do we need local or extended gather list?
+				// depends on size - we can handle 3 len/addr pairs
+				// locally.
+
+				fcp_dl = build_SEST_sgList(dev->PciDev, &pIWE->GLen1, Cmnd,	// S/G list
+							   &sgPairs,	// return # of pairs in S/G list (from "Data" descriptor)
+							   &fcChip->SEST->sgPages[*fcExchangeIndex]);	// (for Freeing later)
+
+				if (!fcp_dl)	// error building S/G list?
+				{
+					ulStatus = MEMPOOL_FAIL;
+					break;	// give up
+				}
+				// Now that we know total data length in
+				// the passed S/G buffer, set FCP CMND frame
+				build_FCP_payload(Cmnd, (u8 *) & CMDfchs->pl[0], type, fcp_dl);
+
+
+
+				if (sgPairs > 3)	// need extended s/g list
+					pIWE->Buff_Off = 0x78000000L;	// extended data | (no offset)
+				else	// local data pointers (in SEST)
+					pIWE->Buff_Off = 0xf8000000L;	// local data | (no offset)
+
+				// u32 5
+				pIWE->Link = 0x0000ffffL;	// Buff_Index | Link
+
+				pIWE->RX_ID = 0x0L;	// DWord 6: RX_ID set by target XFER_RDY
+
+				// DWord 7
+				pIWE->Data_Len = 0L;	// TL enters rcv'd XFER_RDY BURST_LEN
+				pIWE->Exp_RO = 0L;	// DWord 8
+				// DWord 9
+				pIWE->Exp_Byte_Cnt = fcp_dl;	// sum of gather buffers
+			}
+			break;
 
-    default:
-      printk("cpqfcTS: don't know how to build FC type: %Xh(%d)\n", type,type);
-      break;
+		case SCSI_IRE:	// TachLite Initiator Read Entry
+			if (Cmnd->timeout != 0) {
+//      printk("Cmnd->timeout %d\n", Cmnd->timeout);
+				// per Linux Scsi
+				Exchanges->fcExchange[*fcExchangeIndex].timeOut = Cmnd->timeout;
+			} else	// use our best guess, based on FC & device
+			{
+
+				if (Cmnd->SCp.Message == 1)	// Tape device? (from INQUIRY)     
+				{
+					// turn off our timeouts (for now...)
+					Exchanges->fcExchange[*fcExchangeIndex].timeOut = 0xFFFFFFFF;
+				} else {
+					Exchanges->fcExchange[*fcExchangeIndex].reTries = 1;
+					Exchanges->fcExchange[*fcExchangeIndex].timeOut = 7;	// per SCSI req.
+				}
+			}
+			// first, build FCP_CMND
+			*pIRB_flags = 0;	// clear IRB flags
+			IRB_flags.SFA = 1;	// send SFS FCP-CMND (not SEST index)
+			// NOTE: unlike FC LinkService login frames,
+			// normal SCSI commands are sent "open loop"
+			IRB_flags.DCM = 1;	// Disable completion message for Cmnd frame
+			SfsLen = *pIRB_flags;
+
+			SfsLen <<= 24;	// shift flags to MSB
+			SfsLen += 64L;	// add len to LSB (header & CMND payload)
+
+			CMDfchs->d_id |= (0x06000000L);	// R_CTL = 6 for command
+
+			// TYPE[31-24] 8 for FCP SCSI
+			// f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
+			//             valid RO
+			CMDfchs->f_ctl = 0x08210008L;
+			CMDfchs->seq_cnt = 0x0L;
+			// x_ID & data direction bit set later
+			CMDfchs->ox_rx_id = 0xFFFF;	// clear
+			CMDfchs->ro = 0x0L;	// relative offset (n/a)
+			// Now setup the SEST entry
+			pIRE = &fcChip->SEST->u[*fcExchangeIndex].IRE;
+			// fill out the IRE:
+			// VALid entry:Dir outbound:enable CM:enal INT:
+			pIRE->Seq_Accum = 0xCE000000L;	// VAL,DIR inbound,DCM| INI,DAT,RSP
+
+			pIRE->reserved = 0L;
+			pIRE->RSP_Len = sizeof(TachFCHDR_RSP);	// hdr+data (recv'd RSP frame)
+			pIRE->RSP_Len |= (InFCHS->s_id << 8);	// MS 24 bits Remote_ID
+
+			pIRE->RSP_Addr = fcChip->SEST->base + ((unsigned long) &fcChip->SEST->RspHDR[*fcExchangeIndex] - (unsigned long) fcChip->SEST);
+
+			// Do we need local or extended gather list?
+			// depends on size - we can handle 3 len/addr pairs
+			// locally.
+
+			fcp_dl = build_SEST_sgList(dev->PciDev, &pIRE->SLen1, Cmnd,	// SCSI command Data desc. with S/G list
+						   &sgPairs,	// return # of pairs in S/G list (from "Data" descriptor)
+						   &fcChip->SEST->sgPages[*fcExchangeIndex]);	// (for Freeing later)
+
+
+			if (!fcp_dl)	// error building S/G list?
+			{
+				// It is permissible to have a ZERO LENGTH Read command.
+				// If there is the case, simply set fcp_dl (and Exp_Byte_Cnt)
+				// to 0 and continue.
+				if (Cmnd->request_bufflen == 0) {
+					fcp_dl = 0;	// no FC DATA frames expected
+
+				} else {
+					ulStatus = MEMPOOL_FAIL;
+					break;	// give up
+				}
+			}
+			// now that we know the S/G length, build CMND payload
+			build_FCP_payload(Cmnd, (u8 *) & CMDfchs->pl[0], type, fcp_dl);
 
-    }
 
-    
-    
-    if( !ulStatus)  // no errors above?
-    {
-      // FCHS is built; now build IRB
+			if (sgPairs > 3)	// need extended s/g list
+				pIRE->Buff_Off = 0x00000000;	// DWord 4: extended s/g list, no offset
+			else
+				pIRE->Buff_Off = 0x80000000;	// local data, no offset
+
+			pIRE->Buff_Index = 0x0L;	// DWord 5: Buff_Index | Reserved
+
+			pIRE->Exp_RO = 0x0L;	// DWord 6: Expected Rel. Offset
+
+			pIRE->Byte_Count = 0;	// DWord 7: filled in by TL on err
+			pIRE->reserved_ = 0;	// DWord 8: reserved
+			// NOTE: 0 length READ is OK.
+			pIRE->Exp_Byte_Cnt = fcp_dl;	// DWord 9: sum of scatter buffers
+			break;
+
+			// Fibre Channel SCSI 'responder' sequences...
+			// (originator means 'target' in FCP-SCSI)
+		case SCSI_TWE:	// TachLite Target Write Entry
+			Exchanges->fcExchange[*fcExchangeIndex].timeOut = 10;	// per SCSI req.
+			// first, build FCP_CMND
+			*pIRB_flags = 0;	// clear IRB flags
+			IRB_flags.SFA = 1;	// send SFS (XFER_RDY)
+			SfsLen = *pIRB_flags;
+			SfsLen <<= 24;	// shift flags to MSB
+			SfsLen += (32L + 12L);	// add SFS len (header & XFER_RDY payload)
+
+			CMDfchs->d_id |= (0x05000000L);	// R_CTL = 5 for XFER_RDY
+
+			// TYPE[31-24] 8 for FCP SCSI
+			// f_ctl[23:0] exchg responder, 1st seq, xfer S.I.
+			//             valid RO
+			CMDfchs->f_ctl = 0x08810008L;
+			CMDfchs->seq_cnt = 0x01000000;	// sequence ID: df_ctl: sequence count
+			// use originator (other port's) OX_ID
+			CMDfchs->ox_rx_id = InFCHS->ox_rx_id;	// we want upper 16 bits
+			CMDfchs->ro = 0x0L;	// relative offset (n/a)
+
+			// now, fill out FCP-RSP header
+			// (use buffer inside SEST object)
+
+			rspHDR = &fcChip->SEST->RspHDR[*fcExchangeIndex];
+			rspHDR->reserved = 0L;	// must clear
+			rspHDR->sof_eof = 0x75000000L;	// SOFi3:EOFn  no UAM; no CLS, noLCr, no TS
+			rspHDR->d_id = (InFCHS->s_id | 0x07000000L);	// R_CTL= FCP_RSP
+			rspHDR->s_id = fcChip->Registers.my_al_pa;	// CS_CTL = 0
+			// TYPE[31-24] 8 for FCP SCSI
+			// f_ctl[23:0] responder|last seq| xfer S.I.
+			rspHDR->f_ctl = 0x08910000L;
+			rspHDR->seq_cnt = 0x03000000;	// sequence ID
+			rspHDR->ox_rx_id = InFCHS->ox_rx_id;	// gives us OX_ID
+			rspHDR->ro = 0x0L;	// relative offset (n/a)
+			// Now setup the SEST entry
+
+			pTWE = &fcChip->SEST->u[*fcExchangeIndex].TWE;
+			// fill out the TWE:
+
+			// VALid entry:Dir outbound:enable CM:enal INT:
+			pTWE->Seq_Accum = 0xC4000000L;	// upper word flags
+			pTWE->reserved = 0L;
+			pTWE->Remote_Node_ID = 0L;	// no more auto RSP frame! (TL/TS change)
+			pTWE->Remote_Node_ID |= (InFCHS->s_id << 8);	// MS 24 bits Remote_ID
+
+			// Do we need local or extended gather list?
+			// depends on size - we can handle 3 len/addr pairs
+			// locally.
+
+			fcp_dl = build_SEST_sgList(dev->PciDev, &pTWE->SLen1, Cmnd,	// S/G list
+						   &sgPairs,	// return # of pairs in S/G list (from "Data" descriptor)
+						   &fcChip->SEST->sgPages[*fcExchangeIndex]);	// (for Freeing later)
+
+			if (!fcp_dl)	// error building S/G list?
+			{
+				ulStatus = MEMPOOL_FAIL;
+				break;	// give up
+			}
+			// now that we know the S/G length, build CMND payload
+			build_FCP_payload(Cmnd, (u8 *) & CMDfchs->pl[0], type, fcp_dl);
 
-      // link the just built FCHS (the "command") to the IRB entry 
-      // for this Exchange.
-      pIRB = &Exchanges->fcExchange[ *fcExchangeIndex].IRB; 
-    
-                          // len & flags according to command type above
-      pIRB->Req_A_SFS_Len = SfsLen;  // includes IRB flags & len
-      pIRB->Req_A_SFS_Addr = // TL needs physical addr of frame to send
-		fcChip->exch_dma_handle + (unsigned long)CMDfchs - 
-			(unsigned long)Exchanges;
-
-      pIRB->Req_A_SFS_D_ID = CMDfchs->d_id << 8; // Dest_ID must be consistent!
-
-    // Exchange is complete except for "fix-up" fields to be set
-    // at Tachyon Queuing time:
-    //    IRB->Req_A_Trans_ID (OX_ID/ RX_ID):  
-    //        for SEST entry, lower bits correspond to actual FC Exchange ID
-    //    fchs->OX_ID or RX_ID
-    }
-    else
-    {
-#ifdef DBG     
-      printk( "FC Error: SEST build Pool Allocation failed\n");
+			if (sgPairs > 3)	// need extended s/g list
+				pTWE->Buff_Off = 0x00000000;	// extended s/g list, no offset
+			else
+				pTWE->Buff_Off = 0x80000000;	// local data, no offset
+
+			pTWE->Buff_Index = 0;	// Buff_Index | Link
+			pTWE->Exp_RO = 0;
+			pTWE->Byte_Count = 0;	// filled in by TL on err
+			pTWE->reserved_ = 0;
+			pTWE->Exp_Byte_Cnt = fcp_dl;	// sum of scatter buffers
+			break;
+
+		case SCSI_TRE:	// TachLite Target Read Entry
+			// It doesn't make much sense for us to "time-out" a READ,
+			// but we'll use it for design consistency and internal error recovery.
+			Exchanges->fcExchange[*fcExchangeIndex].timeOut = 10;	// per SCSI req.
+			// I/O request block settings...
+			*pIRB_flags = 0;	// clear IRB flags
+			// check PRLI (process login) info
+			// to see if Initiator Requires XFER_RDY
+			// if not, don't send one!
+			// { PRLI check...}
+			IRB_flags.SFA = 0;	// don't send XFER_RDY - start data
+			SfsLen = *pIRB_flags;
+			SfsLen <<= 24;	// shift flags to MSB
+			SfsLen += (32L + 12L);	// add SFS len (header & XFER_RDY payload)
+
+			// now, fill out FCP-DATA header
+			// (use buffer inside SEST object)
+			dataHDR = &fcChip->SEST->DataHDR[*fcExchangeIndex];
+
+			dataHDR->reserved = 0L;	// must clear
+			dataHDR->sof_eof = 0x75000000L;	// SOFi3:EOFn no UAM; no CLS,noLCr,no TS
+			dataHDR->d_id = (InFCHS->s_id | 0x01000000L);	// R_CTL= FCP_DATA
+			dataHDR->s_id = fcChip->Registers.my_al_pa;	// CS_CTL = 0
+
+			// TYPE[31-24] 8 for FCP SCSI
+			// f_ctl[23:0] exchg responder, not 1st seq, xfer S.I.
+			//             valid RO
+			dataHDR->f_ctl = 0x08810008L;
+			dataHDR->seq_cnt = 0x01000000;	// sequence ID (no XRDY)
+			dataHDR->ox_rx_id = InFCHS->ox_rx_id & 0xFFFF0000;	// we want upper 16 bits
+			dataHDR->ro = 0x0L;	// relative offset (n/a)
+
+			// now, fill out FCP-RSP header
+			// (use buffer inside SEST object)
+			rspHDR = &fcChip->SEST->RspHDR[*fcExchangeIndex];
+
+			rspHDR->reserved = 0L;	// must clear
+			rspHDR->sof_eof = 0x75000000L;	// SOFi3:EOFn  no UAM; no CLS, noLCr, no TS
+			rspHDR->d_id = (InFCHS->s_id | 0x07000000L);	// R_CTL= FCP_RSP
+			rspHDR->s_id = fcChip->Registers.my_al_pa;	// CS_CTL = 0
+			// TYPE[31-24] 8 for FCP SCSI
+			// f_ctl[23:0] responder|last seq| xfer S.I.
+			rspHDR->f_ctl = 0x08910000L;
+			rspHDR->seq_cnt = 0x02000000;	// sequence ID: df_ctl: sequence count
+			rspHDR->ro = 0x0L;	// relative offset (n/a)
+
+			// Now setup the SEST entry
+			pTRE = &fcChip->SEST->u[*fcExchangeIndex].TRE;
+
+			// VALid entry:Dir outbound:enable CM:enal INT:
+			pTRE->Hdr_Len = 0x86010020L;	// data frame Len always 32 bytes
+			pTRE->Hdr_Addr =	// bus address of dataHDR;
+			    fcChip->SEST->base + ((unsigned long) &fcChip->SEST->DataHDR[*fcExchangeIndex] - (unsigned long) fcChip->SEST);
+
+			pTRE->RSP_Len = 64L;	// hdr+data (TL assisted RSP frame)
+			pTRE->RSP_Len |= (InFCHS->s_id << 8);	// MS 24 bits Remote_ID
+			pTRE->RSP_Addr =	// bus address of rspHDR
+			    fcChip->SEST->base + ((unsigned long) &fcChip->SEST->RspHDR[*fcExchangeIndex] - (unsigned long) fcChip->SEST);
+
+			// Do we need local or extended gather list?
+			// depends on size - we can handle 3 len/addr pairs
+			// locally.
+
+			fcp_dl = build_SEST_sgList(dev->PciDev, &pTRE->GLen1, Cmnd,	// S/G list
+						   &sgPairs,	// return # of pairs in S/G list (from "Data" descriptor)
+						   &fcChip->SEST->sgPages[*fcExchangeIndex]);	// (for Freeing later)
+
+			if (!fcp_dl)	// error building S/G list?
+			{
+				ulStatus = MEMPOOL_FAIL;
+				break;	// give up
+			}
+			// no payload or command to build -- READ doesn't need XRDY
+			if (sgPairs > 3)	// need extended s/g list
+				pTRE->Buff_Off = 0x78000000L;	// extended data | (no offset)
+			else	// local data pointers (in SEST)
+				pTRE->Buff_Off = 0xf8000000L;	// local data | (no offset)
+
+			// u32 5
+			pTRE->Buff_Index = 0L;	// Buff_Index | reserved
+			pTRE->reserved = 0x0L;	// DWord 6
+
+			// DWord 7: NOTE: zero length will
+			// hang TachLite!
+			pTRE->Data_Len = fcp_dl;	// e.g. sum of scatter buffers
+
+			pTRE->reserved_ = 0L;	// DWord 8
+			pTRE->reserved__ = 0L;	// DWord 9
+
+			break;
+
+		case FCP_RESPONSE:
+			// Target response frame: this sequence uses an OX/RX ID
+			// pair from a completed SEST exchange.  We built most
+			// of the response frame when we created the TWE/TRE.
+
+			*pIRB_flags = 0;	// clear IRB flags
+			IRB_flags.SFA = 1;	// send SFS (RSP)
+			SfsLen = *pIRB_flags;
+
+			SfsLen <<= 24;	// shift flags to MSB
+			SfsLen += sizeof(TachFCHDR_RSP);	// add SFS len (header & RSP payload)
+			Exchanges->fcExchange[*fcExchangeIndex].type = FCP_RESPONSE;	// change Exchange type to "response" phase
+
+			// take advantage of prior knowledge of OX/RX_ID pair from
+			// previous XFER outbound frame (still in fchs of exchange)
+			fcChip->SEST->RspHDR[*fcExchangeIndex].ox_rx_id = CMDfchs->ox_rx_id;
+
+			// Check the status of the DATA phase of the exchange so we can report
+			// status to the initiator
+			buildFCPstatus(fcChip, *fcExchangeIndex);	// set RSP payload fields
+
+			memcpy(CMDfchs,	// re-use same XFER fchs for Response frame
+			       &fcChip->SEST->RspHDR[*fcExchangeIndex], sizeof(TachFCHDR_RSP));
+			break;
+
+		default:
+			printk("cpqfcTS: don't know how to build FC type: %Xh(%d)\n", type, type);
+			break;
+		}
+		if (!ulStatus)	// no errors above?
+		{
+			// FCHS is built; now build IRB
+
+			// link the just built FCHS (the "command") to the IRB entry 
+			// for this Exchange.
+			pIRB = &Exchanges->fcExchange[*fcExchangeIndex].IRB;
+
+			// len & flags according to command type above
+			pIRB->Req_A_SFS_Len = SfsLen;	// includes IRB flags & len
+			pIRB->Req_A_SFS_Addr =	// TL needs physical addr of frame to send
+			    fcChip->exch_dma_handle + (unsigned long) CMDfchs - (unsigned long) Exchanges;
+
+			pIRB->Req_A_SFS_D_ID = CMDfchs->d_id << 8;	// Dest_ID must be consistent!
+
+			// Exchange is complete except for "fix-up" fields to be set
+			// at Tachyon Queuing time:
+			//    IRB->Req_A_Trans_ID (OX_ID/ RX_ID):  
+			//        for SEST entry, lower bits correspond to actual FC Exchange ID
+			//    fchs->OX_ID or RX_ID
+		} else {
+#ifdef DBG
+			printk("FC Error: SEST build Pool Allocation failed\n");
 #endif
-      // return resources...
-      cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, *fcExchangeIndex);  // SEST build failed
-    }
-  }
-  else  // no Exchanges available
-  {
-    ulStatus = SEST_FULL;
-    printk( "FC Error: no fcExchanges available\n");
-  }
-  return ulStatus;
+			// return resources...
+			cpqfcTSCompleteExchange(dev->PciDev, fcChip, *fcExchangeIndex);	// SEST build failed
+		}
+	} else			// no Exchanges available
+	{
+		ulStatus = SEST_FULL;
+		printk("FC Error: no fcExchanges available\n");
+	}
+	return ulStatus;
 }
 
-
-
-
-
-
 // set RSP payload fields
-static void  buildFCPstatus( PTACHYON fcChip, ULONG ExchangeID) 
+static void buildFCPstatus(PTACHYON fcChip, u32 ExchangeID)
 {
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  FC_EXCHANGE *pExchange = &Exchanges->fcExchange[ExchangeID];  // shorthand
-  PFCP_STATUS_RESPONSE pFcpStatus;
-  
-  memset( &fcChip->SEST->RspHDR[ ExchangeID ].pl, 0,
-    sizeof( FCP_STATUS_RESPONSE) );
-  if( pExchange->status ) // something wrong?
-  {
-    pFcpStatus = (PFCP_STATUS_RESPONSE)  // cast RSP buffer for this xchng
-      &fcChip->SEST->RspHDR[ ExchangeID ].pl;
-    if( pExchange->status & COUNT_ERROR )
-    {
-      
-      // set FCP response len valid (so we can report count error)
-      pFcpStatus->fcp_status |= FCP_RSP_LEN_VALID;
-      pFcpStatus->fcp_rsp_len = 0x04000000;  // 4 byte len (BIG Endian)
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	FC_EXCHANGE *pExchange = &Exchanges->fcExchange[ExchangeID];	// shorthand
+	PFCP_STATUS_RESPONSE pFcpStatus;
 
-      pFcpStatus->fcp_rsp_info = FCP_DATA_LEN_NOT_BURST_LEN; // RSP_CODE
-    }
-  }
+	memset(&fcChip->SEST->RspHDR[ExchangeID].pl, 0, sizeof(FCP_STATUS_RESPONSE));
+	if (pExchange->status)	// something wrong?
+	{
+		pFcpStatus = (PFCP_STATUS_RESPONSE)	// cast RSP buffer for this xchng
+		    & fcChip->SEST->RspHDR[ExchangeID].pl;
+		if (pExchange->status & COUNT_ERROR) {
+
+			// set FCP response len valid (so we can report count error)
+			pFcpStatus->fcp_status |= FCP_RSP_LEN_VALID;
+			pFcpStatus->fcp_rsp_len = 0x04000000;	// 4 byte len (BIG Endian)
+
+			pFcpStatus->fcp_rsp_info = FCP_DATA_LEN_NOT_BURST_LEN;	// RSP_CODE
+		}
+	}
 }
 
 
-static dma_addr_t 
-cpqfc_pci_map_sg_page(
-    		struct pci_dev *pcidev,
-		ULONG *hw_paddr, 	// where to put phys addr for HW use
-		void *sgp_vaddr,	// the virtual address of the sg page 
-	 	dma_addr_t *umap_paddr,	// where to put phys addr for unmap
-		unsigned int *maplen,	// where to store sg entry length
-		int PairCount)		// number of sg pairs used in the page.	
+static dma_addr_t cpqfc_pci_map_sg_page(struct pci_dev *pcidev, u32 * hw_paddr,	// where to put phys addr for HW use
+					void *sgp_vaddr,	// the virtual address of the sg page 
+					dma_addr_t * umap_paddr,	// where to put phys addr for unmap
+					unsigned int *maplen,	// where to store sg entry length
+					int PairCount)	// number of sg pairs used in the page. 
 {
 	unsigned long aligned_addr = (unsigned long) sgp_vaddr;
 
 	*maplen = PairCount * 8;
-        aligned_addr += TL_EXT_SG_PAGE_BYTELEN;
-        aligned_addr &= ~(TL_EXT_SG_PAGE_BYTELEN -1);
-	
-	*umap_paddr = pci_map_single(pcidev, (void *) aligned_addr, 
-				*maplen, PCI_DMA_TODEVICE);
-	*hw_paddr = (ULONG) *umap_paddr;
+	aligned_addr += TL_EXT_SG_PAGE_BYTELEN;
+	aligned_addr &= ~(TL_EXT_SG_PAGE_BYTELEN - 1);
+
+	*umap_paddr = pci_map_single(pcidev, (void *) aligned_addr, *maplen, PCI_DMA_TODEVICE);
+	*hw_paddr = (u32) * umap_paddr;
 
 #       if BITS_PER_LONG > 32
-       		if( *umap_paddr >>32 ) {
-       	  		printk("cqpfcTS:Tach SG DMA addr %p>32 bits\n", 
-	  			(void*)umap_paddr);
-       			return 0;
-       		}
+	if (*umap_paddr >> 32) {
+		printk("cqpfcTS:Tach SG DMA addr %p>32 bits\n", (void *) umap_paddr);
+		return 0;
+	}
 #       endif
 	return *umap_paddr;
 }
 
-static void
-cpqfc_undo_SEST_mappings(struct pci_dev *pcidev,
-			unsigned long contigaddr, int len, int dir,
-  			struct scatterlist *sgl, int use_sg,
-    			PSGPAGES *sgPages_head,
-			int allocated_pages)
+static void cpqfc_undo_SEST_mappings(struct pci_dev *pcidev, unsigned long contigaddr, int len, int dir, struct scatterlist *sgl, int use_sg, PSGPAGES * sgPages_head, int allocated_pages)
 {
 	PSGPAGES i, next;
 
@@ -5136,14 +4141,12 @@
 	if (sgl != NULL)
 		pci_unmap_sg(pcidev, sgl, use_sg, dir);
 
-	for (i=*sgPages_head; i != NULL ;i = next)
-	{
-		pci_unmap_single(pcidev, i->busaddr, i->maplen, 
-			scsi_to_pci_dma_dir(PCI_DMA_TODEVICE));
-		i->busaddr = (dma_addr_t) NULL; 
-		i->maplen = 0L; 
+	for (i = *sgPages_head; i != NULL; i = next) {
+		pci_unmap_single(pcidev, i->busaddr, i->maplen, scsi_to_pci_dma_dir(PCI_DMA_TODEVICE));
+		i->busaddr = (dma_addr_t) NULL;
+		i->maplen = 0L;
 		next = i->next;
-		kfree(i); 
+		kfree(i);
 	}
 	*sgPages_head = NULL;
 }
@@ -5166,380 +4169,331 @@
 
 static int ap_hi_water = TL_DANGER_SGPAGES;
 
-static ULONG build_SEST_sgList( 
-    struct pci_dev *pcidev,
-    ULONG *SESTalPairStart,  // the 3 len/address buffers in SEST
-    Scsi_Cmnd *Cmnd,
-    ULONG *sgPairs, 
-    PSGPAGES *sgPages_head)  // link list of TL Ext. S/G pages from O/S Pool
-    
+static u32 build_SEST_sgList(struct pci_dev *pcidev, u32 * SESTalPairStart,	// the 3 len/address buffers in SEST
+			       Scsi_Cmnd * Cmnd, u32 * sgPairs, PSGPAGES * sgPages_head)	// link list of TL Ext. S/G pages from O/S Pool
 {
-  ULONG i, AllocatedPages=0; // Tach Ext. S/G page allocations
-  ULONG* alPair = SESTalPairStart;
-  ULONG* ext_sg_page_phys_addr_place = NULL;
-  int PairCount;
-  unsigned long ulBuff, contigaddr;
-  ULONG total_data_len=0; // (in bytes)
-  ULONG bytes_to_go = Cmnd->request_bufflen; // total xfer (S/G sum)
-  ULONG thisMappingLen;
-  struct scatterlist *sgl = NULL;  // S/G list (Linux format)
-  int sg_count, totalsgs; 
-  dma_addr_t busaddr;
-  unsigned long thislen, offset;
-  PSGPAGES *sgpage = sgPages_head;
-  PSGPAGES prev_page = NULL;
-
-# define WE_HAVE_SG_LIST (sgl != (unsigned long) NULL)
-  contigaddr = (unsigned long) NULL;
-
-  if( !Cmnd->use_sg )  // no S/G list?
-  {
-	if (bytes_to_go <= TL_MAX_SG_ELEM_LEN)
-	{
-    		*sgPairs = 1;	// use "local" S/G pair in SEST entry
-				// (for now, ignore address bits above #31)
+	u32 i, AllocatedPages = 0;	// Tach Ext. S/G page allocations
+	u32 *alPair = SESTalPairStart;
+	u32 *ext_sg_page_phys_addr_place = NULL;
+	int PairCount;
+	unsigned long ulBuff, contigaddr;
+	u32 total_data_len = 0;	// (in bytes)
+	u32 bytes_to_go = Cmnd->request_bufflen;	// total xfer (S/G sum)
+	u32 thisMappingLen;
+	struct scatterlist *sgl = NULL;	// S/G list (Linux format)
+	int sg_count, totalsgs;
+	dma_addr_t busaddr;
+	unsigned long thislen, offset;
+	PSGPAGES *sgpage = sgPages_head;
+	PSGPAGES prev_page = NULL;
 
-		*alPair++ = bytes_to_go; // bits 18-0, length
+# define WE_HAVE_SG_LIST (sgl != (unsigned long) NULL)
+	contigaddr = (unsigned long) NULL;
 
-		if (bytes_to_go != 0) {
-			contigaddr = ulBuff = pci_map_single(pcidev, 
-				Cmnd->request_buffer, 
-				Cmnd->request_bufflen,
-				scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
-			// printk("ms %p ", ulBuff);
-		}
-		else {
-			// No data transfer, (e.g.: Test Unit Ready)
-			// printk("btg=0 ");
-			*sgPairs = 0;
-			memset(alPair, 0, sizeof(*alPair));
-			return 0;
-		}
+	if (!Cmnd->use_sg)	// no S/G list?
+	{
+		if (bytes_to_go <= TL_MAX_SG_ELEM_LEN) {
+			*sgPairs = 1;	// use "local" S/G pair in SEST entry
+			// (for now, ignore address bits above #31)
+
+			*alPair++ = bytes_to_go;	// bits 18-0, length
+
+			if (bytes_to_go != 0) {
+				contigaddr = ulBuff = pci_map_single(pcidev, Cmnd->request_buffer, Cmnd->request_bufflen, scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+				// printk("ms %p ", ulBuff);
+			} else {
+				// No data transfer, (e.g.: Test Unit Ready)
+				// printk("btg=0 ");
+				*sgPairs = 0;
+				memset(alPair, 0, sizeof(*alPair));
+				return 0;
+			}
 
 #		if BITS_PER_LONG > 32
-    			if( ulBuff >>32 ) {
-      				printk("FATAL! Tachyon DMA address %p "
-					"exceeds 32 bits\n", (void*)ulBuff );
-      				return 0;
-    			}
+			if (ulBuff >> 32) {
+				printk("FATAL! Tachyon DMA address %p " "exceeds 32 bits\n", (void *) ulBuff);
+				return 0;
+			}
 #		endif
-    		*alPair = (ULONG)ulBuff;      
-    		return bytes_to_go;
-	} 
-	else	// We have a single large (too big) contiguous buffer.
-	{	// We will have to break it up.  We'll use the scatter
-		// gather code way below, but use contigaddr instead
-		// of sg_dma_addr(). (this is a very rare case).
-
-		unsigned long btg;
-		contigaddr = pci_map_single(pcidev, Cmnd->request_buffer, 
-				Cmnd->request_bufflen,
-				scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
-
-		// printk("contigaddr = %p, len = %d\n", 
-		//	(void *) contigaddr, bytes_to_go);
-		totalsgs = 0;
-		for (btg = bytes_to_go; btg > 0; ) {
-			btg -= ( btg > TL_MAX_SG_ELEM_LEN ? 
-				TL_MAX_SG_ELEM_LEN : btg );
-			totalsgs++;
-		}
-		sgl = NULL;
-		*sgPairs = totalsgs;
-	}
-  }
-  else  // we do have a scatter gather list
-  {
-	// [TBD - update for Linux to support > 32 bits addressing]
-	// since the format for local & extended S/G lists is different,
-	// check if S/G pairs exceeds 3.
-	// *sgPairs = Cmnd->use_sg; Nope, that's wrong.
- 
-	sgl = (struct scatterlist*)Cmnd->request_buffer;  
-	sg_count = pci_map_sg(pcidev, sgl, Cmnd->use_sg, 
-		scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
-        // printk("sgl = %p, sg_count = %d\n", (void *) sgl, sg_count);
-  	if( sg_count <= 3 ) {
-
-	// we need to be careful here that no individual mapping
-	// is too large, and if any is, that breaking it up
-	// doesn't push us over 3 sgs, or, if it does, that we
-	// handle that case.  Tachyon can take 0x7FFFF bits for length,
-	// but sg structure uses "unsigned int", on the face of it, 
-	// up to 0xFFFFFFFF or even more.
-
-		int i;
-		unsigned long thislen;
-
-		totalsgs = 0;
-		for (i=0;i<sg_count;i++) {
-      			thislen = sg_dma_len(&sgl[i]);
-			while (thislen >= TL_MAX_SG_ELEM_LEN) {
+			*alPair = (u32) ulBuff;
+			return bytes_to_go;
+		} else		// We have a single large (too big) contiguous buffer.
+		{		// We will have to break it up.  We'll use the scatter
+			// gather code way below, but use contigaddr instead
+			// of sg_dma_addr(). (this is a very rare case).
+
+			unsigned long btg;
+			contigaddr = pci_map_single(pcidev, Cmnd->request_buffer, Cmnd->request_bufflen, scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+
+			// printk("contigaddr = %p, len = %d\n", 
+			//      (void *) contigaddr, bytes_to_go);
+			totalsgs = 0;
+			for (btg = bytes_to_go; btg > 0;) {
+				btg -= (btg > TL_MAX_SG_ELEM_LEN ? TL_MAX_SG_ELEM_LEN : btg);
 				totalsgs++;
-				thislen -= TL_MAX_SG_ELEM_LEN;
 			}
-			if (thislen > 0) totalsgs++;
+			sgl = NULL;
+			*sgPairs = totalsgs;
 		}
-		*sgPairs = totalsgs;
-  	} else totalsgs = 999; // as a first estimate, definitely >3, 
-			      
-	// if (totalsgs != sg_count) 
-	//	printk("totalsgs = %d, sgcount=%d\n",totalsgs,sg_count);
-  }
+	} else			// we do have a scatter gather list
+	{
+		// [TBD - update for Linux to support > 32 bits addressing]
+		// since the format for local & extended S/G lists is different,
+		// check if S/G pairs exceeds 3.
+		// *sgPairs = Cmnd->use_sg; Nope, that's wrong.
+
+		sgl = (struct scatterlist *) Cmnd->request_buffer;
+		sg_count = pci_map_sg(pcidev, sgl, Cmnd->use_sg, scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+		// printk("sgl = %p, sg_count = %d\n", (void *) sgl, sg_count);
+		if (sg_count <= 3) {
+
+			// we need to be careful here that no individual mapping
+			// is too large, and if any is, that breaking it up
+			// doesn't push us over 3 sgs, or, if it does, that we
+			// handle that case.  Tachyon can take 0x7FFFF bits for length,
+			// but sg structure uses "unsigned int", on the face of it, 
+			// up to 0xFFFFFFFF or even more.
+
+			int i;
+			unsigned long thislen;
+
+			totalsgs = 0;
+			for (i = 0; i < sg_count; i++) {
+				thislen = sg_dma_len(&sgl[i]);
+				while (thislen >= TL_MAX_SG_ELEM_LEN) {
+					totalsgs++;
+					thislen -= TL_MAX_SG_ELEM_LEN;
+				}
+				if (thislen > 0)
+					totalsgs++;
+			}
+			*sgPairs = totalsgs;
+		} else
+			totalsgs = 999;	// as a first estimate, definitely >3, 
 
-  // printk("totalsgs = %d, sgcount=%d\n", totalsgs, sg_count);
-  if( totalsgs <= 3 ) // can (must) use "local" SEST list
-  {
-    while( bytes_to_go)
-    {
-      offset = 0L;
+		// if (totalsgs != sg_count) 
+		//      printk("totalsgs = %d, sgcount=%d\n",totalsgs,sg_count);
+	}
 
-      if ( WE_HAVE_SG_LIST ) 
-	thisMappingLen = sg_dma_len(sgl);
-      else					// or contiguous buffer?
-	thisMappingLen = bytes_to_go;
+	// printk("totalsgs = %d, sgcount=%d\n", totalsgs, sg_count);
+	if (totalsgs <= 3)	// can (must) use "local" SEST list
+	{
+		while (bytes_to_go) {
+			offset = 0L;
 
-      while (thisMappingLen > 0)
-      {  
-	thislen = thisMappingLen > TL_MAX_SG_ELEM_LEN ? 
-		TL_MAX_SG_ELEM_LEN : thisMappingLen;
-	bytes_to_go = bytes_to_go - thislen;
+			if (WE_HAVE_SG_LIST)
+				thisMappingLen = sg_dma_len(sgl);
+			else	// or contiguous buffer?
+				thisMappingLen = bytes_to_go;
 
-	// we have L/A pair; L = thislen, A = physicalAddress
-	// load into SEST...
+			while (thisMappingLen > 0) {
+				thislen = thisMappingLen > TL_MAX_SG_ELEM_LEN ? TL_MAX_SG_ELEM_LEN : thisMappingLen;
+				bytes_to_go = bytes_to_go - thislen;
 
-	total_data_len += thislen;
-	*alPair = thislen; // bits 18-0, length
+				// we have L/A pair; L = thislen, A = physicalAddress
+				// load into SEST...
 
-	alPair++;
+				total_data_len += thislen;
+				*alPair = thislen;	// bits 18-0, length
 
-	if ( WE_HAVE_SG_LIST ) 
-		ulBuff = sg_dma_address(sgl) + offset;
-	else
-		ulBuff = contigaddr + offset;
+				alPair++;
 
-	offset += thislen;
+				if (WE_HAVE_SG_LIST)
+					ulBuff = sg_dma_address(sgl) + offset;
+				else
+					ulBuff = contigaddr + offset;
+
+				offset += thislen;
 
 #	if BITS_PER_LONG > 32
-		if( ulBuff >>32 ) {
-        		printk("cqpfcTS: 2Tach DMA address %p > 32 bits\n", 
-				(void*)ulBuff );
-		    printk("%s = %p, offset = %ld\n", 
-			WE_HAVE_SG_LIST ? "ulBuff" : "contigaddr",
-			WE_HAVE_SG_LIST ? (void *) ulBuff : (void *) contigaddr,
-				offset);
-        		return 0;
-      		}
+				if (ulBuff >> 32) {
+					printk("cqpfcTS: 2Tach DMA address %p > 32 bits\n", (void *) ulBuff);
+					printk("%s = %p, offset = %ld\n", WE_HAVE_SG_LIST ? "ulBuff" : "contigaddr", WE_HAVE_SG_LIST ? (void *) ulBuff : (void *) contigaddr, offset);
+					return 0;
+				}
 #	endif
-        *alPair++ = (ULONG)ulBuff; // lower 32 bits (31-0)
-	thisMappingLen -= thislen;
-      }
+				*alPair++ = (u32) ulBuff;	// lower 32 bits (31-0)
+				thisMappingLen -= thislen;
+			}
 
-      if ( WE_HAVE_SG_LIST ) ++sgl;  // next S/G pair
-	else if (bytes_to_go != 0) printk("BTG not zero!\n");
+			if (WE_HAVE_SG_LIST)
+				++sgl;	// next S/G pair
+			else if (bytes_to_go != 0)
+				printk("BTG not zero!\n");
 
 #     ifdef DBG_SEST_SGLIST
-	printk("L=%d ", thisMappingLen);
-	printk("btg=%d ", bytes_to_go);
+			printk("L=%d ", thisMappingLen);
+			printk("btg=%d ", bytes_to_go);
 #     endif
 
-    }
-    // printk("i:%d\n", *sgPairs);
-  }
-  else    // more than 3 pairs requires Extended S/G page (Pool Allocation)
-  {
-    // clear out SEST DWORDs (local S/G addr) C-F (A-B set in following logic)
-    for( i=2; i<6; i++)
-      alPair[i] = 0;
-
-    PairCount = TL_EXT_SG_PAGE_COUNT;    // forces initial page allocation
-    totalsgs = 0;
-    while( bytes_to_go )
-    {
-      // Per SEST format, we can support 524287 byte lengths per
-      // S/G pair.  Typical user buffers are 4k, and very rarely
-      // exceed 12k due to fragmentation of physical memory pages.
-      // However, on certain O/S system (not "user") buffers (on platforms 
-      // with huge memories), it's possible to exceed this
-      // length in a single S/G address/len mapping, so we have to handle
-      // that.
-
-      offset = 0L;
-      if ( WE_HAVE_SG_LIST ) 
-	thisMappingLen = sg_dma_len(sgl);
-      else
-	thisMappingLen = bytes_to_go;
-
-      while (thisMappingLen > 0)
-      {
-	thislen = thisMappingLen > TL_MAX_SG_ELEM_LEN ? 
-		TL_MAX_SG_ELEM_LEN : thisMappingLen;
-	// printk("%d/%d/%d\n", thislen, thisMappingLen, bytes_to_go);
-      
-  	// should we load into "this" extended S/G page, or allocate
-	// new page?
-
-	if( PairCount >= TL_EXT_SG_PAGE_COUNT )
+		}
+		// printk("i:%d\n", *sgPairs);
+	} else			// more than 3 pairs requires Extended S/G page (Pool Allocation)
 	{
-	  // Now, we have to map the previous page, (triggering buffer bounce)
-	  // The first time thru the loop, there won't be a previous page.
-	  if (prev_page != NULL) // is there a prev page? 
-	  {
-		// this code is normally kind of hard to trigger, 
-		// you have to use up more than 256 scatter gather 
-		// elements to get here.  Cranking down TL_MAX_SG_ELEM_LEN
-		// to an absurdly low value (128 bytes or so) to artificially
-		// break i/o's into a zillion pieces is how I tested it. 
-		busaddr = cpqfc_pci_map_sg_page(pcidev,
-				ext_sg_page_phys_addr_place,
-				prev_page->page,
-        			&prev_page->busaddr,
-        			&prev_page->maplen,
-				PairCount);
-          } 
-          // Allocate the TL Extended S/G list page.  We have
-          // to allocate twice what we want to ensure required TL alignment
-          // (Tachlite TL/TS User Man. Rev 6.0, p 168)
-          // We store the original allocated PVOID so we can free later
-	  *sgpage = kmalloc( sizeof(SGPAGES), GFP_ATOMIC);
-	  if ( ! *sgpage )
-          {
-		printk("cpqfc: Allocation failed @ %d S/G page allocations\n",
-			AllocatedPages);
-		total_data_len = 0;  // failure!! Ext. S/G is All-or-none affair
-
-	        // unmap the previous mappings, if any.
-
-	        cpqfc_undo_SEST_mappings(pcidev, contigaddr, 
-			Cmnd->request_bufflen,
-			scsi_to_pci_dma_dir(Cmnd->sc_data_direction),
-  			sgl, Cmnd->use_sg, sgPages_head, AllocatedPages+1);
-
-		// FIXME: testing shows that if we get here, 
-		// it's bad news.  (this has been this way for a long 
-		// time though, AFAIK.  Not that that excuses it.)
-
-		return 0; // give up (and probably hang the system)
-          }
-                               // clear out memory we just allocated
-	  memset( (*sgpage)->page,0,TL_EXT_SG_PAGE_BYTELEN*2);
-	  (*sgpage)->next = NULL;
-	  (*sgpage)->busaddr = (dma_addr_t) NULL;
-	  (*sgpage)->maplen = 0L;
-      
-	  // align the memory - TL requires sizeof() Ext. S/G page alignment.
-	  // We doubled the actual required size so we could mask off LSBs 
-	  // to get desired offset 
-
-	  ulBuff = (unsigned long) (*sgpage)->page;
-	  ulBuff += TL_EXT_SG_PAGE_BYTELEN;
-	  ulBuff &= ~(TL_EXT_SG_PAGE_BYTELEN -1);
-
-	  // set pointer, in SEST if first Ext. S/G page, or in last pair
-	  // of linked Ext. S/G pages... (Only 32-bit PVOIDs, so just 
-	  // load lower 32 bits)
-	  // NOTE: the Len field must be '0' if this is the first Ext. S/G
-	  // pointer in SEST, and not 0 otherwise (we know thislen != 0).
+		// clear out SEST DWORDs (local S/G addr) C-F (A-B set in following logic)
+		for (i = 2; i < 6; i++)
+			alPair[i] = 0;
 
-	  *alPair = (alPair != SESTalPairStart) ? thislen : 0;
+		PairCount = TL_EXT_SG_PAGE_COUNT;	// forces initial page allocation
+		totalsgs = 0;
+		while (bytes_to_go) {
+			// Per SEST format, we can support 524287 byte lengths per
+			// S/G pair.  Typical user buffers are 4k, and very rarely
+			// exceed 12k due to fragmentation of physical memory pages.
+			// However, on certain O/S system (not "user") buffers (on platforms 
+			// with huge memories), it's possible to exceed this
+			// length in a single S/G address/len mapping, so we have to handle
+			// that.
+
+			offset = 0L;
+			if (WE_HAVE_SG_LIST)
+				thisMappingLen = sg_dma_len(sgl);
+			else
+				thisMappingLen = bytes_to_go;
+
+			while (thisMappingLen > 0) {
+				thislen = thisMappingLen > TL_MAX_SG_ELEM_LEN ? TL_MAX_SG_ELEM_LEN : thisMappingLen;
+				// printk("%d/%d/%d\n", thislen, thisMappingLen, bytes_to_go);
+
+				// should we load into "this" extended S/G page, or allocate
+				// new page?
+
+				if (PairCount >= TL_EXT_SG_PAGE_COUNT) {
+					// Now, we have to map the previous page, (triggering buffer bounce)
+					// The first time thru the loop, there won't be a previous page.
+					if (prev_page != NULL)	// is there a prev page? 
+					{
+						// this code is normally kind of hard to trigger, 
+						// you have to use up more than 256 scatter gather 
+						// elements to get here.  Cranking down TL_MAX_SG_ELEM_LEN
+						// to an absurdly low value (128 bytes or so) to artificially
+						// break i/o's into a zillion pieces is how I tested it. 
+						busaddr = cpqfc_pci_map_sg_page(pcidev, ext_sg_page_phys_addr_place, prev_page->page, &prev_page->busaddr, &prev_page->maplen, PairCount);
+					}
+					// Allocate the TL Extended S/G list page.  We have
+					// to allocate twice what we want to ensure required TL alignment
+					// (Tachlite TL/TS User Man. Rev 6.0, p 168)
+					// We store the original allocated PVOID so we can free later
+					*sgpage = kmalloc(sizeof(SGPAGES), GFP_ATOMIC);
+					if (!*sgpage) {
+						printk("cpqfc: Allocation failed @ %d S/G page allocations\n", AllocatedPages);
+						total_data_len = 0;	// failure!! Ext. S/G is All-or-none affair
+
+						// unmap the previous mappings, if any.
+
+						cpqfc_undo_SEST_mappings(pcidev, contigaddr, Cmnd->request_bufflen, scsi_to_pci_dma_dir(Cmnd->sc_data_direction), sgl, Cmnd->use_sg, sgPages_head, AllocatedPages + 1);
+
+						// FIXME: testing shows that if we get here, 
+						// it's bad news.  (this has been this way for a long 
+						// time though, AFAIK.  Not that that excuses it.)
+
+						return 0;	// give up (and probably hang the system)
+					}
+					// clear out memory we just allocated
+					memset((*sgpage)->page, 0, TL_EXT_SG_PAGE_BYTELEN * 2);
+					(*sgpage)->next = NULL;
+					(*sgpage)->busaddr = (dma_addr_t) NULL;
+					(*sgpage)->maplen = 0L;
+
+					// align the memory - TL requires sizeof() Ext. S/G page alignment.
+					// We doubled the actual required size so we could mask off LSBs 
+					// to get desired offset 
+
+					ulBuff = (unsigned long) (*sgpage)->page;
+					ulBuff += TL_EXT_SG_PAGE_BYTELEN;
+					ulBuff &= ~(TL_EXT_SG_PAGE_BYTELEN - 1);
+
+					// set pointer, in SEST if first Ext. S/G page, or in last pair
+					// of linked Ext. S/G pages... (Only 32-bit PVOIDs, so just 
+					// load lower 32 bits)
+					// NOTE: the Len field must be '0' if this is the first Ext. S/G
+					// pointer in SEST, and not 0 otherwise (we know thislen != 0).
+
+					*alPair = (alPair != SESTalPairStart) ? thislen : 0;
 
 #	  ifdef DBG_SEST_SGLIST
-        	printk("PairCount %d @%p even %Xh, ", 
-			PairCount, alPair, *alPair);
+					printk("PairCount %d @%p even %Xh, ", PairCount, alPair, *alPair);
 #	  endif
 
-	  // Save the place where we need to store the physical
-	  // address of this scatter gather page which we get when we map it
-	  // (and mapping we can do only after we fill it in.)
-	  alPair++;  // next DWORD, will contain phys addr of the ext page
-	  ext_sg_page_phys_addr_place = alPair;
-
-	  // Now, set alPair = the virtual addr of the (Extended) S/G page
-	  // which will accept the Len/ PhysicalAddress pairs
-	  alPair = (ULONG *) ulBuff;
-
-	  AllocatedPages++;
-	  if (AllocatedPages >= ap_hi_water)
-	  {
-		// This message should rarely, if ever, come out.
-		// Previously (cpqfc version <= 2.0.5) the driver would
-		// just puke if more than 4 SG pages were used, and nobody
-		// ever complained about that.  This only comes out if 
-		// more than 8 pages are used.
-
-		printk(KERN_WARNING
-		"cpqfc: Possible danger.  %d scatter gather pages used.\n"
-			"cpqfc: detected seemingly extreme memory "
-			"fragmentation or huge data transfers.\n", 
-			AllocatedPages);
-		ap_hi_water = AllocatedPages+1;
-	  }
-		
-	  PairCount = 1;  // starting new Ext. S/G page
-	  prev_page = (*sgpage);  // remember this page, for next time thru
-	  sgpage = &((*sgpage)->next);
-	}  // end of new TL Ext. S/G page allocation
+					// Save the place where we need to store the physical
+					// address of this scatter gather page which we get when we map it
+					// (and mapping we can do only after we fill it in.)
+					alPair++;	// next DWORD, will contain phys addr of the ext page
+					ext_sg_page_phys_addr_place = alPair;
+
+					// Now, set alPair = the virtual addr of the (Extended) S/G page
+					// which will accept the Len/ PhysicalAddress pairs
+					alPair = (u32 *) ulBuff;
+
+					AllocatedPages++;
+					if (AllocatedPages >= ap_hi_water) {
+						// This message should rarely, if ever, come out.
+						// Previously (cpqfc version <= 2.0.5) the driver would
+						// just puke if more than 4 SG pages were used, and nobody
+						// ever complained about that.  This only comes out if 
+						// more than 8 pages are used.
+
+						printk(KERN_WARNING "cpqfc: Possible danger.  %d scatter gather pages used.\n" "cpqfc: detected seemingly extreme memory " "fragmentation or huge data transfers.\n", AllocatedPages);
+						ap_hi_water = AllocatedPages + 1;
+					}
+
+					PairCount = 1;	// starting new Ext. S/G page
+					prev_page = (*sgpage);	// remember this page, for next time thru
+					sgpage = &((*sgpage)->next);
+				}	// end of new TL Ext. S/G page allocation
+
+				*alPair = thislen;	// bits 18-0, length (range check above)
 
-	*alPair = thislen; // bits 18-0, length (range check above)
-      
 #	ifdef DBG_SEST_SGLIST
-	  printk("PairCount %d @%p, even %Xh, ", PairCount, alPair, *alPair);
+				printk("PairCount %d @%p, even %Xh, ", PairCount, alPair, *alPair);
 #	endif
 
-	alPair++;    // next DWORD, physical address 
+				alPair++;	// next DWORD, physical address 
 
-	if ( WE_HAVE_SG_LIST ) 
-		ulBuff = sg_dma_address(sgl) + offset;
-	else
-		ulBuff = contigaddr + offset;
-	offset += thislen;
+				if (WE_HAVE_SG_LIST)
+					ulBuff = sg_dma_address(sgl) + offset;
+				else
+					ulBuff = contigaddr + offset;
+				offset += thislen;
 
 #	if BITS_PER_LONG > 32
-          if( ulBuff >>32 )
-	  {
-	    printk("cqpfcTS: 1Tach DMA address %p > 32 bits\n", (void*)ulBuff );
-	    printk("%s = %p, offset = %ld\n", 
-		WE_HAVE_SG_LIST ? "ulBuff" : "contigaddr",
-		WE_HAVE_SG_LIST ? (void *) ulBuff : (void *) contigaddr,
-			offset);
-	    return 0;
-	  }
+				if (ulBuff >> 32) {
+					printk("cqpfcTS: 1Tach DMA address %p > 32 bits\n", (void *) ulBuff);
+					printk("%s = %p, offset = %ld\n", WE_HAVE_SG_LIST ? "ulBuff" : "contigaddr", WE_HAVE_SG_LIST ? (void *) ulBuff : (void *) contigaddr, offset);
+					return 0;
+				}
 #	endif
 
-	*alPair = (ULONG) ulBuff; // lower 32 bits (31-0)
+				*alPair = (u32) ulBuff;	// lower 32 bits (31-0)
 
 #       ifdef DBG_SEST_SGLIST
-        printk("odd %Xh\n", *alPair);
+				printk("odd %Xh\n", *alPair);
 #       endif
-	alPair++;    // next DWORD, next address/length pair
-                                           
-	PairCount++; // next Length/Address pair
-
-	// if (PairCount > pc_hi_water)
-	// {
-		// printk("pc hi = %d ", PairCount);
-		// pc_hi_water = PairCount;
-	// }
-	bytes_to_go -= thislen;
-	total_data_len += thislen;  
-	thisMappingLen -= thislen;
-	totalsgs++;
-      } // while (thisMappingLen > 0)
-      if ( WE_HAVE_SG_LIST ) sgl++;  // next S/G pair
-    } // while (bytes_to_go)
-
-    // printk("Totalsgs=%d\n", totalsgs);
-    *sgPairs = totalsgs;
-
-    // PCI map (and bounce) the last (and usually only) extended SG page
-    busaddr = cpqfc_pci_map_sg_page(pcidev,
-		ext_sg_page_phys_addr_place,
-		prev_page->page, 
-		&prev_page->busaddr, 
-		&prev_page->maplen,
-		PairCount);
-  }
-  return total_data_len;
+				alPair++;	// next DWORD, next address/length pair
+
+				PairCount++;	// next Length/Address pair
+
+				// if (PairCount > pc_hi_water)
+				// {
+				// printk("pc hi = %d ", PairCount);
+				// pc_hi_water = PairCount;
+				// }
+				bytes_to_go -= thislen;
+				total_data_len += thislen;
+				thisMappingLen -= thislen;
+				totalsgs++;
+			}	// while (thisMappingLen > 0)
+			if (WE_HAVE_SG_LIST)
+				sgl++;	// next S/G pair
+		}		// while (bytes_to_go)
+
+		// printk("Totalsgs=%d\n", totalsgs);
+		*sgPairs = totalsgs;
+
+		// PCI map (and bounce) the last (and usually only) extended SG page
+		busaddr = cpqfc_pci_map_sg_page(pcidev, ext_sg_page_phys_addr_place, prev_page->page, &prev_page->busaddr, &prev_page->maplen, PairCount);
+	}
+	return total_data_len;
 }
 
 
@@ -5554,268 +4508,249 @@
 // 0 if successful
 // non-zero on error
 //sstartex
-ULONG cpqfcTSStartExchange( 
-  CPQFCHBA *cpqfcHBAdata,                      
-  LONG ExchangeID )
-{
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  FC_EXCHANGE *pExchange = &Exchanges->fcExchange[ ExchangeID ]; // shorthand
-  USHORT producer, consumer;
-  ULONG ulStatus=0;
-  short int ErqIndex;
-  BOOLEAN CompleteExchange = FALSE;  // e.g. ACC replies are complete
-  BOOLEAN SestType=FALSE;
-  ULONG InboundData=0;
 
-  // We will manipulate Tachlite chip registers here to successfully
-  // start exchanges. 
+u32 cpqfcTSStartExchange(CPQFCHBA * dev, s32 ExchangeID)
+{
+	PTACHYON fcChip = &dev->fcChip;
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	FC_EXCHANGE *pExchange = &Exchanges->fcExchange[ExchangeID];	// shorthand
+	u16 producer, consumer;
+	u32 ulStatus = 0;
+	short int ErqIndex;
+	u8 CompleteExchange = 0;	// e.g. ACC replies are complete
+	u8 SestType = 0;
+	u32 InboundData = 0;
 
-  // Check that link is not down -- we can't start an exchange on a
-  // down link!
+	// We will manipulate Tachlite chip registers here to successfully
+	// start exchanges. 
 
-  if( fcChip->Registers.FMstatus.value & 0x80) // LPSM offline?
-  {
-printk("fcStartExchange: PSM offline (%Xh), x_ID %Xh, type %Xh, port_id %Xh\n",
-         fcChip->Registers.FMstatus.value & 0xFF,
-         ExchangeID,
-         pExchange->type,
-         pExchange->fchs.d_id);
+	// Check that link is not down -- we can't start an exchange on a
+	// down link!
 
-    if( ExchangeID >= TACH_SEST_LEN )  // Link Service Outbound frame?
-    {
-      // Our most popular LinkService commands are port discovery types
-      // (PLOGI/ PDISC...), which are implicitly nullified by Link Down
-      // events, so it makes no sense to Que them.  However, ABTS should
-      // be queued, since exchange sequences are likely destroyed by
-      // Link Down events, and we want to notify other ports of broken
-      // sequences by aborting the corresponding exchanges.
-      if( pExchange->type != BLS_ABTS )
-      {
-	ulStatus = LNKDWN_OSLS;
-	goto Done;
-        // don't Que most LinkServ exchanges on LINK DOWN
-      }
-    }
+	if (fcChip->Registers.FMstatus.value & 0x80)	// LPSM offline?
+	{
+		printk("fcStartExchange: PSM offline (%Xh), x_ID %Xh, type %Xh, port_id %Xh\n", fcChip->Registers.FMstatus.value & 0xFF, ExchangeID, pExchange->type, pExchange->fchs.d_id);
 
-    printk("fcStartExchange: Que x_ID %Xh, type %Xh\n", 
-      ExchangeID, pExchange->type);
-    pExchange->status |= EXCHANGE_QUEUED;
-    ulStatus = EXCHANGE_QUEUED;
-    goto Done;
-  }
+		if (ExchangeID >= TACH_SEST_LEN)	// Link Service Outbound frame?
+		{
+			// Our most popular LinkService commands are port discovery types
+			// (PLOGI/ PDISC...), which are implicitly nullified by Link Down
+			// events, so it makes no sense to Que them.  However, ABTS should
+			// be queued, since exchange sequences are likely destroyed by
+			// Link Down events, and we want to notify other ports of broken
+			// sequences by aborting the corresponding exchanges.
+			if (pExchange->type != BLS_ABTS) {
+				ulStatus = LNKDWN_OSLS;
+				goto Done;
+				// don't Que most LinkServ exchanges on LINK DOWN
+			}
+		}
 
-  // Make sure ERQ has available space.
-  
-  producer = (USHORT)fcChip->ERQ->producerIndex; // copies for logical arith.
-  consumer = (USHORT)fcChip->ERQ->consumerIndex;
-  producer++;  // We are testing for full que by incrementing
-  
-  if( producer >= ERQ_LEN )  // rollover condition?
-    producer = 0;
-  if( consumer != producer ) // ERQ not full?
-  {
-    // ****************** Need Atomic access to chip registers!!********
-    
-    // remember ERQ PI for copying IRB
-    ErqIndex = (USHORT)fcChip->ERQ->producerIndex; 
-    fcChip->ERQ->producerIndex = producer; // this is written to Tachyon
-               // we have an ERQ slot! If SCSI command, need SEST slot
-               // otherwise we are done.
-
-    // Note that Tachyon requires that bit 15 of the OX_ID or RX_ID be
-    // set according to direction of data to/from Tachyon for SEST assists.
-    // For consistency, enforce this rule for Link Service (non-SEST)
-    // exchanges as well.
-
-    // fix-up the X_ID field in IRB
-    pExchange->IRB.Req_A_Trans_ID = ExchangeID & 0x7FFF; // 15-bit field
-
-    // fix-up the X_ID field in fchs -- depends on Originator or Responder,
-    // outgoing or incoming data?
-    switch( pExchange->type )
-    {
-               // ORIGINATOR types...  we're setting our OX_ID and
-               // defaulting the responder's RX_ID to 0xFFFF
-    
-    case SCSI_IRE:
-      // Requirement: set MSB of x_ID for Incoming TL data
-      // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
-      InboundData = 0x8000;
-
-    case SCSI_IWE:   
-      SestType = TRUE;
-      pExchange->fchs.ox_rx_id = (ExchangeID | InboundData);
-      pExchange->fchs.ox_rx_id <<= 16;     // MSW shift
-      pExchange->fchs.ox_rx_id |= 0xffff;  // add default RX_ID
-      
-      // now fix-up the Data HDR OX_ID (TL automatically does rx_id)
-      // (not necessary for IRE -- data buffer unused)
-      if( pExchange->type == SCSI_IWE)
-      {
-        fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id = 
-          pExchange->fchs.ox_rx_id;
-
-      }
-
-      break;
-
-
-    case FCS_NSR:  // ext. link service Name Service Request
-    case ELS_SCR:  // ext. link service State Change Registration
-    case ELS_FDISC:// ext. link service login
-    case ELS_FLOGI:// ext. link service login
-    case ELS_LOGO: // FC-PH extended link service logout
-    case BLS_NOP:  // Basic link service No OPeration
-    case ELS_PLOGI:// ext. link service login (PLOGI)
-    case ELS_PDISC:// ext. link service login (PDISC)
-    case ELS_PRLI: // ext. link service process login
-
-      pExchange->fchs.ox_rx_id = ExchangeID;
-      pExchange->fchs.ox_rx_id <<= 16;  // MSW shift
-      pExchange->fchs.ox_rx_id |= 0xffff;  // and RX_ID
+		printk("fcStartExchange: Que x_ID %Xh, type %Xh\n", ExchangeID, pExchange->type);
+		pExchange->status |= EXCHANGE_QUEUED;
+		ulStatus = EXCHANGE_QUEUED;
+		goto Done;
+	}
+	// Make sure ERQ has available space.
 
-      break;
-      
+	producer = (u16) fcChip->ERQ->producerIndex;	// copies for logical arith.
+	consumer = (u16) fcChip->ERQ->consumerIndex;
+	producer++;		// We are testing for full que by incrementing
+
+	if (producer >= ERQ_LEN)	// rollover condition?
+		producer = 0;
+	if (consumer != producer)	// ERQ not full?
+	{
+		// ****************** Need Atomic access to chip registers!!********
 
+		// remember ERQ PI for copying IRB
+		ErqIndex = (u16) fcChip->ERQ->producerIndex;
+		fcChip->ERQ->producerIndex = producer;	// this is written to Tachyon
+		// we have an ERQ slot! If SCSI command, need SEST slot
+		// otherwise we are done.
+
+		// Note that Tachyon requires that bit 15 of the OX_ID or RX_ID be
+		// set according to direction of data to/from Tachyon for SEST assists.
+		// For consistency, enforce this rule for Link Service (non-SEST)
+		// exchanges as well.
+
+		// fix-up the X_ID field in IRB
+		pExchange->IRB.Req_A_Trans_ID = ExchangeID & 0x7FFF;	// 15-bit field
+
+		// fix-up the X_ID field in fchs -- depends on Originator or Responder,
+		// outgoing or incoming data?
+		switch (pExchange->type) {
+			// ORIGINATOR types...  we're setting our OX_ID and
+			// defaulting the responder's RX_ID to 0xFFFF
+
+		case SCSI_IRE:
+			// Requirement: set MSB of x_ID for Incoming TL data
+			// (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
+			InboundData = 0x8000;
+
+		case SCSI_IWE:
+			SestType = 1;
+			pExchange->fchs.ox_rx_id = (ExchangeID | InboundData);
+			pExchange->fchs.ox_rx_id <<= 16;	// MSW shift
+			pExchange->fchs.ox_rx_id |= 0xffff;	// add default RX_ID
+
+			// now fix-up the Data HDR OX_ID (TL automatically does rx_id)
+			// (not necessary for IRE -- data buffer unused)
+			if (pExchange->type == SCSI_IWE) {
+				fcChip->SEST->DataHDR[ExchangeID].ox_rx_id = pExchange->fchs.ox_rx_id;
 
+			}
 
-               // RESPONDER types... we must set our RX_ID while preserving
-               // sender's OX_ID
-               // outgoing (or no) data
-    case ELS_RJT:       // extended link service reject 
-    case ELS_LOGO_ACC: // FC-PH extended link service logout accept
-    case ELS_ACC:      // ext. generic link service accept
-    case ELS_PLOGI_ACC:// ext. link service login accept (PLOGI or PDISC)
-    case ELS_PRLI_ACC: // ext. link service process login accept
-
-      CompleteExchange = TRUE;   // Reply (ACC or RJT) is end of exchange
-      pExchange->fchs.ox_rx_id |= (ExchangeID & 0xFFFF);
-
-      break;
-
-
-      // since we are a Responder, OX_ID should already be set by
-      // cpqfcTSBuildExchange().  We need to -OR- in RX_ID
-    case SCSI_TWE:
-      SestType = TRUE;
-      // Requirement: set MSB of x_ID for Incoming TL data
-      // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
-
-      pExchange->fchs.ox_rx_id &= 0xFFFF0000;  // clear RX_ID
-      // Requirement: set MSB of RX_ID for Incoming TL data
-      // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
-      pExchange->fchs.ox_rx_id |= (ExchangeID | 0x8000);
-      break;
-          
-    
-    case SCSI_TRE:
-      SestType = TRUE;
-      
-      // there is no XRDY for SEST target read; the data
-      // header needs to be updated. Also update the RSP
-      // exchange IDs for the status frame, in case it is sent automatically
-      fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id |= ExchangeID;
-      fcChip->SEST->RspHDR[ ExchangeID ].ox_rx_id = 
-        fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id;
-      
-      // for easier FCP response logic (works for TWE and TRE), 
-      // copy exchange IDs.  (Not needed if TRE 'RSP' bit set)
-      pExchange->fchs.ox_rx_id =
-        fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id;
-
-      break;
+			break;
 
 
-    case FCP_RESPONSE:  // using existing OX_ID/ RX_ID pair,
-                        // start SFS FCP-RESPONSE frame
-      // OX/RX_ID should already be set! (See "fcBuild" above)
-      CompleteExchange = TRUE;   // RSP is end of FCP-SCSI exchange
+		case FCS_NSR:	// ext. link service Name Service Request
+		case ELS_SCR:	// ext. link service State Change Registration
+		case ELS_FDISC:	// ext. link service login
+		case ELS_FLOGI:	// ext. link service login
+		case ELS_LOGO:	// FC-PH extended link service logout
+		case BLS_NOP:	// Basic link service No OPeration
+		case ELS_PLOGI:	// ext. link service login (PLOGI)
+		case ELS_PDISC:	// ext. link service login (PDISC)
+		case ELS_PRLI:	// ext. link service process login
 
-      
-      break;
+			pExchange->fchs.ox_rx_id = ExchangeID;
+			pExchange->fchs.ox_rx_id <<= 16;	// MSW shift
+			pExchange->fchs.ox_rx_id |= 0xffff;	// and RX_ID
 
+			break;
 
-    case BLS_ABTS_RJT:  // uses new RX_ID, since SEST x_ID non-existent
-    case BLS_ABTS_ACC:  // using existing OX_ID/ RX_ID pair from SEST entry
-      CompleteExchange = TRUE;   // ACC or RJT marks end of FCP-SCSI exchange
-    case BLS_ABTS:  // using existing OX_ID/ RX_ID pair from SEST entry
 
 
-      break;
 
+			// RESPONDER types... we must set our RX_ID while preserving
+			// sender's OX_ID
+			// outgoing (or no) data
+		case ELS_RJT:	// extended link service reject 
+		case ELS_LOGO_ACC:	// FC-PH extended link service logout accept
+		case ELS_ACC:	// ext. generic link service accept
+		case ELS_PLOGI_ACC:	// ext. link service login accept (PLOGI or PDISC)
+		case ELS_PRLI_ACC:	// ext. link service process login accept
 
-    default:
-      printk("Error on fcStartExchange: undefined type %Xh(%d)\n",
-        pExchange->type, pExchange->type);
-      return INVALID_ARGS;
-    }
-    
-    
-      // X_ID fields are entered -- copy IRB to Tachyon's ERQ
-    
+			CompleteExchange = 1;	// Reply (ACC or RJT) is end of exchange
+			pExchange->fchs.ox_rx_id |= (ExchangeID & 0xFFFF);
 
-    memcpy(
-        &fcChip->ERQ->QEntry[ ErqIndex ],  // dest.
-        &pExchange->IRB,
-        32);  // fixed (hardware) length!
-
-    PCI_TRACEO( ExchangeID, 0xA0)
-
-    // ACTION!  May generate INT and IMQ entry
-    writel( fcChip->ERQ->producerIndex,
-          fcChip->Registers.ERQproducerIndex.address);
+			break;
 
-  
-    if( ExchangeID >= TACH_SEST_LEN )  // Link Service Outbound frame?
-    {
-    
-      // wait for completion! (TDB -- timeout and chip reset)
-      
 
-  PCI_TRACEO( ExchangeID, 0xA4)
-  
-      enable_irq( cpqfcHBAdata->HostAdapter->irq); // only way to get Sem.
-      
-      down_interruptible( cpqfcHBAdata->TYOBcomplete); 
-  
-      disable_irq( cpqfcHBAdata->HostAdapter->irq);
-  PCI_TRACE( 0xA4)
-
-      // On login exchanges, BAD_ALPA (non-existent port_id) results in 
-      // FTO (Frame Time Out) on the Outbound Completion message.
-      // If we got an FTO status, complete the exchange (free up slot)
-      if( CompleteExchange ||   // flag from Reply frames
-          pExchange->status )   // typically, can get FRAME_TO
-      {
-    	cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID);  
-      }
-    }
+			// since we are a Responder, OX_ID should already be set by
+			// cpqfcTSBuildExchange().  We need to -OR- in RX_ID
+		case SCSI_TWE:
+			SestType = 1;
+			// Requirement: set MSB of x_ID for Incoming TL data
+			// (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
 
-    else                         // SEST Exchange
-    {
-      ulStatus = 0;   // ship & pray success (e.g. FCP-SCSI)
-      
-      if( CompleteExchange )   // by Type of exchange (e.g. end-of-xchng)
-      {
-    	cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID);  
-      }
-       
-      else
-        pExchange->status &= ~EXCHANGE_QUEUED;  // clear ExchangeQueued flag 
+			pExchange->fchs.ox_rx_id &= 0xFFFF0000;	// clear RX_ID
+			// Requirement: set MSB of RX_ID for Incoming TL data
+			// (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
+			pExchange->fchs.ox_rx_id |= (ExchangeID | 0x8000);
+			break;
 
-    }
-  }
 
-  
-  else                // ERQ 'producer' = 'consumer' and QUE is full
-  {
-    ulStatus = OUTQUE_FULL; // Outbound (ERQ) Que full
-  }
- 
-Done: 
-  PCI_TRACE( 0xA0)
-  return ulStatus; 
+		case SCSI_TRE:
+			SestType = 1;
+
+			// there is no XRDY for SEST target read; the data
+			// header needs to be updated. Also update the RSP
+			// exchange IDs for the status frame, in case it is sent automatically
+			fcChip->SEST->DataHDR[ExchangeID].ox_rx_id |= ExchangeID;
+			fcChip->SEST->RspHDR[ExchangeID].ox_rx_id = fcChip->SEST->DataHDR[ExchangeID].ox_rx_id;
+
+			// for easier FCP response logic (works for TWE and TRE), 
+			// copy exchange IDs.  (Not needed if TRE 'RSP' bit set)
+			pExchange->fchs.ox_rx_id = fcChip->SEST->DataHDR[ExchangeID].ox_rx_id;
+
+			break;
+
+
+		case FCP_RESPONSE:	// using existing OX_ID/ RX_ID pair,
+			// start SFS FCP-RESPONSE frame
+			// OX/RX_ID should already be set! (See "fcBuild" above)
+			CompleteExchange = 1;	// RSP is end of FCP-SCSI exchange
+
+
+			break;
+
+
+		case BLS_ABTS_RJT:	// uses new RX_ID, since SEST x_ID non-existent
+		case BLS_ABTS_ACC:	// using existing OX_ID/ RX_ID pair from SEST entry
+			CompleteExchange = 1;	// ACC or RJT marks end of FCP-SCSI exchange
+		case BLS_ABTS:	// using existing OX_ID/ RX_ID pair from SEST entry
+
+
+			break;
+
+
+		default:
+			printk("Error on fcStartExchange: undefined type %Xh(%d)\n", pExchange->type, pExchange->type);
+			return INVALID_ARGS;
+		}
+
+
+		// X_ID fields are entered -- copy IRB to Tachyon's ERQ
+
+
+		memcpy(&fcChip->ERQ->QEntry[ErqIndex],	// dest.
+		       &pExchange->IRB, 32);	// fixed (hardware) length!
+
+		PCI_TRACEO(ExchangeID, 0xA0)
+		    // ACTION!  May generate INT and IMQ entry
+		    writel(fcChip->ERQ->producerIndex, fcChip->Registers.ERQproducerIndex.address);
+
+
+		if (ExchangeID >= TACH_SEST_LEN)	// Link Service Outbound frame?
+		{
+
+			// wait for completion! (TDB -- timeout and chip reset)
+
+
+			PCI_TRACEO(ExchangeID, 0xA4)
+
+			    enable_irq(dev->HostAdapter->irq);	// only way to get Sem.
+
+			down_interruptible(dev->TYOBcomplete);
+
+			disable_irq(dev->HostAdapter->irq);
+			PCI_TRACE(0xA4)
+			    // On login exchanges, BAD_ALPA (non-existent port_id) results in 
+			    // FTO (Frame Time Out) on the Outbound Completion message.
+			    // If we got an FTO status, complete the exchange (free up slot)
+			    if (CompleteExchange ||	// flag from Reply frames
+				pExchange->status)	// typically, can get FRAME_TO
+			{
+				cpqfcTSCompleteExchange(dev->PciDev, fcChip, ExchangeID);
+			}
+		}
+
+		else		// SEST Exchange
+		{
+			ulStatus = 0;	// ship & pray success (e.g. FCP-SCSI)
+
+			if (CompleteExchange)	// by Type of exchange (e.g. end-of-xchng)
+			{
+				cpqfcTSCompleteExchange(dev->PciDev, fcChip, ExchangeID);
+			}
+
+			else
+				pExchange->status &= ~EXCHANGE_QUEUED;	// clear ExchangeQueued flag 
+
+		}
+	}
+
+
+	else			// ERQ 'producer' = 'consumer' and QUE is full
+	{
+		ulStatus = OUTQUE_FULL;	// Outbound (ERQ) Que full
+	}
+
+      Done:
+	PCI_TRACE(0xA0)
+	    return ulStatus;
 }
 
 
@@ -5839,408 +4774,364 @@
 // (Least Recently Used) scheme.
 
 
-static LONG FindFreeExchange( PTACHYON fcChip, ULONG type )
+static s32 FindFreeExchange(PTACHYON fcChip, u32 type)
 {
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  ULONG i;
-  ULONG ulStatus=-1;  // assume failure
-
-
-  if( type == SCSI_IRE ||
-      type == SCSI_TRE ||
-      type == SCSI_IWE ||
-      type == SCSI_TWE)
-  {
-        // SCSI type - X_IDs should be from 0 to TACH_SEST_LEN-1
-    if( fcChip->fcSestExchangeLRU >= TACH_SEST_LEN) // rollover?
-      fcChip->fcSestExchangeLRU = 0;
-    i = fcChip->fcSestExchangeLRU; // typically it's already free!
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	u32 i;
+	u32 ulStatus = -1;	// assume failure
+
+
+	if (type == SCSI_IRE || type == SCSI_TRE || type == SCSI_IWE || type == SCSI_TWE) {
+		// SCSI type - X_IDs should be from 0 to TACH_SEST_LEN-1
+		if (fcChip->fcSestExchangeLRU >= TACH_SEST_LEN)	// rollover?
+			fcChip->fcSestExchangeLRU = 0;
+		i = fcChip->fcSestExchangeLRU;	// typically it's already free!
+
+		if (Exchanges->fcExchange[i].type == 0)	// check for "free" element
+		{
+			ulStatus = 0;	// success!
+		}
 
-    if( Exchanges->fcExchange[i].type == 0 ) // check for "free" element
-    {
-      ulStatus = 0; // success!
-    }
-    
-    else
-    {         // YUK! we need to do a linear search for free element.
-              // Fragmentation of the fcExchange array is due to excessively
-              // long completions or timeouts.
-      
-      while( TRUE )
-      {
-        if( ++i >= TACH_SEST_LEN ) // rollover check
-          i = 0;  // beginning of SEST X_IDs
-
-//        printk( "looping for SCSI xchng ID: i=%d, type=%Xh\n", 
-//         i, Exchanges->fcExchange[i].type);
-
-        if( Exchanges->fcExchange[i].type == 0 ) // "free"?
-        {
-          ulStatus = 0; // success!
-          break;
-        }
-        if( i == fcChip->fcSestExchangeLRU ) // wrapped-around array?
-        {
-          printk( "SEST X_ID space full\n");
-          break;       // failed - prevent inf. loop
-        }
-      }
-    }
-    fcChip->fcSestExchangeLRU = i + 1; // next! (rollover check next pass)
-  }
+		else {		// YUK! we need to do a linear search for free element.
+			// Fragmentation of the fcExchange array is due to excessively
+			// long completions or timeouts.
+
+			while (1) {
+				if (++i >= TACH_SEST_LEN)	// rollover check
+					i = 0;	// beginning of SEST X_IDs
+
+//					printk( "looping for SCSI xchng ID: i=%d, type=%Xh\n", 
+//						i, Exchanges->fcExchange[i].type);
+
+				if (Exchanges->fcExchange[i].type == 0)	// "free"?
+				{
+					ulStatus = 0;	// success!
+					break;
+				}
+				if (i == fcChip->fcSestExchangeLRU)	// wrapped-around array?
+				{
+					printk("SEST X_ID space full\n");
+					break;	// failed - prevent inf. loop
+				}
+			}
+		}
+		fcChip->fcSestExchangeLRU = i + 1;	// next! (rollover check next pass)
+	}
+	else			// Link Service type - X_IDs should be from TACH_SEST_LEN 
+				// to TACH_MAX_XID
+	{
+		if (fcChip->fcLsExchangeLRU >= TACH_MAX_XID ||	// range check
+		    fcChip->fcLsExchangeLRU < TACH_SEST_LEN)	// (e.g. startup)
+			fcChip->fcLsExchangeLRU = TACH_SEST_LEN;
+
+		i = fcChip->fcLsExchangeLRU;	// typically it's already free!
+		if (Exchanges->fcExchange[i].type == 0)	// check for "free" element
+		{
+			ulStatus = 0;	// success!
+		}
 
-  
-  
-  else  // Link Service type - X_IDs should be from TACH_SEST_LEN 
-        // to TACH_MAX_XID
-  {
-    if( fcChip->fcLsExchangeLRU >= TACH_MAX_XID || // range check
-        fcChip->fcLsExchangeLRU < TACH_SEST_LEN ) // (e.g. startup)
-      fcChip->fcLsExchangeLRU = TACH_SEST_LEN;
+		else {		// YUK! we need to do a linear search for free element
+			// Fragmentation of the fcExchange array is due to excessively
+			// long completions or timeouts.
+
+			while (1) {
+				if (++i >= TACH_MAX_XID)	// rollover check
+					i = TACH_SEST_LEN;	// beginning of Link Service X_IDs
+
+//				printk( "looping for xchng ID: i=%d, type=%Xh\n", 
+//					i, Exchanges->fcExchange[i].type);
+
+				if (Exchanges->fcExchange[i].type == 0)	// "free"?
+				{
+					ulStatus = 0;	// success!
+					break;
+				}
+				if (i == fcChip->fcLsExchangeLRU)	// wrapped-around array?
+				{
+					printk("LinkService X_ID space full\n");
+					break;	// failed - prevent inf. loop
+				}
+			}
+		}
+		fcChip->fcLsExchangeLRU = i + 1;	// next! (rollover check next pass)
 
-    i = fcChip->fcLsExchangeLRU; // typically it's already free!
-    if( Exchanges->fcExchange[i].type == 0 ) // check for "free" element
-    {
-      ulStatus = 0; // success!
-    }
-    
-    else
-    {         // YUK! we need to do a linear search for free element
-              // Fragmentation of the fcExchange array is due to excessively
-              // long completions or timeouts.
-      
-      while( TRUE )
-      {
-        if( ++i >= TACH_MAX_XID ) // rollover check
-          i = TACH_SEST_LEN;// beginning of Link Service X_IDs
-
-//        printk( "looping for xchng ID: i=%d, type=%Xh\n", 
-//         i, Exchanges->fcExchange[i].type);
-
-        if( Exchanges->fcExchange[i].type == 0 ) // "free"?
-        {
-          ulStatus = 0; // success!
-          break;
-        }
-        if( i == fcChip->fcLsExchangeLRU ) // wrapped-around array?
-        {
-          printk( "LinkService X_ID space full\n");
-          break;       // failed - prevent inf. loop
-        }
-      }
-    }
-    fcChip->fcLsExchangeLRU = i + 1; // next! (rollover check next pass)
+	}
 
-  }
+	if (!ulStatus)		// success?
+		Exchanges->fcExchange[i].type = type;	// allocate it.
 
-  if( !ulStatus )  // success?
-    Exchanges->fcExchange[i].type = type; // allocate it.
-  
-  else
-    i = -1;  // error - all exchanges "open"
+	else
+		i = -1;		// error - all exchanges "open"
 
-  return i;  
+	return i;
 }
 
-static void
-cpqfc_pci_unmap_extended_sg(struct pci_dev *pcidev,
-	PTACHYON fcChip,
-	ULONG x_ID)
+static void cpqfc_pci_unmap_extended_sg(struct pci_dev *pcidev, PTACHYON fcChip, u32 x_ID)
 {
 	// Unmaps the memory regions used to hold the scatter gather lists
 
 	PSGPAGES i;
 
 	// Were there any such regions needing unmapping?
-	if (! USES_EXTENDED_SGLIST(fcChip->SEST, x_ID))
-		return;	// No such regions, we're outta here.
+	if (!USES_EXTENDED_SGLIST(fcChip->SEST, x_ID))
+		return;		// No such regions, we're outta here.
 
 	// for each extended scatter gather region needing unmapping... 
-	for (i=fcChip->SEST->sgPages[x_ID] ; i != NULL ; i = i->next)
-		pci_unmap_single(pcidev, i->busaddr, i->maplen,
-			scsi_to_pci_dma_dir(PCI_DMA_TODEVICE));
+	for (i = fcChip->SEST->sgPages[x_ID]; i != NULL; i = i->next)
+		pci_unmap_single(pcidev, i->busaddr, i->maplen, scsi_to_pci_dma_dir(PCI_DMA_TODEVICE));
 }
 
 // Called also from cpqfcTScontrol.o, so can't be static
-void
-cpqfc_pci_unmap(struct pci_dev *pcidev, 
-	Scsi_Cmnd *cmd, 
-	PTACHYON fcChip, 
-	ULONG x_ID)
+void cpqfc_pci_unmap(struct pci_dev *pcidev, Scsi_Cmnd * cmd, PTACHYON fcChip, u32 x_ID)
 {
 	// Undo the DMA mappings
 	if (cmd->use_sg) {	// Used scatter gather list for data buffer?
 		cpqfc_pci_unmap_extended_sg(pcidev, fcChip, x_ID);
-		pci_unmap_sg(pcidev, cmd->buffer, cmd->use_sg,
-			scsi_to_pci_dma_dir(cmd->sc_data_direction));
+		pci_unmap_sg(pcidev, cmd->buffer, cmd->use_sg, scsi_to_pci_dma_dir(cmd->sc_data_direction));
 		// printk("umsg %d\n", cmd->use_sg);
-	}
-	else if (cmd->request_bufflen) {
+	} else if (cmd->request_bufflen) {
 		// printk("ums %p ", fcChip->SEST->u[ x_ID ].IWE.GAddr1);
-		pci_unmap_single(pcidev, fcChip->SEST->u[ x_ID ].IWE.GAddr1,
-			cmd->request_bufflen,
-			scsi_to_pci_dma_dir(cmd->sc_data_direction));
-	}	 
+		pci_unmap_single(pcidev, fcChip->SEST->u[x_ID].IWE.GAddr1, cmd->request_bufflen, scsi_to_pci_dma_dir(cmd->sc_data_direction));
+	}
 }
 
 // We call this routine to free an Exchange for any reason:
 // completed successfully, completed with error, aborted, etc.
 
-// returns FALSE if Exchange failed and "retry" is acceptable
-// returns TRUE if Exchange was successful, or retry is impossible
+// returns 0 if Exchange failed and "retry" is acceptable
+// returns 1 if Exchange was successful, or retry is impossible
 // (e.g. port/device gone).
 //scompleteexchange
 
-void cpqfcTSCompleteExchange( 
-       struct pci_dev *pcidev,
-       PTACHYON fcChip, 
-       ULONG x_ID)
-{
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  int already_unmapped = 0;
-  
-  if( x_ID < TACH_SEST_LEN ) // SEST-based (or LinkServ for FCP exchange)
-  {
-    if( Exchanges->fcExchange[ x_ID ].Cmnd == NULL ) // what#@!
-    {
-//      TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
-      printk(" x_ID %Xh, type %Xh, NULL ptr!\n", x_ID,
-			Exchanges->fcExchange[ x_ID ].type);
+void cpqfcTSCompleteExchange(struct pci_dev *pcidev, PTACHYON fcChip, u32 x_ID)
+{
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	int already_unmapped = 0;
 
-      goto CleanUpSestResources;  // this path should be very rare.
-    }
+	if (x_ID < TACH_SEST_LEN)	// SEST-based (or LinkServ for FCP exchange)
+	{
+		if (Exchanges->fcExchange[x_ID].Cmnd == NULL)	// what#@!
+		{
+//			TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
+			printk(" x_ID %Xh, type %Xh, NULL ptr!\n", x_ID, Exchanges->fcExchange[x_ID].type);
 
-    // we have Linux Scsi Cmnd ptr..., now check our Exchange status
-    // to decide how to complete this SEST FCP exchange
+			goto CleanUpSestResources;	// this path should be very rare.
+		}
+		// we have Linux Scsi Cmnd ptr..., now check our Exchange status
+		// to decide how to complete this SEST FCP exchange
 
-    if( Exchanges->fcExchange[ x_ID ].status ) // perhaps a Tach indicated problem,
-                                             // or abnormal exchange completion
-    {
-      // set FCP Link statistics
-     
-      if( Exchanges->fcExchange[ x_ID ].status & FC2_TIMEOUT)
-        fcChip->fcStats.timeouts++;
-      if( Exchanges->fcExchange[ x_ID ].status & INITIATOR_ABORT)
-        fcChip->fcStats.FC4aborted++;
-      if( Exchanges->fcExchange[ x_ID ].status & COUNT_ERROR)
-        fcChip->fcStats.CntErrors++;
-      if( Exchanges->fcExchange[ x_ID ].status & LINKFAIL_TX)
-        fcChip->fcStats.linkFailTX++;
-      if( Exchanges->fcExchange[ x_ID ].status & LINKFAIL_RX)
-        fcChip->fcStats.linkFailRX++;
-      if( Exchanges->fcExchange[ x_ID ].status & OVERFLOW)
-        fcChip->fcStats.CntErrors++;
-
-      // First, see if the Scsi upper level initiated an ABORT on this
-      // exchange...
-      if( Exchanges->fcExchange[ x_ID ].status == INITIATOR_ABORT )
-      {
-        printk(" DID_ABORT, x_ID %Xh, Cmnd %p ", 
-            x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
-        goto CleanUpSestResources;  // (we don't expect Linux _aborts)
-      }
-
-      // Did our driver timeout the Exchange, or did Tachyon indicate
-      // a failure during transmission?  Ask for retry with "SOFT_ERROR"
-      else if( Exchanges->fcExchange[ x_ID ].status & FC2_TIMEOUT) 
-      {
-//        printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n", 
-//            x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
-        Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
-      }
-      
-      // Did frame(s) for an open exchange arrive in the SFQ,
-      // meaning the SEST was unable to process them?
-      else if( Exchanges->fcExchange[ x_ID ].status & SFQ_FRAME) 
-      {
-//        printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n", 
-//            x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
-        Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
-      }
-      
-      // Did our driver timeout the Exchange, or did Tachyon indicate
-      // a failure during transmission?  Ask for retry with "SOFT_ERROR"
-      else if( 
-               (Exchanges->fcExchange[ x_ID ].status & LINKFAIL_TX) ||
-               (Exchanges->fcExchange[ x_ID ].status & PORTID_CHANGED) ||
-	       (Exchanges->fcExchange[ x_ID ].status & FRAME_TO)    ||
-	       (Exchanges->fcExchange[ x_ID ].status & INV_ENTRY)    ||
-	       (Exchanges->fcExchange[ x_ID ].status & ABORTSEQ_NOTIFY)    )
-
-
-      {
-//        printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n", 
-//            x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
-        Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
-
-
-      }
-
-      // e.g., a LOGOut happened, or device never logged back in.
-      else if( Exchanges->fcExchange[ x_ID ].status & DEVICE_REMOVED) 
-      {
-//	printk(" *LOGOut or timeout on login!* ");
-	// trigger?
-//        TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
-
-        Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_BAD_TARGET <<16);
-      }      
-		
-		      
-      // Did Tachyon indicate a CNT error?  We need further analysis
-      // to determine if the exchange is acceptable
-      else if( Exchanges->fcExchange[ x_ID ].status == COUNT_ERROR)
-      {
-        UCHAR ScsiStatus;
-        FCP_STATUS_RESPONSE *pFcpStatus = 
-	  (PFCP_STATUS_RESPONSE)&fcChip->SEST->RspHDR[ x_ID ].pl;
-
-      	ScsiStatus = pFcpStatus->fcp_status >>24;
-  
-	// If the command is a SCSI Read/Write type, we don't tolerate
-	// count errors of any kind; assume the count error is due to
-	// a dropped frame and ask for retry...
-	
-	if(( (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0x8) ||
-	    (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0x28) ||		
-            (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0xA) ||
-            (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0x2A) )
-	                   &&
-                     ScsiStatus == 0 )
-	{
-          // ask for retry
-/*          printk("COUNT_ERROR retry, x_ID %Xh, status %Xh, Cmnd %p\n", 
-            x_ID, Exchanges->fcExchange[ x_ID ].status,
-            Exchanges->fcExchange[ x_ID ].Cmnd);*/
-          Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
-	}
-	
-	else  // need more analysis
-	{
-	  cpqfcTSCheckandSnoopFCP(fcChip, x_ID);  // (will set ->result)
-	}
-      }
-      
-      // default: NOTE! We don't ever want to get here.  Getting here
-      // implies something new is happening that we've never had a test
-      // case for.  Need code maintenance!  Return "ERROR"
-      else
-      {
-	unsigned int stat = Exchanges->fcExchange[ x_ID ].status;
-        printk("DEFAULT result %Xh, x_ID %Xh, Cmnd %p", 
-          Exchanges->fcExchange[ x_ID ].status, x_ID, 
-	  Exchanges->fcExchange[ x_ID ].Cmnd);
-
-	if (stat & INVALID_ARGS)	printk(" INVALID_ARGS ");
-	if (stat & LNKDWN_OSLS)		printk(" LNKDWN_OSLS ");
-	if (stat & LNKDWN_LASER)	printk(" LNKDWN_LASER ");
-	if (stat & OUTQUE_FULL)		printk(" OUTQUE_FULL ");
-	if (stat & DRIVERQ_FULL)	printk(" DRIVERQ_FULL ");
-	if (stat & SEST_FULL)		printk(" SEST_FULL ");
-	if (stat & BAD_ALPA)		printk(" BAD_ALPA ");
-	if (stat & OVERFLOW)		printk(" OVERFLOW ");
-	if (stat & COUNT_ERROR)		printk(" COUNT_ERROR ");
-	if (stat & LINKFAIL_RX)		printk(" LINKFAIL_RX ");
-	if (stat & ABORTSEQ_NOTIFY)	printk(" ABORTSEQ_NOTIFY ");
-	if (stat & LINKFAIL_TX)		printk(" LINKFAIL_TX ");
-	if (stat & HOSTPROG_ERR)	printk(" HOSTPROG_ERR ");
-	if (stat & FRAME_TO)		printk(" FRAME_TO ");
-	if (stat & INV_ENTRY)		printk(" INV_ENTRY ");
-	if (stat & SESTPROG_ERR)	printk(" SESTPROG_ERR ");
-	if (stat & OUTBOUND_TIMEOUT)	printk(" OUTBOUND_TIMEOUT ");
-	if (stat & INITIATOR_ABORT)	printk(" INITIATOR_ABORT ");
-	if (stat & MEMPOOL_FAIL)	printk(" MEMPOOL_FAIL ");
-	if (stat & FC2_TIMEOUT)		printk(" FC2_TIMEOUT ");
-	if (stat & TARGET_ABORT)	printk(" TARGET_ABORT ");
-	if (stat & EXCHANGE_QUEUED)	printk(" EXCHANGE_QUEUED ");
-	if (stat & PORTID_CHANGED)	printk(" PORTID_CHANGED ");
-	if (stat & DEVICE_REMOVED)	printk(" DEVICE_REMOVED ");
-	if (stat & SFQ_FRAME)		printk(" SFQ_FRAME ");
-	printk("\n");
+		if (Exchanges->fcExchange[x_ID].status)	// perhaps a Tach indicated problem,
+			// or abnormal exchange completion
+		{
+			// set FCP Link statistics
+
+			if (Exchanges->fcExchange[x_ID].status & FC2_TIMEOUT)
+				fcChip->fcStats.timeouts++;
+			if (Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT)
+				fcChip->fcStats.FC4aborted++;
+			if (Exchanges->fcExchange[x_ID].status & COUNT_ERROR)
+				fcChip->fcStats.CntErrors++;
+			if (Exchanges->fcExchange[x_ID].status & LINKFAIL_TX)
+				fcChip->fcStats.linkFailTX++;
+			if (Exchanges->fcExchange[x_ID].status & LINKFAIL_RX)
+				fcChip->fcStats.linkFailRX++;
+			if (Exchanges->fcExchange[x_ID].status & OVERFLOW)
+				fcChip->fcStats.CntErrors++;
+
+			// First, see if the Scsi upper level initiated an ABORT on this
+			// exchange...
+			if (Exchanges->fcExchange[x_ID].status == INITIATOR_ABORT) {
+				printk(" DID_ABORT, x_ID %Xh, Cmnd %p ", x_ID, Exchanges->fcExchange[x_ID].Cmnd);
+				goto CleanUpSestResources;	// (we don't expect Linux _aborts)
+			}
+			// Did our driver timeout the Exchange, or did Tachyon indicate
+			// a failure during transmission?  Ask for retry with "SOFT_ERROR"
+			else if (Exchanges->fcExchange[x_ID].status & FC2_TIMEOUT) {
+//				printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n", 
+//					x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
+				Exchanges->fcExchange[x_ID].Cmnd->result = (DID_SOFT_ERROR << 16);
+			}
+			// Did frame(s) for an open exchange arrive in the SFQ,
+			// meaning the SEST was unable to process them?
+			else if (Exchanges->fcExchange[x_ID].status & SFQ_FRAME) {
+//				printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n", 
+//					x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
+				Exchanges->fcExchange[x_ID].Cmnd->result = (DID_SOFT_ERROR << 16);
+			}
+			// Did our driver timeout the Exchange, or did Tachyon indicate
+			// a failure during transmission?  Ask for retry with "SOFT_ERROR"
+			else if ((Exchanges->fcExchange[x_ID].status & LINKFAIL_TX) ||
+				 (Exchanges->fcExchange[x_ID].status & PORTID_CHANGED) || (Exchanges->fcExchange[x_ID].status & FRAME_TO) || (Exchanges->fcExchange[x_ID].status & INV_ENTRY) || (Exchanges->fcExchange[x_ID].status & ABORTSEQ_NOTIFY))
+
+			{
+//				printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n", 
+//					x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
+				Exchanges->fcExchange[x_ID].Cmnd->result = (DID_SOFT_ERROR << 16);
 
-        Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_ERROR <<16);
-      }
-    }
-    else    // definitely no Tach problem, but perhaps an FCP problem
-    {
-      // set FCP Link statistic
-      fcChip->fcStats.ok++;
-      cpqfcTSCheckandSnoopFCP( fcChip, x_ID);  // (will set ->result)    
-    }
 
-    cpqfc_pci_unmap(pcidev, Exchanges->fcExchange[x_ID].Cmnd, 
-			fcChip, x_ID); // undo DMA mappings.
-    already_unmapped = 1;
-
-    // OK, we've set the Scsi "->result" field, so proceed with calling
-    // Linux Scsi "done" (if not NULL), and free any kernel memory we
-    // may have allocated for the exchange.
-
-  PCI_TRACEO( (ULONG)Exchanges->fcExchange[x_ID].Cmnd, 0xAC);
-    // complete the command back to upper Scsi drivers
-    if( Exchanges->fcExchange[ x_ID ].Cmnd->scsi_done != NULL)
-    {
-      // Calling "done" on an Linux _abort() aborted
-      // Cmnd causes a kernel panic trying to re-free mem.
-      // Actually, we shouldn't do anything with an _abort CMND
-      if( Exchanges->fcExchange[ x_ID ].Cmnd->result != (DID_ABORT<<16) )
-      {
-        PCI_TRACE(0xAC)
-	call_scsi_done(Exchanges->fcExchange[ x_ID ].Cmnd);
-      }
-      else
-      {
-	Exchanges->fcExchange[ x_ID ].Cmnd->SCp.sent_command = 0;
-//	printk(" not calling scsi_done on x_ID %Xh, Cmnd %p\n",
-//			x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
-      }
-    }
-    else{
-	Exchanges->fcExchange[ x_ID ].Cmnd->SCp.sent_command = 0;
-      printk(" x_ID %Xh, type %Xh, Cdb0 %Xh\n", x_ID,
-	Exchanges->fcExchange[ x_ID ].type, 
-	Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0]);	      
-      printk(" cpqfcTS: Null scsi_done function pointer!\n");
-    }
+			}
+			// e.g., a LOGOut happened, or device never logged back in.
+			else if (Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED) {
+//				printk(" *LOGOut or timeout on login!* ");
+//				trigger?
+//				TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
+				Exchanges->fcExchange[x_ID].Cmnd->result = (DID_BAD_TARGET << 16);
+			}
+
+			// Did Tachyon indicate a CNT error?  We need further analysis
+			// to determine if the exchange is acceptable
+			else if (Exchanges->fcExchange[x_ID].status == COUNT_ERROR) {
+				u8 ScsiStatus;
+				FCP_STATUS_RESPONSE *pFcpStatus = (PFCP_STATUS_RESPONSE) & fcChip->SEST->RspHDR[x_ID].pl;
+
+				ScsiStatus = pFcpStatus->fcp_status >> 24;
+
+				// If the command is a SCSI Read/Write type, we don't tolerate
+				// count errors of any kind; assume the count error is due to
+				// a dropped frame and ask for retry...
+
+				if (((Exchanges->fcExchange[x_ID].Cmnd->cmnd[0] == 0x8) || (Exchanges->fcExchange[x_ID].Cmnd->cmnd[0] == 0x28) || (Exchanges->fcExchange[x_ID].Cmnd->cmnd[0] == 0xA) || (Exchanges->fcExchange[x_ID].Cmnd->cmnd[0] == 0x2A))
+				    && ScsiStatus == 0) {
+					// ask for retry
+//					printk("COUNT_ERROR retry, x_ID %Xh, status %Xh, Cmnd %p\n", 
+//						x_ID, Exchanges->fcExchange[ x_ID ].status,
+//						Exchanges->fcExchange[ x_ID ].Cmnd);
+					Exchanges->fcExchange[x_ID].Cmnd->result = (DID_SOFT_ERROR << 16);
+				}
+
+				else	// need more analysis
+				{
+					cpqfcTSCheckandSnoopFCP(fcChip, x_ID);	// (will set ->result)
+				}
+			}
+			// default: NOTE! We don't ever want to get here.  Getting here
+			// implies something new is happening that we've never had a test
+			// case for.  Need code maintenance!  Return "ERROR"
+			else {
+				unsigned int stat = Exchanges->fcExchange[x_ID].status;
+				printk("DEFAULT result %Xh, x_ID %Xh, Cmnd %p", Exchanges->fcExchange[x_ID].status, x_ID, Exchanges->fcExchange[x_ID].Cmnd);
+
+				if (stat & INVALID_ARGS)
+					printk(" INVALID_ARGS ");
+				if (stat & LNKDWN_OSLS)
+					printk(" LNKDWN_OSLS ");
+				if (stat & LNKDWN_LASER)
+					printk(" LNKDWN_LASER ");
+				if (stat & OUTQUE_FULL)
+					printk(" OUTQUE_FULL ");
+				if (stat & DRIVERQ_FULL)
+					printk(" DRIVERQ_FULL ");
+				if (stat & SEST_FULL)
+					printk(" SEST_FULL ");
+				if (stat & BAD_ALPA)
+					printk(" BAD_ALPA ");
+				if (stat & OVERFLOW)
+					printk(" OVERFLOW ");
+				if (stat & COUNT_ERROR)
+					printk(" COUNT_ERROR ");
+				if (stat & LINKFAIL_RX)
+					printk(" LINKFAIL_RX ");
+				if (stat & ABORTSEQ_NOTIFY)
+					printk(" ABORTSEQ_NOTIFY ");
+				if (stat & LINKFAIL_TX)
+					printk(" LINKFAIL_TX ");
+				if (stat & HOSTPROG_ERR)
+					printk(" HOSTPROG_ERR ");
+				if (stat & FRAME_TO)
+					printk(" FRAME_TO ");
+				if (stat & INV_ENTRY)
+					printk(" INV_ENTRY ");
+				if (stat & SESTPROG_ERR)
+					printk(" SESTPROG_ERR ");
+				if (stat & OUTBOUND_TIMEOUT)
+					printk(" OUTBOUND_TIMEOUT ");
+				if (stat & INITIATOR_ABORT)
+					printk(" INITIATOR_ABORT ");
+				if (stat & MEMPOOL_FAIL)
+					printk(" MEMPOOL_FAIL ");
+				if (stat & FC2_TIMEOUT)
+					printk(" FC2_TIMEOUT ");
+				if (stat & TARGET_ABORT)
+					printk(" TARGET_ABORT ");
+				if (stat & EXCHANGE_QUEUED)
+					printk(" EXCHANGE_QUEUED ");
+				if (stat & PORTID_CHANGED)
+					printk(" PORTID_CHANGED ");
+				if (stat & DEVICE_REMOVED)
+					printk(" DEVICE_REMOVED ");
+				if (stat & SFQ_FRAME)
+					printk(" SFQ_FRAME ");
+				printk("\n");
+
+				Exchanges->fcExchange[x_ID].Cmnd->result = (DID_ERROR << 16);
+			}
+		} else		// definitely no Tach problem, but perhaps an FCP problem
+		{
+			// set FCP Link statistic
+			fcChip->fcStats.ok++;
+			cpqfcTSCheckandSnoopFCP(fcChip, x_ID);	// (will set ->result)    
+		}
+
+		cpqfc_pci_unmap(pcidev, Exchanges->fcExchange[x_ID].Cmnd, fcChip, x_ID);	// undo DMA mappings.
+		already_unmapped = 1;
+
+		// OK, we've set the Scsi "->result" field, so proceed with calling
+		// Linux Scsi "done" (if not NULL), and free any kernel memory we
+		// may have allocated for the exchange.
+
+		PCI_TRACEO((u32) Exchanges->fcExchange[x_ID].Cmnd, 0xAC);
+		// complete the command back to upper Scsi drivers
+		if (Exchanges->fcExchange[x_ID].Cmnd->scsi_done != NULL) {
+			// Calling "done" on an Linux _abort() aborted
+			// Cmnd causes a kernel panic trying to re-free mem.
+			// Actually, we shouldn't do anything with an _abort CMND
+			if (Exchanges->fcExchange[x_ID].Cmnd->result != (DID_ABORT << 16)) {
+				PCI_TRACE(0xAC)
+				    call_scsi_done(Exchanges->fcExchange[x_ID].Cmnd);
+			} else {
+				Exchanges->fcExchange[x_ID].Cmnd->SCp.sent_command = 0;
+//				printk(" not calling scsi_done on x_ID %Xh, Cmnd %p\n",
+//					x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
+			}
+		} else {
+			Exchanges->fcExchange[x_ID].Cmnd->SCp.sent_command = 0;
+			printk(" x_ID %Xh, type %Xh, Cdb0 %Xh\n", x_ID, Exchanges->fcExchange[x_ID].type, Exchanges->fcExchange[x_ID].Cmnd->cmnd[0]);
+			printk(" cpqfcTS: Null scsi_done function pointer!\n");
+		}
 
 
-    // Now, clean up non-Scsi_Cmnd items...
+		// Now, clean up non-Scsi_Cmnd items...
 CleanUpSestResources:
-   
-    if (!already_unmapped) 
-	cpqfc_pci_unmap(pcidev, Exchanges->fcExchange[x_ID].Cmnd, 
-			fcChip, x_ID); // undo DMA mappings.
-
-    // Was an Extended Scatter/Gather page allocated?  We know
-    // this by checking DWORD 4, bit 31 ("LOC") of SEST entry
-    if( !(fcChip->SEST->u[ x_ID ].IWE.Buff_Off & 0x80000000))
-    {
-      PSGPAGES p, next;
 
-      // extended S/G list was used -- Free the allocated ext. S/G pages
-      for (p = fcChip->SEST->sgPages[x_ID]; p != NULL; p = next) {
-	 next = p->next;
-	 kfree(p);
-      }
-      fcChip->SEST->sgPages[x_ID] = NULL;
-    }
-  
-    Exchanges->fcExchange[ x_ID ].Cmnd = NULL; 
-  }  // Done with FCP (SEST) exchanges
-
-
-  // the remaining logic is common to ALL Exchanges: 
-  // FCP(SEST) and LinkServ.
-
-  Exchanges->fcExchange[ x_ID ].type = 0; // there -- FREE!  
-  Exchanges->fcExchange[ x_ID ].status = 0; 
-
-  PCI_TRACEO( x_ID, 0xAC)
-     
-  
-  return;
-}   // (END of CompleteExchange function)
- 
+		if (!already_unmapped)
+			cpqfc_pci_unmap(pcidev, Exchanges->fcExchange[x_ID].Cmnd, fcChip, x_ID);	// undo DMA mappings.
+
+		// Was an Extended Scatter/Gather page allocated?  We know
+		// this by checking DWORD 4, bit 31 ("LOC") of SEST entry
+		if (!(fcChip->SEST->u[x_ID].IWE.Buff_Off & 0x80000000)) {
+			PSGPAGES p, next;
+
+			// extended S/G list was used -- Free the allocated ext. S/G pages
+			for (p = fcChip->SEST->sgPages[x_ID]; p != NULL; p = next) {
+				next = p->next;
+				kfree(p);
+			}
+			fcChip->SEST->sgPages[x_ID] = NULL;
+		}
+
+		Exchanges->fcExchange[x_ID].Cmnd = NULL;
+	}			// Done with FCP (SEST) exchanges
+
+
+	// the remaining logic is common to ALL Exchanges: 
+	// FCP(SEST) and LinkServ.
+
+	Exchanges->fcExchange[x_ID].type = 0;	// there -- FREE!  
+	Exchanges->fcExchange[x_ID].status = 0;
+
+	PCI_TRACEO(x_ID, 0xAC)
+}				// (END of CompleteExchange function)
+
 
 
 
@@ -6249,161 +5140,137 @@
 // device types, etc., to facilitate the Fibre-Channel to SCSI
 // "mapping".  
 // (Watch for BIG Endian confusion on some payload fields)
-void cpqfcTSCheckandSnoopFCP( PTACHYON fcChip, ULONG x_ID)
+void cpqfcTSCheckandSnoopFCP(PTACHYON fcChip, u32 x_ID)
 {
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  Scsi_Cmnd *Cmnd = Exchanges->fcExchange[ x_ID].Cmnd;
-  FCP_STATUS_RESPONSE *pFcpStatus = 
-    (PFCP_STATUS_RESPONSE)&fcChip->SEST->RspHDR[ x_ID ].pl;
-  UCHAR ScsiStatus;
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	Scsi_Cmnd *Cmnd = Exchanges->fcExchange[x_ID].Cmnd;
+	FCP_STATUS_RESPONSE *pFcpStatus = (PFCP_STATUS_RESPONSE) & fcChip->SEST->RspHDR[x_ID].pl;
+	u8 ScsiStatus;
 
-  ScsiStatus = pFcpStatus->fcp_status >>24;
+	ScsiStatus = pFcpStatus->fcp_status >> 24;
 
 #ifdef FCP_COMPLETION_DBG
-  printk("ScsiStatus = 0x%X\n", ScsiStatus);
-#endif	
+	printk("ScsiStatus = 0x%X\n", ScsiStatus);
+#endif
 
-  // First, check FCP status
-  if( pFcpStatus->fcp_status & FCP_RSP_LEN_VALID )
-  {
-    // check response code (RSP_CODE) -- most popular is bad len
-    // 1st 4 bytes of rsp info -- only byte 3 interesting
-    if( pFcpStatus->fcp_rsp_info & FCP_DATA_LEN_NOT_BURST_LEN )
-    { 
+	// First, check FCP status
+	if (pFcpStatus->fcp_status & FCP_RSP_LEN_VALID) {
+		// check response code (RSP_CODE) -- most popular is bad len
+		// 1st 4 bytes of rsp info -- only byte 3 interesting
+		if (pFcpStatus->fcp_rsp_info & FCP_DATA_LEN_NOT_BURST_LEN) {
 
-      // do we EVER get here?
-      printk("cpqfcTS: FCP data len not burst len, x_ID %Xh\n", x_ID);
-    }
-  }
+			// do we EVER get here?
+			printk("cpqfcTS: FCP data len not burst len, x_ID %Xh\n", x_ID);
+		}
+	}
+	// for now, go by the ScsiStatus, and manipulate certain
+	// commands when necessary...
+	if (ScsiStatus == 0)	// SCSI status byte "good"?
+	{
+		Cmnd->result = 0;	// everything's OK
 
-  // for now, go by the ScsiStatus, and manipulate certain
-  // commands when necessary...
-  if( ScsiStatus == 0) // SCSI status byte "good"?
-  {
-    Cmnd->result = 0; // everything's OK
+		if ((Cmnd->cmnd[0] == INQUIRY)) {
+			u8 *InquiryData = Cmnd->request_buffer;
+			PFC_LOGGEDIN_PORT pLoggedInPort;
+
+			// We need to manipulate INQUIRY
+			// strings for COMPAQ RAID controllers to force
+			// Linux to scan additional LUNs.  Namely, set
+			// the Inquiry string byte 2 (ANSI-approved version)
+			// to 2.
+
+			if (!memcmp(&InquiryData[8], "COMPAQ", 6)) {
+				InquiryData[2] = 0x2;	// claim SCSI-2 compliance,
+				// so multiple LUNs may be scanned.
+				// (no SCSI-2 problems known in CPQ)
+			}
+			// snoop the Inquiry to detect Disk, Tape, etc. type
+			// (search linked list for the port_id we sent INQUIRY to)
+			pLoggedInPort = fcFindLoggedInPort(fcChip, NULL,	// DON'T search Scsi Nexus (we will set it)
+							   Exchanges->fcExchange[x_ID].fchs.d_id & 0xFFFFFF, NULL,	// DON'T search linked list for FC WWN
+							   NULL);	// DON'T care about end of list
+
+			if (pLoggedInPort) {
+				pLoggedInPort->ScsiNexus.InqDeviceType = InquiryData[0];
+			} else {
+				printk("cpqfcTS: can't find LoggedIn FC port %06X for INQUIRY\n", Exchanges->fcExchange[x_ID].fchs.d_id & 0xFFFFFF);
+			}
+		}
+	}
 
-    if( (Cmnd->cmnd[0] == INQUIRY)) 
-    {
-      UCHAR *InquiryData = Cmnd->request_buffer;
-      PFC_LOGGEDIN_PORT pLoggedInPort;
+	// Scsi Status not good -- pass it back to caller 
 
-      // We need to manipulate INQUIRY
-      // strings for COMPAQ RAID controllers to force
-      // Linux to scan additional LUNs.  Namely, set
-      // the Inquiry string byte 2 (ANSI-approved version)
-      // to 2.
-
-      if( !memcmp( &InquiryData[8], "COMPAQ", 6 ))
-      {
-        InquiryData[2] = 0x2;  // claim SCSI-2 compliance,
-                               // so multiple LUNs may be scanned.
-                               // (no SCSI-2 problems known in CPQ)
-      }
-        
-      // snoop the Inquiry to detect Disk, Tape, etc. type
-      // (search linked list for the port_id we sent INQUIRY to)
-      pLoggedInPort = fcFindLoggedInPort( fcChip,
-        NULL,     // DON'T search Scsi Nexus (we will set it)
-        Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF,        
-        NULL,     // DON'T search linked list for FC WWN
-        NULL);    // DON'T care about end of list
- 
-      if( pLoggedInPort )
-      {
-        pLoggedInPort->ScsiNexus.InqDeviceType = InquiryData[0];
-      }
-      else
-      {
-	printk("cpqfcTS: can't find LoggedIn FC port %06X for INQUIRY\n",
-          Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF);
-      }
-    }
-  }
+	else {
+		Cmnd->result = ScsiStatus;	// SCSI status byte is 1st
 
+		// check for valid "sense" data
 
-  // Scsi Status not good -- pass it back to caller 
+		if (pFcpStatus->fcp_status & FCP_SNS_LEN_VALID) {	// limit Scsi Sense field length!
+			int SenseLen = pFcpStatus->fcp_sns_len >> 24;	// (BigEndian) lower byte
 
-  else
-  {
-    Cmnd->result = ScsiStatus; // SCSI status byte is 1st
-    
-    // check for valid "sense" data
+			SenseLen = SenseLen > sizeof(Cmnd->sense_buffer) ? sizeof(Cmnd->sense_buffer) : SenseLen;
 
-    if( pFcpStatus->fcp_status & FCP_SNS_LEN_VALID ) 
-    {            // limit Scsi Sense field length!
-      int SenseLen = pFcpStatus->fcp_sns_len >>24; // (BigEndian) lower byte
-      
-      SenseLen = SenseLen > sizeof( Cmnd->sense_buffer) ? 
-        sizeof( Cmnd->sense_buffer) : SenseLen;
-	   
-
-#ifdef FCP_COMPLETION_DBG	    
-      printk("copy sense_buffer %p, len %d, result %Xh\n",
-        Cmnd->sense_buffer, SenseLen, Cmnd->result);
-#endif	  
-
-      // NOTE: There is some dispute over the FCP response
-      // format.  Most FC devices assume that FCP_RSP_INFO
-      // is 8 bytes long, in spite of the fact that FCP_RSP_LEN
-      // is (virtually) always 0 and the field is "invalid".  
-      // Some other devices assume that
-      // the FCP_SNS_INFO begins after FCP_RSP_LEN bytes (i.e. 0)
-      // when the FCP_RSP is invalid (this almost appears to be
-      // one of those "religious" issues).
-      // Consequently, we test the usual position of FCP_SNS_INFO
-      // for 7Xh, since the SCSI sense format says the first
-      // byte ("error code") should be 0x70 or 0x71.  In practice,
-      // we find that every device does in fact have 0x70 or 0x71
-      // in the first byte position, so this test works for all
-      // FC devices.  
-      // (This logic is especially effective for the CPQ/DEC HSG80
-      // & HSG60 controllers).
-
-      if( (pFcpStatus->fcp_sns_info[0] & 0x70) == 0x70 )
-        memcpy( Cmnd->sense_buffer, 
-          &pFcpStatus->fcp_sns_info[0], SenseLen);
-      else
-      {
-        unsigned char *sbPtr = 
-		(unsigned char *)&pFcpStatus->fcp_sns_info[0];
-        sbPtr -= 8;  // back up 8 bytes hoping to find the
-	             // start of the sense buffer
-        memcpy( Cmnd->sense_buffer, sbPtr, SenseLen);
-      }
-
-      // in the special case of Device Reset, tell upper layer
-      // to immediately retry (with SOFT_ERROR status)
-      // look for Sense Key Unit Attention (0x6) with ASC Device
-      // Reset (0x29)
-      //	    printk("SenseLen %d, Key = 0x%X, ASC = 0x%X\n",
-      //		    SenseLen, Cmnd->sense_buffer[2], 
-      //                   Cmnd->sense_buffer[12]);
-      if( ((Cmnd->sense_buffer[2] & 0xF) == 0x6) &&
-	        (Cmnd->sense_buffer[12] == 0x29) ) // Sense Code "reset"
-      {
-        Cmnd->result |= (DID_SOFT_ERROR << 16); // "Host" status byte 3rd
-      }
- 
-      // check for SenseKey "HARDWARE ERROR", ASC InternalTargetFailure
-      else if(  ((Cmnd->sense_buffer[2] & 0xF) == 0x4) &&  // "hardware error"
-      	        (Cmnd->sense_buffer[12] == 0x44) ) // Addtl. Sense Code 
-      {
+
+#ifdef FCP_COMPLETION_DBG
+			printk("copy sense_buffer %p, len %d, result %Xh\n", Cmnd->sense_buffer, SenseLen, Cmnd->result);
+#endif
+
+			// NOTE: There is some dispute over the FCP response
+			// format.  Most FC devices assume that FCP_RSP_INFO
+			// is 8 bytes long, in spite of the fact that FCP_RSP_LEN
+			// is (virtually) always 0 and the field is "invalid".  
+			// Some other devices assume that
+			// the FCP_SNS_INFO begins after FCP_RSP_LEN bytes (i.e. 0)
+			// when the FCP_RSP is invalid (this almost appears to be
+			// one of those "religious" issues).
+			// Consequently, we test the usual position of FCP_SNS_INFO
+			// for 7Xh, since the SCSI sense format says the first
+			// byte ("error code") should be 0x70 or 0x71.  In practice,
+			// we find that every device does in fact have 0x70 or 0x71
+			// in the first byte position, so this test works for all
+			// FC devices.  
+			// (This logic is especially effective for the CPQ/DEC HSG80
+			// & HSG60 controllers).
+
+			if ((pFcpStatus->fcp_sns_info[0] & 0x70) == 0x70)
+				memcpy(Cmnd->sense_buffer, &pFcpStatus->fcp_sns_info[0], SenseLen);
+			else {
+				unsigned char *sbPtr = (unsigned char *) &pFcpStatus->fcp_sns_info[0];
+				sbPtr -= 8;	// back up 8 bytes hoping to find the
+				// start of the sense buffer
+				memcpy(Cmnd->sense_buffer, sbPtr, SenseLen);
+			}
+
+			// in the special case of Device Reset, tell upper layer
+			// to immediately retry (with SOFT_ERROR status)
+			// look for Sense Key Unit Attention (0x6) with ASC Device
+			// Reset (0x29)
+			//            printk("SenseLen %d, Key = 0x%X, ASC = 0x%X\n",
+			//                    SenseLen, Cmnd->sense_buffer[2], 
+			//                   Cmnd->sense_buffer[12]);
+			if (((Cmnd->sense_buffer[2] & 0xF) == 0x6) && (Cmnd->sense_buffer[12] == 0x29))	// Sense Code "reset"
+			{
+				Cmnd->result |= (DID_SOFT_ERROR << 16);	// "Host" status byte 3rd
+			}
+			// check for SenseKey "HARDWARE ERROR", ASC InternalTargetFailure
+			else if (((Cmnd->sense_buffer[2] & 0xF) == 0x4) &&	// "hardware error"
+				 (Cmnd->sense_buffer[12] == 0x44))	// Addtl. Sense Code 
+			{
 //        printk("HARDWARE_ERROR, Channel/Target/Lun %d/%d/%d\n",
-//		Cmnd->channel, Cmnd->target, Cmnd->lun);
-      	Cmnd->result |= (DID_ERROR << 16); // "Host" status byte 3rd
-      }
-      
-    }  // (end of sense len valid)
+//              Cmnd->channel, Cmnd->target, Cmnd->lun);
+				Cmnd->result |= (DID_ERROR << 16);	// "Host" status byte 3rd
+			}
 
-    // there is no sense data to help out Linux's Scsi layers...
-    // We'll just return the Scsi status and hope he will "do the 
-    // right thing"
-    else
-    {
-      // as far as we know, the Scsi status is sufficient
-      Cmnd->result |= (DID_OK << 16); // "Host" status byte 3rd
-    }
-  }
+		}		// (end of sense len valid)
+
+		// there is no sense data to help out Linux's Scsi layers...
+		// We'll just return the Scsi status and hope he will "do the 
+		// right thing"
+		else {
+			// as far as we know, the Scsi status is sufficient
+			Cmnd->result |= (DID_OK << 16);	// "Host" status byte 3rd
+		}
+	}
 }
 
 
@@ -6413,118 +5280,108 @@
 // remember BIG ENDIAN payload - DWord values must be byte-reversed
 // (hence the affinity for byte pointer building).
 
-static int build_FCP_payload( Scsi_Cmnd *Cmnd, 
-      UCHAR* payload, ULONG type, ULONG fcp_dl )
+static int build_FCP_payload(Scsi_Cmnd * Cmnd, u8 * payload, u32 type, u32 fcp_dl)
 {
-  int i;
+	int i;
 
-  
-  switch( type)
-  {
-		  
-    case SCSI_IWE: 
-    case SCSI_IRE:        
-      // 8 bytes FCP_LUN
-      // Peripheral Device or Volume Set addressing, and LUN mapping
-      // When the FC port was looked up, we copied address mode
-      // and any LUN mask to the scratch pad SCp.phase & .mode
-
-      *payload++ = (UCHAR)Cmnd->SCp.phase;
-
-      // Now, because of "lun masking" 
-      // (aka selective storage presentation),
-      // the contiguous Linux Scsi lun number may not match the
-      // device's lun number, so we may have to "map".  
-      
-      *payload++ = (UCHAR)Cmnd->SCp.have_data_in;
-      
-      // We don't know of anyone in the FC business using these 
-      // extra "levels" of addressing.  In fact, confusion still exists
-      // just using the FIRST level... ;-)
-      
-      *payload++ = 0;  // 2nd level addressing
-      *payload++ = 0;
-      *payload++ = 0;  // 3rd level addressing
-      *payload++ = 0;
-      *payload++ = 0;  // 4th level addressing
-      *payload++ = 0;
-
-      // 4 bytes Control Field FCP_CNTL
-      *payload++ = 0;    // byte 0: (MSB) reserved
-      *payload++ = 0;    // byte 1: task codes
-
-                         // byte 2: task management flags
-      // another "use" of the spare field to accomplish TDR
-      // note combination needed
-      if( (Cmnd->cmnd[0] == RELEASE) &&
-          (Cmnd->SCp.buffers_residual == FCP_TARGET_RESET) )
-      {
-        Cmnd->cmnd[0] = 0;    // issue "Test Unit Ready" for TDR
-        *payload++ = 0x20;    // target device reset bit
-      }
-      else
-        *payload++ = 0;    // no TDR
-		      // byte 3: (LSB) execution management codes
-		      // bit 0 write, bit 1 read (don't set together)
-      
-      if( fcp_dl != 0 )
-      {
-        if( type == SCSI_IWE )         // WRITE
-          *payload++ = 1;
-        else                           // READ
-          *payload++ = 2;
-      }
-      else
-      {
-	// On some devices, if RD or WR bits are set,
-	// and fcp_dl is 0, they will generate an error on the command.
-	// (i.e., if direction is specified, they insist on a length).
-	*payload++ = 0;                // no data (necessary for CPQ)
-      }
-
-
-      // NOTE: clean this up if/when MAX_COMMAND_SIZE is increased to 16
-      // FCP_CDB allows 16 byte SCSI command descriptor blk;
-      // Linux SCSI CDB array is MAX_COMMAND_SIZE (12 at this time...)
-      for( i=0; (i < Cmnd->cmd_len) && i < MAX_COMMAND_SIZE; i++)
-	*payload++ = Cmnd->cmnd[i];
-
-      if( Cmnd->cmd_len == 16 )
-      {
-        memcpy( payload, &Cmnd->SCp.buffers_residual, 4);
-      }
-      payload+= (16 - i);  
-
-		      // FCP_DL is largest number of expected data bytes
-		      // per CDB (i.e. read/write command)
-      *payload++ = (UCHAR)(fcp_dl >>24);  // (MSB) 8 bytes data len FCP_DL
-      *payload++ = (UCHAR)(fcp_dl >>16);
-      *payload++ = (UCHAR)(fcp_dl >>8);
-      *payload++ = (UCHAR)fcp_dl;    // (LSB)
-      break;
-
-    case SCSI_TWE:          // need FCP_XFER_RDY
-      *payload++ = 0;     // (4 bytes) DATA_RO (MSB byte 0)
-      *payload++ = 0;
-      *payload++ = 0;
-      *payload++ = 0;     // LSB (byte 3)
-			     // (4 bytes) BURST_LEN
-			     // size of following FCP_DATA payload
-      *payload++ = (UCHAR)(fcp_dl >>24);  // (MSB) 8 bytes data len FCP_DL
-      *payload++ = (UCHAR)(fcp_dl >>16);
-      *payload++ = (UCHAR)(fcp_dl >>8);
-      *payload++ = (UCHAR)fcp_dl;    // (LSB)
-		       // 4 bytes RESERVED
-      *payload++ = 0;
-      *payload++ = 0;
-      *payload++ = 0;
-      *payload++ = 0;
-      break;
 
-    default:
-      break;
-  }
+	switch (type) {
 
-  return 0;
-}
+	case SCSI_IWE:
+	case SCSI_IRE:
+		// 8 bytes FCP_LUN
+		// Peripheral Device or Volume Set addressing, and LUN mapping
+		// When the FC port was looked up, we copied address mode
+		// and any LUN mask to the scratch pad SCp.phase & .mode
+
+		*payload++ = (u8) Cmnd->SCp.phase;
+
+		// Now, because of "lun masking" 
+		// (aka selective storage presentation),
+		// the contiguous Linux Scsi lun number may not match the
+		// device's lun number, so we may have to "map".  
+
+		*payload++ = (u8) Cmnd->SCp.have_data_in;
+
+		// We don't know of anyone in the FC business using these 
+		// extra "levels" of addressing.  In fact, confusion still exists
+		// just using the FIRST level... ;-)
+
+		*payload++ = 0;	// 2nd level addressing
+		*payload++ = 0;
+		*payload++ = 0;	// 3rd level addressing
+		*payload++ = 0;
+		*payload++ = 0;	// 4th level addressing
+		*payload++ = 0;
+
+		// 4 bytes Control Field FCP_CNTL
+		*payload++ = 0;	// byte 0: (MSB) reserved
+		*payload++ = 0;	// byte 1: task codes
+
+		// byte 2: task management flags
+		// another "use" of the spare field to accomplish TDR
+		// note combination needed
+		if ((Cmnd->cmnd[0] == RELEASE) && (Cmnd->SCp.buffers_residual == FCP_TARGET_RESET)) {
+			Cmnd->cmnd[0] = 0;	// issue "Test Unit Ready" for TDR
+			*payload++ = 0x20;	// target device reset bit
+		} else
+			*payload++ = 0;	// no TDR
+		// byte 3: (LSB) execution management codes
+		// bit 0 write, bit 1 read (don't set together)
+
+		if (fcp_dl != 0) {
+			if (type == SCSI_IWE)	// WRITE
+				*payload++ = 1;
+			else	// READ
+				*payload++ = 2;
+		} else {
+			// On some devices, if RD or WR bits are set,
+			// and fcp_dl is 0, they will generate an error on the command.
+			// (i.e., if direction is specified, they insist on a length).
+			*payload++ = 0;	// no data (necessary for CPQ)
+		}
+
+
+		// NOTE: clean this up if/when MAX_COMMAND_SIZE is increased to 16
+		// FCP_CDB allows 16 byte SCSI command descriptor blk;
+		// Linux SCSI CDB array is MAX_COMMAND_SIZE (12 at this time...)
+		for (i = 0; (i < Cmnd->cmd_len) && i < MAX_COMMAND_SIZE; i++)
+			*payload++ = Cmnd->cmnd[i];
+
+		if (Cmnd->cmd_len == 16) {
+			memcpy(payload, &Cmnd->SCp.buffers_residual, 4);
+		}
+		payload += (16 - i);
 
+		// FCP_DL is largest number of expected data bytes
+		// per CDB (i.e. read/write command)
+		*payload++ = (u8) (fcp_dl >> 24);	// (MSB) 8 bytes data len FCP_DL
+		*payload++ = (u8) (fcp_dl >> 16);
+		*payload++ = (u8) (fcp_dl >> 8);
+		*payload++ = (u8) fcp_dl;	// (LSB)
+		break;
+
+	case SCSI_TWE:		// need FCP_XFER_RDY
+		*payload++ = 0;	// (4 bytes) DATA_RO (MSB byte 0)
+		*payload++ = 0;
+		*payload++ = 0;
+		*payload++ = 0;	// LSB (byte 3)
+		// (4 bytes) BURST_LEN
+		// size of following FCP_DATA payload
+		*payload++ = (u8) (fcp_dl >> 24);	// (MSB) 8 bytes data len FCP_DL
+		*payload++ = (u8) (fcp_dl >> 16);
+		*payload++ = (u8) (fcp_dl >> 8);
+		*payload++ = (u8) fcp_dl;	// (LSB)
+		// 4 bytes RESERVED
+		*payload++ = 0;
+		*payload++ = 0;
+		*payload++ = 0;
+		*payload++ = 0;
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/cyberstorm.c linux-2.4.21-pre6/drivers/scsi/cyberstorm.c
--- linux-2.4.20/drivers/scsi/cyberstorm.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/cyberstorm.c	2003-03-26 23:49:19.000000000 +0000
@@ -131,8 +131,8 @@
 		esp->eregs = (struct ESP_regs *)(address + CYBER_ESP_ADDR);
 		
 		/* Set the command buffer */
-		esp->esp_command = (volatile unsigned char*) cmd_buffer;
-		esp->esp_command_dvma = virt_to_bus(cmd_buffer);
+		esp->esp_command = cmd_buffer;
+		esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer);
 
 		esp->irq = IRQ_AMIGA_PORTS;
 		request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/cyberstormII.c linux-2.4.21-pre6/drivers/scsi/cyberstormII.c
--- linux-2.4.20/drivers/scsi/cyberstormII.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/cyberstormII.c	2003-03-26 23:49:20.000000000 +0000
@@ -125,8 +125,8 @@
 		esp->eregs = eregs;
 		
 		/* Set the command buffer */
-		esp->esp_command = (volatile unsigned char*) cmd_buffer;
-		esp->esp_command_dvma = virt_to_bus(cmd_buffer);
+		esp->esp_command = cmd_buffer;
+		esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer);
 
 		esp->irq = IRQ_AMIGA_PORTS;
 		request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/dpt_i2o.c linux-2.4.21-pre6/drivers/scsi/dpt_i2o.c
--- linux-2.4.20/drivers/scsi/dpt_i2o.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/dpt_i2o.c	2003-03-26 23:49:20.000000000 +0000
@@ -1498,7 +1498,7 @@
 							pDev->next_lun; pDev = pDev->next_lun){
 					}
 					pDev->next_lun = kmalloc(sizeof(struct adpt_device),GFP_KERNEL);
-					if(pDev == NULL) {
+					if(pDev->next_lun == NULL) {
 						return -ENOMEM;
 					}
 					memset(pDev->next_lun,0,sizeof(struct adpt_device));
@@ -2560,7 +2560,7 @@
 
 	if(pHba->initialized ) {
 		if (adpt_i2o_status_get(pHba) < 0) {
-			if((rcode = adpt_i2o_reset_hba(pHba) != 0)){
+			if((rcode = adpt_i2o_reset_hba(pHba)) != 0){
 				printk(KERN_WARNING"%s: Could NOT reset.\n", pHba->name);
 				return rcode;
 			}
@@ -2586,7 +2586,7 @@
 			}
 		}
 	} else {
-		if((rcode = adpt_i2o_reset_hba(pHba) != 0)){
+		if((rcode = adpt_i2o_reset_hba(pHba)) != 0){
 			printk(KERN_WARNING"%s: Could NOT reset.\n", pHba->name);
 			return rcode;
 		}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/eata_generic.h linux-2.4.21-pre6/drivers/scsi/eata_generic.h
--- linux-2.4.20/drivers/scsi/eata_generic.h	2001-08-15 08:22:16.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/eata_generic.h	2003-03-26 23:49:40.000000000 +0000
@@ -97,7 +97,7 @@
 #define DELAY(x) { ulong flags, i;                \
                    save_flags(flags); sti();      \
                    i = jiffies + (x * HZ);        \
-                   while (jiffies < i);           \
+                   while (time_before(jiffies, i)) cpu_relax();           \
                    restore_flags(flags); }
 
 /***********************************************
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/fastlane.c linux-2.4.21-pre6/drivers/scsi/fastlane.c
--- linux-2.4.20/drivers/scsi/fastlane.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/fastlane.c	2003-03-26 23:49:29.000000000 +0000
@@ -140,7 +140,7 @@
 
 		/* Map the physical address space into virtual kernel space */
 		address = (unsigned long)
-			ioremap_nocache(board, z->resource.end-board+1);
+			z_ioremap(board, z->resource.end-board+1);
 
 		if(!address){
 			printk("Could not remap Fastlane controller memory!");
@@ -161,8 +161,8 @@
 		esp->edev = (void *) address;
 		
 		/* Set the command buffer */
-		esp->esp_command = (volatile unsigned char*) cmd_buffer;
-		esp->esp_command_dvma = virt_to_bus(cmd_buffer);
+		esp->esp_command = cmd_buffer;
+		esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer);
 
 		esp->irq = IRQ_AMIGA_PORTS;
 		esp->slot = board+FASTLANE_ESP_ADDR;
@@ -189,7 +189,7 @@
 	return 0;
 
  err_unmap:
-	iounmap((void *)address);
+	z_iounmap((void *)address);
  err_unregister:
 	scsi_unregister (esp->ehost);
  err_release:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/gdth.c linux-2.4.21-pre6/drivers/scsi/gdth.c
--- linux-2.4.20/drivers/scsi/gdth.c	2001-11-09 22:05:06.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/gdth.c	2003-03-26 23:49:49.000000000 +0000
@@ -4,9 +4,11 @@
  * Intel Corporation:  Storage RAID Controllers                         *
  *                                                                      *
  * gdth.c                                                               *
- * Copyright (C) 1995-01 ICP vortex, an Intel company,  Achim Leubner   *
+ * Copyright (C) 1995-02 ICP vortex, an Intel company,  Achim Leubner   *
+ * <achim.leubner@intel.com>                                            *
  *                                                                      *
- * <achim@vortex.de>                                                    *
+ * Additions/Fixes: Boji Tony Kannanthanam                              *
+ * <boji.t.kannanthanam@intel.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    *
@@ -22,9 +24,23 @@
  * along with this kernel; if not, write to the Free Software           *
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.            *
  *                                                                      *
- * Tested with Linux 1.2.13, ..., 2.2.19, ..., 2.4.7                    *
+ * Tested with Linux 1.2.13, ..., 2.2.20, ..., 2.4.18                   *
  *                                                                      *
  * $Log: gdth.c,v $
+ * Revision 1.61  2002/10/03 09:35:22  boji
+ * Fixed SCREENSERVICE intialisation in SMP cases.
+ * Added checks for gdth_polling before GDTH_HA_LOCK
+ *
+ * Revision 1.60  2002/02/05 09:35:22  achim
+ * MODULE_LICENSE only if kernel >= 2.4.11
+ *
+ * Revision 1.59  2002/01/30 09:46:33  achim
+ * Small changes
+ *
+ * Revision 1.58  2002/01/29 15:30:02  achim
+ * Set default value of shared_access to Y
+ * New status S_CACHE_RESERV for clustering added
+ *
  * Revision 1.57  2001/08/21 11:16:35  achim
  * Bugfix free_irq()
  *
@@ -232,7 +248,7 @@
  * Initial revision
  *
  ************************************************************************/
-#ident "$Id: gdth.c,v 1.57 2001/08/21 11:16:35 achim Exp $" 
+#ident "$Id: gdth.c,v 1.60 2002/02/05 09:35:22 achim Exp $" 
 
 /* All GDT Disk Array Controllers are fully supported by this driver.
  * This includes the PCI/EISA/ISA SCSI Disk Array Controllers and the
@@ -269,7 +285,7 @@
  *
  * The default values are: "gdth=disable:N,reserve_mode:1,reverse_scan:N,
  *                          max_ids:127,rescan:N,virt_ctr:N,hdr_channel:0,
- *                          shared_access:N".
+ *                          shared_access:Y".
  * Here is another example: "gdth=reserve_list:0,1,2,0,0,1,3,0,rescan:Y".
  * 
  * When loading the gdth driver as a module, the same options are available. 
@@ -669,7 +685,7 @@
 /* map channels to virtual controllers */
 static int virt_ctr = 0;
 /* shared access */
-static int shared_access = 0;
+static int shared_access = 1;
 
 #ifdef MODULE
 #if LINUX_VERSION_CODE >= 0x02011A
@@ -685,6 +701,8 @@
 MODULE_PARM(virt_ctr, "i");
 MODULE_PARM(shared_access, "i");
 MODULE_AUTHOR("Achim Leubner");
+#endif
+#if LINUX_VERSION_CODE >= 0x02040B
 MODULE_LICENSE("GPL");
 #endif
 #endif
@@ -2342,12 +2360,13 @@
     register Scsi_Cmnd *nscp;
     unchar b, t, firsttime;
     unchar this_cmd, next_cmd;
-    ulong flags;
+    ulong flags = 0;
     int cmd_index;
 
     TRACE(("gdth_next() hanum %d\n",hanum));
     ha = HADATA(gdth_ctr_tab[hanum]);
-    GDTH_LOCK_HA(ha, flags);
+    if (!gdth_polling) 
+    	GDTH_LOCK_HA(ha, flags);
 
     ha->cmd_cnt = ha->cmd_offs_dpmem = 0;
     this_cmd = firsttime = TRUE;
@@ -2442,10 +2461,12 @@
                 if (!nscp->SCp.have_data_in)
                     nscp->SCp.have_data_in++;
                 else {
-                    GDTH_UNLOCK_HA(ha,flags);
+                    if (!gdth_polling) 
+                        GDTH_UNLOCK_HA(ha,flags);
                     /* io_request_lock already active ! */
                     nscp->scsi_done(nscp);
-                    GDTH_LOCK_HA(ha,flags);
+                    if (!gdth_polling) 
+                    	GDTH_LOCK_HA(ha,flags);
                 }
             }
         } else
@@ -2470,10 +2491,12 @@
             if (!nscp->SCp.have_data_in)
                 nscp->SCp.have_data_in++;
             else {
-                GDTH_UNLOCK_HA(ha,flags);
+                if (!gdth_polling) 
+                	GDTH_UNLOCK_HA(ha,flags);
                 /* io_request_lock already active ! */      
                 nscp->scsi_done(nscp);
-                GDTH_LOCK_HA(ha,flags);
+                if (!gdth_polling) 
+                	GDTH_LOCK_HA(ha,flags);
             }
         } else {
             switch (nscp->cmnd[0]) {
@@ -2499,16 +2522,20 @@
                     if (!nscp->SCp.have_data_in)
                         nscp->SCp.have_data_in++;
                     else {
-                        GDTH_UNLOCK_HA(ha,flags);
+                	if (!gdth_polling) 
+                        	GDTH_UNLOCK_HA(ha,flags);
                         /* io_request_lock already active ! */      
                         nscp->scsi_done(nscp);
-                        GDTH_LOCK_HA(ha,flags);
+                	if (!gdth_polling) 
+                        	GDTH_LOCK_HA(ha,flags);
                     }
                 } else if (gdth_internal_cache_cmd(hanum,nscp)) {
-                    GDTH_UNLOCK_HA(ha,flags);
+                    if (!gdth_polling) 
+                    	GDTH_UNLOCK_HA(ha,flags);
                     /* io_request_lock already active ! */      
                     nscp->scsi_done(nscp);
-                    GDTH_LOCK_HA(ha,flags);
+                    if (!gdth_polling) 
+                    	GDTH_LOCK_HA(ha,flags);
                 }
                 break;
 
@@ -2523,10 +2550,12 @@
                     if (!nscp->SCp.have_data_in)
                         nscp->SCp.have_data_in++;
                     else {
-                        GDTH_UNLOCK_HA(ha,flags);
+                    	if (!gdth_polling) 
+                        	GDTH_UNLOCK_HA(ha,flags);
                         /* io_request_lock already active ! */      
                         nscp->scsi_done(nscp);
-                        GDTH_LOCK_HA(ha,flags);
+                    	if (!gdth_polling) 
+                        	GDTH_LOCK_HA(ha,flags);
                     }
                 } else {
                     nscp->cmnd[3] = (ha->hdr[t].devtype&1) ? 1:0;
@@ -2561,10 +2590,12 @@
                     if (!nscp->SCp.have_data_in)
                         nscp->SCp.have_data_in++;
                     else {
-                        GDTH_UNLOCK_HA(ha,flags);
+                    	if (!gdth_polling) 
+                        	GDTH_UNLOCK_HA(ha,flags);
                         /* io_request_lock already active ! */      
                         nscp->scsi_done(nscp);
-                        GDTH_LOCK_HA(ha,flags);
+                    	if (!gdth_polling) 
+                        	GDTH_LOCK_HA(ha,flags);
                     }
                 } else if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t)))
                     this_cmd = FALSE;
@@ -2580,10 +2611,12 @@
                 if (!nscp->SCp.have_data_in)
                     nscp->SCp.have_data_in++;
                 else {
-                    GDTH_UNLOCK_HA(ha,flags);
+                    if (!gdth_polling) 
+                    	GDTH_UNLOCK_HA(ha,flags);
                     /* io_request_lock already active ! */  
                     nscp->scsi_done(nscp);
-                    GDTH_LOCK_HA(ha,flags);
+                    if (!gdth_polling) 
+                    	GDTH_LOCK_HA(ha,flags);
                 }
                 break;
             }
@@ -2603,7 +2636,8 @@
         gdth_release_event(hanum);
     }
 
-    GDTH_UNLOCK_HA(ha, flags);
+    if (!gdth_polling) 
+    	GDTH_UNLOCK_HA(ha, flags);
 
     if (gdth_polling && ha->cmd_cnt > 0) {
         if (!gdth_wait(hanum,cmd_index,POLL_TIMEOUT))
@@ -3511,9 +3545,13 @@
                     ha->hdr[scp->target].cluster_type &= ~CLUSTER_RESERVED;
                 }
                 memset((char*)scp->sense_buffer,0,16);
-                scp->sense_buffer[0] = 0x70;
-                scp->sense_buffer[2] = NOT_READY;
-                scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+                if (ha->status == (ushort)S_CACHE_RESERV) {
+                    scp->result = (DID_OK << 16) | (RESERVATION_CONFLICT << 1);
+                } else {
+                    scp->sense_buffer[0] = 0x70;
+                    scp->sense_buffer[2] = NOT_READY;
+                    scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+                }
 #if LINUX_VERSION_CODE >= 0x010300
                 if (scp->done != gdth_scsi_done)
 #endif  
@@ -3980,6 +4018,7 @@
         return 0;
     }
 
+    printk("GDT: Storage RAID Controller Driver. Version: %s \n",GDTH_VERSION_STR);
     /* initializations */
     gdth_polling = TRUE; b = 0;
     gdth_clear_events();
@@ -4104,6 +4143,9 @@
             break;
         if (gdth_search_eisa(eisa_slot)) {      /* controller found */
             shp = scsi_register(shtp,sizeof(gdth_ext_str));
+	    if(shp == NULL)
+		    continue;
+
             ha = HADATA(shp);
             if (!gdth_init_eisa(eisa_slot,ha)) {
                 scsi_unregister(shp);
@@ -4208,19 +4250,23 @@
         gdth_pci_str pcistr[MAXHA];
 
         cnt = gdth_search_pci(pcistr);
+	printk("GDT: Found %d PCI Storage RAID Controllers\n",cnt);
         gdth_sort_pci(pcistr,cnt);
         for (ctr = 0; ctr < cnt; ++ctr) {
             if (gdth_ctr_count >= MAXHA)
                 break;
             shp = scsi_register(shtp,sizeof(gdth_ext_str));
+	    if(shp == NULL)
+		    continue;
+
             ha = HADATA(shp);
             if (!gdth_init_pci(&pcistr[ctr],ha)) {
                 scsi_unregister(shp);
                 continue;
             }
             /* controller found and initialized */
-            printk("Configuring GDT-PCI HA at %d/%d IRQ %u\n",
-                   pcistr[ctr].bus,PCI_SLOT(pcistr[ctr].device_fn),ha->irq);
+            printk("GDT CTR%d: Configuring GDT-PCI HA at %d/%d IRQ %u\n",
+                   ctr,pcistr[ctr].bus,PCI_SLOT(pcistr[ctr].device_fn),ha->irq);
 
 #if LINUX_VERSION_CODE >= 0x010346 
             if (request_irq(ha->irq, gdth_interrupt,
@@ -4696,9 +4742,7 @@
     del_timer(&gdth_timer);
 #endif
 #if LINUX_VERSION_CODE >= 0x020100
-#if LINUX_VERSION_CODE < 0x020322
     unregister_reboot_notifier(&gdth_notifier);
-#endif
     return NOTIFY_OK;
 #endif
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/gdth.h linux-2.4.21-pre6/drivers/scsi/gdth.h
--- linux-2.4.20/drivers/scsi/gdth.h	2001-09-07 16:28:37.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/gdth.h	2003-03-26 23:49:29.000000000 +0000
@@ -2,15 +2,15 @@
 #define _GDTH_H
 
 /*
- * Header file for the GDT ISA/EISA/PCI Disk Array Controller driver for Linux
+ * Header file for the GDT Disk Array/Storage RAID controllers driver for Linux
  * 
- * gdth.h Copyright (C) 1995-01 ICP vortex Computersysteme GmbH, Achim Leubner
+ * gdth.h Copyright (C) 1995-02 ICP vortex, an Intel company, Achim Leubner
  * See gdth.c for further informations and 
  * below for supported controller types
  *
- * <achim@vortex.de>
+ * <achim.leubner@intel.com>
  *
- * $Id: gdth.h,v 1.44 2001/08/21 11:19:05 achim Exp $
+ * $Id: gdth.h,v 1.46 2002/02/05 09:39:53 achim Exp $
  */
 
 #include <linux/version.h>
@@ -29,9 +29,9 @@
 /* defines, macros */
 
 /* driver version */
-#define GDTH_VERSION_STR        "2.03"
+#define GDTH_VERSION_STR        "2.05"
 #define GDTH_VERSION            2
-#define GDTH_SUBVERSION         3
+#define GDTH_SUBVERSION         5
 
 /* protocol version */
 #define PROTOCOL_VERSION        1
@@ -265,6 +265,7 @@
 #define S_CACHE_UNKNOWN 12                      /* cache serv.: drive unknown */
 #define S_RAW_SCSI      12                      /* raw serv.: target error */
 #define S_RAW_ILL       0xff                    /* raw serv.: illegal */
+#define S_CACHE_RESERV	-24			/* cache: reserv. conflict */	
 
 /* timeout values */
 #define INIT_RETRIES    100000                  /* 100000 * 1ms = 100s */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/gdth_proc.c linux-2.4.21-pre6/drivers/scsi/gdth_proc.c
--- linux-2.4.20/drivers/scsi/gdth_proc.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/gdth_proc.c	2003-03-26 23:49:38.000000000 +0000
@@ -1464,7 +1464,7 @@
             timer_table[SCSI_TIMER].expires = jiffies + timeout;
             timer_active |= 1 << SCSI_TIMER;
         } else {
-            if (time_before(jiffies + timeout, timer_table[SCSI_TIMER].expires))
+            if (time_before(jiffies + timeout < timer_table[SCSI_TIMER].expires))
                 timer_table[SCSI_TIMER].expires = jiffies + timeout;
         }
     }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/hosts.c linux-2.4.21-pre6/drivers/scsi/hosts.c
--- linux-2.4.20/drivers/scsi/hosts.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/hosts.c	2003-03-26 23:48:59.000000000 +0000
@@ -81,8 +81,8 @@
 struct Scsi_Host * scsi_hostlist;
 struct Scsi_Device_Template * scsi_devicelist;
 
-int max_scsi_hosts;
-int next_scsi_host;
+int max_scsi_hosts;	/* host_no for next new host */
+int next_scsi_host;	/* count of registered scsi hosts */
 
 void
 scsi_unregister(struct Scsi_Host * sh){
@@ -107,21 +107,8 @@
     if (shn) shn->host_registered = 0;
     /* else {} : This should not happen, we should panic here... */
     
-    /* If we are removing the last host registered, it is safe to reuse
-     * its host number (this avoids "holes" at boot time) (DB) 
-     * It is also safe to reuse those of numbers directly below which have
-     * been released earlier (to avoid some holes in numbering).
-     */
-    if(sh->host_no == max_scsi_hosts - 1) {
-	while(--max_scsi_hosts >= next_scsi_host) {
-	    shpnt = scsi_hostlist;
-	    while(shpnt && shpnt->host_no != max_scsi_hosts - 1)
-		shpnt = shpnt->next;
-	    if(shpnt)
-		break;
-	}
-    }
     next_scsi_host--;
+
     kfree((char *) sh);
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/hosts.h linux-2.4.21-pre6/drivers/scsi/hosts.h
--- linux-2.4.20/drivers/scsi/hosts.h	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/hosts.h	2003-03-26 23:49:25.000000000 +0000
@@ -291,6 +291,9 @@
      */
     unsigned emulated:1;
 
+    /*
+     * True for drivers that can do I/O from highmem
+     */
     unsigned highmem_io:1;
 
     /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/ide-scsi.c linux-2.4.21-pre6/drivers/scsi/ide-scsi.c
--- linux-2.4.20/drivers/scsi/ide-scsi.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/ide-scsi.c	2003-03-26 23:48:58.000000000 +0000
@@ -1,7 +1,8 @@
 /*
- * linux/drivers/scsi/ide-scsi.c	Version 0.9		Jul   4, 1999
+ * linux/drivers/scsi/ide-scsi.c	Version 0.93    June 10, 2002
  *
  * Copyright (C) 1996 - 1999 Gadi Oxman <gadio@netvision.net.il>
+ * Copyright (C) 2001 - 2002 Andre Hedrick <andre@linux-ide.org>
  */
 
 /*
@@ -27,11 +28,19 @@
  *                        detection of devices with CONFIG_SCSI_MULTI_LUN
  * Ver 0.8   Feb 05 99   Optical media need translation too. Reverse 0.7.
  * Ver 0.9   Jul 04 99   Fix a bug in SG_SET_TRANSFORM.
+ * Ver 0.91  Jan 06 02   Added 'ignore' parameter when ide-scsi is a module
+ *                        so that use of scsi emulation can be made independent
+ *                        of load order when other IDE drivers are modules.
+ *                        Chris Ebenezer <chriseb@pobox.com>
+ * Ver 0.92  Mar 21 02   Include DevFs support
+ *                        Borsenkow Andrej <Andrej.Borsenkow@mow.siemens.ru>
+ * Ver 0.93  Jun 10 02   Fix "off by one" error in transforms
  */
 
-#define IDESCSI_VERSION "0.9"
+#define IDESCSI_VERSION "0.93"
 
 #include <linux/module.h>
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
@@ -53,76 +62,77 @@
 #include "ide-scsi.h"
 #include <scsi/sg.h>
 
-#define IDESCSI_DEBUG_LOG		0
+#define IDESCSI_DEBUG_LOG	0
 
 typedef struct idescsi_pc_s {
-	u8 c[12];				/* Actual packet bytes */
-	int request_transfer;			/* Bytes to transfer */
-	int actually_transferred;		/* Bytes actually transferred */
-	int buffer_size;			/* Size of our data buffer */
-	struct request *rq;			/* The corresponding request */
-	byte *buffer;				/* Data buffer */
-	byte *current_position;			/* Pointer into the above buffer */
-	struct scatterlist *sg;			/* Scatter gather table */
-	int b_count;				/* Bytes transferred from current entry */
-	Scsi_Cmnd *scsi_cmd;			/* SCSI command */
-	void (*done)(Scsi_Cmnd *);		/* Scsi completion routine */
-	unsigned long flags;			/* Status/Action flags */
-	unsigned long timeout;			/* Command timeout */
+	u8 c[12];			/* Actual packet bytes */
+	int request_transfer;		/* Bytes to transfer */
+	int actually_transferred;	/* Bytes actually transferred */
+	int buffer_size;		/* Size of our data buffer */
+	struct request *rq;		/* The corresponding request */
+	u8 *buffer;			/* Data buffer */
+	u8 *current_position;		/* Pointer into the above buffer */
+	struct scatterlist *sg;		/* Scatter gather table */
+	int b_count;			/* Bytes transferred from current entry */
+	Scsi_Cmnd *scsi_cmd;		/* SCSI command */
+	void (*done)(Scsi_Cmnd *);	/* Scsi completion routine */
+	unsigned long flags;		/* Status/Action flags */
+	unsigned long timeout;		/* Command timeout */
 } idescsi_pc_t;
 
 /*
  *	Packet command status bits.
  */
-#define PC_DMA_IN_PROGRESS		0	/* 1 while DMA in progress */
-#define PC_WRITING			1	/* Data direction */
-#define PC_TRANSFORM			2	/* transform SCSI commands */
+#define PC_DMA_IN_PROGRESS	0	/* 1 while DMA in progress */
+#define PC_WRITING		1	/* Data direction */
+#define PC_TRANSFORM		2	/* transform SCSI commands */
+#define PC_DMA_OK		4	/* Use DMA */
 
 /*
  *	SCSI command transformation layer
  */
-#define IDESCSI_TRANSFORM		0	/* Enable/Disable transformation */
-#define IDESCSI_SG_TRANSFORM		1	/* /dev/sg transformation */
+#define IDESCSI_TRANSFORM	0	/* Enable/Disable transformation */
+#define IDESCSI_SG_TRANSFORM	1	/* /dev/sg transformation */
 
 /*
  *	Log flags
  */
-#define IDESCSI_LOG_CMD			0	/* Log SCSI commands */
+#define IDESCSI_LOG_CMD		0	/* Log SCSI commands */
+
+#define IDESCSI_DEVFS
 
 typedef struct {
 	ide_drive_t *drive;
-	idescsi_pc_t *pc;			/* Current packet command */
-	unsigned long flags;			/* Status/Action flags */
-	unsigned long transform;		/* SCSI cmd translation layer */
-	unsigned long log;			/* log flags */
+	idescsi_pc_t *pc;		/* Current packet command */
+	unsigned long flags;		/* Status/Action flags */
+	unsigned long transform;	/* SCSI cmd translation layer */
+	unsigned long log;		/* log flags */
+	int id;				/* id */
+#ifdef IDESCSI_DEVFS
+	devfs_handle_t de;		/* pointer to IDE device */
+#endif /* IDESCSI_DEVFS */
 } idescsi_scsi_t;
 
 /*
  *	Per ATAPI device status bits.
  */
-#define IDESCSI_DRQ_INTERRUPT		0	/* DRQ interrupt device */
+#define IDESCSI_DRQ_INTERRUPT	0	/* DRQ interrupt device */
 
 /*
  *	ide-scsi requests.
  */
-#define IDESCSI_PC_RQ			90
-
-/*
- *	Bits of the interrupt reason register.
- */
-#define IDESCSI_IREASON_COD	0x1		/* Information transferred is command */
-#define IDESCSI_IREASON_IO	0x2		/* The device requests us to read */
+#define IDESCSI_PC_RQ		90
 
 static void idescsi_discard_data (ide_drive_t *drive, unsigned int bcount)
 {
 	while (bcount--)
-		IN_BYTE (IDE_DATA_REG);
+		(void) HWIF(drive)->INB(IDE_DATA_REG);
 }
 
 static void idescsi_output_zeros (ide_drive_t *drive, unsigned int bcount)
 {
 	while (bcount--)
-		OUT_BYTE (0, IDE_DATA_REG);
+		HWIF(drive)->OUTB(0, IDE_DATA_REG);
 }
 
 /*
@@ -134,13 +144,15 @@
 
 	while (bcount) {
 		if (pc->sg - (struct scatterlist *) pc->scsi_cmd->request_buffer > pc->scsi_cmd->use_sg) {
-			printk (KERN_ERR "ide-scsi: scatter gather table too small, discarding data\n");
-			idescsi_discard_data (drive, bcount);
+			printk(KERN_ERR "ide-scsi: scatter gather "
+				"table too small, discarding data\n");
+			idescsi_discard_data(drive, bcount);
 			return;
 		}
-		count = IDE_MIN (pc->sg->length - pc->b_count, bcount);
-		atapi_input_bytes (drive, pc->sg->address + pc->b_count, count);
-		bcount -= count; pc->b_count += count;
+		count = IDE_MIN(pc->sg->length - pc->b_count, bcount);
+		HWIF(drive)->atapi_input_bytes(drive, pc->sg->address + pc->b_count, count);
+		bcount -= count;
+		pc->b_count += count;
 		if (pc->b_count == pc->sg->length) {
 			pc->sg++;
 			pc->b_count = 0;
@@ -154,13 +166,15 @@
 
 	while (bcount) {
 		if (pc->sg - (struct scatterlist *) pc->scsi_cmd->request_buffer > pc->scsi_cmd->use_sg) {
-			printk (KERN_ERR "ide-scsi: scatter gather table too small, padding with zeros\n");
-			idescsi_output_zeros (drive, bcount);
+			printk(KERN_ERR "ide-scsi: scatter gather table "
+				"too small, padding with zeros\n");
+			idescsi_output_zeros(drive, bcount);
 			return;
 		}
-		count = IDE_MIN (pc->sg->length - pc->b_count, bcount);
-		atapi_output_bytes (drive, pc->sg->address + pc->b_count, count);
-		bcount -= count; pc->b_count += count;
+		count = IDE_MIN(pc->sg->length - pc->b_count, bcount);
+		HWIF(drive)->atapi_output_bytes(drive, pc->sg->address + pc->b_count, count);
+		bcount -= count;
+		pc->b_count += count;
 		if (pc->b_count == pc->sg->length) {
 			pc->sg++;
 			pc->b_count = 0;
@@ -181,26 +195,38 @@
 		return;
 	if (drive->media == ide_cdrom || drive->media == ide_optical) {
 		if (c[0] == READ_6 || c[0] == WRITE_6) {
-			c[8] = c[4];		c[5] = c[3];		c[4] = c[2];
-			c[3] = c[1] & 0x1f;	c[2] = 0;		c[1] &= 0xe0;
+			c[8] = c[4];
+			c[5] = c[3];
+			c[4] = c[2];
+			c[3] = c[1] & 0x1f;
+			c[2] = 0;
+			c[1] &= 0xe0;
 			c[0] += (READ_10 - READ_6);
 		}
 		if (c[0] == MODE_SENSE || c[0] == MODE_SELECT) {
+			unsigned short new_len;
 			if (!scsi_buf)
 				return;
 			if ((atapi_buf = kmalloc(pc->buffer_size + 4, GFP_ATOMIC)) == NULL)
 				return;
 			memset(atapi_buf, 0, pc->buffer_size + 4);
 			memset (c, 0, 12);
-			c[0] = sc[0] | 0x40;	c[1] = sc[1];		c[2] = sc[2];
-			c[8] = sc[4] + 4;	c[9] = sc[5];
-			if (sc[4] + 4 > 255)
-				c[7] = sc[4] + 4 - 255;
+			c[0] = sc[0] | 0x40;
+			c[1] = sc[1];
+			c[2] = sc[2];
+ 			new_len = sc[4] + 4;
+			c[8] = new_len;
+			c[7] = new_len >> 8;
+			c[9] = sc[5];
 			if (c[0] == MODE_SELECT_10) {
-				atapi_buf[1] = scsi_buf[0];	/* Mode data length */
-				atapi_buf[2] = scsi_buf[1];	/* Medium type */
-				atapi_buf[3] = scsi_buf[2];	/* Device specific parameter */
-				atapi_buf[7] = scsi_buf[3];	/* Block descriptor length */
+				/* Mode data length */
+				atapi_buf[1] = scsi_buf[0];
+				/* Medium type */
+				atapi_buf[2] = scsi_buf[1];
+				/* Device specific parameter */
+				atapi_buf[3] = scsi_buf[2];
+				/* Block descriptor length */
+				atapi_buf[7] = scsi_buf[3];
 				memcpy(atapi_buf + 8, scsi_buf + 4, pc->buffer_size - 4);
 			}
 			pc->buffer = atapi_buf;
@@ -220,15 +246,21 @@
 		return;
 	if (drive->media == ide_cdrom || drive->media == ide_optical) {
 		if (pc->c[0] == MODE_SENSE_10 && sc[0] == MODE_SENSE) {
-			scsi_buf[0] = atapi_buf[1];		/* Mode data length */
-			scsi_buf[1] = atapi_buf[2];		/* Medium type */
-			scsi_buf[2] = atapi_buf[3];		/* Device specific parameter */
-			scsi_buf[3] = atapi_buf[7];		/* Block descriptor length */
+			/* Mode data length */
+			scsi_buf[0] = atapi_buf[1];
+			/* Medium type */
+			scsi_buf[1] = atapi_buf[2];
+			/* Device specific parameter */
+			scsi_buf[2] = atapi_buf[3];
+			/* Block descriptor length */
+			scsi_buf[3] = atapi_buf[7];
 			memcpy(scsi_buf + 4, atapi_buf + 8, pc->request_transfer - 8);
 		}
 		if (pc->c[0] == INQUIRY) {
-			scsi_buf[2] |= 2;			/* ansi_revision */
-			scsi_buf[3] = (scsi_buf[3] & 0xf0) | 2;	/* response data format */
+			/* ansi_revision */
+			scsi_buf[2] |= 2;
+			/* response data format */
+			scsi_buf[3] = (scsi_buf[3] & 0xf0) | 2;
 		}
 	}
 	if (atapi_buf && atapi_buf != scsi_buf)
@@ -256,47 +288,83 @@
 	printk("]\n");
 }
 
-static void idescsi_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
+static int idescsi_do_end_request (ide_drive_t *drive, int uptodate)
+{
+	struct request *rq;
+	unsigned long flags;
+	int ret = 1;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	rq = HWGROUP(drive)->rq;
+
+	/*
+	 * decide whether to reenable DMA -- 3 is a random magic for now,
+	 * if we DMA timeout more than 3 times, just stay in PIO
+	 */
+	if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
+		drive->state = 0;
+		HWGROUP(drive)->hwif->ide_dma_on(drive);
+	}
+
+	if (!end_that_request_first(rq, uptodate, drive->name)) {
+		add_blkdev_randomness(MAJOR(rq->rq_dev));
+		blkdev_dequeue_request(rq);
+		HWGROUP(drive)->rq = NULL;
+		end_that_request_last(rq);
+		ret = 0;
+	}
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	return ret;
+}
+
+static int idescsi_end_request (ide_drive_t *drive, int uptodate)
 {
-	ide_drive_t *drive = hwgroup->drive;
 	idescsi_scsi_t *scsi = drive->driver_data;
-	struct request *rq = hwgroup->rq;
+	struct request *rq = HWGROUP(drive)->rq;
 	idescsi_pc_t *pc = (idescsi_pc_t *) rq->buffer;
 	int log = test_bit(IDESCSI_LOG_CMD, &scsi->log);
 	u8 *scsi_buf;
 	unsigned long flags;
 
 	if (rq->cmd != IDESCSI_PC_RQ) {
-		ide_end_request (uptodate, hwgroup);
-		return;
+		idescsi_do_end_request(drive, uptodate);
+		return 0;
 	}
-	ide_end_drive_cmd (drive, 0, 0);
+	ide_end_drive_cmd(drive, 0, 0);
 	if (rq->errors >= ERROR_MAX) {
 		pc->scsi_cmd->result = DID_ERROR << 16;
 		if (log)
-			printk ("ide-scsi: %s: I/O error for %lu\n", drive->name, pc->scsi_cmd->serial_number);
+			printk("ide-scsi: %s: I/O error for %lu\n",
+				drive->name, pc->scsi_cmd->serial_number);
 	} else if (rq->errors) {
 		pc->scsi_cmd->result = (CHECK_CONDITION << 1) | (DID_OK << 16);
 		if (log)
-			printk ("ide-scsi: %s: check condition for %lu\n", drive->name, pc->scsi_cmd->serial_number);
+			printk("ide-scsi: %s: check condition for %lu\n",
+				drive->name, pc->scsi_cmd->serial_number);
 	} else {
 		pc->scsi_cmd->result = DID_OK << 16;
-		idescsi_transform_pc2 (drive, pc);
+		idescsi_transform_pc2(drive, pc);
 		if (log) {
-			printk ("ide-scsi: %s: suc %lu", drive->name, pc->scsi_cmd->serial_number);
-			if (!test_bit(PC_WRITING, &pc->flags) && pc->actually_transferred && pc->actually_transferred <= 1024 && pc->buffer) {
+			printk("ide-scsi: %s: suc %lu", drive->name,
+				pc->scsi_cmd->serial_number);
+			if (!test_bit(PC_WRITING, &pc->flags) &&
+			    pc->actually_transferred &&
+			    pc->actually_transferred <= 1024 &&
+			    pc->buffer) {
 				printk(", rst = ");
 				scsi_buf = pc->scsi_cmd->request_buffer;
 				hexdump(scsi_buf, IDE_MIN(16, pc->scsi_cmd->request_bufflen));
 			} else printk("\n");
 		}
 	}
-	spin_lock_irqsave(&io_request_lock,flags);	
+	spin_lock_irqsave(&io_request_lock, flags);	
 	pc->done(pc->scsi_cmd);
-	spin_unlock_irqrestore(&io_request_lock,flags);
-	idescsi_free_bh (rq->bh);
-	kfree(pc); kfree(rq);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	idescsi_free_bh(rq->bh);
+	kfree(pc);
+	kfree(rq);
 	scsi->pc = NULL;
+	return 0;
 }
 
 static inline unsigned long get_timeout(idescsi_pc_t *pc)
@@ -310,84 +378,112 @@
 static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
 {
 	idescsi_scsi_t *scsi = drive->driver_data;
-	byte status, ireason;
-	int bcount;
-	idescsi_pc_t *pc=scsi->pc;
+	idescsi_pc_t *pc = scsi->pc;
 	struct request *rq = pc->rq;
+	atapi_bcount_t bcount;
+	atapi_status_t status;
+	atapi_ireason_t ireason;
+	atapi_feature_t feature;
 	unsigned int temp;
 
 #if IDESCSI_DEBUG_LOG
-	printk (KERN_INFO "ide-scsi: Reached idescsi_pc_intr interrupt handler\n");
+	printk(KERN_INFO "ide-scsi: Reached idescsi_pc_intr "
+		"interrupt handler\n");
 #endif /* IDESCSI_DEBUG_LOG */
 
-	if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
+	if (test_and_clear_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
 #if IDESCSI_DEBUG_LOG
-		printk ("ide-scsi: %s: DMA complete\n", drive->name);
+		printk("ide-scsi: %s: DMA complete\n", drive->name);
 #endif /* IDESCSI_DEBUG_LOG */
-		pc->actually_transferred=pc->request_transfer;
-		(void) (HWIF(drive)->dmaproc(ide_dma_end, drive));
+		pc->actually_transferred = pc->request_transfer;
+		(void) (HWIF(drive)->ide_dma_end(drive));
 	}
 
-	status = GET_STAT();						/* Clear the interrupt */
+	feature.all = 0;
+	/* Clear the interrupt */
+	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
 
-	if ((status & DRQ_STAT) == 0) {					/* No more interrupts */
+	if (!status.b.drq) {
+		/* No more interrupts */
 		if (test_bit(IDESCSI_LOG_CMD, &scsi->log))
-			printk (KERN_INFO "Packet command completed, %d bytes transferred\n", pc->actually_transferred);
-		ide__sti();
-		if (status & ERR_STAT)
+			printk(KERN_INFO "Packet command completed, %d "
+				"bytes transferred\n",
+				pc->actually_transferred);
+		local_irq_enable();
+		if (status.b.check)
 			rq->errors++;
-		idescsi_end_request (1, HWGROUP(drive));
+		idescsi_end_request(drive, 1);
 		return ide_stopped;
 	}
-	bcount = IN_BYTE (IDE_BCOUNTH_REG) << 8 | IN_BYTE (IDE_BCOUNTL_REG);
-	ireason = IN_BYTE (IDE_IREASON_REG);
 
-	if (ireason & IDESCSI_IREASON_COD) {
-		printk (KERN_ERR "ide-scsi: CoD != 0 in idescsi_pc_intr\n");
-		return ide_do_reset (drive);
-	}
-	if (ireason & IDESCSI_IREASON_IO) {
-		temp = pc->actually_transferred + bcount;
-		if ( temp > pc->request_transfer) {
+	bcount.b.low	= HWIF(drive)->INB(IDE_BCOUNTL_REG);
+	bcount.b.high	= HWIF(drive)->INB(IDE_BCOUNTH_REG);
+	ireason.all	= HWIF(drive)->INB(IDE_IREASON_REG);
+
+	if (ireason.b.cod) {
+		printk(KERN_ERR "ide-scsi: CoD != 0 in idescsi_pc_intr\n");
+		return ide_do_reset(drive);
+	}
+	if (ireason.b.io) {
+		temp = pc->actually_transferred + bcount.all;
+		if (temp > pc->request_transfer) {
 			if (temp > pc->buffer_size) {
-				printk (KERN_ERR "ide-scsi: The scsi wants to send us more data than expected - discarding data\n");
+				printk(KERN_ERR "ide-scsi: The scsi wants to "
+					"send us more data than expected "
+					"- discarding data\n");
+				printk(KERN_ERR "ide-scsi: [");
+				hexdump(pc->c, 12);
+				printk("]\n");
+				printk(KERN_ERR "ide-scsi: expected %d got %d limit %d\n",
+					pc->request_transfer, temp, pc->buffer_size);
 				temp = pc->buffer_size - pc->actually_transferred;
 				if (temp) {
 					clear_bit(PC_WRITING, &pc->flags);
 					if (pc->sg)
 						idescsi_input_buffers(drive, pc, temp);
 					else
-						atapi_input_bytes(drive, pc->current_position, temp);
-					printk(KERN_ERR "ide-scsi: transferred %d of %d bytes\n", temp, bcount);
+						HWIF(drive)->atapi_input_bytes(drive, pc->current_position, temp);
+					printk(KERN_ERR "ide-scsi: transferred %d of %d bytes\n", temp, bcount.all);
 				}
 				pc->actually_transferred += temp;
 				pc->current_position += temp;
-				idescsi_discard_data (drive,bcount - temp);
-				ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL);
+				idescsi_discard_data(drive, bcount.all - temp);
+				if (HWGROUP(drive)->handler != NULL)
+					BUG();
+				ide_set_handler(drive,
+						&idescsi_pc_intr,
+						get_timeout(pc),
+						NULL);
 				return ide_started;
 			}
 #if IDESCSI_DEBUG_LOG
-			printk (KERN_NOTICE "ide-scsi: The scsi wants to send us more data than expected - allowing transfer\n");
+			printk(KERN_NOTICE "ide-scsi: The scsi wants to send "
+				"us more data than expected - "
+				"allowing transfer\n");
 #endif /* IDESCSI_DEBUG_LOG */
 		}
 	}
-	if (ireason & IDESCSI_IREASON_IO) {
+	if (ireason.b.io) {
 		clear_bit(PC_WRITING, &pc->flags);
 		if (pc->sg)
-			idescsi_input_buffers (drive, pc, bcount);
+			idescsi_input_buffers(drive, pc, bcount.all);
 		else
-			atapi_input_bytes (drive,pc->current_position,bcount);
+			HWIF(drive)->atapi_input_bytes(drive, pc->current_position, bcount.all);
 	} else {
 		set_bit(PC_WRITING, &pc->flags);
 		if (pc->sg)
-			idescsi_output_buffers (drive, pc, bcount);
+			idescsi_output_buffers(drive, pc, bcount.all);
 		else
-			atapi_output_bytes (drive,pc->current_position,bcount);
+			HWIF(drive)->atapi_output_bytes(drive, pc->current_position, bcount.all);
 	}
-	pc->actually_transferred+=bcount;				/* Update the current position */
-	pc->current_position+=bcount;
-
-	ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL);	/* And set the interrupt handler again */
+	/* Update the current position */
+	pc->actually_transferred += bcount.all;
+	pc->current_position += bcount.all;
+
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	/* And set the interrupt handler again */
+	ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL);
 	return ide_started;
 }
 
@@ -395,20 +491,33 @@
 {
 	idescsi_scsi_t *scsi = drive->driver_data;
 	idescsi_pc_t *pc = scsi->pc;
-	byte ireason;
+	atapi_ireason_t ireason;
 	ide_startstop_t startstop;
 
-	if (ide_wait_stat (&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
-		printk (KERN_ERR "ide-scsi: Strange, packet command initiated yet DRQ isn't asserted\n");
+	if (ide_wait_stat(&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
+		printk(KERN_ERR "ide-scsi: Strange, packet command "
+			"initiated yet DRQ isn't asserted\n");
 		return startstop;
 	}
-	ireason = IN_BYTE (IDE_IREASON_REG);
-	if ((ireason & (IDESCSI_IREASON_IO | IDESCSI_IREASON_COD)) != IDESCSI_IREASON_COD) {
-		printk (KERN_ERR "ide-scsi: (IO,CoD) != (0,1) while issuing a packet command\n");
-		return ide_do_reset (drive);
+
+	ireason.all	= HWIF(drive)->INB(IDE_IREASON_REG);
+
+	if (!ireason.b.cod || ireason.b.io) {
+		printk(KERN_ERR "ide-scsi: (IO,CoD) != (0,1) while "
+				"issuing a packet command\n");
+		return ide_do_reset(drive);
+	}
+
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	/* Set the interrupt routine */
+	ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL);
+	/* Send the actual packet */
+	HWIF(drive)->atapi_output_bytes(drive, scsi->pc->c, 12);
+	if (test_bit (PC_DMA_OK, &pc->flags)) {
+		set_bit(PC_DMA_IN_PROGRESS, &pc->flags);
+		(void) (HWIF(drive)->ide_dma_begin(drive));
 	}
-	ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL);	/* Set the interrupt routine */
-	atapi_output_bytes (drive, scsi->pc->c, 12);			/* Send the actual packet */
 	return ide_started;
 }
 
@@ -418,36 +527,49 @@
 static ide_startstop_t idescsi_issue_pc (ide_drive_t *drive, idescsi_pc_t *pc)
 {
 	idescsi_scsi_t *scsi = drive->driver_data;
-	int bcount;
+	atapi_feature_t feature;
+	atapi_bcount_t bcount;
 	struct request *rq = pc->rq;
-	int dma_ok = 0;
-
-	scsi->pc=pc;							/* Set the current packet command */
-	pc->actually_transferred=0;					/* We haven't transferred any data yet */
-	pc->current_position=pc->buffer;
-	bcount = IDE_MIN (pc->request_transfer, 63 * 1024);		/* Request to transfer the entire buffer at once */
 
-	if (drive->using_dma && rq->bh)
-		dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
+	/* Set the current packet command */
+	scsi->pc = pc;
+	/* We haven't transferred any data yet */
+	pc->actually_transferred = 0;
+	pc->current_position = pc->buffer;
+	/* Request to transfer the entire buffer at once */
+	bcount.all = IDE_MIN(pc->request_transfer, 63 * 1024);
+
+	if (drive->using_dma && rq->bh) {
+		if (test_bit(PC_WRITING, &pc->flags))
+			feature.b.dma = !HWIF(drive)->ide_dma_write(drive);
+		else
+			feature.b.dma = !HWIF(drive)->ide_dma_read(drive);
+	}
 
-	SELECT_DRIVE(HWIF(drive), drive);
+	SELECT_DRIVE(drive);
 	if (IDE_CONTROL_REG)
-		OUT_BYTE (drive->ctl,IDE_CONTROL_REG);
-	OUT_BYTE (dma_ok,IDE_FEATURE_REG);
-	OUT_BYTE (bcount >> 8,IDE_BCOUNTH_REG);
-	OUT_BYTE (bcount & 0xff,IDE_BCOUNTL_REG);
-
-	if (dma_ok) {
-		set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
-		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
-	}
-	if (test_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags)) {
-		ide_set_handler (drive, &idescsi_transfer_pc, get_timeout(pc), NULL);
-		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);		/* Issue the packet command */
+		HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);
+	HWIF(drive)->OUTB(feature.all, IDE_FEATURE_REG);
+	HWIF(drive)->OUTB(bcount.b.high, IDE_BCOUNTH_REG);
+	HWIF(drive)->OUTB(bcount.b.low, IDE_BCOUNTL_REG);
+
+	if (feature.b.dma) {
+		set_bit(PC_DMA_OK, &pc->flags);
+	}
+	if (test_bit(IDESCSI_DRQ_INTERRUPT, &scsi->flags)) {
+		if (HWGROUP(drive)->handler != NULL)
+			BUG();
+		ide_set_handler(drive,
+				&idescsi_transfer_pc,
+				get_timeout(pc),
+				NULL);
+		/* Issue the packet command */
+		HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG);
 		return ide_started;
 	} else {
-		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);
-		return idescsi_transfer_pc (drive);
+		/* Issue the packet command */
+		HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG);
+		return idescsi_transfer_pc(drive);
 	}
 }
 
@@ -457,19 +579,30 @@
 static ide_startstop_t idescsi_do_request (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
 #if IDESCSI_DEBUG_LOG
-	printk (KERN_INFO "rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->cmd,rq->errors);
-	printk (KERN_INFO "sector: %ld, nr_sectors: %ld, current_nr_sectors: %ld\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors);
+	printk(KERN_INFO "rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",
+		rq->rq_status, (unsigned int) rq->rq_dev, rq->cmd, rq->errors);
+	printk(KERN_INFO "sector: %ld, nr_sectors: %ld, "
+		"current_nr_sectors: %ld\n", rq->sector,
+		rq->nr_sectors, rq->current_nr_sectors);
 #endif /* IDESCSI_DEBUG_LOG */
 
 	if (rq->cmd == IDESCSI_PC_RQ) {
-		return idescsi_issue_pc (drive, (idescsi_pc_t *) rq->buffer);
+		return idescsi_issue_pc(drive, (idescsi_pc_t *) rq->buffer);
 	}
-	printk (KERN_ERR "ide-scsi: %s: unsupported command in request queue (%x)\n", drive->name, rq->cmd);
-	idescsi_end_request (0,HWGROUP (drive));
+	printk(KERN_ERR "ide-scsi: %s: unsupported command in request "
+		"queue (%x)\n", drive->name, rq->cmd);
+	idescsi_end_request(drive, 0);
 	return ide_stopped;
 }
 
-static int idescsi_open (struct inode *inode, struct file *filp, ide_drive_t *drive)
+static int idescsi_do_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	/* need to figure out how to parse scsi-atapi media type */
+
+	return -EINVAL;
+}
+
+static int idescsi_ide_open (struct inode *inode, struct file *filp, ide_drive_t *drive)
 {
 	MOD_INC_USE_COUNT;
 	return 0;
@@ -482,6 +615,7 @@
 
 static ide_drive_t *idescsi_drives[MAX_HWIFS * MAX_DRIVES];
 static int idescsi_initialized = 0;
+static int drive_count = 0;
 
 static void idescsi_add_settings(ide_drive_t *drive)
 {
@@ -502,34 +636,58 @@
  */
 static void idescsi_setup (ide_drive_t *drive, idescsi_scsi_t *scsi, int id)
 {
+	int minor = (drive->select.b.unit) << PARTN_BITS;
+
 	DRIVER(drive)->busy++;
 	idescsi_drives[id] = drive;
 	drive->driver_data = scsi;
 	drive->ready_stat = 0;
-	memset (scsi, 0, sizeof (idescsi_scsi_t));
+	memset(scsi, 0, sizeof(idescsi_scsi_t));
 	scsi->drive = drive;
+	scsi->id = id;
 	if (drive->id && (drive->id->config & 0x0060) == 0x20)
-		set_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags);
+		set_bit(IDESCSI_DRQ_INTERRUPT, &scsi->flags);
 	set_bit(IDESCSI_TRANSFORM, &scsi->transform);
 	clear_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
 #if IDESCSI_DEBUG_LOG
 	set_bit(IDESCSI_LOG_CMD, &scsi->log);
 #endif /* IDESCSI_DEBUG_LOG */
 	idescsi_add_settings(drive);
+#ifdef IDESCSI_DEVFS
+	scsi->de = devfs_register(drive->de, "generic", DEVFS_FL_DEFAULT,
+					HWIF(drive)->major, minor,
+					S_IFBLK | S_IRUSR | S_IWUSR,
+					ide_fops, NULL);
+#endif /* IDESCSI_DEVFS */
+	drive_count++;
+	DRIVER(drive)->busy--;
 }
 
 static int idescsi_cleanup (ide_drive_t *drive)
 {
 	idescsi_scsi_t *scsi = drive->driver_data;
 
-	if (ide_unregister_subdriver (drive))
+	if (ide_unregister_subdriver(drive)) {
+		printk("%s: %s: failed to unregister! \n",
+			__FUNCTION__, drive->name);
+		printk("%s: usage %d, busy %d, driver %p, Dbusy %d\n",
+			drive->name, drive->usage, drive->busy,
+			drive->driver, DRIVER(drive)->busy);
 		return 1;
+	}
+	idescsi_drives[scsi->id] = NULL;
+#ifdef IDESCSI_DEVFS
+	if (scsi->de)
+		devfs_unregister(scsi->de);
+#endif /* IDESCSI_DEVFS */
 	drive->driver_data = NULL;
-	kfree (scsi);
+	kfree(scsi);
+	drive_count--;
 	return 0;
 }
 
-int idescsi_reinit(ide_drive_t *drive);
+int idescsi_init(void);
+int idescsi_attach(ide_drive_t *drive);
 
 /*
  *	IDE subdriver functions, registered with ide.c
@@ -539,15 +697,23 @@
 	version:		IDESCSI_VERSION,
 	media:			ide_scsi,
 	busy:			0,
+#ifdef CONFIG_IDEDMA_ONLYDISK
+	supports_dma:		0,
+#else
 	supports_dma:		1,
+#endif
 	supports_dsc_overlap:	0,
 	cleanup:		idescsi_cleanup,
 	standby:		NULL,
+	suspend:		NULL,
+	resume:			NULL,
 	flushcache:		NULL,
 	do_request:		idescsi_do_request,
 	end_request:		idescsi_end_request,
-	ioctl:			NULL,
-	open:			idescsi_open,
+	sense:			NULL,
+	error:			NULL,
+	ioctl:			idescsi_do_ioctl,
+	open:			idescsi_ide_open,
 	release:		idescsi_ide_release,
 	media_change:		NULL,
 	revalidate:		NULL,
@@ -555,12 +721,12 @@
 	capacity:		NULL,
 	special:		NULL,
 	proc:			NULL,
-	reinit:			idescsi_reinit,
+	init:			idescsi_init,
+	attach:			idescsi_attach,
 	ata_prebuilder:		NULL,
 	atapi_prebuilder:	NULL,
 };
 
-int idescsi_init (void);
 static ide_module_t idescsi_module = {
 	IDE_DRIVER_MODULE,
 	idescsi_init,
@@ -568,51 +734,91 @@
 	NULL
 };
 
-int idescsi_reinit (ide_drive_t *drive)
+int idescsi_attach (ide_drive_t *drive)
 {
-#if 0
 	idescsi_scsi_t *scsi;
-	byte media[] = {TYPE_DISK, TYPE_TAPE, TYPE_PROCESSOR, TYPE_WORM, TYPE_ROM, TYPE_SCANNER, TYPE_MOD, 255};
-	int i, failed, id;
-
-	if (!idescsi_initialized)
-		return 0;
-	for (i = 0; i < MAX_HWIFS * MAX_DRIVES; i++)
-		idescsi_drives[i] = NULL;
+	u8 media[] = {	TYPE_DISK,		/* 0x00 */
+			TYPE_TAPE,		/* 0x01 */
+			TYPE_PRINTER,		/* 0x02 */
+			TYPE_PROCESSOR,		/* 0x03 */
+			TYPE_WORM,		/* 0x04 */
+			TYPE_ROM,		/* 0x05 */
+			TYPE_SCANNER,		/* 0x06 */
+			TYPE_MOD,		/* 0x07 */
+			255};
+	int i = 0, ret = 0, id = 0;
+//	int id = 2 * HWIF(drive)->index + drive->select.b.unit;
+//	int id = drive_count + 1;
+
+	for (id = 0; id < MAX_HWIFS*MAX_DRIVES; id++)
+		if (idescsi_drives[id] == NULL)
+			break;
+
+	printk("%s: id = %d\n", drive->name, id);
+
+	if ((!idescsi_initialized) || (drive->media == ide_disk)) {
+		printk(KERN_ERR "ide-scsi: (%sinitialized) %s: "
+				"media-type (%ssupported)\n",
+			(idescsi_initialized) ? "" : "! ",
+			drive->name,
+			(drive->media == ide_disk) ? "! " : "");
+		return (drive->media == ide_disk) ? 2 : 0;
+	}
 
 	MOD_INC_USE_COUNT;
+
 	for (i = 0; media[i] != 255; i++) {
-		failed = 0;
-		while ((drive = ide_scan_devices (media[i], idescsi_driver.name, NULL, failed++)) != NULL) {
+		if (drive->media != media[i])
+			continue;
+		else
+			break;
+	}
 
-			if ((scsi = (idescsi_scsi_t *) kmalloc (sizeof (idescsi_scsi_t), GFP_KERNEL)) == NULL) {
-				printk (KERN_ERR "ide-scsi: %s: Can't allocate a scsi structure\n", drive->name);
-				continue;
-			}
-			if (ide_register_subdriver (drive, &idescsi_driver, IDE_SUBDRIVER_VERSION)) {
-				printk (KERN_ERR "ide-scsi: %s: Failed to register the driver with ide.c\n", drive->name);
-				kfree (scsi);
-				continue;
-			}
-			for (id = 0; id < MAX_HWIFS * MAX_DRIVES && idescsi_drives[id]; id++);
-				idescsi_setup (drive, scsi, id);
-			failed--;
-		}
+	if ((scsi = (idescsi_scsi_t *) kmalloc(sizeof(idescsi_scsi_t), GFP_KERNEL)) == NULL) {
+		printk(KERN_ERR "ide-scsi: %s: Can't allocate a scsi "
+			"structure\n", drive->name);
+		ret = 1;
+		goto bye_game_over;
 	}
-	ide_register_module(&idescsi_module);
+	if (ide_register_subdriver(drive, &idescsi_driver,
+			IDE_SUBDRIVER_VERSION)) {
+		printk(KERN_ERR "ide-scsi: %s: Failed to register the "
+			"driver with ide.c\n", drive->name);
+		kfree(scsi);
+		ret = 1;
+		goto bye_game_over;
+	}
+
+	idescsi_setup(drive, scsi, id);
+
+//	scan_scsis(HBA, 1, channel, id, lun);
+bye_game_over:
 	MOD_DEC_USE_COUNT;
-#endif
-	return 0;
+	return ret;
 }
 
-/*
- *	idescsi_init will register the driver for each scsi.
- */
+#ifdef MODULE
+/* options */
+char *ignore = NULL;
+
+MODULE_PARM(ignore, "s");
+#endif
+
 int idescsi_init (void)
 {
+#ifdef CLASSIC_BUILTINS_METHOD
 	ide_drive_t *drive;
 	idescsi_scsi_t *scsi;
-	byte media[] = {TYPE_DISK, TYPE_TAPE, TYPE_PROCESSOR, TYPE_WORM, TYPE_ROM, TYPE_SCANNER, TYPE_MOD, 255};
+	u8 media[] = {  TYPE_DISK,		/* 0x00 */
+			TYPE_TAPE,		/* 0x01 */
+			TYPE_PRINTER,		/* 0x02 */
+			TYPE_PROCESSOR,		/* 0x03 */
+			TYPE_WORM,		/* 0x04 */
+			TYPE_ROM,		/* 0x05 */
+			TYPE_SCANNER,		/* 0x06 */
+			TYPE_MOD,		/* 0x07 */
+			255};
+
 	int i, failed, id;
 
 	if (idescsi_initialized)
@@ -623,22 +829,47 @@
 	MOD_INC_USE_COUNT;
 	for (i = 0; media[i] != 255; i++) {
 		failed = 0;
-		while ((drive = ide_scan_devices (media[i], idescsi_driver.name, NULL, failed++)) != NULL) {
+		while ((drive = ide_scan_devices(media[i],
+				idescsi_driver.name, NULL, failed++)) != NULL) {
+#ifdef MODULE
+			/* skip drives we were told to ignore */
+			if (ignore != NULL && strstr(ignore, drive->name)) {
+				printk("ide-scsi: ignoring drive %s\n",
+					drive->name);
+				continue;
+			}
+#endif
 
-			if ((scsi = (idescsi_scsi_t *) kmalloc (sizeof (idescsi_scsi_t), GFP_KERNEL)) == NULL) {
-				printk (KERN_ERR "ide-scsi: %s: Can't allocate a scsi structure\n", drive->name);
+		if ((scsi = (idescsi_scsi_t *) kmalloc(sizeof(idescsi_scsi_t), GFP_KERNEL)) == NULL) {
+				printk(KERN_ERR "ide-scsi: %s: Can't allocate "
+					"a scsi structure\n", drive->name);
 				continue;
 			}
-			if (ide_register_subdriver (drive, &idescsi_driver, IDE_SUBDRIVER_VERSION)) {
-				printk (KERN_ERR "ide-scsi: %s: Failed to register the driver with ide.c\n", drive->name);
-				kfree (scsi);
+			if (ide_register_subdriver(drive, &idescsi_driver,
+					IDE_SUBDRIVER_VERSION)) {
+				printk(KERN_ERR "ide-scsi: %s: Failed to "
+					"register the driver with ide.c\n",
+					drive->name);
+				kfree(scsi);
 				continue;
 			}
-			for (id = 0; id < MAX_HWIFS * MAX_DRIVES && idescsi_drives[id]; id++);
-				idescsi_setup (drive, scsi, id);
+			for (id = 0;
+				id < MAX_HWIFS*MAX_DRIVES && idescsi_drives[id];
+					id++);
+				idescsi_setup(drive, scsi, id);
 			failed--;
 		}
 	}
+#else /* ! CLASSIC_BUILTINS_METHOD */
+	int i;
+
+	if (idescsi_initialized)
+		return 0;
+	idescsi_initialized = 1;
+	for (i = 0; i < MAX_HWIFS * MAX_DRIVES; i++)
+		idescsi_drives[i] = NULL;
+	MOD_INC_USE_COUNT;
+#endif /* CLASSIC_BUILTINS_METHOD */
 	ide_register_module(&idescsi_module);
 	MOD_DEC_USE_COUNT;
 	return 0;
@@ -652,9 +883,11 @@
 
 	host_template->proc_name = "ide-scsi";
 	host = scsi_register(host_template, 0);
-	if(host == NULL)
+	if (host == NULL) {
+		printk(KERN_WARNING "%s: host failure!\n", __FUNCTION__);
 		return 0;
-		
+	}
+
 	for (id = 0; id < MAX_HWIFS * MAX_DRIVES && idescsi_drives[id]; id++)
 		last_lun = IDE_MAX(last_lun, idescsi_drives[id]->last_lun);
 	host->max_id = id;
@@ -671,7 +904,7 @@
 	for (id = 0; id < MAX_HWIFS * MAX_DRIVES; id++) {
 		drive = idescsi_drives[id];
 		if (drive)
-			DRIVER(drive)->busy--;
+			DRIVER(drive)->busy = 0;
 	}
 	return 0;
 }
@@ -701,32 +934,36 @@
 {
 	struct buffer_head *bh, *bhp, *first_bh;
 
-	if ((first_bh = bhp = bh = kmalloc (sizeof(struct buffer_head), GFP_ATOMIC)) == NULL)
+	if ((first_bh = bhp = bh = kmalloc(sizeof(struct buffer_head), GFP_ATOMIC)) == NULL)
 		goto abort;
-	memset (bh, 0, sizeof (struct buffer_head));
+	memset(bh, 0, sizeof(struct buffer_head));
 	bh->b_reqnext = NULL;
 	while (--count) {
-		if ((bh = kmalloc (sizeof(struct buffer_head), GFP_ATOMIC)) == NULL)
+		if ((bh = kmalloc(sizeof(struct buffer_head), GFP_ATOMIC)) == NULL)
 			goto abort;
-		memset (bh, 0, sizeof (struct buffer_head));
+		memset(bh, 0, sizeof(struct buffer_head));
 		bhp->b_reqnext = bh;
 		bhp = bh;
 		bh->b_reqnext = NULL;
 	}
 	return first_bh;
 abort:
-	idescsi_free_bh (first_bh);
+	idescsi_free_bh(first_bh);
 	return NULL;
 }
 
 static inline int idescsi_set_direction (idescsi_pc_t *pc)
 {
 	switch (pc->c[0]) {
-		case READ_6: case READ_10: case READ_12:
-			clear_bit (PC_WRITING, &pc->flags);
+		case READ_6:
+		case READ_10:
+		case READ_12:
+			clear_bit(PC_WRITING, &pc->flags);
 			return 0;
-		case WRITE_6: case WRITE_10: case WRITE_12:
-			set_bit (PC_WRITING, &pc->flags);
+		case WRITE_6:
+		case WRITE_10:
+		case WRITE_12:
+			set_bit(PC_WRITING, &pc->flags);
 			return 0;
 		default:
 			return 1;
@@ -744,12 +981,17 @@
 	if (idescsi_set_direction(pc))
 		return NULL;
 	if (segments) {
-		if ((first_bh = bh = idescsi_kmalloc_bh (segments)) == NULL)
+		if ((first_bh = bh = idescsi_kmalloc_bh(segments)) == NULL)
 			return NULL;
 #if IDESCSI_DEBUG_LOG
-		printk ("ide-scsi: %s: building DMA table, %d segments, %dkB total\n", drive->name, segments, pc->request_transfer >> 10);
+		printk("ide-scsi: %s: building DMA table, %d segments, "
+			"%dkB total\n", drive->name, segments,
+			pc->request_transfer >> 10);
 #endif /* IDESCSI_DEBUG_LOG */
 		while (segments--) {
+#if 1
+			bh->b_data = sg->address;
+#else
 			if (sg->address) {
 				bh->b_page = virt_to_page(sg->address);
 				bh->b_data = (char *) ((unsigned long) sg->address & ~PAGE_MASK);
@@ -757,7 +999,7 @@
 				bh->b_page = sg->page;
 				bh->b_data = (char *) sg->offset;
 			}
-
+#endif
 			bh->b_size = sg->length;
 			bh = bh->b_reqnext;
 			sg++;
@@ -766,10 +1008,12 @@
 		/*
 		 * non-sg requests are guarenteed not to reside in highmem /jens
 		 */
-		if ((first_bh = bh = idescsi_kmalloc_bh (1)) == NULL)
+		if ((first_bh = bh = idescsi_kmalloc_bh(1)) == NULL)
 			return NULL;
 #if IDESCSI_DEBUG_LOG
-		printk ("ide-scsi: %s: building DMA table for a single buffer (%dkB)\n", drive->name, pc->request_transfer >> 10);
+		printk("ide-scsi: %s: building DMA table for a single "
+			"buffer (%dkB)\n", drive->name,
+			pc->request_transfer >> 10);
 #endif /* IDESCSI_DEBUG_LOG */
 		bh->b_data = pc->scsi_cmd->request_buffer;
 		bh->b_size = pc->request_transfer;
@@ -794,21 +1038,22 @@
 	idescsi_pc_t *pc = NULL;
 
 	if (!drive) {
-		printk (KERN_ERR "ide-scsi: drive id %d not present\n", cmd->target);
+		printk(KERN_ERR "ide-scsi: drive id %d not present\n",
+			cmd->target);
 		goto abort;
 	}
 	scsi = drive->driver_data;
-	pc = kmalloc (sizeof (idescsi_pc_t), GFP_ATOMIC);
-	rq = kmalloc (sizeof (struct request), GFP_ATOMIC);
+	pc = kmalloc(sizeof(idescsi_pc_t), GFP_ATOMIC);
+	rq = kmalloc(sizeof(struct request), GFP_ATOMIC);
 	if (rq == NULL || pc == NULL) {
-		printk (KERN_ERR "ide-scsi: %s: out of memory\n", drive->name);
+		printk(KERN_ERR "ide-scsi: %s: out of memory\n", drive->name);
 		goto abort;
 	}
 
-	memset (pc->c, 0, 12);
+	memset(pc->c, 0, 12);
 	pc->flags = 0;
 	pc->rq = rq;
-	memcpy (pc->c, cmd->cmnd, cmd->cmd_len);
+	memcpy(pc->c, cmd->cmnd, cmd->cmd_len);
 	if (cmd->use_sg) {
 		pc->buffer = NULL;
 		pc->sg = cmd->request_buffer;
@@ -824,28 +1069,30 @@
 
 	if (should_transform(drive, cmd))
 		set_bit(PC_TRANSFORM, &pc->flags);
-	idescsi_transform_pc1 (drive, pc);
+	idescsi_transform_pc1(drive, pc);
 
 	if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) {
-		printk ("ide-scsi: %s: que %lu, cmd = ", drive->name, cmd->serial_number);
+		printk("ide-scsi: %s: que %lu, cmd = ",
+			drive->name, cmd->serial_number);
 		hexdump(cmd->cmnd, cmd->cmd_len);
 		if (memcmp(pc->c, cmd->cmnd, cmd->cmd_len)) {
-			printk ("ide-scsi: %s: que %lu, tsl = ", drive->name, cmd->serial_number);
+			printk("ide-scsi: %s: que %lu, tsl = ",
+				drive->name, cmd->serial_number);
 			hexdump(pc->c, 12);
 		}
 	}
 
-	ide_init_drive_cmd (rq);
+	ide_init_drive_cmd(rq);
 	rq->buffer = (char *) pc;
-	rq->bh = idescsi_dma_bh (drive, pc);
+	rq->bh = idescsi_dma_bh(drive, pc);
 	rq->cmd = IDESCSI_PC_RQ;
 	spin_unlock_irq(&io_request_lock);
-	(void) ide_do_drive_cmd (drive, rq, ide_end);
+	(void) ide_do_drive_cmd(drive, rq, ide_end);
 	spin_lock_irq(&io_request_lock);
 	return 0;
 abort:
-	if (pc) kfree (pc);
-	if (rq) kfree (rq);
+	if (pc) kfree(pc);
+	if (rq) kfree(rq);
 	cmd->result = DID_ERROR << 16;
 	done(cmd);
 	return 0;
@@ -858,6 +1105,14 @@
 
 int idescsi_reset (Scsi_Cmnd *cmd, unsigned int resetflags)
 {
+	ide_drive_t *drive	= idescsi_drives[cmd->target];
+
+	/* We cannot reset the interface holding the lock. We can
+	   drop the lock here however */
+	   
+	spin_unlock(&io_request_lock);
+	(void) ide_do_reset(drive);
+	spin_lock(&io_request_lock);
 	return SCSI_RESET_SUCCESS;
 }
 
@@ -877,24 +1132,25 @@
 
 static int __init init_idescsi_module(void)
 {
+	drive_count = 0;
 	idescsi_init();
 	idescsi_template.module = THIS_MODULE;
-	scsi_register_module (MODULE_SCSI_HA, &idescsi_template);
+	scsi_register_module(MODULE_SCSI_HA, &idescsi_template);
 	return 0;
 }
 
 static void __exit exit_idescsi_module(void)
 {
 	ide_drive_t *drive;
-	byte media[] = {TYPE_DISK, TYPE_TAPE, TYPE_PROCESSOR, TYPE_WORM, TYPE_ROM, TYPE_SCANNER, TYPE_MOD, 255};
+	u8 media[] = {TYPE_DISK, TYPE_TAPE, TYPE_PROCESSOR, TYPE_WORM, TYPE_ROM, TYPE_SCANNER, TYPE_MOD, 255};
 	int i, failed;
 
-	scsi_unregister_module (MODULE_SCSI_HA, &idescsi_template);
+	scsi_unregister_module(MODULE_SCSI_HA, &idescsi_template);
 	for (i = 0; media[i] != 255; i++) {
 		failed = 0;
-		while ((drive = ide_scan_devices (media[i], idescsi_driver.name, &idescsi_driver, failed)) != NULL)
-			if (idescsi_cleanup (drive)) {
-				printk ("%s: exit_idescsi_module() called while still busy\n", drive->name);
+		while ((drive = ide_scan_devices(media[i], idescsi_driver.name, &idescsi_driver, failed)) != NULL)
+			if (idescsi_cleanup(drive)) {
+				printk("%s: exit_idescsi_module() called while still busy\n", drive->name);
 				failed++;
 			}
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/ide-scsi.h linux-2.4.21-pre6/drivers/scsi/ide-scsi.h
--- linux-2.4.20/drivers/scsi/ide-scsi.h	1998-04-10 22:22:21.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/ide-scsi.h	2003-03-26 23:49:56.000000000 +0000
@@ -16,22 +16,22 @@
 extern int idescsi_reset (Scsi_Cmnd *cmd, unsigned int resetflags);
 extern int idescsi_bios (Disk *disk, kdev_t dev, int *parm);
 
-#define IDESCSI  {								\
-	name:            "idescsi",		/* name		*/		\
-	detect:          idescsi_detect,	/* detect	*/		\
-	release:         idescsi_release,	/* release	*/		\
-	info:            idescsi_info,		/* info		*/		\
-	ioctl:           idescsi_ioctl,		/* ioctl        */		\
-	queuecommand:    idescsi_queue,		/* queuecommand */		\
-	abort:           idescsi_abort,		/* abort	*/		\
-	reset:           idescsi_reset,		/* reset	*/		\
-	bios_param:      idescsi_bios,		/* bios_param	*/		\
-	can_queue:       10,			/* can_queue	*/		\
-	this_id:         -1,			/* this_id	*/		\
-	sg_tablesize:    256,			/* sg_tablesize	*/		\
-	cmd_per_lun:     5,			/* cmd_per_lun	*/		\
-	use_clustering:  DISABLE_CLUSTERING,	/* clustering	*/		\
-	emulated:        1			/* emulated     */		\
+#define IDESCSI  {							\
+	name:            "idescsi",		/* name		*/	\
+	detect:          idescsi_detect,	/* detect	*/	\
+	release:         idescsi_release,	/* release	*/	\
+	info:            idescsi_info,		/* info		*/	\
+	ioctl:           idescsi_ioctl,		/* ioctl        */	\
+	queuecommand:    idescsi_queue,		/* queuecommand */	\
+	abort:           idescsi_abort,		/* abort	*/	\
+	reset:           idescsi_reset,		/* reset	*/	\
+	bios_param:      idescsi_bios,		/* bios_param	*/	\
+	can_queue:       10,			/* can_queue	*/	\
+	this_id:         -1,			/* this_id	*/	\
+	sg_tablesize:    256,			/* sg_tablesize	*/	\
+	cmd_per_lun:     5,			/* cmd_per_lun	*/	\
+	use_clustering:  DISABLE_CLUSTERING,	/* clustering	*/	\
+	emulated:        1			/* emulated     */	\
 }
 
 #endif /* IDESCSI_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/in2000.c linux-2.4.21-pre6/drivers/scsi/in2000.c
--- linux-2.4.20/drivers/scsi/in2000.c	2001-09-30 19:26:07.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/in2000.c	2003-03-26 23:49:50.000000000 +0000
@@ -1916,14 +1916,14 @@
    0
    };
 
-static const unsigned short base_tab[] in2000__INITDATA = {
+static unsigned short base_tab[] in2000__INITDATA = {
    0x220,
    0x200,
    0x110,
    0x100,
    };
 
-static const int int_tab[] in2000__INITDATA = {
+static int int_tab[] in2000__INITDATA = {
    15,
    14,
    11,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/ips.c linux-2.4.21-pre6/drivers/scsi/ips.c
--- linux-2.4.20/drivers/scsi/ips.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/ips.c	2003-03-26 23:48:57.000000000 +0000
@@ -1,11 +1,12 @@
 /*****************************************************************************/
-/* ips.c -- driver for the IBM ServeRAID controller                          */
+/* ips.c -- driver for the Adaptec / IBM ServeRAID controller                */
 /*                                                                           */
 /* Written By: Keith Mitchell, IBM Corporation                               */
 /*             Jack Hammer, Adaptec, Inc.                                    */
 /*             David Jeffery, Adaptec, Inc.                                  */
 /*                                                                           */
-/* Copyright (C) 2000 IBM Corporation                                        */
+/* Copyright (C) 2000 IBM Corporation                                        */ 
+/* Copyright (C) 2003 Adaptec, Inc.                                          */ 
 /*                                                                           */
 /* This program is free software; you can redistribute it and/or modify      */
 /* it under the terms of the GNU General Public License as published by      */
@@ -42,7 +43,7 @@
 /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 /*                                                                           */
 /* Bugs/Comments/Suggestions about this driver should be mailed to:          */
-/*      ipslinux@adaptec.com     	                                         */
+/*      ipslinux@adaptec.com        	                                     */
 /*                                                                           */
 /* For system support issues, contact your local IBM Customer support.       */
 /* Directions to find IBM Customer Support for each country can be found at: */
@@ -66,9 +67,8 @@
 /* 0.99.05  - Fix an oops when we get certain passthru commands              */
 /* 1.00.00  - Initial Public Release                                         */
 /*            Functionally equivalent to 0.99.05                             */
-/* 3.60.00  - Bump max commands to 128 for use with ServeRAID firmware 3.60  */
-/*          - Change version to 3.60 to coincide with ServeRAID release      */
-/*            numbering.                                                     */
+/* 3.60.00  - Bump max commands to 128 for use with firmware 3.60            */
+/*          - Change version to 3.60 to coincide with release numbering.     */
 /* 3.60.01  - Remove bogus error check in passthru routine                   */
 /* 3.60.02  - Make DCDB direction based on lookup table                      */
 /*          - Only allow one DCDB command to a SCSI ID at a time             */
@@ -76,7 +76,7 @@
 /* 4.00.01  - Add support for First Failure Data Capture                     */
 /* 4.00.02  - Fix problem with PT DCDB with no buffer                        */
 /* 4.00.03  - Add alternative passthru interface                             */
-/*          - Add ability to flash ServeRAID BIOS                            */
+/*          - Add ability to flash BIOS                                      */
 /* 4.00.04  - Rename structures/constants to be prefixed with IPS_           */
 /* 4.00.05  - Remove wish_block from init routine                            */
 /*          - Use linux/spinlock.h instead of asm/spinlock.h for kernels     */
@@ -126,6 +126,10 @@
 /* 5.00.01  - Sarasota ( 5i ) adapters must always be scanned first          */
 /*          - Get rid on IOCTL_NEW_COMMAND code                              */
 /*          - Add Extended DCDB Commands for Tape Support in 5I              */
+/* 5.10.12  - use pci_dma interfaces, update for 2.5 kernel changes          */
+/* 5.10.15  - remove unused code (sem, macros, etc.)                         */
+/* 5.30.00  - use __devexit_p()                                              */
+/* 6.00.00  - Add 6x Adapters and Battery Flash                              */
 /*****************************************************************************/
 
 /*
@@ -157,13 +161,10 @@
 #include <linux/kernel.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
-#include <linux/vmalloc.h>
 #include <linux/delay.h>
-#include <linux/sched.h>
 #include <linux/pci.h>
 #include <linux/proc_fs.h>
 #include <linux/reboot.h>
-#include <linux/tqueue.h>
 #include <linux/interrupt.h>
 
 #include <linux/blk.h>
@@ -198,8 +199,8 @@
 /*
  * DRIVER_VER
  */
-#define IPS_VERSION_HIGH        "5.10"
-#define IPS_VERSION_LOW         ".21 "
+#define IPS_VERSION_HIGH        "6.00"
+#define IPS_VERSION_LOW         ".26 "
 
 
 #if LINUX_VERSION_CODE < LinuxVersionCode(2,4,0)
@@ -223,7 +224,7 @@
                                              dma_addr_t *dmahandle) {
        void * ptr = kmalloc(size, GFP_ATOMIC); 
        if(ptr){     
-          *dmahandle = VIRT_TO_BUS(ptr);
+          *dmahandle = (uint32_t)virt_to_bus(ptr);
        }
        return ptr;
     }
@@ -232,15 +233,34 @@
     
     #define pci_map_sg(a,b,n,z)       (n)
     #define pci_unmap_sg(a,b,c,d)     
-    #define pci_map_single(a,b,c,d)   (VIRT_TO_BUS(b))
+    #define pci_map_single(a,b,c,d)   ((uint32_t)virt_to_bus(b))
     #define pci_unmap_single(a,b,c,d) 
     #ifndef sg_dma_address
-      #define sg_dma_address(x)         (VIRT_TO_BUS((x)->address))
+      #define sg_dma_address(x)         ((uint32_t)virt_to_bus((x)->address))
       #define sg_dma_len(x)             ((x)->length)
     #endif
     #define pci_unregister_driver(x)
 #endif
 
+#if LINUX_VERSION_CODE <= LinuxVersionCode(2,5,0)
+    #define IPS_SG_ADDRESS(sg)       ((sg)->address)
+    #define IPS_LOCK_SAVE(lock,flags) spin_lock_irqsave(&io_request_lock,flags)
+    #define IPS_UNLOCK_RESTORE(lock,flags) spin_unlock_irqrestore(&io_request_lock,flags)
+    #ifndef __devexit_p
+        #define __devexit_p(x) x
+    #endif
+#else
+    #define IPS_SG_ADDRESS(sg)      (page_address((sg)->page) ? \
+                                     page_address((sg)->page)+(sg)->offset : 0)
+    #define IPS_LOCK_SAVE(lock,flags) spin_lock(lock)
+    #define IPS_UNLOCK_RESTORE(lock,flags) spin_unlock(lock)
+#endif
+
+#define IPS_DMA_DIR(scb) ((!scb->scsi_cmd || ips_is_passthru(scb->scsi_cmd) || \
+                         SCSI_DATA_NONE == scb->scsi_cmd->sc_data_direction) ? \
+                         PCI_DMA_BIDIRECTIONAL : \
+                         scsi_to_pci_dma_dir(scb->scsi_cmd->sc_data_direction))
+
 #ifdef IPS_DEBUG
    #define METHOD_TRACE(s, i)    if (ips_debug >= (i+10)) printk(KERN_NOTICE s "\n");
    #define DEBUG(i, s)           if (ips_debug >= i) printk(KERN_NOTICE s "\n");
@@ -265,19 +285,26 @@
 static int          ips_force_memio = 1;             /* Always use Memory Mapped I/O    */
 static int          ips_force_i2o = 1;               /* Always use I2O command delivery */
 static int          ips_ioctlsize = IPS_IOCTL_SIZE;  /* Size of the ioctl buffer        */
-static int          ips_cd_boot = 0;                 /* Booting from ServeRAID Manager CD */
+static int          ips_cd_boot = 0;                 /* Booting from Manager CD         */
 static char        *ips_FlashData = NULL;            /* CD Boot - Flash Data Buffer      */
-static int          ips_FlashDataInUse = 0;          /* CD Boot - Flash Data In Use Flag */
+static long         ips_FlashDataInUse = 0;          /* CD Boot - Flash Data In Use Flag */
 static uint32_t     MaxLiteCmds = 32;                /* Max Active Cmds for a Lite Adapter */  
 
 IPS_DEFINE_COMPAT_TABLE( Compatable );               /* Version Compatability Table      */
 
 
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
-   /* This table describes any / all ServeRAID Adapters */
+   /* This table describes all ServeRAID Adapters */
    static struct  pci_device_id  ips_pci_table[]  __devinitdata = {
            { 0x1014, 0x002E, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
            { 0x1014, 0x01BD, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
+           { 0x9005, 0x0250, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
+           { 0, }
+   };
+
+   /* This table describes only Anaconda Family Adapters */
+   static struct  pci_device_id  ips_pci_table_anaconda[]  __devinitdata = {
+           { 0x1014, 0x002E, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
            { 0, }
    };
 
@@ -287,13 +314,25 @@
                    { 0x1014, 0x01BD, PCI_ANY_ID, 0x258, 0, 0 },
                    { 0, }
                    };   
+
+   /* This table describes only Sebring ( ServeRAID 6i ) Adapters */
+   static struct  pci_device_id  ips_pci_table_6i[]  __devinitdata = {
+                   { 0x9005, 0x0250, PCI_ANY_ID, 0x28C, 0, 0 },
+                   { 0, }
+                   };   
     
-   /* This table describes all i960 Adapters */
+   /* This table describes all i960 ( 4M, 4Mx, 4L, 4Lx ) Adapters */
    static struct  pci_device_id  ips_pci_table_i960[]  __devinitdata = {
                    { 0x1014, 0x01BD, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
                    { 0, }
                    };   
 
+   /* This table describes all Adaptec ( 6M ) Adapters */
+   static struct  pci_device_id  ips_pci_table_adaptec[]  __devinitdata = {
+                   { 0x9005, 0x0250, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
+                   { 0, }
+                   };   
+
    MODULE_DEVICE_TABLE( pci, ips_pci_table );
 
    static char ips_hot_plug_name[] = "ips";
@@ -308,12 +347,26 @@
        remove:		__devexit_p(ips_remove_device),
    }; 
            
+   struct pci_driver ips_pci_driver_anaconda = {
+       name:		ips_hot_plug_name,
+       id_table:	ips_pci_table_anaconda,
+       probe:		ips_insert_device,
+       remove:		__devexit_p(ips_remove_device),
+   }; 
+
    struct pci_driver ips_pci_driver_5i = {
        name:		ips_hot_plug_name,
        id_table:	ips_pci_table_5i,
        probe:		ips_insert_device,
        remove:		__devexit_p(ips_remove_device),
    };
+           
+   struct pci_driver ips_pci_driver_6i = {
+       name:		ips_hot_plug_name,
+       id_table:	ips_pci_table_6i,
+       probe:		ips_insert_device,
+       remove:		__devexit_p(ips_remove_device),
+   };
 
    struct pci_driver ips_pci_driver_i960 = {
        name:		ips_hot_plug_name,
@@ -322,6 +375,13 @@
        remove:		__devexit_p(ips_remove_device),
    };
 
+   struct pci_driver ips_pci_driver_adaptec = {
+       name:		ips_hot_plug_name,
+       id_table:	ips_pci_table_adaptec,
+       probe:		ips_insert_device,
+       remove:		__devexit_p(ips_remove_device),
+   };
+
 #endif
 
 /*
@@ -344,9 +404,17 @@
    "ServeRAID 4Mx",
    "ServeRAID 4Lx",
    "ServeRAID 5i",
-   "ServeRAID 5i"
+   "ServeRAID 5i",
+   "ServeRAID 6M",
+   "ServeRAID 6i"
 };
 
+/* Init State 0 means we're only looking for a device to provide us the BIOS Adapter Ordering Table */
+/* Init State 1 is when we are actually enumerating the devices.                                    */
+static  int      InitState;
+/* IF BIOS wants to tell us the enumeration order, it puts a table in NVRAM Page 5 */
+static  uint8_t  AdapterOrder[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
 static struct notifier_block ips_notifier = {
    ips_halt, NULL, 0
 };
@@ -479,6 +547,7 @@
 static void ips_free(ips_ha_t *);
 static void ips_init_scb(ips_ha_t *, ips_scb_t *);
 static void ips_freescb(ips_ha_t *, ips_scb_t *);
+static void ips_setup_funclist(ips_ha_t *);
 static void ips_statinit(ips_ha_t *);
 static void ips_statinit_memio(ips_ha_t *);
 static void ips_fix_ffdc_time(ips_ha_t *, ips_scb_t *, time_t);
@@ -512,10 +581,13 @@
 static int copy_info(IPS_INFOSTR *, char *, ...);
 static int ips_get_version_info(ips_ha_t *ha, IPS_VERSION_DATA *Buffer, int intr );
 static void ips_version_check(ips_ha_t *ha, int intr);
+static int ips_abort_init(ips_ha_t *ha, struct Scsi_Host *sh, int index);
 static int ips_init_phase2( int index );
 
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
 static int ips_init_phase1( struct pci_dev *pci_dev, int *indexPtr );
+#else
+static int ips_init_oldphase1(Scsi_Host_Template *SHT);
 #endif
 
 /*--------------------------------------------------------------------------*/
@@ -578,8 +650,8 @@
 
 #else
 
-  char      *p;
-   char       tokens[3] = {',', '.', 0};
+   char   *p;
+   char    tokens[3] = {',', '.', 0};
 
    for (key = strtok(ips_str, tokens); key; key = strtok(NULL, tokens)) {
       p = key;
@@ -593,7 +665,7 @@
          value = p+1;
       } else
          value = NULL;
-
+                          
       /*
        * We now have key/value pairs.
        * Update the variables
@@ -631,33 +703,9 @@
 /****************************************************************************/
 int
 ips_detect(Scsi_Host_Template *SHT) {
-   struct Scsi_Host *sh;
-   ips_ha_t         *ha;
-   uint32_t          io_addr;
-   uint32_t          mem_addr;
-   uint32_t          io_len;
-   uint32_t          mem_len;
-   uint16_t          planer;
-   uint8_t           revision_id;
-   uint8_t           bus;
-   uint8_t           func;
-   uint8_t           irq;
-   uint16_t          deviceID[2];
-   uint16_t          subdevice_id;
-   int               i;
-   int               j;
-   uint32_t          count;
-   char             *ioremap_ptr;
-   char             *mem_ptr;
-   struct pci_dev   *dev[2];
-   struct pci_dev   *morpheus = NULL;
-   struct pci_dev   *trombone = NULL;
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,4,0)
-   uint32_t          currbar;
-   uint32_t          maskbar;
-   uint8_t           barnum;
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
+   int  i;
 #endif
-   uint32_t          IsDead;
 
    METHOD_TRACE("ips_detect", 1);
 
@@ -670,8 +718,8 @@
 #endif
 #endif
 
-   /* If Booting from the ServeRAID Manager CD, Allocate a large Flash  */
-   /* Buffer ( so we won't need to allocate one for each adapter ).     */
+   /* If Booting from the Manager CD, Allocate a large Flash        */
+   /* Buffer ( so we won't need to allocate one for each adapter ). */
     if ( ips_cd_boot ) {            
       ips_FlashData = ( char * ) __get_free_pages( GFP_KERNEL, 7 );   
       if (ips_FlashData == NULL) {
@@ -679,16 +727,6 @@
          printk( KERN_WARNING "ERROR: Can't Allocate Large Buffer for Flashing\n" );
       }
    }                                                                               
-
-   SHT->proc_info = ips_proc_info;
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,4,0)
-   SHT->proc_dir = &proc_scsi_ips;
-#else
-   SHT->proc_name = "ips";
-#endif
-
-#if defined(CONFIG_PCI)
-
    /* initalize number of controllers */
    ips_num_controllers = 0;
    ips_next_controller = 0;
@@ -697,539 +735,569 @@
    if (!pci_present())
       return (0);
 
-   morpheus = pci_find_device(IPS_VENDORID, IPS_DEVICEID_MORPHEUS, morpheus);
-   trombone = pci_find_device(IPS_VENDORID, IPS_DEVICEID_COPPERHEAD, trombone);
-
-   /* determine which controller to probe first */
-   if (!morpheus) {
-      /* we only have trombone */
-      dev[0] = trombone;
-      dev[1] = NULL;
-      deviceID[0] = IPS_DEVICEID_COPPERHEAD;
-   } else if (!trombone) {
-      /* we only have morpheus */
-      dev[0] = morpheus;
-      dev[1] = NULL;
-      deviceID[0] = IPS_DEVICEID_MORPHEUS;
-   } else {
-      /* we have both in the system */
-      if (trombone->bus->number < morpheus->bus->number) {
-         dev[0] = trombone;
-         dev[1] = morpheus;
-         deviceID[0] = IPS_DEVICEID_COPPERHEAD;
-         deviceID[1] = IPS_DEVICEID_MORPHEUS;
-      } else if (trombone->bus->number > morpheus->bus->number) {
-         dev[0] = morpheus;
-         dev[1] = trombone;
-         deviceID[0] = IPS_DEVICEID_MORPHEUS;
-         deviceID[1] = IPS_DEVICEID_COPPERHEAD;
-      } else {
-         /* further detection required */
-         if (trombone->devfn < morpheus->devfn) {
-            dev[0] = trombone;
-            dev[1] = morpheus;
-            deviceID[0] = IPS_DEVICEID_COPPERHEAD;
-            deviceID[1] = IPS_DEVICEID_MORPHEUS;
-         } else {
-            dev[0] = morpheus;
-            dev[1] = trombone;
-            deviceID[0] = IPS_DEVICEID_MORPHEUS;
-            deviceID[1] = IPS_DEVICEID_COPPERHEAD;
-         }
-      }
-   }
-
 /**********************************************************************************/
 /* For Kernel Versions 2.4 or greater, use new PCI ( Hot Pluggable ) architecture */
 /**********************************************************************************/
 
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
+ #if LINUX_VERSION_CODE < LinuxVersionCode(2,5,0)
    spin_unlock_irq(&io_request_lock);
+ #endif
+   SHT->proc_info = ips_proc_info;
+   SHT->proc_name = "ips";
 
-   /* By definition, a Sarasota ( 5i ) Adapter MUST be enumerated first or the */
-   /* server may not boot properly. The adapters must be enumerated in exactly */
-   /* the same order as ServeRAID BIOS for the machine to come up properly.    */
-
-   pci_module_init(&ips_pci_driver_5i);          /* Ask for 5i Adapters First  */
-   if (ips_num_controllers)                      /* If there is a 5i Adapter   */
-      pci_module_init(&ips_pci_driver_i960);     /*    Get all i960's next     */
-   pci_module_init(&ips_pci_driver);             /* Get all remaining Adapters */
-                                                 /*  ( in normal BUS order )   */
-   spin_lock_irq(&io_request_lock);
-   if (ips_num_controllers > 0) 
-      register_reboot_notifier(&ips_notifier);
-
-   return (ips_num_controllers);
+   /* There are several special cases ( which are too complicated to enumerate here ) where, due */
+   /* to System BIOS rules, the adapters must be enumerated in a certain order.  If ServeRAID    */
+   /* BIOS tells us the order, then we will follow it.  The first pass at init is simply to be   */
+   /* able to communicate with the first adapter to see if BIOS is telling us the order.         */ 
+   /* This does not apply to ia64 EFI BIOS.                                                      */
+
+#if !defined(__ia64__)
+   InitState = 0;
+   pci_module_init(&ips_pci_driver); /* Look for Any Adapter, to fill in the Adapter Order Table */
 #endif
 
-   /* Now scan the controllers */
-   for (i = 0; i < 2; i++) {
-      if (!dev[i])
-         break;
+   InitState = 1;       
+   
+   if ( AdapterOrder[0] ) {  
+      /* BIOS has dictated the order that we should enumerate Adapters */
+      for ( i = 1; i <= AdapterOrder[0]; i++ ) {
+          switch (AdapterOrder[i]) {
+          case 'M':
+              pci_module_init(&ips_pci_driver_adaptec);     /* Ask for Adaptec Adapters */
+              break;
+          case 'S':
+              pci_module_init(&ips_pci_driver_5i);          /* Ask for 5i Adapters      */
+              pci_module_init(&ips_pci_driver_6i);          /* Ask for 6i Adapters      */
+              break;
+          case 'N':
+              pci_module_init(&ips_pci_driver_i960);        /* Ask for i960 Adapters    */
+              break;
+          case 'A':
+              pci_module_init(&ips_pci_driver_anaconda);    /* Ask for Anaconda Family Adapters */
+              break;
+          default:
+              i = AdapterOrder[0] + 1;                      /* Premature End of List - Ensure Loop Ends */
+              break;
+          }
+      }
+   }
+   else { 
+      /* No Adapter Order Table from BIOS, so sort things the old-fashioned way */
 
-      do {
-         if (ips_next_controller >= IPS_MAX_ADAPTERS)
-            break;
+      /* By definition, an Internal ( 5i or 6i ) Adapter MUST be enumerated first */
+      /* or the server may not boot properly. The adapters must be enumerated in  */
+      /* exactly the same order as BIOS for the machine to come up properly.      */
+      /*    NOTE: There will never be both a 5i and a 6i in the same machine.     */
 
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
-         if (pci_enable_device(dev[i]))
-            break;
-#endif
+      pci_module_init(&ips_pci_driver_5i);          /* Ask for 5i Adapters First  */
+      if (ips_num_controllers) {                    /* If there is a 5i Adapter   */
+         pci_module_init(&ips_pci_driver_i960);     /*    Get all i960's next     */
+      }
+      else {
+         pci_module_init(&ips_pci_driver_6i);         /* Ask if any 6i Adapters   */
+         if (ips_num_controllers)                     /* If there is a 6i Adapter */
+            pci_module_init(&ips_pci_driver_adaptec); /*    Get all Adaptecs next */
+      }
 
-         /* stuff that we get in dev */
-         irq = dev[i]->irq;
-         bus = dev[i]->bus->number;
-         func = dev[i]->devfn;
-
-         /* Init MEM/IO addresses to 0 */
-         mem_addr = 0;
-         io_addr = 0;
-         mem_len = 0;
-         io_len = 0;
+      pci_module_init(&ips_pci_driver);             /* Get all remaining Adapters */
+                                                    /*  ( in normal BUS order )   */
+   }
 
-         for (j = 0; j < 2; j++) {
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
-            if (!pci_resource_start(dev[i], j))
-               break;
+ #if LINUX_VERSION_CODE < LinuxVersionCode(2,5,0)
+   spin_lock_irq(&io_request_lock);
+ #endif
+   if (ips_num_controllers > 0) 
+      register_reboot_notifier(&ips_notifier);
 
-            if (pci_resource_flags(dev[i], j) & IORESOURCE_IO) {
-               io_addr = pci_resource_start(dev[i], j);
-               io_len = pci_resource_len(dev[i], j);
-            } else {
-               mem_addr = pci_resource_start(dev[i], j);
-               mem_len = pci_resource_len(dev[i], j);
-            }
+   return (ips_num_controllers);
 #else
-            if (!dev[i]->base_address[j])
-               break;
-
-            if ((dev[i]->base_address[j] & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) {
-               barnum = PCI_BASE_ADDRESS_0 + (j * 4);
-               io_addr = dev[i]->base_address[j] & PCI_BASE_ADDRESS_IO_MASK;
-
-               /* Get Size */
-               pci_read_config_dword(dev[i], barnum, &currbar);
-               pci_write_config_dword(dev[i], barnum, ~0);
-               pci_read_config_dword(dev[i], barnum, &maskbar);
-               pci_write_config_dword(dev[i], barnum, currbar);
+   InitState = 1;
+   SHT->proc_info = ips_proc_info;
+   SHT->proc_dir = &proc_scsi_ips;
+   return ips_init_oldphase1(SHT);
+#endif /* LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0) */
 
-               io_len = ~(maskbar & PCI_BASE_ADDRESS_IO_MASK) + 1;
-            } else {
-               barnum = PCI_BASE_ADDRESS_0 + (j * 4);
-               mem_addr = dev[i]->base_address[j] & PCI_BASE_ADDRESS_MEM_MASK;
+}
 
-               /* Get Size */
-               pci_read_config_dword(dev[i], barnum, &currbar);
-               pci_write_config_dword(dev[i], barnum, ~0);
-               pci_read_config_dword(dev[i], barnum, &maskbar);
-               pci_write_config_dword(dev[i], barnum, currbar);
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,4,0)
 
-               mem_len = ~(maskbar & PCI_BASE_ADDRESS_MEM_MASK) + 1;
+/***********************************************************************************/
+/*   Sort the Device Structures                                                    */
+/*   Devices are sorted by groups ( type ) and then PCI address within each group  */  
+/*   This also results in the same ordering that results when using the 2.4 kernel */
+/*   architecture for initialization.                                              */
+/***********************************************************************************/
+
+static void 
+ips_sort_controllers(struct pci_dev *dev[]) {
+   struct pci_dev *tempdev[IPS_MAX_ADAPTERS];
+   struct pci_dev *lowestdev;
+   int             i, j;
+   int             temp_index = 0;    /* Index into tempdev[] array */    
+   int             lowIndex = 0;
+   int             newlowflag = 0;    /* Flag to indicate when a new low address has been found */
+   uint16_t        subdevice_id;
+   unsigned char   BusNumber;
+
+   /* Clear the Temporary Dev Structure */
+   for (i = 0; i < IPS_MAX_ADAPTERS; i++) 
+       tempdev[i] = NULL;
+
+   /* The Outer Loop goes thru each Adapter Type Supported */
+   for (j = 0; j < IPS_MAX_ADAPTER_TYPES; j++) {
+      lowestdev = NULL;
+      /* The Inner Loop Checks each Device still in the List and */
+      /* Finds the lowset adapter left ( by PCI boot order )     */
+      for (i = 0; i < IPS_MAX_ADAPTERS; i++) {
+         if (dev[i]) {
+            if (lowestdev == NULL) {  /* If this is the first one found, it must be the lowest ! */
+               lowestdev = dev[i];
+               lowIndex = i;
             }
-#endif
-         }
-
-         /* setup memory mapped area (if applicable) */
-         if (mem_addr) {
-            uint32_t base;
-            uint32_t offs;
-
-            DEBUG_VAR(1, "(%s%d) detect, Memory region %x, size: %d",
-                      ips_name, ips_next_controller, mem_addr, mem_len);
 
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
-            if (check_mem_region(mem_addr, mem_len)) {
-               /* Couldn't allocate io space */
-               printk(KERN_WARNING "(%s%d) couldn't allocate IO space %x len %d.\n",
-                      ips_name, ips_next_controller, io_addr, io_len);
+            /* If you find a Sarasota ( 5i ), it must always be treated as the first adapter */
+            if (dev[i]->device == IPS_DEVICEID_MORPHEUS) {
+                pci_read_config_word(dev[i], PCI_SUBSYSTEM_ID, &subdevice_id);
+                if ((subdevice_id == IPS_SUBDEVICEID_5I1) || 
+                    (subdevice_id == IPS_SUBDEVICEID_5I2)) {
+                     lowestdev = dev[i];
+                     lowIndex = i;
+                     break;
+                }
+            } 
 
-               ips_next_controller++;
+            /* If you find a Sebring ( 6i ), it must always be treated as the first adapter */
+            if (dev[i]->device == IPS_DEVICEID_MARCO) {
+                pci_read_config_word(dev[i], PCI_SUBSYSTEM_ID, &subdevice_id);
+                if (subdevice_id == IPS_SUBDEVICEID_6I) {
+                    lowestdev = dev[i];
+                    lowIndex = i;
+                    break;
+                }
+            }    
 
-               continue;
-            }
+            /* Determine if this device is at a lower PCI address than the current lowest device */
+            newlowflag = 0;
 
-            request_mem_region(mem_addr, mem_len, "ips");
-#endif
+            if (dev[i]->device == IPS_DEVICEID_MARCO)     /* System BIOS adds 1 to Marco Bus Number */
+                BusNumber = ( dev[i]->bus->number ) - 1;  /*        because of Bridge Chip          */
+            else
+                BusNumber = dev[i]->bus->number;
 
-            base = mem_addr & PAGE_MASK;
-            offs = mem_addr - base;
+            if (BusNumber < lowestdev->bus->number)        /* IF a lower BUS # */
+                newlowflag = i;
 
-            ioremap_ptr = ioremap(base, PAGE_SIZE);
-            mem_ptr = ioremap_ptr + offs;
-         } else {
-            ioremap_ptr = NULL;
-            mem_ptr = NULL;
+            if ((BusNumber == lowestdev->bus->number) &&   /* If Same Bus #, but a lower device # */
+                (dev[i]->devfn < lowestdev->devfn)) 
+                newlowflag = i;
+
+            if ( newlowflag ) {
+                lowestdev = dev[i];
+                lowIndex = i;
+            }
          }
-
-         /* setup I/O mapped area (if applicable) */
-         if (io_addr) {
-            DEBUG_VAR(1, "(%s%d) detect, IO region %x, size: %d",
-                      ips_name, ips_next_controller, io_addr, io_len);
-
-            if (check_region(io_addr, io_len)) {
-               /* Couldn't allocate io space */
-               printk(KERN_WARNING "(%s%d) couldn't allocate IO space %x len %d.\n",
-                      ips_name, ips_next_controller, io_addr, io_len);
-
-               ips_next_controller++;
-
-               continue;
+      }
+                                                                                     
+      if (lowestdev) {                       /* If we found another adapter */
+         tempdev[temp_index] = lowestdev;    /*    Add it in the list       */
+         dev[lowIndex] = NULL;               /*    Null it out so we don't find it again */
+         temp_index++;
+         /* Now get all the adapters that are the same type as the low one      . */
+         /* They will already be in order, so they don't need any further sorting.*/
+         for (i = 0; i < IPS_MAX_ADAPTERS; i++) {
+            if (dev[i]) {
+               if (dev[i]->device == lowestdev->device) {
+                  tempdev[temp_index] = dev[i];  /* Add the same type adapter to the list */
+                  temp_index++;                    
+                  dev[i] = NULL;                 /* Null it out so we don't find it again */
+               }                           
             }
-
-            request_region(io_addr, io_len, "ips");
          }
+      }
+   }
 
-         /* get planer status */
-         if (pci_read_config_word(dev[i], 0x04, &planer)) {
-            printk(KERN_WARNING "(%s%d) can't get planer status.\n",
-                   ips_name, ips_next_controller);
+   /* Copy the Sorted Adapter Pointers ( tempdev[] ) to the Original Structure */
+   for (i = 0; i < IPS_MAX_ADAPTERS; i++) 
+       dev[i] = tempdev[i];
 
-            ips_next_controller++;
+}
 
-            continue;
-         }
+/****************************************************************************/
+/*   Detect and initialize the driver for 2.2 kernels                       */
+/*                                                                          */
+/* NOTE: this routine is called under the io_request_lock spinlock          */
+/****************************************************************************/
+static int ips_init_oldphase1(Scsi_Host_Template *SHT){
+   struct Scsi_Host *sh;
+   ips_ha_t         *ha;
+   uint32_t          io_addr;
+   uint32_t          mem_addr;
+   uint32_t          io_len;
+   uint32_t          mem_len;
+   uint16_t          planer;
+   uint8_t           revision_id;
+   uint8_t           bus;
+   uint8_t           func;
+   uint8_t           irq;
+   uint16_t          subdevice_id;
+   int               i;
+   int               j;
+   uint32_t          count;
+   char             *ioremap_ptr;
+   char             *mem_ptr;
+   struct pci_dev   *dev[IPS_MAX_ADAPTERS];
+   dma_addr_t        dma_address;
+   uint32_t          currbar;
+   uint32_t          maskbar;
+   uint8_t           barnum;
+   uint32_t          IsDead;
 
-         /* check to see if an onboard planer controller is disabled */
-         if (!(planer & 0x000C)) {
+   METHOD_TRACE("ips_init_oldphase1", 1);
+   
+   for ( i = 0; i < IPS_MAX_ADAPTERS; i++ ) 
+       dev[i] = NULL;
+   
+   /* Find all the adapters that we support and save them in the dev[] structure */
+   i = 0;
+   dev[i] = pci_find_device(IPS_VENDORID_IBM, IPS_DEVICEID_MORPHEUS, NULL);
+   while ( dev[i] ) {
+      i++;
+      dev[i] = pci_find_device(IPS_VENDORID_IBM, IPS_DEVICEID_MORPHEUS, dev[i-1]);
+   }
+
+   dev[i] = pci_find_device(IPS_VENDORID_IBM, IPS_DEVICEID_COPPERHEAD, NULL);
+   while ( dev[i] ) {
+       i++;
+       dev[i] = pci_find_device(IPS_VENDORID_IBM, IPS_DEVICEID_COPPERHEAD, dev[i-1]);
+   }
+
+   dev[i] = pci_find_device(IPS_VENDORID_ADAPTEC, IPS_DEVICEID_MARCO, NULL);
+   while ( dev[i] ) {
+       i++;
+       dev[i] = pci_find_device(IPS_VENDORID_IBM, IPS_DEVICEID_MARCO, dev[i-1]);
+   }
+     
+   /* Sort the Adapters */
+   if ( dev[0] ) 
+      ips_sort_controllers( dev );
+   else
+      return (0);    
 
-            DEBUG_VAR(1, "(%s%d) detect, Onboard ServeRAID disabled by BIOS",
-                      ips_name, ips_next_controller);
+   /* Now scan and Initialize the controllers */
+   for ( i = 0; i < IPS_MAX_ADAPTERS; i++ ) {
+      if (!dev[i])
+         break;
 
-            ips_next_controller++;
+      if (ips_next_controller >= IPS_MAX_ADAPTERS)
+         break;
 
-            continue;
-         }
+      /* stuff that we get in dev */
+      irq = dev[i]->irq;
+      bus = dev[i]->bus->number;
+      func = dev[i]->devfn;
+
+      /* Init MEM/IO addresses to 0 */
+      mem_addr = 0;
+      io_addr = 0;
+      mem_len = 0;
+      io_len = 0;
 
-         DEBUG_VAR(1, "(%s%d) detect bus %d, func %x, irq %d, io %x, mem: %x, ptr: %p",
-                   ips_name, ips_next_controller, bus, func, irq, io_addr, mem_addr, mem_ptr);
+      for (j = 0; j < 2; j++) {
+         if (!dev[i]->base_address[j])
+            break;
 
-         /* get the revision ID */
-         if (pci_read_config_byte(dev[i], PCI_REVISION_ID, &revision_id)) {
-            printk(KERN_WARNING "(%s%d) can't get revision id.\n",
-                   ips_name, ips_next_controller);
+         if ((dev[i]->base_address[j] & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) {
+            barnum = PCI_BASE_ADDRESS_0 + (j * 4);
+            io_addr = dev[i]->base_address[j] & PCI_BASE_ADDRESS_IO_MASK;
 
-            ips_next_controller++;
+            /* Get Size */
+            pci_read_config_dword(dev[i], barnum, &currbar);
+            pci_write_config_dword(dev[i], barnum, ~0);
+            pci_read_config_dword(dev[i], barnum, &maskbar);
+            pci_write_config_dword(dev[i], barnum, currbar);
 
-            continue;
-         }
+            io_len = ~(maskbar & PCI_BASE_ADDRESS_IO_MASK) + 1;
+        } else {
+            barnum = PCI_BASE_ADDRESS_0 + (j * 4);
+            mem_addr = dev[i]->base_address[j] & PCI_BASE_ADDRESS_MEM_MASK;
 
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,4,0)
-         /* get the subdevice id */
-         if (pci_read_config_word(dev[i], PCI_SUBSYSTEM_ID, &subdevice_id)) {
-            printk(KERN_WARNING "(%s%d) can't get subdevice id.\n",
-                   ips_name, ips_next_controller);
+            /* Get Size */
+            pci_read_config_dword(dev[i], barnum, &currbar);
+            pci_write_config_dword(dev[i], barnum, ~0);
+            pci_read_config_dword(dev[i], barnum, &maskbar);
+            pci_write_config_dword(dev[i], barnum, currbar);
 
-            ips_next_controller++;
-
-            continue;
+            mem_len = ~(maskbar & PCI_BASE_ADDRESS_MEM_MASK) + 1;
          }
-#else
-         subdevice_id = dev[i]->subsystem_device;
-#endif
-
-         /* found a controller */
-         sh = scsi_register(SHT, sizeof(ips_ha_t));
-
-         if (sh == NULL) {
-            printk(KERN_WARNING "(%s%d) Unable to register controller with SCSI subsystem - skipping controller\n",
-                   ips_name, ips_next_controller);
-
-            ips_next_controller++;
+      }
 
-            continue;
-         }
+      /* setup memory mapped area (if applicable) */
+      if (mem_addr) {
+         uint32_t base;
+         uint32_t offs;
 
-         ha = IPS_HA(sh);
-         memset(ha, 0, sizeof(ips_ha_t));
+         DEBUG_VAR(1, "(%s%d) detect, Memory region %x, size: %d",
+                   ips_name, ips_next_controller, mem_addr, mem_len);
 
-         /* Initialize spin lock */
-         spin_lock_init(&ha->scb_lock);
-         spin_lock_init(&ha->copp_lock);
-         spin_lock_init(&ha->ips_lock);
-         spin_lock_init(&ha->copp_waitlist.lock);
-         spin_lock_init(&ha->scb_waitlist.lock);
-         spin_lock_init(&ha->scb_activelist.lock);
-
-         ips_sh[ips_next_controller] = sh;
-         ips_ha[ips_next_controller] = ha;
-         ips_num_controllers++;
-         ha->active = 1;
+         base = mem_addr & PAGE_MASK;
+         offs = mem_addr - base;
 
-         ha->enq = kmalloc(sizeof(IPS_ENQ), GFP_KERNEL);
+         ioremap_ptr = ioremap(base, PAGE_SIZE);
+         mem_ptr = ioremap_ptr + offs;
+      } else {
+         ioremap_ptr = NULL;
+         mem_ptr = NULL;
+      }
 
-         if (!ha->enq) {
-            printk(KERN_WARNING "(%s%d) Unable to allocate host inquiry structure - skipping contoller\n",
-                   ips_name, ips_next_controller);
+      /* setup I/O mapped area (if applicable) */
+      if (io_addr) {
+         DEBUG_VAR(1, "(%s%d) detect, IO region %x, size: %d",
+                   ips_name, ips_next_controller, io_addr, io_len);
+
+         if (check_region(io_addr, io_len)) {
+             /* Couldn't allocate io space */
+            printk(KERN_WARNING "(%s%d) couldn't allocate IO space %x len %d.\n",
+                   ips_name, ips_next_controller, io_addr, io_len);
 
-            ha->active = 0;
-            ips_free(ha);
-            scsi_unregister(sh);
-            ips_ha[ips_next_controller] = 0;
-            ips_sh[ips_next_controller] = 0;
             ips_next_controller++;
-            ips_num_controllers--;
 
             continue;
          }
 
-         ha->adapt = kmalloc(sizeof(IPS_ADAPTER), GFP_KERNEL);
+         request_region(io_addr, io_len, "ips");
+      }
 
-         if (!ha->adapt) {
-            printk(KERN_WARNING "(%s%d) Unable to allocate host adapt structure - skipping controller\n",
-                   ips_name, ips_next_controller);
+      /* get planer status */
+      if (pci_read_config_word(dev[i], 0x04, &planer)) {
+         printk(KERN_WARNING "(%s%d) can't get planer status.\n",
+                ips_name, ips_next_controller);
 
-            ha->active = 0;
-            ips_free(ha);
-            scsi_unregister(sh);
-            ips_ha[ips_next_controller] = 0;
-            ips_sh[ips_next_controller] = 0;
-            ips_next_controller++;
-            ips_num_controllers--;
+         ips_next_controller++;
 
-            continue;
-         }
+         continue;
+      }
 
-         ha->conf = kmalloc(sizeof(IPS_CONF), GFP_KERNEL);
+      /* check to see if an onboard planer controller is disabled */
+      if (!(planer & 0x000C)) {
 
-         if (!ha->conf) {
-            printk(KERN_WARNING "(%s%d) Unable to allocate host conf structure - skipping controller\n",
+         DEBUG_VAR(1, "(%s%d) detect, Onboard controller disabled by BIOS",
                    ips_name, ips_next_controller);
 
-            ha->active = 0;
-            ips_free(ha);
-            scsi_unregister(sh);
-            ips_ha[ips_next_controller] = 0;
-            ips_sh[ips_next_controller] = 0;
-            ips_next_controller++;
-            ips_num_controllers--;
+         ips_next_controller++;
 
-            continue;
-         }
+         continue;
+      }
 
-         ha->nvram = kmalloc(sizeof(IPS_NVRAM_P5), GFP_KERNEL);
+      DEBUG_VAR(1, "(%s%d) detect bus %d, func %x, irq %d, io %x, mem: %x, ptr: %p",
+                ips_name, ips_next_controller, bus, func, irq, io_addr, mem_addr, mem_ptr);
 
-         if (!ha->nvram) {
-            printk(KERN_WARNING "(%s%d) Unable to allocate host nvram structure - skipping controller\n",
-                   ips_name, ips_next_controller);
+      /* get the revision ID */
+      if (pci_read_config_byte(dev[i], PCI_REVISION_ID, &revision_id)) {
+          printk(KERN_WARNING "(%s%d) can't get revision id.\n",
+                 ips_name, ips_next_controller);
+
+        ips_next_controller++;
+        continue;
+      }
+
+      /* get the subdevice id */
+      if (pci_read_config_word(dev[i], PCI_SUBSYSTEM_ID, &subdevice_id)) {
+         printk(KERN_WARNING "(%s%d) can't get subdevice id.\n",
+                ips_name, ips_next_controller);
 
-            ha->active = 0;
-            ips_free(ha);
-            scsi_unregister(sh);
-            ips_ha[ips_next_controller] = 0;
-            ips_sh[ips_next_controller] = 0;
-            ips_next_controller++;
-            ips_num_controllers--;
+         ips_next_controller++;
 
-            continue;
-         }
+         continue;
+      }
 
-         ha->subsys = kmalloc(sizeof(IPS_SUBSYS), GFP_KERNEL);
+      /* found a controller */
+      sh = scsi_register(SHT, sizeof(ips_ha_t));
 
-         if (!ha->subsys) {
-            printk(KERN_WARNING "(%s%d) Unable to allocate host subsystem structure - skipping controller\n",
-                   ips_name, ips_next_controller);
+      if (sh == NULL) {
+         printk(KERN_WARNING "(%s%d) Unable to register controller with SCSI subsystem - skipping controller\n",
+                ips_name, ips_next_controller);
 
-            ha->active = 0;
-            ips_free(ha);
-            scsi_unregister(sh);
-            ips_ha[ips_next_controller] = 0;
-            ips_sh[ips_next_controller] = 0;
-            ips_next_controller++;
-            ips_num_controllers--;
+         ips_next_controller++;
 
-            continue;
-         }
+         continue;
+      }
 
-         ha->dummy = kmalloc(sizeof(IPS_IO_CMD), GFP_KERNEL);
+      ha = IPS_HA(sh);
+      memset(ha, 0, sizeof(ips_ha_t));
 
-         if (!ha->dummy) {
-            printk(KERN_WARNING "(%s%d) Unable to allocate host dummy structure - skipping controller\n",
-                   ips_name, ips_next_controller);
+      ips_sh[ips_next_controller] = sh;
+      ips_ha[ips_next_controller] = ha;
+      ips_num_controllers++;
+      ha->active = 1;
+
+      ha->enq = kmalloc(sizeof(IPS_ENQ), GFP_KERNEL);
+
+      if (!ha->enq) {
+         printk(KERN_WARNING "(%s%d) Unable to allocate host inquiry structure - skipping contoller\n",
+                ips_name, ips_next_controller);
+         ips_abort_init(ha, sh, ips_next_controller);
+         ips_next_controller++;
+         ips_num_controllers--;
 
-            ha->active = 0;
-            ips_free(ha);
-            scsi_unregister(sh);
-            ips_ha[ips_next_controller] = 0;
-            ips_sh[ips_next_controller] = 0;
-            ips_next_controller++;
-            ips_num_controllers--;
+         continue;
+      }
 
-            continue;
-         }
+      ha->adapt = pci_alloc_consistent(dev[i], sizeof(IPS_ADAPTER) + sizeof(IPS_IO_CMD), &dma_address);
 
-         for (count = PAGE_SIZE, ha->ioctl_order = 0;
-              count < ips_ioctlsize;
-              ha->ioctl_order++, count <<= 1);
+      if (!ha->adapt) {
+         printk(KERN_WARNING "(%s%d) Unable to allocate host adapt and dummy structure - skipping controller\n",
+                ips_name, ips_next_controller);
+         ips_abort_init(ha, sh, ips_next_controller);
+         ips_next_controller++;
+         ips_num_controllers--;
 
-         ha->ioctl_data = (char *) __get_free_pages(GFP_KERNEL, ha->ioctl_order);
-         ha->ioctl_datasize = count;
+         continue;
+      }
+      ha->adapt->hw_status_start = dma_address;
+      ha->dummy = (void *)ha->adapt + 1;
 
-         if (!ha->ioctl_data) {
-            printk(KERN_WARNING "(%s%d) Unable to allocate ioctl data\n",
-                   ips_name, ips_next_controller);
+      ha->conf = kmalloc(sizeof(IPS_CONF), GFP_KERNEL);
 
-            ha->ioctl_data = NULL;
-            ha->ioctl_order = 0;
-            ha->ioctl_datasize = 0;
-         }
+      if (!ha->conf) {
+         printk(KERN_WARNING "(%s%d) Unable to allocate host conf structure - skipping controller\n",
+                ips_name, ips_next_controller);
+         ips_abort_init(ha, sh, ips_next_controller);
+         ips_next_controller++;
+         ips_num_controllers--;
 
-         /* Store away needed values for later use */
-         sh->io_port = io_addr;
-         sh->n_io_port = io_addr ? 255 : 0;
-         sh->unique_id = (io_addr) ? io_addr : mem_addr;
-         sh->irq = irq;
-         sh->select_queue_depths = ips_select_queue_depth;
-         sh->sg_tablesize = sh->hostt->sg_tablesize;
-         sh->can_queue = sh->hostt->can_queue;
-         sh->cmd_per_lun = sh->hostt->cmd_per_lun;
-         sh->unchecked_isa_dma = sh->hostt->unchecked_isa_dma;
-         sh->use_clustering = sh->hostt->use_clustering;
+         continue;
+      }
 
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,7)
-         sh->max_sectors = 128;
-#endif                      
+      ha->nvram = kmalloc(sizeof(IPS_NVRAM_P5), GFP_KERNEL);
 
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,4,0)
-         sh->wish_block = FALSE;
-#endif
+      if (!ha->nvram) {
+         printk(KERN_WARNING "(%s%d) Unable to allocate host nvram structure - skipping controller\n",
+                ips_name, ips_next_controller);
+         ips_abort_init(ha, sh, ips_next_controller);
+         ips_next_controller++;
+         ips_num_controllers--;
 
-         /* Store info in HA structure */
-         ha->irq = irq;
-         ha->io_addr = io_addr;
-         ha->io_len = io_len;
-         ha->mem_addr = mem_addr;
-         ha->mem_len = mem_len;
-         ha->mem_ptr = mem_ptr;
-         ha->ioremap_ptr = ioremap_ptr;
-         ha->host_num = ips_next_controller;
-         ha->revision_id = revision_id;
-         ha->slot_num = PCI_SLOT(dev[i]->devfn);
-         ha->device_id = deviceID[i];
-         ha->subdevice_id = subdevice_id;
-         ha->pcidev = dev[i];
+         continue;
+      }
 
-         /*
-          * Setup Functions
-          */
-         if (IPS_IS_MORPHEUS(ha)) {
-            /* morpheus */
-            ha->func.isintr = ips_isintr_morpheus;
-            ha->func.isinit = ips_isinit_morpheus;
-            ha->func.issue = ips_issue_i2o_memio;
-            ha->func.init = ips_init_morpheus;
-            ha->func.statupd = ips_statupd_morpheus;
-            ha->func.reset = ips_reset_morpheus;
-            ha->func.intr = ips_intr_morpheus;
-            ha->func.enableint = ips_enable_int_morpheus;
-         } else if (IPS_USE_MEMIO(ha)) {
-            /* copperhead w/MEMIO */
-            ha->func.isintr = ips_isintr_copperhead_memio;
-            ha->func.isinit = ips_isinit_copperhead_memio;
-            ha->func.init = ips_init_copperhead_memio;
-            ha->func.statupd = ips_statupd_copperhead_memio;
-            ha->func.statinit = ips_statinit_memio;
-            ha->func.reset = ips_reset_copperhead_memio;
-            ha->func.intr = ips_intr_copperhead;
-            ha->func.erasebios = ips_erase_bios_memio;
-            ha->func.programbios = ips_program_bios_memio;
-            ha->func.verifybios = ips_verify_bios_memio;
-            ha->func.enableint = ips_enable_int_copperhead_memio;
+      ha->subsys = kmalloc(sizeof(IPS_SUBSYS), GFP_KERNEL);
 
-            if (IPS_USE_I2O_DELIVER(ha))
-               ha->func.issue = ips_issue_i2o_memio;
-            else
-               ha->func.issue = ips_issue_copperhead_memio;
-         } else {
-            /* copperhead */
-            ha->func.isintr = ips_isintr_copperhead;
-            ha->func.isinit = ips_isinit_copperhead;
-            ha->func.init = ips_init_copperhead;
-            ha->func.statupd = ips_statupd_copperhead;
-            ha->func.statinit = ips_statinit;
-            ha->func.reset = ips_reset_copperhead;
-            ha->func.intr = ips_intr_copperhead;
-            ha->func.erasebios = ips_erase_bios;
-            ha->func.programbios = ips_program_bios;
-            ha->func.verifybios = ips_verify_bios;
-            ha->func.enableint = ips_enable_int_copperhead;
+      if (!ha->subsys) {
+         printk(KERN_WARNING "(%s%d) Unable to allocate host subsystem structure - skipping controller\n",
+                ips_name, ips_next_controller);
+         ips_abort_init(ha, sh, ips_next_controller);
+         ips_next_controller++;
+         ips_num_controllers--;
 
-            if (IPS_USE_I2O_DELIVER(ha))
-               ha->func.issue = ips_issue_i2o;
-            else
-               ha->func.issue = ips_issue_copperhead;
-         }
-            
-         /* If Morpheus appears dead, reset it */
-         if ( IPS_IS_MORPHEUS( ha ) ) {
-             IsDead = readl( ha->mem_ptr + IPS_REG_I960_MSG1 );
-             if ( IsDead == 0xDEADBEEF ) {
-                 ips_reset_morpheus( ha );
-             }
-         }
+         continue;
+      }
 
-         /*
-          * Initialize the card if it isn't already
-          */
+      for (count = PAGE_SIZE, ha->ioctl_order = 0;
+           count < ips_ioctlsize;
+           ha->ioctl_order++, count <<= 1);
+
+      ha->ioctl_data = (char *) __get_free_pages(GFP_KERNEL, ha->ioctl_order);
+      ha->ioctl_datasize = count;
+
+      if (!ha->ioctl_data) {
+         printk(KERN_WARNING "(%s%d) Unable to allocate ioctl data\n",
+                ips_name, ips_next_controller);
 
-         if (!(*ha->func.isinit)(ha)) {
-            if (!(*ha->func.init)(ha)) {
-               /*
-                * Initialization failed
-                */
-               printk(KERN_WARNING "(%s%d) unable to initialize controller - skipping controller\n",
-                      ips_name, ips_next_controller);
+         ha->ioctl_data = NULL;
+         ha->ioctl_order = 0;
+         ha->ioctl_datasize = 0;
+      }
 
-               ha->active = 0;
-               ips_free(ha);
-               scsi_unregister(sh);
-               ips_ha[ips_next_controller] = 0;
-               ips_sh[ips_next_controller] = 0;
-               ips_next_controller++;
-               ips_num_controllers--;
+      /* Store away needed values for later use */
+      sh->io_port = io_addr;
+      sh->n_io_port = io_addr ? 255 : 0;
+      sh->unique_id = (io_addr) ? io_addr : mem_addr;
+      sh->irq = irq;
+      sh->select_queue_depths = ips_select_queue_depth;
+      sh->sg_tablesize = sh->hostt->sg_tablesize;
+      sh->can_queue = sh->hostt->can_queue;
+      sh->cmd_per_lun = sh->hostt->cmd_per_lun;
+      sh->unchecked_isa_dma = sh->hostt->unchecked_isa_dma;
+      sh->use_clustering = sh->hostt->use_clustering;
+
+      sh->wish_block = FALSE;
+
+      /* Store info in HA structure */
+      ha->irq = irq;
+      ha->io_addr = io_addr;
+      ha->io_len = io_len;
+      ha->mem_addr = mem_addr;
+      ha->mem_len = mem_len;
+      ha->mem_ptr = mem_ptr;
+      ha->ioremap_ptr = ioremap_ptr;
+      ha->host_num = ips_next_controller;
+      ha->revision_id = revision_id;
+      ha->slot_num = PCI_SLOT(dev[i]->devfn);
+      ha->device_id = dev[i]->device;
+      ha->subdevice_id = subdevice_id;
+      ha->pcidev = dev[i];
 
-               continue;
-            }
-         }
+      /*
+       * Setup Functions
+       */
+      ips_setup_funclist(ha);
+            
+      /* If Morpheus appears dead, reset it */
+      if ( ( IPS_IS_MORPHEUS( ha ) ) || ( IPS_IS_MARCO( ha ) ) ) {
+          IsDead = readl( ha->mem_ptr + IPS_REG_I960_MSG1 );
+          if ( IsDead == 0xDEADBEEF ) {
+              ips_reset_morpheus( ha );
+          }
+      }
 
-         /* install the interrupt handler */
-         if (request_irq(irq, do_ipsintr, SA_SHIRQ, ips_name, ha)) {
-            printk(KERN_WARNING "(%s%d) unable to install interrupt handler - skipping controller\n",
-                   ips_name, ips_next_controller);
+      /*
+       * Initialize the card if it isn't already
+       */
 
-            ha->active = 0;
-            ips_free(ha);
-            scsi_unregister(sh);
-            ips_ha[ips_next_controller] = 0;
-            ips_sh[ips_next_controller] = 0;
+      if (!(*ha->func.isinit)(ha)) {
+         if (!(*ha->func.init)(ha)) {
+            /*
+             * Initialization failed
+             */
+            printk(KERN_WARNING "(%s%d) unable to initialize controller - skipping controller\n",
+                   ips_name, ips_next_controller);
+            ips_abort_init(ha, sh, ips_next_controller);
             ips_next_controller++;
             ips_num_controllers--;
 
             continue;
          }
+      }
 
-         /*
-          * Allocate a temporary SCB for initialization
-          */
-         ha->max_cmds = 1;
-         if (!ips_allocatescbs(ha)) {
-            /* couldn't allocate a temp SCB */
-            printk(KERN_WARNING "(%s%d) unable to allocate CCBs - skipping contoller\n",
-                   ips_name, ips_next_controller);
-
-            ha->active = 0;
-            ips_free(ha);
-            scsi_unregister(sh);
-            ips_ha[ips_next_controller] = 0;
-            ips_sh[ips_next_controller] = 0;
-            free_irq(ha->irq, ha);
-            ips_next_controller++;
-            ips_num_controllers--;
+      /* install the interrupt handler */
+      if (request_irq(irq, do_ipsintr, SA_SHIRQ, ips_name, ha)) {
+         printk(KERN_WARNING "(%s%d) unable to install interrupt handler - skipping controller\n",
+                ips_name, ips_next_controller);
+         ips_abort_init(ha, sh, ips_next_controller);
+         ips_next_controller++;
+         ips_num_controllers--;
 
-            continue;
-         }
+         continue;
+      }
 
+      /*
+       * Allocate a temporary SCB for initialization
+       */
+      ha->max_cmds = 1;
+      if (!ips_allocatescbs(ha)) {
+         /* couldn't allocate a temp SCB */
+         printk(KERN_WARNING "(%s%d) unable to allocate CCBs - skipping contoller\n",
+                ips_name, ips_next_controller);
+         free_irq(ha->irq, ha);
+         ips_abort_init(ha, sh, ips_next_controller);
          ips_next_controller++;
-      } while ((dev[i] = pci_find_device(IPS_VENDORID, deviceID[i], dev[i])));
+         ips_num_controllers--;
+
+         continue;
+      }
+
+      ips_next_controller++;
    }
 
    /*
@@ -1252,12 +1320,64 @@
       register_reboot_notifier(&ips_notifier);
 
    return (ips_num_controllers);
+}
+#endif
 
-#else
+/****************************************************************************/
+/*   configure the function pointers to use the functions that will work    */
+/*   with the found version of the adapter                                  */
+/****************************************************************************/
+static void ips_setup_funclist(ips_ha_t *ha){
 
-   /* No PCI -- No ServeRAID */
-   return (0);
-#endif /* CONFIG_PCI */
+   /*                                
+    * Setup Functions
+    */
+   if (IPS_IS_MORPHEUS(ha) || IPS_IS_MARCO(ha)) {
+      /* morpheus / marco / sebring */
+      ha->func.isintr = ips_isintr_morpheus;
+      ha->func.isinit = ips_isinit_morpheus;
+      ha->func.issue = ips_issue_i2o_memio;
+      ha->func.init = ips_init_morpheus;
+      ha->func.statupd = ips_statupd_morpheus;
+      ha->func.reset = ips_reset_morpheus;
+      ha->func.intr = ips_intr_morpheus;
+      ha->func.enableint = ips_enable_int_morpheus;
+   } else if (IPS_USE_MEMIO(ha)) {
+      /* copperhead w/MEMIO */
+      ha->func.isintr = ips_isintr_copperhead_memio;
+      ha->func.isinit = ips_isinit_copperhead_memio;
+      ha->func.init = ips_init_copperhead_memio;
+      ha->func.statupd = ips_statupd_copperhead_memio;
+      ha->func.statinit = ips_statinit_memio;
+      ha->func.reset = ips_reset_copperhead_memio;
+      ha->func.intr = ips_intr_copperhead;
+      ha->func.erasebios = ips_erase_bios_memio;
+      ha->func.programbios = ips_program_bios_memio;
+      ha->func.verifybios = ips_verify_bios_memio;
+      ha->func.enableint = ips_enable_int_copperhead_memio;
+      if (IPS_USE_I2O_DELIVER(ha))
+         ha->func.issue = ips_issue_i2o_memio;
+      else
+         ha->func.issue = ips_issue_copperhead_memio;
+   } else {
+      /* copperhead */
+      ha->func.isintr = ips_isintr_copperhead;
+      ha->func.isinit = ips_isinit_copperhead;
+      ha->func.init = ips_init_copperhead;
+      ha->func.statupd = ips_statupd_copperhead;
+      ha->func.statinit = ips_statinit;
+      ha->func.reset = ips_reset_copperhead;
+      ha->func.intr = ips_intr_copperhead;
+      ha->func.erasebios = ips_erase_bios;
+      ha->func.programbios = ips_program_bios;
+      ha->func.verifybios = ips_verify_bios;
+      ha->func.enableint = ips_enable_int_copperhead;
+
+      if (IPS_USE_I2O_DELIVER(ha))
+         ha->func.issue = ips_issue_i2o;
+      else
+         ha->func.issue = ips_issue_copperhead;
+   }
 }
 
 /****************************************************************************/
@@ -1309,13 +1429,15 @@
    scb->cmd.flush_cache.reserved3 = 0;
    scb->cmd.flush_cache.reserved4 = 0;
 
-   printk(KERN_NOTICE "(%s%d) Flushing Cache.\n", ips_name, ha->host_num);
+   if (InitState != 0)    /* If Not just Searching for the Adapter Order Table */
+      printk(KERN_NOTICE "(%s%d) Flushing Cache.\n", ips_name, ha->host_num);
 
    /* send command */
    if (ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_ON) == IPS_FAILURE)
       printk(KERN_NOTICE "(%s%d) Incomplete Flush.\n", ips_name, ha->host_num);
 
-   printk(KERN_NOTICE "(%s%d) Flushing Complete.\n", ips_name, ha->host_num);
+   if (InitState != 0)    /* If Not just Searching for the Adapter Order Table */
+      printk(KERN_NOTICE "(%s%d) Flushing Complete.\n", ips_name, ha->host_num);
 
    ips_sh[i] = NULL;
    ips_ha[i] = NULL;
@@ -1332,12 +1454,14 @@
 
    scsi_unregister(sh);
 
-   ips_released_controllers++;
-
-   if (ips_num_controllers == ips_released_controllers){
-      unregister_reboot_notifier(&ips_notifier);
-      pci_unregister_driver(&ips_pci_driver);
+   if (InitState != 0) {
+      ips_released_controllers++;
+      if (ips_num_controllers == ips_released_controllers){
+         unregister_reboot_notifier(&ips_notifier);
+         pci_unregister_driver(ha->pcidev->driver);
+      }
    }
+
    return (FALSE);
 }
 
@@ -1404,12 +1528,13 @@
 /* Routine Description:                                                     */
 /*                                                                          */
 /*   Abort a command (using the new error code stuff)                       */
-/*                                                                          */
+/* Note: this routine is called under the io_request_lock                   */
 /****************************************************************************/
 int
 ips_eh_abort(Scsi_Cmnd *SC) {
    ips_ha_t         *ha;
    ips_copp_wait_item_t *item;
+   int ret;
 
    METHOD_TRACE("ips_eh_abort", 1);
 
@@ -1431,36 +1556,25 @@
       return (FAILED);
    }
 
-   if (test_and_set_bit(IPS_IN_ABORT, &ha->flags))
-      return (FAILED);
-
    /* See if the command is on the copp queue */
-   IPS_QUEUE_LOCK(&ha->copp_waitlist);
    item = ha->copp_waitlist.head;
    while ((item) && (item->scsi_cmd != SC))
       item = item->next;
-   IPS_QUEUE_UNLOCK(&ha->copp_waitlist);
 
    if (item) {
       /* Found it */
       ips_removeq_copp(&ha->copp_waitlist, item);
-      clear_bit(IPS_IN_ABORT, &ha->flags);
-
-      return (SUCCESS);
-   }
+      ret = (SUCCESS);
 
    /* See if the command is on the wait queue */
-   if (ips_removeq_wait(&ha->scb_waitlist, SC)) {
+   } else if (ips_removeq_wait(&ha->scb_waitlist, SC)) {
       /* command not sent yet */
-      clear_bit(IPS_IN_ABORT, &ha->flags);
-
-      return (SUCCESS);
+      ret = (SUCCESS);
    } else {
       /* command must have already been sent */
-      clear_bit(IPS_IN_ABORT, &ha->flags);
-
-      return (FAILED);
+      ret = (FAILED);
    }
+   return ret;
 }
 
 /****************************************************************************/
@@ -1481,7 +1595,6 @@
    ips_ha_t             *ha;
    ips_scb_t            *scb;
    ips_copp_wait_item_t *item;
-   unsigned long         cpu_flags;
 
    METHOD_TRACE("ips_eh_reset", 1);
 
@@ -1506,36 +1619,27 @@
    if (!ha->active)
       return (FAILED);
 
-   if (test_and_set_bit(IPS_IN_RESET, &ha->flags))
-      return (FAILED);
-
    /* See if the command is on the copp queue */
-   IPS_QUEUE_LOCK(&ha->copp_waitlist);
    item = ha->copp_waitlist.head;
    while ((item) && (item->scsi_cmd != SC))
       item = item->next;
-   IPS_QUEUE_UNLOCK(&ha->copp_waitlist);
 
    if (item) {
       /* Found it */
       ips_removeq_copp(&ha->copp_waitlist, item);
-      clear_bit(IPS_IN_RESET, &ha->flags);
-
       return (SUCCESS);
    }
 
    /* See if the command is on the wait queue */
    if (ips_removeq_wait(&ha->scb_waitlist, SC)) {
       /* command not sent yet */
-      clear_bit(IPS_IN_RESET, &ha->flags);
-
       return (SUCCESS);
    }
 
    /* An explanation for the casual observer:                              */
    /* Part of the function of a RAID controller is automatic error         */
    /* detection and recovery.  As such, the only problem that physically   */
-   /* resetting a ServeRAID adapter will ever fix is when, for some reason,*/
+   /* resetting an adapter will ever fix is when, for some reason,         */
    /* the driver is not successfully communicating with the adapter.       */
    /* Therefore, we will attempt to flush this adapter.  If that succeeds, */
    /* then there's no real purpose in a physical reset. This will complete */
@@ -1562,13 +1666,12 @@
       ret = ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_IORL);
       if (ret == IPS_SUCCESS) {
          printk(KERN_NOTICE "(%s%d) Reset Request - Flushed Cache\n", ips_name, ha->host_num);
-         clear_bit(IPS_IN_RESET, &ha->flags);
          return (SUCCESS);
          }
    }
 
    /* Either we can't communicate with the adapter or it's an IOCTL request */
-   /* from a ServeRAID utility.  A physical reset is needed at this point.  */
+   /* from a utility.  A physical reset is needed at this point.            */
 
    ha->ioctl_reset = 0;             /* Reset the IOCTL Requested Reset Flag */
 
@@ -1607,8 +1710,6 @@
       }
 
       ha->active = FALSE;
-      clear_bit(IPS_IN_RESET, &ha->flags);
-
       return (FAILED);
    }
 
@@ -1639,8 +1740,6 @@
       }
 
       ha->active = FALSE;
-      clear_bit(IPS_IN_RESET, &ha->flags);
-
       return (FAILED);
    }
 
@@ -1649,10 +1748,8 @@
       struct timeval tv;
 
       do_gettimeofday(&tv);
-      IPS_HA_LOCK(cpu_flags);
       ha->last_ffdc = tv.tv_sec;
       ha->reset_count++;
-      IPS_HA_UNLOCK(cpu_flags);
       ips_ffdc_reset(ha, IPS_INTR_IORL);
    }
 
@@ -1671,25 +1768,11 @@
       ha->dcdb_active[i-1] = 0;
 
    /* Reset the number of active IOCTLs */
-   IPS_HA_LOCK(cpu_flags);
    ha->num_ioctl = 0;
-   IPS_HA_UNLOCK(cpu_flags);
-
-   clear_bit(IPS_IN_RESET, &ha->flags);
 
-   if (!test_bit(IPS_IN_INTR, &ha->flags)) {
-      /*
-       * Only execute the next command when
-       * we are not being called from the
-       * interrupt handler.  The interrupt
-       * handler wants to do this and since
-       * interrupts are turned off here....
-       */
-      ips_next(ha, IPS_INTR_IORL);
-   }
+   ips_next(ha, IPS_INTR_IORL);
 
    return (SUCCESS);
-
 #endif /* NO_IPS_RESET */
 
 }
@@ -1709,7 +1792,6 @@
 int
 ips_queue(Scsi_Cmnd *SC, void (*done) (Scsi_Cmnd *)) {
    ips_ha_t         *ha;
-   unsigned long     cpu_flags;
    ips_passthru_t   *pt;                                             
 
    METHOD_TRACE("ips_queue", 1);
@@ -1723,28 +1805,17 @@
       return (DID_ERROR);
 
    if (ips_is_passthru(SC)) {
-      IPS_QUEUE_LOCK(&ha->copp_waitlist);
       if (ha->copp_waitlist.count == IPS_MAX_IOCTL_QUEUE) {
-         IPS_QUEUE_UNLOCK(&ha->copp_waitlist);
          SC->result = DID_BUS_BUSY << 16;
          done(SC);
 
          return (0);
-      } else {
-         IPS_QUEUE_UNLOCK(&ha->copp_waitlist);
-      }
-   } else {
-      IPS_QUEUE_LOCK(&ha->scb_waitlist);
-      if (ha->scb_waitlist.count == IPS_MAX_QUEUE) {
-         IPS_QUEUE_UNLOCK(&ha->scb_waitlist);
-         SC->result = DID_BUS_BUSY << 16;
-         done(SC);
-
-         return (0);
-      } else {
-         IPS_QUEUE_UNLOCK(&ha->scb_waitlist);
       }
+   } else if (ha->scb_waitlist.count == IPS_MAX_QUEUE) {
+      SC->result = DID_BUS_BUSY << 16;
+      done(SC);
 
+      return (0);
    }
 
    SC->scsi_done = done;
@@ -1769,7 +1840,7 @@
 
       ips_copp_wait_item_t *scratch;
       
-      /* A Reset IOCTL is only sent by the ServeRAID boot CD in extreme cases. */
+      /* A Reset IOCTL is only sent by the boot CD in extreme cases.           */
       /* There can never be any system activity ( network or disk ), but check */
       /* anyway just as a good practice.                                       */
       pt = (ips_passthru_t *) SC->request_buffer;                                
@@ -1798,27 +1869,15 @@
       }
 
       scratch->scsi_cmd = SC;
-      sema_init(&ha->ioctl_sem, 0);
-      scratch->sem = &ha->ioctl_sem;
       scratch->next = NULL;
 
       ips_putq_copp_tail(&ha->copp_waitlist, scratch);
    }
-   else
+   else {
       ips_putq_wait_tail(&ha->scb_waitlist, SC);
-
-   if(ha->scb_waitlist.count + ha->scb_activelist.count > 32)
-         mod_timer(&SC->eh_timeout, jiffies + 120 * HZ);
-
-   IPS_HA_LOCK(cpu_flags);
-   if ((!test_bit(IPS_IN_INTR, &ha->flags)) &&
-       (!test_bit(IPS_IN_ABORT, &ha->flags)) &&
-       (!test_bit(IPS_IN_RESET, &ha->flags))) {
-      IPS_HA_UNLOCK(cpu_flags);
-      ips_next(ha, IPS_INTR_IORL);
-   } else {
-      IPS_HA_UNLOCK(cpu_flags);
    }
+
+   ips_next(ha, IPS_INTR_IORL);
    
    /* If We were using the CD Boot Flash Buffer, Restore the Old Values */
    if ( ips_FlashData == ha->ioctl_data ) {                               
@@ -1938,33 +1997,24 @@
 do_ipsintr(int irq, void *dev_id, struct pt_regs *regs) {
    ips_ha_t         *ha;
    unsigned long     cpu_flags;
+   struct Scsi_Host *host;
 
    METHOD_TRACE("do_ipsintr", 2);
 
    ha = (ips_ha_t *) dev_id;
    if (!ha) 
       return;
-   
-   spin_lock_irqsave(&io_request_lock, cpu_flags);
-
-   if (test_and_set_bit(IPS_IN_INTR, &ha->flags)) {
-      spin_unlock_irqrestore(&io_request_lock, cpu_flags);
-
-      return ;
-   }
+   host = ips_sh[ha->host_num];
+   IPS_LOCK_SAVE(host->host_lock, cpu_flags);
 
    if (!ha->active) {
-      clear_bit(IPS_IN_INTR, &ha->flags);
-      spin_unlock_irqrestore(&io_request_lock, cpu_flags);
-
+      IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
       return;
    }
 
    (*ha->func.intr)(ha);
 
-   clear_bit(IPS_IN_INTR, &ha->flags);
-
-   spin_unlock_irqrestore(&io_request_lock, cpu_flags);
+   IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
 
    /* start the next command */
    ips_next(ha, IPS_INTR_ON);
@@ -1987,7 +2037,6 @@
    ips_scb_t        *scb;
    IPS_STATUS        cstatus;
    int               intrstatus;
-   unsigned long     cpu_flags;
 
    METHOD_TRACE("ips_intr", 2);
 
@@ -1997,15 +2046,12 @@
    if (!ha->active)
       return;
 
-   IPS_HA_LOCK(cpu_flags);
-
    intrstatus = (*ha->func.isintr)(ha);
 
    if (!intrstatus) {
       /*
        * Unexpected/Shared interrupt
        */
-      IPS_HA_UNLOCK(cpu_flags);
 
       return;
    }
@@ -2032,12 +2078,8 @@
        * use the callback function to finish things up
        * NOTE: interrupts are OFF for this
        */
-      IPS_HA_UNLOCK(cpu_flags);
       (*scb->callback) (ha, scb);
-      IPS_HA_LOCK(cpu_flags);
    } /* end while */
-
-   IPS_HA_UNLOCK(cpu_flags);
 }
 
 /****************************************************************************/
@@ -2057,7 +2099,6 @@
    ips_scb_t        *scb;
    IPS_STATUS        cstatus;
    int               intrstatus;
-   unsigned long     cpu_flags;
 
    METHOD_TRACE("ips_intr_morpheus", 2);
 
@@ -2067,15 +2108,12 @@
    if (!ha->active)
       return;
 
-   IPS_HA_LOCK(cpu_flags);
-
    intrstatus = (*ha->func.isintr)(ha);
 
    if (!intrstatus) {
       /*
        * Unexpected/Shared interrupt
        */
-      IPS_HA_UNLOCK(cpu_flags);
 
       return;
    }
@@ -2108,12 +2146,8 @@
        * use the callback function to finish things up
        * NOTE: interrupts are OFF for this
        */
-      IPS_HA_UNLOCK(cpu_flags);
       (*scb->callback) (ha, scb);
-      IPS_HA_LOCK(cpu_flags);
    } /* end while */
-
-   IPS_HA_UNLOCK(cpu_flags);
 }
 
 /****************************************************************************/
@@ -2231,7 +2265,7 @@
          return 1;
       else if(SC->use_sg){
          struct scatterlist *sg = SC->request_buffer;
-         char *buffer = sg[0].address;
+         char *buffer = IPS_SG_ADDRESS(sg);
          if(buffer && buffer[0] == 'C' && buffer[1] == 'O' && 
             buffer[2] == 'P' && buffer[3] == 'P')
             return 1;
@@ -2288,7 +2322,7 @@
             ha->ioctl_order = order;
             ha->ioctl_datasize = count;
          } else {
-             pt = (ips_passthru_t*)sg[0].address;
+             pt = (ips_passthru_t*)IPS_SG_ADDRESS(sg);
              pt->BasicStatus = 0x0B;
              pt->ExtendedStatus = 0x00;
              SC->result = DID_ERROR << 16;
@@ -2298,7 +2332,7 @@
       ha->ioctl_datasize = length;
       length = 0;
       for(i = 0; i < SC->use_sg; i++){
-         memcpy(&ha->ioctl_data[length], sg[i].address, sg[i].length);
+         memcpy(&ha->ioctl_data[length], IPS_SG_ADDRESS(&sg[i]), sg[i].length);
          length += sg[i].length;
       }
       pt = (ips_passthru_t *)ha->ioctl_data;
@@ -2327,13 +2361,6 @@
     * packet we received from the sg driver. In this
     * case the CmdBSize field of the pt structure is
     * used for the size of the buffer.
-    *
-    * IF the scsi op_code == 0x81 then we assume that
-    * we will need our own buffer and we will copy the
-    * data to/from the user buffer passed in the scsi
-    * command.  The data address resides at offset 4
-    * in the scsi command.  The length of the data resides
-    * at offset 8 in the scsi command.
     */
 
    switch (pt->CoppCmd) {
@@ -2499,6 +2526,7 @@
 static int
 ips_flash_firmware(ips_ha_t * ha, ips_passthru_t *pt, ips_scb_t *scb){
    IPS_SG_LIST *sg_list;
+   uint32_t cmd_busaddr;
 
    if(pt->CoppCP.cmd.flashfw.type == IPS_FW_IMAGE &&
       pt->CoppCP.cmd.flashfw.direction == IPS_WRITE_FW ){
@@ -2513,11 +2541,12 @@
    }
    /* Save the S/G list pointer so it doesn't get clobbered */
    sg_list = scb->sg_list;
+   cmd_busaddr = scb->scb_busaddr;
    /* copy in the CP */
    memcpy(&scb->cmd, &pt->CoppCP.cmd, sizeof(IPS_IOCTL_CMD));
    /* FIX stuff that might be wrong */
    scb->sg_list = sg_list;
-   scb->scb_busaddr = VIRT_TO_BUS(scb);
+   scb->scb_busaddr = cmd_busaddr;
    scb->bus = scb->scsi_cmd->channel;
    scb->target_id = scb->scsi_cmd->target;
    scb->lun = scb->scsi_cmd->lun;
@@ -2527,8 +2556,13 @@
    scb->op_code = 0;
    scb->callback = ipsintr_done;
    scb->timeout = ips_cmd_timeout;
+
+   scb->data_len = ha->flash_datasize;
+   scb->data_busaddr = pci_map_single(ha->pcidev, ha->flash_data, scb->data_len,
+                                      IPS_DMA_DIR(scb));
+   scb->flags |= IPS_SCB_MAP_SINGLE;
    scb->cmd.flashfw.command_id = IPS_COMMAND_ID(ha, scb);
-   scb->cmd.flashfw.buffer_addr = VIRT_TO_BUS(ha->flash_data);
+   scb->cmd.flashfw.buffer_addr = scb->data_busaddr;
    if (pt->TimeOut)
       scb->timeout = pt->TimeOut;
    scb->scsi_cmd->result = DID_OK <<16;
@@ -2561,6 +2595,7 @@
 static int
 ips_usrcmd(ips_ha_t *ha, ips_passthru_t *pt, ips_scb_t *scb) {
    IPS_SG_LIST *sg_list;
+   uint32_t cmd_busaddr;
 
    METHOD_TRACE("ips_usrcmd", 1);
 
@@ -2569,14 +2604,14 @@
 
    /* Save the S/G list pointer so it doesn't get clobbered */
    sg_list = scb->sg_list;
-
+   cmd_busaddr = scb->scb_busaddr;
    /* copy in the CP */
    memcpy(&scb->cmd, &pt->CoppCP.cmd, sizeof(IPS_IOCTL_CMD));
    memcpy(&scb->dcdb, &pt->CoppCP.dcdb, sizeof(IPS_DCDB_TABLE));
 
    /* FIX stuff that might be wrong */
    scb->sg_list = sg_list;
-   scb->scb_busaddr = VIRT_TO_BUS(scb);
+   scb->scb_busaddr = cmd_busaddr;
    scb->bus = scb->scsi_cmd->channel;
    scb->target_id = scb->scsi_cmd->target;
    scb->lun = scb->scsi_cmd->lun;
@@ -2595,16 +2630,31 @@
       return (0);
 
    if (pt->CmdBSize) {
-      if(!scb->scsi_cmd->use_sg)
-         scb->data_busaddr = VIRT_TO_BUS(scb->scsi_cmd->request_buffer + sizeof(ips_passthru_t));
-      else
-         scb->data_busaddr = VIRT_TO_BUS(ha->ioctl_data + sizeof(ips_passthru_t));
+      if(!scb->scsi_cmd->use_sg){
+         scb->data_len = pt->CmdBSize;
+         scb->data_busaddr = pci_map_single(ha->pcidev,
+                                            scb->scsi_cmd->request_buffer +
+                                            sizeof(ips_passthru_t),
+                                            pt->CmdBSize,
+                                            IPS_DMA_DIR(scb));
+         scb->flags |= IPS_SCB_MAP_SINGLE;
+      } else {
+         scb->data_len = pt->CmdBSize;
+         scb->data_busaddr = pci_map_single(ha->pcidev,
+                                            ha->ioctl_data +
+                                            sizeof(ips_passthru_t),
+                                            pt->CmdBSize,
+                                            IPS_DMA_DIR(scb));
+         scb->flags |= IPS_SCB_MAP_SINGLE;
+      }
    } else {
       scb->data_busaddr = 0L;
    }
 
    if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB)
-      scb->cmd.dcdb.dcdb_address = cpu_to_le32(VIRT_TO_BUS(&scb->dcdb));
+      scb->cmd.dcdb.dcdb_address = cpu_to_le32(scb->scb_busaddr +
+                                          (unsigned long)&scb->dcdb -
+                                          (unsigned long)scb);
 
    if (pt->CmdBSize) {
       if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB)
@@ -2675,7 +2725,7 @@
       int i, length = 0;
       struct scatterlist *sg = scb->scsi_cmd->request_buffer;
       for(i = 0; i < scb->scsi_cmd->use_sg; i++){
-         memcpy(sg[i].address, &ha->ioctl_data[length], sg[i].length);
+         memcpy(IPS_SG_ADDRESS(&sg[i]), &ha->ioctl_data[length], sg[i].length);
          length += sg[i].length;
       }
    }
@@ -2885,6 +2935,17 @@
       }
 
       break;
+
+   case IPS_DEVICEID_MARCO:
+      switch (ha->subdevice_id) {
+      case IPS_SUBDEVICEID_6M:
+          ha->ad_type = IPS_ADTYPE_SERVERAID6M;
+          break;
+      case IPS_SUBDEVICEID_6I:
+          ha->ad_type = IPS_ADTYPE_SERVERAID6I;
+          break;
+      }
+      break;
    }
 }
 
@@ -3013,9 +3074,13 @@
       scb->cmd.flashfw.type = 1;
       scb->cmd.flashfw.direction = 0;
       scb->cmd.flashfw.count = cpu_to_le32(0x800);
-      scb->cmd.flashfw.buffer_addr = cpu_to_le32(VIRT_TO_BUS(buffer));
       scb->cmd.flashfw.total_packets = 1;
       scb->cmd.flashfw.packet_num = 0;
+      scb->data_len = 0x1000;
+      scb->data_busaddr = pci_map_single(ha->pcidev, buffer, scb->data_len,
+                                         IPS_DMA_DIR(scb));
+      scb->cmd.flashfw.buffer_addr = scb->data_busaddr;
+      scb->flags |= IPS_SCB_MAP_SINGLE;
 
       /* issue the command */
       if (((ret = ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) ||
@@ -3113,6 +3178,10 @@
       return (0);
    }
 
+   /* If there are Logical Drives and a Reset Occurred, then an EraseStripeLock is Needed */
+   if ( (ha->conf->ucLogDriveCount > 0) && (ha->requires_esl == 1) ) 
+      ips_clear_adapter(ha, IPS_INTR_IORL);
+   
    /* set limits on SID, LUN, BUS */
    ha->ntargets = IPS_MAX_TARGETS + 1;
    ha->nlun = 1;
@@ -3198,39 +3267,31 @@
    Scsi_Cmnd            *q;
    ips_copp_wait_item_t *item;
    int                   ret;
-   unsigned long         cpu_flags;
-   unsigned long         cpu_flags2 = 0;
-
+   unsigned long         cpu_flags = 0;
+   struct Scsi_Host *host;
    METHOD_TRACE("ips_next", 1);
 
    if (!ha)
       return ;
-
+   host = ips_sh[ha->host_num];
    /*
     * Block access to the queue function so
     * this command won't time out
     */
-   if (intr == IPS_INTR_ON) 
-       spin_lock_irqsave(&io_request_lock, cpu_flags2);
+   if(intr == IPS_INTR_ON)
+      IPS_LOCK_SAVE(host->host_lock, cpu_flags);
    
    if ((ha->subsys->param[3] & 0x300000)  && ( ha->scb_activelist.count == 0 )) {
       struct timeval tv;
 
       do_gettimeofday(&tv);
 
-      IPS_HA_LOCK(cpu_flags);
       if (tv.tv_sec - ha->last_ffdc > IPS_SECS_8HOURS) {
          ha->last_ffdc = tv.tv_sec;
-         IPS_HA_UNLOCK(cpu_flags);
          ips_ffdc_time(ha);
-      } else {
-         IPS_HA_UNLOCK(cpu_flags);
       }
    }
 
-   if (intr == IPS_INTR_ON)
-       spin_unlock_irqrestore(&io_request_lock, cpu_flags2);
-
    /*
     * Send passthru commands
     * These have priority over normal I/O
@@ -3238,22 +3299,21 @@
     * since we limit the number that can be active
     * on the card at any one time
     */
-   IPS_HA_LOCK(cpu_flags);
-   IPS_QUEUE_LOCK(&ha->copp_waitlist);
    while ((ha->num_ioctl < IPS_MAX_IOCTL) &&
           (ha->copp_waitlist.head) &&
           (scb = ips_getscb(ha))) {
 
-      IPS_QUEUE_UNLOCK(&ha->copp_waitlist);
       item = ips_removeq_copp_head(&ha->copp_waitlist);
       ha->num_ioctl++;
-      IPS_HA_UNLOCK(cpu_flags);
+      if(intr == IPS_INTR_ON)
+         IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
       scb->scsi_cmd = item->scsi_cmd;
-      scb->sem = item->sem;
       kfree(item);
 
       ret = ips_make_passthru(ha, scb->scsi_cmd, scb, intr);
 
+      if(intr == IPS_INTR_ON)
+         IPS_LOCK_SAVE(host->host_lock, cpu_flags);
       switch (ret) {
       case IPS_FAILURE:
          if (scb->scsi_cmd) {
@@ -3276,8 +3336,6 @@
       } /* end case */
 
       if (ret != IPS_SUCCESS) {
-         IPS_HA_LOCK(cpu_flags);
-         IPS_QUEUE_LOCK(&ha->copp_waitlist);
          ha->num_ioctl--;
          continue;
      }
@@ -3304,20 +3362,14 @@
          break;
       } /* end case */
 
-      IPS_HA_LOCK(cpu_flags);
-      IPS_QUEUE_LOCK(&ha->copp_waitlist);
    }
 
-   IPS_QUEUE_UNLOCK(&ha->copp_waitlist);
-   IPS_HA_UNLOCK(cpu_flags);
 
    /*
     * Send "Normal" I/O commands
     */
-   IPS_HA_LOCK(cpu_flags);
-   IPS_QUEUE_LOCK(&ha->scb_waitlist);
+    
    p = ha->scb_waitlist.head;
-   IPS_QUEUE_UNLOCK(&ha->scb_waitlist);
    while ((p) && (scb = ips_getscb(ha))) {
       if ((p->channel > 0) && (ha->dcdb_active[p->channel-1] & (1 << p->target))) {
          ips_freescb(ha, scb);
@@ -3327,10 +3379,9 @@
 
       q = p;
       SC = ips_removeq_wait(&ha->scb_waitlist, q);
-      if (SC == NULL)                    /* Should never happen, but good to check anyway */
-         continue;
 
-      IPS_HA_UNLOCK(cpu_flags);          /* Unlock HA after command is taken off queue */
+      if(intr == IPS_INTR_ON)
+         IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags); /* Unlock HA after command is taken off queue */
 
       SC->result = DID_OK;
       SC->host_scribble = NULL;
@@ -3356,7 +3407,8 @@
          int                 i;
 
          sg = SC->request_buffer;
-         scb->sg_count = pci_map_sg(ha->pcidev, sg, SC->use_sg, PCI_DMA_BIDIRECTIONAL);
+         scb->sg_count = pci_map_sg(ha->pcidev, sg, SC->use_sg,
+                                    scsi_to_pci_dma_dir(SC->sc_data_direction));
          scb->flags |= IPS_SCB_MAP_SG;
          if (scb->sg_count == 1) {
             if (sg_dma_len(sg) > ha->max_xfer) {
@@ -3416,7 +3468,8 @@
 
             scb->dcdb.transfer_length = scb->data_len;
             scb->data_busaddr = pci_map_single(ha->pcidev, SC->request_buffer,
-                                               scb->data_len, PCI_DMA_BIDIRECTIONAL);
+                                               scb->data_len,
+                                               scsi_to_pci_dma_dir(SC->sc_data_direction));
             scb->flags |= IPS_SCB_MAP_SINGLE;
             scb->sg_len = 0;
          } else {
@@ -3437,13 +3490,15 @@
          scb->dcdb.cmd_attribute |= IPS_TRANSFER64K;
          scb->dcdb.transfer_length = 0;
       }
-
+      if(intr == IPS_INTR_ON)
+         IPS_LOCK_SAVE(host->host_lock, cpu_flags);
+      
       ret = ips_send_cmd(ha, scb);
 
-      if (ret == IPS_SUCCESS)
-         ips_putq_scb_head(&ha->scb_activelist, scb);
-
       switch(ret) {
+      case IPS_SUCCESS:
+         ips_putq_scb_head(&ha->scb_activelist, scb);
+         break;
       case IPS_FAILURE:
          if (scb->scsi_cmd) {
             scb->scsi_cmd->result = DID_ERROR << 16;
@@ -3470,10 +3525,10 @@
 
       p = (Scsi_Cmnd *) p->host_scribble;
 
-      IPS_HA_LOCK(cpu_flags);
    } /* end while */
 
-   IPS_HA_UNLOCK(cpu_flags);
+   if(intr == IPS_INTR_ON)
+      IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
 }
 
 /****************************************************************************/
@@ -3484,7 +3539,7 @@
 /*                                                                          */
 /*   Add an item to the head of the queue                                   */
 /*                                                                          */
-/* ASSUMED to be called from within a lock                                  */
+/* ASSUMED to be called from within the HA lock                             */
 /*                                                                          */
 /****************************************************************************/
 static inline void
@@ -3494,8 +3549,6 @@
    if (!item)
       return ;
 
-   IPS_QUEUE_LOCK(queue);
-
    item->q_next = queue->head;
    queue->head = item;
 
@@ -3503,8 +3556,6 @@
       queue->tail = item;
 
    queue->count++;
-
-   IPS_QUEUE_UNLOCK(queue);
 }
 
 /****************************************************************************/
@@ -3515,7 +3566,7 @@
 /*                                                                          */
 /*   Add an item to the tail of the queue                                   */
 /*                                                                          */
-/* ASSUMED to be called from within a lock                                  */
+/* ASSUMED to be called from within the HA lock                             */
 /*                                                                          */
 /****************************************************************************/
 static inline void
@@ -3525,8 +3576,6 @@
    if (!item)
       return ;
 
-   IPS_QUEUE_LOCK(queue);
-
    item->q_next = NULL;
 
    if (queue->tail)
@@ -3538,8 +3587,6 @@
       queue->head = item;
 
    queue->count++;
-
-   IPS_QUEUE_UNLOCK(queue);
 }
 
 /****************************************************************************/
@@ -3550,7 +3597,7 @@
 /*                                                                          */
 /*   Remove the head of the queue                                           */
 /*                                                                          */
-/* ASSUMED to be called from within a lock                                  */
+/* ASSUMED to be called from within the HA lock                             */
 /*                                                                          */
 /****************************************************************************/
 static inline ips_scb_t *
@@ -3559,13 +3606,9 @@
 
    METHOD_TRACE("ips_removeq_scb_head", 1);
 
-   IPS_QUEUE_LOCK(queue);
-
    item = queue->head;
 
    if (!item) {
-      IPS_QUEUE_UNLOCK(queue);
-
       return (NULL);
    }
 
@@ -3577,8 +3620,6 @@
 
    queue->count--;
 
-   IPS_QUEUE_UNLOCK(queue);
-
    return (item);
 }
 
@@ -3590,7 +3631,7 @@
 /*                                                                          */
 /*   Remove an item from a queue                                            */
 /*                                                                          */
-/* ASSUMED to be called from within a lock                                  */
+/* ASSUMED to be called from within the HA lock                             */
 /*                                                                          */
 /****************************************************************************/
 static inline ips_scb_t *
@@ -3602,11 +3643,7 @@
    if (!item)
       return (NULL);
 
-   IPS_QUEUE_LOCK(queue);
-
    if (item == queue->head) {
-      IPS_QUEUE_UNLOCK(queue);
-
       return (ips_removeq_scb_head(queue));
    }
 
@@ -3625,13 +3662,9 @@
       item->q_next = NULL;
       queue->count--;
 
-      IPS_QUEUE_UNLOCK(queue);
-
       return (item);
    }
 
-   IPS_QUEUE_UNLOCK(queue);
-
    return (NULL);
 }
 
@@ -3643,7 +3676,7 @@
 /*                                                                          */
 /*   Add an item to the head of the queue                                   */
 /*                                                                          */
-/* ASSUMED to be called from within a lock                                  */
+/* ASSUMED to be called from within the HA lock                             */
 /*                                                                          */
 /****************************************************************************/
 static inline void
@@ -3653,8 +3686,6 @@
    if (!item)
       return ;
 
-   IPS_QUEUE_LOCK(queue);
-
    item->host_scribble = (char *) queue->head;
    queue->head = item;
 
@@ -3662,8 +3693,6 @@
       queue->tail = item;
 
    queue->count++;
-
-   IPS_QUEUE_UNLOCK(queue);
 }
 
 /****************************************************************************/
@@ -3674,7 +3703,7 @@
 /*                                                                          */
 /*   Add an item to the tail of the queue                                   */
 /*                                                                          */
-/* ASSUMED to be called from within a lock                                  */
+/* ASSUMED to be called from within the HA lock                             */
 /*                                                                          */
 /****************************************************************************/
 static inline void
@@ -3684,8 +3713,6 @@
    if (!item)
       return ;
 
-   IPS_QUEUE_LOCK(queue);
-
    item->host_scribble = NULL;
 
    if (queue->tail)
@@ -3697,8 +3724,6 @@
       queue->head = item;
 
    queue->count++;
-
-   IPS_QUEUE_UNLOCK(queue);
 }
 
 /****************************************************************************/
@@ -3709,7 +3734,7 @@
 /*                                                                          */
 /*   Remove the head of the queue                                           */
 /*                                                                          */
-/* ASSUMED to be called from within a lock                                  */
+/* ASSUMED to be called from within the HA lock                             */
 /*                                                                          */
 /****************************************************************************/
 static inline Scsi_Cmnd *
@@ -3718,13 +3743,9 @@
 
    METHOD_TRACE("ips_removeq_wait_head", 1);
 
-   IPS_QUEUE_LOCK(queue);
-
    item = queue->head;
 
    if (!item) {
-      IPS_QUEUE_UNLOCK(queue);
-
       return (NULL);
    }
 
@@ -3736,8 +3757,6 @@
 
    queue->count--;
 
-   IPS_QUEUE_UNLOCK(queue);
-
    return (item);
 }
 
@@ -3749,7 +3768,7 @@
 /*                                                                          */
 /*   Remove an item from a queue                                            */
 /*                                                                          */
-/* ASSUMED to be called from within a lock                                  */
+/* ASSUMED to be called from within the HA lock                             */
 /*                                                                          */
 /****************************************************************************/
 static inline Scsi_Cmnd *
@@ -3761,11 +3780,7 @@
    if (!item)
       return (NULL);
 
-   IPS_QUEUE_LOCK(queue);
-
    if (item == queue->head) {
-      IPS_QUEUE_UNLOCK(queue);
-
       return (ips_removeq_wait_head(queue));
    }
 
@@ -3784,13 +3799,9 @@
       item->host_scribble = NULL;
       queue->count--;
 
-      IPS_QUEUE_UNLOCK(queue);
-
       return (item);
    }
 
-   IPS_QUEUE_UNLOCK(queue);
-
    return (NULL);
 }
 
@@ -3802,7 +3813,7 @@
 /*                                                                          */
 /*   Add an item to the head of the queue                                   */
 /*                                                                          */
-/* ASSUMED to be called from within a lock                                  */
+/* ASSUMED to be called from within the HA lock                             */
 /*                                                                          */
 /****************************************************************************/
 static inline void
@@ -3812,8 +3823,6 @@
    if (!item)
       return ;
 
-   IPS_QUEUE_LOCK(queue);
-
    item->next = queue->head;
    queue->head = item;
 
@@ -3821,8 +3830,6 @@
       queue->tail = item;
 
    queue->count++;
-
-   IPS_QUEUE_UNLOCK(queue);
 }
 
 /****************************************************************************/
@@ -3833,7 +3840,7 @@
 /*                                                                          */
 /*   Add an item to the tail of the queue                                   */
 /*                                                                          */
-/* ASSUMED to be called from within a lock                                  */
+/* ASSUMED to be called from within the HA lock                             */
 /*                                                                          */
 /****************************************************************************/
 static inline void
@@ -3843,8 +3850,6 @@
    if (!item)
       return ;
 
-   IPS_QUEUE_LOCK(queue);
-
    item->next = NULL;
 
    if (queue->tail)
@@ -3856,8 +3861,6 @@
       queue->head = item;
 
    queue->count++;
-
-   IPS_QUEUE_UNLOCK(queue);
 }
 
 /****************************************************************************/
@@ -3868,7 +3871,7 @@
 /*                                                                          */
 /*   Remove the head of the queue                                           */
 /*                                                                          */
-/* ASSUMED to be called from within a lock                                  */
+/* ASSUMED to be called from within the HA lock                             */
 /*                                                                          */
 /****************************************************************************/
 static inline ips_copp_wait_item_t *
@@ -3877,13 +3880,9 @@
 
    METHOD_TRACE("ips_removeq_copp_head", 1);
 
-   IPS_QUEUE_LOCK(queue);
-
    item = queue->head;
 
    if (!item) {
-      IPS_QUEUE_UNLOCK(queue);
-
       return (NULL);
    }
 
@@ -3895,8 +3894,6 @@
 
    queue->count--;
 
-   IPS_QUEUE_UNLOCK(queue);
-
    return (item);
 }
 
@@ -3908,7 +3905,7 @@
 /*                                                                          */
 /*   Remove an item from a queue                                            */
 /*                                                                          */
-/* ASSUMED to be called from within a lock                                  */
+/* ASSUMED to be called from within the HA lock                             */
 /*                                                                          */
 /****************************************************************************/
 static inline ips_copp_wait_item_t *
@@ -3920,11 +3917,7 @@
    if (!item)
       return (NULL);
 
-   IPS_QUEUE_LOCK(queue);
-
    if (item == queue->head) {
-      IPS_QUEUE_UNLOCK(queue);
-
       return (ips_removeq_copp_head(queue));
    }
 
@@ -3943,13 +3936,9 @@
       item->next = NULL;
       queue->count--;
 
-      IPS_QUEUE_UNLOCK(queue);
-
       return (item);
    }
 
-   IPS_QUEUE_UNLOCK(queue);
-
    return (NULL);
 }
 
@@ -3966,6 +3955,7 @@
 ipsintr_blocking(ips_ha_t *ha, ips_scb_t *scb) {
    METHOD_TRACE("ipsintr_blocking", 2);
 
+   ips_freescb(ha, scb);
    if ((ha->waitflag == TRUE) &&
        (ha->cmd_in_progress == scb->cdb[0])) {
       ha->waitflag = FALSE;
@@ -4012,12 +4002,11 @@
 /* Routine Description:                                                     */
 /*                                                                          */
 /*   Do housekeeping on completed commands                                  */
-/*                                                                          */
+/*  ASSUMED to be called form within the request lock                       */
 /****************************************************************************/
 static void
 ips_done(ips_ha_t *ha, ips_scb_t *scb) {
    int ret;
-   unsigned long cpu_flags;
 
    METHOD_TRACE("ips_done", 1);
 
@@ -4026,9 +4015,7 @@
 
    if ((scb->scsi_cmd) && (ips_is_passthru(scb->scsi_cmd))) {
       ips_cleanup_passthru(ha, scb);
-      IPS_HA_LOCK(cpu_flags);
       ha->num_ioctl--;
-      IPS_HA_UNLOCK(cpu_flags);
    } else {
       /*
        * Check to see if this command had too much
@@ -4041,7 +4028,6 @@
 
          bk_save = scb->breakup;
          scb->breakup = 0;
-         mod_timer(&scb->scsi_cmd->eh_timeout, jiffies + 120 * HZ);
 
          if (scb->sg_count) {
             /* S/G request */
@@ -4128,15 +4114,21 @@
          } else {
             /* Non S/G Request */
             pci_unmap_single(ha->pcidev, scb->data_busaddr, scb->data_len,
-                             PCI_DMA_BIDIRECTIONAL);
+                             IPS_DMA_DIR(scb));
             if ((scb->scsi_cmd->request_bufflen - (bk_save * ha->max_xfer)) > ha->max_xfer) {
                /* Further breakup required */
                scb->data_len = ha->max_xfer;
-               scb->data_busaddr = pci_map_single(ha->pcidev, scb->scsi_cmd->request_buffer + (bk_save * ha->max_xfer), scb->data_len, PCI_DMA_BIDIRECTIONAL);
+               scb->data_busaddr = pci_map_single(ha->pcidev,
+                                           scb->scsi_cmd->request_buffer +
+                                           (bk_save * ha->max_xfer),
+                                           scb->data_len, IPS_DMA_DIR(scb));
                scb->breakup = bk_save + 1;
             } else {
                scb->data_len = scb->scsi_cmd->request_bufflen - (bk_save * ha->max_xfer);
-               scb->data_busaddr = pci_map_single(ha->pcidev, scb->scsi_cmd->request_buffer + (bk_save * ha->max_xfer), scb->data_len, PCI_DMA_BIDIRECTIONAL);
+               scb->data_busaddr = pci_map_single(ha->pcidev,
+                                           scb->scsi_cmd->request_buffer +
+                                           (bk_save * ha->max_xfer),
+                                           scb->data_len, IPS_DMA_DIR(scb));
 	    }
 
             scb->dcdb.transfer_length = scb->data_len;
@@ -4181,9 +4173,7 @@
    } /* end if passthru */
 
    if (scb->bus) {
-      IPS_HA_LOCK(cpu_flags);
       ha->dcdb_active[scb->bus-1] &= ~(1 << scb->target_id);
-      IPS_HA_UNLOCK(cpu_flags);
    }
 
    scb->scsi_cmd->scsi_done(scb->scsi_cmd);
@@ -4197,7 +4187,7 @@
 /*                                                                          */
 /* Routine Description:                                                     */
 /*                                                                          */
-/*   Map ServeRAID error codes to Linux Error Codes                         */
+/*   Map Controller Error codes to Linux Error Codes                        */
 /*                                                                          */
 /****************************************************************************/
 static int
@@ -4363,6 +4353,7 @@
    char     *sp;
    int       device_error;
    IPS_DCDB_TABLE_TAPE *tapeDCDB;
+   int       TimeOut;
 
    METHOD_TRACE("ips_send_cmd", 1);
 
@@ -4372,8 +4363,8 @@
       /* internal command */
 
       if (scb->bus > 0) {
-         /* ServeRAID commands can't be issued */
-         /* to real devices -- fail them       */
+         /* Controller commands can't be issued */
+         /* to real devices -- fail them        */
          if ((ha->waitflag == TRUE) &&
              (ha->cmd_in_progress == scb->cdb[0])) {
             ha->waitflag = FALSE;
@@ -4383,6 +4374,8 @@
       }
    } else if ((scb->bus == 0) && (!ips_is_passthru(scb->scsi_cmd))) {
       /* command to logical bus -- interpret */
+      if(ha->scb_waitlist.count + ha->scb_activelist.count > 32)
+         mod_timer(&scb->scsi_cmd->eh_timeout, jiffies + 120 * HZ);
       ret = IPS_SUCCESS_IMM;
 
       switch (scb->scsi_cmd->cmnd[0]) {
@@ -4399,43 +4392,17 @@
 
       case TEST_UNIT_READY:
       case INQUIRY:
-         if (scb->target_id == IPS_ADAPTER_ID) {
-            /*
-             * Either we have a TUR
-             * or we have a SCSI inquiry
-             */
-            if (scb->scsi_cmd->cmnd[0] == TEST_UNIT_READY)
-               scb->scsi_cmd->result = DID_OK << 16;
-
-            if (scb->scsi_cmd->cmnd[0] == INQUIRY) {
-               IPS_SCSI_INQ_DATA inquiry;
-
-               memset(&inquiry, 0, sizeof(IPS_SCSI_INQ_DATA));
-
-               inquiry.DeviceType = IPS_SCSI_INQ_TYPE_PROCESSOR;
-               inquiry.DeviceTypeQualifier = IPS_SCSI_INQ_LU_CONNECTED;
-               inquiry.Version = IPS_SCSI_INQ_REV2;
-               inquiry.ResponseDataFormat = IPS_SCSI_INQ_RD_REV2;
-               inquiry.AdditionalLength = 31;
-               inquiry.Flags[0] = IPS_SCSI_INQ_Address16;
-               inquiry.Flags[1] = IPS_SCSI_INQ_WBus16 | IPS_SCSI_INQ_Sync;
-               strncpy(inquiry.VendorId, "IBM     ", 8);
-               strncpy(inquiry.ProductId, "SERVERAID       ", 16);
-               strncpy(inquiry.ProductRevisionLevel, "1.00", 4);
-
-               memcpy(scb->scsi_cmd->request_buffer, &inquiry, scb->scsi_cmd->request_bufflen);
-
-               scb->scsi_cmd->result = DID_OK << 16;
-            }
-         } else {
-            scb->cmd.logical_info.op_code = IPS_CMD_GET_LD_INFO;
-            scb->cmd.logical_info.command_id = IPS_COMMAND_ID(ha, scb);
-            scb->cmd.logical_info.buffer_addr = cpu_to_le32(VIRT_TO_BUS(&ha->adapt->logical_drive_info));
-            scb->cmd.logical_info.reserved = 0;
-            scb->cmd.logical_info.reserved2 = 0;
-            ret = IPS_SUCCESS;
-         }
-
+         scb->cmd.logical_info.op_code = IPS_CMD_GET_LD_INFO;
+         scb->cmd.logical_info.command_id = IPS_COMMAND_ID(ha, scb);
+         scb->cmd.logical_info.reserved = 0;
+         scb->cmd.logical_info.reserved2 = 0;
+         scb->data_len = sizeof(ha->adapt->logical_drive_info);
+         scb->data_busaddr = pci_map_single(ha->pcidev,
+                                            &ha->adapt->logical_drive_info,
+                                            scb->data_len, IPS_DMA_DIR(scb));
+         scb->flags |= IPS_SCB_MAP_SINGLE;
+         scb->cmd.logical_info.buffer_addr = scb->data_busaddr;
+         ret = IPS_SUCCESS;
          break;
 
       case REQUEST_SENSE:
@@ -4523,17 +4490,26 @@
       case MODE_SENSE:
          scb->cmd.basic_io.op_code = IPS_CMD_ENQUIRY;
          scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
-         scb->cmd.basic_io.sg_addr = cpu_to_le32(VIRT_TO_BUS(ha->enq));
+         scb->data_len = sizeof(*ha->enq);
+         scb->data_busaddr = pci_map_single(ha->pcidev, ha->enq,
+                                            scb->data_len, IPS_DMA_DIR(scb));
+         scb->cmd.basic_io.sg_addr = scb->data_busaddr;
+         scb->flags |= IPS_SCB_MAP_SINGLE;
          ret = IPS_SUCCESS;
          break;
 
       case READ_CAPACITY:
          scb->cmd.logical_info.op_code = IPS_CMD_GET_LD_INFO;
          scb->cmd.logical_info.command_id = IPS_COMMAND_ID(ha, scb);
-         scb->cmd.logical_info.buffer_addr = cpu_to_le32(VIRT_TO_BUS(&ha->adapt->logical_drive_info));
          scb->cmd.logical_info.reserved = 0;
          scb->cmd.logical_info.reserved2 = 0;
          scb->cmd.logical_info.reserved3 = 0;
+         scb->data_len = sizeof(ha->adapt->logical_drive_info);
+         scb->data_busaddr = pci_map_single(ha->pcidev,
+                                            &ha->adapt->logical_drive_info,
+                                            scb->data_len, IPS_DMA_DIR(scb));
+         scb->flags |= IPS_SCB_MAP_SINGLE;
+         scb->cmd.logical_info.buffer_addr = scb->data_busaddr;
          ret = IPS_SUCCESS;
          break;
 
@@ -4586,10 +4562,14 @@
 
       ha->dcdb_active[scb->bus-1] |= (1 << scb->target_id);
       scb->cmd.dcdb.command_id = IPS_COMMAND_ID(ha, scb);
-      scb->cmd.dcdb.dcdb_address = cpu_to_le32(VIRT_TO_BUS(&scb->dcdb));
+      scb->cmd.dcdb.dcdb_address = cpu_to_le32(scb->scb_busaddr +
+                                               (unsigned long)&scb->dcdb -
+                                               (unsigned long)scb);
       scb->cmd.dcdb.reserved = 0;
       scb->cmd.dcdb.reserved2 = 0;
-      scb->cmd.dcdb.reserved3 = 0;
+      scb->cmd.dcdb.reserved3 = 0;   
+
+      TimeOut = scb->scsi_cmd->timeout_per_command;
 
       if (ha->subsys->param[4] & 0x00100000) {          /* If NEW Tape DCDB is Supported */
          if (!scb->sg_len)
@@ -4602,51 +4582,50 @@
          tapeDCDB->cmd_attribute |= IPS_DISCONNECT_ALLOWED;
          tapeDCDB->cmd_attribute &= ~IPS_TRANSFER64K;   /* Always Turn OFF 64K Size Flag */
 
-         if (scb->timeout) {
-           if (scb->timeout <= 10)
-               tapeDCDB->cmd_attribute |= IPS_TIMEOUT10;
-            else if (scb->timeout <= 60)
-               tapeDCDB->cmd_attribute |= IPS_TIMEOUT60;
-            else
-               tapeDCDB->cmd_attribute |= IPS_TIMEOUT20M;
+         if (TimeOut) {
+            if (TimeOut < ( 10 * HZ ))                  
+                tapeDCDB->cmd_attribute |= IPS_TIMEOUT10;     /* TimeOut is 10 Seconds */
+            else if (TimeOut < (60 * HZ)) 
+                tapeDCDB->cmd_attribute |= IPS_TIMEOUT60;     /* TimeOut is 60 Seconds */
+            else if (TimeOut < (1200 * HZ)) 
+                tapeDCDB->cmd_attribute |= IPS_TIMEOUT20M;    /* TimeOut is 20 Minutes */
          }
 
-         if (!(tapeDCDB->cmd_attribute & IPS_TIMEOUT20M))
-            tapeDCDB->cmd_attribute |= IPS_TIMEOUT20M;
-
-         tapeDCDB->sense_length = sizeof(tapeDCDB->sense_info);
+         tapeDCDB->cdb_length = scb->scsi_cmd->cmd_len;
+         tapeDCDB->reserved_for_LUN = 0;
          tapeDCDB->transfer_length = scb->data_len;
          tapeDCDB->buffer_pointer = cpu_to_le32(scb->data_busaddr);
          tapeDCDB->sg_count = scb->sg_len;
-         tapeDCDB->cdb_length = scb->scsi_cmd->cmd_len;
-         tapeDCDB->reserved_for_LUN = 0;
-         tapeDCDB->reserved = 0;
+         tapeDCDB->sense_length = sizeof(tapeDCDB->sense_info);
          tapeDCDB->scsi_status = 0;
+         tapeDCDB->reserved = 0;
          memcpy(tapeDCDB->scsi_cdb, scb->scsi_cmd->cmnd, scb->scsi_cmd->cmd_len);
       } else {
          scb->dcdb.device_address = ((scb->bus - 1) << 4) | scb->target_id;
          scb->dcdb.cmd_attribute |= IPS_DISCONNECT_ALLOWED;
 
-         if (scb->timeout) {
-           if (scb->timeout <= 10)
-               scb->dcdb.cmd_attribute |= IPS_TIMEOUT10;
-            else if (scb->timeout <= 60)
-               scb->dcdb.cmd_attribute |= IPS_TIMEOUT60;
-            else
-               scb->dcdb.cmd_attribute |= IPS_TIMEOUT20M;
+         if (TimeOut) {
+            if (TimeOut < (10 * HZ))                  
+                scb->dcdb.cmd_attribute |= IPS_TIMEOUT10;     /* TimeOut is 10 Seconds */
+            else if (TimeOut < (60 * HZ)) 
+                scb->dcdb.cmd_attribute |= IPS_TIMEOUT60;     /* TimeOut is 60 Seconds */
+            else if (TimeOut < (1200 * HZ)) 
+                scb->dcdb.cmd_attribute |= IPS_TIMEOUT20M;    /* TimeOut is 20 Minutes */
          }
-
-         if (!(scb->dcdb.cmd_attribute & IPS_TIMEOUT20M))
-            scb->dcdb.cmd_attribute |= IPS_TIMEOUT20M;
-
-         scb->dcdb.sense_length = sizeof(scb->dcdb.sense_info);
+         
          scb->dcdb.transfer_length = scb->data_len;
          if ( scb->dcdb.cmd_attribute & IPS_TRANSFER64K ) 
              scb->dcdb.transfer_length = 0;
          scb->dcdb.buffer_pointer = cpu_to_le32(scb->data_busaddr);
-         scb->dcdb.sg_count = scb->sg_len;
          scb->dcdb.cdb_length = scb->scsi_cmd->cmd_len;
+         scb->dcdb.sense_length = sizeof(scb->dcdb.sense_info);
+         scb->dcdb.sg_count = scb->sg_len;
+         scb->dcdb.reserved = 0;
          memcpy(scb->dcdb.scsi_cdb, scb->scsi_cmd->cmnd, scb->scsi_cmd->cmd_len);
+         scb->dcdb.scsi_status = 0;
+         scb->dcdb.reserved2[0] = 0;
+         scb->dcdb.reserved2[1] = 0;
+         scb->dcdb.reserved2[2] = 0;
       }
    }
 
@@ -4660,7 +4639,7 @@
 /* Routine Description:                                                     */
 /*                                                                          */
 /*   Check the status of commands to logical drives                         */
-/*                                                                          */
+/*   Assumed to be called with the HA lock                                  */
 /****************************************************************************/
 static void
 ips_chkstatus(ips_ha_t *ha, IPS_STATUS *pstatus) {
@@ -4725,12 +4704,37 @@
             break;
 
          case TEST_UNIT_READY:
+            if (scb->target_id == IPS_ADAPTER_ID) 
+               break;
+
             if (!ips_online(ha, scb)) {
                errcode = DID_TIME_OUT;
             }
             break;
 
          case INQUIRY:
+            if (scb->target_id == IPS_ADAPTER_ID) {
+               IPS_SCSI_INQ_DATA inquiry;
+
+               memset(&inquiry, 0, sizeof(IPS_SCSI_INQ_DATA));
+
+               inquiry.DeviceType = IPS_SCSI_INQ_TYPE_PROCESSOR;
+               inquiry.DeviceTypeQualifier = IPS_SCSI_INQ_LU_CONNECTED;
+               inquiry.Version = IPS_SCSI_INQ_REV2;
+               inquiry.ResponseDataFormat = IPS_SCSI_INQ_RD_REV2;
+               inquiry.AdditionalLength = 31;
+               inquiry.Flags[0] = IPS_SCSI_INQ_Address16;
+               inquiry.Flags[1] = IPS_SCSI_INQ_WBus16 | IPS_SCSI_INQ_Sync;
+               strncpy(inquiry.VendorId, "IBM     ", 8);
+               strncpy(inquiry.ProductId, "SERVERAID       ", 16);
+               strncpy(inquiry.ProductRevisionLevel, "1.00", 4);
+
+               memcpy(scb->scsi_cmd->request_buffer, &inquiry, scb->scsi_cmd->request_bufflen);
+
+               scb->scsi_cmd->result = DID_OK << 16;
+               break;
+            }
+
             if (ips_online(ha, scb)) {
                ips_inquiry(ha, scb);
             } else {
@@ -5024,7 +5028,8 @@
       }
 
       if (ha->adapt) {
-         kfree(ha->adapt);
+         pci_free_consistent(ha->pcidev,sizeof(IPS_ADAPTER)+ sizeof(IPS_IO_CMD),
+                             ha->adapt, ha->adapt->hw_status_start);
          ha->adapt = NULL;
       }
 
@@ -5038,11 +5043,6 @@
          ha->subsys = NULL;
       }
 
-      if (ha->dummy) {
-         kfree(ha->dummy);
-         ha->dummy = NULL;
-      }
-
       if (ha->ioctl_data) {
          free_pages((unsigned long) ha->ioctl_data, ha->ioctl_order);
          ha->ioctl_data = NULL;
@@ -5164,7 +5164,8 @@
 
    /* Initialize dummy command bucket */
    ha->dummy->op_code = 0xFF;
-   ha->dummy->ccsar = cpu_to_le32(VIRT_TO_BUS(ha->dummy));
+   ha->dummy->ccsar = cpu_to_le32(ha->adapt->hw_status_start
+                                      + sizeof(IPS_ADAPTER));
    ha->dummy->command_id = IPS_MAX_CMDS;
 
    /* set bus address of scb */
@@ -5174,7 +5175,8 @@
 
    /* Neptune Fix */
    scb->cmd.basic_io.cccr = cpu_to_le32((uint32_t) IPS_BIT_ILE);
-   scb->cmd.basic_io.ccsar = cpu_to_le32(VIRT_TO_BUS(ha->dummy));
+   scb->cmd.basic_io.ccsar = cpu_to_le32(ha->adapt->hw_status_start
+                                           + sizeof(IPS_ADAPTER));
 }
 
 /****************************************************************************/
@@ -5191,13 +5193,10 @@
 static ips_scb_t *
 ips_getscb(ips_ha_t *ha) {
    ips_scb_t     *scb;
-   unsigned long  cpu_flags;
 
    METHOD_TRACE("ips_getscb", 1);
 
-   IPS_SCB_LOCK(cpu_flags);
    if ((scb = ha->scb_freelist) == NULL) {
-      IPS_SCB_UNLOCK(cpu_flags);
 
       return (NULL);
    }
@@ -5205,8 +5204,6 @@
    ha->scb_freelist = scb->q_next;
    scb->q_next = NULL;
 
-   IPS_SCB_UNLOCK(cpu_flags);
-
    ips_init_scb(ha, scb);
 
    return (scb);
@@ -5225,20 +5222,20 @@
 /****************************************************************************/
 static void
 ips_freescb(ips_ha_t *ha, ips_scb_t *scb) {
-   unsigned long cpu_flags;
 
    METHOD_TRACE("ips_freescb", 1);
    if(scb->flags & IPS_SCB_MAP_SG)
-      pci_unmap_sg(ha->pcidev,scb->scsi_cmd->request_buffer, scb->scsi_cmd->use_sg, PCI_DMA_BIDIRECTIONAL); 
+      pci_unmap_sg(ha->pcidev, scb->scsi_cmd->request_buffer,
+                   scb->scsi_cmd->use_sg,
+                   IPS_DMA_DIR(scb));
    else if(scb->flags & IPS_SCB_MAP_SINGLE)
-      pci_unmap_single(ha->pcidev,scb->cmd.basic_io.sg_addr, scb->data_len, PCI_DMA_BIDIRECTIONAL);
+      pci_unmap_single(ha->pcidev, scb->data_busaddr, scb->data_len,
+                       IPS_DMA_DIR(scb));
 
    /* check to make sure this is not our "special" scb */
    if (IPS_COMMAND_ID(ha, scb) < (ha->max_cmds - 1)) {
-      IPS_SCB_LOCK(cpu_flags);
       scb->q_next = ha->scb_freelist;
       ha->scb_freelist = scb;
-      IPS_SCB_UNLOCK(cpu_flags);
    }
 }
 
@@ -5593,6 +5590,29 @@
 
    Post = readl(ha->mem_ptr + IPS_REG_I960_MSG0);
 
+   if (Post == 0x4F00) {                          /* If Flashing the Battery PIC         */
+       printk(KERN_WARNING "Flashing Battery PIC, Please wait ...\n" );
+
+       /* Clear the interrupt bit */
+       Isr = (uint32_t) IPS_BIT_I960_MSG0I;
+       writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR);
+
+       for (i = 0; i < 120; i++) {                /*    Wait Up to 2 Min. for Completion */
+          Post = readl(ha->mem_ptr + IPS_REG_I960_MSG0);
+          if (Post != 0x4F00)
+              break;
+          /* Delay for 1 Second */
+          MDELAY(IPS_ONE_SEC);
+       }
+
+       if (i >= 120) {
+          printk(KERN_WARNING "(%s%d) timeout waiting for Battery PIC Flash\n",
+                 ips_name, ha->host_num);
+          return (0);
+       }
+
+   }
+
    /* Clear the interrupt bit */
    Isr = (uint32_t) IPS_BIT_I960_MSG0I;
    writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR);
@@ -5635,6 +5655,13 @@
    writel(Oimr, ha->mem_ptr + IPS_REG_I960_OIMR);
 
    /* if we get here then everything went OK */
+
+   /* Since we did a RESET, an EraseStripeLock may be needed */
+   if (Post == 0xEF10) {
+      if ( (Config == 0x000F) || (Config == 0x0009) )
+         ha->requires_esl = 1;
+   }
+
    return (1);
 }
 
@@ -5650,15 +5677,12 @@
 static int
 ips_reset_copperhead(ips_ha_t *ha) {
    int reset_counter;
-   unsigned long cpu_flags;
 
    METHOD_TRACE("ips_reset_copperhead", 1);
 
    DEBUG_VAR(1, "(%s%d) ips_reset_copperhead: io addr: %x, irq: %d",
              ips_name, ha->host_num, ha->io_addr, ha->irq);
 
-   IPS_HA_LOCK(cpu_flags);
-
    reset_counter = 0;
 
    while (reset_counter < 2) {
@@ -5677,14 +5701,11 @@
       if ((*ha->func.init)(ha))
          break;
       else if (reset_counter >= 2) {
-         IPS_HA_UNLOCK(cpu_flags);
 
          return (0);
       }
    }
 
-   IPS_HA_UNLOCK(cpu_flags);
-
    return (1);
 }
 
@@ -5700,15 +5721,12 @@
 static int
 ips_reset_copperhead_memio(ips_ha_t *ha) {
    int reset_counter;
-   unsigned long cpu_flags;
 
    METHOD_TRACE("ips_reset_copperhead_memio", 1);
 
    DEBUG_VAR(1, "(%s%d) ips_reset_copperhead_memio: mem addr: %x, irq: %d",
              ips_name, ha->host_num, ha->mem_addr, ha->irq);
 
-   IPS_HA_LOCK(cpu_flags);
-
    reset_counter = 0;
 
    while (reset_counter < 2) {
@@ -5727,14 +5745,11 @@
       if ((*ha->func.init)(ha))
          break;
       else if (reset_counter >= 2) {
-         IPS_HA_UNLOCK(cpu_flags);
 
          return (0);
       }
    }
 
-   IPS_HA_UNLOCK(cpu_flags);
-
    return (1);
 }
 
@@ -5751,15 +5766,12 @@
 ips_reset_morpheus(ips_ha_t *ha) {
    int           reset_counter;
    uint8_t       junk;
-   unsigned long cpu_flags;
 
    METHOD_TRACE("ips_reset_morpheus", 1);
 
    DEBUG_VAR(1, "(%s%d) ips_reset_morpheus: mem addr: %x, irq: %d",
              ips_name, ha->host_num, ha->mem_addr, ha->irq);
 
-   IPS_HA_LOCK(cpu_flags);
-
    reset_counter = 0;
 
    while (reset_counter < 2) {
@@ -5776,14 +5788,11 @@
       if ((*ha->func.init)(ha))
          break;
       else if (reset_counter >= 2) {
-         IPS_HA_UNLOCK(cpu_flags);
 
          return (0);
       }
    }
 
-   IPS_HA_UNLOCK(cpu_flags);
-
    return (1);
 }
 
@@ -5806,13 +5815,12 @@
    ha->adapt->p_status_end = ha->adapt->status + IPS_MAX_CMDS;
    ha->adapt->p_status_tail = ha->adapt->status;
 
-   phys_status_start = VIRT_TO_BUS(ha->adapt->status);
+   phys_status_start = ha->adapt->hw_status_start;
    outl(cpu_to_le32(phys_status_start), ha->io_addr + IPS_REG_SQSR);
    outl(cpu_to_le32(phys_status_start + IPS_STATUS_Q_SIZE), ha->io_addr + IPS_REG_SQER);
    outl(cpu_to_le32(phys_status_start + IPS_STATUS_SIZE), ha->io_addr + IPS_REG_SQHR);
    outl(cpu_to_le32(phys_status_start), ha->io_addr + IPS_REG_SQTR);
 
-   ha->adapt->hw_status_start = phys_status_start;
    ha->adapt->hw_status_tail = phys_status_start;
 }
 
@@ -5835,13 +5843,12 @@
    ha->adapt->p_status_end = ha->adapt->status + IPS_MAX_CMDS;
    ha->adapt->p_status_tail = ha->adapt->status;
 
-   phys_status_start = VIRT_TO_BUS(ha->adapt->status);
+   phys_status_start = ha->adapt->hw_status_start;
    writel(phys_status_start, ha->mem_ptr + IPS_REG_SQSR);
    writel(phys_status_start + IPS_STATUS_Q_SIZE, ha->mem_ptr + IPS_REG_SQER);
    writel(phys_status_start + IPS_STATUS_SIZE, ha->mem_ptr + IPS_REG_SQHR);
    writel(phys_status_start, ha->mem_ptr + IPS_REG_SQTR);
 
-   ha->adapt->hw_status_start = phys_status_start;
    ha->adapt->hw_status_tail = phys_status_start;
 }
 
@@ -5930,7 +5937,6 @@
 ips_issue_copperhead(ips_ha_t *ha, ips_scb_t *scb) {
    uint32_t TimeOut;
    uint32_t val;
-   unsigned long cpu_flags;
 
    METHOD_TRACE("ips_issue_copperhead", 1);
 
@@ -5950,8 +5956,6 @@
                 scb->cmd.basic_io.command_id);
    }
 
-   IPS_HA_LOCK(cpu_flags);
-
    TimeOut = 0;
 
    while ((val = le32_to_cpu(inl(ha->io_addr + IPS_REG_CCCR))) & IPS_BIT_SEM) {
@@ -5966,8 +5970,6 @@
          printk(KERN_WARNING "(%s%d) ips_issue semaphore chk timeout.\n",
                 ips_name, ha->host_num);
 
-         IPS_HA_UNLOCK(cpu_flags);
-
          return (IPS_FAILURE);
       } /* end if */
    } /* end while */
@@ -5975,8 +5977,6 @@
    outl(cpu_to_le32(scb->scb_busaddr), ha->io_addr + IPS_REG_CCSAR);
    outw(cpu_to_le32(IPS_BIT_START_CMD), ha->io_addr + IPS_REG_CCCR);
 
-   IPS_HA_UNLOCK(cpu_flags);
-
    return (IPS_SUCCESS);
 }
 
@@ -5993,7 +5993,6 @@
 ips_issue_copperhead_memio(ips_ha_t *ha, ips_scb_t *scb) {
    uint32_t      TimeOut;
    uint32_t      val;
-   unsigned long cpu_flags;
 
    METHOD_TRACE("ips_issue_copperhead_memio", 1);
 
@@ -6013,8 +6012,6 @@
                 scb->cmd.basic_io.command_id);
    }
 
-   IPS_HA_LOCK(cpu_flags);
-
    TimeOut = 0;
 
    while ((val = readl(ha->mem_ptr + IPS_REG_CCCR)) & IPS_BIT_SEM) {
@@ -6029,8 +6026,6 @@
          printk(KERN_WARNING "(%s%d) ips_issue semaphore chk timeout.\n",
                 ips_name, ha->host_num);
 
-         IPS_HA_UNLOCK(cpu_flags);
-
          return (IPS_FAILURE);
       } /* end if */
    } /* end while */
@@ -6038,8 +6033,6 @@
    writel(scb->scb_busaddr, ha->mem_ptr + IPS_REG_CCSAR);
    writel(IPS_BIT_START_CMD, ha->mem_ptr + IPS_REG_CCCR);
 
-   IPS_HA_UNLOCK(cpu_flags);
-
    return (IPS_SUCCESS);
 }
 
@@ -6054,7 +6047,6 @@
 /****************************************************************************/
 static int
 ips_issue_i2o(ips_ha_t *ha, ips_scb_t *scb) {
-   unsigned long cpu_flags;
 
    METHOD_TRACE("ips_issue_i2o", 1);
 
@@ -6074,12 +6066,8 @@
                 scb->cmd.basic_io.command_id);
    }
 
-   IPS_HA_LOCK(cpu_flags);
-
    outl(cpu_to_le32(scb->scb_busaddr), ha->io_addr + IPS_REG_I2O_INMSGQ);
 
-   IPS_HA_UNLOCK(cpu_flags);
-
    return (IPS_SUCCESS);
 }
 
@@ -6094,7 +6082,6 @@
 /****************************************************************************/
 static int
 ips_issue_i2o_memio(ips_ha_t *ha, ips_scb_t *scb) {
-   unsigned long cpu_flags;
 
    METHOD_TRACE("ips_issue_i2o_memio", 1);
 
@@ -6114,12 +6101,8 @@
                 scb->cmd.basic_io.command_id);
    }
 
-   IPS_HA_LOCK(cpu_flags);
-
    writel(scb->scb_busaddr, ha->mem_ptr + IPS_REG_I2O_INMSGQ);
 
-   IPS_HA_UNLOCK(cpu_flags);
-
    return (IPS_SUCCESS);
 }
 
@@ -6256,12 +6239,7 @@
           * until after we finish.
           */
 
-         while (test_and_set_bit(IPS_IN_INTR, &ha->flags))
-            udelay(1000);
-
          (*ha->func.intr)(ha);
-
-         clear_bit(IPS_IN_INTR, &ha->flags);
       } 
 
       /* This looks like a very evil loop, but it only does this during start-up */
@@ -6297,8 +6275,7 @@
    if (le32_to_cpu(ha->nvram->signature) != IPS_NVRAM_P5_SIG) {
       DEBUG_VAR(1, "(%s%d) NVRAM page 5 has an invalid signature: %X.",
                 ips_name, ha->host_num, ha->nvram->signature);
-
-      return (1);
+      ha->nvram->signature = IPS_NVRAM_P5_SIG;
    }
 
    DEBUG_VAR(2, "(%s%d) Ad Type: %d, Ad Slot: %d, BIOS: %c%c%c%c %c%c%c%c.",
@@ -6321,6 +6298,10 @@
 
    ips_version_check(ha, intr);                           /* Check BIOS/FW/Driver Versions */
 
+   /* Save the First Copy of the Adapter Order that BIOS put in Page 5 */
+   if ( (InitState == 0) && (AdapterOrder[0] == 0) ) 
+      strncpy((char *) AdapterOrder, (char *) ha->nvram->adapter_order, sizeof(AdapterOrder) );
+
    /* now update the page */
    if (!ips_readwrite_page5(ha, TRUE, intr)) {
       printk(KERN_WARNING "(%s%d) unable to write NVRAM page 5.\n",
@@ -6362,11 +6343,15 @@
    scb->cmd.basic_io.op_code = IPS_CMD_ENQUIRY;
    scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
    scb->cmd.basic_io.sg_count = 0;
-   scb->cmd.basic_io.sg_addr = cpu_to_le32(VIRT_TO_BUS(ha->enq));
    scb->cmd.basic_io.lba = 0;
    scb->cmd.basic_io.sector_count = 0;
    scb->cmd.basic_io.log_drv = 0;
    scb->cmd.basic_io.reserved = 0;
+   scb->data_len = sizeof(*ha->enq);
+   scb->data_busaddr = pci_map_single(ha->pcidev, ha->enq, scb->data_len,
+                                      IPS_DMA_DIR(scb));
+   scb->cmd.basic_io.sg_addr = scb->data_busaddr;
+   scb->flags |= IPS_SCB_MAP_SINGLE;
 
    /* send command */
    if (((ret = ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) ||
@@ -6403,11 +6388,15 @@
    scb->cmd.basic_io.op_code = IPS_CMD_GET_SUBSYS;
    scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
    scb->cmd.basic_io.sg_count = 0;
-   scb->cmd.basic_io.sg_addr = cpu_to_le32(VIRT_TO_BUS(ha->subsys));
    scb->cmd.basic_io.lba = 0;
    scb->cmd.basic_io.sector_count = 0;
    scb->cmd.basic_io.log_drv = 0;
    scb->cmd.basic_io.reserved = 0;
+   scb->data_len = sizeof(*ha->subsys);
+   scb->data_busaddr = pci_map_single(ha->pcidev, ha->subsys,
+                                      scb->data_len, IPS_DMA_DIR(scb));
+   scb->cmd.basic_io.sg_addr = scb->data_busaddr;
+   scb->flags |= IPS_SCB_MAP_SINGLE;
 
    /* send command */
    if (((ret = ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) ||
@@ -6448,7 +6437,11 @@
 
    scb->cmd.basic_io.op_code = IPS_CMD_READ_CONF;
    scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
-   scb->cmd.basic_io.sg_addr = cpu_to_le32(VIRT_TO_BUS(ha->conf));
+   scb->data_len = sizeof(*ha->conf);
+   scb->data_busaddr = pci_map_single(ha->pcidev, ha->conf,
+                                      scb->data_len, IPS_DMA_DIR(scb));
+   scb->cmd.basic_io.sg_addr = scb->data_busaddr;
+   scb->flags |= IPS_SCB_MAP_SINGLE;
 
    /* send command */
    if (((ret = ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) ||
@@ -6498,9 +6491,13 @@
    scb->cmd.nvram.command_id = IPS_COMMAND_ID(ha, scb);
    scb->cmd.nvram.page = 5;
    scb->cmd.nvram.write = write;
-   scb->cmd.nvram.buffer_addr = cpu_to_le32(VIRT_TO_BUS(ha->nvram));
    scb->cmd.nvram.reserved = 0;
    scb->cmd.nvram.reserved2 = 0;
+   scb->data_len = sizeof(*ha->nvram);
+   scb->data_busaddr = pci_map_single(ha->pcidev, ha->nvram,
+                                      scb->data_len, IPS_DMA_DIR(scb));
+   scb->cmd.nvram.buffer_addr = scb->data_busaddr;
+   scb->flags |= IPS_SCB_MAP_SINGLE;
 
    /* issue the command */
    if (((ret = ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) ||
@@ -7211,7 +7208,7 @@
 /*     Assumes that ips_read_adapter_status() is called first filling in     */
 /*     the data for SubSystem Parameters.                                    */
 /*     Called from ips_write_driver_status() so it also assumes NVRAM Page 5 */
-/*     Data is availaible.                                                   */
+/*     Data is available.                                                    */
 /*                                                                           */
 /*---------------------------------------------------------------------------*/
 static void ips_version_check(ips_ha_t *ha, int intr) {
@@ -7220,6 +7217,8 @@
  uint8_t  BiosVersion[ IPS_COMPAT_ID_LENGTH + 1];
  int      MatchError;
  int      rc;
+ char     BiosString[10];
+ char     FirmwareString[10];
 
  METHOD_TRACE("ips_version_check", 1);
 
@@ -7252,28 +7251,30 @@
  MatchError = 0;
 
  if  (strncmp(FirmwareVersion, Compatable[ ha->nvram->adapter_type ], IPS_COMPAT_ID_LENGTH) != 0)
- {
-     if (ips_cd_boot == 0)                                                                              
-       printk(KERN_WARNING "Warning: Adapter %d Firmware Compatible Version is %s, but should be %s\n", 
-              ha->host_num, FirmwareVersion, Compatable[ ha->nvram->adapter_type ]);                    
      MatchError = 1;
- }
 
  if  (strncmp(BiosVersion, IPS_COMPAT_BIOS, IPS_COMPAT_ID_LENGTH) != 0)
- {
-     if (ips_cd_boot == 0)                                                                          
-       printk(KERN_WARNING "Warning: Adapter %d BIOS Compatible Version is %s, but should be %s\n", 
-              ha->host_num, BiosVersion, IPS_COMPAT_BIOS);                                          
      MatchError = 1;
- }
 
  ha->nvram->versioning = 1;          /* Indicate the Driver Supports Versioning */
 
  if  (MatchError)
  {
      ha->nvram->version_mismatch = 1;
-     if (ips_cd_boot == 0)                                               
+     if (ips_cd_boot == 0)  
+     {
+       strncpy(&BiosString[0], ha->nvram->bios_high, 4);
+       strncpy(&BiosString[4], ha->nvram->bios_low, 4);
+       BiosString[8] = 0;
+
+       strncpy(&FirmwareString[0], ha->enq->CodeBlkVersion, 8);
+       FirmwareString[8] = 0;
+
        printk(KERN_WARNING "Warning ! ! ! ServeRAID Version Mismatch\n");
+       printk(KERN_WARNING "Bios = %s, Firmware = %s, Device Driver = %s%s\n",
+                            BiosString, FirmwareString, IPS_VERSION_HIGH, IPS_VERSION_LOW );
+       printk(KERN_WARNING "These levels should match to avoid possible compatibility problems.\n" );
+     }
  }
  else
  {
@@ -7287,7 +7288,7 @@
 /*   Routine Name: ips_get_version_info                                      */
 /*                                                                           */
 /*   Routine Description:                                                    */
-/*     Issue an internal GETVERSION ServeRAID Command                        */
+/*     Issue an internal GETVERSION Command                                  */
 /*                                                                           */
 /*   Return Value:                                                           */
 /*     0 if Successful, else non-zero                                        */
@@ -7309,8 +7310,12 @@
    scb->cmd.version_info.command_id = IPS_COMMAND_ID(ha, scb);
    scb->cmd.version_info.reserved = 0;
    scb->cmd.version_info.count = sizeof( IPS_VERSION_DATA);
-   scb->cmd.version_info.buffer_addr = cpu_to_le32(VIRT_TO_BUS(Buffer));
    scb->cmd.version_info.reserved2 = 0;
+   scb->data_len = sizeof(*Buffer);
+   scb->data_busaddr = pci_map_single(ha->pcidev, Buffer,
+                                      scb->data_len, IPS_DMA_DIR(scb));
+   scb->cmd.version_info.buffer_addr = scb->data_busaddr;
+   scb->flags |= IPS_SCB_MAP_SINGLE;
 
    /* issue command */
    rc = ips_send_wait(ha, scb, ips_cmd_timeout, intr);
@@ -7324,6 +7329,14 @@
 #include "scsi_module.c"
 #endif
 
+static int ips_abort_init(ips_ha_t *ha, struct Scsi_Host *sh, int index){
+   ha->active = 0;
+   ips_free(ha);
+   scsi_unregister(sh);
+   ips_ha[index] = 0;
+   ips_sh[index] = 0;
+   return -1;
+}
 
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
 
@@ -7367,12 +7380,25 @@
     int  rc;
 
     METHOD_TRACE("ips_insert_device", 1);
+
+    /* If we're still in Init State 0, and we've already found the Adapter */
+    /* Ordering Table, there is no reason to continue.                     */
+    if ( (InitState == 0) && (AdapterOrder[0]) ) 
+        return -1;
+    
     if (pci_enable_device(pci_dev)) 
 		return -1;
 
     rc = ips_init_phase1(pci_dev, &index);
     if (rc == SUCCESS)
-       rc = ips_init_phase2(index);  
+       rc = ips_init_phase2(index); 
+
+    /* If we're in Init State 0, we're done with the device for now. */
+    /* Release the device and don't count it.                        */
+    if ( InitState == 0 ) {
+        ips_remove_device(pci_dev);
+		return -1;
+    }
 
     if (rc == SUCCESS)
        ips_num_controllers++;
@@ -7407,6 +7433,7 @@
    int               j;
    int               index; 
    uint32_t          count;
+   dma_addr_t        dma_address;
    char             *ioremap_ptr;
    char             *mem_ptr;             
    uint32_t          IsDead
@@ -7486,6 +7513,10 @@
 
     /* found a controller */
     sh = scsi_register(&driver_template, sizeof(ips_ha_t));
+#if LINUX_VERSION_CODE > LinuxVersionCode(2,5,0) 
+    pci_set_dma_mask(pci_dev, (u64)0xffffffff);
+    scsi_set_pci_device(sh, pci_dev);
+#endif
     if (sh == NULL) {
        printk(KERN_WARNING "Unable to register controller with SCSI subsystem\n" );
        return -1;
@@ -7493,14 +7524,7 @@
 
     ha = IPS_HA(sh);
     memset(ha, 0, sizeof(ips_ha_t));
-
-    /* Initialize spin lock */
-    spin_lock_init(&ha->scb_lock);
-    spin_lock_init(&ha->copp_lock);                                                              spin_lock_init(&ha->ips_lock);
-    spin_lock_init(&ha->copp_waitlist.lock);
-    spin_lock_init(&ha->scb_waitlist.lock);
-    spin_lock_init(&ha->scb_activelist.lock);
-
+    
     ips_sh[index] = sh;
     ips_ha[index] = ha;
     ha->active = 1;
@@ -7509,72 +7533,37 @@
 
     if (!ha->enq) {
        printk(KERN_WARNING "Unable to allocate host inquiry structure\n" );
-       ha->active = 0;
-       ips_free(ha);
-       scsi_unregister(sh);
-       ips_ha[index] = 0;
-       ips_sh[index] = 0;
-       return -1;
+       return ips_abort_init(ha, sh, index);
     }
 
-    ha->adapt = kmalloc(sizeof(IPS_ADAPTER), GFP_KERNEL);
-
+    ha->adapt = pci_alloc_consistent(pci_dev, sizeof(IPS_ADAPTER) +
+                                     sizeof(IPS_IO_CMD), &dma_address);
     if (!ha->adapt) {
-       printk(KERN_WARNING "Unable to allocate host adapt structure\n" );
-       ha->active = 0;
-       ips_free(ha);
-       scsi_unregister(sh);
-       ips_ha[index] = 0;
-       ips_sh[index] = 0;
-       return -1;
+       printk(KERN_WARNING "Unable to allocate host adapt & dummy structures\n");
+       return ips_abort_init(ha, sh, index);
     }
+    ha->adapt->hw_status_start = dma_address;
+    ha->dummy = (void *)(ha->adapt + 1);
 
     ha->conf = kmalloc(sizeof(IPS_CONF), GFP_KERNEL);
 
     if (!ha->conf) {
        printk(KERN_WARNING "Unable to allocate host conf structure\n" );
-       ha->active = 0;
-       ips_free(ha);
-       scsi_unregister(sh);
-       ips_ha[index] = 0;
-       ips_sh[index] = 0;
-       return -1;
+       return ips_abort_init(ha, sh, index);
     }
 
     ha->nvram = kmalloc(sizeof(IPS_NVRAM_P5), GFP_KERNEL);
 
     if (!ha->nvram) {
        printk(KERN_WARNING "Unable to allocate host NVRAM structure\n" );
-       ha->active = 0;
-       ips_free(ha);
-       scsi_unregister(sh);
-       ips_ha[index] = 0;
-       ips_sh[index] = 0;
-       return -1;
+       return ips_abort_init(ha, sh, index);
     }
 
     ha->subsys = kmalloc(sizeof(IPS_SUBSYS), GFP_KERNEL);
 
     if (!ha->subsys) {
        printk(KERN_WARNING "Unable to allocate host subsystem structure\n" );
-       ha->active = 0;
-       ips_free(ha);
-       scsi_unregister(sh);
-       ips_ha[index] = 0;
-       ips_sh[index] = 0;
-       return -1;
-    }
-
-    ha->dummy = kmalloc(sizeof(IPS_IO_CMD), GFP_KERNEL);
-
-    if (!ha->dummy) {
-       printk(KERN_WARNING "Unable to allocate host dummy structure\n" );
-       ha->active = 0;
-       ips_free(ha);
-       scsi_unregister(sh);
-       ips_ha[index] = 0;
-       ips_sh[index] = 0;
-       return -1;
+       return ips_abort_init(ha, sh, index);
     }
 
     for (count = PAGE_SIZE, ha->ioctl_order = 0;
@@ -7625,55 +7614,9 @@
     /*
      * Setup Functions
      */
-    if (IPS_IS_MORPHEUS(ha)) {
-       /* morpheus */
-       ha->func.isintr = ips_isintr_morpheus;
-       ha->func.isinit = ips_isinit_morpheus;
-       ha->func.issue = ips_issue_i2o_memio;
-       ha->func.init = ips_init_morpheus;
-       ha->func.statupd = ips_statupd_morpheus;
-       ha->func.reset = ips_reset_morpheus;
-       ha->func.intr = ips_intr_morpheus;
-       ha->func.enableint = ips_enable_int_morpheus;
-    } else if (IPS_USE_MEMIO(ha)) {
-       /* copperhead w/MEMIO */
-       ha->func.isintr = ips_isintr_copperhead_memio;
-       ha->func.isinit = ips_isinit_copperhead_memio;
-       ha->func.init = ips_init_copperhead_memio;
-       ha->func.statupd = ips_statupd_copperhead_memio;
-       ha->func.statinit = ips_statinit_memio;
-       ha->func.reset = ips_reset_copperhead_memio;
-       ha->func.intr = ips_intr_copperhead;
-       ha->func.erasebios = ips_erase_bios_memio;
-       ha->func.programbios = ips_program_bios_memio;
-       ha->func.verifybios = ips_verify_bios_memio;
-       ha->func.enableint = ips_enable_int_copperhead_memio;
-
-       if (IPS_USE_I2O_DELIVER(ha))
-          ha->func.issue = ips_issue_i2o_memio;
-       else
-          ha->func.issue = ips_issue_copperhead_memio;
-    } else {
-       /* copperhead */
-       ha->func.isintr = ips_isintr_copperhead;
-       ha->func.isinit = ips_isinit_copperhead;
-       ha->func.init = ips_init_copperhead;
-       ha->func.statupd = ips_statupd_copperhead;
-       ha->func.statinit = ips_statinit;
-       ha->func.reset = ips_reset_copperhead;
-       ha->func.intr = ips_intr_copperhead;
-       ha->func.erasebios = ips_erase_bios;
-       ha->func.programbios = ips_program_bios;
-       ha->func.verifybios = ips_verify_bios;
-       ha->func.enableint = ips_enable_int_copperhead;
-
-       if (IPS_USE_I2O_DELIVER(ha))
-          ha->func.issue = ips_issue_i2o;
-       else
-          ha->func.issue = ips_issue_copperhead;
-    }
+    ips_setup_funclist(ha);
 
-    if ( IPS_IS_MORPHEUS( ha ) ) {
+    if ( ( IPS_IS_MORPHEUS( ha ) ) || ( IPS_IS_MARCO( ha ) ) ) {
         /* If Morpheus appears dead, reset it */
         IsDead = readl( ha->mem_ptr + IPS_REG_I960_MSG1 );
         if ( IsDead == 0xDEADBEEF ) {
@@ -7691,24 +7634,14 @@
            * Initialization failed
            */
           printk(KERN_WARNING "Unable to initialize controller\n" );
-          ha->active = 0;
-          ips_free(ha);
-          scsi_unregister(sh);
-          ips_ha[index] = 0;
-          ips_sh[index] = 0;
-          return -1;
+          return ips_abort_init(ha, sh, index);
        }
     }
 
     /* Install the interrupt handler */
      if (request_irq(irq, do_ipsintr, SA_SHIRQ, ips_name, ha)) {
        printk(KERN_WARNING "Unable to install interrupt handler\n" );
-       ha->active = 0;
-       ips_free(ha);
-       scsi_unregister(sh);
-       ips_ha[index] = 0;
-       ips_sh[index] = 0;
-       return -1;
+       return ips_abort_init(ha, sh, index);
     }
 
     /*
@@ -7717,13 +7650,8 @@
     ha->max_cmds = 1;
     if (!ips_allocatescbs(ha)) {
        printk(KERN_WARNING "Unable to allocate a CCB\n" );
-       ha->active = 0;
        free_irq(ha->irq, ha);
-       ips_free(ha);
-       scsi_unregister(sh);
-       ips_ha[index] = 0;
-       ips_sh[index] = 0;
-       return -1;
+       return ips_abort_init(ha, sh, index);
     }
 
     *indexPtr = index;
@@ -7759,13 +7687,8 @@
 
     if (!ips_hainit(ha)) {
        printk(KERN_WARNING "Unable to initialize controller\n" );
-       ha->active = 0;
-       ips_free(ha);
        free_irq(ha->irq, ha);
-       scsi_unregister(sh);
-       ips_ha[index] = NULL;
-       ips_sh[index] = NULL;
-       return -1;
+       return ips_abort_init(ha, sh, index);
     }
     /* Free the temporary SCB */
     ips_deallocatescbs(ha, 1);
@@ -7773,13 +7696,8 @@
     /* allocate CCBs */
     if (!ips_allocatescbs(ha)) {
        printk(KERN_WARNING "Unable to allocate CCBs\n" );
-       ha->active = 0;
-       ips_free(ha);
        free_irq(ha->irq, ha);
-       scsi_unregister(sh);
-       ips_ha[index] = NULL;
-       ips_sh[index] = NULL;
-       return -1;
+       return ips_abort_init(ha, sh, index);
     }
 
     /* finish setting values */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/ips.h linux-2.4.21-pre6/drivers/scsi/ips.h
--- linux-2.4.20/drivers/scsi/ips.h	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/ips.h	2003-03-26 23:49:19.000000000 +0000
@@ -1,11 +1,12 @@
 /*****************************************************************************/
-/* ips.h -- driver for the IBM ServeRAID controller                          */
+/* ips.h -- driver for the Adaptec / IBM ServeRAID controller                */
 /*                                                                           */
 /* Written By: Keith Mitchell, IBM Corporation                               */
 /*             Jack Hammer, Adaptec, Inc.                                    */
 /*             David Jeffery, Adaptec, Inc.                                  */
 /*                                                                           */
 /* Copyright (C) 1999 IBM Corporation                                        */
+/* Copyright (C) 2003 Adaptec, Inc.                                          */ 
 /*                                                                           */
 /* This program is free software; you can redistribute it and/or modify      */
 /* it under the terms of the GNU General Public License as published by      */
@@ -42,7 +43,7 @@
 /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 /*                                                                           */
 /* Bugs/Comments/Suggestions should be mailed to:                            */
-/*      ipslinux@adaptec.com     	                                         */
+/*      ipslinux@adaptec.com                                                 */
 /*                                                                           */
 /*****************************************************************************/
 
@@ -60,7 +61,6 @@
    extern int ips_queue(Scsi_Cmnd *, void (*) (Scsi_Cmnd *));
    extern int ips_biosparam(Disk *, kdev_t, int *);
    extern const char * ips_info(struct Scsi_Host *);
-   extern void do_ips(int, void *, struct pt_regs *);
 
    /*
     * Some handy macros
@@ -78,41 +78,19 @@
                                          (ha->revision_id >= IPS_REVID_CLARINETP1) && \
                                          (ha->revision_id <= IPS_REVID_CLARINETP3)) ? 1 : 0)
    #define IPS_IS_MORPHEUS(ha)         (ha->device_id == IPS_DEVICEID_MORPHEUS)
+   #define IPS_IS_MARCO(ha)            (ha->device_id == IPS_DEVICEID_MARCO)
    #define IPS_USE_I2O_DELIVER(ha)     ((IPS_IS_MORPHEUS(ha) || \
                                          (IPS_IS_TROMBONE(ha) && \
                                           (ips_force_i2o))) ? 1 : 0)
-   #define IPS_USE_I2O_STATUS(ha)      (IPS_IS_MORPHEUS(ha))
    #define IPS_USE_MEMIO(ha)           ((IPS_IS_MORPHEUS(ha) || \
                                          ((IPS_IS_TROMBONE(ha) || IPS_IS_CLARINET(ha)) && \
                                           (ips_force_memio))) ? 1 : 0)
 
-   #ifndef VIRT_TO_BUS
-      #define VIRT_TO_BUS(x)           (uint32_t) virt_to_bus((void *) x)
-   #endif
-
    #ifndef MDELAY
       #define MDELAY mdelay
    #endif
-
-   #ifndef verify_area_20
-      #define verify_area_20(t,a,sz)   (0) /* success */
-   #endif
-
-   #ifndef DECLARE_MUTEX_LOCKED
-      #define DECLARE_MUTEX_LOCKED(sem) struct semaphore sem = MUTEX_LOCKED;
-   #endif
    
    /*
-    * Lock macros
-    */
-   #define IPS_SCB_LOCK(cpu_flags)      spin_lock_irqsave(&ha->scb_lock, cpu_flags)
-   #define IPS_SCB_UNLOCK(cpu_flags)    spin_unlock_irqrestore(&ha->scb_lock, cpu_flags)
-   #define IPS_QUEUE_LOCK(queue)        spin_lock_irqsave(&(queue)->lock, (queue)->cpu_flags)
-   #define IPS_QUEUE_UNLOCK(queue)      spin_unlock_irqrestore(&(queue)->lock, (queue)->cpu_flags)
-   #define IPS_HA_LOCK(cpu_flags)       spin_lock_irqsave(&ha->ips_lock, cpu_flags)
-   #define IPS_HA_UNLOCK(cpu_flags)     spin_unlock_irqrestore(&ha->ips_lock, cpu_flags)
-
-   /*
     * Adapter address map equates
     */
    #define IPS_REG_HISR                 0x08    /* Host Interrupt Status Reg   */
@@ -171,7 +149,7 @@
    #define IPS_CMD_DCDB                 0x04
    #define IPS_CMD_DCDB_SG              0x84
    #define IPS_CMD_EXTENDED_DCDB 	    0x95
-	#define IPS_CMD_EXTENDED_DCDB_SG		 0x96
+   #define IPS_CMD_EXTENDED_DCDB_SG	    0x96
    #define IPS_CMD_CONFIG_SYNC          0x58
    #define IPS_CMD_ERROR_TABLE          0x17
    #define IPS_CMD_DOWNLOAD             0x20
@@ -185,6 +163,7 @@
    #define IPS_CSL                      0xFF
    #define IPS_POCL                     0x30
    #define IPS_NORM_STATE               0x00
+   #define IPS_MAX_ADAPTER_TYPES        3
    #define IPS_MAX_ADAPTERS             16
    #define IPS_MAX_IOCTL                1
    #define IPS_MAX_IOCTL_QUEUE          8
@@ -207,15 +186,19 @@
    #define IPS_INTR_IORL                1
    #define IPS_FFDC                     99
    #define IPS_ADAPTER_ID               0xF
-   #define IPS_VENDORID                 0x1014
+   #define IPS_VENDORID_IBM             0x1014
+   #define IPS_VENDORID_ADAPTEC         0x9005
    #define IPS_DEVICEID_COPPERHEAD      0x002E
    #define IPS_DEVICEID_MORPHEUS        0x01BD
+   #define IPS_DEVICEID_MARCO           0x0250
    #define IPS_SUBDEVICEID_4M           0x01BE
    #define IPS_SUBDEVICEID_4L           0x01BF
    #define IPS_SUBDEVICEID_4MX          0x0208
    #define IPS_SUBDEVICEID_4LX          0x020E
    #define IPS_SUBDEVICEID_5I2          0x0259
    #define IPS_SUBDEVICEID_5I1          0x0258
+   #define IPS_SUBDEVICEID_6M           0x0279
+   #define IPS_SUBDEVICEID_6I           0x028C
    #define IPS_IOCTL_SIZE               8192
    #define IPS_STATUS_SIZE              4
    #define IPS_STATUS_Q_SIZE            (IPS_MAX_CMDS+1) * IPS_STATUS_SIZE
@@ -298,6 +281,8 @@
    #define IPS_ADTYPE_SERVERAID4LX      0x0B
    #define IPS_ADTYPE_SERVERAID5I2      0x0C
    #define IPS_ADTYPE_SERVERAID5I1      0x0D
+   #define IPS_ADTYPE_SERVERAID6M       0x0E
+   #define IPS_ADTYPE_SERVERAID6I       0x0F
 
    /*
     * Adapter Command/Status Packet Definitions
@@ -369,27 +354,8 @@
    #define IPS_SCSI_MP3_AllocateSurface 0x08
 
    /*
-    * Configuration Structure Flags
-    */
-   #define IPS_CFG_USEROPT_UPDATECOUNT(cfg)   (((cfg)->UserOpt & 0xffff000) >> 16)
-   #define IPS_CFG_USEROPT_CONCURSTART(cfg)   (((cfg)->UserOpt & 0xf000) >> 12)
-   #define IPS_CFG_USEROPT_STARTUPDELAY(cfg)  (((cfg)->UserOpt & 0xf00) >> 8)
-   #define IPS_CFG_USEROPT_REARRANGE(cfg)     ((cfg)->UserOpt & 0x80)
-   #define IPS_CFG_USEROPT_CDBOOT(cfg)        ((cfg)->UserOpt & 0x40)
-   #define IPS_CFG_USEROPT_CLUSTER(cfg)       ((cfg)->UserOpt & 0x20)
-
-   /*
-    * Host adapter Flags (bit numbers)
-    */
-   #define IPS_IN_INTR                  0
-   #define IPS_IN_ABORT                 1
-   #define IPS_IN_RESET                 2
-
-   /*
     * SCB Flags
     */
-   #define IPS_SCB_ACTIVE               0x00001
-   #define IPS_SCB_WAITING              0x00002
    #define IPS_SCB_MAP_SG               0x00008
    #define IPS_SCB_MAP_SINGLE           0X00010
 
@@ -400,7 +366,6 @@
    #define IPS_COPPIOCCMD              (('C'<<8) | 66)
    #define IPS_NUMCTRLS                (('C'<<8) | 68)
    #define IPS_CTRLINFO                (('C'<<8) | 69)
-   #define IPS_FLASHBIOS               (('C'<<8) | 70)
 
    /* flashing defines */
    #define IPS_FW_IMAGE                0x00
@@ -455,7 +420,7 @@
     use_clustering : ENABLE_CLUSTERING,   \
     use_new_eh_code : 1                   \
 }
-#else
+#elif LINUX_VERSION_CODE < LinuxVersionCode(2,5,0)
  #define IPS {                            \
     next : NULL,                          \
     module : NULL,                        \
@@ -484,10 +449,39 @@
     use_clustering : ENABLE_CLUSTERING,   \
     use_new_eh_code : 1                   \
 }
+#else
+ #define IPS {                            \
+    next : NULL,                          \
+    module : NULL,                        \
+    proc_info : NULL,                     \
+    name : NULL,                          \
+    detect : ips_detect,                  \
+    release : ips_release,                \
+    info : ips_info,                      \
+    command : NULL,                       \
+    queuecommand : ips_queue,             \
+    eh_strategy_handler : NULL,           \
+    eh_abort_handler : ips_eh_abort,      \
+    eh_device_reset_handler : NULL,       \
+    eh_bus_reset_handler : NULL,          \
+    eh_host_reset_handler : ips_eh_reset, \
+    abort : NULL,                         \
+    reset : NULL,                         \
+    slave_attach : NULL,                  \
+    bios_param : ips_biosparam,           \
+    can_queue : 0,                        \
+    this_id: -1,                          \
+    sg_tablesize : IPS_MAX_SG,            \
+    cmd_per_lun: 16,                      \
+    present : 0,                          \
+    unchecked_isa_dma : 0,                \
+    use_clustering : ENABLE_CLUSTERING,   \
+    highmem_io : 1                        \
+}
 #endif
 
 /*
- * IBM PCI Raid Command Formats
+ * Raid Command Formats
  */
 typedef struct {
    uint8_t  op_code;
@@ -765,7 +759,7 @@
    uint16_t usConfigUpdateCount;
    uint8_t  ucBlkFlag;
    uint8_t  reserved;
-   uint16_t usAddrDeadDisk[IPS_MAX_CHANNELS * IPS_MAX_TARGETS];
+   uint16_t usAddrDeadDisk[IPS_MAX_CHANNELS * (IPS_MAX_TARGETS + 1)];
 } IPS_ENQ, *PIPS_ENQ;
 
 typedef struct {
@@ -841,7 +835,8 @@
    uint8_t   ReservedForOS2[8];
    uint8_t   bios_high[4];                 /* Adapter's Flashed BIOS Version   */
    uint8_t   bios_low[4];
-   uint8_t   Filler[76];
+   uint8_t   adapter_order[16];            /* BIOS Telling us the Sort Order   */
+   uint8_t   Filler[60];
 } IPS_NVRAM_P5, *PIPS_NVRAM_P5;
 
 /*--------------------------------------------------------------------------*/
@@ -1007,19 +1002,6 @@
    int   option_value;
 } IPS_OPTION;
 
-typedef struct {
-   void             *userbuffer;
-   uint32_t          usersize;
-   void             *kernbuffer;
-   uint32_t          kernsize;
-   void             *ha;
-   void             *SC;
-   void             *pt;
-   struct semaphore *sem;
-   uint32_t          offset;
-   uint32_t          retcode;
-} IPS_FLASH_DATA;
-
 /*
  * Status Info
  */
@@ -1036,8 +1018,6 @@
    struct ips_scb *head;
    struct ips_scb *tail;
    int             count;
-   unsigned long   cpu_flags;
-   spinlock_t      lock;
 } ips_scb_queue_t;
 
 /*
@@ -1047,13 +1027,10 @@
    Scsi_Cmnd      *head;
    Scsi_Cmnd      *tail;
    int             count;
-   unsigned long   cpu_flags;
-   spinlock_t      lock;
 } ips_wait_queue_t;
 
 typedef struct ips_copp_wait_item {
    Scsi_Cmnd                 *scsi_cmd;
-   struct semaphore          *sem;
    struct ips_copp_wait_item *next;
 } ips_copp_wait_item_t;
 
@@ -1061,8 +1038,6 @@
    struct ips_copp_wait_item *head;
    struct ips_copp_wait_item *tail;
    int                        count;
-   unsigned long              cpu_flags;
-   spinlock_t                 lock;
 } ips_copp_queue_t;
 
 /* forward decl for host structure */
@@ -1111,7 +1086,6 @@
    char              *ioctl_data;         /* IOCTL data area            */
    uint32_t           ioctl_datasize;     /* IOCTL data size            */
    uint32_t           cmd_in_progress;    /* Current command in progress*/
-   unsigned long      flags;              /* HA flags                   */
    uint8_t            waitflag;           /* are we waiting for cmd     */
    uint8_t            active;
    int                ioctl_reset;        /* IOCTL Requested Reset Flag */
@@ -1122,7 +1096,6 @@
    uint8_t            slot_num;           /* PCI Slot Number            */
    uint16_t           subdevice_id;       /* Subsystem device ID        */
    uint8_t            ioctl_order;        /* Number of pages in ioctl   */
-   uint8_t            reserved2;          /* Empty                      */
    uint8_t            bios_version[8];    /* BIOS Revision              */
    uint32_t           mem_addr;           /* Memory mapped address      */
    uint32_t           io_len;             /* Size of IO Address         */
@@ -1131,14 +1104,10 @@
    char              *ioremap_ptr;        /* ioremapped memory pointer  */
    ips_hw_func_t      func;               /* hw function pointers       */
    struct pci_dev    *pcidev;             /* PCI device handle          */
-   spinlock_t         scb_lock;
-   spinlock_t         copp_lock;
-   spinlock_t         ips_lock;
-   struct semaphore   ioctl_sem;          /* Semaphore for new IOCTL's  */
-   struct semaphore   flash_ioctl_sem;    /* Semaphore for Flashing     */
    char              *flash_data;         /* Save Area for flash data   */
-   u8                 flash_order;        /* Save Area for flash size order  */
-   u32                flash_datasize;   /* Save Area for flash data size */
+   u8                 flash_order;        /* Save Area for flash size order */
+   u32                flash_datasize;     /* Save Area for flash data size */
+   uint8_t            requires_esl;       /* Requires an EraseStripeLock */
 } ips_ha_t;
 
 typedef void (*ips_scb_callback) (ips_ha_t *, struct ips_scb *);
@@ -1168,7 +1137,6 @@
    Scsi_Cmnd        *scsi_cmd;
    struct ips_scb   *q_next;
    ips_scb_callback  callback;
-   struct semaphore *sem;
    uint32_t          sg_busaddr;
    int               sg_count;
 } ips_scb_t;
@@ -1224,44 +1192,46 @@
 *
 *************************************************************************/
 
-#define IPS_VER_MAJOR 5
-#define IPS_VER_MAJOR_STRING "5"
-#define IPS_VER_MINOR 10
-#define IPS_VER_MINOR_STRING "10"
-#define IPS_VER_BUILD 21
-#define IPS_VER_BUILD_STRING "21"
-#define IPS_VER_STRING "5.10.21"
-#define IPS_LEGALCOPYRIGHT_STRING "(C) Copyright IBM Corp. 1994, 2002. All Rights Reserved."
+#define IPS_VER_MAJOR 6
+#define IPS_VER_MAJOR_STRING "6"
+#define IPS_VER_MINOR 00
+#define IPS_VER_MINOR_STRING "00"
+#define IPS_VER_BUILD 26
+#define IPS_VER_BUILD_STRING "26"
+#define IPS_VER_STRING "6.00.26"
+#define IPS_LEGALCOPYRIGHT_STRING "(C) Copyright IBM Corp. 1994, 2003. All Rights Reserved."
 #define IPS_ADAPTECCOPYRIGHT_STRING "(c) Copyright Adaptec, Inc. 2002 to present. All Rights Reserved."
-#define IPS_NT_LEGALCOPYRIGHT_STRING "(C) Copyright IBM Corp. 1994, 2002."
+#define IPS_NT_LEGALCOPYRIGHT_STRING "(C) Copyright IBM Corp. 1994, 2003."
 
 /* Version numbers for various adapters */
 #define IPS_VER_SERVERAID1 "2.25.01"
 #define IPS_VER_SERVERAID2 "2.88.13"
 #define IPS_VER_NAVAJO "2.88.13"
-#define IPS_VER_SERVERAID3 "5.10.21"
-#define IPS_VER_SERVERAID4H "5.10.21"
-#define IPS_VER_SERVERAID4MLx "5.10.21"
-#define IPS_VER_SARASOTA "5.10.21"
+#define IPS_VER_SERVERAID3 "6.00.26"
+#define IPS_VER_SERVERAID4H "6.00.26"
+#define IPS_VER_SERVERAID4MLx "6.00.26"
+#define IPS_VER_SARASOTA "6.00.26"
+#define IPS_VER_MARCO "6.00.26"
 
 /* Compatability IDs for various adapters */
 #define IPS_COMPAT_UNKNOWN ""
-#define IPS_COMPAT_CURRENT "SA510"
+#define IPS_COMPAT_CURRENT "MR600"
 #define IPS_COMPAT_SERVERAID1 "2.25.01"
 #define IPS_COMPAT_SERVERAID2 "2.88.13"
 #define IPS_COMPAT_NAVAJO  "2.88.13"
 #define IPS_COMPAT_KIOWA "2.88.13"
-#define IPS_COMPAT_SERVERAID3H  "SA510"
-#define IPS_COMPAT_SERVERAID3L  "SA510"
-#define IPS_COMPAT_SERVERAID4H  "SA510"
-#define IPS_COMPAT_SERVERAID4M  "SA510"
-#define IPS_COMPAT_SERVERAID4L  "SA510"
-#define IPS_COMPAT_SERVERAID4Mx "SA510"
-#define IPS_COMPAT_SERVERAID4Lx "SA510"
-#define IPS_COMPAT_SARASOTA     "SA510"
-#define IPS_COMPAT_BIOS "SA510"
+#define IPS_COMPAT_SERVERAID3H  "MR600"
+#define IPS_COMPAT_SERVERAID3L  "MR600"
+#define IPS_COMPAT_SERVERAID4H  "MR600"
+#define IPS_COMPAT_SERVERAID4M  "MR600"
+#define IPS_COMPAT_SERVERAID4L  "MR600"
+#define IPS_COMPAT_SERVERAID4Mx "MR600"
+#define IPS_COMPAT_SERVERAID4Lx "MR600"
+#define IPS_COMPAT_SARASOTA     "MR600"
+#define IPS_COMPAT_MARCO        "MR600"
+#define IPS_COMPAT_BIOS "MR600"
 
-#define IPS_COMPAT_MAX_ADAPTER_TYPE 14
+#define IPS_COMPAT_MAX_ADAPTER_TYPE 15
 #define IPS_COMPAT_ID_LENGTH 8
 
 #define IPS_DEFINE_COMPAT_TABLE(tablename) \
@@ -1278,8 +1248,9 @@
       IPS_COMPAT_SERVERAID4L, \
       IPS_COMPAT_SERVERAID4Mx, \
       IPS_COMPAT_SERVERAID4Lx, \
-      IPS_COMPAT_SARASOTA, \
-      IPS_COMPAT_SARASOTA \
+      IPS_COMPAT_SARASOTA,         /* one-channel variety of SARASOTA */  \
+      IPS_COMPAT_SARASOTA,         /* two-channel variety of SARASOTA */  \
+      IPS_COMPAT_MARCO \
    }
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/mac_scsi.c linux-2.4.21-pre6/drivers/scsi/mac_scsi.c
--- linux-2.4.20/drivers/scsi/mac_scsi.c	2002-02-25 19:38:04.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/mac_scsi.c	2003-03-26 23:49:00.000000000 +0000
@@ -25,26 +25,10 @@
  * 1+ (800) 334-5454
  */
 
-
-/*
- * Options :
- *
- * PARITY - enable parity checking.  Not supported.
- *
- * SCSI2 - enable support for SCSI-II tagged queueing.  Untested.
- *
- * USLEEP - enable support for devices that don't disconnect.  Untested.
- */
-
 /*
  * $Log: mac_NCR5380.c,v $
  */
 
-#define AUTOSENSE
-#if 0
-#define PSEUDO_DMA
-#endif
-
 #include <linux/types.h>
 #include <linux/stddef.h>
 #include <linux/ctype.h>
@@ -81,33 +65,28 @@
 #define RESET_BOOT
 #define DRIVER_SETUP
 
-/*
- * BUG can be used to trigger a strange code-size related hang on 2.1 kernels
- */
-#ifdef BUG
-#undef RESET_BOOT
-#undef DRIVER_SETUP
-#endif
-
 #define	ENABLE_IRQ()	mac_enable_irq( IRQ_MAC_SCSI ); 
 #define	DISABLE_IRQ()	mac_disable_irq( IRQ_MAC_SCSI );
 
+extern void via_scsi_clear(void);
+
 #ifdef RESET_BOOT
 static void mac_scsi_reset_boot(struct Scsi_Host *instance);
 #endif
-static char macscsi_read(struct Scsi_Host *instance, int reg);
-static void macscsi_write(struct Scsi_Host *instance, int reg, int value);
 
+static __inline__ char macscsi_read(struct Scsi_Host *instance, int reg);
+static __inline__ void macscsi_write(struct Scsi_Host *instance, int reg, int value);
+
+static int setup_called = 0;
 static int setup_can_queue = -1;
 static int setup_cmd_per_lun = -1;
 static int setup_sg_tablesize = -1;
+static int setup_use_pdma = -1;
 #ifdef SUPPORT_TAGS
 static int setup_use_tagged_queuing = -1;
 #endif
 static int setup_hostid = -1;
 
-static int polled_scsi_on = 0;
-
 /* Time (in jiffies) to wait after a reset; the SCSI standard calls for 250ms,
  * we usually do 0.5s to be on the safe side. But Toshiba CD-ROMs once more
  * need ten times the standard value... */
@@ -124,44 +103,27 @@
 static volatile unsigned char *mac_scsi_nodrq = NULL;
 
 /*
- * Function : mac_scsi_setup(char *str, int *ints)
+ * Function : mac_scsi_setup(char *str)
  *
  * Purpose : booter command line initialization of the overrides array,
  *
- * Inputs : str - unused, ints - array of integer parameters with ints[0]
- *	equal to the number of ints.
+ * Inputs : str - comma delimited list of options
  *
  */
 
-static int __init mac_scsi_setup(char *str, int *ints) {
-#ifdef DRIVER_SETUP
-	/* Format of mac5380 parameter is:
-	 *   mac5380=<can_queue>,<cmd_per_lun>,<sg_tablesize>,<hostid>,<use_tags>
-	 * Negative values mean don't change.
-	 */
+static int __init mac_scsi_setup(char *str) {
+#ifdef DRIVER_SETUP	
+	int ints[7];
 	
-	/* Grmbl... the standard parameter parsing can't handle negative numbers
-	 * :-( So let's do it ourselves!
-	 */
-
-	int i = ints[0]+1, fact;
-
-	while( str && (isdigit(*str) || *str == '-') && i <= 10) {
-		if (*str == '-')
-			fact = -1, ++str;
-		else
-			fact = 1;
-		ints[i++] = simple_strtoul( str, NULL, 0 ) * fact;
-		if ((str = strchr( str, ',' )) != NULL)
-			++str;
-	}
-	ints[0] = i-1;
+	(void)get_options( str, ARRAY_SIZE(ints), ints);
 	
-	if (ints[0] < 1) {
-		printk( "mac_scsi_setup: no arguments!\n" );
-		return 0;
+	if (setup_called++ || ints[0] < 1 || ints[0] > 6) {
+	    printk(KERN_WARNING "scsi: <mac5380>"
+		" Usage: mac5380=<can_queue>[,<cmd_per_lun>,<sg_tablesize>,<hostid>,<use_tags>,<use_pdma>]\n");
+	    printk(KERN_ALERT "scsi: <mac5380> Bad Penguin parameters?\n");
+	    return 0;
 	}
-
+	    
 	if (ints[0] >= 1) {
 		if (ints[1] > 0)
 			/* no limits on this, just > 0 */
@@ -184,25 +146,31 @@
 		if (ints[4] >= 0 && ints[4] <= 7)
 			setup_hostid = ints[4];
 		else if (ints[4] > 7)
-			printk( "mac_scsi_setup: invalid host ID %d !\n", ints[4] );
+			printk(KERN_WARNING "mac_scsi_setup: invalid host ID %d !\n", ints[4] );
 	}
-#ifdef SUPPORT_TAGS
+#ifdef SUPPORT_TAGS	
 	if (ints[0] >= 5) {
 		if (ints[5] >= 0)
 			setup_use_tagged_queuing = !!ints[5];
 	}
+	
+	if (ints[0] == 6) {
+	    if (ints[6] >= 0)
+		setup_use_pdma = ints[6];
+	}
+#else
+	if (ints[0] == 5) {
+	    if (ints[5] >= 0)
+		setup_use_pdma = ints[5];
+	}
 #endif
+	
 #endif
-	return 1; 
+	return 1;
 }
 
 __setup("mac5380=", mac_scsi_setup);
 
-#if 0
-#define MAC_ADDRESS(card) (ecard_address((card), ECARD_IOC, ECARD_SLOW) + 0x800)
-#define MAC_IRQ(card)     ((card)->irq)
-#endif
-
 /*
  * XXX: status debug
  */
@@ -222,93 +190,89 @@
  
 int macscsi_detect(Scsi_Host_Template * tpnt)
 {
-    int count = 0;
     static int called = 0;
+    int flags = 0;
     struct Scsi_Host *instance;
 
     if (!MACH_IS_MAC || called)
 	return( 0 );
 
     if (macintosh_config->scsi_type != MAC_SCSI_OLD)
-	 return( 0 );
-
-    tpnt->proc_name = "mac5380";
+	return( 0 );
 
     /* setup variables */
     tpnt->can_queue =
-      (setup_can_queue > 0) ? setup_can_queue : CAN_QUEUE;
+	(setup_can_queue > 0) ? setup_can_queue : CAN_QUEUE;
     tpnt->cmd_per_lun =
-      (setup_cmd_per_lun > 0) ? setup_cmd_per_lun : CMD_PER_LUN;
+	(setup_cmd_per_lun > 0) ? setup_cmd_per_lun : CMD_PER_LUN;
     tpnt->sg_tablesize = 
-      (setup_sg_tablesize >= 0) ? setup_sg_tablesize : SG_TABLESIZE;
+	(setup_sg_tablesize >= 0) ? setup_sg_tablesize : SG_TABLESIZE;
 
     if (setup_hostid >= 0)
-      tpnt->this_id = setup_hostid;
+	tpnt->this_id = setup_hostid;
     else {
-      /* use 7 as default */
-      tpnt->this_id = 7;
+	/* use 7 as default */
+	tpnt->this_id = 7;
     }
 
 #ifdef SUPPORT_TAGS
-	if (setup_use_tagged_queuing < 0)
-		setup_use_tagged_queuing = DEFAULT_USE_TAGGED_QUEUING;
+    if (setup_use_tagged_queuing < 0)
+	setup_use_tagged_queuing = USE_TAGGED_QUEUING;
 #endif
 
-#if 0	/* loop over multiple adapters (Powerbooks ??) */
-    for (count = 0; count < mac_num_scsi; count++) {
-#endif
-        instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
-        if(instance == NULL)
-        	continue;
-	default_instance = instance;
-
-	if (macintosh_config->ident == MAC_MODEL_IIFX) {
-		mac_scsi_regp  = via1+0x8000;
-		mac_scsi_drq   = via1+0xE000;
-		mac_scsi_nodrq = via1+0xC000;
-	} else {
-		mac_scsi_regp  = via1+0x10000;
-		mac_scsi_drq   = via1+0x6000;
-		mac_scsi_nodrq = via1+0x12000;
-	}
-
+    /* Once we support multiple 5380s (e.g. DuoDock) we'll do
+       something different here */
+    instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
+    default_instance = instance;
+    
+    if (macintosh_config->ident == MAC_MODEL_IIFX) {
+	mac_scsi_regp  = via1+0x8000;
+	mac_scsi_drq   = via1+0xE000;
+	mac_scsi_nodrq = via1+0xC000;
+	/* The IIFX should be able to do true DMA, but pseudo-dma doesn't work */
+	flags = FLAG_NO_PSEUDO_DMA;
+    } else {
+	mac_scsi_regp  = via1+0x10000;
+	mac_scsi_drq   = via1+0x6000;
+	mac_scsi_nodrq = via1+0x12000;
+    }
 
-        instance->io_port = (unsigned long) mac_scsi_regp;
-	instance->irq = IRQ_MAC_SCSI;
+    if (! setup_use_pdma)
+	flags = FLAG_NO_PSEUDO_DMA;
+	
+    instance->io_port = (unsigned long) mac_scsi_regp;
+    instance->irq = IRQ_MAC_SCSI;
 
-#ifdef RESET_BOOT
-	mac_scsi_reset_boot(instance);
+#ifdef RESET_BOOT   
+    mac_scsi_reset_boot(instance);
 #endif
+    
+    NCR5380_init(instance, flags);
 
-	NCR5380_init(instance, 0);
+    instance->n_io_port = 255;
 
-	instance->n_io_port = 255;
+    ((struct NCR5380_hostdata *)instance->hostdata)->ctrl = 0;
 
-        ((struct NCR5380_hostdata *)instance->hostdata)->ctrl = 0;
+    if (instance->irq != IRQ_NONE)
+	if (request_irq(instance->irq, NCR5380_intr, IRQ_FLG_SLOW, 
+		"ncr5380", NCR5380_intr)) {
+	    printk(KERN_WARNING "scsi%d: IRQ%d not free, interrupts disabled\n",
+		   instance->host_no, instance->irq);
+	    instance->irq = IRQ_NONE;
+	}
 
-	if (instance->irq != IRQ_NONE)
-	    if (request_irq(instance->irq, NCR5380_intr, IRQ_FLG_SLOW, "ncr5380", NCR5380_intr)) {
-		printk("scsi%d: IRQ%d not free, interrupts disabled\n",
-		    instance->host_no, instance->irq);
-		instance->irq = IRQ_NONE;
-	    }
-
-	printk("scsi%d: generic 5380 at port %lX irq", instance->host_no, instance->io_port);
-	if (instance->irq == IRQ_NONE)
-	    printk ("s disabled");
-	else
-	    printk (" %d", instance->irq);
-	printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
-	    instance->can_queue, instance->cmd_per_lun, MACSCSI_PUBLIC_RELEASE);
-	printk("\nscsi%d:", instance->host_no);
-	NCR5380_print_options(instance);
-	printk("\n");
-#if 0	/* multiple adapters */
-    }
-#endif
+    printk(KERN_INFO "scsi%d: generic 5380 at port %lX irq", instance->host_no, instance->io_port);
+    if (instance->irq == IRQ_NONE)
+	printk (KERN_INFO "s disabled");
+    else
+	printk (KERN_INFO " %d", instance->irq);
+    printk(KERN_INFO " options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
+	   instance->can_queue, instance->cmd_per_lun, MACSCSI_PUBLIC_RELEASE);
+    printk(KERN_INFO "\nscsi%d:", instance->host_no);
+    NCR5380_print_options(instance);
+    printk("\n");
     called = 1;
     return 1;
-
 }
 
 int macscsi_release (struct Scsi_Host *shpnt)
@@ -336,10 +300,10 @@
 	 * with the queues, interrupts, or locks necessary here.
 	 */
 
-	printk( "Macintosh SCSI: resetting the SCSI bus..." );
+	printk(KERN_INFO "Macintosh SCSI: resetting the SCSI bus..." );
 
 	/* switch off SCSI IRQ - catch an interrupt without IRQ bit set else */
-       	mac_disable_irq(IRQ_MAC_SCSI);
+	mac_disable_irq(IRQ_MAC_SCSI);
 
 	/* get in phase */
 	NCR5380_write( TARGET_COMMAND_REG,
@@ -357,207 +321,22 @@
 		barrier();
 
 	/* switch on SCSI IRQ again */
-       	mac_enable_irq(IRQ_MAC_SCSI);
+	mac_enable_irq(IRQ_MAC_SCSI);
 
-	printk( " done\n" );
+	printk(KERN_INFO " done\n" );
 }
 #endif
 
 const char * macscsi_info (struct Scsi_Host *spnt) {
-    return "";
-}
-
-void restore_irq(struct pt_regs *regs)
-{
-	unsigned long flags;
-
-	save_flags(flags);
-	flags = (flags & ~0x0700) | (regs->sr & 0x0700);
-	restore_flags(flags);
+	return "";
 }
 
 /*
- * pseudo-DMA transfer functions, copied and modified from Russel King's
- * ARM 5380 driver (cumana_1)
- *
- * Work in progress (sort of), didn't work last time I checked, don't use!
- */
-
-#ifdef NOT_EFFICIENT
-#define CTRL(p,v)     outb(*ctrl = (v), (p) - 577)
-#define STAT(p)       inb((p)+1)
-#define IN(p)         inb((p))
-#define OUT(v,p)      outb((v), (p))
-#else
-#if 0
-#define CTRL(p,v)	(p[-2308] = (*ctrl = (v)))
-#else
-#define CTRL(p,v)	(*ctrl = (v))
-#endif
-#define STAT(p)		(p[1<<4])
-#define IN(p)		(*(p))
-#define IN2(p)		((unsigned short)(*(volatile unsigned long *)(p)))
-#define OUT(v,p)	(*(p) = (v))
-#define OUT2(v,p)	(*((volatile unsigned long *)(p)) = (v))
-#endif
-#define L(v)		(((v)<<16)|((v) & 0x0000ffff))
-#define H(v)		(((v)>>16)|((v) & 0xffff0000))
-#define ioaddr(v)	(v)
-
-static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *addr,
-              int len)
-{
-  int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
-  int oldctrl = *ctrl;
-  unsigned long *laddr;
-#ifdef NOT_EFFICIENT
-  int iobase = instance->io_port;
-  int dma_io = mac_scsi_nodrq;
-#else
-  volatile unsigned char *iobase = (unsigned char *)ioaddr(instance->io_port);
-  volatile unsigned char *dma_io = (unsigned char *)(mac_scsi_nodrq);
-#endif
-
-  if(!len) return 0;
-
-  CTRL(iobase, 0x02);
-  laddr = (unsigned long *)addr;
-  while(len >= 32)
-  {
-    int status;
-    unsigned long v;
-    status = STAT(iobase);
-    if(status & 0x80)
-      goto end;
-    if(!(status & 0x40))
-      continue;
-    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
-    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
-    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
-    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
-    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
-    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
-    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
-    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
-    len -= 32;
-    if(len == 0)
-      break;
-  }
-
-  addr = (unsigned char *)laddr;
-  CTRL(iobase, 0x12);
-  while(len > 0)
-  {
-    int status;
-    status = STAT(iobase);
-    if(status & 0x80)
-      goto end;
-    if(status & 0x40)
-    {
-      OUT(*addr++, dma_io);
-      if(--len == 0)
-        break;
-    }
-
-    status = STAT(iobase);
-    if(status & 0x80)
-      goto end;
-    if(status & 0x40)
-    {
-      OUT(*addr++, dma_io);
-      if(--len == 0)
-        break;
-    }
-  }
-end:
-  CTRL(iobase, oldctrl|0x40);
-  return len;
-}
-
-static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *addr,
-              int len)
-{
-  int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
-  int oldctrl = *ctrl;
-  unsigned long *laddr;
-#ifdef NOT_EFFICIENT
-  int iobase = instance->io_port;
-  int dma_io = mac_scsi_nodrq;
-#else
-  volatile unsigned char *iobase = (unsigned char *)ioaddr(instance->io_port);
-  volatile unsigned char *dma_io = (unsigned char *)((int)mac_scsi_nodrq);
-#endif
-
-  if(!len) return 0;
-
-  CTRL(iobase, 0x00);
-  laddr = (unsigned long *)addr;
-  while(len >= 32)
-  {
-    int status;
-    status = STAT(iobase);
-    if(status & 0x80)
-      goto end;
-    if(!(status & 0x40))
-      continue;
-    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
-    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
-    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
-    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
-    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
-    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
-    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
-    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
-    len -= 32;
-    if(len == 0)
-      break;
-  }
-
-  addr = (unsigned char *)laddr;
-  CTRL(iobase, 0x10);
-  while(len > 0)
-  {
-    int status;
-    status = STAT(iobase);
-    if(status & 0x80)
-      goto end;
-    if(status & 0x40)
-    {
-      *addr++ = IN(dma_io);
-      if(--len == 0)
-        break;
-    }
-
-    status = STAT(iobase);
-    if(status & 0x80)
-      goto end;
-    if(status & 0x40)
-    {
-      *addr++ = IN(dma_io);
-      if(--len == 0)
-        break;
-    }
-  }
-end:
-  CTRL(iobase, oldctrl|0x40);
-  return len;
-}
-
-#undef STAT
-#undef CTRL
-#undef IN
-#undef OUT
-
-/*
  * NCR 5380 register access functions
  */
 
-#ifdef ORIG
-#if 0
-#define CTRL(p,v) outb(*ctrl = (v), (p) - 577)
-#else
+/* Debug versions
 #define CTRL(p,v) (*ctrl = (v))
-#endif
 
 static char macscsi_read(struct Scsi_Host *instance, int reg)
 {
@@ -566,11 +345,7 @@
   int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
 
   CTRL(iobase, 0);
-#if 0
-  i = inb(iobase + 64 + reg);
-#else
-  i = inb(iobase + reg<<4);
-#endif
+  i = in_8(iobase + (reg<<4));
   CTRL(iobase, 0x40);
 
   return i;
@@ -582,87 +357,224 @@
   int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
 
   CTRL(iobase, 0);
-#if 0
-  outb(value, iobase + 64 + reg);
-#else
-  outb(value, iobase + reg<<4);
-#endif
+  out_8(value, iobase + (reg<<4));
   CTRL(iobase, 0x40);
 }
+*/
 
-#undef CTRL
-
-#else
-static char macscsi_read(struct Scsi_Host *instance, int reg)
+/* Fast versions */
+static __inline__ char macscsi_read(struct Scsi_Host *instance, int reg)
 {
-	return( mac_scsi_regp[reg << 4] );
+  return in_8(instance->io_port + (reg<<4));
 }
 
-static void macscsi_write(struct Scsi_Host *instance, int reg, int value)
-{
-	mac_scsi_regp[reg << 4] = value;
+static __inline__ void macscsi_write(struct Scsi_Host *instance, int reg, int value)
+{
+  out_8(value, instance->io_port + (reg<<4));
+}
+
+
+/* 
+   Pseudo-DMA: (Ove Edlund)
+   The code attempts to catch bus errors that occur if one for example
+   "trips over the cable".
+   XXX: Since bus errors in the PDMA routines never happen on my 
+   computer, the bus error code is untested. 
+   If the code works as intended, a bus error results in Pseudo-DMA 
+   beeing disabled, meaning that the driver switches to slow handshake. 
+   If bus errors are NOT extremely rare, this has to be changed. 
+*/
+
+#define CP_IO_TO_MEM(s,d,len)				\
+__asm__ __volatile__					\
+    ("    cmp.w  #4,%2\n"				\
+     "    bls    8f\n"					\
+     "    move.w %1,%%d0\n"				\
+     "    neg.b  %%d0\n"				\
+     "    and.w  #3,%%d0\n"				\
+     "    sub.w  %%d0,%2\n"				\
+     "    bra    2f\n"					\
+     " 1: move.b (%0),(%1)+\n"				\
+     " 2: dbf    %%d0,1b\n"				\
+     "    move.w %2,%%d0\n"				\
+     "    lsr.w  #5,%%d0\n"				\
+     "    bra    4f\n"					\
+     " 3: move.l (%0),(%1)+\n"				\
+     "31: move.l (%0),(%1)+\n"				\
+     "32: move.l (%0),(%1)+\n"				\
+     "33: move.l (%0),(%1)+\n"				\
+     "34: move.l (%0),(%1)+\n"				\
+     "35: move.l (%0),(%1)+\n"				\
+     "36: move.l (%0),(%1)+\n"				\
+     "37: move.l (%0),(%1)+\n"				\
+     " 4: dbf    %%d0,3b\n"				\
+     "    move.w %2,%%d0\n"				\
+     "    lsr.w  #2,%%d0\n"				\
+     "    and.w  #7,%%d0\n"				\
+     "    bra    6f\n"					\
+     " 5: move.l (%0),(%1)+\n"				\
+     " 6: dbf    %%d0,5b\n"				\
+     "    and.w  #3,%2\n"				\
+     "    bra    8f\n"					\
+     " 7: move.b (%0),(%1)+\n"				\
+     " 8: dbf    %2,7b\n"				\
+     "    moveq.l #0, %2\n"				\
+     " 9: \n"						\
+     ".section .fixup,\"ax\"\n"				\
+     "    .even\n"					\
+     "90: moveq.l #1, %2\n"				\
+     "    jra 9b\n"					\
+     ".previous\n"					\
+     ".section __ex_table,\"a\"\n"			\
+     "   .align 4\n"					\
+     "   .long  1b,90b\n"				\
+     "   .long  3b,90b\n"				\
+     "   .long 31b,90b\n"				\
+     "   .long 32b,90b\n"				\
+     "   .long 33b,90b\n"				\
+     "   .long 34b,90b\n"				\
+     "   .long 35b,90b\n"				\
+     "   .long 36b,90b\n"				\
+     "   .long 37b,90b\n"				\
+     "   .long  5b,90b\n"				\
+     "   .long  7b,90b\n"				\
+     ".previous"					\
+     : "=a"(s), "=a"(d), "=d"(len)			\
+     : "0"(s), "1"(d), "2"(len)				\
+     : "d0")
+
+
+static int macscsi_pread (struct Scsi_Host *instance,
+			  unsigned char *dst, int len)
+{
+   unsigned char *d;
+   volatile unsigned char *s;
+
+   NCR5380_local_declare();
+   NCR5380_setup(instance);
+
+   s = mac_scsi_drq+0x60;
+   d = dst;
+
+/* These conditions are derived from MacOS */
+
+   while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ) 
+         && !(NCR5380_read(STATUS_REG) & SR_REQ))
+      ;
+   if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ) 
+         && (NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH)) {
+      printk(KERN_ERR "Error in macscsi_pread\n");
+      return -1;
+   }
+
+   CP_IO_TO_MEM(s, d, len);
+   
+   if (len != 0) {
+      printk(KERN_NOTICE "Bus error in macscsi_pread\n");
+      return -1;
+   }
+   
+   return 0;
+}
+
+
+#define CP_MEM_TO_IO(s,d,len)				\
+__asm__ __volatile__					\
+    ("    cmp.w  #4,%2\n"				\
+     "    bls    8f\n"					\
+     "    move.w %0,%%d0\n"				\
+     "    neg.b  %%d0\n"				\
+     "    and.w  #3,%%d0\n"				\
+     "    sub.w  %%d0,%2\n"				\
+     "    bra    2f\n"					\
+     " 1: move.b (%0)+,(%1)\n"				\
+     " 2: dbf    %%d0,1b\n"				\
+     "    move.w %2,%%d0\n"				\
+     "    lsr.w  #5,%%d0\n"				\
+     "    bra    4f\n"					\
+     " 3: move.l (%0)+,(%1)\n"				\
+     "31: move.l (%0)+,(%1)\n"				\
+     "32: move.l (%0)+,(%1)\n"				\
+     "33: move.l (%0)+,(%1)\n"				\
+     "34: move.l (%0)+,(%1)\n"				\
+     "35: move.l (%0)+,(%1)\n"				\
+     "36: move.l (%0)+,(%1)\n"				\
+     "37: move.l (%0)+,(%1)\n"				\
+     " 4: dbf    %%d0,3b\n"				\
+     "    move.w %2,%%d0\n"				\
+     "    lsr.w  #2,%%d0\n"				\
+     "    and.w  #7,%%d0\n"				\
+     "    bra    6f\n"					\
+     " 5: move.l (%0)+,(%1)\n"				\
+     " 6: dbf    %%d0,5b\n"				\
+     "    and.w  #3,%2\n"				\
+     "    bra    8f\n"					\
+     " 7: move.b (%0)+,(%1)\n"				\
+     " 8: dbf    %2,7b\n"				\
+     "    moveq.l #0, %2\n"				\
+     " 9: \n"						\
+     ".section .fixup,\"ax\"\n"				\
+     "    .even\n"					\
+     "90: moveq.l #1, %2\n"				\
+     "    jra 9b\n"					\
+     ".previous\n"					\
+     ".section __ex_table,\"a\"\n"			\
+     "   .align 4\n"					\
+     "   .long  1b,90b\n"				\
+     "   .long  3b,90b\n"				\
+     "   .long 31b,90b\n"				\
+     "   .long 32b,90b\n"				\
+     "   .long 33b,90b\n"				\
+     "   .long 34b,90b\n"				\
+     "   .long 35b,90b\n"				\
+     "   .long 36b,90b\n"				\
+     "   .long 37b,90b\n"				\
+     "   .long  5b,90b\n"				\
+     "   .long  7b,90b\n"				\
+     ".previous"					\
+     : "=a"(s), "=a"(d), "=d"(len)			\
+     : "0"(s), "1"(d), "2"(len)				\
+     : "d0")
+
+static int macscsi_pwrite (struct Scsi_Host *instance,
+				  unsigned char *src, int len)
+{
+   unsigned char *s;
+   volatile unsigned char *d;
+
+   NCR5380_local_declare();
+   NCR5380_setup(instance);
+
+   s = src;
+   d = mac_scsi_drq;
+   
+/* These conditions are derived from MacOS */
+
+   while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ) 
+         && (!(NCR5380_read(STATUS_REG) & SR_REQ) 
+            || (NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH))) 
+      ;
+   if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ)) {
+      printk(KERN_ERR "Error in macscsi_pwrite\n");
+      return -1;
+   }
+
+   CP_MEM_TO_IO(s, d, len);   
+
+   if (len != 0) {
+      printk(KERN_NOTICE "Bus error in macscsi_pwrite\n");
+      return -1;
+   }
+   
+   return 0;
 }
 
-#endif
-
-#include "NCR5380.c"
-
-/*
- * Debug stuff - to be called on NMI, or sysrq key. Use at your own risk; 
- * reentering NCR5380_print_status seems to have ugly side effects
- */
-
-void scsi_mac_debug (void)
-{
-	unsigned long flags;
-	NCR5380_local_declare();
-
-	if (default_instance) {
-#if 0
-		NCR5380_setup(default_instance);
-		if(NCR5380_read(BUS_AND_STATUS_REG)&BASR_IRQ)
-#endif
-			save_flags(flags);
-			cli();
-			NCR5380_print_status(default_instance);
-			restore_flags(flags);
-	}
-#if 0
-	polled_scsi_on = 1;
-#endif
-}
-/*
- * Helper function for interrupt trouble. More ugly side effects here.
- */
-
-void scsi_mac_polled (void)
-{
-	unsigned long flags;
-	NCR5380_local_declare();
-	struct Scsi_Host *instance;
-	
-#if 0
-	for (instance = first_instance; instance && (instance->hostt == 
-	    the_template); instance = instance->next)
-	    if (instance->irq == IRQ_MAC_SCSI && polled_scsi_on) {
-#else
-		instance = default_instance;
-#endif
-		NCR5380_setup(instance);
-		if(NCR5380_read(BUS_AND_STATUS_REG)&BASR_IRQ)
-		{
-			printk("SCSI poll\n");
-			save_flags(flags);
-			cli();
-			NCR5380_intr(IRQ_MAC_SCSI, instance, NULL);
-			restore_flags(flags);
-		}
-#if 0
-	    }
-#endif
-}
 
+/* These control the behaviour of the generic 5380 core */
+#define AUTOSENSE
+#define PSEUDO_DMA
 
+#include "NCR5380.c"
 
 static Scsi_Host_Template driver_template = MAC_NCR5380;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/mac_scsi.h linux-2.4.21-pre6/drivers/scsi/mac_scsi.h
--- linux-2.4.20/drivers/scsi/mac_scsi.h	2000-01-25 21:01:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/mac_scsi.h	2003-03-26 23:49:40.000000000 +0000
@@ -29,8 +29,7 @@
 #ifndef MAC_NCR5380_H
 #define MAC_NCR5380_H
 
-#define MACSCSI_PUBLIC_RELEASE 1
-
+#define MACSCSI_PUBLIC_RELEASE 2
 
 #ifndef ASM
 int macscsi_abort (Scsi_Cmnd *);
@@ -65,6 +64,8 @@
 #include <scsi/scsicam.h>
 
 #define MAC_NCR5380 {						\
+proc_name:		"Mac5380",					\
+proc_info:		macscsi_proc_info,                              \
 name:			"Macintosh NCR5380 SCSI",			\
 detect:			macscsi_detect,					\
 release:		macscsi_release,	/* Release */		\
@@ -95,6 +96,9 @@
 #define NCR5380_read(reg) macscsi_read(_instance, reg)
 #define NCR5380_write(reg, value) macscsi_write(_instance, reg, value)
 
+#define NCR5380_pread 	macscsi_pread
+#define NCR5380_pwrite 	macscsi_pwrite
+	
 #define NCR5380_intr macscsi_intr
 #define NCR5380_queue_command macscsi_queue_command
 #define NCR5380_abort macscsi_abort
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/megaraid.c linux-2.4.21-pre6/drivers/scsi/megaraid.c
--- linux-2.4.20/drivers/scsi/megaraid.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/megaraid.c	2003-03-26 23:48:57.000000000 +0000
@@ -2,14 +2,14 @@
  *
  *                    Linux MegaRAID device driver
  *
- * Copyright 2001  American Megatrends Inc.
+ * Copyright 2001  LSI Logic Corporation.
  *
  *              This program is free software; you can redistribute it and/or
  *              modify it under the terms of the GNU General Public License
  *              as published by the Free Software Foundation; either version
  *              2 of the License, or (at your option) any later version.
  *
- * Version : v1.18 (Oct 11, 2001)
+ * Version : v1.18f (Dec 10, 2002)
  *
  * Description: Linux device driver for LSI Logic MegaRAID controller
  *
@@ -459,6 +459,58 @@
  *
  * References to AMI have been changed to LSI Logic.
  *
+ * Version 1.18a
+ * Mon Mar 11 11:38:38 EST 2002 - Atul Mukker <Atul.Mukker@lsil.com>
+ *
+ * RAID On MotherBoard (ROMB) - boot from logical or physical drives
+ *
+ * Support added for discovery(ROMB) vendor and device ids.
+ *
+ * Data transfer length for passthru commands must be valid even if the
+ * command has an associated scatter-gather list.
+ *
+ *
+ * Version 1.18b
+ * Tue Apr 23 11:01:58 EDT 2002 - Atul Mukker <Atul.Mukker@lsil.com>
+ *
+ * typo corrected for scsi condition CHECK_CONDITION in mega_cmd_done()
+ *
+ * Support added for PCI_VENDOR_ID_LSI_LOGIC with device id
+ * PCI_DEVICE_ID_AMI_MEGARAID3.
+ *
+ *
+ * Version 1.18c
+ * Thu May 16 10:27:55 EDT 2002 - Atul Mukker <Atul.Mukker@lsil.com>
+ *
+ * Retrun valid return status for mega passthru commands resulting in
+ * contingent allegiance condition. Check for 64-bit passthru commands also.
+ *
+ * Do not check_region() anymore and check for return value of
+ * request_region()
+ *
+ * Send valid sense data to appliations using the private ioctl interface.
+ *
+ *
+ * Version 1.18d
+ * Wed Aug  7 18:51:51 EDT 2002 - Atul Mukker <atul.mukker@lsil.com>
+ *
+ * Added support for yellowstone and verde controller
+ *
+ * Version 1.18e
+ * Mon Nov 18 12:11:02 EST 2002 - Atul Mukker <atul.mukker@lsil.com>
+ *
+ * Don't use virt_to_bus in mega_register_mailbox when you've got the DMA
+ * address already. Submitted by Jens Axboe and is included in SuSE Linux
+ * Enterprise Server 7.
+ *
+ * s/pcibios_read_config/pci_read_config - Matt Domsch <mdomsch@dell.com>
+ *
+ * remove an unsed variable
+ *
+ * Version 1.18f
+ * Tue Dec 10 09:54:39 EST 2002 - Atul Mukker <atul.mukker@lsil.com>
+ *
+ * remove GFP_DMA flag for ioctl. This was causing overrun of DMA buffers.
  *
  * BUGS:
  *     Some older 2.1 kernels (eg. 2.1.90) have a bug in pci.c that
@@ -772,7 +824,7 @@
 static struct mcontroller mcontroller[MAX_CONTROLLERS];
 
 /* The current driver version */
-static u32 driver_ver = 114;
+static u32 driver_ver = 0x118C;
 
 /* major number used by the device for character interface */
 static int major;
@@ -795,8 +847,7 @@
 extern struct proc_dir_entry proc_root;
 #endif
 
-static char mega_ch_class;	/* channels are raid or scsi */
-#define	IS_RAID_CH(ch)	( (mega_ch_class >> (ch)) & 0x01 )
+#define	IS_RAID_CH(this, ch)	( (this->mega_ch_class >> (ch)) & 0x01 )
 
 #if SERDEBUG
 static char strbuf[MAX_SERBUF + 1];
@@ -1076,11 +1127,14 @@
 		panic(KERN_ERR "megaraid:Problem...!\n");
 	}
 
+#if 0
 	islogical = ( (SCpnt->channel >= megaCfg->productInfo.SCSIChanPresent) &&
 					(SCpnt->channel <= megaCfg->host->max_channel) );
+#endif
 #if 0
 	islogical = (SCpnt->channel == megaCfg->host->max_channel);
 #endif
+	islogical = megaCfg->logdrv_chan[SCpnt->channel];
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 	/* Special Case to handle PassThrough->XferAddrress > 4GB */
@@ -1117,7 +1171,7 @@
 			status = 0xF0;
 		}
 #endif
-		if( IS_RAID_CH(SCpnt->channel) && ((c & 0x1F ) == TYPE_DISK) ) {
+		if(IS_RAID_CH(megaCfg, SCpnt->channel) && ((c & 0x1F) == TYPE_DISK)) {
 			status = 0xF0;
 		}
 	}
@@ -1126,7 +1180,7 @@
 	/* clear result; otherwise, success returns corrupt value */
 	SCpnt->result = 0;
 
-	if ((SCpnt->cmnd[0] & M_RD_IOCTL_CMD)) {	/* i.e. ioctl cmd such as M_RD_IOCTL_CMD, M_RD_IOCTL_CMD_NEW of megamgr */
+	if ( 0 && SCpnt->cmnd[0] & M_RD_IOCTL_CMD ) {	/* i.e. ioctl cmd such as M_RD_IOCTL_CMD, M_RD_IOCTL_CMD_NEW of megamgr */
 		switch (status) {
 		case 2:
 		case 0xF0:
@@ -1146,18 +1200,21 @@
 		case 0x02:	/* ERROR_ABORTED, i.e. SCSI_STATUS_CHECK_CONDITION */
 
 			/*set sense_buffer and result fields */
-			if (mbox->cmd == MEGA_MBOXCMD_PASSTHRU) {
+			if (mbox->cmd == MEGA_MBOXCMD_PASSTHRU || mbox->cmd ==
+							MEGA_MBOXCMD_PASSTHRU64 ) {
+
 				memcpy (SCpnt->sense_buffer, pthru->reqsensearea, 14);
+
+				SCpnt->result = (DRIVER_SENSE << 24) | (DID_OK << 16) |
+						(CHECK_CONDITION << 1);
+
 			} else if (mbox->cmd == MEGA_MBOXCMD_EXTPASSTHRU) {
-				SCpnt->result = (DRIVER_SENSE << 24) | (DID_OK << 16) | (CHECK_CONDITION << 1);
-				memcpy(
-					SCpnt->sense_buffer,
-					epthru->reqsensearea, 14
-				);
-				SCpnt->result = (DRIVER_SENSE << 24) | (DID_OK << 16) | (CHECK_CONDITION << 1);
-				/*SCpnt->result =
-					(DRIVER_SENSE << 24) |
-					(DID_ERROR << 16) | status;*/
+
+				memcpy( SCpnt->sense_buffer, epthru->reqsensearea, 14);
+
+				SCpnt->result = (DRIVER_SENSE << 24) | (DID_OK << 16) |
+						(CHECK_CONDITION << 1);
+
 			} else {
 				SCpnt->sense_buffer[0] = 0x70;
 				SCpnt->sense_buffer[2] = ABORTED_COMMAND;
@@ -1204,8 +1261,10 @@
 	mega_ext_passthru *epthru;
 	long seg;
 	char islogical;
-	int lun = SCpnt->lun;
-	int		max_lun;
+	int		max_ldrv_num;
+	int		channel = 0;
+	int		target = 0;
+	int		ldrv_num = 0;	/* logical drive number */
 
 	if ((SCpnt->cmnd[0] == MEGADEVIOC))
 		return megadev_doioctl (megaCfg, SCpnt);
@@ -1222,15 +1281,61 @@
 	}
 #endif
 
+#if 0
 	islogical = ( (SCpnt->channel >= megaCfg->productInfo.SCSIChanPresent) &&
 					(SCpnt->channel <= megaCfg->host->max_channel) );
+#endif
 #if 0
 	islogical = (IS_RAID_CH(SCpnt->channel) && /* virtual ch is raid - AM */
 						(SCpnt->channel == megaCfg->host->max_channel));
 #endif
 
+	/*
+	 * We know on what channels are our logical drives - mega_findCard()
+	 */
+	islogical = megaCfg->logdrv_chan[SCpnt->channel];
+
+	/*
+	 * The theory: If physical drive is chosen for boot, all the physical
+	 * devices are exported before the logical drives, otherwise physical
+	 * devices are pushed after logical drives, in which case - Kernel sees
+	 * the physical devices on virtual channel which is obviously converted
+	 * to actual channel on the HBA.
+	 */
+	if( megaCfg->boot_pdrv_enabled ) {
+		if( islogical ) {
+			/* logical channel */
+			channel = SCpnt->channel - megaCfg->productInfo.SCSIChanPresent;
+		}
+		else {
+			channel = SCpnt->channel; /* this is physical channel */
+			target = SCpnt->target;
+
+			/*
+			 * boot from a physical disk, that disk needs to be exposed first
+			 * IF both the channels are SCSI, then booting from the second
+			 * channel is not allowed.
+			 */
+			if( target == 0 ) {
+				target = megaCfg->boot_pdrv_tgt;
+			}
+			else if( target == megaCfg->boot_pdrv_tgt ) {
+				target = 0;
+			}
+		}
+	}
+	else {
+		if( islogical ) {
+			channel = SCpnt->channel; /* this is the logical channel */
+		}
+		else {
+			channel = SCpnt->channel - NVIRT_CHAN;	/* physical channel */
+			target = SCpnt->target;
+		}
+	}
+
 	if ( ! megaCfg->support_ext_cdb ) {
-		if (!islogical && lun != 0) {
+		if (!islogical && SCpnt->lun != 0) {
 			SCpnt->result = (DID_BAD_TARGET << 16);
 			callDone (SCpnt);
 			return NULL;
@@ -1252,39 +1357,26 @@
 			return NULL;
 		}
 
-		lun = mega_get_lun(megaCfg, SCpnt);
+		ldrv_num = mega_get_ldrv_num(megaCfg, SCpnt, channel);
 
-	    max_lun = (megaCfg->flag & BOARD_40LD) ?
+	    max_ldrv_num = (megaCfg->flag & BOARD_40LD) ?
 						FC_MAX_LOGICAL_DRIVES : MAX_LOGICAL_DRIVES;
 
 		 /*
-		  * max_lun increases by 0x80 if some logical drive was deleted.
+		  * max_ldrv_num increases by 0x80 if some logical drive was deleted.
 		  */
 		if(megaCfg->read_ldidmap) {
-			max_lun += 0x80;
+			max_ldrv_num += 0x80;
 		}
 
-		if( lun > max_lun ) {
+		if( ldrv_num > max_ldrv_num ) {
 			SCpnt->result = (DID_BAD_TARGET << 16);
 			callDone (SCpnt);
 			return NULL;
 		}
 
-		/*
-		 * If we have a logical drive with boot enabled, project it first
-		 */
-		if( megaCfg->boot_ldrv_enabled ) {
-			if( lun == 0 ) {
-				lun = megaCfg->boot_ldrv;
-			}
-			else {
-				if( lun <= megaCfg->boot_ldrv ) {
-					lun--;
-				}
-			}
-		}
 	} else {
-		if ( lun > 7) {
+		if ( SCpnt->lun > 7) {
 				/* Do not support lun >7 for physically accessed devices */
 			SCpnt->result = (DID_BAD_TARGET << 16);
 			callDone (SCpnt);
@@ -1312,6 +1404,14 @@
 
 		case READ_CAPACITY:
 		case INQUIRY:
+			if(!(megaCfg->flag & (1L << SCpnt->channel))) {
+				printk(KERN_NOTICE
+					"scsi%d: scanning virtual channel %d for logical drives.\n",
+					megaCfg->host->host_no, channel);
+
+				megaCfg->flag |= (1L << SCpnt->channel);
+			}
+
 			/* Allocate a SCB and initialize passthru */
 			if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) {
 				SCpnt->result = (DID_ERROR << 16);
@@ -1331,7 +1431,7 @@
 			pthru->ars = 1;
 			pthru->reqsenselen = 14;
 			pthru->islogical = 1;
-			pthru->logdrv = lun;
+			pthru->logdrv = ldrv_num;
 			pthru->cdblen = SCpnt->cmd_len;
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
@@ -1386,7 +1486,7 @@
 			mbox = (mega_mailbox *) & pScb->mboxData;
 
 			memset (mbox, 0, sizeof (pScb->mboxData));
-			mbox->logdrv = lun;
+			mbox->logdrv = ldrv_num;
 
 			if (megaCfg->flag & BOARD_64BIT) {
 				mbox->cmd = (*SCpnt->cmnd == READ_6
@@ -1410,12 +1510,12 @@
 				mbox->lba &= 0x1FFFFF;
 
 				if (*SCpnt->cmnd == READ_6) {
-					megaCfg->nReads[(int) lun]++;
-					megaCfg->nReadBlocks[(int) lun] +=
+					megaCfg->nReads[(int)ldrv_num]++;
+					megaCfg->nReadBlocks[(int)ldrv_num] +=
 					    mbox->numsectors;
 				} else {
-					megaCfg->nWrites[(int) lun]++;
-					megaCfg->nWriteBlocks[(int) lun] +=
+					megaCfg->nWrites[(int)ldrv_num]++;
+					megaCfg->nWriteBlocks[(int)ldrv_num] +=
 					    mbox->numsectors;
 				}
 			}
@@ -1432,12 +1532,12 @@
 				    (u32) SCpnt->cmnd[5];
 
 				if (*SCpnt->cmnd == READ_10) {
-					megaCfg->nReads[(int) lun]++;
-					megaCfg->nReadBlocks[(int) lun] +=
+					megaCfg->nReads[(int)ldrv_num]++;
+					megaCfg->nReadBlocks[(int)ldrv_num] +=
 					    mbox->numsectors;
 				} else {
-					megaCfg->nWrites[(int) lun]++;
-					megaCfg->nWriteBlocks[(int) lun] +=
+					megaCfg->nWrites[(int)ldrv_num]++;
+					megaCfg->nWriteBlocks[(int)ldrv_num] +=
 					    mbox->numsectors;
 				}
 			}
@@ -1457,12 +1557,12 @@
 				    (u32) SCpnt->cmnd[9];
 
 				if (*SCpnt->cmnd == READ_12) {
-					megaCfg->nReads[(int) lun]++;
-					megaCfg->nReadBlocks[(int) lun] +=
+					megaCfg->nReads[(int)ldrv_num]++;
+					megaCfg->nReadBlocks[(int)ldrv_num] +=
 					    mbox->numsectors;
 				} else {
-					megaCfg->nWrites[(int) lun]++;
-					megaCfg->nWriteBlocks[(int) lun] +=
+					megaCfg->nWrites[(int)ldrv_num]++;
+					megaCfg->nWriteBlocks[(int)ldrv_num] +=
 					    mbox->numsectors;
 				}
 			}
@@ -1516,7 +1616,8 @@
 		memset (mbox, 0, sizeof (pScb->mboxData));
 
 		if ( megaCfg->support_ext_cdb && SCpnt->cmd_len > 10 ) {
-			epthru = mega_prepare_extpassthru(megaCfg, pScb, SCpnt);
+			epthru = mega_prepare_extpassthru(megaCfg, pScb, SCpnt, channel,
+					target);
 			mbox->cmd = MEGA_MBOXCMD_EXTPASSTHRU;
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 			mbox->xferaddr = pScb->dma_ext_passthruhandle64;
@@ -1531,7 +1632,8 @@
 #endif
 		}
 		else {
-			pthru = mega_prepare_passthru(megaCfg, pScb, SCpnt);
+			pthru = mega_prepare_passthru(megaCfg, pScb, SCpnt, channel,
+					target);
 
 			/* Initialize mailbox */
 			mbox->cmd = MEGA_MBOXCMD_PASSTHRU;
@@ -1553,18 +1655,30 @@
 }
 
 static int
-mega_get_lun(mega_host_config *this_hba, Scsi_Cmnd *sc)
+mega_get_ldrv_num(mega_host_config *this_hba, Scsi_Cmnd *sc, int channel)
 {
 	int		tgt;
-	int		lun;
-	int		virt_chan;
+	int		ldrv_num;
 
 	tgt = sc->target;
 	
 	if ( tgt > 7 ) tgt--;	/* we do not get inquires for tgt 7 */
 
-	virt_chan = sc->channel - this_hba->productInfo.SCSIChanPresent;
-	lun = (virt_chan * 15) + tgt;
+	ldrv_num = (channel * 15) + tgt; /* 14 targets per channel */
+
+	/*
+	 * If we have a logical drive with boot enabled, project it first
+	 */
+	if( this_hba->boot_ldrv_enabled ) {
+		if( ldrv_num == 0 ) {
+			ldrv_num = this_hba->boot_ldrv;
+		}
+		else {
+			if( ldrv_num <= this_hba->boot_ldrv ) {
+				ldrv_num--;
+			}
+		}
+	}
 
 	/*
 	 * If "delete logical drive" feature is enabled on this controller.
@@ -1582,16 +1696,17 @@
 		case WRITE_6:	/* fall through */
 		case READ_10:	/* fall through */
 		case WRITE_10:
-			lun += 0x80;
+			ldrv_num += 0x80;
 		}
 	 }
 
-	 return lun;
+	 return ldrv_num;
 }
 
 
 static mega_passthru *
-mega_prepare_passthru(mega_host_config *megacfg, mega_scb *scb, Scsi_Cmnd *sc)
+mega_prepare_passthru(mega_host_config *megacfg, mega_scb *scb, Scsi_Cmnd *sc,
+		int channel, int target)
 {
 	mega_passthru *pthru;
 
@@ -1608,9 +1723,9 @@
 	pthru->ars = 1;
 	pthru->reqsenselen = 14;
 	pthru->islogical = 0;
-	pthru->channel = (megacfg->flag & BOARD_40LD) ? 0 : sc->channel;
+	pthru->channel = (megacfg->flag & BOARD_40LD) ? 0 : channel;
 	pthru->target = (megacfg->flag & BOARD_40LD) ?
-	    (sc->channel << 4) | sc->target : sc->target;
+	    (channel << 4) | target : target;
 	pthru->cdblen = sc->cmd_len;
 	pthru->logdrv = sc->lun;
 
@@ -1624,6 +1739,15 @@
 	switch (sc->cmnd[0]) {
 	case INQUIRY:
 	case READ_CAPACITY:
+
+		if(!(megacfg->flag & (1L << sc->channel))) {
+			printk(KERN_NOTICE
+				"scsi%d: scanning physical channel %d for devices.\n",
+				megacfg->host->host_no, channel);
+
+			megacfg->flag |= (1L << sc->channel);
+		}
+
 		pthru->numsgelements = 0;
 		pthru->dataxferaddr = scb->dma_bounce_buffer;
 		pthru->dataxferlen = sc->request_bufflen;
@@ -1647,7 +1771,8 @@
 }
 
 static mega_ext_passthru *
-mega_prepare_extpassthru(mega_host_config *megacfg, mega_scb *scb, Scsi_Cmnd *sc)
+mega_prepare_extpassthru(mega_host_config *megacfg, mega_scb *scb,
+		Scsi_Cmnd *sc, int channel, int target)
 {
 	mega_ext_passthru *epthru;
 
@@ -1664,9 +1789,9 @@
 	epthru->ars = 1;
 	epthru->reqsenselen = 14;
 	epthru->islogical = 0;
-	epthru->channel = (megacfg->flag & BOARD_40LD) ? 0 : sc->channel;
+	epthru->channel = (megacfg->flag & BOARD_40LD) ? 0 : channel;
 	epthru->target = (megacfg->flag & BOARD_40LD) ?
-	    (sc->channel << 4) | sc->target : sc->target;
+	    (channel << 4) | target : target;
 	epthru->cdblen = sc->cmd_len;
 	epthru->logdrv = sc->lun;
 
@@ -1680,6 +1805,14 @@
 	switch (sc->cmnd[0]) {
 	case INQUIRY:
 	case READ_CAPACITY:
+		if(!(megacfg->flag & (1L << sc->channel))) {
+			printk(KERN_NOTICE
+				"scsi%d: scanning physical channel %d for devices.\n",
+				megacfg->host->host_no, channel);
+
+			megacfg->flag |= (1L << sc->channel);
+		}
+
 		epthru->numsgelements = 0;
 		epthru->dataxferaddr = scb->dma_bounce_buffer;
 		epthru->dataxferlen = sc->request_bufflen;
@@ -2240,7 +2373,6 @@
 			return 0;
 		}
 		udelay (100);
-		barrier ();
 	}
 	return -1;		/* give up after 1 second */
 }
@@ -2439,7 +2571,7 @@
 			scb->sg64List[0].address = scb->dma_h_bulkdata;
 			scb->sg64List[0].length = scb->SCpnt->request_bufflen;
 			*buffer = scb->dma_sghandle64;
-			*length = 0;
+			*length = (u32)scb->SCpnt->request_bufflen;
 			scb->sglist_count = 1;
 			return 1;
 		} else {
@@ -2520,7 +2652,15 @@
 #else
 	*buffer = virt_to_bus (scb->sgList);
 #endif
+
+#if 0
 	*length = 0;
+#endif
+	/*
+	 * For passthru command, dataxferlen must be set, even for commands with a
+	 * sg list
+	 */
+	*length = (u32)scb->SCpnt->request_bufflen;
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 	/* Return count of SG requests */
@@ -2743,12 +2883,7 @@
 		megaCfg->productInfo.SCSIChanPresent + NVIRT_CHAN -1;
 
 	megaCfg->host->max_id = 16;	/* max targets per channel */
-	/*(megaCfg->flag & BOARD_40LD)?FC_MAX_TARGETS_PER_CHANNEL:MAX_TARGET+1; */
-#if 0
-	megaCfg->host->max_lun =	/* max lun */
-	    (megaCfg->flag & BOARD_40LD) ?
-			FC_MAX_LOGICAL_DRIVES : MAX_LOGICAL_DRIVES;
-#endif
+
 	megaCfg->host->max_lun = 7;	/* Upto 7 luns for non disk devices */
 
 	megaCfg->host->cmd_per_lun = MAX_CMD_PER_LUN;
@@ -2760,12 +2895,6 @@
 
 	megaCfg->host->can_queue = megaCfg->max_cmds - 1;
 
-#if 0
-	if (megaCfg->host->can_queue >= MAX_COMMANDS) {
-		megaCfg->host->can_queue = MAX_COMMANDS - 16;
-	}
-#endif
-
 	/* use HP firmware and bios version encoding */
 	if (megaCfg->productInfo.subSystemVendorID == HP_SUBSYS_ID) {
 		sprintf (megaCfg->fwVer, "%c%d%d.%d%d",
@@ -2833,7 +2962,7 @@
 	u32 magic64;
 #endif
 
-	int		i;
+	int		i, j;
 
 #if BITS_PER_LONG==64
 	u64 megaBase;
@@ -2863,20 +2992,27 @@
 		pciDevFun = pdev->devfn;
 #endif
 		if ((flag & BOARD_QUARTZ) && (skip_id == -1)) {
-			pcibios_read_config_word (pciBus, pciDevFun,
-						  PCI_CONF_AMISIG, &magic);
-			if ((magic != AMI_SIGNATURE)
-			    && (magic != AMI_SIGNATURE_471)) {
-				pciIdx++;
-				continue;	/* not an AMI board */
-			}
+				if( (pciVendor == PCI_VENDOR_ID_PERC4_DI_YSTONE &&
+					pciDev == PCI_DEVICE_ID_PERC4_DI_YSTONE) ||
+					(pciVendor == PCI_VENDOR_ID_PERC4_QC_VERDE &&
+					pciDev == PCI_DEVICE_ID_PERC4_QC_VERDE) ) {
+
+					flag |= BOARD_64BIT;
+				}
+				else {
+					pci_read_config_word (pdev, PCI_CONF_AMISIG, &magic);
+					if ((magic != AMI_SIGNATURE)
+						&& (magic != AMI_SIGNATURE_471)) {
+						pciIdx++;
+						continue;	/* not an AMI board */
+					}
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-			pcibios_read_config_dword (pciBus, pciDevFun,
-						   PCI_CONF_AMISIG64, &magic64);
+					pci_read_config_dword (pdev, PCI_CONF_AMISIG64, &magic64);
 
-			if (magic64 == AMI_64BIT_SIGNATURE)
-				flag |= BOARD_64BIT;
+					if (magic64 == AMI_64BIT_SIGNATURE)
+						flag |= BOARD_64BIT;
 #endif
+				}
 		}
 
 		/* Hmmm...Should we not make this more modularized so that in future we dont add
@@ -2898,24 +3034,15 @@
 					      PCI_SUBSYSTEM_ID, &subsysid);
 #endif
 
-#if 0
 			/*
-			 * This routine is called with well know values and we
-			 * should not be getting what we have not asked.
-			 * Also, the check is not right. It should have been for
-			 * pci_vendor_id not subsysvid - AM
-			 */
-
-			/* If we dont detect this valid subsystem vendor id's 
-			   we refuse to load the driver 
-			   PART of PC200X compliance
+			 * If we do not find the valid subsys vendor id, refuse to load
+			 * the driver. This is part of PCI200X compliance
 			 */
+			if( (subsysvid != AMI_SUBSYS_ID) &&
+					(subsysvid != DELL_SUBSYS_ID) &&
+					(subsysvid != LSI_SUBSYS_ID) &&
+					(subsysvid != HP_SUBSYS_ID) ) continue;
 
-			if ((subsysvid != AMI_SUBSYS_ID)
-			    && (subsysvid != DELL_SUBSYS_ID)
-			    && (subsysvid != HP_SUBSYS_ID))
-				continue;
-#endif
 		}
 
 		printk (KERN_NOTICE
@@ -3004,11 +3131,10 @@
 		megaCtlrs[numCtlrs] = megaCfg;
 
 		if (!(flag & BOARD_QUARTZ)) {
+
 			/* Request our IO Range */
-			if (!request_region(megaBase, 16, "megaraid")) {
-				printk(KERN_WARNING "megaraid: Couldn't register I/O range!\n");
+			if( !request_region(megaBase, 16, "megaraid") )
 				goto err_unregister;
-			}
 		}
 
 		/* Request our IRQ */
@@ -3031,9 +3157,7 @@
 					    sizeof (mega_mailbox64),
 					    &(megaCfg->dma_handle64));
 
-		mega_register_mailbox (megaCfg,
-				       virt_to_bus ((void *) megaCfg->
-						    mailbox64ptr));
+		mega_register_mailbox (megaCfg,megaCfg->dma_handle64);
 #else
 		mega_register_mailbox (megaCfg,
 				       virt_to_bus ((void *) &megaCfg->
@@ -3097,18 +3221,35 @@
 		 * Find out which channel is raid and which is scsi
 		 */
 		mega_enum_raid_scsi(megaCfg);
-		for( i = 0; i < megaCfg->productInfo.SCSIChanPresent; i++ ) {
-			if(IS_RAID_CH(i))
-				printk(KERN_NOTICE"megaraid: channel[%d] is raid.\n", i+1);
-			else
-				printk(KERN_NOTICE"megaraid: channel[%d] is scsi.\n", i+1);
-		}
 
 		/*
 		 * Find out if a logical drive is set as the boot drive. If there is
 		 * one, will make that as the first logical drive.
+		 * ROMB: Do we have to boot from a physical drive. Then all the
+		 * physical drives would appear before the logical disks. Else, all
+		 * the physical drives would be exported to the mid layer after
+		 * logical disks.
 		 */
-		mega_get_boot_ldrv(megaCfg);
+		mega_get_boot_drv(megaCfg);
+
+		if( ! megaCfg->boot_pdrv_enabled ) {
+			for( i = 0; i < NVIRT_CHAN; i++ )
+				megaCfg->logdrv_chan[i] = 1;
+
+			for( i = NVIRT_CHAN; i < MAX_CHANNEL + NVIRT_CHAN; i++ )
+				megaCfg->logdrv_chan[i] = 0;
+
+			megaCfg->mega_ch_class <<= NVIRT_CHAN;
+		}
+		else {
+			j = megaCfg->productInfo.SCSIChanPresent;
+			for( i = 0; i < j; i++ )
+				megaCfg->logdrv_chan[i] = 0;
+
+			for( i = j; i < NVIRT_CHAN + j; i++ )
+				megaCfg->logdrv_chan[i] = 1;
+		}
+
 
 		mega_hbas[numCtlrs].hostdata_addr = megaCfg;
 
@@ -3208,6 +3349,12 @@
 
 	memset (mega_hbas, 0, sizeof (mega_hbas));
 
+	/* Detect ROMBs first */
+	count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_DISCOVERY,
+				PCI_DEVICE_ID_DISCOVERY, BOARD_QUARTZ);
+	count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_PERC4_DI_YSTONE,
+				PCI_DEVICE_ID_PERC4_DI_YSTONE, BOARD_QUARTZ);
+	/* Then detect cards based on date they were produced, oldest first */
 	count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_AMI,
 				PCI_DEVICE_ID_AMI_MEGARAID, 0);
 	count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_AMI,
@@ -3216,6 +3363,10 @@
 				PCI_DEVICE_ID_AMI_MEGARAID3, BOARD_QUARTZ);
 	count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_AMI,
 				PCI_DEVICE_ID_AMI_MEGARAID3, BOARD_QUARTZ);
+	count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_LSI_LOGIC,
+				PCI_DEVICE_ID_AMI_MEGARAID3, BOARD_QUARTZ);
+	count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_PERC4_QC_VERDE,
+				PCI_DEVICE_ID_PERC4_QC_VERDE, BOARD_QUARTZ);
 
 	mega_reorder_hosts ();
 
@@ -3366,7 +3517,7 @@
 /*
  * Find out what channels are RAID/SCSI
  */
-void
+static void
 mega_enum_raid_scsi(mega_host_config *megacfg)
 {
 	mega_mailbox *mboxp;
@@ -3401,16 +3552,16 @@
 	 * Non-ROMB firware fail this command, so all channels
 	 * must be shown RAID
 	 */
+	megacfg->mega_ch_class = 0xFF;
 	if( megaIssueCmd(megacfg, mbox, NULL, 0) == 0 ) {
-		mega_ch_class = *((char *)megacfg->mega_buffer);
-
-		for( i = 0; i < NVIRT_CHAN; i++ ) {
-			/* logical drives channel is RAID */
-			mega_ch_class |= (0x01 << (megacfg->productInfo.SCSIChanPresent+i));
-		}
+		megacfg->mega_ch_class = *((char *)megacfg->mega_buffer);
 	}
-	else {
-		mega_ch_class = 0xFF;
+
+	for( i = 0; i < megacfg->productInfo.SCSIChanPresent; i++ ) {
+		if( (megacfg->mega_ch_class >> i) & 0x01 )
+			printk(KERN_NOTICE"megaraid: channel[%d] is raid.\n", i+1);
+		else
+			printk(KERN_NOTICE"megaraid: channel[%d] is scsi.\n", i+1);
 	}
 
 
@@ -3426,13 +3577,14 @@
  * get the boot logical drive number if enabled
  */
 void
-mega_get_boot_ldrv(mega_host_config *megacfg)
+mega_get_boot_drv(mega_host_config *megacfg)
 {
 	mega_mailbox *mboxp;
 	unsigned char mbox[16];
 	struct private_bios_data *prv_bios_data;
 	u16		cksum = 0;
-	char	*cksum_p;
+	u8		*cksum_p;
+	u8		boot_pdrv;
 	int		i;
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
@@ -3459,19 +3611,35 @@
 
 	megacfg->boot_ldrv_enabled = 0;
 	megacfg->boot_ldrv = 0;
-	if( megaIssueCmd(megacfg, mbox, NULL, 0) == 0 ) {
 
+	megacfg->boot_pdrv_enabled = 0;
+	megacfg->boot_pdrv_ch = 0;
+	megacfg->boot_pdrv_tgt = 0;
+
+	if( megaIssueCmd(megacfg, mbox, NULL, 0) == 0 ) {
 		prv_bios_data = (struct private_bios_data *)megacfg->mega_buffer;
 
 		cksum = 0;
-		cksum_p = (char *)prv_bios_data;
+		cksum_p = (u8 *)prv_bios_data;
 		for( i = 0; i < 14; i++ ) {
-			cksum += (u16)(*cksum_p++);
+			cksum += *cksum_p++;
 		}
 
 		if( prv_bios_data->cksum == (u16)(0-cksum) ) {
-			megacfg->boot_ldrv_enabled = 1;
-			megacfg->boot_ldrv = prv_bios_data->boot_ldrv;
+
+			/*
+			 * If MSB is set, a physical drive is set as boot device
+			 */
+			if( prv_bios_data->boot_drv & 0x80 ) {
+				megacfg->boot_pdrv_enabled = 1;
+				boot_pdrv = prv_bios_data->boot_drv & 0x7F;
+				megacfg->boot_pdrv_ch = boot_pdrv / 16;
+				megacfg->boot_pdrv_tgt = boot_pdrv % 16;
+			}
+			else {
+				megacfg->boot_ldrv_enabled = 1;
+				megacfg->boot_ldrv = prv_bios_data->boot_drv;
+			}
 		}
 	}
 
@@ -3681,7 +3849,7 @@
 	sprintf (buffer,
 		 "LSI Logic MegaRAID %s %d commands %d targs %d chans %d luns",
 		 megaCfg->fwVer, megaCfg->productInfo.MaxConcCmds,
-		 megaCfg->host->max_id, megaCfg->host->max_channel,
+		 megaCfg->host->max_id-1, megaCfg->host->max_channel,
 		 megaCfg->host->max_lun);
 	return buffer;
 }
@@ -3710,6 +3878,7 @@
 	megaCfg = (mega_host_config *) SCpnt->host->hostdata;
 	DRIVER_LOCK (megaCfg);
 
+#if 0
 	if (!(megaCfg->flag & (1L << SCpnt->channel))) {
 		if (SCpnt->channel < megaCfg->productInfo.SCSIChanPresent)
 			printk ( KERN_NOTICE
@@ -3723,6 +3892,7 @@
 
 		megaCfg->flag |= (1L << SCpnt->channel);
 	}
+#endif
 
 	SCpnt->scsi_done = pktComp;
 
@@ -4232,7 +4402,7 @@
 	/* Get pointer to host config structure */
 	megaCfg = (mega_host_config *) disk->device->host->hostdata;
 
-	if( IS_RAID_CH(disk->device->channel)) {
+	if( IS_RAID_CH(megaCfg, disk->device->channel)) {
 			/* Default heads (64) & sectors (32) */
 			heads = 64;
 			sectors = 32;
@@ -4297,7 +4467,15 @@
 	int heads, cyls, sectors;
 	int capacity = disk->capacity;
 
-	if(!(bh = bread(MKDEV(MAJOR(dev), MINOR(dev)&~0xf), 0, block_size(dev))))
+	int ma = MAJOR(dev);
+	int mi = (MINOR(dev) & ~0xf);
+
+	int block = 1024; 
+
+	if(blksize_size[ma])
+		block = blksize_size[ma][mi];
+		
+	if(!(bh = bread(MKDEV(ma,mi), 0, block)))
 		return -1;
 
 	if( *(unsigned short *)(bh->b_data + 510) == 0xAA55 ) {
@@ -4626,9 +4804,10 @@
 			/*
 			 * Copy struct mcontroller to user area
 			 */
-			copy_to_user (ioc.data,
+			if (copy_to_user (ioc.data,
 				      mcontroller + adapno,
-				      sizeof (struct mcontroller));
+				      sizeof (struct mcontroller)))
+				      return -EFAULT;
 			return 0;
 
 		default:
@@ -4694,7 +4873,7 @@
 		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);
+		scsicmd = (Scsi_Cmnd *)kmalloc(sizeof(Scsi_Cmnd), GFP_KERNEL);
 #else
 		scsicmd = (Scsi_Cmnd *)scsi_init_malloc(sizeof(Scsi_Cmnd),
 							  GFP_ATOMIC | GFP_DMA);
@@ -4745,7 +4924,8 @@
 		down(&mimd_ioctl_sem);
 
 		if( !scsicmd->result && outlen ) {
-			copy_to_user(uaddr, kvaddr, length);
+			if (copy_to_user(uaddr, kvaddr, length))
+				return -EFAULT;
 		}
 
 		/*
@@ -4755,6 +4935,9 @@
 
 		if( ioc.mbox[0] == MEGA_MBOXCMD_PASSTHRU ) {
 			put_user( scsicmd->result, &uioc->pthru.scsistatus );
+			if (copy_to_user( uioc->pthru.reqsensearea, scsicmd->sense_buffer,
+							  MAX_REQ_SENSE_LEN ))
+				ret= -EFAULT;
 		} else {
 			put_user(1, &uioc->mbox[16]);	/* numstatus */
 			/* status */
@@ -4836,7 +5019,7 @@
 		}
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-		scsicmd = (Scsi_Cmnd *)kmalloc(sizeof(Scsi_Cmnd), GFP_KERNEL|GFP_DMA);
+		scsicmd = (Scsi_Cmnd *)kmalloc(sizeof(Scsi_Cmnd), GFP_KERNEL);
 #else
 		scsicmd = (Scsi_Cmnd *)scsi_init_malloc(sizeof(Scsi_Cmnd),
 							  GFP_ATOMIC | GFP_DMA);
@@ -4894,9 +5077,11 @@
 
 		if (!scsicmd->result && outlen) {
 			if (ioc.mbox[0] == MEGA_MBOXCMD_PASSTHRU) {
-				copy_to_user (uaddr, kvaddr, ioc.pthru.dataxferlen);
+				if (copy_to_user (uaddr, kvaddr, ioc.pthru.dataxferlen))	
+					ret = -EFAULT;
 			} else {
-				copy_to_user (uaddr, kvaddr, outlen);
+				if (copy_to_user (uaddr, kvaddr, outlen)) 
+					ret = -EFAULT;
 			}
 		}
 
@@ -4907,6 +5092,15 @@
 
 		if (ioc.mbox[0] == MEGA_MBOXCMD_PASSTHRU) {
 			put_user (scsicmd->result, &uioc->pthru.scsistatus);
+
+			/*
+			 * If scsicmd->result is 0x02 (CHECK CONDITION) then copy the
+			 * SCSI sense data into user area
+			 */
+			if (copy_to_user( uioc->pthru.reqsensearea, scsicmd->sense_buffer,
+							  MAX_REQ_SENSE_LEN ))
+				ret = -EFAULT;
+							
 		} else {
 			put_user (1, &uioc->mbox[16]);	/* numstatus */
 			put_user (scsicmd->result, &uioc->mbox[17]); /* status */
@@ -4995,7 +5189,7 @@
 			scb->sg64List[0].length = 4096;	// TODO: Check this
 			pthru->dataxferaddr = scb->dma_sghandle64;
 			pthru->numsgelements = 1;
-			mboxpthru->cmd = 0xC3;
+			mboxpthru->cmd = MEGA_MBOXCMD_PASSTHRU64;
 		} else {
 			mboxpthru->dataxferaddr = scb->dma_passthruhandle64;
 			pthru->dataxferaddr =
@@ -5189,8 +5383,6 @@
 		return rval;
 	}
 
-	printk("megaraid: logical drive %d deleted.\n", logdrv);
-
 	/*
 	 * After deleting first logical drive, the logical drives must be
 	 * addressed by adding 0x80 to the logical drive id.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/megaraid.h linux-2.4.21-pre6/drivers/scsi/megaraid.h
--- linux-2.4.20/drivers/scsi/megaraid.h	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/megaraid.h	2003-03-26 23:49:39.000000000 +0000
@@ -30,7 +30,7 @@
 #define M_RD_IOCTL_CMD_NEW		0x81
 #define M_RD_DRIVER_IOCTL_INTERFACE	0x82
 
-#define MEGARAID_VERSION "v1.18 (Release Date: Thu Oct 11 15:02:53 EDT 2001)\n"
+#define MEGARAID_VERSION "v1.18f (Release Date: Tue Dec 10 09:54:39 EST 2002)\n"
 
 #define MEGARAID_IOCTL_VERSION 	114
 
@@ -73,6 +73,7 @@
 #define MEGA_MBOXCMD_LWRITE64		0xA8
 #define MEGA_MBOXCMD_PASSTHRU		0x03
 #define MEGA_MBOXCMD_EXTPASSTHRU	0xE3
+#define MEGA_MBOXCMD_PASSTHRU64		0xC3
 #define MEGA_MBOXCMD_ADAPTERINQ		0x05
 
 
@@ -121,6 +122,10 @@
 #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)
 
+#ifndef PCI_VENDOR_ID_LSI_LOGIC
+#define PCI_VENDOR_ID_LSI_LOGIC		0x1000
+#endif
+
 /* Define AMI's PCI codes */
 #ifndef PCI_VENDOR_ID_AMI
 #define PCI_VENDOR_ID_AMI		0x101E
@@ -138,6 +143,15 @@
 #define PCI_DEVICE_ID_AMI_MEGARAID3	0x1960
 #endif
 
+#define PCI_VENDOR_ID_DISCOVERY		0x1028
+#define PCI_DEVICE_ID_DISCOVERY		0x000E
+
+#define PCI_VENDOR_ID_PERC4_DI_YSTONE	0x1028
+#define PCI_DEVICE_ID_PERC4_DI_YSTONE	0x000F
+
+#define PCI_VENDOR_ID_PERC4_QC_VERDE	0x1000
+#define PCI_DEVICE_ID_PERC4_QC_VERDE	0x0407
+
 /* Special Adapter Commands */
 #define FW_FIRE_WRITE   	0x2C
 #define FW_FIRE_FLASH   	0x2D
@@ -172,6 +186,7 @@
 #define PCI_CONF_AMISIG64		0xa4
 
 /* Sub-System Vendor ID sorted on alphabetical order*/
+#define LSI_SUBSYS_ID                  0x1000
 #define	AMI_SUBSYS_ID			0x101E
 #define DELL_SUBSYS_ID			0x1028
 #define	HP_SUBSYS_ID			0x103C
@@ -704,12 +719,15 @@
 #define INTR_ENB	0	/* do not disable interrupt while manipulating */
 #define INTR_DIS	1	/* disable interrupt while manipulating */
 
+#define NVIRT_CHAN		4	/* # of virtual channels to represent 60 logical
+							drives */
+
 /* Per-controller data */
 typedef struct _mega_host_config {
 	u8 numldrv;
 	u32 flag;
 
-#if BITS_PER_LONG==64
+#ifdef __LP64__
 	u64 base;
 #else
 	u32 base;
@@ -769,8 +787,12 @@
 	struct proc_dir_entry *controller_proc_dir_entry;
 	struct proc_dir_entry *proc_read, *proc_stat, *proc_status, *proc_mbox;
 	int		support_ext_cdb;
-	int		boot_ldrv_enabled;
-	int		boot_ldrv;
+
+	u8		boot_ldrv_enabled;	/* boot from logical drive */
+	u8		boot_ldrv;			/* boot logical drive */
+	u8		boot_pdrv_enabled;	/* boot from physical drive */
+	u8		boot_pdrv_ch;		/* boot physical drive channel */
+	u8		boot_pdrv_tgt;		/* boot physical drive target */
 
 	int		support_random_del;	/* Do we support random deletion of logdrvs */
 	int		read_ldidmap;	/* set after logical drive deltion. The logical
@@ -782,6 +804,9 @@
 	mega_scb	*int_qh;	/* commands are queued in the internal queue */
 	mega_scb	*int_qt;	/* while the hba is quiescent */
 	int			int_qlen;
+	char		logdrv_chan[MAX_CHANNEL+NVIRT_CHAN]; /* logical drive are on
+														 what channels. */
+	int			mega_ch_class;
 } mega_host_config;
 
 typedef struct _driver_info {
@@ -916,8 +941,8 @@
 							 * Others values are invalid
 							 */
 	u8		unused:4;		/* bits 4-7 are unused */
-	u8		boot_ldrv;		/*
-							 * logical drive set as boot drive
+	u8		boot_drv;		/*
+							 * logical/physical drive set as boot drive
 							 * 0..7 - for 8LD cards
 							 * 0..39 - for 40LD cards
 							 */
@@ -926,9 +951,6 @@
 };
 #pragma pack()
 
-#define NVIRT_CHAN		4	/* # of virtual channels to represent 60 logical
-							drives */
-
 /*
  * Command for random deletion of logical drives
  */
@@ -994,13 +1016,13 @@
 static void mega_create_proc_entry (int index, struct proc_dir_entry *);
 static int mega_support_ext_cdb(mega_host_config *);
 static mega_passthru* mega_prepare_passthru(mega_host_config *, mega_scb *,
-		Scsi_Cmnd *);
+		Scsi_Cmnd *, int, int);
 static mega_ext_passthru* mega_prepare_extpassthru(mega_host_config *,
-		mega_scb *, Scsi_Cmnd *);
+		mega_scb *, Scsi_Cmnd *, int, int);
 static void mega_enum_raid_scsi(mega_host_config *);
 static int mega_partsize(Disk *, kdev_t, int *);
-static void mega_get_boot_ldrv(mega_host_config *);
-static int mega_get_lun(mega_host_config *, Scsi_Cmnd *);
+static void mega_get_boot_drv(mega_host_config *);
+static int mega_get_ldrv_num(mega_host_config *, Scsi_Cmnd *, int);
 static int mega_support_random_del(mega_host_config *);
 static int mega_del_logdrv(mega_host_config *, int);
 static int mega_do_del_logdrv(mega_host_config *, int);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/nsp32.c linux-2.4.21-pre6/drivers/scsi/nsp32.c
--- linux-2.4.20/drivers/scsi/nsp32.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/nsp32.c	2003-03-26 23:49:40.000000000 +0000
@@ -0,0 +1,3526 @@
+/*
+ * NinjaSCSI-32Bi Cardbus, NinjaSCSI-32UDE PCI/CardBus SCSI driver
+ * Copyright (C) 2001, 2002
+ *      YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>
+ *      GOTO Masanori <gotom@debian.or.jp>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <linux/major.h>
+#include <linux/blk.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+
+#include <asm/dma.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include <scsi/scsi_ioctl.h>
+#include <scsi/scsi.h>
+
+#include "nsp32.h"
+
+
+static int trans_mode = 0;	/* default: BIOS */
+static int auto_param = 0;	/* default: ON */
+MODULE_PARM(trans_mode, "i");
+MODULE_PARM(auto_param, "i");
+MODULE_PARM_DESC(trans_mode, "transfer mode (0: BIOS 1: Async 2: Ultra20M");
+MODULE_PARM_DESC(auto_param, "AutoParameter mode (0: ON 1: OFF)");
+#define ASYNC_MODE    1
+#define ULTRA20M_MODE 2
+
+MODULE_AUTHOR("YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>, GOTO Masanori <gotom@debian.or.jp>");
+MODULE_DESCRIPTION("Workbit NinjaSCSI-32Bi/UDE PCI/CardBus SCSI host bus adapter module");
+MODULE_LICENSE("GPL");
+
+static const char *nsp32_release_version = "1.0";
+
+
+/*
+ * structure for DMA/Scatter Gather list
+ */
+#define AUTOPARAM_SIZE		(sizeof(int)*0x15)	/* 4x15H = 0x60 */
+#define NSP_SG_SIZE		SG_ALL
+#define NSP32_SG_END_SGT	0x80000000		/* Last SGT marker */
+#define NSP32_SG_CNT_MASK	0x1FFFF
+
+struct nsp32_sgtable {
+	unsigned long		addr;		/* transfer address */
+	unsigned long		len;		/* transfer length.
+						   Bit (24-32) is for SGT_END */
+};
+
+struct nsp32_sglun {
+	struct nsp32_sgtable sgt[NSP_SG_SIZE+1];	/* SG table */
+};
+
+
+/*
+ * host data structure
+ */
+/* message in/out buffer */
+#define MSGOUTBUF_MAX	13  /* 13 is ok ? */
+#define MSGINBUF_MAX	13
+
+/* flag for trans_method */
+#define NSP32_TRANSFER_BUSMASTER	BIT(0)
+#define NSP32_TRANSFER_MMIO		BIT(1)	/* Not supported yet */
+#define NSP32_TRANSFER_PIO		BIT(2)	/* Not supported yet */
+
+
+/*
+ * SCSI TARGET/LUN definition
+ */
+#define NSP32_HOST_SCSIID	7	/* SCSI initiator is everytime defined as 7 */
+#define MAX_TARGET		8
+#define MAX_LUN			8	/* XXX: In SPI3, max number of LUN is 64. */
+
+
+/*
+ * structure for synchronous transfer negotiation data
+ */
+#define SYNC_NOT_YET	0
+#define SYNC_OK		1
+#define SYNC_NG		2
+
+struct nsp32_sync_table {
+	unsigned char	period_num;	/* period number */
+	unsigned char	ackwidth;	/* ack width designated by period */
+	unsigned char	start_period;	/* search range - start period */
+	unsigned char	end_period;	/* search range - end period */
+};
+
+
+/*
+ * structure for target device static data
+ */
+/* flag for nsp32_target.sync_flag */
+#define SDTR_INITIATOR		BIT(0)	/* sending SDTR from initiator */
+#define SDTR_TARGET		BIT(1)	/* sending SDTR from target */
+#define SDTR_DONE		BIT(2)	/* exchanging SDTR has been processed */
+
+/* syncronous period value for nsp32_target.config_max */
+#define FAST5M			0x32
+#define FAST10M			0x19
+#define ULTRA20M		0x0c
+
+/* flag for nsp32_target.{sync_offset}, period */
+#define ASYNC_OFFSET		0	/* asynchronous transfer */
+#define SYNC_OFFSET		0xf	/* synchronous transfer max offset */
+
+/* syncreg:
+      07 06 05 04 03 02 01 00
+      ---PERIOD-- ---OFFSET--   */
+#define TO_SYNCREG(period, offset)	(period << 4 | offset)
+
+struct nsp32_target {
+	unsigned char	syncreg;	/* value for SYNCREG  */
+	unsigned char	ackwidth;	/* value for ACKWIDTH */
+	unsigned char	offset;		/* sync offset (0-15) */
+	int		sync_flag;	/* SDTR_*, 0 */
+	int		limit_entry;	/* max speed limit entry designated
+					   by EEPROM configuration */
+};
+
+typedef struct _nsp32_hw_data {
+	int IrqNumber;
+	int BaseAddress;
+	int NumAddress;
+#define NSP32_MMIO_OFFSET 0x0800
+	unsigned long MmioAddress;
+	unsigned long length;
+
+	Scsi_Cmnd *CurrentSC;
+
+	struct pci_dev *Pci;
+	const struct pci_device_id *pci_devid;
+	struct Scsi_Host *Host;
+	spinlock_t Lock;
+
+	char info_str[100];
+
+	/* allocated memory region */
+	struct nsp32_lunt	*lunt_list;	/* kmalloc region for lunt */
+	struct nsp32_sglun	*sg_list;	/* sglist virtual address */
+	dma_addr_t		sgaddr;		/* physical address of hw_sg_table */
+	unsigned char		*autoparam;	/* auto parameter transfer region */
+	dma_addr_t		apaddr;		/* physical address of autoparam */
+	int 			cur_entry;	/* current sgt entry */
+
+	/* target/LUN */
+	struct nsp32_lunt	*curlunt;	/* Current connected LUN table */
+	struct nsp32_lunt	*lunt[MAX_TARGET][MAX_LUN];  /* All LUN table */
+	struct nsp32_target	*curtarget;	/* Current connected SCSI ID */
+	struct nsp32_target	target[MAX_TARGET];	     /* SCSI ID */
+	int			pid;		/* Current connected target ID */
+	int			plun;		/* Current connected target LUN */
+
+	/* behavior setting parameters */
+	int			trans_method;	/* transfer method flag */
+	int			resettime;	/* Reset time */
+	int 			clock;	       	/* clock dividing flag */
+	struct nsp32_sync_table	*synct;		/* sync_table determined by clock */
+	int			syncnum;	/* the max number of synct element */
+
+	/* message buffer */
+        unsigned char	msgoutbuf[MSGOUTBUF_MAX]; /* msgout buffer */
+	char		msgoutlen;		  /* msgoutbuf length */
+	unsigned char	msginbuf[MSGINBUF_MAX];	  /* megin buffer */
+	char		msginlen;		  /* msginbuf length */
+
+
+} nsp32_hw_data;
+static nsp32_hw_data nsp32_data_base;  /* probe <-> detect glue */
+
+
+/*
+ * TIME definition
+ */
+#define RESET_HOLD_TIME		10000	/* reset time in us (SCSI-2 says the
+					   minimum is 25us) */
+#define SEL_TIMEOUT_TIME	10000	/* 250ms defined in SCSI specification
+					   (25.6us/1unit) */
+#define ARBIT_TIMEOUT_TIME	100	/* 100us */
+#define REQSACK_TIMEOUT_TIME	10000	/* max wait time for REQ/SACK assertion
+					   or negation, 10000us == 10ms */
+
+/*
+ * structure for connected LUN dynamic data
+ *
+ * Note: Currently tagged queuing is disabled, each nsp32_lunt holds
+ *       one SCSI command and one state.
+ */
+#define DISCPRIV_OK		BIT(0)		/* DISCPRIV Enable mode */
+#define MSGIN03			BIT(1)		/* Auto Msg In 03 Flag */
+
+struct nsp32_lunt {
+	Scsi_Cmnd		*SCpnt;		/* Current Handling Scsi_Cmnd */
+	unsigned long		save_datp;	/* Save Data Pointer - saved position from initial address */
+	int			msgin03;	/* auto msg in 03 flag */
+	unsigned int		sg_num;		/* Total number of SG entries */
+	int			cur_entry;	/* Current SG entry number */
+	struct nsp32_sglun	*sglun;		/* sg table per lun */
+	long			sglun_paddr;	/* sglun physical address */
+};
+
+
+/*
+ * Period/AckWidth speed conversion table
+ *
+ * Note: This period/ackwidth speed table must be in descending order.
+ */
+static struct nsp32_sync_table nsp32_sync_table_40M[] = {
+     /* {PNo, AW,  SP,   EP}  Speed(MB/s) Period AckWidth */
+	{0x1, 0, 0x0c, 0x0c},	/*  20.0 :  50ns,  25ns */
+	{0x2, 0, 0x0d, 0x18},	/*  13.3 :  75ns,  25ns */
+	{0x3, 1, 0x19, 0x19},	/*  10.0 : 100ns,  50ns */
+	{0x4, 1, 0x1a, 0x1f},	/*   8.0 : 125ns,  50ns */
+	{0x5, 2, 0x20, 0x25},	/*   6.7 : 150ns,  75ns */
+	{0x6, 2, 0x26, 0x31},	/*   5.7 : 175ns,  75ns */
+	{0x7, 3, 0x32, 0x32},	/*   5.0 : 200ns, 100ns */
+	{0x8, 3, 0x33, 0x38},	/*   4.4 : 225ns, 100ns */
+	{0x9, 3, 0x39, 0x3e},	/*   4.0 : 250ns, 100ns */
+};
+static const int nsp32_table_40M_num =
+		sizeof(nsp32_sync_table_40M)/sizeof(struct nsp32_sync_table);
+
+static struct nsp32_sync_table nsp32_sync_table_20M[] = {
+	{0x1, 0, 0x19, 0x19},	/* 10.0 : 100ns,  50ns */
+	{0x2, 0, 0x1a, 0x25},	/*  6.7 : 150ns,  50ns */
+	{0x3, 1, 0x26, 0x32},	/*  5.0 : 200ns, 100ns */
+	{0x4, 1, 0x33, 0x3e},	/*  4.0 : 250ns, 100ns */
+	{0x5, 2, 0x3f, 0x4b},	/*  3.3 : 300ns, 150ns */
+	{0x6, 2, 0x4c, 0x57},	/*  2.8 : 350ns, 150ns */
+	{0x7, 3, 0x58, 0x64},	/*  2.5 : 400ns, 200ns */
+	{0x8, 3, 0x65, 0x70},	/*  2.2 : 450ns, 200ns */
+	{0x9, 3, 0x71, 0x7d},	/*  2.0 : 500ns, 200ns */
+};
+static const int nsp32_table_20M_num =
+		sizeof(nsp32_sync_table_20M)/sizeof(struct nsp32_sync_table);
+
+static struct nsp32_sync_table nsp32_sync_table_pci[] = {
+	{0x1, 0, 0x0c, 0x0f},	/* 16.6 :  60ns,  30ns */
+	{0x2, 0, 0x10, 0x16},	/* 11.1 :  90ns,  30ns */
+	{0x3, 1, 0x17, 0x1e},	/*  8.3 : 120ns,  60ns */
+	{0x4, 1, 0x1f, 0x25},	/*  6.7 : 150ns,  60ns */
+	{0x5, 2, 0x26, 0x2d},	/*  5.6 : 180ns,  90ns */
+	{0x6, 2, 0x2e, 0x34},	/*  4.8 : 210ns,  90ns */
+	{0x7, 3, 0x35, 0x3c},	/*  4.2 : 240ns, 120ns */
+	{0x8, 3, 0x3d, 0x43},	/*  3.7 : 270ns, 120ns */
+	{0x9, 3, 0x44, 0x4b}, 	/*  3.3 : 300ns, 120ns */
+};
+static const int nsp32_table_pci_num =
+		sizeof(nsp32_sync_table_pci)/sizeof(struct nsp32_sync_table);
+
+/*
+ * function declaration
+ */
+static int nsp32_detect(Scsi_Host_Template *);
+static int nsp32_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+static const char *nsp32_info(struct Scsi_Host *);
+static int nsp32_eh_abort(Scsi_Cmnd *);
+static int nsp32_eh_bus_reset(Scsi_Cmnd *);
+static int nsp32_eh_host_reset(Scsi_Cmnd *);
+static int nsp32_reset(Scsi_Cmnd *, unsigned int);
+static int nsp32_release(struct Scsi_Host *);
+static int nsp32_proc_info(char *, char **, off_t, int, int, int);
+static int __devinit nsp32_probe(struct pci_dev *, const struct pci_device_id *);
+static void __devexit nsp32_remove(struct pci_dev *);
+static int __init init_nsp32(void);
+static void __exit exit_nsp32(void);
+
+static void nsp32_message(char *, int, char *, char *, ...);
+static void nsp32_dmessage(char *, int, int, char *, ...);
+static void nsp32_build_identify(nsp32_hw_data *, Scsi_Cmnd *);
+static void nsp32_build_sdtr(nsp32_hw_data *, unsigned char, unsigned char);
+static void nsp32_build_nop(nsp32_hw_data *);
+static void nsp32_build_reject(nsp32_hw_data *);
+static int nsp32hw_start_selection(Scsi_Cmnd *, nsp32_hw_data *);
+static int nsp32_selection_autoscsi(Scsi_Cmnd *, nsp32_hw_data *);
+static int nsp32_reselection(nsp32_hw_data *, unsigned char);
+static int nsp32hw_setup_sg_table(Scsi_Cmnd *, nsp32_hw_data *);
+static int nsp32hw_init(struct Scsi_Host *);
+static void nsp32_scsi_done(nsp32_hw_data *, Scsi_Cmnd *);
+static int nsp32_busfree_occur(nsp32_hw_data *, unsigned short);
+static void nsp32_adjust_busfree(nsp32_hw_data *, unsigned int);
+static void nsp32_msgout_occur(nsp32_hw_data *);
+static void nsp32_restart_autoscsi(nsp32_hw_data *, unsigned short);
+static void nsp32_msgin_occur(nsp32_hw_data *, unsigned long, unsigned short);
+static void nsp32_analyze_sdtr(nsp32_hw_data *);
+static int nsp32_search_period_entry(nsp32_hw_data *,struct nsp32_target *, unsigned char);
+static void nsp32_set_async(nsp32_hw_data *, struct nsp32_target *);
+static void nsp32_set_max_sync(nsp32_hw_data *, struct nsp32_target *, unsigned char *, unsigned char *);
+static void nsp32_set_sync_entry(nsp32_hw_data *, struct nsp32_target *, int, unsigned char);
+static void nsp32_wait_req(nsp32_hw_data *, int);
+static void nsp32_wait_sack(nsp32_hw_data *, int);
+static void nsp32_sack_assert(nsp32_hw_data *);
+static void nsp32_sack_negate(nsp32_hw_data *);
+static void nsp32_do_bus_reset(nsp32_hw_data *);
+static void do_nsp32_isr(int, void *, struct pt_regs *);
+
+static int nsp32_getprom_param(nsp32_hw_data *);
+static int nsp32_getprom_new(nsp32_hw_data *);
+static int nsp32_getprom_standard(nsp32_hw_data *);
+static int nsp32_prom_read(nsp32_hw_data *, int);
+static void nsp32_prom_start(nsp32_hw_data *);
+static void nsp32_prom_stop(nsp32_hw_data *);
+static void nsp32_prom_write(nsp32_hw_data *, int);
+static int nsp32_prom_fetch(nsp32_hw_data *);
+static inline void nsp32_prom_set(nsp32_hw_data *, int, int);
+static inline int nsp32_prom_get(nsp32_hw_data *, int);
+
+
+/*
+ * max_sectors is currently limited up to 128.
+ */
+static Scsi_Host_Template driver_template = {
+	.proc_name =			"nsp32",
+	.name =				"Workbit NinjaSCSI-32Bi/UDE",
+	.proc_info =			nsp32_proc_info,
+	.detect =			nsp32_detect,
+	.info =				nsp32_info,
+	.queuecommand =			nsp32_queuecommand,
+	.can_queue =			1,
+	.sg_tablesize =			NSP_SG_SIZE,
+	.max_sectors =			128,
+	.cmd_per_lun =			1,
+	.this_id =			7,
+	.use_clustering =		DISABLE_CLUSTERING,
+	.eh_abort_handler =       	nsp32_eh_abort,
+	.eh_device_reset_handler =	NULL,
+	.eh_bus_reset_handler =		nsp32_eh_bus_reset,
+	.eh_host_reset_handler =	nsp32_eh_host_reset,
+	.reset =			nsp32_reset,
+	.release =			nsp32_release,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,2))
+	.use_new_eh_code =        	1,
+#else
+	/* .highmem_io =		1,	*/
+#endif
+};
+
+#include "nsp32_io.h"
+
+/*
+ * debug, error print
+ */
+#define nsp32_msg(type, args...) \
+	nsp32_message(__FUNCTION__, __LINE__, (type), ## args)
+#define nsp32_dbg(mask, args...) \
+	nsp32_dmessage(__FUNCTION__, __LINE__, (mask), ## args)
+
+#ifndef NSP32_DEBUG
+# define NSP32_DEBUG_MASK		0x000000
+#else
+# define NSP32_DEBUG_MASK		0xffffff
+#endif
+
+#define NSP32_DEBUG_QUEUECOMMAND	0x000001
+#define NSP32_DEBUG_REGISTER		0x000002
+#define NSP32_DEBUG_AUTOSCSI		0x000004
+#define NSP32_DEBUG_INTR		0x000008
+#define NSP32_DEBUG_SGLIST		0x000010
+#define NSP32_DEBUG_BUSFREE		0x000020
+#define NSP32_DEBUG_CDB_CONTENTS	0x000040
+#define NSP32_DEBUG_RESELECTION		0x000080
+#define NSP32_DEBUG_MSGINOCCUR		0x000100
+#define NSP32_DEBUG_EEPROM		0x000200
+#define NSP32_DEBUG_MSGOUTOCCUR		0x000400
+#define NSP32_DEBUG_BUSRESET		0x000800
+#define NSP32_DEBUG_RESTART		0x001000
+#define NSP32_DEBUG_SYNC		0x002000
+#define NSP32_DEBUG_WAIT		0x004000
+#define NSP32_DEBUG_TARGETFLAG		0x008000
+#define NSP32_DEBUG_PROC		0x010000
+#define NSP32_DEBUG_INIT		0x020000
+#define NSP32_SPECIAL_PRINT_REGISTER	0x100000
+
+#define NSP32_DEBUG_BUF_LEN		100
+
+static void nsp32_message(char *func, int line, char *type, char *fmt, ...)
+{
+	va_list args;
+	char buf[NSP32_DEBUG_BUF_LEN];
+
+	va_start(args, fmt);
+	vsprintf(buf, fmt, args);
+	va_end(args);
+
+#ifndef NSP32_DEBUG
+	printk("%snsp32: %s\n", type, buf);
+#else
+	printk("%snsp32: %s (%d): %s\n", type, func, line, buf);
+#endif
+}
+
+static void nsp32_dmessage(char *func, int line, int mask, char *fmt, ...)
+{
+	va_list args;
+	char buf[NSP32_DEBUG_BUF_LEN];
+
+	va_start(args, fmt);
+	vsprintf(buf, fmt, args);
+	va_end(args);
+
+	if (mask & NSP32_DEBUG_MASK) {
+		printk("Ninja: %d %s (%d): %s\n", mask, func, line, buf);
+	}
+}
+
+#ifdef NSP32_DEBUG
+# include "nsp32_debug.c"
+#else
+# define show_command(arg)   /* */
+# define show_busphase(arg)  /* */
+# define show_autophase(arg) /* */
+#endif
+
+#ifdef NSP32_DEBUG
+static int pc_debug = NSP32_DEBUG;
+MODULE_PARM(pc_debug, "i");
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(/*KERN_DEBUG*/ args)
+#else
+#define DEBUG(n, args...)
+#endif
+
+
+/*
+ * IDENTIFY Message
+ */
+static void nsp32_build_identify(nsp32_hw_data *data, Scsi_Cmnd *SCpnt)
+{
+	int pos = data->msgoutlen;
+
+	data->msgoutbuf[pos++] =
+		0x80 |		/* Identify */
+#if 0
+		/* XXX: Auto DiscPriv detection is progressing... */
+		0x40 |		/* DiscPriv */
+#endif
+		SCpnt->lun;	/* LUNTRN */
+
+	data->msgoutlen = pos;
+}
+
+/*
+ * SDTR Message Routine
+ */
+static void nsp32_build_sdtr(nsp32_hw_data *data,
+			     unsigned char period, unsigned char offset)
+{
+	int pos = data->msgoutlen;
+
+	data->msgoutbuf[pos++] = EXTENDED_MESSAGE;
+	data->msgoutbuf[pos++] = EXTENDED_SDTR_LEN;
+	data->msgoutbuf[pos++] = EXTENDED_SDTR;
+	data->msgoutbuf[pos++] = period;
+	data->msgoutbuf[pos++] = offset;
+
+	data->msgoutlen = pos;
+}
+
+/*
+ * No Operation Message
+ */
+static void nsp32_build_nop(nsp32_hw_data *data)
+{
+	int pos = data->msgoutlen;
+
+	if (pos != 0) {
+		nsp32_msg(KERN_WARNING,
+			  "Some messages are already contained!");
+		return;
+	}
+
+	data->msgoutbuf[pos++] = NOP;
+	data->msgoutlen = pos;
+}
+
+/*
+ * Reject Message
+ */
+static void nsp32_build_reject(nsp32_hw_data *data)
+{
+	int pos = data->msgoutlen;
+
+	data->msgoutbuf[pos++] = MESSAGE_REJECT;
+	data->msgoutlen = pos;
+}
+	
+/*
+ * timer
+ */
+#if 0
+static void nsp32_start_timer(Scsi_Cmnd *SCpnt, int time)
+{
+	unsigned int base = SCpnt->host->io_port;
+
+	DEBUG(0, __func__ " time=%d\n", time);
+
+	if (time & (~TIMER_CNT_MASK)) {
+		printk("timer set overflow\n");
+	}
+
+	nsp32_write2(base, TIMER_SET, time & TIMER_CNT_MASK);
+}
+#endif
+
+
+/*
+ * set SCSI command and other parameter to asic, and start selection phase
+ */
+static int nsp32hw_start_selection(Scsi_Cmnd *SCpnt, nsp32_hw_data *data)
+{
+	unsigned int   host_id = SCpnt->host->this_id;
+	unsigned int   base    = SCpnt->host->io_port;
+	unsigned char  target  = SCpnt->target;
+	unsigned char  *param  = data->autoparam;
+	unsigned char  phase, arbit;
+	int	       i, time;
+	unsigned int   msgout;
+	unsigned long  l;
+	unsigned short s;
+
+	/*
+	 * check bus free
+	 */
+	phase = nsp32_read1(base, SCSI_BUS_MONITOR);
+	if (phase != BUSMON_BUS_FREE) {
+		nsp32_msg(KERN_WARNING, "bus busy");
+		show_busphase(phase & BUSMON_PHASE_MASK);
+		SCpnt->result = DID_BUS_BUSY << 16;
+		return FALSE;
+	}
+
+	/*
+	 * message out
+	 *
+	 * Note: If the range of msgoutlen is 1 - 3, fill scsi_msgout.
+	 *       over 3 messages needs another routine.
+	 */
+	if (data->msgoutlen == 0) {
+		nsp32_msg(KERN_ERR, "SCSI MsgOut without any message!");
+		SCpnt->result = DID_ERROR << 16;
+		return FALSE;
+	} else if (data->msgoutlen > 0 && data->msgoutlen <= 3) {
+		msgout = 0;
+		for (i=0; i<data->msgoutlen; i++) {
+			/*
+			 * the sending order of the message is:
+			 *  MCNT 3: MSG#0 -> MSG#1 -> MSG#2
+			 *  MCNT 2:          MSG#1 -> MSG#2
+			 *  MCNT 1:                   MSG#2    
+			 */
+			msgout >>= 8;
+			msgout |= (unsigned int)(data->msgoutbuf[i] << 24);
+		}
+		msgout |= MV_VALID;	/* MV valid */
+		msgout |= (unsigned int)data->msgoutlen; /* len */
+	} else {
+		/* data->msgoutlen > 3 */
+		msgout = 0;
+	}
+
+	/*
+	 * setup asic parameter
+	 */
+	memset(param, 0, AUTOPARAM_SIZE);
+
+	/* cdb */
+	for (i=0; i<SCpnt->cmd_len; i++) {
+		param[4*i] = SCpnt->cmnd[i];
+	}
+
+	/* message out */
+	param[4*0x10 +0] = (msgout & 0x000000ff) >> 0;
+	param[4*0x10 +1] = (msgout & 0x0000ff00) >> 8;
+	param[4*0x10 +2] = (msgout & 0x00ff0000) >> 16;
+	param[4*0x10 +3] = (msgout & 0xff000000) >> 24;
+
+	/* syncreg, ackwidth, target id, sampleing rate */
+	param[4*0x11 +0] = data->curtarget->syncreg;
+	param[4*0x11 +1] = data->curtarget->ackwidth;
+	param[4*0x11 +2] = BIT(host_id) | BIT(target);
+	param[4*0x11 +3] = 0;
+
+	/* command control */
+	s = (CLEAR_CDB_FIFO_POINTER | AUTOSCSI_START |
+	     AUTO_MSGIN_00_OR_04 | AUTO_MSGIN_02 | AUTO_ATN);
+	param[4*0x12 +0] = (s & 0x00ff) >> 0;
+	param[4*0x12 +1] = (s & 0xff00) >> 8;
+
+	/* transfer control */
+	s = 0;
+	switch (data->trans_method) {
+	case NSP32_TRANSFER_BUSMASTER:
+		s |= BM_START;
+		break;
+	case NSP32_TRANSFER_MMIO:
+		s |= CB_MMIO_MODE;
+		break;
+	case NSP32_TRANSFER_PIO:
+		s |= CB_IO_MODE;
+		break;
+	default:
+		nsp32_msg(KERN_ERR, "unknown trans_method");
+	}
+	/*
+	 * ORed BLIEND_MODE, FIFO intr is decreased, instead of PCI bus waits.
+	 * For bus master transfer, it's taken off.
+	 */
+	s |= (TRANSFER_GO | ALL_COUNTER_CLR);
+	param[4*0x12 +2] = (s & 0x00ff) >> 0;
+	param[4*0x12 +3] = (s & 0xff00) >> 8;
+
+	/* sg table addr */
+	l = data->curlunt->sglun_paddr;
+	param[4*0x13 +0] = (l & 0x000000ff) >> 0;
+	param[4*0x13 +1] = (l & 0x0000ff00) >> 8;
+	param[4*0x13 +2] = (l & 0x00ff0000) >> 16;
+	param[4*0x13 +3] = (l & 0xff000000) >> 24;
+
+	/*
+	 * transfer parameter to asic
+	 */
+	nsp32_write4(base, SGT_ADR,         virt_to_bus(param));
+	nsp32_write2(base, COMMAND_CONTROL, CLEAR_CDB_FIFO_POINTER |
+		                            AUTO_PARAMETER         );
+
+	/*
+	 * Arbitration Status Check
+	 *	
+	 * Note: Arbitration counter is wait during ARBIT_GO is not lifting.
+	 *	 Using udelay(1) consumes CPU time and system time, but 
+	 *	 arbitration delay time is defined minimal 2.4us in SCSI
+	 *	 specification, thus udelay works as coarse grained wait timer.
+	 */
+	time = 0;
+	do {
+		arbit = nsp32_read1(base, ARBIT_STATUS);
+		nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "arbit=0x%x", arbit);
+	} while ((arbit & (ARBIT_WIN | ARBIT_FAIL)) == 0 &&
+		 (time++ <= 1000));
+
+	nsp32_dbg(NSP32_DEBUG_AUTOSCSI,
+		  "arbit: 0x%x, delay time: %d", arbit, time);
+
+	if (arbit & ARBIT_WIN) {
+		SCpnt->result = DID_OK << 16;
+		/* PCI LED on! */
+		nsp32_index_write1(base, EXT_PORT, LED_ON);
+	} else if (arbit & ARBIT_FAIL) {
+		SCpnt->result = DID_BUS_BUSY << 16;
+		nsp32_write1(base, SET_ARBIT, ARBIT_CLEAR);
+		return FALSE;
+	} else {
+		/* unknown error or ARBIT_GO timeout */
+		nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "arbit fail");
+		SCpnt->result = DID_NO_CONNECT << 16;
+		nsp32_write1(base, SET_ARBIT, ARBIT_CLEAR);
+		return FALSE;
+        }
+
+	/*
+	 * clear Arbit
+	 */
+	nsp32_write1(base, SET_ARBIT, ARBIT_CLEAR);
+
+	return TRUE;
+}
+
+
+/*
+ * Selection with AUTO SCSI (without AUTO PARAMETER)
+ */
+static int nsp32_selection_autoscsi(Scsi_Cmnd *SCpnt, nsp32_hw_data *data)
+{
+	unsigned char	phase;
+	unsigned char	arbit;
+	int		status;
+	int		i;
+	unsigned short	command	= 0;
+	int		time = 0;
+	unsigned int	msgout = 0;
+	unsigned short	execph;
+	unsigned int	base = data->BaseAddress;
+
+	/*
+	 * IRQ disable
+	 */
+	nsp32_write2(base, IRQ_CONTROL, IRQ_CONTROL_ALL_IRQ_MASK);
+
+	/*
+	 * check bus line
+	 */
+	phase = nsp32_read1(base, SCSI_BUS_MONITOR);
+	if(((phase & BUSMON_BSY) == 1) ||
+	   (phase & BUSMON_SEL) == 1) {
+		nsp32_msg(KERN_WARNING, "bus busy");
+		SCpnt->result = DID_BUS_BUSY << 16;
+		status = 1;
+		goto out;
+        }
+
+	/*
+	 * clear execph
+	 */
+	execph = nsp32_read2(base, SCSI_EXECUTE_PHASE);
+
+	/*
+	 * clear FIFO counter to set CDBs
+	 */
+	nsp32_write2(base, COMMAND_CONTROL, CLEAR_CDB_FIFO_POINTER);
+
+	/*
+	 * set CDB0 - CDB15
+	 */
+	for (i=0; i<SCpnt->cmd_len; i++) {
+		nsp32_write1(base, COMMAND_DATA, SCpnt->cmnd[i]);
+        }
+	nsp32_dbg(NSP32_DEBUG_CDB_CONTENTS, "CDB[0]=[0x%x]", SCpnt->cmnd[i]);
+
+	/*
+	 * set SCSIOUT LATCH(initiator)/TARGET(target) (ORed) ID
+	 */
+	nsp32_write1(base, SCSI_OUT_LATCH_TARGET_ID,
+		((1 << NSP32_HOST_SCSIID) | (1 << SCpnt->target)));
+
+	/*
+	 * set SCSI MSGOUT REG
+	 *
+	 * Note: If the range of msgoutlen is 1 - 3, fill scsi_msgout.
+	 *       over 3 messages needs another routine.
+	 */
+	if (data->msgoutlen == 0) {
+		nsp32_msg(KERN_ERR, 
+			  "SCSI MsgOut without any message!");
+		SCpnt->result = DID_ERROR << 16;
+		status = 1;
+		goto out;
+	} else if (data->msgoutlen > 0 && data->msgoutlen <= 3) {
+		msgout = 0;
+		for (i=0; i<data->msgoutlen; i++) {
+			/*
+			 * the sending order of the message is:
+			 *  MCNT 3: MSG#0 -> MSG#1 -> MSG#2
+			 *  MCNT 2:          MSG#1 -> MSG#2
+			 *  MCNT 1:                   MSG#2    
+			 */
+			msgout >>= 8;
+			msgout |= (unsigned int)(data->msgoutbuf[i] << 24);
+		}
+		msgout |= MV_VALID;	/* MV valid */
+		msgout |= (unsigned int)data->msgoutlen; /* len */
+		nsp32_write4(base, SCSI_MSG_OUT, msgout);
+	} else {
+		/* data->msgoutlen > 3 */
+		nsp32_write4(base, SCSI_MSG_OUT, 0);
+	}
+
+	/*
+	 * set selection timeout(= 250ms)
+	 */
+	nsp32_write2(base, SEL_TIME_OUT, SEL_TIMEOUT_TIME);
+
+	/*
+	 * set smpl rate
+	 * 
+	 * TODO: smpl_rate (BASE+0F) is 0 when internal clock = 40MHz.
+	 *      check other internal clock!
+	 */
+	nsp32_write1(base, SREQ_SMPL_RATE, 0);
+
+	/*
+	 * clear Arbit
+	 */
+	nsp32_write1(base, SET_ARBIT, ARBIT_CLEAR);
+
+	/*
+	 * set SYNCREG
+	 * Don't set BM_START_ADR before setting this register.
+	 */
+	nsp32_write1(base, SYNC_REG, data->curtarget->syncreg);
+
+	/*
+	 * set ACKWIDTH
+	 */
+	nsp32_write1(base, ACK_WIDTH, data->curtarget->ackwidth);
+
+	nsp32_dbg(NSP32_DEBUG_AUTOSCSI,
+		  "syncreg=0x%x, ackwidth=0x%x, sgtpaddr=0x%x, id=0x%x",
+		  nsp32_read1(base, SYNC_REG), nsp32_read1(base, ACK_WIDTH),
+		  nsp32_read4(base, SGT_ADR), nsp32_read1(base, SCSI_OUT_LATCH_TARGET_ID));
+	nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "msgoutlen=%d, msgout=0x%x",
+		  data->msgoutlen, msgout);
+
+	/*
+	 * set SGT ADDR (physical address)
+	 */
+	nsp32_write4(base, SGT_ADR, data->curlunt->sglun_paddr);
+
+	/*
+	 * set TRANSFER CONTROL REG
+	 */
+	command = 0;
+	command |= ( TRANSFER_GO | ALL_COUNTER_CLR);
+	if (data->trans_method & NSP32_TRANSFER_BUSMASTER) {
+		if (SCpnt->request_bufflen > 0) {
+			command |= BM_START;
+		}
+	} else if (data->trans_method & NSP32_TRANSFER_MMIO) {
+		command |= CB_MMIO_MODE;
+	} else if (data->trans_method & NSP32_TRANSFER_PIO) {
+		command |= CB_IO_MODE;
+	}
+	nsp32_write2(base, TRANSFER_CONTROL, command);
+
+	/*
+	 * start AUTO SCSI, kick off arbitration
+	 */
+	command = 0;
+	command |= (CLEAR_CDB_FIFO_POINTER
+		    | AUTOSCSI_START
+		    | AUTO_MSGIN_00_OR_04
+		    | AUTO_MSGIN_02 
+		    | AUTO_ATN);
+	nsp32_write2(base, COMMAND_CONTROL, command);
+
+	/*
+	 * Arbitration Status Check
+	 *	
+	 * Note: Arbitration counter is wait during ARBIT_GO is not lifting.
+	 *	 Using udelay(1) consumes CPU time and system time, but 
+	 *	 arbitration delay time is defined minimal 2.4us in SCSI
+	 *	 specification, thus udelay works as coarse grained wait timer.
+	 */
+	time = 0;
+	while(1) {
+		arbit = nsp32_read1(base, ARBIT_STATUS);
+		if(arbit & ARBIT_GO) {
+			udelay(1);
+			time++;
+			if ( time > ARBIT_TIMEOUT_TIME ) {
+				/* something lock up! guess no connection */
+				SCpnt->result = DID_NO_CONNECT << 16;
+				status = FALSE;
+				goto out;
+			}
+		} else {
+			break;
+		}
+	};
+
+	nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "arbit: 0x%x, delay time: %d", arbit, time);
+
+	/*
+	 * check Arbitration Status Result
+	 */
+	if(arbit & ARBIT_WIN) {
+		/* Arbitration succeeded */
+		status = TRUE;
+		SCpnt->result = DID_OK << 16;
+		/* PCI LED on! */
+		nsp32_index_write1(base, EXT_PORT, LED_ON);
+	} else if(arbit & ARBIT_FAIL) {
+		/* Arbitration failed */
+		status = FALSE;
+		SCpnt->result = DID_BUS_BUSY << 16;
+	} else {
+		/* unknown error? */
+		status = FALSE;
+		SCpnt->result = DID_ERROR << 16;
+		SCpnt->result = DID_NO_CONNECT << 16;
+	}
+
+	/*
+	 * clear Arbit
+	 */
+	nsp32_write1(base, SET_ARBIT, ARBIT_CLEAR);
+
+ out:
+	/*
+	 * IRQ enable
+	 */
+	nsp32_write2(base, IRQ_CONTROL, 0);
+
+	return(status);
+}
+
+
+/*
+ * reselection
+ *
+ * Note: This reselection routine is called from msgin_occur,
+ *	 reselection target id&lun must be already set.
+ *	 SCSI-2 says IDENTIFY implies RESTORE_POINTER operation.
+ */
+static int nsp32_reselection(nsp32_hw_data *data, unsigned char newlun)
+{
+	unsigned int base = data->BaseAddress;
+	unsigned char tmpid, newid;
+
+	nsp32_dbg(NSP32_DEBUG_RESELECTION, "enter");
+
+	/*
+	 * calculate reselected SCSI ID
+	 */
+	tmpid = nsp32_read1(base, RESELECT_ID);
+	tmpid &= 0x7f;
+	newid = 0;
+	while (tmpid) {
+		if (tmpid & 1) {
+			break;
+		}
+		tmpid >>= 1;
+		newid++;
+	}
+
+	/*
+	 * If reselected New ID:LUN is not existed
+	 * or current nexus is not existed, unexpected
+	 * reselection is occured. Send reject message.
+	 */
+	if (newid >= MAX_TARGET || newlun >= MAX_LUN) {
+		nsp32_msg(KERN_WARNING, "unknown id/lun");
+		return FALSE;
+	} else if(data->lunt[newid][newlun]->SCpnt == NULL) {
+		nsp32_msg(KERN_WARNING, "no SCSI command is processing");
+		return FALSE;
+	}
+
+	data->pid       = newid;
+	data->plun      = newlun;
+	data->curtarget = &data->target[newid];
+	data->curlunt   = data->lunt[newid][newlun];
+
+	/* reset SACK/SavedACK counter (or ALL clear?) */
+	nsp32_write4(base, CLR_COUNTER, CLRCOUNTER_ALLMASK);
+
+	return TRUE;
+}
+
+
+/*
+ * nsp32hw_setup_sg_table - build scatter gather list for transfer data
+ *			    with bus master.
+ *
+ * Note: NinjaSCSI-32Bi/UDE bus master can not transfer over 64KB at a time.
+ */
+static int nsp32hw_setup_sg_table(Scsi_Cmnd *SCpnt, nsp32_hw_data *data)
+{
+	struct scatterlist *sgl;
+	struct nsp32_sgtable *sgt = data->curlunt->sglun->sgt;
+	int num, i;
+
+	if (SCpnt->request_bufflen == 0) {
+		return TRUE;
+	}
+
+	if (sgt == NULL) {
+		nsp32_dbg(NSP32_DEBUG_SGLIST, "SGT == null");
+		return FALSE;
+	}
+
+	if (SCpnt->use_sg) {
+		sgl = (struct scatterlist *)SCpnt->request_buffer;
+		num = pci_map_sg(data->Pci, sgl, SCpnt->use_sg,
+				 scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+		for (i=0; i<num; i++) {
+			/*
+			 * Build nsp32_sglist, substitute sg dma addresses.
+			 */
+			sgt[i].addr = cpu_to_le32(sg_dma_address(sgl));
+			sgt[i].len  = cpu_to_le32(sg_dma_len(sgl));
+			sgl++;
+
+			if (sgt[i].len > 65536) {
+				nsp32_msg(KERN_ERR,
+					"can't transfer over 64KB at a time");
+				return FALSE;
+			}
+			nsp32_dbg(NSP32_DEBUG_SGLIST,
+				  "num 0x%x : addr 0x%lx len 0x%x",
+				  i, sgt[i].addr, sgt[i].len);
+		}
+		sgt[num-1].len |= NSP32_SG_END_SGT; /* set end mark */
+	} else {
+		SCpnt->SCp.have_data_in	= pci_map_single(data->Pci,
+			SCpnt->request_buffer, SCpnt->request_bufflen,
+			scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+		sgt[0].addr = cpu_to_le32(SCpnt->SCp.have_data_in);
+		sgt[0].len  = cpu_to_le32(SCpnt->request_bufflen);
+		sgt[0].len |= NSP32_SG_END_SGT; /* set end mark */
+
+		nsp32_dbg(NSP32_DEBUG_SGLIST, "single : addr 0x%lx len=0x%x",
+			  sgt[0].addr, sgt[0].len);
+	}
+
+	return TRUE;
+}
+
+static int nsp32_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+{
+	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->host->hostdata;
+	struct nsp32_target *target;
+	struct nsp32_lunt *curlunt;
+	int ret;
+
+	nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND,
+		  "enter. target: 0x%x LUN: 0x%x cmnd: 0x%x cmndlen: 0x%x "
+		  "use_sg: 0x%x reqbuf: 0x%lx reqlen: 0x%x",
+		  SCpnt->target, SCpnt->lun, SCpnt->cmnd[0], SCpnt->cmd_len,
+		  SCpnt->use_sg, SCpnt->request_buffer, SCpnt->request_bufflen);
+
+	if (data->CurrentSC != NULL ) {
+		nsp32_msg(KERN_ERR, "Currentsc != NULL. Cancel this command request");
+		data->CurrentSC = NULL;
+		SCpnt->result   = DID_NO_CONNECT << 16;
+		done(SCpnt);
+
+		return 1;
+	}
+
+	/* check target ID is not same as this initiator ID */
+	if (SCpnt->target == NSP32_HOST_SCSIID) {
+		SCpnt->result = DID_BAD_TARGET << 16;
+		done(SCpnt);
+		return 1;
+	}
+
+	/* check target LUN is allowable value */
+	if (SCpnt->lun >= MAX_LUN) {
+		SCpnt->result = DID_BAD_TARGET << 16;
+		done(SCpnt);
+		return 1;
+	}
+
+	show_command(SCpnt);
+
+	SCpnt->scsi_done     = done;
+	data->CurrentSC      = SCpnt;
+	SCpnt->SCp.Status    = CHECK_CONDITION;
+	SCpnt->SCp.Message   = 0;
+	SCpnt->resid         = 0; //SCpnt->request_bufflen;
+
+	SCpnt->SCp.ptr		    = (char *) SCpnt->request_buffer;
+	SCpnt->SCp.this_residual    = SCpnt->request_bufflen;
+	SCpnt->SCp.buffer	    = NULL;
+	SCpnt->SCp.buffers_residual = 0;
+
+	/* initialize data */
+	data->msgoutlen		= 0;
+	data->msginlen		= 0;
+	curlunt			= data->lunt[SCpnt->target][SCpnt->lun];
+	curlunt->SCpnt		= SCpnt;
+	curlunt->save_datp	= 0;
+	curlunt->msgin03	= FALSE;
+	data->curlunt		= curlunt;
+	data->pid		= SCpnt->target;
+	data->plun		= SCpnt->lun;
+
+	ret = nsp32hw_setup_sg_table(SCpnt, data);
+	if (ret == FALSE) {
+		SCpnt->result = DID_ERROR << 16;
+		nsp32_scsi_done(data, SCpnt);
+	}
+
+	/* Build IDENTIFY */
+	nsp32_build_identify(data, SCpnt);
+
+	/* 
+	 * If target is the first time to transfer after the reset
+	 * (target don't have SDTR_DONE and SDTR_INITIATOR), sync
+	 * message SDTR is needed to do synchronous transfer.
+	 */
+	target = &data->target[SCpnt->target];
+	data->curtarget = target;
+
+	if (!(target->sync_flag & (SDTR_DONE | SDTR_INITIATOR | SDTR_TARGET))) {
+		unsigned char period, offset;
+
+		if (trans_mode != ASYNC_MODE) {
+			nsp32_set_max_sync(data, target, &period, &offset);
+			nsp32_build_sdtr(data, period, offset);
+			target->sync_flag |= SDTR_INITIATOR;
+		} else {
+			nsp32_set_async(data, target);
+			target->sync_flag |= SDTR_DONE;
+		}
+
+		nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND,
+			  "SDTR: entry: %d start_period: 0x%x offset: 0x%x\n",
+			  target->limit_entry, period, offset);
+	} else if (target->sync_flag & SDTR_INITIATOR) {
+		/*
+		 * It was negotiating SDTR with target, sending from the
+		 * initiator, but there are no chance to remove this flag.
+		 * Set async because we don't get proper negotiation.
+		 */
+		nsp32_set_async(data, target);
+		target->sync_flag &= ~SDTR_INITIATOR;
+		target->sync_flag |= SDTR_DONE;
+
+		nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND,
+			  "SDTR_INITIATOR: fall back to async");
+	} else if (target->sync_flag & SDTR_TARGET) {
+		/*
+		 * It was negotiating SDTR with target, sending from target,
+		 * but there are no chance to remove this flag.  Set async
+		 * because we don't get proper negotiation.
+		 */
+		nsp32_set_async(data, target);
+		target->sync_flag &= ~SDTR_TARGET;
+		target->sync_flag |= SDTR_DONE;
+
+		nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND,
+			  "Unknown SDTR from target is reached, fall back to async.");
+	}
+
+	nsp32_dbg(NSP32_DEBUG_TARGETFLAG,
+		  "target: %d sync_flag: 0x%x syncreg: 0x%x ackwidth: 0x%x",
+		  SCpnt->target, target->sync_flag, target->syncreg,
+		  target->ackwidth);
+
+	/* Selection */
+	if (auto_param == 0) {
+		ret = nsp32hw_start_selection(SCpnt, data);
+	} else {
+		ret = nsp32_selection_autoscsi(SCpnt, data);
+	}
+
+	if (ret != TRUE) {
+		nsp32_scsi_done(data, SCpnt);
+		return 1;
+	}
+
+	return 0;
+}
+
+/* initialize asic */
+static int nsp32hw_init(struct Scsi_Host *host)
+{
+	unsigned int  base = host->io_port;
+	unsigned short irq_stat;
+	unsigned long lc_reg;
+	unsigned char power;
+	nsp32_hw_data *data = (nsp32_hw_data *)host->hostdata;
+
+	lc_reg = nsp32_index_read4(base, CFG_LATE_CACHE);
+	if ((lc_reg & 0xff00) == 0) {
+		lc_reg |= (0x20 << 8);
+		nsp32_index_write2(base, CFG_LATE_CACHE, lc_reg & 0xffff);
+	}
+
+	nsp32_write2(base, IRQ_CONTROL,      IRQ_CONTROL_ALL_IRQ_MASK);
+	nsp32_write2(base, TRANSFER_CONTROL, 0);
+	nsp32_write4(base, BM_CNT,           0);
+	nsp32_write2(base, SCSI_EXECUTE_PHASE, 0);
+
+	do {
+		irq_stat = nsp32_read2(base, IRQ_STATUS);
+	} while (irq_stat & IRQSTATUS_ANY_IRQ);
+	nsp32_dbg(NSP32_DEBUG_INIT, "irq_stat 0x%x", irq_stat);
+
+	/*
+	 * Fill FIFO_FULL_SHLD, FIFO_EMPTY_SHLD. Below parameter is
+	 *  designated by specification.
+	 */
+	if ((data->trans_method & NSP32_TRANSFER_PIO) ||
+	    (data->trans_method & NSP32_TRANSFER_MMIO)) {
+		nsp32_index_write1(base, FIFO_FULL_SHLD_COUNT, 0x40);
+	} else if (data->trans_method & NSP32_TRANSFER_BUSMASTER) {
+		nsp32_index_write1(base, FIFO_FULL_SHLD_COUNT, 0x10);
+	}
+	nsp32_index_write1(base, FIFO_EMPTY_SHLD_COUNT, 0x60);
+
+	nsp32_dbg(NSP32_DEBUG_INIT, "full 0x%x emp 0x%x",
+		  nsp32_index_read1(base, FIFO_FULL_SHLD_COUNT),
+		  nsp32_index_read1(base, FIFO_EMPTY_SHLD_COUNT));
+
+	nsp32_index_write1(base, CLOCK_DIV, data->clock);
+	nsp32_index_write1(base, BM_CYCLE, MEMRD_CMD1 | SGT_AUTO_PARA_MEMED_CMD);
+	nsp32_write1(base, PARITY_CONTROL, 0);	/* parity check is disable */
+
+	/*
+	 * initialize I_MISC_WRRD register
+	 * 
+	 * Note: Designated parameters is obeyed as following:
+	 *	MISC_SCSI_DIRECTION_DETECTOR_SELECT: It must be set.
+	 *	MISC_MASTER_TERMINATION_SELECT:      It must be set.
+	 *	MISC_BMREQ_NEGATE_TIMING_SEL:	     It should be set.
+	 *	MISC_AUTOSEL_TIMING_SEL:	     It should be set.
+	 *	MISC_BMSTOP_CHANGE2_NONDATA_PHASE:   It should be set.
+	 *	MISC_DELAYED_BMSTART:		     It's selected for safety.
+	 *
+	 * Note: If MISC_BMSTOP_CHANGE2_NONDATA_PHASE is set, then
+	 *	we have to set TRANSFERCONTROL_BM_START as 0 and set
+	 *	appropriate value before restarting bus master transfer.
+	 */
+	nsp32_index_write2(base, MISC_WR,
+			   (SCSI_DIRECTION_DETECTOR_SELECT |
+			    DELAYED_BMSTART |
+			    MASTER_TERMINATION_SELECT |
+			    BMREQ_NEGATE_TIMING_SEL |
+			    AUTOSEL_TIMING_SEL |
+			    BMSTOP_CHANGE2_NONDATA_PHASE));
+
+	nsp32_index_write1(base, TERM_PWR_CONTROL, 0);
+	power = nsp32_index_read1(base, TERM_PWR_CONTROL);
+	if (!(power & SENSE)) {
+		nsp32_msg(KERN_INFO, "term power on");
+		nsp32_index_write1(base, TERM_PWR_CONTROL, BPWR);
+	}
+
+	nsp32_write2(base, TIMER_SET, TIMER_STOP);
+	nsp32_write2(base, TIMER_SET, TIMER_STOP);
+
+	nsp32_write1(base, SYNC_REG,  0);
+	nsp32_write1(base, ACK_WIDTH, 0);
+	nsp32_write2(base, SEL_TIME_OUT, 10000); /* 25us x10000 = 250ms defined in SCSI */
+
+	/*
+	 * enable to select designated IRQ (except for
+	 * IRQSELECT_SERR, IRQSELECT_PERR, IRQSELECT_BMCNTERR)
+	 */
+	nsp32_index_write2(base, IRQ_SELECT, IRQSELECT_TIMER_IRQ         |
+			                     IRQSELECT_SCSIRESET_IRQ     |
+			                     IRQSELECT_FIFO_SHLD_IRQ     |
+			                     IRQSELECT_RESELECT_IRQ      |
+			                     IRQSELECT_PHASE_CHANGE_IRQ  |
+			                     IRQSELECT_AUTO_SCSI_SEQ_IRQ |
+			                     //IRQSELECT_BMCNTERR_IRQ    |
+			                     IRQSELECT_TARGET_ABORT_IRQ  |
+			                     IRQSELECT_MASTER_ABORT_IRQ );
+	nsp32_write2(base, IRQ_CONTROL, 0);
+
+	/* PCI LED off */
+	nsp32_index_write1(base, EXT_PORT_DDR, LED_OFF);
+	nsp32_index_write1(base, EXT_PORT, LED_OFF);
+
+	return TRUE;
+}
+
+
+/* interrupt routine */
+static void do_nsp32_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	nsp32_hw_data *data = dev_id;
+	unsigned int base = data->BaseAddress;
+	Scsi_Cmnd *SCpnt = data->CurrentSC;
+	unsigned short auto_stat, irq_stat, trans_stat;
+	unsigned char busmon, busphase;
+	unsigned long flags;
+	int ret;
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+	struct Scsi_Host *host = data->Host;
+	spin_lock_irqsave(host->host_lock, flags);
+#else
+	spin_lock_irqsave(&io_request_lock, flags);
+#endif
+
+	/*
+	 * IRQ check, then enable IRQ mask
+	 */
+	irq_stat = nsp32_read2(base, IRQ_STATUS);
+	nsp32_dbg(NSP32_DEBUG_INTR, 
+		  "enter IRQ: %d, IRQstatus: 0x%x", irq, irq_stat);
+	/* is this interrupt comes from Ninja asic? */
+	if ((irq_stat & IRQSTATUS_ANY_IRQ) == 0) {
+		nsp32_msg(KERN_INFO, "spurious interrupt: irq other 0x%x", irq_stat);
+		goto out2;
+	}
+	nsp32_write2(base, IRQ_CONTROL, IRQ_CONTROL_ALL_IRQ_MASK);
+
+	busmon = nsp32_read1(base, SCSI_BUS_MONITOR);
+	busphase = busmon & BUSMON_PHASE_MASK;
+
+	trans_stat = nsp32_read2(base, TRANSFER_STATUS);
+	if ((irq_stat == 0xffff) && (trans_stat == 0xffff)) {
+		nsp32_msg(KERN_INFO, "card disconnect");
+		if (data->CurrentSC != NULL) {
+			nsp32_msg(KERN_INFO, "clean up current SCSI command");
+			SCpnt->result = DID_BAD_TARGET << 16;
+			nsp32_scsi_done(data, SCpnt);
+		}
+		goto out;
+	}
+
+	/* Timer IRQ */
+	if (irq_stat & IRQSTATUS_TIMER_IRQ) {
+		DEBUG(0, "timer stop\n");
+		nsp32_write2(base, TIMER_SET, TIMER_STOP);
+		goto out;
+	}
+
+	/* SCSI reset */
+	if (irq_stat & IRQSTATUS_SCSIRESET_IRQ) {
+		nsp32_msg(KERN_INFO, "detected someone do bus reset");
+		nsp32_do_bus_reset(data);
+		if (SCpnt != NULL) {
+			SCpnt->result = DID_RESET << 16;
+			nsp32_scsi_done(data, SCpnt);
+		}
+		goto out;
+	}
+	
+	if (SCpnt == NULL) {
+		nsp32_msg(KERN_WARNING, "SCpnt==NULL this can't be happen\n");
+		nsp32_msg(KERN_WARNING, "irq_stat=0x%x trans_stat=0x%x\n", irq_stat, trans_stat);
+		goto out;
+	}
+
+	/*
+	 * AutoSCSI Interrupt.
+	 * Note: This interrupt is occured when AutoSCSI is finished.  Then
+	 * check SCSIEXECUTEPHASE, and do appropriate action.  Each phases are
+	 * recorded when AutoSCSI sequencer has been processed.
+	 */
+	if(irq_stat & IRQSTATUS_AUTOSCSI_IRQ) {
+		/* getting SCSI executed phase */
+		auto_stat = nsp32_read2(base, SCSI_EXECUTE_PHASE);
+		nsp32_write2(base, SCSI_EXECUTE_PHASE, 0);
+
+		/* Selection Timeout, go busfree phase. */
+		if (auto_stat & SELECTION_TIMEOUT) {
+			nsp32_dbg(NSP32_DEBUG_INTR,
+				  "selection timeout occured");
+
+			SCpnt->result = DID_TIME_OUT << 16;
+			nsp32_scsi_done(data, SCpnt);
+			goto out;
+		}
+
+		if (auto_stat & MSGOUT_PHASE) {
+			/*
+			 * MsgOut phase was processed.
+			 * If MSG_IN_OCCUER is not set, then MsgOut phase is
+			 * completed. Thus, msgoutlen must reset.  Otherwise,
+			 * nothing to do here. If MSG_OUT_OCCUER is occured,
+			 * then we will encounter the condition and check.
+			 */
+			if (!(auto_stat & MSG_IN_OCCUER) &&
+			     (data->msgoutlen <= 3)) {
+				/*
+				 * !MSG_IN_OCCUER && msgoutlen <=3
+				 *   ---> AutoSCSI with MSGOUTreg is processed.
+				 */
+				data->msgoutlen = 0;
+			};
+
+			nsp32_dbg(NSP32_DEBUG_INTR, "MsgOut phase processed");
+		}
+
+		if ((auto_stat & DATA_IN_PHASE) &&
+		    (SCpnt->resid > 0) &&
+		    ((nsp32_read2(base, FIFO_REST_CNT) & FIFO_REST_MASK) != 0)) {
+			printk( "auto+fifo\n");
+			//nsp32_pio_read(SCpnt);
+		}
+
+		if (auto_stat & (DATA_IN_PHASE | DATA_OUT_PHASE)) {
+			/* DATA_IN_PHASE/DATA_OUT_PHASE was processed. */
+			nsp32_dbg(NSP32_DEBUG_INTR,
+				  "Data in/out phase processed");
+
+			/* read BMCNT, SGT pointer addr */
+			nsp32_dbg(NSP32_DEBUG_INTR, "BMCNT=0x%lx", 
+				    nsp32_read4(base, BM_CNT));
+			nsp32_dbg(NSP32_DEBUG_INTR, "addr=0x%lx", 
+				    nsp32_read4(base, SGT_ADR));
+			nsp32_dbg(NSP32_DEBUG_INTR, "SACK=0x%lx", 
+				    nsp32_read4(base, SACK_CNT));
+			nsp32_dbg(NSP32_DEBUG_INTR, "SSACK=0x%lx", 
+				    nsp32_read4(base, SAVED_SACK_CNT));
+			
+		}
+
+		/*
+		 * MsgIn Occur
+		 */
+		if (auto_stat & MSG_IN_OCCUER) {
+			nsp32_msgin_occur(data, irq_stat, auto_stat);
+		}
+
+		/*
+		 * MsgOut Occur
+		 */
+		if (auto_stat & MSG_OUT_OCCUER) {
+			nsp32_msgout_occur(data);
+		}
+
+		/*
+		 * Bus Free Occur
+		 */
+		if (auto_stat & BUS_FREE_OCCUER) {
+			ret = nsp32_busfree_occur(data, auto_stat);
+			if (ret == TRUE) {
+				goto out;
+			}
+		}
+
+		if (auto_stat & STATUS_PHASE) {
+			/*
+			 * Read CSB and substitute CSB for SCpnt->result
+			 * to save status phase stutas byte.
+			 * scsi error handler checks host_byte (DID_*:
+			 * low level driver to indicate status), then checks 
+			 * status_byte (SCSI status byte).
+			 */
+			SCpnt->result =	(int)nsp32_read1(base, SCSI_CSB_IN);
+		}
+
+		if (auto_stat & ILLEGAL_PHASE) {
+			/* Illegal phase is detected. SACK is not back. */
+			nsp32_msg(KERN_WARNING, 
+				  "AUTO SCSI ILLEGAL PHASE OCCUR!!!!");
+
+			/* TODO: currently we don't have any action... bus reset? */
+
+			/*
+			 * To send back SACK, assert, wait, and negate.
+			 */
+			nsp32_sack_assert(data);
+			nsp32_wait_req(data, NEGATE);
+			nsp32_sack_negate(data);
+
+		}
+
+		if (auto_stat & COMMAND_PHASE) {
+			/* nothing to do */
+			nsp32_dbg(NSP32_DEBUG_INTR, "Command phase processed");
+		}
+
+		if (auto_stat & AUTOSCSI_BUSY) {
+			/* AutoSCSI is running */
+		}
+
+		show_autophase(auto_stat);
+	}
+
+	/* FIFO_SHLD_IRQ */
+	if (irq_stat & IRQSTATUS_FIFO_SHLD_IRQ) {
+		nsp32_dbg(NSP32_DEBUG_INTR, "FIFO IRQ");
+
+		switch(busphase) {
+		case BUSPHASE_DATA_OUT:
+			printk( "write\n");
+
+			//nsp32_pio_write(SCpnt);
+
+			break;
+
+		case BUSPHASE_DATA_IN:
+			printk( "read\n");
+
+			//nsp32_pio_read(SCpnt);
+
+			break;
+
+		case BUSPHASE_STATUS:
+			//DEBUG(0, "fifo/status\n");
+
+			SCpnt->SCp.Status = nsp32_read1(base, SCSI_CSB_IN);
+
+			break;
+		default:
+			printk("fifo/other phase?\n");
+			printk("irq_stat=0x%x trans_stat=0x%x\n", irq_stat, trans_stat);
+			show_busphase(busphase);
+			break;
+		}
+
+		goto out;
+	}
+
+	/* Phase Change IRQ */
+	if (irq_stat & IRQSTATUS_PHASE_CHANGE_IRQ) {
+		nsp32_dbg(NSP32_DEBUG_INTR, "phase change IRQ");
+
+		switch(busphase) {
+		case BUSPHASE_MESSAGE_IN:
+			nsp32_dbg(NSP32_DEBUG_INTR, "phase chg/msg in");
+			nsp32_msgin_occur(data, irq_stat, 0);
+			break;
+		default:
+			nsp32_msg(KERN_WARNING, "phase chg/other phase?");
+			nsp32_msg(KERN_WARNING, "irq_stat=0x%x trans_stat=0x%x\n",
+				  irq_stat, trans_stat);
+			show_busphase(busphase);
+			break;
+		}
+		goto out;
+	}
+
+	/* PCI_IRQ */
+	if (irq_stat & IRQSTATUS_PCI_IRQ) {
+		nsp32_dbg(NSP32_DEBUG_INTR, "PCI IRQ occured");
+		/* Do nothing */
+	}
+
+	/* BMCNTERR_IRQ */
+	if (irq_stat & IRQSTATUS_BMCNTERR_IRQ) {
+		nsp32_msg(KERN_ERR, "Received unexpected BMCNTERR IRQ! ");
+		/*
+		 * TODO: To be implemented improving bus master
+		 * transfer reliablity when BMCNTERR is occured in
+		 * AutoSCSI phase described in specification.
+		 */
+	}
+
+#if 0
+	printk("irq_stat=0x%x trans_stat=0x%x\n", irq_stat, trans_stat);
+	show_busphase(busphase);
+#endif
+
+ out:
+	/* disable IRQ mask */
+	nsp32_write2(base, IRQ_CONTROL, 0);
+
+ out2:
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	spin_unlock_irqrestore(&io_request_lock, flags);
+#else
+	spin_unlock_irqrestore(host->host_lock, flags);
+#endif
+
+	nsp32_dbg(NSP32_DEBUG_INTR, "exit");
+
+	return;
+}
+
+#undef SPRINTF
+#define SPRINTF(args...) \
+        do { if(pos < buffer + length) pos += sprintf(pos, ## args); } while(0)
+static int nsp32_proc_info(char  *buffer,
+			   char **start,
+			   off_t  offset,
+			   int    length,
+			   int    hostno,
+			   int    inout)
+{
+	char *pos = buffer;
+	int thislength;
+	unsigned long flags;
+	nsp32_hw_data *data;
+	struct Scsi_Host *host = NULL;
+	unsigned int base;
+	unsigned char mode_reg;
+
+	/* Write is not supported, just return. */
+	if (inout == TRUE) {
+		return -EINVAL;
+	}
+
+	/* search this HBA host */
+	for (host=scsi_hostlist; host; host=host->next) {
+		if (host->host_no == hostno) {
+			break;
+		}
+	}
+	if (host == NULL) {
+		return -ESRCH;
+	}
+	data = (nsp32_hw_data *)host->hostdata;
+	base = host->io_port;
+
+	SPRINTF("NinjaSCSI-32 status\n\n");
+	SPRINTF("Driver version:        %s\n",		nsp32_release_version);
+	SPRINTF("SCSI host No.:         %d\n",		hostno);
+	SPRINTF("IRQ:                   %d\n",		host->irq);
+	SPRINTF("IO:                    0x%lx-0x%lx\n", host->io_port, host->io_port + host->n_io_port - 1);
+	SPRINTF("MMIO(virtual address): 0x%lx\n",	host->base);
+	SPRINTF("sg_tablesize:          %d\n",		host->sg_tablesize);
+	SPRINTF("Chip revision:         %d\n",		(nsp32_read2(base, INDEX_REG) >> 8) - 0x4f);
+
+	mode_reg = nsp32_index_read1(base, CHIP_MODE);
+
+#ifdef CONFIG_PM
+	//SPRINTF("Power Management:      %s\n",          (mode_reg & OPTF) ? "yes" : "no");
+#endif
+	SPRINTF("OEM:                   %s\n",          nsp32_model[mode_reg & (OEM0|OEM1)]);
+
+	spin_lock_irqsave(&(data->Lock), flags);
+	SPRINTF("CurrentSC:             0x%p\n\n",      data->CurrentSC);
+	spin_unlock_irqrestore(&(data->Lock), flags);
+
+	thislength = pos - (buffer + offset);
+
+	if(thislength < 0) {
+		*start = 0;
+                return 0;
+        }
+
+
+	thislength = MIN(thislength, length);
+	*start = buffer + offset;
+
+	return thislength;
+}
+#undef SPRINTF
+
+/*
+ * Note: n_io_port is defined as 0x7f because I/O register port is
+ *	 assigned as:
+ *	0x800-0x8ff: memory mapped I/O port
+ *	0x900-0xbff: (map same 0x800-0x8ff I/O port image repeatedly)
+ *	0xc00-0xfff: CardBus status registers
+ */
+static int nsp32_detect(Scsi_Host_Template *sht)
+{
+	struct Scsi_Host *host;	/* registered host structure */
+	int ret;
+	nsp32_hw_data *data;
+	int i, j;
+
+	nsp32_dbg(NSP32_DEBUG_REGISTER, "enter");
+
+	/*
+	 * register this HBA as SCSI device
+	 */
+	host = scsi_register(sht, sizeof(nsp32_hw_data));
+	if (host == NULL) {
+		nsp32_msg (KERN_ERR, "failed to scsi register");
+		goto err;
+	}
+
+	/*
+	 * set nsp32_hw_data
+	 */
+	data = (nsp32_hw_data *)host->hostdata;
+	memset(data, 0, sizeof(nsp32_hw_data));
+
+	data->IrqNumber   = nsp32_data_base.IrqNumber;
+	data->BaseAddress = nsp32_data_base.BaseAddress;
+	data->NumAddress  = nsp32_data_base.NumAddress; 
+	data->MmioAddress = nsp32_data_base.MmioAddress;
+	data->Pci         = nsp32_data_base.Pci;
+	data->pci_devid   = nsp32_data_base.pci_devid;
+
+	host->irq         = data->IrqNumber;
+	host->io_port	  = data->BaseAddress;
+	host->unique_id	  = data->BaseAddress;
+	host->n_io_port	  = data->NumAddress;
+	host->base        = data->MmioAddress;
+	scsi_set_pci_device(host, data->Pci);
+
+	data->Host        = host;
+	spin_lock_init(&(data->Lock));
+
+	data->curlunt     = NULL;
+	data->curtarget   = NULL;
+
+	/*
+	 * Bus master transfer mode is supported currently.
+	 */
+	data->trans_method	= NSP32_TRANSFER_BUSMASTER;
+
+	/*
+	 * Set clock div, CLOCK_4 (HBA has external clock, and
+	 * dividing * 100ns/4).
+	 * Currently CLOCK_4 has only tested, not for CLOCK_2/PCICLK yet.
+	 */
+	data->clock = CLOCK_4;
+
+	/*
+	 * Select appropriate nsp32_sync_table and set I_CLOCKDIV.
+	 */
+	switch (data->clock) {
+	case CLOCK_4:
+		/* If data->clock is CLOCK_4, then select 40M sync table. */
+		data->synct = nsp32_sync_table_40M;
+		data->syncnum = nsp32_table_40M_num;
+		break;
+	case CLOCK_2:
+		/* If data->clock is CLOCK_2, then select 20M sync table. */
+		data->synct = nsp32_sync_table_20M;
+		data->syncnum = nsp32_table_20M_num;
+		break;
+	case PCICLK:
+		/* If data->clock is PCICLK, then select pci sync table. */
+		data->synct = nsp32_sync_table_pci;
+		data->syncnum = nsp32_table_pci_num;
+		break;
+	default:
+		nsp32_msg(KERN_WARNING,
+			  "Invalid clock div is selected, set CLOCK_4.");
+		/* Use default value CLOCK_4 */
+		data->clock = CLOCK_4;
+		data->synct = nsp32_sync_table_40M;
+		data->syncnum = nsp32_table_40M_num;
+	}
+
+	/*
+	 * setup nsp32_lunt
+	 */
+	data->lunt_list = (struct nsp32_lunt *)
+		kmalloc(sizeof(struct nsp32_lunt) * MAX_TARGET * MAX_LUN,
+			GFP_KERNEL);
+	if (data->lunt_list == NULL) {
+		nsp32_msg(KERN_ERR, "cannot allocate LUN memory");
+		goto scsi_unregister;
+	}
+	nsp32_dbg(NSP32_DEBUG_REGISTER, "0x%x 0x%x",
+		  data->lunt_list, sizeof(struct nsp32_lunt)*MAX_TARGET*MAX_LUN);
+
+	/*
+	 * setup DMA 
+	 */
+	if (pci_set_dma_mask(data->Pci, 0xffffffffUL)) {
+		nsp32_msg (KERN_ERR, "failed to set PCI DMA mask");
+		goto kfree_lunt;
+	}
+
+	/*
+	 * allocate autoparam DMA resource.
+	 */
+	data->autoparam = pci_alloc_consistent(data->Pci, AUTOPARAM_SIZE, &data->apaddr);
+	if (data->autoparam == NULL) {
+		nsp32_msg(KERN_ERR, "failed to allocate DMA memory");
+		goto kfree_lunt;
+	}
+
+	/*
+	 * allocate scatter-gather DMA resource.
+	 */
+	data->sg_list = pci_alloc_consistent(data->Pci, 
+			(sizeof(struct nsp32_sgtable) * NSP_SG_SIZE * MAX_TARGET * MAX_LUN),
+			 &data->sgaddr);
+	if (data->sg_list == NULL) {
+		nsp32_msg(KERN_ERR, "failed to allocate DMA memory");
+		goto free_autoparam;
+	}
+
+	for (i=0; i<MAX_TARGET; i++) {
+		for (j=0; j<MAX_LUN; j++) {
+			data->lunt[i][j] = data->lunt_list + (i * MAX_LUN + j);
+		}
+	}
+
+	for (i=0; i<MAX_TARGET; i++) {
+		for (j=0; j<MAX_LUN; j++) {
+			struct nsp32_lunt *lp = data->lunt[i][j];
+			lp->sglun = (struct nsp32_sglun *)
+				(data->sg_list + (i * MAX_LUN + j));
+			lp->sglun_paddr = data->sgaddr +
+				(long)((i * MAX_LUN + j) 
+				       * sizeof(struct nsp32_sglun));
+			lp->SCpnt = NULL;
+			lp->save_datp = 0;
+			lp->msgin03 = FALSE;
+			lp->sg_num = 0;
+			lp->cur_entry = 0;
+		}
+	}
+
+	/*
+	 * setup target
+	 */
+	for (i=0; i<MAX_TARGET; i++) {
+		struct nsp32_target *target = &data->target[i];
+
+		target->limit_entry  = 0;
+		target->sync_flag    = 0;
+		nsp32_set_async(data, target);
+	}
+
+	/*
+	 * EEPROM check
+	 */
+	ret = nsp32_getprom_param(data);
+	if (ret == FALSE) {
+		data->resettime = 3;	/* default 3 */
+	}
+
+	/*
+	 * setup HBA
+	 */
+	nsp32hw_init(host);
+
+	snprintf(data->info_str, sizeof(data->info_str),
+		 "NinjaSCSI-32Bi/UDE: irq %d, io 0x%lx+0x%x",
+		 host->irq, host->io_port, host->n_io_port);
+
+	sht->name = data->info_str;
+
+	/*
+	 * SCSI bus reset
+	 *
+	 * Note: It's important to reset SCSI bus in initialization phase.
+	 *     NinjaSCSI-32Bi/UDE HBA EEPROM seems to exchange SDTR when system is
+	 *     coming up, so SCSI devices connected to HBA is set as
+	 *     un-asynchronous mode.  It brings the merit that this HBA is
+	 *     ready to start synchronous transfer without any preparation,
+	 *     but we are difficult to control transfer speed.  In addition,
+	 *     it prevents device transfer speed from effecting EEPROM start-up
+	 *     SDTR.  NinjaSCSI-32Bi/UDE has the feature if EEPROM is set as Auto
+	 *     Mode, then FAST-10M is selected when SCSI devices are connected
+	 *     same or more than 4 devices.  It should be avoided depending on
+	 *     this specification Thus, resetting the SCSI bus restores all
+	 *     connected SCSI devices to asynchronous mode, then this driver
+	 *     put SDTR safely later, and we can control all SCSI device
+	 *     transfer mode.
+	 */
+	nsp32_do_bus_reset(data);
+
+	ret = request_irq(host->irq, do_nsp32_isr, SA_SHIRQ, "nsp32", data);
+	if (ret < 0) {
+		nsp32_msg(KERN_ERR, "Unable to allocate IRQ for NSP32 "
+			  "SCSI PCI controller. Interrupt: %d\n", host->irq);
+		goto free_sg_list;
+	}
+
+        /*
+         * PCI IO register
+         */
+	if(!request_region(host->io_port, host->n_io_port, "nsp32")) {
+		nsp32_msg(KERN_ERR, 
+			  "I/O region 0x%lx+0x%lx is already used",
+			  data->BaseAddress, data->length);
+		goto free_irq;
+        }
+
+	return 1;
+
+ free_irq:
+	free_irq(host->irq, data);
+
+ free_autoparam:
+	pci_free_consistent(data->Pci, AUTOPARAM_SIZE, data->autoparam, data->apaddr);
+	
+ free_sg_list:
+	pci_free_consistent(data->Pci,
+		(sizeof(struct nsp32_sgtable) * NSP_SG_SIZE * MAX_TARGET * MAX_LUN),
+		data->sg_list, data->sgaddr);
+	
+ kfree_lunt:
+	kfree(data->lunt_list);
+
+ scsi_unregister:
+	scsi_unregister(host);
+
+ err:
+	return 0;
+}
+
+static int nsp32_release(struct Scsi_Host *shpnt)
+{
+	nsp32_hw_data *data = (nsp32_hw_data *)shpnt->hostdata;
+
+	if (data->lunt_list) {
+		kfree(data->lunt_list);
+	}
+
+	if (data->autoparam) {
+		pci_free_consistent(data->Pci, AUTOPARAM_SIZE,
+					data->autoparam, data->apaddr);
+	}
+
+	if (data->sg_list) {
+		pci_free_consistent(data->Pci, 
+			(sizeof(struct nsp32_sgtable) * NSP_SG_SIZE * MAX_TARGET * MAX_LUN),
+			data->sg_list, data->sgaddr);
+	}
+
+	DEBUG(0, "free irq\n");
+	if (shpnt->irq) {
+		free_irq(shpnt->irq, data);
+	}
+
+	DEBUG(0, "free io\n");
+	if (shpnt->io_port && shpnt->n_io_port) {
+		release_region(shpnt->io_port, shpnt->n_io_port);
+	}
+
+	if (data->MmioAddress != 0) {
+		iounmap((void *)(data->MmioAddress));
+	}
+
+	return 0;
+}
+
+static const char *nsp32_info(struct Scsi_Host *shpnt)
+{
+	nsp32_hw_data *data = (nsp32_hw_data *)shpnt->hostdata;
+
+	return data->info_str;
+}
+
+
+/*
+ * error handler
+ */
+static int nsp32_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
+{
+	nsp32_dbg(NSP32_DEBUG_BUSRESET, "SCpnt=0x%p why=%d\n", SCpnt, reset_flags);
+
+	nsp32_eh_bus_reset(SCpnt);
+
+	return SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET;
+}
+
+static int nsp32_eh_abort(Scsi_Cmnd *SCpnt)
+{
+	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->host->hostdata;
+	unsigned int base = data->BaseAddress;
+
+	nsp32_msg(KERN_WARNING, "abort");
+
+	if (data->curlunt->SCpnt == NULL) {
+		return (FAILED);
+	}
+
+	if (data->curtarget->sync_flag & (SDTR_INITIATOR | SDTR_TARGET)) {
+		/* reset SDTR negotiation */
+		data->curtarget->sync_flag = 0;
+	}
+
+	nsp32_write2(base, TRANSFER_CONTROL, 0);
+	nsp32_write2(base, BM_CNT, 0);
+
+	return (FAILED);
+}
+
+static int nsp32_eh_bus_reset(Scsi_Cmnd *SCpnt)
+{
+	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->host->hostdata;
+	unsigned int base = data->BaseAddress;
+
+	nsp32_msg(KERN_INFO, "Bus Reset");	
+	nsp32_dbg(NSP32_DEBUG_BUSRESET, "SCpnt=0x%x", SCpnt);
+
+	nsp32_write2(base, IRQ_CONTROL, IRQ_CONTROL_ALL_IRQ_MASK);
+	nsp32_do_bus_reset(data);
+	nsp32_write2(base, IRQ_CONTROL, 0);
+
+	return SUCCESS;	/* SCSI bus reset is succeeded at any time. */
+}
+
+static void nsp32_do_bus_reset(nsp32_hw_data *data)
+{
+	unsigned int base = data->BaseAddress;
+	unsigned short intrdat;
+	int i;
+
+	/*
+	 * stop all transfer
+	 * clear TRANSFERCONTROL_BM_START
+	 * clear counter
+	 */
+	nsp32_write2(base, TRANSFER_CONTROL, 0);
+	nsp32_write4(base, BM_CNT,           0);
+	nsp32_write4(base, CLR_COUNTER, CLRCOUNTER_ALLMASK);
+
+	/*
+	 * fall back to asynchronous transfer mode
+	 * initialize SDTR negotiation flag
+	 */
+	for (i=0; i<MAX_TARGET; i++) {
+		struct nsp32_target *target = &data->target[i];
+
+		target->sync_flag = 0;
+		nsp32_set_async(data, target);
+	}
+
+	/*
+	 * reset SCSI bus
+	 */
+	nsp32_write1(base, SCSI_BUS_CONTROL, BUSCTL_RST);
+	udelay(RESET_HOLD_TIME);
+	nsp32_write1(base, SCSI_BUS_CONTROL, 0);
+	for(i = 0; i < 5; i++) {
+		intrdat = nsp32_read2(base, IRQ_STATUS); /* dummy read */
+		nsp32_dbg(NSP32_DEBUG_BUSRESET, "irq:1: 0x%x", intrdat);
+        }
+
+	data->CurrentSC = NULL;
+}
+
+static int nsp32_eh_host_reset(Scsi_Cmnd *SCpnt)
+{
+	struct Scsi_Host *host = SCpnt->host;
+	nsp32_hw_data *data = (nsp32_hw_data *)host->hostdata;
+	unsigned int base = data->BaseAddress;
+
+	nsp32_msg(KERN_INFO, "Host Reset");	
+	nsp32_dbg(NSP32_DEBUG_BUSRESET, "SCpnt=0x%x", SCpnt);
+
+	nsp32hw_init(host);
+	nsp32_write2(base, IRQ_CONTROL, IRQ_CONTROL_ALL_IRQ_MASK);
+	nsp32_do_bus_reset(data);
+	nsp32_write2(base, IRQ_CONTROL, 0);
+
+	return SUCCESS;	/* Host reset is succeeded at any time. */
+}
+
+/*
+ * PCI/Cardbus probe/remove routine
+ */
+static int __devinit nsp32_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	int ret;
+	nsp32_hw_data *data = &nsp32_data_base;
+
+	nsp32_dbg(NSP32_DEBUG_REGISTER, "enter");
+
+        ret = pci_enable_device(pdev);
+	if (ret) {
+		nsp32_msg(KERN_ERR, "failed to enable pci device");
+		return ret;
+	}
+
+	data->Pci = pdev;
+	data->pci_devid = id;
+	data->IrqNumber = pdev->irq;
+	data->BaseAddress = pci_resource_start(pdev, 0);
+	data->NumAddress = pci_resource_len(pdev, 0);
+	data->MmioAddress = (unsigned long)ioremap_nocache(
+		pci_resource_start(pdev, 1), pci_resource_len(pdev, 1));
+
+	pci_set_master(pdev);
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2))
+	scsi_register_host(&driver_template);
+#else
+	scsi_register_module(MODULE_SCSI_HA, &driver_template);
+#endif
+
+	nsp32_msg(KERN_INFO, "nsp32 irq: %i mmio: 0x%lx slot: %s model: %s",
+		  pdev->irq, data->MmioAddress, pdev->slot_name,
+		  nsp32_model[id->driver_data]);
+
+	nsp32_dbg(NSP32_DEBUG_REGISTER, "exit");
+
+	return 0;
+}
+
+static void __devexit nsp32_remove(struct pci_dev *pdev)
+{
+	nsp32_dbg(NSP32_DEBUG_REGISTER, "enter");
+	
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2))
+	scsi_unregister_host(&driver_template);
+#else
+	scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
+#endif
+}
+
+static struct pci_device_id nsp32_pci_table[] __devinitdata = {
+	{
+		vendor:      PCI_VENDOR_ID_IODATA,
+		device:      PCI_DEVICE_ID_NINJASCSI_32BI_CBSC_II,
+		subvendor:   PCI_ANY_ID,
+		subdevice:   PCI_ANY_ID,
+		driver_data: MODEL_IODATA,
+	},
+	{
+		vendor:      PCI_VENDOR_ID_WORKBIT,
+		device:      PCI_DEVICE_ID_NINJASCSI_32BI_KME,
+		subvendor:   PCI_ANY_ID,
+		subdevice:   PCI_ANY_ID,
+		driver_data: MODEL_KME,
+	},
+	{
+		vendor:      PCI_VENDOR_ID_WORKBIT,
+		device:      PCI_DEVICE_ID_NINJASCSI_32BI_WBT,
+		subvendor:   PCI_ANY_ID,
+		subdevice:   PCI_ANY_ID,
+		driver_data: MODEL_WORKBIT,
+	},
+	{
+		vendor:      PCI_VENDOR_ID_WORKBIT,
+		device:      PCI_DEVICE_ID_WORKBIT_STANDARD,
+		subvendor:   PCI_ANY_ID,
+		subdevice:   PCI_ANY_ID,
+		driver_data: MODEL_PCI_WORKBIT,
+	},
+	{
+		vendor:      PCI_VENDOR_ID_WORKBIT,
+		device:      PCI_DEVICE_ID_NINJASCSI_32BI_LOGITEC,
+		subvendor:   PCI_ANY_ID,
+		subdevice:   PCI_ANY_ID,
+		driver_data: MODEL_EXT_ROM,
+	},
+	{
+		vendor:      PCI_VENDOR_ID_WORKBIT,
+		device:      PCI_DEVICE_ID_NINJASCSI_32BIB_LOGITEC,
+		subvendor:   PCI_ANY_ID,
+		subdevice:   PCI_ANY_ID,
+		driver_data: MODEL_PCI_LOGITEC,
+	},
+	{
+		vendor:      PCI_VENDOR_ID_WORKBIT,
+		device:      PCI_DEVICE_ID_NINJASCSI_32UDE_MELCO,
+		subvendor:   PCI_ANY_ID,
+		subdevice:   PCI_ANY_ID,
+		driver_data: MODEL_PCI_MELCO,
+	},
+	{0,0,},
+};
+MODULE_DEVICE_TABLE(pci, nsp32_pci_table);
+
+static struct pci_driver nsp32_driver = {
+	.name =		"nsp32",
+	.id_table =	nsp32_pci_table,
+	.probe =	nsp32_probe,
+	.remove =	nsp32_remove,
+#ifdef CONFIG_PM
+/*	.suspend =	nsp32_suspend,*/
+/*	.resume =	nsp32_resume,*/
+#endif
+};
+
+static int __init init_nsp32(void) {
+	return pci_module_init(&nsp32_driver);
+}
+
+static void __exit exit_nsp32(void) {
+	pci_unregister_driver(&nsp32_driver);
+}
+
+module_init(init_nsp32);
+module_exit(exit_nsp32);
+
+
+/*
+ * Reset parameters and call scsi_done for data->curlunt.
+ * Be careful setting SCpnt->result = DID_* before calling this function.
+ */
+static void nsp32_scsi_done(nsp32_hw_data *data, Scsi_Cmnd *SCpnt)
+{
+	unsigned int base = data->BaseAddress;
+
+	/*
+	 * unmap pci
+	 */
+	if (SCpnt->request_bufflen == 0) {
+		goto skip;
+	}
+
+	if (SCpnt->use_sg) {
+		pci_unmap_sg(data->Pci,
+			(struct scatterlist *)SCpnt->buffer,
+			SCpnt->use_sg,
+			scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+	} else {
+		pci_unmap_single(data->Pci,
+			(u32)SCpnt->SCp.have_data_in,
+			SCpnt->request_bufflen,
+			scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+	}
+
+ skip:
+	/*
+	 * clear TRANSFERCONTROL_BM_START
+	 */
+	nsp32_write2(base, TRANSFER_CONTROL, 0);
+	nsp32_write4(base, BM_CNT, 0);
+
+	/*
+	 * call scsi_done
+	 */
+	(*SCpnt->scsi_done)(SCpnt);
+
+	/*
+	 * reset parameters
+	 */
+	data->curlunt->SCpnt = NULL;
+	data->curlunt = NULL;
+	data->curtarget = NULL;
+	data->CurrentSC = NULL;
+}
+
+
+/*
+ * Bus Free Occur
+ *
+ * Current Phase is BUSFREE. AutoSCSI is automatically execute BUSFREE phase
+ * with ACK reply when below condition is matched:
+ *	MsgIn 00: Command Complete.
+ *	MsgIn 02: Save Data Pointer.
+ *	MsgIn 04: Diconnect.
+ * In other case, unexpected BUSFREE is detected.
+ */
+static int nsp32_busfree_occur(nsp32_hw_data *data, unsigned short execph)
+{
+	Scsi_Cmnd *SCpnt = data->curlunt->SCpnt;
+	unsigned int base = data->BaseAddress;
+
+	nsp32_dbg(NSP32_DEBUG_BUSFREE, "enter");
+
+	nsp32_write4(base, BM_CNT, 0);
+	nsp32_write2(base, TRANSFER_CONTROL, 0);
+
+	/*
+	 * MsgIn 02: Save Data Pointer
+	 *
+	 * VALID:
+	 *   Save Data Pointer is received. Adjust pointer.
+	 *   
+	 * NO-VALID:
+	 *   SCSI-3 says if Save Data Pointer is not received, then we restart
+	 *   processing and we can't adjust any SCSI data pointer in next data
+	 *   phase.
+	 */
+	if (execph & MSGIN_02_VALID) {
+		nsp32_dbg(NSP32_DEBUG_BUSFREE, "MsgIn02_Valid");
+
+		/*
+		 * Check sack_cnt/saved_sack_cnt, then adjust sg table if
+		 * needed.
+		 */
+		if (!(execph & MSGIN_00_VALID) && 
+		    ((execph & DATA_IN_PHASE) || (execph & DATA_OUT_PHASE))) {
+			unsigned int sacklen, s_sacklen;
+
+			/*
+			 * Read SACK count and SAVEDSACK count, then compare.
+			 */
+			sacklen   = nsp32_read4(base, SACK_CNT);
+			s_sacklen = nsp32_read4(base, SAVED_SACK_CNT);
+
+			/*
+			 * If SAVEDSACKCNT == 0, it means SavedDataPointer is
+			 * come after data transfering.
+			 */
+			if (s_sacklen > 0) {
+				/*
+				 * Comparing between sack and savedsack to
+				 * check the condition of AutoMsgIn03.
+				 *
+				 * If they are same, set msgin03 == TRUE,
+				 * COMMANDCONTROL_AUTO_MSGIN_03 is enabled at
+				 * reselection.  On the other hand, if they
+				 * aren't same, set msgin03 == FALSE, and
+				 * COMMANDCONTROL_AUTO_MSGIN_03 is disabled at
+				 * reselection.
+				 */
+				if (sacklen != s_sacklen) {
+					data->curlunt->msgin03 = FALSE;
+				} else {
+					data->curlunt->msgin03 = TRUE;
+				}
+
+				nsp32_adjust_busfree(data, s_sacklen);
+			}
+		}
+
+		/* This value has not substitude with valid value yet... */
+		//data->curlunt->save_datp = data->cur_datp;
+	} else {
+		/*
+		 * no processing.
+		 */
+	}
+	
+	if (execph & MSGIN_03_VALID) {
+		/* MsgIn03 was valid to be processed. No need processing. */
+	}
+
+	/*
+	 * target SDTR check
+	 */
+	if (data->curtarget->sync_flag & SDTR_INITIATOR) {
+		/*
+		 * SDTR negotiation pulled by the initiator has not
+		 * finished yet. Fall back to ASYNC mode.
+		 */
+		nsp32_set_async(data, data->curtarget);
+		data->curtarget->sync_flag &= ~SDTR_INITIATOR;
+		data->curtarget->sync_flag |= SDTR_DONE;
+	} else if (data->curtarget->sync_flag & SDTR_TARGET) {
+		/*
+		 * SDTR negotiation pulled by the target has been
+		 * negotiating.
+		 */
+		if (execph & (MSGIN_00_VALID | MSGIN_04_VALID)) {
+			/* 
+			 * If valid message is received, then
+			 * negotiation is succeeded.
+			 */
+		} else {
+			/*
+			 * On the contrary, if unexpected bus free is
+			 * occured, then negotiation is failed. Fall
+			 * back to ASYNC mode.
+			 */
+			nsp32_set_async(data, data->curtarget);
+		}
+		data->curtarget->sync_flag &= ~SDTR_TARGET;
+		data->curtarget->sync_flag |= SDTR_DONE;
+	}
+	
+	/*
+	 * It is always ensured by SCSI standard that initiator
+	 * switches into Bus Free Phase after
+	 * receiving message 00 (Command Complete), 04 (Disconnect).
+	 * It's the reason that processing here is valid.
+	 */
+	if (execph & MSGIN_00_VALID) {
+		/* MsgIn 00: Command Complete */
+		nsp32_dbg(NSP32_DEBUG_BUSFREE, "command complete");
+
+		SCpnt->SCp.Status  = nsp32_read1(base, SCSI_CSB_IN);
+		SCpnt->SCp.Message = 0;
+		nsp32_dbg(NSP32_DEBUG_BUSFREE, 
+			  "normal end stat=0x%x resid=0x%x\n",
+			  SCpnt->SCp.Status, SCpnt->resid);
+		SCpnt->result = 
+			(DID_OK << 16) | (SCpnt->SCp.Message << 8) | (SCpnt->SCp.Status << 0);
+		nsp32_scsi_done(data, SCpnt);
+		/* All operation is done */
+		return (TRUE);
+	} else if (execph & MSGIN_04_VALID) {
+		/* MsgIn 04: Disconnect */
+		SCpnt->SCp.Status  = nsp32_read1(base, SCSI_CSB_IN);
+		SCpnt->SCp.Message = 4;
+		
+		nsp32_dbg(NSP32_DEBUG_BUSFREE, "disconnect");
+		return (TRUE);
+	} else {
+		/* Unexpected bus free */
+		nsp32_msg(KERN_WARNING, "unexpected bus free occured");
+
+		/* DID_ERROR? */
+		//SCpnt->result   = (DID_OK << 16) | (SCpnt->SCp.Message << 8) | (SCpnt->SCp.Status << 0);
+		SCpnt->result = DID_ERROR << 16;
+		nsp32_scsi_done(data, SCpnt);
+		return (TRUE);
+	}
+	return (FALSE);
+}
+
+
+/*
+ * nsp32_adjust_busfree - adjusting SG table
+ *
+ * Note: This driver adjust the SG table using SCSI ACK
+ *       counter instead of BMCNT counter!
+ */
+static void nsp32_adjust_busfree(nsp32_hw_data *data, unsigned int s_sacklen)
+{
+	int old_entry = data->cur_entry;
+	int new_entry;
+	struct nsp32_sgtable *sgt = data->curlunt->sglun->sgt;
+	unsigned int restlen, sentlen;
+	int sg_num = data->curlunt->sg_num;
+
+	/* adjust saved SACK count with 4 byte start address boundary */
+	s_sacklen -= sgt[old_entry].addr & 3;
+
+	/*
+	 * calculate new_entry from sack count and each sgt[].len 
+	 * calculate the byte which is intent to send
+	 */
+	sentlen = 0;
+	for (new_entry = old_entry; new_entry < sg_num; new_entry++) {
+		sentlen += (sgt[new_entry].len & ~NSP32_SG_END_SGT);
+		if (sentlen > s_sacklen) {
+			break;
+		}
+	}
+
+	/* all sgt is processed */
+	if (new_entry == sg_num) {
+		goto last;
+	}
+
+	if (sentlen == s_sacklen) {
+		/* XXX: confirm it's ok or not */
+		/* In this case, it's ok because we are at 
+		   the head element of the sg. restlen is correctly calculated. */
+	}
+
+	/* calculate the rest length for transfering */
+	restlen = sentlen - s_sacklen;
+	
+	/* update adjusting current SG table entry */
+	sgt[new_entry].addr += (sgt[new_entry].len - restlen);
+	sgt[new_entry].len = restlen;
+
+	/* set cur_entry with new_entry */
+	data->cur_entry = new_entry;
+	
+	return;
+
+ last:
+	/* update hostdata and lun */
+
+	return;
+}
+
+
+/*
+ * It's called MsgOut phase occur.
+ * NinjaSCSI-32Bi/UDE automatically processes up to 3 messages in
+ * message out phase. It, however, has more than 3 messages,
+ * HBA creates the interrupt and we have to process by hand.
+ */
+static void nsp32_msgout_occur(nsp32_hw_data *data)
+{
+	unsigned int base = data->BaseAddress;
+	//unsigned short command;
+	long new_sgtp;
+	int i;
+	
+	nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR,
+		  "enter: msgoutlen: 0x%x", data->msgoutlen);
+
+	/*
+	 * If MsgOut phase is occured without having any
+	 * message, then No_Operation is sent (SCSI-2).
+	 */
+	if (data->msgoutlen == 0) {
+		nsp32_build_nop(data);
+	}
+
+	/*
+	 * Set SGTP ADDR current entry for restarting AUTOSCSI, 
+	 * because SGTP is incremented next point.
+	 * There is few statement in the specification...
+	 */
+ 	new_sgtp = data->curlunt->sglun_paddr
+		+ data->curlunt->cur_entry * sizeof(struct nsp32_sgtable);
+
+	/*
+	 * send messages
+	 */
+	for (i=0; i<data->msgoutlen; i++) {
+		nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR,
+			  "%d : 0x%x", i, data->msgoutbuf[i]);
+
+		/*
+		 * Check REQ is asserted.
+		 */
+		nsp32_wait_req(data, ASSERT);
+
+		if (i == (data->msgoutlen - 1)) {
+			/*
+			 * If the last message, set the AutoSCSI restart
+			 * before send back the ack message. AutoSCSI
+			 * restart automatically negate ATN signal.
+			 */
+			//command = (AUTO_MSGIN_00_OR_04 | AUTO_MSGIN_02);
+			//nsp32_restart_autoscsi(data, command);
+			nsp32_write2(base, COMMAND_CONTROL,
+					 (CLEAR_CDB_FIFO_POINTER |
+					  AUTO_COMMAND_PHASE |
+					  AUTOSCSI_RESTART |
+					  AUTO_MSGIN_00_OR_04 |
+					  AUTO_MSGIN_02 ));
+		}
+		/*
+		 * Write data with SACK, then wait sack is
+		 * automatically negated.
+		 */
+		nsp32_write1(base, SCSI_DATA_WITH_ACK, data->msgoutbuf[i]);
+		nsp32_wait_sack(data, NEGATE);
+
+		nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR, "bus: 0x%x\n",
+			  nsp32_read1(base, SCSI_BUS_MONITOR));
+	};
+
+	data->msgoutlen = 0;
+
+	nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR, "exit");
+}
+
+/*
+ * Restart AutoSCSI
+ *
+ * Note: Restarting AutoSCSI needs set:
+ *		SYNC_REG, ACK_WIDTH, SGT_ADR, TRANSFER_CONTROL
+ */
+static void nsp32_restart_autoscsi(nsp32_hw_data *data, unsigned short command)
+{
+	unsigned int base = data->BaseAddress;
+	unsigned short transfer = 0;
+	Scsi_Cmnd *SCpnt = data->curlunt->SCpnt;
+
+	nsp32_dbg(NSP32_DEBUG_RESTART, "enter");
+
+	if (data->curtarget == NULL || data->curlunt == NULL) {
+		nsp32_msg(KERN_ERR, "Target or Lun is invalid");
+	}
+
+	/*
+	 * set SYNC_REG
+	 * Don't set BM_START_ADR before setting this register.
+	 */
+	nsp32_write1(base, SYNC_REG, data->curtarget->syncreg);
+
+	/*
+	 * set ACKWIDTH
+	 */
+	nsp32_write1(base, ACK_WIDTH, data->curtarget->ackwidth);
+
+	/*
+	 * set SGT ADDR (physical address)
+	 */
+	nsp32_write4(base, SGT_ADR, data->curlunt->sglun_paddr);
+
+	/*
+	 * set TRANSFER CONTROL REG
+	 */
+	transfer = 0;
+	transfer |= (TRANSFER_GO | ALL_COUNTER_CLR);
+	if (data->trans_method & NSP32_TRANSFER_BUSMASTER) {
+		if (SCpnt->request_bufflen > 0) {
+			transfer |= BM_START;
+		}
+	} else if (data->trans_method & NSP32_TRANSFER_MMIO) {
+		transfer |= CB_MMIO_MODE;
+	} else if (data->trans_method & NSP32_TRANSFER_PIO) {
+		transfer |= CB_IO_MODE;
+	}
+	nsp32_write2(base, TRANSFER_CONTROL, transfer);
+
+	/*
+	 * restart AutoSCSI
+	 *
+	 * TODO: COMMANDCONTROL_AUTO_COMMAND_PHASE is needed ?
+	 */
+	command |= (CLEAR_CDB_FIFO_POINTER |
+		    AUTO_COMMAND_PHASE |
+		    AUTOSCSI_RESTART);
+	nsp32_write2(base, COMMAND_CONTROL, command);
+
+	nsp32_dbg(NSP32_DEBUG_RESTART, "exit");
+}
+
+
+/*
+ * cannot run automatically message in occur
+ */
+static void nsp32_msgin_occur(nsp32_hw_data *data, unsigned long irq_status,
+			unsigned short execph)
+{
+	unsigned int base = data->BaseAddress;
+	unsigned char msg;
+	unsigned char msgtype;
+	unsigned char newlun;
+	unsigned short command = 0;
+	int msgclear = TRUE;
+	long new_sgtp;
+	int ret;
+
+	/*
+	 * read first message
+	 *    Use SCSIDATA_W_ACK instead of SCSIDATAIN, because the procedure
+	 *    of Message-In have to be processed before sending back SCSI ACK.
+	 */
+	msg = nsp32_read1(base, SCSI_DATA_IN);
+	data->msginbuf[(unsigned char)data->msginlen] = msg;
+	msgtype = data->msginbuf[0];
+	nsp32_dbg(NSP32_DEBUG_MSGINOCCUR,
+		  "enter: msglen: 0x%x msgin: 0x%x msgtype: 0x%x",
+		  data->msginlen, msg, msgtype);
+
+	/*
+	 * TODO: We need checking whether bus phase is message in?
+	 */
+
+	/*
+	 * assert SCSI ACK
+	 */
+	nsp32_sack_assert(data);
+
+	/*
+	 * processing IDENTIFY
+	 */
+	if (msgtype & 0x80) {
+		if (!(irq_status & IRQSTATUS_RESELECT_OCCUER)) {
+			/* Invalid (non reselect) phase */
+			goto reject;
+		}
+
+		newlun = msgtype & 0x1f; /* TODO: SPI-3 compliant? */
+		ret = nsp32_reselection(data, newlun);
+		if (ret == TRUE) {
+			goto restart;
+		} else {
+			goto reject;
+		}
+	}
+	
+	/*
+	 * processing messages except for IDENTIFY
+	 *
+	 * TODO: Messages are all SCSI-2 terminology. SCSI-3 compliance is TODO.
+	 */
+	switch (msgtype) {
+	/*
+	 * 1-byte message
+	 */
+	case COMMAND_COMPLETE:
+	case DISCONNECT:
+		/*
+		 * These messages should not be occured.
+		 * They should be processed on AutoSCSI sequencer.
+		 */
+		nsp32_msg(KERN_WARNING, 
+			   "unexpected message of AutoSCSI MsgIn: 0x%x", msg);
+		break;
+		
+	case RESTORE_POINTERS:
+		/*
+		 * AutoMsgIn03 is disabled, and HBA gets this message.
+		 */
+
+		if ((execph & DATA_IN_PHASE) || (execph & DATA_OUT_PHASE)) {
+			unsigned int s_sacklen;
+
+			s_sacklen = nsp32_read4(base, SAVED_SACK_CNT);
+			if ((execph & MSGIN_02_VALID) && (s_sacklen > 0)) {
+				nsp32_adjust_busfree(data, s_sacklen);
+			} else {
+				/* No need to rewrite SGT */
+			}
+		}
+		data->curlunt->msgin03 = FALSE;
+
+		/* Update with the new value */
+
+		/* reset SACK/SavedACK counter (or ALL clear?) */
+		nsp32_write4(base, CLR_COUNTER, CLRCOUNTER_ALLMASK);
+
+		/*
+		 * set new sg pointer
+		 */
+		new_sgtp = data->curlunt->sglun_paddr + 
+			data->curlunt->cur_entry * sizeof(struct nsp32_sgtable);
+		nsp32_write4(base, SGT_ADR, new_sgtp);
+
+		break;
+
+	case SAVE_POINTERS:
+		/*
+		 * These messages should not be occured.
+		 * They should be processed on AutoSCSI sequencer.
+		 */
+		nsp32_msg (KERN_WARNING, 
+			   "unexpected message of AutoSCSI MsgIn: SAVE_POINTERS");
+		
+		break;
+		
+	case MESSAGE_REJECT:
+		/* If previous message_out is sending SDTR, and get 
+		   message_reject from target, SDTR negotiation is failed */
+		if (data->curtarget->sync_flag &
+				(SDTR_INITIATOR | SDTR_TARGET)) {
+			/*
+			 * Current target is negotiating SDTR, but it's
+			 * failed.  Fall back to async transfer mode, and set
+			 * SDTR_DONE.
+			 */
+			nsp32_set_async(data, data->curtarget);
+			data->curtarget->sync_flag &= ~SDTR_INITIATOR;
+			data->curtarget->sync_flag |= SDTR_DONE;
+
+		}
+		break;
+
+	case LINKED_CMD_COMPLETE:
+	case LINKED_FLG_CMD_COMPLETE:
+		/* queue tag is not supported currently */
+		nsp32_msg (KERN_WARNING, 
+			   "unsupported message: 0x%x", msgtype);
+		break;
+
+	case INITIATE_RECOVERY:
+		/* staring ECA (Extended Contingent Allegiance) state. */
+		/* This message is declined in SPI2 or later. */
+
+		goto reject;
+
+	/*
+	 * 2-byte message
+	 */
+	case SIMPLE_QUEUE_TAG:
+	case 0x23:
+		/*
+		 * 0x23: Ignore_Wide_Residue is not declared in scsi.h.
+		 * No support is needed.
+		 */
+		if (data->msginlen >= 1) {
+			goto reject;
+		}
+
+		/* current position is 1-byte of 2 byte */
+		msgclear = FALSE;
+
+		break;
+
+	/*
+	 * extended message
+	 */
+	case EXTENDED_MESSAGE:
+		if (data->msginlen < 1) {
+			/*
+			 * Current position does not reach 2-byte
+			 * (2-byte is extended message length).
+			 */
+			msgclear = FALSE;
+			break;
+		}
+
+		if ((data->msginbuf[1] + 1) > data->msginlen) {
+			/*
+			 * Current extended message has msginbuf[1] + 2
+			 * (msginlen starts counting from 0, so buf[1] + 1).
+			 * If current message position is not finished,
+			 * continue receiving message.
+			 */
+			msgclear = FALSE;
+			break;
+		}
+
+		/*
+		 * Reach here means regular length of each type of 
+		 * extended messages.
+		 */
+		switch (data->msginbuf[2]) {
+		case EXTENDED_MODIFY_DATA_POINTER:
+			/* TODO */
+			goto reject; /* not implemented yet */
+			break;
+
+		case EXTENDED_SDTR:
+			/*
+			 * Exchange this message between initiator and target.
+			 */
+			if (data->msginlen != EXTENDED_SDTR_LEN + 1) {
+				/*
+				 * received inappropriate message.
+				 */
+				goto reject;
+				break;
+			}
+
+			nsp32_analyze_sdtr(data);
+
+			break;
+
+		case EXTENDED_EXTENDED_IDENTIFY:
+			/* SCSI-I only, not supported. */
+			goto reject; /* not implemented yet */
+
+			break;
+
+		case EXTENDED_WDTR:
+			goto reject; /* not implemented yet */
+
+			break;
+			
+		default:
+			goto reject;
+		}
+		break;
+		
+	default:
+		goto reject;
+	}
+
+ restart:
+	if (msgclear == TRUE) {
+		data->msginlen = 0;
+
+		/*
+		 * If restarting AutoSCSI, but there are some message to out
+		 * (msgoutlen > 0), set AutoATN, and set SCSIMSGOUT as 0
+		 * (MV_VALID = 0). When commandcontrol is written with
+		 * AutoSCSI restart, at the same time MsgOutOccur should be
+		 * happened (however, such situation is really possible...?).
+		 */
+		if (data->msgoutlen > 0) {	
+			nsp32_write4(base, SCSI_MSG_OUT, 0);
+			command |= AUTO_ATN;
+		}
+
+		/*
+		 * restart AutoSCSI
+		 * If it's failed, COMMANDCONTROL_AUTO_COMMAND_PHASE is needed.
+		 */
+		command |= (AUTO_MSGIN_00_OR_04 | AUTO_MSGIN_02);
+
+		/*
+		 * If current msgin03 is TRUE, then flag on.
+		 */
+		if (data->curlunt->msgin03 == TRUE) {
+			command |= AUTO_MSGIN_03;
+		}
+		data->curlunt->msgin03 = FALSE;
+	} else {
+		data->msginlen++;
+	}
+
+	/*
+	 * restart AutoSCSI
+	 */
+	nsp32_restart_autoscsi(data, command);
+
+	/*
+	 * wait SCSI REQ negate for REQ-ACK handshake
+	 */
+	nsp32_wait_req(data, NEGATE);
+
+	/*
+	 * negate SCSI ACK
+	 */
+	nsp32_sack_negate(data);
+
+	nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "exit");
+
+	return;
+
+ reject:
+	nsp32_msg(KERN_WARNING, 
+		  "invalid or unsupported MessageIn, rejected. "
+		  "current msg: 0x%x (len: 0x%x), processing msg: 0x%x",
+		  msg, data->msginlen, msgtype);
+	nsp32_build_reject(data);
+	data->msginlen = 0;
+
+	goto restart;
+}
+
+/*
+ * 
+ */
+static void nsp32_analyze_sdtr(nsp32_hw_data *data)
+{
+	struct nsp32_target *target = data->curtarget;
+	struct nsp32_sync_table *synct;
+	unsigned char get_period = data->msginbuf[3];
+	unsigned char get_offset = data->msginbuf[4];
+	int entry;
+	int syncnum;
+
+	nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "enter");
+
+	synct = data->synct;
+	syncnum = data->syncnum;
+
+	/*
+	 * If this inititor sent the SDTR message, then target responds SDTR,
+	 * initiator SYNCREG, ACKWIDTH from SDTR parameter.
+	 * Messages are not appropriate, then send back reject message.
+	 * If initiator did not send the SDTR, but target sends SDTR, 
+	 * initiator calculator the appropriate parameter and send back SDTR.
+	 */	
+	if (target->sync_flag & SDTR_INITIATOR) {
+		/*
+		 * Initiator sent SDTR, the target responds and
+		 * send back negotiation SDTR.
+		 */
+		nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "target responds SDTR");
+	
+		target->sync_flag &= ~SDTR_INITIATOR;
+		target->sync_flag |= SDTR_DONE;
+
+		/*
+		 * offset:
+		 */
+		if (get_offset > SYNC_OFFSET) {
+			/*
+			 * Negotiation is failed, the target send back
+			 * unexpected offset value.
+			 */
+			goto reject;
+		}
+		
+		if (get_offset == ASYNC_OFFSET) {
+			/*
+			 * Negotiation is succeeded, the target want
+			 * to fall back into asynchronous transfer mode.
+			 */
+			goto async;
+		}
+
+		/*
+		 * period:
+		 *    Check whether sync period is too short. If too short,
+		 *    fall back to async mode. If it's ok, then investigate
+		 *    the received sync period. If sync period is acceptable
+		 *    between sync table start_period and end_period, then
+		 *    set this I_T nexus as sent offset and period.
+		 *    If it's not acceptable, send back reject and fall back
+		 *    to async mode.
+		 */
+		if (get_period < data->synct[0].period_num) {
+			/*
+			 * Negotiation is failed, the target send back
+			 * unexpected period value.
+			 */
+			goto reject;
+		}
+
+		entry = nsp32_search_period_entry(data, target, get_period);
+
+		if (entry < 0) {
+			/*
+			 * Target want to use long period which is not 
+			 * acceptable NinjaSCSI-32Bi/UDE.
+			 */
+			goto reject;
+		}
+
+		/*
+		 * Set new sync table and offset in this I_T nexus.
+		 */
+		nsp32_set_sync_entry(data, target, entry, get_offset);
+	} else {
+		/* Target send SDTR to initiator. */
+		nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "target send SDTR");
+	
+		target->sync_flag |= SDTR_INITIATOR;
+
+		/* offset: */
+		if (get_offset > SYNC_OFFSET) {
+			/* send back as SYNC_OFFSET */
+			get_offset = SYNC_OFFSET;
+		}
+
+		/* period: */
+		if (get_period < data->synct[0].period_num) {
+			get_period = data->synct[0].period_num;
+		}
+
+		entry = nsp32_search_period_entry(data, target, get_period);
+
+		if (get_offset == ASYNC_OFFSET || entry < 0) {
+			nsp32_set_async(data, target);
+			nsp32_build_sdtr(data, 0, ASYNC_OFFSET);
+		} else {
+			nsp32_set_sync_entry(data, target, entry, get_offset);
+			nsp32_build_sdtr(data, get_period, get_offset);
+		}
+	}
+	
+	nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "exit");
+	return;
+
+ reject:
+	/*
+	 * If the current message is unacceptable, send back to the target
+	 * with reject message.
+	 */
+	nsp32_build_reject(data);
+
+ async:
+	nsp32_set_async(data, target);	/* set as ASYNC transfer mode */
+
+	nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "exit: set async");
+	return;
+}
+
+
+/*
+ * Search config entry number matched in sync_table from given
+ * target and speed period value. If failed to search, return negative value.
+ */
+static int nsp32_search_period_entry(nsp32_hw_data *data,
+			      struct nsp32_target *target,
+			      unsigned char period)
+{
+	int i;
+
+	if (target->limit_entry >= data->syncnum) {
+		nsp32_msg(KERN_ERR, "limit_entry exceeds syncnum!");
+		target->limit_entry = 0;
+	}
+
+	for (i=target->limit_entry; i<data->syncnum; i++) {
+		if (period >= data->synct[i].start_period &&
+		    period <= data->synct[i].end_period) {
+				break;
+		}
+	}
+
+	/*
+	 * Check given period value is over the sync_table value.
+	 * If so, return max value.
+	 */
+	if (i == data->syncnum) {
+		i = -1;
+	}
+
+	return i;
+}
+
+
+/*
+ * target <-> initiator use ASYNC transfer
+ */
+static void nsp32_set_async(nsp32_hw_data *data, struct nsp32_target *target)
+{
+	unsigned char period = data->synct[target->limit_entry].period_num;
+
+	target->offset   = ASYNC_OFFSET;
+	target->syncreg  = TO_SYNCREG(period, ASYNC_OFFSET);
+	target->ackwidth = 0;
+
+	nsp32_dbg(NSP32_DEBUG_SYNC, "set async");
+}
+
+
+/*
+ * target <-> initiator use maximum SYNC transfer
+ */
+static void nsp32_set_max_sync(nsp32_hw_data *data,
+			       struct nsp32_target *target,
+			       unsigned char *period, unsigned char *offset)
+{
+	unsigned char period_num, ackwidth;
+
+	period_num = data->synct[target->limit_entry].period_num;
+	*period    = data->synct[target->limit_entry].start_period;
+	ackwidth   = data->synct[target->limit_entry].ackwidth;
+	*offset    = SYNC_OFFSET;
+
+	target->syncreg  = TO_SYNCREG(period_num, *offset);
+	target->ackwidth = ackwidth;
+	target->offset   = *offset;
+}
+
+
+/*
+ * target <-> initiator use entry number speed
+ */
+static void nsp32_set_sync_entry(nsp32_hw_data *data,
+				 struct nsp32_target *target,
+				 int entry, unsigned char offset)
+{
+	unsigned char period, ackwidth;
+
+	period   = data->synct[entry].period_num;
+	ackwidth = data->synct[entry].ackwidth;
+	offset  = offset;
+
+	target->syncreg  = TO_SYNCREG(period, offset);
+	target->ackwidth = ackwidth;
+	target->offset   = offset;
+
+	nsp32_dbg(NSP32_DEBUG_SYNC, "set sync");
+}
+
+
+/*
+ * It waits until SCSI REQ becomes assertion or negation state.
+ *
+ * Note: If nsp32_msgin_occur is called, we asserts SCSI ACK. Then
+ *     connected target responds SCSI REQ negation.  We have to wait
+ *     SCSI REQ becomes negation in order to negate SCSI ACK signal for
+ *     REQ-ACK handshake.
+ */
+static void nsp32_wait_req(nsp32_hw_data *data, int state)
+{
+	unsigned int base = data->BaseAddress;
+	int wait_time = 0;
+	unsigned char bus;
+
+	if (!((state == ASSERT) || (state == NEGATE))) {
+		nsp32_msg(KERN_ERR, "unknown state designation");
+	}
+	state <<= 5; /* REQ is BIT(5) */
+
+	do {
+		bus = nsp32_read1(base, SCSI_BUS_MONITOR);
+		if ((bus & BUSMON_REQ) == state) {
+			nsp32_dbg(NSP32_DEBUG_WAIT, 
+				  "wait_time: %d", wait_time);
+			return;
+		}
+		udelay(1);
+		wait_time++;
+	} while (wait_time < REQSACK_TIMEOUT_TIME);
+
+	nsp32_msg(KERN_WARNING, "wait REQ timeout, state: %d", state);
+}
+
+/*
+ * It waits until SCSI SACK becomes assertion or negation state.
+ */
+static void nsp32_wait_sack(nsp32_hw_data *data, int state)
+{
+	unsigned int base = data->BaseAddress;
+	int wait_time = 0;
+	unsigned char bus;
+
+	if (!((state == ASSERT) || (state == NEGATE))) {
+		nsp32_msg(KERN_ERR, "unknown state designation");
+	}
+	state <<= 4; /* ACK is BIT(4) */
+
+	do {
+		bus = nsp32_read1(base, SCSI_BUS_MONITOR);
+		if ((bus & BUSMON_ACK) == state) {
+			nsp32_dbg(NSP32_DEBUG_WAIT,
+				  "wait_time: %d", wait_time);
+			return;
+		}
+		udelay(1);
+		wait_time++;
+	} while (wait_time < REQSACK_TIMEOUT_TIME);
+
+	nsp32_msg(KERN_WARNING, "wait SACK timeout, state: %d", state);
+}
+
+/*
+ * assert SCSI ACK
+ *
+ * Note: SCSI ACK assertion needs with ACKENB=1, AUTODIRECTION=1.
+ */
+static void nsp32_sack_assert(nsp32_hw_data *data)
+{
+	unsigned char busctrl;
+	unsigned int base = data->BaseAddress;
+
+	busctrl  = nsp32_read1(base, SCSI_BUS_CONTROL);
+	busctrl	|= (BUSCTL_ACK | AUTODIRECTION | ACKENB);
+	nsp32_write1(base, SCSI_BUS_CONTROL,busctrl);
+}
+
+/*
+ * negate SCSI ACK
+ */
+static void nsp32_sack_negate(nsp32_hw_data *data)
+{
+	unsigned char busctrl;
+	unsigned int base = data->BaseAddress;
+
+	busctrl  = nsp32_read1(base, SCSI_BUS_CONTROL);
+	busctrl	&= ~BUSCTL_ACK;
+	nsp32_write1(base, SCSI_BUS_CONTROL, busctrl);
+}
+
+
+
+/*
+ * getting EEPROM parameter
+ */
+static int nsp32_getprom_param(nsp32_hw_data *data)
+{
+	int vendor = data->pci_devid->vendor;
+	int device = data->pci_devid->device;
+	int ret, val, i;
+
+	/*
+	 * EEPROM checking.
+	 */
+	ret = nsp32_prom_read(data, 0x7e);
+	if (ret != 0x55) {
+		nsp32_msg(KERN_INFO, "No EEPROM detected: 0x%x", ret);
+		return (FALSE);
+	}
+	ret = nsp32_prom_read(data, 0x7f);
+	if (ret != 0xaa) {
+		nsp32_msg(KERN_INFO, "Invalid number: 0x%x", ret);
+		return (FALSE);
+	}
+
+	/*
+	 * check EEPROM type
+	 */
+	if (vendor == PCI_VENDOR_ID_WORKBIT &&
+	    device == PCI_DEVICE_ID_WORKBIT_STANDARD) {
+		ret = nsp32_getprom_standard(data);
+	} else if (vendor == PCI_VENDOR_ID_WORKBIT &&
+		   device == PCI_DEVICE_ID_NINJASCSI_32BIB_LOGITEC) {
+		ret = nsp32_getprom_new(data);
+	} else if (vendor == PCI_VENDOR_ID_WORKBIT &&
+		   device == PCI_DEVICE_ID_NINJASCSI_32UDE_MELCO ) {
+		ret = nsp32_getprom_new(data);
+	} else {
+		nsp32_msg(KERN_WARNING, "Unknown EEPROM");
+		ret = FALSE;
+	}
+
+	/* for debug : SPROM data full checking */
+	for (i=0; i<=0x1f; i++) {
+		val = nsp32_prom_read(data, i);
+		nsp32_dbg(NSP32_DEBUG_EEPROM,
+			  "rom address 0x%x : 0x%x", i, val);
+	}
+
+	return (ret);
+}
+
+
+/*
+ * AT24C01A (Logitec: LHA-600S), AT24C02 (Melco Buffalo: IFC-USLP) data map:
+ *
+ *   ROMADDR
+ *   0x00 - 0x06 :  Device Synchronous Transfer Period (SCSI ID 0 - 6) 
+ *			Value 0x0: ASYNC, 0x0c: Ultra-20M, 0x19: Fast-10M
+ *   0x07        :  HBA Synchronous Transfer Period
+ *			Value 0: AutoSync, 1: Manual Setting
+ *   0x08 - 0x0f :  Not Used? (0x0)
+ *   0x10        :  Bus Termination
+ * 			Value 0: Auto[ON], 1: ON, 2: OFF
+ *   0x11        :  Not Used? (0)
+ *   0x12        :  Bus Reset Delay Time (0x03)
+ *   0x13        :  Bootable CD Support
+ *			Value 0: Disable, 1: Enable
+ *   0x14        :  Device Scan
+ *			Bit   7  6  5  4  3  2  1  0
+ *			      |  <----------------->
+ * 			      |    SCSI ID: Value 0: Skip, 1: YES
+ *			      |->  Value 0: ALL scan,  Value 1: Manual
+ *   0x15 - 0x1b :  Not Used? (0)
+ *   0x1c        :  Constant? (0x01) (clock div?)
+ *   0x1d - 0x7c :  Not Used (0xff)
+ *   0x7d	 :  Not Used? (0xff)
+ *   0x7e        :  Constant (0x55), HBA chip revision
+ *   0x7f        :  Constant (0xaa), HBA value
+ */
+static int nsp32_getprom_new(nsp32_hw_data *data)
+{
+	int ret, i;
+	int auto_sync;
+	struct nsp32_target *target;
+	int entry;
+
+	/*
+	 * Reset time which is designated by EEPROM.
+	 *
+	 * TODO: Not used yet.
+	 */
+	data->resettime = nsp32_prom_read(data, 0x12);
+
+	/*
+	 * HBA Synchronous Transfer Period
+	 *
+	 * Note: auto_sync = 0: auto, 1: manual.  Ninja SCSI HBA spec says
+	 *	that if auto_sync is 0 (auto), and connected SCSI devices are
+	 *	same or lower than 3, then transfer speed is set as ULTRA-20M.
+	 *	On the contrary if connected SCSI devices are same or higher
+	 *	than 4, then transfer speed is set as FAST-10M.
+	 *
+	 *	I break this rule. The number of connected SCSI devices are
+	 *	only ignored. If auto_sync is 0 (auto), then transfer speed is
+	 *	forced as ULTRA-20M.
+	 */
+	ret = nsp32_prom_read(data, 0x07);
+	switch (ret) {
+	case 0:
+		auto_sync = TRUE;
+		break;
+	case 1:
+		auto_sync = FALSE;
+		break;
+	default:
+		nsp32_msg(KERN_WARNING,
+			  "Unsupported Auto Sync mode."
+			  "Fall back to manual mode.");
+		auto_sync = TRUE;
+	}
+
+	if (trans_mode == ULTRA20M_MODE) {
+		auto_sync = TRUE;
+	}
+
+	/*
+	 * each device Synchronous Transfer Period
+	 */
+	for (i=0; i<NSP32_HOST_SCSIID; i++) {
+		target = &data->target[i];
+		if (auto_sync == TRUE) {
+			target->limit_entry = 0;   /* set as ULTRA20M */
+		} else {
+			ret = nsp32_prom_read(data, i);
+			entry = nsp32_search_period_entry(data, target, ret);
+			if (entry < 0) {
+				/* search failed... set maximum speed */
+				entry = 0;
+			}
+			target->limit_entry = entry;
+		}
+	}
+
+	return (TRUE);
+}
+
+
+/*
+ * ? (I-O Data: SC-NBD) data map:
+ *
+ *   ROMADDR
+ *   0x00 - 0x06 :  Device Synchronous Transfer Period (SCSI ID 0 - 6) 
+ *			Value 0x0: 20MB/S, 0x1: 10MB/S, 0x2: 5MB/S, 0x3: ASYNC
+ *   0x07        :  0 (HBA Synchronous Transfer Period: Auto Sync)
+ *   0x08 - 0x0f :  Not Used? (0x0)
+ *   0x10        :  Transfer Mode
+ *			Value 0: PIO, 1: Busmater
+ *   0x11        :  Bus Reset Delay Time (0x00-0x20)
+ *   0x12        :  Bus Termination
+ * 			Value 0: Disable, 1: Enable
+ *   0x13 - 0x19 :  Disconnection
+ *			Value 0: Disable, 1: Enable
+ *   0x1a - 0x7c :  Not Used? (0)
+ *   0x7d	 :  Not Used? (0xf8)
+ *   0x7e        :  Constant (0x55), HBA chip revision
+ *   0x7f        :  Constant (0xaa), HBA value
+ */
+static int nsp32_getprom_standard(nsp32_hw_data *data)
+{
+	int ret, i;
+	struct nsp32_target *target;
+	int entry, val;
+
+	/*
+	 * Reset time which is designated by EEPROM.
+	 *
+	 * TODO: Not used yet.
+	 */
+	data->resettime = nsp32_prom_read(data, 0x11);
+
+	/*
+	 * each device Synchronous Transfer Period
+	 */
+	for (i=0; i<NSP32_HOST_SCSIID; i++) {
+		target = &data->target[i];
+		ret = nsp32_prom_read(data, i);
+		switch (ret) {
+		case 0:		/* 20MB/s */
+			val = 0x0c;
+			break;
+		case 1:		/* 10MB/s */
+			val = 0x19;
+			break;
+		case 2:		/* 5MB/s */
+			val = 0x32;
+			break;
+		case 3:		/* ASYNC */
+			val = 0x0;
+			break;
+		default:	/* default 20MB/s */
+			val = 0x0c;
+		}
+		entry = nsp32_search_period_entry(data, target, val);
+		if (entry < 0 || trans_mode == ULTRA20M_MODE) {
+			/* search failed... set maximum speed */
+			entry = 0;
+		}
+		target->limit_entry = entry;
+	}
+
+	return (TRUE);
+}
+
+
+/*
+ * Atmel AT24C01A (drived in 5V) serial EEPROM routines
+ */
+static int nsp32_prom_read(nsp32_hw_data *data, int romaddr)
+{
+	int i, val;
+
+	/* start condition */
+	nsp32_prom_start(data);
+
+	/* device address */
+	nsp32_prom_write(data, 1);	/* 1 */
+	nsp32_prom_write(data, 0);	/* 0 */
+	nsp32_prom_write(data, 1);	/* 1 */
+	nsp32_prom_write(data, 0);	/* 0 */
+	nsp32_prom_write(data, 0);	/* A2: 0 (GND) */
+	nsp32_prom_write(data, 0);	/* A1: 0 (GND) */
+	nsp32_prom_write(data, 0);	/* A0: 0 (GND) */
+
+	/* R/W: W for dummy write */
+	nsp32_prom_write(data, 0);
+
+	/* ack */
+	nsp32_prom_write(data, 0);
+
+	/* word address */
+	for (i=7; i>=0; i--) {
+		nsp32_prom_write(data, ((romaddr >> i) & 1));
+	}
+
+	/* ack */
+	nsp32_prom_write(data, 0);
+
+	/* start condition */
+	nsp32_prom_start(data);
+
+	/* device address */
+	nsp32_prom_write(data, 1);	/* 1 */
+	nsp32_prom_write(data, 0);	/* 0 */
+	nsp32_prom_write(data, 1);	/* 1 */
+	nsp32_prom_write(data, 0);	/* 0 */
+	nsp32_prom_write(data, 0);	/* A2: 0 (GND) */
+	nsp32_prom_write(data, 0);	/* A1: 0 (GND) */
+	nsp32_prom_write(data, 0);	/* A0: 0 (GND) */
+
+	/* R/W: R */
+	nsp32_prom_write(data, 1);
+
+	/* ack */
+	nsp32_prom_write(data, 0);
+
+	/* data... */
+	val = 0;
+	for (i=7; i>=0; i--) {
+		val += (nsp32_prom_fetch(data) << i);
+	}
+	
+	/* no ack */
+	nsp32_prom_write(data, 1);
+
+	/* stop condition */
+	nsp32_prom_stop(data);
+
+	return (val);
+}
+
+static void nsp32_prom_start (nsp32_hw_data *data)
+{
+	/* start condition */
+	nsp32_prom_set(data, SCL, 1);
+	nsp32_prom_set(data, SDA, 1);
+	nsp32_prom_set(data, ENA, 1);	/* output mode */
+	nsp32_prom_set(data, SDA, 0);	/* keeping SCL=1 and transiting
+					 * SDA 1->0 is start condition */
+	nsp32_prom_set(data, SCL, 0);
+}
+
+static void nsp32_prom_stop (nsp32_hw_data *data)
+{
+	/* stop condition */
+	nsp32_prom_set(data, SCL, 1);
+	nsp32_prom_set(data, SDA, 0);
+	nsp32_prom_set(data, ENA, 1);	/* output mode */
+	nsp32_prom_set(data, SDA, 1);
+	nsp32_prom_set(data, SCL, 0);
+}
+
+static void nsp32_prom_write (nsp32_hw_data *data, int val)
+{
+	/* write */
+	nsp32_prom_set(data, SDA, val);
+	nsp32_prom_set(data, SCL, 1);
+	nsp32_prom_set(data, SCL, 0);
+}
+
+static int nsp32_prom_fetch (nsp32_hw_data *data)
+{
+	int val;
+
+	/* read */
+	nsp32_prom_set(data, ENA, 0);	/* input mode */
+	nsp32_prom_set(data, SCL, 1);
+	val = nsp32_prom_get(data, SDA);
+	nsp32_prom_set(data, SCL, 0);
+	nsp32_prom_set(data, ENA, 1);	/* output mode */
+	return (val);
+}
+
+static inline void nsp32_prom_set(nsp32_hw_data *data, int bit, int val)
+{
+	int cur;
+	int base = data->BaseAddress;
+
+	switch(val) {
+	case 0:
+		cur = nsp32_index_read1(base, SERIAL_ROM_CTL);
+		nsp32_index_write1(base, SERIAL_ROM_CTL, cur & ~bit);
+		break;
+	case 1:
+		cur = nsp32_index_read1(base, SERIAL_ROM_CTL);
+		nsp32_index_write1(base, SERIAL_ROM_CTL, cur | bit);
+		break;
+	default:
+		nsp32_msg(KERN_ERR, "val must be 0 or 1");
+		return;
+	}
+
+	udelay(10);
+}
+
+static inline int nsp32_prom_get(nsp32_hw_data *data, int bit)
+{
+	int ret;
+	int base = data->BaseAddress;
+
+	ret = nsp32_index_read1(base, SERIAL_ROM_CTL) & bit;
+	switch (ret) {
+	case 0:
+		ret = 0;
+		break;
+	case SDA:
+		ret = 1;
+		break;
+	default:
+		nsp32_msg(KERN_ERR, "return value is not appropriate");
+	}
+
+	udelay(10);
+
+	return (ret);
+}
+
+/* end */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/nsp32.h linux-2.4.21-pre6/drivers/scsi/nsp32.h
--- linux-2.4.20/drivers/scsi/nsp32.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/nsp32.h	2003-03-26 23:49:39.000000000 +0000
@@ -0,0 +1,429 @@
+/*
+ * Workbit NinjaSCSI-32Bi/UDE PCI/Cardbus SCSI Host Bus Adapter driver
+ * Basic data header
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+*/
+
+#ifndef _NSP32_H
+#define _NSP32_H
+
+
+//#define NSP32_DEBUG 9
+
+
+/*
+ * VENDOR/DEVICE ID
+ */
+#define PCI_VENDOR_ID_IODATA  0x10fc
+#define PCI_VENDOR_ID_WORKBIT 0x1145
+
+#define PCI_DEVICE_ID_NINJASCSI_32BI_CBSC_II  0x0005
+#define PCI_DEVICE_ID_NINJASCSI_32BI_KME      0xf007
+#define PCI_DEVICE_ID_NINJASCSI_32BI_WBT      0x8007
+#define PCI_DEVICE_ID_WORKBIT_STANDARD        0xf010
+#define PCI_DEVICE_ID_WORKBIT_DUALEDGE        0xf011
+#define PCI_DEVICE_ID_NINJASCSI_32BI_LOGITEC  0xf012
+#define PCI_DEVICE_ID_NINJASCSI_32BIB_LOGITEC 0xf013
+#define PCI_DEVICE_ID_NINJASCSI_32UDE_MELCO   0xf015
+
+/*
+ * MODEL
+ */
+enum {
+	MODEL_IODATA        = 0,
+	MODEL_KME           = 1,
+	MODEL_WORKBIT       = 2,
+	MODEL_EXT_ROM       = 3,
+	MODEL_PCI_WORKBIT   = 4,
+	MODEL_PCI_LOGITEC   = 5,
+	MODEL_PCI_MELCO     = 6,
+};
+
+static char * nsp32_model[] = {
+	"I-O DATA CBSC-II",
+	"KME SCSI card",
+	"Workbit duo SCSI card",
+	"External ROM",
+	"Workbit Standard/IO Data PCI card",
+	"Logitec PCI card",
+	"Melco PCI card",
+};
+
+
+/*
+ * SCSI Generic Definitions
+ */
+#define EXTENDED_SDTR_LEN	0x03
+
+
+/*
+ * MACRO
+ */
+#define BIT(x)    (1UL << (x))
+#ifndef MIN
+# define MIN(a,b)  ((a) > (b) ? (b) : (a))
+#endif
+
+/*
+ * BASIC Definitions
+ */
+#ifndef TRUE
+# define TRUE  1
+#endif
+#ifndef FALSE
+# define FALSE 0
+#endif
+#define ASSERT 1
+#define NEGATE 0
+
+
+/*******************/
+/* normal register */
+/*******************/
+/*
+ * Don't access below register with Double Word:
+ * +00, +04, +08, +0c, +64, +80, +84, +88, +90, +c4, +c8, +cc, +d0.
+ */
+#define IRQ_CONTROL 0x00	/* BASE+00, W, W */
+#define IRQ_STATUS  0x00	/* BASE+00, W, R */
+# define IRQSTATUS_LATCHED_MSG      BIT(0)
+# define IRQSTATUS_LATCHED_IO       BIT(1)
+# define IRQSTATUS_LATCHED_CD       BIT(2)
+# define IRQSTATUS_LATCHED_BUS_FREE BIT(3)
+# define IRQSTATUS_RESELECT_OCCUER  BIT(4)
+# define IRQSTATUS_PHASE_CHANGE_IRQ BIT(5)
+# define IRQSTATUS_SCSIRESET_IRQ    BIT(6)
+# define IRQSTATUS_TIMER_IRQ        BIT(7)
+# define IRQSTATUS_FIFO_SHLD_IRQ    BIT(8)
+# define IRQSTATUS_PCI_IRQ	    BIT(9)
+# define IRQSTATUS_BMCNTERR_IRQ     BIT(10)
+# define IRQSTATUS_AUTOSCSI_IRQ     BIT(11)
+# define PCI_IRQ_MASK               BIT(12)
+# define TIMER_IRQ_MASK             BIT(13)
+# define FIFO_IRQ_MASK              BIT(14)
+# define SCSI_IRQ_MASK              BIT(15)
+# define IRQ_CONTROL_ALL_IRQ_MASK   0xf000
+# define IRQSTATUS_ANY_IRQ          (IRQSTATUS_RESELECT_OCCUER	| \
+				     IRQSTATUS_PHASE_CHANGE_IRQ	| \
+				     IRQSTATUS_SCSIRESET_IRQ	| \
+				     IRQSTATUS_TIMER_IRQ	| \
+				     IRQSTATUS_FIFO_SHLD_IRQ	| \
+				     IRQSTATUS_PCI_IRQ		| \
+				     IRQSTATUS_BMCNTERR_IRQ	| \
+				     IRQSTATUS_AUTOSCSI_IRQ	)
+
+#define TRANSFER_CONTROL 0x02	/* BASE+02, W, W */
+#define TRANSFER_STATUS  0x02	/* BASE+02, W, R */
+# define CB_MMIO_MODE        BIT(0)
+# define CB_IO_MODE          BIT(1)
+# define BM_TEST             BIT(2)
+# define BM_TEST_DIR         BIT(3)
+# define DUAL_EDGE_ENABLE    BIT(4)
+# define NO_TRANSFER_TO_HOST BIT(5)
+# define TRANSFER_GO         BIT(7)
+# define BLIEND_MODE         BIT(8)
+# define BM_START            BIT(9)
+# define ADVANCED_BM_WRITE   BIT(10)
+# define BM_SINGLE_MODE      BIT(11)
+# define FIFO_TRUE_FULL      BIT(12)
+# define FIFO_TRUE_EMPTY     BIT(13)
+# define ALL_COUNTER_CLR     BIT(14)
+# define FIFOTEST            BIT(15)
+
+#define INDEX_REG 0x04		/* BASE+04, Byte(R/W), Word(R) */
+
+#define TIMER_SET 0x06		/* BASE+06, W, R/W */
+# define TIMER_CNT_MASK 0xff
+# define TIMER_STOP     BIT(8)
+
+#define DATA_REG_LOW 0x08	/* BASE+08, LowW, R/W */
+#define DATA_REG_HI  0x0a	/* BASE+0a, Hi-W, R/W */
+
+#define FIFO_REST_CNT 0x0c	/* BASE+0c, W, R/W */
+# define FIFO_REST_MASK       0x1ff
+# define FIFO_EMPTY_SHLD_FLAG BIT(14)
+# define FIFO_FULL_SHLD_FLAG  BIT(15)
+
+#define SREQ_SMPL_RATE 0x0f	/* BASE+0f, B, R/W */
+# define SREQSMPLRATE_RATE0 BIT(0)
+# define SREQSMPLRATE_RATE1 BIT(1)
+# define SAMPLING_ENABLE    BIT(2)
+
+#define SCSI_BUS_CONTROL 0x10	/* BASE+10, B, R/W */
+# define BUSCTL_SEL         BIT(0)
+# define BUSCTL_RST         BIT(1)
+# define BUSCTL_DATAOUT_ENB BIT(2)
+# define BUSCTL_ATN         BIT(3)
+# define BUSCTL_ACK         BIT(4)
+# define BUSCTL_BSY         BIT(5)
+# define AUTODIRECTION      BIT(6)
+# define ACKENB             BIT(7)
+
+#define CLR_COUNTER 0x12	/* BASE+12, B, W */
+# define ACK_COUNTER_CLR       BIT(0)
+# define SREQ_COUNTER_CLR      BIT(1)
+# define FIFO_HOST_POINTER_CLR BIT(2)
+# define FIFO_REST_COUNT_CLR   BIT(3)
+# define BM_COUNTER_CLR        BIT(4)
+# define SAVED_ACK_CLR         BIT(5)
+# define CLRCOUNTER_ALLMASK    (BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5))
+
+#define SCSI_BUS_MONITOR 0x12	/* BASE+12, B, R */
+# define BUSMON_MSG BIT(0)
+# define BUSMON_IO  BIT(1)
+# define BUSMON_CD  BIT(2)
+# define BUSMON_BSY BIT(3)
+# define BUSMON_ACK BIT(4)
+# define BUSMON_REQ BIT(5)
+# define BUSMON_SEL BIT(6)
+# define BUSMON_ATN BIT(7)
+
+#define COMMAND_DATA 0x14	/* BASE+14, B, R/W */
+
+#define PARITY_CONTROL 0x16	/* BASE+16, B, R/W */
+# define PARITY_CHECK_ENABLE BIT(0)
+# define PARITY_ERROR_CLEAR  BIT(1)
+#define PARITY_STATUS  0x16
+//# define PARITY_CHECK_ENABLE BIT(0)
+# define PARITY_ERROR_NORMAL BIT(1)
+# define PARITY_ERROR_LSB    BIT(1)
+# define PARITY_ERROR_MSB    BIT(2)
+
+#define RESELECT_ID 0x18	/* BASE+18, B, R */
+
+#define COMMAND_CONTROL 0x18	/* BASE+18, W, W */
+# define CLEAR_CDB_FIFO_POINTER BIT(0)
+# define AUTO_COMMAND_PHASE     BIT(1)
+# define AUTOSCSI_START         BIT(2)
+# define AUTOSCSI_RESTART       BIT(3)
+# define AUTO_PARAMETER         BIT(4)
+# define AUTO_ATN               BIT(5)
+# define AUTO_MSGIN_00_OR_04    BIT(6)
+# define AUTO_MSGIN_02          BIT(7)
+# define AUTO_MSGIN_03          BIT(8)
+
+#define SET_ARBIT 0x1a		/* BASE+1a, B, W */
+# define ARBIT_GO    BIT(0)
+# define ARBIT_CLEAR BIT(1)
+
+#define ARBIT_STATUS 0x1a	/* BASE+1a, B, R */
+//# define ARBIT_GO             BIT(0)
+# define ARBIT_WIN            BIT(1)
+# define ARBIT_FAIL           BIT(2)
+# define AUTO_PARAMETER_VALID BIT(3)
+# define SGT_VALID            BIT(4)
+
+#define SYNC_REG 0x1c	/* BASE+1c, B, R/W */
+
+#define ACK_WIDTH 0x1d	/* BASE+1d, B, R/W */
+
+#define SCSI_DATA_WITH_ACK 0x20	/* BASE+20, B, R/W */
+#define SCSI_OUT_LATCH_TARGET_ID 0x22	/* BASE+22, B, W */
+#define SCSI_DATA_IN 0x22	/* BASE+22, B, R */
+
+#define SCAM_CONTROL 0x24	/* BASE+24, B, W */
+#define SCAM_STATUS  0x24	/* BASE+24, B, R */
+# define SCAM_MSG    BIT(0)
+# define SCAM_IO     BIT(1)
+# define SCAM_CD     BIT(2)
+# define SCAM_BSY    BIT(3)
+# define SCAM_SEL    BIT(4)
+# define SCAM_XFEROK BIT(5)
+
+#define SCAM_DATA 0x26	/* BASE+26, B, R/W */
+# define SD0					BIT(0)
+# define SD1					BIT(1)
+# define SD2					BIT(2)
+# define SD3					BIT(3)
+# define SD4					BIT(4)
+# define SD5					BIT(5)
+# define SD6					BIT(6)
+# define SD7					BIT(7)
+
+#define SACK_CNT 0x28	/* BASE+28, DW, R/W */
+#define SREQ_CNT 0x2c	/* BASE+2c, DW, R/W */
+
+#define FIFO_DATA_LOW 0x30	/* BASE+30, B/W/DW, R/W */
+#define FIFO_DATA_HIGH 0x32	/* BASE+32, B/W, R/W */
+#define BM_START_ADR 0x34	/* BASE+34, DW, R/W */
+
+#define BM_CNT 0x38	/* BASE+38, DW, R/W */
+# define BM_COUNT_MASK 0x0001ffff
+# define SGTEND        BIT(31)
+
+#define SGT_ADR 0x3c	/* BASE+3c, DW, R/W */
+#define WAIT_REG 0x40	/* Bi only */
+
+#define SCSI_EXECUTE_PHASE 0x40	/* BASE+40, W, R */
+# define COMMAND_PHASE     BIT(0)
+# define DATA_IN_PHASE     BIT(1)
+# define DATA_OUT_PHASE    BIT(2)
+# define MSGOUT_PHASE      BIT(3)
+# define STATUS_PHASE      BIT(4)
+# define ILLEGAL_PHASE     BIT(5)
+# define BUS_FREE_OCCUER   BIT(6)
+# define MSG_IN_OCCUER     BIT(7)
+# define MSG_OUT_OCCUER    BIT(8)
+# define SELECTION_TIMEOUT BIT(9)
+# define MSGIN_00_VALID    BIT(10)
+# define MSGIN_02_VALID    BIT(11)
+# define MSGIN_03_VALID    BIT(12)
+# define MSGIN_04_VALID    BIT(13)
+# define AUTOSCSI_BUSY     BIT(15)
+
+#define SCSI_CSB_IN 0x42	/* BASE+42, B, R */
+
+#define SCSI_MSG_OUT 0x44	/* BASE+44, DW, R/W */
+# define MSGOUT_COUNT_MASK (BIT(0)|BIT(1))
+# define MV_VALID	      BIT(7)
+
+#define SEL_TIME_OUT 0x48	/* BASE+48, W, R/W */
+#define SAVED_SACK_CNT 0x4c	/* BASE+4c, DW, R */
+
+#define HTOSDATADELAY		0x50	/* BASE+50, B, R/W */
+#define STOHDATADELAY		0x54	/* BASE+54, B, R/W */
+#define ACKSUMCHECKRD		0x58	/* BASE+58, W, R */
+#define REQSUMCHECKRD		0x5c	/* BASE+5c, W, R */
+
+
+/********************/
+/* indexed register */
+/********************/
+
+#define CLOCK_DIV 0x00	/* BASE+08, IDX+00, B, R/W */
+# define CLOCK_2		BIT(0)	/* MCLK/2 */
+# define CLOCK_4		BIT(1)	/* MCLK/4 */
+# define PCICLK			BIT(7)	/* PCICLK (33MHz) */
+
+#define TERM_PWR_CONTROL 0x01	/* BASE+08, IDX+01, B, R/W */
+# define BPWR  BIT(0)
+# define SENSE BIT(1)	/* Read Only */
+
+#define EXT_PORT_DDR 0x02	/* BASE+08, IDX+02, B, R/W */
+#define EXT_PORT     0x03	/* BASE+08, IDX+03, B, R/W */
+# define LED_ON	 0
+# define LED_OFF 1
+
+#define IRQ_SELECT 0x04	/* BASE+08, IDX+04, W, R/W */
+# define IRQSELECT_RESELECT_IRQ      BIT(0)
+# define IRQSELECT_PHASE_CHANGE_IRQ  BIT(1)
+# define IRQSELECT_SCSIRESET_IRQ     BIT(2)
+# define IRQSELECT_TIMER_IRQ         BIT(3)
+# define IRQSELECT_FIFO_SHLD_IRQ     BIT(4)
+# define IRQSELECT_TARGET_ABORT_IRQ  BIT(5)
+# define IRQSELECT_MASTER_ABORT_IRQ  BIT(6)
+# define IRQSELECT_SERR_IRQ          BIT(7)
+# define IRQSELECT_PERR_IRQ          BIT(8)
+# define IRQSELECT_BMCNTERR_IRQ      BIT(9)
+# define IRQSELECT_AUTO_SCSI_SEQ_IRQ BIT(10)
+
+#define OLD_SCSI_PHASE 0x05	/* BASE+08, IDX+05, B, R */
+# define OLD_MSG  BIT(0)
+# define OLD_IO   BIT(1)
+# define OLD_CD   BIT(2)
+# define OLD_BUSY BIT(3)
+
+#define FIFO_FULL_SHLD_COUNT 0x06	/* BASE+08, IDX+06, B, R/W */
+#define FIFO_EMPTY_SHLD_COUNT 0x07	/* BASE+08, IDX+07, B, R/W */
+
+#define EXP_ROM_CONTROL 0x08	/* BASE+08, IDX+08, B, R/W */
+
+#define EXP_ROM_ADRL		0x09	/* BASE+08, IDX+09, W, R/W */
+
+#define EXP_ROM_DATA		0x0a	/* BASE+08, IDX+0a, B, R/W */
+
+#define CHIP_MODE 0x0b	/* Bi only */
+# define OEM0 BIT(1)
+# define OEM1 BIT(2)
+# define OPTB BIT(3)
+# define OPTC BIT(4)
+# define OPTD BIT(5)
+# define OPTE BIT(6)
+# define OPTF BIT(7)
+
+#define MISC_WR 0x0c	/* BASE+08, IDX+0c, W, R/W */
+#define MISC_RD 0x0c
+# define SCSI_DIRECTION_DETECTOR_SELECT BIT(0)
+# define SCSI2_HOST_DIRECTION_VALID	BIT(1)	/* Read only */
+# define HOST2_SCSI_DIRECTION_VALID	BIT(2)	/* Read only */
+# define DELAYED_BMSTART                BIT(3)
+# define MASTER_TERMINATION_SELECT      BIT(4)
+# define BMREQ_NEGATE_TIMING_SEL        BIT(5)
+# define AUTOSEL_TIMING_SEL             BIT(6)
+# define MISC_MABORT_MASK		BIT(7)
+# define BMSTOP_CHANGE2_NONDATA_PHASE	BIT(8)
+
+#define BM_CYCLE 0x0d	/* BASE+08, IDX+0d, B, R/W */
+# define BM_CYCLE0		 BIT(0)
+# define BM_CYCLE1		 BIT(1)
+# define BM_FRAME_ASSERT_TIMING	 BIT(2)
+# define BM_IRDY_ASSERT_TIMING	 BIT(3)
+# define BM_SINGLE_BUS_MASTER	 BIT(4)
+# define MEMRD_CMD0              BIT(5)
+# define SGT_AUTO_PARA_MEMED_CMD BIT(6)
+# define MEMRD_CMD1              BIT(7)
+
+
+#define SREQ_EDGH 0x0e	/* BASE+08, IDX+0e, B, W */
+# define SREQ_EDGH_SELECT BIT(0)
+
+#define UP_CNT		0x0f	/* BASE+08, IDX+0f, B, W */
+#define CFG_CMD_STR      0x10	/* BASE+08, IDX+10, W, R */
+#define CFG_LATE_CACHE   0x11	/* BASE+08, IDX+11, W, R/W */
+#define CFG_BASE_ADR_1   0x12	/* BASE+08, IDX+12, W, R */
+#define CFG_BASE_ADR_2   0x13	/* BASE+08, IDX+13, W, R */
+#define CFG_INLINE       0x14	/* BASE+08, IDX+14, W, R */
+
+#define SERIAL_ROM_CTL	0x15	/* BASE+08, IDX+15, B, R */
+# define SCL 					BIT(0)
+# define ENA					BIT(1)
+# define SDA					BIT(2)
+
+#define FIFO_HST_POINTER	0x16	/* BASE+08, IDX+16, B, R/W */
+#define SREQ_DELAY		0x17	/* BASE+08, IDX+17, B, R/W */
+#define SACK_DELAY		0x18	/* BASE+08, IDX+18, B, R/W */
+#define SREQ_NOISE_CANCEL	0x19	/* BASE+08, IDX+19, B, R/W */
+#define SDP_NOISE_CANCEL	0x1a	/* BASE+08, IDX+1a, B, R/W */
+#define DELAY_TEST		0x1b	/* BASE+08, IDX+1b, B, R/W */
+#define SD0_NOISE_CANCEL	0x20	/* BASE+08, IDX+20, B, R/W */
+#define SD1_NOISE_CANCEL	0x21	/* BASE+08, IDX+21, B, R/W */
+#define SD2_NOISE_CANCEL	0x22	/* BASE+08, IDX+22, B, R/W */
+#define SD3_NOISE_CANCEL	0x23	/* BASE+08, IDX+23, B, R/W */
+#define SD4_NOISE_CANCEL	0x24	/* BASE+08, IDX+24, B, R/W */
+#define SD5_NOISE_CANCEL	0x25	/* BASE+08, IDX+25, B, R/W */
+#define SD6_NOISE_CANCEL	0x26	/* BASE+08, IDX+26, B, R/W */
+#define SD7_NOISE_CANCEL	0x27	/* BASE+08, IDX+27, B, R/W */
+
+
+/*
+ * Useful Bus Monitor status combinations.
+ */
+#define BUSMON_BUS_FREE    0
+#define BUSMON_COMMAND     ( BUSMON_BSY |                          BUSMON_CD | BUSMON_REQ )
+#define BUSMON_MESSAGE_IN  ( BUSMON_BSY | BUSMON_MSG | BUSMON_IO | BUSMON_CD | BUSMON_REQ )
+#define BUSMON_MESSAGE_OUT ( BUSMON_BSY | BUSMON_MSG |             BUSMON_CD | BUSMON_REQ )
+#define BUSMON_DATA_IN     ( BUSMON_BSY |              BUSMON_IO |             BUSMON_REQ )
+#define BUSMON_DATA_OUT    ( BUSMON_BSY |                                      BUSMON_REQ )
+#define BUSMON_STATUS      ( BUSMON_BSY |              BUSMON_IO | BUSMON_CD | BUSMON_REQ )
+#define BUSMON_RESELECT    (                           BUSMON_IO                          | BUSMON_SEL)
+#define BUSMON_PHASE_MASK  (              BUSMON_MSG | BUSMON_IO | BUSMON_CD              | BUSMON_SEL)
+
+#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      ( BUSMON_SEL | BUSMON_IO )
+
+#endif _NSP32_H
+/* end */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/nsp32_debug.c linux-2.4.21-pre6/drivers/scsi/nsp32_debug.c
--- linux-2.4.20/drivers/scsi/nsp32_debug.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/nsp32_debug.c	2003-03-26 23:49:31.000000000 +0000
@@ -0,0 +1,262 @@
+/*
+ * Workbit NinjaSCSI-32Bi/UDE PCI/Cardbus SCSI Host Bus Adapter driver
+ * Debug routine
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License.
+ */
+
+/*
+ * 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;
+	}
+}
+
+static void print_commandk (unsigned char *command)
+{
+	int i,s;
+//	printk(KERN_DEBUG);
+	print_opcodek(command[0]);
+	/*printk(KERN_DEBUG __func__ " ");*/
+	if ((command[0] >> 5) == 6 ||
+	    (command[0] >> 5) == 7 ) {
+		s = 12; /* vender specific */
+	} else {
+		s = COMMAND_SIZE(command[0]);
+	}
+
+	for ( i = 1; i < s; ++i) {
+		printk("%02x ", command[i]);
+	}
+
+	switch (s) {
+	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_busphase(unsigned char stat)
+{
+	switch(stat) {
+	case BUSPHASE_COMMAND:
+		printk( "BUSPHASE_COMMAND\n");
+		break;
+	case BUSPHASE_MESSAGE_IN:
+		printk( "BUSPHASE_MESSAGE_IN\n");
+		break;
+	case BUSPHASE_MESSAGE_OUT:
+		printk( "BUSPHASE_MESSAGE_OUT\n");
+		break;
+	case BUSPHASE_DATA_IN:
+		printk( "BUSPHASE_DATA_IN\n");
+		break;
+	case BUSPHASE_DATA_OUT:
+		printk( "BUSPHASE_DATA_OUT\n");
+		break;
+	case BUSPHASE_STATUS:
+		printk( "BUSPHASE_STATUS\n");
+		break;
+	case BUSPHASE_SELECT:
+		printk( "BUSPHASE_SELECT\n");
+		break;
+	default:
+		printk( "BUSPHASE_other: 0x%x\n", stat);
+		break;
+	}
+}
+
+static void show_autophase(unsigned short i)
+{
+	printk("auto: 0x%x,", i);
+
+	if(i & COMMAND_PHASE) {
+		printk(" cmd");
+	}
+	if(i & DATA_IN_PHASE) {
+		printk(" din");
+	}
+	if(i & DATA_OUT_PHASE) {
+		printk(" dout");
+	}
+	if(i & MSGOUT_PHASE) {
+		printk(" mout");
+	}
+	if(i & STATUS_PHASE) {
+		printk(" stat");
+	}
+	if(i & ILLEGAL_PHASE) {
+		printk(" ill");
+	}
+	if(i & BUS_FREE_OCCUER) {
+		printk(" bfree-o");
+	}
+	if(i & MSG_IN_OCCUER) {
+		printk(" min-o");
+	}
+	if(i & MSG_OUT_OCCUER) {
+		printk(" mout-o");
+	}
+	if(i & SELECTION_TIMEOUT) {
+		printk(" sel");
+	}
+	if(i & MSGIN_00_VALID) {
+		printk(" m0");
+	}
+	if(i & MSGIN_02_VALID) {
+		printk(" m2");
+	}
+	if(i & MSGIN_03_VALID) {
+		printk(" m3");
+	}
+	if(i & MSGIN_04_VALID) {
+		printk(" m4");
+	}
+	if(i & AUTOSCSI_BUSY) {
+		printk(" busy");
+	}
+
+	printk("\n");
+}
+
+static void nsp32_print_register(int base)
+{
+	if (!(NSP32_DEBUG_MASK & NSP32_SPECIAL_PRINT_REGISTER))
+		return;
+
+	printk("Phase=0x%x, ", nsp32_read1(base, SCSI_BUS_MONITOR));
+	printk("OldPhase=0x%x, ", nsp32_index_read1(base, OLD_SCSI_PHASE));
+	printk("syncreg=0x%x, ", nsp32_read1(base, SYNC_REG));
+	printk("ackwidth=0x%x, ", nsp32_read1(base, ACK_WIDTH));
+	printk("sgtpaddr=0x%lx, ", nsp32_read4(base, SGT_ADR));
+	printk("scsioutlatch=0x%x, ", nsp32_read1(base, SCSI_OUT_LATCH_TARGET_ID));
+	printk("msgout=0x%lx, ", nsp32_read4(base, SCSI_MSG_OUT));
+	printk("miscrd=0x%x, ", nsp32_index_read2(base, MISC_WR));
+	printk("seltimeout=0x%x, ", nsp32_read2(base, SEL_TIME_OUT));
+	printk("sreqrate=0x%x, ", nsp32_read1(base, SREQ_SMPL_RATE));
+	printk("transStatus=0x%x, ", nsp32_read2(base, TRANSFER_STATUS));
+	printk("reselectid=0x%x, ", nsp32_read2(base, COMMAND_CONTROL));
+	printk("arbit=0x%x, ", nsp32_read1(base, ARBIT_STATUS));
+	printk("BmStart=0x%lx, ", nsp32_read4(base, BM_START_ADR));
+	printk("BmCount=0x%lx, ", nsp32_read4(base, BM_CNT));
+	printk("SackCnt=0x%lx, ", nsp32_read4(base, SACK_CNT));
+	printk("SReqCnt=0x%lx, ", nsp32_read4(base, SREQ_CNT));
+	printk("SavedSackCnt=0x%lx, ", nsp32_read4(base, SAVED_SACK_CNT));
+	printk("ScsiBusControl=0x%x, ", nsp32_read1(base, SCSI_BUS_CONTROL));
+	printk("FifoRestCnt=0x%x, ", nsp32_read2(base, FIFO_REST_CNT));
+	printk("CdbIn=0x%x, ", nsp32_read1(base, SCSI_CSB_IN));
+	printk("\n");
+
+	if (0) {
+		printk("execph=0x%x, ", nsp32_read2(base, SCSI_EXECUTE_PHASE));
+		printk("IrqStatus=0x%x, ", nsp32_read2(base, IRQ_STATUS));
+		printk("\n");
+	}
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/nsp32_io.h linux-2.4.21-pre6/drivers/scsi/nsp32_io.h
--- linux-2.4.20/drivers/scsi/nsp32_io.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/nsp32_io.h	2003-03-26 23:49:20.000000000 +0000
@@ -0,0 +1,269 @@
+/*
+ * Workbit NinjaSCSI-32Bi/UDE PCI/Cardbus SCSI Host Bus Adapter driver
+ * I/O routine
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License.
+ */
+
+#ifndef _NSP32_IO_H
+#define _NSP32_IO_H
+
+static inline void nsp32_write1(unsigned int  base,
+				unsigned int  index,
+				unsigned char val)
+{
+	outb(val, (base + index));
+}
+
+static inline unsigned char nsp32_read1(unsigned int base,
+					unsigned int index)
+{
+	return inb(base + index);
+}
+
+static inline void nsp32_write2(unsigned int  base,
+				unsigned int  index,
+				unsigned short val)
+{
+	outw(cpu_to_le16(val), (base + index));
+}
+
+static inline unsigned short nsp32_read2(unsigned int base,
+					 unsigned int index)
+{
+	return le16_to_cpu(inw(base + index));
+}
+
+static inline void nsp32_write4(unsigned int  base,
+				unsigned int  index,
+				unsigned long val)
+{
+	outl(cpu_to_le32(val), (base + index));
+}
+
+static inline unsigned long nsp32_read4(unsigned int base,
+					unsigned int index)
+{
+	return le32_to_cpu(inl(base + index));
+}
+
+/*==============================================*/
+
+static inline void nsp32_mmio_write1(unsigned long base,
+				     unsigned int  index,
+				     unsigned char val)
+{
+	volatile unsigned char *ptr;
+
+	ptr = (unsigned char *)(base + NSP32_MMIO_OFFSET + index);
+
+	*ptr = val;
+}
+
+static inline unsigned char nsp32_mmio_read1(unsigned long base,
+					     unsigned int  index)
+{
+	volatile unsigned char *ptr;
+
+	ptr = (unsigned char *)(base + NSP32_MMIO_OFFSET + index);
+
+	return *ptr;
+}
+
+static inline void nsp32_mmio_write2(unsigned long base,
+				     unsigned int  index,
+				     unsigned short val)
+{
+	volatile unsigned short *ptr;
+
+	ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + index);
+
+	*ptr = cpu_to_le16(val);
+}
+
+static inline unsigned short nsp32_mmio_read2(unsigned long base,
+					      unsigned int  index)
+{
+	volatile unsigned short *ptr;
+
+	//printk(__FUNCTION__ "\n");
+
+	ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + index);
+
+	return le16_to_cpu(*ptr);
+}
+
+static inline void nsp32_mmio_write4(unsigned long base,
+				     unsigned int  index,
+				     unsigned long val)
+{
+	volatile unsigned long *ptr;
+
+	ptr = (unsigned long *)(base + NSP32_MMIO_OFFSET + index);
+
+	*ptr = cpu_to_le32(val);
+}
+
+static inline unsigned long nsp32_mmio_read4(unsigned long base,
+					     unsigned int  index)
+{
+	volatile unsigned long *ptr;
+
+	//printk(__FUNCTION__ "\n");
+
+	ptr = (unsigned long *)(base + NSP32_MMIO_OFFSET + index);
+
+	return le32_to_cpu(*ptr);
+}
+
+
+/*=============================================*/
+
+
+static inline unsigned char nsp32_index_read1(unsigned int base,
+					      unsigned int reg)
+{
+	outb(reg, base + INDEX_REG);
+	return inb(base + DATA_REG_LOW);
+}
+
+static inline void nsp32_index_write1(unsigned int  base,
+				      unsigned int  reg,
+				      unsigned char val)
+{
+	outb(reg, base + INDEX_REG);
+	outb(val, base + DATA_REG_LOW);
+}
+
+static inline unsigned short nsp32_index_read2(unsigned int base,
+					       unsigned int reg)
+{
+	outb(reg, base + INDEX_REG);
+	return le16_to_cpu(inw(base + DATA_REG_LOW));
+}
+
+static inline void nsp32_index_write2(unsigned int  base,
+				      unsigned int  reg,
+				      unsigned short val)
+{
+	outb(reg, base + INDEX_REG);
+	outw(cpu_to_le16(val), base + DATA_REG_LOW);
+}
+
+static inline unsigned long nsp32_index_read4(unsigned int base,
+					      unsigned int reg)
+{
+	unsigned long h,l;
+
+	outb(reg, base + INDEX_REG);
+	l = le16_to_cpu(inw(base + DATA_REG_LOW));
+	h = le16_to_cpu(inw(base + DATA_REG_HI ));
+
+	return ((h << 16) | l);
+}
+
+static inline void nsp32_index_write4(unsigned int  base,
+				      unsigned int  reg,
+				      unsigned long val)
+{
+	unsigned long h,l;
+
+	h = (val & 0xffff0000) >> 16;
+	l = (val & 0x0000ffff) >> 0;
+
+	outb(reg, base + INDEX_REG);
+	outw(cpu_to_le16(l), base + DATA_REG_LOW);
+	outw(cpu_to_le16(h), base + DATA_REG_HI);
+}
+
+
+/* ===================================*/
+
+static inline unsigned char nsp32_mmio_index_read1(unsigned int base,
+						   unsigned int reg)
+{
+	volatile unsigned short *index_ptr, *data_ptr;
+
+	index_ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + INDEX_REG);
+	data_ptr  = (unsigned short *)(base + NSP32_MMIO_OFFSET + DATA_REG_LOW);
+
+	*index_ptr = reg;
+
+	return ((*data_ptr) & 0xff);
+}
+
+static inline void nsp32_mmio_index_write1(unsigned int base,
+					   unsigned int reg,
+					   unsigned char val)
+{
+	volatile unsigned short *index_ptr, *data_ptr;
+
+	index_ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + INDEX_REG);
+	data_ptr  = (unsigned short *)(base + NSP32_MMIO_OFFSET + DATA_REG_LOW);
+
+	*index_ptr = reg;
+	*data_ptr  = (unsigned short)val;
+}
+
+static inline unsigned short nsp32_mmio_index_read2(unsigned int base,
+						    unsigned int reg)
+{
+	volatile unsigned short *index_ptr, *data_ptr;
+
+	index_ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + INDEX_REG);
+	data_ptr  = (unsigned short *)(base + NSP32_MMIO_OFFSET + DATA_REG_LOW);
+
+	*index_ptr = reg;
+
+	return le16_to_cpu(*data_ptr);
+}
+
+static inline void nsp32_mmio_index_write2(unsigned int base,
+					   unsigned int reg,
+					   unsigned short val)
+{
+	volatile unsigned short *index_ptr, *data_ptr;
+
+	index_ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + INDEX_REG);
+	data_ptr  = (unsigned short *)(base + NSP32_MMIO_OFFSET + DATA_REG_LOW);
+
+	*index_ptr = reg;
+	*data_ptr  = val;
+}
+
+/*-------------------------------------------------------------------*/
+
+static inline void nsp32_multi_read4(unsigned int   BaseAddr,
+				     unsigned int   Register,
+				     void          *buf,
+				     unsigned long  count)
+{
+	insl(BaseAddr + Register, buf, count);
+}
+
+static inline void nsp32_fifo_read(unsigned int   base,
+				   void          *buf,
+				   unsigned long  count)
+{
+	//DEBUG(0, __FUNCTION__ "() buf=0x%p, count=0x%lx*4\n", buf, count);
+	nsp32_multi_read4(base, FIFO_DATA_LOW, buf, count);
+}
+
+static inline void nsp32_multi_write4(unsigned int   BaseAddr,
+				      unsigned int   Register,
+				      void          *buf,
+				      unsigned long  count)
+{
+	outsl(BaseAddr + Register, buf, count);
+}
+
+static inline void nsp32_fifo_write(unsigned int   base,
+				    void          *buf,
+				    unsigned long  count)
+{
+	nsp32_multi_write4(base, FIFO_DATA_LOW, buf, count);
+}
+
+#endif _NSP32_IO_H
+/* end */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/pcmcia/nsp_cs.c linux-2.4.21-pre6/drivers/scsi/pcmcia/nsp_cs.c
--- linux-2.4.20/drivers/scsi/pcmcia/nsp_cs.c	2001-10-11 16:04:57.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/pcmcia/nsp_cs.c	2003-03-26 23:49:55.000000000 +0000
@@ -707,7 +707,7 @@
 		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 */
+		/* go to next scatter list if available */
 		if (SCpnt->SCp.this_residual	== 0 &&
 		    SCpnt->SCp.buffers_residual != 0 ) {
 			//DEBUG(0, " scatterlist next timeout=%d\n", time_out);
@@ -780,7 +780,7 @@
 		SCpnt->SCp.this_residual -= res;
 		ocount			 += res;
 
-		/* go to next scatter list if availavle */
+		/* go to next scatter list if available */
 		if (SCpnt->SCp.this_residual	== 0 &&
 		    SCpnt->SCp.buffers_residual != 0 ) {
 			//DEBUG(0, " scatterlist next\n");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/scsi_lib.c linux-2.4.21-pre6/drivers/scsi/scsi_lib.c
--- linux-2.4.20/drivers/scsi/scsi_lib.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/scsi_lib.c	2003-03-26 23:49:39.000000000 +0000
@@ -695,6 +695,8 @@
 		 */
 
 		switch (SCpnt->sense_buffer[2]) {
+		case RECOVERED_ERROR: /* Added, KG, 2003-01-20 */
+			return;
 		case ILLEGAL_REQUEST:
 			if (SCpnt->device->ten && SCSI_RETRY_10(SCpnt->cmnd[0])) {
 				SCpnt->device->ten = 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/scsi_proc.c linux-2.4.21-pre6/drivers/scsi/scsi_proc.c
--- linux-2.4.20/drivers/scsi/scsi_proc.c	2001-06-28 00:10:55.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/scsi_proc.c	2003-03-26 23:49:00.000000000 +0000
@@ -308,22 +308,3 @@
 }
 
 #endif				/* CONFIG_PROC_FS */
-
-/*
- * Overrides for Emacs so that we get a uniform tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
- * tab-width: 8
- * End:
- */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/scsi_scan.c linux-2.4.21-pre6/drivers/scsi/scsi_scan.c
--- linux-2.4.20/drivers/scsi/scsi_scan.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/scsi_scan.c	2003-03-26 23:49:51.000000000 +0000
@@ -162,10 +162,10 @@
 	{"DELL", "PV530F",    "*", BLIST_SPARSELUN | BLIST_LARGELUN}, // Dell PV 530F
 	{"EMC", "SYMMETRIX", "*", BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_FORCELUN},
 	{"HP", "A6189A", "*", BLIST_SPARSELUN |  BLIST_LARGELUN}, // HP VA7400, by Alar Aun
-	{"HP", "OPEN-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},			/* HP XP Arrays */
+	{"HP", "OPEN-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},	/* HP XP Arrays */
 	{"CMD", "CRA-7280", "*", BLIST_SPARSELUN | BLIST_LARGELUN},   // CMD RAID Controller
 	{"CNSI", "G7324", "*", BLIST_SPARSELUN | BLIST_LARGELUN},     // Chaparral G7324 RAID
-	{"CNSi", "G8324", "*", BLIST_SPARSELUN},     // Chaparral G8324 RAID
+	{"CNSi", "G8324", "*", BLIST_SPARSELUN | BLIST_LARGELUN},     // Chaparral G8324 RAID
 	{"Zzyzx", "RocketStor 500S", "*", BLIST_SPARSELUN},
 	{"Zzyzx", "RocketStor 2000", "*", BLIST_SPARSELUN},
 	{"SONY", "TSL",       "*", BLIST_FORCELUN},  // DDS3 & DDS4 autoloaders
@@ -173,7 +173,7 @@
 	{"HP", "NetRAID-4M", "*", BLIST_FORCELUN},
 	{"ADAPTEC", "AACRAID", "*", BLIST_FORCELUN},
 	{"ADAPTEC", "Adaptec 5400S", "*", BLIST_FORCELUN},
-	{"COMPAQ", "MSA1000", "*", BLIST_FORCELUN},
+	{"COMPAQ", "MSA1000", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
 	{"HP", "C1557A", "*", BLIST_FORCELUN},
 	{"IBM", "AuSaV1S2", "*", BLIST_FORCELUN},
 	{"FSC", "CentricStor", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
@@ -182,6 +182,11 @@
 	{"HITACHI", "DF500", "*", BLIST_SPARSELUN},
 	{"HITACHI", "DF600", "*", BLIST_SPARSELUN},
 	{"IBM", "ProFibre 4000R", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+	{"HITACHI", "OPEN-", "*", BLIST_SPARSELUN},		/* HITACHI XP Arrays */
+	{"WINSYS","FLASHDISK G6", "*", BLIST_SPARSELUN},
+	{"DotHill","SANnet RAID X300", "*", BLIST_SPARSELUN},	
+	{"SUN", "T300", "*", BLIST_SPARSELUN},
+	{"SUN", "T4", "*", BLIST_SPARSELUN},
 
 	/*
 	 * Must be at end of list...
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/sd.c linux-2.4.21-pre6/drivers/scsi/sd.c
--- linux-2.4.20/drivers/scsi/sd.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/sd.c	2003-03-26 23:49:51.000000000 +0000
@@ -621,9 +621,11 @@
 
 	/* An error occurred */
 	if (driver_byte(result) != 0 && 	/* An error occured */
-	    SCpnt->sense_buffer[0] == 0xF0) {	/* Sense data is valid */
+	    (SCpnt->sense_buffer[0] & 0x7f) == 0x70) {	/* Sense data is valid */
 		switch (SCpnt->sense_buffer[2]) {
 		case MEDIUM_ERROR:
+			if (!(SCpnt->sense_buffer[0] & 0x80))
+				break;
 			error_sector = (SCpnt->sense_buffer[3] << 24) |
 			(SCpnt->sense_buffer[4] << 16) |
 			(SCpnt->sense_buffer[5] << 8) |
@@ -668,7 +670,7 @@
 			 * hard error.
 			 */
 			print_sense("sd", SCpnt);
-			result = 0;
+			SCpnt->result = 0;
 			SCpnt->sense_buffer[0] = 0x0;
 			good_sectors = this_count;
 			break;
@@ -1439,16 +1441,14 @@
 		kfree(sd_blocksizes);
 		kfree(sd_hardsizes);
 		for (i = 0; i < N_USED_SD_MAJORS; i++) {
-#if 0 /* XXX aren't we forgetting to deallocate something? */
 			kfree(sd_gendisks[i].de_arr);
 			kfree(sd_gendisks[i].flags);
-#endif
 			kfree(sd_gendisks[i].part);
 		}
 	}
 	for (i = 0; i < N_USED_SD_MAJORS; i++) {
 		del_gendisk(&sd_gendisks[i]);
-		blk_size[SD_MAJOR(i)] = NULL;	/* XXX blksize_size actually? */
+		blksize_size[SD_MAJOR(i)] = NULL;
 		hardsect_size[SD_MAJOR(i)] = NULL;
 		read_ahead[SD_MAJOR(i)] = 0;
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/sim710.h linux-2.4.21-pre6/drivers/scsi/sim710.h
--- linux-2.4.20/drivers/scsi/sim710.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/sim710.h	2003-03-26 23:49:39.000000000 +0000
@@ -14,7 +14,6 @@
 int sim710_bus_reset(Scsi_Cmnd * SCpnt);
 int sim710_dev_reset(Scsi_Cmnd * SCpnt);
 int sim710_host_reset(Scsi_Cmnd * SCpnt);
-int sim710_biosparam(Disk *, kdev_t, int*);
 #ifdef MODULE
 int sim710_release(struct Scsi_Host *);
 #else
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/sr.c linux-2.4.21-pre6/drivers/scsi/sr.c
--- linux-2.4.20/drivers/scsi/sr.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/sr.c	2003-03-26 23:49:19.000000000 +0000
@@ -211,11 +211,13 @@
 
 
 	if (driver_byte(result) != 0 &&		/* An error occurred */
-	    SCpnt->sense_buffer[0] == 0xF0) {	/* Sense data is valid */
+	    (SCpnt->sense_buffer[0] & 0x7f) == 0x70) {	/* Sense data is valid */
 		switch (SCpnt->sense_buffer[2]) {
 		case MEDIUM_ERROR:
 		case VOLUME_OVERFLOW:
 		case ILLEGAL_REQUEST:
+			if (!(SCpnt->sense_buffer[0] & 0x80))
+				break;
 			error_sector = (SCpnt->sense_buffer[3] << 24) |
 			(SCpnt->sense_buffer[4] << 16) |
 			(SCpnt->sense_buffer[5] << 8) |
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/sun3_NCR5380.c linux-2.4.21-pre6/drivers/scsi/sun3_NCR5380.c
--- linux-2.4.20/drivers/scsi/sun3_NCR5380.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/sun3_NCR5380.c	2003-03-26 23:49:06.000000000 +0000
@@ -754,11 +754,8 @@
 static
 char *lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length);
 
-#ifndef NCR5380_proc_info
-static
-#endif
-int NCR5380_proc_info (char *buffer, char **start, off_t offset,
-		       int length, int hostno, int inout)
+static int NCR5380_proc_info (char *buffer, char **start, off_t offset,
+			      int length, int hostno, int inout)
 {
     char *pos = buffer;
     struct Scsi_Host *instance;
@@ -913,10 +910,7 @@
  */
 
 /* Only make static if a wrapper function is used */
-#ifndef NCR5380_queue_command
-static
-#endif
-int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+static int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
 {
     SETUP_HOSTDATA(cmd->host);
     Scsi_Cmnd *tmp;
@@ -1226,8 +1220,8 @@
 					    BASR_ACK)) ==
        (BASR_PHASE_MATCH | BASR_ACK)) {
 	    printk("scsi%d: BASR %02x\n", HOSTNO, NCR5380_read(BUS_AND_STATUS_REG));
-	    printk("scsi%d: bus stuck in data phase -- probably a
- single byte overrun!\n", HOSTNO); 
+	    printk("scsi%d: bus stuck in data phase -- probably a single byte "
+		   "overrun!\n", HOSTNO);
 	    printk("not prepared for this error!\n");
 	    printk("please e-mail sammy@sammy.net with a description of how this\n");
 	    printk("error was produced.\n");
@@ -1318,11 +1312,14 @@
 	    {
 /* MS: Ignore unknown phase mismatch interrupts (caused by EOP interrupt) */
 		if (basr & BASR_PHASE_MATCH)
-		    printk(KERN_NOTICE "scsi%d: unknown interrupt, "
+		   INT_PRINTK("scsi%d: unknown interrupt, "
 			   "BASR 0x%x, MR 0x%x, SR 0x%x\n",
 			   HOSTNO, basr, NCR5380_read(MODE_REG),
 			   NCR5380_read(STATUS_REG));
 		(void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+#ifdef SUN3_SCSI_VME
+		dregs->csr |= CSR_DMA_ENABLE;
+#endif
 	    }
 	} /* if !(SELECTION || PARITY) */
     } /* BASR & IRQ */
@@ -1332,6 +1329,9 @@
 	       "BASR 0x%X, MR 0x%X, SR 0x%x\n", HOSTNO, basr,
 	       NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG));
 	(void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+#ifdef SUN3_SCSI_VME
+		dregs->csr |= CSR_DMA_ENABLE;
+#endif
     }
     
     if (!done) {
@@ -1694,7 +1694,9 @@
 #ifndef SUPPORT_TAGS
     hostdata->busy[cmd->target] |= (1 << cmd->lun);
 #endif    
-
+#ifdef SUN3_SCSI_VME
+    dregs->csr |= CSR_INTR;
+#endif
     initialize_SCp(cmd);
 
 
@@ -1921,19 +1923,18 @@
 	 printk("scsi%d: transfer_dma without setup!\n", HOSTNO);
 	 BUG();
     }
-
     hostdata->dma_len = c;
 
     DMA_PRINTK("scsi%d: initializing DMA for %s, %d bytes %s %p\n",
 	       HOSTNO, (p & SR_IO) ? "reading" : "writing",
-	       c, (p & SR_IO) ? "to" : "from", d);
+	       c, (p & SR_IO) ? "to" : "from", *data);
 
     /* netbsd turns off ints here, why not be safe and do it too */
     save_flags(flags);
     cli();
     
     /* send start chain */
-    sun3_udc_write(UDC_CHN_START, UDC_CSR);
+    sun3scsi_dma_start(c, *data);
     
     if (p & SR_IO) {
 	    NCR5380_write(TARGET_COMMAND_REG, 1);
@@ -1949,6 +1950,10 @@
 	    NCR5380_write(START_DMA_SEND_REG, 0);
     }
 
+#ifdef SUN3_SCSI_VME
+    dregs->csr |= CSR_DMA_ENABLE;
+#endif
+
     restore_flags(flags);
 
     sun3_dma_active = 1;
@@ -1987,6 +1992,10 @@
     unsigned char phase, tmp, extended_msg[10], old_phase=0xff;
     Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected;
 
+#ifdef SUN3_SCSI_VME
+    dregs->csr |= CSR_INTR;
+#endif
+
     while (1) {
 	tmp = NCR5380_read(STATUS_REG);
 	/* We only have a valid SCSI phase when REQ is asserted */
@@ -2020,6 +2029,9 @@
 			}
 		}
 #endif
+#ifdef SUN3_SCSI_VME
+		dregs->csr |= CSR_INTR;
+#endif
 	    }
 
 	    
@@ -2341,6 +2353,9 @@
 		    /* Wait for bus free to avoid nasty timeouts */
 		    while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
 		    	barrier();
+#ifdef SUN3_SCSI_VME
+		    dregs->csr |= CSR_DMA_ENABLE;
+#endif
 		    return;
 		/* 
 		 * The SCSI data pointer is *IMPLICITLY* saved on a disconnect
@@ -2678,10 +2693,7 @@
  * 	 called where the loop started in NCR5380_main().
  */
 
-#ifndef NCR5380_abort
-static
-#endif
-int NCR5380_abort (Scsi_Cmnd *cmd)
+static int NCR5380_abort (Scsi_Cmnd *cmd)
 {
     struct Scsi_Host *instance = cmd->host;
     SETUP_HOSTDATA(instance);
@@ -2875,7 +2887,7 @@
  *
  */ 
 
-int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags)
+static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags)
 {
     SETUP_HOSTDATA(cmd->host);
     int           i;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/sun3_scsi.c linux-2.4.21-pre6/drivers/scsi/sun3_scsi.c
--- linux-2.4.20/drivers/scsi/sun3_scsi.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/sun3_scsi.c	2003-03-26 23:49:02.000000000 +0000
@@ -1,7 +1,7 @@
 /*
  * Sun3 SCSI stuff by Erik Verbruggen (erik@bigmama.xtdnet.nl)
  *
- * Sun3 DMA routines added by Sam Creasey (sammy@oh.verio.com)
+ * Sun3 DMA routines added by Sam Creasey (sammy@sammy.net)
  *
  * Adapted from mac_scsinew.c:
  */
@@ -192,8 +192,7 @@
  
 int sun3scsi_detect(Scsi_Host_Template * tpnt)
 {
-	unsigned long ioaddr, iopte;
-	int count = 0;
+	unsigned long ioaddr;
 	static int called = 0;
 	struct Scsi_Host *instance;
 
@@ -227,28 +226,9 @@
 		tpnt->this_id = 7;
 	}
 
-	/* Taken from Sammy's lance driver: */
-        /* IOBASE_SUN3_SCSI can be found within the IO pmeg with some effort */
-        for(ioaddr = 0xfe00000; ioaddr < (0xfe00000 + SUN3_PMEG_SIZE);
-            ioaddr += SUN3_PTE_SIZE) {
-
-                iopte = sun3_get_pte(ioaddr);
-                if(!(iopte & SUN3_PAGE_TYPE_IO)) /* this an io page? */
-                        continue;
-
-                if(((iopte & SUN3_PAGE_PGNUM_MASK) << PAGE_SHIFT) ==
-                   IOBASE_SUN3_SCSI) {
-                        count = 1;
-                        break;
-                }
-        }
-
-	if(!count) {
-		printk("No Sun3 NCR5380 found!\n");
-		return 0;
-	}
-
+	ioaddr = (unsigned long)ioremap(IOBASE_SUN3_SCSI, PAGE_SIZE);
 	sun3_scsi_regp = (unsigned char *)ioaddr;
+
 	dregs = (struct sun3_dma_regs *)(((unsigned char *)ioaddr) + 8);
 
 	if((udc_regs = dvma_malloc(sizeof(struct sun3_udc_regs)))
@@ -322,13 +302,17 @@
 	return 1;
 }
 
+#ifdef MODULE
 int sun3scsi_release (struct Scsi_Host *shpnt)
 {
 	if (shpnt->irq != IRQ_NONE)
 		free_irq (shpnt->irq, NULL);
 
+	iounmap((void *)sun3_scsi_regp);
+
 	return 0;
 }
+#endif
 
 #ifdef RESET_BOOT
 /*
@@ -537,6 +521,14 @@
 		return 0;
 }
 
+static inline int sun3scsi_dma_start(unsigned long count, unsigned char *data)
+{
+
+    sun3_udc_write(UDC_CHN_START, UDC_CSR);
+    
+    return 0;
+}
+
 /* clean up after our dma is done */
 static int sun3scsi_dma_finish(int write_flag)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/sun3_scsi.h linux-2.4.21-pre6/drivers/scsi/sun3_scsi.h
--- linux-2.4.20/drivers/scsi/sun3_scsi.h	2000-02-13 19:21:42.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/sun3_scsi.h	2003-03-26 23:49:00.000000000 +0000
@@ -1,7 +1,7 @@
 /*
  * Sun3 SCSI stuff by Erik Verbruggen (erik@bigmama.xtdnet.nl)
  *
- * Sun3 DMA additions by Sam Creasey (sammy@oh.verio.com)
+ * Sun3 DMA additions by Sam Creasey (sammy@sammy.net)
  *
  * Adapted from mac_scsinew.h:
  */
@@ -36,6 +36,11 @@
 #ifndef SUN3_NCR5380_H
 #define SUN3_NCR5380_H
 
+#ifndef NULL
+#define NULL 0
+#endif
+
+
 #define SUN3SCSI_PUBLIC_RELEASE 1
 
 /*
@@ -45,17 +50,19 @@
 #define IRQ_SUN3_SCSI 2
 #define IOBASE_SUN3_SCSI 0x00140000
 
-int sun3scsi_abort (Scsi_Cmnd *);
-int sun3scsi_detect (Scsi_Host_Template *);
-int sun3scsi_release (struct Scsi_Host *);
-const char *sun3scsi_info (struct Scsi_Host *);
-int sun3scsi_reset(Scsi_Cmnd *, unsigned int);
-int sun3scsi_queue_command (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-int sun3scsi_proc_info (char *buffer, char **start, off_t offset,
-			int length, int hostno, int inout);
+#define IOBASE_SUN3_VMESCSI 0xff200000
 
-#ifndef NULL
-#define NULL 0
+static int sun3scsi_abort (Scsi_Cmnd *);
+static int sun3scsi_detect (Scsi_Host_Template *);
+static const char *sun3scsi_info (struct Scsi_Host *);
+static int sun3scsi_reset(Scsi_Cmnd *, unsigned int);
+static int sun3scsi_queue_command (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+static int sun3scsi_proc_info (char *buffer, char **start, off_t offset,
+			int length, int hostno, int inout);
+#ifdef MODULE
+static int sun3scsi_release (struct Scsi_Host *);
+#else
+#define sun3scsi_release NULL
 #endif
 
 #ifndef CMD_PER_LUN
@@ -70,27 +77,36 @@
 #define SG_TABLESIZE SG_NONE
 #endif
 
+#ifndef MAX_TAGS
+#define MAX_TAGS 32
+#endif
+
 #ifndef USE_TAGGED_QUEUING
-#define	USE_TAGGED_QUEUING 0
+#define	USE_TAGGED_QUEUING 1
 #endif
 
 #include <scsi/scsicam.h>
 
+#ifdef SUN3_SCSI_VME
+#define SUN3_SCSI_NAME "Sun3 NCR5380 VME SCSI"
+#else
+#define SUN3_SCSI_NAME "Sun3 NCR5380 SCSI"
+#endif
+
 #define SUN3_NCR5380 {							\
-name:			"Sun3 NCR5380 SCSI",				\
-detect:			sun3scsi_detect,				\
-release:		sun3scsi_release,	/* Release */		\
-info:			sun3scsi_info,					\
-queuecommand:		sun3scsi_queue_command,				\
-abort:			sun3scsi_abort,			 		\
-reset:			sun3scsi_reset,					\
-bios_param:		scsicam_bios_param,	/* biosparam */		\
-can_queue:		CAN_QUEUE,		/* can queue */		\
-this_id:		7,			/* id */		\
-sg_tablesize:		SG_ALL,			/* sg_tablesize */	\
-cmd_per_lun:		CMD_PER_LUN,		/* cmd per lun */	\
-unchecked_isa_dma:	0,			/* unchecked_isa_dma */	\
-use_clustering:		DISABLE_CLUSTERING				\
+.name =			SUN3_SCSI_NAME,					\
+.detect =		sun3scsi_detect,				\
+.release =		sun3scsi_release,	/* Release */		\
+.info =			sun3scsi_info,					\
+.queuecommand =		sun3scsi_queue_command,				\
+.abort =		sun3scsi_abort,					\
+.reset =		sun3scsi_reset,					\
+.can_queue =		CAN_QUEUE,		/* can queue */		\
+.this_id =		7,			/* id */		\
+.sg_tablesize =		SG_TABLESIZE,		/* sg_tablesize */	\
+.cmd_per_lun =		CMD_PER_LUN,		/* cmd per lun */	\
+.unchecked_isa_dma =	0,			/* unchecked_isa_dma */	\
+.use_clustering =	DISABLE_CLUSTERING				\
 	}
 
 #ifndef HOSTS_C
@@ -125,13 +141,20 @@
 /* additional registers - mainly DMA control regs */
 /* these start at regbase + 8 -- directly after the NCR regs */
 struct sun3_dma_regs {
-	unsigned short vmeregs[4];  /* unimpl vme stuff */
-	unsigned short udc_data; /* udc dma data reg */
-	unsigned short udc_addr; /* uda dma addr reg */
+	unsigned short dma_addr_hi; /* vme only */
+	unsigned short dma_addr_lo; /* vme only */
+	unsigned short dma_count_hi; /* vme only */
+	unsigned short dma_count_lo; /* vme only */
+	unsigned short udc_data; /* udc dma data reg (obio only) */
+	unsigned short udc_addr; /* uda dma addr reg (obio only) */
 	unsigned short fifo_data; /* fifo data reg, holds extra byte on
 				     odd dma reads */
 	unsigned short fifo_count; 
 	unsigned short csr; /* control/status reg */
+	unsigned short bpack_hi; /* vme only */
+	unsigned short bpack_lo; /* vme only */
+	unsigned short ivect; /* vme only */
+	unsigned short fifo_count_hi; /* vme only */
 };
 
 /* ucd chip specific regs - live in dvma space */
@@ -180,11 +203,21 @@
 #define CSR_SDB_INT 0x200 /* sbc interrupt pending */
 #define CSR_DMA_INT 0x100 /* dma interrupt pending */
 
+#define CSR_LEFT 0xc0
+#define CSR_LEFT_3 0xc0
+#define CSR_LEFT_2 0x80
+#define CSR_LEFT_1 0x40
+#define CSR_PACK_ENABLE 0x20
+
+#define CSR_DMA_ENABLE 0x10
+
 #define CSR_SEND 0x8 /* 1 = send  0 = recv */
 #define CSR_FIFO 0x2 /* reset fifo */
 #define CSR_INTR 0x4 /* interrupt enable */
 #define CSR_SCSI 0x1 
 
+#define VME_DATA24 0x3d00
+
 // debugging printk's, taken from atari_scsi.h 
 /* Debugging printk definitions:
  *
@@ -366,8 +399,6 @@
 #define NCR_PRINT_STATUS(mask) \
 	((NDEBUG & (mask)) ? NCR5380_print_status(instance) : (void)0)
 
-#define NDEBUG_ANY	0xffffffff
-
 
 
 #endif /* ndef HOSTS_C */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/sun3_scsi_vme.c linux-2.4.21-pre6/drivers/scsi/sun3_scsi_vme.c
--- linux-2.4.20/drivers/scsi/sun3_scsi_vme.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/sun3_scsi_vme.c	2003-03-26 23:49:10.000000000 +0000
@@ -0,0 +1,568 @@
+/*
+ * Sun3 SCSI stuff by Erik Verbruggen (erik@bigmama.xtdnet.nl)
+ *
+ * Sun3 DMA routines added by Sam Creasey (sammy@sammy.net)
+ *
+ * VME support added by Sam Creasey
+ *
+ * Adapted from sun3_scsi.c -- see there for other headers
+ *
+ * TODO: modify this driver to support multiple Sun3 SCSI VME boards
+ *
+ */
+
+#define AUTOSENSE
+
+#include <linux/types.h>
+#include <linux/stddef.h>
+#include <linux/ctype.h>
+#include <linux/delay.h>
+
+#include <linux/module.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/blk.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <asm/sun3ints.h>
+#include <asm/dvma.h>
+#include <asm/idprom.h>
+#include <asm/machines.h>
+
+#define SUN3_SCSI_VME
+
+#undef SUN3_SCSI_DEBUG
+
+/* dma on! */
+#define REAL_DMA
+
+#include "scsi.h"
+#include "hosts.h"
+#include "sun3_scsi.h"
+#include "NCR5380.h"
+#include "constants.h"
+
+extern int sun3_map_test(unsigned long, char *);
+
+#define USE_WRAPPER
+/*#define RESET_BOOT */
+#define DRIVER_SETUP
+
+#define NDEBUG 0
+
+/*
+ * BUG can be used to trigger a strange code-size related hang on 2.1 kernels
+ */
+#ifdef BUG
+#undef RESET_BOOT
+#undef DRIVER_SETUP
+#endif
+
+/* #define SUPPORT_TAGS */
+
+//#define	ENABLE_IRQ()	enable_irq( SUN3_VEC_VMESCSI0 ); 
+#define ENABLE_IRQ()
+
+
+static void scsi_sun3_intr(int irq, void *dummy, struct pt_regs *fp);
+static inline unsigned char sun3scsi_read(int reg);
+static inline void sun3scsi_write(int reg, int value);
+
+static int setup_can_queue = -1;
+MODULE_PARM(setup_can_queue, "i");
+static int setup_cmd_per_lun = -1;
+MODULE_PARM(setup_cmd_per_lun, "i");
+static int setup_sg_tablesize = -1;
+MODULE_PARM(setup_sg_tablesize, "i");
+#ifdef SUPPORT_TAGS
+static int setup_use_tagged_queuing = -1;
+MODULE_PARM(setup_use_tagged_queuing, "i");
+#endif
+static int setup_hostid = -1;
+MODULE_PARM(setup_hostid, "i");
+
+static Scsi_Cmnd *sun3_dma_setup_done = NULL;
+
+#define	AFTER_RESET_DELAY	(HZ/2)
+
+/* ms to wait after hitting dma regs */
+#define SUN3_DMA_DELAY 10
+
+/* dvma buffer to allocate -- 32k should hopefully be more than sufficient */
+#define SUN3_DVMA_BUFSIZE 0xe000
+
+/* minimum number of bytes to do dma on */
+#define SUN3_DMA_MINSIZE 128
+
+static volatile unsigned char *sun3_scsi_regp;
+static volatile struct sun3_dma_regs *dregs;
+#ifdef OLDDMA
+static unsigned char *dmabuf = NULL; /* dma memory buffer */
+#endif
+static unsigned char *sun3_dma_orig_addr = NULL;
+static unsigned long sun3_dma_orig_count = 0;
+static int sun3_dma_active = 0;
+static unsigned long last_residual = 0;
+
+/*
+ * NCR 5380 register access functions
+ */
+
+static inline unsigned char sun3scsi_read(int reg)
+{
+	return( sun3_scsi_regp[reg] );
+}
+
+static inline void sun3scsi_write(int reg, int value)
+{
+	sun3_scsi_regp[reg] = value;
+}
+
+/*
+ * XXX: status debug
+ */
+static struct Scsi_Host *default_instance;
+
+/*
+ * Function : int sun3scsi_detect(Scsi_Host_Template * tpnt)
+ *
+ * Purpose : initializes mac NCR5380 driver based on the
+ *	command line / compile time port and irq definitions.
+ *
+ * Inputs : tpnt - template for this SCSI adapter.
+ *
+ * Returns : 1 if a host adapter was found, 0 if not.
+ *
+ */
+ 
+static int sun3scsi_detect(Scsi_Host_Template * tpnt)
+{
+	unsigned long ioaddr, irq;
+	static int called = 0;
+	struct Scsi_Host *instance;
+	int i;
+	unsigned long addrs[3] = { IOBASE_SUN3_VMESCSI, 
+				   IOBASE_SUN3_VMESCSI + 0x4000,
+				   0 };
+	unsigned long vecs[3] = { SUN3_VEC_VMESCSI0,
+				  SUN3_VEC_VMESCSI1,
+				  0 };
+	/* check that this machine has an onboard 5380 */
+	switch(idprom->id_machtype) {
+	case SM_SUN3|SM_3_160:
+	case SM_SUN3|SM_3_260:
+		break;
+
+	default:
+		return 0;
+	}
+
+	if(called)
+		return 0;
+
+	tpnt->proc_name = "Sun3 5380 VME SCSI";
+
+	/* setup variables */
+	tpnt->can_queue =
+		(setup_can_queue > 0) ? setup_can_queue : CAN_QUEUE;
+	tpnt->cmd_per_lun =
+		(setup_cmd_per_lun > 0) ? setup_cmd_per_lun : CMD_PER_LUN;
+	tpnt->sg_tablesize = 
+		(setup_sg_tablesize >= 0) ? setup_sg_tablesize : SG_TABLESIZE;
+	
+	if (setup_hostid >= 0)
+		tpnt->this_id = setup_hostid;
+	else {
+		/* use 7 as default */
+		tpnt->this_id = 7;
+	}
+	
+	ioaddr = 0;
+	for(i = 0; addrs[i] != 0; i++) {
+		unsigned char x;
+		
+		ioaddr = (unsigned long)sun3_ioremap(addrs[i], PAGE_SIZE,
+						     SUN3_PAGE_TYPE_VME16);
+		irq = vecs[i];
+		sun3_scsi_regp = (unsigned char *)ioaddr;
+		
+		dregs = (struct sun3_dma_regs *)(((unsigned char *)ioaddr) + 8);
+		
+		if(sun3_map_test((unsigned long)dregs, &x)) {
+			unsigned short oldcsr;
+
+			oldcsr = dregs->csr;
+			dregs->csr = 0;
+			udelay(SUN3_DMA_DELAY);
+			if(dregs->csr == 0x1400)
+				break;
+			
+			dregs->csr = oldcsr;
+		}
+
+		iounmap((void *)ioaddr);
+		ioaddr = 0;
+	}
+
+	if(!ioaddr)
+		return 0;
+	
+#ifdef SUPPORT_TAGS
+	if (setup_use_tagged_queuing < 0)
+		setup_use_tagged_queuing = USE_TAGGED_QUEUING;
+#endif
+
+	instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
+	if(instance == NULL)
+		return 0;
+		
+	default_instance = instance;
+
+        instance->io_port = (unsigned long) ioaddr;
+	instance->irq = irq;
+
+	NCR5380_init(instance, 0);
+
+	instance->n_io_port = 32;
+
+        ((struct NCR5380_hostdata *)instance->hostdata)->ctrl = 0;
+
+	if (request_irq(instance->irq, scsi_sun3_intr,
+			     0, "Sun3SCSI-5380VME", NULL)) {
+#ifndef REAL_DMA
+		printk("scsi%d: IRQ%d not free, interrupts disabled\n",
+		       instance->host_no, instance->irq);
+		instance->irq = IRQ_NONE;
+#else
+		printk("scsi%d: IRQ%d not free, bailing out\n",
+		       instance->host_no, instance->irq);
+		return 0;
+#endif
+	}
+
+	printk("scsi%d: Sun3 5380 VME at port %lX irq", instance->host_no, instance->io_port);
+	if (instance->irq == IRQ_NONE)
+		printk ("s disabled");
+	else
+		printk (" %d", instance->irq);
+	printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
+	       instance->can_queue, instance->cmd_per_lun,
+	       SUN3SCSI_PUBLIC_RELEASE);
+	printk("\nscsi%d:", instance->host_no);
+	NCR5380_print_options(instance);
+	printk("\n");
+
+	dregs->csr = 0;
+	udelay(SUN3_DMA_DELAY);
+	dregs->csr = CSR_SCSI | CSR_FIFO | CSR_INTR;
+	udelay(SUN3_DMA_DELAY);
+	dregs->fifo_count = 0;
+	dregs->fifo_count_hi = 0;
+	dregs->dma_addr_hi = 0;
+	dregs->dma_addr_lo = 0;
+	dregs->dma_count_hi = 0;
+	dregs->dma_count_lo = 0;
+
+	dregs->ivect = VME_DATA24 | (instance->irq & 0xff);
+
+	called = 1;
+
+#ifdef RESET_BOOT
+	sun3_scsi_reset_boot(instance);
+#endif
+
+	return 1;
+}
+
+#ifdef MODULE
+int sun3scsi_release (struct Scsi_Host *shpnt)
+{
+	if (shpnt->irq != IRQ_NONE)
+		free_irq (shpnt->irq, NULL);
+
+	iounmap(sun3_scsi_regp);
+
+	return 0;
+}
+#endif
+
+#ifdef RESET_BOOT
+/*
+ * Our 'bus reset on boot' function
+ */
+
+static void sun3_scsi_reset_boot(struct Scsi_Host *instance)
+{
+	unsigned long end;
+
+	NCR5380_local_declare();
+	NCR5380_setup(instance);
+	
+	/*
+	 * Do a SCSI reset to clean up the bus during initialization. No
+	 * messing with the queues, interrupts, or locks necessary here.
+	 */
+
+	printk( "Sun3 SCSI: resetting the SCSI bus..." );
+
+	/* switch off SCSI IRQ - catch an interrupt without IRQ bit set else */
+//       	sun3_disable_irq( IRQ_SUN3_SCSI );
+
+	/* get in phase */
+	NCR5380_write( TARGET_COMMAND_REG,
+		      PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) ));
+
+	/* assert RST */
+	NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST );
+
+	/* The min. reset hold time is 25us, so 40us should be enough */
+	udelay( 50 );
+
+	/* reset RST and interrupt */
+	NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
+	NCR5380_read( RESET_PARITY_INTERRUPT_REG );
+
+	for( end = jiffies + AFTER_RESET_DELAY; time_before(jiffies, end); )
+		barrier();
+
+	/* switch on SCSI IRQ again */
+//       	sun3_enable_irq( IRQ_SUN3_SCSI );
+
+	printk( " done\n" );
+}
+#endif
+
+static const char * sun3scsi_info (struct Scsi_Host *spnt) {
+    return "";
+}
+
+// safe bits for the CSR
+#define CSR_GOOD 0x060f
+
+static void scsi_sun3_intr(int irq, void *dummy, struct pt_regs *fp)
+{
+	unsigned short csr = dregs->csr;
+
+	dregs->csr &= ~CSR_DMA_ENABLE;
+
+
+#ifdef SUN3_SCSI_DEBUG
+	printk("scsi_intr csr %x\n", csr);
+#endif
+
+	if(csr & ~CSR_GOOD) {
+		if(csr & CSR_DMA_BUSERR) {
+			printk("scsi%d: bus error in dma\n", default_instance->host_no);
+#ifdef SUN3_SCSI_DEBUG
+			printk("scsi: residual %x count %x addr %p dmaaddr %x\n", 
+			       dregs->fifo_count,
+			       dregs->dma_count_lo | (dregs->dma_count_hi << 16),
+			       sun3_dma_orig_addr,
+			       dregs->dma_addr_lo | (dregs->dma_addr_hi << 16));
+#endif
+		}
+
+		if(csr & CSR_DMA_CONFLICT) {
+			printk("scsi%d: dma conflict\n", default_instance->host_no);
+		}
+	}
+
+	if(csr & (CSR_SDB_INT | CSR_DMA_INT))
+		NCR5380_intr(irq, dummy, fp);
+}
+
+/*
+ * Debug stuff - to be called on NMI, or sysrq key. Use at your own risk; 
+ * reentering NCR5380_print_status seems to have ugly side effects
+ */
+
+/* this doesn't seem to get used at all -- sam */
+#if 0
+void sun3_sun3_debug (void)
+{
+	unsigned long flags;
+	NCR5380_local_declare();
+
+	if (default_instance) {
+			save_flags(flags);
+			cli();
+			NCR5380_print_status(default_instance);
+			restore_flags(flags);
+	}
+}
+#endif
+
+
+/* sun3scsi_dma_setup() -- initialize the dma controller for a read/write */
+static unsigned long sun3scsi_dma_setup(void *data, unsigned long count, int write_flag)
+{
+	void *addr;
+
+	if(sun3_dma_orig_addr != NULL)
+		dvma_unmap(sun3_dma_orig_addr);
+
+//	addr = sun3_dvma_page((unsigned long)data, (unsigned long)dmabuf);
+	addr = (void *)dvma_map_vme((unsigned long) data, count);
+		
+	sun3_dma_orig_addr = addr;
+	sun3_dma_orig_count = count;
+	
+#ifdef SUN3_SCSI_DEBUG
+	printk("scsi: dma_setup addr %p count %x\n", addr, count);
+#endif
+
+//	dregs->fifo_count = 0;
+#if 0	
+	/* reset fifo */
+	dregs->csr &= ~CSR_FIFO;
+	dregs->csr |= CSR_FIFO;
+#endif	
+	/* set direction */
+	if(write_flag)
+		dregs->csr |= CSR_SEND;
+	else
+		dregs->csr &= ~CSR_SEND;
+	
+	/* reset fifo */
+//	dregs->csr &= ~CSR_FIFO;
+//	dregs->csr |= CSR_FIFO;
+
+	dregs->csr |= CSR_PACK_ENABLE;
+
+	dregs->dma_addr_hi = ((unsigned long)addr >> 16);
+	dregs->dma_addr_lo = ((unsigned long)addr & 0xffff);
+	
+	dregs->dma_count_hi = 0;
+	dregs->dma_count_lo = 0;
+	dregs->fifo_count_hi = 0;
+	dregs->fifo_count = 0;
+		
+#ifdef SUN3_SCSI_DEBUG
+	printk("scsi: dma_setup done csr %x\n", dregs->csr);
+#endif
+       	return count;
+
+}
+
+static inline unsigned long sun3scsi_dma_residual(struct Scsi_Host *instance)
+{
+	return last_residual;
+}
+
+static inline unsigned long sun3scsi_dma_xfer_len(unsigned long wanted, Scsi_Cmnd *cmd,
+				    int write_flag)
+{
+	if((cmd->request.cmd == 0) || (cmd->request.cmd == 1))
+ 		return wanted;
+	else
+		return 0;
+}
+
+static int sun3scsi_dma_start(unsigned long count, char *data)
+{
+	
+	unsigned short csr;
+
+	csr = dregs->csr;
+#ifdef SUN3_SCSI_DEBUG
+	printk("scsi: dma_start data %p count %x csr %x fifo %x\n", data, count, csr, dregs->fifo_count);
+#endif
+	
+	dregs->dma_count_hi = (sun3_dma_orig_count >> 16);
+	dregs->dma_count_lo = (sun3_dma_orig_count & 0xffff);
+
+	dregs->fifo_count_hi = (sun3_dma_orig_count >> 16);
+	dregs->fifo_count = (sun3_dma_orig_count & 0xffff);
+
+//	if(!(csr & CSR_DMA_ENABLE))
+//		dregs->csr |= CSR_DMA_ENABLE;
+
+	return 0;
+}
+
+/* clean up after our dma is done */
+static int sun3scsi_dma_finish(int write_flag)
+{
+	unsigned short fifo;
+	int ret = 0;
+	
+	sun3_dma_active = 0;
+
+	dregs->csr &= ~CSR_DMA_ENABLE;
+	
+	fifo = dregs->fifo_count;
+	if(write_flag) {
+		if((fifo > 0) && (fifo < sun3_dma_orig_count))
+			fifo++;
+	}
+
+	last_residual = fifo;
+#ifdef SUN3_SCSI_DEBUG
+	printk("scsi: residual %x total %x\n", fifo, sun3_dma_orig_count);
+#endif
+	/* empty bytes from the fifo which didn't make it */
+	if((!write_flag) && (dregs->csr & CSR_LEFT)) {
+		unsigned char *vaddr;
+
+#ifdef SUN3_SCSI_DEBUG
+		printk("scsi: got left over bytes\n");
+#endif
+
+		vaddr = (unsigned char *)dvma_vmetov(sun3_dma_orig_addr);
+		
+		vaddr += (sun3_dma_orig_count - fifo);
+		vaddr--;
+		
+		switch(dregs->csr & CSR_LEFT) {
+		case CSR_LEFT_3:
+			*vaddr = (dregs->bpack_lo & 0xff00) >> 8;
+			vaddr--;
+			
+		case CSR_LEFT_2:
+			*vaddr = (dregs->bpack_hi & 0x00ff);
+			vaddr--;
+			
+		case CSR_LEFT_1:
+			*vaddr = (dregs->bpack_hi & 0xff00) >> 8;
+			break;
+		}
+		
+		
+	}
+
+	dvma_unmap(sun3_dma_orig_addr);
+	sun3_dma_orig_addr = NULL;
+
+	dregs->dma_addr_hi = 0;
+	dregs->dma_addr_lo = 0;
+	dregs->dma_count_hi = 0;
+	dregs->dma_count_lo = 0;
+
+	dregs->fifo_count = 0;
+	dregs->fifo_count_hi = 0;
+
+	dregs->csr &= ~CSR_SEND;
+	
+//	dregs->csr |= CSR_DMA_ENABLE;
+	
+#if 0
+	/* reset fifo */
+	dregs->csr &= ~CSR_FIFO;
+	dregs->csr |= CSR_FIFO;
+#endif	
+	sun3_dma_setup_done = NULL;
+
+	return ret;
+
+}
+
+#include "sun3_NCR5380.c"
+
+static Scsi_Host_Template driver_template = SUN3_NCR5380;
+
+#include "scsi_module.c"
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/sym53c8xx.c linux-2.4.21-pre6/drivers/scsi/sym53c8xx.c
--- linux-2.4.20/drivers/scsi/sym53c8xx.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/sym53c8xx.c	2003-03-26 23:49:07.000000000 +0000
@@ -7005,7 +7005,7 @@
 			INW (nc_sist);
 		}
 		else if (istat & DIP) {
-			if (INB (nc_dstat) & ABRT);
+			if (INB (nc_dstat) & ABRT)
 				break;
 		}
 		UDELAY(5);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/sym53c8xx_2/sym_hipd.c linux-2.4.21-pre6/drivers/scsi/sym53c8xx_2/sym_hipd.c
--- linux-2.4.20/drivers/scsi/sym53c8xx_2/sym_hipd.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/sym53c8xx_2/sym_hipd.c	2003-03-26 23:48:57.000000000 +0000
@@ -234,7 +234,7 @@
 			INW (nc_sist);
 		}
 		else if (istat & DIP) {
-			if (INB (nc_dstat) & ABRT);
+			if (INB (nc_dstat) & ABRT)
 				break;
 		}
 		UDELAY(5);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/scsi/t128.c linux-2.4.21-pre6/drivers/scsi/t128.c
--- linux-2.4.20/drivers/scsi/t128.c	2001-12-21 17:41:55.000000000 +0000
+++ linux-2.4.21-pre6/drivers/scsi/t128.c	2003-03-26 23:49:54.000000000 +0000
@@ -142,7 +142,7 @@
 
 #define NO_BASES (sizeof (bases) / sizeof (struct base))
 
-static const struct signature {
+static struct signature {
 	const char *string;
 	int offset;
 } signatures[] __initdata = {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/sound/Config.in linux-2.4.21-pre6/drivers/sound/Config.in
--- linux-2.4.20/drivers/sound/Config.in	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/sound/Config.in	2003-03-26 23:49:50.000000000 +0000
@@ -133,6 +133,7 @@
 
    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
       dep_tristate '    AD1816(A) based cards (EXPERIMENTAL)' CONFIG_SOUND_AD1816 $CONFIG_SOUND_OSS
+      dep_tristate '    AD1889 based cards (AD1819 codec) (EXPERIMENTAL)' CONFIG_SOUND_AD1889 $CONFIG_SOUND_OSS
    fi
    dep_tristate '    Aztech Sound Galaxy (non-PnP) cards' CONFIG_SOUND_SGALAXY $CONFIG_SOUND_OSS
    dep_tristate '    Adlib Cards' CONFIG_SOUND_ADLIB $CONFIG_SOUND_OSS
@@ -174,6 +175,7 @@
 
    dep_tristate '    100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support' CONFIG_SOUND_SB $CONFIG_SOUND_OSS
    dep_tristate '    AWE32 synth' CONFIG_SOUND_AWE32_SYNTH $CONFIG_SOUND_OSS
+   dep_tristate '    XpressAudio Sound Blaster emulation' CONFIG_SOUND_KAHLUA $CONFIG_SOUND_SB $CONFIG_SOUND_OSS
    dep_tristate '    Full support for Turtle Beach WaveFront (Tropez Plus, Tropez, Maui) synth/soundcards' CONFIG_SOUND_WAVEFRONT $CONFIG_SOUND_OSS m
    dep_tristate '    Limited support for Turtle Beach Wave Front (Maui, Tropez) synthesizers' CONFIG_SOUND_MAUI $CONFIG_SOUND_OSS
    if [ "$CONFIG_SOUND_MAUI" = "y" ]; then
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/sound/Makefile linux-2.4.21-pre6/drivers/sound/Makefile
--- linux-2.4.20/drivers/sound/Makefile	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/sound/Makefile	2003-03-26 23:49:20.000000000 +0000
@@ -33,6 +33,7 @@
 obj-$(CONFIG_SOUND_MSS)		+= ad1848.o
 obj-$(CONFIG_SOUND_PAS)		+= pas2.o sb.o sb_lib.o uart401.o
 obj-$(CONFIG_SOUND_SB)		+= sb.o sb_lib.o uart401.o
+obj-$(CONFIG_SOUND_KAHLUA)	+= kahlua.o
 obj-$(CONFIG_SOUND_WAVEFRONT)	+= wavefront.o
 obj-$(CONFIG_SOUND_MAUI)	+= maui.o mpu401.o
 obj-$(CONFIG_SOUND_MPU401)	+= mpu401.o
@@ -45,6 +46,7 @@
 obj-$(CONFIG_SOUND_WAVEARTIST)	+= waveartist.o
 obj-$(CONFIG_SOUND_SGALAXY)	+= sgalaxy.o ad1848.o
 obj-$(CONFIG_SOUND_AD1816)	+= ad1816.o
+obj-$(CONFIG_SOUND_AD1889)      += ad1889.o ac97_codec.o
 obj-$(CONFIG_SOUND_ACI_MIXER)	+= aci.o
 obj-$(CONFIG_SOUND_AWE32_SYNTH)	+= awe_wave.o
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/sound/ac97_codec.c linux-2.4.21-pre6/drivers/sound/ac97_codec.c
--- linux-2.4.20/drivers/sound/ac97_codec.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/sound/ac97_codec.c	2003-03-26 23:49:07.000000000 +0000
@@ -52,6 +52,8 @@
 #include <linux/ac97_codec.h>
 #include <asm/uaccess.h>
 
+#define CODEC_ID_BUFSZ 14
+
 static int ac97_read_mixer(struct ac97_codec *codec, int oss_channel);
 static void ac97_write_mixer(struct ac97_codec *codec, int oss_channel, 
 			     unsigned int left, unsigned int right);
@@ -657,7 +659,7 @@
  *	codec_id	-  Turn id1/id2 into a PnP string
  *	@id1: Vendor ID1
  *	@id2: Vendor ID2
- *	@buf: 10 byte buffer
+ *	@buf: CODEC_ID_BUFSZ byte buffer
  *
  *	Fills buf with a zero terminated PnP ident string for the id1/id2
  *	pair. For convenience the return is the passed in buffer pointer.
@@ -665,12 +667,14 @@
  
 static char *codec_id(u16 id1, u16 id2, char *buf)
 {
-	if(id1&0x8080)
-		snprintf(buf, 10, "%0x4X:%0x4X", id1, id2);
-	buf[0] = (id1 >> 8);
-	buf[1] = (id1 & 0xFF);
-	buf[2] = (id2 >> 8);
-	snprintf(buf+3, 7, "%d", id2&0xFF);
+	if(id1&0x8080) {
+		snprintf(buf, CODEC_ID_BUFSZ, "0x%04x:0x%04x", id1, id2);
+	} else {
+		buf[0] = (id1 >> 8);
+		buf[1] = (id1 & 0xFF);
+		buf[2] = (id2 >> 8);
+		snprintf(buf+3, CODEC_ID_BUFSZ - 3, "%d", id2&0xFF);
+	}
 	return buf;
 }
  
@@ -702,7 +706,7 @@
 	u16 id1, id2;
 	u16 audio, modem;
 	int i;
-	char cidbuf[10];
+	char cidbuf[CODEC_ID_BUFSZ];
 
 	/* probing AC97 codec, AC97 2.0 says that bit 15 of register 0x00 (reset) should 
 	 * be read zero.
@@ -746,7 +750,7 @@
 	}
 	if (codec->name == NULL)
 		codec->name = "Unknown";
-	printk(KERN_INFO "ac97_codec: AC97 %s codec, id: %s(%s)\n", 
+	printk(KERN_INFO "ac97_codec: AC97 %s codec, id: %s (%s)\n", 
 		modem ? "Modem" : (audio ? "Audio" : ""),
 	       codec_id(id1, id2, cidbuf), codec->name);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/sound/ad1889.c linux-2.4.21-pre6/drivers/sound/ad1889.c
--- linux-2.4.20/drivers/sound/ad1889.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/sound/ad1889.c	2003-03-26 23:49:53.000000000 +0000
@@ -0,0 +1,1077 @@
+/*
+ *  Copyright 2001 Randolph Chung <tausq@debian.org>
+ *
+ *  Analog Devices 1889 PCI audio driver (AD1819 AC97-compatible codec)
+ *
+ *   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.
+ *
+ *   Notes:
+ *   1. Only flat DMA is supported; s-g is not supported right now
+ *
+ *
+<jsm> tausq: Anyway, to set up sample rates for D to A, you just use the sample rate on the codec. For A to D, you need to set the codec always to 48K (using the split sample rate feature on the codec) and then set the resampler on the AD1889 to the sample rate you want.
+<jsm> Also, when changing the sample rate on the codec you need to power it down and re power it up for the change to take effect!
+ *
+ * $Id: ad1889.c,v 1.2 2002/10/16 04:14:12 grundler Exp $
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/slab.h>
+#include <linux/soundcard.h>
+#include <linux/ac97_codec.h>
+#include <linux/sound.h>
+#include <linux/wrapper.h>
+
+#include <asm/delay.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/uaccess.h>
+
+#include "ad1889.h"
+
+#define DBG(fmt, arg...) printk(fmt, ##arg)
+#define DEVNAME "ad1889"
+
+#define NR_HW_CH	4
+#define DAC_RUNNING	1
+#define ADC_RUNNING	2
+
+#define UNDERRUN(dev)	(0)
+
+#define AD1889_READW(dev,reg) readw(dev->regbase + reg)
+#define AD1889_WRITEW(dev,reg,val) writew((val), dev->regbase + reg)
+#define AD1889_READL(dev,reg) readl(dev->regbase + reg)
+#define AD1889_WRITEL(dev,reg,val) writel((val), dev->regbase + reg)
+
+//now 100ms
+#define WAIT_10MS()	do { int __i; for (__i = 0; __i < 100; __i++) udelay(1000); } while(0)
+
+/* currently only support a single device */
+static ad1889_dev_t *ad1889_dev = NULL;
+
+/************************* helper routines ***************************** */
+static inline void ad1889_set_wav_rate(ad1889_dev_t *dev, int rate)
+{
+	dev->state[AD_WAV_STATE].dmabuf.rate = rate;
+	AD1889_WRITEW(dev, AD_DSWAS, rate);
+}
+
+static inline void ad1889_set_adc_rate(ad1889_dev_t *dev, int rate)
+{
+	dev->state[AD_ADC_STATE].dmabuf.rate = rate;
+	AD1889_WRITEW(dev, AD_DSRES, rate);
+}
+
+static inline void ad1889_set_wav_fmt(ad1889_dev_t *dev, int fmt)
+{
+	u16 tmp;
+
+	tmp = AD1889_READW(ad1889_dev, AD_DSWSMC);
+	if (fmt == AFMT_S16_LE) {
+		//tmp |= 0x0100; /* set WA16 */
+		tmp |= 0x0300; /* set WA16 stereo */
+	} else if (fmt == AFMT_U8) {
+		tmp &= ~0x0100; /* clear WA16 */
+	} 
+	AD1889_WRITEW(ad1889_dev, AD_DSWSMC, tmp);
+}
+
+static inline void ad1889_set_adc_fmt(ad1889_dev_t *dev, int fmt)
+{
+	u16 tmp;
+
+	tmp = AD1889_READW(ad1889_dev, AD_DSRAMC);
+	if (fmt == AFMT_S16_LE) {
+		tmp |= 0x0100; /* set WA16 */
+	} else if (fmt == AFMT_U8) {
+		tmp &= ~0x0100; /* clear WA16 */
+	} 
+	AD1889_WRITEW(ad1889_dev, AD_DSRAMC, tmp);
+}
+
+static void ad1889_start_wav(ad1889_state_t *state)
+{
+	unsigned long flags;
+	struct dmabuf *dmabuf = &state->dmabuf;
+	int cnt;
+	u16 tmp;
+
+	spin_lock_irqsave(&state->card->lock, flags);
+
+	if (dmabuf->dma_len)	/* DMA already in flight */
+		goto skip_dma;
+
+	/* setup dma */
+	cnt = dmabuf->wr_ptr - dmabuf->rd_ptr;
+	if (cnt == 0)		/* done - don't need to do anything */
+		goto skip_dma;
+
+	/* If the wr_ptr has wrapped, only map to the end */
+	if (cnt < 0)
+		cnt = DMA_SIZE - dmabuf->rd_ptr;
+
+	dmabuf->dma_handle = pci_map_single(ad1889_dev->pci,
+					dmabuf->rawbuf + dmabuf->rd_ptr,
+					cnt, PCI_DMA_TODEVICE);
+	dmabuf->dma_len = cnt;
+	dmabuf->ready = 1;
+
+        /* load up the current register set */
+	AD1889_WRITEL(ad1889_dev, AD_DMAWAVCC, cnt);
+	AD1889_WRITEL(ad1889_dev, AD_DMAWAVICC, cnt);
+	AD1889_WRITEL(ad1889_dev, AD_DMAWAVCA, dmabuf->dma_handle);
+
+	/* TODO: for now we load the base registers with the same thing */
+	AD1889_WRITEL(ad1889_dev, AD_DMAWAVBC, cnt);
+	AD1889_WRITEL(ad1889_dev, AD_DMAWAVIBC, cnt);
+	AD1889_WRITEL(ad1889_dev, AD_DMAWAVBA, dmabuf->dma_handle);
+
+	/* and we're off to the races... */
+	AD1889_WRITEL(ad1889_dev, AD_DMACHSS, 0x8);
+	tmp = AD1889_READW(ad1889_dev, AD_DSWSMC);
+	tmp |= 0x0400; /* set WAEN */
+	AD1889_WRITEW(ad1889_dev, AD_DSWSMC, tmp);
+	(void) AD1889_READW(ad1889_dev, AD_DSWSMC); /* flush posted PCI write */
+
+	dmabuf->enable |= DAC_RUNNING;
+
+skip_dma:
+	spin_unlock_irqrestore(&state->card->lock, flags);
+}
+
+
+static void ad1889_stop_wav(ad1889_state_t *state)
+{
+	unsigned long flags;
+	struct dmabuf *dmabuf = &state->dmabuf;
+
+	spin_lock_irqsave(&state->card->lock, flags);
+
+	if (dmabuf->enable & DAC_RUNNING) {
+		u16 tmp;
+		unsigned long cnt = dmabuf->dma_len;
+
+		tmp = AD1889_READW(ad1889_dev, AD_DSWSMC);
+		tmp &= ~0x0400; /* clear WAEN */
+		AD1889_WRITEW(ad1889_dev, AD_DSWSMC, tmp);
+		(void) AD1889_READW(ad1889_dev, AD_DSWSMC); /* flush posted PCI write */
+		pci_unmap_single(ad1889_dev->pci, dmabuf->dma_handle, 
+				cnt, PCI_DMA_TODEVICE);
+
+		dmabuf->enable &= ~DAC_RUNNING;
+
+		/* update dma pointers */
+		dmabuf->rd_ptr += cnt;
+		dmabuf->rd_ptr &= (DMA_SIZE - 1);
+
+		dmabuf->dma_handle = 0;
+		dmabuf->dma_len = 0;
+		dmabuf->ready = 0;
+
+		wake_up(&dmabuf->wait);
+	}
+
+	spin_unlock_irqrestore(&state->card->lock, flags);
+}
+
+
+#if 0
+static void ad1889_startstop_adc(ad1889_state_t *state, int start)
+{
+	u16 tmp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&state->card->lock, flags);
+	
+	tmp = AD1889_READW(ad1889_dev, AD_DSRAMC);
+	if (start) {
+		state->dmabuf.enable |= ADC_RUNNING;
+		tmp |= 0x0004; /* set ADEN */
+	} else {
+		state->dmabuf.enable &= ~ADC_RUNNING;
+		tmp &= ~0x0004; /* clear ADEN */
+	}
+	AD1889_WRITEW(ad1889_dev, AD_DSRAMC, tmp);
+
+	spin_unlock_irqrestore(&state->card->lock, flags);
+}
+#endif
+
+static ad1889_dev_t *ad1889_alloc_dev(struct pci_dev *pci)
+{
+	ad1889_dev_t *dev;
+	struct dmabuf *dmabuf;
+	int i;
+
+	if ((dev = kmalloc(sizeof(ad1889_dev_t), GFP_KERNEL)) == NULL) 
+		return NULL;
+	memset(dev, 0, sizeof(ad1889_dev_t));
+	spin_lock_init(&dev->lock);
+	dev->pci = pci;
+
+	for (i = 0; i < AD_MAX_STATES; i++) {
+		dev->state[i].card = dev;
+		init_MUTEX(&dev->state[i].sem);
+		init_waitqueue_head(&dev->state[i].dmabuf.wait);
+	}
+
+	/* allocate dma buffer */
+
+	for (i = 0; i < AD_MAX_STATES; i++) {
+		dmabuf = &dev->state[i].dmabuf;
+		if ((dmabuf->rawbuf = kmalloc(DMA_SIZE, GFP_KERNEL|GFP_DMA)) == NULL)
+			return NULL;
+		dmabuf->rawbuf_size = DMA_SIZE;
+		dmabuf->dma_handle = 0;
+		dmabuf->rd_ptr = dmabuf->wr_ptr = dmabuf->dma_len = 0UL;
+		dmabuf->ready = 0;
+		dmabuf->rate = 44100;
+	}
+
+	return dev;
+}
+
+static void ad1889_free_dev(ad1889_dev_t *dev)
+{
+	int j;
+	struct dmabuf *dmabuf;
+
+	if (dev == NULL) 
+		return;
+
+	if (dev->ac97_codec)
+		kfree(dev->ac97_codec);
+
+	for (j = 0; j < AD_MAX_STATES; j++) {
+		dmabuf = &dev->state[j].dmabuf;
+		if (dmabuf->rawbuf != NULL) 
+			kfree(dmabuf->rawbuf);
+	}
+
+	kfree(dev);
+}
+
+static inline void ad1889_trigger_playback(ad1889_dev_t *dev)
+{
+#if 0
+	u32 val;
+	struct dmabuf *dmabuf = &dev->state[AD_WAV_STATE].dmabuf;
+#endif
+
+	ad1889_start_wav(&dev->state[AD_WAV_STATE]);
+}
+
+int ad1889_read_proc (char *page, char **start, off_t off,
+		      int count, int *eof, void *data)
+{
+	char *out = page;
+	int len, i;
+	ad1889_dev_t *dev = data;
+	ad1889_reg_t regs[] = {
+		{ "WSMC", AD_DSWSMC, 16 },
+		{ "RAMC", AD_DSRAMC, 16 },
+		{ "WADA", AD_DSWADA, 16 },
+		{ "SYDA", AD_DSSYDA, 16 },
+		{ "WAS", AD_DSWAS, 16 },
+		{ "RES", AD_DSRES, 16 },
+		{ "CCS", AD_DSCCS, 16 },
+		{ "ADCBA", AD_DMAADCBA, 32 },
+		{ "ADCCA", AD_DMAADCCA, 32 },
+		{ "ADCBC", AD_DMAADCBC, 32 },
+		{ "ADCCC", AD_DMAADCCC, 32 },
+		{ "ADCIBC", AD_DMAADCIBC, 32 },
+		{ "ADCICC", AD_DMAADCICC, 32 },
+		{ "ADCCTRL", AD_DMAADCCTRL, 16 },
+		{ "WAVBA", AD_DMAWAVBA, 32 },
+		{ "WAVCA", AD_DMAWAVCA, 32 },
+		{ "WAVBC", AD_DMAWAVBC, 32 },
+		{ "WAVCC", AD_DMAWAVCC, 32 },
+		{ "WAVIBC", AD_DMAWAVIBC, 32 },
+		{ "WAVICC", AD_DMAWAVICC, 32 },
+		{ "WAVCTRL", AD_DMAWAVCTRL, 16 },
+		{ "DISR", AD_DMADISR, 32 },
+		{ "CHSS", AD_DMACHSS, 32 },
+		{ "IPC", AD_GPIOIPC, 16 },
+		{ "OP", AD_GPIOOP, 16 },
+		{ "IP", AD_GPIOIP, 16 },
+		{ "ACIC", AD_ACIC, 16 },
+		{ "AC97_RESET", 0x100 + AC97_RESET, 16 },
+		{ "AC97_MASTER_VOL_STEREO", 0x100 + AC97_MASTER_VOL_STEREO, 16 },
+		{ "AC97_HEADPHONE_VOL", 0x100 + AC97_HEADPHONE_VOL, 16 },
+		{ "AC97_MASTER_VOL_MONO", 0x100 + AC97_MASTER_VOL_MONO, 16 },
+		{ "AC97_MASTER_TONE", 0x100 + AC97_MASTER_TONE, 16 },
+		{ "AC97_PCBEEP_VOL", 0x100 + AC97_PCBEEP_VOL, 16 },
+		{ "AC97_PHONE_VOL", 0x100 + AC97_PHONE_VOL, 16 },
+		{ "AC97_MIC_VOL", 0x100 + AC97_MIC_VOL, 16 },
+		{ "AC97_LINEIN_VOL", 0x100 + AC97_LINEIN_VOL, 16 },
+		{ "AC97_CD_VOL", 0x100 + AC97_CD_VOL, 16 },
+		{ "AC97_VIDEO_VOL", 0x100 + AC97_VIDEO_VOL, 16 },
+		{ "AC97_AUX_VOL", 0x100 + AC97_AUX_VOL, 16 },
+		{ "AC97_PCMOUT_VOL", 0x100 + AC97_PCMOUT_VOL, 16 },
+		{ "AC97_RECORD_SELECT", 0x100 + AC97_RECORD_SELECT, 16 },
+		{ "AC97_RECORD_GAIN", 0x100 + AC97_RECORD_GAIN, 16 },
+		{ "AC97_RECORD_GAIN_MIC", 0x100 + AC97_RECORD_GAIN_MIC, 16 },
+		{ "AC97_GENERAL_PURPOSE", 0x100 + AC97_GENERAL_PURPOSE, 16 },
+		{ "AC97_3D_CONTROL", 0x100 + AC97_3D_CONTROL, 16 },
+		{ "AC97_MODEM_RATE", 0x100 + AC97_MODEM_RATE, 16 },
+		{ "AC97_POWER_CONTROL", 0x100 + AC97_POWER_CONTROL, 16 },
+		{ 0 }
+	};
+
+	if (dev == NULL)
+		return -ENODEV;
+
+	for (i = 0; regs[i].name != 0; i++)
+		out += sprintf(out, "%s: 0x%0*x\n", regs[i].name, 
+			regs[i].width >> 2, 
+			(regs[i].width == 16 
+			 	? AD1889_READW(dev, regs[i].offset)
+				: AD1889_READL(dev, regs[i].offset)));
+
+	for (i = 0; i < AD_MAX_STATES; i++) {
+		out += sprintf(out, "DMA status for %s:\n", 
+			(i == AD_WAV_STATE ? "WAV" : "ADC")); 
+		out += sprintf(out, "\t\t0x%p (IOVA: 0x%u)\n", 
+			dev->state[i].dmabuf.rawbuf,
+			dev->state[i].dmabuf.dma_handle);
+
+		out += sprintf(out, "\tread ptr: offset %u\n", 
+			(unsigned int)dev->state[i].dmabuf.rd_ptr);
+		out += sprintf(out, "\twrite ptr: offset %u\n", 
+			(unsigned int)dev->state[i].dmabuf.wr_ptr);
+		out += sprintf(out, "\tdma len: offset %u\n", 
+			(unsigned int)dev->state[i].dmabuf.dma_len);
+	}
+
+	len = out - page - off;
+	if (len < count) {
+		*eof = 1;
+		if (len <= 0) return 0;
+	} else {
+		len = count;
+	}
+	*start = page + off;
+	return len;
+}
+
+/***************************** DMA interfaces ************************** */
+#if 0
+static inline unsigned long ad1889_get_dma_addr(ad1889_state_t *state)
+{
+	struct dmabuf *dmabuf = &state->dmabuf;
+	u32 offset;
+
+	if (!(dmabuf->enable & (DAC_RUNNING | ADC_RUNNING))) {
+		printk(KERN_ERR DEVNAME ": get_dma_addr called without dma enabled\n");
+		return 0;
+	}
+	
+	if (dmabuf->enable & DAC_RUNNING)
+		offset = le32_to_cpu(AD1889_READL(state->card, AD_DMAWAVBA));
+	else
+		offset = le32_to_cpu(AD1889_READL(state->card, AD_DMAADCBA));
+
+	return (unsigned long)bus_to_virt((unsigned long)offset) - (unsigned long)dmabuf->rawbuf;
+}
+
+static void ad1889_update_ptr(ad1889_dev_t *dev, int wake)
+{
+	ad1889_state_t *state;
+	struct dmabuf *dmabuf;
+	unsigned long hwptr;
+	int diff;
+
+	/* check ADC first */
+	state = &dev->adc_state;
+	dmabuf = &state->dmabuf;
+	if (dmabuf->enable & ADC_RUNNING) {
+		hwptr = ad1889_get_dma_addr(state);
+		diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
+
+		dmabuf->hwptr = hwptr;
+		dmabuf->total_bytes += diff;
+		dmabuf->count += diff;
+		if (dmabuf->count > dmabuf->dmasize)
+			dmabuf->count = dmabuf->dmasize;
+
+		if (dmabuf->mapped) {
+			if (wake & dmabuf->count >= dmabuf->fragsize)
+				wake_up(&dmabuf->wait);
+		} else {
+			if (wake & dmabuf->count > 0)
+				wake_up(&dmabuf->wait);
+		}
+	}
+
+	/* check DAC */
+	state = &dev->wav_state;
+	dmabuf = &state->dmabuf;
+	if (dmabuf->enable & DAC_RUNNING) {
+XXX
+
+}
+#endif
+
+/************************* /dev/dsp interfaces ************************* */
+
+static ssize_t ad1889_read(struct file *file, char *buffer, size_t count,
+	loff_t *ppos)
+{
+	return 0;
+}
+
+static ssize_t ad1889_write(struct file *file, const char *buffer, size_t count,
+	loff_t *ppos)
+{
+	ad1889_dev_t *dev = (ad1889_dev_t *)file->private_data;
+	ad1889_state_t *state = &dev->state[AD_WAV_STATE];
+	volatile struct dmabuf *dmabuf = &state->dmabuf;
+	ssize_t ret = 0;
+	DECLARE_WAITQUEUE(wait, current);
+
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	down(&state->sem);
+#if 0
+	if (dmabuf->mapped) {
+		ret = -ENXIO;
+		goto err1;
+	}
+#endif
+	if (!access_ok(VERIFY_READ, buffer, count)) {
+		ret = -EFAULT;
+		goto err1;
+	}
+
+	add_wait_queue(&state->dmabuf.wait, &wait);
+
+	/* start filling dma buffer.... */
+	while (count > 0) {
+		long rem;
+		long cnt = count;
+		unsigned long flags;
+
+
+		for (;;) {
+			long used_bytes;
+			long timeout;	/* max time for DMA in jiffies */
+
+			/* buffer is full if wr catches up to rd */
+			spin_lock_irqsave(&state->card->lock, flags);
+			used_bytes = dmabuf->wr_ptr - dmabuf->rd_ptr;
+			timeout = (dmabuf->dma_len * HZ) / dmabuf->rate;
+			spin_unlock_irqrestore(&state->card->lock, flags);
+
+			/* adjust for buffer wrap around */
+			used_bytes = (used_bytes + DMA_SIZE) & (DMA_SIZE - 1);
+
+			/* If at least one page unused */
+			if (used_bytes < (DMA_SIZE - 0x1000))
+				break;
+
+			/* dma buffer full */
+
+			if (file->f_flags & O_NONBLOCK) {
+				ret = -EAGAIN;
+				goto err2;
+			}
+
+			set_current_state(TASK_INTERRUPTIBLE);
+			if (!schedule_timeout(timeout + 1))
+				printk(KERN_WARNING "AD1889 timeout(%ld) r/w %lx/%lx len %lx\n",
+				    timeout+1,
+				    dmabuf->rd_ptr, dmabuf->wr_ptr,
+				    dmabuf->dma_len);
+
+			if (signal_pending(current)) {
+				ret = -ERESTARTSYS;
+				goto err2;
+			}
+
+		}
+
+		/* watch out for wrapping around static buffer */
+		spin_lock_irqsave(&state->card->lock, flags);
+		rem = DMA_SIZE - dmabuf->wr_ptr;
+		if (cnt > rem)
+			cnt = rem;
+
+		rem = dmabuf->wr_ptr;
+
+		/* update dma pointers */
+		dmabuf->wr_ptr += cnt;
+		dmabuf->wr_ptr &= DMA_SIZE - 1;	/* wrap ptr if necessary */
+		spin_unlock_irqrestore(&state->card->lock, flags);
+
+		/* transfer unwrapped chunk */
+		if (copy_from_user(dmabuf->rawbuf + rem, buffer, cnt)) {
+			ret = -EFAULT;
+			goto err2;
+		}
+
+		DBG("Writing 0x%lx bytes to +0x%lx\n", cnt, rem);
+
+		/* update counters */
+		count -= cnt;
+		buffer += cnt;
+		ret += cnt;
+
+		/* we have something to play - go play it! */
+		ad1889_trigger_playback(dev);
+	}
+
+err2:
+	remove_wait_queue(&state->dmabuf.wait, &wait);
+err1:
+	up(&state->sem);
+	return ret;
+}
+
+static unsigned int ad1889_poll(struct file *file, struct poll_table_struct *wait)
+{
+	unsigned int mask = 0;
+#if 0
+	ad1889_dev_t *dev = (ad1889_dev_t *)file->private_data;
+	ad1889_state_t *state = NULL;
+	struct dmabuf *dmabuf;
+	unsigned long flags;
+	
+	if (!(file->f_mode & (FMODE_READ | FMODE_WRITE)))
+		return -EINVAL;
+
+	if (file->f_mode & FMODE_WRITE) {
+		state = &dev->state[AD_WAV_STATE];
+		if (!state) return 0;
+		dmabuf = &state->dmabuf;
+		poll_wait(file, &dmabuf->wait, wait);
+	}
+
+	if (file->f_mode & FMODE_READ) {
+		state = &dev->state[AD_ADC_STATE];
+		if (!state) return 0;
+		dmabuf = &state->dmabuf;
+		poll_wait(file, &dmabuf->wait, wait);
+	}
+
+	spin_lock_irqsave(&dev->lock, flags);
+	ad1889_update_ptr(dev, 0);
+
+	if (file->f_mode & FMODE_WRITE) {
+		state = &dev->state[WAV_STATE];
+		dmabuf = &state->dmabuf;
+		if (dmabuf->mapped) {
+			if (dmabuf->count >= (int)dmabuf->fragsize)
+				mask |= POLLOUT | POLLWRNORM;
+		} else {
+			if ((int)dmabuf->dmasize >= dmabuf->count + 
+				(int)dmabuf->fragsize)
+				mask |= POLLOUT | POLLWRNORM;
+		}
+	}
+
+	if (file ->f_mode & FMODE_READ) {
+		state = &dev->state[AD_ADC_STATE];
+		dmabuf = &state->dmabuf;
+		if (dmabuf->count >= (int)dmabuf->fragsize)
+			mask |= POLLIN | POLLRDNORM;
+	}
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+#endif
+	return mask;
+}
+
+static int ad1889_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	return 0;
+}
+
+static int ad1889_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	unsigned long arg)
+{
+	int val = 0;
+	ad1889_dev_t *dev = (ad1889_dev_t *)file->private_data;
+	struct dmabuf *dmabuf;
+	audio_buf_info abinfo;
+
+	switch (cmd)
+	{
+	case OSS_GETVERSION:
+		return put_user(SOUND_VERSION, (int *)arg);
+
+	case SNDCTL_DSP_RESET:
+		break;
+
+	case SNDCTL_DSP_SYNC:
+		break;
+
+	case SNDCTL_DSP_SPEED:
+		/* set sampling rate */
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
+		if (val > 5400 && val < 48000)
+		{
+			if (file->f_mode & FMODE_WRITE)
+				AD1889_WRITEW(ad1889_dev, AD_DSWAS, val);
+			if (file->f_mode & FMODE_READ)
+				AD1889_WRITEW(ad1889_dev, AD_DSRES, val);
+		}
+		return 0;
+
+	case SNDCTL_DSP_STEREO: /* undocumented? */
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
+		if (file->f_mode & FMODE_READ) {
+			val = AD1889_READW(ad1889_dev, AD_DSWSMC);
+			if (val) {
+				val |= 0x0200;  /* set WAST */
+			} else {
+				val &= ~0x0200; /* clear WAST */
+			}
+			AD1889_WRITEW(ad1889_dev, AD_DSWSMC, val);
+		}
+		if (file->f_mode & FMODE_WRITE) {
+			val = AD1889_READW(ad1889_dev, AD_DSRAMC);
+			if (val) {
+				val |= 0x0002;  /* set ADST */
+			} else {
+				val &= ~0x0002; /* clear ADST */
+			}
+			AD1889_WRITEW(ad1889_dev, AD_DSRAMC, val);
+		}
+
+		return 0;
+
+	case SNDCTL_DSP_GETBLKSIZE:
+		return put_user(DMA_SIZE, (int *)arg);
+
+	case SNDCTL_DSP_GETFMTS:
+		return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg);
+
+	case SNDCTL_DSP_SETFMT:
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
+
+		if (file->f_mode & FMODE_READ) 
+			ad1889_set_adc_fmt(dev, val);
+
+		if (file->f_mode & FMODE_WRITE) 
+			ad1889_set_wav_fmt(dev, val);
+
+		return put_user(val, (int *)arg);
+
+	case SNDCTL_DSP_CHANNELS:
+		break;
+
+	case SNDCTL_DSP_POST:
+		/* send all data to device */
+		break;
+
+	case SNDCTL_DSP_SUBDIVIDE:
+		break;
+
+	case SNDCTL_DSP_SETFRAGMENT:
+		/* not supported; uses fixed fragment sizes */
+		return put_user(DMA_SIZE, (int *)arg);
+
+	case SNDCTL_DSP_GETOSPACE:
+	case SNDCTL_DSP_GETISPACE:
+		/* space left in dma buffers */
+		if (cmd == SNDCTL_DSP_GETOSPACE)
+			dmabuf = &dev->state[AD_WAV_STATE].dmabuf;
+		else
+			dmabuf = &dev->state[AD_ADC_STATE].dmabuf;
+		abinfo.fragments = 1;
+		abinfo.fragstotal = 1;
+		abinfo.fragsize = DMA_SIZE;
+		abinfo.bytes = DMA_SIZE;
+		return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+	case SNDCTL_DSP_NONBLOCK:
+		file->f_flags |= O_NONBLOCK;
+		return 0;
+
+	case SNDCTL_DSP_GETCAPS:
+		return put_user(0, (int *)arg);
+
+	case SNDCTL_DSP_GETTRIGGER:
+	case SNDCTL_DSP_SETTRIGGER:
+		break;
+
+	case SNDCTL_DSP_GETIPTR:
+	case SNDCTL_DSP_GETOPTR:
+		break;
+
+	case SNDCTL_DSP_SETDUPLEX:
+		break;
+	
+	case SNDCTL_DSP_GETODELAY:
+		break;
+
+	case SOUND_PCM_READ_RATE:
+		return put_user(AD1889_READW(ad1889_dev, AD_DSWAS), (int *)arg);
+
+	case SOUND_PCM_READ_CHANNELS:
+	case SOUND_PCM_READ_BITS:
+		break;
+
+	case SNDCTL_DSP_MAPINBUF:
+	case SNDCTL_DSP_MAPOUTBUF:
+	case SNDCTL_DSP_SETSYNCRO:
+	case SOUND_PCM_WRITE_FILTER:
+	case SOUND_PCM_READ_FILTER:
+		break;
+
+	default:
+		break;
+	}
+
+	return -ENOTTY;
+}
+
+static int ad1889_open(struct inode *inode, struct file *file)
+{
+	/* check minor; only support /dev/dsp atm */
+	if (MINOR(inode->i_rdev) != 3)
+		return -ENXIO;
+	
+	file->private_data = ad1889_dev;
+
+	ad1889_set_wav_rate(ad1889_dev, 44100);
+	ad1889_set_wav_fmt(ad1889_dev, AFMT_S16_LE);
+	AD1889_WRITEW(ad1889_dev, AD_DSWADA, 0x0404); /* attenuation */
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int ad1889_release(struct inode *inode, struct file *file)
+{
+	/* if we have state free it here */
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static struct file_operations ad1889_fops = {
+	llseek:         no_llseek,
+	read:           ad1889_read,
+	write:          ad1889_write,
+	poll:           ad1889_poll,
+	ioctl:          ad1889_ioctl,
+	mmap:           ad1889_mmap,
+	open:           ad1889_open,
+	release:        ad1889_release,
+};
+
+/************************* /dev/mixer interfaces ************************ */
+static int ad1889_mixer_open(struct inode *inode, struct file *file)
+{
+	if (ad1889_dev->ac97_codec->dev_mixer != MINOR(inode->i_rdev))
+		return -ENODEV;
+
+	file->private_data = ad1889_dev->ac97_codec;
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int ad1889_mixer_release(struct inode *inode, struct file *file)
+{
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int ad1889_mixer_ioctl(struct inode *inode, struct file *file,
+	unsigned int cmd, unsigned long arg)
+{
+	struct ac97_codec *codec = (struct ac97_codec *)file->private_data;
+	return codec->mixer_ioctl(codec, cmd, arg);
+}
+
+static struct file_operations ad1889_mixer_fops = {
+	llseek:         no_llseek,
+	ioctl:		ad1889_mixer_ioctl,
+	open:		ad1889_mixer_open,
+	release:	ad1889_mixer_release,
+};
+
+/************************* AC97 interfaces ****************************** */
+static void ad1889_codec_write(struct ac97_codec *ac97, u8 reg, u16 val)
+{
+	ad1889_dev_t *dev = ac97->private_data;
+
+	//DBG("Writing 0x%x to 0x%lx\n", val, dev->regbase + 0x100 + reg);
+	AD1889_WRITEW(dev, 0x100 + reg, val);
+}
+
+static u16 ad1889_codec_read(struct ac97_codec *ac97, u8 reg)
+{
+	ad1889_dev_t *dev = ac97->private_data;
+	//DBG("Reading from 0x%lx\n", dev->regbase + 0x100 + reg);
+	return AD1889_READW(dev, 0x100 + reg);
+}	
+
+static int ad1889_ac97_init(ad1889_dev_t *dev, int id)
+{
+	struct ac97_codec *ac97;
+	u16 eid;
+
+	if ((ac97 = kmalloc(sizeof(struct ac97_codec), GFP_KERNEL)) == NULL) 
+		return -ENOMEM;
+	memset(ac97, 0, sizeof(struct ac97_codec));
+
+	ac97->private_data = dev;
+	ac97->id = id;
+
+	ac97->codec_read = ad1889_codec_read;
+	ac97->codec_write = ad1889_codec_write;
+
+	if (ac97_probe_codec(ac97) == 0) {
+		printk(DEVNAME ": ac97_probe_codec failed\n");
+		goto out_free;
+	}
+
+	eid = ad1889_codec_read(ac97, AC97_EXTENDED_ID);
+	if (eid == 0xffffff) {
+		printk(KERN_WARNING DEVNAME ": no codec attached?\n");
+		goto out_free;
+	}
+
+	dev->ac97_features = eid;
+
+	if ((ac97->dev_mixer = register_sound_mixer(&ad1889_mixer_fops, -1)) < 0) {
+		printk(KERN_ERR DEVNAME ": cannot register mixer\n");
+		goto out_free;
+	}
+
+	dev->ac97_codec = ac97;
+	return 0;
+
+out_free:
+	kfree(ac97);
+	return -ENODEV;
+}
+
+static int ad1889_aclink_reset(struct pci_dev * pcidev)
+{
+	u16 stat;
+	int retry = 200;
+	ad1889_dev_t *dev = pci_get_drvdata(pcidev);
+
+	AD1889_WRITEW(dev, AD_DSCCS, 0x8000); /* turn on clock */
+	AD1889_READW(dev, AD_DSCCS); 
+
+	WAIT_10MS();
+
+	stat = AD1889_READW(dev, AD_ACIC);
+	stat |= 0x0002;				/* Reset Disable */
+	AD1889_WRITEW(dev, AD_ACIC, stat);
+	(void) AD1889_READW(dev, AD_ACIC);	/* flush posted write */
+
+	udelay(10);
+
+	stat = AD1889_READW(dev, AD_ACIC);
+	stat |= 0x0001;				/* Interface Enable */
+	AD1889_WRITEW(dev, AD_ACIC, stat);
+
+	do {
+		if (AD1889_READW(dev, AD_ACIC) & 0x8000)	/* Ready */
+			break;
+		WAIT_10MS();
+		retry--;
+	} while (retry > 0);
+
+	if (!retry) {
+		printk(KERN_ERR "ad1889_aclink_reset: codec is not ready [0x%x]\n",
+			    AD1889_READW(dev, AD_ACIC));
+		return -EBUSY;
+	}
+
+	/* TODO reset AC97 codec */
+	/* TODO set wave/adc pci ctrl status */
+
+	stat = AD1889_READW(dev, AD_ACIC);
+	stat |= 0x0004;				/* Audio Stream Output Enable */
+	AD1889_WRITEW(dev, AD_ACIC, stat);
+	return 0;
+}
+
+/************************* PCI interfaces ****************************** */
+/* PCI device table */
+static struct pci_device_id ad1889_id_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_ANALOG_DEVICES, PCI_DEVICE_ID_AD1889JS, PCI_ANY_ID, 
+	  PCI_ANY_ID, 0, 0, (unsigned long)DEVNAME },
+	{ },
+};
+MODULE_DEVICE_TABLE(pci, ad1889_id_tbl);
+
+static void ad1889_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	u32 stat;
+	ad1889_dev_t *dev = (ad1889_dev_t *)dev_id;
+
+	stat = AD1889_READL(dev, AD_DMADISR);
+
+	/* clear ISR */
+	AD1889_WRITEL(dev, AD_DMADISR, stat);
+
+	if (stat & 0x8) {		/* WAVI */
+		DBG("WAV interrupt\n");
+		dev->stats.wav_intrs++;
+		if (dev->state[AD_WAV_STATE].dmabuf.ready) {
+			ad1889_stop_wav(&dev->state[AD_WAV_STATE]);	/* clean up */
+			ad1889_start_wav(&dev->state[AD_WAV_STATE]);	/* start new */
+		}
+
+	}
+
+	if (stat & 0x2 && dev->state[AD_ADC_STATE].dmabuf.ready) { /* ADCI */
+		DBG("ADC interrupt\n");
+		dev->stats.adc_intrs++;
+	}
+}
+
+static void ad1889_initcfg(ad1889_dev_t *dev)
+{
+	u16 tmp;
+
+	/* make sure the interrupt bits are setup the way we want */
+	tmp = AD1889_READW(dev, AD_DMAWAVCTRL);
+	tmp &= ~0x00ff; /* flat dma, no sg, mask out the intr bits */
+	tmp |= 0x0004;  /* intr on count, loop */
+	AD1889_WRITEW(dev, AD_DMAWAVCTRL, tmp);
+
+	/* unmute... */
+	tmp = AD1889_READW(dev, AD_DSWADA);
+	tmp &= ~0x8080;
+	AD1889_WRITEW(dev, AD_DSWADA, tmp);
+}
+
+static int __devinit ad1889_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
+{
+	int err;
+	ad1889_dev_t *dev;
+	unsigned long bar;
+	struct proc_dir_entry *proc_root = NULL;
+
+	if ((err = pci_enable_device(pcidev)) != 0) {
+		printk(KERN_ERR DEVNAME ": pci_enable_device failed\n");
+		return err;
+	}
+
+	pci_set_master(pcidev);
+	if ((dev = ad1889_alloc_dev(pcidev)) == NULL) {
+		printk(KERN_ERR DEVNAME ": cannot allocate memory for device\n");
+		return -ENOMEM;
+	}
+	pci_set_drvdata(pcidev, dev);
+	bar = pci_resource_start(pcidev, 0);
+	
+        if (!(pci_resource_flags(pcidev, 0) & IORESOURCE_MEM)) {
+		printk(KERN_ERR DEVNAME ": memory region not assigned\n");
+		goto err_free_mem;
+	}
+
+	if (request_irq(pcidev->irq, ad1889_interrupt, SA_SHIRQ, DEVNAME, dev) != 0) {
+		printk(KERN_ERR DEVNAME ": unable to request interrupt\n");
+		goto err_free_mem;
+	}
+
+	request_mem_region(bar, AD_DSIOMEMSIZE, DEVNAME);
+	dev->regbase = (unsigned long)ioremap_nocache(bar, AD_DSIOMEMSIZE);
+
+	printk(KERN_INFO DEVNAME ": %s at 0x%lx IRQ %d\n",
+		(char *)ent->driver_data, dev->regbase, pcidev->irq);
+
+	if (ad1889_aclink_reset(pcidev) != 0)
+		goto err_free_mem;
+
+	/* register /dev/dsp */
+	if ((dev->dev_audio = register_sound_dsp(&ad1889_fops, -1)) < 0) {
+		printk(KERN_ERR DEVNAME ": cannot register /dev/dsp\n");
+		goto err_free_irq;
+	}
+
+	if ((err = ad1889_ac97_init(dev, 0)) != 0)
+		goto err_free_dsp;
+
+	if (((proc_root = proc_mkdir("driver/ad1889", 0)) == NULL) ||
+	    create_proc_read_entry("ac97", S_IFREG|S_IRUGO, proc_root, ac97_read_proc, dev->ac97_codec) == NULL ||
+	    create_proc_read_entry("info", S_IFREG|S_IRUGO, proc_root, ad1889_read_proc, dev) == NULL) 
+		goto err_free_dsp;
+	
+	ad1889_initcfg(dev);
+
+	//DBG(DEVNAME ": Driver initialization done!\n");
+
+	ad1889_dev = dev;
+
+	return 0;
+
+err_free_dsp:
+	unregister_sound_dsp(dev->dev_audio);
+
+err_free_irq:
+	free_irq(pcidev->irq, dev);
+
+err_free_mem:
+	ad1889_free_dev(dev);
+	pci_set_drvdata(pcidev, 0);
+
+	return -ENODEV;
+}
+
+static void __devexit ad1889_remove(struct pci_dev *pcidev)
+{
+	ad1889_dev_t *dev = pci_get_drvdata(pcidev);
+
+	if (dev == NULL) return;
+	
+	unregister_sound_mixer(dev->ac97_codec->dev_mixer);
+	unregister_sound_dsp(dev->dev_audio);
+	free_irq(pcidev->irq, dev);
+	release_mem_region(dev->regbase, AD_DSIOMEMSIZE);
+
+	/* any hw programming needed? */
+	ad1889_free_dev(dev);
+}
+
+MODULE_AUTHOR("Randolph Chung");
+MODULE_DESCRIPTION("Analog Devices AD1889 PCI Audio");
+MODULE_LICENSE("GPL");
+
+static struct pci_driver ad1889_driver = {
+	name:		DEVNAME,
+	id_table:	ad1889_id_tbl,
+	probe:		ad1889_probe,
+	remove:		ad1889_remove,
+};
+
+static int __init ad1889_init_module(void)
+{
+	return pci_module_init(&ad1889_driver);
+}
+
+static void ad1889_exit_module(void)
+{
+	pci_unregister_driver(&ad1889_driver);
+	return;
+}
+
+module_init(ad1889_init_module);
+module_exit(ad1889_exit_module);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/sound/ad1889.h linux-2.4.21-pre6/drivers/sound/ad1889.h
--- linux-2.4.20/drivers/sound/ad1889.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/sound/ad1889.h	2003-03-26 23:49:40.000000000 +0000
@@ -0,0 +1,134 @@
+#ifndef _AD1889_H_
+#define _AD1889_H_
+
+#define AD_DSWSMC	0x00	/* DMA input wave/syn mixer control */
+#define AD_DSRAMC	0x02	/* DMA output resamp/ADC mixer control */
+#define AD_DSWADA	0x04	/* DMA input wave attenuation */
+#define AD_DSSYDA	0x06	/* DMA input syn attentuation */
+#define AD_DSWAS	0x08	/* wave input sample rate */
+#define AD_DSRES	0x0a	/* resampler output sample rate */
+#define AD_DSCCS	0x0c	/* chip control/status */
+
+#define AD_DMARESBA	0x40	/* RES base addr */
+#define AD_DMARESCA	0x44	/* RES current addr */
+#define AD_DMARESBC	0x48	/* RES base cnt */
+#define AD_DMARESCC	0x4c	/* RES current count */
+#define AD_DMAADCBA	0x50	/* ADC */
+#define AD_DMAADCCA	0x54
+#define AD_DMAADCBC	0x58
+#define AD_DMAADCCC	0x5c
+#define AD_DMASYNBA	0x60	/* SYN */
+#define AD_DMASYNCA	0x64
+#define AD_DMASYNBC	0x68
+#define AD_DMASYNCC	0x6c
+#define AD_DMAWAVBA	0x70	/* WAV */
+#define AD_DMAWAVCA	0x74
+#define AD_DMAWAVBC	0x78
+#define AD_DMAWAVCC	0x7c
+#define AD_DMARESICC	0x80	/* RES interrupt current count */
+#define AD_DMARESIBC	0x84	/* RES interrupt base count */
+#define AD_DMAADCICC	0x88	/* ADC interrupt current count */
+#define AD_DMAADCIBC	0x8c	/* ADC interrupt base count */
+#define AD_DMASYNICC	0x90	/* SYN interrupt current count */
+#define AD_DMASYNIBC	0x94	/* SYN interrupt base count */
+#define AD_DMAWAVICC	0x98	/* WAV interrupt current count */
+#define AD_DMAWAVIBC	0x9c	/* WAV interrupt base count */
+#define AD_DMARESCTRL	0xa0	/* RES PCI control/status */
+#define AD_DMAADCCTRL	0xa8	/* RES PCI control/status */
+#define AD_DMASYNCTRL	0xb0	/* RES PCI control/status */
+#define AD_DMAWAVCTRL	0xb8	/* RES PCI control/status */
+#define AD_DMADISR	0xc0	/* PCI DMA intr status */
+#define AD_DMACHSS	0xc4	/* PCI DMA channel stop status */
+
+#define AD_GPIOIPC	0xc8	/* IO port ctrl */
+#define AD_GPIOOP	0xca	/* IO output status */
+#define AD_GPIOIP	0xcc	/* IO input status */
+
+/* AC97 registers, 0x100 - 0x17f; see ac97.h */
+#define AD_ACIC		0x180	/* AC Link interface ctrl */
+
+/* OPL3; BAR1 */
+#define AD_OPLM0AS	0x00	/* Music0 address/status */
+#define AD_OPLM0DATA	0x01	/* Music0 data */
+#define AD_OPLM1A	0x02	/* Music1 address */
+#define AD_OPLM1DATA	0x03	/* Music1 data */
+/* 0x04-0x0f reserved */
+
+/* MIDI; BAR2 */
+#define AD_MIDA		0x00	/* MIDI data */
+#define AD_MISC		0x01	/* MIDI status/cmd */
+/* 0x02-0xff reserved */
+
+#define AD_DSIOMEMSIZE	512
+#define AD_OPLMEMSIZE	16
+#define AD_MIDIMEMSIZE	16
+
+#define AD_WAV_STATE	0
+#define AD_ADC_STATE	1
+#define AD_MAX_STATES	2
+
+#define DMA_SIZE	(128*1024)
+
+#define DMA_FLAG_MAPPED	1
+
+struct ad1889_dev;
+
+typedef struct ad1889_state {
+	struct ad1889_dev *card;
+
+	mode_t open_mode;
+	struct dmabuf {
+		unsigned int rate;
+		unsigned char fmt, enable;
+
+		/* buf management */
+		size_t rawbuf_size;
+		void *rawbuf;
+		dma_addr_t dma_handle;	/* mapped address */
+		unsigned long dma_len;	/* number of bytes mapped */
+
+		/* indexes into rawbuf for setting up DMA engine */
+		volatile unsigned long rd_ptr, wr_ptr;
+
+		wait_queue_head_t wait; /* to wait for buf servicing */
+
+		/* OSS bits */
+		unsigned int mapped:1;
+		unsigned int ready:1;
+		unsigned int ossfragshift;
+		int ossmaxfrags;
+		unsigned int subdivision;
+	} dmabuf;
+
+	struct semaphore sem;
+} ad1889_state_t;
+
+typedef struct ad1889_dev {
+	unsigned long regbase;
+	struct pci_dev *pci;
+	
+	spinlock_t lock;
+
+	int dev_audio;
+
+	/* states; one per channel; right now only WAV and ADC */
+	struct ad1889_state state[AD_MAX_STATES];
+
+	/* AC97 codec */
+	struct ac97_codec *ac97_codec;
+	u16 ac97_features;
+
+	/* debugging stuff */
+	struct stats {
+		unsigned int wav_intrs, adc_intrs;
+		unsigned int blocks, underrun, error;
+	} stats;
+} ad1889_dev_t;
+
+typedef struct ad1889_reg {
+	const char *name;
+	int offset;
+	int width;
+} ad1889_reg_t;
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/sound/cmpci.c linux-2.4.21-pre6/drivers/sound/cmpci.c
--- linux-2.4.20/drivers/sound/cmpci.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/sound/cmpci.c	2003-03-26 23:48:57.000000000 +0000
@@ -82,6 +82,7 @@
  *	- speaker mixer support 
  *	Mon Aug 13 2001
  *	- optimizations and cleanups
+ *    03/01/2003 - open_mode fixes from Georg Acher <acher@in.tum.de>
  *
  */
 /*****************************************************************************/
@@ -2266,7 +2267,7 @@
 		stop_adc(s);
 		dealloc_dmabuf(&s->dma_adc);
 	}
-	s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
+	s->open_mode &= ~(file->f_mode & (FMODE_READ|FMODE_WRITE));
 	up(&s->open_sem);
 	wake_up(&s->open_wait);
 	unlock_kernel();
@@ -2535,7 +2536,7 @@
 		set_current_state(TASK_RUNNING);
 	}
 	down(&s->open_sem);
-	s->open_mode &= (~(file->f_mode << FMODE_MIDI_SHIFT)) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE);
+	s->open_mode &= ~((file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE));
 	spin_lock_irqsave(&s->lock, flags);
 	if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
 		del_timer(&s->midi.timer);		
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/sound/dmasound/dmasound_core.c linux-2.4.21-pre6/drivers/sound/dmasound/dmasound_core.c
--- linux-2.4.20/drivers/sound/dmasound/dmasound_core.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/sound/dmasound/dmasound_core.c	2003-03-26 23:49:08.000000000 +0000
@@ -1212,7 +1212,7 @@
 		return result ;
 		break ;
 	case SNDCTL_DSP_SPEED:
-		/* changing this on the fly will have wierd effects on the sound.
+		/* Changing this on the fly will have weird effects on the sound.
 		   Where there are rate conversions implemented in soft form - it
 		   will cause the _ctx_xxx() functions to be substituted.
 		   However, there doesn't appear to be any reason to dis-allow it from
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/sound/es1370.c linux-2.4.21-pre6/drivers/sound/es1370.c
--- linux-2.4.20/drivers/sound/es1370.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/sound/es1370.c	2003-03-26 23:49:35.000000000 +0000
@@ -3,7 +3,7 @@
 /*
  *      es1370.c  --  Ensoniq ES1370/Asahi Kasei AK4531 audio driver.
  *
- *      Copyright (C) 1998-2001  Thomas Sailer (t.sailer@alumni.ethz.ch)
+ *      Copyright (C) 1998-2001, 2003  Thomas Sailer (t.sailer@alumni.ethz.ch)
  *
  *      This program is free software; you can redistribute it and/or modify
  *      it under the terms of the GNU General Public License as published by
@@ -122,6 +122,7 @@
  *    07.01.2001   0.36  Timeout change in wrcodec as requested by Frank Klemm <pfk@fuchs.offl.uni-jena.de>
  *    31.01.2001   0.37  Register/Unregister gameport
  *                       Fix SETTRIGGER non OSS API conformity
+ *    03.01.2003   0.38  open_mode fixes from Georg Acher <acher@in.tum.de>
  *
  * some important things missing in Ensoniq documentation:
  *
@@ -1809,7 +1810,7 @@
 		stop_adc(s);
 		dealloc_dmabuf(s, &s->dma_adc);
 	}
-	s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
+	s->open_mode &= ~(file->f_mode & (FMODE_READ|FMODE_WRITE));
 	wake_up(&s->open_wait);
 	up(&s->open_sem);
 	unlock_kernel();
@@ -2494,7 +2495,7 @@
 		set_current_state(TASK_RUNNING);
 	}
 	down(&s->open_sem);
-	s->open_mode &= (~(file->f_mode << FMODE_MIDI_SHIFT)) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE);
+	s->open_mode &= ~((file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE));
 	spin_lock_irqsave(&s->lock, flags);
 	if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
 		s->ctrl &= ~CTRL_UART_EN;
@@ -2745,7 +2746,7 @@
 {
 	if (!pci_present())   /* No PCI bus in this machine! */
 		return -ENODEV;
-	printk(KERN_INFO "es1370: version v0.37 time " __TIME__ " " __DATE__ "\n");
+	printk(KERN_INFO "es1370: version v0.38 time " __TIME__ " " __DATE__ "\n");
 	return pci_module_init(&es1370_driver);
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/sound/es1371.c linux-2.4.21-pre6/drivers/sound/es1371.c
--- linux-2.4.20/drivers/sound/es1371.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/sound/es1371.c	2003-03-26 23:49:16.000000000 +0000
@@ -3,7 +3,7 @@
 /*
  *      es1371.c  --  Creative Ensoniq ES1371.
  *
- *      Copyright (C) 1998-2001  Thomas Sailer (t.sailer@alumni.ethz.ch)
+ *      Copyright (C) 1998-2001, 2003  Thomas Sailer (t.sailer@alumni.ethz.ch)
  *
  *      This program is free software; you can redistribute it and/or modify
  *      it under the terms of the GNU General Public License as published by
@@ -110,6 +110,7 @@
  *    31.01.2001   0.30  Register/Unregister gameport
  *                       Fix SETTRIGGER non OSS API conformity
  *    14.07.2001   0.31  Add list of laptops needing amplifier control
+ *    03.01.2003   0.32  open_mode fixes from Georg Acher <acher@in.tum.de>
  */
 
 /*****************************************************************************/
@@ -1995,7 +1996,7 @@
 		stop_adc(s);
 		dealloc_dmabuf(s, &s->dma_adc);
 	}
-	s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
+	s->open_mode &= ~(file->f_mode & (FMODE_READ|FMODE_WRITE));
 	up(&s->open_sem);
 	wake_up(&s->open_wait);
 	unlock_kernel();
@@ -2670,7 +2671,7 @@
 		set_current_state(TASK_RUNNING);
 	}
 	down(&s->open_sem);
-	s->open_mode &= (~(file->f_mode << FMODE_MIDI_SHIFT)) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE);
+	s->open_mode &= ~((file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE));
 	spin_lock_irqsave(&s->lock, flags);
 	if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
 		s->ctrl &= ~CTRL_UART_EN;
@@ -2982,6 +2983,11 @@
  err_gp:
 	if (s->gameport.io)
 		release_region(s->gameport.io, JOY_EXTENT);
+#ifdef ES1371_DEBUG
+	if (s->ps)
+		remove_proc_entry("es1371", NULL);
+#endif
+	unregister_sound_midi(s->dev_midi);
  err_dev4:
 	unregister_sound_dsp(s->dev_dac);
  err_dev3:
@@ -3046,7 +3052,7 @@
 {
 	if (!pci_present())   /* No PCI bus in this machine! */
 		return -ENODEV;
-	printk(KERN_INFO PFX "version v0.30 time " __TIME__ " " __DATE__ "\n");
+	printk(KERN_INFO PFX "version v0.32 time " __TIME__ " " __DATE__ "\n");
 	return pci_module_init(&es1371_driver);
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/sound/esssolo1.c linux-2.4.21-pre6/drivers/sound/esssolo1.c
--- linux-2.4.20/drivers/sound/esssolo1.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/sound/esssolo1.c	2003-03-26 23:49:07.000000000 +0000
@@ -3,7 +3,7 @@
 /*
  *      esssolo1.c  --  ESS Technology Solo1 (ES1946) audio driver.
  *
- *      Copyright (C) 1998-2001  Thomas Sailer (t.sailer@alumni.ethz.ch)
+ *      Copyright (C) 1998-2001, 2003  Thomas Sailer (t.sailer@alumni.ethz.ch)
  *
  *      This program is free software; you can redistribute it and/or modify
  *      it under the terms of the GNU General Public License as published by
@@ -82,6 +82,7 @@
  *    22.05.2001   0.19  more cleanups, changed PM to PCI 2.4 style, got rid
  *                       of global list of devices, using pci device data.
  *                       Marcus Meissner <mm@caldera.de>
+ *    03.01.2003   0.20  open_mode fixes from Georg Acher <acher@in.tum.de>
  */
 
 /*****************************************************************************/
@@ -1977,7 +1978,7 @@
 		set_current_state(TASK_RUNNING);
 	}
 	down(&s->open_sem);
-	s->open_mode &= (~(file->f_mode << FMODE_MIDI_SHIFT)) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE);
+	s->open_mode &= ~((file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE));
 	spin_lock_irqsave(&s->lock, flags);
 	if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
 		outb(0x30, s->iobase + 7); /* enable A1, A2 irq's */
@@ -2452,7 +2453,7 @@
 {
 	if (!pci_present())   /* No PCI bus in this machine! */
 		return -ENODEV;
-	printk(KERN_INFO "solo1: version v0.19 time " __TIME__ " " __DATE__ "\n");
+	printk(KERN_INFO "solo1: version v0.20 time " __TIME__ " " __DATE__ "\n");
 	if (!pci_register_driver(&solo1_driver)) {
 		pci_unregister_driver(&solo1_driver);
                 return -ENODEV;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/sound/i810_audio.c linux-2.4.21-pre6/drivers/sound/i810_audio.c
--- linux-2.4.20/drivers/sound/i810_audio.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/sound/i810_audio.c	2003-03-26 23:49:51.000000000 +0000
@@ -65,6 +65,20 @@
  *	If you need to force a specific rate set the clocking= option
  *
  *	This driver is cursed. (Ben LaHaise)
+ *
+ *  ICH 3 caveats
+ *	Intel errata #7 for ICH3 IO. We need to disable SMI stuff
+ *	when codec probing. [Not Yet Done]
+ *
+ *  ICH 4 caveats
+ *
+ *      The ICH4 has the feature, that the codec ID doesn't have to be 
+ *      congruent with the IO connection.
+ * 
+ *      Therefore, from driver version 0.23 on, there is a "codec ID" <->
+ *      "IO register base offset" mapping (card->ac97_id_map) field.
+ *   
+ *      Juergen "George" Sawinski (jsaw) 
  */
  
 #include <linux/module.h>
@@ -122,6 +136,9 @@
 #ifndef PCI_DEVICE_ID_AMD_768_AUDIO
 #define PCI_DEVICE_ID_AMD_768_AUDIO	0x7445
 #endif
+#ifndef PCI_DEVICE_ID_AMD_8111_AC97
+#define PCI_DEVICE_ID_AMD_8111_AC97	0x746d
+#endif
 
 static int ftsodell=0;
 static int strict_clocking=0;
@@ -132,6 +149,7 @@
 //#define DEBUG2
 //#define DEBUG_INTERRUPTS
 //#define DEBUG_MMAP
+//#define DEBUG_MMIO
 
 #define ADC_RUNNING	1
 #define DAC_RUNNING	2
@@ -174,6 +192,11 @@
  * each dma engine has controlling registers.  These goofy
  * names are from the datasheet, but make it easy to write
  * code while leafing through it.
+ *
+ * ICH4 has 6 dma engines, pcm in, pcm out, mic, pcm in 2, 
+ * mic in 2, s/pdif.   Of special interest is the fact that
+ * the upper 3 DMA engines on the ICH4 *must* be accessed
+ * via mmio access instead of pio access.
  */
 
 #define ENUM_ENGINE(PRE,DIG) 									\
@@ -198,6 +221,14 @@
 	CAS	 = 	0x34			/* Codec Write Semaphore Register */
 };
 
+ENUM_ENGINE(MC2,4);     /* Mic In 2 */
+ENUM_ENGINE(PI2,5);     /* PCM In 2 */
+ENUM_ENGINE(SP,6);      /* S/PDIF */
+
+enum {
+	SDM =           0x80                    /* SDATA_IN Map Register */
+};
+
 /* interrupts for a dma engine */
 #define DMA_INT_FIFO		(1<<4)  /* fifo under/over flow */
 #define DMA_INT_COMPLETE	(1<<3)  /* buffer read/write complete and ioc set */
@@ -217,8 +248,7 @@
 #define INT_GPI		(1<<0)
 #define INT_MASK (INT_SEC|INT_PRI|INT_MC|INT_PO|INT_PI|INT_MO|INT_NI|INT_GPI)
 
-
-#define DRIVER_VERSION "0.21"
+#define DRIVER_VERSION "0.24"
 
 /* magic numbers to protect our data structures */
 #define I810_CARD_MAGIC		0x5072696E /* "Prin" */
@@ -227,7 +257,7 @@
 #define NR_HW_CH		3
 
 /* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */
-#define NR_AC97		2
+#define NR_AC97                 4
 
 /* Please note that an 8bit mono stream is not valid on this card, you must have a 16bit */
 /* stream at a minimum for this card to be happy */
@@ -262,6 +292,25 @@
 	"AMD-8111 IOHub"
 };
 
+/* These are capabilities (and bugs) the chipsets _can_ have */
+static struct {
+	int16_t      nr_ac97;
+#define CAP_MMIO                 0x0001
+#define CAP_20BIT_AUDIO_SUPPORT  0x0002
+	u_int16_t flags;
+} card_cap[] = {
+	{  1, 0x0000 }, /* ICH82801AA */
+	{  1, 0x0000 }, /* ICH82901AB */
+	{  1, 0x0000 }, /* INTEL440MX */
+	{  1, 0x0000 }, /* INTELICH2 */
+	{  2, 0x0000 }, /* INTELICH3 */
+        {  3, 0x0003 }, /* INTELICH4 */
+	/*@FIXME to be verified*/	{  2, 0x0000 }, /* SI7012 */
+	/*@FIXME to be verified*/	{  2, 0x0000 }, /* NVIDIA_NFORCE */
+	/*@FIXME to be verified*/	{  2, 0x0000 }, /* AMD768 */
+	/*@FIXME to be verified*/	{  3, 0x0001 }, /* AMD8111 */
+};
+
 static struct pci_device_id i810_pci_tbl [] __initdata = {
 	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801,
 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, ICH82801AA},
@@ -363,7 +412,6 @@
 
 
 struct i810_card {
-	struct i810_channel channel[3];
 	unsigned int magic;
 
 	/* We keep i810 cards in a linked list */
@@ -376,6 +424,7 @@
 	/* PCI device stuff */
 	struct pci_dev * pci_dev;
 	u16 pci_id;
+	u16 pci_id_internal; /* used to access card_cap[] */
 #ifdef CONFIG_PM	
 	u16 pm_suspended;
 	u32 pm_save_state[64/sizeof(u32)];
@@ -385,17 +434,27 @@
 	int dev_audio;
 
 	/* structures for abstraction of hardware facilities, codecs, banks and channels*/
+	u16    ac97_id_map[NR_AC97];
 	struct ac97_codec *ac97_codec[NR_AC97];
 	struct i810_state *states[NR_HW_CH];
+	struct i810_channel *channel;	/* 1:1 to states[] but diff. lifetime */
+	dma_addr_t chandma;
 
 	u16 ac97_features;
 	u16 ac97_status;
 	u16 channels;
 	
 	/* hardware resources */
-	unsigned long iobase;
 	unsigned long ac97base;
+	unsigned long iobase;
 	u32 irq;
+
+	unsigned long ac97base_mmio_phys;
+	unsigned long iobase_mmio_phys;
+	u_int8_t *ac97base_mmio;
+	u_int8_t *iobase_mmio;
+
+	int           use_mmio;
 	
 	/* Function support */
 	struct i810_channel *(*alloc_pcm_channel)(struct i810_card *);
@@ -408,6 +467,12 @@
 	int initializing;
 };
 
+/* extract register offset from codec struct */
+#define IO_REG_OFF(codec) (((struct i810_card *) codec->private_data)->ac97_id_map[codec->id])
+
+/* set LVI from CIV */
+#define CIV_TO_LVI(port, off) outb((inb(port+OFF_CIV)+off) & 31, port+OFF_LVI)
+
 static struct i810_card *devs = NULL;
 
 static int i810_open_mixdev(struct inode *inode, struct file *file);
@@ -415,6 +480,10 @@
 			     unsigned int cmd, unsigned long arg);
 static u16 i810_ac97_get(struct ac97_codec *dev, u8 reg);
 static void i810_ac97_set(struct ac97_codec *dev, u8 reg, u16 data);
+static u16 i810_ac97_get_mmio(struct ac97_codec *dev, u8 reg);
+static void i810_ac97_set_mmio(struct ac97_codec *dev, u8 reg, u16 data);
+static u16 i810_ac97_get_io(struct ac97_codec *dev, u8 reg);
+static void i810_ac97_set_io(struct ac97_codec *dev, u8 reg, u16 data);
 
 static struct i810_channel *i810_alloc_pcm_channel(struct i810_card *card)
 {
@@ -574,6 +643,11 @@
 {
 	int	aud_reg;
 	struct ac97_codec *codec = state->card->ac97_codec[0];
+	
+	/* No codec, no setup */
+	
+	if(codec == NULL)
+		return;
 
 	aud_reg = i810_ac97_get(codec, AC97_EXTENDED_STATUS);
 	aud_reg |= AC97_EA_PRI | AC97_EA_PRJ | AC97_EA_PRK;
@@ -766,7 +840,8 @@
 	if (dmabuf->count < dmabuf->dmasize && dmabuf->ready && !dmabuf->enable &&
 	    (dmabuf->trigger & PCM_ENABLE_INPUT)) {
 		dmabuf->enable |= ADC_RUNNING;
-		outb((1<<4) | (1<<2) | 1, state->card->iobase + PI_CR);
+		// Interrupt enable, LVI enable, DMA enable
+		outb(0x10 | 0x04 | 0x01, state->card->iobase + PI_CR);
 	}
 }
 
@@ -815,7 +890,8 @@
 	if (dmabuf->count > 0 && dmabuf->ready && !dmabuf->enable &&
 	    (dmabuf->trigger & PCM_ENABLE_OUTPUT)) {
 		dmabuf->enable |= DAC_RUNNING;
-		outb((1<<4) | (1<<2) | 1, state->card->iobase + PO_CR);
+		// Interrupt enable, LVI enable, DMA enable
+		outb(0x10 | 0x04 | 0x01, state->card->iobase + PO_CR);
 	}
 }
 static void start_dac(struct i810_state *state)
@@ -967,7 +1043,7 @@
 	  
 		for(i=0;i<dmabuf->numfrag;i++)
 		{
-			sg->busaddr=virt_to_bus(dmabuf->rawbuf+dmabuf->fragsize*i);
+			sg->busaddr=(u32)dmabuf->dma_handle+dmabuf->fragsize*i;
 			// the card will always be doing 16bit stereo
 			sg->control=dmabuf->fragsamples;
 			if(state->card->pci_id == PCI_DEVICE_ID_SI_7012)
@@ -982,9 +1058,11 @@
 		}
 		spin_lock_irqsave(&state->card->lock, flags);
 		outb(2, state->card->iobase+c->port+OFF_CR);   /* reset DMA machine */
-		outl(virt_to_bus(&c->sg[0]), state->card->iobase+c->port+OFF_BDBAR);
-		outb(0, state->card->iobase+c->port+OFF_CIV);
-		outb(0, state->card->iobase+c->port+OFF_LVI);
+		while( inb(state->card->iobase+c->port+OFF_CR) & 0x02 ) ;
+		outl((u32)state->card->chandma +
+		    c->num*sizeof(struct i810_channel),
+		    state->card->iobase+c->port+OFF_BDBAR);
+		CIV_TO_LVI(state->card->iobase+c->port, 0);
 
 		spin_unlock_irqrestore(&state->card->lock, flags);
 
@@ -1030,13 +1108,13 @@
 		if(rec && dmabuf->count < dmabuf->dmasize &&
 		   (dmabuf->trigger & PCM_ENABLE_INPUT))
 		{
-			outb((inb(port+OFF_CIV)+1)&31, port+OFF_LVI);
+			CIV_TO_LVI(port, 1);
 			__start_adc(state);
 			while( !(inb(port + OFF_CR) & ((1<<4) | (1<<2))) ) ;
 		} else if (!rec && dmabuf->count &&
 			   (dmabuf->trigger & PCM_ENABLE_OUTPUT))
 		{
-			outb((inb(port+OFF_CIV)+1)&31, port+OFF_LVI);
+			CIV_TO_LVI(port, 1);
 			__start_dac(state);
 			while( !(inb(port + OFF_CR) & ((1<<4) | (1<<2))) ) ;
 		}
@@ -1304,7 +1382,6 @@
 				if (dmabuf->enable & ADC_RUNNING)
 					__stop_adc(state);
 				dmabuf->enable = 0;
-				wake_up(&dmabuf->wait);
 #ifdef DEBUG_INTERRUPTS
 				printk(" STOP ");
 #endif
@@ -1750,9 +1827,11 @@
 		}
 		if (c != NULL) {
 			outb(2, state->card->iobase+c->port+OFF_CR);   /* reset DMA machine */
-			outl(virt_to_bus(&c->sg[0]), state->card->iobase+c->port+OFF_BDBAR);
-			outb(0, state->card->iobase+c->port+OFF_CIV);
-			outb(0, state->card->iobase+c->port+OFF_LVI);
+			while ( inb(state->card->iobase+c->port+OFF_CR) & 2 );
+			outl((u32)state->card->chandma +
+			    c->num*sizeof(struct i810_channel),
+			    state->card->iobase+c->port+OFF_BDBAR);
+			CIV_TO_LVI(state->card->iobase+c->port, 0);
 		}
 
 		spin_unlock_irqrestore(&state->card->lock, flags);
@@ -1874,7 +1953,8 @@
 		}
 
 		/* ICH and ICH0 only support 2 channels */
-		if ( state->card->pci_id == 0x2415 || state->card->pci_id == 0x2425 ) 
+		if ( state->card->pci_id == PCI_DEVICE_ID_INTEL_82801 
+		     || state->card->pci_id == PCI_DEVICE_ID_INTEL_82901) 
 			return put_user(2, (int *)arg);
 	
 		/* Multi-channel support was added with ICH2. Bits in */
@@ -1893,12 +1973,14 @@
 
 		switch ( val ) {
 			case 2: /* 2 channels is always supported */
-				outl(state->card->iobase + GLOB_CNT, (i_glob_cnt & 0xcfffff));
+				outl(i_glob_cnt & 0xffcfffff,
+				     state->card->iobase + GLOB_CNT);
 				/* Do we need to change mixer settings????  */
 				break;
 			case 4: /* Supported on some chipsets, better check first */
 				if ( state->card->channels >= 4 ) {
-					outl(state->card->iobase + GLOB_CNT, ((i_glob_cnt & 0xcfffff) | 0x0100000));
+					outl((i_glob_cnt & 0xffcfffff) | 0x100000,
+					      state->card->iobase + GLOB_CNT);
 					/* Do we need to change mixer settings??? */
 				} else {
 					val = ret;
@@ -1906,7 +1988,8 @@
 				break;
 			case 6: /* Supported on some chipsets, better check first */
 				if ( state->card->channels >= 6 ) {
-					outl(state->card->iobase + GLOB_CNT, ((i_glob_cnt & 0xcfffff) | 0x0200000));
+					outl((i_glob_cnt & 0xffcfffff) | 0x200000,
+					      state->card->iobase + GLOB_CNT);
 					/* Do we need to change mixer settings??? */
 				} else {
 					val = ret;
@@ -2111,14 +2194,14 @@
 #if defined(DEBUG) || defined(DEBUG_MMAP)
 		printk("SNDCTL_DSP_SETTRIGGER 0x%x\n", val);
 #endif
-		if( !(val & PCM_ENABLE_INPUT) && dmabuf->enable == ADC_RUNNING) {
+		if((file->f_mode & FMODE_READ) && !(val & PCM_ENABLE_INPUT) && dmabuf->enable == ADC_RUNNING) {
 			stop_adc(state);
 		}
-		if( !(val & PCM_ENABLE_OUTPUT) && dmabuf->enable == DAC_RUNNING) {
+		if((file->f_mode & FMODE_WRITE) && !(val & PCM_ENABLE_OUTPUT) && dmabuf->enable == DAC_RUNNING) {
 			stop_dac(state);
 		}
 		dmabuf->trigger = val;
-		if(val & PCM_ENABLE_OUTPUT && !(dmabuf->enable & DAC_RUNNING)) {
+		if((file->f_mode & FMODE_WRITE) && (val & PCM_ENABLE_OUTPUT) && !(dmabuf->enable & DAC_RUNNING)) {
 			if (!dmabuf->write_channel) {
 				dmabuf->ready = 0;
 				dmabuf->write_channel = state->card->alloc_pcm_channel(state->card);
@@ -2139,7 +2222,7 @@
 			} else
 				start_dac(state);
 		}
-		if(val & PCM_ENABLE_INPUT && !(dmabuf->enable & ADC_RUNNING)) {
+		if((file->f_mode & FMODE_READ) && (val & PCM_ENABLE_INPUT) && !(dmabuf->enable & ADC_RUNNING)) {
 			if (!dmabuf->read_channel) {
 				dmabuf->ready = 0;
 				dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card);
@@ -2424,6 +2507,9 @@
 			i810_set_spdif_output(state, AC97_EA_SPSA_3_4, spdif_locked);
 		} else {
 			i810_set_dac_rate(state, 8000);
+			/* Put the ACLink in 2 channel mode by default */
+			i = inl(card->iobase + GLOB_CNT);
+			outl(i & 0xffcfffff, card->iobase + GLOB_CNT);
 		}
 	}
 		
@@ -2488,27 +2574,86 @@
 
 /* Write AC97 codec registers */
 
-static u16 i810_ac97_get(struct ac97_codec *dev, u8 reg)
+static u16 i810_ac97_get_mmio(struct ac97_codec *dev, u8 reg)
 {
 	struct i810_card *card = dev->private_data;
 	int count = 100;
-	u8 reg_set = ((dev->id)?((reg&0x7f)|0x80):(reg&0x7f));
+	u16 reg_set = IO_REG_OFF(dev) | (reg&0x7f);
+	
+	while(count-- && (readb(card->iobase_mmio + CAS) & 1)) 
+		udelay(1);
+	
+#ifdef DEBUG_MMIO
+	{
+		u16 ans = readw(card->ac97base_mmio + reg_set);
+		printk(KERN_DEBUG "i810_audio: ac97_get_mmio(%d) -> 0x%04X\n", ((int) reg_set) & 0xffff, (u32) ans);
+		return ans;
+	}
+#else
+	return readw(card->ac97base_mmio + reg_set);
+#endif
+}
 
+static u16 i810_ac97_get_io(struct ac97_codec *dev, u8 reg)
+{
+	struct i810_card *card = dev->private_data;
+	int count = 100;
+	u16 reg_set = IO_REG_OFF(dev) | (reg&0x7f);
+	
 	while(count-- && (inb(card->iobase + CAS) & 1)) 
 		udelay(1);
 	
 	return inw(card->ac97base + reg_set);
 }
 
-static void i810_ac97_set(struct ac97_codec *dev, u8 reg, u16 data)
+static void i810_ac97_set_mmio(struct ac97_codec *dev, u8 reg, u16 data)
 {
 	struct i810_card *card = dev->private_data;
 	int count = 100;
-	u8 reg_set = ((dev->id)?((reg&0x7f)|0x80):(reg&0x7f));
+	u16 reg_set = IO_REG_OFF(dev) | (reg&0x7f);
+	
+	while(count-- && (readb(card->iobase_mmio + CAS) & 1)) 
+		udelay(1);
+	
+	writew(data, card->ac97base_mmio + reg_set);
 
+#ifdef DEBUG_MMIO
+	printk(KERN_DEBUG "i810_audio: ac97_set_mmio(0x%04X, %d)\n", (u32) data, ((int) reg_set) & 0xffff);
+#endif
+}
+
+static void i810_ac97_set_io(struct ac97_codec *dev, u8 reg, u16 data)
+{
+	struct i810_card *card = dev->private_data;
+	int count = 100;
+	u16 reg_set = IO_REG_OFF(dev) | (reg&0x7f);
+	
 	while(count-- && (inb(card->iobase + CAS) & 1)) 
 		udelay(1);
-	outw(data, card->ac97base + reg_set);
+	
+        outw(data, card->ac97base + reg_set);
+}
+
+static u16 i810_ac97_get(struct ac97_codec *dev, u8 reg)
+{
+	struct i810_card *card = dev->private_data;
+	if (card->use_mmio) {
+		return i810_ac97_get_mmio(dev, reg);
+	}
+	else {
+		return i810_ac97_get_io(dev, reg);
+	}
+}
+
+static void i810_ac97_set(struct ac97_codec *dev, u8 reg, u16 data)
+{
+	struct i810_card *card = dev->private_data;
+	if (card->use_mmio) {
+		i810_ac97_set_mmio(dev, reg, data);
+	}
+	else {
+		i810_ac97_set_io(dev, reg, data);
+	}
 }
 
 
@@ -2533,7 +2678,7 @@
 			set_current_state(TASK_UNINTERRUPTIBLE);
 			schedule_timeout(HZ/20);
 		}
-		for (i = 0; i < NR_AC97 && card && !card->initializing; i++)
+		for (i = 0; i < NR_AC97 && card && !card->initializing; i++) 
 			if (card->ac97_codec[i] != NULL &&
 			    card->ac97_codec[i]->dev_mixer == minor) {
 				file->private_data = card->ac97_codec[i];
@@ -2561,10 +2706,18 @@
 /* AC97 codec initialisation.  These small functions exist so we don't
    duplicate code between module init and apm resume */
 
-static inline int i810_ac97_exists(struct i810_card *card,int ac97_number)
+static inline int i810_ac97_exists(struct i810_card *card, int ac97_number)
 {
 	u32 reg = inl(card->iobase + GLOB_STA);
-	return (reg & (0x100 << ac97_number));
+	switch (ac97_number) {
+	case 0:
+		return reg & (1<<8);
+	case 1: 
+		return reg & (1<<9);
+	case 2:
+		return reg & (1<<28);
+	}
+	return 0;
 }
 
 static inline int i810_ac97_enable_variable_rate(struct ac97_codec *codec)
@@ -2587,10 +2740,9 @@
 	/* power it all up */
 	i810_ac97_set(codec, AC97_POWER_CONTROL,
 		      i810_ac97_get(codec, AC97_POWER_CONTROL) & ~0x7f00);
+
 	/* wait for analog ready */
-	for (i=10;
-	     i && ((i810_ac97_get(codec, AC97_POWER_CONTROL) & 0xf) != 0xf);
-	     i--)
+	for (i=10; i && ((i810_ac97_get(codec, AC97_POWER_CONTROL) & 0xf) != 0xf); i--)
 	{
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		schedule_timeout(HZ/20);
@@ -2598,11 +2750,18 @@
 	return i;
 }
 
-/* if I knew what this did, I'd give it a better name */
-static int i810_ac97_random_init_stuff(struct i810_card *card)
+/**
+ *	i810_ac97_power_up_bus	-	bring up AC97 link
+ *	@card : ICH audio device to power up
+ *
+ *	Bring up the ACLink AC97 codec bus
+ */
+ 
+static int i810_ac97_power_up_bus(struct i810_card *card)
 {	
 	u32 reg = inl(card->iobase + GLOB_CNT);
 	int i;
+	int primary_codec_id = 0;
 
 	if((reg&2)==0)	/* Cold required */
 		reg|=2;
@@ -2610,8 +2769,13 @@
 		reg|=4;	/* Warm */
 		
 	reg&=~8;	/* ACLink on */
-	outl(reg , card->iobase + GLOB_CNT);
 	
+	/* At this point we deassert AC_RESET # */
+	outl(reg , card->iobase + GLOB_CNT);
+
+	/* We must now allow time for the Codec initialisation.
+	   600mS is the specified time */
+	   	
 	for(i=0;i<10;i++)
 	{
 		if((inl(card->iobase+GLOB_CNT)&4)==0)
@@ -2628,7 +2792,31 @@
 
 	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule_timeout(HZ/2);
-	reg = inl(card->iobase + GLOB_STA);
+
+	/*
+	 *	See if the primary codec comes ready. This must happen
+	 *	before we start doing DMA stuff
+	 */	
+	/* see i810_ac97_init for the next 7 lines (jsaw) */
+	inw(card->ac97base);
+	if ((card->pci_id == PCI_DEVICE_ID_INTEL_ICH4)
+	    && (card->use_mmio)) {
+		primary_codec_id = (int) readl(card->iobase_mmio + SDM) & 0x3;
+		printk(KERN_INFO "i810_audio: Primary codec has ID %d\n",
+		       primary_codec_id);
+	}
+
+	if(! i810_ac97_exists(card, primary_codec_id))
+	{
+		printk(KERN_INFO "i810_audio: Codec not ready.. wait.. ");
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(HZ);	/* actually 600mS by the spec */
+
+		if(i810_ac97_exists(card, primary_codec_id))
+			printk("OK\n");
+		else 
+			printk("no response.\n");
+	}
 	inw(card->ac97base);
 	return 1;
 }
@@ -2636,12 +2824,14 @@
 static int __init i810_ac97_init(struct i810_card *card)
 {
 	int num_ac97 = 0;
+	int ac97_id;
 	int total_channels = 0;
+	int nr_ac97_max = card_cap[card->pci_id_internal].nr_ac97;
 	struct ac97_codec *codec;
 	u16 eid;
 	u32 reg;
 
-	if(!i810_ac97_random_init_stuff(card)) return 0;
+	if(!i810_ac97_power_up_bus(card)) return 0;
 
 	/* Number of channels supported */
 	/* What about the codec?  Just because the ICH supports */
@@ -2657,26 +2847,47 @@
 		card->channels = 6;
 	else if ( reg & 0x0100000 )
 		card->channels = 4;
-	printk("i810_audio: Audio Controller supports %d channels.\n", card->channels);
+	printk(KERN_INFO "i810_audio: Audio Controller supports %d channels.\n", card->channels);
+	printk(KERN_INFO "i810_audio: Defaulting to base 2 channel mode.\n");
+	reg = inl(card->iobase + GLOB_CNT);
+	outl(reg & 0xffcfffff, card->iobase + GLOB_CNT);
 		
-	inw(card->ac97base);
+	for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) 
+		card->ac97_codec[num_ac97] = NULL;
 
-	for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
+	/*@FIXME I don't know, if I'm playing to safe here... (jsaw) */
+	if ((nr_ac97_max > 2) && !card->use_mmio) nr_ac97_max = 2;
 
-		/* Assume codec isn't available until we go through the
-		 * gauntlet below */
-		card->ac97_codec[num_ac97] = NULL;
+	for (num_ac97 = 0; num_ac97 < nr_ac97_max; num_ac97++) {
+		/* codec reset */
+		printk(KERN_INFO "i810_audio: Resetting connection %d\n", num_ac97);
+		if (card->use_mmio) readw(card->ac97base_mmio + 0x80*num_ac97);
+		else inw(card->ac97base + 0x80*num_ac97);
+
+		/* If we have the SDATA_IN Map Register, as on ICH4, we
+		   do not loop thru all possible codec IDs but thru all 
+		   possible IO channels. Bit 0:1 of SDM then holds the 
+		   last codec ID spoken to. 
+		*/
+		if ((card->pci_id == PCI_DEVICE_ID_INTEL_ICH4)
+		    && (card->use_mmio)) {
+			ac97_id = (int) readl(card->iobase_mmio + SDM) & 0x3;
+			printk(KERN_INFO "i810_audio: Connection %d with codec id %d\n",
+			       num_ac97, ac97_id);
+		}
+		else {
+			ac97_id = num_ac97;
+		}
 
 		/* The ICH programmer's reference says you should   */
 		/* check the ready status before probing. So we chk */
 		/*   What do we do if it's not ready?  Wait and try */
 		/*   again, or abort?                               */
-		if (!i810_ac97_exists(card,num_ac97)) {
+		if (!i810_ac97_exists(card, ac97_id)) {
 			if(num_ac97 == 0)
 				printk(KERN_ERR "i810_audio: Primary codec not ready.\n");
-			break; /* I think this works, if not ready stop */
 		}
-
+		
 		if ((codec = kmalloc(sizeof(struct ac97_codec), GFP_KERNEL)) == NULL)
 			return -ENOMEM;
 		memset(codec, 0, sizeof(struct ac97_codec));
@@ -2684,13 +2895,20 @@
 		/* initialize some basic codec information, other fields will be filled
 		   in ac97_probe_codec */
 		codec->private_data = card;
-		codec->id = num_ac97;
+		codec->id = ac97_id;
+		card->ac97_id_map[ac97_id] = num_ac97 * 0x80;
 
-		codec->codec_read = i810_ac97_get;
-		codec->codec_write = i810_ac97_set;
+		if (card->use_mmio) {	
+			codec->codec_read = i810_ac97_get_mmio;
+			codec->codec_write = i810_ac97_set_mmio;
+		}
+		else {
+			codec->codec_read = i810_ac97_get_io;
+			codec->codec_write = i810_ac97_set_io;
+		}
 	
 		if(!i810_ac97_probe_and_powerup(card,codec)) {
-			printk("i810_audio: timed out waiting for codec %d analog ready.\n", num_ac97);
+			printk(KERN_ERR "i810_audio: timed out waiting for codec %d analog ready.\n", ac97_id);
 			kfree(codec);
 			break;	/* it didn't work */
 		}
@@ -2699,7 +2917,7 @@
 		
 		/* Don't attempt to get eid until powerup is complete */
 		eid = i810_ac97_get(codec, AC97_EXTENDED_ID);
-		
+
 		if(eid==0xFFFFFF)
 		{
 			printk(KERN_WARNING "i810_audio: no codec attached ?\n");
@@ -2707,16 +2925,27 @@
 			break;
 		}
 		
+		/* Check for an AC97 1.0 soft modem (ID1) */
+		
+		if(codec->codec_read(codec, AC97_RESET) & 2)
+		{
+			printk(KERN_WARNING "i810_audio: codec %d is an AC97 1.0 softmodem - skipping.\n", ac97_id);
+			kfree(codec);
+			continue;
+		}
+		
+		/* Check for an AC97 2.x soft modem */
+		
 		codec->codec_write(codec, AC97_EXTENDED_MODEM_ID, 0L);
-		if(codec->codec_read(codec, AC97_EXTENDED_MODEM_ID))
+		if(codec->codec_read(codec, AC97_EXTENDED_MODEM_ID) & 1)
 		{
-			printk(KERN_WARNING "i810_audio: codec %d is a softmodem - skipping.\n", num_ac97);
+			printk(KERN_WARNING "i810_audio: codec %d is an AC97 2.x softmodem - skipping.\n", ac97_id);
 			kfree(codec);
 			continue;
 		}
 	
 		card->ac97_features = eid;
-				
+
 		/* Now check the codec for useful features to make up for
 		   the dumbness of the 810 hardware engine */
 
@@ -2730,6 +2959,11 @@
 			}			
 		}
    		
+		/* Turn on the amplifier */
+
+		codec->codec_write(codec, AC97_POWER_CONTROL, 
+			 codec->codec_read(codec, AC97_POWER_CONTROL) & ~0x8000);
+				
 		/* Determine how many channels the codec(s) support   */
 		/*   - The primary codec always supports 2            */
 		/*   - If the codec supports AMAP, surround DACs will */
@@ -2755,7 +2989,7 @@
 				total_channels += 2;
 			if (eid & 0x0140) /* LFE and Center channels */
 				total_channels += 2;
-			printk("i810_audio: AC'97 codec %d supports AMAP, total channels = %d\n", num_ac97, total_channels);
+			printk("i810_audio: AC'97 codec %d supports AMAP, total channels = %d\n", ac97_id, total_channels);
 		} else if (eid & 0x0400) {  /* this only works on 2.2 compliant codecs */
 			eid &= 0xffcf;
 			if((eid & 0xc000) != 0)	{
@@ -2777,14 +3011,14 @@
 			}
 			i810_ac97_set(codec, AC97_EXTENDED_ID, eid);
 			eid = i810_ac97_get(codec, AC97_EXTENDED_ID);
-			printk("i810_audio: AC'97 codec %d, new EID value = 0x%04x\n", num_ac97, eid);
+			printk("i810_audio: AC'97 codec %d, new EID value = 0x%04x\n", ac97_id, eid);
 			if (eid & 0x0080) /* L/R Surround channels */
 				total_channels += 2;
 			if (eid & 0x0140) /* LFE and Center channels */
 				total_channels += 2;
-			printk("i810_audio: AC'97 codec %d, DAC map configured, total channels = %d\n", num_ac97, total_channels);
+			printk("i810_audio: AC'97 codec %d, DAC map configured, total channels = %d\n", ac97_id, total_channels);
 		} else {
-			printk("i810_audio: AC'97 codec %d Unable to map surround DAC's (or DAC's not present), total channels = %d\n", num_ac97, total_channels);
+			printk("i810_audio: AC'97 codec %d Unable to map surround DAC's (or DAC's not present), total channels = %d\n", ac97_id, total_channels);
 		}
 
 		if ((codec->dev_mixer = register_sound_mixer(&i810_mixer_fops, -1)) < 0) {
@@ -2833,6 +3067,8 @@
 		init_MUTEX(&state->open_sem);
 		dmabuf->fmt = I810_FMT_STEREO | I810_FMT_16BIT;
 		dmabuf->trigger = PCM_ENABLE_OUTPUT;
+		i810_set_spdif_output(state, -1, 0);
+		i810_set_dac_channels(state, 2);
 		i810_set_dac_rate(state, 48000);
 		if(prog_dmabuf(state, 0) != 0) {
 			goto config_out_nodmabuf;
@@ -2841,7 +3077,7 @@
 			goto config_out;
 		}
 		dmabuf->count = dmabuf->dmasize;
-		outb(31,card->iobase+dmabuf->write_channel->port+OFF_LVI);
+		CIV_TO_LVI(card->iobase+dmabuf->write_channel->port, 31);
 		save_flags(flags);
 		cli();
 		start_dac(state);
@@ -2849,10 +3085,9 @@
 		mdelay(50);
 		new_offset = i810_get_dma_addr(state, 0);
 		stop_dac(state);
-		outb(2,card->iobase+dmabuf->write_channel->port+OFF_CR);
 		restore_flags(flags);
 		i = new_offset - offset;
-#ifdef DEBUG
+#ifdef DEBUG_INTERRUPTS
 		printk("i810_audio: %d bytes in 50 milliseconds\n", i);
 #endif
 		if(i == 0)
@@ -2894,10 +3129,25 @@
 	memset(card, 0, sizeof(*card));
 
 	card->initializing = 1;
-	card->iobase = pci_resource_start (pci_dev, 1);
-	card->ac97base = pci_resource_start (pci_dev, 0);
 	card->pci_dev = pci_dev;
 	card->pci_id = pci_id->device;
+	card->ac97base = pci_resource_start (pci_dev, 0);
+	card->iobase = pci_resource_start (pci_dev, 1);
+
+	/* if chipset could have mmio capability, check it */ 
+	if (card_cap[pci_id->driver_data].flags & CAP_MMIO) {
+		card->ac97base_mmio_phys = pci_resource_start (pci_dev, 2);
+		card->iobase_mmio_phys = pci_resource_start (pci_dev, 3);
+
+		if ((card->ac97base_mmio_phys) && (card->iobase_mmio_phys)) {
+			card->use_mmio = 1;
+		}
+		else {
+			card->ac97base_mmio_phys = 0;
+			card->iobase_mmio_phys = 0;
+		}
+	}
+
 	card->irq = pci_dev->irq;
 	card->next = devs;
 	card->magic = I810_CARD_MAGIC;
@@ -2909,23 +3159,37 @@
 
 	pci_set_master(pci_dev);
 
-	printk(KERN_INFO "i810: %s found at IO 0x%04lx and 0x%04lx, IRQ %d\n",
-	       card_names[pci_id->driver_data], card->iobase, card->ac97base, 
+	printk(KERN_INFO "i810: %s found at IO 0x%04lx and 0x%04lx, "
+	       "MEM 0x%04lx and 0x%04lx, IRQ %d\n",
+	       card_names[pci_id->driver_data], 
+	       card->iobase, card->ac97base, 
+	       card->ac97base_mmio_phys, card->iobase_mmio_phys,
 	       card->irq);
 
 	card->alloc_pcm_channel = i810_alloc_pcm_channel;
 	card->alloc_rec_pcm_channel = i810_alloc_rec_pcm_channel;
 	card->alloc_rec_mic_channel = i810_alloc_rec_mic_channel;
 	card->free_pcm_channel = i810_free_pcm_channel;
-	card->channel[0].offset = 0;
-	card->channel[0].port = 0x00;
-	card->channel[0].num=0;
-	card->channel[1].offset = 0;
-	card->channel[1].port = 0x10;
-	card->channel[1].num=1;
-	card->channel[2].offset = 0;
-	card->channel[2].port = 0x20;
-	card->channel[2].num=2;
+
+	if ((card->channel = pci_alloc_consistent(pci_dev,
+	    sizeof(struct i810_channel)*NR_HW_CH, &card->chandma)) == NULL) {
+		printk(KERN_ERR "i810: cannot allocate channel DMA memory\n");
+		goto out_mem;
+	}
+
+	{ /* We may dispose of this altogether some time soon, so... */
+		struct i810_channel *cp = card->channel;
+
+		cp[0].offset = 0;
+		cp[0].port = 0x00;
+		cp[0].num = 0;
+		cp[1].offset = 0;
+		cp[1].port = 0x10;
+		cp[1].num = 1;
+		cp[2].offset = 0;
+		cp[2].port = 0x20;
+		cp[2].num = 2;
+	}
 
 	/* claim our iospace and irq */
 	request_region(card->iobase, 64, card_names[pci_id->driver_data]);
@@ -2934,19 +3198,42 @@
 	if (request_irq(card->irq, &i810_interrupt, SA_SHIRQ,
 			card_names[pci_id->driver_data], card)) {
 		printk(KERN_ERR "i810_audio: unable to allocate irq %d\n", card->irq);
-		release_region(card->iobase, 64);
-		release_region(card->ac97base, 256);
-		kfree(card);
-		return -ENODEV;
+		goto out_pio;
+	}
+
+	if (card->use_mmio) {
+		if (request_mem_region(card->ac97base_mmio_phys, 512, "ich_audio MMBAR")) {
+			if ((card->ac97base_mmio = ioremap(card->ac97base_mmio_phys, 512))) { /*@FIXME can ioremap fail? don't know (jsaw) */
+				if (request_mem_region(card->iobase_mmio_phys, 256, "ich_audio MBBAR")) {
+					if ((card->iobase_mmio = ioremap(card->iobase_mmio_phys, 256))) {
+						printk(KERN_INFO "i810: %s mmio at 0x%04lx and 0x%04lx\n",
+						       card_names[pci_id->driver_data], 
+						       (unsigned long) card->ac97base_mmio, 
+						       (unsigned long) card->iobase_mmio); 
+					}
+					else {
+						iounmap(card->ac97base_mmio);
+						release_mem_region(card->ac97base_mmio_phys, 512);
+						release_mem_region(card->iobase_mmio_phys, 512);
+						card->use_mmio = 0;
+					}
+				}
+				else {
+					iounmap(card->ac97base_mmio);
+					release_mem_region(card->ac97base_mmio_phys, 512);
+					card->use_mmio = 0;
+				}
+			}
+		}
+		else {
+			card->use_mmio = 0;
+		}
 	}
 
 	/* initialize AC97 codec and register /dev/mixer */
 	if (i810_ac97_init(card) <= 0) {
-		release_region(card->iobase, 64);
-		release_region(card->ac97base, 256);
 		free_irq(card->irq, card);
-		kfree(card);
-		return -ENODEV;
+		goto out_iospace;
 	}
 	pci_set_drvdata(pci_dev, card);
 
@@ -2959,19 +3246,34 @@
 	if ((card->dev_audio = register_sound_dsp(&i810_audio_fops, -1)) < 0) {
 		int i;
 		printk(KERN_ERR "i810_audio: couldn't register DSP device!\n");
-		release_region(card->iobase, 64);
-		release_region(card->ac97base, 256);
 		free_irq(card->irq, card);
 		for (i = 0; i < NR_AC97; i++)
 		if (card->ac97_codec[i] != NULL) {
 			unregister_sound_mixer(card->ac97_codec[i]->dev_mixer);
 			kfree (card->ac97_codec[i]);
 		}
-		kfree(card);
-		return -ENODEV;
+		goto out_iospace;
 	}
+
  	card->initializing = 0;
 	return 0;
+
+out_iospace:
+	if (card->use_mmio) {
+		iounmap(card->ac97base_mmio);
+		iounmap(card->iobase_mmio);
+		release_mem_region(card->ac97base_mmio_phys, 512);
+		release_mem_region(card->iobase_mmio_phys, 256);
+	}
+out_pio:	
+	release_region(card->iobase, 64);
+	release_region(card->ac97base, 256);
+out_chan:
+	pci_free_consistent(pci_dev, sizeof(struct i810_channel)*NR_HW_CH,
+	    card->channel, card->chandma);
+out_mem:
+	kfree(card);
+	return -ENODEV;
 }
 
 static void __devexit i810_remove(struct pci_dev *pci_dev)
@@ -2982,6 +3284,12 @@
 	free_irq(card->irq, devs);
 	release_region(card->iobase, 64);
 	release_region(card->ac97base, 256);
+	if (card->use_mmio) {
+		iounmap(card->ac97base_mmio);
+		iounmap(card->iobase_mmio);
+		release_mem_region(card->ac97base_mmio_phys, 512);
+		release_mem_region(card->iobase_mmio_phys, 256);
+	}
 
 	/* unregister audio devices */
 	for (i = 0; i < NR_AC97; i++)
@@ -3064,7 +3372,7 @@
 	   hardware has to be more or less completely reinitialized from
 	   scratch after an apm suspend.  Works For Me.   -dan */
 
-	i810_ac97_random_init_stuff(card);
+	i810_ac97_power_up_bus(card);
 
 	for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
 		struct ac97_codec *codec = card->ac97_codec[num_ac97];
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/sound/kahlua.c linux-2.4.21-pre6/drivers/sound/kahlua.c
--- linux-2.4.20/drivers/sound/kahlua.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/sound/kahlua.c	2003-03-26 23:49:25.000000000 +0000
@@ -0,0 +1,230 @@
+/*
+ *	Initialisation code for Cyrix/NatSemi VSA1 softaudio
+ *
+ *	(C) Copyright 2003 Red Hat Inc <alan@redhat.com>
+ *
+ * XpressAudio(tm) is used on the Cyrix MediaGX (now NatSemi Geode) systems.
+ * The older version (VSA1) provides fairly good soundblaster emulation
+ * although there are a couple of bugs: large DMA buffers break record,
+ * and the MPU event handling seems suspect. VSA2 allows the native driver
+ * to control the AC97 audio engine directly and requires a different driver.
+ *
+ * Thanks to National Semiconductor for providing the needed information
+ * on the XpressAudio(tm) internals.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * For the avoidance of doubt the "preferred form" of this code is one which
+ * is in an open non patent encumbered format. Where cryptographic key signing
+ * forms part of the process of creating an executable the information
+ * including keys needed to generate an equivalently functional executable
+ * are deemed to be part of the source code.
+ *
+ * TO DO:
+ *	Investigate whether we can portably support Cognac (5520) in the
+ *	same manner.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#include "sound_config.h"
+
+#include "sb.h"
+
+/*
+ *	Read a soundblaster compatible mixer register.
+ *	In this case we are actually reading an SMI trap
+ *	not real hardware.
+ */
+
+static u8 __devinit mixer_read(unsigned long io, u8 reg)
+{
+	outb(reg, io + 4);
+	udelay(20);
+	reg = inb(io + 5);
+	udelay(20);
+	return reg;
+}
+
+static int __devinit probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	struct address_info *hw_config;
+	unsigned long base;
+	void *mem;
+	unsigned long io;
+	u16 map;
+	u8 irq, dma8, dma16;
+	int oldquiet;
+	extern int sb_be_quiet;
+		
+	base = pci_resource_start(pdev, 0);
+	if(base == 0UL)
+		return 1;
+	
+	mem = ioremap(base, 128);
+	if(mem == 0UL)
+		return 1;
+	map = readw(mem + 0x18);	/* Read the SMI enables */
+	iounmap(mem);
+	
+	/* Map bits
+		0:1	* 0x20 + 0x200 = sb base
+		2	sb enable
+		3	adlib enable
+		5	MPU enable 0x330
+		6	MPU enable 0x300
+		
+	   The other bits may be used internally so must be masked */
+
+	io = 0x220 + 0x20 * (map & 3);	   
+	
+	if(map & (1<<2))
+		printk(KERN_INFO "kahlua: XpressAudio at 0x%lx\n", io);
+	else
+		return 1;
+		
+	if(map & (1<<5))
+		printk(KERN_INFO "kahlua: MPU at 0x300\n");
+	else if(map & (1<<6))
+		printk(KERN_INFO "kahlua: MPU at 0x330\n");
+	
+	irq = mixer_read(io, 0x80) & 0x0F;
+	dma8 = mixer_read(io, 0x81);
+
+	// printk("IRQ=%x MAP=%x DMA=%x\n", irq, map, dma8);
+	
+	if(dma8 & 0x20)
+		dma16 = 5;
+	else if(dma8 & 0x40)
+		dma16 = 6;
+	else if(dma8 & 0x80)
+		dma16 = 7;
+	else
+	{
+		printk(KERN_ERR "kahlua: No 16bit DMA enabled.\n");
+		return 1;
+	}
+		
+	if(dma8 & 0x01)
+		dma8 = 0;
+	else if(dma8 & 0x02)
+		dma8 = 1;
+	else if(dma8 & 0x08)
+		dma8 = 3;
+	else
+	{
+		printk(KERN_ERR "kahlua: No 8bit DMA enabled.\n");
+		return 1;
+	}
+	
+	if(irq & 1)
+		irq = 9;
+	else if(irq & 2)
+		irq = 5;
+	else if(irq & 4)
+		irq = 7;
+	else if(irq & 8)
+		irq = 10;
+	else
+	{
+		printk(KERN_ERR "kahlua: SB IRQ not set.\n");
+		return 1;
+	}
+	
+	printk(KERN_INFO "kahlua: XpressAudio on IRQ %d, DMA %d, %d\n",
+		irq, dma8, dma16);
+	
+	hw_config = kmalloc(sizeof(struct address_info), GFP_KERNEL);
+	if(hw_config == NULL)
+	{
+		printk(KERN_ERR "kahlua: out of memory.\n");
+		return 1;
+	}
+	memset(hw_config, 0, sizeof(*hw_config));
+	
+	pci_set_drvdata(pdev, hw_config);
+	
+	hw_config->io_base = io;
+	hw_config->irq = irq;
+	hw_config->dma = dma8;
+	hw_config->dma2 = dma16;
+	hw_config->name = "Cyrix XpressAudio";
+	hw_config->driver_use_1 = SB_NO_MIDI | SB_PCI_IRQ;
+	
+	if(sb_dsp_detect(hw_config, 0, 0, NULL)==0)
+	{
+		printk(KERN_ERR "kahlua: audio not responding.\n");
+		return 1;
+	}
+
+	oldquiet = sb_be_quiet;	
+	sb_be_quiet = 1;
+	if(sb_dsp_init(hw_config, THIS_MODULE))
+	{
+		sb_be_quiet = oldquiet;
+		pci_set_drvdata(pdev, NULL);
+		kfree(hw_config);
+		return 1;
+	}
+	sb_be_quiet = oldquiet;
+	
+	return 0;
+}
+
+static void __exit remove_one(struct pci_dev *pdev)
+{
+	struct address_info *hw_config = pci_get_drvdata(pdev);
+	sb_dsp_unload(hw_config, 0);
+	pci_set_drvdata(pdev, NULL);
+	kfree(hw_config);
+}
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("Kahlua VSA1 PCI Audio");
+MODULE_LICENSE("GPL");
+
+/*
+ *	5530 only. The 5510/5520 decode is different.
+ */
+
+static struct pci_device_id id_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_AUDIO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(pci, id_tbl);
+
+static struct pci_driver kahlua_driver = {
+	name:		"kahlua",
+	id_table:	id_tbl,
+	probe:		probe_one,
+	remove:         __devexit_p(remove_one),
+};
+
+
+static int __init kahlua_init_module(void)
+{
+	printk(KERN_INFO "Cyrix Kahlua VSA1 XpressAudio support (c) Copyright 2003 Red Hat Inc\n");
+	return pci_module_init(&kahlua_driver);
+}
+
+static void __exit kahlua_cleanup_module(void)
+{
+	return pci_unregister_driver(&kahlua_driver);
+}
+
+
+module_init(kahlua_init_module);
+module_exit(kahlua_cleanup_module);
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/sound/mad16.c linux-2.4.21-pre6/drivers/sound/mad16.c
--- linux-2.4.20/drivers/sound/mad16.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/sound/mad16.c	2003-03-26 23:49:51.000000000 +0000
@@ -367,6 +367,8 @@
 {
 	unsigned char cfg = 0;
 
+	cfg |= (0x0f & mad16_conf);
+
 	if(c931_detected)
 	{
 		/* Bit 0 has reversd meaning. Bits 1 and 2 sese
@@ -404,7 +406,10 @@
 	   and the C931. */
 	cfg = c931_detected ? 0x04 : 0x00;
 
-	mad_write(MC4_PORT, 0x52|cfg);
+	if(mad16_cdsel & 0x20)
+		mad_write(MC4_PORT, 0x62|cfg);  /* opl4 */
+	else
+		mad_write(MC4_PORT, 0x52|cfg);  /* opl3 */
 
 	mad_write(MC5_PORT, 0x3C);	/* Init it into mode2 */
 	mad_write(MC6_PORT, 0x02);	/* Enable WSS, Disable MPU and SB */
@@ -561,10 +566,10 @@
 	 */
 
 	tmp &= ~0x0f;
+	tmp |= (mad16_conf & 0x0f);   /* CD-ROM and joystick bits */
 	mad_write(MC1_PORT, tmp);
 
-	tmp = mad_read(MC2_PORT);
-
+	tmp = mad16_cdsel;
 	mad_write(MC2_PORT, tmp);
 	mad_write(MC3_PORT, 0xf0);	/* Disable SB */
 
@@ -1051,6 +1056,12 @@
 {
 	if (found_mpu)
 		unload_mad16_mpu(&cfg_mpu);
+	if (gameport.io) {
+		/* the gameport was initialized so we must free it up */
+		gameport_unregister_port(&gameport);
+		gameport.io = 0;
+		release_region(0x201, 1);
+	}
 	unload_mad16(&cfg);
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/sound/maestro.c linux-2.4.21-pre6/drivers/sound/maestro.c
--- linux-2.4.20/drivers/sound/maestro.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/sound/maestro.c	2003-03-26 23:49:25.000000000 +0000
@@ -3359,7 +3359,7 @@
 	/* check to see if we have a capabilities list in
 		the config register */
 	pci_read_config_word(pcidev, PCI_STATUS, &w);
-	if(! w & PCI_STATUS_CAP_LIST) return 0;
+	if(!(w & PCI_STATUS_CAP_LIST)) return 0;
 
 	/* walk the list, starting at the head. */
 	pci_read_config_byte(pcidev,PCI_CAPABILITY_LIST,&next);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/sound/midibuf.c linux-2.4.21-pre6/drivers/sound/midibuf.c
--- linux-2.4.20/drivers/sound/midibuf.c	2001-09-30 19:26:08.000000000 +0000
+++ linux-2.4.21-pre6/drivers/sound/midibuf.c	2003-03-26 23:49:34.000000000 +0000
@@ -129,15 +129,16 @@
 		for (dev = 0; dev < num_midis; dev++)
 			if (midi_devs[dev] != NULL && midi_out_buf[dev] != NULL)
 			{
-				int ok = 1;
-
-				while (DATA_AVAIL(midi_out_buf[dev]) && ok)
+				while (DATA_AVAIL(midi_out_buf[dev]))
 				{
+					int ok;
 					int c = midi_out_buf[dev]->queue[midi_out_buf[dev]->head];
 
 					restore_flags(flags);	/* Give some time to others */
 					ok = midi_devs[dev]->outputc(dev, c);
 					cli();
+					if (!ok)
+						break;
 					midi_out_buf[dev]->head = (midi_out_buf[dev]->head + 1) % MAX_QUEUE_SIZE;
 					midi_out_buf[dev]->len--;
 				}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/sound/mpu401.c linux-2.4.21-pre6/drivers/sound/mpu401.c
--- linux-2.4.20/drivers/sound/mpu401.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/sound/mpu401.c	2003-03-26 23:49:54.000000000 +0000
@@ -1766,8 +1766,8 @@
 
 static struct address_info cfg;
 
-static int __initdata io = -1;
-static int __initdata irq = -1;
+static int io = -1;
+static int irq = -1;
 
 MODULE_PARM(irq, "i");
 MODULE_PARM(io, "i");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/sound/nec_vrc5477.c linux-2.4.21-pre6/drivers/sound/nec_vrc5477.c
--- linux-2.4.20/drivers/sound/nec_vrc5477.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/sound/nec_vrc5477.c	2003-03-26 23:49:50.000000000 +0000
@@ -1187,7 +1187,7 @@
 #endif
 
 		count -= copyCount;
-		totalCopyCount =+ copyCount;
+		totalCopyCount += copyCount;
 		avail -= copyFragCount;
 		totalCopyFragCount += copyFragCount;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/sound/sb_card.c linux-2.4.21-pre6/drivers/sound/sb_card.c
--- linux-2.4.20/drivers/sound/sb_card.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/sound/sb_card.c	2003-03-26 23:49:50.000000000 +0000
@@ -17,7 +17,7 @@
  *  CMI 8330 support - Alessandro Zummo <azummo@ita.flashnet.it>
  *
  * 18-01-2000 Separated sb_card and sb_common
- *  Jeff Garzik <jgarzik@mandrakesoft.com>
+ *  Jeff Garzik <jgarzik@pobox.com>
  *
  * 04-02-2000 Added Soundblaster AWE 64 PnP support, isapnpjump
  *  Alessandro Zummo <azummo@ita.flashnet.it>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/sound/sb_common.c linux-2.4.21-pre6/drivers/sound/sb_common.c
--- linux-2.4.20/drivers/sound/sb_common.c	2001-09-30 19:26:08.000000000 +0000
+++ linux-2.4.21-pre6/drivers/sound/sb_common.c	2003-03-26 23:48:59.000000000 +0000
@@ -17,7 +17,7 @@
  * (fokkensr@vertis.nl)	 Which means: You can adjust the recording levels.
  *
  * 2000/01/18 - separated sb_card and sb_common -
- * Jeff Garzik <jgarzik@mandrakesoft.com>
+ * Jeff Garzik <jgarzik@pobox.com>
  *
  * 2000/09/18 - got rid of attach_uart401
  * Arnaldo Carvalho de Melo <acme@conectiva.com.br>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/sound/sb_mixer.c linux-2.4.21-pre6/drivers/sound/sb_mixer.c
--- linux-2.4.20/drivers/sound/sb_mixer.c	2001-09-30 19:26:08.000000000 +0000
+++ linux-2.4.21-pre6/drivers/sound/sb_mixer.c	2003-03-26 23:49:09.000000000 +0000
@@ -479,9 +479,9 @@
 						regimageL |= sb16_recmasks_L[i];
 						regimageR |= sb16_recmasks_R[i];
 					}
-					sb_setmixer (devc, SB16_IMASK_L, regimageL);
-					sb_setmixer (devc, SB16_IMASK_R, regimageR);
 				}
+				sb_setmixer (devc, SB16_IMASK_L, regimageL);
+				sb_setmixer (devc, SB16_IMASK_R, regimageR);
 			}
 			break;
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/sound/sonicvibes.c linux-2.4.21-pre6/drivers/sound/sonicvibes.c
--- linux-2.4.20/drivers/sound/sonicvibes.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/sound/sonicvibes.c	2003-03-26 23:49:35.000000000 +0000
@@ -3,7 +3,7 @@
 /*
  *      sonicvibes.c  --  S3 Sonic Vibes audio driver.
  *
- *      Copyright (C) 1998-2001  Thomas Sailer (t.sailer@alumni.ethz.ch)
+ *      Copyright (C) 1998-2001, 2003  Thomas Sailer (t.sailer@alumni.ethz.ch)
  *
  *      This program is free software; you can redistribute it and/or modify
  *      it under the terms of the GNU General Public License as published by
@@ -94,6 +94,7 @@
  *                       Fix SETTRIGGER non OSS API conformity
  *    18.05.2001   0.30  PCI probing and error values cleaned up by Marcus
  *                       Meissner <mm@caldera.de>
+ *    03.01.2003   0.31  open_mode fixes from Georg Acher <acher@in.tum.de>
  *
  */
 
@@ -1964,7 +1965,7 @@
 		stop_adc(s);
 		dealloc_dmabuf(s, &s->dma_adc);
 	}
-	s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
+	s->open_mode &= ~(file->f_mode & (FMODE_READ|FMODE_WRITE));
 	wake_up(&s->open_wait);
 	up(&s->open_sem);
 	unlock_kernel();
@@ -2236,7 +2237,7 @@
 		set_current_state(TASK_RUNNING);
 	}
 	down(&s->open_sem);
-	s->open_mode &= (~(file->f_mode << FMODE_MIDI_SHIFT)) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE);
+	s->open_mode &= ~((file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE));
 	spin_lock_irqsave(&s->lock, flags);
 	if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
 		outb(inb(s->ioenh + SV_CODEC_INTMASK) & ~SV_CINTMASK_MIDI, s->ioenh + SV_CODEC_INTMASK);
@@ -2716,7 +2717,7 @@
 {
 	if (!pci_present())   /* No PCI bus in this machine! */
 		return -ENODEV;
-	printk(KERN_INFO "sv: version v0.30 time " __TIME__ " " __DATE__ "\n");
+	printk(KERN_INFO "sv: version v0.31 time " __TIME__ " " __DATE__ "\n");
 #if 0
 	if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT)))
 		printk(KERN_INFO "sv: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/sound/sscape.c linux-2.4.21-pre6/drivers/sound/sscape.c
--- linux-2.4.20/drivers/sound/sscape.c	2001-09-30 19:26:08.000000000 +0000
+++ linux-2.4.21-pre6/drivers/sound/sscape.c	2003-03-26 23:49:02.000000000 +0000
@@ -668,7 +668,7 @@
 			break;
 		}
 	}
-	if (hw_config->irq > 15 || (regs[4] = irq_bits == 0xff))
+	if (hw_config->irq > 15 || ((regs[4] = irq_bits) == 0xff))
 	{
 		printk(KERN_ERR "Invalid IRQ%d\n", hw_config->irq);
 		return;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/sound/trident.c linux-2.4.21-pre6/drivers/sound/trident.c
--- linux-2.4.20/drivers/sound/trident.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/sound/trident.c	2003-03-26 23:49:51.000000000 +0000
@@ -223,7 +223,7 @@
 #define TRIDENT_STATE_MAGIC	0x63657373 /* "cess" */
 
 #define TRIDENT_DMA_MASK	0x3fffffff /* DMA buffer mask for pci_alloc_consist */
-#define ALI_DMA_MASK		0xffffffff /* ALI Tridents lack the 30-bit limitation */
+#define ALI_DMA_MASK		0x7fffffff /* ALI Tridents have 31-bit DMA. Wow. */
 
 #define NR_HW_CH		32
 
@@ -3368,15 +3368,17 @@
         pci_dev = pci_find_device(PCI_VENDOR_ID_AL,PCI_DEVICE_ID_AL_M1533, pci_dev);
         if (pci_dev == NULL)
                 return -1;
-	temp = 0x80;
-	pci_write_config_byte(pci_dev, 0x59, ~temp);
+	pci_read_config_byte(pci_dev, 0x59, &temp);
+	temp &= ~0x80;
+	pci_write_config_byte(pci_dev, 0x59, temp);
 	
 	pci_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, pci_dev);
 	if (pci_dev == NULL)
                 return -1;
 
-	temp = 0x20;
-	pci_write_config_byte(pci_dev, 0xB8, ~temp);
+	pci_read_config_byte(pci_dev, 0xB8, &temp);
+	temp &= ~0x20;
+	pci_write_config_byte(pci_dev, 0xB8, temp);
 
 	return 0;
 }
@@ -3390,13 +3392,15 @@
 	pci_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, pci_dev);
 	if (pci_dev == NULL)
                 return -1;
-	temp = 0x80;
+	pci_read_config_byte(pci_dev, 0x59, &temp);
+	temp |= 0x80;
 	pci_write_config_byte(pci_dev, 0x59, temp);
 	
 	pci_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, pci_dev);
  	if (pci_dev == NULL)
                 return -1;
-	temp = 0x20;
+	pci_read_config_byte(pci_dev, (int)0xB8, &temp);
+	temp |= 0x20;
 	pci_write_config_byte(pci_dev, (int)0xB8,(u8) temp);
 	if (chan_nums == 6) {
 		dwValue = inl(TRID_REG(card, ALI_SCTRL)) | 0x000f0000;
@@ -3936,8 +3940,9 @@
 		wReg = ali_ac97_get(card, 0, AC97_POWER_CONTROL);
 		if((wReg & 0x000f) == 0x000f)
 			return 0;
-		udelay(500);
+		udelay(5000);
 	}
+	/* This is non fatal if you have a non PM capable codec.. */
 	return 0;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/sound/via82cxxx_audio.c linux-2.4.21-pre6/drivers/sound/via82cxxx_audio.c
--- linux-2.4.20/drivers/sound/via82cxxx_audio.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/sound/via82cxxx_audio.c	2003-03-26 23:49:21.000000000 +0000
@@ -2,17 +2,20 @@
  * Support for VIA 82Cxxx Audio Codecs
  * Copyright 1999,2000 Jeff Garzik
  *
+ * Updated to support the VIA 8233/8235 audio subsystem
+ * Alan Cox <alan@redhat.com> (C) Copyright 2002 Red Hat Inc
+ *
  * Distributed under the GNU GENERAL PUBLIC LICENSE (GPL) Version 2.
  * See the "COPYING" file distributed with this software for more info.
+ * NO WARRANTY
  *
  * For a list of known bugs (errata) and documentation,
  * see via-audio.pdf in linux/Documentation/DocBook.
  * If this documentation does not exist, run "make pdfdocs".
- *
  */
 
 
-#define VIA_VERSION	"1.9.1"
+#define VIA_VERSION	"1.9.1-ac2"
 
 
 #include <linux/config.h>
@@ -117,7 +120,10 @@
 #define VIA_PCM_STATUS			0x00
 #define VIA_PCM_CONTROL			0x01
 #define VIA_PCM_TYPE			0x02
+#define VIA_PCM_LEFTVOL			0x02
+#define VIA_PCM_RIGHTVOL		0x03
 #define VIA_PCM_TABLE_ADDR		0x04
+#define VIA_PCM_STOPRATE		0x08	/* 8233+ */
 #define VIA_PCM_BLOCK_COUNT		0x0C
 
 /* XXX unused DMA channel for FM PCM data */
@@ -126,6 +132,12 @@
 #define VIA_BASE0_FM_OUT_CHAN_CTRL	0x21
 #define VIA_BASE0_FM_OUT_CHAN_TYPE	0x22
 
+/* Six channel audio output on 8233 */
+#define VIA_BASE0_MULTI_OUT_CHAN		0x40
+#define VIA_BASE0_MULTI_OUT_CHAN_STATUS		0x40
+#define VIA_BASE0_MULTI_OUT_CHAN_CTRL		0x41
+#define VIA_BASE0_MULTI_OUT_CHAN_TYPE		0x42
+
 #define VIA_BASE0_AC97_CTRL		0x80
 #define VIA_BASE0_SGD_STATUS_SHADOW	0x84
 #define VIA_BASE0_GPI_INT_ENABLE	0x8C
@@ -134,6 +146,12 @@
 #define VIA_INTR_FM			((1<<2) |  (1<<6) | (1<<10))
 #define VIA_INTR_MASK		(VIA_INTR_OUT | VIA_INTR_IN | VIA_INTR_FM)
 
+/* Newer VIA we need to monitor the low 3 bits of each channel. This
+   mask covers the channels we don't yet use as well 
+ */
+ 
+#define VIA_NEW_INTR_MASK		0x77077777UL
+
 /* VIA_BASE0_AUDIO_xxx_CHAN_TYPE bits */
 #define VIA_IRQ_ON_FLAG			(1<<0)	/* int on each flagged scatter block */
 #define VIA_IRQ_ON_EOL			(1<<1)	/* int at end of scatter list */
@@ -251,11 +269,15 @@
 	unsigned is_record : 1;
 	unsigned is_mapped : 1;
 	unsigned is_enabled : 1;
+	unsigned is_multi: 1;	/* 8233 6 channel */
 	u8 pcm_fmt;		/* VIA_PCM_FMT_xxx */
+	u8 channels;		/* Channel count */
 
 	unsigned rate;		/* sample rate */
 	unsigned int frag_size;
 	unsigned int frag_number;
+	
+	unsigned char intmask;
 
 	volatile struct via_sgd_table *sgtable;
 	dma_addr_t sgt_handle;
@@ -281,12 +303,23 @@
 	int dev_dsp;		/* /dev/dsp index from register_sound_dsp() */
 
 	unsigned rev_h : 1;
+	unsigned legacy: 1;	/* Has legacy ports */
+	unsigned intmask: 1;	/* Needs int bits */
+	unsigned sixchannel: 1;	/* 8233/35 with 6 channel support */
+	unsigned volume: 1;
 
 	int locked_rate : 1;
+	
+	int mixer_vol;		/* 8233/35 volume  - not yet implemented */
 
 	struct semaphore syscall_sem;
 	struct semaphore open_sem;
 
+	/* The 8233/8235 have 4 DX audio channels, two record and
+	   one six channel out. We bind ch_in to DX 1, ch_out to multichannel
+	   and ch_fm to DX 2. DX 3 and REC0/REC1 are unused at the
+	   moment */
+	   
 	struct via_channel ch_in;
 	struct via_channel ch_out;
 	struct via_channel ch_fm;
@@ -353,7 +386,9 @@
 
 static struct pci_device_id via_pci_tbl[] __initdata = {
 	{ PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5,
-	  PCI_ANY_ID, PCI_ANY_ID, },
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8233_5,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
 	{ 0, }
 };
 MODULE_DEVICE_TABLE(pci,via_pci_tbl);
@@ -427,7 +462,13 @@
 
 static inline void sg_begin (struct via_channel *chan)
 {
-	outb (VIA_SGD_START, chan->iobase + VIA_PCM_CONTROL);
+	DPRINTK("Start with intmask %d\n", chan->intmask);
+	DPRINTK("About to start from %d to %d\n", 
+		inl(chan->iobase + VIA_PCM_BLOCK_COUNT),
+		inb(chan->iobase + VIA_PCM_STOPRATE + 3));
+	outb (VIA_SGD_START|chan->intmask, chan->iobase + VIA_PCM_CONTROL);
+	DPRINTK("Status is now %02X\n", inb(chan->iobase + VIA_PCM_STATUS));
+	DPRINTK("Control is now %02X\n", inb(chan->iobase + VIA_PCM_CONTROL));
 }
 
 
@@ -443,6 +484,10 @@
 	return 0;
 }
 
+static int via_sg_offset(struct via_channel *chan)
+{
+	return inl (chan->iobase + VIA_PCM_BLOCK_COUNT) & 0x00FFFFFF;
+}
 
 /****************************************************************
  *
@@ -506,6 +551,8 @@
 	via_chan_stop (card->baseaddr + VIA_BASE0_PCM_OUT_CHAN);
 	via_chan_stop (card->baseaddr + VIA_BASE0_PCM_IN_CHAN);
 	via_chan_stop (card->baseaddr + VIA_BASE0_FM_OUT_CHAN);
+	if(card->sixchannel)
+		via_chan_stop (card->baseaddr + VIA_BASE0_MULTI_OUT_CHAN);
 
 	/*
 	 * clear any existing stops / flags (sanity check mainly)
@@ -513,6 +560,8 @@
 	via_chan_status_clear (card->baseaddr + VIA_BASE0_PCM_OUT_CHAN);
 	via_chan_status_clear (card->baseaddr + VIA_BASE0_PCM_IN_CHAN);
 	via_chan_status_clear (card->baseaddr + VIA_BASE0_FM_OUT_CHAN);
+	if(card->sixchannel)
+		via_chan_status_clear (card->baseaddr + VIA_BASE0_MULTI_OUT_CHAN);
 
 	/*
 	 * clear any enabled interrupt bits
@@ -532,6 +581,14 @@
 	if (tmp != new_tmp)
 		outb (0, card->baseaddr + VIA_BASE0_FM_OUT_CHAN_TYPE);
 
+	if(card->sixchannel)
+	{
+		tmp = inb (card->baseaddr + VIA_BASE0_MULTI_OUT_CHAN_TYPE);
+		new_tmp = tmp & ~(VIA_IRQ_ON_FLAG|VIA_IRQ_ON_EOL|VIA_RESTART_SGD_ON_EOL);
+		if (tmp != new_tmp)
+			outb (0, card->baseaddr + VIA_BASE0_MULTI_OUT_CHAN_TYPE);
+	}
+
 	udelay(10);
 
 	/*
@@ -562,6 +619,9 @@
 {
 	struct via_info *card = ac97->private_data;
 	int rate_reg;
+	u32 dacp;
+	u32 mast_vol, phone_vol, mono_vol, pcm_vol;
+	u32 mute_vol = 0x8000;	/* The mute volume? -- Seems to work! */
 
 	DPRINTK ("ENTER, rate = %d\n", rate);
 
@@ -578,16 +638,32 @@
 	rate_reg = chan->is_record ? AC97_PCM_LR_ADC_RATE :
 			    AC97_PCM_FRONT_DAC_RATE;
 
-	via_ac97_write_reg (ac97, AC97_POWER_CONTROL,
-		(via_ac97_read_reg (ac97, AC97_POWER_CONTROL) & ~0x0200) |
-		0x0200);
+	/* Save current state */
+	dacp=via_ac97_read_reg(ac97, AC97_POWER_CONTROL);
+	mast_vol = via_ac97_read_reg(ac97, AC97_MASTER_VOL_STEREO);
+	mono_vol = via_ac97_read_reg(ac97, AC97_MASTER_VOL_MONO);
+	phone_vol = via_ac97_read_reg(ac97, AC97_HEADPHONE_VOL);
+	pcm_vol = via_ac97_read_reg(ac97, AC97_PCMOUT_VOL);
+	/* Mute - largely reduces popping */
+	via_ac97_write_reg(ac97, AC97_MASTER_VOL_STEREO, mute_vol);
+	via_ac97_write_reg(ac97, AC97_MASTER_VOL_MONO, mute_vol);
+	via_ac97_write_reg(ac97, AC97_HEADPHONE_VOL, mute_vol);
+       	via_ac97_write_reg(ac97, AC97_PCMOUT_VOL, mute_vol);
+	/* Power down the DAC */
+	via_ac97_write_reg(ac97, AC97_POWER_CONTROL, dacp|0x0200);
 
+        /* Set new rate */
 	via_ac97_write_reg (ac97, rate_reg, rate);
 
-	via_ac97_write_reg (ac97, AC97_POWER_CONTROL,
-		via_ac97_read_reg (ac97, AC97_POWER_CONTROL) & ~0x0200);
-
-	udelay (10);
+	/* Power DAC back up */
+	via_ac97_write_reg(ac97, AC97_POWER_CONTROL, dacp);
+	udelay (200); /* reduces popping */
+
+	/* Restore volumes */
+	via_ac97_write_reg(ac97, AC97_MASTER_VOL_STEREO, mast_vol);
+	via_ac97_write_reg(ac97, AC97_MASTER_VOL_MONO, mono_vol);
+	via_ac97_write_reg(ac97, AC97_HEADPHONE_VOL, phone_vol);
+	via_ac97_write_reg(ac97, AC97_PCMOUT_VOL, pcm_vol);
 
 	/* the hardware might return a value different than what we
 	 * passed to it, so read the rate value back from hardware
@@ -627,9 +703,19 @@
 {
 	memset (chan, 0, sizeof (*chan));
 
+	if(card->intmask)
+		chan->intmask = 0x23;	/* Turn on the IRQ bits */
+		
 	if (chan == &card->ch_out) {
 		chan->name = "PCM-OUT";
-		chan->iobase = card->baseaddr + VIA_BASE0_PCM_OUT_CHAN;
+		if(card->sixchannel)
+		{
+			chan->iobase = card->baseaddr + VIA_BASE0_MULTI_OUT_CHAN;
+			chan->is_multi = 1;
+			DPRINTK("Using multichannel for pcm out\n");
+		}
+		else
+			chan->iobase = card->baseaddr + VIA_BASE0_PCM_OUT_CHAN;
 	} else if (chan == &card->ch_in) {
 		chan->name = "PCM-IN";
 		chan->iobase = card->baseaddr + VIA_BASE0_PCM_IN_CHAN;
@@ -708,6 +794,11 @@
 
 	DPRINTK ("ENTER\n");
 
+
+	chan->intmask = 0;
+	if(card->intmask)
+		chan->intmask = 0x23;	/* Turn on the IRQ bits */
+		
 	if (chan->sgtable != NULL) {
 		DPRINTK ("EXIT\n");
 		return 0;
@@ -778,6 +869,16 @@
 	outl (chan->sgt_handle, chan->iobase + VIA_PCM_TABLE_ADDR);
 	udelay (20);
 	via_ac97_wait_idle (card);
+	/* load no rate adaption, stereo 16bit, set up ring slots */
+	if(card->sixchannel)
+	{
+		if(!chan->is_multi)
+		{
+			outl (0xFFFFF | (0x3 << 20) | (chan->frag_number << 24), chan->iobase + VIA_PCM_STOPRATE);
+			udelay (20);
+			via_ac97_wait_idle (card);
+		}
+	}
 
 	DPRINTK ("inl (0x%lX) = %x\n",
 		chan->iobase + VIA_PCM_TABLE_ADDR,
@@ -881,8 +982,11 @@
 	assert (chan != NULL);
 
 	if (reset)
+	{
 		/* reset to 8-bit mono mode */
 		chan->pcm_fmt = 0;
+		chan->channels = 1;
+	}
 
 	/* enable interrupts on FLAG and EOL */
 	chan->pcm_fmt |= VIA_CHAN_TYPE_MASK;
@@ -893,8 +997,83 @@
 	/* set interrupt select bits where applicable (PCM in & out channels) */
 	if (!chan->is_record)
 		chan->pcm_fmt |= VIA_CHAN_TYPE_INT_SELECT;
+	
+	DPRINTK("SET FMT - %02x %02x\n", chan->intmask , chan->is_multi);
+	
+	if(chan->intmask)
+	{
+		u32 m;
+
+		/*
+		 *	Channel 0x4 is up to 6 x 16bit and has to be
+		 *	programmed differently 
+		 */
+		 		
+		if(chan->is_multi)
+		{
+			u8 c = 0;
+			
+			/*
+			 *	Load the type bit for num channels
+			 *	and 8/16bit
+			 */
+			 
+			if(chan->pcm_fmt & VIA_PCM_FMT_16BIT)
+				c = 1 << 7;
+			if(chan->pcm_fmt & VIA_PCM_FMT_STEREO)
+				c |= (2<<4);
+			else
+				c |= (1<<4);
+				
+			outb(c, chan->iobase + VIA_PCM_TYPE);
+			
+			/*
+			 *	Set the channel steering
+			 *	Mono
+			 *		Channel 0 to slot 3
+			 *		Channel 0 to slot 4
+			 *	Stereo
+			 *		Channel 0 to slot 3
+			 *		Channel 1 to slot 4
+			 */
+			 
+			switch(chan->channels)
+			{
+				case 1:
+					outl(0xFF000000 | (1<<0) | (1<<4) , chan->iobase + VIA_PCM_STOPRATE);
+					break;
+				case 2:
+					outl(0xFF000000 | (1<<0) | (2<<4) , chan->iobase + VIA_PCM_STOPRATE);
+					break;
+				case 4:
+					outl(0xFF000000 | (1<<0) | (2<<4) | (3<<8) | (4<<12), chan->iobase + VIA_PCM_STOPRATE);
+					break;
+				case 6:
+					outl(0xFF000000 | (1<<0) | (2<<4) | (5<<8) | (6<<12) | (3<<16) | (4<<20), chan->iobase + VIA_PCM_STOPRATE);
+					break;
+			}				
+		}
+		else
+		{
+			/*
+			 *	New style, turn off channel volume
+			 *	control, set bits in the right register
+			 */	
+			outb(0x0, chan->iobase + VIA_PCM_LEFTVOL);
+			outb(0x0, chan->iobase + VIA_PCM_RIGHTVOL);
+
+			m = inl(chan->iobase + VIA_PCM_STOPRATE);
+			m &= ~(3<<20);
+			if(chan->pcm_fmt & VIA_PCM_FMT_STEREO)
+				m |= (1 << 20);
+			if(chan->pcm_fmt & VIA_PCM_FMT_16BIT)
+				m |= (1 << 21);
+			outl(m, chan->iobase + VIA_PCM_STOPRATE);
+		}		
+	}
+	else
+		outb (chan->pcm_fmt, chan->iobase + VIA_PCM_TYPE);
 
-	outb (chan->pcm_fmt, chan->iobase + VIA_PCM_TYPE);
 
 	DPRINTK ("EXIT, pcm_fmt = 0x%02X, reg = 0x%02X\n",
 		 chan->pcm_fmt,
@@ -1035,15 +1214,25 @@
 	/* mono */
 	case 1:
 		chan->pcm_fmt &= ~VIA_PCM_FMT_STEREO;
+		chan->channels = 1;
 		via_chan_pcm_fmt (chan, 0);
 		break;
 
 	/* stereo */
 	case 2:
 		chan->pcm_fmt |= VIA_PCM_FMT_STEREO;
+		chan->channels = 2;
 		via_chan_pcm_fmt (chan, 0);
 		break;
 
+	case 4:
+	case 6:
+		if(chan->is_multi)
+		{
+			chan->pcm_fmt |= VIA_PCM_FMT_STEREO;
+			chan->channels = val;
+			break;
+		}
 	/* unknown */
 	default:
 		printk (KERN_WARNING PFX "unknown number of channels\n");
@@ -1077,9 +1266,8 @@
 
 		DPRINTK ("\n");
 
-		chan->frag_size = (VIA_DEFAULT_FRAG_TIME * chan->rate *
-				   ((chan->pcm_fmt & VIA_PCM_FMT_STEREO) ? 2 : 1) *
-				   ((chan->pcm_fmt & VIA_PCM_FMT_16BIT) ? 2 : 1)) / 1000 - 1;
+		chan->frag_size = (VIA_DEFAULT_FRAG_TIME * chan->rate * chan->channels
+				   * ((chan->pcm_fmt & VIA_PCM_FMT_16BIT) ? 2 : 1)) / 1000 - 1;
 
 		shift = 0;
 		while (chan->frag_size) {
@@ -1400,7 +1588,30 @@
 
 	rc = via_syscall_down (card, nonblock);
 	if (rc) goto out;
-
+	
+#if 0
+	/*
+	 *	Intercept volume control on 8233 and 8235
+	 */
+	if(card->volume)
+	{
+		switch(cmd)
+		{
+			case SOUND_MIXER_READ_VOLUME:
+				return card->mixer_vol;
+			case SOUND_MIXER_WRITE_VOLUME:
+			{
+				int v;
+				if(get_user(v, (int *)arg))
+				{
+					rc = -EFAULT;
+					goto out;
+				}
+				card->mixer_vol = v;
+			}
+		}
+	}		
+#endif
 	rc = codec->mixer_ioctl(codec, cmd, arg);
 
 	up (&card->syscall_sem);
@@ -1494,16 +1705,19 @@
         	udelay (100);
 	}
 
+	if(card->legacy)
+	{
 #if 0 /* this breaks on K7M */
-	/* disable legacy stuff */
-	pci_write_config_byte (pdev, 0x42, 0x00);
-	udelay(10);
+		/* disable legacy stuff */
+		pci_write_config_byte (pdev, 0x42, 0x00);
+		udelay(10);
 #endif
 
-	/* route FM trap to IRQ, disable FM trap */
-	pci_write_config_byte (pdev, 0x48, 0x05);
-	udelay(10);
-
+		/* route FM trap to IRQ, disable FM trap */
+		pci_write_config_byte (pdev, 0x48, 0x05);
+		udelay(10);
+	}
+	
 	/* disable all codec GPI interrupts */
 	outl (0, pci_resource_start (pdev, 0) + 0x8C);
 
@@ -1553,7 +1767,9 @@
 		printk (KERN_ERR PFX "unable to reset AC97 codec, aborting\n");
 		goto err_out;
 	}
-
+	
+	mdelay(10);
+	
 	if (ac97_probe_codec (&card->ac97) == 0) {
 		printk (KERN_ERR PFX "unable to probe AC97 codec, aborting\n");
 		rc = -EIO;
@@ -1730,6 +1946,31 @@
 	spin_unlock (&card->lock);
 }
 
+static void via_new_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct via_info *card = dev_id;
+	u32 status32;
+
+	/* to minimize interrupt sharing costs, we use the SGD status
+	 * shadow register to check the status of all inputs and
+	 * outputs with a single 32-bit bus read.  If no interrupt
+	 * conditions are flagged, we exit immediately
+	 */
+	status32 = inl (card->baseaddr + VIA_BASE0_SGD_STATUS_SHADOW);
+	if (!(status32 & VIA_NEW_INTR_MASK))
+		return;
+	/*
+	 * goes away completely on UP
+	 */
+	spin_lock (&card->lock);
+
+	via_intr_channel (&card->ch_out);
+	via_intr_channel (&card->ch_in);
+	via_intr_channel (&card->ch_fm);
+
+	spin_unlock (&card->lock);
+}
+
 
 /**
  *	via_interrupt_init - Initialize interrupt handling
@@ -1757,18 +1998,32 @@
 		return -EIO;
 	}
 
-	/* make sure FM irq is not routed to us */
-	pci_read_config_byte (card->pdev, VIA_FM_NMI_CTRL, &tmp8);
-	if ((tmp8 & VIA_CR48_FM_TRAP_TO_NMI) == 0) {
-		tmp8 |= VIA_CR48_FM_TRAP_TO_NMI;
-		pci_write_config_byte (card->pdev, VIA_FM_NMI_CTRL, tmp8);
+	/* VIA requires this is done */
+	pci_write_config_byte(card->pdev, PCI_INTERRUPT_LINE, card->pdev->irq);
+	
+	if(card->legacy)
+	{
+		/* make sure FM irq is not routed to us */
+		pci_read_config_byte (card->pdev, VIA_FM_NMI_CTRL, &tmp8);
+		if ((tmp8 & VIA_CR48_FM_TRAP_TO_NMI) == 0) {
+			tmp8 |= VIA_CR48_FM_TRAP_TO_NMI;
+			pci_write_config_byte (card->pdev, VIA_FM_NMI_CTRL, tmp8);
+		}
+		if (request_irq (card->pdev->irq, via_interrupt, SA_SHIRQ, VIA_MODULE_NAME, card)) {
+			printk (KERN_ERR PFX "unable to obtain IRQ %d, aborting\n",
+				card->pdev->irq);
+			DPRINTK ("EXIT, returning -EBUSY\n");
+			return -EBUSY;
+		}
 	}
-
-	if (request_irq (card->pdev->irq, via_interrupt, SA_SHIRQ, VIA_MODULE_NAME, card)) {
-		printk (KERN_ERR PFX "unable to obtain IRQ %d, aborting\n",
-			card->pdev->irq);
-		DPRINTK ("EXIT, returning -EBUSY\n");
-		return -EBUSY;
+	else 
+	{
+		if (request_irq (card->pdev->irq, via_new_interrupt, SA_SHIRQ, VIA_MODULE_NAME, card)) {
+			printk (KERN_ERR PFX "unable to obtain IRQ %d, aborting\n",
+				card->pdev->irq);
+			DPRINTK ("EXIT, returning -EBUSY\n");
+			return -EBUSY;
+		}
 	}
 
 	DPRINTK ("EXIT, returning 0\n");
@@ -1803,11 +2058,14 @@
 
 	assert (card != NULL);
 
-	/* turn off legacy features, if not already */
-	pci_read_config_byte (card->pdev, VIA_FUNC_ENABLE, &tmp8);
-	if (tmp8 & (VIA_CR42_SB_ENABLE |  VIA_CR42_FM_ENABLE)) {
-		tmp8 &= ~(VIA_CR42_SB_ENABLE | VIA_CR42_FM_ENABLE);
-		pci_write_config_byte (card->pdev, VIA_FUNC_ENABLE, tmp8);
+	if(card->legacy)
+	{
+		/* turn off legacy features, if not already */
+		pci_read_config_byte (card->pdev, VIA_FUNC_ENABLE, &tmp8);
+		if (tmp8 & (VIA_CR42_SB_ENABLE |  VIA_CR42_FM_ENABLE)) {
+			tmp8 &= ~(VIA_CR42_SB_ENABLE | VIA_CR42_FM_ENABLE);
+			pci_write_config_byte (card->pdev, VIA_FUNC_ENABLE, tmp8);
+		}
 	}
 
 	via_stop_everything (card);
@@ -2120,7 +2378,6 @@
 		 file, buffer, count, ppos ? ((unsigned long)*ppos) : 0);
 
 	assert (file != NULL);
-	assert (buffer != NULL);
 	card = file->private_data;
 	assert (card != NULL);
 
@@ -2278,11 +2535,12 @@
 	DPRINTK ("Flushed block %u, sw_ptr now %u, n_frags now %d\n",
 		n, chan->sw_ptr, atomic_read (&chan->n_frags));
 
-	DPRINTK ("regs==%02X %02X %02X %08X %08X %08X %08X\n",
+	DPRINTK ("regs==S=%02X C=%02X TP=%02X BP=%08X RT=%08X SG=%08X CC=%08X SS=%08X\n",
 		 inb (card->baseaddr + 0x00),
 		 inb (card->baseaddr + 0x01),
 		 inb (card->baseaddr + 0x02),
 		 inl (card->baseaddr + 0x04),
+		 inl (card->baseaddr + 0x08),
 		 inl (card->baseaddr + 0x0C),
 		 inl (card->baseaddr + 0x80),
 		 inl (card->baseaddr + 0x84));
@@ -2305,7 +2563,6 @@
 		 file, buffer, count, ppos ? ((unsigned long)*ppos) : 0);
 
 	assert (file != NULL);
-	assert (buffer != NULL);
 	card = file->private_data;
 	assert (card != NULL);
 
@@ -2558,7 +2815,7 @@
 	if (chan->is_active) {
 		unsigned long extra;
 		info.ptr = atomic_read (&chan->hw_ptr) * chan->frag_size;
-		extra = chan->frag_size - inl (chan->iobase + VIA_PCM_BLOCK_COUNT);
+		extra = chan->frag_size - via_sg_offset(chan);
 		info.ptr += extra;
 		info.bytes += extra;
 	} else {
@@ -2679,7 +2936,7 @@
                 rc = put_user (val, (int *)arg);
 		break;
 
-	/* query or set number of channels (1=mono, 2=stereo) */
+	/* query or set number of channels (1=mono, 2=stereo, 4/6 for multichannel) */
         case SNDCTL_DSP_CHANNELS:
 		if (get_user(val, (int *)arg)) {
 			rc = -EFAULT;
@@ -2700,11 +2957,10 @@
 
 			val = rc;
 		} else {
-			if ((rd && (card->ch_in.pcm_fmt & VIA_PCM_FMT_STEREO)) ||
-			    (wr && (card->ch_out.pcm_fmt & VIA_PCM_FMT_STEREO)))
-				val = 2;
+			if (rd)
+				val = card->ch_in.channels;
 			else
-				val = 1;
+				val = card->ch_out.channels;
 		}
 		DPRINTK ("CHANNELS EXIT, returning %d\n", val);
                 rc = put_user (val, (int *)arg);
@@ -2864,10 +3120,11 @@
 
 			val = chan->frag_number - atomic_read (&chan->n_frags);
 
+			assert(val >= 0);
+				
 			if (val > 0) {
 				val *= chan->frag_size;
-				val -= chan->frag_size -
-				       inl (chan->iobase + VIA_PCM_BLOCK_COUNT);
+				val -= chan->frag_size - via_sg_offset(chan);
 			}
 			val += chan->slop_len % chan->frag_size;
 		} else
@@ -3029,7 +3286,9 @@
 
 		/* why is this forced to 16-bit stereo in all drivers? */
 		chan->pcm_fmt = VIA_PCM_FMT_16BIT | VIA_PCM_FMT_STEREO;
+		chan->channels = 2;
 
+		// TO DO - use FIFO: via_capture_fifo(card, 1);
 		via_chan_pcm_fmt (chan, 0);
 		via_set_rate (&card->ac97, chan, 44100);
 	}
@@ -3044,6 +3303,7 @@
 			/* if in duplex mode make the recording and playback channels
 			   have the same settings */
 			chan->pcm_fmt = VIA_PCM_FMT_16BIT | VIA_PCM_FMT_STEREO;
+			chan->channels = 2;
 			via_chan_pcm_fmt (chan, 0);
                         via_set_rate (&card->ac97, chan, 44100);
 		} else {
@@ -3083,7 +3343,7 @@
 
 	if (file->f_mode & FMODE_WRITE) {
 		rc = via_dsp_drain_playback (card, &card->ch_out, nonblock);
-		if (rc)
+		if (rc && rc != ERESTARTSYS)	/* Nobody needs to know about ^C */
 			printk (KERN_DEBUG "via_audio: ignoring drain playback error %d\n", rc);
 
 		via_chan_free (card, &card->ch_out);
@@ -3122,11 +3382,12 @@
 	DPRINTK ("ENTER\n");
 
 	if (printed_version++ == 0)
-		printk (KERN_INFO "Via 686a audio driver " VIA_VERSION "\n");
+		printk (KERN_INFO "Via 686a/8233/8235 audio driver " VIA_VERSION "\n");
 
 	rc = pci_enable_device (pdev);
 	if (rc)
 		goto err_out;
+		
 
 	rc = pci_request_regions (pdev, "via82cxxx_audio");
 	if (rc)
@@ -3158,7 +3419,15 @@
 	 * which means it has a few extra features */
 	if (pci_resource_start (pdev, 2) > 0)
 		card->rev_h = 1;
-
+		
+	/* Overkill for now, but more flexible done right */
+	
+	card->intmask = id->driver_data;
+	card->legacy = !card->intmask;
+	card->sixchannel = id->driver_data;
+	
+	if(card->sixchannel)
+		printk(KERN_INFO PFX "Six channel audio available\n");
 	if (pdev->irq < 1) {
 		printk (KERN_ERR PFX "invalid PCI IRQ %d, aborting\n", pdev->irq);
 		rc = -ENODEV;
@@ -3171,6 +3440,8 @@
 		goto err_out_kfree;
 	}
 
+	pci_set_master(pdev);
+	
 	/*
 	 * init AC97 mixer and codec
 	 */
@@ -3214,26 +3485,29 @@
 	/* Disable by default */
 	card->midi_info.io_base = 0;
 
-	pci_read_config_byte (pdev, 0x42, &r42);
-	/* Disable MIDI interrupt */
-	pci_write_config_byte (pdev, 0x42, r42 | VIA_CR42_MIDI_IRQMASK);
-	if (r42 & VIA_CR42_MIDI_ENABLE)
+	if(card->legacy)
 	{
-		if (r42 & VIA_CR42_MIDI_PNP) /* Address selected by iobase 2 - not tested */
-			card->midi_info.io_base = pci_resource_start (pdev, 2);
-		else /* Address selected by byte 0x43 */
+		pci_read_config_byte (pdev, 0x42, &r42);
+		/* Disable MIDI interrupt */
+		pci_write_config_byte (pdev, 0x42, r42 | VIA_CR42_MIDI_IRQMASK);
+		if (r42 & VIA_CR42_MIDI_ENABLE)
 		{
-			u8 r43;
-			pci_read_config_byte (pdev, 0x43, &r43);
-			card->midi_info.io_base = 0x300 + ((r43 & 0x0c) << 2);
-		}
+			if (r42 & VIA_CR42_MIDI_PNP) /* Address selected by iobase 2 - not tested */
+				card->midi_info.io_base = pci_resource_start (pdev, 2);
+			else /* Address selected by byte 0x43 */
+			{
+				u8 r43;
+				pci_read_config_byte (pdev, 0x43, &r43);
+				card->midi_info.io_base = 0x300 + ((r43 & 0x0c) << 2);
+			}
 
-		card->midi_info.irq = -pdev->irq;
-		if (probe_uart401(& card->midi_info, THIS_MODULE))
-		{
-			card->midi_devc=midi_devs[card->midi_info.slots[4]]->devc;
-			pci_write_config_byte(pdev, 0x42, r42 & ~VIA_CR42_MIDI_IRQMASK);
-			printk("Enabled Via MIDI\n");
+			card->midi_info.irq = -pdev->irq;
+			if (probe_uart401(& card->midi_info, THIS_MODULE))
+			{
+				card->midi_devc=midi_devs[card->midi_info.slots[4]]->devc;
+				pci_write_config_byte(pdev, 0x42, r42 & ~VIA_CR42_MIDI_IRQMASK);
+				printk("Enabled Via MIDI\n");
+			}
 		}
 	}
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/CDCEther.c linux-2.4.21-pre6/drivers/usb/CDCEther.c
--- linux-2.4.20/drivers/usb/CDCEther.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/CDCEther.c	2003-03-26 23:48:59.000000000 +0000
@@ -313,7 +313,7 @@
 	// into an integer number of USB packets, we force it to send one 
 	// more byte so the device will get a runt USB packet signalling the 
 	// end of the ethernet frame
-	if ( (skb->len) ^ (ether_dev->data_ep_out_size) ) {
+	if ( skb->len % ether_dev->data_ep_out_size) {
 		// It was not an exact multiple
 		// no need to add anything extra
 		count = skb->len;
@@ -562,7 +562,7 @@
 			MODE_FLAG_DIRECTED |
 			MODE_FLAG_BROADCAST |
 			MODE_FLAG_MULTICAST;
-		buff = kmalloc(6 * net->mc_count, in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+		buff = kmalloc(6 * net->mc_count, GFP_ATOMIC);
 		for (i = 0, mclist = net->mc_list;
 			mclist && i < net->mc_count;
 			i++, mclist = mclist->next) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/Config.in linux-2.4.21-pre6/drivers/usb/Config.in
--- linux-2.4.20/drivers/usb/Config.in	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/Config.in	2003-03-26 23:49:30.000000000 +0000
@@ -15,25 +15,20 @@
    else
       define_bool CONFIG_USB_BANDWIDTH n
    fi
-   bool '  Long timeout for slow-responding devices (some MGE Ellipse UPSes)' CONFIG_USB_LONG_TIMEOUT
 
-   comment 'USB Host Controller Drivers'
-   source drivers/usb/hcd/Config.in
-   if [ "$CONFIG_USB_UHCI_ALT" != "y" ]; then
-      dep_tristate '  UHCI (Intel PIIX4, VIA, ...) support' CONFIG_USB_UHCI $CONFIG_USB
-   fi
-   if [ "$CONFIG_USB_UHCI" != "y" ]; then
-      dep_tristate '  UHCI Alternate Driver (JE) support' CONFIG_USB_UHCI_ALT $CONFIG_USB
-   else
-      define_bool CONFIG_USB_UHCI_ALT n
-   fi
-   dep_tristate '  OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI $CONFIG_USB
+   source drivers/usb/host/Config.in
 
    comment 'USB Device Class drivers'
    dep_tristate '  USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB $CONFIG_SOUND
    dep_tristate '    EMI 2|6 USB Audio interface support' CONFIG_USB_EMI26 $CONFIG_USB_AUDIO
-   dep_tristate '  USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB $CONFIG_EXPERIMENTAL
-   dep_tristate '  USB MIDI support' CONFIG_USB_MIDI $CONFIG_USB
+   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      if [ "$CONFIG_BLUEZ" = "n" ]; then
+         dep_tristate '  USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB
+      else
+         comment '  USB Bluetooth can only be used with disabled Bluetooth subsystem'
+      fi
+   fi
+   dep_tristate '  USB MIDI support' CONFIG_USB_MIDI $CONFIG_USB $CONFIG_SOUND
    if [ "$CONFIG_SCSI" = "n" ]; then
       comment '  SCSI support is needed for USB Storage'
    fi
@@ -41,7 +36,7 @@
       dep_mbool '    USB Mass Storage verbose debug' CONFIG_USB_STORAGE_DEBUG $CONFIG_USB_STORAGE
       dep_mbool '    Datafab MDCFE-B Compact Flash Reader support' CONFIG_USB_STORAGE_DATAFAB $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL
       dep_mbool '    Freecom USB/ATAPI Bridge support' CONFIG_USB_STORAGE_FREECOM  $CONFIG_USB_STORAGE
-      dep_mbool '    ISD-200 USB/ATA Bridge support' CONFIG_USB_STORAGE_ISD200 $CONFIG_USB_STORAGE
+      dep_mbool '    ISD-200 USB/ATA Bridge support' CONFIG_USB_STORAGE_ISD200 $CONFIG_USB_STORAGE $CONFIG_IDE
       dep_mbool '    Microtech CompactFlash/SmartMedia support' CONFIG_USB_STORAGE_DPCM $CONFIG_USB_STORAGE
       dep_mbool '    HP CD-Writer 82xx support' CONFIG_USB_STORAGE_HP8200e $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL
       dep_mbool '    SanDisk SDDR-09 (and other SmartMedia) support' CONFIG_USB_STORAGE_SDDR09 $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL
@@ -63,6 +58,8 @@
    fi
    dep_tristate '  Aiptek 6000U/8000U tablet support' CONFIG_USB_AIPTEK $CONFIG_USB $CONFIG_INPUT
    dep_tristate '  Wacom Intuos/Graphire tablet support' CONFIG_USB_WACOM $CONFIG_USB $CONFIG_INPUT
+   dep_tristate '  KB Gear JamStudio tablet support' CONFIG_USB_KBTAB $CONFIG_USB $CONFIG_INPUT
+   dep_tristate '  Griffin Technology PowerMate support' CONFIG_USB_POWERMATE $CONFIG_USB $CONFIG_INPUT
 
    comment 'USB Imaging devices'
    dep_tristate '  USB Kodak DC-2xx Camera support' CONFIG_USB_DC2XX $CONFIG_USB
@@ -76,6 +73,7 @@
       comment '  Video4Linux support is needed for USB Multimedia device support'
    else
       dep_tristate '  USB IBM (Xirlink) C-it Camera support' CONFIG_USB_IBMCAM $CONFIG_USB $CONFIG_VIDEO_DEV
+      dep_tristate '  USB Konica Webcam support' CONFIG_USB_KONICAWC $CONFIG_USB $CONFIG_VIDEO_DEV
       dep_tristate '  USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB $CONFIG_VIDEO_DEV
       dep_tristate '  USB Philips Cameras' CONFIG_USB_PWC $CONFIG_USB $CONFIG_VIDEO_DEV
       dep_tristate '  USB SE401 Camera support' CONFIG_USB_SE401 $CONFIG_USB $CONFIG_VIDEO_DEV
@@ -94,7 +92,7 @@
       dep_tristate '  USB KLSI KL5USB101-based ethernet device support (EXPERIMENTAL)' CONFIG_USB_KAWETH $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
       dep_tristate '  USB CATC NetMate-based Ethernet device support (EXPERIMENTAL)' CONFIG_USB_CATC $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
       dep_tristate '  USB Communication Class Ethernet device support (EXPERIMENTAL)' CONFIG_USB_CDCETHER $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
-      dep_tristate '  USB-to-USB Networking cable device support (EXPERIMENTAL)' CONFIG_USB_USBNET $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
+      dep_tristate '  USB-to-USB Networking cables, Linux PDAs, ... (EXPERIMENTAL)' CONFIG_USB_USBNET $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
    fi
 
    comment 'USB port drivers'
@@ -103,7 +101,7 @@
 
    comment 'USB Miscellaneous drivers'
    dep_tristate '  USB Diamond Rio500 support (EXPERIMENTAL)' CONFIG_USB_RIO500 $CONFIG_USB $CONFIG_EXPERIMENTAL
-   dep_tristate '  USB Auerswald ISDN support (EXPERIMENTAL)' CONFIG_USB_AUERSWALD $CONFIG_USB $CONFIG_EXPERIMENTAL
+   dep_tristate '  Auerswald device support' CONFIG_USB_AUERSWALD $CONFIG_USB
    dep_tristate '  Texas Instruments Graph Link USB (aka SilverLink) cable support' CONFIG_USB_TIGL $CONFIG_USB
    dep_tristate '  Tieman Voyager USB Braille display support (EXPERIMENTAL)' CONFIG_USB_BRLVGER $CONFIG_USB $CONFIG_EXPERIMENTAL
    dep_tristate '  USB LCD device support' CONFIG_USB_LCD $CONFIG_USB
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/Makefile linux-2.4.21-pre6/drivers/usb/Makefile
--- linux-2.4.20/drivers/usb/Makefile	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/Makefile	2003-03-26 23:49:30.000000000 +0000
@@ -18,7 +18,7 @@
 usbcore-objs		:= usb.o usb-debug.o hub.o
 hid-objs		:= hid-core.o
 pwc-objs		:= pwc-if.o pwc-misc.o pwc-ctrl.o pwc-uncompress.o
-
+auerswald-objs		:= auerbuf.o auerchain.o auerchar.o auermain.o
 
 # Optional parts of multipart objects.
 
@@ -34,6 +34,12 @@
 	hid-objs	+= hid-input.o
 endif
 
+ifdef CONFIG_USB_AUERISDN
+ifneq ($(CONFIG_USB_AUERISDN),n)
+	auerswald-objs	+= auerisdn.o auerisdn_b.o
+endif
+endif
+
 # Object file lists.
 
 obj-y	:=
@@ -47,23 +53,25 @@
 
 # EHCI should initialize/link before the other HCDs
 ifeq ($(CONFIG_USB_EHCI_HCD),y)
-	obj-y += hcd/ehci-hcd.o
+	obj-y += host/ehci-hcd.o
 endif
 
-obj-$(CONFIG_USB_UHCI)		+= usb-uhci.o
-obj-$(CONFIG_USB_UHCI_ALT)	+= uhci.o
-obj-$(CONFIG_USB_OHCI)		+= usb-ohci.o
-
 ifneq ($(CONFIG_USB_EHCI_HCD),n)
 	usbcore-objs		+= hcd.o
 endif
-subdir-$(CONFIG_USB_EHCI_HCD)	+= hcd
+
+subdir-$(CONFIG_USB_EHCI_HCD)	+= host
+subdir-$(CONFIG_USB_UHCI_ALT)	+= host
+subdir-$(CONFIG_USB_UHCI)	+= host
+subdir-$(CONFIG_USB_OHCI)	+= host
 
 obj-$(CONFIG_USB_MOUSE)		+= usbmouse.o
 obj-$(CONFIG_USB_HID)		+= hid.o
 obj-$(CONFIG_USB_KBD)		+= usbkbd.o
 obj-$(CONFIG_USB_AIPTEK)	+= aiptek.o
 obj-$(CONFIG_USB_WACOM)		+= wacom.o
+obj-$(CONFIG_USB_KBTAB)		+= kbtab.o
+obj-$(CONFIG_USB_POWERMATE)	+= powermate.o
 
 obj-$(CONFIG_USB_SCANNER)	+= scanner.o
 obj-$(CONFIG_USB_ACM)		+= acm.o
@@ -72,12 +80,13 @@
 obj-$(CONFIG_USB_EMI26)		+= emi26.o
 obj-$(CONFIG_USB_MIDI)		+= usb-midi.o
 obj-$(CONFIG_USB_IBMCAM)	+= ibmcam.o usbvideo.o ultracam.o
+obj-$(CONFIG_USB_KONICAWC)	+= konicawc.o usbvideo.o
 obj-$(CONFIG_USB_PWC)		+= pwc.o
 obj-$(CONFIG_USB_DC2XX)		+= dc2xx.o
 obj-$(CONFIG_USB_MDC800)	+= mdc800.o
 obj-$(CONFIG_USB_USS720)	+= uss720.o
 obj-$(CONFIG_USB_DABUSB)	+= dabusb.o
-obj-$(CONFIG_USB_VICAM)		+= vicam.o
+obj-$(CONFIG_USB_VICAM)		+= vicam.o usbvideo.o
 obj-$(CONFIG_USB_OV511)		+= ov511.o
 obj-$(CONFIG_USB_SE401)		+= se401.o
 obj-$(CONFIG_USB_STV680)	+= stv680.o
@@ -98,7 +107,7 @@
 obj-$(CONFIG_USB_LCD)		+= usblcd.o
 
 # Object files in subdirectories
-mod-subdirs	:= serial hcd
+mod-subdirs	:= serial host
 
 subdir-$(CONFIG_USB_SERIAL)	+= serial
 subdir-$(CONFIG_USB_STORAGE)	+= storage
@@ -123,3 +132,6 @@
 
 pwc.o: $(pwc-objs)
 	$(LD) -r -o $@ $(pwc-objs)
+
+auerswald.o: $(auerswald-objs)
+	$(LD) -r -o $@ $(auerswald-objs)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/acm.c linux-2.4.21-pre6/drivers/usb/acm.c
--- linux-2.4.20/drivers/usb/acm.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/acm.c	2003-03-26 23:49:02.000000000 +0000
@@ -240,7 +240,7 @@
 	if (urb->status)
 		dbg("nonzero read bulk status received: %d", urb->status);
 
-	if (!urb->status & !acm->throttle)  {
+	if (!urb->status && !acm->throttle)  {
 		for (i = 0; i < urb->actual_length && !acm->throttle; i++) {
 			/* if we insert more than TTY_FLIPBUF_SIZE characters,
 			 * we drop them. */
@@ -649,6 +649,7 @@
  */
 
 static struct usb_device_id acm_ids[] = {
+	{ USB_DEVICE(0x22B8, 0x1005) },		/* Motorola TimePort 280 */
 	{ USB_DEVICE_INFO(USB_CLASS_COMM, 0, 0) },
 	{ }
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/audio.c linux-2.4.21-pre6/drivers/usb/audio.c
--- linux-2.4.20/drivers/usb/audio.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/audio.c	2003-03-26 23:49:55.000000000 +0000
@@ -99,6 +99,12 @@
  *              for abs. Bug report by Andrew Morton <andrewm@uow.edu.au>
  * 2001-06-16:  Bryce Nesbitt <bryce@obviously.com>
  *              Fix SNDCTL_DSP_STEREO API violation
+ * 2002-10-16:  Monty <monty@xiph.org>
+ *              Expand device support from a maximum of 8/16bit,mono/stereo to 
+ *              8/16/24/32bit,N channels.  Add AFMT_?24_?? and AFMT_?32_?? to OSS
+ *              functionality. Tested and used in production with the emagic emi 2|6 
+ *              on PPC and Intel. Also fixed a few logic 'crash and burn' corner 
+ *              cases.
  */
 
 /*
@@ -230,6 +236,11 @@
 #define DMABUFSHIFT       17  /* 128k worth of DMA buffer */
 #define NRSGBUF           (1U<<(DMABUFSHIFT-PAGE_SHIFT))
 
+#define MAXCHANNELS       32
+#define MAXWIDTH          4
+#define MAXSAMPLEWIDTH    (MAXCHANNELS*MAXWIDTH)
+#define TMPCOPYWIDTH      MAXSAMPLEWIDTH /* max (128,MAXSAMPLEWIDTH) */
+
 /*
  * This influences:
  * - Latency
@@ -387,13 +398,62 @@
 	unsigned count;  /* usage counter; NOTE: the usb stack is also considered a user */
 };
 
+/* in the event we don't have the extended soundcard.h, we still need
+   to compile successfully.  Supply definitions */
+
+#ifndef AFMT_S24_LE
+#	define AFMT_S24_LE	        0x00000800	
+#endif
+#ifndef AFMT_S24_BE
+#	define AFMT_S24_BE	        0x00001000	
+#endif
+#ifndef AFMT_U24_LE
+#	define AFMT_U24_LE	        0x00002000	
+#endif
+#ifndef AFMT_U24_BE
+#	define AFMT_U24_BE	        0x00004000	
+#endif
+#ifndef AFMT_S32_LE
+#	define AFMT_S32_LE	        0x00008000	
+#endif
+#ifndef AFMT_S32_BE
+#	define AFMT_S32_BE	        0x00010000	
+#endif
+#ifndef AFMT_U32_LE
+#	define AFMT_U32_LE	        0x00020000	
+#endif
+#ifndef AFMT_U32_BE
+#	define AFMT_U32_BE	        0x00040000	
+#endif
+
 /* private audio format extensions */
-#define AFMT_STEREO        0x80000000
-#define AFMT_ISSTEREO(x)   ((x) & AFMT_STEREO)
-#define AFMT_IS16BIT(x)    ((x) & (AFMT_S16_LE|AFMT_S16_BE|AFMT_U16_LE|AFMT_U16_BE))
-#define AFMT_ISUNSIGNED(x) ((x) & (AFMT_U8|AFMT_U16_LE|AFMT_U16_BE))
-#define AFMT_BYTESSHIFT(x) ((AFMT_ISSTEREO(x) ? 1 : 0) + (AFMT_IS16BIT(x) ? 1 : 0))
-#define AFMT_BYTES(x)      (1<<AFMT_BYTESSHFIT(x))
+#define AFMT_STEREO         0x01000000
+#define AFMT_CHMASK         0xff000000
+#define AFMT_8MASK          (AFMT_U8 | AFMT_S8)
+#define AFMT_16MASK         (AFMT_U16_LE | AFMT_S16_LE | AFMT_U16_BE | AFMT_S16_BE)
+#define AFMT_24MASK         (AFMT_U24_LE | AFMT_S24_LE | AFMT_U24_BE | AFMT_S24_BE)
+#define AFMT_32MASK         (AFMT_U32_LE | AFMT_S32_LE | AFMT_U32_BE | AFMT_S32_BE)
+
+#define AFMT_SIGNMASK       (AFMT_S8 | AFMT_S16_LE | AFMT_S16_BE |\
+                                       AFMT_S24_LE | AFMT_S24_BE |\
+                                       AFMT_S32_LE | AFMT_S32_BE)
+
+/* a little odd, but the code counts on byte formats being identified as 'big endian' */
+#define AFMT_ENDIANMASK     (AFMT_S8 | AFMT_U8 |\
+			               AFMT_S16_BE | AFMT_U16_BE |\
+                                       AFMT_S24_BE | AFMT_U24_BE |\
+                                       AFMT_S32_BE | AFMT_U32_BE)
+
+#define AFMT_ISSTEREO(x)    (((x) & 0xff000000) == AFMT_STEREO)
+#define AFMT_CHANNELS(x)    (((unsigned)(x) >> 24) + 1)
+#define AFMT_BYTES(x)       ( (((x)&AFMT_8MASK)!=0)+\
+                              (((x)&AFMT_16MASK)!=0)*2+\
+                              (((x)&AFMT_24MASK)!=0)*3+\
+                              (((x)&AFMT_32MASK)!=0)*4 )
+#define AFMT_SAMPLEBYTES(x) (AFMT_BYTES(x)*AFMT_CHANNELS(x))
+#define AFMT_SIGN(x)        ((x)&AFMT_SIGNMASK)
+#define AFMT_ENDIAN(x)      ((x)&AFMT_ENDIANMASK)
+
 
 /* --------------------------------------------------------------------- */
 
@@ -468,7 +528,7 @@
 	/* initialize some fields */
 	db->rdptr = db->wrptr = db->total_bytes = db->count = db->error = 0;
 	/* calculate required buffer size */
-	bytepersec = db->srate << AFMT_BYTESSHIFT(db->format);
+	bytepersec = db->srate * AFMT_SAMPLEBYTES(db->format);
 	bufs = 1U << DMABUFSHIFT;
 	if (db->ossfragshift) {
 		if ((1000 << db->ossfragshift) < bytepersec)
@@ -497,7 +557,7 @@
 			db->sgbuf[nr] = p;
 			mem_map_reserve(virt_to_page(p));
 		}
-		memset(db->sgbuf[nr], AFMT_ISUNSIGNED(db->format) ? 0x80 : 0, PAGE_SIZE);
+		memset(db->sgbuf[nr], AFMT_SIGN(db->format) ? 0 : 0x80, PAGE_SIZE);
 		if ((nr << PAGE_SHIFT) >= db->dmasize)
 			break;
 	}
@@ -688,147 +748,168 @@
 	usbin_stop(as);
 }
 
-static void conversion(const void *ibuf, unsigned int ifmt, void *obuf, unsigned int ofmt, void *tmp, unsigned int scnt)
+static inline int iconvert(unsigned char **xx,int jump)
 {
-	unsigned int cnt, i;
-	__s16 *sp, *sp2, s;
-	unsigned char *bp;
-
-	cnt = scnt;
-	if (AFMT_ISSTEREO(ifmt))
-		cnt <<= 1;
-	sp = ((__s16 *)tmp) + cnt;
-	switch (ifmt & ~AFMT_STEREO) {
-	case AFMT_U8:
-		for (bp = ((unsigned char *)ibuf)+cnt, i = 0; i < cnt; i++) {
-			bp--;
-			sp--;
-			*sp = (*bp ^ 0x80) << 8;
-		}
-		break;
+  int value=0;
+  unsigned char *x=*xx;
 			
-	case AFMT_S8:
-		for (bp = ((unsigned char *)ibuf)+cnt, i = 0; i < cnt; i++) {
-			bp--;
-			sp--;
-			*sp = *bp << 8;
-		}
-		break;
-		
-	case AFMT_U16_LE:
-		for (bp = ((unsigned char *)ibuf)+2*cnt, i = 0; i < cnt; i++) {
-			bp -= 2;
-			sp--;
-			*sp = (bp[0] | (bp[1] << 8)) ^ 0x8000;
-		}
-		break;
-
-	case AFMT_U16_BE:
-		for (bp = ((unsigned char *)ibuf)+2*cnt, i = 0; i < cnt; i++) {
-			bp -= 2;
-			sp--;
-			*sp = (bp[1] | (bp[0] << 8)) ^ 0x8000;
-		}
-		break;
-
-	case AFMT_S16_LE:
-		for (bp = ((unsigned char *)ibuf)+2*cnt, i = 0; i < cnt; i++) {
-			bp -= 2;
-			sp--;
-			*sp = bp[0] | (bp[1] << 8);
-		}
-		break;
-
-	case AFMT_S16_BE:
-		for (bp = ((unsigned char *)ibuf)+2*cnt, i = 0; i < cnt; i++) {
-			bp -= 2;
-			sp--;
-			*sp = bp[1] | (bp[0] << 8);
-		}
-		break;
+  /* conversion fall-through cascade compiles to a jump table */
+  switch(jump){
+  case 0:
+    /* 32 bit BE */
+    value  = x[3];
+  case 1:
+    /* 24 bit BE */
+    value |= x[2] << 8;
+  case 2:
+    /* 16 bit BE */
+    value |= x[1] << 16;
+  case 3:
+    /* 8 bit */
+    value |= x[0] << 24;
+    x+=(4-jump);
+    break;
+
+  case 4:
+    /* 32 bit LE */
+    value  = *x++;
+  case 5:
+    /* 24 bit LE */
+    value |= *x++ << 8;
+  case 6:
+    /* 16 bit LE */
+    value |= *x++ << 16;
+    value |= *x++ << 24;
+    break;
+  }
+  *xx=x;
+  return(value);
+}
+
+static inline void oconvert(unsigned char **yy,int jump,int value)
+{
+  unsigned char *y=*yy;
+
+  /* conversion fall-through cascade compiles to a jump table */
+  switch(jump){
+  case 0:
+    /* 32 bit BE */
+    y[3] = value;
+  case 1:
+    /* 24 bit BE */
+    y[2] = value >> 8;
+  case 2:
+    /* 16 bit BE */
+    y[1] = value >> 16;
+  case 3:
+    /* 8 bit */
+    y[0] = value >> 24;
+    y+=(4-jump);
+    break;
+
+  case 4:
+    /* 32 bit LE */
+    *y++ = value;
+  case 5:
+    /* 24 bit LE */
+    *y++ = value >> 8;
+  case 6:
+    /* 16 bit LE */
+    *y++ = value >> 16;
+    *y++ = value >> 24;
+    break;
+  }
+  *yy=y;
+}
+
+/* capable of any-to-any conversion */
+static void conversion(const void *ibuf, unsigned int ifmt, 
+		       void *obuf, unsigned int ofmt, unsigned int scnt)
+{
+
+  /* some conversion is indeed needed */
+  unsigned int i,j;
+  unsigned char *x=(unsigned char *)ibuf;
+  unsigned char *y=(unsigned char *)obuf;
+
+  int ichannels = AFMT_CHANNELS(ifmt);
+  int ochannels = AFMT_CHANNELS(ofmt);
+  int ibytes    = AFMT_BYTES(ifmt);
+  int obytes    = AFMT_BYTES(ofmt);
+  int iendian   = AFMT_ENDIAN(ifmt);
+  int oendian   = AFMT_ENDIAN(ofmt);
+  int isign     = AFMT_SIGN(ifmt)?0:0x80000000UL;
+  int osign     = AFMT_SIGN(ofmt)?0:0x80000000UL;
+  int sign      = (isign==osign?0:0x80000000UL);
+  
+  /* build the byte/endian jump table offsets */
+  int ijump = (iendian ? 4-ibytes : 8-ibytes);
+  int ojump = (oendian ? 4-obytes : 8-obytes);
+  
+  if(ichannels == 2 && ochannels == 1){
+    /* Stereo -> mono is a special case loop; we downmix */
+    for(i=0;i<scnt;i++){
+      int valueL = iconvert(&x,ijump) ^ isign; /* side effect; increments x */
+      int valueR = iconvert(&x,ijump) ^ isign; /* side effect; increments x */
+      int value  = (valueL>>1) + (valueR>>1);
+      oconvert(&y,ojump,value^osign);  /* side effect; increments y */
+		}
+    return;
+		}
+  if(ichannels == 1 && ochannels == 2){
+    /* mono->stereo is a special case loop; we replicate */
+    for(i=0;i<scnt;i++){
+      int value = iconvert(&x,ijump) ^ sign; /* side effect; increments x */
+      oconvert(&y,ojump,value);  /* side effect; increments y */
+      oconvert(&y,ojump,value);  /* side effect; increments y */
+	}
+    return;
+		}
+  if(ichannels<ochannels){
+    /* zero out extra output channels */
+    for(i=0;i<scnt;i++){
+      for(j=0;j<ichannels;j++){
+	int value = iconvert(&x,ijump) ^ sign; /* side effect; increments x */
+	oconvert(&y,ojump,value);  /* side effect; increments y */
+	
+	}
+      for(;j<ochannels;j++){
+	oconvert(&y,ojump,osign);  /* side effect; increments y */
 	}
-	if (!AFMT_ISSTEREO(ifmt) && AFMT_ISSTEREO(ofmt)) {
-		/* expand from mono to stereo */
-		for (sp = ((__s16 *)tmp)+scnt, sp2 = ((__s16 *)tmp)+2*scnt, i = 0; i < scnt; i++) {
-			sp--;
-			sp2 -= 2;
-			sp2[0] = sp2[1] = sp[0];
-		}
-	}
-	if (AFMT_ISSTEREO(ifmt) && !AFMT_ISSTEREO(ofmt)) {
-		/* contract from stereo to mono */
-		for (sp = sp2 = ((__s16 *)tmp), i = 0; i < scnt; i++, sp++, sp2 += 2)
-			sp[0] = (sp2[0] + sp2[1]) >> 1;
-	}
-	cnt = scnt;
-	if (AFMT_ISSTEREO(ofmt))
-		cnt <<= 1;
-	sp = ((__s16 *)tmp);
-	bp = ((unsigned char *)obuf);
-	switch (ofmt & ~AFMT_STEREO) {
-	case AFMT_U8:
-		for (i = 0; i < cnt; i++, sp++, bp++)
-			*bp = (*sp >> 8) ^ 0x80;
-		break;
-
-	case AFMT_S8:
-		for (i = 0; i < cnt; i++, sp++, bp++)
-			*bp = *sp >> 8;
-		break;
-
-	case AFMT_U16_LE:
-		for (i = 0; i < cnt; i++, sp++, bp += 2) {
-			s = *sp;
-			bp[0] = s;
-			bp[1] = (s >> 8) ^ 0x80;
 		}
-		break;
-
-	case AFMT_U16_BE:
-		for (i = 0; i < cnt; i++, sp++, bp += 2) {
-			s = *sp;
-			bp[1] = s;
-			bp[0] = (s >> 8) ^ 0x80;
+    return;
 		}
-		break;
+  if(ichannels>=ochannels){
+    /* discard extra input channels */
+    int xincrement=ibytes*(ichannels-ochannels);
+    for(i=0;i<scnt;i++){
+      for(j=0;j<ichannels;j++){
+	int value = iconvert(&x,ijump) ^ sign; /* side effect; increments x */
+	oconvert(&y,ojump,value);  /* side effect; increments y */
 
-	case AFMT_S16_LE:
-		for (i = 0; i < cnt; i++, sp++, bp += 2) {
-			s = *sp;
-			bp[0] = s;
-			bp[1] = s >> 8;
 		}
-		break;
-
-	case AFMT_S16_BE:
-		for (i = 0; i < cnt; i++, sp++, bp += 2) {
-			s = *sp;
-			bp[1] = s;
-			bp[0] = s >> 8;
+      x+=xincrement;
 		}
-		break;
+    return;
 	}
-	
 }
 
 static void usbin_convert(struct usbin *u, unsigned char *buffer, unsigned int samples)
 {
-	union {
-		__s16 s[64];
-		unsigned char b[0];
-	} tmp;
-	unsigned int scnt, maxs, ufmtsh, dfmtsh;
-
-	ufmtsh = AFMT_BYTESSHIFT(u->format);
-	dfmtsh = AFMT_BYTESSHIFT(u->dma.format);
-	maxs = (AFMT_ISSTEREO(u->dma.format | u->format)) ? 32 : 64;
+        unsigned int scnt;
+	unsigned int ufmtb = AFMT_SAMPLEBYTES(u->format);
+	unsigned int dfmtb = AFMT_SAMPLEBYTES(u->dma.format);
+        unsigned char tmp[TMPCOPYWIDTH];
+	unsigned int maxs  = sizeof(tmp)/dfmtb;
+
 	while (samples > 0) {
 		scnt = samples;
 		if (scnt > maxs)
 			scnt = maxs;
-		conversion(buffer, u->format, tmp.b, u->dma.format, tmp.b, scnt);
-		dmabuf_copyin(&u->dma, tmp.b, scnt << dfmtsh);
-		buffer += scnt << ufmtsh;
+
+	        conversion(buffer, u->format, tmp, u->dma.format, scnt);
+                dmabuf_copyin(&u->dma, tmp, scnt * dfmtb);
+                buffer += scnt * ufmtb;
 		samples -= scnt;
 	}
 }		
@@ -837,7 +918,7 @@
 {
 	unsigned int i, maxsize, offs;
 
-	maxsize = (u->freqmax + 0x3fff) >> (14 - AFMT_BYTESSHIFT(u->format));
+	maxsize = ((u->freqmax + 0x3fff) * AFMT_SAMPLEBYTES(u->format)) >> 14;
 	//printk(KERN_DEBUG "usbin_prepare_desc: maxsize %d freq 0x%x format 0x%x\n", maxsize, u->freqn, u->format);
 	for (i = offs = 0; i < DESCFRAMES; i++, offs += maxsize) {
 		urb->iso_frame_desc[i].length = maxsize;
@@ -852,26 +933,26 @@
  */
 static int usbin_retire_desc(struct usbin *u, struct urb *urb)
 {
-	unsigned int i, ufmtsh, dfmtsh, err = 0, cnt, scnt, dmafree;
+	unsigned int i, ufmtb, dfmtb, err = 0, cnt, scnt, dmafree;
 	unsigned char *cp;
 
-	ufmtsh = AFMT_BYTESSHIFT(u->format);
-	dfmtsh = AFMT_BYTESSHIFT(u->dma.format);
+	ufmtb = AFMT_SAMPLEBYTES(u->format);
+	dfmtb = AFMT_SAMPLEBYTES(u->dma.format);
 	for (i = 0; i < DESCFRAMES; i++) {
 		cp = ((unsigned char *)urb->transfer_buffer) + urb->iso_frame_desc[i].offset;
 		if (urb->iso_frame_desc[i].status) {
 			dprintk((KERN_DEBUG "usbin_retire_desc: frame %u status %d\n", i, urb->iso_frame_desc[i].status));
 			continue;
 		}
-		scnt = urb->iso_frame_desc[i].actual_length >> ufmtsh;
+		scnt = urb->iso_frame_desc[i].actual_length / ufmtb;
 		if (!scnt)
 			continue;
-		cnt = scnt << dfmtsh;
+		cnt = scnt * dfmtb;
 		if (!u->dma.mapped) {
 			dmafree = u->dma.dmasize - u->dma.count;
 			if (cnt > dmafree) {
-				scnt = dmafree >> dfmtsh;
-				cnt = scnt << dfmtsh;
+				scnt = dmafree / dfmtb;
+				cnt = scnt * dfmtb;
 				err++;
 			}
 		}
@@ -1015,7 +1096,7 @@
 		u->freqn = ((u->dma.srate << 11) + 62) / 125; /* this will overflow at approx 2MSPS */
 		u->freqmax = u->freqn + (u->freqn >> 2);
 		u->phase = 0;
-		maxsze = (u->freqmax + 0x3fff) >> (14 - AFMT_BYTESSHIFT(u->format));
+		maxsze = ((u->freqmax + 0x3fff) * AFMT_SAMPLEBYTES(u->format)) >> 14;
 		bufsz = DESCFRAMES * maxsze;
 		if (u->durb[0].urb.transfer_buffer)
 			kfree(u->durb[0].urb.transfer_buffer);
@@ -1166,33 +1247,31 @@
 
 static void usbout_convert(struct usbout *u, unsigned char *buffer, unsigned int samples)
 {
-	union {
-		__s16 s[64];
-		unsigned char b[0];
-	} tmp;
-	unsigned int scnt, maxs, ufmtsh, dfmtsh;
-
-	ufmtsh = AFMT_BYTESSHIFT(u->format);
-	dfmtsh = AFMT_BYTESSHIFT(u->dma.format);
-	maxs = (AFMT_ISSTEREO(u->dma.format | u->format)) ? 32 : 64;
+        unsigned char tmp[TMPCOPYWIDTH];
+        unsigned int scnt;
+	unsigned int ufmtb = AFMT_SAMPLEBYTES(u->format);
+	unsigned int dfmtb = AFMT_SAMPLEBYTES(u->dma.format);
+	unsigned int maxs  = sizeof(tmp)/dfmtb;
+	
 	while (samples > 0) {
 		scnt = samples;
 		if (scnt > maxs)
 			scnt = maxs;
-		dmabuf_copyout(&u->dma, tmp.b, scnt << dfmtsh);
-		conversion(tmp.b, u->dma.format, buffer, u->format, tmp.b, scnt);
-		buffer += scnt << ufmtsh;
+
+		dmabuf_copyout(&u->dma, tmp, scnt * dfmtb);
+		conversion(tmp, u->dma.format, buffer, u->format, scnt);
+                buffer += scnt * ufmtb;
 		samples -= scnt;
 	}
 }		
 
 static int usbout_prepare_desc(struct usbout *u, struct urb *urb)
 {
-	unsigned int i, ufmtsh, dfmtsh, err = 0, cnt, scnt, offs;
+	unsigned int i, ufmtb, dfmtb, err = 0, cnt, scnt, offs;
 	unsigned char *cp = urb->transfer_buffer;
 
-	ufmtsh = AFMT_BYTESSHIFT(u->format);
-	dfmtsh = AFMT_BYTESSHIFT(u->dma.format);
+	ufmtb = AFMT_SAMPLEBYTES(u->format);
+	dfmtb = AFMT_SAMPLEBYTES(u->dma.format);
 	for (i = offs = 0; i < DESCFRAMES; i++) {
 		urb->iso_frame_desc[i].offset = offs;
 		u->phase = (u->phase & 0x3fff) + u->freqm;
@@ -1201,11 +1280,11 @@
 			urb->iso_frame_desc[i].length = 0;
 			continue;
 		}
-		cnt = scnt << dfmtsh;
+		cnt = scnt * dfmtb;
 		if (!u->dma.mapped) {
 			if (cnt > u->dma.count) {
-				scnt = u->dma.count >> dfmtsh;
-				cnt = scnt << dfmtsh;
+				scnt = u->dma.count / dfmtb;
+				cnt = scnt * dfmtb;
 				err++;
 			}
 			u->dma.count -= cnt;
@@ -1218,7 +1297,7 @@
 			/* we need sampling format conversion */
 			usbout_convert(u, cp, scnt);
 		}
-		cnt = scnt << ufmtsh;
+		cnt = scnt * ufmtb;
 		urb->iso_frame_desc[i].length = cnt;
 		offs += cnt;
 		cp += cnt;
@@ -1380,7 +1459,8 @@
 		u->freqn = u->freqm = ((u->dma.srate << 11) + 62) / 125; /* this will overflow at approx 2MSPS */
 		u->freqmax = u->freqn + (u->freqn >> 2);
 		u->phase = 0;
-		maxsze = (u->freqmax + 0x3fff) >> (14 - AFMT_BYTESSHIFT(u->format));
+		maxsze = ((u->freqmax + 0x3fff) * AFMT_SAMPLEBYTES(u->format)) >>14;
+
 		bufsz = DESCFRAMES * maxsze;
 		if (u->durb[0].urb.transfer_buffer)
 			kfree(u->durb[0].urb.transfer_buffer);
@@ -1473,27 +1553,86 @@
 }
 
 /* --------------------------------------------------------------------- */
+/* allowed conversions (sign, endian, width, channels), and relative
+   weighting penalties against fuzzy match selection.  For the
+   purposes of not confusing users, 'lossy' format translation is
+   disallowed, eg, don't allow a mono 8 bit device to successfully
+   open as 5.1, 24 bit... Never allow a mode that tries to deliver greater
+   than the hard capabilities of the device.
+
+   device --=> app
+
+   signed   => unsigned : 1
+   unsigned => signed   : 1
+
+   le       => be       : 1
+   be       => le       : 1
+
+   8        => 16       : not allowed
+   8        => 24       : not allowed
+   8        => 32       : not allowed
+   16       => 24       : not allowed
+   16       => 32       : not allowed
+   24       => 32       : not allowed
+
+   16       => 8        : 4
+   24       => 16       : 4
+   24       => 8        : 5
+   32       => 24       : 4
+   32       => 16       : 5
+   32       => 8        : 5
 
-static unsigned int format_goodness(struct audioformat *afp, unsigned int fmt, unsigned int srate)
-{
+   mono     => stereo   : not allowed
+   stereo   => mono     : 32 (downmix to L+R/2)
+
+   N        => >N       : not allowed
+   N        => <N       : 32 */
+
+static unsigned int format_goodness(struct audioformat *afp, unsigned int app,
+				    unsigned int srate){
 	unsigned int g = 0;
+	unsigned int sratelo=afp->sratelo;
+	unsigned int sratehi=afp->sratehi;
+	unsigned int dev=afp->format;
+
+	if(AFMT_SIGN(dev) && !AFMT_SIGN(app))     g += 1;
+	if(!AFMT_SIGN(dev) && AFMT_SIGN(app))     g += 1;
+	if(AFMT_ENDIAN(dev) && !AFMT_ENDIAN(app)) g += 1;
+	if(!AFMT_ENDIAN(dev) && AFMT_ENDIAN(app)) g += 1;
+
+	switch(AFMT_BYTES(app)+AFMT_BYTES(dev)*10){
+	case 12: return ~0;
+	case 13: return ~0;
+	case 14: return ~0;
+	case 21: g += 4; break;
+	case 23: return ~0;
+	case 24: return ~0;
+	case 31: g += 5; break;
+	case 32: g += 4; break;
+	case 34: return ~0;
+	case 41: g += 6; break;
+	case 42: g += 5; break;
+	case 43: g += 4; break;
+	}
+
+	if(AFMT_CHANNELS(dev) > AFMT_CHANNELS(app)){
+	        g+=32;
+	}else if(AFMT_CHANNELS(dev) < AFMT_CHANNELS(app)){
+	        return ~0;
+	}
+	  
+	g<<=20;
+
+	if (srate < sratelo)
+	        g += sratelo - srate;
+        if (srate > sratehi)
+	        g += srate - sratehi;
 
-	if (srate < afp->sratelo)
-		g += afp->sratelo - srate;
-	if (srate > afp->sratehi)
-		g += srate - afp->sratehi;
-	if (AFMT_ISSTEREO(afp->format) && !AFMT_ISSTEREO(fmt))
-		g += 0x100000;
-	if (!AFMT_ISSTEREO(afp->format) && AFMT_ISSTEREO(fmt))
-		g += 0x400000;
-	if (AFMT_IS16BIT(afp->format) && !AFMT_IS16BIT(fmt))
-		g += 0x100000;
-	if (!AFMT_IS16BIT(afp->format) && AFMT_IS16BIT(fmt))
-		g += 0x400000;
-	return g;
+	return(g);
 }
 
-static int find_format(struct audioformat *afp, unsigned int nr, unsigned int fmt, unsigned int srate)
+static int find_format(struct audioformat *afp, unsigned int nr, 
+			  unsigned int fmt, unsigned int srate)
 {
 	unsigned int i, g, gb = ~0;
 	int j = -1; /* default to failure */
@@ -1501,8 +1640,7 @@
 	/* find "best" format (according to format_goodness) */
 	for (i = 0; i < nr; i++) {
 		g = format_goodness(&afp[i], fmt, srate);
-		if (g >= gb) 
-			continue;
+		if (g >= gb) continue;
 		j = i;
 		gb = g;
 	}
@@ -2116,8 +2254,8 @@
 			set_current_state(TASK_RUNNING);
 			return -EBUSY;
 		}
-		tmo = 3 * HZ * count / as->usbout.dma.srate;
-		tmo >>= AFMT_BYTESSHIFT(as->usbout.dma.format);
+		tmo = 3 * HZ * count / (as->usbout.dma.srate * 
+					AFMT_SAMPLEBYTES(as->usbout.dma.format));
 		if (!schedule_timeout(tmo + 1)) {
 			printk(KERN_DEBUG "usbaudio: dma timed out??\n");
 			break;
@@ -2218,7 +2356,7 @@
 		return ret;
 	if (!access_ok(VERIFY_READ, buffer, count))
 		return -EFAULT;
-	start_thr = (as->usbout.dma.srate << AFMT_BYTESSHIFT(as->usbout.dma.format)) / (1000 / (3 * DESCFRAMES));
+	start_thr = (as->usbout.dma.srate * AFMT_SAMPLEBYTES(as->usbout.dma.format)) / (1000 / (3 * DESCFRAMES));
 	add_wait_queue(&as->usbout.dma.wait, &wait);
 	while (count > 0) {
 #if 0
@@ -2410,6 +2548,7 @@
 		if (get_user(val, (int *)arg))
 			return -EFAULT;
 		val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
+		val2 &= 0x00ffffff;
 		if (val)
 			val2 |= AFMT_STEREO;
 		else
@@ -2423,19 +2562,22 @@
 			return -EFAULT;
 		if (val != 0) {
 			val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
-			if (val == 1)
-				val2 &= ~AFMT_STEREO;
-			else
-				val2 |= AFMT_STEREO;
+			
+			val2 &= 0x00ffffff;
+			val2 |= (val-1)<<24;
+
 			if (set_format(as, file->f_mode, val2, 0))
 				return -EIO;
 		}
 		val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
-		return put_user(AFMT_ISSTEREO(val2) ? 2 : 1, (int *)arg);
+		return put_user(AFMT_CHANNELS(val2), (int *)arg);
 
 	case SNDCTL_DSP_GETFMTS: /* Returns a mask */
 		return put_user(AFMT_U8 | AFMT_U16_LE | AFMT_U16_BE |
-				AFMT_S8 | AFMT_S16_LE | AFMT_S16_BE, (int *)arg);
+				AFMT_S8 | AFMT_S16_LE | AFMT_S16_BE |
+				AFMT_U24_LE | AFMT_U24_BE | AFMT_S24_LE | AFMT_S24_BE |
+				AFMT_U32_LE | AFMT_U32_BE | AFMT_S32_LE | AFMT_S32_BE,
+				(int *)arg);
 
 	case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
 		if (get_user(val, (int *)arg))
@@ -2444,15 +2586,17 @@
 			if (hweight32(val) != 1)
 				return -EINVAL;
 			if (!(val & (AFMT_U8 | AFMT_U16_LE | AFMT_U16_BE |
-				     AFMT_S8 | AFMT_S16_LE | AFMT_S16_BE)))
+				     AFMT_S8 | AFMT_S16_LE | AFMT_S16_BE |
+				     AFMT_U24_LE | AFMT_U24_BE | AFMT_S24_LE | AFMT_S24_BE |
+				     AFMT_U32_LE | AFMT_U32_BE | AFMT_S32_LE | AFMT_S32_BE)))
 				return -EINVAL;
 			val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
-			val |= val2 & AFMT_STEREO;
+			val |= val2 & AFMT_CHMASK;
 			if (set_format(as, file->f_mode, val, 0))
 				return -EIO;
 		}
 		val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
-		return put_user(val2 & ~AFMT_STEREO, (int *)arg);
+		return put_user(val2 & ~AFMT_CHMASK, (int *)arg);
 
 	case SNDCTL_DSP_POST:
 		return 0;
@@ -2491,7 +2635,24 @@
 	case SNDCTL_DSP_GETOSPACE:
 		if (!(file->f_mode & FMODE_WRITE))
 			return -EINVAL;
-		if (!(as->usbout.flags & FLG_RUNNING) && (val = prog_dmabuf_out(as)) != 0)
+
+		/*if (!(as->usbout.flags & FLG_RUNNING) && (val = prog_dmabuf_out(as)) != 0)
+
+		The above is potentially disasterous; if the
+		userspace app calls the GETOSPACE ioctl() before a
+		data write on the device (as can happen in a
+		sensible client that's tracking the write buffer
+		low watermark), the kernel driver will never
+		recover from momentary starvation (recall that
+		FLG_RUNNING will be cleared by usbout_completed)
+		because the ioctl will keep resetting the DMA
+		buffer before each write, potentially never
+		allowing us to fill the buffer back to the DMA
+		restart threshhold.
+
+		Can you tell this was actually biting me? :-) */
+
+		if ((!as->usbout.dma.ready) && (val = prog_dmabuf_out(as)) != 0)
 			return val;
 		spin_lock_irqsave(&as->lock, flags);
 		abinfo.fragsize = as->usbout.dma.fragsize;
@@ -2504,7 +2665,9 @@
 	case SNDCTL_DSP_GETISPACE:
 		if (!(file->f_mode & FMODE_READ))
 			return -EINVAL;
-		if (!(as->usbin.flags & FLG_RUNNING) && (val = prog_dmabuf_in(as)) != 0)
+		
+		/*if (!(as->usbin.flags & FLG_RUNNING) && (val = prog_dmabuf_in(as)) != 0)*/
+		if ((!as->usbin.dma.ready) && (val = prog_dmabuf_in(as)) != 0)
 			return val;
 		spin_lock_irqsave(&as->lock, flags);
 		abinfo.fragsize = as->usbin.dma.fragsize;
@@ -2552,11 +2715,14 @@
 
        case SNDCTL_DSP_GETBLKSIZE:
 		if (file->f_mode & FMODE_WRITE) {
-			if ((val = prog_dmabuf_out(as)))
+
+		  /* do not clobber devices that are already running! */
+		  if ((!as->usbout.dma.ready) && (val = prog_dmabuf_out(as)) != 0)
 				return val;
 			return put_user(as->usbout.dma.fragsize, (int *)arg);
 		}
-		if ((val = prog_dmabuf_in(as)))
+		/* do not clobber devices that are already running! */
+		if ((!as->usbin.dma.ready) && (val = prog_dmabuf_in(as)) != 0)
 			return val;
 		return put_user(as->usbin.dma.fragsize, (int *)arg);
 
@@ -2604,11 +2770,11 @@
 
 	case SOUND_PCM_READ_CHANNELS:
 		val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
-		return put_user(AFMT_ISSTEREO(val2) ? 2 : 1, (int *)arg);
+		return put_user(AFMT_CHANNELS(val2), (int *)arg);
 
 	case SOUND_PCM_READ_BITS:
 		val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
-		return put_user(AFMT_IS16BIT(val2) ? 16 : 8, (int *)arg);
+		return put_user(AFMT_BYTES(val2) * 8, (int *)arg);
 
 	case SOUND_PCM_WRITE_FILTER:
 	case SNDCTL_DSP_SETSYNCRO:
@@ -2864,7 +3030,9 @@
 				       dev->devnum, asifin, i);
 				continue;
 			}
-			format = (fmt[5] == 2) ? (AFMT_U16_LE | AFMT_U8) : (AFMT_S16_LE | AFMT_S8);
+			format = (fmt[5] == 2) ? 
+			  (AFMT_U32_LE | AFMT_U24_LE | AFMT_U16_LE | AFMT_U8) : 
+			  (AFMT_S32_LE | AFMT_S24_LE | AFMT_S16_LE | AFMT_S8);
 			fmt = find_csinterface_descriptor(buffer, buflen, NULL, FORMAT_TYPE, asifin, i);
 			if (!fmt) {
 				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not found\n", 
@@ -2876,7 +3044,7 @@
 				       dev->devnum, asifin, i);
 				continue;
 			}
-			if (fmt[4] < 1 || fmt[4] > 2 || fmt[5] < 1 || fmt[5] > 2) {
+			if (fmt[4] < 1 || fmt[4] > MAXCHANNELS || fmt[5] < 1 || fmt[5] > 4) {
 				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u unsupported channels %u framesize %u\n", 
 				       dev->devnum, asifin, i, fmt[4], fmt[5]);
 				continue;
@@ -2889,13 +3057,26 @@
 			}
 			if (as->numfmtin >= MAXFORMATS)
 				continue;
+			printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u channels %u framesize %u configured\n", 
+				       dev->devnum, asifin, i, fmt[4], fmt[5]);
 			fp = &as->fmtin[as->numfmtin++];
-			if (fmt[5] == 2)
-				format &= (AFMT_U16_LE | AFMT_S16_LE);
-			else
+			switch (fmt[5]) {
+			case 1:
 				format &= (AFMT_U8 | AFMT_S8);
-			if (fmt[4] == 2)
-				format |= AFMT_STEREO;
+				break;
+			case 2:
+				format &= (AFMT_U16_LE | AFMT_S16_LE);
+				break;
+			case 3:
+				format &= (AFMT_U24_LE | AFMT_S24_LE);
+				break;
+			case 4:
+				format &= (AFMT_U32_LE | AFMT_S32_LE);
+				break;
+			}
+			
+			format |= (fmt[4]-1) << 24;
+
 			fp->format = format;
 			fp->altsetting = i;
 			fp->sratelo = fp->sratehi = fmt[8] | (fmt[9] << 8) | (fmt[10] << 16);
@@ -2944,7 +3125,10 @@
 				       dev->devnum, asifout, i);
 				continue;
 			}
-			format = (fmt[5] == 2) ? (AFMT_U16_LE | AFMT_U8) : (AFMT_S16_LE | AFMT_S8);
+			format = (fmt[5] == 2) ? 
+			  (AFMT_U32_LE | AFMT_U24_LE | AFMT_U16_LE | AFMT_U8) : 
+			  (AFMT_S32_LE | AFMT_S24_LE | AFMT_S16_LE | AFMT_S8);
+
 			/* Dallas DS4201 workaround */
 			if (dev->descriptor.idVendor == 0x04fa && dev->descriptor.idProduct == 0x4201)
 				format = (AFMT_S16_LE | AFMT_S8);
@@ -2959,7 +3143,7 @@
 				       dev->devnum, asifout, i);
 				continue;
 			}
-			if (fmt[4] < 1 || fmt[4] > 2 || fmt[5] < 1 || fmt[5] > 2) {
+			if (fmt[4] < 1 || fmt[4] > MAXCHANNELS || fmt[5] < 1 || fmt[5] > 4) {
 				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u unsupported channels %u framesize %u\n", 
 				       dev->devnum, asifout, i, fmt[4], fmt[5]);
 				continue;
@@ -2972,13 +3156,27 @@
 			}
 			if (as->numfmtout >= MAXFORMATS)
 				continue;
+			printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u channels %u framesize %u configured\n", 
+			       dev->devnum, asifout, i, fmt[4], fmt[5]);
 			fp = &as->fmtout[as->numfmtout++];
-			if (fmt[5] == 2)
-				format &= (AFMT_U16_LE | AFMT_S16_LE);
-			else
+
+			switch (fmt[5]) {
+			case 1:
 				format &= (AFMT_U8 | AFMT_S8);
-			if (fmt[4] == 2)
-				format |= AFMT_STEREO;
+				break;
+			case 2:
+				format &= (AFMT_U16_LE | AFMT_S16_LE);
+				break;
+			case 3:
+				format &= (AFMT_U24_LE | AFMT_S24_LE);
+				break;
+			case 4:
+				format &= (AFMT_U32_LE | AFMT_S32_LE);
+				break;
+			}
+
+			format |= (fmt[4]-1) << 24;
+
 			fp->format = format;
 			fp->altsetting = i;
 			fp->sratelo = fp->sratehi = fmt[8] | (fmt[9] << 8) | (fmt[10] << 16);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/auerbuf.c linux-2.4.21-pre6/drivers/usb/auerbuf.c
--- linux-2.4.20/drivers/usb/auerbuf.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/auerbuf.c	2003-03-26 23:48:58.000000000 +0000
@@ -0,0 +1,148 @@
+/*****************************************************************************/
+/*
+ *      auerbuf.c  --  Auerswald PBX/System Telephone urb list storage.
+ *
+ *      Copyright (C) 2002  Wolfgang Mües (wolfgang@iksw-muees.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.
+ */
+ /*****************************************************************************/
+
+#undef DEBUG			/* include debug macros until it's done */
+#include <linux/usb.h>
+#include "auerbuf.h"
+#include <linux/slab.h>
+
+/* free a single auerbuf */
+void auerbuf_free(struct auerbuf *bp)
+{
+	kfree(bp->bufp);
+	kfree(bp->dr);
+	if (bp->urbp) {
+		usb_free_urb(bp->urbp);
+	}
+	kfree(bp);
+}
+
+/* free the buffers from an auerbuf list */
+void auerbuf_free_list(struct list_head *q)
+{
+	struct list_head *tmp;
+	struct list_head *p;
+	struct auerbuf *bp;
+
+	dbg("auerbuf_free_list");
+	for (p = q->next; p != q;) {
+		bp = list_entry(p, struct auerbuf, buff_list);
+		tmp = p->next;
+		list_del(p);
+		p = tmp;
+		auerbuf_free(bp);
+	}
+}
+
+/* free all buffers from an auerbuf chain */
+void auerbuf_free_buffers(struct auerbufctl *bcp)
+{
+	unsigned long flags;
+	dbg("auerbuf_free_buffers");
+
+	spin_lock_irqsave(&bcp->lock, flags);
+
+	auerbuf_free_list(&bcp->free_buff_list);
+	auerbuf_free_list(&bcp->rec_buff_list);
+
+	spin_unlock_irqrestore(&bcp->lock, flags);
+}
+
+/* init the members of a list control block */
+void auerbuf_init(struct auerbufctl *bcp)
+{
+	dbg("auerbuf_init");
+	spin_lock_init(&bcp->lock);
+	INIT_LIST_HEAD(&bcp->free_buff_list);
+	INIT_LIST_HEAD(&bcp->rec_buff_list);
+}
+
+/* setup a list of buffers */
+/* requirement: auerbuf_init() */
+int auerbuf_setup(struct auerbufctl *bcp, unsigned int numElements,
+		  unsigned int bufsize)
+{
+	struct auerbuf *bep;
+
+	dbg("auerbuf_setup called with %d elements of %d bytes",
+	    numElements, bufsize);
+
+	/* fill the list of free elements */
+	for (; numElements; numElements--) {
+		bep =
+		    (struct auerbuf *) kmalloc(sizeof(struct auerbuf),
+					       GFP_KERNEL);
+		if (!bep)
+			goto bl_fail;
+		memset(bep, 0, sizeof(struct auerbuf));
+		bep->list = bcp;
+		INIT_LIST_HEAD(&bep->buff_list);
+		bep->bufp = (char *) kmalloc(bufsize, GFP_KERNEL);
+		if (!bep->bufp)
+			goto bl_fail;
+		bep->dr =
+		    (struct usb_ctrlrequest *)
+		    kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+		if (!bep->dr)
+			goto bl_fail;
+		bep->urbp = usb_alloc_urb(0);
+		if (!bep->urbp)
+			goto bl_fail;
+		list_add_tail(&bep->buff_list, &bcp->free_buff_list);
+	}
+	return 0;
+
+      bl_fail:			/* not enought memory. Free allocated elements */
+	dbg("auerbuf_setup: no more memory");
+	auerbuf_free_buffers(bcp);
+	return -ENOMEM;
+}
+
+/* alloc a free buffer from the list. Returns NULL if no buffer available */
+struct auerbuf *auerbuf_getbuf(struct auerbufctl *bcp)
+{
+	unsigned long flags;
+	struct auerbuf *bp = NULL;
+
+	spin_lock_irqsave(&bcp->lock, flags);
+	if (!list_empty(&bcp->free_buff_list)) {
+		/* yes: get the entry */
+		struct list_head *tmp = bcp->free_buff_list.next;
+		list_del(tmp);
+		bp = list_entry(tmp, struct auerbuf, buff_list);
+	}
+	spin_unlock_irqrestore(&bcp->lock, flags);
+	return bp;
+}
+
+/* insert a used buffer into the free list */
+void auerbuf_releasebuf(struct auerbuf *bp)
+{
+	unsigned long flags;
+	struct auerbufctl *bcp = bp->list;
+	bp->retries = 0;
+
+	dbg("auerbuf_releasebuf called");
+	spin_lock_irqsave(&bcp->lock, flags);
+	list_add_tail(&bp->buff_list, &bcp->free_buff_list);
+	spin_unlock_irqrestore(&bcp->lock, flags);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/auerbuf.h linux-2.4.21-pre6/drivers/usb/auerbuf.h
--- linux-2.4.20/drivers/usb/auerbuf.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/auerbuf.h	2003-03-26 23:49:07.000000000 +0000
@@ -0,0 +1,69 @@
+/*****************************************************************************/
+/*
+ *      auerbuf.h  --  Auerswald PBX/System Telephone urb list storage.
+ *
+ *      Copyright (C) 2002  Wolfgang Mües (wolfgang@iksw-muees.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.
+ */
+ /*****************************************************************************/
+
+/* This module assembles together an URB, an usb_ctrlrequest struct for sending of
+ * control messages, and a data buffer.
+ * These items (auerbuf) are collected in a list (auerbufctl) and are used
+ * for serialized usb data transfer.
+ */
+
+#ifndef AUERBUF_H
+#define AUERBUF_H
+
+#include <linux/usb.h>
+
+/* buffer element */
+struct auerbufctl;			/* forward */
+struct auerbuf {
+	unsigned char *bufp;		/* reference to allocated data buffer */
+	unsigned int len;		/* number of characters in data buffer */
+	unsigned int retries;		/* for urb retries */
+	struct usb_ctrlrequest *dr;	/* for setup data in control messages */
+	struct urb *urbp;		/* USB urb */
+	struct auerbufctl *list;	/* pointer to list */
+	struct list_head buff_list;	/* reference to next buffer in list */
+};
+
+/* buffer list control block */
+struct auerbufctl {
+	spinlock_t lock;		/* protection in interrupt */
+	struct list_head free_buff_list;/* free buffers */
+	struct list_head rec_buff_list;	/* buffers with received data */
+};
+
+/* Function prototypes */
+void auerbuf_free(struct auerbuf *bp);
+
+void auerbuf_free_list(struct list_head *q);
+
+void auerbuf_init(struct auerbufctl *bcp);
+
+void auerbuf_free_buffers(struct auerbufctl *bcp);
+
+int auerbuf_setup(struct auerbufctl *bcp, unsigned int numElements,
+		  unsigned int bufsize);
+
+struct auerbuf *auerbuf_getbuf(struct auerbufctl *bcp);
+
+void auerbuf_releasebuf(struct auerbuf *bp);
+
+#endif	/* AUERBUF_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/auerchain.c linux-2.4.21-pre6/drivers/usb/auerchain.c
--- linux-2.4.20/drivers/usb/auerchain.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/auerchain.c	2003-03-26 23:49:39.000000000 +0000
@@ -0,0 +1,468 @@
+/*****************************************************************************/
+/*
+ *      auerchain.c  --  Auerswald PBX/System Telephone chained urb support.
+ *
+ *      Copyright (C) 2002  Wolfgang Mües (wolfgang@iksw-muees.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.
+ */
+ /*****************************************************************************/
+
+#undef DEBUG			/* include debug macros until it's done */
+#include <linux/usb.h>
+#include "auerchain.h"
+#include <linux/slab.h>
+
+/* completion function for chained urbs */
+static void auerchain_complete(struct urb *urb)
+{
+	unsigned long flags;
+	int result;
+
+	/* get pointer to element and to chain */
+	struct auerchainelement *acep =
+	    (struct auerchainelement *) urb->context;
+	struct auerchain *acp = acep->chain;
+
+	/* restore original entries in urb */
+	urb->context = acep->context;
+	urb->complete = acep->complete;
+
+	dbg("auerchain_complete called");
+
+	/* call original completion function
+	   NOTE: this function may lead to more urbs submitted into the chain.
+	   (no chain lock at calling complete()!)
+	   acp->active != NULL is protecting us against recursion. */
+	urb->complete(urb);
+
+	/* detach element from chain data structure */
+	spin_lock_irqsave(&acp->lock, flags);
+	if (acp->active != acep)	/* paranoia debug check */
+		dbg("auerchain_complete: completion on non-active element called!");
+	else
+		acp->active = NULL;
+
+	/* add the used chain element to the list of free elements */
+	list_add_tail(&acep->list, &acp->free_list);
+	acep = NULL;
+
+	/* is there a new element waiting in the chain? */
+	if (!acp->active && !list_empty(&acp->waiting_list)) {
+		/* yes: get the entry */
+		struct list_head *tmp = acp->waiting_list.next;
+		list_del(tmp);
+		acep = list_entry(tmp, struct auerchainelement, list);
+		acp->active = acep;
+	}
+	spin_unlock_irqrestore(&acp->lock, flags);
+
+	/* submit the new urb */
+	if (acep) {
+		urb = acep->urbp;
+		dbg("auerchain_complete: submitting next urb from chain");
+		urb->status = 0;	/* needed! */
+		result = usb_submit_urb(urb);
+
+		/* check for submit errors */
+		if (result) {
+			urb->status = result;
+			dbg("auerchain_complete: usb_submit_urb with error code %d", result);
+			/* and do error handling via *this* completion function (recursive) */
+			auerchain_complete(urb);
+		}
+	} else {
+		/* simple return without submitting a new urb.
+		   The empty chain is detected with acp->active == NULL. */
+	};
+}
+
+/* submit function for chained urbs
+   this function may be called from completion context or from user space!
+   early = 1 -> submit in front of chain
+*/
+int auerchain_submit_urb_list(struct auerchain *acp, struct urb *urb,
+			      int early)
+{
+	int result;
+	unsigned long flags;
+	struct auerchainelement *acep = NULL;
+
+	dbg("auerchain_submit_urb called");
+
+	/* try to get a chain element */
+	spin_lock_irqsave(&acp->lock, flags);
+	if (!list_empty(&acp->free_list)) {
+		/* yes: get the entry */
+		struct list_head *tmp = acp->free_list.next;
+		list_del(tmp);
+		acep = list_entry(tmp, struct auerchainelement, list);
+	}
+	spin_unlock_irqrestore(&acp->lock, flags);
+
+	/* if no chain element available: return with error */
+	if (!acep) {
+		return -ENOMEM;
+	}
+
+	/* fill in the new chain element values */
+	acep->chain = acp;
+	acep->context = urb->context;
+	acep->complete = urb->complete;
+	acep->urbp = urb;
+	INIT_LIST_HEAD(&acep->list);
+
+	/* modify urb */
+	urb->context = acep;
+	urb->complete = auerchain_complete;
+	urb->status = -EINPROGRESS;	/* usb_submit_urb does this, too */
+
+	/* add element to chain - or start it immediately */
+	spin_lock_irqsave(&acp->lock, flags);
+	if (acp->active) {
+		/* there is traffic in the chain, simple add element to chain */
+		if (early) {
+			dbg("adding new urb to head of chain");
+			list_add(&acep->list, &acp->waiting_list);
+		} else {
+			dbg("adding new urb to end of chain");
+			list_add_tail(&acep->list, &acp->waiting_list);
+		}
+		acep = NULL;
+	} else {
+		/* the chain is empty. Prepare restart */
+		acp->active = acep;
+	}
+	/* Spin has to be removed before usb_submit_urb! */
+	spin_unlock_irqrestore(&acp->lock, flags);
+
+	/* Submit urb if immediate restart */
+	if (acep) {
+		dbg("submitting urb immediate");
+		urb->status = 0;	/* needed! */
+		result = usb_submit_urb(urb);
+		/* check for submit errors */
+		if (result) {
+			urb->status = result;
+			dbg("auerchain_submit_urb: usb_submit_urb with error code %d", result);
+			/* and do error handling via completion function */
+			auerchain_complete(urb);
+		}
+	}
+
+	return 0;
+}
+
+/* submit function for chained urbs
+   this function may be called from completion context or from user space!
+*/
+int auerchain_submit_urb(struct auerchain *acp, struct urb *urb)
+{
+	return auerchain_submit_urb_list(acp, urb, 0);
+}
+
+/* cancel an urb which is submitted to the chain
+   the result is 0 if the urb is cancelled, or -EINPROGRESS if
+   USB_ASYNC_UNLINK is set and the function is successfully started.
+*/
+int auerchain_unlink_urb(struct auerchain *acp, struct urb *urb)
+{
+	unsigned long flags;
+	struct urb *urbp;
+	struct auerchainelement *acep;
+	struct list_head *tmp;
+
+	dbg("auerchain_unlink_urb called");
+
+	/* search the chain of waiting elements */
+	spin_lock_irqsave(&acp->lock, flags);
+	list_for_each(tmp, &acp->waiting_list) {
+		acep = list_entry(tmp, struct auerchainelement, list);
+		if (acep->urbp == urb) {
+			list_del(tmp);
+			urb->context = acep->context;
+			urb->complete = acep->complete;
+			list_add_tail(&acep->list, &acp->free_list);
+			spin_unlock_irqrestore(&acp->lock, flags);
+			dbg("unlink waiting urb");
+			urb->status = -ENOENT;
+			urb->complete(urb);
+			return 0;
+		}
+	}
+	/* not found. */
+	spin_unlock_irqrestore(&acp->lock, flags);
+
+	/* get the active urb */
+	acep = acp->active;
+	if (acep) {
+		urbp = acep->urbp;
+
+		/* check if we have to cancel the active urb */
+		if (urbp == urb) {
+			/* note that there is a race condition between the check above
+			   and the unlink() call because of no lock. This race is harmless,
+			   because the usb module will detect the unlink() after completion.
+			   We can't use the acp->lock here because the completion function
+			   wants to grab it.
+			 */
+			dbg("unlink active urb");
+			return usb_unlink_urb(urbp);
+		}
+	}
+
+	/* not found anyway
+	   ... is some kind of success
+	 */
+	dbg("urb to unlink not found in chain");
+	return 0;
+}
+
+/* cancel all urbs which are in the chain.
+   this function must not be called from interrupt or completion handler.
+*/
+void auerchain_unlink_all(struct auerchain *acp)
+{
+	unsigned long flags;
+	struct urb *urbp;
+	struct auerchainelement *acep;
+
+	dbg("auerchain_unlink_all called");
+
+	/* clear the chain of waiting elements */
+	spin_lock_irqsave(&acp->lock, flags);
+	while (!list_empty(&acp->waiting_list)) {
+		/* get the next entry */
+		struct list_head *tmp = acp->waiting_list.next;
+		list_del(tmp);
+		acep = list_entry(tmp, struct auerchainelement, list);
+		urbp = acep->urbp;
+		urbp->context = acep->context;
+		urbp->complete = acep->complete;
+		list_add_tail(&acep->list, &acp->free_list);
+		spin_unlock_irqrestore(&acp->lock, flags);
+		dbg("unlink waiting urb");
+		urbp->status = -ENOENT;
+		urbp->complete(urbp);
+		spin_lock_irqsave(&acp->lock, flags);
+	}
+	spin_unlock_irqrestore(&acp->lock, flags);
+
+	/* clear the active urb */
+	acep = acp->active;
+	if (acep) {
+		urbp = acep->urbp;
+		urbp->transfer_flags &= ~USB_ASYNC_UNLINK;
+		dbg("unlink active urb");
+		usb_unlink_urb(urbp);
+	}
+}
+
+
+/* free the chain.
+   this function must not be called from interrupt or completion handler.
+*/
+void auerchain_free(struct auerchain *acp)
+{
+	unsigned long flags;
+	struct auerchainelement *acep;
+
+	dbg("auerchain_free called");
+
+	/* first, cancel all pending urbs */
+	auerchain_unlink_all(acp);
+
+	/* free the elements */
+	spin_lock_irqsave(&acp->lock, flags);
+	while (!list_empty(&acp->free_list)) {
+		/* get the next entry */
+		struct list_head *tmp = acp->free_list.next;
+		list_del(tmp);
+		spin_unlock_irqrestore(&acp->lock, flags);
+		acep = list_entry(tmp, struct auerchainelement, list);
+		kfree(acep);
+		spin_lock_irqsave(&acp->lock, flags);
+	}
+	spin_unlock_irqrestore(&acp->lock, flags);
+}
+
+
+/* Init the chain control structure */
+void auerchain_init(struct auerchain *acp)
+{
+	/* init the chain data structure */
+	acp->active = NULL;
+	spin_lock_init(&acp->lock);
+	INIT_LIST_HEAD(&acp->waiting_list);
+	INIT_LIST_HEAD(&acp->free_list);
+}
+
+/* setup a chain.
+   It is assumed that there is no concurrency while setting up the chain
+   requirement: auerchain_init()
+*/
+int auerchain_setup(struct auerchain *acp, unsigned int numElements)
+{
+	struct auerchainelement *acep;
+
+	dbg("auerchain_setup called with %d elements", numElements);
+
+	/* fill the list of free elements */
+	for (; numElements; numElements--) {
+		acep =
+		    (struct auerchainelement *)
+		    kmalloc(sizeof(struct auerchainelement), GFP_KERNEL);
+		if (!acep)
+			goto ac_fail;
+		memset(acep, 0, sizeof(struct auerchainelement));
+		INIT_LIST_HEAD(&acep->list);
+		list_add_tail(&acep->list, &acp->free_list);
+	}
+	return 0;
+
+      ac_fail:	/* free the elements */
+	while (!list_empty(&acp->free_list)) {
+		/* get the next entry */
+		struct list_head *tmp = acp->free_list.next;
+		list_del(tmp);
+		acep = list_entry(tmp, struct auerchainelement, list);
+		kfree(acep);
+	}
+	return -ENOMEM;
+}
+
+
+/* completion handler for synchronous chained URBs */
+static void auerchain_blocking_completion(struct urb *urb)
+{
+	struct auerchain_chs *pchs = (struct auerchain_chs *) urb->context;
+	pchs->done = 1;
+	wmb();
+	wake_up(&pchs->wqh);
+}
+
+
+/* Starts chained urb and waits for completion or timeout */
+static int auerchain_start_wait_urb(struct auerchain *acp, struct urb *urb,
+				    int timeout, int *actual_length)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	struct auerchain_chs chs;
+	int status;
+
+	dbg("auerchain_start_wait_urb called");
+	init_waitqueue_head(&chs.wqh);
+	chs.done = 0;
+
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	add_wait_queue(&chs.wqh, &wait);
+	urb->context = &chs;
+	status = auerchain_submit_urb(acp, urb);
+	if (status) {
+		/* something went wrong */
+		set_current_state(TASK_RUNNING);
+		remove_wait_queue(&chs.wqh, &wait);
+		return status;
+	}
+
+	while (timeout && !chs.done) {
+		timeout = schedule_timeout(timeout);
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		rmb();
+	}
+
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&chs.wqh, &wait);
+
+	if (!timeout && !chs.done) {
+		if (urb->status != -EINPROGRESS) {	/* No callback?!! */
+			dbg("auerchain_start_wait_urb: raced timeout");
+			status = urb->status;
+		} else {
+			dbg("auerchain_start_wait_urb: timeout");
+			auerchain_unlink_urb(acp, urb);	/* remove urb safely */
+			status = -ETIMEDOUT;
+		}
+	} else
+		status = urb->status;
+
+	if (actual_length)
+		*actual_length = urb->actual_length;
+
+	return status;
+}
+
+
+/* auerchain_control_msg - Builds a control urb, sends it off and waits for completion
+   acp: pointer to the auerchain
+   dev: pointer to the usb device to send the message to
+   pipe: endpoint "pipe" to send the message to
+   request: USB message request value
+   requesttype: USB message request type value
+   value: USB message value
+   index: USB message index value
+   data: pointer to the data to send
+   size: length in bytes of the data to send
+   timeout: time to wait for the message to complete before timing out (if 0 the wait is forever)
+
+   This function sends a simple control message to a specified endpoint
+   and waits for the message to complete, or timeout.
+
+   If successful, it returns the transfered length, othwise a negative error number.
+
+   Don't use this function from within an interrupt context, like a
+   bottom half handler.  If you need a asyncronous message, or need to send
+   a message from within interrupt context, use auerchain_submit_urb()
+*/
+int auerchain_control_msg(struct auerchain *acp, struct usb_device *dev,
+			  unsigned int pipe, __u8 request,
+			  __u8 requesttype, __u16 value, __u16 index,
+			  void *data, __u16 size, int timeout)
+{
+	int ret;
+	struct usb_ctrlrequest *dr;
+	struct urb *urb;
+	int length;
+
+	dbg("auerchain_control_msg");
+	dr = (struct usb_ctrlrequest *)
+	    kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+	if (!dr)
+		return -ENOMEM;
+	urb = usb_alloc_urb(0);
+	if (!urb) {
+		kfree(dr);
+		return -ENOMEM;
+	}
+
+	dr->bRequestType = requesttype;
+	dr->bRequest = request;
+	dr->wValue = cpu_to_le16(value);
+	dr->wIndex = cpu_to_le16(index);
+	dr->wLength = cpu_to_le16(size);
+
+	FILL_CONTROL_URB(urb, dev, pipe, (unsigned char *) dr, data, size,	/* build urb */
+			 (usb_complete_t) auerchain_blocking_completion,
+			 0);
+	ret = auerchain_start_wait_urb(acp, urb, timeout, &length);
+
+	usb_free_urb(urb);
+	kfree(dr);
+
+	if (ret < 0)
+		return ret;
+	else
+		return length;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/auerchain.h linux-2.4.21-pre6/drivers/usb/auerchain.h
--- linux-2.4.20/drivers/usb/auerchain.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/auerchain.h	2003-03-26 23:49:10.000000000 +0000
@@ -0,0 +1,79 @@
+/*****************************************************************************/
+/*
+ *      auerchain.h  --  Auerswald PBX/System Telephone chained urb support.
+ *
+ *      Copyright (C) 2002  Wolfgang Mües (wolfgang@iksw-muees.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.
+ */
+ /*****************************************************************************/
+
+/* This module is used to make a FIFO of URBs, to serialize the submit.
+ * This may be used to serialize control messages, which is not supported
+ * by the Linux USB subsystem.
+ */
+
+#ifndef AUERCHAIN_H
+#define AUERCHAIN_H
+
+#include <linux/usb.h>
+
+/* urb chain element */
+struct auerchain;			/* forward for circular reference */
+struct auerchainelement {
+	struct auerchain *chain;	/* pointer to the chain to which this element belongs */
+	struct urb *urbp;		/* pointer to attached urb */
+	void *context;			/* saved URB context */
+	usb_complete_t complete;	/* saved URB completion function */
+	struct list_head list;		/* to include element into a list */
+};
+
+/* urb chain */
+struct auerchain {
+	struct auerchainelement *active;/* element which is submitted to urb */
+	spinlock_t lock;		/* protection agains interrupts */
+	struct list_head waiting_list;	/* list of waiting elements */
+	struct list_head free_list;	/* list of available elements */
+};
+
+/* urb blocking completion helper struct */
+struct auerchain_chs {
+	wait_queue_head_t wqh;		/* wait for completion */
+	unsigned int done;		/* completion flag */
+};
+
+
+/* Function prototypes */
+int auerchain_submit_urb_list(struct auerchain *acp, struct urb *urb,
+			      int early);
+
+int auerchain_submit_urb(struct auerchain *acp, struct urb *urb);
+
+int auerchain_unlink_urb(struct auerchain *acp, struct urb *urb);
+
+void auerchain_unlink_all(struct auerchain *acp);
+
+void auerchain_free(struct auerchain *acp);
+
+void auerchain_init(struct auerchain *acp);
+
+int auerchain_setup(struct auerchain *acp, unsigned int numElements);
+
+int auerchain_control_msg(struct auerchain *acp, struct usb_device *dev,
+			  unsigned int pipe, __u8 request,
+			  __u8 requesttype, __u16 value, __u16 index,
+			  void *data, __u16 size, int timeout);
+
+#endif	/* AUERCHAIN_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/auerchar.c linux-2.4.21-pre6/drivers/usb/auerchar.c
--- linux-2.4.20/drivers/usb/auerchar.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/auerchar.c	2003-03-26 23:49:29.000000000 +0000
@@ -0,0 +1,615 @@
+/*****************************************************************************/
+/*
+ *      auerchar.c  --  Auerswald PBX/System Telephone character interface.
+ *
+ *      Copyright (C) 2002  Wolfgang Mües (wolfgang@iksw-muees.de)
+ *
+ *      Very much code of this driver is borrowed from dabusb.c (Deti Fliegl)
+ *      and from the USB Skeleton driver (Greg Kroah-Hartman). Thank you.
+ *
+ *      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.
+ */
+ /*****************************************************************************/
+
+#undef DEBUG			/* include debug macros until it's done */
+#include <linux/usb.h>
+#include "auerchar.h"
+#include "auermain.h"
+#include <linux/slab.h>
+#include <asm/uaccess.h>	/* user area access functions */
+
+/*-------------------------------------------------------------------*/
+
+/* wake up waiting readers */
+static void auerchar_disconnect(struct auerscon *scp)
+{
+	struct auerchar *ccp =((struct auerchar *) ((char *) (scp) - (unsigned long) (&((struct auerchar *) 0)->scontext)));
+	dbg("auerchar_disconnect called");
+	ccp->removed = 1;
+	wake_up(&ccp->readwait);
+}
+
+
+/* dispatch a read paket to a waiting character device */
+static void auerchar_ctrlread_dispatch(struct auerscon *scp,
+				       struct auerbuf *bp)
+{
+	unsigned long flags;
+	struct auerchar *ccp;
+	struct auerbuf *newbp = NULL;
+	char *charp;
+	dbg("auerchar_ctrlread_dispatch called");
+	ccp =((struct auerchar *) ((char *) (scp) - (unsigned long)(&((struct auerchar *) 0)->scontext)));
+
+	/* get a read buffer from character device context */
+	newbp = auerbuf_getbuf(&ccp->bufctl);
+	if (!newbp) {
+		dbg("No read buffer available, discard paket!");
+		return;		/* no buffer, no dispatch */
+	}
+
+	/* copy information to new buffer element
+	   (all buffers have the same length) */
+	charp = newbp->bufp;
+	newbp->bufp = bp->bufp;
+	bp->bufp = charp;
+	newbp->len = bp->len;
+
+	/* insert new buffer in read list */
+	spin_lock_irqsave(&ccp->bufctl.lock, flags);
+	list_add_tail(&newbp->buff_list, &ccp->bufctl.rec_buff_list);
+	spin_unlock_irqrestore(&ccp->bufctl.lock, flags);
+	dbg("read buffer appended to rec_list");
+
+	/* wake up pending synchronous reads */
+	wake_up(&ccp->readwait);
+}
+
+
+/* Delete an auerswald character context */
+void auerchar_delete(struct auerchar *ccp)
+{
+	dbg("auerchar_delete");
+	if (ccp == NULL)
+		return;
+
+	/* wake up pending synchronous reads */
+	ccp->removed = 1;
+	wake_up(&ccp->readwait);
+
+	/* remove the read buffer */
+	if (ccp->readbuf) {
+		auerbuf_releasebuf(ccp->readbuf);
+		ccp->readbuf = NULL;
+	}
+
+	/* remove the character buffers */
+	auerbuf_free_buffers(&ccp->bufctl);
+
+	/* release the memory */
+	kfree(ccp);
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Char device functions                                                 */
+
+/* Open a new character device */
+int auerchar_open(struct inode *inode, struct file *file)
+{
+	int dtindex = MINOR(inode->i_rdev) - AUER_MINOR_BASE;
+	struct auerswald *cp = NULL;
+	struct auerchar *ccp = NULL;
+	int ret;
+
+	/* minor number in range? */
+	if ((dtindex < 0) || (dtindex >= AUER_MAX_DEVICES)) {
+		return -ENODEV;
+	}
+	/* usb device available? */
+	if (down_interruptible(&auerdev_table_mutex)) {
+		return -ERESTARTSYS;
+	}
+	cp = auerdev_table[dtindex];
+	if (cp == NULL) {
+		up(&auerdev_table_mutex);
+		return -ENODEV;
+	}
+	if (down_interruptible(&cp->mutex)) {
+		up(&auerdev_table_mutex);
+		return -ERESTARTSYS;
+	}
+	up(&auerdev_table_mutex);
+
+	/* we have access to the device. Now lets allocate memory */
+	ccp = (struct auerchar *) kmalloc(sizeof(struct auerchar), GFP_KERNEL);
+	if (ccp == NULL) {
+		err("out of memory");
+		ret = -ENOMEM;
+		goto ofail;
+	}
+
+	/* Initialize device descriptor */
+	memset(ccp, 0, sizeof(struct auerchar));
+	init_MUTEX(&ccp->mutex);
+	init_MUTEX(&ccp->readmutex);
+	auerbuf_init(&ccp->bufctl);
+	ccp->scontext.id = AUH_UNASSIGNED;
+	ccp->scontext.dispatch = auerchar_ctrlread_dispatch;
+	ccp->scontext.disconnect = auerchar_disconnect;
+	init_waitqueue_head(&ccp->readwait);
+
+	ret =
+	    auerbuf_setup(&ccp->bufctl, AU_RBUFFERS,
+			  cp->maxControlLength + AUH_SIZE);
+	if (ret) {
+		goto ofail;
+	}
+
+	cp->open_count++;
+	ccp->auerdev = cp;
+	dbg("open %s as /dev/usb/%s", cp->dev_desc, cp->name);
+	up(&cp->mutex);
+
+	/* file IO stuff */
+	file->f_pos = 0;
+	file->private_data = ccp;
+	return 0;
+
+	/* Error exit */
+      ofail:up(&cp->mutex);
+	auerchar_delete(ccp);
+	return ret;
+}
+
+
+/* IOCTL functions */
+int auerchar_ioctl(struct inode *inode, struct file *file,
+		   unsigned int cmd, unsigned long arg)
+{
+	struct auerchar *ccp = (struct auerchar *) file->private_data;
+	int ret = 0;
+	struct audevinfo devinfo;
+	struct auerswald *cp = NULL;
+	unsigned int u;
+	dbg("ioctl");
+
+	/* get the mutexes */
+	if (down_interruptible(&ccp->mutex)) {
+		return -ERESTARTSYS;
+	}
+	cp = ccp->auerdev;
+	if (!cp) {
+		up(&ccp->mutex);
+		return -ENODEV;
+	}
+	if (down_interruptible(&cp->mutex)) {
+		up(&ccp->mutex);
+		return -ERESTARTSYS;
+	}
+
+	/* Check for removal */
+	if (!cp->usbdev) {
+		up(&cp->mutex);
+		up(&ccp->mutex);
+		return -ENODEV;
+	}
+
+	switch (cmd) {
+
+		/* return != 0 if Transmitt channel ready to send */
+	case IOCTL_AU_TXREADY:
+		dbg("IOCTL_AU_TXREADY");
+		u = ccp->auerdev && (ccp->scontext.id != AUH_UNASSIGNED)
+		    && !list_empty(&cp->bufctl.free_buff_list);
+		ret = put_user(u, (unsigned int *) arg);
+		break;
+
+		/* return != 0 if connected to a service channel */
+	case IOCTL_AU_CONNECT:
+		dbg("IOCTL_AU_CONNECT");
+		u = (ccp->scontext.id != AUH_UNASSIGNED);
+		ret = put_user(u, (unsigned int *) arg);
+		break;
+
+		/* return != 0 if Receive Data available */
+	case IOCTL_AU_RXAVAIL:
+		dbg("IOCTL_AU_RXAVAIL");
+		if (ccp->scontext.id == AUH_UNASSIGNED) {
+			ret = -EIO;
+			break;
+		}
+		u = 0;		/* no data */
+		if (ccp->readbuf) {
+			int restlen = ccp->readbuf->len - ccp->readoffset;
+			if (restlen > 0)
+				u = 1;
+		}
+		if (!u) {
+			if (!list_empty(&ccp->bufctl.rec_buff_list)) {
+				u = 1;
+			}
+		}
+		ret = put_user(u, (unsigned int *) arg);
+		break;
+
+		/* return the max. buffer length for the device */
+	case IOCTL_AU_BUFLEN:
+		dbg("IOCTL_AU_BUFLEN");
+		u = cp->maxControlLength;
+		ret = put_user(u, (unsigned int *) arg);
+		break;
+
+		/* requesting a service channel */
+	case IOCTL_AU_SERVREQ:
+		dbg("IOCTL_AU_SERVREQ");
+		/* requesting a service means: release the previous one first */
+		auerswald_removeservice(cp, &ccp->scontext);
+		/* get the channel number */
+		ret = get_user(u, (unsigned int *) arg);
+		if (ret) {
+			break;
+		}
+		if ((u < AUH_FIRSTUSERCH) || (u >= AUH_TYPESIZE)) {
+			ret = -EIO;
+			break;
+		}
+		dbg("auerchar service request parameters are ok");
+		ccp->scontext.id = u;
+
+		/* request the service now */
+		ret = auerswald_addservice(cp, &ccp->scontext);
+		if (ret) {
+			/* no: revert service entry */
+			ccp->scontext.id = AUH_UNASSIGNED;
+		}
+		break;
+
+		/* get a string descriptor for the device */
+	case IOCTL_AU_DEVINFO:
+		dbg("IOCTL_AU_DEVINFO");
+		if (copy_from_user
+		    (&devinfo, (void *) arg, sizeof(struct audevinfo))) {
+			ret = -EFAULT;
+			break;
+		}
+		u = strlen(cp->dev_desc) + 1;
+		if (u > devinfo.bsize) {
+			u = devinfo.bsize;
+		}
+		ret = copy_to_user(devinfo.buf, cp->dev_desc, u);
+		break;
+
+		/* get the max. string descriptor length */
+	case IOCTL_AU_SLEN:
+		dbg("IOCTL_AU_SLEN");
+		u = AUSI_DLEN;
+		ret = put_user(u, (unsigned int *) arg);
+		break;
+
+	default:
+		dbg("IOCTL_AU_UNKNOWN");
+		ret = -ENOIOCTLCMD;
+		break;
+	}
+	/* release the mutexes */
+	up(&cp->mutex);
+	up(&ccp->mutex);
+	return ret;
+}
+
+
+/* Seek is not supported */
+loff_t auerchar_llseek(struct file * file, loff_t offset, int origin)
+{
+	dbg("auerchar_seek");
+	return -ESPIPE;
+}
+
+
+/* Read data from the device */
+ssize_t auerchar_read(struct file * file, char *buf, size_t count,
+		      loff_t * ppos)
+{
+	unsigned long flags;
+	struct auerchar *ccp = (struct auerchar *) file->private_data;
+	struct auerbuf *bp = NULL;
+	wait_queue_t wait;
+
+	dbg("auerchar_read");
+
+	/* Error checking */
+	if (!ccp)
+		return -EIO;
+	if (*ppos)
+		return -ESPIPE;
+	if (count == 0)
+		return 0;
+
+	/* get the mutex */
+	if (down_interruptible(&ccp->mutex))
+		return -ERESTARTSYS;
+
+	/* Can we expect to read something? */
+	if (ccp->scontext.id == AUH_UNASSIGNED) {
+		up(&ccp->mutex);
+		return -EIO;
+	}
+
+	/* only one reader per device allowed */
+	if (down_interruptible(&ccp->readmutex)) {
+		up(&ccp->mutex);
+		return -ERESTARTSYS;
+	}
+
+	/* read data from readbuf, if available */
+      doreadbuf:
+	bp = ccp->readbuf;
+	if (bp) {
+		/* read the maximum bytes */
+		int restlen = bp->len - ccp->readoffset;
+		if (restlen < 0)
+			restlen = 0;
+		if (count > restlen)
+			count = restlen;
+		if (count) {
+			if (copy_to_user
+			    (buf, bp->bufp + ccp->readoffset, count)) {
+				dbg("auerswald_read: copy_to_user failed");
+				up(&ccp->readmutex);
+				up(&ccp->mutex);
+				return -EFAULT;
+			}
+		}
+		/* advance the read offset */
+		ccp->readoffset += count;
+		restlen -= count;
+		// reuse the read buffer
+		if (restlen <= 0) {
+			auerbuf_releasebuf(bp);
+			ccp->readbuf = NULL;
+		}
+		/* return with number of bytes read */
+		if (count) {
+			up(&ccp->readmutex);
+			up(&ccp->mutex);
+			return count;
+		}
+	}
+
+	/* a read buffer is not available. Try to get the next data block. */
+      doreadlist:
+	/* Preparing for sleep */
+	init_waitqueue_entry(&wait, current);
+	set_current_state(TASK_INTERRUPTIBLE);
+	add_wait_queue(&ccp->readwait, &wait);
+
+	bp = NULL;
+	spin_lock_irqsave(&ccp->bufctl.lock, flags);
+	if (!list_empty(&ccp->bufctl.rec_buff_list)) {
+		/* yes: get the entry */
+		struct list_head *tmp = ccp->bufctl.rec_buff_list.next;
+		list_del(tmp);
+		bp = list_entry(tmp, struct auerbuf, buff_list);
+	}
+	spin_unlock_irqrestore(&ccp->bufctl.lock, flags);
+
+	/* have we got data? */
+	if (bp) {
+		ccp->readbuf = bp;
+		ccp->readoffset = AUH_SIZE;	/* for headerbyte */
+		set_current_state(TASK_RUNNING);
+		remove_wait_queue(&ccp->readwait, &wait);
+		goto doreadbuf;	/* now we can read! */
+	}
+
+	/* no data available. Should we wait? */
+	if (file->f_flags & O_NONBLOCK) {
+		dbg("No read buffer available, returning -EAGAIN");
+		set_current_state(TASK_RUNNING);
+		remove_wait_queue(&ccp->readwait, &wait);
+		up(&ccp->readmutex);
+		up(&ccp->mutex);
+		return -EAGAIN;	/* nonblocking, no data available */
+	}
+
+	/* yes, we should wait! */
+	up(&ccp->mutex);	/* allow other operations while we wait */
+	schedule();
+	remove_wait_queue(&ccp->readwait, &wait);
+	if (signal_pending(current)) {
+		/* waked up by a signal */
+		up(&ccp->readmutex);
+		return -ERESTARTSYS;
+	}
+
+	/* Anything left to read? */
+	if ((ccp->scontext.id == AUH_UNASSIGNED) || ccp->removed) {
+		up(&ccp->readmutex);
+		return -EIO;
+	}
+
+	if (down_interruptible(&ccp->mutex)) {
+		up(&ccp->readmutex);
+		return -ERESTARTSYS;
+	}
+
+	/* try to read the incomming data again */
+	goto doreadlist;
+}
+
+
+/* Write a data block into the right service channel of the device */
+ssize_t auerchar_write(struct file *file, const char *buf, size_t len,
+		       loff_t * ppos)
+{
+	struct auerchar *ccp = (struct auerchar *) file->private_data;
+	struct auerswald *cp = NULL;
+	struct auerbuf *bp;
+	int ret;
+	wait_queue_t wait;
+
+	dbg("auerchar_write %d bytes", len);
+
+	/* Error checking */
+	if (!ccp)
+		return -EIO;
+	if (*ppos)
+		return -ESPIPE;
+	if (len == 0)
+		return 0;
+
+      write_again:
+	/* get the mutex */
+	if (down_interruptible(&ccp->mutex))
+		return -ERESTARTSYS;
+
+	/* Can we expect to write something? */
+	if (ccp->scontext.id == AUH_UNASSIGNED) {
+		up(&ccp->mutex);
+		return -EIO;
+	}
+
+	cp = ccp->auerdev;
+	if (!cp) {
+		up(&ccp->mutex);
+		return -ERESTARTSYS;
+	}
+	if (down_interruptible(&cp->mutex)) {
+		up(&ccp->mutex);
+		return -ERESTARTSYS;
+	}
+	if (!cp->usbdev) {
+		up(&cp->mutex);
+		up(&ccp->mutex);
+		return -EIO;
+	}
+	/* Prepare for sleep */
+	init_waitqueue_entry(&wait, current);
+	set_current_state(TASK_INTERRUPTIBLE);
+	add_wait_queue(&cp->bufferwait, &wait);
+
+	/* Try to get a buffer from the device pool.
+	   We can't use a buffer from ccp->bufctl because the write
+	   command will last beond a release() */
+	bp = auerbuf_getbuf(&cp->bufctl);
+	/* are there any buffers left? */
+	if (!bp) {
+		up(&cp->mutex);
+		up(&ccp->mutex);
+
+		/* NONBLOCK: don't wait */
+		if (file->f_flags & O_NONBLOCK) {
+			set_current_state(TASK_RUNNING);
+			remove_wait_queue(&cp->bufferwait, &wait);
+			return -EAGAIN;
+		}
+
+		/* BLOCKING: wait */
+		schedule();
+		remove_wait_queue(&cp->bufferwait, &wait);
+		if (signal_pending(current)) {
+			/* waked up by a signal */
+			return -ERESTARTSYS;
+		}
+		goto write_again;
+	} else {
+		set_current_state(TASK_RUNNING);
+		remove_wait_queue(&cp->bufferwait, &wait);
+	}
+
+	/* protect against too big write requests */
+	if (len > cp->maxControlLength)
+		len = cp->maxControlLength;
+
+	/* Fill the buffer */
+	if (copy_from_user(bp->bufp + AUH_SIZE, buf, len)) {
+		dbg("copy_from_user failed");
+		auerbuf_releasebuf(bp);
+		/* Wake up all processes waiting for a buffer */
+		wake_up(&cp->bufferwait);
+		up(&cp->mutex);
+		up(&ccp->mutex);
+		return -EIO;
+	}
+
+	/* set the header byte */
+	*(bp->bufp) = ccp->scontext.id | AUH_DIRECT | AUH_UNSPLIT;
+
+	/* Set the transfer Parameters */
+	bp->len = len + AUH_SIZE;
+	bp->dr->bRequestType = AUT_WREQ;
+	bp->dr->bRequest = AUV_WBLOCK;
+	bp->dr->wValue = cpu_to_le16(0);
+	bp->dr->wIndex =
+	    cpu_to_le16(ccp->scontext.id | AUH_DIRECT | AUH_UNSPLIT);
+	bp->dr->wLength = cpu_to_le16(len + AUH_SIZE);
+	FILL_CONTROL_URB(bp->urbp, cp->usbdev,
+			 usb_sndctrlpipe(cp->usbdev, 0),
+			 (unsigned char *) bp->dr, bp->bufp,
+			 len + AUH_SIZE, auerchar_ctrlwrite_complete, bp);
+	/* up we go */
+	ret = auerchain_submit_urb(&cp->controlchain, bp->urbp);
+	up(&cp->mutex);
+	if (ret) {
+		dbg("auerchar_write: nonzero result of auerchain_submit_urb %d", ret);
+		auerbuf_releasebuf(bp);
+		/* Wake up all processes waiting for a buffer */
+		wake_up(&cp->bufferwait);
+		up(&ccp->mutex);
+		return -EIO;
+	} else {
+		dbg("auerchar_write: Write OK");
+		up(&ccp->mutex);
+		return len;
+	}
+}
+
+
+/* Close a character device */
+int auerchar_release(struct inode *inode, struct file *file)
+{
+	struct auerchar *ccp = (struct auerchar *) file->private_data;
+	struct auerswald *cp;
+	dbg("release");
+
+	/* get the mutexes */
+	if (down_interruptible(&ccp->mutex)) {
+		return -ERESTARTSYS;
+	}
+	cp = ccp->auerdev;
+	if (cp) {
+		if (down_interruptible(&cp->mutex)) {
+			up(&ccp->mutex);
+			return -ERESTARTSYS;
+		}
+		/* remove an open service */
+		auerswald_removeservice(cp, &ccp->scontext);
+		/* detach from device */
+		if ((--cp->open_count <= 0) && (cp->usbdev == NULL)) {
+			/* usb device waits for removal */
+			up(&cp->mutex);
+			auerswald_delete(cp);
+		} else {
+			up(&cp->mutex);
+		}
+		cp = NULL;
+		ccp->auerdev = NULL;
+	}
+	up(&ccp->mutex);
+	auerchar_delete(ccp);
+
+	return 0;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/auerchar.h linux-2.4.21-pre6/drivers/usb/auerchar.h
--- linux-2.4.20/drivers/usb/auerchar.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/auerchar.h	2003-03-26 23:49:07.000000000 +0000
@@ -0,0 +1,79 @@
+/*****************************************************************************/
+/*
+ *      auerchar.h  --  Auerswald PBX/System Telephone character interface.
+ *
+ *      Copyright (C) 2002  Wolfgang Mües (wolfgang@iksw-muees.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 AUERCHAR_H
+#define AUERCHAR_H
+
+#include "auerchain.h"
+#include "auerbuf.h"
+#include "auerserv.h"
+
+/* External data structures / Interface                              */
+struct audevinfo {
+	char *buf;		/* return buffer for string contents */
+	unsigned int bsize;	/* size of return buffer */
+};
+
+/* IO controls */
+#define IOCTL_AU_SLEN	  _IOR( 'U', 0xF0, int)	/* return the max. string descriptor length */
+#define IOCTL_AU_DEVINFO  _IOWR('U', 0xF1, struct audevinfo)	/* get name of a specific device */
+#define IOCTL_AU_SERVREQ  _IOW( 'U', 0xF2, int)	/* request a service channel */
+#define IOCTL_AU_BUFLEN	  _IOR( 'U', 0xF3, int)	/* return the max. buffer length for the device */
+#define IOCTL_AU_RXAVAIL  _IOR( 'U', 0xF4, int)	/* return != 0 if Receive Data available */
+#define IOCTL_AU_CONNECT  _IOR( 'U', 0xF5, int)	/* return != 0 if connected to a service channel */
+#define IOCTL_AU_TXREADY  _IOR( 'U', 0xF6, int)	/* return != 0 if Transmitt channel ready to send */
+/*                              'U'  0xF7..0xFF reserved */
+
+/* character device context */
+struct auerswald;
+struct auerchar {
+	struct semaphore mutex;		/* protection in user context */
+	struct auerswald *auerdev;	/* context pointer of assigned device */
+	struct auerbufctl bufctl;	/* controls the buffer chain */
+	struct auerscon scontext;	/* service context */
+	wait_queue_head_t readwait;	/* for synchronous reading */
+	struct semaphore readmutex;	/* protection against multiple reads */
+	struct auerbuf *readbuf;	/* buffer held for partial reading */
+	unsigned int readoffset;	/* current offset in readbuf */
+	unsigned int removed;		/* is != 0 if device is removed */
+};
+
+/* Function prototypes */
+void auerchar_delete(struct auerchar *ccp);
+
+int auerchar_open(struct inode *inode, struct file *file);
+
+int auerchar_ioctl(struct inode *inode, struct file *file,
+		   unsigned int cmd, unsigned long arg);
+
+loff_t auerchar_llseek(struct file *file, loff_t offset, int origin);
+
+ssize_t auerchar_read(struct file *file, char *buf, size_t count,
+		      loff_t * ppos);
+
+ssize_t auerchar_write(struct file *file, const char *buf, size_t len,
+		       loff_t * ppos);
+
+int auerchar_release(struct inode *inode, struct file *file);
+
+
+#endif	/* AUERCHAR_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/auerisdn.c linux-2.4.21-pre6/drivers/usb/auerisdn.c
--- linux-2.4.20/drivers/usb/auerisdn.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/auerisdn.c	2003-03-26 23:49:00.000000000 +0000
@@ -0,0 +1,1076 @@
+/*****************************************************************************/
+/*
+ *      auerisdn.c  --  Auerswald PBX/System Telephone ISDN interface.
+ *
+ *      Copyright (C) 2002  Wolfgang Mües (wolfgang@iksw-muees.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/isdnif.h>
+#include <linux/netdevice.h>
+#include <linux/sched.h>
+
+#undef	DEBUG			/* include debug macros until it's done */
+#include <linux/usb.h>
+
+#include "auerisdn.h"
+#include "auermain.h"
+
+/*-------------------------------------------------------------------*/
+/* ISDN support defines                                              */
+#define AUISDN_TEI	64	/* use a constant TEI */
+
+/*-------------------------------------------------------------------*/
+/* Debug support 						     */
+#ifdef DEBUG
+#define dump( desc, adr, len) \
+do {			\
+	unsigned int u;	\
+	printk (KERN_DEBUG); \
+	printk (desc); \
+	for (u = 0; u < len; u++) \
+		printk (" %02X", adr[u] & 0xFF); \
+	printk ("\n"); \
+} while (0)
+#else
+#define dump( desc, adr, len)
+#endif
+
+/*-------------------------------------------------------------------*/
+/* Hisax Interface.     					     */
+
+/* The interface to hisax is long-lasting because hisax_unregister()
+   don't work well in Linux 2.4.x. So we have to hold each registered
+   hisax interface until driver removal. */
+static struct auerhisax auerhisax_table[AUER_MAX_DEVICES];
+
+
+/*-------------------------------------------------------------------*/
+
+/* Callback to L2 for HISAX */
+/* This callback can be called from 3 sources:
+   a) from hisax context (answer from a l2l1 function)
+   b) from interrupt context (a D channel paket arrived)
+   c) from kernel daemon context (probe/disconnecting)
+*/
+static void auerisdn_d_l1l2(struct auerisdn *ip, int pr, void *arg)
+{
+	struct sk_buff *skb;
+	struct auerhisax *ahp;
+
+	/* do the callback */
+	ahp = ip->ahp;
+	if (ahp) {
+		ahp->hisax_d_if.ifc.l1l2(&ahp->hisax_d_if.ifc, pr, arg);
+	} else {
+		dbg("auerisdn_d_l1l2 with ahp == NULL");
+		if (pr == (PH_DATA | INDICATION)) {
+			skb = (struct sk_buff *) arg;
+			if (skb) {
+				skb_pull(skb, skb->len);
+				dev_kfree_skb_any(skb);
+			}
+		}
+	}
+}
+
+
+/* D-Channel sending completion function */
+static void auerisdn_dcw_complete(struct urb *urb)
+{
+	struct auerbuf *bp = (struct auerbuf *) urb->context;
+	struct auerswald *cp =
+	    ((struct auerswald *) ((char *) (bp->list) -
+				   (unsigned
+				    long) (&((struct auerswald *) 0)->
+					   bufctl)));
+
+	dbg("auerisdn_dcw_complete with status %d", urb->status);
+
+	/* reuse the buffer */
+	auerbuf_releasebuf(bp);
+
+	/* Wake up all processes waiting for a buffer */
+	wake_up(&cp->bufferwait);
+}
+
+
+/* Translate non-ETSI ISDN messages from the device */
+static void auerisdn_translate_incoming(struct auerswald *cp,
+					unsigned char *msg,
+					unsigned int len)
+{
+	struct auerbuf *bp;
+	int ret;
+
+	/* Translate incomming CONNECT -> CONNECT_ACK */
+	/* Format:   0   1    2     3     4        5        6    7      */
+	/*         SAPI TEI TXSEQ RXSEQ PID=08 CREFLEN=01 CREF MSG=7 ...*/
+	/* CREF.7 == 0 -> Incoming Call                                 */
+
+	/* Check for minimum length */
+	if (len < 8)
+		return;
+
+	/* Check for a CONNECT, call originated from device */
+	if (((msg[6] & 0x80) == 0) && (msg[7] == 0x07)) {
+		dbg("false CONNECT from device found");
+		/* change into CONNECT_ACK */
+		msg[7] = 0x0F;
+
+		/* Send a CONNECT_ACK back to the device */
+
+		/* get a new data buffer */
+		bp = auerbuf_getbuf(&cp->bufctl);
+		if (!bp) {
+			warn("no auerbuf free");
+			return;
+		}
+
+		/* Form a CONNECT ACK */
+		bp->bufp[0] =
+		    cp->isdn.dchannelservice.id | AUH_DIRECT | AUH_UNSPLIT;
+		bp->bufp[1] = 0x08;
+		bp->bufp[2] = 0x01;
+		bp->bufp[3] = msg[6] | 0x80;
+		bp->bufp[4] = 0x0F;
+
+		/* Set the transfer Parameters */
+		bp->len = 5;
+		bp->dr->bRequestType = AUT_WREQ;
+		bp->dr->bRequest = AUV_WBLOCK;
+		bp->dr->wValue = cpu_to_le16(0);
+		bp->dr->wIndex =
+		    cpu_to_le16(cp->isdn.dchannelservice.
+				id | AUH_DIRECT | AUH_UNSPLIT);
+		bp->dr->wLength = cpu_to_le16(5);
+		FILL_CONTROL_URB(bp->urbp, cp->usbdev,
+				 usb_sndctrlpipe(cp->usbdev, 0),
+				 (unsigned char *) bp->dr, bp->bufp, 5,
+				 auerisdn_dcw_complete, bp);
+		/* up we go */
+		ret = auerchain_submit_urb(&cp->controlchain, bp->urbp);
+		if (ret)
+			auerisdn_dcw_complete(bp->urbp);
+		else
+			dbg("auerisdn_translate: Write OK");
+	}
+	/* Check for a DISCONNECT and change to RELEASE */
+	if (msg[7] == 0x45) {
+		dbg("DISCONNECT changed to RELEASE");
+		msg[7] = 0x4D;
+		return;
+	}
+}
+
+
+/* a D-channel paket arrived from the device */
+static void auerisdn_dispatch_dc(struct auerscon *scp, struct auerbuf *bp)
+{
+	struct sk_buff *skb;
+	struct auerhisax *ahp;
+	struct auerswald *cp =
+	    ((struct auerswald *) ((char *) (scp) -
+				   (unsigned
+				    long) (&((struct auerswald *) 0)->isdn.
+					   dchannelservice)));
+	unsigned char *sp;
+	unsigned int l2_index;
+	unsigned char c;
+	unsigned char l2_header[10];
+	unsigned long flags;
+
+	dump("D-Channel paket arrived:", bp->bufp, bp->len);
+	if (cp->disconnecting)
+		return;
+
+	/* add a self-generated L2 message header */
+	l2_index = 0;
+	l2_header[l2_index++] = 0x02;	/* SAPI 0, C/R = 1 */
+
+	/* Parse the L3 message */
+	sp = bp->bufp + AUH_SIZE;
+
+	c = *sp++;		/* Protocol discriminator */
+	if (c != 0x08) {
+		warn("D channel paket is not ETSI");
+		return;
+	}
+	c = *sp++;		/* Call Reference length byte */
+	sp += c;		/* Skip Call Reference */
+
+	/* translate charge IEs */
+	/* Format of Auerswald Header:
+	   0x32 len=0x0B 0xFF 0xFF 0x73 len=0x07 0x27 */
+	/* Format of IE2_UNIT:
+	   0x49 len=0x04 uu1 uu2 uu3 uu4 */
+	/* Translate into: (?? Bytes)
+	   0x1C Facility
+	   0x?? restlen
+	   0x91 Sup. Services
+	   0xA1 Invoke
+	   0x?? restlen
+	   0x02 Invoke ID Tag
+	   0x02 Invoke ID len
+	   0x12 Invoke ID = 0x1234
+	   0x34
+	   0x02 OP Value Tag
+	   0x01 Length of OPvalue
+	   0x24 OpValue = AOCE
+	   0x30 Universal Constructor Sequence
+	   0x?? restlen
+	   0x30 Universal Constructor Sequence
+	   0x?? restlen
+	   0xA1 Context Specific Constructor Recorded Units List
+	   0x?? restlen
+	   0x30 Universal Constructor Sequence
+	   0x?? restlen
+	   0x02 Universal Primitive Integer
+	   0x?? len from IE2_UNIT
+	   uu1  Recorded Units List
+	   uu2
+	   uu3
+	   uu4
+	 */
+	{
+		unsigned char *ucp = sp;	// pointer to start of msg
+		int l = bp->len;	// length until EOP
+		unsigned char alen;	// length of auerswald msg
+		l -= (int) (ucp - bp->bufp);
+		// scan for Auerswald Header
+		for (; l >= 9; l--, ucp++) {	// 9 = minimal length of auerswald msg
+			if (ucp[0] != 0x32)
+				continue;
+			if (ucp[2] != 0xFF)
+				continue;
+			if (ucp[3] != 0xFF)
+				continue;
+			if (ucp[4] != 0x73)
+				continue;
+			if (ucp[6] != 0x27)
+				continue;
+			// Auerswald Header found. Is it units?
+			dbg("Auerswald msg header found");
+			alen = ucp[1] + 2;
+			if (ucp[7] == 0x49) {
+				// yes
+				unsigned char ul = ucp[8] + 1;	// length of charge integer
+				unsigned char charge[32];
+				// Copy charge info into new buffer
+				unsigned char *xp = &ucp[8];
+				int count;
+				for (count = 0; count < ul; count++)
+					charge[count] = *xp++;
+				// Erase auerswald msg
+				count = l - alen;
+				xp = ucp;
+				for (; count; count--, xp++)
+					xp[0] = xp[alen];
+				l -= alen;
+				bp->len -= alen;
+				// make room for new message
+				count = l;
+				xp = &ucp[l - 1];
+				for (; count; count--, xp--);
+				xp[21 + ul] = xp[0];
+				l += (21 + ul);
+				bp->len += (21 + ul);
+				// insert IE header
+				ucp[0] = 0x1C;
+				ucp[1] = 19 + ul;
+				ucp[2] = 0x91;
+				ucp[3] = 0xA1;
+				ucp[4] = 16 + ul;
+				ucp[5] = 0x02;
+				ucp[6] = 0x02;
+				ucp[7] = 0x12;
+				ucp[8] = 0x34;
+				ucp[9] = 0x02;
+				ucp[10] = 0x01;
+				ucp[11] = 0x24;
+				ucp[12] = 0x30;
+				ucp[13] = 7 + ul;
+				ucp[14] = 0x30;
+				ucp[15] = 5 + ul;
+				ucp[16] = 0xA1;
+				ucp[17] = 3 + ul;
+				ucp[18] = 0x30;
+				ucp[19] = 1 + ul;
+				ucp[20] = 0x02;
+				// Insert charge units
+				xp = &ucp[21];
+				for (count = 0; count < ul; count++)
+					*xp++ = charge[count];
+				dump("Rearranged message:", bp->bufp,
+				     bp->len);
+				break;
+			} else {
+				// we can't handle something else, erase it
+				int count = l - alen;
+				unsigned char *xp = ucp;
+				for (; count; count--, xp++)
+					xp[0] = xp[alen];
+				l -= alen;
+				bp->len -= alen;
+				dump("Shortened message:", bp->bufp,
+				     bp->len);
+			}
+		}
+	}
+
+
+	c = *sp;		/* Message type */
+	if (c == 0x05) {
+		/* SETUP. Use an UI frame */
+		dbg("SETUP");
+		l2_header[l2_index++] = 0xFF;	/* TEI 127 */
+		l2_header[l2_index++] = 0x03;	/* UI control field */
+		skb = dev_alloc_skb(bp->len - AUH_SIZE + l2_index);
+	} else {
+		/* use an I frame */
+		dbg("I Frame");
+		l2_header[l2_index++] = (AUISDN_TEI << 1) | 0x01;	/* TEI byte */
+		skb = dev_alloc_skb(bp->len - AUH_SIZE + l2_index + 2);
+		if (skb) {
+			ahp = cp->isdn.ahp;
+			if (!ahp) {
+				err("ahp == NULL");
+				return;
+			}
+			spin_lock_irqsave(&ahp->seq_lock, flags);
+			l2_header[l2_index++] = ahp->txseq;	/* transmitt sequence number */
+			l2_header[l2_index++] = ahp->rxseq;	/* receive sequence number */
+			ahp->txseq += 2;			/* next paket gets next number */
+			spin_unlock_irqrestore(&ahp->seq_lock, flags);
+		}
+	}
+	if (!skb) {
+		err("no memory - skipped");
+		return;
+	}
+	sp = skb_put(skb, bp->len - AUH_SIZE + l2_index);
+	/* Add L2 header */
+	memcpy(sp, l2_header, l2_index);
+	memcpy(sp + l2_index, bp->bufp + AUH_SIZE, bp->len - AUH_SIZE);
+	/* Translate false messages */
+	auerisdn_translate_incoming(cp, sp, bp->len - AUH_SIZE + l2_index);
+	/* Send message to L2 */
+	auerisdn_d_l1l2(&cp->isdn, PH_DATA | INDICATION, skb);
+}
+
+/* D-channel is closed because the device is removed */
+/* This is a no-op because ISDN close is handled different */
+static void auerisdn_disconnect_dc(struct auerscon *scp)
+{
+}
+
+
+/* confirmation helper function. */
+static void auerisdn_d_confirmskb(struct auerswald *cp,
+				  struct sk_buff *skb)
+{
+	/* free the skb */
+	if (skb) {
+		skb_pull(skb, skb->len);
+		dev_kfree_skb_any(skb);
+	}
+
+	/* confirm the sending of data */
+	dbg("Confirm PH_DATA");
+	auerisdn_d_l1l2(&cp->isdn, PH_DATA | CONFIRM, NULL);
+}
+
+/* D-channel transfer function L2->L1 */
+static void auerisdn_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg)
+{
+	struct auerhisax *ahp;
+	struct sk_buff *skb;
+	unsigned int len;
+	int ret;
+	struct auerbuf *bp;
+	struct auerswald *cp;
+	unsigned long flags;
+	unsigned int l2_index;
+	unsigned char c;
+	unsigned char l2_header[32];
+	unsigned char *sp;
+
+	dbg("hisax D-Channel l2l1 called");
+
+	/* Get reference to auerhisax struct */
+	cp = NULL;
+	ahp = hisax_d_if->priv;
+	if (ahp)
+		cp = ahp->cp;
+	if (cp && !cp->disconnecting) {
+		/* normal usage */
+		switch (pr) {
+		case PH_ACTIVATE | REQUEST:	/* activation request */
+			dbg("Activation Request");
+			cp->isdn.dc_activated = 1;
+			/* send activation back to layer 2 */
+			auerisdn_d_l1l2(&cp->isdn,
+					PH_ACTIVATE | INDICATION, NULL);
+			break;
+		case PH_DEACTIVATE | REQUEST:	/* deactivation request */
+			dbg("Deactivation Request");
+			cp->isdn.dc_activated = 0;
+			/* send deactivation back to layer 2 */
+			auerisdn_d_l1l2(&cp->isdn,
+					PH_DEACTIVATE | INDICATION, NULL);
+			break;
+		case PH_DATA | REQUEST:	/* Transmit data request */
+			skb = (struct sk_buff *) arg;
+			len = skb->len;
+			l2_index = 0;
+			sp = skb->data;
+			dump("Data Request:", sp, len);
+
+			/* Parse the L2 header */
+			if (!len)
+				goto phd_free;
+			c = *sp++;	/* SAPI */
+			l2_header[l2_index++] = c;
+			len--;
+			if (!len)
+				goto phd_free;
+			c = *sp++;	/* TEI */
+			l2_header[l2_index++] = c;
+			len--;
+			if (!len)
+				goto phd_free;
+			c = *sp++;	/* Control Field, Byte 1 */
+			len--;
+			if (!(c & 0x01)) {
+				/* I FRAME */
+				dbg("I Frame");
+				if (!len)
+					goto phd_free;
+				spin_lock_irqsave(&ahp->seq_lock, flags);
+				ahp->rxseq = c + 2;	/* store new sequence info */
+				spin_unlock_irqrestore(&ahp->seq_lock,
+						       flags);
+				sp++;	/* skip Control Field, Byte 2 */
+				len--;
+				/* Check for RELEASE command */
+				/* and change to RELEASE_COMPLETE */
+				if (sp[3] == 0x4D)
+					sp[3] = 0x5A;
+				goto phd_send;
+			}
+			/* check the frame type */
+			switch (c) {
+			case 0x03:	/* UI frame */
+				dbg("UI Frame");
+				if (l2_header[0] == 0xFC) {
+					dbg("TEI Managment");
+					l2_header[0] = 0xFE;	/* set C/R bit in answer */
+					l2_header[l2_index++] = c;	/* Answer is UI frame */
+					if (!len)
+						break;
+					c = *sp++;	/* Managment ID */
+					len--;
+					if (c != 0x0F)
+						break;
+					l2_header[l2_index++] = c;
+					/* Read Reference Number */
+					if (!len)
+						break;
+					l2_header[l2_index++] = *sp++;
+					len--;
+					if (!len)
+						break;
+					l2_header[l2_index++] = *sp++;
+					len--;
+					if (!len)
+						break;
+					c = *sp++;	/* Message Type */
+					len--;
+					switch (c) {
+					case 0x01:	/* Identity Request */
+						dbg("Identity Request");
+						l2_header[l2_index++] = 0x02;	/* Identity Assign */
+						l2_header[l2_index++] =
+						    (AUISDN_TEI << 1) |
+						    0x01;
+						goto phd_answer;
+					default:
+						dbg("Unhandled TEI Managment %X", (int) c);
+						break;
+					}
+					// throw away
+					goto phd_free;
+				}
+				/* else send UI frame out */
+				goto phd_send;
+			case 0x01:	/* RR frame */
+			case 0x05:	/* RNR frame */
+				dbg("RR/RNR Frame");
+				if (!len)
+					break;
+				c = *sp++;	/* Control Field, Byte 2 */
+				len--;
+				if (!(c & 0x01))
+					break;	/* P/F = 1 in commands */
+				if (l2_header[0] & 0x02)
+					break;	/* C/R = 0 from TE */
+				dbg("Send RR as answer");
+				l2_header[l2_index++] = 0x01;	/* send an RR as Answer */
+				spin_lock_irqsave(&ahp->seq_lock, flags);
+				l2_header[l2_index++] = ahp->rxseq | 0x01;
+				spin_unlock_irqrestore(&ahp->seq_lock,
+						       flags);
+				goto phd_answer;
+			case 0x7F:	/* SABME */
+				dbg("SABME");
+				spin_lock_irqsave(&ahp->seq_lock, flags);
+				ahp->txseq = 0;
+				ahp->rxseq = 0;
+				spin_unlock_irqrestore(&ahp->seq_lock,
+						       flags);
+				l2_header[l2_index++] = 0x73;	/* UA */
+				goto phd_answer;
+			case 0x53:	/* DISC */
+				dbg("DISC");
+				/* Send back a UA */
+				l2_header[l2_index++] = 0x73;	/* UA */
+				goto phd_answer;
+			default:
+				dbg("Unhandled L2 Message %X", (int) c);
+				break;
+			}
+			/* all done */
+			goto phd_free;
+
+			/* we have to generate a local answer */
+			/* first, confirm old message, free old skb */
+		      phd_answer:auerisdn_d_confirmskb(cp,
+					      skb);
+
+			/* allocate a new skbuff */
+			skb = dev_alloc_skb(l2_index);
+			if (!skb) {
+				err("no memory for new skb");
+				break;
+			}
+			dump("local answer to L2 is:", l2_header,
+			     l2_index);
+			memcpy(skb_put(skb, l2_index), l2_header,
+			       l2_index);
+			auerisdn_d_l1l2(&cp->isdn, PH_DATA | INDICATION,
+					skb);
+			break;
+
+			/* we have to send the L3 message out */
+		      phd_send:if (!len)
+				goto phd_free;	/* no message left */
+
+			/* get a new data buffer */
+			bp = auerbuf_getbuf(&cp->bufctl);
+			if (!bp) {
+				warn("no auerbuf free");
+				goto phd_free;
+			}
+			/* protect against too big write requests */
+			/* Should not happen */
+			if (len > cp->maxControlLength) {
+				err("too long D-channel paket truncated");
+				len = cp->maxControlLength;
+			}
+
+			/* Copy the data */
+			memcpy(bp->bufp + AUH_SIZE, sp, len);
+
+			/* set the header byte */
+			*(bp->bufp) =
+			    cp->isdn.dchannelservice.
+			    id | AUH_DIRECT | AUH_UNSPLIT;
+
+			/* Set the transfer Parameters */
+			bp->len = len + AUH_SIZE;
+			bp->dr->bRequestType = AUT_WREQ;
+			bp->dr->bRequest = AUV_WBLOCK;
+			bp->dr->wValue = cpu_to_le16(0);
+			bp->dr->wIndex =
+			    cpu_to_le16(cp->isdn.dchannelservice.
+					id | AUH_DIRECT | AUH_UNSPLIT);
+			bp->dr->wLength = cpu_to_le16(len + AUH_SIZE);
+			FILL_CONTROL_URB(bp->urbp, cp->usbdev,
+					 usb_sndctrlpipe(cp->usbdev, 0),
+					 (unsigned char *) bp->dr,
+					 bp->bufp, len + AUH_SIZE,
+					 auerisdn_dcw_complete, bp);
+			/* up we go */
+			ret =
+			    auerchain_submit_urb(&cp->controlchain,
+						 bp->urbp);
+			if (ret)
+				auerisdn_dcw_complete(bp->urbp);
+			else
+				dbg("auerisdn_dwrite: Write OK");
+			/* confirm message, free skb */
+		      phd_free:auerisdn_d_confirmskb(cp,
+					      skb);
+			break;
+
+		default:
+			warn("pr %#x\n", pr);
+			break;
+		}
+	} else {
+		/* hisax interface is down */
+		switch (pr) {
+		case PH_ACTIVATE | REQUEST:	/* activation request */
+			dbg("D channel PH_ACTIVATE | REQUEST with interface down");
+			/* don't answer this request! Endless... */
+			break;
+		case PH_DEACTIVATE | REQUEST:	/* deactivation request */
+			dbg("D channel PH_DEACTIVATE | REQUEST with interface down");
+			hisax_d_if->l1l2(hisax_d_if,
+					 PH_DEACTIVATE | INDICATION, NULL);
+			break;
+		case PH_DATA | REQUEST:	/* Transmit data request */
+			dbg("D channel PH_DATA | REQUEST with interface down");
+			skb = (struct sk_buff *) arg;
+			/* free data buffer */
+			if (skb) {
+				skb_pull(skb, skb->len);
+				dev_kfree_skb_any(skb);
+			}
+			/* send confirmation back to layer 2 */
+			hisax_d_if->l1l2(hisax_d_if, PH_DATA | CONFIRM,
+					 NULL);
+			break;
+		default:
+			warn("pr %#x\n", pr);
+			break;
+		}
+	}
+}
+
+
+/* Completion function for D channel open */
+static void auerisdn_dcopen_complete(struct urb *urbp)
+{
+	struct auerbuf *bp = (struct auerbuf *) urbp->context;
+	struct auerswald *cp =
+	    ((struct auerswald *) ((char *) (bp->list) -
+				   (unsigned
+				    long) (&((struct auerswald *) 0)->
+					   bufctl)));
+	dbg("auerisdn_dcopen_complete called");
+
+	auerbuf_releasebuf(bp);
+
+	/* Wake up all processes waiting for a buffer */
+	wake_up(&cp->bufferwait);
+}
+
+
+/* Open the D-channel once more */
+static void auerisdn_dcopen(unsigned long data)
+{
+	struct auerswald *cp = (struct auerswald *) data;
+	struct auerbuf *bp;
+	int ret;
+
+	if (cp->disconnecting)
+		return;
+	dbg("auerisdn_dcopen running");
+
+	/* get a buffer for the command */
+	bp = auerbuf_getbuf(&cp->bufctl);
+	/* if no buffer available: can't change the mode */
+	if (!bp) {
+		err("auerisdn_dcopen: no data buffer available");
+		return;
+	}
+
+	/* fill the control message */
+	bp->dr->bRequestType = AUT_WREQ;
+	bp->dr->bRequest = AUV_CHANNELCTL;
+	bp->dr->wValue = cpu_to_le16(1);
+	bp->dr->wIndex = cpu_to_le16(0);
+	bp->dr->wLength = cpu_to_le16(0);
+	FILL_CONTROL_URB(bp->urbp, cp->usbdev,
+			 usb_sndctrlpipe(cp->usbdev, 0),
+			 (unsigned char *) bp->dr, bp->bufp, 0,
+			 (usb_complete_t) auerisdn_dcopen_complete, bp);
+
+	/* submit the control msg */
+	ret = auerchain_submit_urb(&cp->controlchain, bp->urbp);
+	dbg("dcopen submitted");
+	if (ret) {
+		bp->urbp->status = ret;
+		auerisdn_dcopen_complete(bp->urbp);
+	}
+	return;
+}
+
+
+/* Initialize the isdn related items in struct auerswald */
+void auerisdn_init_dev(struct auerswald *cp)
+{
+	unsigned int u;
+	cp->isdn.dchannelservice.id = AUH_UNASSIGNED;
+	cp->isdn.dchannelservice.dispatch = auerisdn_dispatch_dc;
+	cp->isdn.dchannelservice.disconnect = auerisdn_disconnect_dc;
+	init_timer(&cp->isdn.dcopen_timer);
+	cp->isdn.dcopen_timer.data = (unsigned long) cp;
+	cp->isdn.dcopen_timer.function = auerisdn_dcopen;
+	for (u = 0; u < AUISDN_BCHANNELS; u++) {
+		cp->isdn.bc[u].cp = cp;
+		cp->isdn.bc[u].mode = L1_MODE_NULL;
+		cp->isdn.bc[u].channel = u;
+		spin_lock_init(&cp->isdn.bc[u].txskb_lock);
+	}
+}
+
+
+/* Connect to the HISAX interface. Returns 0 if successfull */
+int auerisdn_probe(struct auerswald *cp)
+{
+	struct hisax_b_if *b_if[AUISDN_BCHANNELS];
+	struct usb_endpoint_descriptor *ep;
+	struct auerhisax *ahp;
+	DECLARE_WAIT_QUEUE_HEAD(wqh);
+	unsigned int u;
+	unsigned char *ucp;
+	unsigned int first_time;
+	int ret;
+
+	/* First allocate resources, then register hisax interface */
+
+	/* Allocate RX buffers */
+	for (u = 0; u < AUISDN_BCHANNELS; u++) {
+		if (!cp->isdn.bc[u].rxbuf) {
+			cp->isdn.bc[u].rxbuf =
+			    (char *) kmalloc(AUISDN_RXSIZE, GFP_KERNEL);
+			if (!cp->isdn.bc[u].rxbuf) {
+				err("can't allocate buffer for B channel RX data");
+				return -1;
+			}
+		}
+	}
+
+	/* Read out B-Channel output fifo size */
+	ucp = kmalloc(32, GFP_KERNEL);
+	if (!ucp) {
+		err("Out of memory");
+		return -3;
+	}
+	ret = usb_control_msg(cp->usbdev,			/* pointer to device */
+			      usb_rcvctrlpipe(cp->usbdev, 0),	/* pipe to control endpoint */
+			      AUV_GETINFO,			/* USB message request value */
+			      AUT_RREQ,				/* USB message request type value */
+			      0,				/* USB message value */
+			      AUDI_OUTFSIZE,			/* USB message index value */
+			      ucp,				/* pointer to the receive buffer */
+			      32,				/* length of the buffer */
+			      HZ * 2);				/* time to wait for the message to complete before timing out */
+	if (ret < 4) {
+		kfree(ucp);
+		err("can't read TX Fifo sizes for B1,B2");
+		return -4;
+	}
+	for (u = 0; u < AUISDN_BCHANNELS; u++) {
+		ret = le16_to_cpup(ucp + u * 2);
+		cp->isdn.bc[u].ofsize = ret;
+		cp->isdn.bc[u].txfree = ret;
+	}
+	kfree(ucp);
+	for (u = 0; u < AUISDN_BCHANNELS; u++) {
+		dbg("B%d buffer size is %d", u, cp->isdn.bc[u].ofsize);
+	}
+
+	/* get the B channel output INT size */
+	cp->isdn.intbo_endp = AU_IRQENDPBO;
+	ep = usb_epnum_to_ep_desc(cp->usbdev, USB_DIR_OUT | AU_IRQENDPBO);
+	if (!ep) {
+		/* Some devices have another endpoint number here ... */
+		cp->isdn.intbo_endp = AU_IRQENDPBO_2;
+		ep = usb_epnum_to_ep_desc(cp->usbdev,
+					  USB_DIR_OUT | AU_IRQENDPBO_2);
+		if (!ep) {
+			err("can't get B channel OUT endpoint");
+			return -5;
+		}
+	}
+	cp->isdn.outsize = ep->wMaxPacketSize;
+	cp->isdn.outInterval = ep->bInterval;
+	cp->isdn.usbdev = cp->usbdev;
+
+	/* allocate the urb and data buffer */
+	if (!cp->isdn.intbo_urbp) {
+		cp->isdn.intbo_urbp = usb_alloc_urb(0);
+		if (!cp->isdn.intbo_urbp) {
+			err("can't allocate urb for B channel output endpoint");
+			return -6;
+		}
+	}
+	if (!cp->isdn.intbo_bufp) {
+		cp->isdn.intbo_bufp =
+		    (char *) kmalloc(cp->isdn.outsize, GFP_KERNEL);
+		if (!cp->isdn.intbo_bufp) {
+			err("can't allocate buffer for B channel output endpoint");
+			return -7;
+		}
+	}
+
+	/* get the B channel input INT size */
+	ep = usb_epnum_to_ep_desc(cp->usbdev, USB_DIR_IN | AU_IRQENDPBI);
+	if (!ep) {
+		err("can't get B channel IN endpoint");
+		return -8;
+	}
+	cp->isdn.insize = ep->wMaxPacketSize;
+
+	/* allocate the urb and data buffer */
+	if (!cp->isdn.intbi_urbp) {
+		cp->isdn.intbi_urbp = usb_alloc_urb(0);
+		if (!cp->isdn.intbi_urbp) {
+			err("can't allocate urb for B channel input endpoint");
+			return -9;
+		}
+	}
+	if (!cp->isdn.intbi_bufp) {
+		cp->isdn.intbi_bufp =
+		    (char *) kmalloc(cp->isdn.insize, GFP_KERNEL);
+		if (!cp->isdn.intbi_bufp) {
+			err("can't allocate buffer for B channel input endpoint");
+			return -10;
+		}
+	}
+
+	/* setup urb */
+	FILL_INT_URB(cp->isdn.intbi_urbp, cp->usbdev,
+		     usb_rcvintpipe(cp->usbdev, AU_IRQENDPBI),
+		     cp->isdn.intbi_bufp, cp->isdn.insize,
+		     auerisdn_intbi_complete, cp, ep->bInterval);
+	/* start the urb */
+	cp->isdn.intbi_urbp->status = 0;	/* needed! */
+	ret = usb_submit_urb(cp->isdn.intbi_urbp);
+	if (ret < 0) {
+		err("activation of B channel input int failed %d", ret);
+		usb_free_urb(cp->isdn.intbi_urbp);
+		cp->isdn.intbi_urbp = NULL;
+		return -11;
+	}
+
+	/* request the D-channel service now */
+	dbg("Requesting D channel now");
+	cp->isdn.dchannelservice.id = AUH_DCHANNEL;
+	if (auerswald_addservice(cp, &cp->isdn.dchannelservice)) {
+		err("can not open D-channel");
+		cp->isdn.dchannelservice.id = AUH_UNASSIGNED;
+		return -2;
+	}
+
+	/* Find a free hisax interface */
+	for (u = 0; u < AUER_MAX_DEVICES; u++) {
+		ahp = &auerhisax_table[u];
+		if (!ahp->cp) {
+			first_time = (u == 0);
+			goto ahp_found;
+		}
+	}
+	/* no free interface found */
+	return -12;
+
+	/* we found a free hisax interface */
+      ahp_found:
+	/* Wait until ipppd timeout expired. The reason behind this ugly construct:
+	   If we connect to a hisax device without waiting for ipppd we are not able
+	   to make a new IP connection. */
+	if (ahp->last_close) {
+		unsigned long timeout = jiffies - ahp->last_close;
+		if (timeout < AUISDN_IPTIMEOUT) {
+			info("waiting for ipppd to timeout");
+			sleep_on_timeout(&wqh, AUISDN_IPTIMEOUT - timeout);
+		}
+	}
+
+	cp->isdn.ahp = ahp;
+	u = ahp->hisax_registered;
+	ahp->hisax_registered = 1;
+	ahp->cp = cp;
+
+	/* now do the registration */
+	if (!u) {
+		for (u = 0; u < AUISDN_BCHANNELS; u++) {
+			b_if[u] = &ahp->hisax_b_if[u];
+		}
+		if (hisax_register
+		    (&ahp->hisax_d_if, b_if, "auerswald_usb",
+		     ISDN_PTYPE_EURO)) {
+			err("hisax registration failed");
+			ahp->cp = NULL;
+			cp->isdn.ahp = NULL;
+			ahp->hisax_registered = 0;
+			return -13;
+		}
+		dbg("hisax interface registered");
+	}
+
+	/* send a D channel L1 activation indication to hisax */
+	auerisdn_d_l1l2(&cp->isdn, PH_ACTIVATE | INDICATION, NULL);
+	cp->isdn.dc_activated = 1;
+
+	/* do another D channel activation for problematic devices */
+	cp->isdn.dcopen_timer.expires = jiffies + HZ;
+	dbg("add timer");
+	add_timer(&cp->isdn.dcopen_timer);
+
+	return 0;
+}
+
+/* The USB device was disconnected */
+void auerisdn_disconnect(struct auerswald *cp)
+{
+	struct auerhisax *ahp;
+	DECLARE_WAIT_QUEUE_HEAD(wqh);
+	unsigned long flags;
+	unsigned int u;
+	int ret;
+	unsigned int stop_bc;
+
+	dbg("auerisdn_disconnect called");
+
+	/* stop a running timer */
+	del_timer_sync(&cp->isdn.dcopen_timer);
+
+	/* first, stop the B channels */
+	stop_bc = auerisdn_b_disconnect(cp);
+
+	/* stop the D channels */
+	auerisdn_d_l1l2(&cp->isdn, PH_DEACTIVATE | INDICATION, NULL);
+	cp->isdn.dc_activated = 0;
+	dbg("D-Channel disconnected");
+
+	/* Wait a moment */
+	sleep_on_timeout(&wqh, HZ / 10);
+
+	/* Shut the connection to the hisax interface */
+	ahp = cp->isdn.ahp;
+	if (ahp) {
+		dbg("closing connection to hisax interface");
+		ahp->cp = NULL;
+		cp->isdn.ahp = NULL;
+		/* time of last closure */
+		if (stop_bc)
+			/* if we kill a running connection ... */
+			ahp->last_close = jiffies;
+		else
+			ahp->last_close = 0;
+	}
+
+	/* Now free the memory */
+	if (cp->isdn.intbi_urbp) {
+		ret = usb_unlink_urb(cp->isdn.intbi_urbp);
+		if (ret)
+			dbg("B in: nonzero int unlink result received: %d",
+			    ret);
+		usb_free_urb(cp->isdn.intbi_urbp);
+		cp->isdn.intbi_urbp = NULL;
+	}
+	kfree(cp->isdn.intbi_bufp);
+	cp->isdn.intbi_bufp = NULL;
+	
+	if (cp->isdn.intbo_urbp) {
+		cp->isdn.intbo_urbp->transfer_flags &= ~USB_ASYNC_UNLINK;
+		ret = usb_unlink_urb(cp->isdn.intbo_urbp);
+		if (ret)
+			dbg("B out: nonzero int unlink result received: %d", ret);
+		usb_free_urb(cp->isdn.intbo_urbp);
+		cp->isdn.intbo_urbp = NULL;
+	}
+	kfree(cp->isdn.intbo_bufp);
+	cp->isdn.intbo_bufp = NULL;
+
+	/* Remove the rx and tx buffers */
+	for (u = 0; u < AUISDN_BCHANNELS; u++) {
+		kfree(cp->isdn.bc[u].rxbuf);
+		cp->isdn.bc[u].rxbuf = NULL;
+		spin_lock_irqsave(&cp->isdn.bc[u].txskb_lock, flags);
+		if (cp->isdn.bc[u].txskb) {
+			skb_pull(cp->isdn.bc[u].txskb,
+				 cp->isdn.bc[u].txskb->len);
+			dev_kfree_skb_any(cp->isdn.bc[u].txskb);
+			cp->isdn.bc[u].txskb = NULL;
+		}
+		spin_unlock_irqrestore(&cp->isdn.bc[u].txskb_lock, flags);
+	}
+
+	/* Remove the D-channel connection */
+	auerswald_removeservice(cp, &cp->isdn.dchannelservice);
+}
+
+
+/*-------------------------------------------------------------------*/
+/* Environment for long-lasting hisax interface                      */
+
+/* Wrapper for hisax B0 channel L2L1 */
+static void auerisdn_b0_l2l1_wrapper(struct hisax_if *ifc, int pr,
+				     void *arg)
+{
+	auerisdn_b_l2l1(ifc, pr, arg, 0);
+}
+
+/* Wrapper for hisax B1 channel L2L1 */
+static void auerisdn_b1_l2l1_wrapper(struct hisax_if *ifc, int pr,
+				     void *arg)
+{
+	auerisdn_b_l2l1(ifc, pr, arg, 1);
+}
+
+/* Init the global variables */
+void auerisdn_init(void)
+{
+	struct auerhisax *ahp;
+	unsigned int u;
+
+	memset(&auerhisax_table, 0, sizeof(auerhisax_table));
+	for (u = 0; u < AUER_MAX_DEVICES; u++) {
+		ahp = &auerhisax_table[u];
+		spin_lock_init(&ahp->seq_lock);
+		ahp->hisax_d_if.ifc.priv = ahp;
+		ahp->hisax_d_if.ifc.l2l1 = auerisdn_d_l2l1;
+		ahp->hisax_b_if[0].ifc.priv = ahp;
+		ahp->hisax_b_if[0].ifc.l2l1 = auerisdn_b0_l2l1_wrapper;
+		ahp->hisax_b_if[1].ifc.priv = ahp;
+		ahp->hisax_b_if[1].ifc.l2l1 = auerisdn_b1_l2l1_wrapper;
+	}
+}
+
+/* Deinit the global variables */
+void auerisdn_cleanup(void)
+{
+	struct auerhisax *ahp;
+	int i;
+
+	/* cleanup last allocated device first */
+	for (i = AUER_MAX_DEVICES - 1; i >= 0; i--) {
+		ahp = &auerhisax_table[i];
+		if (ahp->cp) {
+			err("hisax device %d open at cleanup", i);
+		}
+		if (ahp->hisax_registered) {
+			hisax_unregister(&ahp->hisax_d_if);
+			dbg("hisax interface %d freed", i);
+		}
+	}
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/auerisdn.h linux-2.4.21-pre6/drivers/usb/auerisdn.h
--- linux-2.4.20/drivers/usb/auerisdn.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/auerisdn.h	2003-03-26 23:49:20.000000000 +0000
@@ -0,0 +1,94 @@
+/*****************************************************************************/
+/*
+ *      auerisdn.h  --  Auerswald PBX/System Telephone ISDN interface.
+ *
+ *      Copyright (C) 2002  Wolfgang Mües (wolfgang@iksw-muees.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 AUERISDN_H
+#define AUERISDN_H
+
+#if (CONFIG_USB_AUERISDN || CONFIG_USB_AUERISDN_MODULE)
+
+#include <linux/timer.h>
+#include "auerserv.h"
+#include "auerisdn_b.h"
+
+#define AUISDN_IPTIMEOUT (HZ * 60)	/* IP Timeout is 40s */
+
+struct auerswald;
+struct auerhisax;
+
+struct auerisdn {
+	struct auerscon dchannelservice;	/* serving the D channel */
+	struct auerhisax *ahp;			/* Reference to hisax interface */
+	unsigned int dc_activated;		/* 1 if D-Channel is activated */
+	struct auerisdnbc bc[AUISDN_BCHANNELS];	/* B channel data */
+	unsigned int insize;			/* Max. Block Size of Input INT */
+	unsigned int outsize;			/* Max. Block Size of Output INT */
+	unsigned int outInterval;		/* nr. of ms between INT OUT transfers */
+	struct urb *intbi_urbp;			/* B channel Input Interrupt urb */
+	unsigned char *intbi_bufp;		/* B channel Input data buffer */
+	unsigned int paketsize;			/* Data size of the INT OUT pakets */
+	struct usb_device *usbdev;		/* USB device handle */
+	unsigned int intbo_state;		/* Status of INT OUT urb */
+	struct urb *intbo_urbp;			/* B channel Output Interrupt urb */
+	unsigned char *intbo_bufp;		/* B channel Output data buffer */
+	unsigned int intbo_index;		/* Index of last served B channel */
+	unsigned int intbo_toggletimer;		/* data toggle timer for 2 b channels */
+	unsigned int intbo_endp;		/* grrr.. different on some devices */
+	struct timer_list dcopen_timer;		/* Open D-channel once more later... */
+};
+
+struct auerhisax {
+	struct hisax_d_if hisax_d_if;		/* Hisax D-Channel interface */
+	struct hisax_b_if hisax_b_if[AUISDN_BCHANNELS];	/* Hisax B-channel interfaces */
+	struct auerswald *cp;			/* Context to usb device */
+	unsigned int hisax_registered;		/* 1 if registered at hisax interface */
+	unsigned char txseq;			/* L2 emulation: tx sequence byte */
+	unsigned char rxseq;			/* L2 emulation: rx sequence byte */
+	spinlock_t seq_lock;			/* Lock sequence numbers */
+	unsigned long last_close;		/* Time of last close in jiffies */
+};
+
+/* Function Prototypes */
+void auerisdn_init_dev(struct auerswald *cp);
+
+int auerisdn_probe(struct auerswald *cp);
+
+void auerisdn_disconnect(struct auerswald *cp);
+
+void auerisdn_init(void);
+
+void auerisdn_cleanup(void);
+
+#else	/* no CONFIG_USB_AUERISDN */
+
+struct auerisdn {
+	int dummy;
+};
+
+/* Dummy ISDN functions */
+#define auerisdn_init_dev( cp)
+#define auerisdn_probe( cp) 0
+#define auerisdn_disconnect( cp)
+#define auerisdn_init()
+#define auerisdn_cleanup()
+#endif	/* CONFIG_USB_AUERISDN */
+
+#endif	/* AUERISDN_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/auerisdn_b.c linux-2.4.21-pre6/drivers/usb/auerisdn_b.c
--- linux-2.4.20/drivers/usb/auerisdn_b.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/auerisdn_b.c	2003-03-26 23:49:10.000000000 +0000
@@ -0,0 +1,689 @@
+/*****************************************************************************/
+/*
+ *      auerisdn_b.c  --  Auerswald PBX/System Telephone ISDN B-channel interface.
+ *
+ *      Copyright (C) 2002  Wolfgang Mües (wolfgang@iksw-muees.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/isdnif.h>	/* ISDN constants */
+#include <linux/netdevice.h>	/* skb functions */
+
+#undef DEBUG			/* include debug macros until it's done */
+#include <linux/usb.h>		/* standard usb header */
+
+#include "auerisdn.h"
+#include "auermain.h"
+
+/*-------------------------------------------------------------------*/
+/* ISDN B channel support defines                                    */
+#define AUISDN_BC_1MS		8	/* Bytes per channel and ms */
+#define AUISDN_BC_INC		4	/* change INT OUT size increment */
+#define AUISDN_BCDATATHRESHOLD	48	/* for unsymmetric 2-B-channels */
+#define AUISDN_TOGGLETIME	6	/* Timeout for unsymmetric serve */
+
+/*-------------------------------------------------------------------*/
+/* Debug support 						     */
+#ifdef DEBUG
+#define dump( desc, adr, len) \
+do {			\
+	unsigned int u;	\
+	printk (KERN_DEBUG); \
+	printk (desc); \
+	for (u = 0; u < len; u++) \
+		printk (" %02X", adr[u] & 0xFF); \
+	printk ("\n"); \
+} while (0)
+#else
+#define dump( desc, adr, len)
+#endif
+
+/*-------------------------------------------------------------------*/
+
+/* Callback to L2 for HISAX */
+/* This callback can be called from 3 sources:
+   a) from hisax context (answer from a l2l1 function)
+   b) from interrupt context (a B channel paket arrived, a B channel paket was sent)
+   c) from kernel daemon context (probe/disconnecting)
+*/
+void auerisdn_b_l1l2(struct auerisdnbc *bc, int pr, void *arg)
+{
+	struct auerhisax *ahp;
+	struct sk_buff *skb;
+
+	/* do the callback */
+	ahp = bc->cp->isdn.ahp;
+	if (ahp) {
+		ahp->hisax_b_if[bc->channel].ifc.l1l2(&ahp->
+						      hisax_b_if[bc->
+								 channel].
+						      ifc, pr, arg);
+	} else {
+		dbg("auerisdn_b_l1l2 called without ahp");
+		if (pr == (PH_DATA | INDICATION)) {
+			skb = (struct sk_buff *) arg;
+			if (skb) {
+				skb_pull(skb, skb->len);
+				dev_kfree_skb_any(skb);
+			}
+		}
+	}
+}
+
+/* fill the INT OUT data buffer with new data */
+/* Transfer buffer size to fill is in urbp->transfer_buffer_length */
+static void auerisdn_bintbo_newdata(struct auerisdn *ip)
+{
+	unsigned long flags;
+	struct urb *urbp = ip->intbo_urbp;
+	struct auerisdnbc *bc = &ip->bc[0];	/* start with B-channel 0 */
+	struct sk_buff *skb;
+	unsigned char *ucp;
+	int buf_size;
+	int len;
+	int bytes_sent;
+	int i;
+
+	/* FIXME: this algorithm is fixed to 2 B-channels */
+	/* Which B channel should we serve? */
+	if (ip->bc[1].mode != L1_MODE_NULL) {
+		/* B channel 1 is used */
+		if (bc->mode != L1_MODE_NULL) {
+			/* both B-channels are used */
+			if (ip->intbo_toggletimer) {
+				/* simply toggling */
+				ip->intbo_toggletimer--;
+				i = ip->intbo_index ^ 1;	/* serve both channels equal */
+			} else {
+				/* search the B channel with the most demand of data */
+				i = bc->txfree - ip->bc[1].txfree;
+				if (i < -AUISDN_BCDATATHRESHOLD)
+					i = 1;	/* B channel 1 needs more data */
+				else if (i > AUISDN_BCDATATHRESHOLD)
+					i = 0;	/* B channel 0 needs more data */
+				else
+					i = ip->intbo_index ^ 1;	/* serve both channels equal */
+				if (i == ip->intbo_index)
+					ip->intbo_toggletimer =
+					    AUISDN_TOGGLETIME;
+			}
+			bc = &ip->bc[i];
+			ip->intbo_index = i;
+		} else {
+			bc = &ip->bc[1];
+		}
+	}
+	dbg("INTBO: Fill B%d with %d Bytes, %d Bytes free",
+	    bc->channel + 1, urbp->transfer_buffer_length - AUH_SIZE,
+	    bc->txfree);
+
+	/* Fill the buffer with data */
+	ucp = ip->intbo_bufp;
+	*ucp++ = AUH_B1CHANNEL + bc->channel;	/* First byte is channel nr. */
+	buf_size = urbp->transfer_buffer_length - AUH_SIZE;
+	len = 0;
+	while (len < buf_size) {
+		spin_lock_irqsave(&bc->txskb_lock, flags);
+		if ((skb = bc->txskb)) {
+			/* dump ("raw tx data:", skb->data, skb->len); */
+			if (bc->mode == L1_MODE_TRANS) {
+				bytes_sent = buf_size - len;
+				if (skb->len < bytes_sent)
+					bytes_sent = skb->len;
+				{	/* swap tx bytes */
+					register unsigned char *src =
+					    skb->data;
+					unsigned int count;
+					for (count = 0; count < bytes_sent;
+					     count++)
+						*ucp++ =
+						    isdnhdlc_bit_rev_tab
+						    [*src++];
+				}
+				len += bytes_sent;
+				bc->lastbyte = skb->data[bytes_sent - 1];
+			} else {
+				int bs =
+				    isdnhdlc_encode(&bc->outp_hdlc_state,
+						    skb->data, skb->len,
+						    &bytes_sent,
+						    ucp, buf_size - len);
+				/* dump ("hdlc data:", ucp, bs); */
+				len += bs;
+				ucp += bs;
+			}
+			skb_pull(skb, bytes_sent);
+
+			if (!skb->len) {
+				// Frame sent
+				bc->txskb = NULL;
+				spin_unlock_irqrestore(&bc->txskb_lock,
+						       flags);
+				auerisdn_b_l1l2(bc, PH_DATA | CONFIRM,
+						(void *) skb->truesize);
+				dev_kfree_skb_any(skb);
+				continue;	//while
+			}
+		} else {
+			if (bc->mode == L1_MODE_TRANS) {
+				memset(ucp, bc->lastbyte, buf_size - len);
+				ucp += buf_size - len;
+				len = buf_size;
+				/* dbg ("fill = 0xFF"); */
+			} else {
+				// Send flags
+				int bs =
+				    isdnhdlc_encode(&bc->outp_hdlc_state,
+						    NULL, 0, &bytes_sent,
+						    ucp, buf_size - len);
+				/* dbg ("fill = 0x%02X", (int)*ucp); */
+				len += bs;
+				ucp += bs;
+			}
+		}
+		spin_unlock_irqrestore(&bc->txskb_lock, flags);
+	}
+	/* dbg ("%d Bytes to TX buffer", len); */
+}
+
+
+/* INT OUT completion handler */
+static void auerisdn_bintbo_complete(struct urb *urbp)
+{
+	struct auerisdn *ip = urbp->context;
+
+	/* unlink completion? */
+	if ((urbp->status == -ENOENT) || (urbp->status == -ECONNRESET)) {
+		/* should we restart with another size? */
+		if (ip->intbo_state == INTBOS_CHANGE) {
+			dbg("state => RESTART");
+			ip->intbo_state = INTBOS_RESTART;
+		} else {
+			/* set up variables for later restart */
+			dbg("INTBO stopped");
+			ip->intbo_state = INTBOS_IDLE;
+		}
+		/* nothing more to do */
+		return;
+	}
+
+	/* other state != 0? */
+	if (urbp->status) {
+		warn("auerisdn_bintbo_complete: status = %d",
+		     urbp->status);
+		return;
+	}
+
+	/* Should we fill in new data? */
+	if (ip->intbo_state == INTBOS_CHANGE) {
+		dbg("state == INTBOS_CHANGE, no new data");
+		return;
+	}
+
+	/* fill in new data */
+	auerisdn_bintbo_newdata(ip);
+}
+
+/* set up the INT OUT URB the first time */
+/* Don't start the URB */
+static void auerisdn_bintbo_setup(struct auerisdn *ip, unsigned int len)
+{
+	ip->intbo_state = INTBOS_IDLE;
+	FILL_INT_URB(ip->intbo_urbp, ip->usbdev,
+		     usb_sndintpipe(ip->usbdev, ip->intbo_endp),
+		     ip->intbo_bufp, len, auerisdn_bintbo_complete, ip,
+		     ip->outInterval);
+	ip->intbo_urbp->transfer_flags |= USB_ASYNC_UNLINK;
+	ip->intbo_urbp->status = 0;
+}
+
+/* restart the INT OUT endpoint */
+static void auerisdn_bintbo_restart(struct auerisdn *ip)
+{
+	struct urb *urbp = ip->intbo_urbp;
+	int status;
+
+	/* dbg ("auerisdn_intbo_restart"); */
+
+	/* fresh restart */
+	auerisdn_bintbo_setup(ip, ip->paketsize + AUH_SIZE);
+
+	/* Fill in new data */
+	auerisdn_bintbo_newdata(ip);
+
+	/* restart the urb */
+	ip->intbo_state = INTBOS_RUNNING;
+	status = usb_submit_urb(urbp);
+	if (status < 0) {
+		err("can't submit INT OUT urb, status = %d", status);
+		urbp->status = status;
+		urbp->complete(urbp);
+	}
+}
+
+/* change the size of the INT OUT endpoint */
+static void auerisdn_bchange(struct auerisdn *ip, unsigned int paketsize)
+{
+	/* changing... */
+	dbg("txfree[0] = %d, txfree[1] = %d, old size = %d, new size = %d",
+	    ip->bc[0].txfree, ip->bc[1].txfree, ip->paketsize, paketsize);
+	ip->paketsize = paketsize;
+
+	if (paketsize == 0) {
+		/* stop the INT OUT endpoint */
+		dbg("stop unlinking INT out urb");
+		ip->intbo_state = INTBOS_IDLE;
+		usb_unlink_urb(ip->intbo_urbp);
+		return;
+	}
+	if (ip->intbo_state != INTBOS_IDLE) {
+		/* dbg ("unlinking INT out urb"); */
+		ip->intbo_state = INTBOS_CHANGE;
+		usb_unlink_urb(ip->intbo_urbp);
+	} else {
+		/* dbg ("restart immediately"); */
+		auerisdn_bintbo_restart(ip);
+	}
+}
+
+/* serve the outgoing B channel interrupt */
+/* Called from the INT IN completion handler */
+static void auerisdn_bserv(struct auerisdn *ip)
+{
+	struct auerisdnbc *bc;
+	unsigned int u;
+	unsigned int paketsize;
+
+	/* should we start the INT OUT endpoint again? */
+	if (ip->intbo_state == INTBOS_RESTART) {
+		/* dbg ("Restart INT OUT from INT IN"); */
+		auerisdn_bintbo_restart(ip);
+		return;
+	}
+	/* no new calculation if change already in progress */
+	if (ip->intbo_state == INTBOS_CHANGE)
+		return;
+
+	/* calculation of transfer parameters for INT OUT endpoint */
+	paketsize = 0;
+	for (u = 0; u < AUISDN_BCHANNELS; u++) {
+		bc = &ip->bc[u];
+		if (bc->mode != L1_MODE_NULL) {	/* B channel is active */
+			unsigned int bpp = AUISDN_BC_1MS * ip->outInterval;
+			if (bc->txfree < bpp) {	/* buffer is full, throttle */
+				bc->txsize = bpp - AUISDN_BC_INC;
+				paketsize += bpp - AUISDN_BC_INC;
+			} else if (bc->txfree < bpp * 2) {
+				paketsize += bc->txsize;	/* schmidt-trigger, continue */
+			} else if (bc->txfree < bpp * 4) {	/* we are in synch */
+				bc->txsize = bpp;
+				paketsize += bpp;
+			} else if (bc->txfree > bc->ofsize / 2) {/* we have to fill the buffer */
+				bc->txsize = bpp + AUISDN_BC_INC;
+				paketsize += bpp + AUISDN_BC_INC;
+			} else {
+				paketsize += bc->txsize;	/* schmidt-trigger, continue */
+			}
+		}
+	}
+
+	/* check if we have to change the paket size */
+	if (paketsize != ip->paketsize)
+		auerisdn_bchange(ip, paketsize);
+}
+
+/* Send activation/deactivation state to L2 */
+static void auerisdn_bconf(struct auerisdnbc *bc)
+{
+	unsigned long flags;
+	struct sk_buff *skb;
+
+	if (bc->mode == L1_MODE_NULL) {
+		auerisdn_b_l1l2(bc, PH_DEACTIVATE | INDICATION, NULL);
+		/* recycle old txskb */
+		spin_lock_irqsave(&bc->txskb_lock, flags);
+		skb = bc->txskb;
+		bc->txskb = NULL;
+		spin_unlock_irqrestore(&bc->txskb_lock, flags);
+		if (skb) {
+			skb_pull(skb, skb->len);
+			auerisdn_b_l1l2(bc, PH_DATA | CONFIRM,
+					(void *) skb->truesize);
+			dev_kfree_skb_any(skb);
+		}
+	} else {
+		auerisdn_b_l1l2(bc, PH_ACTIVATE | INDICATION, NULL);
+	}
+}
+
+/* B channel setup completion handler */
+static void auerisdn_bmode_complete(struct urb *urb)
+{
+	struct auerswald *cp;
+	struct auerbuf *bp = (struct auerbuf *) urb->context;
+	struct auerisdnbc *bc;
+	int channel;
+
+	dbg("auerisdn_bmode_complete called");
+	cp = ((struct auerswald *) ((char *) (bp->list) -
+				    (unsigned
+				     long) (&((struct auerswald *) 0)->
+					    bufctl)));
+
+	/* select the B-channel */
+	channel = le16_to_cpu(bp->dr->wIndex);
+	channel -= AUH_B1CHANNEL;
+	if (channel < 0)
+		goto rel;
+	if (channel >= AUISDN_BCHANNELS)
+		goto rel;
+	bc = &cp->isdn.bc[channel];
+
+	/* Check for success */
+	if (urb->status) {
+		err("complete with non-zero status: %d", urb->status);
+	} else {
+		bc->mode = *bp->bufp;
+	}
+	/* Signal current mode to L2 */
+	auerisdn_bconf(bc);
+
+	/* reuse the buffer */
+      rel:auerbuf_releasebuf(bp);
+
+	/* Wake up all processes waiting for a buffer */
+	wake_up(&cp->bufferwait);
+}
+
+/* Setup a B channel transfer mode */
+static void auerisdn_bmode(struct auerisdnbc *bc, unsigned int mode)
+{
+	struct auerswald *cp = bc->cp;
+	struct auerbuf *bp;
+	int ret;
+
+	/* don't allow activation on disconnect */
+	if (cp->disconnecting) {
+		mode = L1_MODE_NULL;
+
+		/* Else check if something changed */
+	} else if (bc->mode != mode) {
+		if ((mode != L1_MODE_NULL) && (mode != L1_MODE_TRANS)) {
+			/* init RX hdlc decoder */
+			dbg("rcv init");
+			isdnhdlc_rcv_init(&bc->inp_hdlc_state, 0);
+			/* init TX hdlc decoder */
+			dbg("out init");
+			isdnhdlc_out_init(&bc->outp_hdlc_state, 0, 0);
+		}
+		/* stop ASAP */
+		if (mode == L1_MODE_NULL)
+			bc->mode = mode;
+		if ((bc->mode == L1_MODE_NULL) || (mode == L1_MODE_NULL)) {
+			/* Activation or deactivation required */
+
+			/* get a buffer for the command */
+			bp = auerbuf_getbuf(&cp->bufctl);
+			/* if no buffer available: can't change the mode */
+			if (!bp) {
+				err("auerisdn_bmode: no data buffer available");
+				return;
+			}
+
+			/* fill the control message */
+			bp->dr->bRequestType = AUT_WREQ;
+			bp->dr->bRequest = AUV_CHANNELCTL;
+			if (mode != L1_MODE_NULL)
+				bp->dr->wValue = cpu_to_le16(1);
+			else
+				bp->dr->wValue = cpu_to_le16(0);
+			bp->dr->wIndex =
+			    cpu_to_le16(AUH_B1CHANNEL + bc->channel);
+			bp->dr->wLength = cpu_to_le16(0);
+			*bp->bufp = mode;
+			FILL_CONTROL_URB(bp->urbp, cp->usbdev,
+					 usb_sndctrlpipe(cp->usbdev, 0),
+					 (unsigned char *) bp->dr,
+					 bp->bufp, 0,
+					 (usb_complete_t)
+					 auerisdn_bmode_complete, bp);
+
+			/* submit the control msg */
+			ret =
+			    auerchain_submit_urb(&cp->controlchain,
+						 bp->urbp);
+			if (ret) {
+				bp->urbp->status = ret;
+				auerisdn_bmode_complete(bp->urbp);
+			}
+			return;
+		}
+	}
+	/* new mode is set */
+	bc->mode = mode;
+
+	/* send confirmation to L2 */
+	auerisdn_bconf(bc);
+}
+
+/* B-channel transfer function L2->L1 */
+void auerisdn_b_l2l1(struct hisax_if *ifc, int pr, void *arg,
+		     unsigned int channel)
+{
+	struct auerhisax *ahp;
+	struct auerisdnbc *bc;
+	struct auerswald *cp;
+	struct sk_buff *skb;
+	unsigned long flags;
+	int mode;
+
+	cp = NULL;
+	ahp = (struct auerhisax *) ifc->priv;
+	if (ahp)
+		cp = ahp->cp;
+	if (cp && !cp->disconnecting) {
+		/* normal execution */
+		bc = &cp->isdn.bc[channel];
+		switch (pr) {
+		case PH_ACTIVATE | REQUEST:	/* activation request */
+			mode = (int) arg;	/* one of the L1_MODE constants */
+			dbg("B%d, PH_ACTIVATE_REQUEST Mode = %d",
+			    bc->channel + 1, mode);
+			auerisdn_bmode(bc, mode);
+			break;
+		case PH_DEACTIVATE | REQUEST:	/* deactivation request */
+			dbg("B%d, PH_DEACTIVATE_REQUEST", bc->channel + 1);
+			auerisdn_bmode(bc, L1_MODE_NULL);
+			break;
+		case PH_DATA | REQUEST:	/* Transmit data request */
+			skb = (struct sk_buff *) arg;
+			spin_lock_irqsave(&bc->txskb_lock, flags);
+			if (bc->txskb) {
+				err("Overflow in B channel TX");
+				skb_pull(skb, skb->len);
+				dev_kfree_skb_any(skb);
+			} else {
+				if (cp->disconnecting
+				    || (bc->mode == L1_MODE_NULL)) {
+					skb_pull(skb, skb->len);
+					spin_unlock_irqrestore(&bc->
+							       txskb_lock,
+							       flags);
+					auerisdn_b_l1l2(bc,
+							PH_DATA | CONFIRM,
+							(void *) skb->
+							truesize);
+					dev_kfree_skb_any(skb);
+					goto next;
+				} else
+					bc->txskb = skb;
+			}
+			spin_unlock_irqrestore(&bc->txskb_lock, flags);
+		      next:break;
+		default:
+			warn("pr %#x\n", pr);
+			break;
+		}
+	} else {
+		/* hisax interface is down */
+		switch (pr) {
+		case PH_ACTIVATE | REQUEST:	/* activation request */
+			dbg("B channel: PH_ACTIVATE | REQUEST with interface down");
+			/* don't answer this request! Endless... */
+			break;
+		case PH_DEACTIVATE | REQUEST:	/* deactivation request */
+			dbg("B channel: PH_DEACTIVATE | REQUEST with interface down");
+			ifc->l1l2(ifc, PH_DEACTIVATE | INDICATION, NULL);
+			break;
+		case PH_DATA | REQUEST:	/* Transmit data request */
+			dbg("B channel: PH_DATA | REQUEST with interface down");
+			skb = (struct sk_buff *) arg;
+			/* free data buffer */
+			if (skb) {
+				skb_pull(skb, skb->len);
+				dev_kfree_skb_any(skb);
+			}
+			/* send confirmation back to layer 2 */
+			ifc->l1l2(ifc, PH_DATA | CONFIRM, NULL);
+			break;
+		default:
+			warn("pr %#x\n", pr);
+			break;
+		}
+	}
+}
+
+/* Completion handler for B channel input endpoint */
+void auerisdn_intbi_complete(struct urb *urb)
+{
+	unsigned int bytecount;
+	unsigned char *ucp;
+	int channel;
+	unsigned int syncbit;
+	unsigned int syncdata;
+	struct auerisdnbc *bc;
+	struct sk_buff *skb;
+	int count;
+	int status;
+	struct auerswald *cp = (struct auerswald *) urb->context;
+	/* do not respond to an error condition */
+	if (urb->status != 0) {
+		dbg("nonzero URB status = %d", urb->status);
+		return;
+	}
+	if (cp->disconnecting)
+		return;
+
+	/* Parse and extract the header information */
+	bytecount = urb->actual_length;
+	ucp = cp->isdn.intbi_bufp;
+	if (!bytecount)
+		return;		/* no data */
+	channel = *ucp & AUH_TYPEMASK;
+	syncbit = *ucp & AUH_SYNC;
+	ucp++;
+	bytecount--;
+	channel -= AUH_B1CHANNEL;
+	if (channel < 0)
+		return;		/* unknown data channel, no B1,B2 */
+	if (channel >= AUISDN_BCHANNELS)
+		return;		/* unknown data channel, no B1,B2 */
+	bc = &cp->isdn.bc[channel];
+	if (!bytecount)
+		return;
+	/* Calculate amount of bytes which are free in tx device buffer */
+	bc->txfree = ((255 - *ucp++) * bc->ofsize) / 256;
+	/* dbg ("%d Bytes free in TX buffer", bc->txfree); */
+	bytecount--;
+
+	/* Next Byte: TX sync information */
+	if (syncbit) {
+		if (!bytecount)
+			goto int_tx;
+		syncdata = *ucp++;
+		dbg("Sync data = %d", syncdata);
+		bytecount--;
+	}
+	/* The rest of the paket is plain data */
+	if (!bytecount)
+		goto int_tx;
+	/* dump ("RX Data is:", ucp, bytecount); */
+
+	/* Send B channel data to upper layers */
+	while (bytecount > 0) {
+		if (bc->mode == L1_MODE_NULL) {
+			/* skip the data. Nobody needs them */
+			status = 0;
+			bytecount = 0;
+		} else if (bc->mode == L1_MODE_TRANS) {
+			{	/* swap rx bytes */
+				register unsigned char *dest = bc->rxbuf;
+				status = bytecount;
+				for (; bytecount; bytecount--)
+					*dest++ =
+					    isdnhdlc_bit_rev_tab[*ucp++];
+			}
+
+		} else {
+			status = isdnhdlc_decode(&bc->inp_hdlc_state, ucp,
+						 bytecount, &count,
+						 bc->rxbuf, AUISDN_RXSIZE);
+			ucp += count;
+			bytecount -= count;
+		}
+		if (status > 0) {
+			/* Good frame received */
+			if (!(skb = dev_alloc_skb(status))) {
+				warn("receive out of memory");
+				break;
+			}
+			memcpy(skb_put(skb, status), bc->rxbuf, status);
+			/* dump ("HDLC Paket", bc->rxbuf, status); */
+			auerisdn_b_l1l2(bc, PH_DATA | INDICATION, skb);
+			/* these errors may actually happen at the start of a connection! */
+		} else if (status == -HDLC_CRC_ERROR) {
+			dbg("CRC error");
+		} else if (status == -HDLC_FRAMING_ERROR) {
+			dbg("framing error");
+		} else if (status == -HDLC_LENGTH_ERROR) {
+			dbg("length error");
+		}
+	}
+
+      int_tx:			/* serve the outgoing B channel */
+	auerisdn_bserv(&cp->isdn);
+}
+
+/* Stop the B channel activity. The device is disconnecting */
+/* This function is called after cp->disconnecting is true */
+unsigned int auerisdn_b_disconnect(struct auerswald *cp)
+{
+	unsigned int u;
+	struct auerisdnbc *bc;
+	unsigned int result = 0;
+
+	/* Close the B channels */
+	for (u = 0; u < AUISDN_BCHANNELS; u++) {
+		bc = &cp->isdn.bc[u];
+		if (bc->mode != L1_MODE_NULL) {	/* B channel is active */
+			auerisdn_bmode(bc, L1_MODE_NULL);
+			result = 1;
+		}
+	}
+	/* return 1 if there is B channel traffic */
+	return result;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/auerisdn_b.h linux-2.4.21-pre6/drivers/usb/auerisdn_b.h
--- linux-2.4.20/drivers/usb/auerisdn_b.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/auerisdn_b.h	2003-03-26 23:48:58.000000000 +0000
@@ -0,0 +1,66 @@
+/*****************************************************************************/
+/*
+ *      auerisdn_b.h  --  Auerswald PBX/System Telephone ISDN B channel interface.
+ *
+ *      Copyright (C) 2002  Wolfgang Mües (wolfgang@iksw-muees.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 AUERISDN_B_H
+#define AUERISDN_B_H
+
+#include <../drivers/isdn/hisax/hisax_if.h>
+#include <linux/skbuff.h>
+#include "auerbuf.h"
+#include <../drivers/isdn/hisax/isdnhdlc.h>
+
+#define AUISDN_RXSIZE	4096	/* RX buffer size */
+#define AUISDN_BCHANNELS   2	/* Number of supported B channels */
+
+/* states for intbo_state */
+#define INTBOS_IDLE	0
+#define INTBOS_RUNNING	1
+#define INTBOS_CHANGE 	2
+#define INTBOS_RESTART	3
+
+/* ...................................................................*/
+/* B channel state data */
+struct auerswald;
+struct auerisdnbc {
+	struct auerswald *cp;	/* Context to usb device */
+	struct sk_buff *txskb;	/* sk buff to transmitt */
+	spinlock_t txskb_lock;	/* protect against races */
+	unsigned int mode;	/* B-channel mode */
+	unsigned int channel;	/* Number of this B-channel */
+	unsigned int ofsize;	/* Size of device OUT fifo in Bytes */
+	int txfree;		/* free bytes in tx buffer of device */
+	unsigned int txsize;	/* size of data paket for this channel */
+	unsigned char *rxbuf;	/* Receiver input buffer */
+	struct isdnhdlc_vars inp_hdlc_state;	/* state for RX software HDLC */
+	struct isdnhdlc_vars outp_hdlc_state;	/* state for TX software HDLC */
+	unsigned int lastbyte;	/* last byte sent out to trans. B channel */
+};
+
+/* Function Prototypes */
+void auerisdn_b_l2l1(struct hisax_if *ifc, int pr, void *arg,
+		     unsigned int channel);
+void auerisdn_b_l1l2(struct auerisdnbc *bc, int pr, void *arg);
+
+void auerisdn_intbi_complete(struct urb *urb);
+unsigned int auerisdn_b_disconnect(struct auerswald *cp);
+
+#endif	/* AUERISDN_B_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/auermain.c linux-2.4.21-pre6/drivers/usb/auermain.c
--- linux-2.4.20/drivers/usb/auermain.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/auermain.c	2003-03-26 23:49:35.000000000 +0000
@@ -0,0 +1,897 @@
+/*****************************************************************************/
+/*
+ *      auermain.c  --  Auerswald PBX/System Telephone usb driver.
+ *
+ *      Copyright (C) 2002  Wolfgang Mües (wolfgang@iksw-muees.de)
+ *
+ *      Very much code of this driver is borrowed from dabusb.c (Deti Fliegl)
+ *      and from the USB Skeleton driver (Greg Kroah-Hartman). Thank you.
+ *
+ *      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.
+ */
+ /*****************************************************************************/
+
+/* Standard Linux module include files */
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/devfs_fs_kernel.h>
+#undef DEBUG			/* include debug macros until it's done */
+#include <linux/usb.h>
+#include "auerchain.h"
+#include "auerbuf.h"
+#include "auerchar.h"
+#include "auerserv.h"
+#include "auermain.h"
+#include "auerisdn.h"
+
+/*-------------------------------------------------------------------*/
+/* Debug support 						     */
+#ifdef DEBUG
+#define dump( desc, adr, len) \
+do {			\
+	unsigned int u;	\
+	printk (KERN_DEBUG); \
+	printk (desc); \
+	for (u = 0; u < len; u++) \
+		printk (" %02X", adr[u] & 0xFF); \
+	printk ("\n"); \
+} while (0)
+#else
+#define dump( desc, adr, len)
+#endif
+
+/*-------------------------------------------------------------------*/
+/* Version Information */
+#define DRIVER_VERSION "1.2.0"
+#define DRIVER_AUTHOR  "Wolfgang Mües <wolfgang@iksw-muees.de>"
+#define DRIVER_DESC    "Auerswald PBX/System Telephone usb driver"
+
+/*-------------------------------------------------------------------*/
+/* Internal data structures                                          */
+
+/* the global usb devfs handle */
+extern devfs_handle_t usb_devfs_handle;
+
+/* array of pointers to our devices that are currently connected */
+struct auerswald *auerdev_table[AUER_MAX_DEVICES];
+
+/* lock to protect the auerdev_table structure */
+struct semaphore auerdev_table_mutex;
+
+/*-------------------------------------------------------------------*/
+/* Forwards */
+static void auerswald_ctrlread_complete(struct urb *urb);
+
+/*-------------------------------------------------------------------*/
+/* Completion handlers */
+
+/* Values of urb->status or results of usb_submit_urb():
+0		Initial, OK
+-EINPROGRESS	during submission until end
+-ENOENT		if urb is unlinked
+-ETIMEDOUT	Transfer timed out, NAK
+-ENOMEM		Memory Overflow
+-ENODEV		Specified USB-device or bus doesn't exist
+-ENXIO		URB already queued
+-EINVAL		a) Invalid transfer type specified (or not supported)
+		b) Invalid interrupt interval (0n256)
+-EAGAIN		a) Specified ISO start frame too early
+		b) (using ISO-ASAP) Too much scheduled for the future wait some time and try again.
+-EFBIG		Too much ISO frames requested (currently uhci900)
+-EPIPE		Specified pipe-handle/Endpoint is already stalled
+-EMSGSIZE	Endpoint message size is zero, do interface/alternate setting
+-EPROTO		a) Bitstuff error
+		b) Unknown USB error
+-EILSEQ		CRC mismatch
+-ENOSR		Buffer error
+-EREMOTEIO	Short packet detected
+-EXDEV		ISO transfer only partially completed look at individual frame status for details
+-EINVAL		ISO madness, if this happens: Log off and go home
+-EOVERFLOW	babble
+*/
+
+/* check if a status code allows a retry */
+static int auerswald_status_retry(int status)
+{
+	switch (status) {
+	case 0:
+	case -ETIMEDOUT:
+	case -EOVERFLOW:
+	case -EAGAIN:
+	case -EPIPE:
+	case -EPROTO:
+	case -EILSEQ:
+	case -ENOSR:
+	case -EREMOTEIO:
+		return 1;	/* do a retry */
+	}
+	return 0;		/* no retry possible */
+}
+
+
+/* Completion of asynchronous write block */
+void auerchar_ctrlwrite_complete(struct urb *urb)
+{
+	struct auerbuf *bp = (struct auerbuf *) urb->context;
+	struct auerswald *cp =
+	    ((struct auerswald *) ((char *) (bp->list) -
+				   (unsigned
+				    long) (&((struct auerswald *) 0)->
+					   bufctl)));
+	dbg("auerchar_ctrlwrite_complete called");
+
+	/* reuse the buffer */
+	auerbuf_releasebuf(bp);
+	/* Wake up all processes waiting for a buffer */
+	wake_up(&cp->bufferwait);
+}
+
+/* Completion handler for dummy retry packet */
+static void auerswald_ctrlread_wretcomplete(struct urb *urb)
+{
+	struct auerbuf *bp = (struct auerbuf *) urb->context;
+	struct auerswald *cp;
+	int ret;
+	dbg("auerswald_ctrlread_wretcomplete called");
+	dbg("complete with status: %d", urb->status);
+	cp = ((struct auerswald *) ((char *) (bp->list) -
+				    (unsigned
+				     long) (&((struct auerswald *) 0)->
+					    bufctl)));
+
+	/* check if it is possible to advance */
+	if (!auerswald_status_retry(urb->status) || !cp->usbdev) {
+		/* reuse the buffer */
+		err("control dummy: transmission error %d, can not retry",
+		    urb->status);
+		auerbuf_releasebuf(bp);
+		/* Wake up all processes waiting for a buffer */
+		wake_up(&cp->bufferwait);
+		return;
+	}
+
+	/* fill the control message */
+	bp->dr->bRequestType = AUT_RREQ;
+	bp->dr->bRequest = AUV_RBLOCK;
+	bp->dr->wLength = bp->dr->wValue;	/* temporary stored */
+	bp->dr->wValue = cpu_to_le16(1);	/* Retry Flag */
+	/* bp->dr->wIndex    = channel id;          remains */
+	FILL_CONTROL_URB(bp->urbp, cp->usbdev,
+			 usb_rcvctrlpipe(cp->usbdev, 0),
+			 (unsigned char *) bp->dr, bp->bufp,
+			 le16_to_cpu(bp->dr->wLength),
+			 (usb_complete_t) auerswald_ctrlread_complete, bp);
+
+	/* submit the control msg as next paket */
+	ret = auerchain_submit_urb_list(&cp->controlchain, bp->urbp, 1);
+	if (ret) {
+		dbg("auerswald_ctrlread_complete: nonzero result of auerchain_submit_urb_list %d", ret);
+		bp->urbp->status = ret;
+		auerswald_ctrlread_complete(bp->urbp);
+	}
+}
+
+/* completion handler for receiving of control messages */
+static void auerswald_ctrlread_complete(struct urb *urb)
+{
+	unsigned int serviceid;
+	struct auerswald *cp;
+	struct auerscon *scp;
+	struct auerbuf *bp = (struct auerbuf *) urb->context;
+	int ret;
+	dbg("auerswald_ctrlread_complete called");
+
+	cp = ((struct auerswald *) ((char *) (bp->list) -
+				    (unsigned
+				     long) (&((struct auerswald *) 0)->
+					    bufctl)));
+
+	/* check if there is valid data in this urb */
+	if (urb->status) {
+		dbg("complete with non-zero status: %d", urb->status);
+		/* should we do a retry? */
+		if (!auerswald_status_retry(urb->status)
+		    || !cp->usbdev || (cp->version < AUV_RETRY)
+		    || (bp->retries >= AU_RETRIES)) {
+			/* reuse the buffer */
+			err("control read: transmission error %d, can not retry", urb->status);
+			auerbuf_releasebuf(bp);
+			/* Wake up all processes waiting for a buffer */
+			wake_up(&cp->bufferwait);
+			return;
+		}
+		bp->retries++;
+		dbg("Retry count = %d", bp->retries);
+		/* send a long dummy control-write-message to allow device firmware to react */
+		bp->dr->bRequestType = AUT_WREQ;
+		bp->dr->bRequest = AUV_DUMMY;
+		bp->dr->wValue = bp->dr->wLength;	/* temporary storage */
+		// bp->dr->wIndex    channel ID remains
+		bp->dr->wLength = cpu_to_le16(32);	/* >= 8 bytes */
+		FILL_CONTROL_URB(bp->urbp, cp->usbdev,
+				 usb_sndctrlpipe(cp->usbdev, 0),
+				 (unsigned char *) bp->dr, bp->bufp, 32,
+				 (usb_complete_t)
+				 auerswald_ctrlread_wretcomplete, bp);
+
+		/* submit the control msg as next paket */
+		ret =
+		    auerchain_submit_urb_list(&cp->controlchain, bp->urbp,
+					      1);
+		if (ret) {
+			dbg("auerswald_ctrlread_complete: nonzero result of auerchain_submit_urb_list %d", ret);
+			bp->urbp->status = ret;
+			auerswald_ctrlread_wretcomplete(bp->urbp);
+		}
+		return;
+	}
+
+	/* get the actual bytecount (incl. headerbyte) */
+	bp->len = urb->actual_length;
+	serviceid = bp->bufp[0] & AUH_TYPEMASK;
+	dbg("Paket with serviceid %d and %d bytes received", serviceid,
+	    bp->len);
+
+	/* dispatch the paket */
+	scp = cp->services[serviceid];
+	if (scp) {
+		/* look, Ma, a listener! */
+		scp->dispatch(scp, bp);
+	}
+
+	/* release the paket */
+	auerbuf_releasebuf(bp);
+	/* Wake up all processes waiting for a buffer */
+	wake_up(&cp->bufferwait);
+}
+
+/*-------------------------------------------------------------------*/
+/* Handling of Interrupt Endpoint                                    */
+/* This interrupt Endpoint is used to inform the host about waiting
+   messages from the USB device.
+*/
+/* int completion handler. */
+static void auerswald_int_complete(struct urb *urb)
+{
+	unsigned int channelid;
+	unsigned int bytecount;
+	int ret;
+	struct auerbuf *bp = NULL;
+	struct auerswald *cp = (struct auerswald *) urb->context;
+
+	dbg("auerswald_int_complete called");
+
+	/* do not respond to an error condition */
+	if (urb->status != 0) {
+		dbg("nonzero URB status = %d", urb->status);
+		return;
+	}
+
+	/* check if all needed data was received */
+	if (urb->actual_length < AU_IRQMINSIZE) {
+		dbg("invalid data length received: %d bytes",
+		    urb->actual_length);
+		return;
+	}
+
+	/* check the command code */
+	if (cp->intbufp[0] != AU_IRQCMDID) {
+		dbg("invalid command received: %d", cp->intbufp[0]);
+		return;
+	}
+
+	/* check the command type */
+	if (cp->intbufp[1] != AU_BLOCKRDY) {
+		dbg("invalid command type received: %d", cp->intbufp[1]);
+		return;
+	}
+
+	/* now extract the information */
+	channelid = cp->intbufp[2];
+	bytecount = le16_to_cpup(&cp->intbufp[3]);
+
+	/* check the channel id */
+	if (channelid >= AUH_TYPESIZE) {
+		dbg("invalid channel id received: %d", channelid);
+		return;
+	}
+
+	/* check the byte count */
+	if (bytecount > (cp->maxControlLength + AUH_SIZE)) {
+		dbg("invalid byte count received: %d", bytecount);
+		return;
+	}
+	dbg("Service Channel = %d", channelid);
+	dbg("Byte Count = %d", bytecount);
+
+	/* get a buffer for the next data paket */
+	bp = auerbuf_getbuf(&cp->bufctl);
+	/* if no buffer available: skip it */
+	if (!bp) {
+		dbg("auerswald_int_complete: no data buffer available");
+		/* can we do something more?
+		   This is a big problem: if this int packet is ignored, the
+		   device will wait forever and not signal any more data.
+		   The only real solution is: having enought buffers!
+		   Or perhaps temporary disabling the int endpoint?
+		 */
+		return;
+	}
+
+	/* fill the control message */
+	bp->dr->bRequestType = AUT_RREQ;
+	bp->dr->bRequest = AUV_RBLOCK;
+	bp->dr->wValue = cpu_to_le16(0);
+	bp->dr->wIndex = cpu_to_le16(channelid | AUH_DIRECT | AUH_UNSPLIT);
+	bp->dr->wLength = cpu_to_le16(bytecount);
+	FILL_CONTROL_URB(bp->urbp, cp->usbdev,
+			 usb_rcvctrlpipe(cp->usbdev, 0),
+			 (unsigned char *) bp->dr, bp->bufp, bytecount,
+			 (usb_complete_t) auerswald_ctrlread_complete, bp);
+
+	/* submit the control msg */
+	ret = auerchain_submit_urb(&cp->controlchain, bp->urbp);
+	if (ret) {
+		dbg("auerswald_int_complete: nonzero result of auerchain_submit_urb %d", ret);
+		bp->urbp->status = ret;
+		auerswald_ctrlread_complete(bp->urbp);
+		/* here applies the same problem as above: device locking! */
+	}
+}
+
+/* int memory deallocation
+   NOTE: no mutex please!
+*/
+static void auerswald_int_free(struct auerswald *cp)
+{
+	if (cp->inturbp) {
+		usb_free_urb(cp->inturbp);
+		cp->inturbp = NULL;
+	}
+	kfree(cp->intbufp);
+}
+
+/* This function is called to activate the interrupt
+   endpoint. This function returns 0 if successfull or an error code.
+   NOTE: no mutex please!
+*/
+static int auerswald_int_open(struct auerswald *cp)
+{
+	int ret;
+	struct usb_endpoint_descriptor *ep;
+	int irqsize;
+	dbg("auerswald_int_open");
+
+	ep = usb_epnum_to_ep_desc(cp->usbdev, USB_DIR_IN | AU_IRQENDP);
+	if (!ep) {
+		ret = -EFAULT;
+		goto intoend;
+	}
+	irqsize = ep->wMaxPacketSize;
+	cp->irqsize = irqsize;
+
+	/* allocate the urb and data buffer */
+	if (!cp->inturbp) {
+		cp->inturbp = usb_alloc_urb(0);
+		if (!cp->inturbp) {
+			ret = -ENOMEM;
+			goto intoend;
+		}
+	}
+	if (!cp->intbufp) {
+		cp->intbufp = (char *) kmalloc(irqsize, GFP_KERNEL);
+		if (!cp->intbufp) {
+			ret = -ENOMEM;
+			goto intoend;
+		}
+	}
+	/* setup urb */
+	FILL_INT_URB(cp->inturbp, cp->usbdev,
+		     usb_rcvintpipe(cp->usbdev, AU_IRQENDP), cp->intbufp,
+		     irqsize, auerswald_int_complete, cp, ep->bInterval);
+	/* start the urb */
+	cp->inturbp->status = 0;	/* needed! */
+	ret = usb_submit_urb(cp->inturbp);
+
+      intoend:
+	if (ret < 0) {
+		/* activation of interrupt endpoint has failed. Now clean up. */
+		dbg("auerswald_int_open: activation of int endpoint failed");
+
+		/* deallocate memory */
+		auerswald_int_free(cp);
+	}
+	return ret;
+}
+
+/* This function is called to deactivate the interrupt
+   endpoint. This function returns 0 if successfull or an error code.
+   NOTE: no mutex please!
+*/
+static int auerswald_int_release(struct auerswald *cp)
+{
+	int ret = 0;
+	dbg("auerswald_int_release");
+
+	/* stop the int endpoint */
+	if (cp->inturbp) {
+		ret = usb_unlink_urb(cp->inturbp);
+		if (ret)
+			dbg("nonzero int unlink result received: %d", ret);
+	}
+
+	/* deallocate memory */
+	auerswald_int_free(cp);
+
+	return ret;
+}
+
+/* --------------------------------------------------------------------- */
+/* Helper functions                                                      */
+
+/* Delete an auerswald driver context */
+void auerswald_delete(struct auerswald *cp)
+{
+	dbg("auerswald_delete");
+	if (cp == NULL)
+		return;
+
+	/* Wake up all processes waiting for a buffer */
+	wake_up(&cp->bufferwait);
+
+	/* Cleaning up */
+	auerisdn_disconnect(cp);
+	auerswald_int_release(cp);
+	auerchain_free(&cp->controlchain);
+	auerbuf_free_buffers(&cp->bufctl);
+
+	/* release the memory */
+	kfree(cp);
+}
+
+
+/* add a new service to the device
+   scp->id must be set!
+   return: 0 if OK, else error code
+*/
+int auerswald_addservice(struct auerswald *cp, struct auerscon *scp)
+{
+	int ret;
+
+	/* is the device available? */
+	if (!cp->usbdev) {
+		dbg("usbdev == NULL");
+		return -EIO;	/*no: can not add a service, sorry */
+	}
+
+	/* is the service available? */
+	if (cp->services[scp->id]) {
+		dbg("service is busy");
+		return -EBUSY;
+	}
+
+	/* device is available, service is free */
+	cp->services[scp->id] = scp;
+
+	/* register service in device */
+	ret = auerchain_control_msg(&cp->controlchain,			/* pointer to control chain */
+				    cp->usbdev,				/* pointer to device */
+				    usb_sndctrlpipe(cp->usbdev, 0),	/* pipe to control endpoint */
+				    AUV_CHANNELCTL,			/* USB message request value */
+				    AUT_WREQ,				/* USB message request type value */
+				    0x01,	/* open */		/* USB message value */
+				    scp->id,				/* USB message index value */
+				    NULL,				/* pointer to the data to send */
+				    0,					/* length in bytes of the data to send */
+				    HZ * 2);				/* time to wait for the message to complete before timing out */
+	if (ret < 0) {
+		dbg("auerswald_addservice: auerchain_control_msg returned error code %d", ret);
+		/* undo above actions */
+		cp->services[scp->id] = NULL;
+		return ret;
+	}
+
+	dbg("auerswald_addservice: channel open OK");
+	return 0;
+}
+
+
+/* remove a service from the the device
+   scp->id must be set! */
+void auerswald_removeservice(struct auerswald *cp, struct auerscon *scp)
+{
+	dbg("auerswald_removeservice called");
+
+	/* check if we have a service allocated */
+	if (scp->id == AUH_UNASSIGNED)
+		return;
+
+	/* If there is a device: close the channel */
+	if (cp->usbdev && !cp->disconnecting) {
+		/* Close the service channel inside the device */
+		int ret = auerchain_control_msg(&cp->controlchain,		/* pointer to control chain */
+						cp->usbdev,			/* pointer to device */
+						usb_sndctrlpipe(cp->usbdev, 0),	/* pipe to control endpoint */
+						AUV_CHANNELCTL,			/* USB message request value */
+						AUT_WREQ,			/* USB message request type value */
+						0x00,	/* close */		/* USB message value */
+						scp->id,			/* USB message index value */
+						NULL,				/* pointer to the data to send */
+						0,				/* length in bytes of the data to send */
+						HZ * 2);			/* time to wait for the message to complete before timing out */
+		if (ret < 0) {
+			dbg("auerswald_removeservice: auerchain_control_msg returned error code %d", ret);
+		} else {
+			dbg("auerswald_removeservice: channel close OK");
+		}
+	}
+
+	/* remove the service from the device */
+	cp->services[scp->id] = NULL;
+	scp->id = AUH_UNASSIGNED;
+}
+
+
+/*----------------------------------------------------------------------*/
+/* File operation structure                                             */
+static struct file_operations auerswald_fops = {
+	owner:THIS_MODULE,
+	llseek:auerchar_llseek,
+	read:auerchar_read,
+	write:auerchar_write,
+	ioctl:auerchar_ioctl,
+	open:auerchar_open,
+	release:auerchar_release,
+};
+
+/* --------------------------------------------------------------------- */
+/* Special USB driver functions                                          */
+
+/* Probe if this driver wants to serve an USB device
+
+   This entry point is called whenever a new device is attached to the bus.
+   Then the device driver has to create a new instance of its internal data
+   structures for the new device.
+
+   The  dev argument specifies the device context, which contains pointers
+   to all USB descriptors. The  interface argument specifies the interface
+   number. If a USB driver wants to bind itself to a particular device and
+   interface it has to return a pointer. This pointer normally references
+   the device driver's context structure.
+
+   Probing normally is done by checking the vendor and product identifications
+   or the class and subclass definitions. If they match the interface number
+   is compared with the ones supported by the driver. When probing is done
+   class based it might be necessary to parse some more USB descriptors because
+   the device properties can differ in a wide range.
+*/
+static void *auerswald_probe(struct usb_device *usbdev, unsigned int ifnum,
+			     const struct usb_device_id *id)
+{
+	struct auerswald *cp = NULL;
+	DECLARE_WAIT_QUEUE_HEAD(wqh);
+	unsigned int dtindex;
+	unsigned int u = 0;
+	char *pbuf;
+	int ret;
+
+	dbg("probe: vendor id 0x%x, device id 0x%x ifnum:%d",
+	    usbdev->descriptor.idVendor, usbdev->descriptor.idProduct,
+	    ifnum);
+
+	/* See if the device offered us matches that we can accept */
+	if (usbdev->descriptor.idVendor != ID_AUERSWALD)
+		return NULL;
+
+	/* we use only the first -and only- interface */
+	if (ifnum != 0)
+		return NULL;
+
+	/* prevent module unloading while sleeping */
+	MOD_INC_USE_COUNT;
+
+	/* allocate memory for our device and intialize it */
+	cp = kmalloc(sizeof(struct auerswald), GFP_KERNEL);
+	if (cp == NULL) {
+		err("out of memory");
+		goto pfail;
+	}
+
+	/* Initialize device descriptor */
+	memset(cp, 0, sizeof(struct auerswald));
+	init_MUTEX(&cp->mutex);
+	cp->usbdev = usbdev;
+	auerchain_init(&cp->controlchain);
+	auerbuf_init(&cp->bufctl);
+	init_waitqueue_head(&cp->bufferwait);
+	auerisdn_init_dev(cp);
+
+	/* find a free slot in the device table */
+	down(&auerdev_table_mutex);
+	for (dtindex = 0; dtindex < AUER_MAX_DEVICES; ++dtindex) {
+		if (auerdev_table[dtindex] == NULL)
+			break;
+	}
+	if (dtindex >= AUER_MAX_DEVICES) {
+		err("more than %d devices plugged in, can not handle this device", AUER_MAX_DEVICES);
+		up(&auerdev_table_mutex);
+		goto pfail;
+	}
+
+	/* Give the device a name */
+	sprintf(cp->name, AU_PREFIX "%d", dtindex);
+
+	/* Store the index */
+	cp->dtindex = dtindex;
+	auerdev_table[dtindex] = cp;
+	up(&auerdev_table_mutex);
+
+	/* initialize the devfs node for this device and register it */
+	cp->devfs = devfs_register(usb_devfs_handle, cp->name,
+				   DEVFS_FL_DEFAULT, USB_MAJOR,
+				   AUER_MINOR_BASE + dtindex,
+				   S_IFCHR | S_IRUGO | S_IWUGO,
+				   &auerswald_fops, NULL);
+
+	/* Get the usb version of the device */
+	cp->version = cp->usbdev->descriptor.bcdDevice;
+	dbg("Version is %X", cp->version);
+
+	/* allow some time to settle the device */
+	sleep_on_timeout(&wqh, HZ / 3);
+
+	/* Try to get a suitable textual description of the device */
+	/* Device name: */
+	ret =
+	    usb_string(cp->usbdev, AUSI_DEVICE, cp->dev_desc,
+		       AUSI_DLEN - 1);
+	if (ret >= 0) {
+		u += ret;
+		/* Append Serial Number */
+		memcpy(&cp->dev_desc[u], ",Ser# ", 6);
+		u += 6;
+		ret =
+		    usb_string(cp->usbdev, AUSI_SERIALNR, &cp->dev_desc[u],
+			       AUSI_DLEN - u - 1);
+		if (ret >= 0) {
+			u += ret;
+			/* Append subscriber number */
+			memcpy(&cp->dev_desc[u], ", ", 2);
+			u += 2;
+			ret =
+			    usb_string(cp->usbdev, AUSI_MSN,
+				       &cp->dev_desc[u],
+				       AUSI_DLEN - u - 1);
+			if (ret >= 0) {
+				u += ret;
+			}
+		}
+	}
+	cp->dev_desc[u] = '\0';
+	info("device is a %s", cp->dev_desc);
+
+	/* get the maximum allowed control transfer length */
+	pbuf = (char *) kmalloc(2, GFP_KERNEL);	/* use an allocated buffer because of urb target */
+	if (!pbuf) {
+		err("out of memory");
+		goto pfail;
+	}
+	ret = usb_control_msg(cp->usbdev,			/* pointer to device */
+			      usb_rcvctrlpipe(cp->usbdev, 0),	/* pipe to control endpoint */
+			      AUV_GETINFO,			/* USB message request value */
+			      AUT_RREQ,				/* USB message request type value */
+			      0,				/* USB message value */
+			      AUDI_MBCTRANS,			/* USB message index value */
+			      pbuf,				/* pointer to the receive buffer */
+			      2,				/* length of the buffer */
+			      HZ * 2);				/* time to wait for the message to complete before timing out */
+	if (ret == 2) {
+		cp->maxControlLength = le16_to_cpup(pbuf);
+		kfree(pbuf);
+		dbg("setup: max. allowed control transfersize is %d bytes",
+		    cp->maxControlLength);
+	} else {
+		kfree(pbuf);
+		err("setup: getting max. allowed control transfer length failed with error %d", ret);
+		goto pfail;
+	}
+	/* allocate a chain for the control messages */
+	if (auerchain_setup(&cp->controlchain, AUCH_ELEMENTS)) {
+		err("out of memory");
+		goto pfail;
+	}
+
+	/* allocate buffers for control messages */
+	if (auerbuf_setup
+	    (&cp->bufctl, AU_RBUFFERS * 2,
+	     cp->maxControlLength + AUH_SIZE)) {
+		err("out of memory");
+		goto pfail;
+	}
+
+	/* start the interrupt endpoint */
+	if (auerswald_int_open(cp)) {
+		err("int endpoint failed");
+		goto pfail;
+	}
+
+	/* Try to connect to hisax interface */
+	if (auerisdn_probe(cp)) {
+		err("hisax connect failed");
+		goto pfail;
+	}
+
+	/* all OK */
+	return cp;
+
+	/* Error exit: clean up the memory */
+      pfail:auerswald_delete(cp);
+	MOD_DEC_USE_COUNT;
+	return NULL;
+}
+
+
+/* Disconnect driver from a served device
+
+   This function is called whenever a device which was served by this driver
+   is disconnected.
+
+   The argument  dev specifies the device context and the  driver_context
+   returns a pointer to the previously registered  driver_context of the
+   probe function. After returning from the disconnect function the USB
+   framework completly deallocates all data structures associated with
+   this device. So especially the usb_device structure must not be used
+   any longer by the usb driver.
+*/
+static void auerswald_disconnect(struct usb_device *usbdev,
+				 void *driver_context)
+{
+	struct auerswald *cp = (struct auerswald *) driver_context;
+	unsigned int u;
+
+	/* all parallel tasks can react on disconnect ASAP */
+	cp->disconnecting = 1;
+	down(&cp->mutex);
+	info("device /dev/usb/%s now disconnecting", cp->name);
+
+	/* remove from device table */
+	/* Nobody can open() this device any more */
+	down(&auerdev_table_mutex);
+	auerdev_table[cp->dtindex] = NULL;
+	up(&auerdev_table_mutex);
+
+	/* remove our devfs node */
+	/* Nobody can see this device any more */
+	devfs_unregister(cp->devfs);
+
+	/* stop the ISDN connection */
+	auerisdn_disconnect(cp);
+
+	/* Stop the interrupt endpoint 0 */
+	auerswald_int_release(cp);
+
+	/* remove the control chain allocated in auerswald_probe
+	   This has the benefit of
+	   a) all pending (a)synchronous urbs are unlinked
+	   b) all buffers dealing with urbs are reclaimed
+	 */
+	auerchain_free(&cp->controlchain);
+
+	if (cp->open_count == 0) {
+		struct auerscon *scp;
+		/* nobody is using this device. So we can clean up now */
+		up(&cp->mutex);	/* up() is possible here because no other task
+				   can open the device (see above). I don't want
+				   to kfree() a locked mutex. */
+		/* disconnect the D channel */
+		scp = cp->services[AUH_DCHANNEL];
+		if (scp)
+			scp->disconnect(scp);
+		auerswald_delete(cp);
+	} else {
+		/* device is used. Remove the pointer to the
+		   usb device (it's not valid any more). The last
+		   release() will do the clean up */
+		cp->usbdev = NULL;
+		up(&cp->mutex);
+		/* Terminate waiting writers */
+		wake_up(&cp->bufferwait);
+		/* Inform all waiting readers */
+		for (u = 0; u < AUH_TYPESIZE; u++) {
+			struct auerscon *scp = cp->services[u];
+			if (scp)
+				scp->disconnect(scp);
+		}
+	}
+
+	/* The device releases this module */
+	MOD_DEC_USE_COUNT;
+}
+
+/* Descriptor for the devices which are served by this driver.
+   NOTE: this struct is parsed by the usbmanager install scripts.
+         Don't change without caution!
+*/
+static struct usb_device_id auerswald_ids[] = {
+	{USB_DEVICE(ID_AUERSWALD, 0x00C0)},	/* COMpact 2104 USB/DSL */
+	{USB_DEVICE(ID_AUERSWALD, 0x00DB)},	/* COMpact 4410/2206 USB */
+	{USB_DEVICE(ID_AUERSWALD, 0x00DC)},	/* comming soon... */
+	{USB_DEVICE(ID_AUERSWALD, 0x00F1)},	/* Comfort 2000 System Telephone */
+	{USB_DEVICE(ID_AUERSWALD, 0x00F2)},	/* Comfort 1200 System Telephone */
+	{}					/* Terminating entry */
+};
+
+/* Standard module device table */
+MODULE_DEVICE_TABLE(usb, auerswald_ids);
+
+/* Standard usb driver struct */
+static struct usb_driver auerswald_driver = {
+	name:"auerswald",
+	probe:auerswald_probe,
+	disconnect:auerswald_disconnect,
+	fops:&auerswald_fops,
+	minor:AUER_MINOR_BASE,
+	id_table:auerswald_ids,
+};
+
+
+/* --------------------------------------------------------------------- */
+/* Module loading/unloading                                              */
+
+/* Driver initialisation. Called after module loading.
+   NOTE: there is no concurrency at _init
+*/
+static int __init auerswald_init(void)
+{
+	int result;
+	dbg("init");
+
+	/* initialize the device table */
+	memset(&auerdev_table, 0, sizeof(auerdev_table));
+	init_MUTEX(&auerdev_table_mutex);
+	auerisdn_init();
+
+	/* register driver at the USB subsystem */
+	/* NOTE: usb_register() may call probe()! */
+	result = usb_register(&auerswald_driver);
+	if (result < 0) {
+		err("driver could not be registered");
+		return -1;
+	}
+	return 0;
+}
+
+/* Driver deinit. Called before module removal.
+   NOTE: there is no concurrency at _cleanup
+*/
+static void __exit auerswald_cleanup(void)
+{
+	dbg("cleanup");
+	auerisdn_cleanup();
+	usb_deregister(&auerswald_driver);
+}
+
+/* --------------------------------------------------------------------- */
+/* Linux device driver module description                                */
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+module_init(auerswald_init);
+module_exit(auerswald_cleanup);
+
+/* --------------------------------------------------------------------- */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/auermain.h linux-2.4.21-pre6/drivers/usb/auermain.h
--- linux-2.4.20/drivers/usb/auermain.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/auermain.h	2003-03-26 23:49:10.000000000 +0000
@@ -0,0 +1,172 @@
+/*****************************************************************************/
+/*
+ *      auermain.h  --  Auerswald PBX/System Telephone usb driver.
+ *
+ *      Copyright (C) 2002  Wolfgang Mües (wolfgang@iksw-muees.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 AUERMAIN_H
+#define AUERMAIN_H
+
+#include <linux/devfs_fs_kernel.h>
+#include <linux/usb.h>
+#include "auerchain.h"
+#include "auerbuf.h"
+#include "auerserv.h"
+#include "auerisdn.h"
+
+/*-------------------------------------------------------------------*/
+/* Private declarations for Auerswald USB driver                     */
+
+/* Auerswald Vendor ID */
+#define ID_AUERSWALD  	0x09BF
+
+#ifndef AUER_MINOR_BASE		/* allow external override */
+#define AUER_MINOR_BASE	112	/* auerswald driver minor number */
+#endif
+
+/* we can have up to this number of device plugged in at once */
+#define AUER_MAX_DEVICES 16
+
+/* prefix for the device descriptors in /dev/usb */
+#define AU_PREFIX	"auer"
+
+/* Number of read buffers for each device */
+#define AU_RBUFFERS     10
+
+/* Number of chain elements for each control chain */
+#define AUCH_ELEMENTS   20
+
+/* Number of retries in communication */
+#define AU_RETRIES	10
+
+/*-------------------------------------------------------------------*/
+/* vendor specific protocol                                          */
+/* Header Byte */
+#define AUH_INDIRMASK   0x80	/* mask for direct/indirect bit */
+#define AUH_DIRECT      0x00	/* data is for USB device */
+#define AUH_INDIRECT    0x80	/* USB device is relay */
+
+#define AUH_SPLITMASK   0x40	/* mask for split bit */
+#define AUH_UNSPLIT     0x00	/* data block is full-size */
+#define AUH_SPLIT       0x40	/* data block is part of a larger one,
+				   split-byte follows */
+#define AUH_SYNC	0x40	/* Sync to start of HDLC frame for B1,B2 */
+
+#define AUH_TYPEMASK    0x3F	/* mask for type of data transfer */
+#define AUH_TYPESIZE    0x40	/* different types */
+#define AUH_DCHANNEL    0x00	/* D channel data */
+#define AUH_B1CHANNEL   0x01	/* B1 channel transparent */
+#define AUH_B2CHANNEL   0x02	/* B2 channel transparent */
+/*                0x03..0x0F       reserved for driver internal use */
+#define AUH_COMMAND     0x10	/* Command channel */
+#define AUH_BPROT       0x11	/* Configuration block protocol */
+#define AUH_DPROTANA    0x12	/* D channel protocol analyzer */
+#define AUH_TAPI        0x13	/* telephone api data (ATD) */
+/*                0x14..0x3F       reserved for other protocols */
+#define AUH_UNASSIGNED  0xFF	/* if char device has no assigned service */
+#define AUH_FIRSTUSERCH 0x11	/* first channel which is available for driver users */
+
+#define AUH_SIZE	1	/* Size of Header Byte */
+
+/* Split Byte. Only present if split bit in header byte set.*/
+#define AUS_STARTMASK   0x80	/* mask for first block of splitted frame */
+#define AUS_FIRST       0x80	/* first block */
+#define AUS_FOLLOW      0x00	/* following block */
+
+#define AUS_ENDMASK     0x40	/* mask for last block of splitted frame */
+#define AUS_END         0x40	/* last block */
+#define AUS_NOEND       0x00	/* not the last block */
+
+#define AUS_LENMASK     0x3F	/* mask for block length information */
+
+/* Request types */
+#define AUT_RREQ        (USB_DIR_IN  | USB_TYPE_VENDOR | USB_RECIP_OTHER)	/* Read Request */
+#define AUT_WREQ        (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER)	/* Write Request */
+
+/* Vendor Requests */
+#define AUV_GETINFO     0x00	/* GetDeviceInfo */
+#define AUV_WBLOCK      0x01	/* Write Block */
+#define AUV_RBLOCK      0x02	/* Read Block */
+#define AUV_CHANNELCTL  0x03	/* Channel Control */
+#define AUV_DUMMY	0x04	/* Dummy Out for retry */
+
+/* Device Info Types */
+#define AUDI_NUMBCH     0x0000	/* Number of supported B channels */
+#define AUDI_OUTFSIZE   0x0001	/* Size of OUT B channel fifos */
+#define AUDI_MBCTRANS   0x0002	/* max. Blocklength of control transfer */
+
+/* Interrupt endpoint definitions */
+#define AU_IRQENDP      1	/* Endpoint number */
+#define AU_IRQCMDID     16	/* Command-block ID */
+#define AU_BLOCKRDY     0	/* Command: Block data ready on ctl endpoint */
+#define AU_IRQMINSIZE	5	/* Nr. of bytes decoded in this driver */
+
+/* B channel Interrupt endpoint definitions */
+#define AU_IRQENDPBI	2	/* Input Endpoint number */
+#define AU_IRQENDPBO	3	/* Output Endpoint number for 4410, 2206 */
+#define AU_IRQENDPBO_2	2	/* Output Endpoint number for 2104 */
+
+/* Device String Descriptors */
+#define AUSI_VENDOR   	1	/* "Auerswald GmbH & Co. KG" */
+#define AUSI_DEVICE   	2	/* Name of the Device */
+#define AUSI_SERIALNR 	3	/* Serial Number */
+#define AUSI_MSN      	4	/* "MSN ..." (first) Multiple Subscriber Number */
+
+#define AUSI_DLEN	100	/* Max. Length of Device Description */
+
+#define AUV_RETRY	0x101	/* First Firmware version which can do control retries */
+
+/* ...................................................................*/
+/* USB device context */
+struct auerswald {
+	struct semaphore mutex;		/* protection in user context */
+	char name[16];			/* name of the /dev/usb entry */
+	unsigned int dtindex;		/* index in the device table */
+	devfs_handle_t devfs;		/* devfs device node */
+	struct usb_device *usbdev;	/* USB device handle */
+	int open_count;			/* count the number of open character channels */
+	char dev_desc[AUSI_DLEN];	/* for storing a textual description */
+	unsigned int maxControlLength;	/* max. Length of control paket (without header) */
+	struct urb *inturbp;		/* interrupt urb */
+	char *intbufp;			/* data buffer for interrupt urb */
+	unsigned int irqsize;		/* size of interrupt endpoint 1 */
+	struct auerchain controlchain;	/* for chaining of control messages */
+	struct auerbufctl bufctl;	/* Buffer control for control transfers */
+	struct auerscon *services[AUH_TYPESIZE];/* context pointers for each service */
+	unsigned int version;		/* Version of the device */
+	wait_queue_head_t bufferwait;	/* wait for a control buffer */
+	volatile unsigned int disconnecting;/* 1: removal in progress */
+	struct auerisdn isdn;		/* ISDN-Related parameters */
+};
+
+/* array of pointers to our devices that are currently connected */
+extern struct auerswald *auerdev_table[AUER_MAX_DEVICES];
+
+/* lock to protect the auerdev_table structure */
+extern struct semaphore auerdev_table_mutex;
+
+void auerswald_removeservice(struct auerswald *cp, struct auerscon *scp);
+
+int auerswald_addservice(struct auerswald *cp, struct auerscon *scp);
+
+void auerchar_ctrlwrite_complete(struct urb *urb);
+
+void auerswald_delete(struct auerswald *cp);
+
+#endif	/* AUERMAIN_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/auerserv.h linux-2.4.21-pre6/drivers/usb/auerserv.h
--- linux-2.4.20/drivers/usb/auerserv.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/auerserv.h	2003-03-26 23:49:38.000000000 +0000
@@ -0,0 +1,47 @@
+/*****************************************************************************/
+/*
+ *      auerserv.h  --  Auerswald PBX/System Telephone service request structure.
+ *
+ *      Copyright (C) 2002  Wolfgang Mües (wolfgang@iksw-muees.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.
+ */
+ /*****************************************************************************/
+
+/* The auerswald ISDN devices have a logical channel concept. Many channels are
+ * realized via one control endpoint or INT endpoint. At the receiver side, these
+ * messages must be dispatched. Some data may be for an application which is
+ * connected through the char interface, other data may be D-channel information
+ * routed to ISDN4LINUX. The auerscon struct is used to dispatch the data.
+ */
+
+#ifndef AUERSERV_H
+#define AUERSERV_H
+
+#include "auerbuf.h"
+
+/* service context */
+struct auerscon;
+typedef void (*auer_dispatch_t) (struct auerscon *, struct auerbuf *);
+typedef void (*auer_disconn_t) (struct auerscon *);
+
+struct auerscon {
+	unsigned int id;		/* protocol service id AUH_xxxx */
+	auer_dispatch_t dispatch;	/* dispatch read buffer */
+	auer_disconn_t disconnect;	/* disconnect from device, wake up all readers */
+};
+
+
+#endif	/* AUERSERV_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/auerswald.c linux-2.4.21-pre6/drivers/usb/auerswald.c
--- linux-2.4.20/drivers/usb/auerswald.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/auerswald.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,2196 +0,0 @@
-/*****************************************************************************/
-/*
- *      auerswald.c  --  Auerswald PBX/System Telephone usb driver.
- *
- *      Copyright (C) 2001  Wolfgang Mües (wolfgang@iksw-muees.de)
- *
- *      Very much code of this driver is borrowed from dabusb.c (Deti Fliegl)
- *      and from the USB Skeleton driver (Greg Kroah-Hartman). Thank you.
- *
- *      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.
- */
- /*****************************************************************************/
-
-/* Standard Linux module include files */
-#include <asm/uaccess.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/devfs_fs_kernel.h>
-#undef DEBUG   		/* include debug macros until it's done	*/
-#include <linux/usb.h>
-
-/*-------------------------------------------------------------------*/
-/* Debug support 						     */
-#ifdef DEBUG
-#define dump( adr, len) \
-do {			\
-	unsigned int u;	\
-	printk (KERN_DEBUG); \
-	for (u = 0; u < len; u++) \
-		printk (" %02X", adr[u] & 0xFF); \
-	printk ("\n"); \
-} while (0)
-#else
-#define dump( adr, len)
-#endif
-
-/*-------------------------------------------------------------------*/
-/* Version Information */
-#define DRIVER_VERSION "0.9.11"
-#define DRIVER_AUTHOR  "Wolfgang Mües <wolfgang@iksw-muees.de>"
-#define DRIVER_DESC    "Auerswald PBX/System Telephone usb driver"
-
-/*-------------------------------------------------------------------*/
-/* Private declarations for Auerswald USB driver                     */
-
-/* Auerswald Vendor ID */
-#define ID_AUERSWALD  	0x09BF
-
-#ifndef AUER_MINOR_BASE		/* allow external override */
-#define AUER_MINOR_BASE	112	/* auerswald driver minor number */
-#endif
-
-/* we can have up to this number of device plugged in at once */
-#define AUER_MAX_DEVICES 16
-
-/* prefix for the device descriptors in /dev/usb */
-#define AU_PREFIX	"auer"
-
-/* Number of read buffers for each device */
-#define AU_RBUFFERS     10
-
-/* Number of chain elements for each control chain */
-#define AUCH_ELEMENTS   20
-
-/* Number of retries in communication */
-#define AU_RETRIES	10
-
-/*-------------------------------------------------------------------*/
-/* vendor specific protocol                                          */
-/* Header Byte */
-#define AUH_INDIRMASK   0x80    /* mask for direct/indirect bit */
-#define AUH_DIRECT      0x00    /* data is for USB device */
-#define AUH_INDIRECT    0x80    /* USB device is relay */
-
-#define AUH_SPLITMASK   0x40    /* mask for split bit */
-#define AUH_UNSPLIT     0x00    /* data block is full-size */
-#define AUH_SPLIT       0x40    /* data block is part of a larger one,
-                                   split-byte follows */
-
-#define AUH_TYPEMASK    0x3F    /* mask for type of data transfer */
-#define AUH_TYPESIZE    0x40    /* different types */
-#define AUH_DCHANNEL    0x00    /* D channel data */
-#define AUH_B1CHANNEL   0x01    /* B1 channel transparent */
-#define AUH_B2CHANNEL   0x02    /* B2 channel transparent */
-/*                0x03..0x0F       reserved for driver internal use */
-#define AUH_COMMAND     0x10    /* Command channel */
-#define AUH_BPROT       0x11    /* Configuration block protocol */
-#define AUH_DPROTANA    0x12    /* D channel protocol analyzer */
-#define AUH_TAPI        0x13    /* telephone api data (ATD) */
-/*                0x14..0x3F       reserved for other protocols */
-#define AUH_UNASSIGNED  0xFF    /* if char device has no assigned service */
-#define AUH_FIRSTUSERCH 0x11    /* first channel which is available for driver users */
-
-#define AUH_SIZE	1 	/* Size of Header Byte */
-
-/* Split Byte. Only present if split bit in header byte set.*/
-#define AUS_STARTMASK   0x80    /* mask for first block of splitted frame */
-#define AUS_FIRST       0x80    /* first block */
-#define AUS_FOLLOW      0x00    /* following block */
-
-#define AUS_ENDMASK     0x40    /* mask for last block of splitted frame */
-#define AUS_END         0x40    /* last block */
-#define AUS_NOEND       0x00    /* not the last block */
-
-#define AUS_LENMASK     0x3F    /* mask for block length information */
-
-/* Request types */
-#define AUT_RREQ        (USB_DIR_IN  | USB_TYPE_VENDOR | USB_RECIP_OTHER)   /* Read Request */
-#define AUT_WREQ        (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER)   /* Write Request */
-
-/* Vendor Requests */
-#define AUV_GETINFO     0x00    /* GetDeviceInfo */
-#define AUV_WBLOCK      0x01    /* Write Block */
-#define AUV_RBLOCK      0x02    /* Read Block */
-#define AUV_CHANNELCTL  0x03    /* Channel Control */
-#define AUV_DUMMY	0x04	/* Dummy Out for retry */
-
-/* Device Info Types */
-#define AUDI_NUMBCH     0x0000  /* Number of supported B channels */
-#define AUDI_OUTFSIZE   0x0001  /* Size of OUT B channel fifos */
-#define AUDI_MBCTRANS   0x0002  /* max. Blocklength of control transfer */
-
-/* Interrupt endpoint definitions */
-#define AU_IRQENDP      1       /* Endpoint number */
-#define AU_IRQCMDID     16      /* Command-block ID */
-#define AU_BLOCKRDY     0       /* Command: Block data ready on ctl endpoint */
-#define AU_IRQMINSIZE	5	/* Nr. of bytes decoded in this driver */
-
-/* Device String Descriptors */
-#define AUSI_VENDOR   	1	/* "Auerswald GmbH & Co. KG" */
-#define AUSI_DEVICE   	2	/* Name of the Device */
-#define AUSI_SERIALNR 	3	/* Serial Number */
-#define AUSI_MSN      	4	/* "MSN ..." (first) Multiple Subscriber Number */
-
-#define AUSI_DLEN	100	/* Max. Length of Device Description */
-
-#define AUV_RETRY	0x101	/* First Firmware version which can do control retries */
-
-/*-------------------------------------------------------------------*/
-/* External data structures / Interface                              */
-typedef struct
-{
-        char *buf;               /* return buffer for string contents */
-        unsigned int bsize;      /* size of return buffer */
-} audevinfo_t,*paudevinfo_t;
-
-/* IO controls */
-#define IOCTL_AU_SLEN	  _IOR( 'U', 0xF0, int)         /* return the max. string descriptor length */
-#define IOCTL_AU_DEVINFO  _IOWR('U', 0xF1, audevinfo_t) /* get name of a specific device */
-#define IOCTL_AU_SERVREQ  _IOW( 'U', 0xF2, int) 	/* request a service channel */
-#define IOCTL_AU_BUFLEN	  _IOR( 'U', 0xF3, int)         /* return the max. buffer length for the device */
-#define IOCTL_AU_RXAVAIL  _IOR( 'U', 0xF4, int)         /* return != 0 if Receive Data available */
-#define IOCTL_AU_CONNECT  _IOR( 'U', 0xF5, int)         /* return != 0 if connected to a service channel */
-#define IOCTL_AU_TXREADY  _IOR( 'U', 0xF6, int)         /* return != 0 if Transmitt channel ready to send */
-/*                              'U'  0xF7..0xFF reseved */
-
-/*-------------------------------------------------------------------*/
-/* Internal data structures                                          */
-
-/* ..................................................................*/
-/* urb chain element */
-struct  auerchain;                      /* forward for circular reference */
-typedef struct
-{
-        struct auerchain *chain;        /* pointer to the chain to which this element belongs */
-        struct urb * urbp;                   /* pointer to attached urb */
-        void *context;                  /* saved URB context */
-        usb_complete_t complete;        /* saved URB completion function */
-        struct list_head list;          /* to include element into a list */
-} auerchainelement_t,*pauerchainelement_t;
-
-/* urb chain */
-typedef struct auerchain
-{
-        pauerchainelement_t active;     /* element which is submitted to urb */
-	spinlock_t lock;                /* protection agains interrupts */
-        struct list_head waiting_list;  /* list of waiting elements */
-        struct list_head free_list;     /* list of available elements */
-} auerchain_t,*pauerchain_t;
-
-/* urb blocking completion helper struct */
-typedef struct
-{
-	wait_queue_head_t wqh;    	/* wait for completion */
-	unsigned int done;		/* completion flag */
-} auerchain_chs_t,*pauerchain_chs_t;
-
-/* ...................................................................*/
-/* buffer element */
-struct  auerbufctl;                     /* forward */
-typedef struct
-{
-        char *bufp;                     /* reference to allocated data buffer */
-        unsigned int len;               /* number of characters in data buffer */
-	unsigned int retries;		/* for urb retries */
-        struct usb_ctrlrequest *dr;                 /* for setup data in control messages */
-        struct urb * urbp;                   /* USB urb */
-        struct auerbufctl *list;        /* pointer to list */
-        struct list_head buff_list;     /* reference to next buffer in list */
-} auerbuf_t,*pauerbuf_t;
-
-/* buffer list control block */
-typedef struct auerbufctl
-{
-        spinlock_t lock;                /* protection in interrupt */
-        struct list_head free_buff_list;/* free buffers */
-        struct list_head rec_buff_list; /* buffers with receive data */
-} auerbufctl_t,*pauerbufctl_t;
-
-/* ...................................................................*/
-/* service context */
-struct  auerscon;                       /* forward */
-typedef void (*auer_dispatch_t)(struct auerscon*, pauerbuf_t);
-typedef void (*auer_disconn_t) (struct auerscon*);
-typedef struct auerscon
-{
-        unsigned int id;                /* protocol service id AUH_xxxx */
-        auer_dispatch_t dispatch;       /* dispatch read buffer */
-	auer_disconn_t disconnect;	/* disconnect from device, wake up all char readers */
-} auerscon_t,*pauerscon_t;
-
-/* ...................................................................*/
-/* USB device context */
-typedef struct
-{
-	struct semaphore 	mutex;         	    /* protection in user context */
-	char 			name[16];	    /* name of the /dev/usb entry */
-	unsigned int		dtindex;	    /* index in the device table */
-	devfs_handle_t 		devfs;	 	    /* devfs device node */
-	struct usb_device *	usbdev;      	    /* USB device handle */
-	int			open_count;	    /* count the number of open character channels */
-        char 			dev_desc[AUSI_DLEN];/* for storing a textual description */
-        unsigned int 		maxControlLength;   /* max. Length of control paket (without header) */
-        struct urb * 		inturbp;            /* interrupt urb */
-        char *			intbufp;            /* data buffer for interrupt urb */
-	unsigned int 		irqsize;	    /* size of interrupt endpoint 1 */
-        struct auerchain 	controlchain;  	    /* for chaining of control messages */
-	auerbufctl_t 		bufctl;             /* Buffer control for control transfers */
-        pauerscon_t 	     	services[AUH_TYPESIZE];/* context pointers for each service */
-	unsigned int		version;	    /* Version of the device */
-	wait_queue_head_t 	bufferwait;         /* wait for a control buffer */
-} auerswald_t,*pauerswald_t;
-
-/* the global usb devfs handle */
-extern devfs_handle_t usb_devfs_handle;
-
-/* array of pointers to our devices that are currently connected */
-static pauerswald_t dev_table[AUER_MAX_DEVICES];
-
-/* lock to protect the dev_table structure */
-static struct semaphore dev_table_mutex;
-
-/* ................................................................... */
-/* character device context */
-typedef struct
-{
-	struct semaphore mutex;         /* protection in user context */
-	pauerswald_t auerdev;           /* context pointer of assigned device */
-        auerbufctl_t bufctl;            /* controls the buffer chain */
-        auerscon_t scontext;            /* service context */
-	wait_queue_head_t readwait;     /* for synchronous reading */
-	struct semaphore readmutex;     /* protection against multiple reads */
-	pauerbuf_t readbuf;		/* buffer held for partial reading */
-	unsigned int readoffset;	/* current offset in readbuf */
-	unsigned int removed;		/* is != 0 if device is removed */
-} auerchar_t,*pauerchar_t;
-
-
-/*-------------------------------------------------------------------*/
-/* Forwards */
-static void auerswald_ctrlread_complete (struct urb * urb);
-static void auerswald_removeservice (pauerswald_t cp, pauerscon_t scp);
-
-
-/*-------------------------------------------------------------------*/
-/* USB chain helper functions                                        */
-/* --------------------------                                        */
-
-/* completion function for chained urbs */
-static void auerchain_complete (struct urb * urb)
-{
-	unsigned long flags;
-        int result;
-
-        /* get pointer to element and to chain */
-        pauerchainelement_t acep = (pauerchainelement_t) urb->context;
-        pauerchain_t         acp = acep->chain;
-
-        /* restore original entries in urb */
-        urb->context  = acep->context;
-        urb->complete = acep->complete;
-
-        dbg ("auerchain_complete called");
-
-        /* call original completion function
-           NOTE: this function may lead to more urbs submitted into the chain.
-                 (no chain lock at calling complete()!)
-                 acp->active != NULL is protecting us against recursion.*/
-        urb->complete (urb);
-
-        /* detach element from chain data structure */
-	spin_lock_irqsave (&acp->lock, flags);
-        if (acp->active != acep) /* paranoia debug check */
-	        dbg ("auerchain_complete: completion on non-active element called!");
-        else
-                acp->active = NULL;
-
-        /* add the used chain element to the list of free elements */
-	list_add_tail (&acep->list, &acp->free_list);
-        acep = NULL;
-
-        /* is there a new element waiting in the chain? */
-        if (!acp->active && !list_empty (&acp->waiting_list)) {
-                /* yes: get the entry */
-                struct list_head *tmp = acp->waiting_list.next;
-                list_del (tmp);
-                acep = list_entry (tmp, auerchainelement_t, list);
-                acp->active = acep;
-        }
-        spin_unlock_irqrestore (&acp->lock, flags);
-
-        /* submit the new urb */
-        if (acep) {
-                urb    = acep->urbp;
-                dbg ("auerchain_complete: submitting next urb from chain");
-		urb->status = 0;	/* needed! */
-		result = usb_submit_urb( urb);
-
-                /* check for submit errors */
-                if (result) {
-                        urb->status = result;
-                        dbg("auerchain_complete: usb_submit_urb with error code %d", result);
-                        /* and do error handling via *this* completion function (recursive) */
-                        auerchain_complete( urb);
-                }
-        } else {
-                /* simple return without submitting a new urb.
-                   The empty chain is detected with acp->active == NULL. */
-        };
-}
-
-
-/* submit function for chained urbs
-   this function may be called from completion context or from user space!
-   early = 1 -> submit in front of chain
-*/
-static int auerchain_submit_urb_list (pauerchain_t acp, struct urb * urb, int early)
-{
-        int result;
-        unsigned long flags;
-        pauerchainelement_t acep = NULL;
-
-        dbg ("auerchain_submit_urb called");
-
-        /* try to get a chain element */
-        spin_lock_irqsave (&acp->lock, flags);
-        if (!list_empty (&acp->free_list)) {
-                /* yes: get the entry */
-                struct list_head *tmp = acp->free_list.next;
-                list_del (tmp);
-                acep = list_entry (tmp, auerchainelement_t, list);
-        }
-        spin_unlock_irqrestore (&acp->lock, flags);
-
-        /* if no chain element available: return with error */
-        if (!acep) {
-                return -ENOMEM;
-        }
-
-        /* fill in the new chain element values */
-        acep->chain    = acp;
-        acep->context  = urb->context;
-        acep->complete = urb->complete;
-        acep->urbp     = urb;
-        INIT_LIST_HEAD (&acep->list);
-
-        /* modify urb */
-        urb->context   = acep;
-        urb->complete  = auerchain_complete;
-        urb->status    = -EINPROGRESS;    /* usb_submit_urb does this, too */
-
-        /* add element to chain - or start it immediately */
-        spin_lock_irqsave (&acp->lock, flags);
-        if (acp->active) {
-                /* there is traffic in the chain, simple add element to chain */
-		if (early) {
-			dbg ("adding new urb to head of chain");
-			list_add (&acep->list, &acp->waiting_list);
-		} else {
-			dbg ("adding new urb to end of chain");
-			list_add_tail (&acep->list, &acp->waiting_list);
-		}
-		acep = NULL;
-        } else {
-                /* the chain is empty. Prepare restart */
-                acp->active = acep;
-        }
-        /* Spin has to be removed before usb_submit_urb! */
-        spin_unlock_irqrestore (&acp->lock, flags);
-
-        /* Submit urb if immediate restart */
-        if (acep) {
-                dbg("submitting urb immediate");
-		urb->status = 0;	/* needed! */
-                result = usb_submit_urb( urb);
-                /* check for submit errors */
-                if (result) {
-                        urb->status = result;
-                        dbg("auerchain_submit_urb: usb_submit_urb with error code %d", result);
-                        /* and do error handling via completion function */
-                        auerchain_complete( urb);
-                }
-        }
-
-        return 0;
-}
-
-/* submit function for chained urbs
-   this function may be called from completion context or from user space!
-*/
-static int auerchain_submit_urb (pauerchain_t acp, struct urb * urb)
-{
-	return auerchain_submit_urb_list (acp, urb, 0);
-}
-
-/* cancel an urb which is submitted to the chain
-   the result is 0 if the urb is cancelled, or -EINPROGRESS if
-   USB_ASYNC_UNLINK is set and the function is successfully started.
-*/
-static int auerchain_unlink_urb (pauerchain_t acp, struct urb * urb)
-{
-	unsigned long flags;
-        struct urb * urbp;
-        pauerchainelement_t acep;
-        struct list_head *tmp;
-
-        dbg ("auerchain_unlink_urb called");
-
-        /* search the chain of waiting elements */
-        spin_lock_irqsave (&acp->lock, flags);
-        list_for_each (tmp, &acp->waiting_list) {
-                acep = list_entry (tmp, auerchainelement_t, list);
-                if (acep->urbp == urb) {
-                        list_del (tmp);
-                        urb->context = acep->context;
-                        urb->complete = acep->complete;
-                        list_add_tail (&acep->list, &acp->free_list);
-                        spin_unlock_irqrestore (&acp->lock, flags);
-                        dbg ("unlink waiting urb");
-                        urb->status = -ENOENT;
-                        urb->complete (urb);
-                        return 0;
-                }
-        }
-        /* not found. */
-        spin_unlock_irqrestore (&acp->lock, flags);
-
-        /* get the active urb */
-        acep = acp->active;
-        if (acep) {
-                urbp = acep->urbp;
-
-                /* check if we have to cancel the active urb */
-                if (urbp == urb) {
-                        /* note that there is a race condition between the check above
-                           and the unlink() call because of no lock. This race is harmless,
-                           because the usb module will detect the unlink() after completion.
-                           We can't use the acp->lock here because the completion function
-                           wants to grab it.
-			*/
-                        dbg ("unlink active urb");
-                        return usb_unlink_urb (urbp);
-                }
-        }
-
-        /* not found anyway
-           ... is some kind of success
-	*/
-        dbg ("urb to unlink not found in chain");
-        return 0;
-}
-
-/* cancel all urbs which are in the chain.
-   this function must not be called from interrupt or completion handler.
-*/
-static void auerchain_unlink_all (pauerchain_t acp)
-{
-	unsigned long flags;
-        struct urb * urbp;
-        pauerchainelement_t acep;
-
-        dbg ("auerchain_unlink_all called");
-
-        /* clear the chain of waiting elements */
-        spin_lock_irqsave (&acp->lock, flags);
-        while (!list_empty (&acp->waiting_list)) {
-                /* get the next entry */
-                struct list_head *tmp = acp->waiting_list.next;
-                list_del (tmp);
-                acep = list_entry (tmp, auerchainelement_t, list);
-                urbp = acep->urbp;
-                urbp->context = acep->context;
-                urbp->complete = acep->complete;
-                list_add_tail (&acep->list, &acp->free_list);
-                spin_unlock_irqrestore (&acp->lock, flags);
-                dbg ("unlink waiting urb");
-                urbp->status = -ENOENT;
-                urbp->complete (urbp);
-                spin_lock_irqsave (&acp->lock, flags);
-        }
-        spin_unlock_irqrestore (&acp->lock, flags);
-
-        /* clear the active urb */
-        acep = acp->active;
-        if (acep) {
-                urbp = acep->urbp;
-                urbp->transfer_flags &= ~USB_ASYNC_UNLINK;
-                dbg ("unlink active urb");
-                usb_unlink_urb (urbp);
-        }
-}
-
-
-/* free the chain.
-   this function must not be called from interrupt or completion handler.
-*/
-static void auerchain_free (pauerchain_t acp)
-{
-	unsigned long flags;
-        pauerchainelement_t acep;
-
-        dbg ("auerchain_free called");
-
-        /* first, cancel all pending urbs */
-        auerchain_unlink_all (acp);
-
-        /* free the elements */
-        spin_lock_irqsave (&acp->lock, flags);
-        while (!list_empty (&acp->free_list)) {
-                /* get the next entry */
-                struct list_head *tmp = acp->free_list.next;
-                list_del (tmp);
-                spin_unlock_irqrestore (&acp->lock, flags);
-		acep = list_entry (tmp, auerchainelement_t, list);
-                kfree (acep);
-	        spin_lock_irqsave (&acp->lock, flags);
-	}
-        spin_unlock_irqrestore (&acp->lock, flags);
-}
-
-
-/* Init the chain control structure */
-static void auerchain_init (pauerchain_t acp)
-{
-        /* init the chain data structure */
-        acp->active = NULL;
-	spin_lock_init (&acp->lock);
-        INIT_LIST_HEAD (&acp->waiting_list);
-        INIT_LIST_HEAD (&acp->free_list);
-}
-
-/* setup a chain.
-   It is assumed that there is no concurrency while setting up the chain
-   requirement: auerchain_init()
-*/
-static int auerchain_setup (pauerchain_t acp, unsigned int numElements)
-{
-        pauerchainelement_t acep;
-
-        dbg ("auerchain_setup called with %d elements", numElements);
-
-        /* fill the list of free elements */
-        for (;numElements; numElements--) {
-                acep = (pauerchainelement_t) kmalloc (sizeof (auerchainelement_t), GFP_KERNEL);
-                if (!acep) goto ac_fail;
-		memset (acep, 0, sizeof (auerchainelement_t));
-                INIT_LIST_HEAD (&acep->list);
-                list_add_tail (&acep->list, &acp->free_list);
-        }
-        return 0;
-
-ac_fail:/* free the elements */
-        while (!list_empty (&acp->free_list)) {
-                /* get the next entry */
-                struct list_head *tmp = acp->free_list.next;
-                list_del (tmp);
-                acep = list_entry (tmp, auerchainelement_t, list);
-                kfree (acep);
-        }
-        return -ENOMEM;
-}
-
-
-/* completion handler for synchronous chained URBs */
-static void auerchain_blocking_completion (struct urb *urb)
-{
-	pauerchain_chs_t pchs = (pauerchain_chs_t)urb->context;
-	pchs->done = 1;
-	wmb();
-	wake_up (&pchs->wqh);
-}
-
-
-/* Starts chained urb and waits for completion or timeout */
-static int auerchain_start_wait_urb (pauerchain_t acp, struct urb *urb, int timeout, int* actual_length)
-{
-	DECLARE_WAITQUEUE (wait, current);
-	auerchain_chs_t chs;
-	int status;
-
-	dbg ("auerchain_start_wait_urb called");
-	init_waitqueue_head (&chs.wqh);
-	chs.done = 0;
-
-	set_current_state (TASK_UNINTERRUPTIBLE);
-	add_wait_queue (&chs.wqh, &wait);
-	urb->context = &chs;
-	status = auerchain_submit_urb (acp, urb);
-	if (status) {
-		/* something went wrong */
-		set_current_state (TASK_RUNNING);
-		remove_wait_queue (&chs.wqh, &wait);
-		return status;
-	}
-
-	while (timeout && !chs.done)
-	{
-		timeout = schedule_timeout (timeout);
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		rmb();
-	}
-
-	set_current_state (TASK_RUNNING);
-	remove_wait_queue (&chs.wqh, &wait);
-
-	if (!timeout && !chs.done) {
-		if (urb->status != -EINPROGRESS) {	/* No callback?!! */
-			dbg ("auerchain_start_wait_urb: raced timeout");
-			status = urb->status;
-		} else {
-			dbg ("auerchain_start_wait_urb: timeout");
-			auerchain_unlink_urb (acp, urb);  /* remove urb safely */
-			status = -ETIMEDOUT;
-		}
-	} else
-		status = urb->status;
-
-	if (actual_length)
-		*actual_length = urb->actual_length;
-
-  	return status;
-}
-
-
-/* auerchain_control_msg - Builds a control urb, sends it off and waits for completion
-   acp: pointer to the auerchain
-   dev: pointer to the usb device to send the message to
-   pipe: endpoint "pipe" to send the message to
-   request: USB message request value
-   requesttype: USB message request type value
-   value: USB message value
-   index: USB message index value
-   data: pointer to the data to send
-   size: length in bytes of the data to send
-   timeout: time to wait for the message to complete before timing out (if 0 the wait is forever)
-
-   This function sends a simple control message to a specified endpoint
-   and waits for the message to complete, or timeout.
-
-   If successful, it returns the transfered length, othwise a negative error number.
-
-   Don't use this function from within an interrupt context, like a
-   bottom half handler.  If you need a asyncronous message, or need to send
-   a message from within interrupt context, use auerchain_submit_urb()
-*/
-static int auerchain_control_msg (pauerchain_t acp, struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype,
-			          __u16 value, __u16 index, void *data, __u16 size, int timeout)
-{
-	int ret;
-	struct usb_ctrlrequest *dr;
-	struct urb *urb;
-        int length;
-
-        dbg ("auerchain_control_msg");
-        dr = kmalloc (sizeof (struct usb_ctrlrequest), GFP_KERNEL);
-	if (!dr)
-		return -ENOMEM;
-	urb = usb_alloc_urb (0);
-	if (!urb) {
-        	kfree (dr);
-		return -ENOMEM;
-        }
-
-	dr->bRequestType = requesttype;
-	dr->bRequest = request;
-	dr->wValue  = cpu_to_le16 (value);
-	dr->wIndex  = cpu_to_le16 (index);
-	dr->wLength = cpu_to_le16 (size);
-
-	FILL_CONTROL_URB (urb, dev, pipe, (unsigned char*)dr, data, size,    /* build urb */
-		          (usb_complete_t)auerchain_blocking_completion,0);
-	ret = auerchain_start_wait_urb (acp, urb, timeout, &length);
-
-	usb_free_urb (urb);
-	kfree (dr);
-
-        if (ret < 0)
-		return ret;
-	else
-		return length;
-}
-
-
-/*-------------------------------------------------------------------*/
-/* Buffer List helper functions                                      */
-
-/* free a single auerbuf */
-static void auerbuf_free (pauerbuf_t bp)
-{
-	if (bp->bufp) {
-		kfree (bp->bufp);
-	}
-	if (bp->dr) {
-		kfree (bp->dr);
-	}
-	if (bp->urbp) {
-		usb_free_urb (bp->urbp);
-	}
-	kfree (bp);
-}
-
-/* free the buffers from an auerbuf list */
-static void auerbuf_free_list (struct list_head *q)
-{
-        struct list_head *tmp;
-	struct list_head *p;
-	pauerbuf_t bp;
-
-	dbg ("auerbuf_free_list");
-	for (p = q->next; p != q;) {
-		bp = list_entry (p, auerbuf_t, buff_list);
-		tmp = p->next;
-		list_del (p);
-		p = tmp;
-		auerbuf_free (bp);
-	}
-}
-
-/* init the members of a list control block */
-static void auerbuf_init (pauerbufctl_t bcp)
-{
-	dbg ("auerbuf_init");
-	spin_lock_init (&bcp->lock);
-        INIT_LIST_HEAD (&bcp->free_buff_list);
-        INIT_LIST_HEAD (&bcp->rec_buff_list);
-}
-
-/* free all buffers from an auerbuf chain */
-static void auerbuf_free_buffers (pauerbufctl_t bcp)
-{
-	unsigned long flags;
-	dbg ("auerbuf_free_buffers");
-
-        spin_lock_irqsave (&bcp->lock, flags);
-
-	auerbuf_free_list (&bcp->free_buff_list);
-	auerbuf_free_list (&bcp->rec_buff_list);
-
-        spin_unlock_irqrestore (&bcp->lock, flags);
-}
-
-/* setup a list of buffers */
-/* requirement: auerbuf_init() */
-static int auerbuf_setup (pauerbufctl_t bcp, unsigned int numElements, unsigned int bufsize)
-{
-        pauerbuf_t bep;
-
-        dbg ("auerbuf_setup called with %d elements of %d bytes", numElements, bufsize);
-
-        /* fill the list of free elements */
-        for (;numElements; numElements--) {
-                bep = (pauerbuf_t) kmalloc (sizeof (auerbuf_t), GFP_KERNEL);
-                if (!bep) goto bl_fail;
-	        memset (bep, 0, sizeof (auerbuf_t));
-                bep->list = bcp;
-                INIT_LIST_HEAD (&bep->buff_list);
-                bep->bufp = (char *) kmalloc (bufsize, GFP_KERNEL);
-                if (!bep->bufp) goto bl_fail;
-                bep->dr = (struct usb_ctrlrequest *) kmalloc (sizeof (struct usb_ctrlrequest), GFP_KERNEL);
-                if (!bep->dr) goto bl_fail;
-                bep->urbp = usb_alloc_urb (0);
-                if (!bep->urbp) goto bl_fail;
-                list_add_tail (&bep->buff_list, &bcp->free_buff_list);
-        }
-        return 0;
-
-bl_fail:/* not enought memory. Free allocated elements */
-        dbg ("auerbuf_setup: no more memory");
-        auerbuf_free_buffers (bcp);
-        return -ENOMEM;
-}
-
-/* insert a used buffer into the free list */
-static void auerbuf_releasebuf( pauerbuf_t bp)
-{
-        unsigned long flags;
-        pauerbufctl_t bcp = bp->list;
-	bp->retries = 0;
-
-        dbg ("auerbuf_releasebuf called");
-        spin_lock_irqsave (&bcp->lock, flags);
-	list_add_tail (&bp->buff_list, &bcp->free_buff_list);
-        spin_unlock_irqrestore (&bcp->lock, flags);
-}
-
-
-/*-------------------------------------------------------------------*/
-/* Completion handlers */
-
-/* Values of urb->status or results of usb_submit_urb():
-0		Initial, OK
--EINPROGRESS	during submission until end
--ENOENT		if urb is unlinked
--ETIMEDOUT	Transfer timed out, NAK
--ENOMEM		Memory Overflow
--ENODEV		Specified USB-device or bus doesn't exist
--ENXIO		URB already queued
--EINVAL		a) Invalid transfer type specified (or not supported)
-		b) Invalid interrupt interval (0n256)
--EAGAIN		a) Specified ISO start frame too early
-		b) (using ISO-ASAP) Too much scheduled for the future wait some time and try again.
--EFBIG		Too much ISO frames requested (currently uhci900)
--EPIPE		Specified pipe-handle/Endpoint is already stalled
--EMSGSIZE	Endpoint message size is zero, do interface/alternate setting
--EPROTO		a) Bitstuff error
-		b) Unknown USB error
--EILSEQ		CRC mismatch
--ENOSR		Buffer error
--EREMOTEIO	Short packet detected
--EXDEV		ISO transfer only partially completed look at individual frame status for details
--EINVAL		ISO madness, if this happens: Log off and go home
--EOVERFLOW	babble
-*/
-
-/* check if a status code allows a retry */
-static int auerswald_status_retry (int status)
-{
-	switch (status) {
-	case 0:
-	case -ETIMEDOUT:
-	case -EOVERFLOW:
-	case -EAGAIN:
-	case -EPIPE:
-	case -EPROTO:
-	case -EILSEQ:
-	case -ENOSR:
-	case -EREMOTEIO:
-		return 1; /* do a retry */
-	}
-	return 0;	/* no retry possible */
-}
-
-/* Completion of asynchronous write block */
-static void auerchar_ctrlwrite_complete (struct urb * urb)
-{
-	pauerbuf_t bp = (pauerbuf_t) urb->context;
-	pauerswald_t cp = ((pauerswald_t)((char *)(bp->list)-(unsigned long)(&((pauerswald_t)0)->bufctl)));
-	dbg ("auerchar_ctrlwrite_complete called");
-
-	/* reuse the buffer */
-	auerbuf_releasebuf (bp);
-	/* Wake up all processes waiting for a buffer */
-	wake_up (&cp->bufferwait);
-}
-
-/* Completion handler for dummy retry packet */
-static void auerswald_ctrlread_wretcomplete (struct urb * urb)
-{
-        pauerbuf_t bp = (pauerbuf_t) urb->context;
-        pauerswald_t cp;
-	int ret;
-        dbg ("auerswald_ctrlread_wretcomplete called");
-        dbg ("complete with status: %d", urb->status);
-	cp = ((pauerswald_t)((char *)(bp->list)-(unsigned long)(&((pauerswald_t)0)->bufctl)));
-
-	/* check if it is possible to advance */
-	if (!auerswald_status_retry (urb->status) || !cp->usbdev) {
-		/* reuse the buffer */
-		err ("control dummy: transmission error %d, can not retry", urb->status);
-		auerbuf_releasebuf (bp);
-		/* Wake up all processes waiting for a buffer */
-		wake_up (&cp->bufferwait);
-		return;
-	}
-
-	/* fill the control message */
-	bp->dr->bRequestType = AUT_RREQ;
-	bp->dr->bRequest     = AUV_RBLOCK;
-	bp->dr->wLength      = bp->dr->wValue;	/* temporary stored */
-	bp->dr->wValue       = cpu_to_le16 (1);	/* Retry Flag */
-	/* bp->dr->index    = channel id;          remains */
-	FILL_CONTROL_URB (bp->urbp, cp->usbdev, usb_rcvctrlpipe (cp->usbdev, 0),
-                          (unsigned char*)bp->dr, bp->bufp, le16_to_cpu (bp->dr->wLength),
-		          (usb_complete_t)auerswald_ctrlread_complete,bp);
-
-	/* submit the control msg as next paket */
-	ret = auerchain_submit_urb_list (&cp->controlchain, bp->urbp, 1);
-        if (ret) {
-        	dbg ("auerswald_ctrlread_complete: nonzero result of auerchain_submit_urb_list %d", ret);
-        	bp->urbp->status = ret;
-        	auerswald_ctrlread_complete (bp->urbp);
-    	}
-}
-
-/* completion handler for receiving of control messages */
-static void auerswald_ctrlread_complete (struct urb * urb)
-{
-        unsigned int  serviceid;
-        pauerswald_t  cp;
-        pauerscon_t   scp;
-        pauerbuf_t    bp  = (pauerbuf_t) urb->context;
-	int ret;
-        dbg ("auerswald_ctrlread_complete called");
-
-	cp = ((pauerswald_t)((char *)(bp->list)-(unsigned long)(&((pauerswald_t)0)->bufctl)));
-
-	/* check if there is valid data in this urb */
-        if (urb->status) {
-		dbg ("complete with non-zero status: %d", urb->status);
-		/* should we do a retry? */
-		if (!auerswald_status_retry (urb->status)
-		 || !cp->usbdev
-		 || (cp->version < AUV_RETRY)
-                 || (bp->retries >= AU_RETRIES)) {
-			/* reuse the buffer */
-			err ("control read: transmission error %d, can not retry", urb->status);
-			auerbuf_releasebuf (bp);
-			/* Wake up all processes waiting for a buffer */
-			wake_up (&cp->bufferwait);
-			return;
-		}
-		bp->retries++;
-		dbg ("Retry count = %d", bp->retries);
-		/* send a long dummy control-write-message to allow device firmware to react */
-		bp->dr->bRequestType = AUT_WREQ;
-		bp->dr->bRequest     = AUV_DUMMY;
-		bp->dr->wValue       = bp->dr->wLength; /* temporary storage */
-		// bp->dr->index    channel ID remains
-		bp->dr->wLength      = cpu_to_le16 (32); /* >= 8 bytes */
-		FILL_CONTROL_URB (bp->urbp, cp->usbdev, usb_sndctrlpipe (cp->usbdev, 0),
-  			(unsigned char*)bp->dr, bp->bufp, 32,
-	   		(usb_complete_t)auerswald_ctrlread_wretcomplete,bp);
-
-		/* submit the control msg as next paket */
-       		ret = auerchain_submit_urb_list (&cp->controlchain, bp->urbp, 1);
-       		if (ret) {
-               		dbg ("auerswald_ctrlread_complete: nonzero result of auerchain_submit_urb_list %d", ret);
-               		bp->urbp->status = ret;
-               		auerswald_ctrlread_wretcomplete (bp->urbp);
-		}
-                return;
-	} 
-
-        /* get the actual bytecount (incl. headerbyte) */
-        bp->len = urb->actual_length;
-        serviceid = bp->bufp[0] & AUH_TYPEMASK;
-        dbg ("Paket with serviceid %d and %d bytes received", serviceid, bp->len);
-
-        /* dispatch the paket */
-        scp = cp->services[serviceid];
-        if (scp) {
-                /* look, Ma, a listener! */
-                scp->dispatch (scp, bp);
-        }
-
-        /* release the paket */
-        auerbuf_releasebuf (bp);
-	/* Wake up all processes waiting for a buffer */
-	wake_up (&cp->bufferwait);
-}
-
-/*-------------------------------------------------------------------*/
-/* Handling of Interrupt Endpoint                                    */
-/* This interrupt Endpoint is used to inform the host about waiting
-   messages from the USB device.
-*/
-/* int completion handler. */
-static void auerswald_int_complete (struct urb * urb)
-{
-        unsigned long flags;
-        unsigned  int channelid;
-        unsigned  int bytecount;
-        int ret;
-        pauerbuf_t   bp = NULL;
-        pauerswald_t cp = (pauerswald_t) urb->context;
-
-        dbg ("auerswald_int_complete called");
-
-        /* do not respond to an error condition */
-        if (urb->status != 0) {
-                dbg ("nonzero URB status = %d", urb->status);
-                return;
-        }
-
-        /* check if all needed data was received */
-	if (urb->actual_length < AU_IRQMINSIZE) {
-                dbg ("invalid data length received: %d bytes", urb->actual_length);
-                return;
-        }
-
-        /* check the command code */
-        if (cp->intbufp[0] != AU_IRQCMDID) {
-                dbg ("invalid command received: %d", cp->intbufp[0]);
-                return;
-        }
-
-        /* check the command type */
-        if (cp->intbufp[1] != AU_BLOCKRDY) {
-                dbg ("invalid command type received: %d", cp->intbufp[1]);
-                return;
-        }
-
-        /* now extract the information */
-        channelid = cp->intbufp[2];
-        bytecount = le16_to_cpup (&cp->intbufp[3]);
-
-        /* check the channel id */
-        if (channelid >= AUH_TYPESIZE) {
-                dbg ("invalid channel id received: %d", channelid);
-                return;
-        }
-
-        /* check the byte count */
-        if (bytecount > (cp->maxControlLength+AUH_SIZE)) {
-                dbg ("invalid byte count received: %d", bytecount);
-                return;
-        }
-        dbg ("Service Channel = %d", channelid);
-        dbg ("Byte Count = %d", bytecount);
-
-        /* get a buffer for the next data paket */
-        spin_lock_irqsave (&cp->bufctl.lock, flags);
-        if (!list_empty (&cp->bufctl.free_buff_list)) {
-                /* yes: get the entry */
-                struct list_head *tmp = cp->bufctl.free_buff_list.next;
-                list_del (tmp);
-                bp = list_entry (tmp, auerbuf_t, buff_list);
-        }
-        spin_unlock_irqrestore (&cp->bufctl.lock, flags);
-
-        /* if no buffer available: skip it */
-        if (!bp) {
-                dbg ("auerswald_int_complete: no data buffer available");
-                /* can we do something more?
-		   This is a big problem: if this int packet is ignored, the
-		   device will wait forever and not signal any more data.
-		   The only real solution is: having enought buffers!
-		   Or perhaps temporary disabling the int endpoint?
-		*/
-		return;
-        }
-
-	/* fill the control message */
-        bp->dr->bRequestType = AUT_RREQ;
-	bp->dr->bRequest     = AUV_RBLOCK;
-	bp->dr->wValue       = cpu_to_le16 (0);
-	bp->dr->wIndex       = cpu_to_le16 (channelid | AUH_DIRECT | AUH_UNSPLIT);
-	bp->dr->wLength      = cpu_to_le16 (bytecount);
-	FILL_CONTROL_URB (bp->urbp, cp->usbdev, usb_rcvctrlpipe (cp->usbdev, 0),
-                          (unsigned char*)bp->dr, bp->bufp, bytecount,
-		          (usb_complete_t)auerswald_ctrlread_complete,bp);
-
-        /* submit the control msg */
-        ret = auerchain_submit_urb (&cp->controlchain, bp->urbp);
-        if (ret) {
-                dbg ("auerswald_int_complete: nonzero result of auerchain_submit_urb %d", ret);
-                bp->urbp->status = ret;
-                auerswald_ctrlread_complete( bp->urbp);
-		/* here applies the same problem as above: device locking! */
-        }
-}
-
-/* int memory deallocation
-   NOTE: no mutex please!
-*/
-static void auerswald_int_free (pauerswald_t cp)
-{
-        if (cp->inturbp) {
-                usb_free_urb (cp->inturbp);
-                cp->inturbp = NULL;
-        }
-        if (cp->intbufp) {
-                kfree (cp->intbufp);
-                cp->intbufp = NULL;
-        }
-}
-
-/* This function is called to activate the interrupt
-   endpoint. This function returns 0 if successfull or an error code.
-   NOTE: no mutex please!
-*/
-static int auerswald_int_open (pauerswald_t cp)
-{
-        int ret;
-	struct usb_endpoint_descriptor *ep;
-	int irqsize;
-	dbg ("auerswald_int_open");
-
-	ep = usb_epnum_to_ep_desc (cp->usbdev, USB_DIR_IN | AU_IRQENDP);
-	if (!ep) {
-		ret = -EFAULT;
-  		goto intoend;
-    	}
-	irqsize = ep->wMaxPacketSize;
-	cp->irqsize = irqsize;
-
-	/* allocate the urb and data buffer */
-        if (!cp->inturbp) {
-                cp->inturbp = usb_alloc_urb (0);
-                if (!cp->inturbp) {
-                        ret = -ENOMEM;
-                        goto intoend;
-                }
-        }
-        if (!cp->intbufp) {
-                cp->intbufp = (char *) kmalloc (irqsize, GFP_KERNEL);
-                if (!cp->intbufp) {
-                        ret = -ENOMEM;
-                        goto intoend;
-                }
-        }
-        /* setup urb */
-        FILL_INT_URB (cp->inturbp, cp->usbdev, usb_rcvintpipe (cp->usbdev,AU_IRQENDP), cp->intbufp, irqsize, auerswald_int_complete, cp, ep->bInterval);
-        /* start the urb */
-	cp->inturbp->status = 0;	/* needed! */
-	ret = usb_submit_urb (cp->inturbp);
-
-intoend:
-        if (ret < 0) {
-                /* activation of interrupt endpoint has failed. Now clean up. */
-                dbg ("auerswald_int_open: activation of int endpoint failed");
-
-                /* deallocate memory */
-                auerswald_int_free (cp);
-        }
-        return ret;
-}
-
-/* This function is called to deactivate the interrupt
-   endpoint. This function returns 0 if successfull or an error code.
-   NOTE: no mutex please!
-*/
-static int auerswald_int_release (pauerswald_t cp)
-{
-        int ret = 0;
-        dbg ("auerswald_int_release");
-
-        /* stop the int endpoint */
-        if (cp->inturbp) {
-                ret = usb_unlink_urb (cp->inturbp);
-                if (ret)
-	                dbg ("nonzero int unlink result received: %d", ret);
-        }
-
-        /* deallocate memory */
-        auerswald_int_free (cp);
-
-        return ret;
-}
-
-/* --------------------------------------------------------------------- */
-/* Helper functions                                                      */
-
-/* wake up waiting readers */
-static void auerchar_disconnect (pauerscon_t scp)
-{
-        pauerchar_t ccp = ((pauerchar_t)((char *)(scp)-(unsigned long)(&((pauerchar_t)0)->scontext)));
-	dbg ("auerchar_disconnect called");
-	ccp->removed = 1;
-	wake_up (&ccp->readwait);
-}
-
-
-/* dispatch a read paket to a waiting character device */
-static void auerchar_ctrlread_dispatch (pauerscon_t scp, pauerbuf_t bp)
-{
-	unsigned long flags;
-        pauerchar_t ccp;
-        pauerbuf_t newbp = NULL;
-        char * charp;
-        dbg ("auerchar_ctrlread_dispatch called");
-        ccp = ((pauerchar_t)((char *)(scp)-(unsigned long)(&((pauerchar_t)0)->scontext)));
-
-        /* get a read buffer from character device context */
-        spin_lock_irqsave (&ccp->bufctl.lock, flags);
-        if (!list_empty (&ccp->bufctl.free_buff_list)) {
-                /* yes: get the entry */
-                struct list_head *tmp = ccp->bufctl.free_buff_list.next;
-                list_del (tmp);
-                newbp = list_entry (tmp, auerbuf_t, buff_list);
-        }
-        spin_unlock_irqrestore (&ccp->bufctl.lock, flags);
-
-        if (!newbp) {
-                dbg ("No read buffer available, discard paket!");
-                return;     /* no buffer, no dispatch */
-        }
-
-        /* copy information to new buffer element
-           (all buffers have the same length) */
-        charp = newbp->bufp;
-        newbp->bufp = bp->bufp;
-        bp->bufp = charp;
-        newbp->len = bp->len;
-
-        /* insert new buffer in read list */
-        spin_lock_irqsave (&ccp->bufctl.lock, flags);
-	list_add_tail (&newbp->buff_list, &ccp->bufctl.rec_buff_list);
-        spin_unlock_irqrestore (&ccp->bufctl.lock, flags);
-        dbg ("read buffer appended to rec_list");
-
-        /* wake up pending synchronous reads */
-	wake_up (&ccp->readwait);
-}
-
-
-/* Delete an auerswald driver context */
-static void auerswald_delete( pauerswald_t cp)
-{
-	dbg( "auerswald_delete");
-	if (cp == NULL) return;
-
-	/* Wake up all processes waiting for a buffer */
-	wake_up (&cp->bufferwait);
-
-	/* Cleaning up */
-	auerswald_int_release (cp);
-	auerchain_free (&cp->controlchain);
-	auerbuf_free_buffers (&cp->bufctl);
-
-	/* release the memory */
-	kfree( cp);
-}
-
-
-/* Delete an auerswald character context */
-static void auerchar_delete( pauerchar_t ccp)
-{
-	dbg ("auerchar_delete");
-	if (ccp == NULL) return;
-
-        /* wake up pending synchronous reads */
-	ccp->removed = 1;
-	wake_up (&ccp->readwait);
-
-	/* remove the read buffer */
-	if (ccp->readbuf) {
-		auerbuf_releasebuf (ccp->readbuf);
-		ccp->readbuf = NULL;
-	}
-
-	/* remove the character buffers */
-	auerbuf_free_buffers (&ccp->bufctl);
-
-	/* release the memory */
-	kfree( ccp);
-}
-
-
-/* add a new service to the device
-   scp->id must be set!
-   return: 0 if OK, else error code
-*/
-static int auerswald_addservice (pauerswald_t cp, pauerscon_t scp)
-{
-	int ret;
-
-	/* is the device available? */
-	if (!cp->usbdev) {
-		dbg ("usbdev == NULL");
-		return -EIO;	/*no: can not add a service, sorry*/
-	}
-
-	/* is the service available? */
-	if (cp->services[scp->id]) {
-		dbg ("service is busy");
-                return -EBUSY;
-	}
-
-	/* device is available, service is free */
-	cp->services[scp->id] = scp;
-
-	/* register service in device */
-	ret = auerchain_control_msg(
-		&cp->controlchain,                      /* pointer to control chain */
-		cp->usbdev,                             /* pointer to device */
-		usb_sndctrlpipe (cp->usbdev, 0),        /* pipe to control endpoint */
-		AUV_CHANNELCTL,                         /* USB message request value */
-		AUT_WREQ,                               /* USB message request type value */
-		0x01,              /* open                 USB message value */
-		scp->id,            		        /* USB message index value */
-		NULL,                                   /* pointer to the data to send */
-		0,                                      /* length in bytes of the data to send */
-		HZ * 2);                                /* time to wait for the message to complete before timing out */
-	if (ret < 0) {
-		dbg ("auerswald_addservice: auerchain_control_msg returned error code %d", ret);
-		/* undo above actions */
-		cp->services[scp->id] = NULL;
-		return ret;
-	}
-
-	dbg ("auerswald_addservice: channel open OK");
-	return 0;
-}
-
-
-/* remove a service from the device
-   scp->id must be set! */
-static void auerswald_removeservice (pauerswald_t cp, pauerscon_t scp)
-{
-	dbg ("auerswald_removeservice called");
-
-	/* check if we have a service allocated */
-	if (scp->id == AUH_UNASSIGNED) return;
-
-	/* If there is a device: close the channel */
-	if (cp->usbdev) {
-		/* Close the service channel inside the device */
-		int ret = auerchain_control_msg(
-		&cp->controlchain,            		/* pointer to control chain */
-		cp->usbdev,         		        /* pointer to device */
-		usb_sndctrlpipe (cp->usbdev, 0),	/* pipe to control endpoint */
-		AUV_CHANNELCTL,                         /* USB message request value */
-		AUT_WREQ,                               /* USB message request type value */
-		0x00,              // close             /* USB message value */
-		scp->id,            		        /* USB message index value */
-		NULL,                                   /* pointer to the data to send */
-		0,                                      /* length in bytes of the data to send */
-		HZ * 2);                                /* time to wait for the message to complete before timing out */
-		if (ret < 0) {
-			dbg ("auerswald_removeservice: auerchain_control_msg returned error code %d", ret);
-		}
-		else {
-			dbg ("auerswald_removeservice: channel close OK");
-		}
-	}
-
-	/* remove the service from the device */
-	cp->services[scp->id] = NULL;
-	scp->id = AUH_UNASSIGNED;
-}
-
-
-/* --------------------------------------------------------------------- */
-/* Char device functions                                                 */
-
-/* Open a new character device */
-static int auerchar_open (struct inode *inode, struct file *file)
-{
-	int dtindex = MINOR(inode->i_rdev) - AUER_MINOR_BASE;
-	pauerswald_t cp = NULL;
-	pauerchar_t ccp = NULL;
-        int ret;
-
-        /* minor number in range? */
-	if ((dtindex < 0) || (dtindex >= AUER_MAX_DEVICES)) {
-		return -ENODEV;
-        }
-	/* usb device available? */
-	if (down_interruptible (&dev_table_mutex)) {
-		return -ERESTARTSYS;
-	}
-	cp = dev_table[dtindex];
-	if (cp == NULL) {
-		up (&dev_table_mutex);
-		return -ENODEV;
-	}
-	if (down_interruptible (&cp->mutex)) {
-		up (&dev_table_mutex);
-		return -ERESTARTSYS;
-	}
-	up (&dev_table_mutex);
-
-	/* we have access to the device. Now lets allocate memory */
-	ccp = (pauerchar_t) kmalloc(sizeof(auerchar_t), GFP_KERNEL);
-	if (ccp == NULL) {
-		err ("out of memory");
-		ret = -ENOMEM;
-		goto ofail;
-	}
-
-	/* Initialize device descriptor */
-	memset( ccp, 0, sizeof(auerchar_t));
-	init_MUTEX( &ccp->mutex);
-	init_MUTEX( &ccp->readmutex);
-        auerbuf_init (&ccp->bufctl);
-        ccp->scontext.id = AUH_UNASSIGNED;
-        ccp->scontext.dispatch = auerchar_ctrlread_dispatch;
-	ccp->scontext.disconnect = auerchar_disconnect;
-	init_waitqueue_head (&ccp->readwait);
-
-	ret = auerbuf_setup (&ccp->bufctl, AU_RBUFFERS, cp->maxControlLength+AUH_SIZE);
-       	if (ret) {
-		goto ofail;
-	}
-
-	cp->open_count++;
-	ccp->auerdev = cp;
-	dbg("open %s as /dev/usb/%s", cp->dev_desc, cp->name);
-	up (&cp->mutex);
-
-	/* file IO stuff */
-	file->f_pos = 0;
-	file->private_data = ccp;
-	return 0;
-
-	/* Error exit */
-ofail:	up (&cp->mutex);
-	auerchar_delete (ccp);
-	return ret;
-}
-
-
-/* IOCTL functions */
-static int auerchar_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-	pauerchar_t ccp = (pauerchar_t) file->private_data;
-	int ret = 0;
-        audevinfo_t devinfo;
-        pauerswald_t cp = NULL;
-	unsigned int u;
-        dbg ("ioctl");
-
-	/* get the mutexes */
-	if (down_interruptible (&ccp->mutex)) {
-		return -ERESTARTSYS;
-	}
-	cp = ccp->auerdev;
-	if (!cp) {
-		up (&ccp->mutex);
-                return -ENODEV;
-	}
-	if (down_interruptible (&cp->mutex)) {
-		up(&ccp->mutex);
-		return -ERESTARTSYS;
-	}
-
-	/* Check for removal */
-	if (!cp->usbdev) {
-		up(&cp->mutex);
-		up(&ccp->mutex);
-                return -ENODEV;
-	}
-
-	switch (cmd) {
-
-	/* return != 0 if Transmitt channel ready to send */
-	case IOCTL_AU_TXREADY:
-		dbg ("IOCTL_AU_TXREADY");
-		u   = ccp->auerdev
-		   && (ccp->scontext.id != AUH_UNASSIGNED)
-		   && !list_empty (&cp->bufctl.free_buff_list);
-	        ret = put_user (u, (unsigned int *) arg);
-		break;
-
-	/* return != 0 if connected to a service channel */
-	case IOCTL_AU_CONNECT:
-		dbg ("IOCTL_AU_CONNECT");
-		u = (ccp->scontext.id != AUH_UNASSIGNED);
-	        ret = put_user (u, (unsigned int *) arg);
-		break;
-
-	/* return != 0 if Receive Data available */
-	case IOCTL_AU_RXAVAIL:
-		dbg ("IOCTL_AU_RXAVAIL");
-		if (ccp->scontext.id == AUH_UNASSIGNED) {
-                        ret = -EIO;
-                        break;
-                }
-		u = 0;	/* no data */
-		if (ccp->readbuf) {
-			int restlen = ccp->readbuf->len - ccp->readoffset;
-			if (restlen > 0) u = 1;
-		}
-		if (!u) {
-        		if (!list_empty (&ccp->bufctl.rec_buff_list)) {
-				u = 1;
-			}
-		}
-	        ret = put_user (u, (unsigned int *) arg);
-		break;
-
-	/* return the max. buffer length for the device */
-	case IOCTL_AU_BUFLEN:
-		dbg ("IOCTL_AU_BUFLEN");
-		u = cp->maxControlLength;
-	        ret = put_user (u, (unsigned int *) arg);
-		break;
-
-	/* requesting a service channel */
-        case IOCTL_AU_SERVREQ:
-		dbg ("IOCTL_AU_SERVREQ");
-                /* requesting a service means: release the previous one first */
-		auerswald_removeservice (cp, &ccp->scontext);
-		/* get the channel number */
-		ret = get_user (u, (unsigned int *) arg);
-		if (ret) {
-			break;
-		}
-		if ((u < AUH_FIRSTUSERCH) || (u >= AUH_TYPESIZE)) {
-                        ret = -EIO;
-                        break;
-                }
-                dbg ("auerchar service request parameters are ok");
-		ccp->scontext.id = u;
-
-		/* request the service now */
-		ret = auerswald_addservice (cp, &ccp->scontext);
-		if (ret) {
-			/* no: revert service entry */
-                	ccp->scontext.id = AUH_UNASSIGNED;
-		}
-		break;
-
-	/* get a string descriptor for the device */
-	case IOCTL_AU_DEVINFO:
-		dbg ("IOCTL_AU_DEVINFO");
-                if (copy_from_user (&devinfo, (void *) arg, sizeof (audevinfo_t))) {
-        		ret = -EFAULT;
-	        	break;
-                }
-		u = strlen(cp->dev_desc)+1;
-		if (u > devinfo.bsize) {
-			u = devinfo.bsize;
-		}
-		ret = copy_to_user(devinfo.buf, cp->dev_desc, u)?-EFAULT:0;
-		break;
-
-	/* get the max. string descriptor length */
-        case IOCTL_AU_SLEN:
-		dbg ("IOCTL_AU_SLEN");
-		u = AUSI_DLEN;
-	        ret = put_user (u, (unsigned int *) arg);
-		break;
-
-	default:
-		dbg ("IOCTL_AU_UNKNOWN");
-		ret = -ENOIOCTLCMD;
-		break;
-        }
-	/* release the mutexes */
-	up(&cp->mutex);
-	up(&ccp->mutex);
-	return ret;
-}
-
-
-/* Seek is not supported */
-static loff_t auerchar_llseek (struct file *file, loff_t offset, int origin)
-{
-        dbg ("auerchar_seek");
-        return -ESPIPE;
-}
-
-
-/* Read data from the device */
-static ssize_t auerchar_read (struct file *file, char *buf, size_t count, loff_t * ppos)
-{
-        unsigned long flags;
-	pauerchar_t ccp = (pauerchar_t) file->private_data;
-        pauerbuf_t   bp = NULL;
-	wait_queue_t wait;
-
-        dbg ("auerchar_read");
-
-	/* Error checking */
-	if (!ccp)
-		return -EIO;
-	if (*ppos)
- 		return -ESPIPE;
-        if (count == 0)
-		return 0;
-
-	/* get the mutex */
-	if (down_interruptible (&ccp->mutex))
-		return -ERESTARTSYS;
-
-	/* Can we expect to read something? */
-	if (ccp->scontext.id == AUH_UNASSIGNED) {
-		up (&ccp->mutex);
-                return -EIO;
-	}
-
-	/* only one reader per device allowed */
-	if (down_interruptible (&ccp->readmutex)) {
-		up (&ccp->mutex);
-		return -ERESTARTSYS;
-	}
-
-	/* read data from readbuf, if available */
-doreadbuf:
-	bp = ccp->readbuf;
-	if (bp) {
-		/* read the maximum bytes */
-		int restlen = bp->len - ccp->readoffset;
-		if (restlen < 0)
-			restlen = 0;
-		if (count > restlen)
-			count = restlen;
-		if (count) {
-			if (copy_to_user (buf, bp->bufp+ccp->readoffset, count)) {
-				dbg ("auerswald_read: copy_to_user failed");
-				up (&ccp->readmutex);
-				up (&ccp->mutex);
-				return -EFAULT;
-			}
-		}
-		/* advance the read offset */
-		ccp->readoffset += count;
-		restlen -= count;
-		// reuse the read buffer
-		if (restlen <= 0) {
-			auerbuf_releasebuf (bp);
-			ccp->readbuf = NULL;
-		}
-		/* return with number of bytes read */
-		if (count) {
-			up (&ccp->readmutex);
-			up (&ccp->mutex);
-			return count;
-		}
-	}
-
-	/* a read buffer is not available. Try to get the next data block. */
-doreadlist:
-	/* Preparing for sleep */
-	init_waitqueue_entry (&wait, current);
-	set_current_state (TASK_INTERRUPTIBLE);
-	add_wait_queue (&ccp->readwait, &wait);
-
-	bp = NULL;
-	spin_lock_irqsave (&ccp->bufctl.lock, flags);
-        if (!list_empty (&ccp->bufctl.rec_buff_list)) {
-                /* yes: get the entry */
-                struct list_head *tmp = ccp->bufctl.rec_buff_list.next;
-                list_del (tmp);
-                bp = list_entry (tmp, auerbuf_t, buff_list);
-        }
-        spin_unlock_irqrestore (&ccp->bufctl.lock, flags);
-
-	/* have we got data? */
-	if (bp) {
-		ccp->readbuf = bp;
-		ccp->readoffset = AUH_SIZE; /* for headerbyte */
-		set_current_state (TASK_RUNNING);
-		remove_wait_queue (&ccp->readwait, &wait);
-		goto doreadbuf;		  /* now we can read! */
-	}
-
-	/* no data available. Should we wait? */
-	if (file->f_flags & O_NONBLOCK) {
-                dbg ("No read buffer available, returning -EAGAIN");
-		set_current_state (TASK_RUNNING);
-		remove_wait_queue (&ccp->readwait, &wait);
-		up (&ccp->readmutex);
-		up (&ccp->mutex);
-		return -EAGAIN;  /* nonblocking, no data available */
-        }
-
-	/* yes, we should wait! */
-	up (&ccp->mutex); /* allow other operations while we wait */
-	schedule();
-	remove_wait_queue (&ccp->readwait, &wait);
-	if (signal_pending (current)) {
-		/* waked up by a signal */
-		up (&ccp->readmutex);
-		return -ERESTARTSYS;
-	}
-
-	/* Anything left to read? */
-	if ((ccp->scontext.id == AUH_UNASSIGNED) || ccp->removed) {
-		up (&ccp->readmutex);
-		return -EIO;
-	}
-
-	if (down_interruptible (&ccp->mutex)) {
-		up (&ccp->readmutex);
-		return -ERESTARTSYS;
-	}
-
-	/* try to read the incomming data again */
-	goto doreadlist;
-}
-
-
-/* Write a data block into the right service channel of the device */
-static ssize_t auerchar_write (struct file *file, const char *buf, size_t len, loff_t *ppos)
-{
-	pauerchar_t ccp = (pauerchar_t) file->private_data;
-        pauerswald_t cp = NULL;
-        pauerbuf_t bp;
-        unsigned long flags;
-	int ret;
-	wait_queue_t wait;
-
-        dbg ("auerchar_write %d bytes", len);
-
-	/* Error checking */
-	if (!ccp)
-		return -EIO;
-        if (*ppos)
-		return -ESPIPE;
-        if (len == 0)
-                return 0;
-
-write_again:
-	/* get the mutex */
-	if (down_interruptible (&ccp->mutex))
-		return -ERESTARTSYS;
-
-	/* Can we expect to write something? */
-	if (ccp->scontext.id == AUH_UNASSIGNED) {
-		up (&ccp->mutex);
-                return -EIO;
-	}
-
-	cp = ccp->auerdev;
-	if (!cp) {
-		up (&ccp->mutex);
-		return -ERESTARTSYS;
-	}
-	if (down_interruptible (&cp->mutex)) {
-		up (&ccp->mutex);
-		return -ERESTARTSYS;
-	}
-	if (!cp->usbdev) {
-		up (&cp->mutex);
-		up (&ccp->mutex);
-		return -EIO;
-	}
-	/* Prepare for sleep */
-	init_waitqueue_entry (&wait, current);
-	set_current_state (TASK_INTERRUPTIBLE);
-	add_wait_queue (&cp->bufferwait, &wait);
-
-	/* Try to get a buffer from the device pool.
-	   We can't use a buffer from ccp->bufctl because the write
-	   command will last beond a release() */
-	bp = NULL;
-	spin_lock_irqsave (&cp->bufctl.lock, flags);
-        if (!list_empty (&cp->bufctl.free_buff_list)) {
-                /* yes: get the entry */
-                struct list_head *tmp = cp->bufctl.free_buff_list.next;
-                list_del (tmp);
-                bp = list_entry (tmp, auerbuf_t, buff_list);
-        }
-        spin_unlock_irqrestore (&cp->bufctl.lock, flags);
-
-	/* are there any buffers left? */
-	if (!bp) {
-		up (&cp->mutex);
-		up (&ccp->mutex);
-
-		/* NONBLOCK: don't wait */
-		if (file->f_flags & O_NONBLOCK) {
-			set_current_state (TASK_RUNNING);
-			remove_wait_queue (&cp->bufferwait, &wait);
-			return -EAGAIN;
-		}
-
-		/* BLOCKING: wait */
-		schedule();
-		remove_wait_queue (&cp->bufferwait, &wait);
-		if (signal_pending (current)) {
-			/* waked up by a signal */
-			return -ERESTARTSYS;
-		}
-		goto write_again;
-	} else {
-		set_current_state (TASK_RUNNING);
-		remove_wait_queue (&cp->bufferwait, &wait);
-	}
-
-	/* protect against too big write requests */
-	if (len > cp->maxControlLength) len = cp->maxControlLength;
-
-	/* Fill the buffer */
-	if (copy_from_user ( bp->bufp+AUH_SIZE, buf, len)) {
-		dbg ("copy_from_user failed");
-		auerbuf_releasebuf (bp);
-		/* Wake up all processes waiting for a buffer */
-		wake_up (&cp->bufferwait);
-		up (&cp->mutex);
-		up (&ccp->mutex);
-		return -EIO;
-	}
-
-	/* set the header byte */
-        *(bp->bufp) = ccp->scontext.id | AUH_DIRECT | AUH_UNSPLIT;
-
-	/* Set the transfer Parameters */
-	bp->len = len+AUH_SIZE;
-        bp->dr->bRequestType = AUT_WREQ;
-	bp->dr->bRequest     = AUV_WBLOCK;
-	bp->dr->wValue       = cpu_to_le16 (0);
-	bp->dr->wIndex       = cpu_to_le16 (ccp->scontext.id | AUH_DIRECT | AUH_UNSPLIT);
-	bp->dr->wLength      = cpu_to_le16 (len+AUH_SIZE);
-	FILL_CONTROL_URB (bp->urbp, cp->usbdev, usb_sndctrlpipe (cp->usbdev, 0),
-                   (unsigned char*)bp->dr, bp->bufp, len+AUH_SIZE,
-		    auerchar_ctrlwrite_complete, bp);
-	/* up we go */
-	ret = auerchain_submit_urb (&cp->controlchain, bp->urbp);
-	up (&cp->mutex);
-	if (ret) {
-		dbg ("auerchar_write: nonzero result of auerchain_submit_urb %d", ret);
-		auerbuf_releasebuf (bp);
-		/* Wake up all processes waiting for a buffer */
-		wake_up (&cp->bufferwait);
-		up (&ccp->mutex);
-		return -EIO;
-	}
-	else {
-		dbg ("auerchar_write: Write OK");
-		up (&ccp->mutex);
-		return len;
-	}
-}
-
-
-/* Close a character device */
-static int auerchar_release (struct inode *inode, struct file *file)
-{
-	pauerchar_t ccp = (pauerchar_t) file->private_data;
-	pauerswald_t cp;
-	dbg("release");
-
-	/* get the mutexes */
-	if (down_interruptible (&ccp->mutex)) {
-		return -ERESTARTSYS;
-	}
-	cp = ccp->auerdev;
-	if (cp) {
-		if (down_interruptible (&cp->mutex)) {
-			up (&ccp->mutex);
-			return -ERESTARTSYS;
-		}
-		/* remove an open service */
-		auerswald_removeservice (cp, &ccp->scontext);
-		/* detach from device */
-		if ((--cp->open_count <= 0) && (cp->usbdev == NULL)) {
-			/* usb device waits for removal */
-			up (&cp->mutex);
-			auerswald_delete (cp);
-		} else {
-			up (&cp->mutex);
-		}
-		cp = NULL;
-		ccp->auerdev = NULL;
-	}
-	up (&ccp->mutex);
-	auerchar_delete (ccp);
-
-	return 0;
-}
-
-
-/*----------------------------------------------------------------------*/
-/* File operation structure                                             */
-static struct file_operations auerswald_fops =
-{
-	owner:		THIS_MODULE,
-	llseek:		auerchar_llseek,
-	read:		auerchar_read,
-	write:          auerchar_write,
-	ioctl:		auerchar_ioctl,
-	open:		auerchar_open,
-	release:	auerchar_release,
-};
-
-
-/* --------------------------------------------------------------------- */
-/* Special USB driver functions                                          */
-
-/* Probe if this driver wants to serve an USB device
-
-   This entry point is called whenever a new device is attached to the bus.
-   Then the device driver has to create a new instance of its internal data
-   structures for the new device.
-
-   The  dev argument specifies the device context, which contains pointers
-   to all USB descriptors. The  interface argument specifies the interface
-   number. If a USB driver wants to bind itself to a particular device and
-   interface it has to return a pointer. This pointer normally references
-   the device driver's context structure.
-
-   Probing normally is done by checking the vendor and product identifications
-   or the class and subclass definitions. If they match the interface number
-   is compared with the ones supported by the driver. When probing is done
-   class based it might be necessary to parse some more USB descriptors because
-   the device properties can differ in a wide range.
-*/
-static void *auerswald_probe (struct usb_device *usbdev, unsigned int ifnum,
-			      const struct usb_device_id *id)
-{
-	pauerswald_t cp = NULL;
-	DECLARE_WAIT_QUEUE_HEAD (wqh);
-	unsigned int dtindex;
-	unsigned int u = 0;
-	char *pbuf;
-	int ret;
-
-	dbg ("probe: vendor id 0x%x, device id 0x%x ifnum:%d",
-	     usbdev->descriptor.idVendor, usbdev->descriptor.idProduct, ifnum);
-
-	/* See if the device offered us matches that we can accept */
-	if (usbdev->descriptor.idVendor != ID_AUERSWALD) return NULL;
-
-        /* we use only the first -and only- interface */
-        if (ifnum != 0) return NULL;
-
-	/* prevent module unloading while sleeping */
-	MOD_INC_USE_COUNT;
-
-	/* allocate memory for our device and intialize it */
-	cp = kmalloc (sizeof(auerswald_t), GFP_KERNEL);
-	if (cp == NULL) {
-		err ("out of memory");
-		goto pfail;
-	}
-
-	/* Initialize device descriptor */
-	memset (cp, 0, sizeof(auerswald_t));
-	init_MUTEX (&cp->mutex);
-	cp->usbdev = usbdev;
-	auerchain_init (&cp->controlchain);
-        auerbuf_init (&cp->bufctl);
-	init_waitqueue_head (&cp->bufferwait);
-
-	/* find a free slot in the device table */
-	down (&dev_table_mutex);
-	for (dtindex = 0; dtindex < AUER_MAX_DEVICES; ++dtindex) {
-		if (dev_table[dtindex] == NULL)
-			break;
-	}
-	if ( dtindex >= AUER_MAX_DEVICES) {
-		err ("more than %d devices plugged in, can not handle this device", AUER_MAX_DEVICES);
-		up (&dev_table_mutex);
-		goto pfail;
-	}
-
-	/* Give the device a name */
-	sprintf (cp->name, AU_PREFIX "%d", dtindex);
-
-	/* Store the index */
-	cp->dtindex = dtindex;
-	dev_table[dtindex] = cp;
-	up (&dev_table_mutex);
-
-	/* initialize the devfs node for this device and register it */
-	cp->devfs = devfs_register (usb_devfs_handle, cp->name,
-				    DEVFS_FL_DEFAULT, USB_MAJOR,
-				    AUER_MINOR_BASE + dtindex,
-				    S_IFCHR | S_IRUGO | S_IWUGO,
-				    &auerswald_fops, NULL);
-
-	/* Get the usb version of the device */
-	cp->version = cp->usbdev->descriptor.bcdDevice;
-	dbg ("Version is %X", cp->version);
-
-	/* allow some time to settle the device */
-	sleep_on_timeout (&wqh, HZ / 3 );
-
-	/* Try to get a suitable textual description of the device */
-	/* Device name:*/
-	ret = usb_string( cp->usbdev, AUSI_DEVICE, cp->dev_desc, AUSI_DLEN-1);
-	if (ret >= 0) {
-		u += ret;
-		/* Append Serial Number */
-		memcpy(&cp->dev_desc[u], ",Ser# ", 6);
-		u += 6;
-		ret = usb_string( cp->usbdev, AUSI_SERIALNR, &cp->dev_desc[u], AUSI_DLEN-u-1);
-		if (ret >= 0) {
-			u += ret;
-			/* Append subscriber number */
-			memcpy(&cp->dev_desc[u], ", ", 2);
-			u += 2;
-			ret = usb_string( cp->usbdev, AUSI_MSN, &cp->dev_desc[u], AUSI_DLEN-u-1);
-			if (ret >= 0) {
-				u += ret;
-			}
-		}
-	}
-	cp->dev_desc[u] = '\0';
-	info("device is a %s", cp->dev_desc);
-
-        /* get the maximum allowed control transfer length */
-        pbuf = (char *) kmalloc (2, GFP_KERNEL);    /* use an allocated buffer because of urb target */
-        if (!pbuf) {
-		err( "out of memory");
-		goto pfail;
-	}
-        ret = usb_control_msg(cp->usbdev,           /* pointer to device */
-                usb_rcvctrlpipe( cp->usbdev, 0 ),   /* pipe to control endpoint */
-                AUV_GETINFO,                        /* USB message request value */
-                AUT_RREQ,                           /* USB message request type value */
-                0,                                  /* USB message value */
-                AUDI_MBCTRANS,                      /* USB message index value */
-                pbuf,                               /* pointer to the receive buffer */
-                2,                                  /* length of the buffer */
-                HZ * 2);                            /* time to wait for the message to complete before timing out */
-        if (ret == 2) {
-	        cp->maxControlLength = le16_to_cpup(pbuf);
-                kfree(pbuf);
-                dbg("setup: max. allowed control transfersize is %d bytes", cp->maxControlLength);
-        } else {
-                kfree(pbuf);
-                err("setup: getting max. allowed control transfer length failed with error %d", ret);
-		goto pfail;
-        }
-
-	/* allocate a chain for the control messages */
-        if (auerchain_setup (&cp->controlchain, AUCH_ELEMENTS)) {
-		err ("out of memory");
-		goto pfail;
-	}
-
-        /* allocate buffers for control messages */
-	if (auerbuf_setup (&cp->bufctl, AU_RBUFFERS, cp->maxControlLength+AUH_SIZE)) {
-		err ("out of memory");
-		goto pfail;
-	}
-
-	/* start the interrupt endpoint */
-	if (auerswald_int_open (cp)) {
-		err ("int endpoint failed");
-		goto pfail;
-	}
-
-	/* all OK */
-	return cp;
-
-	/* Error exit: clean up the memory */
-pfail:	auerswald_delete (cp);
-	MOD_DEC_USE_COUNT;
-	return NULL;
-}
-
-
-/* Disconnect driver from a served device
-
-   This function is called whenever a device which was served by this driver
-   is disconnected.
-
-   The argument  dev specifies the device context and the  driver_context
-   returns a pointer to the previously registered  driver_context of the
-   probe function. After returning from the disconnect function the USB
-   framework completly deallocates all data structures associated with
-   this device. So especially the usb_device structure must not be used
-   any longer by the usb driver.
-*/
-static void auerswald_disconnect (struct usb_device *usbdev, void *driver_context)
-{
-	pauerswald_t cp = (pauerswald_t) driver_context;
-	unsigned int u;
-
-	down (&cp->mutex);
-	info ("device /dev/usb/%s now disconnecting", cp->name);
-
-	/* remove from device table */
-	/* Nobody can open() this device any more */
-	down (&dev_table_mutex);
-	dev_table[cp->dtindex] = NULL;
-	up (&dev_table_mutex);
-
-	/* remove our devfs node */
-	/* Nobody can see this device any more */
-	devfs_unregister (cp->devfs);
-
-	/* Stop the interrupt endpoint */
-	auerswald_int_release (cp);
-
-	/* remove the control chain allocated in auerswald_probe
-	   This has the benefit of
-	   a) all pending (a)synchronous urbs are unlinked
-	   b) all buffers dealing with urbs are reclaimed
-	*/
-	auerchain_free (&cp->controlchain);
-
-	if (cp->open_count == 0) {
-		/* nobody is using this device. So we can clean up now */
-		up (&cp->mutex);/* up() is possible here because no other task
-				   can open the device (see above). I don't want
-				   to kfree() a locked mutex. */
-		auerswald_delete (cp);
-	} else {
-		/* device is used. Remove the pointer to the
-		   usb device (it's not valid any more). The last
-		   release() will do the clean up */
-		cp->usbdev = NULL;
-		up (&cp->mutex);
-		/* Terminate waiting writers */
-		wake_up (&cp->bufferwait);
-		/* Inform all waiting readers */
-		for ( u = 0; u < AUH_TYPESIZE; u++) {
-			pauerscon_t scp = cp->services[u];
-			if (scp) scp->disconnect( scp);
-		}
-	}
-
-	/* The device releases this module */
-	MOD_DEC_USE_COUNT;
-}
-
-/* Descriptor for the devices which are served by this driver.
-   NOTE: this struct is parsed by the usbmanager install scripts.
-         Don't change without caution!
-*/
-static struct usb_device_id auerswald_ids [] = {
-	{ USB_DEVICE (ID_AUERSWALD, 0x00C0) },          /* COMpact 2104 USB */
-	{ USB_DEVICE (ID_AUERSWALD, 0x00DB) },          /* COMpact 4410/2206 USB */
-	{ USB_DEVICE (ID_AUERSWALD, 0x00F1) },          /* Comfort 2000 System Telephone */
-	{ USB_DEVICE (ID_AUERSWALD, 0x00F2) },          /* Comfort 1200 System Telephone */
-        { }			                        /* Terminating entry */
-};
-
-/* Standard module device table */
-MODULE_DEVICE_TABLE (usb, auerswald_ids);
-
-/* Standard usb driver struct */
-static struct usb_driver auerswald_driver = {
-	name:		"auerswald",
-	probe:		auerswald_probe,
-	disconnect:	auerswald_disconnect,
-	fops:		&auerswald_fops,
-	minor:		AUER_MINOR_BASE,
-	id_table:	auerswald_ids,
-};
-
-
-/* --------------------------------------------------------------------- */
-/* Module loading/unloading                                              */
-
-/* Driver initialisation. Called after module loading.
-   NOTE: there is no concurrency at _init
-*/
-static int __init auerswald_init (void)
-{
-	int result;
-	dbg ("init");
-
-	/* initialize the device table */
-	memset (&dev_table, 0, sizeof(dev_table));
-	init_MUTEX (&dev_table_mutex);
-
-	/* register driver at the USB subsystem */
-	result = usb_register (&auerswald_driver);
-	if (result < 0) {
-		err ("driver could not be registered");
-		return -1;
-	}
-	return 0;
-}
-
-/* Driver deinit. Called before module removal.
-   NOTE: there is no concurrency at _cleanup
-*/
-static void __exit auerswald_cleanup (void)
-{
-	dbg ("cleanup");
-	usb_deregister (&auerswald_driver);
-}
-
-/* --------------------------------------------------------------------- */
-/* Linux device driver module description                                */
-
-MODULE_AUTHOR (DRIVER_AUTHOR);
-MODULE_DESCRIPTION (DRIVER_DESC);
-
-module_init (auerswald_init);
-module_exit (auerswald_cleanup);
-
-/* --------------------------------------------------------------------- */
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/devio.c linux-2.4.21-pre6/drivers/usb/devio.c
--- linux-2.4.20/drivers/usb/devio.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/devio.c	2003-03-26 23:49:39.000000000 +0000
@@ -50,6 +50,7 @@
         struct dev_state *ps;
 	struct task_struct *task;
 	unsigned int signr;
+	unsigned int intf;
 	void *userbuffer;
         void *userurb;
         struct urb urb;
@@ -204,8 +205,7 @@
         unsigned long flags;
         
         spin_lock_irqsave(&ps->lock, flags);
-        list_del(&as->asynclist);
-        INIT_LIST_HEAD(&as->asynclist);
+        list_del_init(&as->asynclist);
         spin_unlock_irqrestore(&ps->lock, flags);
 }
 
@@ -217,8 +217,7 @@
         spin_lock_irqsave(&ps->lock, flags);
         if (!list_empty(&ps->async_completed)) {
                 as = list_entry(ps->async_completed.next, struct async, asynclist);
-                list_del(&as->asynclist);
-                INIT_LIST_HEAD(&as->asynclist);
+                list_del_init(&as->asynclist);
         }
         spin_unlock_irqrestore(&ps->lock, flags);
         return as;
@@ -228,19 +227,14 @@
 {
         unsigned long flags;
         struct async *as;
-        struct list_head *p;
 
         spin_lock_irqsave(&ps->lock, flags);
-        for (p = ps->async_pending.next; p != &ps->async_pending; ) {
-                as = list_entry(p, struct async, asynclist);
-                p = p->next;
-                if (as->userurb != userurb)
-                        continue;
-                list_del(&as->asynclist);
-                INIT_LIST_HEAD(&as->asynclist);
-                spin_unlock_irqrestore(&ps->lock, flags);
-                return as;
-        }
+	list_for_each_entry(as, &ps->async_pending, asynclist)
+		if (as->userurb == userurb) {
+			list_del_init(&as->asynclist);
+			spin_unlock_irqrestore(&ps->lock, flags);
+			return as;
+		}
         spin_unlock_irqrestore(&ps->lock, flags);
         return NULL;
 }
@@ -252,8 +246,7 @@
 	struct siginfo sinfo;
 
         spin_lock(&ps->lock);
-        list_del(&as->asynclist);
-        list_add_tail(&as->asynclist, &ps->async_completed);
+        list_move_tail(&as->asynclist, &ps->async_completed);
         spin_unlock(&ps->lock);
         wake_up(&ps->wait);
 	if (as->signr) {
@@ -265,24 +258,42 @@
 	}
 }
 
-static void destroy_all_async(struct dev_state *ps)
+static void destroy_async (struct dev_state *ps, struct list_head *list)
 {
-        struct async *as;
-        unsigned long flags;
+	struct async *as;
+	unsigned long flags;
 
-        spin_lock_irqsave(&ps->lock, flags);
-        while (!list_empty(&ps->async_pending)) {
-                as = list_entry(ps->async_pending.next, struct async, asynclist);
-                list_del(&as->asynclist);
-                INIT_LIST_HEAD(&as->asynclist);
-                spin_unlock_irqrestore(&ps->lock, flags);
-                /* usb_unlink_urb calls the completion handler with status == USB_ST_URB_KILLED */
-                usb_unlink_urb(&as->urb);
-                spin_lock_irqsave(&ps->lock, flags);
-        }
-        spin_unlock_irqrestore(&ps->lock, flags);
-        while ((as = async_getcompleted(ps)))
-                free_async(as);
+	spin_lock_irqsave(&ps->lock, flags);
+	while (!list_empty(list)) {
+		as = list_entry(list->next, struct async, asynclist);
+		list_del_init(&as->asynclist);
+		spin_unlock_irqrestore(&ps->lock, flags);
+		/* usb_unlink_urb calls the completion handler with status == USB_ST_URB_KILLED */
+		usb_unlink_urb(&as->urb);
+		spin_lock_irqsave(&ps->lock, flags);
+	}
+	spin_unlock_irqrestore(&ps->lock, flags);
+	while ((as = async_getcompleted(ps)))
+		free_async(as);
+}
+
+static void destroy_async_on_interface (struct dev_state *ps, unsigned int intf)
+{
+	struct list_head *p, *q, hitlist;
+	unsigned long flags;
+
+	INIT_LIST_HEAD(&hitlist);
+	spin_lock_irqsave(&ps->lock, flags);
+	list_for_each_safe(p, q, &ps->async_pending)
+		if (intf == list_entry(p, struct async, asynclist)->intf)
+			list_move_tail(p, &hitlist);
+	spin_unlock_irqrestore(&ps->lock, flags);
+	destroy_async(ps, &hitlist);
+}
+
+static inline void destroy_all_async(struct dev_state *ps)
+{
+	destroy_async(ps, &ps->async_pending);
 }
 
 /*
@@ -519,8 +530,7 @@
 	unsigned int i;
 
 	lock_kernel();
-	list_del(&ps->list);
-	INIT_LIST_HEAD(&ps->list);
+	list_del_init(&ps->list);
 	if (ps->dev) {
 		for (i = 0; ps->ifclaimed && i < 8*sizeof(ps->ifclaimed); i++)
 			if (test_bit(i, &ps->ifclaimed))
@@ -775,6 +785,7 @@
 	struct usb_ctrlrequest *dr = NULL;
 	unsigned int u, totlen, isofrmlen;
 	int ret;
+	int intf = -1;
 
 	if (copy_from_user(&uurb, arg, sizeof(uurb)))
 		return -EFAULT;
@@ -786,9 +797,9 @@
 	if (uurb.signr != 0 && (uurb.signr < SIGRTMIN || uurb.signr > SIGRTMAX))
 		return -EINVAL;
 	if (!(uurb.type == USBDEVFS_URB_TYPE_CONTROL && (uurb.endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) {
-		if ((ret = findintfep(ps->dev, uurb.endpoint)) < 0)
-			return ret;
-		if ((ret = checkintf(ps, ret)))
+		if ((intf = findintfep(ps->dev, uurb.endpoint)) < 0)
+			return intf;
+		if ((ret = checkintf(ps, intf)))
 			return ret;
 	}
 	switch(uurb.type) {
@@ -909,6 +920,7 @@
 	else
 		as->userbuffer = NULL;
 	as->signr = uurb.signr;
+	as->intf = intf;
 	as->task = current;
 	if (!(uurb.endpoint & USB_DIR_IN)) {
 		if (copy_from_user(as->urb.transfer_buffer, uurb.buffer, as->urb.transfer_buffer_length)) {
@@ -1054,7 +1066,10 @@
 		return -EFAULT;
 	if ((ret = findintfif(ps->dev, intf)) < 0)
 		return ret;
-	return releaseintf(ps, intf);
+	if ((ret = releaseintf(ps, intf)) < 0)
+		return ret;
+	destroy_async_on_interface (ps, intf);
+	return 0;
 }
 
 static int proc_ioctl (struct dev_state *ps, void *arg)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/hc_sl811.c linux-2.4.21-pre6/drivers/usb/hc_sl811.c
--- linux-2.4.20/drivers/usb/hc_sl811.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/hc_sl811.c	2003-03-26 23:49:31.000000000 +0000
@@ -28,7 +28,7 @@
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/sched.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/smp_lock.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/hcd/Config.in linux-2.4.21-pre6/drivers/usb/hcd/Config.in
--- linux-2.4.20/drivers/usb/hcd/Config.in	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/hcd/Config.in	1970-01-01 00:00:00.000000000 +0000
@@ -1,7 +0,0 @@
-#
-# USB Host Controller Drivers
-#
-dep_tristate '  EHCI HCD (USB 2.0) support (EXPERIMENTAL)' CONFIG_USB_EHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
-# dep_tristate '  OHCI HCD support (EXPERIMENTAL)' CONFIG_USB_OHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
-# dep_tristate '  UHCI HCD (most Intel and VIA) support (EXPERIMENTAL)' CONFIG_USB_UHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/hcd/Makefile linux-2.4.21-pre6/drivers/usb/hcd/Makefile
--- linux-2.4.20/drivers/usb/hcd/Makefile	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/hcd/Makefile	1970-01-01 00:00:00.000000000 +0000
@@ -1,27 +0,0 @@
-#
-# Makefile for USB Host Controller Driver
-# framework and drivers
-#
-
-O_TARGET	:=
-
-obj-$(CONFIG_USB_EHCI_HCD)			+= ehci-hcd.o
-# obj-$(CONFIG_USB_OHCI_HCD)			+= ohci-hcd.o
-# obj-$(CONFIG_USB_UHCI_HCD)			+= uhci-hcd.o
-
-# Extract lists of the multi-part drivers.
-# The 'int-*' lists are the intermediate files used to build the multi's.
-multi-y		:= $(filter $(list-multi), $(obj-y))
-multi-m		:= $(filter $(list-multi), $(obj-m))
-int-y		:= $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
-int-m		:= $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
-
-# Take multi-part drivers out of obj-y and put components in.
-obj-y		:= $(filter-out $(list-multi), $(obj-y)) $(int-y)
-
-# Translate to Rules.make lists.
-OX_OBJS		:= $(obj-y)
-MX_OBJS		:= $(obj-m)
-MIX_OBJS	:= $(int-m)
-
-include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/hcd/ehci-dbg.c linux-2.4.21-pre6/drivers/usb/hcd/ehci-dbg.c
--- linux-2.4.20/drivers/usb/hcd/ehci-dbg.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/hcd/ehci-dbg.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,179 +0,0 @@
-/*
- * Copyright (c) 2001 by David Brownell
- * 
- * 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 file is part of ehci-hcd.c */
-
-#ifdef EHCI_VERBOSE_DEBUG
-#	define vdbg dbg
-#else
-	static inline void vdbg (char *fmt, ...) { }
-#endif
-
-#ifdef	DEBUG
-
-/* check the values in the HCSPARAMS register - host controller structural parameters */
-/* see EHCI 0.95 Spec, Table 2-4 for each value */
-static void dbg_hcs_params (struct ehci_hcd *ehci, char *label)
-{
-	u32	params = readl (&ehci->caps->hcs_params);
-
-	dbg ("%s hcs_params 0x%x dbg=%d%s cc=%d pcc=%d%s%s ports=%d",
-		label, params,
-		HCS_DEBUG_PORT (params),
-		HCS_INDICATOR (params) ? " ind" : "",
-		HCS_N_CC (params),
-		HCS_N_PCC (params),
-	        HCS_PORTROUTED (params) ? "" : " ordered",
-		HCS_PPC (params) ? "" : " !ppc",
-		HCS_N_PORTS (params)
-		);
-	/* Port routing, per EHCI 0.95 Spec, Section 2.2.5 */
-	if (HCS_PORTROUTED (params)) {
-		int i;
-		char buf [46], tmp [7], byte;
-
-		buf[0] = 0;
-		for (i = 0; i < HCS_N_PORTS (params); i++) {
-			byte = readb (&ehci->caps->portroute[(i>>1)]);
-			sprintf(tmp, "%d ", 
-				((i & 0x1) ? ((byte)&0xf) : ((byte>>4)&0xf)));
-			strcat(buf, tmp);
-		}
-		dbg ("%s: %s portroute %s", 
-			ehci->hcd.bus_name, label,
-			buf);
-	}
-}
-#else
-
-static inline void dbg_hcs_params (struct ehci_hcd *ehci, char *label) {}
-
-#endif
-
-#ifdef	DEBUG
-
-/* check the values in the HCCPARAMS register - host controller capability parameters */
-/* see EHCI 0.95 Spec, Table 2-5 for each value */
-static void dbg_hcc_params (struct ehci_hcd *ehci, char *label)
-{
-	u32	params = readl (&ehci->caps->hcc_params);
-
-	if (HCC_EXT_CAPS (params)) {
-		// EHCI 0.96 ... could interpret these (legacy?)
-		dbg ("%s extended capabilities at pci %d",
-			label, HCC_EXT_CAPS (params));
-	}
-	if (HCC_ISOC_CACHE (params)) {
-		dbg ("%s hcc_params 0x%04x caching frame %s%s%s",
-		     label, params,
-		     HCC_PGM_FRAMELISTLEN (params) ? "256/512/1024" : "1024",
-		     HCC_CANPARK (params) ? " park" : "",
-		     HCC_64BIT_ADDR (params) ? " 64 bit addr" : "");
-	} else {
-		dbg ("%s hcc_params 0x%04x caching %d uframes %s%s%s",
-		     label,
-		     params,
-		     HCC_ISOC_THRES (params),
-		     HCC_PGM_FRAMELISTLEN (params) ? "256/512/1024" : "1024",
-		     HCC_CANPARK (params) ? " park" : "",
-		     HCC_64BIT_ADDR (params) ? " 64 bit addr" : "");
-	}
-}
-#else
-
-static inline void dbg_hcc_params (struct ehci_hcd *ehci, char *label) {}
-
-#endif
-
-#ifdef	DEBUG
-
-#if 0
-static void dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
-{
-	dbg ("%s %p info1 %x info2 %x hw_curr %x qtd_next %x", label,
-		qh, qh->hw_info1, qh->hw_info2,
-		qh->hw_current, qh->hw_qtd_next);
-	dbg ("  alt+errs= %x, token= %x, page0= %x, page1= %x",
-		qh->hw_alt_next, qh->hw_token,
-		qh->hw_buf [0], qh->hw_buf [1]);
-	if (qh->hw_buf [2]) {
-		dbg ("  page2= %x, page3= %x, page4= %x",
-			qh->hw_buf [2], qh->hw_buf [3],
-			qh->hw_buf [4]);
-	}
-}
-#endif
-
-static const char *const fls_strings [] =
-    { "1024", "512", "256", "??" };
-
-#else
-#if 0
-static inline void dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh) {}
-#endif
-#endif	/* DEBUG */
-
-/* functions have the "wrong" filename when they're output... */
-
-#define dbg_status(ehci, label, status) \
-	dbg ("%s status 0x%x%s%s%s%s%s%s%s%s%s%s", \
-		label, status, \
-		(status & STS_ASS) ? " Async" : "", \
-		(status & STS_PSS) ? " Periodic" : "", \
-		(status & STS_RECL) ? " Recl" : "", \
-		(status & STS_HALT) ? " Halt" : "", \
-		(status & STS_IAA) ? " IAA" : "", \
-		(status & STS_FATAL) ? " FATAL" : "", \
-		(status & STS_FLR) ? " FLR" : "", \
-		(status & STS_PCD) ? " PCD" : "", \
-		(status & STS_ERR) ? " ERR" : "", \
-		(status & STS_INT) ? " INT" : "" \
-		)
-
-#define dbg_cmd(ehci, label, command) \
-	dbg ("%s %x cmd %s=%d ithresh=%d%s%s%s%s period=%s%s %s", \
-		label, command, \
-		(command & CMD_PARK) ? "park" : "(park)", \
-		CMD_PARK_CNT (command), \
-		(command >> 16) & 0x3f, \
-		(command & CMD_LRESET) ? " LReset" : "", \
-		(command & CMD_IAAD) ? " IAAD" : "", \
-		(command & CMD_ASE) ? " Async" : "", \
-		(command & CMD_PSE) ? " Periodic" : "", \
-		fls_strings [(command >> 2) & 0x3], \
-		(command & CMD_RESET) ? " Reset" : "", \
-		(command & CMD_RUN) ? "RUN" : "HALT" \
-		)
-
-#define dbg_port(hcd, label, port, status) \
-	dbg ("%s port %d status 0x%x%s%s speed=%d%s%s%s%s%s%s%s%s%s", \
-		label, port, status, \
-		(status & PORT_OWNER) ? " OWNER" : "", \
-		(status & PORT_POWER) ? " POWER" : "", \
-		(status >> 10) & 3, \
-		(status & PORT_RESET) ? " RESET" : "", \
-		(status & PORT_SUSPEND) ? " SUSPEND" : "", \
-		(status & PORT_RESUME) ? " RESUME" : "", \
-		(status & PORT_OCC) ? " OCC" : "", \
-		(status & PORT_OC) ? " OC" : "", \
-		(status & PORT_PEC) ? " PEC" : "", \
-		(status & PORT_PE) ? " PE" : "", \
-		(status & PORT_CSC) ? " CSC" : "", \
-		(status & PORT_CONNECT) ? " CONNECT" : "" \
-	    )
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/hcd/ehci-hcd.c linux-2.4.21-pre6/drivers/usb/hcd/ehci-hcd.c
--- linux-2.4.20/drivers/usb/hcd/ehci-hcd.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/hcd/ehci-hcd.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,762 +0,0 @@
-/*
- * Copyright (c) 2000-2002 by David Brownell
- * 
- * 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/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/smp_lock.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
-
-#ifdef CONFIG_USB_DEBUG
-	#define DEBUG
-#else
-	#undef DEBUG
-#endif
-
-#include <linux/usb.h>
-#include "../hcd.h"
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/unaligned.h>
-
-//#undef KERN_DEBUG
-//#define KERN_DEBUG ""
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * EHCI hc_driver implementation ... experimental, incomplete.
- * Based on the final 1.0 register interface specification.
- *
- * There are lots of things to help out with here ... notably
- * everything "periodic", and of course testing with all sorts
- * of usb 2.0 devices and configurations.
- *
- * USB 2.0 shows up in upcoming www.pcmcia.org technology.
- * First was PCMCIA, like ISA; then CardBus, which is PCI.
- * Next comes "CardBay", using USB 2.0 signals.
- *
- * Contains additional contributions by:
- *	Brad Hards
- *	Rory Bolt
- *	...
- *
- * HISTORY:
- *
- * 2002-05-07	Some error path cleanups to report better errors; wmb();
- *	use non-CVS version id; better iso bandwidth claim.
- * 2002-04-19	Control/bulk/interrupt submit no longer uses giveback() on
- *	errors in submit path.  Bugfixes to interrupt scheduling/processing.
- * 2002-03-05	Initial high-speed ISO support; reduce ITD memory; shift
- *	more checking to generic hcd framework (db).  Make it work with
- *	Philips EHCI; reduce PCI traffic; shorten IRQ path (Rory Bolt).
- * 2002-01-14	Minor cleanup; version synch.
- * 2002-01-08	Fix roothub handoff of FS/LS to companion controllers.
- * 2002-01-04	Control/Bulk queuing behaves.
- *
- * 2001-12-12	Initial patch version for Linux 2.5.1 kernel.
- * 2001-June	Works with usb-storage and NEC EHCI on 2.4
- */
-
-#define DRIVER_VERSION "2002-May-07"
-#define DRIVER_AUTHOR "David Brownell"
-#define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
-
-
-// #define EHCI_VERBOSE_DEBUG
-// #define have_split_iso
-
-/* magic numbers that can affect system performance */
-#define	EHCI_TUNE_CERR		3	/* 0-3 qtd retries; 0 == don't stop */
-#define	EHCI_TUNE_RL_HS		0	/* nak throttle; see 4.9 */
-#define	EHCI_TUNE_RL_TT		0
-#define	EHCI_TUNE_MULT_HS	1	/* 1-3 transactions/uframe; 4.10.3 */
-#define	EHCI_TUNE_MULT_TT	1
-
-/* Initial IRQ latency:  lower than default */
-static int log2_irq_thresh = 0;		// 0 to 6
-MODULE_PARM (log2_irq_thresh, "i");
-MODULE_PARM_DESC (log2_irq_thresh, "log2 IRQ latency, 1-64 microframes");
-
-#define	INTR_MASK (STS_IAA | STS_FATAL | STS_ERR | STS_INT)
-
-/*-------------------------------------------------------------------------*/
-
-#include "ehci.h"
-#include "ehci-dbg.c"
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * hc states include: unknown, halted, ready, running
- * transitional states are messy just now
- * trying to avoid "running" unless urbs are active
- * a "ready" hc can be finishing prefetched work
- */
-
-/* halt a non-running controller */
-static void ehci_reset (struct ehci_hcd *ehci)
-{
-	u32	command = readl (&ehci->regs->command);
-
-	command |= CMD_RESET;
-	dbg_cmd (ehci, "reset", command);
-	writel (command, &ehci->regs->command);
-	while (readl (&ehci->regs->command) & CMD_RESET)
-		continue;
-	ehci->hcd.state = USB_STATE_HALT;
-}
-
-/* idle the controller (from running) */
-static void ehci_ready (struct ehci_hcd *ehci)
-{
-	u32	command;
-
-#ifdef DEBUG
-	if (!HCD_IS_RUNNING (ehci->hcd.state))
-		BUG ();
-#endif
-
-	while (!(readl (&ehci->regs->status) & (STS_ASS | STS_PSS)))
-		udelay (100);
-	command = readl (&ehci->regs->command);
-	command &= ~(CMD_ASE | CMD_IAAD | CMD_PSE);
-	writel (command, &ehci->regs->command);
-
-	// hardware can take 16 microframes to turn off ...
-	ehci->hcd.state = USB_STATE_READY;
-}
-
-/*-------------------------------------------------------------------------*/
-
-#include "ehci-hub.c"
-#include "ehci-mem.c"
-#include "ehci-q.c"
-#include "ehci-sched.c"
-
-/*-------------------------------------------------------------------------*/
-
-static void ehci_tasklet (unsigned long param);
-
-/* called by khubd or root hub init threads */
-
-static int ehci_start (struct usb_hcd *hcd)
-{
-	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
-	u32			temp;
-	struct usb_device	*udev;
-	int			retval;
-	u32			hcc_params;
-	u8                      tempbyte;
-
-	// FIXME:  given EHCI 0.96 or later, and a controller with
-	// the USBLEGSUP/USBLEGCTLSTS extended capability, make sure
-	// the BIOS doesn't still own this controller.
-
-	spin_lock_init (&ehci->lock);
-
-	ehci->caps = (struct ehci_caps *) hcd->regs;
-	ehci->regs = (struct ehci_regs *) (hcd->regs + ehci->caps->length);
-	dbg_hcs_params (ehci, "ehci_start");
-	dbg_hcc_params (ehci, "ehci_start");
-
-	/* cache this readonly data; minimize PCI reads */
-	ehci->hcs_params = readl (&ehci->caps->hcs_params);
-
-	/*
-	 * hw default: 1K periodic list heads, one per frame.
-	 * periodic_size can shrink by USBCMD update if hcc_params allows.
-	 */
-	ehci->periodic_size = DEFAULT_I_TDPS;
-	if ((retval = ehci_mem_init (ehci, SLAB_KERNEL)) < 0)
-		return retval;
-	hcc_params = readl (&ehci->caps->hcc_params);
-
-	/* controllers may cache some of the periodic schedule ... */
-	if (HCC_ISOC_CACHE (hcc_params)) 	// full frame cache
-		ehci->i_thresh = 8;
-	else					// N microframes cached
-		ehci->i_thresh = 2 + HCC_ISOC_THRES (hcc_params);
-
-	ehci->async = 0;
-	ehci->reclaim = 0;
-	ehci->next_uframe = -1;
-
-	/* controller state:  unknown --> reset */
-
-	/* EHCI spec section 4.1 */
-	// FIXME require STS_HALT before reset...
-	ehci_reset (ehci);
-	writel (INTR_MASK, &ehci->regs->intr_enable);
-	writel (ehci->periodic_dma, &ehci->regs->frame_list);
-
-	/*
-	 * hcc_params controls whether ehci->regs->segment must (!!!)
-	 * be used; it constrains QH/ITD/SITD and QTD locations.
-	 * pci_pool consistent memory always uses segment zero.
-	 */
-	if (HCC_64BIT_ADDR (hcc_params)) {
-		writel (0, &ehci->regs->segment);
-		/*
-		 * FIXME Enlarge pci_set_dma_mask() when possible.  The DMA
-		 * mapping API spec now says that'll affect only single shot
-		 * mappings, and the pci_pool data will stay safe in seg 0.
-		 * That's what we want:  no extra copies for USB transfers.
-		 */
-		info ("restricting 64bit DMA mappings to segment 0 ...");
-	}
-
-	/* clear interrupt enables, set irq latency */
-	temp = readl (&ehci->regs->command) & 0xff;
-	if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
-	    log2_irq_thresh = 0;
-	temp |= 1 << (16 + log2_irq_thresh);
-	// keeping default periodic framelist size
-	temp &= ~(CMD_IAAD | CMD_ASE | CMD_PSE),
-	// Philips, Intel, and maybe others need CMD_RUN before the
-	// root hub will detect new devices (why?); NEC doesn't
-	temp |= CMD_RUN;
-	writel (temp, &ehci->regs->command);
-	dbg_cmd (ehci, "init", temp);
-
-	/* set async sleep time = 10 us ... ? */
-
-	ehci->tasklet.func = ehci_tasklet;
-	ehci->tasklet.data = (unsigned long) ehci;
-
-	/* wire up the root hub */
-	hcd->bus->root_hub = udev = usb_alloc_dev (NULL, hcd->bus);
-	if (!udev) {
-done2:
-		ehci_mem_cleanup (ehci);
-		return -ENOMEM;
-	}
-
-	/*
-	 * Start, enabling full USB 2.0 functionality ... usb 1.1 devices
-	 * are explicitly handed to companion controller(s), so no TT is
-	 * involved with the root hub.
-	 */
-	ehci->hcd.state = USB_STATE_READY;
-	writel (FLAG_CF, &ehci->regs->configured_flag);
-	readl (&ehci->regs->command);	/* unblock posted write */
-
-        /* PCI Serial Bus Release Number is at 0x60 offset */
-	pci_read_config_byte (hcd->pdev, 0x60, &tempbyte);
-	temp = readw (&ehci->caps->hci_version);
-	info ("USB %x.%x support enabled, EHCI rev %x.%2x",
-	      ((tempbyte & 0xf0)>>4),
-	      (tempbyte & 0x0f),
-	       temp >> 8,
-	       temp & 0xff);
-
-	/*
-	 * From here on, khubd concurrently accesses the root
-	 * hub; drivers will be talking to enumerated devices.
-	 *
-	 * Before this point the HC was idle/ready.  After, khubd
-	 * and device drivers may start it running.
-	 */
-	usb_connect (udev);
-	udev->speed = USB_SPEED_HIGH;
-	if (usb_new_device (udev) != 0) {
-		if (hcd->state == USB_STATE_RUNNING)
-			ehci_ready (ehci);
-		while (readl (&ehci->regs->status) & (STS_ASS | STS_PSS))
-			udelay (100);
-		ehci_reset (ehci);
-		// usb_disconnect (udev); 
-		hcd->bus->root_hub = 0;
-		usb_free_dev (udev); 
-		retval = -ENODEV;
-		goto done2;
-	}
-
-	return 0;
-}
-
-/* always called by thread; normally rmmod */
-
-static void ehci_stop (struct usb_hcd *hcd)
-{
-	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
-
-	dbg ("%s: stop", hcd->bus_name);
-
-	if (hcd->state == USB_STATE_RUNNING)
-		ehci_ready (ehci);
-	while (readl (&ehci->regs->status) & (STS_ASS | STS_PSS))
-		udelay (100);
-	ehci_reset (ehci);
-
-	// root hub is shut down separately (first, when possible)
-	scan_async (ehci);
-	if (ehci->next_uframe != -1)
-		scan_periodic (ehci);
-	ehci_mem_cleanup (ehci);
-
-	dbg_status (ehci, "ehci_stop completed", readl (&ehci->regs->status));
-}
-
-static int ehci_get_frame (struct usb_hcd *hcd)
-{
-	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
-	return (readl (&ehci->regs->frame_index) >> 3) % ehci->periodic_size;
-}
-
-/*-------------------------------------------------------------------------*/
-
-#ifdef	CONFIG_PM
-
-/* suspend/resume, section 4.3 */
-
-static int ehci_suspend (struct usb_hcd *hcd, u32 state)
-{
-	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
-	int			ports;
-	int			i;
-
-	dbg ("%s: suspend to %d", hcd->bus_name, state);
-
-	ports = HCS_N_PORTS (ehci->hcs_params);
-
-	// FIXME:  This assumes what's probably a D3 level suspend...
-
-	// FIXME:  usb wakeup events on this bus should resume the machine.
-	// pci config register PORTWAKECAP controls which ports can do it;
-	// bios may have initted the register...
-
-	/* suspend each port, then stop the hc */
-	for (i = 0; i < ports; i++) {
-		int	temp = readl (&ehci->regs->port_status [i]);
-
-		if ((temp & PORT_PE) == 0
-				|| (temp & PORT_OWNER) != 0)
-			continue;
-dbg ("%s: suspend port %d", hcd->bus_name, i);
-		temp |= PORT_SUSPEND;
-		writel (temp, &ehci->regs->port_status [i]);
-	}
-
-	if (hcd->state == USB_STATE_RUNNING)
-		ehci_ready (ehci);
-	while (readl (&ehci->regs->status) & (STS_ASS | STS_PSS))
-		udelay (100);
-	writel (readl (&ehci->regs->command) & ~CMD_RUN, &ehci->regs->command);
-
-// save pci FLADJ value
-
-	/* who tells PCI to reduce power consumption? */
-
-	return 0;
-}
-
-static int ehci_resume (struct usb_hcd *hcd)
-{
-	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
-	int			ports;
-	int			i;
-
-	dbg ("%s: resume", hcd->bus_name);
-
-	ports = HCS_N_PORTS (ehci->hcs_params);
-
-	// FIXME:  if controller didn't retain state,
-	// return and let generic code clean it up
-	// test configured_flag ?
-
-	/* resume HC and each port */
-// restore pci FLADJ value
-	// khubd and drivers will set HC running, if needed;
-	hcd->state = USB_STATE_READY;
-	// FIXME Philips/Intel/... etc don't really have a "READY"
-	// state ... turn on CMD_RUN too
-	for (i = 0; i < ports; i++) {
-		int	temp = readl (&ehci->regs->port_status [i]);
-
-		if ((temp & PORT_PE) == 0
-				|| (temp & PORT_SUSPEND) != 0)
-			continue;
-dbg ("%s: resume port %d", hcd->bus_name, i);
-		temp |= PORT_RESUME;
-		writel (temp, &ehci->regs->port_status [i]);
-		readl (&ehci->regs->command);	/* unblock posted writes */
-
-		wait_ms (20);
-		temp &= ~PORT_RESUME;
-		writel (temp, &ehci->regs->port_status [i]);
-	}
-	readl (&ehci->regs->command);	/* unblock posted writes */
-	return 0;
-}
-
-#endif
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * tasklet scheduled by some interrupts and other events
- * calls driver completion functions ... but not in_irq()
- */
-static void ehci_tasklet (unsigned long param)
-{
-	struct ehci_hcd		*ehci = (struct ehci_hcd *) param;
-
-	if (ehci->reclaim_ready)
-		end_unlink_async (ehci);
-	scan_async (ehci);
-	if (ehci->next_uframe != -1)
-		scan_periodic (ehci);
-}
-
-/*-------------------------------------------------------------------------*/
-
-static void ehci_irq (struct usb_hcd *hcd)
-{
-	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
-	u32			status = readl (&ehci->regs->status);
-	int			bh;
-
-	status &= INTR_MASK;
-	if (!status)			/* irq sharing? */
-		return;
-
-	/* clear (just) interrupts */
-	writel (status, &ehci->regs->status);
-	readl (&ehci->regs->command);	/* unblock posted write */
-	bh = 0;
-
-#ifdef	EHCI_VERBOSE_DEBUG
-	/* unrequested/ignored: Port Change Detect, Frame List Rollover */
-	dbg_status (ehci, "irq", status);
-#endif
-
-	/* INT, ERR, and IAA interrupt rates can be throttled */
-
-	/* normal [4.15.1.2] or error [4.15.1.1] completion */
-	if (likely ((status & (STS_INT|STS_ERR)) != 0))
-		bh = 1;
-
-	/* complete the unlinking of some qh [4.15.2.3] */
-	if (status & STS_IAA) {
-		ehci->reclaim_ready = 1;
-		bh = 1;
-	}
-
-	/* PCI errors [4.15.2.4] */
-	if (unlikely ((status & STS_FATAL) != 0)) {
-		err ("%s: fatal error, state %x", hcd->bus_name, hcd->state);
-		ehci_reset (ehci);
-		// generic layer kills/unlinks all urbs
-		// then tasklet cleans up the rest
-		bh = 1;
-	}
-
-	/* most work doesn't need to be in_irq() */
-	if (likely (bh == 1))
-		tasklet_schedule (&ehci->tasklet);
-}
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * non-error returns are a promise to giveback() the urb later
- * we drop ownership so next owner (or urb unlink) can get it
- *
- * urb + dev is in hcd_dev.urb_list
- * we're queueing TDs onto software and hardware lists
- *
- * hcd-specific init for hcpriv hasn't been done yet
- *
- * NOTE:  EHCI queues control and bulk requests transparently, like OHCI.
- */
-static int ehci_urb_enqueue (
-	struct usb_hcd	*hcd,
-	struct urb	*urb,
-	int		mem_flags
-) {
-	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
-	struct list_head	qtd_list;
-
-	urb->transfer_flags &= ~EHCI_STATE_UNLINK;
-	INIT_LIST_HEAD (&qtd_list);
-	switch (usb_pipetype (urb->pipe)) {
-
-	case PIPE_CONTROL:
-	case PIPE_BULK:
-		if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
-			return -ENOMEM;
-		return submit_async (ehci, urb, &qtd_list, mem_flags);
-
-	case PIPE_INTERRUPT:
-		if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
-			return -ENOMEM;
-		return intr_submit (ehci, urb, &qtd_list, mem_flags);
-
-	case PIPE_ISOCHRONOUS:
-		if (urb->dev->speed == USB_SPEED_HIGH)
-			return itd_submit (ehci, urb, mem_flags);
-#ifdef have_split_iso
-		else
-			return sitd_submit (ehci, urb, mem_flags);
-#else
-		dbg ("no split iso support yet");
-		return -ENOSYS;
-#endif /* have_split_iso */
-
-	default:	/* can't happen */
-		return -ENOSYS;
-	}
-}
-
-/* remove from hardware lists
- * completions normally happen asynchronously
- */
-
-static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
-{
-	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
-	struct ehci_qh		*qh = (struct ehci_qh *) urb->hcpriv;
-	unsigned long		flags;
-
-	dbg ("%s urb_dequeue %p qh state %d",
-		hcd->bus_name, urb, qh->qh_state);
-
-	switch (usb_pipetype (urb->pipe)) {
-	case PIPE_CONTROL:
-	case PIPE_BULK:
-		spin_lock_irqsave (&ehci->lock, flags);
-		if (ehci->reclaim) {
-dbg ("dq: reclaim busy, %s", RUN_CONTEXT);
-			if (in_interrupt ()) {
-				spin_unlock_irqrestore (&ehci->lock, flags);
-				return -EAGAIN;
-			}
-			while (qh->qh_state == QH_STATE_LINKED
-					&& ehci->reclaim
-					&& ehci->hcd.state != USB_STATE_HALT
-					) {
-				spin_unlock_irqrestore (&ehci->lock, flags);
-// yeech ... this could spin for up to two frames!
-dbg ("wait for dequeue: state %d, reclaim %p, hcd state %d",
-    qh->qh_state, ehci->reclaim, ehci->hcd.state
-);
-				udelay (100);
-				spin_lock_irqsave (&ehci->lock, flags);
-			}
-		}
-		if (qh->qh_state == QH_STATE_LINKED)
-			start_unlink_async (ehci, qh);
-		spin_unlock_irqrestore (&ehci->lock, flags);
-		return 0;
-
-	case PIPE_INTERRUPT:
-		intr_deschedule (ehci, urb->start_frame, qh,
-			(urb->dev->speed == USB_SPEED_HIGH)
-			    ? urb->interval
-			    : (urb->interval << 3));
-		if (ehci->hcd.state == USB_STATE_HALT)
-			urb->status = -ESHUTDOWN;
-		qh_completions (ehci, qh, 1);
-		return 0;
-
-	case PIPE_ISOCHRONOUS:
-		// itd or sitd ...
-
-		// wait till next completion, do it then.
-		// completion irqs can wait up to 1024 msec,
-		urb->transfer_flags |= EHCI_STATE_UNLINK;
-		return 0;
-	}
-	return -EINVAL;
-}
-
-/*-------------------------------------------------------------------------*/
-
-// bulk qh holds the data toggle
-
-static void ehci_free_config (struct usb_hcd *hcd, struct usb_device *udev)
-{
-	struct hcd_dev		*dev = (struct hcd_dev *)udev->hcpriv;
-	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
-	int			i;
-	unsigned long		flags;
-
-	/* ASSERT:  nobody can be submitting urbs for this any more */
-
-	dbg ("%s: free_config devnum %d", hcd->bus_name, udev->devnum);
-
-	spin_lock_irqsave (&ehci->lock, flags);
-	for (i = 0; i < 32; i++) {
-		if (dev->ep [i]) {
-			struct ehci_qh		*qh;
-
-			/* dev->ep never has ITDs or SITDs */
-			qh = (struct ehci_qh *) dev->ep [i];
-			vdbg ("free_config, ep 0x%02x qh %p", i, qh);
-			if (!list_empty (&qh->qtd_list)) {
-				dbg ("ep 0x%02x qh %p not empty!", i, qh);
-				BUG ();
-			}
-			dev->ep [i] = 0;
-
-			/* wait_ms() won't spin here -- we're a thread */
-			while (qh->qh_state == QH_STATE_LINKED
-					&& ehci->reclaim
-					&& ehci->hcd.state != USB_STATE_HALT
-					) {
-				spin_unlock_irqrestore (&ehci->lock, flags);
-				wait_ms (1);
-				spin_lock_irqsave (&ehci->lock, flags);
-			}
-			if (qh->qh_state == QH_STATE_LINKED) {
-				start_unlink_async (ehci, qh);
-				while (qh->qh_state != QH_STATE_IDLE) {
-					spin_unlock_irqrestore (&ehci->lock,
-						flags);
-					wait_ms (1);
-					spin_lock_irqsave (&ehci->lock, flags);
-				}
-			}
-			qh_put (ehci, qh);
-		}
-	}
-
-	spin_unlock_irqrestore (&ehci->lock, flags);
-}
-
-/*-------------------------------------------------------------------------*/
-
-static const char	hcd_name [] = "ehci-hcd";
-
-static const struct hc_driver ehci_driver = {
-	description:		hcd_name,
-
-	/*
-	 * generic hardware linkage
-	 */
-	irq:			ehci_irq,
-	flags:			HCD_MEMORY | HCD_USB2,
-
-	/*
-	 * basic lifecycle operations
-	 */
-	start:			ehci_start,
-#ifdef	CONFIG_PM
-	suspend:		ehci_suspend,
-	resume:			ehci_resume,
-#endif
-	stop:			ehci_stop,
-
-	/*
-	 * memory lifecycle (except per-request)
-	 */
-	hcd_alloc:		ehci_hcd_alloc,
-	hcd_free:		ehci_hcd_free,
-
-	/*
-	 * managing i/o requests and associated device resources
-	 */
-	urb_enqueue:		ehci_urb_enqueue,
-	urb_dequeue:		ehci_urb_dequeue,
-	free_config:		ehci_free_config,
-
-	/*
-	 * scheduling support
-	 */
-	get_frame_number:	ehci_get_frame,
-
-	/*
-	 * root hub support
-	 */
-	hub_status_data:	ehci_hub_status_data,
-	hub_control:		ehci_hub_control,
-};
-
-/*-------------------------------------------------------------------------*/
-
-/* EHCI spec says PCI is required. */
-
-/* PCI driver selection metadata; PCI hotplugging uses this */
-static const struct pci_device_id __devinitdata pci_ids [] = { {
-
-	/* handle any USB 2.0 EHCI controller */
-
-	class: 		((PCI_CLASS_SERIAL_USB << 8) | 0x20),
-	class_mask: 	~0,
-	driver_data:	(unsigned long) &ehci_driver,
-
-	/* no matter who makes it */
-	vendor:		PCI_ANY_ID,
-	device:		PCI_ANY_ID,
-	subvendor:	PCI_ANY_ID,
-	subdevice:	PCI_ANY_ID,
-
-}, { /* end: all zeroes */ }
-};
-MODULE_DEVICE_TABLE (pci, pci_ids);
-
-/* pci driver glue; this is a "new style" PCI driver module */
-static struct pci_driver ehci_pci_driver = {
-	name:		(char *) hcd_name,
-	id_table:	pci_ids,
-
-	probe:		usb_hcd_pci_probe,
-	remove:		usb_hcd_pci_remove,
-
-#ifdef	CONFIG_PM
-	suspend:	usb_hcd_pci_suspend,
-	resume:		usb_hcd_pci_resume,
-#endif
-};
-
-#define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC
-
-EXPORT_NO_SYMBOLS;
-MODULE_DESCRIPTION (DRIVER_INFO);
-MODULE_AUTHOR (DRIVER_AUTHOR);
-MODULE_LICENSE ("GPL");
-
-static int __init init (void) 
-{
-	dbg (DRIVER_INFO);
-	dbg ("block sizes: qh %Zd qtd %Zd itd %Zd sitd %Zd",
-		sizeof (struct ehci_qh), sizeof (struct ehci_qtd),
-		sizeof (struct ehci_itd), sizeof (struct ehci_sitd));
-
-	return pci_module_init (&ehci_pci_driver);
-}
-module_init (init);
-
-static void __exit cleanup (void) 
-{	
-	pci_unregister_driver (&ehci_pci_driver);
-}
-module_exit (cleanup);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/hcd/ehci-hub.c linux-2.4.21-pre6/drivers/usb/hcd/ehci-hub.c
--- linux-2.4.20/drivers/usb/hcd/ehci-hub.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/hcd/ehci-hub.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,343 +0,0 @@
-/*
- * Copyright (c) 2001-2002 by David Brownell
- * 
- * 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 file is part of ehci-hcd.c */
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * EHCI Root Hub ... the nonsharable stuff
- *
- * Registers don't need cpu_to_le32, that happens transparently
- */
-
-/*-------------------------------------------------------------------------*/
-
-static int check_reset_complete (
-	struct ehci_hcd	*ehci,
-	int		index,
-	int		port_status
-) {
-	if (!(port_status & PORT_CONNECT)) {
-		ehci->reset_done [index] = 0;
-		return port_status;
-	}
-
-	/* if reset finished and it's still not enabled -- handoff */
-	if (!(port_status & PORT_PE)) {
-		dbg ("%s port %d full speed, give to companion, 0x%x",
-			ehci->hcd.bus_name, index + 1, port_status);
-
-		// what happens if HCS_N_CC(params) == 0 ?
-		port_status |= PORT_OWNER;
-		writel (port_status, &ehci->regs->port_status [index]);
-
-	} else
-		dbg ("%s port %d high speed", ehci->hcd.bus_name, index + 1);
-
-	return port_status;
-}
-
-/*-------------------------------------------------------------------------*/
-
-
-/* build "status change" packet (one or two bytes) from HC registers */
-
-static int
-ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
-{
-	struct ehci_hcd	*ehci = hcd_to_ehci (hcd);
-	u32		temp, status = 0;
-	int		ports, i, retval = 1;
-	unsigned long	flags;
-
-	/* init status to no-changes */
-	buf [0] = 0;
-	ports = HCS_N_PORTS (ehci->hcs_params);
-	if (ports > 7) {
-		buf [1] = 0;
-		retval++;
-	}
-	
-	/* no hub change reports (bit 0) for now (power, ...) */
-
-	/* port N changes (bit N)? */
-	spin_lock_irqsave (&ehci->lock, flags);
-	for (i = 0; i < ports; i++) {
-		temp = readl (&ehci->regs->port_status [i]);
-		if (temp & PORT_OWNER) {
-			/* don't report this in GetPortStatus */
-			if (temp & PORT_CSC) {
-				temp &= ~PORT_CSC;
-				writel (temp, &ehci->regs->port_status [i]);
-			}
-			continue;
-		}
-		if (!(temp & PORT_CONNECT))
-			ehci->reset_done [i] = 0;
-		if ((temp & (PORT_CSC | PORT_PEC | PORT_OCC)) != 0) {
-			if (i < 7)
-			    buf [0] |= 1 << (i + 1);
-			else
-			    buf [1] |= 1 << (i - 7);
-			status = STS_PCD;
-		}
-	}
-	spin_unlock_irqrestore (&ehci->lock, flags);
-	return status ? retval : 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-static void
-ehci_hub_descriptor (
-	struct ehci_hcd			*ehci,
-	struct usb_hub_descriptor	*desc
-) {
-	int		ports = HCS_N_PORTS (ehci->hcs_params);
-	u16		temp;
-
-	desc->bDescriptorType = 0x29;
-	desc->bPwrOn2PwrGood = 0;	/* FIXME: f(system power) */
-	desc->bHubContrCurrent = 0;
-
-	desc->bNbrPorts = ports;
-	temp = 1 + (ports / 8);
-	desc->bDescLength = 7 + 2 * temp;
-
-	/* two bitmaps:  ports removable, and usb 1.0 legacy PortPwrCtrlMask */
-	memset (&desc->bitmap [0], 0, temp);
-	memset (&desc->bitmap [temp], 0xff, temp);
-
-	temp = 0x0008;			/* per-port overcurrent reporting */
-	if (HCS_PPC (ehci->hcs_params))
-		temp |= 0x0001;		/* per-port power control */
-	if (HCS_INDICATOR (ehci->hcs_params))
-		temp |= 0x0080;		/* per-port indicators (LEDs) */
-	desc->wHubCharacteristics = cpu_to_le16 (temp);
-}
-
-/*-------------------------------------------------------------------------*/
-
-static int ehci_hub_control (
-	struct usb_hcd	*hcd,
-	u16		typeReq,
-	u16		wValue,
-	u16		wIndex,
-	char		*buf,
-	u16		wLength
-) {
-	struct ehci_hcd	*ehci = hcd_to_ehci (hcd);
-	int		ports = HCS_N_PORTS (ehci->hcs_params);
-	u32		temp, status;
-	unsigned long	flags;
-	int		retval = 0;
-
-	/*
-	 * FIXME:  support SetPortFeatures USB_PORT_FEAT_INDICATOR.
-	 * HCS_INDICATOR may say we can change LEDs to off/amber/green.
-	 * (track current state ourselves) ... blink for diagnostics,
-	 * power, "this is the one", etc.  EHCI spec supports this.
-	 */
-
-	spin_lock_irqsave (&ehci->lock, flags);
-	switch (typeReq) {
-	case ClearHubFeature:
-		switch (wValue) {
-		case C_HUB_LOCAL_POWER:
-		case C_HUB_OVER_CURRENT:
-			/* no hub-wide feature/status flags */
-			break;
-		default:
-			goto error;
-		}
-		break;
-	case ClearPortFeature:
-		if (!wIndex || wIndex > ports)
-			goto error;
-		wIndex--;
-		temp = readl (&ehci->regs->port_status [wIndex]);
-		if (temp & PORT_OWNER)
-			break;
-
-		switch (wValue) {
-		case USB_PORT_FEAT_ENABLE:
-			writel (temp & ~PORT_PE,
-				&ehci->regs->port_status [wIndex]);
-			break;
-		case USB_PORT_FEAT_C_ENABLE:
-			writel (temp | PORT_PEC,
-				&ehci->regs->port_status [wIndex]);
-			break;
-		case USB_PORT_FEAT_SUSPEND:
-		case USB_PORT_FEAT_C_SUSPEND:
-			/* ? */
-			break;
-		case USB_PORT_FEAT_POWER:
-			if (HCS_PPC (ehci->hcs_params))
-				writel (temp & ~PORT_POWER,
-					&ehci->regs->port_status [wIndex]);
-			break;
-		case USB_PORT_FEAT_C_CONNECTION:
-			writel (temp | PORT_CSC,
-				&ehci->regs->port_status [wIndex]);
-			break;
-		case USB_PORT_FEAT_C_OVER_CURRENT:
-			writel (temp | PORT_OCC,
-				&ehci->regs->port_status [wIndex]);
-			break;
-		case USB_PORT_FEAT_C_RESET:
-			/* GetPortStatus clears reset */
-			break;
-		default:
-			goto error;
-		}
-		readl (&ehci->regs->command);	/* unblock posted write */
-		break;
-	case GetHubDescriptor:
-		ehci_hub_descriptor (ehci, (struct usb_hub_descriptor *)
-			buf);
-		break;
-	case GetHubStatus:
-		/* no hub-wide feature/status flags */
-		memset (buf, 0, 4);
-		//cpu_to_le32s ((u32 *) buf);
-		break;
-	case GetPortStatus:
-		if (!wIndex || wIndex > ports)
-			goto error;
-		wIndex--;
-		status = 0;
-		temp = readl (&ehci->regs->port_status [wIndex]);
-
-		// wPortChange bits
-		if (temp & PORT_CSC)
-			status |= 1 << USB_PORT_FEAT_C_CONNECTION;
-		if (temp & PORT_PEC)
-			status |= 1 << USB_PORT_FEAT_C_ENABLE;
-		// USB_PORT_FEAT_C_SUSPEND
-		if (temp & PORT_OCC)
-			status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT;
-
-		/* whoever resets must GetPortStatus to complete it!! */
-		if ((temp & PORT_RESET)
-				&& jiffies > ehci->reset_done [wIndex]) {
-			status |= 1 << USB_PORT_FEAT_C_RESET;
-
-			/* force reset to complete */
-			writel (temp & ~PORT_RESET,
-					&ehci->regs->port_status [wIndex]);
-			do {
-				temp = readl (
-					&ehci->regs->port_status [wIndex]);
-				udelay (10);
-			} while (temp & PORT_RESET);
-
-			/* see what we found out */
-			temp = check_reset_complete (ehci, wIndex, temp);
-		}
-
-		// don't show wPortStatus if it's owned by a companion hc
-		if (!(temp & PORT_OWNER)) {
-			if (temp & PORT_CONNECT) {
-				status |= 1 << USB_PORT_FEAT_CONNECTION;
-				status |= 1 << USB_PORT_FEAT_HIGHSPEED;
-			}
-			if (temp & PORT_PE)
-				status |= 1 << USB_PORT_FEAT_ENABLE;
-			if (temp & PORT_SUSPEND)
-				status |= 1 << USB_PORT_FEAT_SUSPEND;
-			if (temp & PORT_OC)
-				status |= 1 << USB_PORT_FEAT_OVER_CURRENT;
-			if (temp & PORT_RESET)
-				status |= 1 << USB_PORT_FEAT_RESET;
-			if (temp & PORT_POWER)
-				status |= 1 << USB_PORT_FEAT_POWER;
-		}
-
-#ifndef	EHCI_VERBOSE_DEBUG
-	if (status & ~0xffff)	/* only if wPortChange is interesting */
-#endif
-		dbg_port (hcd, "GetStatus", wIndex + 1, temp);
-		// we "know" this alignment is good, caller used kmalloc()...
-		*((u32 *) buf) = cpu_to_le32 (status);
-		break;
-	case SetHubFeature:
-		switch (wValue) {
-		case C_HUB_LOCAL_POWER:
-		case C_HUB_OVER_CURRENT:
-			/* no hub-wide feature/status flags */
-			break;
-		default:
-			goto error;
-		}
-		break;
-	case SetPortFeature:
-		if (!wIndex || wIndex > ports)
-			goto error;
-		wIndex--;
-		temp = readl (&ehci->regs->port_status [wIndex]);
-		if (temp & PORT_OWNER)
-			break;
-
-		switch (wValue) {
-		case USB_PORT_FEAT_SUSPEND:
-			writel (temp | PORT_SUSPEND,
-				&ehci->regs->port_status [wIndex]);
-			break;
-		case USB_PORT_FEAT_POWER:
-			if (HCS_PPC (ehci->hcs_params))
-				writel (temp | PORT_POWER,
-					&ehci->regs->port_status [wIndex]);
-			break;
-		case USB_PORT_FEAT_RESET:
-			/* line status bits may report this as low speed */
-			if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT
-					&& PORT_USB11 (temp)) {
-				dbg ("%s port %d low speed, give to companion",
-					hcd->bus_name, wIndex + 1);
-				temp |= PORT_OWNER;
-			} else {
-				vdbg ("%s port %d reset",
-					hcd->bus_name, wIndex + 1);
-				temp |= PORT_RESET;
-				temp &= ~PORT_PE;
-
-				/*
-				 * caller must wait, then call GetPortStatus
-				 * usb 2.0 spec says 50 ms resets on root
-				 */
-				ehci->reset_done [wIndex] = jiffies
-				    	+ ((50 /* msec */ * HZ) / 1000);
-			}
-			writel (temp, &ehci->regs->port_status [wIndex]);
-			break;
-		default:
-			goto error;
-		}
-		readl (&ehci->regs->command);	/* unblock posted writes */
-		break;
-
-	default:
-error:
-		/* "stall" on error */
-		retval = -EPIPE;
-	}
-	spin_unlock_irqrestore (&ehci->lock, flags);
-	return retval;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/hcd/ehci-mem.c linux-2.4.21-pre6/drivers/usb/hcd/ehci-mem.c
--- linux-2.4.20/drivers/usb/hcd/ehci-mem.c	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/hcd/ehci-mem.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,236 +0,0 @@
-/*
- * Copyright (c) 2001 by David Brownell
- * 
- * 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 file is part of ehci-hcd.c */
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * There's basically three types of memory:
- *	- data used only by the HCD ... kmalloc is fine
- *	- async and periodic schedules, shared by HC and HCD ... these
- *	  need to use pci_pool or pci_alloc_consistent
- *	- driver buffers, read/written by HC ... single shot DMA mapped 
- *
- * There's also PCI "register" data, which is memory mapped.
- * No memory seen by this driver is pagable.
- */
-
-/*-------------------------------------------------------------------------*/
-/* 
- * Allocator / cleanup for the per device structure
- * Called by hcd init / removal code
- */
-static struct usb_hcd *ehci_hcd_alloc (void)
-{
-	struct ehci_hcd *ehci;
-
-	ehci = (struct ehci_hcd *)
-		kmalloc (sizeof (struct ehci_hcd), GFP_KERNEL);
-	if (ehci != 0) {
-		memset (ehci, 0, sizeof (struct ehci_hcd));
-		return &ehci->hcd;
-	}
-	return 0;
-}
-
-static void ehci_hcd_free (struct usb_hcd *hcd)
-{
-	kfree (hcd_to_ehci (hcd));
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* Allocate the key transfer structures from the previously allocated pool */
-
-static struct ehci_qtd *ehci_qtd_alloc (struct ehci_hcd *ehci, int flags)
-{
-	struct ehci_qtd		*qtd;
-	dma_addr_t		dma;
-
-	qtd = pci_pool_alloc (ehci->qtd_pool, flags, &dma);
-	if (qtd != 0) {
-		memset (qtd, 0, sizeof *qtd);
-		qtd->qtd_dma = dma;
-		qtd->hw_next = EHCI_LIST_END;
-		qtd->hw_alt_next = EHCI_LIST_END;
-		INIT_LIST_HEAD (&qtd->qtd_list);
-	}
-	return qtd;
-}
-
-static inline void ehci_qtd_free (struct ehci_hcd *ehci, struct ehci_qtd *qtd)
-{
-	pci_pool_free (ehci->qtd_pool, qtd, qtd->qtd_dma);
-}
-
-
-static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, int flags)
-{
-	struct ehci_qh		*qh;
-	dma_addr_t		dma;
-
-	qh = (struct ehci_qh *)
-		pci_pool_alloc (ehci->qh_pool, flags, &dma);
-	if (qh) {
-		memset (qh, 0, sizeof *qh);
-		atomic_set (&qh->refcount, 1);
-		qh->qh_dma = dma;
-		// INIT_LIST_HEAD (&qh->qh_list);
-		INIT_LIST_HEAD (&qh->qtd_list);
-	}
-	return qh;
-}
-
-/* to share a qh (cpu threads, or hc) */
-static inline struct ehci_qh *qh_get (/* ehci, */ struct ehci_qh *qh)
-{
-	// dbg ("get %p (%d++)", qh, qh->refcount.counter);
-	atomic_inc (&qh->refcount);
-	return qh;
-}
-
-static void qh_put (struct ehci_hcd *ehci, struct ehci_qh *qh)
-{
-	// dbg ("put %p (--%d)", qh, qh->refcount.counter);
-	if (!atomic_dec_and_test (&qh->refcount))
-		return;
-	/* clean qtds first, and know this is not linked */
-	if (!list_empty (&qh->qtd_list) || qh->qh_next.ptr) {
-		dbg ("unused qh not empty!");
-		BUG ();
-	}
-	pci_pool_free (ehci->qh_pool, qh, qh->qh_dma);
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* The queue heads and transfer descriptors are managed from pools tied 
- * to each of the "per device" structures.
- * This is the initialisation and cleanup code.
- */
-
-static void ehci_mem_cleanup (struct ehci_hcd *ehci)
-{
-	/* PCI consistent memory and pools */
-	if (ehci->qtd_pool)
-		pci_pool_destroy (ehci->qtd_pool);
-	ehci->qtd_pool = 0;
-
-	if (ehci->qh_pool) {
-		pci_pool_destroy (ehci->qh_pool);
-		ehci->qh_pool = 0;
-	}
-
-	if (ehci->itd_pool)
-		pci_pool_destroy (ehci->itd_pool);
-	ehci->itd_pool = 0;
-
-	if (ehci->sitd_pool)
-		pci_pool_destroy (ehci->sitd_pool);
-	ehci->sitd_pool = 0;
-
-	if (ehci->periodic)
-		pci_free_consistent (ehci->hcd.pdev,
-			ehci->periodic_size * sizeof (u32),
-			ehci->periodic, ehci->periodic_dma);
-	ehci->periodic = 0;
-
-	/* shadow periodic table */
-	if (ehci->pshadow)
-		kfree (ehci->pshadow);
-	ehci->pshadow = 0;
-}
-
-/* remember to add cleanup code (above) if you add anything here */
-static int ehci_mem_init (struct ehci_hcd *ehci, int flags)
-{
-	int i;
-
-	/* QTDs for control/bulk/intr transfers */
-	ehci->qtd_pool = pci_pool_create ("ehci_qtd", ehci->hcd.pdev,
-			sizeof (struct ehci_qtd),
-			32 /* byte alignment (for hw parts) */,
-			4096 /* can't cross 4K */,
-			flags);
-	if (!ehci->qtd_pool) {
-		dbg ("no qtd pool");
-		ehci_mem_cleanup (ehci);
-		return -ENOMEM;
-	}
-
-	/* QH for control/bulk/intr transfers */
-	ehci->qh_pool = pci_pool_create ("ehci_qh", ehci->hcd.pdev,
-			sizeof (struct ehci_qh),
-			32 /* byte alignment (for hw parts) */,
-			4096 /* can't cross 4K */,
-			flags);
-	if (!ehci->qh_pool) {
-		dbg ("no qh pool");
-		ehci_mem_cleanup (ehci);
-		return -ENOMEM;
-	}
-
-	/* ITD for high speed ISO transfers */
-	ehci->itd_pool = pci_pool_create ("ehci_itd", ehci->hcd.pdev,
-			sizeof (struct ehci_itd),
-			32 /* byte alignment (for hw parts) */,
-			4096 /* can't cross 4K */,
-			flags);
-	if (!ehci->itd_pool) {
-		dbg ("no itd pool");
-		ehci_mem_cleanup (ehci);
-		return -ENOMEM;
-	}
-
-	/* SITD for full/low speed split ISO transfers */
-	ehci->sitd_pool = pci_pool_create ("ehci_sitd", ehci->hcd.pdev,
-			sizeof (struct ehci_sitd),
-			32 /* byte alignment (for hw parts) */,
-			4096 /* can't cross 4K */,
-			flags);
-	if (!ehci->sitd_pool) {
-		dbg ("no sitd pool");
-		ehci_mem_cleanup (ehci);
-		return -ENOMEM;
-	}
-
-	/* Hardware periodic table */
-	ehci->periodic = (u32 *)
-		pci_alloc_consistent (ehci->hcd.pdev,
-			ehci->periodic_size * sizeof (u32),
-			&ehci->periodic_dma);
-	if (ehci->periodic == 0) {
-		dbg ("no hw periodic table");
-		ehci_mem_cleanup (ehci);
-		return -ENOMEM;
-	}
-	for (i = 0; i < ehci->periodic_size; i++)
-		ehci->periodic [i] = EHCI_LIST_END;
-
-	/* software shadow of hardware table */
-	ehci->pshadow = kmalloc (ehci->periodic_size * sizeof (void *), flags);
-	if (ehci->pshadow == 0) {
-		dbg ("no shadow periodic table");
-		ehci_mem_cleanup (ehci);
-		return -ENOMEM;
-	}
-	memset (ehci->pshadow, 0, ehci->periodic_size * sizeof (void *));
-
-	return 0;
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/hcd/ehci-q.c linux-2.4.21-pre6/drivers/usb/hcd/ehci-q.c
--- linux-2.4.20/drivers/usb/hcd/ehci-q.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/hcd/ehci-q.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,1004 +0,0 @@
-/*
- * Copyright (c) 2001-2002 by David Brownell
- * 
- * 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 file is part of ehci-hcd.c */
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * EHCI hardware queue manipulation ... the core.  QH/QTD manipulation.
- *
- * Control, bulk, and interrupt traffic all use "qh" lists.  They list "qtd"
- * entries describing USB transactions, max 16-20kB/entry (with 4kB-aligned
- * buffers needed for the larger number).  We use one QH per endpoint, queue
- * multiple (bulk or control) urbs per endpoint.  URBs may need several qtds.
- * A scheduled interrupt qh always (for now) has one qtd, one urb.
- *
- * ISO traffic uses "ISO TD" (itd, and sitd) records, and (along with
- * interrupts) needs careful scheduling.  Performance improvements can be
- * an ongoing challenge.  That's in "ehci-sched.c".
- * 
- * USB 1.1 devices are handled (a) by "companion" OHCI or UHCI root hubs,
- * or otherwise through transaction translators (TTs) in USB 2.0 hubs using
- * (b) special fields in qh entries or (c) split iso entries.  TTs will
- * buffer low/full speed data so the host collects it at high speed.
- */
-
-/*-------------------------------------------------------------------------*/
-
-/* fill a qtd, returning how much of the buffer we were able to queue up */
-
-static int
-qtd_fill (struct ehci_qtd *qtd, dma_addr_t buf, size_t len, int token)
-{
-	int	i, count;
-
-	/* one buffer entry per 4K ... first might be short or unaligned */
-	qtd->hw_buf [0] = cpu_to_le32 (buf);
-	count = 0x1000 - (buf & 0x0fff);	/* rest of that page */
-	if (likely (len < count))		/* ... iff needed */
-		count = len;
-	else {
-		buf +=  0x1000;
-		buf &= ~0x0fff;
-
-		/* per-qtd limit: from 16K to 20K (best alignment) */
-		for (i = 1; count < len && i < 5; i++) {
-			u64	addr = buf;
-			qtd->hw_buf [i] = cpu_to_le32 ((u32)addr);
-			qtd->hw_buf_hi [i] = cpu_to_le32 ((u32)(addr >> 32));
-			buf += 0x1000;
-			if ((count + 0x1000) < len)
-				count += 0x1000;
-			else
-				count = len;
-		}
-	}
-	qtd->hw_token = cpu_to_le32 ((count << 16) | token);
-	qtd->length = count;
-
-#if 0
-	vdbg ("  qtd_fill %p, token %8x bytes %d dma %x",
-		qtd, le32_to_cpu (qtd->hw_token), count, qtd->hw_buf [0]);
-#endif
-
-	return count;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* update halted (but potentially linked) qh */
-
-static inline void qh_update (struct ehci_qh *qh, struct ehci_qtd *qtd)
-{
-	qh->hw_current = 0;
-	qh->hw_qtd_next = QTD_NEXT (qtd->qtd_dma);
-	qh->hw_alt_next = EHCI_LIST_END;
-
-	/* HC must see latest qtd and qh data before we clear ACTIVE+HALT */
-	wmb ();
-	qh->hw_token &= __constant_cpu_to_le32 (QTD_TOGGLE | QTD_STS_PING);
-}
-
-/*-------------------------------------------------------------------------*/
-
-static inline void qtd_copy_status (struct urb *urb, size_t length, u32 token)
-{
-	/* count IN/OUT bytes, not SETUP (even short packets) */
-	if (likely (QTD_PID (token) != 2))
-		urb->actual_length += length - QTD_LENGTH (token);
-
-	/* don't modify error codes */
-	if (unlikely (urb->status == -EINPROGRESS && (token & QTD_STS_HALT))) {
-		if (token & QTD_STS_BABBLE) {
-			/* FIXME "must" disable babbling device's port too */
-			urb->status = -EOVERFLOW;
-		} else if (token & QTD_STS_MMF) {
-			/* fs/ls interrupt xfer missed the complete-split */
-			urb->status = -EPROTO;
-		} else if (token & QTD_STS_DBE) {
-			urb->status = (QTD_PID (token) == 1) /* IN ? */
-				? -ENOSR  /* hc couldn't read data */
-				: -ECOMM; /* hc couldn't write data */
-		} else if (token & QTD_STS_XACT) {
-			/* timeout, bad crc, wrong PID, etc; retried */
-			if (QTD_CERR (token))
-				urb->status = -EPIPE;
-			else {
-				dbg ("3strikes");
-				urb->status = -EPROTO;
-			}
-		/* CERR nonzero + no errors + halt --> stall */
-		} else if (QTD_CERR (token))
-			urb->status = -EPIPE;
-		else	/* unknown */
-			urb->status = -EPROTO;
-
-		dbg ("ep %d-%s qtd token %08x --> status %d",
-			/* devpath */
-			usb_pipeendpoint (urb->pipe),
-			usb_pipein (urb->pipe) ? "in" : "out",
-			token, urb->status);
-
-		/* stall indicates some recovery action is needed */
-		if (urb->status == -EPIPE) {
-			int	pipe = urb->pipe;
-
-			if (!usb_pipecontrol (pipe))
-				usb_endpoint_halt (urb->dev,
-					usb_pipeendpoint (pipe),
-					usb_pipeout (pipe));
-			if (urb->dev->tt && !usb_pipeint (pipe)) {
-err ("must CLEAR_TT_BUFFER, hub port %d%s addr %d ep %d",
-    urb->dev->ttport, /* devpath */
-    urb->dev->tt->multi ? "" : " (all-ports TT)",
-    urb->dev->devnum, usb_pipeendpoint (urb->pipe));
-				// FIXME something (khubd?) should make the hub
-				// CLEAR_TT_BUFFER ASAP, it's blocking other
-				// fs/ls requests... hub_tt_clear_buffer() ?
-			}
-		}
-	}
-}
-
-static void ehci_urb_complete (
-	struct ehci_hcd		*ehci,
-	dma_addr_t		addr,
-	struct urb		*urb
-) {
-	if (urb->transfer_buffer_length && usb_pipein (urb->pipe))
-		pci_dma_sync_single (ehci->hcd.pdev, addr,
-			urb->transfer_buffer_length,
-			PCI_DMA_FROMDEVICE);
-
-	/* cleanse status if we saw no error */
-	if (likely (urb->status == -EINPROGRESS)) {
-		if (urb->actual_length != urb->transfer_buffer_length
-				&& (urb->transfer_flags & USB_DISABLE_SPD))
-			urb->status = -EREMOTEIO;
-		else
-			urb->status = 0;
-	}
-
-	/* only report unlinks once */
-	if (likely (urb->status != -ENOENT && urb->status != -ENOTCONN))
-		urb->complete (urb);
-}
-
-/* urb->lock ignored from here on (hcd is done with urb) */
-
-static void ehci_urb_done (
-	struct ehci_hcd		*ehci,
-	dma_addr_t		addr,
-	struct urb		*urb
-) {
-	if (urb->transfer_buffer_length)
-		pci_unmap_single (ehci->hcd.pdev,
-			addr,
-			urb->transfer_buffer_length,
-			usb_pipein (urb->pipe)
-			    ? PCI_DMA_FROMDEVICE
-			    : PCI_DMA_TODEVICE);
-	if (likely (urb->hcpriv != 0)) {
-		qh_put (ehci, (struct ehci_qh *) urb->hcpriv);
-		urb->hcpriv = 0;
-	}
-
-	if (likely (urb->status == -EINPROGRESS)) {
-		if (urb->actual_length != urb->transfer_buffer_length
-				&& (urb->transfer_flags & USB_DISABLE_SPD))
-			urb->status = -EREMOTEIO;
-		else
-			urb->status = 0;
-	}
-
-	/* hand off urb ownership */
-	usb_hcd_giveback_urb (&ehci->hcd, urb);
-}
-
-
-/*
- * Process completed qtds for a qh, issuing completions if needed.
- * When freeing:  frees qtds, unmaps buf, returns URB to driver.
- * When not freeing (queued periodic qh):  retain qtds, mapping, and urb.
- * Races up to qh->hw_current; returns number of urb completions.
- */
-static int
-qh_completions (
-	struct ehci_hcd		*ehci,
-	struct ehci_qh		*qh,
-	int			freeing
-) {
-	struct ehci_qtd		*qtd, *last;
-	struct list_head	*next, *qtd_list = &qh->qtd_list;
-	int			unlink = 0, halted = 0;
-	unsigned long		flags;
-	int			retval = 0;
-
-	spin_lock_irqsave (&ehci->lock, flags);
-	if (unlikely (list_empty (qtd_list))) {
-		spin_unlock_irqrestore (&ehci->lock, flags);
-		return retval;
-	}
-
-	/* scan QTDs till end of list, or we reach an active one */
-	for (qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list),
-			    	last = 0, next = 0;
-			next != qtd_list;
-			last = qtd, qtd = list_entry (next,
-						struct ehci_qtd, qtd_list)) {
-		struct urb	*urb = qtd->urb;
-		u32		token = 0;
-
-		/* clean up any state from previous QTD ...*/
-		if (last) {
-			if (likely (last->urb != urb)) {
-				/* complete() can reenter this HCD */
-				spin_unlock_irqrestore (&ehci->lock, flags);
-				if (likely (freeing != 0))
-					ehci_urb_done (ehci, last->buf_dma,
-						last->urb);
-				else
-					ehci_urb_complete (ehci, last->buf_dma,
-						last->urb);
-				spin_lock_irqsave (&ehci->lock, flags);
-				retval++;
-			}
-
-			/* qh overlays can have HC's old cached copies of
-			 * next qtd ptrs, if an URB was queued afterwards.
-			 */
-			if (cpu_to_le32 (last->qtd_dma) == qh->hw_current
-					&& last->hw_next != qh->hw_qtd_next) {
-				qh->hw_alt_next = last->hw_alt_next;
-				qh->hw_qtd_next = last->hw_next;
-			}
-
-			if (likely (freeing != 0))
-				ehci_qtd_free (ehci, last);
-			last = 0;
-		}
-		next = qtd->qtd_list.next;
-
-		/* QTDs at tail may be active if QH+HC are running,
-		 * or when unlinking some urbs queued to this QH
-		 */
-		token = le32_to_cpu (qtd->hw_token);
-		halted = halted
-			|| (__constant_cpu_to_le32 (QTD_STS_HALT)
-				& qh->hw_token) != 0
-			|| (ehci->hcd.state == USB_STATE_HALT)
-			|| (qh->qh_state == QH_STATE_IDLE);
-
-		/* fault: unlink the rest, since this qtd saw an error? */
-		if (unlikely ((token & QTD_STS_HALT) != 0)) {
-			freeing = unlink = 1;
-			/* status copied below */
-
-		/* QH halts only because of fault (above) or unlink (here). */
-		} else if (unlikely (halted != 0)) {
-
-			/* unlinking everything because of HC shutdown? */
-			if (ehci->hcd.state == USB_STATE_HALT) {
-				freeing = unlink = 1;
-
-			/* explicit unlink, maybe starting here? */
-			} else if (qh->qh_state == QH_STATE_IDLE
-					&& (urb->status == -ECONNRESET
-						|| urb->status == -ENOENT)) {
-				freeing = unlink = 1;
-
-			/* QH halted to unlink urbs _after_ this?  */
-			} else if (!unlink && (token & QTD_STS_ACTIVE) != 0) {
-				qtd = 0;
-				continue;
-			}
-
-			/* unlink the rest?  once we start unlinking, after
-			 * a fault or explicit unlink, we unlink all later
-			 * urbs.  usb spec requires that.
-			 */
-			if (unlink && urb->status == -EINPROGRESS)
-				urb->status = -ECONNRESET;
-
-		/* Else QH is active, so we must not modify QTDs
-		 * that HC may be working on.  No more qtds to check.
-		 */
-		} else if (unlikely ((token & QTD_STS_ACTIVE) != 0)) {
-			next = qtd_list;
-			qtd = 0;
-			continue;
-		}
-
-		spin_lock (&urb->lock);
-		qtd_copy_status (urb, qtd->length, token);
-		spin_unlock (&urb->lock);
-
-		/*
-		 * NOTE:  this won't work right with interrupt urbs that
-		 * need multiple qtds ... only the first scan of qh->qtd_list
-		 * starts at the right qtd, yet multiple scans could happen
-		 * for transfers that are scheduled across multiple uframes. 
-		 * (Such schedules are not currently allowed!)
-		 */
-		if (likely (freeing != 0))
-			list_del (&qtd->qtd_list);
-		else {
-			/* restore everything the HC could change
-			 * from an interrupt QTD
-			 */
-			qtd->hw_token = (qtd->hw_token
-					& __constant_cpu_to_le32 (0x8300))
-				| cpu_to_le32 (qtd->length << 16)
-				| __constant_cpu_to_le32 (QTD_STS_ACTIVE
-					| (EHCI_TUNE_CERR << 10));
-			qtd->hw_buf [0] &= ~__constant_cpu_to_le32 (0x0fff);
-
-			/* this offset, and the length above,
-			 * are likely wrong on QTDs #2..N
-			 */
-			qtd->hw_buf [0] |= cpu_to_le32 (0x0fff & qtd->buf_dma);
-		}
-
-#if 0
-		if (urb->status == -EINPROGRESS)
-			vdbg ("  qtd %p ok, urb %p, token %8x, len %d",
-				qtd, urb, token, urb->actual_length);
-		else
-			vdbg ("urb %p status %d, qtd %p, token %8x, len %d",
-				urb, urb->status, qtd, token,
-				urb->actual_length);
-#endif
-
-		/* SETUP for control urb? */
-		if (unlikely (QTD_PID (token) == 2))
-			pci_unmap_single (ehci->hcd.pdev,
-				qtd->buf_dma, sizeof (struct usb_ctrlrequest),
-				PCI_DMA_TODEVICE);
-	}
-
-	/* patch up list head? */
-	if (unlikely (halted && !list_empty (qtd_list))) {
-		qh_update (qh, list_entry (qtd_list->next,
-				struct ehci_qtd, qtd_list));
-	}
-	spin_unlock_irqrestore (&ehci->lock, flags);
-
-	/* last urb's completion might still need calling */
-	if (likely (last != 0)) {
-		if (likely (freeing != 0)) {
-			ehci_urb_done (ehci, last->buf_dma, last->urb);
-			ehci_qtd_free (ehci, last);
-		} else
-			ehci_urb_complete (ehci, last->buf_dma, last->urb);
-		retval++;
-	}
-	return retval;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * reverse of qh_urb_transaction:  free a list of TDs.
- * used for cleanup after errors, before HC sees an URB's TDs.
- */
-static void qtd_list_free (
-	struct ehci_hcd		*ehci,
-	struct urb		*urb,
-	struct list_head	*qtd_list
-) {
-	struct list_head	*entry, *temp;
-	int			unmapped = 0;
-
-	list_for_each_safe (entry, temp, qtd_list) {
-		struct ehci_qtd	*qtd;
-
-		qtd = list_entry (entry, struct ehci_qtd, qtd_list);
-		list_del (&qtd->qtd_list);
-		if (unmapped != 2) {
-			int	direction;
-			size_t	size;
-
-			/* for ctrl unmap twice: SETUP and DATA;
-			 * else (bulk, intr) just once: DATA
-			 */
-			if (!unmapped++ && usb_pipecontrol (urb->pipe)) {
-				direction = PCI_DMA_TODEVICE;
-				size = sizeof (struct usb_ctrlrequest);
-			} else {
-				direction = usb_pipein (urb->pipe)
-					? PCI_DMA_FROMDEVICE
-					: PCI_DMA_TODEVICE;
-				size = qtd->urb->transfer_buffer_length;
-				unmapped++;
-			}
-			if (qtd->buf_dma)
-				pci_unmap_single (ehci->hcd.pdev,
-					qtd->buf_dma,
-					size, direction);
-		}
-		ehci_qtd_free (ehci, qtd);
-	}
-}
-
-/*
- * create a list of filled qtds for this URB; won't link into qh.
- */
-static struct list_head *
-qh_urb_transaction (
-	struct ehci_hcd		*ehci,
-	struct urb		*urb,
-	struct list_head	*head,
-	int			flags
-) {
-	struct ehci_qtd		*qtd, *qtd_prev;
-	dma_addr_t		buf, map_buf;
-	int			len, maxpacket;
-	u32			token;
-
-	/*
-	 * URBs map to sequences of QTDs:  one logical transaction
-	 */
-	qtd = ehci_qtd_alloc (ehci, flags);
-	if (unlikely (!qtd))
-		return 0;
-	qtd_prev = 0;
-	list_add_tail (&qtd->qtd_list, head);
-	qtd->urb = urb;
-
-	token = QTD_STS_ACTIVE;
-	token |= (EHCI_TUNE_CERR << 10);
-	/* for split transactions, SplitXState initialized to zero */
-
-	if (usb_pipecontrol (urb->pipe)) {
-		/* control request data is passed in the "setup" pid */
-		qtd->buf_dma = pci_map_single (
-					ehci->hcd.pdev,
-					urb->setup_packet,
-					sizeof (struct usb_ctrlrequest),
-					PCI_DMA_TODEVICE);
-		if (unlikely (!qtd->buf_dma))
-			goto cleanup;
-
-		/* SETUP pid */
-		qtd_fill (qtd, qtd->buf_dma, sizeof (struct usb_ctrlrequest),
-			token | (2 /* "setup" */ << 8));
-
-		/* ... and always at least one more pid */
-		token ^= QTD_TOGGLE;
-		qtd_prev = qtd;
-		qtd = ehci_qtd_alloc (ehci, flags);
-		if (unlikely (!qtd))
-			goto cleanup;
-		qtd->urb = urb;
-		qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma);
-		list_add_tail (&qtd->qtd_list, head);
-	} 
-
-	/*
-	 * data transfer stage:  buffer setup
-	 */
-	len = urb->transfer_buffer_length;
-	if (likely (len > 0)) {
-		buf = map_buf = pci_map_single (ehci->hcd.pdev,
-			urb->transfer_buffer, len,
-			usb_pipein (urb->pipe)
-			    ? PCI_DMA_FROMDEVICE
-			    : PCI_DMA_TODEVICE);
-		if (unlikely (!buf))
-			goto cleanup;
-	} else
-		buf = map_buf = 0;
-
-	if (!buf || usb_pipein (urb->pipe))
-		token |= (1 /* "in" */ << 8);
-	/* else it's already initted to "out" pid (0 << 8) */
-
-	maxpacket = usb_maxpacket (urb->dev, urb->pipe,
-			usb_pipeout (urb->pipe));
-
-	/*
-	 * buffer gets wrapped in one or more qtds;
-	 * last one may be "short" (including zero len)
-	 * and may serve as a control status ack
-	 */
-	for (;;) {
-		int this_qtd_len;
-
-		qtd->urb = urb;
-		qtd->buf_dma = map_buf;
-		this_qtd_len = qtd_fill (qtd, buf, len, token);
-		len -= this_qtd_len;
-		buf += this_qtd_len;
-
-		/* qh makes control packets use qtd toggle; maybe switch it */
-		if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0)
-			token ^= QTD_TOGGLE;
-
-		if (likely (len <= 0))
-			break;
-
-		qtd_prev = qtd;
-		qtd = ehci_qtd_alloc (ehci, flags);
-		if (unlikely (!qtd))
-			goto cleanup;
-		qtd->urb = urb;
-		qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma);
-		list_add_tail (&qtd->qtd_list, head);
-	}
-
-	/*
-	 * control requests may need a terminating data "status" ack;
-	 * bulk ones may need a terminating short packet (zero length).
-	 */
-	if (likely (buf != 0)) {
-		int	one_more = 0;
-
-		if (usb_pipecontrol (urb->pipe)) {
-			one_more = 1;
-			token ^= 0x0100;	/* "in" <--> "out"  */
-			token |= QTD_TOGGLE;	/* force DATA1 */
-		} else if (usb_pipebulk (urb->pipe)
-				&& (urb->transfer_flags & USB_ZERO_PACKET)
-				&& !(urb->transfer_buffer_length % maxpacket)) {
-			one_more = 1;
-		}
-		if (one_more) {
-			qtd_prev = qtd;
-			qtd = ehci_qtd_alloc (ehci, flags);
-			if (unlikely (!qtd))
-				goto cleanup;
-			qtd->urb = urb;
-			qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma);
-			list_add_tail (&qtd->qtd_list, head);
-
-			/* never any data in such packets */
-			qtd_fill (qtd, 0, 0, token);
-		}
-	}
-
-	/* by default, enable interrupt on urb completion */
-	if (likely (!(urb->transfer_flags & URB_NO_INTERRUPT)))
-		qtd->hw_token |= __constant_cpu_to_le32 (QTD_IOC);
-	return head;
-
-cleanup:
-	qtd_list_free (ehci, urb, head);
-	return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * Hardware maintains data toggle (like OHCI) ... here we (re)initialize
- * the hardware data toggle in the QH, and set the pseudo-toggle in udev
- * so we can see if usb_clear_halt() was called.  NOP for control, since
- * we set up qh->hw_info1 to always use the QTD toggle bits. 
- */
-static inline void
-clear_toggle (struct usb_device *udev, int ep, int is_out, struct ehci_qh *qh)
-{
-	vdbg ("clear toggle, dev %d ep 0x%x-%s",
-		udev->devnum, ep, is_out ? "out" : "in");
-	qh->hw_token &= ~__constant_cpu_to_le32 (QTD_TOGGLE);
-	usb_settoggle (udev, ep, is_out, 1);
-}
-
-// Would be best to create all qh's from config descriptors,
-// when each interface/altsetting is established.  Unlink
-// any previous qh and cancel its urbs first; endpoints are
-// implicitly reset then (data toggle too).
-// That'd mean updating how usbcore talks to HCDs. (2.5?)
-
-
-/*
- * Each QH holds a qtd list; a QH is used for everything except iso.
- *
- * For interrupt urbs, the scheduler must set the microframe scheduling
- * mask(s) each time the QH gets scheduled.  For highspeed, that's
- * just one microframe in the s-mask.  For split interrupt transactions
- * there are additional complications: c-mask, maybe FSTNs.
- */
-static struct ehci_qh *
-ehci_qh_make (
-	struct ehci_hcd		*ehci,
-	struct urb		*urb,
-	struct list_head	*qtd_list,
-	int			flags
-) {
-	struct ehci_qh		*qh = ehci_qh_alloc (ehci, flags);
-	u32			info1 = 0, info2 = 0;
-
-	if (!qh)
-		return qh;
-
-	/*
-	 * init endpoint/device data for this QH
-	 */
-	info1 |= usb_pipeendpoint (urb->pipe) << 8;
-	info1 |= usb_pipedevice (urb->pipe) << 0;
-
-	/* using TT? */
-	switch (urb->dev->speed) {
-	case USB_SPEED_LOW:
-		info1 |= (1 << 12);	/* EPS "low" */
-		/* FALL THROUGH */
-
-	case USB_SPEED_FULL:
-		/* EPS 0 means "full" */
-		info1 |= (EHCI_TUNE_RL_TT << 28);
-		if (usb_pipecontrol (urb->pipe)) {
-			info1 |= (1 << 27);	/* for TT */
-			info1 |= 1 << 14;	/* toggle from qtd */
-		}
-		info1 |= usb_maxpacket (urb->dev, urb->pipe,
-					usb_pipeout (urb->pipe)) << 16;
-
-		info2 |= (EHCI_TUNE_MULT_TT << 30);
-		info2 |= urb->dev->ttport << 23;
-		info2 |= urb->dev->tt->hub->devnum << 16;
-
-		/* NOTE:  if (usb_pipeint (urb->pipe)) { scheduler sets c-mask }
-		 * ... and a 0.96 scheduler might use FSTN nodes too
-		 */
-		break;
-
-	case USB_SPEED_HIGH:		/* no TT involved */
-		info1 |= (2 << 12);	/* EPS "high" */
-		info1 |= (EHCI_TUNE_RL_HS << 28);
-		if (usb_pipecontrol (urb->pipe)) {
-			info1 |= 64 << 16;	/* usb2 fixed maxpacket */
-			info1 |= 1 << 14;	/* toggle from qtd */
-			info2 |= (EHCI_TUNE_MULT_HS << 30);
-		} else if (usb_pipebulk (urb->pipe)) {
-			info1 |= 512 << 16;	/* usb2 fixed maxpacket */
-			info2 |= (EHCI_TUNE_MULT_HS << 30);
-		} else {
-			u32	temp;
-			temp = usb_maxpacket (urb->dev, urb->pipe,
-						usb_pipeout (urb->pipe));
-			info1 |= (temp & 0x3ff) << 16;	/* maxpacket */
-			/* HS intr can be "high bandwidth" */
-			temp = 1 + ((temp >> 11) & 0x03);
-			info2 |= temp << 30;		/* mult */
-		}
-		break;
-	default:
-#ifdef DEBUG
-		BUG ();
-#else
-		;
-#endif
-	}
-
-	/* NOTE:  if (usb_pipeint (urb->pipe)) { scheduler sets s-mask } */
-
-	qh->qh_state = QH_STATE_IDLE;
-	qh->hw_info1 = cpu_to_le32 (info1);
-	qh->hw_info2 = cpu_to_le32 (info2);
-
-	/* initialize sw and hw queues with these qtds */
-	list_splice (qtd_list, &qh->qtd_list);
-	qh_update (qh, list_entry (qtd_list->next, struct ehci_qtd, qtd_list));
-
-	/* initialize data toggle state */
-	if (!usb_pipecontrol (urb->pipe))
-		clear_toggle (urb->dev,
-			usb_pipeendpoint (urb->pipe),
-			usb_pipeout (urb->pipe),
-			qh);
-
-	return qh;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* move qh (and its qtds) onto async queue; maybe enable queue.  */
-
-static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
-{
-	u32		dma = QH_NEXT (qh->qh_dma);
-	struct ehci_qh	*q;
-
-	if (unlikely (!(q = ehci->async))) {
-		u32	cmd = readl (&ehci->regs->command);
-
-		/* in case a clear of CMD_ASE didn't take yet */
-		while (readl (&ehci->regs->status) & STS_ASS)
-			udelay (100);
-
-		qh->hw_info1 |= __constant_cpu_to_le32 (QH_HEAD); /* [4.8] */
-		qh->qh_next.qh = qh;
-		qh->hw_next = dma;
-		wmb ();
-		ehci->async = qh;
-		writel ((u32)qh->qh_dma, &ehci->regs->async_next);
-		cmd |= CMD_ASE | CMD_RUN;
-		writel (cmd, &ehci->regs->command);
-		ehci->hcd.state = USB_STATE_RUNNING;
-		/* posted write need not be known to HC yet ... */
-	} else {
-		/* splice right after "start" of ring */
-		qh->hw_info1 &= ~__constant_cpu_to_le32 (QH_HEAD); /* [4.8] */
-		qh->qh_next = q->qh_next;
-		qh->hw_next = q->hw_next;
-		wmb ();
-		q->qh_next.qh = qh;
-		q->hw_next = dma;
-	}
-	qh->qh_state = QH_STATE_LINKED;
-	/* qtd completions reported later by interrupt */
-}
-
-/*-------------------------------------------------------------------------*/
-
-static int
-submit_async (
-	struct ehci_hcd		*ehci,
-	struct urb		*urb,
-	struct list_head	*qtd_list,
-	int			mem_flags
-) {
-	struct ehci_qtd		*qtd;
-	struct hcd_dev		*dev;
-	int			epnum;
-	unsigned long		flags;
-	struct ehci_qh		*qh = 0;
-
-	qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list);
-	dev = (struct hcd_dev *)urb->dev->hcpriv;
-	epnum = usb_pipeendpoint (urb->pipe);
-	if (usb_pipein (urb->pipe))
-		epnum |= 0x10;
-
-	vdbg ("%s: submit_async urb %p len %d ep %d-%s qtd %p [qh %p]",
-		ehci->hcd.bus_name, urb, urb->transfer_buffer_length,
-		epnum & 0x0f, (epnum & 0x10) ? "in" : "out",
-		qtd, dev ? dev->ep [epnum] : (void *)~0);
-
-	spin_lock_irqsave (&ehci->lock, flags);
-
-	qh = (struct ehci_qh *) dev->ep [epnum];
-	if (likely (qh != 0)) {
-		u32	hw_next = QTD_NEXT (qtd->qtd_dma);
-
-		/* maybe patch the qh used for set_address */
-		if (unlikely (epnum == 0
-				&& le32_to_cpu (qh->hw_info1 & 0x7f) == 0))
-			qh->hw_info1 |= cpu_to_le32 (usb_pipedevice(urb->pipe));
-
-		/* is an URB is queued to this qh already? */
-		if (unlikely (!list_empty (&qh->qtd_list))) {
-			struct ehci_qtd		*last_qtd;
-			int			short_rx = 0;
-
-			/* update the last qtd's "next" pointer */
-			// dbg_qh ("non-empty qh", ehci, qh);
-			last_qtd = list_entry (qh->qtd_list.prev,
-					struct ehci_qtd, qtd_list);
-			last_qtd->hw_next = hw_next;
-
-			/* previous urb allows short rx? maybe optimize. */
-			if (!(last_qtd->urb->transfer_flags & USB_DISABLE_SPD)
-					&& (epnum & 0x10)) {
-				// only the last QTD for now
-				last_qtd->hw_alt_next = hw_next;
-				short_rx = 1;
-			}
-
-			/* Adjust any old copies in qh overlay too.
-			 * Interrupt code must cope with case of HC having it
-			 * cached, and clobbering these updates.
-			 * ... complicates getting rid of extra interrupts!
-			 */
-			if (qh->hw_current == cpu_to_le32 (last_qtd->qtd_dma)) {
-				wmb ();
-				qh->hw_qtd_next = hw_next;
-				if (short_rx)
-					qh->hw_alt_next = hw_next
-				    		| (qh->hw_alt_next & 0x1e);
-				vdbg ("queue to qh %p, patch", qh);
-			}
-
-		/* no URB queued */
-		} else {
-			// dbg_qh ("empty qh", ehci, qh);
-
-			/* NOTE: we already canceled any queued URBs
-			 * when the endpoint halted.
-			 */
-
-			/* usb_clear_halt() means qh data toggle gets reset */
-			if (usb_pipebulk (urb->pipe)
-					&& unlikely (!usb_gettoggle (urb->dev,
-						(epnum & 0x0f),
-						!(epnum & 0x10)))) {
-				clear_toggle (urb->dev,
-					epnum & 0x0f, !(epnum & 0x10), qh);
-			}
-			qh_update (qh, qtd);
-		}
-		list_splice (qtd_list, qh->qtd_list.prev);
-
-	} else {
-		/* can't sleep here, we have ehci->lock... */
-		qh = ehci_qh_make (ehci, urb, qtd_list, SLAB_ATOMIC);
-		if (likely (qh != 0)) {
-			// dbg_qh ("new qh", ehci, qh);
-			dev->ep [epnum] = qh;
-		}
-	}
-
-	/* Control/bulk operations through TTs don't need scheduling,
-	 * the HC and TT handle it when the TT has a buffer ready.
-	 */
-	if (likely (qh != 0)) {
-		urb->hcpriv = qh_get (qh);
-		if (likely (qh->qh_state == QH_STATE_IDLE))
-			qh_link_async (ehci, qh_get (qh));
-	}
-	spin_unlock_irqrestore (&ehci->lock, flags);
-	if (unlikely (qh == 0)) {
-		qtd_list_free (ehci, urb, qtd_list);
-		return -ENOMEM;
-	}
-	return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* the async qh for the qtds being reclaimed are now unlinked from the HC */
-/* caller must not own ehci->lock */
-
-static void end_unlink_async (struct ehci_hcd *ehci)
-{
-	struct ehci_qh		*qh = ehci->reclaim;
-
-	qh->qh_state = QH_STATE_IDLE;
-	qh->qh_next.qh = 0;
-	qh_put (ehci, qh);			// refcount from reclaim 
-	ehci->reclaim = 0;
-	ehci->reclaim_ready = 0;
-
-	qh_completions (ehci, qh, 1);
-
-	// unlink any urb should now unlink all following urbs, so that
-	// relinking only happens for urbs before the unlinked ones.
-	if (!list_empty (&qh->qtd_list)
-			&& HCD_IS_RUNNING (ehci->hcd.state))
-		qh_link_async (ehci, qh);
-	else
-		qh_put (ehci, qh);		// refcount from async list
-}
-
-
-/* makes sure the async qh will become idle */
-/* caller must own ehci->lock */
-
-static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
-{
-	int		cmd = readl (&ehci->regs->command);
-	struct ehci_qh	*prev;
-
-#ifdef DEBUG
-	if (ehci->reclaim
-			|| !ehci->async
-			|| qh->qh_state != QH_STATE_LINKED
-#ifdef CONFIG_SMP
-// this macro lies except on SMP compiles
-			|| !spin_is_locked (&ehci->lock)
-#endif
-			)
-		BUG ();
-#endif
-
-	qh->qh_state = QH_STATE_UNLINK;
-	ehci->reclaim = qh = qh_get (qh);
-
-	// dbg_qh ("start unlink", ehci, qh);
-
-	/* Remove the last QH (qhead)?  Stop async schedule first. */
-	if (unlikely (qh == ehci->async && qh->qh_next.qh == qh)) {
-		/* can't get here without STS_ASS set */
-		if (ehci->hcd.state != USB_STATE_HALT) {
-			if (cmd & CMD_PSE)
-				writel (cmd & ~CMD_ASE, &ehci->regs->command);
-			else {
-				ehci_ready (ehci);
-				while (readl (&ehci->regs->status) & STS_ASS)
-					udelay (100);
-			}
-		}
-		qh->qh_next.qh = ehci->async = 0;
-
-		ehci->reclaim_ready = 1;
-		tasklet_schedule (&ehci->tasklet);
-		return;
-	} 
-
-	if (unlikely (ehci->hcd.state == USB_STATE_HALT)) {
-		ehci->reclaim_ready = 1;
-		tasklet_schedule (&ehci->tasklet);
-		return;
-	}
-
-	prev = ehci->async;
-	while (prev->qh_next.qh != qh && prev->qh_next.qh != ehci->async)
-		prev = prev->qh_next.qh;
-#ifdef DEBUG
-	if (prev->qh_next.qh != qh)
-		BUG ();
-#endif
-
-	if (qh->hw_info1 & __constant_cpu_to_le32 (QH_HEAD)) {
-		ehci->async = prev;
-		prev->hw_info1 |= __constant_cpu_to_le32 (QH_HEAD);
-	}
-	prev->hw_next = qh->hw_next;
-	prev->qh_next = qh->qh_next;
-	wmb ();
-
-	ehci->reclaim_ready = 0;
-	cmd |= CMD_IAAD;
-	writel (cmd, &ehci->regs->command);
-	/* posted write need not be known to HC yet ... */
-}
-
-/*-------------------------------------------------------------------------*/
-
-static void scan_async (struct ehci_hcd *ehci)
-{
-	struct ehci_qh		*qh;
-	unsigned long		flags;
-
-	spin_lock_irqsave (&ehci->lock, flags);
-rescan:
-	qh = ehci->async;
-	if (likely (qh != 0)) {
-		do {
-			/* clean any finished work for this qh */
-			if (!list_empty (&qh->qtd_list)) {
-				// dbg_qh ("scan_async", ehci, qh);
-				qh = qh_get (qh);
-				spin_unlock_irqrestore (&ehci->lock, flags);
-
-				/* concurrent unlink could happen here */
-				qh_completions (ehci, qh, 1);
-
-				spin_lock_irqsave (&ehci->lock, flags);
-				qh_put (ehci, qh);
-			}
-
-			/* unlink idle entries (reduces PCI usage) */
-			if (list_empty (&qh->qtd_list) && !ehci->reclaim) {
-				if (qh->qh_next.qh != qh) {
-					// dbg ("irq/empty");
-					start_unlink_async (ehci, qh);
-				} else {
-					// FIXME:  arrange to stop
-					// after it's been idle a while.
-				}
-			}
-			qh = qh->qh_next.qh;
-			if (!qh)		/* unlinked? */
-				goto rescan;
-		} while (qh != ehci->async);
-	}
-
-	spin_unlock_irqrestore (&ehci->lock, flags);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/hcd/ehci-sched.c linux-2.4.21-pre6/drivers/usb/hcd/ehci-sched.c
--- linux-2.4.20/drivers/usb/hcd/ehci-sched.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/hcd/ehci-sched.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,1245 +0,0 @@
-/*
- * Copyright (c) 2001-2002 by David Brownell
- * 
- * 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 file is part of ehci-hcd.c */
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * EHCI scheduled transaction support:  interrupt, iso, split iso
- * These are called "periodic" transactions in the EHCI spec.
- *
- * Note that for interrupt transfers, the QH/QTD manipulation is shared
- * with the "asynchronous" transaction support (control/bulk transfers).
- * The only real difference is in how interrupt transfers are scheduled.
- * We get some funky API restrictions from the current URB model, which
- * works notably better for reading transfers than for writing.  (And
- * which accordingly needs to change before it'll work inside devices,
- * or with "USB On The Go" additions to USB 2.0 ...)
- */
-
-/*
- * Ceiling microseconds (typical) for that many bytes at high speed
- * ISO is a bit less, no ACK ... from USB 2.0 spec, 5.11.3 (and needed
- * to preallocate bandwidth)
- */
-#define EHCI_HOST_DELAY	5	/* nsec, guess */
-#define HS_USECS(bytes) NS_TO_US ( ((55 * 8 * 2083)/1000) \
-	+ ((2083UL * (3167 + BitTime (bytes)))/1000) \
-	+ EHCI_HOST_DELAY)
-#define HS_USECS_ISO(bytes) NS_TO_US ( ((long)(38 * 8 * 2.083)) \
-	+ ((2083UL * (3167 + BitTime (bytes)))/1000) \
-	+ EHCI_HOST_DELAY)
-	
-static int ehci_get_frame (struct usb_hcd *hcd);
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * periodic_next_shadow - return "next" pointer on shadow list
- * @periodic: host pointer to qh/itd/sitd
- * @tag: hardware tag for type of this record
- */
-static union ehci_shadow *
-periodic_next_shadow (union ehci_shadow *periodic, int tag)
-{
-	switch (tag) {
-	case Q_TYPE_QH:
-		return &periodic->qh->qh_next;
-	case Q_TYPE_FSTN:
-		return &periodic->fstn->fstn_next;
-	case Q_TYPE_ITD:
-		return &periodic->itd->itd_next;
-#ifdef have_split_iso
-	case Q_TYPE_SITD:
-		return &periodic->sitd->sitd_next;
-#endif /* have_split_iso */
-	}
-	dbg ("BAD shadow %p tag %d", periodic->ptr, tag);
-	// BUG ();
-	return 0;
-}
-
-/* returns true after successful unlink */
-/* caller must hold ehci->lock */
-static int periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr)
-{
-	union ehci_shadow	*prev_p = &ehci->pshadow [frame];
-	u32			*hw_p = &ehci->periodic [frame];
-	union ehci_shadow	here = *prev_p;
-	union ehci_shadow	*next_p;
-
-	/* find predecessor of "ptr"; hw and shadow lists are in sync */
-	while (here.ptr && here.ptr != ptr) {
-		prev_p = periodic_next_shadow (prev_p, Q_NEXT_TYPE (*hw_p));
-		hw_p = &here.qh->hw_next;
-		here = *prev_p;
-	}
-	/* an interrupt entry (at list end) could have been shared */
-	if (!here.ptr) {
-		dbg ("entry %p no longer on frame [%d]", ptr, frame);
-		return 0;
-	}
-	// vdbg ("periodic unlink %p from frame %d", ptr, frame);
-
-	/* update hardware list ... HC may still know the old structure, so
-	 * don't change hw_next until it'll have purged its cache
-	 */
-	next_p = periodic_next_shadow (&here, Q_NEXT_TYPE (*hw_p));
-	*hw_p = here.qh->hw_next;
-
-	/* unlink from shadow list; HCD won't see old structure again */
-	*prev_p = *next_p;
-	next_p->ptr = 0;
-
-	return 1;
-}
-
-/* how many of the uframe's 125 usecs are allocated? */
-static unsigned short
-periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe)
-{
-	u32			*hw_p = &ehci->periodic [frame];
-	union ehci_shadow	*q = &ehci->pshadow [frame];
-	unsigned		usecs = 0;
-
-	while (q->ptr) {
-		switch (Q_NEXT_TYPE (*hw_p)) {
-		case Q_TYPE_QH:
-			/* is it in the S-mask? */
-			if (q->qh->hw_info2 & cpu_to_le32 (1 << uframe))
-				usecs += q->qh->usecs;
-			q = &q->qh->qh_next;
-			break;
-		case Q_TYPE_FSTN:
-			/* for "save place" FSTNs, count the relevant INTR
-			 * bandwidth from the previous frame
-			 */
-			if (q->fstn->hw_prev != EHCI_LIST_END) {
-				dbg ("not counting FSTN bandwidth yet ...");
-			}
-			q = &q->fstn->fstn_next;
-			break;
-		case Q_TYPE_ITD:
-			/* NOTE the "one uframe per itd" policy */
-			if (q->itd->hw_transaction [uframe] != 0)
-				usecs += q->itd->usecs;
-			q = &q->itd->itd_next;
-			break;
-#ifdef have_split_iso
-		case Q_TYPE_SITD:
-			temp = q->sitd->hw_fullspeed_ep &
-				__constant_cpu_to_le32 (1 << 31);
-
-			// FIXME:  this doesn't count data bytes right...
-
-			/* is it in the S-mask?  (count SPLIT, DATA) */
-			if (q->sitd->hw_uframe & cpu_to_le32 (1 << uframe)) {
-				if (temp)
-					usecs += HS_USECS (188);
-				else
-					usecs += HS_USECS (1);
-			}
-
-			/* ... C-mask?  (count CSPLIT, DATA) */
-			if (q->sitd->hw_uframe &
-					cpu_to_le32 (1 << (8 + uframe))) {
-				if (temp)
-					usecs += HS_USECS (0);
-				else
-					usecs += HS_USECS (188);
-			}
-			q = &q->sitd->sitd_next;
-			break;
-#endif /* have_split_iso */
-		default:
-			BUG ();
-		}
-	}
-#ifdef	DEBUG
-	if (usecs > 100)
-		err ("overallocated uframe %d, periodic is %d usecs",
-			frame * 8 + uframe, usecs);
-#endif
-	return usecs;
-}
-
-/*-------------------------------------------------------------------------*/
-
-static void enable_periodic (struct ehci_hcd *ehci)
-{
-	u32	cmd;
-
-	/* did clearing PSE did take effect yet?
-	 * takes effect only at frame boundaries...
-	 */
-	while (readl (&ehci->regs->status) & STS_PSS)
-		udelay (20);
-
-	cmd = readl (&ehci->regs->command) | CMD_PSE;
-	writel (cmd, &ehci->regs->command);
-	/* posted write ... PSS happens later */
-	ehci->hcd.state = USB_STATE_RUNNING;
-
-	/* make sure tasklet scans these */
-	ehci->next_uframe = readl (&ehci->regs->frame_index)
-				% (ehci->periodic_size << 3);
-}
-
-static void disable_periodic (struct ehci_hcd *ehci)
-{
-	u32	cmd;
-
-	/* did setting PSE not take effect yet?
-	 * takes effect only at frame boundaries...
-	 */
-	while (!(readl (&ehci->regs->status) & STS_PSS))
-		udelay (20);
-
-	cmd = readl (&ehci->regs->command) & ~CMD_PSE;
-	writel (cmd, &ehci->regs->command);
-	/* posted write ... */
-
-	ehci->next_uframe = -1;
-}
-
-/*-------------------------------------------------------------------------*/
-
-static void intr_deschedule (
-	struct ehci_hcd	*ehci,
-	unsigned	frame,
-	struct ehci_qh	*qh,
-	unsigned	period
-) {
-	unsigned long	flags;
-
-	period >>= 3;		// FIXME microframe periods not handled yet
-
-	spin_lock_irqsave (&ehci->lock, flags);
-
-	do {
-		periodic_unlink (ehci, frame, qh);
-		qh_put (ehci, qh);
-		frame += period;
-	} while (frame < ehci->periodic_size);
-
-	qh->qh_state = QH_STATE_UNLINK;
-	qh->qh_next.ptr = 0;
-	ehci->periodic_urbs--;
-
-	/* maybe turn off periodic schedule */
-	if (!ehci->periodic_urbs)
-		disable_periodic (ehci);
-	else
-		vdbg ("periodic schedule still enabled");
-
-	spin_unlock_irqrestore (&ehci->lock, flags);
-
-	/*
-	 * If the hc may be looking at this qh, then delay a uframe
-	 * (yeech!) to be sure it's done.
-	 * No other threads may be mucking with this qh.
-	 */
-	if (((ehci_get_frame (&ehci->hcd) - frame) % period) == 0)
-		udelay (125);
-
-	qh->qh_state = QH_STATE_IDLE;
-	qh->hw_next = EHCI_LIST_END;
-
-	vdbg ("descheduled qh %p, per = %d frame = %d count = %d, urbs = %d",
-		qh, period, frame,
-		atomic_read (&qh->refcount), ehci->periodic_urbs);
-}
-
-static int check_period (
-	struct ehci_hcd *ehci, 
-	unsigned	frame,
-	int		uframe,
-	unsigned	period,
-	unsigned	usecs
-) {
-	/*
-	 * 80% periodic == 100 usec/uframe available
-	 * convert "usecs we need" to "max already claimed" 
-	 */
-	usecs = 100 - usecs;
-
-	do {
-		int	claimed;
-
-// FIXME delete when intr_submit handles non-empty queues
-// this gives us a one intr/frame limit (vs N/uframe)
-		if (ehci->pshadow [frame].ptr)
-			return 0;
-
-		claimed = periodic_usecs (ehci, frame, uframe);
-		if (claimed > usecs)
-			return 0;
-
-// FIXME update to handle sub-frame periods
-	} while ((frame += period) < ehci->periodic_size);
-
-	// success!
-	return 1;
-}
-
-static int intr_submit (
-	struct ehci_hcd		*ehci,
-	struct urb		*urb,
-	struct list_head	*qtd_list,
-	int			mem_flags
-) {
-	unsigned		epnum, period;
-	unsigned short		usecs;
-	unsigned long		flags;
-	struct ehci_qh		*qh;
-	struct hcd_dev		*dev;
-	int			status = 0;
-
-	/* get endpoint and transfer data */
-	epnum = usb_pipeendpoint (urb->pipe);
-	if (usb_pipein (urb->pipe))
-		epnum |= 0x10;
-	if (urb->dev->speed != USB_SPEED_HIGH) {
-		dbg ("no intr/tt scheduling yet"); 
-		status = -ENOSYS;
-		goto done;
-	}
-
-	/*
-	 * NOTE: current completion/restart logic doesn't handle more than
-	 * one qtd in a periodic qh ... 16-20 KB/urb is pretty big for this.
-	 * such big requests need many periods to transfer.
-	 *
-	 * FIXME want to change hcd core submit model to expect queuing
-	 * for all transfer types ... not just ISO and (with flag) BULK.
-	 * that means: getting rid of this check; handling the "interrupt
-	 * urb already queued" case below like bulk queuing is handled (no
-	 * errors possible!); and completly getting rid of that annoying
-	 * qh restart logic.  simpler/smaller overall, and more flexible.
-	 */
-	if (unlikely (qtd_list->next != qtd_list->prev)) {
-		dbg ("only one intr qtd per urb allowed"); 
-		status = -EINVAL;
-		goto done;
-	}
-
-	usecs = HS_USECS (urb->transfer_buffer_length);
-
-	/* FIXME handle HS periods of less than 1 frame. */
-	period = urb->interval >> 3;
-	if (period < 1) {
-		dbg ("intr period %d uframes, NYET!", urb->interval);
-		status = -EINVAL;
-		goto done;
-	}
-
-	spin_lock_irqsave (&ehci->lock, flags);
-
-	/* get the qh (must be empty and idle) */
-	dev = (struct hcd_dev *)urb->dev->hcpriv;
-	qh = (struct ehci_qh *) dev->ep [epnum];
-	if (qh) {
-		/* only allow one queued interrupt urb per EP */
-		if (unlikely (qh->qh_state != QH_STATE_IDLE
-				|| !list_empty (&qh->qtd_list))) {
-			dbg ("interrupt urb already queued");
-			status = -EBUSY;
-		} else {
-			/* maybe reset hardware's data toggle in the qh */
-			if (unlikely (!usb_gettoggle (urb->dev, epnum & 0x0f,
-					!(epnum & 0x10)))) {
-				qh->hw_token |=
-					__constant_cpu_to_le32 (QTD_TOGGLE);
-				usb_settoggle (urb->dev, epnum & 0x0f,
-					!(epnum & 0x10), 1);
-			}
-			/* trust the QH was set up as interrupt ... */
-			list_splice (qtd_list, &qh->qtd_list);
-			qh_update (qh, list_entry (qtd_list->next,
-						struct ehci_qtd, qtd_list));
-			qtd_list = &qh->qtd_list;
-		}
-	} else {
-		/* can't sleep here, we have ehci->lock... */
-		qh = ehci_qh_make (ehci, urb, qtd_list, SLAB_ATOMIC);
-		if (likely (qh != 0)) {
-			// dbg ("new INTR qh %p", qh);
-			dev->ep [epnum] = qh;
-			qtd_list = &qh->qtd_list;
-		} else
-			status = -ENOMEM;
-	}
-
-	/* Schedule this periodic QH. */
-	if (likely (status == 0)) {
-		unsigned	frame = period;
-
-		qh->hw_next = EHCI_LIST_END;
-		qh->usecs = usecs;
-
-		urb->hcpriv = qh_get (qh);
-		status = -ENOSPC;
-
-		/* pick a set of schedule slots, link the QH into them */
-		do {
-			int	uframe;
-
-			/* pick a set of slots such that all uframes have
-			 * enough periodic bandwidth available.
-			 *
-			 * FIXME for TT splits, need uframes for start and end.
-			 * FSTNs can put end into next frame (uframes 0 or 1).
-			 */
-			frame--;
-			for (uframe = 0; uframe < 8; uframe++) {
-				if (check_period (ehci, frame, uframe,
-						period, usecs) != 0)
-					break;
-			}
-			if (uframe == 8)
-				continue;
-
-			/* QH will run once each period, starting there  */
-			urb->start_frame = frame;
-			status = 0;
-
-			/* set S-frame mask */
-			qh->hw_info2 |= cpu_to_le32 (1 << uframe);
-			// dbg_qh ("Schedule INTR qh", ehci, qh);
-
-			/* stuff into the periodic schedule */
-			qh->qh_state = QH_STATE_LINKED;
-			vdbg ("qh %p usecs %d period %d starting %d.%d",
-				qh, qh->usecs, period, frame, uframe);
-			do {
-				if (unlikely (ehci->pshadow [frame].ptr != 0)) {
-// FIXME -- just link toward the end, before any qh with a shorter period,
-// AND handle it already being (implicitly) linked into this frame
-// AS WELL AS updating the check_period() logic
-					BUG ();
-				} else {
-					ehci->pshadow [frame].qh = qh_get (qh);
-					ehci->periodic [frame] =
-						QH_NEXT (qh->qh_dma);
-				}
-				wmb ();
-				frame += period;
-			} while (frame < ehci->periodic_size);
-
-			/* update bandwidth utilization records (for usbfs) */
-			usb_claim_bandwidth (urb->dev, urb, usecs/period, 0);
-
-			/* maybe enable periodic schedule processing */
-			if (!ehci->periodic_urbs++)
-				enable_periodic (ehci);
-			break;
-
-		} while (frame);
-	}
-	spin_unlock_irqrestore (&ehci->lock, flags);
-done:
-	if (status)
-		qtd_list_free (ehci, urb, qtd_list);
-
-	return status;
-}
-
-static unsigned long
-intr_complete (
-	struct ehci_hcd	*ehci,
-	unsigned	frame,
-	struct ehci_qh	*qh,
-	unsigned long	flags		/* caller owns ehci->lock ... */
-) {
-	struct ehci_qtd	*qtd;
-	struct urb	*urb;
-	int		unlinking;
-
-	/* nothing to report? */
-	if (likely ((qh->hw_token & __constant_cpu_to_le32 (QTD_STS_ACTIVE))
-			!= 0))
-		return flags;
-	if (unlikely (list_empty (&qh->qtd_list))) {
-		dbg ("intr qh %p no TDs?", qh);
-		return flags;
-	}
-	
-	qtd = list_entry (qh->qtd_list.next, struct ehci_qtd, qtd_list);
-	urb = qtd->urb;
-	unlinking = (urb->status == -ENOENT) || (urb->status == -ECONNRESET);
-
-	/* call any completions, after patching for reactivation */
-	spin_unlock_irqrestore (&ehci->lock, flags);
-	/* NOTE:  currently restricted to one qtd per qh! */
-	if (qh_completions (ehci, qh, 0) == 0)
-		urb = 0;
-	spin_lock_irqsave (&ehci->lock, flags);
-
-	/* never reactivate requests that were unlinked ... */
-	if (likely (urb != 0)) {
-		if (unlinking
-				|| urb->status == -ECONNRESET
-				|| urb->status == -ENOENT
-				// || (urb->dev == null)
-				|| ehci->hcd.state == USB_STATE_HALT)
-			urb = 0;
-		// FIXME look at all those unlink cases ... we always
-		// need exactly one completion that reports unlink.
-		// the one above might not have been it!
-	}
-
-	/* normally reactivate */
-	if (likely (urb != 0)) {
-		if (usb_pipeout (urb->pipe))
-			pci_dma_sync_single (ehci->hcd.pdev,
-				qtd->buf_dma,
-				urb->transfer_buffer_length,
-				PCI_DMA_TODEVICE);
-		urb->status = -EINPROGRESS;
-		urb->actual_length = 0;
-
-		/* patch qh and restart */
-		qh_update (qh, qtd);
-	}
-	return flags;
-}
-
-/*-------------------------------------------------------------------------*/
-
-static void
-itd_free_list (struct ehci_hcd *ehci, struct urb *urb)
-{
-	struct ehci_itd *first_itd = urb->hcpriv;
-
-	pci_unmap_single (ehci->hcd.pdev,
-		first_itd->buf_dma, urb->transfer_buffer_length,
-		usb_pipein (urb->pipe)
-		    ? PCI_DMA_FROMDEVICE
-		    : PCI_DMA_TODEVICE);
-	while (!list_empty (&first_itd->itd_list)) {
-		struct ehci_itd	*itd;
-
-		itd = list_entry (
-			first_itd->itd_list.next,
-			struct ehci_itd, itd_list);
-		list_del (&itd->itd_list);
-		pci_pool_free (ehci->itd_pool, itd, itd->itd_dma);
-	}
-	pci_pool_free (ehci->itd_pool, first_itd, first_itd->itd_dma);
-	urb->hcpriv = 0;
-}
-
-static int
-itd_fill (
-	struct ehci_hcd	*ehci,
-	struct ehci_itd	*itd,
-	struct urb	*urb,
-	unsigned	index,		// urb->iso_frame_desc [index]
-	dma_addr_t	dma		// mapped transfer buffer
-) {
-	u64		temp;
-	u32		buf1;
-	unsigned	i, epnum, maxp, multi;
-	unsigned	length;
-
-	itd->hw_next = EHCI_LIST_END;
-	itd->urb = urb;
-	itd->index = index;
-
-	/* tell itd about its transfer buffer, max 2 pages */
-	length = urb->iso_frame_desc [index].length;
-	dma += urb->iso_frame_desc [index].offset;
-	temp = dma & ~0x0fff;
-	for (i = 0; i < 2; i++) {
-		itd->hw_bufp [i] = cpu_to_le32 ((u32) temp);
-		itd->hw_bufp_hi [i] = cpu_to_le32 ((u32)(temp >> 32));
-		temp += 0x1000;
-	}
-	itd->buf_dma = dma;
-
-	/*
-	 * this might be a "high bandwidth" highspeed endpoint,
-	 * as encoded in the ep descriptor's maxpacket field
-	 */
-	epnum = usb_pipeendpoint (urb->pipe);
-	if (usb_pipein (urb->pipe)) {
-		maxp = urb->dev->epmaxpacketin [epnum];
-		buf1 = (1 << 11);
-	} else {
-		maxp = urb->dev->epmaxpacketout [epnum];
-		buf1 = 0;
-	}
-	buf1 |= (maxp & 0x03ff);
-	multi = 1;
-	multi += (maxp >> 11) & 0x03;
-	maxp &= 0x03ff;
-	maxp *= multi;
-
-	/* transfer can't fit in any uframe? */ 
-	if (length < 0 || maxp < length) {
-		dbg ("BAD iso packet: %d bytes, max %d, urb %p [%d] (of %d)",
-			length, maxp, urb, index,
-			urb->iso_frame_desc [index].length);
-		return -ENOSPC;
-	}
-	itd->usecs = HS_USECS_ISO (length);
-
-	/* "plus" info in low order bits of buffer pointers */
-	itd->hw_bufp [0] |= cpu_to_le32 ((epnum << 8) | urb->dev->devnum);
-	itd->hw_bufp [1] |= cpu_to_le32 (buf1);
-	itd->hw_bufp [2] |= cpu_to_le32 (multi);
-
-	/* figure hw_transaction[] value (it's scheduled later) */
-	itd->transaction = EHCI_ISOC_ACTIVE;
-	itd->transaction |= dma & 0x0fff;		/* offset; buffer=0 */
-	if ((index + 1) == urb->number_of_packets)
-		itd->transaction |= EHCI_ITD_IOC; 	/* end-of-urb irq */
-	itd->transaction |= length << 16;
-	cpu_to_le32s (&itd->transaction);
-
-	return 0;
-}
-
-static int
-itd_urb_transaction (
-	struct ehci_hcd		*ehci,
-	struct urb		*urb,
-	int			mem_flags
-) {
-	int			frame_index;
-	struct ehci_itd		*first_itd, *itd;
-	int			status;
-	dma_addr_t		buf_dma, itd_dma;
-
-	/* set up one dma mapping for this urb */
-	buf_dma = pci_map_single (ehci->hcd.pdev,
-		urb->transfer_buffer, urb->transfer_buffer_length,
-		usb_pipein (urb->pipe)
-		    ? PCI_DMA_FROMDEVICE
-		    : PCI_DMA_TODEVICE);
-	if (buf_dma == 0)
-		return -ENOMEM;
-
-	/* allocate/init ITDs */
-	for (frame_index = 0, first_itd = 0;
-			frame_index < urb->number_of_packets;
-			frame_index++) {
-		itd = pci_pool_alloc (ehci->itd_pool, mem_flags, &itd_dma);
-		if (!itd) {
-			status = -ENOMEM;
-			goto fail;
-		}
-		memset (itd, 0, sizeof *itd);
-		itd->itd_dma = itd_dma;
-
-		status = itd_fill (ehci, itd, urb, frame_index, buf_dma);
-		if (status != 0)
-			goto fail;
-
-		if (first_itd)
-			list_add_tail (&itd->itd_list,
-					&first_itd->itd_list);
-		else {
-			INIT_LIST_HEAD (&itd->itd_list);
-			urb->hcpriv = first_itd = itd;
-		}
-	}
-	urb->error_count = 0;
-	return 0;
-
-fail:
-	if (urb->hcpriv)
-		itd_free_list (ehci, urb);
-	return status;
-}
-
-/*-------------------------------------------------------------------------*/
-
-static inline void
-itd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_itd *itd)
-{
-	/* always prepend ITD/SITD ... only QH tree is order-sensitive */
-	itd->itd_next = ehci->pshadow [frame];
-	itd->hw_next = ehci->periodic [frame];
-	ehci->pshadow [frame].itd = itd;
-	ehci->periodic [frame] = cpu_to_le32 (itd->itd_dma) | Q_TYPE_ITD;
-}
-
-/*
- * return zero on success, else -errno
- * - start holds first uframe to start scheduling into
- * - max is the first uframe it's NOT (!) OK to start scheduling into
- * math to be done modulo "mod" (ehci->periodic_size << 3)
- */
-static int get_iso_range (
-	struct ehci_hcd		*ehci,
-	struct urb		*urb,
-	unsigned		*start,
-	unsigned		*max,
-	unsigned		mod
-) {
-	struct list_head	*lh;
-	struct hcd_dev		*dev = urb->dev->hcpriv;
-	int			last = -1;
-	unsigned		now, span, end;
-
-	span = urb->interval * urb->number_of_packets;
-
-	/* first see if we know when the next transfer SHOULD happen */
-	list_for_each (lh, &dev->urb_list) {
-		struct urb	*u;
-		struct ehci_itd	*itd;
-		unsigned	s;
-
-		u = list_entry (lh, struct urb, urb_list);
-		if (u == urb || u->pipe != urb->pipe)
-			continue;
-		if (u->interval != urb->interval) {	/* must not change! */ 
-			dbg ("urb %p interval %d ... != %p interval %d",
-				u, u->interval, urb, urb->interval);
-			return -EINVAL;
-		}
-		
-		/* URB for this endpoint... covers through when?  */
-		itd = urb->hcpriv;
-		s = itd->uframe + u->interval * u->number_of_packets;
-		if (last < 0)
-			last = s;
-		else {
-			/*
-			 * So far we can only queue two ISO URBs...
-			 *
-			 * FIXME do interval math, figure out whether
-			 * this URB is "before" or not ... also, handle
-			 * the case where the URB might have completed,
-			 * but hasn't yet been processed.
-			 */
-			dbg ("NYET: queue >2 URBs per ISO endpoint");
-			return -EDOM;
-		}
-	}
-
-	/* calculate the legal range [start,max) */
-	now = readl (&ehci->regs->frame_index) + 1;	/* next uframe */
-	if (!ehci->periodic_urbs)
-		now += 8;				/* startup delay */
-	now %= mod;
-	end = now + mod;
-	if (last < 0) {
-		*start = now + ehci->i_thresh + /* paranoia */ 1;
-		*max = end - span;
-		if (*max < *start + 1)
-			*max = *start + 1;
-	} else {
-		*start = last % mod;
-		*max = (last + 1) % mod;
-	}
-
-	/* explicit start frame? */
-	if (!(urb->transfer_flags & USB_ISO_ASAP)) {
-		unsigned	temp;
-
-		/* sanity check: must be in range */
-		urb->start_frame %= ehci->periodic_size;
-		temp = urb->start_frame << 3;
-		if (temp < *start)
-			temp += mod;
-		if (temp > *max)
-			return -EDOM;
-
-		/* use that explicit start frame */
-		*start = urb->start_frame << 3;
-		temp += 8;
-		if (temp < *max)
-			*max = temp;
-	}
-
-	// FIXME minimize wraparound to "now" ... insist max+span
-	// (and start+span) remains a few frames short of "end"
-
-	*max %= ehci->periodic_size;
-	if ((*start + span) < end)
-		return 0;
-	return -EFBIG;
-}
-
-static int
-itd_schedule (struct ehci_hcd *ehci, struct urb *urb)
-{
-	unsigned	start, max, i;
-	int		status;
-	unsigned	mod = ehci->periodic_size << 3;
-
-	for (i = 0; i < urb->number_of_packets; i++) {
-		urb->iso_frame_desc [i].status = -EINPROGRESS;
-		urb->iso_frame_desc [i].actual_length = 0;
-	}
-
-	if ((status = get_iso_range (ehci, urb, &start, &max, mod)) != 0)
-		return status;
-
-	do {
-		unsigned	uframe;
-		unsigned	usecs;
-		struct ehci_itd	*itd;
-
-		/* check schedule: enough space? */
-		itd = urb->hcpriv;
-		uframe = start;
-		for (i = 0, uframe = start;
-				i < urb->number_of_packets;
-				i++, uframe += urb->interval) {
-			uframe %= mod;
-
-			/* can't commit more than 80% periodic == 100 usec */
-			if (periodic_usecs (ehci, uframe >> 3, uframe & 0x7)
-					> (100 - itd->usecs)) {
-				itd = 0;
-				break;
-			}
-			itd = list_entry (itd->itd_list.next,
-				struct ehci_itd, itd_list);
-		}
-		if (!itd)
-			continue;
-		
-		/* that's where we'll schedule this! */
-		itd = urb->hcpriv;
-		urb->start_frame = start >> 3;
-		vdbg ("ISO urb %p (%d packets period %d) starting %d.%d",
-			urb, urb->number_of_packets, urb->interval,
-			urb->start_frame, start & 0x7);
-		for (i = 0, uframe = start, usecs = 0;
-				i < urb->number_of_packets;
-				i++, uframe += urb->interval) {
-			uframe %= mod;
-
-			itd->uframe = uframe;
-			itd->hw_transaction [uframe & 0x07] = itd->transaction;
-			itd_link (ehci, (uframe >> 3) % ehci->periodic_size,
-				itd);
-			wmb ();
-			usecs += itd->usecs;
-
-			itd = list_entry (itd->itd_list.next,
-				struct ehci_itd, itd_list);
-		}
-
-		/* update bandwidth utilization records (for usbfs)
-		 *
-		 * FIXME This claims each URB queued to an endpoint, as if
-		 * transfers were concurrent, not sequential.  So bandwidth
-		 * typically gets double-billed ... comes from tying it to
-		 * URBs rather than endpoints in the schedule.  Luckily we
-		 * don't use this usbfs data for serious decision making.
-		 */
-		usecs /= urb->number_of_packets;
-		usecs /= urb->interval;
-		usecs >>= 3;
-		if (usecs < 1)
-			usecs = 1;
-		usb_claim_bandwidth (urb->dev, urb, usecs, 1);
-
-		/* maybe enable periodic schedule processing */
-		if (!ehci->periodic_urbs++)
-			enable_periodic (ehci);
-
-		return 0;
-
-	} while ((start = ++start % mod) != max);
-
-	/* no room in the schedule */
-	dbg ("urb %p, CAN'T SCHEDULE", urb);
-	return -ENOSPC;
-}
-
-/*-------------------------------------------------------------------------*/
-
-#define	ISO_ERRS (EHCI_ISOC_BUF_ERR | EHCI_ISOC_BABBLE | EHCI_ISOC_XACTERR)
-
-static unsigned long
-itd_complete (
-	struct ehci_hcd	*ehci,
-	struct ehci_itd	*itd,
-	unsigned	uframe,
-	unsigned long	flags
-) {
-	struct urb				*urb = itd->urb;
-	struct iso_packet_descriptor		*desc;
-	u32					t;
-
-	/* update status for this uframe's transfers */
-	desc = &urb->iso_frame_desc [itd->index];
-
-	t = itd->hw_transaction [uframe];
-	itd->hw_transaction [uframe] = 0;
-	if (t & EHCI_ISOC_ACTIVE)
-		desc->status = -EXDEV;
-	else if (t & ISO_ERRS) {
-		urb->error_count++;
-		if (t & EHCI_ISOC_BUF_ERR)
-			desc->status = usb_pipein (urb->pipe)
-				? -ENOSR  /* couldn't read */
-				: -ECOMM; /* couldn't write */
-		else if (t & EHCI_ISOC_BABBLE)
-			desc->status = -EOVERFLOW;
-		else /* (t & EHCI_ISOC_XACTERR) */
-			desc->status = -EPROTO;
-
-		/* HC need not update length with this error */
-		if (!(t & EHCI_ISOC_BABBLE))
-			desc->actual_length += EHCI_ITD_LENGTH (t);
-	} else {
-		desc->status = 0;
-		desc->actual_length += EHCI_ITD_LENGTH (t);
-	}
-
-	vdbg ("itd %p urb %p packet %d/%d trans %x status %d len %d",
-		itd, urb, itd->index + 1, urb->number_of_packets,
-		t, desc->status, desc->actual_length);
-
-	/* handle completion now? */
-	if ((itd->index + 1) != urb->number_of_packets)
-		return flags;
-
-	/*
-	 * Always give the urb back to the driver ... expect it to submit
-	 * a new urb (or resubmit this), and to have another already queued
-	 * when un-interrupted transfers are needed.
-	 *
-	 * NOTE that for now we don't accelerate ISO unlinks; they just
-	 * happen according to the current schedule.  Means a delay of
-	 * up to about a second (max).
-	 */
-	itd_free_list (ehci, urb);
-	if (urb->status == -EINPROGRESS)
-		urb->status = 0;
-
-	spin_unlock_irqrestore (&ehci->lock, flags);
-	usb_hcd_giveback_urb (&ehci->hcd, urb);
-	spin_lock_irqsave (&ehci->lock, flags);
-
-	/* defer stopping schedule; completion can submit */
-	ehci->periodic_urbs--;
-	if (!ehci->periodic_urbs)
-		disable_periodic (ehci);
-
-	return flags;
-}
-
-/*-------------------------------------------------------------------------*/
-
-static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags)
-{
-	int		status;
-	unsigned long	flags;
-
-	dbg ("itd_submit urb %p", urb);
-
-	/* NOTE DMA mapping assumes this ... */
-	if (urb->iso_frame_desc [0].offset != 0)
-		return -EINVAL;
-	
-	/* allocate ITDs w/o locking anything */
-	status = itd_urb_transaction (ehci, urb, mem_flags);
-	if (status < 0)
-		return status;
-
-	/* schedule ... need to lock */
-	spin_lock_irqsave (&ehci->lock, flags);
-	status = itd_schedule (ehci, urb);
-	spin_unlock_irqrestore (&ehci->lock, flags);
-	if (status < 0)
-		itd_free_list (ehci, urb);
-
-	return status;
-}
-
-#ifdef have_split_iso
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * "Split ISO TDs" ... used for USB 1.1 devices going through
- * the TTs in USB 2.0 hubs.
- */
-
-static void
-sitd_free (struct ehci_hcd *ehci, struct ehci_sitd *sitd)
-{
-	pci_pool_free (ehci->sitd_pool, sitd, sitd->sitd_dma);
-}
-
-static struct ehci_sitd *
-sitd_make (
-	struct ehci_hcd	*ehci,
-	struct urb	*urb,
-	unsigned	index,		// urb->iso_frame_desc [index]
-	unsigned	uframe,		// scheduled start
-	dma_addr_t	dma,		// mapped transfer buffer
-	int		mem_flags
-) {
-	struct ehci_sitd	*sitd;
-	unsigned		length;
-
-	sitd = pci_pool_alloc (ehci->sitd_pool, mem_flags, &dma);
-	if (!sitd)
-		return sitd;
-	sitd->urb = urb;
-	length = urb->iso_frame_desc [index].length;
-	dma += urb->iso_frame_desc [index].offset;
-
-#if 0
-	// FIXME:  do the rest!
-#else
-	sitd_free (ehci, sitd);
-	return 0;
-#endif
-
-}
-
-static void
-sitd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_sitd *sitd)
-{
-	u32		ptr;
-
-	ptr = cpu_to_le32 (sitd->sitd_dma | 2);	// type 2 == sitd
-	if (ehci->pshadow [frame].ptr) {
-		if (!sitd->sitd_next.ptr) {
-			sitd->sitd_next = ehci->pshadow [frame];
-			sitd->hw_next = ehci->periodic [frame];
-		} else if (sitd->sitd_next.ptr != ehci->pshadow [frame].ptr) {
-			dbg ("frame %d sitd link goof", frame);
-			BUG ();
-		}
-	}
-	ehci->pshadow [frame].sitd = sitd;
-	ehci->periodic [frame] = ptr;
-}
-
-static unsigned long
-sitd_complete (
-	struct ehci_hcd *ehci,
-	struct ehci_sitd	*sitd,
-	unsigned long		flags
-) {
-	// FIXME -- implement!
-
-	dbg ("NYI -- sitd_complete");
-	return flags;
-}
-
-/*-------------------------------------------------------------------------*/
-
-static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags)
-{
-	// struct ehci_sitd	*first_sitd = 0;
-	unsigned		frame_index;
-	dma_addr_t		dma;
-
-	dbg ("NYI -- sitd_submit");
-
-	// FIXME -- implement!
-
-	// FIXME:  setup one big dma mapping
-	dma = 0;
-
-	for (frame_index = 0;
-			frame_index < urb->number_of_packets;
-			frame_index++) {
-		struct ehci_sitd	*sitd;
-		unsigned		uframe;
-
-		// FIXME:  use real arguments, schedule this!
-		uframe = -1;
-
-		sitd = sitd_make (ehci, urb, frame_index,
-				uframe, dma, mem_flags);
-
-		if (sitd) {
-    /*
-			if (first_sitd)
-				list_add_tail (&sitd->sitd_list,
-						&first_sitd->sitd_list);
-			else
-				first_sitd = sitd;
-    */
-		} else {
-			// FIXME:  clean everything up
-		}
-	}
-
-	// if we have a first sitd, then
-		// store them all into the periodic schedule!
-		// urb->hcpriv = first sitd in sitd_list
-
-	return -ENOSYS;
-}
-#endif /* have_split_iso */
-
-/*-------------------------------------------------------------------------*/
-
-static void scan_periodic (struct ehci_hcd *ehci)
-{
-	unsigned	frame, clock, now_uframe, mod;
-	unsigned long	flags;
-
-	mod = ehci->periodic_size << 3;
-	spin_lock_irqsave (&ehci->lock, flags);
-
-	/*
-	 * When running, scan from last scan point up to "now"
-	 * else clean up by scanning everything that's left.
-	 * Touches as few pages as possible:  cache-friendly.
-	 * Don't scan ISO entries more than once, though.
-	 */
-	frame = ehci->next_uframe >> 3;
-	if (HCD_IS_RUNNING (ehci->hcd.state))
-		now_uframe = readl (&ehci->regs->frame_index);
-	else
-		now_uframe = (frame << 3) - 1;
-	now_uframe %= mod;
-	clock = now_uframe >> 3;
-
-	for (;;) {
-		union ehci_shadow	q, *q_p;
-		u32			type, *hw_p;
-		unsigned		uframes;
-
-restart:
-		/* scan schedule to _before_ current frame index */
-		if (frame == clock)
-			uframes = now_uframe & 0x07;
-		else
-			uframes = 8;
-
-		q_p = &ehci->pshadow [frame];
-		hw_p = &ehci->periodic [frame];
-		q.ptr = q_p->ptr;
-		type = Q_NEXT_TYPE (*hw_p);
-
-		/* scan each element in frame's queue for completions */
-		while (q.ptr != 0) {
-			int			last;
-			unsigned		uf;
-			union ehci_shadow	temp;
-
-			switch (type) {
-			case Q_TYPE_QH:
-				last = (q.qh->hw_next == EHCI_LIST_END);
-				temp = q.qh->qh_next;
-				type = Q_NEXT_TYPE (q.qh->hw_next);
-				flags = intr_complete (ehci, frame,
-						qh_get (q.qh), flags);
-				qh_put (ehci, q.qh);
-				q = temp;
-				break;
-			case Q_TYPE_FSTN:
-				last = (q.fstn->hw_next == EHCI_LIST_END);
-				/* for "save place" FSTNs, look at QH entries
-				 * in the previous frame for completions.
-				 */
-				if (q.fstn->hw_prev != EHCI_LIST_END) {
-					dbg ("ignoring completions from FSTNs");
-				}
-				type = Q_NEXT_TYPE (q.fstn->hw_next);
-				q = q.fstn->fstn_next;
-				break;
-			case Q_TYPE_ITD:
-				last = (q.itd->hw_next == EHCI_LIST_END);
-
-				/* Unlink each (S)ITD we see, since the ISO
-				 * URB model forces constant rescheduling.
-				 * That complicates sharing uframes in ITDs,
-				 * and means we need to skip uframes the HC
-				 * hasn't yet processed.
-				 */
-				for (uf = 0; uf < uframes; uf++) {
-					if (q.itd->hw_transaction [uf] != 0) {
-						temp = q;
-						*q_p = q.itd->itd_next;
-						*hw_p = q.itd->hw_next;
-						type = Q_NEXT_TYPE (*hw_p);
-
-						/* might free q.itd ... */
-						flags = itd_complete (ehci,
-							temp.itd, uf, flags);
-						break;
-					}
-				}
-				/* we might skip this ITD's uframe ... */
-				if (uf == uframes) {
-					q_p = &q.itd->itd_next;
-					hw_p = &q.itd->hw_next;
-					type = Q_NEXT_TYPE (q.itd->hw_next);
-				}
-
-				q = *q_p;
-				break;
-#ifdef have_split_iso
-			case Q_TYPE_SITD:
-				last = (q.sitd->hw_next == EHCI_LIST_END);
-				flags = sitd_complete (ehci, q.sitd, flags);
-				type = Q_NEXT_TYPE (q.sitd->hw_next);
-
-				// FIXME unlink SITD after split completes
-				q = q.sitd->sitd_next;
-				break;
-#endif /* have_split_iso */
-			default:
-				dbg ("corrupt type %d frame %d shadow %p",
-					type, frame, q.ptr);
-				// BUG ();
-				last = 1;
-				q.ptr = 0;
-			}
-
-			/* did completion remove an interior q entry? */
-			if (unlikely (q.ptr == 0 && !last))
-				goto restart;
-		}
-
-		/* stop when we catch up to the HC */
-
-		// FIXME:  this assumes we won't get lapped when
-		// latencies climb; that should be rare, but...
-		// detect it, and just go all the way around.
-		// FLR might help detect this case, so long as latencies
-		// don't exceed periodic_size msec (default 1.024 sec).
-
-		// FIXME:  likewise assumes HC doesn't halt mid-scan
-
-		if (frame == clock) {
-			unsigned	now;
-
-			if (!HCD_IS_RUNNING (ehci->hcd.state))
-				break;
-			ehci->next_uframe = now_uframe;
-			now = readl (&ehci->regs->frame_index) % mod;
-			if (now_uframe == now)
-				break;
-
-			/* rescan the rest of this frame, then ... */
-			now_uframe = now;
-			clock = now_uframe >> 3;
-		} else
-			frame = (frame + 1) % ehci->periodic_size;
-	} 
-	spin_unlock_irqrestore (&ehci->lock, flags);
-}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/hcd/ehci.h linux-2.4.21-pre6/drivers/usb/hcd/ehci.h
--- linux-2.4.20/drivers/usb/hcd/ehci.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/hcd/ehci.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,385 +0,0 @@
-/*
- * Copyright (c) 2001-2002 by David Brownell
- * 
- * 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 __LINUX_EHCI_HCD_H
-#define __LINUX_EHCI_HCD_H
-
-/* definitions used for the EHCI driver */
-
-/* ehci_hcd->lock guards shared data against other CPUs:
- *   ehci_hcd:	async, reclaim, periodic (and shadow), ...
- *   hcd_dev:	ep[]
- *   ehci_qh:	qh_next, qtd_list
- *   ehci_qtd:	qtd_list
- *
- * Also, hold this lock when talking to HC registers or
- * when updating hw_* fields in shared qh/qtd/... structures.
- */
-
-#define	EHCI_MAX_ROOT_PORTS	15		/* see HCS_N_PORTS */
-
-struct ehci_hcd {			/* one per controller */
-	spinlock_t		lock;
-
-	/* async schedule support */
-	struct ehci_qh		*async;
-	struct ehci_qh		*reclaim;
-	int			reclaim_ready;
-
-	/* periodic schedule support */
-#define	DEFAULT_I_TDPS		1024		/* some HCs can do less */
-	unsigned		periodic_size;
-	u32			*periodic;	/* hw periodic table */
-	dma_addr_t		periodic_dma;
-	unsigned		i_thresh;	/* uframes HC might cache */
-
-	union ehci_shadow	*pshadow;	/* mirror hw periodic table */
-	int			next_uframe;	/* scan periodic, start here */
-	unsigned		periodic_urbs;	/* how many urbs scheduled? */
-
-	/* deferred work from IRQ, etc */
-	struct tasklet_struct	tasklet;
-
-	/* per root hub port */
-	unsigned long		reset_done [EHCI_MAX_ROOT_PORTS];
-
-	/* glue to PCI and HCD framework */
-	struct usb_hcd		hcd;
-	struct ehci_caps	*caps;
-	struct ehci_regs	*regs;
-	u32			hcs_params;	/* cached register copy */
-
-	/* per-HC memory pools (could be per-PCI-bus, but ...) */
-	struct pci_pool		*qh_pool;	/* qh per active urb */
-	struct pci_pool		*qtd_pool;	/* one or more per qh */
-	struct pci_pool		*itd_pool;	/* itd per iso urb */
-	struct pci_pool		*sitd_pool;	/* sitd per split iso urb */
-};
-
-/* unwrap an HCD pointer to get an EHCI_HCD pointer */ 
-#define hcd_to_ehci(hcd_ptr) list_entry(hcd_ptr, struct ehci_hcd, hcd)
-
-/* NOTE:  urb->transfer_flags expected to not use this bit !!! */
-#define EHCI_STATE_UNLINK	0x8000		/* urb being unlinked */
-
-/*-------------------------------------------------------------------------*/
-
-/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */
-
-/* Section 2.2 Host Controller Capability Registers */
-struct ehci_caps {
-	u8		length;		/* CAPLENGTH - size of this struct */
-	u8		reserved;       /* offset 0x1 */
-	u16		hci_version;    /* HCIVERSION - offset 0x2 */
-	u32		hcs_params;     /* HCSPARAMS - offset 0x4 */
-#define HCS_DEBUG_PORT(p)	(((p)>>20)&0xf)	/* bits 23:20, debug port? */
-#define HCS_INDICATOR(p)	((p)&(1 << 16))	/* true: has port indicators */
-#define HCS_N_CC(p)		(((p)>>12)&0xf)	/* bits 15:12, #companion HCs */
-#define HCS_N_PCC(p)		(((p)>>8)&0xf)	/* bits 11:8, ports per CC */
-#define HCS_PORTROUTED(p)	((p)&(1 << 7))	/* true: port routing */ 
-#define HCS_PPC(p)		((p)&(1 << 4))	/* true: port power control */ 
-#define HCS_N_PORTS(p)		(((p)>>0)&0xf)	/* bits 3:0, ports on HC */
-
-	u32		hcc_params;      /* HCCPARAMS - offset 0x8 */
-#define HCC_EXT_CAPS(p)		(((p)>>8)&0xff)	/* for pci extended caps */
-#define HCC_ISOC_CACHE(p)       ((p)&(1 << 7))  /* true: can cache isoc frame */
-#define HCC_ISOC_THRES(p)       (((p)>>4)&0x7)  /* bits 6:4, uframes cached */
-#define HCC_CANPARK(p)		((p)&(1 << 2))  /* true: can park on async qh */
-#define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1))  /* true: periodic_size changes*/
-#define HCC_64BIT_ADDR(p)       ((p)&(1))       /* true: can use 64-bit addr */
-	u8		portroute [8];	 /* nibbles for routing - offset 0xC */
-} __attribute__ ((packed));
-
-
-/* Section 2.3 Host Controller Operational Registers */
-struct ehci_regs {
-
-	/* USBCMD: offset 0x00 */
-	u32		command;
-/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */
-#define CMD_PARK	(1<<11)		/* enable "park" on async qh */
-#define CMD_PARK_CNT(c)	(((c)>>8)&3)	/* how many transfers to park for */
-#define CMD_LRESET	(1<<7)		/* partial reset (no ports, etc) */
-#define CMD_IAAD	(1<<6)		/* "doorbell" interrupt async advance */
-#define CMD_ASE		(1<<5)		/* async schedule enable */
-#define CMD_PSE  	(1<<4)		/* periodic schedule enable */
-/* 3:2 is periodic frame list size */
-#define CMD_RESET	(1<<1)		/* reset HC not bus */
-#define CMD_RUN		(1<<0)		/* start/stop HC */
-
-	/* USBSTS: offset 0x04 */
-	u32		status;
-#define STS_ASS		(1<<15)		/* Async Schedule Status */
-#define STS_PSS		(1<<14)		/* Periodic Schedule Status */
-#define STS_RECL	(1<<13)		/* Reclamation */
-#define STS_HALT	(1<<12)		/* Not running (any reason) */
-/* some bits reserved */
-	/* these STS_* flags are also intr_enable bits (USBINTR) */
-#define STS_IAA		(1<<5)		/* Interrupted on async advance */
-#define STS_FATAL	(1<<4)		/* such as some PCI access errors */
-#define STS_FLR		(1<<3)		/* frame list rolled over */
-#define STS_PCD		(1<<2)		/* port change detect */
-#define STS_ERR		(1<<1)		/* "error" completion (overflow, ...) */
-#define STS_INT		(1<<0)		/* "normal" completion (short, ...) */
-
-	/* USBINTR: offset 0x08 */
-	u32		intr_enable;
-
-	/* FRINDEX: offset 0x0C */
-	u32		frame_index;	/* current microframe number */
-	/* CTRLDSSEGMENT: offset 0x10 */
-	u32		segment; 	/* address bits 63:32 if needed */
-	/* PERIODICLISTBASE: offset 0x14 */
-	u32		frame_list; 	/* points to periodic list */
-	/* ASYNCICLISTADDR: offset 0x18 */
-	u32		async_next;	/* address of next async queue head */
-
-	u32		reserved [9];
-
-	/* CONFIGFLAG: offset 0x40 */
-	u32		configured_flag;
-#define FLAG_CF		(1<<0)		/* true: we'll support "high speed" */
-
-	/* PORTSC: offset 0x44 */
-	u32		port_status [0];	/* up to N_PORTS */
-/* 31:23 reserved */
-#define PORT_WKOC_E	(1<<22)		/* wake on overcurrent (enable) */
-#define PORT_WKDISC_E	(1<<21)		/* wake on disconnect (enable) */
-#define PORT_WKCONN_E	(1<<20)		/* wake on connect (enable) */
-/* 19:16 for port testing */
-/* 15:14 for using port indicator leds (if HCS_INDICATOR allows) */
-#define PORT_OWNER	(1<<13)		/* true: companion hc owns this port */
-#define PORT_POWER	(1<<12)		/* true: has power (see PPC) */
-#define PORT_USB11(x) (((x)&(3<<10))==(1<<10))	/* USB 1.1 device */
-/* 11:10 for detecting lowspeed devices (reset vs release ownership) */
-/* 9 reserved */
-#define PORT_RESET	(1<<8)		/* reset port */
-#define PORT_SUSPEND	(1<<7)		/* suspend port */
-#define PORT_RESUME	(1<<6)		/* resume it */
-#define PORT_OCC	(1<<5)		/* over current change */
-#define PORT_OC		(1<<4)		/* over current active */
-#define PORT_PEC	(1<<3)		/* port enable change */
-#define PORT_PE		(1<<2)		/* port enable */
-#define PORT_CSC	(1<<1)		/* connect status change */
-#define PORT_CONNECT	(1<<0)		/* device connected */
-} __attribute__ ((packed));
-
-
-/*-------------------------------------------------------------------------*/
-
-#define	QTD_NEXT(dma)	cpu_to_le32((u32)dma)
-
-/*
- * EHCI Specification 0.95 Section 3.5
- * QTD: describe data transfer components (buffer, direction, ...) 
- * See Fig 3-6 "Queue Element Transfer Descriptor Block Diagram".
- *
- * These are associated only with "QH" (Queue Head) structures,
- * used with control, bulk, and interrupt transfers.
- */
-struct ehci_qtd {
-	/* first part defined by EHCI spec */
-	u32			hw_next;	  /* see EHCI 3.5.1 */
-	u32			hw_alt_next;      /* see EHCI 3.5.2 */
-	u32			hw_token;         /* see EHCI 3.5.3 */       
-#define	QTD_TOGGLE	(1 << 31)	/* data toggle */
-#define	QTD_LENGTH(tok)	(((tok)>>16) & 0x7fff)
-#define	QTD_IOC		(1 << 15)	/* interrupt on complete */
-#define	QTD_CERR(tok)	(((tok)>>10) & 0x3)
-#define	QTD_PID(tok)	(((tok)>>8) & 0x3)
-#define	QTD_STS_ACTIVE	(1 << 7)	/* HC may execute this */
-#define	QTD_STS_HALT	(1 << 6)	/* halted on error */
-#define	QTD_STS_DBE	(1 << 5)	/* data buffer error (in HC) */
-#define	QTD_STS_BABBLE	(1 << 4)	/* device was babbling (qtd halted) */
-#define	QTD_STS_XACT	(1 << 3)	/* device gave illegal response */
-#define	QTD_STS_MMF	(1 << 2)	/* incomplete split transaction */
-#define	QTD_STS_STS	(1 << 1)	/* split transaction state */
-#define	QTD_STS_PING	(1 << 0)	/* issue PING? */
-	u32			hw_buf [5];        /* see EHCI 3.5.4 */
-	u32			hw_buf_hi [5];        /* Appendix B */
-
-	/* the rest is HCD-private */
-	dma_addr_t		qtd_dma;		/* qtd address */
-	struct list_head	qtd_list;		/* sw qtd list */
-
-	/* dma same in urb's qtds, except 1st control qtd (setup buffer) */
-	struct urb		*urb;			/* qtd's urb */
-	dma_addr_t		buf_dma;		/* buffer address */
-	size_t			length;			/* length of buffer */
-} __attribute__ ((aligned (32)));
-
-/*-------------------------------------------------------------------------*/
-
-/* type tag from {qh,itd,sitd,fstn}->hw_next */
-#define Q_NEXT_TYPE(dma) ((dma) & __constant_cpu_to_le32 (3 << 1))
-
-/* values for that type tag */
-#define Q_TYPE_ITD	__constant_cpu_to_le32 (0 << 1)
-#define Q_TYPE_QH	__constant_cpu_to_le32 (1 << 1)
-#define Q_TYPE_SITD 	__constant_cpu_to_le32 (2 << 1)
-#define Q_TYPE_FSTN 	__constant_cpu_to_le32 (3 << 1)
-
-/* next async queue entry, or pointer to interrupt/periodic QH */
-#define	QH_NEXT(dma)	(cpu_to_le32(((u32)dma)&~0x01f)|Q_TYPE_QH)
-
-/* for periodic/async schedules and qtd lists, mark end of list */
-#define	EHCI_LIST_END	__constant_cpu_to_le32(1) /* "null pointer" to hw */
-
-/*
- * Entries in periodic shadow table are pointers to one of four kinds
- * of data structure.  That's dictated by the hardware; a type tag is
- * encoded in the low bits of the hardware's periodic schedule.  Use
- * Q_NEXT_TYPE to get the tag.
- *
- * For entries in the async schedule, the type tag always says "qh".
- */
-union ehci_shadow {
-	struct ehci_qh 		*qh;		/* Q_TYPE_QH */
-	struct ehci_itd		*itd;		/* Q_TYPE_ITD */
-	struct ehci_sitd	*sitd;		/* Q_TYPE_SITD */
-	struct ehci_fstn	*fstn;		/* Q_TYPE_FSTN */
-	void			*ptr;
-};
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * EHCI Specification 0.95 Section 3.6
- * QH: describes control/bulk/interrupt endpoints
- * See Fig 3-7 "Queue Head Structure Layout".
- *
- * These appear in both the async and (for interrupt) periodic schedules.
- */
-
-struct ehci_qh {
-	/* first part defined by EHCI spec */
-	u32			hw_next;	 /* see EHCI 3.6.1 */
-	u32			hw_info1;        /* see EHCI 3.6.2 */
-#define	QH_HEAD		0x00008000
-	u32			hw_info2;        /* see EHCI 3.6.2 */
-	u32			hw_current;	 /* qtd list - see EHCI 3.6.4 */
-	
-	/* qtd overlay (hardware parts of a struct ehci_qtd) */
-	u32			hw_qtd_next;
-	u32			hw_alt_next;
-	u32			hw_token;
-	u32			hw_buf [5];
-	u32			hw_buf_hi [5];
-
-	/* the rest is HCD-private */
-	dma_addr_t		qh_dma;		/* address of qh */
-	union ehci_shadow	qh_next;	/* ptr to qh; or periodic */
-	struct list_head	qtd_list;	/* sw qtd list */
-
-	atomic_t		refcount;
-	unsigned short		usecs;		/* intr bandwidth */
-	short			qh_state;
-#define	QH_STATE_LINKED		1		/* HC sees this */
-#define	QH_STATE_UNLINK		2		/* HC may still see this */
-#define	QH_STATE_IDLE		3		/* HC doesn't see this */
-
-#ifdef EHCI_SOFT_RETRIES
-	int			retries;
-#endif
-} __attribute__ ((aligned (32)));
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * EHCI Specification 0.95 Section 3.3
- * Fig 3-4 "Isochronous Transaction Descriptor (iTD)"
- *
- * Schedule records for high speed iso xfers
- */
-struct ehci_itd {
-	/* first part defined by EHCI spec */
-	u32			hw_next;           /* see EHCI 3.3.1 */
-	u32			hw_transaction [8]; /* see EHCI 3.3.2 */
-#define EHCI_ISOC_ACTIVE        (1<<31)        /* activate transfer this slot */
-#define EHCI_ISOC_BUF_ERR       (1<<30)        /* Data buffer error */
-#define EHCI_ISOC_BABBLE        (1<<29)        /* babble detected */
-#define EHCI_ISOC_XACTERR       (1<<28)        /* XactErr - transaction error */
-#define	EHCI_ITD_LENGTH(tok)	(((tok)>>16) & 0x7fff)
-#define	EHCI_ITD_IOC		(1 << 15)	/* interrupt on complete */
-
-	u32			hw_bufp [7];	/* see EHCI 3.3.3 */ 
-	u32			hw_bufp_hi [7];	/* Appendix B */
-
-	/* the rest is HCD-private */
-	dma_addr_t		itd_dma;	/* for this itd */
-	union ehci_shadow	itd_next;	/* ptr to periodic q entry */
-
-	struct urb		*urb;
-	struct list_head	itd_list;	/* list of urb frames' itds */
-	dma_addr_t		buf_dma;	/* frame's buffer address */
-
-	/* for now, only one hw_transaction per itd */
-	u32			transaction;
-	u16			index;		/* in urb->iso_frame_desc */
-	u16			uframe;		/* in periodic schedule */
-	u16			usecs;
-} __attribute__ ((aligned (32)));
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * EHCI Specification 0.95 Section 3.4 
- * siTD, aka split-transaction isochronous Transfer Descriptor
- *       ... describe low/full speed iso xfers through TT in hubs
- * see Figure 3-5 "Split-transaction Isochronous Transaction Descriptor (siTD)
- */
-struct ehci_sitd {
-	/* first part defined by EHCI spec */
-	u32			hw_next;
-/* uses bit field macros above - see EHCI 0.95 Table 3-8 */
-	u32			hw_fullspeed_ep;  /* see EHCI table 3-9 */
-	u32                     hw_uframe;        /* see EHCI table 3-10 */
-        u32                     hw_tx_results1;   /* see EHCI table 3-11 */
-	u32                     hw_tx_results2;   /* see EHCI table 3-12 */
-	u32                     hw_tx_results3;   /* see EHCI table 3-12 */
-        u32                     hw_backpointer;   /* see EHCI table 3-13 */
-	u32			hw_buf_hi [2];	  /* Appendix B */
-
-	/* the rest is HCD-private */
-	dma_addr_t		sitd_dma;
-	union ehci_shadow	sitd_next;	/* ptr to periodic q entry */
-	struct urb		*urb;
-	dma_addr_t		buf_dma;	/* buffer address */
-} __attribute__ ((aligned (32)));
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * EHCI Specification 0.96 Section 3.7
- * Periodic Frame Span Traversal Node (FSTN)
- *
- * Manages split interrupt transactions (using TT) that span frame boundaries
- * into uframes 0/1; see 4.12.2.2.  In those uframes, a "save place" FSTN
- * makes the HC jump (back) to a QH to scan for fs/ls QH completions until
- * it hits a "restore" FSTN; then it returns to finish other uframe 0/1 work.
- */
-struct ehci_fstn {
-	u32			hw_next;	/* any periodic q entry */
-	u32			hw_prev;	/* qh or EHCI_LIST_END */
-
-	/* the rest is HCD-private */
-	dma_addr_t		fstn_dma;
-	union ehci_shadow	fstn_next;	/* ptr to periodic q entry */
-} __attribute__ ((aligned (32)));
-
-#endif /* __LINUX_EHCI_HCD_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/hcd.c linux-2.4.21-pre6/drivers/usb/hcd.c
--- linux-2.4.20/drivers/usb/hcd.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/hcd.c	2003-03-26 23:49:35.000000000 +0000
@@ -296,7 +296,7 @@
 
 	// serial number
 	} else if (id == 1) {
-		strcpy (buf, hcd->bus_name);
+		strcpy (buf, hcd->bus->bus_name);
 
 	// product description
 	} else if (id == 2) {
@@ -311,9 +311,9 @@
 	} else
 	    return 0;
 
-	data [0] = 2 + ascii2utf (buf, data + 2, len - 2);
+	data [0] = 2 * (strlen (buf) + 1);
 	data [1] = 3;	/* type == string */
-	return data [0];
+	return 2 + ascii2utf (buf, data + 2, len - 2);
 }
 
 
@@ -392,7 +392,7 @@
 	case DeviceOutRequest | USB_REQ_SET_ADDRESS:
 		// wValue == urb->dev->devaddr
 		dbg ("%s root hub device address %d",
-			hcd->bus_name, wValue);
+			hcd->bus->bus_name, wValue);
 		break;
 
 	/* INTERFACE REQUESTS (no defined feature/status flags) */
@@ -437,7 +437,7 @@
 	}
 
 	/* any errors get returned through the urb completion */
-	usb_hcd_giveback_urb (hcd, urb);
+	usb_hcd_giveback_urb (hcd, urb, 0);
 	return 0;
 }
 
@@ -506,7 +506,7 @@
 					&& rh_status_urb (hcd, urb) != 0) {
 				/* another driver snuck in? */
 				dbg ("%s, can't resubmit roothub status urb?",
-					hcd->bus_name);
+					hcd->bus->bus_name);
 				spin_unlock_irqrestore (&hcd_data_lock, flags);
 				BUG ();
 			}
@@ -518,7 +518,7 @@
 		urb->hcpriv = 0;
 		spin_unlock_irqrestore (&urb->lock, flags);
 
-		usb_hcd_giveback_urb (hcd, urb);
+		usb_hcd_giveback_urb (hcd, urb, 0);
 	}
 }
 
@@ -553,7 +553,7 @@
 	spin_unlock_irqrestore (&hcd_data_lock, flags);
 
 	/* we rely on RH callback code not unlinking its URB! */
-	usb_hcd_giveback_urb (hcd, urb);
+	usb_hcd_giveback_urb (hcd, urb, 0);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -663,7 +663,8 @@
 	hcd->driver = driver;
 	hcd->description = driver->description;
 	hcd->pdev = dev;
-	info ("%s @ %s, %s", hcd->description,  dev->slot_name, dev->name);
+	printk (KERN_INFO "%s %s: %s\n",
+			hcd->description,  dev->slot_name, dev->name);
 
 #ifndef __sparc__
 	sprintf (buf, "%d", dev->irq);
@@ -682,11 +683,13 @@
 
 	hcd->regs = base;
 	hcd->region = region;
-	info ("irq %s, %s %p", bufp,
+	printk (KERN_INFO "%s %s: irq %s, %s %p\n",
+		hcd->description,  dev->slot_name, bufp,
 		(driver->flags & HCD_MEMORY) ? "pci mem" : "io base",
 		base);
 
 // FIXME simpler: make "bus" be that data, not pointer to it.
+// (fixed in 2.5)
 	bus = usb_alloc_bus (&hcd_operations);
 	if (bus == NULL) {
 		dbg ("usb_alloc_bus fail");
@@ -695,7 +698,6 @@
 		goto clean_3;
 	}
 	hcd->bus = bus;
-	hcd->bus_name = dev->slot_name;		/* prefer bus->bus_name */
 	bus->bus_name = dev->slot_name;
 	hcd->product_desc = dev->name;
 	bus->hcpriv = (void *) hcd;
@@ -739,14 +741,15 @@
 	hcd = pci_get_drvdata(dev);
 	if (!hcd)
 		return;
-	info ("remove: %s, state %x", hcd->bus_name, hcd->state);
+	printk (KERN_INFO "%s %s: remove state %x\n",
+		hcd->description,  dev->slot_name, hcd->state);
 
 	if (in_interrupt ()) BUG ();
 
 	hub = hcd->bus->root_hub;
 	hcd->state = USB_STATE_QUIESCING;
 
-	dbg ("%s: roothub graceful disconnect", hcd->bus_name);
+	dbg ("%s: roothub graceful disconnect", hcd->bus->bus_name);
 	usb_disconnect (&hub);
 	// usb_disconnect (&hcd->bus->root_hub);
 
@@ -817,7 +820,8 @@
 	int			retval;
 
 	hcd = pci_get_drvdata(dev);
-	info ("suspend %s to state %d", hcd->bus_name, state);
+	printk (KERN_INFO "%s %s: suspend to state %d\n",
+		hcd->description,  dev->slot_name, state);
 
 	pci_save_state (dev, hcd->pci_state);
 
@@ -846,12 +850,13 @@
 	int			retval;
 
 	hcd = pci_get_drvdata(dev);
-	info ("resume %s", hcd->bus_name);
+	printk (KERN_INFO "%s %s: resume\n",
+		hcd->description,  dev->slot_name);
 
 	/* guard against multiple resumes (APM bug?) */
 	atomic_inc (&hcd->resume_count);
 	if (atomic_read (&hcd->resume_count) != 1) {
-		err ("concurrent PCI resumes for %s", hcd->bus_name);
+		err ("concurrent PCI resumes for %s", hcd->bus->bus_name);
 		retval = 0;
 		goto done;
 	}
@@ -868,7 +873,8 @@
 
 	retval = hcd->driver->resume (hcd);
 	if (!HCD_IS_RUNNING (hcd->state)) {
-		dbg ("resume %s failure, retval %d", hcd->bus_name, retval);
+		dbg ("resume %s failure, retval %d",
+			hcd->bus->bus_name, retval);
 		hc_died (hcd);
 // FIXME:  recover, reset etc.
 	} else {
@@ -929,6 +935,12 @@
 
 /*-------------------------------------------------------------------------*/
 
+static void hcd_panic (void *_hcd)
+{
+	struct usb_hcd *hcd = _hcd;
+	hcd->driver->stop (hcd);
+}
+
 static void hc_died (struct usb_hcd *hcd)
 {
 	struct list_head	*devlist, *urblist;
@@ -943,7 +955,8 @@
 		list_for_each (urblist, &dev->urb_list) {
 			urb = list_entry (urblist, struct urb, urb_list);
 			dbg ("shutdown %s urb %p pipe %x, current status %d",
-				hcd->bus_name, urb, urb->pipe, urb->status);
+				hcd->bus->bus_name,
+				urb, urb->pipe, urb->status);
 			if (urb->status == -EINPROGRESS)
 				urb->status = -ESHUTDOWN;
 		}
@@ -955,7 +968,10 @@
 
 	if (urb)
 		rh_status_dequeue (hcd, urb);
-	hcd->driver->stop (hcd);
+
+	/* hcd->stop() needs a task context */
+	INIT_TQUEUE (&hcd->work, hcd_panic, hcd);
+	(void) schedule_task (&hcd->work);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -1067,8 +1083,6 @@
 	if (urb->transfer_buffer_length < 0)
 		return -EINVAL;
 
-	// FIXME set urb->transfer_dma and/or setup_dma 
-
 	if (urb->next) {
 		warn ("use explicit queuing not urb->next");
 		return -EINVAL;
@@ -1186,16 +1200,26 @@
 	if (status)
 		return status;
 
+	// NOTE:  2.5 does this if !URB_NO_DMA_MAP transfer flag
+	if (usb_pipecontrol (urb->pipe))
+		urb->setup_dma = pci_map_single (
+				hcd->pdev,
+				urb->setup_packet,
+				sizeof (struct usb_ctrlrequest),
+				PCI_DMA_TODEVICE);
+	if (urb->transfer_buffer_length != 0)
+		urb->transfer_dma = pci_map_single (
+				hcd->pdev,
+				urb->transfer_buffer,
+				urb->transfer_buffer_length,
+				usb_pipein (urb->pipe)
+				    ? PCI_DMA_FROMDEVICE
+				    : PCI_DMA_TODEVICE);
+
 	if (urb->dev == hcd->bus->root_hub)
 		status = rh_urb_enqueue (hcd, urb);
 	else
 		status = hcd->driver->urb_enqueue (hcd, urb, mem_flags);
-	/* urb->dev got nulled if hcd called giveback for us
-	 * NOTE: ref to urb->dev is a race without (2.5) refcounting,
-	 * unless driver only returns status when it didn't giveback 
-	 */
-	if (status && urb->dev)
-		urb_unlink (urb);
 	return status;
 }
 
@@ -1282,25 +1306,25 @@
 		goto done;
 	}
 
-	/* For non-periodic transfers, any status except -EINPROGRESS means
-	 * the HCD has already started to unlink this URB from the hardware.
-	 * In that case, there's no more work to do.
+	/* Any status except -EINPROGRESS means the HCD has already started
+	 * to return this URB to the driver.  In that case, there's no
+	 * more work for us to do.
 	 *
-	 * For periodic transfers, this is the only way to trigger unlinking
-	 * from the hardware.  Since we (currently) overload urb->status to
-	 * tell the driver to unlink, error status might get clobbered ...
-	 * unless that transfer hasn't yet restarted.  One such case is when
-	 * the URB gets unlinked from its completion handler.
+	 * There's much magic because of "automagic resubmit" of interrupt
+	 * transfers, stopped only by explicit unlinking.  We won't issue
+	 * an "it's unlinked" callback more than once, but device drivers
+	 * can need to retry (SMP, -EAGAIN) an unlink request as well as
+	 * fake out the "not yet completed" state (set -EINPROGRESS) if
+	 * unlinking from complete().  Automagic eventually vanishes.
 	 *
 	 * FIXME use an URB_UNLINKED flag to match URB_TIMEOUT_KILLED
 	 */
-	switch (usb_pipetype (urb->pipe)) {
-	case PIPE_CONTROL:
-	case PIPE_BULK:
-		if (urb->status != -EINPROGRESS) {
-			retval = -EINVAL;
-			goto done;
-		}
+	if (urb->status != -EINPROGRESS) {
+		if (usb_pipetype (urb->pipe) == PIPE_INTERRUPT)
+			retval = -EAGAIN;
+		else
+			retval = -EBUSY;
+		goto done;
 	}
 
 	/* maybe set up to block on completion notification */
@@ -1339,8 +1363,6 @@
 	if (!(urb->transfer_flags & (USB_ASYNC_UNLINK|USB_TIMEOUT_KILLED))
 			&& HCD_IS_RUNNING (hcd->state)
 			&& !retval) {
-		dbg ("%s: wait for giveback urb %p",
-			hcd->bus_name, urb);
 		wait_for_completion (&splice.done);
 	} else if ((urb->transfer_flags & USB_ASYNC_UNLINK) && retval == 0) {
 		return -EINPROGRESS;
@@ -1352,7 +1374,7 @@
 bye:
 	if (retval)
 		dbg ("%s: hcd_unlink_urb fail %d",
-		    hcd ? hcd->bus_name : "(no bus?)",
+		    hcd ? hcd->bus->bus_name : "(no bus?)",
 		    retval);
 	return retval;
 }
@@ -1385,7 +1407,7 @@
 	/* device driver problem with refcounts? */
 	if (!list_empty (&dev->urb_list)) {
 		dbg ("free busy dev, %s devnum %d (bug!)",
-			hcd->bus_name, udev->devnum);
+			hcd->bus->bus_name, udev->devnum);
 		return -EINVAL;
 	}
 
@@ -1418,7 +1440,7 @@
 	if (unlikely (hcd->state == USB_STATE_HALT))	/* irq sharing? */
 		return;
 
-	hcd->driver->irq (hcd);
+	hcd->driver->irq (hcd, r);
 	if (hcd->state != start && hcd->state == USB_STATE_HALT)
 		hc_died (hcd);
 }
@@ -1429,6 +1451,7 @@
  * usb_hcd_giveback_urb - return URB from HCD to device driver
  * @hcd: host controller returning the URB
  * @urb: urb being returned to the USB device driver.
+ * @regs: saved hardware registers (ignored on 2.4 kernels)
  * Context: in_interrupt()
  *
  * This hands the URB from HCD to its USB device driver, using its
@@ -1446,7 +1469,7 @@
  * ISO streaming functionality can be achieved by having completion handlers
  * re-queue URBs.  Such explicit queuing doesn't discard error reports.
  */
-void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
+void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs)
 {
 	urb_unlink (urb);
 
@@ -1456,11 +1479,17 @@
 	// completions for periodic urbs need hooks inside the HCD.
 	// hcd_monitor_hook(MONITOR_URB_UPDATE, urb, dev)
 
-	if (urb->status)
-		dbg ("giveback urb %p status %d len %d",
-			urb, urb->status, urb->actual_length);
-
-	// FIXME unmap urb->transfer_dma and/or setup_dma 
+	// NOTE:  2.5 does this if !URB_NO_DMA_MAP transfer flag
+	if (usb_pipecontrol (urb->pipe))
+		pci_unmap_single (hcd->pdev, urb->setup_dma,
+				sizeof (struct usb_ctrlrequest),
+				PCI_DMA_TODEVICE);
+	if (urb->transfer_buffer_length != 0)
+		pci_unmap_single (hcd->pdev, urb->transfer_dma,
+				urb->transfer_buffer_length,
+				usb_pipein (urb->pipe)
+				    ? PCI_DMA_FROMDEVICE
+				    : PCI_DMA_TODEVICE);
 
 	/* pass ownership to the completion handler */
 	urb->complete (urb);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/hcd.h linux-2.4.21-pre6/drivers/usb/hcd.h
--- linux-2.4.20/drivers/usb/hcd.h	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/hcd.h	2003-03-26 23:49:00.000000000 +0000
@@ -36,12 +36,12 @@
 	struct usb_bus		*bus;		/* hcd is-a bus */
 	struct list_head	hcd_list;
 
-	const char		*bus_name;
 	const char		*product_desc;
 	const char		*description;	/* "ehci-hcd" etc */
 
 	struct timer_list	rh_timer;	/* drives root hub */
 	struct list_head	dev_list;	/* devices on this bus */
+	struct tq_struct	work;
 
 	/*
 	 * hardware info/state
@@ -104,7 +104,7 @@
 	const char	*description;	/* "ehci-hcd" etc */
 
 	/* irq handler */
-	void	(*irq) (struct usb_hcd *hcd);
+	void	(*irq) (struct usb_hcd *hcd, struct pt_regs *regs);
 
 	int	flags;
 #define	HCD_MEMORY	0x0001		/* HC regs use memory (else I/O) */
@@ -149,7 +149,8 @@
 				char *buf, u16 wLength);
 };
 
-extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb);
+extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb,
+		struct pt_regs *regs);
 
 #ifdef CONFIG_PCI
 
@@ -283,3 +284,5 @@
 usb_hub_tt_clear_buffer (struct usb_device *dev, int pipe)
 	{ }
 
+#define URB_ZERO_PACKET	USB_ZERO_PACKET
+#define URB_ISO_ASAP	USB_ISO_ASAP
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/hid-core.c linux-2.4.21-pre6/drivers/usb/hid-core.c
--- linux-2.4.20/drivers/usb/hid-core.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/hid-core.c	2003-03-26 23:49:40.000000000 +0000
@@ -1080,12 +1080,28 @@
 #define USB_DEVICE_ID_WACOM_PL		0x0030
 #define USB_DEVICE_ID_WACOM_INTUOS2	0x0041
 
+#define USB_VENDOR_ID_KBGEAR		0x084e
+#define USB_DEVICE_ID_KBGEAR_JAMSTUDIO	0x1001
+
 #define USB_VENDOR_ID_ATEN		0x0557
 #define USB_DEVICE_ID_ATEN_UC100KM	0x2004
 #define USB_DEVICE_ID_ATEN_CS124U	0x2202
 #define USB_DEVICE_ID_ATEN_2PORTKVM	0x2204
 #define USB_DEVICE_ID_ATEN_4PORTKVM	0x2205
 
+#define USB_VENDOR_ID_GRIFFIN		0x077d
+#define USB_DEVICE_ID_POWERMATE		0x0410 /* Griffin PowerMate */
+#define USB_DEVICE_ID_SOUNDKNOB		0x04AA /* Griffin SoundKnob */
+
+#define USB_VENDOR_ID_ONTRAK	0x0a07
+#define USB_DEVICE_ID_ONTRAK_ADU100	0x0064
+
+#define USB_VENDOR_ID_TANGTOP		0x0d3d
+#define USB_DEVICE_ID_TANGTOP_USBPS2	0x0001
+
+#define USB_VENDOR_ID_OKI		0x070a
+#define USB_VENDOR_ID_OKI_MULITI	0x0007
+
 struct hid_blacklist {
 	__u16 idVendor;
 	__u16 idProduct;
@@ -1111,10 +1127,21 @@
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 2, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 3, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 4, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET },
+	{ USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE },
+ 	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100, HID_QUIRK_IGNORE },
+ 	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 100, HID_QUIRK_IGNORE },
+ 	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 200, HID_QUIRK_IGNORE },
+ 	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 300, HID_QUIRK_IGNORE },
+ 	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 400, HID_QUIRK_IGNORE },
+ 	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500, HID_QUIRK_IGNORE },
+ 	{ USB_VENDOR_ID_TANGTOP, USB_DEVICE_ID_TANGTOP_USBPS2, HID_QUIRK_NOGET },
+	{ USB_VENDOR_ID_OKI, USB_VENDOR_ID_OKI_MULITI, HID_QUIRK_NOGET },
 	{ 0, 0 }
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/host/Config.in linux-2.4.21-pre6/drivers/usb/host/Config.in
--- linux-2.4.20/drivers/usb/host/Config.in	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/host/Config.in	2003-03-26 23:49:55.000000000 +0000
@@ -0,0 +1,15 @@
+#
+# USB Host Controller Drivers
+#
+comment 'USB Host Controller Drivers'
+dep_tristate '  EHCI HCD (USB 2.0) support (EXPERIMENTAL)' CONFIG_USB_EHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
+if [ "$CONFIG_USB_UHCI_ALT" != "y" ]; then
+   dep_tristate '  UHCI (Intel PIIX4, VIA, ...) support' CONFIG_USB_UHCI $CONFIG_USB
+fi
+if [ "$CONFIG_USB_UHCI" != "y" ]; then
+   dep_tristate '  UHCI Alternate Driver (JE) support' CONFIG_USB_UHCI_ALT $CONFIG_USB
+else
+   define_bool CONFIG_USB_UHCI_ALT n
+fi
+dep_tristate '  OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI $CONFIG_USB
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/host/Makefile linux-2.4.21-pre6/drivers/usb/host/Makefile
--- linux-2.4.20/drivers/usb/host/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/host/Makefile	2003-03-26 23:49:19.000000000 +0000
@@ -0,0 +1,28 @@
+#
+# Makefile for USB Host Controller Driver
+# framework and drivers
+#
+
+O_TARGET	:=
+
+obj-$(CONFIG_USB_EHCI_HCD)			+= ehci-hcd.o
+obj-$(CONFIG_USB_UHCI_ALT)			+= uhci.o
+obj-$(CONFIG_USB_UHCI)				+= usb-uhci.o
+obj-$(CONFIG_USB_OHCI)				+= usb-ohci.o
+
+# Extract lists of the multi-part drivers.
+# The 'int-*' lists are the intermediate files used to build the multi's.
+multi-y		:= $(filter $(list-multi), $(obj-y))
+multi-m		:= $(filter $(list-multi), $(obj-m))
+int-y		:= $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
+int-m		:= $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
+
+# Take multi-part drivers out of obj-y and put components in.
+obj-y		:= $(filter-out $(list-multi), $(obj-y)) $(int-y)
+
+# Translate to Rules.make lists.
+OX_OBJS		:= $(obj-y)
+MX_OBJS		:= $(obj-m)
+MIX_OBJS	:= $(int-m)
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/host/ehci-dbg.c linux-2.4.21-pre6/drivers/usb/host/ehci-dbg.c
--- linux-2.4.20/drivers/usb/host/ehci-dbg.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/host/ehci-dbg.c	2003-03-26 23:49:39.000000000 +0000
@@ -0,0 +1,652 @@
+/*
+ * Copyright (c) 2001-2002 by David Brownell
+ * 
+ * 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 file is part of ehci-hcd.c */
+
+#ifdef DEBUG
+#define ehci_dbg(ehci, fmt, args...) \
+	printk(KERN_DEBUG "%s %s: " fmt , hcd_name , \
+		(ehci)->hcd.pdev->slot_name , ## args )
+#else
+#define ehci_dbg(ehci, fmt, args...) do { } while (0)
+#endif
+
+#define ehci_err(ehci, fmt, args...) \
+	printk(KERN_ERR "%s %s: " fmt , hcd_name , \
+		(ehci)->hcd.pdev->slot_name , ## args )
+#define ehci_info(ehci, fmt, args...) \
+	printk(KERN_INFO "%s %s: " fmt , hcd_name , \
+		(ehci)->hcd.pdev->slot_name , ## args )
+#define ehci_warn(ehci, fmt, args...) \
+	printk(KERN_WARNING "%s %s: " fmt , hcd_name , \
+		(ehci)->hcd.pdev->slot_name , ## args )
+
+
+#ifdef EHCI_VERBOSE_DEBUG
+#	define vdbg dbg
+#	define ehci_vdbg ehci_dbg
+#else
+#	define vdbg(fmt,args...) do { } while (0)
+#	define ehci_vdbg(ehci, fmt, args...) do { } while (0)
+#endif
+
+#ifdef	DEBUG
+
+/* check the values in the HCSPARAMS register
+ * (host controller _Structural_ parameters)
+ * see EHCI spec, Table 2-4 for each value
+ */
+static void dbg_hcs_params (struct ehci_hcd *ehci, char *label)
+{
+	u32	params = readl (&ehci->caps->hcs_params);
+
+	ehci_dbg (ehci,
+		"%s hcs_params 0x%x dbg=%d%s cc=%d pcc=%d%s%s ports=%d\n",
+		label, params,
+		HCS_DEBUG_PORT (params),
+		HCS_INDICATOR (params) ? " ind" : "",
+		HCS_N_CC (params),
+		HCS_N_PCC (params),
+	        HCS_PORTROUTED (params) ? "" : " ordered",
+		HCS_PPC (params) ? "" : " !ppc",
+		HCS_N_PORTS (params)
+		);
+	/* Port routing, per EHCI 0.95 Spec, Section 2.2.5 */
+	if (HCS_PORTROUTED (params)) {
+		int i;
+		char buf [46], tmp [7], byte;
+
+		buf[0] = 0;
+		for (i = 0; i < HCS_N_PORTS (params); i++) {
+			byte = readb (&ehci->caps->portroute[(i>>1)]);
+			sprintf(tmp, "%d ", 
+				((i & 0x1) ? ((byte)&0xf) : ((byte>>4)&0xf)));
+			strcat(buf, tmp);
+		}
+		ehci_dbg (ehci, "%s portroute %s\n",
+				label, buf);
+	}
+}
+#else
+
+static inline void dbg_hcs_params (struct ehci_hcd *ehci, char *label) {}
+
+#endif
+
+#ifdef	DEBUG
+
+/* check the values in the HCCPARAMS register
+ * (host controller _Capability_ parameters)
+ * see EHCI Spec, Table 2-5 for each value
+ * */
+static void dbg_hcc_params (struct ehci_hcd *ehci, char *label)
+{
+	u32	params = readl (&ehci->caps->hcc_params);
+
+	if (HCC_ISOC_CACHE (params)) {
+		ehci_dbg (ehci,
+		     "%s hcc_params %04x caching frame %s%s%s\n",
+		     label, params,
+		     HCC_PGM_FRAMELISTLEN (params) ? "256/512/1024" : "1024",
+		     HCC_CANPARK (params) ? " park" : "",
+		     HCC_64BIT_ADDR (params) ? " 64 bit addr" : "");
+	} else {
+		ehci_dbg (ehci,
+		     "%s hcc_params %04x thresh %d uframes %s%s%s\n",
+		     label,
+		     params,
+		     HCC_ISOC_THRES (params),
+		     HCC_PGM_FRAMELISTLEN (params) ? "256/512/1024" : "1024",
+		     HCC_CANPARK (params) ? " park" : "",
+		     HCC_64BIT_ADDR (params) ? " 64 bit addr" : "");
+	}
+}
+#else
+
+static inline void dbg_hcc_params (struct ehci_hcd *ehci, char *label) {}
+
+#endif
+
+#ifdef	DEBUG
+
+static void __attribute__((__unused__))
+dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+	dbg ("%s %p info1 %x info2 %x hw_curr %x qtd_next %x", label,
+		qh, qh->hw_info1, qh->hw_info2,
+		qh->hw_current, qh->hw_qtd_next);
+	dbg ("  alt+errs= %x, token= %x, page0= %x, page1= %x",
+		qh->hw_alt_next, qh->hw_token,
+		qh->hw_buf [0], qh->hw_buf [1]);
+	if (qh->hw_buf [2]) {
+		dbg ("  page2= %x, page3= %x, page4= %x",
+			qh->hw_buf [2], qh->hw_buf [3],
+			qh->hw_buf [4]);
+	}
+}
+
+static int __attribute__((__unused__))
+dbg_status_buf (char *buf, unsigned len, char *label, u32 status)
+{
+	return snprintf (buf, len,
+		"%s%sstatus %04x%s%s%s%s%s%s%s%s%s%s",
+		label, label [0] ? " " : "", status,
+		(status & STS_ASS) ? " Async" : "",
+		(status & STS_PSS) ? " Periodic" : "",
+		(status & STS_RECL) ? " Recl" : "",
+		(status & STS_HALT) ? " Halt" : "",
+		(status & STS_IAA) ? " IAA" : "",
+		(status & STS_FATAL) ? " FATAL" : "",
+		(status & STS_FLR) ? " FLR" : "",
+		(status & STS_PCD) ? " PCD" : "",
+		(status & STS_ERR) ? " ERR" : "",
+		(status & STS_INT) ? " INT" : ""
+		);
+}
+
+static int __attribute__((__unused__))
+dbg_intr_buf (char *buf, unsigned len, char *label, u32 enable)
+{
+	return snprintf (buf, len,
+		"%s%sintrenable %02x%s%s%s%s%s%s",
+		label, label [0] ? " " : "", enable,
+		(enable & STS_IAA) ? " IAA" : "",
+		(enable & STS_FATAL) ? " FATAL" : "",
+		(enable & STS_FLR) ? " FLR" : "",
+		(enable & STS_PCD) ? " PCD" : "",
+		(enable & STS_ERR) ? " ERR" : "",
+		(enable & STS_INT) ? " INT" : ""
+		);
+}
+
+static const char *const fls_strings [] =
+    { "1024", "512", "256", "??" };
+
+static int dbg_command_buf (char *buf, unsigned len, char *label, u32 command)
+{
+	return snprintf (buf, len,
+		"%s%scommand %06x %s=%d ithresh=%d%s%s%s%s period=%s%s %s",
+		label, label [0] ? " " : "", command,
+		(command & CMD_PARK) ? "park" : "(park)",
+		CMD_PARK_CNT (command),
+		(command >> 16) & 0x3f,
+		(command & CMD_LRESET) ? " LReset" : "",
+		(command & CMD_IAAD) ? " IAAD" : "",
+		(command & CMD_ASE) ? " Async" : "",
+		(command & CMD_PSE) ? " Periodic" : "",
+		fls_strings [(command >> 2) & 0x3],
+		(command & CMD_RESET) ? " Reset" : "",
+		(command & CMD_RUN) ? "RUN" : "HALT"
+		);
+}
+
+static int
+dbg_port_buf (char *buf, unsigned len, char *label, int port, u32 status)
+{
+	char	*sig;
+
+	/* signaling state */
+	switch (status & (3 << 10)) {
+	case 0 << 10: sig = "se0"; break;
+	case 1 << 10: sig = "k"; break;		/* low speed */
+	case 2 << 10: sig = "j"; break;
+	default: sig = "?"; break;
+	}
+
+	return snprintf (buf, len,
+		"%s%sport %d status %06x%s%s sig=%s %s%s%s%s%s%s%s%s%s",
+		label, label [0] ? " " : "", port, status,
+		(status & PORT_POWER) ? " POWER" : "",
+		(status & PORT_OWNER) ? " OWNER" : "",
+		sig,
+		(status & PORT_RESET) ? " RESET" : "",
+		(status & PORT_SUSPEND) ? " SUSPEND" : "",
+		(status & PORT_RESUME) ? " RESUME" : "",
+		(status & PORT_OCC) ? " OCC" : "",
+		(status & PORT_OC) ? " OC" : "",
+		(status & PORT_PEC) ? " PEC" : "",
+		(status & PORT_PE) ? " PE" : "",
+		(status & PORT_CSC) ? " CSC" : "",
+		(status & PORT_CONNECT) ? " CONNECT" : ""
+	    );
+}
+
+#else
+static inline void __attribute__((__unused__))
+dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
+{}
+
+static inline int __attribute__((__unused__))
+dbg_status_buf (char *buf, unsigned len, char *label, u32 status)
+{ return 0; }
+
+static inline int __attribute__((__unused__))
+dbg_command_buf (char *buf, unsigned len, char *label, u32 command)
+{ return 0; }
+
+static inline int __attribute__((__unused__))
+dbg_intr_buf (char *buf, unsigned len, char *label, u32 enable)
+{ return 0; }
+
+static inline int __attribute__((__unused__))
+dbg_port_buf (char *buf, unsigned len, char *label, int port, u32 status)
+{ return 0; }
+
+#endif	/* DEBUG */
+
+/* functions have the "wrong" filename when they're output... */
+#define dbg_status(ehci, label, status) { \
+	char _buf [80]; \
+	dbg_status_buf (_buf, sizeof _buf, label, status); \
+	ehci_dbg (ehci, "%s\n", _buf); \
+}
+
+#define dbg_cmd(ehci, label, command) { \
+	char _buf [80]; \
+	dbg_command_buf (_buf, sizeof _buf, label, command); \
+	ehci_dbg (ehci, "%s\n", _buf); \
+}
+
+#define dbg_port(ehci, label, port, status) { \
+	char _buf [80]; \
+	dbg_port_buf (_buf, sizeof _buf, label, port, status); \
+	ehci_dbg (ehci, "%s\n", _buf); \
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef STUB_DEBUG_FILES
+
+static inline void create_debug_files (struct ehci_hcd *bus) { }
+static inline void remove_debug_files (struct ehci_hcd *bus) { }
+
+#else
+
+/* troubleshooting help: expose state in driverfs */
+
+#define speed_char(info1) ({ char tmp; \
+		switch (info1 & (3 << 12)) { \
+		case 0 << 12: tmp = 'f'; break; \
+		case 1 << 12: tmp = 'l'; break; \
+		case 2 << 12: tmp = 'h'; break; \
+		default: tmp = '?'; break; \
+		}; tmp; })
+
+static inline char token_mark (u32 token)
+{
+	token = le32_to_cpu (token);
+	if (token & QTD_STS_ACTIVE)
+		return '*';
+	if (token & QTD_STS_HALT)
+		return '-';
+	if (QTD_PID (token) != 1 /* not IN: OUT or SETUP */
+			|| QTD_LENGTH (token) == 0)
+		return ' ';
+	/* tries to advance through hw_alt_next */
+	return '/';
+}
+
+static void qh_lines (
+	struct ehci_hcd *ehci,
+	struct ehci_qh *qh,
+	char **nextp,
+	unsigned *sizep
+)
+{
+	u32			scratch;
+	u32			hw_curr;
+	struct list_head	*entry;
+	struct ehci_qtd		*td;
+	unsigned		temp;
+	unsigned		size = *sizep;
+	char			*next = *nextp;
+	char			mark;
+
+	mark = token_mark (qh->hw_token);
+	if (mark == '/') {	/* qh_alt_next controls qh advance? */
+		if ((qh->hw_alt_next & QTD_MASK) == ehci->async->hw_alt_next)
+			mark = '#';	/* blocked */
+		else if (qh->hw_alt_next & cpu_to_le32 (0x01))
+			mark = '.';	/* use hw_qtd_next */
+		/* else alt_next points to some other qtd */
+	}
+	scratch = cpu_to_le32p (&qh->hw_info1);
+	hw_curr = (mark == '*') ? cpu_to_le32p (&qh->hw_current) : 0;
+	temp = snprintf (next, size,
+			"qh/%p dev%d %cs ep%d %08x %08x (%08x%c %s nak%d)",
+			qh, scratch & 0x007f,
+			speed_char (scratch),
+			(scratch >> 8) & 0x000f,
+			scratch, cpu_to_le32p (&qh->hw_info2),
+			cpu_to_le32p (&qh->hw_token), mark,
+			(cpu_to_le32 (0x8000000) & qh->hw_token)
+				? "data0" : "data1",
+			(cpu_to_le32p (&qh->hw_alt_next) >> 1) & 0x0f);
+	size -= temp;
+	next += temp;
+
+	/* hc may be modifying the list as we read it ... */
+	list_for_each (entry, &qh->qtd_list) {
+		td = list_entry (entry, struct ehci_qtd, qtd_list);
+		scratch = cpu_to_le32p (&td->hw_token);
+		mark = ' ';
+		if (hw_curr == td->qtd_dma)
+			mark = '*';
+		else if (qh->hw_qtd_next == td->qtd_dma)
+			mark = '+';
+		else if (QTD_LENGTH (scratch)) {
+			if (td->hw_alt_next == ehci->async->hw_alt_next)
+				mark = '#';
+			else if (td->hw_alt_next != EHCI_LIST_END)
+				mark = '/';
+		}
+		temp = snprintf (next, size,
+				"\n\t%p%c%s len=%d %08x urb %p",
+				td, mark, ({ char *tmp;
+				 switch ((scratch>>8)&0x03) {
+				 case 0: tmp = "out"; break;
+				 case 1: tmp = "in"; break;
+				 case 2: tmp = "setup"; break;
+				 default: tmp = "?"; break;
+				 } tmp;}),
+				(scratch >> 16) & 0x7fff,
+				scratch,
+				td->urb);
+		if (temp < 0)
+			temp = 0;
+		else if (size < temp)
+			temp = size;
+		size -= temp;
+		next += temp;
+		if (temp == size)
+			goto done;
+	}
+
+	temp = snprintf (next, size, "\n");
+	if (temp < 0)
+		temp = 0;
+	else if (size < temp)
+		temp = size;
+	size -= temp;
+	next += temp;
+
+done:
+	*sizep = size;
+	*nextp = next;
+}
+
+static ssize_t
+show_async (struct device *dev, char *buf)
+{
+	struct pci_dev		*pdev;
+	struct ehci_hcd		*ehci;
+	unsigned long		flags;
+	unsigned		temp, size;
+	char			*next;
+	struct ehci_qh		*qh;
+
+	pdev = container_of (dev, struct pci_dev, dev);
+	ehci = container_of (pci_get_drvdata (pdev), struct ehci_hcd, hcd);
+	next = buf;
+	size = PAGE_SIZE;
+
+	/* dumps a snapshot of the async schedule.
+	 * usually empty except for long-term bulk reads, or head.
+	 * one QH per line, and TDs we know about
+	 */
+	spin_lock_irqsave (&ehci->lock, flags);
+	for (qh = ehci->async->qh_next.qh; size > 0 && qh; qh = qh->qh_next.qh)
+		qh_lines (ehci, qh, &next, &size);
+	if (ehci->reclaim && size > 0) {
+		temp = snprintf (next, size, "\nreclaim =\n");
+		size -= temp;
+		next += temp;
+
+		for (qh = ehci->reclaim; size > 0 && qh; qh = qh->reclaim)
+			qh_lines (ehci, qh, &next, &size);
+	}
+	spin_unlock_irqrestore (&ehci->lock, flags);
+
+	return PAGE_SIZE - size;
+}
+static DEVICE_ATTR (async, S_IRUGO, show_async, NULL);
+
+#define DBG_SCHED_LIMIT 64
+
+static ssize_t
+show_periodic (struct device *dev, char *buf)
+{
+	struct pci_dev		*pdev;
+	struct ehci_hcd		*ehci;
+	unsigned long		flags;
+	union ehci_shadow	p, *seen;
+	unsigned		temp, size, seen_count;
+	char			*next;
+	unsigned		i, tag;
+
+	if (!(seen = kmalloc (DBG_SCHED_LIMIT * sizeof *seen, SLAB_ATOMIC)))
+		return 0;
+	seen_count = 0;
+
+	pdev = container_of (dev, struct pci_dev, dev);
+	ehci = container_of (pci_get_drvdata (pdev), struct ehci_hcd, hcd);
+	next = buf;
+	size = PAGE_SIZE;
+
+	temp = snprintf (next, size, "size = %d\n", ehci->periodic_size);
+	size -= temp;
+	next += temp;
+
+	/* dump a snapshot of the periodic schedule.
+	 * iso changes, interrupt usually doesn't.
+	 */
+	spin_lock_irqsave (&ehci->lock, flags);
+	for (i = 0; i < ehci->periodic_size; i++) {
+		p = ehci->pshadow [i];
+		if (!p.ptr)
+			continue;
+		tag = Q_NEXT_TYPE (ehci->periodic [i]);
+
+		temp = snprintf (next, size, "%4d: ", i);
+		size -= temp;
+		next += temp;
+
+		do {
+			switch (tag) {
+			case Q_TYPE_QH:
+				temp = snprintf (next, size, " qh%d/%p",
+						p.qh->period, p.qh);
+				size -= temp;
+				next += temp;
+				for (temp = 0; temp < seen_count; temp++) {
+					if (seen [temp].ptr == p.ptr)
+						break;
+				}
+				/* show more info the first time around */
+				if (temp == seen_count) {
+					u32	scratch = cpu_to_le32p (
+							&p.qh->hw_info1);
+
+					temp = snprintf (next, size,
+						" (%cs dev%d ep%d [%d/%d] %d)",
+						speed_char (scratch),
+						scratch & 0x007f,
+						(scratch >> 8) & 0x000f,
+						p.qh->usecs, p.qh->c_usecs,
+						0x7ff & (scratch >> 16));
+
+					/* FIXME TD info too */
+
+					if (seen_count < DBG_SCHED_LIMIT)
+						seen [seen_count++].qh = p.qh;
+				} else
+					temp = 0;
+				tag = Q_NEXT_TYPE (p.qh->hw_next);
+				p = p.qh->qh_next;
+				break;
+			case Q_TYPE_FSTN:
+				temp = snprintf (next, size,
+					" fstn-%8x/%p", p.fstn->hw_prev,
+					p.fstn);
+				tag = Q_NEXT_TYPE (p.fstn->hw_next);
+				p = p.fstn->fstn_next;
+				break;
+			case Q_TYPE_ITD:
+				temp = snprintf (next, size,
+					" itd/%p", p.itd);
+				tag = Q_NEXT_TYPE (p.itd->hw_next);
+				p = p.itd->itd_next;
+				break;
+			case Q_TYPE_SITD:
+				temp = snprintf (next, size,
+					" sitd/%p", p.sitd);
+				tag = Q_NEXT_TYPE (p.sitd->hw_next);
+				p = p.sitd->sitd_next;
+				break;
+			}
+			size -= temp;
+			next += temp;
+		} while (p.ptr);
+
+		temp = snprintf (next, size, "\n");
+		size -= temp;
+		next += temp;
+	}
+	spin_unlock_irqrestore (&ehci->lock, flags);
+	kfree (seen);
+
+	return PAGE_SIZE - size;
+}
+static DEVICE_ATTR (periodic, S_IRUGO, show_periodic, NULL);
+
+#undef DBG_SCHED_LIMIT
+
+static ssize_t
+show_registers (struct device *dev, char *buf)
+{
+	struct pci_dev		*pdev;
+	struct ehci_hcd		*ehci;
+	unsigned long		flags;
+	unsigned		temp, size, i;
+	char			*next, scratch [80];
+	static char		fmt [] = "%*s\n";
+	static char		label [] = "";
+
+	pdev = container_of (dev, struct pci_dev, dev);
+	ehci = container_of (pci_get_drvdata (pdev), struct ehci_hcd, hcd);
+
+	next = buf;
+	size = PAGE_SIZE;
+
+	spin_lock_irqsave (&ehci->lock, flags);
+
+	/* Capability Registers */
+	i = readw (&ehci->caps->hci_version);
+	temp = snprintf (next, size,
+		"EHCI %x.%02x, hcd state %d (version " DRIVER_VERSION ")\n",
+		i >> 8, i & 0x0ff, ehci->hcd.state);
+	size -= temp;
+	next += temp;
+
+	// FIXME interpret both types of params
+	i = readl (&ehci->caps->hcs_params);
+	temp = snprintf (next, size, "structural params 0x%08x\n", i);
+	size -= temp;
+	next += temp;
+
+	i = readl (&ehci->caps->hcc_params);
+	temp = snprintf (next, size, "capability params 0x%08x\n", i);
+	size -= temp;
+	next += temp;
+
+	/* Operational Registers */
+	temp = dbg_status_buf (scratch, sizeof scratch, label,
+			readl (&ehci->regs->status));
+	temp = snprintf (next, size, fmt, temp, scratch);
+	size -= temp;
+	next += temp;
+
+	temp = dbg_command_buf (scratch, sizeof scratch, label,
+			readl (&ehci->regs->command));
+	temp = snprintf (next, size, fmt, temp, scratch);
+	size -= temp;
+	next += temp;
+
+	temp = dbg_intr_buf (scratch, sizeof scratch, label,
+			readl (&ehci->regs->intr_enable));
+	temp = snprintf (next, size, fmt, temp, scratch);
+	size -= temp;
+	next += temp;
+
+	temp = snprintf (next, size, "uframe %04x\n",
+			readl (&ehci->regs->frame_index));
+	size -= temp;
+	next += temp;
+
+	for (i = 0; i < HCS_N_PORTS (ehci->hcs_params); i++) {
+		temp = dbg_port_buf (scratch, sizeof scratch, label, i,
+				readl (&ehci->regs->port_status [i]));
+		temp = snprintf (next, size, fmt, temp, scratch);
+		size -= temp;
+		next += temp;
+	}
+
+	if (ehci->reclaim) {
+		temp = snprintf (next, size, "reclaim qh %p%s\n",
+				ehci->reclaim,
+				ehci->reclaim_ready ? " ready" : "");
+		size -= temp;
+		next += temp;
+	}
+
+#ifdef EHCI_STATS
+	temp = snprintf (next, size,
+		"irq normal %ld err %ld reclaim %ld (lost %ld)\n",
+		ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim,
+		ehci->stats.lost_iaa);
+	size -= temp;
+	next += temp;
+
+	temp = snprintf (next, size, "complete %ld unlink %ld\n",
+		ehci->stats.complete, ehci->stats.unlink);
+	size -= temp;
+	next += temp;
+#endif
+
+	spin_unlock_irqrestore (&ehci->lock, flags);
+
+	return PAGE_SIZE - size;
+}
+static DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL);
+
+static inline void create_debug_files (struct ehci_hcd *bus)
+{
+	device_create_file (&bus->hcd.pdev->dev, &dev_attr_async);
+	device_create_file (&bus->hcd.pdev->dev, &dev_attr_periodic);
+	device_create_file (&bus->hcd.pdev->dev, &dev_attr_registers);
+}
+
+static inline void remove_debug_files (struct ehci_hcd *bus)
+{
+	device_remove_file (&bus->hcd.pdev->dev, &dev_attr_async);
+	device_remove_file (&bus->hcd.pdev->dev, &dev_attr_periodic);
+	device_remove_file (&bus->hcd.pdev->dev, &dev_attr_registers);
+}
+
+#endif /* STUB_DEBUG_FILES */
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/host/ehci-hcd.c linux-2.4.21-pre6/drivers/usb/host/ehci-hcd.c
--- linux-2.4.20/drivers/usb/host/ehci-hcd.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/host/ehci-hcd.c	2003-03-26 23:49:38.000000000 +0000
@@ -0,0 +1,1054 @@
+/*
+ * Copyright (c) 2000-2002 by David Brownell
+ * 
+ * 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/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+
+#ifdef CONFIG_USB_DEBUG
+	#define DEBUG
+#else
+	#undef DEBUG
+#endif
+
+#include <linux/usb.h>
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,32)
+#include "../hcd.h"
+#else
+#include "../core/hcd.h"
+#endif
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI hc_driver implementation ... experimental, incomplete.
+ * Based on the final 1.0 register interface specification.
+ *
+ * USB 2.0 shows up in upcoming www.pcmcia.org technology.
+ * First was PCMCIA, like ISA; then CardBus, which is PCI.
+ * Next comes "CardBay", using USB 2.0 signals.
+ *
+ * Contains additional contributions by Brad Hards, Rory Bolt, and others.
+ * Special thanks to Intel and VIA for providing host controllers to
+ * test this driver on, and Cypress (including In-System Design) for
+ * providing early devices for those host controllers to talk to!
+ *
+ * HISTORY:
+ *
+ * 2002-11-29	Correct handling for hw async_next register.
+ * 2002-08-06	Handling for bulk and interrupt transfers is mostly shared;
+ *	only scheduling is different, no arbitrary limitations.
+ * 2002-07-25	Sanity check PCI reads, mostly for better cardbus support,
+ * 	clean up HC run state handshaking.
+ * 2002-05-24	Preliminary FS/LS interrupts, using scheduling shortcuts
+ * 2002-05-11	Clear TT errors for FS/LS ctrl/bulk.  Fill in some other
+ *	missing pieces:  enabling 64bit dma, handoff from BIOS/SMM.
+ * 2002-05-07	Some error path cleanups to report better errors; wmb();
+ *	use non-CVS version id; better iso bandwidth claim.
+ * 2002-04-19	Control/bulk/interrupt submit no longer uses giveback() on
+ *	errors in submit path.  Bugfixes to interrupt scheduling/processing.
+ * 2002-03-05	Initial high-speed ISO support; reduce ITD memory; shift
+ *	more checking to generic hcd framework (db).  Make it work with
+ *	Philips EHCI; reduce PCI traffic; shorten IRQ path (Rory Bolt).
+ * 2002-01-14	Minor cleanup; version synch.
+ * 2002-01-08	Fix roothub handoff of FS/LS to companion controllers.
+ * 2002-01-04	Control/Bulk queuing behaves.
+ *
+ * 2001-12-12	Initial patch version for Linux 2.5.1 kernel.
+ * 2001-June	Works with usb-storage and NEC EHCI on 2.4
+ */
+
+#define DRIVER_VERSION "2003-Jan-22"
+#define DRIVER_AUTHOR "David Brownell"
+#define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
+
+static const char	hcd_name [] = "ehci-hcd";
+
+
+// #define EHCI_VERBOSE_DEBUG
+// #define have_split_iso
+
+#ifdef DEBUG
+#define EHCI_STATS
+#endif
+
+#define INTR_AUTOMAGIC		/* urb lifecycle mode, gone in 2.5 */
+
+/* magic numbers that can affect system performance */
+#define	EHCI_TUNE_CERR		3	/* 0-3 qtd retries; 0 == don't stop */
+#define	EHCI_TUNE_RL_HS		4	/* nak throttle; see 4.9 */
+#define	EHCI_TUNE_RL_TT		0
+#define	EHCI_TUNE_MULT_HS	1	/* 1-3 transactions/uframe; 4.10.3 */
+#define	EHCI_TUNE_MULT_TT	1
+#define	EHCI_TUNE_FLS		2	/* (small) 256 frame schedule */
+
+#define EHCI_WATCHDOG_JIFFIES	(HZ/100)	/* arbitrary; ~10 msec */
+#define EHCI_ASYNC_JIFFIES	(HZ/20)		/* async idle timeout */
+
+/* Initial IRQ latency:  lower than default */
+static int log2_irq_thresh = 0;		// 0 to 6
+MODULE_PARM (log2_irq_thresh, "i");
+MODULE_PARM_DESC (log2_irq_thresh, "log2 IRQ latency, 1-64 microframes");
+
+#define	INTR_MASK (STS_IAA | STS_FATAL | STS_ERR | STS_INT)
+
+/*-------------------------------------------------------------------------*/
+
+#include "ehci.h"
+#include "ehci-dbg.c"
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * handshake - spin reading hc until handshake completes or fails
+ * @ptr: address of hc register to be read
+ * @mask: bits to look at in result of read
+ * @done: value of those bits when handshake succeeds
+ * @usec: timeout in microseconds
+ *
+ * Returns negative errno, or zero on success
+ *
+ * Success happens when the "mask" bits have the specified value (hardware
+ * handshake done).  There are two failure modes:  "usec" have passed (major
+ * hardware flakeout), or the register reads as all-ones (hardware removed).
+ *
+ * That last failure should_only happen in cases like physical cardbus eject
+ * before driver shutdown. But it also seems to be caused by bugs in cardbus
+ * bridge shutdown:  shutting down the bridge before the devices using it.
+ */
+static int handshake (u32 *ptr, u32 mask, u32 done, int usec)
+{
+	u32	result;
+
+	do {
+		result = readl (ptr);
+		if (result == ~(u32)0)		/* card removed */
+			return -ENODEV;
+		result &= mask;
+		if (result == done)
+			return 0;
+		udelay (1);
+		usec--;
+	} while (usec > 0);
+	return -ETIMEDOUT;
+}
+
+/*
+ * hc states include: unknown, halted, ready, running
+ * transitional states are messy just now
+ * trying to avoid "running" unless urbs are active
+ * a "ready" hc can be finishing prefetched work
+ */
+
+/* force HC to halt state from unknown (EHCI spec section 2.3) */
+static int ehci_halt (struct ehci_hcd *ehci)
+{
+	u32	temp = readl (&ehci->regs->status);
+
+	if ((temp & STS_HALT) != 0)
+		return 0;
+
+	temp = readl (&ehci->regs->command);
+	temp &= ~CMD_RUN;
+	writel (temp, &ehci->regs->command);
+	return handshake (&ehci->regs->status, STS_HALT, STS_HALT, 16 * 125);
+}
+
+/* reset a non-running (STS_HALT == 1) controller */
+static int ehci_reset (struct ehci_hcd *ehci)
+{
+	u32	command = readl (&ehci->regs->command);
+
+	command |= CMD_RESET;
+	dbg_cmd (ehci, "reset", command);
+	writel (command, &ehci->regs->command);
+	ehci->hcd.state = USB_STATE_HALT;
+	return handshake (&ehci->regs->command, CMD_RESET, 0, 250 * 1000);
+}
+
+/* idle the controller (from running) */
+static void ehci_ready (struct ehci_hcd *ehci)
+{
+	u32	temp;
+
+#ifdef DEBUG
+	if (!HCD_IS_RUNNING (ehci->hcd.state))
+		BUG ();
+#endif
+
+	/* wait for any schedule enables/disables to take effect */
+	temp = 0;
+	if (ehci->async->qh_next.qh)
+		temp = STS_ASS;
+	if (ehci->next_uframe != -1)
+		temp |= STS_PSS;
+	if (handshake (&ehci->regs->status, STS_ASS | STS_PSS,
+				temp, 16 * 125) != 0) {
+		ehci->hcd.state = USB_STATE_HALT;
+		return;
+	}
+
+	/* then disable anything that's still active */
+	temp = readl (&ehci->regs->command);
+	temp &= ~(CMD_ASE | CMD_IAAD | CMD_PSE);
+	writel (temp, &ehci->regs->command);
+
+	/* hardware can take 16 microframes to turn off ... */
+	if (handshake (&ehci->regs->status, STS_ASS | STS_PSS,
+				0, 16 * 125) != 0) {
+		ehci->hcd.state = USB_STATE_HALT;
+		return;
+	}
+	ehci->hcd.state = USB_STATE_READY;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#include "ehci-hub.c"
+#include "ehci-mem.c"
+#include "ehci-q.c"
+#include "ehci-sched.c"
+
+/*-------------------------------------------------------------------------*/
+
+static void ehci_work(struct ehci_hcd *ehci, struct pt_regs *regs);
+
+static void ehci_watchdog (unsigned long param)
+{
+	struct ehci_hcd		*ehci = (struct ehci_hcd *) param;
+	unsigned long		flags;
+
+	spin_lock_irqsave (&ehci->lock, flags);
+
+	/* lost IAA irqs wedge things badly; seen with a vt8235 */
+	if (ehci->reclaim) {
+		u32		status = readl (&ehci->regs->status);
+
+		if (status & STS_IAA) {
+			ehci_vdbg (ehci, "lost IAA\n");
+			COUNT (ehci->stats.lost_iaa);
+			writel (STS_IAA, &ehci->regs->status);
+			ehci->reclaim_ready = 1;
+		}
+	}
+
+	ehci_work (ehci, NULL);
+	if (ehci->reclaim && !timer_pending (&ehci->watchdog))
+		mod_timer (&ehci->watchdog,
+				jiffies + EHCI_WATCHDOG_JIFFIES);
+
+ 	/* stop async processing after it's idled a while */
+	else if (ehci->async_idle) {
+ 		start_unlink_async (ehci, ehci->async);
+ 		ehci->async_idle = 0;
+	}
+	spin_unlock_irqrestore (&ehci->lock, flags);
+}
+
+/* EHCI 0.96 (and later) section 5.1 says how to kick BIOS/SMM/...
+ * off the controller (maybe it can boot from highspeed USB disks).
+ */
+static int bios_handoff (struct ehci_hcd *ehci, int where, u32 cap)
+{
+	if (cap & (1 << 16)) {
+		int msec = 500;
+
+		/* request handoff to OS */
+		cap &= 1 << 24;
+		pci_write_config_dword (ehci->hcd.pdev, where, cap);
+
+		/* and wait a while for it to happen */
+		do {
+			wait_ms (10);
+			msec -= 10;
+			pci_read_config_dword (ehci->hcd.pdev, where, &cap);
+		} while ((cap & (1 << 16)) && msec);
+		if (cap & (1 << 16)) {
+			ehci_err (ehci, "BIOS handoff failed (%d, %04x)\n",
+				where, cap);
+			return 1;
+		} 
+		ehci_dbg (ehci, "BIOS handoff succeeded\n");
+	}
+	return 0;
+}
+
+static int
+ehci_reboot (struct notifier_block *self, unsigned long code, void *null)
+{
+	struct ehci_hcd		*ehci;
+
+	ehci = container_of (self, struct ehci_hcd, reboot_notifier);
+
+	/* make BIOS/etc use companion controller during reboot */
+	writel (0, &ehci->regs->configured_flag);
+	return 0;
+}
+
+
+/* called by khubd or root hub init threads */
+
+static int ehci_start (struct usb_hcd *hcd)
+{
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+	u32			temp;
+	struct usb_device	*udev;
+	struct usb_bus		*bus;
+	int			retval;
+	u32			hcc_params;
+	u8                      tempbyte;
+
+	spin_lock_init (&ehci->lock);
+
+	ehci->caps = (struct ehci_caps *) hcd->regs;
+	ehci->regs = (struct ehci_regs *) (hcd->regs + ehci->caps->length);
+	dbg_hcs_params (ehci, "ehci_start");
+	dbg_hcc_params (ehci, "ehci_start");
+
+	hcc_params = readl (&ehci->caps->hcc_params);
+
+	/* EHCI 0.96 and later may have "extended capabilities" */
+	temp = HCC_EXT_CAPS (hcc_params);
+	while (temp) {
+		u32		cap;
+
+		pci_read_config_dword (ehci->hcd.pdev, temp, &cap);
+		ehci_dbg (ehci, "capability %04x at %02x\n", cap, temp);
+		switch (cap & 0xff) {
+		case 1:			/* BIOS/SMM/... handoff */
+			if (bios_handoff (ehci, temp, cap) != 0)
+				return -EOPNOTSUPP;
+			break;
+		case 0:			/* illegal reserved capability */
+			ehci_warn (ehci, "illegal capability!\n");
+			cap = 0;
+			/* FALLTHROUGH */
+		default:		/* unknown */
+			break;
+		}
+		temp = (cap >> 8) & 0xff;
+	}
+
+	/* cache this readonly data; minimize PCI reads */
+	ehci->hcs_params = readl (&ehci->caps->hcs_params);
+
+	/* force HC to halt state */
+	if ((retval = ehci_halt (ehci)) != 0)
+		return retval;
+
+	/*
+	 * hw default: 1K periodic list heads, one per frame.
+	 * periodic_size can shrink by USBCMD update if hcc_params allows.
+	 */
+	ehci->periodic_size = DEFAULT_I_TDPS;
+	if ((retval = ehci_mem_init (ehci, SLAB_KERNEL)) < 0)
+		return retval;
+
+	/* controllers may cache some of the periodic schedule ... */
+	if (HCC_ISOC_CACHE (hcc_params)) 	// full frame cache
+		ehci->i_thresh = 8;
+	else					// N microframes cached
+		ehci->i_thresh = 2 + HCC_ISOC_THRES (hcc_params);
+
+	ehci->reclaim = 0;
+	ehci->next_uframe = -1;
+
+	/* controller state:  unknown --> reset */
+
+	/* EHCI spec section 4.1 */
+	if ((retval = ehci_reset (ehci)) != 0) {
+		ehci_mem_cleanup (ehci);
+		return retval;
+	}
+	writel (INTR_MASK, &ehci->regs->intr_enable);
+	writel (ehci->periodic_dma, &ehci->regs->frame_list);
+
+	/*
+	 * dedicate a qh for the async ring head, since we couldn't unlink
+	 * a 'real' qh without stopping the async schedule [4.8].  use it
+	 * as the 'reclamation list head' too.
+	 * its dummy is used in hw_alt_next of many tds, to prevent the qh
+	 * from automatically advancing to the next td after short reads.
+	 */
+	ehci->async->qh_next.qh = 0;
+	ehci->async->hw_next = QH_NEXT (ehci->async->qh_dma);
+	ehci->async->hw_info1 = cpu_to_le32 (QH_HEAD);
+	ehci->async->hw_token = cpu_to_le32 (QTD_STS_HALT);
+	ehci->async->hw_qtd_next = EHCI_LIST_END;
+	ehci->async->qh_state = QH_STATE_LINKED;
+	ehci->async->hw_alt_next = QTD_NEXT (ehci->async->dummy->qtd_dma);
+	writel ((u32)ehci->async->qh_dma, &ehci->regs->async_next);
+
+	/*
+	 * hcc_params controls whether ehci->regs->segment must (!!!)
+	 * be used; it constrains QH/ITD/SITD and QTD locations.
+	 * pci_pool consistent memory always uses segment zero.
+	 * streaming mappings for I/O buffers, like pci_map_single(),
+	 * can return segments above 4GB, if the device allows.
+	 *
+	 * NOTE:  the dma mask is visible through dma_supported(), so
+	 * drivers can pass this info along ... like NETIF_F_HIGHDMA,
+	 * Scsi_Host.highmem_io, and so forth.  It's readonly to all
+	 * host side drivers though.
+	 */
+	if (HCC_64BIT_ADDR (hcc_params)) {
+		writel (0, &ehci->regs->segment);
+		if (!pci_set_dma_mask (ehci->hcd.pdev, 0xffffffffffffffffULL))
+			ehci_info (ehci, "enabled 64bit PCI DMA\n");
+	}
+
+	/* help hc dma work well with cachelines */
+	pci_set_mwi (ehci->hcd.pdev);
+
+	/* clear interrupt enables, set irq latency */
+	temp = readl (&ehci->regs->command) & 0xff;
+	if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
+		log2_irq_thresh = 0;
+	temp |= 1 << (16 + log2_irq_thresh);
+	// if hc can park (ehci >= 0.96), default is 3 packets per async QH 
+	if (HCC_PGM_FRAMELISTLEN (hcc_params)) {
+		/* periodic schedule size can be smaller than default */
+		temp &= ~(3 << 2);
+		temp |= (EHCI_TUNE_FLS << 2);
+		switch (EHCI_TUNE_FLS) {
+		case 0: ehci->periodic_size = 1024; break;
+		case 1: ehci->periodic_size = 512; break;
+		case 2: ehci->periodic_size = 256; break;
+		default:	BUG ();
+		}
+	}
+	temp &= ~(CMD_IAAD | CMD_ASE | CMD_PSE),
+	// Philips, Intel, and maybe others need CMD_RUN before the
+	// root hub will detect new devices (why?); NEC doesn't
+	temp |= CMD_RUN;
+	writel (temp, &ehci->regs->command);
+	dbg_cmd (ehci, "init", temp);
+
+	/* set async sleep time = 10 us ... ? */
+
+	init_timer (&ehci->watchdog);
+	ehci->watchdog.function = ehci_watchdog;
+	ehci->watchdog.data = (unsigned long) ehci;
+
+	/* wire up the root hub */
+	bus = hcd_to_bus (hcd);
+	bus->root_hub = udev = usb_alloc_dev (NULL, bus);
+	if (!udev) {
+done2:
+		ehci_mem_cleanup (ehci);
+		return -ENOMEM;
+	}
+
+	/*
+	 * Start, enabling full USB 2.0 functionality ... usb 1.1 devices
+	 * are explicitly handed to companion controller(s), so no TT is
+	 * involved with the root hub.
+	 */
+	ehci->reboot_notifier.notifier_call = ehci_reboot;
+	register_reboot_notifier (&ehci->reboot_notifier);
+
+	ehci->hcd.state = USB_STATE_READY;
+	writel (FLAG_CF, &ehci->regs->configured_flag);
+	readl (&ehci->regs->command);	/* unblock posted write */
+
+        /* PCI Serial Bus Release Number is at 0x60 offset */
+	pci_read_config_byte (hcd->pdev, 0x60, &tempbyte);
+	temp = readw (&ehci->caps->hci_version);
+	ehci_info (ehci,
+		"USB %x.%x enabled, EHCI %x.%02x, driver %s\n",
+		((tempbyte & 0xf0)>>4), (tempbyte & 0x0f),
+		temp >> 8, temp & 0xff, DRIVER_VERSION);
+
+	/*
+	 * From here on, khubd concurrently accesses the root
+	 * hub; drivers will be talking to enumerated devices.
+	 *
+	 * Before this point the HC was idle/ready.  After, khubd
+	 * and device drivers may start it running.
+	 */
+	usb_connect (udev);
+	udev->speed = USB_SPEED_HIGH;
+	if (hcd_register_root (hcd) != 0) {
+		if (hcd->state == USB_STATE_RUNNING)
+			ehci_ready (ehci);
+		ehci_reset (ehci);
+		bus->root_hub = 0;
+		usb_free_dev (udev); 
+		retval = -ENODEV;
+		goto done2;
+	}
+
+	create_debug_files (ehci);
+
+	return 0;
+}
+
+/* always called by thread; normally rmmod */
+
+static void ehci_stop (struct usb_hcd *hcd)
+{
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+
+	ehci_dbg (ehci, "stop\n");
+
+	/* no more interrupts ... */
+	if (hcd->state == USB_STATE_RUNNING)
+		ehci_ready (ehci);
+	if (in_interrupt ()) {		/* must not happen!! */
+		ehci_err (ehci, "stopped in_interrupt!\n");
+		return;
+	}
+	del_timer_sync (&ehci->watchdog);
+	ehci_reset (ehci);
+
+	/* let companion controllers work when we aren't */
+	writel (0, &ehci->regs->configured_flag);
+	unregister_reboot_notifier (&ehci->reboot_notifier);
+
+	remove_debug_files (ehci);
+
+	/* root hub is shut down separately (first, when possible) */
+	spin_lock_irq (&ehci->lock);
+	ehci_work (ehci, NULL);
+	spin_unlock_irq (&ehci->lock);
+	ehci_mem_cleanup (ehci);
+
+#ifdef	EHCI_STATS
+	ehci_dbg (ehci, "irq normal %ld err %ld reclaim %ld (lost %ld)\n",
+		ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim,
+		ehci->stats.lost_iaa);
+	ehci_dbg (ehci, "complete %ld unlink %ld\n",
+		ehci->stats.complete, ehci->stats.unlink);
+#endif
+
+	dbg_status (ehci, "ehci_stop completed", readl (&ehci->regs->status));
+}
+
+static int ehci_get_frame (struct usb_hcd *hcd)
+{
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+	return (readl (&ehci->regs->frame_index) >> 3) % ehci->periodic_size;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef	CONFIG_PM
+
+/* suspend/resume, section 4.3 */
+
+static int ehci_suspend (struct usb_hcd *hcd, u32 state)
+{
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+	int			ports;
+	int			i;
+
+	dbg ("%s: suspend to %d", hcd_to_bus (hcd)->bus_name, state);
+
+	ports = HCS_N_PORTS (ehci->hcs_params);
+
+	// FIXME:  This assumes what's probably a D3 level suspend...
+
+	// FIXME:  usb wakeup events on this bus should resume the machine.
+	// pci config register PORTWAKECAP controls which ports can do it;
+	// bios may have initted the register...
+
+	/* suspend each port, then stop the hc */
+	for (i = 0; i < ports; i++) {
+		int	temp = readl (&ehci->regs->port_status [i]);
+
+		if ((temp & PORT_PE) == 0
+				|| (temp & PORT_OWNER) != 0)
+			continue;
+dbg ("%s: suspend port %d", hcd_to_bus (hcd)->bus_name, i);
+		temp |= PORT_SUSPEND;
+		writel (temp, &ehci->regs->port_status [i]);
+	}
+
+	if (hcd->state == USB_STATE_RUNNING)
+		ehci_ready (ehci);
+	writel (readl (&ehci->regs->command) & ~CMD_RUN, &ehci->regs->command);
+
+// save pci FLADJ value
+
+	/* who tells PCI to reduce power consumption? */
+
+	return 0;
+}
+
+static int ehci_resume (struct usb_hcd *hcd)
+{
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+	int			ports;
+	int			i;
+
+	dbg ("%s: resume", hcd_to_bus (hcd)->bus_name);
+
+	ports = HCS_N_PORTS (ehci->hcs_params);
+
+	// FIXME:  if controller didn't retain state,
+	// return and let generic code clean it up
+	// test configured_flag ?
+
+	/* resume HC and each port */
+// restore pci FLADJ value
+	// khubd and drivers will set HC running, if needed;
+	hcd->state = USB_STATE_READY;
+	// FIXME Philips/Intel/... etc don't really have a "READY"
+	// state ... turn on CMD_RUN too
+	for (i = 0; i < ports; i++) {
+		int	temp = readl (&ehci->regs->port_status [i]);
+
+		if ((temp & PORT_PE) == 0
+				|| (temp & PORT_SUSPEND) != 0)
+			continue;
+dbg ("%s: resume port %d", hcd_to_bus (hcd)->bus_name, i);
+		temp |= PORT_RESUME;
+		writel (temp, &ehci->regs->port_status [i]);
+		readl (&ehci->regs->command);	/* unblock posted writes */
+
+		wait_ms (20);
+		temp &= ~PORT_RESUME;
+		writel (temp, &ehci->regs->port_status [i]);
+	}
+	readl (&ehci->regs->command);	/* unblock posted writes */
+	return 0;
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * ehci_work is called from some interrupts, timers, and so on.
+ * it calls driver completion functions, after dropping ehci->lock.
+ */
+static void ehci_work (struct ehci_hcd *ehci, struct pt_regs *regs)
+{
+	if (ehci->reclaim_ready)
+		end_unlink_async (ehci, regs);
+	scan_async (ehci, regs);
+	if (ehci->next_uframe != -1)
+		scan_periodic (ehci, regs);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs)
+{
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+	u32			status;
+	int			bh;
+
+	spin_lock (&ehci->lock);
+
+	status = readl (&ehci->regs->status);
+
+	/* e.g. cardbus physical eject */
+	if (status == ~(u32) 0) {
+		ehci_dbg (ehci, "device removed\n");
+		goto dead;
+	}
+
+	status &= INTR_MASK;
+	if (!status)			/* irq sharing? */
+		goto done;
+
+	/* clear (just) interrupts */
+	writel (status, &ehci->regs->status);
+	readl (&ehci->regs->command);	/* unblock posted write */
+	bh = 0;
+
+#ifdef	EHCI_VERBOSE_DEBUG
+	/* unrequested/ignored: Port Change Detect, Frame List Rollover */
+	dbg_status (ehci, "irq", status);
+#endif
+
+	/* INT, ERR, and IAA interrupt rates can be throttled */
+
+	/* normal [4.15.1.2] or error [4.15.1.1] completion */
+	if (likely ((status & (STS_INT|STS_ERR)) != 0)) {
+		if (likely ((status & STS_ERR) == 0))
+			COUNT (ehci->stats.normal);
+		else
+			COUNT (ehci->stats.error);
+		bh = 1;
+	}
+
+	/* complete the unlinking of some qh [4.15.2.3] */
+	if (status & STS_IAA) {
+		COUNT (ehci->stats.reclaim);
+		ehci->reclaim_ready = 1;
+		bh = 1;
+	}
+
+	/* PCI errors [4.15.2.4] */
+	if (unlikely ((status & STS_FATAL) != 0)) {
+		ehci_err (ehci, "fatal error\n");
+dead:
+		ehci_reset (ehci);
+		/* generic layer kills/unlinks all urbs, then
+		 * uses ehci_stop to clean up the rest
+		 */
+		bh = 1;
+	}
+
+	if (bh)
+		ehci_work (ehci, regs);
+done:
+	spin_unlock (&ehci->lock);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * non-error returns are a promise to giveback() the urb later
+ * we drop ownership so next owner (or urb unlink) can get it
+ *
+ * urb + dev is in hcd_dev.urb_list
+ * we're queueing TDs onto software and hardware lists
+ *
+ * hcd-specific init for hcpriv hasn't been done yet
+ *
+ * NOTE:  control, bulk, and interrupt share the same code to append TDs
+ * to a (possibly active) QH, and the same QH scanning code.
+ */
+static int ehci_urb_enqueue (
+	struct usb_hcd	*hcd,
+	struct urb	*urb,
+	int		mem_flags
+) {
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+	struct list_head	qtd_list;
+
+	urb->transfer_flags &= ~EHCI_STATE_UNLINK;
+	INIT_LIST_HEAD (&qtd_list);
+
+	switch (usb_pipetype (urb->pipe)) {
+	// case PIPE_CONTROL:
+	// case PIPE_BULK:
+	default:
+		if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
+			return -ENOMEM;
+		return submit_async (ehci, urb, &qtd_list, mem_flags);
+
+	case PIPE_INTERRUPT:
+		if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
+			return -ENOMEM;
+		return intr_submit (ehci, urb, &qtd_list, mem_flags);
+
+	case PIPE_ISOCHRONOUS:
+		if (urb->dev->speed == USB_SPEED_HIGH)
+			return itd_submit (ehci, urb, mem_flags);
+#ifdef have_split_iso
+		else
+			return sitd_submit (ehci, urb, mem_flags);
+#else
+		dbg ("no split iso support yet");
+		return -ENOSYS;
+#endif /* have_split_iso */
+	}
+}
+
+/* remove from hardware lists
+ * completions normally happen asynchronously
+ */
+
+static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+{
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+	struct ehci_qh		*qh;
+	unsigned long		flags;
+
+	spin_lock_irqsave (&ehci->lock, flags);
+	switch (usb_pipetype (urb->pipe)) {
+	// case PIPE_CONTROL:
+	// case PIPE_BULK:
+	default:
+		qh = (struct ehci_qh *) urb->hcpriv;
+		if (!qh)
+			break;
+
+		/* if we need to use IAA and it's busy, defer */
+		if (qh->qh_state == QH_STATE_LINKED
+				&& ehci->reclaim
+				&& HCD_IS_RUNNING (ehci->hcd.state)
+				) {
+			struct ehci_qh		*last;
+
+			for (last = ehci->reclaim;
+					last->reclaim;
+					last = last->reclaim)
+				continue;
+			qh->qh_state = QH_STATE_UNLINK_WAIT;
+			last->reclaim = qh;
+
+		/* bypass IAA if the hc can't care */
+		} else if (!HCD_IS_RUNNING (ehci->hcd.state) && ehci->reclaim)
+			end_unlink_async (ehci, NULL);
+
+		/* something else might have unlinked the qh by now */
+		if (qh->qh_state == QH_STATE_LINKED)
+			start_unlink_async (ehci, qh);
+		break;
+
+	case PIPE_INTERRUPT:
+		qh = (struct ehci_qh *) urb->hcpriv;
+		if (!qh)
+			break;
+		if (qh->qh_state == QH_STATE_LINKED) {
+			/* messy, can spin or block a microframe ... */
+			intr_deschedule (ehci, qh, 1);
+			/* qh_state == IDLE */
+		}
+		qh_completions (ehci, qh, NULL);
+
+		/* reschedule QH iff another request is queued */
+		if (!list_empty (&qh->qtd_list)
+				&& HCD_IS_RUNNING (ehci->hcd.state)) {
+			int status;
+
+			status = qh_schedule (ehci, qh);
+			spin_unlock_irqrestore (&ehci->lock, flags);
+
+			if (status != 0) {
+				// shouldn't happen often, but ...
+				// FIXME kill those tds' urbs
+				err ("can't reschedule qh %p, err %d",
+					qh, status);
+			}
+			return status;
+		}
+		break;
+
+	case PIPE_ISOCHRONOUS:
+		// itd or sitd ...
+
+		// wait till next completion, do it then.
+		// completion irqs can wait up to 1024 msec,
+		urb->transfer_flags |= EHCI_STATE_UNLINK;
+		break;
+	}
+	spin_unlock_irqrestore (&ehci->lock, flags);
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+// bulk qh holds the data toggle
+
+static void ehci_free_config (struct usb_hcd *hcd, struct usb_device *udev)
+{
+	struct hcd_dev		*dev = (struct hcd_dev *)udev->hcpriv;
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+	int			i;
+	unsigned long		flags;
+
+	/* ASSERT:  no requests/urbs are still linked (so no TDs) */
+	/* ASSERT:  nobody can be submitting urbs for this any more */
+
+	dbg ("%s: free_config devnum %d",
+		hcd_to_bus (hcd)->bus_name, udev->devnum);
+
+	spin_lock_irqsave (&ehci->lock, flags);
+	for (i = 0; i < 32; i++) {
+		if (dev->ep [i]) {
+			struct ehci_qh		*qh;
+			char			*why;
+
+			/* dev->ep never has ITDs or SITDs */
+			qh = (struct ehci_qh *) dev->ep [i];
+
+			/* detect/report non-recoverable errors */
+			if (in_interrupt ()) 
+				why = "disconnect() didn't";
+			else if ((qh->hw_info2 & cpu_to_le32 (0xffff)) != 0
+					&& qh->qh_state != QH_STATE_IDLE)
+				why = "(active periodic)";
+			else
+				why = 0;
+			if (why) {
+				err ("dev %s-%s ep %d-%s error: %s",
+					hcd_to_bus (hcd)->bus_name,
+					udev->devpath,
+					i & 0xf, (i & 0x10) ? "IN" : "OUT",
+					why);
+				BUG ();
+			}
+
+			dev->ep [i] = 0;
+			if (qh->qh_state == QH_STATE_IDLE)
+				goto idle;
+			dbg ("free_config, async ep 0x%02x qh %p", i, qh);
+
+			/* scan_async() empties the ring as it does its work,
+			 * using IAA, but doesn't (yet?) turn it off.  if it
+			 * doesn't empty this qh, likely it's the last entry.
+			 */
+			while (qh->qh_state == QH_STATE_LINKED
+					&& ehci->reclaim
+					&& HCD_IS_RUNNING (ehci->hcd.state)
+					) {
+				spin_unlock_irqrestore (&ehci->lock, flags);
+				/* wait_ms() won't spin, we're a thread;
+				 * and we know IRQ/timer/... can progress
+				 */
+				wait_ms (1);
+				spin_lock_irqsave (&ehci->lock, flags);
+			}
+			if (qh->qh_state == QH_STATE_LINKED)
+				start_unlink_async (ehci, qh);
+			while (qh->qh_state != QH_STATE_IDLE
+					&& ehci->hcd.state != USB_STATE_HALT) {
+				spin_unlock_irqrestore (&ehci->lock, flags);
+				wait_ms (1);
+				spin_lock_irqsave (&ehci->lock, flags);
+			}
+idle:
+			qh_put (ehci, qh);
+		}
+	}
+
+	spin_unlock_irqrestore (&ehci->lock, flags);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static const struct hc_driver ehci_driver = {
+	.description =		hcd_name,
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq =			ehci_irq,
+	.flags =		HCD_MEMORY | HCD_USB2,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	.start =		ehci_start,
+#ifdef	CONFIG_PM
+	.suspend =		ehci_suspend,
+	.resume =		ehci_resume,
+#endif
+	.stop =			ehci_stop,
+
+	/*
+	 * memory lifecycle (except per-request)
+	 */
+	.hcd_alloc =		ehci_hcd_alloc,
+	.hcd_free =		ehci_hcd_free,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue =		ehci_urb_enqueue,
+	.urb_dequeue =		ehci_urb_dequeue,
+	.free_config =		ehci_free_config,
+
+	/*
+	 * scheduling support
+	 */
+	.get_frame_number =	ehci_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	.hub_status_data =	ehci_hub_status_data,
+	.hub_control =		ehci_hub_control,
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* EHCI spec says PCI is required. */
+
+/* PCI driver selection metadata; PCI hotplugging uses this */
+static const struct pci_device_id __devinitdata pci_ids [] = { {
+
+	/* handle any USB 2.0 EHCI controller */
+
+	.class = 		((PCI_CLASS_SERIAL_USB << 8) | 0x20),
+	.class_mask = 	~0,
+	.driver_data =	(unsigned long) &ehci_driver,
+
+	/* no matter who makes it */
+	.vendor =	PCI_ANY_ID,
+	.device =	PCI_ANY_ID,
+	.subvendor =	PCI_ANY_ID,
+	.subdevice =	PCI_ANY_ID,
+
+}, { /* end: all zeroes */ }
+};
+MODULE_DEVICE_TABLE (pci, pci_ids);
+
+/* pci driver glue; this is a "new style" PCI driver module */
+static struct pci_driver ehci_pci_driver = {
+	.name =		(char *) hcd_name,
+	.id_table =	pci_ids,
+
+	.probe =	usb_hcd_pci_probe,
+	.remove =	usb_hcd_pci_remove,
+
+#ifdef	CONFIG_PM
+	.suspend =	usb_hcd_pci_suspend,
+	.resume =	usb_hcd_pci_resume,
+#endif
+};
+
+#define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC
+
+MODULE_DESCRIPTION (DRIVER_INFO);
+MODULE_AUTHOR (DRIVER_AUTHOR);
+MODULE_LICENSE ("GPL");
+
+static int __init init (void) 
+{
+	dbg (DRIVER_INFO);
+	dbg ("block sizes: qh %Zd qtd %Zd itd %Zd sitd %Zd",
+		sizeof (struct ehci_qh), sizeof (struct ehci_qtd),
+		sizeof (struct ehci_itd), sizeof (struct ehci_sitd));
+
+	return pci_module_init (&ehci_pci_driver);
+}
+module_init (init);
+
+static void __exit cleanup (void) 
+{	
+	pci_unregister_driver (&ehci_pci_driver);
+}
+module_exit (cleanup);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/host/ehci-hub.c linux-2.4.21-pre6/drivers/usb/host/ehci-hub.c
--- linux-2.4.20/drivers/usb/host/ehci-hub.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/host/ehci-hub.c	2003-03-26 23:49:00.000000000 +0000
@@ -0,0 +1,344 @@
+/*
+ * Copyright (c) 2001-2002 by David Brownell
+ * 
+ * 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 file is part of ehci-hcd.c */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI Root Hub ... the nonsharable stuff
+ *
+ * Registers don't need cpu_to_le32, that happens transparently
+ */
+
+/*-------------------------------------------------------------------------*/
+
+static int check_reset_complete (
+	struct ehci_hcd	*ehci,
+	int		index,
+	int		port_status
+) {
+	if (!(port_status & PORT_CONNECT)) {
+		ehci->reset_done [index] = 0;
+		return port_status;
+	}
+
+	/* if reset finished and it's still not enabled -- handoff */
+	if (!(port_status & PORT_PE)) {
+		ehci_dbg (ehci, "port %d full speed --> companion\n",
+			index + 1);
+
+		// what happens if HCS_N_CC(params) == 0 ?
+		port_status |= PORT_OWNER;
+		writel (port_status, &ehci->regs->port_status [index]);
+
+	} else
+		ehci_dbg (ehci, "port %d high speed\n", index + 1);
+
+	return port_status;
+}
+
+/*-------------------------------------------------------------------------*/
+
+
+/* build "status change" packet (one or two bytes) from HC registers */
+
+static int
+ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
+{
+	struct ehci_hcd	*ehci = hcd_to_ehci (hcd);
+	u32		temp, status = 0;
+	int		ports, i, retval = 1;
+	unsigned long	flags;
+
+	/* init status to no-changes */
+	buf [0] = 0;
+	ports = HCS_N_PORTS (ehci->hcs_params);
+	if (ports > 7) {
+		buf [1] = 0;
+		retval++;
+	}
+	
+	/* no hub change reports (bit 0) for now (power, ...) */
+
+	/* port N changes (bit N)? */
+	spin_lock_irqsave (&ehci->lock, flags);
+	for (i = 0; i < ports; i++) {
+		temp = readl (&ehci->regs->port_status [i]);
+		if (temp & PORT_OWNER) {
+			/* don't report this in GetPortStatus */
+			if (temp & PORT_CSC) {
+				temp &= ~PORT_CSC;
+				writel (temp, &ehci->regs->port_status [i]);
+			}
+			continue;
+		}
+		if (!(temp & PORT_CONNECT))
+			ehci->reset_done [i] = 0;
+		if ((temp & (PORT_CSC | PORT_PEC | PORT_OCC)) != 0) {
+			if (i < 7)
+			    buf [0] |= 1 << (i + 1);
+			else
+			    buf [1] |= 1 << (i - 7);
+			status = STS_PCD;
+		}
+	}
+	spin_unlock_irqrestore (&ehci->lock, flags);
+	return status ? retval : 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void
+ehci_hub_descriptor (
+	struct ehci_hcd			*ehci,
+	struct usb_hub_descriptor	*desc
+) {
+	int		ports = HCS_N_PORTS (ehci->hcs_params);
+	u16		temp;
+
+	desc->bDescriptorType = 0x29;
+	desc->bPwrOn2PwrGood = 0;	/* FIXME: f(system power) */
+	desc->bHubContrCurrent = 0;
+
+	desc->bNbrPorts = ports;
+	temp = 1 + (ports / 8);
+	desc->bDescLength = 7 + 2 * temp;
+
+	/* two bitmaps:  ports removable, and usb 1.0 legacy PortPwrCtrlMask */
+	memset (&desc->bitmap [0], 0, temp);
+	memset (&desc->bitmap [temp], 0xff, temp);
+
+	temp = 0x0008;			/* per-port overcurrent reporting */
+	if (HCS_PPC (ehci->hcs_params))
+		temp |= 0x0001;		/* per-port power control */
+	if (HCS_INDICATOR (ehci->hcs_params))
+		temp |= 0x0080;		/* per-port indicators (LEDs) */
+	desc->wHubCharacteristics = cpu_to_le16 (temp);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int ehci_hub_control (
+	struct usb_hcd	*hcd,
+	u16		typeReq,
+	u16		wValue,
+	u16		wIndex,
+	char		*buf,
+	u16		wLength
+) {
+	struct ehci_hcd	*ehci = hcd_to_ehci (hcd);
+	int		ports = HCS_N_PORTS (ehci->hcs_params);
+	u32		temp, status;
+	unsigned long	flags;
+	int		retval = 0;
+
+	/*
+	 * FIXME:  support SetPortFeatures USB_PORT_FEAT_INDICATOR.
+	 * HCS_INDICATOR may say we can change LEDs to off/amber/green.
+	 * (track current state ourselves) ... blink for diagnostics,
+	 * power, "this is the one", etc.  EHCI spec supports this.
+	 */
+
+	spin_lock_irqsave (&ehci->lock, flags);
+	switch (typeReq) {
+	case ClearHubFeature:
+		switch (wValue) {
+		case C_HUB_LOCAL_POWER:
+		case C_HUB_OVER_CURRENT:
+			/* no hub-wide feature/status flags */
+			break;
+		default:
+			goto error;
+		}
+		break;
+	case ClearPortFeature:
+		if (!wIndex || wIndex > ports)
+			goto error;
+		wIndex--;
+		temp = readl (&ehci->regs->port_status [wIndex]);
+		if (temp & PORT_OWNER)
+			break;
+
+		switch (wValue) {
+		case USB_PORT_FEAT_ENABLE:
+			writel (temp & ~PORT_PE,
+				&ehci->regs->port_status [wIndex]);
+			break;
+		case USB_PORT_FEAT_C_ENABLE:
+			writel (temp | PORT_PEC,
+				&ehci->regs->port_status [wIndex]);
+			break;
+		case USB_PORT_FEAT_SUSPEND:
+		case USB_PORT_FEAT_C_SUSPEND:
+			/* ? */
+			break;
+		case USB_PORT_FEAT_POWER:
+			if (HCS_PPC (ehci->hcs_params))
+				writel (temp & ~PORT_POWER,
+					&ehci->regs->port_status [wIndex]);
+			break;
+		case USB_PORT_FEAT_C_CONNECTION:
+			writel (temp | PORT_CSC,
+				&ehci->regs->port_status [wIndex]);
+			break;
+		case USB_PORT_FEAT_C_OVER_CURRENT:
+			writel (temp | PORT_OCC,
+				&ehci->regs->port_status [wIndex]);
+			break;
+		case USB_PORT_FEAT_C_RESET:
+			/* GetPortStatus clears reset */
+			break;
+		default:
+			goto error;
+		}
+		readl (&ehci->regs->command);	/* unblock posted write */
+		break;
+	case GetHubDescriptor:
+		ehci_hub_descriptor (ehci, (struct usb_hub_descriptor *)
+			buf);
+		break;
+	case GetHubStatus:
+		/* no hub-wide feature/status flags */
+		memset (buf, 0, 4);
+		//cpu_to_le32s ((u32 *) buf);
+		break;
+	case GetPortStatus:
+		if (!wIndex || wIndex > ports)
+			goto error;
+		wIndex--;
+		status = 0;
+		temp = readl (&ehci->regs->port_status [wIndex]);
+
+		// wPortChange bits
+		if (temp & PORT_CSC)
+			status |= 1 << USB_PORT_FEAT_C_CONNECTION;
+		if (temp & PORT_PEC)
+			status |= 1 << USB_PORT_FEAT_C_ENABLE;
+		// USB_PORT_FEAT_C_SUSPEND
+		if (temp & PORT_OCC)
+			status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT;
+
+		/* whoever resets must GetPortStatus to complete it!! */
+		if ((temp & PORT_RESET)
+				&& time_after (jiffies,
+					ehci->reset_done [wIndex])) {
+			status |= 1 << USB_PORT_FEAT_C_RESET;
+
+			/* force reset to complete */
+			writel (temp & ~PORT_RESET,
+					&ehci->regs->port_status [wIndex]);
+			do {
+				temp = readl (
+					&ehci->regs->port_status [wIndex]);
+				udelay (10);
+			} while (temp & PORT_RESET);
+
+			/* see what we found out */
+			temp = check_reset_complete (ehci, wIndex, temp);
+		}
+
+		// don't show wPortStatus if it's owned by a companion hc
+		if (!(temp & PORT_OWNER)) {
+			if (temp & PORT_CONNECT) {
+				status |= 1 << USB_PORT_FEAT_CONNECTION;
+				status |= 1 << USB_PORT_FEAT_HIGHSPEED;
+			}
+			if (temp & PORT_PE)
+				status |= 1 << USB_PORT_FEAT_ENABLE;
+			if (temp & PORT_SUSPEND)
+				status |= 1 << USB_PORT_FEAT_SUSPEND;
+			if (temp & PORT_OC)
+				status |= 1 << USB_PORT_FEAT_OVER_CURRENT;
+			if (temp & PORT_RESET)
+				status |= 1 << USB_PORT_FEAT_RESET;
+			if (temp & PORT_POWER)
+				status |= 1 << USB_PORT_FEAT_POWER;
+		}
+
+#ifndef	EHCI_VERBOSE_DEBUG
+	if (status & ~0xffff)	/* only if wPortChange is interesting */
+#endif
+		dbg_port (ehci, "GetStatus", wIndex + 1, temp);
+		// we "know" this alignment is good, caller used kmalloc()...
+		*((u32 *) buf) = cpu_to_le32 (status);
+		break;
+	case SetHubFeature:
+		switch (wValue) {
+		case C_HUB_LOCAL_POWER:
+		case C_HUB_OVER_CURRENT:
+			/* no hub-wide feature/status flags */
+			break;
+		default:
+			goto error;
+		}
+		break;
+	case SetPortFeature:
+		if (!wIndex || wIndex > ports)
+			goto error;
+		wIndex--;
+		temp = readl (&ehci->regs->port_status [wIndex]);
+		if (temp & PORT_OWNER)
+			break;
+
+		switch (wValue) {
+		case USB_PORT_FEAT_SUSPEND:
+			writel (temp | PORT_SUSPEND,
+				&ehci->regs->port_status [wIndex]);
+			break;
+		case USB_PORT_FEAT_POWER:
+			if (HCS_PPC (ehci->hcs_params))
+				writel (temp | PORT_POWER,
+					&ehci->regs->port_status [wIndex]);
+			break;
+		case USB_PORT_FEAT_RESET:
+			/* line status bits may report this as low speed */
+			if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT
+					&& PORT_USB11 (temp)) {
+				ehci_dbg (ehci,
+					"port %d low speed --> companion\n",
+					wIndex + 1);
+				temp |= PORT_OWNER;
+			} else {
+				ehci_vdbg (ehci, "port %d reset\n", wIndex + 1);
+				temp |= PORT_RESET;
+				temp &= ~PORT_PE;
+
+				/*
+				 * caller must wait, then call GetPortStatus
+				 * usb 2.0 spec says 50 ms resets on root
+				 */
+				ehci->reset_done [wIndex] = jiffies
+				    	+ ((50 /* msec */ * HZ) / 1000);
+			}
+			writel (temp, &ehci->regs->port_status [wIndex]);
+			break;
+		default:
+			goto error;
+		}
+		readl (&ehci->regs->command);	/* unblock posted writes */
+		break;
+
+	default:
+error:
+		/* "stall" on error */
+		retval = -EPIPE;
+	}
+	spin_unlock_irqrestore (&ehci->lock, flags);
+	return retval;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/host/ehci-mem.c linux-2.4.21-pre6/drivers/usb/host/ehci-mem.c
--- linux-2.4.20/drivers/usb/host/ehci-mem.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/host/ehci-mem.c	2003-03-26 23:49:29.000000000 +0000
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2001 by David Brownell
+ * 
+ * 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 file is part of ehci-hcd.c */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * There's basically three types of memory:
+ *	- data used only by the HCD ... kmalloc is fine
+ *	- async and periodic schedules, shared by HC and HCD ... these
+ *	  need to use pci_pool or pci_alloc_consistent
+ *	- driver buffers, read/written by HC ... single shot DMA mapped 
+ *
+ * There's also PCI "register" data, which is memory mapped.
+ * No memory seen by this driver is pagable.
+ */
+
+/*-------------------------------------------------------------------------*/
+/* 
+ * Allocator / cleanup for the per device structure
+ * Called by hcd init / removal code
+ */
+static struct usb_hcd *ehci_hcd_alloc (void)
+{
+	struct ehci_hcd *ehci;
+
+	ehci = (struct ehci_hcd *)
+		kmalloc (sizeof (struct ehci_hcd), GFP_KERNEL);
+	if (ehci != 0) {
+		memset (ehci, 0, sizeof (struct ehci_hcd));
+		return &ehci->hcd;
+	}
+	return 0;
+}
+
+static void ehci_hcd_free (struct usb_hcd *hcd)
+{
+	kfree (hcd_to_ehci (hcd));
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Allocate the key transfer structures from the previously allocated pool */
+
+static inline void ehci_qtd_init (struct ehci_qtd *qtd, dma_addr_t dma)
+{
+	memset (qtd, 0, sizeof *qtd);
+	qtd->qtd_dma = dma;
+	qtd->hw_next = EHCI_LIST_END;
+	qtd->hw_alt_next = EHCI_LIST_END;
+	INIT_LIST_HEAD (&qtd->qtd_list);
+}
+
+static struct ehci_qtd *ehci_qtd_alloc (struct ehci_hcd *ehci, int flags)
+{
+	struct ehci_qtd		*qtd;
+	dma_addr_t		dma;
+
+	qtd = pci_pool_alloc (ehci->qtd_pool, flags, &dma);
+	if (qtd != 0) {
+		ehci_qtd_init (qtd, dma);
+	}
+	return qtd;
+}
+
+static inline void ehci_qtd_free (struct ehci_hcd *ehci, struct ehci_qtd *qtd)
+{
+	pci_pool_free (ehci->qtd_pool, qtd, qtd->qtd_dma);
+}
+
+
+static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, int flags)
+{
+	struct ehci_qh		*qh;
+	dma_addr_t		dma;
+
+	qh = (struct ehci_qh *)
+		pci_pool_alloc (ehci->qh_pool, flags, &dma);
+	if (!qh)
+		return qh;
+
+	memset (qh, 0, sizeof *qh);
+	atomic_set (&qh->refcount, 1);
+	qh->qh_dma = dma;
+	// INIT_LIST_HEAD (&qh->qh_list);
+	INIT_LIST_HEAD (&qh->qtd_list);
+
+	/* dummy td enables safe urb queuing */
+	qh->dummy = ehci_qtd_alloc (ehci, flags);
+	if (qh->dummy == 0) {
+		ehci_dbg (ehci, "no dummy td\n");
+		pci_pool_free (ehci->qh_pool, qh, qh->qh_dma);
+		qh = 0;
+	}
+	return qh;
+}
+
+/* to share a qh (cpu threads, or hc) */
+static inline struct ehci_qh *qh_get (/* ehci, */ struct ehci_qh *qh)
+{
+	atomic_inc (&qh->refcount);
+	return qh;
+}
+
+static void qh_put (struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+	if (!atomic_dec_and_test (&qh->refcount))
+		return;
+	/* clean qtds first, and know this is not linked */
+	if (!list_empty (&qh->qtd_list) || qh->qh_next.ptr) {
+		ehci_dbg (ehci, "unused qh not empty!\n");
+		BUG ();
+	}
+	if (qh->dummy)
+		ehci_qtd_free (ehci, qh->dummy);
+	pci_pool_free (ehci->qh_pool, qh, qh->qh_dma);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* The queue heads and transfer descriptors are managed from pools tied 
+ * to each of the "per device" structures.
+ * This is the initialisation and cleanup code.
+ */
+
+static void ehci_mem_cleanup (struct ehci_hcd *ehci)
+{
+	if (ehci->async)
+		qh_put (ehci, ehci->async);
+	ehci->async = 0;
+
+	/* PCI consistent memory and pools */
+	if (ehci->qtd_pool)
+		pci_pool_destroy (ehci->qtd_pool);
+	ehci->qtd_pool = 0;
+
+	if (ehci->qh_pool) {
+		pci_pool_destroy (ehci->qh_pool);
+		ehci->qh_pool = 0;
+	}
+
+	if (ehci->itd_pool)
+		pci_pool_destroy (ehci->itd_pool);
+	ehci->itd_pool = 0;
+
+	if (ehci->sitd_pool)
+		pci_pool_destroy (ehci->sitd_pool);
+	ehci->sitd_pool = 0;
+
+	if (ehci->periodic)
+		pci_free_consistent (ehci->hcd.pdev,
+			ehci->periodic_size * sizeof (u32),
+			ehci->periodic, ehci->periodic_dma);
+	ehci->periodic = 0;
+
+	/* shadow periodic table */
+	if (ehci->pshadow)
+		kfree (ehci->pshadow);
+	ehci->pshadow = 0;
+}
+
+/* remember to add cleanup code (above) if you add anything here */
+static int ehci_mem_init (struct ehci_hcd *ehci, int flags)
+{
+	int i;
+
+	/* QTDs for control/bulk/intr transfers */
+	ehci->qtd_pool = pci_pool_create ("ehci_qtd", ehci->hcd.pdev,
+			sizeof (struct ehci_qtd),
+			32 /* byte alignment (for hw parts) */,
+			4096 /* can't cross 4K */,
+			flags);
+	if (!ehci->qtd_pool) {
+		goto fail;
+	}
+
+	/* QHs for control/bulk/intr transfers */
+	ehci->qh_pool = pci_pool_create ("ehci_qh", ehci->hcd.pdev,
+			sizeof (struct ehci_qh),
+			32 /* byte alignment (for hw parts) */,
+			4096 /* can't cross 4K */,
+			flags);
+	if (!ehci->qh_pool) {
+		goto fail;
+	}
+	ehci->async = ehci_qh_alloc (ehci, flags);
+	if (!ehci->async) {
+		goto fail;
+	}
+
+	/* ITD for high speed ISO transfers */
+	ehci->itd_pool = pci_pool_create ("ehci_itd", ehci->hcd.pdev,
+			sizeof (struct ehci_itd),
+			32 /* byte alignment (for hw parts) */,
+			4096 /* can't cross 4K */,
+			flags);
+	if (!ehci->itd_pool) {
+		goto fail;
+	}
+
+	/* SITD for full/low speed split ISO transfers */
+	ehci->sitd_pool = pci_pool_create ("ehci_sitd", ehci->hcd.pdev,
+			sizeof (struct ehci_sitd),
+			32 /* byte alignment (for hw parts) */,
+			4096 /* can't cross 4K */,
+			flags);
+	if (!ehci->sitd_pool) {
+		goto fail;
+	}
+
+	/* Hardware periodic table */
+	ehci->periodic = (u32 *)
+		pci_alloc_consistent (ehci->hcd.pdev,
+			ehci->periodic_size * sizeof (u32),
+			&ehci->periodic_dma);
+	if (ehci->periodic == 0) {
+		goto fail;
+	}
+	for (i = 0; i < ehci->periodic_size; i++)
+		ehci->periodic [i] = EHCI_LIST_END;
+
+	/* software shadow of hardware table */
+	ehci->pshadow = kmalloc (ehci->periodic_size * sizeof (void *), flags);
+	if (ehci->pshadow == 0) {
+		goto fail;
+	}
+	memset (ehci->pshadow, 0, ehci->periodic_size * sizeof (void *));
+
+	return 0;
+
+fail:
+	ehci_dbg (ehci, "couldn't init memory\n");
+	ehci_mem_cleanup (ehci);
+	return -ENOMEM;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/host/ehci-q.c linux-2.4.21-pre6/drivers/usb/host/ehci-q.c
--- linux-2.4.20/drivers/usb/host/ehci-q.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/host/ehci-q.c	2003-03-26 23:48:57.000000000 +0000
@@ -0,0 +1,1105 @@
+/*
+ * Copyright (c) 2001-2002 by David Brownell
+ * 
+ * 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 file is part of ehci-hcd.c */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI hardware queue manipulation ... the core.  QH/QTD manipulation.
+ *
+ * Control, bulk, and interrupt traffic all use "qh" lists.  They list "qtd"
+ * entries describing USB transactions, max 16-20kB/entry (with 4kB-aligned
+ * buffers needed for the larger number).  We use one QH per endpoint, queue
+ * multiple urbs (all three types) per endpoint.  URBs may need several qtds.
+ *
+ * ISO traffic uses "ISO TD" (itd, and sitd) records, and (along with
+ * interrupts) needs careful scheduling.  Performance improvements can be
+ * an ongoing challenge.  That's in "ehci-sched.c".
+ * 
+ * USB 1.1 devices are handled (a) by "companion" OHCI or UHCI root hubs,
+ * or otherwise through transaction translators (TTs) in USB 2.0 hubs using
+ * (b) special fields in qh entries or (c) split iso entries.  TTs will
+ * buffer low/full speed data so the host collects it at high speed.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/* fill a qtd, returning how much of the buffer we were able to queue up */
+
+static int
+qtd_fill (struct ehci_qtd *qtd, dma_addr_t buf, size_t len,
+		int token, int maxpacket)
+{
+	int	i, count;
+	u64	addr = buf;
+
+	/* one buffer entry per 4K ... first might be short or unaligned */
+	qtd->hw_buf [0] = cpu_to_le32 ((u32)addr);
+	qtd->hw_buf_hi [0] = cpu_to_le32 ((u32)(addr >> 32));
+	count = 0x1000 - (buf & 0x0fff);	/* rest of that page */
+	if (likely (len < count))		/* ... iff needed */
+		count = len;
+	else {
+		buf +=  0x1000;
+		buf &= ~0x0fff;
+
+		/* per-qtd limit: from 16K to 20K (best alignment) */
+		for (i = 1; count < len && i < 5; i++) {
+			addr = buf;
+			qtd->hw_buf [i] = cpu_to_le32 ((u32)addr);
+			qtd->hw_buf_hi [i] = cpu_to_le32 ((u32)(addr >> 32));
+			buf += 0x1000;
+			if ((count + 0x1000) < len)
+				count += 0x1000;
+			else
+				count = len;
+		}
+
+		/* short packets may only terminate transfers */
+		if (count != len)
+			count -= (count % maxpacket);
+	}
+	qtd->hw_token = cpu_to_le32 ((count << 16) | token);
+	qtd->length = count;
+
+	return count;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* update halted (but potentially linked) qh */
+
+static inline void
+qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd)
+{
+	qh->hw_current = 0;
+	qh->hw_qtd_next = QTD_NEXT (qtd->qtd_dma);
+	qh->hw_alt_next = EHCI_LIST_END;
+
+	/* HC must see latest qtd and qh data before we clear ACTIVE+HALT */
+	wmb ();
+	qh->hw_token &= __constant_cpu_to_le32 (QTD_TOGGLE | QTD_STS_PING);
+}
+
+/*-------------------------------------------------------------------------*/
+
+#define IS_SHORT_READ(token) (QTD_LENGTH (token) != 0 && QTD_PID (token) == 1)
+
+static void qtd_copy_status (
+	struct ehci_hcd *ehci,
+	struct urb *urb,
+	size_t length,
+	u32 token
+)
+{
+	/* count IN/OUT bytes, not SETUP (even short packets) */
+	if (likely (QTD_PID (token) != 2))
+		urb->actual_length += length - QTD_LENGTH (token);
+
+	/* don't modify error codes */
+	if (unlikely (urb->status != -EINPROGRESS))
+		return;
+
+	/* force cleanup after short read; not always an error */
+	if (unlikely (IS_SHORT_READ (token)))
+		urb->status = -EREMOTEIO;
+
+	/* serious "can't proceed" faults reported by the hardware */
+	if (token & QTD_STS_HALT) {
+		if (token & QTD_STS_BABBLE) {
+			/* FIXME "must" disable babbling device's port too */
+			urb->status = -EOVERFLOW;
+		} else if (token & QTD_STS_MMF) {
+			/* fs/ls interrupt xfer missed the complete-split */
+			urb->status = -EPROTO;
+		} else if (token & QTD_STS_DBE) {
+			urb->status = (QTD_PID (token) == 1) /* IN ? */
+				? -ENOSR  /* hc couldn't read data */
+				: -ECOMM; /* hc couldn't write data */
+		} else if (token & QTD_STS_XACT) {
+			/* timeout, bad crc, wrong PID, etc; retried */
+			if (QTD_CERR (token))
+				urb->status = -EPIPE;
+			else {
+				dbg ("3strikes");
+				urb->status = -EPROTO;
+			}
+		/* CERR nonzero + no errors + halt --> stall */
+		} else if (QTD_CERR (token))
+			urb->status = -EPIPE;
+		else	/* unknown */
+			urb->status = -EPROTO;
+
+		ehci_vdbg (ehci,
+			"dev%d ep%d%s qtd token %08x --> status %d\n",
+			usb_pipedevice (urb->pipe),
+			usb_pipeendpoint (urb->pipe),
+			usb_pipein (urb->pipe) ? "in" : "out",
+			token, urb->status);
+
+		/* stall indicates some recovery action is needed */
+		if (urb->status == -EPIPE) {
+			int	pipe = urb->pipe;
+
+			if (!usb_pipecontrol (pipe))
+				usb_endpoint_halt (urb->dev,
+					usb_pipeendpoint (pipe),
+					usb_pipeout (pipe));
+			if (urb->dev->tt && !usb_pipeint (pipe)) {
+#ifdef DEBUG
+				struct usb_device *tt = urb->dev->tt->hub;
+				dbg ("clear tt %s-%s p%d buffer, a%d ep%d",
+					tt->bus->bus_name, tt->devpath,
+    					urb->dev->ttport, urb->dev->devnum,
+    					usb_pipeendpoint (pipe));
+#endif /* DEBUG */
+				usb_hub_tt_clear_buffer (urb->dev, pipe);
+			}
+		}
+	}
+}
+
+static void
+ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb, struct pt_regs *regs)
+{
+#ifdef	INTR_AUTOMAGIC
+	struct urb		*resubmit = 0;
+	struct usb_device	*dev = 0;
+
+	static int ehci_urb_enqueue (struct usb_hcd *, struct urb *, int);
+#endif
+
+	if (likely (urb->hcpriv != 0)) {
+		struct ehci_qh	*qh = (struct ehci_qh *) urb->hcpriv;
+
+		/* S-mask in a QH means it's an interrupt urb */
+		if ((qh->hw_info2 & cpu_to_le32 (0x00ff)) != 0) {
+
+			/* ... update hc-wide periodic stats (for usbfs) */
+			hcd_to_bus (&ehci->hcd)->bandwidth_int_reqs--;
+
+#ifdef	INTR_AUTOMAGIC
+			if (!((urb->status == -ENOENT)
+					|| (urb->status == -ECONNRESET))) {
+				resubmit = usb_get_urb (urb);
+				dev = urb->dev;
+			}
+#endif
+		}
+		qh_put (ehci, qh);
+	}
+
+	spin_lock (&urb->lock);
+	urb->hcpriv = 0;
+	switch (urb->status) {
+	case -EINPROGRESS:		/* success */
+		urb->status = 0;
+	default:			/* fault */
+		COUNT (ehci->stats.complete);
+		break;
+	case -EREMOTEIO:		/* fault or normal */
+		if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
+			urb->status = 0;
+		COUNT (ehci->stats.complete);
+		break;
+	case -ECONNRESET:		/* canceled */
+	case -ENOENT:
+		COUNT (ehci->stats.unlink);
+		break;
+	}
+	spin_unlock (&urb->lock);
+
+	/* complete() can reenter this HCD */
+	spin_unlock (&ehci->lock);
+	usb_hcd_giveback_urb (&ehci->hcd, urb, regs);
+
+#ifdef	INTR_AUTOMAGIC
+	if (resubmit && ((urb->status == -ENOENT)
+				|| (urb->status == -ECONNRESET))) {
+		usb_put_urb (resubmit);
+		resubmit = 0;
+	}
+	// device drivers will soon be doing something like this
+	if (resubmit) {
+		int	status;
+
+		resubmit->dev = dev;
+		status = SUBMIT_URB (resubmit, SLAB_ATOMIC);
+		if (status != 0)
+			err ("can't resubmit interrupt urb %p: status %d",
+					resubmit, status);
+		usb_put_urb (resubmit);
+	}
+#endif
+
+	spin_lock (&ehci->lock);
+}
+
+
+/*
+ * Process and free completed qtds for a qh, returning URBs to drivers.
+ * Chases up to qh->hw_current.  Returns number of completions called,
+ * indicating how much "real" work we did.
+ */
+#define HALT_BIT cpu_to_le32(QTD_STS_HALT)
+static unsigned
+qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, struct pt_regs *regs)
+{
+	struct ehci_qtd		*last = 0, *end = qh->dummy;
+	struct list_head	*entry, *tmp;
+	int			stopped;
+	unsigned		count = 0;
+	int			do_status = 0;
+	u8			state;
+
+	if (unlikely (list_empty (&qh->qtd_list)))
+		return count;
+
+	/* completions (or tasks on other cpus) must never clobber HALT
+	 * till we've gone through and cleaned everything up, even when
+	 * they add urbs to this qh's queue or mark them for unlinking.
+	 *
+	 * NOTE:  unlinking expects to be done in queue order.
+	 */
+	state = qh->qh_state;
+	qh->qh_state = QH_STATE_COMPLETING;
+	stopped = (state == QH_STATE_IDLE);
+
+	/* remove de-activated QTDs from front of queue.
+	 * after faults (including short reads), cleanup this urb
+	 * then let the queue advance.
+	 * if queue is stopped, handles unlinks.
+	 */
+	list_for_each_safe (entry, tmp, &qh->qtd_list) {
+		struct ehci_qtd	*qtd;
+		struct urb	*urb;
+		u32		token = 0;
+
+		qtd = list_entry (entry, struct ehci_qtd, qtd_list);
+		urb = qtd->urb;
+
+		/* clean up any state from previous QTD ...*/
+		if (last) {
+			if (likely (last->urb != urb)) {
+				ehci_urb_done (ehci, last->urb, regs);
+				count++;
+			}
+			ehci_qtd_free (ehci, last);
+			last = 0;
+		}
+
+		/* ignore urbs submitted during completions we reported */
+		if (qtd == end)
+			break;
+
+		/* hardware copies qtd out of qh overlay */
+		rmb ();
+		token = le32_to_cpu (qtd->hw_token);
+		stopped = stopped
+			|| (HALT_BIT & qh->hw_token) != 0
+			|| (ehci->hcd.state == USB_STATE_HALT);
+
+		/* always clean up qtds the hc de-activated */
+		if ((token & QTD_STS_ACTIVE) == 0) {
+
+			/* magic dummy for short reads; won't advance */
+			if (IS_SHORT_READ (token)
+					&& !(token & QTD_STS_HALT)
+					&& (qh->hw_alt_next & QTD_MASK)
+						== ehci->async->hw_alt_next) {
+				stopped = 1;
+				goto halt;
+			}
+
+		/* stop scanning when we reach qtds the hc is using */
+		} else if (likely (!stopped)) {
+			break;
+
+		} else {
+			/* ignore active urbs unless some previous qtd
+			 * for the urb faulted (including short read) or
+			 * its urb was canceled.  we may patch qh or qtds.
+			 */
+			if (likely (urb->status == -EINPROGRESS))
+				continue;
+			
+			/* issue status after short control reads */
+			if (unlikely (do_status != 0)
+					&& QTD_PID (token) == 0 /* OUT */) {
+				do_status = 0;
+				continue;
+			}
+
+			/* token in overlay may be most current */
+			if (state == QH_STATE_IDLE
+					&& cpu_to_le32 (qtd->qtd_dma)
+						== qh->hw_current)
+				token = le32_to_cpu (qh->hw_token);
+
+			/* force halt for unlinked or blocked qh, so we'll
+			 * patch the qh later and so that completions can't
+			 * activate it while we "know" it's stopped.
+			 */
+			if ((HALT_BIT & qh->hw_token) == 0) {
+halt:
+				qh->hw_token |= HALT_BIT;
+				wmb ();
+			}
+		}
+ 
+		/* remove it from the queue */
+		spin_lock (&urb->lock);
+		qtd_copy_status (ehci, urb, qtd->length, token);
+		do_status = (urb->status == -EREMOTEIO)
+				&& usb_pipecontrol (urb->pipe);
+		spin_unlock (&urb->lock);
+
+		if (stopped && qtd->qtd_list.prev != &qh->qtd_list) {
+			last = list_entry (qtd->qtd_list.prev,
+					struct ehci_qtd, qtd_list);
+			last->hw_next = qtd->hw_next;
+		}
+		list_del (&qtd->qtd_list);
+		last = qtd;
+	}
+
+	/* last urb's completion might still need calling */
+	if (likely (last != 0)) {
+		ehci_urb_done (ehci, last->urb, regs);
+		count++;
+		ehci_qtd_free (ehci, last);
+	}
+
+	/* restore original state; caller must unlink or relink */
+	qh->qh_state = state;
+
+	/* update qh after fault cleanup */
+	if (unlikely ((HALT_BIT & qh->hw_token) != 0)) {
+		qh_update (ehci, qh,
+			list_empty (&qh->qtd_list)
+				? qh->dummy
+				: list_entry (qh->qtd_list.next,
+					struct ehci_qtd, qtd_list));
+	}
+
+	return count;
+}
+#undef HALT_BIT
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * reverse of qh_urb_transaction:  free a list of TDs.
+ * used for cleanup after errors, before HC sees an URB's TDs.
+ */
+static void qtd_list_free (
+	struct ehci_hcd		*ehci,
+	struct urb		*urb,
+	struct list_head	*qtd_list
+) {
+	struct list_head	*entry, *temp;
+
+	list_for_each_safe (entry, temp, qtd_list) {
+		struct ehci_qtd	*qtd;
+
+		qtd = list_entry (entry, struct ehci_qtd, qtd_list);
+		list_del (&qtd->qtd_list);
+		ehci_qtd_free (ehci, qtd);
+	}
+}
+
+/*
+ * create a list of filled qtds for this URB; won't link into qh.
+ */
+static struct list_head *
+qh_urb_transaction (
+	struct ehci_hcd		*ehci,
+	struct urb		*urb,
+	struct list_head	*head,
+	int			flags
+) {
+	struct ehci_qtd		*qtd, *qtd_prev;
+	dma_addr_t		buf;
+	int			len, maxpacket;
+	int			is_input;
+	u32			token;
+
+	/*
+	 * URBs map to sequences of QTDs:  one logical transaction
+	 */
+	qtd = ehci_qtd_alloc (ehci, flags);
+	if (unlikely (!qtd))
+		return 0;
+	list_add_tail (&qtd->qtd_list, head);
+	qtd->urb = urb;
+
+	token = QTD_STS_ACTIVE;
+	token |= (EHCI_TUNE_CERR << 10);
+	/* for split transactions, SplitXState initialized to zero */
+
+	len = urb->transfer_buffer_length;
+	is_input = usb_pipein (urb->pipe);
+	if (usb_pipecontrol (urb->pipe)) {
+		/* SETUP pid */
+		qtd_fill (qtd, urb->setup_dma, sizeof (struct usb_ctrlrequest),
+			token | (2 /* "setup" */ << 8), 8);
+
+		/* ... and always at least one more pid */
+		token ^= QTD_TOGGLE;
+		qtd_prev = qtd;
+		qtd = ehci_qtd_alloc (ehci, flags);
+		if (unlikely (!qtd))
+			goto cleanup;
+		qtd->urb = urb;
+		qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma);
+		list_add_tail (&qtd->qtd_list, head);
+	} 
+
+	/*
+	 * data transfer stage:  buffer setup
+	 */
+	if (likely (len > 0))
+		buf = urb->transfer_dma;
+	else
+		buf = 0;
+
+	// FIXME this 'buf' check break some zlps...
+	if (!buf || is_input)
+		token |= (1 /* "in" */ << 8);
+	/* else it's already initted to "out" pid (0 << 8) */
+
+	maxpacket = usb_maxpacket (urb->dev, urb->pipe, !is_input) & 0x03ff;
+
+	/*
+	 * buffer gets wrapped in one or more qtds;
+	 * last one may be "short" (including zero len)
+	 * and may serve as a control status ack
+	 */
+	for (;;) {
+		int this_qtd_len;
+
+		this_qtd_len = qtd_fill (qtd, buf, len, token, maxpacket);
+		len -= this_qtd_len;
+		buf += this_qtd_len;
+		if (is_input)
+			qtd->hw_alt_next = ehci->async->hw_alt_next;
+
+		/* qh makes control packets use qtd toggle; maybe switch it */
+		if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0)
+			token ^= QTD_TOGGLE;
+
+		if (likely (len <= 0))
+			break;
+
+		qtd_prev = qtd;
+		qtd = ehci_qtd_alloc (ehci, flags);
+		if (unlikely (!qtd))
+			goto cleanup;
+		qtd->urb = urb;
+		qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma);
+		list_add_tail (&qtd->qtd_list, head);
+	}
+
+	/* unless the bulk/interrupt caller wants a chance to clean
+	 * up after short reads, hc should advance qh past this urb
+	 */
+	if (likely ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0
+				|| usb_pipecontrol (urb->pipe)))
+		qtd->hw_alt_next = EHCI_LIST_END;
+
+	/*
+	 * control requests may need a terminating data "status" ack;
+	 * bulk ones may need a terminating short packet (zero length).
+	 */
+	if (likely (buf != 0)) {
+		int	one_more = 0;
+
+		if (usb_pipecontrol (urb->pipe)) {
+			one_more = 1;
+			token ^= 0x0100;	/* "in" <--> "out"  */
+			token |= QTD_TOGGLE;	/* force DATA1 */
+		} else if (usb_pipebulk (urb->pipe)
+				&& (urb->transfer_flags & URB_ZERO_PACKET)
+				&& !(urb->transfer_buffer_length % maxpacket)) {
+			one_more = 1;
+		}
+		if (one_more) {
+			qtd_prev = qtd;
+			qtd = ehci_qtd_alloc (ehci, flags);
+			if (unlikely (!qtd))
+				goto cleanup;
+			qtd->urb = urb;
+			qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma);
+			list_add_tail (&qtd->qtd_list, head);
+
+			/* never any data in such packets */
+			qtd_fill (qtd, 0, 0, token, 0);
+		}
+	}
+
+	/* by default, enable interrupt on urb completion */
+	if (likely (!(urb->transfer_flags & URB_NO_INTERRUPT)))
+		qtd->hw_token |= __constant_cpu_to_le32 (QTD_IOC);
+	return head;
+
+cleanup:
+	qtd_list_free (ehci, urb, head);
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Hardware maintains data toggle (like OHCI) ... here we (re)initialize
+ * the hardware data toggle in the QH, and set the pseudo-toggle in udev
+ * so we can see if usb_clear_halt() was called.  NOP for control, since
+ * we set up qh->hw_info1 to always use the QTD toggle bits. 
+ */
+static inline void
+clear_toggle (struct usb_device *udev, int ep, int is_out, struct ehci_qh *qh)
+{
+	vdbg ("clear toggle, dev %d ep 0x%x-%s",
+		udev->devnum, ep, is_out ? "out" : "in");
+	qh->hw_token &= ~__constant_cpu_to_le32 (QTD_TOGGLE);
+	usb_settoggle (udev, ep, is_out, 1);
+}
+
+// Would be best to create all qh's from config descriptors,
+// when each interface/altsetting is established.  Unlink
+// any previous qh and cancel its urbs first; endpoints are
+// implicitly reset then (data toggle too).
+// That'd mean updating how usbcore talks to HCDs. (2.5?)
+
+
+// high bandwidth multiplier, as encoded in highspeed endpoint descriptors
+#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
+// ... and packet size, for any kind of endpoint descriptor
+#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x03ff)
+
+/*
+ * Each QH holds a qtd list; a QH is used for everything except iso.
+ *
+ * For interrupt urbs, the scheduler must set the microframe scheduling
+ * mask(s) each time the QH gets scheduled.  For highspeed, that's
+ * just one microframe in the s-mask.  For split interrupt transactions
+ * there are additional complications: c-mask, maybe FSTNs.
+ */
+static struct ehci_qh *
+qh_make (
+	struct ehci_hcd		*ehci,
+	struct urb		*urb,
+	int			flags
+) {
+	struct ehci_qh		*qh = ehci_qh_alloc (ehci, flags);
+	u32			info1 = 0, info2 = 0;
+	int			is_input, type;
+	int			maxp = 0;
+
+	if (!qh)
+		return qh;
+
+	/*
+	 * init endpoint/device data for this QH
+	 */
+	info1 |= usb_pipeendpoint (urb->pipe) << 8;
+	info1 |= usb_pipedevice (urb->pipe) << 0;
+
+	is_input = usb_pipein (urb->pipe);
+	type = usb_pipetype (urb->pipe);
+	maxp = usb_maxpacket (urb->dev, urb->pipe, !is_input);
+
+	/* Compute interrupt scheduling parameters just once, and save.
+	 * - allowing for high bandwidth, how many nsec/uframe are used?
+	 * - split transactions need a second CSPLIT uframe; same question
+	 * - splits also need a schedule gap (for full/low speed I/O)
+	 * - qh has a polling interval
+	 *
+	 * For control/bulk requests, the HC or TT handles these.
+	 */
+	if (type == PIPE_INTERRUPT) {
+		qh->usecs = usb_calc_bus_time (USB_SPEED_HIGH, is_input, 0,
+				hb_mult (maxp) * max_packet (maxp));
+		qh->start = NO_FRAME;
+
+		if (urb->dev->speed == USB_SPEED_HIGH) {
+			qh->c_usecs = 0;
+			qh->gap_uf = 0;
+
+			/* FIXME handle HS periods of less than 1 frame. */
+			qh->period = urb->interval >> 3;
+			if (qh->period < 1) {
+				dbg ("intr period %d uframes, NYET!",
+						urb->interval);
+				goto done;
+			}
+		} else {
+			/* gap is f(FS/LS transfer times) */
+			qh->gap_uf = 1 + usb_calc_bus_time (urb->dev->speed,
+					is_input, 0, maxp) / (125 * 1000);
+
+			/* FIXME this just approximates SPLIT/CSPLIT times */
+			if (is_input) {		// SPLIT, gap, CSPLIT+DATA
+				qh->c_usecs = qh->usecs + HS_USECS (0);
+				qh->usecs = HS_USECS (1);
+			} else {		// SPLIT+DATA, gap, CSPLIT
+				qh->usecs += HS_USECS (1);
+				qh->c_usecs = HS_USECS (0);
+			}
+
+			qh->period = urb->interval;
+		}
+	}
+
+	/* using TT? */
+	switch (urb->dev->speed) {
+	case USB_SPEED_LOW:
+		info1 |= (1 << 12);	/* EPS "low" */
+		/* FALL THROUGH */
+
+	case USB_SPEED_FULL:
+		/* EPS 0 means "full" */
+		if (type != PIPE_INTERRUPT)
+			info1 |= (EHCI_TUNE_RL_TT << 28);
+		if (type == PIPE_CONTROL) {
+			info1 |= (1 << 27);	/* for TT */
+			info1 |= 1 << 14;	/* toggle from qtd */
+		}
+		info1 |= maxp << 16;
+
+		info2 |= (EHCI_TUNE_MULT_TT << 30);
+		info2 |= urb->dev->ttport << 23;
+		info2 |= urb->dev->tt->hub->devnum << 16;
+
+		/* NOTE:  if (PIPE_INTERRUPT) { scheduler sets c-mask } */
+
+		break;
+
+	case USB_SPEED_HIGH:		/* no TT involved */
+		info1 |= (2 << 12);	/* EPS "high" */
+		if (type == PIPE_CONTROL) {
+			info1 |= (EHCI_TUNE_RL_HS << 28);
+			info1 |= 64 << 16;	/* usb2 fixed maxpacket */
+			info1 |= 1 << 14;	/* toggle from qtd */
+			info2 |= (EHCI_TUNE_MULT_HS << 30);
+		} else if (type == PIPE_BULK) {
+			info1 |= (EHCI_TUNE_RL_HS << 28);
+			info1 |= 512 << 16;	/* usb2 fixed maxpacket */
+			info2 |= (EHCI_TUNE_MULT_HS << 30);
+		} else {		/* PIPE_INTERRUPT */
+			info1 |= max_packet (maxp) << 16;
+			info2 |= hb_mult (maxp) << 30;
+		}
+		break;
+	default:
+ 		dbg ("bogus dev %p speed %d", urb->dev, urb->dev->speed);
+done:
+		qh_put (ehci, qh);
+		return 0;
+	}
+
+	/* NOTE:  if (PIPE_INTERRUPT) { scheduler sets s-mask } */
+
+	/* init as halted, toggle clear, advance to dummy */
+	qh->qh_state = QH_STATE_IDLE;
+	qh->hw_info1 = cpu_to_le32 (info1);
+	qh->hw_info2 = cpu_to_le32 (info2);
+	qh_update (ehci, qh, qh->dummy);
+	qh->hw_token = cpu_to_le32 (QTD_STS_HALT);
+	usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1);
+	return qh;
+}
+#undef hb_mult
+#undef hb_packet
+
+/*-------------------------------------------------------------------------*/
+
+/* move qh (and its qtds) onto async queue; maybe enable queue.  */
+
+static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+	u32		dma = QH_NEXT (qh->qh_dma);
+	struct ehci_qh	*head;
+
+	/* (re)start the async schedule? */
+	head = ehci->async;
+	if (ehci->async_idle)
+		del_timer (&ehci->watchdog);
+	if (!head->qh_next.qh) {
+		u32	cmd = readl (&ehci->regs->command);
+
+		if (!(cmd & CMD_ASE)) {
+			/* in case a clear of CMD_ASE didn't take yet */
+			(void) handshake (&ehci->regs->status, STS_ASS, 0, 150);
+
+			/* force async head to be valid */
+			writel ((u32)ehci->async->qh_dma,
+					&ehci->regs->async_next);
+
+			cmd |= CMD_ASE | CMD_RUN;
+			writel (cmd, &ehci->regs->command);
+			ehci->hcd.state = USB_STATE_RUNNING;
+			/* posted write need not be known to HC yet ... */
+		}
+	}
+
+	qh->hw_token &= ~__constant_cpu_to_le32 (QTD_STS_HALT);
+
+	/* splice right after start */
+	qh->qh_next = head->qh_next;
+	qh->hw_next = head->hw_next;
+	wmb ();
+
+	head->qh_next.qh = qh;
+	head->hw_next = dma;
+
+	qh->qh_state = QH_STATE_LINKED;
+	/* qtd completions reported later by interrupt */
+
+	ehci->async_idle = 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * For control/bulk/interrupt, return QH with these TDs appended.
+ * Allocates and initializes the QH if necessary.
+ * Returns null if it can't allocate a QH it needs to.
+ * If the QH has TDs (urbs) already, that's great.
+ */
+static struct ehci_qh *qh_append_tds (
+	struct ehci_hcd		*ehci,
+	struct urb		*urb,
+	struct list_head	*qtd_list,
+	int			epnum,
+	void			**ptr
+)
+{
+	struct ehci_qh		*qh = 0;
+
+	qh = (struct ehci_qh *) *ptr;
+	if (unlikely (qh == 0)) {
+		/* can't sleep here, we have ehci->lock... */
+		qh = qh_make (ehci, urb, SLAB_ATOMIC);
+		*ptr = qh;
+	}
+	if (likely (qh != 0)) {
+		struct ehci_qtd	*qtd;
+
+		if (unlikely (list_empty (qtd_list)))
+			qtd = 0;
+		else
+			qtd = list_entry (qtd_list->next, struct ehci_qtd,
+					qtd_list);
+
+		/* control qh may need patching after enumeration */
+		if (unlikely (epnum == 0)) {
+			/* set_address changes the address */
+			if (le32_to_cpu (qh->hw_info1 & 0x7f) == 0)
+				qh->hw_info1 |= cpu_to_le32 (
+						usb_pipedevice (urb->pipe));
+
+			/* for full speed, ep0 maxpacket can grow */
+			else if (!(qh->hw_info1 & cpu_to_le32 (0x3 << 12))) {
+				u32	info, max;
+
+				info = le32_to_cpu (qh->hw_info1);
+				max = urb->dev->descriptor.bMaxPacketSize0;
+				if (max > (0x07ff & (info >> 16))) {
+					info &= ~(0x07ff << 16);
+					info |= max << 16;
+					qh->hw_info1 = cpu_to_le32 (info);
+				}
+			}
+		}
+
+		/* FIXME:  changing config or interface setting is not
+		 * supported yet.  preferred fix is for usbcore to tell
+		 * us to clear out each endpoint's state, but...
+		 */
+
+		/* usb_clear_halt() means qh data toggle gets reset */
+		if (unlikely (!usb_gettoggle (urb->dev,
+					(epnum & 0x0f), !(epnum & 0x10)))
+				&& !usb_pipecontrol (urb->pipe)) {
+			/* "never happens": drivers do stall cleanup right */
+			if (qh->qh_state != QH_STATE_IDLE
+					&& !list_empty (&qh->qtd_list)
+					&& qh->qh_state != QH_STATE_COMPLETING)
+				ehci_warn (ehci, "clear toggle dev%d "
+						"ep%d%s: not idle\n",
+						usb_pipedevice (urb->pipe),
+						epnum & 0x0f,
+						usb_pipein (urb->pipe)
+							? "in" : "out");
+			/* else we know this overlay write is safe */
+			clear_toggle (urb->dev,
+				epnum & 0x0f, !(epnum & 0x10), qh);
+		}
+
+		/* just one way to queue requests: swap with the dummy qtd.
+		 * only hc or qh_completions() usually modify the overlay.
+		 */
+		if (likely (qtd != 0)) {
+			struct ehci_qtd		*dummy;
+			dma_addr_t		dma;
+			u32			token;
+
+			/* to avoid racing the HC, use the dummy td instead of
+			 * the first td of our list (becomes new dummy).  both
+			 * tds stay deactivated until we're done, when the
+			 * HC is allowed to fetch the old dummy (4.10.2).
+			 */
+			token = qtd->hw_token;
+			qtd->hw_token = 0;
+			wmb ();
+			dummy = qh->dummy;
+
+			dma = dummy->qtd_dma;
+			*dummy = *qtd;
+			dummy->qtd_dma = dma;
+
+			list_del (&qtd->qtd_list);
+			list_add (&dummy->qtd_list, qtd_list);
+			__list_splice (qtd_list, qh->qtd_list.prev);
+
+			ehci_qtd_init (qtd, qtd->qtd_dma);
+			qh->dummy = qtd;
+
+			/* hc must see the new dummy at list end */
+			dma = qtd->qtd_dma;
+			qtd = list_entry (qh->qtd_list.prev,
+					struct ehci_qtd, qtd_list);
+			qtd->hw_next = QTD_NEXT (dma);
+
+			/* let the hc process these next qtds */
+			wmb ();
+			dummy->hw_token = token;
+
+			urb->hcpriv = qh_get (qh);
+		}
+	}
+	return qh;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int
+submit_async (
+	struct ehci_hcd		*ehci,
+	struct urb		*urb,
+	struct list_head	*qtd_list,
+	int			mem_flags
+) {
+	struct ehci_qtd		*qtd;
+	struct hcd_dev		*dev;
+	int			epnum;
+	unsigned long		flags;
+	struct ehci_qh		*qh = 0;
+
+	qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list);
+	dev = (struct hcd_dev *)urb->dev->hcpriv;
+	epnum = usb_pipeendpoint (urb->pipe);
+	if (usb_pipein (urb->pipe) && !usb_pipecontrol (urb->pipe))
+		epnum |= 0x10;
+
+	vdbg ("%s: submit_async urb %p len %d ep %d-%s qtd %p [qh %p]",
+		hcd_to_bus (&ehci->hcd)->bus_name,
+		urb, urb->transfer_buffer_length,
+		epnum & 0x0f, (epnum & 0x10) ? "in" : "out",
+		qtd, dev ? dev->ep [epnum] : (void *)~0);
+
+	spin_lock_irqsave (&ehci->lock, flags);
+	qh = qh_append_tds (ehci, urb, qtd_list, epnum, &dev->ep [epnum]);
+
+	/* Control/bulk operations through TTs don't need scheduling,
+	 * the HC and TT handle it when the TT has a buffer ready.
+	 */
+	if (likely (qh != 0)) {
+		if (likely (qh->qh_state == QH_STATE_IDLE))
+			qh_link_async (ehci, qh_get (qh));
+	}
+	spin_unlock_irqrestore (&ehci->lock, flags);
+	if (unlikely (qh == 0)) {
+		qtd_list_free (ehci, urb, qtd_list);
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* the async qh for the qtds being reclaimed are now unlinked from the HC */
+
+static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh);
+
+static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs)
+{
+	struct ehci_qh		*qh = ehci->reclaim;
+	struct ehci_qh		*next;
+
+	del_timer (&ehci->watchdog);
+
+	// qh->hw_next = cpu_to_le32 (qh->qh_dma);
+	qh->qh_state = QH_STATE_IDLE;
+	qh->qh_next.qh = 0;
+	qh_put (ehci, qh);			// refcount from reclaim 
+	ehci->reclaim = 0;
+	ehci->reclaim_ready = 0;
+
+	/* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */
+	next = qh->reclaim;
+	qh->reclaim = 0;
+
+	qh_completions (ehci, qh, regs);
+
+	if (!list_empty (&qh->qtd_list)
+			&& HCD_IS_RUNNING (ehci->hcd.state))
+		qh_link_async (ehci, qh);
+	else {
+		qh_put (ehci, qh);		// refcount from async list
+
+		/* it's not free to turn the async schedule on/off; leave it
+		 * active but idle for a while once it empties.
+		 */
+		if (HCD_IS_RUNNING (ehci->hcd.state)
+				&& ehci->async->qh_next.qh == 0
+				&& !timer_pending (&ehci->watchdog)) {
+			ehci->async_idle = 1;
+			mod_timer (&ehci->watchdog,
+					jiffies + EHCI_ASYNC_JIFFIES);
+		}
+	}
+
+	if (next)
+		start_unlink_async (ehci, next);
+}
+
+/* makes sure the async qh will become idle */
+/* caller must own ehci->lock */
+
+static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+	int		cmd = readl (&ehci->regs->command);
+	struct ehci_qh	*prev;
+
+#ifdef DEBUG
+	if (ehci->reclaim
+			|| (qh->qh_state != QH_STATE_LINKED
+				&& qh->qh_state != QH_STATE_UNLINK_WAIT)
+#ifdef CONFIG_SMP
+// this macro lies except on SMP compiles
+			|| !spin_is_locked (&ehci->lock)
+#endif
+			)
+		BUG ();
+#endif
+
+	/* stop async schedule right now? */
+	if (unlikely (qh == ehci->async)) {
+		/* can't get here without STS_ASS set */
+		if (ehci->hcd.state != USB_STATE_HALT) {
+			writel (cmd & ~CMD_ASE, &ehci->regs->command);
+			wmb ();
+			// handshake later, if we need to
+		}
+		return;
+	} 
+
+	qh->qh_state = QH_STATE_UNLINK;
+	ehci->reclaim = qh = qh_get (qh);
+
+	prev = ehci->async;
+	while (prev->qh_next.qh != qh)
+		prev = prev->qh_next.qh;
+
+	prev->hw_next = qh->hw_next;
+	prev->qh_next = qh->qh_next;
+	wmb ();
+
+	if (unlikely (ehci->hcd.state == USB_STATE_HALT)) {
+		/* if (unlikely (qh->reclaim != 0))
+		 * 	this will recurse, probably not much
+		 */
+		end_unlink_async (ehci, NULL);
+		return;
+	}
+
+	ehci->reclaim_ready = 0;
+	cmd |= CMD_IAAD;
+	writel (cmd, &ehci->regs->command);
+	/* posted write need not be known to HC yet ... */
+
+	mod_timer (&ehci->watchdog, jiffies + EHCI_WATCHDOG_JIFFIES);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void
+scan_async (struct ehci_hcd *ehci, struct pt_regs *regs)
+{
+	struct ehci_qh		*qh;
+	int			unlink_delay = 0;
+
+	if (!++(ehci->stamp))
+		ehci->stamp++;
+rescan:
+	qh = ehci->async->qh_next.qh;
+	if (likely (qh != 0)) {
+		do {
+			/* clean any finished work for this qh */
+			if (!list_empty (&qh->qtd_list)
+					&& qh->stamp != ehci->stamp) {
+				int temp;
+
+				/* unlinks could happen here; completion
+				 * reporting drops the lock.  rescan using
+				 * the latest schedule, but don't rescan
+				 * qhs we already finished (no looping).
+				 */
+				qh = qh_get (qh);
+				qh->stamp = ehci->stamp;
+				temp = qh_completions (ehci, qh, regs);
+				qh_put (ehci, qh);
+				if (temp != 0) {
+					goto rescan;
+				}
+			}
+
+			/* unlink idle entries, reducing HC PCI usage as well
+			 * as HCD schedule-scanning costs.  delay for any qh
+			 * we just scanned, there's a not-unusual case that it
+			 * doesn't stay idle for long.
+			 * (plus, avoids some kind of re-activation race.)
+			 */
+			if (list_empty (&qh->qtd_list)) {
+				if (qh->stamp == ehci->stamp)
+					unlink_delay = 1;
+				else if (!ehci->reclaim) {
+					start_unlink_async (ehci, qh);
+					unlink_delay = 0;
+				}
+			}
+
+			qh = qh->qh_next.qh;
+		} while (qh);
+	}
+
+	if (unlink_delay && !timer_pending (&ehci->watchdog))
+		mod_timer (&ehci->watchdog, jiffies + EHCI_WATCHDOG_JIFFIES/2);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/host/ehci-sched.c linux-2.4.21-pre6/drivers/usb/host/ehci-sched.c
--- linux-2.4.20/drivers/usb/host/ehci-sched.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/host/ehci-sched.c	2003-03-26 23:49:25.000000000 +0000
@@ -0,0 +1,1123 @@
+/*
+ * Copyright (c) 2001-2002 by David Brownell
+ * 
+ * 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 file is part of ehci-hcd.c */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI scheduled transaction support:  interrupt, iso, split iso
+ * These are called "periodic" transactions in the EHCI spec.
+ *
+ * Note that for interrupt transfers, the QH/QTD manipulation is shared
+ * with the "asynchronous" transaction support (control/bulk transfers).
+ * The only real difference is in how interrupt transfers are scheduled.
+ * We get some funky API restrictions from the current URB model, which
+ * works notably better for reading transfers than for writing.  (And
+ * which accordingly needs to change before it'll work inside devices,
+ * or with "USB On The Go" additions to USB 2.0 ...)
+ */
+
+static int ehci_get_frame (struct usb_hcd *hcd);
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * periodic_next_shadow - return "next" pointer on shadow list
+ * @periodic: host pointer to qh/itd/sitd
+ * @tag: hardware tag for type of this record
+ */
+static union ehci_shadow *
+periodic_next_shadow (union ehci_shadow *periodic, int tag)
+{
+	switch (tag) {
+	case Q_TYPE_QH:
+		return &periodic->qh->qh_next;
+	case Q_TYPE_FSTN:
+		return &periodic->fstn->fstn_next;
+	case Q_TYPE_ITD:
+		return &periodic->itd->itd_next;
+#ifdef have_split_iso
+	case Q_TYPE_SITD:
+		return &periodic->sitd->sitd_next;
+#endif /* have_split_iso */
+	}
+	dbg ("BAD shadow %p tag %d", periodic->ptr, tag);
+	// BUG ();
+	return 0;
+}
+
+/* returns true after successful unlink */
+/* caller must hold ehci->lock */
+static int periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr)
+{
+	union ehci_shadow	*prev_p = &ehci->pshadow [frame];
+	u32			*hw_p = &ehci->periodic [frame];
+	union ehci_shadow	here = *prev_p;
+	union ehci_shadow	*next_p;
+
+	/* find predecessor of "ptr"; hw and shadow lists are in sync */
+	while (here.ptr && here.ptr != ptr) {
+		prev_p = periodic_next_shadow (prev_p, Q_NEXT_TYPE (*hw_p));
+		hw_p = &here.qh->hw_next;
+		here = *prev_p;
+	}
+	/* an interrupt entry (at list end) could have been shared */
+	if (!here.ptr) {
+		dbg ("entry %p no longer on frame [%d]", ptr, frame);
+		return 0;
+	}
+	// vdbg ("periodic unlink %p from frame %d", ptr, frame);
+
+	/* update hardware list ... HC may still know the old structure, so
+	 * don't change hw_next until it'll have purged its cache
+	 */
+	next_p = periodic_next_shadow (&here, Q_NEXT_TYPE (*hw_p));
+	*hw_p = here.qh->hw_next;
+
+	/* unlink from shadow list; HCD won't see old structure again */
+	*prev_p = *next_p;
+	next_p->ptr = 0;
+
+	return 1;
+}
+
+/* how many of the uframe's 125 usecs are allocated? */
+static unsigned short
+periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe)
+{
+	u32			*hw_p = &ehci->periodic [frame];
+	union ehci_shadow	*q = &ehci->pshadow [frame];
+	unsigned		usecs = 0;
+
+	while (q->ptr) {
+		switch (Q_NEXT_TYPE (*hw_p)) {
+		case Q_TYPE_QH:
+			/* is it in the S-mask? */
+			if (q->qh->hw_info2 & cpu_to_le32 (1 << uframe))
+				usecs += q->qh->usecs;
+			/* ... or C-mask? */
+			if (q->qh->hw_info2 & cpu_to_le32 (1 << (8 + uframe)))
+				usecs += q->qh->c_usecs;
+			q = &q->qh->qh_next;
+			break;
+		case Q_TYPE_FSTN:
+			/* for "save place" FSTNs, count the relevant INTR
+			 * bandwidth from the previous frame
+			 */
+			if (q->fstn->hw_prev != EHCI_LIST_END) {
+				dbg ("not counting FSTN bandwidth yet ...");
+			}
+			q = &q->fstn->fstn_next;
+			break;
+		case Q_TYPE_ITD:
+			/* NOTE the "one uframe per itd" policy */
+			if (q->itd->hw_transaction [uframe] != 0)
+				usecs += q->itd->usecs;
+			q = &q->itd->itd_next;
+			break;
+#ifdef have_split_iso
+		case Q_TYPE_SITD:
+			temp = q->sitd->hw_fullspeed_ep &
+				__constant_cpu_to_le32 (1 << 31);
+
+			// FIXME:  this doesn't count data bytes right...
+
+			/* is it in the S-mask?  (count SPLIT, DATA) */
+			if (q->sitd->hw_uframe & cpu_to_le32 (1 << uframe)) {
+				if (temp)
+					usecs += HS_USECS (188);
+				else
+					usecs += HS_USECS (1);
+			}
+
+			/* ... C-mask?  (count CSPLIT, DATA) */
+			if (q->sitd->hw_uframe &
+					cpu_to_le32 (1 << (8 + uframe))) {
+				if (temp)
+					usecs += HS_USECS (0);
+				else
+					usecs += HS_USECS (188);
+			}
+			q = &q->sitd->sitd_next;
+			break;
+#endif /* have_split_iso */
+		default:
+			BUG ();
+		}
+	}
+#ifdef	DEBUG
+	if (usecs > 100)
+		err ("overallocated uframe %d, periodic is %d usecs",
+			frame * 8 + uframe, usecs);
+#endif
+	return usecs;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int enable_periodic (struct ehci_hcd *ehci)
+{
+	u32	cmd;
+	int	status;
+
+	/* did clearing PSE did take effect yet?
+	 * takes effect only at frame boundaries...
+	 */
+	status = handshake (&ehci->regs->status, STS_PSS, 0, 9 * 125);
+	if (status != 0) {
+		ehci->hcd.state = USB_STATE_HALT;
+		return status;
+	}
+
+	cmd = readl (&ehci->regs->command) | CMD_PSE;
+	writel (cmd, &ehci->regs->command);
+	/* posted write ... PSS happens later */
+	ehci->hcd.state = USB_STATE_RUNNING;
+
+	/* make sure ehci_work scans these */
+	ehci->next_uframe = readl (&ehci->regs->frame_index)
+				% (ehci->periodic_size << 3);
+	return 0;
+}
+
+static int disable_periodic (struct ehci_hcd *ehci)
+{
+	u32	cmd;
+	int	status;
+
+	/* did setting PSE not take effect yet?
+	 * takes effect only at frame boundaries...
+	 */
+	status = handshake (&ehci->regs->status, STS_PSS, STS_PSS, 9 * 125);
+	if (status != 0) {
+		ehci->hcd.state = USB_STATE_HALT;
+		return status;
+	}
+
+	cmd = readl (&ehci->regs->command) & ~CMD_PSE;
+	writel (cmd, &ehci->regs->command);
+	/* posted write ... */
+
+	ehci->next_uframe = -1;
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+// FIXME microframe periods not yet handled
+
+static void intr_deschedule (
+	struct ehci_hcd	*ehci,
+	struct ehci_qh	*qh,
+	int		wait
+) {
+	int		status;
+	unsigned	frame = qh->start;
+
+	do {
+		periodic_unlink (ehci, frame, qh);
+		qh_put (ehci, qh);
+		frame += qh->period;
+	} while (frame < ehci->periodic_size);
+
+	qh->qh_state = QH_STATE_UNLINK;
+	qh->qh_next.ptr = 0;
+	ehci->periodic_sched--;
+
+	/* maybe turn off periodic schedule */
+	if (!ehci->periodic_sched)
+		status = disable_periodic (ehci);
+	else {
+		status = 0;
+		vdbg ("periodic schedule still enabled");
+	}
+
+	/*
+	 * If the hc may be looking at this qh, then delay a uframe
+	 * (yeech!) to be sure it's done.
+	 * No other threads may be mucking with this qh.
+	 */
+	if (((ehci_get_frame (&ehci->hcd) - frame) % qh->period) == 0) {
+		if (wait) {
+			udelay (125);
+			qh->hw_next = EHCI_LIST_END;
+		} else {
+			/* we may not be IDLE yet, but if the qh is empty
+			 * the race is very short.  then if qh also isn't
+			 * rescheduled soon, it won't matter.  otherwise...
+			 */
+			vdbg ("intr_deschedule...");
+		}
+	} else
+		qh->hw_next = EHCI_LIST_END;
+
+	qh->qh_state = QH_STATE_IDLE;
+
+	/* update per-qh bandwidth utilization (for usbfs) */
+	hcd_to_bus (&ehci->hcd)->bandwidth_allocated -= 
+		(qh->usecs + qh->c_usecs) / qh->period;
+
+	dbg ("descheduled qh %p, period = %d frame = %d count = %d, urbs = %d",
+		qh, qh->period, frame,
+		atomic_read (&qh->refcount), ehci->periodic_sched);
+}
+
+static int check_period (
+	struct ehci_hcd *ehci, 
+	unsigned	frame,
+	unsigned	uframe,
+	unsigned	period,
+	unsigned	usecs
+) {
+	/* complete split running into next frame?
+	 * given FSTN support, we could sometimes check...
+	 */
+	if (uframe >= 8)
+		return 0;
+
+	/*
+	 * 80% periodic == 100 usec/uframe available
+	 * convert "usecs we need" to "max already claimed" 
+	 */
+	usecs = 100 - usecs;
+
+	do {
+		int	claimed;
+
+// FIXME delete when intr_submit handles non-empty queues
+// this gives us a one intr/frame limit (vs N/uframe)
+// ... and also lets us avoid tracking split transactions
+// that might collide at a given TT/hub.
+		if (ehci->pshadow [frame].ptr)
+			return 0;
+
+		claimed = periodic_usecs (ehci, frame, uframe);
+		if (claimed > usecs)
+			return 0;
+
+// FIXME update to handle sub-frame periods
+	} while ((frame += period) < ehci->periodic_size);
+
+	// success!
+	return 1;
+}
+
+static int check_intr_schedule (
+	struct ehci_hcd		*ehci, 
+	unsigned		frame,
+	unsigned		uframe,
+	const struct ehci_qh	*qh,
+	u32			*c_maskp
+)
+{
+    	int		retval = -ENOSPC;
+
+	if (!check_period (ehci, frame, uframe, qh->period, qh->usecs))
+		goto done;
+	if (!qh->c_usecs) {
+		retval = 0;
+		*c_maskp = cpu_to_le32 (0);
+		goto done;
+	}
+
+	/* This is a split transaction; check the bandwidth available for
+	 * the completion too.  Check both worst and best case gaps: worst
+	 * case is SPLIT near uframe end, and CSPLIT near start ... best is
+	 * vice versa.  Difference can be almost two uframe times, but we
+	 * reserve unnecessary bandwidth (waste it) this way.  (Actually
+	 * even better cases exist, like immediate device NAK.)
+	 *
+	 * FIXME don't even bother unless we know this TT is idle in that
+	 * range of uframes ... for now, check_period() allows only one
+	 * interrupt transfer per frame, so needn't check "TT busy" status
+	 * when scheduling a split (QH, SITD, or FSTN).
+	 *
+	 * FIXME ehci 0.96 and above can use FSTNs
+	 */
+	if (!check_period (ehci, frame, uframe + qh->gap_uf + 1,
+				qh->period, qh->c_usecs))
+		goto done;
+	if (!check_period (ehci, frame, uframe + qh->gap_uf,
+				qh->period, qh->c_usecs))
+		goto done;
+
+	*c_maskp = cpu_to_le32 (0x03 << (8 + uframe + qh->gap_uf));
+	retval = 0;
+done:
+	return retval;
+}
+
+static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+	int 		status;
+	unsigned	uframe;
+	u32		c_mask;
+	unsigned	frame;		/* 0..(qh->period - 1), or NO_FRAME */
+
+	qh->hw_next = EHCI_LIST_END;
+	frame = qh->start;
+
+	/* reuse the previous schedule slots, if we can */
+	if (frame < qh->period) {
+		uframe = ffs (le32_to_cpup (&qh->hw_info2) & 0x00ff);
+		status = check_intr_schedule (ehci, frame, --uframe,
+				qh, &c_mask);
+	} else {
+		uframe = 0;
+		c_mask = 0;
+		status = -ENOSPC;
+	}
+
+	/* else scan the schedule to find a group of slots such that all
+	 * uframes have enough periodic bandwidth available.
+	 */
+	if (status) {
+		frame = qh->period - 1;
+		do {
+			for (uframe = 0; uframe < 8; uframe++) {
+				status = check_intr_schedule (ehci,
+						frame, uframe, qh,
+						&c_mask);
+				if (status == 0)
+					break;
+			}
+		} while (status && --frame);
+		if (status)
+			goto done;
+		qh->start = frame;
+
+		/* reset S-frame and (maybe) C-frame masks */
+		qh->hw_info2 &= ~0xffff;
+		qh->hw_info2 |= cpu_to_le32 (1 << uframe) | c_mask;
+	} else
+		dbg ("reused previous qh %p schedule", qh);
+
+	/* stuff into the periodic schedule */
+	qh->qh_state = QH_STATE_LINKED;
+	dbg ("scheduled qh %p usecs %d/%d period %d.0 starting %d.%d (gap %d)",
+		qh, qh->usecs, qh->c_usecs,
+		qh->period, frame, uframe, qh->gap_uf);
+	do {
+		if (unlikely (ehci->pshadow [frame].ptr != 0)) {
+
+// FIXME -- just link toward the end, before any qh with a shorter period,
+// AND accomodate it already having been linked here (after some other qh)
+// AS WELL AS updating the schedule checking logic
+
+			BUG ();
+		} else {
+			ehci->pshadow [frame].qh = qh_get (qh);
+			ehci->periodic [frame] =
+				QH_NEXT (qh->qh_dma);
+		}
+		wmb ();
+		frame += qh->period;
+	} while (frame < ehci->periodic_size);
+
+	/* update per-qh bandwidth for usbfs */
+	hcd_to_bus (&ehci->hcd)->bandwidth_allocated += 
+		(qh->usecs + qh->c_usecs) / qh->period;
+
+	/* maybe enable periodic schedule processing */
+	if (!ehci->periodic_sched++)
+		status = enable_periodic (ehci);
+done:
+	return status;
+}
+
+static int intr_submit (
+	struct ehci_hcd		*ehci,
+	struct urb		*urb,
+	struct list_head	*qtd_list,
+	int			mem_flags
+) {
+	unsigned		epnum;
+	unsigned long		flags;
+	struct ehci_qh		*qh;
+	struct hcd_dev		*dev;
+	int			is_input;
+	int			status = 0;
+	struct list_head	empty;
+
+	/* get endpoint and transfer/schedule data */
+	epnum = usb_pipeendpoint (urb->pipe);
+	is_input = usb_pipein (urb->pipe);
+	if (is_input)
+		epnum |= 0x10;
+
+	spin_lock_irqsave (&ehci->lock, flags);
+	dev = (struct hcd_dev *)urb->dev->hcpriv;
+
+	/* get qh and force any scheduling errors */
+	INIT_LIST_HEAD (&empty);
+	qh = qh_append_tds (ehci, urb, &empty, epnum, &dev->ep [epnum]);
+	if (qh == 0) {
+		status = -ENOMEM;
+		goto done;
+	}
+	if (qh->qh_state == QH_STATE_IDLE) {
+		if ((status = qh_schedule (ehci, qh)) != 0)
+			goto done;
+	}
+
+	/* then queue the urb's tds to the qh */
+	qh = qh_append_tds (ehci, urb, qtd_list, epnum, &dev->ep [epnum]);
+	BUG_ON (qh == 0);
+
+	/* ... update usbfs periodic stats */
+	hcd_to_bus (&ehci->hcd)->bandwidth_int_reqs++;
+
+done:
+	spin_unlock_irqrestore (&ehci->lock, flags);
+	if (status)
+		qtd_list_free (ehci, urb, qtd_list);
+
+	return status;
+}
+
+static unsigned
+intr_complete (
+	struct ehci_hcd	*ehci,
+	unsigned	frame,
+	struct ehci_qh	*qh,
+	struct pt_regs	*regs
+) {
+	unsigned	count;
+
+	/* nothing to report? */
+	if (likely ((qh->hw_token & __constant_cpu_to_le32 (QTD_STS_ACTIVE))
+			!= 0))
+		return 0;
+	if (unlikely (list_empty (&qh->qtd_list))) {
+		dbg ("intr qh %p no TDs?", qh);
+		return 0;
+	}
+	
+	/* handle any completions */
+	count = qh_completions (ehci, qh, regs);
+
+	if (unlikely (list_empty (&qh->qtd_list)))
+		intr_deschedule (ehci, qh, 0);
+
+	return count;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void
+itd_free_list (struct ehci_hcd *ehci, struct urb *urb)
+{
+	struct ehci_itd *first_itd = urb->hcpriv;
+
+	while (!list_empty (&first_itd->itd_list)) {
+		struct ehci_itd	*itd;
+
+		itd = list_entry (
+			first_itd->itd_list.next,
+			struct ehci_itd, itd_list);
+		list_del (&itd->itd_list);
+		pci_pool_free (ehci->itd_pool, itd, itd->itd_dma);
+	}
+	pci_pool_free (ehci->itd_pool, first_itd, first_itd->itd_dma);
+	urb->hcpriv = 0;
+}
+
+static int
+itd_fill (
+	struct ehci_hcd	*ehci,
+	struct ehci_itd	*itd,
+	struct urb	*urb,
+	unsigned	index,		// urb->iso_frame_desc [index]
+	dma_addr_t	dma		// mapped transfer buffer
+) {
+	u64		temp;
+	u32		buf1;
+	unsigned	i, epnum, maxp, multi;
+	unsigned	length;
+	int		is_input;
+
+	itd->hw_next = EHCI_LIST_END;
+	itd->urb = urb;
+	itd->index = index;
+
+	/* tell itd about its transfer buffer, max 2 pages */
+	length = urb->iso_frame_desc [index].length;
+	dma += urb->iso_frame_desc [index].offset;
+	temp = dma & ~0x0fff;
+	for (i = 0; i < 2; i++) {
+		itd->hw_bufp [i] = cpu_to_le32 ((u32) temp);
+		itd->hw_bufp_hi [i] = cpu_to_le32 ((u32)(temp >> 32));
+		temp += 0x1000;
+	}
+	itd->buf_dma = dma;
+
+	/*
+	 * this might be a "high bandwidth" highspeed endpoint,
+	 * as encoded in the ep descriptor's maxpacket field
+	 */
+	epnum = usb_pipeendpoint (urb->pipe);
+	is_input = usb_pipein (urb->pipe);
+	if (is_input) {
+		maxp = urb->dev->epmaxpacketin [epnum];
+		buf1 = (1 << 11);
+	} else {
+		maxp = urb->dev->epmaxpacketout [epnum];
+		buf1 = 0;
+	}
+	buf1 |= (maxp & 0x03ff);
+	multi = 1;
+	multi += (maxp >> 11) & 0x03;
+	maxp &= 0x03ff;
+	maxp *= multi;
+
+	/* transfer can't fit in any uframe? */ 
+	if (length < 0 || maxp < length) {
+		dbg ("BAD iso packet: %d bytes, max %d, urb %p [%d] (of %d)",
+			length, maxp, urb, index,
+			urb->iso_frame_desc [index].length);
+		return -ENOSPC;
+	}
+	itd->usecs = usb_calc_bus_time (USB_SPEED_HIGH, is_input, 1, length);
+
+	/* "plus" info in low order bits of buffer pointers */
+	itd->hw_bufp [0] |= cpu_to_le32 ((epnum << 8) | urb->dev->devnum);
+	itd->hw_bufp [1] |= cpu_to_le32 (buf1);
+	itd->hw_bufp [2] |= cpu_to_le32 (multi);
+
+	/* figure hw_transaction[] value (it's scheduled later) */
+	itd->transaction = EHCI_ISOC_ACTIVE;
+	itd->transaction |= dma & 0x0fff;		/* offset; buffer=0 */
+	if ((index + 1) == urb->number_of_packets)
+		itd->transaction |= EHCI_ITD_IOC; 	/* end-of-urb irq */
+	itd->transaction |= length << 16;
+	cpu_to_le32s (&itd->transaction);
+
+	return 0;
+}
+
+static int
+itd_urb_transaction (
+	struct ehci_hcd		*ehci,
+	struct urb		*urb,
+	int			mem_flags
+) {
+	int			frame_index;
+	struct ehci_itd		*first_itd, *itd;
+	int			status;
+	dma_addr_t		itd_dma;
+
+	/* allocate/init ITDs */
+	for (frame_index = 0, first_itd = 0;
+			frame_index < urb->number_of_packets;
+			frame_index++) {
+		itd = pci_pool_alloc (ehci->itd_pool, mem_flags, &itd_dma);
+		if (!itd) {
+			status = -ENOMEM;
+			goto fail;
+		}
+		memset (itd, 0, sizeof *itd);
+		itd->itd_dma = itd_dma;
+
+		status = itd_fill (ehci, itd, urb, frame_index,
+				urb->transfer_dma);
+		if (status != 0)
+			goto fail;
+
+		if (first_itd)
+			list_add_tail (&itd->itd_list,
+					&first_itd->itd_list);
+		else {
+			INIT_LIST_HEAD (&itd->itd_list);
+			urb->hcpriv = first_itd = itd;
+		}
+	}
+	urb->error_count = 0;
+	return 0;
+
+fail:
+	if (urb->hcpriv)
+		itd_free_list (ehci, urb);
+	return status;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static inline void
+itd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_itd *itd)
+{
+	/* always prepend ITD/SITD ... only QH tree is order-sensitive */
+	itd->itd_next = ehci->pshadow [frame];
+	itd->hw_next = ehci->periodic [frame];
+	ehci->pshadow [frame].itd = itd;
+	ehci->periodic [frame] = cpu_to_le32 (itd->itd_dma) | Q_TYPE_ITD;
+}
+
+/*
+ * return zero on success, else -errno
+ * - start holds first uframe to start scheduling into
+ * - max is the first uframe it's NOT (!) OK to start scheduling into
+ * math to be done modulo "mod" (ehci->periodic_size << 3)
+ */
+static int get_iso_range (
+	struct ehci_hcd		*ehci,
+	struct urb		*urb,
+	unsigned		*start,
+	unsigned		*max,
+	unsigned		mod
+) {
+	struct list_head	*lh;
+	struct hcd_dev		*dev = urb->dev->hcpriv;
+	int			last = -1;
+	unsigned		now, span, end;
+
+	span = urb->interval * urb->number_of_packets;
+
+	/* first see if we know when the next transfer SHOULD happen */
+	list_for_each (lh, &dev->urb_list) {
+		struct urb	*u;
+		struct ehci_itd	*itd;
+		unsigned	s;
+
+		u = list_entry (lh, struct urb, urb_list);
+		if (u == urb || u->pipe != urb->pipe)
+			continue;
+		if (u->interval != urb->interval) {	/* must not change! */ 
+			dbg ("urb %p interval %d ... != %p interval %d",
+				u, u->interval, urb, urb->interval);
+			return -EINVAL;
+		}
+		
+		/* URB for this endpoint... covers through when?  */
+		itd = urb->hcpriv;
+		s = itd->uframe + u->interval * u->number_of_packets;
+		if (last < 0)
+			last = s;
+		else {
+			/*
+			 * So far we can only queue two ISO URBs...
+			 *
+			 * FIXME do interval math, figure out whether
+			 * this URB is "before" or not ... also, handle
+			 * the case where the URB might have completed,
+			 * but hasn't yet been processed.
+			 */
+			dbg ("NYET: queue >2 URBs per ISO endpoint");
+			return -EDOM;
+		}
+	}
+
+	/* calculate the legal range [start,max) */
+	now = readl (&ehci->regs->frame_index) + 1;	/* next uframe */
+	if (!ehci->periodic_sched)
+		now += 8;				/* startup delay */
+	now %= mod;
+	end = now + mod;
+	if (last < 0) {
+		*start = now + ehci->i_thresh + /* paranoia */ 1;
+		*max = end - span;
+		if (*max < *start + 1)
+			*max = *start + 1;
+	} else {
+		*start = last % mod;
+		*max = (last + 1) % mod;
+	}
+
+	/* explicit start frame? */
+	if (!(urb->transfer_flags & URB_ISO_ASAP)) {
+		unsigned	temp;
+
+		/* sanity check: must be in range */
+		urb->start_frame %= ehci->periodic_size;
+		temp = urb->start_frame << 3;
+		if (temp < *start)
+			temp += mod;
+		if (temp > *max)
+			return -EDOM;
+
+		/* use that explicit start frame */
+		*start = urb->start_frame << 3;
+		temp += 8;
+		if (temp < *max)
+			*max = temp;
+	}
+
+	// FIXME minimize wraparound to "now" ... insist max+span
+	// (and start+span) remains a few frames short of "end"
+
+	*max %= ehci->periodic_size;
+	if ((*start + span) < end)
+		return 0;
+	return -EFBIG;
+}
+
+static int
+itd_schedule (struct ehci_hcd *ehci, struct urb *urb)
+{
+	unsigned	start, max, i;
+	int		status;
+	unsigned	mod = ehci->periodic_size << 3;
+
+	for (i = 0; i < urb->number_of_packets; i++) {
+		urb->iso_frame_desc [i].status = -EINPROGRESS;
+		urb->iso_frame_desc [i].actual_length = 0;
+	}
+
+	if ((status = get_iso_range (ehci, urb, &start, &max, mod)) != 0)
+		return status;
+
+	do {
+		unsigned	uframe;
+		unsigned	usecs;
+		struct ehci_itd	*itd;
+
+		/* check schedule: enough space? */
+		itd = urb->hcpriv;
+		uframe = start;
+		for (i = 0, uframe = start;
+				i < urb->number_of_packets;
+				i++, uframe += urb->interval) {
+			uframe %= mod;
+
+			/* can't commit more than 80% periodic == 100 usec */
+			if (periodic_usecs (ehci, uframe >> 3, uframe & 0x7)
+					> (100 - itd->usecs)) {
+				itd = 0;
+				break;
+			}
+			itd = list_entry (itd->itd_list.next,
+				struct ehci_itd, itd_list);
+		}
+		if (!itd)
+			continue;
+		
+		/* that's where we'll schedule this! */
+		itd = urb->hcpriv;
+		urb->start_frame = start >> 3;
+		vdbg ("ISO urb %p (%d packets period %d) starting %d.%d",
+			urb, urb->number_of_packets, urb->interval,
+			urb->start_frame, start & 0x7);
+		for (i = 0, uframe = start, usecs = 0;
+				i < urb->number_of_packets;
+				i++, uframe += urb->interval) {
+			uframe %= mod;
+
+			itd->uframe = uframe;
+			itd->hw_transaction [uframe & 0x07] = itd->transaction;
+			itd_link (ehci, (uframe >> 3) % ehci->periodic_size,
+				itd);
+			wmb ();
+			usecs += itd->usecs;
+
+			itd = list_entry (itd->itd_list.next,
+				struct ehci_itd, itd_list);
+		}
+
+		/* update bandwidth utilization records (for usbfs)
+		 *
+		 * FIXME This claims each URB queued to an endpoint, as if
+		 * transfers were concurrent, not sequential.  So bandwidth
+		 * typically gets double-billed ... comes from tying it to
+		 * URBs rather than endpoints in the schedule.  Luckily we
+		 * don't use this usbfs data for serious decision making.
+		 */
+		usecs /= urb->number_of_packets;
+		usecs /= urb->interval;
+		usecs >>= 3;
+		if (usecs < 1)
+			usecs = 1;
+		usb_claim_bandwidth (urb->dev, urb, usecs, 1);
+
+		/* maybe enable periodic schedule processing */
+		if (!ehci->periodic_sched++) {
+			if ((status =  enable_periodic (ehci)) != 0) {
+				// FIXME deschedule right away
+				err ("itd_schedule, enable = %d", status);
+			}
+		}
+
+		return 0;
+
+	} while ((start = ++start % mod) != max);
+
+	/* no room in the schedule */
+	dbg ("urb %p, CAN'T SCHEDULE", urb);
+	return -ENOSPC;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#define	ISO_ERRS (EHCI_ISOC_BUF_ERR | EHCI_ISOC_BABBLE | EHCI_ISOC_XACTERR)
+
+static unsigned
+itd_complete (
+	struct ehci_hcd	*ehci,
+	struct ehci_itd	*itd,
+	unsigned	uframe,
+	struct pt_regs	*regs
+) {
+	struct urb				*urb = itd->urb;
+	struct usb_iso_packet_descriptor	*desc;
+	u32					t;
+
+	/* update status for this uframe's transfers */
+	desc = &urb->iso_frame_desc [itd->index];
+
+	t = itd->hw_transaction [uframe];
+	itd->hw_transaction [uframe] = 0;
+	if (t & EHCI_ISOC_ACTIVE)
+		desc->status = -EXDEV;
+	else if (t & ISO_ERRS) {
+		urb->error_count++;
+		if (t & EHCI_ISOC_BUF_ERR)
+			desc->status = usb_pipein (urb->pipe)
+				? -ENOSR  /* couldn't read */
+				: -ECOMM; /* couldn't write */
+		else if (t & EHCI_ISOC_BABBLE)
+			desc->status = -EOVERFLOW;
+		else /* (t & EHCI_ISOC_XACTERR) */
+			desc->status = -EPROTO;
+
+		/* HC need not update length with this error */
+		if (!(t & EHCI_ISOC_BABBLE))
+			desc->actual_length += EHCI_ITD_LENGTH (t);
+	} else {
+		desc->status = 0;
+		desc->actual_length += EHCI_ITD_LENGTH (t);
+	}
+
+	vdbg ("itd %p urb %p packet %d/%d trans %x status %d len %d",
+		itd, urb, itd->index + 1, urb->number_of_packets,
+		t, desc->status, desc->actual_length);
+
+	/* handle completion now? */
+	if ((itd->index + 1) != urb->number_of_packets)
+		return 0;
+
+	/*
+	 * Always give the urb back to the driver ... expect it to submit
+	 * a new urb (or resubmit this), and to have another already queued
+	 * when un-interrupted transfers are needed.
+	 *
+	 * NOTE that for now we don't accelerate ISO unlinks; they just
+	 * happen according to the current schedule.  Means a delay of
+	 * up to about a second (max).
+	 */
+	itd_free_list (ehci, urb);
+	if (urb->status == -EINPROGRESS)
+		urb->status = 0;
+
+	/* complete() can reenter this HCD */
+	spin_unlock (&ehci->lock);
+	usb_hcd_giveback_urb (&ehci->hcd, urb, regs);
+	spin_lock (&ehci->lock);
+
+	/* defer stopping schedule; completion can submit */
+	ehci->periodic_sched--;
+	if (!ehci->periodic_sched)
+		(void) disable_periodic (ehci);
+
+	return 1;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags)
+{
+	int		status;
+	unsigned long	flags;
+
+	dbg ("itd_submit urb %p", urb);
+
+	/* allocate ITDs w/o locking anything */
+	status = itd_urb_transaction (ehci, urb, mem_flags);
+	if (status < 0)
+		return status;
+
+	/* schedule ... need to lock */
+	spin_lock_irqsave (&ehci->lock, flags);
+	status = itd_schedule (ehci, urb);
+	spin_unlock_irqrestore (&ehci->lock, flags);
+	if (status < 0)
+		itd_free_list (ehci, urb);
+
+	return status;
+}
+
+#ifdef have_split_iso
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * "Split ISO TDs" ... used for USB 1.1 devices going through
+ * the TTs in USB 2.0 hubs.
+ *
+ * FIXME not yet implemented
+ */
+
+#endif /* have_split_iso */
+
+/*-------------------------------------------------------------------------*/
+
+static void
+scan_periodic (struct ehci_hcd *ehci, struct pt_regs *regs)
+{
+	unsigned	frame, clock, now_uframe, mod;
+	unsigned	count = 0;
+
+	mod = ehci->periodic_size << 3;
+
+	/*
+	 * When running, scan from last scan point up to "now"
+	 * else clean up by scanning everything that's left.
+	 * Touches as few pages as possible:  cache-friendly.
+	 * Don't scan ISO entries more than once, though.
+	 */
+	frame = ehci->next_uframe >> 3;
+	if (HCD_IS_RUNNING (ehci->hcd.state))
+		now_uframe = readl (&ehci->regs->frame_index);
+	else
+		now_uframe = (frame << 3) - 1;
+	now_uframe %= mod;
+	clock = now_uframe >> 3;
+
+	for (;;) {
+		union ehci_shadow	q, *q_p;
+		u32			type, *hw_p;
+		unsigned		uframes;
+
+restart:
+		/* scan schedule to _before_ current frame index */
+		if (frame == clock)
+			uframes = now_uframe & 0x07;
+		else
+			uframes = 8;
+
+		q_p = &ehci->pshadow [frame];
+		hw_p = &ehci->periodic [frame];
+		q.ptr = q_p->ptr;
+		type = Q_NEXT_TYPE (*hw_p);
+
+		/* scan each element in frame's queue for completions */
+		while (q.ptr != 0) {
+			int			last;
+			unsigned		uf;
+			union ehci_shadow	temp;
+
+			switch (type) {
+			case Q_TYPE_QH:
+				last = (q.qh->hw_next == EHCI_LIST_END);
+				temp = q.qh->qh_next;
+				type = Q_NEXT_TYPE (q.qh->hw_next);
+				count += intr_complete (ehci, frame,
+						qh_get (q.qh), regs);
+				qh_put (ehci, q.qh);
+				q = temp;
+				break;
+			case Q_TYPE_FSTN:
+				last = (q.fstn->hw_next == EHCI_LIST_END);
+				/* for "save place" FSTNs, look at QH entries
+				 * in the previous frame for completions.
+				 */
+				if (q.fstn->hw_prev != EHCI_LIST_END) {
+					dbg ("ignoring completions from FSTNs");
+				}
+				type = Q_NEXT_TYPE (q.fstn->hw_next);
+				q = q.fstn->fstn_next;
+				break;
+			case Q_TYPE_ITD:
+				last = (q.itd->hw_next == EHCI_LIST_END);
+
+				/* Unlink each (S)ITD we see, since the ISO
+				 * URB model forces constant rescheduling.
+				 * That complicates sharing uframes in ITDs,
+				 * and means we need to skip uframes the HC
+				 * hasn't yet processed.
+				 */
+				for (uf = 0; uf < uframes; uf++) {
+					if (q.itd->hw_transaction [uf] != 0) {
+						temp = q;
+						*q_p = q.itd->itd_next;
+						*hw_p = q.itd->hw_next;
+						type = Q_NEXT_TYPE (*hw_p);
+
+						/* might free q.itd ... */
+						count += itd_complete (ehci,
+							temp.itd, uf, regs);
+						break;
+					}
+				}
+				/* we might skip this ITD's uframe ... */
+				if (uf == uframes) {
+					q_p = &q.itd->itd_next;
+					hw_p = &q.itd->hw_next;
+					type = Q_NEXT_TYPE (q.itd->hw_next);
+				}
+
+				q = *q_p;
+				break;
+#ifdef have_split_iso
+			case Q_TYPE_SITD:
+				last = (q.sitd->hw_next == EHCI_LIST_END);
+				sitd_complete (ehci, q.sitd);
+				type = Q_NEXT_TYPE (q.sitd->hw_next);
+
+				// FIXME unlink SITD after split completes
+				q = q.sitd->sitd_next;
+				break;
+#endif /* have_split_iso */
+			default:
+				dbg ("corrupt type %d frame %d shadow %p",
+					type, frame, q.ptr);
+				// BUG ();
+				last = 1;
+				q.ptr = 0;
+			}
+
+			/* did completion remove an interior q entry? */
+			if (unlikely (q.ptr == 0 && !last))
+				goto restart;
+		}
+
+		/* stop when we catch up to the HC */
+
+		// FIXME:  this assumes we won't get lapped when
+		// latencies climb; that should be rare, but...
+		// detect it, and just go all the way around.
+		// FLR might help detect this case, so long as latencies
+		// don't exceed periodic_size msec (default 1.024 sec).
+
+		// FIXME:  likewise assumes HC doesn't halt mid-scan
+
+		if (frame == clock) {
+			unsigned	now;
+
+			if (!HCD_IS_RUNNING (ehci->hcd.state))
+				break;
+			ehci->next_uframe = now_uframe;
+			now = readl (&ehci->regs->frame_index) % mod;
+			if (now_uframe == now)
+				break;
+
+			/* rescan the rest of this frame, then ... */
+			now_uframe = now;
+			clock = now_uframe >> 3;
+		} else
+			frame = (frame + 1) % ehci->periodic_size;
+	} 
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/host/ehci.h linux-2.4.21-pre6/drivers/usb/host/ehci.h
--- linux-2.4.20/drivers/usb/host/ehci.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/host/ehci.h	2003-03-26 23:49:54.000000000 +0000
@@ -0,0 +1,455 @@
+/*
+ * Copyright (c) 2001-2002 by David Brownell
+ * 
+ * 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 __LINUX_EHCI_HCD_H
+#define __LINUX_EHCI_HCD_H
+
+/* definitions used for the EHCI driver */
+
+/* statistics can be kept for for tuning/monitoring */
+struct ehci_stats {
+	/* irq usage */
+	unsigned long		normal;
+	unsigned long		error;
+	unsigned long		reclaim;
+	unsigned long		lost_iaa;
+
+	/* termination of urbs from core */
+	unsigned long		complete;
+	unsigned long		unlink;
+};
+
+/* ehci_hcd->lock guards shared data against other CPUs:
+ *   ehci_hcd:	async, reclaim, periodic (and shadow), ...
+ *   hcd_dev:	ep[]
+ *   ehci_qh:	qh_next, qtd_list
+ *   ehci_qtd:	qtd_list
+ *
+ * Also, hold this lock when talking to HC registers or
+ * when updating hw_* fields in shared qh/qtd/... structures.
+ */
+
+#define	EHCI_MAX_ROOT_PORTS	15		/* see HCS_N_PORTS */
+
+struct ehci_hcd {			/* one per controller */
+	spinlock_t		lock;
+
+	/* async schedule support */
+	struct ehci_qh		*async;
+	struct ehci_qh		*reclaim;
+	int			reclaim_ready : 1,
+				async_idle : 1;
+
+	/* periodic schedule support */
+#define	DEFAULT_I_TDPS		1024		/* some HCs can do less */
+	unsigned		periodic_size;
+	u32			*periodic;	/* hw periodic table */
+	dma_addr_t		periodic_dma;
+	unsigned		i_thresh;	/* uframes HC might cache */
+
+	union ehci_shadow	*pshadow;	/* mirror hw periodic table */
+	int			next_uframe;	/* scan periodic, start here */
+	unsigned		periodic_sched;	/* periodic activity count */
+
+	/* per root hub port */
+	unsigned long		reset_done [EHCI_MAX_ROOT_PORTS];
+
+	/* glue to PCI and HCD framework */
+	struct usb_hcd		hcd;
+	struct ehci_caps	*caps;
+	struct ehci_regs	*regs;
+	u32			hcs_params;	/* cached register copy */
+
+	/* per-HC memory pools (could be per-PCI-bus, but ...) */
+	struct pci_pool		*qh_pool;	/* qh per active urb */
+	struct pci_pool		*qtd_pool;	/* one or more per qh */
+	struct pci_pool		*itd_pool;	/* itd per iso urb */
+	struct pci_pool		*sitd_pool;	/* sitd per split iso urb */
+
+	struct timer_list	watchdog;
+	struct notifier_block	reboot_notifier;
+	unsigned		stamp;
+
+	/* irq statistics */
+#ifdef EHCI_STATS
+	struct ehci_stats	stats;
+#	define COUNT(x) do { (x)++; } while (0)
+#else
+#	define COUNT(x) do {} while (0)
+#endif
+};
+
+/* unwrap an HCD pointer to get an EHCI_HCD pointer */ 
+#define hcd_to_ehci(hcd_ptr) container_of(hcd_ptr, struct ehci_hcd, hcd)
+
+/* NOTE:  urb->transfer_flags expected to not use this bit !!! */
+#define EHCI_STATE_UNLINK	0x8000		/* urb being unlinked */
+
+/*-------------------------------------------------------------------------*/
+
+/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */
+
+/* Section 2.2 Host Controller Capability Registers */
+struct ehci_caps {
+	u8		length;		/* CAPLENGTH - size of this struct */
+	u8		reserved;       /* offset 0x1 */
+	u16		hci_version;    /* HCIVERSION - offset 0x2 */
+	u32		hcs_params;     /* HCSPARAMS - offset 0x4 */
+#define HCS_DEBUG_PORT(p)	(((p)>>20)&0xf)	/* bits 23:20, debug port? */
+#define HCS_INDICATOR(p)	((p)&(1 << 16))	/* true: has port indicators */
+#define HCS_N_CC(p)		(((p)>>12)&0xf)	/* bits 15:12, #companion HCs */
+#define HCS_N_PCC(p)		(((p)>>8)&0xf)	/* bits 11:8, ports per CC */
+#define HCS_PORTROUTED(p)	((p)&(1 << 7))	/* true: port routing */ 
+#define HCS_PPC(p)		((p)&(1 << 4))	/* true: port power control */ 
+#define HCS_N_PORTS(p)		(((p)>>0)&0xf)	/* bits 3:0, ports on HC */
+
+	u32		hcc_params;      /* HCCPARAMS - offset 0x8 */
+#define HCC_EXT_CAPS(p)		(((p)>>8)&0xff)	/* for pci extended caps */
+#define HCC_ISOC_CACHE(p)       ((p)&(1 << 7))  /* true: can cache isoc frame */
+#define HCC_ISOC_THRES(p)       (((p)>>4)&0x7)  /* bits 6:4, uframes cached */
+#define HCC_CANPARK(p)		((p)&(1 << 2))  /* true: can park on async qh */
+#define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1))  /* true: periodic_size changes*/
+#define HCC_64BIT_ADDR(p)       ((p)&(1))       /* true: can use 64-bit addr */
+	u8		portroute [8];	 /* nibbles for routing - offset 0xC */
+} __attribute__ ((packed));
+
+
+/* Section 2.3 Host Controller Operational Registers */
+struct ehci_regs {
+
+	/* USBCMD: offset 0x00 */
+	u32		command;
+/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */
+#define CMD_PARK	(1<<11)		/* enable "park" on async qh */
+#define CMD_PARK_CNT(c)	(((c)>>8)&3)	/* how many transfers to park for */
+#define CMD_LRESET	(1<<7)		/* partial reset (no ports, etc) */
+#define CMD_IAAD	(1<<6)		/* "doorbell" interrupt async advance */
+#define CMD_ASE		(1<<5)		/* async schedule enable */
+#define CMD_PSE  	(1<<4)		/* periodic schedule enable */
+/* 3:2 is periodic frame list size */
+#define CMD_RESET	(1<<1)		/* reset HC not bus */
+#define CMD_RUN		(1<<0)		/* start/stop HC */
+
+	/* USBSTS: offset 0x04 */
+	u32		status;
+#define STS_ASS		(1<<15)		/* Async Schedule Status */
+#define STS_PSS		(1<<14)		/* Periodic Schedule Status */
+#define STS_RECL	(1<<13)		/* Reclamation */
+#define STS_HALT	(1<<12)		/* Not running (any reason) */
+/* some bits reserved */
+	/* these STS_* flags are also intr_enable bits (USBINTR) */
+#define STS_IAA		(1<<5)		/* Interrupted on async advance */
+#define STS_FATAL	(1<<4)		/* such as some PCI access errors */
+#define STS_FLR		(1<<3)		/* frame list rolled over */
+#define STS_PCD		(1<<2)		/* port change detect */
+#define STS_ERR		(1<<1)		/* "error" completion (overflow, ...) */
+#define STS_INT		(1<<0)		/* "normal" completion (short, ...) */
+
+	/* USBINTR: offset 0x08 */
+	u32		intr_enable;
+
+	/* FRINDEX: offset 0x0C */
+	u32		frame_index;	/* current microframe number */
+	/* CTRLDSSEGMENT: offset 0x10 */
+	u32		segment; 	/* address bits 63:32 if needed */
+	/* PERIODICLISTBASE: offset 0x14 */
+	u32		frame_list; 	/* points to periodic list */
+	/* ASYNCICLISTADDR: offset 0x18 */
+	u32		async_next;	/* address of next async queue head */
+
+	u32		reserved [9];
+
+	/* CONFIGFLAG: offset 0x40 */
+	u32		configured_flag;
+#define FLAG_CF		(1<<0)		/* true: we'll support "high speed" */
+
+	/* PORTSC: offset 0x44 */
+	u32		port_status [0];	/* up to N_PORTS */
+/* 31:23 reserved */
+#define PORT_WKOC_E	(1<<22)		/* wake on overcurrent (enable) */
+#define PORT_WKDISC_E	(1<<21)		/* wake on disconnect (enable) */
+#define PORT_WKCONN_E	(1<<20)		/* wake on connect (enable) */
+/* 19:16 for port testing */
+/* 15:14 for using port indicator leds (if HCS_INDICATOR allows) */
+#define PORT_OWNER	(1<<13)		/* true: companion hc owns this port */
+#define PORT_POWER	(1<<12)		/* true: has power (see PPC) */
+#define PORT_USB11(x) (((x)&(3<<10))==(1<<10))	/* USB 1.1 device */
+/* 11:10 for detecting lowspeed devices (reset vs release ownership) */
+/* 9 reserved */
+#define PORT_RESET	(1<<8)		/* reset port */
+#define PORT_SUSPEND	(1<<7)		/* suspend port */
+#define PORT_RESUME	(1<<6)		/* resume it */
+#define PORT_OCC	(1<<5)		/* over current change */
+#define PORT_OC		(1<<4)		/* over current active */
+#define PORT_PEC	(1<<3)		/* port enable change */
+#define PORT_PE		(1<<2)		/* port enable */
+#define PORT_CSC	(1<<1)		/* connect status change */
+#define PORT_CONNECT	(1<<0)		/* device connected */
+} __attribute__ ((packed));
+
+
+/*-------------------------------------------------------------------------*/
+
+#define	QTD_NEXT(dma)	cpu_to_le32((u32)dma)
+
+/*
+ * EHCI Specification 0.95 Section 3.5
+ * QTD: describe data transfer components (buffer, direction, ...) 
+ * See Fig 3-6 "Queue Element Transfer Descriptor Block Diagram".
+ *
+ * These are associated only with "QH" (Queue Head) structures,
+ * used with control, bulk, and interrupt transfers.
+ */
+struct ehci_qtd {
+	/* first part defined by EHCI spec */
+	u32			hw_next;	  /* see EHCI 3.5.1 */
+	u32			hw_alt_next;      /* see EHCI 3.5.2 */
+	u32			hw_token;         /* see EHCI 3.5.3 */       
+#define	QTD_TOGGLE	(1 << 31)	/* data toggle */
+#define	QTD_LENGTH(tok)	(((tok)>>16) & 0x7fff)
+#define	QTD_IOC		(1 << 15)	/* interrupt on complete */
+#define	QTD_CERR(tok)	(((tok)>>10) & 0x3)
+#define	QTD_PID(tok)	(((tok)>>8) & 0x3)
+#define	QTD_STS_ACTIVE	(1 << 7)	/* HC may execute this */
+#define	QTD_STS_HALT	(1 << 6)	/* halted on error */
+#define	QTD_STS_DBE	(1 << 5)	/* data buffer error (in HC) */
+#define	QTD_STS_BABBLE	(1 << 4)	/* device was babbling (qtd halted) */
+#define	QTD_STS_XACT	(1 << 3)	/* device gave illegal response */
+#define	QTD_STS_MMF	(1 << 2)	/* incomplete split transaction */
+#define	QTD_STS_STS	(1 << 1)	/* split transaction state */
+#define	QTD_STS_PING	(1 << 0)	/* issue PING? */
+	u32			hw_buf [5];        /* see EHCI 3.5.4 */
+	u32			hw_buf_hi [5];        /* Appendix B */
+
+	/* the rest is HCD-private */
+	dma_addr_t		qtd_dma;		/* qtd address */
+	struct list_head	qtd_list;		/* sw qtd list */
+	struct urb		*urb;			/* qtd's urb */
+	size_t			length;			/* length of buffer */
+} __attribute__ ((aligned (32)));
+
+#define QTD_MASK cpu_to_le32 (~0x1f)	/* mask NakCnt+T in qh->hw_alt_next */
+
+/*-------------------------------------------------------------------------*/
+
+/* type tag from {qh,itd,sitd,fstn}->hw_next */
+#define Q_NEXT_TYPE(dma) ((dma) & __constant_cpu_to_le32 (3 << 1))
+
+/* values for that type tag */
+#define Q_TYPE_ITD	__constant_cpu_to_le32 (0 << 1)
+#define Q_TYPE_QH	__constant_cpu_to_le32 (1 << 1)
+#define Q_TYPE_SITD 	__constant_cpu_to_le32 (2 << 1)
+#define Q_TYPE_FSTN 	__constant_cpu_to_le32 (3 << 1)
+
+/* next async queue entry, or pointer to interrupt/periodic QH */
+#define	QH_NEXT(dma)	(cpu_to_le32(((u32)dma)&~0x01f)|Q_TYPE_QH)
+
+/* for periodic/async schedules and qtd lists, mark end of list */
+#define	EHCI_LIST_END	__constant_cpu_to_le32(1) /* "null pointer" to hw */
+
+/*
+ * Entries in periodic shadow table are pointers to one of four kinds
+ * of data structure.  That's dictated by the hardware; a type tag is
+ * encoded in the low bits of the hardware's periodic schedule.  Use
+ * Q_NEXT_TYPE to get the tag.
+ *
+ * For entries in the async schedule, the type tag always says "qh".
+ */
+union ehci_shadow {
+	struct ehci_qh 		*qh;		/* Q_TYPE_QH */
+	struct ehci_itd		*itd;		/* Q_TYPE_ITD */
+	struct ehci_sitd	*sitd;		/* Q_TYPE_SITD */
+	struct ehci_fstn	*fstn;		/* Q_TYPE_FSTN */
+	void			*ptr;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI Specification 0.95 Section 3.6
+ * QH: describes control/bulk/interrupt endpoints
+ * See Fig 3-7 "Queue Head Structure Layout".
+ *
+ * These appear in both the async and (for interrupt) periodic schedules.
+ */
+
+struct ehci_qh {
+	/* first part defined by EHCI spec */
+	u32			hw_next;	 /* see EHCI 3.6.1 */
+	u32			hw_info1;        /* see EHCI 3.6.2 */
+#define	QH_HEAD		0x00008000
+	u32			hw_info2;        /* see EHCI 3.6.2 */
+	u32			hw_current;	 /* qtd list - see EHCI 3.6.4 */
+	
+	/* qtd overlay (hardware parts of a struct ehci_qtd) */
+	u32			hw_qtd_next;
+	u32			hw_alt_next;
+	u32			hw_token;
+	u32			hw_buf [5];
+	u32			hw_buf_hi [5];
+
+	/* the rest is HCD-private */
+	dma_addr_t		qh_dma;		/* address of qh */
+	union ehci_shadow	qh_next;	/* ptr to qh; or periodic */
+	struct list_head	qtd_list;	/* sw qtd list */
+	struct ehci_qtd		*dummy;
+	struct ehci_qh		*reclaim;	/* next to reclaim */
+
+	atomic_t		refcount;
+	unsigned		stamp;
+
+	u8			qh_state;
+#define	QH_STATE_LINKED		1		/* HC sees this */
+#define	QH_STATE_UNLINK		2		/* HC may still see this */
+#define	QH_STATE_IDLE		3		/* HC doesn't see this */
+#define	QH_STATE_UNLINK_WAIT	4		/* LINKED and on reclaim q */
+#define	QH_STATE_COMPLETING	5		/* don't touch token.HALT */
+
+	/* periodic schedule info */
+	u8			usecs;		/* intr bandwidth */
+	u8			gap_uf;		/* uframes split/csplit gap */
+	u8			c_usecs;	/* ... split completion bw */
+	unsigned short		period;		/* polling interval */
+	unsigned short		start;		/* where polling starts */
+#define NO_FRAME ((unsigned short)~0)			/* pick new start */
+
+} __attribute__ ((aligned (32)));
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI Specification 0.95 Section 3.3
+ * Fig 3-4 "Isochronous Transaction Descriptor (iTD)"
+ *
+ * Schedule records for high speed iso xfers
+ */
+struct ehci_itd {
+	/* first part defined by EHCI spec */
+	u32			hw_next;           /* see EHCI 3.3.1 */
+	u32			hw_transaction [8]; /* see EHCI 3.3.2 */
+#define EHCI_ISOC_ACTIVE        (1<<31)        /* activate transfer this slot */
+#define EHCI_ISOC_BUF_ERR       (1<<30)        /* Data buffer error */
+#define EHCI_ISOC_BABBLE        (1<<29)        /* babble detected */
+#define EHCI_ISOC_XACTERR       (1<<28)        /* XactErr - transaction error */
+#define	EHCI_ITD_LENGTH(tok)	(((tok)>>16) & 0x7fff)
+#define	EHCI_ITD_IOC		(1 << 15)	/* interrupt on complete */
+
+	u32			hw_bufp [7];	/* see EHCI 3.3.3 */ 
+	u32			hw_bufp_hi [7];	/* Appendix B */
+
+	/* the rest is HCD-private */
+	dma_addr_t		itd_dma;	/* for this itd */
+	union ehci_shadow	itd_next;	/* ptr to periodic q entry */
+
+	struct urb		*urb;
+	struct list_head	itd_list;	/* list of urb frames' itds */
+	dma_addr_t		buf_dma;	/* frame's buffer address */
+
+	/* for now, only one hw_transaction per itd */
+	u32			transaction;
+	u16			index;		/* in urb->iso_frame_desc */
+	u16			uframe;		/* in periodic schedule */
+	u16			usecs;
+} __attribute__ ((aligned (32)));
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI Specification 0.95 Section 3.4 
+ * siTD, aka split-transaction isochronous Transfer Descriptor
+ *       ... describe low/full speed iso xfers through TT in hubs
+ * see Figure 3-5 "Split-transaction Isochronous Transaction Descriptor (siTD)
+ */
+struct ehci_sitd {
+	/* first part defined by EHCI spec */
+	u32			hw_next;
+/* uses bit field macros above - see EHCI 0.95 Table 3-8 */
+	u32			hw_fullspeed_ep;  /* see EHCI table 3-9 */
+	u32                     hw_uframe;        /* see EHCI table 3-10 */
+        u32                     hw_tx_results1;   /* see EHCI table 3-11 */
+	u32                     hw_tx_results2;   /* see EHCI table 3-12 */
+	u32                     hw_tx_results3;   /* see EHCI table 3-12 */
+        u32                     hw_backpointer;   /* see EHCI table 3-13 */
+	u32			hw_buf_hi [2];	  /* Appendix B */
+
+	/* the rest is HCD-private */
+	dma_addr_t		sitd_dma;
+	union ehci_shadow	sitd_next;	/* ptr to periodic q entry */
+	struct urb		*urb;
+	dma_addr_t		buf_dma;	/* buffer address */
+
+	unsigned short		usecs;		/* start bandwidth */
+	unsigned short		c_usecs;	/* completion bandwidth */
+} __attribute__ ((aligned (32)));
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI Specification 0.96 Section 3.7
+ * Periodic Frame Span Traversal Node (FSTN)
+ *
+ * Manages split interrupt transactions (using TT) that span frame boundaries
+ * into uframes 0/1; see 4.12.2.2.  In those uframes, a "save place" FSTN
+ * makes the HC jump (back) to a QH to scan for fs/ls QH completions until
+ * it hits a "restore" FSTN; then it returns to finish other uframe 0/1 work.
+ */
+struct ehci_fstn {
+	u32			hw_next;	/* any periodic q entry */
+	u32			hw_prev;	/* qh or EHCI_LIST_END */
+
+	/* the rest is HCD-private */
+	dma_addr_t		fstn_dma;
+	union ehci_shadow	fstn_next;	/* ptr to periodic q entry */
+} __attribute__ ((aligned (32)));
+
+/*-------------------------------------------------------------------------*/
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,32)
+
+#define SUBMIT_URB(urb,mem_flags) usb_submit_urb(urb)
+#define STUB_DEBUG_FILES
+
+static inline int hcd_register_root (struct usb_hcd *hcd)
+{
+	return usb_new_device (hcd_to_bus (hcd)->root_hub);
+}
+
+#else	/* LINUX_VERSION_CODE */
+
+// hcd_to_bus() eventually moves to hcd.h on 2.5 too
+static inline struct usb_bus *hcd_to_bus (struct usb_hcd *hcd)
+	{ return &hcd->self; }
+// ... as does hcd_register_root()
+static inline int hcd_register_root (struct usb_hcd *hcd)
+{
+	return usb_register_root_hub (
+		hcd_to_bus (hcd)->root_hub, &hcd->pdev->dev);
+}
+
+#define SUBMIT_URB(urb,mem_flags) usb_submit_urb(urb,mem_flags)
+
+#ifndef DEBUG
+#define STUB_DEBUG_FILES
+#endif	/* DEBUG */
+
+#endif	/* LINUX_VERSION_CODE */
+
+/*-------------------------------------------------------------------------*/
+
+#endif /* __LINUX_EHCI_HCD_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/host/uhci-debug.h linux-2.4.21-pre6/drivers/usb/host/uhci-debug.h
--- linux-2.4.20/drivers/usb/host/uhci-debug.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/host/uhci-debug.h	2003-03-26 23:49:53.000000000 +0000
@@ -0,0 +1,573 @@
+/*
+ * UHCI-specific debugging code. Invaluable when something
+ * goes wrong, but don't get in my face.
+ *
+ * Kernel visible pointers are surrounded in []'s and bus
+ * visible pointers are surrounded in ()'s
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999-2001 Johannes Erdfelt
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/proc_fs.h>
+#include <asm/io.h>
+
+#include "uhci.h"
+
+/* Handle REALLY large printk's so we don't overflow buffers */
+static void inline lprintk(char *buf)
+{
+	char *p;
+
+	/* Just write one line at a time */
+	while (buf) {
+		p = strchr(buf, '\n');
+		if (p)
+			*p = 0;
+		printk("%s\n", buf);
+		buf = p;
+		if (buf)
+			buf++;
+	}
+}
+
+static int inline uhci_is_skeleton_td(struct uhci *uhci, struct uhci_td *td)
+{
+	int i;
+
+	for (i = 0; i < UHCI_NUM_SKELTD; i++)
+		if (td == uhci->skeltd[i])
+			return 1;
+
+	return 0;
+}
+
+static int inline uhci_is_skeleton_qh(struct uhci *uhci, struct uhci_qh *qh)
+{
+	int i;
+
+	for (i = 0; i < UHCI_NUM_SKELQH; i++)
+		if (qh == uhci->skelqh[i])
+			return 1;
+
+	return 0;
+}
+
+static int uhci_show_td(struct uhci_td *td, char *buf, int len, int space)
+{
+	char *out = buf;
+	char *spid;
+
+	/* Try to make sure there's enough memory */
+	if (len < 160)
+		return 0;
+
+	out += sprintf(out, "%*s[%p] link (%08x) ", space, "", td, td->link);
+	out += sprintf(out, "e%d %s%s%s%s%s%s%s%s%s%sLength=%x ",
+		((td->status >> 27) & 3),
+		(td->status & TD_CTRL_SPD) ?      "SPD " : "",
+		(td->status & TD_CTRL_LS) ?       "LS " : "",
+		(td->status & TD_CTRL_IOC) ?      "IOC " : "",
+		(td->status & TD_CTRL_ACTIVE) ?   "Active " : "",
+		(td->status & TD_CTRL_STALLED) ?  "Stalled " : "",
+		(td->status & TD_CTRL_DBUFERR) ?  "DataBufErr " : "",
+		(td->status & TD_CTRL_BABBLE) ?   "Babble " : "",
+		(td->status & TD_CTRL_NAK) ?      "NAK " : "",
+		(td->status & TD_CTRL_CRCTIMEO) ? "CRC/Timeo " : "",
+		(td->status & TD_CTRL_BITSTUFF) ? "BitStuff " : "",
+		td->status & 0x7ff);
+
+	switch (td->info & 0xff) {
+		case USB_PID_SETUP:
+			spid = "SETUP";
+			break;
+		case USB_PID_OUT:
+			spid = "OUT";
+			break;
+		case USB_PID_IN:
+			spid = "IN";
+			break;
+		default:
+			spid = "?";
+			break;
+	}
+
+	out += sprintf(out, "MaxLen=%x DT%d EndPt=%x Dev=%x, PID=%x(%s) ",
+		td->info >> 21,
+		((td->info >> 19) & 1),
+		(td->info >> 15) & 15,
+		(td->info >> 8) & 127,
+		(td->info & 0xff),
+		spid);
+	out += sprintf(out, "(buf=%08x)\n", td->buffer);
+
+	return out - buf;
+}
+
+static int uhci_show_sc(int port, unsigned short status, char *buf, int len)
+{
+	char *out = buf;
+
+	/* Try to make sure there's enough memory */
+	if (len < 80)
+		return 0;
+
+	out += sprintf(out, "  stat%d     =     %04x   %s%s%s%s%s%s%s%s\n",
+		port,
+		status,
+		(status & USBPORTSC_SUSP) ? "PortSuspend " : "",
+		(status & USBPORTSC_PR) ?   "PortReset " : "",
+		(status & USBPORTSC_LSDA) ? "LowSpeed " : "",
+		(status & USBPORTSC_RD) ?   "ResumeDetect " : "",
+		(status & USBPORTSC_PEC) ?  "EnableChange " : "",
+		(status & USBPORTSC_PE) ?   "PortEnabled " : "",
+		(status & USBPORTSC_CSC) ?  "ConnectChange " : "",
+		(status & USBPORTSC_CCS) ?  "PortConnected " : "");
+
+	return out - buf;
+}
+
+static int uhci_show_status(struct uhci *uhci, char *buf, int len)
+{
+	char *out = buf;
+	unsigned int io_addr = uhci->io_addr;
+	unsigned short usbcmd, usbstat, usbint, usbfrnum;
+	unsigned int flbaseadd;
+	unsigned char sof;
+	unsigned short portsc1, portsc2;
+
+	/* Try to make sure there's enough memory */
+	if (len < 80 * 6)
+		return 0;
+
+	usbcmd    = inw(io_addr + 0);
+	usbstat   = inw(io_addr + 2);
+	usbint    = inw(io_addr + 4);
+	usbfrnum  = inw(io_addr + 6);
+	flbaseadd = inl(io_addr + 8);
+	sof       = inb(io_addr + 12);
+	portsc1   = inw(io_addr + 16);
+	portsc2   = inw(io_addr + 18);
+
+	out += sprintf(out, "  usbcmd    =     %04x   %s%s%s%s%s%s%s%s\n",
+		usbcmd,
+		(usbcmd & USBCMD_MAXP) ?    "Maxp64 " : "Maxp32 ",
+		(usbcmd & USBCMD_CF) ?      "CF " : "",
+		(usbcmd & USBCMD_SWDBG) ?   "SWDBG " : "",
+		(usbcmd & USBCMD_FGR) ?     "FGR " : "",
+		(usbcmd & USBCMD_EGSM) ?    "EGSM " : "",
+		(usbcmd & USBCMD_GRESET) ?  "GRESET " : "",
+		(usbcmd & USBCMD_HCRESET) ? "HCRESET " : "",
+		(usbcmd & USBCMD_RS) ?      "RS " : "");
+
+	out += sprintf(out, "  usbstat   =     %04x   %s%s%s%s%s%s\n",
+		usbstat,
+		(usbstat & USBSTS_HCH) ?    "HCHalted " : "",
+		(usbstat & USBSTS_HCPE) ?   "HostControllerProcessError " : "",
+		(usbstat & USBSTS_HSE) ?    "HostSystemError " : "",
+		(usbstat & USBSTS_RD) ?     "ResumeDetect " : "",
+		(usbstat & USBSTS_ERROR) ?  "USBError " : "",
+		(usbstat & USBSTS_USBINT) ? "USBINT " : "");
+
+	out += sprintf(out, "  usbint    =     %04x\n", usbint);
+	out += sprintf(out, "  usbfrnum  =   (%d)%03x\n", (usbfrnum >> 10) & 1,
+		0xfff & (4*(unsigned int)usbfrnum));
+	out += sprintf(out, "  flbaseadd = %08x\n", flbaseadd);
+	out += sprintf(out, "  sof       =       %02x\n", sof);
+	out += uhci_show_sc(1, portsc1, out, len - (out - buf));
+	out += uhci_show_sc(2, portsc2, out, len - (out - buf));
+
+	return out - buf;
+}
+
+static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
+{
+	char *out = buf;
+	struct urb_priv *urbp;
+	struct list_head *head, *tmp;
+	struct uhci_td *td;
+	int i = 0, checked = 0, prevactive = 0;
+
+	/* Try to make sure there's enough memory */
+	if (len < 80 * 6)
+		return 0;
+
+	out += sprintf(out, "%*s[%p] link (%08x) element (%08x)\n", space, "",
+			qh, qh->link, qh->element);
+
+	if (qh->element & UHCI_PTR_QH)
+		out += sprintf(out, "%*s  Element points to QH (bug?)\n", space, "");
+
+	if (qh->element & UHCI_PTR_DEPTH)
+		out += sprintf(out, "%*s  Depth traverse\n", space, "");
+
+	if (qh->element & 8)
+		out += sprintf(out, "%*s  Bit 3 set (bug?)\n", space, "");
+
+	if (!(qh->element & ~(UHCI_PTR_QH | UHCI_PTR_DEPTH)))
+		out += sprintf(out, "%*s  Element is NULL (bug?)\n", space, "");
+
+	if (!qh->urbp) {
+		out += sprintf(out, "%*s  urbp == NULL\n", space, "");
+		goto out;
+	}
+
+	urbp = qh->urbp;
+
+	head = &urbp->td_list;
+	tmp = head->next;
+
+	td = list_entry(tmp, struct uhci_td, list);
+
+	if (td->dma_handle != (qh->element & ~UHCI_PTR_BITS))
+		out += sprintf(out, "%*s Element != First TD\n", space, "");
+
+	while (tmp != head) {
+		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
+
+		tmp = tmp->next;
+
+		out += sprintf(out, "%*s%d: ", space + 2, "", i++);
+		out += uhci_show_td(td, out, len - (out - buf), 0);
+
+		if (i > 10 && !checked && prevactive && tmp != head &&
+		    debug <= 2) {
+			struct list_head *ntmp = tmp;
+			struct uhci_td *ntd = td;
+			int active = 1, ni = i;
+
+			checked = 1;
+
+			while (ntmp != head && ntmp->next != head && active) {
+				ntd = list_entry(ntmp, struct uhci_td, list);
+
+				ntmp = ntmp->next;
+
+				active = ntd->status & TD_CTRL_ACTIVE;
+
+				ni++;
+			}
+
+			if (active && ni > i) {
+				out += sprintf(out, "%*s[skipped %d active TD's]\n", space, "", ni - i);
+				tmp = ntmp;
+				td = ntd;
+				i = ni;
+			}
+		}
+
+		prevactive = td->status & TD_CTRL_ACTIVE;
+	}
+
+	if (list_empty(&urbp->queue_list) || urbp->queued)
+		goto out;
+
+	out += sprintf(out, "%*sQueued QH's:\n", -space, "--");
+
+	head = &urbp->queue_list;
+	tmp = head->next;
+
+	while (tmp != head) {
+		struct urb_priv *nurbp = list_entry(tmp, struct urb_priv,
+						queue_list);
+		tmp = tmp->next;
+
+		out += uhci_show_qh(nurbp->qh, out, len - (out - buf), space);
+	}
+
+out:
+	return out - buf;
+}
+
+static const char *td_names[] = {"skel_int1_td", "skel_int2_td",
+				 "skel_int4_td", "skel_int8_td",
+				 "skel_int16_td", "skel_int32_td",
+				 "skel_int64_td", "skel_int128_td",
+				 "skel_int256_td", "skel_term_td" };
+static const char *qh_names[] = { "skel_ls_control_qh", "skel_hs_control_qh",
+				  "skel_bulk_qh", "skel_term_qh" };
+
+#define show_frame_num()	\
+	if (!shown) {		\
+	  shown = 1;		\
+	  out += sprintf(out, "- Frame %d\n", i); \
+	}
+
+#define show_td_name()		\
+	if (!shown) {		\
+	  shown = 1;		\
+	  out += sprintf(out, "- %s\n", td_names[i]); \
+	}
+
+#define show_qh_name()		\
+	if (!shown) {		\
+	  shown = 1;		\
+	  out += sprintf(out, "- %s\n", qh_names[i]); \
+	}
+
+static int uhci_sprint_schedule(struct uhci *uhci, char *buf, int len)
+{
+	char *out = buf;
+	int i;
+	struct uhci_qh *qh;
+	struct uhci_td *td;
+	struct list_head *tmp, *head;
+
+	out += sprintf(out, "HC status\n");
+	out += uhci_show_status(uhci, out, len - (out - buf));
+
+	out += sprintf(out, "Frame List\n");
+	for (i = 0; i < UHCI_NUMFRAMES; ++i) {
+		int shown = 0;
+		td = uhci->fl->frame_cpu[i];
+		if (!td)
+			continue;
+
+		if (td->dma_handle != (dma_addr_t)uhci->fl->frame[i]) {
+			show_frame_num();
+			out += sprintf(out, "    frame list does not match td->dma_handle!\n");
+		}
+		if (uhci_is_skeleton_td(uhci, td))
+			continue;
+		show_frame_num();
+
+		head = &td->fl_list;
+		tmp = head;
+		do {
+			td = list_entry(tmp, struct uhci_td, fl_list);
+			tmp = tmp->next;
+			out += uhci_show_td(td, out, len - (out - buf), 4);
+		} while (tmp != head);
+	}
+
+	out += sprintf(out, "Skeleton TD's\n");
+	for (i = UHCI_NUM_SKELTD - 1; i >= 0; i--) {
+		int shown = 0;
+
+		td = uhci->skeltd[i];
+
+		if (debug > 1) {
+			show_td_name();
+			out += uhci_show_td(td, out, len - (out - buf), 4);
+		}
+
+		if (list_empty(&td->fl_list)) {
+			/* TD 0 is the int1 TD and links to control_ls_qh */
+			if (!i) {
+				if (td->link !=
+				    (uhci->skel_ls_control_qh->dma_handle | UHCI_PTR_QH)) {
+					show_td_name();
+					out += sprintf(out, "    skeleton TD not linked to ls_control QH!\n");
+				}
+			} else if (i < 9) {
+				if (td->link != uhci->skeltd[i - 1]->dma_handle) {
+					show_td_name();
+					out += sprintf(out, "    skeleton TD not linked to next skeleton TD!\n");
+				}
+			} else {
+				show_td_name();
+
+				if (td->link != td->dma_handle)
+					out += sprintf(out, "    skel_term_td does not link to self\n");
+
+				/* Don't show it twice */
+				if (debug <= 1)
+					out += uhci_show_td(td, out, len - (out - buf), 4);
+			}
+
+			continue;
+		}
+
+		show_td_name();
+
+		head = &td->fl_list;
+		tmp = head->next;
+
+		while (tmp != head) {
+			td = list_entry(tmp, struct uhci_td, fl_list);
+
+			tmp = tmp->next;
+
+			out += uhci_show_td(td, out, len - (out - buf), 4);
+		}
+
+		if (!i) {
+			if (td->link !=
+			    (uhci->skel_ls_control_qh->dma_handle | UHCI_PTR_QH))
+				out += sprintf(out, "    last TD not linked to ls_control QH!\n");
+		} else if (i < 9) {
+			if (td->link != uhci->skeltd[i - 1]->dma_handle)
+				out += sprintf(out, "    last TD not linked to next skeleton!\n");
+		}
+	}
+
+	out += sprintf(out, "Skeleton QH's\n");
+
+	for (i = 0; i < UHCI_NUM_SKELQH; ++i) {
+		int shown = 0;
+
+		qh = uhci->skelqh[i];
+
+		if (debug > 1) {
+			show_qh_name();
+			out += uhci_show_qh(qh, out, len - (out - buf), 4);
+		}
+
+		/* QH 3 is the Terminating QH, it's different */
+		if (i == 3) {
+			if (qh->link != UHCI_PTR_TERM) {
+				show_qh_name();
+				out += sprintf(out, "    bandwidth reclamation on!\n");
+			}
+
+			if (qh->element != uhci->skel_term_td->dma_handle) {
+				show_qh_name();
+				out += sprintf(out, "    skel_term_qh element is not set to skel_term_td\n");
+			}
+		}
+
+		if (list_empty(&qh->list)) {
+			if (i < 3) {
+				if (qh->link !=
+				    (uhci->skelqh[i + 1]->dma_handle | UHCI_PTR_QH)) {
+					show_qh_name();
+					out += sprintf(out, "    skeleton QH not linked to next skeleton QH!\n");
+				}
+			}
+
+			continue;
+		}
+
+		show_qh_name();
+
+		head = &qh->list;
+		tmp = head->next;
+
+		while (tmp != head) {
+			qh = list_entry(tmp, struct uhci_qh, list);
+
+			tmp = tmp->next;
+
+			out += uhci_show_qh(qh, out, len - (out - buf), 4);
+		}
+
+		if (i < 3) {
+			if (qh->link !=
+			    (uhci->skelqh[i + 1]->dma_handle | UHCI_PTR_QH))
+				out += sprintf(out, "    last QH not linked to next skeleton!\n");
+		}
+	}
+
+	return out - buf;
+}
+
+#ifdef CONFIG_PROC_FS
+#define MAX_OUTPUT	(PAGE_SIZE * 8)
+
+static struct proc_dir_entry *uhci_proc_root = NULL;
+
+struct uhci_proc {
+	int size;
+	char *data;
+	struct uhci *uhci;
+};
+
+static int uhci_proc_open(struct inode *inode, struct file *file)
+{
+	const struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct uhci *uhci = dp->data;
+	struct uhci_proc *up;
+	unsigned long flags;
+	int ret = -ENOMEM;
+
+	lock_kernel();
+	up = kmalloc(sizeof(*up), GFP_KERNEL);
+	if (!up)
+		goto out;
+
+	up->data = kmalloc(MAX_OUTPUT, GFP_KERNEL);
+	if (!up->data) {
+		kfree(up);
+		goto out;
+	}
+
+	spin_lock_irqsave(&uhci->frame_list_lock, flags);
+	up->size = uhci_sprint_schedule(uhci, up->data, MAX_OUTPUT);
+	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
+
+	file->private_data = up;
+
+	ret = 0;
+out:
+	unlock_kernel();
+	return ret;
+}
+
+static loff_t uhci_proc_lseek(struct file *file, loff_t off, int whence)
+{
+	struct uhci_proc *up = file->private_data;
+	loff_t new;
+
+	switch (whence) {
+	case 0:
+		new = off;
+		break;
+	case 1:
+		new = file->f_pos + off;
+		break;
+	case 2:
+	default:
+		return -EINVAL;
+	}
+	if (new < 0 || new > up->size)
+		return -EINVAL;
+	return (file->f_pos = new);
+}
+
+static ssize_t uhci_proc_read(struct file *file, char *buf, size_t nbytes,
+			loff_t *ppos)
+{
+	struct uhci_proc *up = file->private_data;
+	unsigned int pos;
+	unsigned int size;
+
+	pos = *ppos;
+	size = up->size;
+	if (pos >= size)
+		return 0;
+	if (nbytes >= size)
+		nbytes = size;
+	if (pos + nbytes > size)
+		nbytes = size - pos;
+
+	if (!access_ok(VERIFY_WRITE, buf, nbytes))
+		return -EINVAL;
+
+	copy_to_user(buf, up->data + pos, nbytes);
+
+	*ppos += nbytes;
+
+	return nbytes;
+}
+
+static int uhci_proc_release(struct inode *inode, struct file *file)
+{
+	struct uhci_proc *up = file->private_data;
+
+	kfree(up->data);
+	kfree(up);
+
+	return 0;
+}
+
+static struct file_operations uhci_proc_operations = {
+	open:		uhci_proc_open,
+	llseek:		uhci_proc_lseek,
+	read:		uhci_proc_read,
+//	write:		uhci_proc_write,
+	release:	uhci_proc_release,
+};
+#endif
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/host/uhci.c linux-2.4.21-pre6/drivers/usb/host/uhci.c
--- linux-2.4.20/drivers/usb/host/uhci.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/host/uhci.c	2003-03-26 23:49:51.000000000 +0000
@@ -0,0 +1,3172 @@
+/*
+ * Universal Host Controller Interface driver for USB.
+ *
+ * Maintainer: Johannes Erdfelt <johannes@erdfelt.com>
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@erdfelt.com
+ * (C) Copyright 1999 Randy Dunlap
+ * (C) Copyright 1999 Georg Acher, acher@in.tum.de
+ * (C) Copyright 1999 Deti Fliegl, deti@fliegl.de
+ * (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch
+ * (C) Copyright 1999 Roman Weissgaerber, weissg@vienna.at
+ * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
+ *               support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
+ * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
+ *
+ * Intel documents this fairly well, and as far as I know there
+ * are no royalties or anything like that, but even so there are
+ * people who decided that they want to do the same thing in a
+ * completely different way.
+ *
+ * WARNING! The USB documentation is downright evil. Most of it
+ * is just crap, written by a committee. You're better off ignoring
+ * most of it, the important stuff is:
+ *  - the low-level protocol (fairly simple but lots of small details)
+ *  - working around the horridness of the rest
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/proc_fs.h>
+#ifdef CONFIG_USB_DEBUG
+#define DEBUG
+#else
+#undef DEBUG
+#endif
+#include <linux/usb.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+#include "uhci.h"
+
+#include <linux/pm.h>
+
+#include "../hcd.h"
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v1.1"
+#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"
+
+/*
+ * debug = 0, no debugging messages
+ * debug = 1, dump failed URB's except for stalls
+ * debug = 2, dump all failed URB's (including stalls)
+ *            show all queues in /proc/uhci/hc*
+ * debug = 3, show all TD's in URB's when dumping
+ */
+#ifdef DEBUG
+static int debug = 1;
+#else
+static int debug = 0;
+#endif
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug level");
+static char *errbuf;
+#define ERRBUF_LEN    (PAGE_SIZE * 8)
+
+#include "uhci-debug.h"
+
+static kmem_cache_t *uhci_up_cachep;	/* urb_priv */
+
+static int rh_submit_urb(struct urb *urb);
+static int rh_unlink_urb(struct urb *urb);
+static int uhci_get_current_frame_number(struct usb_device *dev);
+static int uhci_unlink_urb(struct urb *urb);
+static void uhci_unlink_generic(struct uhci *uhci, struct urb *urb);
+static void uhci_call_completion(struct urb *urb);
+
+static int  ports_active(struct uhci *uhci);
+static void suspend_hc(struct uhci *uhci);
+static void wakeup_hc(struct uhci *uhci);
+
+/* If a transfer is still active after this much time, turn off FSBR */
+#define IDLE_TIMEOUT	(HZ / 20)	/* 50 ms */
+#define FSBR_DELAY	(HZ / 20)	/* 50 ms */
+
+/* When we timeout an idle transfer for FSBR, we'll switch it over to */
+/* depth first traversal. We'll do it in groups of this number of TD's */
+/* to make sure it doesn't hog all of the bandwidth */
+#define DEPTH_INTERVAL	5
+
+#define MAX_URB_LOOP	2048		/* Maximum number of linked URB's */
+
+/*
+ * Only the USB core should call uhci_alloc_dev and uhci_free_dev
+ */
+static int uhci_alloc_dev(struct usb_device *dev)
+{
+	return 0;
+}
+
+static int uhci_free_dev(struct usb_device *dev)
+{
+	return 0;
+}
+
+/*
+ * Technically, updating td->status here is a race, but it's not really a
+ * problem. The worst that can happen is that we set the IOC bit again
+ * generating a spurios interrupt. We could fix this by creating another
+ * QH and leaving the IOC bit always set, but then we would have to play
+ * games with the FSBR code to make sure we get the correct order in all
+ * the cases. I don't think it's worth the effort
+ */
+static inline void uhci_set_next_interrupt(struct uhci *uhci)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&uhci->frame_list_lock, flags);
+	uhci->skel_term_td->status |= TD_CTRL_IOC;
+	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
+}
+
+static inline void uhci_clear_next_interrupt(struct uhci *uhci)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&uhci->frame_list_lock, flags);
+	uhci->skel_term_td->status &= ~TD_CTRL_IOC;
+	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
+}
+
+static inline void uhci_add_complete(struct urb *urb)
+{
+	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	unsigned long flags;
+
+	spin_lock_irqsave(&uhci->complete_list_lock, flags);
+	list_add(&urbp->complete_list, &uhci->complete_list);
+	spin_unlock_irqrestore(&uhci->complete_list_lock, flags);
+}
+
+static struct uhci_td *uhci_alloc_td(struct uhci *uhci, struct usb_device *dev)
+{
+	dma_addr_t dma_handle;
+	struct uhci_td *td;
+
+	td = pci_pool_alloc(uhci->td_pool, GFP_DMA | GFP_ATOMIC, &dma_handle);
+	if (!td)
+		return NULL;
+
+	td->dma_handle = dma_handle;
+
+	td->link = UHCI_PTR_TERM;
+	td->buffer = 0;
+
+	td->frame = -1;
+	td->dev = dev;
+
+	INIT_LIST_HEAD(&td->list);
+	INIT_LIST_HEAD(&td->fl_list);
+
+	usb_inc_dev_use(dev);
+
+	return td;
+}
+
+static void inline uhci_fill_td(struct uhci_td *td, __u32 status,
+		__u32 info, __u32 buffer)
+{
+	td->status = status;
+	td->info = info;
+	td->buffer = buffer;
+}
+
+static void uhci_insert_td(struct uhci *uhci, struct uhci_td *skeltd, struct uhci_td *td)
+{
+	unsigned long flags;
+	struct uhci_td *ltd;
+
+	spin_lock_irqsave(&uhci->frame_list_lock, flags);
+
+	ltd = list_entry(skeltd->fl_list.prev, struct uhci_td, fl_list);
+
+	td->link = ltd->link;
+	mb();
+	ltd->link = td->dma_handle;
+
+	list_add_tail(&td->fl_list, &skeltd->fl_list);
+
+	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
+}
+
+/*
+ * We insert Isochronous transfers directly into the frame list at the
+ * beginning
+ * The layout looks as follows:
+ * frame list pointer -> iso td's (if any) ->
+ * periodic interrupt td (if frame 0) -> irq td's -> control qh -> bulk qh
+ */
+static void uhci_insert_td_frame_list(struct uhci *uhci, struct uhci_td *td, unsigned framenum)
+{
+	unsigned long flags;
+
+	framenum %= UHCI_NUMFRAMES;
+
+	spin_lock_irqsave(&uhci->frame_list_lock, flags);
+
+	td->frame = framenum;
+
+	/* Is there a TD already mapped there? */
+	if (uhci->fl->frame_cpu[framenum]) {
+		struct uhci_td *ftd, *ltd;
+
+		ftd = uhci->fl->frame_cpu[framenum];
+		ltd = list_entry(ftd->fl_list.prev, struct uhci_td, fl_list);
+
+		list_add_tail(&td->fl_list, &ftd->fl_list);
+
+		td->link = ltd->link;
+		mb();
+		ltd->link = td->dma_handle;
+	} else {
+		td->link = uhci->fl->frame[framenum];
+		mb();
+		uhci->fl->frame[framenum] = td->dma_handle;
+		uhci->fl->frame_cpu[framenum] = td;
+	}
+
+	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
+}
+
+static void uhci_remove_td(struct uhci *uhci, struct uhci_td *td)
+{
+	unsigned long flags;
+
+	/* If it's not inserted, don't remove it */
+	spin_lock_irqsave(&uhci->frame_list_lock, flags);
+	if (td->frame == -1 && list_empty(&td->fl_list))
+		goto out;
+
+	if (td->frame != -1 && uhci->fl->frame_cpu[td->frame] == td) {
+		if (list_empty(&td->fl_list)) {
+			uhci->fl->frame[td->frame] = td->link;
+			uhci->fl->frame_cpu[td->frame] = NULL;
+		} else {
+			struct uhci_td *ntd;
+
+			ntd = list_entry(td->fl_list.next, struct uhci_td, fl_list);
+			uhci->fl->frame[td->frame] = ntd->dma_handle;
+			uhci->fl->frame_cpu[td->frame] = ntd;
+		}
+	} else {
+		struct uhci_td *ptd;
+
+		ptd = list_entry(td->fl_list.prev, struct uhci_td, fl_list);
+		ptd->link = td->link;
+	}
+
+	mb();
+	td->link = UHCI_PTR_TERM;
+
+	list_del_init(&td->fl_list);
+	td->frame = -1;
+
+out:
+	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
+}
+
+/*
+ * Inserts a td into qh list at the top.
+ */
+static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, int breadth)
+{
+	struct list_head *tmp, *head;
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	struct uhci_td *td, *ptd;
+
+	if (list_empty(&urbp->td_list))
+		return;
+
+	head = &urbp->td_list;
+	tmp = head->next;
+
+	/* Ordering isn't important here yet since the QH hasn't been */
+	/*  inserted into the schedule yet */
+	td = list_entry(tmp, struct uhci_td, list);
+
+	/* Add the first TD to the QH element pointer */
+	qh->element = td->dma_handle | (breadth ? 0 : UHCI_PTR_DEPTH);
+
+	ptd = td;
+
+	/* Then link the rest of the TD's */
+	tmp = tmp->next;
+	while (tmp != head) {
+		td = list_entry(tmp, struct uhci_td, list);
+
+		tmp = tmp->next;
+
+		ptd->link = td->dma_handle | (breadth ? 0 : UHCI_PTR_DEPTH);
+
+		ptd = td;
+	}
+
+	ptd->link = UHCI_PTR_TERM;
+}
+
+static void uhci_free_td(struct uhci *uhci, struct uhci_td *td)
+{
+	if (!list_empty(&td->list) || !list_empty(&td->fl_list))
+		dbg("td is still in URB list!");
+
+	if (td->dev)
+		usb_dec_dev_use(td->dev);
+
+	pci_pool_free(uhci->td_pool, td, td->dma_handle);
+}
+
+static struct uhci_qh *uhci_alloc_qh(struct uhci *uhci, struct usb_device *dev)
+{
+	dma_addr_t dma_handle;
+	struct uhci_qh *qh;
+
+	qh = pci_pool_alloc(uhci->qh_pool, GFP_DMA | GFP_ATOMIC, &dma_handle);
+	if (!qh)
+		return NULL;
+
+	qh->dma_handle = dma_handle;
+
+	qh->element = UHCI_PTR_TERM;
+	qh->link = UHCI_PTR_TERM;
+
+	qh->dev = dev;
+	qh->urbp = NULL;
+
+	INIT_LIST_HEAD(&qh->list);
+	INIT_LIST_HEAD(&qh->remove_list);
+
+	usb_inc_dev_use(dev);
+
+	return qh;
+}
+
+static void uhci_free_qh(struct uhci *uhci, struct uhci_qh *qh)
+{
+	if (!list_empty(&qh->list))
+		dbg("qh list not empty!");
+	if (!list_empty(&qh->remove_list))
+		dbg("qh still in remove_list!");
+
+	if (qh->dev)
+		usb_dec_dev_use(qh->dev);
+
+	pci_pool_free(uhci->qh_pool, qh, qh->dma_handle);
+}
+
+/*
+ * MUST be called with uhci->frame_list_lock acquired
+ */
+static void _uhci_insert_qh(struct uhci *uhci, struct uhci_qh *skelqh, struct urb *urb)
+{
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	struct list_head *head, *tmp;
+	struct uhci_qh *lqh;
+
+	/* Grab the last QH */
+	lqh = list_entry(skelqh->list.prev, struct uhci_qh, list);
+
+	if (lqh->urbp) {
+		head = &lqh->urbp->queue_list;
+		tmp = head->next;
+		while (head != tmp) {
+			struct urb_priv *turbp =
+				list_entry(tmp, struct urb_priv, queue_list);
+
+			tmp = tmp->next;
+
+			turbp->qh->link = urbp->qh->dma_handle | UHCI_PTR_QH;
+		}
+	}
+
+	head = &urbp->queue_list;
+	tmp = head->next;
+	while (head != tmp) {
+		struct urb_priv *turbp =
+			list_entry(tmp, struct urb_priv, queue_list);
+
+		tmp = tmp->next;
+
+		turbp->qh->link = lqh->link;
+	}
+
+	urbp->qh->link = lqh->link;
+	mb();				/* Ordering is important */
+	lqh->link = urbp->qh->dma_handle | UHCI_PTR_QH;
+
+	list_add_tail(&urbp->qh->list, &skelqh->list);
+}
+
+static void uhci_insert_qh(struct uhci *uhci, struct uhci_qh *skelqh, struct urb *urb)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&uhci->frame_list_lock, flags);
+	_uhci_insert_qh(uhci, skelqh, urb);
+	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
+}
+
+static void uhci_remove_qh(struct uhci *uhci, struct uhci_qh *qh)
+{
+	unsigned long flags;
+	struct uhci_qh *pqh;
+
+	if (!qh)
+		return;
+
+	qh->urbp = NULL;
+
+	/* Only go through the hoops if it's actually linked in */
+	spin_lock_irqsave(&uhci->frame_list_lock, flags);
+	if (!list_empty(&qh->list)) {
+		pqh = list_entry(qh->list.prev, struct uhci_qh, list);
+
+		if (pqh->urbp) {
+			struct list_head *head, *tmp;
+
+			head = &pqh->urbp->queue_list;
+			tmp = head->next;
+			while (head != tmp) {
+				struct urb_priv *turbp =
+					list_entry(tmp, struct urb_priv, queue_list);
+
+				tmp = tmp->next;
+
+				turbp->qh->link = qh->link;
+			}
+		}
+
+		pqh->link = qh->link;
+		mb();
+		qh->element = qh->link = UHCI_PTR_TERM;
+
+		list_del_init(&qh->list);
+	}
+	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
+
+	spin_lock_irqsave(&uhci->qh_remove_list_lock, flags);
+
+	/* Check to see if the remove list is empty. Set the IOC bit */
+	/* to force an interrupt so we can remove the QH */
+	if (list_empty(&uhci->qh_remove_list))
+		uhci_set_next_interrupt(uhci);
+
+	list_add(&qh->remove_list, &uhci->qh_remove_list);
+
+	spin_unlock_irqrestore(&uhci->qh_remove_list_lock, flags);
+}
+
+static int uhci_fixup_toggle(struct urb *urb, unsigned int toggle)
+{
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	struct list_head *head, *tmp;
+
+	head = &urbp->td_list;
+	tmp = head->next;
+	while (head != tmp) {
+		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
+
+		tmp = tmp->next;
+
+		if (toggle)
+			td->info |= TD_TOKEN_TOGGLE;
+		else
+			td->info &= ~TD_TOKEN_TOGGLE;
+
+		toggle ^= 1;
+	}
+
+	return toggle;
+}
+
+/* This function will append one URB's QH to another URB's QH. This is for */
+/*  USB_QUEUE_BULK support for bulk transfers and soon implicitily for */
+/*  control transfers */
+static void uhci_append_queued_urb(struct uhci *uhci, struct urb *eurb, struct urb *urb)
+{
+	struct urb_priv *eurbp, *urbp, *furbp, *lurbp;
+	struct list_head *tmp;
+	struct uhci_td *lltd;
+	unsigned long flags;
+
+	eurbp = eurb->hcpriv;
+	urbp = urb->hcpriv;
+
+	spin_lock_irqsave(&uhci->frame_list_lock, flags);
+
+	/* Find the first URB in the queue */
+	if (eurbp->queued) {
+		struct list_head *head = &eurbp->queue_list;
+
+		tmp = head->next;
+		while (tmp != head) {
+			struct urb_priv *turbp =
+				list_entry(tmp, struct urb_priv, queue_list);
+
+			if (!turbp->queued)
+				break;
+
+			tmp = tmp->next;
+		}
+	} else
+		tmp = &eurbp->queue_list;
+
+	furbp = list_entry(tmp, struct urb_priv, queue_list);
+	lurbp = list_entry(furbp->queue_list.prev, struct urb_priv, queue_list);
+
+	lltd = list_entry(lurbp->td_list.prev, struct uhci_td, list);
+
+	usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe),
+		uhci_fixup_toggle(urb, uhci_toggle(lltd->info) ^ 1));
+
+	/* All qh's in the queue need to link to the next queue */
+	urbp->qh->link = eurbp->qh->link;
+
+	mb();			/* Make sure we flush everything */
+	/* Only support bulk right now, so no depth */
+	lltd->link = urbp->qh->dma_handle | UHCI_PTR_QH;
+
+	list_add_tail(&urbp->queue_list, &furbp->queue_list);
+
+	urbp->queued = 1;
+
+	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
+}
+
+static void uhci_delete_queued_urb(struct uhci *uhci, struct urb *urb)
+{
+	struct urb_priv *urbp, *nurbp;
+	struct list_head *head, *tmp;
+	struct urb_priv *purbp;
+	struct uhci_td *pltd;
+	unsigned int toggle;
+	unsigned long flags;
+
+	urbp = urb->hcpriv;
+
+	spin_lock_irqsave(&uhci->frame_list_lock, flags);
+
+	if (list_empty(&urbp->queue_list))
+		goto out;
+
+	nurbp = list_entry(urbp->queue_list.next, struct urb_priv, queue_list);
+
+	/* Fix up the toggle for the next URB's */
+	if (!urbp->queued)
+		/* We set the toggle when we unlink */
+		toggle = usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
+	else {
+		/* If we're in the middle of the queue, grab the toggle */
+		/*  from the TD previous to us */
+		purbp = list_entry(urbp->queue_list.prev, struct urb_priv,
+				queue_list);
+
+		pltd = list_entry(purbp->td_list.prev, struct uhci_td, list);
+
+		toggle = uhci_toggle(pltd->info) ^ 1;
+	}
+
+	head = &urbp->queue_list;
+	tmp = head->next;
+	while (head != tmp) {
+		struct urb_priv *turbp;
+
+		turbp = list_entry(tmp, struct urb_priv, queue_list);
+
+		tmp = tmp->next;
+
+		if (!turbp->queued)
+			break;
+
+		toggle = uhci_fixup_toggle(turbp->urb, toggle);
+	}
+
+	usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+		usb_pipeout(urb->pipe), toggle);
+
+	if (!urbp->queued) {
+		nurbp->queued = 0;
+
+		_uhci_insert_qh(uhci, uhci->skel_bulk_qh, nurbp->urb);
+	} else {
+		/* We're somewhere in the middle (or end). A bit trickier */
+		/*  than the head scenario */
+		purbp = list_entry(urbp->queue_list.prev, struct urb_priv,
+				queue_list);
+
+		pltd = list_entry(purbp->td_list.prev, struct uhci_td, list);
+		if (nurbp->queued)
+			pltd->link = nurbp->qh->dma_handle | UHCI_PTR_QH;
+		else
+			/* The next URB happens to be the beginning, so */
+			/*  we're the last, end the chain */
+			pltd->link = UHCI_PTR_TERM;
+	}
+
+	list_del_init(&urbp->queue_list);
+
+out:
+	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
+}
+
+static struct urb_priv *uhci_alloc_urb_priv(struct uhci *uhci, struct urb *urb)
+{
+	struct urb_priv *urbp;
+
+	urbp = kmem_cache_alloc(uhci_up_cachep, SLAB_ATOMIC);
+	if (!urbp) {
+		err("uhci_alloc_urb_priv: couldn't allocate memory for urb_priv\n");
+		return NULL;
+	}
+
+	memset((void *)urbp, 0, sizeof(*urbp));
+
+	urbp->inserttime = jiffies;
+	urbp->fsbrtime = jiffies;
+	urbp->urb = urb;
+	urbp->dev = urb->dev;
+	
+	INIT_LIST_HEAD(&urbp->td_list);
+	INIT_LIST_HEAD(&urbp->queue_list);
+	INIT_LIST_HEAD(&urbp->complete_list);
+
+	urb->hcpriv = urbp;
+
+	if (urb->dev != uhci->rh.dev) {
+		if (urb->transfer_buffer_length) {
+			urbp->transfer_buffer_dma_handle = pci_map_single(uhci->dev,
+				urb->transfer_buffer, urb->transfer_buffer_length,
+				usb_pipein(urb->pipe) ? PCI_DMA_FROMDEVICE :
+				PCI_DMA_TODEVICE);
+			if (!urbp->transfer_buffer_dma_handle)
+				return NULL;
+		}
+
+		if (usb_pipetype(urb->pipe) == PIPE_CONTROL && urb->setup_packet) {
+			urbp->setup_packet_dma_handle = pci_map_single(uhci->dev,
+				urb->setup_packet, sizeof(struct usb_ctrlrequest),
+				PCI_DMA_TODEVICE);
+			if (!urbp->setup_packet_dma_handle)
+				return NULL;
+		}
+	}
+
+	return urbp;
+}
+
+/*
+ * MUST be called with urb->lock acquired
+ */
+static void uhci_add_td_to_urb(struct urb *urb, struct uhci_td *td)
+{
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+
+	td->urb = urb;
+
+	list_add_tail(&td->list, &urbp->td_list);
+}
+
+/*
+ * MUST be called with urb->lock acquired
+ */
+static void uhci_remove_td_from_urb(struct uhci_td *td)
+{
+	if (list_empty(&td->list))
+		return;
+
+	list_del_init(&td->list);
+
+	td->urb = NULL;
+}
+
+/*
+ * MUST be called with urb->lock acquired
+ */
+static void uhci_destroy_urb_priv(struct urb *urb)
+{
+	struct list_head *head, *tmp;
+	struct urb_priv *urbp;
+	struct uhci *uhci;
+
+	urbp = (struct urb_priv *)urb->hcpriv;
+	if (!urbp)
+		return;
+
+	if (!urbp->dev || !urbp->dev->bus || !urbp->dev->bus->hcpriv) {
+		warn("uhci_destroy_urb_priv: urb %p belongs to disconnected device or bus?", urb);
+		return;
+	}
+
+	if (!list_empty(&urb->urb_list))
+		warn("uhci_destroy_urb_priv: urb %p still on uhci->urb_list or uhci->remove_list", urb);
+
+	if (!list_empty(&urbp->complete_list))
+		warn("uhci_destroy_urb_priv: urb %p still on uhci->complete_list", urb);
+
+	uhci = urbp->dev->bus->hcpriv;
+
+	head = &urbp->td_list;
+	tmp = head->next;
+	while (tmp != head) {
+		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
+
+		tmp = tmp->next;
+
+		uhci_remove_td_from_urb(td);
+		uhci_remove_td(uhci, td);
+		uhci_free_td(uhci, td);
+	}
+
+	if (urbp->setup_packet_dma_handle) {
+		pci_unmap_single(uhci->dev, urbp->setup_packet_dma_handle,
+			sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE);
+		urbp->setup_packet_dma_handle = 0;
+	}
+
+	if (urbp->transfer_buffer_dma_handle) {
+		pci_unmap_single(uhci->dev, urbp->transfer_buffer_dma_handle,
+			urb->transfer_buffer_length, usb_pipein(urb->pipe) ?
+			PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
+		urbp->transfer_buffer_dma_handle = 0;
+	}
+
+	urb->hcpriv = NULL;
+	kmem_cache_free(uhci_up_cachep, urbp);
+}
+
+static void uhci_inc_fsbr(struct uhci *uhci, struct urb *urb)
+{
+	unsigned long flags;
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+
+	spin_lock_irqsave(&uhci->frame_list_lock, flags);
+
+	if ((!(urb->transfer_flags & USB_NO_FSBR)) && !urbp->fsbr) {
+		urbp->fsbr = 1;
+		if (!uhci->fsbr++ && !uhci->fsbrtimeout)
+			uhci->skel_term_qh->link = uhci->skel_hs_control_qh->dma_handle | UHCI_PTR_QH;
+	}
+
+	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
+}
+
+static void uhci_dec_fsbr(struct uhci *uhci, struct urb *urb)
+{
+	unsigned long flags;
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+
+	spin_lock_irqsave(&uhci->frame_list_lock, flags);
+
+	if ((!(urb->transfer_flags & USB_NO_FSBR)) && urbp->fsbr) {
+		urbp->fsbr = 0;
+		if (!--uhci->fsbr)
+			uhci->fsbrtimeout = jiffies + FSBR_DELAY;
+	}
+
+	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
+}
+
+/*
+ * Map status to standard result codes
+ *
+ * <status> is (td->status & 0xFE0000) [a.k.a. uhci_status_bits(td->status)]
+ * <dir_out> is True for output TDs and False for input TDs.
+ */
+static int uhci_map_status(int status, int dir_out)
+{
+	if (!status)
+		return 0;
+	if (status & TD_CTRL_BITSTUFF)			/* Bitstuff error */
+		return -EPROTO;
+	if (status & TD_CTRL_CRCTIMEO) {		/* CRC/Timeout */
+		if (dir_out)
+			return -ETIMEDOUT;
+		else
+			return -EILSEQ;
+	}
+	if (status & TD_CTRL_NAK)			/* NAK */
+		return -ETIMEDOUT;
+	if (status & TD_CTRL_BABBLE)			/* Babble */
+		return -EOVERFLOW;
+	if (status & TD_CTRL_DBUFERR)			/* Buffer error */
+		return -ENOSR;
+	if (status & TD_CTRL_STALLED)			/* Stalled */
+		return -EPIPE;
+	if (status & TD_CTRL_ACTIVE)			/* Active */
+		return 0;
+
+	return -EINVAL;
+}
+
+/*
+ * Control transfers
+ */
+static int uhci_submit_control(struct urb *urb)
+{
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+	struct uhci_td *td;
+	struct uhci_qh *qh;
+	unsigned long destination, status;
+	int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+	int len = urb->transfer_buffer_length;
+	dma_addr_t data = urbp->transfer_buffer_dma_handle;
+
+	/* The "pipe" thing contains the destination in bits 8--18 */
+	destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
+
+	/* 3 errors */
+	status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | (3 << 27);
+
+	/*
+	 * Build the TD for the control request
+	 */
+	td = uhci_alloc_td(uhci, urb->dev);
+	if (!td)
+		return -ENOMEM;
+
+	uhci_add_td_to_urb(urb, td);
+	uhci_fill_td(td, status, destination | (7 << 21),
+		urbp->setup_packet_dma_handle);
+
+	/*
+	 * If direction is "send", change the frame from SETUP (0x2D)
+	 * to OUT (0xE1). Else change it from SETUP to IN (0x69).
+	 */
+	destination ^= (USB_PID_SETUP ^ usb_packetid(urb->pipe));
+
+	if (!(urb->transfer_flags & USB_DISABLE_SPD))
+		status |= TD_CTRL_SPD;
+
+	/*
+	 * Build the DATA TD's
+	 */
+	while (len > 0) {
+		int pktsze = len;
+
+		if (pktsze > maxsze)
+			pktsze = maxsze;
+
+		td = uhci_alloc_td(uhci, urb->dev);
+		if (!td)
+			return -ENOMEM;
+
+		/* Alternate Data0/1 (start with Data1) */
+		destination ^= TD_TOKEN_TOGGLE;
+	
+		uhci_add_td_to_urb(urb, td);
+		uhci_fill_td(td, status, destination | ((pktsze - 1) << 21),
+			data);
+
+		data += pktsze;
+		len -= pktsze;
+	}
+
+	/*
+	 * Build the final TD for control status 
+	 */
+	td = uhci_alloc_td(uhci, urb->dev);
+	if (!td)
+		return -ENOMEM;
+
+	/*
+	 * It's IN if the pipe is an output pipe or we're not expecting
+	 * data back.
+	 */
+	destination &= ~TD_TOKEN_PID_MASK;
+	if (usb_pipeout(urb->pipe) || !urb->transfer_buffer_length)
+		destination |= USB_PID_IN;
+	else
+		destination |= USB_PID_OUT;
+
+	destination |= TD_TOKEN_TOGGLE;		/* End in Data1 */
+
+	status &= ~TD_CTRL_SPD;
+
+	uhci_add_td_to_urb(urb, td);
+	uhci_fill_td(td, status | TD_CTRL_IOC,
+		destination | (UHCI_NULL_DATA_SIZE << 21), 0);
+
+	qh = uhci_alloc_qh(uhci, urb->dev);
+	if (!qh)
+		return -ENOMEM;
+
+	urbp->qh = qh;
+	qh->urbp = urbp;
+
+	/* Low speed or small transfers gets a different queue and treatment */
+	if (urb->pipe & TD_CTRL_LS) {
+		uhci_insert_tds_in_qh(qh, urb, 0);
+		uhci_insert_qh(uhci, uhci->skel_ls_control_qh, urb);
+	} else {
+		uhci_insert_tds_in_qh(qh, urb, 1);
+		uhci_insert_qh(uhci, uhci->skel_hs_control_qh, urb);
+		uhci_inc_fsbr(uhci, urb);
+	}
+
+	return -EINPROGRESS;
+}
+
+static int usb_control_retrigger_status(struct urb *urb);
+
+static int uhci_result_control(struct urb *urb)
+{
+	struct list_head *tmp, *head;
+	struct urb_priv *urbp = urb->hcpriv;
+	struct uhci_td *td;
+	unsigned int status;
+	int ret = 0;
+
+	if (list_empty(&urbp->td_list))
+		return -EINVAL;
+
+	head = &urbp->td_list;
+
+	if (urbp->short_control_packet) {
+		tmp = head->prev;
+		goto status_phase;
+	}
+
+	tmp = head->next;
+	td = list_entry(tmp, struct uhci_td, list);
+
+	/* The first TD is the SETUP phase, check the status, but skip */
+	/*  the count */
+	status = uhci_status_bits(td->status);
+	if (status & TD_CTRL_ACTIVE)
+		return -EINPROGRESS;
+
+	if (status)
+		goto td_error;
+
+	urb->actual_length = 0;
+
+	/* The rest of the TD's (but the last) are data */
+	tmp = tmp->next;
+	while (tmp != head && tmp->next != head) {
+		td = list_entry(tmp, struct uhci_td, list);
+
+		tmp = tmp->next;
+
+		status = uhci_status_bits(td->status);
+		if (status & TD_CTRL_ACTIVE)
+			return -EINPROGRESS;
+
+		urb->actual_length += uhci_actual_length(td->status);
+
+		if (status)
+			goto td_error;
+
+		/* Check to see if we received a short packet */
+		if (uhci_actual_length(td->status) < uhci_expected_length(td->info)) {
+			if (urb->transfer_flags & USB_DISABLE_SPD) {
+				ret = -EREMOTEIO;
+				goto err;
+			}
+
+			if (uhci_packetid(td->info) == USB_PID_IN)
+				return usb_control_retrigger_status(urb);
+			else
+				return 0;
+		}
+	}
+
+status_phase:
+	td = list_entry(tmp, struct uhci_td, list);
+
+	/* Control status phase */
+	status = uhci_status_bits(td->status);
+
+#ifdef I_HAVE_BUGGY_APC_BACKUPS
+	/* APC BackUPS Pro kludge */
+	/* It tries to send all of the descriptor instead of the amount */
+	/*  we requested */
+	if (td->status & TD_CTRL_IOC &&	/* IOC is masked out by uhci_status_bits */
+	    status & TD_CTRL_ACTIVE &&
+	    status & TD_CTRL_NAK)
+		return 0;
+#endif
+
+	if (status & TD_CTRL_ACTIVE)
+		return -EINPROGRESS;
+
+	if (status)
+		goto td_error;
+
+	return 0;
+
+td_error:
+	ret = uhci_map_status(status, uhci_packetout(td->info));
+	if (ret == -EPIPE)
+		/* endpoint has stalled - mark it halted */
+		usb_endpoint_halt(urb->dev, uhci_endpoint(td->info),
+	    			uhci_packetout(td->info));
+
+err:
+	if ((debug == 1 && ret != -EPIPE) || debug > 1) {
+		/* Some debugging code */
+		dbg("uhci_result_control() failed with status %x", status);
+
+		if (errbuf) {
+			/* Print the chain for debugging purposes */
+			uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0);
+
+			lprintk(errbuf);
+		}
+	}
+
+	return ret;
+}
+
+static int usb_control_retrigger_status(struct urb *urb)
+{
+	struct list_head *tmp, *head;
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	struct uhci *uhci = urb->dev->bus->hcpriv;
+
+	urbp->short_control_packet = 1;
+
+	/* Create a new QH to avoid pointer overwriting problems */
+	uhci_remove_qh(uhci, urbp->qh);
+
+	/* Delete all of the TD's except for the status TD at the end */
+	head = &urbp->td_list;
+	tmp = head->next;
+	while (tmp != head && tmp->next != head) {
+		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
+
+		tmp = tmp->next;
+
+		uhci_remove_td_from_urb(td);
+		uhci_remove_td(uhci, td);
+		uhci_free_td(uhci, td);
+	}
+
+	urbp->qh = uhci_alloc_qh(uhci, urb->dev);
+	if (!urbp->qh) {
+		err("unable to allocate new QH for control retrigger");
+		return -ENOMEM;
+	}
+
+	urbp->qh->urbp = urbp;
+
+	/* One TD, who cares about Breadth first? */
+	uhci_insert_tds_in_qh(urbp->qh, urb, 0);
+
+	/* Low speed or small transfers gets a different queue and treatment */
+	if (urb->pipe & TD_CTRL_LS)
+		uhci_insert_qh(uhci, uhci->skel_ls_control_qh, urb);
+	else
+		uhci_insert_qh(uhci, uhci->skel_hs_control_qh, urb);
+
+	return -EINPROGRESS;
+}
+
+/*
+ * Interrupt transfers
+ */
+static int uhci_submit_interrupt(struct urb *urb)
+{
+	struct uhci_td *td;
+	unsigned long destination, status;
+	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+
+	if (urb->transfer_buffer_length > usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)))
+		return -EINVAL;
+
+	/* The "pipe" thing contains the destination in bits 8--18 */
+	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
+
+	status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC;
+
+	td = uhci_alloc_td(uhci, urb->dev);
+	if (!td)
+		return -ENOMEM;
+
+	destination |= (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT);
+	destination |= ((urb->transfer_buffer_length - 1) << 21);
+
+	usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
+
+	uhci_add_td_to_urb(urb, td);
+	uhci_fill_td(td, status, destination, urbp->transfer_buffer_dma_handle);
+
+	uhci_insert_td(uhci, uhci->skeltd[__interval_to_skel(urb->interval)], td);
+
+	return -EINPROGRESS;
+}
+
+static int uhci_result_interrupt(struct urb *urb)
+{
+	struct list_head *tmp, *head;
+	struct urb_priv *urbp = urb->hcpriv;
+	struct uhci_td *td;
+	unsigned int status;
+	int ret = 0;
+
+	urb->actual_length = 0;
+
+	head = &urbp->td_list;
+	tmp = head->next;
+	while (tmp != head) {
+		td = list_entry(tmp, struct uhci_td, list);
+
+		tmp = tmp->next;
+
+		status = uhci_status_bits(td->status);
+		if (status & TD_CTRL_ACTIVE)
+			return -EINPROGRESS;
+
+		urb->actual_length += uhci_actual_length(td->status);
+
+		if (status)
+			goto td_error;
+
+		if (uhci_actual_length(td->status) < uhci_expected_length(td->info)) {
+			if (urb->transfer_flags & USB_DISABLE_SPD) {
+				ret = -EREMOTEIO;
+				goto err;
+			} else
+				return 0;
+		}
+	}
+
+	return 0;
+
+td_error:
+	ret = uhci_map_status(status, uhci_packetout(td->info));
+	if (ret == -EPIPE)
+		/* endpoint has stalled - mark it halted */
+		usb_endpoint_halt(urb->dev, uhci_endpoint(td->info),
+	    			uhci_packetout(td->info));
+
+err:
+	if ((debug == 1 && ret != -EPIPE) || debug > 1) {
+		/* Some debugging code */
+		dbg("uhci_result_interrupt/bulk() failed with status %x",
+			status);
+
+		if (errbuf) {
+			/* Print the chain for debugging purposes */
+			if (urbp->qh)
+				uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0);
+			else
+				uhci_show_td(td, errbuf, ERRBUF_LEN, 0);
+
+			lprintk(errbuf);
+		}
+	}
+
+	return ret;
+}
+
+static void uhci_reset_interrupt(struct urb *urb)
+{
+	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	struct uhci_td *td;
+	unsigned long flags;
+
+	spin_lock_irqsave(&urb->lock, flags);
+
+	/* Root hub is special */
+	if (urb->dev == uhci->rh.dev)
+		goto out;
+
+	td = list_entry(urbp->td_list.next, struct uhci_td, list);
+
+	td->status = (td->status & 0x2F000000) | TD_CTRL_ACTIVE | TD_CTRL_IOC;
+	td->info &= ~TD_TOKEN_TOGGLE;
+	td->info |= (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT);
+	usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
+
+out:
+	urb->status = -EINPROGRESS;
+
+	spin_unlock_irqrestore(&urb->lock, flags);
+}
+
+/*
+ * Bulk transfers
+ */
+static int uhci_submit_bulk(struct urb *urb, struct urb *eurb)
+{
+	struct uhci_td *td;
+	struct uhci_qh *qh;
+	unsigned long destination, status;
+	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+	int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+	int len = urb->transfer_buffer_length;
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	dma_addr_t data = urbp->transfer_buffer_dma_handle;
+
+	if (len < 0)
+		return -EINVAL;
+
+	/* Can't have low speed bulk transfers */
+	if (urb->pipe & TD_CTRL_LS)
+		return -EINVAL;
+
+	/* The "pipe" thing contains the destination in bits 8--18 */
+	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
+
+	/* 3 errors */
+	status = TD_CTRL_ACTIVE | (3 << TD_CTRL_C_ERR_SHIFT);
+
+	if (!(urb->transfer_flags & USB_DISABLE_SPD))
+		status |= TD_CTRL_SPD;
+
+	/*
+	 * Build the DATA TD's
+	 */
+	do {	/* Allow zero length packets */
+		int pktsze = len;
+
+		if (pktsze > maxsze)
+			pktsze = maxsze;
+
+		td = uhci_alloc_td(uhci, urb->dev);
+		if (!td)
+			return -ENOMEM;
+
+		uhci_add_td_to_urb(urb, td);
+		uhci_fill_td(td, status, destination |
+			(((pktsze - 1) & UHCI_NULL_DATA_SIZE) << 21) |
+			(usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+			 usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT),
+			data);
+
+		data += pktsze;
+		len -= maxsze;
+
+		usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+			usb_pipeout(urb->pipe));
+	} while (len > 0);
+
+	/*
+	 * USB_ZERO_PACKET means adding a 0-length packet, if
+	 * direction is OUT and the transfer_length was an
+	 * exact multiple of maxsze, hence
+	 * (len = transfer_length - N * maxsze) == 0
+	 * however, if transfer_length == 0, the zero packet
+	 * was already prepared above.
+	 */
+	if (usb_pipeout(urb->pipe) && (urb->transfer_flags & USB_ZERO_PACKET) &&
+	   !len && urb->transfer_buffer_length) {
+		td = uhci_alloc_td(uhci, urb->dev);
+		if (!td)
+			return -ENOMEM;
+
+		uhci_add_td_to_urb(urb, td);
+		uhci_fill_td(td, status, destination |
+			(UHCI_NULL_DATA_SIZE << 21) |
+			(usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+			 usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT),
+			data);
+
+		usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+			usb_pipeout(urb->pipe));
+	}
+
+	/* Set the flag on the last packet */
+	td->status |= TD_CTRL_IOC;
+
+	qh = uhci_alloc_qh(uhci, urb->dev);
+	if (!qh)
+		return -ENOMEM;
+
+	urbp->qh = qh;
+	qh->urbp = urbp;
+
+	/* Always assume breadth first */
+	uhci_insert_tds_in_qh(qh, urb, 1);
+
+	if (urb->transfer_flags & USB_QUEUE_BULK && eurb)
+		uhci_append_queued_urb(uhci, eurb, urb);
+	else
+		uhci_insert_qh(uhci, uhci->skel_bulk_qh, urb);
+
+	uhci_inc_fsbr(uhci, urb);
+
+	return -EINPROGRESS;
+}
+
+/* We can use the result interrupt since they're identical */
+#define uhci_result_bulk uhci_result_interrupt
+
+/*
+ * Isochronous transfers
+ */
+static int isochronous_find_limits(struct urb *urb, unsigned int *start, unsigned int *end)
+{
+	struct urb *last_urb = NULL;
+	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+	struct list_head *tmp, *head;
+	int ret = 0;
+
+	head = &uhci->urb_list;
+	tmp = head->next;
+	while (tmp != head) {
+		struct urb *u = list_entry(tmp, struct urb, urb_list);
+
+		tmp = tmp->next;
+
+		/* look for pending URB's with identical pipe handle */
+		if ((urb->pipe == u->pipe) && (urb->dev == u->dev) &&
+		    (u->status == -EINPROGRESS) && (u != urb)) {
+			if (!last_urb)
+				*start = u->start_frame;
+			last_urb = u;
+		}
+	}
+
+	if (last_urb) {
+		*end = (last_urb->start_frame + last_urb->number_of_packets) & 1023;
+		ret = 0;
+	} else
+		ret = -1;	/* no previous urb found */
+
+	return ret;
+}
+
+static int isochronous_find_start(struct urb *urb)
+{
+	int limits;
+	unsigned int start = 0, end = 0;
+
+	if (urb->number_of_packets > 900)	/* 900? Why? */
+		return -EFBIG;
+
+	limits = isochronous_find_limits(urb, &start, &end);
+
+	if (urb->transfer_flags & USB_ISO_ASAP) {
+		if (limits) {
+			int curframe;
+
+			curframe = uhci_get_current_frame_number(urb->dev) % UHCI_NUMFRAMES;
+			urb->start_frame = (curframe + 10) % UHCI_NUMFRAMES;
+		} else
+			urb->start_frame = end;
+	} else {
+		urb->start_frame %= UHCI_NUMFRAMES;
+		/* FIXME: Sanity check */
+	}
+
+	return 0;
+}
+
+/*
+ * Isochronous transfers
+ */
+static int uhci_submit_isochronous(struct urb *urb)
+{
+	struct uhci_td *td;
+	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+	int i, ret, framenum;
+	int status, destination;
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+
+	status = TD_CTRL_ACTIVE | TD_CTRL_IOS;
+	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
+
+	ret = isochronous_find_start(urb);
+	if (ret)
+		return ret;
+
+	framenum = urb->start_frame;
+	for (i = 0; i < urb->number_of_packets; i++, framenum++) {
+		if (!urb->iso_frame_desc[i].length)
+			continue;
+
+		td = uhci_alloc_td(uhci, urb->dev);
+		if (!td)
+			return -ENOMEM;
+
+		uhci_add_td_to_urb(urb, td);
+		uhci_fill_td(td, status, destination | ((urb->iso_frame_desc[i].length - 1) << 21),
+			urbp->transfer_buffer_dma_handle + urb->iso_frame_desc[i].offset);
+
+		if (i + 1 >= urb->number_of_packets)
+			td->status |= TD_CTRL_IOC;
+
+		uhci_insert_td_frame_list(uhci, td, framenum);
+	}
+
+	return -EINPROGRESS;
+}
+
+static int uhci_result_isochronous(struct urb *urb)
+{
+	struct list_head *tmp, *head;
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	int status;
+	int i, ret = 0;
+
+	urb->actual_length = 0;
+
+	i = 0;
+	head = &urbp->td_list;
+	tmp = head->next;
+	while (tmp != head) {
+		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
+		int actlength;
+
+		tmp = tmp->next;
+
+		if (td->status & TD_CTRL_ACTIVE)
+			return -EINPROGRESS;
+
+		actlength = uhci_actual_length(td->status);
+		urb->iso_frame_desc[i].actual_length = actlength;
+		urb->actual_length += actlength;
+
+		status = uhci_map_status(uhci_status_bits(td->status), usb_pipeout(urb->pipe));
+		urb->iso_frame_desc[i].status = status;
+		if (status) {
+			urb->error_count++;
+			ret = status;
+		}
+
+		i++;
+	}
+
+	return ret;
+}
+
+/*
+ * MUST be called with uhci->urb_list_lock acquired
+ */
+static struct urb *uhci_find_urb_ep(struct uhci *uhci, struct urb *urb)
+{
+	struct list_head *tmp, *head;
+
+	/* We don't match Isoc transfers since they are special */
+	if (usb_pipeisoc(urb->pipe))
+		return NULL;
+
+	head = &uhci->urb_list;
+	tmp = head->next;
+	while (tmp != head) {
+		struct urb *u = list_entry(tmp, struct urb, urb_list);
+
+		tmp = tmp->next;
+
+		if (u->dev == urb->dev && u->pipe == urb->pipe &&
+		    u->status == -EINPROGRESS)
+			return u;
+	}
+
+	return NULL;
+}
+
+static int uhci_submit_urb(struct urb *urb)
+{
+	int ret = -EINVAL;
+	struct uhci *uhci;
+	unsigned long flags;
+	struct urb *eurb;
+	int bustime;
+
+	if (!urb)
+		return -EINVAL;
+
+	if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv) {
+		warn("uhci_submit_urb: urb %p belongs to disconnected device or bus?", urb);
+		return -ENODEV;
+	}
+
+	uhci = (struct uhci *)urb->dev->bus->hcpriv;
+
+	usb_inc_dev_use(urb->dev);
+
+	spin_lock_irqsave(&uhci->urb_list_lock, flags);
+	spin_lock(&urb->lock);
+
+	if (urb->status == -EINPROGRESS || urb->status == -ECONNRESET ||
+	    urb->status == -ECONNABORTED) {
+		dbg("uhci_submit_urb: urb not available to submit (status = %d)", urb->status);
+		/* Since we can have problems on the out path */
+		spin_unlock(&urb->lock);
+		spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
+		usb_dec_dev_use(urb->dev);
+
+		return ret;
+	}
+
+	INIT_LIST_HEAD(&urb->urb_list);
+	if (!uhci_alloc_urb_priv(uhci, urb)) {
+		ret = -ENOMEM;
+
+		goto out;
+	}
+
+	eurb = uhci_find_urb_ep(uhci, urb);
+	if (eurb && !(urb->transfer_flags & USB_QUEUE_BULK)) {
+		ret = -ENXIO;
+
+		goto out;
+	}
+
+	/* Short circuit the virtual root hub */
+	if (urb->dev == uhci->rh.dev) {
+		ret = rh_submit_urb(urb);
+
+		goto out;
+	}
+
+	switch (usb_pipetype(urb->pipe)) {
+	case PIPE_CONTROL:
+		ret = uhci_submit_control(urb);
+		break;
+	case PIPE_INTERRUPT:
+		if (urb->bandwidth == 0) {	/* not yet checked/allocated */
+			bustime = usb_check_bandwidth(urb->dev, urb);
+			if (bustime < 0)
+				ret = bustime;
+			else {
+				ret = uhci_submit_interrupt(urb);
+				if (ret == -EINPROGRESS)
+					usb_claim_bandwidth(urb->dev, urb, bustime, 0);
+			}
+		} else		/* bandwidth is already set */
+			ret = uhci_submit_interrupt(urb);
+		break;
+	case PIPE_BULK:
+		ret = uhci_submit_bulk(urb, eurb);
+		break;
+	case PIPE_ISOCHRONOUS:
+		if (urb->bandwidth == 0) {	/* not yet checked/allocated */
+			if (urb->number_of_packets <= 0) {
+				ret = -EINVAL;
+				break;
+			}
+			bustime = usb_check_bandwidth(urb->dev, urb);
+			if (bustime < 0) {
+				ret = bustime;
+				break;
+			}
+
+			ret = uhci_submit_isochronous(urb);
+			if (ret == -EINPROGRESS)
+				usb_claim_bandwidth(urb->dev, urb, bustime, 1);
+		} else		/* bandwidth is already set */
+			ret = uhci_submit_isochronous(urb);
+		break;
+	}
+
+out:
+	urb->status = ret;
+
+	if (ret == -EINPROGRESS) {
+		/* We use _tail to make find_urb_ep more efficient */
+		list_add_tail(&urb->urb_list, &uhci->urb_list);
+
+		spin_unlock(&urb->lock);
+		spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
+
+		return 0;
+	}
+
+	uhci_unlink_generic(uhci, urb);
+
+	spin_unlock(&urb->lock);
+	spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
+
+	/* Only call completion if it was successful */
+	if (!ret)
+		uhci_call_completion(urb);
+
+	return ret;
+}
+
+/*
+ * Return the result of a transfer
+ *
+ * MUST be called with urb_list_lock acquired
+ */
+static void uhci_transfer_result(struct uhci *uhci, struct urb *urb)
+{
+	int ret = -EINVAL;
+	unsigned long flags;
+	struct urb_priv *urbp;
+
+	/* The root hub is special */
+	if (urb->dev == uhci->rh.dev)
+		return;
+
+	spin_lock_irqsave(&urb->lock, flags);
+
+	urbp = (struct urb_priv *)urb->hcpriv;
+
+	if (urb->status != -EINPROGRESS) {
+		info("uhci_transfer_result: called for URB %p not in flight?", urb);
+		goto out;
+	}
+
+	switch (usb_pipetype(urb->pipe)) {
+	case PIPE_CONTROL:
+		ret = uhci_result_control(urb);
+		break;
+	case PIPE_INTERRUPT:
+		ret = uhci_result_interrupt(urb);
+		break;
+	case PIPE_BULK:
+		ret = uhci_result_bulk(urb);
+		break;
+	case PIPE_ISOCHRONOUS:
+		ret = uhci_result_isochronous(urb);
+		break;
+	}
+
+	urbp->status = ret;
+
+	if (ret == -EINPROGRESS)
+		goto out;
+
+	switch (usb_pipetype(urb->pipe)) {
+	case PIPE_CONTROL:
+	case PIPE_BULK:
+	case PIPE_ISOCHRONOUS:
+		/* Release bandwidth for Interrupt or Isoc. transfers */
+		/* Spinlock needed ? */
+		if (urb->bandwidth)
+			usb_release_bandwidth(urb->dev, urb, 1);
+		uhci_unlink_generic(uhci, urb);
+		break;
+	case PIPE_INTERRUPT:
+		/* Interrupts are an exception */
+		if (urb->interval)
+			goto out_complete;
+
+		/* Release bandwidth for Interrupt or Isoc. transfers */
+		/* Spinlock needed ? */
+		if (urb->bandwidth)
+			usb_release_bandwidth(urb->dev, urb, 0);
+		uhci_unlink_generic(uhci, urb);
+		break;
+	default:
+		info("uhci_transfer_result: unknown pipe type %d for urb %p\n",
+			usb_pipetype(urb->pipe), urb);
+	}
+
+	/* Remove it from uhci->urb_list */
+	list_del_init(&urb->urb_list);
+
+out_complete:
+	uhci_add_complete(urb);
+
+out:
+	spin_unlock_irqrestore(&urb->lock, flags);
+}
+
+/*
+ * MUST be called with urb->lock acquired
+ */
+static void uhci_unlink_generic(struct uhci *uhci, struct urb *urb)
+{
+	struct list_head *head, *tmp;
+	struct urb_priv *urbp = urb->hcpriv;
+	int prevactive = 1;
+
+	/* We can get called when urbp allocation fails, so check */
+	if (!urbp)
+		return;
+
+	uhci_dec_fsbr(uhci, urb);	/* Safe since it checks */
+
+	/*
+	 * Now we need to find out what the last successful toggle was
+	 * so we can update the local data toggle for the next transfer
+	 *
+	 * There's 3 way's the last successful completed TD is found:
+	 *
+	 * 1) The TD is NOT active and the actual length < expected length
+	 * 2) The TD is NOT active and it's the last TD in the chain
+	 * 3) The TD is active and the previous TD is NOT active
+	 *
+	 * Control and Isochronous ignore the toggle, so this is safe
+	 * for all types
+	 */
+	head = &urbp->td_list;
+	tmp = head->next;
+	while (tmp != head) {
+		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
+
+		tmp = tmp->next;
+
+		if (!(td->status & TD_CTRL_ACTIVE) &&
+		    (uhci_actual_length(td->status) < uhci_expected_length(td->info) ||
+		    tmp == head))
+			usb_settoggle(urb->dev, uhci_endpoint(td->info),
+				uhci_packetout(td->info),
+				uhci_toggle(td->info) ^ 1);
+		else if ((td->status & TD_CTRL_ACTIVE) && !prevactive)
+			usb_settoggle(urb->dev, uhci_endpoint(td->info),
+				uhci_packetout(td->info),
+				uhci_toggle(td->info));
+
+		prevactive = td->status & TD_CTRL_ACTIVE;
+	}
+
+	uhci_delete_queued_urb(uhci, urb);
+
+	/* The interrupt loop will reclaim the QH's */
+	uhci_remove_qh(uhci, urbp->qh);
+	urbp->qh = NULL;
+}
+
+static int uhci_unlink_urb(struct urb *urb)
+{
+	struct uhci *uhci;
+	unsigned long flags;
+	struct urb_priv *urbp = urb->hcpriv;
+
+	if (!urb)
+		return -EINVAL;
+
+	if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv)
+		return -ENODEV;
+
+	uhci = (struct uhci *)urb->dev->bus->hcpriv;
+
+	spin_lock_irqsave(&uhci->urb_list_lock, flags);
+	spin_lock(&urb->lock);
+
+	/* Release bandwidth for Interrupt or Isoc. transfers */
+	/* Spinlock needed ? */
+	if (urb->bandwidth) {
+		switch (usb_pipetype(urb->pipe)) {
+		case PIPE_INTERRUPT:
+			usb_release_bandwidth(urb->dev, urb, 0);
+			break;
+		case PIPE_ISOCHRONOUS:
+			usb_release_bandwidth(urb->dev, urb, 1);
+			break;
+		default:
+			break;
+		}
+	}
+
+	if (urb->status != -EINPROGRESS) {
+		spin_unlock(&urb->lock);
+		spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
+		return 0;
+	}
+
+	list_del_init(&urb->urb_list);
+
+	uhci_unlink_generic(uhci, urb);
+
+	/* Short circuit the virtual root hub */
+	if (urb->dev == uhci->rh.dev) {
+		rh_unlink_urb(urb);
+
+		spin_unlock(&urb->lock);
+		spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
+
+		uhci_call_completion(urb);
+	} else {
+		if (urb->transfer_flags & USB_ASYNC_UNLINK) {
+			urbp->status = urb->status = -ECONNABORTED;
+
+			spin_lock(&uhci->urb_remove_list_lock);
+
+			/* If we're the first, set the next interrupt bit */
+			if (list_empty(&uhci->urb_remove_list))
+				uhci_set_next_interrupt(uhci);
+			
+			list_add(&urb->urb_list, &uhci->urb_remove_list);
+
+			spin_unlock(&uhci->urb_remove_list_lock);
+
+			spin_unlock(&urb->lock);
+			spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
+
+		} else {
+			urb->status = -ENOENT;
+
+			spin_unlock(&urb->lock);
+			spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
+
+			if (in_interrupt()) {	/* wait at least 1 frame */
+				static int errorcount = 10;
+
+				if (errorcount--)
+					dbg("uhci_unlink_urb called from interrupt for urb %p", urb);
+				udelay(1000);
+			} else
+				schedule_timeout(1+1*HZ/1000); 
+
+			uhci_call_completion(urb);
+		}
+	}
+
+	return 0;
+}
+
+static int uhci_fsbr_timeout(struct uhci *uhci, struct urb *urb)
+{
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	struct list_head *head, *tmp;
+	int count = 0;
+
+	uhci_dec_fsbr(uhci, urb);
+
+	urbp->fsbr_timeout = 1;
+
+	/*
+	 * Ideally we would want to fix qh->element as well, but it's
+	 * read/write by the HC, so that can introduce a race. It's not
+	 * really worth the hassle
+	 */
+
+	head = &urbp->td_list;
+	tmp = head->next;
+	while (tmp != head) {
+		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
+
+		tmp = tmp->next;
+
+		/*
+		 * Make sure we don't do the last one (since it'll have the
+		 * TERM bit set) as well as we skip every so many TD's to
+		 * make sure it doesn't hog the bandwidth
+		 */
+		if (tmp != head && (count % DEPTH_INTERVAL) == (DEPTH_INTERVAL - 1))
+			td->link |= UHCI_PTR_DEPTH;
+
+		count++;
+	}
+
+	return 0;
+}
+
+/*
+ * uhci_get_current_frame_number()
+ *
+ * returns the current frame number for a USB bus/controller.
+ */
+static int uhci_get_current_frame_number(struct usb_device *dev)
+{
+	struct uhci *uhci = (struct uhci *)dev->bus->hcpriv;
+
+	return inw(uhci->io_addr + USBFRNUM);
+}
+
+struct usb_operations uhci_device_operations = {
+	uhci_alloc_dev,
+	uhci_free_dev,
+	uhci_get_current_frame_number,
+	uhci_submit_urb,
+	uhci_unlink_urb
+};
+
+/* Virtual Root Hub */
+
+static __u8 root_hub_dev_des[] =
+{
+ 	0x12,			/*  __u8  bLength; */
+	0x01,			/*  __u8  bDescriptorType; Device */
+	0x00,			/*  __u16 bcdUSB; v1.0 */
+	0x01,
+	0x09,			/*  __u8  bDeviceClass; HUB_CLASSCODE */
+	0x00,			/*  __u8  bDeviceSubClass; */
+	0x00,			/*  __u8  bDeviceProtocol; */
+	0x08,			/*  __u8  bMaxPacketSize0; 8 Bytes */
+	0x00,			/*  __u16 idVendor; */
+	0x00,
+	0x00,			/*  __u16 idProduct; */
+	0x00,
+	0x00,			/*  __u16 bcdDevice; */
+	0x00,
+	0x00,			/*  __u8  iManufacturer; */
+	0x02,			/*  __u8  iProduct; */
+	0x01,			/*  __u8  iSerialNumber; */
+	0x01			/*  __u8  bNumConfigurations; */
+};
+
+
+/* Configuration descriptor */
+static __u8 root_hub_config_des[] =
+{
+	0x09,			/*  __u8  bLength; */
+	0x02,			/*  __u8  bDescriptorType; Configuration */
+	0x19,			/*  __u16 wTotalLength; */
+	0x00,
+	0x01,			/*  __u8  bNumInterfaces; */
+	0x01,			/*  __u8  bConfigurationValue; */
+	0x00,			/*  __u8  iConfiguration; */
+	0x40,			/*  __u8  bmAttributes;
+					Bit 7: Bus-powered, 6: Self-powered,
+					Bit 5 Remote-wakeup, 4..0: resvd */
+	0x00,			/*  __u8  MaxPower; */
+
+	/* interface */
+	0x09,			/*  __u8  if_bLength; */
+	0x04,			/*  __u8  if_bDescriptorType; Interface */
+	0x00,			/*  __u8  if_bInterfaceNumber; */
+	0x00,			/*  __u8  if_bAlternateSetting; */
+	0x01,			/*  __u8  if_bNumEndpoints; */
+	0x09,			/*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
+	0x00,			/*  __u8  if_bInterfaceSubClass; */
+	0x00,			/*  __u8  if_bInterfaceProtocol; */
+	0x00,			/*  __u8  if_iInterface; */
+
+	/* endpoint */
+	0x07,			/*  __u8  ep_bLength; */
+	0x05,			/*  __u8  ep_bDescriptorType; Endpoint */
+	0x81,			/*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
+	0x03,			/*  __u8  ep_bmAttributes; Interrupt */
+	0x08,			/*  __u16 ep_wMaxPacketSize; 8 Bytes */
+	0x00,
+	0xff			/*  __u8  ep_bInterval; 255 ms */
+};
+
+static __u8 root_hub_hub_des[] =
+{
+	0x09,			/*  __u8  bLength; */
+	0x29,			/*  __u8  bDescriptorType; Hub-descriptor */
+	0x02,			/*  __u8  bNbrPorts; */
+	0x00,			/* __u16  wHubCharacteristics; */
+	0x00,
+	0x01,			/*  __u8  bPwrOn2pwrGood; 2ms */
+	0x00,			/*  __u8  bHubContrCurrent; 0 mA */
+	0x00,			/*  __u8  DeviceRemovable; *** 7 Ports max *** */
+	0xff			/*  __u8  PortPwrCtrlMask; *** 7 ports max *** */
+};
+
+/* prepare Interrupt pipe transaction data; HUB INTERRUPT ENDPOINT */
+static int rh_send_irq(struct urb *urb)
+{
+	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	unsigned int io_addr = uhci->io_addr;
+	unsigned long flags;
+	int i, len = 1;
+	__u16 data = 0;
+
+	spin_lock_irqsave(&urb->lock, flags);
+	for (i = 0; i < uhci->rh.numports; i++) {
+		data |= ((inw(io_addr + USBPORTSC1 + i * 2) & 0xa) > 0 ? (1 << (i + 1)) : 0);
+		len = (i + 1) / 8 + 1;
+	}
+
+	*(__u16 *) urb->transfer_buffer = cpu_to_le16(data);
+	urb->actual_length = len;
+	urbp->status = 0;
+
+	spin_unlock_irqrestore(&urb->lock, flags);
+
+	if ((data > 0) && (uhci->rh.send != 0)) {
+		dbg("root-hub INT complete: port1: %x port2: %x data: %x",
+			inw(io_addr + USBPORTSC1), inw(io_addr + USBPORTSC2), data);
+		uhci_call_completion(urb);
+	}
+
+	return 0;
+}
+
+/* Virtual Root Hub INTs are polled by this timer every "interval" ms */
+static int rh_init_int_timer(struct urb *urb);
+
+static void rh_int_timer_do(unsigned long ptr)
+{
+	struct urb *urb = (struct urb *)ptr;
+	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+	struct list_head list, *tmp, *head;
+	unsigned long flags;
+
+	if (uhci->rh.send)
+		rh_send_irq(urb);
+
+	INIT_LIST_HEAD(&list);
+
+	spin_lock_irqsave(&uhci->urb_list_lock, flags);
+	head = &uhci->urb_list;
+	tmp = head->next;
+	while (tmp != head) {
+		struct urb *u = list_entry(tmp, struct urb, urb_list);
+		struct urb_priv *up = (struct urb_priv *)u->hcpriv;
+
+		tmp = tmp->next;
+
+		spin_lock(&u->lock);
+
+		/* Check if the FSBR timed out */
+		if (up->fsbr && !up->fsbr_timeout && time_after_eq(jiffies, up->fsbrtime + IDLE_TIMEOUT))
+			uhci_fsbr_timeout(uhci, u);
+
+		/* Check if the URB timed out */
+		if (u->timeout && time_after_eq(jiffies, up->inserttime + u->timeout)) {
+			list_del(&u->urb_list);
+			list_add_tail(&u->urb_list, &list);
+		}
+
+		spin_unlock(&u->lock);
+	}
+	spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
+
+	head = &list;
+	tmp = head->next;
+	while (tmp != head) {
+		struct urb *u = list_entry(tmp, struct urb, urb_list);
+
+		tmp = tmp->next;
+
+		u->transfer_flags |= USB_ASYNC_UNLINK | USB_TIMEOUT_KILLED;
+		uhci_unlink_urb(u);
+	}
+
+	/* Really disable FSBR */
+	if (!uhci->fsbr && uhci->fsbrtimeout && time_after_eq(jiffies, uhci->fsbrtimeout)) {
+		uhci->fsbrtimeout = 0;
+		uhci->skel_term_qh->link = UHCI_PTR_TERM;
+	}
+
+	/* enter global suspend if nothing connected */
+	if (!uhci->is_suspended && !ports_active(uhci))
+		suspend_hc(uhci);
+
+	rh_init_int_timer(urb);
+}
+
+/* Root Hub INTs are polled by this timer */
+static int rh_init_int_timer(struct urb *urb)
+{
+	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+
+	uhci->rh.interval = urb->interval;
+	init_timer(&uhci->rh.rh_int_timer);
+	uhci->rh.rh_int_timer.function = rh_int_timer_do;
+	uhci->rh.rh_int_timer.data = (unsigned long)urb;
+	uhci->rh.rh_int_timer.expires = jiffies + (HZ * (urb->interval < 30 ? 30 : urb->interval)) / 1000;
+	add_timer(&uhci->rh.rh_int_timer);
+
+	return 0;
+}
+
+#define OK(x)			len = (x); break
+
+#define CLR_RH_PORTSTAT(x) \
+	status = inw(io_addr + USBPORTSC1 + 2 * (wIndex-1)); \
+	status = (status & 0xfff5) & ~(x); \
+	outw(status, io_addr + USBPORTSC1 + 2 * (wIndex-1))
+
+#define SET_RH_PORTSTAT(x) \
+	status = inw(io_addr + USBPORTSC1 + 2 * (wIndex-1)); \
+	status = (status & 0xfff5) | (x); \
+	outw(status, io_addr + USBPORTSC1 + 2 * (wIndex-1))
+
+
+/* Root Hub Control Pipe */
+static int rh_submit_urb(struct urb *urb)
+{
+	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+	unsigned int pipe = urb->pipe;
+	struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *)urb->setup_packet;
+	void *data = urb->transfer_buffer;
+	int leni = urb->transfer_buffer_length;
+	int len = 0;
+	int status = 0;
+	int stat = 0;
+	int i;
+	unsigned int io_addr = uhci->io_addr;
+	__u16 cstatus;
+	__u16 bmRType_bReq;
+	__u16 wValue;
+	__u16 wIndex;
+	__u16 wLength;
+
+	if (usb_pipetype(pipe) == PIPE_INTERRUPT) {
+		uhci->rh.urb = urb;
+		uhci->rh.send = 1;
+		uhci->rh.interval = urb->interval;
+		rh_init_int_timer(urb);
+
+		return -EINPROGRESS;
+	}
+
+	bmRType_bReq = cmd->bRequestType | cmd->bRequest << 8;
+	wValue = le16_to_cpu(cmd->wValue);
+	wIndex = le16_to_cpu(cmd->wIndex);
+	wLength = le16_to_cpu(cmd->wLength);
+
+	for (i = 0; i < 8; i++)
+		uhci->rh.c_p_r[i] = 0;
+
+	switch (bmRType_bReq) {
+		/* Request Destination:
+		   without flags: Device,
+		   RH_INTERFACE: interface,
+		   RH_ENDPOINT: endpoint,
+		   RH_CLASS means HUB here,
+		   RH_OTHER | RH_CLASS  almost ever means HUB_PORT here
+		*/
+
+	case RH_GET_STATUS:
+		*(__u16 *)data = cpu_to_le16(1);
+		OK(2);
+	case RH_GET_STATUS | RH_INTERFACE:
+		*(__u16 *)data = cpu_to_le16(0);
+		OK(2);
+	case RH_GET_STATUS | RH_ENDPOINT:
+		*(__u16 *)data = cpu_to_le16(0);
+		OK(2);
+	case RH_GET_STATUS | RH_CLASS:
+		*(__u32 *)data = cpu_to_le32(0);
+		OK(4);		/* hub power */
+	case RH_GET_STATUS | RH_OTHER | RH_CLASS:
+		status = inw(io_addr + USBPORTSC1 + 2 * (wIndex - 1));
+		cstatus = ((status & USBPORTSC_CSC) >> (1 - 0)) |
+			((status & USBPORTSC_PEC) >> (3 - 1)) |
+			(uhci->rh.c_p_r[wIndex - 1] << (0 + 4));
+			status = (status & USBPORTSC_CCS) |
+			((status & USBPORTSC_PE) >> (2 - 1)) |
+			((status & USBPORTSC_SUSP) >> (12 - 2)) |
+			((status & USBPORTSC_PR) >> (9 - 4)) |
+			(1 << 8) |      /* power on */
+			((status & USBPORTSC_LSDA) << (-8 + 9));
+
+		*(__u16 *)data = cpu_to_le16(status);
+		*(__u16 *)(data + 2) = cpu_to_le16(cstatus);
+		OK(4);
+	case RH_CLEAR_FEATURE | RH_ENDPOINT:
+		switch (wValue) {
+		case RH_ENDPOINT_STALL:
+			OK(0);
+		}
+		break;
+	case RH_CLEAR_FEATURE | RH_CLASS:
+		switch (wValue) {
+		case RH_C_HUB_OVER_CURRENT:
+			OK(0);	/* hub power over current */
+		}
+		break;
+	case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+		switch (wValue) {
+		case RH_PORT_ENABLE:
+			CLR_RH_PORTSTAT(USBPORTSC_PE);
+			OK(0);
+		case RH_PORT_SUSPEND:
+			CLR_RH_PORTSTAT(USBPORTSC_SUSP);
+			OK(0);
+		case RH_PORT_POWER:
+			OK(0);	/* port power */
+		case RH_C_PORT_CONNECTION:
+			SET_RH_PORTSTAT(USBPORTSC_CSC);
+			OK(0);
+		case RH_C_PORT_ENABLE:
+			SET_RH_PORTSTAT(USBPORTSC_PEC);
+			OK(0);
+		case RH_C_PORT_SUSPEND:
+			/*** WR_RH_PORTSTAT(RH_PS_PSSC); */
+			OK(0);
+		case RH_C_PORT_OVER_CURRENT:
+			OK(0);	/* port power over current */
+		case RH_C_PORT_RESET:
+			uhci->rh.c_p_r[wIndex - 1] = 0;
+			OK(0);
+		}
+		break;
+	case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+		switch (wValue) {
+		case RH_PORT_SUSPEND:
+			SET_RH_PORTSTAT(USBPORTSC_SUSP);
+			OK(0);
+		case RH_PORT_RESET:
+			SET_RH_PORTSTAT(USBPORTSC_PR);
+			mdelay(50);	/* USB v1.1 7.1.7.3 */
+			uhci->rh.c_p_r[wIndex - 1] = 1;
+			CLR_RH_PORTSTAT(USBPORTSC_PR);
+			udelay(10);
+			SET_RH_PORTSTAT(USBPORTSC_PE);
+			mdelay(10);
+			SET_RH_PORTSTAT(0xa);
+			OK(0);
+		case RH_PORT_POWER:
+			OK(0); /* port power ** */
+		case RH_PORT_ENABLE:
+			SET_RH_PORTSTAT(USBPORTSC_PE);
+			OK(0);
+		}
+		break;
+	case RH_SET_ADDRESS:
+		uhci->rh.devnum = wValue;
+		OK(0);
+	case RH_GET_DESCRIPTOR:
+		switch ((wValue & 0xff00) >> 8) {
+		case 0x01:	/* device descriptor */
+			len = min_t(unsigned int, leni,
+				  min_t(unsigned int,
+				      sizeof(root_hub_dev_des), wLength));
+			memcpy(data, root_hub_dev_des, len);
+			OK(len);
+		case 0x02:	/* configuration descriptor */
+			len = min_t(unsigned int, leni,
+				  min_t(unsigned int,
+				      sizeof(root_hub_config_des), wLength));
+			memcpy (data, root_hub_config_des, len);
+			OK(len);
+		case 0x03:	/* string descriptors */
+			len = usb_root_hub_string (wValue & 0xff,
+				uhci->io_addr, "UHCI-alt",
+				data, wLength);
+			if (len > 0) {
+				OK(min_t(int, leni, len));
+			} else 
+				stat = -EPIPE;
+		}
+		break;
+	case RH_GET_DESCRIPTOR | RH_CLASS:
+		root_hub_hub_des[2] = uhci->rh.numports;
+		len = min_t(unsigned int, leni,
+			  min_t(unsigned int, sizeof(root_hub_hub_des), wLength));
+		memcpy(data, root_hub_hub_des, len);
+		OK(len);
+	case RH_GET_CONFIGURATION:
+		*(__u8 *)data = 0x01;
+		OK(1);
+	case RH_SET_CONFIGURATION:
+		OK(0);
+	case RH_GET_INTERFACE | RH_INTERFACE:
+		*(__u8 *)data = 0x00;
+		OK(1);
+	case RH_SET_INTERFACE | RH_INTERFACE:
+		OK(0);
+	default:
+		stat = -EPIPE;
+	}
+
+	urb->actual_length = len;
+
+	return stat;
+}
+
+/*
+ * MUST be called with urb->lock acquired
+ */
+static int rh_unlink_urb(struct urb *urb)
+{
+	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+
+	if (uhci->rh.urb == urb) {
+		urb->status = -ENOENT;
+		uhci->rh.send = 0;
+		uhci->rh.urb = NULL;
+		del_timer(&uhci->rh.rh_int_timer);
+	}
+	return 0;
+}
+
+static void uhci_free_pending_qhs(struct uhci *uhci)
+{
+	struct list_head *tmp, *head;
+	unsigned long flags;
+
+	spin_lock_irqsave(&uhci->qh_remove_list_lock, flags);
+	head = &uhci->qh_remove_list;
+	tmp = head->next;
+	while (tmp != head) {
+		struct uhci_qh *qh = list_entry(tmp, struct uhci_qh, remove_list);
+
+		tmp = tmp->next;
+
+		list_del_init(&qh->remove_list);
+
+		uhci_free_qh(uhci, qh);
+	}
+	spin_unlock_irqrestore(&uhci->qh_remove_list_lock, flags);
+}
+
+static void uhci_call_completion(struct urb *urb)
+{
+	struct urb_priv *urbp;
+	struct usb_device *dev = urb->dev;
+	struct uhci *uhci = (struct uhci *)dev->bus->hcpriv;
+	int is_ring = 0, killed, resubmit_interrupt, status;
+	struct urb *nurb;
+	unsigned long flags;
+
+	spin_lock_irqsave(&urb->lock, flags);
+
+	urbp = (struct urb_priv *)urb->hcpriv;
+	if (!urbp || !urb->dev) {
+		spin_unlock_irqrestore(&urb->lock, flags);
+		return;
+	}
+
+	killed = (urb->status == -ENOENT || urb->status == -ECONNABORTED ||
+			urb->status == -ECONNRESET);
+	resubmit_interrupt = (usb_pipetype(urb->pipe) == PIPE_INTERRUPT &&
+			urb->interval);
+
+	nurb = urb->next;
+	if (nurb && !killed) {
+		int count = 0;
+
+		while (nurb && nurb != urb && count < MAX_URB_LOOP) {
+			if (nurb->status == -ENOENT ||
+			    nurb->status == -ECONNABORTED ||
+			    nurb->status == -ECONNRESET) {
+				killed = 1;
+				break;
+			}
+
+			nurb = nurb->next;
+			count++;
+		}
+
+		if (count == MAX_URB_LOOP)
+			err("uhci_call_completion: too many linked URB's, loop? (first loop)");
+
+		/* Check to see if chain is a ring */
+		is_ring = (nurb == urb);
+	}
+
+	if (urbp->transfer_buffer_dma_handle)
+		pci_dma_sync_single(uhci->dev, urbp->transfer_buffer_dma_handle,
+			urb->transfer_buffer_length, usb_pipein(urb->pipe) ?
+			PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
+
+	if (urbp->setup_packet_dma_handle)
+		pci_dma_sync_single(uhci->dev, urbp->setup_packet_dma_handle,
+			sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE);
+
+	status = urbp->status;
+	if (!resubmit_interrupt || killed)
+		/* We don't need urb_priv anymore */
+		uhci_destroy_urb_priv(urb);
+
+	if (!killed)
+		urb->status = status;
+
+	urb->dev = NULL;
+	spin_unlock_irqrestore(&urb->lock, flags);
+
+	if (urb->complete)
+		urb->complete(urb);
+
+	if (resubmit_interrupt)
+		/* Recheck the status. The completion handler may have */
+		/*  unlinked the resubmitting interrupt URB */
+		killed = (urb->status == -ENOENT ||
+			  urb->status == -ECONNABORTED ||
+			  urb->status == -ECONNRESET);
+
+	if (resubmit_interrupt && !killed) {
+		urb->dev = dev;
+		uhci_reset_interrupt(urb);
+	} else {
+		if (is_ring && !killed) {
+			urb->dev = dev;
+			uhci_submit_urb(urb);
+		} else {
+			/* We decrement the usage count after we're done */
+			/*  with everything */
+			usb_dec_dev_use(dev);
+		}
+	}
+}
+
+static void uhci_finish_completion(struct uhci *uhci)
+{
+	struct list_head *tmp, *head;
+	unsigned long flags;
+
+	spin_lock_irqsave(&uhci->complete_list_lock, flags);
+	head = &uhci->complete_list;
+	tmp = head->next;
+	while (tmp != head) {
+		struct urb_priv *urbp = list_entry(tmp, struct urb_priv, complete_list);
+		struct urb *urb = urbp->urb;
+
+		list_del_init(&urbp->complete_list);
+		spin_unlock_irqrestore(&uhci->complete_list_lock, flags);
+
+		uhci_call_completion(urb);
+
+		spin_lock_irqsave(&uhci->complete_list_lock, flags);
+		head = &uhci->complete_list;
+		tmp = head->next;
+	}
+	spin_unlock_irqrestore(&uhci->complete_list_lock, flags);
+}
+
+static void uhci_remove_pending_qhs(struct uhci *uhci)
+{
+	struct list_head *tmp, *head;
+	unsigned long flags;
+
+	spin_lock_irqsave(&uhci->urb_remove_list_lock, flags);
+	head = &uhci->urb_remove_list;
+	tmp = head->next;
+	while (tmp != head) {
+		struct urb *urb = list_entry(tmp, struct urb, urb_list);
+		struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+
+		tmp = tmp->next;
+
+		list_del_init(&urb->urb_list);
+
+		urbp->status = urb->status = -ECONNRESET;
+
+		uhci_add_complete(urb);
+	}
+	spin_unlock_irqrestore(&uhci->urb_remove_list_lock, flags);
+}
+
+static void uhci_interrupt(int irq, void *__uhci, struct pt_regs *regs)
+{
+	struct uhci *uhci = __uhci;
+	unsigned int io_addr = uhci->io_addr;
+	unsigned short status;
+	struct list_head *tmp, *head;
+
+	/*
+	 * Read the interrupt status, and write it back to clear the
+	 * interrupt cause
+	 */
+	status = inw(io_addr + USBSTS);
+	if (!status)	/* shared interrupt, not mine */
+		return;
+	outw(status, io_addr + USBSTS);		/* Clear it */
+
+	if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD)) {
+		if (status & USBSTS_HSE)
+			err("%x: host system error, PCI problems?", io_addr);
+		if (status & USBSTS_HCPE)
+			err("%x: host controller process error. something bad happened", io_addr);
+		if ((status & USBSTS_HCH) && !uhci->is_suspended) {
+			err("%x: host controller halted. very bad", io_addr);
+			/* FIXME: Reset the controller, fix the offending TD */
+		}
+	}
+
+	if (status & USBSTS_RD)
+		wakeup_hc(uhci);
+
+	uhci_free_pending_qhs(uhci);
+
+	uhci_remove_pending_qhs(uhci);
+
+	uhci_clear_next_interrupt(uhci);
+
+	/* Walk the list of pending URB's to see which ones completed */
+	spin_lock(&uhci->urb_list_lock);
+	head = &uhci->urb_list;
+	tmp = head->next;
+	while (tmp != head) {
+		struct urb *urb = list_entry(tmp, struct urb, urb_list);
+
+		tmp = tmp->next;
+
+		/* Checks the status and does all of the magic necessary */
+		uhci_transfer_result(uhci, urb);
+	}
+	spin_unlock(&uhci->urb_list_lock);
+
+	uhci_finish_completion(uhci);
+}
+
+static void reset_hc(struct uhci *uhci)
+{
+	unsigned int io_addr = uhci->io_addr;
+
+	/* Global reset for 50ms */
+	outw(USBCMD_GRESET, io_addr + USBCMD);
+	wait_ms(50);
+	outw(0, io_addr + USBCMD);
+	wait_ms(10);
+}
+
+static void suspend_hc(struct uhci *uhci)
+{
+	unsigned int io_addr = uhci->io_addr;
+
+	dbg("%x: suspend_hc", io_addr);
+
+	outw(USBCMD_EGSM, io_addr + USBCMD);
+
+	uhci->is_suspended = 1;
+}
+
+static void wakeup_hc(struct uhci *uhci)
+{
+	unsigned int io_addr = uhci->io_addr;
+	unsigned int status;
+
+	dbg("%x: wakeup_hc", io_addr);
+
+	outw(0, io_addr + USBCMD);
+	
+	/* wait for EOP to be sent */
+	status = inw(io_addr + USBCMD);
+	while (status & USBCMD_FGR)
+		status = inw(io_addr + USBCMD);
+
+	uhci->is_suspended = 0;
+
+	/* Run and mark it configured with a 64-byte max packet */
+	outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD);
+}
+
+static int ports_active(struct uhci *uhci)
+{
+	unsigned int io_addr = uhci->io_addr;
+	int connection = 0;
+	int i;
+
+	for (i = 0; i < uhci->rh.numports; i++)
+		connection |= (inw(io_addr + USBPORTSC1 + i * 2) & 0x1);
+
+	return connection;
+}
+
+static void start_hc(struct uhci *uhci)
+{
+	unsigned int io_addr = uhci->io_addr;
+	int timeout = 1000;
+
+	/*
+	 * Reset the HC - this will force us to get a
+	 * new notification of any already connected
+	 * ports due to the virtual disconnect that it
+	 * implies.
+	 */
+	outw(USBCMD_HCRESET, io_addr + USBCMD);
+	while (inw(io_addr + USBCMD) & USBCMD_HCRESET) {
+		if (!--timeout) {
+			printk(KERN_ERR "uhci: USBCMD_HCRESET timed out!\n");
+			break;
+		}
+	}
+
+	/* Turn on all interrupts */
+	outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP,
+		io_addr + USBINTR);
+
+	/* Start at frame 0 */
+	outw(0, io_addr + USBFRNUM);
+	outl(uhci->fl->dma_handle, io_addr + USBFLBASEADD);
+
+	/* Run and mark it configured with a 64-byte max packet */
+	outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD);
+}
+
+#ifdef CONFIG_PROC_FS
+static int uhci_num = 0;
+#endif
+
+static void free_uhci(struct uhci *uhci)
+{
+	kfree(uhci);
+}
+
+/*
+ * De-allocate all resources..
+ */
+static void release_uhci(struct uhci *uhci)
+{
+	int i;
+#ifdef CONFIG_PROC_FS
+	char buf[8];
+#endif
+
+	if (uhci->irq >= 0) {
+		free_irq(uhci->irq, uhci);
+		uhci->irq = -1;
+	}
+
+	for (i = 0; i < UHCI_NUM_SKELQH; i++)
+		if (uhci->skelqh[i]) {
+			uhci_free_qh(uhci, uhci->skelqh[i]);
+			uhci->skelqh[i] = NULL;
+		}
+
+	for (i = 0; i < UHCI_NUM_SKELTD; i++)
+		if (uhci->skeltd[i]) {
+			uhci_free_td(uhci, uhci->skeltd[i]);
+			uhci->skeltd[i] = NULL;
+		}
+
+	if (uhci->qh_pool) {
+		pci_pool_destroy(uhci->qh_pool);
+		uhci->qh_pool = NULL;
+	}
+
+	if (uhci->td_pool) {
+		pci_pool_destroy(uhci->td_pool);
+		uhci->td_pool = NULL;
+	}
+
+	if (uhci->fl) {
+		pci_free_consistent(uhci->dev, sizeof(*uhci->fl), uhci->fl, uhci->fl->dma_handle);
+		uhci->fl = NULL;
+	}
+
+	if (uhci->bus) {
+		usb_free_bus(uhci->bus);
+		uhci->bus = NULL;
+	}
+
+#ifdef CONFIG_PROC_FS
+	if (uhci->proc_entry) {
+		sprintf(buf, "hc%d", uhci->num);
+
+		remove_proc_entry(buf, uhci_proc_root);
+		uhci->proc_entry = NULL;
+	}
+#endif
+
+	free_uhci(uhci);
+}
+
+/*
+ * Allocate a frame list, and then setup the skeleton
+ *
+ * The hardware doesn't really know any difference
+ * in the queues, but the order does matter for the
+ * protocols higher up. The order is:
+ *
+ *  - any isochronous events handled before any
+ *    of the queues. We don't do that here, because
+ *    we'll create the actual TD entries on demand.
+ *  - The first queue is the interrupt queue.
+ *  - The second queue is the control queue, split into low and high speed
+ *  - The third queue is bulk queue.
+ *  - The fourth queue is the bandwidth reclamation queue, which loops back
+ *    to the high speed control queue.
+ */
+static int alloc_uhci(struct pci_dev *dev, unsigned int io_addr, unsigned int io_size)
+{
+	struct uhci *uhci;
+	int retval;
+	char buf[8], *bufp = buf;
+	int i, port;
+	struct usb_bus *bus;
+	dma_addr_t dma_handle;
+#ifdef CONFIG_PROC_FS
+	struct proc_dir_entry *ent;
+#endif
+
+	retval = -ENODEV;
+	if (pci_enable_device(dev) < 0) {
+		err("couldn't enable PCI device");
+		goto err_enable_device;
+	}
+
+	if (!dev->irq) {
+		err("found UHCI device with no IRQ assigned. check BIOS settings!");
+		goto err_invalid_irq;
+	}
+
+	if (!pci_dma_supported(dev, 0xFFFFFFFF)) {
+		err("PCI subsystem doesn't support 32 bit addressing?");
+		goto err_pci_dma_supported;
+	}
+
+	retval = -EBUSY;
+	if (!request_region(io_addr, io_size, "usb-uhci")) {
+		err("couldn't allocate I/O range %x - %x", io_addr,
+			io_addr + io_size - 1);
+		goto err_request_region;
+	}
+
+	pci_set_master(dev);
+
+#ifndef __sparc__
+	sprintf(buf, "%d", dev->irq);
+#else
+	bufp = __irq_itoa(dev->irq);
+#endif
+	printk(KERN_INFO __FILE__ ": USB UHCI at I/O 0x%x, IRQ %s\n",
+		io_addr, bufp);
+
+	if (pci_set_dma_mask(dev, 0xFFFFFFFF)) {
+		err("couldn't set PCI dma mask");
+		retval = -ENODEV;
+		goto err_pci_set_dma_mask;
+	}
+
+	uhci = kmalloc(sizeof(*uhci), GFP_KERNEL);
+	if (!uhci) {
+		err("couldn't allocate uhci structure");
+		retval = -ENOMEM;
+		goto err_alloc_uhci;
+	}
+
+	uhci->dev = dev;
+	uhci->irq = dev->irq;
+	uhci->io_addr = io_addr;
+	uhci->io_size = io_size;
+	pci_set_drvdata(dev, uhci);
+
+#ifdef CONFIG_PROC_FS
+	uhci->num = uhci_num++;
+
+	sprintf(buf, "hc%d", uhci->num);
+
+	ent = create_proc_entry(buf, S_IFREG|S_IRUGO|S_IWUSR, uhci_proc_root);
+	if (!ent) {
+		err("couldn't create uhci proc entry");
+		retval = -ENOMEM;
+		goto err_create_proc_entry;
+	}
+
+	ent->data = uhci;
+	ent->proc_fops = &uhci_proc_operations;
+	ent->size = 0;
+	uhci->proc_entry = ent;
+#endif
+
+	/* Reset here so we don't get any interrupts from an old setup */
+	/*  or broken setup */
+	reset_hc(uhci);
+
+	uhci->fsbr = 0;
+	uhci->fsbrtimeout = 0;
+
+	uhci->is_suspended = 0;
+
+	spin_lock_init(&uhci->qh_remove_list_lock);
+	INIT_LIST_HEAD(&uhci->qh_remove_list);
+
+	spin_lock_init(&uhci->urb_remove_list_lock);
+	INIT_LIST_HEAD(&uhci->urb_remove_list);
+
+	spin_lock_init(&uhci->urb_list_lock);
+	INIT_LIST_HEAD(&uhci->urb_list);
+
+	spin_lock_init(&uhci->complete_list_lock);
+	INIT_LIST_HEAD(&uhci->complete_list);
+
+	spin_lock_init(&uhci->frame_list_lock);
+
+	/* We need exactly one page (per UHCI specs), how convenient */
+	/* We assume that one page is atleast 4k (1024 frames * 4 bytes) */
+#if PAGE_SIZE < (4 * 1024)
+#error PAGE_SIZE is not atleast 4k
+#endif
+	uhci->fl = pci_alloc_consistent(uhci->dev, sizeof(*uhci->fl), &dma_handle);
+	if (!uhci->fl) {
+		err("unable to allocate consistent memory for frame list");
+		goto err_alloc_fl;
+	}
+
+	memset((void *)uhci->fl, 0, sizeof(*uhci->fl));
+
+	uhci->fl->dma_handle = dma_handle;
+
+	uhci->td_pool = pci_pool_create("uhci_td", uhci->dev,
+		sizeof(struct uhci_td), 16, 0, GFP_DMA | GFP_ATOMIC);
+	if (!uhci->td_pool) {
+		err("unable to create td pci_pool");
+		goto err_create_td_pool;
+	}
+
+	uhci->qh_pool = pci_pool_create("uhci_qh", uhci->dev,
+		sizeof(struct uhci_qh), 16, 0, GFP_DMA | GFP_ATOMIC);
+	if (!uhci->qh_pool) {
+		err("unable to create qh pci_pool");
+		goto err_create_qh_pool;
+	}
+
+	bus = usb_alloc_bus(&uhci_device_operations);
+	if (!bus) {
+		err("unable to allocate bus");
+		goto err_alloc_bus;
+	}
+
+	uhci->bus = bus;
+	bus->bus_name = dev->slot_name;
+	bus->hcpriv = uhci;
+
+	usb_register_bus(uhci->bus);
+
+	/* Initialize the root hub */
+
+	/* UHCI specs says devices must have 2 ports, but goes on to say */
+	/*  they may have more but give no way to determine how many they */
+	/*  have. However, according to the UHCI spec, Bit 7 is always set */
+	/*  to 1. So we try to use this to our advantage */
+	for (port = 0; port < (uhci->io_size - 0x10) / 2; port++) {
+		unsigned int portstatus;
+
+		portstatus = inw(uhci->io_addr + 0x10 + (port * 2));
+		if (!(portstatus & 0x0080))
+			break;
+	}
+	if (debug)
+		info("detected %d ports", port);
+
+	/* This is experimental so anything less than 2 or greater than 8 is */
+	/*  something weird and we'll ignore it */
+	if (port < 2 || port > 8) {
+		info("port count misdetected? forcing to 2 ports");
+		port = 2;
+	}
+
+	uhci->rh.numports = port;
+
+	uhci->bus->root_hub = uhci->rh.dev = usb_alloc_dev(NULL, uhci->bus);
+	if (!uhci->rh.dev) {
+		err("unable to allocate root hub");
+		goto err_alloc_root_hub;
+	}
+
+	uhci->skeltd[0] = uhci_alloc_td(uhci, uhci->rh.dev);
+	if (!uhci->skeltd[0]) {
+		err("unable to allocate TD 0");
+		goto err_alloc_skeltd;
+	}
+
+	/*
+	 * 9 Interrupt queues; link int2 to int1, int4 to int2, etc
+	 * then link int1 to control and control to bulk
+	 */
+	for (i = 1; i < 9; i++) {
+		struct uhci_td *td;
+
+		td = uhci->skeltd[i] = uhci_alloc_td(uhci, uhci->rh.dev);
+		if (!td) {
+			err("unable to allocate TD %d", i);
+			goto err_alloc_skeltd;
+		}
+
+		uhci_fill_td(td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0);
+		td->link = uhci->skeltd[i - 1]->dma_handle;
+	}
+
+	uhci->skel_term_td = uhci_alloc_td(uhci, uhci->rh.dev);
+	if (!uhci->skel_term_td) {
+		err("unable to allocate skel TD term");
+		goto err_alloc_skeltd;
+	}
+
+	for (i = 0; i < UHCI_NUM_SKELQH; i++) {
+		uhci->skelqh[i] = uhci_alloc_qh(uhci, uhci->rh.dev);
+		if (!uhci->skelqh[i]) {
+			err("unable to allocate QH %d", i);
+			goto err_alloc_skelqh;
+		}
+	}
+
+	uhci_fill_td(uhci->skel_int1_td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0);
+	uhci->skel_int1_td->link = uhci->skel_ls_control_qh->dma_handle | UHCI_PTR_QH;
+
+	uhci->skel_ls_control_qh->link = uhci->skel_hs_control_qh->dma_handle | UHCI_PTR_QH;
+	uhci->skel_ls_control_qh->element = UHCI_PTR_TERM;
+
+	uhci->skel_hs_control_qh->link = uhci->skel_bulk_qh->dma_handle | UHCI_PTR_QH;
+	uhci->skel_hs_control_qh->element = UHCI_PTR_TERM;
+
+	uhci->skel_bulk_qh->link = uhci->skel_term_qh->dma_handle | UHCI_PTR_QH;
+	uhci->skel_bulk_qh->element = UHCI_PTR_TERM;
+
+	/* This dummy TD is to work around a bug in Intel PIIX controllers */
+	uhci_fill_td(uhci->skel_term_td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0);
+	uhci->skel_term_td->link = uhci->skel_term_td->dma_handle;
+
+	uhci->skel_term_qh->link = UHCI_PTR_TERM;
+	uhci->skel_term_qh->element = uhci->skel_term_td->dma_handle;
+
+	/*
+	 * Fill the frame list: make all entries point to
+	 * the proper interrupt queue.
+	 *
+	 * This is probably silly, but it's a simple way to
+	 * scatter the interrupt queues in a way that gives
+	 * us a reasonable dynamic range for irq latencies.
+	 */
+	for (i = 0; i < UHCI_NUMFRAMES; i++) {
+		int irq = 0;
+
+		if (i & 1) {
+			irq++;
+			if (i & 2) {
+				irq++;
+				if (i & 4) { 
+					irq++;
+					if (i & 8) { 
+						irq++;
+						if (i & 16) {
+							irq++;
+							if (i & 32) {
+								irq++;
+								if (i & 64)
+									irq++;
+							}
+						}
+					}
+				}
+			}
+		}
+
+		/* Only place we don't use the frame list routines */
+		uhci->fl->frame[i] =  uhci->skeltd[irq]->dma_handle;
+	}
+
+	start_hc(uhci);
+
+	if (request_irq(dev->irq, uhci_interrupt, SA_SHIRQ, "usb-uhci", uhci))
+		goto err_request_irq;
+
+	/* disable legacy emulation */
+	pci_write_config_word(uhci->dev, USBLEGSUP, USBLEGSUP_DEFAULT);
+
+	usb_connect(uhci->rh.dev);
+
+	if (usb_new_device(uhci->rh.dev) != 0) {
+		err("unable to start root hub");
+		retval = -ENOMEM;
+		goto err_start_root_hub;
+	}
+
+	return 0;
+
+/*
+ * error exits:
+ */
+err_start_root_hub:
+	free_irq(uhci->irq, uhci);
+	uhci->irq = -1;
+
+err_request_irq:
+	for (i = 0; i < UHCI_NUM_SKELQH; i++)
+		if (uhci->skelqh[i]) {
+			uhci_free_qh(uhci, uhci->skelqh[i]);
+			uhci->skelqh[i] = NULL;
+		}
+
+err_alloc_skelqh:
+	for (i = 0; i < UHCI_NUM_SKELTD; i++)
+		if (uhci->skeltd[i]) {
+			uhci_free_td(uhci, uhci->skeltd[i]);
+			uhci->skeltd[i] = NULL;
+		}
+
+err_alloc_skeltd:
+	usb_free_dev(uhci->rh.dev);
+	uhci->rh.dev = NULL;
+
+err_alloc_root_hub:
+	usb_free_bus(uhci->bus);
+	uhci->bus = NULL;
+
+err_alloc_bus:
+	pci_pool_destroy(uhci->qh_pool);
+	uhci->qh_pool = NULL;
+
+err_create_qh_pool:
+	pci_pool_destroy(uhci->td_pool);
+	uhci->td_pool = NULL;
+
+err_create_td_pool:
+	pci_free_consistent(uhci->dev, sizeof(*uhci->fl), uhci->fl, uhci->fl->dma_handle);
+	uhci->fl = NULL;
+
+err_alloc_fl:
+#ifdef CONFIG_PROC_FS
+	remove_proc_entry(buf, uhci_proc_root);
+	uhci->proc_entry = NULL;
+
+err_create_proc_entry:
+	free_uhci(uhci);
+#endif
+
+err_alloc_uhci:
+
+err_pci_set_dma_mask:
+	release_region(io_addr, io_size);
+
+err_request_region:
+
+err_pci_dma_supported:
+
+err_invalid_irq:
+
+err_enable_device:
+
+	return retval;
+}
+
+static int __devinit uhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	int i;
+
+	/* Search for the IO base address.. */
+	for (i = 0; i < 6; i++) {
+		unsigned int io_addr = pci_resource_start(dev, i);
+		unsigned int io_size = pci_resource_len(dev, i);
+
+		/* IO address? */
+		if (!(pci_resource_flags(dev, i) & IORESOURCE_IO))
+			continue;
+
+		return alloc_uhci(dev, io_addr, io_size);
+	}
+
+	return -ENODEV;
+}
+
+static void __devexit uhci_pci_remove(struct pci_dev *dev)
+{
+	struct uhci *uhci = pci_get_drvdata(dev);
+
+	if (uhci->bus->root_hub)
+		usb_disconnect(&uhci->bus->root_hub);
+
+	usb_deregister_bus(uhci->bus);
+
+	/*
+	 * At this point, we're guaranteed that no new connects can be made
+	 * to this bus since there are no more parents
+	 */
+	uhci_free_pending_qhs(uhci);
+	uhci_remove_pending_qhs(uhci);
+
+	reset_hc(uhci);
+	release_region(uhci->io_addr, uhci->io_size);
+
+	uhci_free_pending_qhs(uhci);
+
+	release_uhci(uhci);
+}
+
+#ifdef CONFIG_PM
+static int uhci_pci_suspend(struct pci_dev *dev, u32 state)
+{
+	suspend_hc((struct uhci *) pci_get_drvdata(dev));
+	return 0;
+}
+
+static int uhci_pci_resume(struct pci_dev *dev)
+{
+	reset_hc((struct uhci *) pci_get_drvdata(dev));
+	start_hc((struct uhci *) pci_get_drvdata(dev));
+	return 0;
+}
+#endif
+
+static const struct pci_device_id __devinitdata uhci_pci_ids[] = { {
+
+	/* handle any USB UHCI controller */
+	class: 		((PCI_CLASS_SERIAL_USB << 8) | 0x00),
+	class_mask: 	~0,
+
+	/* no matter who makes it */
+	vendor:		PCI_ANY_ID,
+	device:		PCI_ANY_ID,
+	subvendor:	PCI_ANY_ID,
+	subdevice:	PCI_ANY_ID,
+
+	}, { /* end: all zeroes */ }
+};
+
+MODULE_DEVICE_TABLE(pci, uhci_pci_ids);
+
+static struct pci_driver uhci_pci_driver = {
+	name:		"usb-uhci",
+	id_table:	uhci_pci_ids,
+
+	probe:		uhci_pci_probe,
+	remove:		__devexit_p(uhci_pci_remove),
+
+#ifdef	CONFIG_PM
+	suspend:	uhci_pci_suspend,
+	resume:		uhci_pci_resume,
+#endif	/* PM */
+};
+
+ 
+static int __init uhci_hcd_init(void)
+{
+	int retval = -ENOMEM;
+
+	info(DRIVER_DESC " " DRIVER_VERSION);
+
+	if (debug) {
+		errbuf = kmalloc(ERRBUF_LEN, GFP_KERNEL);
+		if (!errbuf)
+			goto errbuf_failed;
+	}
+
+#ifdef CONFIG_PROC_FS
+	uhci_proc_root = create_proc_entry("driver/uhci", S_IFDIR, 0);
+	if (!uhci_proc_root)
+		goto proc_failed;
+#endif
+
+	uhci_up_cachep = kmem_cache_create("uhci_urb_priv",
+		sizeof(struct urb_priv), 0, 0, NULL, NULL);
+	if (!uhci_up_cachep)
+		goto up_failed;
+
+	retval = pci_module_init(&uhci_pci_driver);
+	if (retval)
+		goto init_failed;
+
+	return 0;
+
+init_failed:
+	if (kmem_cache_destroy(uhci_up_cachep))
+		printk(KERN_INFO "uhci: not all urb_priv's were freed\n");
+
+up_failed:
+
+#ifdef CONFIG_PROC_FS
+	remove_proc_entry("driver/uhci", 0);
+
+proc_failed:
+#endif
+	if (errbuf)
+		kfree(errbuf);
+
+errbuf_failed:
+
+	return retval;
+}
+
+static void __exit uhci_hcd_cleanup(void) 
+{
+	pci_unregister_driver(&uhci_pci_driver);
+	
+	if (kmem_cache_destroy(uhci_up_cachep))
+		printk(KERN_INFO "uhci: not all urb_priv's were freed\n");
+
+#ifdef CONFIG_PROC_FS
+	remove_proc_entry("driver/uhci", 0);
+#endif
+
+	if (errbuf)
+		kfree(errbuf);
+}
+
+module_init(uhci_hcd_init);
+module_exit(uhci_hcd_cleanup);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/host/uhci.h linux-2.4.21-pre6/drivers/usb/host/uhci.h
--- linux-2.4.20/drivers/usb/host/uhci.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/host/uhci.h	2003-03-26 23:49:08.000000000 +0000
@@ -0,0 +1,441 @@
+#ifndef __LINUX_UHCI_H
+#define __LINUX_UHCI_H
+
+#include <linux/list.h>
+#include <linux/usb.h>
+
+/*
+ * Universal Host Controller Interface data structures and defines
+ */
+
+/* Command register */
+#define USBCMD		0
+#define   USBCMD_RS		0x0001	/* Run/Stop */
+#define   USBCMD_HCRESET	0x0002	/* Host reset */
+#define   USBCMD_GRESET		0x0004	/* Global reset */
+#define   USBCMD_EGSM		0x0008	/* Global Suspend Mode */
+#define   USBCMD_FGR		0x0010	/* Force Global Resume */
+#define   USBCMD_SWDBG		0x0020	/* SW Debug mode */
+#define   USBCMD_CF		0x0040	/* Config Flag (sw only) */
+#define   USBCMD_MAXP		0x0080	/* Max Packet (0 = 32, 1 = 64) */
+
+/* Status register */
+#define USBSTS		2
+#define   USBSTS_USBINT		0x0001	/* Interrupt due to IOC */
+#define   USBSTS_ERROR		0x0002	/* Interrupt due to error */
+#define   USBSTS_RD		0x0004	/* Resume Detect */
+#define   USBSTS_HSE		0x0008	/* Host System Error - basically PCI problems */
+#define   USBSTS_HCPE		0x0010	/* Host Controller Process Error - the scripts were buggy */
+#define   USBSTS_HCH		0x0020	/* HC Halted */
+
+/* Interrupt enable register */
+#define USBINTR		4
+#define   USBINTR_TIMEOUT	0x0001	/* Timeout/CRC error enable */
+#define   USBINTR_RESUME	0x0002	/* Resume interrupt enable */
+#define   USBINTR_IOC		0x0004	/* Interrupt On Complete enable */
+#define   USBINTR_SP		0x0008	/* Short packet interrupt enable */
+
+#define USBFRNUM	6
+#define USBFLBASEADD	8
+#define USBSOF		12
+
+/* USB port status and control registers */
+#define USBPORTSC1	16
+#define USBPORTSC2	18
+#define   USBPORTSC_CCS		0x0001	/* Current Connect Status ("device present") */
+#define   USBPORTSC_CSC		0x0002	/* Connect Status Change */
+#define   USBPORTSC_PE		0x0004	/* Port Enable */
+#define   USBPORTSC_PEC		0x0008	/* Port Enable Change */
+#define   USBPORTSC_LS		0x0030	/* Line Status */
+#define   USBPORTSC_RD		0x0040	/* Resume Detect */
+#define   USBPORTSC_LSDA	0x0100	/* Low Speed Device Attached */
+#define   USBPORTSC_PR		0x0200	/* Port Reset */
+#define   USBPORTSC_SUSP	0x1000	/* Suspend */
+
+/* Legacy support register */
+#define USBLEGSUP		0xc0
+#define   USBLEGSUP_DEFAULT	0x2000	/* only PIRQ enable set */
+
+#define UHCI_NULL_DATA_SIZE	0x7FF	/* for UHCI controller TD */
+
+#define UHCI_PTR_BITS		0x000F
+#define UHCI_PTR_TERM		0x0001
+#define UHCI_PTR_QH		0x0002
+#define UHCI_PTR_DEPTH		0x0004
+
+#define UHCI_NUMFRAMES		1024	/* in the frame list [array] */
+#define UHCI_MAX_SOF_NUMBER	2047	/* in an SOF packet */
+#define CAN_SCHEDULE_FRAMES	1000	/* how far future frames can be scheduled */
+
+struct uhci_frame_list {
+	__u32 frame[UHCI_NUMFRAMES];
+
+	void *frame_cpu[UHCI_NUMFRAMES];
+
+	dma_addr_t dma_handle;
+};
+
+struct urb_priv;
+
+struct uhci_qh {
+	/* Hardware fields */
+	__u32 link;			/* Next queue */
+	__u32 element;			/* Queue element pointer */
+
+	/* Software fields */
+	dma_addr_t dma_handle;
+
+	struct usb_device *dev;
+	struct urb_priv *urbp;
+
+	struct list_head list;		/* P: uhci->frame_list_lock */
+	struct list_head remove_list;	/* P: uhci->remove_list_lock */
+} __attribute__((aligned(16)));
+
+/*
+ * for TD <status>:
+ */
+#define TD_CTRL_SPD		(1 << 29)	/* Short Packet Detect */
+#define TD_CTRL_C_ERR_MASK	(3 << 27)	/* Error Counter bits */
+#define TD_CTRL_C_ERR_SHIFT	27
+#define TD_CTRL_LS		(1 << 26)	/* Low Speed Device */
+#define TD_CTRL_IOS		(1 << 25)	/* Isochronous Select */
+#define TD_CTRL_IOC		(1 << 24)	/* Interrupt on Complete */
+#define TD_CTRL_ACTIVE		(1 << 23)	/* TD Active */
+#define TD_CTRL_STALLED		(1 << 22)	/* TD Stalled */
+#define TD_CTRL_DBUFERR		(1 << 21)	/* Data Buffer Error */
+#define TD_CTRL_BABBLE		(1 << 20)	/* Babble Detected */
+#define TD_CTRL_NAK		(1 << 19)	/* NAK Received */
+#define TD_CTRL_CRCTIMEO	(1 << 18)	/* CRC/Time Out Error */
+#define TD_CTRL_BITSTUFF	(1 << 17)	/* Bit Stuff Error */
+#define TD_CTRL_ACTLEN_MASK	0x7FF		/* actual length, encoded as n - 1 */
+
+#define TD_CTRL_ANY_ERROR	(TD_CTRL_STALLED | TD_CTRL_DBUFERR | \
+				 TD_CTRL_BABBLE | TD_CTRL_CRCTIME | TD_CTRL_BITSTUFF)
+
+#define uhci_status_bits(ctrl_sts)	(ctrl_sts & 0xFE0000)
+#define uhci_actual_length(ctrl_sts)	((ctrl_sts + 1) & TD_CTRL_ACTLEN_MASK) /* 1-based */
+
+/*
+ * for TD <info>: (a.k.a. Token)
+ */
+#define TD_TOKEN_TOGGLE_SHIFT	19
+#define TD_TOKEN_TOGGLE		(1 << 19)
+#define TD_TOKEN_PID_MASK	0xFF
+#define TD_TOKEN_EXPLEN_MASK	0x7FF		/* expected length, encoded as n - 1 */
+
+#define uhci_maxlen(token)	((token) >> 21)
+#define uhci_expected_length(info) (((info >> 21) + 1) & TD_TOKEN_EXPLEN_MASK) /* 1-based */
+#define uhci_toggle(token)	(((token) >> TD_TOKEN_TOGGLE_SHIFT) & 1)
+#define uhci_endpoint(token)	(((token) >> 15) & 0xf)
+#define uhci_devaddr(token)	(((token) >> 8) & 0x7f)
+#define uhci_devep(token)	(((token) >> 8) & 0x7ff)
+#define uhci_packetid(token)	((token) & TD_TOKEN_PID_MASK)
+#define uhci_packetout(token)	(uhci_packetid(token) != USB_PID_IN)
+#define uhci_packetin(token)	(uhci_packetid(token) == USB_PID_IN)
+
+/*
+ * The documentation says "4 words for hardware, 4 words for software".
+ *
+ * That's silly, the hardware doesn't care. The hardware only cares that
+ * the hardware words are 16-byte aligned, and we can have any amount of
+ * sw space after the TD entry as far as I can tell.
+ *
+ * But let's just go with the documentation, at least for 32-bit machines.
+ * On 64-bit machines we probably want to take advantage of the fact that
+ * hw doesn't really care about the size of the sw-only area.
+ *
+ * Alas, not anymore, we have more than 4 words for software, woops.
+ * Everything still works tho, surprise! -jerdfelt
+ */
+struct uhci_td {
+	/* Hardware fields */
+	__u32 link;
+	__u32 status;
+	__u32 info;
+	__u32 buffer;
+
+	/* Software fields */
+	dma_addr_t dma_handle;
+
+	struct usb_device *dev;
+	struct urb *urb;
+
+	struct list_head list;		/* P: urb->lock */
+
+	int frame;
+	struct list_head fl_list;	/* P: uhci->frame_list_lock */
+} __attribute__((aligned(16)));
+
+/*
+ * There are various standard queues. We set up several different
+ * queues for each of the three basic queue types: interrupt,
+ * control, and bulk.
+ *
+ *  - There are various different interrupt latencies: ranging from
+ *    every other USB frame (2 ms apart) to every 256 USB frames (ie
+ *    256 ms apart). Make your choice according to how obnoxious you
+ *    want to be on the wire, vs how critical latency is for you.
+ *  - The control list is done every frame.
+ *  - There are 4 bulk lists, so that up to four devices can have a
+ *    bulk list of their own and when run concurrently all four lists
+ *    will be be serviced.
+ *
+ * This is a bit misleading, there are various interrupt latencies, but they
+ * vary a bit, interrupt2 isn't exactly 2ms, it can vary up to 4ms since the
+ * other queues can "override" it. interrupt4 can vary up to 8ms, etc. Minor
+ * problem
+ *
+ * In the case of the root hub, these QH's are just head's of qh's. Don't
+ * be scared, it kinda makes sense. Look at this wonderful picture care of
+ * Linus:
+ *
+ *  generic-  ->  dev1-  ->  generic-  ->  dev1-  ->  control-  ->  bulk- -> ...
+ *   iso-QH      iso-QH       irq-QH      irq-QH        QH           QH
+ *      |           |            |           |           |            |
+ *     End     dev1-iso-TD1     End     dev1-irq-TD1    ...          ... 
+ *                  |
+ *             dev1-iso-TD2
+ *                  |
+ *                ....
+ *
+ * This may vary a bit (the UHCI docs don't explicitly say you can put iso
+ * transfers in QH's and all of their pictures don't have that either) but
+ * other than that, that is what we're doing now
+ *
+ * And now we don't put Iso transfers in QH's, so we don't waste one on it
+ * --jerdfelt
+ *
+ * To keep with Linus' nomenclature, this is called the QH skeleton. These
+ * labels (below) are only signficant to the root hub's QH's
+ */
+
+#define UHCI_NUM_SKELTD		10
+#define skel_int1_td		skeltd[0]
+#define skel_int2_td		skeltd[1]
+#define skel_int4_td		skeltd[2]
+#define skel_int8_td		skeltd[3]
+#define skel_int16_td		skeltd[4]
+#define skel_int32_td		skeltd[5]
+#define skel_int64_td		skeltd[6]
+#define skel_int128_td		skeltd[7]
+#define skel_int256_td		skeltd[8]
+#define skel_term_td		skeltd[9]	/* To work around PIIX UHCI bug */
+
+#define UHCI_NUM_SKELQH		4
+#define skel_ls_control_qh	skelqh[0]
+#define skel_hs_control_qh	skelqh[1]
+#define skel_bulk_qh		skelqh[2]
+#define skel_term_qh		skelqh[3]
+
+/*
+ * Search tree for determining where <interval> fits in the
+ * skelqh[] skeleton.
+ *
+ * An interrupt request should be placed into the slowest skelqh[]
+ * which meets the interval/period/frequency requirement.
+ * An interrupt request is allowed to be faster than <interval> but not slower.
+ *
+ * For a given <interval>, this function returns the appropriate/matching
+ * skelqh[] index value.
+ *
+ * NOTE: For UHCI, we don't really need int256_qh since the maximum interval
+ * is 255 ms.  However, we do need an int1_qh since 1 is a valid interval
+ * and we should meet that frequency when requested to do so.
+ * This will require some change(s) to the UHCI skeleton.
+ */
+static inline int __interval_to_skel(int interval)
+{
+	if (interval < 16) {
+		if (interval < 4) {
+			if (interval < 2)
+				return 0;	/* int1 for 0-1 ms */
+			return 1;		/* int2 for 2-3 ms */
+		}
+		if (interval < 8)
+			return 2;		/* int4 for 4-7 ms */
+		return 3;			/* int8 for 8-15 ms */
+	}
+	if (interval < 64) {
+		if (interval < 32)
+			return 4;		/* int16 for 16-31 ms */
+		return 5;			/* int32 for 32-63 ms */
+	}
+	if (interval < 128)
+		return 6;			/* int64 for 64-127 ms */
+	return 7;				/* int128 for 128-255 ms (Max.) */
+}
+
+struct virt_root_hub {
+	struct usb_device *dev;
+	int devnum;		/* Address of Root Hub endpoint */
+	struct urb *urb;
+	void *int_addr;
+	int send;
+	int interval;
+	int numports;
+	int c_p_r[8];
+	struct timer_list rh_int_timer;
+};
+
+/*
+ * This describes the full uhci information.
+ *
+ * Note how the "proper" USB information is just
+ * a subset of what the full implementation needs.
+ */
+struct uhci {
+	struct pci_dev *dev;
+
+#ifdef CONFIG_PROC_FS
+	/* procfs */
+	int num;
+	struct proc_dir_entry *proc_entry;
+#endif
+
+	/* Grabbed from PCI */
+	int irq;
+	unsigned int io_addr;
+	unsigned int io_size;
+
+	struct pci_pool *qh_pool;
+	struct pci_pool *td_pool;
+
+	struct usb_bus *bus;
+
+	struct uhci_td *skeltd[UHCI_NUM_SKELTD];	/* Skeleton TD's */
+	struct uhci_qh *skelqh[UHCI_NUM_SKELQH];	/* Skeleton QH's */
+
+	spinlock_t frame_list_lock;
+	struct uhci_frame_list *fl;		/* P: uhci->frame_list_lock */
+	int fsbr;				/* Full speed bandwidth reclamation */
+	unsigned long fsbrtimeout;		/* FSBR delay */
+	int is_suspended;
+
+	/* Main list of URB's currently controlled by this HC */
+	spinlock_t urb_list_lock;
+	struct list_head urb_list;		/* P: uhci->urb_list_lock */
+
+	/* List of QH's that are done, but waiting to be unlinked (race) */
+	spinlock_t qh_remove_list_lock;
+	struct list_head qh_remove_list;	/* P: uhci->qh_remove_list_lock */
+
+	/* List of asynchronously unlinked URB's */
+	spinlock_t urb_remove_list_lock;
+	struct list_head urb_remove_list;	/* P: uhci->urb_remove_list_lock */
+
+	/* List of URB's awaiting completion callback */
+	spinlock_t complete_list_lock;
+	struct list_head complete_list;		/* P: uhci->complete_list_lock */
+
+	struct virt_root_hub rh;	/* private data of the virtual root hub */
+};
+
+struct urb_priv {
+	struct urb *urb;
+	struct usb_device *dev;
+
+	dma_addr_t setup_packet_dma_handle;
+	dma_addr_t transfer_buffer_dma_handle;
+
+	struct uhci_qh *qh;		/* QH for this URB */
+	struct list_head td_list;	/* P: urb->lock */
+
+	int fsbr : 1;			/* URB turned on FSBR */
+	int fsbr_timeout : 1;		/* URB timed out on FSBR */
+	int queued : 1;			/* QH was queued (not linked in) */
+	int short_control_packet : 1;	/* If we get a short packet during */
+					/*  a control transfer, retrigger */
+					/*  the status phase */
+
+	int status;			/* Final status */
+
+	unsigned long inserttime;	/* In jiffies */
+	unsigned long fsbrtime;		/* In jiffies */
+
+	struct list_head queue_list;	/* P: uhci->frame_list_lock */
+	struct list_head complete_list;	/* P: uhci->complete_list_lock */
+};
+
+/*
+ * Locking in uhci.c
+ *
+ * spinlocks are used extensively to protect the many lists and data
+ * structures we have. It's not that pretty, but it's necessary. We
+ * need to be done with all of the locks (except complete_list_lock) when
+ * we call urb->complete. I've tried to make it simple enough so I don't
+ * have to spend hours racking my brain trying to figure out if the
+ * locking is safe.
+ *
+ * Here's the safe locking order to prevent deadlocks:
+ *
+ * #1 uhci->urb_list_lock
+ * #2 urb->lock
+ * #3 uhci->urb_remove_list_lock, uhci->frame_list_lock, 
+ *   uhci->qh_remove_list_lock
+ * #4 uhci->complete_list_lock
+ *
+ * If you're going to grab 2 or more locks at once, ALWAYS grab the lock
+ * at the lowest level FIRST and NEVER grab locks at the same level at the
+ * same time.
+ * 
+ * So, if you need uhci->urb_list_lock, grab it before you grab urb->lock
+ */
+
+/* -------------------------------------------------------------------------
+   Virtual Root HUB
+   ------------------------------------------------------------------------- */
+/* destination of request */
+#define RH_DEVICE		0x00
+#define RH_INTERFACE		0x01
+#define RH_ENDPOINT		0x02
+#define RH_OTHER		0x03
+
+#define RH_CLASS		0x20
+#define RH_VENDOR		0x40
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define RH_GET_STATUS		0x0080
+#define RH_CLEAR_FEATURE	0x0100
+#define RH_SET_FEATURE		0x0300
+#define RH_SET_ADDRESS		0x0500
+#define RH_GET_DESCRIPTOR	0x0680
+#define RH_SET_DESCRIPTOR	0x0700
+#define RH_GET_CONFIGURATION	0x0880
+#define RH_SET_CONFIGURATION	0x0900
+#define RH_GET_STATE		0x0280
+#define RH_GET_INTERFACE	0x0A80
+#define RH_SET_INTERFACE	0x0B00
+#define RH_SYNC_FRAME		0x0C80
+/* Our Vendor Specific Request */
+#define RH_SET_EP		0x2000
+
+/* Hub port features */
+#define RH_PORT_CONNECTION	0x00
+#define RH_PORT_ENABLE		0x01
+#define RH_PORT_SUSPEND		0x02
+#define RH_PORT_OVER_CURRENT	0x03
+#define RH_PORT_RESET		0x04
+#define RH_PORT_POWER		0x08
+#define RH_PORT_LOW_SPEED	0x09
+#define RH_C_PORT_CONNECTION	0x10
+#define RH_C_PORT_ENABLE	0x11
+#define RH_C_PORT_SUSPEND	0x12
+#define RH_C_PORT_OVER_CURRENT	0x13
+#define RH_C_PORT_RESET		0x14
+
+/* Hub features */
+#define RH_C_HUB_LOCAL_POWER	0x00
+#define RH_C_HUB_OVER_CURRENT	0x01
+#define RH_DEVICE_REMOTE_WAKEUP	0x00
+#define RH_ENDPOINT_STALL	0x01
+
+/* Our Vendor Specific feature */
+#define RH_REMOVE_EP		0x00
+
+#define RH_ACK			0x01
+#define RH_REQ_ERR		-1
+#define RH_NACK			0x00
+
+#endif
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/host/usb-ohci.c linux-2.4.21-pre6/drivers/usb/host/usb-ohci.c
--- linux-2.4.20/drivers/usb/host/usb-ohci.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/host/usb-ohci.c	2003-03-26 23:49:18.000000000 +0000
@@ -0,0 +1,2938 @@
+/*
+ * URB OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ * 
+ * [ Initialisation is based on Linus'  ]
+ * [ uhci code and gregs ohci fragments ]
+ * [ (C) Copyright 1999 Linus Torvalds  ]
+ * [ (C) Copyright 1999 Gregory P. Smith]
+ * 
+ * 
+ * History:
+ *
+ * 2002/10/22 OHCI_USB_OPER for ALi lockup in IBM i1200 (ALEX <thchou@ali>)
+ * 2002/03/08 interrupt unlink fix (Matt Hughes), better cleanup on
+ *	load failure (Matthew Frederickson)
+ * 2002/01/20 async unlink fixes:  return -EINPROGRESS (per spec) and
+ *	make interrupt unlink-in-completion work (db)
+ * 2001/09/19 USB_ZERO_PACKET support (Jean Tourrilhes)
+ * 2001/07/17 power management and pmac cleanup (Benjamin Herrenschmidt)
+ * 2001/03/24 td/ed hashing to remove bus_to_virt (Steve Longerbeam);
+ 	pci_map_single (db)
+ * 2001/03/21 td and dev/ed allocation uses new pci_pool API (db)
+ * 2001/03/07 hcca allocation uses pci_alloc_consistent (Steve Longerbeam)
+ *
+ * 2000/09/26 fixed races in removing the private portion of the urb
+ * 2000/09/07 disable bulk and control lists when unlinking the last
+ *	endpoint descriptor in order to avoid unrecoverable errors on
+ *	the Lucent chips. (rwc@sgi)
+ * 2000/08/29 use bandwidth claiming hooks (thanks Randy!), fix some
+ *	urb unlink probs, indentation fixes
+ * 2000/08/11 various oops fixes mostly affecting iso and cleanup from
+ *	device unplugs.
+ * 2000/06/28 use PCI hotplug framework, for better power management
+ *	and for Cardbus support (David Brownell)
+ * 2000/earlier:  fixes for NEC/Lucent chips; suspend/resume handling
+ *	when the controller loses power; handle UE; cleanup; ...
+ *
+ * v5.2 1999/12/07 URB 3rd preview, 
+ * v5.1 1999/11/30 URB 2nd preview, cpia, (usb-scsi)
+ * v5.0 1999/11/22 URB Technical preview, Paul Mackerras powerbook susp/resume 
+ * 	i386: HUB, Keyboard, Mouse, Printer 
+ *
+ * v4.3 1999/10/27 multiple HCs, bulk_request
+ * v4.2 1999/09/05 ISO API alpha, new dev alloc, neg Error-codes
+ * v4.1 1999/08/27 Randy Dunlap's - ISO API first impl.
+ * v4.0 1999/08/18 
+ * v3.0 1999/06/25 
+ * v2.1 1999/05/09  code clean up
+ * v2.0 1999/05/04 
+ * v1.0 1999/04/27 initial release
+ */
+ 
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>  /* for in_interrupt() */
+#undef DEBUG
+#include <linux/usb.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+
+#define OHCI_USE_NPS		// force NoPowerSwitching mode
+// #define OHCI_VERBOSE_DEBUG	/* not always helpful */
+
+#include "usb-ohci.h"
+
+#include "../hcd.h"
+
+#ifdef CONFIG_PMAC_PBOOK
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
+#include <asm/pci-bridge.h>
+#ifndef CONFIG_PM
+#define CONFIG_PM
+#endif
+#endif
+
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v5.3"
+#define DRIVER_AUTHOR "Roman Weissgaerber <weissg@vienna.at>, David Brownell"
+#define DRIVER_DESC "USB OHCI Host Controller Driver"
+
+/* For initializing controller (mask in an HCFS mode too) */
+#define	OHCI_CONTROL_INIT \
+	(OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE
+
+#define OHCI_UNLINK_TIMEOUT	(HZ / 10)
+
+static LIST_HEAD (ohci_hcd_list);
+static spinlock_t usb_ed_lock = SPIN_LOCK_UNLOCKED;
+
+
+/*-------------------------------------------------------------------------*/
+
+/* AMD-756 (D2 rev) reports corrupt register contents in some cases.
+ * The erratum (#4) description is incorrect.  AMD's workaround waits
+ * till some bits (mostly reserved) are clear; ok for all revs.
+ */
+#define read_roothub(hc, register, mask) ({ \
+	u32 temp = readl (&hc->regs->roothub.register); \
+	if (hc->flags & OHCI_QUIRK_AMD756) \
+		while (temp & mask) \
+			temp = readl (&hc->regs->roothub.register); \
+	temp; })
+
+static u32 roothub_a (struct ohci *hc)
+	{ return read_roothub (hc, a, 0xfc0fe000); }
+static inline u32 roothub_b (struct ohci *hc)
+	{ return readl (&hc->regs->roothub.b); }
+static inline u32 roothub_status (struct ohci *hc)
+	{ return readl (&hc->regs->roothub.status); }
+static u32 roothub_portstatus (struct ohci *hc, int i)
+	{ return read_roothub (hc, portstatus [i], 0xffe0fce0); }
+
+
+/*-------------------------------------------------------------------------*
+ * URB support functions 
+ *-------------------------------------------------------------------------*/ 
+ 
+/* free HCD-private data associated with this URB */
+
+static void urb_free_priv (struct ohci *hc, urb_priv_t * urb_priv)
+{
+	int		i;
+	int		last = urb_priv->length - 1;
+	int		len;
+	int		dir;
+	struct td	*td;
+
+	if (last >= 0) {
+
+		/* ISOC, BULK, INTR data buffer starts at td 0 
+		 * CTRL setup starts at td 0 */
+		td = urb_priv->td [0];
+
+		len = td->urb->transfer_buffer_length,
+		dir = usb_pipeout (td->urb->pipe)
+					? PCI_DMA_TODEVICE
+					: PCI_DMA_FROMDEVICE;
+
+		/* unmap CTRL URB setup */
+		if (usb_pipecontrol (td->urb->pipe)) {
+			pci_unmap_single (hc->ohci_dev, 
+					td->data_dma, 8, PCI_DMA_TODEVICE);
+			
+			/* CTRL data buffer starts at td 1 if len > 0 */
+			if (len && last > 0)
+				td = urb_priv->td [1]; 		
+		} 
+
+		/* unmap data buffer */
+		if (len && td->data_dma)
+			pci_unmap_single (hc->ohci_dev, td->data_dma, len, dir);
+		
+		for (i = 0; i <= last; i++) {
+			td = urb_priv->td [i];
+			if (td)
+				td_free (hc, td);
+		}
+	}
+
+	kfree (urb_priv);
+}
+ 
+static void urb_rm_priv_locked (struct urb * urb) 
+{
+	urb_priv_t * urb_priv = urb->hcpriv;
+	
+	if (urb_priv) {
+		urb->hcpriv = NULL;
+
+#ifdef	DO_TIMEOUTS
+		if (urb->timeout) {
+			list_del (&urb->urb_list);
+			urb->timeout -= jiffies;
+		}
+#endif
+
+		/* Release int/iso bandwidth */
+		if (urb->bandwidth) {
+			switch (usb_pipetype(urb->pipe)) {
+			case PIPE_INTERRUPT:
+				usb_release_bandwidth (urb->dev, urb, 0);
+				break;
+			case PIPE_ISOCHRONOUS:
+				usb_release_bandwidth (urb->dev, urb, 1);
+				break;
+			default:
+				break;
+			}
+		}
+
+		urb_free_priv ((struct ohci *)urb->dev->bus->hcpriv, urb_priv);
+		usb_dec_dev_use (urb->dev);
+		urb->dev = NULL;
+	}
+}
+
+static void urb_rm_priv (struct urb * urb)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave (&usb_ed_lock, flags);
+	urb_rm_priv_locked (urb);
+	spin_unlock_irqrestore (&usb_ed_lock, flags);
+}
+
+/*-------------------------------------------------------------------------*/
+ 
+#ifdef DEBUG
+static int sohci_get_current_frame_number (struct usb_device * dev);
+
+/* debug| print the main components of an URB     
+ * small: 0) header + data packets 1) just header */
+ 
+static void urb_print (struct urb * urb, char * str, int small)
+{
+	unsigned int pipe= urb->pipe;
+	
+	if (!urb->dev || !urb->dev->bus) {
+		dbg("%s URB: no dev", str);
+		return;
+	}
+	
+#ifndef	OHCI_VERBOSE_DEBUG
+	if (urb->status != 0)
+#endif
+	dbg("%s URB:[%4x] dev:%2d,ep:%2d-%c,type:%s,flags:%4x,len:%d/%d,stat:%d(%x)", 
+			str,
+		 	sohci_get_current_frame_number (urb->dev), 
+		 	usb_pipedevice (pipe),
+		 	usb_pipeendpoint (pipe), 
+		 	usb_pipeout (pipe)? 'O': 'I',
+		 	usb_pipetype (pipe) < 2? (usb_pipeint (pipe)? "INTR": "ISOC"):
+		 		(usb_pipecontrol (pipe)? "CTRL": "BULK"),
+		 	urb->transfer_flags, 
+		 	urb->actual_length, 
+		 	urb->transfer_buffer_length,
+		 	urb->status, urb->status);
+#ifdef	OHCI_VERBOSE_DEBUG
+	if (!small) {
+		int i, len;
+
+		if (usb_pipecontrol (pipe)) {
+			printk (KERN_DEBUG __FILE__ ": cmd(8):");
+			for (i = 0; i < 8 ; i++) 
+				printk (" %02x", ((__u8 *) urb->setup_packet) [i]);
+			printk ("\n");
+		}
+		if (urb->transfer_buffer_length > 0 && urb->transfer_buffer) {
+			printk (KERN_DEBUG __FILE__ ": data(%d/%d):", 
+				urb->actual_length, 
+				urb->transfer_buffer_length);
+			len = usb_pipeout (pipe)? 
+						urb->transfer_buffer_length: urb->actual_length;
+			for (i = 0; i < 16 && i < len; i++) 
+				printk (" %02x", ((__u8 *) urb->transfer_buffer) [i]);
+			printk ("%s stat:%d\n", i < len? "...": "", urb->status);
+		}
+	} 
+#endif
+}
+
+/* just for debugging; prints non-empty branches of the int ed tree inclusive iso eds*/
+void ep_print_int_eds (ohci_t * ohci, char * str) {
+	int i, j;
+	 __u32 * ed_p;
+	for (i= 0; i < 32; i++) {
+		j = 5;
+		ed_p = &(ohci->hcca->int_table [i]);
+		if (*ed_p == 0)
+		    continue;
+		printk (KERN_DEBUG __FILE__ ": %s branch int %2d(%2x):", str, i, i);
+		while (*ed_p != 0 && j--) {
+			ed_t *ed = dma_to_ed (ohci, le32_to_cpup(ed_p));
+			printk (" ed: %4x;", ed->hwINFO);
+			ed_p = &ed->hwNextED;
+		}
+		printk ("\n");
+	}
+}
+
+
+static void ohci_dump_intr_mask (char *label, __u32 mask)
+{
+	dbg ("%s: 0x%08x%s%s%s%s%s%s%s%s%s",
+		label,
+		mask,
+		(mask & OHCI_INTR_MIE) ? " MIE" : "",
+		(mask & OHCI_INTR_OC) ? " OC" : "",
+		(mask & OHCI_INTR_RHSC) ? " RHSC" : "",
+		(mask & OHCI_INTR_FNO) ? " FNO" : "",
+		(mask & OHCI_INTR_UE) ? " UE" : "",
+		(mask & OHCI_INTR_RD) ? " RD" : "",
+		(mask & OHCI_INTR_SF) ? " SF" : "",
+		(mask & OHCI_INTR_WDH) ? " WDH" : "",
+		(mask & OHCI_INTR_SO) ? " SO" : ""
+		);
+}
+
+static void maybe_print_eds (char *label, __u32 value)
+{
+	if (value)
+		dbg ("%s %08x", label, value);
+}
+
+static char *hcfs2string (int state)
+{
+	switch (state) {
+		case OHCI_USB_RESET:	return "reset";
+		case OHCI_USB_RESUME:	return "resume";
+		case OHCI_USB_OPER:	return "operational";
+		case OHCI_USB_SUSPEND:	return "suspend";
+	}
+	return "?";
+}
+
+// dump control and status registers
+static void ohci_dump_status (ohci_t *controller)
+{
+	struct ohci_regs	*regs = controller->regs;
+	__u32			temp;
+
+	temp = readl (&regs->revision) & 0xff;
+	if (temp != 0x10)
+		dbg ("spec %d.%d", (temp >> 4), (temp & 0x0f));
+
+	temp = readl (&regs->control);
+	dbg ("control: 0x%08x%s%s%s HCFS=%s%s%s%s%s CBSR=%d", temp,
+		(temp & OHCI_CTRL_RWE) ? " RWE" : "",
+		(temp & OHCI_CTRL_RWC) ? " RWC" : "",
+		(temp & OHCI_CTRL_IR) ? " IR" : "",
+		hcfs2string (temp & OHCI_CTRL_HCFS),
+		(temp & OHCI_CTRL_BLE) ? " BLE" : "",
+		(temp & OHCI_CTRL_CLE) ? " CLE" : "",
+		(temp & OHCI_CTRL_IE) ? " IE" : "",
+		(temp & OHCI_CTRL_PLE) ? " PLE" : "",
+		temp & OHCI_CTRL_CBSR
+		);
+
+	temp = readl (&regs->cmdstatus);
+	dbg ("cmdstatus: 0x%08x SOC=%d%s%s%s%s", temp,
+		(temp & OHCI_SOC) >> 16,
+		(temp & OHCI_OCR) ? " OCR" : "",
+		(temp & OHCI_BLF) ? " BLF" : "",
+		(temp & OHCI_CLF) ? " CLF" : "",
+		(temp & OHCI_HCR) ? " HCR" : ""
+		);
+
+	ohci_dump_intr_mask ("intrstatus", readl (&regs->intrstatus));
+	ohci_dump_intr_mask ("intrenable", readl (&regs->intrenable));
+	// intrdisable always same as intrenable
+	// ohci_dump_intr_mask ("intrdisable", readl (&regs->intrdisable));
+
+	maybe_print_eds ("ed_periodcurrent", readl (&regs->ed_periodcurrent));
+
+	maybe_print_eds ("ed_controlhead", readl (&regs->ed_controlhead));
+	maybe_print_eds ("ed_controlcurrent", readl (&regs->ed_controlcurrent));
+
+	maybe_print_eds ("ed_bulkhead", readl (&regs->ed_bulkhead));
+	maybe_print_eds ("ed_bulkcurrent", readl (&regs->ed_bulkcurrent));
+
+	maybe_print_eds ("donehead", readl (&regs->donehead));
+}
+
+static void ohci_dump_roothub (ohci_t *controller, int verbose)
+{
+	__u32			temp, ndp, i;
+
+	temp = roothub_a (controller);
+	if (temp == ~(u32)0)
+		return;
+	ndp = (temp & RH_A_NDP);
+
+	if (verbose) {
+		dbg ("roothub.a: %08x POTPGT=%d%s%s%s%s%s NDP=%d", temp,
+			((temp & RH_A_POTPGT) >> 24) & 0xff,
+			(temp & RH_A_NOCP) ? " NOCP" : "",
+			(temp & RH_A_OCPM) ? " OCPM" : "",
+			(temp & RH_A_DT) ? " DT" : "",
+			(temp & RH_A_NPS) ? " NPS" : "",
+			(temp & RH_A_PSM) ? " PSM" : "",
+			ndp
+			);
+		temp = roothub_b (controller);
+		dbg ("roothub.b: %08x PPCM=%04x DR=%04x",
+			temp,
+			(temp & RH_B_PPCM) >> 16,
+			(temp & RH_B_DR)
+			);
+		temp = roothub_status (controller);
+		dbg ("roothub.status: %08x%s%s%s%s%s%s",
+			temp,
+			(temp & RH_HS_CRWE) ? " CRWE" : "",
+			(temp & RH_HS_OCIC) ? " OCIC" : "",
+			(temp & RH_HS_LPSC) ? " LPSC" : "",
+			(temp & RH_HS_DRWE) ? " DRWE" : "",
+			(temp & RH_HS_OCI) ? " OCI" : "",
+			(temp & RH_HS_LPS) ? " LPS" : ""
+			);
+	}
+	
+	for (i = 0; i < ndp; i++) {
+		temp = roothub_portstatus (controller, i);
+		dbg ("roothub.portstatus [%d] = 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s",
+			i,
+			temp,
+			(temp & RH_PS_PRSC) ? " PRSC" : "",
+			(temp & RH_PS_OCIC) ? " OCIC" : "",
+			(temp & RH_PS_PSSC) ? " PSSC" : "",
+			(temp & RH_PS_PESC) ? " PESC" : "",
+			(temp & RH_PS_CSC) ? " CSC" : "",
+
+			(temp & RH_PS_LSDA) ? " LSDA" : "",
+			(temp & RH_PS_PPS) ? " PPS" : "",
+			(temp & RH_PS_PRS) ? " PRS" : "",
+			(temp & RH_PS_POCI) ? " POCI" : "",
+			(temp & RH_PS_PSS) ? " PSS" : "",
+
+			(temp & RH_PS_PES) ? " PES" : "",
+			(temp & RH_PS_CCS) ? " CCS" : ""
+			);
+	}
+}
+
+static void ohci_dump (ohci_t *controller, int verbose)
+{
+	dbg ("OHCI controller usb-%s state", controller->ohci_dev->slot_name);
+
+	// dumps some of the state we know about
+	ohci_dump_status (controller);
+	if (verbose)
+		ep_print_int_eds (controller, "hcca");
+	dbg ("hcca frame #%04x", controller->hcca->frame_no);
+	ohci_dump_roothub (controller, 1);
+}
+
+
+#endif
+
+/*-------------------------------------------------------------------------*
+ * Interface functions (URB)
+ *-------------------------------------------------------------------------*/
+
+/* return a request to the completion handler */
+ 
+static int sohci_return_urb (struct ohci *hc, struct urb * urb)
+{
+	urb_priv_t * urb_priv = urb->hcpriv;
+	struct urb * urbt;
+	unsigned long flags;
+	int i;
+	
+	if (!urb_priv)
+		return -1; /* urb already unlinked */
+
+	/* just to be sure */
+	if (!urb->complete) {
+		urb_rm_priv (urb);
+		return -1;
+	}
+	
+#ifdef DEBUG
+	urb_print (urb, "RET", usb_pipeout (urb->pipe));
+#endif
+
+	switch (usb_pipetype (urb->pipe)) {
+  		case PIPE_INTERRUPT:
+			pci_unmap_single (hc->ohci_dev,
+				urb_priv->td [0]->data_dma,
+				urb->transfer_buffer_length,
+				usb_pipeout (urb->pipe)
+					? PCI_DMA_TODEVICE
+					: PCI_DMA_FROMDEVICE);
+			urb->complete (urb);
+
+			/* implicitly requeued */
+  			urb->actual_length = 0;
+			urb->status = -EINPROGRESS;
+			td_submit_urb (urb);
+  			break;
+  			
+		case PIPE_ISOCHRONOUS:
+			for (urbt = urb->next; urbt && (urbt != urb); urbt = urbt->next);
+			if (urbt) { /* send the reply and requeue URB */	
+				pci_unmap_single (hc->ohci_dev,
+					urb_priv->td [0]->data_dma,
+					urb->transfer_buffer_length,
+					usb_pipeout (urb->pipe)
+						? PCI_DMA_TODEVICE
+						: PCI_DMA_FROMDEVICE);
+				urb->complete (urb);
+				spin_lock_irqsave (&usb_ed_lock, flags);
+				urb->actual_length = 0;
+  				urb->status = USB_ST_URB_PENDING;
+  				urb->start_frame = urb_priv->ed->last_iso + 1;
+  				if (urb_priv->state != URB_DEL) {
+  					for (i = 0; i < urb->number_of_packets; i++) {
+  						urb->iso_frame_desc[i].actual_length = 0;
+  						urb->iso_frame_desc[i].status = -EXDEV;
+  					}
+  					td_submit_urb (urb);
+  				}
+  				spin_unlock_irqrestore (&usb_ed_lock, flags);
+  				
+  			} else { /* unlink URB, call complete */
+				urb_rm_priv (urb);
+				urb->complete (urb); 	
+			}		
+			break;
+  				
+		case PIPE_BULK:
+		case PIPE_CONTROL: /* unlink URB, call complete */
+			urb_rm_priv (urb);
+			urb->complete (urb);	
+			break;
+	}
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* get a transfer request */
+ 
+static int sohci_submit_urb (struct urb * urb)
+{
+	ohci_t * ohci;
+	ed_t * ed;
+	urb_priv_t * urb_priv;
+	unsigned int pipe = urb->pipe;
+	int maxps = usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe));
+	int i, size = 0;
+	unsigned long flags;
+	int bustime = 0;
+	int mem_flags = ALLOC_FLAGS;
+	
+	if (!urb->dev || !urb->dev->bus)
+		return -ENODEV;
+	
+	if (urb->hcpriv)			/* urb already in use */
+		return -EINVAL;
+
+//	if(usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe))) 
+//		return -EPIPE;
+	
+	usb_inc_dev_use (urb->dev);
+	ohci = (ohci_t *) urb->dev->bus->hcpriv;
+	
+#ifdef DEBUG
+	urb_print (urb, "SUB", usb_pipein (pipe));
+#endif
+	
+	/* handle a request to the virtual root hub */
+	if (usb_pipedevice (pipe) == ohci->rh.devnum) 
+		return rh_submit_urb (urb);
+	
+	/* when controller's hung, permit only roothub cleanup attempts
+	 * such as powering down ports */
+	if (ohci->disabled) {
+		usb_dec_dev_use (urb->dev);	
+		return -ESHUTDOWN;
+	}
+
+	/* every endpoint has a ed, locate and fill it */
+	if (!(ed = ep_add_ed (urb->dev, pipe, urb->interval, 1, mem_flags))) {
+		usb_dec_dev_use (urb->dev);	
+		return -ENOMEM;
+	}
+
+	/* for the private part of the URB we need the number of TDs (size) */
+	switch (usb_pipetype (pipe)) {
+		case PIPE_BULK:	/* one TD for every 4096 Byte */
+			size = (urb->transfer_buffer_length - 1) / 4096 + 1;
+
+			/* If the transfer size is multiple of the pipe mtu,
+			 * we may need an extra TD to create a empty frame
+			 * Jean II */
+			if ((urb->transfer_flags & USB_ZERO_PACKET) &&
+			    usb_pipeout (pipe) &&
+			    (urb->transfer_buffer_length != 0) && 
+			    ((urb->transfer_buffer_length % maxps) == 0))
+				size++;
+			break;
+		case PIPE_ISOCHRONOUS: /* number of packets from URB */
+			size = urb->number_of_packets;
+			if (size <= 0) {
+				usb_dec_dev_use (urb->dev);	
+				return -EINVAL;
+			}
+			for (i = 0; i < urb->number_of_packets; i++) {
+  				urb->iso_frame_desc[i].actual_length = 0;
+  				urb->iso_frame_desc[i].status = -EXDEV;
+  			}
+			break;
+		case PIPE_CONTROL: /* 1 TD for setup, 1 for ACK and 1 for every 4096 B */
+			size = (urb->transfer_buffer_length == 0)? 2: 
+						(urb->transfer_buffer_length - 1) / 4096 + 3;
+			break;
+		case PIPE_INTERRUPT: /* one TD */
+			size = 1;
+			break;
+	}
+
+	/* allocate the private part of the URB */
+	urb_priv = kmalloc (sizeof (urb_priv_t) + size * sizeof (td_t *), 
+							in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+	if (!urb_priv) {
+		usb_dec_dev_use (urb->dev);	
+		return -ENOMEM;
+	}
+	memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (td_t *));
+	
+	/* fill the private part of the URB */
+	urb_priv->length = size;
+	urb_priv->ed = ed;	
+
+	/* allocate the TDs (updating hash chains) */
+	spin_lock_irqsave (&usb_ed_lock, flags);
+	for (i = 0; i < size; i++) { 
+		urb_priv->td[i] = td_alloc (ohci, SLAB_ATOMIC);
+		if (!urb_priv->td[i]) {
+			urb_priv->length = i;
+			urb_free_priv (ohci, urb_priv);
+			spin_unlock_irqrestore (&usb_ed_lock, flags);
+			usb_dec_dev_use (urb->dev);	
+			return -ENOMEM;
+		}
+	}	
+
+	if (ed->state == ED_NEW || (ed->state & ED_DEL)) {
+		urb_free_priv (ohci, urb_priv);
+		spin_unlock_irqrestore (&usb_ed_lock, flags);
+		usb_dec_dev_use (urb->dev);	
+		return -EINVAL;
+	}
+	
+	/* allocate and claim bandwidth if needed; ISO
+	 * needs start frame index if it was't provided.
+	 */
+	switch (usb_pipetype (pipe)) {
+		case PIPE_ISOCHRONOUS:
+			if (urb->transfer_flags & USB_ISO_ASAP) { 
+				urb->start_frame = ((ed->state == ED_OPER)
+					? (ed->last_iso + 1)
+					: (le16_to_cpu (ohci->hcca->frame_no) + 10)) & 0xffff;
+			}	
+			/* FALLTHROUGH */
+		case PIPE_INTERRUPT:
+			if (urb->bandwidth == 0) {
+				bustime = usb_check_bandwidth (urb->dev, urb);
+			}
+			if (bustime < 0) {
+				urb_free_priv (ohci, urb_priv);
+				spin_unlock_irqrestore (&usb_ed_lock, flags);
+				usb_dec_dev_use (urb->dev);	
+				return bustime;
+			}
+			usb_claim_bandwidth (urb->dev, urb, bustime, usb_pipeisoc (urb->pipe));
+#ifdef	DO_TIMEOUTS
+			urb->timeout = 0;
+#endif
+	}
+
+	urb->actual_length = 0;
+	urb->hcpriv = urb_priv;
+	urb->status = USB_ST_URB_PENDING;
+
+	/* link the ed into a chain if is not already */
+	if (ed->state != ED_OPER)
+		ep_link (ohci, ed);
+
+	/* fill the TDs and link it to the ed */
+	td_submit_urb (urb);
+
+#ifdef	DO_TIMEOUTS
+	/* maybe add to ordered list of timeouts */
+	if (urb->timeout) {
+		struct list_head	*entry;
+
+		urb->timeout += jiffies;
+
+		list_for_each (entry, &ohci->timeout_list) {
+			struct urb	*next_urb;
+
+			next_urb = list_entry (entry, struct urb, urb_list);
+			if (time_after_eq (urb->timeout, next_urb->timeout))
+				break;
+		}
+		list_add (&urb->urb_list, entry);
+
+		/* drive timeouts by SF (messy, but works) */
+		writel (OHCI_INTR_SF, &ohci->regs->intrenable);	
+	}
+#endif
+
+	spin_unlock_irqrestore (&usb_ed_lock, flags);
+
+	return 0;	
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* deactivate all TDs and remove the private part of the URB */
+/* interrupt callers must use async unlink mode */
+
+static int sohci_unlink_urb (struct urb * urb)
+{
+	unsigned long flags;
+	ohci_t * ohci;
+	
+	if (!urb) /* just to be sure */ 
+		return -EINVAL;
+		
+	if (!urb->dev || !urb->dev->bus)
+		return -ENODEV;
+
+	ohci = (ohci_t *) urb->dev->bus->hcpriv; 
+
+#ifdef DEBUG
+	urb_print (urb, "UNLINK", 1);
+#endif		  
+
+	/* handle a request to the virtual root hub */
+	if (usb_pipedevice (urb->pipe) == ohci->rh.devnum)
+		return rh_unlink_urb (urb);
+
+	if (urb->hcpriv && (urb->status == USB_ST_URB_PENDING)) { 
+		if (!ohci->disabled) {
+			urb_priv_t  * urb_priv;
+
+			/* interrupt code may not sleep; it must use
+			 * async status return to unlink pending urbs.
+			 */
+			if (!(urb->transfer_flags & USB_ASYNC_UNLINK)
+					&& in_interrupt ()) {
+				err ("bug in call from %p; use async!",
+					__builtin_return_address(0));
+				return -EWOULDBLOCK;
+			}
+
+			/* flag the urb and its TDs for deletion in some
+			 * upcoming SF interrupt delete list processing
+			 */
+			spin_lock_irqsave (&usb_ed_lock, flags);
+			urb_priv = urb->hcpriv;
+
+			if (!urb_priv || (urb_priv->state == URB_DEL)) {
+				spin_unlock_irqrestore (&usb_ed_lock, flags);
+				return 0;
+			}
+				
+			urb_priv->state = URB_DEL; 
+			ep_rm_ed (urb->dev, urb_priv->ed);
+			urb_priv->ed->state |= ED_URB_DEL;
+
+			if (!(urb->transfer_flags & USB_ASYNC_UNLINK)) {
+				DECLARE_WAIT_QUEUE_HEAD (unlink_wakeup); 
+				DECLARE_WAITQUEUE (wait, current);
+				int timeout = OHCI_UNLINK_TIMEOUT;
+
+				add_wait_queue (&unlink_wakeup, &wait);
+				urb_priv->wait = &unlink_wakeup;
+				spin_unlock_irqrestore (&usb_ed_lock, flags);
+
+				/* wait until all TDs are deleted */
+				set_current_state(TASK_UNINTERRUPTIBLE);
+				while (timeout && (urb->status == USB_ST_URB_PENDING))
+					timeout = schedule_timeout (timeout);
+				set_current_state(TASK_RUNNING);
+				remove_wait_queue (&unlink_wakeup, &wait); 
+				if (urb->status == USB_ST_URB_PENDING) {
+					err ("unlink URB timeout");
+					return -ETIMEDOUT;
+				}
+			} else {
+				/* usb_dec_dev_use done in dl_del_list() */
+				urb->status = -EINPROGRESS;
+				spin_unlock_irqrestore (&usb_ed_lock, flags);
+				return -EINPROGRESS;
+			}
+		} else {
+			urb_rm_priv (urb);
+			if (urb->transfer_flags & USB_ASYNC_UNLINK) {
+				urb->status = -ECONNRESET;
+				if (urb->complete)
+					urb->complete (urb); 
+			} else 
+				urb->status = -ENOENT;
+		}	
+	}	
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* allocate private data space for a usb device */
+
+static int sohci_alloc_dev (struct usb_device *usb_dev)
+{
+	struct ohci_device * dev;
+
+	dev = dev_alloc ((struct ohci *) usb_dev->bus->hcpriv, ALLOC_FLAGS);
+	if (!dev)
+		return -ENOMEM;
+
+	usb_dev->hcpriv = dev;
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* may be called from interrupt context */
+/* frees private data space of usb device */
+  
+static int sohci_free_dev (struct usb_device * usb_dev)
+{
+	unsigned long flags;
+	int i, cnt = 0;
+	ed_t * ed;
+	struct ohci_device * dev = usb_to_ohci (usb_dev);
+	ohci_t * ohci = usb_dev->bus->hcpriv;
+	
+	if (!dev)
+		return 0;
+	
+	if (usb_dev->devnum >= 0) {
+	
+		/* driver disconnects should have unlinked all urbs
+		 * (freeing all the TDs, unlinking EDs) but we need
+		 * to defend against bugs that prevent that.
+		 */
+		spin_lock_irqsave (&usb_ed_lock, flags);	
+		for(i = 0; i < NUM_EDS; i++) {
+  			ed = &(dev->ed[i]);
+  			if (ed->state != ED_NEW) {
+  				if (ed->state == ED_OPER) {
+					/* driver on that interface didn't unlink an urb */
+					dbg ("driver usb-%s dev %d ed 0x%x unfreed URB",
+						ohci->ohci_dev->slot_name, usb_dev->devnum, i);
+					ep_unlink (ohci, ed);
+				}
+  				ep_rm_ed (usb_dev, ed);
+  				ed->state = ED_DEL;
+  				cnt++;
+  			}
+  		}
+  		spin_unlock_irqrestore (&usb_ed_lock, flags);
+  		
+		/* if the controller is running, tds for those unlinked
+		 * urbs get freed by dl_del_list at the next SF interrupt
+		 */
+		if (cnt > 0) {
+
+			if (ohci->disabled) {
+				/* FIXME: Something like this should kick in,
+				 * though it's currently an exotic case ...
+				 * the controller won't ever be touching
+				 * these lists again!!
+				dl_del_list (ohci,
+					le16_to_cpu (ohci->hcca->frame_no) & 1);
+				 */
+				warn ("TD leak, %d", cnt);
+
+			} else if (!in_interrupt ()) {
+				DECLARE_WAIT_QUEUE_HEAD (freedev_wakeup); 
+				DECLARE_WAITQUEUE (wait, current);
+				int timeout = OHCI_UNLINK_TIMEOUT;
+
+				/* SF interrupt handler calls dl_del_list */
+				add_wait_queue (&freedev_wakeup, &wait);
+				dev->wait = &freedev_wakeup;
+				set_current_state(TASK_UNINTERRUPTIBLE);
+				while (timeout && dev->ed_cnt)
+					timeout = schedule_timeout (timeout);
+				set_current_state(TASK_RUNNING);
+				remove_wait_queue (&freedev_wakeup, &wait);
+				if (dev->ed_cnt) {
+					err ("free device %d timeout", usb_dev->devnum);
+					return -ETIMEDOUT;
+				}
+			} else {
+				/* likely some interface's driver has a refcount bug */
+				err ("bus %s devnum %d deletion in interrupt",
+					ohci->ohci_dev->slot_name, usb_dev->devnum);
+				BUG ();
+			}
+		}
+	}
+
+	/* free device, and associated EDs */
+	dev_free (ohci, dev);
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* tell us the current USB frame number */
+
+static int sohci_get_current_frame_number (struct usb_device *usb_dev) 
+{
+	ohci_t * ohci = usb_dev->bus->hcpriv;
+	
+	return le16_to_cpu (ohci->hcca->frame_no);
+}
+
+/*-------------------------------------------------------------------------*/
+
+struct usb_operations sohci_device_operations = {
+	sohci_alloc_dev,
+	sohci_free_dev,
+	sohci_get_current_frame_number,
+	sohci_submit_urb,
+	sohci_unlink_urb
+};
+
+/*-------------------------------------------------------------------------*
+ * ED handling functions
+ *-------------------------------------------------------------------------*/  
+		
+/* search for the right branch to insert an interrupt ed into the int tree 
+ * do some load ballancing;
+ * returns the branch and 
+ * sets the interval to interval = 2^integer (ld (interval)) */
+
+static int ep_int_ballance (ohci_t * ohci, int interval, int load)
+{
+	int i, branch = 0;
+   
+	/* search for the least loaded interrupt endpoint branch of all 32 branches */
+	for (i = 0; i < 32; i++) 
+		if (ohci->ohci_int_load [branch] > ohci->ohci_int_load [i]) branch = i; 
+  
+	branch = branch % interval;
+	for (i = branch; i < 32; i += interval) ohci->ohci_int_load [i] += load;
+
+	return branch;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*  2^int( ld (inter)) */
+
+static int ep_2_n_interval (int inter)
+{	
+	int i;
+	for (i = 0; ((inter >> i) > 1 ) && (i < 5); i++); 
+	return 1 << i;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* the int tree is a binary tree 
+ * in order to process it sequentially the indexes of the branches have to be mapped 
+ * the mapping reverses the bits of a word of num_bits length */
+ 
+static int ep_rev (int num_bits, int word)
+{
+	int i, wout = 0;
+
+	for (i = 0; i < num_bits; i++) wout |= (((word >> i) & 1) << (num_bits - i - 1));
+	return wout;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* link an ed into one of the HC chains */
+
+static int ep_link (ohci_t * ohci, ed_t * edi)
+{	 
+	int int_branch;
+	int i;
+	int inter;
+	int interval;
+	int load;
+	__u32 * ed_p;
+	volatile ed_t * ed = edi;
+	
+	ed->state = ED_OPER;
+	
+	switch (ed->type) {
+	case PIPE_CONTROL:
+		ed->hwNextED = 0;
+		if (ohci->ed_controltail == NULL) {
+			writel (ed->dma, &ohci->regs->ed_controlhead);
+		} else {
+			ohci->ed_controltail->hwNextED = cpu_to_le32 (ed->dma);
+		}
+		ed->ed_prev = ohci->ed_controltail;
+		if (!ohci->ed_controltail && !ohci->ed_rm_list[0] &&
+			!ohci->ed_rm_list[1] && !ohci->sleeping) {
+			ohci->hc_control |= OHCI_CTRL_CLE;
+			writel (ohci->hc_control, &ohci->regs->control);
+		}
+		ohci->ed_controltail = edi;	  
+		break;
+		
+	case PIPE_BULK:
+		ed->hwNextED = 0;
+		if (ohci->ed_bulktail == NULL) {
+			writel (ed->dma, &ohci->regs->ed_bulkhead);
+		} else {
+			ohci->ed_bulktail->hwNextED = cpu_to_le32 (ed->dma);
+		}
+		ed->ed_prev = ohci->ed_bulktail;
+		if (!ohci->ed_bulktail && !ohci->ed_rm_list[0] &&
+			!ohci->ed_rm_list[1] && !ohci->sleeping) {
+			ohci->hc_control |= OHCI_CTRL_BLE;
+			writel (ohci->hc_control, &ohci->regs->control);
+		}
+		ohci->ed_bulktail = edi;	  
+		break;
+		
+	case PIPE_INTERRUPT:
+		load = ed->int_load;
+		interval = ep_2_n_interval (ed->int_period);
+		ed->int_interval = interval;
+		int_branch = ep_int_ballance (ohci, interval, load);
+		ed->int_branch = int_branch;
+		
+		for (i = 0; i < ep_rev (6, interval); i += inter) {
+			inter = 1;
+			for (ed_p = &(ohci->hcca->int_table[ep_rev (5, i) + int_branch]); 
+				(*ed_p != 0) && ((dma_to_ed (ohci, le32_to_cpup (ed_p)))->int_interval >= interval); 
+				ed_p = &((dma_to_ed (ohci, le32_to_cpup (ed_p)))->hwNextED)) 
+					inter = ep_rev (6, (dma_to_ed (ohci, le32_to_cpup (ed_p)))->int_interval);
+			ed->hwNextED = *ed_p; 
+			*ed_p = cpu_to_le32 (ed->dma);
+		}
+#ifdef DEBUG
+		ep_print_int_eds (ohci, "LINK_INT");
+#endif
+		break;
+		
+	case PIPE_ISOCHRONOUS:
+		ed->hwNextED = 0;
+		ed->int_interval = 1;
+		if (ohci->ed_isotail != NULL) {
+			ohci->ed_isotail->hwNextED = cpu_to_le32 (ed->dma);
+			ed->ed_prev = ohci->ed_isotail;
+		} else {
+			for ( i = 0; i < 32; i += inter) {
+				inter = 1;
+				for (ed_p = &(ohci->hcca->int_table[ep_rev (5, i)]); 
+					*ed_p != 0; 
+					ed_p = &((dma_to_ed (ohci, le32_to_cpup (ed_p)))->hwNextED)) 
+						inter = ep_rev (6, (dma_to_ed (ohci, le32_to_cpup (ed_p)))->int_interval);
+				*ed_p = cpu_to_le32 (ed->dma);	
+			}	
+			ed->ed_prev = NULL;
+		}	
+		ohci->ed_isotail = edi;  
+#ifdef DEBUG
+		ep_print_int_eds (ohci, "LINK_ISO");
+#endif
+		break;
+	}	 	
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* scan the periodic table to find and unlink this ED */
+static void periodic_unlink (
+	struct ohci	*ohci,
+	struct ed	*ed,
+	unsigned	index,
+	unsigned	period
+) {
+	for (; index < NUM_INTS; index += period) {
+		__u32	*ed_p = &ohci->hcca->int_table [index];
+
+		/* ED might have been unlinked through another path */
+		while (*ed_p != 0) {
+			if ((dma_to_ed (ohci, le32_to_cpup (ed_p))) == ed) {
+				*ed_p = ed->hwNextED;		
+				break;
+			}
+			ed_p = & ((dma_to_ed (ohci,
+				le32_to_cpup (ed_p)))->hwNextED);
+		}
+	}	
+}
+
+/* unlink an ed from one of the HC chains. 
+ * just the link to the ed is unlinked.
+ * the link from the ed still points to another operational ed or 0
+ * so the HC can eventually finish the processing of the unlinked ed */
+
+static int ep_unlink (ohci_t * ohci, ed_t * ed) 
+{
+	int i;
+
+	ed->hwINFO |= cpu_to_le32 (OHCI_ED_SKIP);
+
+	switch (ed->type) {
+	case PIPE_CONTROL:
+		if (ed->ed_prev == NULL) {
+			if (!ed->hwNextED) {
+				ohci->hc_control &= ~OHCI_CTRL_CLE;
+				writel (ohci->hc_control, &ohci->regs->control);
+			}
+			writel (le32_to_cpup (&ed->hwNextED), &ohci->regs->ed_controlhead);
+		} else {
+			ed->ed_prev->hwNextED = ed->hwNextED;
+		}
+		if (ohci->ed_controltail == ed) {
+			ohci->ed_controltail = ed->ed_prev;
+		} else {
+			(dma_to_ed (ohci, le32_to_cpup (&ed->hwNextED)))->ed_prev = ed->ed_prev;
+		}
+		break;
+      
+	case PIPE_BULK:
+		if (ed->ed_prev == NULL) {
+			if (!ed->hwNextED) {
+				ohci->hc_control &= ~OHCI_CTRL_BLE;
+				writel (ohci->hc_control, &ohci->regs->control);
+			}
+			writel (le32_to_cpup (&ed->hwNextED), &ohci->regs->ed_bulkhead);
+		} else {
+			ed->ed_prev->hwNextED = ed->hwNextED;
+		}
+		if (ohci->ed_bulktail == ed) {
+			ohci->ed_bulktail = ed->ed_prev;
+		} else {
+			(dma_to_ed (ohci, le32_to_cpup (&ed->hwNextED)))->ed_prev = ed->ed_prev;
+		}
+		break;
+      
+	case PIPE_INTERRUPT:
+		periodic_unlink (ohci, ed, 0, 1);
+		for (i = ed->int_branch; i < 32; i += ed->int_interval)
+		    ohci->ohci_int_load[i] -= ed->int_load;
+#ifdef DEBUG
+		ep_print_int_eds (ohci, "UNLINK_INT");
+#endif
+		break;
+		
+	case PIPE_ISOCHRONOUS:
+		if (ohci->ed_isotail == ed)
+			ohci->ed_isotail = ed->ed_prev;
+		if (ed->hwNextED != 0) 
+		    (dma_to_ed (ohci, le32_to_cpup (&ed->hwNextED)))
+		    	->ed_prev = ed->ed_prev;
+				    
+		if (ed->ed_prev != NULL)
+			ed->ed_prev->hwNextED = ed->hwNextED;
+		else
+			periodic_unlink (ohci, ed, 0, 1);
+#ifdef DEBUG
+		ep_print_int_eds (ohci, "UNLINK_ISO");
+#endif
+		break;
+	}
+	ed->state = ED_UNLINK;
+	return 0;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* add/reinit an endpoint; this should be done once at the usb_set_configuration command,
+ * but the USB stack is a little bit stateless  so we do it at every transaction
+ * if the state of the ed is ED_NEW then a dummy td is added and the state is changed to ED_UNLINK
+ * in all other cases the state is left unchanged
+ * the ed info fields are setted anyway even though most of them should not change */
+ 
+static ed_t * ep_add_ed (
+	struct usb_device * usb_dev,
+	unsigned int pipe,
+	int interval,
+	int load,
+	int mem_flags
+)
+{
+   	ohci_t * ohci = usb_dev->bus->hcpriv;
+	td_t * td;
+	ed_t * ed_ret;
+	volatile ed_t * ed; 
+	unsigned long flags;
+ 	
+ 	
+	spin_lock_irqsave (&usb_ed_lock, flags);
+
+	ed = ed_ret = &(usb_to_ohci (usb_dev)->ed[(usb_pipeendpoint (pipe) << 1) | 
+			(usb_pipecontrol (pipe)? 0: usb_pipeout (pipe))]);
+
+	if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) {
+		/* pending delete request */
+		spin_unlock_irqrestore (&usb_ed_lock, flags);
+		return NULL;
+	}
+	
+	if (ed->state == ED_NEW) {
+		ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP); /* skip ed */
+  		/* dummy td; end of td list for ed */
+		td = td_alloc (ohci, SLAB_ATOMIC);
+		/* hash the ed for later reverse mapping */
+ 		if (!td || !hash_add_ed (ohci, (ed_t *)ed)) {
+			/* out of memory */
+		        if (td)
+		            td_free(ohci, td);
+			spin_unlock_irqrestore (&usb_ed_lock, flags);
+			return NULL;
+		}
+		ed->hwTailP = cpu_to_le32 (td->td_dma);
+		ed->hwHeadP = ed->hwTailP;	
+		ed->state = ED_UNLINK;
+		ed->type = usb_pipetype (pipe);
+		usb_to_ohci (usb_dev)->ed_cnt++;
+	}
+
+	ohci->dev[usb_pipedevice (pipe)] = usb_dev;
+	
+	ed->hwINFO = cpu_to_le32 (usb_pipedevice (pipe)
+			| usb_pipeendpoint (pipe) << 7
+			| (usb_pipeisoc (pipe)? 0x8000: 0)
+			| (usb_pipecontrol (pipe)? 0: (usb_pipeout (pipe)? 0x800: 0x1000)) 
+			| usb_pipeslow (pipe) << 13
+			| usb_maxpacket (usb_dev, pipe, usb_pipeout (pipe)) << 16);
+  
+  	if (ed->type == PIPE_INTERRUPT && ed->state == ED_UNLINK) {
+  		ed->int_period = interval;
+  		ed->int_load = load;
+  	}
+  	
+	spin_unlock_irqrestore (&usb_ed_lock, flags);
+	return ed_ret; 
+}
+
+/*-------------------------------------------------------------------------*/
+ 
+/* request the removal of an endpoint
+ * put the ep on the rm_list and request a stop of the bulk or ctrl list 
+ * real removal is done at the next start frame (SF) hardware interrupt */
+ 
+static void ep_rm_ed (struct usb_device * usb_dev, ed_t * ed)
+{    
+	unsigned int frame;
+	ohci_t * ohci = usb_dev->bus->hcpriv;
+
+	if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL))
+		return;
+	
+	ed->hwINFO |= cpu_to_le32 (OHCI_ED_SKIP);
+
+	if (!ohci->disabled) {
+		switch (ed->type) {
+			case PIPE_CONTROL: /* stop control list */
+				ohci->hc_control &= ~OHCI_CTRL_CLE;
+				writel (ohci->hc_control, &ohci->regs->control); 
+  				break;
+			case PIPE_BULK: /* stop bulk list */
+				ohci->hc_control &= ~OHCI_CTRL_BLE;
+				writel (ohci->hc_control, &ohci->regs->control); 
+				break;
+		}
+	}
+
+	frame = le16_to_cpu (ohci->hcca->frame_no) & 0x1;
+	ed->ed_rm_list = ohci->ed_rm_list[frame];
+	ohci->ed_rm_list[frame] = ed;
+
+	if (!ohci->disabled && !ohci->sleeping) {
+		/* enable SOF interrupt */
+		writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
+		writel (OHCI_INTR_SF, &ohci->regs->intrenable);
+	}
+}
+
+/*-------------------------------------------------------------------------*
+ * TD handling functions
+ *-------------------------------------------------------------------------*/
+
+/* enqueue next TD for this URB (OHCI spec 5.2.8.2) */
+
+static void
+td_fill (ohci_t * ohci, unsigned int info,
+	dma_addr_t data, int len,
+	struct urb * urb, int index)
+{
+	volatile td_t  * td, * td_pt;
+	urb_priv_t * urb_priv = urb->hcpriv;
+	
+	if (index >= urb_priv->length) {
+		err("internal OHCI error: TD index > length");
+		return;
+	}
+	
+	/* use this td as the next dummy */
+	td_pt = urb_priv->td [index];
+	td_pt->hwNextTD = 0;
+
+	/* fill the old dummy TD */
+	td = urb_priv->td [index] = dma_to_td (ohci,
+			le32_to_cpup (&urb_priv->ed->hwTailP) & ~0xf);
+
+	td->ed = urb_priv->ed;
+	td->next_dl_td = NULL;
+	td->index = index;
+	td->urb = urb; 
+	td->data_dma = data;
+	if (!len)
+		data = 0;
+
+	td->hwINFO = cpu_to_le32 (info);
+	if ((td->ed->type) == PIPE_ISOCHRONOUS) {
+		td->hwCBP = cpu_to_le32 (data & 0xFFFFF000);
+		td->ed->last_iso = info & 0xffff;
+	} else {
+		td->hwCBP = cpu_to_le32 (data); 
+	}			
+	if (data)
+		td->hwBE = cpu_to_le32 (data + len - 1);
+	else
+		td->hwBE = 0;
+	td->hwNextTD = cpu_to_le32 (td_pt->td_dma);
+	td->hwPSW [0] = cpu_to_le16 ((data & 0x0FFF) | 0xE000);
+
+	/* append to queue */
+	wmb();
+	td->ed->hwTailP = td->hwNextTD;
+}
+
+/*-------------------------------------------------------------------------*/
+ 
+/* prepare all TDs of a transfer */
+
+static void td_submit_urb (struct urb * urb)
+{ 
+	urb_priv_t * urb_priv = urb->hcpriv;
+	ohci_t * ohci = (ohci_t *) urb->dev->bus->hcpriv;
+	dma_addr_t data;
+	int data_len = urb->transfer_buffer_length;
+	int maxps = usb_maxpacket (urb->dev, urb->pipe, usb_pipeout (urb->pipe));
+	int cnt = 0; 
+	__u32 info = 0;
+  	unsigned int toggle = 0;
+
+	/* OHCI handles the DATA-toggles itself, we just use the USB-toggle bits for reseting */
+  	if(usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe))) {
+  		toggle = TD_T_TOGGLE;
+	} else {
+  		toggle = TD_T_DATA0;
+		usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe), 1);
+	}
+	
+	urb_priv->td_cnt = 0;
+
+	if (data_len) {
+		data = pci_map_single (ohci->ohci_dev,
+			urb->transfer_buffer, data_len,
+			usb_pipeout (urb->pipe)
+				? PCI_DMA_TODEVICE
+				: PCI_DMA_FROMDEVICE
+			);
+	} else
+		data = 0;
+	
+	switch (usb_pipetype (urb->pipe)) {
+		case PIPE_BULK:
+			info = usb_pipeout (urb->pipe)? 
+				TD_CC | TD_DP_OUT : TD_CC | TD_DP_IN ;
+			while(data_len > 4096) {		
+				td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, 4096, urb, cnt);
+				data += 4096; data_len -= 4096; cnt++;
+			}
+			info = usb_pipeout (urb->pipe)?
+				TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ;
+			td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, data_len, urb, cnt);
+			cnt++;
+
+			/* If the transfer size is multiple of the pipe mtu,
+			 * we may need an extra TD to create a empty frame
+			 * Note : another way to check this condition is
+			 * to test if(urb_priv->length > cnt) - Jean II */
+			if ((urb->transfer_flags & USB_ZERO_PACKET) &&
+			    usb_pipeout (urb->pipe) &&
+			    (urb->transfer_buffer_length != 0) && 
+			    ((urb->transfer_buffer_length % maxps) == 0)) {
+				td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), 0, 0, urb, cnt);
+				cnt++;
+			}
+
+			if (!ohci->sleeping) {
+				wmb();
+				writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
+			}
+			break;
+
+		case PIPE_INTERRUPT:
+			info = usb_pipeout (urb->pipe)? 
+				TD_CC | TD_DP_OUT | toggle: TD_CC | TD_R | TD_DP_IN | toggle;
+			td_fill (ohci, info, data, data_len, urb, cnt++);
+			break;
+
+		case PIPE_CONTROL:
+			info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
+			td_fill (ohci, info,
+				pci_map_single (ohci->ohci_dev,
+					urb->setup_packet, 8,
+					PCI_DMA_TODEVICE),
+				8, urb, cnt++); 
+			if (data_len > 0) {  
+				info = usb_pipeout (urb->pipe)? 
+					TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1 : TD_CC | TD_R | TD_DP_IN | TD_T_DATA1;
+				/* NOTE:  mishandles transfers >8K, some >4K */
+				td_fill (ohci, info, data, data_len, urb, cnt++);  
+			} 
+			info = usb_pipeout (urb->pipe)? 
+ 				TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1;
+			td_fill (ohci, info, data, 0, urb, cnt++);
+			if (!ohci->sleeping) {
+				wmb();
+				writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
+			}
+			break;
+
+		case PIPE_ISOCHRONOUS:
+			for (cnt = 0; cnt < urb->number_of_packets; cnt++) {
+				td_fill (ohci, TD_CC|TD_ISO | ((urb->start_frame + cnt) & 0xffff), 
+					data + urb->iso_frame_desc[cnt].offset, 
+					urb->iso_frame_desc[cnt].length, urb, cnt); 
+			}
+			break;
+	} 
+	if (urb_priv->length != cnt) 
+		dbg("TD LENGTH %d != CNT %d", urb_priv->length, cnt);
+}
+
+/*-------------------------------------------------------------------------*
+ * Done List handling functions
+ *-------------------------------------------------------------------------*/
+
+
+/* calculate the transfer length and update the urb */
+
+static void dl_transfer_length(td_t * td)
+{
+	__u32 tdINFO, tdBE, tdCBP;
+ 	__u16 tdPSW;
+ 	struct urb * urb = td->urb;
+ 	urb_priv_t * urb_priv = urb->hcpriv;
+	int dlen = 0;
+	int cc = 0;
+	
+	tdINFO = le32_to_cpup (&td->hwINFO);
+  	tdBE   = le32_to_cpup (&td->hwBE);
+  	tdCBP  = le32_to_cpup (&td->hwCBP);
+
+
+  	if (tdINFO & TD_ISO) {
+ 		tdPSW = le16_to_cpu (td->hwPSW[0]);
+ 		cc = (tdPSW >> 12) & 0xF;
+		if (cc < 0xE)  {
+			if (usb_pipeout(urb->pipe)) {
+				dlen = urb->iso_frame_desc[td->index].length;
+			} else {
+				dlen = tdPSW & 0x3ff;
+			}
+			urb->actual_length += dlen;
+			urb->iso_frame_desc[td->index].actual_length = dlen;
+			if (!(urb->transfer_flags & USB_DISABLE_SPD) && (cc == TD_DATAUNDERRUN))
+				cc = TD_CC_NOERROR;
+					 
+			urb->iso_frame_desc[td->index].status = cc_to_error[cc];
+		}
+	} else { /* BULK, INT, CONTROL DATA */
+		if (!(usb_pipetype (urb->pipe) == PIPE_CONTROL && 
+				((td->index == 0) || (td->index == urb_priv->length - 1)))) {
+ 			if (tdBE != 0) {
+ 				if (td->hwCBP == 0)
+					urb->actual_length += tdBE - td->data_dma + 1;
+  				else
+					urb->actual_length += tdCBP - td->data_dma;
+			}
+  		}
+  	}
+}
+
+/* handle an urb that is being unlinked */
+
+static void dl_del_urb (struct urb * urb)
+{
+	wait_queue_head_t * wait_head = ((urb_priv_t *)(urb->hcpriv))->wait;
+
+	urb_rm_priv_locked (urb);
+
+	if (urb->transfer_flags & USB_ASYNC_UNLINK) {
+		urb->status = -ECONNRESET;
+		if (urb->complete)
+			urb->complete (urb);
+	} else {
+		urb->status = -ENOENT;
+		if (urb->complete)
+			urb->complete (urb);
+
+		/* unblock sohci_unlink_urb */
+		if (wait_head)
+			wake_up (wait_head);
+	}
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* replies to the request have to be on a FIFO basis so
+ * we reverse the reversed done-list */
+ 
+static td_t * dl_reverse_done_list (ohci_t * ohci)
+{
+	__u32 td_list_hc;
+	td_t * td_rev = NULL;
+	td_t * td_list = NULL;
+  	urb_priv_t * urb_priv = NULL;
+  	unsigned long flags;
+  	
+  	spin_lock_irqsave (&usb_ed_lock, flags);
+  	
+	td_list_hc = le32_to_cpup (&ohci->hcca->done_head) & 0xfffffff0;
+	ohci->hcca->done_head = 0;
+	
+	while (td_list_hc) {		
+		td_list = dma_to_td (ohci, td_list_hc);
+
+		if (TD_CC_GET (le32_to_cpup (&td_list->hwINFO))) {
+			urb_priv = (urb_priv_t *) td_list->urb->hcpriv;
+			dbg(" USB-error/status: %x : %p", 
+					TD_CC_GET (le32_to_cpup (&td_list->hwINFO)), td_list);
+			if (td_list->ed->hwHeadP & cpu_to_le32 (0x1)) {
+				if (urb_priv && ((td_list->index + 1) < urb_priv->length)) {
+					td_list->ed->hwHeadP = 
+						(urb_priv->td[urb_priv->length - 1]->hwNextTD & cpu_to_le32 (0xfffffff0)) |
+									(td_list->ed->hwHeadP & cpu_to_le32 (0x2));
+					urb_priv->td_cnt += urb_priv->length - td_list->index - 1;
+				} else 
+					td_list->ed->hwHeadP &= cpu_to_le32 (0xfffffff2);
+			}
+		}
+
+		td_list->next_dl_td = td_rev;	
+		td_rev = td_list;
+		td_list_hc = le32_to_cpup (&td_list->hwNextTD) & 0xfffffff0;	
+	}	
+	spin_unlock_irqrestore (&usb_ed_lock, flags);
+	return td_list;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* there are some pending requests to remove 
+ * - some of the eds (if ed->state & ED_DEL (set by sohci_free_dev)
+ * - some URBs/TDs if urb_priv->state == URB_DEL */
+ 
+static void dl_del_list (ohci_t  * ohci, unsigned int frame)
+{
+	unsigned long flags;
+	ed_t * ed;
+	__u32 edINFO;
+	__u32 tdINFO;
+	td_t * td = NULL, * td_next = NULL, * tdHeadP = NULL, * tdTailP;
+	__u32 * td_p;
+	int ctrl = 0, bulk = 0;
+
+	spin_lock_irqsave (&usb_ed_lock, flags);
+
+	for (ed = ohci->ed_rm_list[frame]; ed != NULL; ed = ed->ed_rm_list) {
+
+		tdTailP = dma_to_td (ohci, le32_to_cpup (&ed->hwTailP) & 0xfffffff0);
+		tdHeadP = dma_to_td (ohci, le32_to_cpup (&ed->hwHeadP) & 0xfffffff0);
+		edINFO = le32_to_cpup (&ed->hwINFO);
+		td_p = &ed->hwHeadP;
+
+		for (td = tdHeadP; td != tdTailP; td = td_next) { 
+			struct urb * urb = td->urb;
+			urb_priv_t * urb_priv = td->urb->hcpriv;
+			
+			td_next = dma_to_td (ohci, le32_to_cpup (&td->hwNextTD) & 0xfffffff0);
+			if ((urb_priv->state == URB_DEL) || (ed->state & ED_DEL)) {
+				tdINFO = le32_to_cpup (&td->hwINFO);
+				if (TD_CC_GET (tdINFO) < 0xE)
+					dl_transfer_length (td);
+				*td_p = td->hwNextTD | (*td_p & cpu_to_le32 (0x3));
+
+				/* URB is done; clean up */
+				if (++(urb_priv->td_cnt) == urb_priv->length)
+					dl_del_urb (urb);
+			} else {
+				td_p = &td->hwNextTD;
+			}
+		}
+
+		if (ed->state & ED_DEL) { /* set by sohci_free_dev */
+			struct ohci_device * dev = usb_to_ohci (ohci->dev[edINFO & 0x7F]);
+			td_free (ohci, tdTailP); /* free dummy td */
+   	 		ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP); 
+			ed->state = ED_NEW;
+			hash_free_ed(ohci, ed);
+   	 		/* if all eds are removed wake up sohci_free_dev */
+   	 		if (!--dev->ed_cnt) {
+				wait_queue_head_t *wait_head = dev->wait;
+
+				dev->wait = 0;
+				if (wait_head)
+					wake_up (wait_head);
+			}
+   	 	} else {
+   	 		ed->state &= ~ED_URB_DEL;
+			tdHeadP = dma_to_td (ohci, le32_to_cpup (&ed->hwHeadP) & 0xfffffff0);
+
+			if (tdHeadP == tdTailP) {
+				if (ed->state == ED_OPER)
+					ep_unlink(ohci, ed);
+			} else
+   	 			ed->hwINFO &= ~cpu_to_le32 (OHCI_ED_SKIP);
+   	 	}
+
+		switch (ed->type) {
+			case PIPE_CONTROL:
+				ctrl = 1;
+				break;
+			case PIPE_BULK:
+				bulk = 1;
+				break;
+		}
+   	}
+   	
+	/* maybe reenable control and bulk lists */ 
+	if (!ohci->disabled) {
+		if (ctrl) 	/* reset control list */
+			writel (0, &ohci->regs->ed_controlcurrent);
+		if (bulk)	/* reset bulk list */
+			writel (0, &ohci->regs->ed_bulkcurrent);
+		if (!ohci->ed_rm_list[!frame] && !ohci->sleeping) {
+			if (ohci->ed_controltail)
+				ohci->hc_control |= OHCI_CTRL_CLE;
+			if (ohci->ed_bulktail)
+				ohci->hc_control |= OHCI_CTRL_BLE;
+			writel (ohci->hc_control, &ohci->regs->control);   
+		}
+	}
+
+   	ohci->ed_rm_list[frame] = NULL;
+   	spin_unlock_irqrestore (&usb_ed_lock, flags);
+}
+
+
+  		
+/*-------------------------------------------------------------------------*/
+
+/* td done list */
+
+static void dl_done_list (ohci_t * ohci, td_t * td_list)
+{
+  	td_t * td_list_next = NULL;
+	ed_t * ed;
+	int cc = 0;
+	struct urb * urb;
+	urb_priv_t * urb_priv;
+ 	__u32 tdINFO, edHeadP, edTailP;
+ 	
+ 	unsigned long flags;
+ 	
+  	while (td_list) {
+   		td_list_next = td_list->next_dl_td;
+   		
+  		urb = td_list->urb;
+  		urb_priv = urb->hcpriv;
+  		tdINFO = le32_to_cpup (&td_list->hwINFO);
+  		
+   		ed = td_list->ed;
+   		
+   		dl_transfer_length(td_list);
+ 			
+  		/* error code of transfer */
+  		cc = TD_CC_GET (tdINFO);
+  		if (cc == TD_CC_STALL)
+			usb_endpoint_halt(urb->dev,
+				usb_pipeendpoint(urb->pipe),
+				usb_pipeout(urb->pipe));
+  		
+  		if (!(urb->transfer_flags & USB_DISABLE_SPD)
+				&& (cc == TD_DATAUNDERRUN))
+			cc = TD_CC_NOERROR;
+
+  		if (++(urb_priv->td_cnt) == urb_priv->length) {
+			if ((ed->state & (ED_OPER | ED_UNLINK))
+					&& (urb_priv->state != URB_DEL)) {
+  				urb->status = cc_to_error[cc];
+  				sohci_return_urb (ohci, urb);
+  			} else {
+				spin_lock_irqsave (&usb_ed_lock, flags);
+  				dl_del_urb (urb);
+				spin_unlock_irqrestore (&usb_ed_lock, flags);
+			}
+  		}
+  		
+  		spin_lock_irqsave (&usb_ed_lock, flags);
+  		if (ed->state != ED_NEW) { 
+  			edHeadP = le32_to_cpup (&ed->hwHeadP) & 0xfffffff0;
+  			edTailP = le32_to_cpup (&ed->hwTailP);
+
+			/* unlink eds if they are not busy */
+     			if ((edHeadP == edTailP) && (ed->state == ED_OPER)) 
+     				ep_unlink (ohci, ed);
+     		}	
+     		spin_unlock_irqrestore (&usb_ed_lock, flags);
+     	
+    		td_list = td_list_next;
+  	}  
+}
+
+
+
+
+/*-------------------------------------------------------------------------*
+ * Virtual Root Hub 
+ *-------------------------------------------------------------------------*/
+ 
+/* Device descriptor */
+static __u8 root_hub_dev_des[] =
+{
+	0x12,       /*  __u8  bLength; */
+	0x01,       /*  __u8  bDescriptorType; Device */
+	0x10,	    /*  __u16 bcdUSB; v1.1 */
+	0x01,
+	0x09,	    /*  __u8  bDeviceClass; HUB_CLASSCODE */
+	0x00,	    /*  __u8  bDeviceSubClass; */
+	0x00,       /*  __u8  bDeviceProtocol; */
+	0x08,       /*  __u8  bMaxPacketSize0; 8 Bytes */
+	0x00,       /*  __u16 idVendor; */
+	0x00,
+	0x00,       /*  __u16 idProduct; */
+ 	0x00,
+	0x00,       /*  __u16 bcdDevice; */
+ 	0x00,
+	0x00,       /*  __u8  iManufacturer; */
+	0x02,       /*  __u8  iProduct; */
+	0x01,       /*  __u8  iSerialNumber; */
+	0x01        /*  __u8  bNumConfigurations; */
+};
+
+
+/* Configuration descriptor */
+static __u8 root_hub_config_des[] =
+{
+	0x09,       /*  __u8  bLength; */
+	0x02,       /*  __u8  bDescriptorType; Configuration */
+	0x19,       /*  __u16 wTotalLength; */
+	0x00,
+	0x01,       /*  __u8  bNumInterfaces; */
+	0x01,       /*  __u8  bConfigurationValue; */
+	0x00,       /*  __u8  iConfiguration; */
+	0x40,       /*  __u8  bmAttributes; 
+                 Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
+	0x00,       /*  __u8  MaxPower; */
+      
+	/* interface */	  
+	0x09,       /*  __u8  if_bLength; */
+	0x04,       /*  __u8  if_bDescriptorType; Interface */
+	0x00,       /*  __u8  if_bInterfaceNumber; */
+	0x00,       /*  __u8  if_bAlternateSetting; */
+	0x01,       /*  __u8  if_bNumEndpoints; */
+	0x09,       /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
+	0x00,       /*  __u8  if_bInterfaceSubClass; */
+	0x00,       /*  __u8  if_bInterfaceProtocol; */
+	0x00,       /*  __u8  if_iInterface; */
+     
+	/* endpoint */
+	0x07,       /*  __u8  ep_bLength; */
+	0x05,       /*  __u8  ep_bDescriptorType; Endpoint */
+	0x81,       /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
+ 	0x03,       /*  __u8  ep_bmAttributes; Interrupt */
+ 	0x02,       /*  __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
+ 	0x00,
+	0xff        /*  __u8  ep_bInterval; 255 ms */
+};
+
+/* Hub class-specific descriptor is constructed dynamically */
+
+
+/*-------------------------------------------------------------------------*/
+
+/* prepare Interrupt pipe data; HUB INTERRUPT ENDPOINT */ 
+ 
+static int rh_send_irq (ohci_t * ohci, void * rh_data, int rh_len)
+{
+	int num_ports;
+	int i;
+	int ret;
+	int len;
+
+	__u8 data[8];
+
+	num_ports = roothub_a (ohci) & RH_A_NDP; 
+	if (num_ports > MAX_ROOT_PORTS) {
+		err ("bogus NDP=%d for OHCI usb-%s", num_ports,
+			ohci->ohci_dev->slot_name);
+		err ("rereads as NDP=%d",
+			readl (&ohci->regs->roothub.a) & RH_A_NDP);
+		/* retry later; "should not happen" */
+		return 0;
+	}
+	*(__u8 *) data = (roothub_status (ohci) & (RH_HS_LPSC | RH_HS_OCIC))
+		? 1: 0;
+	ret = *(__u8 *) data;
+
+	for ( i = 0; i < num_ports; i++) {
+		*(__u8 *) (data + (i + 1) / 8) |= 
+			((roothub_portstatus (ohci, i) &
+				(RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC | RH_PS_OCIC | RH_PS_PRSC))
+			    ? 1: 0) << ((i + 1) % 8);
+		ret += *(__u8 *) (data + (i + 1) / 8);
+	}
+	len = i/8 + 1;
+  
+	if (ret > 0) { 
+		memcpy(rh_data, data,
+		       min_t(unsigned int, len,
+			   min_t(unsigned int, rh_len, sizeof(data))));
+		return len;
+	}
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Virtual Root Hub INTs are polled by this timer every "interval" ms */
+ 
+static void rh_int_timer_do (unsigned long ptr)
+{
+	int len; 
+
+	struct urb * urb = (struct urb *) ptr;
+	ohci_t * ohci = urb->dev->bus->hcpriv;
+
+	if (ohci->disabled)
+		return;
+
+	/* ignore timers firing during PM suspend, etc */
+	if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER)
+		goto out;
+
+	if(ohci->rh.send) { 
+		len = rh_send_irq (ohci, urb->transfer_buffer, urb->transfer_buffer_length);
+		if (len > 0) {
+			urb->actual_length = len;
+#ifdef DEBUG
+			urb_print (urb, "RET-t(rh)", usb_pipeout (urb->pipe));
+#endif
+			if (urb->complete)
+				urb->complete (urb);
+		}
+	}
+ out:
+	rh_init_int_timer (urb);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Root Hub INTs are polled by this timer */
+
+static int rh_init_int_timer (struct urb * urb) 
+{
+	ohci_t * ohci = urb->dev->bus->hcpriv;
+
+	ohci->rh.interval = urb->interval;
+	init_timer (&ohci->rh.rh_int_timer);
+	ohci->rh.rh_int_timer.function = rh_int_timer_do;
+	ohci->rh.rh_int_timer.data = (unsigned long) urb;
+	ohci->rh.rh_int_timer.expires = 
+			jiffies + (HZ * (urb->interval < 30? 30: urb->interval)) / 1000;
+	add_timer (&ohci->rh.rh_int_timer);
+	
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#define OK(x) 			len = (x); break
+#define WR_RH_STAT(x) 		writel((x), &ohci->regs->roothub.status)
+#define WR_RH_PORTSTAT(x) 	writel((x), &ohci->regs->roothub.portstatus[wIndex-1])
+#define RD_RH_STAT		roothub_status(ohci)
+#define RD_RH_PORTSTAT		roothub_portstatus(ohci,wIndex-1)
+
+/* request to virtual root hub */
+
+static int rh_submit_urb (struct urb * urb)
+{
+	struct usb_device * usb_dev = urb->dev;
+	ohci_t * ohci = usb_dev->bus->hcpriv;
+	unsigned int pipe = urb->pipe;
+	struct usb_ctrlrequest * cmd = (struct usb_ctrlrequest *) urb->setup_packet;
+	void * data = urb->transfer_buffer;
+	int leni = urb->transfer_buffer_length;
+	int len = 0;
+	int status = TD_CC_NOERROR;
+	
+	__u32 datab[4];
+	__u8  * data_buf = (__u8 *) datab;
+	
+ 	__u16 bmRType_bReq;
+	__u16 wValue; 
+	__u16 wIndex;
+	__u16 wLength;
+
+	if (usb_pipeint(pipe)) {
+		ohci->rh.urb =  urb;
+		ohci->rh.send = 1;
+		ohci->rh.interval = urb->interval;
+		rh_init_int_timer(urb);
+		urb->status = cc_to_error [TD_CC_NOERROR];
+		
+		return 0;
+	}
+
+	bmRType_bReq  = cmd->bRequestType | (cmd->bRequest << 8);
+	wValue        = le16_to_cpu (cmd->wValue);
+	wIndex        = le16_to_cpu (cmd->wIndex);
+	wLength       = le16_to_cpu (cmd->wLength);
+
+	switch (bmRType_bReq) {
+	/* Request Destination:
+	   without flags: Device, 
+	   RH_INTERFACE: interface, 
+	   RH_ENDPOINT: endpoint,
+	   RH_CLASS means HUB here, 
+	   RH_OTHER | RH_CLASS  almost ever means HUB_PORT here 
+	*/
+  
+		case RH_GET_STATUS: 				 		
+				*(__u16 *) data_buf = cpu_to_le16 (1); OK (2);
+		case RH_GET_STATUS | RH_INTERFACE: 	 		
+				*(__u16 *) data_buf = cpu_to_le16 (0); OK (2);
+		case RH_GET_STATUS | RH_ENDPOINT:	 		
+				*(__u16 *) data_buf = cpu_to_le16 (0); OK (2);   
+		case RH_GET_STATUS | RH_CLASS: 				
+				*(__u32 *) data_buf = cpu_to_le32 (
+					RD_RH_STAT & ~(RH_HS_CRWE | RH_HS_DRWE));
+				OK (4);
+		case RH_GET_STATUS | RH_OTHER | RH_CLASS: 	
+				*(__u32 *) data_buf = cpu_to_le32 (RD_RH_PORTSTAT); OK (4);
+
+		case RH_CLEAR_FEATURE | RH_ENDPOINT:  
+			switch (wValue) {
+				case (RH_ENDPOINT_STALL): OK (0);
+			}
+			break;
+
+		case RH_CLEAR_FEATURE | RH_CLASS:
+			switch (wValue) {
+				case RH_C_HUB_LOCAL_POWER:
+					OK(0);
+				case (RH_C_HUB_OVER_CURRENT): 
+						WR_RH_STAT(RH_HS_OCIC); OK (0);
+			}
+			break;
+		
+		case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+			switch (wValue) {
+				case (RH_PORT_ENABLE): 			
+						WR_RH_PORTSTAT (RH_PS_CCS ); OK (0);
+				case (RH_PORT_SUSPEND):			
+						WR_RH_PORTSTAT (RH_PS_POCI); OK (0);
+				case (RH_PORT_POWER):			
+						WR_RH_PORTSTAT (RH_PS_LSDA); OK (0);
+				case (RH_C_PORT_CONNECTION):	
+						WR_RH_PORTSTAT (RH_PS_CSC ); OK (0);
+				case (RH_C_PORT_ENABLE):		
+						WR_RH_PORTSTAT (RH_PS_PESC); OK (0);
+				case (RH_C_PORT_SUSPEND):		
+						WR_RH_PORTSTAT (RH_PS_PSSC); OK (0);
+				case (RH_C_PORT_OVER_CURRENT):	
+						WR_RH_PORTSTAT (RH_PS_OCIC); OK (0);
+				case (RH_C_PORT_RESET):			
+						WR_RH_PORTSTAT (RH_PS_PRSC); OK (0); 
+			}
+			break;
+ 
+		case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+			switch (wValue) {
+				case (RH_PORT_SUSPEND):			
+						WR_RH_PORTSTAT (RH_PS_PSS ); OK (0); 
+				case (RH_PORT_RESET): /* BUG IN HUP CODE *********/
+						if (RD_RH_PORTSTAT & RH_PS_CCS)
+						    WR_RH_PORTSTAT (RH_PS_PRS);
+						OK (0);
+				case (RH_PORT_POWER):			
+						WR_RH_PORTSTAT (RH_PS_PPS ); OK (0); 
+				case (RH_PORT_ENABLE): /* BUG IN HUP CODE *********/
+						if (RD_RH_PORTSTAT & RH_PS_CCS)
+						    WR_RH_PORTSTAT (RH_PS_PES );
+						OK (0);
+			}
+			break;
+
+		case RH_SET_ADDRESS: ohci->rh.devnum = wValue; OK(0);
+
+		case RH_GET_DESCRIPTOR:
+			switch ((wValue & 0xff00) >> 8) {
+				case (0x01): /* device descriptor */
+					len = min_t(unsigned int,
+						  leni,
+						  min_t(unsigned int,
+						      sizeof (root_hub_dev_des),
+						      wLength));
+					data_buf = root_hub_dev_des; OK(len);
+				case (0x02): /* configuration descriptor */
+					len = min_t(unsigned int,
+						  leni,
+						  min_t(unsigned int,
+						      sizeof (root_hub_config_des),
+						      wLength));
+					data_buf = root_hub_config_des; OK(len);
+				case (0x03): /* string descriptors */
+					len = usb_root_hub_string (wValue & 0xff,
+						(int)(long) ohci->regs, "OHCI",
+						data, wLength);
+					if (len > 0) {
+						data_buf = data;
+						OK(min_t(int, leni, len));
+					}
+					// else fallthrough
+				default: 
+					status = TD_CC_STALL;
+			}
+			break;
+		
+		case RH_GET_DESCRIPTOR | RH_CLASS:
+		    {
+			    __u32 temp = roothub_a (ohci);
+
+			    data_buf [0] = 9;		// min length;
+			    data_buf [1] = 0x29;
+			    data_buf [2] = temp & RH_A_NDP;
+			    data_buf [3] = 0;
+			    if (temp & RH_A_PSM) 	/* per-port power switching? */
+				data_buf [3] |= 0x1;
+			    if (temp & RH_A_NOCP)	/* no overcurrent reporting? */
+				data_buf [3] |= 0x10;
+			    else if (temp & RH_A_OCPM)	/* per-port overcurrent reporting? */
+				data_buf [3] |= 0x8;
+
+			    datab [1] = 0;
+			    data_buf [5] = (temp & RH_A_POTPGT) >> 24;
+			    temp = roothub_b (ohci);
+			    data_buf [7] = temp & RH_B_DR;
+			    if (data_buf [2] < 7) {
+				data_buf [8] = 0xff;
+			    } else {
+				data_buf [0] += 2;
+				data_buf [8] = (temp & RH_B_DR) >> 8;
+				data_buf [10] = data_buf [9] = 0xff;
+			    }
+				
+			    len = min_t(unsigned int, leni,
+				      min_t(unsigned int, data_buf [0], wLength));
+			    OK (len);
+			}
+ 
+		case RH_GET_CONFIGURATION: 	*(__u8 *) data_buf = 0x01; OK (1);
+
+		case RH_SET_CONFIGURATION: 	WR_RH_STAT (0x10000); OK (0);
+
+		default: 
+			dbg ("unsupported root hub command");
+			status = TD_CC_STALL;
+	}
+	
+#ifdef	DEBUG
+	// ohci_dump_roothub (ohci, 0);
+#endif
+
+	len = min_t(int, len, leni);
+	if (data != data_buf)
+	    memcpy (data, data_buf, len);
+  	urb->actual_length = len;
+	urb->status = cc_to_error [status];
+	
+#ifdef DEBUG
+	urb_print (urb, "RET(rh)", usb_pipeout (urb->pipe));
+#endif
+
+	urb->hcpriv = NULL;
+	usb_dec_dev_use (usb_dev);
+	urb->dev = NULL;
+	if (urb->complete)
+	    	urb->complete (urb);
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int rh_unlink_urb (struct urb * urb)
+{
+	ohci_t * ohci = urb->dev->bus->hcpriv;
+ 
+	if (ohci->rh.urb == urb) {
+		ohci->rh.send = 0;
+		del_timer (&ohci->rh.rh_int_timer);
+		ohci->rh.urb = NULL;
+
+		urb->hcpriv = NULL;
+		usb_dec_dev_use(urb->dev);
+		urb->dev = NULL;
+		if (urb->transfer_flags & USB_ASYNC_UNLINK) {
+			urb->status = -ECONNRESET;
+			if (urb->complete)
+				urb->complete (urb);
+		} else
+			urb->status = -ENOENT;
+	}
+	return 0;
+}
+ 
+/*-------------------------------------------------------------------------*
+ * HC functions
+ *-------------------------------------------------------------------------*/
+
+/* reset the HC and BUS */
+
+static int hc_reset (ohci_t * ohci)
+{
+	int timeout = 30;
+	int smm_timeout = 50; /* 0,5 sec */
+	 	
+#ifndef __hppa__
+	/* PA-RISC doesn't have SMM, but PDC might leave IR set */
+	if (readl (&ohci->regs->control) & OHCI_CTRL_IR) { /* SMM owns the HC */
+		writel (OHCI_OCR, &ohci->regs->cmdstatus); /* request ownership */
+		dbg("USB HC TakeOver from SMM");
+		while (readl (&ohci->regs->control) & OHCI_CTRL_IR) {
+			wait_ms (10);
+			if (--smm_timeout == 0) {
+				err("USB HC TakeOver failed!");
+				return -1;
+			}
+		}
+	}
+#endif	
+		
+	/* Disable HC interrupts */
+	writel (OHCI_INTR_MIE, &ohci->regs->intrdisable);
+
+	dbg("USB HC reset_hc usb-%s: ctrl = 0x%x ;",
+		ohci->ohci_dev->slot_name,
+		readl (&ohci->regs->control));
+
+  	/* Reset USB (needed by some controllers) */
+	writel (0, &ohci->regs->control);
+
+	/* Force a state change from USBRESET to USBOPERATIONAL for ALi */
+	(void) readl (&ohci->regs->control);	/* PCI posting */
+	writel (ohci->hc_control = OHCI_USB_OPER, &ohci->regs->control);
+
+	/* HC Reset requires max 10 ms delay */
+	writel (OHCI_HCR,  &ohci->regs->cmdstatus);
+	while ((readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) {
+		if (--timeout == 0) {
+			err("USB HC reset timed out!");
+			return -1;
+		}	
+		udelay (1);
+	}	 
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Start an OHCI controller, set the BUS operational
+ * enable interrupts 
+ * connect the virtual root hub */
+
+static int hc_start (ohci_t * ohci)
+{
+  	__u32 mask;
+  	unsigned int fminterval;
+  	struct usb_device  * usb_dev;
+	struct ohci_device * dev;
+	
+	ohci->disabled = 1;
+
+	/* Tell the controller where the control and bulk lists are
+	 * The lists are empty now. */
+	 
+	writel (0, &ohci->regs->ed_controlhead);
+	writel (0, &ohci->regs->ed_bulkhead);
+	
+	writel (ohci->hcca_dma, &ohci->regs->hcca); /* a reset clears this */
+   
+  	fminterval = 0x2edf;
+	writel ((fminterval * 9) / 10, &ohci->regs->periodicstart);
+	fminterval |= ((((fminterval - 210) * 6) / 7) << 16); 
+	writel (fminterval, &ohci->regs->fminterval);	
+	writel (0x628, &ohci->regs->lsthresh);
+
+ 	/* start controller operations */
+ 	ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
+	ohci->disabled = 0;
+ 	writel (ohci->hc_control, &ohci->regs->control);
+ 
+	/* Choose the interrupts we care about now, others later on demand */
+	mask = OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_WDH | OHCI_INTR_SO;
+	writel (mask, &ohci->regs->intrenable);
+	writel (mask, &ohci->regs->intrstatus);
+
+#ifdef	OHCI_USE_NPS
+	if(ohci->flags & OHCI_QUIRK_SUCKYIO)
+	{
+		/* NSC 87560 at least requires different setup .. */
+		writel ((roothub_a (ohci) | RH_A_NOCP) &
+			~(RH_A_OCPM | RH_A_POTPGT | RH_A_PSM | RH_A_NPS),
+			&ohci->regs->roothub.a);
+	}
+	else
+	{
+		/* required for AMD-756 and some Mac platforms */
+		writel ((roothub_a (ohci) | RH_A_NPS) & ~RH_A_PSM,
+			&ohci->regs->roothub.a);
+	}
+	writel (RH_HS_LPSC, &ohci->regs->roothub.status);
+#endif	/* OHCI_USE_NPS */
+
+	// POTPGT delay is bits 24-31, in 2 ms units.
+	mdelay ((roothub_a (ohci) >> 23) & 0x1fe);
+ 
+	/* connect the virtual root hub */
+	ohci->rh.devnum = 0;
+	usb_dev = usb_alloc_dev (NULL, ohci->bus);
+	if (!usb_dev) {
+	    ohci->disabled = 1;
+	    return -ENOMEM;
+	}
+
+	dev = usb_to_ohci (usb_dev);
+	ohci->bus->root_hub = usb_dev;
+	usb_connect (usb_dev);
+	if (usb_new_device (usb_dev) != 0) {
+		usb_free_dev (usb_dev); 
+		ohci->disabled = 1;
+		return -ENODEV;
+	}
+	
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* called only from interrupt handler */
+
+static void check_timeouts (struct ohci *ohci)
+{
+	spin_lock (&usb_ed_lock);
+	while (!list_empty (&ohci->timeout_list)) {
+		struct urb	*urb;
+
+		urb = list_entry (ohci->timeout_list.next, struct urb, urb_list);
+		if (time_after (jiffies, urb->timeout))
+			break;
+
+		list_del_init (&urb->urb_list);
+		if (urb->status != -EINPROGRESS)
+			continue;
+
+		urb->transfer_flags |= USB_TIMEOUT_KILLED | USB_ASYNC_UNLINK;
+		spin_unlock (&usb_ed_lock);
+
+		// outside the interrupt handler (in a timer...)
+		// this reference would race interrupts
+		sohci_unlink_urb (urb);
+
+		spin_lock (&usb_ed_lock);
+	}
+	spin_unlock (&usb_ed_lock);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* an interrupt happens */
+
+static void hc_interrupt (int irq, void * __ohci, struct pt_regs * r)
+{
+	ohci_t * ohci = __ohci;
+	struct ohci_regs * regs = ohci->regs;
+ 	int ints; 
+
+	/* avoid (slow) readl if only WDH happened */
+	if ((ohci->hcca->done_head != 0)
+			&& !(le32_to_cpup (&ohci->hcca->done_head) & 0x01)) {
+		ints =  OHCI_INTR_WDH;
+
+	/* cardbus/... hardware gone before remove() */
+	} else if ((ints = readl (&regs->intrstatus)) == ~(u32)0) {
+		ohci->disabled++;
+		err ("%s device removed!", ohci->ohci_dev->slot_name);
+		return;
+
+	/* interrupt for some other device? */
+	} else if ((ints &= readl (&regs->intrenable)) == 0) {
+		return;
+	} 
+
+	// dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no));
+
+	if (ints & OHCI_INTR_UE) {
+		ohci->disabled++;
+		err ("OHCI Unrecoverable Error, controller usb-%s disabled",
+			ohci->ohci_dev->slot_name);
+		// e.g. due to PCI Master/Target Abort
+
+#ifdef	DEBUG
+		ohci_dump (ohci, 1);
+#else
+		// FIXME: be optimistic, hope that bug won't repeat often.
+		// Make some non-interrupt context restart the controller.
+		// Count and limit the retries though; either hardware or
+		// software errors can go forever...
+#endif
+		hc_reset (ohci);
+	}
+  
+	if (ints & OHCI_INTR_WDH) {
+		writel (OHCI_INTR_WDH, &regs->intrdisable);	
+		dl_done_list (ohci, dl_reverse_done_list (ohci));
+		writel (OHCI_INTR_WDH, &regs->intrenable); 
+	}
+  
+	if (ints & OHCI_INTR_SO) {
+		dbg("USB Schedule overrun");
+		writel (OHCI_INTR_SO, &regs->intrenable); 	 
+	}
+
+	// FIXME:  this assumes SOF (1/ms) interrupts don't get lost...
+	if (ints & OHCI_INTR_SF) { 
+		unsigned int frame = le16_to_cpu (ohci->hcca->frame_no) & 1;
+		writel (OHCI_INTR_SF, &regs->intrdisable);	
+		if (ohci->ed_rm_list[!frame] != NULL) {
+			dl_del_list (ohci, !frame);
+		}
+		if (ohci->ed_rm_list[frame] != NULL)
+			writel (OHCI_INTR_SF, &regs->intrenable);	
+	}
+
+	if (!list_empty (&ohci->timeout_list)) {
+		check_timeouts (ohci);
+// FIXME:  enable SF as needed in a timer;
+// don't make lots of 1ms interrupts
+// On unloaded USB, think 4k ~= 4-5msec
+		if (!list_empty (&ohci->timeout_list))
+			writel (OHCI_INTR_SF, &regs->intrenable);	
+	}
+
+	writel (ints, &regs->intrstatus);
+	writel (OHCI_INTR_MIE, &regs->intrenable);	
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* allocate OHCI */
+
+static ohci_t * __devinit hc_alloc_ohci (struct pci_dev *dev, void * mem_base)
+{
+	ohci_t * ohci;
+
+	ohci = (ohci_t *) kmalloc (sizeof *ohci, GFP_KERNEL);
+	if (!ohci)
+		return NULL;
+		
+	memset (ohci, 0, sizeof (ohci_t));
+
+	ohci->hcca = pci_alloc_consistent (dev, sizeof *ohci->hcca,
+			&ohci->hcca_dma);
+        if (!ohci->hcca) {
+                kfree (ohci);
+                return NULL;
+        }
+        memset (ohci->hcca, 0, sizeof (struct ohci_hcca));
+
+	ohci->disabled = 1;
+	ohci->sleeping = 0;
+	ohci->irq = -1;
+	ohci->regs = mem_base;   
+
+	ohci->ohci_dev = dev;
+	pci_set_drvdata(dev, ohci);
+ 
+	INIT_LIST_HEAD (&ohci->ohci_hcd_list);
+	list_add (&ohci->ohci_hcd_list, &ohci_hcd_list);
+
+	INIT_LIST_HEAD (&ohci->timeout_list);
+
+	ohci->bus = usb_alloc_bus (&sohci_device_operations);
+	if (!ohci->bus) {
+		pci_set_drvdata (dev, NULL);
+		pci_free_consistent (ohci->ohci_dev, sizeof *ohci->hcca,
+				ohci->hcca, ohci->hcca_dma);
+		kfree (ohci);
+		return NULL;
+	}
+	ohci->bus->bus_name = dev->slot_name;
+	ohci->bus->hcpriv = (void *) ohci;
+
+	return ohci;
+} 
+
+
+/*-------------------------------------------------------------------------*/
+
+/* De-allocate all resources.. */
+
+static void hc_release_ohci (ohci_t * ohci)
+{	
+	dbg ("USB HC release ohci usb-%s", ohci->ohci_dev->slot_name);
+
+	/* disconnect all devices */    
+	if (ohci->bus->root_hub)
+		usb_disconnect (&ohci->bus->root_hub);
+
+	if (!ohci->disabled)
+		hc_reset (ohci);
+	
+	if (ohci->irq >= 0) {
+		free_irq (ohci->irq, ohci);
+		ohci->irq = -1;
+	}
+	pci_set_drvdata(ohci->ohci_dev, NULL);
+	if (ohci->bus) {
+		if (ohci->bus->busnum != -1)
+			usb_deregister_bus (ohci->bus);
+
+		usb_free_bus (ohci->bus);
+	}
+
+	list_del (&ohci->ohci_hcd_list);
+	INIT_LIST_HEAD (&ohci->ohci_hcd_list);
+
+	ohci_mem_cleanup (ohci);
+    
+	/* unmap the IO address space */
+	iounmap (ohci->regs);
+
+	pci_free_consistent (ohci->ohci_dev, sizeof *ohci->hcca,
+		ohci->hcca, ohci->hcca_dma);
+	kfree (ohci);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Increment the module usage count, start the control thread and
+ * return success. */
+
+static struct pci_driver ohci_pci_driver;
+ 
+static int __devinit
+hc_found_ohci (struct pci_dev *dev, int irq,
+	void *mem_base, const struct pci_device_id *id)
+{
+	ohci_t * ohci;
+	char buf[8], *bufp = buf;
+	int ret;
+
+#ifndef __sparc__
+	sprintf(buf, "%d", irq);
+#else
+	bufp = __irq_itoa(irq);
+#endif
+	printk(KERN_INFO __FILE__ ": USB OHCI at membase 0x%lx, IRQ %s\n",
+		(unsigned long)	mem_base, bufp);
+	printk(KERN_INFO __FILE__ ": usb-%s, %s\n", dev->slot_name, dev->name);
+    
+	ohci = hc_alloc_ohci (dev, mem_base);
+	if (!ohci) {
+		return -ENOMEM;
+	}
+	if ((ret = ohci_mem_init (ohci)) < 0) {
+		hc_release_ohci (ohci);
+		return ret;
+	}
+	ohci->flags = id->driver_data;
+	
+	/* Check for NSC87560. We have to look at the bridge (fn1) to identify
+	   the USB (fn2). This quirk might apply to more or even all NSC stuff
+	   I don't know.. */
+	   
+	if(dev->vendor == PCI_VENDOR_ID_NS)
+	{
+		struct pci_dev *fn1  = pci_find_slot(dev->bus->number, PCI_DEVFN(PCI_SLOT(dev->devfn), 1));
+		if(fn1 && fn1->vendor == PCI_VENDOR_ID_NS && fn1->device == PCI_DEVICE_ID_NS_87560_LIO)
+			ohci->flags |= OHCI_QUIRK_SUCKYIO;
+		
+	}
+	
+	if (ohci->flags & OHCI_QUIRK_SUCKYIO)
+		printk (KERN_INFO __FILE__ ": Using NSC SuperIO setup\n");
+	if (ohci->flags & OHCI_QUIRK_AMD756)
+		printk (KERN_INFO __FILE__ ": AMD756 erratum 4 workaround\n");
+
+	if (hc_reset (ohci) < 0) {
+		hc_release_ohci (ohci);
+		return -ENODEV;
+	}
+
+	/* FIXME this is a second HC reset; why?? */
+	writel (ohci->hc_control = OHCI_USB_RESET, &ohci->regs->control);
+	wait_ms (10);
+
+	usb_register_bus (ohci->bus);
+	
+	if (request_irq (irq, hc_interrupt, SA_SHIRQ,
+			ohci_pci_driver.name, ohci) != 0) {
+		err ("request interrupt %s failed", bufp);
+		hc_release_ohci (ohci);
+		return -EBUSY;
+	}
+	ohci->irq = irq;     
+
+	if (hc_start (ohci) < 0) {
+		err ("can't start usb-%s", dev->slot_name);
+		hc_release_ohci (ohci);
+		return -EBUSY;
+	}
+
+#ifdef	DEBUG
+	ohci_dump (ohci, 1);
+#endif
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef	CONFIG_PM
+
+/* controller died; cleanup debris, then restart */
+/* must not be called from interrupt context */
+
+static void hc_restart (ohci_t *ohci)
+{
+	int temp;
+	int i;
+
+	if (ohci->pci_latency)
+		pci_write_config_byte (ohci->ohci_dev, PCI_LATENCY_TIMER, ohci->pci_latency);
+
+	ohci->disabled = 1;
+	ohci->sleeping = 0;
+	if (ohci->bus->root_hub)
+		usb_disconnect (&ohci->bus->root_hub);
+	
+	/* empty the interrupt branches */
+	for (i = 0; i < NUM_INTS; i++) ohci->ohci_int_load[i] = 0;
+	for (i = 0; i < NUM_INTS; i++) ohci->hcca->int_table[i] = 0;
+	
+	/* no EDs to remove */
+	ohci->ed_rm_list [0] = NULL;
+	ohci->ed_rm_list [1] = NULL;
+
+	/* empty control and bulk lists */	 
+	ohci->ed_isotail     = NULL;
+	ohci->ed_controltail = NULL;
+	ohci->ed_bulktail    = NULL;
+
+	if ((temp = hc_reset (ohci)) < 0 || (temp = hc_start (ohci)) < 0) {
+		err ("can't restart usb-%s, %d", ohci->ohci_dev->slot_name, temp);
+	} else
+		dbg ("restart usb-%s completed", ohci->ohci_dev->slot_name);
+}
+
+#endif	/* CONFIG_PM */
+
+/*-------------------------------------------------------------------------*/
+
+/* configured so that an OHCI device is always provided */
+/* always called with process context; sleeping is OK */
+
+static int __devinit
+ohci_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
+{
+	unsigned long mem_resource, mem_len;
+	void *mem_base;
+	int status;
+
+	if (pci_enable_device(dev) < 0)
+		return -ENODEV;
+
+        if (!dev->irq) {
+        	err("found OHCI device with no IRQ assigned. check BIOS settings!");
+		pci_disable_device (dev);
+   	        return -ENODEV;
+        }
+	
+	/* we read its hardware registers as memory */
+	mem_resource = pci_resource_start(dev, 0);
+	mem_len = pci_resource_len(dev, 0);
+	if (!request_mem_region (mem_resource, mem_len, ohci_pci_driver.name)) {
+		dbg ("controller already in use");
+		pci_disable_device (dev);
+		return -EBUSY;
+	}
+
+	mem_base = ioremap_nocache (mem_resource, mem_len);
+	if (!mem_base) {
+		err("Error mapping OHCI memory");
+		release_mem_region (mem_resource, mem_len);
+		pci_disable_device (dev);
+		return -EFAULT;
+	}
+
+	/* controller writes into our memory */
+	pci_set_master (dev);
+
+	status = hc_found_ohci (dev, dev->irq, mem_base, id);
+	if (status < 0) {
+		iounmap (mem_base);
+		release_mem_region (mem_resource, mem_len);
+		pci_disable_device (dev);
+	}
+	return status;
+} 
+
+/*-------------------------------------------------------------------------*/
+
+/* may be called from interrupt context [interface spec] */
+/* may be called without controller present */
+/* may be called with controller, bus, and devices active */
+
+static void __devexit
+ohci_pci_remove (struct pci_dev *dev)
+{
+	ohci_t		*ohci = pci_get_drvdata(dev);
+
+	dbg ("remove %s controller usb-%s%s%s",
+		hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS),
+		dev->slot_name,
+		ohci->disabled ? " (disabled)" : "",
+		in_interrupt () ? " in interrupt" : ""
+		);
+#ifdef	DEBUG
+	ohci_dump (ohci, 1);
+#endif
+
+	/* don't wake up sleeping controllers, or block in interrupt context */
+	if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER || in_interrupt ()) {
+		dbg ("controller being disabled");
+		ohci->disabled = 1;
+	}
+
+	/* on return, USB will always be reset (if present) */
+	if (ohci->disabled)
+		writel (ohci->hc_control = OHCI_USB_RESET,
+			&ohci->regs->control);
+
+	hc_release_ohci (ohci);
+
+	release_mem_region (pci_resource_start (dev, 0), pci_resource_len (dev, 0));
+	pci_disable_device (dev);
+}
+
+
+#ifdef	CONFIG_PM
+
+/*-------------------------------------------------------------------------*/
+
+static int
+ohci_pci_suspend (struct pci_dev *dev, u32 state)
+{
+	ohci_t			*ohci = pci_get_drvdata(dev);
+	unsigned long		flags;
+	u16 cmd;
+
+	if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER) {
+		dbg ("can't suspend usb-%s (state is %s)", dev->slot_name,
+			hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS));
+		return -EIO;
+	}
+
+	/* act as if usb suspend can always be used */
+	info ("USB suspend: usb-%s", dev->slot_name);
+	ohci->sleeping = 1;
+
+	/* First stop processing */
+  	spin_lock_irqsave (&usb_ed_lock, flags);
+	ohci->hc_control &= ~(OHCI_CTRL_PLE|OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_IE);
+	writel (ohci->hc_control, &ohci->regs->control);
+	writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
+	(void) readl (&ohci->regs->intrstatus);
+  	spin_unlock_irqrestore (&usb_ed_lock, flags);
+
+	/* Wait a frame or two */
+	mdelay(1);
+	if (!readl (&ohci->regs->intrstatus) & OHCI_INTR_SF)
+		mdelay (1);
+		
+#ifdef CONFIG_PMAC_PBOOK
+	if (_machine == _MACH_Pmac)
+		disable_irq (ohci->irq);
+	/* else, 2.4 assumes shared irqs -- don't disable */
+#endif
+	/* Enable remote wakeup */
+	writel (readl(&ohci->regs->intrenable) | OHCI_INTR_RD, &ohci->regs->intrenable);
+
+	/* Suspend chip and let things settle down a bit */
+	ohci->hc_control = OHCI_USB_SUSPEND;
+	writel (ohci->hc_control, &ohci->regs->control);
+	(void) readl (&ohci->regs->control);
+	mdelay (500); /* No schedule here ! */
+	switch (readl (&ohci->regs->control) & OHCI_CTRL_HCFS) {
+		case OHCI_USB_RESET:
+			dbg("Bus in reset phase ???");
+			break;
+		case OHCI_USB_RESUME:
+			dbg("Bus in resume phase ???");
+			break;
+		case OHCI_USB_OPER:
+			dbg("Bus in operational phase ???");
+			break;
+		case OHCI_USB_SUSPEND:
+			dbg("Bus suspended");
+			break;
+	}
+	/* In some rare situations, Apple's OHCI have happily trashed
+	 * memory during sleep. We disable it's bus master bit during
+	 * suspend
+	 */
+	pci_read_config_word (dev, PCI_COMMAND, &cmd);
+	cmd &= ~PCI_COMMAND_MASTER;
+	pci_write_config_word (dev, PCI_COMMAND, cmd);
+#ifdef CONFIG_PMAC_PBOOK
+	{
+	   	struct device_node	*of_node;
+
+		/* Disable USB PAD & cell clock */
+		of_node = pci_device_to_OF_node (ohci->ohci_dev);
+		if (of_node)
+			pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0);
+	}
+#endif
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int
+ohci_pci_resume (struct pci_dev *dev)
+{
+	ohci_t		*ohci = pci_get_drvdata(dev);
+	int		temp;
+	unsigned long	flags;
+
+	/* guard against multiple resumes */
+	atomic_inc (&ohci->resume_count);
+	if (atomic_read (&ohci->resume_count) != 1) {
+		err ("concurrent PCI resumes for usb-%s", dev->slot_name);
+		atomic_dec (&ohci->resume_count);
+		return 0;
+	}
+
+#ifdef CONFIG_PMAC_PBOOK
+	{
+		struct device_node *of_node;
+
+		/* Re-enable USB PAD & cell clock */
+		of_node = pci_device_to_OF_node (ohci->ohci_dev);
+		if (of_node)
+			pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 1);
+	}
+#endif
+
+	/* did we suspend, or were we powered off? */
+	ohci->hc_control = readl (&ohci->regs->control);
+	temp = ohci->hc_control & OHCI_CTRL_HCFS;
+
+#ifdef DEBUG
+	/* the registers may look crazy here */
+	ohci_dump_status (ohci);
+#endif
+
+	/* Re-enable bus mastering */
+	pci_set_master(ohci->ohci_dev);
+	
+	switch (temp) {
+
+	case OHCI_USB_RESET:	// lost power
+		info ("USB restart: usb-%s", dev->slot_name);
+		hc_restart (ohci);
+		break;
+
+	case OHCI_USB_SUSPEND:	// host wakeup
+	case OHCI_USB_RESUME:	// remote wakeup
+		info ("USB continue: usb-%s from %s wakeup", dev->slot_name,
+			(temp == OHCI_USB_SUSPEND)
+				? "host" : "remote");
+		ohci->hc_control = OHCI_USB_RESUME;
+		writel (ohci->hc_control, &ohci->regs->control);
+		(void) readl (&ohci->regs->control);
+		mdelay (20); /* no schedule here ! */
+		/* Some controllers (lucent) need a longer delay here */
+		mdelay (15);
+		temp = readl (&ohci->regs->control);
+		temp = ohci->hc_control & OHCI_CTRL_HCFS;
+		if (temp != OHCI_USB_RESUME) {
+			err ("controller usb-%s won't resume", dev->slot_name);
+			ohci->disabled = 1;
+			return -EIO;
+		}
+
+		/* Some chips likes being resumed first */
+		writel (OHCI_USB_OPER, &ohci->regs->control);
+		(void) readl (&ohci->regs->control);
+		mdelay (3);
+
+		/* Then re-enable operations */
+		spin_lock_irqsave (&usb_ed_lock, flags);
+		ohci->disabled = 0;
+		ohci->sleeping = 0;
+		ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
+		if (!ohci->ed_rm_list[0] && !ohci->ed_rm_list[1]) {
+			if (ohci->ed_controltail)
+				ohci->hc_control |= OHCI_CTRL_CLE;
+			if (ohci->ed_bulktail)
+				ohci->hc_control |= OHCI_CTRL_BLE;
+		}
+		writel (ohci->hc_control, &ohci->regs->control);
+		writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
+		writel (OHCI_INTR_SF, &ohci->regs->intrenable);
+		/* Check for a pending done list */
+		writel (OHCI_INTR_WDH, &ohci->regs->intrdisable);	
+		(void) readl (&ohci->regs->intrdisable);
+		spin_unlock_irqrestore (&usb_ed_lock, flags);
+#ifdef CONFIG_PMAC_PBOOK
+		if (_machine == _MACH_Pmac)
+			enable_irq (ohci->irq);
+#endif
+		if (ohci->hcca->done_head)
+			dl_done_list (ohci, dl_reverse_done_list (ohci));
+		writel (OHCI_INTR_WDH, &ohci->regs->intrenable); 
+		writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
+		writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
+		break;
+
+	default:
+		warn ("odd PCI resume for usb-%s", dev->slot_name);
+	}
+
+	/* controller is operational, extra resumes are harmless */
+	atomic_dec (&ohci->resume_count);
+
+	return 0;
+}
+
+#endif	/* CONFIG_PM */
+
+
+/*-------------------------------------------------------------------------*/
+
+static const struct pci_device_id __devinitdata ohci_pci_ids [] = { {
+
+	/*
+	 * AMD-756 [Viper] USB has a serious erratum when used with
+	 * lowspeed devices like mice.
+	 */
+	vendor:		0x1022,
+	device:		0x740c,
+	subvendor:	PCI_ANY_ID,
+	subdevice:	PCI_ANY_ID,
+
+	driver_data:	OHCI_QUIRK_AMD756,
+
+} , {
+
+	/* handle any USB OHCI controller */
+	class: 		((PCI_CLASS_SERIAL_USB << 8) | 0x10),
+	class_mask: 	~0,
+
+	/* no matter who makes it */
+	vendor:		PCI_ANY_ID,
+	device:		PCI_ANY_ID,
+	subvendor:	PCI_ANY_ID,
+	subdevice:	PCI_ANY_ID,
+
+	}, { /* end: all zeroes */ }
+};
+
+MODULE_DEVICE_TABLE (pci, ohci_pci_ids);
+
+static struct pci_driver ohci_pci_driver = {
+	name:		"usb-ohci",
+	id_table:	&ohci_pci_ids [0],
+
+	probe:		ohci_pci_probe,
+	remove:		__devexit_p(ohci_pci_remove),
+
+#ifdef	CONFIG_PM
+	suspend:	ohci_pci_suspend,
+	resume:		ohci_pci_resume,
+#endif	/* PM */
+};
+
+ 
+/*-------------------------------------------------------------------------*/
+
+static int __init ohci_hcd_init (void) 
+{
+	return pci_module_init (&ohci_pci_driver);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void __exit ohci_hcd_cleanup (void) 
+{	
+	pci_unregister_driver (&ohci_pci_driver);
+}
+
+module_init (ohci_hcd_init);
+module_exit (ohci_hcd_cleanup);
+
+
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/host/usb-ohci.h linux-2.4.21-pre6/drivers/usb/host/usb-ohci.h
--- linux-2.4.20/drivers/usb/host/usb-ohci.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/host/usb-ohci.h	2003-03-26 23:49:10.000000000 +0000
@@ -0,0 +1,643 @@
+/*
+ * URB OHCI HCD (Host Controller Driver) for USB.
+ * 
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ * 
+ * usb-ohci.h
+ */
+
+ 
+static int cc_to_error[16] = { 
+
+/* mapping of the OHCI CC status to error codes */ 
+	/* No  Error  */               USB_ST_NOERROR,
+	/* CRC Error  */               USB_ST_CRC,
+	/* Bit Stuff  */               USB_ST_BITSTUFF,
+	/* Data Togg  */               USB_ST_CRC,
+	/* Stall      */               USB_ST_STALL,
+	/* DevNotResp */               USB_ST_NORESPONSE,
+	/* PIDCheck   */               USB_ST_BITSTUFF,
+	/* UnExpPID   */               USB_ST_BITSTUFF,
+	/* DataOver   */               USB_ST_DATAOVERRUN,
+	/* DataUnder  */               USB_ST_DATAUNDERRUN,
+	/* reservd    */               USB_ST_NORESPONSE,
+	/* reservd    */               USB_ST_NORESPONSE,
+	/* BufferOver */               USB_ST_BUFFEROVERRUN,
+	/* BuffUnder  */               USB_ST_BUFFERUNDERRUN,
+	/* Not Access */               USB_ST_NORESPONSE,
+	/* Not Access */               USB_ST_NORESPONSE 
+};
+
+#include <linux/config.h>
+
+/* ED States */
+
+#define ED_NEW 		0x00
+#define ED_UNLINK 	0x01
+#define ED_OPER		0x02
+#define ED_DEL		0x04
+#define ED_URB_DEL  	0x08
+
+/* usb_ohci_ed */
+struct ed {
+	__u32 hwINFO;       
+	__u32 hwTailP;
+	__u32 hwHeadP;
+	__u32 hwNextED;
+
+	struct ed * ed_prev;  
+	__u8 int_period;
+	__u8 int_branch;
+	__u8 int_load; 
+	__u8 int_interval;
+	__u8 state;
+	__u8 type; 
+	__u16 last_iso;
+	struct ed * ed_rm_list;
+
+	dma_addr_t dma;
+	__u32 unused[3];
+} __attribute((aligned(16)));
+typedef struct ed ed_t;
+
+ 
+/* TD info field */
+#define TD_CC       0xf0000000
+#define TD_CC_GET(td_p) ((td_p >>28) & 0x0f)
+#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28)
+#define TD_EC       0x0C000000
+#define TD_T        0x03000000
+#define TD_T_DATA0  0x02000000
+#define TD_T_DATA1  0x03000000
+#define TD_T_TOGGLE 0x00000000
+#define TD_R        0x00040000
+#define TD_DI       0x00E00000
+#define TD_DI_SET(X) (((X) & 0x07)<< 21)
+#define TD_DP       0x00180000
+#define TD_DP_SETUP 0x00000000
+#define TD_DP_IN    0x00100000
+#define TD_DP_OUT   0x00080000
+
+#define TD_ISO	    0x00010000
+#define TD_DEL      0x00020000
+
+/* CC Codes */
+#define TD_CC_NOERROR      0x00
+#define TD_CC_CRC          0x01
+#define TD_CC_BITSTUFFING  0x02
+#define TD_CC_DATATOGGLEM  0x03
+#define TD_CC_STALL        0x04
+#define TD_DEVNOTRESP      0x05
+#define TD_PIDCHECKFAIL    0x06
+#define TD_UNEXPECTEDPID   0x07
+#define TD_DATAOVERRUN     0x08
+#define TD_DATAUNDERRUN    0x09
+#define TD_BUFFEROVERRUN   0x0C
+#define TD_BUFFERUNDERRUN  0x0D
+#define TD_NOTACCESSED     0x0F
+
+
+#define MAXPSW 1
+
+struct td {
+	__u32 hwINFO;
+  	__u32 hwCBP;		/* Current Buffer Pointer */
+  	__u32 hwNextTD;		/* Next TD Pointer */
+  	__u32 hwBE;		/* Memory Buffer End Pointer */
+
+  	__u16 hwPSW[MAXPSW];
+  	__u8 unused;
+  	__u8 index;
+  	struct ed * ed;
+  	struct td * next_dl_td;
+  	struct urb * urb;
+
+	dma_addr_t td_dma;
+	dma_addr_t data_dma;
+	__u32 unused2[2];
+} __attribute((aligned(32)));	/* normally 16, iso needs 32 */
+typedef struct td td_t;
+
+#define OHCI_ED_SKIP	(1 << 14)
+
+/*
+ * The HCCA (Host Controller Communications Area) is a 256 byte
+ * structure defined in the OHCI spec. that the host controller is
+ * told the base address of.  It must be 256-byte aligned.
+ */
+ 
+#define NUM_INTS 32	/* part of the OHCI standard */
+struct ohci_hcca {
+	__u32	int_table[NUM_INTS];	/* Interrupt ED table */
+	__u16	frame_no;		/* current frame number */
+	__u16	pad1;			/* set to 0 on each frame_no change */
+	__u32	done_head;		/* info returned for an interrupt */
+	u8		reserved_for_hc[116];
+} __attribute((aligned(256)));
+
+  
+/*
+ * Maximum number of root hub ports.  
+ */
+#define MAX_ROOT_PORTS	15	/* maximum OHCI root hub ports */
+
+/*
+ * This is the structure of the OHCI controller's memory mapped I/O
+ * region.  This is Memory Mapped I/O.  You must use the readl() and
+ * writel() macros defined in asm/io.h to access these!!
+ */
+struct ohci_regs {
+	/* control and status registers */
+	__u32	revision;
+	__u32	control;
+	__u32	cmdstatus;
+	__u32	intrstatus;
+	__u32	intrenable;
+	__u32	intrdisable;
+	/* memory pointers */
+	__u32	hcca;
+	__u32	ed_periodcurrent;
+	__u32	ed_controlhead;
+	__u32	ed_controlcurrent;
+	__u32	ed_bulkhead;
+	__u32	ed_bulkcurrent;
+	__u32	donehead;
+	/* frame counters */
+	__u32	fminterval;
+	__u32	fmremaining;
+	__u32	fmnumber;
+	__u32	periodicstart;
+	__u32	lsthresh;
+	/* Root hub ports */
+	struct	ohci_roothub_regs {
+		__u32	a;
+		__u32	b;
+		__u32	status;
+		__u32	portstatus[MAX_ROOT_PORTS];
+	} roothub;
+} __attribute((aligned(32)));
+
+
+/* OHCI CONTROL AND STATUS REGISTER MASKS */
+
+/*
+ * HcControl (control) register masks
+ */
+#define OHCI_CTRL_CBSR	(3 << 0)	/* control/bulk service ratio */
+#define OHCI_CTRL_PLE	(1 << 2)	/* periodic list enable */
+#define OHCI_CTRL_IE	(1 << 3)	/* isochronous enable */
+#define OHCI_CTRL_CLE	(1 << 4)	/* control list enable */
+#define OHCI_CTRL_BLE	(1 << 5)	/* bulk list enable */
+#define OHCI_CTRL_HCFS	(3 << 6)	/* host controller functional state */
+#define OHCI_CTRL_IR	(1 << 8)	/* interrupt routing */
+#define OHCI_CTRL_RWC	(1 << 9)	/* remote wakeup connected */
+#define OHCI_CTRL_RWE	(1 << 10)	/* remote wakeup enable */
+
+/* pre-shifted values for HCFS */
+#	define OHCI_USB_RESET	(0 << 6)
+#	define OHCI_USB_RESUME	(1 << 6)
+#	define OHCI_USB_OPER	(2 << 6)
+#	define OHCI_USB_SUSPEND	(3 << 6)
+
+/*
+ * HcCommandStatus (cmdstatus) register masks
+ */
+#define OHCI_HCR	(1 << 0)	/* host controller reset */
+#define OHCI_CLF  	(1 << 1)	/* control list filled */
+#define OHCI_BLF  	(1 << 2)	/* bulk list filled */
+#define OHCI_OCR  	(1 << 3)	/* ownership change request */
+#define OHCI_SOC  	(3 << 16)	/* scheduling overrun count */
+
+/*
+ * masks used with interrupt registers:
+ * HcInterruptStatus (intrstatus)
+ * HcInterruptEnable (intrenable)
+ * HcInterruptDisable (intrdisable)
+ */
+#define OHCI_INTR_SO	(1 << 0)	/* scheduling overrun */
+#define OHCI_INTR_WDH	(1 << 1)	/* writeback of done_head */
+#define OHCI_INTR_SF	(1 << 2)	/* start frame */
+#define OHCI_INTR_RD	(1 << 3)	/* resume detect */
+#define OHCI_INTR_UE	(1 << 4)	/* unrecoverable error */
+#define OHCI_INTR_FNO	(1 << 5)	/* frame number overflow */
+#define OHCI_INTR_RHSC	(1 << 6)	/* root hub status change */
+#define OHCI_INTR_OC	(1 << 30)	/* ownership change */
+#define OHCI_INTR_MIE	(1 << 31)	/* master interrupt enable */
+
+
+
+/* Virtual Root HUB */
+struct virt_root_hub {
+	int devnum; /* Address of Root Hub endpoint */ 
+	void * urb;
+	void * int_addr;
+	int send;
+	int interval;
+	struct timer_list rh_int_timer;
+};
+
+
+/* USB HUB CONSTANTS (not OHCI-specific; see hub.h) */
+ 
+/* destination of request */
+#define RH_INTERFACE               0x01
+#define RH_ENDPOINT                0x02
+#define RH_OTHER                   0x03
+
+#define RH_CLASS                   0x20
+#define RH_VENDOR                  0x40
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define RH_GET_STATUS           0x0080
+#define RH_CLEAR_FEATURE        0x0100
+#define RH_SET_FEATURE          0x0300
+#define RH_SET_ADDRESS		0x0500
+#define RH_GET_DESCRIPTOR	0x0680
+#define RH_SET_DESCRIPTOR       0x0700
+#define RH_GET_CONFIGURATION	0x0880
+#define RH_SET_CONFIGURATION	0x0900
+#define RH_GET_STATE            0x0280
+#define RH_GET_INTERFACE        0x0A80
+#define RH_SET_INTERFACE        0x0B00
+#define RH_SYNC_FRAME           0x0C80
+/* Our Vendor Specific Request */
+#define RH_SET_EP               0x2000
+
+
+/* Hub port features */
+#define RH_PORT_CONNECTION         0x00
+#define RH_PORT_ENABLE             0x01
+#define RH_PORT_SUSPEND            0x02
+#define RH_PORT_OVER_CURRENT       0x03
+#define RH_PORT_RESET              0x04
+#define RH_PORT_POWER              0x08
+#define RH_PORT_LOW_SPEED          0x09
+
+#define RH_C_PORT_CONNECTION       0x10
+#define RH_C_PORT_ENABLE           0x11
+#define RH_C_PORT_SUSPEND          0x12
+#define RH_C_PORT_OVER_CURRENT     0x13
+#define RH_C_PORT_RESET            0x14  
+
+/* Hub features */
+#define RH_C_HUB_LOCAL_POWER       0x00
+#define RH_C_HUB_OVER_CURRENT      0x01
+
+#define RH_DEVICE_REMOTE_WAKEUP    0x00
+#define RH_ENDPOINT_STALL          0x01
+
+#define RH_ACK                     0x01
+#define RH_REQ_ERR                 -1
+#define RH_NACK                    0x00
+
+
+/* OHCI ROOT HUB REGISTER MASKS */
+ 
+/* roothub.portstatus [i] bits */
+#define RH_PS_CCS            0x00000001   	/* current connect status */
+#define RH_PS_PES            0x00000002   	/* port enable status*/
+#define RH_PS_PSS            0x00000004   	/* port suspend status */
+#define RH_PS_POCI           0x00000008   	/* port over current indicator */
+#define RH_PS_PRS            0x00000010  	/* port reset status */
+#define RH_PS_PPS            0x00000100   	/* port power status */
+#define RH_PS_LSDA           0x00000200    	/* low speed device attached */
+#define RH_PS_CSC            0x00010000 	/* connect status change */
+#define RH_PS_PESC           0x00020000   	/* port enable status change */
+#define RH_PS_PSSC           0x00040000    	/* port suspend status change */
+#define RH_PS_OCIC           0x00080000    	/* over current indicator change */
+#define RH_PS_PRSC           0x00100000   	/* port reset status change */
+
+/* roothub.status bits */
+#define RH_HS_LPS	     0x00000001		/* local power status */
+#define RH_HS_OCI	     0x00000002		/* over current indicator */
+#define RH_HS_DRWE	     0x00008000		/* device remote wakeup enable */
+#define RH_HS_LPSC	     0x00010000		/* local power status change */
+#define RH_HS_OCIC	     0x00020000		/* over current indicator change */
+#define RH_HS_CRWE	     0x80000000		/* clear remote wakeup enable */
+
+/* roothub.b masks */
+#define RH_B_DR		0x0000ffff		/* device removable flags */
+#define RH_B_PPCM	0xffff0000		/* port power control mask */
+
+/* roothub.a masks */
+#define	RH_A_NDP	(0xff << 0)		/* number of downstream ports */
+#define	RH_A_PSM	(1 << 8)		/* power switching mode */
+#define	RH_A_NPS	(1 << 9)		/* no power switching */
+#define	RH_A_DT		(1 << 10)		/* device type (mbz) */
+#define	RH_A_OCPM	(1 << 11)		/* over current protection mode */
+#define	RH_A_NOCP	(1 << 12)		/* no over current protection */
+#define	RH_A_POTPGT	(0xff << 24)		/* power on to power good time */
+
+/* urb */
+typedef struct 
+{
+	ed_t * ed;
+	__u16 length;	// number of tds associated with this request
+	__u16 td_cnt;	// number of tds already serviced
+	int   state;
+	wait_queue_head_t * wait;
+	td_t * td[0];	// list pointer to all corresponding TDs associated with this request
+
+} urb_priv_t;
+#define URB_DEL 1
+
+
+/* Hash struct used for TD/ED hashing */
+struct hash_t {
+	void		*virt;
+	dma_addr_t	dma;
+	struct hash_t	*next; // chaining for collision cases
+};
+
+/* List of TD/ED hash entries */
+struct hash_list_t {
+	struct hash_t	*head;
+	struct hash_t	*tail;
+};
+
+#define TD_HASH_SIZE    64    /* power'o'two */
+#define ED_HASH_SIZE    64    /* power'o'two */
+
+#define TD_HASH_FUNC(td_dma) ((td_dma ^ (td_dma >> 5)) % TD_HASH_SIZE)
+#define ED_HASH_FUNC(ed_dma) ((ed_dma ^ (ed_dma >> 5)) % ED_HASH_SIZE)
+
+
+/*
+ * This is the full ohci controller description
+ *
+ * Note how the "proper" USB information is just
+ * a subset of what the full implementation needs. (Linus)
+ */
+
+
+typedef struct ohci {
+	struct ohci_hcca *hcca;		/* hcca */
+	dma_addr_t hcca_dma;
+
+	int irq;
+	int disabled;			/* e.g. got a UE, we're hung */
+	int sleeping;
+	atomic_t resume_count;		/* defending against multiple resumes */
+	unsigned long flags;		/* for HC bugs */
+#define	OHCI_QUIRK_AMD756	0x01		/* erratum #4 */
+#define OHCI_QUIRK_SUCKYIO	0x02		/* NSC superio */
+
+	struct ohci_regs * regs;	/* OHCI controller's memory */
+	struct list_head ohci_hcd_list;	/* list of all ohci_hcd */
+
+	struct list_head timeout_list;
+	// struct list_head urb_list; 	// list of all pending urbs
+	// spinlock_t urb_list_lock; 	// lock to keep consistency 
+  
+	int ohci_int_load[32];		/* load of the 32 Interrupt Chains (for load balancing)*/
+	ed_t * ed_rm_list[2];     /* lists of all endpoints to be removed */
+	ed_t * ed_bulktail;       /* last endpoint of bulk list */
+	ed_t * ed_controltail;    /* last endpoint of control list */
+ 	ed_t * ed_isotail;        /* last endpoint of iso list */
+	int intrstatus;
+	__u32 hc_control;		/* copy of the hc control reg */
+	struct usb_bus * bus;    
+	struct usb_device * dev[128];
+	struct virt_root_hub rh;
+
+	/* PCI device handle, settings, ... */
+	struct pci_dev	*ohci_dev;
+	u8		pci_latency;
+	struct pci_pool	*td_cache;
+	struct pci_pool	*dev_cache;
+	struct hash_list_t	td_hash[TD_HASH_SIZE];
+	struct hash_list_t	ed_hash[ED_HASH_SIZE];
+
+} ohci_t;
+
+#define NUM_EDS 32		/* num of preallocated endpoint descriptors */
+
+struct ohci_device {
+	ed_t 	ed[NUM_EDS];
+	dma_addr_t dma;
+	int ed_cnt;
+	wait_queue_head_t * wait;
+};
+
+// #define ohci_to_usb(ohci)	((ohci)->usb)
+#define usb_to_ohci(usb)	((struct ohci_device *)(usb)->hcpriv)
+
+/* hcd */
+/* endpoint */
+static int ep_link(ohci_t * ohci, ed_t * ed);
+static int ep_unlink(ohci_t * ohci, ed_t * ed);
+static ed_t * ep_add_ed(struct usb_device * usb_dev, unsigned int pipe, int interval, int load, int mem_flags);
+static void ep_rm_ed(struct usb_device * usb_dev, ed_t * ed);
+/* td */
+static void td_fill(ohci_t * ohci, unsigned int info, dma_addr_t data, int len, struct urb * urb, int index);
+static void td_submit_urb(struct urb * urb);
+/* root hub */
+static int rh_submit_urb(struct urb * urb);
+static int rh_unlink_urb(struct urb * urb);
+static int rh_init_int_timer(struct urb * urb);
+
+/*-------------------------------------------------------------------------*/
+
+#define ALLOC_FLAGS (in_interrupt () || current->state != TASK_RUNNING ? GFP_ATOMIC : GFP_KERNEL)
+
+#ifdef DEBUG
+#	define OHCI_MEM_FLAGS	SLAB_POISON
+#else
+#	define OHCI_MEM_FLAGS	0
+#endif
+ 
+#ifndef CONFIG_PCI
+#	error "usb-ohci currently requires PCI-based controllers"
+	/* to support non-PCI OHCIs, you need custom bus/mem/... glue */
+#endif
+
+
+/* Recover a TD/ED using its collision chain */
+static inline void *
+dma_to_ed_td (struct hash_list_t * entry, dma_addr_t dma)
+{
+	struct hash_t * scan = entry->head;
+	while (scan && scan->dma != dma)
+		scan = scan->next;
+	if (!scan)
+		BUG();
+	return scan->virt;
+}
+
+static inline struct ed *
+dma_to_ed (struct ohci * hc, dma_addr_t ed_dma)
+{
+	return (struct ed *) dma_to_ed_td(&(hc->ed_hash[ED_HASH_FUNC(ed_dma)]),
+				      ed_dma);
+}
+
+static inline struct td *
+dma_to_td (struct ohci * hc, dma_addr_t td_dma)
+{
+	return (struct td *) dma_to_ed_td(&(hc->td_hash[TD_HASH_FUNC(td_dma)]),
+				      td_dma);
+}
+
+/* Add a hash entry for a TD/ED; return true on success */
+static inline int
+hash_add_ed_td(struct hash_list_t * entry, void * virt, dma_addr_t dma)
+{
+	struct hash_t * scan;
+	
+	scan = (struct hash_t *)kmalloc(sizeof(struct hash_t), ALLOC_FLAGS);
+	if (!scan)
+		return 0;
+	
+	if (!entry->tail) {
+		entry->head = entry->tail = scan;
+	} else {
+		entry->tail->next = scan;
+		entry->tail = scan;
+	}
+	
+	scan->virt = virt;
+	scan->dma = dma;
+	scan->next = NULL;
+	return 1;
+}
+
+static inline int
+hash_add_ed (struct ohci * hc, struct ed * ed)
+{
+	return hash_add_ed_td (&(hc->ed_hash[ED_HASH_FUNC(ed->dma)]),
+			ed, ed->dma);
+}
+
+static inline int
+hash_add_td (struct ohci * hc, struct td * td)
+{
+	return hash_add_ed_td (&(hc->td_hash[TD_HASH_FUNC(td->td_dma)]),
+			td, td->td_dma);
+}
+
+
+static inline void
+hash_free_ed_td (struct hash_list_t * entry, void * virt)
+{
+	struct hash_t *scan, *prev;
+	scan = prev = entry->head;
+
+	// Find and unlink hash entry
+	while (scan && scan->virt != virt) {
+		prev = scan;
+		scan = scan->next;
+	}
+	if (scan) {
+		if (scan == entry->head) {
+			if (entry->head == entry->tail)
+				entry->head = entry->tail = NULL;
+			else
+				entry->head = scan->next;
+		} else if (scan == entry->tail) {
+			entry->tail = prev;
+			prev->next = NULL;
+		} else
+			prev->next = scan->next;
+		kfree(scan);
+	}
+}
+
+static inline void
+hash_free_ed (struct ohci * hc, struct ed * ed)
+{
+	hash_free_ed_td (&(hc->ed_hash[ED_HASH_FUNC(ed->dma)]), ed);
+}
+
+static inline void
+hash_free_td (struct ohci * hc, struct td * td)
+{
+	hash_free_ed_td (&(hc->td_hash[TD_HASH_FUNC(td->td_dma)]), td);
+}
+
+
+static int ohci_mem_init (struct ohci *ohci)
+{
+	ohci->td_cache = pci_pool_create ("ohci_td", ohci->ohci_dev,
+		sizeof (struct td),
+		32 /* byte alignment */,
+		0 /* no page-crossing issues */,
+		GFP_KERNEL | OHCI_MEM_FLAGS);
+	if (!ohci->td_cache)
+		return -ENOMEM;
+	ohci->dev_cache = pci_pool_create ("ohci_dev", ohci->ohci_dev,
+		sizeof (struct ohci_device),
+		16 /* byte alignment */,
+		0 /* no page-crossing issues */,
+		GFP_KERNEL | OHCI_MEM_FLAGS);
+	if (!ohci->dev_cache)
+		return -ENOMEM;
+	return 0;
+}
+
+static void ohci_mem_cleanup (struct ohci *ohci)
+{
+	if (ohci->td_cache) {
+		pci_pool_destroy (ohci->td_cache);
+		ohci->td_cache = 0;
+	}
+	if (ohci->dev_cache) {
+		pci_pool_destroy (ohci->dev_cache);
+		ohci->dev_cache = 0;
+	}
+}
+
+/* TDs ... */
+static inline struct td *
+td_alloc (struct ohci *hc, int mem_flags)
+{
+	dma_addr_t	dma;
+	struct td	*td;
+
+	td = pci_pool_alloc (hc->td_cache, mem_flags, &dma);
+	if (td) {
+		td->td_dma = dma;
+
+		/* hash it for later reverse mapping */
+		if (!hash_add_td (hc, td)) {
+			pci_pool_free (hc->td_cache, td, dma);
+			return NULL;
+		}
+	}
+	return td;
+}
+
+static inline void
+td_free (struct ohci *hc, struct td *td)
+{
+	hash_free_td (hc, td);
+	pci_pool_free (hc->td_cache, td, td->td_dma);
+}
+
+
+/* DEV + EDs ... only the EDs need to be consistent */
+static inline struct ohci_device *
+dev_alloc (struct ohci *hc, int mem_flags)
+{
+	dma_addr_t		dma;
+	struct ohci_device	*dev;
+	int			i, offset;
+
+	dev = pci_pool_alloc (hc->dev_cache, mem_flags, &dma);
+	if (dev) {
+		memset (dev, 0, sizeof (*dev));
+		dev->dma = dma;
+		offset = ((char *)&dev->ed) - ((char *)dev);
+		for (i = 0; i < NUM_EDS; i++, offset += sizeof dev->ed [0])
+			dev->ed [i].dma = dma + offset;
+		/* add to hashtable if used */
+	}
+	return dev;
+}
+
+static inline void
+dev_free (struct ohci *hc, struct ohci_device *dev)
+{
+	pci_pool_free (hc->dev_cache, dev, dev->dma);
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/host/usb-uhci-debug.h linux-2.4.21-pre6/drivers/usb/host/usb-uhci-debug.h
--- linux-2.4.20/drivers/usb/host/usb-uhci-debug.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/host/usb-uhci-debug.h	2003-03-26 23:49:40.000000000 +0000
@@ -0,0 +1,195 @@
+#ifdef DEBUG
+static void __attribute__((__unused__)) uhci_show_qh (puhci_desc_t qh)
+{
+	if (qh->type != QH_TYPE) {
+		dbg("qh has not QH_TYPE");
+		return;
+	}
+	dbg("QH @ %p/%08llX:", qh, (unsigned long long)qh->dma_addr);
+
+	if (qh->hw.qh.head & UHCI_PTR_TERM)
+		dbg("    Head Terminate");
+	else 
+		dbg("    Head: %s @ %08X",
+		    (qh->hw.qh.head & UHCI_PTR_QH?"QH":"TD"),
+		    qh->hw.qh.head & ~UHCI_PTR_BITS);
+
+	if (qh->hw.qh.element & UHCI_PTR_TERM)
+		dbg("    Element Terminate");
+	else 
+		dbg("    Element: %s @ %08X",
+		    (qh->hw.qh.element & UHCI_PTR_QH?"QH":"TD"),
+		    qh->hw.qh.element & ~UHCI_PTR_BITS);
+}
+#endif
+
+#if 0
+static void uhci_show_td (puhci_desc_t td)
+{
+	char *spid;
+	
+	switch (td->hw.td.info & 0xff) {
+	case USB_PID_SETUP:
+		spid = "SETUP";
+		break;
+	case USB_PID_OUT:
+		spid = " OUT ";
+		break;
+	case USB_PID_IN:
+		spid = " IN  ";
+		break;
+	default:
+		spid = "  ?  ";
+		break;
+	}
+
+	warn("  TD @ %p/%08X, MaxLen=%02x DT%d EP=%x Dev=%x PID=(%s) buf=%08x",
+	     td, td->dma_addr,
+	     td->hw.td.info >> 21,
+	     ((td->hw.td.info >> 19) & 1),
+	     (td->hw.td.info >> 15) & 15,
+	     (td->hw.td.info >> 8) & 127,
+	     spid,
+	     td->hw.td.buffer);
+
+	warn("    Len=%02x e%d %s%s%s%s%s%s%s%s%s%s",
+	     td->hw.td.status & 0x7ff,
+	     ((td->hw.td.status >> 27) & 3),
+	     (td->hw.td.status & TD_CTRL_SPD) ? "SPD " : "",
+	     (td->hw.td.status & TD_CTRL_LS) ? "LS " : "",
+	     (td->hw.td.status & TD_CTRL_IOC) ? "IOC " : "",
+	     (td->hw.td.status & TD_CTRL_ACTIVE) ? "Active " : "",
+	     (td->hw.td.status & TD_CTRL_STALLED) ? "Stalled " : "",
+	     (td->hw.td.status & TD_CTRL_DBUFERR) ? "DataBufErr " : "",
+	     (td->hw.td.status & TD_CTRL_BABBLE) ? "Babble " : "",
+	     (td->hw.td.status & TD_CTRL_NAK) ? "NAK " : "",
+	     (td->hw.td.status & TD_CTRL_CRCTIMEO) ? "CRC/Timeo " : "",
+	     (td->hw.td.status & TD_CTRL_BITSTUFF) ? "BitStuff " : ""
+		);
+
+	if (td->hw.td.link & UHCI_PTR_TERM)
+		warn("   TD Link Terminate");
+	else 
+		warn("    Link points to %s @ %08x, %s",
+		     (td->hw.td.link & UHCI_PTR_QH?"QH":"TD"),
+		     td->hw.td.link & ~UHCI_PTR_BITS,
+		     (td->hw.td.link & UHCI_PTR_DEPTH ? "Depth first" : "Breadth first"));
+}
+#endif
+
+#ifdef DEBUG
+static void __attribute__((__unused__)) uhci_show_td_queue (puhci_desc_t td)
+{
+	//dbg("uhci_show_td_queue %p (%08lX):", td, td->dma_addr);
+#if 1
+	return;
+#else
+	while (1) {
+		uhci_show_td (td);
+		if (td->hw.td.link & UHCI_PTR_TERM)
+			break;
+		if (td != bus_to_virt (td->hw.td.link & ~UHCI_PTR_BITS))
+			td = bus_to_virt (td->hw.td.link & ~UHCI_PTR_BITS);
+		else {
+			dbg("td points to itself!");
+			break;
+		}
+	}
+#endif
+}
+
+static void __attribute__((__unused__)) uhci_show_queue (puhci_desc_t qh)
+{
+#if 0
+	uhci_desc_t *start_qh=qh;
+#endif
+
+	dbg("uhci_show_queue %p:", qh);
+#if 1
+	return;
+#else
+	while (1) {
+		uhci_show_qh (qh);
+
+		if (!(qh->hw.qh.element & UHCI_PTR_TERM))
+			uhci_show_td_queue (bus_to_virt (qh->hw.qh.element & ~UHCI_PTR_BITS));
+
+		if (qh->hw.qh.head & UHCI_PTR_TERM)
+			break;
+
+		if (qh != bus_to_virt (qh->hw.qh.head & ~UHCI_PTR_BITS))
+			qh = bus_to_virt (qh->hw.qh.head & ~UHCI_PTR_BITS);
+		else {
+			dbg("qh points to itself!");
+			break;
+		}
+		
+		if (qh==start_qh) { // avoid loop
+			dbg("Loop detect");
+			break;
+		}
+	}		
+#endif
+}
+
+static void __attribute__((__unused__)) uhci_show_sc (int port, unsigned short status)
+{
+	dbg("  stat%d     =     %04x   %s%s%s%s%s%s%s%s",
+	     port,
+	     status,
+	     (status & USBPORTSC_SUSP) ? "PortSuspend " : "",
+	     (status & USBPORTSC_PR) ? "PortReset " : "",
+	     (status & USBPORTSC_LSDA) ? "LowSpeed " : "",
+	     (status & USBPORTSC_RD) ? "ResumeDetect " : "",
+	     (status & USBPORTSC_PEC) ? "EnableChange " : "",
+	     (status & USBPORTSC_PE) ? "PortEnabled " : "",
+	     (status & USBPORTSC_CSC) ? "ConnectChange " : "",
+	     (status & USBPORTSC_CCS) ? "PortConnected " : "");
+}
+
+void uhci_show_status (puhci_t s)
+{
+	unsigned int io_addr = s->io_addr;
+	unsigned short usbcmd, usbstat, usbint, usbfrnum;
+	unsigned int flbaseadd;
+	unsigned char sof;
+	unsigned short portsc1, portsc2;
+
+	usbcmd = inw (io_addr + 0);
+	usbstat = inw (io_addr + 2);
+	usbint = inw (io_addr + 4);
+	usbfrnum = inw (io_addr + 6);
+	flbaseadd = inl (io_addr + 8);
+	sof = inb (io_addr + 12);
+	portsc1 = inw (io_addr + 16);
+	portsc2 = inw (io_addr + 18);
+
+	dbg("  usbcmd    =     %04x   %s%s%s%s%s%s%s%s",
+	     usbcmd,
+	     (usbcmd & USBCMD_MAXP) ? "Maxp64 " : "Maxp32 ",
+	     (usbcmd & USBCMD_CF) ? "CF " : "",
+	     (usbcmd & USBCMD_SWDBG) ? "SWDBG " : "",
+	     (usbcmd & USBCMD_FGR) ? "FGR " : "",
+	     (usbcmd & USBCMD_EGSM) ? "EGSM " : "",
+	     (usbcmd & USBCMD_GRESET) ? "GRESET " : "",
+	     (usbcmd & USBCMD_HCRESET) ? "HCRESET " : "",
+	     (usbcmd & USBCMD_RS) ? "RS " : "");
+
+	dbg("  usbstat   =     %04x   %s%s%s%s%s%s",
+	     usbstat,
+	     (usbstat & USBSTS_HCH) ? "HCHalted " : "",
+	     (usbstat & USBSTS_HCPE) ? "HostControllerProcessError " : "",
+	     (usbstat & USBSTS_HSE) ? "HostSystemError " : "",
+	     (usbstat & USBSTS_RD) ? "ResumeDetect " : "",
+	     (usbstat & USBSTS_ERROR) ? "USBError " : "",
+	     (usbstat & USBSTS_USBINT) ? "USBINT " : "");
+
+	dbg("  usbint    =     %04x", usbint);
+	dbg("  usbfrnum  =   (%d)%03x", (usbfrnum >> 10) & 1,
+	     0xfff & (4 * (unsigned int) usbfrnum));
+	dbg("  flbaseadd = %08x", flbaseadd);
+	dbg("  sof       =       %02x", sof);
+	uhci_show_sc (1, portsc1);
+	uhci_show_sc (2, portsc2);
+}
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/host/usb-uhci.c linux-2.4.21-pre6/drivers/usb/host/usb-uhci.c
--- linux-2.4.20/drivers/usb/host/usb-uhci.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/host/usb-uhci.c	2003-03-26 23:49:35.000000000 +0000
@@ -0,0 +1,3143 @@
+/* 
+ * Universal Host Controller Interface driver for USB (take II).
+ *
+ * (c) 1999-2001 Georg Acher, acher@in.tum.de (executive slave) (base guitar)
+ *               Deti Fliegl, deti@fliegl.de (executive slave) (lead voice)
+ *               Thomas Sailer, sailer@ife.ee.ethz.ch (chief consultant) (cheer leader)
+ *               Roman Weissgaerber, weissg@vienna.at (virt root hub) (studio porter)
+ * (c) 2000      Yggdrasil Computing, Inc. (port of new PCI interface support
+ *               from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
+ * (C) 2000      David Brownell, david-b@pacbell.net (usb-ohci.c)
+ *          
+ * HW-initalization based on material of
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999 Johannes Erdfelt
+ * (C) Copyright 1999 Randy Dunlap
+ * (C) Copyright 1999 Gregory P. Smith
+ *
+ * $Id: usb-uhci.c,v 1.275 2002/01/19 20:57:33 acher Exp $
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/interrupt.h>	/* for in_interrupt() */
+#include <linux/init.h>
+#include <linux/version.h>
+#include <linux/pm.h>
+#include <linux/timer.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+/* This enables more detailed sanity checks in submit_iso */
+//#define ISO_SANITY_CHECK
+
+/* This enables debug printks */
+#define DEBUG
+
+/* This enables all symbols to be exported, to ease debugging oopses */
+//#define DEBUG_SYMBOLS
+
+/* This enables an extra UHCI slab for memory debugging */
+#define DEBUG_SLAB
+
+#define VERSTR "$Revision: 1.275 $ time " __TIME__ " " __DATE__
+
+#include <linux/usb.h>
+#include "usb-uhci.h"
+#include "usb-uhci-debug.h"
+
+#include "../hcd.h"
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v1.275"
+#define DRIVER_AUTHOR "Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber"
+#define DRIVER_DESC "USB Universal Host Controller Interface driver"
+
+#undef DEBUG
+#undef dbg
+#define dbg(format, arg...) do {} while (0)
+#define DEBUG_SYMBOLS
+#ifdef DEBUG_SYMBOLS
+	#define _static
+	#ifndef EXPORT_SYMTAB
+		#define EXPORT_SYMTAB
+	#endif
+#else
+	#define _static static
+#endif
+
+#define queue_dbg dbg //err
+#define async_dbg dbg //err
+
+#ifdef DEBUG_SLAB
+	static kmem_cache_t *urb_priv_kmem;
+#endif
+
+#define SLAB_FLAG     (in_interrupt () || current->state != TASK_RUNNING ? SLAB_ATOMIC : SLAB_KERNEL)
+#define KMALLOC_FLAG  (in_interrupt () || current->state != TASK_RUNNING ? GFP_ATOMIC : GFP_KERNEL)
+
+/* CONFIG_USB_UHCI_HIGH_BANDWITH turns on Full Speed Bandwidth
+ * Reclamation: feature that puts loop on descriptor loop when
+ * there's some transfer going on. With FSBR, USB performance
+ * is optimal, but PCI can be slowed down up-to 5 times, slowing down
+ * system performance (eg. framebuffer devices).
+ */
+#define CONFIG_USB_UHCI_HIGH_BANDWIDTH
+
+/* *_DEPTH_FIRST puts descriptor in depth-first mode. This has
+ * somehow similar effect to FSBR (higher speed), but does not
+ * slow PCI down. OTOH USB performace is slightly slower than
+ * in FSBR case and single device could hog whole USB, starving
+ * other devices.
+ */
+#define USE_CTRL_DEPTH_FIRST 0  // 0: Breadth first, 1: Depth first
+#define USE_BULK_DEPTH_FIRST 0  // 0: Breadth first, 1: Depth first
+
+/* Turning off both CONFIG_USB_UHCI_HIGH_BANDWITH and *_DEPTH_FIRST
+ * will lead to <64KB/sec performance over USB for bulk transfers targeting
+ * one device's endpoint. You probably do not want to do that.
+ */
+
+// stop bandwidth reclamation after (roughly) 50ms
+#define IDLE_TIMEOUT  (HZ/20)
+
+// Suppress HC interrupt error messages for 5s
+#define ERROR_SUPPRESSION_TIME (HZ*5)
+
+_static int rh_submit_urb (struct urb *urb);
+_static int rh_unlink_urb (struct urb *urb);
+_static int delete_qh (uhci_t *s, uhci_desc_t *qh);
+_static int process_transfer (uhci_t *s, struct urb *urb, int mode);
+_static int process_interrupt (uhci_t *s, struct urb *urb);
+_static int process_iso (uhci_t *s, struct urb *urb, int force);
+
+// How much URBs with ->next are walked
+#define MAX_NEXT_COUNT 2048
+
+static uhci_t *devs = NULL;
+
+/* used by userspace UHCI data structure dumper */
+uhci_t **uhci_devices = &devs;
+
+/*-------------------------------------------------------------------*/
+// Cleans up collected QHs, but not more than 100 in one go
+void clean_descs(uhci_t *s, int force)
+{
+	struct list_head *q;
+	uhci_desc_t *qh;
+	int now=UHCI_GET_CURRENT_FRAME(s), n=0;
+
+	q=s->free_desc.prev;
+
+	while (q != &s->free_desc && (force || n<100)) {
+		qh = list_entry (q, uhci_desc_t, horizontal);
+		q=qh->horizontal.prev;
+
+		if ((qh->last_used!=now) || force)
+			delete_qh(s,qh);
+		n++;
+	}
+}
+/*-------------------------------------------------------------------*/
+_static void uhci_switch_timer_int(uhci_t *s)
+{
+
+	if (!list_empty(&s->urb_unlinked))
+		set_td_ioc(s->td1ms);
+	else
+		clr_td_ioc(s->td1ms);
+
+	if (s->timeout_urbs)
+		set_td_ioc(s->td32ms);
+	else
+		clr_td_ioc(s->td32ms);
+	wmb();
+}
+/*-------------------------------------------------------------------*/
+#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
+_static void enable_desc_loop(uhci_t *s, struct urb *urb)
+{
+	unsigned long flags;
+
+	if (urb->transfer_flags & USB_NO_FSBR)
+		return;
+
+	spin_lock_irqsave (&s->qh_lock, flags);
+	s->chain_end->hw.qh.head&=cpu_to_le32(~UHCI_PTR_TERM);
+	mb();
+	s->loop_usage++;
+	((urb_priv_t*)urb->hcpriv)->use_loop=1;
+	spin_unlock_irqrestore (&s->qh_lock, flags);
+}
+/*-------------------------------------------------------------------*/
+_static void disable_desc_loop(uhci_t *s, struct urb *urb)
+{
+	unsigned long flags;
+
+	if (urb->transfer_flags & USB_NO_FSBR)
+		return;
+
+	spin_lock_irqsave (&s->qh_lock, flags);
+	if (((urb_priv_t*)urb->hcpriv)->use_loop) {
+		s->loop_usage--;
+
+		if (!s->loop_usage) {
+			s->chain_end->hw.qh.head|=cpu_to_le32(UHCI_PTR_TERM);
+			mb();
+		}
+		((urb_priv_t*)urb->hcpriv)->use_loop=0;
+	}
+	spin_unlock_irqrestore (&s->qh_lock, flags);
+}
+#endif
+/*-------------------------------------------------------------------*/
+_static void queue_urb_unlocked (uhci_t *s, struct urb *urb)
+{
+	struct list_head *p=&urb->urb_list;
+#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
+	{
+		int type;
+		type=usb_pipetype (urb->pipe);
+
+		if ((type == PIPE_BULK) || (type == PIPE_CONTROL))
+			enable_desc_loop(s, urb);
+	}
+#endif
+	urb->status = -EINPROGRESS;
+	((urb_priv_t*)urb->hcpriv)->started=jiffies;
+	list_add (p, &s->urb_list);
+	if (urb->timeout)
+		s->timeout_urbs++;
+	uhci_switch_timer_int(s);
+}
+/*-------------------------------------------------------------------*/
+_static void queue_urb (uhci_t *s, struct urb *urb)
+{
+	unsigned long flags=0;
+
+	spin_lock_irqsave (&s->urb_list_lock, flags);
+	queue_urb_unlocked(s,urb);
+	spin_unlock_irqrestore (&s->urb_list_lock, flags);
+}
+/*-------------------------------------------------------------------*/
+_static void dequeue_urb (uhci_t *s, struct urb *urb)
+{
+#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
+	int type;
+
+	type=usb_pipetype (urb->pipe);
+
+	if ((type == PIPE_BULK) || (type == PIPE_CONTROL))
+		disable_desc_loop(s, urb);
+#endif
+
+	list_del (&urb->urb_list);
+	if (urb->timeout && s->timeout_urbs)
+		s->timeout_urbs--;
+
+}
+/*-------------------------------------------------------------------*/
+_static int alloc_td (uhci_t *s, uhci_desc_t ** new, int flags)
+{
+	dma_addr_t dma_handle;
+
+	*new = pci_pool_alloc(s->desc_pool, GFP_DMA | GFP_ATOMIC, &dma_handle);
+	if (!*new)
+		return -ENOMEM;
+	memset (*new, 0, sizeof (uhci_desc_t));
+	(*new)->dma_addr = dma_handle;
+	set_td_link((*new), UHCI_PTR_TERM | (flags & UHCI_PTR_BITS));	// last by default
+	(*new)->type = TD_TYPE;
+	mb();
+	INIT_LIST_HEAD (&(*new)->vertical);
+	INIT_LIST_HEAD (&(*new)->horizontal);
+	
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+// append a qh to td.link physically, the SW linkage is not affected
+_static void append_qh(uhci_t *s, uhci_desc_t *td, uhci_desc_t* qh, int  flags)
+{
+	unsigned long xxx;
+	
+	spin_lock_irqsave (&s->td_lock, xxx);
+
+	set_td_link(td, qh->dma_addr | (flags & UHCI_PTR_DEPTH) | UHCI_PTR_QH);
+       
+	mb();
+	spin_unlock_irqrestore (&s->td_lock, xxx);
+}
+/*-------------------------------------------------------------------*/
+/* insert td at last position in td-list of qh (vertical) */
+_static int insert_td (uhci_t *s, uhci_desc_t *qh, uhci_desc_t* new, int flags)
+{
+	uhci_desc_t *prev;
+	unsigned long xxx;
+	
+	spin_lock_irqsave (&s->td_lock, xxx);
+
+	list_add_tail (&new->vertical, &qh->vertical);
+
+	prev = list_entry (new->vertical.prev, uhci_desc_t, vertical);
+
+	if (qh == prev ) {
+		// virgin qh without any tds
+		set_qh_element(qh, new->dma_addr | UHCI_PTR_TERM);
+	}
+	else {
+		// already tds inserted, implicitely remove TERM bit of prev
+		set_td_link(prev, new->dma_addr | (flags & UHCI_PTR_DEPTH));
+	}
+	mb();
+	spin_unlock_irqrestore (&s->td_lock, xxx);
+	
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+/* insert new_td after td (horizontal) */
+_static int insert_td_horizontal (uhci_t *s, uhci_desc_t *td, uhci_desc_t* new)
+{
+	uhci_desc_t *next;
+	unsigned long flags;
+	
+	spin_lock_irqsave (&s->td_lock, flags);
+
+	next = list_entry (td->horizontal.next, uhci_desc_t, horizontal);
+	list_add (&new->horizontal, &td->horizontal);
+	new->hw.td.link = td->hw.td.link;
+	set_td_link(td, new->dma_addr);
+	mb();
+	spin_unlock_irqrestore (&s->td_lock, flags);	
+	
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+_static int unlink_td (uhci_t *s, uhci_desc_t *element, int phys_unlink)
+{
+	uhci_desc_t *next, *prev;
+	int dir = 0;
+	unsigned long flags;
+	
+	spin_lock_irqsave (&s->td_lock, flags);
+	
+	next = list_entry (element->vertical.next, uhci_desc_t, vertical);
+	
+	if (next == element) {
+		dir = 1;
+		prev = list_entry (element->horizontal.prev, uhci_desc_t, horizontal);
+	}
+	else 
+		prev = list_entry (element->vertical.prev, uhci_desc_t, vertical);
+	
+	if (phys_unlink) {
+		// really remove HW linking
+		if (prev->type == TD_TYPE)
+			prev->hw.td.link = element->hw.td.link;
+		else
+			prev->hw.qh.element = element->hw.td.link;
+	}
+
+	mb ();
+
+	if (dir == 0)
+		list_del (&element->vertical);
+	else
+		list_del (&element->horizontal);
+	
+	spin_unlock_irqrestore (&s->td_lock, flags);	
+	
+	return 0;
+}
+
+/*-------------------------------------------------------------------*/
+_static int delete_desc (uhci_t *s, uhci_desc_t *element)
+{
+	pci_pool_free(s->desc_pool, element, element->dma_addr);
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+// Allocates qh element
+_static int alloc_qh (uhci_t *s, uhci_desc_t ** new)
+{
+	dma_addr_t dma_handle;
+
+	*new = pci_pool_alloc(s->desc_pool, GFP_DMA | GFP_ATOMIC, &dma_handle);
+	if (!*new)
+		return -ENOMEM;
+	memset (*new, 0, sizeof (uhci_desc_t));
+	(*new)->dma_addr = dma_handle;
+	set_qh_head(*new, UHCI_PTR_TERM);
+	set_qh_element(*new, UHCI_PTR_TERM);
+	(*new)->type = QH_TYPE;
+	
+	mb();
+	INIT_LIST_HEAD (&(*new)->horizontal);
+	INIT_LIST_HEAD (&(*new)->vertical);
+	
+	dbg("Allocated qh @ %p", *new);
+	
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+// inserts new qh before/after the qh at pos
+// flags: 0: insert before pos, 1: insert after pos (for low speed transfers)
+_static int insert_qh (uhci_t *s, uhci_desc_t *pos, uhci_desc_t *new, int order)
+{
+	uhci_desc_t *old;
+	unsigned long flags;
+
+	spin_lock_irqsave (&s->qh_lock, flags);
+
+	if (!order) {
+		// (OLD) (POS) -> (OLD) (NEW) (POS)
+		old = list_entry (pos->horizontal.prev, uhci_desc_t, horizontal);
+		list_add_tail (&new->horizontal, &pos->horizontal);
+		set_qh_head(new, MAKE_QH_ADDR (pos)) ;
+		if (!(old->hw.qh.head & cpu_to_le32(UHCI_PTR_TERM)))
+			set_qh_head(old, MAKE_QH_ADDR (new)) ;
+	}
+	else {
+		// (POS) (OLD) -> (POS) (NEW) (OLD)
+		old = list_entry (pos->horizontal.next, uhci_desc_t, horizontal);
+		list_add (&new->horizontal, &pos->horizontal);
+		set_qh_head(new, MAKE_QH_ADDR (old));
+		set_qh_head(pos, MAKE_QH_ADDR (new)) ;
+	}
+
+	mb ();
+	
+	spin_unlock_irqrestore (&s->qh_lock, flags);
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------*/
+_static int unlink_qh (uhci_t *s, uhci_desc_t *element)
+{
+	uhci_desc_t  *prev;
+	unsigned long flags;
+
+	spin_lock_irqsave (&s->qh_lock, flags);
+	
+	prev = list_entry (element->horizontal.prev, uhci_desc_t, horizontal);
+	prev->hw.qh.head = element->hw.qh.head;
+
+	dbg("unlink qh %p, pqh %p, nxqh %p, to %08x", element, prev, 
+	    list_entry (element->horizontal.next, uhci_desc_t, horizontal),le32_to_cpu(element->hw.qh.head) &~15);
+	
+	list_del(&element->horizontal);
+
+	mb ();
+	spin_unlock_irqrestore (&s->qh_lock, flags);
+	
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+_static int delete_qh (uhci_t *s, uhci_desc_t *qh)
+{
+	uhci_desc_t *td;
+	struct list_head *p;
+	
+	list_del (&qh->horizontal);
+
+	while ((p = qh->vertical.next) != &qh->vertical) {
+		td = list_entry (p, uhci_desc_t, vertical);
+		dbg("unlink td @ %p",td);
+		unlink_td (s, td, 0); // no physical unlink
+		delete_desc (s, td);
+	}
+
+	delete_desc (s, qh);
+	
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+_static void clean_td_chain (uhci_t *s, uhci_desc_t *td)
+{
+	struct list_head *p;
+	uhci_desc_t *td1;
+
+	if (!td)
+		return;
+	
+	while ((p = td->horizontal.next) != &td->horizontal) {
+		td1 = list_entry (p, uhci_desc_t, horizontal);
+		delete_desc (s, td1);
+	}
+	
+	delete_desc (s, td);
+}
+
+/*-------------------------------------------------------------------*/
+_static void fill_td (uhci_desc_t *td, int status, int info, __u32 buffer)
+{
+	td->hw.td.status = cpu_to_le32(status);
+	td->hw.td.info = cpu_to_le32(info);
+	td->hw.td.buffer = cpu_to_le32(buffer);
+}
+/*-------------------------------------------------------------------*/
+// Removes ALL qhs in chain (paranoia!)
+_static void cleanup_skel (uhci_t *s)
+{
+	unsigned int n;
+	uhci_desc_t *td;
+
+	dbg("cleanup_skel");
+
+	clean_descs(s,1);
+
+	
+	if (s->td32ms) {
+	
+		unlink_td(s,s->td32ms,1);
+		delete_desc(s, s->td32ms);
+	}
+
+	for (n = 0; n < 8; n++) {
+		td = s->int_chain[n];
+		clean_td_chain (s, td);
+	}
+
+	if (s->iso_td) {
+		for (n = 0; n < 1024; n++) {
+			td = s->iso_td[n];
+			clean_td_chain (s, td);
+		}
+		kfree (s->iso_td);
+	}
+
+	if (s->framelist)
+		pci_free_consistent(s->uhci_pci, PAGE_SIZE,
+				    s->framelist, s->framelist_dma);
+
+	if (s->control_chain) {
+		// completed init_skel?
+		struct list_head *p;
+		uhci_desc_t *qh, *qh1;
+
+		qh = s->control_chain;
+		while ((p = qh->horizontal.next) != &qh->horizontal) {
+			qh1 = list_entry (p, uhci_desc_t, horizontal);
+			delete_qh (s, qh1);
+		}
+
+		delete_qh (s, qh);
+	}
+	else {
+		if (s->ls_control_chain)
+			delete_desc (s, s->ls_control_chain);
+		if (s->control_chain)
+			delete_desc (s, s->control_chain);
+		if (s->bulk_chain)
+			delete_desc (s, s->bulk_chain);
+		if (s->chain_end)
+			delete_desc (s, s->chain_end);
+	}
+
+	if (s->desc_pool) {
+		pci_pool_destroy(s->desc_pool);
+		s->desc_pool = NULL;
+	}
+
+	dbg("cleanup_skel finished");	
+}
+/*-------------------------------------------------------------------*/
+// allocates framelist and qh-skeletons
+// only HW-links provide continous linking, SW-links stay in their domain (ISO/INT)
+_static int init_skel (uhci_t *s)
+{
+	int n, ret;
+	uhci_desc_t *qh, *td;
+	
+	dbg("init_skel");
+	
+	s->framelist = pci_alloc_consistent(s->uhci_pci, PAGE_SIZE,
+					    &s->framelist_dma);
+
+	if (!s->framelist)
+		return -ENOMEM;
+
+	memset (s->framelist, 0, 4096);
+
+	dbg("creating descriptor pci_pool");
+
+	s->desc_pool = pci_pool_create("uhci_desc", s->uhci_pci,
+				       sizeof(uhci_desc_t), 16, 0,
+				       GFP_DMA | GFP_ATOMIC);	
+	if (!s->desc_pool)
+		goto init_skel_cleanup;
+
+	dbg("allocating iso desc pointer list");
+	s->iso_td = (uhci_desc_t **) kmalloc (1024 * sizeof (uhci_desc_t*), GFP_KERNEL);
+	
+	if (!s->iso_td)
+		goto init_skel_cleanup;
+
+	s->ls_control_chain = NULL;
+	s->control_chain = NULL;
+	s->bulk_chain = NULL;
+	s->chain_end = NULL;
+
+	dbg("allocating iso descs");
+	for (n = 0; n < 1024; n++) {
+	 	// allocate skeleton iso/irq-tds
+		if (alloc_td (s, &td, 0))
+			goto init_skel_cleanup;
+
+		s->iso_td[n] = td;
+		s->framelist[n] = cpu_to_le32((__u32) td->dma_addr);
+	}
+
+	dbg("allocating qh: chain_end");
+	if (alloc_qh (s, &qh))	
+		goto init_skel_cleanup;
+				
+	s->chain_end = qh;
+
+	if (alloc_td (s, &td, 0))
+		goto init_skel_cleanup;
+	
+	fill_td (td, 0 * TD_CTRL_IOC, 0, 0); // generate 1ms interrupt (enabled on demand)
+	insert_td (s, qh, td, 0);
+	qh->hw.qh.element &= cpu_to_le32(~UHCI_PTR_TERM); // remove TERM bit
+	s->td1ms=td;
+
+	dbg("allocating qh: bulk_chain");
+	if (alloc_qh (s, &qh))
+		goto init_skel_cleanup;
+	
+	insert_qh (s, s->chain_end, qh, 0);
+	s->bulk_chain = qh;
+
+	dbg("allocating qh: control_chain");
+	ret = alloc_qh (s, &qh);
+	if (ret)
+		goto init_skel_cleanup;
+	
+	insert_qh (s, s->bulk_chain, qh, 0);
+	s->control_chain = qh;
+
+#ifdef	CONFIG_USB_UHCI_HIGH_BANDWIDTH
+	// disabled reclamation loop
+	set_qh_head(s->chain_end, s->control_chain->dma_addr | UHCI_PTR_QH | UHCI_PTR_TERM);
+#endif
+
+	dbg("allocating qh: ls_control_chain");
+	if (alloc_qh (s, &qh))
+		goto init_skel_cleanup;
+	
+	insert_qh (s, s->control_chain, qh, 0);
+	s->ls_control_chain = qh;
+
+	for (n = 0; n < 8; n++)
+		s->int_chain[n] = 0;
+
+	dbg("allocating skeleton INT-TDs");
+	
+	for (n = 0; n < 8; n++) {
+		uhci_desc_t *td;
+
+		if (alloc_td (s, &td, 0))
+			goto init_skel_cleanup;
+
+		s->int_chain[n] = td;
+		if (n == 0) {
+			set_td_link(s->int_chain[0], s->ls_control_chain->dma_addr | UHCI_PTR_QH);
+		}
+		else {
+			set_td_link(s->int_chain[n], s->int_chain[0]->dma_addr);
+		}
+	}
+
+	dbg("Linking skeleton INT-TDs");
+	
+	for (n = 0; n < 1024; n++) {
+		// link all iso-tds to the interrupt chains
+		int m, o;
+		dbg("framelist[%i]=%x",n,le32_to_cpu(s->framelist[n]));
+		if ((n&127)==127) 
+			((uhci_desc_t*) s->iso_td[n])->hw.td.link = cpu_to_le32(s->int_chain[0]->dma_addr);
+		else 
+			for (o = 1, m = 2; m <= 128; o++, m += m)
+				if ((n & (m - 1)) == ((m - 1) / 2))
+					set_td_link(((uhci_desc_t*) s->iso_td[n]), s->int_chain[o]->dma_addr);
+	}
+
+	if (alloc_td (s, &td, 0))
+		goto init_skel_cleanup;
+	
+	fill_td (td, 0 * TD_CTRL_IOC, 0, 0); // generate 32ms interrupt (activated later)
+	s->td32ms=td;
+
+	insert_td_horizontal (s, s->int_chain[5], td);
+
+	mb();
+	//uhci_show_queue(s->control_chain);   
+	dbg("init_skel exit");
+	return 0;
+
+      init_skel_cleanup:
+	cleanup_skel (s);
+	return -ENOMEM;
+}
+
+/*-------------------------------------------------------------------*/
+//                         LOW LEVEL STUFF
+//          assembles QHs und TDs for control, bulk and iso
+/*-------------------------------------------------------------------*/
+_static int uhci_submit_control_urb (struct urb *urb)
+{
+	uhci_desc_t *qh, *td;
+	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
+	urb_priv_t *urb_priv = urb->hcpriv;
+	unsigned long destination, status;
+	int maxsze = usb_maxpacket (urb->dev, urb->pipe, usb_pipeout (urb->pipe));
+	unsigned long len;
+	char *data;
+	int depth_first=USE_CTRL_DEPTH_FIRST;  // UHCI descriptor chasing method
+
+	dbg("uhci_submit_control start");
+	if (alloc_qh (s, &qh))		// alloc qh for this request
+		return -ENOMEM;
+
+	if (alloc_td (s, &td, UHCI_PTR_DEPTH * depth_first))		// get td for setup stage
+	{
+		delete_qh (s, qh);
+		return -ENOMEM;
+	}
+
+	/* The "pipe" thing contains the destination in bits 8--18 */
+	destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
+
+	/* 3 errors */
+	status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE |
+		(urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27);
+
+	/*  Build the TD for the control request, try forever, 8 bytes of data */
+	fill_td (td, status, destination | (7 << 21), urb_priv->setup_packet_dma);
+
+	insert_td (s, qh, td, 0);	// queue 'setup stage'-td in qh
+#if 0
+	{
+		char *sp=urb->setup_packet;
+		dbg("SETUP to pipe %x: %x %x %x %x %x %x %x %x", urb->pipe,
+		    sp[0],sp[1],sp[2],sp[3],sp[4],sp[5],sp[6],sp[7]);
+	}
+	//uhci_show_td(td);
+#endif
+
+	len = urb->transfer_buffer_length;
+	data = urb->transfer_buffer;
+
+	/* If direction is "send", change the frame from SETUP (0x2D)
+	   to OUT (0xE1). Else change it from SETUP to IN (0x69). */
+
+	destination = (urb->pipe & PIPE_DEVEP_MASK) | (usb_pipeout (urb->pipe)?USB_PID_OUT:USB_PID_IN);
+
+	while (len > 0) {
+		int pktsze = len;
+
+		if (alloc_td (s, &td, UHCI_PTR_DEPTH * depth_first))
+			goto fail_unmap_enomem;
+
+		if (pktsze > maxsze)
+			pktsze = maxsze;
+
+		destination ^= 1 << TD_TOKEN_TOGGLE;	// toggle DATA0/1
+
+		// Status, pktsze bytes of data
+		fill_td (td, status, destination | ((pktsze - 1) << 21),
+			 urb_priv->transfer_buffer_dma + (data - (char *)urb->transfer_buffer));
+
+		insert_td (s, qh, td, UHCI_PTR_DEPTH * depth_first);	// queue 'data stage'-td in qh
+
+		data += pktsze;
+		len -= pktsze;
+	}
+
+	/* Build the final TD for control status */
+	/* It's only IN if the pipe is out AND we aren't expecting data */
+
+	destination &= ~UHCI_PID;
+
+	if (usb_pipeout (urb->pipe) || (urb->transfer_buffer_length == 0))
+		destination |= USB_PID_IN;
+	else
+		destination |= USB_PID_OUT;
+
+	destination |= 1 << TD_TOKEN_TOGGLE;	/* End in Data1 */
+
+	if (alloc_td (s, &td, UHCI_PTR_DEPTH))
+		goto fail_unmap_enomem;
+
+	status &=~TD_CTRL_SPD;
+
+	/* no limit on errors on final packet , 0 bytes of data */
+	fill_td (td, status | TD_CTRL_IOC, destination | (UHCI_NULL_DATA_SIZE << 21),
+		 0);
+
+	insert_td (s, qh, td, UHCI_PTR_DEPTH * depth_first);	// queue status td
+
+	list_add (&qh->desc_list, &urb_priv->desc_list);
+
+	queue_urb (s, urb);	// queue before inserting in desc chain
+
+	qh->hw.qh.element &= cpu_to_le32(~UHCI_PTR_TERM);
+
+	//uhci_show_queue(qh);
+	/* Start it up... put low speed first */
+	if (urb->pipe & TD_CTRL_LS)
+		insert_qh (s, s->control_chain, qh, 0);
+	else
+		insert_qh (s, s->bulk_chain, qh, 0);
+
+	dbg("uhci_submit_control end");
+	return 0;
+
+fail_unmap_enomem:
+	delete_qh(s, qh);
+	return -ENOMEM;
+}
+/*-------------------------------------------------------------------*/
+// For queued bulk transfers, two additional QH helpers are allocated (nqh, bqh)
+// Due to the linking with other bulk urbs, it has to be locked with urb_list_lock!
+
+_static int uhci_submit_bulk_urb (struct urb *urb, struct urb *bulk_urb)
+{
+	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
+	urb_priv_t *urb_priv = urb->hcpriv, *upriv, *bpriv=NULL;
+	uhci_desc_t *qh, *td, *nqh=NULL, *bqh=NULL, *first_td=NULL;
+	unsigned long destination, status;
+	char *data;
+	unsigned int pipe = urb->pipe;
+	int maxsze = usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe));
+	int info, len, last;
+	int depth_first=USE_BULK_DEPTH_FIRST;  // UHCI descriptor chasing method
+
+	if (usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)))
+		return -EPIPE;
+
+	queue_dbg("uhci_submit_bulk_urb: urb %p, old %p, pipe %08x, len %i",
+		  urb,bulk_urb,urb->pipe,urb->transfer_buffer_length);
+
+	upriv = (urb_priv_t*)urb->hcpriv;
+
+	if (!bulk_urb) {
+		if (alloc_qh (s, &qh))		// get qh for this request
+			return -ENOMEM;
+
+		if (urb->transfer_flags & USB_QUEUE_BULK) {
+			if (alloc_qh(s, &nqh)) // placeholder for clean unlink
+			{
+				delete_desc (s, qh);
+				return -ENOMEM;
+			}
+			upriv->next_qh = nqh;
+			queue_dbg("new next qh %p",nqh);
+		}
+	}
+	else { 
+		bpriv = (urb_priv_t*)bulk_urb->hcpriv;
+		qh = bpriv->bottom_qh;  // re-use bottom qh and next qh
+		nqh = bpriv->next_qh;
+		upriv->next_qh=nqh;	
+		upriv->prev_queued_urb=bulk_urb;
+	}
+
+	if (urb->transfer_flags & USB_QUEUE_BULK) {
+		if (alloc_qh (s, &bqh))  // "bottom" QH
+		{
+			if (!bulk_urb) { 
+				delete_desc(s, qh);
+				delete_desc(s, nqh);
+			}
+			return -ENOMEM;
+		}
+		set_qh_element(bqh, UHCI_PTR_TERM);
+		set_qh_head(bqh, nqh->dma_addr | UHCI_PTR_QH); // element
+		upriv->bottom_qh = bqh;
+	}
+	queue_dbg("uhci_submit_bulk: qh %p bqh %p nqh %p",qh, bqh, nqh);
+
+	/* The "pipe" thing contains the destination in bits 8--18. */
+	destination = (pipe & PIPE_DEVEP_MASK) | usb_packetid (pipe);
+
+	/* 3 errors */
+	status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE |
+		((urb->transfer_flags & USB_DISABLE_SPD) ? 0 : TD_CTRL_SPD) | (3 << 27);
+
+	/* Build the TDs for the bulk request */
+	len = urb->transfer_buffer_length;
+	data = urb->transfer_buffer;
+	
+	do {					// TBD: Really allow zero-length packets?
+		int pktsze = len;
+
+		if (alloc_td (s, &td, UHCI_PTR_DEPTH * depth_first))
+		{
+			delete_qh (s, qh);
+			return -ENOMEM;
+		}
+
+		if (pktsze > maxsze)
+			pktsze = maxsze;
+
+		// pktsze bytes of data 
+		info = destination | (((pktsze - 1)&UHCI_NULL_DATA_SIZE) << 21) |
+			(usb_gettoggle (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)) << TD_TOKEN_TOGGLE);
+
+		fill_td (td, status, info,
+			 urb_priv->transfer_buffer_dma + (data - (char *)urb->transfer_buffer));
+
+		data += pktsze;
+		len -= pktsze;
+		// Use USB_ZERO_PACKET to finish bulk OUTs always with a zero length packet
+		last = (len == 0 && (usb_pipein(pipe) || pktsze < maxsze || !(urb->transfer_flags & USB_ZERO_PACKET)));
+
+		if (last)
+			set_td_ioc(td);	// last one generates INT
+
+		insert_td (s, qh, td, UHCI_PTR_DEPTH * depth_first);
+		if (!first_td)
+			first_td=td;
+		usb_dotoggle (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe));
+
+	} while (!last);
+
+	if (bulk_urb && bpriv)   // everything went OK, link with old bulk URB
+		bpriv->next_queued_urb=urb;
+
+	list_add (&qh->desc_list, &urb_priv->desc_list);
+
+	if (urb->transfer_flags & USB_QUEUE_BULK)
+		append_qh(s, td, bqh, UHCI_PTR_DEPTH * depth_first);
+
+	queue_urb_unlocked (s, urb);
+	
+	if (urb->transfer_flags & USB_QUEUE_BULK)
+		set_qh_element(qh, first_td->dma_addr);
+	else
+		qh->hw.qh.element &= cpu_to_le32(~UHCI_PTR_TERM);    // arm QH
+
+	if (!bulk_urb) { 					// new bulk queue	
+		if (urb->transfer_flags & USB_QUEUE_BULK) {
+			spin_lock (&s->td_lock);		// both QHs in one go
+			insert_qh (s, s->chain_end, qh, 0);	// Main QH
+			insert_qh (s, s->chain_end, nqh, 0);	// Helper QH
+			spin_unlock (&s->td_lock);
+		}
+		else
+			insert_qh (s, s->chain_end, qh, 0);
+	}
+	
+	//uhci_show_queue(s->bulk_chain);
+	//dbg("uhci_submit_bulk_urb: exit\n");
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+_static void uhci_clean_iso_step1(uhci_t *s, urb_priv_t *urb_priv)
+{
+	struct list_head *p;
+	uhci_desc_t *td;
+
+	for (p = urb_priv->desc_list.next; p != &urb_priv->desc_list; p = p->next) {
+				td = list_entry (p, uhci_desc_t, desc_list);
+				unlink_td (s, td, 1);
+	}
+}
+/*-------------------------------------------------------------------*/
+_static void uhci_clean_iso_step2(uhci_t *s, urb_priv_t *urb_priv)
+{
+	struct list_head *p;
+	uhci_desc_t *td;
+
+	while ((p = urb_priv->desc_list.next) != &urb_priv->desc_list) {
+				td = list_entry (p, uhci_desc_t, desc_list);
+				list_del (p);
+				delete_desc (s, td);
+	}
+}
+/*-------------------------------------------------------------------*/
+/* mode: CLEAN_TRANSFER_NO_DELETION: unlink but no deletion mark (step 1 of async_unlink)
+         CLEAN_TRANSFER_REGULAR: regular (unlink/delete-mark)
+         CLEAN_TRANSFER_DELETION_MARK: deletion mark for QH (step 2 of async_unlink)
+ looks a bit complicated because of all the bulk queueing goodies
+*/
+
+_static void uhci_clean_transfer (uhci_t *s, struct urb *urb, uhci_desc_t *qh, int mode)
+{
+	uhci_desc_t *bqh, *nqh, *prevqh, *prevtd;
+	int now;
+	urb_priv_t *priv=(urb_priv_t*)urb->hcpriv;
+
+	now=UHCI_GET_CURRENT_FRAME(s);
+
+	bqh=priv->bottom_qh;	
+	
+	if (!priv->next_queued_urb)  { // no more appended bulk queues
+
+		queue_dbg("uhci_clean_transfer: No more bulks for urb %p, qh %p, bqh %p, nqh %p", urb, qh, bqh, priv->next_qh);	
+	
+		if (priv->prev_queued_urb && mode != CLEAN_TRANSFER_DELETION_MARK) {  // qh not top of the queue
+				unsigned long flags; 
+				urb_priv_t* ppriv=(urb_priv_t*)priv->prev_queued_urb->hcpriv;
+
+				spin_lock_irqsave (&s->qh_lock, flags);
+				prevqh = list_entry (ppriv->desc_list.next, uhci_desc_t, desc_list);
+				prevtd = list_entry (prevqh->vertical.prev, uhci_desc_t, vertical);
+				set_td_link(prevtd, priv->bottom_qh->dma_addr | UHCI_PTR_QH); // skip current qh
+				mb();
+				queue_dbg("uhci_clean_transfer: relink pqh %p, ptd %p",prevqh, prevtd);
+				spin_unlock_irqrestore (&s->qh_lock, flags);
+
+				ppriv->bottom_qh = priv->bottom_qh;
+				ppriv->next_queued_urb = NULL;
+			}
+		else {   // queue is dead, qh is top of the queue
+			
+			if (mode != CLEAN_TRANSFER_DELETION_MARK) 				
+				unlink_qh(s, qh); // remove qh from horizontal chain
+
+			if (bqh) {  // remove remainings of bulk queue
+				nqh=priv->next_qh;
+
+				if (mode != CLEAN_TRANSFER_DELETION_MARK) 
+					unlink_qh(s, nqh);  // remove nqh from horizontal chain
+				
+				if (mode != CLEAN_TRANSFER_NO_DELETION) {  // add helper QHs to free desc list
+					nqh->last_used = bqh->last_used = now;
+					list_add_tail (&nqh->horizontal, &s->free_desc);
+					list_add_tail (&bqh->horizontal, &s->free_desc);
+				}			
+			}
+		}
+	}
+	else { // there are queued urbs following
+	
+	  queue_dbg("uhci_clean_transfer: urb %p, prevurb %p, nexturb %p, qh %p, bqh %p, nqh %p",
+		       urb, priv->prev_queued_urb,  priv->next_queued_urb, qh, bqh, priv->next_qh);	
+       	
+		if (mode != CLEAN_TRANSFER_DELETION_MARK) {	// no work for cleanup at unlink-completion
+			struct urb *nurb;
+			unsigned long flags;
+
+			nurb = priv->next_queued_urb;
+			spin_lock_irqsave (&s->qh_lock, flags);		
+
+			if (!priv->prev_queued_urb) { // top QH
+				
+				prevqh = list_entry (qh->horizontal.prev, uhci_desc_t, horizontal);
+				set_qh_head(prevqh, bqh->dma_addr | UHCI_PTR_QH);
+				list_del (&qh->horizontal);  // remove this qh form horizontal chain
+				list_add (&bqh->horizontal, &prevqh->horizontal); // insert next bqh in horizontal chain
+			}
+			else {		// intermediate QH
+				urb_priv_t* ppriv=(urb_priv_t*)priv->prev_queued_urb->hcpriv;
+				urb_priv_t* npriv=(urb_priv_t*)nurb->hcpriv;
+				uhci_desc_t * bnqh;
+				
+				bnqh = list_entry (npriv->desc_list.next, uhci_desc_t, desc_list);
+				ppriv->bottom_qh = bnqh;
+				ppriv->next_queued_urb = nurb;				
+				prevqh = list_entry (ppriv->desc_list.next, uhci_desc_t, desc_list);
+				set_qh_head(prevqh, bqh->dma_addr | UHCI_PTR_QH);
+			}
+
+			mb();
+			((urb_priv_t*)nurb->hcpriv)->prev_queued_urb=priv->prev_queued_urb;
+			spin_unlock_irqrestore (&s->qh_lock, flags);
+		}		
+	}
+
+	if (mode != CLEAN_TRANSFER_NO_DELETION) {
+		qh->last_used = now;	
+		list_add_tail (&qh->horizontal, &s->free_desc); // mark qh for later deletion/kfree
+	}
+}
+/*-------------------------------------------------------------------*/
+// Release bandwidth for Interrupt or Isoc. transfers 
+_static void uhci_release_bandwidth(struct urb *urb)
+{       
+	if (urb->bandwidth) {
+		switch (usb_pipetype(urb->pipe)) {
+		case PIPE_INTERRUPT:
+			usb_release_bandwidth (urb->dev, urb, 0);
+			break;
+		case PIPE_ISOCHRONOUS:
+			usb_release_bandwidth (urb->dev, urb, 1);
+			break;
+		default:
+			break;
+		}
+	}	
+}
+
+_static void uhci_urb_dma_sync(uhci_t *s, struct urb *urb, urb_priv_t *urb_priv)
+{
+	if (urb_priv->setup_packet_dma)
+		pci_dma_sync_single(s->uhci_pci, urb_priv->setup_packet_dma,
+				    sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE);
+
+	if (urb_priv->transfer_buffer_dma)
+		pci_dma_sync_single(s->uhci_pci, urb_priv->transfer_buffer_dma,
+				    urb->transfer_buffer_length,
+				    usb_pipein(urb->pipe) ?
+				    PCI_DMA_FROMDEVICE :
+				    PCI_DMA_TODEVICE);
+}
+
+_static void uhci_urb_dma_unmap(uhci_t *s, struct urb *urb, urb_priv_t *urb_priv)
+{
+	if (urb_priv->setup_packet_dma) {
+		pci_unmap_single(s->uhci_pci, urb_priv->setup_packet_dma,
+				 sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE);
+		urb_priv->setup_packet_dma = 0;
+	}
+	if (urb_priv->transfer_buffer_dma) {
+		pci_unmap_single(s->uhci_pci, urb_priv->transfer_buffer_dma,
+				 urb->transfer_buffer_length,
+				 usb_pipein(urb->pipe) ?
+				 PCI_DMA_FROMDEVICE :
+				 PCI_DMA_TODEVICE);
+		urb_priv->transfer_buffer_dma = 0;
+	}
+}
+/*-------------------------------------------------------------------*/
+/* needs urb_list_lock!
+   mode: UNLINK_ASYNC_STORE_URB: unlink and move URB into unlinked list
+         UNLINK_ASYNC_DONT_STORE: unlink, don't move URB into unlinked list
+*/
+_static int uhci_unlink_urb_async (uhci_t *s,struct urb *urb, int mode)
+{
+	uhci_desc_t *qh;
+	urb_priv_t *urb_priv;
+	
+	async_dbg("unlink_urb_async called %p",urb);
+
+	if ((urb->status == -EINPROGRESS) ||
+	    ((usb_pipetype (urb->pipe) ==  PIPE_INTERRUPT) && ((urb_priv_t*)urb->hcpriv)->flags))
+	{
+		((urb_priv_t*)urb->hcpriv)->started = ~0;  // mark
+		dequeue_urb (s, urb);
+
+		if (mode==UNLINK_ASYNC_STORE_URB)
+			list_add_tail (&urb->urb_list, &s->urb_unlinked); // store urb
+
+		uhci_switch_timer_int(s);
+       		s->unlink_urb_done = 1;
+		uhci_release_bandwidth(urb);
+
+		urb->status = -ECONNABORTED;	// mark urb as "waiting to be killed"	
+		urb_priv = (urb_priv_t*)urb->hcpriv;
+
+		switch (usb_pipetype (urb->pipe)) {
+		case PIPE_INTERRUPT:
+			usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
+
+		case PIPE_ISOCHRONOUS:
+			uhci_clean_iso_step1 (s, urb_priv);
+			break;
+
+		case PIPE_BULK:
+		case PIPE_CONTROL:
+			qh = list_entry (urb_priv->desc_list.next, uhci_desc_t, desc_list);
+			uhci_clean_transfer (s, urb, qh, CLEAN_TRANSFER_NO_DELETION);
+			break;
+		}
+		((urb_priv_t*)urb->hcpriv)->started = UHCI_GET_CURRENT_FRAME(s);
+		return -EINPROGRESS;  // completion will follow
+	}		
+
+	return 0;    // URB already dead
+}
+/*-------------------------------------------------------------------*/
+// kills an urb by unlinking descriptors and waiting for at least one frame
+_static int uhci_unlink_urb_sync (uhci_t *s, struct urb *urb)
+{
+	uhci_desc_t *qh;
+	urb_priv_t *urb_priv;
+	unsigned long flags=0;
+	struct usb_device *usb_dev;
+
+	spin_lock_irqsave (&s->urb_list_lock, flags);
+
+	if (urb->status == -EINPROGRESS) {
+
+		// move descriptors out of the running chains, dequeue urb
+		uhci_unlink_urb_async(s, urb, UNLINK_ASYNC_DONT_STORE);
+
+		urb_priv = urb->hcpriv;
+		urb->status = -ENOENT;	// prevent from double deletion after unlock		
+		spin_unlock_irqrestore (&s->urb_list_lock, flags);
+		
+		// cleanup the rest
+		switch (usb_pipetype (urb->pipe)) {
+
+		case PIPE_INTERRUPT:
+		case PIPE_ISOCHRONOUS:
+			uhci_wait_ms(1);
+			uhci_clean_iso_step2(s, urb_priv);
+			break;
+
+		case PIPE_BULK:
+		case PIPE_CONTROL:
+			qh = list_entry (urb_priv->desc_list.next, uhci_desc_t, desc_list);
+			uhci_clean_transfer(s, urb, qh, CLEAN_TRANSFER_DELETION_MARK);
+			uhci_wait_ms(1);
+		}
+		urb->status = -ENOENT;	// mark urb as killed		
+					
+		uhci_urb_dma_unmap(s, urb, urb->hcpriv);
+
+#ifdef DEBUG_SLAB
+		kmem_cache_free (urb_priv_kmem, urb->hcpriv);
+#else
+		kfree (urb->hcpriv);
+#endif
+		usb_dev = urb->dev;
+		if (urb->complete) {
+			dbg("unlink_urb: calling completion");
+			urb->dev = NULL;
+			urb->complete ((struct urb *) urb);
+		}
+		usb_dec_dev_use (usb_dev);
+	}
+	else
+		spin_unlock_irqrestore (&s->urb_list_lock, flags);
+
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+// async unlink_urb completion/cleanup work
+// has to be protected by urb_list_lock!
+// features: if set in transfer_flags, the resulting status of the killed
+// transaction is not overwritten
+
+_static void uhci_cleanup_unlink(uhci_t *s, int force)
+{
+	struct list_head *q;
+	struct urb *urb;
+	struct usb_device *dev;
+	int now, type;
+	urb_priv_t *urb_priv;
+
+	q=s->urb_unlinked.next;
+	now=UHCI_GET_CURRENT_FRAME(s);
+
+	while (q != &s->urb_unlinked) {
+
+		urb = list_entry (q, struct urb, urb_list);
+
+		urb_priv = (urb_priv_t*)urb->hcpriv;
+		q = urb->urb_list.next;
+		
+		if (!urb_priv) // avoid crash when URB is corrupted
+			break;
+			
+		if (force || ((urb_priv->started != ~0) && (urb_priv->started != now))) {
+			async_dbg("async cleanup %p",urb);
+			type=usb_pipetype (urb->pipe);
+
+			switch (type) { // process descriptors
+			case PIPE_CONTROL:
+				process_transfer (s, urb, CLEAN_TRANSFER_DELETION_MARK);  // don't unlink (already done)
+				break;
+			case PIPE_BULK:
+				if (!s->avoid_bulk.counter)
+					process_transfer (s, urb, CLEAN_TRANSFER_DELETION_MARK); // don't unlink (already done)
+				else
+					continue;
+				break;
+			case PIPE_ISOCHRONOUS:
+				process_iso (s, urb, PROCESS_ISO_FORCE); // force, don't unlink
+				break;
+			case PIPE_INTERRUPT:
+				process_interrupt (s, urb);
+				break;
+			}
+
+			if (!(urb->transfer_flags & USB_TIMEOUT_KILLED))
+		  		urb->status = -ECONNRESET; // mark as asynchronously killed
+
+			dev = urb->dev;	// completion may destroy all...
+			urb_priv = urb->hcpriv;
+			list_del (&urb->urb_list);
+			
+			uhci_urb_dma_sync(s, urb, urb_priv);
+			if (urb->complete) {
+				spin_unlock(&s->urb_list_lock);
+				urb->dev = NULL;
+				urb->complete ((struct urb *) urb);
+				spin_lock(&s->urb_list_lock);
+			}
+
+			if (!(urb->transfer_flags & USB_TIMEOUT_KILLED))
+				urb->status = -ENOENT;  // now the urb is really dead
+
+			switch (type) {
+			case PIPE_ISOCHRONOUS:
+			case PIPE_INTERRUPT:
+				uhci_clean_iso_step2(s, urb_priv);
+				break;
+			}
+	
+			uhci_urb_dma_unmap(s, urb, urb_priv);
+
+			usb_dec_dev_use (dev);
+#ifdef DEBUG_SLAB
+			kmem_cache_free (urb_priv_kmem, urb_priv);
+#else
+			kfree (urb_priv);
+#endif
+
+		}
+	}
+}
+ 
+/*-------------------------------------------------------------------*/
+_static int uhci_unlink_urb (struct urb *urb)
+{
+	uhci_t *s;
+	unsigned long flags=0;
+	dbg("uhci_unlink_urb called for %p",urb);
+	if (!urb || !urb->dev)		// you never know...
+		return -EINVAL;
+	
+	s = (uhci_t*) urb->dev->bus->hcpriv;
+
+	if (usb_pipedevice (urb->pipe) == s->rh.devnum)
+		return rh_unlink_urb (urb);
+
+	if (!urb->hcpriv)
+		return -EINVAL;
+
+	if (urb->transfer_flags & USB_ASYNC_UNLINK) {
+		int ret;
+       		spin_lock_irqsave (&s->urb_list_lock, flags);
+       		
+		uhci_release_bandwidth(urb);
+		ret = uhci_unlink_urb_async(s, urb, UNLINK_ASYNC_STORE_URB);
+
+		spin_unlock_irqrestore (&s->urb_list_lock, flags);	
+		return ret;
+	}
+	else
+		return uhci_unlink_urb_sync(s, urb);
+}
+/*-------------------------------------------------------------------*/
+// In case of ASAP iso transfer, search the URB-list for already queued URBs
+// for this EP and calculate the earliest start frame for the new
+// URB (easy seamless URB continuation!)
+_static int find_iso_limits (struct urb *urb, unsigned int *start, unsigned int *end)
+{
+	struct urb *u, *last_urb = NULL;
+	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
+	struct list_head *p;
+	int ret=-1;
+	unsigned long flags;
+	
+	spin_lock_irqsave (&s->urb_list_lock, flags);
+	p=s->urb_list.prev;
+
+	for (; p != &s->urb_list; p = p->prev) {
+		u = list_entry (p, struct urb, urb_list);
+		// look for pending URBs with identical pipe handle
+		// works only because iso doesn't toggle the data bit!
+		if ((urb->pipe == u->pipe) && (urb->dev == u->dev) && (u->status == -EINPROGRESS)) {
+			if (!last_urb)
+				*start = u->start_frame;
+			last_urb = u;
+		}
+	}
+	
+	if (last_urb) {
+		*end = (last_urb->start_frame + last_urb->number_of_packets) & 1023;
+		ret=0;
+	}
+	
+	spin_unlock_irqrestore(&s->urb_list_lock, flags);
+	
+	return ret;
+}
+/*-------------------------------------------------------------------*/
+// adjust start_frame according to scheduling constraints (ASAP etc)
+
+_static int iso_find_start (struct urb *urb)
+{
+	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
+	unsigned int now;
+	unsigned int start_limit = 0, stop_limit = 0, queued_size;
+	int limits;
+
+	now = UHCI_GET_CURRENT_FRAME (s) & 1023;
+
+	if ((unsigned) urb->number_of_packets > 900)
+		return -EFBIG;
+	
+	limits = find_iso_limits (urb, &start_limit, &stop_limit);
+	queued_size = (stop_limit - start_limit) & 1023;
+
+	if (urb->transfer_flags & USB_ISO_ASAP) {
+		// first iso
+		if (limits) {
+			// 10ms setup should be enough //FIXME!
+			urb->start_frame = (now + 10) & 1023;
+		}
+		else {
+			urb->start_frame = stop_limit;		//seamless linkage
+
+			if (((now - urb->start_frame) & 1023) <= (unsigned) urb->number_of_packets) {
+				info("iso_find_start: gap in seamless isochronous scheduling");
+				dbg("iso_find_start: now %u start_frame %u number_of_packets %u pipe 0x%08x",
+					now, urb->start_frame, urb->number_of_packets, urb->pipe);
+				urb->start_frame = (now + 5) & 1023;	// 5ms setup should be enough //FIXME!
+			}
+		}
+	}
+	else {
+		urb->start_frame &= 1023;
+		if (((now - urb->start_frame) & 1023) < (unsigned) urb->number_of_packets) {
+			dbg("iso_find_start: now between start_frame and end");
+			return -EAGAIN;
+		}
+	}
+
+	/* check if either start_frame or start_frame+number_of_packets-1 lies between start_limit and stop_limit */
+	if (limits)
+		return 0;
+
+	if (((urb->start_frame - start_limit) & 1023) < queued_size ||
+	    ((urb->start_frame + urb->number_of_packets - 1 - start_limit) & 1023) < queued_size) {
+		dbg("iso_find_start: start_frame %u number_of_packets %u start_limit %u stop_limit %u",
+			urb->start_frame, urb->number_of_packets, start_limit, stop_limit);
+		return -EAGAIN;
+	}
+
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+// submits USB interrupt (ie. polling ;-) 
+// ASAP-flag set implicitely
+// if period==0, the transfer is only done once
+
+_static int uhci_submit_int_urb (struct urb *urb)
+{
+	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
+	urb_priv_t *urb_priv = urb->hcpriv;
+	int nint, n;
+	uhci_desc_t *td;
+	int status, destination;
+	int info;
+	unsigned int pipe = urb->pipe;
+
+	if (urb->interval < 0 || urb->interval >= 256)
+		return -EINVAL;
+
+	if (urb->interval == 0)
+		nint = 0;
+	else {
+		for (nint = 0, n = 1; nint <= 8; nint++, n += n)	// round interval down to 2^n
+		 {
+			if (urb->interval < n) {
+				urb->interval = n / 2;
+				break;
+			}
+		}
+		nint--;
+	}
+
+	dbg("Rounded interval to %i, chain  %i", urb->interval, nint);
+
+	urb->start_frame = UHCI_GET_CURRENT_FRAME (s) & 1023;	// remember start frame, just in case...
+
+	urb->number_of_packets = 1;
+
+	// INT allows only one packet
+	if (urb->transfer_buffer_length > usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe)))
+		return -EINVAL;
+
+	if (alloc_td (s, &td, UHCI_PTR_DEPTH))
+		return -ENOMEM;
+
+	status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC |
+		(urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27);
+
+	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid (urb->pipe) |
+		(((urb->transfer_buffer_length - 1) & 0x7ff) << 21);
+
+
+	info = destination | (usb_gettoggle (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)) << TD_TOKEN_TOGGLE);
+
+	fill_td (td, status, info, urb_priv->transfer_buffer_dma);
+	list_add_tail (&td->desc_list, &urb_priv->desc_list);
+
+	queue_urb (s, urb);
+
+	insert_td_horizontal (s, s->int_chain[nint], td);	// store in INT-TDs
+
+	usb_dotoggle (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe));
+
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+_static int uhci_submit_iso_urb (struct urb *urb)
+{
+	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
+	urb_priv_t *urb_priv = urb->hcpriv;
+#ifdef ISO_SANITY_CHECK
+	int pipe=urb->pipe;
+	int maxsze = usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe));
+#endif
+	int n, ret, last=0;
+	uhci_desc_t *td, **tdm;
+	int status, destination;
+	unsigned long flags;
+
+	__save_flags(flags);
+	__cli();		      // Disable IRQs to schedule all ISO-TDs in time
+	ret = iso_find_start (urb);	// adjusts urb->start_frame for later use
+	
+	if (ret)
+		goto err;
+
+	tdm = (uhci_desc_t **) kmalloc (urb->number_of_packets * sizeof (uhci_desc_t*), KMALLOC_FLAG);
+
+	if (!tdm) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	memset(tdm, 0, urb->number_of_packets * sizeof (uhci_desc_t*));
+
+	// First try to get all TDs. Cause: Removing already inserted TDs can only be done 
+	// racefree in three steps: unlink TDs, wait one frame, delete TDs. 
+	// So, this solutions seems simpler...
+
+	for (n = 0; n < urb->number_of_packets; n++) {
+		dbg("n:%d urb->iso_frame_desc[n].length:%d", n, urb->iso_frame_desc[n].length);
+		if (!urb->iso_frame_desc[n].length)
+			continue;  // allows ISO striping by setting length to zero in iso_descriptor
+
+
+#ifdef ISO_SANITY_CHECK
+		if(urb->iso_frame_desc[n].length > maxsze) {
+
+			err("submit_iso: urb->iso_frame_desc[%d].length(%d)>%d",n , urb->iso_frame_desc[n].length, maxsze);
+			ret=-EINVAL;		
+		}
+		else
+#endif
+		if (alloc_td (s, &td, UHCI_PTR_DEPTH)) {
+			int i;	// Cleanup allocated TDs
+
+			for (i = 0; i < n; n++)
+				if (tdm[i])
+					 delete_desc(s, tdm[i]);
+			kfree (tdm);
+			goto err;
+		}
+		last=n;
+		tdm[n] = td;
+	}
+
+	status = TD_CTRL_ACTIVE | TD_CTRL_IOS;
+
+	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid (urb->pipe);
+
+	// Queue all allocated TDs
+	for (n = 0; n < urb->number_of_packets; n++) {
+		td = tdm[n];
+		if (!td)
+			continue;
+			
+		if (n  == last) {
+			status |= TD_CTRL_IOC;
+			queue_urb (s, urb);
+		}
+
+		fill_td (td, status, destination | (((urb->iso_frame_desc[n].length - 1) & 0x7ff) << 21),
+			 urb_priv->transfer_buffer_dma + urb->iso_frame_desc[n].offset);
+		list_add_tail (&td->desc_list, &urb_priv->desc_list);
+	
+		insert_td_horizontal (s, s->iso_td[(urb->start_frame + n) & 1023], td);	// store in iso-tds
+	}
+
+	kfree (tdm);
+	dbg("ISO-INT# %i, start %i, now %i", urb->number_of_packets, urb->start_frame, UHCI_GET_CURRENT_FRAME (s) & 1023);
+	ret = 0;
+
+      err:
+	__restore_flags(flags);
+	return ret;
+}
+/*-------------------------------------------------------------------*/
+// returns: 0 (no transfer queued), urb* (this urb already queued)
+ 
+_static struct urb* search_dev_ep (uhci_t *s, struct urb *urb)
+{
+	struct list_head *p;
+	struct urb *tmp;
+	unsigned int mask = usb_pipecontrol(urb->pipe) ? (~USB_DIR_IN) : (~0);
+
+	dbg("search_dev_ep:");
+
+	p=s->urb_list.next;
+
+	for (; p != &s->urb_list; p = p->next) {
+		tmp = list_entry (p, struct urb, urb_list);
+		dbg("urb: %p", tmp);
+		// we can accept this urb if it is not queued at this time 
+		// or if non-iso transfer requests should be scheduled for the same device and pipe
+		if ((!usb_pipeisoc(urb->pipe) && (tmp->dev == urb->dev) && !((tmp->pipe ^ urb->pipe) & mask)) ||
+		    (urb == tmp)) {
+			return tmp;	// found another urb already queued for processing
+		}
+	}
+
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+_static int uhci_submit_urb (struct urb *urb)
+{
+	uhci_t *s;
+	urb_priv_t *urb_priv;
+	int ret = 0, type;
+	unsigned long flags;
+	struct urb *queued_urb=NULL;
+	int bustime;
+		
+	if (!urb->dev || !urb->dev->bus)
+		return -ENODEV;
+
+	s = (uhci_t*) urb->dev->bus->hcpriv;
+	//dbg("submit_urb: %p type %d",urb,usb_pipetype(urb->pipe));
+	
+	if (!s->running)
+		return -ENODEV;
+	
+	type = usb_pipetype (urb->pipe);
+
+	if (usb_pipedevice (urb->pipe) == s->rh.devnum)
+		return rh_submit_urb (urb);	/* virtual root hub */
+
+	// Sanity checks
+	if (usb_maxpacket (urb->dev, urb->pipe, usb_pipeout (urb->pipe)) <= 0) {		
+		err("uhci_submit_urb: pipesize for pipe %x is zero", urb->pipe);
+		return -EMSGSIZE;
+	}
+
+	if (urb->transfer_buffer_length < 0 && type != PIPE_ISOCHRONOUS) {
+		err("uhci_submit_urb: Negative transfer length for urb %p", urb);
+		return -EINVAL;
+	}
+
+	usb_inc_dev_use (urb->dev);
+
+	spin_lock_irqsave (&s->urb_list_lock, flags);
+
+	queued_urb = search_dev_ep (s, urb); // returns already queued urb for that pipe
+
+	if (queued_urb) {
+
+		queue_dbg("found bulk urb %p\n", queued_urb);
+
+		if (( type != PIPE_BULK) ||
+		    ((type == PIPE_BULK) &&
+		     (!(urb->transfer_flags & USB_QUEUE_BULK) || !(queued_urb->transfer_flags & USB_QUEUE_BULK)))) {
+			spin_unlock_irqrestore (&s->urb_list_lock, flags);
+			usb_dec_dev_use (urb->dev);
+			err("ENXIO %08x, flags %x, urb %p, burb %p",urb->pipe,urb->transfer_flags,urb,queued_urb);
+			return -ENXIO;	// urb already queued
+		}
+	}
+
+#ifdef DEBUG_SLAB
+	urb_priv = kmem_cache_alloc(urb_priv_kmem, SLAB_FLAG);
+#else
+	urb_priv = kmalloc (sizeof (urb_priv_t), KMALLOC_FLAG);
+#endif
+	if (!urb_priv) {
+		usb_dec_dev_use (urb->dev);
+		spin_unlock_irqrestore (&s->urb_list_lock, flags);
+		return -ENOMEM;
+	}
+
+	memset(urb_priv, 0, sizeof(urb_priv_t));
+	urb->hcpriv = urb_priv;
+	INIT_LIST_HEAD (&urb_priv->desc_list);
+
+	dbg("submit_urb: scheduling %p", urb);
+	
+	if (type == PIPE_CONTROL)
+		urb_priv->setup_packet_dma = pci_map_single(s->uhci_pci, urb->setup_packet,
+							    sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE);
+
+	if (urb->transfer_buffer_length)
+		urb_priv->transfer_buffer_dma = pci_map_single(s->uhci_pci,
+							       urb->transfer_buffer,
+							       urb->transfer_buffer_length,
+							       usb_pipein(urb->pipe) ?
+							       PCI_DMA_FROMDEVICE :
+							       PCI_DMA_TODEVICE);
+
+	if (type == PIPE_BULK) {
+	
+		if (queued_urb) {
+			while (((urb_priv_t*)queued_urb->hcpriv)->next_queued_urb)  // find last queued bulk
+				queued_urb=((urb_priv_t*)queued_urb->hcpriv)->next_queued_urb;
+			
+			((urb_priv_t*)queued_urb->hcpriv)->next_queued_urb=urb;
+		}
+		atomic_inc (&s->avoid_bulk);
+		ret = uhci_submit_bulk_urb (urb, queued_urb);
+		atomic_dec (&s->avoid_bulk);
+		spin_unlock_irqrestore (&s->urb_list_lock, flags);
+	}
+	else {
+		spin_unlock_irqrestore (&s->urb_list_lock, flags);
+		switch (type) {
+		case PIPE_ISOCHRONOUS:			
+			if (urb->bandwidth == 0) {      /* not yet checked/allocated */
+				if (urb->number_of_packets <= 0) {
+					ret = -EINVAL;
+					break;
+				}
+
+				bustime = usb_check_bandwidth (urb->dev, urb);
+				if (bustime < 0) 
+					ret = bustime;
+				else {
+					ret = uhci_submit_iso_urb(urb);
+					if (ret == 0)
+						usb_claim_bandwidth (urb->dev, urb, bustime, 1);
+				}
+			} else {        /* bandwidth is already set */
+				ret = uhci_submit_iso_urb(urb);
+			}
+			break;
+		case PIPE_INTERRUPT:
+			if (urb->bandwidth == 0) {      /* not yet checked/allocated */
+				bustime = usb_check_bandwidth (urb->dev, urb);
+				if (bustime < 0)
+					ret = bustime;
+				else {
+					ret = uhci_submit_int_urb(urb);
+					if (ret == 0)
+						usb_claim_bandwidth (urb->dev, urb, bustime, 0);
+				}
+			} else {        /* bandwidth is already set */
+				ret = uhci_submit_int_urb(urb);
+			}
+			break;
+		case PIPE_CONTROL:
+			ret = uhci_submit_control_urb (urb);
+			break;
+		default:
+			ret = -EINVAL;
+		}
+	}
+
+	dbg("submit_urb: scheduled with ret: %d", ret);
+	
+	if (ret != 0) {
+		uhci_urb_dma_unmap(s, urb, urb_priv);
+		usb_dec_dev_use (urb->dev);
+#ifdef DEBUG_SLAB
+		kmem_cache_free(urb_priv_kmem, urb_priv);
+#else
+		kfree (urb_priv);
+#endif
+		return ret;
+	}
+
+	return 0;
+}
+
+// Checks for URB timeout and removes bandwidth reclamation if URB idles too long
+_static void uhci_check_timeouts(uhci_t *s)
+{
+	struct list_head *p,*p2;
+	struct urb *urb;
+	int type;	
+
+	p = s->urb_list.prev;	
+
+	while (p != &s->urb_list) {
+		urb_priv_t *hcpriv;
+
+		p2 = p;
+		p = p->prev;
+		urb = list_entry (p2, struct urb, urb_list);
+		type = usb_pipetype (urb->pipe);
+
+		hcpriv = (urb_priv_t*)urb->hcpriv;
+		
+		if ( urb->timeout && time_after(jiffies, hcpriv->started + urb->timeout)) {
+			urb->transfer_flags |= USB_TIMEOUT_KILLED | USB_ASYNC_UNLINK;
+			async_dbg("uhci_check_timeout: timeout for %p",urb);
+			uhci_unlink_urb_async(s, urb, UNLINK_ASYNC_STORE_URB);
+		}
+#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
+		else if (((type == PIPE_BULK) || (type == PIPE_CONTROL)) &&  
+			 (hcpriv->use_loop) && time_after(jiffies, hcpriv->started + IDLE_TIMEOUT))
+			disable_desc_loop(s, urb);
+#endif
+
+	}
+	s->timeout_check=jiffies;
+}
+
+/*-------------------------------------------------------------------
+ Virtual Root Hub
+ -------------------------------------------------------------------*/
+
+_static __u8 root_hub_dev_des[] =
+{
+	0x12,			/*  __u8  bLength; */
+	0x01,			/*  __u8  bDescriptorType; Device */
+	0x00,			/*  __u16 bcdUSB; v1.0 */
+	0x01,
+	0x09,			/*  __u8  bDeviceClass; HUB_CLASSCODE */
+	0x00,			/*  __u8  bDeviceSubClass; */
+	0x00,			/*  __u8  bDeviceProtocol; */
+	0x08,			/*  __u8  bMaxPacketSize0; 8 Bytes */
+	0x00,			/*  __u16 idVendor; */
+	0x00,
+	0x00,			/*  __u16 idProduct; */
+	0x00,
+	0x00,			/*  __u16 bcdDevice; */
+	0x00,
+	0x00,			/*  __u8  iManufacturer; */
+	0x02,			/*  __u8  iProduct; */
+	0x01,			/*  __u8  iSerialNumber; */
+	0x01			/*  __u8  bNumConfigurations; */
+};
+
+
+/* Configuration descriptor */
+_static __u8 root_hub_config_des[] =
+{
+	0x09,			/*  __u8  bLength; */
+	0x02,			/*  __u8  bDescriptorType; Configuration */
+	0x19,			/*  __u16 wTotalLength; */
+	0x00,
+	0x01,			/*  __u8  bNumInterfaces; */
+	0x01,			/*  __u8  bConfigurationValue; */
+	0x00,			/*  __u8  iConfiguration; */
+	0x40,			/*  __u8  bmAttributes; 
+				   Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
+	0x00,			/*  __u8  MaxPower; */
+
+     /* interface */
+	0x09,			/*  __u8  if_bLength; */
+	0x04,			/*  __u8  if_bDescriptorType; Interface */
+	0x00,			/*  __u8  if_bInterfaceNumber; */
+	0x00,			/*  __u8  if_bAlternateSetting; */
+	0x01,			/*  __u8  if_bNumEndpoints; */
+	0x09,			/*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
+	0x00,			/*  __u8  if_bInterfaceSubClass; */
+	0x00,			/*  __u8  if_bInterfaceProtocol; */
+	0x00,			/*  __u8  if_iInterface; */
+
+     /* endpoint */
+	0x07,			/*  __u8  ep_bLength; */
+	0x05,			/*  __u8  ep_bDescriptorType; Endpoint */
+	0x81,			/*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
+	0x03,			/*  __u8  ep_bmAttributes; Interrupt */
+	0x08,			/*  __u16 ep_wMaxPacketSize; 8 Bytes */
+	0x00,
+	0xff			/*  __u8  ep_bInterval; 255 ms */
+};
+
+
+_static __u8 root_hub_hub_des[] =
+{
+	0x09,			/*  __u8  bLength; */
+	0x29,			/*  __u8  bDescriptorType; Hub-descriptor */
+	0x02,			/*  __u8  bNbrPorts; */
+	0x00,			/* __u16  wHubCharacteristics; */
+	0x00,
+	0x01,			/*  __u8  bPwrOn2pwrGood; 2ms */
+	0x00,			/*  __u8  bHubContrCurrent; 0 mA */
+	0x00,			/*  __u8  DeviceRemovable; *** 7 Ports max *** */
+	0xff			/*  __u8  PortPwrCtrlMask; *** 7 ports max *** */
+};
+
+/*-------------------------------------------------------------------------*/
+/* prepare Interrupt pipe transaction data; HUB INTERRUPT ENDPOINT */
+_static int rh_send_irq (struct urb *urb)
+{
+	int len = 1;
+	int i;
+	uhci_t *uhci = urb->dev->bus->hcpriv;
+	unsigned int io_addr = uhci->io_addr;
+	__u16 data = 0;
+
+	for (i = 0; i < uhci->rh.numports; i++) {
+		data |= ((inw (io_addr + USBPORTSC1 + i * 2) & 0xa) > 0 ? (1 << (i + 1)) : 0);
+		len = (i + 1) / 8 + 1;
+	}
+
+	*(__u16 *) urb->transfer_buffer = cpu_to_le16 (data);
+	urb->actual_length = len;
+	urb->status = 0;
+	
+	if ((data > 0) && (uhci->rh.send != 0)) {
+		dbg("Root-Hub INT complete: port1: %x port2: %x data: %x",
+		     inw (io_addr + USBPORTSC1), inw (io_addr + USBPORTSC2), data);
+		urb->complete (urb);
+	}
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+/* Virtual Root Hub INTs are polled by this timer every "intervall" ms */
+_static int rh_init_int_timer (struct urb *urb);
+
+_static void rh_int_timer_do (unsigned long ptr)
+{
+	int len;
+	struct urb *urb = (struct urb*) ptr;
+	uhci_t *uhci = urb->dev->bus->hcpriv;
+
+	if (uhci->rh.send) {
+		len = rh_send_irq (urb);
+		if (len > 0) {
+			urb->actual_length = len;
+			if (urb->complete)
+				urb->complete (urb);
+		}
+	}
+	rh_init_int_timer (urb);
+}
+
+/*-------------------------------------------------------------------------*/
+/* Root Hub INTs are polled by this timer, polling interval 20ms */
+
+_static int rh_init_int_timer (struct urb *urb)
+{
+	uhci_t *uhci = urb->dev->bus->hcpriv;
+
+	uhci->rh.interval = urb->interval;
+	init_timer (&uhci->rh.rh_int_timer);
+	uhci->rh.rh_int_timer.function = rh_int_timer_do;
+	uhci->rh.rh_int_timer.data = (unsigned long) urb;
+	uhci->rh.rh_int_timer.expires = jiffies + (HZ * 20) / 1000;
+	add_timer (&uhci->rh.rh_int_timer);
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+#define OK(x) 			len = (x); break
+
+#define CLR_RH_PORTSTAT(x) \
+		status = inw(io_addr+USBPORTSC1+2*(wIndex-1)); \
+		status = (status & 0xfff5) & ~(x); \
+		outw(status, io_addr+USBPORTSC1+2*(wIndex-1))
+
+#define SET_RH_PORTSTAT(x) \
+		status = inw(io_addr+USBPORTSC1+2*(wIndex-1)); \
+		status = (status & 0xfff5) | (x); \
+		outw(status, io_addr+USBPORTSC1+2*(wIndex-1))
+
+
+/*-------------------------------------------------------------------------*/
+/****
+ ** Root Hub Control Pipe
+ *************************/
+
+
+_static int rh_submit_urb (struct urb *urb)
+{
+	struct usb_device *usb_dev = urb->dev;
+	uhci_t *uhci = usb_dev->bus->hcpriv;
+	unsigned int pipe = urb->pipe;
+	struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *) urb->setup_packet;
+	void *data = urb->transfer_buffer;
+	int leni = urb->transfer_buffer_length;
+	int len = 0;
+	int status = 0;
+	int stat = 0;
+	int i;
+	unsigned int io_addr = uhci->io_addr;
+	__u16 cstatus;
+
+	__u16 bmRType_bReq;
+	__u16 wValue;
+	__u16 wIndex;
+	__u16 wLength;
+
+	if (usb_pipetype (pipe) == PIPE_INTERRUPT) {
+		dbg("Root-Hub submit IRQ: every %d ms", urb->interval);
+		uhci->rh.urb = urb;
+		uhci->rh.send = 1;
+		uhci->rh.interval = urb->interval;
+		rh_init_int_timer (urb);
+
+		return 0;
+	}
+
+
+	bmRType_bReq = cmd->bRequestType | cmd->bRequest << 8;
+	wValue = le16_to_cpu (cmd->wValue);
+	wIndex = le16_to_cpu (cmd->wIndex);
+	wLength = le16_to_cpu (cmd->wLength);
+
+	for (i = 0; i < 8; i++)
+		uhci->rh.c_p_r[i] = 0;
+
+	dbg("Root-Hub: adr: %2x cmd(%1x): %04x %04x %04x %04x",
+	     uhci->rh.devnum, 8, bmRType_bReq, wValue, wIndex, wLength);
+
+	switch (bmRType_bReq) {
+		/* Request Destination:
+		   without flags: Device, 
+		   RH_INTERFACE: interface, 
+		   RH_ENDPOINT: endpoint,
+		   RH_CLASS means HUB here, 
+		   RH_OTHER | RH_CLASS  almost ever means HUB_PORT here 
+		 */
+
+	case RH_GET_STATUS:
+		*(__u16 *) data = cpu_to_le16 (1);
+		OK (2);
+	case RH_GET_STATUS | RH_INTERFACE:
+		*(__u16 *) data = cpu_to_le16 (0);
+		OK (2);
+	case RH_GET_STATUS | RH_ENDPOINT:
+		*(__u16 *) data = cpu_to_le16 (0);
+		OK (2);
+	case RH_GET_STATUS | RH_CLASS:
+		*(__u32 *) data = cpu_to_le32 (0);
+		OK (4);		/* hub power ** */
+	case RH_GET_STATUS | RH_OTHER | RH_CLASS:
+		status = inw (io_addr + USBPORTSC1 + 2 * (wIndex - 1));
+		cstatus = ((status & USBPORTSC_CSC) >> (1 - 0)) |
+			((status & USBPORTSC_PEC) >> (3 - 1)) |
+			(uhci->rh.c_p_r[wIndex - 1] << (0 + 4));
+		status = (status & USBPORTSC_CCS) |
+			((status & USBPORTSC_PE) >> (2 - 1)) |
+			((status & USBPORTSC_SUSP) >> (12 - 2)) |
+			((status & USBPORTSC_PR) >> (9 - 4)) |
+			(1 << 8) |	/* power on ** */
+			((status & USBPORTSC_LSDA) << (-8 + 9));
+
+		*(__u16 *) data = cpu_to_le16 (status);
+		*(__u16 *) (data + 2) = cpu_to_le16 (cstatus);
+		OK (4);
+
+	case RH_CLEAR_FEATURE | RH_ENDPOINT:
+		switch (wValue) {
+		case (RH_ENDPOINT_STALL):
+			OK (0);
+		}
+		break;
+
+	case RH_CLEAR_FEATURE | RH_CLASS:
+		switch (wValue) {
+		case (RH_C_HUB_OVER_CURRENT):
+			OK (0);	/* hub power over current ** */
+		}
+		break;
+
+	case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+		switch (wValue) {
+		case (RH_PORT_ENABLE):
+			CLR_RH_PORTSTAT (USBPORTSC_PE);
+			OK (0);
+		case (RH_PORT_SUSPEND):
+			CLR_RH_PORTSTAT (USBPORTSC_SUSP);
+			OK (0);
+		case (RH_PORT_POWER):
+			OK (0);	/* port power ** */
+		case (RH_C_PORT_CONNECTION):
+			SET_RH_PORTSTAT (USBPORTSC_CSC);
+			OK (0);
+		case (RH_C_PORT_ENABLE):
+			SET_RH_PORTSTAT (USBPORTSC_PEC);
+			OK (0);
+		case (RH_C_PORT_SUSPEND):
+/*** WR_RH_PORTSTAT(RH_PS_PSSC); */
+			OK (0);
+		case (RH_C_PORT_OVER_CURRENT):
+			OK (0);	/* port power over current ** */
+		case (RH_C_PORT_RESET):
+			uhci->rh.c_p_r[wIndex - 1] = 0;
+			OK (0);
+		}
+		break;
+
+	case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+		switch (wValue) {
+		case (RH_PORT_SUSPEND):
+			SET_RH_PORTSTAT (USBPORTSC_SUSP);
+			OK (0);
+		case (RH_PORT_RESET):
+			SET_RH_PORTSTAT (USBPORTSC_PR);
+			uhci_wait_ms (10);
+			uhci->rh.c_p_r[wIndex - 1] = 1;
+			CLR_RH_PORTSTAT (USBPORTSC_PR);
+			udelay (10);
+			SET_RH_PORTSTAT (USBPORTSC_PE);
+			uhci_wait_ms (10);
+			SET_RH_PORTSTAT (0xa);
+			OK (0);
+		case (RH_PORT_POWER):
+			OK (0);	/* port power ** */
+		case (RH_PORT_ENABLE):
+			SET_RH_PORTSTAT (USBPORTSC_PE);
+			OK (0);
+		}
+		break;
+
+	case RH_SET_ADDRESS:
+		uhci->rh.devnum = wValue;
+		OK (0);
+
+	case RH_GET_DESCRIPTOR:
+		switch ((wValue & 0xff00) >> 8) {
+		case (0x01):	/* device descriptor */
+			len = min_t(unsigned int, leni,
+				  min_t(unsigned int,
+				      sizeof (root_hub_dev_des), wLength));
+			memcpy (data, root_hub_dev_des, len);
+			OK (len);
+		case (0x02):	/* configuration descriptor */
+			len = min_t(unsigned int, leni,
+				  min_t(unsigned int,
+				      sizeof (root_hub_config_des), wLength));
+			memcpy (data, root_hub_config_des, len);
+			OK (len);
+		case (0x03):	/* string descriptors */
+			len = usb_root_hub_string (wValue & 0xff,
+			        uhci->io_addr, "UHCI",
+				data, wLength);
+			if (len > 0) {
+				OK(min_t(int, leni, len));
+			} else 
+				stat = -EPIPE;
+		}
+		break;
+
+	case RH_GET_DESCRIPTOR | RH_CLASS:
+		root_hub_hub_des[2] = uhci->rh.numports;
+		len = min_t(unsigned int, leni,
+			  min_t(unsigned int, sizeof (root_hub_hub_des), wLength));
+		memcpy (data, root_hub_hub_des, len);
+		OK (len);
+
+	case RH_GET_CONFIGURATION:
+		*(__u8 *) data = 0x01;
+		OK (1);
+
+	case RH_SET_CONFIGURATION:
+		OK (0);
+	default:
+		stat = -EPIPE;
+	}
+
+	dbg("Root-Hub stat port1: %x port2: %x",
+	     inw (io_addr + USBPORTSC1), inw (io_addr + USBPORTSC2));
+
+	urb->actual_length = len;
+	urb->status = stat;
+	urb->dev=NULL;
+	if (urb->complete)
+		urb->complete (urb);
+	return 0;
+}
+/*-------------------------------------------------------------------------*/
+
+_static int rh_unlink_urb (struct urb *urb)
+{
+	uhci_t *uhci = urb->dev->bus->hcpriv;
+
+	if (uhci->rh.urb==urb) {
+		dbg("Root-Hub unlink IRQ");
+		uhci->rh.send = 0;
+		del_timer (&uhci->rh.rh_int_timer);
+	}
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+
+/*
+ * Map status to standard result codes
+ *
+ * <status> is (td->status & 0xFE0000) [a.k.a. uhci_status_bits(td->status)
+ * <dir_out> is True for output TDs and False for input TDs.
+ */
+_static int uhci_map_status (int status, int dir_out)
+{
+	if (!status)
+		return 0;
+	if (status & TD_CTRL_BITSTUFF)	/* Bitstuff error */
+		return -EPROTO;
+	if (status & TD_CTRL_CRCTIMEO) {	/* CRC/Timeout */
+		if (dir_out)
+			return -ETIMEDOUT;
+		else
+			return -EILSEQ;
+	}
+	if (status & TD_CTRL_NAK)	/* NAK */
+		return -ETIMEDOUT;
+	if (status & TD_CTRL_BABBLE)	/* Babble */
+		return -EOVERFLOW;
+	if (status & TD_CTRL_DBUFERR)	/* Buffer error */
+		return -ENOSR;
+	if (status & TD_CTRL_STALLED)	/* Stalled */
+		return -EPIPE;
+	if (status & TD_CTRL_ACTIVE)	/* Active */
+		return 0;
+
+	return -EPROTO;
+}
+
+/*
+ * Only the USB core should call uhci_alloc_dev and uhci_free_dev
+ */
+_static int uhci_alloc_dev (struct usb_device *usb_dev)
+{
+	return 0;
+}
+
+_static void uhci_unlink_urbs(uhci_t *s, struct usb_device *usb_dev, int remove_all)
+{
+	unsigned long flags;
+	struct list_head *p;
+	struct list_head *p2;
+	struct urb *urb;
+
+	spin_lock_irqsave (&s->urb_list_lock, flags);
+	p = s->urb_list.prev;	
+	while (p != &s->urb_list) {
+		p2 = p;
+		p = p->prev ;
+		urb = list_entry (p2, struct urb, urb_list);
+		dbg("urb: %p, dev %p, %p", urb, usb_dev,urb->dev);
+		
+		//urb->transfer_flags |=USB_ASYNC_UNLINK; 
+			
+		if (remove_all || (usb_dev == urb->dev)) {
+			spin_unlock_irqrestore (&s->urb_list_lock, flags);
+			warn("forced removing of queued URB %p due to disconnect",urb);
+			uhci_unlink_urb(urb);
+			urb->dev = NULL; // avoid further processing of this URB
+			spin_lock_irqsave (&s->urb_list_lock, flags);
+			p = s->urb_list.prev;	
+		}
+	}
+	spin_unlock_irqrestore (&s->urb_list_lock, flags);
+}
+
+_static int uhci_free_dev (struct usb_device *usb_dev)
+{
+	uhci_t *s;
+	
+
+	if(!usb_dev || !usb_dev->bus || !usb_dev->bus->hcpriv)
+		return -EINVAL;
+	
+	s=(uhci_t*) usb_dev->bus->hcpriv;	
+	uhci_unlink_urbs(s, usb_dev, 0);
+
+	return 0;
+}
+
+/*
+ * uhci_get_current_frame_number()
+ *
+ * returns the current frame number for a USB bus/controller.
+ */
+_static int uhci_get_current_frame_number (struct usb_device *usb_dev)
+{
+	return UHCI_GET_CURRENT_FRAME ((uhci_t*) usb_dev->bus->hcpriv);
+}
+
+struct usb_operations uhci_device_operations =
+{
+	uhci_alloc_dev,
+	uhci_free_dev,
+	uhci_get_current_frame_number,
+	uhci_submit_urb,
+	uhci_unlink_urb
+};
+
+_static void correct_data_toggles(struct urb *urb)
+{
+	usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe), 
+		       !usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe)));
+
+	while(urb) {
+		urb_priv_t *priv=urb->hcpriv;		
+		uhci_desc_t *qh = list_entry (priv->desc_list.next, uhci_desc_t, desc_list);
+		struct list_head *p = qh->vertical.next;
+		uhci_desc_t *td;
+		dbg("URB to correct %p\n", urb);
+	
+		for (; p != &qh->vertical; p = p->next) {
+			td = list_entry (p, uhci_desc_t, vertical);
+			td->hw.td.info^=cpu_to_le32(1<<TD_TOKEN_TOGGLE);
+		}
+		urb=priv->next_queued_urb;
+	}
+}
+
+/* 
+ * For IN-control transfers, process_transfer gets a bit more complicated,
+ * since there are devices that return less data (eg. strings) than they
+ * have announced. This leads to a queue abort due to the short packet,
+ * the status stage is not executed. If this happens, the status stage
+ * is manually re-executed.
+ * mode: PROCESS_TRANSFER_REGULAR: regular (unlink QH)
+ *       PROCESS_TRANSFER_DONT_UNLINK: QHs already unlinked (for async unlink_urb)
+ */
+
+_static int process_transfer (uhci_t *s, struct urb *urb, int mode)
+{
+	int ret = 0;
+	urb_priv_t *urb_priv = urb->hcpriv;
+	struct list_head *qhl = urb_priv->desc_list.next;
+	uhci_desc_t *qh = list_entry (qhl, uhci_desc_t, desc_list);
+	struct list_head *p = qh->vertical.next;
+	uhci_desc_t *desc= list_entry (urb_priv->desc_list.prev, uhci_desc_t, desc_list);
+	uhci_desc_t *last_desc = list_entry (desc->vertical.prev, uhci_desc_t, vertical);
+	int data_toggle = usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));	// save initial data_toggle
+	int maxlength; 	// extracted and remapped info from TD
+	int actual_length;
+	int status = 0;
+
+	//dbg("process_transfer: urb %p, urb_priv %p, qh %p last_desc %p\n",urb,urb_priv, qh, last_desc);
+
+	/* if the status phase has been retriggered and the
+	   queue is empty or the last status-TD is inactive, the retriggered
+	   status stage is completed
+	 */
+
+	if (urb_priv->flags && 
+	    ((qh->hw.qh.element == cpu_to_le32(UHCI_PTR_TERM)) || !is_td_active(desc)))
+		goto transfer_finished;
+
+	urb->actual_length=0;
+
+	for (; p != &qh->vertical; p = p->next) {
+		desc = list_entry (p, uhci_desc_t, vertical);
+
+		if (is_td_active(desc)) {	// do not process active TDs
+			if (mode == CLEAN_TRANSFER_DELETION_MARK) // if called from async_unlink
+				uhci_clean_transfer(s, urb, qh, CLEAN_TRANSFER_DELETION_MARK);
+			return ret;
+		}
+	
+		actual_length = uhci_actual_length(le32_to_cpu(desc->hw.td.status));		// extract transfer parameters from TD
+		maxlength = (((le32_to_cpu(desc->hw.td.info) >> 21) & 0x7ff) + 1) & 0x7ff;
+		status = uhci_map_status (uhci_status_bits (le32_to_cpu(desc->hw.td.status)), usb_pipeout (urb->pipe));
+
+		if (status == -EPIPE) { 		// see if EP is stalled
+			// set up stalled condition
+			usb_endpoint_halt (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
+		}
+
+		if (status && (status != -EPIPE)) {	// if any error occurred stop processing of further TDs
+			// only set ret if status returned an error
+  is_error:
+			ret = status;
+			urb->error_count++;
+			break;
+		}
+		else if ((le32_to_cpu(desc->hw.td.info) & 0xff) != USB_PID_SETUP)
+			urb->actual_length += actual_length;
+
+		// got less data than requested
+		if ( (actual_length < maxlength)) {
+			if (urb->transfer_flags & USB_DISABLE_SPD) {
+				status = -EREMOTEIO;	// treat as real error
+				dbg("process_transfer: SPD!!");
+				break;	// exit after this TD because SP was detected
+			}
+
+			// short read during control-IN: re-start status stage
+			if ((usb_pipetype (urb->pipe) == PIPE_CONTROL)) {
+				if (uhci_packetid(le32_to_cpu(last_desc->hw.td.info)) == USB_PID_OUT) {
+			
+					set_qh_element(qh, last_desc->dma_addr);  // re-trigger status stage
+					dbg("short packet during control transfer, retrigger status stage @ %p",last_desc);
+					urb_priv->flags = 1; // mark as short control packet
+					return 0;
+				}
+			}
+			// all other cases: short read is OK
+			data_toggle = uhci_toggle (le32_to_cpu(desc->hw.td.info));
+			break;
+		}
+		else if (status)
+			goto is_error;
+
+		data_toggle = uhci_toggle (le32_to_cpu(desc->hw.td.info));
+		queue_dbg("process_transfer: len:%d status:%x mapped:%x toggle:%d", actual_length, le32_to_cpu(desc->hw.td.status),status, data_toggle);      
+
+	}
+
+	if (usb_pipetype (urb->pipe) == PIPE_BULK ) {  /* toggle correction for short bulk transfers (nonqueued/queued) */
+
+		urb_priv_t *priv=(urb_priv_t*)urb->hcpriv;
+		struct urb *next_queued_urb=priv->next_queued_urb;
+
+		if (next_queued_urb) {
+			urb_priv_t *next_priv=(urb_priv_t*)next_queued_urb->hcpriv;
+			uhci_desc_t *qh = list_entry (next_priv->desc_list.next, uhci_desc_t, desc_list);
+			uhci_desc_t *first_td=list_entry (qh->vertical.next, uhci_desc_t, vertical);
+
+			if (data_toggle == uhci_toggle (le32_to_cpu(first_td->hw.td.info))) {
+				err("process_transfer: fixed toggle");
+				correct_data_toggles(next_queued_urb);
+			}						
+		}
+		else
+			usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe), !data_toggle);		
+	}
+
+ transfer_finished:
+	
+	uhci_clean_transfer(s, urb, qh, mode);
+
+	urb->status = status;
+
+#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH	
+	disable_desc_loop(s,urb);
+#endif	
+
+	queue_dbg("process_transfer: (end) urb %p, wanted len %d, len %d status %x err %d",
+		urb,urb->transfer_buffer_length,urb->actual_length, urb->status, urb->error_count);
+	return ret;
+}
+
+_static int process_interrupt (uhci_t *s, struct urb *urb)
+{
+	int i, ret = -EINPROGRESS;
+	urb_priv_t *urb_priv = urb->hcpriv;
+	struct list_head *p = urb_priv->desc_list.next;
+	uhci_desc_t *desc = list_entry (urb_priv->desc_list.prev, uhci_desc_t, desc_list);
+
+	int actual_length;
+	int status = 0;
+
+	//dbg("urb contains interrupt request");
+
+	for (i = 0; p != &urb_priv->desc_list; p = p->next, i++)	// Maybe we allow more than one TD later ;-)
+	{
+		desc = list_entry (p, uhci_desc_t, desc_list);
+
+		if (is_td_active(desc)) {
+			// do not process active TDs
+			//dbg("TD ACT Status @%p %08x",desc,le32_to_cpu(desc->hw.td.status));
+			break;
+		}
+
+		if (!(desc->hw.td.status & cpu_to_le32(TD_CTRL_IOC))) {
+			// do not process one-shot TDs, no recycling
+			break;
+		}
+		// extract transfer parameters from TD
+
+		actual_length = uhci_actual_length(le32_to_cpu(desc->hw.td.status));
+		status = uhci_map_status (uhci_status_bits (le32_to_cpu(desc->hw.td.status)), usb_pipeout (urb->pipe));
+
+		// see if EP is stalled
+		if (status == -EPIPE) {
+			// set up stalled condition
+			usb_endpoint_halt (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
+		}
+
+		// if any error occurred: ignore this td, and continue
+		if (status != 0) {
+			//uhci_show_td (desc);
+			urb->error_count++;
+			goto recycle;
+		}
+		else
+			urb->actual_length = actual_length;
+
+	recycle:
+		uhci_urb_dma_sync(s, urb, urb->hcpriv);
+		if (urb->complete) {
+			//dbg("process_interrupt: calling completion, status %i",status);
+			urb->status = status;
+			((urb_priv_t*)urb->hcpriv)->flags=1; // if unlink_urb is called during completion
+
+			spin_unlock(&s->urb_list_lock);
+			
+			urb->complete ((struct urb *) urb);
+			
+			spin_lock(&s->urb_list_lock);
+
+			((urb_priv_t*)urb->hcpriv)->flags=0;		       			
+		}
+		
+		if ((urb->status != -ECONNABORTED) && (urb->status != ECONNRESET) &&
+			    (urb->status != -ENOENT)) {
+
+			urb->status = -EINPROGRESS;
+
+			// Recycle INT-TD if interval!=0, else mark TD as one-shot
+			if (urb->interval) {
+				
+				desc->hw.td.info &= cpu_to_le32(~(1 << TD_TOKEN_TOGGLE));
+				if (status==0) {
+					((urb_priv_t*)urb->hcpriv)->started=jiffies;
+					desc->hw.td.info |= cpu_to_le32((usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe),
+									    usb_pipeout (urb->pipe)) << TD_TOKEN_TOGGLE));
+					usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
+				} else {
+					desc->hw.td.info |= cpu_to_le32((!usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe),
+									     usb_pipeout (urb->pipe)) << TD_TOKEN_TOGGLE));
+				}
+				desc->hw.td.status= cpu_to_le32((urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC |
+					(urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27));
+				mb();
+			}
+			else {
+				uhci_unlink_urb_async(s, urb, UNLINK_ASYNC_STORE_URB);
+				uhci_clean_iso_step2(s, urb_priv);
+				// correct toggle after unlink
+				usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
+				clr_td_ioc(desc); // inactivate TD
+			}
+		}
+	}
+
+	return ret;
+}
+
+// mode: PROCESS_ISO_REGULAR: processing only for done TDs, unlink TDs
+// mode: PROCESS_ISO_FORCE: force processing, don't unlink TDs (already unlinked)
+
+_static int process_iso (uhci_t *s, struct urb *urb, int mode)
+{
+	int i;
+	int ret = 0;
+	urb_priv_t *urb_priv = urb->hcpriv;
+	struct list_head *p = urb_priv->desc_list.next, *p_tmp;
+	uhci_desc_t *desc = list_entry (urb_priv->desc_list.prev, uhci_desc_t, desc_list);
+
+	dbg("urb contains iso request");
+	if (is_td_active(desc) && mode==PROCESS_ISO_REGULAR)
+		return -EXDEV;	// last TD not finished
+
+	urb->error_count = 0;
+	urb->actual_length = 0;
+	urb->status = 0;
+	dbg("process iso urb %p, %li, %i, %i, %i %08x",urb,jiffies,UHCI_GET_CURRENT_FRAME(s),
+	    urb->number_of_packets,mode,le32_to_cpu(desc->hw.td.status));
+
+	for (i = 0; p != &urb_priv->desc_list;  i++) {
+		desc = list_entry (p, uhci_desc_t, desc_list);
+		
+		//uhci_show_td(desc);
+		if (is_td_active(desc)) {
+			// means we have completed the last TD, but not the TDs before
+			desc->hw.td.status &= cpu_to_le32(~TD_CTRL_ACTIVE);
+			dbg("TD still active (%x)- grrr. paranoia!", le32_to_cpu(desc->hw.td.status));
+			ret = -EXDEV;
+			urb->iso_frame_desc[i].status = ret;
+			unlink_td (s, desc, 1);
+			// FIXME: immediate deletion may be dangerous
+			goto err;
+		}
+
+		if (mode == PROCESS_ISO_REGULAR)
+			unlink_td (s, desc, 1);
+
+		if (urb->number_of_packets <= i) {
+			dbg("urb->number_of_packets (%d)<=(%d)", urb->number_of_packets, i);
+			ret = -EINVAL;
+			goto err;
+		}
+
+		urb->iso_frame_desc[i].actual_length = uhci_actual_length(le32_to_cpu(desc->hw.td.status));
+		urb->iso_frame_desc[i].status = uhci_map_status (uhci_status_bits (le32_to_cpu(desc->hw.td.status)), usb_pipeout (urb->pipe));
+		urb->actual_length += urb->iso_frame_desc[i].actual_length;
+
+	      err:
+
+		if (urb->iso_frame_desc[i].status != 0) {
+			urb->error_count++;
+			urb->status = urb->iso_frame_desc[i].status;
+		}
+		dbg("process_iso: %i: len:%d %08x status:%x",
+		     i, urb->iso_frame_desc[i].actual_length, le32_to_cpu(desc->hw.td.status),urb->iso_frame_desc[i].status);
+
+		p_tmp = p;
+		p = p->next;
+		list_del (p_tmp);
+		delete_desc (s, desc);
+	}
+	
+	dbg("process_iso: exit %i (%d), actual_len %i", i, ret,urb->actual_length);
+	return ret;
+}
+
+
+_static int process_urb (uhci_t *s, struct list_head *p)
+{
+	int ret = 0;
+	struct urb *urb;
+
+	urb=list_entry (p, struct urb, urb_list);
+	//dbg("process_urb: found queued urb: %p", urb);
+
+	switch (usb_pipetype (urb->pipe)) {
+	case PIPE_CONTROL:
+		ret = process_transfer (s, urb, CLEAN_TRANSFER_REGULAR);
+		break;
+	case PIPE_BULK:
+		if (!s->avoid_bulk.counter)
+			ret = process_transfer (s, urb, CLEAN_TRANSFER_REGULAR);
+		else
+			return 0;
+		break;
+	case PIPE_ISOCHRONOUS:
+		ret = process_iso (s, urb, PROCESS_ISO_REGULAR);
+		break;
+	case PIPE_INTERRUPT:
+		ret = process_interrupt (s, urb);
+		break;
+	}
+
+	if (urb->status != -EINPROGRESS) {
+		urb_priv_t *urb_priv;
+		struct usb_device *usb_dev;
+		
+		usb_dev=urb->dev;
+
+		/* Release bandwidth for Interrupt or Iso transfers */
+		if (urb->bandwidth) {
+			if (usb_pipetype(urb->pipe)==PIPE_ISOCHRONOUS)
+				usb_release_bandwidth (urb->dev, urb, 1);
+			else if (usb_pipetype(urb->pipe)==PIPE_INTERRUPT && urb->interval)
+				usb_release_bandwidth (urb->dev, urb, 0);
+		}
+
+		dbg("dequeued urb: %p", urb);
+		dequeue_urb (s, urb);
+
+		urb_priv = urb->hcpriv;
+
+		uhci_urb_dma_unmap(s, urb, urb_priv);
+
+#ifdef DEBUG_SLAB
+		kmem_cache_free(urb_priv_kmem, urb_priv);
+#else
+		kfree (urb_priv);
+#endif
+
+		if ((usb_pipetype (urb->pipe) != PIPE_INTERRUPT)) {  // process_interrupt does completion on its own		
+			struct urb *next_urb = urb->next;
+			int is_ring = 0;
+			int contains_killed = 0;
+			int loop_count=0;
+			
+			if (next_urb) {
+				// Find out if the URBs are linked to a ring
+				while  (next_urb != NULL && next_urb != urb && loop_count < MAX_NEXT_COUNT) {
+					if (next_urb->status == -ENOENT) {// killed URBs break ring structure & resubmission
+						contains_killed = 1;
+						break;
+					}	
+					next_urb = next_urb->next;
+					loop_count++;
+				}
+				
+				if (loop_count == MAX_NEXT_COUNT)
+					err("process_urb: Too much linked URBs in ring detection!");
+
+				if (next_urb == urb)
+					is_ring=1;
+			}			
+
+			// Submit idle/non-killed URBs linked with urb->next
+			// Stop before the current URB				
+			
+			next_urb = urb->next;	
+			if (next_urb && !contains_killed) {
+				int ret_submit;
+				next_urb = urb->next;	
+				
+				loop_count=0;
+				while (next_urb != NULL && next_urb != urb && loop_count < MAX_NEXT_COUNT) {
+					if (next_urb->status != -EINPROGRESS) {
+					
+						if (next_urb->status == -ENOENT) 
+							break;
+
+						spin_unlock(&s->urb_list_lock);
+
+						ret_submit=uhci_submit_urb(next_urb);
+						spin_lock(&s->urb_list_lock);
+						
+						if (ret_submit)
+							break;						
+					}
+					loop_count++;
+					next_urb = next_urb->next;
+				}
+				if (loop_count == MAX_NEXT_COUNT)
+					err("process_urb: Too much linked URBs in resubmission!");
+			}
+
+			// Completion
+			if (urb->complete) {
+				int was_unlinked = (urb->status == -ENOENT);
+				urb->dev = NULL;
+				spin_unlock(&s->urb_list_lock);
+
+				urb->complete ((struct urb *) urb);
+
+				// Re-submit the URB if ring-linked
+				if (is_ring && !was_unlinked && !contains_killed) {
+					urb->dev=usb_dev;
+					uhci_submit_urb (urb);
+				}
+				spin_lock(&s->urb_list_lock);
+			}
+			
+			usb_dec_dev_use (usb_dev);
+		}
+	}
+
+	return ret;
+}
+
+_static void uhci_interrupt (int irq, void *__uhci, struct pt_regs *regs)
+{
+	uhci_t *s = __uhci;
+	unsigned int io_addr = s->io_addr;
+	unsigned short status;
+	struct list_head *p, *p2;
+	int restarts, work_done;
+	
+	/*
+	 * Read the interrupt status, and write it back to clear the
+	 * interrupt cause
+	 */
+
+	status = inw (io_addr + USBSTS);
+
+	if (!status)		/* shared interrupt, not mine */
+		return;
+
+	dbg("interrupt");
+
+	if (status != 1) {
+		// Avoid too much error messages at a time
+		if (time_after(jiffies, s->last_error_time + ERROR_SUPPRESSION_TIME)) {
+			warn("interrupt, status %x, frame# %i", status, 
+			     UHCI_GET_CURRENT_FRAME(s));
+			s->last_error_time = jiffies;
+		}
+		
+		// remove host controller halted state
+		if ((status&0x20) && (s->running)) {
+			err("Host controller halted, trying to restart.");
+			outw (USBCMD_RS | inw(io_addr + USBCMD), io_addr + USBCMD);
+		}
+		//uhci_show_status (s);
+	}
+	/*
+	 * traverse the list in *reverse* direction, because new entries
+	 * may be added at the end.
+	 * also, because process_urb may unlink the current urb,
+	 * we need to advance the list before
+	 * New: check for max. workload and restart count
+	 */
+
+	spin_lock (&s->urb_list_lock);
+
+	restarts=0;
+	work_done=0;
+
+restart:
+	s->unlink_urb_done=0;
+	p = s->urb_list.prev;	
+
+	while (p != &s->urb_list && (work_done < 1024)) {
+		p2 = p;
+		p = p->prev;
+
+		process_urb (s, p2);
+		
+		work_done++;
+
+		if (s->unlink_urb_done) {
+			s->unlink_urb_done=0;
+			restarts++;
+			
+			if (restarts<16)	// avoid endless restarts
+				goto restart;
+			else 
+				break;
+		}
+	}
+	if (time_after(jiffies, s->timeout_check + (HZ/30)))
+		uhci_check_timeouts(s);
+
+	clean_descs(s, CLEAN_NOT_FORCED);
+	uhci_cleanup_unlink(s, CLEAN_NOT_FORCED);
+	uhci_switch_timer_int(s);
+							
+	spin_unlock (&s->urb_list_lock);
+	
+	outw (status, io_addr + USBSTS);
+
+	//dbg("uhci_interrupt: done");
+}
+
+_static void reset_hc (uhci_t *s)
+{
+	unsigned int io_addr = s->io_addr;
+
+	s->apm_state = 0;
+	/* Global reset for 50ms */
+	outw (USBCMD_GRESET, io_addr + USBCMD);
+	uhci_wait_ms (50);
+	outw (0, io_addr + USBCMD);
+	uhci_wait_ms (10);
+}
+
+_static void start_hc (uhci_t *s)
+{
+	unsigned int io_addr = s->io_addr;
+	int timeout = 10;
+
+	/*
+	 * Reset the HC - this will force us to get a
+	 * new notification of any already connected
+	 * ports due to the virtual disconnect that it
+	 * implies.
+	 */
+	outw (USBCMD_HCRESET, io_addr + USBCMD);
+
+	while (inw (io_addr + USBCMD) & USBCMD_HCRESET) {
+		if (!--timeout) {
+			err("USBCMD_HCRESET timed out!");
+			break;
+		}
+		udelay(1);
+	}
+
+	/* Turn on all interrupts */
+	outw (USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP, io_addr + USBINTR);
+
+	/* Start at frame 0 */
+	outw (0, io_addr + USBFRNUM);
+	outl (s->framelist_dma, io_addr + USBFLBASEADD);
+
+	/* Run and mark it configured with a 64-byte max packet */
+	outw (USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD);
+	s->apm_state = 1;
+	s->running = 1;
+}
+
+/* No  __devexit, since it maybe called from alloc_uhci() */
+_static void
+uhci_pci_remove (struct pci_dev *dev)
+{
+	uhci_t *s = pci_get_drvdata(dev);
+	struct usb_device *root_hub = s->bus->root_hub;
+
+	s->running = 0;		    // Don't allow submit_urb
+
+	if (root_hub)
+		usb_disconnect (&root_hub);
+
+	reset_hc (s);
+	wait_ms (1);
+
+	uhci_unlink_urbs (s, 0, CLEAN_FORCED);  // Forced unlink of remaining URBs
+	uhci_cleanup_unlink (s, CLEAN_FORCED);  // force cleanup of async killed URBs
+	
+	usb_deregister_bus (s->bus);
+
+	release_region (s->io_addr, s->io_size);
+	free_irq (s->irq, s);
+	usb_free_bus (s->bus);
+	cleanup_skel (s);
+	kfree (s);
+}
+
+_static int __init uhci_start_usb (uhci_t *s)
+{				/* start it up */
+	/* connect the virtual root hub */
+	struct usb_device *usb_dev;
+
+	usb_dev = usb_alloc_dev (NULL, s->bus);
+	if (!usb_dev)
+		return -1;
+
+	s->bus->root_hub = usb_dev;
+	usb_connect (usb_dev);
+
+	if (usb_new_device (usb_dev) != 0) {
+		usb_free_dev (usb_dev);
+		return -1;
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+_static int
+uhci_pci_suspend (struct pci_dev *dev, u32 state)
+{
+	reset_hc((uhci_t *) pci_get_drvdata(dev));
+	return 0;
+}
+
+_static int
+uhci_pci_resume (struct pci_dev *dev)
+{
+	start_hc((uhci_t *) pci_get_drvdata(dev));
+	return 0;
+}
+#endif
+
+_static int __devinit alloc_uhci (struct pci_dev *dev, int irq, unsigned int io_addr, unsigned int io_size)
+{
+	uhci_t *s;
+	struct usb_bus *bus;
+	char buf[8], *bufp = buf;
+
+#ifndef __sparc__
+	sprintf(buf, "%d", irq);
+#else
+	bufp = __irq_itoa(irq);
+#endif
+	printk(KERN_INFO __FILE__ ": USB UHCI at I/O 0x%x, IRQ %s\n",
+		io_addr, bufp);
+
+	s = kmalloc (sizeof (uhci_t), GFP_KERNEL);
+	if (!s)
+		return -1;
+
+	memset (s, 0, sizeof (uhci_t));
+	INIT_LIST_HEAD (&s->free_desc);
+	INIT_LIST_HEAD (&s->urb_list);
+	INIT_LIST_HEAD (&s->urb_unlinked);
+	spin_lock_init (&s->urb_list_lock);
+	spin_lock_init (&s->qh_lock);
+	spin_lock_init (&s->td_lock);
+	atomic_set(&s->avoid_bulk, 0);
+	s->irq = -1;
+	s->io_addr = io_addr;
+	s->io_size = io_size;
+	s->uhci_pci=dev;
+
+	bus = usb_alloc_bus (&uhci_device_operations);
+	if (!bus) {
+		kfree (s);
+		return -1;
+	}
+
+	s->bus = bus;
+	bus->bus_name = dev->slot_name;
+	bus->hcpriv = s;
+
+	/* UHCI specs says devices must have 2 ports, but goes on to say */
+	/* they may have more but give no way to determine how many they */
+	/* have, so default to 2 */
+	/* According to the UHCI spec, Bit 7 is always set to 1. So we try */
+	/* to use this to our advantage */
+
+	for (s->maxports = 0; s->maxports < (io_size - 0x10) / 2; s->maxports++) {
+		unsigned int portstatus;
+
+		portstatus = inw (io_addr + 0x10 + (s->maxports * 2));
+		dbg("port %i, adr %x status %x", s->maxports,
+			io_addr + 0x10 + (s->maxports * 2), portstatus);
+		if (!(portstatus & 0x0080))
+			break;
+	}
+	warn("Detected %d ports", s->maxports);
+
+	/* This is experimental so anything less than 2 or greater than 8 is */
+	/*  something weird and we'll ignore it */
+	if (s->maxports < 2 || s->maxports > 8) {
+		dbg("Port count misdetected, forcing to 2 ports");
+		s->maxports = 2;
+	}
+
+	s->rh.numports = s->maxports;
+	s->loop_usage=0;
+	if (init_skel (s)) {
+		usb_free_bus (bus);
+		kfree(s);
+		return -1;
+	}
+
+	request_region (s->io_addr, io_size, MODNAME);
+	reset_hc (s);
+	usb_register_bus (s->bus);
+
+	start_hc (s);
+
+	if (request_irq (irq, uhci_interrupt, SA_SHIRQ, MODNAME, s)) {
+		err("request_irq %d failed!",irq);
+		usb_free_bus (bus);
+		reset_hc (s);
+		release_region (s->io_addr, s->io_size);
+		cleanup_skel(s);
+		kfree(s);
+		return -1;
+	}
+
+	/* Enable PIRQ */
+	pci_write_config_word (dev, USBLEGSUP, USBLEGSUP_DEFAULT);
+
+	s->irq = irq;
+
+	if(uhci_start_usb (s) < 0) {
+		uhci_pci_remove(dev);
+		return -1;
+	}
+
+	//chain new uhci device into global list
+	pci_set_drvdata(dev, s);
+	devs=s;
+
+	return 0;
+}
+
+_static int __devinit
+uhci_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
+{
+	int i;
+
+	if (pci_enable_device(dev) < 0)
+		return -ENODEV;
+		
+	if (!dev->irq) {
+		err("found UHCI device with no IRQ assigned. check BIOS settings!");
+		return -ENODEV;
+	}
+	
+	pci_set_master(dev);
+
+	/* Search for the IO base address.. */
+	for (i = 0; i < 6; i++) {
+
+		unsigned int io_addr = pci_resource_start(dev, i);
+		unsigned int io_size = pci_resource_len(dev, i);
+		if (!(pci_resource_flags(dev,i) & IORESOURCE_IO))
+			continue;
+
+		/* Is it already in use? */
+		if (check_region (io_addr, io_size))
+			break;
+		/* disable legacy emulation */
+		pci_write_config_word (dev, USBLEGSUP, 0);
+	
+		return alloc_uhci(dev, dev->irq, io_addr, io_size);
+	}
+	return -ENODEV;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static const struct pci_device_id __devinitdata uhci_pci_ids [] = { {
+
+	/* handle any USB UHCI controller */
+	class: 		((PCI_CLASS_SERIAL_USB << 8) | 0x00),
+	class_mask: 	~0,
+
+	/* no matter who makes it */
+	vendor:		PCI_ANY_ID,
+	device:		PCI_ANY_ID,
+	subvendor:	PCI_ANY_ID,
+	subdevice:	PCI_ANY_ID,
+
+	}, { /* end: all zeroes */ }
+};
+
+MODULE_DEVICE_TABLE (pci, uhci_pci_ids);
+
+static struct pci_driver uhci_pci_driver = {
+	name:		"usb-uhci",
+	id_table:	&uhci_pci_ids [0],
+
+	probe:		uhci_pci_probe,
+	remove:		uhci_pci_remove,
+
+#ifdef	CONFIG_PM
+	suspend:	uhci_pci_suspend,
+	resume:		uhci_pci_resume,
+#endif	/* PM */
+
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int __init uhci_hcd_init (void) 
+{
+	int retval;
+
+#ifdef DEBUG_SLAB
+	urb_priv_kmem = kmem_cache_create("urb_priv", sizeof(urb_priv_t), 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+	
+	if(!urb_priv_kmem) {
+		err("kmem_cache_create for urb_priv_t failed (out of memory)");
+		return -ENOMEM;
+	}
+#endif	
+	info(VERSTR);
+
+#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
+	info("High bandwidth mode enabled");	
+#endif
+
+	retval = pci_module_init (&uhci_pci_driver);
+
+#ifdef DEBUG_SLAB
+	if (retval < 0 ) {
+		if (kmem_cache_destroy(urb_priv_kmem))
+			err("urb_priv_kmem remained");
+	}
+#endif
+	
+	info(DRIVER_VERSION ":" DRIVER_DESC);
+
+	return retval;
+}
+
+static void __exit uhci_hcd_cleanup (void) 
+{      
+	pci_unregister_driver (&uhci_pci_driver);
+	
+#ifdef DEBUG_SLAB
+	if(kmem_cache_destroy(urb_priv_kmem))
+		err("urb_priv_kmem remained");
+#endif
+}
+
+module_init (uhci_hcd_init);
+module_exit (uhci_hcd_cleanup);
+
+
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/host/usb-uhci.h linux-2.4.21-pre6/drivers/usb/host/usb-uhci.h
--- linux-2.4.20/drivers/usb/host/usb-uhci.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/host/usb-uhci.h	2003-03-26 23:49:00.000000000 +0000
@@ -0,0 +1,308 @@
+#ifndef __LINUX_UHCI_H
+#define __LINUX_UHCI_H
+
+/*
+   $Id: usb-uhci.h,v 1.58 2001/08/28 16:45:00 acher Exp $
+ */
+#define MODNAME "usb-uhci"
+#define UHCI_LATENCY_TIMER 0
+
+static __inline__ void uhci_wait_ms(unsigned int ms)
+{
+	if(!in_interrupt())
+	{
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1 + ms * HZ / 1000);
+	}
+	else
+		mdelay(ms);
+}
+
+/* Command register */
+#define USBCMD		0
+#define   USBCMD_RS		0x0001	/* Run/Stop */
+#define   USBCMD_HCRESET	0x0002	/* Host reset */
+#define   USBCMD_GRESET		0x0004	/* Global reset */
+#define   USBCMD_EGSM		0x0008	/* Global Suspend Mode */
+#define   USBCMD_FGR		0x0010	/* Force Global Resume */
+#define   USBCMD_SWDBG		0x0020	/* SW Debug mode */
+#define   USBCMD_CF		0x0040	/* Config Flag (sw only) */
+#define   USBCMD_MAXP		0x0080	/* Max Packet (0 = 32, 1 = 64) */
+
+/* Status register */
+#define USBSTS		2
+#define   USBSTS_USBINT		0x0001	/* Interrupt due to IOC */
+#define   USBSTS_ERROR		0x0002	/* Interrupt due to error */
+#define   USBSTS_RD		0x0004	/* Resume Detect */
+#define   USBSTS_HSE		0x0008	/* Host System Error - basically PCI problems */
+#define   USBSTS_HCPE		0x0010	/* Host Controller Process Error - the scripts were buggy */
+#define   USBSTS_HCH		0x0020	/* HC Halted */
+
+/* Interrupt enable register */
+#define USBINTR		4
+#define   USBINTR_TIMEOUT	0x0001	/* Timeout/CRC error enable */
+#define   USBINTR_RESUME	0x0002	/* Resume interrupt enable */
+#define   USBINTR_IOC		0x0004	/* Interrupt On Complete enable */
+#define   USBINTR_SP		0x0008	/* Short packet interrupt enable */
+
+#define USBFRNUM	6
+#define USBFLBASEADD	8
+#define USBSOF		12
+
+/* USB port status and control registers */
+#define USBPORTSC1	16
+#define USBPORTSC2	18
+#define   USBPORTSC_CCS		0x0001	/* Current Connect Status ("device present") */
+#define   USBPORTSC_CSC		0x0002	/* Connect Status Change */
+#define   USBPORTSC_PE		0x0004	/* Port Enable */
+#define   USBPORTSC_PEC		0x0008	/* Port Enable Change */
+#define   USBPORTSC_LS		0x0030	/* Line Status */
+#define   USBPORTSC_RD		0x0040	/* Resume Detect */
+#define   USBPORTSC_LSDA	0x0100	/* Low Speed Device Attached */
+#define   USBPORTSC_PR		0x0200	/* Port Reset */
+#define   USBPORTSC_SUSP	0x1000	/* Suspend */
+
+/* Legacy support register */
+#define USBLEGSUP 0xc0
+#define USBLEGSUP_DEFAULT 0x2000	/* only PIRQ enable set */
+
+#define UHCI_NULL_DATA_SIZE	0x7ff	/* for UHCI controller TD */
+#define UHCI_PID 		0xff	/* PID MASK */
+
+#define UHCI_PTR_BITS		0x000F
+#define UHCI_PTR_TERM		0x0001
+#define UHCI_PTR_QH		0x0002
+#define UHCI_PTR_DEPTH		0x0004
+
+#define UHCI_NUMFRAMES		1024	/* in the frame list [array] */
+#define UHCI_MAX_SOF_NUMBER	2047	/* in an SOF packet */
+#define CAN_SCHEDULE_FRAMES	1000	/* how far future frames can be scheduled */
+
+/*
+ * for TD <status>:
+ */
+#define TD_CTRL_SPD		(1 << 29)	/* Short Packet Detect */
+#define TD_CTRL_C_ERR_MASK	(3 << 27)	/* Error Counter bits */
+#define TD_CTRL_LS		(1 << 26)	/* Low Speed Device */
+#define TD_CTRL_IOS		(1 << 25)	/* Isochronous Select */
+#define TD_CTRL_IOC		(1 << 24)	/* Interrupt on Complete */
+#define TD_CTRL_ACTIVE		(1 << 23)	/* TD Active */
+#define TD_CTRL_STALLED		(1 << 22)	/* TD Stalled */
+#define TD_CTRL_DBUFERR		(1 << 21)	/* Data Buffer Error */
+#define TD_CTRL_BABBLE		(1 << 20)	/* Babble Detected */
+#define TD_CTRL_NAK		(1 << 19)	/* NAK Received */
+#define TD_CTRL_CRCTIMEO	(1 << 18)	/* CRC/Time Out Error */
+#define TD_CTRL_BITSTUFF	(1 << 17)	/* Bit Stuff Error */
+#define TD_CTRL_ACTLEN_MASK	0x7ff	/* actual length, encoded as n - 1 */
+
+#define TD_CTRL_ANY_ERROR	(TD_CTRL_STALLED | TD_CTRL_DBUFERR | \
+				 TD_CTRL_BABBLE | TD_CTRL_CRCTIME | TD_CTRL_BITSTUFF)
+
+#define uhci_status_bits(ctrl_sts)	(ctrl_sts & 0xFE0000)
+#define uhci_actual_length(ctrl_sts)	((ctrl_sts + 1) & TD_CTRL_ACTLEN_MASK)	/* 1-based */
+#define uhci_ptr_to_virt(x)	bus_to_virt(x & ~UHCI_PTR_BITS)
+
+/*
+ * for TD <flags>:
+ */
+#define UHCI_TD_REMOVE		0x0001	/* Remove when done */
+
+/*
+ * for TD <info>: (a.k.a. Token)
+ */
+#define TD_TOKEN_TOGGLE		19
+
+#define uhci_maxlen(token)	((token) >> 21)
+#define uhci_toggle(token)	(((token) >> TD_TOKEN_TOGGLE) & 1)
+#define uhci_endpoint(token)	(((token) >> 15) & 0xf)
+#define uhci_devaddr(token)	(((token) >> 8) & 0x7f)
+#define uhci_devep(token)	(((token) >> 8) & 0x7ff)
+#define uhci_packetid(token)	((token) & 0xff)
+#define uhci_packetout(token)	(uhci_packetid(token) != USB_PID_IN)
+#define uhci_packetin(token)	(uhci_packetid(token) == USB_PID_IN)
+
+/* ------------------------------------------------------------------------------------
+   New TD/QH-structures
+   ------------------------------------------------------------------------------------ */
+typedef enum {
+	TD_TYPE, QH_TYPE
+} uhci_desc_type_t;
+
+typedef struct {
+	__u32 link;
+	__u32 status;
+	__u32 info;
+	__u32 buffer;
+} uhci_td_t, *puhci_td_t;
+
+typedef struct {
+	__u32 head;
+	__u32 element;		/* Queue element pointer */
+} uhci_qh_t, *puhci_qh_t;
+
+typedef struct {
+	union {
+		uhci_td_t td;
+		uhci_qh_t qh;
+	} hw;
+	uhci_desc_type_t type;
+	dma_addr_t dma_addr;
+	struct list_head horizontal;
+	struct list_head vertical;
+	struct list_head desc_list;
+	int last_used;
+} uhci_desc_t, *puhci_desc_t;
+
+typedef struct {
+	struct list_head desc_list;	// list pointer to all corresponding TDs/QHs associated with this request
+	dma_addr_t setup_packet_dma;
+	dma_addr_t transfer_buffer_dma;
+	unsigned long started;
+	struct urb *next_queued_urb;	// next queued urb for this EP
+	struct urb *prev_queued_urb;
+	uhci_desc_t *bottom_qh;
+	uhci_desc_t *next_qh;       	// next helper QH
+	char use_loop;
+	char flags;
+} urb_priv_t, *purb_priv_t;
+
+struct virt_root_hub {
+	int devnum;		/* Address of Root Hub endpoint */
+	void *urb;
+	void *int_addr;
+	int send;
+	int interval;
+	int numports;
+	int c_p_r[8];
+	struct timer_list rh_int_timer;
+};
+
+typedef struct uhci {
+	int irq;
+	unsigned int io_addr;
+	unsigned int io_size;
+	unsigned int maxports;
+	int running;
+
+	int apm_state;
+
+	struct uhci *next;	// chain of uhci device contexts
+
+	struct list_head urb_list;	// list of all pending urbs
+
+	spinlock_t urb_list_lock;	// lock to keep consistency 
+
+	int unlink_urb_done;
+	atomic_t avoid_bulk;
+	
+	struct usb_bus *bus;	// our bus
+
+	__u32 *framelist;
+	dma_addr_t framelist_dma;
+	uhci_desc_t **iso_td;
+	uhci_desc_t *int_chain[8];
+	uhci_desc_t *ls_control_chain;
+	uhci_desc_t *control_chain;
+	uhci_desc_t *bulk_chain;
+	uhci_desc_t *chain_end;
+	uhci_desc_t *td1ms;
+	uhci_desc_t *td32ms;
+	struct list_head free_desc;
+	spinlock_t qh_lock;
+	spinlock_t td_lock;
+	struct virt_root_hub rh;	//private data of the virtual root hub
+	int loop_usage;            // URBs using bandwidth reclamation
+
+	struct list_head urb_unlinked;	// list of all unlinked  urbs
+	long timeout_check;
+	int timeout_urbs;
+	struct pci_dev *uhci_pci;
+	struct pci_pool *desc_pool;
+	long last_error_time;          // last error output in uhci_interrupt()
+} uhci_t, *puhci_t;
+
+
+#define MAKE_TD_ADDR(a) ((a)->dma_addr&~UHCI_PTR_QH)
+#define MAKE_QH_ADDR(a) ((a)->dma_addr|UHCI_PTR_QH)
+#define UHCI_GET_CURRENT_FRAME(uhci) (inw ((uhci)->io_addr + USBFRNUM))
+
+#define CLEAN_TRANSFER_NO_DELETION 0
+#define CLEAN_TRANSFER_REGULAR 1
+#define CLEAN_TRANSFER_DELETION_MARK 2
+
+#define CLEAN_NOT_FORCED 0
+#define CLEAN_FORCED 1
+
+#define PROCESS_ISO_REGULAR 0
+#define PROCESS_ISO_FORCE 1
+
+#define UNLINK_ASYNC_STORE_URB 0
+#define UNLINK_ASYNC_DONT_STORE 1
+
+#define is_td_active(desc) (desc->hw.td.status & cpu_to_le32(TD_CTRL_ACTIVE))
+
+#define set_qh_head(desc,val) (desc)->hw.qh.head=cpu_to_le32(val)
+#define set_qh_element(desc,val) (desc)->hw.qh.element=cpu_to_le32(val)
+#define set_td_link(desc,val) (desc)->hw.td.link=cpu_to_le32(val)
+#define set_td_ioc(desc) (desc)->hw.td.status |= cpu_to_le32(TD_CTRL_IOC)
+#define clr_td_ioc(desc) (desc)->hw.td.status &= cpu_to_le32(~TD_CTRL_IOC)
+
+
+/* ------------------------------------------------------------------------------------ 
+   Virtual Root HUB 
+   ------------------------------------------------------------------------------------ */
+/* destination of request */
+#define RH_INTERFACE               0x01
+#define RH_ENDPOINT                0x02
+#define RH_OTHER                   0x03
+
+#define RH_CLASS                   0x20
+#define RH_VENDOR                  0x40
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define RH_GET_STATUS           0x0080
+#define RH_CLEAR_FEATURE        0x0100
+#define RH_SET_FEATURE          0x0300
+#define RH_SET_ADDRESS			0x0500
+#define RH_GET_DESCRIPTOR		0x0680
+#define RH_SET_DESCRIPTOR       0x0700
+#define RH_GET_CONFIGURATION	0x0880
+#define RH_SET_CONFIGURATION	0x0900
+#define RH_GET_STATE            0x0280
+#define RH_GET_INTERFACE        0x0A80
+#define RH_SET_INTERFACE        0x0B00
+#define RH_SYNC_FRAME           0x0C80
+/* Our Vendor Specific Request */
+#define RH_SET_EP               0x2000
+
+
+/* Hub port features */
+#define RH_PORT_CONNECTION         0x00
+#define RH_PORT_ENABLE             0x01
+#define RH_PORT_SUSPEND            0x02
+#define RH_PORT_OVER_CURRENT       0x03
+#define RH_PORT_RESET              0x04
+#define RH_PORT_POWER              0x08
+#define RH_PORT_LOW_SPEED          0x09
+#define RH_C_PORT_CONNECTION       0x10
+#define RH_C_PORT_ENABLE           0x11
+#define RH_C_PORT_SUSPEND          0x12
+#define RH_C_PORT_OVER_CURRENT     0x13
+#define RH_C_PORT_RESET            0x14
+
+/* Hub features */
+#define RH_C_HUB_LOCAL_POWER       0x00
+#define RH_C_HUB_OVER_CURRENT      0x01
+
+#define RH_DEVICE_REMOTE_WAKEUP    0x00
+#define RH_ENDPOINT_STALL          0x01
+
+/* Our Vendor Specific feature */
+#define RH_REMOVE_EP               0x00
+
+
+#define RH_ACK                     0x01
+#define RH_REQ_ERR                 -1
+#define RH_NACK                    0x00
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/hpusbscsi.c linux-2.4.21-pre6/drivers/usb/hpusbscsi.c
--- linux-2.4.20/drivers/usb/hpusbscsi.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/hpusbscsi.c	2003-03-26 23:49:55.000000000 +0000
@@ -71,7 +71,7 @@
 
 #ifdef HPUSBSCSI_DEBUG
 #  define PDEBUG(level, fmt, args...) \
-          if (debug >= (level)) info("[" __PRETTY_FUNCTION__ ":%d] " fmt, __LINE__ , \
+          if (debug >= (level)) info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ , \
                  ## args)
 #else
 #  define PDEBUG(level, fmt, args...) do {} while(0)
@@ -125,7 +125,11 @@
 	new->dev = dev;
 	init_waitqueue_head (&new->pending);
 	init_waitqueue_head (&new->deathrow);
+	init_MUTEX(&new->lock);
 	INIT_LIST_HEAD (&new->lh);
+	
+	if (id->idVendor == 0x0686 && id->idProduct == 0x4004)
+		new->need_short_workaround = 1;
 
 
 
@@ -202,12 +206,12 @@
 {
 	struct hpusbscsi *hp = (struct hpusbscsi *)ptr;
 
+	down(&hp->lock);
 	usb_unlink_urb(&hp->controlurb);
 	usb_unlink_urb(&hp->dataurb);
 
-	spin_lock_irq(&io_request_lock);
 	hp->dev = NULL;
-	spin_unlock_irq(&io_request_lock);
+	up(&hp->lock);
 }
 
 static struct usb_device_id hpusbscsi_usb_ids[] = {
@@ -339,7 +343,7 @@
 {
 	struct hpusbscsi* hpusbscsi = (struct hpusbscsi*)(srb->host->hostdata[0]);
 	usb_urb_callback usb_callback;
-	int res;
+	int res, passed_length;
 
 	spin_unlock_irq(&io_request_lock);
 
@@ -347,8 +351,30 @@
 	if ( srb->device->lun || srb->device->id || srb->device->channel ) {
 		srb->result = DID_BAD_TARGET;
 		callback(srb);
+		goto out_nolock;
+	}
+
+	/* to prevent a race with removal */
+	down(&hpusbscsi->lock);
+
+	if (hpusbscsi->dev == NULL) {
+		srb->result = DID_ERROR;
+		callback(srb);
 		goto out;
 	}
+	
+	/* otto fix - the Scan Elite II has a 5 second
+	* delay anytime the srb->cmd_len=6
+	* This causes it to run very slowly unless we
+	* pad the command length to 10 */
+        
+	if (hpusbscsi -> need_short_workaround && srb->cmd_len < 10) {
+		memset(srb->cmnd + srb->cmd_len, 0, 10 - srb->cmd_len);
+		passed_length = 10;
+	} else {
+		passed_length = srb->cmd_len;
+	}
+        
 
 	/* Now we need to decide which callback to give to the urb we send the command with */
 
@@ -394,18 +420,13 @@
 		hpusbscsi->dev,
 		usb_sndbulkpipe(hpusbscsi->dev,hpusbscsi->ep_out),
 		srb->cmnd,
-		srb->cmd_len,
+		passed_length,
 		usb_callback,
 		hpusbscsi
 	);
 	hpusbscsi->scallback = callback;
 	hpusbscsi->srb = srb;
-	
-	if (hpusbscsi->dev == NULL) {
-		srb->result = DID_ERROR;
-		callback(srb);
-		goto out;
-	}
+
 
 	res = usb_submit_urb(&hpusbscsi->dataurb);
 	if (res) {
@@ -417,6 +438,8 @@
 	}
 
 out:
+	up(&hpusbscsi->lock);
+out_nolock:
 	spin_lock_irq(&io_request_lock);
 	return 0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/hpusbscsi.h linux-2.4.21-pre6/drivers/usb/hpusbscsi.h
--- linux-2.4.20/drivers/usb/hpusbscsi.h	2002-08-03 00:39:44.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/hpusbscsi.h	2003-03-26 23:49:07.000000000 +0000
@@ -20,6 +20,7 @@
         int ep_in;
         int ep_int;
         int interrupt_interval;
+	int need_short_workaround;
 
         struct Scsi_Host *host;
         Scsi_Host_Template ctempl;
@@ -29,6 +30,7 @@
 	u8 sense_command[SENSE_COMMAND_SIZE];
 
         int use_count;
+	struct semaphore lock;
         wait_queue_head_t pending;
         wait_queue_head_t deathrow;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/ibmcam.c linux-2.4.21-pre6/drivers/usb/ibmcam.c
--- linux-2.4.20/drivers/usb/ibmcam.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/ibmcam.c	2003-03-26 23:49:19.000000000 +0000
@@ -78,7 +78,7 @@
 };
 
 /*
- * This structure lives in uvd_t->user field.
+ * This structure lives in uvd->user field.
  */
 typedef struct {
 	int initialized;	/* Had we already sent init sequence? */
@@ -87,7 +87,7 @@
 } ibmcam_t;
 #define	IBMCAM_T(uvd)	((ibmcam_t *)((uvd)->user_data))
 
-usbvideo_t *cams = NULL;
+struct usbvideo *cams = NULL;
 
 static int debug = 0;
 
@@ -249,9 +249,9 @@
  * History:
  * 1/21/00  Created.
  */
-static ParseState_t ibmcam_find_header(uvd_t *uvd) /* FIXME: Add frame here */
+static enum ParseState ibmcam_find_header(struct uvd *uvd) /* FIXME: Add frame here */
 {
-	usbvideo_frame_t *frame;
+	struct usbvideo_frame *frame;
 	ibmcam_t *icam;
 
 	if ((uvd->curframe) < 0 || (uvd->curframe >= USBVIDEO_NUMFRAMES)) {
@@ -397,9 +397,9 @@
  * 21-Jan-2000 Created.
  * 12-Oct-2000 Reworked to reflect interlaced nature of the data.
  */
-static ParseState_t ibmcam_parse_lines(
-	uvd_t *uvd,
-	usbvideo_frame_t *frame,
+static enum ParseState ibmcam_parse_lines(
+	struct uvd *uvd,
+	struct usbvideo_frame *frame,
 	long *pcopylen)
 {
 	unsigned char *f;
@@ -662,9 +662,9 @@
  * them both as R component in attempt to at least partially recover the
  * lost resolution.
  */
-static ParseState_t ibmcam_model2_320x240_parse_lines(
-	uvd_t *uvd,
-	usbvideo_frame_t *frame,
+static enum ParseState ibmcam_model2_320x240_parse_lines(
+	struct uvd *uvd,
+	struct usbvideo_frame *frame,
 	long *pcopylen)
 {
 	unsigned char *f, *la, *lb;
@@ -816,9 +816,9 @@
 		return scan_Continue;
 }
 
-static ParseState_t ibmcam_model3_parse_lines(
-	uvd_t *uvd,
-	usbvideo_frame_t *frame,
+static enum ParseState ibmcam_model3_parse_lines(
+	struct uvd *uvd,
+	struct usbvideo_frame *frame,
 	long *pcopylen)
 {
 	unsigned char *data;
@@ -961,9 +961,9 @@
  * History:
  * 10-Feb-2001 Created.
  */
-static ParseState_t ibmcam_model4_128x96_parse_lines(
-	uvd_t *uvd,
-	usbvideo_frame_t *frame,
+static enum ParseState ibmcam_model4_128x96_parse_lines(
+	struct uvd *uvd,
+	struct usbvideo_frame *frame,
 	long *pcopylen)
 {
 	const unsigned char *data_rv, *data_gv, *data_bv;
@@ -1049,9 +1049,9 @@
  * History:
  * 1/21/00  Created.
  */
-void ibmcam_ProcessIsocData(uvd_t *uvd, usbvideo_frame_t *frame)
+void ibmcam_ProcessIsocData(struct uvd *uvd, struct usbvideo_frame *frame)
 {
-	ParseState_t newstate;
+	enum ParseState newstate;
 	long copylen = 0;
 	int mod = IBMCAM_T(uvd)->camera_model;
 
@@ -1128,7 +1128,7 @@
  * 1/27/00  Added check for dev == NULL; this happens if camera is unplugged.
  */
 static int ibmcam_veio(
-	uvd_t *uvd,
+	struct uvd *uvd,
 	unsigned char req,
 	unsigned short value,
 	unsigned short index)
@@ -1195,7 +1195,7 @@
  * History:
  * 1/18/00  Created.
  */
-static int ibmcam_calculate_fps(uvd_t *uvd)
+static int ibmcam_calculate_fps(struct uvd *uvd)
 {
 	return 3 + framerate*4 + framerate/2;
 }
@@ -1209,33 +1209,33 @@
  * History:
  * 1/2/00   Created.
  */
-static void ibmcam_send_FF_04_02(uvd_t *uvd)
+static void ibmcam_send_FF_04_02(struct uvd *uvd)
 {
 	ibmcam_veio(uvd, 0, 0x00FF, 0x0127);
 	ibmcam_veio(uvd, 0, 0x0004, 0x0124);
 	ibmcam_veio(uvd, 0, 0x0002, 0x0124);
 }
 
-static void ibmcam_send_00_04_06(uvd_t *uvd)
+static void ibmcam_send_00_04_06(struct uvd *uvd)
 {
 	ibmcam_veio(uvd, 0, 0x0000, 0x0127);
 	ibmcam_veio(uvd, 0, 0x0004, 0x0124);
 	ibmcam_veio(uvd, 0, 0x0006, 0x0124);
 }
 
-static void ibmcam_send_x_00(uvd_t *uvd, unsigned short x)
+static void ibmcam_send_x_00(struct uvd *uvd, unsigned short x)
 {
 	ibmcam_veio(uvd, 0, x,      0x0127);
 	ibmcam_veio(uvd, 0, 0x0000, 0x0124);
 }
 
-static void ibmcam_send_x_00_05(uvd_t *uvd, unsigned short x)
+static void ibmcam_send_x_00_05(struct uvd *uvd, unsigned short x)
 {
 	ibmcam_send_x_00(uvd, x);
 	ibmcam_veio(uvd, 0, 0x0005, 0x0124);
 }
 
-static void ibmcam_send_x_00_05_02(uvd_t *uvd, unsigned short x)
+static void ibmcam_send_x_00_05_02(struct uvd *uvd, unsigned short x)
 {
 	ibmcam_veio(uvd, 0, x,      0x0127);
 	ibmcam_veio(uvd, 0, 0x0000, 0x0124);
@@ -1243,7 +1243,7 @@
 	ibmcam_veio(uvd, 0, 0x0002, 0x0124);
 }
 
-static void ibmcam_send_x_01_00_05(uvd_t *uvd, unsigned short x)
+static void ibmcam_send_x_01_00_05(struct uvd *uvd, unsigned short x)
 {
 	ibmcam_veio(uvd, 0, x,      0x0127);
 	ibmcam_veio(uvd, 0, 0x0001, 0x0124);
@@ -1251,7 +1251,7 @@
 	ibmcam_veio(uvd, 0, 0x0005, 0x0124);
 }
 
-static void ibmcam_send_x_00_05_02_01(uvd_t *uvd, unsigned short x)
+static void ibmcam_send_x_00_05_02_01(struct uvd *uvd, unsigned short x)
 {
 	ibmcam_veio(uvd, 0, x,      0x0127);
 	ibmcam_veio(uvd, 0, 0x0000, 0x0124);
@@ -1260,7 +1260,7 @@
 	ibmcam_veio(uvd, 0, 0x0001, 0x0124);
 }
 
-static void ibmcam_send_x_00_05_02_08_01(uvd_t *uvd, unsigned short x)
+static void ibmcam_send_x_00_05_02_08_01(struct uvd *uvd, unsigned short x)
 {
 	ibmcam_veio(uvd, 0, x,      0x0127);
 	ibmcam_veio(uvd, 0, 0x0000, 0x0124);
@@ -1270,7 +1270,7 @@
 	ibmcam_veio(uvd, 0, 0x0001, 0x0124);
 }
 
-static void ibmcam_Packet_Format1(uvd_t *uvd, unsigned char fkey, unsigned char val)
+static void ibmcam_Packet_Format1(struct uvd *uvd, unsigned char fkey, unsigned char val)
 {
 	ibmcam_send_x_01_00_05(uvd, unknown_88);
 	ibmcam_send_x_00_05(uvd, fkey);
@@ -1284,20 +1284,20 @@
 	ibmcam_send_FF_04_02(uvd);
 }
 
-static void ibmcam_PacketFormat2(uvd_t *uvd, unsigned char fkey, unsigned char val)
+static void ibmcam_PacketFormat2(struct uvd *uvd, unsigned char fkey, unsigned char val)
 {
 	ibmcam_send_x_01_00_05	(uvd, unknown_88);
 	ibmcam_send_x_00_05	(uvd, fkey);
 	ibmcam_send_x_00_05_02	(uvd, val);
 }
 
-static void ibmcam_model2_Packet2(uvd_t *uvd)
+static void ibmcam_model2_Packet2(struct uvd *uvd)
 {
 	ibmcam_veio(uvd, 0, 0x00ff, 0x012d);
 	ibmcam_veio(uvd, 0, 0xfea3, 0x0124);
 }
 
-static void ibmcam_model2_Packet1(uvd_t *uvd, unsigned short v1, unsigned short v2)
+static void ibmcam_model2_Packet1(struct uvd *uvd, unsigned short v1, unsigned short v2)
 {
 	ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
 	ibmcam_veio(uvd, 0, 0x00ff, 0x012e);
@@ -1318,7 +1318,7 @@
  * 00_0096_0127
  * 00_fea8_0124	
 */
-static void ibmcam_model3_Packet1(uvd_t *uvd, unsigned short v1, unsigned short v2)
+static void ibmcam_model3_Packet1(struct uvd *uvd, unsigned short v1, unsigned short v2)
 {
 	ibmcam_veio(uvd, 0, 0x0078, 0x012d);
 	ibmcam_veio(uvd, 0, v1,     0x012f);
@@ -1327,7 +1327,7 @@
 	ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
 }
 
-static void ibmcam_model4_BrightnessPacket(uvd_t *uvd, int i)
+static void ibmcam_model4_BrightnessPacket(struct uvd *uvd, int i)
 {
 	ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
 	ibmcam_veio(uvd, 0, 0x0026, 0x012f);
@@ -1353,7 +1353,7 @@
  * History:
  * 1/2/00   Created.
  */
-static void ibmcam_adjust_contrast(uvd_t *uvd)
+static void ibmcam_adjust_contrast(struct uvd *uvd)
 {
 	unsigned char a_contrast = uvd->vpic.contrast >> 12;
 	unsigned char new_contrast;
@@ -1428,7 +1428,7 @@
  * 1/5/00   Created.
  * 2/20/00  Added support for Model 2 cameras.
  */
-static void ibmcam_change_lighting_conditions(uvd_t *uvd)
+static void ibmcam_change_lighting_conditions(struct uvd *uvd)
 {
 	static const char proc[] = "ibmcam_change_lighting_conditions";
 
@@ -1474,7 +1474,7 @@
  * range [0..6], where 0 is most smooth and 6 is most sharp (raw image, I guess).
  * Recommended value is 4. Cameras model 2 do not have this feature at all.
  */
-static void ibmcam_set_sharpness(uvd_t *uvd)
+static void ibmcam_set_sharpness(struct uvd *uvd)
 {
 	static const char proc[] = "ibmcam_set_sharpness";
 
@@ -1543,7 +1543,7 @@
  *
  * This procedure changes brightness of the picture.
  */
-static void ibmcam_set_brightness(uvd_t *uvd)
+static void ibmcam_set_brightness(struct uvd *uvd)
 {
 	static const char proc[] = "ibmcam_set_brightness";
 	static const unsigned short n = 1;
@@ -1608,7 +1608,7 @@
 	}
 }
 
-static void ibmcam_set_hue(uvd_t *uvd)
+static void ibmcam_set_hue(struct uvd *uvd)
 {
 	switch (IBMCAM_T(uvd)->camera_model) {
 	case IBMCAM_MODEL_2:
@@ -1704,14 +1704,14 @@
  * This procedure gets called from V4L interface to update picture settings.
  * Here we change brightness and contrast.
  */
-static void ibmcam_adjust_picture(uvd_t *uvd)
+static void ibmcam_adjust_picture(struct uvd *uvd)
 {
 	ibmcam_adjust_contrast(uvd);
 	ibmcam_set_brightness(uvd);
 	ibmcam_set_hue(uvd);
 }
 
-static int ibmcam_model1_setup(uvd_t *uvd)
+static int ibmcam_model1_setup(struct uvd *uvd)
 {
 	const int ntries = 5;
 	int i;
@@ -1908,7 +1908,7 @@
 	return (CAMERA_IS_OPERATIONAL(uvd) ? 0 : -EFAULT);
 }
 
-static int ibmcam_model2_setup(uvd_t *uvd)
+static int ibmcam_model2_setup(struct uvd *uvd)
 {
 	ibmcam_veio(uvd, 0, 0x0000, 0x0100);	/* LED on */
 	ibmcam_veio(uvd, 1, 0x0000, 0x0116);
@@ -1966,7 +1966,7 @@
  * This code adds finishing touches to the video data interface.
  * Here we configure the frame rate and turn on the LED.
  */
-static void ibmcam_model1_setup_after_video_if(uvd_t *uvd)
+static void ibmcam_model1_setup_after_video_if(struct uvd *uvd)
 {
 	unsigned short internal_frame_rate;
 
@@ -1978,7 +1978,7 @@
 	ibmcam_veio(uvd, 0, 0xc0, 0x010c);
 }
 
-static void ibmcam_model2_setup_after_video_if(uvd_t *uvd)
+static void ibmcam_model2_setup_after_video_if(struct uvd *uvd)
 {
 	unsigned short setup_model2_rg2, setup_model2_sat, setup_model2_yb;
 
@@ -2154,7 +2154,7 @@
 	usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
 }
 
-static void ibmcam_model4_setup_after_video_if(uvd_t *uvd)
+static void ibmcam_model4_setup_after_video_if(struct uvd *uvd)
 {
 	switch (uvd->videosize) {
 	case VIDEOSIZE_128x96:
@@ -2704,7 +2704,7 @@
 	usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
 }
 
-static void ibmcam_model3_setup_after_video_if(uvd_t *uvd)
+static void ibmcam_model3_setup_after_video_if(struct uvd *uvd)
 {
 	int i;
 	/*
@@ -3485,7 +3485,7 @@
  * This code tells camera to stop streaming. The interface remains
  * configured and bandwidth - claimed.
  */
-static void ibmcam_video_stop(uvd_t *uvd)
+static void ibmcam_video_stop(struct uvd *uvd)
 {
 	switch (IBMCAM_T(uvd)->camera_model) {
 	case IBMCAM_MODEL_1:
@@ -3546,7 +3546,7 @@
  * History:
  * 1/2/00   Created.
  */
-static void ibmcam_reinit_iso(uvd_t *uvd, int do_stop)
+static void ibmcam_reinit_iso(struct uvd *uvd, int do_stop)
 {
 	switch (IBMCAM_T(uvd)->camera_model) {
 	case IBMCAM_MODEL_1:
@@ -3570,7 +3570,7 @@
 	}
 }
 
-static void ibmcam_video_start(uvd_t *uvd)
+static void ibmcam_video_start(struct uvd *uvd)
 {
 	ibmcam_change_lighting_conditions(uvd);
 	ibmcam_set_sharpness(uvd);
@@ -3580,7 +3580,7 @@
 /*
  * Return negative code on failure, 0 on success.
  */
-static int ibmcam_setup_on_open(uvd_t *uvd)
+static int ibmcam_setup_on_open(struct uvd *uvd)
 {
 	int setup_ok = 0; /* Success by default */
 	/* Send init sequence only once, it's large! */
@@ -3602,7 +3602,7 @@
 	return setup_ok;
 }
 
-static void ibmcam_configure_video(uvd_t *uvd)
+static void ibmcam_configure_video(struct uvd *uvd)
 {
 	if (uvd == NULL)
 		return;
@@ -3658,7 +3658,7 @@
  */
 static void *ibmcam_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *devid)
 {
-	uvd_t *uvd = NULL;
+	struct uvd *uvd = NULL;
 	int i, nas, model=0, canvasX=0, canvasY=0;
 	int actInterface=-1, inactInterface=-1, maxPS=0;
 	unsigned char video_ep = 0;
@@ -3868,7 +3868,7 @@
 	MOD_INC_USE_COUNT;
 	uvd = usbvideo_AllocateDevice(cams);
 	if (uvd != NULL) {
-		/* Here uvd is a fully allocated uvd_t object */
+		/* Here uvd is a fully allocated uvd object */
 		uvd->flags = flags;
 		uvd->debug = debug;
 		uvd->dev = dev;
@@ -3899,6 +3899,17 @@
 	return uvd;
 }
 
+
+static struct usb_device_id id_table[] = {
+	{ USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x0002, 0x0002) },	/* Model 1 */
+	{ USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x030a, 0x030a) },	/* Model 2 */
+	{ USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x0301, 0x0301) },	/* Model 3 */
+	{ USB_DEVICE_VER(IBMCAM_VENDOR_ID, NETCAM_PRODUCT_ID, 0x030a, 0x030a) },	/* Model 4 */
+	{ USB_DEVICE_VER(IBMCAM_VENDOR_ID, VEO_800C_PRODUCT_ID, 0x030a, 0x030a) },	/* Model 2 */
+	{ USB_DEVICE_VER(IBMCAM_VENDOR_ID, VEO_800D_PRODUCT_ID, 0x030a, 0x030a) },	/* Model 4 */
+	{ }  /* Terminating entry */
+};
+
 /*
  * ibmcam_init()
  *
@@ -3910,7 +3921,7 @@
  */
 static int __init ibmcam_init(void)
 {
-	usbvideo_cb_t cbTbl;
+	struct usbvideo_cb cbTbl;
 	memset(&cbTbl, 0, sizeof(cbTbl));
 	cbTbl.probe = ibmcam_probe;
 	cbTbl.setupOnOpen = ibmcam_setup_on_open;
@@ -3926,7 +3937,8 @@
 		sizeof(ibmcam_t),
 		"ibmcam",
 		&cbTbl,
-		THIS_MODULE);
+		THIS_MODULE,
+		id_table);
 }
 
 static void __exit ibmcam_cleanup(void)
@@ -3934,15 +3946,6 @@
 	usbvideo_Deregister(&cams);
 }
 
-static __devinitdata struct usb_device_id id_table[] = {
-	{ USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x0002, 0x0002) },	/* Model 1 */
-	{ USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x030a, 0x030a) },	/* Model 2 */
-	{ USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x0301, 0x0301) },	/* Model 3 */
-	{ USB_DEVICE_VER(IBMCAM_VENDOR_ID, NETCAM_PRODUCT_ID, 0x030a, 0x030a) },	/* Model 4 */
-	{ USB_DEVICE_VER(IBMCAM_VENDOR_ID, VEO_800C_PRODUCT_ID, 0x030a, 0x030a) },	/* Model 2 */
-	{ USB_DEVICE_VER(IBMCAM_VENDOR_ID, VEO_800D_PRODUCT_ID, 0x030a, 0x030a) },	/* Model 4 */
-	{ }  /* Terminating entry */
-};
 MODULE_DEVICE_TABLE(usb, id_table);
 
 module_init(ibmcam_init);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/kaweth.c linux-2.4.21-pre6/drivers/usb/kaweth.c
--- linux-2.4.20/drivers/usb/kaweth.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/kaweth.c	2003-03-26 23:49:50.000000000 +0000
@@ -131,6 +131,7 @@
 	{ USB_DEVICE(0x03e8, 0x0008) }, /* AOX Endpoints USB Ethernet */
 	{ USB_DEVICE(0x04bb, 0x0901) }, /* I-O DATA USB-ET/T */
 	{ USB_DEVICE(0x0506, 0x03e8) }, /* 3Com 3C19250 */
+	{ USB_DEVICE(0x0506, 0x11f8) }, /* 3Com 3C460 */
 	{ USB_DEVICE(0x0557, 0x2002) }, /* ATEN USB Ethernet */
 	{ USB_DEVICE(0x0557, 0x4000) }, /* D-Link DSB-650C */
 	{ USB_DEVICE(0x0565, 0x0002) }, /* Peracom Enet */
@@ -142,6 +143,7 @@
 	{ USB_DEVICE(0x06e1, 0x0008) }, /* ADS USB-10BT */
 	{ USB_DEVICE(0x06e1, 0x0009) }, /* ADS USB-10BT */
 	{ USB_DEVICE(0x0707, 0x0100) }, /* SMC 2202USB */
+	{ USB_DEVICE(0x0785, 0x0002) }, /* NTT-TE MN128 USB-Ethernet Adapter */
 	{ USB_DEVICE(0x07aa, 0x0001) }, /* Correga K.K. */
 	{ USB_DEVICE(0x07b8, 0x4000) }, /* D-Link DU-E10 */
 	{ USB_DEVICE(0x0846, 0x1001) }, /* NetGear EA-101 */
@@ -691,7 +693,7 @@
 		kaweth_dbg("%s: TX status %d.", kaweth->net->name, urb->status);
 
 	netif_wake_queue(kaweth->net);
-	dev_kfree_skb(skb);
+	dev_kfree_skb_irq(skb);
 }
 
 /****************************************************************
@@ -700,7 +702,7 @@
 static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net)
 {
 	struct kaweth_device *kaweth = net->priv;
-	char *private_header;
+	u16 *private_header;
 
 	int res;
 
@@ -709,7 +711,7 @@
 	if (kaweth->removed) {
 	/* our device is undergoing disconnection - we bail out */
 		spin_unlock(&kaweth->device_lock);
-		dev_kfree_skb(skb);
+		dev_kfree_skb_irq(skb);
 		return 0;
 	}
 
@@ -721,7 +723,7 @@
 		/* no such luck - we make our own */
 		struct sk_buff *copied_skb;
 		copied_skb = skb_copy_expand(skb, 2, 0, GFP_ATOMIC);
-		dev_kfree_skb_any(skb);
+		dev_kfree_skb_irq(skb);
 		skb = copied_skb;
 		if (!copied_skb) {
 			kaweth->stats.tx_errors++;
@@ -732,7 +734,7 @@
 	}
 
 	private_header = __skb_push(skb, 2);
-	*private_header = cpu_to_le16(skb->len);
+	*private_header = cpu_to_le16(skb->len-2);
 	kaweth->tx_skb = skb;
 
 	FILL_BULK_URB(kaweth->tx_urb,
@@ -751,7 +753,7 @@
 		kaweth->stats.tx_errors++;
 
 		netif_start_queue(net);
-		dev_kfree_skb(skb);
+		dev_kfree_skb_irq(skb);
 	}
 	else
 	{
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/kbtab.c linux-2.4.21-pre6/drivers/usb/kbtab.c
--- linux-2.4.20/drivers/usb/kbtab.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/kbtab.c	2003-03-26 23:49:30.000000000 +0000
@@ -0,0 +1,179 @@
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v0.0.1"
+#define DRIVER_AUTHOR "Josh Myer <josh@joshisanerd.com>"
+#define DRIVER_DESC "KB Gear Jam Studio Tablet Driver"
+
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_LICENSE("GPL");
+
+#define USB_VENDOR_ID_KBTAB 0x84e
+
+static int       kb_pressure_click = 0x10;
+MODULE_PARM     (kb_pressure_click,"i");
+MODULE_PARM_DESC(kb_pressure_click,
+		 "pressure threshold for clicks");
+
+struct kbtab {
+	signed char data[8];
+	struct input_dev dev;
+	struct usb_device *usbdev;
+	struct urb irq;
+	int open;
+	int x, y;
+	int button;
+	int pressure;
+};
+
+static void kbtab_irq(struct urb *urb)
+{
+
+	struct kbtab *tab = urb->context;
+	unsigned char *data = tab->data;
+	struct input_dev *dev = &tab->dev;
+
+	if(urb->status)
+		return;
+
+	tab->x = (data[2] << 8) + data[1];
+	tab->y = (data[4] << 8) + data[3];
+
+	tab->pressure = (data[5]);
+
+	/* XXX: don't report unless actual change */
+
+	input_report_abs(dev, ABS_X, tab->x);
+	input_report_abs(dev, ABS_Y, tab->y);
+	input_report_abs(dev, ABS_PRESSURE, tab->pressure);
+
+	input_report_key(dev, BTN_STYLUS, (data[0] & 2));
+	input_report_key(dev, BTN_TOUCH, (data[0] & 1));
+	input_report_key(dev, BTN_LEFT, (tab->pressure > kb_pressure_click) ? 1 : 0);
+
+	input_event(dev, EV_MSC, MSC_SERIAL, 0);
+}
+
+struct usb_device_id kbtab_ids[] = {
+	{ USB_DEVICE(USB_VENDOR_ID_KBTAB, 0x1001), driver_info : 0 },
+	{ }
+};
+  
+MODULE_DEVICE_TABLE(usb, kbtab_ids);
+
+static int kbtab_open(struct input_dev *dev)
+{
+	struct kbtab *kbtab = dev->private;
+
+	if(kbtab->open++)
+		return 0;
+
+	kbtab->irq.dev = kbtab->usbdev;
+	if(usb_submit_urb(&kbtab->irq))
+		return -EIO;
+
+	return 0;
+}
+
+static void kbtab_close(struct input_dev *dev)
+{
+	struct kbtab *kbtab = dev->private;
+
+	if(!--kbtab->open)
+		usb_unlink_urb(&kbtab->irq);
+}
+
+static void *kbtab_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id)
+{
+	struct usb_endpoint_descriptor *endpoint;
+	struct kbtab *kbtab;
+
+	if(!(kbtab = kmalloc(sizeof(struct kbtab), GFP_KERNEL)))
+		return NULL;
+
+	memset(kbtab, 0, sizeof(struct kbtab));
+
+	kbtab->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_MSC);
+	kbtab->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
+
+	kbtab->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
+	kbtab->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_STYLUS);
+
+	kbtab->dev.mscbit[0] |= BIT(MSC_SERIAL);
+
+	kbtab->dev.absmax[ABS_X] = 0x2000;
+	kbtab->dev.absmax[ABS_Y] = 0x1750;
+
+	kbtab->dev.absmax[ABS_PRESSURE] = 0xff;
+  
+	kbtab->dev.absfuzz[ABS_X] = 4;
+	kbtab->dev.absfuzz[ABS_Y] = 4;
+  
+	kbtab->dev.private = kbtab;
+
+	kbtab->dev.open = kbtab_open;
+	kbtab->dev.close = kbtab_close;
+
+	kbtab->dev.name = "KB Gear Tablet";
+	kbtab->dev.idbus = BUS_USB;
+  
+	kbtab->dev.idvendor = dev->descriptor.idVendor;
+	kbtab->dev.idproduct = dev->descriptor.idProduct;
+	kbtab->dev.idversion = dev->descriptor.bcdDevice;
+	kbtab->usbdev = dev;
+
+
+	endpoint = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0;
+
+	usb_set_idle(dev, dev->config[0].interface[ifnum].altsetting[0].bInterfaceNumber, 0, 0);
+
+	FILL_INT_URB(&kbtab->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress),
+		     kbtab->data, 8, kbtab_irq, kbtab, endpoint->bInterval);
+
+	input_register_device(&kbtab->dev);
+
+	printk(KERN_INFO "input%d: KB Gear Tablet on usb%d:%d.%d\n",
+	       kbtab->dev.number, dev->bus->busnum, dev->devnum, ifnum);
+
+	return kbtab;
+
+}
+
+static void kbtab_disconnect(struct usb_device *dev, void *ptr)
+{
+	struct kbtab *kbtab = ptr;
+	usb_unlink_urb(&kbtab->irq);
+	input_unregister_device(&kbtab->dev);
+	kfree(kbtab);
+}
+
+static struct usb_driver kbtab_driver = {
+	name:		"kbtab",
+	probe:		kbtab_probe,
+	disconnect:	kbtab_disconnect,
+	id_table:	kbtab_ids,
+};
+
+static int __init kbtab_init(void)
+{
+	usb_register(&kbtab_driver);
+	info(DRIVER_VERSION " " DRIVER_AUTHOR);
+	info(DRIVER_DESC);
+	return 0;
+}
+
+static void __exit kbtab_exit(void)
+{
+	usb_deregister(&kbtab_driver);
+}
+
+module_init(kbtab_init);
+module_exit(kbtab_exit);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/konicawc.c linux-2.4.21-pre6/drivers/usb/konicawc.c
--- linux-2.4.20/drivers/usb/konicawc.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/konicawc.c	2003-03-26 23:49:40.000000000 +0000
@@ -0,0 +1,938 @@
+/*
+ * konicawc.c - konica webcam driver
+ *
+ * Author: Simon Evans <spse@secret.org.uk>
+ *
+ * Copyright (C) 2002 Simon Evans
+ *
+ * Licence: GPL
+ *
+ * Driver for USB webcams based on Konica chipset. This
+ * chipset is used in Intel YC76 camera.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+
+#include "usbvideo.h"
+
+#define MAX_BRIGHTNESS	108
+#define MAX_CONTRAST	108
+#define MAX_SATURATION	108
+#define MAX_SHARPNESS	108
+#define MAX_WHITEBAL	372
+#define MAX_SPEED	6
+
+
+#define MAX_CAMERAS	1
+
+#define DRIVER_VERSION	"v1.4"
+#define DRIVER_DESC	"Konica Webcam driver"
+
+enum ctrl_req {
+	SetWhitebal	= 0x01,
+	SetBrightness	= 0x02,
+        SetSharpness	= 0x03,
+	SetContrast	= 0x04,
+	SetSaturation	= 0x05,
+};
+
+
+enum frame_sizes {
+	SIZE_160X120	= 0,
+	SIZE_160X136	= 1,
+	SIZE_176X144	= 2,
+	SIZE_320X240	= 3,
+	
+};
+
+#define MAX_FRAME_SIZE	SIZE_320X240
+
+static struct usbvideo *cams;
+
+#ifdef CONFIG_USB_DEBUG
+static int debug;
+#define DEBUG(n, format, arg...) \
+	if (n <= debug) {	 \
+		printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __FUNCTION__ , ## arg); \
+	}
+#else
+#define DEBUG(n, arg...)
+static const int debug = 0;
+#endif
+
+
+/* Some default values for inital camera settings,
+   can be set by modprobe */
+
+static enum frame_sizes size;	
+static int speed = 6;		/* Speed (fps) 0 (slowest) to 6 (fastest) */
+static int brightness =	MAX_BRIGHTNESS/2;
+static int contrast =	MAX_CONTRAST/2;
+static int saturation =	MAX_SATURATION/2;
+static int sharpness =	MAX_SHARPNESS/2;
+static int whitebal =	3*(MAX_WHITEBAL/4);
+
+static int spd_to_iface[] = { 1, 0, 3, 2, 4, 5, 6 };
+
+/* These FPS speeds are from the windows config box. They are
+ * indexed on size (0-3) and speed (0-6). Divide by 3 to get the
+ * real fps.
+ */
+
+static int spd_to_fps[][7] = { { 24, 40, 48, 60, 72, 80, 100 },
+			       { 24, 40, 48, 60, 72, 80, 100 },
+			       { 18, 30, 36, 45, 54, 60, 75  },
+			       { 6,  10, 12, 15, 18, 21, 25  } };
+
+struct cam_size {
+	u16	width;
+	u16	height;
+	u8	cmd;
+};
+
+static struct cam_size camera_sizes[] = { { 160, 120, 0x7 },
+					  { 160, 136, 0xa },
+					  { 176, 144, 0x4 },
+					  { 320, 240, 0x5 } };
+
+struct konicawc {
+	u8 brightness;		/* camera uses 0 - 9, x11 for real value */
+	u8 contrast;		/* as above */
+	u8 saturation;		/* as above */
+	u8 sharpness;		/* as above */
+	u8 white_bal;		/* 0 - 33, x11 for real value */
+	u8 speed;		/* Stored as 0 - 6, used as index in spd_to_* (above) */
+	u8 size;		/* Frame Size */
+	int height;
+	int width;
+	struct urb *sts_urb[USBVIDEO_NUMSBUF];
+	u8 sts_buf[USBVIDEO_NUMSBUF][FRAMES_PER_DESC];
+	struct urb *last_data_urb, *last_sts_urb;
+	int lastframe;
+	int cur_frame_size;	/* number of bytes in current frame size */
+	int maxline;		/* number of lines per frame */
+	int yplanesz;		/* Number of bytes in the Y plane */
+	unsigned int buttonsts:1;
+#ifdef CONFIG_INPUT
+	struct input_dev input;
+#endif
+};
+
+
+#define konicawc_set_misc(uvd, req, value, index)		konicawc_ctrl_msg(uvd, USB_DIR_OUT, req, value, index, NULL, 0)
+#define konicawc_get_misc(uvd, req, value, index, buf, sz)	konicawc_ctrl_msg(uvd, USB_DIR_IN, req, value, index, buf, sz)
+#define konicawc_set_value(uvd, value, index)			konicawc_ctrl_msg(uvd, USB_DIR_OUT, 2, value, index, NULL, 0)
+
+
+static int konicawc_ctrl_msg(struct uvd *uvd, u8 dir, u8 request, u16 value, u16 index, void *buf, int len)
+{
+        int retval = usb_control_msg(uvd->dev,
+		dir ? usb_rcvctrlpipe(uvd->dev, 0) : usb_sndctrlpipe(uvd->dev, 0),
+		    request, 0x40 | dir, value, index, buf, len, HZ);
+        return retval < 0 ? retval : 0;
+}
+
+
+static inline void konicawc_camera_on(struct uvd *uvd)
+{
+        DEBUG(0, "camera on");
+        konicawc_set_misc(uvd, 0x2, 1, 0x0b);
+}
+
+
+static inline void konicawc_camera_off(struct uvd *uvd)
+{
+        DEBUG(0, "camera off");
+        konicawc_set_misc(uvd, 0x2, 0, 0x0b);
+}
+
+
+static void konicawc_set_camera_size(struct uvd *uvd)
+{
+	struct konicawc *cam = (struct konicawc *)uvd->user_data;
+
+	konicawc_set_misc(uvd, 0x2, camera_sizes[cam->size].cmd, 0x08);
+	cam->width = camera_sizes[cam->size].width;
+	cam->height = camera_sizes[cam->size].height;
+	cam->yplanesz = cam->height * cam->width;
+	cam->cur_frame_size = (cam->yplanesz * 3) / 2;
+	cam->maxline = cam->yplanesz / 256;
+	uvd->videosize = VIDEOSIZE(cam->width, cam->height);
+}
+
+
+static int konicawc_setup_on_open(struct uvd *uvd)
+{
+	struct konicawc *cam = (struct konicawc *)uvd->user_data;
+
+	DEBUG(1, "setting brightness to %d (%d)", cam->brightness,
+	    cam->brightness * 11);
+	konicawc_set_value(uvd, cam->brightness, SetBrightness);
+	DEBUG(1, "setting white balance to %d (%d)", cam->white_bal,
+	    cam->white_bal * 11);
+	konicawc_set_value(uvd, cam->white_bal, SetWhitebal);
+	DEBUG(1, "setting contrast to %d (%d)", cam->contrast,
+	    cam->contrast * 11);
+	konicawc_set_value(uvd, cam->contrast, SetContrast);
+	DEBUG(1, "setting saturation to %d (%d)", cam->saturation,
+	    cam->saturation * 11);
+	konicawc_set_value(uvd, cam->saturation, SetSaturation);
+	DEBUG(1, "setting sharpness to %d (%d)", cam->sharpness,
+	    cam->sharpness * 11);
+	konicawc_set_value(uvd, cam->sharpness, SetSharpness);
+	konicawc_set_camera_size(uvd);
+	cam->lastframe = -2;
+	cam->buttonsts = 0;
+	return 0;
+}
+
+
+static void konicawc_adjust_picture(struct uvd *uvd)
+{
+	struct konicawc *cam = (struct konicawc *)uvd->user_data;
+
+	konicawc_camera_off(uvd);
+	DEBUG(1, "new brightness: %d", uvd->vpic.brightness);
+	uvd->vpic.brightness = (uvd->vpic.brightness > MAX_BRIGHTNESS) ? MAX_BRIGHTNESS : uvd->vpic.brightness;
+	if(cam->brightness != uvd->vpic.brightness / 11) {
+	   cam->brightness = uvd->vpic.brightness / 11;
+	   DEBUG(1, "setting brightness to %d (%d)", cam->brightness,
+	       cam->brightness * 11);
+	   konicawc_set_value(uvd, cam->brightness, SetBrightness);
+	}
+
+	DEBUG(1, "new contrast: %d", uvd->vpic.contrast);
+	uvd->vpic.contrast = (uvd->vpic.contrast > MAX_CONTRAST) ? MAX_CONTRAST : uvd->vpic.contrast;
+	if(cam->contrast != uvd->vpic.contrast / 11) {
+		cam->contrast = uvd->vpic.contrast / 11;
+		DEBUG(1, "setting contrast to %d (%d)", cam->contrast,
+		    cam->contrast * 11);
+		konicawc_set_value(uvd, cam->contrast, SetContrast);
+	}
+	konicawc_camera_on(uvd);
+}
+
+
+static int konicawc_compress_iso(struct uvd *uvd, struct urb *dataurb, struct urb *stsurb)
+{
+	char *cdata;
+	int i, totlen = 0;
+	unsigned char *status = stsurb->transfer_buffer;
+	int keep = 0, discard = 0, bad = 0;
+	struct konicawc *cam = (struct konicawc *)uvd->user_data;
+
+	for (i = 0; i < dataurb->number_of_packets; i++) {
+		int button = cam->buttonsts;
+		unsigned char sts;
+		int n = dataurb->iso_frame_desc[i].actual_length;
+		int st = dataurb->iso_frame_desc[i].status;
+		cdata = dataurb->transfer_buffer +
+			dataurb->iso_frame_desc[i].offset;
+
+		/* Detect and ignore errored packets */
+		if (st < 0) {
+			DEBUG(1, "Data error: packet=%d. len=%d. status=%d.",
+			      i, n, st);
+			uvd->stats.iso_err_count++;
+			continue;
+		}
+
+		/* Detect and ignore empty packets */
+		if (n <= 0) {
+			uvd->stats.iso_skip_count++;
+			continue;
+		}
+
+		/* See what the status data said about the packet */
+		sts = *(status+stsurb->iso_frame_desc[i].offset);
+
+		/* sts: 0x80-0xff: frame start with frame number (ie 0-7f)
+		 * otherwise:
+		 * bit 0 0: keep packet
+		 *	 1: drop packet (padding data)
+		 *
+		 * bit 4 0 button not clicked
+		 *       1 button clicked
+		 * button is used to `take a picture' (in software)
+		 */
+
+		if(sts < 0x80) {
+			button = !!(sts & 0x40);
+			sts &= ~0x40;
+		}
+		
+		/* work out the button status, but dont do
+		   anything with it for now */
+
+		if(button != cam->buttonsts) {
+			DEBUG(2, "button: %sclicked", button ? "" : "un");
+			cam->buttonsts = button;
+#ifdef CONFIG_INPUT
+			input_report_key(&cam->input, BTN_0, cam->buttonsts);
+#endif
+		}
+
+		if(sts == 0x01) { /* drop frame */
+			discard++;
+			continue;
+		}
+		
+		if((sts > 0x01) && (sts < 0x80)) {
+			info("unknown status %2.2x", sts);
+			bad++;
+			continue;
+		}
+		if(!sts && cam->lastframe == -2) {
+			DEBUG(2, "dropping frame looking for image start");
+			continue;
+		}
+
+		keep++;
+		if(sts & 0x80) { /* frame start */
+			unsigned char marker[] = { 0, 0xff, 0, 0x00 };
+
+			if(cam->lastframe == -2) {
+				DEBUG(2, "found initial image");
+				cam->lastframe = -1;
+			}
+				
+			marker[3] = sts & 0x7F;
+			RingQueue_Enqueue(&uvd->dp, marker, 4);
+			totlen += 4;
+		}
+
+		totlen += n;	/* Little local accounting */
+		RingQueue_Enqueue(&uvd->dp, cdata, n);
+	}
+	DEBUG(8, "finished: keep = %d discard = %d bad = %d added %d bytes",
+		    keep, discard, bad, totlen);
+	return totlen;
+}
+
+
+static void resubmit_urb(struct uvd *uvd, struct urb *urb)
+{
+        int i, ret;
+        for (i = 0; i < FRAMES_PER_DESC; i++) {
+                urb->iso_frame_desc[i].status = 0;
+        }
+        urb->dev = uvd->dev;
+        urb->status = 0;
+        ret = usb_submit_urb(urb);
+	DEBUG(3, "submitting urb of length %d", urb->transfer_buffer_length);
+        if(ret)
+                err("usb_submit_urb error (%d)", ret);
+
+}
+
+
+static void konicawc_isoc_irq(struct urb *urb)
+{
+	struct uvd *uvd = urb->context;
+	struct konicawc *cam = (struct konicawc *)uvd->user_data;
+
+	/* We don't want to do anything if we are about to be removed! */
+	if (!CAMERA_IS_OPERATIONAL(uvd))
+		return;
+
+	if (!uvd->streaming) {
+		DEBUG(1, "Not streaming, but interrupt!");
+		return;
+	}
+
+	DEBUG(3, "got frame %d len = %d buflen =%d", urb->start_frame, urb->actual_length, urb->transfer_buffer_length);
+
+	uvd->stats.urb_count++;
+
+	if (urb->transfer_buffer_length > 32) {
+		cam->last_data_urb = urb;
+	} else {
+		cam->last_sts_urb = urb;
+	}
+	/* Copy the data received into ring queue */
+	if(cam->last_data_urb && cam->last_sts_urb) {
+		int len = 0;
+		if(cam->last_sts_urb->start_frame != cam->last_data_urb->start_frame)
+			err("Lost sync on frames (%d != %d)",
+			    cam->last_sts_urb->start_frame, cam->last_data_urb->start_frame);
+		else if (!cam->last_sts_urb->status && !cam->last_data_urb->status)
+			len = konicawc_compress_iso(uvd, cam->last_data_urb,
+						    cam->last_sts_urb);
+
+		resubmit_urb(uvd, cam->last_sts_urb);
+		resubmit_urb(uvd, cam->last_data_urb);
+		cam->last_data_urb = NULL;
+		cam->last_sts_urb = NULL;
+		uvd->stats.urb_length = len;
+		uvd->stats.data_count += len;
+		if(len)
+			RingQueue_WakeUpInterruptible(&uvd->dp);
+		return;
+	}
+	return;
+}
+
+
+static int konicawc_start_data(struct uvd *uvd)
+{
+	struct usb_device *dev = uvd->dev;
+	int i, errFlag;
+	struct konicawc *cam = (struct konicawc *)uvd->user_data;
+	int pktsz;
+	struct usb_interface_descriptor *interface;
+
+	interface = &dev->actconfig->interface[uvd->iface].altsetting[spd_to_iface[cam->speed]];
+	pktsz = interface->endpoint[1].wMaxPacketSize;
+	DEBUG(1, "pktsz = %d", pktsz);
+	if (!CAMERA_IS_OPERATIONAL(uvd)) {
+		err("Camera is not operational");
+		return -EFAULT;
+	}
+	uvd->curframe = -1;
+	konicawc_camera_on(uvd);
+	/* Alternate interface 1 is is the biggest frame size */
+	i = usb_set_interface(dev, uvd->iface, uvd->ifaceAltActive);
+	if (i < 0) {
+		err("usb_set_interface error");
+		uvd->last_error = i;
+		return -EBUSY;
+	}
+
+	/* We double buffer the Iso lists */
+	for (i=0; i < USBVIDEO_NUMSBUF; i++) {
+		int j, k;
+		struct urb *urb = uvd->sbuf[i].urb;
+		urb->dev = dev;
+		urb->context = uvd;
+		urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp);
+		urb->interval = 1;
+		urb->transfer_flags = USB_ISO_ASAP;
+		urb->transfer_buffer = uvd->sbuf[i].data;
+		urb->complete = konicawc_isoc_irq;
+		urb->number_of_packets = FRAMES_PER_DESC;
+		urb->transfer_buffer_length = pktsz * FRAMES_PER_DESC;
+		for (j=k=0; j < FRAMES_PER_DESC; j++, k += pktsz) {
+			urb->iso_frame_desc[j].offset = k;
+			urb->iso_frame_desc[j].length = pktsz;
+		}
+
+		urb = cam->sts_urb[i];
+		urb->dev = dev;
+		urb->context = uvd;
+		urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp-1);
+		urb->interval = 1;
+		urb->transfer_flags = USB_ISO_ASAP;
+		urb->transfer_buffer = cam->sts_buf[i];
+		urb->complete = konicawc_isoc_irq;
+		urb->number_of_packets = FRAMES_PER_DESC;
+		urb->transfer_buffer_length = FRAMES_PER_DESC;
+		for (j=0; j < FRAMES_PER_DESC; j++) {
+			urb->iso_frame_desc[j].offset = j;
+			urb->iso_frame_desc[j].length = 1;
+		}
+	}
+
+	cam->last_data_urb = NULL;
+	cam->last_sts_urb = NULL;
+	
+	/* Submit all URBs */
+	for (i=0; i < USBVIDEO_NUMSBUF; i++) {
+		errFlag = usb_submit_urb(cam->sts_urb[i]);
+		if (errFlag)
+			err("usb_submit_isoc(%d) ret %d", i, errFlag);
+
+		errFlag = usb_submit_urb(uvd->sbuf[i].urb);
+		if (errFlag)
+			err ("usb_submit_isoc(%d) ret %d", i, errFlag);
+	}
+
+	uvd->streaming = 1;
+	DEBUG(1, "streaming=1 video_endp=$%02x", uvd->video_endp);
+	return 0;
+}
+
+
+static void konicawc_stop_data(struct uvd *uvd)
+{
+	int i, j;
+	struct konicawc *cam;
+
+	if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL))
+		return;
+
+	konicawc_camera_off(uvd);
+	uvd->streaming = 0;
+	cam = (struct konicawc *)uvd->user_data;
+	cam->last_data_urb = NULL;
+	cam->last_sts_urb = NULL;
+
+	/* Unschedule all of the iso td's */
+	for (i=0; i < USBVIDEO_NUMSBUF; i++) {
+		j = usb_unlink_urb(uvd->sbuf[i].urb);
+		if (j < 0)
+			err("usb_unlink_urb() error %d.", j);
+
+		j = usb_unlink_urb(cam->sts_urb[i]);
+		if (j < 0)
+			err("usb_unlink_urb() error %d.", j);
+	}
+
+	if (!uvd->remove_pending) {
+		/* Set packet size to 0 */
+		j = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltInactive);
+		if (j < 0) {
+			err("usb_set_interface() error %d.", j);
+			uvd->last_error = j;
+		}
+	}
+}
+
+
+static void konicawc_process_isoc(struct uvd *uvd, struct usbvideo_frame *frame)
+{	
+	struct konicawc *cam = (struct konicawc *)uvd->user_data;
+	int maxline = cam->maxline;
+	int yplanesz = cam->yplanesz;
+
+	assert(frame != NULL);
+
+	DEBUG(5, "maxline = %d yplanesz = %d", maxline, yplanesz);
+	DEBUG(3, "Frame state = %d", frame->scanstate);
+
+	if(frame->scanstate == ScanState_Scanning) {
+		int drop = 0;
+		int curframe;
+		int fdrops = 0;
+		DEBUG(3, "Searching for marker, queue len = %d", RingQueue_GetLength(&uvd->dp));
+		while(RingQueue_GetLength(&uvd->dp) >= 4) {
+			if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) &&
+			    (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xff) &&
+			    (RING_QUEUE_PEEK(&uvd->dp, 2) == 0x00) &&
+			    (RING_QUEUE_PEEK(&uvd->dp, 3) < 0x80)) {
+				curframe = RING_QUEUE_PEEK(&uvd->dp, 3);
+				if(cam->lastframe >= 0) {
+					fdrops = (0x80 + curframe - cam->lastframe) & 0x7F;
+					fdrops--;
+					if(fdrops) {
+						info("Dropped %d frames (%d -> %d)", fdrops,
+						     cam->lastframe, curframe);
+					}
+				}
+				cam->lastframe = curframe;
+				frame->curline = 0;
+				frame->scanstate = ScanState_Lines;
+				RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 4);
+				break;
+			}
+			RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
+			drop++;
+		}
+		if(drop)
+			DEBUG(2, "dropped %d bytes looking for new frame", drop);
+	}
+
+	if(frame->scanstate == ScanState_Scanning)
+		return;
+		
+	/* Try to move data from queue into frame buffer
+	 * We get data in blocks of 384 bytes made up of:
+	 * 256 Y, 64 U, 64 V.
+	 * This needs to be written out as a Y plane, a U plane and a V plane.
+	 */
+		
+	while ( frame->curline < maxline && (RingQueue_GetLength(&uvd->dp) >= 384)) {
+		/* Y */
+		RingQueue_Dequeue(&uvd->dp, frame->data + (frame->curline * 256), 256);
+		/* U */
+		RingQueue_Dequeue(&uvd->dp, frame->data + yplanesz + (frame->curline * 64), 64);
+		/* V */
+		RingQueue_Dequeue(&uvd->dp, frame->data + (5 * yplanesz)/4 + (frame->curline * 64), 64);
+		frame->seqRead_Length += 384;
+		frame->curline++;
+	}
+	/* See if we filled the frame */
+	if (frame->curline == maxline) {
+		DEBUG(5, "got whole frame");
+
+		frame->frameState = FrameState_Done_Hold;
+		frame->curline = 0;
+		uvd->curframe = -1;
+		uvd->stats.frame_num++;
+	}
+}
+
+
+static int konicawc_find_fps(int size, int fps)
+{
+	int i;
+
+	fps *= 3;
+	DEBUG(1, "konica_find_fps: size = %d fps = %d", size, fps);
+	if(fps <= spd_to_fps[size][0])
+		return 0;
+
+	if(fps >= spd_to_fps[size][MAX_SPEED])
+		return MAX_SPEED;
+
+	for(i = 0; i < MAX_SPEED; i++) {
+		if((fps >= spd_to_fps[size][i]) && (fps <= spd_to_fps[size][i+1])) {
+			DEBUG(2, "fps %d between %d and %d", fps, i, i+1);
+			if( (fps - spd_to_fps[size][i]) < (spd_to_fps[size][i+1] - fps))
+				return i;
+			else
+				return i+1;
+		}
+	}
+	return MAX_SPEED+1;
+}
+
+
+static int konicawc_set_video_mode(struct uvd *uvd, struct video_window *vw)
+{
+	struct konicawc *cam = (struct konicawc *)uvd->user_data;
+	int newspeed = cam->speed;
+	int newsize;
+	int x = vw->width;
+	int y = vw->height;
+	int fps = vw->flags;
+
+	if(x > 0 && y > 0) {
+		DEBUG(2, "trying to find size %d,%d", x, y);
+		for(newsize = 0; newsize <= MAX_FRAME_SIZE; newsize++) {
+			if((camera_sizes[newsize].width == x) && (camera_sizes[newsize].height == y))
+				break;
+		}
+	} else {
+		newsize = cam->size;
+	}
+
+	if(newsize > MAX_FRAME_SIZE) {
+		DEBUG(1, "couldnt find size %d,%d", x, y);
+		return -EINVAL;
+	}
+
+	if(fps > 0) {
+		DEBUG(1, "trying to set fps to %d", fps);
+		newspeed = konicawc_find_fps(newsize, fps);
+		DEBUG(1, "find_fps returned %d (%d)", newspeed, spd_to_fps[newsize][newspeed]);
+	}
+
+	if(newspeed > MAX_SPEED)
+		return -EINVAL;
+
+	DEBUG(1, "setting size to %d speed to %d", newsize, newspeed);
+	if((newsize == cam->size) && (newspeed == cam->speed)) {
+		DEBUG(1, "Nothing to do");
+		return 0;
+	}
+	DEBUG(0, "setting to  %dx%d @ %d fps", camera_sizes[newsize].width,
+	     camera_sizes[newsize].height, spd_to_fps[newsize][newspeed]/3);
+
+	konicawc_stop_data(uvd);
+	uvd->ifaceAltActive = spd_to_iface[newspeed];
+	DEBUG(1, "new interface = %d", uvd->ifaceAltActive);
+	cam->speed = newspeed;
+
+	if(cam->size != newsize) {
+		cam->size = newsize;
+		konicawc_set_camera_size(uvd);
+	}
+
+	/* Flush the input queue and clear any current frame in progress */
+
+	RingQueue_Flush(&uvd->dp);
+	cam->lastframe = -2;
+	if(uvd->curframe != -1) {
+	  uvd->frame[uvd->curframe].curline = 0;
+	  uvd->frame[uvd->curframe].seqRead_Length = 0;
+	  uvd->frame[uvd->curframe].seqRead_Index = 0;
+	}
+
+	konicawc_start_data(uvd);
+	return 0;
+}
+
+
+static int konicawc_calculate_fps(struct uvd *uvd)
+{
+	struct konicawc *cam = uvd->user_data;
+	return spd_to_fps[cam->size][cam->speed]/3;
+}
+
+
+static void konicawc_configure_video(struct uvd *uvd)
+{
+	struct konicawc *cam = (struct konicawc *)uvd->user_data;
+	u8 buf[2];
+
+	memset(&uvd->vpic, 0, sizeof(uvd->vpic));
+	memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old));
+
+	RESTRICT_TO_RANGE(brightness, 0, MAX_BRIGHTNESS);
+	RESTRICT_TO_RANGE(contrast, 0, MAX_CONTRAST);
+	RESTRICT_TO_RANGE(saturation, 0, MAX_SATURATION);
+	RESTRICT_TO_RANGE(sharpness, 0, MAX_SHARPNESS);
+	RESTRICT_TO_RANGE(whitebal, 0, MAX_WHITEBAL);
+
+	cam->brightness = brightness / 11;
+	cam->contrast = contrast / 11;
+	cam->saturation = saturation / 11;
+	cam->sharpness = sharpness / 11;
+	cam->white_bal = whitebal / 11;
+
+	uvd->vpic.colour = 108;
+	uvd->vpic.hue = 108;
+	uvd->vpic.brightness = brightness;
+	uvd->vpic.contrast = contrast;
+	uvd->vpic.whiteness = whitebal;
+	uvd->vpic.depth = 6;
+	uvd->vpic.palette = VIDEO_PALETTE_YUV420P;
+
+	memset(&uvd->vcap, 0, sizeof(uvd->vcap));
+	strcpy(uvd->vcap.name, "Konica Webcam");
+	uvd->vcap.type = VID_TYPE_CAPTURE;
+	uvd->vcap.channels = 1;
+	uvd->vcap.audios = 0;
+	uvd->vcap.minwidth = camera_sizes[SIZE_160X120].width;
+	uvd->vcap.minheight = camera_sizes[SIZE_160X120].height;
+	uvd->vcap.maxwidth = camera_sizes[SIZE_320X240].width;
+	uvd->vcap.maxheight = camera_sizes[SIZE_320X240].height;
+
+	memset(&uvd->vchan, 0, sizeof(uvd->vchan));
+	uvd->vchan.flags = 0 ;
+	uvd->vchan.tuners = 0;
+	uvd->vchan.channel = 0;
+	uvd->vchan.type = VIDEO_TYPE_CAMERA;
+	strcpy(uvd->vchan.name, "Camera");
+
+	/* Talk to device */
+	DEBUG(1, "device init");
+	if(!konicawc_get_misc(uvd, 0x3, 0, 0x10, buf, 2))
+		DEBUG(2, "3,10 -> %2.2x %2.2x", buf[0], buf[1]);
+	if(!konicawc_get_misc(uvd, 0x3, 0, 0x10, buf, 2))
+		DEBUG(2, "3,10 -> %2.2x %2.2x", buf[0], buf[1]);
+	if(konicawc_set_misc(uvd, 0x2, 0, 0xd))
+		DEBUG(2, "2,0,d failed");
+	DEBUG(1, "setting initial values");
+}
+
+
+static void *konicawc_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *devid)
+{
+	struct uvd *uvd = NULL;
+	int i, nas;
+	int actInterface=-1, inactInterface=-1, maxPS=0;
+	unsigned char video_ep = 0;
+
+	DEBUG(1, "konicawc_probe(%p,%u.)", dev, ifnum);
+
+	/* We don't handle multi-config cameras */
+	if (dev->descriptor.bNumConfigurations != 1)
+		return NULL;
+
+	info("Konica Webcam (rev. 0x%04x)", dev->descriptor.bcdDevice);
+	RESTRICT_TO_RANGE(speed, 0, MAX_SPEED);
+
+	/* Validate found interface: must have one ISO endpoint */
+	nas = dev->actconfig->interface[ifnum].num_altsetting;
+	if (nas != 8) {
+		err("Incorrect number of alternate settings (%d) for this camera!", nas);
+		return NULL;
+	}
+	/* Validate all alternate settings */
+	for (i=0; i < nas; i++) {
+		const struct usb_interface_descriptor *interface;
+		const struct usb_endpoint_descriptor *endpoint;
+
+		interface = &dev->actconfig->interface[ifnum].altsetting[i];
+		if (interface->bNumEndpoints != 2) {
+			err("Interface %d. has %u. endpoints!",
+			    ifnum, (unsigned)(interface->bNumEndpoints));
+			return NULL;
+		}
+		endpoint = &interface->endpoint[1];
+		DEBUG(1, "found endpoint: addr: 0x%2.2x maxps = 0x%4.4x",
+		    endpoint->bEndpointAddress, endpoint->wMaxPacketSize);
+		if (video_ep == 0)
+			video_ep = endpoint->bEndpointAddress;
+		else if (video_ep != endpoint->bEndpointAddress) {
+			err("Alternate settings have different endpoint addresses!");
+			return NULL;
+		}
+		if ((endpoint->bmAttributes & 0x03) != 0x01) {
+			err("Interface %d. has non-ISO endpoint!", ifnum);
+			return NULL;
+		}
+		if ((endpoint->bEndpointAddress & 0x80) == 0) {
+			err("Interface %d. has ISO OUT endpoint!", ifnum);
+			return NULL;
+		}
+		if (endpoint->wMaxPacketSize == 0) {
+			if (inactInterface < 0)
+				inactInterface = i;
+			else {
+				err("More than one inactive alt. setting!");
+				return NULL;
+			}
+		} else {
+			if (i == spd_to_iface[speed]) {
+				/* This one is the requested one */
+				actInterface = i;
+			}
+		}
+		if(endpoint->wMaxPacketSize > maxPS)
+			maxPS = endpoint->wMaxPacketSize;
+	}
+	if(actInterface == -1) {
+		err("Cant find required endpoint");
+		return NULL;
+	}
+
+	DEBUG(1, "Selecting requested active setting=%d. maxPS=%d.", actInterface, maxPS);
+
+	/* Code below may sleep, need to lock module while we are here */
+	MOD_INC_USE_COUNT;
+	uvd = usbvideo_AllocateDevice(cams);
+	if (uvd != NULL) {
+		struct konicawc *cam = (struct konicawc *)(uvd->user_data);
+		/* Here uvd is a fully allocated uvd object */
+		for(i = 0; i < USBVIDEO_NUMSBUF; i++) {
+			cam->sts_urb[i] = usb_alloc_urb(FRAMES_PER_DESC);
+			if(cam->sts_urb[i] == NULL) {
+				while(i--) {
+					usb_free_urb(cam->sts_urb[i]);
+				}
+				err("cant allocate urbs");
+				return NULL;
+			}
+		}
+		cam->speed = speed;
+		RESTRICT_TO_RANGE(size, SIZE_160X120, SIZE_320X240);
+		cam->width = camera_sizes[size].width;
+		cam->height = camera_sizes[size].height;
+		cam->size = size;
+
+		uvd->flags = 0;
+		uvd->debug = debug;
+		uvd->dev = dev;
+		uvd->iface = ifnum;
+		uvd->ifaceAltInactive = inactInterface;
+		uvd->ifaceAltActive = actInterface;
+		uvd->video_endp = video_ep;
+		uvd->iso_packet_len = maxPS;
+		uvd->paletteBits = 1L << VIDEO_PALETTE_YUV420P;
+		uvd->defaultPalette = VIDEO_PALETTE_YUV420P;
+		uvd->canvas = VIDEOSIZE(320, 240);
+		uvd->videosize = VIDEOSIZE(cam->width, cam->height);
+
+		/* Initialize konicawc specific data */
+		konicawc_configure_video(uvd);
+
+		i = usbvideo_RegisterVideoDevice(uvd);
+		uvd->max_frame_size = (320 * 240 * 3)/2;
+		if (i != 0) {
+			err("usbvideo_RegisterVideoDevice() failed.");
+			uvd = NULL;
+		}
+#ifdef CONFIG_INPUT
+		/* Register input device for button */
+		memset(&cam->input, 0, sizeof(struct input_dev));
+		cam->input.name = "Konicawc snapshot button";
+		cam->input.private = cam;
+		cam->input.evbit[0] = BIT(EV_KEY);
+		cam->input.keybit[LONG(BTN_0)] = BIT(BTN_0);
+		cam->input.idbus = BUS_USB;
+		cam->input.idvendor = dev->descriptor.idVendor;
+		cam->input.idproduct = dev->descriptor.idProduct;
+		cam->input.idversion = dev->descriptor.bcdDevice;
+		input_register_device(&cam->input);
+#endif
+	}
+	MOD_DEC_USE_COUNT;
+	return uvd;
+}
+
+
+static void konicawc_free_uvd(struct uvd *uvd)
+{
+	int i;
+	struct konicawc *cam = (struct konicawc *)uvd->user_data;
+
+#ifdef CONFIG_INPUT
+	input_unregister_device(&cam->input);
+#endif
+	for (i=0; i < USBVIDEO_NUMSBUF; i++) {
+		usb_free_urb(cam->sts_urb[i]);
+		cam->sts_urb[i] = NULL;
+	}
+}
+
+
+static struct usb_device_id id_table[] = {
+	{ USB_DEVICE(0x04c8, 0x0720) }, /* Intel YC 76 */
+	{ }  /* Terminating entry */
+};
+
+
+static int __init konicawc_init(void)
+{
+	struct usbvideo_cb cbTbl;
+	info(DRIVER_DESC " " DRIVER_VERSION);
+	memset(&cbTbl, 0, sizeof(cbTbl));
+	cbTbl.probe = konicawc_probe;
+	cbTbl.setupOnOpen = konicawc_setup_on_open;
+	cbTbl.processData = konicawc_process_isoc;
+	cbTbl.getFPS = konicawc_calculate_fps;
+	cbTbl.setVideoMode = konicawc_set_video_mode;
+	cbTbl.startDataPump = konicawc_start_data;
+	cbTbl.stopDataPump = konicawc_stop_data;
+	cbTbl.adjustPicture = konicawc_adjust_picture;
+	cbTbl.userFree = konicawc_free_uvd;
+	return usbvideo_register(
+		&cams,
+		MAX_CAMERAS,
+		sizeof(struct konicawc),
+		"konicawc",
+		&cbTbl,
+		THIS_MODULE,
+		id_table);
+}
+
+
+static void __exit konicawc_cleanup(void)
+{
+	usbvideo_Deregister(&cams);
+}
+
+
+MODULE_DEVICE_TABLE(usb, id_table);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Simon Evans <spse@secret.org.uk>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_PARM(speed, "i");
+MODULE_PARM_DESC(speed, "Initial speed: 0 (slowest) - 6 (fastest)");
+MODULE_PARM(size, "i");
+MODULE_PARM_DESC(size, "Initial Size 0: 160x120 1: 160x136 2: 176x144 3: 320x240");
+MODULE_PARM(brightness, "i");
+MODULE_PARM_DESC(brightness, "Initial brightness 0 - 108");
+MODULE_PARM(contrast, "i");
+MODULE_PARM_DESC(contrast, "Initial contrast 0 - 108");
+MODULE_PARM(saturation, "i");
+MODULE_PARM_DESC(saturation, "Initial saturation 0 - 108");
+MODULE_PARM(sharpness, "i");
+MODULE_PARM_DESC(sharpness, "Initial sharpness 0 - 108");
+MODULE_PARM(whitebal, "i");
+MODULE_PARM_DESC(whitebal, "Initial white balance 0 - 363");
+
+#ifdef CONFIG_USB_DEBUG
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)");
+#endif
+
+module_init(konicawc_init);
+module_exit(konicawc_cleanup);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/ov511.c linux-2.4.21-pre6/drivers/usb/ov511.c
--- linux-2.4.20/drivers/usb/ov511.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/ov511.c	2003-03-26 23:49:25.000000000 +0000
@@ -1,7 +1,7 @@
 /*
  * OmniVision OV511 Camera-to-USB Bridge Driver
  *
- * Copyright (c) 1999-2002 Mark W. McClelland
+ * Copyright (c) 1999-2003 Mark W. McClelland
  * Original decompression code Copyright 1998-2000 OmniVision Technologies
  * Many improvements by Bret Wallach <bwallac1@san.rr.com>
  * Color fixes by by Orion Sky Lawlor <olawlor@acm.org> (2/26/2000)
@@ -11,6 +11,7 @@
  * Original SAA7111A code by Dave Perks <dperks@ibm.net>
  * URB error messages from pwc driver by Nemosoft
  * generic_ioctl() code from videodev.c by Gerd Knorr and Alan Cox
+ * Memory management (rvmalloc) code from bttv driver, by Gerd Knorr and others
  *
  * Based on the Linux CPiA driver written by Peter Pregler,
  * Scott J. Bertin and Johannes Erdfelt.
@@ -48,6 +49,7 @@
 #include <asm/semaphore.h>
 #include <asm/processor.h>
 #include <linux/wrapper.h>
+#include <linux/mm.h>
 
 #if defined (__i386__)
 	#include <asm/cpufeature.h>
@@ -58,9 +60,9 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.61 for Linux 2.4"
+#define DRIVER_VERSION "v1.63 for Linux 2.4"
 #define EMAIL "mark@alpha.dyndns.org"
-#define DRIVER_AUTHOR "Mark McClelland <mmcclell@bigfoot.com> & Bret Wallach \
+#define DRIVER_AUTHOR "Mark McClelland <mark@alpha.dyndns.org> & Bret Wallach \
 	& Orion Sky Lawlor <olawlor@acm.org> & Kevin Moore & Charl P. Botha \
 	<cpbotha@ieee.org> & Claudio Matsuoka <claudio@conectiva.com>"
 #define DRIVER_DESC "ov511 USB Camera Driver"
@@ -97,7 +99,6 @@
 static int cams			= 1;
 static int compress;
 static int testpat;
-static int sensor_gbr;
 static int dumppix;
 static int led 			= 1;
 static int dump_bridge;
@@ -122,6 +123,7 @@
 static int unit_video[OV511_MAX_UNIT_VIDEO];
 static int remove_zeros;
 static int mirror;
+static int ov518_color;
 
 MODULE_PARM(autobright, "i");
 MODULE_PARM_DESC(autobright, "Sensor automatically changes brightness");
@@ -199,6 +201,8 @@
   "Remove zero-padding from uncompressed incoming data");
 MODULE_PARM(mirror, "i");
 MODULE_PARM_DESC(mirror, "Reverse image horizontally");
+MODULE_PARM(ov518_color, "i");
+MODULE_PARM_DESC(ov518_color, "Enable OV518 color (experimental)");
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
@@ -222,7 +226,7 @@
 /* MMX support is present in kernel and CPU. Checked upon decomp module load. */
 static int ov51x_mmx_available;
 
-static __devinitdata struct usb_device_id device_table [] = {
+static struct usb_device_id device_table [] = {
 	{ USB_DEVICE(VEND_OMNIVISION, PROD_OV511) },
 	{ USB_DEVICE(VEND_OMNIVISION, PROD_OV511PLUS) },
 	{ USB_DEVICE(VEND_OMNIVISION, PROD_OV518) },
@@ -261,7 +265,9 @@
 	{ 100, "Lifeview RoboCam" },
 	{ 102, "AverMedia InterCam Elite" },
 	{ 112, "MediaForte MV300" },	/* or OV7110 evaluation kit */
+	{ 134, "Ezonics EZCam II" },
 	{ 192, "Webeye 2000B" },
+	{ 253, "Alpha Vision Tech. AlphaCam SE" },
 	{  -1, NULL }
 };
 
@@ -294,6 +300,7 @@
 	{ -1, NULL }
 };
 
+#if defined(CONFIG_VIDEO_PROC_FS)
 static struct symbolic_list senlist[] = {
 	{ SEN_OV76BE,	"OV76BE" },
 	{ SEN_OV7610,	"OV7610" },
@@ -309,6 +316,7 @@
 	{ SEN_SAA7111A,	"SAA7111A" },
 	{ -1, NULL }
 };
+#endif
 
 /* URB error codes: */
 static struct symbolic_list urb_errlist[] = {
@@ -403,7 +411,7 @@
 extern struct proc_dir_entry *video_proc_entry;
 
 static struct file_operations ov511_control_fops = {
-	ioctl:		ov51x_control_ioctl,
+	.ioctl =	ov51x_control_ioctl,
 };
 
 #define YES_NO(x) ((x) ? "yes" : "no")
@@ -463,6 +471,8 @@
 		       symbolic(senlist, ov->sensor));
 	out += sprintf(out, "packet_size     : %d\n", ov->packet_size);
 	out += sprintf(out, "framebuffer     : 0x%p\n", ov->fbuf);
+	out += sprintf(out, "packet_numbering: %d\n", ov->packet_numbering);
+	out += sprintf(out, "topology        : %s\n", ov->usb_path);
 
 	len = out - page;
 	len -= off;
@@ -554,8 +564,8 @@
 			ov511_read_proc_button, ov);
 		if (!ov->proc_button)
 			return;
+		ov->proc_button->owner = THIS_MODULE;
 	}
-	ov->proc_button->owner = THIS_MODULE;
 
 	/* Create "control" entry (ioctl() interface) */
 	PDEBUG(4, "creating /proc/video/ov511/%s/control", dirname);
@@ -1133,8 +1143,6 @@
 	return 0;
 }
 
-#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
-
 /* Write to a specific I2C slave ID and register, using the specified mask */
 static int
 i2c_w_slave(struct usb_ov511 *ov,
@@ -1190,8 +1198,6 @@
 	return rc;
 }
 
-#endif /* defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) */
-
 /* Sets I2C read and write slave IDs. Returns <0 for error */
 static int
 ov51x_set_slave_ids(struct usb_ov511 *ov, unsigned char sid)
@@ -1237,8 +1243,7 @@
 static void
 dump_i2c_range(struct usb_ov511 *ov, int reg1, int regn)
 {
-	int i;
-	int rc;
+	int i, rc;
 
 	for (i = reg1; i <= regn; i++) {
 		rc = i2c_r(ov, i);
@@ -1256,8 +1261,7 @@
 static void
 dump_reg_range(struct usb_ov511 *ov, int reg1, int regn)
 {
-	int i;
-	int rc;
+	int i, rc;
 
 	for (i = reg1; i <= regn; i++) {
 		rc = reg_r(ov, i);
@@ -1265,7 +1269,6 @@
 	}
 }
 
-/* FIXME: Should there be an OV518 version of this? */
 static void
 ov511_dump_regs(struct usb_ov511 *ov)
 {
@@ -1291,6 +1294,31 @@
 	dump_reg_range(ov, 0xa0, 0xbf);
 
 }
+
+static void
+ov518_dump_regs(struct usb_ov511 *ov)
+{
+	info("VIDEO MODE REGS");
+	dump_reg_range(ov, 0x20, 0x2f);
+	info("DATA PUMP AND SNAPSHOT REGS");
+	dump_reg_range(ov, 0x30, 0x3f);
+	info("I2C REGS");
+	dump_reg_range(ov, 0x40, 0x4f);
+	info("SYSTEM CONTROL AND VENDOR REGS");
+	dump_reg_range(ov, 0x50, 0x5f);
+	info("60 - 6F");
+	dump_reg_range(ov, 0x60, 0x6f);
+	info("70 - 7F");
+	dump_reg_range(ov, 0x70, 0x7f);
+	info("Y QUANTIZATION TABLE");
+	dump_reg_range(ov, 0x80, 0x8f);
+	info("UV QUANTIZATION TABLE");
+	dump_reg_range(ov, 0x90, 0x9f);
+	info("A0 - BF");
+	dump_reg_range(ov, 0xa0, 0xbf);
+	info("CBR");
+	dump_reg_range(ov, 0xc0, 0xcf);
+}
 #endif
 
 /*****************************************************************************/
@@ -1332,9 +1360,9 @@
 ov51x_clear_snapshot(struct usb_ov511 *ov)
 {
 	if (ov->bclass == BCL_OV511) {
-		reg_w(ov, R51x_SYS_SNAP, 0x01);
-		reg_w(ov, R51x_SYS_SNAP, 0x03);
-		reg_w(ov, R51x_SYS_SNAP, 0x01);
+		reg_w(ov, R51x_SYS_SNAP, 0x00);
+		reg_w(ov, R51x_SYS_SNAP, 0x02);
+		reg_w(ov, R51x_SYS_SNAP, 0x00);
 	} else if (ov->bclass == BCL_OV518) {
 		warn("snapshot reset not supported yet on OV518(+)");
 	} else {
@@ -1379,7 +1407,7 @@
 	if (i2c_w(ov, 0x12, 0x80) < 0) return -EIO;
 
 	/* Wait for it to initialize */
-	schedule_timeout (1 + 150 * HZ / 1000);
+	schedule_timeout(1 + 150 * HZ / 1000);
 
 	for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) {
 		if ((i2c_r(ov, OV7610_REG_ID_HIGH) == 0x7F) &&
@@ -2014,10 +2042,6 @@
 
 	p->whiteness = 105 << 8;
 
-	/* Can we get these from frame[0]? -claudio? */
-	p->depth = ov->frame[0].depth;
-	p->palette = ov->frame[0].format;
-
 	return 0;
 }
 
@@ -2425,9 +2449,10 @@
 #endif
 		break;
 	case SEN_OV6620:
-	case SEN_OV6630:
 		i2c_w(ov, 0x14, qvga?0x24:0x04);
-		/* No special settings yet */
+		break;
+	case SEN_OV6630:
+		i2c_w(ov, 0x14, qvga?0xa0:0x80);
 		break;
 	default:
 		err("Invalid sensor");
@@ -2441,13 +2466,33 @@
 			/* these aren't valid on the OV6620/OV7620/6630? */
 			i2c_w_mask(ov, 0x0e, 0x40, 0x40);
 		}
-		i2c_w_mask(ov, 0x13, 0x20, 0x20);
+
+		if (ov->sensor == SEN_OV6630 && ov->bridge == BRG_OV518
+		    && ov518_color) {
+			i2c_w_mask(ov, 0x12, 0x00, 0x10);
+			i2c_w_mask(ov, 0x13, 0x00, 0x20);
+		} else {
+			i2c_w_mask(ov, 0x13, 0x20, 0x20);
+		}
 	} else {
 		if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) {
 			/* not valid on the OV6620/OV7620/6630? */
 			i2c_w_mask(ov, 0x0e, 0x00, 0x40);
 		}
-		i2c_w_mask(ov, 0x13, 0x00, 0x20);
+
+		/* The OV518 needs special treatment. Although both the OV518
+		 * and the OV6630 support a 16-bit video bus, only the 8 bit Y
+		 * bus is actually used. The UV bus is tied to ground.
+		 * Therefore, the OV6630 needs to be in 8-bit multiplexed
+		 * output mode */
+
+		if (ov->sensor == SEN_OV6630 && ov->bridge == BRG_OV518
+		    && ov518_color) {
+			i2c_w_mask(ov, 0x12, 0x10, 0x10);
+			i2c_w_mask(ov, 0x13, 0x20, 0x20);
+		} else {
+			i2c_w_mask(ov, 0x13, 0x00, 0x20);
+		}
 	}
 
 	/******** Clock programming ********/
@@ -2505,19 +2550,11 @@
 	if (framedrop >= 0)
 		i2c_w(ov, 0x16, framedrop);
 
-	if (sensor_gbr)
-		i2c_w_mask(ov, 0x12, 0x08, 0x08);
-	else
-		i2c_w_mask(ov, 0x12, 0x00, 0x08);
-
 	/* Test Pattern */
 	i2c_w_mask(ov, 0x12, (testpat?0x02:0x00), 0x02);
 
-	/* Auto white balance */
-//	if (awb)
-		i2c_w_mask(ov, 0x12, 0x04, 0x04);
-//	else
-//		i2c_w_mask(ov, 0x12, 0x00, 0x04);
+	/* Enable auto white balance */
+	i2c_w_mask(ov, 0x12, 0x04, 0x04);
 
 	// This will go away as soon as ov51x_mode_init_sensor_regs()
 	// is fully tested.
@@ -2706,7 +2743,7 @@
 	reg_w(ov, R511_CAM_PXDIV, 0x00);
 	reg_w(ov, R511_CAM_LNDIV, 0x00);
 
-	/* YUV420, low pass filer on */
+	/* YUV420, low pass filter on */
 	reg_w(ov, R511_CAM_OPTS, 0x03);
 
 	/* Snapshot additions */
@@ -2782,8 +2819,29 @@
 	reg_w(ov, 0x3d, 0);
 	reg_w(ov, 0x3e, 0);
 
-	reg_w(ov, 0x28, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80);
-	reg_w(ov, 0x38, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80);
+	if (ov->bridge == BRG_OV518 && ov518_color) {
+		/* OV518 needs U and V swapped */
+		i2c_w_mask(ov, 0x15, 0x00, 0x01);
+
+	 	if (mode == VIDEO_PALETTE_GREY) {
+			/* Set 16-bit input format (UV data are ignored) */
+			reg_w_mask(ov, 0x20, 0x00, 0x08);
+
+			/* Set 8-bit (4:0:0) output format */
+			reg_w_mask(ov, 0x28, 0x00, 0xf0);
+			reg_w_mask(ov, 0x38, 0x00, 0xf0);
+		} else {
+			/* Set 8-bit (YVYU) input format */
+			reg_w_mask(ov, 0x20, 0x08, 0x08);
+
+			/* Set 12-bit (4:2:0) output format */
+			reg_w_mask(ov, 0x28, 0x80, 0xf0);
+			reg_w_mask(ov, 0x38, 0x80, 0xf0);
+		}
+	} else {
+		reg_w(ov, 0x28, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80);
+		reg_w(ov, 0x38, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80);
+	}
 
 	hsegs = width / 16;
 	vsegs = height / 4;
@@ -3176,7 +3234,7 @@
 }
 
 /*
- * For RAW BW (YUV400) images, data shows up in 256 byte segments.
+ * For RAW BW (YUV 4:0:0) images, data show up in 256 byte segments.
  * The segments represent 4 squares of 8x8 pixels as follows:
  *
  *      0  1 ...  7    64  65 ...  71   ...  192 193 ... 199
@@ -3207,7 +3265,7 @@
 }
 
 /*
- * For YUV4:2:0 images, the data shows up in 384 byte segments.
+ * For YUV 4:2:0 images, the data show up in 384 byte segments.
  * The first 64 bytes of each segment are U, the next 64 are V.  The U and
  * V are arranged as follows:
  *
@@ -3226,8 +3284,8 @@
  *           ...              ...                    ...
  *     56 57 ... 63   120 121 ... 127   ...  248 249 ... 255
  *
- * Note that the U and V data in one segment represents a 16 x 16 pixel
- * area, but the Y data represents a 32 x 8 pixel area. If the width is not an
+ * Note that the U and V data in one segment represent a 16 x 16 pixel
+ * area, but the Y data represent a 32 x 8 pixel area. If the width is not an
  * even multiple of 32, the extra 8x8 blocks within a 32x8 block belong to the
  * next horizontal stripe.
  *
@@ -3235,7 +3293,7 @@
  * verbatim, in order, into the frame. When used with vidcat -f ppm -s 640x480
  * this puts the data on the standard output and can be analyzed with the
  * parseppm.c utility I wrote.  That's a much faster way for figuring out how
- * this data is scrambled.
+ * these data are scrambled.
  */
 
 /* Converts from raw, uncompressed segments at pIn0 to a YUV420P frame at pOut0.
@@ -4144,7 +4202,10 @@
 		}
 	}
 
+	/* Resubmit this URB */
 	urb->dev = ov->dev;
+	if ((i = usb_submit_urb(urb)) != 0)
+		err("usb_submit_urb() ret %d", i);
 
 	return;
 }
@@ -4216,6 +4277,7 @@
 
 	for (n = 0; n < OV511_NUMSBUF; n++) {
 		urb = usb_alloc_urb(FRAMES_PER_DESC);
+
 		if (!urb) {
 			err("init isoc: usb_alloc_urb ret. NULL");
 			return -ENOMEM;
@@ -4229,6 +4291,7 @@
 		urb->complete = ov51x_isoc_irq;
 		urb->number_of_packets = FRAMES_PER_DESC;
 		urb->transfer_buffer_length = ov->packet_size * FRAMES_PER_DESC;
+		urb->interval = 1;
 		for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
 			urb->iso_frame_desc[fx].offset = ov->packet_size * fx;
 			urb->iso_frame_desc[fx].length = ov->packet_size;
@@ -4237,10 +4300,6 @@
 
 	ov->streaming = 1;
 
-	ov->sbuf[OV511_NUMSBUF - 1].urb->next = ov->sbuf[0].urb;
-	for (n = 0; n < OV511_NUMSBUF - 1; n++)
-		ov->sbuf[n].urb->next = ov->sbuf[n+1].urb;
-
 	for (n = 0; n < OV511_NUMSBUF; n++) {
 		ov->sbuf[n].urb->dev = ov->dev;
 		err = usb_submit_urb(ov->sbuf[n].urb);
@@ -4398,11 +4457,6 @@
 	PDEBUG(4, "entered");
 	down(&ov->buf_lock);
 
-	if (ov->buf_state == BUF_PEND_DEALLOC) {
-		ov->buf_state = BUF_ALLOCATED;
-		del_timer(&ov->buf_timer);
-	}
-
 	if (ov->buf_state == BUF_ALLOCATED)
 		goto out;
 
@@ -4475,8 +4529,9 @@
  ***************************************************************************/
 
 static int
-ov51x_v4l1_open(struct video_device *vdev, int flags)
+ov51x_v4l1_open(struct inode *inode, struct file *file)
 {
+	struct video_device *vdev = video_devdata(file);
 	struct usb_ov511 *ov = vdev->priv;
 	int err, i;
 
@@ -4520,6 +4575,7 @@
 	}
 
 	ov->user++;
+	file->private_data = vdev;
 
 	if (ov->led_policy == LED_AUTO)
 		ov51x_led_control(ov, 1);
@@ -4529,9 +4585,10 @@
 	return err;
 }
 
-static void
-ov51x_v4l1_close(struct video_device *vdev)
+static int
+ov51x_v4l1_close(struct inode *inode, struct file *file)
 {
+	struct video_device *vdev = file->private_data;
 	struct usb_ov511 *ov = vdev->priv;
 
 	PDEBUG(4, "ov511_close");
@@ -4560,19 +4617,22 @@
 		up(&ov->cbuf_lock);
 
 		ov51x_dealloc(ov, 1);
-		video_unregister_device(&ov->vdev);
 		kfree(ov);
 		ov = NULL;
 	}
 
-	return;
+	file->private_data = NULL;
+	return 0;
 }
 
 /* Do not call this function directly! */
 static int
-ov51x_v4l1_ioctl_internal(struct usb_ov511 *ov, unsigned int cmd,
-			  void *arg)
+ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file,
+			  unsigned int cmd, void *arg)
 {
+	struct video_device *vdev = file->private_data;
+	struct usb_ov511 *ov = vdev->priv;
+
 	PDEBUG(5, "IOCtl: 0x%X", cmd);
 
 	if (!ov->dev)
@@ -4666,6 +4726,10 @@
 		if (sensor_get_picture(ov, p))
 			return -EIO;
 
+		/* Can we get these from frame[0]? -claudio? */
+		p->depth = ov->frame[0].depth;
+		p->palette = ov->frame[0].format;
+
 		return 0;
 	}
 	case VIDIOCSPICT:
@@ -4830,8 +4894,8 @@
 
 		depth = get_depth(vm->format);
 		if (!depth) {
-			err("VIDIOCMCAPTURE: invalid format (%s)",
-			    symbolic(v4l1_plist, vm->format));
+			PDEBUG(2, "VIDIOCMCAPTURE: invalid format (%s)",
+			       symbolic(v4l1_plist, vm->format));
 			return -EINVAL;
 		}
 
@@ -4852,8 +4916,8 @@
 		}
 
 		if (force_palette && (vm->format != force_palette)) {
-			info("palette rejected (%s)",
-			     symbolic(v4l1_plist, vm->format));
+			PDEBUG(2, "palette rejected (%s)",
+			       symbolic(v4l1_plist, vm->format));
 			return -EINVAL;
 		}
 
@@ -4982,88 +5046,55 @@
 
 		return 0;
 	}
-	default:
-		PDEBUG(3, "Unsupported IOCtl: 0x%X", cmd);
-		return -ENOIOCTLCMD;
-	} /* end switch */
-
-	return 0;
-}
-
-/* This is implemented as video_generic_ioctl() in the new V4L's videodev.c */
-static int
-ov51x_v4l1_generic_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
-{
-	char	sbuf[128];
-	void    *mbuf = NULL;
-	void	*parg = NULL;
-	int	err  = -EINVAL;
-
-	/*  Copy arguments into temp kernel buffer  */
-	switch (_IOC_DIR(cmd)) {
-	case _IOC_NONE:
-		parg = arg;
-		break;
-	case _IOC_READ: /* some v4l ioctls are marked wrong ... */
-	case _IOC_WRITE:
-	case (_IOC_WRITE | _IOC_READ):
-		if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
-			parg = sbuf;
-		} else {
-			/* too big to allocate from stack */
-			mbuf = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL);
-			if (NULL == mbuf)
-				return -ENOMEM;
-			parg = mbuf;
-		}
+	case OV511IOC_WI2C:
+	{
+		struct ov511_i2c_struct *w = arg;
 
-		err = -EFAULT;
-		if (copy_from_user(parg, arg, _IOC_SIZE(cmd)))
-			goto out;
-		break;
+		return i2c_w_slave(ov, w->slave, w->reg, w->value, w->mask);
 	}
+	case OV511IOC_RI2C:
+	{
+		struct ov511_i2c_struct *r = arg;
+		int rc;
 
-	err = ov51x_v4l1_ioctl_internal(vdev->priv, cmd, parg);
-	if (err == -ENOIOCTLCMD)
-		err = -EINVAL;
-	if (err < 0)
-		goto out;
+		rc = i2c_r_slave(ov, r->slave, r->reg);
+		if (rc < 0)
+			return rc;
 
-	/*  Copy results into user buffer  */
-	switch (_IOC_DIR(cmd))
-	{
-	case _IOC_READ:
-	case (_IOC_WRITE | _IOC_READ):
-		if (copy_to_user(arg, parg, _IOC_SIZE(cmd)))
-			err = -EFAULT;
-		break;
+		r->value = rc;
+		return 0;
 	}
+	default:
+		PDEBUG(3, "Unsupported IOCtl: 0x%X", cmd);
+		return -ENOIOCTLCMD;
+	} /* end switch */
 
-out:
-	if (mbuf)
-		kfree(mbuf);
-	return err;
+	return 0;
 }
 
 static int
-ov51x_v4l1_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
+ov51x_v4l1_ioctl(struct inode *inode, struct file *file,
+		 unsigned int cmd, unsigned long arg)
 {
+	struct video_device *vdev = file->private_data;
 	struct usb_ov511 *ov = vdev->priv;
 	int rc;
 
 	if (down_interruptible(&ov->lock))
 		return -EINTR;
 
-	rc = ov51x_v4l1_generic_ioctl(vdev, cmd, arg);
+	rc = video_usercopy(inode, file, cmd, arg, ov51x_v4l1_ioctl_internal);
 
 	up(&ov->lock);
 	return rc;
 }
 
-static inline long
-ov51x_v4l1_read(struct video_device *vdev, char *buf, unsigned long count,
-		int noblock)
+static int
+ov51x_v4l1_read(struct file *file, char *buf, size_t cnt, loff_t *ppos)
 {
+	struct video_device *vdev = file->private_data;
+	int noblock = file->f_flags&O_NONBLOCK;
+	unsigned long count = cnt;
 	struct usb_ov511 *ov = vdev->priv;
 	int i, rc = 0, frmx = -1;
 	struct ov511_frame *frame;
@@ -5188,7 +5219,7 @@
 	PDEBUG(4, "{copy} count used=%ld, new bytes_read=%ld",
 		count, frame->bytes_read);
 
-	/* If all data has been read... */
+	/* If all data have been read... */
 	if (frame->bytes_read
 	    >= get_frame_length(frame)) {
 		frame->bytes_read = 0;
@@ -5213,9 +5244,11 @@
 }
 
 static int
-ov51x_v4l1_mmap(struct video_device *vdev, const char *adr, unsigned long size)
+ov51x_v4l1_mmap(struct file *file, struct vm_area_struct *vma)
 {
-	unsigned long start = (unsigned long)adr;
+	struct video_device *vdev = file->private_data;
+	unsigned long start = vma->vm_start;
+	unsigned long size  = vma->vm_end - vma->vm_start;
 	struct usb_ov511 *ov = vdev->priv;
 	unsigned long page, pos;
 
@@ -5251,16 +5284,22 @@
 	return 0;
 }
 
+static struct file_operations ov511_fops = {
+	.owner =	THIS_MODULE,
+	.open =		ov51x_v4l1_open,
+	.release =	ov51x_v4l1_close,
+	.read =		ov51x_v4l1_read,
+	.mmap =		ov51x_v4l1_mmap,
+	.ioctl =	ov51x_v4l1_ioctl,
+	.llseek =	no_llseek,
+};
+
 static struct video_device vdev_template = {
-	owner:		THIS_MODULE,
-	name:		"OV511 USB Camera",
-	type:		VID_TYPE_CAPTURE,
-	hardware:	VID_HARDWARE_OV511,
-	open:		ov51x_v4l1_open,
-	close:		ov51x_v4l1_close,
-	read:		ov51x_v4l1_read,
-	ioctl:		ov51x_v4l1_ioctl,
-	mmap:		ov51x_v4l1_mmap,
+	.owner =	THIS_MODULE,
+	.name =		"OV511 USB Camera",
+	.type =		VID_TYPE_CAPTURE,
+	.hardware =	VID_HARDWARE_OV511,
+	.fops =		&ov511_fops,
 };
 
 #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
@@ -5450,8 +5489,7 @@
 		if (copy_from_user(&w, arg, sizeof(w)))
 			return -EFAULT;
 
-		return i2c_w_slave(ov, w.slave, w.reg, w.value,
-			w.mask);
+		return i2c_w_slave(ov, w.slave, w.reg, w.value,	w.mask);
 	}
 	case OV511IOC_RI2C:
 	{
@@ -5657,19 +5695,16 @@
 		ov->sensor = SEN_OV7610;
 	} else if ((rc & 3) == 1) {
 		/* I don't know what's different about the 76BE yet. */
-		if (i2c_r(ov, 0x15) & 1) {
+		if (i2c_r(ov, 0x15) & 1)
 			info("Sensor is an OV7620AE");
-			info("PLEASE REPORT THE EXISTENCE OF THIS SENSOR TO");
-			info("THE DRIVER AUTHOR");
-		} else {
+		else
 			info("Sensor is an OV76BE");
-		}
 
 		/* OV511+ will return all zero isoc data unless we
 		 * configure the sensor as a 7620. Someone needs to
 		 * find the exact reg. setting that causes this. */
 		if (ov->bridge == BRG_OV511PLUS) {
-			info("Enabling 511+/76BE workaround");
+			info("Enabling 511+/7620AE workaround");
 			ov->sensor = SEN_OV7620;
 		} else {
 			ov->sensor = SEN_OV76BE;
@@ -5754,86 +5789,61 @@
 		{ OV511_I2C_BUS, 0x4f, 0x04 },
 // Do 50-53 have any effect?
 // Toggle 0x12[2] off and on here?
-		{ OV511_DONE_BUS, 0x0, 0x00 },
+		{ OV511_DONE_BUS, 0x0, 0x00 },	/* END MARKER */
 	};
 
-	/* This chip is undocumented so many of these are guesses. OK=verified,
-	 * A=Added since 6620, U=unknown function (not a 6620 reg) */
 	static struct ov511_regvals aRegvalsNorm6x30[] = {
-	/*OK*/	{ OV511_I2C_BUS, 0x12, 0x80 }, /* reset */
-	/*00?*/	{ OV511_I2C_BUS, 0x11, 0x01 },
-	/*OK*/	{ OV511_I2C_BUS, 0x03, 0x60 },
-	/*0A?*/	{ OV511_I2C_BUS, 0x05, 0x7f }, /* For when autoadjust is off */
+		{ OV511_I2C_BUS, 0x12, 0x80 }, /* reset */
+		{ OV511_I2C_BUS, 0x11, 0x00 },
+		{ OV511_I2C_BUS, 0x03, 0x60 },
+		{ OV511_I2C_BUS, 0x05, 0x7f }, /* For when autoadjust is off */
 		{ OV511_I2C_BUS, 0x07, 0xa8 },
 		/* The ratio of 0x0c and 0x0d  controls the white point */
-	/*OK*/	{ OV511_I2C_BUS, 0x0c, 0x24 },
-	/*OK*/	{ OV511_I2C_BUS, 0x0d, 0x24 },
-	/*A*/	{ OV511_I2C_BUS, 0x0e, 0x20 },
-
-//	/*24?*/	{ OV511_I2C_BUS, 0x12, 0x28 }, /* Enable AGC */
-//		{ OV511_I2C_BUS, 0x12, 0x24 }, /* Enable AGC */
-
-//	/*A*/	{ OV511_I2C_BUS, 0x13, 0x21 },
-//	/*A*/	{ OV511_I2C_BUS, 0x13, 0x25 }, /* Tristate Y and UV busses */
-
-//	/*04?*/	{ OV511_I2C_BUS, 0x14, 0x80 },
-		/* 0x16: 0x06 helps frame stability with moving objects */
-	/*03?*/	{ OV511_I2C_BUS, 0x16, 0x06 },
-//	/*OK*/	{ OV511_I2C_BUS, 0x20, 0x30 }, /* Aperture correction enable */
+		{ OV511_I2C_BUS, 0x0c, 0x24 },
+		{ OV511_I2C_BUS, 0x0d, 0x24 },
+		{ OV511_I2C_BUS, 0x0e, 0x20 },
+//		{ OV511_I2C_BUS, 0x14, 0x80 },
+		{ OV511_I2C_BUS, 0x16, 0x03 },
+//		{ OV511_I2C_BUS, 0x20, 0x30 }, /* Aperture correction enable */
 		// 21 & 22? The suggested values look wrong. Go with default
-	/*A*/	{ OV511_I2C_BUS, 0x23, 0xc0 },
-	/*A*/	{ OV511_I2C_BUS, 0x25, 0x9a }, // Check this against default
-//	/*OK*/	{ OV511_I2C_BUS, 0x26, 0xb2 }, /* BLC enable */
+		{ OV511_I2C_BUS, 0x23, 0xc0 },
+		{ OV511_I2C_BUS, 0x25, 0x9a }, // Check this against default
+//		{ OV511_I2C_BUS, 0x26, 0xb2 }, /* BLC enable */
 
 		/* 0x28: 0x05 Selects RGB format if RGB on */
-//	/*04?*/	{ OV511_I2C_BUS, 0x28, 0x05 },
-//	/*04?*/	{ OV511_I2C_BUS, 0x28, 0x45 }, // DEBUG: Tristate UV bus
+//		{ OV511_I2C_BUS, 0x28, 0x05 },
+//		{ OV511_I2C_BUS, 0x28, 0x45 }, // DEBUG: Tristate UV bus
 
-	/*OK*/	{ OV511_I2C_BUS, 0x2a, 0x04 }, /* Disable framerate adjust */
-//	/*OK*/	{ OV511_I2C_BUS, 0x2b, 0xac }, /* Framerate; Set 2a[7] first */
-//	/*U*/	{ OV511_I2C_BUS, 0x2c, 0xa0 },
+		{ OV511_I2C_BUS, 0x2a, 0x04 }, /* Disable framerate adjust */
+//		{ OV511_I2C_BUS, 0x2b, 0xac }, /* Framerate; Set 2a[7] first */
 		{ OV511_I2C_BUS, 0x2d, 0x99 },
-//	/*A*/	{ OV511_I2C_BUS, 0x33, 0x26 }, // Reserved bits on 6620
-//	/*d2?*/	{ OV511_I2C_BUS, 0x34, 0x03 }, /* Max A/D range */
-//	/*U*/	{ OV511_I2C_BUS, 0x36, 0x8f }, // May not be necessary
-//	/*U*/	{ OV511_I2C_BUS, 0x37, 0x80 }, // May not be necessary
-//	/*8b?*/	{ OV511_I2C_BUS, 0x38, 0x83 },
-//	/*40?*/	{ OV511_I2C_BUS, 0x39, 0xc0 }, // 6630 adds bit 7
+//		{ OV511_I2C_BUS, 0x33, 0x26 }, // Reserved bits on 6620
+//		{ OV511_I2C_BUS, 0x34, 0x03 }, /* Max A/D range */
+//		{ OV511_I2C_BUS, 0x38, 0x83 },
+//		{ OV511_I2C_BUS, 0x39, 0xc0 }, // 6630 adds bit 7
 //		{ OV511_I2C_BUS, 0x3c, 0x39 }, /* Enable AEC mode changing */
 //		{ OV511_I2C_BUS, 0x3c, 0x3c }, /* Change AEC mode */
 //		{ OV511_I2C_BUS, 0x3c, 0x24 }, /* Disable AEC mode changing */
-	/*OK*/	{ OV511_I2C_BUS, 0x3d, 0x80 },
-//	/*A*/	{ OV511_I2C_BUS, 0x3f, 0x0e },
-//	/*U*/	{ OV511_I2C_BUS, 0x40, 0x00 },
-//	/*U*/	{ OV511_I2C_BUS, 0x41, 0x00 },
-//	/*U*/	{ OV511_I2C_BUS, 0x42, 0x80 },
-//	/*U*/	{ OV511_I2C_BUS, 0x43, 0x3f },
-//	/*U*/	{ OV511_I2C_BUS, 0x44, 0x80 },
-//	/*U*/	{ OV511_I2C_BUS, 0x45, 0x20 },
-//	/*U*/	{ OV511_I2C_BUS, 0x46, 0x20 },
-//	/*U*/	{ OV511_I2C_BUS, 0x47, 0x80 },
-//	/*U*/	{ OV511_I2C_BUS, 0x48, 0x7f },
-//	/*U*/	{ OV511_I2C_BUS, 0x49, 0x00 },
+		{ OV511_I2C_BUS, 0x3d, 0x80 },
+//		{ OV511_I2C_BUS, 0x3f, 0x0e },
 
 		/* These next two registers (0x4a, 0x4b) are undocumented. They
 		 * control the color balance */
-//	/*OK?*/	{ OV511_I2C_BUS, 0x4a, 0x80 }, // Check these
-//	/*OK?*/	{ OV511_I2C_BUS, 0x4b, 0x80 },
-//	/*U*/	{ OV511_I2C_BUS, 0x4c, 0xd0 },
-	/*d2?*/	{ OV511_I2C_BUS, 0x4d, 0x10 }, /* This reduces noise a bit */
-	/*c1?*/	{ OV511_I2C_BUS, 0x4e, 0x40 },
-	/*04?*/	{ OV511_I2C_BUS, 0x4f, 0x07 },
-//	/*U*/	{ OV511_I2C_BUS, 0x50, 0xff },
-	/*U*/	{ OV511_I2C_BUS, 0x54, 0x23 },
-//	/*U*/	{ OV511_I2C_BUS, 0x55, 0xff },
-//	/*U*/	{ OV511_I2C_BUS, 0x56, 0x12 },
-	/*U*/	{ OV511_I2C_BUS, 0x57, 0x81 },
-//	/*U*/	{ OV511_I2C_BUS, 0x58, 0x75 },
-	/*U*/	{ OV511_I2C_BUS, 0x59, 0x01 },
-	/*U*/	{ OV511_I2C_BUS, 0x5a, 0x2c },
-	/*U*/	{ OV511_I2C_BUS, 0x5b, 0x0f },
-//	/*U*/	{ OV511_I2C_BUS, 0x5c, 0x10 },
-		{ OV511_DONE_BUS, 0x0, 0x00 },
+//		{ OV511_I2C_BUS, 0x4a, 0x80 }, // Check these
+//		{ OV511_I2C_BUS, 0x4b, 0x80 },
+		{ OV511_I2C_BUS, 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */
+		{ OV511_I2C_BUS, 0x4e, 0x40 },
+
+		/* UV average mode, color killer: strongest */
+		{ OV511_I2C_BUS, 0x4f, 0x07 },
+
+		{ OV511_I2C_BUS, 0x54, 0x23 }, /* Max AGC gain: 18dB */
+		{ OV511_I2C_BUS, 0x57, 0x81 }, /* (default) */
+		{ OV511_I2C_BUS, 0x59, 0x01 }, /* AGC dark current comp: +1 */
+		{ OV511_I2C_BUS, 0x5a, 0x2c }, /* (undocumented) */
+		{ OV511_I2C_BUS, 0x5b, 0x0f }, /* AWB chrominance levels */
+//		{ OV511_I2C_BUS, 0x5c, 0x10 },
+		{ OV511_DONE_BUS, 0x0, 0x00 },	/* END MARKER */
 	};
 
 	PDEBUG(4, "starting sensor configuration");
@@ -5854,16 +5864,19 @@
 		return -1;
 	}
 
-	if ((rc & 3) == 0)
+	if ((rc & 3) == 0) {
 		ov->sensor = SEN_OV6630;
-	else if ((rc & 3) == 1)
+		info("Sensor is an OV6630");
+	} else if ((rc & 3) == 1) {
 		ov->sensor = SEN_OV6620;
-	else if ((rc & 3) == 2)
+		info("Sensor is an OV6620");
+	} else if ((rc & 3) == 2) {
 		ov->sensor = SEN_OV6630;
-	else if ((rc & 3) == 3)
+		info("Sensor is an OV6630AE");
+	} else if ((rc & 3) == 3) {
 		ov->sensor = SEN_OV6630;
-
-	info("Sensor is an %s", symbolic(senlist, ov->sensor));
+		info("Sensor is an OV6630AF");
+	}
 
 	/* Set sensor-specific vars */
 	ov->maxwidth = 352;
@@ -6061,9 +6074,9 @@
 
 	static struct ov511_regvals aRegvalsNorm511[] = {
 		{ OV511_REG_BUS, R511_DRAM_FLOW_CTL, 	0x01 },
-		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x01 },
-		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x03 },
-		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x01 },
+		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x00 },
+		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x02 },
+		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x00 },
 		{ OV511_REG_BUS, R511_FIFO_OPTS,	0x1f },
 		{ OV511_REG_BUS, R511_COMP_EN,		0x00 },
 		{ OV511_REG_BUS, R511_COMP_LUT_EN,	0x03 },
@@ -6072,9 +6085,9 @@
 
 	static struct ov511_regvals aRegvalsNorm511Plus[] = {
 		{ OV511_REG_BUS, R511_DRAM_FLOW_CTL,	0xff },
-		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x01 },
-		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x03 },
-		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x01 },
+		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x00 },
+		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x02 },
+		{ OV511_REG_BUS, R51x_SYS_SNAP,		0x00 },
 		{ OV511_REG_BUS, R511_FIFO_OPTS,	0xff },
 		{ OV511_REG_BUS, R511_COMP_EN,		0x00 },
 		{ OV511_REG_BUS, R511_COMP_LUT_EN,	0x03 },
@@ -6223,7 +6236,7 @@
 		{ OV511_REG_BUS, 0x5d,			0x03 },
 		{ OV511_REG_BUS, 0x24,			0x9f },
 		{ OV511_REG_BUS, 0x25,			0x90 },
-		{ OV511_REG_BUS, 0x20,			0x00 }, /* Was 0x08 */
+		{ OV511_REG_BUS, 0x20,			0x00 },
 		{ OV511_REG_BUS, 0x51,			0x04 },
 		{ OV511_REG_BUS, 0x71,			0x19 },
 		{ OV511_DONE_BUS, 0x0, 0x00 },
@@ -6236,7 +6249,7 @@
 		{ OV511_REG_BUS, 0x5d,			0x03 },
 		{ OV511_REG_BUS, 0x24,			0x9f },
 		{ OV511_REG_BUS, 0x25,			0x90 },
-		{ OV511_REG_BUS, 0x20,			0x60 }, /* Was 0x08 */
+		{ OV511_REG_BUS, 0x20,			0x60 },
 		{ OV511_REG_BUS, 0x51,			0x02 },
 		{ OV511_REG_BUS, 0x71,			0x19 },
 		{ OV511_REG_BUS, 0x40,			0xff },
@@ -6286,11 +6299,20 @@
 
 	if (ov518_init_compression(ov)) goto error;
 
-	/* OV518+ has packet numbering turned on by default */
 	if (ov->bridge == BRG_OV518)
-		ov->packet_numbering = 0;
-	else
+	{
+		struct usb_interface *ifp = &ov->dev->config[0].interface[0];
+		__u16 mxps = ifp->altsetting[7].endpoint[0].wMaxPacketSize;
+
+		/* Some OV518s have packet numbering by default, some don't */
+		if (mxps == 897)
+			ov->packet_numbering = 1;
+		else
+			ov->packet_numbering = 0;
+	} else {
+		/* OV518+ has packet numbering turned on by default */
 		ov->packet_numbering = 1;
+	}
 
 	ov518_set_packet_size(ov, 0);
 
@@ -6450,7 +6472,13 @@
 
 	ov->buf_state = BUF_NOT_ALLOCATED;
 
-	/* Must be kmalloc()'ed, for DMA accessibility */
+	if (usb_make_path(dev, ov->usb_path, OV511_USB_PATH_LEN) < 0) {
+		err("usb_make_path error");
+		goto error_dealloc;
+	}
+
+	/* Allocate control transfer buffer. */
+	/* Must be kmalloc()'ed, for DMA compatibility */
 	ov->cbuf = kmalloc(OV511_CBUF_SIZE, GFP_KERNEL);
 	if (!ov->cbuf)
 		goto error;
@@ -6480,8 +6508,12 @@
 		goto error;
 
 #ifdef OV511_DEBUG
-	if (dump_bridge)
-		ov511_dump_regs(ov);
+	if (dump_bridge) {
+		if (ov->bclass == BCL_OV511)
+			ov511_dump_regs(ov);
+		else
+			ov518_dump_regs(ov);
+	}
 #endif
 
 	memcpy(&ov->vdev, &vdev_template, sizeof(vdev_template));
@@ -6506,7 +6538,8 @@
 		goto error;
 	}
 
-	info("Device registered on minor %d", ov->vdev.minor);
+	info("Device at %s registered to minor %d", ov->usb_path,
+	     ov->vdev.minor);
 
 #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
 	create_proc_ov511_cam(ov);
@@ -6551,10 +6584,8 @@
 
 	PDEBUG(3, "");
 
-	/* We don't want people trying to open up the device */
-	if (!ov->user)
-		video_unregister_device(&ov->vdev);
-	else
+	video_unregister_device(&ov->vdev);
+	if (ov->user)
 		PDEBUG(3, "Device open...deferring video_unregister_device");
 
 	for (n = 0; n < OV511_NUMFRAMES; n++)
@@ -6592,13 +6623,15 @@
 	}
 
 	MOD_DEC_USE_COUNT;
+
+	PDEBUG(3, "Disconnect complete");
 }
 
 static struct usb_driver ov511_driver = {
-	name:		"ov511",
-	id_table:       device_table,
-	probe:		ov51x_probe,
-	disconnect:	ov51x_disconnect
+	.name =		"ov511",
+	.id_table =	device_table,
+	.probe =	ov51x_probe,
+	.disconnect =	ov51x_disconnect
 };
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/ov511.h linux-2.4.21-pre6/drivers/usb/ov511.h
--- linux-2.4.20/drivers/usb/ov511.h	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/ov511.h	2003-03-26 23:49:29.000000000 +0000
@@ -253,6 +253,9 @@
 /* Control transfers use up to 4 bytes */
 #define OV511_CBUF_SIZE		4
 
+/* Size of usb_make_path() buffer */
+#define OV511_USB_PATH_LEN	64
+
 /* Bridge types */
 enum {
 	BRG_UNKNOWN,
@@ -286,21 +289,6 @@
 	SEN_SAA7111A,
 };
 
-// Not implemented yet
-#if 0
-/* Sensor classes */
-enum {
-	SCL_UNKNOWN,
-	SCL_OV7610,	/* 7610, 76BE, 7620AE (for now) */
-	SCL_OV7620,
-	SCL_OV6620,	
-	SCL_OV6630,	/* 6630, 6630AE, 6630AF */
-	SCL_OV8600,
-	SCL_KS0127,	/* SEN_KS0127, SEN_KS0127B */
-	SCL_SAA7111A,
-};
-#endif
-
 enum {
 	STATE_SCANNING,		/* Scanning for start */
 	STATE_HEADER,		/* Parsing header */
@@ -311,7 +299,6 @@
 enum {
 	BUF_NOT_ALLOCATED,
 	BUF_ALLOCATED,
-	BUF_PEND_DEALLOC,	/* ov511->buf_timer is set */
 };
 
 /* --------- Definition of ioctl interface --------- */
@@ -466,6 +453,7 @@
 	int customid;
 	char *desc;
 	unsigned char iface;
+	char usb_path[OV511_USB_PATH_LEN];
 
 	/* Determined by sensor type */
 	int maxwidth;
@@ -521,7 +509,6 @@
 	int bridge;		/* Type of bridge (BRG_*) */
 	int bclass;		/* Class of bridge (BCL_*) */
 	int sensor;		/* Type of image sensor chip (SEN_*) */
-	int sclass;		/* Type of image sensor chip (SCL_*) */
 
 	int packet_size;	/* Frame size per isoc desc */
 	int packet_numbering;	/* Is ISO frame numbering enabled? */
@@ -537,7 +524,6 @@
 	/* Framebuffer/sbuf management */
 	int buf_state;
 	struct semaphore buf_lock;
-	struct timer_list buf_timer;
 
 	struct ov51x_decomp_ops *decomp_ops;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/pegasus.c linux-2.4.21-pre6/drivers/usb/pegasus.c
--- linux-2.4.20/drivers/usb/pegasus.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/pegasus.c	2003-03-26 23:49:55.000000000 +0000
@@ -42,10 +42,12 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.4.26 (2002/03/21)"
+#define DRIVER_VERSION "v0.4.29 (2002/12/31)"
 #define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
 #define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver"
 
+static const char driver_name[] = "pegasus";
+
 #define	PEGASUS_USE_INTR
 #define	PEGASUS_WRITE_EEPROM
 #define	BMSR_MEDIA	(BMSR_10HALF | BMSR_10FULL | BMSR_100HALF | \
@@ -110,20 +112,18 @@
 	wake_up(&pegasus->ctrl_wait);
 }
 
-static int get_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
+static int get_registers(pegasus_t * pegasus, u16 indx, u16 size,
 			 void *data)
 {
 	int ret;
-	unsigned char *buffer;
+	char *buffer;
 	DECLARE_WAITQUEUE(wait, current);
 
-	buffer = kmalloc(size, GFP_KERNEL);
+	buffer = kmalloc(size, GFP_DMA);
 	if (!buffer) {
-		err("unable to allocate memory for configuration descriptors");
-		return 0;
+		warn("%s: looks like we're out of memory", __FUNCTION__);
+		return -ENOMEM;
 	}
-	memcpy(buffer, data, size);
-
 	add_wait_queue(&pegasus->ctrl_wait, &wait);
 	set_current_state(TASK_UNINTERRUPTIBLE);
 	while (pegasus->flags & ETH_REGS_CHANGED)
@@ -160,17 +160,17 @@
 	return ret;
 }
 
-static int set_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
+static int set_registers(pegasus_t * pegasus, u16 indx, u16 size,
 			 void *data)
 {
 	int ret;
-	unsigned char *buffer;
+	char *buffer;
 	DECLARE_WAITQUEUE(wait, current);
 
-	buffer = kmalloc(size, GFP_KERNEL);
+	buffer = kmalloc(size, GFP_DMA);
 	if (!buffer) {
-		err("unable to allocate memory for configuration descriptors");
-		return 0;
+		warn("%s: looks like we're out of memory", __FUNCTION__);
+		return -ENOMEM;
 	}
 	memcpy(buffer, data, size);
 
@@ -209,20 +209,18 @@
 	return ret;
 }
 
-static int set_register(pegasus_t * pegasus, __u16 indx, __u8 data)
+static int set_register(pegasus_t * pegasus, u16 indx, u8 data)
 {
 	int ret;
-	unsigned char *buffer;
-	__u16 dat = data;
+	char *tmp;
 	DECLARE_WAITQUEUE(wait, current);
 
-	buffer = kmalloc(1, GFP_KERNEL);
-	if (!buffer) {
-		err("unable to allocate memory for configuration descriptors");
-		return 0;
+	tmp = kmalloc(1, GFP_DMA);
+	if (!tmp) {
+		warn("%s: looks like we're out of memory", __FUNCTION__);
+		return -ENOMEM;
 	}
-	memcpy(buffer, &data, 1);
-
+	memcpy(tmp, &data, 1);
 	add_wait_queue(&pegasus->ctrl_wait, &wait);
 	set_current_state(TASK_UNINTERRUPTIBLE);
 	while (pegasus->flags & ETH_REGS_CHANGED)
@@ -232,7 +230,7 @@
 
 	pegasus->dr.bRequestType = PEGASUS_REQT_WRITE;
 	pegasus->dr.bRequest = PEGASUS_REQ_SET_REG;
-	pegasus->dr.wValue = cpu_to_le16p(&dat);
+	pegasus->dr.wValue = cpu_to_le16p(&data);
 	pegasus->dr.wIndex = cpu_to_le16p(&indx);
 	pegasus->dr.wLength = cpu_to_le16(1);
 	pegasus->ctrl_urb->transfer_buffer_length = 1;
@@ -240,7 +238,7 @@
 	FILL_CONTROL_URB(pegasus->ctrl_urb, pegasus->usb,
 			 usb_sndctrlpipe(pegasus->usb, 0),
 			 (char *) &pegasus->dr,
-			 buffer, 1, ctrl_callback, pegasus);
+			 tmp, 1, ctrl_callback, pegasus);
 
 	add_wait_queue(&pegasus->ctrl_wait, &wait);
 	set_current_state(TASK_UNINTERRUPTIBLE);
@@ -253,7 +251,7 @@
 	schedule();
 out:
 	remove_wait_queue(&pegasus->ctrl_wait, &wait);
-	kfree(buffer);
+	kfree(tmp);
 
 	return ret;
 }
@@ -281,11 +279,11 @@
 	return ret;
 }
 
-static int read_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 * regd)
+static int read_mii_word(pegasus_t * pegasus, u8 phy, u8 indx, u16 * regd)
 {
 	int i;
-	__u8 data[4] = { phy, 0, 0, indx };
-	__u16 regdi;
+	u8 data[4] = { phy, 0, 0, indx };
+	u16 regdi;
 
 	set_register(pegasus, PhyCtrl, 0);
 	set_registers(pegasus, PhyAddr, sizeof(data), data);
@@ -305,10 +303,19 @@
 	return 1;
 }
 
-static int write_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 regd)
+static int mdio_read(struct net_device *dev, int phy_id, int loc)
+{
+	pegasus_t *pegasus = (pegasus_t *) dev->priv;
+	int res;
+
+	read_mii_word(pegasus, phy_id, loc, (u16 *) & res);
+	return res & 0xffff;
+}
+
+static int write_mii_word(pegasus_t * pegasus, u8 phy, u8 indx, u16 regd)
 {
 	int i;
-	__u8 data[4] = { phy, 0, 0, indx };
+	u8 data[4] = { phy, 0, 0, indx };
 
 	*(data + 1) = cpu_to_le16p(&regd);
 	set_register(pegasus, PhyCtrl, 0);
@@ -326,11 +333,18 @@
 	return 1;
 }
 
-static int read_eprom_word(pegasus_t * pegasus, __u8 index, __u16 * retdata)
+static void mdio_write(struct net_device *dev, int phy_id, int loc, int val)
+{
+	pegasus_t *pegasus = (pegasus_t *) dev->priv;
+
+	write_mii_word(pegasus, phy_id, loc, val);
+}
+
+static int read_eprom_word(pegasus_t * pegasus, u8 index, u16 * retdata)
 {
 	int i;
-	__u8 tmp;
-	__u16 retdatai;
+	u8 tmp;
+	u16 retdatai;
 
 	set_register(pegasus, EpromCtrl, 0);
 	set_register(pegasus, EpromOffset, index);
@@ -354,7 +368,7 @@
 #ifdef	PEGASUS_WRITE_EEPROM
 static inline void enable_eprom_write(pegasus_t * pegasus)
 {
-	__u8 tmp;
+	u8 tmp;
 
 	get_registers(pegasus, EthCtrl2, 1, &tmp);
 	set_register(pegasus, EthCtrl2, tmp | EPROM_WR_ENABLE);
@@ -362,17 +376,17 @@
 
 static inline void disable_eprom_write(pegasus_t * pegasus)
 {
-	__u8 tmp;
+	u8 tmp;
 
 	get_registers(pegasus, EthCtrl2, 1, &tmp);
 	set_register(pegasus, EpromCtrl, 0);
 	set_register(pegasus, EthCtrl2, tmp & ~EPROM_WR_ENABLE);
 }
 
-static int write_eprom_word(pegasus_t * pegasus, __u8 index, __u16 data)
+static int write_eprom_word(pegasus_t * pegasus, u8 index, u16 data)
 {
 	int i, tmp;
-	__u8 d[4] = { 0x3f, 0, 0, EPROM_WRITE };
+	u8 d[4] = { 0x3f, 0, 0, EPROM_WRITE };
 
 	set_registers(pegasus, EpromOffset, 4, d);
 	enable_eprom_write(pegasus);
@@ -393,20 +407,20 @@
 }
 #endif				/* PEGASUS_WRITE_EEPROM */
 
-static inline void get_node_id(pegasus_t * pegasus, __u8 * id)
+static inline void get_node_id(pegasus_t * pegasus, u8 * id)
 {
 	int i;
-	__u16 w16;
+	u16 w16;
 
 	for (i = 0; i < 3; i++) {
 		read_eprom_word(pegasus, i, &w16);
-		((__u16 *) id)[i] = cpu_to_le16p(&w16);
+		((u16 *) id)[i] = cpu_to_le16p(&w16);
 	}
 }
 
 static void set_ethernet_addr(pegasus_t * pegasus)
 {
-	__u8 node_id[6];
+	u8 node_id[6];
 
 	get_node_id(pegasus, node_id);
 	set_registers(pegasus, EthID, sizeof(node_id), node_id);
@@ -415,7 +429,7 @@
 
 static inline int reset_mac(pegasus_t * pegasus)
 {
-	__u8 data = 0x8;
+	u8 data = 0x8;
 	int i;
 
 	set_register(pegasus, EthCtrl1, data);
@@ -438,13 +452,13 @@
 
 	if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS ||
 	    usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK) {
-		__u16 auxmode;
+		u16 auxmode;
 
 		read_mii_word(pegasus, 1, 0x1b, &auxmode);
 		write_mii_word(pegasus, 1, 0x1b, auxmode | 4);
 	}
 	if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_ELCON) {
-		__u16 auxmode;
+		u16 auxmode;
 		read_mii_word(pegasus, 3, 0x1b, &auxmode);
 		write_mii_word(pegasus, 3, 0x1b, auxmode | 4);
 	}
@@ -453,8 +467,8 @@
 
 static int enable_net_traffic(struct net_device *dev, struct usb_device *usb)
 {
-	__u16 linkpart, bmsr;
-	__u8 data[4];
+	u16 linkpart, bmsr;
+	u8 data[4];
 	pegasus_t *pegasus = dev->priv;
 
 	/* read twice 'cos this is a latch bit */
@@ -487,7 +501,7 @@
 	int count = urb->actual_length, res;
 	int rx_status;
 	struct sk_buff *skb;
-	__u16 pkt_len;
+	u16 pkt_len;
 
 	if (!pegasus || !(pegasus->flags & PEGASUS_RUNNING))
 		return;
@@ -531,7 +545,12 @@
 		goto goon;
 	}
 
-	pkt_len = (rx_status & 0xfff) - 8;
+	if (pegasus->chip == 0x8513) {
+		pkt_len = le32_to_cpu(*(int *)pegasus->rx_buff);
+		pkt_len &= 0x0fff;
+	} else {
+		pkt_len = (rx_status & 0x0fff) - 8;
+	}
 
 	if (!(skb = dev_alloc_skb(pkt_len + 2)))
 		goto goon;
@@ -541,6 +560,10 @@
 	eth_copy_and_sum(skb, pegasus->rx_buff, pkt_len, 0);
 	skb_put(skb, pkt_len);
 
+	if (pegasus->chip == 0x8513) {
+		skb->data += 2;
+	}
+
 	skb->protocol = eth_type_trans(skb, net);
 	netif_rx(skb);
 	pegasus->stats.rx_packets++;
@@ -578,7 +601,7 @@
 {
 	pegasus_t *pegasus = urb->context;
 	struct net_device *net;
-	__u8 *d;
+	u8 *d;
 
 	if (!pegasus)
 		return;
@@ -626,11 +649,11 @@
 	pegasus_t *pegasus = net->priv;
 	int count = ((skb->len + 2) & 0x3f) ? skb->len + 2 : skb->len + 3;
 	int res;
-	__u16 l16 = skb->len;
+	u16 l16 = skb->len;
 
 	netif_stop_queue(net);
 
-	((__u16 *) pegasus->tx_buff)[0] = cpu_to_le16(l16);
+	((u16 *) pegasus->tx_buff)[0] = cpu_to_le16(l16);
 	memcpy(pegasus->tx_buff + 2, skb->data, skb->len);
 	FILL_BULK_URB(pegasus->tx_urb, pegasus->usb,
 		      usb_sndbulkpipe(pegasus->usb, 2),
@@ -666,15 +689,15 @@
 
 static inline void get_interrupt_interval(pegasus_t * pegasus)
 {
-	__u8 data[2];
+	u8 data[2];
 
-	read_eprom_word(pegasus, 4, (__u16 *) data);
+	read_eprom_word(pegasus, 4, (u16 *) data);
 	if (data[1] < 0x80) {
 		info("intr interval will be changed from %ums to %ums",
 		     data[1], 0x80);
 		data[1] = 0x80;
 #ifdef	PEGASUS_WRITE_EEPROM
-		write_eprom_word(pegasus, 4, *(__u16 *) data);
+		write_eprom_word(pegasus, 4, *(u16 *) data);
 #endif
 	}
 	pegasus->intr_interval = data[1];
@@ -700,6 +723,9 @@
 	int res;
 
 	down(&pegasus->sem);
+
+	set_registers(pegasus, EthID, 6, net->dev_addr);
+	
 	FILL_BULK_URB(pegasus->rx_urb, pegasus->usb,
 		      usb_rcvbulkpipe(pegasus->usb, 1),
 		      pegasus->rx_buff, PEGASUS_MAX_MTU,
@@ -750,7 +776,82 @@
 
 	return 0;
 }
+#if CONFIG_MII
+static int pegasus_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+
+	u32 ethcmd;
+	pegasus_t *pegasus = dev->priv;
+
+	if (copy_from_user(&ethcmd, useraddr, sizeof (ethcmd)))
+		return -EFAULT;
+
+	switch (ethcmd) {
+	/* get driver-specific version/etc. info */
+	case ETHTOOL_GDRVINFO:{
+			struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+			strncpy(info.driver, driver_name,
+				sizeof (info.driver) - 1);
+			strncpy(info.version, DRIVER_VERSION,
+				sizeof (info.version) - 1);
+			if (copy_to_user(useraddr, &info, sizeof (info)))
+				return -EFAULT;
+			return 0;
+		}
 
+	/* get settings */
+	case ETHTOOL_GSET:{
+			struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+			mii_ethtool_gset(&pegasus->mii, &ecmd);
+			if (copy_to_user(useraddr, &ecmd, sizeof (ecmd)))
+				return -EFAULT;
+			return 0;
+		}
+	/* set settings */
+	case ETHTOOL_SSET:{
+			int r;
+			struct ethtool_cmd ecmd;
+			if (copy_from_user(&ecmd, useraddr, sizeof (ecmd)))
+				return -EFAULT;
+			r = mii_ethtool_sset(&pegasus->mii, &ecmd);
+			return r;
+		}
+	/* restart autonegotiation */
+	case ETHTOOL_NWAY_RST:{
+			return mii_nway_restart(&pegasus->mii);
+		}
+
+	/* get link status */
+	case ETHTOOL_GLINK:{
+			struct ethtool_value edata = { ETHTOOL_GLINK };
+			edata.data = mii_link_ok(&pegasus->mii);
+			if (copy_to_user(useraddr, &edata, sizeof (edata)))
+				return -EFAULT;
+			return 0;
+		}
+	/* get message-level */
+	case ETHTOOL_GMSGLVL:{
+			struct ethtool_value edata = { ETHTOOL_GMSGLVL };
+			/* edata.data = pegasus->msg_enable; FIXME */
+			if (copy_to_user(useraddr, &edata, sizeof (edata)))
+				return -EFAULT;
+			return 0;
+		}
+	/* set message-level */
+	case ETHTOOL_SMSGLVL:{
+			struct ethtool_value edata;
+			if (copy_from_user(&edata, useraddr, sizeof (edata)))
+				return -EFAULT;
+			/* sp->msg_enable = edata.data; FIXME */
+			return 0;
+		}
+
+	}
+
+	return -EOPNOTSUPP;
+
+}
+#else
 static int pegasus_ethtool_ioctl(struct net_device *net, void *uaddr)
 {
 	pegasus_t *pegasus;
@@ -826,10 +927,10 @@
 		return -EOPNOTSUPP;
 	}
 }
-
+#endif
 static int pegasus_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
 {
-	__u16 *data = (__u16 *) & rq->ifr_data;
+	u16 *data = (u16 *) & rq->ifr_data;
 	pegasus_t *pegasus = net->priv;
 	int res;
 
@@ -885,10 +986,10 @@
 	netif_wake_queue(net);
 }
 
-static __u8 mii_phy_probe(pegasus_t * pegasus)
+static u8 mii_phy_probe(pegasus_t * pegasus)
 {
 	int i;
-	__u16 tmp;
+	u16 tmp;
 
 	for (i = 0; i < 32; i++) {
 		read_mii_word(pegasus, i, MII_BMSR, &tmp);
@@ -903,9 +1004,27 @@
 
 static inline void setup_pegasus_II(pegasus_t * pegasus)
 {
+	u16 data = 0xa5;
+	
 	set_register(pegasus, Reg1d, 0);
+	set_register(pegasus, Reg7b, 1);
+	mdelay(100);
 	set_register(pegasus, Reg7b, 2);
-	if (pegasus->features & HAS_HOME_PNA && mii_mode)
+	
+	set_register(pegasus, 0x83, data);
+	get_registers(pegasus, 0x83, 1, &data);
+	
+	if (data & 0xa5) {
+		pegasus->chip = 0x8513;
+	} else {
+		pegasus->chip = 0;
+	}
+	
+	set_register( pegasus, 0x80, 0xc0 );
+	set_register( pegasus, 0x83, 0xff );
+	set_register( pegasus, 0x84, 0x01 );
+	
+	if ((pegasus->features & HAS_HOME_PNA) && mii_mode)
 		set_register(pegasus, Reg81, 6);
 	else
 		set_register(pegasus, Reg81, 2);
@@ -984,6 +1103,11 @@
 	net->set_multicast_list = pegasus_set_multicast;
 	net->get_stats = pegasus_netdev_stats;
 	net->mtu = PEGASUS_MTU;
+	pegasus->mii.dev = net;
+	pegasus->mii.mdio_read = mdio_read;
+	pegasus->mii.mdio_write = mdio_write;
+	pegasus->mii.phy_id_mask = 0x1f;
+	pegasus->mii.reg_num_mask = 0x1f;
 
 	pegasus->features = usb_dev_id[dev_index].private;
 #ifdef	PEGASUS_USE_INTR
@@ -1015,9 +1139,9 @@
 		warn("can't locate MII phy, using default");
 		pegasus->phy = 1;
 	}
-
 exit:
 	up(&pegasus->sem);
+	
 	return pegasus;
 }
 
@@ -1047,7 +1171,7 @@
 }
 
 static struct usb_driver pegasus_driver = {
-	name:		"pegasus",
+	name:		driver_name,
 	probe:		pegasus_probe,
 	disconnect:	pegasus_disconnect,
 	id_table:	pegasus_ids,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/pegasus.h linux-2.4.21-pre6/drivers/usb/pegasus.h
--- linux-2.4.20/drivers/usb/pegasus.h	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/pegasus.h	2003-03-26 23:49:55.000000000 +0000
@@ -85,6 +85,7 @@
 	struct usb_device	*usb;
 	struct net_device	*net;
 	struct net_device_stats	stats;
+	struct mii_if_info	mii;
 	unsigned		flags;
 	unsigned		features;
 	int			dev_index;
@@ -93,6 +94,7 @@
 	struct usb_ctrlrequest	dr;
 	wait_queue_head_t	ctrl_wait;
 	struct semaphore	sem;
+	int			chip;
 	unsigned char		rx_buff[PEGASUS_MAX_MTU];
 	unsigned char		tx_buff[PEGASUS_MAX_MTU];
 	unsigned char		intr_buff[8];
@@ -128,6 +130,8 @@
 #define	VENDOR_LANEED		0x056e
 #define	VENDOR_LINKSYS		0x066b
 #define	VENDOR_MELCO		0x0411
+#define	VENDOR_MOBILITY		0x1342
+#define VENDOR_NETGEAR		0x0846
 #define	VENDOR_SMARTBRIDGES	0x08d1
 #define	VENDOR_SMC		0x0707
 #define	VENDOR_SOHOWARE		0x15e8
@@ -160,11 +164,14 @@
 PEGASUS_DEV( "Accton USB 10/100 Ethernet Adapter", VENDOR_ACCTON, 0x1046,
 		DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_ACCTON, 0x5046,
-		DEFAULT_GPIO_RESET )
+		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "ADMtek ADM8511 \"Pegasus II\" USB Ethernet",
 		VENDOR_ADMTEK, 0x8511,
 		DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "ADMtek AN986 \"Pegasus\" USB Ethernet (eval. board)",
+PEGASUS_DEV( "ADMtek ADM8513 \"Pegasus II\" USB Ethernet",
+		VENDOR_ADMTEK, 0x8513,
+		DEFAULT_GPIO_RESET | PEGASUS_II )	
+PEGASUS_DEV( "ADMtek AN986 \"Pegasus\" USB Ethernet (evaluation board)",
 		VENDOR_ADMTEK, 0x0986,
 		DEFAULT_GPIO_RESET | HAS_HOME_PNA )
 PEGASUS_DEV( "ADMtek AN986A USB MAC", VENDOR_ADMTEK, 0x1986,
@@ -187,7 +194,7 @@
 		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "Corega FEter USB-TX", VENDOR_COREGA, 0x0004,
 		DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "Corega FEter", VENDOR_COREGA, 0x000d,
+PEGASUS_DEV( "Corega FEter USB-TXS", VENDOR_COREGA, 0x000d,
 		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4001,
 		LINKSYS_GPIO_RESET )
@@ -205,6 +212,8 @@
 		DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "GOLDPFEIL USB Adapter", VENDOR_ELCON, 0x0002,
 		DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA )
+PEGASUS_DEV( "EasiDock Ethernet", VENDOR_MOBILITY, 0x0304,
+		DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "Elsa Micolink USB2Ethernet", VENDOR_ELSA, 0x3000,
 		DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "Hawking UF100 10/100 Ethernet", VENDOR_HAWKING, 0x400c,
@@ -223,14 +232,16 @@
 		DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x200c,
 		DEFAULT_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "LANEED USB Ethernet LD-USBL/TX", VENDOR_LANEED, 0x4005,
+		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "Linksys USB10TX", VENDOR_LINKSYS, 0x2202,
 		LINKSYS_GPIO_RESET )
 PEGASUS_DEV( "Linksys USB100TX", VENDOR_LINKSYS, 0x2203,
 		LINKSYS_GPIO_RESET )
 PEGASUS_DEV( "Linksys USB100TX", VENDOR_LINKSYS, 0x2204,
 		LINKSYS_GPIO_RESET | HAS_HOME_PNA )
-PEGASUS_DEV( "Linksys USB Ethernet Adapter", VENDOR_LINKSYS, 0x2206,
-		LINKSYS_GPIO_RESET )
+PEGASUS_DEV( "Linksys USB10T Ethernet Adapter", VENDOR_LINKSYS, 0x2206,
+		LINKSYS_GPIO_RESET | PEGASUS_II)
 PEGASUS_DEV( "Linksys USB USB10TX", VENDOR_LINKSYS, 0x400b,
 		LINKSYS_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "Linksys USB10TX", VENDOR_LINKSYS, 0x200c,
@@ -241,6 +252,8 @@
 		DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "MELCO/BUFFALO LUA2-TX", VENDOR_MELCO, 0x0009,
 		DEFAULT_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "NETGEAR FA101", VENDOR_NETGEAR, 0x1020,
+		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "smartNIC 2 PnP Adapter", VENDOR_SMARTBRIDGES, 0x0003,
 		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "SMC 202 USB Ethernet", VENDOR_SMC, 0x0200,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/powermate.c linux-2.4.21-pre6/drivers/usb/powermate.c
--- linux-2.4.20/drivers/usb/powermate.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/powermate.c	2003-03-26 23:49:55.000000000 +0000
@@ -0,0 +1,363 @@
+/*
+ * A driver for the Griffin Technology, Inc. "PowerMate" USB controller dial.
+ *
+ * v1.0, (c)2002 William R Sowerbutts <will@sowerbutts.com>
+ *
+ * This device is a stainless steel knob which connects over USB. It can measure
+ * clockwise and anticlockwise rotation. The dial also acts as a pushbutton with
+ * a spring for automatic release. The base contains a pair of LEDs which illuminate
+ * the translucent base. It rotates without limit and reports its relative rotation
+ * back to the host when polled by the USB controller.
+ *
+ * Testing with the knob I have has shown that it measures approximately 96 "clicks"
+ * for one full rotation. Testing with my High Speed Rotation Actuator (ok, it was 
+ * a variable speed cordless electric drill) has shown that the device can measure
+ * speeds of up to 7 clicks either clockwise or anticlockwise between pollings from
+ * the host. If it counts more than 7 clicks before it is polled, it will wrap back
+ * to zero and start counting again. This was at quite high speed, however, almost
+ * certainly faster than the human hand could turn it. Griffin say that it loses a
+ * pulse or two on a direction change; the granularity is so fine that I never
+ * noticed this in practice.
+ *
+ * The device's microcontroller can be programmed to set the LED to either a constant
+ * intensity, or to a rhythmic pulsing. Several patterns and speeds are available.
+ *
+ * Griffin were very happy to provide documentation and free hardware for development.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+
+#define POWERMATE_VENDOR       0x077d    /* Griffin Technology, Inc. */
+#define POWERMATE_PRODUCT_NEW  0x0410    /* Griffin PowerMate */
+#define POWERMATE_PRODUCT_OLD  0x04AA    /* Griffin soundKnob */
+
+/* these are the command codes we send to the device */
+#define SET_STATIC_BRIGHTNESS  0x01
+#define SET_PULSE_ASLEEP       0x02
+#define SET_PULSE_AWAKE        0x03
+#define SET_PULSE_MODE         0x04
+
+/* these refer to bits in the powermate_device's requires_update field. */
+#define UPDATE_STATIC_BRIGHTNESS (1<<0)
+#define UPDATE_PULSE_ASLEEP      (1<<1)
+#define UPDATE_PULSE_AWAKE       (1<<2)
+#define UPDATE_PULSE_MODE        (1<<3)
+
+#define POWERMATE_PAYLOAD_SIZE 3
+struct powermate_device {
+	signed char data[POWERMATE_PAYLOAD_SIZE];
+	struct urb irq, config;
+	struct usb_ctrlrequest configdr;
+	struct usb_device *udev;
+	struct input_dev input;
+	struct semaphore lock;
+	int static_brightness;
+	int pulse_speed;
+	int pulse_table;
+	int pulse_asleep;
+	int pulse_awake;
+	int requires_update; // physical settings which are out of sync
+	char phys[64];
+};
+
+static char pm_name_powermate[] = "Griffin PowerMate";
+static char pm_name_soundknob[] = "Griffin SoundKnob";
+
+static void powermate_config_complete(struct urb *urb); /* forward declararation of callback */
+
+/* Callback for data arriving from the PowerMate over the USB interrupt pipe */
+static void powermate_irq(struct urb *urb)
+{
+	struct powermate_device *pm = urb->context;
+
+	if(urb->status)
+		return;
+
+	/* handle updates to device state */
+	input_report_key(&pm->input, BTN_0, pm->data[0] & 0x01);
+	input_report_rel(&pm->input, REL_DIAL, pm->data[1]);
+}
+
+/* Decide if we need to issue a control message and do so. Must be called with pm->lock down */
+static void powermate_sync_state(struct powermate_device *pm)
+{
+	if(pm->requires_update == 0) 
+		return; /* no updates are required */
+	if(pm->config.status == -EINPROGRESS) 
+		return; /* an update is already in progress; it'll issue this update when it completes */
+
+	if(pm->requires_update & UPDATE_PULSE_ASLEEP){
+		pm->configdr.wValue = cpu_to_le16( SET_PULSE_ASLEEP );
+		pm->configdr.wIndex = cpu_to_le16( pm->pulse_asleep ? 1 : 0 );
+		pm->requires_update &= ~UPDATE_PULSE_ASLEEP;
+	}else if(pm->requires_update & UPDATE_PULSE_AWAKE){
+		pm->configdr.wValue = cpu_to_le16( SET_PULSE_AWAKE );
+		pm->configdr.wIndex = cpu_to_le16( pm->pulse_awake ? 1 : 0 );
+		pm->requires_update &= ~UPDATE_PULSE_AWAKE;
+	}else if(pm->requires_update & UPDATE_PULSE_MODE){
+		int op, arg;
+		/* the powermate takes an operation and an argument for its pulse algorithm.
+		   the operation can be:
+		   0: divide the speed
+		   1: pulse at normal speed
+		   2: multiply the speed
+		   the argument only has an effect for operations 0 and 2, and ranges between
+		   1 (least effect) to 255 (maximum effect).
+       
+		   thus, several states are equivalent and are coalesced into one state.
+
+		   we map this onto a range from 0 to 510, with:
+		   0 -- 254    -- use divide (0 = slowest)
+		   255         -- use normal speed
+		   256 -- 510  -- use multiple (510 = fastest).
+
+		   Only values of 'arg' quite close to 255 are particularly useful/spectacular.
+		*/    
+		if(pm->pulse_speed < 255){
+			op = 0;                   // divide
+			arg = 255 - pm->pulse_speed;
+		}else if(pm->pulse_speed > 255){
+			op = 2;                   // multiply
+			arg = pm->pulse_speed - 255;
+		}else{
+			op = 1;                   // normal speed
+			arg = 0;                  // can be any value
+		}
+		pm->configdr.wValue = cpu_to_le16( (pm->pulse_table << 8) | SET_PULSE_MODE );
+		pm->configdr.wIndex = cpu_to_le16( (arg << 8) | op );
+		pm->requires_update &= ~UPDATE_PULSE_MODE;
+	}else if(pm->requires_update & UPDATE_STATIC_BRIGHTNESS){
+		pm->configdr.wValue = cpu_to_le16( SET_STATIC_BRIGHTNESS );
+		pm->configdr.wIndex = cpu_to_le16( pm->static_brightness );
+		pm->requires_update &= ~UPDATE_STATIC_BRIGHTNESS;
+	}else{
+		printk(KERN_ERR "powermate: unknown update required");
+		pm->requires_update = 0; /* fudge the bug */
+		return;
+	}
+
+	pm->config.dev = pm->udev; /* is this necessary? */
+	pm->configdr.bRequestType = 0x41; /* vendor request */
+	pm->configdr.bRequest = 0x01;
+	pm->configdr.wLength = 0;
+
+        FILL_CONTROL_URB(&pm->config, pm->udev, usb_sndctrlpipe(pm->udev, 0), 
+			 (void*)&pm->configdr, 0, 0, powermate_config_complete, pm);	
+
+	if(usb_submit_urb(&pm->config))
+		printk(KERN_ERR "powermate: usb_submit_urb(config) failed");
+}
+
+/* Called when our asynchronous control message completes. We may need to issue another immediately */
+static void powermate_config_complete(struct urb *urb)
+{
+	struct powermate_device *pm = urb->context;
+
+	if(urb->status)
+		printk(KERN_ERR "powermate: config urb returned %d\n", urb->status);
+	
+	down(&pm->lock);
+	powermate_sync_state(pm);
+	up(&pm->lock);
+}
+
+/* Set the LED up as described and begin the sync with the hardware if required */
+static void powermate_pulse_led(struct powermate_device *pm, int static_brightness, int pulse_speed, 
+				int pulse_table, int pulse_asleep, int pulse_awake)
+{
+	if(pulse_speed < 0)
+		pulse_speed = 0;
+	if(pulse_table < 0)
+		pulse_table = 0;
+	if(pulse_speed > 510)
+		pulse_speed = 510;
+	if(pulse_table > 2)
+		pulse_table = 2;
+
+	pulse_asleep = !!pulse_asleep;
+	pulse_awake = !!pulse_awake;
+
+	down(&pm->lock);
+
+	/* mark state updates which are required */
+	/* we update the static brightness if we've changed pulse mode,
+	   because the hardware seems to stick at an arbitrary value rather
+	   than jumping back to the static brightness we requested */
+	if(static_brightness != pm->static_brightness){
+		pm->static_brightness = static_brightness;
+		pm->requires_update |= UPDATE_STATIC_BRIGHTNESS;		
+	}
+	if(pulse_asleep != pm->pulse_asleep){
+		pm->pulse_asleep = pulse_asleep;
+		pm->requires_update |= (UPDATE_PULSE_ASLEEP | UPDATE_STATIC_BRIGHTNESS);
+	}
+	if(pulse_awake != pm->pulse_awake){
+		pm->pulse_awake = pulse_awake;
+		pm->requires_update |= (UPDATE_PULSE_AWAKE | UPDATE_STATIC_BRIGHTNESS);
+	}
+	if(pulse_speed != pm->pulse_speed || pulse_table != pm->pulse_table){
+		pm->pulse_speed = pulse_speed;
+		pm->pulse_table = pulse_table;
+		pm->requires_update |= UPDATE_PULSE_MODE;
+	}
+
+	powermate_sync_state(pm);
+   
+	up(&pm->lock);
+}
+
+/* Callback from the Input layer when an event arrives from userspace to configure the LED */
+static int powermate_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int _value)
+{
+	unsigned int command = (unsigned int)_value;
+	struct powermate_device *pm = dev->private;
+
+	if(type == EV_MSC && code == MSC_PULSELED){
+		/*  
+		    bits  0- 7: 8 bits: LED brightness
+		    bits  8-16: 9 bits: pulsing speed modifier (0 ... 510); 0-254 = slower, 255 = standard, 256-510 = faster.
+		    bits 17-18: 2 bits: pulse table (0, 1, 2 valid)
+		    bit     19: 1 bit : pulse whilst asleep?
+		    bit     20: 1 bit : pulse constantly?
+		*/  
+		int static_brightness = command & 0xFF;   // bits 0-7
+		int pulse_speed = (command >> 8) & 0x1FF; // bits 8-16
+		int pulse_table = (command >> 17) & 0x3;  // bits 17-18
+		int pulse_asleep = (command >> 19) & 0x1; // bit 19
+		int pulse_awake  = (command >> 20) & 0x1; // bit 20
+  
+		powermate_pulse_led(pm, static_brightness, pulse_speed, pulse_table, pulse_asleep, pulse_awake);
+	}
+
+	return 0;
+}
+
+/* Called whenever a USB device matching one in our supported devices table is connected */
+static void *powermate_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id)
+{
+	struct usb_interface_descriptor *interface;
+	struct usb_endpoint_descriptor *endpoint;
+	struct powermate_device *pm;
+	int pipe, maxp;
+
+	interface = udev->config[0].interface[ifnum].altsetting + 0;
+	endpoint = interface->endpoint + 0;
+	if (!(endpoint->bEndpointAddress & 0x80)) return NULL;
+	if ((endpoint->bmAttributes & 3) != 3) return NULL;
+
+	usb_set_protocol(udev, interface->bInterfaceNumber, 0);
+	usb_set_idle(udev, interface->bInterfaceNumber, 0, 0);
+
+	if (!(pm = kmalloc(sizeof(struct powermate_device), GFP_KERNEL)))
+		return NULL;
+
+	memset(pm, 0, sizeof(struct powermate_device));
+	pm->udev = udev;
+
+	init_MUTEX(&pm->lock);
+
+	/* get a handle to the interrupt data pipe */
+	pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
+	maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
+
+	if(maxp != POWERMATE_PAYLOAD_SIZE)
+		printk("powermate: Expected payload of %d bytes, found %d bytes!\n", POWERMATE_PAYLOAD_SIZE, maxp);
+
+	FILL_INT_URB(&pm->irq, udev, pipe, pm->data, POWERMATE_PAYLOAD_SIZE, powermate_irq, pm, endpoint->bInterval);
+
+	/* register our interrupt URB with the USB system */
+	if(usb_submit_urb(&pm->irq)) {
+		kfree(pm);
+		return NULL; /* failure */
+	}
+
+	switch (udev->descriptor.idProduct) {
+	case POWERMATE_PRODUCT_NEW: pm->input.name = pm_name_powermate; break;
+	case POWERMATE_PRODUCT_OLD: pm->input.name = pm_name_soundknob; break;
+	default: 
+	  pm->input.name = pm_name_soundknob;
+	  printk(KERN_WARNING "powermate: unknown product id %04x\n", udev->descriptor.idProduct);
+	}
+
+	pm->input.private = pm;
+	pm->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_MSC);
+	pm->input.keybit[LONG(BTN_0)] = BIT(BTN_0);
+	pm->input.relbit[LONG(REL_DIAL)] = BIT(REL_DIAL);
+	pm->input.mscbit[LONG(MSC_PULSELED)] = BIT(MSC_PULSELED);
+	pm->input.idbus = BUS_USB;
+	pm->input.idvendor = udev->descriptor.idVendor;
+	pm->input.idproduct = udev->descriptor.idProduct;
+	pm->input.idversion = udev->descriptor.bcdDevice;
+	pm->input.event = powermate_input_event;
+
+	input_register_device(&pm->input);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) /* Vojtech -- is this the correct version? */
+	{
+		char path[64];
+		usb_make_path(udev, path, 64);
+		snprintf(pm->phys, 64, "%s/input0", path);
+		printk(KERN_INFO "input: %s on %s\n", pm->input.name, pm->input.path);
+	}
+#else
+	printk(KERN_INFO "input: %s on input%d\n", pm->input.name, pm->input.number);
+#endif
+	
+	/* force an update of everything */
+	pm->requires_update = UPDATE_PULSE_ASLEEP | UPDATE_PULSE_AWAKE | UPDATE_PULSE_MODE | UPDATE_STATIC_BRIGHTNESS;
+	powermate_pulse_led(pm, 0x80, 255, 0, 1, 0); // set default pulse parameters
+  
+	return pm;
+}
+
+/* Called when a USB device we've accepted ownership of is removed */
+static void powermate_disconnect(struct usb_device *dev, void *ptr)
+{
+	struct powermate_device *pm = ptr;
+	down(&pm->lock);
+	pm->requires_update = 0;
+	usb_unlink_urb(&pm->irq);  
+	input_unregister_device(&pm->input);
+  
+	kfree(pm);
+}
+
+static struct usb_device_id powermate_devices [] = {
+	{ USB_DEVICE(POWERMATE_VENDOR, POWERMATE_PRODUCT_NEW) },
+	{ USB_DEVICE(POWERMATE_VENDOR, POWERMATE_PRODUCT_OLD) },
+	{ } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, powermate_devices);
+
+static struct usb_driver powermate_driver = {
+        name:           "powermate",
+        probe:          powermate_probe,
+        disconnect:     powermate_disconnect,
+        id_table:       powermate_devices,
+};
+
+int powermate_init(void)
+{
+	if (usb_register(&powermate_driver) < 0)
+		return -1;
+	return 0;
+}
+
+void powermate_cleanup(void)
+{
+	usb_deregister(&powermate_driver);
+}
+
+module_init(powermate_init);
+module_exit(powermate_cleanup);
+
+MODULE_AUTHOR( "William R Sowerbutts" );
+MODULE_DESCRIPTION( "Griffin Technology, Inc PowerMate driver" );
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/pwc-ctrl.c linux-2.4.21-pre6/drivers/usb/pwc-ctrl.c
--- linux-2.4.20/drivers/usb/pwc-ctrl.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/pwc-ctrl.c	2003-03-26 23:49:55.000000000 +0000
@@ -256,8 +256,10 @@
 
 	memcpy(buf, pEntry->mode, 3);	
 	ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 3);
-	if (ret < 0)
+	if (ret < 0) {
+		Debug("Failed to send video command... %d\n", ret);
 		return ret;
+	}
 	if (pEntry->compressed && pdev->decompressor != NULL)
 		pdev->decompressor->init(pdev->release, buf, pdev->decompress_data);
 		
@@ -444,8 +446,8 @@
 			Info("Video mode %s@%d fps is only supported with the decompressor module (pwcx).\n", size2name[size], frames);
 		else {
 			Err("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret);
-			return ret;
 		}
+		return ret;
 	}
 	pdev->view.x = width;
 	pdev->view.y = height;
@@ -997,7 +999,7 @@
 		&buf, 1, HZ / 2);
 
 	if (ret < 0)
-	    return ret;
+		return ret;
 	
 	return (buf << 8);
 }
@@ -1103,12 +1105,7 @@
 	buf[0] = on_value;
 	buf[1] = off_value;
 
-	return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
-		SET_STATUS_CTL,
-		USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-		LED_FORMATTER,
-		pdev->vcinterface,
-		&buf, 2, HZ / 2);
+	return SendControlMsg(SET_STATUS_CTL, LED_FORMATTER, 2);
 }
 
 int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value)
@@ -1122,13 +1119,7 @@
 		return 0;
 	}
 
-	ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
-   	        GET_STATUS_CTL,
-		USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-		LED_FORMATTER,
-		pdev->vcinterface,
-		&buf, 2, HZ / 2);
-
+	ret = RecvControlMsg(GET_STATUS_CTL, LED_FORMATTER, 2);
 	if (ret < 0)
 		return ret;
 	*on_value = buf[0] * 100;
@@ -1252,7 +1243,7 @@
 	int ret;
 	unsigned char buf;
 	
-	ret = RecvControlMsg(SET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1);
+	ret = RecvControlMsg(GET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1);
 	if (ret < 0)
 		return ret;
 	return buf;
@@ -1276,10 +1267,9 @@
 	int ret;
 	unsigned char buf;
 	
-	ret = RecvControlMsg(SET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1);
+	ret = RecvControlMsg(GET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1);
 	if (ret < 0)
 		return ret;
-Debug("pwc_get_dynamic_noise = %d\n", buf);
 	return buf;
 }
 
@@ -1595,6 +1585,16 @@
 		break;
 	}
 	
+	case VIDIOCPWCGREALSIZE:
+	{
+		struct pwc_imagesize size;
+		
+		size.width = pdev->image.x;
+		size.height = pdev->image.y;
+		if (copy_to_user(arg, &size, sizeof(size)))
+			ret = -EFAULT;
+		break;
+	}	
 
 	default:
 		ret = -ENOIOCTLCMD;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/pwc-if.c linux-2.4.21-pre6/drivers/usb/pwc-if.c
--- linux-2.4.20/drivers/usb/pwc-if.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/pwc-if.c	2003-03-26 23:49:51.000000000 +0000
@@ -42,11 +42,15 @@
    - Alistar Moire: QuickCam 3000 Pro device/product ID
    - Tony Hoyle: Creative Labs Webcam 5 device/product ID
    - Mark Burazin: solving hang in VIDIOCSYNC when camera gets unplugged
-   - Jk Fang: SOTEC device/product ID
+   - Jk Fang: Sotec Afina Eye ID
+   - Xavier Roche: QuickCam Pro 4000 ID
+   - Jens Knudsen: QuickCam Zoom ID
+   - J. Debert: QuickCam for Notebooks ID
 */
 
 #include <linux/errno.h>
 #include <linux/init.h>
+#include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/poll.h>
 #include <linux/slab.h>
@@ -58,10 +62,6 @@
 #include "pwc-ioctl.h"
 #include "pwc-uncompress.h"
 
-#if !defined(MAP_NR)
-#define MAP_NR(a) virt_to_page(a)
-#endif
-
 /* Function prototypes and driver templates */
 
 /* hotplug device table support */
@@ -76,10 +76,13 @@
 	{ USB_DEVICE(0x0471, 0x0311) },
 	{ USB_DEVICE(0x0471, 0x0312) },
 	{ USB_DEVICE(0x069A, 0x0001) }, /* Askey */
-	{ USB_DEVICE(0x046D, 0x08b0) }, /* Logitech */
+	{ USB_DEVICE(0x046D, 0x08b0) }, /* Logitech QuickCam Pro 3000 */
+	{ USB_DEVICE(0x046D, 0x08b1) }, /* Logitech QuickCam Notebook Pro */
+	{ USB_DEVICE(0x046d, 0x08b2) }, /* Logitech QuickCam Pro 4000 */
+	{ USB_DEVICE(0x046d, 0x08b3) }, /* Logitech QuickCam Zoom */
 	{ USB_DEVICE(0x055D, 0x9000) }, /* Samsung */
 	{ USB_DEVICE(0x055D, 0x9001) },
-	{ USB_DEVICE(0x041E, 0x400C) }, /* Creative */
+	{ USB_DEVICE(0x041E, 0x400C) }, /* Creative Webcam 5 */
 	{ USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */
 	{ USB_DEVICE(0x0d81, 0x1910) }, /* Visionite */
 	{ USB_DEVICE(0x0d81, 0x1900) },
@@ -127,7 +130,7 @@
 static long pwc_video_write(struct video_device *vdev, const char *buf, unsigned long count, int noblock);
 static unsigned int pwc_video_poll(struct video_device *vdev, struct file *file, poll_table *wait);
 static int  pwc_video_ioctl(struct video_device *vdev, unsigned int cmd, void *arg);
-static int  pwc_video_mmap(struct video_device *dev, const char *adr, unsigned long size);
+static int  pwc_video_mmap(struct video_device *vdev, const char *adr, unsigned long size);
 
 static struct video_device pwc_template = {
 	owner:		THIS_MODULE,
@@ -238,7 +241,7 @@
 	int i;
 	void *kbuf;
 
-	Trace(TRACE_MEMORY, "Entering allocate_buffers(%p).\n", pdev);
+	Trace(TRACE_MEMORY, ">> pwc_allocate_buffers(pdev = 0x%p)\n", pdev);
 
 	if (pdev == NULL)
 		return -ENXIO;
@@ -315,7 +318,7 @@
 
 	kbuf = NULL;
 	  
-	Trace(TRACE_MEMORY, "Leaving pwc_allocate_buffers().\n");
+	Trace(TRACE_MEMORY, "<< pwc_allocate_buffers()\n");
 	return 0;
 }
 
@@ -612,7 +615,7 @@
 	}
 #endif
 	if (urb->status == -ENOENT || urb->status == -ECONNRESET) {
-		Trace(TRACE_OPEN, "pwc_isoc_handler(): URB unlinked.\n");
+		Trace(TRACE_OPEN, "pwc_isoc_handler(): URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a");
 		return;
 	}
 	if (urb->status != -EINPROGRESS && urb->status != 0) {
@@ -685,9 +688,22 @@
 #if PWC_DEBUG
 							Debug("Hyundai CMOS sensor bug. Dropping frame %d.\n", fbuf->sequence);
 #endif
-							pdev->drop_frames = 2;
+							pdev->drop_frames += 2;
 							pdev->vframes_error++;
 						}
+						if ((ptr[0] ^ pdev->vmirror) & 0x01) {
+							if (ptr[0] & 0x01)
+								Info("Snapshot button pressed.\n");
+							else
+								Info("Snapshot button released.\n");
+						}
+						if ((ptr[0] ^ pdev->vmirror) & 0x02) {
+							if (ptr[0] & 0x02)
+								Info("Image is mirrored.\n");
+							else
+								Info("Image is normal.\n");
+						}
+						pdev->vmirror = ptr[0] & 0x03;
 						/* Sometimes the trailer of the 730 is still sent as a 4 byte packet 
 						   after a short frame; this condition is filtered out specifically. A 4 byte
 						   frame doesn't make sense anyway.
@@ -704,7 +720,7 @@
 					/* In case we were instructed to drop the frame, do so silently.
 					   The buffer pointers are not updated either (but the counters are reset below).
 					 */
-					if (pdev->drop_frames)
+					if (pdev->drop_frames > 0)
 						pdev->drop_frames--;
 					else {
 						/* Check for underflow first */
@@ -740,10 +756,14 @@
 			} /* .. flen < last_packet_size */
 			pdev->vlast_packet_size = flen;
 		} /* ..status == 0 */
-#ifdef PWC_DEBUG
+#if PWC_DEBUG
 		/* This is normally not interesting to the user, unless you are really debugging something */
-		else 
-			Trace(TRACE_FLOW, "Iso frame %d of USB has error %d\n", i, fst);
+		else {
+			static int iso_error = 0;
+			iso_error++;
+			if (iso_error < 20)
+				Trace(TRACE_FLOW, "Iso frame %d of USB has error %d\n", i, fst);
+		}
 #endif			
 	}
 	if (awake)
@@ -758,7 +778,6 @@
 	int i, j, ret;
 
 	struct usb_interface_descriptor *idesc;
-	int cur_alt;
 
 	if (pdev == NULL)
 		return -EFAULT;
@@ -766,12 +785,11 @@
 		return 0;
 	pdev->vsync = 0;
 	udev = pdev->udev;
-	
+
 	/* Get the current alternate interface, adjust packet size */
 	if (!udev->actconfig)
 		return -EFAULT;
-	cur_alt = udev->actconfig->interface[0].act_altsetting;
-	idesc = &udev->actconfig->interface[0].altsetting[cur_alt];
+	idesc = &udev->actconfig->interface[0].altsetting[pdev->valternate];
 	if (!idesc)
 		return -EFAULT;
 
@@ -783,12 +801,18 @@
 			break;
 		}
 	
-	if (pdev->vmax_packet_size < 0) {
+	if (pdev->vmax_packet_size < 0 || pdev->vmax_packet_size > ISO_MAX_FRAME_SIZE) {
 		Err("Failed to find packet size for video endpoint in current alternate setting.\n");
 		return -ENFILE; /* Odd error, that should be noticable */
 	}
 
+	/* Set alternate interface */
 	ret = 0;
+	Trace(TRACE_OPEN, "Setting alternate interface %d\n", pdev->valternate);
+	ret = usb_set_interface(pdev->udev, 0, pdev->valternate);
+	if (ret < 0)
+		return ret;
+
 	for (i = 0; i < MAX_ISO_BUFS; i++) {
 		urb = usb_alloc_urb(ISO_FRAMES_PER_DESC);
 		if (urb == NULL) {
@@ -797,6 +821,7 @@
 			break;
 		}
 		pdev->sbuf[i].urb = urb;
+		Trace(TRACE_MEMORY, "Allocated URB at 0x%p\n", urb);
 	}
 	if (ret) {
 		/* De-allocate in reverse order */
@@ -808,8 +833,7 @@
 		}
 		return ret;
 	}
-	
-	
+
 	/* init URB structure */	
 	for (i = 0; i < MAX_ISO_BUFS; i++) {
 		urb = pdev->sbuf[i].urb;
@@ -826,7 +850,7 @@
 		urb->number_of_packets = ISO_FRAMES_PER_DESC;
 		for (j = 0; j < ISO_FRAMES_PER_DESC; j++) {
 			urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE;
-			urb->iso_frame_desc[j].length = ISO_MAX_FRAME_SIZE;
+			urb->iso_frame_desc[j].length = pdev->vmax_packet_size;
 		}
 	}
 
@@ -836,11 +860,12 @@
 		if (ret)
 			Err("isoc_init() submit_urb %d failed with error %d\n", i, ret);
 		else
-			Trace(TRACE_OPEN, "pwc_isoc_init(): URB submitted.\n");
+			Trace(TRACE_OPEN, "URB 0x%p submitted.\n", pdev->sbuf[i].urb);
 	}
 
-	/* data should stream in now */
+	/* All is done... */
 	pdev->iso_init = 1;
+	Trace(TRACE_OPEN, "<< pwc_isoc_init()\n");
 	return 0;
 }
 
@@ -848,21 +873,34 @@
 {
 	int i;
 	
+	Trace(TRACE_OPEN, ">> pwc_isoc_cleanup()\n");
 	if (pdev == NULL)
 		return;
-	if (!pdev->iso_init)
-		return;
+
+	/* Unlinking ISOC buffers one by one */
+	for (i = 0; i < MAX_ISO_BUFS; i++) {
+		struct urb *urb;
+
+		urb = pdev->sbuf[i].urb;
+		if (urb != 0) {
+			if (pdev->iso_init) {
+				Trace(TRACE_MEMORY, "Unlinking URB %p\n", urb);
+				usb_unlink_urb(urb);
+			}
+			Trace(TRACE_MEMORY, "Freeing URB\n");
+			usb_free_urb(urb);
+			pdev->sbuf[i].urb = NULL;
+		}
+	}
+
 	/* Stop camera, but only if we are sure the camera is still there */
-	if (!pdev->unplugged)
+	if (!pdev->unplugged) {
+		Trace(TRACE_OPEN, "Setting alternate interface 0.\n");
 		usb_set_interface(pdev->udev, 0, 0);
-	/* Unlinking ISOC buffers one by one */
-	for (i = MAX_ISO_BUFS - 1; i >= 0; i--) {
-		pdev->sbuf[i].urb->next = NULL;
-		usb_unlink_urb(pdev->sbuf[i].urb);
-		usb_free_urb(pdev->sbuf[i].urb);
-		pdev->sbuf[i].urb = NULL;
 	}
+
 	pdev->iso_init = 0;
+	Trace(TRACE_OPEN, "<< pwc_isoc_cleanup()\n");
 }
 
 int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot)
@@ -876,11 +914,10 @@
 	ret = pwc_set_video_mode(pdev, width, height, new_fps, new_compression, new_snapshot);
 	if (ret) /* That failed... restore old mode (we know that worked) */
 		ret = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
-	else /* Set (new) alternate interface */
-		ret = usb_set_interface(pdev->udev, 0, pdev->valternate);
 	if (!ret)
-		ret = pwc_isoc_init(pdev);
-	pdev->drop_frames = 1; /* try to avoid garbage during switch */
+		if (pwc_isoc_init(pdev) < 0)
+			Info("Failed to restart ISOC transfers in pwc_try_video_mode.\n");
+	pdev->drop_frames++; /* try to avoid garbage during switch */
 	return ret;
 }
 
@@ -915,20 +952,19 @@
 	int i;
 	struct pwc_device *pdev;
 
-	Trace(TRACE_OPEN, "video_open called(0x%p, 0%o).\n", vdev, mode);
+	Trace(TRACE_OPEN, ">> video_open called(vdev = 0x%p).\n", vdev);
 	
 	if (vdev == NULL)
 		BUG();
 	pdev = (struct pwc_device *)vdev->priv;
 	if (pdev == NULL)
 		BUG();
+	if (pdev->vopen)
+		return -EBUSY;
 	
 	down(&pdev->modlock);
 	if (!pdev->usb_init) {
 		Trace(TRACE_OPEN, "Doing first time initialization.\n");
-		/* Reset camera */
-		if (usb_set_interface(pdev->udev, 0, 0))
-			Info("Failed to set alternate interface to 0.\n");
 		pdev->usb_init = 1;
 		
 		if (pwc_trace & TRACE_OPEN) {
@@ -948,10 +984,10 @@
 			case 0x40:  sensor_type = "UPA 1021 sensor"; break;
 			case 0x100: sensor_type = "VGA sensor"; break;
 			case 0x101: sensor_type = "PAL MR sensor"; break;
-			default:   sensor_type = "unknown type of sensor"; break;
+			default:    sensor_type = "unknown type of sensor"; break;
 			}
 			if (sensor_type != NULL)
-				Info("Thes %s camera is equipped with a %s (%d).\n", pdev->vdev->name, sensor_type, i);
+				Info("This %s camera is equipped with a %s (%d).\n", pdev->vdev->name, sensor_type, i);
 		}
 	}
 
@@ -1017,16 +1053,9 @@
 		return i;
 	}
 	
-	i = usb_set_interface(pdev->udev, 0, pdev->valternate);
-	if (i) {
-		Trace(TRACE_OPEN, "Failed to set alternate interface = %d.\n", i);
-		up(&pdev->modlock);
-		return -EINVAL;
-	}
 	i = pwc_isoc_init(pdev);
 	if (i) {
 		Trace(TRACE_OPEN, "Failed to init ISOC stuff = %d.\n", i);
-		MOD_DEC_USE_COUNT;
 		up(&pdev->modlock);
 		return i;
 	}
@@ -1039,7 +1068,7 @@
 	if (pdev->decompressor != NULL)
 		pdev->decompressor->lock();
 	up(&pdev->modlock);
-	Trace(TRACE_OPEN, "video_open() returning 0.\n");
+	Trace(TRACE_OPEN, "<< video_open() returns 0.\n");
 	return 0;
 }
 
@@ -1049,15 +1078,12 @@
 	struct pwc_device *pdev;
 	int i;
 
-	Trace(TRACE_OPEN, "video_close called(0x%p).\n", vdev);
+	Trace(TRACE_OPEN, ">> video_close called(vdev = 0x%p).\n", vdev);
 
 	pdev = (struct pwc_device *)vdev->priv;
 	if (pdev->vopen == 0)
 		Info("video_close() called on closed device?\n");
 
-	/* Free isoc URBs */
-	pwc_isoc_cleanup(pdev);
-
 	/* Dump statistics, but only if a reasonable amount of frames were
 	   processed (to prevent endless log-entries in case of snap-shot
 	   programs) 
@@ -1065,21 +1091,14 @@
 	if (pdev->vframe_count > 20)
 		Info("Closing video device: %d frames received, dumped %d frames, %d frames with errors.\n", pdev->vframe_count, pdev->vframes_dumped, pdev->vframes_error);
 
-	if (pdev->unplugged) {
-		/* The device was unplugged or some other error occured */
-		/* We unregister the video_device */
-		Trace(TRACE_OPEN, "Delayed video device unregistered.\n");
-		video_unregister_device(pdev->vdev);
-	}
-	else {
-		/* Normal close: stop isochronuous and interrupt endpoint */
-		Trace(TRACE_OPEN, "Normal close(): setting interface to 0.\n");
-		usb_set_interface(pdev->udev, 0, 0);
+	/* Free isoc URBs, stop camera */
+	pwc_isoc_cleanup(pdev);
 
+	if (!pdev->unplugged) {
 		/* Turn LEDs off */
 		if (pwc_set_leds(pdev, 0, 0) < 0)
-			Info("Failed to set LED on/off time..\n");
-		/* Power down camere to save energy */
+			Info("Failed to set LED on/off time.\n");
+		/* Power down camera to save energy */
 		if (power_save) {
 			i = pwc_camera_power(pdev, 0);
 			if (i < 0) 
@@ -1097,6 +1116,7 @@
 	/* wake up _disconnect() routine */
 	if (pdev->unplugged)
 		wake_up(&pdev->remove_ok);
+	Trace(TRACE_OPEN, "<< video_close()\n");
 }
 
 /*
@@ -1131,6 +1151,7 @@
 	if (pdev->image_read_pos == 0) {
 		/* Do wait queueing according to the (doc)book */
 		add_wait_queue(&pdev->frameq, &wait);
+	        set_current_state(TASK_INTERRUPTIBLE);
 		while (pdev->full_frames == NULL) {
 	                if (noblock) {
 	                	remove_wait_queue(&pdev->frameq, &wait);
@@ -1483,6 +1504,7 @@
 			            frameq is safe now.
 			 */
 			add_wait_queue(&pdev->frameq, &wait);
+		        set_current_state(TASK_INTERRUPTIBLE);
 			while (pdev->full_frames == NULL) {
 				if (pdev->unplugged) {
 					remove_wait_queue(&pdev->frameq, &wait);
@@ -1495,8 +1517,8 @@
 		                	set_current_state(TASK_RUNNING);
 		                	return -ERESTARTSYS;
 	        	        }
-	                	schedule();
 		                set_current_state(TASK_INTERRUPTIBLE);
+	                	schedule();
 			}
 			remove_wait_queue(&pdev->frameq, &wait);
 			set_current_state(TASK_RUNNING);
@@ -1574,8 +1596,6 @@
 	Trace(TRACE_MEMORY, "mmap(0x%p, 0x%p, %lu) called.\n", vdev, adr, size);
 	pdev = vdev->priv;
 
-	/* FIXME - audit mmap during a read */		
-	/* Nemo: 9 months and 20 kernel revisions later I still don't know what you mean by this :-) */
 	pos = (unsigned long)pdev->image_data;
 	while (size > 0) {
 		page = kvirt_to_pa(pos);
@@ -1691,10 +1711,25 @@
 	else if (vendor_id == 0x046d) {
 		switch(product_id) {
 		case 0x08b0:
-			Info("Logitech QuickCam 3000 Pro USB webcam detected.\n");
-			name = "Logitech QuickCam 3000 Pro";
+			Info("Logitech QuickCam Pro 3000 USB webcam detected.\n");
+			name = "Logitech QuickCam Pro 3000";
 			type_id = 730;
-        		break;
+			break;
+		case 0x08b1:
+			Info("Logitech QuickCam for Notebook Pro USB webcam detected.\n");
+			name = "Logitech QuickCam Notebook Pro";
+			type_id = 740; /* ?? unknown sensor */
+			break;
+		case 0x08b2:
+			Info("Logitech QuickCam 4000 Pro USB webcam detected.\n");
+			name = "Logitech QuickCam Pro 4000";
+			type_id = 740; /* CCD sensor */
+			break;
+		case 0x08b3:
+			Info("Logitech QuickCam Zoom USB webcam detected.\n");
+			name = "Logitech QuickCam Zoom";
+			type_id = 740; /* CCD sensor */
+			break;
         	default:
         		return NULL;
         		break;
@@ -1868,6 +1903,10 @@
 	
 	pdev->unplugged = 1;
 	if (pdev->vdev != NULL) {
+		add_wait_queue(&pdev->remove_ok, &wait);
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		Trace(TRACE_PROBE, "Unregistering video device.\n");
+		video_unregister_device(pdev->vdev); 
 		if (pdev->vopen) {
 			Info("Disconnected while device/video is open!\n");
 			
@@ -1883,23 +1922,19 @@
 			 */
 			   
 			Trace(TRACE_PROBE, "Sleeping on remove_ok.\n");
-			add_wait_queue(&pdev->remove_ok, &wait);
-			set_current_state(TASK_UNINTERRUPTIBLE);
 			/* ... wait ... */
 			schedule();
-			remove_wait_queue(&pdev->remove_ok, &wait);
-			set_current_state(TASK_RUNNING);
 			Trace(TRACE_PROBE, "Done sleeping.\n");
 			set_mem_leak(pdev->vdev);
 			pdev->vdev = NULL;
 		}
 		else {
 			/* Normal disconnect; remove from available devices */
-			Trace(TRACE_PROBE, "Unregistering video device normally.\n");
-			video_unregister_device(pdev->vdev); 
 			kfree(pdev->vdev);
 			pdev->vdev = NULL;
 		}
+		remove_wait_queue(&pdev->remove_ok, &wait);
+		set_current_state(TASK_RUNNING);
 	}
 
 	/* search device_hint[] table if we occupy a slot, by any chance */
@@ -1914,7 +1949,7 @@
 
 
 /* *grunt* We have to do atoi ourselves :-( */
-static int pwc_atoi(char *s)
+static int pwc_atoi(const char *s)
 {
 	int k = 0;
 	
@@ -1959,7 +1994,7 @@
 MODULE_PARM(dev_hint, "0-10s");
 MODULE_PARM_DESC(dev_hint, "Device node hints");
 
-MODULE_DESCRIPTION("Philips USB webcam driver");
+MODULE_DESCRIPTION("Philips USB & OEM webcam driver");
 MODULE_AUTHOR("Nemosoft Unv. <nemosoft@smcc.demon.nl>");
 MODULE_LICENSE("GPL");
 
@@ -1969,7 +2004,7 @@
 	char *sizenames[PSZ_MAX] = { "sqcif", "qsif", "qcif", "sif", "cif", "vga" };
 
 	Info("Philips PCA645/646 + PCVC675/680/690 + PCVC730/740/750 webcam module version " PWC_VERSION " loaded.\n");
-	Info("Also supports the Askey VC010, Logitech Quickcam 3000 Pro, Samsung MPC-C10 and MPC-C30,\n");
+	Info("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n");
 	Info("the Creative WebCam 5, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n");
 
 	if (fps) {
@@ -2087,7 +2122,7 @@
 					device_hint[i].serial_number[k] = '\0';
 				}
 			}
-#ifdef PWC_DEBUG		
+#if PWC_DEBUG		
 			Debug("device_hint[%d]:\n", i);
 			Debug("  type    : %d\n", device_hint[i].type);
 			Debug("  serial# : %s\n", device_hint[i].serial_number);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/pwc-ioctl.h linux-2.4.21-pre6/drivers/usb/pwc-ioctl.h
--- linux-2.4.20/drivers/usb/pwc-ioctl.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/pwc-ioctl.h	2003-03-26 23:49:35.000000000 +0000
@@ -18,12 +18,13 @@
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
 
-/*         This is pwc-ioctl.h belonging to PWC 8.6                        */
+/*         This is pwc-ioctl.h belonging to PWC 8.10                        */
 
 /* 
    Changes
    2001/08/03  Alvarado   Added ioctl constants to access methods for 
                           changing white balance and red/blue gains
+   2002/12/15  G. H. Fernandez-Toribio   VIDIOCGREALSIZE
  */
 
 /* These are private ioctl() commands, specific for the Philips webcams.
@@ -104,7 +105,12 @@
 	int led_off;			/* Led off-time; range = 0..25000  */
 };
 
-
+/* Image size (used with GREALSIZE) */
+struct pwc_imagesize
+{
+	int width;
+	int height;
+};
 
  /* Restore user settings */
 #define VIDIOCPWCRUSER		_IO('v', 192)
@@ -173,4 +179,7 @@
 #define VIDIOCPWCSDYNNOISE	_IOW('v', 209, int)
 #define VIDIOCPWCGDYNNOISE	_IOR('v', 209, int)
 
+ /* Real image size as used by the camera; tells you whether or not there's a gray border around the image */
+#define VIDIOCPWCGREALSIZE	_IOR('v', 210, struct pwc_imagesize)
+ 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/pwc-uncompress.c linux-2.4.21-pre6/drivers/usb/pwc-uncompress.c
--- linux-2.4.20/drivers/usb/pwc-uncompress.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/pwc-uncompress.c	2003-03-26 23:49:40.000000000 +0000
@@ -77,7 +77,7 @@
 {
 	struct pwc_frame_buf *fbuf;
 	int n, line, col, stride;
-	void *yuv, *image, *dst;
+	void *yuv, *image;
 	u16 *src;
 	u16 *dsty, *dstu, *dstv;
 
@@ -114,19 +114,6 @@
 		   to get the desired output format/size.
 		 */
 		switch (pdev->vpalette) {
-		case VIDEO_PALETTE_YUV420:
-			/* Calculate byte offsets per line in image & view */
-			n   = (pdev->image.x * 3) / 2;
-			col = (pdev->view.x  * 3) / 2;
-			/* Offset into image */
-			dst = image + (pdev->view.x * pdev->offset.y + pdev->offset.x) * 3 / 2;
-			for (line = 0; line < pdev->image.y; line++) {
-				memcpy(dst, yuv, n);
-				yuv += n;
-				dst += col;
-			}
-			break;
-
 		case VIDEO_PALETTE_YUV420P:
 			/* 
 			 * We do some byte shuffling here to go from the 
@@ -163,17 +150,20 @@
 					dstu += (stride >> 1);
 			}
 			break;
+		default:
+			Err("Unsupported palette!");
+			break;
 		}
 	}
 	else { 
 		/* Compressed; the decompressor routines will write the data 
-		   in interlaced or planar format immediately.
+		   in planar format immediately.
 		 */
 		if (pdev->decompressor)
 			pdev->decompressor->decompress(
 				&pdev->image, &pdev->view, &pdev->offset,
-				yuv, image, 
-				pdev->vpalette == VIDEO_PALETTE_YUV420P ? 1 : 0,
+				yuv, image,
+				1,
 				pdev->decompress_data, pdev->vbandlength);
 		else
 			return -ENXIO; /* No such device or address: missing decompressor */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/pwc.h linux-2.4.21-pre6/drivers/usb/pwc.h
--- linux-2.4.20/drivers/usb/pwc.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/pwc.h	2003-03-26 23:49:40.000000000 +0000
@@ -60,8 +60,8 @@
 
 /* Version block */
 #define PWC_MAJOR	8
-#define PWC_MINOR	6
-#define PWC_VERSION 	"8.6"
+#define PWC_MINOR	10
+#define PWC_VERSION 	"8.10"
 #define PWC_NAME 	"pwc"
 
 /* Turn certain features on/off */
@@ -130,7 +130,7 @@
    int vcinterface;		/* video control interface */
    int valternate;		/* alternate interface needed */
    int vframes, vsize;		/* frames-per-second & size (see PSZ_*) */
-   int vpalette;		/* YUV, RGB24, RGB32, etc */
+   int vpalette;		/* YUV */
    int vframe_count;		/* received frames */
    int vframes_dumped; 		/* counter for dumped frames */
    int vframes_error;		/* frames received in error */
@@ -140,7 +140,8 @@
    int vbandlength;		/* compressed band length; 0 is uncompressed */
    char vsnapshot;		/* snapshot mode */
    char vsync;			/* used by isoc handler */
-   
+   char vmirror;		/* for ToUCaM series */
+
    /* The image acquisition requires 3 to 4 steps:
       1. data is gathered in short packets from the USB controller
       2. data is synchronized and packed into a frame buffer
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/rtl8150.c linux-2.4.21-pre6/drivers/usb/rtl8150.c
--- linux-2.4.20/drivers/usb/rtl8150.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/rtl8150.c	2003-03-26 23:49:31.000000000 +0000
@@ -21,11 +21,11 @@
 #include <asm/uaccess.h>
 
 /* Version Information */
-#define DRIVER_VERSION "v0.4.1 (2002/07/22)"
+#define DRIVER_VERSION "v0.4.3 (2002/12/31)"
 #define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
 #define DRIVER_DESC "rtl8150 based usb-ethernet driver"
 
-#define	IRD			0x0120
+#define	IDR			0x0120
 #define	MAR			0x0126
 #define	CR			0x012e
 #define	TCR			0x012f
@@ -45,6 +45,8 @@
 #define	ANLP			0x0146
 #define	AER			0x0148
 
+#define	IDR_EEPROM		0x1202
+
 #define	PHY_READ		0
 #define	PHY_WRITE		0x20
 #define	PHY_GO			0x40
@@ -71,6 +73,8 @@
 #define PRODUCT_ID_RTL8150		0x8150
 #define	PRODUCT_ID_LUAKTX		0x0012
 
+#undef EEPROM_WRITE
+
 /* table of devices that work with this driver */
 static struct usb_device_id rtl8150_table[] = {
 	{USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8150)},
@@ -225,10 +229,51 @@
 {
 	u8 node_id[6];
 
-	get_registers(dev, IRD, sizeof(node_id), node_id);
+	get_registers(dev, IDR, sizeof(node_id), node_id);
 	memcpy(dev->netdev->dev_addr, node_id, sizeof(node_id));
 }
 
+static int rtl8150_set_mac_address(struct net_device *netdev, void *p)
+{
+	struct sockaddr *addr = p;
+	rtl8150_t *dev;
+	int i;
+
+	if (netif_running(netdev))
+		return -EBUSY;
+	dev = netdev->priv;
+	if (dev == NULL) {
+		return -ENODEV;
+	}
+	memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+	dbg("%s: Setting MAC address to ", netdev->name);
+	for (i = 0; i < 5; i++)
+		printk("%02X:", netdev->dev_addr[i]);
+	dbg("%02X\n", netdev->dev_addr[i]);
+	/* Set the IDR registers. */
+	set_registers(dev, IDR, sizeof(netdev->dev_addr), netdev->dev_addr);
+#ifdef EEPROM_WRITE
+	{
+	u8 cr;
+	/* Get the CR contents. */
+	get_registers(dev, CR, 1, &cr);
+	/* Set the WEPROM bit (eeprom write enable). */
+	cr |= 0x20;
+	set_registers(dev, CR, 1, &cr);
+	/* Write the MAC address into eeprom. Eeprom writes must be word-sized,
+	   so we need to split them up. */
+	for (i = 0; i * 2 < netdev->addr_len; i++) {
+		set_registers(dev, IDR_EEPROM + (i * 2), 2, 
+		              netdev->dev_addr + (i * 2));
+	}
+	/* Clear the WEPROM bit (preventing accidental eeprom writes). */
+	cr &= 0xdf;
+	set_registers(dev, CR, 1, &cr);
+	}
+#endif	
+	return 0;
+}
+
 static int rtl8150_reset(rtl8150_t * dev)
 {
 	u8 data = 0x10;
@@ -309,7 +354,7 @@
 	case -ENOENT:
 		return;
 	case -ETIMEDOUT:
-		warn("reset needed may be?..");
+		warn("need a device reset?..");
 		goto goon;
 	default:
 		warn("Rx status %d", urb->status);
@@ -452,7 +497,7 @@
 	count = (count & 0x3f) ? count : count + 1;
 	memcpy(dev->tx_buff, skb->data, skb->len);
 	FILL_BULK_URB(dev->tx_urb, dev->udev, usb_sndbulkpipe(dev->udev, 2),
-		      dev->tx_buff, RTL8150_MAX_MTU, write_bulk_callback, dev);
+		      dev->tx_buff, count, write_bulk_callback, dev);
 	dev->tx_urb->transfer_buffer_length = count;
 
 	if ((res = usb_submit_urb(dev->tx_urb))) {
@@ -480,6 +525,9 @@
 	}
 
 	down(&dev->sem);
+
+	set_registers(dev, IDR, 6, netdev->dev_addr);
+	
 	FILL_BULK_URB(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
 		      dev->rx_buff, RTL8150_MAX_MTU, read_bulk_callback, dev);
 	if ((res = usb_submit_urb(dev->rx_urb)))
@@ -666,6 +714,7 @@
 	netdev->tx_timeout = rtl8150_tx_timeout;
 	netdev->hard_start_xmit = rtl8150_start_xmit;
 	netdev->set_multicast_list = rtl8150_set_multicast;
+	netdev->set_mac_address = rtl8150_set_mac_address;
 	netdev->get_stats = rtl8150_netdev_stats;
 	netdev->mtu = RTL8150_MTU;
 	dev->intr_interval = 100;	/* 100ms */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/scanner.c linux-2.4.21-pre6/drivers/usb/scanner.c
--- linux-2.4.20/drivers/usb/scanner.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/scanner.c	2003-03-26 23:49:20.000000000 +0000
@@ -1,13 +1,16 @@
 /* -*- linux-c -*- */
 
 /* 
- * Driver for USB Scanners (linux-2.4.18)
+ * Driver for USB Scanners (linux-2.4.21)
  *
  * Copyright (C) 1999, 2000, 2001, 2002 David E. Nelson
+ * Copyright (C) 2002, 2003 Henning Meier-Geinitz
  *
  * Portions may be copyright Brad Keryan and Michael Gee.
  *
- * Brian Beattie <beattie@beattie-home.net>
+ * Previously maintained by Brian Beattie
+ *
+ * Current maintainer: Henning Meier-Geinitz <henning@meier-geinitz.de>
  * 
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -311,12 +314,52 @@
  *    - Changed maintainership from David E. Nelson to Brian
  *      Beattie <beattie@beattie-home.net>.
  *
+ * 0.4.9  12/19/2002
+ *    - Added vendor/product ids for Nikon, Mustek, Plustek, Genius, Epson,
+ *      Canon, Umax, Hewlett-Packard, Benq, Agfa, Minolta scanners.
+ *      Thanks to Dieter Faulbaum <faulbaum@mail.bessy.de>, Stian Jordet
+ *      <liste@jordet.nu>, "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>,
+ *      "Jaeger, Gerhard" <gerhard@gjaeger.de>, Ira Childress 
+ *      <ichildress@mn.rr.com>, Till Kamppeter <till.kamppeter@gmx.net>,
+ *      Ed Hamrick <EdHamrick@aol.com>, Oliver Schwartz
+ *      <Oliver.Schwartz@gmx.de> and everyone else who sent ids.
+ *    - Some Benq, Genius and Plustek ids are identified now.
+ *    - Don't clutter syslog with "Unable to access minor data" messages.
+ *    - Accept scanners with only one bulk (in) endpoint (thanks to Sergey
+ *      Vlasov <vsu@mivlgu.murom.ru>).
+ *    - Accept devices with more than one interface. Only use interfaces that
+ *      look like belonging to scanners.
+ *    - Use altsetting[0], not altsetting[ifnum].
+ *    - Add locking to ioctl_scanner(). Thanks to Oliver Neukum
+ *      <oliver@neukum.name>.
+ *
+ * 0.4.10  01/07/2003
+ *    - Added vendor/product ids for Artec, Canon, Compaq, Epson, HP, Microtek 
+ *      and Visioneer scanners. Thanks to William Lam <wklam@triad.rr.com>,
+ *      Till Kamppeter <till.kamppeter@gmx.net> and others for all the ids.
+ *    - Cleaned up list of vendor/product ids.
+ *    - Print ids and device number when a device was detected.
+ *    - Don't print errors when the device is busy.
+ *    - Added vendor/product ids for Visioneer scanners.
+ *    - Print information about user-supplied ids only once at startup instead
+ *      of everytime any USB device is plugged in.
+ *    - Removed PV8630 ioctls. Use the standard ioctls instead.
+ *    - Made endpoint detection more generic. Basically, only one bulk-in 
+ *      endpoint is required, everything else is optional.
+ *    - Move the scanner ioctls to usb_scanner_ioctl.h to allow access by archs
+ *      that need it (by Greg KH).
+ *    - New maintainer: Henning Meier-Geinitz.
+ *    - Print ids and device number when a device was detected.
+ *    - Don't print errors when the device is busy.
+ *      
+ * 0.4.11  2003-02-25
+ *    - Added vendor/product ids for Artec, Avision, Brother, Medion, Primax,
+ *      Prolink, Fujitsu, Plustek, and SYSCAN scanners.
+ *
  * TODO
- *    - Remove the 2/3 endpoint limitation
  *    - Performance
  *    - Select/poll methods
  *    - More testing
- *    - Proper registry/assignment for LM9830 ioctl's
  *    - More general usage ioctl's
  *
  *
@@ -334,7 +377,7 @@
  *    - All the developers that are working on USB SANE backends or other
  *      applications to use USB scanners.
  *    - Thanks to Greg KH <greg@kroah.com> for setting up Brian Beattie
- *      to be the new USB Scanner maintainer.
+ *      and Henning Meier-Geinitz to be the new USB Scanner maintainer.
  *
  *  Performance:
  *
@@ -343,6 +386,14 @@
  *      24 Bit Color ~ 70 secs - 3.6 Mbit/sec
  *       8 Bit Gray ~ 17 secs - 4.2 Mbit/sec */
 
+/*
+ * For documentation, see Documentation/usb/scanner.txt.
+ * Website: http://www.meier-geinitz.de/kernel/
+ * Please contact the maintainer if your scanner is not detected by this
+ * driver automatically.
+ */
+
+
 /* 
  * Scanner definitions, macros, module info, 
  * debug/ioctl/data_dump enable, and other constants.
@@ -384,8 +435,6 @@
 
 	int err=0;
 
-	MOD_INC_USE_COUNT;
-
 	down(&scn_mutex);
 
 	scn_minor = USB_SCN_MINOR(inode);
@@ -394,8 +443,7 @@
 
 	if (!p_scn_table[scn_minor]) {
 		up(&scn_mutex);
-		MOD_DEC_USE_COUNT;
-		err("open_scanner(%d): Unable to access minor data", scn_minor);
+		dbg("open_scanner(%d): Unable to access minor data", scn_minor);
 		return -ENODEV;
 	}
 
@@ -403,7 +451,7 @@
 
 	dev = scn->scn_dev;
 
-	down(&(scn->sem));	/* Now protect the scn_usb_data structure */ 
+	down(&(scn->sem));	/* Now protect the scn_usb_data structure */
 
 	up(&scn_mutex); /* Now handled by the above */
 
@@ -420,7 +468,7 @@
 	}
 
 	if (scn->isopen) {
-		err("open_scanner(%d): Scanner device is already open", scn_minor);
+		dbg("open_scanner(%d): Scanner device is already open", scn_minor);
 		err = -EBUSY;
 		goto out_error;
 	}
@@ -436,9 +484,6 @@
 
 	up(&(scn->sem)); /* Wake up any possible contending processes */
 
-	if (err)
-		MOD_DEC_USE_COUNT;
-
 	return err;
 }
 
@@ -469,8 +514,6 @@
 	up(&scn_mutex);
 	up(&(scn->sem));
 
-	MOD_DEC_USE_COUNT;
-
 	return 0;
 }
 
@@ -496,6 +539,12 @@
 
 	down(&(scn->sem));
 
+	if (!scn->bulk_out_ep) {
+		/* This scanner does not have a bulk-out endpoint */
+		up(&(scn->sem));
+		return -EINVAL;
+	}
+
 	scn_minor = scn->scn_minor;
 
 	obuf = scn->obuf;
@@ -636,7 +685,7 @@
 				goto data_recvd;
 			}
 		}
-		
+
 		if (result == -EPIPE) { /* No hope */
 			if(usb_clear_halt(dev, scn->bulk_in_ep)) {
 				err("read_scanner(%d): Failure to clear endpoint halt condition (%Zd).", scn_minor, ret);
@@ -684,81 +733,23 @@
 ioctl_scanner(struct inode *inode, struct file *file,
 	      unsigned int cmd, unsigned long arg)
 {
+	struct scn_usb_data *scn;
 	struct usb_device *dev;
+	int retval = -ENOTTY;
 
-	kdev_t scn_minor;
-
-	scn_minor = USB_SCN_MINOR(inode);
-
-	if (!p_scn_table[scn_minor]) {
-		err("ioctl_scanner(%d): invalid scn_minor", scn_minor);
-		return -ENODEV;
-	}
+	scn = file->private_data;
+	down(&(scn->sem));
 
-	dev = p_scn_table[scn_minor]->scn_dev;
+	dev = scn->scn_dev;
 
 	switch (cmd)
 	{
 	case SCANNER_IOCTL_VENDOR :
-		return (put_user(dev->descriptor.idVendor, (unsigned int *) arg));
+		retval = (put_user(dev->descriptor.idVendor, (unsigned int *) arg));
+		break;
 	case SCANNER_IOCTL_PRODUCT :
-		return (put_user(dev->descriptor.idProduct, (unsigned int *) arg));
-#ifdef PV8630
-	case PV8630_IOCTL_INREQUEST :
-	{
-		int result;
-
-		struct {
-			__u8  data;
-			__u8  request;
-			__u16 value;
-			__u16 index;
-		} args;
-
-		if (copy_from_user(&args, (void *)arg, sizeof(args)))
-			return -EFAULT;
-
-		result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-					 args.request, USB_TYPE_VENDOR|
-					 USB_RECIP_DEVICE|USB_DIR_IN,
-					 args.value, args.index, &args.data,
-					 1, HZ*5);
-
-		dbg("ioctl_scanner(%d): inreq: args.data:%x args.value:%x args.index:%x args.request:%x\n", scn_minor, args.data, args.value, args.index, args.request);
-
-		if (copy_to_user((void *)arg, &args, sizeof(args)))
-			return -EFAULT;
-
-		dbg("ioctl_scanner(%d): inreq: result:%d\n", scn_minor, result);
-
-		return result;
-	}
-	case PV8630_IOCTL_OUTREQUEST :
-	{
-		int result;
-
-		struct {
-			__u8  request;
-			__u16 value;
-			__u16 index;
-		} args;
-
-		if (copy_from_user(&args, (void *)arg, sizeof(args)))
-			return -EFAULT;
-
-		dbg("ioctl_scanner(%d): outreq: args.value:%x args.index:%x args.request:%x\n", scn_minor, args.value, args.index, args.request);
-
-		result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-					 args.request, USB_TYPE_VENDOR|
-					 USB_RECIP_DEVICE|USB_DIR_OUT,
-					 args.value, args.index, NULL,
-					 0, HZ*5);
-
-		dbg("ioctl_scanner(%d): outreq: result:%d\n", scn_minor, result);
-
-		return result;
-	}
-#endif /* PV8630 */
+		retval = (put_user(dev->descriptor.idProduct, (unsigned int *) arg));
+		break;
  	case SCANNER_IOCTL_CTRLMSG:
  	{
  		struct ctrlmsg_ioctl {
@@ -767,19 +758,26 @@
  		} cmsg;
  		int pipe, nb, ret;
  		unsigned char buf[64];
- 
- 		if (copy_from_user(&cmsg, (void *)arg, sizeof(cmsg)))
- 			return -EFAULT;
+		retval = 0;
+
+ 		if (copy_from_user(&cmsg, (void *)arg, sizeof(cmsg))) {
+ 			retval = -EFAULT;
+			break;
+		}
 
  		nb = cmsg.req.wLength;
 
- 		if (nb > sizeof(buf))
- 			return -EINVAL;
+ 		if (nb > sizeof(buf)) {
+ 			retval = -EINVAL;
+			break;
+		}
 
  		if ((cmsg.req.bRequestType & 0x80) == 0) {
  			pipe = usb_sndctrlpipe(dev, 0);
- 			if (nb > 0 && copy_from_user(buf, cmsg.data, nb))
- 				return -EFAULT;
+ 			if (nb > 0 && copy_from_user(buf, cmsg.data, nb)) {
+ 				retval = -EFAULT;
+				break;
+			}
  		} else {
  			pipe = usb_rcvctrlpipe(dev, 0);
 		}
@@ -791,23 +789,26 @@
  				      buf, nb, HZ);
 
  		if (ret < 0) {
- 			err("ioctl_scanner(%d): control_msg returned %d\n", scn_minor, ret);
- 			return -EIO;
+ 			err("ioctl_scanner: control_msg returned %d\n", ret);
+ 			retval = -EIO;
+			break;
  		}
 
  		if (nb > 0 && (cmsg.req.bRequestType & 0x80) && copy_to_user(cmsg.data, buf, nb))
- 			return -EFAULT;
+ 			retval = -EFAULT;
 
- 		return 0;
+ 		break;
  	}
 	default:
-		return -ENOTTY;
+		break;
 	}
-	return 0;
+	up(&(scn->sem));
+	return retval;
 }
 
 static struct
 file_operations usb_scanner_fops = {
+	owner:		THIS_MODULE,
 	read:		read_scanner,
 	write:		write_scanner,
 	ioctl:		ioctl_scanner,
@@ -832,10 +833,6 @@
 	char have_bulk_in, have_bulk_out, have_intr;
 	char name[10];
 
-	if (vendor != -1 && product != -1) {
-		info("probe_scanner: User specified USB scanner -- Vendor:Product - %x:%x", vendor, product);
-	}
-
 	dbg("probe_scanner: USB dev address:%p", dev);
 	dbg("probe_scanner: ifnum:%u", ifnum);
 
@@ -886,47 +883,57 @@
 		return NULL;
 	}
 
-	if (dev->config[0].bNumInterfaces != 1) {
-		info("probe_scanner: Only one device interface is supported.");
+	interface = dev->config[0].interface[ifnum].altsetting;
+
+	if (interface[0].bInterfaceClass != USB_CLASS_VENDOR_SPEC &&
+	    interface[0].bInterfaceClass != USB_CLASS_PER_INTERFACE &&
+	    interface[0].bInterfaceClass != SCN_CLASS_SCANJET) {
+		dbg("probe_scanner: This interface doesn't look like a scanner (class=0x%x).", interface[0].bInterfaceClass);
 		return NULL;
 	}
 
-	interface = dev->config[0].interface[ifnum].altsetting;
-	endpoint = interface[ifnum].endpoint;
+	endpoint = interface[0].endpoint;
 
 /*
- * Start checking for two bulk endpoints OR two bulk endpoints *and* one
- * interrupt endpoint. If we have an interrupt endpoint go ahead and
+ * Start checking for bulk and interrupt endpoints. We are only using the first
+ * one of each type of endpoint. If we have an interrupt endpoint go ahead and
  * setup the handler. FIXME: This is a future enhancement...
  */
 
 	dbg("probe_scanner: Number of Endpoints:%d", (int) interface->bNumEndpoints);
 
-	if ((interface->bNumEndpoints != 2) && (interface->bNumEndpoints != 3)) {
-		info("probe_scanner: Only two or three endpoints supported.");
-		return NULL;
-	}
-
 	ep_cnt = have_bulk_in = have_bulk_out = have_intr = 0;
 
 	while (ep_cnt < interface->bNumEndpoints) {
 
-		if (!have_bulk_in && IS_EP_BULK_IN(endpoint[ep_cnt])) {
+		if (IS_EP_BULK_IN(endpoint[ep_cnt])) {
 			ep_cnt++;
+			if (have_bulk_in) {
+				info ("probe_scanner: ignoring additional bulk_in_ep:%d", ep_cnt);
+				continue;
+			}
 			have_bulk_in = ep_cnt;
 			dbg("probe_scanner: bulk_in_ep:%d", have_bulk_in);
 			continue;
 		}
 
-		if (!have_bulk_out && IS_EP_BULK_OUT(endpoint[ep_cnt])) {
+		if (IS_EP_BULK_OUT(endpoint[ep_cnt])) {
 			ep_cnt++;
+			if (have_bulk_out) {
+				info ("probe_scanner: ignoring additional bulk_out_ep:%d", ep_cnt);
+				continue;
+			}
 			have_bulk_out = ep_cnt;
 			dbg("probe_scanner: bulk_out_ep:%d", have_bulk_out);
 			continue;
 		}
 
-		if (!have_intr && IS_EP_INTR(endpoint[ep_cnt])) {
+		if (IS_EP_INTR(endpoint[ep_cnt])) {
 			ep_cnt++;
+			if (have_intr) {
+				info ("probe_scanner: ignoring additional intr_ep:%d", ep_cnt);
+				continue;
+			}
 			have_intr = ep_cnt;
 			dbg("probe_scanner: intr_ep:%d", have_intr);
 			continue;
@@ -940,22 +947,8 @@
  * Perform a quick check to make sure that everything worked as it
  * should have.
  */
-
-	switch(interface->bNumEndpoints) {
-	case 2:
-		if (!have_bulk_in || !have_bulk_out) {
-			info("probe_scanner: Two bulk endpoints required.");
-			return NULL;
-		}
-		break;
-	case 3:
-		if (!have_bulk_in || !have_bulk_out || !have_intr) {
-			info("probe_scanner: Two bulk endpoints and one interrupt endpoint required.");
-			return NULL;
-		}
-		break;
-	default:
-		info("probe_scanner: Endpoint determination failed --  consult Documentation/usb/scanner.txt");
+	if (!have_bulk_in) {
+		err("probe_scanner: One bulk-in endpoint required.");
 		return NULL;
 	}
 
@@ -1036,7 +1029,6 @@
 		break;
 	case 0x055f:		/* Mustek */
 	case 0x0400:		/* Another Mustek */
-	case 0x0ff5:		/* And yet another Mustek */
 		scn->rd_nak_timeout = HZ * 1;
 	default:
 		scn->rd_nak_timeout = RD_NAK_TIMEOUT;
@@ -1067,6 +1059,8 @@
 	if (scn->devfs == NULL)
 		dbg("scanner%d: device node registration failed", scn_minor);
 
+	info ("USB scanner device (0x%04x/0x%04x) now attached to %s",
+	      dev->descriptor.idVendor, dev->descriptor.idProduct, name);
 	p_scn_table[scn_minor] = scn;
 
 	up(&scn_mutex);
@@ -1125,6 +1119,8 @@
                 return -1;
 
 	info(DRIVER_VERSION ":" DRIVER_DESC);
+	if (vendor != -1 && product != -1)
+		info("probe_scanner: User specified USB scanner -- Vendor:Product - %x:%x", vendor, product);
 	return 0;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/scanner.h linux-2.4.21-pre6/drivers/usb/scanner.h
--- linux-2.4.20/drivers/usb/scanner.h	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/scanner.h	2003-03-26 23:49:30.000000000 +0000
@@ -1,9 +1,10 @@
 /*
- * Driver for USB Scanners (linux-2.4.18)
+ * Driver for USB Scanners (linux-2.4.21)
  *
  * Copyright (C) 1999, 2000, 2001, 2002 David E. Nelson
+ * Previously maintained by Brian Beattie
  *
- * Brian Beattie <beattie@beattie-home.net>
+ * Current maintainer: Henning Meier-Geinitz <henning@meier-geinitz.de>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -21,6 +22,13 @@
  *
  */ 
 
+/*
+ * For documentation, see Documentation/usb/scanner.txt.
+ * Website: http://www.meier-geinitz.de/kernel/
+ * Please contact the maintainer if your scanner is not detected by this
+ * driver automatically.
+ */
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
@@ -32,23 +40,18 @@
 #include <linux/sched.h>
 #include <linux/smp_lock.h>
 #include <linux/devfs_fs_kernel.h>
+#include <linux/usb_scanner_ioctl.h>
 
 // #define DEBUG
 
-/* Enable this to support the older ioctl interfaces scanners that
- * a PV8630 Scanner-On-Chip.  The prefered method is the
- * SCANNER_IOCTL_CTRLMSG ioctl.
- */
-// #define PV8630 
-
-#define DRIVER_VERSION "0.4.6"
+#define DRIVER_VERSION "0.4.11"
 #define DRIVER_DESC "USB Scanner Driver"
 
 #include <linux/usb.h>
 
 static __s32 vendor=-1, product=-1, read_timeout=0;
 
-MODULE_AUTHOR("Brian Beattie, beattie@beattie-home.net");
+MODULE_AUTHOR("Henning Meier-Geinitz, henning@meier-geinitz.de");
 MODULE_DESCRIPTION(DRIVER_DESC" "DRIVER_VERSION);
 MODULE_LICENSE("GPL");
 
@@ -67,65 +70,103 @@
 // #define WR_DATA_DUMP /* DEBUG does not have to be defined. */
 
 static struct usb_device_id scanner_device_ids [] = {
-	/* Acer */
-	{ USB_DEVICE(0x04a5, 0x2060) },	/* Prisa Acerscan 620U & 640U (!)*/
-	{ USB_DEVICE(0x04a5, 0x2040) },	/* Prisa AcerScan 620U (!) */
-	{ USB_DEVICE(0x04a5, 0x20c0) },  /* Prisa AcerScan 1240UT */
-	{ USB_DEVICE(0x04a5, 0x2022) },	/* Vuego Scan Brisa 340U */
+	/* Acer (now Benq) */
 	{ USB_DEVICE(0x04a5, 0x1a20) },	/* Unknown - Oliver Schwartz */
-	{ USB_DEVICE(0x04a5, 0x1a2a) },	/* Unknown - Oliver Schwartz */
-	{ USB_DEVICE(0x04a5, 0x207e) },	/* Prisa 640BU */
+	{ USB_DEVICE(0x04a5, 0x1a2a) },	/* Another 620U */
+	{ USB_DEVICE(0x04a5, 0x2022) },	/* 340U */
+	{ USB_DEVICE(0x04a5, 0x2040) },	/* 620U (!) */
+	{ USB_DEVICE(0x04a5, 0x2060) },	/* 620U & 640U (!)*/
+	{ USB_DEVICE(0x04a5, 0x207e) },	/* 640BU */
+	{ USB_DEVICE(0x04a5, 0x20b0) },	/* Benq 4300 */
 	{ USB_DEVICE(0x04a5, 0x20be) },	/* Unknown - Oliver Schwartz */
-	{ USB_DEVICE(0x04a5, 0x20c0) },	/* Unknown - Oliver Schwartz */
+	{ USB_DEVICE(0x04a5, 0x20c0) }, /* 1240UT, 1240U */
 	{ USB_DEVICE(0x04a5, 0x20de) },	/* S2W 3300U */
-	{ USB_DEVICE(0x04a5, 0x20b0) },	/* Unknown - Oliver Schwartz */
-	{ USB_DEVICE(0x04a5, 0x20fe) },	/* Unknown - Oliver Schwartz */
+	{ USB_DEVICE(0x04a5, 0x20fc) }, /* Benq 5000 */
+	{ USB_DEVICE(0x04a5, 0x20fe) },	/* Benq 5300 */
 	/* Agfa */
 	{ USB_DEVICE(0x06bd, 0x0001) },	/* SnapScan 1212U */
 	{ USB_DEVICE(0x06bd, 0x0002) },	/* SnapScan 1236U */
-	{ USB_DEVICE(0x06bd, 0x2061) },	/* Another SnapScan 1212U (?)*/
 	{ USB_DEVICE(0x06bd, 0x0100) },	/* SnapScan Touch */
+	{ USB_DEVICE(0x06bd, 0x2061) },	/* Another SnapScan 1212U (?)*/
+	{ USB_DEVICE(0x06bd, 0x208d) }, /* Snapscan e40 */
+	{ USB_DEVICE(0x06bd, 0x208f) }, /* SnapScan e50*/
 	{ USB_DEVICE(0x06bd, 0x2091) }, /* SnapScan e20 */
+	{ USB_DEVICE(0x06bd, 0x2093) }, /* SnapScan e10*/
 	{ USB_DEVICE(0x06bd, 0x2095) }, /* SnapScan e25 */
 	{ USB_DEVICE(0x06bd, 0x2097) }, /* SnapScan e26 */
-	{ USB_DEVICE(0x06bd, 0x208d) }, /* Snapscan e40 */
+	{ USB_DEVICE(0x06bd, 0x20fd) }, /* SnapScan e52*/
+	{ USB_DEVICE(0x06bd, 0x20ff) }, /* SnapScan e42*/
+	/* Artec */
+	{ USB_DEVICE(0x05d8, 0x4001) },	/* Ultima 2000 */
+	{ USB_DEVICE(0x05d8, 0x4002) }, /* Ultima 2000 (GT6801 based) */
+	{ USB_DEVICE(0x05d8, 0x4003) }, /* E+ 48U */
+	{ USB_DEVICE(0x05d8, 0x4004) }, /* E+ Pro */
+	/* Avision */
+	{ USB_DEVICE(0x0638, 0x0a10) },	/* iVina FB1600 (=Umax Astra 4500) */
+	/* Benq: see Acer */
+	/* Brother */
+	{ USB_DEVICE(0x04f9, 0x0111) },	/* MFC 6800 */
 	/* Canon */
+	{ USB_DEVICE(0x04a9, 0x2201) }, /* CanoScan FB320U */
 	{ USB_DEVICE(0x04a9, 0x2202) }, /* CanoScan FB620U */
 	{ USB_DEVICE(0x04a9, 0x2204) }, /* CanoScan FB630U/FB636U */
+	{ USB_DEVICE(0x04a9, 0x2205) }, /* CanoScan FB1210U */
 	{ USB_DEVICE(0x04a9, 0x2206) }, /* CanoScan N650U/N656U */
 	{ USB_DEVICE(0x04a9, 0x2207) }, /* CanoScan N1220U */
 	{ USB_DEVICE(0x04a9, 0x2208) }, /* CanoScan D660U */ 
-	{ USB_DEVICE(0x04a9, 0x220b) }, /* D646U */
+	{ USB_DEVICE(0x04a9, 0x220b) }, /* CanoScan D646U */
+	{ USB_DEVICE(0x04a9, 0x220c) },	/* CanoScan D1250U2 */
+	{ USB_DEVICE(0x04a9, 0x220d) }, /* CanoScan N670U/N676U/LIDE 20 */
+	{ USB_DEVICE(0x04a9, 0x220e) }, /* CanoScan N1240U/LIDE 30 */
+	{ USB_DEVICE(0x04a9, 0x3042) }, /* FS4000US */
 	/* Colorado -- See Primax/Colorado below */
+	/* Compaq */
+	{ USB_DEVICE(0x049f, 0x0021) },	/* S200 */
 	/* Epson -- See Seiko/Epson below */
+	/* Fujitsu */
+	{ USB_DEVICE(0x04c5, 0x1041) }, /* fi-4220c USB/SCSI info:mza@mu-tec.de */
+	{ USB_DEVICE(0x04c5, 0x1042) }, /* fi-4120c USB/SCSI info:mza@mu-tec.de */
+	{ USB_DEVICE(0x04c5, 0x1029) }, /* fi-4010c USB AVision info:mza@mu-tec.de */
 	/* Genius */
-	{ USB_DEVICE(0x0458, 0x2001) },	/* ColorPage-Vivid Pro */
+	{ USB_DEVICE(0x0458, 0x2001) },	/* ColorPage Vivid Pro */
 	{ USB_DEVICE(0x0458, 0x2007) },	/* ColorPage HR6 V2 */
-	{ USB_DEVICE(0x0458, 0x2008) },	/* Unknown */
-	{ USB_DEVICE(0x0458, 0x2009) },	/* Unknown */
-	{ USB_DEVICE(0x0458, 0x2013) },	/* Unknown */
-	{ USB_DEVICE(0x0458, 0x2015) },	/* Unknown  */
-	{ USB_DEVICE(0x0458, 0x2016) },	/* Unknown  */
+	{ USB_DEVICE(0x0458, 0x2008) }, /* ColorPage HR6 V2 */
+	{ USB_DEVICE(0x0458, 0x2009) }, /* ColorPage HR6A */
+	{ USB_DEVICE(0x0458, 0x2011) }, /* ColorPage Vivid3x */
+	{ USB_DEVICE(0x0458, 0x2013) }, /* ColorPage HR7 */
+	{ USB_DEVICE(0x0458, 0x2015) }, /* ColorPage HR7LE */
+	{ USB_DEVICE(0x0458, 0x2016) }, /* ColorPage HR6X */
 	/* Hewlett Packard */
-	{ USB_DEVICE(0x03f0, 0x0205) },	/* 3300C */
-	{ USB_DEVICE(0x03f0, 0x0405) }, /* 3400C */
-	{ USB_DEVICE(0x03f0, 0x0101) },	/* 4100C */
-	{ USB_DEVICE(0x03f0, 0x0105) },	/* 4200C */
-	{ USB_DEVICE(0x03f0, 0x0305) }, /* 4300C */
+	{ USB_DEVICE(0x03f0, 0x0101) },	/* ScanJet 4100C */
 	{ USB_DEVICE(0x03f0, 0x0102) },	/* PhotoSmart S20 */
-	{ USB_DEVICE(0x03f0, 0x0705) }, /* 4400C */
-	{ USB_DEVICE(0x03f0, 0x0401) },	/* 5200C */
-	//	{ USB_DEVICE(0x03f0, 0x0701) },	/* 5300C - NOT SUPPORTED - see http://www.neatech.nl/oss/HP5300C/ */
-	{ USB_DEVICE(0x03f0, 0x0201) },	/* 6200C */
-	{ USB_DEVICE(0x03f0, 0x0601) },	/* 6300C */
-	{ USB_DEVICE(0x03f0, 0x605) },	/* 2200C */
+	{ USB_DEVICE(0x03f0, 0x0105) },	/* ScanJet 4200C */
+	{ USB_DEVICE(0x03f0, 0x0201) },	/* ScanJet 6200C */
+	{ USB_DEVICE(0x03f0, 0x0205) },	/* ScanJet 3300C */
+	{ USB_DEVICE(0x03f0, 0x0305) }, /* ScanJet 4300C */
+	{ USB_DEVICE(0x03f0, 0x0401) },	/* ScanJet 5200C */
+	{ USB_DEVICE(0x03f0, 0x0405) }, /* ScanJet 3400C */
+	{ USB_DEVICE(0x03f0, 0x0505) }, /* ScanJet 2100C */
+	{ USB_DEVICE(0x03f0, 0x0601) },	/* ScanJet 6300C */
+	{ USB_DEVICE(0x03f0, 0x0605) },	/* ScanJet 2200C */
+	//	{ USB_DEVICE(0x03f0, 0x0701) },	/* ScanJet 5300C - NOT SUPPORTED - use hpusbscsi driver */
+	{ USB_DEVICE(0x03f0, 0x0705) }, /* ScanJet 4400C */
+	//	{ USB_DEVICE(0x03f0, 0x0801) },	/* ScanJet 7400C - NOT SUPPORTED - use hpusbscsi driver */
+	{ USB_DEVICE(0x03f0, 0x0901) }, /* ScanJet 2300C */
+	{ USB_DEVICE(0x03f0, 0x1305) },	/* Scanjet 4570c */
+	{ USB_DEVICE(0x03f0, 0x2005) },	/* ScanJet 3570c */
+	{ USB_DEVICE(0x03f0, 0x2205) },	/* ScanJet 3500c */
 	/* iVina */
 	{ USB_DEVICE(0x0638, 0x0268) }, /* 1200U */
-	/* Lifetec */
-	{ USB_DEVICE(0x05d8, 0x4002) }, /* Lifetec LT9385 */
+	/* Lexmark */
+	{ USB_DEVICE(0x043d, 0x002d) }, /* X70/X73 */
+	/* Medion */
+	{ USB_DEVICE(0x0461, 0x0377) },	/* MD 5345 - repackaged Primax? */
 	/* Memorex */
 	{ USB_DEVICE(0x0461, 0x0346) }, /* 6136u - repackaged Primax ? */
-	/* Microtek -- No longer supported - Enable SCSI and USB Microtek in kernel config */
+	/* Microtek */
+	{ USB_DEVICE(0x05da, 0x30ce) },	/* ScanMaker 3800 */
+	/* The following SCSI-over-USB Microtek devices are supported by the
+	   microtek driver: Enable SCSI and USB Microtek in kernel config */
 	//	{ USB_DEVICE(0x05da, 0x0099) },	/* ScanMaker X6 - X6U */
 	//	{ USB_DEVICE(0x05da, 0x0094) },	/* Phantom 336CX - C3 */
 	//	{ USB_DEVICE(0x05da, 0x00a0) },	/* Phantom 336CX - C3 #2 */
@@ -134,53 +175,74 @@
 	//	{ USB_DEVICE(0x05da, 0x80a3) },	/* ScanMaker V6USL #2 */
 	//	{ USB_DEVICE(0x05da, 0x80ac) },	/* ScanMaker V6UL - SpicyU */
 	/* Minolta */
-	//	{ USB_DEVICE(0x0638,0x026a) }, /* Minolta Dimage Scan Dual II */
+	{ USB_DEVICE(0x0686, 0x400d) }, /* Scan Dual III */
+	/* The following SCSI-over-USB Minolta devices are supported by the
+	   hpusbscsi driver: Enable SCSI and USB hpusbscsi in kernel config */
+	//	{ USB_DEVICE(0x0638, 0x026a) }, /* Minolta Dimage Scan Dual II */
+	//	{ USB_DEVICE(0x0686, 0x4004) }, /* Scan Elite II (need interrupt ep) */
 	/* Mustek */
-	{ USB_DEVICE(0x055f, 0x0001) },	/* 1200 CU */
-	{ USB_DEVICE(0x0400, 0x1000) },	/* BearPaw 1200 */
-	{ USB_DEVICE(0x055f, 0x0002) },	/* 600 CU */
-	{ USB_DEVICE(0x055f, 0x0873) }, /* 600 USB */
-	{ USB_DEVICE(0x055f, 0x0003) },	/* 1200 USB */
-	{ USB_DEVICE(0x055f, 0x0006) },	/* 1200 UB */
-	{ USB_DEVICE(0x0400, 0x1001) }, /* BearPaw 2400 */
-	{ USB_DEVICE(0x055f, 0x0008) }, /* 1200 CU Plus */
-	{ USB_DEVICE(0x0ff5, 0x0010) }, /* BearPaw 1200F */
+	{ USB_DEVICE(0x0400, 0x1000) },	/* BearPaw 1200 (National Semiconductor LM9831) */
+	{ USB_DEVICE(0x0400, 0x1001) }, /* BearPaw 2400 (National Semiconductor LM9832) */
+	{ USB_DEVICE(0x055f, 0x0001) },	/* ScanExpress 1200 CU */
+	{ USB_DEVICE(0x055f, 0x0002) },	/* ScanExpress 600 CU */
+	{ USB_DEVICE(0x055f, 0x0003) },	/* ScanExpress 1200 USB */
+	{ USB_DEVICE(0x055f, 0x0006) },	/* ScanExpress 1200 UB */
+	{ USB_DEVICE(0x055f, 0x0007) },	/* ScanExpress 1200 USB Plus */
+	{ USB_DEVICE(0x055f, 0x0008) }, /* ScanExpress 1200 CU Plus */
+	{ USB_DEVICE(0x055f, 0x0010) }, /* BearPaw 1200F */
+	{ USB_DEVICE(0x055f, 0x0210) },	/* ScanExpress A3 USB */
 	{ USB_DEVICE(0x055f, 0x0218) }, /* BearPaw 2400 TA */
-	{ USB_DEVICE(0x05d8, 0x4002) }, /* 1200 CU and 1200 UB Plus */
+	{ USB_DEVICE(0x055f, 0x0219) }, /* BearPaw 2400 TA Plus */
+	{ USB_DEVICE(0x055f, 0x021c) }, /* BearPaw 1200 CU Plus */
+	{ USB_DEVICE(0x055f, 0x021d) }, /* Bearpaw 2400 CU Plus */
+	{ USB_DEVICE(0x055f, 0x021e) }, /* BearPaw 1200 TA/CS */
+	{ USB_DEVICE(0x055f, 0x0400) }, /* BearPaw 2400 TA PRO */
+	{ USB_DEVICE(0x055f, 0x0873) }, /* ScanExpress 600 USB */
+	{ USB_DEVICE(0x055f, 0x1000) }, /* BearPaw 4800 TA PRO */
+	//	{ USB_DEVICE(0x05d8, 0x4002) }, /* BearPaw 1200 CU and ScanExpress 1200 UB Plus (see Artec) */
+	/* Nikon */
+	{ USB_DEVICE(0x04b0, 0x4000) }, /* Coolscan LS 40 ED */
 	/* Plustek */
-	{ USB_DEVICE(0x07b3, 0x0017) }, /* OpticPro UT12 */
-	{ USB_DEVICE(0x07b3, 0x0011) }, /* OpticPro UT24 */
 	{ USB_DEVICE(0x07b3, 0x0005) }, /* Unknown */
 	{ USB_DEVICE(0x07b3, 0x0007) }, /* Unknown */
 	{ USB_DEVICE(0x07b3, 0x000F) }, /* Unknown */
-	{ USB_DEVICE(0x07b3, 0x0010) }, /* Unknown */
+	{ USB_DEVICE(0x07b3, 0x0010) }, /* OpticPro U12 */
+	{ USB_DEVICE(0x07b3, 0x0011) }, /* OpticPro U24 */
 	{ USB_DEVICE(0x07b3, 0x0012) }, /* Unknown */
 	{ USB_DEVICE(0x07b3, 0x0013) }, /* Unknown */
 	{ USB_DEVICE(0x07b3, 0x0014) }, /* Unknown */
-	{ USB_DEVICE(0x07b3, 0x0015) }, /* Unknown */
+	{ USB_DEVICE(0x07b3, 0x0015) }, /* OpticPro U24 */
 	{ USB_DEVICE(0x07b3, 0x0016) }, /* Unknown */
-	{ USB_DEVICE(0x07b3, 0x0012) }, /* Unknown */
+	{ USB_DEVICE(0x07b3, 0x0017) }, /* OpticPro UT12/UT16/UT24 */
+	{ USB_DEVICE(0x07b3, 0x0400) }, /* OpticPro 1248U */
+	{ USB_DEVICE(0x07b3, 0x0401) }, /* OpticPro 1248U (another one) */
 	/* Primax/Colorado */
 	{ USB_DEVICE(0x0461, 0x0300) },	/* G2-300 #1 */
-	{ USB_DEVICE(0x0461, 0x0380) },	/* G2-600 #1 */
 	{ USB_DEVICE(0x0461, 0x0301) },	/* G2E-300 #1 */
-	{ USB_DEVICE(0x0461, 0x0381) },	/* ReadyScan 636i */
 	{ USB_DEVICE(0x0461, 0x0302) },	/* G2-300 #2 */
-	{ USB_DEVICE(0x0461, 0x0382) },	/* G2-600 #2 */
 	{ USB_DEVICE(0x0461, 0x0303) },	/* G2E-300 #2 */
-	{ USB_DEVICE(0x0461, 0x0383) },	/* G2E-600 */
 	{ USB_DEVICE(0x0461, 0x0340) },	/* Colorado USB 9600 */
-	// { USB_DEVICE(0x0461, 0x0360) },	/* Colorado USB 19200 - undetected endpoint */
 	{ USB_DEVICE(0x0461, 0x0341) },	/* Colorado 600u */
+	{ USB_DEVICE(0x0461, 0x0347) },	/* Primascan Colorado 2600u */
+	{ USB_DEVICE(0x0461, 0x0360) },	/* Colorado USB 19200 */
 	{ USB_DEVICE(0x0461, 0x0361) },	/* Colorado 1200u */
+	{ USB_DEVICE(0x0461, 0x0380) },	/* G2-600 #1 */
+	{ USB_DEVICE(0x0461, 0x0381) },	/* ReadyScan 636i */
+	{ USB_DEVICE(0x0461, 0x0382) },	/* G2-600 #2 */
+	{ USB_DEVICE(0x0461, 0x0383) },	/* G2E-600 */
+	/* Prolink */
+	{ USB_DEVICE(0x06dc, 0x0014) }, /* Winscan Pro 2448U */
 	/* Relisis */
 	// { USB_DEVICE(0x0475, 0x0103) },	/* Episode - undetected endpoint */
 	/* Seiko/Epson Corp. */
 	{ USB_DEVICE(0x04b8, 0x0101) },	/* Perfection 636U and 636Photo */
+	{ USB_DEVICE(0x04b8, 0x0102) }, /* GT-2200 */
 	{ USB_DEVICE(0x04b8, 0x0103) },	/* Perfection 610 */
 	{ USB_DEVICE(0x04b8, 0x0104) },	/* Perfection 1200U and 1200Photo*/
+	{ USB_DEVICE(0x04b8, 0x0105) }, /* StylusScan 2000 */
 	{ USB_DEVICE(0x04b8, 0x0106) },	/* Stylus Scan 2500 */
 	{ USB_DEVICE(0x04b8, 0x0107) },	/* Expression 1600 */
+	{ USB_DEVICE(0x04b8, 0x0109) }, /* Expression 1640XL */
 	{ USB_DEVICE(0x04b8, 0x010a) }, /* Perfection 1640SU and 1640SU Photo */
 	{ USB_DEVICE(0x04b8, 0x010b) }, /* Perfection 1240U */
 	{ USB_DEVICE(0x04b8, 0x010c) }, /* Perfection 640U */
@@ -190,19 +252,29 @@
 	{ USB_DEVICE(0x04b8, 0x0112) }, /* Perfection 2450 - GT-9700 for the Japanese mkt */
 	{ USB_DEVICE(0x04b8, 0x0114) }, /* Perfection 660 */
 	{ USB_DEVICE(0x04b8, 0x011b) }, /* Perfection 2400 Photo */
+	{ USB_DEVICE(0x04b8, 0x011c) }, /* Perfection 3200 */
+	{ USB_DEVICE(0x04b8, 0x011d) }, /* Perfection 1260 */
 	{ USB_DEVICE(0x04b8, 0x011e) }, /* Perfection 1660 Photo */
+	{ USB_DEVICE(0x04b8, 0x0801) }, /* Stylus CX5200 */
+	{ USB_DEVICE(0x04b8, 0x0802) }, /* Stylus CX3200 */
+	/* SYSCAN */
+	{ USB_DEVICE(0x0a82, 0x4600) }, /* TravelScan 460/464 */
 	/* Umax */
 	{ USB_DEVICE(0x1606, 0x0010) },	/* Astra 1220U */
 	{ USB_DEVICE(0x1606, 0x0030) },	/* Astra 2000U */
+	{ USB_DEVICE(0x1606, 0x0060) }, /* Astra 3400U/3450U */
 	{ USB_DEVICE(0x1606, 0x0130) }, /* Astra 2100U */
+	{ USB_DEVICE(0x1606, 0x0160) }, /* Astra 5400U */  
 	{ USB_DEVICE(0x1606, 0x0230) },	/* Astra 2200U */
 	/* Visioneer */
-	{ USB_DEVICE(0x04a7, 0x0221) },	/* OneTouch 5300 USB */
 	{ USB_DEVICE(0x04a7, 0x0211) },	/* OneTouch 7600 USB */
+	{ USB_DEVICE(0x04a7, 0x0221) },	/* OneTouch 5300 USB */
 	{ USB_DEVICE(0x04a7, 0x0231) },	/* 6100 USB */
 	{ USB_DEVICE(0x04a7, 0x0311) },	/* 6200 EPP/USB */
 	{ USB_DEVICE(0x04a7, 0x0321) },	/* OneTouch 8100 EPP/USB */
 	{ USB_DEVICE(0x04a7, 0x0331) }, /* OneTouch 8600 EPP/USB */
+	{ USB_DEVICE(0x0461, 0x0345) }, /* 6200 (actually Primax?) */
+	{ USB_DEVICE(0x0461, 0x0371) }, /* Onetouch 8920 USB (actually Primax?) */
 	{ }				/* Terminating entry */
 };
 
@@ -229,19 +301,9 @@
 #define RD_EXPIRE 12		/* Number of attempts to wait X seconds */
 
 
-/* FIXME: These are NOT registered ioctls()'s */
-#ifdef PV8630
-#define PV8630_IOCTL_INREQUEST 69
-#define PV8630_IOCTL_OUTREQUEST 70
-#endif /* PV8630 */
-
-
-/* read vendor and product IDs from the scanner */
-#define SCANNER_IOCTL_VENDOR _IOR('U', 0x20, int)
-#define SCANNER_IOCTL_PRODUCT _IOR('U', 0x21, int)
-/* send/recv a control message to the scanner */
-#define SCANNER_IOCTL_CTRLMSG _IOWR('U', 0x22, struct usb_ctrlrequest )
-
+/* USB bInterfaceClass used by Hewlett-Packard ScanJet 3300c and Genius HR6
+   USB - Vivid III */
+#define SCN_CLASS_SCANJET 16
 
 #define SCN_MAX_MNR 16		/* We're allocated 16 minors */
 #define SCN_BASE_MNR 48		/* USB Scanners start at minor 48 */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/serial/Config.in linux-2.4.21-pre6/drivers/usb/serial/Config.in
--- linux-2.4.20/drivers/usb/serial/Config.in	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/serial/Config.in	2003-03-26 23:48:58.000000000 +0000
@@ -30,10 +30,13 @@
       bool '    USB Keyspan USA-19W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19W
       bool '    USB Keyspan USA-19QW Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19QW
       bool '    USB Keyspan USA-19QI Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19QI
+      bool '    USB Keyspan MPR Firmware' CONFIG_USB_SERIAL_KEYSPAN_MPR
       bool '    USB Keyspan USA-49W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA49W
+      bool '    USB Keyspan USA-49WLC Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA49WLC
    fi
    dep_tristate '  USB MCT Single Port Serial Driver' CONFIG_USB_SERIAL_MCT_U232 $CONFIG_USB_SERIAL
    dep_tristate '  USB KL5KUSB105 (Palmconnect) Driver' CONFIG_USB_SERIAL_KLSI $CONFIG_USB_SERIAL
+   dep_tristate '  USB KOBIL chipcard reader (EXPERIMENTAL)' CONFIG_USB_SERIAL_KOBIL_SCT $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
    dep_tristate '  USB Prolific 2303 Single Port Serial Driver' CONFIG_USB_SERIAL_PL2303 $CONFIG_USB_SERIAL
    dep_tristate '  USB REINER SCT cyberJack pinpad/e-com chipcard reader (EXPERIMENTAL)' CONFIG_USB_SERIAL_CYBERJACK $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
    dep_tristate '  USB Xircom / Entregra Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_XIRCOM $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/serial/Makefile linux-2.4.21-pre6/drivers/usb/serial/Makefile
--- linux-2.4.20/drivers/usb/serial/Makefile	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/serial/Makefile	2003-03-26 23:49:08.000000000 +0000
@@ -25,6 +25,7 @@
 obj-$(CONFIG_USB_SERIAL_CYBERJACK)		+= cyberjack.o
 obj-$(CONFIG_USB_SERIAL_IR)			+= ir-usb.o
 obj-$(CONFIG_USB_SERIAL_KLSI)			+= kl5kusb105.o
+obj-$(CONFIG_USB_SERIAL_KOBIL_SCT)		+= kobil_sct.o
 
 # Objects that export symbols.
 export-objs	:= usbserial.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/serial/ftdi_sio.c linux-2.4.21-pre6/drivers/usb/serial/ftdi_sio.c
--- linux-2.4.20/drivers/usb/serial/ftdi_sio.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/serial/ftdi_sio.c	2003-03-26 23:49:19.000000000 +0000
@@ -17,6 +17,14 @@
  * See http://ftdi-usb-sio.sourceforge.net for upto date testing info
  *	and extra documentation
  *
+ * (07/Jun/2002) Kuba Ober
+ *	Changed FTDI_SIO_BASE_BAUD_TO_DIVISOR macro into ftdi_baud_to_divisor
+ *	function. It was getting too complex.
+ *	Fix the divisor calculation logic which was setting divisor of 0.125
+ *	instead of 0.5 for fractional parts of divisor equal to 5/8, 6/8, 7/8.
+ *	Also make it bump up the divisor to next integer in case of 7/8 - it's
+ *	a better approximation.
+ *
  * (25/Jul/2002) Bill Ryder inserted Dmitri's TIOCMIWAIT patch
  *      Not tested by me but it doesn't break anything I use.
  * 
@@ -153,6 +161,7 @@
 
 static struct usb_device_id id_table_8U232AM [] = {
 	{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) },
+	{ USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) },
 	{ USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) },
 	{ }						/* Terminating entry */
 };
@@ -161,6 +170,7 @@
 static __devinitdata struct usb_device_id id_table_combined [] = {
 	{ USB_DEVICE(FTDI_VID, FTDI_SIO_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) },
+	{ USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) },
 	{ USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) },
 	{ }						/* Terminating entry */
 };
@@ -203,6 +213,10 @@
 static void ftdi_set_termios		(struct usb_serial_port *port, struct termios * old);
 static int  ftdi_ioctl			(struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
 static void ftdi_break_ctl		(struct usb_serial_port *port, int break_state );
+static unsigned short int ftdi_baud_base_to_divisor
+					(int baud, int base);
+static unsigned short int ftdi_baud_to_divisor
+					(int baud);
 
 static struct usb_serial_device_type ftdi_SIO_device = {
 	.owner =		THIS_MODULE,
@@ -257,6 +271,23 @@
  * ***************************************************************************
  */
 
+static unsigned short int ftdi_baud_base_to_divisor(int baud, int base)
+{
+	unsigned short int divisor;
+	int divisor3 = base / 2 / baud; // divisor shifted 3 bits to the left
+	if ((divisor3 & 0x7) == 7) divisor3 ++; // round x.7/8 up to x+1
+	divisor = divisor3 >> 3;
+	divisor3 &= 0x7;
+	if (divisor3 == 1) divisor |= 0xc000; else // 0.125
+	if (divisor3 >= 4) divisor |= 0x4000; else // 0.5
+	if (divisor3 != 0) divisor |= 0x8000;      // 0.25
+	return divisor;
+}
+
+static unsigned short int ftdi_baud_to_divisor(int baud)
+{
+	 return(ftdi_baud_base_to_divisor(baud, 48000000));
+}
 
 static int set_rts(struct usb_device *dev,
 		   unsigned int pipe,
@@ -373,7 +404,7 @@
 		break;
 	case FT8U232AM: /* 8U232AM chip */
 		if (baud <= 3000000) {
-			urb_value = FTDI_SIO_BAUD_TO_DIVISOR(baud);
+			urb_value = ftdi_baud_to_divisor(baud);
 		} else {
 	                dbg("%s - Baud rate too high!", __FUNCTION__);
 		}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/serial/ftdi_sio.h linux-2.4.21-pre6/drivers/usb/serial/ftdi_sio.h
--- linux-2.4.20/drivers/usb/serial/ftdi_sio.h	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/serial/ftdi_sio.h	2003-03-26 23:49:25.000000000 +0000
@@ -17,11 +17,14 @@
  * Bill Ryder - bryder@sgi.com of Silicon Graphics, Inc.- wrote the 
  * FTDI_SIO implementation.
  *
+ * Philipp Gühring - pg@futureware.at - added the Device ID of the USB relais
+ * from Rudolf Gugler
  */
 
 #define FTDI_VID	0x0403	/* Vendor Id */
 #define FTDI_SIO_PID	0x8372	/* Product Id SIO application of 8U100AX  */
 #define FTDI_8U232AM_PID 0x6001 /* Similar device to SIO above */
+#define FTDI_RELAIS_PID	0xFA10  /* Relais device from Rudolf Gugler */
 #define FTDI_NF_RIC_VID	0x0DCD	/* Vendor Id */
 #define FTDI_NF_RIC_PID	0x0001	/* Product Id */
 
@@ -125,17 +128,9 @@
  ftdi_sio_b115200 = 9
 } FTDI_SIO_baudrate_t ;
 
-#define FTDI_SIO_BASE_BAUD_TO_DIVISOR(base, baud) ( \
-((base/2/baud) >> 3) | \
-(((base/2/baud) & 2) ? 0x8000 : 0) | \
-(((base/2/baud) & 4) ? 0x4000 : 0) | \
-((((base/2/baud) & 0x7) == 1) ? 0xc000 : 0) )
-
-#define FTDI_SIO_BAUD_TO_DIVISOR(baud) FTDI_SIO_BASE_BAUD_TO_DIVISOR(48000000, baud)
-
 /*
- * The ftdi_8U232AM_xxMHz_byyy constans have been removed. Their values can
- * be calculated as follows: FTDI_SIO_BAUD_TO_DIVISOR(xx000000, yyy)
+ * The ftdi_8U232AM_xxMHz_byyy constants have been removed. The encoded divisor values
+ * are calculated internally.
  */
 
 #define FTDI_SIO_SET_DATA_REQUEST FTDI_SIO_SET_DATA
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/serial/io_16654.h linux-2.4.21-pre6/drivers/usb/serial/io_16654.h
--- linux-2.4.20/drivers/usb/serial/io_16654.h	2001-03-20 01:21:54.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/serial/io_16654.h	2003-03-26 23:49:25.000000000 +0000
@@ -142,14 +142,14 @@
 #define LSR_FIFO_ERR		0x80	// Rx Fifo contains at least 1 erred char
 
 
-#define MSR_DELTA_CTS		0x01	// CTS changed from last read
-#define MSR_DELTA_DSR		0x02	// DSR changed from last read
-#define MSR_DELTA_RI		0x04	// RI  changed from 0 -> 1
-#define MSR_DELTA_CD		0x08	// CD  changed from last read
-#define MSR_CTS			0x10	// Current state of CTS
-#define MSR_DSR			0x20	// Current state of DSR
-#define MSR_RI			0x40	// Current state of RI
-#define MSR_CD			0x80	// Current state of CD
+#define EDGEPORT_MSR_DELTA_CTS		0x01	// CTS changed from last read
+#define EDGEPORT_MSR_DELTA_DSR		0x02	// DSR changed from last read
+#define EDGEPORT_MSR_DELTA_RI		0x04	// RI  changed from 0 -> 1
+#define EDGEPORT_MSR_DELTA_CD		0x08	// CD  changed from last read
+#define EDGEPORT_MSR_CTS			0x10	// Current state of CTS
+#define EDGEPORT_MSR_DSR			0x20	// Current state of DSR
+#define EDGEPORT_MSR_RI			0x40	// Current state of RI
+#define EDGEPORT_MSR_CD			0x80	// Current state of CD
 
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/serial/io_edgeport.c linux-2.4.21-pre6/drivers/usb/serial/io_edgeport.c
--- linux-2.4.20/drivers/usb/serial/io_edgeport.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/serial/io_edgeport.c	2003-03-26 23:49:00.000000000 +0000
@@ -515,7 +515,7 @@
 		case EDGE_DOWNLOAD_FILE_I930:
 			BootMajorVersion	= BootCodeImageVersion_GEN1.MajorVersion;
 			BootMinorVersion	= BootCodeImageVersion_GEN1.MinorVersion;
-			BootBuildNumber		= BootCodeImageVersion_GEN1.BuildNumber;
+			BootBuildNumber		= cpu_to_le16(BootCodeImageVersion_GEN1.BuildNumber);
 			BootImage		= &BootCodeImage_GEN1[0];
 			BootSize		= sizeof( BootCodeImage_GEN1 );
 			break;
@@ -523,7 +523,7 @@
 		case EDGE_DOWNLOAD_FILE_80251:
 			BootMajorVersion	= BootCodeImageVersion_GEN2.MajorVersion;
 			BootMinorVersion	= BootCodeImageVersion_GEN2.MinorVersion;
-			BootBuildNumber		= BootCodeImageVersion_GEN2.BuildNumber;
+			BootBuildNumber		= cpu_to_le16(BootCodeImageVersion_GEN2.BuildNumber);
 			BootImage		= &BootCodeImage_GEN2[0];
 			BootSize		= sizeof( BootCodeImage_GEN2 );
 			break;
@@ -535,26 +535,26 @@
 	// Check Boot Image Version
 	BootCurVer = (edge_serial->boot_descriptor.MajorVersion << 24) +
 		     (edge_serial->boot_descriptor.MinorVersion << 16) +
-		      edge_serial->boot_descriptor.BuildNumber;
+		      le16_to_cpu(edge_serial->boot_descriptor.BuildNumber);
 
 	BootNewVer = (BootMajorVersion << 24) +
 		     (BootMinorVersion << 16) +
-		      BootBuildNumber;
+		      le16_to_cpu(BootBuildNumber);
 
 	dbg("Current Boot Image version %d.%d.%d",
 	    edge_serial->boot_descriptor.MajorVersion,
 	    edge_serial->boot_descriptor.MinorVersion,
-	    edge_serial->boot_descriptor.BuildNumber);
+	    le16_to_cpu(edge_serial->boot_descriptor.BuildNumber));
 
 
 	if (BootNewVer > BootCurVer) {
 		dbg("**Update Boot Image from %d.%d.%d to %d.%d.%d",
 		    edge_serial->boot_descriptor.MajorVersion,
 		    edge_serial->boot_descriptor.MinorVersion,
-		    edge_serial->boot_descriptor.BuildNumber,
+		    le16_to_cpu(edge_serial->boot_descriptor.BuildNumber),
 		    BootMajorVersion,
 		    BootMinorVersion,
-		    BootBuildNumber);
+		    le16_to_cpu(BootBuildNumber));
 
 
 		dbg("Downloading new Boot Image");
@@ -563,12 +563,12 @@
 
 		for (;;) {
 			record = (struct edge_firmware_image_record *)firmware;
-			response = rom_write (edge_serial->serial, record->ExtAddr, record->Addr, record->Len, &record->Data[0]);
+			response = rom_write (edge_serial->serial, le16_to_cpu(record->ExtAddr), le16_to_cpu(record->Addr), le16_to_cpu(record->Len), &record->Data[0]);
 			if (response < 0) {
-				err("sram_write failed (%x, %x, %d)", record->ExtAddr, record->Addr, record->Len);
+				err("rom_write failed (%x, %x, %d)", le16_to_cpu(record->ExtAddr), le16_to_cpu(record->Addr), le16_to_cpu(record->Len));
 				break;
 			}
-			firmware += sizeof (struct edge_firmware_image_record) + record->Len;
+			firmware += sizeof (struct edge_firmware_image_record) + le16_to_cpu(record->Len);
 			if (firmware >= &BootImage[BootSize]) {
 				break;
 			}
@@ -671,12 +671,12 @@
 	if (edge_serial->serial->dev->descriptor.idProduct & ION_DEVICE_ID_GENERATION_2) {
 		product_info->FirmwareMajorVersion	= OperationalCodeImageVersion_GEN2.MajorVersion;
 		product_info->FirmwareMinorVersion	= OperationalCodeImageVersion_GEN2.MinorVersion;
-		product_info->FirmwareBuildNumber	= OperationalCodeImageVersion_GEN2.BuildNumber;
+		product_info->FirmwareBuildNumber	= cpu_to_le16(OperationalCodeImageVersion_GEN2.BuildNumber);
 		product_info->iDownloadFile		= EDGE_DOWNLOAD_FILE_80251;
 	} else {
 		product_info->FirmwareMajorVersion	= OperationalCodeImageVersion_GEN1.MajorVersion;
 		product_info->FirmwareMinorVersion	= OperationalCodeImageVersion_GEN1.MinorVersion;
-		product_info->FirmwareBuildNumber	= OperationalCodeImageVersion_GEN1.BuildNumber;
+		product_info->FirmwareBuildNumber	= cpu_to_le16(OperationalCodeImageVersion_GEN1.BuildNumber);
 		product_info->iDownloadFile		= EDGE_DOWNLOAD_FILE_I930;
 	}
 
@@ -722,10 +722,10 @@
 	dbg("  BoardRev              %x", product_info->BoardRev);
 	dbg("  BootMajorVersion      %d.%d.%d", product_info->BootMajorVersion,
 	    product_info->BootMinorVersion,
-	    product_info->BootBuildNumber);
+	    le16_to_cpu(product_info->BootBuildNumber));
 	dbg("  FirmwareMajorVersion  %d.%d.%d", product_info->FirmwareMajorVersion,
 	    product_info->FirmwareMinorVersion,
-	    product_info->FirmwareBuildNumber);
+	    le16_to_cpu(product_info->FirmwareBuildNumber));
 	dbg("  ManufactureDescDate   %d/%d/%d", product_info->ManufactureDescDate[0],
 	    product_info->ManufactureDescDate[1],
 	    product_info->ManufactureDescDate[2]+1900);
@@ -1790,10 +1790,10 @@
 
 	result = ((mcr & MCR_DTR)	? TIOCM_DTR: 0)	  /* 0x002 */
 		  | ((mcr & MCR_RTS)	? TIOCM_RTS: 0)   /* 0x004 */
-		  | ((msr & MSR_CTS)	? TIOCM_CTS: 0)   /* 0x020 */
-		  | ((msr & MSR_CD)	? TIOCM_CAR: 0)   /* 0x040 */
-		  | ((msr & MSR_RI)	? TIOCM_RI:  0)   /* 0x080 */
-		  | ((msr & MSR_DSR)	? TIOCM_DSR: 0);  /* 0x100 */
+		  | ((msr & EDGEPORT_MSR_CTS)	? TIOCM_CTS: 0)   /* 0x020 */
+		  | ((msr & EDGEPORT_MSR_CD)	? TIOCM_CAR: 0)   /* 0x040 */
+		  | ((msr & EDGEPORT_MSR_RI)	? TIOCM_RI:  0)   /* 0x080 */
+		  | ((msr & EDGEPORT_MSR_DSR)	? TIOCM_DSR: 0);  /* 0x100 */
 
 
 	dbg("%s -- %x", __FUNCTION__, result);
@@ -2219,20 +2219,20 @@
 
 	dbg("%s %02x", __FUNCTION__, newMsr);
 
-	if (newMsr & (MSR_DELTA_CTS | MSR_DELTA_DSR | MSR_DELTA_RI | MSR_DELTA_CD)) {
+	if (newMsr & (EDGEPORT_MSR_DELTA_CTS | EDGEPORT_MSR_DELTA_DSR | EDGEPORT_MSR_DELTA_RI | EDGEPORT_MSR_DELTA_CD)) {
 		icount = &edge_port->icount;
 
 		/* update input line counters */
-		if (newMsr & MSR_DELTA_CTS) {
+		if (newMsr & EDGEPORT_MSR_DELTA_CTS) {
 			icount->cts++;
 		}
-		if (newMsr & MSR_DELTA_DSR) {
+		if (newMsr & EDGEPORT_MSR_DELTA_DSR) {
 			icount->dsr++;
 		}
-		if (newMsr & MSR_DELTA_CD) {
+		if (newMsr & EDGEPORT_MSR_DELTA_CD) {
 			icount->dcd++;
 		}
-		if (newMsr & MSR_DELTA_RI) {
+		if (newMsr & EDGEPORT_MSR_DELTA_RI) {
 			icount->rng++;
 		}
 		wake_up_interruptible(&edge_port->delta_msr_wait);
@@ -2305,7 +2305,7 @@
 	__u16 current_length;
 	unsigned char *transfer_buffer;
 
-//	dbg("%s - %x, %x, %d", __FUNCTION__, extAddr, addr, length);
+	dbg("%s - %x, %x, %d", __FUNCTION__, extAddr, addr, length);
 
 	transfer_buffer =  kmalloc (64, GFP_KERNEL);
 	if (!transfer_buffer) {
@@ -2793,12 +2793,13 @@
  *	Turns a string from Unicode into ASCII.
  *	Doesn't do a good job with any characters that are outside the normal
  *	ASCII range, but it's only for debugging...
+ *	NOTE: expects the unicode in LE format
  ****************************************************************************/
 static void unicode_to_ascii (char *string, short *unicode, int unicode_size)
 {
 	int i;
 	for (i = 0; i < unicode_size; ++i) {
-		string[i] = (char)(unicode[i]);
+		string[i] = (char)(le16_to_cpu(unicode[i]));
 	}
 	string[unicode_size] = 0x00;
 }
@@ -2862,11 +2863,11 @@
 		err("error in getting boot descriptor");
 	} else {
 		dbg("**Boot Descriptor:");
-		dbg("  BootCodeLength: %d", edge_serial->boot_descriptor.BootCodeLength);
+		dbg("  BootCodeLength: %d", le16_to_cpu(edge_serial->boot_descriptor.BootCodeLength));
 		dbg("  MajorVersion:   %d", edge_serial->boot_descriptor.MajorVersion);
 		dbg("  MinorVersion:   %d", edge_serial->boot_descriptor.MinorVersion);
-		dbg("  BuildNumber:    %d", edge_serial->boot_descriptor.BuildNumber);
-		dbg("  Capabilities:   0x%x", edge_serial->boot_descriptor.Capabilities);
+		dbg("  BuildNumber:    %d", le16_to_cpu(edge_serial->boot_descriptor.BuildNumber));
+		dbg("  Capabilities:   0x%x", le16_to_cpu(edge_serial->boot_descriptor.Capabilities));
 		dbg("  UConfig0:       %d", edge_serial->boot_descriptor.UConfig0);
 		dbg("  UConfig1:       %d", edge_serial->boot_descriptor.UConfig1);
 	}
@@ -2918,12 +2919,12 @@
 
 	for (;;) {
 		record = (struct edge_firmware_image_record *)firmware;
-		response = sram_write (edge_serial->serial, record->ExtAddr, record->Addr, record->Len, &record->Data[0]);
+		response = sram_write (edge_serial->serial, le16_to_cpu(record->ExtAddr), le16_to_cpu(record->Addr), le16_to_cpu(record->Len), &record->Data[0]);
 		if (response < 0) {
-			err("sram_write failed (%x, %x, %d)", record->ExtAddr, record->Addr, record->Len);
+			err("sram_write failed (%x, %x, %d)", le16_to_cpu(record->ExtAddr), le16_to_cpu(record->Addr), record->Len);
 			break;
 		}
-		firmware += sizeof (struct edge_firmware_image_record) + record->Len;
+		firmware += sizeof (struct edge_firmware_image_record) + le16_to_cpu(record->Len);
 		if (firmware >= &FirmwareImage[ImageSize]) {
 			break;
 		}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/serial/io_ti.c linux-2.4.21-pre6/drivers/usb/serial/io_ti.c
--- linux-2.4.20/drivers/usb/serial/io_ti.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/serial/io_ti.c	2003-03-26 23:49:35.000000000 +0000
@@ -1549,17 +1549,17 @@
 
 	dbg ("%s - %02x", __FUNCTION__, msr);
 
-	if (msr & (MSR_DELTA_CTS | MSR_DELTA_DSR | MSR_DELTA_RI | MSR_DELTA_CD)) {
+	if (msr & (EDGEPORT_MSR_DELTA_CTS | EDGEPORT_MSR_DELTA_DSR | EDGEPORT_MSR_DELTA_RI | EDGEPORT_MSR_DELTA_CD)) {
 		icount = &edge_port->icount;
 
 		/* update input line counters */
-		if (msr & MSR_DELTA_CTS)
+		if (msr & EDGEPORT_MSR_DELTA_CTS)
 			icount->cts++;
-		if (msr & MSR_DELTA_DSR)
+		if (msr & EDGEPORT_MSR_DELTA_DSR)
 			icount->dsr++;
-		if (msr & MSR_DELTA_CD)
+		if (msr & EDGEPORT_MSR_DELTA_CD)
 			icount->dcd++;
-		if (msr & MSR_DELTA_RI)
+		if (msr & EDGEPORT_MSR_DELTA_RI)
 			icount->rng++;
 		wake_up_interruptible (&edge_port->delta_msr_wait);
 	}
@@ -2416,10 +2416,10 @@
 
 	result = ((mcr & MCR_DTR)	? TIOCM_DTR: 0)	  /* 0x002 */
 		  | ((mcr & MCR_RTS)	? TIOCM_RTS: 0)   /* 0x004 */
-		  | ((msr & MSR_CTS)	? TIOCM_CTS: 0)   /* 0x020 */
-		  | ((msr & MSR_CD)	? TIOCM_CAR: 0)   /* 0x040 */
-		  | ((msr & MSR_RI)	? TIOCM_RI:  0)   /* 0x080 */
-		  | ((msr & MSR_DSR)	? TIOCM_DSR: 0);  /* 0x100 */
+		  | ((msr & EDGEPORT_MSR_CTS)	? TIOCM_CTS: 0)   /* 0x020 */
+		  | ((msr & EDGEPORT_MSR_CD)	? TIOCM_CAR: 0)   /* 0x040 */
+		  | ((msr & EDGEPORT_MSR_RI)	? TIOCM_RI:  0)   /* 0x080 */
+		  | ((msr & EDGEPORT_MSR_DSR)	? TIOCM_DSR: 0);  /* 0x100 */
 
 
 	dbg("%s -- %x", __FUNCTION__, result);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/serial/ipaq.c linux-2.4.21-pre6/drivers/usb/serial/ipaq.c
--- linux-2.4.20/drivers/usb/serial/ipaq.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/serial/ipaq.c	2003-03-26 23:49:39.000000000 +0000
@@ -9,6 +9,14 @@
  *	the Free Software Foundation; either version 2 of the License, or
  *	(at your option) any later version.
  *
+ * (12/12/2002) ganesh
+ * 	Added support for practically all devices supported by ActiveSync
+ * 	on Windows. Thanks to Wes Cilldhaire <billybobjoehenrybob@hotmail.com>.
+ *
+ * (26/11/2002) ganesh
+ * 	Added insmod options to specify product and vendor id.
+ * 	Use modprobe ipaq vendor=0xfoo product=0xbar
+ *
  * (26/7/2002) ganesh
  * 	Fixed up broken error handling in ipaq_open. Retry the "kickstart"
  * 	packet much harder - this drastically reduces connection failures.
@@ -63,9 +71,12 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.2"
+
+#define DRIVER_VERSION "v0.5"
 #define DRIVER_AUTHOR "Ganesh Varadarajan <ganesh@veritas.com>"
-#define DRIVER_DESC "USB Compaq iPAQ, HP Jornada, Casio EM500 driver"
+#define DRIVER_DESC "USB PocketPC PDA driver"
+
+static int	product, vendor;
 
 /* Function prototypes for an ipaq */
 static int  ipaq_open (struct usb_serial_port *port, struct file *filp);
@@ -85,10 +96,41 @@
 
 
 static struct usb_device_id ipaq_id_table [] = {
+	/* The first entry is a placeholder for the insmod-specified device */
+	{ USB_DEVICE(COMPAQ_VENDOR_ID, COMPAQ_IPAQ_ID) },
+	{ USB_DEVICE(ASKEY_VENDOR_ID, ASKEY_PRODUCT_ID) },
+	{ USB_DEVICE(BCOM_VENDOR_ID, BCOM_0065_ID) },
+	{ USB_DEVICE(BCOM_VENDOR_ID, BCOM_0066_ID) },
+	{ USB_DEVICE(BCOM_VENDOR_ID, BCOM_0067_ID) },
+	{ USB_DEVICE(CASIO_VENDOR_ID, CASIO_2001_ID) },
+	{ USB_DEVICE(CASIO_VENDOR_ID, CASIO_EM500_ID) },
 	{ USB_DEVICE(COMPAQ_VENDOR_ID, COMPAQ_IPAQ_ID) },
+	{ USB_DEVICE(COMPAQ_VENDOR_ID, COMPAQ_0032_ID) },
+	{ USB_DEVICE(DELL_VENDOR_ID, DELL_AXIM_ID) },
+	{ USB_DEVICE(FSC_VENDOR_ID, FSC_LOOX_ID) },
 	{ USB_DEVICE(HP_VENDOR_ID, HP_JORNADA_548_ID) },
 	{ USB_DEVICE(HP_VENDOR_ID, HP_JORNADA_568_ID) },
-	{ USB_DEVICE(CASIO_VENDOR_ID, CASIO_EM500_ID) },
+	{ USB_DEVICE(HP_VENDOR_ID, HP_2016_ID) },
+	{ USB_DEVICE(HP_VENDOR_ID, HP_2116_ID) },
+	{ USB_DEVICE(HP_VENDOR_ID, HP_2216_ID) },
+	{ USB_DEVICE(HP_VENDOR_ID, HP_3016_ID) },
+	{ USB_DEVICE(HP_VENDOR_ID, HP_3116_ID) },
+	{ USB_DEVICE(HP_VENDOR_ID, HP_3216_ID) },
+	{ USB_DEVICE(HP_VENDOR_ID, HP_4016_ID) },
+	{ USB_DEVICE(HP_VENDOR_ID, HP_4116_ID) },
+	{ USB_DEVICE(HP_VENDOR_ID, HP_4216_ID) },
+	{ USB_DEVICE(HP_VENDOR_ID, HP_5016_ID) },
+	{ USB_DEVICE(HP_VENDOR_ID, HP_5116_ID) },
+	{ USB_DEVICE(HP_VENDOR_ID, HP_5216_ID) },
+	{ USB_DEVICE(LINKUP_VENDOR_ID, LINKUP_PRODUCT_ID) },
+	{ USB_DEVICE(MICROSOFT_VENDOR_ID, MICROSOFT_00CE_ID) },
+	{ USB_DEVICE(PORTATEC_VENDOR_ID, PORTATEC_PRODUCT_ID) },
+	{ USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_WIRELESS_ID) },
+	{ USB_DEVICE(SOCKET_VENDOR_ID, SOCKET_PRODUCT_ID) },
+	{ USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_PRODUCT_ID) },
+	{ USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_E740_ID) },
+	{ USB_DEVICE(HTC_VENDOR_ID, HTC_PRODUCT_ID) },
+	{ USB_DEVICE(NEC_VENDOR_ID, NEC_PRODUCT_ID) },
 	{ }					/* Terminating entry */
 };
 
@@ -97,7 +139,7 @@
 /* All of the device info needed for the Compaq iPAQ */
 struct usb_serial_device_type ipaq_device = {
 	.owner =		THIS_MODULE,
-	.name =			"Compaq iPAQ",
+	.name =			"PocketPC PDA",
 	.id_table =		ipaq_id_table,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		1,
@@ -516,8 +558,13 @@
 
 static int __init ipaq_init(void)
 {
-	usb_serial_register(&ipaq_device);
+	spin_lock_init(&write_list_lock);
 	info(DRIVER_DESC " " DRIVER_VERSION);
+	if (vendor) {
+		ipaq_id_table[0].idVendor = vendor;
+		ipaq_id_table[0].idProduct = product;
+	}
+	usb_serial_register(&ipaq_device);
 
 	return 0;
 }
@@ -539,3 +586,8 @@
 MODULE_PARM(debug, "i");
 MODULE_PARM_DESC(debug, "Debug enabled or not");
 
+MODULE_PARM(vendor, "h");
+MODULE_PARM_DESC(vendor, "User specified USB idVendor");
+
+MODULE_PARM(product, "h");
+MODULE_PARM_DESC(product, "User specified USB idProduct");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/serial/ipaq.h linux-2.4.21-pre6/drivers/usb/serial/ipaq.h
--- linux-2.4.20/drivers/usb/serial/ipaq.h	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/serial/ipaq.h	2003-03-26 23:49:20.000000000 +0000
@@ -9,22 +9,73 @@
  *	the Free Software Foundation; either version 2 of the License, or
  *	(at your option) any later version.
  *
- * 
  */
 
 #ifndef __LINUX_USB_SERIAL_IPAQ_H
 #define __LINUX_USB_SERIAL_IPAQ_H
 
+#define ASKEY_VENDOR_ID		0x1690
+#define ASKEY_PRODUCT_ID	0x0601
+
+#define BCOM_VENDOR_ID		0x0960
+#define BCOM_0065_ID		0x0065
+#define BCOM_0066_ID		0x0066
+#define BCOM_0067_ID		0x0067
+
+#define CASIO_VENDOR_ID		0x07cf
+#define CASIO_2001_ID		0x2001
+#define CASIO_EM500_ID		0x2002
 
 #define COMPAQ_VENDOR_ID	0x049f
 #define COMPAQ_IPAQ_ID		0x0003
+#define COMPAQ_0032_ID		0x0032
+
+#define DELL_VENDOR_ID		0x413c
+#define DELL_AXIM_ID		0x4001
+
+#define FSC_VENDOR_ID		0x0bf8
+#define FSC_LOOX_ID		0x1001
 
 #define HP_VENDOR_ID		0x03f0
 #define HP_JORNADA_548_ID	0x1016
 #define HP_JORNADA_568_ID	0x1116
+#define HP_2016_ID		0x2016
+#define HP_2116_ID		0x2116
+#define HP_2216_ID		0x2216
+#define HP_3016_ID		0x3016
+#define HP_3116_ID		0x3116
+#define HP_3216_ID		0x3216
+#define HP_4016_ID		0x4016
+#define HP_4116_ID		0x4116
+#define HP_4216_ID		0x4216
+#define HP_5016_ID		0x5016
+#define HP_5116_ID		0x5116
+#define HP_5216_ID		0x5216
+
+#define LINKUP_VENDOR_ID	0x094b
+#define LINKUP_PRODUCT_ID	0x0001
+
+#define MICROSOFT_VENDOR_ID	0x045e
+#define MICROSOFT_00CE_ID	0x00ce
+
+#define PORTATEC_VENDOR_ID	0x0961
+#define PORTATEC_PRODUCT_ID	0x0010
+
+#define SAGEM_VENDOR_ID		0x5e04
+#define SAGEM_WIRELESS_ID	0xce00
+
+#define SOCKET_VENDOR_ID	0x0104
+#define SOCKET_PRODUCT_ID	0x00be
+
+#define TOSHIBA_VENDOR_ID	0x0930
+#define TOSHIBA_PRODUCT_ID	0x0700
+#define TOSHIBA_E740_ID		0x0706
 
-#define CASIO_VENDOR_ID		0x07cf
-#define CASIO_EM500_ID		0x2002
+#define HTC_VENDOR_ID		0x0bb4
+#define HTC_PRODUCT_ID		0x00ce
+
+#define NEC_VENDOR_ID		0x0409
+#define NEC_PRODUCT_ID		0x00d5
 
 /*
  * Since we can't queue our bulk write urbs (don't know why - it just
@@ -41,8 +92,7 @@
  *
  * The value of PACKET_SIZE was empirically determined by
  * checking the maximum write sizes sent down by the ppp ldisc.
- * URBDATA_QUEUE_MAX is set to 64K, which is the maximum TCP window size
- * supported by the iPAQ.
+ * URBDATA_QUEUE_MAX is set to 64K, which is the maximum TCP window size.
  */
 
 struct ipaq_packet {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/serial/keyspan.c linux-2.4.21-pre6/drivers/usb/serial/keyspan.c
--- linux-2.4.20/drivers/usb/serial/keyspan.c	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/serial/keyspan.c	2003-03-26 23:49:07.000000000 +0000
@@ -28,6 +28,24 @@
 
   Change History
 
+    Wed Feb 19 22:00:00 PST 2003 (Jeffrey S. Laing <keyspan@jsl.com>)
+      Merged the current (1/31/03) Keyspan code with the current (2.4.21-pre4)
+      Linux source tree.  The Linux tree lacked support for the 49WLC and
+      others.  The Keyspan patches didn't work with the current kernel.
+
+    2003jan30	LPM	add support for the 49WLC and MPR
+
+    Wed Apr 25 12:00:00 PST 2002 (Keyspan)
+      Started with Hugh Blemings' code dated Jan 17, 2002.  All adapters
+      now supported (including QI and QW).  Modified port open, port
+      close, and send setup() logic to fix various data and endpoint
+      synchronization bugs and device LED status bugs.  Changed keyspan_
+      write_room() to accurately return transmit buffer availability.
+      Changed forwardingLength from 1 to 16 for all adapters.
+
+    Fri Oct 12 16:45:00 EST 2001
+      Preliminary USA-19QI and USA-28 support (both test OK for me, YMMV)
+
     Wed Apr 25 12:00:00 PST 2002 (Keyspan)
       Started with Hugh Blemings' code dated Jan 17, 2002.  All adapters
       now supported (including QI and QW).  Modified port open, port
@@ -102,7 +120,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.1.3"
+#define DRIVER_VERSION "v1.1.4"
 #define DRIVER_AUTHOR "Hugh Blemings <hugh@misc.nu"
 #define DRIVER_DESC "Keyspan USB to Serial Converter Driver"
 
@@ -343,7 +361,7 @@
 		if (this_urb->status == -EINPROGRESS) {
 			if (this_urb->transfer_flags & USB_ASYNC_UNLINK)
 				break;
-			if (jiffies - p_priv->tx_start_time[flip] < 10 * HZ)
+			if (time_before(jiffies, p_priv->tx_start_time[flip] + 10 * HZ))
 				break;
 			this_urb->transfer_flags |= USB_ASYNC_UNLINK;
 			usb_unlink_urb(this_urb);
@@ -530,6 +548,7 @@
 		dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err);
 	}
 exit:
+	;
 }
 
 static void	usa26_glocont_callback(struct urb *urb)
@@ -665,6 +684,7 @@
 		dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err);
 	}
 exit:	
+	;
 }
 
 static void	usa28_glocont_callback(struct urb *urb)
@@ -758,6 +778,7 @@
 		dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err);
 	}
 exit:	
+	;
 }
 
 static void	usa49_inack_callback(struct urb *urb)
@@ -901,6 +922,9 @@
 		/* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe), 0); */
 	}
 
+	// if the device is a USA49x, determine whether it is an W or WLC model
+	// and set the baud clock accordingly
+
 	keyspan_send_setup(port, 1);
 	//mdelay(100);
 	keyspan_set_termios(port, NULL);
@@ -1009,6 +1033,11 @@
 		fw_name = "USA19QI";
 		break;
 			     
+	case keyspan_mpr_pre_product_id:
+		record = &keyspan_mpr_firmware[0];
+		fw_name = "MPR";
+		break;
+
 	case keyspan_usa19qw_pre_product_id:
 		record = &keyspan_usa19qw_firmware[0];
 		fw_name = "USA19QI";
@@ -1029,6 +1058,11 @@
 		fw_name = "USA49W";
 		break;
 
+	case keyspan_usa49wlc_pre_product_id:
+		record = &keyspan_usa49wlc_firmware[0];
+		fw_name = "USA49WLC";
+		break;
+
 	default:
 		record = NULL;
 		fw_name = "Unknown";
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/serial/keyspan.h linux-2.4.21-pre6/drivers/usb/serial/keyspan.h
--- linux-2.4.20/drivers/usb/serial/keyspan.h	2002-11-28 23:53:14.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/serial/keyspan.h	2003-03-26 23:49:50.000000000 +0000
@@ -136,6 +136,12 @@
 	static const struct ezusb_hex_record *keyspan_usa19qi_firmware = NULL;
 #endif
 
+#ifdef CONFIG_USB_SERIAL_KEYSPAN_MPR
+        #include "keyspan_mpr_fw.h"
+#else
+	static const struct ezusb_hex_record *keyspan_mpr_firmware = NULL;
+#endif
+
 #ifdef CONFIG_USB_SERIAL_KEYSPAN_USA19QW
 	#include "keyspan_usa19qw_fw.h"
 #else
@@ -160,6 +166,12 @@
 	static const struct ezusb_hex_record *keyspan_usa49w_firmware = NULL;
 #endif
 
+#ifdef CONFIG_USB_SERIAL_KEYSPAN_USA49WLC
+        #include "keyspan_usa49wlc_fw.h"
+#else
+	static const struct ezusb_hex_record *keyspan_usa49wlc_firmware = NULL;
+#endif
+
 /* Values used for baud rate calculation - device specific */
 #define	KEYSPAN_INVALID_BAUD_RATE		(-1)
 #define	KEYSPAN_BAUD_RATE_OK			(0)
@@ -182,6 +194,7 @@
 #define	keyspan_usa18x_pre_product_id		0x0105
 #define	keyspan_usa19_pre_product_id		0x0103
 #define	keyspan_usa19qi_pre_product_id		0x010b
+#define	keyspan_mpr_pre_product_id		0x011b
 #define	keyspan_usa19qw_pre_product_id		0x0118
 #define	keyspan_usa19w_pre_product_id		0x0106
 #define	keyspan_usa28_pre_product_id		0x0101
@@ -189,6 +202,7 @@
 #define	keyspan_usa28xa_pre_product_id		0x0114
 #define	keyspan_usa28xb_pre_product_id		0x0113
 #define	keyspan_usa49w_pre_product_id		0x0109
+#define	keyspan_usa49wlc_pre_product_id		0x011a
 
 /* Product IDs post-renumeration.  Note that the 28x and 28xb
    have the same id's post-renumeration but behave identically
@@ -196,6 +210,7 @@
 #define	keyspan_usa18x_product_id		0x0112
 #define	keyspan_usa19_product_id		0x0107
 #define	keyspan_usa19qi_product_id		0x010c
+#define	keyspan_mpr_product_id			0x011c
 #define	keyspan_usa19qw_product_id		0x0119
 #define	keyspan_usa19w_product_id		0x0108
 #define	keyspan_usa28_product_id		0x010f
@@ -203,6 +218,7 @@
 #define	keyspan_usa28xa_product_id		0x0115
 #define	keyspan_usa28xb_product_id		0x0110
 #define	keyspan_usa49w_product_id		0x010a
+#define	keyspan_usa49wlc_product_id		0x012a
 
 
 struct keyspan_device_details {
@@ -394,6 +410,22 @@
 	baudclk:		KEYSPAN_USA49W_BAUDCLK,
 };
 
+static const struct keyspan_device_details usa49wlc_device_details = {
+	product_id:		keyspan_usa49wlc_product_id,
+	msg_format:		msg_usa49,
+	num_ports:		4,
+	indat_endp_flip:	0,
+	outdat_endp_flip:	0,
+	indat_endpoints:	{0x81, 0x82, 0x83, 0x84},
+	outdat_endpoints:	{0x01, 0x02, 0x03, 0x04},
+	inack_endpoints:	{-1, -1, -1, -1},
+	outcont_endpoints:	{-1, -1, -1, -1},
+	instat_endpoint:	0x87,
+	glocont_endpoint:	0x07,
+	calculate_baud_rate:	keyspan_usa19w_calc_baud,
+	baudclk:		KEYSPAN_USA19W_BAUDCLK,
+};
+
 static const struct keyspan_device_details *keyspan_devices[] = {
 	&usa18x_device_details,
 	&usa19_device_details,
@@ -405,6 +437,7 @@
 	&usa28xa_device_details,
 	/* 28xb not required as it renumerates as a 28x */
 	&usa49w_device_details,
+	&usa49wlc_device_details,
 	NULL,
 };
 
@@ -414,21 +447,25 @@
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_pre_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_pre_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_pre_product_id) },
+	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_pre_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_pre_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_pre_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_pre_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_pre_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_pre_product_id) },
+	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_pre_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_product_id) },
+	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_product_id)},
+	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_product_id)},
 	{ } /* Terminating entry */
 };
 
@@ -441,11 +478,13 @@
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_pre_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_pre_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_pre_product_id) },
+	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_pre_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_pre_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_pre_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_pre_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_pre_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_pre_product_id) },
+	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_pre_product_id) },
 	{ } /* Terminating entry */
 };
 
@@ -455,6 +494,7 @@
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_product_id) },
+	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_pre_product_id) },
 	{ } /* Terminating entry */
 };
 
@@ -462,11 +502,13 @@
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) },
+	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_product_id) },
 	{ } /* Terminating entry */
 };
 
 static struct usb_device_id keyspan_4port_ids[] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_product_id) },
+	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_product_id)},
 	{ } /* Terminating entry */
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/serial/keyspan_mpr_fw.h linux-2.4.21-pre6/drivers/usb/serial/keyspan_mpr_fw.h
--- linux-2.4.20/drivers/usb/serial/keyspan_mpr_fw.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/serial/keyspan_mpr_fw.h	2003-03-26 23:48:59.000000000 +0000
@@ -0,0 +1,286 @@
+/* keyspan_mpr_fw.h
+ 
+	The firmware contained herein as keyspan_mpr_fw.h is
+
+		Copyright (C) 1999-2001
+		Keyspan, A division of InnoSys Incorporated ("Keyspan")
+		
+	as an unpublished work. This notice does not imply unrestricted or
+	public access to the source code from which this firmware image is
+	derived.  Except as noted below this firmware image may not be 
+	reproduced, used, sold or transferred to any third party without 
+	Keyspan's prior written consent.  All Rights Reserved.
+
+	Permission is hereby granted for the distribution of this firmware 
+	image as part of a Linux or other Open Source operating system kernel 
+	in text or binary form as required. 
+
+	This firmware may not be modified and may only be used with  
+	Keyspan hardware.  Distribution and/or Modification of the 
+	keyspan.c driver which includes this firmware, in whole or in 
+	part, requires the inclusion of this statement."
+
+static char theFirmwareDate53[] =
+	"04/26/2002  02:47p              11,570 USA53";
+*/
+
+static const struct ezusb_hex_record keyspan_mpr_firmware[] = {
+ {0x0033,  3, { 0x02, 0x00, 0x1a}},
+ {0x001a,  4, { 0x53, 0xd8, 0xef, 0x32}},
+ {0x0003, 16, { 0x8e, 0x56, 0x8f, 0x57, 0xe5, 0x57, 0x15, 0x57, 0xae, 0x56, 0x70, 0x02, 0x15, 0x56, 0x4e, 0x60}},
+ {0x0013,  7, { 0x05, 0x12, 0x0f, 0xa2, 0x80, 0xee, 0x22}},
+ {0x0023,  3, { 0x02, 0x00, 0x46}},
+ {0x0046, 16, { 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xc0, 0xd0, 0x75, 0xd0, 0x08}},
+ {0x0056, 16, { 0x30, 0x99, 0x0e, 0x30, 0x0b, 0x07, 0xa2, 0x0e, 0x92, 0x9b, 0x85, 0x36, 0x99, 0xc2, 0x99, 0xd2}},
+ {0x0066, 16, { 0x12, 0x20, 0x12, 0x03, 0x02, 0x02, 0xf9, 0xc2, 0x12, 0x30, 0x03, 0x19, 0x7e, 0x7e, 0x7f, 0x40}},
+ {0x0076, 16, { 0x75, 0x1a, 0x7e, 0x75, 0x1b, 0x40, 0x75, 0x17, 0x00, 0x7e, 0x7d, 0x7f, 0xc0, 0x75, 0x18, 0x7d}},
+ {0x0086, 16, { 0x75, 0x19, 0xc0, 0x80, 0x17, 0x7e, 0x7d, 0x7f, 0xc0, 0x75, 0x1a, 0x7d, 0x75, 0x1b, 0xc0, 0x75}},
+ {0x0096, 16, { 0x17, 0x01, 0x7e, 0x7e, 0x7f, 0x40, 0x75, 0x18, 0x7e, 0x75, 0x19, 0x40, 0x20, 0x0b, 0x03, 0x02}},
+ {0x00a6, 16, { 0x01, 0x84, 0xe5, 0x3a, 0xc3, 0x95, 0x53, 0x50, 0x3c, 0x20, 0x0c, 0x34, 0x20, 0x09, 0x31, 0x90}},
+ {0x00b6, 16, { 0x7f, 0x9b, 0xe0, 0x55, 0x38, 0x70, 0x29, 0x30, 0x10, 0x12, 0xaf, 0x3a, 0x05, 0x3a, 0xe5, 0x1b}},
+ {0x00c6, 16, { 0x2f, 0xf5, 0x82, 0xe4, 0x35, 0x1a, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x0e, 0xaf, 0x3a, 0x05, 0x3a}},
+ {0x00d6, 16, { 0xe5, 0x1b, 0x2f, 0xf5, 0x82, 0xe4, 0x35, 0x1a, 0xf5, 0x83, 0xe0, 0xf5, 0x36, 0x02, 0x02, 0xf7}},
+ {0x00e6, 16, { 0xc2, 0x0b, 0x02, 0x02, 0xf7, 0x30, 0x03, 0x11, 0x90, 0x7f, 0xc7, 0xe4, 0xf0, 0xa3, 0xe0, 0x54}},
+ {0x00f6, 16, { 0x02, 0xf5, 0x1d, 0xa3, 0xe0, 0xf5, 0x1c, 0x80, 0x11, 0x90, 0x7f, 0xc9, 0xe4, 0xf0, 0x90, 0x7f}},
+ {0x0043,  3, { 0x02, 0x0f, 0x00}},
+ {0x0000,  3, { 0x02, 0x00, 0x26}},
+ {0x0026, 12, { 0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x5a, 0x02, 0x0a, 0x33}},
+ {0x0106, 64, { 0xc6, 0xe0, 0x54, 0x02, 0xf5, 0x1d, 0xa3, 0xe0, 0xf5, 0x1c, 0xe5, 0x17, 0x24, 0xff, 0x92, 0x03, 0x30,
+  0x0d, 0x0d, 0xc2, 0x0d, 0x90, 0x7f, 0xbb, 0x74, 0x01, 0xf0, 0xc2, 0x0b, 0x02, 0x02, 0xf7, 0xe5,
+  0x1d, 0x60, 0x05, 0xc2, 0x0b, 0x02, 0x02, 0xf7, 0x85, 0x1c, 0x53, 0x85, 0x19, 0x82, 0x85, 0x18,
+  0x83, 0xe0, 0x13, 0x92, 0x0d, 0x75, 0x12, 0xff, 0x20, 0x0c, 0x3a, 0x20, 0x09, 0x37, 0x90}},
+ {0x0146, 64, { 0x7f, 0x9b, 0xe0, 0x55, 0x38, 0x70, 0x2f, 0x30, 0x10, 0x1c, 0x85, 0x19, 0x82, 0x85, 0x18, 0x83, 0xa3,
+  0xe0, 0x13, 0x92, 0x0e, 0x85, 0x19, 0x82, 0x85, 0x18, 0x83, 0xa3, 0xa3, 0xe0, 0xf5, 0x36, 0x75,
+  0x3a, 0x03, 0x02, 0x02, 0xf7, 0x75, 0x3a, 0x02, 0x85, 0x19, 0x82, 0x85, 0x18, 0x83, 0xa3, 0xe0,
+  0xf5, 0x36, 0x02, 0x02, 0xf7, 0x75, 0x3a, 0x01, 0xc2, 0x0b, 0x02, 0x02, 0xf7, 0x30, 0x03}},
+ {0x0186, 64, { 0x0e, 0x90, 0x7f, 0xc6, 0xe0, 0x54, 0x02, 0xf5, 0x1d, 0xa3, 0xe0, 0xf5, 0x1c, 0x80, 0x0c, 0x90, 0x7f,
+  0xc8, 0xe0, 0x54, 0x02, 0xf5, 0x1d, 0xa3, 0xe0, 0xf5, 0x1c, 0xe5, 0x3a, 0xc3, 0x95, 0x53, 0x50,
+  0x03, 0x02, 0x02, 0x68, 0xe5, 0x1d, 0x60, 0x07, 0xc2, 0x14, 0xc2, 0x05, 0x02, 0x02, 0xf7, 0x85,
+  0x1c, 0x53, 0x85, 0x1b, 0x82, 0x85, 0x1a, 0x83, 0xe0, 0x13, 0x92, 0x0d, 0x75, 0x12, 0xff}},
+ {0x01c6, 64, { 0x30, 0x0c, 0x03, 0x02, 0x02, 0x60, 0x30, 0x09, 0x03, 0x02, 0x02, 0x60, 0x90, 0x7f, 0x9b, 0xe0, 0x55,
+  0x38, 0x60, 0x03, 0x02, 0x02, 0x60, 0x30, 0x10, 0x1b, 0x85, 0x1b, 0x82, 0x85, 0x1a, 0x83, 0xa3,
+  0xe0, 0x13, 0x92, 0x9b, 0x85, 0x1b, 0x82, 0x85, 0x1a, 0x83, 0xa3, 0xa3, 0xe0, 0xf5, 0x99, 0x75,
+  0x3a, 0x03, 0x80, 0x0d, 0x85, 0x1b, 0x82, 0x85, 0x1a, 0x83, 0xa3, 0xe0, 0xf5, 0x99, 0x75}},
+ {0x0206, 64, { 0x3a, 0x02, 0xe5, 0x3a, 0xc3, 0x95, 0x53, 0x40, 0x26, 0x30, 0x03, 0x07, 0x90, 0x7f, 0xc7, 0xe4, 0xf0,
+  0x80, 0x05, 0x90, 0x7f, 0xc9, 0xe4, 0xf0, 0xe5, 0x17, 0x24, 0xff, 0x92, 0x03, 0x20, 0x0d, 0x03,
+  0x02, 0x02, 0xf7, 0xc2, 0x0d, 0x90, 0x7f, 0xbb, 0x74, 0x01, 0xf0, 0x02, 0x02, 0xf7, 0x30, 0x10,
+  0x12, 0xaf, 0x3a, 0x05, 0x3a, 0xe5, 0x1b, 0x2f, 0xf5, 0x82, 0xe4, 0x35, 0x1a, 0xf5, 0x83}},
+ {0x0246, 64, { 0xe0, 0x13, 0x92, 0x0e, 0xaf, 0x3a, 0x05, 0x3a, 0xe5, 0x1b, 0x2f, 0xf5, 0x82, 0xe4, 0x35, 0x1a, 0xf5,
+  0x83, 0xe0, 0xf5, 0x36, 0xd2, 0x0b, 0x02, 0x02, 0xf7, 0x75, 0x3a, 0x01, 0xc2, 0x14, 0x02, 0x02,
+  0xf7, 0x30, 0x0c, 0x03, 0x02, 0x02, 0xf5, 0x30, 0x09, 0x03, 0x02, 0x02, 0xf5, 0x90, 0x7f, 0x9b,
+  0xe0, 0x55, 0x38, 0x70, 0x79, 0x30, 0x10, 0x12, 0xaf, 0x3a, 0x05, 0x3a, 0xe5, 0x1b, 0x2f}},
+ {0x0286, 64, { 0xf5, 0x82, 0xe4, 0x35, 0x1a, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x9b, 0xaf, 0x3a, 0x05, 0x3a, 0xe5, 0x1b,
+  0x2f, 0xf5, 0x82, 0xe4, 0x35, 0x1a, 0xf5, 0x83, 0xe0, 0xf5, 0x99, 0xe5, 0x3a, 0xc3, 0x95, 0x53,
+  0x40, 0x22, 0x30, 0x03, 0x07, 0x90, 0x7f, 0xc7, 0xe4, 0xf0, 0x80, 0x05, 0x90, 0x7f, 0xc9, 0xe4,
+  0xf0, 0xe5, 0x17, 0x24, 0xff, 0x92, 0x03, 0x30, 0x0d, 0x36, 0xc2, 0x0d, 0x90, 0x7f, 0xbb}},
+ {0x02c6, 64, { 0x74, 0x01, 0xf0, 0x80, 0x2c, 0x30, 0x10, 0x12, 0xaf, 0x3a, 0x05, 0x3a, 0xe5, 0x1b, 0x2f, 0xf5, 0x82,
+  0xe4, 0x35, 0x1a, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x0e, 0xaf, 0x3a, 0x05, 0x3a, 0xe5, 0x1b, 0x2f,
+  0xf5, 0x82, 0xe4, 0x35, 0x1a, 0xf5, 0x83, 0xe0, 0xf5, 0x36, 0xd2, 0x0b, 0x80, 0x02, 0xc2, 0x14,
+  0xd2, 0x01, 0x20, 0x98, 0x03, 0x02, 0x04, 0x35, 0xc2, 0x98, 0x20, 0x02, 0x03, 0x02, 0x03}},
+ {0x0306, 64, { 0xa2, 0x20, 0x15, 0x27, 0xaf, 0x39, 0x05, 0x39, 0x74, 0x80, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5,
+  0x83, 0xe5, 0x99, 0xf0, 0x30, 0x10, 0x4d, 0xaf, 0x39, 0x05, 0x39, 0x74, 0x80, 0x2f, 0xf5, 0x82,
+  0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe5, 0x98, 0xf0, 0x80, 0x3a, 0x85, 0x99, 0x55, 0xe5, 0x55, 0xb5,
+  0x47, 0x04, 0xd2, 0x09, 0x80, 0x2e, 0xe5, 0x55, 0xb5, 0x46, 0x04, 0xc2, 0x09, 0x80, 0x25}},
+ {0x0346, 64, { 0xaf, 0x39, 0x05, 0x39, 0x74, 0x80, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe5, 0x55, 0xf0,
+  0x30, 0x10, 0x11, 0xaf, 0x39, 0x05, 0x39, 0x74, 0x80, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5,
+  0x83, 0xe5, 0x98, 0xf0, 0xd2, 0x0f, 0xe5, 0x39, 0xc3, 0x95, 0x43, 0x50, 0x03, 0x02, 0x04, 0x33,
+  0x90, 0x7f, 0xb8, 0xe0, 0x30, 0xe1, 0x16, 0xe5, 0x39, 0xc3, 0x94, 0x40, 0x50, 0x03, 0x02}},
+ {0x0386, 64, { 0x04, 0x33, 0x15, 0x39, 0x15, 0x39, 0x05, 0x2b, 0x43, 0x34, 0x01, 0x02, 0x04, 0x33, 0x90, 0x7f, 0xb7,
+  0xe5, 0x39, 0xf0, 0x75, 0x39, 0x00, 0xc2, 0x02, 0x02, 0x04, 0x33, 0x20, 0x15, 0x27, 0xaf, 0x39,
+  0x05, 0x39, 0x74, 0x00, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe5, 0x99, 0xf0, 0x30,
+  0x10, 0x4d, 0xaf, 0x39, 0x05, 0x39, 0x74, 0x00, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5}},
+ {0x03c6, 64, { 0x83, 0xe5, 0x98, 0xf0, 0x80, 0x3a, 0x85, 0x99, 0x55, 0xe5, 0x55, 0xb5, 0x47, 0x04, 0xd2, 0x09, 0x80,
+  0x2e, 0xe5, 0x55, 0xb5, 0x46, 0x04, 0xc2, 0x09, 0x80, 0x25, 0xaf, 0x39, 0x05, 0x39, 0x74, 0x00,
+  0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe5, 0x55, 0xf0, 0x30, 0x10, 0x11, 0xaf, 0x39,
+  0x05, 0x39, 0x74, 0x00, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe5, 0x98, 0xf0}},
+ {0x0406, 64, { 0xd2, 0x0f, 0xe5, 0x39, 0xc3, 0x95, 0x43, 0x40, 0x24, 0x90, 0x7f, 0xb6, 0xe0, 0x30, 0xe1, 0x12, 0xe5,
+  0x39, 0xc3, 0x94, 0x40, 0x40, 0x16, 0x15, 0x39, 0x15, 0x39, 0x05, 0x2b, 0x43, 0x34, 0x01, 0x80,
+  0x0b, 0x90, 0x7f, 0xb9, 0xe5, 0x39, 0xf0, 0x75, 0x39, 0x00, 0xd2, 0x02, 0xd2, 0x01, 0x30, 0x01,
+  0x05, 0xc2, 0x01, 0x02, 0x00, 0x56, 0xd0, 0xd0, 0xd0, 0x86, 0xd0, 0x82, 0xd0, 0x83, 0xd0}},
+ {0x0446, 64, { 0xe0, 0x32, 0x90, 0x7f, 0xbc, 0xe0, 0x20, 0xe1, 0x54, 0xe5, 0x34, 0x60, 0x50, 0xe5, 0x31, 0x70, 0x4c,
+  0xe5, 0x34, 0x30, 0xe1, 0x0b, 0xe4, 0xf5, 0x2f, 0x75, 0x34, 0x01, 0x75, 0x31, 0x02, 0x80, 0x0e,
+  0xa2, 0x08, 0xe4, 0x33, 0xf5, 0x2f, 0xc2, 0x08, 0xe4, 0xf5, 0x34, 0x75, 0x31, 0x10, 0xe4, 0xf5,
+  0x56, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x24, 0x25, 0x56, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12}},
+ {0x0486, 64, { 0x0c, 0x79, 0xff, 0x74, 0x00, 0x25, 0x56, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xef, 0xf0, 0x05,
+  0x56, 0xe5, 0x56, 0xb4, 0x0c, 0xdb, 0x90, 0x7f, 0xbd, 0x74, 0x0c, 0xf0, 0x90, 0x7f, 0xca, 0xe0,
+  0x30, 0xe1, 0x03, 0x02, 0x05, 0xd1, 0xe4, 0xf5, 0x56, 0x74, 0x40, 0x25, 0x56, 0xf5, 0x82, 0xe4,
+  0x34, 0x7d, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x56, 0x7c, 0x00, 0x7b, 0x00, 0x24, 0x3b, 0xf9}},
+ {0x04c6, 64, { 0xec, 0x34, 0x00, 0xfa, 0xef, 0x12, 0x0c, 0x92, 0x05, 0x56, 0xe5, 0x56, 0xb4, 0x18, 0xdb, 0xe5, 0x3b,
+  0x60, 0x11, 0x75, 0xc9, 0x20, 0x75, 0xc8, 0x36, 0x85, 0x3c, 0xca, 0x85, 0x3d, 0xcb, 0xe4, 0x90,
+  0x7f, 0x9f, 0xf0, 0xe5, 0x3e, 0x13, 0x92, 0x10, 0x92, 0x9f, 0x85, 0x3f, 0x38, 0xe5, 0x40, 0x13,
+  0x92, 0x15, 0xe5, 0x41, 0x60, 0x09, 0x90, 0x7f, 0x98, 0xe0, 0x54, 0xfb, 0xf0, 0x80, 0x07}},
+ {0x0506, 64, { 0x90, 0x7f, 0x98, 0xe0, 0x44, 0x04, 0xf0, 0xe5, 0x42, 0x60, 0x09, 0x90, 0x7f, 0x98, 0xe0, 0x54, 0x7f,
+  0xf0, 0x80, 0x07, 0x90, 0x7f, 0x98, 0xe0, 0x44, 0x80, 0xf0, 0xe5, 0x48, 0x60, 0x0b, 0xc2, 0x0c,
+  0xc2, 0x09, 0x90, 0x7f, 0x95, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x49, 0x60, 0x0c, 0xd2, 0x09, 0x43,
+  0x34, 0x01, 0x90, 0x7f, 0x95, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x4a, 0x60, 0x0d, 0xc2, 0xaf}},
+ {0x0546, 64, { 0xc2, 0x0b, 0xd2, 0x00, 0xe4, 0xf5, 0x53, 0xf5, 0x3a, 0xd2, 0xaf, 0xe5, 0x4b, 0x60, 0x05, 0x30, 0x15,
+  0x02, 0xd2, 0x09, 0xe5, 0x4c, 0x60, 0x15, 0x90, 0x7f, 0x95, 0xe0, 0x54, 0xfd, 0xf0, 0x90, 0x7f,
+  0x9e, 0xe0, 0x44, 0x02, 0xf0, 0x90, 0x7f, 0x98, 0xe0, 0x54, 0xfd, 0xf0, 0xe5, 0x4d, 0x60, 0x0a,
+  0xd2, 0x9c, 0xc2, 0x98, 0x75, 0x2c, 0x01, 0x75, 0x31, 0x1e, 0xe5, 0x4e, 0x60, 0x07, 0xc2}},
+ {0x0586, 64, { 0x9c, 0xe4, 0xf5, 0x39, 0xf5, 0x2c, 0xe5, 0x4f, 0x60, 0x03, 0xe4, 0xf5, 0x39, 0xe5, 0x50, 0x60, 0x02,
+  0xd2, 0x07, 0xe5, 0x51, 0x60, 0x0a, 0xe5, 0x4d, 0x70, 0x02, 0xf5, 0x31, 0xe5, 0x51, 0x42, 0x34,
+  0xe5, 0x52, 0x60, 0x1f, 0x90, 0x7f, 0xd7, 0x74, 0x11, 0xf0, 0x74, 0x31, 0xf0, 0x74, 0x12, 0xf0,
+  0x74, 0x32, 0xf0, 0x74, 0x13, 0xf0, 0x74, 0x33, 0xf0, 0x74, 0x14, 0xf0, 0x74, 0x34, 0xf0}},
+ {0x05c6, 64, { 0xd2, 0x03, 0xd2, 0x02, 0xd2, 0x08, 0xe4, 0x90, 0x7f, 0xcb, 0xf0, 0xa2, 0x0c, 0xe4, 0x33, 0xff, 0x65,
+  0x29, 0x60, 0x05, 0x8f, 0x29, 0x43, 0x34, 0x01, 0xa2, 0x09, 0xe4, 0x33, 0xff, 0x65, 0x2a, 0x60,
+  0x05, 0x8f, 0x2a, 0x43, 0x34, 0x01, 0x90, 0x7f, 0x9b, 0xe0, 0xff, 0x54, 0x08, 0x64, 0x08, 0xf5,
+  0x57, 0x65, 0x25, 0x60, 0x06, 0x85, 0x57, 0x25, 0x43, 0x34, 0x01, 0xef, 0x54, 0x10, 0x64}},
+ {0x0606, 64, { 0x10, 0xf5, 0x57, 0x65, 0x26, 0x60, 0x06, 0x85, 0x57, 0x26, 0x43, 0x34, 0x01, 0xef, 0x54, 0x40, 0x64,
+  0x40, 0xf5, 0x57, 0x65, 0x27, 0x60, 0x06, 0x85, 0x57, 0x27, 0x43, 0x34, 0x01, 0xef, 0x54, 0x20,
+  0x64, 0x20, 0xf5, 0x57, 0x65, 0x28, 0x60, 0x06, 0x85, 0x57, 0x28, 0x43, 0x34, 0x01, 0x90, 0x7f,
+  0x9a, 0xe0, 0x54, 0x40, 0x64, 0x40, 0xf5, 0x57, 0x65, 0x2e, 0x60, 0x06, 0x85, 0x57, 0x2e}},
+ {0x0646, 64, { 0x43, 0x34, 0x01, 0x30, 0x07, 0x35, 0xc2, 0xaf, 0x30, 0x02, 0x18, 0x90, 0x7f, 0xb8, 0xe0, 0x20, 0xe1,
+  0x27, 0xe5, 0x39, 0x60, 0x09, 0x90, 0x7f, 0xb7, 0xf0, 0xe4, 0xf5, 0x39, 0xc2, 0x02, 0xc2, 0x07,
+  0x80, 0x16, 0x90, 0x7f, 0xb6, 0xe0, 0x20, 0xe1, 0x0f, 0xe5, 0x39, 0x60, 0x09, 0x90, 0x7f, 0xb9,
+  0xf0, 0xe4, 0xf5, 0x39, 0xd2, 0x02, 0xc2, 0x07, 0xd2, 0xaf, 0x20, 0x05, 0x3d, 0x30, 0x03}},
+ {0x0686, 64, { 0x1e, 0x90, 0x7f, 0xc6, 0xe0, 0x20, 0xe1, 0x33, 0x90, 0x7e, 0x40, 0xe0, 0x13, 0x92, 0x0d, 0x75, 0x3a,
+  0x01, 0x90, 0x7f, 0xc7, 0xe0, 0xf5, 0x53, 0xd2, 0x05, 0x75, 0x12, 0xff, 0x80, 0x1c, 0x90, 0x7f,
+  0xc8, 0xe0, 0x20, 0xe1, 0x15, 0x90, 0x7d, 0xc0, 0xe0, 0x13, 0x92, 0x0d, 0x75, 0x3a, 0x01, 0x90,
+  0x7f, 0xc9, 0xe0, 0xf5, 0x53, 0xd2, 0x05, 0x75, 0x12, 0xff, 0x20, 0x14, 0x33, 0x20, 0x00}},
+ {0x06c6, 64, { 0x06, 0xe5, 0x3a, 0x65, 0x53, 0x70, 0x2a, 0x30, 0x05, 0x1a, 0x30, 0x03, 0x09, 0xe4, 0x90, 0x7f, 0xc7,
+  0xf0, 0xc2, 0x03, 0x80, 0x07, 0xe4, 0x90, 0x7f, 0xc9, 0xf0, 0xd2, 0x03, 0xc2, 0x05, 0xe4, 0xf5,
+  0x53, 0xf5, 0x3a, 0x30, 0x0d, 0x0a, 0xc2, 0x0d, 0xc2, 0x00, 0x90, 0x7f, 0xbb, 0x74, 0x01, 0xf0,
+  0x30, 0x14, 0x03, 0x02, 0x07, 0xbf, 0x20, 0x05, 0x03, 0x02, 0x07, 0xbf, 0x30, 0x0c, 0x03}},
+ {0x0706, 64, { 0x02, 0x07, 0xbf, 0x30, 0x09, 0x03, 0x02, 0x07, 0xbf, 0x90, 0x7f, 0x9b, 0xe0, 0x55, 0x38, 0x60, 0x03,
+  0x02, 0x07, 0xbf, 0x30, 0x03, 0x0c, 0x7e, 0x7e, 0x7f, 0x40, 0x75, 0x58, 0x7e, 0x75, 0x59, 0x40,
+  0x80, 0x0a, 0x7e, 0x7d, 0x7f, 0xc0, 0x75, 0x58, 0x7d, 0x75, 0x59, 0xc0, 0x30, 0x10, 0x12, 0xaf,
+  0x3a, 0x05, 0x3a, 0xe5, 0x59, 0x2f, 0xf5, 0x82, 0xe4, 0x35, 0x58, 0xf5, 0x83, 0xe0, 0x13}},
+ {0x0746, 64, { 0x92, 0x1a, 0xaf, 0x3a, 0x05, 0x3a, 0xe5, 0x59, 0x2f, 0xf5, 0x82, 0xe4, 0x35, 0x58, 0xf5, 0x83, 0xe0,
+  0xf5, 0x57, 0xe5, 0x3a, 0xc3, 0x95, 0x53, 0x50, 0x2a, 0x30, 0x10, 0x12, 0xaf, 0x3a, 0x05, 0x3a,
+  0xe5, 0x59, 0x2f, 0xf5, 0x82, 0xe4, 0x35, 0x58, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x0e, 0xaf, 0x3a,
+  0x05, 0x3a, 0xe5, 0x59, 0x2f, 0xf5, 0x82, 0xe4, 0x35, 0x58, 0xf5, 0x83, 0xe0, 0xf5, 0x36}},
+ {0x0786, 64, { 0xd2, 0x0b, 0x80, 0x15, 0xc2, 0x0b, 0x30, 0x03, 0x09, 0xe4, 0x90, 0x7f, 0xc7, 0xf0, 0xc2, 0x03, 0x80,
+  0x07, 0xe4, 0x90, 0x7f, 0xc9, 0xf0, 0xd2, 0x03, 0x30, 0x10, 0x04, 0xa2, 0x1a, 0x92, 0x9b, 0xd2,
+  0x14, 0xc2, 0xaf, 0x85, 0x57, 0x99, 0x20, 0x0b, 0x0d, 0x30, 0x0d, 0x0a, 0xc2, 0x0d, 0xc2, 0x00,
+  0x90, 0x7f, 0xbb, 0x74, 0x01, 0xf0, 0xd2, 0xaf, 0x22, 0x90, 0x7f, 0xe9, 0xe0, 0x12, 0x0c}},
+ {0x07c6, 64, { 0xa4, 0x09, 0x1c, 0x00, 0x09, 0x89, 0x01, 0x09, 0xe6, 0x03, 0x07, 0xe3, 0x06, 0x09, 0x0d, 0x08, 0x09,
+  0x01, 0x09, 0x08, 0xe9, 0x0a, 0x08, 0xf8, 0x0b, 0x00, 0x00, 0x0a, 0x24, 0x90, 0x7f, 0xeb, 0xe0,
+  0x24, 0xfe, 0x60, 0x1c, 0x14, 0x70, 0x03, 0x02, 0x08, 0x79, 0x24, 0x02, 0x60, 0x03, 0x02, 0x0a,
+  0x24, 0x74, 0x0d, 0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x87, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x0a}},
+ {0x0806, 64, { 0x2b, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x04, 0x7f, 0x02, 0x80, 0x02, 0x7f, 0x03, 0x75, 0x82, 0xd8,
+  0x75, 0x83, 0x0d, 0xef, 0xf0, 0x75, 0x82, 0xd1, 0x75, 0x83, 0x0d, 0xf0, 0x75, 0x82, 0xca, 0x75,
+  0x83, 0x0d, 0xf0, 0x75, 0x82, 0xc3, 0x75, 0x83, 0x0d, 0xf0, 0x90, 0x7f, 0xea, 0xe0, 0x04, 0x75,
+  0x82, 0x9e, 0x75, 0x83, 0x0d, 0xf0, 0x90, 0x7f, 0xef, 0xe0, 0xfe, 0x90, 0x7f, 0xee, 0xe0}},
+ {0x0846, 64, { 0x7c, 0x00, 0x24, 0x00, 0xf5, 0x5a, 0xec, 0x3e, 0xf5, 0x59, 0x75, 0x15, 0x0d, 0x75, 0x16, 0x99, 0x75,
+  0x82, 0x9b, 0x75, 0x83, 0x0d, 0xe0, 0x75, 0x13, 0x00, 0xf5, 0x14, 0xd3, 0xe5, 0x14, 0x95, 0x5a,
+  0xe5, 0x13, 0x95, 0x59, 0x40, 0x06, 0x85, 0x59, 0x13, 0x85, 0x5a, 0x14, 0x12, 0x0b, 0xba, 0x02,
+  0x0a, 0x2b, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x0b, 0x75, 0x56, 0xff, 0x75, 0x57, 0x0d, 0x75}},
+ {0x0886, 64, { 0x58, 0xdc, 0x80, 0x2d, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x0b, 0x75, 0x56, 0xff, 0x75, 0x57, 0x0d,
+  0x75, 0x58, 0xe0, 0x80, 0x1b, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x02, 0x0b, 0x75, 0x56, 0xff, 0x75,
+  0x57, 0x0d, 0x75, 0x58, 0xf0, 0x80, 0x09, 0x75, 0x56, 0xff, 0x75, 0x57, 0x0e, 0x75, 0x58, 0x1e,
+  0x90, 0x7f, 0xee, 0xe0, 0x75, 0x59, 0x00, 0xf5, 0x5a, 0xae, 0x57, 0xaf, 0x58, 0x8e, 0x15}},
+ {0x08c6, 64, { 0x8f, 0x16, 0x8f, 0x82, 0x8e, 0x83, 0xe0, 0xfe, 0xa3, 0xe0, 0x8e, 0x13, 0xf5, 0x14, 0xd3, 0x95, 0x5a,
+  0xe5, 0x13, 0x95, 0x59, 0x40, 0x06, 0x85, 0x59, 0x13, 0x85, 0x5a, 0x14, 0x12, 0x0b, 0xba, 0x02,
+  0x0a, 0x2b, 0x90, 0x7f, 0x00, 0xe5, 0x11, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x02, 0x0a,
+  0x2b, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x11, 0x02, 0x0a, 0x2b, 0x12, 0x0c, 0x24, 0x90, 0x7f}},
+ {0x0906, 64, { 0xea, 0xe0, 0xf5, 0x10, 0x02, 0x0a, 0x2b, 0x90, 0x7f, 0x00, 0xe5, 0x10, 0xf0, 0x90, 0x7f, 0xb5, 0x74,
+  0x01, 0xf0, 0x02, 0x0a, 0x2b, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0x7f, 0x60, 0x27, 0x14, 0x60, 0x34,
+  0x24, 0x02, 0x60, 0x03, 0x02, 0x0a, 0x24, 0xa2, 0x16, 0xe4, 0x33, 0xff, 0x25, 0xe0, 0xff, 0xa2,
+  0x18, 0xe4, 0x33, 0x4f, 0x90, 0x7f, 0x00, 0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74}},
+ {0x0946, 64, { 0x02, 0xf0, 0x02, 0x0a, 0x2b, 0xe4, 0x90, 0x7f, 0x00, 0xf0, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02,
+  0xf0, 0x02, 0x0a, 0x2b, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff,
+  0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe0,
+  0x54, 0xfd, 0x90, 0x7f, 0x00, 0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0}},
+ {0x0986, 64, { 0x02, 0x0a, 0x2b, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x17, 0x24, 0x02, 0x60, 0x03, 0x02, 0x0a,
+  0x2b, 0x90, 0x7f, 0xea, 0xe0, 0x64, 0x01, 0x60, 0x03, 0x02, 0x0a, 0x24, 0xc2, 0x16, 0x02, 0x0a,
+  0x2b, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x76, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4,
+  0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34}},
+ {0x09c6, 64, { 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x90, 0x7f, 0xec, 0xe0, 0x54, 0x80, 0xff, 0x13, 0x13, 0x13, 0x54, 0x1f,
+  0xff, 0xe0, 0x54, 0x07, 0x2f, 0x90, 0x7f, 0xd7, 0xf0, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x45, 0x90,
+  0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x10, 0x24, 0x02, 0x70, 0x39, 0x90, 0x7f, 0xea, 0xe0, 0x64,
+  0x01, 0x70, 0x2a, 0xd2, 0x16, 0x80, 0x2d, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x20, 0x90, 0x7f}},
+ {0x0a06, 64, { 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24,
+  0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0x80, 0x07, 0x90, 0x7f, 0xb4,
+  0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x22, 0xc2, 0x10, 0xe4, 0xf5,
+  0x10, 0xf5, 0x34, 0xc2, 0x09, 0xc2, 0x0c, 0xc2, 0x0b, 0xc2, 0x14, 0xc2, 0x0d, 0xc2, 0x15}},
+ {0x0a46, 64, { 0xc2, 0x11, 0xc2, 0x07, 0xc2, 0x12, 0xc2, 0x0f, 0xc2, 0x08, 0xf5, 0x35, 0xf5, 0x39, 0xf5, 0x53, 0xf5,
+  0x3a, 0xf5, 0x33, 0xf5, 0x30, 0xf5, 0x2f, 0xf5, 0x2e, 0xf5, 0x2d, 0xf5, 0x2c, 0xf5, 0x2b, 0xf5,
+  0x2a, 0xf5, 0x29, 0xf5, 0x28, 0xf5, 0x27, 0xf5, 0x26, 0xf5, 0x25, 0xf5, 0x24, 0xc2, 0x05, 0xc2,
+  0x17, 0xc2, 0x19, 0xc2, 0x16, 0xc2, 0x18, 0xc2, 0x04, 0xd2, 0x13, 0xc2, 0x06, 0xc2, 0x01}},
+ {0x0a86, 64, { 0x90, 0x7f, 0x92, 0xe0, 0x54, 0xfd, 0xf0, 0xd2, 0xe8, 0x43, 0xd8, 0x20, 0x90, 0x7f, 0xde, 0x74, 0x01,
+  0xf0, 0x90, 0x7f, 0xdf, 0xf0, 0x90, 0x7f, 0xab, 0x74, 0xff, 0xf0, 0x90, 0x7f, 0xa9, 0xf0, 0x90,
+  0x7f, 0xaa, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xaf, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xae,
+  0xe0, 0x44, 0x0f, 0xf0, 0x90, 0x7f, 0xac, 0x74, 0x0e, 0xf0, 0xd2, 0xaf, 0xd2, 0xbc, 0xd2}},
+ {0x0ac6, 64, { 0x1a, 0x12, 0x0f, 0x7d, 0xc2, 0x17, 0x30, 0x04, 0x03, 0x12, 0x04, 0x48, 0x30, 0x04, 0x2a, 0x30, 0x06,
+  0x27, 0xc2, 0x06, 0xe5, 0x12, 0x60, 0x16, 0x15, 0x12, 0x90, 0x7f, 0xd8, 0xe0, 0x30, 0xe6, 0x04,
+  0x7f, 0x00, 0x80, 0x02, 0x7f, 0x20, 0x90, 0x7f, 0x96, 0xef, 0xf0, 0x80, 0x06, 0x90, 0x7f, 0x96,
+  0x74, 0x20, 0xf0, 0x12, 0x0b, 0x14, 0x80, 0xcd, 0x30, 0x17, 0x07, 0xc2, 0x17, 0x12, 0x07}},
+ {0x0b06, 64, { 0xc0, 0x80, 0xc3, 0x30, 0x19, 0xc0, 0xc2, 0x19, 0x12, 0x0e, 0xdc, 0x80, 0xb9, 0x22, 0xe5, 0x31, 0x60,
+  0x02, 0x15, 0x31, 0xe5, 0x39, 0x60, 0x55, 0x65, 0x35, 0x70, 0x4b, 0xe5, 0x33, 0xf4, 0x60, 0x02,
+  0x05, 0x33, 0xe5, 0x33, 0xc3, 0x95, 0x44, 0x40, 0x43, 0xc2, 0xaf, 0x30, 0x02, 0x1b, 0x90, 0x7f,
+  0xb8, 0xe0, 0x20, 0xe1, 0x2d, 0x90, 0x7f, 0xb7, 0xe5, 0x39, 0xf0, 0xc2, 0x02, 0xe4, 0xf5}},
+ {0x0b46, 64, { 0x39, 0xf5, 0x33, 0xf5, 0x35, 0x75, 0x12, 0xff, 0x80, 0x19, 0x90, 0x7f, 0xb6, 0xe0, 0x20, 0xe1, 0x12,
+  0x90, 0x7f, 0xb9, 0xe5, 0x39, 0xf0, 0xd2, 0x02, 0xe4, 0xf5, 0x39, 0xf5, 0x33, 0xf5, 0x35, 0x75,
+  0x12, 0xff, 0xd2, 0xaf, 0x80, 0x06, 0x85, 0x39, 0x35, 0xe4, 0xf5, 0x33, 0xe5, 0x2c, 0x60, 0x30,
+  0x20, 0x0f, 0x07, 0x90, 0x7f, 0x9b, 0xe0, 0x30, 0xe0, 0x0f, 0xe5, 0x2d, 0x60, 0x06, 0xe4}},
+ {0x0b86, 64, { 0xf5, 0x2d, 0x43, 0x34, 0x01, 0xe4, 0xf5, 0x30, 0x80, 0x14, 0xe5, 0x30, 0xd3, 0x95, 0x45, 0x50, 0x0d,
+  0xe5, 0x30, 0xb5, 0x45, 0x06, 0x75, 0x2d, 0x01, 0x43, 0x34, 0x01, 0x05, 0x30, 0xc2, 0x0f, 0x22,
+  0x90, 0x7f, 0xd9, 0xe0, 0x30, 0xe2, 0x04, 0x7f, 0x00, 0x80, 0x02, 0x7f, 0x20, 0x90, 0x7f, 0x96,
+  0xef, 0xf0, 0x22, 0xe5, 0x14, 0x45, 0x13, 0x60, 0x57, 0xae, 0x13, 0xaf, 0x14, 0xd3, 0xef}},
+ {0x0bc6, 64, { 0x94, 0x40, 0xee, 0x94, 0x00, 0x40, 0x04, 0x7e, 0x00, 0x7f, 0x40, 0xc3, 0xe5, 0x14, 0x9f, 0xf5, 0x14,
+  0xe5, 0x13, 0x9e, 0xf5, 0x13, 0xe4, 0xfd, 0xed, 0xc3, 0x9f, 0xe4, 0x9e, 0x50, 0x1f, 0x85, 0x16,
+  0x82, 0x85, 0x15, 0x83, 0xe0, 0xfc, 0x74, 0x00, 0x2d, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83,
+  0xec, 0xf0, 0x0d, 0x05, 0x16, 0xe5, 0x16, 0x70, 0x02, 0x05, 0x15, 0x80, 0xda, 0x90, 0x7f}},
+ {0x0c06, 64, { 0xa9, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xac, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xb5, 0xef, 0xf0, 0x22,
+  0x90, 0x7f, 0xac, 0xe0, 0x54, 0xfe, 0xf0, 0xe4, 0x90, 0x7f, 0xb5, 0xf0, 0x22, 0xe4, 0x90, 0x7f,
+  0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0x30, 0xf0, 0x90, 0x7f, 0x96, 0x74, 0x20, 0xf0, 0x90, 0x7f,
+  0x94, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0x9d, 0x74, 0xff, 0xf0, 0x90, 0x7f, 0x97, 0x74, 0x86}},
+ {0x0c46, 64, { 0xf0, 0x90, 0x7f, 0x95, 0x74, 0x03, 0xf0, 0x90, 0x7f, 0x9e, 0x74, 0x84, 0xf0, 0x90, 0x7f, 0x98, 0xf0,
+  0xe4, 0x90, 0x7f, 0xc7, 0xf0, 0x90, 0x7f, 0xc9, 0xf0, 0x90, 0x7f, 0xcb, 0xf0, 0x75, 0x98, 0x40,
+  0x43, 0xa8, 0x10, 0x90, 0x7f, 0xde, 0x74, 0x1f, 0xf0, 0x90, 0x7f, 0xdf, 0x74, 0x0f, 0xf0, 0xd2,
+  0x04, 0x22, 0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, 0xe7, 0x22}},
+ {0x0c86, 64, { 0xbb, 0xfe, 0x02, 0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22, 0xbb, 0x01, 0x06, 0x89, 0x82,
+  0x8a, 0x83, 0xf0, 0x22, 0x50, 0x02, 0xf7, 0x22, 0xbb, 0xfe, 0x01, 0xf3, 0x22, 0xd0, 0x83, 0xd0,
+  0x82, 0xf8, 0xe4, 0x93, 0x70, 0x12, 0x74, 0x01, 0x93, 0x70, 0x0d, 0xa3, 0xa3, 0x93, 0xf8, 0x74,
+  0x01, 0x93, 0xf5, 0x82, 0x88, 0x83, 0xe4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60, 0xef, 0xa3}},
+ {0x0cc6, 64, { 0xa3, 0xa3, 0x80, 0xdf, 0xe4, 0x90, 0x7f, 0x95, 0xf0, 0x90, 0x7f, 0x94, 0xf0, 0x90, 0x7f, 0x93, 0xf0,
+  0x90, 0x7f, 0x9d, 0xe0, 0x44, 0x02, 0xf0, 0x90, 0x7f, 0x97, 0xe0, 0x44, 0x42, 0xf0, 0x90, 0x7f,
+  0x9c, 0x74, 0x10, 0xf0, 0xe4, 0x90, 0x7f, 0x96, 0xf0, 0x90, 0x7f, 0x9d, 0x74, 0xbe, 0xf0, 0x30,
+  0x16, 0x04, 0x7f, 0x80, 0x80, 0x02, 0x7f, 0x00, 0x90, 0x7f, 0x97, 0xef, 0xf0, 0xe4, 0x90}},
+ {0x0d06, 64, { 0x7f, 0x95, 0xf0, 0x90, 0x7f, 0x9e, 0xf0, 0x90, 0x7f, 0x98, 0xf0, 0x22, 0xc0, 0xe0, 0xc0, 0xf0, 0xc0,
+  0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xc0, 0xd0, 0x75, 0xd0,
+  0x08, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xa9, 0x74, 0x01, 0xf0, 0x12, 0x0b, 0xba, 0xd0, 0xd0, 0xd0,
+  0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xf0, 0xd0, 0xe0, 0x32, 0xc0}},
+ {0x0d46, 64, { 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x90, 0x7f, 0xc4,
+  0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x04, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0,
+  0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x0d86, 64, { 0x00, 0x12, 0x01, 0x10, 0x01, 0xff, 0xff, 0xff, 0x40, 0xcd, 0x06, 0x1c, 0x01, 0x01, 0x00, 0x01, 0x02,
+  0x00, 0x02, 0x09, 0x02, 0x43, 0x00, 0x01, 0x01, 0x00, 0x80, 0x32, 0x09, 0x04, 0x00, 0x00, 0x07,
+  0xff, 0x00, 0x00, 0x00, 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40,
+  0x00, 0x00, 0x07, 0x05, 0x03, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x81, 0x02, 0x40, 0x00}},
+ {0x0dc6, 64, { 0x01, 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x83, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05,
+  0x84, 0x02, 0x40, 0x00, 0x01, 0x04, 0x03, 0x09, 0x04, 0x10, 0x03, 0x4b, 0x00, 0x65, 0x00, 0x79,
+  0x00, 0x73, 0x00, 0x70, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x2e, 0x03, 0x4b, 0x00, 0x65, 0x00, 0x79,
+  0x00, 0x73, 0x00, 0x70, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x55, 0x00, 0x50, 0x00}},
+ {0x0e06, 64, { 0x53, 0x00, 0x48, 0x00, 0x31, 0x00, 0x31, 0x00, 0x32, 0x00, 0x2d, 0x00, 0x53, 0x00, 0x65, 0x00, 0x72,
+  0x00, 0x69, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x22, 0x03, 0x55, 0x00, 0x53, 0x00, 0x41, 0x00, 0x2d,
+  0x00, 0x35, 0x00, 0x33, 0x00, 0x20, 0x00, 0x32, 0x00, 0x30, 0x00, 0x30, 0x00, 0x32, 0x00, 0x61,
+  0x00, 0x70, 0x00, 0x72, 0x00, 0x32, 0x00, 0x36, 0x00, 0x00, 0x00, 0xc0, 0xe0, 0xc0, 0x83}},
+ {0x0e46, 64, { 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab,
+  0x74, 0x02, 0xf0, 0xd2, 0x06, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0,
+  0xe0, 0x32, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86,
+  0x00, 0xd2, 0x17, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x01, 0xf0, 0xd0, 0x86, 0xd0}},
+ {0x0e86, 64, { 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0,
+  0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xd2, 0x19, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab,
+  0x74, 0x08, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32,
+  0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00}},
+ {0x0ec6, 64, { 0x53, 0x91, 0xef, 0x90, 0x7f, 0xa9, 0x74, 0x02, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82,
+  0xd0, 0x83, 0xd0, 0xe0, 0x32, 0x12, 0x0c, 0xca, 0x12, 0x0f, 0xb3, 0x90, 0x7f, 0xd6, 0xe0, 0x30,
+  0xe7, 0x12, 0xe0, 0x44, 0x01, 0xf0, 0x7f, 0x0d, 0x7e, 0x00, 0x12, 0x00, 0x03, 0x90, 0x7f, 0xd6,
+  0xe0, 0x54, 0xfe, 0xf0, 0x12, 0x0c, 0x24, 0x22, 0x00, 0x02, 0x0e, 0x69, 0x00, 0x02, 0x0e}},
+ {0x0f06, 64, { 0x42, 0x00, 0x02, 0x0d, 0x45, 0x00, 0x02, 0x0e, 0x90, 0x00, 0x02, 0x0f, 0x10, 0x00, 0x02, 0x0f, 0x14,
+  0x00, 0x02, 0x0d, 0x12, 0x00, 0x02, 0x0f, 0x1c, 0x00, 0x02, 0x0e, 0xb7, 0x00, 0x02, 0x0f, 0x24,
+  0x00, 0x02, 0x0f, 0x33, 0x00, 0x02, 0x0f, 0x2c, 0x00, 0x02, 0x0f, 0x58, 0xc0, 0xe0, 0xc0, 0x83,
+  0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x53, 0x91, 0xef, 0x90}},
+ {0x0f46, 64, { 0x7f, 0xa9, 0x74, 0x04, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0,
+  0x32, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00,
+  0x53, 0x91, 0xef, 0x90, 0x7f, 0xa9, 0x74, 0x08, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0,
+  0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfb, 0xf0, 0xe0, 0x44}},
+ {0x0f86, 61, { 0x08, 0xf0, 0x30, 0x1a, 0x04, 0xe0, 0x44, 0x02, 0xf0, 0x7f, 0xf4, 0x7e, 0x01, 0x12, 0x00, 0x03, 0x90,
+  0x7f, 0xd6, 0xe0, 0x54, 0xf7, 0xf0, 0xe0, 0x44, 0x04, 0xf0, 0x22, 0x74, 0x00, 0xf5, 0x86, 0x90,
+  0xfd, 0xa5, 0x7c, 0x05, 0xa3, 0xe5, 0x82, 0x45, 0x83, 0x70, 0xf9, 0x22, 0x90, 0x7f, 0xd6, 0xe0,
+  0x44, 0x80, 0xf0, 0x43, 0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22}},
+ {0xffff,	0,	{0x00}}
+};
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/serial/keyspan_usa49wlc_fw.h linux-2.4.21-pre6/drivers/usb/serial/keyspan_usa49wlc_fw.h
--- linux-2.4.20/drivers/usb/serial/keyspan_usa49wlc_fw.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/serial/keyspan_usa49wlc_fw.h	2003-03-26 23:49:25.000000000 +0000
@@ -0,0 +1,476 @@
+/* keyspan_usa49w_fw.h
+
+	The firmware contained herein as keyspan_usa49w_fw.h is
+
+		Copyright (C) 1999-2003
+		Keyspan, A division of InnoSys Incorporated ("Keyspan")
+		
+	as an unpublished work. This notice does not imply unrestricted or
+	public access to the source code from which this firmware image is
+	derived.  Except as noted below this firmware image may not be 
+	reproduced, used, sold or transferred to any third party without 
+	Keyspan's prior written consent.  All Rights Reserved.
+
+	Permission is hereby granted for the distribution of this firmware 
+	image as part of a Linux or other Open Source operating system kernel 
+	in text or binary form as required. 
+
+	This firmware may not be modified and may only be used with  
+	Keyspan hardware.  Distribution and/or Modification of the 
+	keyspan.c driver which includes this firmware, in whole or in 
+	part, requires the inclusion of this statement."
+
+static char theFirmwareDate49[] =
+	"02/14/2002  02:37p              19,347 USA49";
+
+
+
+static char theFirmwareDate65[] =
+	"01/31/2003  09:34a              19,331 USA65";
+
+
+*/
+
+static const struct ezusb_hex_record keyspan_usa49wlc_firmware[] = {
+ {0x7f92,  1, { 0x01}},
+ {0x0033,  3, { 0x02, 0x18, 0xfb}},
+ {0x0036, 13, { 0xe5, 0x11, 0x04, 0x90, 0x78, 0x41, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22}},
+ {0x0046, 16, { 0xe4, 0xff, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xe0, 0xfe, 0xe5, 0x15}},
+ {0x0056, 16, { 0x24, 0x04, 0xfd, 0xe4, 0x35, 0x14, 0xfa, 0xa9, 0x05, 0x7b, 0x01, 0xef, 0x7c, 0x00, 0x29, 0xf9}},
+ {0x0066, 16, { 0xec, 0x3a, 0xfa, 0xee, 0x12, 0x11, 0xec, 0x0f, 0xbf, 0x22, 0xd7, 0xe5, 0x15, 0x24, 0x05, 0xf5}},
+ {0x0076, 16, { 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x70, 0x03, 0x02, 0x01, 0x34, 0xe5, 0x15, 0x24, 0x09}},
+ {0x0086, 16, { 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x70, 0x0e, 0xe5, 0x15, 0x24, 0x0a, 0xf5, 0x82}},
+ {0x0096, 16, { 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x60, 0x18, 0x7f, 0x01, 0xe4, 0xfd, 0x12, 0x16, 0x6b, 0xe5}},
+ {0x00a6, 16, { 0x15, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x54, 0xcf, 0xf0, 0x80, 0x41}},
+ {0x00b6, 16, { 0xe5, 0x15, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0xff, 0x12, 0x00, 0x03}},
+ {0x00c6, 16, { 0xe5, 0x15, 0x24, 0x07, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0xff, 0x12, 0x15, 0xab}},
+ {0x00d6, 16, { 0x7f, 0x01, 0xe5, 0x15, 0x24, 0x08, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0xfd, 0x12}},
+ {0x00e6, 16, { 0x16, 0x6b, 0xe5, 0x15, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x44, 0x30}},
+ {0x00f6, 16, { 0xf0, 0xe5, 0x15, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x44, 0x80, 0xf0}},
+ {0x0003, 16, { 0x90, 0x78, 0x41, 0x74, 0xf3, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x78, 0x41, 0x74}},
+ {0x0013, 16, { 0xf0, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0xf3, 0xf0, 0xe5, 0x15, 0x24}},
+ {0x0023, 16, { 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22}},
+ {0x0043,  3, { 0x02, 0x1b, 0x00}},
+ {0x0000,  3, { 0x02, 0x10, 0x90}},
+ {0x0106, 64, { 0x90, 0x78, 0x41, 0x74, 0xf4, 0xf0, 0xe5, 0x15, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83,
+  0xe0, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x78, 0x41, 0x74, 0xf2, 0xf0, 0xe5, 0x15, 0x24, 0x36, 0xf5,
+  0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x44, 0x06, 0x90, 0xc0, 0x00, 0xf0, 0xe5, 0x15, 0x24,
+  0x0b, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x60, 0x32, 0xe5, 0x15, 0x24, 0x0c}},
+ {0x0146, 64, { 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x54, 0x3f, 0xff, 0xe5, 0x15, 0x24, 0x37, 0xf5, 0x82,
+  0xe4, 0x35, 0x14, 0xf5, 0x83, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0xf3, 0xf0, 0xe5, 0x15, 0x24,
+  0x37, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x90, 0xc0, 0x00, 0xf0, 0xe5, 0x15, 0x24,
+  0x0d, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x70, 0x03, 0x02, 0x02, 0x4f, 0xe5}},
+ {0x0186, 64, { 0x15, 0x24, 0x17, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x60, 0x11, 0xe5, 0x15, 0x24, 0x32,
+  0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x44, 0x04, 0xf0, 0x80, 0x0f, 0xe5, 0x15, 0x24,
+  0x32, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x54, 0xfb, 0xf0, 0xe4, 0xff, 0xe5, 0x15,
+  0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0xfd, 0x12, 0x16, 0x6b, 0xe5}},
+ {0x01c6, 64, { 0x15, 0x24, 0x0e, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x60, 0x11, 0xe5, 0x15, 0x24, 0x33,
+  0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x44, 0x80, 0xf0, 0x80, 0x0f, 0xe5, 0x15, 0x24,
+  0x33, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0xf0, 0xe5, 0x15, 0x24, 0x33,
+  0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x54, 0xfc, 0xf0, 0xe5, 0x15, 0x24, 0x0f}},
+ {0x0206, 64, { 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x60, 0x2f, 0xe5, 0x15, 0x24, 0x33, 0xf5, 0x82, 0xe4,
+  0x35, 0x14, 0xf5, 0x83, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x15, 0x24, 0x10, 0xf5, 0x82, 0xe4, 0x35,
+  0x14, 0xf5, 0x83, 0xe0, 0xff, 0x12, 0x16, 0x0b, 0xe5, 0x15, 0x24, 0x11, 0xf5, 0x82, 0xe4, 0x35,
+  0x14, 0xf5, 0x83, 0xe0, 0xff, 0x12, 0x16, 0x3b, 0xe5, 0x15, 0x24, 0x33, 0xf5, 0x82, 0xe4}},
+ {0x0246, 64, { 0x35, 0x14, 0xf5, 0x83, 0xe0, 0xff, 0x12, 0x15, 0xdb, 0xe5, 0x15, 0x24, 0x14, 0xf5, 0x82, 0xe4, 0x35,
+  0x14, 0xf5, 0x83, 0xe0, 0x60, 0x44, 0xe5, 0x15, 0x24, 0x15, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5,
+  0x83, 0xe0, 0x60, 0x11, 0xe5, 0x15, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0,
+  0x44, 0x01, 0xf0, 0x80, 0x0f, 0xe5, 0x15, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5}},
+ {0x0286, 64, { 0x83, 0xe0, 0x54, 0xfe, 0xf0, 0x90, 0x78, 0x41, 0x74, 0xf4, 0xf0, 0xe5, 0x15, 0x24, 0x39, 0xf5, 0x82,
+  0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x90, 0xc0, 0x00, 0xf0, 0xe5, 0x15, 0x24, 0x12, 0xf5, 0x82,
+  0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x60, 0x44, 0xe5, 0x15, 0x24, 0x13, 0xf5, 0x82, 0xe4, 0x35,
+  0x14, 0xf5, 0x83, 0xe0, 0x60, 0x11, 0xe5, 0x15, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35, 0x14}},
+ {0x02c6, 64, { 0xf5, 0x83, 0xe0, 0x44, 0x02, 0xf0, 0x80, 0x0f, 0xe5, 0x15, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35, 0x14,
+  0xf5, 0x83, 0xe0, 0x54, 0xfd, 0xf0, 0x90, 0x78, 0x41, 0x74, 0xf4, 0xf0, 0xe5, 0x15, 0x24, 0x39,
+  0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x90, 0xc0, 0x00, 0xf0, 0xe5, 0x15, 0x24, 0x16,
+  0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x15, 0x24, 0x35, 0xf5, 0x82}},
+ {0x0306, 64, { 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xef, 0xf0, 0xe5, 0x15, 0x24, 0x17, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5,
+  0x83, 0xe0, 0x30, 0xe0, 0x11, 0xe5, 0x15, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83,
+  0xe0, 0x44, 0x40, 0xf0, 0x80, 0x0f, 0xe5, 0x15, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5,
+  0x83, 0xe0, 0x54, 0xbf, 0xf0, 0xe5, 0x15, 0x24, 0x18, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5}},
+ {0x0346, 64, { 0x83, 0xe0, 0xff, 0xe5, 0x15, 0x24, 0x3b, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xef, 0xf0, 0xe5,
+  0x15, 0x24, 0x19, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x60, 0x11, 0xe5, 0x15, 0x24,
+  0x39, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x44, 0x10, 0xf0, 0x80, 0x0f, 0xe5, 0x15,
+  0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x54, 0xef, 0xf0, 0x90, 0x78}},
+ {0x0386, 64, { 0x41, 0x74, 0xf4, 0xf0, 0xe5, 0x15, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x90,
+  0xc0, 0x00, 0xf0, 0xe5, 0x15, 0x24, 0x1a, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x60,
+  0x6b, 0xe5, 0x15, 0x24, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x54, 0xbf, 0xf0,
+  0x90, 0x78, 0x41, 0x74, 0xf3, 0xf0, 0xe5, 0x15, 0x24, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x14}},
+ {0x03c6, 64, { 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x78, 0x41, 0x74, 0xf1, 0xf0, 0x12, 0x00,
+  0x36, 0xef, 0x54, 0xfe, 0x90, 0xc0, 0x00, 0xf0, 0xe5, 0x15, 0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35,
+  0x14, 0xf5, 0x83, 0xe0, 0x54, 0xfd, 0xff, 0xf0, 0xfd, 0xe4, 0xff, 0x12, 0x16, 0x6b, 0xe5, 0x15,
+  0x24, 0x2c, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x15, 0x24, 0x2b}},
+ {0x0406, 64, { 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x16, 0x42, 0x13, 0xe5, 0x15, 0x24, 0x1b,
+  0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x70, 0x0e, 0xe5, 0x15, 0x24, 0x25, 0xf5, 0x82,
+  0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x60, 0x28, 0xe5, 0x15, 0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35,
+  0x14, 0xf5, 0x83, 0xe0, 0x44, 0x02, 0xff, 0xf0, 0xfd, 0xe4, 0xff, 0x12, 0x16, 0x6b, 0xe5}},
+ {0x0446, 64, { 0x15, 0x24, 0x2b, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0xe5, 0x16, 0x42, 0x13,
+  0xe5, 0x15, 0x24, 0x1c, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0xff, 0x70, 0x0e, 0xe5,
+  0x15, 0x24, 0x25, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x60, 0x2a, 0x90, 0x78, 0x41,
+  0x74, 0xf2, 0xf0, 0xe5, 0x15, 0x24, 0x36, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0}},
+ {0x0486, 64, { 0x44, 0x04, 0x90, 0xc0, 0x00, 0xf0, 0xef, 0x60, 0x0f, 0xe5, 0x15, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35,
+  0x14, 0xf5, 0x83, 0xe0, 0x44, 0x04, 0xf0, 0xe5, 0x15, 0x24, 0x1d, 0xf5, 0x82, 0xe4, 0x35, 0x14,
+  0xf5, 0x83, 0xe0, 0x60, 0x27, 0xe5, 0x15, 0x24, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83,
+  0xe0, 0x44, 0x40, 0xf0, 0x90, 0x78, 0x41, 0x74, 0xf3, 0xf0, 0xe5, 0x15, 0x24, 0x37, 0xf5}},
+ {0x04c6, 64, { 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0xe5, 0x15, 0x24, 0x1e,
+  0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x60, 0x28, 0xe5, 0x15, 0x24, 0x32, 0xf5, 0x82,
+  0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x54, 0xfe, 0xff, 0xf0, 0xfd, 0xe4, 0xff, 0x12, 0x16, 0x6b,
+  0xe5, 0x15, 0x24, 0x2d, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0xe5}},
+ {0x0506, 64, { 0x16, 0x42, 0x13, 0xe5, 0x15, 0x24, 0x1f, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x70, 0x0e,
+  0xe5, 0x15, 0x24, 0x25, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x60, 0x27, 0xe5, 0x15,
+  0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x44, 0x01, 0xff, 0xf0, 0xfd, 0xe4,
+  0xff, 0x12, 0x16, 0x6b, 0xe5, 0x15, 0x24, 0x2d, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83}},
+ {0x0546, 64, { 0xe4, 0xf0, 0xe5, 0x16, 0x42, 0x13, 0xe5, 0x15, 0x24, 0x20, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83,
+  0xe0, 0x70, 0x0e, 0xe5, 0x15, 0x24, 0x25, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x60,
+  0x18, 0x90, 0x78, 0x41, 0x74, 0xf2, 0xf0, 0xe5, 0x15, 0x24, 0x36, 0xf5, 0x82, 0xe4, 0x35, 0x14,
+  0xf5, 0x83, 0xe0, 0x44, 0x02, 0x90, 0xc0, 0x00, 0xf0, 0xe5, 0x15, 0x24, 0x21, 0xf5, 0x82}},
+ {0x0586, 64, { 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x60, 0x0f, 0xe5, 0x15, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x14,
+  0xf5, 0x83, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x15, 0x24, 0x22, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5,
+  0x83, 0xe0, 0x60, 0x1f, 0xe5, 0x15, 0x24, 0x2e, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0x74,
+  0x01, 0xf0, 0xe5, 0x15, 0x24, 0x3a, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe4, 0xf0}},
+ {0x05c6, 64, { 0xe5, 0x16, 0x42, 0x13, 0xe5, 0x15, 0x24, 0x23, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x60,
+  0x03, 0x12, 0x18, 0x7a, 0xe5, 0x15, 0x24, 0x24, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0,
+  0x60, 0x23, 0xe5, 0x15, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x44, 0x08,
+  0xf0, 0xe5, 0x16, 0xc4, 0x54, 0xf0, 0xff, 0x42, 0x11, 0x90, 0x7f, 0x96, 0xe0, 0x4f, 0xf0}},
+ {0x0606, 64, { 0x90, 0x78, 0x41, 0xe0, 0x4f, 0xf0, 0xe5, 0x15, 0x24, 0x25, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83,
+  0xe0, 0x60, 0x24, 0xe5, 0x15, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x54,
+  0xf7, 0xf0, 0xe5, 0x16, 0xc4, 0x54, 0xf0, 0xf4, 0xff, 0x52, 0x11, 0x90, 0x7f, 0x96, 0xe0, 0x5f,
+  0xf0, 0x90, 0x78, 0x41, 0xe0, 0x5f, 0xf0, 0x22, 0x90, 0x7f, 0xe9, 0xe0, 0x12, 0x11, 0xfe}},
+ {0x0646, 64, { 0x07, 0x99, 0x00, 0x08, 0x0d, 0x01, 0x08, 0x79, 0x03, 0x06, 0x62, 0x06, 0x07, 0x8a, 0x08, 0x07, 0x7e,
+  0x09, 0x07, 0x66, 0x0a, 0x07, 0x75, 0x0b, 0x00, 0x00, 0x08, 0xc8, 0x90, 0x7f, 0xeb, 0xe0, 0x24,
+  0xfe, 0x60, 0x1c, 0x14, 0x70, 0x03, 0x02, 0x07, 0x14, 0x24, 0x02, 0x60, 0x03, 0x02, 0x07, 0x5c,
+  0x74, 0x19, 0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x00, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x08, 0xcf}},
+ {0x0686, 64, { 0x90, 0x7f, 0xea, 0xe0, 0x04, 0x75, 0x82, 0x17, 0x75, 0x83, 0x19, 0xf0, 0x90, 0x7f, 0xea, 0xe0, 0x30,
+  0xe0, 0x04, 0x7f, 0x02, 0x80, 0x02, 0x7f, 0x03, 0x75, 0x82, 0x82, 0x75, 0x83, 0x19, 0xef, 0xf0,
+  0x75, 0x82, 0x6d, 0x75, 0x83, 0x19, 0xf0, 0x75, 0x82, 0x66, 0x75, 0x83, 0x19, 0xf0, 0x75, 0x82,
+  0x5f, 0x75, 0x83, 0x19, 0xf0, 0x75, 0x82, 0x58, 0x75, 0x83, 0x19, 0xf0, 0x90, 0x7f, 0xea}},
+ {0x06c6, 64, { 0xe0, 0x30, 0xe1, 0x04, 0x7f, 0x64, 0x80, 0x02, 0x7f, 0x32, 0x75, 0x82, 0x1a, 0x75, 0x83, 0x19, 0xef,
+  0xf0, 0x90, 0x7f, 0xef, 0xe0, 0xfe, 0x90, 0x7f, 0xee, 0xe0, 0x7c, 0x00, 0x24, 0x00, 0xf5, 0x18,
+  0xec, 0x3e, 0xf5, 0x17, 0x75, 0x33, 0x19, 0x75, 0x34, 0x12, 0x75, 0x82, 0x14, 0x75, 0x83, 0x19,
+  0xe0, 0x75, 0x27, 0x00, 0xf5, 0x28, 0xd3, 0xe5, 0x28, 0x95, 0x18, 0xe5, 0x27, 0x95, 0x17}},
+ {0x0706, 64, { 0x40, 0x06, 0x85, 0x17, 0x27, 0x85, 0x18, 0x28, 0x12, 0x13, 0x0d, 0x02, 0x08, 0xcf, 0x90, 0x7f, 0xea,
+  0xe0, 0xff, 0x12, 0x14, 0x5f, 0xea, 0x49, 0x60, 0x32, 0x90, 0x7f, 0xee, 0xe0, 0x75, 0x17, 0x00,
+  0xf5, 0x18, 0xae, 0x02, 0xaf, 0x01, 0x8e, 0x33, 0x8f, 0x34, 0x8f, 0x82, 0x8e, 0x83, 0xe0, 0xfe,
+  0xa3, 0xe0, 0x8e, 0x27, 0xf5, 0x28, 0xd3, 0x95, 0x18, 0xe5, 0x27, 0x95, 0x17, 0x40, 0x06}},
+ {0x0746, 64, { 0x85, 0x17, 0x27, 0x85, 0x18, 0x28, 0x12, 0x13, 0x0d, 0x02, 0x08, 0xcf, 0x90, 0x7f, 0xb4, 0xe0, 0x44,
+  0x01, 0xf0, 0x02, 0x08, 0xcf, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x08, 0xcf, 0x90,
+  0x7f, 0x00, 0xe5, 0x25, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x02, 0x08, 0xcf, 0x90, 0x7f,
+  0xea, 0xe0, 0xf5, 0x25, 0x02, 0x08, 0xcf, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x22, 0x12, 0x0a}},
+ {0x0786, 64, { 0xce, 0x02, 0x08, 0xcf, 0x90, 0x7f, 0x00, 0xe5, 0x22, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x02,
+  0x08, 0xcf, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0x7f, 0x60, 0x24, 0x14, 0x60, 0x31, 0x24, 0x02, 0x70,
+  0x5b, 0xa2, 0x00, 0xe4, 0x33, 0xff, 0x25, 0xe0, 0xff, 0xa2, 0x06, 0xe4, 0x33, 0x4f, 0x90, 0x7f,
+  0x00, 0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x08, 0xcf, 0xe4}},
+ {0x07c6, 64, { 0x90, 0x7f, 0x00, 0xf0, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x08, 0xcf, 0x90, 0x7f,
+  0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0,
+  0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x54, 0xfd, 0x90, 0x7f, 0x00, 0xf0,
+  0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x08, 0xcf, 0x90, 0x7f, 0xb4}},
+ {0x0806, 64, { 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x08, 0xcf, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x1d, 0x24, 0x02,
+  0x60, 0x03, 0x02, 0x08, 0xcf, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x05, 0xc2, 0x00, 0x02, 0x08,
+  0xcf, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x08, 0xcf, 0x90, 0x7f, 0xea, 0xe0, 0x70,
+  0x38, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54}},
+ {0x0846, 64, { 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x90, 0x7f,
+  0xec, 0xe0, 0x54, 0x80, 0xff, 0x13, 0x13, 0x13, 0x54, 0x1f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x90,
+  0x7f, 0xd7, 0xf0, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x5f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0,
+  0x80, 0x56, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x18, 0x24, 0x02, 0x70, 0x4a, 0x90}},
+ {0x0886, 64, { 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x04, 0xd2, 0x00, 0x80, 0x3f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0,
+  0x80, 0x36, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x20, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff,
+  0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34,
+  0x7f, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0x80, 0x10, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0}},
+ {0x08c6, 64, { 0x80, 0x07, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x22,
+  0xe5, 0x12, 0x54, 0x0f, 0x70, 0x03, 0x02, 0x09, 0xc8, 0x12, 0x16, 0x9a, 0xef, 0x20, 0xe1, 0x75,
+  0x12, 0x16, 0xf8, 0xef, 0x14, 0xf5, 0x18, 0x12, 0x18, 0xc5, 0xef, 0x25, 0x18, 0xff, 0xe4, 0x33,
+  0xfe, 0xc3, 0xef, 0x94, 0x80, 0xee, 0x64, 0x80, 0x94, 0x80, 0x50, 0x59, 0x85, 0x15, 0x82}},
+ {0x0906, 64, { 0x85, 0x14, 0x83, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xf5, 0x82, 0x8e, 0x83, 0xe0, 0x30, 0xe0, 0x11, 0xe5,
+  0x15, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x44, 0x80, 0xf0, 0x80, 0x0f,
+  0xe5, 0x15, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0xf0, 0xe5,
+  0x15, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x20, 0xe2, 0x12, 0xe5}},
+ {0x0946, 64, { 0x18, 0x60, 0x0e, 0xf5, 0x23, 0xef, 0x24, 0x01, 0xf5, 0x2d, 0xe4, 0x3e, 0xf5, 0x2c, 0x12, 0x14, 0xa0,
+  0xe4, 0xff, 0x12, 0x14, 0xd7, 0xe5, 0x15, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83,
+  0xe0, 0x30, 0xe7, 0x5d, 0x12, 0x18, 0xc5, 0xe5, 0x15, 0x24, 0x3b, 0xf5, 0x82, 0xe4, 0x35, 0x14,
+  0xf5, 0x83, 0xe0, 0xfe, 0xef, 0xc3, 0x9e, 0x50, 0x48, 0xe5, 0x15, 0x24, 0x2f, 0xf5, 0x82}},
+ {0x0986, 64, { 0xe4, 0x35, 0x14, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0xe5, 0x15, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x14,
+  0xf5, 0x83, 0xe0, 0x54, 0x7b, 0xf0, 0xe5, 0x15, 0x24, 0x3a, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5,
+  0x83, 0xe4, 0xf0, 0xe5, 0x16, 0x42, 0x13, 0x90, 0x7f, 0xc2, 0xe0, 0x30, 0xe1, 0x10, 0xe5, 0x15,
+  0x24, 0x26, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0xf5, 0x24, 0x80, 0x03, 0x12}},
+ {0x09c6, 64, { 0x12, 0x9c, 0x12, 0x16, 0xc9, 0xef, 0x30, 0xe1, 0x03, 0x02, 0x0a, 0xcd, 0x12, 0x17, 0xc7, 0x8f, 0x18,
+  0x12, 0x18, 0xd3, 0xe5, 0x15, 0x24, 0x38, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xef, 0xf0,
+  0xe5, 0x15, 0x24, 0x35, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x18, 0xc3,
+  0x9f, 0x50, 0x28, 0x12, 0x18, 0xa9, 0xef, 0x30, 0xe0, 0x21, 0xe5, 0x15, 0x24, 0x38, 0xf5}},
+ {0x0a06, 64, { 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x20, 0xe7, 0x12, 0xe5, 0x15, 0x24, 0x31, 0xf5, 0x82, 0xe4,
+  0x35, 0x14, 0xf5, 0x83, 0xe0, 0x20, 0xe1, 0x03, 0x02, 0x0a, 0xcd, 0xe5, 0x15, 0x24, 0x31, 0xf5,
+  0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x54, 0xfd, 0xf0, 0xe5, 0x18, 0x70, 0x03, 0x02, 0x0a,
+  0xcd, 0xb4, 0x80, 0x0f, 0xe5, 0x15, 0x24, 0x38, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83}},
+ {0x0a46, 64, { 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x15, 0x24, 0x38, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0xff,
+  0x30, 0xe7, 0x29, 0xe5, 0x18, 0xd3, 0x94, 0x20, 0x40, 0x03, 0x75, 0x18, 0x20, 0x85, 0x18, 0x23,
+  0x85, 0x15, 0x82, 0x85, 0x14, 0x83, 0xa3, 0xa3, 0xe0, 0xfc, 0xa3, 0xe0, 0x8c, 0x2c, 0xf5, 0x2d,
+  0x12, 0x13, 0xcf, 0xe5, 0x18, 0x25, 0xe0, 0xff, 0x12, 0x15, 0x0d, 0x22, 0xe5, 0x18, 0xd3}},
+ {0x0a86, 64, { 0x94, 0x3f, 0x40, 0x03, 0x75, 0x18, 0x3f, 0x85, 0x18, 0x23, 0xe5, 0x15, 0x24, 0x38, 0xf5, 0x82, 0xe4,
+  0x35, 0x14, 0xf5, 0x83, 0xe0, 0xff, 0x85, 0x15, 0x82, 0x85, 0x14, 0x83, 0xa3, 0xa3, 0xe0, 0xfc,
+  0xa3, 0xe0, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x85, 0x15, 0x82, 0x85, 0x14, 0x83, 0xa3, 0xa3,
+  0xe0, 0xfe, 0xa3, 0xe0, 0x24, 0x01, 0xf5, 0x2d, 0xe4, 0x3e, 0xf5, 0x2c, 0x12, 0x14, 0x1d}},
+ {0x0ac6, 64, { 0xe5, 0x18, 0x04, 0xff, 0x12, 0x15, 0x0d, 0x22, 0xe4, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74,
+  0xff, 0xf0, 0xe4, 0x90, 0x7f, 0x96, 0xf0, 0x90, 0x7f, 0x94, 0xf0, 0x90, 0x78, 0x4a, 0x04, 0xf0,
+  0xf5, 0x8e, 0x90, 0x7f, 0x95, 0x74, 0xc0, 0xf0, 0x90, 0x7f, 0x9e, 0x74, 0x3f, 0xf0, 0x90, 0x7f,
+  0x98, 0x74, 0x2f, 0xf0, 0x90, 0x78, 0x43, 0x74, 0xf7, 0xf0, 0xe4, 0x90, 0x78, 0x41, 0xf0}},
+ {0x0b06, 64, { 0x90, 0x7f, 0xdf, 0x74, 0x9f, 0xf0, 0x90, 0x7f, 0xde, 0xf0, 0x90, 0x7f, 0x92, 0xe0, 0x44, 0x02, 0xf0,
+  0x7e, 0x7b, 0x7f, 0xc0, 0x75, 0x14, 0x7b, 0x75, 0x15, 0xc0, 0x90, 0x7f, 0x98, 0x74, 0x2e, 0xf0,
+  0x75, 0x16, 0x01, 0x12, 0x0f, 0x28, 0x7e, 0x7b, 0x7f, 0xc0, 0x75, 0x14, 0x7b, 0x75, 0x15, 0xc0,
+  0x90, 0x7f, 0x98, 0x74, 0x2e, 0xf0, 0x75, 0x16, 0x01, 0xe5, 0x15, 0x24, 0x26, 0xf5, 0x82}},
+ {0x0b46, 64, { 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe4, 0xf0, 0x7e, 0x7e, 0x7f, 0x40, 0x85, 0x15, 0x82, 0x85, 0x14, 0x83,
+  0x74, 0x7e, 0xf0, 0xa3, 0x74, 0x40, 0xf0, 0x7e, 0x7e, 0x7f, 0x80, 0x85, 0x15, 0x82, 0x85, 0x14,
+  0x83, 0xa3, 0xa3, 0x74, 0x7e, 0xf0, 0xa3, 0x74, 0x80, 0xf0, 0x7e, 0x7c, 0x7f, 0x00, 0x75, 0x14,
+  0x7c, 0x75, 0x15, 0x00, 0x90, 0x7f, 0x98, 0x74, 0x2d, 0xf0, 0x75, 0x16, 0x02, 0x12, 0x0f}},
+ {0x0b86, 64, { 0x28, 0x7e, 0x7c, 0x7f, 0x00, 0x75, 0x14, 0x7c, 0x75, 0x15, 0x00, 0x90, 0x7f, 0x98, 0x74, 0x2d, 0xf0,
+  0x75, 0x16, 0x02, 0xe5, 0x15, 0x24, 0x26, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0x74, 0x01,
+  0xf0, 0x7e, 0x7d, 0x7f, 0xc0, 0x85, 0x15, 0x82, 0x85, 0x14, 0x83, 0x74, 0x7d, 0xf0, 0xa3, 0x74,
+  0xc0, 0xf0, 0x7e, 0x7e, 0x7f, 0x00, 0x85, 0x15, 0x82, 0x85, 0x14, 0x83, 0xa3, 0xa3, 0x74}},
+ {0x0bc6, 64, { 0x7e, 0xf0, 0xa3, 0x74, 0x00, 0xf0, 0x7e, 0x7c, 0x7f, 0x40, 0x75, 0x14, 0x7c, 0x75, 0x15, 0x40, 0x90,
+  0x7f, 0x98, 0x74, 0x2b, 0xf0, 0x75, 0x16, 0x04, 0x12, 0x0f, 0x28, 0x7e, 0x7c, 0x7f, 0x40, 0x75,
+  0x14, 0x7c, 0x75, 0x15, 0x40, 0x90, 0x7f, 0x98, 0x74, 0x2b, 0xf0, 0x75, 0x16, 0x04, 0xe5, 0x15,
+  0x24, 0x26, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0x74, 0x02, 0xf0, 0x7e, 0x7d, 0x7f}},
+ {0x0c06, 64, { 0x40, 0x85, 0x15, 0x82, 0x85, 0x14, 0x83, 0x74, 0x7d, 0xf0, 0xa3, 0x74, 0x40, 0xf0, 0x7e, 0x7d, 0x7f,
+  0x80, 0x85, 0x15, 0x82, 0x85, 0x14, 0x83, 0xa3, 0xa3, 0x74, 0x7d, 0xf0, 0xa3, 0x74, 0x80, 0xf0,
+  0x7e, 0x7c, 0x7f, 0x80, 0x75, 0x14, 0x7c, 0x75, 0x15, 0x80, 0x90, 0x7f, 0x98, 0x74, 0x27, 0xf0,
+  0x75, 0x16, 0x08, 0x12, 0x0f, 0x28, 0x7e, 0x7c, 0x7f, 0x80, 0x75, 0x14, 0x7c, 0x75, 0x15}},
+ {0x0c46, 64, { 0x80, 0x90, 0x7f, 0x98, 0x74, 0x27, 0xf0, 0x75, 0x16, 0x08, 0xe5, 0x15, 0x24, 0x26, 0xf5, 0x82, 0xe4,
+  0x35, 0x14, 0xf5, 0x83, 0x74, 0x03, 0xf0, 0x7e, 0x7c, 0x7f, 0xc0, 0x85, 0x15, 0x82, 0x85, 0x14,
+  0x83, 0x74, 0x7c, 0xf0, 0xa3, 0x74, 0xc0, 0xf0, 0x7e, 0x7d, 0x7f, 0x00, 0x85, 0x15, 0x82, 0x85,
+  0x14, 0x83, 0xa3, 0xa3, 0x74, 0x7d, 0xf0, 0xa3, 0x74, 0x00, 0xf0, 0xc2, 0x0a, 0xc2, 0x09}},
+ {0x0c86, 64, { 0xe4, 0xf5, 0x11, 0xd2, 0x02, 0x22, 0xe5, 0x10, 0x04, 0x54, 0x03, 0xf5, 0x10, 0x14, 0x60, 0x1f, 0x14,
+  0x60, 0x31, 0x14, 0x60, 0x43, 0x24, 0x03, 0x70, 0x52, 0x7e, 0x7b, 0x7f, 0xc0, 0x75, 0x14, 0x7b,
+  0x75, 0x15, 0xc0, 0x90, 0x7f, 0x98, 0x74, 0x2e, 0xf0, 0x75, 0x16, 0x01, 0x80, 0x3d, 0x7e, 0x7c,
+  0x7f, 0x00, 0x75, 0x14, 0x7c, 0x75, 0x15, 0x00, 0x90, 0x7f, 0x98, 0x74, 0x2d, 0xf0, 0x75}},
+ {0x0cc6, 64, { 0x16, 0x02, 0x80, 0x28, 0x7e, 0x7c, 0x7f, 0x40, 0x75, 0x14, 0x7c, 0x75, 0x15, 0x40, 0x90, 0x7f, 0x98,
+  0x74, 0x2b, 0xf0, 0x75, 0x16, 0x04, 0x80, 0x13, 0x7e, 0x7c, 0x7f, 0x80, 0x75, 0x14, 0x7c, 0x75,
+  0x15, 0x80, 0x90, 0x7f, 0x98, 0x74, 0x27, 0xf0, 0x75, 0x16, 0x08, 0xe5, 0x32, 0x55, 0x16, 0x70,
+  0x03, 0x02, 0x0e, 0x27, 0xe5, 0x16, 0xf4, 0x52, 0x32, 0xe5, 0x26, 0x54, 0x7f, 0xff, 0x70}},
+ {0x0d06, 64, { 0x17, 0xe5, 0x2a, 0x55, 0x16, 0x60, 0x34, 0x90, 0x7f, 0x96, 0xe0, 0xfe, 0xe5, 0x16, 0xc4, 0x54, 0xf0,
+  0xf4, 0xfd, 0xee, 0x5d, 0xf0, 0x80, 0x23, 0xbf, 0x20, 0x20, 0xe5, 0x15, 0x24, 0x31, 0xf5, 0x82,
+  0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x30, 0xe3, 0x11, 0xe4, 0xf5, 0x2a, 0x90, 0x7f, 0x96, 0xe0,
+  0xff, 0xe5, 0x16, 0xc4, 0x54, 0xf0, 0xfe, 0xef, 0x4e, 0xf0, 0xe5, 0x15, 0x24, 0x3a, 0xf5}},
+ {0x0d46, 64, { 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x60, 0x03, 0xe0, 0x14, 0xf0, 0xe5, 0x15, 0x24, 0x34, 0xf5,
+  0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x60, 0x03, 0xe0, 0x14, 0xf0, 0xe0, 0x60, 0x03, 0x02,
+  0x0e, 0x27, 0x74, 0x0a, 0xf0, 0x12, 0x00, 0x36, 0xef, 0x54, 0x01, 0xff, 0xf5, 0x18, 0xe5, 0x15,
+  0x24, 0x2c, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x6f, 0x60, 0x07, 0xe5, 0x18}},
+ {0x0d86, 64, { 0xf0, 0xe5, 0x16, 0x42, 0x13, 0x12, 0x18, 0xe1, 0x8f, 0x18, 0xe5, 0x15, 0x24, 0x27, 0xf5, 0x82, 0xe4,
+  0x35, 0x14, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x18, 0x54, 0x10, 0xfe, 0x6f, 0x60, 0x06, 0xee, 0xf0,
+  0xe5, 0x16, 0x42, 0x13, 0xe5, 0x15, 0x24, 0x28, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0,
+  0xff, 0xe5, 0x18, 0x54, 0x80, 0xfe, 0x6f, 0x60, 0x06, 0xee, 0xf0, 0xe5, 0x16, 0x42, 0x13}},
+ {0x0dc6, 64, { 0xe5, 0x15, 0x24, 0x29, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x18, 0x54, 0x20,
+  0xfe, 0x6f, 0x60, 0x15, 0xee, 0xf0, 0xe5, 0x15, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5,
+  0x83, 0xe0, 0x30, 0xe4, 0x04, 0xe5, 0x16, 0x42, 0x13, 0xe5, 0x15, 0x24, 0x2a, 0xf5, 0x82, 0xe4,
+  0x35, 0x14, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x18, 0x54, 0x40, 0xfe, 0x6f, 0x60, 0x15, 0xee}},
+ {0x0e06, 64, { 0xf0, 0xe5, 0x15, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x30, 0xe5, 0x04, 0xe5,
+  0x16, 0x42, 0x13, 0xe5, 0x15, 0x24, 0x30, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe4, 0xf0,
+  0x22, 0x30, 0x09, 0x03, 0x02, 0x0f, 0x27, 0xe5, 0x24, 0x14, 0x60, 0x2a, 0x14, 0x60, 0x41, 0x14,
+  0x60, 0x58, 0x14, 0x60, 0x6f, 0x24, 0x04, 0x60, 0x03, 0x02, 0x0e, 0xe5, 0x7e, 0x7b, 0x7f}},
+ {0x0e46, 64, { 0xc0, 0x75, 0x14, 0x7b, 0x75, 0x15, 0xc0, 0x90, 0x7f, 0x98, 0x74, 0x2e, 0xf0, 0x75, 0x16, 0x01, 0x12,
+  0x12, 0x9c, 0x75, 0x24, 0x01, 0x22, 0x7e, 0x7c, 0x7f, 0x00, 0x75, 0x14, 0x7c, 0x75, 0x15, 0x00,
+  0x90, 0x7f, 0x98, 0x74, 0x2d, 0xf0, 0x75, 0x16, 0x02, 0x12, 0x12, 0x9c, 0x75, 0x24, 0x02, 0x22,
+  0x7e, 0x7c, 0x7f, 0x40, 0x75, 0x14, 0x7c, 0x75, 0x15, 0x40, 0x90, 0x7f, 0x98, 0x74, 0x2b}},
+ {0x0e86, 64, { 0xf0, 0x75, 0x16, 0x04, 0x12, 0x12, 0x9c, 0x75, 0x24, 0x03, 0x22, 0x7e, 0x7c, 0x7f, 0x80, 0x75, 0x14,
+  0x7c, 0x75, 0x15, 0x80, 0x90, 0x7f, 0x98, 0x74, 0x27, 0xf0, 0x75, 0x16, 0x08, 0x12, 0x12, 0x9c,
+  0x75, 0x24, 0x04, 0x22, 0x30, 0x04, 0x33, 0xc2, 0x04, 0x53, 0x13, 0xdf, 0xe4, 0xf5, 0x18, 0x7e,
+  0x00, 0x7b, 0x00, 0x74, 0x2e, 0x25, 0x18, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x11, 0xa6}},
+ {0x0ec6, 64, { 0xff, 0x74, 0x80, 0x25, 0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x18, 0xe5,
+  0x18, 0xb4, 0x03, 0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x03, 0xf0, 0x75, 0x24, 0x05, 0x22, 0xe5, 0x36,
+  0x60, 0x3b, 0xd5, 0x36, 0x0a, 0x53, 0x13, 0xef, 0x30, 0x0a, 0x04, 0xd2, 0x09, 0xc2, 0x0a, 0xe4,
+  0xf5, 0x18, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x35, 0x25, 0x18, 0xf9, 0xee, 0x34, 0x00, 0xfa}},
+ {0x0f06, 64, { 0x12, 0x11, 0xa6, 0xff, 0x74, 0x80, 0x25, 0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0,
+  0x05, 0x18, 0xe5, 0x18, 0xb4, 0x03, 0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x03, 0xf0, 0xe4, 0xf5, 0x24,
+  0x22, 0xe4, 0xf5, 0x19, 0x7e, 0x00, 0x7b, 0x01, 0xe5, 0x15, 0x25, 0x19, 0xf9, 0xee, 0x35, 0x14,
+  0xfa, 0xe4, 0x12, 0x11, 0xec, 0x05, 0x19, 0xe5, 0x19, 0xb4, 0x3c, 0xe8, 0xe5, 0x15, 0x24}},
+ {0x0f46, 64, { 0x35, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0x90, 0x78, 0x41, 0x74, 0xf3, 0xf0,
+  0xe5, 0x15, 0x24, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0x74, 0x03, 0xf0, 0x90, 0xc0,
+  0x00, 0xf0, 0x7f, 0x0c, 0xe4, 0xfd, 0x12, 0x16, 0x6b, 0x7f, 0x10, 0xe5, 0x15, 0x24, 0x33, 0xf5,
+  0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xef, 0xf0, 0x12, 0x15, 0xdb, 0x90, 0x78, 0x41, 0x74}},
+ {0x0f86, 64, { 0xf2, 0xf0, 0x7f, 0x01, 0xe5, 0x15, 0x24, 0x36, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xef, 0xf0,
+  0x44, 0x06, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x78, 0x41, 0x74, 0xf4, 0xf0, 0xe5, 0x15, 0x24, 0x39,
+  0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0x74, 0x80, 0xf0, 0x90, 0xc0, 0x00, 0xf0, 0x0f, 0xe4,
+  0xfd, 0x12, 0x16, 0x6b, 0xe4, 0xff, 0x7e, 0xa3, 0xe5, 0x15, 0x24, 0x32, 0xf5, 0x82, 0xe4}},
+ {0x0fc6, 64, { 0x35, 0x14, 0xf5, 0x83, 0xee, 0xf0, 0xfd, 0x12, 0x16, 0x6b, 0x90, 0x78, 0x41, 0x74, 0xf1, 0xf0, 0x90,
+  0xc0, 0x00, 0xe4, 0xf0, 0x7f, 0x05, 0x7d, 0x7f, 0x12, 0x16, 0x6b, 0x7f, 0x01, 0x12, 0x15, 0x43,
+  0x7f, 0x03, 0x7d, 0x07, 0x12, 0x16, 0x6b, 0x22, 0x53, 0x13, 0x3f, 0x90, 0x7b, 0xf1, 0xe0, 0x30,
+  0xe3, 0x16, 0x7e, 0x7b, 0x7f, 0xc0, 0x75, 0x14, 0x7b, 0x75, 0x15, 0xc0, 0x90, 0x7f, 0x98}},
+ {0x1006, 64, { 0x74, 0x2e, 0xf0, 0x75, 0x16, 0x01, 0x12, 0x08, 0xd7, 0x90, 0x7c, 0x31, 0xe0, 0x30, 0xe3, 0x16, 0x7e,
+  0x7c, 0x7f, 0x00, 0x75, 0x14, 0x7c, 0x75, 0x15, 0x00, 0x90, 0x7f, 0x98, 0x74, 0x2d, 0xf0, 0x75,
+  0x16, 0x02, 0x12, 0x08, 0xd7, 0x90, 0x7c, 0x71, 0xe0, 0x30, 0xe3, 0x16, 0x7e, 0x7c, 0x7f, 0x40,
+  0x75, 0x14, 0x7c, 0x75, 0x15, 0x40, 0x90, 0x7f, 0x98, 0x74, 0x2b, 0xf0, 0x75, 0x16, 0x04}},
+ {0x1046, 64, { 0x12, 0x08, 0xd7, 0x90, 0x7c, 0xb1, 0xe0, 0x30, 0xe3, 0x16, 0x7e, 0x7c, 0x7f, 0x80, 0x75, 0x14, 0x7c,
+  0x75, 0x15, 0x80, 0x90, 0x7f, 0x98, 0x74, 0x27, 0xf0, 0x75, 0x16, 0x08, 0x12, 0x08, 0xd7, 0x05,
+  0x12, 0xe5, 0x12, 0x54, 0x0f, 0xf5, 0x17, 0x70, 0x04, 0x12, 0x11, 0x1c, 0x22, 0xe5, 0x17, 0xb4,
+  0x01, 0x04, 0x12, 0x0c, 0x8c, 0x22, 0x90, 0x7f, 0xc2, 0xe0, 0x20, 0xe1, 0x08, 0xe5, 0x13}},
+ {0x1086, 64, { 0x60, 0x04, 0x12, 0x0e, 0x28, 0x22, 0x12, 0x0c, 0x8c, 0x22, 0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75,
+  0x81, 0x37, 0x02, 0x10, 0xd7, 0x02, 0x12, 0x24, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40,
+  0x03, 0xf6, 0x80, 0x01, 0xf2, 0x08, 0xdf, 0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07,
+  0x24, 0x0c, 0xc8, 0xc3, 0x33, 0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4}},
+ {0x10c6, 64, { 0x56, 0x80, 0x01, 0x46, 0xf6, 0xdf, 0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
+  0x90, 0x18, 0x45, 0xe4, 0x7e, 0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09,
+  0x54, 0x1f, 0xfe, 0xe4, 0x93, 0xa3, 0x60, 0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8,
+  0x40, 0xb8, 0xe4, 0x93, 0xa3, 0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5}},
+ {0x1106, 64, { 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf,
+  0xe9, 0xde, 0xe7, 0x80, 0xbe, 0x90, 0x7f, 0xd2, 0xe0, 0x30, 0xe1, 0x03, 0x02, 0x11, 0xa5, 0xc2,
+  0x09, 0x90, 0x7b, 0x40, 0xe0, 0x14, 0x60, 0x26, 0x14, 0x60, 0x3b, 0x14, 0x60, 0x50, 0x24, 0x83,
+  0x60, 0x64, 0x24, 0x80, 0x70, 0x63, 0x7e, 0x7b, 0x7f, 0xc0, 0x75, 0x14, 0x7b, 0x75, 0x15}},
+ {0x1146, 64, { 0xc0, 0x90, 0x7f, 0x98, 0x74, 0x2e, 0xf0, 0x75, 0x16, 0x01, 0x12, 0x00, 0x46, 0x80, 0x4b, 0x7e, 0x7c,
+  0x7f, 0x00, 0x75, 0x14, 0x7c, 0x75, 0x15, 0x00, 0x90, 0x7f, 0x98, 0x74, 0x2d, 0xf0, 0x75, 0x16,
+  0x02, 0x12, 0x00, 0x46, 0x80, 0x33, 0x7e, 0x7c, 0x7f, 0x40, 0x75, 0x14, 0x7c, 0x75, 0x15, 0x40,
+  0x90, 0x7f, 0x98, 0x74, 0x2b, 0xf0, 0x75, 0x16, 0x04, 0x12, 0x00, 0x46, 0x80, 0x1b, 0x7e}},
+ {0x1186, 64, { 0x7c, 0x7f, 0x80, 0x75, 0x14, 0x7c, 0x75, 0x15, 0x80, 0x90, 0x7f, 0x98, 0x74, 0x27, 0xf0, 0x75, 0x16,
+  0x08, 0x12, 0x00, 0x46, 0x80, 0x03, 0x12, 0x17, 0x51, 0xe4, 0x90, 0x7f, 0xd3, 0xf0, 0x22, 0xbb,
+  0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, 0xe7, 0x22, 0xbb, 0xfe, 0x02, 0xe3,
+  0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22, 0xbb, 0x01, 0x0c, 0xe5, 0x82, 0x29, 0xf5}},
+ {0x11c6, 64, { 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe6, 0x22, 0xbb,
+  0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a,
+  0xf5, 0x83, 0xe4, 0x93, 0x22, 0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xf0, 0x22, 0x50, 0x02,
+  0xf7, 0x22, 0xbb, 0xfe, 0x01, 0xf3, 0x22, 0xd0, 0x83, 0xd0, 0x82, 0xf8, 0xe4, 0x93, 0x70}},
+ {0x1206, 64, { 0x12, 0x74, 0x01, 0x93, 0x70, 0x0d, 0xa3, 0xa3, 0x93, 0xf8, 0x74, 0x01, 0x93, 0xf5, 0x82, 0x88, 0x83,
+  0xe4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60, 0xef, 0xa3, 0xa3, 0xa3, 0x80, 0xdf, 0x90, 0x7f, 0xae,
+  0xe0, 0xff, 0xd3, 0x92, 0x00, 0xe4, 0x33, 0xfe, 0xef, 0x4e, 0xf0, 0xd2, 0xe8, 0x43, 0xd8, 0x20,
+  0x90, 0x7f, 0xde, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xdf, 0xf0, 0x90, 0x7f, 0xab, 0x74, 0xff}},
+ {0x1246, 64, { 0xf0, 0x90, 0x7f, 0xa9, 0xf0, 0x90, 0x7f, 0xaa, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xaf, 0x74, 0x01,
+  0xf0, 0x90, 0x7f, 0xae, 0x74, 0x0d, 0xf0, 0xd2, 0xaf, 0xd2, 0x0b, 0x12, 0x18, 0x09, 0xc2, 0x01,
+  0xe4, 0xf5, 0x2b, 0xf5, 0x31, 0xc2, 0x07, 0xc2, 0x02, 0x75, 0x29, 0x0f, 0x90, 0x7f, 0xd8, 0xe0,
+  0x65, 0x26, 0x60, 0x06, 0x75, 0x32, 0x0f, 0xe0, 0xf5, 0x26, 0x30, 0x02, 0x03, 0x12, 0x0f}},
+ {0x1286, 64, { 0xef, 0x30, 0x01, 0x07, 0xc2, 0x01, 0x12, 0x06, 0x3f, 0x80, 0xe2, 0x30, 0x08, 0xdf, 0xc2, 0x08, 0x12,
+  0x18, 0x2a, 0x80, 0xd8, 0x22, 0xe5, 0x13, 0x55, 0x16, 0x60, 0x6a, 0xe5, 0x15, 0x24, 0x3a, 0xf5,
+  0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x70, 0x5c, 0xe5, 0x16, 0xf4, 0x52, 0x13, 0xe5, 0x15,
+  0x24, 0x26, 0xff, 0xe4, 0x35, 0x14, 0xfe, 0xe4, 0xfd, 0x0f, 0xef, 0xaa, 0x06, 0x70, 0x01}},
+ {0x12c6, 64, { 0x0e, 0x14, 0xf5, 0x82, 0x8a, 0x83, 0xe0, 0xfc, 0x74, 0x80, 0x2d, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5,
+  0x83, 0xec, 0xf0, 0x0d, 0xbd, 0x0b, 0xe2, 0x90, 0x7f, 0xc3, 0x74, 0x0b, 0xf0, 0xe5, 0x15, 0x24,
+  0x3a, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0x74, 0x10, 0xf0, 0xe5, 0x15, 0x24, 0x2e, 0xf5,
+  0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x15, 0x24, 0x2f, 0xf5, 0x82, 0xe4}},
+ {0x1306, 64, { 0x35, 0x14, 0xf5, 0x83, 0xe4, 0xf0, 0x22, 0xe5, 0x28, 0x45, 0x27, 0x60, 0x57, 0xae, 0x27, 0xaf, 0x28,
+  0xd3, 0xef, 0x94, 0x40, 0xee, 0x94, 0x00, 0x40, 0x04, 0x7e, 0x00, 0x7f, 0x40, 0xc3, 0xe5, 0x28,
+  0x9f, 0xf5, 0x28, 0xe5, 0x27, 0x9e, 0xf5, 0x27, 0xe4, 0xfd, 0xed, 0xc3, 0x9f, 0xe4, 0x9e, 0x50,
+  0x1f, 0x85, 0x34, 0x82, 0x85, 0x33, 0x83, 0xe0, 0xfc, 0x74, 0x00, 0x2d, 0xf5, 0x82, 0xe4}},
+ {0x1346, 64, { 0x34, 0x7f, 0xf5, 0x83, 0xec, 0xf0, 0x0d, 0x05, 0x34, 0xe5, 0x34, 0x70, 0x02, 0x05, 0x33, 0x80, 0xda,
+  0x90, 0x7f, 0xa9, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xac, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xb5,
+  0xef, 0xf0, 0x22, 0x90, 0x7f, 0xac, 0xe0, 0x54, 0xfe, 0xf0, 0xe4, 0x90, 0x7f, 0xb5, 0xf0, 0x22,
+  0x90, 0x7f, 0x98, 0x74, 0x0f, 0xf0, 0xe4, 0x90, 0x78, 0x4a, 0xf0, 0x90, 0x7f, 0x94, 0xf0}},
+ {0x1386, 64, { 0x90, 0x7f, 0x9d, 0x74, 0xff, 0xf0, 0xe4, 0x90, 0x7f, 0x97, 0xf0, 0x90, 0x78, 0x41, 0xf0, 0x90, 0x7f,
+  0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0xff, 0xf0, 0x30, 0x00, 0x07, 0xe5, 0x29, 0x54, 0x0f, 0xff,
+  0x80, 0x02, 0x7f, 0x00, 0x90, 0x7f, 0x96, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x1f, 0xf0, 0xe4,
+  0x90, 0x7f, 0x95, 0xf0, 0x90, 0x7f, 0x9e, 0x74, 0x3f, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0xdf}},
+ {0x13c6, 64, { 0xf0, 0x90, 0x7f, 0x92, 0xe0, 0x54, 0xfd, 0xf0, 0x22, 0x8f, 0x19, 0x05, 0x2d, 0xe5, 0x2d, 0xae, 0x2c,
+  0x70, 0x02, 0x05, 0x2c, 0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe5, 0x19, 0xf0, 0x12, 0x18, 0xef, 0x05,
+  0x2d, 0xe5, 0x2d, 0xac, 0x2c, 0x70, 0x02, 0x05, 0x2c, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0,
+  0x15, 0x23, 0xe5, 0x23, 0x60, 0x1f, 0xe5, 0x15, 0x24, 0x38, 0xf5, 0x82, 0xe4, 0x35, 0x14}},
+ {0x1406, 64, { 0xf5, 0x83, 0xc0, 0x83, 0xc0, 0x82, 0xe0, 0xfe, 0x12, 0x18, 0xd3, 0x8f, 0x19, 0xee, 0x4f, 0xd0, 0x82,
+  0xd0, 0x83, 0xf0, 0x80, 0xb5, 0x22, 0x90, 0x78, 0x41, 0xe5, 0x11, 0xf0, 0x90, 0x78, 0x4f, 0x74,
+  0xc0, 0xf0, 0xe4, 0x90, 0x78, 0x50, 0xf0, 0xe5, 0x2c, 0x90, 0x78, 0x51, 0xf0, 0xae, 0x2c, 0xe5,
+  0x2d, 0x90, 0x78, 0x52, 0xf0, 0x90, 0x78, 0x54, 0xe5, 0x23, 0xf0, 0x90, 0x78, 0x57, 0x74}},
+ {0x1446, 64, { 0x04, 0xf0, 0x90, 0x7f, 0xe2, 0xe0, 0x44, 0x10, 0xf0, 0xe0, 0x54, 0xf7, 0xf0, 0xe4, 0x90, 0x78, 0x55,
+  0xf0, 0x90, 0x78, 0x55, 0xe0, 0x60, 0xfa, 0x22, 0x8f, 0x19, 0xe4, 0xf5, 0x1a, 0x75, 0x1b, 0xff,
+  0x75, 0x1c, 0x19, 0x75, 0x1d, 0x86, 0xab, 0x1b, 0xaa, 0x1c, 0xa9, 0x1d, 0x90, 0x00, 0x01, 0x12,
+  0x11, 0xbf, 0xb4, 0x03, 0x1d, 0xaf, 0x1a, 0x05, 0x1a, 0xef, 0xb5, 0x19, 0x01, 0x22, 0x12}},
+ {0x1486, 64, { 0x11, 0xa6, 0x7e, 0x00, 0x29, 0xff, 0xee, 0x3a, 0xa9, 0x07, 0x75, 0x1b, 0xff, 0xf5, 0x1c, 0x89, 0x1d,
+  0x80, 0xd4, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00, 0x22, 0x90, 0x78, 0x41, 0xe5, 0x11, 0xf0, 0xe5,
+  0x2c, 0x90, 0x78, 0x4f, 0xf0, 0xae, 0x2c, 0xe5, 0x2d, 0x90, 0x78, 0x50, 0xf0, 0x90, 0x78, 0x51,
+  0x74, 0xc0, 0xf0, 0xe4, 0x90, 0x78, 0x52, 0xf0, 0x90, 0x78, 0x54, 0xe5, 0x23, 0xf0, 0x90}},
+ {0x14c6, 64, { 0x78, 0x57, 0x74, 0x04, 0xf0, 0xe4, 0x90, 0x78, 0x55, 0xf0, 0x90, 0x78, 0x55, 0xe0, 0x60, 0xfa, 0x22,
+  0xe5, 0x15, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x14, 0x60, 0x0f, 0x14,
+  0x60, 0x13, 0x14, 0x60, 0x17, 0x80, 0x00, 0x90, 0x7f, 0xc7, 0xef, 0xf0, 0x80, 0x13, 0x90, 0x7f,
+  0xc9, 0xef, 0xf0, 0x80, 0x0c, 0x90, 0x7f, 0xcb, 0xef, 0xf0, 0x80, 0x05, 0x90, 0x7f, 0xcd}},
+ {0x1506, 64, { 0xef, 0xf0, 0xe5, 0x16, 0x42, 0x2a, 0x22, 0xe5, 0x15, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5,
+  0x83, 0xe0, 0x14, 0x60, 0x0f, 0x14, 0x60, 0x13, 0x14, 0x60, 0x17, 0x80, 0x00, 0x90, 0x7f, 0xb7,
+  0xef, 0xf0, 0x80, 0x13, 0x90, 0x7f, 0xb9, 0xef, 0xf0, 0x80, 0x0c, 0x90, 0x7f, 0xbb, 0xef, 0xf0,
+  0x80, 0x05, 0x90, 0x7f, 0xbd, 0xef, 0xf0, 0xe5, 0x16, 0x42, 0x2a, 0x22, 0xae, 0x07, 0xe4}},
+ {0x1546, 64, { 0xff, 0xe5, 0x15, 0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0xfd, 0x12,
+  0x16, 0x6b, 0x90, 0x78, 0x41, 0x74, 0xf1, 0xf0, 0x90, 0xc0, 0x00, 0xee, 0xf0, 0xe4, 0xe5, 0x15,
+  0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x44, 0x80, 0xfd, 0x12, 0x16, 0x6b,
+  0x22, 0xc0, 0xe0, 0xc0, 0xf0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86}},
+ {0x1586, 64, { 0x75, 0x86, 0x00, 0xc0, 0xd0, 0x75, 0xd0, 0x08, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xa9, 0x74, 0x01, 0xf0,
+  0x12, 0x13, 0x0d, 0xd0, 0xd0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0,
+  0xf0, 0xd0, 0xe0, 0x32, 0x90, 0x78, 0x41, 0x74, 0xf3, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0,
+  0x90, 0x78, 0x41, 0x74, 0xf1, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74}},
+ {0x15c6, 64, { 0xf3, 0xf0, 0xe5, 0x15, 0x24, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0x90,
+  0xc0, 0x00, 0xf0, 0x22, 0x90, 0x78, 0x41, 0x74, 0xf3, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0,
+  0x90, 0x78, 0x41, 0x74, 0xf2, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0xf3,
+  0xf0, 0xe5, 0x15, 0x24, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x54, 0x7f}},
+ {0x1606, 64, { 0x90, 0xc0, 0x00, 0xf0, 0x22, 0x90, 0x78, 0x41, 0x74, 0xf3, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0,
+  0x90, 0x78, 0x41, 0x74, 0xf4, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0xf3,
+  0xf0, 0xe5, 0x15, 0x24, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0x90,
+  0xc0, 0x00, 0xf0, 0x22, 0x90, 0x78, 0x41, 0x74, 0xf3, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf}},
+ {0x1646, 64, { 0xf0, 0x90, 0x78, 0x41, 0x74, 0xf6, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0xf3,
+  0xf0, 0xe5, 0x15, 0x24, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0x90,
+  0xc0, 0x00, 0xf0, 0x22, 0x90, 0x78, 0x41, 0x74, 0xf3, 0xf0, 0xe5, 0x15, 0x24, 0x37, 0xf5, 0x82,
+  0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x78, 0x41}},
+ {0x1686, 64, { 0x74, 0xf7, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0xf5, 0xf0, 0x90, 0xc0, 0x00,
+  0xed, 0xf0, 0x22, 0xe5, 0x15, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x14,
+  0x60, 0x0e, 0x14, 0x60, 0x11, 0x14, 0x60, 0x14, 0x80, 0x00, 0x90, 0x7f, 0xc6, 0xe0, 0xff, 0x22,
+  0x90, 0x7f, 0xc8, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0xca, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0xcc}},
+ {0x16c6, 64, { 0xe0, 0xff, 0x22, 0xe5, 0x15, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x14, 0x60,
+  0x0e, 0x14, 0x60, 0x11, 0x14, 0x60, 0x14, 0x80, 0x00, 0x90, 0x7f, 0xb6, 0xe0, 0xff, 0x22, 0x90,
+  0x7f, 0xb8, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0xba, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0xbc, 0xe0, 0xff,
+  0x22, 0xe5, 0x15, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0, 0x14, 0x60}},
+ {0x1706, 64, { 0x0e, 0x14, 0x60, 0x11, 0x14, 0x60, 0x14, 0x80, 0x00, 0x90, 0x7f, 0xc7, 0xe0, 0xff, 0x22, 0x90, 0x7f,
+  0xc9, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0xcb, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0xcd, 0xe0, 0xff, 0x22,
+  0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x90,
+  0x7f, 0xc4, 0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x04, 0xf0, 0xd0, 0x86}},
+ {0x1746, 64, { 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0x90, 0x7b, 0x41, 0xe0, 0xf5, 0x36,
+  0x43, 0x13, 0x10, 0xa3, 0xe0, 0x60, 0x09, 0x90, 0x7f, 0xd7, 0x74, 0x17, 0xf0, 0x74, 0x37, 0xf0,
+  0x90, 0x7b, 0x43, 0xe0, 0xf5, 0x37, 0xa3, 0xe0, 0x54, 0xf0, 0xf5, 0x29, 0xe0, 0x60, 0x02, 0xd2,
+  0x0a, 0x22, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75}},
+ {0x1786, 64, { 0x86, 0x00, 0xd2, 0x01, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x01, 0xf0, 0xd0, 0x86, 0xd0, 0x84,
+  0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0,
+  0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xd2, 0x08, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab,
+  0x74, 0x08, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0}},
+ {0x17c6, 64, { 0x32, 0x12, 0x18, 0xb7, 0xae, 0x07, 0x12, 0x18, 0xb7, 0xad, 0x07, 0xee, 0x6d, 0x60, 0x10, 0x12, 0x18,
+  0xb7, 0xae, 0x07, 0xee, 0x6d, 0x60, 0x07, 0x12, 0x18, 0xb7, 0xad, 0x07, 0x80, 0xec, 0xaf, 0x06,
+  0x22, 0x74, 0x00, 0xf5, 0x86, 0x90, 0xfd, 0xa5, 0x7c, 0x05, 0xa3, 0xe5, 0x82, 0x45, 0x83, 0x70,
+  0xf9, 0x22, 0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x80, 0xf0, 0x43, 0x87, 0x01, 0x00, 0x00, 0x00}},
+ {0x1806, 64, { 0x00, 0x00, 0x22, 0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x04, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x30, 0x0b, 0x04,
+  0xe0, 0x44, 0x02, 0xf0, 0x7f, 0xf4, 0x7e, 0x01, 0x12, 0x18, 0x60, 0x90, 0x7f, 0xd6, 0xe0, 0x54,
+  0xf7, 0xf0, 0x22, 0x12, 0x13, 0x77, 0x12, 0x17, 0xf9, 0x90, 0x7f, 0xd6, 0xe0, 0x30, 0xe7, 0x0a,
+  0x7f, 0x05, 0x7e, 0x00, 0x12, 0x18, 0x60, 0x12, 0x18, 0x93, 0x12, 0x0a, 0xce, 0x22, 0x03}},
+ {0x1846, 64, { 0x35, 0x80, 0x00, 0x00, 0x03, 0x2e, 0x81, 0x00, 0x00, 0xc1, 0x85, 0xc1, 0x81, 0xc1, 0x08, 0xc1, 0x00,
+  0xc1, 0x06, 0x01, 0x22, 0x00, 0x01, 0x24, 0x00, 0x00, 0x8e, 0x17, 0x8f, 0x18, 0xe5, 0x18, 0x15,
+  0x18, 0xae, 0x17, 0x70, 0x02, 0x15, 0x17, 0x4e, 0x60, 0x08, 0x12, 0x17, 0xe8, 0x12, 0x17, 0xe8,
+  0x80, 0xeb, 0x22, 0xe5, 0x15, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x14, 0xf5, 0x83, 0xe0}},
+ {0x1886, 64, { 0x04, 0xff, 0x44, 0x10, 0x90, 0x7f, 0xd7, 0xf0, 0xef, 0x44, 0x30, 0xf0, 0x22, 0x90, 0x7f, 0xd6, 0xe0,
+  0x44, 0x01, 0xf0, 0x7f, 0x0d, 0x7e, 0x00, 0x12, 0x18, 0x60, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfe,
+  0xf0, 0x22, 0xe5, 0x11, 0x24, 0x02, 0x90, 0x78, 0x41, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22,
+  0xe5, 0x11, 0x24, 0x03, 0x90, 0x78, 0x41, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0xe5}},
+ {0x18c6, 64, { 0x11, 0x24, 0x04, 0x90, 0x78, 0x41, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0xe5, 0x11, 0x24, 0x05,
+  0x90, 0x78, 0x41, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0xe5, 0x11, 0x24, 0x06, 0x90, 0x78,
+  0x41, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22, 0x90, 0x78, 0x41, 0xe5, 0x11, 0xf0, 0x90, 0xc0,
+  0x00, 0xe0, 0xff, 0x22, 0x53, 0xd8, 0xef, 0x32, 0x00, 0x12, 0x01, 0x10, 0x01, 0xff, 0xff}},
+ {0x1906, 64, { 0xff, 0x40, 0xcd, 0x06, 0x2a, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x04, 0x09, 0x02, 0x74, 0x00, 0x01,
+  0x01, 0x00, 0xa0, 0x32, 0x09, 0x04, 0x00, 0x00, 0x0e, 0xff, 0x00, 0x00, 0x00, 0x07, 0x05, 0x01,
+  0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x03, 0x02, 0x40,
+  0x00, 0x00, 0x07, 0x05, 0x04, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x05, 0x02, 0x40, 0x00}},
+ {0x1946, 64, { 0x00, 0x07, 0x05, 0x06, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x07, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05,
+  0x81, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x83, 0x02,
+  0x40, 0x00, 0x01, 0x07, 0x05, 0x84, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x85, 0x02, 0x40, 0x00,
+  0x01, 0x07, 0x05, 0x86, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x87, 0x02, 0x40, 0x00, 0x01}},
+ {0x1986, 64, { 0x04, 0x03, 0x09, 0x04, 0x48, 0x03, 0x4b, 0x00, 0x65, 0x00, 0x79, 0x00, 0x73, 0x00, 0x70, 0x00, 0x61,
+  0x00, 0x6e, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x61, 0x00, 0x20, 0x00, 0x64, 0x00, 0x69, 0x00, 0x76,
+  0x00, 0x69, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x6f, 0x00, 0x66,
+  0x00, 0x20, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x6e, 0x00, 0x6f, 0x00, 0x53, 0x00, 0x79, 0x00}},
+ {0x19c6, 64, { 0x73, 0x00, 0x20, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x2e, 0x00, 0x24, 0x03, 0x4b, 0x00, 0x65,
+  0x00, 0x79, 0x00, 0x73, 0x00, 0x70, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x55, 0x00, 0x53,
+  0x00, 0x41, 0x00, 0x2d, 0x00, 0x34, 0x00, 0x39, 0x00, 0x57, 0x00, 0x4c, 0x00, 0x43, 0x00, 0x22,
+  0x03, 0x55, 0x00, 0x53, 0x00, 0x41, 0x00, 0x2d, 0x00, 0x36, 0x00, 0x35, 0x00, 0x20, 0x00}},
+ {0x1a06, 64, { 0x32, 0x00, 0x30, 0x00, 0x30, 0x00, 0x33, 0x00, 0x6a, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x33, 0x00, 0x31,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x1a46, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x1a86, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x1ac6, 64, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x17, 0x79, 0x00, 0x02, 0x1b}},
+ {0x1b06, 21, { 0x04, 0x00, 0x02, 0x17, 0x27, 0x00, 0x02, 0x17, 0xa0, 0x00, 0x02, 0x1b, 0x10, 0x00, 0x02, 0x1b, 0x14,
+  0x00, 0x02, 0x15, 0x78}},
+ {0xffff,  0, { 0x00}},
+};
+
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/serial/kobil_sct.c linux-2.4.21-pre6/drivers/usb/serial/kobil_sct.c
--- linux-2.4.20/drivers/usb/serial/kobil_sct.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/serial/kobil_sct.c	2003-03-26 23:49:20.000000000 +0000
@@ -0,0 +1,713 @@
+/*
+ *  KOBIL USB Smart Card Terminal Driver
+ *
+ *  Copyright (C) 2002  KOBIL Systems GmbH 
+ *  Author: Thomas Wahrenbruch
+ *
+ *  Contact: linuxusb@kobil.de
+ *
+ *  This program is largely derived from work by the linux-usb group
+ *  and associated source files.  Please see the usb/serial files for
+ *  individual credits and copyrights.
+ *
+ *  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.
+ *
+ *  Thanks to Greg Kroah-Hartman (greg@kroah.com) for his help and
+ *  patience.
+ *
+ * Supported readers: USB TWIN, KAAN Standard Plus and SecOVID Reader Plus
+ * (Adapter K), B1 Professional and KAAN Professional (Adapter B)
+ * 
+ * TODO: High baudrates
+ *
+ * (12/03/2002) tw
+ *      Fixed bug with Pro-readers and PNP
+ *
+ * (11/13/2002) tw
+ *      Initial version.
+ */
+
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <asm/uaccess.h>
+#include <linux/usb.h>
+
+#include <linux/ioctl.h>
+
+
+#include "kobil_sct.h"
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+	static int debug = 1;
+#else
+	static int debug;
+#endif
+
+#include "usb-serial.h"
+
+/* Version Information */
+#define DRIVER_VERSION "12/03/2002"
+#define DRIVER_AUTHOR "KOBIL Systems GmbH - http://www.kobil.com"
+#define DRIVER_DESC "KOBIL USB Smart Card Terminal Driver (experimental)"
+
+#define KOBIL_VENDOR_ID	           0x0D46
+#define KOBIL_ADAPTER_B_PRODUCT_ID 0x2011
+#define KOBIL_ADAPTER_K_PRODUCT_ID 0x2012
+#define KOBIL_USBTWIN_PRODUCT_ID   0x0078
+
+#define KOBIL_TIMEOUT    500
+#define KOBIL_BUF_LENGTH 300
+
+
+/* Function prototypes */
+static int  kobil_startup (struct usb_serial *serial);
+static void kobil_shutdown (struct usb_serial *serial);
+static int  kobil_open (struct usb_serial_port *port, struct file *filp);
+static void kobil_close (struct usb_serial_port *port, struct file *filp);
+static int  kobil_write (struct usb_serial_port *port, int from_user, 
+			 const unsigned char *buf, int count);
+static int  kobil_write_room(struct usb_serial_port *port);
+static int  kobil_ioctl(struct usb_serial_port *port, struct file *file,
+			unsigned int cmd, unsigned long arg);
+static void kobil_read_int_callback( struct urb *urb );
+static void kobil_write_callback( struct urb *purb );
+
+
+static struct usb_device_id id_table [] = {
+	{ USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_ADAPTER_B_PRODUCT_ID) },
+	{ USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_ADAPTER_K_PRODUCT_ID) },
+	{ USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_USBTWIN_PRODUCT_ID) },
+	{ }			/* Terminating entry */
+};
+
+
+MODULE_DEVICE_TABLE (usb, id_table);
+
+struct usb_serial_device_type kobil_device = {
+	.owner =                THIS_MODULE,
+	.name =			"KOBIL USB smart card terminal",
+	.id_table =		id_table,
+	.num_interrupt_in =	NUM_DONT_CARE,
+	.num_bulk_in =		0,
+	.num_bulk_out =		0,
+	.num_ports =		1,
+	.startup =		kobil_startup,
+	.shutdown =		kobil_shutdown,
+	.ioctl =		kobil_ioctl,
+	.open =			kobil_open,
+	.close =		kobil_close,
+	.write =		kobil_write,
+	.write_room =           kobil_write_room,
+	.read_int_callback =	kobil_read_int_callback,
+};
+
+
+struct kobil_private {
+	int write_int_endpoint_address;
+	int read_int_endpoint_address;
+	unsigned char buf[KOBIL_BUF_LENGTH]; // buffer for the APDU to send
+	int filled;  // index of the last char in buf
+	int cur_pos; // index of the next char to send in buf
+	__u16 device_type;
+	int line_state;
+	struct termios internal_termios;
+};
+
+
+static int kobil_startup (struct usb_serial *serial)
+{
+	int i;
+	struct kobil_private *priv;
+	struct usb_device *pdev;
+	struct usb_config_descriptor *actconfig;
+	struct usb_interface *interface;
+	struct usb_interface_descriptor *altsetting;
+	struct usb_endpoint_descriptor *endpoint;
+
+	serial->port->private = kmalloc(sizeof(struct kobil_private), GFP_KERNEL);
+	if (!serial->port->private){
+		return -1;
+	}
+ 
+	priv = (struct kobil_private *) serial->port->private;
+	priv->filled = 0;
+	priv->cur_pos = 0;
+	priv->device_type = serial->product;
+	priv->line_state = 0;
+	
+	switch (priv->device_type){
+	case KOBIL_ADAPTER_B_PRODUCT_ID:
+		printk(KERN_DEBUG "KOBIL B1 PRO / KAAN PRO detected\n");
+		break;
+	case KOBIL_ADAPTER_K_PRODUCT_ID:
+		printk(KERN_DEBUG "KOBIL KAAN Standard Plus / SecOVID Reader Plus detected\n");
+		break;
+	case KOBIL_USBTWIN_PRODUCT_ID:
+		printk(KERN_DEBUG "KOBIL USBTWIN detected\n");
+		break;
+	}
+
+	// search for the neccessary endpoints
+	pdev = serial->dev;
+ 	actconfig = pdev->actconfig;
+ 	interface = actconfig->interface;
+	altsetting = interface->altsetting;
+ 	endpoint = altsetting->endpoint;
+  
+ 	for (i = 0; i < altsetting->bNumEndpoints; i++) {
+		endpoint = &altsetting->endpoint[i];
+		if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) && 
+ 		    ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) {
+		 	dbg("%s Found interrupt out endpoint. Address: %d", __FUNCTION__, endpoint->bEndpointAddress);
+		 	priv->write_int_endpoint_address = endpoint->bEndpointAddress;
+ 		}
+ 		if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) && 
+ 		    ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) {
+		 	dbg("%s Found interrupt in  endpoint. Address: %d", __FUNCTION__, endpoint->bEndpointAddress);
+		 	priv->read_int_endpoint_address = endpoint->bEndpointAddress;
+	 	}
+	}
+	return 0;
+}
+
+
+static void kobil_shutdown (struct usb_serial *serial)
+{
+	int i;
+  	dbg("%s - port %d", __FUNCTION__, serial->port->number);
+
+	for (i=0; i < serial->num_ports; ++i) {
+		while (serial->port[i].open_count > 0) {
+			kobil_close (&serial->port[i], NULL);
+		}
+		if (serial->port[i].private) {
+			kfree(serial->port[i].private);
+		}
+	} 
+}
+
+
+static int kobil_open (struct usb_serial_port *port, struct file *filp)
+{
+	int i, result = 0;
+	struct kobil_private *priv;
+	unsigned char *transfer_buffer;
+	int transfer_buffer_length = 8;
+	int write_urb_transfer_buffer_length = 8;
+	
+  	dbg("%s - port %d", __FUNCTION__, port->number);
+	priv = (struct kobil_private *) port->private;
+	priv->line_state = 0;
+
+	if (port_paranoia_check (port, __FUNCTION__))
+		return -ENODEV;
+	
+	// someone sets the dev to 0 if the close method has been called
+	port->interrupt_in_urb->dev = port->serial->dev;
+
+	
+	/* force low_latency on so that our tty_push actually forces
+	 * the data through, otherwise it is scheduled, and with high
+	 * data rates (like with OHCI) data can get lost.
+	 */
+	port->tty->low_latency = 1;
+
+	// without this, every push_tty_char is echoed :-(  
+	port->tty->termios->c_lflag = 0;
+	port->tty->termios->c_lflag &= ~(ISIG | ICANON | ECHO | IEXTEN | XCASE);
+	port->tty->termios->c_iflag = IGNBRK | IGNPAR | IXOFF;
+	port->tty->termios->c_oflag &= ~ONLCR; // do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D)
+	
+	// set up internal termios structure 
+	priv->internal_termios.c_iflag = port->tty->termios->c_iflag;
+	priv->internal_termios.c_oflag = port->tty->termios->c_oflag;
+	priv->internal_termios.c_cflag = port->tty->termios->c_cflag;
+	priv->internal_termios.c_lflag = port->tty->termios->c_lflag;
+	
+	for (i=0; i<NCCS; i++) {
+		priv->internal_termios.c_cc[i] = port->tty->termios->c_cc[i];
+	}
+	
+	// allocate memory for transfer buffer
+	transfer_buffer = (unsigned char *) kmalloc(transfer_buffer_length, GFP_KERNEL);  
+	if (! transfer_buffer) {
+		return -1;
+	} else {
+		memset(transfer_buffer, 0, transfer_buffer_length);
+	}
+	
+	// allocate write_urb
+	if (!port->write_urb) { 
+		dbg("%s - port %d  Allocating port->write_urb", __FUNCTION__, port->number);
+		port->write_urb = usb_alloc_urb(0);  
+		if (!port->write_urb) {
+			dbg("%s - port %d usb_alloc_urb failed", __FUNCTION__, port->number);
+			return -1;
+		}
+	}
+ 
+	// allocate memory for write_urb transfer buffer
+	port->write_urb->transfer_buffer = (unsigned char *) kmalloc(write_urb_transfer_buffer_length, GFP_KERNEL);
+	if (! port->write_urb->transfer_buffer) {
+		return -1;
+	} 
+
+	// get hardware version
+	result = usb_control_msg( port->serial->dev, 
+				  usb_rcvctrlpipe(port->serial->dev, 0 ), 
+				  SUSBCRequest_GetMisc,
+				  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_IN,
+				  SUSBCR_MSC_GetHWVersion,
+				  0,
+				  transfer_buffer,
+				  transfer_buffer_length,
+				  KOBIL_TIMEOUT
+		);
+	dbg("%s - port %d Send get_HW_version URB returns: %i", __FUNCTION__, port->number, result);
+	dbg("Harware version: %i.%i.%i", transfer_buffer[0], transfer_buffer[1], transfer_buffer[2] );
+	
+	// get firmware version
+	result = usb_control_msg( port->serial->dev, 
+				  usb_rcvctrlpipe(port->serial->dev, 0 ), 
+				  SUSBCRequest_GetMisc,
+				  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_IN,
+				  SUSBCR_MSC_GetFWVersion,
+				  0,
+				  transfer_buffer,
+				  transfer_buffer_length,
+				  KOBIL_TIMEOUT
+		);
+	dbg("%s - port %d Send get_FW_version URB returns: %i", __FUNCTION__, port->number, result);
+	dbg("Firmware version: %i.%i.%i", transfer_buffer[0], transfer_buffer[1], transfer_buffer[2] );
+
+	if (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID || priv->device_type == KOBIL_ADAPTER_K_PRODUCT_ID) {
+		// Setting Baudrate, Parity and Stopbits
+		result = usb_control_msg( port->serial->dev, 
+					  usb_rcvctrlpipe(port->serial->dev, 0 ), 
+					  SUSBCRequest_SetBaudRateParityAndStopBits,
+					  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
+					  SUSBCR_SBR_9600 | SUSBCR_SPASB_EvenParity | SUSBCR_SPASB_1StopBit,
+					  0,
+					  transfer_buffer,
+					  0,
+					  KOBIL_TIMEOUT
+			);
+		dbg("%s - port %d Send set_baudrate URB returns: %i", __FUNCTION__, port->number, result);
+		
+		// reset all queues
+		result = usb_control_msg( port->serial->dev, 
+					  usb_rcvctrlpipe(port->serial->dev, 0 ), 
+					  SUSBCRequest_Misc,
+					  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
+					  SUSBCR_MSC_ResetAllQueues,
+					  0,
+					  transfer_buffer,
+					  0,
+					  KOBIL_TIMEOUT
+			);
+		dbg("%s - port %d Send reset_all_queues URB returns: %i", __FUNCTION__, port->number, result);
+	}
+
+	if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) {
+		// start reading (Adapter B 'cause PNP string)
+		result = usb_submit_urb( port->interrupt_in_urb ); 
+		dbg("%s - port %d Send read URB returns: %i", __FUNCTION__, port->number, result);
+	}
+
+	kfree(transfer_buffer);
+	return 0;
+}
+
+
+static void kobil_close (struct usb_serial_port *port, struct file *filp)
+{
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	if (port->write_urb){
+		usb_unlink_urb( port->write_urb );
+		usb_free_urb( port->write_urb );
+		port->write_urb = 0;
+	}
+	if (port->interrupt_in_urb){
+		usb_unlink_urb (port->interrupt_in_urb);
+	}
+}
+
+
+static void kobil_read_int_callback( struct urb *purb )
+{  
+	int i;
+	struct usb_serial_port *port = (struct usb_serial_port *) purb->context;
+	struct tty_struct *tty;
+	unsigned char *data = purb->transfer_buffer;
+	char *dbg_data;
+
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	if (purb->status) {
+		dbg("%s - port %d Read int status not zero: %d", __FUNCTION__, port->number, purb->status);
+		return;
+	}
+	
+	tty = port->tty; 
+	if (purb->actual_length) {
+		
+		// BEGIN DEBUG
+		dbg_data = (unsigned char *) kmalloc((3 *  purb->actual_length + 10) * sizeof(char), GFP_KERNEL);  
+		if (! dbg_data) {
+			return;
+		}
+		memset(dbg_data, 0, (3 *  purb->actual_length + 10));
+		for (i = 0; i < purb->actual_length; i++) { 
+			sprintf(dbg_data +3*i, "%02X ", data[i]); 
+		}
+		dbg(" <-- %s", dbg_data );
+		kfree(dbg_data);
+		// END DEBUG
+
+		for (i = 0; i < purb->actual_length; ++i) {
+			// if we insert more than TTY_FLIPBUF_SIZE characters, we drop them.
+			if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
+				tty_flip_buffer_push(tty);
+			}
+			// this doesn't actually push the data through unless tty->low_latency is set
+			tty_insert_flip_char(tty, data[i], 0);
+		}
+		tty_flip_buffer_push(tty);
+	}
+}
+
+
+static void kobil_write_callback( struct urb *purb )
+{
+}
+
+
+static int kobil_write (struct usb_serial_port *port, int from_user, 
+			const unsigned char *buf, int count)
+{
+	int length = 0;
+	int result = 0;
+	int todo = 0;
+	struct kobil_private * priv;
+	int i;
+	char *data;
+
+	if (count == 0) {
+		dbg("%s - port %d write request of 0 bytes", __FUNCTION__, port->number);
+		return 0;
+	}
+
+	priv = (struct kobil_private *) port->private;
+
+	if (count > (KOBIL_BUF_LENGTH - priv->filled)) {
+		dbg("%s - port %d Error: write request bigger than buffer size", __FUNCTION__, port->number);
+		return -ENOMEM;
+	}
+	
+	// BEGIN DEBUG
+	data = (unsigned char *) kmalloc((3 * count + 10) * sizeof(char), GFP_KERNEL);  
+	if (! data) {
+		return (-1);
+	}
+	memset(data, 0, (3 * count + 10));
+	for (i = 0; i < count; i++) { 
+		sprintf(data +3*i, "%02X ", buf[i]); 
+	} 
+	dbg(" %d --> %s", port->number, data );
+	kfree(data);
+	// END DEBUG
+
+	// Copy data to buffer
+	if (from_user) {
+		if (copy_from_user(priv->buf + priv->filled, buf, count)) {
+			return -EFAULT;
+		}
+	} else {
+		memcpy (priv->buf + priv->filled, buf, count);
+	}
+
+	priv->filled = priv->filled + count;
+  
+
+	// only send complete block. TWIN and adapter K use the same protocol.
+	if ( ((priv->device_type != KOBIL_ADAPTER_B_PRODUCT_ID) && (priv->filled > 2) && (priv->filled >= (priv->buf[1] + 3))) || 
+	     ((priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) && (priv->filled > 3) && (priv->filled >= (priv->buf[2] + 4))) ) {
+		
+		// stop reading (except TWIN)
+		if (priv->device_type != KOBIL_USBTWIN_PRODUCT_ID) {
+			usb_unlink_urb( port->interrupt_in_urb );
+		}
+		
+		todo = priv->filled - priv->cur_pos;
+
+		while(todo > 0) {
+			// max 8 byte in one urb (endpoint size)
+			length = (todo < 8) ? todo : 8;
+			// copy data to transfer buffer
+			memcpy(port->write_urb->transfer_buffer, priv->buf + priv->cur_pos, length );
+			
+			usb_fill_bulk_urb( port->write_urb,
+					   port->serial->dev,
+					   usb_sndbulkpipe( port->serial->dev, priv->write_int_endpoint_address),
+					   port->write_urb->transfer_buffer,
+					   length,
+					   kobil_write_callback,
+					   port
+				);
+
+			priv->cur_pos = priv->cur_pos + length;
+			result = usb_submit_urb( port->write_urb );
+			dbg("%s - port %d Send write URB returns: %i", __FUNCTION__, port->number, result);
+			todo = priv->filled - priv->cur_pos;
+
+			if (todo > 0) {
+				//mdelay(16);
+				set_current_state(TASK_UNINTERRUPTIBLE);
+				schedule_timeout(24 * HZ / 1000);
+			}
+
+		} // end while
+		
+		priv->filled = 0;
+		priv->cur_pos = 0;
+				
+		// start reading (except TWIN)	
+		if (priv->device_type != KOBIL_USBTWIN_PRODUCT_ID) {
+			// someone sets the dev to 0 if the close method has been called
+			port->interrupt_in_urb->dev = port->serial->dev;
+		
+			// start reading
+			result = usb_submit_urb( port->interrupt_in_urb ); 
+			dbg("%s - port %d Send read URB returns: %i", __FUNCTION__, port->number, result);
+		}
+		
+	}
+	return count;  
+}
+
+
+static int kobil_write_room (struct usb_serial_port *port)
+{
+	return 8;
+}
+
+
+static int  kobil_ioctl(struct usb_serial_port *port, struct file *file,
+			unsigned int cmd, unsigned long arg)
+{
+	struct kobil_private * priv;
+	int mask;
+	int result;
+	unsigned short urb_val = 0;
+	unsigned char *transfer_buffer;
+	int transfer_buffer_length = 8;
+	char *settings;
+
+	priv = (struct kobil_private *) port->private;
+	if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID) {
+		// This device doesn't support ioctl calls
+		return 0;
+	}
+
+	switch (cmd) {
+	case TCGETS:   // 0x5401
+		result = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct termios));
+		if (result) {
+			dbg("%s - port %d Error in verify_area", __FUNCTION__, port->number);
+			return(result);
+		}
+		kernel_termios_to_user_termios((struct termios *)arg, &priv->internal_termios);
+		return 0;
+
+	case TCSETS:   // 0x5402
+		if (! &port->tty->termios) {
+			dbg("%s - port %d Error: port->tty->termios is NULL", __FUNCTION__, port->number);
+			return -ENOTTY;
+		}
+		result = verify_area(VERIFY_READ, (void *)arg, sizeof(struct termios));
+		if (result) {
+			dbg("%s - port %d Error in verify_area", __FUNCTION__, port->number);
+			return result;
+		}
+		user_termios_to_kernel_termios( &priv->internal_termios, (struct termios *)arg);
+		
+		settings = (unsigned char *) kmalloc(50, GFP_KERNEL);  
+		if (! settings) {
+			return -ENOBUFS;
+		}
+		memset(settings, 0, 50);
+
+		switch (priv->internal_termios.c_cflag & CBAUD) {
+		case B1200:
+			urb_val = SUSBCR_SBR_1200;
+			strcat(settings, "1200 ");
+			break;
+		case B9600:
+		default:
+			urb_val = SUSBCR_SBR_9600;
+			strcat(settings, "9600 ");
+			break;
+		}
+
+		urb_val |= (priv->internal_termios.c_cflag & CSTOPB) ? SUSBCR_SPASB_2StopBits : SUSBCR_SPASB_1StopBit;
+		strcat(settings, (priv->internal_termios.c_cflag & CSTOPB) ? "2 StopBits " : "1 StopBit ");
+		
+		if (priv->internal_termios.c_cflag & PARENB) {
+			if  (priv->internal_termios.c_cflag & PARODD) {
+				urb_val |= SUSBCR_SPASB_OddParity;
+				strcat(settings, "Odd Parity");
+			} else {
+				urb_val |= SUSBCR_SPASB_EvenParity;
+				strcat(settings, "Even Parity");
+			}
+		} else {
+			urb_val |= SUSBCR_SPASB_NoParity;
+			strcat(settings, "No Parity");
+		}
+		dbg("%s - port %d setting port to: %s", __FUNCTION__, port->number, settings );
+
+		result = usb_control_msg( port->serial->dev, 
+					  usb_rcvctrlpipe(port->serial->dev, 0 ), 
+					  SUSBCRequest_SetBaudRateParityAndStopBits,
+					  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
+					  urb_val,
+					  0,
+					  settings,
+					  0,
+					  KOBIL_TIMEOUT
+			);
+		
+		dbg("%s - port %d Send set_baudrate URB returns: %i", __FUNCTION__, port->number, result);
+		kfree(settings);
+		return 0;
+    
+	case TCFLSH:   // 0x540B
+		result = usb_control_msg( port->serial->dev, 
+		 			  usb_rcvctrlpipe(port->serial->dev, 0 ), 
+					  SUSBCRequest_Misc,
+					  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
+					  SUSBCR_MSC_ResetAllQueues,
+					  0,
+					  NULL,
+					  0,
+					  KOBIL_TIMEOUT
+			);
+		
+		dbg("%s - port %d Send reset_all_queues (FLUSH) URB returns: %i", __FUNCTION__, port->number, result);
+		return ((result < 0) ? -EFAULT : 0);
+
+	case TIOCMGET: // 0x5415
+		// allocate memory for transfer buffer
+		transfer_buffer = (unsigned char *) kmalloc(transfer_buffer_length, GFP_KERNEL);  
+		if (! transfer_buffer) {
+			return -ENOBUFS;
+		} else {
+			memset(transfer_buffer, 0, transfer_buffer_length);
+		}
+
+		result = usb_control_msg( port->serial->dev, 
+					  usb_rcvctrlpipe(port->serial->dev, 0 ), 
+					  SUSBCRequest_GetStatusLineState,
+					  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_IN,
+					  0,
+					  0,
+					  transfer_buffer,
+					  transfer_buffer_length,
+					  KOBIL_TIMEOUT
+			);
+	
+		dbg("%s - port %d Send get_status_line_state (TIOCMGET) URB returns: %i. Statusline: %02x", 
+		    __FUNCTION__, port->number, result, transfer_buffer[0]);
+	
+		if ((transfer_buffer[0] & SUSBCR_GSL_DSR) != 0) {
+			priv->line_state |= TIOCM_DSR;
+		} else {
+			priv->line_state &= ~TIOCM_DSR; 
+		}
+		
+		kfree(transfer_buffer);
+		return put_user(priv->line_state, (unsigned long *) arg);
+		
+	case TIOCMSET: // 0x5418
+		if (get_user(mask, (unsigned long *) arg)){
+			return -EFAULT;
+		}
+		if (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) {
+			if ((mask & TIOCM_DTR) != 0){
+				dbg("%s - port %d Setting DTR", __FUNCTION__, port->number);
+			} else {
+				dbg("%s - port %d Clearing DTR", __FUNCTION__, port->number);
+			} 
+			result = usb_control_msg( port->serial->dev, 
+						  usb_rcvctrlpipe(port->serial->dev, 0 ), 
+						  SUSBCRequest_SetStatusLinesOrQueues,
+						  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
+						  ( ((mask & TIOCM_DTR) != 0) ? SUSBCR_SSL_SETDTR : SUSBCR_SSL_CLRDTR),
+						  0,
+						  NULL,
+						  0,
+						  KOBIL_TIMEOUT
+				);
+			
+		} else {
+			if ((mask & TIOCM_RTS) != 0){
+				dbg("%s - port %d Setting RTS", __FUNCTION__, port->number);
+			} else {
+				dbg("%s - port %d Clearing RTS", __FUNCTION__, port->number);
+			}
+			result = usb_control_msg( port->serial->dev, 
+						  usb_rcvctrlpipe(port->serial->dev, 0 ), 
+						  SUSBCRequest_SetStatusLinesOrQueues,
+						  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
+						  (((mask & TIOCM_RTS) != 0) ? SUSBCR_SSL_SETRTS : SUSBCR_SSL_CLRRTS),
+						  0,
+						  NULL,
+						  0,
+						  KOBIL_TIMEOUT
+				);
+		}
+		dbg("%s - port %d Send set_status_line (TIOCMSET) URB returns: %i", __FUNCTION__, port->number, result);
+		return ((result < 0) ? -EFAULT : 0);
+	}
+	return 0;
+}
+
+
+static int __init kobil_init (void)
+{
+	usb_serial_register (&kobil_device);
+
+	info(DRIVER_VERSION " " DRIVER_AUTHOR);
+	info(DRIVER_DESC);
+
+	return 0;
+}
+
+
+static void __exit kobil_exit (void)
+{
+	usb_serial_deregister (&kobil_device);
+}
+
+module_init(kobil_init);
+module_exit(kobil_exit);
+
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_LICENSE( "GPL" );
+
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug enabled or not");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/serial/kobil_sct.h linux-2.4.21-pre6/drivers/usb/serial/kobil_sct.h
--- linux-2.4.20/drivers/usb/serial/kobil_sct.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/serial/kobil_sct.h	2003-03-26 23:49:35.000000000 +0000
@@ -0,0 +1,60 @@
+#define SUSBCRequest_SetBaudRateParityAndStopBits       1
+#define SUSBCR_SBR_MASK				0xFF00
+#define SUSBCR_SBR_1200				0x0100
+#define SUSBCR_SBR_9600				0x0200
+#define SUSBCR_SBR_19200			0x0400
+#define SUSBCR_SBR_28800			0x0800
+#define SUSBCR_SBR_38400			0x1000
+#define SUSBCR_SBR_57600			0x2000
+#define SUSBCR_SBR_115200			0x4000
+
+#define SUSBCR_SPASB_MASK			0x0070
+#define SUSBCR_SPASB_NoParity			0x0010
+#define SUSBCR_SPASB_OddParity			0x0020
+#define SUSBCR_SPASB_EvenParity			0x0040
+
+#define SUSBCR_SPASB_STPMASK			0x0003
+#define SUSBCR_SPASB_1StopBit			0x0001
+#define SUSBCR_SPASB_2StopBits			0x0002
+
+#define SUSBCRequest_SetStatusLinesOrQueues	2
+#define SUSBCR_SSL_SETRTS			0x0001
+#define SUSBCR_SSL_CLRRTS			0x0002
+#define SUSBCR_SSL_SETDTR			0x0004
+#define SUSBCR_SSL_CLRDTR			0x0010
+
+#define SUSBCR_SSL_PURGE_TXABORT		0x0100  // Kill the pending/current writes to the comm port.
+#define SUSBCR_SSL_PURGE_RXABORT		0x0200  // Kill the pending/current reads to the comm port.
+#define SUSBCR_SSL_PURGE_TXCLEAR		0x0400  // Kill the transmit queue if there.
+#define SUSBCR_SSL_PURGE_RXCLEAR		0x0800  // Kill the typeahead buffer if there.
+
+#define SUSBCRequest_GetStatusLineState		4
+#define SUSBCR_GSL_RXCHAR			0x0001  // Any Character received
+#define SUSBCR_GSL_TXEMPTY			0x0004  // Transmitt Queue Empty
+#define SUSBCR_GSL_CTS				0x0008  // CTS changed state
+#define SUSBCR_GSL_DSR				0x0010  // DSR changed state
+#define SUSBCR_GSL_RLSD				0x0020  // RLSD changed state
+#define SUSBCR_GSL_BREAK			0x0040  // BREAK received
+#define SUSBCR_GSL_ERR				0x0080  // Line status error occurred
+#define SUSBCR_GSL_RING				0x0100  // Ring signal detected
+
+#define SUSBCRequest_Misc			8
+#define SUSBCR_MSC_ResetReader			0x0001	// use a predefined reset sequence
+#define SUSBCR_MSC_ResetAllQueues	        0x0002	// use a predefined sequence to reset the internal queues
+
+#define SUSBCRequest_GetMisc			0x10
+#define SUSBCR_MSC_GetFWVersion			0x0001	/* get the firmware version from device,
+							   coded like this 0xHHLLBBPP
+							   with HH = Firmware Version High Byte
+							   LL = Firmware Version Low Byte
+							   BB = Build Number
+							   PP = Further Attributes
+							*/
+
+#define SUSBCR_MSC_GetHWVersion			0x0002	/* get the hardware version from device
+							   coded like this 0xHHLLPPRR
+							   with HH = Software Version High Byte
+							   LL = Software Version Low Byte
+							   PP = Further Attributes
+							   RR = Reserved for the hardware ID 
+							*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/serial/pl2303.c linux-2.4.21-pre6/drivers/usb/serial/pl2303.c
--- linux-2.4.20/drivers/usb/serial/pl2303.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/serial/pl2303.c	2003-03-26 23:49:35.000000000 +0000
@@ -69,6 +69,9 @@
 	{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
 	{ USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) },
 	{ USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },
+	{ USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) },
+	{ USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) },
+	{ USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) },
 	{ }					/* Terminating entry */
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/serial/pl2303.h linux-2.4.21-pre6/drivers/usb/serial/pl2303.h
--- linux-2.4.20/drivers/usb/serial/pl2303.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/serial/pl2303.h	2003-03-26 23:49:40.000000000 +0000
@@ -25,3 +25,12 @@
 
 #define MA620_VENDOR_ID		0x0df7
 #define MA620_PRODUCT_ID	0x0620
+
+#define RATOC_VENDOR_ID		0x0584
+#define RATOC_PRODUCT_ID	0xb000
+
+#define TRIPP_VENDOR_ID		0x2478
+#define TRIPP_PRODUCT_ID	0x2008
+
+#define RADIOSHACK_VENDOR_ID	0x1453
+#define RADIOSHACK_PRODUCT_ID	0x4026
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/serial/usbserial.c linux-2.4.21-pre6/drivers/usb/serial/usbserial.c
--- linux-2.4.20/drivers/usb/serial/usbserial.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/serial/usbserial.c	2003-03-26 23:49:31.000000000 +0000
@@ -1188,8 +1188,10 @@
 	     (dev->descriptor.idProduct == ATEN_PRODUCT_ID))) {
 		if (ifnum == 1) {
 			/* check out the endpoints of the other interface*/
-			interface = &dev->actconfig->interface[ifnum ^ 1];
-			iface_desc = &interface->altsetting[0];
+			struct usb_interface *other_iface;
+
+			other_iface = &dev->actconfig->interface[ifnum ^ 1];
+			iface_desc = &other_iface->altsetting[0];
 			for (i = 0; i < iface_desc->bNumEndpoints; ++i) {
 				endpoint = &iface_desc->endpoint[i];
 				if ((endpoint->bEndpointAddress & 0x80) &&
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/serial/visor.c linux-2.4.21-pre6/drivers/usb/serial/visor.c
--- linux-2.4.20/drivers/usb/serial/visor.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/serial/visor.c	2003-03-26 23:49:25.000000000 +0000
@@ -174,11 +174,14 @@
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_I705_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M130_ID) },
+	{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_T_ID) },
+	{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID) },
 	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_S360_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_1_ID) },
+	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NX60_ID) },
 	{ }					/* Terminating entry */
 };
 
@@ -195,11 +198,14 @@
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_I705_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M130_ID) },
+	{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_T_ID) },
+	{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_S360_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_1_ID) },
+	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NX60_ID) },
 	{ }					/* Terminating entry */
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/serial/visor.h linux-2.4.21-pre6/drivers/usb/serial/visor.h
--- linux-2.4.20/drivers/usb/serial/visor.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/serial/visor.h	2003-03-26 23:49:20.000000000 +0000
@@ -27,6 +27,8 @@
 #define PALM_I705_ID			0x0020
 #define PALM_M125_ID			0x0040
 #define PALM_M130_ID			0x0050
+#define PALM_TUNGSTEN_T_ID		0x0060
+#define PALM_TUNGSTEN_Z_ID		0x0031
 #define PALM_ZIRE_ID			0x0070
 
 #define SONY_VENDOR_ID			0x054C
@@ -34,6 +36,7 @@
 #define SONY_CLIE_4_0_ID		0x0066
 #define SONY_CLIE_S360_ID		0x0095
 #define SONY_CLIE_4_1_ID		0x009A
+#define SONY_CLIE_NX60_ID		0x00DA
 
 /****************************************************************************
  * Handspring Visor Vendor specific request codes (bRequest values)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/storage/datafab.c linux-2.4.21-pre6/drivers/usb/storage/datafab.c
--- linux-2.4.20/drivers/usb/storage/datafab.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/storage/datafab.c	2003-03-26 23:49:55.000000000 +0000
@@ -121,8 +121,8 @@
 			return US_BULK_TRANSFER_FAILED;
 		}
 
-		// -ENOENT -- we canceled this transfer
-		if (result == -ENOENT) {
+		// -ECONNRESET -- we canceled this transfer
+		if (result == -ECONNRESET) {
 			US_DEBUGP("datafab_raw_bulk:  transfer aborted\n");
 			return US_BULK_TRANSFER_ABORTED;
 		}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/storage/freecom.c linux-2.4.21-pre6/drivers/usb/storage/freecom.c
--- linux-2.4.20/drivers/usb/storage/freecom.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/storage/freecom.c	2003-03-26 23:49:37.000000000 +0000
@@ -198,7 +198,7 @@
         result = usb_stor_bulk_msg (us, ideout, opipe,
                         FCM_PACKET_LENGTH, &partial);
         if (result != 0) {
-                if (result == -ENOENT)
+                if (result == -ECONNRESET)
                         return US_BULK_TRANSFER_ABORTED;
                 else
                         return USB_STOR_TRANSPORT_ERROR;
@@ -238,7 +238,7 @@
         result = usb_stor_bulk_msg (us, idein, opipe,
                         FCM_PACKET_LENGTH, &partial);
         if (result != 0) {
-                if (result == -ENOENT)
+                if (result == -ECONNRESET)
                         return US_BULK_TRANSFER_ABORTED;
                 else
                         return USB_STOR_TRANSPORT_ERROR;
@@ -251,7 +251,7 @@
         result = usb_stor_bulk_msg (us, buffer, ipipe,
                         desired_length, &partial);
         if (result != 0) {
-                if (result == -ENOENT)
+                if (result == -ECONNRESET)
                         return US_BULK_TRANSFER_ABORTED;
                 else
                         return USB_STOR_TRANSPORT_ERROR;
@@ -292,8 +292,8 @@
                 US_DEBUGP ("Freecom readdata xpot failure: r=%d, p=%d\n",
                                 result, partial);
 
-		/* -ENOENT -- we canceled this transfer */
-		if (result == -ENOENT) {
+		/* -ECONNRESET -- we canceled this transfer */
+		if (result == -ECONNRESET) {
 			US_DEBUGP("freecom_readdata(): transfer aborted\n");
 			return US_BULK_TRANSFER_ABORTED;
 		}
@@ -333,8 +333,8 @@
                 US_DEBUGP ("Freecom writedata xpot failure: r=%d, p=%d\n",
                                 result, partial);
 
-		/* -ENOENT -- we canceled this transfer */
-		if (result == -ENOENT) {
+		/* -ECONNRESET -- we canceled this transfer */
+		if (result == -ECONNRESET) {
 			US_DEBUGP("freecom_writedata(): transfer aborted\n");
 			return US_BULK_TRANSFER_ABORTED;
 		}
@@ -396,8 +396,8 @@
                 US_DEBUGP ("freecom xport failure: r=%d, p=%d\n",
                                 result, partial);
 
-		/* -ENOENT -- we canceled this transfer */
-		if (result == -ENOENT) {
+		/* -ECONNRESET -- we canceled this transfer */
+		if (result == -ECONNRESET) {
 			US_DEBUGP("freecom_transport(): transfer aborted\n");
 			return US_BULK_TRANSFER_ABORTED;
 		}
@@ -410,8 +410,8 @@
         result = usb_stor_bulk_msg (us, fst, ipipe,
                         FCM_PACKET_LENGTH, &partial);
         US_DEBUGP("foo Status result %d %d\n", result, partial);
-	/* -ENOENT -- we canceled this transfer */
-	if (result == -ENOENT) {
+	/* -ECONNRESET -- we canceled this transfer */
+	if (result == -ECONNRESET) {
 		US_DEBUGP("freecom_transport(): transfer aborted\n");
 		return US_BULK_TRANSFER_ABORTED;
 	}
@@ -448,8 +448,8 @@
 			US_DEBUGP ("freecom xport failure: r=%d, p=%d\n",
 					result, partial);
 
-			/* -ENOENT -- we canceled this transfer */
-			if (result == -ENOENT) {
+			/* -ECONNRESET -- we canceled this transfer */
+			if (result == -ECONNRESET) {
 				US_DEBUGP("freecom_transport(): transfer aborted\n");
 				return US_BULK_TRANSFER_ABORTED;
 			}
@@ -463,8 +463,8 @@
 
 		US_DEBUGP("bar Status result %d %d\n", result, partial);
 
-		/* -ENOENT -- we canceled this transfer */
-		if (result == -ENOENT) {
+		/* -ECONNRESET -- we canceled this transfer */
+		if (result == -ECONNRESET) {
 			US_DEBUGP("freecom_transport(): transfer aborted\n");
 			return US_BULK_TRANSFER_ABORTED;
 		}
@@ -524,7 +524,7 @@
                 result = usb_stor_bulk_msg (us, fst, ipipe,
                                 FCM_PACKET_LENGTH, &partial);
 		US_DEBUG(pdump ((void *) fst, partial));
-                if (result == -ENOENT) {
+                if (result == -ECONNRESET) {
                         US_DEBUGP ("freecom_transport: transfer aborted\n");
                         return US_BULK_TRANSFER_ABORTED;
                 }
@@ -552,7 +552,7 @@
                 US_DEBUGP("FCM: Waiting for status\n");
                 result = usb_stor_bulk_msg (us, fst, ipipe,
                                 FCM_PACKET_LENGTH, &partial);
-                if (result == -ENOENT) {
+                if (result == -ECONNRESET) {
                         US_DEBUGP ("freecom_transport: transfer aborted\n");
                         return US_BULK_TRANSFER_ABORTED;
                 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/storage/isd200.c linux-2.4.21-pre6/drivers/usb/storage/isd200.c
--- linux-2.4.20/drivers/usb/storage/isd200.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/storage/isd200.c	2003-03-26 23:49:39.000000000 +0000
@@ -102,13 +102,6 @@
 #define REG_STATUS           0x80
 #define REG_COMMAND          0x80
 
-/* ATA error definitions not in <linux/hdreg.h> */
-#define ATA_ERROR_MEDIA_CHANGE       0x20
-
-/* ATA command definitions not in <linux/hdreg.h> */
-#define ATA_COMMAND_GET_MEDIA_STATUS        0xDA
-#define ATA_COMMAND_MEDIA_EJECT             0xED
-
 /* ATA drive control definitions */
 #define ATA_DC_DISABLE_INTERRUPTS    0x02
 #define ATA_DC_RESET_CONTROLLER      0x04
@@ -353,7 +346,7 @@
         struct sense_data *buf = (struct sense_data *) &srb->sense_buffer[0];
         unsigned char error = info->ATARegs[IDE_ERROR_OFFSET];
 
-	if(error & ATA_ERROR_MEDIA_CHANGE) {
+	if(error & MC_ERR) {
 		buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID;
 		buf->AdditionalSenseLength = 0xb;
 		buf->Flags = UNIT_ATTENTION;
@@ -442,8 +435,8 @@
                         return ISD200_TRANSPORT_FAILED;
                 }
 
-                /* -ENOENT -- we canceled this transfer */
-                if (result == -ENOENT) {
+                /* -ECONNRESET -- we canceled this transfer */
+                if (result == -ECONNRESET) {
                         US_DEBUGP("isd200_transfer_partial(): transfer aborted\n");
                         return ISD200_TRANSPORT_ABORTED;
                 }
@@ -581,7 +574,7 @@
 				   &partial);
         US_DEBUGP("Bulk command transfer result=%d\n", result);
     
-	if (result == -ENOENT)
+	if (result == -ECONNRESET)
 		return ISD200_TRANSPORT_ABORTED;
 	else if (result == -EPIPE) {
 		/* if we stall, we need to clear it before we go on */
@@ -610,7 +603,7 @@
         US_DEBUGP("Attempting to get CSW...\n");
         result = usb_stor_bulk_msg(us, &bcs, pipe, US_BULK_CS_WRAP_LEN, 
 				   &partial);
-        if (result == -ENOENT)
+        if (result == -ECONNRESET)
                 return ISD200_TRANSPORT_ABORTED;
 
         /* did the attempt to read the CSW fail? */
@@ -624,7 +617,7 @@
                                            US_BULK_CS_WRAP_LEN, &partial);
 
                 /* if the command was aborted, indicate that */
-                if (result == -ENOENT)
+                if (result == -ECONNRESET)
                         return ISD200_TRANSPORT_ABORTED;
         
                 /* if it fails again, we need a reset and return an error*/
@@ -1472,7 +1465,7 @@
 			ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
 			ataCdb->generic.TransferBlockSize = 1;
 			ataCdb->generic.RegisterSelect = REG_COMMAND;
-			ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
+			ataCdb->write.CommandByte = WIN_GETMEDIASTATUS;
 			srb->request_bufflen = 0;
 		} else {
 			US_DEBUGP("   Media Status not supported, just report okay\n");
@@ -1493,7 +1486,7 @@
 			ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
 			ataCdb->generic.TransferBlockSize = 1;
 			ataCdb->generic.RegisterSelect = REG_COMMAND;
-			ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
+			ataCdb->write.CommandByte = WIN_GETMEDIASTATUS;
 			srb->request_bufflen = 0;
 		} else {
 			US_DEBUGP("   Media Status not supported, just report okay\n");
@@ -1625,14 +1618,14 @@
 			ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
 			ataCdb->generic.TransferBlockSize = 0;
 			ataCdb->generic.RegisterSelect = REG_COMMAND;
-			ataCdb->write.CommandByte = ATA_COMMAND_MEDIA_EJECT;
+			ataCdb->write.CommandByte = WIN_MEDIAEJECT;
 		} else if ((srb->cmnd[4] & 0x3) == 0x1) {
 			US_DEBUGP("   Get Media Status\n");
 			ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
 			ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
 			ataCdb->generic.TransferBlockSize = 1;
 			ataCdb->generic.RegisterSelect = REG_COMMAND;
-			ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
+			ataCdb->write.CommandByte = WIN_GETMEDIASTATUS;
 			srb->request_bufflen = 0;
 		} else {
 			US_DEBUGP("   Nothing to do, just report okay\n");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/storage/jumpshot.c linux-2.4.21-pre6/drivers/usb/storage/jumpshot.c
--- linux-2.4.20/drivers/usb/storage/jumpshot.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/storage/jumpshot.c	2003-03-26 23:48:58.000000000 +0000
@@ -132,7 +132,7 @@
 
 	if (result < 0) {
 		/* if the command was aborted, indicate that */
-		if (result == -ENOENT)
+		if (result == -ECONNRESET)
 			return USB_STOR_TRANSPORT_ABORTED;
 
 		/* a stall is a fatal condition from the device */
@@ -181,8 +181,8 @@
 			return US_BULK_TRANSFER_FAILED;
 		}
 
-		// -ENOENT -- we canceled this transfer
-		if (result == -ENOENT) {
+		// -ECONNRESET -- we canceled this transfer
+		if (result == -ECONNRESET) {
 			US_DEBUGP("jumpshot_raw_bulk:  transfer aborted\n");
 			return US_BULK_TRANSFER_ABORTED;
 		}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/storage/sddr09.c linux-2.4.21-pre6/drivers/usb/storage/sddr09.c
--- linux-2.4.20/drivers/usb/storage/sddr09.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/storage/sddr09.c	2003-03-26 23:49:53.000000000 +0000
@@ -110,7 +110,7 @@
 
 	if (result < 0) {
 		/* if the command was aborted, indicate that */
-		if (result == -ENOENT)
+		if (result == -ECONNRESET)
 			return USB_STOR_TRANSPORT_ABORTED;
 
 		/* a stall is a fatal condition from the device */
@@ -161,8 +161,8 @@
                         return US_BULK_TRANSFER_FAILED;
                 }
 
-                /* -ENOENT -- we canceled this transfer */
-                if (result == -ENOENT) {
+                /* -ECONNRESET -- we canceled this transfer */
+                if (result == -ECONNRESET) {
                         US_DEBUGP("usbat_raw_bulk():"
 				" transfer aborted\n");
                         return US_BULK_TRANSFER_ABORTED;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/storage/sddr55.c linux-2.4.21-pre6/drivers/usb/storage/sddr55.c
--- linux-2.4.20/drivers/usb/storage/sddr55.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/storage/sddr55.c	2003-03-26 23:49:39.000000000 +0000
@@ -106,8 +106,8 @@
 			return US_BULK_TRANSFER_FAILED;
 		}
 
-		/* -ENOENT -- we canceled this transfer */
-		if (result == -ENOENT) {
+		/* -ECONNRESET -- we canceled this transfer */
+		if (result == -ECONNRESET) {
 			US_DEBUGP("usbat_raw_bulk():"
 				" transfer aborted\n");
 			return US_BULK_TRANSFER_ABORTED;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/storage/shuttle_usbat.c linux-2.4.21-pre6/drivers/usb/storage/shuttle_usbat.c
--- linux-2.4.20/drivers/usb/storage/shuttle_usbat.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/storage/shuttle_usbat.c	2003-03-26 23:48:58.000000000 +0000
@@ -104,7 +104,7 @@
 
 	if (result < 0) {
 		/* if the command was aborted, indicate that */
-		if (result == -ENOENT)
+		if (result == -ECONNRESET)
 			return USB_STOR_TRANSPORT_ABORTED;
 
 		/* a stall is a fatal condition from the device */
@@ -155,8 +155,8 @@
                         return US_BULK_TRANSFER_FAILED;
                 }
 
-                /* -ENOENT -- we canceled this transfer */
-                if (result == -ENOENT) {
+                /* -ECONNRESET -- we canceled this transfer */
+                if (result == -ECONNRESET) {
                         US_DEBUGP("usbat_raw_bulk():"
 				" transfer aborted\n");
                         return US_BULK_TRANSFER_ABORTED;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/storage/transport.c linux-2.4.21-pre6/drivers/usb/storage/transport.c
--- linux-2.4.20/drivers/usb/storage/transport.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/storage/transport.c	2003-03-26 23:49:29.000000000 +0000
@@ -520,7 +520,7 @@
 	}
 
 	/* did we abort this command? */
-	if (result == -ENOENT) {
+	if (result == -ECONNRESET) {
 		US_DEBUGP("usb_stor_transfer_partial(): transfer aborted\n");
 		return US_BULK_TRANSFER_ABORTED;
 	}
@@ -700,20 +700,26 @@
 		unsigned short old_sg;
 		unsigned old_request_bufflen;
 		unsigned char old_sc_data_direction;
+		unsigned char old_cmd_len;
 		unsigned char old_cmnd[MAX_COMMAND_SIZE];
 
 		US_DEBUGP("Issuing auto-REQUEST_SENSE\n");
 
 		/* save the old command */
 		memcpy(old_cmnd, srb->cmnd, MAX_COMMAND_SIZE);
+		old_cmd_len = srb->cmd_len;
 
 		/* set the command and the LUN */
+		memset(srb->cmnd, 0, MAX_COMMAND_SIZE);
 		srb->cmnd[0] = REQUEST_SENSE;
 		srb->cmnd[1] = old_cmnd[1] & 0xE0;
-		srb->cmnd[2] = 0;
-		srb->cmnd[3] = 0;
 		srb->cmnd[4] = 18;
-		srb->cmnd[5] = 0;
+
+		/* FIXME: we must do the protocol translation here */
+		if (us->subclass == US_SC_RBC || us->subclass == US_SC_SCSI)
+			srb->cmd_len = 6;
+		else
+			srb->cmd_len = 12;
 
 		/* set the transfer direction */
 		old_sc_data_direction = srb->sc_data_direction;
@@ -739,6 +745,7 @@
 		srb->request_bufflen = old_request_bufflen;
 		srb->use_sg = old_sg;
 		srb->sc_data_direction = old_sc_data_direction;
+		srb->cmd_len = old_cmd_len;
 		memcpy(srb->cmnd, old_cmnd, MAX_COMMAND_SIZE);
 
 		if (temp_result == USB_STOR_TRANSPORT_ABORTED) {
@@ -820,7 +827,7 @@
 	}
 
 	/* is the device removed? */
-	if (urb->status == -ENOENT) {
+	if (urb->status == -ENODEV) {
 		US_DEBUGP("-- device has been removed\n");
 		return;
 	}
@@ -876,7 +883,7 @@
 	}
 
 	/* if the command was aborted, indicate that */
-	if (result == -ENOENT)
+	if (result == -ECONNRESET)
 		return USB_STOR_TRANSPORT_ABORTED;
 
 	/* STALL must be cleared when it is detected */
@@ -886,7 +893,7 @@
 			usb_sndctrlpipe(us->pusb_dev, 0));
 
 		/* if the command was aborted, indicate that */
-		if (result == -ENOENT)
+		if (result == -ECONNRESET)
 			return USB_STOR_TRANSPORT_ABORTED;
 		return USB_STOR_TRANSPORT_FAILED;
 	}
@@ -989,7 +996,7 @@
 	US_DEBUGP("Call to usb_stor_control_msg() returned %d\n", result);
 	if (result < 0) {
 		/* if the command was aborted, indicate that */
-		if (result == -ENOENT)
+		if (result == -ECONNRESET)
 			return USB_STOR_TRANSPORT_ABORTED;
 
 		/* a stall is a fatal condition from the device */
@@ -999,7 +1006,7 @@
 				usb_sndctrlpipe(us->pusb_dev, 0));
 
 			/* if the command was aborted, indicate that */
-			if (result == -ENOENT)
+			if (result == -ECONNRESET)
 				return USB_STOR_TRANSPORT_ABORTED;
 			return USB_STOR_TRANSPORT_FAILED;
 		}
@@ -1129,7 +1136,7 @@
 	US_DEBUGP("Bulk command transfer result=%d\n", result);
 
 	/* if the command was aborted, indicate that */
-	if (result == -ENOENT) {
+	if (result == -ECONNRESET) {
 		ret = USB_STOR_TRANSPORT_ABORTED;
 		goto out;
 	}
@@ -1140,7 +1147,7 @@
 		result = usb_stor_clear_halt(us, pipe);
 
 		/* if the command was aborted, indicate that */
-		if (result == -ENOENT) {
+		if (result == -ECONNRESET) {
 			ret = USB_STOR_TRANSPORT_ABORTED;
 			goto out;
 		}
@@ -1180,7 +1187,7 @@
 				   &partial);
 
 	/* if the command was aborted, indicate that */
-	if (result == -ENOENT) {
+	if (result == -ECONNRESET) {
 		ret = USB_STOR_TRANSPORT_ABORTED;
 		goto out;
 	}
@@ -1191,7 +1198,7 @@
 		result = usb_stor_clear_halt(us, pipe);
 
 		/* if the command was aborted, indicate that */
-		if (result == -ENOENT) {
+		if (result == -ECONNRESET) {
 			ret = USB_STOR_TRANSPORT_ABORTED;
 			goto out;
 		}
@@ -1202,7 +1209,7 @@
 					   US_BULK_CS_WRAP_LEN, &partial);
 
 		/* if the command was aborted, indicate that */
-		if (result == -ENOENT) {
+		if (result == -ECONNRESET) {
 			ret = USB_STOR_TRANSPORT_ABORTED;
 			goto out;
 		}
@@ -1213,7 +1220,7 @@
 			result = usb_stor_clear_halt(us, pipe);
 
 			/* if the command was aborted, indicate that */
-			if (result == -ENOENT) {
+			if (result == -ECONNRESET) {
 				ret = USB_STOR_TRANSPORT_ABORTED;
 			} else {
 				ret = USB_STOR_TRANSPORT_ERROR;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/storage/unusual_devs.h linux-2.4.21-pre6/drivers/usb/storage/unusual_devs.h
--- linux-2.4.20/drivers/usb/storage/unusual_devs.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/storage/unusual_devs.h	2003-03-26 23:49:19.000000000 +0000
@@ -97,6 +97,22 @@
 		"DVD-CAM DZ-MV100A Camcorder",
 		US_SC_SCSI, US_PR_CB, NULL, US_FL_SINGLE_LUN),
 
+/* Reported by Khalid Aziz <khalid@gonehiking.org>
+ * This entry is needed because the device reports Sub=ff */
+UNUSUAL_DEV(  0x04b8, 0x0602, 0x0110, 0x0110,
+		"Epson",
+		"785EPX Storage",
+		US_SC_SCSI, US_PR_BULK, NULL, US_FL_SINGLE_LUN),
+
+/* Reported by Jan Willamowius <jan@willamowius.de>
+ * The device needs the flags only.
+ */
+UNUSUAL_DEV(  0x04c8, 0x0723, 0x0000, 0x9999,
+		"Konica",
+		"KD-200Z",
+		US_SC_SCSI, US_PR_BULK, NULL,
+		US_FL_START_STOP),
+
 UNUSUAL_DEV(  0x04cb, 0x0100, 0x0000, 0x2210,
 		"Fujifilm",
 		"FinePix 1400Zoom",
@@ -207,9 +223,9 @@
 		US_FL_FIX_INQUIRY | US_FL_START_STOP ),
 
 /* This entry is needed because the device reports Sub=ff */
-UNUSUAL_DEV(  0x054c, 0x0010, 0x0106, 0x0422, 
+UNUSUAL_DEV(  0x054c, 0x0010, 0x0106, 0x0440, 
 		"Sony",
-		"DSC-S30/S70/S75/505V/F505/F707", 
+		"DSC-S30/S70/S75/505V/F505/F707/F717", 
 		US_SC_SCSI, US_PR_CB, NULL,
 		US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE ),
 
@@ -239,6 +255,12 @@
 		US_SC_UFI, US_PR_CB, NULL,
 		US_FL_SINGLE_LUN | US_FL_START_STOP ),
 		
+UNUSUAL_DEV(  0x054c, 0x0069, 0x0000, 0x9999,
+		"Sony",
+		"Memorystick MSC-U03",
+		US_SC_UFI, US_PR_CB, NULL,
+		US_FL_SINGLE_LUN | US_FL_START_STOP ),
+
 /* Submitted by Nathan Babb <nathan@lexi.com> */
 UNUSUAL_DEV(  0x054c, 0x006d, 0x0000, 0x9999,
                 "Sony",
@@ -487,6 +509,18 @@
 		US_FL_MODE_XLATE ),
 #endif
 
+/* Datafab KECF-USB / Sagatek DCS-CF / Simpletech Flashlink UCF-100
+ * Only revision 1.13 tested (same for all of the above devices,
+ * based on the Datafab DF-UG-07 chip).  Needed for US_FL_FIX_INQUIRY.
+ * Submitted by Marek Michalkiewicz <marekm@amelek.gda.pl>.
+ * See also http://martin.wilck.bei.t-online.de/#kecf .
+ */
+UNUSUAL_DEV(  0x07c4, 0xa400, 0x0000, 0xffff,
+		"Datafab",
+		"KECF-USB",
+		US_SC_SCSI, US_PR_BULK, NULL,
+		US_FL_FIX_INQUIRY ),
+
 /* Casio QV 2x00/3x00/4000/8000 digital still cameras are not conformant
  * to the USB storage specification in two ways:
  * - They tell us they are using transport protocol CBI. In reality they
@@ -506,6 +540,12 @@
  		US_SC_SCSI, US_PR_CB, NULL,
 		US_FL_MODE_XLATE ),
 
+UNUSUAL_DEV(  0x0a16, 0x8888, 0x0100, 0x0100,
+		"IBM",
+		"IBM USB Memory Key",
+		US_SC_SCSI, US_PR_BULK, NULL,
+		US_FL_FIX_INQUIRY ),
+		
 #ifdef CONFIG_USB_STORAGE_ISD200
 UNUSUAL_DEV(  0x0bf6, 0xa001, 0x0100, 0x0110,
                 "ATI",
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/tiglusb.c linux-2.4.21-pre6/drivers/usb/tiglusb.c
--- linux-2.4.20/drivers/usb/tiglusb.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/tiglusb.c	2003-03-26 23:49:50.000000000 +0000
@@ -14,17 +14,11 @@
  * and the website at:  http://lpg.ticalc.org/prj_usb/
  * for more info.
  *
- * History :
- *  16/07/2002 : v1.04 -- Julien BLACHE <jb@jblache.org>
- *    + removed useless usblp_cleanup()
- *    + removed {un,}lock_kernel() as suggested on lkml
- *    + inlined clear_pipes() (used once)
- *    + inlined clear_device() (small, used twice)
- *    + removed tiglusb_find_struct() (used once, simple code)
- *    + replaced down() with down_interruptible() wherever possible
- *    + fixed double unregistering wrt devfs, causing devfs
- *      to force an oops when the device is deconnected
- *    + removed unused fields from struct tiglusb_t
+ *   1.0x, Romain & Julien: initial submit.
+ *   1.03, Greg Kroah: modifications.
+ *   1.04, Julien: clean-up & fixes; Romain: 2.4 backport.
+ *   1.05, Randy Dunlap: bug fix with the timeout parameter (divide-by-zero).
+ *   1.06, Romain: synched with 2.5, version/firmware changed (confusing).
  */
 
 #include <linux/module.h>
@@ -44,7 +38,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "1.04"
+#define DRIVER_VERSION "1.06"
 #define DRIVER_AUTHOR  "Romain Lievin <roms@lpg.ticalc.org> & Julien Blache <jb@jblache.org>"
 #define DRIVER_DESC    "TI-GRAPH LINK USB (aka SilverLink) driver"
 #define DRIVER_LICENSE "GPL"
@@ -185,7 +179,7 @@
 
 	pipe = usb_rcvbulkpipe (s->dev, 1);
 	result = usb_bulk_msg (s->dev, pipe, buffer, bytes_to_read,
-			       &bytes_read, HZ / (timeout / 10));
+			       &bytes_read, HZ * 10 / timeout);
 	if (result == -ETIMEDOUT) {	/* NAK */
 		ret = result;
 		if (!bytes_read) {
@@ -242,7 +236,7 @@
 
 	pipe = usb_sndbulkpipe (s->dev, 2);
 	result = usb_bulk_msg (s->dev, pipe, buffer, bytes_to_write,
-			       &bytes_written, HZ / (timeout / 10));
+			       &bytes_written, HZ * 10 / timeout);
 
 	if (result == -ETIMEDOUT) {	/* NAK */
 		warn ("tiglusb_write, NAK received.");
@@ -315,6 +309,7 @@
 /* ----- kernel module registering ------------------------------------ */
 
 static struct file_operations tiglusb_fops = {
+	.owner =        THIS_MODULE,
 	.llseek =	no_llseek,
 	.read =		tiglusb_read,
 	.write =	tiglusb_write,
@@ -385,7 +380,7 @@
 			    &tiglusb_fops, NULL);
 
 	/* Display firmware version */
-	info ("link cable version %i.%02x",
+	info ("firmware revision %i.%02x",
 		dev->descriptor.bcdDevice >> 8,
 		dev->descriptor.bcdDevice & 0xff);
 
@@ -424,6 +419,7 @@
 MODULE_DEVICE_TABLE (usb, tiglusb_ids);
 
 static struct usb_driver tiglusb_driver = {
+	.owner =        THIS_MODULE,
 	.name =		"tiglusb",
 	.probe =	tiglusb_probe,
 	.disconnect =	tiglusb_disconnect,
@@ -446,6 +442,8 @@
 	if (ints[0] > 0) {
 		timeout = ints[1];
 	}
+	if (!timeout)
+		timeout = TIMAXTIME;
 
 	return 1;
 }
@@ -468,9 +466,11 @@
 		init_waitqueue_head (&s->wait);
 		init_waitqueue_head (&s->remove_ok);
 	}
+	if (timeout <= 0)
+               timeout = TIMAXTIME;
 
 	/* register device */
-	if (devfs_register_chrdev (TIUSB_MAJOR, "tiglusb", &tiglusb_fops)) {
+	if (register_chrdev (TIUSB_MAJOR, "tiglusb", &tiglusb_fops)) {
 		err ("unable to get major %d", TIUSB_MAJOR);
 		return -EIO;
 	}
@@ -481,11 +481,17 @@
 	/* register USB module */
 	result = usb_register (&tiglusb_driver);
 	if (result < 0) {
-		devfs_unregister_chrdev (TIUSB_MAJOR, "tiglusb");
+		unregister_chrdev (TIUSB_MAJOR, "tiglusb");
 		return -1;
 	}
 
-	info (DRIVER_DESC ", " DRIVER_VERSION);
+	info (DRIVER_DESC ", version " DRIVER_VERSION);
+
+       if (timeout <= 0)
+               timeout = TIMAXTIME;
+
+	if (!timeout)
+		timeout = TIMAXTIME;
 
 	return 0;
 }
@@ -495,7 +501,7 @@
 {
 	usb_deregister (&tiglusb_driver);
 	devfs_unregister (devfs_handle);
-	devfs_unregister_chrdev (TIUSB_MAJOR, "tiglusb");
+	unregister_chrdev (TIUSB_MAJOR, "tiglusb");
 }
 
 /* --------------------------------------------------------------------- */
@@ -509,6 +515,6 @@
 MODULE_LICENSE (DRIVER_LICENSE);
 
 MODULE_PARM (timeout, "i");
-MODULE_PARM_DESC (timeout, "Timeout (default=1.5 seconds)");
+MODULE_PARM_DESC (timeout, "Timeout in tenths of seconds (default=1.5 seconds)");
 
 /* --------------------------------------------------------------------- */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/uhci-debug.h linux-2.4.21-pre6/drivers/usb/uhci-debug.h
--- linux-2.4.20/drivers/usb/uhci-debug.h	2001-11-22 19:49:54.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/uhci-debug.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,573 +0,0 @@
-/*
- * UHCI-specific debugging code. Invaluable when something
- * goes wrong, but don't get in my face.
- *
- * Kernel visible pointers are surrounded in []'s and bus
- * visible pointers are surrounded in ()'s
- *
- * (C) Copyright 1999 Linus Torvalds
- * (C) Copyright 1999-2001 Johannes Erdfelt
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/proc_fs.h>
-#include <asm/io.h>
-
-#include "uhci.h"
-
-/* Handle REALLY large printk's so we don't overflow buffers */
-static void inline lprintk(char *buf)
-{
-	char *p;
-
-	/* Just write one line at a time */
-	while (buf) {
-		p = strchr(buf, '\n');
-		if (p)
-			*p = 0;
-		printk("%s\n", buf);
-		buf = p;
-		if (buf)
-			buf++;
-	}
-}
-
-static int inline uhci_is_skeleton_td(struct uhci *uhci, struct uhci_td *td)
-{
-	int i;
-
-	for (i = 0; i < UHCI_NUM_SKELTD; i++)
-		if (td == uhci->skeltd[i])
-			return 1;
-
-	return 0;
-}
-
-static int inline uhci_is_skeleton_qh(struct uhci *uhci, struct uhci_qh *qh)
-{
-	int i;
-
-	for (i = 0; i < UHCI_NUM_SKELQH; i++)
-		if (qh == uhci->skelqh[i])
-			return 1;
-
-	return 0;
-}
-
-static int uhci_show_td(struct uhci_td *td, char *buf, int len, int space)
-{
-	char *out = buf;
-	char *spid;
-
-	/* Try to make sure there's enough memory */
-	if (len < 160)
-		return 0;
-
-	out += sprintf(out, "%*s[%p] link (%08x) ", space, "", td, td->link);
-	out += sprintf(out, "e%d %s%s%s%s%s%s%s%s%s%sLength=%x ",
-		((td->status >> 27) & 3),
-		(td->status & TD_CTRL_SPD) ?      "SPD " : "",
-		(td->status & TD_CTRL_LS) ?       "LS " : "",
-		(td->status & TD_CTRL_IOC) ?      "IOC " : "",
-		(td->status & TD_CTRL_ACTIVE) ?   "Active " : "",
-		(td->status & TD_CTRL_STALLED) ?  "Stalled " : "",
-		(td->status & TD_CTRL_DBUFERR) ?  "DataBufErr " : "",
-		(td->status & TD_CTRL_BABBLE) ?   "Babble " : "",
-		(td->status & TD_CTRL_NAK) ?      "NAK " : "",
-		(td->status & TD_CTRL_CRCTIMEO) ? "CRC/Timeo " : "",
-		(td->status & TD_CTRL_BITSTUFF) ? "BitStuff " : "",
-		td->status & 0x7ff);
-
-	switch (td->info & 0xff) {
-		case USB_PID_SETUP:
-			spid = "SETUP";
-			break;
-		case USB_PID_OUT:
-			spid = "OUT";
-			break;
-		case USB_PID_IN:
-			spid = "IN";
-			break;
-		default:
-			spid = "?";
-			break;
-	}
-
-	out += sprintf(out, "MaxLen=%x DT%d EndPt=%x Dev=%x, PID=%x(%s) ",
-		td->info >> 21,
-		((td->info >> 19) & 1),
-		(td->info >> 15) & 15,
-		(td->info >> 8) & 127,
-		(td->info & 0xff),
-		spid);
-	out += sprintf(out, "(buf=%08x)\n", td->buffer);
-
-	return out - buf;
-}
-
-static int uhci_show_sc(int port, unsigned short status, char *buf, int len)
-{
-	char *out = buf;
-
-	/* Try to make sure there's enough memory */
-	if (len < 80)
-		return 0;
-
-	out += sprintf(out, "  stat%d     =     %04x   %s%s%s%s%s%s%s%s\n",
-		port,
-		status,
-		(status & USBPORTSC_SUSP) ? "PortSuspend " : "",
-		(status & USBPORTSC_PR) ?   "PortReset " : "",
-		(status & USBPORTSC_LSDA) ? "LowSpeed " : "",
-		(status & USBPORTSC_RD) ?   "ResumeDetect " : "",
-		(status & USBPORTSC_PEC) ?  "EnableChange " : "",
-		(status & USBPORTSC_PE) ?   "PortEnabled " : "",
-		(status & USBPORTSC_CSC) ?  "ConnectChange " : "",
-		(status & USBPORTSC_CCS) ?  "PortConnected " : "");
-
-	return out - buf;
-}
-
-static int uhci_show_status(struct uhci *uhci, char *buf, int len)
-{
-	char *out = buf;
-	unsigned int io_addr = uhci->io_addr;
-	unsigned short usbcmd, usbstat, usbint, usbfrnum;
-	unsigned int flbaseadd;
-	unsigned char sof;
-	unsigned short portsc1, portsc2;
-
-	/* Try to make sure there's enough memory */
-	if (len < 80 * 6)
-		return 0;
-
-	usbcmd    = inw(io_addr + 0);
-	usbstat   = inw(io_addr + 2);
-	usbint    = inw(io_addr + 4);
-	usbfrnum  = inw(io_addr + 6);
-	flbaseadd = inl(io_addr + 8);
-	sof       = inb(io_addr + 12);
-	portsc1   = inw(io_addr + 16);
-	portsc2   = inw(io_addr + 18);
-
-	out += sprintf(out, "  usbcmd    =     %04x   %s%s%s%s%s%s%s%s\n",
-		usbcmd,
-		(usbcmd & USBCMD_MAXP) ?    "Maxp64 " : "Maxp32 ",
-		(usbcmd & USBCMD_CF) ?      "CF " : "",
-		(usbcmd & USBCMD_SWDBG) ?   "SWDBG " : "",
-		(usbcmd & USBCMD_FGR) ?     "FGR " : "",
-		(usbcmd & USBCMD_EGSM) ?    "EGSM " : "",
-		(usbcmd & USBCMD_GRESET) ?  "GRESET " : "",
-		(usbcmd & USBCMD_HCRESET) ? "HCRESET " : "",
-		(usbcmd & USBCMD_RS) ?      "RS " : "");
-
-	out += sprintf(out, "  usbstat   =     %04x   %s%s%s%s%s%s\n",
-		usbstat,
-		(usbstat & USBSTS_HCH) ?    "HCHalted " : "",
-		(usbstat & USBSTS_HCPE) ?   "HostControllerProcessError " : "",
-		(usbstat & USBSTS_HSE) ?    "HostSystemError " : "",
-		(usbstat & USBSTS_RD) ?     "ResumeDetect " : "",
-		(usbstat & USBSTS_ERROR) ?  "USBError " : "",
-		(usbstat & USBSTS_USBINT) ? "USBINT " : "");
-
-	out += sprintf(out, "  usbint    =     %04x\n", usbint);
-	out += sprintf(out, "  usbfrnum  =   (%d)%03x\n", (usbfrnum >> 10) & 1,
-		0xfff & (4*(unsigned int)usbfrnum));
-	out += sprintf(out, "  flbaseadd = %08x\n", flbaseadd);
-	out += sprintf(out, "  sof       =       %02x\n", sof);
-	out += uhci_show_sc(1, portsc1, out, len - (out - buf));
-	out += uhci_show_sc(2, portsc2, out, len - (out - buf));
-
-	return out - buf;
-}
-
-static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
-{
-	char *out = buf;
-	struct urb_priv *urbp;
-	struct list_head *head, *tmp;
-	struct uhci_td *td;
-	int i = 0, checked = 0, prevactive = 0;
-
-	/* Try to make sure there's enough memory */
-	if (len < 80 * 6)
-		return 0;
-
-	out += sprintf(out, "%*s[%p] link (%08x) element (%08x)\n", space, "",
-			qh, qh->link, qh->element);
-
-	if (qh->element & UHCI_PTR_QH)
-		out += sprintf(out, "%*s  Element points to QH (bug?)\n", space, "");
-
-	if (qh->element & UHCI_PTR_DEPTH)
-		out += sprintf(out, "%*s  Depth traverse\n", space, "");
-
-	if (qh->element & 8)
-		out += sprintf(out, "%*s  Bit 3 set (bug?)\n", space, "");
-
-	if (!(qh->element & ~(UHCI_PTR_QH | UHCI_PTR_DEPTH)))
-		out += sprintf(out, "%*s  Element is NULL (bug?)\n", space, "");
-
-	if (!qh->urbp) {
-		out += sprintf(out, "%*s  urbp == NULL\n", space, "");
-		goto out;
-	}
-
-	urbp = qh->urbp;
-
-	head = &urbp->td_list;
-	tmp = head->next;
-
-	td = list_entry(tmp, struct uhci_td, list);
-
-	if (td->dma_handle != (qh->element & ~UHCI_PTR_BITS))
-		out += sprintf(out, "%*s Element != First TD\n", space, "");
-
-	while (tmp != head) {
-		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
-
-		tmp = tmp->next;
-
-		out += sprintf(out, "%*s%d: ", space + 2, "", i++);
-		out += uhci_show_td(td, out, len - (out - buf), 0);
-
-		if (i > 10 && !checked && prevactive && tmp != head &&
-		    debug <= 2) {
-			struct list_head *ntmp = tmp;
-			struct uhci_td *ntd = td;
-			int active = 1, ni = i;
-
-			checked = 1;
-
-			while (ntmp != head && ntmp->next != head && active) {
-				ntd = list_entry(ntmp, struct uhci_td, list);
-
-				ntmp = ntmp->next;
-
-				active = ntd->status & TD_CTRL_ACTIVE;
-
-				ni++;
-			}
-
-			if (active && ni > i) {
-				out += sprintf(out, "%*s[skipped %d active TD's]\n", space, "", ni - i);
-				tmp = ntmp;
-				td = ntd;
-				i = ni;
-			}
-		}
-
-		prevactive = td->status & TD_CTRL_ACTIVE;
-	}
-
-	if (list_empty(&urbp->queue_list) || urbp->queued)
-		goto out;
-
-	out += sprintf(out, "%*sQueued QH's:\n", -space, "--");
-
-	head = &urbp->queue_list;
-	tmp = head->next;
-
-	while (tmp != head) {
-		struct urb_priv *nurbp = list_entry(tmp, struct urb_priv,
-						queue_list);
-		tmp = tmp->next;
-
-		out += uhci_show_qh(nurbp->qh, out, len - (out - buf), space);
-	}
-
-out:
-	return out - buf;
-}
-
-static const char *td_names[] = {"skel_int1_td", "skel_int2_td",
-				 "skel_int4_td", "skel_int8_td",
-				 "skel_int16_td", "skel_int32_td",
-				 "skel_int64_td", "skel_int128_td",
-				 "skel_int256_td", "skel_term_td" };
-static const char *qh_names[] = { "skel_ls_control_qh", "skel_hs_control_qh",
-				  "skel_bulk_qh", "skel_term_qh" };
-
-#define show_frame_num()	\
-	if (!shown) {		\
-	  shown = 1;		\
-	  out += sprintf(out, "- Frame %d\n", i); \
-	}
-
-#define show_td_name()		\
-	if (!shown) {		\
-	  shown = 1;		\
-	  out += sprintf(out, "- %s\n", td_names[i]); \
-	}
-
-#define show_qh_name()		\
-	if (!shown) {		\
-	  shown = 1;		\
-	  out += sprintf(out, "- %s\n", qh_names[i]); \
-	}
-
-static int uhci_sprint_schedule(struct uhci *uhci, char *buf, int len)
-{
-	char *out = buf;
-	int i;
-	struct uhci_qh *qh;
-	struct uhci_td *td;
-	struct list_head *tmp, *head;
-
-	out += sprintf(out, "HC status\n");
-	out += uhci_show_status(uhci, out, len - (out - buf));
-
-	out += sprintf(out, "Frame List\n");
-	for (i = 0; i < UHCI_NUMFRAMES; ++i) {
-		int shown = 0;
-		td = uhci->fl->frame_cpu[i];
-		if (!td)
-			continue;
-
-		if (td->dma_handle != (dma_addr_t)uhci->fl->frame[i]) {
-			show_frame_num();
-			out += sprintf(out, "    frame list does not match td->dma_handle!\n");
-		}
-		if (uhci_is_skeleton_td(uhci, td))
-			continue;
-		show_frame_num();
-
-		head = &td->fl_list;
-		tmp = head;
-		do {
-			td = list_entry(tmp, struct uhci_td, fl_list);
-			tmp = tmp->next;
-			out += uhci_show_td(td, out, len - (out - buf), 4);
-		} while (tmp != head);
-	}
-
-	out += sprintf(out, "Skeleton TD's\n");
-	for (i = UHCI_NUM_SKELTD - 1; i >= 0; i--) {
-		int shown = 0;
-
-		td = uhci->skeltd[i];
-
-		if (debug > 1) {
-			show_td_name();
-			out += uhci_show_td(td, out, len - (out - buf), 4);
-		}
-
-		if (list_empty(&td->fl_list)) {
-			/* TD 0 is the int1 TD and links to control_ls_qh */
-			if (!i) {
-				if (td->link !=
-				    (uhci->skel_ls_control_qh->dma_handle | UHCI_PTR_QH)) {
-					show_td_name();
-					out += sprintf(out, "    skeleton TD not linked to ls_control QH!\n");
-				}
-			} else if (i < 9) {
-				if (td->link != uhci->skeltd[i - 1]->dma_handle) {
-					show_td_name();
-					out += sprintf(out, "    skeleton TD not linked to next skeleton TD!\n");
-				}
-			} else {
-				show_td_name();
-
-				if (td->link != td->dma_handle)
-					out += sprintf(out, "    skel_term_td does not link to self\n");
-
-				/* Don't show it twice */
-				if (debug <= 1)
-					out += uhci_show_td(td, out, len - (out - buf), 4);
-			}
-
-			continue;
-		}
-
-		show_td_name();
-
-		head = &td->fl_list;
-		tmp = head->next;
-
-		while (tmp != head) {
-			td = list_entry(tmp, struct uhci_td, fl_list);
-
-			tmp = tmp->next;
-
-			out += uhci_show_td(td, out, len - (out - buf), 4);
-		}
-
-		if (!i) {
-			if (td->link !=
-			    (uhci->skel_ls_control_qh->dma_handle | UHCI_PTR_QH))
-				out += sprintf(out, "    last TD not linked to ls_control QH!\n");
-		} else if (i < 9) {
-			if (td->link != uhci->skeltd[i - 1]->dma_handle)
-				out += sprintf(out, "    last TD not linked to next skeleton!\n");
-		}
-	}
-
-	out += sprintf(out, "Skeleton QH's\n");
-
-	for (i = 0; i < UHCI_NUM_SKELQH; ++i) {
-		int shown = 0;
-
-		qh = uhci->skelqh[i];
-
-		if (debug > 1) {
-			show_qh_name();
-			out += uhci_show_qh(qh, out, len - (out - buf), 4);
-		}
-
-		/* QH 3 is the Terminating QH, it's different */
-		if (i == 3) {
-			if (qh->link != UHCI_PTR_TERM) {
-				show_qh_name();
-				out += sprintf(out, "    bandwidth reclamation on!\n");
-			}
-
-			if (qh->element != uhci->skel_term_td->dma_handle) {
-				show_qh_name();
-				out += sprintf(out, "    skel_term_qh element is not set to skel_term_td\n");
-			}
-		}
-
-		if (list_empty(&qh->list)) {
-			if (i < 3) {
-				if (qh->link !=
-				    (uhci->skelqh[i + 1]->dma_handle | UHCI_PTR_QH)) {
-					show_qh_name();
-					out += sprintf(out, "    skeleton QH not linked to next skeleton QH!\n");
-				}
-			}
-
-			continue;
-		}
-
-		show_qh_name();
-
-		head = &qh->list;
-		tmp = head->next;
-
-		while (tmp != head) {
-			qh = list_entry(tmp, struct uhci_qh, list);
-
-			tmp = tmp->next;
-
-			out += uhci_show_qh(qh, out, len - (out - buf), 4);
-		}
-
-		if (i < 3) {
-			if (qh->link !=
-			    (uhci->skelqh[i + 1]->dma_handle | UHCI_PTR_QH))
-				out += sprintf(out, "    last QH not linked to next skeleton!\n");
-		}
-	}
-
-	return out - buf;
-}
-
-#ifdef CONFIG_PROC_FS
-#define MAX_OUTPUT	(PAGE_SIZE * 8)
-
-static struct proc_dir_entry *uhci_proc_root = NULL;
-
-struct uhci_proc {
-	int size;
-	char *data;
-	struct uhci *uhci;
-};
-
-static int uhci_proc_open(struct inode *inode, struct file *file)
-{
-	const struct proc_dir_entry *dp = inode->u.generic_ip;
-	struct uhci *uhci = dp->data;
-	struct uhci_proc *up;
-	unsigned long flags;
-	int ret = -ENOMEM;
-
-	lock_kernel();
-	up = kmalloc(sizeof(*up), GFP_KERNEL);
-	if (!up)
-		goto out;
-
-	up->data = kmalloc(MAX_OUTPUT, GFP_KERNEL);
-	if (!up->data) {
-		kfree(up);
-		goto out;
-	}
-
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-	up->size = uhci_sprint_schedule(uhci, up->data, MAX_OUTPUT);
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
-
-	file->private_data = up;
-
-	ret = 0;
-out:
-	unlock_kernel();
-	return ret;
-}
-
-static loff_t uhci_proc_lseek(struct file *file, loff_t off, int whence)
-{
-	struct uhci_proc *up = file->private_data;
-	loff_t new;
-
-	switch (whence) {
-	case 0:
-		new = off;
-		break;
-	case 1:
-		new = file->f_pos + off;
-		break;
-	case 2:
-	default:
-		return -EINVAL;
-	}
-	if (new < 0 || new > up->size)
-		return -EINVAL;
-	return (file->f_pos = new);
-}
-
-static ssize_t uhci_proc_read(struct file *file, char *buf, size_t nbytes,
-			loff_t *ppos)
-{
-	struct uhci_proc *up = file->private_data;
-	unsigned int pos;
-	unsigned int size;
-
-	pos = *ppos;
-	size = up->size;
-	if (pos >= size)
-		return 0;
-	if (nbytes >= size)
-		nbytes = size;
-	if (pos + nbytes > size)
-		nbytes = size - pos;
-
-	if (!access_ok(VERIFY_WRITE, buf, nbytes))
-		return -EINVAL;
-
-	copy_to_user(buf, up->data + pos, nbytes);
-
-	*ppos += nbytes;
-
-	return nbytes;
-}
-
-static int uhci_proc_release(struct inode *inode, struct file *file)
-{
-	struct uhci_proc *up = file->private_data;
-
-	kfree(up->data);
-	kfree(up);
-
-	return 0;
-}
-
-static struct file_operations uhci_proc_operations = {
-	open:		uhci_proc_open,
-	llseek:		uhci_proc_lseek,
-	read:		uhci_proc_read,
-//	write:		uhci_proc_write,
-	release:	uhci_proc_release,
-};
-#endif
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/uhci.c linux-2.4.21-pre6/drivers/usb/uhci.c
--- linux-2.4.20/drivers/usb/uhci.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/uhci.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,3172 +0,0 @@
-/*
- * Universal Host Controller Interface driver for USB.
- *
- * Maintainer: Johannes Erdfelt <johannes@erdfelt.com>
- *
- * (C) Copyright 1999 Linus Torvalds
- * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@erdfelt.com
- * (C) Copyright 1999 Randy Dunlap
- * (C) Copyright 1999 Georg Acher, acher@in.tum.de
- * (C) Copyright 1999 Deti Fliegl, deti@fliegl.de
- * (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch
- * (C) Copyright 1999 Roman Weissgaerber, weissg@vienna.at
- * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
- *               support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
- * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
- *
- * Intel documents this fairly well, and as far as I know there
- * are no royalties or anything like that, but even so there are
- * people who decided that they want to do the same thing in a
- * completely different way.
- *
- * WARNING! The USB documentation is downright evil. Most of it
- * is just crap, written by a committee. You're better off ignoring
- * most of it, the important stuff is:
- *  - the low-level protocol (fairly simple but lots of small details)
- *  - working around the horridness of the rest
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/smp_lock.h>
-#include <linux/errno.h>
-#include <linux/unistd.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/proc_fs.h>
-#ifdef CONFIG_USB_DEBUG
-#define DEBUG
-#else
-#undef DEBUG
-#endif
-#include <linux/usb.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-
-#include "uhci.h"
-
-#include <linux/pm.h>
-
-#include "hcd.h"
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v1.1"
-#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"
-
-/*
- * debug = 0, no debugging messages
- * debug = 1, dump failed URB's except for stalls
- * debug = 2, dump all failed URB's (including stalls)
- *            show all queues in /proc/uhci/hc*
- * debug = 3, show all TD's in URB's when dumping
- */
-#ifdef DEBUG
-static int debug = 1;
-#else
-static int debug = 0;
-#endif
-MODULE_PARM(debug, "i");
-MODULE_PARM_DESC(debug, "Debug level");
-static char *errbuf;
-#define ERRBUF_LEN    (PAGE_SIZE * 8)
-
-#include "uhci-debug.h"
-
-static kmem_cache_t *uhci_up_cachep;	/* urb_priv */
-
-static int rh_submit_urb(struct urb *urb);
-static int rh_unlink_urb(struct urb *urb);
-static int uhci_get_current_frame_number(struct usb_device *dev);
-static int uhci_unlink_urb(struct urb *urb);
-static void uhci_unlink_generic(struct uhci *uhci, struct urb *urb);
-static void uhci_call_completion(struct urb *urb);
-
-static int  ports_active(struct uhci *uhci);
-static void suspend_hc(struct uhci *uhci);
-static void wakeup_hc(struct uhci *uhci);
-
-/* If a transfer is still active after this much time, turn off FSBR */
-#define IDLE_TIMEOUT	(HZ / 20)	/* 50 ms */
-#define FSBR_DELAY	(HZ / 20)	/* 50 ms */
-
-/* When we timeout an idle transfer for FSBR, we'll switch it over to */
-/* depth first traversal. We'll do it in groups of this number of TD's */
-/* to make sure it doesn't hog all of the bandwidth */
-#define DEPTH_INTERVAL	5
-
-#define MAX_URB_LOOP	2048		/* Maximum number of linked URB's */
-
-/*
- * Only the USB core should call uhci_alloc_dev and uhci_free_dev
- */
-static int uhci_alloc_dev(struct usb_device *dev)
-{
-	return 0;
-}
-
-static int uhci_free_dev(struct usb_device *dev)
-{
-	return 0;
-}
-
-/*
- * Technically, updating td->status here is a race, but it's not really a
- * problem. The worst that can happen is that we set the IOC bit again
- * generating a spurios interrupt. We could fix this by creating another
- * QH and leaving the IOC bit always set, but then we would have to play
- * games with the FSBR code to make sure we get the correct order in all
- * the cases. I don't think it's worth the effort
- */
-static inline void uhci_set_next_interrupt(struct uhci *uhci)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-	uhci->skel_term_td->status |= TD_CTRL_IOC;
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
-}
-
-static inline void uhci_clear_next_interrupt(struct uhci *uhci)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-	uhci->skel_term_td->status &= ~TD_CTRL_IOC;
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
-}
-
-static inline void uhci_add_complete(struct urb *urb)
-{
-	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	unsigned long flags;
-
-	spin_lock_irqsave(&uhci->complete_list_lock, flags);
-	list_add(&urbp->complete_list, &uhci->complete_list);
-	spin_unlock_irqrestore(&uhci->complete_list_lock, flags);
-}
-
-static struct uhci_td *uhci_alloc_td(struct uhci *uhci, struct usb_device *dev)
-{
-	dma_addr_t dma_handle;
-	struct uhci_td *td;
-
-	td = pci_pool_alloc(uhci->td_pool, GFP_DMA | GFP_ATOMIC, &dma_handle);
-	if (!td)
-		return NULL;
-
-	td->dma_handle = dma_handle;
-
-	td->link = UHCI_PTR_TERM;
-	td->buffer = 0;
-
-	td->frame = -1;
-	td->dev = dev;
-
-	INIT_LIST_HEAD(&td->list);
-	INIT_LIST_HEAD(&td->fl_list);
-
-	usb_inc_dev_use(dev);
-
-	return td;
-}
-
-static void inline uhci_fill_td(struct uhci_td *td, __u32 status,
-		__u32 info, __u32 buffer)
-{
-	td->status = status;
-	td->info = info;
-	td->buffer = buffer;
-}
-
-static void uhci_insert_td(struct uhci *uhci, struct uhci_td *skeltd, struct uhci_td *td)
-{
-	unsigned long flags;
-	struct uhci_td *ltd;
-
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-
-	ltd = list_entry(skeltd->fl_list.prev, struct uhci_td, fl_list);
-
-	td->link = ltd->link;
-	mb();
-	ltd->link = td->dma_handle;
-
-	list_add_tail(&td->fl_list, &skeltd->fl_list);
-
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
-}
-
-/*
- * We insert Isochronous transfers directly into the frame list at the
- * beginning
- * The layout looks as follows:
- * frame list pointer -> iso td's (if any) ->
- * periodic interrupt td (if frame 0) -> irq td's -> control qh -> bulk qh
- */
-static void uhci_insert_td_frame_list(struct uhci *uhci, struct uhci_td *td, unsigned framenum)
-{
-	unsigned long flags;
-
-	framenum %= UHCI_NUMFRAMES;
-
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-
-	td->frame = framenum;
-
-	/* Is there a TD already mapped there? */
-	if (uhci->fl->frame_cpu[framenum]) {
-		struct uhci_td *ftd, *ltd;
-
-		ftd = uhci->fl->frame_cpu[framenum];
-		ltd = list_entry(ftd->fl_list.prev, struct uhci_td, fl_list);
-
-		list_add_tail(&td->fl_list, &ftd->fl_list);
-
-		td->link = ltd->link;
-		mb();
-		ltd->link = td->dma_handle;
-	} else {
-		td->link = uhci->fl->frame[framenum];
-		mb();
-		uhci->fl->frame[framenum] = td->dma_handle;
-		uhci->fl->frame_cpu[framenum] = td;
-	}
-
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
-}
-
-static void uhci_remove_td(struct uhci *uhci, struct uhci_td *td)
-{
-	unsigned long flags;
-
-	/* If it's not inserted, don't remove it */
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-	if (td->frame == -1 && list_empty(&td->fl_list))
-		goto out;
-
-	if (td->frame != -1 && uhci->fl->frame_cpu[td->frame] == td) {
-		if (list_empty(&td->fl_list)) {
-			uhci->fl->frame[td->frame] = td->link;
-			uhci->fl->frame_cpu[td->frame] = NULL;
-		} else {
-			struct uhci_td *ntd;
-
-			ntd = list_entry(td->fl_list.next, struct uhci_td, fl_list);
-			uhci->fl->frame[td->frame] = ntd->dma_handle;
-			uhci->fl->frame_cpu[td->frame] = ntd;
-		}
-	} else {
-		struct uhci_td *ptd;
-
-		ptd = list_entry(td->fl_list.prev, struct uhci_td, fl_list);
-		ptd->link = td->link;
-	}
-
-	mb();
-	td->link = UHCI_PTR_TERM;
-
-	list_del_init(&td->fl_list);
-	td->frame = -1;
-
-out:
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
-}
-
-/*
- * Inserts a td into qh list at the top.
- */
-static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, int breadth)
-{
-	struct list_head *tmp, *head;
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	struct uhci_td *td, *ptd;
-
-	if (list_empty(&urbp->td_list))
-		return;
-
-	head = &urbp->td_list;
-	tmp = head->next;
-
-	/* Ordering isn't important here yet since the QH hasn't been */
-	/*  inserted into the schedule yet */
-	td = list_entry(tmp, struct uhci_td, list);
-
-	/* Add the first TD to the QH element pointer */
-	qh->element = td->dma_handle | (breadth ? 0 : UHCI_PTR_DEPTH);
-
-	ptd = td;
-
-	/* Then link the rest of the TD's */
-	tmp = tmp->next;
-	while (tmp != head) {
-		td = list_entry(tmp, struct uhci_td, list);
-
-		tmp = tmp->next;
-
-		ptd->link = td->dma_handle | (breadth ? 0 : UHCI_PTR_DEPTH);
-
-		ptd = td;
-	}
-
-	ptd->link = UHCI_PTR_TERM;
-}
-
-static void uhci_free_td(struct uhci *uhci, struct uhci_td *td)
-{
-	if (!list_empty(&td->list) || !list_empty(&td->fl_list))
-		dbg("td is still in URB list!");
-
-	if (td->dev)
-		usb_dec_dev_use(td->dev);
-
-	pci_pool_free(uhci->td_pool, td, td->dma_handle);
-}
-
-static struct uhci_qh *uhci_alloc_qh(struct uhci *uhci, struct usb_device *dev)
-{
-	dma_addr_t dma_handle;
-	struct uhci_qh *qh;
-
-	qh = pci_pool_alloc(uhci->qh_pool, GFP_DMA | GFP_ATOMIC, &dma_handle);
-	if (!qh)
-		return NULL;
-
-	qh->dma_handle = dma_handle;
-
-	qh->element = UHCI_PTR_TERM;
-	qh->link = UHCI_PTR_TERM;
-
-	qh->dev = dev;
-	qh->urbp = NULL;
-
-	INIT_LIST_HEAD(&qh->list);
-	INIT_LIST_HEAD(&qh->remove_list);
-
-	usb_inc_dev_use(dev);
-
-	return qh;
-}
-
-static void uhci_free_qh(struct uhci *uhci, struct uhci_qh *qh)
-{
-	if (!list_empty(&qh->list))
-		dbg("qh list not empty!");
-	if (!list_empty(&qh->remove_list))
-		dbg("qh still in remove_list!");
-
-	if (qh->dev)
-		usb_dec_dev_use(qh->dev);
-
-	pci_pool_free(uhci->qh_pool, qh, qh->dma_handle);
-}
-
-/*
- * MUST be called with uhci->frame_list_lock acquired
- */
-static void _uhci_insert_qh(struct uhci *uhci, struct uhci_qh *skelqh, struct urb *urb)
-{
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	struct list_head *head, *tmp;
-	struct uhci_qh *lqh;
-
-	/* Grab the last QH */
-	lqh = list_entry(skelqh->list.prev, struct uhci_qh, list);
-
-	if (lqh->urbp) {
-		head = &lqh->urbp->queue_list;
-		tmp = head->next;
-		while (head != tmp) {
-			struct urb_priv *turbp =
-				list_entry(tmp, struct urb_priv, queue_list);
-
-			tmp = tmp->next;
-
-			turbp->qh->link = urbp->qh->dma_handle | UHCI_PTR_QH;
-		}
-	}
-
-	head = &urbp->queue_list;
-	tmp = head->next;
-	while (head != tmp) {
-		struct urb_priv *turbp =
-			list_entry(tmp, struct urb_priv, queue_list);
-
-		tmp = tmp->next;
-
-		turbp->qh->link = lqh->link;
-	}
-
-	urbp->qh->link = lqh->link;
-	mb();				/* Ordering is important */
-	lqh->link = urbp->qh->dma_handle | UHCI_PTR_QH;
-
-	list_add_tail(&urbp->qh->list, &skelqh->list);
-}
-
-static void uhci_insert_qh(struct uhci *uhci, struct uhci_qh *skelqh, struct urb *urb)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-	_uhci_insert_qh(uhci, skelqh, urb);
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
-}
-
-static void uhci_remove_qh(struct uhci *uhci, struct uhci_qh *qh)
-{
-	unsigned long flags;
-	struct uhci_qh *pqh;
-
-	if (!qh)
-		return;
-
-	qh->urbp = NULL;
-
-	/* Only go through the hoops if it's actually linked in */
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-	if (!list_empty(&qh->list)) {
-		pqh = list_entry(qh->list.prev, struct uhci_qh, list);
-
-		if (pqh->urbp) {
-			struct list_head *head, *tmp;
-
-			head = &pqh->urbp->queue_list;
-			tmp = head->next;
-			while (head != tmp) {
-				struct urb_priv *turbp =
-					list_entry(tmp, struct urb_priv, queue_list);
-
-				tmp = tmp->next;
-
-				turbp->qh->link = qh->link;
-			}
-		}
-
-		pqh->link = qh->link;
-		mb();
-		qh->element = qh->link = UHCI_PTR_TERM;
-
-		list_del_init(&qh->list);
-	}
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
-
-	spin_lock_irqsave(&uhci->qh_remove_list_lock, flags);
-
-	/* Check to see if the remove list is empty. Set the IOC bit */
-	/* to force an interrupt so we can remove the QH */
-	if (list_empty(&uhci->qh_remove_list))
-		uhci_set_next_interrupt(uhci);
-
-	list_add(&qh->remove_list, &uhci->qh_remove_list);
-
-	spin_unlock_irqrestore(&uhci->qh_remove_list_lock, flags);
-}
-
-static int uhci_fixup_toggle(struct urb *urb, unsigned int toggle)
-{
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	struct list_head *head, *tmp;
-
-	head = &urbp->td_list;
-	tmp = head->next;
-	while (head != tmp) {
-		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
-
-		tmp = tmp->next;
-
-		if (toggle)
-			td->info |= TD_TOKEN_TOGGLE;
-		else
-			td->info &= ~TD_TOKEN_TOGGLE;
-
-		toggle ^= 1;
-	}
-
-	return toggle;
-}
-
-/* This function will append one URB's QH to another URB's QH. This is for */
-/*  USB_QUEUE_BULK support for bulk transfers and soon implicitily for */
-/*  control transfers */
-static void uhci_append_queued_urb(struct uhci *uhci, struct urb *eurb, struct urb *urb)
-{
-	struct urb_priv *eurbp, *urbp, *furbp, *lurbp;
-	struct list_head *tmp;
-	struct uhci_td *lltd;
-	unsigned long flags;
-
-	eurbp = eurb->hcpriv;
-	urbp = urb->hcpriv;
-
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-
-	/* Find the first URB in the queue */
-	if (eurbp->queued) {
-		struct list_head *head = &eurbp->queue_list;
-
-		tmp = head->next;
-		while (tmp != head) {
-			struct urb_priv *turbp =
-				list_entry(tmp, struct urb_priv, queue_list);
-
-			if (!turbp->queued)
-				break;
-
-			tmp = tmp->next;
-		}
-	} else
-		tmp = &eurbp->queue_list;
-
-	furbp = list_entry(tmp, struct urb_priv, queue_list);
-	lurbp = list_entry(furbp->queue_list.prev, struct urb_priv, queue_list);
-
-	lltd = list_entry(lurbp->td_list.prev, struct uhci_td, list);
-
-	usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe),
-		uhci_fixup_toggle(urb, uhci_toggle(lltd->info) ^ 1));
-
-	/* All qh's in the queue need to link to the next queue */
-	urbp->qh->link = eurbp->qh->link;
-
-	mb();			/* Make sure we flush everything */
-	/* Only support bulk right now, so no depth */
-	lltd->link = urbp->qh->dma_handle | UHCI_PTR_QH;
-
-	list_add_tail(&urbp->queue_list, &furbp->queue_list);
-
-	urbp->queued = 1;
-
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
-}
-
-static void uhci_delete_queued_urb(struct uhci *uhci, struct urb *urb)
-{
-	struct urb_priv *urbp, *nurbp;
-	struct list_head *head, *tmp;
-	struct urb_priv *purbp;
-	struct uhci_td *pltd;
-	unsigned int toggle;
-	unsigned long flags;
-
-	urbp = urb->hcpriv;
-
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-
-	if (list_empty(&urbp->queue_list))
-		goto out;
-
-	nurbp = list_entry(urbp->queue_list.next, struct urb_priv, queue_list);
-
-	/* Fix up the toggle for the next URB's */
-	if (!urbp->queued)
-		/* We set the toggle when we unlink */
-		toggle = usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
-	else {
-		/* If we're in the middle of the queue, grab the toggle */
-		/*  from the TD previous to us */
-		purbp = list_entry(urbp->queue_list.prev, struct urb_priv,
-				queue_list);
-
-		pltd = list_entry(purbp->td_list.prev, struct uhci_td, list);
-
-		toggle = uhci_toggle(pltd->info) ^ 1;
-	}
-
-	head = &urbp->queue_list;
-	tmp = head->next;
-	while (head != tmp) {
-		struct urb_priv *turbp;
-
-		turbp = list_entry(tmp, struct urb_priv, queue_list);
-
-		tmp = tmp->next;
-
-		if (!turbp->queued)
-			break;
-
-		toggle = uhci_fixup_toggle(turbp->urb, toggle);
-	}
-
-	usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
-		usb_pipeout(urb->pipe), toggle);
-
-	if (!urbp->queued) {
-		nurbp->queued = 0;
-
-		_uhci_insert_qh(uhci, uhci->skel_bulk_qh, nurbp->urb);
-	} else {
-		/* We're somewhere in the middle (or end). A bit trickier */
-		/*  than the head scenario */
-		purbp = list_entry(urbp->queue_list.prev, struct urb_priv,
-				queue_list);
-
-		pltd = list_entry(purbp->td_list.prev, struct uhci_td, list);
-		if (nurbp->queued)
-			pltd->link = nurbp->qh->dma_handle | UHCI_PTR_QH;
-		else
-			/* The next URB happens to be the beginning, so */
-			/*  we're the last, end the chain */
-			pltd->link = UHCI_PTR_TERM;
-	}
-
-	list_del_init(&urbp->queue_list);
-
-out:
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
-}
-
-static struct urb_priv *uhci_alloc_urb_priv(struct uhci *uhci, struct urb *urb)
-{
-	struct urb_priv *urbp;
-
-	urbp = kmem_cache_alloc(uhci_up_cachep, SLAB_ATOMIC);
-	if (!urbp) {
-		err("uhci_alloc_urb_priv: couldn't allocate memory for urb_priv\n");
-		return NULL;
-	}
-
-	memset((void *)urbp, 0, sizeof(*urbp));
-
-	urbp->inserttime = jiffies;
-	urbp->fsbrtime = jiffies;
-	urbp->urb = urb;
-	urbp->dev = urb->dev;
-	
-	INIT_LIST_HEAD(&urbp->td_list);
-	INIT_LIST_HEAD(&urbp->queue_list);
-	INIT_LIST_HEAD(&urbp->complete_list);
-
-	urb->hcpriv = urbp;
-
-	if (urb->dev != uhci->rh.dev) {
-		if (urb->transfer_buffer_length) {
-			urbp->transfer_buffer_dma_handle = pci_map_single(uhci->dev,
-				urb->transfer_buffer, urb->transfer_buffer_length,
-				usb_pipein(urb->pipe) ? PCI_DMA_FROMDEVICE :
-				PCI_DMA_TODEVICE);
-			if (!urbp->transfer_buffer_dma_handle)
-				return NULL;
-		}
-
-		if (usb_pipetype(urb->pipe) == PIPE_CONTROL && urb->setup_packet) {
-			urbp->setup_packet_dma_handle = pci_map_single(uhci->dev,
-				urb->setup_packet, sizeof(struct usb_ctrlrequest),
-				PCI_DMA_TODEVICE);
-			if (!urbp->setup_packet_dma_handle)
-				return NULL;
-		}
-	}
-
-	return urbp;
-}
-
-/*
- * MUST be called with urb->lock acquired
- */
-static void uhci_add_td_to_urb(struct urb *urb, struct uhci_td *td)
-{
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-
-	td->urb = urb;
-
-	list_add_tail(&td->list, &urbp->td_list);
-}
-
-/*
- * MUST be called with urb->lock acquired
- */
-static void uhci_remove_td_from_urb(struct uhci_td *td)
-{
-	if (list_empty(&td->list))
-		return;
-
-	list_del_init(&td->list);
-
-	td->urb = NULL;
-}
-
-/*
- * MUST be called with urb->lock acquired
- */
-static void uhci_destroy_urb_priv(struct urb *urb)
-{
-	struct list_head *head, *tmp;
-	struct urb_priv *urbp;
-	struct uhci *uhci;
-
-	urbp = (struct urb_priv *)urb->hcpriv;
-	if (!urbp)
-		return;
-
-	if (!urbp->dev || !urbp->dev->bus || !urbp->dev->bus->hcpriv) {
-		warn("uhci_destroy_urb_priv: urb %p belongs to disconnected device or bus?", urb);
-		return;
-	}
-
-	if (!list_empty(&urb->urb_list))
-		warn("uhci_destroy_urb_priv: urb %p still on uhci->urb_list or uhci->remove_list", urb);
-
-	if (!list_empty(&urbp->complete_list))
-		warn("uhci_destroy_urb_priv: urb %p still on uhci->complete_list", urb);
-
-	uhci = urbp->dev->bus->hcpriv;
-
-	head = &urbp->td_list;
-	tmp = head->next;
-	while (tmp != head) {
-		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
-
-		tmp = tmp->next;
-
-		uhci_remove_td_from_urb(td);
-		uhci_remove_td(uhci, td);
-		uhci_free_td(uhci, td);
-	}
-
-	if (urbp->setup_packet_dma_handle) {
-		pci_unmap_single(uhci->dev, urbp->setup_packet_dma_handle,
-			sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE);
-		urbp->setup_packet_dma_handle = 0;
-	}
-
-	if (urbp->transfer_buffer_dma_handle) {
-		pci_unmap_single(uhci->dev, urbp->transfer_buffer_dma_handle,
-			urb->transfer_buffer_length, usb_pipein(urb->pipe) ?
-			PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
-		urbp->transfer_buffer_dma_handle = 0;
-	}
-
-	urb->hcpriv = NULL;
-	kmem_cache_free(uhci_up_cachep, urbp);
-}
-
-static void uhci_inc_fsbr(struct uhci *uhci, struct urb *urb)
-{
-	unsigned long flags;
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-
-	if ((!(urb->transfer_flags & USB_NO_FSBR)) && !urbp->fsbr) {
-		urbp->fsbr = 1;
-		if (!uhci->fsbr++ && !uhci->fsbrtimeout)
-			uhci->skel_term_qh->link = uhci->skel_hs_control_qh->dma_handle | UHCI_PTR_QH;
-	}
-
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
-}
-
-static void uhci_dec_fsbr(struct uhci *uhci, struct urb *urb)
-{
-	unsigned long flags;
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
-
-	if ((!(urb->transfer_flags & USB_NO_FSBR)) && urbp->fsbr) {
-		urbp->fsbr = 0;
-		if (!--uhci->fsbr)
-			uhci->fsbrtimeout = jiffies + FSBR_DELAY;
-	}
-
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
-}
-
-/*
- * Map status to standard result codes
- *
- * <status> is (td->status & 0xFE0000) [a.k.a. uhci_status_bits(td->status)]
- * <dir_out> is True for output TDs and False for input TDs.
- */
-static int uhci_map_status(int status, int dir_out)
-{
-	if (!status)
-		return 0;
-	if (status & TD_CTRL_BITSTUFF)			/* Bitstuff error */
-		return -EPROTO;
-	if (status & TD_CTRL_CRCTIMEO) {		/* CRC/Timeout */
-		if (dir_out)
-			return -ETIMEDOUT;
-		else
-			return -EILSEQ;
-	}
-	if (status & TD_CTRL_NAK)			/* NAK */
-		return -ETIMEDOUT;
-	if (status & TD_CTRL_BABBLE)			/* Babble */
-		return -EOVERFLOW;
-	if (status & TD_CTRL_DBUFERR)			/* Buffer error */
-		return -ENOSR;
-	if (status & TD_CTRL_STALLED)			/* Stalled */
-		return -EPIPE;
-	if (status & TD_CTRL_ACTIVE)			/* Active */
-		return 0;
-
-	return -EINVAL;
-}
-
-/*
- * Control transfers
- */
-static int uhci_submit_control(struct urb *urb)
-{
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
-	struct uhci_td *td;
-	struct uhci_qh *qh;
-	unsigned long destination, status;
-	int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
-	int len = urb->transfer_buffer_length;
-	dma_addr_t data = urbp->transfer_buffer_dma_handle;
-
-	/* The "pipe" thing contains the destination in bits 8--18 */
-	destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
-
-	/* 3 errors */
-	status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | (3 << 27);
-
-	/*
-	 * Build the TD for the control request
-	 */
-	td = uhci_alloc_td(uhci, urb->dev);
-	if (!td)
-		return -ENOMEM;
-
-	uhci_add_td_to_urb(urb, td);
-	uhci_fill_td(td, status, destination | (7 << 21),
-		urbp->setup_packet_dma_handle);
-
-	/*
-	 * If direction is "send", change the frame from SETUP (0x2D)
-	 * to OUT (0xE1). Else change it from SETUP to IN (0x69).
-	 */
-	destination ^= (USB_PID_SETUP ^ usb_packetid(urb->pipe));
-
-	if (!(urb->transfer_flags & USB_DISABLE_SPD))
-		status |= TD_CTRL_SPD;
-
-	/*
-	 * Build the DATA TD's
-	 */
-	while (len > 0) {
-		int pktsze = len;
-
-		if (pktsze > maxsze)
-			pktsze = maxsze;
-
-		td = uhci_alloc_td(uhci, urb->dev);
-		if (!td)
-			return -ENOMEM;
-
-		/* Alternate Data0/1 (start with Data1) */
-		destination ^= TD_TOKEN_TOGGLE;
-	
-		uhci_add_td_to_urb(urb, td);
-		uhci_fill_td(td, status, destination | ((pktsze - 1) << 21),
-			data);
-
-		data += pktsze;
-		len -= pktsze;
-	}
-
-	/*
-	 * Build the final TD for control status 
-	 */
-	td = uhci_alloc_td(uhci, urb->dev);
-	if (!td)
-		return -ENOMEM;
-
-	/*
-	 * It's IN if the pipe is an output pipe or we're not expecting
-	 * data back.
-	 */
-	destination &= ~TD_TOKEN_PID_MASK;
-	if (usb_pipeout(urb->pipe) || !urb->transfer_buffer_length)
-		destination |= USB_PID_IN;
-	else
-		destination |= USB_PID_OUT;
-
-	destination |= TD_TOKEN_TOGGLE;		/* End in Data1 */
-
-	status &= ~TD_CTRL_SPD;
-
-	uhci_add_td_to_urb(urb, td);
-	uhci_fill_td(td, status | TD_CTRL_IOC,
-		destination | (UHCI_NULL_DATA_SIZE << 21), 0);
-
-	qh = uhci_alloc_qh(uhci, urb->dev);
-	if (!qh)
-		return -ENOMEM;
-
-	urbp->qh = qh;
-	qh->urbp = urbp;
-
-	/* Low speed or small transfers gets a different queue and treatment */
-	if (urb->pipe & TD_CTRL_LS) {
-		uhci_insert_tds_in_qh(qh, urb, 0);
-		uhci_insert_qh(uhci, uhci->skel_ls_control_qh, urb);
-	} else {
-		uhci_insert_tds_in_qh(qh, urb, 1);
-		uhci_insert_qh(uhci, uhci->skel_hs_control_qh, urb);
-		uhci_inc_fsbr(uhci, urb);
-	}
-
-	return -EINPROGRESS;
-}
-
-static int usb_control_retrigger_status(struct urb *urb);
-
-static int uhci_result_control(struct urb *urb)
-{
-	struct list_head *tmp, *head;
-	struct urb_priv *urbp = urb->hcpriv;
-	struct uhci_td *td;
-	unsigned int status;
-	int ret = 0;
-
-	if (list_empty(&urbp->td_list))
-		return -EINVAL;
-
-	head = &urbp->td_list;
-
-	if (urbp->short_control_packet) {
-		tmp = head->prev;
-		goto status_phase;
-	}
-
-	tmp = head->next;
-	td = list_entry(tmp, struct uhci_td, list);
-
-	/* The first TD is the SETUP phase, check the status, but skip */
-	/*  the count */
-	status = uhci_status_bits(td->status);
-	if (status & TD_CTRL_ACTIVE)
-		return -EINPROGRESS;
-
-	if (status)
-		goto td_error;
-
-	urb->actual_length = 0;
-
-	/* The rest of the TD's (but the last) are data */
-	tmp = tmp->next;
-	while (tmp != head && tmp->next != head) {
-		td = list_entry(tmp, struct uhci_td, list);
-
-		tmp = tmp->next;
-
-		status = uhci_status_bits(td->status);
-		if (status & TD_CTRL_ACTIVE)
-			return -EINPROGRESS;
-
-		urb->actual_length += uhci_actual_length(td->status);
-
-		if (status)
-			goto td_error;
-
-		/* Check to see if we received a short packet */
-		if (uhci_actual_length(td->status) < uhci_expected_length(td->info)) {
-			if (urb->transfer_flags & USB_DISABLE_SPD) {
-				ret = -EREMOTEIO;
-				goto err;
-			}
-
-			if (uhci_packetid(td->info) == USB_PID_IN)
-				return usb_control_retrigger_status(urb);
-			else
-				return 0;
-		}
-	}
-
-status_phase:
-	td = list_entry(tmp, struct uhci_td, list);
-
-	/* Control status phase */
-	status = uhci_status_bits(td->status);
-
-#ifdef I_HAVE_BUGGY_APC_BACKUPS
-	/* APC BackUPS Pro kludge */
-	/* It tries to send all of the descriptor instead of the amount */
-	/*  we requested */
-	if (td->status & TD_CTRL_IOC &&	/* IOC is masked out by uhci_status_bits */
-	    status & TD_CTRL_ACTIVE &&
-	    status & TD_CTRL_NAK)
-		return 0;
-#endif
-
-	if (status & TD_CTRL_ACTIVE)
-		return -EINPROGRESS;
-
-	if (status)
-		goto td_error;
-
-	return 0;
-
-td_error:
-	ret = uhci_map_status(status, uhci_packetout(td->info));
-	if (ret == -EPIPE)
-		/* endpoint has stalled - mark it halted */
-		usb_endpoint_halt(urb->dev, uhci_endpoint(td->info),
-	    			uhci_packetout(td->info));
-
-err:
-	if ((debug == 1 && ret != -EPIPE) || debug > 1) {
-		/* Some debugging code */
-		dbg("uhci_result_control() failed with status %x", status);
-
-		if (errbuf) {
-			/* Print the chain for debugging purposes */
-			uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0);
-
-			lprintk(errbuf);
-		}
-	}
-
-	return ret;
-}
-
-static int usb_control_retrigger_status(struct urb *urb)
-{
-	struct list_head *tmp, *head;
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	struct uhci *uhci = urb->dev->bus->hcpriv;
-
-	urbp->short_control_packet = 1;
-
-	/* Create a new QH to avoid pointer overwriting problems */
-	uhci_remove_qh(uhci, urbp->qh);
-
-	/* Delete all of the TD's except for the status TD at the end */
-	head = &urbp->td_list;
-	tmp = head->next;
-	while (tmp != head && tmp->next != head) {
-		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
-
-		tmp = tmp->next;
-
-		uhci_remove_td_from_urb(td);
-		uhci_remove_td(uhci, td);
-		uhci_free_td(uhci, td);
-	}
-
-	urbp->qh = uhci_alloc_qh(uhci, urb->dev);
-	if (!urbp->qh) {
-		err("unable to allocate new QH for control retrigger");
-		return -ENOMEM;
-	}
-
-	urbp->qh->urbp = urbp;
-
-	/* One TD, who cares about Breadth first? */
-	uhci_insert_tds_in_qh(urbp->qh, urb, 0);
-
-	/* Low speed or small transfers gets a different queue and treatment */
-	if (urb->pipe & TD_CTRL_LS)
-		uhci_insert_qh(uhci, uhci->skel_ls_control_qh, urb);
-	else
-		uhci_insert_qh(uhci, uhci->skel_hs_control_qh, urb);
-
-	return -EINPROGRESS;
-}
-
-/*
- * Interrupt transfers
- */
-static int uhci_submit_interrupt(struct urb *urb)
-{
-	struct uhci_td *td;
-	unsigned long destination, status;
-	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-
-	if (urb->transfer_buffer_length > usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)))
-		return -EINVAL;
-
-	/* The "pipe" thing contains the destination in bits 8--18 */
-	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
-
-	status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC;
-
-	td = uhci_alloc_td(uhci, urb->dev);
-	if (!td)
-		return -ENOMEM;
-
-	destination |= (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT);
-	destination |= ((urb->transfer_buffer_length - 1) << 21);
-
-	usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
-
-	uhci_add_td_to_urb(urb, td);
-	uhci_fill_td(td, status, destination, urbp->transfer_buffer_dma_handle);
-
-	uhci_insert_td(uhci, uhci->skeltd[__interval_to_skel(urb->interval)], td);
-
-	return -EINPROGRESS;
-}
-
-static int uhci_result_interrupt(struct urb *urb)
-{
-	struct list_head *tmp, *head;
-	struct urb_priv *urbp = urb->hcpriv;
-	struct uhci_td *td;
-	unsigned int status;
-	int ret = 0;
-
-	urb->actual_length = 0;
-
-	head = &urbp->td_list;
-	tmp = head->next;
-	while (tmp != head) {
-		td = list_entry(tmp, struct uhci_td, list);
-
-		tmp = tmp->next;
-
-		status = uhci_status_bits(td->status);
-		if (status & TD_CTRL_ACTIVE)
-			return -EINPROGRESS;
-
-		urb->actual_length += uhci_actual_length(td->status);
-
-		if (status)
-			goto td_error;
-
-		if (uhci_actual_length(td->status) < uhci_expected_length(td->info)) {
-			if (urb->transfer_flags & USB_DISABLE_SPD) {
-				ret = -EREMOTEIO;
-				goto err;
-			} else
-				return 0;
-		}
-	}
-
-	return 0;
-
-td_error:
-	ret = uhci_map_status(status, uhci_packetout(td->info));
-	if (ret == -EPIPE)
-		/* endpoint has stalled - mark it halted */
-		usb_endpoint_halt(urb->dev, uhci_endpoint(td->info),
-	    			uhci_packetout(td->info));
-
-err:
-	if ((debug == 1 && ret != -EPIPE) || debug > 1) {
-		/* Some debugging code */
-		dbg("uhci_result_interrupt/bulk() failed with status %x",
-			status);
-
-		if (errbuf) {
-			/* Print the chain for debugging purposes */
-			if (urbp->qh)
-				uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0);
-			else
-				uhci_show_td(td, errbuf, ERRBUF_LEN, 0);
-
-			lprintk(errbuf);
-		}
-	}
-
-	return ret;
-}
-
-static void uhci_reset_interrupt(struct urb *urb)
-{
-	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	struct uhci_td *td;
-	unsigned long flags;
-
-	spin_lock_irqsave(&urb->lock, flags);
-
-	/* Root hub is special */
-	if (urb->dev == uhci->rh.dev)
-		goto out;
-
-	td = list_entry(urbp->td_list.next, struct uhci_td, list);
-
-	td->status = (td->status & 0x2F000000) | TD_CTRL_ACTIVE | TD_CTRL_IOC;
-	td->info &= ~TD_TOKEN_TOGGLE;
-	td->info |= (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT);
-	usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
-
-out:
-	urb->status = -EINPROGRESS;
-
-	spin_unlock_irqrestore(&urb->lock, flags);
-}
-
-/*
- * Bulk transfers
- */
-static int uhci_submit_bulk(struct urb *urb, struct urb *eurb)
-{
-	struct uhci_td *td;
-	struct uhci_qh *qh;
-	unsigned long destination, status;
-	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
-	int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
-	int len = urb->transfer_buffer_length;
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	dma_addr_t data = urbp->transfer_buffer_dma_handle;
-
-	if (len < 0)
-		return -EINVAL;
-
-	/* Can't have low speed bulk transfers */
-	if (urb->pipe & TD_CTRL_LS)
-		return -EINVAL;
-
-	/* The "pipe" thing contains the destination in bits 8--18 */
-	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
-
-	/* 3 errors */
-	status = TD_CTRL_ACTIVE | (3 << TD_CTRL_C_ERR_SHIFT);
-
-	if (!(urb->transfer_flags & USB_DISABLE_SPD))
-		status |= TD_CTRL_SPD;
-
-	/*
-	 * Build the DATA TD's
-	 */
-	do {	/* Allow zero length packets */
-		int pktsze = len;
-
-		if (pktsze > maxsze)
-			pktsze = maxsze;
-
-		td = uhci_alloc_td(uhci, urb->dev);
-		if (!td)
-			return -ENOMEM;
-
-		uhci_add_td_to_urb(urb, td);
-		uhci_fill_td(td, status, destination |
-			(((pktsze - 1) & UHCI_NULL_DATA_SIZE) << 21) |
-			(usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
-			 usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT),
-			data);
-
-		data += pktsze;
-		len -= maxsze;
-
-		usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),
-			usb_pipeout(urb->pipe));
-	} while (len > 0);
-
-	/*
-	 * USB_ZERO_PACKET means adding a 0-length packet, if
-	 * direction is OUT and the transfer_length was an
-	 * exact multiple of maxsze, hence
-	 * (len = transfer_length - N * maxsze) == 0
-	 * however, if transfer_length == 0, the zero packet
-	 * was already prepared above.
-	 */
-	if (usb_pipeout(urb->pipe) && (urb->transfer_flags & USB_ZERO_PACKET) &&
-	   !len && urb->transfer_buffer_length) {
-		td = uhci_alloc_td(uhci, urb->dev);
-		if (!td)
-			return -ENOMEM;
-
-		uhci_add_td_to_urb(urb, td);
-		uhci_fill_td(td, status, destination |
-			(UHCI_NULL_DATA_SIZE << 21) |
-			(usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
-			 usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT),
-			data);
-
-		usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),
-			usb_pipeout(urb->pipe));
-	}
-
-	/* Set the flag on the last packet */
-	td->status |= TD_CTRL_IOC;
-
-	qh = uhci_alloc_qh(uhci, urb->dev);
-	if (!qh)
-		return -ENOMEM;
-
-	urbp->qh = qh;
-	qh->urbp = urbp;
-
-	/* Always assume breadth first */
-	uhci_insert_tds_in_qh(qh, urb, 1);
-
-	if (urb->transfer_flags & USB_QUEUE_BULK && eurb)
-		uhci_append_queued_urb(uhci, eurb, urb);
-	else
-		uhci_insert_qh(uhci, uhci->skel_bulk_qh, urb);
-
-	uhci_inc_fsbr(uhci, urb);
-
-	return -EINPROGRESS;
-}
-
-/* We can use the result interrupt since they're identical */
-#define uhci_result_bulk uhci_result_interrupt
-
-/*
- * Isochronous transfers
- */
-static int isochronous_find_limits(struct urb *urb, unsigned int *start, unsigned int *end)
-{
-	struct urb *last_urb = NULL;
-	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
-	struct list_head *tmp, *head;
-	int ret = 0;
-
-	head = &uhci->urb_list;
-	tmp = head->next;
-	while (tmp != head) {
-		struct urb *u = list_entry(tmp, struct urb, urb_list);
-
-		tmp = tmp->next;
-
-		/* look for pending URB's with identical pipe handle */
-		if ((urb->pipe == u->pipe) && (urb->dev == u->dev) &&
-		    (u->status == -EINPROGRESS) && (u != urb)) {
-			if (!last_urb)
-				*start = u->start_frame;
-			last_urb = u;
-		}
-	}
-
-	if (last_urb) {
-		*end = (last_urb->start_frame + last_urb->number_of_packets) & 1023;
-		ret = 0;
-	} else
-		ret = -1;	/* no previous urb found */
-
-	return ret;
-}
-
-static int isochronous_find_start(struct urb *urb)
-{
-	int limits;
-	unsigned int start = 0, end = 0;
-
-	if (urb->number_of_packets > 900)	/* 900? Why? */
-		return -EFBIG;
-
-	limits = isochronous_find_limits(urb, &start, &end);
-
-	if (urb->transfer_flags & USB_ISO_ASAP) {
-		if (limits) {
-			int curframe;
-
-			curframe = uhci_get_current_frame_number(urb->dev) % UHCI_NUMFRAMES;
-			urb->start_frame = (curframe + 10) % UHCI_NUMFRAMES;
-		} else
-			urb->start_frame = end;
-	} else {
-		urb->start_frame %= UHCI_NUMFRAMES;
-		/* FIXME: Sanity check */
-	}
-
-	return 0;
-}
-
-/*
- * Isochronous transfers
- */
-static int uhci_submit_isochronous(struct urb *urb)
-{
-	struct uhci_td *td;
-	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
-	int i, ret, framenum;
-	int status, destination;
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-
-	status = TD_CTRL_ACTIVE | TD_CTRL_IOS;
-	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
-
-	ret = isochronous_find_start(urb);
-	if (ret)
-		return ret;
-
-	framenum = urb->start_frame;
-	for (i = 0; i < urb->number_of_packets; i++, framenum++) {
-		if (!urb->iso_frame_desc[i].length)
-			continue;
-
-		td = uhci_alloc_td(uhci, urb->dev);
-		if (!td)
-			return -ENOMEM;
-
-		uhci_add_td_to_urb(urb, td);
-		uhci_fill_td(td, status, destination | ((urb->iso_frame_desc[i].length - 1) << 21),
-			urbp->transfer_buffer_dma_handle + urb->iso_frame_desc[i].offset);
-
-		if (i + 1 >= urb->number_of_packets)
-			td->status |= TD_CTRL_IOC;
-
-		uhci_insert_td_frame_list(uhci, td, framenum);
-	}
-
-	return -EINPROGRESS;
-}
-
-static int uhci_result_isochronous(struct urb *urb)
-{
-	struct list_head *tmp, *head;
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	int status;
-	int i, ret = 0;
-
-	urb->actual_length = 0;
-
-	i = 0;
-	head = &urbp->td_list;
-	tmp = head->next;
-	while (tmp != head) {
-		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
-		int actlength;
-
-		tmp = tmp->next;
-
-		if (td->status & TD_CTRL_ACTIVE)
-			return -EINPROGRESS;
-
-		actlength = uhci_actual_length(td->status);
-		urb->iso_frame_desc[i].actual_length = actlength;
-		urb->actual_length += actlength;
-
-		status = uhci_map_status(uhci_status_bits(td->status), usb_pipeout(urb->pipe));
-		urb->iso_frame_desc[i].status = status;
-		if (status) {
-			urb->error_count++;
-			ret = status;
-		}
-
-		i++;
-	}
-
-	return ret;
-}
-
-/*
- * MUST be called with uhci->urb_list_lock acquired
- */
-static struct urb *uhci_find_urb_ep(struct uhci *uhci, struct urb *urb)
-{
-	struct list_head *tmp, *head;
-
-	/* We don't match Isoc transfers since they are special */
-	if (usb_pipeisoc(urb->pipe))
-		return NULL;
-
-	head = &uhci->urb_list;
-	tmp = head->next;
-	while (tmp != head) {
-		struct urb *u = list_entry(tmp, struct urb, urb_list);
-
-		tmp = tmp->next;
-
-		if (u->dev == urb->dev && u->pipe == urb->pipe &&
-		    u->status == -EINPROGRESS)
-			return u;
-	}
-
-	return NULL;
-}
-
-static int uhci_submit_urb(struct urb *urb)
-{
-	int ret = -EINVAL;
-	struct uhci *uhci;
-	unsigned long flags;
-	struct urb *eurb;
-	int bustime;
-
-	if (!urb)
-		return -EINVAL;
-
-	if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv) {
-		warn("uhci_submit_urb: urb %p belongs to disconnected device or bus?", urb);
-		return -ENODEV;
-	}
-
-	uhci = (struct uhci *)urb->dev->bus->hcpriv;
-
-	INIT_LIST_HEAD(&urb->urb_list);
-	usb_inc_dev_use(urb->dev);
-
-	spin_lock_irqsave(&uhci->urb_list_lock, flags);
-	spin_lock(&urb->lock);
-
-	if (urb->status == -EINPROGRESS || urb->status == -ECONNRESET ||
-	    urb->status == -ECONNABORTED) {
-		dbg("uhci_submit_urb: urb not available to submit (status = %d)", urb->status);
-		/* Since we can have problems on the out path */
-		spin_unlock(&urb->lock);
-		spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
-		usb_dec_dev_use(urb->dev);
-
-		return ret;
-	}
-
-	if (!uhci_alloc_urb_priv(uhci, urb)) {
-		ret = -ENOMEM;
-
-		goto out;
-	}
-
-	eurb = uhci_find_urb_ep(uhci, urb);
-	if (eurb && !(urb->transfer_flags & USB_QUEUE_BULK)) {
-		ret = -ENXIO;
-
-		goto out;
-	}
-
-	/* Short circuit the virtual root hub */
-	if (urb->dev == uhci->rh.dev) {
-		ret = rh_submit_urb(urb);
-
-		goto out;
-	}
-
-	switch (usb_pipetype(urb->pipe)) {
-	case PIPE_CONTROL:
-		ret = uhci_submit_control(urb);
-		break;
-	case PIPE_INTERRUPT:
-		if (urb->bandwidth == 0) {	/* not yet checked/allocated */
-			bustime = usb_check_bandwidth(urb->dev, urb);
-			if (bustime < 0)
-				ret = bustime;
-			else {
-				ret = uhci_submit_interrupt(urb);
-				if (ret == -EINPROGRESS)
-					usb_claim_bandwidth(urb->dev, urb, bustime, 0);
-			}
-		} else		/* bandwidth is already set */
-			ret = uhci_submit_interrupt(urb);
-		break;
-	case PIPE_BULK:
-		ret = uhci_submit_bulk(urb, eurb);
-		break;
-	case PIPE_ISOCHRONOUS:
-		if (urb->bandwidth == 0) {	/* not yet checked/allocated */
-			if (urb->number_of_packets <= 0) {
-				ret = -EINVAL;
-				break;
-			}
-			bustime = usb_check_bandwidth(urb->dev, urb);
-			if (bustime < 0) {
-				ret = bustime;
-				break;
-			}
-
-			ret = uhci_submit_isochronous(urb);
-			if (ret == -EINPROGRESS)
-				usb_claim_bandwidth(urb->dev, urb, bustime, 1);
-		} else		/* bandwidth is already set */
-			ret = uhci_submit_isochronous(urb);
-		break;
-	}
-
-out:
-	urb->status = ret;
-
-	if (ret == -EINPROGRESS) {
-		/* We use _tail to make find_urb_ep more efficient */
-		list_add_tail(&urb->urb_list, &uhci->urb_list);
-
-		spin_unlock(&urb->lock);
-		spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
-
-		return 0;
-	}
-
-	uhci_unlink_generic(uhci, urb);
-
-	spin_unlock(&urb->lock);
-	spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
-
-	/* Only call completion if it was successful */
-	if (!ret)
-		uhci_call_completion(urb);
-
-	return ret;
-}
-
-/*
- * Return the result of a transfer
- *
- * MUST be called with urb_list_lock acquired
- */
-static void uhci_transfer_result(struct uhci *uhci, struct urb *urb)
-{
-	int ret = -EINVAL;
-	unsigned long flags;
-	struct urb_priv *urbp;
-
-	/* The root hub is special */
-	if (urb->dev == uhci->rh.dev)
-		return;
-
-	spin_lock_irqsave(&urb->lock, flags);
-
-	urbp = (struct urb_priv *)urb->hcpriv;
-
-	if (urb->status != -EINPROGRESS) {
-		info("uhci_transfer_result: called for URB %p not in flight?", urb);
-		goto out;
-	}
-
-	switch (usb_pipetype(urb->pipe)) {
-	case PIPE_CONTROL:
-		ret = uhci_result_control(urb);
-		break;
-	case PIPE_INTERRUPT:
-		ret = uhci_result_interrupt(urb);
-		break;
-	case PIPE_BULK:
-		ret = uhci_result_bulk(urb);
-		break;
-	case PIPE_ISOCHRONOUS:
-		ret = uhci_result_isochronous(urb);
-		break;
-	}
-
-	urbp->status = ret;
-
-	if (ret == -EINPROGRESS)
-		goto out;
-
-	switch (usb_pipetype(urb->pipe)) {
-	case PIPE_CONTROL:
-	case PIPE_BULK:
-	case PIPE_ISOCHRONOUS:
-		/* Release bandwidth for Interrupt or Isoc. transfers */
-		/* Spinlock needed ? */
-		if (urb->bandwidth)
-			usb_release_bandwidth(urb->dev, urb, 1);
-		uhci_unlink_generic(uhci, urb);
-		break;
-	case PIPE_INTERRUPT:
-		/* Interrupts are an exception */
-		if (urb->interval)
-			goto out_complete;
-
-		/* Release bandwidth for Interrupt or Isoc. transfers */
-		/* Spinlock needed ? */
-		if (urb->bandwidth)
-			usb_release_bandwidth(urb->dev, urb, 0);
-		uhci_unlink_generic(uhci, urb);
-		break;
-	default:
-		info("uhci_transfer_result: unknown pipe type %d for urb %p\n",
-			usb_pipetype(urb->pipe), urb);
-	}
-
-	/* Remove it from uhci->urb_list */
-	list_del_init(&urb->urb_list);
-
-out_complete:
-	uhci_add_complete(urb);
-
-out:
-	spin_unlock_irqrestore(&urb->lock, flags);
-}
-
-/*
- * MUST be called with urb->lock acquired
- */
-static void uhci_unlink_generic(struct uhci *uhci, struct urb *urb)
-{
-	struct list_head *head, *tmp;
-	struct urb_priv *urbp = urb->hcpriv;
-	int prevactive = 1;
-
-	/* We can get called when urbp allocation fails, so check */
-	if (!urbp)
-		return;
-
-	uhci_dec_fsbr(uhci, urb);	/* Safe since it checks */
-
-	/*
-	 * Now we need to find out what the last successful toggle was
-	 * so we can update the local data toggle for the next transfer
-	 *
-	 * There's 3 way's the last successful completed TD is found:
-	 *
-	 * 1) The TD is NOT active and the actual length < expected length
-	 * 2) The TD is NOT active and it's the last TD in the chain
-	 * 3) The TD is active and the previous TD is NOT active
-	 *
-	 * Control and Isochronous ignore the toggle, so this is safe
-	 * for all types
-	 */
-	head = &urbp->td_list;
-	tmp = head->next;
-	while (tmp != head) {
-		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
-
-		tmp = tmp->next;
-
-		if (!(td->status & TD_CTRL_ACTIVE) &&
-		    (uhci_actual_length(td->status) < uhci_expected_length(td->info) ||
-		    tmp == head))
-			usb_settoggle(urb->dev, uhci_endpoint(td->info),
-				uhci_packetout(td->info),
-				uhci_toggle(td->info) ^ 1);
-		else if ((td->status & TD_CTRL_ACTIVE) && !prevactive)
-			usb_settoggle(urb->dev, uhci_endpoint(td->info),
-				uhci_packetout(td->info),
-				uhci_toggle(td->info));
-
-		prevactive = td->status & TD_CTRL_ACTIVE;
-	}
-
-	uhci_delete_queued_urb(uhci, urb);
-
-	/* The interrupt loop will reclaim the QH's */
-	uhci_remove_qh(uhci, urbp->qh);
-	urbp->qh = NULL;
-}
-
-static int uhci_unlink_urb(struct urb *urb)
-{
-	struct uhci *uhci;
-	unsigned long flags;
-	struct urb_priv *urbp = urb->hcpriv;
-
-	if (!urb)
-		return -EINVAL;
-
-	if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv)
-		return -ENODEV;
-
-	uhci = (struct uhci *)urb->dev->bus->hcpriv;
-
-	spin_lock_irqsave(&uhci->urb_list_lock, flags);
-	spin_lock(&urb->lock);
-
-	/* Release bandwidth for Interrupt or Isoc. transfers */
-	/* Spinlock needed ? */
-	if (urb->bandwidth) {
-		switch (usb_pipetype(urb->pipe)) {
-		case PIPE_INTERRUPT:
-			usb_release_bandwidth(urb->dev, urb, 0);
-			break;
-		case PIPE_ISOCHRONOUS:
-			usb_release_bandwidth(urb->dev, urb, 1);
-			break;
-		default:
-			break;
-		}
-	}
-
-	if (urb->status != -EINPROGRESS) {
-		spin_unlock(&urb->lock);
-		spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
-		return 0;
-	}
-
-	list_del_init(&urb->urb_list);
-
-	uhci_unlink_generic(uhci, urb);
-
-	/* Short circuit the virtual root hub */
-	if (urb->dev == uhci->rh.dev) {
-		rh_unlink_urb(urb);
-
-		spin_unlock(&urb->lock);
-		spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
-
-		uhci_call_completion(urb);
-	} else {
-		if (urb->transfer_flags & USB_ASYNC_UNLINK) {
-			urbp->status = urb->status = -ECONNABORTED;
-
-			spin_lock(&uhci->urb_remove_list_lock);
-
-			/* If we're the first, set the next interrupt bit */
-			if (list_empty(&uhci->urb_remove_list))
-				uhci_set_next_interrupt(uhci);
-			
-			list_add(&urb->urb_list, &uhci->urb_remove_list);
-
-			spin_unlock(&uhci->urb_remove_list_lock);
-
-			spin_unlock(&urb->lock);
-			spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
-
-		} else {
-			urb->status = -ENOENT;
-
-			spin_unlock(&urb->lock);
-			spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
-
-			if (in_interrupt()) {	/* wait at least 1 frame */
-				static int errorcount = 10;
-
-				if (errorcount--)
-					dbg("uhci_unlink_urb called from interrupt for urb %p", urb);
-				udelay(1000);
-			} else
-				schedule_timeout(1+1*HZ/1000); 
-
-			uhci_call_completion(urb);
-		}
-	}
-
-	return 0;
-}
-
-static int uhci_fsbr_timeout(struct uhci *uhci, struct urb *urb)
-{
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	struct list_head *head, *tmp;
-	int count = 0;
-
-	uhci_dec_fsbr(uhci, urb);
-
-	urbp->fsbr_timeout = 1;
-
-	/*
-	 * Ideally we would want to fix qh->element as well, but it's
-	 * read/write by the HC, so that can introduce a race. It's not
-	 * really worth the hassle
-	 */
-
-	head = &urbp->td_list;
-	tmp = head->next;
-	while (tmp != head) {
-		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
-
-		tmp = tmp->next;
-
-		/*
-		 * Make sure we don't do the last one (since it'll have the
-		 * TERM bit set) as well as we skip every so many TD's to
-		 * make sure it doesn't hog the bandwidth
-		 */
-		if (tmp != head && (count % DEPTH_INTERVAL) == (DEPTH_INTERVAL - 1))
-			td->link |= UHCI_PTR_DEPTH;
-
-		count++;
-	}
-
-	return 0;
-}
-
-/*
- * uhci_get_current_frame_number()
- *
- * returns the current frame number for a USB bus/controller.
- */
-static int uhci_get_current_frame_number(struct usb_device *dev)
-{
-	struct uhci *uhci = (struct uhci *)dev->bus->hcpriv;
-
-	return inw(uhci->io_addr + USBFRNUM);
-}
-
-struct usb_operations uhci_device_operations = {
-	uhci_alloc_dev,
-	uhci_free_dev,
-	uhci_get_current_frame_number,
-	uhci_submit_urb,
-	uhci_unlink_urb
-};
-
-/* Virtual Root Hub */
-
-static __u8 root_hub_dev_des[] =
-{
- 	0x12,			/*  __u8  bLength; */
-	0x01,			/*  __u8  bDescriptorType; Device */
-	0x00,			/*  __u16 bcdUSB; v1.0 */
-	0x01,
-	0x09,			/*  __u8  bDeviceClass; HUB_CLASSCODE */
-	0x00,			/*  __u8  bDeviceSubClass; */
-	0x00,			/*  __u8  bDeviceProtocol; */
-	0x08,			/*  __u8  bMaxPacketSize0; 8 Bytes */
-	0x00,			/*  __u16 idVendor; */
-	0x00,
-	0x00,			/*  __u16 idProduct; */
-	0x00,
-	0x00,			/*  __u16 bcdDevice; */
-	0x00,
-	0x00,			/*  __u8  iManufacturer; */
-	0x02,			/*  __u8  iProduct; */
-	0x01,			/*  __u8  iSerialNumber; */
-	0x01			/*  __u8  bNumConfigurations; */
-};
-
-
-/* Configuration descriptor */
-static __u8 root_hub_config_des[] =
-{
-	0x09,			/*  __u8  bLength; */
-	0x02,			/*  __u8  bDescriptorType; Configuration */
-	0x19,			/*  __u16 wTotalLength; */
-	0x00,
-	0x01,			/*  __u8  bNumInterfaces; */
-	0x01,			/*  __u8  bConfigurationValue; */
-	0x00,			/*  __u8  iConfiguration; */
-	0x40,			/*  __u8  bmAttributes;
-					Bit 7: Bus-powered, 6: Self-powered,
-					Bit 5 Remote-wakeup, 4..0: resvd */
-	0x00,			/*  __u8  MaxPower; */
-
-	/* interface */
-	0x09,			/*  __u8  if_bLength; */
-	0x04,			/*  __u8  if_bDescriptorType; Interface */
-	0x00,			/*  __u8  if_bInterfaceNumber; */
-	0x00,			/*  __u8  if_bAlternateSetting; */
-	0x01,			/*  __u8  if_bNumEndpoints; */
-	0x09,			/*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
-	0x00,			/*  __u8  if_bInterfaceSubClass; */
-	0x00,			/*  __u8  if_bInterfaceProtocol; */
-	0x00,			/*  __u8  if_iInterface; */
-
-	/* endpoint */
-	0x07,			/*  __u8  ep_bLength; */
-	0x05,			/*  __u8  ep_bDescriptorType; Endpoint */
-	0x81,			/*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
-	0x03,			/*  __u8  ep_bmAttributes; Interrupt */
-	0x08,			/*  __u16 ep_wMaxPacketSize; 8 Bytes */
-	0x00,
-	0xff			/*  __u8  ep_bInterval; 255 ms */
-};
-
-static __u8 root_hub_hub_des[] =
-{
-	0x09,			/*  __u8  bLength; */
-	0x29,			/*  __u8  bDescriptorType; Hub-descriptor */
-	0x02,			/*  __u8  bNbrPorts; */
-	0x00,			/* __u16  wHubCharacteristics; */
-	0x00,
-	0x01,			/*  __u8  bPwrOn2pwrGood; 2ms */
-	0x00,			/*  __u8  bHubContrCurrent; 0 mA */
-	0x00,			/*  __u8  DeviceRemovable; *** 7 Ports max *** */
-	0xff			/*  __u8  PortPwrCtrlMask; *** 7 ports max *** */
-};
-
-/* prepare Interrupt pipe transaction data; HUB INTERRUPT ENDPOINT */
-static int rh_send_irq(struct urb *urb)
-{
-	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-	unsigned int io_addr = uhci->io_addr;
-	unsigned long flags;
-	int i, len = 1;
-	__u16 data = 0;
-
-	spin_lock_irqsave(&urb->lock, flags);
-	for (i = 0; i < uhci->rh.numports; i++) {
-		data |= ((inw(io_addr + USBPORTSC1 + i * 2) & 0xa) > 0 ? (1 << (i + 1)) : 0);
-		len = (i + 1) / 8 + 1;
-	}
-
-	*(__u16 *) urb->transfer_buffer = cpu_to_le16(data);
-	urb->actual_length = len;
-	urbp->status = 0;
-
-	spin_unlock_irqrestore(&urb->lock, flags);
-
-	if ((data > 0) && (uhci->rh.send != 0)) {
-		dbg("root-hub INT complete: port1: %x port2: %x data: %x",
-			inw(io_addr + USBPORTSC1), inw(io_addr + USBPORTSC2), data);
-		uhci_call_completion(urb);
-	}
-
-	return 0;
-}
-
-/* Virtual Root Hub INTs are polled by this timer every "interval" ms */
-static int rh_init_int_timer(struct urb *urb);
-
-static void rh_int_timer_do(unsigned long ptr)
-{
-	struct urb *urb = (struct urb *)ptr;
-	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
-	struct list_head list, *tmp, *head;
-	unsigned long flags;
-
-	if (uhci->rh.send)
-		rh_send_irq(urb);
-
-	INIT_LIST_HEAD(&list);
-
-	spin_lock_irqsave(&uhci->urb_list_lock, flags);
-	head = &uhci->urb_list;
-	tmp = head->next;
-	while (tmp != head) {
-		struct urb *u = list_entry(tmp, struct urb, urb_list);
-		struct urb_priv *up = (struct urb_priv *)u->hcpriv;
-
-		tmp = tmp->next;
-
-		spin_lock(&u->lock);
-
-		/* Check if the FSBR timed out */
-		if (up->fsbr && !up->fsbr_timeout && time_after_eq(jiffies, up->fsbrtime + IDLE_TIMEOUT))
-			uhci_fsbr_timeout(uhci, u);
-
-		/* Check if the URB timed out */
-		if (u->timeout && time_after_eq(jiffies, up->inserttime + u->timeout)) {
-			list_del(&u->urb_list);
-			list_add_tail(&u->urb_list, &list);
-		}
-
-		spin_unlock(&u->lock);
-	}
-	spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
-
-	head = &list;
-	tmp = head->next;
-	while (tmp != head) {
-		struct urb *u = list_entry(tmp, struct urb, urb_list);
-
-		tmp = tmp->next;
-
-		u->transfer_flags |= USB_ASYNC_UNLINK | USB_TIMEOUT_KILLED;
-		uhci_unlink_urb(u);
-	}
-
-	/* Really disable FSBR */
-	if (!uhci->fsbr && uhci->fsbrtimeout && time_after_eq(jiffies, uhci->fsbrtimeout)) {
-		uhci->fsbrtimeout = 0;
-		uhci->skel_term_qh->link = UHCI_PTR_TERM;
-	}
-
-	/* enter global suspend if nothing connected */
-	if (!uhci->is_suspended && !ports_active(uhci))
-		suspend_hc(uhci);
-
-	rh_init_int_timer(urb);
-}
-
-/* Root Hub INTs are polled by this timer */
-static int rh_init_int_timer(struct urb *urb)
-{
-	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
-
-	uhci->rh.interval = urb->interval;
-	init_timer(&uhci->rh.rh_int_timer);
-	uhci->rh.rh_int_timer.function = rh_int_timer_do;
-	uhci->rh.rh_int_timer.data = (unsigned long)urb;
-	uhci->rh.rh_int_timer.expires = jiffies + (HZ * (urb->interval < 30 ? 30 : urb->interval)) / 1000;
-	add_timer(&uhci->rh.rh_int_timer);
-
-	return 0;
-}
-
-#define OK(x)			len = (x); break
-
-#define CLR_RH_PORTSTAT(x) \
-	status = inw(io_addr + USBPORTSC1 + 2 * (wIndex-1)); \
-	status = (status & 0xfff5) & ~(x); \
-	outw(status, io_addr + USBPORTSC1 + 2 * (wIndex-1))
-
-#define SET_RH_PORTSTAT(x) \
-	status = inw(io_addr + USBPORTSC1 + 2 * (wIndex-1)); \
-	status = (status & 0xfff5) | (x); \
-	outw(status, io_addr + USBPORTSC1 + 2 * (wIndex-1))
-
-
-/* Root Hub Control Pipe */
-static int rh_submit_urb(struct urb *urb)
-{
-	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
-	unsigned int pipe = urb->pipe;
-	struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *)urb->setup_packet;
-	void *data = urb->transfer_buffer;
-	int leni = urb->transfer_buffer_length;
-	int len = 0;
-	int status = 0;
-	int stat = 0;
-	int i;
-	unsigned int io_addr = uhci->io_addr;
-	__u16 cstatus;
-	__u16 bmRType_bReq;
-	__u16 wValue;
-	__u16 wIndex;
-	__u16 wLength;
-
-	if (usb_pipetype(pipe) == PIPE_INTERRUPT) {
-		uhci->rh.urb = urb;
-		uhci->rh.send = 1;
-		uhci->rh.interval = urb->interval;
-		rh_init_int_timer(urb);
-
-		return -EINPROGRESS;
-	}
-
-	bmRType_bReq = cmd->bRequestType | cmd->bRequest << 8;
-	wValue = le16_to_cpu(cmd->wValue);
-	wIndex = le16_to_cpu(cmd->wIndex);
-	wLength = le16_to_cpu(cmd->wLength);
-
-	for (i = 0; i < 8; i++)
-		uhci->rh.c_p_r[i] = 0;
-
-	switch (bmRType_bReq) {
-		/* Request Destination:
-		   without flags: Device,
-		   RH_INTERFACE: interface,
-		   RH_ENDPOINT: endpoint,
-		   RH_CLASS means HUB here,
-		   RH_OTHER | RH_CLASS  almost ever means HUB_PORT here
-		*/
-
-	case RH_GET_STATUS:
-		*(__u16 *)data = cpu_to_le16(1);
-		OK(2);
-	case RH_GET_STATUS | RH_INTERFACE:
-		*(__u16 *)data = cpu_to_le16(0);
-		OK(2);
-	case RH_GET_STATUS | RH_ENDPOINT:
-		*(__u16 *)data = cpu_to_le16(0);
-		OK(2);
-	case RH_GET_STATUS | RH_CLASS:
-		*(__u32 *)data = cpu_to_le32(0);
-		OK(4);		/* hub power */
-	case RH_GET_STATUS | RH_OTHER | RH_CLASS:
-		status = inw(io_addr + USBPORTSC1 + 2 * (wIndex - 1));
-		cstatus = ((status & USBPORTSC_CSC) >> (1 - 0)) |
-			((status & USBPORTSC_PEC) >> (3 - 1)) |
-			(uhci->rh.c_p_r[wIndex - 1] << (0 + 4));
-			status = (status & USBPORTSC_CCS) |
-			((status & USBPORTSC_PE) >> (2 - 1)) |
-			((status & USBPORTSC_SUSP) >> (12 - 2)) |
-			((status & USBPORTSC_PR) >> (9 - 4)) |
-			(1 << 8) |      /* power on */
-			((status & USBPORTSC_LSDA) << (-8 + 9));
-
-		*(__u16 *)data = cpu_to_le16(status);
-		*(__u16 *)(data + 2) = cpu_to_le16(cstatus);
-		OK(4);
-	case RH_CLEAR_FEATURE | RH_ENDPOINT:
-		switch (wValue) {
-		case RH_ENDPOINT_STALL:
-			OK(0);
-		}
-		break;
-	case RH_CLEAR_FEATURE | RH_CLASS:
-		switch (wValue) {
-		case RH_C_HUB_OVER_CURRENT:
-			OK(0);	/* hub power over current */
-		}
-		break;
-	case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
-		switch (wValue) {
-		case RH_PORT_ENABLE:
-			CLR_RH_PORTSTAT(USBPORTSC_PE);
-			OK(0);
-		case RH_PORT_SUSPEND:
-			CLR_RH_PORTSTAT(USBPORTSC_SUSP);
-			OK(0);
-		case RH_PORT_POWER:
-			OK(0);	/* port power */
-		case RH_C_PORT_CONNECTION:
-			SET_RH_PORTSTAT(USBPORTSC_CSC);
-			OK(0);
-		case RH_C_PORT_ENABLE:
-			SET_RH_PORTSTAT(USBPORTSC_PEC);
-			OK(0);
-		case RH_C_PORT_SUSPEND:
-			/*** WR_RH_PORTSTAT(RH_PS_PSSC); */
-			OK(0);
-		case RH_C_PORT_OVER_CURRENT:
-			OK(0);	/* port power over current */
-		case RH_C_PORT_RESET:
-			uhci->rh.c_p_r[wIndex - 1] = 0;
-			OK(0);
-		}
-		break;
-	case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
-		switch (wValue) {
-		case RH_PORT_SUSPEND:
-			SET_RH_PORTSTAT(USBPORTSC_SUSP);
-			OK(0);
-		case RH_PORT_RESET:
-			SET_RH_PORTSTAT(USBPORTSC_PR);
-			mdelay(50);	/* USB v1.1 7.1.7.3 */
-			uhci->rh.c_p_r[wIndex - 1] = 1;
-			CLR_RH_PORTSTAT(USBPORTSC_PR);
-			udelay(10);
-			SET_RH_PORTSTAT(USBPORTSC_PE);
-			mdelay(10);
-			SET_RH_PORTSTAT(0xa);
-			OK(0);
-		case RH_PORT_POWER:
-			OK(0); /* port power ** */
-		case RH_PORT_ENABLE:
-			SET_RH_PORTSTAT(USBPORTSC_PE);
-			OK(0);
-		}
-		break;
-	case RH_SET_ADDRESS:
-		uhci->rh.devnum = wValue;
-		OK(0);
-	case RH_GET_DESCRIPTOR:
-		switch ((wValue & 0xff00) >> 8) {
-		case 0x01:	/* device descriptor */
-			len = min_t(unsigned int, leni,
-				  min_t(unsigned int,
-				      sizeof(root_hub_dev_des), wLength));
-			memcpy(data, root_hub_dev_des, len);
-			OK(len);
-		case 0x02:	/* configuration descriptor */
-			len = min_t(unsigned int, leni,
-				  min_t(unsigned int,
-				      sizeof(root_hub_config_des), wLength));
-			memcpy (data, root_hub_config_des, len);
-			OK(len);
-		case 0x03:	/* string descriptors */
-			len = usb_root_hub_string (wValue & 0xff,
-				uhci->io_addr, "UHCI-alt",
-				data, wLength);
-			if (len > 0) {
-				OK(min_t(int, leni, len));
-			} else 
-				stat = -EPIPE;
-		}
-		break;
-	case RH_GET_DESCRIPTOR | RH_CLASS:
-		root_hub_hub_des[2] = uhci->rh.numports;
-		len = min_t(unsigned int, leni,
-			  min_t(unsigned int, sizeof(root_hub_hub_des), wLength));
-		memcpy(data, root_hub_hub_des, len);
-		OK(len);
-	case RH_GET_CONFIGURATION:
-		*(__u8 *)data = 0x01;
-		OK(1);
-	case RH_SET_CONFIGURATION:
-		OK(0);
-	case RH_GET_INTERFACE | RH_INTERFACE:
-		*(__u8 *)data = 0x00;
-		OK(1);
-	case RH_SET_INTERFACE | RH_INTERFACE:
-		OK(0);
-	default:
-		stat = -EPIPE;
-	}
-
-	urb->actual_length = len;
-
-	return stat;
-}
-
-/*
- * MUST be called with urb->lock acquired
- */
-static int rh_unlink_urb(struct urb *urb)
-{
-	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
-
-	if (uhci->rh.urb == urb) {
-		urb->status = -ENOENT;
-		uhci->rh.send = 0;
-		uhci->rh.urb = NULL;
-		del_timer(&uhci->rh.rh_int_timer);
-	}
-	return 0;
-}
-
-static void uhci_free_pending_qhs(struct uhci *uhci)
-{
-	struct list_head *tmp, *head;
-	unsigned long flags;
-
-	spin_lock_irqsave(&uhci->qh_remove_list_lock, flags);
-	head = &uhci->qh_remove_list;
-	tmp = head->next;
-	while (tmp != head) {
-		struct uhci_qh *qh = list_entry(tmp, struct uhci_qh, remove_list);
-
-		tmp = tmp->next;
-
-		list_del_init(&qh->remove_list);
-
-		uhci_free_qh(uhci, qh);
-	}
-	spin_unlock_irqrestore(&uhci->qh_remove_list_lock, flags);
-}
-
-static void uhci_call_completion(struct urb *urb)
-{
-	struct urb_priv *urbp;
-	struct usb_device *dev = urb->dev;
-	struct uhci *uhci = (struct uhci *)dev->bus->hcpriv;
-	int is_ring = 0, killed, resubmit_interrupt, status;
-	struct urb *nurb;
-	unsigned long flags;
-
-	spin_lock_irqsave(&urb->lock, flags);
-
-	urbp = (struct urb_priv *)urb->hcpriv;
-	if (!urbp || !urb->dev) {
-		spin_unlock_irqrestore(&urb->lock, flags);
-		return;
-	}
-
-	killed = (urb->status == -ENOENT || urb->status == -ECONNABORTED ||
-			urb->status == -ECONNRESET);
-	resubmit_interrupt = (usb_pipetype(urb->pipe) == PIPE_INTERRUPT &&
-			urb->interval);
-
-	nurb = urb->next;
-	if (nurb && !killed) {
-		int count = 0;
-
-		while (nurb && nurb != urb && count < MAX_URB_LOOP) {
-			if (nurb->status == -ENOENT ||
-			    nurb->status == -ECONNABORTED ||
-			    nurb->status == -ECONNRESET) {
-				killed = 1;
-				break;
-			}
-
-			nurb = nurb->next;
-			count++;
-		}
-
-		if (count == MAX_URB_LOOP)
-			err("uhci_call_completion: too many linked URB's, loop? (first loop)");
-
-		/* Check to see if chain is a ring */
-		is_ring = (nurb == urb);
-	}
-
-	if (urbp->transfer_buffer_dma_handle)
-		pci_dma_sync_single(uhci->dev, urbp->transfer_buffer_dma_handle,
-			urb->transfer_buffer_length, usb_pipein(urb->pipe) ?
-			PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
-
-	if (urbp->setup_packet_dma_handle)
-		pci_dma_sync_single(uhci->dev, urbp->setup_packet_dma_handle,
-			sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE);
-
-	status = urbp->status;
-	if (!resubmit_interrupt || killed)
-		/* We don't need urb_priv anymore */
-		uhci_destroy_urb_priv(urb);
-
-	if (!killed)
-		urb->status = status;
-
-	urb->dev = NULL;
-	spin_unlock_irqrestore(&urb->lock, flags);
-
-	if (urb->complete)
-		urb->complete(urb);
-
-	if (resubmit_interrupt)
-		/* Recheck the status. The completion handler may have */
-		/*  unlinked the resubmitting interrupt URB */
-		killed = (urb->status == -ENOENT ||
-			  urb->status == -ECONNABORTED ||
-			  urb->status == -ECONNRESET);
-
-	if (resubmit_interrupt && !killed) {
-		urb->dev = dev;
-		uhci_reset_interrupt(urb);
-	} else {
-		if (is_ring && !killed) {
-			urb->dev = dev;
-			uhci_submit_urb(urb);
-		} else {
-			/* We decrement the usage count after we're done */
-			/*  with everything */
-			usb_dec_dev_use(dev);
-		}
-	}
-}
-
-static void uhci_finish_completion(struct uhci *uhci)
-{
-	struct list_head *tmp, *head;
-	unsigned long flags;
-
-	spin_lock_irqsave(&uhci->complete_list_lock, flags);
-	head = &uhci->complete_list;
-	tmp = head->next;
-	while (tmp != head) {
-		struct urb_priv *urbp = list_entry(tmp, struct urb_priv, complete_list);
-		struct urb *urb = urbp->urb;
-
-		list_del_init(&urbp->complete_list);
-		spin_unlock_irqrestore(&uhci->complete_list_lock, flags);
-
-		uhci_call_completion(urb);
-
-		spin_lock_irqsave(&uhci->complete_list_lock, flags);
-		head = &uhci->complete_list;
-		tmp = head->next;
-	}
-	spin_unlock_irqrestore(&uhci->complete_list_lock, flags);
-}
-
-static void uhci_remove_pending_qhs(struct uhci *uhci)
-{
-	struct list_head *tmp, *head;
-	unsigned long flags;
-
-	spin_lock_irqsave(&uhci->urb_remove_list_lock, flags);
-	head = &uhci->urb_remove_list;
-	tmp = head->next;
-	while (tmp != head) {
-		struct urb *urb = list_entry(tmp, struct urb, urb_list);
-		struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-
-		tmp = tmp->next;
-
-		list_del_init(&urb->urb_list);
-
-		urbp->status = urb->status = -ECONNRESET;
-
-		uhci_add_complete(urb);
-	}
-	spin_unlock_irqrestore(&uhci->urb_remove_list_lock, flags);
-}
-
-static void uhci_interrupt(int irq, void *__uhci, struct pt_regs *regs)
-{
-	struct uhci *uhci = __uhci;
-	unsigned int io_addr = uhci->io_addr;
-	unsigned short status;
-	struct list_head *tmp, *head;
-
-	/*
-	 * Read the interrupt status, and write it back to clear the
-	 * interrupt cause
-	 */
-	status = inw(io_addr + USBSTS);
-	if (!status)	/* shared interrupt, not mine */
-		return;
-	outw(status, io_addr + USBSTS);		/* Clear it */
-
-	if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD)) {
-		if (status & USBSTS_HSE)
-			err("%x: host system error, PCI problems?", io_addr);
-		if (status & USBSTS_HCPE)
-			err("%x: host controller process error. something bad happened", io_addr);
-		if ((status & USBSTS_HCH) && !uhci->is_suspended) {
-			err("%x: host controller halted. very bad", io_addr);
-			/* FIXME: Reset the controller, fix the offending TD */
-		}
-	}
-
-	if (status & USBSTS_RD)
-		wakeup_hc(uhci);
-
-	uhci_free_pending_qhs(uhci);
-
-	uhci_remove_pending_qhs(uhci);
-
-	uhci_clear_next_interrupt(uhci);
-
-	/* Walk the list of pending URB's to see which ones completed */
-	spin_lock(&uhci->urb_list_lock);
-	head = &uhci->urb_list;
-	tmp = head->next;
-	while (tmp != head) {
-		struct urb *urb = list_entry(tmp, struct urb, urb_list);
-
-		tmp = tmp->next;
-
-		/* Checks the status and does all of the magic necessary */
-		uhci_transfer_result(uhci, urb);
-	}
-	spin_unlock(&uhci->urb_list_lock);
-
-	uhci_finish_completion(uhci);
-}
-
-static void reset_hc(struct uhci *uhci)
-{
-	unsigned int io_addr = uhci->io_addr;
-
-	/* Global reset for 50ms */
-	outw(USBCMD_GRESET, io_addr + USBCMD);
-	wait_ms(50);
-	outw(0, io_addr + USBCMD);
-	wait_ms(10);
-}
-
-static void suspend_hc(struct uhci *uhci)
-{
-	unsigned int io_addr = uhci->io_addr;
-
-	dbg("%x: suspend_hc", io_addr);
-
-	outw(USBCMD_EGSM, io_addr + USBCMD);
-
-	uhci->is_suspended = 1;
-}
-
-static void wakeup_hc(struct uhci *uhci)
-{
-	unsigned int io_addr = uhci->io_addr;
-	unsigned int status;
-
-	dbg("%x: wakeup_hc", io_addr);
-
-	outw(0, io_addr + USBCMD);
-	
-	/* wait for EOP to be sent */
-	status = inw(io_addr + USBCMD);
-	while (status & USBCMD_FGR)
-		status = inw(io_addr + USBCMD);
-
-	uhci->is_suspended = 0;
-
-	/* Run and mark it configured with a 64-byte max packet */
-	outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD);
-}
-
-static int ports_active(struct uhci *uhci)
-{
-	unsigned int io_addr = uhci->io_addr;
-	int connection = 0;
-	int i;
-
-	for (i = 0; i < uhci->rh.numports; i++)
-		connection |= (inw(io_addr + USBPORTSC1 + i * 2) & 0x1);
-
-	return connection;
-}
-
-static void start_hc(struct uhci *uhci)
-{
-	unsigned int io_addr = uhci->io_addr;
-	int timeout = 1000;
-
-	/*
-	 * Reset the HC - this will force us to get a
-	 * new notification of any already connected
-	 * ports due to the virtual disconnect that it
-	 * implies.
-	 */
-	outw(USBCMD_HCRESET, io_addr + USBCMD);
-	while (inw(io_addr + USBCMD) & USBCMD_HCRESET) {
-		if (!--timeout) {
-			printk(KERN_ERR "uhci: USBCMD_HCRESET timed out!\n");
-			break;
-		}
-	}
-
-	/* Turn on all interrupts */
-	outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP,
-		io_addr + USBINTR);
-
-	/* Start at frame 0 */
-	outw(0, io_addr + USBFRNUM);
-	outl(uhci->fl->dma_handle, io_addr + USBFLBASEADD);
-
-	/* Run and mark it configured with a 64-byte max packet */
-	outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD);
-}
-
-#ifdef CONFIG_PROC_FS
-static int uhci_num = 0;
-#endif
-
-static void free_uhci(struct uhci *uhci)
-{
-	kfree(uhci);
-}
-
-/*
- * De-allocate all resources..
- */
-static void release_uhci(struct uhci *uhci)
-{
-	int i;
-#ifdef CONFIG_PROC_FS
-	char buf[8];
-#endif
-
-	if (uhci->irq >= 0) {
-		free_irq(uhci->irq, uhci);
-		uhci->irq = -1;
-	}
-
-	for (i = 0; i < UHCI_NUM_SKELQH; i++)
-		if (uhci->skelqh[i]) {
-			uhci_free_qh(uhci, uhci->skelqh[i]);
-			uhci->skelqh[i] = NULL;
-		}
-
-	for (i = 0; i < UHCI_NUM_SKELTD; i++)
-		if (uhci->skeltd[i]) {
-			uhci_free_td(uhci, uhci->skeltd[i]);
-			uhci->skeltd[i] = NULL;
-		}
-
-	if (uhci->qh_pool) {
-		pci_pool_destroy(uhci->qh_pool);
-		uhci->qh_pool = NULL;
-	}
-
-	if (uhci->td_pool) {
-		pci_pool_destroy(uhci->td_pool);
-		uhci->td_pool = NULL;
-	}
-
-	if (uhci->fl) {
-		pci_free_consistent(uhci->dev, sizeof(*uhci->fl), uhci->fl, uhci->fl->dma_handle);
-		uhci->fl = NULL;
-	}
-
-	if (uhci->bus) {
-		usb_free_bus(uhci->bus);
-		uhci->bus = NULL;
-	}
-
-#ifdef CONFIG_PROC_FS
-	if (uhci->proc_entry) {
-		sprintf(buf, "hc%d", uhci->num);
-
-		remove_proc_entry(buf, uhci_proc_root);
-		uhci->proc_entry = NULL;
-	}
-#endif
-
-	free_uhci(uhci);
-}
-
-/*
- * Allocate a frame list, and then setup the skeleton
- *
- * The hardware doesn't really know any difference
- * in the queues, but the order does matter for the
- * protocols higher up. The order is:
- *
- *  - any isochronous events handled before any
- *    of the queues. We don't do that here, because
- *    we'll create the actual TD entries on demand.
- *  - The first queue is the interrupt queue.
- *  - The second queue is the control queue, split into low and high speed
- *  - The third queue is bulk queue.
- *  - The fourth queue is the bandwidth reclamation queue, which loops back
- *    to the high speed control queue.
- */
-static int alloc_uhci(struct pci_dev *dev, unsigned int io_addr, unsigned int io_size)
-{
-	struct uhci *uhci;
-	int retval;
-	char buf[8], *bufp = buf;
-	int i, port;
-	struct usb_bus *bus;
-	dma_addr_t dma_handle;
-#ifdef CONFIG_PROC_FS
-	struct proc_dir_entry *ent;
-#endif
-
-	retval = -ENODEV;
-	if (pci_enable_device(dev) < 0) {
-		err("couldn't enable PCI device");
-		goto err_enable_device;
-	}
-
-	if (!dev->irq) {
-		err("found UHCI device with no IRQ assigned. check BIOS settings!");
-		goto err_invalid_irq;
-	}
-
-	if (!pci_dma_supported(dev, 0xFFFFFFFF)) {
-		err("PCI subsystem doesn't support 32 bit addressing?");
-		goto err_pci_dma_supported;
-	}
-
-	retval = -EBUSY;
-	if (!request_region(io_addr, io_size, "usb-uhci")) {
-		err("couldn't allocate I/O range %x - %x", io_addr,
-			io_addr + io_size - 1);
-		goto err_request_region;
-	}
-
-	pci_set_master(dev);
-
-#ifndef __sparc__
-	sprintf(buf, "%d", dev->irq);
-#else
-	bufp = __irq_itoa(dev->irq);
-#endif
-	printk(KERN_INFO __FILE__ ": USB UHCI at I/O 0x%x, IRQ %s\n",
-		io_addr, bufp);
-
-	if (pci_set_dma_mask(dev, 0xFFFFFFFF)) {
-		err("couldn't set PCI dma mask");
-		retval = -ENODEV;
-		goto err_pci_set_dma_mask;
-	}
-
-	uhci = kmalloc(sizeof(*uhci), GFP_KERNEL);
-	if (!uhci) {
-		err("couldn't allocate uhci structure");
-		retval = -ENOMEM;
-		goto err_alloc_uhci;
-	}
-
-	uhci->dev = dev;
-	uhci->irq = dev->irq;
-	uhci->io_addr = io_addr;
-	uhci->io_size = io_size;
-	pci_set_drvdata(dev, uhci);
-
-#ifdef CONFIG_PROC_FS
-	uhci->num = uhci_num++;
-
-	sprintf(buf, "hc%d", uhci->num);
-
-	ent = create_proc_entry(buf, S_IFREG|S_IRUGO|S_IWUSR, uhci_proc_root);
-	if (!ent) {
-		err("couldn't create uhci proc entry");
-		retval = -ENOMEM;
-		goto err_create_proc_entry;
-	}
-
-	ent->data = uhci;
-	ent->proc_fops = &uhci_proc_operations;
-	ent->size = 0;
-	uhci->proc_entry = ent;
-#endif
-
-	/* Reset here so we don't get any interrupts from an old setup */
-	/*  or broken setup */
-	reset_hc(uhci);
-
-	uhci->fsbr = 0;
-	uhci->fsbrtimeout = 0;
-
-	uhci->is_suspended = 0;
-
-	spin_lock_init(&uhci->qh_remove_list_lock);
-	INIT_LIST_HEAD(&uhci->qh_remove_list);
-
-	spin_lock_init(&uhci->urb_remove_list_lock);
-	INIT_LIST_HEAD(&uhci->urb_remove_list);
-
-	spin_lock_init(&uhci->urb_list_lock);
-	INIT_LIST_HEAD(&uhci->urb_list);
-
-	spin_lock_init(&uhci->complete_list_lock);
-	INIT_LIST_HEAD(&uhci->complete_list);
-
-	spin_lock_init(&uhci->frame_list_lock);
-
-	/* We need exactly one page (per UHCI specs), how convenient */
-	/* We assume that one page is atleast 4k (1024 frames * 4 bytes) */
-#if PAGE_SIZE < (4 * 1024)
-#error PAGE_SIZE is not atleast 4k
-#endif
-	uhci->fl = pci_alloc_consistent(uhci->dev, sizeof(*uhci->fl), &dma_handle);
-	if (!uhci->fl) {
-		err("unable to allocate consistent memory for frame list");
-		goto err_alloc_fl;
-	}
-
-	memset((void *)uhci->fl, 0, sizeof(*uhci->fl));
-
-	uhci->fl->dma_handle = dma_handle;
-
-	uhci->td_pool = pci_pool_create("uhci_td", uhci->dev,
-		sizeof(struct uhci_td), 16, 0, GFP_DMA | GFP_ATOMIC);
-	if (!uhci->td_pool) {
-		err("unable to create td pci_pool");
-		goto err_create_td_pool;
-	}
-
-	uhci->qh_pool = pci_pool_create("uhci_qh", uhci->dev,
-		sizeof(struct uhci_qh), 16, 0, GFP_DMA | GFP_ATOMIC);
-	if (!uhci->qh_pool) {
-		err("unable to create qh pci_pool");
-		goto err_create_qh_pool;
-	}
-
-	bus = usb_alloc_bus(&uhci_device_operations);
-	if (!bus) {
-		err("unable to allocate bus");
-		goto err_alloc_bus;
-	}
-
-	uhci->bus = bus;
-	bus->bus_name = dev->slot_name;
-	bus->hcpriv = uhci;
-
-	usb_register_bus(uhci->bus);
-
-	/* Initialize the root hub */
-
-	/* UHCI specs says devices must have 2 ports, but goes on to say */
-	/*  they may have more but give no way to determine how many they */
-	/*  have. However, according to the UHCI spec, Bit 7 is always set */
-	/*  to 1. So we try to use this to our advantage */
-	for (port = 0; port < (uhci->io_size - 0x10) / 2; port++) {
-		unsigned int portstatus;
-
-		portstatus = inw(uhci->io_addr + 0x10 + (port * 2));
-		if (!(portstatus & 0x0080))
-			break;
-	}
-	if (debug)
-		info("detected %d ports", port);
-
-	/* This is experimental so anything less than 2 or greater than 8 is */
-	/*  something weird and we'll ignore it */
-	if (port < 2 || port > 8) {
-		info("port count misdetected? forcing to 2 ports");
-		port = 2;
-	}
-
-	uhci->rh.numports = port;
-
-	uhci->bus->root_hub = uhci->rh.dev = usb_alloc_dev(NULL, uhci->bus);
-	if (!uhci->rh.dev) {
-		err("unable to allocate root hub");
-		goto err_alloc_root_hub;
-	}
-
-	uhci->skeltd[0] = uhci_alloc_td(uhci, uhci->rh.dev);
-	if (!uhci->skeltd[0]) {
-		err("unable to allocate TD 0");
-		goto err_alloc_skeltd;
-	}
-
-	/*
-	 * 9 Interrupt queues; link int2 to int1, int4 to int2, etc
-	 * then link int1 to control and control to bulk
-	 */
-	for (i = 1; i < 9; i++) {
-		struct uhci_td *td;
-
-		td = uhci->skeltd[i] = uhci_alloc_td(uhci, uhci->rh.dev);
-		if (!td) {
-			err("unable to allocate TD %d", i);
-			goto err_alloc_skeltd;
-		}
-
-		uhci_fill_td(td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0);
-		td->link = uhci->skeltd[i - 1]->dma_handle;
-	}
-
-	uhci->skel_term_td = uhci_alloc_td(uhci, uhci->rh.dev);
-	if (!uhci->skel_term_td) {
-		err("unable to allocate skel TD term");
-		goto err_alloc_skeltd;
-	}
-
-	for (i = 0; i < UHCI_NUM_SKELQH; i++) {
-		uhci->skelqh[i] = uhci_alloc_qh(uhci, uhci->rh.dev);
-		if (!uhci->skelqh[i]) {
-			err("unable to allocate QH %d", i);
-			goto err_alloc_skelqh;
-		}
-	}
-
-	uhci_fill_td(uhci->skel_int1_td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0);
-	uhci->skel_int1_td->link = uhci->skel_ls_control_qh->dma_handle | UHCI_PTR_QH;
-
-	uhci->skel_ls_control_qh->link = uhci->skel_hs_control_qh->dma_handle | UHCI_PTR_QH;
-	uhci->skel_ls_control_qh->element = UHCI_PTR_TERM;
-
-	uhci->skel_hs_control_qh->link = uhci->skel_bulk_qh->dma_handle | UHCI_PTR_QH;
-	uhci->skel_hs_control_qh->element = UHCI_PTR_TERM;
-
-	uhci->skel_bulk_qh->link = uhci->skel_term_qh->dma_handle | UHCI_PTR_QH;
-	uhci->skel_bulk_qh->element = UHCI_PTR_TERM;
-
-	/* This dummy TD is to work around a bug in Intel PIIX controllers */
-	uhci_fill_td(uhci->skel_term_td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0);
-	uhci->skel_term_td->link = uhci->skel_term_td->dma_handle;
-
-	uhci->skel_term_qh->link = UHCI_PTR_TERM;
-	uhci->skel_term_qh->element = uhci->skel_term_td->dma_handle;
-
-	/*
-	 * Fill the frame list: make all entries point to
-	 * the proper interrupt queue.
-	 *
-	 * This is probably silly, but it's a simple way to
-	 * scatter the interrupt queues in a way that gives
-	 * us a reasonable dynamic range for irq latencies.
-	 */
-	for (i = 0; i < UHCI_NUMFRAMES; i++) {
-		int irq = 0;
-
-		if (i & 1) {
-			irq++;
-			if (i & 2) {
-				irq++;
-				if (i & 4) { 
-					irq++;
-					if (i & 8) { 
-						irq++;
-						if (i & 16) {
-							irq++;
-							if (i & 32) {
-								irq++;
-								if (i & 64)
-									irq++;
-							}
-						}
-					}
-				}
-			}
-		}
-
-		/* Only place we don't use the frame list routines */
-		uhci->fl->frame[i] =  uhci->skeltd[irq]->dma_handle;
-	}
-
-	start_hc(uhci);
-
-	if (request_irq(dev->irq, uhci_interrupt, SA_SHIRQ, "usb-uhci", uhci))
-		goto err_request_irq;
-
-	/* disable legacy emulation */
-	pci_write_config_word(uhci->dev, USBLEGSUP, USBLEGSUP_DEFAULT);
-
-	usb_connect(uhci->rh.dev);
-
-	if (usb_new_device(uhci->rh.dev) != 0) {
-		err("unable to start root hub");
-		retval = -ENOMEM;
-		goto err_start_root_hub;
-	}
-
-	return 0;
-
-/*
- * error exits:
- */
-err_start_root_hub:
-	free_irq(uhci->irq, uhci);
-	uhci->irq = -1;
-
-err_request_irq:
-	for (i = 0; i < UHCI_NUM_SKELQH; i++)
-		if (uhci->skelqh[i]) {
-			uhci_free_qh(uhci, uhci->skelqh[i]);
-			uhci->skelqh[i] = NULL;
-		}
-
-err_alloc_skelqh:
-	for (i = 0; i < UHCI_NUM_SKELTD; i++)
-		if (uhci->skeltd[i]) {
-			uhci_free_td(uhci, uhci->skeltd[i]);
-			uhci->skeltd[i] = NULL;
-		}
-
-err_alloc_skeltd:
-	usb_free_dev(uhci->rh.dev);
-	uhci->rh.dev = NULL;
-
-err_alloc_root_hub:
-	usb_free_bus(uhci->bus);
-	uhci->bus = NULL;
-
-err_alloc_bus:
-	pci_pool_destroy(uhci->qh_pool);
-	uhci->qh_pool = NULL;
-
-err_create_qh_pool:
-	pci_pool_destroy(uhci->td_pool);
-	uhci->td_pool = NULL;
-
-err_create_td_pool:
-	pci_free_consistent(uhci->dev, sizeof(*uhci->fl), uhci->fl, uhci->fl->dma_handle);
-	uhci->fl = NULL;
-
-err_alloc_fl:
-#ifdef CONFIG_PROC_FS
-	remove_proc_entry(buf, uhci_proc_root);
-	uhci->proc_entry = NULL;
-
-err_create_proc_entry:
-	free_uhci(uhci);
-#endif
-
-err_alloc_uhci:
-
-err_pci_set_dma_mask:
-	release_region(io_addr, io_size);
-
-err_request_region:
-
-err_pci_dma_supported:
-
-err_invalid_irq:
-
-err_enable_device:
-
-	return retval;
-}
-
-static int __devinit uhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
-{
-	int i;
-
-	/* Search for the IO base address.. */
-	for (i = 0; i < 6; i++) {
-		unsigned int io_addr = pci_resource_start(dev, i);
-		unsigned int io_size = pci_resource_len(dev, i);
-
-		/* IO address? */
-		if (!(pci_resource_flags(dev, i) & IORESOURCE_IO))
-			continue;
-
-		return alloc_uhci(dev, io_addr, io_size);
-	}
-
-	return -ENODEV;
-}
-
-static void __devexit uhci_pci_remove(struct pci_dev *dev)
-{
-	struct uhci *uhci = pci_get_drvdata(dev);
-
-	if (uhci->bus->root_hub)
-		usb_disconnect(&uhci->bus->root_hub);
-
-	usb_deregister_bus(uhci->bus);
-
-	/*
-	 * At this point, we're guaranteed that no new connects can be made
-	 * to this bus since there are no more parents
-	 */
-	uhci_free_pending_qhs(uhci);
-	uhci_remove_pending_qhs(uhci);
-
-	reset_hc(uhci);
-	release_region(uhci->io_addr, uhci->io_size);
-
-	uhci_free_pending_qhs(uhci);
-
-	release_uhci(uhci);
-}
-
-#ifdef CONFIG_PM
-static int uhci_pci_suspend(struct pci_dev *dev, u32 state)
-{
-	suspend_hc((struct uhci *) pci_get_drvdata(dev));
-	return 0;
-}
-
-static int uhci_pci_resume(struct pci_dev *dev)
-{
-	reset_hc((struct uhci *) pci_get_drvdata(dev));
-	start_hc((struct uhci *) pci_get_drvdata(dev));
-	return 0;
-}
-#endif
-
-static const struct pci_device_id __devinitdata uhci_pci_ids[] = { {
-
-	/* handle any USB UHCI controller */
-	class: 		((PCI_CLASS_SERIAL_USB << 8) | 0x00),
-	class_mask: 	~0,
-
-	/* no matter who makes it */
-	vendor:		PCI_ANY_ID,
-	device:		PCI_ANY_ID,
-	subvendor:	PCI_ANY_ID,
-	subdevice:	PCI_ANY_ID,
-
-	}, { /* end: all zeroes */ }
-};
-
-MODULE_DEVICE_TABLE(pci, uhci_pci_ids);
-
-static struct pci_driver uhci_pci_driver = {
-	name:		"usb-uhci",
-	id_table:	uhci_pci_ids,
-
-	probe:		uhci_pci_probe,
-	remove:		__devexit_p(uhci_pci_remove),
-
-#ifdef	CONFIG_PM
-	suspend:	uhci_pci_suspend,
-	resume:		uhci_pci_resume,
-#endif	/* PM */
-};
-
- 
-static int __init uhci_hcd_init(void)
-{
-	int retval = -ENOMEM;
-
-	info(DRIVER_DESC " " DRIVER_VERSION);
-
-	if (debug) {
-		errbuf = kmalloc(ERRBUF_LEN, GFP_KERNEL);
-		if (!errbuf)
-			goto errbuf_failed;
-	}
-
-#ifdef CONFIG_PROC_FS
-	uhci_proc_root = create_proc_entry("driver/uhci", S_IFDIR, 0);
-	if (!uhci_proc_root)
-		goto proc_failed;
-#endif
-
-	uhci_up_cachep = kmem_cache_create("uhci_urb_priv",
-		sizeof(struct urb_priv), 0, 0, NULL, NULL);
-	if (!uhci_up_cachep)
-		goto up_failed;
-
-	retval = pci_module_init(&uhci_pci_driver);
-	if (retval)
-		goto init_failed;
-
-	return 0;
-
-init_failed:
-	if (kmem_cache_destroy(uhci_up_cachep))
-		printk(KERN_INFO "uhci: not all urb_priv's were freed\n");
-
-up_failed:
-
-#ifdef CONFIG_PROC_FS
-	remove_proc_entry("uhci", 0);
-
-proc_failed:
-#endif
-	if (errbuf)
-		kfree(errbuf);
-
-errbuf_failed:
-
-	return retval;
-}
-
-static void __exit uhci_hcd_cleanup(void) 
-{
-	pci_unregister_driver(&uhci_pci_driver);
-	
-	if (kmem_cache_destroy(uhci_up_cachep))
-		printk(KERN_INFO "uhci: not all urb_priv's were freed\n");
-
-#ifdef CONFIG_PROC_FS
-	remove_proc_entry("uhci", 0);
-#endif
-
-	if (errbuf)
-		kfree(errbuf);
-}
-
-module_init(uhci_hcd_init);
-module_exit(uhci_hcd_cleanup);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/uhci.h linux-2.4.21-pre6/drivers/usb/uhci.h
--- linux-2.4.20/drivers/usb/uhci.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/uhci.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,441 +0,0 @@
-#ifndef __LINUX_UHCI_H
-#define __LINUX_UHCI_H
-
-#include <linux/list.h>
-#include <linux/usb.h>
-
-/*
- * Universal Host Controller Interface data structures and defines
- */
-
-/* Command register */
-#define USBCMD		0
-#define   USBCMD_RS		0x0001	/* Run/Stop */
-#define   USBCMD_HCRESET	0x0002	/* Host reset */
-#define   USBCMD_GRESET		0x0004	/* Global reset */
-#define   USBCMD_EGSM		0x0008	/* Global Suspend Mode */
-#define   USBCMD_FGR		0x0010	/* Force Global Resume */
-#define   USBCMD_SWDBG		0x0020	/* SW Debug mode */
-#define   USBCMD_CF		0x0040	/* Config Flag (sw only) */
-#define   USBCMD_MAXP		0x0080	/* Max Packet (0 = 32, 1 = 64) */
-
-/* Status register */
-#define USBSTS		2
-#define   USBSTS_USBINT		0x0001	/* Interrupt due to IOC */
-#define   USBSTS_ERROR		0x0002	/* Interrupt due to error */
-#define   USBSTS_RD		0x0004	/* Resume Detect */
-#define   USBSTS_HSE		0x0008	/* Host System Error - basically PCI problems */
-#define   USBSTS_HCPE		0x0010	/* Host Controller Process Error - the scripts were buggy */
-#define   USBSTS_HCH		0x0020	/* HC Halted */
-
-/* Interrupt enable register */
-#define USBINTR		4
-#define   USBINTR_TIMEOUT	0x0001	/* Timeout/CRC error enable */
-#define   USBINTR_RESUME	0x0002	/* Resume interrupt enable */
-#define   USBINTR_IOC		0x0004	/* Interrupt On Complete enable */
-#define   USBINTR_SP		0x0008	/* Short packet interrupt enable */
-
-#define USBFRNUM	6
-#define USBFLBASEADD	8
-#define USBSOF		12
-
-/* USB port status and control registers */
-#define USBPORTSC1	16
-#define USBPORTSC2	18
-#define   USBPORTSC_CCS		0x0001	/* Current Connect Status ("device present") */
-#define   USBPORTSC_CSC		0x0002	/* Connect Status Change */
-#define   USBPORTSC_PE		0x0004	/* Port Enable */
-#define   USBPORTSC_PEC		0x0008	/* Port Enable Change */
-#define   USBPORTSC_LS		0x0030	/* Line Status */
-#define   USBPORTSC_RD		0x0040	/* Resume Detect */
-#define   USBPORTSC_LSDA	0x0100	/* Low Speed Device Attached */
-#define   USBPORTSC_PR		0x0200	/* Port Reset */
-#define   USBPORTSC_SUSP	0x1000	/* Suspend */
-
-/* Legacy support register */
-#define USBLEGSUP		0xc0
-#define   USBLEGSUP_DEFAULT	0x2000	/* only PIRQ enable set */
-
-#define UHCI_NULL_DATA_SIZE	0x7FF	/* for UHCI controller TD */
-
-#define UHCI_PTR_BITS		0x000F
-#define UHCI_PTR_TERM		0x0001
-#define UHCI_PTR_QH		0x0002
-#define UHCI_PTR_DEPTH		0x0004
-
-#define UHCI_NUMFRAMES		1024	/* in the frame list [array] */
-#define UHCI_MAX_SOF_NUMBER	2047	/* in an SOF packet */
-#define CAN_SCHEDULE_FRAMES	1000	/* how far future frames can be scheduled */
-
-struct uhci_frame_list {
-	__u32 frame[UHCI_NUMFRAMES];
-
-	void *frame_cpu[UHCI_NUMFRAMES];
-
-	dma_addr_t dma_handle;
-};
-
-struct urb_priv;
-
-struct uhci_qh {
-	/* Hardware fields */
-	__u32 link;			/* Next queue */
-	__u32 element;			/* Queue element pointer */
-
-	/* Software fields */
-	dma_addr_t dma_handle;
-
-	struct usb_device *dev;
-	struct urb_priv *urbp;
-
-	struct list_head list;		/* P: uhci->frame_list_lock */
-	struct list_head remove_list;	/* P: uhci->remove_list_lock */
-} __attribute__((aligned(16)));
-
-/*
- * for TD <status>:
- */
-#define TD_CTRL_SPD		(1 << 29)	/* Short Packet Detect */
-#define TD_CTRL_C_ERR_MASK	(3 << 27)	/* Error Counter bits */
-#define TD_CTRL_C_ERR_SHIFT	27
-#define TD_CTRL_LS		(1 << 26)	/* Low Speed Device */
-#define TD_CTRL_IOS		(1 << 25)	/* Isochronous Select */
-#define TD_CTRL_IOC		(1 << 24)	/* Interrupt on Complete */
-#define TD_CTRL_ACTIVE		(1 << 23)	/* TD Active */
-#define TD_CTRL_STALLED		(1 << 22)	/* TD Stalled */
-#define TD_CTRL_DBUFERR		(1 << 21)	/* Data Buffer Error */
-#define TD_CTRL_BABBLE		(1 << 20)	/* Babble Detected */
-#define TD_CTRL_NAK		(1 << 19)	/* NAK Received */
-#define TD_CTRL_CRCTIMEO	(1 << 18)	/* CRC/Time Out Error */
-#define TD_CTRL_BITSTUFF	(1 << 17)	/* Bit Stuff Error */
-#define TD_CTRL_ACTLEN_MASK	0x7FF		/* actual length, encoded as n - 1 */
-
-#define TD_CTRL_ANY_ERROR	(TD_CTRL_STALLED | TD_CTRL_DBUFERR | \
-				 TD_CTRL_BABBLE | TD_CTRL_CRCTIME | TD_CTRL_BITSTUFF)
-
-#define uhci_status_bits(ctrl_sts)	(ctrl_sts & 0xFE0000)
-#define uhci_actual_length(ctrl_sts)	((ctrl_sts + 1) & TD_CTRL_ACTLEN_MASK) /* 1-based */
-
-/*
- * for TD <info>: (a.k.a. Token)
- */
-#define TD_TOKEN_TOGGLE_SHIFT	19
-#define TD_TOKEN_TOGGLE		(1 << 19)
-#define TD_TOKEN_PID_MASK	0xFF
-#define TD_TOKEN_EXPLEN_MASK	0x7FF		/* expected length, encoded as n - 1 */
-
-#define uhci_maxlen(token)	((token) >> 21)
-#define uhci_expected_length(info) (((info >> 21) + 1) & TD_TOKEN_EXPLEN_MASK) /* 1-based */
-#define uhci_toggle(token)	(((token) >> TD_TOKEN_TOGGLE_SHIFT) & 1)
-#define uhci_endpoint(token)	(((token) >> 15) & 0xf)
-#define uhci_devaddr(token)	(((token) >> 8) & 0x7f)
-#define uhci_devep(token)	(((token) >> 8) & 0x7ff)
-#define uhci_packetid(token)	((token) & TD_TOKEN_PID_MASK)
-#define uhci_packetout(token)	(uhci_packetid(token) != USB_PID_IN)
-#define uhci_packetin(token)	(uhci_packetid(token) == USB_PID_IN)
-
-/*
- * The documentation says "4 words for hardware, 4 words for software".
- *
- * That's silly, the hardware doesn't care. The hardware only cares that
- * the hardware words are 16-byte aligned, and we can have any amount of
- * sw space after the TD entry as far as I can tell.
- *
- * But let's just go with the documentation, at least for 32-bit machines.
- * On 64-bit machines we probably want to take advantage of the fact that
- * hw doesn't really care about the size of the sw-only area.
- *
- * Alas, not anymore, we have more than 4 words for software, woops.
- * Everything still works tho, surprise! -jerdfelt
- */
-struct uhci_td {
-	/* Hardware fields */
-	__u32 link;
-	__u32 status;
-	__u32 info;
-	__u32 buffer;
-
-	/* Software fields */
-	dma_addr_t dma_handle;
-
-	struct usb_device *dev;
-	struct urb *urb;
-
-	struct list_head list;		/* P: urb->lock */
-
-	int frame;
-	struct list_head fl_list;	/* P: uhci->frame_list_lock */
-} __attribute__((aligned(16)));
-
-/*
- * There are various standard queues. We set up several different
- * queues for each of the three basic queue types: interrupt,
- * control, and bulk.
- *
- *  - There are various different interrupt latencies: ranging from
- *    every other USB frame (2 ms apart) to every 256 USB frames (ie
- *    256 ms apart). Make your choice according to how obnoxious you
- *    want to be on the wire, vs how critical latency is for you.
- *  - The control list is done every frame.
- *  - There are 4 bulk lists, so that up to four devices can have a
- *    bulk list of their own and when run concurrently all four lists
- *    will be be serviced.
- *
- * This is a bit misleading, there are various interrupt latencies, but they
- * vary a bit, interrupt2 isn't exactly 2ms, it can vary up to 4ms since the
- * other queues can "override" it. interrupt4 can vary up to 8ms, etc. Minor
- * problem
- *
- * In the case of the root hub, these QH's are just head's of qh's. Don't
- * be scared, it kinda makes sense. Look at this wonderful picture care of
- * Linus:
- *
- *  generic-  ->  dev1-  ->  generic-  ->  dev1-  ->  control-  ->  bulk- -> ...
- *   iso-QH      iso-QH       irq-QH      irq-QH        QH           QH
- *      |           |            |           |           |            |
- *     End     dev1-iso-TD1     End     dev1-irq-TD1    ...          ... 
- *                  |
- *             dev1-iso-TD2
- *                  |
- *                ....
- *
- * This may vary a bit (the UHCI docs don't explicitly say you can put iso
- * transfers in QH's and all of their pictures don't have that either) but
- * other than that, that is what we're doing now
- *
- * And now we don't put Iso transfers in QH's, so we don't waste one on it
- * --jerdfelt
- *
- * To keep with Linus' nomenclature, this is called the QH skeleton. These
- * labels (below) are only signficant to the root hub's QH's
- */
-
-#define UHCI_NUM_SKELTD		10
-#define skel_int1_td		skeltd[0]
-#define skel_int2_td		skeltd[1]
-#define skel_int4_td		skeltd[2]
-#define skel_int8_td		skeltd[3]
-#define skel_int16_td		skeltd[4]
-#define skel_int32_td		skeltd[5]
-#define skel_int64_td		skeltd[6]
-#define skel_int128_td		skeltd[7]
-#define skel_int256_td		skeltd[8]
-#define skel_term_td		skeltd[9]	/* To work around PIIX UHCI bug */
-
-#define UHCI_NUM_SKELQH		4
-#define skel_ls_control_qh	skelqh[0]
-#define skel_hs_control_qh	skelqh[1]
-#define skel_bulk_qh		skelqh[2]
-#define skel_term_qh		skelqh[3]
-
-/*
- * Search tree for determining where <interval> fits in the
- * skelqh[] skeleton.
- *
- * An interrupt request should be placed into the slowest skelqh[]
- * which meets the interval/period/frequency requirement.
- * An interrupt request is allowed to be faster than <interval> but not slower.
- *
- * For a given <interval>, this function returns the appropriate/matching
- * skelqh[] index value.
- *
- * NOTE: For UHCI, we don't really need int256_qh since the maximum interval
- * is 255 ms.  However, we do need an int1_qh since 1 is a valid interval
- * and we should meet that frequency when requested to do so.
- * This will require some change(s) to the UHCI skeleton.
- */
-static inline int __interval_to_skel(int interval)
-{
-	if (interval < 16) {
-		if (interval < 4) {
-			if (interval < 2)
-				return 0;	/* int1 for 0-1 ms */
-			return 1;		/* int2 for 2-3 ms */
-		}
-		if (interval < 8)
-			return 2;		/* int4 for 4-7 ms */
-		return 3;			/* int8 for 8-15 ms */
-	}
-	if (interval < 64) {
-		if (interval < 32)
-			return 4;		/* int16 for 16-31 ms */
-		return 5;			/* int32 for 32-63 ms */
-	}
-	if (interval < 128)
-		return 6;			/* int64 for 64-127 ms */
-	return 7;				/* int128 for 128-255 ms (Max.) */
-}
-
-struct virt_root_hub {
-	struct usb_device *dev;
-	int devnum;		/* Address of Root Hub endpoint */
-	struct urb *urb;
-	void *int_addr;
-	int send;
-	int interval;
-	int numports;
-	int c_p_r[8];
-	struct timer_list rh_int_timer;
-};
-
-/*
- * This describes the full uhci information.
- *
- * Note how the "proper" USB information is just
- * a subset of what the full implementation needs.
- */
-struct uhci {
-	struct pci_dev *dev;
-
-#ifdef CONFIG_PROC_FS
-	/* procfs */
-	int num;
-	struct proc_dir_entry *proc_entry;
-#endif
-
-	/* Grabbed from PCI */
-	int irq;
-	unsigned int io_addr;
-	unsigned int io_size;
-
-	struct pci_pool *qh_pool;
-	struct pci_pool *td_pool;
-
-	struct usb_bus *bus;
-
-	struct uhci_td *skeltd[UHCI_NUM_SKELTD];	/* Skeleton TD's */
-	struct uhci_qh *skelqh[UHCI_NUM_SKELQH];	/* Skeleton QH's */
-
-	spinlock_t frame_list_lock;
-	struct uhci_frame_list *fl;		/* P: uhci->frame_list_lock */
-	int fsbr;				/* Full speed bandwidth reclamation */
-	unsigned long fsbrtimeout;		/* FSBR delay */
-	int is_suspended;
-
-	/* Main list of URB's currently controlled by this HC */
-	spinlock_t urb_list_lock;
-	struct list_head urb_list;		/* P: uhci->urb_list_lock */
-
-	/* List of QH's that are done, but waiting to be unlinked (race) */
-	spinlock_t qh_remove_list_lock;
-	struct list_head qh_remove_list;	/* P: uhci->qh_remove_list_lock */
-
-	/* List of asynchronously unlinked URB's */
-	spinlock_t urb_remove_list_lock;
-	struct list_head urb_remove_list;	/* P: uhci->urb_remove_list_lock */
-
-	/* List of URB's awaiting completion callback */
-	spinlock_t complete_list_lock;
-	struct list_head complete_list;		/* P: uhci->complete_list_lock */
-
-	struct virt_root_hub rh;	/* private data of the virtual root hub */
-};
-
-struct urb_priv {
-	struct urb *urb;
-	struct usb_device *dev;
-
-	dma_addr_t setup_packet_dma_handle;
-	dma_addr_t transfer_buffer_dma_handle;
-
-	struct uhci_qh *qh;		/* QH for this URB */
-	struct list_head td_list;	/* P: urb->lock */
-
-	int fsbr : 1;			/* URB turned on FSBR */
-	int fsbr_timeout : 1;		/* URB timed out on FSBR */
-	int queued : 1;			/* QH was queued (not linked in) */
-	int short_control_packet : 1;	/* If we get a short packet during */
-					/*  a control transfer, retrigger */
-					/*  the status phase */
-
-	int status;			/* Final status */
-
-	unsigned long inserttime;	/* In jiffies */
-	unsigned long fsbrtime;		/* In jiffies */
-
-	struct list_head queue_list;	/* P: uhci->frame_list_lock */
-	struct list_head complete_list;	/* P: uhci->complete_list_lock */
-};
-
-/*
- * Locking in uhci.c
- *
- * spinlocks are used extensively to protect the many lists and data
- * structures we have. It's not that pretty, but it's necessary. We
- * need to be done with all of the locks (except complete_list_lock) when
- * we call urb->complete. I've tried to make it simple enough so I don't
- * have to spend hours racking my brain trying to figure out if the
- * locking is safe.
- *
- * Here's the safe locking order to prevent deadlocks:
- *
- * #1 uhci->urb_list_lock
- * #2 urb->lock
- * #3 uhci->urb_remove_list_lock, uhci->frame_list_lock, 
- *   uhci->qh_remove_list_lock
- * #4 uhci->complete_list_lock
- *
- * If you're going to grab 2 or more locks at once, ALWAYS grab the lock
- * at the lowest level FIRST and NEVER grab locks at the same level at the
- * same time.
- * 
- * So, if you need uhci->urb_list_lock, grab it before you grab urb->lock
- */
-
-/* -------------------------------------------------------------------------
-   Virtual Root HUB
-   ------------------------------------------------------------------------- */
-/* destination of request */
-#define RH_DEVICE		0x00
-#define RH_INTERFACE		0x01
-#define RH_ENDPOINT		0x02
-#define RH_OTHER		0x03
-
-#define RH_CLASS		0x20
-#define RH_VENDOR		0x40
-
-/* Requests: bRequest << 8 | bmRequestType */
-#define RH_GET_STATUS		0x0080
-#define RH_CLEAR_FEATURE	0x0100
-#define RH_SET_FEATURE		0x0300
-#define RH_SET_ADDRESS		0x0500
-#define RH_GET_DESCRIPTOR	0x0680
-#define RH_SET_DESCRIPTOR	0x0700
-#define RH_GET_CONFIGURATION	0x0880
-#define RH_SET_CONFIGURATION	0x0900
-#define RH_GET_STATE		0x0280
-#define RH_GET_INTERFACE	0x0A80
-#define RH_SET_INTERFACE	0x0B00
-#define RH_SYNC_FRAME		0x0C80
-/* Our Vendor Specific Request */
-#define RH_SET_EP		0x2000
-
-/* Hub port features */
-#define RH_PORT_CONNECTION	0x00
-#define RH_PORT_ENABLE		0x01
-#define RH_PORT_SUSPEND		0x02
-#define RH_PORT_OVER_CURRENT	0x03
-#define RH_PORT_RESET		0x04
-#define RH_PORT_POWER		0x08
-#define RH_PORT_LOW_SPEED	0x09
-#define RH_C_PORT_CONNECTION	0x10
-#define RH_C_PORT_ENABLE	0x11
-#define RH_C_PORT_SUSPEND	0x12
-#define RH_C_PORT_OVER_CURRENT	0x13
-#define RH_C_PORT_RESET		0x14
-
-/* Hub features */
-#define RH_C_HUB_LOCAL_POWER	0x00
-#define RH_C_HUB_OVER_CURRENT	0x01
-#define RH_DEVICE_REMOTE_WAKEUP	0x00
-#define RH_ENDPOINT_STALL	0x01
-
-/* Our Vendor Specific feature */
-#define RH_REMOVE_EP		0x00
-
-#define RH_ACK			0x01
-#define RH_REQ_ERR		-1
-#define RH_NACK			0x00
-
-#endif
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/ultracam.c linux-2.4.21-pre6/drivers/usb/ultracam.c
--- linux-2.4.20/drivers/usb/ultracam.c	2001-10-17 21:34:06.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/ultracam.c	2003-03-26 23:49:09.000000000 +0000
@@ -16,7 +16,7 @@
 #define MAX_CAMERAS		4	/* How many devices we allow to connect */
 
 /*
- * This structure lives in uvd_t->user field.
+ * This structure lives in uvd->user field.
  */
 typedef struct {
 	int initialized;	/* Had we already sent init sequence? */
@@ -25,7 +25,7 @@
 } ultracam_t;
 #define	ULTRACAM_T(uvd)	((ultracam_t *)((uvd)->user_data))
 
-static usbvideo_t *cams = NULL;
+static struct usbvideo *cams = NULL;
 
 static int debug = 0;
 
@@ -103,7 +103,7 @@
  * 02-Nov-2000 First (mostly dummy) version.
  * 06-Nov-2000 Rewrote to dump all data into frame.
  */
-void ultracam_ProcessIsocData(uvd_t *uvd, usbvideo_frame_t *frame)
+void ultracam_ProcessIsocData(struct uvd *uvd, struct usbvideo_frame *frame)
 {
 	int n;
 
@@ -140,7 +140,7 @@
  * 1/27/00  Added check for dev == NULL; this happens if camera is unplugged.
  */
 static int ultracam_veio(
-	uvd_t *uvd,
+	struct uvd *uvd,
 	unsigned char req,
 	unsigned short value,
 	unsigned short index,
@@ -193,7 +193,7 @@
 /*
  * ultracam_calculate_fps()
  */
-static int ultracam_calculate_fps(uvd_t *uvd)
+static int ultracam_calculate_fps(struct uvd *uvd)
 {
 	return 3 + framerate*4 + framerate/2;
 }
@@ -201,14 +201,14 @@
 /*
  * ultracam_adjust_contrast()
  */
-static void ultracam_adjust_contrast(uvd_t *uvd)
+static void ultracam_adjust_contrast(struct uvd *uvd)
 {
 }
 
 /*
  * ultracam_change_lighting_conditions()
  */
-static void ultracam_change_lighting_conditions(uvd_t *uvd)
+static void ultracam_change_lighting_conditions(struct uvd *uvd)
 {
 }
 
@@ -219,7 +219,7 @@
  * range [0..6], where 0 is most smooth and 6 is most sharp (raw image, I guess).
  * Recommended value is 4. Cameras model 2 do not have this feature at all.
  */
-static void ultracam_set_sharpness(uvd_t *uvd)
+static void ultracam_set_sharpness(struct uvd *uvd)
 {
 }
 
@@ -228,11 +228,11 @@
  *
  * This procedure changes brightness of the picture.
  */
-static void ultracam_set_brightness(uvd_t *uvd)
+static void ultracam_set_brightness(struct uvd *uvd)
 {
 }
 
-static void ultracam_set_hue(uvd_t *uvd)
+static void ultracam_set_hue(struct uvd *uvd)
 {
 }
 
@@ -242,7 +242,7 @@
  * This procedure gets called from V4L interface to update picture settings.
  * Here we change brightness and contrast.
  */
-static void ultracam_adjust_picture(uvd_t *uvd)
+static void ultracam_adjust_picture(struct uvd *uvd)
 {
 	ultracam_adjust_contrast(uvd);
 	ultracam_set_brightness(uvd);
@@ -255,7 +255,7 @@
  * This code tells camera to stop streaming. The interface remains
  * configured and bandwidth - claimed.
  */
-static void ultracam_video_stop(uvd_t *uvd)
+static void ultracam_video_stop(struct uvd *uvd)
 {
 }
 
@@ -266,24 +266,24 @@
  * resets the video pipe. This sequence was observed to reinit the
  * camera or, at least, to initiate ISO data stream.
  */
-static void ultracam_reinit_iso(uvd_t *uvd, int do_stop)
+static void ultracam_reinit_iso(struct uvd *uvd, int do_stop)
 {
 }
 
-static void ultracam_video_start(uvd_t *uvd)
+static void ultracam_video_start(struct uvd *uvd)
 {
 	ultracam_change_lighting_conditions(uvd);
 	ultracam_set_sharpness(uvd);
 	ultracam_reinit_iso(uvd, 0);
 }
 
-static int ultracam_resetPipe(uvd_t *uvd)
+static int ultracam_resetPipe(struct uvd *uvd)
 {
 	usb_clear_halt(uvd->dev, uvd->video_endp);
 	return 0;
 }
 
-static int ultracam_alternateSetting(uvd_t *uvd, int setting)
+static int ultracam_alternateSetting(struct uvd *uvd, int setting)
 {
 	static const char proc[] = "ultracam_alternateSetting";
 	int i;
@@ -299,7 +299,7 @@
 /*
  * Return negative code on failure, 0 on success.
  */
-static int ultracam_setup_on_open(uvd_t *uvd)
+static int ultracam_setup_on_open(struct uvd *uvd)
 {
 	int setup_ok = 0; /* Success by default */
 	/* Send init sequence only once, it's large! */
@@ -487,7 +487,7 @@
 	return setup_ok;
 }
 
-static void ultracam_configure_video(uvd_t *uvd)
+static void ultracam_configure_video(struct uvd *uvd)
 {
 	if (uvd == NULL)
 		return;
@@ -539,7 +539,7 @@
  */
 static void *ultracam_probe(struct usb_device *dev, unsigned int ifnum ,const struct usb_device_id *devid)
 {
-	uvd_t *uvd = NULL;
+	struct uvd *uvd = NULL;
 	int i, nas;
 	int actInterface=-1, inactInterface=-1, maxPS=0;
 	unsigned char video_ep = 0;
@@ -628,7 +628,7 @@
 	MOD_INC_USE_COUNT;
 	uvd = usbvideo_AllocateDevice(cams);
 	if (uvd != NULL) {
-		/* Here uvd is a fully allocated uvd_t object */
+		/* Here uvd is a fully allocated uvd object */
 		uvd->flags = flags;
 		uvd->debug = debug;
 		uvd->dev = dev;
@@ -659,6 +659,12 @@
 	return uvd;
 }
 
+
+static struct usb_device_id id_table[] = {
+	{ USB_DEVICE(ULTRACAM_VENDOR_ID, ULTRACAM_PRODUCT_ID) },
+	{ }  /* Terminating entry */
+};
+
 /*
  * ultracam_init()
  *
@@ -666,7 +672,7 @@
  */
 static int __init ultracam_init(void)
 {
-	usbvideo_cb_t cbTbl;
+	struct usbvideo_cb cbTbl;
 	memset(&cbTbl, 0, sizeof(cbTbl));
 	cbTbl.probe = ultracam_probe;
 	cbTbl.setupOnOpen = ultracam_setup_on_open;
@@ -682,7 +688,8 @@
 		sizeof(ultracam_t),
 		"ultracam",
 		&cbTbl,
-		THIS_MODULE);
+		THIS_MODULE,
+		id_table);
 }
 
 static void __exit ultracam_cleanup(void)
@@ -690,16 +697,7 @@
 	usbvideo_Deregister(&cams);
 }
 
-#if defined(usb_device_id_ver)
-
-static __devinitdata struct usb_device_id id_table[] = {
-	{ USB_DEVICE(ULTRACAM_VENDOR_ID, ULTRACAM_PRODUCT_ID) },
-	{ }  /* Terminating entry */
-};
 MODULE_DEVICE_TABLE(usb, id_table);
-
-
-#endif /* defined(usb_device_id_ver) */
 MODULE_LICENSE("GPL");
 
 module_init(ultracam_init);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/usb-midi.c linux-2.4.21-pre6/drivers/usb/usb-midi.c
--- linux-2.4.20/drivers/usb/usb-midi.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/usb-midi.c	2003-03-26 23:49:00.000000000 +0000
@@ -370,7 +370,7 @@
 {
 	struct midi_in_endpoint *ep = (struct midi_in_endpoint *)(urb->context);
 	unsigned char *data = urb->transfer_buffer;
-	int i, l, wake;
+	int i, j, wake;
 	unsigned long int flags;
 
 	if ( !ep->urbSubmitted ) {
@@ -381,14 +381,14 @@
 		wake = 0;
 		spin_lock_irqsave( &ep->lock, flags );
 
-		for(l = 0; l < urb->actual_length; l += 4) {
-			int cin = (data[l]>>0)&0xf;
-			int cab = (data[l]>>4)&0xf;
+		for(j = 0; j < urb->actual_length; j += 4) {
+			int cin = (data[j]>>0)&0xf;
+			int cab = (data[j]>>4)&0xf;
 			struct usb_mididev *cable = ep->cables[cab];
 			if ( cable ) {
 				int len = cin_to_len[cin]; /** length of MIDI data **/
 				for (i = 0; i < len; i++) {
-					cable->min.buf[cable->min.bufWrPtr] = data[1+i];
+					cable->min.buf[cable->min.bufWrPtr] = data[1+i+j];
 					cable->min.bufWrPtr = (cable->min.bufWrPtr+1)%MIDI_IN_BUFSIZ;
 					if (cable->min.bufRemains < MIDI_IN_BUFSIZ)
 						cable->min.bufRemains += 1;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/usb-midi.h linux-2.4.21-pre6/drivers/usb/usb-midi.h
--- linux-2.4.20/drivers/usb/usb-midi.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/usb-midi.h	2003-03-26 23:49:35.000000000 +0000
@@ -37,22 +37,35 @@
 /* ------------------------------------------------------------------------- */
 /* Roland MIDI Devices */
 
+#ifndef USB_VENDOR_ID_ROLAND
 #define USB_VENDOR_ID_ROLAND		0x0582
+#endif
 #define USBMIDI_ROLAND_UA100G		0x0000
 #define USBMIDI_ROLAND_MPU64		0x0002
 #define USBMIDI_ROLAND_SC8850		0x0003
 #define USBMIDI_ROLAND_UM2		0x0005
-#define USBMIDI_ROLAND_UM1		0x0009
+#define USBMIDI_ROLAND_SC8820		0x0007
 #define USBMIDI_ROLAND_PC300		0x0008
+#define USBMIDI_ROLAND_UM1		0x0009
 
 /* YAMAHA MIDI Devices */
+#ifndef USB_VENDOR_ID_YAMAHA
 #define USB_VENDOR_ID_YAMAHA		0x0499
+#endif
 #define USBMIDI_YAMAHA_MU1000		0x1001
 
 /* Steinberg MIDI Devices */
+#ifndef USB_VENDOR_ID_STEINBERG
 #define USB_VENDOR_ID_STEINBERG		0x0763
+#endif
 #define USBMIDI_STEINBERG_USB2MIDI	0x1001
 
+/* Mark of the Unicorn devices */
+#ifndef USB_VENDOR_ID_MOTU
+#define USB_VENDOR_ID_MOTU		0x07fd
+#endif
+#define USBMIDI_MOTU_FASTLANE		0x0001
+
 /* ------------------------------------------------------------------------- */
 /* Supported devices */
 
@@ -100,8 +113,15 @@
   { /* Roland SC8850 */
     "Roland SC8850",
     USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8850, 2, -1,
-    { { 0x81, 15 }, {-1, -1} }, /** cables 0,1,2, and 3 **/
-    { { 0x01, 15 }, {-1, -1} },
+    { { 0x81, 0x3f }, {-1, -1} },
+    { { 0x01, 0x3f }, {-1, -1} },
+  },
+
+  { /* Roland SC8820 */
+    "Roland SC8820",
+    USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8820, 2, -1,
+    { { 0x81, 0x13 }, {-1, -1} },
+    { { 0x01, 0x13 }, {-1, -1} },
   },
 
   { /* YAMAHA MU1000 */
@@ -115,6 +135,12 @@
     USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_PC300, 2, -1, 
     { { 0x81, 1 }, {-1, -1} },
     { { 0x01, 1 }, {-1, -1} },
+  },
+  { /* MOTU Fastlane USB */
+    "MOTU Fastlane USB",
+    USB_VENDOR_ID_MOTU, USBMIDI_MOTU_FASTLANE, 1, 0,
+    { { 0x82, 3 }, {-1, -1} },
+    { { 0x02, 3 }, {-1, -1} },
   }
 };
 
@@ -130,7 +156,9 @@
 	{ USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UA100G ) },
 	{ USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_PC300 ) },
 	{ USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8850 ) },
+	{ USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8820 ) },
 	{ USB_DEVICE( USB_VENDOR_ID_YAMAHA, USBMIDI_YAMAHA_MU1000 ) },
+	{ USB_DEVICE( USB_VENDOR_ID_MOTU,   USBMIDI_MOTU_FASTLANE ) },
 /*	{ USB_DEVICE( USB_VENDOR_ID_STEINBERG, USBMIDI_STEINBERG_USB2MIDI ) },*/
 	{ } /* Terminating entry */
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/usb-ohci.c linux-2.4.21-pre6/drivers/usb/usb-ohci.c
--- linux-2.4.20/drivers/usb/usb-ohci.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/usb-ohci.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,2936 +0,0 @@
-/*
- * URB OHCI HCD (Host Controller Driver) for USB.
- *
- * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
- * 
- * [ Initialisation is based on Linus'  ]
- * [ uhci code and gregs ohci fragments ]
- * [ (C) Copyright 1999 Linus Torvalds  ]
- * [ (C) Copyright 1999 Gregory P. Smith]
- * 
- * 
- * History:
- *
- * 2002/03/08 interrupt unlink fix (Matt Hughes), better cleanup on
- *	load failure (Matthew Frederickson)
- * 2002/01/20 async unlink fixes:  return -EINPROGRESS (per spec) and
- *	make interrupt unlink-in-completion work (db)
- * 2001/09/19 USB_ZERO_PACKET support (Jean Tourrilhes)
- * 2001/07/17 power management and pmac cleanup (Benjamin Herrenschmidt)
- * 2001/03/24 td/ed hashing to remove bus_to_virt (Steve Longerbeam);
- 	pci_map_single (db)
- * 2001/03/21 td and dev/ed allocation uses new pci_pool API (db)
- * 2001/03/07 hcca allocation uses pci_alloc_consistent (Steve Longerbeam)
- *
- * 2000/09/26 fixed races in removing the private portion of the urb
- * 2000/09/07 disable bulk and control lists when unlinking the last
- *	endpoint descriptor in order to avoid unrecoverable errors on
- *	the Lucent chips. (rwc@sgi)
- * 2000/08/29 use bandwidth claiming hooks (thanks Randy!), fix some
- *	urb unlink probs, indentation fixes
- * 2000/08/11 various oops fixes mostly affecting iso and cleanup from
- *	device unplugs.
- * 2000/06/28 use PCI hotplug framework, for better power management
- *	and for Cardbus support (David Brownell)
- * 2000/earlier:  fixes for NEC/Lucent chips; suspend/resume handling
- *	when the controller loses power; handle UE; cleanup; ...
- *
- * v5.2 1999/12/07 URB 3rd preview, 
- * v5.1 1999/11/30 URB 2nd preview, cpia, (usb-scsi)
- * v5.0 1999/11/22 URB Technical preview, Paul Mackerras powerbook susp/resume 
- * 	i386: HUB, Keyboard, Mouse, Printer 
- *
- * v4.3 1999/10/27 multiple HCs, bulk_request
- * v4.2 1999/09/05 ISO API alpha, new dev alloc, neg Error-codes
- * v4.1 1999/08/27 Randy Dunlap's - ISO API first impl.
- * v4.0 1999/08/18 
- * v3.0 1999/06/25 
- * v2.1 1999/05/09  code clean up
- * v2.0 1999/05/04 
- * v1.0 1999/04/27 initial release
- */
- 
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/smp_lock.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>  /* for in_interrupt() */
-#undef DEBUG
-#include <linux/usb.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/unaligned.h>
-
-#define OHCI_USE_NPS		// force NoPowerSwitching mode
-// #define OHCI_VERBOSE_DEBUG	/* not always helpful */
-
-#include "usb-ohci.h"
-
-#include "hcd.h"
-
-#ifdef CONFIG_PMAC_PBOOK
-#include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-#include <asm/pci-bridge.h>
-#ifndef CONFIG_PM
-#define CONFIG_PM
-#endif
-#endif
-
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v5.3"
-#define DRIVER_AUTHOR "Roman Weissgaerber <weissg@vienna.at>, David Brownell"
-#define DRIVER_DESC "USB OHCI Host Controller Driver"
-
-/* For initializing controller (mask in an HCFS mode too) */
-#define	OHCI_CONTROL_INIT \
-	(OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE
-
-#define OHCI_UNLINK_TIMEOUT	(HZ / 10)
-
-static LIST_HEAD (ohci_hcd_list);
-static spinlock_t usb_ed_lock = SPIN_LOCK_UNLOCKED;
-
-
-/*-------------------------------------------------------------------------*/
-
-/* AMD-756 (D2 rev) reports corrupt register contents in some cases.
- * The erratum (#4) description is incorrect.  AMD's workaround waits
- * till some bits (mostly reserved) are clear; ok for all revs.
- */
-#define read_roothub(hc, register, mask) ({ \
-	u32 temp = readl (&hc->regs->roothub.register); \
-	if (hc->flags & OHCI_QUIRK_AMD756) \
-		while (temp & mask) \
-			temp = readl (&hc->regs->roothub.register); \
-	temp; })
-
-static u32 roothub_a (struct ohci *hc)
-	{ return read_roothub (hc, a, 0xfc0fe000); }
-static inline u32 roothub_b (struct ohci *hc)
-	{ return readl (&hc->regs->roothub.b); }
-static inline u32 roothub_status (struct ohci *hc)
-	{ return readl (&hc->regs->roothub.status); }
-static u32 roothub_portstatus (struct ohci *hc, int i)
-	{ return read_roothub (hc, portstatus [i], 0xffe0fce0); }
-
-
-/*-------------------------------------------------------------------------*
- * URB support functions 
- *-------------------------------------------------------------------------*/ 
- 
-/* free HCD-private data associated with this URB */
-
-static void urb_free_priv (struct ohci *hc, urb_priv_t * urb_priv)
-{
-	int		i;
-	int		last = urb_priv->length - 1;
-	int		len;
-	int		dir;
-	struct td	*td;
-
-	if (last >= 0) {
-
-		/* ISOC, BULK, INTR data buffer starts at td 0 
-		 * CTRL setup starts at td 0 */
-		td = urb_priv->td [0];
-
-		len = td->urb->transfer_buffer_length,
-		dir = usb_pipeout (td->urb->pipe)
-					? PCI_DMA_TODEVICE
-					: PCI_DMA_FROMDEVICE;
-
-		/* unmap CTRL URB setup */
-		if (usb_pipecontrol (td->urb->pipe)) {
-			pci_unmap_single (hc->ohci_dev, 
-					td->data_dma, 8, PCI_DMA_TODEVICE);
-			
-			/* CTRL data buffer starts at td 1 if len > 0 */
-			if (len && last > 0)
-				td = urb_priv->td [1]; 		
-		} 
-
-		/* unmap data buffer */
-		if (len && td->data_dma)
-			pci_unmap_single (hc->ohci_dev, td->data_dma, len, dir);
-		
-		for (i = 0; i <= last; i++) {
-			td = urb_priv->td [i];
-			if (td)
-				td_free (hc, td);
-		}
-	}
-
-	kfree (urb_priv);
-}
- 
-static void urb_rm_priv_locked (struct urb * urb) 
-{
-	urb_priv_t * urb_priv = urb->hcpriv;
-	
-	if (urb_priv) {
-		urb->hcpriv = NULL;
-
-#ifdef	DO_TIMEOUTS
-		if (urb->timeout) {
-			list_del (&urb->urb_list);
-			urb->timeout -= jiffies;
-		}
-#endif
-
-		/* Release int/iso bandwidth */
-		if (urb->bandwidth) {
-			switch (usb_pipetype(urb->pipe)) {
-			case PIPE_INTERRUPT:
-				usb_release_bandwidth (urb->dev, urb, 0);
-				break;
-			case PIPE_ISOCHRONOUS:
-				usb_release_bandwidth (urb->dev, urb, 1);
-				break;
-			default:
-				break;
-			}
-		}
-
-		urb_free_priv ((struct ohci *)urb->dev->bus->hcpriv, urb_priv);
-		usb_dec_dev_use (urb->dev);
-		urb->dev = NULL;
-	}
-}
-
-static void urb_rm_priv (struct urb * urb)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave (&usb_ed_lock, flags);
-	urb_rm_priv_locked (urb);
-	spin_unlock_irqrestore (&usb_ed_lock, flags);
-}
-
-/*-------------------------------------------------------------------------*/
- 
-#ifdef DEBUG
-static int sohci_get_current_frame_number (struct usb_device * dev);
-
-/* debug| print the main components of an URB     
- * small: 0) header + data packets 1) just header */
- 
-static void urb_print (struct urb * urb, char * str, int small)
-{
-	unsigned int pipe= urb->pipe;
-	
-	if (!urb->dev || !urb->dev->bus) {
-		dbg("%s URB: no dev", str);
-		return;
-	}
-	
-#ifndef	OHCI_VERBOSE_DEBUG
-	if (urb->status != 0)
-#endif
-	dbg("%s URB:[%4x] dev:%2d,ep:%2d-%c,type:%s,flags:%4x,len:%d/%d,stat:%d(%x)", 
-			str,
-		 	sohci_get_current_frame_number (urb->dev), 
-		 	usb_pipedevice (pipe),
-		 	usb_pipeendpoint (pipe), 
-		 	usb_pipeout (pipe)? 'O': 'I',
-		 	usb_pipetype (pipe) < 2? (usb_pipeint (pipe)? "INTR": "ISOC"):
-		 		(usb_pipecontrol (pipe)? "CTRL": "BULK"),
-		 	urb->transfer_flags, 
-		 	urb->actual_length, 
-		 	urb->transfer_buffer_length,
-		 	urb->status, urb->status);
-#ifdef	OHCI_VERBOSE_DEBUG
-	if (!small) {
-		int i, len;
-
-		if (usb_pipecontrol (pipe)) {
-			printk (KERN_DEBUG __FILE__ ": cmd(8):");
-			for (i = 0; i < 8 ; i++) 
-				printk (" %02x", ((__u8 *) urb->setup_packet) [i]);
-			printk ("\n");
-		}
-		if (urb->transfer_buffer_length > 0 && urb->transfer_buffer) {
-			printk (KERN_DEBUG __FILE__ ": data(%d/%d):", 
-				urb->actual_length, 
-				urb->transfer_buffer_length);
-			len = usb_pipeout (pipe)? 
-						urb->transfer_buffer_length: urb->actual_length;
-			for (i = 0; i < 16 && i < len; i++) 
-				printk (" %02x", ((__u8 *) urb->transfer_buffer) [i]);
-			printk ("%s stat:%d\n", i < len? "...": "", urb->status);
-		}
-	} 
-#endif
-}
-
-/* just for debugging; prints non-empty branches of the int ed tree inclusive iso eds*/
-void ep_print_int_eds (ohci_t * ohci, char * str) {
-	int i, j;
-	 __u32 * ed_p;
-	for (i= 0; i < 32; i++) {
-		j = 5;
-		ed_p = &(ohci->hcca->int_table [i]);
-		if (*ed_p == 0)
-		    continue;
-		printk (KERN_DEBUG __FILE__ ": %s branch int %2d(%2x):", str, i, i);
-		while (*ed_p != 0 && j--) {
-			ed_t *ed = dma_to_ed (ohci, le32_to_cpup(ed_p));
-			printk (" ed: %4x;", ed->hwINFO);
-			ed_p = &ed->hwNextED;
-		}
-		printk ("\n");
-	}
-}
-
-
-static void ohci_dump_intr_mask (char *label, __u32 mask)
-{
-	dbg ("%s: 0x%08x%s%s%s%s%s%s%s%s%s",
-		label,
-		mask,
-		(mask & OHCI_INTR_MIE) ? " MIE" : "",
-		(mask & OHCI_INTR_OC) ? " OC" : "",
-		(mask & OHCI_INTR_RHSC) ? " RHSC" : "",
-		(mask & OHCI_INTR_FNO) ? " FNO" : "",
-		(mask & OHCI_INTR_UE) ? " UE" : "",
-		(mask & OHCI_INTR_RD) ? " RD" : "",
-		(mask & OHCI_INTR_SF) ? " SF" : "",
-		(mask & OHCI_INTR_WDH) ? " WDH" : "",
-		(mask & OHCI_INTR_SO) ? " SO" : ""
-		);
-}
-
-static void maybe_print_eds (char *label, __u32 value)
-{
-	if (value)
-		dbg ("%s %08x", label, value);
-}
-
-static char *hcfs2string (int state)
-{
-	switch (state) {
-		case OHCI_USB_RESET:	return "reset";
-		case OHCI_USB_RESUME:	return "resume";
-		case OHCI_USB_OPER:	return "operational";
-		case OHCI_USB_SUSPEND:	return "suspend";
-	}
-	return "?";
-}
-
-// dump control and status registers
-static void ohci_dump_status (ohci_t *controller)
-{
-	struct ohci_regs	*regs = controller->regs;
-	__u32			temp;
-
-	temp = readl (&regs->revision) & 0xff;
-	if (temp != 0x10)
-		dbg ("spec %d.%d", (temp >> 4), (temp & 0x0f));
-
-	temp = readl (&regs->control);
-	dbg ("control: 0x%08x%s%s%s HCFS=%s%s%s%s%s CBSR=%d", temp,
-		(temp & OHCI_CTRL_RWE) ? " RWE" : "",
-		(temp & OHCI_CTRL_RWC) ? " RWC" : "",
-		(temp & OHCI_CTRL_IR) ? " IR" : "",
-		hcfs2string (temp & OHCI_CTRL_HCFS),
-		(temp & OHCI_CTRL_BLE) ? " BLE" : "",
-		(temp & OHCI_CTRL_CLE) ? " CLE" : "",
-		(temp & OHCI_CTRL_IE) ? " IE" : "",
-		(temp & OHCI_CTRL_PLE) ? " PLE" : "",
-		temp & OHCI_CTRL_CBSR
-		);
-
-	temp = readl (&regs->cmdstatus);
-	dbg ("cmdstatus: 0x%08x SOC=%d%s%s%s%s", temp,
-		(temp & OHCI_SOC) >> 16,
-		(temp & OHCI_OCR) ? " OCR" : "",
-		(temp & OHCI_BLF) ? " BLF" : "",
-		(temp & OHCI_CLF) ? " CLF" : "",
-		(temp & OHCI_HCR) ? " HCR" : ""
-		);
-
-	ohci_dump_intr_mask ("intrstatus", readl (&regs->intrstatus));
-	ohci_dump_intr_mask ("intrenable", readl (&regs->intrenable));
-	// intrdisable always same as intrenable
-	// ohci_dump_intr_mask ("intrdisable", readl (&regs->intrdisable));
-
-	maybe_print_eds ("ed_periodcurrent", readl (&regs->ed_periodcurrent));
-
-	maybe_print_eds ("ed_controlhead", readl (&regs->ed_controlhead));
-	maybe_print_eds ("ed_controlcurrent", readl (&regs->ed_controlcurrent));
-
-	maybe_print_eds ("ed_bulkhead", readl (&regs->ed_bulkhead));
-	maybe_print_eds ("ed_bulkcurrent", readl (&regs->ed_bulkcurrent));
-
-	maybe_print_eds ("donehead", readl (&regs->donehead));
-}
-
-static void ohci_dump_roothub (ohci_t *controller, int verbose)
-{
-	__u32			temp, ndp, i;
-
-	temp = roothub_a (controller);
-	if (temp == ~(u32)0)
-		return;
-	ndp = (temp & RH_A_NDP);
-
-	if (verbose) {
-		dbg ("roothub.a: %08x POTPGT=%d%s%s%s%s%s NDP=%d", temp,
-			((temp & RH_A_POTPGT) >> 24) & 0xff,
-			(temp & RH_A_NOCP) ? " NOCP" : "",
-			(temp & RH_A_OCPM) ? " OCPM" : "",
-			(temp & RH_A_DT) ? " DT" : "",
-			(temp & RH_A_NPS) ? " NPS" : "",
-			(temp & RH_A_PSM) ? " PSM" : "",
-			ndp
-			);
-		temp = roothub_b (controller);
-		dbg ("roothub.b: %08x PPCM=%04x DR=%04x",
-			temp,
-			(temp & RH_B_PPCM) >> 16,
-			(temp & RH_B_DR)
-			);
-		temp = roothub_status (controller);
-		dbg ("roothub.status: %08x%s%s%s%s%s%s",
-			temp,
-			(temp & RH_HS_CRWE) ? " CRWE" : "",
-			(temp & RH_HS_OCIC) ? " OCIC" : "",
-			(temp & RH_HS_LPSC) ? " LPSC" : "",
-			(temp & RH_HS_DRWE) ? " DRWE" : "",
-			(temp & RH_HS_OCI) ? " OCI" : "",
-			(temp & RH_HS_LPS) ? " LPS" : ""
-			);
-	}
-	
-	for (i = 0; i < ndp; i++) {
-		temp = roothub_portstatus (controller, i);
-		dbg ("roothub.portstatus [%d] = 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s",
-			i,
-			temp,
-			(temp & RH_PS_PRSC) ? " PRSC" : "",
-			(temp & RH_PS_OCIC) ? " OCIC" : "",
-			(temp & RH_PS_PSSC) ? " PSSC" : "",
-			(temp & RH_PS_PESC) ? " PESC" : "",
-			(temp & RH_PS_CSC) ? " CSC" : "",
-
-			(temp & RH_PS_LSDA) ? " LSDA" : "",
-			(temp & RH_PS_PPS) ? " PPS" : "",
-			(temp & RH_PS_PRS) ? " PRS" : "",
-			(temp & RH_PS_POCI) ? " POCI" : "",
-			(temp & RH_PS_PSS) ? " PSS" : "",
-
-			(temp & RH_PS_PES) ? " PES" : "",
-			(temp & RH_PS_CCS) ? " CCS" : ""
-			);
-	}
-}
-
-static void ohci_dump (ohci_t *controller, int verbose)
-{
-	dbg ("OHCI controller usb-%s state", controller->ohci_dev->slot_name);
-
-	// dumps some of the state we know about
-	ohci_dump_status (controller);
-	if (verbose)
-		ep_print_int_eds (controller, "hcca");
-	dbg ("hcca frame #%04x", controller->hcca->frame_no);
-	ohci_dump_roothub (controller, 1);
-}
-
-
-#endif
-
-/*-------------------------------------------------------------------------*
- * Interface functions (URB)
- *-------------------------------------------------------------------------*/
-
-/* return a request to the completion handler */
- 
-static int sohci_return_urb (struct ohci *hc, struct urb * urb)
-{
-	urb_priv_t * urb_priv = urb->hcpriv;
-	struct urb * urbt;
-	unsigned long flags;
-	int i;
-	
-	if (!urb_priv)
-		return -1; /* urb already unlinked */
-
-	/* just to be sure */
-	if (!urb->complete) {
-		urb_rm_priv (urb);
-		return -1;
-	}
-	
-#ifdef DEBUG
-	urb_print (urb, "RET", usb_pipeout (urb->pipe));
-#endif
-
-	switch (usb_pipetype (urb->pipe)) {
-  		case PIPE_INTERRUPT:
-			pci_unmap_single (hc->ohci_dev,
-				urb_priv->td [0]->data_dma,
-				urb->transfer_buffer_length,
-				usb_pipeout (urb->pipe)
-					? PCI_DMA_TODEVICE
-					: PCI_DMA_FROMDEVICE);
-			urb->complete (urb);
-
-			/* implicitly requeued */
-  			urb->actual_length = 0;
-			urb->status = -EINPROGRESS;
-			td_submit_urb (urb);
-  			break;
-  			
-		case PIPE_ISOCHRONOUS:
-			for (urbt = urb->next; urbt && (urbt != urb); urbt = urbt->next);
-			if (urbt) { /* send the reply and requeue URB */	
-				pci_unmap_single (hc->ohci_dev,
-					urb_priv->td [0]->data_dma,
-					urb->transfer_buffer_length,
-					usb_pipeout (urb->pipe)
-						? PCI_DMA_TODEVICE
-						: PCI_DMA_FROMDEVICE);
-				urb->complete (urb);
-				spin_lock_irqsave (&usb_ed_lock, flags);
-				urb->actual_length = 0;
-  				urb->status = USB_ST_URB_PENDING;
-  				urb->start_frame = urb_priv->ed->last_iso + 1;
-  				if (urb_priv->state != URB_DEL) {
-  					for (i = 0; i < urb->number_of_packets; i++) {
-  						urb->iso_frame_desc[i].actual_length = 0;
-  						urb->iso_frame_desc[i].status = -EXDEV;
-  					}
-  					td_submit_urb (urb);
-  				}
-  				spin_unlock_irqrestore (&usb_ed_lock, flags);
-  				
-  			} else { /* unlink URB, call complete */
-				urb_rm_priv (urb);
-				urb->complete (urb); 	
-			}		
-			break;
-  				
-		case PIPE_BULK:
-		case PIPE_CONTROL: /* unlink URB, call complete */
-			urb_rm_priv (urb);
-			urb->complete (urb);	
-			break;
-	}
-	return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* get a transfer request */
- 
-static int sohci_submit_urb (struct urb * urb)
-{
-	ohci_t * ohci;
-	ed_t * ed;
-	urb_priv_t * urb_priv;
-	unsigned int pipe = urb->pipe;
-	int maxps = usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe));
-	int i, size = 0;
-	unsigned long flags;
-	int bustime = 0;
-	int mem_flags = ALLOC_FLAGS;
-	
-	if (!urb->dev || !urb->dev->bus)
-		return -ENODEV;
-	
-	if (urb->hcpriv)			/* urb already in use */
-		return -EINVAL;
-
-//	if(usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe))) 
-//		return -EPIPE;
-	
-	usb_inc_dev_use (urb->dev);
-	ohci = (ohci_t *) urb->dev->bus->hcpriv;
-	
-#ifdef DEBUG
-	urb_print (urb, "SUB", usb_pipein (pipe));
-#endif
-	
-	/* handle a request to the virtual root hub */
-	if (usb_pipedevice (pipe) == ohci->rh.devnum) 
-		return rh_submit_urb (urb);
-	
-	/* when controller's hung, permit only roothub cleanup attempts
-	 * such as powering down ports */
-	if (ohci->disabled) {
-		usb_dec_dev_use (urb->dev);	
-		return -ESHUTDOWN;
-	}
-
-	/* every endpoint has a ed, locate and fill it */
-	if (!(ed = ep_add_ed (urb->dev, pipe, urb->interval, 1, mem_flags))) {
-		usb_dec_dev_use (urb->dev);	
-		return -ENOMEM;
-	}
-
-	/* for the private part of the URB we need the number of TDs (size) */
-	switch (usb_pipetype (pipe)) {
-		case PIPE_BULK:	/* one TD for every 4096 Byte */
-			size = (urb->transfer_buffer_length - 1) / 4096 + 1;
-
-			/* If the transfer size is multiple of the pipe mtu,
-			 * we may need an extra TD to create a empty frame
-			 * Jean II */
-			if ((urb->transfer_flags & USB_ZERO_PACKET) &&
-			    usb_pipeout (pipe) &&
-			    (urb->transfer_buffer_length != 0) && 
-			    ((urb->transfer_buffer_length % maxps) == 0))
-				size++;
-			break;
-		case PIPE_ISOCHRONOUS: /* number of packets from URB */
-			size = urb->number_of_packets;
-			if (size <= 0) {
-				usb_dec_dev_use (urb->dev);	
-				return -EINVAL;
-			}
-			for (i = 0; i < urb->number_of_packets; i++) {
-  				urb->iso_frame_desc[i].actual_length = 0;
-  				urb->iso_frame_desc[i].status = -EXDEV;
-  			}
-			break;
-		case PIPE_CONTROL: /* 1 TD for setup, 1 for ACK and 1 for every 4096 B */
-			size = (urb->transfer_buffer_length == 0)? 2: 
-						(urb->transfer_buffer_length - 1) / 4096 + 3;
-			break;
-		case PIPE_INTERRUPT: /* one TD */
-			size = 1;
-			break;
-	}
-
-	/* allocate the private part of the URB */
-	urb_priv = kmalloc (sizeof (urb_priv_t) + size * sizeof (td_t *), 
-							in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
-	if (!urb_priv) {
-		usb_dec_dev_use (urb->dev);	
-		return -ENOMEM;
-	}
-	memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (td_t *));
-	
-	/* fill the private part of the URB */
-	urb_priv->length = size;
-	urb_priv->ed = ed;	
-
-	/* allocate the TDs (updating hash chains) */
-	spin_lock_irqsave (&usb_ed_lock, flags);
-	for (i = 0; i < size; i++) { 
-		urb_priv->td[i] = td_alloc (ohci, SLAB_ATOMIC);
-		if (!urb_priv->td[i]) {
-			urb_priv->length = i;
-			urb_free_priv (ohci, urb_priv);
-			spin_unlock_irqrestore (&usb_ed_lock, flags);
-			usb_dec_dev_use (urb->dev);	
-			return -ENOMEM;
-		}
-	}	
-
-	if (ed->state == ED_NEW || (ed->state & ED_DEL)) {
-		urb_free_priv (ohci, urb_priv);
-		spin_unlock_irqrestore (&usb_ed_lock, flags);
-		usb_dec_dev_use (urb->dev);	
-		return -EINVAL;
-	}
-	
-	/* allocate and claim bandwidth if needed; ISO
-	 * needs start frame index if it was't provided.
-	 */
-	switch (usb_pipetype (pipe)) {
-		case PIPE_ISOCHRONOUS:
-			if (urb->transfer_flags & USB_ISO_ASAP) { 
-				urb->start_frame = ((ed->state == ED_OPER)
-					? (ed->last_iso + 1)
-					: (le16_to_cpu (ohci->hcca->frame_no) + 10)) & 0xffff;
-			}	
-			/* FALLTHROUGH */
-		case PIPE_INTERRUPT:
-			if (urb->bandwidth == 0) {
-				bustime = usb_check_bandwidth (urb->dev, urb);
-			}
-			if (bustime < 0) {
-				urb_free_priv (ohci, urb_priv);
-				spin_unlock_irqrestore (&usb_ed_lock, flags);
-				usb_dec_dev_use (urb->dev);	
-				return bustime;
-			}
-			usb_claim_bandwidth (urb->dev, urb, bustime, usb_pipeisoc (urb->pipe));
-#ifdef	DO_TIMEOUTS
-			urb->timeout = 0;
-#endif
-	}
-
-	urb->actual_length = 0;
-	urb->hcpriv = urb_priv;
-	urb->status = USB_ST_URB_PENDING;
-
-	/* link the ed into a chain if is not already */
-	if (ed->state != ED_OPER)
-		ep_link (ohci, ed);
-
-	/* fill the TDs and link it to the ed */
-	td_submit_urb (urb);
-
-#ifdef	DO_TIMEOUTS
-	/* maybe add to ordered list of timeouts */
-	if (urb->timeout) {
-		struct list_head	*entry;
-
-		// FIXME:  usb-uhci uses relative timeouts (like this),
-		// while uhci uses absolute ones (probably better).
-		// Pick one solution and change the affected drivers.
-		urb->timeout += jiffies;
-
-		list_for_each (entry, &ohci->timeout_list) {
-			struct urb	*next_urb;
-
-			next_urb = list_entry (entry, struct urb, urb_list);
-			if (time_after_eq (urb->timeout, next_urb->timeout))
-				break;
-		}
-		list_add (&urb->urb_list, entry);
-
-		/* drive timeouts by SF (messy, but works) */
-		writel (OHCI_INTR_SF, &ohci->regs->intrenable);	
-	}
-#endif
-
-	spin_unlock_irqrestore (&usb_ed_lock, flags);
-
-	return 0;	
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* deactivate all TDs and remove the private part of the URB */
-/* interrupt callers must use async unlink mode */
-
-static int sohci_unlink_urb (struct urb * urb)
-{
-	unsigned long flags;
-	ohci_t * ohci;
-	
-	if (!urb) /* just to be sure */ 
-		return -EINVAL;
-		
-	if (!urb->dev || !urb->dev->bus)
-		return -ENODEV;
-
-	ohci = (ohci_t *) urb->dev->bus->hcpriv; 
-
-#ifdef DEBUG
-	urb_print (urb, "UNLINK", 1);
-#endif		  
-
-	/* handle a request to the virtual root hub */
-	if (usb_pipedevice (urb->pipe) == ohci->rh.devnum)
-		return rh_unlink_urb (urb);
-
-	if (urb->hcpriv && (urb->status == USB_ST_URB_PENDING)) { 
-		if (!ohci->disabled) {
-			urb_priv_t  * urb_priv;
-
-			/* interrupt code may not sleep; it must use
-			 * async status return to unlink pending urbs.
-			 */
-			if (!(urb->transfer_flags & USB_ASYNC_UNLINK)
-					&& in_interrupt ()) {
-				err ("bug in call from %p; use async!",
-					__builtin_return_address(0));
-				return -EWOULDBLOCK;
-			}
-
-			/* flag the urb and its TDs for deletion in some
-			 * upcoming SF interrupt delete list processing
-			 */
-			spin_lock_irqsave (&usb_ed_lock, flags);
-			urb_priv = urb->hcpriv;
-
-			if (!urb_priv || (urb_priv->state == URB_DEL)) {
-				spin_unlock_irqrestore (&usb_ed_lock, flags);
-				return 0;
-			}
-				
-			urb_priv->state = URB_DEL; 
-			ep_rm_ed (urb->dev, urb_priv->ed);
-			urb_priv->ed->state |= ED_URB_DEL;
-
-			if (!(urb->transfer_flags & USB_ASYNC_UNLINK)) {
-				DECLARE_WAIT_QUEUE_HEAD (unlink_wakeup); 
-				DECLARE_WAITQUEUE (wait, current);
-				int timeout = OHCI_UNLINK_TIMEOUT;
-
-				add_wait_queue (&unlink_wakeup, &wait);
-				urb_priv->wait = &unlink_wakeup;
-				spin_unlock_irqrestore (&usb_ed_lock, flags);
-
-				/* wait until all TDs are deleted */
-				set_current_state(TASK_UNINTERRUPTIBLE);
-				while (timeout && (urb->status == USB_ST_URB_PENDING))
-					timeout = schedule_timeout (timeout);
-				set_current_state(TASK_RUNNING);
-				remove_wait_queue (&unlink_wakeup, &wait); 
-				if (urb->status == USB_ST_URB_PENDING) {
-					err ("unlink URB timeout");
-					return -ETIMEDOUT;
-				}
-			} else {
-				/* usb_dec_dev_use done in dl_del_list() */
-				urb->status = -EINPROGRESS;
-				spin_unlock_irqrestore (&usb_ed_lock, flags);
-				return -EINPROGRESS;
-			}
-		} else {
-			urb_rm_priv (urb);
-			if (urb->transfer_flags & USB_ASYNC_UNLINK) {
-				urb->status = -ECONNRESET;
-				if (urb->complete)
-					urb->complete (urb); 
-			} else 
-				urb->status = -ENOENT;
-		}	
-	}	
-	return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* allocate private data space for a usb device */
-
-static int sohci_alloc_dev (struct usb_device *usb_dev)
-{
-	struct ohci_device * dev;
-
-	dev = dev_alloc ((struct ohci *) usb_dev->bus->hcpriv, ALLOC_FLAGS);
-	if (!dev)
-		return -ENOMEM;
-
-	usb_dev->hcpriv = dev;
-	return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* may be called from interrupt context */
-/* frees private data space of usb device */
-  
-static int sohci_free_dev (struct usb_device * usb_dev)
-{
-	unsigned long flags;
-	int i, cnt = 0;
-	ed_t * ed;
-	struct ohci_device * dev = usb_to_ohci (usb_dev);
-	ohci_t * ohci = usb_dev->bus->hcpriv;
-	
-	if (!dev)
-		return 0;
-	
-	if (usb_dev->devnum >= 0) {
-	
-		/* driver disconnects should have unlinked all urbs
-		 * (freeing all the TDs, unlinking EDs) but we need
-		 * to defend against bugs that prevent that.
-		 */
-		spin_lock_irqsave (&usb_ed_lock, flags);	
-		for(i = 0; i < NUM_EDS; i++) {
-  			ed = &(dev->ed[i]);
-  			if (ed->state != ED_NEW) {
-  				if (ed->state == ED_OPER) {
-					/* driver on that interface didn't unlink an urb */
-					dbg ("driver usb-%s dev %d ed 0x%x unfreed URB",
-						ohci->ohci_dev->slot_name, usb_dev->devnum, i);
-					ep_unlink (ohci, ed);
-				}
-  				ep_rm_ed (usb_dev, ed);
-  				ed->state = ED_DEL;
-  				cnt++;
-  			}
-  		}
-  		spin_unlock_irqrestore (&usb_ed_lock, flags);
-  		
-		/* if the controller is running, tds for those unlinked
-		 * urbs get freed by dl_del_list at the next SF interrupt
-		 */
-		if (cnt > 0) {
-
-			if (ohci->disabled) {
-				/* FIXME: Something like this should kick in,
-				 * though it's currently an exotic case ...
-				 * the controller won't ever be touching
-				 * these lists again!!
-				dl_del_list (ohci,
-					le16_to_cpu (ohci->hcca->frame_no) & 1);
-				 */
-				warn ("TD leak, %d", cnt);
-
-			} else if (!in_interrupt ()) {
-				DECLARE_WAIT_QUEUE_HEAD (freedev_wakeup); 
-				DECLARE_WAITQUEUE (wait, current);
-				int timeout = OHCI_UNLINK_TIMEOUT;
-
-				/* SF interrupt handler calls dl_del_list */
-				add_wait_queue (&freedev_wakeup, &wait);
-				dev->wait = &freedev_wakeup;
-				set_current_state(TASK_UNINTERRUPTIBLE);
-				while (timeout && dev->ed_cnt)
-					timeout = schedule_timeout (timeout);
-				set_current_state(TASK_RUNNING);
-				remove_wait_queue (&freedev_wakeup, &wait);
-				if (dev->ed_cnt) {
-					err ("free device %d timeout", usb_dev->devnum);
-					return -ETIMEDOUT;
-				}
-			} else {
-				/* likely some interface's driver has a refcount bug */
-				err ("bus %s devnum %d deletion in interrupt",
-					ohci->ohci_dev->slot_name, usb_dev->devnum);
-				BUG ();
-			}
-		}
-	}
-
-	/* free device, and associated EDs */
-	dev_free (ohci, dev);
-
-	return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* tell us the current USB frame number */
-
-static int sohci_get_current_frame_number (struct usb_device *usb_dev) 
-{
-	ohci_t * ohci = usb_dev->bus->hcpriv;
-	
-	return le16_to_cpu (ohci->hcca->frame_no);
-}
-
-/*-------------------------------------------------------------------------*/
-
-struct usb_operations sohci_device_operations = {
-	sohci_alloc_dev,
-	sohci_free_dev,
-	sohci_get_current_frame_number,
-	sohci_submit_urb,
-	sohci_unlink_urb
-};
-
-/*-------------------------------------------------------------------------*
- * ED handling functions
- *-------------------------------------------------------------------------*/  
-		
-/* search for the right branch to insert an interrupt ed into the int tree 
- * do some load ballancing;
- * returns the branch and 
- * sets the interval to interval = 2^integer (ld (interval)) */
-
-static int ep_int_ballance (ohci_t * ohci, int interval, int load)
-{
-	int i, branch = 0;
-   
-	/* search for the least loaded interrupt endpoint branch of all 32 branches */
-	for (i = 0; i < 32; i++) 
-		if (ohci->ohci_int_load [branch] > ohci->ohci_int_load [i]) branch = i; 
-  
-	branch = branch % interval;
-	for (i = branch; i < 32; i += interval) ohci->ohci_int_load [i] += load;
-
-	return branch;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/*  2^int( ld (inter)) */
-
-static int ep_2_n_interval (int inter)
-{	
-	int i;
-	for (i = 0; ((inter >> i) > 1 ) && (i < 5); i++); 
-	return 1 << i;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* the int tree is a binary tree 
- * in order to process it sequentially the indexes of the branches have to be mapped 
- * the mapping reverses the bits of a word of num_bits length */
- 
-static int ep_rev (int num_bits, int word)
-{
-	int i, wout = 0;
-
-	for (i = 0; i < num_bits; i++) wout |= (((word >> i) & 1) << (num_bits - i - 1));
-	return wout;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* link an ed into one of the HC chains */
-
-static int ep_link (ohci_t * ohci, ed_t * edi)
-{	 
-	int int_branch;
-	int i;
-	int inter;
-	int interval;
-	int load;
-	__u32 * ed_p;
-	volatile ed_t * ed = edi;
-	
-	ed->state = ED_OPER;
-	
-	switch (ed->type) {
-	case PIPE_CONTROL:
-		ed->hwNextED = 0;
-		if (ohci->ed_controltail == NULL) {
-			writel (ed->dma, &ohci->regs->ed_controlhead);
-		} else {
-			ohci->ed_controltail->hwNextED = cpu_to_le32 (ed->dma);
-		}
-		ed->ed_prev = ohci->ed_controltail;
-		if (!ohci->ed_controltail && !ohci->ed_rm_list[0] &&
-			!ohci->ed_rm_list[1] && !ohci->sleeping) {
-			ohci->hc_control |= OHCI_CTRL_CLE;
-			writel (ohci->hc_control, &ohci->regs->control);
-		}
-		ohci->ed_controltail = edi;	  
-		break;
-		
-	case PIPE_BULK:
-		ed->hwNextED = 0;
-		if (ohci->ed_bulktail == NULL) {
-			writel (ed->dma, &ohci->regs->ed_bulkhead);
-		} else {
-			ohci->ed_bulktail->hwNextED = cpu_to_le32 (ed->dma);
-		}
-		ed->ed_prev = ohci->ed_bulktail;
-		if (!ohci->ed_bulktail && !ohci->ed_rm_list[0] &&
-			!ohci->ed_rm_list[1] && !ohci->sleeping) {
-			ohci->hc_control |= OHCI_CTRL_BLE;
-			writel (ohci->hc_control, &ohci->regs->control);
-		}
-		ohci->ed_bulktail = edi;	  
-		break;
-		
-	case PIPE_INTERRUPT:
-		load = ed->int_load;
-		interval = ep_2_n_interval (ed->int_period);
-		ed->int_interval = interval;
-		int_branch = ep_int_ballance (ohci, interval, load);
-		ed->int_branch = int_branch;
-		
-		for (i = 0; i < ep_rev (6, interval); i += inter) {
-			inter = 1;
-			for (ed_p = &(ohci->hcca->int_table[ep_rev (5, i) + int_branch]); 
-				(*ed_p != 0) && ((dma_to_ed (ohci, le32_to_cpup (ed_p)))->int_interval >= interval); 
-				ed_p = &((dma_to_ed (ohci, le32_to_cpup (ed_p)))->hwNextED)) 
-					inter = ep_rev (6, (dma_to_ed (ohci, le32_to_cpup (ed_p)))->int_interval);
-			ed->hwNextED = *ed_p; 
-			*ed_p = cpu_to_le32 (ed->dma);
-		}
-#ifdef DEBUG
-		ep_print_int_eds (ohci, "LINK_INT");
-#endif
-		break;
-		
-	case PIPE_ISOCHRONOUS:
-		ed->hwNextED = 0;
-		ed->int_interval = 1;
-		if (ohci->ed_isotail != NULL) {
-			ohci->ed_isotail->hwNextED = cpu_to_le32 (ed->dma);
-			ed->ed_prev = ohci->ed_isotail;
-		} else {
-			for ( i = 0; i < 32; i += inter) {
-				inter = 1;
-				for (ed_p = &(ohci->hcca->int_table[ep_rev (5, i)]); 
-					*ed_p != 0; 
-					ed_p = &((dma_to_ed (ohci, le32_to_cpup (ed_p)))->hwNextED)) 
-						inter = ep_rev (6, (dma_to_ed (ohci, le32_to_cpup (ed_p)))->int_interval);
-				*ed_p = cpu_to_le32 (ed->dma);	
-			}	
-			ed->ed_prev = NULL;
-		}	
-		ohci->ed_isotail = edi;  
-#ifdef DEBUG
-		ep_print_int_eds (ohci, "LINK_ISO");
-#endif
-		break;
-	}	 	
-	return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* scan the periodic table to find and unlink this ED */
-static void periodic_unlink (
-	struct ohci	*ohci,
-	struct ed	*ed,
-	unsigned	index,
-	unsigned	period
-) {
-	for (; index < NUM_INTS; index += period) {
-		__u32	*ed_p = &ohci->hcca->int_table [index];
-
-		/* ED might have been unlinked through another path */
-		while (*ed_p != 0) {
-			if ((dma_to_ed (ohci, le32_to_cpup (ed_p))) == ed) {
-				*ed_p = ed->hwNextED;		
-				break;
-			}
-			ed_p = & ((dma_to_ed (ohci,
-				le32_to_cpup (ed_p)))->hwNextED);
-		}
-	}	
-}
-
-/* unlink an ed from one of the HC chains. 
- * just the link to the ed is unlinked.
- * the link from the ed still points to another operational ed or 0
- * so the HC can eventually finish the processing of the unlinked ed */
-
-static int ep_unlink (ohci_t * ohci, ed_t * ed) 
-{
-	int i;
-
-	ed->hwINFO |= cpu_to_le32 (OHCI_ED_SKIP);
-
-	switch (ed->type) {
-	case PIPE_CONTROL:
-		if (ed->ed_prev == NULL) {
-			if (!ed->hwNextED) {
-				ohci->hc_control &= ~OHCI_CTRL_CLE;
-				writel (ohci->hc_control, &ohci->regs->control);
-			}
-			writel (le32_to_cpup (&ed->hwNextED), &ohci->regs->ed_controlhead);
-		} else {
-			ed->ed_prev->hwNextED = ed->hwNextED;
-		}
-		if (ohci->ed_controltail == ed) {
-			ohci->ed_controltail = ed->ed_prev;
-		} else {
-			(dma_to_ed (ohci, le32_to_cpup (&ed->hwNextED)))->ed_prev = ed->ed_prev;
-		}
-		break;
-      
-	case PIPE_BULK:
-		if (ed->ed_prev == NULL) {
-			if (!ed->hwNextED) {
-				ohci->hc_control &= ~OHCI_CTRL_BLE;
-				writel (ohci->hc_control, &ohci->regs->control);
-			}
-			writel (le32_to_cpup (&ed->hwNextED), &ohci->regs->ed_bulkhead);
-		} else {
-			ed->ed_prev->hwNextED = ed->hwNextED;
-		}
-		if (ohci->ed_bulktail == ed) {
-			ohci->ed_bulktail = ed->ed_prev;
-		} else {
-			(dma_to_ed (ohci, le32_to_cpup (&ed->hwNextED)))->ed_prev = ed->ed_prev;
-		}
-		break;
-      
-	case PIPE_INTERRUPT:
-		periodic_unlink (ohci, ed, 0, 1);
-		for (i = ed->int_branch; i < 32; i += ed->int_interval)
-		    ohci->ohci_int_load[i] -= ed->int_load;
-#ifdef DEBUG
-		ep_print_int_eds (ohci, "UNLINK_INT");
-#endif
-		break;
-		
-	case PIPE_ISOCHRONOUS:
-		if (ohci->ed_isotail == ed)
-			ohci->ed_isotail = ed->ed_prev;
-		if (ed->hwNextED != 0) 
-		    (dma_to_ed (ohci, le32_to_cpup (&ed->hwNextED)))
-		    	->ed_prev = ed->ed_prev;
-				    
-		if (ed->ed_prev != NULL)
-			ed->ed_prev->hwNextED = ed->hwNextED;
-		else
-			periodic_unlink (ohci, ed, 0, 1);
-#ifdef DEBUG
-		ep_print_int_eds (ohci, "UNLINK_ISO");
-#endif
-		break;
-	}
-	ed->state = ED_UNLINK;
-	return 0;
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-/* add/reinit an endpoint; this should be done once at the usb_set_configuration command,
- * but the USB stack is a little bit stateless  so we do it at every transaction
- * if the state of the ed is ED_NEW then a dummy td is added and the state is changed to ED_UNLINK
- * in all other cases the state is left unchanged
- * the ed info fields are setted anyway even though most of them should not change */
- 
-static ed_t * ep_add_ed (
-	struct usb_device * usb_dev,
-	unsigned int pipe,
-	int interval,
-	int load,
-	int mem_flags
-)
-{
-   	ohci_t * ohci = usb_dev->bus->hcpriv;
-	td_t * td;
-	ed_t * ed_ret;
-	volatile ed_t * ed; 
-	unsigned long flags;
- 	
- 	
-	spin_lock_irqsave (&usb_ed_lock, flags);
-
-	ed = ed_ret = &(usb_to_ohci (usb_dev)->ed[(usb_pipeendpoint (pipe) << 1) | 
-			(usb_pipecontrol (pipe)? 0: usb_pipeout (pipe))]);
-
-	if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) {
-		/* pending delete request */
-		spin_unlock_irqrestore (&usb_ed_lock, flags);
-		return NULL;
-	}
-	
-	if (ed->state == ED_NEW) {
-		ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP); /* skip ed */
-  		/* dummy td; end of td list for ed */
-		td = td_alloc (ohci, SLAB_ATOMIC);
-		/* hash the ed for later reverse mapping */
- 		if (!td || !hash_add_ed (ohci, (ed_t *)ed)) {
-			/* out of memory */
-		        if (td)
-		            td_free(ohci, td);
-			spin_unlock_irqrestore (&usb_ed_lock, flags);
-			return NULL;
-		}
-		ed->hwTailP = cpu_to_le32 (td->td_dma);
-		ed->hwHeadP = ed->hwTailP;	
-		ed->state = ED_UNLINK;
-		ed->type = usb_pipetype (pipe);
-		usb_to_ohci (usb_dev)->ed_cnt++;
-	}
-
-	ohci->dev[usb_pipedevice (pipe)] = usb_dev;
-	
-	ed->hwINFO = cpu_to_le32 (usb_pipedevice (pipe)
-			| usb_pipeendpoint (pipe) << 7
-			| (usb_pipeisoc (pipe)? 0x8000: 0)
-			| (usb_pipecontrol (pipe)? 0: (usb_pipeout (pipe)? 0x800: 0x1000)) 
-			| usb_pipeslow (pipe) << 13
-			| usb_maxpacket (usb_dev, pipe, usb_pipeout (pipe)) << 16);
-  
-  	if (ed->type == PIPE_INTERRUPT && ed->state == ED_UNLINK) {
-  		ed->int_period = interval;
-  		ed->int_load = load;
-  	}
-  	
-	spin_unlock_irqrestore (&usb_ed_lock, flags);
-	return ed_ret; 
-}
-
-/*-------------------------------------------------------------------------*/
- 
-/* request the removal of an endpoint
- * put the ep on the rm_list and request a stop of the bulk or ctrl list 
- * real removal is done at the next start frame (SF) hardware interrupt */
- 
-static void ep_rm_ed (struct usb_device * usb_dev, ed_t * ed)
-{    
-	unsigned int frame;
-	ohci_t * ohci = usb_dev->bus->hcpriv;
-
-	if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL))
-		return;
-	
-	ed->hwINFO |= cpu_to_le32 (OHCI_ED_SKIP);
-
-	if (!ohci->disabled) {
-		switch (ed->type) {
-			case PIPE_CONTROL: /* stop control list */
-				ohci->hc_control &= ~OHCI_CTRL_CLE;
-				writel (ohci->hc_control, &ohci->regs->control); 
-  				break;
-			case PIPE_BULK: /* stop bulk list */
-				ohci->hc_control &= ~OHCI_CTRL_BLE;
-				writel (ohci->hc_control, &ohci->regs->control); 
-				break;
-		}
-	}
-
-	frame = le16_to_cpu (ohci->hcca->frame_no) & 0x1;
-	ed->ed_rm_list = ohci->ed_rm_list[frame];
-	ohci->ed_rm_list[frame] = ed;
-
-	if (!ohci->disabled && !ohci->sleeping) {
-		/* enable SOF interrupt */
-		writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
-		writel (OHCI_INTR_SF, &ohci->regs->intrenable);
-	}
-}
-
-/*-------------------------------------------------------------------------*
- * TD handling functions
- *-------------------------------------------------------------------------*/
-
-/* enqueue next TD for this URB (OHCI spec 5.2.8.2) */
-
-static void
-td_fill (ohci_t * ohci, unsigned int info,
-	dma_addr_t data, int len,
-	struct urb * urb, int index)
-{
-	volatile td_t  * td, * td_pt;
-	urb_priv_t * urb_priv = urb->hcpriv;
-	
-	if (index >= urb_priv->length) {
-		err("internal OHCI error: TD index > length");
-		return;
-	}
-	
-	/* use this td as the next dummy */
-	td_pt = urb_priv->td [index];
-	td_pt->hwNextTD = 0;
-
-	/* fill the old dummy TD */
-	td = urb_priv->td [index] = dma_to_td (ohci,
-			le32_to_cpup (&urb_priv->ed->hwTailP) & ~0xf);
-
-	td->ed = urb_priv->ed;
-	td->next_dl_td = NULL;
-	td->index = index;
-	td->urb = urb; 
-	td->data_dma = data;
-	if (!len)
-		data = 0;
-
-	td->hwINFO = cpu_to_le32 (info);
-	if ((td->ed->type) == PIPE_ISOCHRONOUS) {
-		td->hwCBP = cpu_to_le32 (data & 0xFFFFF000);
-		td->ed->last_iso = info & 0xffff;
-	} else {
-		td->hwCBP = cpu_to_le32 (data); 
-	}			
-	if (data)
-		td->hwBE = cpu_to_le32 (data + len - 1);
-	else
-		td->hwBE = 0;
-	td->hwNextTD = cpu_to_le32 (td_pt->td_dma);
-	td->hwPSW [0] = cpu_to_le16 ((data & 0x0FFF) | 0xE000);
-
-	/* append to queue */
-	wmb();
-	td->ed->hwTailP = td->hwNextTD;
-}
-
-/*-------------------------------------------------------------------------*/
- 
-/* prepare all TDs of a transfer */
-
-static void td_submit_urb (struct urb * urb)
-{ 
-	urb_priv_t * urb_priv = urb->hcpriv;
-	ohci_t * ohci = (ohci_t *) urb->dev->bus->hcpriv;
-	dma_addr_t data;
-	int data_len = urb->transfer_buffer_length;
-	int maxps = usb_maxpacket (urb->dev, urb->pipe, usb_pipeout (urb->pipe));
-	int cnt = 0; 
-	__u32 info = 0;
-  	unsigned int toggle = 0;
-
-	/* OHCI handles the DATA-toggles itself, we just use the USB-toggle bits for reseting */
-  	if(usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe))) {
-  		toggle = TD_T_TOGGLE;
-	} else {
-  		toggle = TD_T_DATA0;
-		usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe), 1);
-	}
-	
-	urb_priv->td_cnt = 0;
-
-	if (data_len) {
-		data = pci_map_single (ohci->ohci_dev,
-			urb->transfer_buffer, data_len,
-			usb_pipeout (urb->pipe)
-				? PCI_DMA_TODEVICE
-				: PCI_DMA_FROMDEVICE
-			);
-	} else
-		data = 0;
-	
-	switch (usb_pipetype (urb->pipe)) {
-		case PIPE_BULK:
-			info = usb_pipeout (urb->pipe)? 
-				TD_CC | TD_DP_OUT : TD_CC | TD_DP_IN ;
-			while(data_len > 4096) {		
-				td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, 4096, urb, cnt);
-				data += 4096; data_len -= 4096; cnt++;
-			}
-			info = usb_pipeout (urb->pipe)?
-				TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ;
-			td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, data_len, urb, cnt);
-			cnt++;
-
-			/* If the transfer size is multiple of the pipe mtu,
-			 * we may need an extra TD to create a empty frame
-			 * Note : another way to check this condition is
-			 * to test if(urb_priv->length > cnt) - Jean II */
-			if ((urb->transfer_flags & USB_ZERO_PACKET) &&
-			    usb_pipeout (urb->pipe) &&
-			    (urb->transfer_buffer_length != 0) && 
-			    ((urb->transfer_buffer_length % maxps) == 0)) {
-				td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), 0, 0, urb, cnt);
-				cnt++;
-			}
-
-			if (!ohci->sleeping) {
-				wmb();
-				writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
-			}
-			break;
-
-		case PIPE_INTERRUPT:
-			info = usb_pipeout (urb->pipe)? 
-				TD_CC | TD_DP_OUT | toggle: TD_CC | TD_R | TD_DP_IN | toggle;
-			td_fill (ohci, info, data, data_len, urb, cnt++);
-			break;
-
-		case PIPE_CONTROL:
-			info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
-			td_fill (ohci, info,
-				pci_map_single (ohci->ohci_dev,
-					urb->setup_packet, 8,
-					PCI_DMA_TODEVICE),
-				8, urb, cnt++); 
-			if (data_len > 0) {  
-				info = usb_pipeout (urb->pipe)? 
-					TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1 : TD_CC | TD_R | TD_DP_IN | TD_T_DATA1;
-				/* NOTE:  mishandles transfers >8K, some >4K */
-				td_fill (ohci, info, data, data_len, urb, cnt++);  
-			} 
-			info = usb_pipeout (urb->pipe)? 
- 				TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1;
-			td_fill (ohci, info, data, 0, urb, cnt++);
-			if (!ohci->sleeping) {
-				wmb();
-				writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
-			}
-			break;
-
-		case PIPE_ISOCHRONOUS:
-			for (cnt = 0; cnt < urb->number_of_packets; cnt++) {
-				td_fill (ohci, TD_CC|TD_ISO | ((urb->start_frame + cnt) & 0xffff), 
-					data + urb->iso_frame_desc[cnt].offset, 
-					urb->iso_frame_desc[cnt].length, urb, cnt); 
-			}
-			break;
-	} 
-	if (urb_priv->length != cnt) 
-		dbg("TD LENGTH %d != CNT %d", urb_priv->length, cnt);
-}
-
-/*-------------------------------------------------------------------------*
- * Done List handling functions
- *-------------------------------------------------------------------------*/
-
-
-/* calculate the transfer length and update the urb */
-
-static void dl_transfer_length(td_t * td)
-{
-	__u32 tdINFO, tdBE, tdCBP;
- 	__u16 tdPSW;
- 	struct urb * urb = td->urb;
- 	urb_priv_t * urb_priv = urb->hcpriv;
-	int dlen = 0;
-	int cc = 0;
-	
-	tdINFO = le32_to_cpup (&td->hwINFO);
-  	tdBE   = le32_to_cpup (&td->hwBE);
-  	tdCBP  = le32_to_cpup (&td->hwCBP);
-
-
-  	if (tdINFO & TD_ISO) {
- 		tdPSW = le16_to_cpu (td->hwPSW[0]);
- 		cc = (tdPSW >> 12) & 0xF;
-		if (cc < 0xE)  {
-			if (usb_pipeout(urb->pipe)) {
-				dlen = urb->iso_frame_desc[td->index].length;
-			} else {
-				dlen = tdPSW & 0x3ff;
-			}
-			urb->actual_length += dlen;
-			urb->iso_frame_desc[td->index].actual_length = dlen;
-			if (!(urb->transfer_flags & USB_DISABLE_SPD) && (cc == TD_DATAUNDERRUN))
-				cc = TD_CC_NOERROR;
-					 
-			urb->iso_frame_desc[td->index].status = cc_to_error[cc];
-		}
-	} else { /* BULK, INT, CONTROL DATA */
-		if (!(usb_pipetype (urb->pipe) == PIPE_CONTROL && 
-				((td->index == 0) || (td->index == urb_priv->length - 1)))) {
- 			if (tdBE != 0) {
- 				if (td->hwCBP == 0)
-					urb->actual_length += tdBE - td->data_dma + 1;
-  				else
-					urb->actual_length += tdCBP - td->data_dma;
-			}
-  		}
-  	}
-}
-
-/* handle an urb that is being unlinked */
-
-static void dl_del_urb (struct urb * urb)
-{
-	wait_queue_head_t * wait_head = ((urb_priv_t *)(urb->hcpriv))->wait;
-
-	urb_rm_priv_locked (urb);
-
-	if (urb->transfer_flags & USB_ASYNC_UNLINK) {
-		urb->status = -ECONNRESET;
-		if (urb->complete)
-			urb->complete (urb);
-	} else {
-		urb->status = -ENOENT;
-		if (urb->complete)
-			urb->complete (urb);
-
-		/* unblock sohci_unlink_urb */
-		if (wait_head)
-			wake_up (wait_head);
-	}
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* replies to the request have to be on a FIFO basis so
- * we reverse the reversed done-list */
- 
-static td_t * dl_reverse_done_list (ohci_t * ohci)
-{
-	__u32 td_list_hc;
-	td_t * td_rev = NULL;
-	td_t * td_list = NULL;
-  	urb_priv_t * urb_priv = NULL;
-  	unsigned long flags;
-  	
-  	spin_lock_irqsave (&usb_ed_lock, flags);
-  	
-	td_list_hc = le32_to_cpup (&ohci->hcca->done_head) & 0xfffffff0;
-	ohci->hcca->done_head = 0;
-	
-	while (td_list_hc) {		
-		td_list = dma_to_td (ohci, td_list_hc);
-
-		if (TD_CC_GET (le32_to_cpup (&td_list->hwINFO))) {
-			urb_priv = (urb_priv_t *) td_list->urb->hcpriv;
-			dbg(" USB-error/status: %x : %p", 
-					TD_CC_GET (le32_to_cpup (&td_list->hwINFO)), td_list);
-			if (td_list->ed->hwHeadP & cpu_to_le32 (0x1)) {
-				if (urb_priv && ((td_list->index + 1) < urb_priv->length)) {
-					td_list->ed->hwHeadP = 
-						(urb_priv->td[urb_priv->length - 1]->hwNextTD & cpu_to_le32 (0xfffffff0)) |
-									(td_list->ed->hwHeadP & cpu_to_le32 (0x2));
-					urb_priv->td_cnt += urb_priv->length - td_list->index - 1;
-				} else 
-					td_list->ed->hwHeadP &= cpu_to_le32 (0xfffffff2);
-			}
-		}
-
-		td_list->next_dl_td = td_rev;	
-		td_rev = td_list;
-		td_list_hc = le32_to_cpup (&td_list->hwNextTD) & 0xfffffff0;	
-	}	
-	spin_unlock_irqrestore (&usb_ed_lock, flags);
-	return td_list;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* there are some pending requests to remove 
- * - some of the eds (if ed->state & ED_DEL (set by sohci_free_dev)
- * - some URBs/TDs if urb_priv->state == URB_DEL */
- 
-static void dl_del_list (ohci_t  * ohci, unsigned int frame)
-{
-	unsigned long flags;
-	ed_t * ed;
-	__u32 edINFO;
-	__u32 tdINFO;
-	td_t * td = NULL, * td_next = NULL, * tdHeadP = NULL, * tdTailP;
-	__u32 * td_p;
-	int ctrl = 0, bulk = 0;
-
-	spin_lock_irqsave (&usb_ed_lock, flags);
-
-	for (ed = ohci->ed_rm_list[frame]; ed != NULL; ed = ed->ed_rm_list) {
-
-		tdTailP = dma_to_td (ohci, le32_to_cpup (&ed->hwTailP) & 0xfffffff0);
-		tdHeadP = dma_to_td (ohci, le32_to_cpup (&ed->hwHeadP) & 0xfffffff0);
-		edINFO = le32_to_cpup (&ed->hwINFO);
-		td_p = &ed->hwHeadP;
-
-		for (td = tdHeadP; td != tdTailP; td = td_next) { 
-			struct urb * urb = td->urb;
-			urb_priv_t * urb_priv = td->urb->hcpriv;
-			
-			td_next = dma_to_td (ohci, le32_to_cpup (&td->hwNextTD) & 0xfffffff0);
-			if ((urb_priv->state == URB_DEL) || (ed->state & ED_DEL)) {
-				tdINFO = le32_to_cpup (&td->hwINFO);
-				if (TD_CC_GET (tdINFO) < 0xE)
-					dl_transfer_length (td);
-				*td_p = td->hwNextTD | (*td_p & cpu_to_le32 (0x3));
-
-				/* URB is done; clean up */
-				if (++(urb_priv->td_cnt) == urb_priv->length)
-					dl_del_urb (urb);
-			} else {
-				td_p = &td->hwNextTD;
-			}
-		}
-
-		if (ed->state & ED_DEL) { /* set by sohci_free_dev */
-			struct ohci_device * dev = usb_to_ohci (ohci->dev[edINFO & 0x7F]);
-			td_free (ohci, tdTailP); /* free dummy td */
-   	 		ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP); 
-			ed->state = ED_NEW;
-			hash_free_ed(ohci, ed);
-   	 		/* if all eds are removed wake up sohci_free_dev */
-   	 		if (!--dev->ed_cnt) {
-				wait_queue_head_t *wait_head = dev->wait;
-
-				dev->wait = 0;
-				if (wait_head)
-					wake_up (wait_head);
-			}
-   	 	} else {
-   	 		ed->state &= ~ED_URB_DEL;
-			tdHeadP = dma_to_td (ohci, le32_to_cpup (&ed->hwHeadP) & 0xfffffff0);
-
-			if (tdHeadP == tdTailP) {
-				if (ed->state == ED_OPER)
-					ep_unlink(ohci, ed);
-			} else
-   	 			ed->hwINFO &= ~cpu_to_le32 (OHCI_ED_SKIP);
-   	 	}
-
-		switch (ed->type) {
-			case PIPE_CONTROL:
-				ctrl = 1;
-				break;
-			case PIPE_BULK:
-				bulk = 1;
-				break;
-		}
-   	}
-   	
-	/* maybe reenable control and bulk lists */ 
-	if (!ohci->disabled) {
-		if (ctrl) 	/* reset control list */
-			writel (0, &ohci->regs->ed_controlcurrent);
-		if (bulk)	/* reset bulk list */
-			writel (0, &ohci->regs->ed_bulkcurrent);
-		if (!ohci->ed_rm_list[!frame] && !ohci->sleeping) {
-			if (ohci->ed_controltail)
-				ohci->hc_control |= OHCI_CTRL_CLE;
-			if (ohci->ed_bulktail)
-				ohci->hc_control |= OHCI_CTRL_BLE;
-			writel (ohci->hc_control, &ohci->regs->control);   
-		}
-	}
-
-   	ohci->ed_rm_list[frame] = NULL;
-   	spin_unlock_irqrestore (&usb_ed_lock, flags);
-}
-
-
-  		
-/*-------------------------------------------------------------------------*/
-
-/* td done list */
-
-static void dl_done_list (ohci_t * ohci, td_t * td_list)
-{
-  	td_t * td_list_next = NULL;
-	ed_t * ed;
-	int cc = 0;
-	struct urb * urb;
-	urb_priv_t * urb_priv;
- 	__u32 tdINFO, edHeadP, edTailP;
- 	
- 	unsigned long flags;
- 	
-  	while (td_list) {
-   		td_list_next = td_list->next_dl_td;
-   		
-  		urb = td_list->urb;
-  		urb_priv = urb->hcpriv;
-  		tdINFO = le32_to_cpup (&td_list->hwINFO);
-  		
-   		ed = td_list->ed;
-   		
-   		dl_transfer_length(td_list);
- 			
-  		/* error code of transfer */
-  		cc = TD_CC_GET (tdINFO);
-  		if (cc == TD_CC_STALL)
-			usb_endpoint_halt(urb->dev,
-				usb_pipeendpoint(urb->pipe),
-				usb_pipeout(urb->pipe));
-  		
-  		if (!(urb->transfer_flags & USB_DISABLE_SPD)
-				&& (cc == TD_DATAUNDERRUN))
-			cc = TD_CC_NOERROR;
-
-  		if (++(urb_priv->td_cnt) == urb_priv->length) {
-			if ((ed->state & (ED_OPER | ED_UNLINK))
-					&& (urb_priv->state != URB_DEL)) {
-  				urb->status = cc_to_error[cc];
-  				sohci_return_urb (ohci, urb);
-  			} else {
-				spin_lock_irqsave (&usb_ed_lock, flags);
-  				dl_del_urb (urb);
-				spin_unlock_irqrestore (&usb_ed_lock, flags);
-			}
-  		}
-  		
-  		spin_lock_irqsave (&usb_ed_lock, flags);
-  		if (ed->state != ED_NEW) { 
-  			edHeadP = le32_to_cpup (&ed->hwHeadP) & 0xfffffff0;
-  			edTailP = le32_to_cpup (&ed->hwTailP);
-
-			/* unlink eds if they are not busy */
-     			if ((edHeadP == edTailP) && (ed->state == ED_OPER)) 
-     				ep_unlink (ohci, ed);
-     		}	
-     		spin_unlock_irqrestore (&usb_ed_lock, flags);
-     	
-    		td_list = td_list_next;
-  	}  
-}
-
-
-
-
-/*-------------------------------------------------------------------------*
- * Virtual Root Hub 
- *-------------------------------------------------------------------------*/
- 
-/* Device descriptor */
-static __u8 root_hub_dev_des[] =
-{
-	0x12,       /*  __u8  bLength; */
-	0x01,       /*  __u8  bDescriptorType; Device */
-	0x10,	    /*  __u16 bcdUSB; v1.1 */
-	0x01,
-	0x09,	    /*  __u8  bDeviceClass; HUB_CLASSCODE */
-	0x00,	    /*  __u8  bDeviceSubClass; */
-	0x00,       /*  __u8  bDeviceProtocol; */
-	0x08,       /*  __u8  bMaxPacketSize0; 8 Bytes */
-	0x00,       /*  __u16 idVendor; */
-	0x00,
-	0x00,       /*  __u16 idProduct; */
- 	0x00,
-	0x00,       /*  __u16 bcdDevice; */
- 	0x00,
-	0x00,       /*  __u8  iManufacturer; */
-	0x02,       /*  __u8  iProduct; */
-	0x01,       /*  __u8  iSerialNumber; */
-	0x01        /*  __u8  bNumConfigurations; */
-};
-
-
-/* Configuration descriptor */
-static __u8 root_hub_config_des[] =
-{
-	0x09,       /*  __u8  bLength; */
-	0x02,       /*  __u8  bDescriptorType; Configuration */
-	0x19,       /*  __u16 wTotalLength; */
-	0x00,
-	0x01,       /*  __u8  bNumInterfaces; */
-	0x01,       /*  __u8  bConfigurationValue; */
-	0x00,       /*  __u8  iConfiguration; */
-	0x40,       /*  __u8  bmAttributes; 
-                 Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
-	0x00,       /*  __u8  MaxPower; */
-      
-	/* interface */	  
-	0x09,       /*  __u8  if_bLength; */
-	0x04,       /*  __u8  if_bDescriptorType; Interface */
-	0x00,       /*  __u8  if_bInterfaceNumber; */
-	0x00,       /*  __u8  if_bAlternateSetting; */
-	0x01,       /*  __u8  if_bNumEndpoints; */
-	0x09,       /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
-	0x00,       /*  __u8  if_bInterfaceSubClass; */
-	0x00,       /*  __u8  if_bInterfaceProtocol; */
-	0x00,       /*  __u8  if_iInterface; */
-     
-	/* endpoint */
-	0x07,       /*  __u8  ep_bLength; */
-	0x05,       /*  __u8  ep_bDescriptorType; Endpoint */
-	0x81,       /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
- 	0x03,       /*  __u8  ep_bmAttributes; Interrupt */
- 	0x02,       /*  __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
- 	0x00,
-	0xff        /*  __u8  ep_bInterval; 255 ms */
-};
-
-/* Hub class-specific descriptor is constructed dynamically */
-
-
-/*-------------------------------------------------------------------------*/
-
-/* prepare Interrupt pipe data; HUB INTERRUPT ENDPOINT */ 
- 
-static int rh_send_irq (ohci_t * ohci, void * rh_data, int rh_len)
-{
-	int num_ports;
-	int i;
-	int ret;
-	int len;
-
-	__u8 data[8];
-
-	num_ports = roothub_a (ohci) & RH_A_NDP; 
-	if (num_ports > MAX_ROOT_PORTS) {
-		err ("bogus NDP=%d for OHCI usb-%s", num_ports,
-			ohci->ohci_dev->slot_name);
-		err ("rereads as NDP=%d",
-			readl (&ohci->regs->roothub.a) & RH_A_NDP);
-		/* retry later; "should not happen" */
-		return 0;
-	}
-	*(__u8 *) data = (roothub_status (ohci) & (RH_HS_LPSC | RH_HS_OCIC))
-		? 1: 0;
-	ret = *(__u8 *) data;
-
-	for ( i = 0; i < num_ports; i++) {
-		*(__u8 *) (data + (i + 1) / 8) |= 
-			((roothub_portstatus (ohci, i) &
-				(RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC | RH_PS_OCIC | RH_PS_PRSC))
-			    ? 1: 0) << ((i + 1) % 8);
-		ret += *(__u8 *) (data + (i + 1) / 8);
-	}
-	len = i/8 + 1;
-  
-	if (ret > 0) { 
-		memcpy(rh_data, data,
-		       min_t(unsigned int, len,
-			   min_t(unsigned int, rh_len, sizeof(data))));
-		return len;
-	}
-	return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* Virtual Root Hub INTs are polled by this timer every "interval" ms */
- 
-static void rh_int_timer_do (unsigned long ptr)
-{
-	int len; 
-
-	struct urb * urb = (struct urb *) ptr;
-	ohci_t * ohci = urb->dev->bus->hcpriv;
-
-	if (ohci->disabled)
-		return;
-
-	/* ignore timers firing during PM suspend, etc */
-	if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER)
-		goto out;
-
-	if(ohci->rh.send) { 
-		len = rh_send_irq (ohci, urb->transfer_buffer, urb->transfer_buffer_length);
-		if (len > 0) {
-			urb->actual_length = len;
-#ifdef DEBUG
-			urb_print (urb, "RET-t(rh)", usb_pipeout (urb->pipe));
-#endif
-			if (urb->complete)
-				urb->complete (urb);
-		}
-	}
- out:
-	rh_init_int_timer (urb);
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* Root Hub INTs are polled by this timer */
-
-static int rh_init_int_timer (struct urb * urb) 
-{
-	ohci_t * ohci = urb->dev->bus->hcpriv;
-
-	ohci->rh.interval = urb->interval;
-	init_timer (&ohci->rh.rh_int_timer);
-	ohci->rh.rh_int_timer.function = rh_int_timer_do;
-	ohci->rh.rh_int_timer.data = (unsigned long) urb;
-	ohci->rh.rh_int_timer.expires = 
-			jiffies + (HZ * (urb->interval < 30? 30: urb->interval)) / 1000;
-	add_timer (&ohci->rh.rh_int_timer);
-	
-	return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-#define OK(x) 			len = (x); break
-#define WR_RH_STAT(x) 		writel((x), &ohci->regs->roothub.status)
-#define WR_RH_PORTSTAT(x) 	writel((x), &ohci->regs->roothub.portstatus[wIndex-1])
-#define RD_RH_STAT		roothub_status(ohci)
-#define RD_RH_PORTSTAT		roothub_portstatus(ohci,wIndex-1)
-
-/* request to virtual root hub */
-
-static int rh_submit_urb (struct urb * urb)
-{
-	struct usb_device * usb_dev = urb->dev;
-	ohci_t * ohci = usb_dev->bus->hcpriv;
-	unsigned int pipe = urb->pipe;
-	struct usb_ctrlrequest * cmd = (struct usb_ctrlrequest *) urb->setup_packet;
-	void * data = urb->transfer_buffer;
-	int leni = urb->transfer_buffer_length;
-	int len = 0;
-	int status = TD_CC_NOERROR;
-	
-	__u32 datab[4];
-	__u8  * data_buf = (__u8 *) datab;
-	
- 	__u16 bmRType_bReq;
-	__u16 wValue; 
-	__u16 wIndex;
-	__u16 wLength;
-
-	if (usb_pipeint(pipe)) {
-		ohci->rh.urb =  urb;
-		ohci->rh.send = 1;
-		ohci->rh.interval = urb->interval;
-		rh_init_int_timer(urb);
-		urb->status = cc_to_error [TD_CC_NOERROR];
-		
-		return 0;
-	}
-
-	bmRType_bReq  = cmd->bRequestType | (cmd->bRequest << 8);
-	wValue        = le16_to_cpu (cmd->wValue);
-	wIndex        = le16_to_cpu (cmd->wIndex);
-	wLength       = le16_to_cpu (cmd->wLength);
-
-	switch (bmRType_bReq) {
-	/* Request Destination:
-	   without flags: Device, 
-	   RH_INTERFACE: interface, 
-	   RH_ENDPOINT: endpoint,
-	   RH_CLASS means HUB here, 
-	   RH_OTHER | RH_CLASS  almost ever means HUB_PORT here 
-	*/
-  
-		case RH_GET_STATUS: 				 		
-				*(__u16 *) data_buf = cpu_to_le16 (1); OK (2);
-		case RH_GET_STATUS | RH_INTERFACE: 	 		
-				*(__u16 *) data_buf = cpu_to_le16 (0); OK (2);
-		case RH_GET_STATUS | RH_ENDPOINT:	 		
-				*(__u16 *) data_buf = cpu_to_le16 (0); OK (2);   
-		case RH_GET_STATUS | RH_CLASS: 				
-				*(__u32 *) data_buf = cpu_to_le32 (
-					RD_RH_STAT & ~(RH_HS_CRWE | RH_HS_DRWE));
-				OK (4);
-		case RH_GET_STATUS | RH_OTHER | RH_CLASS: 	
-				*(__u32 *) data_buf = cpu_to_le32 (RD_RH_PORTSTAT); OK (4);
-
-		case RH_CLEAR_FEATURE | RH_ENDPOINT:  
-			switch (wValue) {
-				case (RH_ENDPOINT_STALL): OK (0);
-			}
-			break;
-
-		case RH_CLEAR_FEATURE | RH_CLASS:
-			switch (wValue) {
-				case RH_C_HUB_LOCAL_POWER:
-					OK(0);
-				case (RH_C_HUB_OVER_CURRENT): 
-						WR_RH_STAT(RH_HS_OCIC); OK (0);
-			}
-			break;
-		
-		case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
-			switch (wValue) {
-				case (RH_PORT_ENABLE): 			
-						WR_RH_PORTSTAT (RH_PS_CCS ); OK (0);
-				case (RH_PORT_SUSPEND):			
-						WR_RH_PORTSTAT (RH_PS_POCI); OK (0);
-				case (RH_PORT_POWER):			
-						WR_RH_PORTSTAT (RH_PS_LSDA); OK (0);
-				case (RH_C_PORT_CONNECTION):	
-						WR_RH_PORTSTAT (RH_PS_CSC ); OK (0);
-				case (RH_C_PORT_ENABLE):		
-						WR_RH_PORTSTAT (RH_PS_PESC); OK (0);
-				case (RH_C_PORT_SUSPEND):		
-						WR_RH_PORTSTAT (RH_PS_PSSC); OK (0);
-				case (RH_C_PORT_OVER_CURRENT):	
-						WR_RH_PORTSTAT (RH_PS_OCIC); OK (0);
-				case (RH_C_PORT_RESET):			
-						WR_RH_PORTSTAT (RH_PS_PRSC); OK (0); 
-			}
-			break;
- 
-		case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
-			switch (wValue) {
-				case (RH_PORT_SUSPEND):			
-						WR_RH_PORTSTAT (RH_PS_PSS ); OK (0); 
-				case (RH_PORT_RESET): /* BUG IN HUP CODE *********/
-						if (RD_RH_PORTSTAT & RH_PS_CCS)
-						    WR_RH_PORTSTAT (RH_PS_PRS);
-						OK (0);
-				case (RH_PORT_POWER):			
-						WR_RH_PORTSTAT (RH_PS_PPS ); OK (0); 
-				case (RH_PORT_ENABLE): /* BUG IN HUP CODE *********/
-						if (RD_RH_PORTSTAT & RH_PS_CCS)
-						    WR_RH_PORTSTAT (RH_PS_PES );
-						OK (0);
-			}
-			break;
-
-		case RH_SET_ADDRESS: ohci->rh.devnum = wValue; OK(0);
-
-		case RH_GET_DESCRIPTOR:
-			switch ((wValue & 0xff00) >> 8) {
-				case (0x01): /* device descriptor */
-					len = min_t(unsigned int,
-						  leni,
-						  min_t(unsigned int,
-						      sizeof (root_hub_dev_des),
-						      wLength));
-					data_buf = root_hub_dev_des; OK(len);
-				case (0x02): /* configuration descriptor */
-					len = min_t(unsigned int,
-						  leni,
-						  min_t(unsigned int,
-						      sizeof (root_hub_config_des),
-						      wLength));
-					data_buf = root_hub_config_des; OK(len);
-				case (0x03): /* string descriptors */
-					len = usb_root_hub_string (wValue & 0xff,
-						(int)(long) ohci->regs, "OHCI",
-						data, wLength);
-					if (len > 0) {
-						data_buf = data;
-						OK(min_t(int, leni, len));
-					}
-					// else fallthrough
-				default: 
-					status = TD_CC_STALL;
-			}
-			break;
-		
-		case RH_GET_DESCRIPTOR | RH_CLASS:
-		    {
-			    __u32 temp = roothub_a (ohci);
-
-			    data_buf [0] = 9;		// min length;
-			    data_buf [1] = 0x29;
-			    data_buf [2] = temp & RH_A_NDP;
-			    data_buf [3] = 0;
-			    if (temp & RH_A_PSM) 	/* per-port power switching? */
-				data_buf [3] |= 0x1;
-			    if (temp & RH_A_NOCP)	/* no overcurrent reporting? */
-				data_buf [3] |= 0x10;
-			    else if (temp & RH_A_OCPM)	/* per-port overcurrent reporting? */
-				data_buf [3] |= 0x8;
-
-			    datab [1] = 0;
-			    data_buf [5] = (temp & RH_A_POTPGT) >> 24;
-			    temp = roothub_b (ohci);
-			    data_buf [7] = temp & RH_B_DR;
-			    if (data_buf [2] < 7) {
-				data_buf [8] = 0xff;
-			    } else {
-				data_buf [0] += 2;
-				data_buf [8] = (temp & RH_B_DR) >> 8;
-				data_buf [10] = data_buf [9] = 0xff;
-			    }
-				
-			    len = min_t(unsigned int, leni,
-				      min_t(unsigned int, data_buf [0], wLength));
-			    OK (len);
-			}
- 
-		case RH_GET_CONFIGURATION: 	*(__u8 *) data_buf = 0x01; OK (1);
-
-		case RH_SET_CONFIGURATION: 	WR_RH_STAT (0x10000); OK (0);
-
-		default: 
-			dbg ("unsupported root hub command");
-			status = TD_CC_STALL;
-	}
-	
-#ifdef	DEBUG
-	// ohci_dump_roothub (ohci, 0);
-#endif
-
-	len = min_t(int, len, leni);
-	if (data != data_buf)
-	    memcpy (data, data_buf, len);
-  	urb->actual_length = len;
-	urb->status = cc_to_error [status];
-	
-#ifdef DEBUG
-	urb_print (urb, "RET(rh)", usb_pipeout (urb->pipe));
-#endif
-
-	urb->hcpriv = NULL;
-	usb_dec_dev_use (usb_dev);
-	urb->dev = NULL;
-	if (urb->complete)
-	    	urb->complete (urb);
-	return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-static int rh_unlink_urb (struct urb * urb)
-{
-	ohci_t * ohci = urb->dev->bus->hcpriv;
- 
-	if (ohci->rh.urb == urb) {
-		ohci->rh.send = 0;
-		del_timer (&ohci->rh.rh_int_timer);
-		ohci->rh.urb = NULL;
-
-		urb->hcpriv = NULL;
-		usb_dec_dev_use(urb->dev);
-		urb->dev = NULL;
-		if (urb->transfer_flags & USB_ASYNC_UNLINK) {
-			urb->status = -ECONNRESET;
-			if (urb->complete)
-				urb->complete (urb);
-		} else
-			urb->status = -ENOENT;
-	}
-	return 0;
-}
- 
-/*-------------------------------------------------------------------------*
- * HC functions
- *-------------------------------------------------------------------------*/
-
-/* reset the HC and BUS */
-
-static int hc_reset (ohci_t * ohci)
-{
-	int timeout = 30;
-	int smm_timeout = 50; /* 0,5 sec */
-	 	
-#ifndef __hppa__
-	/* PA-RISC doesn't have SMM, but PDC might leave IR set */
-	if (readl (&ohci->regs->control) & OHCI_CTRL_IR) { /* SMM owns the HC */
-		writel (OHCI_OCR, &ohci->regs->cmdstatus); /* request ownership */
-		dbg("USB HC TakeOver from SMM");
-		while (readl (&ohci->regs->control) & OHCI_CTRL_IR) {
-			wait_ms (10);
-			if (--smm_timeout == 0) {
-				err("USB HC TakeOver failed!");
-				return -1;
-			}
-		}
-	}
-#endif	
-		
-	/* Disable HC interrupts */
-	writel (OHCI_INTR_MIE, &ohci->regs->intrdisable);
-
-	dbg("USB HC reset_hc usb-%s: ctrl = 0x%x ;",
-		ohci->ohci_dev->slot_name,
-		readl (&ohci->regs->control));
-
-  	/* Reset USB (needed by some controllers) */
-	writel (0, &ohci->regs->control);
-      	
-	/* HC Reset requires max 10 ms delay */
-	writel (OHCI_HCR,  &ohci->regs->cmdstatus);
-	while ((readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) {
-		if (--timeout == 0) {
-			err("USB HC reset timed out!");
-			return -1;
-		}	
-		udelay (1);
-	}	 
-	return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* Start an OHCI controller, set the BUS operational
- * enable interrupts 
- * connect the virtual root hub */
-
-static int hc_start (ohci_t * ohci)
-{
-  	__u32 mask;
-  	unsigned int fminterval;
-  	struct usb_device  * usb_dev;
-	struct ohci_device * dev;
-	
-	ohci->disabled = 1;
-
-	/* Tell the controller where the control and bulk lists are
-	 * The lists are empty now. */
-	 
-	writel (0, &ohci->regs->ed_controlhead);
-	writel (0, &ohci->regs->ed_bulkhead);
-	
-	writel (ohci->hcca_dma, &ohci->regs->hcca); /* a reset clears this */
-   
-  	fminterval = 0x2edf;
-	writel ((fminterval * 9) / 10, &ohci->regs->periodicstart);
-	fminterval |= ((((fminterval - 210) * 6) / 7) << 16); 
-	writel (fminterval, &ohci->regs->fminterval);	
-	writel (0x628, &ohci->regs->lsthresh);
-
- 	/* start controller operations */
- 	ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
-	ohci->disabled = 0;
- 	writel (ohci->hc_control, &ohci->regs->control);
- 
-	/* Choose the interrupts we care about now, others later on demand */
-	mask = OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_WDH | OHCI_INTR_SO;
-	writel (mask, &ohci->regs->intrenable);
-	writel (mask, &ohci->regs->intrstatus);
-
-#ifdef	OHCI_USE_NPS
-	if(ohci->flags & OHCI_QUIRK_SUCKYIO)
-	{
-		/* NSC 87560 at least requires different setup .. */
-		writel ((roothub_a (ohci) | RH_A_NOCP) &
-			~(RH_A_OCPM | RH_A_POTPGT | RH_A_PSM | RH_A_NPS),
-			&ohci->regs->roothub.a);
-	}
-	else
-	{
-		/* required for AMD-756 and some Mac platforms */
-		writel ((roothub_a (ohci) | RH_A_NPS) & ~RH_A_PSM,
-			&ohci->regs->roothub.a);
-	}
-	writel (RH_HS_LPSC, &ohci->regs->roothub.status);
-#endif	/* OHCI_USE_NPS */
-
-	// POTPGT delay is bits 24-31, in 2 ms units.
-	mdelay ((roothub_a (ohci) >> 23) & 0x1fe);
- 
-	/* connect the virtual root hub */
-	ohci->rh.devnum = 0;
-	usb_dev = usb_alloc_dev (NULL, ohci->bus);
-	if (!usb_dev) {
-	    ohci->disabled = 1;
-	    return -ENOMEM;
-	}
-
-	dev = usb_to_ohci (usb_dev);
-	ohci->bus->root_hub = usb_dev;
-	usb_connect (usb_dev);
-	if (usb_new_device (usb_dev) != 0) {
-		usb_free_dev (usb_dev); 
-		ohci->disabled = 1;
-		return -ENODEV;
-	}
-	
-	return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* called only from interrupt handler */
-
-static void check_timeouts (struct ohci *ohci)
-{
-	spin_lock (&usb_ed_lock);
-	while (!list_empty (&ohci->timeout_list)) {
-		struct urb	*urb;
-
-		urb = list_entry (ohci->timeout_list.next, struct urb, urb_list);
-		if (time_after (jiffies, urb->timeout))
-			break;
-
-		list_del_init (&urb->urb_list);
-		if (urb->status != -EINPROGRESS)
-			continue;
-
-		urb->transfer_flags |= USB_TIMEOUT_KILLED | USB_ASYNC_UNLINK;
-		spin_unlock (&usb_ed_lock);
-
-		// outside the interrupt handler (in a timer...)
-		// this reference would race interrupts
-		sohci_unlink_urb (urb);
-
-		spin_lock (&usb_ed_lock);
-	}
-	spin_unlock (&usb_ed_lock);
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-/* an interrupt happens */
-
-static void hc_interrupt (int irq, void * __ohci, struct pt_regs * r)
-{
-	ohci_t * ohci = __ohci;
-	struct ohci_regs * regs = ohci->regs;
- 	int ints; 
-
-	/* avoid (slow) readl if only WDH happened */
-	if ((ohci->hcca->done_head != 0)
-			&& !(le32_to_cpup (&ohci->hcca->done_head) & 0x01)) {
-		ints =  OHCI_INTR_WDH;
-
-	/* cardbus/... hardware gone before remove() */
-	} else if ((ints = readl (&regs->intrstatus)) == ~(u32)0) {
-		ohci->disabled++;
-		err ("%s device removed!", ohci->ohci_dev->slot_name);
-		return;
-
-	/* interrupt for some other device? */
-	} else if ((ints &= readl (&regs->intrenable)) == 0) {
-		return;
-	} 
-
-	// dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no));
-
-	if (ints & OHCI_INTR_UE) {
-		ohci->disabled++;
-		err ("OHCI Unrecoverable Error, controller usb-%s disabled",
-			ohci->ohci_dev->slot_name);
-		// e.g. due to PCI Master/Target Abort
-
-#ifdef	DEBUG
-		ohci_dump (ohci, 1);
-#else
-		// FIXME: be optimistic, hope that bug won't repeat often.
-		// Make some non-interrupt context restart the controller.
-		// Count and limit the retries though; either hardware or
-		// software errors can go forever...
-#endif
-		hc_reset (ohci);
-	}
-  
-	if (ints & OHCI_INTR_WDH) {
-		writel (OHCI_INTR_WDH, &regs->intrdisable);	
-		dl_done_list (ohci, dl_reverse_done_list (ohci));
-		writel (OHCI_INTR_WDH, &regs->intrenable); 
-	}
-  
-	if (ints & OHCI_INTR_SO) {
-		dbg("USB Schedule overrun");
-		writel (OHCI_INTR_SO, &regs->intrenable); 	 
-	}
-
-	// FIXME:  this assumes SOF (1/ms) interrupts don't get lost...
-	if (ints & OHCI_INTR_SF) { 
-		unsigned int frame = le16_to_cpu (ohci->hcca->frame_no) & 1;
-		writel (OHCI_INTR_SF, &regs->intrdisable);	
-		if (ohci->ed_rm_list[!frame] != NULL) {
-			dl_del_list (ohci, !frame);
-		}
-		if (ohci->ed_rm_list[frame] != NULL)
-			writel (OHCI_INTR_SF, &regs->intrenable);	
-	}
-
-	if (!list_empty (&ohci->timeout_list)) {
-		check_timeouts (ohci);
-// FIXME:  enable SF as needed in a timer;
-// don't make lots of 1ms interrupts
-// On unloaded USB, think 4k ~= 4-5msec
-		if (!list_empty (&ohci->timeout_list))
-			writel (OHCI_INTR_SF, &regs->intrenable);	
-	}
-
-	writel (ints, &regs->intrstatus);
-	writel (OHCI_INTR_MIE, &regs->intrenable);	
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* allocate OHCI */
-
-static ohci_t * __devinit hc_alloc_ohci (struct pci_dev *dev, void * mem_base)
-{
-	ohci_t * ohci;
-
-	ohci = (ohci_t *) kmalloc (sizeof *ohci, GFP_KERNEL);
-	if (!ohci)
-		return NULL;
-		
-	memset (ohci, 0, sizeof (ohci_t));
-
-	ohci->hcca = pci_alloc_consistent (dev, sizeof *ohci->hcca,
-			&ohci->hcca_dma);
-        if (!ohci->hcca) {
-                kfree (ohci);
-                return NULL;
-        }
-        memset (ohci->hcca, 0, sizeof (struct ohci_hcca));
-
-	ohci->disabled = 1;
-	ohci->sleeping = 0;
-	ohci->irq = -1;
-	ohci->regs = mem_base;   
-
-	ohci->ohci_dev = dev;
-	pci_set_drvdata(dev, ohci);
- 
-	INIT_LIST_HEAD (&ohci->ohci_hcd_list);
-	list_add (&ohci->ohci_hcd_list, &ohci_hcd_list);
-
-	INIT_LIST_HEAD (&ohci->timeout_list);
-
-	ohci->bus = usb_alloc_bus (&sohci_device_operations);
-	if (!ohci->bus) {
-		pci_set_drvdata (dev, NULL);
-		pci_free_consistent (ohci->ohci_dev, sizeof *ohci->hcca,
-				ohci->hcca, ohci->hcca_dma);
-		kfree (ohci);
-		return NULL;
-	}
-	ohci->bus->bus_name = dev->slot_name;
-	ohci->bus->hcpriv = (void *) ohci;
-
-	return ohci;
-} 
-
-
-/*-------------------------------------------------------------------------*/
-
-/* De-allocate all resources.. */
-
-static void hc_release_ohci (ohci_t * ohci)
-{	
-	dbg ("USB HC release ohci usb-%s", ohci->ohci_dev->slot_name);
-
-	/* disconnect all devices */    
-	if (ohci->bus->root_hub)
-		usb_disconnect (&ohci->bus->root_hub);
-
-	if (!ohci->disabled)
-		hc_reset (ohci);
-	
-	if (ohci->irq >= 0) {
-		free_irq (ohci->irq, ohci);
-		ohci->irq = -1;
-	}
-	pci_set_drvdata(ohci->ohci_dev, NULL);
-	if (ohci->bus) {
-		if (ohci->bus->busnum != -1)
-			usb_deregister_bus (ohci->bus);
-
-		usb_free_bus (ohci->bus);
-	}
-
-	list_del (&ohci->ohci_hcd_list);
-	INIT_LIST_HEAD (&ohci->ohci_hcd_list);
-
-	ohci_mem_cleanup (ohci);
-    
-	/* unmap the IO address space */
-	iounmap (ohci->regs);
-
-	pci_free_consistent (ohci->ohci_dev, sizeof *ohci->hcca,
-		ohci->hcca, ohci->hcca_dma);
-	kfree (ohci);
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* Increment the module usage count, start the control thread and
- * return success. */
-
-static struct pci_driver ohci_pci_driver;
- 
-static int __devinit
-hc_found_ohci (struct pci_dev *dev, int irq,
-	void *mem_base, const struct pci_device_id *id)
-{
-	ohci_t * ohci;
-	char buf[8], *bufp = buf;
-	int ret;
-
-#ifndef __sparc__
-	sprintf(buf, "%d", irq);
-#else
-	bufp = __irq_itoa(irq);
-#endif
-	printk(KERN_INFO __FILE__ ": USB OHCI at membase 0x%lx, IRQ %s\n",
-		(unsigned long)	mem_base, bufp);
-	printk(KERN_INFO __FILE__ ": usb-%s, %s\n", dev->slot_name, dev->name);
-    
-	ohci = hc_alloc_ohci (dev, mem_base);
-	if (!ohci) {
-		return -ENOMEM;
-	}
-	if ((ret = ohci_mem_init (ohci)) < 0) {
-		hc_release_ohci (ohci);
-		return ret;
-	}
-	ohci->flags = id->driver_data;
-	
-	/* Check for NSC87560. We have to look at the bridge (fn1) to identify
-	   the USB (fn2). This quirk might apply to more or even all NSC stuff
-	   I don't know.. */
-	   
-	if(dev->vendor == PCI_VENDOR_ID_NS)
-	{
-		struct pci_dev *fn1  = pci_find_slot(dev->bus->number, PCI_DEVFN(PCI_SLOT(dev->devfn), 1));
-		if(fn1 && fn1->vendor == PCI_VENDOR_ID_NS && fn1->device == PCI_DEVICE_ID_NS_87560_LIO)
-			ohci->flags |= OHCI_QUIRK_SUCKYIO;
-		
-	}
-	
-	if (ohci->flags & OHCI_QUIRK_SUCKYIO)
-		printk (KERN_INFO __FILE__ ": Using NSC SuperIO setup\n");
-	if (ohci->flags & OHCI_QUIRK_AMD756)
-		printk (KERN_INFO __FILE__ ": AMD756 erratum 4 workaround\n");
-
-	if (hc_reset (ohci) < 0) {
-		hc_release_ohci (ohci);
-		return -ENODEV;
-	}
-
-	/* FIXME this is a second HC reset; why?? */
-	writel (ohci->hc_control = OHCI_USB_RESET, &ohci->regs->control);
-	wait_ms (10);
-
-	usb_register_bus (ohci->bus);
-	
-	if (request_irq (irq, hc_interrupt, SA_SHIRQ,
-			ohci_pci_driver.name, ohci) != 0) {
-		err ("request interrupt %s failed", bufp);
-		hc_release_ohci (ohci);
-		return -EBUSY;
-	}
-	ohci->irq = irq;     
-
-	if (hc_start (ohci) < 0) {
-		err ("can't start usb-%s", dev->slot_name);
-		hc_release_ohci (ohci);
-		return -EBUSY;
-	}
-
-#ifdef	DEBUG
-	ohci_dump (ohci, 1);
-#endif
-	return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-#ifdef	CONFIG_PM
-
-/* controller died; cleanup debris, then restart */
-/* must not be called from interrupt context */
-
-static void hc_restart (ohci_t *ohci)
-{
-	int temp;
-	int i;
-
-	if (ohci->pci_latency)
-		pci_write_config_byte (ohci->ohci_dev, PCI_LATENCY_TIMER, ohci->pci_latency);
-
-	ohci->disabled = 1;
-	ohci->sleeping = 0;
-	if (ohci->bus->root_hub)
-		usb_disconnect (&ohci->bus->root_hub);
-	
-	/* empty the interrupt branches */
-	for (i = 0; i < NUM_INTS; i++) ohci->ohci_int_load[i] = 0;
-	for (i = 0; i < NUM_INTS; i++) ohci->hcca->int_table[i] = 0;
-	
-	/* no EDs to remove */
-	ohci->ed_rm_list [0] = NULL;
-	ohci->ed_rm_list [1] = NULL;
-
-	/* empty control and bulk lists */	 
-	ohci->ed_isotail     = NULL;
-	ohci->ed_controltail = NULL;
-	ohci->ed_bulktail    = NULL;
-
-	if ((temp = hc_reset (ohci)) < 0 || (temp = hc_start (ohci)) < 0) {
-		err ("can't restart usb-%s, %d", ohci->ohci_dev->slot_name, temp);
-	} else
-		dbg ("restart usb-%s completed", ohci->ohci_dev->slot_name);
-}
-
-#endif	/* CONFIG_PM */
-
-/*-------------------------------------------------------------------------*/
-
-/* configured so that an OHCI device is always provided */
-/* always called with process context; sleeping is OK */
-
-static int __devinit
-ohci_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
-{
-	unsigned long mem_resource, mem_len;
-	void *mem_base;
-	int status;
-
-	if (pci_enable_device(dev) < 0)
-		return -ENODEV;
-
-        if (!dev->irq) {
-        	err("found OHCI device with no IRQ assigned. check BIOS settings!");
-		pci_disable_device (dev);
-   	        return -ENODEV;
-        }
-	
-	/* we read its hardware registers as memory */
-	mem_resource = pci_resource_start(dev, 0);
-	mem_len = pci_resource_len(dev, 0);
-	if (!request_mem_region (mem_resource, mem_len, ohci_pci_driver.name)) {
-		dbg ("controller already in use");
-		pci_disable_device (dev);
-		return -EBUSY;
-	}
-
-	mem_base = ioremap_nocache (mem_resource, mem_len);
-	if (!mem_base) {
-		err("Error mapping OHCI memory");
-		release_mem_region (mem_resource, mem_len);
-		pci_disable_device (dev);
-		return -EFAULT;
-	}
-
-	/* controller writes into our memory */
-	pci_set_master (dev);
-
-	status = hc_found_ohci (dev, dev->irq, mem_base, id);
-	if (status < 0) {
-		iounmap (mem_base);
-		release_mem_region (mem_resource, mem_len);
-		pci_disable_device (dev);
-	}
-	return status;
-} 
-
-/*-------------------------------------------------------------------------*/
-
-/* may be called from interrupt context [interface spec] */
-/* may be called without controller present */
-/* may be called with controller, bus, and devices active */
-
-static void __devexit
-ohci_pci_remove (struct pci_dev *dev)
-{
-	ohci_t		*ohci = pci_get_drvdata(dev);
-
-	dbg ("remove %s controller usb-%s%s%s",
-		hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS),
-		dev->slot_name,
-		ohci->disabled ? " (disabled)" : "",
-		in_interrupt () ? " in interrupt" : ""
-		);
-#ifdef	DEBUG
-	ohci_dump (ohci, 1);
-#endif
-
-	/* don't wake up sleeping controllers, or block in interrupt context */
-	if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER || in_interrupt ()) {
-		dbg ("controller being disabled");
-		ohci->disabled = 1;
-	}
-
-	/* on return, USB will always be reset (if present) */
-	if (ohci->disabled)
-		writel (ohci->hc_control = OHCI_USB_RESET,
-			&ohci->regs->control);
-
-	hc_release_ohci (ohci);
-
-	release_mem_region (pci_resource_start (dev, 0), pci_resource_len (dev, 0));
-	pci_disable_device (dev);
-}
-
-
-#ifdef	CONFIG_PM
-
-/*-------------------------------------------------------------------------*/
-
-static int
-ohci_pci_suspend (struct pci_dev *dev, u32 state)
-{
-	ohci_t			*ohci = pci_get_drvdata(dev);
-	unsigned long		flags;
-	u16 cmd;
-
-	if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER) {
-		dbg ("can't suspend usb-%s (state is %s)", dev->slot_name,
-			hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS));
-		return -EIO;
-	}
-
-	/* act as if usb suspend can always be used */
-	info ("USB suspend: usb-%s", dev->slot_name);
-	ohci->sleeping = 1;
-
-	/* First stop processing */
-  	spin_lock_irqsave (&usb_ed_lock, flags);
-	ohci->hc_control &= ~(OHCI_CTRL_PLE|OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_IE);
-	writel (ohci->hc_control, &ohci->regs->control);
-	writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
-	(void) readl (&ohci->regs->intrstatus);
-  	spin_unlock_irqrestore (&usb_ed_lock, flags);
-
-	/* Wait a frame or two */
-	mdelay(1);
-	if (!readl (&ohci->regs->intrstatus) & OHCI_INTR_SF)
-		mdelay (1);
-		
-#ifdef CONFIG_PMAC_PBOOK
-	if (_machine == _MACH_Pmac)
-		disable_irq (ohci->irq);
-	/* else, 2.4 assumes shared irqs -- don't disable */
-#endif
-	/* Enable remote wakeup */
-	writel (readl(&ohci->regs->intrenable) | OHCI_INTR_RD, &ohci->regs->intrenable);
-
-	/* Suspend chip and let things settle down a bit */
-	ohci->hc_control = OHCI_USB_SUSPEND;
-	writel (ohci->hc_control, &ohci->regs->control);
-	(void) readl (&ohci->regs->control);
-	mdelay (500); /* No schedule here ! */
-	switch (readl (&ohci->regs->control) & OHCI_CTRL_HCFS) {
-		case OHCI_USB_RESET:
-			dbg("Bus in reset phase ???");
-			break;
-		case OHCI_USB_RESUME:
-			dbg("Bus in resume phase ???");
-			break;
-		case OHCI_USB_OPER:
-			dbg("Bus in operational phase ???");
-			break;
-		case OHCI_USB_SUSPEND:
-			dbg("Bus suspended");
-			break;
-	}
-	/* In some rare situations, Apple's OHCI have happily trashed
-	 * memory during sleep. We disable it's bus master bit during
-	 * suspend
-	 */
-	pci_read_config_word (dev, PCI_COMMAND, &cmd);
-	cmd &= ~PCI_COMMAND_MASTER;
-	pci_write_config_word (dev, PCI_COMMAND, cmd);
-#ifdef CONFIG_PMAC_PBOOK
-	{
-	   	struct device_node	*of_node;
-
-		/* Disable USB PAD & cell clock */
-		of_node = pci_device_to_OF_node (ohci->ohci_dev);
-		if (of_node)
-			pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0);
-	}
-#endif
-	return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-static int
-ohci_pci_resume (struct pci_dev *dev)
-{
-	ohci_t		*ohci = pci_get_drvdata(dev);
-	int		temp;
-	unsigned long	flags;
-
-	/* guard against multiple resumes */
-	atomic_inc (&ohci->resume_count);
-	if (atomic_read (&ohci->resume_count) != 1) {
-		err ("concurrent PCI resumes for usb-%s", dev->slot_name);
-		atomic_dec (&ohci->resume_count);
-		return 0;
-	}
-
-#ifdef CONFIG_PMAC_PBOOK
-	{
-		struct device_node *of_node;
-
-		/* Re-enable USB PAD & cell clock */
-		of_node = pci_device_to_OF_node (ohci->ohci_dev);
-		if (of_node)
-			pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 1);
-	}
-#endif
-
-	/* did we suspend, or were we powered off? */
-	ohci->hc_control = readl (&ohci->regs->control);
-	temp = ohci->hc_control & OHCI_CTRL_HCFS;
-
-#ifdef DEBUG
-	/* the registers may look crazy here */
-	ohci_dump_status (ohci);
-#endif
-
-	/* Re-enable bus mastering */
-	pci_set_master(ohci->ohci_dev);
-	
-	switch (temp) {
-
-	case OHCI_USB_RESET:	// lost power
-		info ("USB restart: usb-%s", dev->slot_name);
-		hc_restart (ohci);
-		break;
-
-	case OHCI_USB_SUSPEND:	// host wakeup
-	case OHCI_USB_RESUME:	// remote wakeup
-		info ("USB continue: usb-%s from %s wakeup", dev->slot_name,
-			(temp == OHCI_USB_SUSPEND)
-				? "host" : "remote");
-		ohci->hc_control = OHCI_USB_RESUME;
-		writel (ohci->hc_control, &ohci->regs->control);
-		(void) readl (&ohci->regs->control);
-		mdelay (20); /* no schedule here ! */
-		/* Some controllers (lucent) need a longer delay here */
-		mdelay (15);
-		temp = readl (&ohci->regs->control);
-		temp = ohci->hc_control & OHCI_CTRL_HCFS;
-		if (temp != OHCI_USB_RESUME) {
-			err ("controller usb-%s won't resume", dev->slot_name);
-			ohci->disabled = 1;
-			return -EIO;
-		}
-
-		/* Some chips likes being resumed first */
-		writel (OHCI_USB_OPER, &ohci->regs->control);
-		(void) readl (&ohci->regs->control);
-		mdelay (3);
-
-		/* Then re-enable operations */
-		spin_lock_irqsave (&usb_ed_lock, flags);
-		ohci->disabled = 0;
-		ohci->sleeping = 0;
-		ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
-		if (!ohci->ed_rm_list[0] && !ohci->ed_rm_list[1]) {
-			if (ohci->ed_controltail)
-				ohci->hc_control |= OHCI_CTRL_CLE;
-			if (ohci->ed_bulktail)
-				ohci->hc_control |= OHCI_CTRL_BLE;
-		}
-		writel (ohci->hc_control, &ohci->regs->control);
-		writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
-		writel (OHCI_INTR_SF, &ohci->regs->intrenable);
-		/* Check for a pending done list */
-		writel (OHCI_INTR_WDH, &ohci->regs->intrdisable);	
-		(void) readl (&ohci->regs->intrdisable);
-		spin_unlock_irqrestore (&usb_ed_lock, flags);
-#ifdef CONFIG_PMAC_PBOOK
-		if (_machine == _MACH_Pmac)
-			enable_irq (ohci->irq);
-#endif
-		if (ohci->hcca->done_head)
-			dl_done_list (ohci, dl_reverse_done_list (ohci));
-		writel (OHCI_INTR_WDH, &ohci->regs->intrenable); 
-		writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
-		writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
-		break;
-
-	default:
-		warn ("odd PCI resume for usb-%s", dev->slot_name);
-	}
-
-	/* controller is operational, extra resumes are harmless */
-	atomic_dec (&ohci->resume_count);
-
-	return 0;
-}
-
-#endif	/* CONFIG_PM */
-
-
-/*-------------------------------------------------------------------------*/
-
-static const struct pci_device_id __devinitdata ohci_pci_ids [] = { {
-
-	/*
-	 * AMD-756 [Viper] USB has a serious erratum when used with
-	 * lowspeed devices like mice.
-	 */
-	vendor:		0x1022,
-	device:		0x740c,
-	subvendor:	PCI_ANY_ID,
-	subdevice:	PCI_ANY_ID,
-
-	driver_data:	OHCI_QUIRK_AMD756,
-
-} , {
-
-	/* handle any USB OHCI controller */
-	class: 		((PCI_CLASS_SERIAL_USB << 8) | 0x10),
-	class_mask: 	~0,
-
-	/* no matter who makes it */
-	vendor:		PCI_ANY_ID,
-	device:		PCI_ANY_ID,
-	subvendor:	PCI_ANY_ID,
-	subdevice:	PCI_ANY_ID,
-
-	}, { /* end: all zeroes */ }
-};
-
-MODULE_DEVICE_TABLE (pci, ohci_pci_ids);
-
-static struct pci_driver ohci_pci_driver = {
-	name:		"usb-ohci",
-	id_table:	&ohci_pci_ids [0],
-
-	probe:		ohci_pci_probe,
-	remove:		__devexit_p(ohci_pci_remove),
-
-#ifdef	CONFIG_PM
-	suspend:	ohci_pci_suspend,
-	resume:		ohci_pci_resume,
-#endif	/* PM */
-};
-
- 
-/*-------------------------------------------------------------------------*/
-
-static int __init ohci_hcd_init (void) 
-{
-	return pci_module_init (&ohci_pci_driver);
-}
-
-/*-------------------------------------------------------------------------*/
-
-static void __exit ohci_hcd_cleanup (void) 
-{	
-	pci_unregister_driver (&ohci_pci_driver);
-}
-
-module_init (ohci_hcd_init);
-module_exit (ohci_hcd_cleanup);
-
-
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
-MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/usb-ohci.h linux-2.4.21-pre6/drivers/usb/usb-ohci.h
--- linux-2.4.20/drivers/usb/usb-ohci.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/usb-ohci.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,644 +0,0 @@
-/*
- * URB OHCI HCD (Host Controller Driver) for USB.
- * 
- * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
- * 
- * usb-ohci.h
- */
-
- 
-static int cc_to_error[16] = { 
-
-/* mapping of the OHCI CC status to error codes */ 
-	/* No  Error  */               USB_ST_NOERROR,
-	/* CRC Error  */               USB_ST_CRC,
-	/* Bit Stuff  */               USB_ST_BITSTUFF,
-	/* Data Togg  */               USB_ST_CRC,
-	/* Stall      */               USB_ST_STALL,
-	/* DevNotResp */               USB_ST_NORESPONSE,
-	/* PIDCheck   */               USB_ST_BITSTUFF,
-	/* UnExpPID   */               USB_ST_BITSTUFF,
-	/* DataOver   */               USB_ST_DATAOVERRUN,
-	/* DataUnder  */               USB_ST_DATAUNDERRUN,
-	/* reservd    */               USB_ST_NORESPONSE,
-	/* reservd    */               USB_ST_NORESPONSE,
-	/* BufferOver */               USB_ST_BUFFEROVERRUN,
-	/* BuffUnder  */               USB_ST_BUFFERUNDERRUN,
-	/* Not Access */               USB_ST_NORESPONSE,
-	/* Not Access */               USB_ST_NORESPONSE 
-};
-
-#include <linux/config.h>
-
-/* ED States */
-
-#define ED_NEW 		0x00
-#define ED_UNLINK 	0x01
-#define ED_OPER		0x02
-#define ED_DEL		0x04
-#define ED_URB_DEL  	0x08
-
-/* usb_ohci_ed */
-struct ed {
-	__u32 hwINFO;       
-	__u32 hwTailP;
-	__u32 hwHeadP;
-	__u32 hwNextED;
-
-	struct ed * ed_prev;  
-	__u8 int_period;
-	__u8 int_branch;
-	__u8 int_load; 
-	__u8 int_interval;
-	__u8 state;
-	__u8 type; 
-	__u16 last_iso;
-	struct ed * ed_rm_list;
-
-	dma_addr_t dma;
-	__u32 unused[3];
-} __attribute((aligned(16)));
-typedef struct ed ed_t;
-
- 
-/* TD info field */
-#define TD_CC       0xf0000000
-#define TD_CC_GET(td_p) ((td_p >>28) & 0x0f)
-#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28)
-#define TD_EC       0x0C000000
-#define TD_T        0x03000000
-#define TD_T_DATA0  0x02000000
-#define TD_T_DATA1  0x03000000
-#define TD_T_TOGGLE 0x00000000
-#define TD_R        0x00040000
-#define TD_DI       0x00E00000
-#define TD_DI_SET(X) (((X) & 0x07)<< 21)
-#define TD_DP       0x00180000
-#define TD_DP_SETUP 0x00000000
-#define TD_DP_IN    0x00100000
-#define TD_DP_OUT   0x00080000
-
-#define TD_ISO	    0x00010000
-#define TD_DEL      0x00020000
-
-/* CC Codes */
-#define TD_CC_NOERROR      0x00
-#define TD_CC_CRC          0x01
-#define TD_CC_BITSTUFFING  0x02
-#define TD_CC_DATATOGGLEM  0x03
-#define TD_CC_STALL        0x04
-#define TD_DEVNOTRESP      0x05
-#define TD_PIDCHECKFAIL    0x06
-#define TD_UNEXPECTEDPID   0x07
-#define TD_DATAOVERRUN     0x08
-#define TD_DATAUNDERRUN    0x09
-#define TD_BUFFEROVERRUN   0x0C
-#define TD_BUFFERUNDERRUN  0x0D
-#define TD_NOTACCESSED     0x0F
-
-
-#define MAXPSW 1
-
-struct td {
-	__u32 hwINFO;
-  	__u32 hwCBP;		/* Current Buffer Pointer */
-  	__u32 hwNextTD;		/* Next TD Pointer */
-  	__u32 hwBE;		/* Memory Buffer End Pointer */
-
-  	__u16 hwPSW[MAXPSW];
-  	__u8 unused;
-  	__u8 index;
-  	struct ed * ed;
-  	struct td * next_dl_td;
-  	struct urb * urb;
-
-	dma_addr_t td_dma;
-	dma_addr_t data_dma;
-	__u32 unused2[2];
-} __attribute((aligned(32)));	/* normally 16, iso needs 32 */
-typedef struct td td_t;
-
-#define OHCI_ED_SKIP	(1 << 14)
-
-/*
- * The HCCA (Host Controller Communications Area) is a 256 byte
- * structure defined in the OHCI spec. that the host controller is
- * told the base address of.  It must be 256-byte aligned.
- */
- 
-#define NUM_INTS 32	/* part of the OHCI standard */
-struct ohci_hcca {
-	__u32	int_table[NUM_INTS];	/* Interrupt ED table */
-	__u16	frame_no;		/* current frame number */
-	__u16	pad1;			/* set to 0 on each frame_no change */
-	__u32	done_head;		/* info returned for an interrupt */
-	u8		reserved_for_hc[116];
-} __attribute((aligned(256)));
-
-  
-/*
- * Maximum number of root hub ports.  
- */
-#define MAX_ROOT_PORTS	15	/* maximum OHCI root hub ports */
-
-/*
- * This is the structure of the OHCI controller's memory mapped I/O
- * region.  This is Memory Mapped I/O.  You must use the readl() and
- * writel() macros defined in asm/io.h to access these!!
- */
-struct ohci_regs {
-	/* control and status registers */
-	__u32	revision;
-	__u32	control;
-	__u32	cmdstatus;
-	__u32	intrstatus;
-	__u32	intrenable;
-	__u32	intrdisable;
-	/* memory pointers */
-	__u32	hcca;
-	__u32	ed_periodcurrent;
-	__u32	ed_controlhead;
-	__u32	ed_controlcurrent;
-	__u32	ed_bulkhead;
-	__u32	ed_bulkcurrent;
-	__u32	donehead;
-	/* frame counters */
-	__u32	fminterval;
-	__u32	fmremaining;
-	__u32	fmnumber;
-	__u32	periodicstart;
-	__u32	lsthresh;
-	/* Root hub ports */
-	struct	ohci_roothub_regs {
-		__u32	a;
-		__u32	b;
-		__u32	status;
-		__u32	portstatus[MAX_ROOT_PORTS];
-	} roothub;
-} __attribute((aligned(32)));
-
-
-/* OHCI CONTROL AND STATUS REGISTER MASKS */
-
-/*
- * HcControl (control) register masks
- */
-#define OHCI_CTRL_CBSR	(3 << 0)	/* control/bulk service ratio */
-#define OHCI_CTRL_PLE	(1 << 2)	/* periodic list enable */
-#define OHCI_CTRL_IE	(1 << 3)	/* isochronous enable */
-#define OHCI_CTRL_CLE	(1 << 4)	/* control list enable */
-#define OHCI_CTRL_BLE	(1 << 5)	/* bulk list enable */
-#define OHCI_CTRL_HCFS	(3 << 6)	/* host controller functional state */
-#define OHCI_CTRL_IR	(1 << 8)	/* interrupt routing */
-#define OHCI_CTRL_RWC	(1 << 9)	/* remote wakeup connected */
-#define OHCI_CTRL_RWE	(1 << 10)	/* remote wakeup enable */
-
-/* pre-shifted values for HCFS */
-#	define OHCI_USB_RESET	(0 << 6)
-#	define OHCI_USB_RESUME	(1 << 6)
-#	define OHCI_USB_OPER	(2 << 6)
-#	define OHCI_USB_SUSPEND	(3 << 6)
-
-/*
- * HcCommandStatus (cmdstatus) register masks
- */
-#define OHCI_HCR	(1 << 0)	/* host controller reset */
-#define OHCI_CLF  	(1 << 1)	/* control list filled */
-#define OHCI_BLF  	(1 << 2)	/* bulk list filled */
-#define OHCI_OCR  	(1 << 3)	/* ownership change request */
-#define OHCI_SOC  	(3 << 16)	/* scheduling overrun count */
-
-/*
- * masks used with interrupt registers:
- * HcInterruptStatus (intrstatus)
- * HcInterruptEnable (intrenable)
- * HcInterruptDisable (intrdisable)
- */
-#define OHCI_INTR_SO	(1 << 0)	/* scheduling overrun */
-#define OHCI_INTR_WDH	(1 << 1)	/* writeback of done_head */
-#define OHCI_INTR_SF	(1 << 2)	/* start frame */
-#define OHCI_INTR_RD	(1 << 3)	/* resume detect */
-#define OHCI_INTR_UE	(1 << 4)	/* unrecoverable error */
-#define OHCI_INTR_FNO	(1 << 5)	/* frame number overflow */
-#define OHCI_INTR_RHSC	(1 << 6)	/* root hub status change */
-#define OHCI_INTR_OC	(1 << 30)	/* ownership change */
-#define OHCI_INTR_MIE	(1 << 31)	/* master interrupt enable */
-
-
-
-/* Virtual Root HUB */
-struct virt_root_hub {
-	int devnum; /* Address of Root Hub endpoint */ 
-	void * urb;
-	void * int_addr;
-	int send;
-	int interval;
-	struct timer_list rh_int_timer;
-};
-
-
-/* USB HUB CONSTANTS (not OHCI-specific; see hub.h) */
- 
-/* destination of request */
-#define RH_INTERFACE               0x01
-#define RH_ENDPOINT                0x02
-#define RH_OTHER                   0x03
-
-#define RH_CLASS                   0x20
-#define RH_VENDOR                  0x40
-
-/* Requests: bRequest << 8 | bmRequestType */
-#define RH_GET_STATUS           0x0080
-#define RH_CLEAR_FEATURE        0x0100
-#define RH_SET_FEATURE          0x0300
-#define RH_SET_ADDRESS		0x0500
-#define RH_GET_DESCRIPTOR	0x0680
-#define RH_SET_DESCRIPTOR       0x0700
-#define RH_GET_CONFIGURATION	0x0880
-#define RH_SET_CONFIGURATION	0x0900
-#define RH_GET_STATE            0x0280
-#define RH_GET_INTERFACE        0x0A80
-#define RH_SET_INTERFACE        0x0B00
-#define RH_SYNC_FRAME           0x0C80
-/* Our Vendor Specific Request */
-#define RH_SET_EP               0x2000
-
-
-/* Hub port features */
-#define RH_PORT_CONNECTION         0x00
-#define RH_PORT_ENABLE             0x01
-#define RH_PORT_SUSPEND            0x02
-#define RH_PORT_OVER_CURRENT       0x03
-#define RH_PORT_RESET              0x04
-#define RH_PORT_POWER              0x08
-#define RH_PORT_LOW_SPEED          0x09
-
-#define RH_C_PORT_CONNECTION       0x10
-#define RH_C_PORT_ENABLE           0x11
-#define RH_C_PORT_SUSPEND          0x12
-#define RH_C_PORT_OVER_CURRENT     0x13
-#define RH_C_PORT_RESET            0x14  
-
-/* Hub features */
-#define RH_C_HUB_LOCAL_POWER       0x00
-#define RH_C_HUB_OVER_CURRENT      0x01
-
-#define RH_DEVICE_REMOTE_WAKEUP    0x00
-#define RH_ENDPOINT_STALL          0x01
-
-#define RH_ACK                     0x01
-#define RH_REQ_ERR                 -1
-#define RH_NACK                    0x00
-
-
-/* OHCI ROOT HUB REGISTER MASKS */
- 
-/* roothub.portstatus [i] bits */
-#define RH_PS_CCS            0x00000001   	/* current connect status */
-#define RH_PS_PES            0x00000002   	/* port enable status*/
-#define RH_PS_PSS            0x00000004   	/* port suspend status */
-#define RH_PS_POCI           0x00000008   	/* port over current indicator */
-#define RH_PS_PRS            0x00000010  	/* port reset status */
-#define RH_PS_PPS            0x00000100   	/* port power status */
-#define RH_PS_LSDA           0x00000200    	/* low speed device attached */
-#define RH_PS_CSC            0x00010000 	/* connect status change */
-#define RH_PS_PESC           0x00020000   	/* port enable status change */
-#define RH_PS_PSSC           0x00040000    	/* port suspend status change */
-#define RH_PS_OCIC           0x00080000    	/* over current indicator change */
-#define RH_PS_PRSC           0x00100000   	/* port reset status change */
-
-/* roothub.status bits */
-#define RH_HS_LPS	     0x00000001		/* local power status */
-#define RH_HS_OCI	     0x00000002		/* over current indicator */
-#define RH_HS_DRWE	     0x00008000		/* device remote wakeup enable */
-#define RH_HS_LPSC	     0x00010000		/* local power status change */
-#define RH_HS_OCIC	     0x00020000		/* over current indicator change */
-#define RH_HS_CRWE	     0x80000000		/* clear remote wakeup enable */
-
-/* roothub.b masks */
-#define RH_B_DR		0x0000ffff		/* device removable flags */
-#define RH_B_PPCM	0xffff0000		/* port power control mask */
-
-/* roothub.a masks */
-#define	RH_A_NDP	(0xff << 0)		/* number of downstream ports */
-#define	RH_A_PSM	(1 << 8)		/* power switching mode */
-#define	RH_A_NPS	(1 << 9)		/* no power switching */
-#define	RH_A_DT		(1 << 10)		/* device type (mbz) */
-#define	RH_A_OCPM	(1 << 11)		/* over current protection mode */
-#define	RH_A_NOCP	(1 << 12)		/* no over current protection */
-#define	RH_A_POTPGT	(0xff << 24)		/* power on to power good time */
-
-/* urb */
-typedef struct 
-{
-	ed_t * ed;
-	__u16 length;	// number of tds associated with this request
-	__u16 td_cnt;	// number of tds already serviced
-	int   state;
-	wait_queue_head_t * wait;
-	td_t * td[0];	// list pointer to all corresponding TDs associated with this request
-
-} urb_priv_t;
-#define URB_DEL 1
-
-
-/* Hash struct used for TD/ED hashing */
-struct hash_t {
-	void		*virt;
-	dma_addr_t	dma;
-	struct hash_t	*next; // chaining for collision cases
-};
-
-/* List of TD/ED hash entries */
-struct hash_list_t {
-	struct hash_t	*head;
-	struct hash_t	*tail;
-};
-
-#define TD_HASH_SIZE    64    /* power'o'two */
-#define ED_HASH_SIZE    64    /* power'o'two */
-
-#define TD_HASH_FUNC(td_dma) ((td_dma ^ (td_dma >> 5)) % TD_HASH_SIZE)
-#define ED_HASH_FUNC(ed_dma) ((ed_dma ^ (ed_dma >> 5)) % ED_HASH_SIZE)
-
-
-/*
- * This is the full ohci controller description
- *
- * Note how the "proper" USB information is just
- * a subset of what the full implementation needs. (Linus)
- */
-
-
-typedef struct ohci {
-	struct ohci_hcca *hcca;		/* hcca */
-	dma_addr_t hcca_dma;
-
-	int irq;
-	int disabled;			/* e.g. got a UE, we're hung */
-	int sleeping;
-	atomic_t resume_count;		/* defending against multiple resumes */
-	unsigned long flags;		/* for HC bugs */
-#define	OHCI_QUIRK_AMD756	0x01		/* erratum #4 */
-#define OHCI_QUIRK_SUCKYIO	0x02		/* NSC superio */
-
-	struct ohci_regs * regs;	/* OHCI controller's memory */
-	struct list_head ohci_hcd_list;	/* list of all ohci_hcd */
-
-	struct ohci * next; 		// chain of ohci device contexts
-	struct list_head timeout_list;
-	// struct list_head urb_list; 	// list of all pending urbs
-	// spinlock_t urb_list_lock; 	// lock to keep consistency 
-  
-	int ohci_int_load[32];		/* load of the 32 Interrupt Chains (for load balancing)*/
-	ed_t * ed_rm_list[2];     /* lists of all endpoints to be removed */
-	ed_t * ed_bulktail;       /* last endpoint of bulk list */
-	ed_t * ed_controltail;    /* last endpoint of control list */
- 	ed_t * ed_isotail;        /* last endpoint of iso list */
-	int intrstatus;
-	__u32 hc_control;		/* copy of the hc control reg */
-	struct usb_bus * bus;    
-	struct usb_device * dev[128];
-	struct virt_root_hub rh;
-
-	/* PCI device handle, settings, ... */
-	struct pci_dev	*ohci_dev;
-	u8		pci_latency;
-	struct pci_pool	*td_cache;
-	struct pci_pool	*dev_cache;
-	struct hash_list_t	td_hash[TD_HASH_SIZE];
-	struct hash_list_t	ed_hash[ED_HASH_SIZE];
-
-} ohci_t;
-
-#define NUM_EDS 32		/* num of preallocated endpoint descriptors */
-
-struct ohci_device {
-	ed_t 	ed[NUM_EDS];
-	dma_addr_t dma;
-	int ed_cnt;
-	wait_queue_head_t * wait;
-};
-
-// #define ohci_to_usb(ohci)	((ohci)->usb)
-#define usb_to_ohci(usb)	((struct ohci_device *)(usb)->hcpriv)
-
-/* hcd */
-/* endpoint */
-static int ep_link(ohci_t * ohci, ed_t * ed);
-static int ep_unlink(ohci_t * ohci, ed_t * ed);
-static ed_t * ep_add_ed(struct usb_device * usb_dev, unsigned int pipe, int interval, int load, int mem_flags);
-static void ep_rm_ed(struct usb_device * usb_dev, ed_t * ed);
-/* td */
-static void td_fill(ohci_t * ohci, unsigned int info, dma_addr_t data, int len, struct urb * urb, int index);
-static void td_submit_urb(struct urb * urb);
-/* root hub */
-static int rh_submit_urb(struct urb * urb);
-static int rh_unlink_urb(struct urb * urb);
-static int rh_init_int_timer(struct urb * urb);
-
-/*-------------------------------------------------------------------------*/
-
-#define ALLOC_FLAGS (in_interrupt () || current->state != TASK_RUNNING ? GFP_ATOMIC : GFP_KERNEL)
-
-#ifdef DEBUG
-#	define OHCI_MEM_FLAGS	SLAB_POISON
-#else
-#	define OHCI_MEM_FLAGS	0
-#endif
- 
-#ifndef CONFIG_PCI
-#	error "usb-ohci currently requires PCI-based controllers"
-	/* to support non-PCI OHCIs, you need custom bus/mem/... glue */
-#endif
-
-
-/* Recover a TD/ED using its collision chain */
-static inline void *
-dma_to_ed_td (struct hash_list_t * entry, dma_addr_t dma)
-{
-	struct hash_t * scan = entry->head;
-	while (scan && scan->dma != dma)
-		scan = scan->next;
-	if (!scan)
-		BUG();
-	return scan->virt;
-}
-
-static inline struct ed *
-dma_to_ed (struct ohci * hc, dma_addr_t ed_dma)
-{
-	return (struct ed *) dma_to_ed_td(&(hc->ed_hash[ED_HASH_FUNC(ed_dma)]),
-				      ed_dma);
-}
-
-static inline struct td *
-dma_to_td (struct ohci * hc, dma_addr_t td_dma)
-{
-	return (struct td *) dma_to_ed_td(&(hc->td_hash[TD_HASH_FUNC(td_dma)]),
-				      td_dma);
-}
-
-/* Add a hash entry for a TD/ED; return true on success */
-static inline int
-hash_add_ed_td(struct hash_list_t * entry, void * virt, dma_addr_t dma)
-{
-	struct hash_t * scan;
-	
-	scan = (struct hash_t *)kmalloc(sizeof(struct hash_t), ALLOC_FLAGS);
-	if (!scan)
-		return 0;
-	
-	if (!entry->tail) {
-		entry->head = entry->tail = scan;
-	} else {
-		entry->tail->next = scan;
-		entry->tail = scan;
-	}
-	
-	scan->virt = virt;
-	scan->dma = dma;
-	scan->next = NULL;
-	return 1;
-}
-
-static inline int
-hash_add_ed (struct ohci * hc, struct ed * ed)
-{
-	return hash_add_ed_td (&(hc->ed_hash[ED_HASH_FUNC(ed->dma)]),
-			ed, ed->dma);
-}
-
-static inline int
-hash_add_td (struct ohci * hc, struct td * td)
-{
-	return hash_add_ed_td (&(hc->td_hash[TD_HASH_FUNC(td->td_dma)]),
-			td, td->td_dma);
-}
-
-
-static inline void
-hash_free_ed_td (struct hash_list_t * entry, void * virt)
-{
-	struct hash_t *scan, *prev;
-	scan = prev = entry->head;
-
-	// Find and unlink hash entry
-	while (scan && scan->virt != virt) {
-		prev = scan;
-		scan = scan->next;
-	}
-	if (scan) {
-		if (scan == entry->head) {
-			if (entry->head == entry->tail)
-				entry->head = entry->tail = NULL;
-			else
-				entry->head = scan->next;
-		} else if (scan == entry->tail) {
-			entry->tail = prev;
-			prev->next = NULL;
-		} else
-			prev->next = scan->next;
-		kfree(scan);
-	}
-}
-
-static inline void
-hash_free_ed (struct ohci * hc, struct ed * ed)
-{
-	hash_free_ed_td (&(hc->ed_hash[ED_HASH_FUNC(ed->dma)]), ed);
-}
-
-static inline void
-hash_free_td (struct ohci * hc, struct td * td)
-{
-	hash_free_ed_td (&(hc->td_hash[TD_HASH_FUNC(td->td_dma)]), td);
-}
-
-
-static int ohci_mem_init (struct ohci *ohci)
-{
-	ohci->td_cache = pci_pool_create ("ohci_td", ohci->ohci_dev,
-		sizeof (struct td),
-		32 /* byte alignment */,
-		0 /* no page-crossing issues */,
-		GFP_KERNEL | OHCI_MEM_FLAGS);
-	if (!ohci->td_cache)
-		return -ENOMEM;
-	ohci->dev_cache = pci_pool_create ("ohci_dev", ohci->ohci_dev,
-		sizeof (struct ohci_device),
-		16 /* byte alignment */,
-		0 /* no page-crossing issues */,
-		GFP_KERNEL | OHCI_MEM_FLAGS);
-	if (!ohci->dev_cache)
-		return -ENOMEM;
-	return 0;
-}
-
-static void ohci_mem_cleanup (struct ohci *ohci)
-{
-	if (ohci->td_cache) {
-		pci_pool_destroy (ohci->td_cache);
-		ohci->td_cache = 0;
-	}
-	if (ohci->dev_cache) {
-		pci_pool_destroy (ohci->dev_cache);
-		ohci->dev_cache = 0;
-	}
-}
-
-/* TDs ... */
-static inline struct td *
-td_alloc (struct ohci *hc, int mem_flags)
-{
-	dma_addr_t	dma;
-	struct td	*td;
-
-	td = pci_pool_alloc (hc->td_cache, mem_flags, &dma);
-	if (td) {
-		td->td_dma = dma;
-
-		/* hash it for later reverse mapping */
-		if (!hash_add_td (hc, td)) {
-			pci_pool_free (hc->td_cache, td, dma);
-			return NULL;
-		}
-	}
-	return td;
-}
-
-static inline void
-td_free (struct ohci *hc, struct td *td)
-{
-	hash_free_td (hc, td);
-	pci_pool_free (hc->td_cache, td, td->td_dma);
-}
-
-
-/* DEV + EDs ... only the EDs need to be consistent */
-static inline struct ohci_device *
-dev_alloc (struct ohci *hc, int mem_flags)
-{
-	dma_addr_t		dma;
-	struct ohci_device	*dev;
-	int			i, offset;
-
-	dev = pci_pool_alloc (hc->dev_cache, mem_flags, &dma);
-	if (dev) {
-		memset (dev, 0, sizeof (*dev));
-		dev->dma = dma;
-		offset = ((char *)&dev->ed) - ((char *)dev);
-		for (i = 0; i < NUM_EDS; i++, offset += sizeof dev->ed [0])
-			dev->ed [i].dma = dma + offset;
-		/* add to hashtable if used */
-	}
-	return dev;
-}
-
-static inline void
-dev_free (struct ohci *hc, struct ohci_device *dev)
-{
-	pci_pool_free (hc->dev_cache, dev, dev->dma);
-}
-
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/usb-skeleton.c linux-2.4.21-pre6/drivers/usb/usb-skeleton.c
--- linux-2.4.20/drivers/usb/usb-skeleton.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/usb-skeleton.c	2003-03-26 23:49:35.000000000 +0000
@@ -87,7 +87,7 @@
 
 
 /* Get a minor range for your devices from the usb maintainer */
-#define USB_SKEL_MINOR_BASE	200	
+#define USB_SKEL_MINOR_BASE	192	
 
 /* we can have up to this number of device plugged in at once */
 #define MAX_DEVICES		16
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/usb-uhci-debug.h linux-2.4.21-pre6/drivers/usb/usb-uhci-debug.h
--- linux-2.4.20/drivers/usb/usb-uhci-debug.h	2001-10-30 23:08:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/usb-uhci-debug.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,195 +0,0 @@
-#ifdef DEBUG
-static void __attribute__((__unused__)) uhci_show_qh (puhci_desc_t qh)
-{
-	if (qh->type != QH_TYPE) {
-		dbg("qh has not QH_TYPE");
-		return;
-	}
-	dbg("QH @ %p/%08llX:", qh, (unsigned long long)qh->dma_addr);
-
-	if (qh->hw.qh.head & UHCI_PTR_TERM)
-		dbg("    Head Terminate");
-	else 
-		dbg("    Head: %s @ %08X",
-		    (qh->hw.qh.head & UHCI_PTR_QH?"QH":"TD"),
-		    qh->hw.qh.head & ~UHCI_PTR_BITS);
-
-	if (qh->hw.qh.element & UHCI_PTR_TERM)
-		dbg("    Element Terminate");
-	else 
-		dbg("    Element: %s @ %08X",
-		    (qh->hw.qh.element & UHCI_PTR_QH?"QH":"TD"),
-		    qh->hw.qh.element & ~UHCI_PTR_BITS);
-}
-#endif
-
-#if 0
-static void uhci_show_td (puhci_desc_t td)
-{
-	char *spid;
-	
-	switch (td->hw.td.info & 0xff) {
-	case USB_PID_SETUP:
-		spid = "SETUP";
-		break;
-	case USB_PID_OUT:
-		spid = " OUT ";
-		break;
-	case USB_PID_IN:
-		spid = " IN  ";
-		break;
-	default:
-		spid = "  ?  ";
-		break;
-	}
-
-	warn("  TD @ %p/%08X, MaxLen=%02x DT%d EP=%x Dev=%x PID=(%s) buf=%08x",
-	     td, td->dma_addr,
-	     td->hw.td.info >> 21,
-	     ((td->hw.td.info >> 19) & 1),
-	     (td->hw.td.info >> 15) & 15,
-	     (td->hw.td.info >> 8) & 127,
-	     spid,
-	     td->hw.td.buffer);
-
-	warn("    Len=%02x e%d %s%s%s%s%s%s%s%s%s%s",
-	     td->hw.td.status & 0x7ff,
-	     ((td->hw.td.status >> 27) & 3),
-	     (td->hw.td.status & TD_CTRL_SPD) ? "SPD " : "",
-	     (td->hw.td.status & TD_CTRL_LS) ? "LS " : "",
-	     (td->hw.td.status & TD_CTRL_IOC) ? "IOC " : "",
-	     (td->hw.td.status & TD_CTRL_ACTIVE) ? "Active " : "",
-	     (td->hw.td.status & TD_CTRL_STALLED) ? "Stalled " : "",
-	     (td->hw.td.status & TD_CTRL_DBUFERR) ? "DataBufErr " : "",
-	     (td->hw.td.status & TD_CTRL_BABBLE) ? "Babble " : "",
-	     (td->hw.td.status & TD_CTRL_NAK) ? "NAK " : "",
-	     (td->hw.td.status & TD_CTRL_CRCTIMEO) ? "CRC/Timeo " : "",
-	     (td->hw.td.status & TD_CTRL_BITSTUFF) ? "BitStuff " : ""
-		);
-
-	if (td->hw.td.link & UHCI_PTR_TERM)
-		warn("   TD Link Terminate");
-	else 
-		warn("    Link points to %s @ %08x, %s",
-		     (td->hw.td.link & UHCI_PTR_QH?"QH":"TD"),
-		     td->hw.td.link & ~UHCI_PTR_BITS,
-		     (td->hw.td.link & UHCI_PTR_DEPTH ? "Depth first" : "Breadth first"));
-}
-#endif
-
-#ifdef DEBUG
-static void __attribute__((__unused__)) uhci_show_td_queue (puhci_desc_t td)
-{
-	//dbg("uhci_show_td_queue %p (%08lX):", td, td->dma_addr);
-#if 1
-	return;
-#else
-	while (1) {
-		uhci_show_td (td);
-		if (td->hw.td.link & UHCI_PTR_TERM)
-			break;
-		if (td != bus_to_virt (td->hw.td.link & ~UHCI_PTR_BITS))
-			td = bus_to_virt (td->hw.td.link & ~UHCI_PTR_BITS);
-		else {
-			dbg("td points to itself!");
-			break;
-		}
-	}
-#endif
-}
-
-static void __attribute__((__unused__)) uhci_show_queue (puhci_desc_t qh)
-{
-#if 0
-	uhci_desc_t *start_qh=qh;
-#endif
-
-	dbg("uhci_show_queue %p:", qh);
-#if 1
-	return;
-#else
-	while (1) {
-		uhci_show_qh (qh);
-
-		if (!(qh->hw.qh.element & UHCI_PTR_TERM))
-			uhci_show_td_queue (bus_to_virt (qh->hw.qh.element & ~UHCI_PTR_BITS));
-
-		if (qh->hw.qh.head & UHCI_PTR_TERM)
-			break;
-
-		if (qh != bus_to_virt (qh->hw.qh.head & ~UHCI_PTR_BITS))
-			qh = bus_to_virt (qh->hw.qh.head & ~UHCI_PTR_BITS);
-		else {
-			dbg("qh points to itself!");
-			break;
-		}
-		
-		if (qh==start_qh) { // avoid loop
-			dbg("Loop detect");
-			break;
-		}
-	}		
-#endif
-}
-
-static void __attribute__((__unused__)) uhci_show_sc (int port, unsigned short status)
-{
-	dbg("  stat%d     =     %04x   %s%s%s%s%s%s%s%s",
-	     port,
-	     status,
-	     (status & USBPORTSC_SUSP) ? "PortSuspend " : "",
-	     (status & USBPORTSC_PR) ? "PortReset " : "",
-	     (status & USBPORTSC_LSDA) ? "LowSpeed " : "",
-	     (status & USBPORTSC_RD) ? "ResumeDetect " : "",
-	     (status & USBPORTSC_PEC) ? "EnableChange " : "",
-	     (status & USBPORTSC_PE) ? "PortEnabled " : "",
-	     (status & USBPORTSC_CSC) ? "ConnectChange " : "",
-	     (status & USBPORTSC_CCS) ? "PortConnected " : "");
-}
-
-void uhci_show_status (puhci_t s)
-{
-	unsigned int io_addr = s->io_addr;
-	unsigned short usbcmd, usbstat, usbint, usbfrnum;
-	unsigned int flbaseadd;
-	unsigned char sof;
-	unsigned short portsc1, portsc2;
-
-	usbcmd = inw (io_addr + 0);
-	usbstat = inw (io_addr + 2);
-	usbint = inw (io_addr + 4);
-	usbfrnum = inw (io_addr + 6);
-	flbaseadd = inl (io_addr + 8);
-	sof = inb (io_addr + 12);
-	portsc1 = inw (io_addr + 16);
-	portsc2 = inw (io_addr + 18);
-
-	dbg("  usbcmd    =     %04x   %s%s%s%s%s%s%s%s",
-	     usbcmd,
-	     (usbcmd & USBCMD_MAXP) ? "Maxp64 " : "Maxp32 ",
-	     (usbcmd & USBCMD_CF) ? "CF " : "",
-	     (usbcmd & USBCMD_SWDBG) ? "SWDBG " : "",
-	     (usbcmd & USBCMD_FGR) ? "FGR " : "",
-	     (usbcmd & USBCMD_EGSM) ? "EGSM " : "",
-	     (usbcmd & USBCMD_GRESET) ? "GRESET " : "",
-	     (usbcmd & USBCMD_HCRESET) ? "HCRESET " : "",
-	     (usbcmd & USBCMD_RS) ? "RS " : "");
-
-	dbg("  usbstat   =     %04x   %s%s%s%s%s%s",
-	     usbstat,
-	     (usbstat & USBSTS_HCH) ? "HCHalted " : "",
-	     (usbstat & USBSTS_HCPE) ? "HostControllerProcessError " : "",
-	     (usbstat & USBSTS_HSE) ? "HostSystemError " : "",
-	     (usbstat & USBSTS_RD) ? "ResumeDetect " : "",
-	     (usbstat & USBSTS_ERROR) ? "USBError " : "",
-	     (usbstat & USBSTS_USBINT) ? "USBINT " : "");
-
-	dbg("  usbint    =     %04x", usbint);
-	dbg("  usbfrnum  =   (%d)%03x", (usbfrnum >> 10) & 1,
-	     0xfff & (4 * (unsigned int) usbfrnum));
-	dbg("  flbaseadd = %08x", flbaseadd);
-	dbg("  sof       =       %02x", sof);
-	uhci_show_sc (1, portsc1);
-	uhci_show_sc (2, portsc2);
-}
-#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/usb-uhci.c linux-2.4.21-pre6/drivers/usb/usb-uhci.c
--- linux-2.4.20/drivers/usb/usb-uhci.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/usb-uhci.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,3142 +0,0 @@
-/* 
- * Universal Host Controller Interface driver for USB (take II).
- *
- * (c) 1999-2001 Georg Acher, acher@in.tum.de (executive slave) (base guitar)
- *               Deti Fliegl, deti@fliegl.de (executive slave) (lead voice)
- *               Thomas Sailer, sailer@ife.ee.ethz.ch (chief consultant) (cheer leader)
- *               Roman Weissgaerber, weissg@vienna.at (virt root hub) (studio porter)
- * (c) 2000      Yggdrasil Computing, Inc. (port of new PCI interface support
- *               from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
- * (C) 2000      David Brownell, david-b@pacbell.net (usb-ohci.c)
- *          
- * HW-initalization based on material of
- *
- * (C) Copyright 1999 Linus Torvalds
- * (C) Copyright 1999 Johannes Erdfelt
- * (C) Copyright 1999 Randy Dunlap
- * (C) Copyright 1999 Gregory P. Smith
- *
- * $Id: usb-uhci.c,v 1.275 2002/01/19 20:57:33 acher Exp $
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/smp_lock.h>
-#include <linux/errno.h>
-#include <linux/unistd.h>
-#include <linux/interrupt.h>	/* for in_interrupt() */
-#include <linux/init.h>
-#include <linux/version.h>
-#include <linux/pm.h>
-#include <linux/timer.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-
-/* This enables more detailed sanity checks in submit_iso */
-//#define ISO_SANITY_CHECK
-
-/* This enables debug printks */
-#define DEBUG
-
-/* This enables all symbols to be exported, to ease debugging oopses */
-//#define DEBUG_SYMBOLS
-
-/* This enables an extra UHCI slab for memory debugging */
-#define DEBUG_SLAB
-
-#define VERSTR "$Revision: 1.275 $ time " __TIME__ " " __DATE__
-
-#include <linux/usb.h>
-#include "usb-uhci.h"
-#include "usb-uhci-debug.h"
-
-#include "hcd.h"
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v1.275"
-#define DRIVER_AUTHOR "Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber"
-#define DRIVER_DESC "USB Universal Host Controller Interface driver"
-
-#undef DEBUG
-#undef dbg
-#define dbg(format, arg...) do {} while (0)
-#define DEBUG_SYMBOLS
-#ifdef DEBUG_SYMBOLS
-	#define _static
-	#ifndef EXPORT_SYMTAB
-		#define EXPORT_SYMTAB
-	#endif
-#else
-	#define _static static
-#endif
-
-#define queue_dbg dbg //err
-#define async_dbg dbg //err
-
-#ifdef DEBUG_SLAB
-	static kmem_cache_t *urb_priv_kmem;
-#endif
-
-#define SLAB_FLAG     (in_interrupt () || current->state != TASK_RUNNING ? SLAB_ATOMIC : SLAB_KERNEL)
-#define KMALLOC_FLAG  (in_interrupt () || current->state != TASK_RUNNING ? GFP_ATOMIC : GFP_KERNEL)
-
-/* CONFIG_USB_UHCI_HIGH_BANDWITH turns on Full Speed Bandwidth
- * Reclamation: feature that puts loop on descriptor loop when
- * there's some transfer going on. With FSBR, USB performance
- * is optimal, but PCI can be slowed down up-to 5 times, slowing down
- * system performance (eg. framebuffer devices).
- */
-#define CONFIG_USB_UHCI_HIGH_BANDWIDTH
-
-/* *_DEPTH_FIRST puts descriptor in depth-first mode. This has
- * somehow similar effect to FSBR (higher speed), but does not
- * slow PCI down. OTOH USB performace is slightly slower than
- * in FSBR case and single device could hog whole USB, starving
- * other devices.
- */
-#define USE_CTRL_DEPTH_FIRST 0  // 0: Breadth first, 1: Depth first
-#define USE_BULK_DEPTH_FIRST 0  // 0: Breadth first, 1: Depth first
-
-/* Turning off both CONFIG_USB_UHCI_HIGH_BANDWITH and *_DEPTH_FIRST
- * will lead to <64KB/sec performance over USB for bulk transfers targeting
- * one device's endpoint. You probably do not want to do that.
- */
-
-// stop bandwidth reclamation after (roughly) 50ms
-#define IDLE_TIMEOUT  (HZ/20)
-
-// Suppress HC interrupt error messages for 5s
-#define ERROR_SUPPRESSION_TIME (HZ*5)
-
-_static int rh_submit_urb (struct urb *urb);
-_static int rh_unlink_urb (struct urb *urb);
-_static int delete_qh (uhci_t *s, uhci_desc_t *qh);
-_static int process_transfer (uhci_t *s, struct urb *urb, int mode);
-_static int process_interrupt (uhci_t *s, struct urb *urb);
-_static int process_iso (uhci_t *s, struct urb *urb, int force);
-
-// How much URBs with ->next are walked
-#define MAX_NEXT_COUNT 2048
-
-static uhci_t *devs = NULL;
-
-/* used by userspace UHCI data structure dumper */
-uhci_t **uhci_devices = &devs;
-
-/*-------------------------------------------------------------------*/
-// Cleans up collected QHs, but not more than 100 in one go
-void clean_descs(uhci_t *s, int force)
-{
-	struct list_head *q;
-	uhci_desc_t *qh;
-	int now=UHCI_GET_CURRENT_FRAME(s), n=0;
-
-	q=s->free_desc.prev;
-
-	while (q != &s->free_desc && (force || n<100)) {
-		qh = list_entry (q, uhci_desc_t, horizontal);
-		q=qh->horizontal.prev;
-
-		if ((qh->last_used!=now) || force)
-			delete_qh(s,qh);
-		n++;
-	}
-}
-/*-------------------------------------------------------------------*/
-_static void uhci_switch_timer_int(uhci_t *s)
-{
-
-	if (!list_empty(&s->urb_unlinked))
-		set_td_ioc(s->td1ms);
-	else
-		clr_td_ioc(s->td1ms);
-
-	if (s->timeout_urbs)
-		set_td_ioc(s->td32ms);
-	else
-		clr_td_ioc(s->td32ms);
-	wmb();
-}
-/*-------------------------------------------------------------------*/
-#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
-_static void enable_desc_loop(uhci_t *s, struct urb *urb)
-{
-	unsigned long flags;
-
-	if (urb->transfer_flags & USB_NO_FSBR)
-		return;
-
-	spin_lock_irqsave (&s->qh_lock, flags);
-	s->chain_end->hw.qh.head&=cpu_to_le32(~UHCI_PTR_TERM);
-	mb();
-	s->loop_usage++;
-	((urb_priv_t*)urb->hcpriv)->use_loop=1;
-	spin_unlock_irqrestore (&s->qh_lock, flags);
-}
-/*-------------------------------------------------------------------*/
-_static void disable_desc_loop(uhci_t *s, struct urb *urb)
-{
-	unsigned long flags;
-
-	if (urb->transfer_flags & USB_NO_FSBR)
-		return;
-
-	spin_lock_irqsave (&s->qh_lock, flags);
-	if (((urb_priv_t*)urb->hcpriv)->use_loop) {
-		s->loop_usage--;
-
-		if (!s->loop_usage) {
-			s->chain_end->hw.qh.head|=cpu_to_le32(UHCI_PTR_TERM);
-			mb();
-		}
-		((urb_priv_t*)urb->hcpriv)->use_loop=0;
-	}
-	spin_unlock_irqrestore (&s->qh_lock, flags);
-}
-#endif
-/*-------------------------------------------------------------------*/
-_static void queue_urb_unlocked (uhci_t *s, struct urb *urb)
-{
-	struct list_head *p=&urb->urb_list;
-#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
-	{
-		int type;
-		type=usb_pipetype (urb->pipe);
-
-		if ((type == PIPE_BULK) || (type == PIPE_CONTROL))
-			enable_desc_loop(s, urb);
-	}
-#endif
-	urb->status = -EINPROGRESS;
-	((urb_priv_t*)urb->hcpriv)->started=jiffies;
-	list_add (p, &s->urb_list);
-	if (urb->timeout)
-		s->timeout_urbs++;
-	uhci_switch_timer_int(s);
-}
-/*-------------------------------------------------------------------*/
-_static void queue_urb (uhci_t *s, struct urb *urb)
-{
-	unsigned long flags=0;
-
-	spin_lock_irqsave (&s->urb_list_lock, flags);
-	queue_urb_unlocked(s,urb);
-	spin_unlock_irqrestore (&s->urb_list_lock, flags);
-}
-/*-------------------------------------------------------------------*/
-_static void dequeue_urb (uhci_t *s, struct urb *urb)
-{
-#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
-	int type;
-
-	type=usb_pipetype (urb->pipe);
-
-	if ((type == PIPE_BULK) || (type == PIPE_CONTROL))
-		disable_desc_loop(s, urb);
-#endif
-
-	list_del (&urb->urb_list);
-	if (urb->timeout && s->timeout_urbs)
-		s->timeout_urbs--;
-
-}
-/*-------------------------------------------------------------------*/
-_static int alloc_td (uhci_t *s, uhci_desc_t ** new, int flags)
-{
-	dma_addr_t dma_handle;
-
-	*new = pci_pool_alloc(s->desc_pool, GFP_DMA | GFP_ATOMIC, &dma_handle);
-	if (!*new)
-		return -ENOMEM;
-	memset (*new, 0, sizeof (uhci_desc_t));
-	(*new)->dma_addr = dma_handle;
-	set_td_link((*new), UHCI_PTR_TERM | (flags & UHCI_PTR_BITS));	// last by default
-	(*new)->type = TD_TYPE;
-	mb();
-	INIT_LIST_HEAD (&(*new)->vertical);
-	INIT_LIST_HEAD (&(*new)->horizontal);
-	
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-// append a qh to td.link physically, the SW linkage is not affected
-_static void append_qh(uhci_t *s, uhci_desc_t *td, uhci_desc_t* qh, int  flags)
-{
-	unsigned long xxx;
-	
-	spin_lock_irqsave (&s->td_lock, xxx);
-
-	set_td_link(td, qh->dma_addr | (flags & UHCI_PTR_DEPTH) | UHCI_PTR_QH);
-       
-	mb();
-	spin_unlock_irqrestore (&s->td_lock, xxx);
-}
-/*-------------------------------------------------------------------*/
-/* insert td at last position in td-list of qh (vertical) */
-_static int insert_td (uhci_t *s, uhci_desc_t *qh, uhci_desc_t* new, int flags)
-{
-	uhci_desc_t *prev;
-	unsigned long xxx;
-	
-	spin_lock_irqsave (&s->td_lock, xxx);
-
-	list_add_tail (&new->vertical, &qh->vertical);
-
-	prev = list_entry (new->vertical.prev, uhci_desc_t, vertical);
-
-	if (qh == prev ) {
-		// virgin qh without any tds
-		set_qh_element(qh, new->dma_addr | UHCI_PTR_TERM);
-	}
-	else {
-		// already tds inserted, implicitely remove TERM bit of prev
-		set_td_link(prev, new->dma_addr | (flags & UHCI_PTR_DEPTH));
-	}
-	mb();
-	spin_unlock_irqrestore (&s->td_lock, xxx);
-	
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-/* insert new_td after td (horizontal) */
-_static int insert_td_horizontal (uhci_t *s, uhci_desc_t *td, uhci_desc_t* new)
-{
-	uhci_desc_t *next;
-	unsigned long flags;
-	
-	spin_lock_irqsave (&s->td_lock, flags);
-
-	next = list_entry (td->horizontal.next, uhci_desc_t, horizontal);
-	list_add (&new->horizontal, &td->horizontal);
-	new->hw.td.link = td->hw.td.link;
-	set_td_link(td, new->dma_addr);
-	mb();
-	spin_unlock_irqrestore (&s->td_lock, flags);	
-	
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-_static int unlink_td (uhci_t *s, uhci_desc_t *element, int phys_unlink)
-{
-	uhci_desc_t *next, *prev;
-	int dir = 0;
-	unsigned long flags;
-	
-	spin_lock_irqsave (&s->td_lock, flags);
-	
-	next = list_entry (element->vertical.next, uhci_desc_t, vertical);
-	
-	if (next == element) {
-		dir = 1;
-		prev = list_entry (element->horizontal.prev, uhci_desc_t, horizontal);
-	}
-	else 
-		prev = list_entry (element->vertical.prev, uhci_desc_t, vertical);
-	
-	if (phys_unlink) {
-		// really remove HW linking
-		if (prev->type == TD_TYPE)
-			prev->hw.td.link = element->hw.td.link;
-		else
-			prev->hw.qh.element = element->hw.td.link;
-	}
-
-	mb ();
-
-	if (dir == 0)
-		list_del (&element->vertical);
-	else
-		list_del (&element->horizontal);
-	
-	spin_unlock_irqrestore (&s->td_lock, flags);	
-	
-	return 0;
-}
-
-/*-------------------------------------------------------------------*/
-_static int delete_desc (uhci_t *s, uhci_desc_t *element)
-{
-	pci_pool_free(s->desc_pool, element, element->dma_addr);
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-// Allocates qh element
-_static int alloc_qh (uhci_t *s, uhci_desc_t ** new)
-{
-	dma_addr_t dma_handle;
-
-	*new = pci_pool_alloc(s->desc_pool, GFP_DMA | GFP_ATOMIC, &dma_handle);
-	if (!*new)
-		return -ENOMEM;
-	memset (*new, 0, sizeof (uhci_desc_t));
-	(*new)->dma_addr = dma_handle;
-	set_qh_head(*new, UHCI_PTR_TERM);
-	set_qh_element(*new, UHCI_PTR_TERM);
-	(*new)->type = QH_TYPE;
-	
-	mb();
-	INIT_LIST_HEAD (&(*new)->horizontal);
-	INIT_LIST_HEAD (&(*new)->vertical);
-	
-	dbg("Allocated qh @ %p", *new);
-	
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-// inserts new qh before/after the qh at pos
-// flags: 0: insert before pos, 1: insert after pos (for low speed transfers)
-_static int insert_qh (uhci_t *s, uhci_desc_t *pos, uhci_desc_t *new, int order)
-{
-	uhci_desc_t *old;
-	unsigned long flags;
-
-	spin_lock_irqsave (&s->qh_lock, flags);
-
-	if (!order) {
-		// (OLD) (POS) -> (OLD) (NEW) (POS)
-		old = list_entry (pos->horizontal.prev, uhci_desc_t, horizontal);
-		list_add_tail (&new->horizontal, &pos->horizontal);
-		set_qh_head(new, MAKE_QH_ADDR (pos)) ;
-		if (!(old->hw.qh.head & cpu_to_le32(UHCI_PTR_TERM)))
-			set_qh_head(old, MAKE_QH_ADDR (new)) ;
-	}
-	else {
-		// (POS) (OLD) -> (POS) (NEW) (OLD)
-		old = list_entry (pos->horizontal.next, uhci_desc_t, horizontal);
-		list_add (&new->horizontal, &pos->horizontal);
-		set_qh_head(new, MAKE_QH_ADDR (old));
-		set_qh_head(pos, MAKE_QH_ADDR (new)) ;
-	}
-
-	mb ();
-	
-	spin_unlock_irqrestore (&s->qh_lock, flags);
-
-	return 0;
-}
-
-/*-------------------------------------------------------------------*/
-_static int unlink_qh (uhci_t *s, uhci_desc_t *element)
-{
-	uhci_desc_t  *prev;
-	unsigned long flags;
-
-	spin_lock_irqsave (&s->qh_lock, flags);
-	
-	prev = list_entry (element->horizontal.prev, uhci_desc_t, horizontal);
-	prev->hw.qh.head = element->hw.qh.head;
-
-	dbg("unlink qh %p, pqh %p, nxqh %p, to %08x", element, prev, 
-	    list_entry (element->horizontal.next, uhci_desc_t, horizontal),le32_to_cpu(element->hw.qh.head) &~15);
-	
-	list_del(&element->horizontal);
-
-	mb ();
-	spin_unlock_irqrestore (&s->qh_lock, flags);
-	
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-_static int delete_qh (uhci_t *s, uhci_desc_t *qh)
-{
-	uhci_desc_t *td;
-	struct list_head *p;
-	
-	list_del (&qh->horizontal);
-
-	while ((p = qh->vertical.next) != &qh->vertical) {
-		td = list_entry (p, uhci_desc_t, vertical);
-		dbg("unlink td @ %p",td);
-		unlink_td (s, td, 0); // no physical unlink
-		delete_desc (s, td);
-	}
-
-	delete_desc (s, qh);
-	
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-_static void clean_td_chain (uhci_t *s, uhci_desc_t *td)
-{
-	struct list_head *p;
-	uhci_desc_t *td1;
-
-	if (!td)
-		return;
-	
-	while ((p = td->horizontal.next) != &td->horizontal) {
-		td1 = list_entry (p, uhci_desc_t, horizontal);
-		delete_desc (s, td1);
-	}
-	
-	delete_desc (s, td);
-}
-
-/*-------------------------------------------------------------------*/
-_static void fill_td (uhci_desc_t *td, int status, int info, __u32 buffer)
-{
-	td->hw.td.status = cpu_to_le32(status);
-	td->hw.td.info = cpu_to_le32(info);
-	td->hw.td.buffer = cpu_to_le32(buffer);
-}
-/*-------------------------------------------------------------------*/
-// Removes ALL qhs in chain (paranoia!)
-_static void cleanup_skel (uhci_t *s)
-{
-	unsigned int n;
-	uhci_desc_t *td;
-
-	dbg("cleanup_skel");
-
-	clean_descs(s,1);
-
-	
-	if (s->td32ms) {
-	
-		unlink_td(s,s->td32ms,1);
-		delete_desc(s, s->td32ms);
-	}
-
-	for (n = 0; n < 8; n++) {
-		td = s->int_chain[n];
-		clean_td_chain (s, td);
-	}
-
-	if (s->iso_td) {
-		for (n = 0; n < 1024; n++) {
-			td = s->iso_td[n];
-			clean_td_chain (s, td);
-		}
-		kfree (s->iso_td);
-	}
-
-	if (s->framelist)
-		pci_free_consistent(s->uhci_pci, PAGE_SIZE,
-				    s->framelist, s->framelist_dma);
-
-	if (s->control_chain) {
-		// completed init_skel?
-		struct list_head *p;
-		uhci_desc_t *qh, *qh1;
-
-		qh = s->control_chain;
-		while ((p = qh->horizontal.next) != &qh->horizontal) {
-			qh1 = list_entry (p, uhci_desc_t, horizontal);
-			delete_qh (s, qh1);
-		}
-
-		delete_qh (s, qh);
-	}
-	else {
-		if (s->ls_control_chain)
-			delete_desc (s, s->ls_control_chain);
-		if (s->control_chain)
-			delete_desc (s, s->control_chain);
-		if (s->bulk_chain)
-			delete_desc (s, s->bulk_chain);
-		if (s->chain_end)
-			delete_desc (s, s->chain_end);
-	}
-
-	if (s->desc_pool) {
-		pci_pool_destroy(s->desc_pool);
-		s->desc_pool = NULL;
-	}
-
-	dbg("cleanup_skel finished");	
-}
-/*-------------------------------------------------------------------*/
-// allocates framelist and qh-skeletons
-// only HW-links provide continous linking, SW-links stay in their domain (ISO/INT)
-_static int init_skel (uhci_t *s)
-{
-	int n, ret;
-	uhci_desc_t *qh, *td;
-	
-	dbg("init_skel");
-	
-	s->framelist = pci_alloc_consistent(s->uhci_pci, PAGE_SIZE,
-					    &s->framelist_dma);
-
-	if (!s->framelist)
-		return -ENOMEM;
-
-	memset (s->framelist, 0, 4096);
-
-	dbg("creating descriptor pci_pool");
-
-	s->desc_pool = pci_pool_create("uhci_desc", s->uhci_pci,
-				       sizeof(uhci_desc_t), 16, 0,
-				       GFP_DMA | GFP_ATOMIC);	
-	if (!s->desc_pool)
-		goto init_skel_cleanup;
-
-	dbg("allocating iso desc pointer list");
-	s->iso_td = (uhci_desc_t **) kmalloc (1024 * sizeof (uhci_desc_t*), GFP_KERNEL);
-	
-	if (!s->iso_td)
-		goto init_skel_cleanup;
-
-	s->ls_control_chain = NULL;
-	s->control_chain = NULL;
-	s->bulk_chain = NULL;
-	s->chain_end = NULL;
-
-	dbg("allocating iso descs");
-	for (n = 0; n < 1024; n++) {
-	 	// allocate skeleton iso/irq-tds
-		if (alloc_td (s, &td, 0))
-			goto init_skel_cleanup;
-
-		s->iso_td[n] = td;
-		s->framelist[n] = cpu_to_le32((__u32) td->dma_addr);
-	}
-
-	dbg("allocating qh: chain_end");
-	if (alloc_qh (s, &qh))	
-		goto init_skel_cleanup;
-				
-	s->chain_end = qh;
-
-	if (alloc_td (s, &td, 0))
-		goto init_skel_cleanup;
-	
-	fill_td (td, 0 * TD_CTRL_IOC, 0, 0); // generate 1ms interrupt (enabled on demand)
-	insert_td (s, qh, td, 0);
-	qh->hw.qh.element &= cpu_to_le32(~UHCI_PTR_TERM); // remove TERM bit
-	s->td1ms=td;
-
-	dbg("allocating qh: bulk_chain");
-	if (alloc_qh (s, &qh))
-		goto init_skel_cleanup;
-	
-	insert_qh (s, s->chain_end, qh, 0);
-	s->bulk_chain = qh;
-
-	dbg("allocating qh: control_chain");
-	ret = alloc_qh (s, &qh);
-	if (ret)
-		goto init_skel_cleanup;
-	
-	insert_qh (s, s->bulk_chain, qh, 0);
-	s->control_chain = qh;
-
-#ifdef	CONFIG_USB_UHCI_HIGH_BANDWIDTH
-	// disabled reclamation loop
-	set_qh_head(s->chain_end, s->control_chain->dma_addr | UHCI_PTR_QH | UHCI_PTR_TERM);
-#endif
-
-	dbg("allocating qh: ls_control_chain");
-	if (alloc_qh (s, &qh))
-		goto init_skel_cleanup;
-	
-	insert_qh (s, s->control_chain, qh, 0);
-	s->ls_control_chain = qh;
-
-	for (n = 0; n < 8; n++)
-		s->int_chain[n] = 0;
-
-	dbg("allocating skeleton INT-TDs");
-	
-	for (n = 0; n < 8; n++) {
-		uhci_desc_t *td;
-
-		if (alloc_td (s, &td, 0))
-			goto init_skel_cleanup;
-
-		s->int_chain[n] = td;
-		if (n == 0) {
-			set_td_link(s->int_chain[0], s->ls_control_chain->dma_addr | UHCI_PTR_QH);
-		}
-		else {
-			set_td_link(s->int_chain[n], s->int_chain[0]->dma_addr);
-		}
-	}
-
-	dbg("Linking skeleton INT-TDs");
-	
-	for (n = 0; n < 1024; n++) {
-		// link all iso-tds to the interrupt chains
-		int m, o;
-		dbg("framelist[%i]=%x",n,le32_to_cpu(s->framelist[n]));
-		if ((n&127)==127) 
-			((uhci_desc_t*) s->iso_td[n])->hw.td.link = cpu_to_le32(s->int_chain[0]->dma_addr);
-		else 
-			for (o = 1, m = 2; m <= 128; o++, m += m)
-				if ((n & (m - 1)) == ((m - 1) / 2))
-					set_td_link(((uhci_desc_t*) s->iso_td[n]), s->int_chain[o]->dma_addr);
-	}
-
-	if (alloc_td (s, &td, 0))
-		goto init_skel_cleanup;
-	
-	fill_td (td, 0 * TD_CTRL_IOC, 0, 0); // generate 32ms interrupt (activated later)
-	s->td32ms=td;
-
-	insert_td_horizontal (s, s->int_chain[5], td);
-
-	mb();
-	//uhci_show_queue(s->control_chain);   
-	dbg("init_skel exit");
-	return 0;
-
-      init_skel_cleanup:
-	cleanup_skel (s);
-	return -ENOMEM;
-}
-
-/*-------------------------------------------------------------------*/
-//                         LOW LEVEL STUFF
-//          assembles QHs und TDs for control, bulk and iso
-/*-------------------------------------------------------------------*/
-_static int uhci_submit_control_urb (struct urb *urb)
-{
-	uhci_desc_t *qh, *td;
-	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
-	urb_priv_t *urb_priv = urb->hcpriv;
-	unsigned long destination, status;
-	int maxsze = usb_maxpacket (urb->dev, urb->pipe, usb_pipeout (urb->pipe));
-	unsigned long len;
-	char *data;
-	int depth_first=USE_CTRL_DEPTH_FIRST;  // UHCI descriptor chasing method
-
-	dbg("uhci_submit_control start");
-	if (alloc_qh (s, &qh))		// alloc qh for this request
-		return -ENOMEM;
-
-	if (alloc_td (s, &td, UHCI_PTR_DEPTH * depth_first))		// get td for setup stage
-	{
-		delete_qh (s, qh);
-		return -ENOMEM;
-	}
-
-	/* The "pipe" thing contains the destination in bits 8--18 */
-	destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
-
-	/* 3 errors */
-	status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE |
-		(urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27);
-
-	/*  Build the TD for the control request, try forever, 8 bytes of data */
-	fill_td (td, status, destination | (7 << 21), urb_priv->setup_packet_dma);
-
-	insert_td (s, qh, td, 0);	// queue 'setup stage'-td in qh
-#if 0
-	{
-		char *sp=urb->setup_packet;
-		dbg("SETUP to pipe %x: %x %x %x %x %x %x %x %x", urb->pipe,
-		    sp[0],sp[1],sp[2],sp[3],sp[4],sp[5],sp[6],sp[7]);
-	}
-	//uhci_show_td(td);
-#endif
-
-	len = urb->transfer_buffer_length;
-	data = urb->transfer_buffer;
-
-	/* If direction is "send", change the frame from SETUP (0x2D)
-	   to OUT (0xE1). Else change it from SETUP to IN (0x69). */
-
-	destination = (urb->pipe & PIPE_DEVEP_MASK) | (usb_pipeout (urb->pipe)?USB_PID_OUT:USB_PID_IN);
-
-	while (len > 0) {
-		int pktsze = len;
-
-		if (alloc_td (s, &td, UHCI_PTR_DEPTH * depth_first))
-			goto fail_unmap_enomem;
-
-		if (pktsze > maxsze)
-			pktsze = maxsze;
-
-		destination ^= 1 << TD_TOKEN_TOGGLE;	// toggle DATA0/1
-
-		// Status, pktsze bytes of data
-		fill_td (td, status, destination | ((pktsze - 1) << 21),
-			 urb_priv->transfer_buffer_dma + (data - (char *)urb->transfer_buffer));
-
-		insert_td (s, qh, td, UHCI_PTR_DEPTH * depth_first);	// queue 'data stage'-td in qh
-
-		data += pktsze;
-		len -= pktsze;
-	}
-
-	/* Build the final TD for control status */
-	/* It's only IN if the pipe is out AND we aren't expecting data */
-
-	destination &= ~UHCI_PID;
-
-	if (usb_pipeout (urb->pipe) || (urb->transfer_buffer_length == 0))
-		destination |= USB_PID_IN;
-	else
-		destination |= USB_PID_OUT;
-
-	destination |= 1 << TD_TOKEN_TOGGLE;	/* End in Data1 */
-
-	if (alloc_td (s, &td, UHCI_PTR_DEPTH))
-		goto fail_unmap_enomem;
-
-	status &=~TD_CTRL_SPD;
-
-	/* no limit on errors on final packet , 0 bytes of data */
-	fill_td (td, status | TD_CTRL_IOC, destination | (UHCI_NULL_DATA_SIZE << 21),
-		 0);
-
-	insert_td (s, qh, td, UHCI_PTR_DEPTH * depth_first);	// queue status td
-
-	list_add (&qh->desc_list, &urb_priv->desc_list);
-
-	queue_urb (s, urb);	// queue before inserting in desc chain
-
-	qh->hw.qh.element &= cpu_to_le32(~UHCI_PTR_TERM);
-
-	//uhci_show_queue(qh);
-	/* Start it up... put low speed first */
-	if (urb->pipe & TD_CTRL_LS)
-		insert_qh (s, s->control_chain, qh, 0);
-	else
-		insert_qh (s, s->bulk_chain, qh, 0);
-
-	dbg("uhci_submit_control end");
-	return 0;
-
-fail_unmap_enomem:
-	delete_qh(s, qh);
-	return -ENOMEM;
-}
-/*-------------------------------------------------------------------*/
-// For queued bulk transfers, two additional QH helpers are allocated (nqh, bqh)
-// Due to the linking with other bulk urbs, it has to be locked with urb_list_lock!
-
-_static int uhci_submit_bulk_urb (struct urb *urb, struct urb *bulk_urb)
-{
-	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
-	urb_priv_t *urb_priv = urb->hcpriv, *upriv, *bpriv=NULL;
-	uhci_desc_t *qh, *td, *nqh=NULL, *bqh=NULL, *first_td=NULL;
-	unsigned long destination, status;
-	char *data;
-	unsigned int pipe = urb->pipe;
-	int maxsze = usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe));
-	int info, len, last;
-	int depth_first=USE_BULK_DEPTH_FIRST;  // UHCI descriptor chasing method
-
-	if (usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)))
-		return -EPIPE;
-
-	queue_dbg("uhci_submit_bulk_urb: urb %p, old %p, pipe %08x, len %i",
-		  urb,bulk_urb,urb->pipe,urb->transfer_buffer_length);
-
-	upriv = (urb_priv_t*)urb->hcpriv;
-
-	if (!bulk_urb) {
-		if (alloc_qh (s, &qh))		// get qh for this request
-			return -ENOMEM;
-
-		if (urb->transfer_flags & USB_QUEUE_BULK) {
-			if (alloc_qh(s, &nqh)) // placeholder for clean unlink
-			{
-				delete_desc (s, qh);
-				return -ENOMEM;
-			}
-			upriv->next_qh = nqh;
-			queue_dbg("new next qh %p",nqh);
-		}
-	}
-	else { 
-		bpriv = (urb_priv_t*)bulk_urb->hcpriv;
-		qh = bpriv->bottom_qh;  // re-use bottom qh and next qh
-		nqh = bpriv->next_qh;
-		upriv->next_qh=nqh;	
-		upriv->prev_queued_urb=bulk_urb;
-	}
-
-	if (urb->transfer_flags & USB_QUEUE_BULK) {
-		if (alloc_qh (s, &bqh))  // "bottom" QH
-		{
-			if (!bulk_urb) { 
-				delete_desc(s, qh);
-				delete_desc(s, nqh);
-			}
-			return -ENOMEM;
-		}
-		set_qh_element(bqh, UHCI_PTR_TERM);
-		set_qh_head(bqh, nqh->dma_addr | UHCI_PTR_QH); // element
-		upriv->bottom_qh = bqh;
-	}
-	queue_dbg("uhci_submit_bulk: qh %p bqh %p nqh %p",qh, bqh, nqh);
-
-	/* The "pipe" thing contains the destination in bits 8--18. */
-	destination = (pipe & PIPE_DEVEP_MASK) | usb_packetid (pipe);
-
-	/* 3 errors */
-	status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE |
-		((urb->transfer_flags & USB_DISABLE_SPD) ? 0 : TD_CTRL_SPD) | (3 << 27);
-
-	/* Build the TDs for the bulk request */
-	len = urb->transfer_buffer_length;
-	data = urb->transfer_buffer;
-	
-	do {					// TBD: Really allow zero-length packets?
-		int pktsze = len;
-
-		if (alloc_td (s, &td, UHCI_PTR_DEPTH * depth_first))
-		{
-			delete_qh (s, qh);
-			return -ENOMEM;
-		}
-
-		if (pktsze > maxsze)
-			pktsze = maxsze;
-
-		// pktsze bytes of data 
-		info = destination | (((pktsze - 1)&UHCI_NULL_DATA_SIZE) << 21) |
-			(usb_gettoggle (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)) << TD_TOKEN_TOGGLE);
-
-		fill_td (td, status, info,
-			 urb_priv->transfer_buffer_dma + (data - (char *)urb->transfer_buffer));
-
-		data += pktsze;
-		len -= pktsze;
-		// Use USB_ZERO_PACKET to finish bulk OUTs always with a zero length packet
-		last = (len == 0 && (usb_pipein(pipe) || pktsze < maxsze || !(urb->transfer_flags & USB_ZERO_PACKET)));
-
-		if (last)
-			set_td_ioc(td);	// last one generates INT
-
-		insert_td (s, qh, td, UHCI_PTR_DEPTH * depth_first);
-		if (!first_td)
-			first_td=td;
-		usb_dotoggle (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe));
-
-	} while (!last);
-
-	if (bulk_urb && bpriv)   // everything went OK, link with old bulk URB
-		bpriv->next_queued_urb=urb;
-
-	list_add (&qh->desc_list, &urb_priv->desc_list);
-
-	if (urb->transfer_flags & USB_QUEUE_BULK)
-		append_qh(s, td, bqh, UHCI_PTR_DEPTH * depth_first);
-
-	queue_urb_unlocked (s, urb);
-	
-	if (urb->transfer_flags & USB_QUEUE_BULK)
-		set_qh_element(qh, first_td->dma_addr);
-	else
-		qh->hw.qh.element &= cpu_to_le32(~UHCI_PTR_TERM);    // arm QH
-
-	if (!bulk_urb) { 					// new bulk queue	
-		if (urb->transfer_flags & USB_QUEUE_BULK) {
-			spin_lock (&s->td_lock);		// both QHs in one go
-			insert_qh (s, s->chain_end, qh, 0);	// Main QH
-			insert_qh (s, s->chain_end, nqh, 0);	// Helper QH
-			spin_unlock (&s->td_lock);
-		}
-		else
-			insert_qh (s, s->chain_end, qh, 0);
-	}
-	
-	//uhci_show_queue(s->bulk_chain);
-	//dbg("uhci_submit_bulk_urb: exit\n");
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-_static void uhci_clean_iso_step1(uhci_t *s, urb_priv_t *urb_priv)
-{
-	struct list_head *p;
-	uhci_desc_t *td;
-
-	for (p = urb_priv->desc_list.next; p != &urb_priv->desc_list; p = p->next) {
-				td = list_entry (p, uhci_desc_t, desc_list);
-				unlink_td (s, td, 1);
-	}
-}
-/*-------------------------------------------------------------------*/
-_static void uhci_clean_iso_step2(uhci_t *s, urb_priv_t *urb_priv)
-{
-	struct list_head *p;
-	uhci_desc_t *td;
-
-	while ((p = urb_priv->desc_list.next) != &urb_priv->desc_list) {
-				td = list_entry (p, uhci_desc_t, desc_list);
-				list_del (p);
-				delete_desc (s, td);
-	}
-}
-/*-------------------------------------------------------------------*/
-/* mode: CLEAN_TRANSFER_NO_DELETION: unlink but no deletion mark (step 1 of async_unlink)
-         CLEAN_TRANSFER_REGULAR: regular (unlink/delete-mark)
-         CLEAN_TRANSFER_DELETION_MARK: deletion mark for QH (step 2 of async_unlink)
- looks a bit complicated because of all the bulk queueing goodies
-*/
-
-_static void uhci_clean_transfer (uhci_t *s, struct urb *urb, uhci_desc_t *qh, int mode)
-{
-	uhci_desc_t *bqh, *nqh, *prevqh, *prevtd;
-	int now;
-	urb_priv_t *priv=(urb_priv_t*)urb->hcpriv;
-
-	now=UHCI_GET_CURRENT_FRAME(s);
-
-	bqh=priv->bottom_qh;	
-	
-	if (!priv->next_queued_urb)  { // no more appended bulk queues
-
-		queue_dbg("uhci_clean_transfer: No more bulks for urb %p, qh %p, bqh %p, nqh %p", urb, qh, bqh, priv->next_qh);	
-	
-		if (priv->prev_queued_urb && mode != CLEAN_TRANSFER_DELETION_MARK) {  // qh not top of the queue
-				unsigned long flags; 
-				urb_priv_t* ppriv=(urb_priv_t*)priv->prev_queued_urb->hcpriv;
-
-				spin_lock_irqsave (&s->qh_lock, flags);
-				prevqh = list_entry (ppriv->desc_list.next, uhci_desc_t, desc_list);
-				prevtd = list_entry (prevqh->vertical.prev, uhci_desc_t, vertical);
-				set_td_link(prevtd, priv->bottom_qh->dma_addr | UHCI_PTR_QH); // skip current qh
-				mb();
-				queue_dbg("uhci_clean_transfer: relink pqh %p, ptd %p",prevqh, prevtd);
-				spin_unlock_irqrestore (&s->qh_lock, flags);
-
-				ppriv->bottom_qh = priv->bottom_qh;
-				ppriv->next_queued_urb = NULL;
-			}
-		else {   // queue is dead, qh is top of the queue
-			
-			if (mode != CLEAN_TRANSFER_DELETION_MARK) 				
-				unlink_qh(s, qh); // remove qh from horizontal chain
-
-			if (bqh) {  // remove remainings of bulk queue
-				nqh=priv->next_qh;
-
-				if (mode != CLEAN_TRANSFER_DELETION_MARK) 
-					unlink_qh(s, nqh);  // remove nqh from horizontal chain
-				
-				if (mode != CLEAN_TRANSFER_NO_DELETION) {  // add helper QHs to free desc list
-					nqh->last_used = bqh->last_used = now;
-					list_add_tail (&nqh->horizontal, &s->free_desc);
-					list_add_tail (&bqh->horizontal, &s->free_desc);
-				}			
-			}
-		}
-	}
-	else { // there are queued urbs following
-	
-	  queue_dbg("uhci_clean_transfer: urb %p, prevurb %p, nexturb %p, qh %p, bqh %p, nqh %p",
-		       urb, priv->prev_queued_urb,  priv->next_queued_urb, qh, bqh, priv->next_qh);	
-       	
-		if (mode != CLEAN_TRANSFER_DELETION_MARK) {	// no work for cleanup at unlink-completion
-			struct urb *nurb;
-			unsigned long flags;
-
-			nurb = priv->next_queued_urb;
-			spin_lock_irqsave (&s->qh_lock, flags);		
-
-			if (!priv->prev_queued_urb) { // top QH
-				
-				prevqh = list_entry (qh->horizontal.prev, uhci_desc_t, horizontal);
-				set_qh_head(prevqh, bqh->dma_addr | UHCI_PTR_QH);
-				list_del (&qh->horizontal);  // remove this qh form horizontal chain
-				list_add (&bqh->horizontal, &prevqh->horizontal); // insert next bqh in horizontal chain
-			}
-			else {		// intermediate QH
-				urb_priv_t* ppriv=(urb_priv_t*)priv->prev_queued_urb->hcpriv;
-				urb_priv_t* npriv=(urb_priv_t*)nurb->hcpriv;
-				uhci_desc_t * bnqh;
-				
-				bnqh = list_entry (npriv->desc_list.next, uhci_desc_t, desc_list);
-				ppriv->bottom_qh = bnqh;
-				ppriv->next_queued_urb = nurb;				
-				prevqh = list_entry (ppriv->desc_list.next, uhci_desc_t, desc_list);
-				set_qh_head(prevqh, bqh->dma_addr | UHCI_PTR_QH);
-			}
-
-			mb();
-			((urb_priv_t*)nurb->hcpriv)->prev_queued_urb=priv->prev_queued_urb;
-			spin_unlock_irqrestore (&s->qh_lock, flags);
-		}		
-	}
-
-	if (mode != CLEAN_TRANSFER_NO_DELETION) {
-		qh->last_used = now;	
-		list_add_tail (&qh->horizontal, &s->free_desc); // mark qh for later deletion/kfree
-	}
-}
-/*-------------------------------------------------------------------*/
-// Release bandwidth for Interrupt or Isoc. transfers 
-_static void uhci_release_bandwidth(struct urb *urb)
-{       
-	if (urb->bandwidth) {
-		switch (usb_pipetype(urb->pipe)) {
-		case PIPE_INTERRUPT:
-			usb_release_bandwidth (urb->dev, urb, 0);
-			break;
-		case PIPE_ISOCHRONOUS:
-			usb_release_bandwidth (urb->dev, urb, 1);
-			break;
-		default:
-			break;
-		}
-	}	
-}
-
-_static void uhci_urb_dma_sync(uhci_t *s, struct urb *urb, urb_priv_t *urb_priv)
-{
-	if (urb_priv->setup_packet_dma)
-		pci_dma_sync_single(s->uhci_pci, urb_priv->setup_packet_dma,
-				    sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE);
-
-	if (urb_priv->transfer_buffer_dma)
-		pci_dma_sync_single(s->uhci_pci, urb_priv->transfer_buffer_dma,
-				    urb->transfer_buffer_length,
-				    usb_pipein(urb->pipe) ?
-				    PCI_DMA_FROMDEVICE :
-				    PCI_DMA_TODEVICE);
-}
-
-_static void uhci_urb_dma_unmap(uhci_t *s, struct urb *urb, urb_priv_t *urb_priv)
-{
-	if (urb_priv->setup_packet_dma) {
-		pci_unmap_single(s->uhci_pci, urb_priv->setup_packet_dma,
-				 sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE);
-		urb_priv->setup_packet_dma = 0;
-	}
-	if (urb_priv->transfer_buffer_dma) {
-		pci_unmap_single(s->uhci_pci, urb_priv->transfer_buffer_dma,
-				 urb->transfer_buffer_length,
-				 usb_pipein(urb->pipe) ?
-				 PCI_DMA_FROMDEVICE :
-				 PCI_DMA_TODEVICE);
-		urb_priv->transfer_buffer_dma = 0;
-	}
-}
-/*-------------------------------------------------------------------*/
-/* needs urb_list_lock!
-   mode: UNLINK_ASYNC_STORE_URB: unlink and move URB into unlinked list
-         UNLINK_ASYNC_DONT_STORE: unlink, don't move URB into unlinked list
-*/
-_static int uhci_unlink_urb_async (uhci_t *s,struct urb *urb, int mode)
-{
-	uhci_desc_t *qh;
-	urb_priv_t *urb_priv;
-	
-	async_dbg("unlink_urb_async called %p",urb);
-
-	if ((urb->status == -EINPROGRESS) ||
-	    ((usb_pipetype (urb->pipe) ==  PIPE_INTERRUPT) && ((urb_priv_t*)urb->hcpriv)->flags))
-	{
-		((urb_priv_t*)urb->hcpriv)->started = ~0;  // mark
-		dequeue_urb (s, urb);
-
-		if (mode==UNLINK_ASYNC_STORE_URB)
-			list_add_tail (&urb->urb_list, &s->urb_unlinked); // store urb
-
-		uhci_switch_timer_int(s);
-       		s->unlink_urb_done = 1;
-		uhci_release_bandwidth(urb);
-
-		urb->status = -ECONNABORTED;	// mark urb as "waiting to be killed"	
-		urb_priv = (urb_priv_t*)urb->hcpriv;
-
-		switch (usb_pipetype (urb->pipe)) {
-		case PIPE_INTERRUPT:
-			usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
-
-		case PIPE_ISOCHRONOUS:
-			uhci_clean_iso_step1 (s, urb_priv);
-			break;
-
-		case PIPE_BULK:
-		case PIPE_CONTROL:
-			qh = list_entry (urb_priv->desc_list.next, uhci_desc_t, desc_list);
-			uhci_clean_transfer (s, urb, qh, CLEAN_TRANSFER_NO_DELETION);
-			break;
-		}
-		((urb_priv_t*)urb->hcpriv)->started = UHCI_GET_CURRENT_FRAME(s);
-		return -EINPROGRESS;  // completion will follow
-	}		
-
-	return 0;    // URB already dead
-}
-/*-------------------------------------------------------------------*/
-// kills an urb by unlinking descriptors and waiting for at least one frame
-_static int uhci_unlink_urb_sync (uhci_t *s, struct urb *urb)
-{
-	uhci_desc_t *qh;
-	urb_priv_t *urb_priv;
-	unsigned long flags=0;
-	struct usb_device *usb_dev;
-
-	spin_lock_irqsave (&s->urb_list_lock, flags);
-
-	if (urb->status == -EINPROGRESS) {
-
-		// move descriptors out of the running chains, dequeue urb
-		uhci_unlink_urb_async(s, urb, UNLINK_ASYNC_DONT_STORE);
-
-		urb_priv = urb->hcpriv;
-		urb->status = -ENOENT;	// prevent from double deletion after unlock		
-		spin_unlock_irqrestore (&s->urb_list_lock, flags);
-		
-		// cleanup the rest
-		switch (usb_pipetype (urb->pipe)) {
-
-		case PIPE_INTERRUPT:
-		case PIPE_ISOCHRONOUS:
-			uhci_wait_ms(1);
-			uhci_clean_iso_step2(s, urb_priv);
-			break;
-
-		case PIPE_BULK:
-		case PIPE_CONTROL:
-			qh = list_entry (urb_priv->desc_list.next, uhci_desc_t, desc_list);
-			uhci_clean_transfer(s, urb, qh, CLEAN_TRANSFER_DELETION_MARK);
-			uhci_wait_ms(1);
-		}
-		urb->status = -ENOENT;	// mark urb as killed		
-					
-		uhci_urb_dma_unmap(s, urb, urb->hcpriv);
-
-#ifdef DEBUG_SLAB
-		kmem_cache_free (urb_priv_kmem, urb->hcpriv);
-#else
-		kfree (urb->hcpriv);
-#endif
-		usb_dev = urb->dev;
-		if (urb->complete) {
-			dbg("unlink_urb: calling completion");
-			urb->dev = NULL;
-			urb->complete ((struct urb *) urb);
-		}
-		usb_dec_dev_use (usb_dev);
-	}
-	else
-		spin_unlock_irqrestore (&s->urb_list_lock, flags);
-
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-// async unlink_urb completion/cleanup work
-// has to be protected by urb_list_lock!
-// features: if set in transfer_flags, the resulting status of the killed
-// transaction is not overwritten
-
-_static void uhci_cleanup_unlink(uhci_t *s, int force)
-{
-	struct list_head *q;
-	struct urb *urb;
-	struct usb_device *dev;
-	int now, type;
-	urb_priv_t *urb_priv;
-
-	q=s->urb_unlinked.next;
-	now=UHCI_GET_CURRENT_FRAME(s);
-
-	while (q != &s->urb_unlinked) {
-
-		urb = list_entry (q, struct urb, urb_list);
-
-		urb_priv = (urb_priv_t*)urb->hcpriv;
-		q = urb->urb_list.next;
-		
-		if (!urb_priv) // avoid crash when URB is corrupted
-			break;
-			
-		if (force || ((urb_priv->started != ~0) && (urb_priv->started != now))) {
-			async_dbg("async cleanup %p",urb);
-			type=usb_pipetype (urb->pipe);
-
-			switch (type) { // process descriptors
-			case PIPE_CONTROL:
-				process_transfer (s, urb, CLEAN_TRANSFER_DELETION_MARK);  // don't unlink (already done)
-				break;
-			case PIPE_BULK:
-				if (!s->avoid_bulk.counter)
-					process_transfer (s, urb, CLEAN_TRANSFER_DELETION_MARK); // don't unlink (already done)
-				else
-					continue;
-				break;
-			case PIPE_ISOCHRONOUS:
-				process_iso (s, urb, PROCESS_ISO_FORCE); // force, don't unlink
-				break;
-			case PIPE_INTERRUPT:
-				process_interrupt (s, urb);
-				break;
-			}
-
-			if (!(urb->transfer_flags & USB_TIMEOUT_KILLED))
-		  		urb->status = -ECONNRESET; // mark as asynchronously killed
-
-			dev = urb->dev;	// completion may destroy all...
-			urb_priv = urb->hcpriv;
-			list_del (&urb->urb_list);
-			
-			uhci_urb_dma_sync(s, urb, urb_priv);
-			if (urb->complete) {
-				spin_unlock(&s->urb_list_lock);
-				urb->dev = NULL;
-				urb->complete ((struct urb *) urb);
-				spin_lock(&s->urb_list_lock);
-			}
-
-			if (!(urb->transfer_flags & USB_TIMEOUT_KILLED))
-				urb->status = -ENOENT;  // now the urb is really dead
-
-			switch (type) {
-			case PIPE_ISOCHRONOUS:
-			case PIPE_INTERRUPT:
-				uhci_clean_iso_step2(s, urb_priv);
-				break;
-			}
-	
-			uhci_urb_dma_unmap(s, urb, urb_priv);
-
-			usb_dec_dev_use (dev);
-#ifdef DEBUG_SLAB
-			kmem_cache_free (urb_priv_kmem, urb_priv);
-#else
-			kfree (urb_priv);
-#endif
-
-		}
-	}
-}
- 
-/*-------------------------------------------------------------------*/
-_static int uhci_unlink_urb (struct urb *urb)
-{
-	uhci_t *s;
-	unsigned long flags=0;
-	dbg("uhci_unlink_urb called for %p",urb);
-	if (!urb || !urb->dev)		// you never know...
-		return -EINVAL;
-	
-	s = (uhci_t*) urb->dev->bus->hcpriv;
-
-	if (usb_pipedevice (urb->pipe) == s->rh.devnum)
-		return rh_unlink_urb (urb);
-
-	if (!urb->hcpriv)
-		return -EINVAL;
-
-	if (urb->transfer_flags & USB_ASYNC_UNLINK) {
-		int ret;
-       		spin_lock_irqsave (&s->urb_list_lock, flags);
-       		
-		uhci_release_bandwidth(urb);
-		ret = uhci_unlink_urb_async(s, urb, UNLINK_ASYNC_STORE_URB);
-
-		spin_unlock_irqrestore (&s->urb_list_lock, flags);	
-		return ret;
-	}
-	else
-		return uhci_unlink_urb_sync(s, urb);
-}
-/*-------------------------------------------------------------------*/
-// In case of ASAP iso transfer, search the URB-list for already queued URBs
-// for this EP and calculate the earliest start frame for the new
-// URB (easy seamless URB continuation!)
-_static int find_iso_limits (struct urb *urb, unsigned int *start, unsigned int *end)
-{
-	struct urb *u, *last_urb = NULL;
-	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
-	struct list_head *p;
-	int ret=-1;
-	unsigned long flags;
-	
-	spin_lock_irqsave (&s->urb_list_lock, flags);
-	p=s->urb_list.prev;
-
-	for (; p != &s->urb_list; p = p->prev) {
-		u = list_entry (p, struct urb, urb_list);
-		// look for pending URBs with identical pipe handle
-		// works only because iso doesn't toggle the data bit!
-		if ((urb->pipe == u->pipe) && (urb->dev == u->dev) && (u->status == -EINPROGRESS)) {
-			if (!last_urb)
-				*start = u->start_frame;
-			last_urb = u;
-		}
-	}
-	
-	if (last_urb) {
-		*end = (last_urb->start_frame + last_urb->number_of_packets) & 1023;
-		ret=0;
-	}
-	
-	spin_unlock_irqrestore(&s->urb_list_lock, flags);
-	
-	return ret;
-}
-/*-------------------------------------------------------------------*/
-// adjust start_frame according to scheduling constraints (ASAP etc)
-
-_static int iso_find_start (struct urb *urb)
-{
-	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
-	unsigned int now;
-	unsigned int start_limit = 0, stop_limit = 0, queued_size;
-	int limits;
-
-	now = UHCI_GET_CURRENT_FRAME (s) & 1023;
-
-	if ((unsigned) urb->number_of_packets > 900)
-		return -EFBIG;
-	
-	limits = find_iso_limits (urb, &start_limit, &stop_limit);
-	queued_size = (stop_limit - start_limit) & 1023;
-
-	if (urb->transfer_flags & USB_ISO_ASAP) {
-		// first iso
-		if (limits) {
-			// 10ms setup should be enough //FIXME!
-			urb->start_frame = (now + 10) & 1023;
-		}
-		else {
-			urb->start_frame = stop_limit;		//seamless linkage
-
-			if (((now - urb->start_frame) & 1023) <= (unsigned) urb->number_of_packets) {
-				info("iso_find_start: gap in seamless isochronous scheduling");
-				dbg("iso_find_start: now %u start_frame %u number_of_packets %u pipe 0x%08x",
-					now, urb->start_frame, urb->number_of_packets, urb->pipe);
-				urb->start_frame = (now + 5) & 1023;	// 5ms setup should be enough //FIXME!
-			}
-		}
-	}
-	else {
-		urb->start_frame &= 1023;
-		if (((now - urb->start_frame) & 1023) < (unsigned) urb->number_of_packets) {
-			dbg("iso_find_start: now between start_frame and end");
-			return -EAGAIN;
-		}
-	}
-
-	/* check if either start_frame or start_frame+number_of_packets-1 lies between start_limit and stop_limit */
-	if (limits)
-		return 0;
-
-	if (((urb->start_frame - start_limit) & 1023) < queued_size ||
-	    ((urb->start_frame + urb->number_of_packets - 1 - start_limit) & 1023) < queued_size) {
-		dbg("iso_find_start: start_frame %u number_of_packets %u start_limit %u stop_limit %u",
-			urb->start_frame, urb->number_of_packets, start_limit, stop_limit);
-		return -EAGAIN;
-	}
-
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-// submits USB interrupt (ie. polling ;-) 
-// ASAP-flag set implicitely
-// if period==0, the transfer is only done once
-
-_static int uhci_submit_int_urb (struct urb *urb)
-{
-	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
-	urb_priv_t *urb_priv = urb->hcpriv;
-	int nint, n;
-	uhci_desc_t *td;
-	int status, destination;
-	int info;
-	unsigned int pipe = urb->pipe;
-
-	if (urb->interval < 0 || urb->interval >= 256)
-		return -EINVAL;
-
-	if (urb->interval == 0)
-		nint = 0;
-	else {
-		for (nint = 0, n = 1; nint <= 8; nint++, n += n)	// round interval down to 2^n
-		 {
-			if (urb->interval < n) {
-				urb->interval = n / 2;
-				break;
-			}
-		}
-		nint--;
-	}
-
-	dbg("Rounded interval to %i, chain  %i", urb->interval, nint);
-
-	urb->start_frame = UHCI_GET_CURRENT_FRAME (s) & 1023;	// remember start frame, just in case...
-
-	urb->number_of_packets = 1;
-
-	// INT allows only one packet
-	if (urb->transfer_buffer_length > usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe)))
-		return -EINVAL;
-
-	if (alloc_td (s, &td, UHCI_PTR_DEPTH))
-		return -ENOMEM;
-
-	status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC |
-		(urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27);
-
-	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid (urb->pipe) |
-		(((urb->transfer_buffer_length - 1) & 0x7ff) << 21);
-
-
-	info = destination | (usb_gettoggle (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)) << TD_TOKEN_TOGGLE);
-
-	fill_td (td, status, info, urb_priv->transfer_buffer_dma);
-	list_add_tail (&td->desc_list, &urb_priv->desc_list);
-
-	queue_urb (s, urb);
-
-	insert_td_horizontal (s, s->int_chain[nint], td);	// store in INT-TDs
-
-	usb_dotoggle (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe));
-
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-_static int uhci_submit_iso_urb (struct urb *urb)
-{
-	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
-	urb_priv_t *urb_priv = urb->hcpriv;
-#ifdef ISO_SANITY_CHECK
-	int pipe=urb->pipe;
-	int maxsze = usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe));
-#endif
-	int n, ret, last=0;
-	uhci_desc_t *td, **tdm;
-	int status, destination;
-	unsigned long flags;
-
-	__save_flags(flags);
-	__cli();		      // Disable IRQs to schedule all ISO-TDs in time
-	ret = iso_find_start (urb);	// adjusts urb->start_frame for later use
-	
-	if (ret)
-		goto err;
-
-	tdm = (uhci_desc_t **) kmalloc (urb->number_of_packets * sizeof (uhci_desc_t*), KMALLOC_FLAG);
-
-	if (!tdm) {
-		ret = -ENOMEM;
-		goto err;
-	}
-
-	memset(tdm, 0, urb->number_of_packets * sizeof (uhci_desc_t*));
-
-	// First try to get all TDs. Cause: Removing already inserted TDs can only be done 
-	// racefree in three steps: unlink TDs, wait one frame, delete TDs. 
-	// So, this solutions seems simpler...
-
-	for (n = 0; n < urb->number_of_packets; n++) {
-		dbg("n:%d urb->iso_frame_desc[n].length:%d", n, urb->iso_frame_desc[n].length);
-		if (!urb->iso_frame_desc[n].length)
-			continue;  // allows ISO striping by setting length to zero in iso_descriptor
-
-
-#ifdef ISO_SANITY_CHECK
-		if(urb->iso_frame_desc[n].length > maxsze) {
-
-			err("submit_iso: urb->iso_frame_desc[%d].length(%d)>%d",n , urb->iso_frame_desc[n].length, maxsze);
-			ret=-EINVAL;		
-		}
-		else
-#endif
-		if (alloc_td (s, &td, UHCI_PTR_DEPTH)) {
-			int i;	// Cleanup allocated TDs
-
-			for (i = 0; i < n; n++)
-				if (tdm[i])
-					 delete_desc(s, tdm[i]);
-			kfree (tdm);
-			goto err;
-		}
-		last=n;
-		tdm[n] = td;
-	}
-
-	status = TD_CTRL_ACTIVE | TD_CTRL_IOS;
-
-	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid (urb->pipe);
-
-	// Queue all allocated TDs
-	for (n = 0; n < urb->number_of_packets; n++) {
-		td = tdm[n];
-		if (!td)
-			continue;
-			
-		if (n  == last) {
-			status |= TD_CTRL_IOC;
-			queue_urb (s, urb);
-		}
-
-		fill_td (td, status, destination | (((urb->iso_frame_desc[n].length - 1) & 0x7ff) << 21),
-			 urb_priv->transfer_buffer_dma + urb->iso_frame_desc[n].offset);
-		list_add_tail (&td->desc_list, &urb_priv->desc_list);
-	
-		insert_td_horizontal (s, s->iso_td[(urb->start_frame + n) & 1023], td);	// store in iso-tds
-	}
-
-	kfree (tdm);
-	dbg("ISO-INT# %i, start %i, now %i", urb->number_of_packets, urb->start_frame, UHCI_GET_CURRENT_FRAME (s) & 1023);
-	ret = 0;
-
-      err:
-	__restore_flags(flags);
-	return ret;
-}
-/*-------------------------------------------------------------------*/
-// returns: 0 (no transfer queued), urb* (this urb already queued)
- 
-_static struct urb* search_dev_ep (uhci_t *s, struct urb *urb)
-{
-	struct list_head *p;
-	struct urb *tmp;
-	unsigned int mask = usb_pipecontrol(urb->pipe) ? (~USB_DIR_IN) : (~0);
-
-	dbg("search_dev_ep:");
-
-	p=s->urb_list.next;
-
-	for (; p != &s->urb_list; p = p->next) {
-		tmp = list_entry (p, struct urb, urb_list);
-		dbg("urb: %p", tmp);
-		// we can accept this urb if it is not queued at this time 
-		// or if non-iso transfer requests should be scheduled for the same device and pipe
-		if ((!usb_pipeisoc(urb->pipe) && (tmp->dev == urb->dev) && !((tmp->pipe ^ urb->pipe) & mask)) ||
-		    (urb == tmp)) {
-			return tmp;	// found another urb already queued for processing
-		}
-	}
-
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-_static int uhci_submit_urb (struct urb *urb)
-{
-	uhci_t *s;
-	urb_priv_t *urb_priv;
-	int ret = 0, type;
-	unsigned long flags;
-	struct urb *queued_urb=NULL;
-	int bustime;
-		
-	if (!urb->dev || !urb->dev->bus)
-		return -ENODEV;
-
-	s = (uhci_t*) urb->dev->bus->hcpriv;
-	//dbg("submit_urb: %p type %d",urb,usb_pipetype(urb->pipe));
-	
-	if (!s->running)
-		return -ENODEV;
-	
-	type = usb_pipetype (urb->pipe);
-
-	if (usb_pipedevice (urb->pipe) == s->rh.devnum)
-		return rh_submit_urb (urb);	/* virtual root hub */
-
-	// Sanity checks
-	if (usb_maxpacket (urb->dev, urb->pipe, usb_pipeout (urb->pipe)) <= 0) {		
-		err("uhci_submit_urb: pipesize for pipe %x is zero", urb->pipe);
-		return -EMSGSIZE;
-	}
-
-	if (urb->transfer_buffer_length < 0 && type != PIPE_ISOCHRONOUS) {
-		err("uhci_submit_urb: Negative transfer length for urb %p", urb);
-		return -EINVAL;
-	}
-
-	usb_inc_dev_use (urb->dev);
-
-	spin_lock_irqsave (&s->urb_list_lock, flags);
-
-	queued_urb = search_dev_ep (s, urb); // returns already queued urb for that pipe
-
-	if (queued_urb) {
-
-		queue_dbg("found bulk urb %p\n", queued_urb);
-
-		if (( type != PIPE_BULK) ||
-		    ((type == PIPE_BULK) &&
-		     (!(urb->transfer_flags & USB_QUEUE_BULK) || !(queued_urb->transfer_flags & USB_QUEUE_BULK)))) {
-			spin_unlock_irqrestore (&s->urb_list_lock, flags);
-			usb_dec_dev_use (urb->dev);
-			err("ENXIO %08x, flags %x, urb %p, burb %p",urb->pipe,urb->transfer_flags,urb,queued_urb);
-			return -ENXIO;	// urb already queued
-		}
-	}
-
-#ifdef DEBUG_SLAB
-	urb_priv = kmem_cache_alloc(urb_priv_kmem, SLAB_FLAG);
-#else
-	urb_priv = kmalloc (sizeof (urb_priv_t), KMALLOC_FLAG);
-#endif
-	if (!urb_priv) {
-		usb_dec_dev_use (urb->dev);
-		spin_unlock_irqrestore (&s->urb_list_lock, flags);
-		return -ENOMEM;
-	}
-
-	memset(urb_priv, 0, sizeof(urb_priv_t));
-	urb->hcpriv = urb_priv;
-	INIT_LIST_HEAD (&urb_priv->desc_list);
-
-	dbg("submit_urb: scheduling %p", urb);
-	
-	if (type == PIPE_CONTROL)
-		urb_priv->setup_packet_dma = pci_map_single(s->uhci_pci, urb->setup_packet,
-							    sizeof(struct usb_ctrlrequest), PCI_DMA_TODEVICE);
-
-	if (urb->transfer_buffer_length)
-		urb_priv->transfer_buffer_dma = pci_map_single(s->uhci_pci,
-							       urb->transfer_buffer,
-							       urb->transfer_buffer_length,
-							       usb_pipein(urb->pipe) ?
-							       PCI_DMA_FROMDEVICE :
-							       PCI_DMA_TODEVICE);
-
-	if (type == PIPE_BULK) {
-	
-		if (queued_urb) {
-			while (((urb_priv_t*)queued_urb->hcpriv)->next_queued_urb)  // find last queued bulk
-				queued_urb=((urb_priv_t*)queued_urb->hcpriv)->next_queued_urb;
-			
-			((urb_priv_t*)queued_urb->hcpriv)->next_queued_urb=urb;
-		}
-		atomic_inc (&s->avoid_bulk);
-		ret = uhci_submit_bulk_urb (urb, queued_urb);
-		atomic_dec (&s->avoid_bulk);
-		spin_unlock_irqrestore (&s->urb_list_lock, flags);
-	}
-	else {
-		spin_unlock_irqrestore (&s->urb_list_lock, flags);
-		switch (type) {
-		case PIPE_ISOCHRONOUS:			
-			if (urb->bandwidth == 0) {      /* not yet checked/allocated */
-				if (urb->number_of_packets <= 0) {
-					ret = -EINVAL;
-					break;
-				}
-
-				bustime = usb_check_bandwidth (urb->dev, urb);
-				if (bustime < 0) 
-					ret = bustime;
-				else {
-					ret = uhci_submit_iso_urb(urb);
-					if (ret == 0)
-						usb_claim_bandwidth (urb->dev, urb, bustime, 1);
-				}
-			} else {        /* bandwidth is already set */
-				ret = uhci_submit_iso_urb(urb);
-			}
-			break;
-		case PIPE_INTERRUPT:
-			if (urb->bandwidth == 0) {      /* not yet checked/allocated */
-				bustime = usb_check_bandwidth (urb->dev, urb);
-				if (bustime < 0)
-					ret = bustime;
-				else {
-					ret = uhci_submit_int_urb(urb);
-					if (ret == 0)
-						usb_claim_bandwidth (urb->dev, urb, bustime, 0);
-				}
-			} else {        /* bandwidth is already set */
-				ret = uhci_submit_int_urb(urb);
-			}
-			break;
-		case PIPE_CONTROL:
-			ret = uhci_submit_control_urb (urb);
-			break;
-		default:
-			ret = -EINVAL;
-		}
-	}
-
-	dbg("submit_urb: scheduled with ret: %d", ret);
-	
-	if (ret != 0) {
-		uhci_urb_dma_unmap(s, urb, urb_priv);
-		usb_dec_dev_use (urb->dev);
-#ifdef DEBUG_SLAB
-		kmem_cache_free(urb_priv_kmem, urb_priv);
-#else
-		kfree (urb_priv);
-#endif
-		return ret;
-	}
-
-	return 0;
-}
-
-// Checks for URB timeout and removes bandwidth reclamation if URB idles too long
-_static void uhci_check_timeouts(uhci_t *s)
-{
-	struct list_head *p,*p2;
-	struct urb *urb;
-	int type;	
-
-	p = s->urb_list.prev;	
-
-	while (p != &s->urb_list) {
-		urb_priv_t *hcpriv;
-
-		p2 = p;
-		p = p->prev;
-		urb = list_entry (p2, struct urb, urb_list);
-		type = usb_pipetype (urb->pipe);
-
-		hcpriv = (urb_priv_t*)urb->hcpriv;
-		
-		if ( urb->timeout && time_after(jiffies, hcpriv->started + urb->timeout)) {
-			urb->transfer_flags |= USB_TIMEOUT_KILLED | USB_ASYNC_UNLINK;
-			async_dbg("uhci_check_timeout: timeout for %p",urb);
-			uhci_unlink_urb_async(s, urb, UNLINK_ASYNC_STORE_URB);
-		}
-#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
-		else if (((type == PIPE_BULK) || (type == PIPE_CONTROL)) &&  
-			 (hcpriv->use_loop) && time_after(jiffies, hcpriv->started + IDLE_TIMEOUT))
-			disable_desc_loop(s, urb);
-#endif
-
-	}
-	s->timeout_check=jiffies;
-}
-
-/*-------------------------------------------------------------------
- Virtual Root Hub
- -------------------------------------------------------------------*/
-
-_static __u8 root_hub_dev_des[] =
-{
-	0x12,			/*  __u8  bLength; */
-	0x01,			/*  __u8  bDescriptorType; Device */
-	0x00,			/*  __u16 bcdUSB; v1.0 */
-	0x01,
-	0x09,			/*  __u8  bDeviceClass; HUB_CLASSCODE */
-	0x00,			/*  __u8  bDeviceSubClass; */
-	0x00,			/*  __u8  bDeviceProtocol; */
-	0x08,			/*  __u8  bMaxPacketSize0; 8 Bytes */
-	0x00,			/*  __u16 idVendor; */
-	0x00,
-	0x00,			/*  __u16 idProduct; */
-	0x00,
-	0x00,			/*  __u16 bcdDevice; */
-	0x00,
-	0x00,			/*  __u8  iManufacturer; */
-	0x02,			/*  __u8  iProduct; */
-	0x01,			/*  __u8  iSerialNumber; */
-	0x01			/*  __u8  bNumConfigurations; */
-};
-
-
-/* Configuration descriptor */
-_static __u8 root_hub_config_des[] =
-{
-	0x09,			/*  __u8  bLength; */
-	0x02,			/*  __u8  bDescriptorType; Configuration */
-	0x19,			/*  __u16 wTotalLength; */
-	0x00,
-	0x01,			/*  __u8  bNumInterfaces; */
-	0x01,			/*  __u8  bConfigurationValue; */
-	0x00,			/*  __u8  iConfiguration; */
-	0x40,			/*  __u8  bmAttributes; 
-				   Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
-	0x00,			/*  __u8  MaxPower; */
-
-     /* interface */
-	0x09,			/*  __u8  if_bLength; */
-	0x04,			/*  __u8  if_bDescriptorType; Interface */
-	0x00,			/*  __u8  if_bInterfaceNumber; */
-	0x00,			/*  __u8  if_bAlternateSetting; */
-	0x01,			/*  __u8  if_bNumEndpoints; */
-	0x09,			/*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
-	0x00,			/*  __u8  if_bInterfaceSubClass; */
-	0x00,			/*  __u8  if_bInterfaceProtocol; */
-	0x00,			/*  __u8  if_iInterface; */
-
-     /* endpoint */
-	0x07,			/*  __u8  ep_bLength; */
-	0x05,			/*  __u8  ep_bDescriptorType; Endpoint */
-	0x81,			/*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
-	0x03,			/*  __u8  ep_bmAttributes; Interrupt */
-	0x08,			/*  __u16 ep_wMaxPacketSize; 8 Bytes */
-	0x00,
-	0xff			/*  __u8  ep_bInterval; 255 ms */
-};
-
-
-_static __u8 root_hub_hub_des[] =
-{
-	0x09,			/*  __u8  bLength; */
-	0x29,			/*  __u8  bDescriptorType; Hub-descriptor */
-	0x02,			/*  __u8  bNbrPorts; */
-	0x00,			/* __u16  wHubCharacteristics; */
-	0x00,
-	0x01,			/*  __u8  bPwrOn2pwrGood; 2ms */
-	0x00,			/*  __u8  bHubContrCurrent; 0 mA */
-	0x00,			/*  __u8  DeviceRemovable; *** 7 Ports max *** */
-	0xff			/*  __u8  PortPwrCtrlMask; *** 7 ports max *** */
-};
-
-/*-------------------------------------------------------------------------*/
-/* prepare Interrupt pipe transaction data; HUB INTERRUPT ENDPOINT */
-_static int rh_send_irq (struct urb *urb)
-{
-	int len = 1;
-	int i;
-	uhci_t *uhci = urb->dev->bus->hcpriv;
-	unsigned int io_addr = uhci->io_addr;
-	__u16 data = 0;
-
-	for (i = 0; i < uhci->rh.numports; i++) {
-		data |= ((inw (io_addr + USBPORTSC1 + i * 2) & 0xa) > 0 ? (1 << (i + 1)) : 0);
-		len = (i + 1) / 8 + 1;
-	}
-
-	*(__u16 *) urb->transfer_buffer = cpu_to_le16 (data);
-	urb->actual_length = len;
-	urb->status = 0;
-	
-	if ((data > 0) && (uhci->rh.send != 0)) {
-		dbg("Root-Hub INT complete: port1: %x port2: %x data: %x",
-		     inw (io_addr + USBPORTSC1), inw (io_addr + USBPORTSC2), data);
-		urb->complete (urb);
-	}
-	return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-/* Virtual Root Hub INTs are polled by this timer every "intervall" ms */
-_static int rh_init_int_timer (struct urb *urb);
-
-_static void rh_int_timer_do (unsigned long ptr)
-{
-	int len;
-	struct urb *urb = (struct urb*) ptr;
-	uhci_t *uhci = urb->dev->bus->hcpriv;
-
-	if (uhci->rh.send) {
-		len = rh_send_irq (urb);
-		if (len > 0) {
-			urb->actual_length = len;
-			if (urb->complete)
-				urb->complete (urb);
-		}
-	}
-	rh_init_int_timer (urb);
-}
-
-/*-------------------------------------------------------------------------*/
-/* Root Hub INTs are polled by this timer, polling interval 20ms */
-
-_static int rh_init_int_timer (struct urb *urb)
-{
-	uhci_t *uhci = urb->dev->bus->hcpriv;
-
-	uhci->rh.interval = urb->interval;
-	init_timer (&uhci->rh.rh_int_timer);
-	uhci->rh.rh_int_timer.function = rh_int_timer_do;
-	uhci->rh.rh_int_timer.data = (unsigned long) urb;
-	uhci->rh.rh_int_timer.expires = jiffies + (HZ * 20) / 1000;
-	add_timer (&uhci->rh.rh_int_timer);
-
-	return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-#define OK(x) 			len = (x); break
-
-#define CLR_RH_PORTSTAT(x) \
-		status = inw(io_addr+USBPORTSC1+2*(wIndex-1)); \
-		status = (status & 0xfff5) & ~(x); \
-		outw(status, io_addr+USBPORTSC1+2*(wIndex-1))
-
-#define SET_RH_PORTSTAT(x) \
-		status = inw(io_addr+USBPORTSC1+2*(wIndex-1)); \
-		status = (status & 0xfff5) | (x); \
-		outw(status, io_addr+USBPORTSC1+2*(wIndex-1))
-
-
-/*-------------------------------------------------------------------------*/
-/****
- ** Root Hub Control Pipe
- *************************/
-
-
-_static int rh_submit_urb (struct urb *urb)
-{
-	struct usb_device *usb_dev = urb->dev;
-	uhci_t *uhci = usb_dev->bus->hcpriv;
-	unsigned int pipe = urb->pipe;
-	struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *) urb->setup_packet;
-	void *data = urb->transfer_buffer;
-	int leni = urb->transfer_buffer_length;
-	int len = 0;
-	int status = 0;
-	int stat = 0;
-	int i;
-	unsigned int io_addr = uhci->io_addr;
-	__u16 cstatus;
-
-	__u16 bmRType_bReq;
-	__u16 wValue;
-	__u16 wIndex;
-	__u16 wLength;
-
-	if (usb_pipetype (pipe) == PIPE_INTERRUPT) {
-		dbg("Root-Hub submit IRQ: every %d ms", urb->interval);
-		uhci->rh.urb = urb;
-		uhci->rh.send = 1;
-		uhci->rh.interval = urb->interval;
-		rh_init_int_timer (urb);
-
-		return 0;
-	}
-
-
-	bmRType_bReq = cmd->bRequestType | cmd->bRequest << 8;
-	wValue = le16_to_cpu (cmd->wValue);
-	wIndex = le16_to_cpu (cmd->wIndex);
-	wLength = le16_to_cpu (cmd->wLength);
-
-	for (i = 0; i < 8; i++)
-		uhci->rh.c_p_r[i] = 0;
-
-	dbg("Root-Hub: adr: %2x cmd(%1x): %04x %04x %04x %04x",
-	     uhci->rh.devnum, 8, bmRType_bReq, wValue, wIndex, wLength);
-
-	switch (bmRType_bReq) {
-		/* Request Destination:
-		   without flags: Device, 
-		   RH_INTERFACE: interface, 
-		   RH_ENDPOINT: endpoint,
-		   RH_CLASS means HUB here, 
-		   RH_OTHER | RH_CLASS  almost ever means HUB_PORT here 
-		 */
-
-	case RH_GET_STATUS:
-		*(__u16 *) data = cpu_to_le16 (1);
-		OK (2);
-	case RH_GET_STATUS | RH_INTERFACE:
-		*(__u16 *) data = cpu_to_le16 (0);
-		OK (2);
-	case RH_GET_STATUS | RH_ENDPOINT:
-		*(__u16 *) data = cpu_to_le16 (0);
-		OK (2);
-	case RH_GET_STATUS | RH_CLASS:
-		*(__u32 *) data = cpu_to_le32 (0);
-		OK (4);		/* hub power ** */
-	case RH_GET_STATUS | RH_OTHER | RH_CLASS:
-		status = inw (io_addr + USBPORTSC1 + 2 * (wIndex - 1));
-		cstatus = ((status & USBPORTSC_CSC) >> (1 - 0)) |
-			((status & USBPORTSC_PEC) >> (3 - 1)) |
-			(uhci->rh.c_p_r[wIndex - 1] << (0 + 4));
-		status = (status & USBPORTSC_CCS) |
-			((status & USBPORTSC_PE) >> (2 - 1)) |
-			((status & USBPORTSC_SUSP) >> (12 - 2)) |
-			((status & USBPORTSC_PR) >> (9 - 4)) |
-			(1 << 8) |	/* power on ** */
-			((status & USBPORTSC_LSDA) << (-8 + 9));
-
-		*(__u16 *) data = cpu_to_le16 (status);
-		*(__u16 *) (data + 2) = cpu_to_le16 (cstatus);
-		OK (4);
-
-	case RH_CLEAR_FEATURE | RH_ENDPOINT:
-		switch (wValue) {
-		case (RH_ENDPOINT_STALL):
-			OK (0);
-		}
-		break;
-
-	case RH_CLEAR_FEATURE | RH_CLASS:
-		switch (wValue) {
-		case (RH_C_HUB_OVER_CURRENT):
-			OK (0);	/* hub power over current ** */
-		}
-		break;
-
-	case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
-		switch (wValue) {
-		case (RH_PORT_ENABLE):
-			CLR_RH_PORTSTAT (USBPORTSC_PE);
-			OK (0);
-		case (RH_PORT_SUSPEND):
-			CLR_RH_PORTSTAT (USBPORTSC_SUSP);
-			OK (0);
-		case (RH_PORT_POWER):
-			OK (0);	/* port power ** */
-		case (RH_C_PORT_CONNECTION):
-			SET_RH_PORTSTAT (USBPORTSC_CSC);
-			OK (0);
-		case (RH_C_PORT_ENABLE):
-			SET_RH_PORTSTAT (USBPORTSC_PEC);
-			OK (0);
-		case (RH_C_PORT_SUSPEND):
-/*** WR_RH_PORTSTAT(RH_PS_PSSC); */
-			OK (0);
-		case (RH_C_PORT_OVER_CURRENT):
-			OK (0);	/* port power over current ** */
-		case (RH_C_PORT_RESET):
-			uhci->rh.c_p_r[wIndex - 1] = 0;
-			OK (0);
-		}
-		break;
-
-	case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
-		switch (wValue) {
-		case (RH_PORT_SUSPEND):
-			SET_RH_PORTSTAT (USBPORTSC_SUSP);
-			OK (0);
-		case (RH_PORT_RESET):
-			SET_RH_PORTSTAT (USBPORTSC_PR);
-			uhci_wait_ms (10);
-			uhci->rh.c_p_r[wIndex - 1] = 1;
-			CLR_RH_PORTSTAT (USBPORTSC_PR);
-			udelay (10);
-			SET_RH_PORTSTAT (USBPORTSC_PE);
-			uhci_wait_ms (10);
-			SET_RH_PORTSTAT (0xa);
-			OK (0);
-		case (RH_PORT_POWER):
-			OK (0);	/* port power ** */
-		case (RH_PORT_ENABLE):
-			SET_RH_PORTSTAT (USBPORTSC_PE);
-			OK (0);
-		}
-		break;
-
-	case RH_SET_ADDRESS:
-		uhci->rh.devnum = wValue;
-		OK (0);
-
-	case RH_GET_DESCRIPTOR:
-		switch ((wValue & 0xff00) >> 8) {
-		case (0x01):	/* device descriptor */
-			len = min_t(unsigned int, leni,
-				  min_t(unsigned int,
-				      sizeof (root_hub_dev_des), wLength));
-			memcpy (data, root_hub_dev_des, len);
-			OK (len);
-		case (0x02):	/* configuration descriptor */
-			len = min_t(unsigned int, leni,
-				  min_t(unsigned int,
-				      sizeof (root_hub_config_des), wLength));
-			memcpy (data, root_hub_config_des, len);
-			OK (len);
-		case (0x03):	/* string descriptors */
-			len = usb_root_hub_string (wValue & 0xff,
-			        uhci->io_addr, "UHCI",
-				data, wLength);
-			if (len > 0) {
-				OK(min_t(int, leni, len));
-			} else 
-				stat = -EPIPE;
-		}
-		break;
-
-	case RH_GET_DESCRIPTOR | RH_CLASS:
-		root_hub_hub_des[2] = uhci->rh.numports;
-		len = min_t(unsigned int, leni,
-			  min_t(unsigned int, sizeof (root_hub_hub_des), wLength));
-		memcpy (data, root_hub_hub_des, len);
-		OK (len);
-
-	case RH_GET_CONFIGURATION:
-		*(__u8 *) data = 0x01;
-		OK (1);
-
-	case RH_SET_CONFIGURATION:
-		OK (0);
-	default:
-		stat = -EPIPE;
-	}
-
-	dbg("Root-Hub stat port1: %x port2: %x",
-	     inw (io_addr + USBPORTSC1), inw (io_addr + USBPORTSC2));
-
-	urb->actual_length = len;
-	urb->status = stat;
-	urb->dev=NULL;
-	if (urb->complete)
-		urb->complete (urb);
-	return 0;
-}
-/*-------------------------------------------------------------------------*/
-
-_static int rh_unlink_urb (struct urb *urb)
-{
-	uhci_t *uhci = urb->dev->bus->hcpriv;
-
-	if (uhci->rh.urb==urb) {
-		dbg("Root-Hub unlink IRQ");
-		uhci->rh.send = 0;
-		del_timer (&uhci->rh.rh_int_timer);
-	}
-	return 0;
-}
-/*-------------------------------------------------------------------*/
-
-/*
- * Map status to standard result codes
- *
- * <status> is (td->status & 0xFE0000) [a.k.a. uhci_status_bits(td->status)
- * <dir_out> is True for output TDs and False for input TDs.
- */
-_static int uhci_map_status (int status, int dir_out)
-{
-	if (!status)
-		return 0;
-	if (status & TD_CTRL_BITSTUFF)	/* Bitstuff error */
-		return -EPROTO;
-	if (status & TD_CTRL_CRCTIMEO) {	/* CRC/Timeout */
-		if (dir_out)
-			return -ETIMEDOUT;
-		else
-			return -EILSEQ;
-	}
-	if (status & TD_CTRL_NAK)	/* NAK */
-		return -ETIMEDOUT;
-	if (status & TD_CTRL_BABBLE)	/* Babble */
-		return -EOVERFLOW;
-	if (status & TD_CTRL_DBUFERR)	/* Buffer error */
-		return -ENOSR;
-	if (status & TD_CTRL_STALLED)	/* Stalled */
-		return -EPIPE;
-	if (status & TD_CTRL_ACTIVE)	/* Active */
-		return 0;
-
-	return -EPROTO;
-}
-
-/*
- * Only the USB core should call uhci_alloc_dev and uhci_free_dev
- */
-_static int uhci_alloc_dev (struct usb_device *usb_dev)
-{
-	return 0;
-}
-
-_static void uhci_unlink_urbs(uhci_t *s, struct usb_device *usb_dev, int remove_all)
-{
-	unsigned long flags;
-	struct list_head *p;
-	struct list_head *p2;
-	struct urb *urb;
-
-	spin_lock_irqsave (&s->urb_list_lock, flags);
-	p = s->urb_list.prev;	
-	while (p != &s->urb_list) {
-		p2 = p;
-		p = p->prev ;
-		urb = list_entry (p2, struct urb, urb_list);
-		dbg("urb: %p, dev %p, %p", urb, usb_dev,urb->dev);
-		
-		//urb->transfer_flags |=USB_ASYNC_UNLINK; 
-			
-		if (remove_all || (usb_dev == urb->dev)) {
-			spin_unlock_irqrestore (&s->urb_list_lock, flags);
-			warn("forced removing of queued URB %p due to disconnect",urb);
-			uhci_unlink_urb(urb);
-			urb->dev = NULL; // avoid further processing of this URB
-			spin_lock_irqsave (&s->urb_list_lock, flags);
-			p = s->urb_list.prev;	
-		}
-	}
-	spin_unlock_irqrestore (&s->urb_list_lock, flags);
-}
-
-_static int uhci_free_dev (struct usb_device *usb_dev)
-{
-	uhci_t *s;
-	
-
-	if(!usb_dev || !usb_dev->bus || !usb_dev->bus->hcpriv)
-		return -EINVAL;
-	
-	s=(uhci_t*) usb_dev->bus->hcpriv;	
-	uhci_unlink_urbs(s, usb_dev, 0);
-
-	return 0;
-}
-
-/*
- * uhci_get_current_frame_number()
- *
- * returns the current frame number for a USB bus/controller.
- */
-_static int uhci_get_current_frame_number (struct usb_device *usb_dev)
-{
-	return UHCI_GET_CURRENT_FRAME ((uhci_t*) usb_dev->bus->hcpriv);
-}
-
-struct usb_operations uhci_device_operations =
-{
-	uhci_alloc_dev,
-	uhci_free_dev,
-	uhci_get_current_frame_number,
-	uhci_submit_urb,
-	uhci_unlink_urb
-};
-
-_static void correct_data_toggles(struct urb *urb)
-{
-	usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe), 
-		       !usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe)));
-
-	while(urb) {
-		urb_priv_t *priv=urb->hcpriv;		
-		uhci_desc_t *qh = list_entry (priv->desc_list.next, uhci_desc_t, desc_list);
-		struct list_head *p = qh->vertical.next;
-		uhci_desc_t *td;
-		dbg("URB to correct %p\n", urb);
-	
-		for (; p != &qh->vertical; p = p->next) {
-			td = list_entry (p, uhci_desc_t, vertical);
-			td->hw.td.info^=cpu_to_le32(1<<TD_TOKEN_TOGGLE);
-		}
-		urb=priv->next_queued_urb;
-	}
-}
-
-/* 
- * For IN-control transfers, process_transfer gets a bit more complicated,
- * since there are devices that return less data (eg. strings) than they
- * have announced. This leads to a queue abort due to the short packet,
- * the status stage is not executed. If this happens, the status stage
- * is manually re-executed.
- * mode: PROCESS_TRANSFER_REGULAR: regular (unlink QH)
- *       PROCESS_TRANSFER_DONT_UNLINK: QHs already unlinked (for async unlink_urb)
- */
-
-_static int process_transfer (uhci_t *s, struct urb *urb, int mode)
-{
-	int ret = 0;
-	urb_priv_t *urb_priv = urb->hcpriv;
-	struct list_head *qhl = urb_priv->desc_list.next;
-	uhci_desc_t *qh = list_entry (qhl, uhci_desc_t, desc_list);
-	struct list_head *p = qh->vertical.next;
-	uhci_desc_t *desc= list_entry (urb_priv->desc_list.prev, uhci_desc_t, desc_list);
-	uhci_desc_t *last_desc = list_entry (desc->vertical.prev, uhci_desc_t, vertical);
-	int data_toggle = usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));	// save initial data_toggle
-	int maxlength; 	// extracted and remapped info from TD
-	int actual_length;
-	int status = 0;
-
-	//dbg("process_transfer: urb %p, urb_priv %p, qh %p last_desc %p\n",urb,urb_priv, qh, last_desc);
-
-	/* if the status phase has been retriggered and the
-	   queue is empty or the last status-TD is inactive, the retriggered
-	   status stage is completed
-	 */
-
-	if (urb_priv->flags && 
-	    ((qh->hw.qh.element == cpu_to_le32(UHCI_PTR_TERM)) || !is_td_active(desc)))
-		goto transfer_finished;
-
-	urb->actual_length=0;
-
-	for (; p != &qh->vertical; p = p->next) {
-		desc = list_entry (p, uhci_desc_t, vertical);
-
-		if (is_td_active(desc)) {	// do not process active TDs
-			if (mode == CLEAN_TRANSFER_DELETION_MARK) // if called from async_unlink
-				uhci_clean_transfer(s, urb, qh, CLEAN_TRANSFER_DELETION_MARK);
-			return ret;
-		}
-	
-		actual_length = uhci_actual_length(le32_to_cpu(desc->hw.td.status));		// extract transfer parameters from TD
-		maxlength = (((le32_to_cpu(desc->hw.td.info) >> 21) & 0x7ff) + 1) & 0x7ff;
-		status = uhci_map_status (uhci_status_bits (le32_to_cpu(desc->hw.td.status)), usb_pipeout (urb->pipe));
-
-		if (status == -EPIPE) { 		// see if EP is stalled
-			// set up stalled condition
-			usb_endpoint_halt (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
-		}
-
-		if (status && (status != -EPIPE)) {	// if any error occurred stop processing of further TDs
-			// only set ret if status returned an error
-  is_error:
-			ret = status;
-			urb->error_count++;
-			break;
-		}
-		else if ((le32_to_cpu(desc->hw.td.info) & 0xff) != USB_PID_SETUP)
-			urb->actual_length += actual_length;
-
-		// got less data than requested
-		if ( (actual_length < maxlength)) {
-			if (urb->transfer_flags & USB_DISABLE_SPD) {
-				status = -EREMOTEIO;	// treat as real error
-				dbg("process_transfer: SPD!!");
-				break;	// exit after this TD because SP was detected
-			}
-
-			// short read during control-IN: re-start status stage
-			if ((usb_pipetype (urb->pipe) == PIPE_CONTROL)) {
-				if (uhci_packetid(le32_to_cpu(last_desc->hw.td.info)) == USB_PID_OUT) {
-			
-					set_qh_element(qh, last_desc->dma_addr);  // re-trigger status stage
-					dbg("short packet during control transfer, retrigger status stage @ %p",last_desc);
-					urb_priv->flags = 1; // mark as short control packet
-					return 0;
-				}
-			}
-			// all other cases: short read is OK
-			data_toggle = uhci_toggle (le32_to_cpu(desc->hw.td.info));
-			break;
-		}
-		else if (status)
-			goto is_error;
-
-		data_toggle = uhci_toggle (le32_to_cpu(desc->hw.td.info));
-		queue_dbg("process_transfer: len:%d status:%x mapped:%x toggle:%d", actual_length, le32_to_cpu(desc->hw.td.status),status, data_toggle);      
-
-	}
-
-	if (usb_pipetype (urb->pipe) == PIPE_BULK ) {  /* toggle correction for short bulk transfers (nonqueued/queued) */
-
-		urb_priv_t *priv=(urb_priv_t*)urb->hcpriv;
-		struct urb *next_queued_urb=priv->next_queued_urb;
-
-		if (next_queued_urb) {
-			urb_priv_t *next_priv=(urb_priv_t*)next_queued_urb->hcpriv;
-			uhci_desc_t *qh = list_entry (next_priv->desc_list.next, uhci_desc_t, desc_list);
-			uhci_desc_t *first_td=list_entry (qh->vertical.next, uhci_desc_t, vertical);
-
-			if (data_toggle == uhci_toggle (le32_to_cpu(first_td->hw.td.info))) {
-				err("process_transfer: fixed toggle");
-				correct_data_toggles(next_queued_urb);
-			}						
-		}
-		else
-			usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe), !data_toggle);		
-	}
-
- transfer_finished:
-	
-	uhci_clean_transfer(s, urb, qh, mode);
-
-	urb->status = status;
-
-#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH	
-	disable_desc_loop(s,urb);
-#endif	
-
-	queue_dbg("process_transfer: (end) urb %p, wanted len %d, len %d status %x err %d",
-		urb,urb->transfer_buffer_length,urb->actual_length, urb->status, urb->error_count);
-	return ret;
-}
-
-_static int process_interrupt (uhci_t *s, struct urb *urb)
-{
-	int i, ret = -EINPROGRESS;
-	urb_priv_t *urb_priv = urb->hcpriv;
-	struct list_head *p = urb_priv->desc_list.next;
-	uhci_desc_t *desc = list_entry (urb_priv->desc_list.prev, uhci_desc_t, desc_list);
-
-	int actual_length;
-	int status = 0;
-
-	//dbg("urb contains interrupt request");
-
-	for (i = 0; p != &urb_priv->desc_list; p = p->next, i++)	// Maybe we allow more than one TD later ;-)
-	{
-		desc = list_entry (p, uhci_desc_t, desc_list);
-
-		if (is_td_active(desc)) {
-			// do not process active TDs
-			//dbg("TD ACT Status @%p %08x",desc,le32_to_cpu(desc->hw.td.status));
-			break;
-		}
-
-		if (!(desc->hw.td.status & cpu_to_le32(TD_CTRL_IOC))) {
-			// do not process one-shot TDs, no recycling
-			break;
-		}
-		// extract transfer parameters from TD
-
-		actual_length = uhci_actual_length(le32_to_cpu(desc->hw.td.status));
-		status = uhci_map_status (uhci_status_bits (le32_to_cpu(desc->hw.td.status)), usb_pipeout (urb->pipe));
-
-		// see if EP is stalled
-		if (status == -EPIPE) {
-			// set up stalled condition
-			usb_endpoint_halt (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
-		}
-
-		// if any error occurred: ignore this td, and continue
-		if (status != 0) {
-			//uhci_show_td (desc);
-			urb->error_count++;
-			goto recycle;
-		}
-		else
-			urb->actual_length = actual_length;
-
-	recycle:
-		uhci_urb_dma_sync(s, urb, urb->hcpriv);
-		if (urb->complete) {
-			//dbg("process_interrupt: calling completion, status %i",status);
-			urb->status = status;
-			((urb_priv_t*)urb->hcpriv)->flags=1; // if unlink_urb is called during completion
-
-			spin_unlock(&s->urb_list_lock);
-			
-			urb->complete ((struct urb *) urb);
-			
-			spin_lock(&s->urb_list_lock);
-
-			((urb_priv_t*)urb->hcpriv)->flags=0;		       			
-		}
-		
-		if ((urb->status != -ECONNABORTED) && (urb->status != ECONNRESET) &&
-			    (urb->status != -ENOENT)) {
-
-			urb->status = -EINPROGRESS;
-
-			// Recycle INT-TD if interval!=0, else mark TD as one-shot
-			if (urb->interval) {
-				
-				desc->hw.td.info &= cpu_to_le32(~(1 << TD_TOKEN_TOGGLE));
-				if (status==0) {
-					((urb_priv_t*)urb->hcpriv)->started=jiffies;
-					desc->hw.td.info |= cpu_to_le32((usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe),
-									    usb_pipeout (urb->pipe)) << TD_TOKEN_TOGGLE));
-					usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
-				} else {
-					desc->hw.td.info |= cpu_to_le32((!usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe),
-									     usb_pipeout (urb->pipe)) << TD_TOKEN_TOGGLE));
-				}
-				desc->hw.td.status= cpu_to_le32((urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC |
-					(urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27));
-				mb();
-			}
-			else {
-				uhci_unlink_urb_async(s, urb, UNLINK_ASYNC_STORE_URB);
-				// correct toggle after unlink
-				usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
-				clr_td_ioc(desc); // inactivate TD
-			}
-		}
-	}
-
-	return ret;
-}
-
-// mode: PROCESS_ISO_REGULAR: processing only for done TDs, unlink TDs
-// mode: PROCESS_ISO_FORCE: force processing, don't unlink TDs (already unlinked)
-
-_static int process_iso (uhci_t *s, struct urb *urb, int mode)
-{
-	int i;
-	int ret = 0;
-	urb_priv_t *urb_priv = urb->hcpriv;
-	struct list_head *p = urb_priv->desc_list.next, *p_tmp;
-	uhci_desc_t *desc = list_entry (urb_priv->desc_list.prev, uhci_desc_t, desc_list);
-
-	dbg("urb contains iso request");
-	if (is_td_active(desc) && mode==PROCESS_ISO_REGULAR)
-		return -EXDEV;	// last TD not finished
-
-	urb->error_count = 0;
-	urb->actual_length = 0;
-	urb->status = 0;
-	dbg("process iso urb %p, %li, %i, %i, %i %08x",urb,jiffies,UHCI_GET_CURRENT_FRAME(s),
-	    urb->number_of_packets,mode,le32_to_cpu(desc->hw.td.status));
-
-	for (i = 0; p != &urb_priv->desc_list;  i++) {
-		desc = list_entry (p, uhci_desc_t, desc_list);
-		
-		//uhci_show_td(desc);
-		if (is_td_active(desc)) {
-			// means we have completed the last TD, but not the TDs before
-			desc->hw.td.status &= cpu_to_le32(~TD_CTRL_ACTIVE);
-			dbg("TD still active (%x)- grrr. paranoia!", le32_to_cpu(desc->hw.td.status));
-			ret = -EXDEV;
-			urb->iso_frame_desc[i].status = ret;
-			unlink_td (s, desc, 1);
-			// FIXME: immediate deletion may be dangerous
-			goto err;
-		}
-
-		if (mode == PROCESS_ISO_REGULAR)
-			unlink_td (s, desc, 1);
-
-		if (urb->number_of_packets <= i) {
-			dbg("urb->number_of_packets (%d)<=(%d)", urb->number_of_packets, i);
-			ret = -EINVAL;
-			goto err;
-		}
-
-		urb->iso_frame_desc[i].actual_length = uhci_actual_length(le32_to_cpu(desc->hw.td.status));
-		urb->iso_frame_desc[i].status = uhci_map_status (uhci_status_bits (le32_to_cpu(desc->hw.td.status)), usb_pipeout (urb->pipe));
-		urb->actual_length += urb->iso_frame_desc[i].actual_length;
-
-	      err:
-
-		if (urb->iso_frame_desc[i].status != 0) {
-			urb->error_count++;
-			urb->status = urb->iso_frame_desc[i].status;
-		}
-		dbg("process_iso: %i: len:%d %08x status:%x",
-		     i, urb->iso_frame_desc[i].actual_length, le32_to_cpu(desc->hw.td.status),urb->iso_frame_desc[i].status);
-
-		p_tmp = p;
-		p = p->next;
-		list_del (p_tmp);
-		delete_desc (s, desc);
-	}
-	
-	dbg("process_iso: exit %i (%d), actual_len %i", i, ret,urb->actual_length);
-	return ret;
-}
-
-
-_static int process_urb (uhci_t *s, struct list_head *p)
-{
-	int ret = 0;
-	struct urb *urb;
-
-	urb=list_entry (p, struct urb, urb_list);
-	//dbg("process_urb: found queued urb: %p", urb);
-
-	switch (usb_pipetype (urb->pipe)) {
-	case PIPE_CONTROL:
-		ret = process_transfer (s, urb, CLEAN_TRANSFER_REGULAR);
-		break;
-	case PIPE_BULK:
-		if (!s->avoid_bulk.counter)
-			ret = process_transfer (s, urb, CLEAN_TRANSFER_REGULAR);
-		else
-			return 0;
-		break;
-	case PIPE_ISOCHRONOUS:
-		ret = process_iso (s, urb, PROCESS_ISO_REGULAR);
-		break;
-	case PIPE_INTERRUPT:
-		ret = process_interrupt (s, urb);
-		break;
-	}
-
-	if (urb->status != -EINPROGRESS) {
-		urb_priv_t *urb_priv;
-		struct usb_device *usb_dev;
-		
-		usb_dev=urb->dev;
-
-		/* Release bandwidth for Interrupt or Iso transfers */
-		if (urb->bandwidth) {
-			if (usb_pipetype(urb->pipe)==PIPE_ISOCHRONOUS)
-				usb_release_bandwidth (urb->dev, urb, 1);
-			else if (usb_pipetype(urb->pipe)==PIPE_INTERRUPT && urb->interval)
-				usb_release_bandwidth (urb->dev, urb, 0);
-		}
-
-		dbg("dequeued urb: %p", urb);
-		dequeue_urb (s, urb);
-
-		urb_priv = urb->hcpriv;
-
-		uhci_urb_dma_unmap(s, urb, urb_priv);
-
-#ifdef DEBUG_SLAB
-		kmem_cache_free(urb_priv_kmem, urb_priv);
-#else
-		kfree (urb_priv);
-#endif
-
-		if ((usb_pipetype (urb->pipe) != PIPE_INTERRUPT)) {  // process_interrupt does completion on its own		
-			struct urb *next_urb = urb->next;
-			int is_ring = 0;
-			int contains_killed = 0;
-			int loop_count=0;
-			
-			if (next_urb) {
-				// Find out if the URBs are linked to a ring
-				while  (next_urb != NULL && next_urb != urb && loop_count < MAX_NEXT_COUNT) {
-					if (next_urb->status == -ENOENT) {// killed URBs break ring structure & resubmission
-						contains_killed = 1;
-						break;
-					}	
-					next_urb = next_urb->next;
-					loop_count++;
-				}
-				
-				if (loop_count == MAX_NEXT_COUNT)
-					err("process_urb: Too much linked URBs in ring detection!");
-
-				if (next_urb == urb)
-					is_ring=1;
-			}			
-
-			// Submit idle/non-killed URBs linked with urb->next
-			// Stop before the current URB				
-			
-			next_urb = urb->next;	
-			if (next_urb && !contains_killed) {
-				int ret_submit;
-				next_urb = urb->next;	
-				
-				loop_count=0;
-				while (next_urb != NULL && next_urb != urb && loop_count < MAX_NEXT_COUNT) {
-					if (next_urb->status != -EINPROGRESS) {
-					
-						if (next_urb->status == -ENOENT) 
-							break;
-
-						spin_unlock(&s->urb_list_lock);
-
-						ret_submit=uhci_submit_urb(next_urb);
-						spin_lock(&s->urb_list_lock);
-						
-						if (ret_submit)
-							break;						
-					}
-					loop_count++;
-					next_urb = next_urb->next;
-				}
-				if (loop_count == MAX_NEXT_COUNT)
-					err("process_urb: Too much linked URBs in resubmission!");
-			}
-
-			// Completion
-			if (urb->complete) {
-				int was_unlinked = (urb->status == -ENOENT);
-				urb->dev = NULL;
-				spin_unlock(&s->urb_list_lock);
-
-				urb->complete ((struct urb *) urb);
-
-				// Re-submit the URB if ring-linked
-				if (is_ring && !was_unlinked && !contains_killed) {
-					urb->dev=usb_dev;
-					uhci_submit_urb (urb);
-				}
-				spin_lock(&s->urb_list_lock);
-			}
-			
-			usb_dec_dev_use (usb_dev);
-		}
-	}
-
-	return ret;
-}
-
-_static void uhci_interrupt (int irq, void *__uhci, struct pt_regs *regs)
-{
-	uhci_t *s = __uhci;
-	unsigned int io_addr = s->io_addr;
-	unsigned short status;
-	struct list_head *p, *p2;
-	int restarts, work_done;
-	
-	/*
-	 * Read the interrupt status, and write it back to clear the
-	 * interrupt cause
-	 */
-
-	status = inw (io_addr + USBSTS);
-
-	if (!status)		/* shared interrupt, not mine */
-		return;
-
-	dbg("interrupt");
-
-	if (status != 1) {
-		// Avoid too much error messages at a time
-		if (time_after(jiffies, s->last_error_time + ERROR_SUPPRESSION_TIME)) {
-			warn("interrupt, status %x, frame# %i", status, 
-			     UHCI_GET_CURRENT_FRAME(s));
-			s->last_error_time = jiffies;
-		}
-		
-		// remove host controller halted state
-		if ((status&0x20) && (s->running)) {
-			err("Host controller halted, trying to restart.");
-			outw (USBCMD_RS | inw(io_addr + USBCMD), io_addr + USBCMD);
-		}
-		//uhci_show_status (s);
-	}
-	/*
-	 * traverse the list in *reverse* direction, because new entries
-	 * may be added at the end.
-	 * also, because process_urb may unlink the current urb,
-	 * we need to advance the list before
-	 * New: check for max. workload and restart count
-	 */
-
-	spin_lock (&s->urb_list_lock);
-
-	restarts=0;
-	work_done=0;
-
-restart:
-	s->unlink_urb_done=0;
-	p = s->urb_list.prev;	
-
-	while (p != &s->urb_list && (work_done < 1024)) {
-		p2 = p;
-		p = p->prev;
-
-		process_urb (s, p2);
-		
-		work_done++;
-
-		if (s->unlink_urb_done) {
-			s->unlink_urb_done=0;
-			restarts++;
-			
-			if (restarts<16)	// avoid endless restarts
-				goto restart;
-			else 
-				break;
-		}
-	}
-	if (time_after(jiffies, s->timeout_check + (HZ/30)))
-		uhci_check_timeouts(s);
-
-	clean_descs(s, CLEAN_NOT_FORCED);
-	uhci_cleanup_unlink(s, CLEAN_NOT_FORCED);
-	uhci_switch_timer_int(s);
-							
-	spin_unlock (&s->urb_list_lock);
-	
-	outw (status, io_addr + USBSTS);
-
-	//dbg("uhci_interrupt: done");
-}
-
-_static void reset_hc (uhci_t *s)
-{
-	unsigned int io_addr = s->io_addr;
-
-	s->apm_state = 0;
-	/* Global reset for 50ms */
-	outw (USBCMD_GRESET, io_addr + USBCMD);
-	uhci_wait_ms (50);
-	outw (0, io_addr + USBCMD);
-	uhci_wait_ms (10);
-}
-
-_static void start_hc (uhci_t *s)
-{
-	unsigned int io_addr = s->io_addr;
-	int timeout = 10;
-
-	/*
-	 * Reset the HC - this will force us to get a
-	 * new notification of any already connected
-	 * ports due to the virtual disconnect that it
-	 * implies.
-	 */
-	outw (USBCMD_HCRESET, io_addr + USBCMD);
-
-	while (inw (io_addr + USBCMD) & USBCMD_HCRESET) {
-		if (!--timeout) {
-			err("USBCMD_HCRESET timed out!");
-			break;
-		}
-		udelay(1);
-	}
-
-	/* Turn on all interrupts */
-	outw (USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP, io_addr + USBINTR);
-
-	/* Start at frame 0 */
-	outw (0, io_addr + USBFRNUM);
-	outl (s->framelist_dma, io_addr + USBFLBASEADD);
-
-	/* Run and mark it configured with a 64-byte max packet */
-	outw (USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD);
-	s->apm_state = 1;
-	s->running = 1;
-}
-
-/* No  __devexit, since it maybe called from alloc_uhci() */
-_static void
-uhci_pci_remove (struct pci_dev *dev)
-{
-	uhci_t *s = pci_get_drvdata(dev);
-	struct usb_device *root_hub = s->bus->root_hub;
-
-	s->running = 0;		    // Don't allow submit_urb
-
-	if (root_hub)
-		usb_disconnect (&root_hub);
-
-	reset_hc (s);
-	wait_ms (1);
-
-	uhci_unlink_urbs (s, 0, CLEAN_FORCED);  // Forced unlink of remaining URBs
-	uhci_cleanup_unlink (s, CLEAN_FORCED);  // force cleanup of async killed URBs
-	
-	usb_deregister_bus (s->bus);
-
-	release_region (s->io_addr, s->io_size);
-	free_irq (s->irq, s);
-	usb_free_bus (s->bus);
-	cleanup_skel (s);
-	kfree (s);
-}
-
-_static int __init uhci_start_usb (uhci_t *s)
-{				/* start it up */
-	/* connect the virtual root hub */
-	struct usb_device *usb_dev;
-
-	usb_dev = usb_alloc_dev (NULL, s->bus);
-	if (!usb_dev)
-		return -1;
-
-	s->bus->root_hub = usb_dev;
-	usb_connect (usb_dev);
-
-	if (usb_new_device (usb_dev) != 0) {
-		usb_free_dev (usb_dev);
-		return -1;
-	}
-
-	return 0;
-}
-
-#ifdef CONFIG_PM
-_static int
-uhci_pci_suspend (struct pci_dev *dev, u32 state)
-{
-	reset_hc((uhci_t *) pci_get_drvdata(dev));
-	return 0;
-}
-
-_static int
-uhci_pci_resume (struct pci_dev *dev)
-{
-	start_hc((uhci_t *) pci_get_drvdata(dev));
-	return 0;
-}
-#endif
-
-_static int __devinit alloc_uhci (struct pci_dev *dev, int irq, unsigned int io_addr, unsigned int io_size)
-{
-	uhci_t *s;
-	struct usb_bus *bus;
-	char buf[8], *bufp = buf;
-
-#ifndef __sparc__
-	sprintf(buf, "%d", irq);
-#else
-	bufp = __irq_itoa(irq);
-#endif
-	printk(KERN_INFO __FILE__ ": USB UHCI at I/O 0x%x, IRQ %s\n",
-		io_addr, bufp);
-
-	s = kmalloc (sizeof (uhci_t), GFP_KERNEL);
-	if (!s)
-		return -1;
-
-	memset (s, 0, sizeof (uhci_t));
-	INIT_LIST_HEAD (&s->free_desc);
-	INIT_LIST_HEAD (&s->urb_list);
-	INIT_LIST_HEAD (&s->urb_unlinked);
-	spin_lock_init (&s->urb_list_lock);
-	spin_lock_init (&s->qh_lock);
-	spin_lock_init (&s->td_lock);
-	atomic_set(&s->avoid_bulk, 0);
-	s->irq = -1;
-	s->io_addr = io_addr;
-	s->io_size = io_size;
-	s->uhci_pci=dev;
-
-	bus = usb_alloc_bus (&uhci_device_operations);
-	if (!bus) {
-		kfree (s);
-		return -1;
-	}
-
-	s->bus = bus;
-	bus->bus_name = dev->slot_name;
-	bus->hcpriv = s;
-
-	/* UHCI specs says devices must have 2 ports, but goes on to say */
-	/* they may have more but give no way to determine how many they */
-	/* have, so default to 2 */
-	/* According to the UHCI spec, Bit 7 is always set to 1. So we try */
-	/* to use this to our advantage */
-
-	for (s->maxports = 0; s->maxports < (io_size - 0x10) / 2; s->maxports++) {
-		unsigned int portstatus;
-
-		portstatus = inw (io_addr + 0x10 + (s->maxports * 2));
-		dbg("port %i, adr %x status %x", s->maxports,
-			io_addr + 0x10 + (s->maxports * 2), portstatus);
-		if (!(portstatus & 0x0080))
-			break;
-	}
-	warn("Detected %d ports", s->maxports);
-
-	/* This is experimental so anything less than 2 or greater than 8 is */
-	/*  something weird and we'll ignore it */
-	if (s->maxports < 2 || s->maxports > 8) {
-		dbg("Port count misdetected, forcing to 2 ports");
-		s->maxports = 2;
-	}
-
-	s->rh.numports = s->maxports;
-	s->loop_usage=0;
-	if (init_skel (s)) {
-		usb_free_bus (bus);
-		kfree(s);
-		return -1;
-	}
-
-	request_region (s->io_addr, io_size, MODNAME);
-	reset_hc (s);
-	usb_register_bus (s->bus);
-
-	start_hc (s);
-
-	if (request_irq (irq, uhci_interrupt, SA_SHIRQ, MODNAME, s)) {
-		err("request_irq %d failed!",irq);
-		usb_free_bus (bus);
-		reset_hc (s);
-		release_region (s->io_addr, s->io_size);
-		cleanup_skel(s);
-		kfree(s);
-		return -1;
-	}
-
-	/* Enable PIRQ */
-	pci_write_config_word (dev, USBLEGSUP, USBLEGSUP_DEFAULT);
-
-	s->irq = irq;
-
-	if(uhci_start_usb (s) < 0) {
-		uhci_pci_remove(dev);
-		return -1;
-	}
-
-	//chain new uhci device into global list
-	pci_set_drvdata(dev, s);
-	devs=s;
-
-	return 0;
-}
-
-_static int __devinit
-uhci_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
-{
-	int i;
-
-	if (pci_enable_device(dev) < 0)
-		return -ENODEV;
-		
-	if (!dev->irq) {
-		err("found UHCI device with no IRQ assigned. check BIOS settings!");
-		return -ENODEV;
-	}
-	
-	pci_set_master(dev);
-
-	/* Search for the IO base address.. */
-	for (i = 0; i < 6; i++) {
-
-		unsigned int io_addr = pci_resource_start(dev, i);
-		unsigned int io_size = pci_resource_len(dev, i);
-		if (!(pci_resource_flags(dev,i) & IORESOURCE_IO))
-			continue;
-
-		/* Is it already in use? */
-		if (check_region (io_addr, io_size))
-			break;
-		/* disable legacy emulation */
-		pci_write_config_word (dev, USBLEGSUP, 0);
-	
-		return alloc_uhci(dev, dev->irq, io_addr, io_size);
-	}
-	return -ENODEV;
-}
-
-/*-------------------------------------------------------------------------*/
-
-static const struct pci_device_id __devinitdata uhci_pci_ids [] = { {
-
-	/* handle any USB UHCI controller */
-	class: 		((PCI_CLASS_SERIAL_USB << 8) | 0x00),
-	class_mask: 	~0,
-
-	/* no matter who makes it */
-	vendor:		PCI_ANY_ID,
-	device:		PCI_ANY_ID,
-	subvendor:	PCI_ANY_ID,
-	subdevice:	PCI_ANY_ID,
-
-	}, { /* end: all zeroes */ }
-};
-
-MODULE_DEVICE_TABLE (pci, uhci_pci_ids);
-
-static struct pci_driver uhci_pci_driver = {
-	name:		"usb-uhci",
-	id_table:	&uhci_pci_ids [0],
-
-	probe:		uhci_pci_probe,
-	remove:		uhci_pci_remove,
-
-#ifdef	CONFIG_PM
-	suspend:	uhci_pci_suspend,
-	resume:		uhci_pci_resume,
-#endif	/* PM */
-
-};
-
-/*-------------------------------------------------------------------------*/
-
-static int __init uhci_hcd_init (void) 
-{
-	int retval;
-
-#ifdef DEBUG_SLAB
-	urb_priv_kmem = kmem_cache_create("urb_priv", sizeof(urb_priv_t), 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
-	
-	if(!urb_priv_kmem) {
-		err("kmem_cache_create for urb_priv_t failed (out of memory)");
-		return -ENOMEM;
-	}
-#endif	
-	info(VERSTR);
-
-#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
-	info("High bandwidth mode enabled");	
-#endif
-
-	retval = pci_module_init (&uhci_pci_driver);
-
-#ifdef DEBUG_SLAB
-	if (retval < 0 ) {
-		if (kmem_cache_destroy(urb_priv_kmem))
-			err("urb_priv_kmem remained");
-	}
-#endif
-	
-	info(DRIVER_VERSION ":" DRIVER_DESC);
-
-	return retval;
-}
-
-static void __exit uhci_hcd_cleanup (void) 
-{      
-	pci_unregister_driver (&uhci_pci_driver);
-	
-#ifdef DEBUG_SLAB
-	if(kmem_cache_destroy(urb_priv_kmem))
-		err("urb_priv_kmem remained");
-#endif
-}
-
-module_init (uhci_hcd_init);
-module_exit (uhci_hcd_cleanup);
-
-
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
-MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/usb-uhci.h linux-2.4.21-pre6/drivers/usb/usb-uhci.h
--- linux-2.4.20/drivers/usb/usb-uhci.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/usb-uhci.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,308 +0,0 @@
-#ifndef __LINUX_UHCI_H
-#define __LINUX_UHCI_H
-
-/*
-   $Id: usb-uhci.h,v 1.58 2001/08/28 16:45:00 acher Exp $
- */
-#define MODNAME "usb-uhci"
-#define UHCI_LATENCY_TIMER 0
-
-static __inline__ void uhci_wait_ms(unsigned int ms)
-{
-	if(!in_interrupt())
-	{
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(1 + ms * HZ / 1000);
-	}
-	else
-		mdelay(ms);
-}
-
-/* Command register */
-#define USBCMD		0
-#define   USBCMD_RS		0x0001	/* Run/Stop */
-#define   USBCMD_HCRESET	0x0002	/* Host reset */
-#define   USBCMD_GRESET		0x0004	/* Global reset */
-#define   USBCMD_EGSM		0x0008	/* Global Suspend Mode */
-#define   USBCMD_FGR		0x0010	/* Force Global Resume */
-#define   USBCMD_SWDBG		0x0020	/* SW Debug mode */
-#define   USBCMD_CF		0x0040	/* Config Flag (sw only) */
-#define   USBCMD_MAXP		0x0080	/* Max Packet (0 = 32, 1 = 64) */
-
-/* Status register */
-#define USBSTS		2
-#define   USBSTS_USBINT		0x0001	/* Interrupt due to IOC */
-#define   USBSTS_ERROR		0x0002	/* Interrupt due to error */
-#define   USBSTS_RD		0x0004	/* Resume Detect */
-#define   USBSTS_HSE		0x0008	/* Host System Error - basically PCI problems */
-#define   USBSTS_HCPE		0x0010	/* Host Controller Process Error - the scripts were buggy */
-#define   USBSTS_HCH		0x0020	/* HC Halted */
-
-/* Interrupt enable register */
-#define USBINTR		4
-#define   USBINTR_TIMEOUT	0x0001	/* Timeout/CRC error enable */
-#define   USBINTR_RESUME	0x0002	/* Resume interrupt enable */
-#define   USBINTR_IOC		0x0004	/* Interrupt On Complete enable */
-#define   USBINTR_SP		0x0008	/* Short packet interrupt enable */
-
-#define USBFRNUM	6
-#define USBFLBASEADD	8
-#define USBSOF		12
-
-/* USB port status and control registers */
-#define USBPORTSC1	16
-#define USBPORTSC2	18
-#define   USBPORTSC_CCS		0x0001	/* Current Connect Status ("device present") */
-#define   USBPORTSC_CSC		0x0002	/* Connect Status Change */
-#define   USBPORTSC_PE		0x0004	/* Port Enable */
-#define   USBPORTSC_PEC		0x0008	/* Port Enable Change */
-#define   USBPORTSC_LS		0x0030	/* Line Status */
-#define   USBPORTSC_RD		0x0040	/* Resume Detect */
-#define   USBPORTSC_LSDA	0x0100	/* Low Speed Device Attached */
-#define   USBPORTSC_PR		0x0200	/* Port Reset */
-#define   USBPORTSC_SUSP	0x1000	/* Suspend */
-
-/* Legacy support register */
-#define USBLEGSUP 0xc0
-#define USBLEGSUP_DEFAULT 0x2000	/* only PIRQ enable set */
-
-#define UHCI_NULL_DATA_SIZE	0x7ff	/* for UHCI controller TD */
-#define UHCI_PID 		0xff	/* PID MASK */
-
-#define UHCI_PTR_BITS		0x000F
-#define UHCI_PTR_TERM		0x0001
-#define UHCI_PTR_QH		0x0002
-#define UHCI_PTR_DEPTH		0x0004
-
-#define UHCI_NUMFRAMES		1024	/* in the frame list [array] */
-#define UHCI_MAX_SOF_NUMBER	2047	/* in an SOF packet */
-#define CAN_SCHEDULE_FRAMES	1000	/* how far future frames can be scheduled */
-
-/*
- * for TD <status>:
- */
-#define TD_CTRL_SPD		(1 << 29)	/* Short Packet Detect */
-#define TD_CTRL_C_ERR_MASK	(3 << 27)	/* Error Counter bits */
-#define TD_CTRL_LS		(1 << 26)	/* Low Speed Device */
-#define TD_CTRL_IOS		(1 << 25)	/* Isochronous Select */
-#define TD_CTRL_IOC		(1 << 24)	/* Interrupt on Complete */
-#define TD_CTRL_ACTIVE		(1 << 23)	/* TD Active */
-#define TD_CTRL_STALLED		(1 << 22)	/* TD Stalled */
-#define TD_CTRL_DBUFERR		(1 << 21)	/* Data Buffer Error */
-#define TD_CTRL_BABBLE		(1 << 20)	/* Babble Detected */
-#define TD_CTRL_NAK		(1 << 19)	/* NAK Received */
-#define TD_CTRL_CRCTIMEO	(1 << 18)	/* CRC/Time Out Error */
-#define TD_CTRL_BITSTUFF	(1 << 17)	/* Bit Stuff Error */
-#define TD_CTRL_ACTLEN_MASK	0x7ff	/* actual length, encoded as n - 1 */
-
-#define TD_CTRL_ANY_ERROR	(TD_CTRL_STALLED | TD_CTRL_DBUFERR | \
-				 TD_CTRL_BABBLE | TD_CTRL_CRCTIME | TD_CTRL_BITSTUFF)
-
-#define uhci_status_bits(ctrl_sts)	(ctrl_sts & 0xFE0000)
-#define uhci_actual_length(ctrl_sts)	((ctrl_sts + 1) & TD_CTRL_ACTLEN_MASK)	/* 1-based */
-#define uhci_ptr_to_virt(x)	bus_to_virt(x & ~UHCI_PTR_BITS)
-
-/*
- * for TD <flags>:
- */
-#define UHCI_TD_REMOVE		0x0001	/* Remove when done */
-
-/*
- * for TD <info>: (a.k.a. Token)
- */
-#define TD_TOKEN_TOGGLE		19
-
-#define uhci_maxlen(token)	((token) >> 21)
-#define uhci_toggle(token)	(((token) >> TD_TOKEN_TOGGLE) & 1)
-#define uhci_endpoint(token)	(((token) >> 15) & 0xf)
-#define uhci_devaddr(token)	(((token) >> 8) & 0x7f)
-#define uhci_devep(token)	(((token) >> 8) & 0x7ff)
-#define uhci_packetid(token)	((token) & 0xff)
-#define uhci_packetout(token)	(uhci_packetid(token) != USB_PID_IN)
-#define uhci_packetin(token)	(uhci_packetid(token) == USB_PID_IN)
-
-/* ------------------------------------------------------------------------------------
-   New TD/QH-structures
-   ------------------------------------------------------------------------------------ */
-typedef enum {
-	TD_TYPE, QH_TYPE
-} uhci_desc_type_t;
-
-typedef struct {
-	__u32 link;
-	__u32 status;
-	__u32 info;
-	__u32 buffer;
-} uhci_td_t, *puhci_td_t;
-
-typedef struct {
-	__u32 head;
-	__u32 element;		/* Queue element pointer */
-} uhci_qh_t, *puhci_qh_t;
-
-typedef struct {
-	union {
-		uhci_td_t td;
-		uhci_qh_t qh;
-	} hw;
-	uhci_desc_type_t type;
-	dma_addr_t dma_addr;
-	struct list_head horizontal;
-	struct list_head vertical;
-	struct list_head desc_list;
-	int last_used;
-} uhci_desc_t, *puhci_desc_t;
-
-typedef struct {
-	struct list_head desc_list;	// list pointer to all corresponding TDs/QHs associated with this request
-	dma_addr_t setup_packet_dma;
-	dma_addr_t transfer_buffer_dma;
-	unsigned long started;
-	struct urb *next_queued_urb;	// next queued urb for this EP
-	struct urb *prev_queued_urb;
-	uhci_desc_t *bottom_qh;
-	uhci_desc_t *next_qh;       	// next helper QH
-	char use_loop;
-	char flags;
-} urb_priv_t, *purb_priv_t;
-
-struct virt_root_hub {
-	int devnum;		/* Address of Root Hub endpoint */
-	void *urb;
-	void *int_addr;
-	int send;
-	int interval;
-	int numports;
-	int c_p_r[8];
-	struct timer_list rh_int_timer;
-};
-
-typedef struct uhci {
-	int irq;
-	unsigned int io_addr;
-	unsigned int io_size;
-	unsigned int maxports;
-	int running;
-
-	int apm_state;
-
-	struct uhci *next;	// chain of uhci device contexts
-
-	struct list_head urb_list;	// list of all pending urbs
-
-	spinlock_t urb_list_lock;	// lock to keep consistency 
-
-	int unlink_urb_done;
-	atomic_t avoid_bulk;
-	
-	struct usb_bus *bus;	// our bus
-
-	__u32 *framelist;
-	dma_addr_t framelist_dma;
-	uhci_desc_t **iso_td;
-	uhci_desc_t *int_chain[8];
-	uhci_desc_t *ls_control_chain;
-	uhci_desc_t *control_chain;
-	uhci_desc_t *bulk_chain;
-	uhci_desc_t *chain_end;
-	uhci_desc_t *td1ms;
-	uhci_desc_t *td32ms;
-	struct list_head free_desc;
-	spinlock_t qh_lock;
-	spinlock_t td_lock;
-	struct virt_root_hub rh;	//private data of the virtual root hub
-	int loop_usage;            // URBs using bandwidth reclamation
-
-	struct list_head urb_unlinked;	// list of all unlinked  urbs
-	long timeout_check;
-	int timeout_urbs;
-	struct pci_dev *uhci_pci;
-	struct pci_pool *desc_pool;
-	long last_error_time;          // last error output in uhci_interrupt()
-} uhci_t, *puhci_t;
-
-
-#define MAKE_TD_ADDR(a) ((a)->dma_addr&~UHCI_PTR_QH)
-#define MAKE_QH_ADDR(a) ((a)->dma_addr|UHCI_PTR_QH)
-#define UHCI_GET_CURRENT_FRAME(uhci) (inw ((uhci)->io_addr + USBFRNUM))
-
-#define CLEAN_TRANSFER_NO_DELETION 0
-#define CLEAN_TRANSFER_REGULAR 1
-#define CLEAN_TRANSFER_DELETION_MARK 2
-
-#define CLEAN_NOT_FORCED 0
-#define CLEAN_FORCED 1
-
-#define PROCESS_ISO_REGULAR 0
-#define PROCESS_ISO_FORCE 1
-
-#define UNLINK_ASYNC_STORE_URB 0
-#define UNLINK_ASYNC_DONT_STORE 1
-
-#define is_td_active(desc) (desc->hw.td.status & cpu_to_le32(TD_CTRL_ACTIVE))
-
-#define set_qh_head(desc,val) (desc)->hw.qh.head=cpu_to_le32(val)
-#define set_qh_element(desc,val) (desc)->hw.qh.element=cpu_to_le32(val)
-#define set_td_link(desc,val) (desc)->hw.td.link=cpu_to_le32(val)
-#define set_td_ioc(desc) (desc)->hw.td.status |= cpu_to_le32(TD_CTRL_IOC)
-#define clr_td_ioc(desc) (desc)->hw.td.status &= cpu_to_le32(~TD_CTRL_IOC)
-
-
-/* ------------------------------------------------------------------------------------ 
-   Virtual Root HUB 
-   ------------------------------------------------------------------------------------ */
-/* destination of request */
-#define RH_INTERFACE               0x01
-#define RH_ENDPOINT                0x02
-#define RH_OTHER                   0x03
-
-#define RH_CLASS                   0x20
-#define RH_VENDOR                  0x40
-
-/* Requests: bRequest << 8 | bmRequestType */
-#define RH_GET_STATUS           0x0080
-#define RH_CLEAR_FEATURE        0x0100
-#define RH_SET_FEATURE          0x0300
-#define RH_SET_ADDRESS			0x0500
-#define RH_GET_DESCRIPTOR		0x0680
-#define RH_SET_DESCRIPTOR       0x0700
-#define RH_GET_CONFIGURATION	0x0880
-#define RH_SET_CONFIGURATION	0x0900
-#define RH_GET_STATE            0x0280
-#define RH_GET_INTERFACE        0x0A80
-#define RH_SET_INTERFACE        0x0B00
-#define RH_SYNC_FRAME           0x0C80
-/* Our Vendor Specific Request */
-#define RH_SET_EP               0x2000
-
-
-/* Hub port features */
-#define RH_PORT_CONNECTION         0x00
-#define RH_PORT_ENABLE             0x01
-#define RH_PORT_SUSPEND            0x02
-#define RH_PORT_OVER_CURRENT       0x03
-#define RH_PORT_RESET              0x04
-#define RH_PORT_POWER              0x08
-#define RH_PORT_LOW_SPEED          0x09
-#define RH_C_PORT_CONNECTION       0x10
-#define RH_C_PORT_ENABLE           0x11
-#define RH_C_PORT_SUSPEND          0x12
-#define RH_C_PORT_OVER_CURRENT     0x13
-#define RH_C_PORT_RESET            0x14
-
-/* Hub features */
-#define RH_C_HUB_LOCAL_POWER       0x00
-#define RH_C_HUB_OVER_CURRENT      0x01
-
-#define RH_DEVICE_REMOTE_WAKEUP    0x00
-#define RH_ENDPOINT_STALL          0x01
-
-/* Our Vendor Specific feature */
-#define RH_REMOVE_EP               0x00
-
-
-#define RH_ACK                     0x01
-#define RH_REQ_ERR                 -1
-#define RH_NACK                    0x00
-
-#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/usb.c linux-2.4.21-pre6/drivers/usb/usb.c
--- linux-2.4.20/drivers/usb/usb.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/usb.c	2003-03-26 23:49:39.000000000 +0000
@@ -782,7 +782,7 @@
  * cases, we know no other thread can recycle our address, since we must
  * already have been serialized enough to prevent that.
  */
-static void call_policy (char *verb, struct usb_device *dev)
+static void call_policy_interface (char *verb, struct usb_device *dev, int interface)
 {
 	char *argv [3], **envp, *buf, *scratch;
 	int i = 0, value;
@@ -861,20 +861,14 @@
 			    dev->descriptor.bDeviceSubClass,
 			    dev->descriptor.bDeviceProtocol) + 1;
 	if (dev->descriptor.bDeviceClass == 0) {
-		int alt = dev->actconfig->interface [0].act_altsetting;
+		int alt = dev->actconfig->interface [interface].act_altsetting;
 
-		/* a simple/common case: one config, one interface, one driver
-		 * with current altsetting being a reasonable setting.
-		 * everything needs a smart agent and usbdevfs; or can rely on
-		 * device-specific binding policies.
-		 */
 		envp [i++] = scratch;
 		scratch += sprintf (scratch, "INTERFACE=%d/%d/%d",
-			dev->actconfig->interface [0].altsetting [alt].bInterfaceClass,
-			dev->actconfig->interface [0].altsetting [alt].bInterfaceSubClass,
-			dev->actconfig->interface [0].altsetting [alt].bInterfaceProtocol)
+			dev->actconfig->interface [interface].altsetting [alt].bInterfaceClass,
+			dev->actconfig->interface [interface].altsetting [alt].bInterfaceSubClass,
+			dev->actconfig->interface [interface].altsetting [alt].bInterfaceProtocol)
 			+ 1;
-		/* INTERFACE-0, INTERFACE-1, ... ? */
 	}
 	envp [i++] = 0;
 	/* assert: (scratch - buf) < sizeof buf */
@@ -889,6 +883,14 @@
 		dbg ("kusbd policy returned 0x%x", value);
 }
 
+static void call_policy (char *verb, struct usb_device *dev)
+{
+	int i;
+	for (i = 0; i < dev->actconfig->bNumInterfaces; i++) {
+		call_policy_interface (verb, dev, i);
+	}
+}
+
 #else
 
 static inline void
@@ -1785,17 +1787,17 @@
  * These are the actual routines to send
  * and receive control messages.
  */
-#ifdef CONFIG_USB_LONG_TIMEOUT
-#define GET_TIMEOUT 4
-#else
-#define GET_TIMEOUT 3
-#endif
-#define SET_TIMEOUT 3
+
+/* USB spec identifies 5 second timeouts.
+ * Some devices (MGE Ellipse UPSes, etc) need it, too.
+ */
+#define GET_TIMEOUT 5
+#define SET_TIMEOUT 5
 
 int usb_set_address(struct usb_device *dev)
 {
 	return usb_control_msg(dev, usb_snddefctrl(dev), USB_REQ_SET_ADDRESS,
-		0, dev->devnum, 0, NULL, 0, HZ * GET_TIMEOUT);
+		0, dev->devnum, 0, NULL, 0, HZ * SET_TIMEOUT);
 }
 
 int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/usbkbd.c linux-2.4.21-pre6/drivers/usb/usbkbd.c
--- linux-2.4.20/drivers/usb/usbkbd.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/usbkbd.c	2003-03-26 23:49:31.000000000 +0000
@@ -272,7 +272,7 @@
 MODULE_DEVICE_TABLE (usb, usb_kbd_id_table);
 
 static struct usb_driver usb_kbd_driver = {
-	name:		"keyboard",
+	name:		"usbkbd",
 	probe:		usb_kbd_probe,
 	disconnect:	usb_kbd_disconnect,
 	id_table:	usb_kbd_id_table,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/usbmouse.c linux-2.4.21-pre6/drivers/usb/usbmouse.c
--- linux-2.4.20/drivers/usb/usbmouse.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/usbmouse.c	2003-03-26 23:49:30.000000000 +0000
@@ -188,7 +188,7 @@
 MODULE_DEVICE_TABLE (usb, usb_mouse_id_table);
 
 static struct usb_driver usb_mouse_driver = {
-	name:		"usb_mouse",
+	name:		"usbmouse",
 	probe:		usb_mouse_probe,
 	disconnect:	usb_mouse_disconnect,
 	id_table:	usb_mouse_id_table,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/usbnet.c linux-2.4.21-pre6/drivers/usb/usbnet.c
--- linux-2.4.20/drivers/usb/usbnet.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/usbnet.c	2003-03-26 23:48:57.000000000 +0000
@@ -1,6 +1,21 @@
 /*
  * USB Host-to-Host Links
  * Copyright (C) 2000-2002 by David Brownell <dbrownell@users.sourceforge.net>
+ * Copyright (C) 2002 Pavel Machek <pavel@ucw.cz>
+ *
+ * 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
  */
 
 /*
@@ -18,13 +33,15 @@
  *	- Belkin, eTEK (interops with Win32 drivers)
  *	- EPSON USB clients
  *	- GeneSys GL620USB-A
- *	- "Linux Devices" (like iPaq and similar SA-1100 based PDAs)
  *	- NetChip 1080 (interoperates with NetChip Win32 drivers)
  *	- Prolific PL-2301/2302 (replaces "plusb" driver)
+ *	- PXA-250 or SA-1100 Linux PDAs like iPAQ, Yopy, and Zaurus
  *
  * USB devices can implement their side of this protocol at the cost
  * of two bulk endpoints; it's not restricted to "cable" applications.
- * See the LINUXDEV or EPSON device/client support.
+ * See the SA1110, Zaurus, or EPSON device/client support in this driver;
+ * slave/target drivers such as "usb-eth" (on most SA-1100 PDAs) are
+ * used inside USB slave/target devices.
  *
  * 
  * Status:
@@ -37,10 +54,6 @@
  *   handshaking; it'd be worth implementing those as "carrier detect".
  *   Prefer generic hooks, not minidriver-specific hacks.
  *
- * - Linux devices ... the www.handhelds.org SA-1100 support works nicely,
- *   but the Sharp Zaurus uses an incompatible protocol (extra checksums).
- *   No reason not to merge the Zaurus protocol here too (got patch? :)
- *
  * - For Netchip, should use keventd to poll via control requests to detect
  *   hardware level "carrier detect". 
  *
@@ -48,11 +61,15 @@
  *   sheets, sometimes it's not needed and sometimes it hangs.  Prolific has
  *   not responded to repeated support/information requests.
  *
+ * - SA-1100 PDAs ... the standard ARM Linux SA-1100 support works nicely,
+ *   as found in www.handhelds.org and other kernels.  The Sharp/Lineo
+ *   kernels use different drivers, which also talk to this code.
+ *
  * Interop with more Win32 drivers may be a good thing.
  *
  * Seems like reporting "peer connected" (carrier present) events may end
- * up going through the netlink event system, not hotplug ... that may be
- * awkward in terms of automatic configuration though.
+ * up going through the netlink event system, not hotplug ... so new links
+ * would likely be handled with a link monitoring thread in some daemon.
  *
  * There are reports that bridging gives lower-than-usual throughput.
  *
@@ -100,6 +117,10 @@
  * 07-may-2002	Generalize/cleanup keventd support, handling rx stalls (mostly
  *		for USB 2.0 TTs) and memory shortages (potential) too. (db)
  *		Use "locally assigned" IEEE802 address space. (Brad Hards)
+ * 18-oct-2002	Support for Zaurus (Pavel Machek), related cleanup (db).
+ * 15-dec-2002	Partial sync with 2.5 code: cleanups and stubbed PXA-250
+ * 		support (db), fix for framing issues on Z, net1080, and
+ * 		gl620a (Toby Milne)
  *
  *-------------------------------------------------------------------------*/
 
@@ -139,12 +160,13 @@
 #define	CONFIG_USB_BELKIN
 #define	CONFIG_USB_EPSON2888
 #define	CONFIG_USB_GENESYS
-#define	CONFIG_USB_LINUXDEV
 #define	CONFIG_USB_NET1080
 #define	CONFIG_USB_PL2301
+#define	CONFIG_USB_SA1100
+#define	CONFIG_USB_ZAURUS
 
 
-#define DRIVER_VERSION		"17-Jul-2002"
+#define DRIVER_VERSION		"18-Oct-2002"
 
 /*-------------------------------------------------------------------------*/
 
@@ -152,6 +174,8 @@
  * Nineteen USB 1.1 max size bulk transactions per frame (ms), max.
  * Several dozen bytes of IPv4 data can fit in two such transactions.
  * One maximum size Ethernet packet takes twenty four of them.
+ * For high speed, each frame comfortably fits almost 36 max size
+ * Ethernet packets (so queues should be bigger).
  */
 #ifdef REALLY_QUEUE
 #define	RX_QLEN		4
@@ -223,6 +247,7 @@
 	int		flags;
 #define FLAG_FRAMING_NC	0x0001		/* guard against device dropouts */ 
 #define FLAG_FRAMING_GL	0x0002		/* genelink batches packets */
+#define FLAG_FRAMING_Z	0x0004		/* zaurus adds a trailer */
 #define FLAG_NO_SETINT	0x0010		/* device can't set_interface() */
 
 	/* reset device ... can sleep */
@@ -277,6 +302,12 @@
 #define	RUN_CONTEXT (in_irq () ? "in_irq" \
 			: (in_interrupt () ? "in_interrupt" : "can sleep"))
 
+/* mostly for PDA style devices, which are always present */
+static int always_connected (struct usbnet *dev)
+{
+	return 0;
+}
+
 /*-------------------------------------------------------------------------*/
 
 #ifdef DEBUG
@@ -345,7 +376,7 @@
  *
  * EPSON USB clients
  *
- * This is the same idea as "linuxdev" (below) except the firmware in the
+ * This is the same idea as Linux PDAs (below) except the firmware in the
  * device might not be Tux-powered.  Epson provides reference firmware that
  * implements this interface.  Product developers can reuse or modify that
  * code, such as by using their own product and vendor codes.
@@ -354,6 +385,7 @@
 
 static const struct driver_info	epson2888_info = {
 	.description =	"Epson USB Device",
+	.check_connect = always_connected,
 
 	.in = 4, .out = 3,
 	.epsize = 64,
@@ -439,10 +471,28 @@
 {
 	int status = urb->status;
 	
+	switch (status) {
+	case 0:
+		/* success */
+		break;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		/* this urb is terminated, clean up */
+		dbg("%s - urb shutting down with status: %d",
+				__FUNCTION__, status);
+		return;
+	default:
+		dbg("%s - nonzero urb status received: %d",
+				__FUNCTION__, urb->status);
+	}
+
+	// NOTE:  2.4 still has automagic resubmit, so this would be
+	// wrong ... but this code has never worked, is always disabled.
+	status = usb_submit_urb (urb, GFP_ATOMIC);
 	if (status)
-		dbg ("gl_interrupt_complete fail - %X", status);
-	else
-		dbg ("gl_interrupt_complete success...");
+		err ("%s - usb_submit_urb failed with result %d",
+		     __FUNCTION__, status);
 }
 
 static int gl_interrupt_read (struct usbnet *dev)
@@ -508,7 +558,7 @@
 	}
 
 	// fill irq urb
-	FILL_INT_URB (priv->irq_urb, dev->udev,
+	usb_fill_int_urb (priv->irq_urb, dev->udev,
 		usb_rcvintpipe (dev->udev, GENELINK_INTERRUPT_PIPE),
 		priv->irq_buf, INTERRUPT_BUFSIZE,
 		gl_interrupt_complete, 0,
@@ -682,34 +732,6 @@
 
 
 
-#ifdef	CONFIG_USB_LINUXDEV
-
-/*-------------------------------------------------------------------------
- *
- * This could talk to a device that uses Linux, such as a PDA or
- * an embedded system, or in fact to any "smart" device using this
- * particular mapping of USB and Ethernet.
- *
- * Such a Linux host would need a "USB Device Controller" hardware
- * (not "USB Host Controller"), and a network driver talking to that
- * hardware.
- *
- * One example is Intel's SA-1100 chip, which integrates basic USB
- * support (arch/arm/sa1100/usb-eth.c); it's used in the iPaq PDA.
- * And others too, like the Yopy.
- *
- *-------------------------------------------------------------------------*/
-
-static const struct driver_info	linuxdev_info = {
-	.description =	"Linux Device",
-
-	.in = 2, .out = 1,
-	.epsize = 64,
-};
-
-#endif	/* CONFIG_USB_LINUXDEV */
-
-
 #ifdef	CONFIG_USB_NET1080
 
 /*-------------------------------------------------------------------------
@@ -1228,6 +1250,188 @@
 
 
 
+#ifdef	CONFIG_USB_PXA
+
+/*-------------------------------------------------------------------------
+ *
+ * PXA250 and PXA210 use XScale cores (ARM v5TE) with better USB support,
+ * and different USB endpoint numbering than the SA1100 devices.
+ *
+ *-------------------------------------------------------------------------*/
+
+static const struct driver_info	pxa_info = {
+	.description =	"PXA-250 Linux Device",
+	.check_connect = always_connected,
+
+	.in = 1, .out = 2,
+	.epsize = 64,
+};
+
+#endif	/* CONFIG_USB_PXA */
+
+
+
+#ifdef	CONFIG_USB_SA1100
+
+/*-------------------------------------------------------------------------
+ *
+ * Intel's SA-1100 chip integrates basic USB support, and is used
+ * in PDAs like some iPAQs, the Yopy, some Zaurus models, and more.
+ * When they run Linux, arch/arm/mach-sa1100/usb-eth.c may be used to
+ * network using minimal USB framing data.
+ *
+ * This describes the driver currently in standard ARM Linux kernels.
+ * The Zaurus uses a different driver (see later).
+ *
+ *-------------------------------------------------------------------------*/
+
+static const struct driver_info	linuxdev_info = {
+	.description =	"SA-1100 Linux Device",
+	.check_connect = always_connected,
+
+	.in = 2, .out = 1,
+	.epsize = 64,
+};
+
+static const struct driver_info	yopy_info = {
+	.description =	"Yopy",
+	.check_connect = always_connected,
+
+	.in = 2, .out = 1,
+	.epsize = 64,
+};
+
+#endif	/* CONFIG_USB_SA1100 */
+
+
+#ifdef CONFIG_USB_ZAURUS
+
+/*-------------------------------------------------------------------------
+ *
+ * Zaurus is also a SA-1110 based PDA, but one using a different driver
+ * (and framing) for its USB slave/gadget controller than the case above.
+ *
+ * For the current version of that driver, the main way that framing is
+ * nonstandard (also from perspective of the CDC ethernet model!) is a
+ * crc32, added to help detect when some sa1100 usb-to-memory DMA errata
+ * haven't been fully worked around.
+ *
+ *-------------------------------------------------------------------------*/
+
+// NOTE: so far on 2.4 <linux/crc32.h> isn't for "bulk data" like this.
+// On 2.5 crc32_le() handles this for us.
+
+static const u32 crc32_table [256] = {
+    0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+    0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+    0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+    0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+    0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+    0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+    0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+    0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+    0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+    0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+    0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+    0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+    0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+    0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+    0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+    0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+    0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+    0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+    0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+    0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+    0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+    0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+    0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+    0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+    0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+    0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+    0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+    0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+    0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+    0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+    0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+    0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+};
+
+#define CRC32_INITFCS     0xffffffff  // Initial FCS value 
+#define CRC32_FCS(fcs, c) (((fcs) >> 8) ^ crc32_table[((fcs) ^ (c)) & 0xff])
+
+/* fcs_compute32 - memcpy and calculate fcs
+ * Perform a memcpy and calculate fcs using ppp 32bit CRC algorithm.
+ */
+static inline u32 fcs_compute32 (unsigned char *sp, int len, u32 fcs)
+{
+	for (;len-- > 0; fcs = CRC32_FCS (fcs, *sp++))
+		continue;
+	return fcs;
+}
+
+static struct sk_buff *
+zaurus_tx_fixup (struct usbnet *dev, struct sk_buff *skb, int flags)
+{
+	int			padlen;
+	struct sk_buff		*skb2;
+
+	padlen = 2;
+	if (!skb_cloned (skb)) {
+		int	tailroom = skb_tailroom (skb);
+		if ((padlen + 4) <= tailroom)
+			goto done;
+	}
+	skb2 = skb_copy_expand (skb, 0, 4 + padlen, flags);
+	dev_kfree_skb_any (skb);
+	skb = skb2;
+	if (skb) {
+		u32		fcs;
+done:
+		fcs = fcs_compute32 (skb->data, skb->len, CRC32_INITFCS);
+		fcs = ~fcs;
+
+		*skb_put (skb, 1) = fcs       & 0xff;
+		*skb_put (skb, 1) = (fcs>> 8) & 0xff;
+		*skb_put (skb, 1) = (fcs>>16) & 0xff;
+		*skb_put (skb, 1) = (fcs>>24) & 0xff;
+	}
+	return skb;
+}
+
+static const struct driver_info	zaurus_sl5x00_info = {
+	.description =	"Sharp Zaurus SL-5x00",
+	.flags =	FLAG_FRAMING_Z,
+	.check_connect = always_connected,
+	.tx_fixup = 	zaurus_tx_fixup,
+
+	.in = 2, .out = 1,
+	.epsize = 64,
+};
+static const struct driver_info	zaurus_sla300_info = {
+	.description =	"Sharp Zaurus SL-A300",
+	.flags =	FLAG_FRAMING_Z,
+	.check_connect = always_connected,
+	.tx_fixup = 	zaurus_tx_fixup,
+
+	.in = 1, .out = 2,
+	.epsize = 64,
+};
+static const struct driver_info	zaurus_slb500_info = {
+	/* Japanese B500 ~= US SL-5600 */
+	.description =	"Sharp Zaurus SL-B500",
+	.flags =	FLAG_FRAMING_Z,
+	.check_connect = always_connected,
+	.tx_fixup = 	zaurus_tx_fixup,
+
+	.in = 1, .out = 2,
+	.epsize = 64,
+};
+
+// SL-5600 and C-700 are PXA based; should resemble A300
+
+#endif
+
+
 /*-------------------------------------------------------------------------
  *
  * Network Device Driver (peer link to "Host Device", from USB host)
@@ -1267,7 +1471,7 @@
 
 /*-------------------------------------------------------------------------*/
 
-/* urb completions are currently in_irq; avoid doing real work then. */
+/* urb completions may be in_irq; avoid doing real work then. */
 
 static void defer_bh (struct usbnet *dev, struct sk_buff *skb)
 {
@@ -1321,6 +1525,11 @@
 		size = GL_RCV_BUF_SIZE;
 	else
 #endif
+#ifdef CONFIG_USB_ZAURUS
+	if (dev->driver_info->flags & FLAG_FRAMING_Z)
+		size = 6 + (sizeof (struct ethhdr) + dev->net.mtu);
+	else
+#endif
 		size = (sizeof (struct ethhdr) + dev->net.mtu);
 
 	if ((skb = alloc_skb (size, flags)) == 0) {
@@ -1336,15 +1545,10 @@
 	entry->state = rx_start;
 	entry->length = 0;
 
-	FILL_BULK_URB (urb, dev->udev,
+	usb_fill_bulk_urb (urb, dev->udev,
 		usb_rcvbulkpipe (dev->udev, dev->driver_info->in),
 		skb->data, size, rx_complete, skb);
 	urb->transfer_flags |= USB_ASYNC_UNLINK;
-#if 0
-	// Idle-but-posted reads with UHCI really chew up
-	// PCI bandwidth unless FSBR is disabled
-	urb->transfer_flags |= USB_NO_FSBR;
-#endif
 
 	spin_lock_irqsave (&dev->rxq.lock, lockflags);
 
@@ -1388,8 +1592,6 @@
 	if (skb->len) {
 		int	status;
 
-// FIXME: eth_copy_and_csum "small" packets to new SKB (small < ~200 bytes) ?
-
 		skb->dev = &dev->net;
 		skb->protocol = eth_type_trans (skb, &dev->net);
 		dev->stats.rx_packets++;
@@ -1662,7 +1864,7 @@
 	/* could also map RINGPARAM to RX/TX QLEN */
 
 	}
-        /* Note that the ethtool user space code requires EOPNOTSUPP */
+	/* Note that the ethtool user space code requires EOPNOTSUPP */
 	return -EOPNOTSUPP;
 }
 
@@ -1768,7 +1970,7 @@
 static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
 {
 	struct usbnet		*dev = (struct usbnet *) net->priv;
-	int			length = skb->len;
+	int			length;
 	int			retval = NET_XMIT_SUCCESS;
 	struct urb		*urb = 0;
 	struct skb_data		*entry;
@@ -1788,6 +1990,7 @@
 			goto drop;
 		}
 	}
+	length = skb->len;
 
 	if (!(urb = ALLOC_URB (0, GFP_ATOMIC))) {
 		dbg ("no urb");
@@ -1802,6 +2005,7 @@
 
 	// FIXME: reorganize a bit, so that fixup() fills out NetChip
 	// framing too. (Packet ID update needs the spinlock...)
+	// [ BETTER:  we already own net->xmit_lock, that's enough ]
 
 #ifdef	CONFIG_USB_NET1080
 	if (info->flags & FLAG_FRAMING_NC) {
@@ -1818,11 +2022,10 @@
 	if ((length % EP_SIZE (dev)) == 0)
 		skb->len++;
 
-	FILL_BULK_URB (urb, dev->udev,
+	usb_fill_bulk_urb (urb, dev->udev,
 			usb_sndbulkpipe (dev->udev, info->out),
 			skb->data, skb->len, tx_complete, skb);
 	urb->transfer_flags |= USB_ASYNC_UNLINK;
-	// FIXME urb->timeout = ... jiffies ... ;
 
 	spin_lock_irqsave (&dev->txq.lock, flags);
 
@@ -1982,21 +2185,26 @@
 {
 	struct usbnet			*dev;
 	struct net_device 		*net;
-	struct usb_interface_descriptor	*interface;
 	struct driver_info		*info;
 	int				altnum = 0;
 
 	info = (struct driver_info *) prod->driver_info;
 
-	// sanity check; expect dedicated interface/devices for now.
-	interface = &udev->actconfig->interface [ifnum].altsetting [altnum];
-	if (udev->descriptor.bNumConfigurations != 1
-			|| udev->config[0].bNumInterfaces != 1
-//			|| interface->bInterfaceClass != USB_CLASS_VENDOR_SPEC
-			) {
-		dbg ("Bogus config info");
-		return 0;
+#ifdef CONFIG_USB_ZAURUS
+	if (info == &zaurus_sl5x00_info) {
+		int	status;
+
+		/* old ROMs have more than one config
+		 * so we have to make sure config="1" (?)
+		 */
+		status = usb_set_configuration (udev, 1);
+		if (status < 0) {
+			err ("set_config failed, %d", status);
+			return 0;
+		}
+		altnum = 1;
 	}
+#endif
 
 	// more sanity (unless the device is broken)
 	if (!(info->flags & FLAG_NO_SETINT)) {
@@ -2099,7 +2307,7 @@
 #ifdef	CONFIG_USB_EPSON2888
 {
 	USB_DEVICE (0x0525, 0x2888),	// EPSON USB client
-	driver_info:	(unsigned long) &epson2888_info,
+	.driver_info	= (unsigned long) &epson2888_info,
 },
 #endif
 
@@ -2113,23 +2321,6 @@
 	 */
 #endif
 
-#ifdef	CONFIG_USB_LINUXDEV
-/*
- * for example, this can be a host side talk-to-PDA driver.
- * this driver is NOT what runs _inside_ a Linux device !!
- */
-{
-	// 1183 = 0x049F, both used as hex values?
-	USB_DEVICE (0x049F, 0x505A),	// Compaq "Itsy"
-	.driver_info =	(unsigned long) &linuxdev_info,
-}, {
-	USB_DEVICE (0x0E7E, 0x1001),	// G.Mate "Yopy"
-	.driver_info =	(unsigned long) &linuxdev_info,
-},
-	// NOTE:  the Sharp Zaurus uses a modified version of
-	// this driver, which is not interoperable with this.
-#endif
-
 #ifdef	CONFIG_USB_NET1080
 {
 	USB_DEVICE (0x0525, 0x1080),	// NetChip ref design
@@ -2150,7 +2341,69 @@
 },
 #endif
 
-/* KC2190 from www.sepoong.co.kr "InstaNET" */
+#ifdef	CONFIG_USB_PXA
+/*
+ * PXA250 or PXA210 ...  these use a "usb-eth" driver much like
+ * the sa1100 one.
+ */
+{
+	// Compaq "Itsy" vendor/product id, version "2.0"
+	USB_DEVICE_VER (0x049F, 0x505A, 0x0200, 0x0200),
+	.driver_info =	(unsigned long) &pxa_info,
+}, 
+#endif
+
+#ifdef	CONFIG_USB_SA1100
+/*
+ * SA-1100 using standard ARM Linux kernels, or compatible.
+ * Often used when talking to Linux PDAs (iPaq, Yopy, etc).
+ * The sa-1100 "usb-eth" driver handles the basic framing.
+ */
+{
+	// 1183 = 0x049F, both used as hex values?
+	// Compaq "Itsy" vendor/product id, version "0.0"
+	USB_DEVICE_VER (0x049F, 0x505A, 0, 0),
+	.driver_info =	(unsigned long) &linuxdev_info,
+}, {
+	USB_DEVICE (0x0E7E, 0x1001),	// G.Mate "Yopy"
+	.driver_info =	(unsigned long) &yopy_info,
+}, 
+#endif
+
+#ifdef	CONFIG_USB_ZAURUS
+/*
+ * SA-1100 based Sharp Zaurus ("collie"), or compatible.
+ * Same idea as above, but different framing.
+ */
+{
+	.match_flags	=   USB_DEVICE_ID_MATCH_INT_INFO
+			  | USB_DEVICE_ID_MATCH_DEVICE, 
+	.idVendor		= 0x04DD,
+	.idProduct		= 0x8004,
+	.bInterfaceClass	= 0x0a,
+	.bInterfaceSubClass	= 0x00,
+	.bInterfaceProtocol	= 0x00,
+	.driver_info =  (unsigned long) &zaurus_sl5x00_info,
+}, {
+	.match_flags	=   USB_DEVICE_ID_MATCH_INT_INFO
+			  | USB_DEVICE_ID_MATCH_DEVICE, 
+	.idVendor		= 0x04DD,
+	.idProduct		= 0x8005,
+	.bInterfaceClass	= 0x02,
+	.bInterfaceSubClass	= 0x0a,
+	.bInterfaceProtocol	= 0x00,
+	.driver_info =  (unsigned long) &zaurus_sla300_info,
+}, {
+	.match_flags	=   USB_DEVICE_ID_MATCH_INT_INFO
+			  | USB_DEVICE_ID_MATCH_DEVICE, 
+	.idVendor		= 0x04DD,
+	.idProduct		= 0x8006,
+	.bInterfaceClass	= 0x02,
+	.bInterfaceSubClass	= 0x0a,
+	.bInterfaceProtocol	= 0x00,
+	.driver_info =  (unsigned long) &zaurus_slb500_info,
+},
+#endif
 
 	{ },		// END
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/usbvideo.c linux-2.4.21-pre6/drivers/usb/usbvideo.c
--- linux-2.4.20/drivers/usb/usbvideo.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/usbvideo.c	2003-03-26 23:49:39.000000000 +0000
@@ -42,10 +42,10 @@
  * Local prototypes.
  */
 #if USES_PROC_FS
-static void usbvideo_procfs_level1_create(usbvideo_t *ut);
-static void usbvideo_procfs_level1_destroy(usbvideo_t *ut);
-static void usbvideo_procfs_level2_create(uvd_t *uvd);
-static void usbvideo_procfs_level2_destroy(uvd_t *uvd);
+static void usbvideo_procfs_level1_create(struct usbvideo *ut);
+static void usbvideo_procfs_level1_destroy(struct usbvideo *ut);
+static void usbvideo_procfs_level2_create(struct uvd *uvd);
+static void usbvideo_procfs_level2_destroy(struct uvd *uvd);
 static int usbvideo_default_procfs_read_proc(
 	char *page, char **start, off_t off, int count,
 	int *eof, void *data);
@@ -109,29 +109,41 @@
 	vfree(mem);
 }
 
-void RingQueue_Initialize(RingQueue_t *rq)
+static void RingQueue_Initialize(struct RingQueue *rq)
 {
 	assert(rq != NULL);
 	init_waitqueue_head(&rq->wqh);
 }
 
-void RingQueue_Allocate(RingQueue_t *rq, int rqLen)
+static void RingQueue_Allocate(struct RingQueue *rq, int rqLen)
 {
+	/* Make sure the requested size is a power of 2 and
+	   round up if necessary. This allows index wrapping
+	   using masks rather than modulo */
+
+	int i = 1;
 	assert(rq != NULL);
 	assert(rqLen > 0);
+
+	while(rqLen >> i)
+		i++;
+	if(rqLen != 1 << (i-1))
+		rqLen = 1 << i;
+
 	rq->length = rqLen;
+	rq->ri = rq->wi = 0;
 	rq->queue = usbvideo_rvmalloc(rq->length);
 	assert(rq->queue != NULL);
 }
 
-int RingQueue_IsAllocated(const RingQueue_t *rq)
+static int RingQueue_IsAllocated(const struct RingQueue *rq)
 {
 	if (rq == NULL)
 		return 0;
 	return (rq->queue != NULL) && (rq->length > 0);
 }
 
-void RingQueue_Free(RingQueue_t *rq)
+static void RingQueue_Free(struct RingQueue *rq)
 {
 	assert(rq != NULL);
 	if (RingQueue_IsAllocated(rq)) {
@@ -141,19 +153,39 @@
 	}
 }
 
-int RingQueue_Dequeue(RingQueue_t *rq, unsigned char *dst, int len)
+int RingQueue_Dequeue(struct RingQueue *rq, unsigned char *dst, int len)
 {
-	int i;
+	int rql, toread;
+
 	assert(rq != NULL);
 	assert(dst != NULL);
-	for (i=0; i < len; i++) {
-		dst[i] = rq->queue[rq->ri];
-		RING_QUEUE_DEQUEUE_BYTES(rq,1);
+
+	rql = RingQueue_GetLength(rq);
+	if(!rql)
+		return 0;
+
+	/* Clip requested length to available data */
+	if(len > rql)
+		len = rql;
+
+	toread = len;
+	if(rq->ri > rq->wi) {
+		/* Read data from tail */
+		int read = (toread < (rq->length - rq->ri)) ? toread : rq->length - rq->ri;
+		memcpy(dst, rq->queue + rq->ri, read);
+		toread -= read;
+		dst += read;
+		rq->ri = (rq->ri + read) & (rq->length-1);
+	}
+	if(toread) {
+		/* Read data from head */
+		memcpy(dst, rq->queue + rq->ri, toread);
+		rq->ri = (rq->ri + toread) & (rq->length-1);
 	}
 	return len;
 }
 
-int RingQueue_Enqueue(RingQueue_t *rq, const unsigned char *cdata, int n)
+int RingQueue_Enqueue(struct RingQueue *rq, const unsigned char *cdata, int n)
 {
 	int enqueued = 0;
 
@@ -174,7 +206,7 @@
 		if (m > q_avail)
 			m = q_avail;
 
-		memmove(rq->queue + rq->wi, cdata, m);
+		memcpy(rq->queue + rq->wi, cdata, m);
 		RING_QUEUE_ADVANCE_INDEX(rq, wi, m);
 		cdata += m;
 		enqueued += m;
@@ -183,35 +215,27 @@
 	return enqueued;
 }
 
-int RingQueue_GetLength(const RingQueue_t *rq)
+static void RingQueue_InterruptibleSleepOn(struct RingQueue *rq)
 {
-	int ri, wi;
-
 	assert(rq != NULL);
-
-	ri = rq->ri;
-	wi = rq->wi;
-	if (ri == wi)
-		return 0;
-	else if (ri < wi)
-		return wi - ri;
-	else
-		return wi + (rq->length - ri);
+	interruptible_sleep_on(&rq->wqh);
 }
 
-void RingQueue_InterruptibleSleepOn(RingQueue_t *rq)
+void RingQueue_WakeUpInterruptible(struct RingQueue *rq)
 {
 	assert(rq != NULL);
-	interruptible_sleep_on(&rq->wqh);
+	if (waitqueue_active(&rq->wqh))
+		wake_up_interruptible(&rq->wqh);
 }
 
-void RingQueue_WakeUpInterruptible(RingQueue_t *rq)
+void RingQueue_Flush(struct RingQueue *rq)
 {
 	assert(rq != NULL);
-	if (waitqueue_active(&rq->wqh))
-		wake_up_interruptible(&rq->wqh);
+	rq->ri = 0;
+	rq->wi = 0;
 }
 
+
 /*
  * usbvideo_VideosizeToString()
  *
@@ -240,7 +264,7 @@
  * History:
  * 01-Feb-2000 Created.
  */
-void usbvideo_OverlayChar(uvd_t *uvd, usbvideo_frame_t *frame,
+void usbvideo_OverlayChar(struct uvd *uvd, struct usbvideo_frame *frame,
 			  int x, int y, int ch)
 {
 	static const unsigned short digits[16] = {
@@ -295,7 +319,7 @@
  * History:
  * 01-Feb-2000 Created.
  */
-void usbvideo_OverlayString(uvd_t *uvd, usbvideo_frame_t *frame,
+void usbvideo_OverlayString(struct uvd *uvd, struct usbvideo_frame *frame,
 			    int x, int y, const char *str)
 {
 	while (*str) {
@@ -313,7 +337,7 @@
  * History:
  * 01-Feb-2000 Created.
  */
-void usbvideo_OverlayStats(uvd_t *uvd, usbvideo_frame_t *frame)
+void usbvideo_OverlayStats(struct uvd *uvd, struct usbvideo_frame *frame)
 {
 	const int y_diff = 8;
 	char tmp[16];
@@ -348,7 +372,7 @@
 		q_used = RingQueue_GetLength(&uvd->dp);
 		if ((uvd->dp.ri + q_used) >= uvd->dp.length) {
 			u_hi = uvd->dp.length;
-			u_lo = (q_used + uvd->dp.ri) % uvd->dp.length;
+			u_lo = (q_used + uvd->dp.ri) & (uvd->dp.length-1);
 		} else {
 			u_hi = (q_used + uvd->dp.ri);
 			u_lo = -1;
@@ -436,7 +460,7 @@
  * History:
  * 14-Jan-2000 Corrected default multiplier.
  */
-void usbvideo_ReportStatistics(const uvd_t *uvd)
+void usbvideo_ReportStatistics(const struct uvd *uvd)
 {
 	if ((uvd != NULL) && (uvd->stats.urb_count > 0)) {
 		unsigned long allPackets, badPackets, goodPackets, percent;
@@ -492,7 +516,7 @@
  * purposes.
  */
 void usbvideo_DrawLine(
-	usbvideo_frame_t *frame,
+	struct usbvideo_frame *frame,
 	int x1, int y1,
 	int x2, int y2,
 	unsigned char cr, unsigned char cg, unsigned char cb)
@@ -562,20 +586,19 @@
  * History:
  * 01-Feb-2000 Created.
  */
-void usbvideo_TestPattern(uvd_t *uvd, int fullframe, int pmode)
+void usbvideo_TestPattern(struct uvd *uvd, int fullframe, int pmode)
 {
-	static const char proc[] = "usbvideo_TestPattern";
-	usbvideo_frame_t *frame;
+	struct usbvideo_frame *frame;
 	int num_cell = 0;
 	int scan_length = 0;
 	static int num_pass = 0;
 
 	if (uvd == NULL) {
-		err("%s: uvd == NULL", proc);
+		err("%s: uvd == NULL", __FUNCTION__);
 		return;
 	}
 	if ((uvd->curframe < 0) || (uvd->curframe >= USBVIDEO_NUMFRAMES)) {
-		err("%s: uvd->curframe=%d.", proc, uvd->curframe);
+		err("%s: uvd->curframe=%d.", __FUNCTION__, uvd->curframe);
 		return;
 	}
 
@@ -673,74 +696,72 @@
 
 /* ******************************************************************** */
 
-static void usbvideo_ClientIncModCount(uvd_t *uvd)
+static void usbvideo_ClientIncModCount(struct uvd *uvd)
 {
-	static const char proc[] = "usbvideo_ClientIncModCount";
 	if (uvd == NULL) {
-		err("%s: uvd == NULL", proc);
+		err("%s: uvd == NULL", __FUNCTION__);
 		return;
 	}
 	if (uvd->handle == NULL) {
-		err("%s: uvd->handle == NULL", proc);
+		err("%s: uvd->handle == NULL", __FUNCTION__);
 		return;
 	}
 	if (uvd->handle->md_module == NULL) {
-		err("%s: uvd->handle->md_module == NULL", proc);
+		err("%s: uvd->handle->md_module == NULL", __FUNCTION__);
 		return;
 	}
 	__MOD_INC_USE_COUNT(uvd->handle->md_module);
 }
 
-static void usbvideo_ClientDecModCount(uvd_t *uvd)
+static void usbvideo_ClientDecModCount(struct uvd *uvd)
 {
-	static const char proc[] = "usbvideo_ClientDecModCount";
 	if (uvd == NULL) {
-		err("%s: uvd == NULL", proc);
+		err("%s: uvd == NULL", __FUNCTION__);
 		return;
 	}
 	if (uvd->handle == NULL) {
-		err("%s: uvd->handle == NULL", proc);
+		err("%s: uvd->handle == NULL", __FUNCTION__);
 		return;
 	}
 	if (uvd->handle->md_module == NULL) {
-		err("%s: uvd->handle->md_module == NULL", proc);
+		err("%s: uvd->handle->md_module == NULL", __FUNCTION__);
 		return;
 	}
 	__MOD_DEC_USE_COUNT(uvd->handle->md_module);
 }
 
 int usbvideo_register(
-	usbvideo_t **pCams,
+	struct usbvideo **pCams,
 	const int num_cams,
 	const int num_extra,
 	const char *driverName,
-	const usbvideo_cb_t *cbTbl,
-	struct module *md )
+	const struct usbvideo_cb *cbTbl,
+	struct module *md,
+	const struct usb_device_id *id_table)
 {
-	static const char proc[] = "usbvideo_register";
-	usbvideo_t *cams;
+	struct usbvideo *cams;
 	int i, base_size;
 
 	/* Check parameters for sanity */
 	if ((num_cams <= 0) || (pCams == NULL) || (cbTbl == NULL)) {
-		err("%s: Illegal call", proc);
+		err("%s: Illegal call", __FUNCTION__);
 		return -EINVAL;
 	}
 
 	/* Check registration callback - must be set! */
 	if (cbTbl->probe == NULL) {
-		err("%s: probe() is required!", proc);
+		err("%s: probe() is required!", __FUNCTION__);
 		return -EINVAL;
 	}
 
-	base_size = num_cams * sizeof(uvd_t) + sizeof(usbvideo_t);
-	cams = (usbvideo_t *) kmalloc(base_size, GFP_KERNEL);
+	base_size = num_cams * sizeof(struct uvd) + sizeof(struct usbvideo);
+	cams = (struct usbvideo *) kmalloc(base_size, GFP_KERNEL);
 	if (cams == NULL) {
-		err("Failed to allocate %d. bytes for usbvideo_t", base_size);
+		err("Failed to allocate %d. bytes for usbvideo struct", base_size);
 		return -ENOMEM;
 	}
 	dbg("%s: Allocated $%p (%d. bytes) for %d. cameras",
-	    proc, cams, base_size, num_cams);
+	    __FUNCTION__, cams, base_size, num_cams);
 	memset(cams, 0, base_size);
 
 	/* Copy callbacks, apply defaults for those that are not set */
@@ -749,6 +770,10 @@
 		cams->cb.getFrame = usbvideo_GetFrame;
 	if (cams->cb.disconnect == NULL)
 		cams->cb.disconnect = usbvideo_Disconnect;
+	if (cams->cb.startDataPump == NULL)
+		cams->cb.startDataPump = usbvideo_StartDataPump;
+	if (cams->cb.stopDataPump == NULL)
+		cams->cb.stopDataPump = usbvideo_StopDataPump;
 #if USES_PROC_FS
 	/*
 	 * If both /proc fs callbacks are NULL then we assume that the driver
@@ -764,18 +789,18 @@
 #else /* !USES_PROC_FS */
 	/* Report a warning so that user knows why there is no /proc entries */
 	if ((cams->cb.procfs_read != NULL) || (cams->cb.procfs_write == NULL)) {
-		dbg("%s: /proc fs support requested but not configured!", proc);
+		dbg("%s: /proc fs support requested but not configured!", __FUNCTION__);
 	}
 #endif
 	cams->num_cameras = num_cams;
-	cams->cam = (uvd_t *) &cams[1];
+	cams->cam = (struct uvd *) &cams[1];
 	cams->md_module = md;
 	if (cams->md_module == NULL)
-		warn("%s: module == NULL!", proc);
+		warn("%s: module == NULL!", __FUNCTION__);
 	init_MUTEX(&cams->lock);	/* to 1 == available */
 
 	for (i = 0; i < num_cams; i++) {
-		uvd_t *up = &cams->cam[i];
+		struct uvd *up = &cams->cam[i];
 
 		up->handle = cams;
 
@@ -786,11 +811,11 @@
 			if (up->user_data == NULL) {
 				up->user_size = 0;
 				err("%s: Failed to allocate user_data (%d. bytes)",
-				    proc, up->user_size);
+				    __FUNCTION__, up->user_size);
 				return -ENOMEM;
 			}
 			dbg("%s: Allocated cams[%d].user_data=$%p (%d. bytes)",
-			     proc, i, up->user_data, up->user_size);
+			     __FUNCTION__, i, up->user_data, up->user_size);
 		}
 	}
 
@@ -801,10 +826,11 @@
 	cams->usbdrv.name = cams->drvName;
 	cams->usbdrv.probe = cams->cb.probe;
 	cams->usbdrv.disconnect = cams->cb.disconnect;
+	cams->usbdrv.id_table = id_table;
 
 #if USES_PROC_FS
 	if (cams->uses_procfs) {
-		dbg("%s: Creating /proc filesystem entries.", proc);
+		dbg("%s: Creating /proc filesystem entries.", __FUNCTION__);
 		usbvideo_procfs_level1_create(cams);
 	}
 #endif
@@ -827,35 +853,34 @@
  * if you had some dynamically allocated components in ->user field then
  * you should free them before calling here.
  */
-void usbvideo_Deregister(usbvideo_t **pCams)
+void usbvideo_Deregister(struct usbvideo **pCams)
 {
-	static const char proc[] = "usbvideo_deregister";
-	usbvideo_t *cams;
+	struct usbvideo *cams;
 	int i;
 
 	if (pCams == NULL) {
-		err("%s: pCams == NULL", proc);
+		err("%s: pCams == NULL", __FUNCTION__);
 		return;
 	}
 	cams = *pCams;
 	if (cams == NULL) {
-		err("%s: cams == NULL", proc);
+		err("%s: cams == NULL", __FUNCTION__);
 		return;
 	}
 
 #if USES_PROC_FS
 	if (cams->uses_procfs) {
-		dbg("%s: Deregistering filesystem entries.", proc);
+		dbg("%s: Deregistering filesystem entries.", __FUNCTION__);
 		usbvideo_procfs_level1_destroy(cams);
 	}
 #endif
 
-	dbg("%s: Deregistering %s driver.", proc, cams->drvName);
+	dbg("%s: Deregistering %s driver.", __FUNCTION__, cams->drvName);
 	usb_deregister(&cams->usbdrv);
 
-	dbg("%s: Deallocating cams=$%p (%d. cameras)", proc, cams, cams->num_cameras);
+	dbg("%s: Deallocating cams=$%p (%d. cameras)", __FUNCTION__, cams, cams->num_cameras);
 	for (i=0; i < cams->num_cameras; i++) {
-		uvd_t *up = &cams->cam[i];
+		struct uvd *up = &cams->cam[i];
 		int warning = 0;
 
 		if (up->user_data != NULL) {
@@ -867,16 +892,16 @@
 		}
 		if (warning) {
 			err("%s: Warning: user_data=$%p user_size=%d.",
-			    proc, up->user_data, up->user_size);
+			    __FUNCTION__, up->user_data, up->user_size);
 		} else {
 			dbg("%s: Freeing %d. $%p->user_data=$%p",
-			    proc, i, up, up->user_data);
+			    __FUNCTION__, i, up, up->user_data);
 			kfree(up->user_data);
 		}
 	}
 	/* Whole array was allocated in one chunk */
-	dbg("%s: Freed %d uvd_t structures",
-	    proc, cams->num_cameras);
+	dbg("%s: Freed %d uvd structures",
+	    __FUNCTION__, cams->num_cameras);
 	kfree(cams);
 	*pCams = NULL;
 }
@@ -905,23 +930,22 @@
  */
 void usbvideo_Disconnect(struct usb_device *dev, void *ptr)
 {
-	static const char proc[] = "usbvideo_Disconnect";
-	uvd_t *uvd = (uvd_t *) ptr;
+	struct uvd *uvd = (struct uvd *) ptr;
 	int i;
 
 	if ((dev == NULL) || (uvd == NULL)) {
-		err("%s($%p,$%p): Illegal call.", proc, dev, ptr);
+		err("%s($%p,$%p): Illegal call.", __FUNCTION__, dev, ptr);
 		return;
 	}
 	usbvideo_ClientIncModCount(uvd);
 	if (uvd->debug > 0)
-		info("%s(%p,%p.)", proc, dev, ptr);
+		info("%s(%p,%p.)", __FUNCTION__, dev, ptr);
 
 	down(&uvd->lock);
 	uvd->remove_pending = 1; /* Now all ISO data will be ignored */
 
 	/* At this time we ask to cancel outstanding URBs */
-	usbvideo_StopDataPump(uvd);
+	GET_CALLBACK(uvd, stopDataPump)(uvd);
 
 	for (i=0; i < USBVIDEO_NUMSBUF; i++)
 		usb_free_urb(uvd->sbuf[i].urb);
@@ -930,7 +954,7 @@
 	uvd->dev = NULL;    	    /* USB device is no more */
 
 	if (uvd->user)
-		info("%s: In use, disconnect pending.", proc);
+		info("%s: In use, disconnect pending.", __FUNCTION__);
 	else
 		usbvideo_CameraRelease(uvd);
 	up(&uvd->lock);
@@ -942,28 +966,27 @@
 /*
  * usbvideo_CameraRelease()
  *
- * This code does final release of uvd_t. This happens
+ * This code does final release of struct uvd. This happens
  * after the device is disconnected -and- all clients
  * closed their files.
  *
  * History:
  * 27-Jan-2000 Created.
  */
-void usbvideo_CameraRelease(uvd_t *uvd)
+void usbvideo_CameraRelease(struct uvd *uvd)
 {
-	static const char proc[] = "usbvideo_CameraRelease";
 	if (uvd == NULL) {
-		err("%s: Illegal call", proc);
+		err("%s: Illegal call", __FUNCTION__);
 		return;
 	}
 	video_unregister_device(&uvd->vdev);
 	if (uvd->debug > 0)
-		info("%s: Video unregistered.", proc);
+		info("%s: Video unregistered.", __FUNCTION__);
 
 #if USES_PROC_FS
 	assert(uvd->handle != NULL);
 	if (uvd->handle->uses_procfs) {
-		dbg("%s: Removing /proc/%s/ filesystem entries.", proc, uvd->handle->drvName);
+		dbg("%s: Removing /proc/%s/ filesystem entries.", __FUNCTION__, uvd->handle->drvName);
 		usbvideo_procfs_level2_destroy(uvd);
 	}
 #endif
@@ -984,17 +1007,17 @@
  * History:
  * 27-Jan-2000 Created.
  */
-static int usbvideo_find_struct(usbvideo_t *cams)
+static int usbvideo_find_struct(struct usbvideo *cams)
 {
 	int u, rv = -1;
 
 	if (cams == NULL) {
-		err("No usbvideo_t handle?");
+		err("No usbvideo handle?");
 		return -1;
 	}
 	down(&cams->lock);
 	for (u = 0; u < cams->num_cameras; u++) {
-		uvd_t *uvd = &cams->cam[u];
+		struct uvd *uvd = &cams->cam[u];
 		if (!uvd->uvd_used) /* This one is free */
 		{
 			uvd->uvd_used = 1;	/* In use now */
@@ -1008,13 +1031,13 @@
 	return rv;
 }
 
-uvd_t *usbvideo_AllocateDevice(usbvideo_t *cams)
+struct uvd *usbvideo_AllocateDevice(struct usbvideo *cams)
 {
 	int i, devnum;
-	uvd_t *uvd = NULL;
+	struct uvd *uvd = NULL;
 
 	if (cams == NULL) {
-		err("No usbvideo_t handle?");
+		err("No usbvideo handle?");
 		return NULL;
 	}
 
@@ -1069,24 +1092,23 @@
 	return uvd;
 }
 
-int usbvideo_RegisterVideoDevice(uvd_t *uvd)
+int usbvideo_RegisterVideoDevice(struct uvd *uvd)
 {
-	static const char proc[] = "usbvideo_RegisterVideoDevice";
 	char tmp1[20], tmp2[20];	/* Buffers for printing */
 
 	if (uvd == NULL) {
-		err("%s: Illegal call.", proc);
+		err("%s: Illegal call.", __FUNCTION__);
 		return -EINVAL;
 	}
 	if (uvd->video_endp == 0) {
-		info("%s: No video endpoint specified; data pump disabled.", proc);
+		info("%s: No video endpoint specified; data pump disabled.", __FUNCTION__);
 	}
 	if (uvd->paletteBits == 0) {
-		err("%s: No palettes specified!", proc);
+		err("%s: No palettes specified!", __FUNCTION__);
 		return -EINVAL;
 	}
 	if (uvd->defaultPalette == 0) {
-		info("%s: No default palette!", proc);
+		info("%s: No default palette!", __FUNCTION__);
 	}
 
 	uvd->max_frame_size = VIDEOSIZE_X(uvd->canvas) *
@@ -1096,17 +1118,17 @@
 
 	if (uvd->debug > 0) {
 		info("%s: iface=%d. endpoint=$%02x paletteBits=$%08lx",
-		     proc, uvd->iface, uvd->video_endp, uvd->paletteBits);
+		     __FUNCTION__, uvd->iface, uvd->video_endp, uvd->paletteBits);
 	}
 	if (video_register_device(&uvd->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
-		err("%s: video_register_device failed", proc);
+		err("%s: video_register_device failed", __FUNCTION__);
 		return -EPIPE;
 	}
 	if (uvd->debug > 1) {
-		info("%s: video_register_device() successful", proc);
+		info("%s: video_register_device() successful", __FUNCTION__);
 	}
 	if (uvd->dev == NULL) {
-		err("%s: uvd->dev == NULL", proc);
+		err("%s: uvd->dev == NULL", __FUNCTION__);
 		return -EINVAL;
 	}
 
@@ -1119,7 +1141,7 @@
 	if (uvd->handle->uses_procfs) {
 		if (uvd->debug > 0) {
 			info("%s: Creating /proc/video/%s/ filesystem entries.",
-			     proc, uvd->handle->drvName);
+			     __FUNCTION__, uvd->handle->drvName);
 		}
 		usbvideo_procfs_level2_create(uvd);
 	}
@@ -1144,14 +1166,14 @@
 
 int usbvideo_v4l_mmap(struct video_device *dev, const char *adr, unsigned long size)
 {
-	uvd_t *uvd = (uvd_t *) dev;
+	struct uvd *uvd = (struct uvd *) dev;
 	unsigned long start = (unsigned long) adr;
 	unsigned long page, pos;
 
 	if (!CAMERA_IS_OPERATIONAL(uvd))
 		return -EFAULT;
 
-	if (size > (((2 * uvd->max_frame_size) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))
+	if (size > (((USBVIDEO_NUMFRAMES * uvd->max_frame_size) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))
 		return -EINVAL;
 
 	pos = (unsigned long) uvd->fbuf;
@@ -1187,19 +1209,18 @@
  */
 int usbvideo_v4l_open(struct video_device *dev, int flags)
 {
-	static const char proc[] = "usbvideo_v4l_open";
-	uvd_t *uvd = (uvd_t *) dev;
+	struct uvd *uvd = (struct uvd *) dev;
 	const int sb_size = FRAMES_PER_DESC * uvd->iso_packet_len;
 	int i, errCode = 0;
 
 	if (uvd->debug > 1)
-		info("%s($%p,$%08x", proc, dev, flags);
+		info("%s($%p,$%08x", __FUNCTION__, dev, flags);
 
 	usbvideo_ClientIncModCount(uvd);
 	down(&uvd->lock);
 
 	if (uvd->user) {
-		err("%s: Someone tried to open an already opened device!", proc);
+		err("%s: Someone tried to open an already opened device!", __FUNCTION__);
 		errCode = -EBUSY;
 	} else {
 		/* Clear statistics */
@@ -1212,10 +1233,10 @@
 		/* Allocate memory for the frame buffers */
 		uvd->fbuf_size = USBVIDEO_NUMFRAMES * uvd->max_frame_size;
 		uvd->fbuf = usbvideo_rvmalloc(uvd->fbuf_size);
-		RingQueue_Allocate(&uvd->dp, 128*1024); /* FIXME #define */
+		RingQueue_Allocate(&uvd->dp, RING_QUEUE_SIZE);
 		if ((uvd->fbuf == NULL) ||
 		    (!RingQueue_IsAllocated(&uvd->dp))) {
-			err("%s: Failed to allocate fbuf or dp", proc);
+			err("%s: Failed to allocate fbuf or dp", __FUNCTION__);
 			errCode = -ENOMEM;
 		} else {
 			/* Allocate all buffers */
@@ -1257,23 +1278,23 @@
 	if (errCode == 0) {
 		/* Start data pump if we have valid endpoint */
 		if (uvd->video_endp != 0)
-			errCode = usbvideo_StartDataPump(uvd);
+			errCode = GET_CALLBACK(uvd, startDataPump)(uvd);
 		if (errCode == 0) {
 			if (VALID_CALLBACK(uvd, setupOnOpen)) {
 				if (uvd->debug > 1)
-					info("%s: setupOnOpen callback", proc);
+					info("%s: setupOnOpen callback", __FUNCTION__);
 				errCode = GET_CALLBACK(uvd, setupOnOpen)(uvd);
 				if (errCode < 0) {
 					err("%s: setupOnOpen callback failed (%d.).",
-					    proc, errCode);
+					    __FUNCTION__, errCode);
 				} else if (uvd->debug > 1) {
-					info("%s: setupOnOpen callback successful", proc);
+					info("%s: setupOnOpen callback successful", __FUNCTION__);
 				}
 			}
 			if (errCode == 0) {
 				uvd->settingsAdjusted = 0;
 				if (uvd->debug > 1)
-					info("%s: Open succeeded.", proc);
+					info("%s: Open succeeded.", __FUNCTION__);
 				uvd->user++;
 			}
 		}
@@ -1282,7 +1303,7 @@
 	if (errCode != 0)
 		usbvideo_ClientDecModCount(uvd);
 	if (uvd->debug > 0)
-		info("%s: Returning %d.", proc, errCode);
+		info("%s: Returning %d.", __FUNCTION__, errCode);
 	return errCode;
 }
 
@@ -1300,15 +1321,14 @@
  */
 void usbvideo_v4l_close(struct video_device *dev)
 {
-	static const char proc[] = "usbvideo_v4l_close";
-	uvd_t *uvd = (uvd_t *)dev;
+	struct uvd *uvd = (struct uvd *)dev;
 	int i;
 
 	if (uvd->debug > 1)
-		info("%s($%p)", proc, dev);
+		info("%s($%p)", __FUNCTION__, dev);
 
-	down(&uvd->lock);	
-	usbvideo_StopDataPump(uvd);
+	down(&uvd->lock);
+	GET_CALLBACK(uvd, stopDataPump)(uvd);
 	usbvideo_rvfree(uvd->fbuf, uvd->fbuf_size);
 	uvd->fbuf = NULL;
 	RingQueue_Free(&uvd->dp);
@@ -1332,7 +1352,7 @@
 	usbvideo_ClientDecModCount(uvd);
 
 	if (uvd->debug > 1)
-		info("%s: Completed.", proc);
+		info("%s: Completed.", __FUNCTION__);
 }
 
 /*
@@ -1345,7 +1365,7 @@
  */
 int usbvideo_v4l_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
 {
-	uvd_t *uvd = (uvd_t *)dev;
+	struct uvd *uvd = (struct uvd *)dev;
 
 	if (!CAMERA_IS_OPERATIONAL(uvd))
 		return -EFAULT;
@@ -1399,6 +1419,9 @@
 
 			if (copy_from_user(&vw, arg, sizeof(vw)))
 				return -EFAULT;
+			if (VALID_CALLBACK(uvd, setVideoMode)) {
+				return GET_CALLBACK(uvd, setVideoMode)(uvd, &vw);
+			}
 			if (vw.flags)
 				return -EINVAL;
 			if (vw.clipcount)
@@ -1416,8 +1439,8 @@
 
 			vw.x = 0;
 			vw.y = 0;
-			vw.width = VIDEOSIZE_X(uvd->canvas);
-			vw.height = VIDEOSIZE_Y(uvd->canvas);
+			vw.width = VIDEOSIZE_X(uvd->videosize);
+			vw.height = VIDEOSIZE_Y(uvd->videosize);
 			vw.chromakey = 0;
 			if (VALID_CALLBACK(uvd, getFPS))
 				vw.flags = GET_CALLBACK(uvd, getFPS)(uvd);
@@ -1432,12 +1455,13 @@
 		case VIDIOCGMBUF:
 		{
 			struct video_mbuf vm;
+			int i;
 
 			memset(&vm, 0, sizeof(vm));
-			vm.size = uvd->max_frame_size * 2;
-			vm.frames = 2;
-			vm.offsets[0] = 0;
-			vm.offsets[1] = uvd->max_frame_size;
+			vm.size = uvd->max_frame_size * USBVIDEO_NUMFRAMES;
+			vm.frames = USBVIDEO_NUMFRAMES;
+			for(i = 0; i < USBVIDEO_NUMFRAMES; i++)
+				vm.offsets[i] = i * uvd->max_frame_size;
 
 			if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
 				return -EFAULT;
@@ -1487,8 +1511,8 @@
 				}
 				return -EINVAL;
 			}
-			if ((vm.frame != 0) && (vm.frame != 1)) {
-				err("VIDIOCMCAPTURE: vm.frame=%d. !E [0,1]", vm.frame);
+			if ((vm.frame < 0) && (vm.frame >= USBVIDEO_NUMFRAMES)) {
+				err("VIDIOCMCAPTURE: vm.frame=%d. !E [0-%d]", vm.frame, USBVIDEO_NUMFRAMES-1);
 				return -EINVAL;
 			}
 			if (uvd->frame[vm.frame].frameState == FrameState_Grabbing) {
@@ -1585,28 +1609,26 @@
  */
 long usbvideo_v4l_read(struct video_device *dev, char *buf, unsigned long count, int noblock)
 {
-	static const char proc[] = "usbvideo_v4l_read";
-	uvd_t *uvd = (uvd_t *) dev;
-	int frmx = -1;
-	usbvideo_frame_t *frame;
+	struct uvd *uvd = (struct uvd *) dev;
+	int frmx = -1, i;
+	struct usbvideo_frame *frame;
 
 	if (!CAMERA_IS_OPERATIONAL(uvd) || (buf == NULL))
 		return -EFAULT;
 
 	if (uvd->debug >= 1)
-		info("%s: %ld. bytes, noblock=%d.", proc, count, noblock);
+		info("%s: %ld. bytes, noblock=%d.", __FUNCTION__, count, noblock);
 
 	down(&uvd->lock);	
 
 	/* See if a frame is completed, then use it. */
-	if ((uvd->frame[0].frameState == FrameState_Done) ||
-	    (uvd->frame[0].frameState == FrameState_Done_Hold) ||
-	    (uvd->frame[0].frameState == FrameState_Error)) {
-		frmx = 0;
-	} else if ((uvd->frame[1].frameState >= FrameState_Done) ||
-		   (uvd->frame[1].frameState == FrameState_Done_Hold) ||
-		   (uvd->frame[1].frameState >= FrameState_Done)) {
-		frmx = 1;
+	for(i = 0; i < USBVIDEO_NUMFRAMES; i++) {
+		if ((uvd->frame[i].frameState == FrameState_Done) ||
+		    (uvd->frame[i].frameState == FrameState_Done_Hold) ||
+		    (uvd->frame[i].frameState == FrameState_Error)) {
+			frmx = i;
+			break;
+		}
 	}
 
 	/* FIXME: If we don't start a frame here then who ever does? */
@@ -1621,10 +1643,12 @@
 	 * We will need to wait until it becomes cooked, of course.
 	 */
 	if (frmx == -1) {
-		if (uvd->frame[0].frameState == FrameState_Grabbing)
-			frmx = 0;
-		else if (uvd->frame[1].frameState == FrameState_Grabbing)
-			frmx = 1;
+		for(i = 0; i < USBVIDEO_NUMFRAMES; i++) {
+			if (uvd->frame[i].frameState == FrameState_Grabbing) {
+				frmx = i;
+				break;
+			}
+		}
 	}
 
 	/*
@@ -1640,7 +1664,7 @@
 	 */
 	if (frmx == -1) {
 		if (uvd->defaultPalette == 0) {
-			err("%s: No default palette; don't know what to do!", proc);
+			err("%s: No default palette; don't know what to do!", __FUNCTION__);
 			count = -EFAULT;
 			goto read_done;
 		}
@@ -1718,7 +1742,7 @@
 	frame->seqRead_Index += count;
 	if (uvd->debug >= 1) {
 		err("%s: {copy} count used=%ld, new seqRead_Index=%ld",
-			proc, count, frame->seqRead_Index);
+		    __FUNCTION__, count, frame->seqRead_Index);
 	}
 
 	/* Finally check if the frame is done with and "release" it */
@@ -1728,8 +1752,8 @@
 
 		/* Mark it as available to be used again. */
 		uvd->frame[frmx].frameState = FrameState_Unused;
-		if (usbvideo_NewFrame(uvd, frmx ? 0 : 1)) {
-			err("%s: usbvideo_NewFrame failed.", proc);
+		if (usbvideo_NewFrame(uvd, (frmx + 1) % USBVIDEO_NUMFRAMES)) {
+			err("%s: usbvideo_NewFrame failed.", __FUNCTION__);
 		}
 	}
 read_done:
@@ -1740,7 +1764,7 @@
 /*
  * Make all of the blocks of data contiguous
  */
-static int usbvideo_CompressIsochronous(uvd_t *uvd, struct urb *urb)
+static int usbvideo_CompressIsochronous(struct uvd *uvd, struct urb *urb)
 {
 	char *cdata;
 	int i, totlen = 0;
@@ -1773,7 +1797,7 @@
 static void usbvideo_IsocIrq(struct urb *urb)
 {
 	int i, len;
-	uvd_t *uvd = urb->context;
+	struct uvd *uvd = urb->context;
 
 	/* We don't want to do anything if we are about to be removed! */
 	if (!CAMERA_IS_OPERATIONAL(uvd))
@@ -1825,17 +1849,16 @@
  *             of hardcoded values. Simplified by using for loop,
  *             allowed any number of URBs.
  */
-int usbvideo_StartDataPump(uvd_t *uvd)
+int usbvideo_StartDataPump(struct uvd *uvd)
 {
-	static const char proc[] = "usbvideo_StartDataPump";
 	struct usb_device *dev = uvd->dev;
 	int i, errFlag;
 
 	if (uvd->debug > 1)
-		info("%s($%p)", proc, uvd);
+		info("%s($%p)", __FUNCTION__, uvd);
 
 	if (!CAMERA_IS_OPERATIONAL(uvd)) {
-		err("%s: Camera is not operational",proc);
+		err("%s: Camera is not operational", __FUNCTION__);
 		return -EFAULT;
 	}
 	uvd->curframe = -1;
@@ -1843,14 +1866,14 @@
 	/* Alternate interface 1 is is the biggest frame size */
 	i = usb_set_interface(dev, uvd->iface, uvd->ifaceAltActive);
 	if (i < 0) {
-		err("%s: usb_set_interface error", proc);
+		err("%s: usb_set_interface error", __FUNCTION__);
 		uvd->last_error = i;
 		return -EBUSY;
 	}
 	if (VALID_CALLBACK(uvd, videoStart))
 		GET_CALLBACK(uvd, videoStart)(uvd);
 	else 
-		err("%s: videoStart not set", proc);
+		err("%s: videoStart not set", __FUNCTION__);
 
 	/* We double buffer the Iso lists */
 	for (i=0; i < USBVIDEO_NUMSBUF; i++) {
@@ -1882,12 +1905,12 @@
 	for (i=0; i < USBVIDEO_NUMSBUF; i++) {
 		errFlag = usb_submit_urb(uvd->sbuf[i].urb);
 		if (errFlag)
-			err("%s: usb_submit_isoc(%d) ret %d", proc, i, errFlag);
+			err("%s: usb_submit_isoc(%d) ret %d", __FUNCTION__, i, errFlag);
 	}
 
 	uvd->streaming = 1;
 	if (uvd->debug > 1)
-		info("%s: streaming=1 video_endp=$%02x", proc, uvd->video_endp);
+		info("%s: streaming=1 video_endp=$%02x", __FUNCTION__, uvd->video_endp);
 	return 0;
 }
 
@@ -1901,13 +1924,12 @@
  * 22-Jan-2000 Corrected order of actions to work after surprise removal.
  * 27-Jan-2000 Used uvd->iface, uvd->ifaceAltInactive instead of hardcoded values.
  */
-void usbvideo_StopDataPump(uvd_t *uvd)
+void usbvideo_StopDataPump(struct uvd *uvd)
 {
-	static const char proc[] = "usbvideo_StopDataPump";
 	int i, j;
 
 	if (uvd->debug > 1)
-		info("%s($%p)", proc, uvd);
+		info("%s($%p)", __FUNCTION__, uvd);
 
 	if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL))
 		return;
@@ -1916,10 +1938,10 @@
 	for (i=0; i < USBVIDEO_NUMSBUF; i++) {
 		j = usb_unlink_urb(uvd->sbuf[i].urb);
 		if (j < 0)
-			err("%s: usb_unlink_urb() error %d.", proc, j);
+			err("%s: usb_unlink_urb() error %d.", __FUNCTION__, j);
 	}
 	if (uvd->debug > 1)
-		info("%s: streaming=0", proc);
+		info("%s: streaming=0", __FUNCTION__);
 	uvd->streaming = 0;
 
 	if (!uvd->remove_pending) {
@@ -1927,12 +1949,12 @@
 		if (VALID_CALLBACK(uvd, videoStop))
 			GET_CALLBACK(uvd, videoStop)(uvd);
 		else 
-			err("%s: videoStop not set" ,proc);
+			err("%s: videoStop not set", __FUNCTION__);
 
 		/* Set packet size to 0 */
 		j = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltInactive);
 		if (j < 0) {
-			err("%s: usb_set_interface() error %d.", proc, j);
+			err("%s: usb_set_interface() error %d.", __FUNCTION__, j);
 			uvd->last_error = j;
 		}
 	}
@@ -1945,9 +1967,9 @@
  * 29-Mar-00 Added copying of previous frame into the current one.
  * 6-Aug-00  Added model 3 video sizes, removed redundant width, height.
  */
-int usbvideo_NewFrame(uvd_t *uvd, int framenum)
+int usbvideo_NewFrame(struct uvd *uvd, int framenum)
 {
-	usbvideo_frame_t *frame;
+	struct usbvideo_frame *frame;
 	int n;
 
 	if (uvd->debug > 1)
@@ -1965,7 +1987,7 @@
 		uvd->settingsAdjusted = 1;
 	}
 
-	n = (framenum - 1 + USBVIDEO_NUMFRAMES) % USBVIDEO_NUMFRAMES;
+	n = (framenum + 1) % USBVIDEO_NUMFRAMES;
 	if (uvd->frame[n].frameState == FrameState_Ready)
 		framenum = n;
 
@@ -1997,7 +2019,8 @@
 	 */
 	if (!(uvd->flags & FLAGS_SEPARATE_FRAMES)) {
 		/* This copies previous frame into this one to mask losses */
-		memmove(frame->data, uvd->frame[1-framenum].data, uvd->max_frame_size);
+		int prev = (framenum - 1 + USBVIDEO_NUMFRAMES) % USBVIDEO_NUMFRAMES;
+		memmove(frame->data, uvd->frame[prev].data, uvd->max_frame_size);
 	} else {
 		if (uvd->flags & FLAGS_CLEAN_FRAMES) {
 			/* This provides a "clean" frame but slows things down */
@@ -2020,7 +2043,7 @@
  * FLAGS_NO_DECODING set. Therefore, any regular build of any driver
  * based on usbvideo can use this feature at any time.
  */
-void usbvideo_CollectRawData(uvd_t *uvd, usbvideo_frame_t *frame)
+void usbvideo_CollectRawData(struct uvd *uvd, struct usbvideo_frame *frame)
 {
 	int n;
 
@@ -2050,18 +2073,17 @@
 	}
 }
 
-int usbvideo_GetFrame(uvd_t *uvd, int frameNum)
+int usbvideo_GetFrame(struct uvd *uvd, int frameNum)
 {
-	static const char proc[] = "usbvideo_GetFrame";
-	usbvideo_frame_t *frame = &uvd->frame[frameNum];
+	struct usbvideo_frame *frame = &uvd->frame[frameNum];
 
 	if (uvd->debug >= 2)
-		info("%s($%p,%d.)", proc, uvd, frameNum);
+		info("%s($%p,%d.)", __FUNCTION__, uvd, frameNum);
 
 	switch (frame->frameState) {
         case FrameState_Unused:
 		if (uvd->debug >= 2)
-			info("%s: FrameState_Unused", proc);
+			info("%s: FrameState_Unused", __FUNCTION__);
 		return -EINVAL;
         case FrameState_Ready:
         case FrameState_Grabbing:
@@ -2071,7 +2093,7 @@
 	redo:
 		if (!CAMERA_IS_OPERATIONAL(uvd)) {
 			if (uvd->debug >= 2)
-				info("%s: Camera is not operational (1)", proc);
+				info("%s: Camera is not operational (1)", __FUNCTION__);
 			return -EIO;
 		}
 		ntries = 0; 
@@ -2080,24 +2102,24 @@
 			signalPending = signal_pending(current);
 			if (!CAMERA_IS_OPERATIONAL(uvd)) {
 				if (uvd->debug >= 2)
-					info("%s: Camera is not operational (2)", proc);
+					info("%s: Camera is not operational (2)", __FUNCTION__);
 				return -EIO;
 			}
 			assert(uvd->fbuf != NULL);
 			if (signalPending) {
 				if (uvd->debug >= 2)
-					info("%s: Signal=$%08x", proc, signalPending);
+					info("%s: Signal=$%08x", __FUNCTION__, signalPending);
 				if (uvd->flags & FLAGS_RETRY_VIDIOCSYNC) {
 					usbvideo_TestPattern(uvd, 1, 0);
 					uvd->curframe = -1;
 					uvd->stats.frame_num++;
 					if (uvd->debug >= 2)
-						info("%s: Forced test pattern screen", proc);
+						info("%s: Forced test pattern screen", __FUNCTION__);
 					return 0;
 				} else {
 					/* Standard answer: Interrupted! */
 					if (uvd->debug >= 2)
-						info("%s: Interrupted!", proc);
+						info("%s: Interrupted!", __FUNCTION__);
 					return -EINTR;
 				}
 			} else {
@@ -2107,17 +2129,17 @@
 				else if (VALID_CALLBACK(uvd, processData))
 					GET_CALLBACK(uvd, processData)(uvd, frame);
 				else 
-					err("%s: processData not set", proc);
+					err("%s: processData not set", __FUNCTION__);
 			}
 		} while (frame->frameState == FrameState_Grabbing);
 		if (uvd->debug >= 2) {
 			info("%s: Grabbing done; state=%d. (%lu. bytes)",
-			     proc, frame->frameState, frame->seqRead_Length);
+			     __FUNCTION__, frame->frameState, frame->seqRead_Length);
 		}
 		if (frame->frameState == FrameState_Error) {
 			int ret = usbvideo_NewFrame(uvd, frameNum);
 			if (ret < 0) {
-				err("%s: usbvideo_NewFrame() failed (%d.)", proc, ret);
+				err("%s: usbvideo_NewFrame() failed (%d.)", __FUNCTION__, ret);
 				return ret;
 			}
 			goto redo;
@@ -2149,7 +2171,7 @@
 		}
 		frame->frameState = FrameState_Done_Hold;
 		if (uvd->debug >= 2)
-			info("%s: Entered FrameState_Done_Hold state.", proc);
+			info("%s: Entered FrameState_Done_Hold state.", __FUNCTION__);
 		return 0;
 
 	case FrameState_Done_Hold:
@@ -2160,12 +2182,12 @@
 		 * it will be released back into the wild to roam freely.
 		 */
 		if (uvd->debug >= 2)
-			info("%s: FrameState_Done_Hold state.", proc);
+			info("%s: FrameState_Done_Hold state.", __FUNCTION__);
 		return 0;
 	}
 
 	/* Catch-all for other cases. We shall not be here. */
-	err("%s: Invalid state %d.", proc, frame->frameState);
+	err("%s: Invalid state %d.", __FUNCTION__, frame->frameState);
 	frame->frameState = FrameState_Unused;
 	return 0;
 }
@@ -2183,7 +2205,7 @@
  * line above then we just copy next line. Similarly, if we need to
  * create a last line then preceding line is used.
  */
-void usbvideo_DeinterlaceFrame(uvd_t *uvd, usbvideo_frame_t *frame)
+void usbvideo_DeinterlaceFrame(struct uvd *uvd, struct usbvideo_frame *frame)
 {
 	if ((uvd == NULL) || (frame == NULL))
 		return;
@@ -2251,15 +2273,14 @@
  * History:
  * 09-Feb-2001  Created.
  */
-void usbvideo_SoftwareContrastAdjustment(uvd_t *uvd, usbvideo_frame_t *frame)
+void usbvideo_SoftwareContrastAdjustment(struct uvd *uvd, struct usbvideo_frame *frame)
 {
-	static const char proc[] = "usbvideo_SoftwareContrastAdjustment";
 	int i, j, v4l_linesize;
 	signed long adj;
 	const int ccm = 128; /* Color correction median - see below */
 
 	if ((uvd == NULL) || (frame == NULL)) {
-		err("%s: Illegal call.", proc);
+		err("%s: Illegal call.", __FUNCTION__);
 		return;
 	}
 	adj = (uvd->vpic.contrast - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/
@@ -2309,16 +2330,14 @@
 
 extern struct proc_dir_entry *video_proc_entry;
 
-static void usbvideo_procfs_level1_create(usbvideo_t *ut)
+static void usbvideo_procfs_level1_create(struct usbvideo *ut)
 {
-	static const char proc[] = "usbvideo_procfs_level1_create";
-
 	if (ut == NULL) {
-		err("%s: ut == NULL", proc);
+		err("%s: ut == NULL", __FUNCTION__);
 		return;
 	}
 	if (video_proc_entry == NULL) {
-		err("%s: /proc/video/ doesn't exist.", proc);
+		err("%s: /proc/video/ doesn't exist.", __FUNCTION__);
 		return;
 	}
 	ut->procfs_dEntry = create_proc_entry(ut->drvName, S_IFDIR, video_proc_entry);
@@ -2326,16 +2345,14 @@
 		if (ut->md_module != NULL)
 			ut->procfs_dEntry->owner = ut->md_module;
 	} else {
-		err("%s: Unable to initialize /proc/video/%s", proc, ut->drvName);
+		err("%s: Unable to initialize /proc/video/%s", __FUNCTION__, ut->drvName);
 	}
 }
 
-static void usbvideo_procfs_level1_destroy(usbvideo_t *ut)
+static void usbvideo_procfs_level1_destroy(struct usbvideo *ut)
 {
-	static const char proc[] = "usbvideo_procfs_level1_destroy";
-
 	if (ut == NULL) {
-		err("%s: ut == NULL", proc);
+		err("%s: ut == NULL", __FUNCTION__);
 		return;
 	}
 	if (ut->procfs_dEntry != NULL) {
@@ -2344,17 +2361,15 @@
 	}
 }
 
-static void usbvideo_procfs_level2_create(uvd_t *uvd)
+static void usbvideo_procfs_level2_create(struct uvd *uvd)
 {
-	static const char proc[] = "usbvideo_procfs_level2_create";
-
 	if (uvd == NULL) {
-		err("%s: uvd == NULL", proc);
+		err("%s: uvd == NULL", __FUNCTION__);
 		return;
 	}
 	assert(uvd->handle != NULL);
 	if (uvd->handle->procfs_dEntry == NULL) {
-		err("%s: uvd->handle->procfs_dEntry == NULL", proc);
+		err("%s: uvd->handle->procfs_dEntry == NULL", __FUNCTION__);
 		return;
 	}
 
@@ -2368,16 +2383,14 @@
 		uvd->procfs_vEntry->read_proc = uvd->handle->cb.procfs_read;
 		uvd->procfs_vEntry->write_proc = uvd->handle->cb.procfs_write;
 	} else {
-		err("%s: Failed to create entry \"%s\"", proc, uvd->videoName);
+		err("%s: Failed to create entry \"%s\"", __FUNCTION__, uvd->videoName);
 	}
 }
 
-static void usbvideo_procfs_level2_destroy(uvd_t *uvd)
+static void usbvideo_procfs_level2_destroy(struct uvd *uvd)
 {
-	static const char proc[] = "usbvideo_procfs_level2_destroy";
-
 	if (uvd == NULL) {
-		err("%s: uvd == NULL", proc);
+		err("%s: uvd == NULL", __FUNCTION__);
 		return;
 	}
 	if (uvd->procfs_vEntry != NULL) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/usbvideo.h linux-2.4.21-pre6/drivers/usb/usbvideo.h
--- linux-2.4.20/drivers/usb/usbvideo.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/usbvideo.h	2003-03-26 23:49:31.000000000 +0000
@@ -113,62 +113,61 @@
     mr = LIMIT_RGB(mm_r); \
 }
 
-#define	RING_QUEUE_ADVANCE_INDEX(rq,ind,n) (rq)->ind = ((rq)->ind + (n)) % (rq)->length
+#define	RING_QUEUE_SIZE		(128*1024)	/* Must be a power of 2 */
+#define	RING_QUEUE_ADVANCE_INDEX(rq,ind,n) (rq)->ind = ((rq)->ind + (n)) & ((rq)->length-1)
 #define	RING_QUEUE_DEQUEUE_BYTES(rq,n) RING_QUEUE_ADVANCE_INDEX(rq,ri,n)
-#define	RING_QUEUE_PEEK(rq,ofs) ((rq)->queue[((ofs) + (rq)->ri) % (rq)->length])
+#define	RING_QUEUE_PEEK(rq,ofs) ((rq)->queue[((ofs) + (rq)->ri) & ((rq)->length-1)])
 
-typedef struct {
+struct RingQueue {
 	unsigned char *queue;	/* Data from the Isoc data pump */
 	int length;		/* How many bytes allocated for the queue */
 	int wi;			/* That's where we write */
 	int ri;			/* Read from here until you hit write index */
 	wait_queue_head_t wqh;	/* Processes waiting */
-} RingQueue_t;
+};
 
-typedef enum {
+enum ScanState {
 	ScanState_Scanning,	/* Scanning for header */
 	ScanState_Lines		/* Parsing lines */
-} ScanState_t;
+};
 
 /* Completion states of the data parser */
-typedef enum {
+enum ParseState {
 	scan_Continue,		/* Just parse next item */
 	scan_NextFrame,		/* Frame done, send it to V4L */
 	scan_Out,		/* Not enough data for frame */
 	scan_EndParse		/* End parsing */
-} ParseState_t;
+};
 
-typedef enum {
+enum FrameState {
 	FrameState_Unused,	/* Unused (no MCAPTURE) */
 	FrameState_Ready,	/* Ready to start grabbing */
 	FrameState_Grabbing,	/* In the process of being grabbed into */
 	FrameState_Done,	/* Finished grabbing, but not been synced yet */
 	FrameState_Done_Hold,	/* Are syncing or reading */
 	FrameState_Error,	/* Something bad happened while processing */
-} FrameState_t;
+};
 
 /*
  * Some frames may contain only even or odd lines. This type
  * specifies what type of deinterlacing is required.
  */
-typedef enum {
+enum Deinterlace {
 	Deinterlace_None=0,
 	Deinterlace_FillOddLines,
 	Deinterlace_FillEvenLines
-} Deinterlace_t;
-
-struct usb_device;
+};
 
 #define USBVIDEO_NUMFRAMES	2	/* How many frames we work with */
 #define USBVIDEO_NUMSBUF	2	/* How many URBs linked in a ring */
 
 /* This structure represents one Isoc request - URB and buffer */
-typedef struct {
+struct usbvideo_sbuf {
 	char *data;
 	struct urb *urb;
-} usbvideo_sbuf_t;
+};
 
-typedef struct {
+struct usbvideo_frame {
 	char *data;		/* Frame buffer */
 	unsigned long header;	/* Significant bits from the header */
 
@@ -176,9 +175,9 @@
 	videosize_t request;	/* That's what the application asked for */
 	unsigned short palette;	/* The desired format */
 
-	FrameState_t frameState;/* State of grabbing */
-	ScanState_t scanstate;	/* State of scanning */
-	Deinterlace_t deinterlace;
+	enum FrameState frameState;/* State of grabbing */
+	enum ScanState scanstate;	/* State of scanning */
+	enum Deinterlace deinterlace;
 	int flags;		/* USBVIDEO_FRAME_FLAG_xxx bit flags */
 
 	int curline;		/* Line of frame we're working on */
@@ -187,10 +186,10 @@
 	long seqRead_Index;	/* Amount of data that has been already read */
 
 	void *user;		/* Additional data that user may need */
-} usbvideo_frame_t;
+};
 
 /* Statistics that can be overlaid on screen */
-typedef struct {
+struct usbvideo_statistics {
         unsigned long frame_num;	/* Sequential number of the frame */
         unsigned long urb_count;        /* How many URBs we received so far */
         unsigned long urb_length;       /* Length of last URB */
@@ -198,14 +197,14 @@
         unsigned long header_count;     /* How many frame headers we found */
 	unsigned long iso_skip_count;	/* How many empty ISO packets received */
 	unsigned long iso_err_count;	/* How many bad ISO packets received */
-} usbvideo_statistics_t;
+};
 
-struct s_usbvideo_t;
+struct usbvideo;
 
-typedef struct {
+struct uvd {
 	struct video_device vdev;	/* Must be the first field! */
 	struct usb_device *dev;
-	struct s_usbvideo_t *handle;	/* Points back to the usbvideo_t */
+	struct usbvideo *handle;	/* Points back to the struct usbvideo */
 	void *user_data;		/* Camera-dependent data */
 	int user_size;			/* Size of that camera-dependent data */
 	int debug;			/* Debug level for usbvideo */
@@ -235,58 +234,61 @@
 	int curframe;
 	int iso_packet_len;	/* Videomode-dependent, saves bus bandwidth */
 
-	RingQueue_t dp;		/* Isoc data pump */
-	usbvideo_frame_t frame[USBVIDEO_NUMFRAMES];
-	usbvideo_sbuf_t sbuf[USBVIDEO_NUMSBUF];
+	struct RingQueue dp;	/* Isoc data pump */
+	struct usbvideo_frame frame[USBVIDEO_NUMFRAMES];
+	struct usbvideo_sbuf sbuf[USBVIDEO_NUMSBUF];
 
 	volatile int remove_pending;	/* If set then about to exit */
 
 	struct video_picture vpic, vpic_old;	/* Picture settings */
 	struct video_capability vcap;		/* Video capabilities */
 	struct video_channel vchan;	/* May be used for tuner support */
-	usbvideo_statistics_t stats;
+	struct usbvideo_statistics stats;
 	struct proc_dir_entry *procfs_vEntry;	/* /proc/video/MYDRIVER/video2 */
 	char videoName[32];		/* Holds name like "video7" */
-} uvd_t;
+};
 
 /*
  * usbvideo callbacks (virtual methods). They are set when usbvideo
  * services are registered. All of these default to NULL, except those
  * that default to usbvideo-provided methods.
  */
-typedef struct {
+struct usbvideo_cb {
 	void *(*probe)(struct usb_device *, unsigned int,const struct usb_device_id *);
-	void (*userFree)(uvd_t *);
+	void (*userFree)(struct uvd *);
 	void (*disconnect)(struct usb_device *, void *);
-	int (*setupOnOpen)(uvd_t *);
-	void (*videoStart)(uvd_t *);
-	void (*videoStop)(uvd_t *);
-	void (*processData)(uvd_t *, usbvideo_frame_t *);
-	void (*postProcess)(uvd_t *, usbvideo_frame_t *);
-	void (*adjustPicture)(uvd_t *);
-	int (*getFPS)(uvd_t *);
-	int (*overlayHook)(uvd_t *, usbvideo_frame_t *);
-	int (*getFrame)(uvd_t *, int);
+	int (*setupOnOpen)(struct uvd *);
+	void (*videoStart)(struct uvd *);
+	void (*videoStop)(struct uvd *);
+	void (*processData)(struct uvd *, struct usbvideo_frame *);
+	void (*postProcess)(struct uvd *, struct usbvideo_frame *);
+	void (*adjustPicture)(struct uvd *);
+	int (*getFPS)(struct uvd *);
+	int (*overlayHook)(struct uvd *, struct usbvideo_frame *);
+	int (*getFrame)(struct uvd *, int);
 	int (*procfs_read)(char *page,char **start,off_t off,int count,int *eof,void *data);
 	int (*procfs_write)(struct file *file,const char *buffer,unsigned long count,void *data);
-} usbvideo_cb_t;
+	int (*startDataPump)(struct uvd *uvd);
+	void (*stopDataPump)(struct uvd *uvd);
+	int (*setVideoMode)(struct uvd *uvd, struct video_window *vw);
+};
 
-struct s_usbvideo_t {
+struct usbvideo {
 	int num_cameras;		/* As allocated */
 	struct usb_driver usbdrv;	/* Interface to the USB stack */
 	char drvName[80];		/* Driver name */
 	struct semaphore lock;		/* Mutex protecting camera structures */
-	usbvideo_cb_t cb;		/* Table of callbacks (virtual methods) */
+	struct usbvideo_cb cb;		/* Table of callbacks (virtual methods) */
 	struct video_device vdt;	/* Video device template */
-	uvd_t *cam;			/* Array of camera structures */
+	struct uvd *cam;			/* Array of camera structures */
 	int uses_procfs;		/* Non-zero if we create /proc entries */
 	struct proc_dir_entry *procfs_dEntry;	/* /proc/video/MYDRIVER */
 	struct module *md_module;	/* Minidriver module */
 };
-typedef struct s_usbvideo_t usbvideo_t;
+
 
 /*
- * This macro retrieves callback address from the uvd_t object.
+ * This macro retrieves callback address from the struct uvd object.
  * No validity checks are done here, so be sure to check the
  * callback beforehand with VALID_CALLBACK.
  */
@@ -302,29 +304,34 @@
 #define	VALID_CALLBACK(uvd,cbName) ((((uvd) != NULL) && \
 		((uvd)->handle != NULL)) ? GET_CALLBACK(uvd,cbName) : NULL)
 
-void RingQueue_Initialize(RingQueue_t *rq);
-void RingQueue_Allocate(RingQueue_t *rq, int rqLen);
-int  RingQueue_IsAllocated(const RingQueue_t *rq);
-void RingQueue_Free(RingQueue_t *rq);
-int  RingQueue_Dequeue(RingQueue_t *rq, unsigned char *dst, int len);
-int  RingQueue_Enqueue(RingQueue_t *rq, const unsigned char *cdata, int n);
-int  RingQueue_GetLength(const RingQueue_t *rq);
-void RingQueue_InterruptibleSleepOn(RingQueue_t *rq);
-void RingQueue_WakeUpInterruptible(RingQueue_t *rq);
+int  RingQueue_Dequeue(struct RingQueue *rq, unsigned char *dst, int len);
+int  RingQueue_Enqueue(struct RingQueue *rq, const unsigned char *cdata, int n);
+void RingQueue_WakeUpInterruptible(struct RingQueue *rq);
+void RingQueue_Flush(struct RingQueue *rq);
+
+static inline int RingQueue_GetLength(const struct RingQueue *rq)
+{
+	return (rq->wi - rq->ri + rq->length) & (rq->length-1);
+}
+
+static inline int RingQueue_GetFreeSpace(const struct RingQueue *rq)
+{
+	return rq->length - RingQueue_GetLength(rq);
+}
 
-void usbvideo_CollectRawData(uvd_t *uvd, usbvideo_frame_t *frame);
+void usbvideo_CollectRawData(struct uvd *uvd, struct usbvideo_frame *frame);
 void usbvideo_DrawLine(
-	usbvideo_frame_t *frame,
+	struct usbvideo_frame *frame,
 	int x1, int y1,
 	int x2, int y2,
 	unsigned char cr, unsigned char cg, unsigned char cb);
 void usbvideo_HexDump(const unsigned char *data, int len);
-void usbvideo_OverlayChar(uvd_t *uvd, usbvideo_frame_t *frame, int x, int y, int ch);
-void usbvideo_OverlayString(uvd_t *uvd, usbvideo_frame_t *frame, int x, int y, const char *str);
-void usbvideo_OverlayStats(uvd_t *uvd, usbvideo_frame_t *frame);
-void usbvideo_ReportStatistics(const uvd_t *uvd);
+void usbvideo_OverlayChar(struct uvd *uvd, struct usbvideo_frame *frame, int x, int y, int ch);
+void usbvideo_OverlayString(struct uvd *uvd, struct usbvideo_frame *frame, int x, int y, const char *str);
+void usbvideo_OverlayStats(struct uvd *uvd, struct usbvideo_frame *frame);
+void usbvideo_ReportStatistics(const struct uvd *uvd);
 void usbvideo_SayAndWait(const char *what);
-void usbvideo_TestPattern(uvd_t *uvd, int fullframe, int pmode);
+void usbvideo_TestPattern(struct uvd *uvd, int fullframe, int pmode);
 void usbvideo_VideosizeToString(char *buf, int bufLen, videosize_t vs);
 
 /* Memory allocation routines */
@@ -334,17 +341,18 @@
 void usbvideo_rvfree(void *mem, unsigned long size);
 
 int usbvideo_register(
-	usbvideo_t **pCams,
+	struct usbvideo **pCams,
 	const int num_cams,
 	const int num_extra,
 	const char *driverName,
-	const usbvideo_cb_t *cbTable,
-	struct module *md);
-uvd_t *usbvideo_AllocateDevice(usbvideo_t *cams);
-int usbvideo_RegisterVideoDevice(uvd_t *uvd);
-void usbvideo_Deregister(usbvideo_t **uvt);
+	const struct usbvideo_cb *cbTable,
+	struct module *md,
+	const struct usb_device_id *id_table);
+struct uvd *usbvideo_AllocateDevice(struct usbvideo *cams);
+int usbvideo_RegisterVideoDevice(struct uvd *uvd);
+void usbvideo_Deregister(struct usbvideo **uvt);
 void usbvideo_Disconnect(struct usb_device *dev, void *ptr);
-void usbvideo_CameraRelease(uvd_t *uvd);
+void usbvideo_CameraRelease(struct uvd *uvd);
 
 void usbvideo_v4l_close(struct video_device *dev);
 int usbvideo_v4l_initialize(struct video_device *dev);
@@ -356,12 +364,12 @@
 long usbvideo_v4l_write(struct video_device *dev, const char *buf,
 			unsigned long count, int noblock);
 
-int usbvideo_GetFrame(uvd_t *uvd, int frameNum);
-int usbvideo_NewFrame(uvd_t *uvd, int framenum);
-int usbvideo_StartDataPump(uvd_t *uvd);
-void usbvideo_StopDataPump(uvd_t *uvd);
-void usbvideo_DeinterlaceFrame(uvd_t *uvd, usbvideo_frame_t *frame);
-void usbvideo_SoftwareContrastAdjustment(uvd_t *uvd, usbvideo_frame_t *frame);
+int usbvideo_GetFrame(struct uvd *uvd, int frameNum);
+int usbvideo_NewFrame(struct uvd *uvd, int framenum);
+int usbvideo_StartDataPump(struct uvd *uvd);
+void usbvideo_StopDataPump(struct uvd *uvd);
+void usbvideo_DeinterlaceFrame(struct uvd *uvd, struct usbvideo_frame *frame);
+void usbvideo_SoftwareContrastAdjustment(struct uvd *uvd, struct usbvideo_frame *frame);
 
 /*
  * This code performs bounds checking - use it when working with
@@ -377,7 +385,7 @@
  * VIDEOSIZE_X(fr->request), total VIDEOSIZE_Y(frame->request) lines.
  */
 static inline void RGB24_PUTPIXEL(
-	usbvideo_frame_t *fr,
+	struct usbvideo_frame *fr,
 	int ix, int iy,
 	unsigned char vr,
 	unsigned char vg,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/vicam.c linux-2.4.21-pre6/drivers/usb/vicam.c
--- linux-2.4.20/drivers/usb/vicam.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/vicam.c	2003-03-26 23:49:09.000000000 +0000
@@ -1,649 +1,1022 @@
-/* -*- linux-c -*-
- * USB ViCAM driver
- *
- * Copyright (c) 2001 Christopher L Cheney (ccheney@cheney.cx)
- * Copyright (c) 2001 Pavel Machek (pavel@suse.cz) sponsored by SuSE
- *
- *      This program is free software; you can redistribute it and/or
- *      modify it under the terms of the GNU General Public License as
- *      published by the Free Software Foundation; either version 2 of
- *      the License, or (at your option) any later version.
- *
- * This driver is for the Vista Imaging ViCAM and 3Com HomeConnect USB
- *
- * Thanks to Greg Kroah-Hartman for the USB Skeleton driver
- *
- * TODO:
- *	- find out the ids for the Vista Imaging ViCAM
+/*
+ * USB ViCam WebCam driver
+ * Copyright (c) 2002 Joe Burks (jburks@wavicle.org)
  *
- * History:
+ * Supports 3COM HomeConnect PC Digital WebCam
  *
- * 2001_07_07 - 0.1 - christopher: first version
- * 2001_08_28 - 0.2 - pavel: messed it up, but for some fun, try 
- 			while true; do dd if=/dev/video of=/dev/fb0 bs=$[0x1e480] count=1 2> /dev/null; done
-		      yep, moving pictures.
- * 2001_08_29 - 0.3 - pavel: played a little bit more. Experimental mmap support. For some fun,
- 			get gqcam-0.9, compile it and run. Better than dd ;-).
- * 2001_08_29 - 0.4 - pavel: added shutter speed control (not much functional)
- 			kill update_params if it does not seem to work for you.
- * 2001_08_30 - 0.5 - pavel: fixed stupid bug with update_params & vicam_bulk
-
+ * 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.
  *
- * FIXME: It crashes on rmmod with camera plugged.
- */
-#define DEBUG 1
+ * This source code is based heavily on the CPiA webcam driver
+ * */
 
-#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/wrapper.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/init.h>
+#include <linux/videodev.h>
 #include <linux/usb.h>
-
-#include <asm/io.h>
-#include <linux/wrapper.h>
 #include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include "usbvideo.h"
 
-#include <linux/videodev.h>
+// #define VICAM_DEBUG
+
+#ifndef MODULE_LICENSE
+#define MODULE_LICENSE(a)
+#endif
+
+#ifndef bool
+#define bool int
+#endif
 
-#include "vicam.h"
-#include "vicamurbs.h"
+#ifdef VICAM_DEBUG
+#define ADBG(lineno,fmt,args...) printk(fmt, jiffies, __FUNCTION__, lineno, ##args)
+#define DBG(fmt,args...) ADBG((__LINE__),KERN_DEBUG __FILE__"(%ld):%s (%d):"fmt,##args)
+#else
+#define DBG(fmn,args...) do {} while(0)
+#endif
 
 /* Version Information */
-#define DRIVER_VERSION "v0"
-#define DRIVER_AUTHOR "Christopher L Cheney <ccheney@cheney.cx>, Pavel Machek <pavel@suse.cz>"
-#define DRIVER_DESC "USB ViCAM Driver"
+#define DRIVER_VERSION "v1.0"
+#define DRIVER_AUTHOR "Joe Burks, jburks@wavicle.org"
+#define DRIVER_DESC "ViCam WebCam Driver"
 
 /* Define these values to match your device */
-#define USB_VICAM_VENDOR_ID	0x04C1
-#define USB_VICAM_PRODUCT_ID	0x009D
+#define USB_VICAM_VENDOR_ID	0x04c1
+#define USB_VICAM_PRODUCT_ID	0x009d
 
-/* table of devices that work with this driver */
-static struct usb_device_id vicam_table [] = {
-	{ USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID) },
-	{ }					/* Terminating entry */
+#define VICAM_BYTES_PER_PIXEL 3
+#define VICAM_MAX_READ_SIZE (512*242+128)
+#define VICAM_MAX_FRAME_SIZE (VICAM_BYTES_PER_PIXEL*320*240)
+#define VICAM_FRAMES 2
+
+/* Not sure what all the bytes in these char
+ * arrays do, but they're necessary to make
+ * the camera work.
+ */
+
+static unsigned char setup1[] = {
+	0xB6, 0xC3, 0x1F, 0x00, 0x02, 0x64, 0xE7, 0x67,
+	0xFD, 0xFF, 0x0E, 0xC0, 0xE7, 0x09, 0xDE, 0x00,
+	0x8E, 0x00, 0xC0, 0x09, 0x40, 0x03, 0xC0, 0x17,
+	0x44, 0x03, 0x4B, 0xAF, 0xC0, 0x07, 0x00, 0x00,
+	0x4B, 0xAF, 0x97, 0xCF, 0x00, 0x00
 };
 
-MODULE_DEVICE_TABLE (usb, vicam_table);
+static unsigned char setup2[] = {
+	0xB6, 0xC3, 0x03, 0x00, 0x03, 0x64, 0x18, 0x00,
+	0x00, 0x00
+};
 
-static int video_nr = -1; 		/* next avail video device */
-static struct usb_driver vicam_driver;
+static unsigned char setup3[] = {
+	0xB6, 0xC3, 0x01, 0x00, 0x06, 0x64, 0x00, 0x00
+};
 
-static char *buf, *buf2;
-static volatile int change_pending = 0; 
+static unsigned char setup4[] = {
+	0xB6, 0xC3, 0x8F, 0x06, 0x02, 0x64, 0xE7, 0x07,
+	0x00, 0x00, 0x08, 0xC0, 0xE7, 0x07, 0x00, 0x00,
+	0x3E, 0xC0, 0xE7, 0x07, 0x54, 0x01, 0xAA, 0x00,
+	0xE7, 0x07, 0xC8, 0x05, 0xB6, 0x00, 0xE7, 0x07,
+	0x42, 0x01, 0xD2, 0x00, 0xE7, 0x07, 0x7C, 0x00,
+	0x16, 0x00, 0xE7, 0x07, 0x56, 0x00, 0x18, 0x00,
+	0xE7, 0x07, 0x06, 0x00, 0x92, 0xC0, 0xE7, 0x07,
+	0x00, 0x00, 0x1E, 0xC0, 0xE7, 0x07, 0xFF, 0xFF,
+	0x22, 0xC0, 0xE7, 0x07, 0x04, 0x00, 0x24, 0xC0,
+	0xE7, 0x07, 0xEC, 0x27, 0x28, 0xC0, 0xE7, 0x07,
+	0x16, 0x01, 0x8E, 0x00, 0xE7, 0x87, 0x01, 0x00,
+	0x0E, 0xC0, 0x97, 0xCF, 0xD7, 0x09, 0x00, 0xC0,
+	0xE7, 0x77, 0x01, 0x00, 0x92, 0xC0, 0x09, 0xC1,
+	0xE7, 0x09, 0xFE, 0x05, 0x24, 0x01, 0xE7, 0x09,
+	0x04, 0x06, 0x26, 0x01, 0xE7, 0x07, 0x07, 0x00,
+	0x92, 0xC0, 0xE7, 0x05, 0x00, 0xC0, 0xC0, 0xDF,
+	0x97, 0xCF, 0x17, 0x00, 0x57, 0x00, 0x17, 0x02,
+	0xD7, 0x09, 0x00, 0xC0, 0xE7, 0x77, 0x01, 0x00,
+	0x92, 0xC0, 0x0A, 0xC1, 0xE7, 0x57, 0xFF, 0xFF,
+	0xFA, 0x05, 0x0D, 0xC0, 0xE7, 0x57, 0x00, 0x00,
+	0xFA, 0x05, 0x0F, 0xC0, 0x9F, 0xAF, 0xC6, 0x00,
+	0xE7, 0x05, 0x00, 0xC0, 0xC8, 0x05, 0xC1, 0x05,
+	0xC0, 0x05, 0xC0, 0xDF, 0x97, 0xCF, 0x27, 0xDA,
+	0xFA, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x0B, 0x06,
+	0x73, 0xCF, 0x9F, 0xAF, 0x78, 0x01, 0x9F, 0xAF,
+	0x1A, 0x03, 0x6E, 0xCF, 0xE7, 0x09, 0xFC, 0x05,
+	0x24, 0x01, 0xE7, 0x09, 0x02, 0x06, 0x26, 0x01,
+	0xE7, 0x07, 0x07, 0x00, 0x92, 0xC0, 0xE7, 0x09,
+	0xFC, 0x05, 0xFE, 0x05, 0xE7, 0x09, 0x02, 0x06,
+	0x04, 0x06, 0xE7, 0x09, 0x00, 0x06, 0xFC, 0x05,
+	0xE7, 0x09, 0xFE, 0x05, 0x00, 0x06, 0x27, 0xDA,
+	0xFA, 0x05, 0xE7, 0x57, 0x01, 0x00, 0xFA, 0x05,
+	0x02, 0xCA, 0x04, 0xC0, 0x97, 0xCF, 0x9F, 0xAF,
+	0x66, 0x05, 0x97, 0xCF, 0xE7, 0x07, 0x40, 0x00,
+	0x02, 0x06, 0xC8, 0x09, 0xFC, 0x05, 0x9F, 0xAF,
+	0xDA, 0x02, 0x97, 0xCF, 0xCF, 0x17, 0x02, 0x00,
+	0xEF, 0x57, 0x81, 0x00, 0x09, 0x06, 0x9F, 0xA0,
+	0xB6, 0x01, 0xEF, 0x57, 0x80, 0x00, 0x09, 0x06,
+	0x9F, 0xA0, 0x40, 0x02, 0xEF, 0x57, 0x01, 0x00,
+	0x0B, 0x06, 0x9F, 0xA0, 0x46, 0x03, 0xE7, 0x07,
+	0x01, 0x00, 0x0A, 0xC0, 0x46, 0xAF, 0x47, 0xAF,
+	0x9F, 0xAF, 0x40, 0x02, 0xE7, 0x07, 0x2E, 0x00,
+	0x0A, 0xC0, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06,
+	0x97, 0xCF, 0x00, 0x0E, 0x01, 0x00, 0xC0, 0x57,
+	0x51, 0x00, 0x9F, 0xC0, 0x9E, 0x02, 0xC0, 0x57,
+	0x50, 0x00, 0x20, 0xC0, 0xC0, 0x57, 0x55, 0x00,
+	0x12, 0xC0, 0xC0, 0x57, 0x56, 0x00, 0x9F, 0xC0,
+	0x72, 0x02, 0x9F, 0xCF, 0xD6, 0x02, 0xC1, 0x0B,
+	0x08, 0x06, 0x01, 0xD0, 0x6F, 0x90, 0x08, 0x06,
+	0xC0, 0x07, 0x08, 0x00, 0xC1, 0x0B, 0x08, 0x06,
+	0x9F, 0xAF, 0x28, 0x05, 0x97, 0xCF, 0x2F, 0x0E,
+	0x02, 0x00, 0x08, 0x06, 0xC0, 0x07, 0x08, 0x00,
+	0xC1, 0x0B, 0x08, 0x06, 0x9F, 0xAF, 0x28, 0x05,
+	0x9F, 0xCF, 0xD6, 0x02, 0x2F, 0x0E, 0x02, 0x00,
+	0x09, 0x06, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06,
+	0x9F, 0xCF, 0xD6, 0x02, 0xEF, 0x67, 0x7F, 0xFF,
+	0x09, 0x06, 0xE7, 0x67, 0xFF, 0xFD, 0x22, 0xC0,
+	0xE7, 0x67, 0xEF, 0xFF, 0x24, 0xC0, 0xE7, 0x87,
+	0x10, 0x00, 0x28, 0xC0, 0x9F, 0xAF, 0xB8, 0x05,
+	0xE7, 0x87, 0xE0, 0x21, 0x24, 0xC0, 0x9F, 0xAF,
+	0xA8, 0x05, 0xE7, 0x87, 0x08, 0x00, 0x24, 0xC0,
+	0xE7, 0x67, 0xDF, 0xFF, 0x24, 0xC0, 0xC8, 0x07,
+	0x0A, 0x00, 0xC0, 0x07, 0x00, 0x00, 0xC1, 0x07,
+	0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0x9F, 0xAF,
+	0xB8, 0x05, 0xC0, 0x07, 0x9E, 0x00, 0x9F, 0xAF,
+	0x44, 0x05, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
+	0xC0, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01,
+	0x24, 0xC0, 0xC0, 0x77, 0x00, 0x02, 0x0F, 0xC1,
+	0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x67,
+	0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x08, 0x00,
+	0x24, 0xC0, 0x08, 0xDA, 0x5E, 0xC1, 0xEF, 0x07,
+	0x80, 0x00, 0x09, 0x06, 0x97, 0xCF, 0xEF, 0x07,
+	0x01, 0x00, 0x0A, 0x06, 0x97, 0xCF, 0xEF, 0x07,
+	0x00, 0x00, 0x0B, 0x06, 0xEF, 0x07, 0x00, 0x00,
+	0x0A, 0x06, 0xEF, 0x67, 0x7F, 0xFF, 0x09, 0x06,
+	0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06, 0xE7, 0x67,
+	0xEF, 0xFF, 0x28, 0xC0, 0xE7, 0x67, 0x17, 0xD8,
+	0x24, 0xC0, 0xE7, 0x07, 0x00, 0x00, 0x1E, 0xC0,
+	0xE7, 0x07, 0xFF, 0xFF, 0x22, 0xC0, 0x97, 0xCF,
+	0xC8, 0x07, 0x0E, 0x06, 0x9F, 0xAF, 0xDA, 0x02,
+	0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07,
+	0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0x0E, 0x06,
+	0xF4, 0x05, 0xE7, 0x07, 0xD6, 0x02, 0xF8, 0x05,
+	0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80,
+	0x50, 0xAF, 0x97, 0xCF, 0x2F, 0x0C, 0x02, 0x00,
+	0x07, 0x06, 0x2F, 0x0C, 0x04, 0x00, 0x06, 0x06,
+	0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07,
+	0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0xE2, 0x05,
+	0xF4, 0x05, 0xE7, 0x07, 0xCE, 0x02, 0xF8, 0x05,
+	0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80,
+	0x51, 0xAF, 0x97, 0xCF, 0x9F, 0xAF, 0x66, 0x04,
+	0x9F, 0xAF, 0x1A, 0x03, 0x59, 0xAF, 0x97, 0xCF,
+	0xC0, 0x07, 0x0E, 0x00, 0xC1, 0x0B, 0x0C, 0x06,
+	0x41, 0xD1, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
+	0x3C, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0x68, 0x00,
+	0xC0, 0x07, 0x3B, 0x00, 0x9F, 0xAF, 0x44, 0x05,
+	0x6F, 0x00, 0x0C, 0x06, 0x68, 0x00, 0xE0, 0x07,
+	0x04, 0x01, 0xE8, 0x0B, 0x0A, 0x06, 0xE8, 0x07,
+	0x00, 0x00, 0xE0, 0x07, 0x00, 0x02, 0xE0, 0x07,
+	0xEC, 0x01, 0xE0, 0x07, 0xFC, 0xFF, 0x97, 0xCF,
+	0xE7, 0x07, 0xFF, 0xFF, 0xFA, 0x05, 0xEF, 0x07,
+	0x00, 0x00, 0x0B, 0x06, 0xE7, 0x07, 0x0E, 0x06,
+	0x24, 0x01, 0xE7, 0x07, 0x0E, 0x06, 0xFE, 0x05,
+	0xE7, 0x07, 0x40, 0x00, 0x26, 0x01, 0xE7, 0x07,
+	0x40, 0x00, 0x04, 0x06, 0xE7, 0x07, 0x07, 0x00,
+	0x92, 0xC0, 0x97, 0xCF, 0xEF, 0x07, 0x02, 0x00,
+	0x0B, 0x06, 0x9F, 0xAF, 0x78, 0x01, 0xEF, 0x77,
+	0x80, 0x00, 0x07, 0x06, 0x9F, 0xC0, 0x14, 0x04,
+	0xEF, 0x77, 0x01, 0x00, 0x07, 0x06, 0x37, 0xC0,
+	0xEF, 0x77, 0x01, 0x00, 0x0D, 0x06, 0x0F, 0xC1,
+	0xEF, 0x07, 0x01, 0x00, 0x0D, 0x06, 0xC0, 0x07,
+	0x02, 0x00, 0xC1, 0x07, 0x30, 0x00, 0x9F, 0xAF,
+	0x28, 0x05, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07,
+	0x02, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07,
+	0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07,
+	0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x77,
+	0x03, 0x00, 0x02, 0xC1, 0x08, 0xDA, 0x75, 0xC1,
+	0xC1, 0x77, 0x01, 0x00, 0x0A, 0xC1, 0xC0, 0x07,
+	0x01, 0x00, 0xC1, 0x07, 0x02, 0x00, 0x9F, 0xAF,
+	0x28, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x06, 0x06,
+	0x2C, 0xCF, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07,
+	0x04, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xEF, 0x07,
+	0x00, 0x00, 0x06, 0x06, 0x22, 0xCF, 0xEF, 0x07,
+	0x00, 0x00, 0x0D, 0x06, 0xEF, 0x57, 0x01, 0x00,
+	0x06, 0x06, 0x1B, 0xC0, 0xC0, 0x07, 0x01, 0x00,
+	0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05,
+	0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00,
+	0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07, 0xFF, 0x4F,
+	0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07, 0x38, 0x00,
+	0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x67, 0x03, 0x00,
+	0xC1, 0x57, 0x03, 0x00, 0x02, 0xC0, 0x08, 0xDA,
+	0x73, 0xC1, 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07,
+	0x12, 0x00, 0xEF, 0x57, 0x00, 0x00, 0x06, 0x06,
+	0x02, 0xC0, 0xC1, 0x07, 0x23, 0x00, 0x9F, 0xAF,
+	0x28, 0x05, 0xC0, 0x07, 0x14, 0x00, 0xC1, 0x0B,
+	0xEA, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
+	0x3E, 0x00, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x09,
+	0xE4, 0x05, 0xFA, 0x05, 0x27, 0xD8, 0xFA, 0x05,
+	0xE7, 0x07, 0x0E, 0x06, 0xFC, 0x05, 0xE7, 0x07,
+	0x4E, 0x06, 0x00, 0x06, 0xE7, 0x07, 0x40, 0x00,
+	0x02, 0x06, 0x9F, 0xAF, 0x66, 0x05, 0x9F, 0xAF,
+	0xC6, 0x00, 0x97, 0xCF, 0xC1, 0x0B, 0xE2, 0x05,
+	0x41, 0xD0, 0x01, 0xD2, 0xC1, 0x17, 0x23, 0x00,
+	0x9F, 0xAF, 0xDC, 0x04, 0xC0, 0x07, 0x04, 0x00,
+	0xC1, 0x0B, 0xE3, 0x05, 0x9F, 0xAF, 0x28, 0x05,
+	0xC0, 0x07, 0x06, 0x00, 0xC1, 0x09, 0xE6, 0x05,
+	0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x07, 0x00,
+	0xC1, 0x09, 0xE6, 0x05, 0xC1, 0xD1, 0x9F, 0xAF,
+	0x28, 0x05, 0xC0, 0x07, 0x0B, 0x00, 0xC1, 0x09,
+	0xE8, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
+	0x0C, 0x00, 0xC1, 0x09, 0xE8, 0x05, 0xC1, 0xD1,
+	0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0D, 0x00,
+	0xC1, 0x07, 0x09, 0x00, 0x9F, 0xAF, 0x28, 0x05,
+	0xC0, 0x07, 0x03, 0x00, 0xC1, 0x07, 0x32, 0x00,
+	0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0F, 0x00,
+	0xC1, 0x07, 0x00, 0x00, 0x9F, 0xAF, 0x28, 0x05,
+	0x97, 0xCF, 0xE7, 0x67, 0xFF, 0xD9, 0x24, 0xC0,
+	0xC8, 0x07, 0x0A, 0x00, 0x40, 0x00, 0xC0, 0x67,
+	0x00, 0x02, 0x27, 0x80, 0x24, 0xC0, 0xE7, 0x87,
+	0x00, 0x04, 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xF9,
+	0x24, 0xC0, 0x01, 0xD2, 0x08, 0xDA, 0x72, 0xC1,
+	0xE7, 0x87, 0x00, 0x20, 0x24, 0xC0, 0x97, 0xCF,
+	0x27, 0x00, 0x1E, 0xC0, 0xE7, 0x87, 0xFF, 0x00,
+	0x22, 0xC0, 0xE7, 0x67, 0x7F, 0xFF, 0x24, 0xC0,
+	0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0, 0xE7, 0x87,
+	0x80, 0x00, 0x24, 0xC0, 0x97, 0xCF, 0x9F, 0xAF,
+	0x0A, 0x05, 0x67, 0x00, 0x1E, 0xC0, 0xE7, 0x67,
+	0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00,
+	0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0,
+	0x97, 0xCF, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x67,
+	0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE,
+	0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
+	0xC1, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01,
+	0x24, 0xC0, 0x97, 0xCF, 0xC0, 0x07, 0x40, 0x00,
+	0xC8, 0x09, 0xFC, 0x05, 0xE7, 0x67, 0x00, 0xFF,
+	0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
+	0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x67,
+	0xBF, 0xFF, 0x24, 0xC0, 0x00, 0xDA, 0xE8, 0x09,
+	0x20, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0,
+	0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, 0x00, 0xDA,
+	0xE8, 0x09, 0x20, 0xC0, 0x6D, 0xC1, 0xE7, 0x87,
+	0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF, 0xE7, 0x07,
+	0x32, 0x00, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80,
+	0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0xE7, 0x07,
+	0x20, 0x4E, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80,
+	0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0x09, 0x02,
+	0x19, 0x00, 0x01, 0x01, 0x00, 0x80, 0x96, 0x09,
+	0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+	0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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 int vicam_parameters(struct usb_vicam *vicam);
+static unsigned char setup5[] = {
+	0xB6, 0xC3, 0x2F, 0x01, 0x03, 0x64, 0x0E, 0x00,
+	0x14, 0x00, 0x1A, 0x00, 0x20, 0x00, 0x26, 0x00,
+	0x4A, 0x00, 0x64, 0x00, 0x6A, 0x00, 0x92, 0x00,
+	0x9A, 0x00, 0xA0, 0x00, 0xB2, 0x00, 0xB8, 0x00,
+	0xBE, 0x00, 0xC2, 0x00, 0xC8, 0x00, 0xCE, 0x00,
+	0xDC, 0x00, 0xDA, 0x00, 0xE2, 0x00, 0xE0, 0x00,
+	0xE8, 0x00, 0xE6, 0x00, 0xEE, 0x00, 0xEC, 0x00,
+	0xF2, 0x00, 0xF8, 0x00, 0x02, 0x01, 0x0A, 0x01,
+	0x0E, 0x01, 0x12, 0x01, 0x1E, 0x01, 0x22, 0x01,
+	0x28, 0x01, 0x2C, 0x01, 0x32, 0x01, 0x36, 0x01,
+	0x44, 0x01, 0x50, 0x01, 0x5E, 0x01, 0x72, 0x01,
+	0x76, 0x01, 0x7A, 0x01, 0x80, 0x01, 0x88, 0x01,
+	0x8C, 0x01, 0x94, 0x01, 0x9C, 0x01, 0xA0, 0x01,
+	0xA4, 0x01, 0xAA, 0x01, 0xB0, 0x01, 0xB4, 0x01,
+	0xBA, 0x01, 0xD0, 0x01, 0xDA, 0x01, 0xF6, 0x01,
+	0xFA, 0x01, 0x02, 0x02, 0x34, 0x02, 0x3C, 0x02,
+	0x44, 0x02, 0x4A, 0x02, 0x50, 0x02, 0x56, 0x02,
+	0x74, 0x02, 0x78, 0x02, 0x7E, 0x02, 0x84, 0x02,
+	0x8A, 0x02, 0x88, 0x02, 0x90, 0x02, 0x8E, 0x02,
+	0x94, 0x02, 0xA2, 0x02, 0xA8, 0x02, 0xAE, 0x02,
+	0xB4, 0x02, 0xBA, 0x02, 0xB8, 0x02, 0xC0, 0x02,
+	0xBE, 0x02, 0xC4, 0x02, 0xD0, 0x02, 0xD4, 0x02,
+	0xE0, 0x02, 0xE6, 0x02, 0xEE, 0x02, 0xF8, 0x02,
+	0xFC, 0x02, 0x06, 0x03, 0x1E, 0x03, 0x24, 0x03,
+	0x28, 0x03, 0x30, 0x03, 0x2E, 0x03, 0x3C, 0x03,
+	0x4A, 0x03, 0x4E, 0x03, 0x54, 0x03, 0x58, 0x03,
+	0x5E, 0x03, 0x66, 0x03, 0x6E, 0x03, 0x7A, 0x03,
+	0x86, 0x03, 0x8E, 0x03, 0x96, 0x03, 0xB2, 0x03,
+	0xB8, 0x03, 0xC6, 0x03, 0xCC, 0x03, 0xD4, 0x03,
+	0xDA, 0x03, 0xE8, 0x03, 0xF4, 0x03, 0xFC, 0x03,
+	0x04, 0x04, 0x20, 0x04, 0x2A, 0x04, 0x32, 0x04,
+	0x36, 0x04, 0x3E, 0x04, 0x44, 0x04, 0x42, 0x04,
+	0x48, 0x04, 0x4E, 0x04, 0x4C, 0x04, 0x54, 0x04,
+	0x52, 0x04, 0x5A, 0x04, 0x5E, 0x04, 0x62, 0x04,
+	0x68, 0x04, 0x74, 0x04, 0x7C, 0x04, 0x80, 0x04,
+	0x88, 0x04, 0x8C, 0x04, 0x94, 0x04, 0x9A, 0x04,
+	0xA2, 0x04, 0xA6, 0x04, 0xAE, 0x04, 0xB4, 0x04,
+	0xC0, 0x04, 0xCC, 0x04, 0xD8, 0x04, 0x2A, 0x05,
+	0x46, 0x05, 0x6C, 0x05, 0x00, 0x00
+};
 
-/******************************************************************************
- *
- *  Memory management functions
- *
- *  Taken from bttv-drivers.c 2.4.7-pre3
- *
- ******************************************************************************/
+struct vicam_camera {
+	u16 shutter_speed;	// capture shutter speed
+	u16 gain;		// capture gain
 
-/* Here we want the physical address of the memory.
- * This is used when initializing the contents of the area.
- */
-static inline unsigned long kvirt_to_pa(unsigned long adr)
-{
-	unsigned long kva, ret;
+	u8 *raw_image;		// raw data captured from the camera
+	u8 *framebuf;		// processed data in RGB24 format
 
-	kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
-	kva |= adr & (PAGE_SIZE-1); /* restore the offset */
-	ret = __pa(kva);
-	return ret;
-}
+	struct video_device vdev;	// v4l video device
+	struct usb_device *udev;	// usb device
 
-static void * rvmalloc(unsigned long size)
-{
-	void * mem;
-	unsigned long adr;
+	struct semaphore busy_lock;	// guard against SMP multithreading
 
-	size=PAGE_ALIGN(size);
-	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)
-		{
-			mem_map_reserve(vmalloc_to_page((void *)adr));
-			adr+=PAGE_SIZE;
-			size-=PAGE_SIZE;
-		}
-	}
-	return mem;
-}
+	bool is_initialized;
+	u8 open_count;
+	u8 bulkEndpoint;
+	bool needsDummyRead;
 
-static void rvfree(void * mem, unsigned long size)
-{
-	unsigned long adr;
+	u32 framebuf_size;	// # of valid bytes in framebuf
+	u32 framebuf_read_start;	// position in frame buf that a read is happening at.
 
-	if (mem)
-	{
-		adr=(unsigned long) mem;
-		while ((long) size > 0)
-		{
-			mem_map_unreserve(vmalloc_to_page((void *)adr));
-			adr+=PAGE_SIZE;
-			size-=PAGE_SIZE;
-		}
-		vfree(mem);
-	}
-}
-
-/******************************************************************************
- *
- *  Foo Bar
- *
- ******************************************************************************/
-
-/**
- *	usb_vicam_debug_data
- */
-static inline void usb_vicam_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");
-}
+#ifdef CONFIG_PROC_FS
+	struct proc_dir_entry *proc_entry;
+#endif
 
-/*****************************************************************************
- *
- *  Send command to vicam
- *
- *****************************************************************************/
+};
 
-static int vicam_sndctrl(int set, struct usb_vicam *vicam, unsigned short req,
-	unsigned short value, unsigned char *cp, int size)
-{
-	int ret;
-	unsigned char *transfer_buffer = kmalloc (size, GFP_KERNEL);
+static void *vicam_probe(struct usb_device *dev, unsigned int ifnum,
+			       const struct usb_device_id *id);
+static void vicam_disconnect(struct usb_device *dev, void *ptr);
+static void read_frame(struct vicam_camera *cam, int framenum);
+
+static int
+send_control_msg(struct usb_device *udev, u8 request, u16 value, u16 index,
+		 unsigned char *cp, u16 size)
+{
+	int status;
+
+	// for reasons not yet known to me, you can't send USB control messages
+	// with data in the module (if you are compiled as a module).  Whatever
+	// the reason, copying it to memory allocated as kernel memory then
+	// doing the usb control message fixes the problem.
 
-	/* Needs to return data I think, works for sending though */
+	unsigned char *transfer_buffer = kmalloc(size, GFP_KERNEL);
 	memcpy(transfer_buffer, cp, size);
-	
-	ret = usb_control_msg ( vicam->udev, set ? usb_sndctrlpipe(vicam->udev, 0) : usb_rcvctrlpipe(vicam->udev, 0), req, (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value, 0, transfer_buffer, size, HZ);
+
+	status = usb_control_msg(udev,
+				 usb_sndctrlpipe(udev, 0),
+				 request,
+				 USB_DIR_OUT | USB_TYPE_VENDOR |
+				 USB_RECIP_DEVICE, value, index,
+				 transfer_buffer, size, HZ);
 
 	kfree(transfer_buffer);
-	if (ret)
-		printk("vicam: error: %d\n", ret);
-	mdelay(100);
-	return ret;
-}
 
-
-/*****************************************************************************
- *
- *  Video4Linux Helpers
- * 
- *****************************************************************************/
-
-static int vicam_get_capability(struct usb_vicam *vicam, struct video_capability *b)
-{
-	dbg("vicam_get_capability");
-
-	strcpy(b->name, vicam->camera_name);
-	b->type = VID_TYPE_CAPTURE | VID_TYPE_MONOCHROME;
-	b->channels = 1;
-	b->audios = 0;
-
-	b->maxwidth = vicam->width[vicam->sizes-1];
-	b->maxheight = vicam->height[vicam->sizes-1];
-	b->minwidth = vicam->width[0];
-	b->minheight = vicam->height[0];
+	if (status < 0) {
+		printk(KERN_INFO "Failed sending control message, error %d.\n",
+		       status);
+	}
+
+	return status;
+}
+
+static int
+initialize_camera(struct vicam_camera *cam)
+{
+	struct usb_device *udev = cam->udev;
+	int status;
+
+	if ((status =
+	     send_control_msg(udev, 0xff, 0, 0, setup1, sizeof (setup1))) < 0)
+		return status;
+	if ((status =
+	     send_control_msg(udev, 0xff, 0, 0, setup2, sizeof (setup2))) < 0)
+		return status;
+	if ((status =
+	     send_control_msg(udev, 0xff, 0, 0, setup3, sizeof (setup3))) < 0)
+		return status;
+	if ((status =
+	     send_control_msg(udev, 0xff, 0, 0, setup4, sizeof (setup4))) < 0)
+		return status;
+	if ((status =
+	     send_control_msg(udev, 0xff, 0, 0, setup5, sizeof (setup5))) < 0)
+		return status;
+	if ((status =
+	     send_control_msg(udev, 0xff, 0, 0, setup3, sizeof (setup3))) < 0)
+		return status;
 
 	return 0;
 }
-		
-static int vicam_get_channel(struct usb_vicam *vicam, struct video_channel *v)
+
+static int
+set_camera_power(struct vicam_camera *cam, int state)
 {
-	dbg("vicam_get_channel");
+	int status;
 
-	if (v->channel != 0)
-		return -EINVAL;
- 
-	v->flags = 0;
-	v->tuners = 0;
-	v->type = VIDEO_TYPE_CAMERA;
-	strcpy(v->name, "Camera");
+	if ((status = send_control_msg(cam->udev, 0x50, state, 0, NULL, 0)) < 0)
+		return status;
 
-	return 0;
-} 
-		
-static int vicam_set_channel(struct usb_vicam *vicam, struct video_channel *v)
-{
-	dbg("vicam_set_channel");
+	if (state) {
+		send_control_msg(cam->udev, 0x55, 1, 0, NULL, 0);
+	}
 
-	if (v->channel != 0)
-		return -EINVAL;
-	
 	return 0;
 }
-		
-static int vicam_get_mmapbuffer(struct usb_vicam *vicam, struct video_mbuf *vm)
-{
-	int i;
 
-	dbg("vicam_get_mmapbuffer");
+static int
+vicam_ioctl(struct video_device *dev, unsigned int ioctlnr, void *arg)
+{
+	struct vicam_camera *cam = dev->priv;
+	int retval = 0;
 
-	memset(vm, 0, sizeof(vm));
-	vm->size = VICAM_NUMFRAMES * vicam->maxframesize;
-	vm->frames = VICAM_NUMFRAMES;
+	if (!cam)
+		return -ENODEV;
 
-	for (i=0; i<VICAM_NUMFRAMES; i++)
-		vm->offsets[i] = vicam->maxframesize * i;
+	/* make this _really_ smp-safe */
+	if (down_interruptible(&cam->busy_lock))
+		return -EINTR;
 
-	return 0;
-}
+	switch (ioctlnr) {
+		/* query capabilites */
+	case VIDIOCGCAP:
+		{
+			struct video_capability b;
 
-static int vicam_get_picture(struct usb_vicam *vicam, struct video_picture *p)
-{
-	dbg("vicam_get_picture");
+			DBG("VIDIOCGCAP\n");
+			strcpy(b.name, "ViCam-based Camera");
+			b.type = VID_TYPE_CAPTURE;
+			b.channels = 1;
+			b.audios = 0;
+			b.maxwidth = 320;	/* VIDEOSIZE_CIF */
+			b.maxheight = 240;
+			b.minwidth = 320;	/* VIDEOSIZE_48_48 */
+			b.minheight = 240;
 
-	/* This is probably where that weird 0x56 call goes */
-	p->brightness = vicam->win.brightness;
-	p->hue = vicam->win.hue;
-	p->colour = vicam->win.colour;
-	p->contrast = vicam->win.contrast;
-	p->whiteness = vicam->win.whiteness;
-	p->depth = vicam->win.depth;
-	p->palette = vicam->win.palette;
+			if (copy_to_user(arg, &b, sizeof (b)))
+				retval = -EFAULT;
 
-	return 0;
-}
+			break;
+		}
+		/* get/set video source - we are a camera and nothing else */
+	case VIDIOCGCHAN:
+		{
+			struct video_channel v;
 
-static void synchronize(struct usb_vicam *vicam)
-{
-	DECLARE_WAITQUEUE(wait, current);
-	change_pending = 1;
-	set_current_state(TASK_INTERRUPTIBLE);
-	add_wait_queue(&vicam->wait, &wait);
-	if (change_pending)
-		schedule();
-	remove_wait_queue(&vicam->wait, &wait);
-	set_current_state(TASK_RUNNING);
-	vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x00, NULL, 0);
-	mdelay(10);
-	vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x00, NULL, 0);
-	mdelay(10);
-}
-
-static void params_changed(struct usb_vicam *vicam)
-{
-#if 1
-	synchronize(vicam);
-	mdelay(10);
-	vicam_parameters(vicam);
-	printk("Submiting urb: %d\n", usb_submit_urb(&vicam->readurb));
-#endif
-}
+			DBG("VIDIOCGCHAN\n");
+			if (copy_from_user(&v, arg, sizeof (v))) {
+				retval = -EFAULT;
+				break;
+			}
+			if (v.channel != 0) {
+				retval = -EINVAL;
+				break;
+			}
+
+			v.channel = 0;
+			strcpy(v.name, "Camera");
+			v.tuners = 0;
+			v.flags = 0;
+			v.type = VIDEO_TYPE_CAMERA;
+			v.norm = 0;
+
+			if (copy_to_user(arg, &v, sizeof (v)))
+				retval = -EFAULT;
+			break;
+		}
 
-static int vicam_set_picture(struct usb_vicam *vicam, struct video_picture *p)
-{
-	int changed = 0;
-	info("vicam_set_picture (%d)", p->brightness);
+	case VIDIOCSCHAN:
+		{
+			int v;
 
+			if (copy_from_user(&v, arg, sizeof (v)))
+				retval = -EFAULT;
+			DBG("VIDIOCSCHAN %d\n", v);
 
-#define SET(x) \
-	if (vicam->win.x != p->x) \
-		vicam->win.x = p->x, changed = 1;
-	SET(brightness);
-	SET(hue);
-	SET(colour);
-	SET(contrast);
-	SET(whiteness);
-	SET(depth);
-	SET(palette);
-	if (changed)
-		params_changed(vicam);
+			if (retval == 0 && v != 0)
+				retval = -EINVAL;
 
-	return 0;
-	/* Investigate what should be done maybe 0x56 type call */
-	if (p->depth != 8) return 1;
-	if (p->palette != VIDEO_PALETTE_GREY) return 1;
+			break;
+		}
 
-	return 0;
-}
+		/* image properties */
+	case VIDIOCGPICT:
+		{
+			struct video_picture vp;
+			DBG("VIDIOCGPICT\n");
+			memset(&vp, 0, sizeof (struct video_picture));
+			vp.brightness = cam->gain << 8;
+			vp.depth = 24;
+			vp.palette = VIDEO_PALETTE_RGB24;
+			if (copy_to_user
+			    (arg, &vp, sizeof (struct video_picture)))
+				retval = -EFAULT;
+			break;
+		}
 
-/* FIXME - vicam_sync_frame - important */
-static int vicam_sync_frame(struct usb_vicam *vicam, int frame)
-{
-	dbg("vicam_sync_frame");
+	case VIDIOCSPICT:
+		{
+			struct video_picture *vp = (struct video_picture *) arg;
 
-	if(frame <0 || frame >= VICAM_NUMFRAMES)
-		return -EINVAL;
+			DBG("VIDIOCSPICT depth = %d, pal = %d\n", vp->depth,
+			    vp->palette);
 
-	/* Probably need to handle various cases */
-/*	ret=vicam_newframe(vicam, frame);
-	vicam->frame[frame].grabstate=FRAME_UNUSED;
-*/
-	return 0;
-}
-	
-static int vicam_get_window(struct usb_vicam *vicam, struct video_window *vw)
-{
-	dbg("vicam_get_window");
+			cam->gain = vp->brightness >> 8;
 
-	vw->x = 0;
-	vw->y = 0;
-	vw->chromakey = 0;
-	vw->flags = 0;
-	vw->clipcount = 0;
-	vw->width = vicam->win.width;
-	vw->height = vicam->win.height;
+			if (vp->depth != 24
+			    || vp->palette != VIDEO_PALETTE_RGB24)
+				retval = -EINVAL;
 
-	return 0;
-}
+			break;
+		}
 
-static int vicam_set_window(struct usb_vicam *vicam, struct video_window *vw)
-{
-	info("vicam_set_window");
-		
-	if (vw->flags)
-		return -EINVAL;
-	if (vw->clipcount)
-		return -EINVAL;
+		/* get/set capture window */
+	case VIDIOCGWIN:
+		{
+			struct video_window vw;
+			vw.x = 0;
+			vw.y = 0;
+			vw.width = 320;
+			vw.height = 240;
+			vw.chromakey = 0;
+			vw.flags = 0;
+			vw.clips = NULL;
+			vw.clipcount = 0;
+
+			DBG("VIDIOCGWIN\n");
+
+			if (copy_to_user
+			    ((void *) arg, (void *) &vw, sizeof (vw)))
+				retval = -EFAULT;
+
+			// I'm not sure what the deal with a capture window is, it is very poorly described
+			// in the doc.  So I won't support it now.
+			break;
+		}
 
-	if (vicam->win.width == vw->width && vicam->win.height == vw->height)
-		return 0;
+	case VIDIOCSWIN:
+		{
 
-	/* Pick largest mode that is smaller than specified res */
-	/* If specified res is too small reject                 */
+			struct video_window *vw = (struct video_window *) arg;
+			DBG("VIDIOCSWIN %d x %d\n", vw->width, vw->height);
 
-	/* Add urb send to device... */
+			if ( vw->width != 320 || vw->height != 240 )
+				retval = -EFAULT;
+			
+			break;
+		}
 
-	vicam->win.width = vw->width;
-	vicam->win.height = vw->height;
-	params_changed(vicam);
+		/* mmap interface */
+	case VIDIOCGMBUF:
+		{
+			struct video_mbuf vm;
+			int i;
 
-	return 0;
-}
+			DBG("VIDIOCGMBUF\n");
+			memset(&vm, 0, sizeof (vm));
+			vm.size =
+			    VICAM_MAX_FRAME_SIZE * VICAM_FRAMES;
+			vm.frames = VICAM_FRAMES;
+			for (i = 0; i < VICAM_FRAMES; i++)
+				vm.offsets[i] = VICAM_MAX_FRAME_SIZE * i;
+
+			if (copy_to_user
+			    ((void *) arg, (void *) &vm, sizeof (vm)))
+				retval = -EFAULT;
 
-/* FIXME - vicam_mmap_capture - important */
-static int vicam_mmap_capture(struct usb_vicam *vicam, struct video_mmap *vm)
-{
-	dbg("vicam_mmap_capture");
+			break;
+		}
 
-	/* usbvideo.c looks good for using here */
+	case VIDIOCMCAPTURE:
+		{
+			struct video_mmap vm;
+			// int video_size;
 
-	/* 
-	if (vm->frame >= VICAM_NUMFRAMES)
-		return -EINVAL;
-	if (vicam->frame[vm->frame].grabstate != FRAME_UNUSED)
-		return -EBUSY;
-	vicam->frame[vm->frame].grabstate=FRAME_READY;
-	*/
+			if (copy_from_user
+			    ((void *) &vm, (void *) arg, sizeof (vm))) {
+				retval = -EFAULT;
+				break;
+			}
+
+			DBG("VIDIOCMCAPTURE frame=%d, height=%d, width=%d, format=%d.\n",vm.frame,vm.width,vm.height,vm.format);
+
+			if ( vm.frame >= VICAM_FRAMES || vm.format != VIDEO_PALETTE_RGB24 )
+				retval = -EINVAL;
+
+			// in theory right here we'd start the image capturing
+			// (fill in a bulk urb and submit it asynchronously)
+			//
+			// Instead we're going to do a total hack job for now and
+			// retrieve the frame in VIDIOCSYNC
 
-	/* No need to vicam_set_window here according to Alan */
+			break;
+		}
 
-	/*
-	if (!vicam->streaming)
-		vicam_start_stream(vicam);
-	*/
+	case VIDIOCSYNC:
+		{
+			int frame;
 
-	/* set frame as ready */
+			if (copy_from_user((void *) &frame, arg, sizeof (int))) {
+				retval = -EFAULT;
+				break;
+			}
+			DBG("VIDIOCSYNC: %d\n", frame);
 
-	return 0;
-}
+			read_frame(cam, frame);
 
-/*****************************************************************************
- *
- *  Video4Linux
- * 
- *****************************************************************************/
+			break;
+		}
 
-static int vicam_v4l_open(struct video_device *vdev, int flags)
-{
-	struct usb_vicam *vicam = (struct usb_vicam *)vdev;
-	int err = 0;
-	
-	dbg("vicam_v4l_open");
+		/* pointless to implement overlay with this camera */
+	case VIDIOCCAPTURE:
+	case VIDIOCGFBUF:
+	case VIDIOCSFBUF:
+	case VIDIOCKEY:
+		retval = -EINVAL;
+		break;
 
-	MOD_INC_USE_COUNT; 
-	down(&vicam->sem);
+		/* tuner interface - we have none */
+	case VIDIOCGTUNER:
+	case VIDIOCSTUNER:
+	case VIDIOCGFREQ:
+	case VIDIOCSFREQ:
+		retval = -EINVAL;
+		break;
 
-	if (vicam->open_count)		/* Maybe not needed? */
-		err = -EBUSY;
-	else {
-		vicam->fbuf = rvmalloc(vicam->maxframesize * VICAM_NUMFRAMES);
-		if (!vicam->fbuf)
-			err=-ENOMEM;
-		else {
-			vicam->open_count = 1;
-		}
-#ifdef BLINKING
-		vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x01, NULL, 0);
-		info ("led on");
-		vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x01, NULL, 0);
-#endif
+		/* audio interface - we have none */
+	case VIDIOCGAUDIO:
+	case VIDIOCSAUDIO:
+		retval = -EINVAL;
+		break;
+	default:
+		retval = -ENOIOCTLCMD;
+		break;
 	}
 
-	up(&vicam->sem);
-	if (err)
-		MOD_DEC_USE_COUNT;
-	return err;
+	up(&cam->busy_lock);
+	return retval;
 }
 
-static void vicam_v4l_close(struct video_device *vdev)
+static int
+vicam_open(struct video_device *dev, int flags)
 {
-	struct usb_vicam *vicam = (struct usb_vicam *)vdev;
+	struct vicam_camera *cam =
+	    (struct vicam_camera *) dev->priv;
+	DBG("open\n");
 
-	dbg("vicam_v4l_close");
-	
-	down(&vicam->sem);
+	if (!cam) {
+		printk(KERN_ERR
+		       "vicam video_device improperly initialized");
+	}
 
-#ifdef BLINKING
-	info ("led off");
-	vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x00, NULL, 0);
-//	vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x00, NULL, 0); Leave it on
-#endif
+	down_interruptible(&cam->busy_lock);
+
+	if (cam->open_count > 0) {
+		printk(KERN_INFO
+		       "vicam_open called on already opened camera");
+		up(&cam->busy_lock);
+		return -EBUSY;
+	}
+
+	if (!cam->raw_image) {
+		cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL);
+		if (!cam->raw_image) {
+			up(&cam->busy_lock);
+			return -ENOMEM;
+		}
+	}
+
+	if (!cam->framebuf) {
+		cam->framebuf =
+		    usbvideo_rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
+		if (!cam->framebuf) {
+			kfree(cam->raw_image);
+			up(&cam->busy_lock);
+			return -ENOMEM;
+		}
+	}
+	// First upload firmware, then turn the camera on
 
-	rvfree(vicam->fbuf, vicam->maxframesize * VICAM_NUMFRAMES);
-	vicam->fbuf = 0;
-	vicam->open_count=0;
+	if (!cam->is_initialized) {
+		initialize_camera(cam);
 
-	up(&vicam->sem);
-	/* Why does se401.c have a usbdevice check here? */
-	/* If device is unplugged while open, I guess we only may unregister now */
-	MOD_DEC_USE_COUNT;
+		cam->is_initialized = 1;
+	}
+
+	set_camera_power(cam, 1);
+
+	cam->needsDummyRead = 1;
+	cam->open_count++;
+
+	up(&cam->busy_lock);
+
+	return 0;
 }
 
-static long vicam_v4l_read(struct video_device *vdev, char *user_buf, unsigned long buflen, int noblock)
+static void
+vicam_close(struct video_device *dev)
 {
-	//struct usb_vicam *vicam = (struct usb_vicam *)vdev;
+	DBG("close\n");
+	set_camera_power((struct vicam_camera *) dev->priv, 0);
 
-	dbg("vicam_v4l_read(%ld)", buflen);
+	((struct vicam_camera *) dev->priv)->open_count--;
+}
 
-	if (!vdev || !buf)
-		return -EFAULT;
-	
-	if(buflen > 0x1e480)
-		buflen = 0x1e480;
-	if (copy_to_user(user_buf, buf2, buflen))
-		return -EFAULT;
-	return buflen;
+inline int pin(int x)
+{
+	return((x > 255) ? 255 : ((x < 0) ? 0 : x));
 }
 
-static long vicam_v4l_write(struct video_device *dev, const char *buf, unsigned long count, int noblock)
+inline void writepixel(char *rgb, int Y, int Cr, int Cb)
 {
-	info("vicam_v4l_write");
-	return -EINVAL;
+	Y = 1160 * (Y - 16);
+	
+	rgb[2] = pin( ( ( Y + ( 1594 * Cr ) ) + 500 ) / 1300 );
+	rgb[1] = pin( ( ( Y - (  392 * Cb ) - ( 813 * Cr ) ) + 500 ) / 1000 );
+	rgb[0] = pin( ( ( Y + ( 2017 * Cb ) ) + 500 ) / 900 );
 }
 
-static int vicam_v4l_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
+#define DATA_HEADER_SIZE 64
+
+// --------------------------------------------------------------------------------
+//	vicam_decode_color - Convert from Vicam Y-Cr-Cb to RGB
+//
+//   Copyright (C) 2002 Monroe Williams (monroe@pobox.com)
+// --------------------------------------------------------------------------------
+
+void vicam_decode_color( char *data, char *rgb)
 {
-	struct usb_vicam *vicam = (struct usb_vicam *)vdev;
-	int ret = -EL3RST;
+	int x,y;
+	int Cr, Cb;
+	int sign;
+	int prevX, nextX, prevY, nextY;
+	int skip;
+	unsigned char *src;
+	unsigned char *dst;
 
-	if (!vicam->udev)
-		return -EIO;
+	prevY = 512;
+	nextY = 512;
 
-	down(&vicam->sem);
+	src = data + DATA_HEADER_SIZE;
+	dst = rgb;
 
-	switch (cmd) {
-	case VIDIOCGCAP:
-	{
-		struct video_capability b;
-		ret = vicam_get_capability(vicam,&b);
-		dbg("name %s",b.name);
-		if (copy_to_user(arg, &b, sizeof(b)))
-			ret = -EFAULT;
-	}
-	case VIDIOCGFBUF:
+	for(y = 1; y < 241; y += 2)
 	{
-		struct video_buffer vb;
-		info("vicam_v4l_ioctl - VIDIOCGBUF - query frame buffer param");
-		/* frame buffer not supported, not used */
-		memset(&vb, 0, sizeof(vb));
-		vb.base = NULL;
+		// even line
+		sign = 1;
+		prevX = 1;
+		nextX = 1;
+
+		skip = 0;
+
+		dst = rgb + (y-1)*320*3;
 		
-		/* FIXME - VIDIOCGFBUF - why the void */
-		if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb)))
-			ret = -EFAULT;
-		ret = 0;
-	}
-	case VIDIOCGWIN:
-	{
-		struct video_window vw;
-		ret = vicam_get_window(vicam, &vw);
-		if (copy_to_user(arg, &vw, sizeof(vw)))
-			ret = -EFAULT;
-	}
-	case VIDIOCSWIN:
-	{
-		struct video_window vw;
-		if (copy_from_user(&vw, arg, sizeof(vw)))
-			ret = -EFAULT;
-		else
-			ret = vicam_set_window(vicam, &vw);
-		return ret;
-	}
-	case VIDIOCGCHAN:
-	{
-		struct video_channel v;
+		for(x = 0; x < 512; x++)
+		{
+			if(x == 512-1)
+				nextX = -1;
 
-		if (copy_from_user(&v, arg, sizeof(v)))
-			ret = -EFAULT;
-		else {
-			ret = vicam_get_channel(vicam,&v);
-			if (copy_to_user(arg, &v, sizeof(v)))
-				ret = -EFAULT;
+			Cr = sign * ((src[prevX] - src[0]) + (src[nextX] - src[0])) >> 1;
+			Cb = sign * ((src[prevY] - src[prevX + prevY]) + (src[prevY] - src[nextX + prevY]) + (src[nextY] - src[prevX + nextY]) + (src[nextY] - src[nextX + nextY])) >> 2;
+
+			writepixel(
+					dst + ((x*5)>>3)*3,
+					src[0] + (sign * (Cr >> 1)),
+					Cr,
+					Cb);
+
+			src++;
+			sign *= -1;
+			prevX = -1;
+		}
+
+		prevY = -512;
+
+		if(y == (242 - 2))
+			nextY = -512;
+
+		// odd line
+		sign = 1;
+		prevX = 1;
+		nextX = 1;
+
+		skip = 0;
+
+		dst = rgb + (y)*320*3;
+		
+		for(x = 0; x < 512; x++)
+		{
+			if(x == 512-1)
+				nextX = -1;
+			
+			Cr = sign * ((src[prevX + prevY] - src[prevY]) + (src[nextX + prevY] - src[prevY]) + (src[prevX + nextY] - src[nextY]) + (src[nextX + nextY] - src[nextY])) >> 2;
+			Cb = sign * ((src[0] - src[prevX]) + (src[0] - src[nextX])) >> 1;
+
+			writepixel(
+					dst + ((x * 5)>>3)*3,
+					src[0] - (sign * (Cb >> 1)),
+					Cr,
+					Cb);
+
+			src++;
+			sign *= -1;
+			prevX = -1;
 		}
 	}
-	case VIDIOCSCHAN:
-	{
-		struct video_channel v;
-		if (copy_from_user(&v, arg, sizeof(v)))
-			ret = -EFAULT;
-		else
-			ret = vicam_set_channel(vicam,&v);
- 	}
-	case VIDIOCGPICT:
-	{
-		struct video_picture p;
-		ret = vicam_get_picture(vicam, &p);
-		if (copy_to_user(arg, &p, sizeof(p)))
-			ret = -EFAULT;
-	}
-	case VIDIOCSPICT:
-	{
-		struct video_picture p;
-		if (copy_from_user(&p, arg, sizeof(p)))
-			ret = -EFAULT;
-		else
-			ret = vicam_set_picture(vicam, &p);
-	}
-	case VIDIOCGMBUF:
-	{
-		struct video_mbuf vm;
-		ret = vicam_get_mmapbuffer(vicam,&vm);
-		/* FIXME - VIDIOCGMBUF - why the void */
-		if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
-			ret = -EFAULT;
+}
+
+static void
+read_frame(struct vicam_camera *cam, int framenum)
+{
+	unsigned char request[16];
+	int realShutter;
+	int n;
+	int actual_length;
+
+	memset(request, 0, 16);
+	request[0] = cam->gain;	// 0 = 0% gain, FF = 100% gain
+
+	request[1] = 0;	// 512x242 capture
+
+	request[2] = 0x90;	// the function of these two bytes
+	request[3] = 0x07;	// is not yet understood
+
+	if (cam->shutter_speed > 60) {
+		// Short exposure
+		realShutter =
+		    ((-15631900 / cam->shutter_speed) + 260533) / 1000;
+		request[4] = realShutter & 0xFF;
+		request[5] = (realShutter >> 8) & 0xFF;
+		request[6] = 0x03;
+		request[7] = 0x01;
+	} else {
+		// Long exposure
+		realShutter = 15600 / cam->shutter_speed - 1;
+		request[4] = 0;
+		request[5] = 0;
+		request[6] = realShutter & 0xFF;
+		request[7] = realShutter >> 8;
+	}
+
+	// Per John Markus Bjørndalen, byte at index 8 causes problems if it isn't 0
+	request[8] = 0;
+	// bytes 9-15 do not seem to affect exposure or image quality
+
+	n = send_control_msg(cam->udev, 0x51, 0x80, 0, request, 16);
+
+	if (n < 0) {
+		printk(KERN_ERR
+		       " Problem sending frame capture control message");
+		return;
 	}
-	case VIDIOCMCAPTURE:
-	{
-		struct video_mmap vm;
-		ret = vicam_mmap_capture(vicam, &vm);
-		/* FIXME: This is probably not right */
+
+	n = usb_bulk_msg(cam->udev,
+			 usb_rcvbulkpipe(cam->udev, cam->bulkEndpoint),
+			 cam->raw_image,
+			 512 * 242 + 128, &actual_length, 500);
+
+	if (n < 0) {
+		printk(KERN_ERR "Problem during bulk read of frame data: %d\n",
+		       n);
 	}
-	case VIDIOCSYNC:
-	{
-		int frame;
-		/* FIXME - VIDIOCSYNC - why the void */
-		if (copy_from_user((void *)&frame, arg, sizeof(int)))
-			ret = -EFAULT;
-		else
-			ret = vicam_sync_frame(vicam,frame);
+
+	vicam_decode_color(cam->raw_image,
+			 cam->framebuf +
+			 framenum * VICAM_MAX_FRAME_SIZE );
+
+	cam->framebuf_size =
+	    320 * 240 * VICAM_BYTES_PER_PIXEL;
+	cam->framebuf_read_start = 0;
+
+	return;
+
+}
+
+static long
+vicam_read(struct video_device *dev, char *buf,
+		 unsigned long count, int noblock)
+{
+	struct vicam_camera *cam = dev->priv;
+	DBG("read %d bytes.\n", (int) count);
+
+	if (!buf)
+		return -EINVAL;
+
+	if (!count)
+		return -EINVAL;
+
+	// This is some code that will hopefully allow us to do shell copies from
+	// the /dev/videoX to a file and have it actually work.
+	if (cam->framebuf_size != 0) {
+		if (cam->framebuf_read_start == cam->framebuf_size) {
+			cam->framebuf_size = cam->framebuf_read_start = 0;
+			return 0;
+		} else {
+			if (cam->framebuf_read_start + count <=
+			    cam->framebuf_size) {
+				// count does not exceed available bytes
+				copy_to_user(buf,
+					     (cam->framebuf) +
+					     cam->framebuf_read_start, count);
+				cam->framebuf_read_start += count;
+				return count;
+			} else {
+				count =
+				    cam->framebuf_size -
+				    cam->framebuf_read_start;
+				copy_to_user(buf,
+					     (cam->framebuf) +
+					     cam->framebuf_read_start, count);
+				cam->framebuf_read_start = cam->framebuf_size;
+				return count;
+			}
+		}
 	}
 
-	case VIDIOCKEY:
-		ret = 0;
- 
-	case VIDIOCCAPTURE:
-	case VIDIOCSFBUF:
-	case VIDIOCGTUNER:
-	case VIDIOCSTUNER:
-	case VIDIOCGFREQ:
-	case VIDIOCSFREQ:
-	case VIDIOCGAUDIO:
-	case VIDIOCSAUDIO:
-	case VIDIOCGUNIT:
-		ret = -EINVAL;
+	down_interruptible(&cam->busy_lock);
 
-	default:
-	{
-		info("vicam_v4l_ioctl - %ui",cmd);
-		ret = -ENOIOCTLCMD;
+	if (cam->needsDummyRead) {
+		read_frame(cam, 0);
+		cam->needsDummyRead = 0;
 	}
-	} /* end switch */
+	// read_frame twice because the camera doesn't seem to take the shutter speed for the first one.
+
+	read_frame(cam, 0);
 
-	up(&vicam->sem);
-        return ret;
+	if (count > cam->framebuf_size)
+		count = cam->framebuf_size;
+
+	copy_to_user(buf, cam->framebuf, count);
+
+	if (count != cam->framebuf_size)
+		cam->framebuf_read_start = count;
+	else
+		cam->framebuf_size = 0;
+
+	up(&cam->busy_lock);
+
+	return count;
 }
 
-static int vicam_v4l_mmap(struct video_device *dev, const char *adr, unsigned long size)
+static int
+vicam_mmap(struct video_device *dev, const char *adr, unsigned long size)
 {
-	struct usb_vicam *vicam = (struct usb_vicam *)dev;
-	unsigned long start = (unsigned long)adr;
+	// TODO: allocate the raw frame buffer if necessary
+	unsigned long start = (unsigned long) adr;
 	unsigned long page, pos;
+	struct vicam_camera *cam = dev->priv;
 
-	down(&vicam->sem);
-	
-	if (vicam->udev == NULL) {
-		up(&vicam->sem);
-		return -EIO;
-	}
-#if 0
-	if (size > (((VICAM_NUMFRAMES * vicam->maxframesize) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) {
-		up(&vicam->sem);
-		return -EINVAL;
+	if (!cam)
+		return -ENODEV;
+
+	DBG("vicam_mmap: %ld\n", size);
+
+	/* We let mmap allocate as much as it wants because Linux was adding 2048 bytes
+	 * to the size the application requested for mmap and it was screwing apps up.
+	 if (size > VICAM_FRAMES*VICAM_MAX_FRAME_SIZE)
+	 return -EINVAL;
+	 */
+
+	/* make this _really_ smp-safe */
+	if (down_interruptible(&cam->busy_lock))
+		return -EINTR;
+
+	if (!cam->framebuf) {	/* we do lazy allocation */
+		cam->framebuf =
+		    usbvideo_rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
+		if (!cam->framebuf) {
+			up(&cam->busy_lock);
+			return -ENOMEM;
+		}
 	}
-#endif
-	pos = (unsigned long)vicam->fbuf;
+
+	pos = (unsigned long) (cam->framebuf);
 	while (size > 0) {
-		page = kvirt_to_pa(pos);
+		page = usbvideo_kvirt_to_pa(pos);
 		if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) {
-			up(&vicam->sem);
+			up(&cam->busy_lock);
 			return -EAGAIN;
 		}
 		start += PAGE_SIZE;
@@ -653,288 +1026,316 @@
 		else
 			size = 0;
 	}
-	up(&vicam->sem);
 
-        return 0;
+	up(&cam->busy_lock);
+
+	return 0;
 }
 
-/* FIXME - vicam_v4l_init */
-static int vicam_v4l_init(struct video_device *dev)
+#ifdef CONFIG_PROC_FS
+
+static struct proc_dir_entry *vicam_proc_root = NULL;
+
+static int
+vicam_read_proc(char *page, char **start, off_t off,
+		      int count, int *eof, void *data)
 {
-	/* stick proc fs stuff in here if wanted */
-	dbg("vicam_v4l_init");
-	return 0;
+	char *out = page;
+	int len;
+	struct vicam_camera *cam = (struct vicam_camera *) data;
+
+	out +=
+	    sprintf(out, "Vicam-based WebCam Linux Driver.\n");
+	out += sprintf(out, "(c) 2002 Joe Burks (jburks@wavicle.org)\n");
+	out += sprintf(out, "vicam stats:\n");
+	out += sprintf(out, "    Shutter Speed: 1/%d\n", cam->shutter_speed);
+	out += sprintf(out, "             Gain: %d\n", cam->gain);
+
+	len = out - page;
+	len -= off;
+	if (len < count) {
+		*eof = 1;
+		if (len <= 0)
+			return 0;
+	} else
+		len = count;
+
+	*start = page + off;
+	return len;
 }
 
-/* FIXME - vicam_template - important */
-static struct video_device vicam_template = {
-	name:		"vicam USB camera",
-	type:		VID_TYPE_CAPTURE,
-	hardware:	VID_HARDWARE_SE401, /* need to ask for own id */
-	open:		vicam_v4l_open,
-	close:		vicam_v4l_close,
-	read:		vicam_v4l_read,
-	write:		vicam_v4l_write,
-	ioctl:		vicam_v4l_ioctl,
-	mmap:		vicam_v4l_mmap,
-	initialize:	vicam_v4l_init,
-};
+static int
+vicam_write_proc(struct file *file, const char *buffer,
+		       unsigned long count, void *data)
+{
+	char *in;
+	char *start;
+	struct vicam_camera *cam = (struct vicam_camera *) data;
 
-/******************************************************************************
- *
- *  Some Routines
- *
- ******************************************************************************/
+	in = kmalloc(count + 1, GFP_KERNEL);
+	if (!in)
+		return -ENOMEM;
 
-/*
-Flash the led
-vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x01, NULL, 0);
-info ("led on");
-vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x01, NULL, 0);
-info ("led off");
-vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x00, NULL, 0);
-vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x00, NULL, 0);
-*/
+	in[count] = 0;		// I'm not sure buffer is gauranteed to be null terminated
+	// so I do this to make sure I have a null in there.
+
+	strncpy(in, buffer, count);
 
-static void vicam_bulk(struct urb *urb)
+	start = strstr(in, "gain=");
+	if (start
+	    && (start == in || *(start - 1) == ' ' || *(start - 1) == ','))
+		cam->gain = simple_strtoul(start + 5, NULL, 10);
+
+	start = strstr(in, "shutter=");
+	if (start
+	    && (start == in || *(start - 1) == ' ' || *(start - 1) == ','))
+		cam->shutter_speed = simple_strtoul(start + 8, NULL, 10);
+
+	kfree(in);
+	return count;
+}
+
+void
+vicam_create_proc_root(void)
 {
-	struct usb_vicam *vicam = urb->context;
+	vicam_proc_root = create_proc_entry("video/vicam", S_IFDIR, 0);
 
-	/*	if (!vicam || !vicam->dev || !vicam->used)
-		return;
-	*/
+	if (vicam_proc_root)
+		vicam_proc_root->owner = THIS_MODULE;
+	else
+		printk(KERN_ERR
+		       "could not create /proc entry for vicam!");
+}
 
-	if (urb->status)
-		printk("vicam%d: nonzero read/write bulk status received: %d",
-			0, urb->status);
-
-	urb->actual_length = 0;
-	urb->dev = vicam->udev;
-
-	memcpy(buf2, buf+64, 0x1e480);
-	if (vicam->fbuf)
-		memcpy(vicam->fbuf, buf+64, 0x1e480);
-
-	if (!change_pending) {
-		if (usb_submit_urb(urb))
-			dbg("failed resubmitting read urb");
-	} else {
-		change_pending = 0;
-		wake_up_interruptible(&vicam->wait);
-	}
+void
+vicam_destroy_proc_root(void)
+{
+	if (vicam_proc_root)
+		remove_proc_entry("video/vicam", 0);
 }
 
-static int vicam_parameters(struct usb_vicam *vicam)
+void
+vicam_create_proc_entry(void *ptr)
 {
-	unsigned char req[0x10];
-	unsigned int shutter;
-	shutter = 10;
+	struct vicam_camera *cam = (struct vicam_camera *) ptr;
 
-	switch (vicam->win.width) {
-	case 512:
-	default:
-		memcpy(req, s512x242bw, 0x10);
-		break;
-	case 256:
-		memcpy(req, s256x242bw, 0x10);
-		break;
-	case 128:
-		memcpy(req, s128x122bw, 0x10);
-		break;
+	char name[7];
+	struct proc_dir_entry *ent;
+
+	DBG(KERN_INFO "vicam: creating proc entry\n");
+
+	if (!vicam_proc_root || !cam) {
+		printk(KERN_INFO
+		       "vicam: could not create proc entry, %s pointer is null.\n",
+		       (!cam ? "camera" : "root"));
+		return;
 	}
 
+	sprintf(name, "video%d", cam->vdev.minor);
 
-	mdelay(10);
-	vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x01, NULL, 0);
-	info ("led on");
-	vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x01, NULL, 0);
-
-	mdelay(10);
-
-	shutter = vicam->win.contrast / 256;
-	if (shutter == 0)
-		shutter = 1;
-	printk("vicam_parameters: brightness %d, shutter %d\n", vicam->win.brightness, shutter );
-	req[0] = vicam->win.brightness /256;
-	shutter = 15600/shutter - 1;
-	req[6] = shutter & 0xff;
-	req[7] = (shutter >> 8) & 0xff;
-	vicam_sndctrl(1, vicam, VICAM_REQ_CAPTURE, 0x80, req, 0x10);
-	mdelay(10);
-	vicam_sndctrl(0, vicam, VICAM_REQ_GET_SOMETHIN, 0, buf, 0x10);
-	mdelay(10);
+	ent =
+	    create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR,
+			      vicam_proc_root);
+	if (!ent)
+		return;
 
-	return 0;
+	ent->data = cam;
+	ent->read_proc = vicam_read_proc;
+	ent->write_proc = vicam_write_proc;
+	ent->size = 512;
+	cam->proc_entry = ent;
 }
 
-static int vicam_init(struct usb_vicam *vicam)
+void
+vicam_destroy_proc_entry(void *ptr)
 {
-	int width[] = {128, 256, 512};
-	int height[] = {122, 242, 242};
+	struct vicam_camera *cam = (struct vicam_camera *) ptr;
+	char name[7];
+
+	if (!cam || !cam->proc_entry)
+		return;
 
-	dbg("vicam_init");
-	buf = kmalloc(0x1e480, GFP_KERNEL);
-	buf2 = kmalloc(0x1e480, GFP_KERNEL);
-	if ((!buf) || (!buf2)) {
-		printk("Not enough memory for vicam!\n");
-		goto error;
-	}
-
-	/* do we do aspect correction in kernel or not? */
-	vicam->sizes = 3;
-	vicam->width = kmalloc(vicam->sizes*sizeof(int), GFP_KERNEL);
-	vicam->height = kmalloc(vicam->sizes*sizeof(int), GFP_KERNEL);
-	memcpy(vicam->width, &width, sizeof(width));
-	memcpy(vicam->height, &height, sizeof(height));
-	vicam->maxframesize = vicam->width[vicam->sizes-1] * vicam->height[vicam->sizes-1];
-
-	/* Download firmware to camera */
-	vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, firmware1, sizeof(firmware1));
-	vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, findex1, sizeof(findex1));
-	vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, fsetup, sizeof(fsetup));
-	vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, firmware2, sizeof(firmware2));
-	vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, findex2, sizeof(findex2));
-	vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, fsetup, sizeof(fsetup));
-
-	vicam_parameters(vicam);
-
-	FILL_BULK_URB(&vicam->readurb, vicam->udev, usb_rcvbulkpipe(vicam->udev, 0x81),
-		      buf, 0x1e480, vicam_bulk, vicam);
-	printk("Submiting urb: %d\n", usb_submit_urb(&vicam->readurb));
+	sprintf(name, "video%d", cam->vdev.minor);
+	remove_proc_entry(name, vicam_proc_root);
+	cam->proc_entry = NULL;
 
+}
+
+#endif
+
+int
+vicam_video_init(struct video_device *vdev)
+{
+	// This would normally create the proc entry for this camera
+#ifdef CONFIG_PROC_FS
+	vicam_create_proc_entry(vdev->priv);
+#endif
 	return 0;
-error:
-	if (buf)
-		kfree(buf);
-	if (buf2)
-		kfree(buf2);
-	return 1;
 }
 
-static void * vicam_probe(struct usb_device *udev, unsigned int ifnum,
-	const struct usb_device_id *id)
+static long
+vicam_write(struct video_device *v, const char *buf, unsigned long count,
+		  int nonblock)
 {
-	struct usb_vicam *vicam;
-	char *camera_name=NULL;
 
-	dbg("vicam_probe");
+	return -EINVAL;
+}
+
+static struct video_device vicam_template = {
+	owner:THIS_MODULE,
+	name:"ViCam-based USB Camera",
+	type:VID_TYPE_CAPTURE,
+	hardware:VID_HARDWARE_VICAM,
+	open:vicam_open,
+	close:vicam_close,
+	read:vicam_read,
+	write:vicam_write,
+	ioctl:vicam_ioctl,
+	mmap:vicam_mmap,
+	initialize:vicam_video_init,
+	minor:-1,
+};
+
+/* table of devices that work with this driver */
+static struct usb_device_id vicam_table[] = {
+	{USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID)},
+	{}			/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, vicam_table);
+
+static struct usb_driver vicam_driver = {
+	name:"vicam",
+	probe:vicam_probe,
+	disconnect:vicam_disconnect,
+	id_table:vicam_table
+};
+
+/**
+ *	vicam_probe
+ *
+ *	Called by the usb core when a new device is connected that it thinks
+ *	this driver might be interested in.
+ */
+static void *
+vicam_probe(struct usb_device *dev, unsigned int ifnum,
+		  const struct usb_device_id *id)
+{
+	int nas, bulkEndpoint = 0;
+	const struct usb_interface_descriptor *interface;
+	const struct usb_endpoint_descriptor *endpoint;
+	struct vicam_camera *cam;
 
 	/* See if the device offered us matches what we can accept */
-	if ((udev->descriptor.idVendor != USB_VICAM_VENDOR_ID) ||
-	    (udev->descriptor.idProduct != USB_VICAM_PRODUCT_ID)) {
+	if ((dev->descriptor.idVendor != USB_VICAM_VENDOR_ID) ||
+	    (dev->descriptor.idProduct != USB_VICAM_PRODUCT_ID)) {
 		return NULL;
 	}
-	
-	camera_name="3Com HomeConnect USB";
-	info("ViCAM camera found: %s", camera_name);
-	
-	vicam = kmalloc (sizeof(struct usb_vicam), GFP_KERNEL);
-	if (vicam == NULL) {
-		err ("couldn't kmalloc vicam struct");
+
+	printk(KERN_INFO "ViCam based webcam connected\n");
+
+	nas = dev->actconfig->interface[ifnum].num_altsetting;
+	if (nas != 1) {
+		printk(KERN_WARNING
+		       "Expected only one alternate setting for this camera!\n");
 		return NULL;
 	}
-	memset(vicam, 0, sizeof(*vicam));
-	
-	vicam->udev = udev;
-	vicam->camera_name = camera_name;
-	vicam->win.brightness = 128;
-	vicam->win.contrast = 10;
-
-	/* FIXME */
-	if (vicam_init(vicam)) {
-		kfree(vicam);
-		return NULL;
+
+	interface = &dev->actconfig->interface[ifnum].altsetting[0];
+	DBG(KERN_DEBUG "Interface %d. has %u. endpoints!\n",
+	       ifnum, (unsigned) (interface->bNumEndpoints));
+	endpoint = &interface->endpoint[0];
+
+	if ((endpoint->bEndpointAddress & 0x80) &&
+	    ((endpoint->bmAttributes & 3) == 0x02)) {
+		/* we found a bulk in endpoint */
+		bulkEndpoint = endpoint->bEndpointAddress;
+	} else {
+		printk(KERN_ERR
+		       "No bulk in endpoint was found ?! (this is bad)\n");
 	}
-	memcpy(&vicam->vdev, &vicam_template, sizeof(vicam_template));
-	memcpy(vicam->vdev.name, vicam->camera_name, strlen(vicam->camera_name));
-	
-	if (video_register_device(&vicam->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
-		err("video_register_device");
-		kfree(vicam);
+
+	if ((cam =
+	     kmalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) {
+		printk(KERN_WARNING
+		       "could not allocate kernel memory for vicam_camera struct\n");
 		return NULL;
 	}
 
-	info("registered new video device: video%d", vicam->vdev.minor);
-	
-	init_MUTEX (&vicam->sem);
-	init_waitqueue_head(&vicam->wait);
-	
-	return vicam;
-}
+	memset(cam, 0, sizeof (struct vicam_camera));
 
+	cam->shutter_speed = 15;
 
-/* FIXME - vicam_disconnect - important */
-static void vicam_disconnect(struct usb_device *udev, void *ptr)
-{
-	struct usb_vicam *vicam;
+	init_MUTEX(&cam->busy_lock);
 
-	vicam = (struct usb_vicam *) ptr;
+	memcpy(&cam->vdev, &vicam_template,
+	       sizeof (vicam_template));
+	cam->vdev.priv = cam;	// sort of a reverse mapping for those functions that get vdev only
 
-	if (!vicam->open_count)
-		video_unregister_device(&vicam->vdev);
-	vicam->udev = NULL;
-/*
-	vicam->frame[0].grabstate = FRAME_ERROR;
-	vicam->frame[1].grabstate = FRAME_ERROR;
-*/
+	cam->udev = dev;
+	cam->bulkEndpoint = bulkEndpoint;
 
-	/* Free buffers and shit */
+	if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) == -1) {
+		kfree(cam);
+		printk(KERN_WARNING "video_register_device failed\n");
+		return NULL;
+	}
 
-	info("%s disconnected", vicam->camera_name);
-	synchronize(vicam);
+	printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor);
 
-	if (!vicam->open_count) {
-		/* Other random junk */
-		kfree(vicam);
-		vicam = NULL;
-	}
+	return cam;
 }
 
-/* usb specific object needed to register this driver with the usb subsystem */
-static struct usb_driver vicam_driver = {
-	name:		"vicam",
-	probe:		vicam_probe,
-	disconnect:	vicam_disconnect,
-	id_table:	vicam_table,
-};
-
-/******************************************************************************
- *
- *  Module Routines
- *
- ******************************************************************************/
+static void
+vicam_disconnect(struct usb_device *dev, void *ptr)
+{
+	struct vicam_camera *cam = ptr;
+	video_unregister_device(&cam->vdev);
 
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
+#ifdef CONFIG_PROC_FS
+	vicam_destroy_proc_entry(cam);
+#endif
 
-/* Module paramaters */
-MODULE_PARM(debug, "i");
-MODULE_PARM_DESC(debug, "Debug enabled or not");
+	if (cam->raw_image)
+		kfree(cam->raw_image);
+	if (cam->framebuf)
+		usbvideo_rvfree(cam->framebuf,
+		       VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
 
-static int __init usb_vicam_init(void)
-{
-	int result;
+	kfree(cam);
 
-	printk("VICAM: initializing\n");
-	/* register this driver with the USB subsystem */
-	result = usb_register(&vicam_driver);
-	if (result < 0) {
-		err("usb_register failed for the "__FILE__" driver. Error number %d",
-		    result);
-		return -1;
-	}
+	printk(KERN_DEBUG "ViCam-based WebCam disconnected\n");
+}
 
-	info(DRIVER_VERSION " " DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+/*
+ */
+static int __init
+usb_vicam_init(void)
+{
+	DBG(KERN_INFO "ViCam-based WebCam driver startup\n");
+#ifdef CONFIG_PROC_FS
+	vicam_create_proc_root();
+#endif
+	if (usb_register(&vicam_driver) != 0)
+		printk(KERN_WARNING "usb_register failed!\n");
 	return 0;
 }
 
-static void __exit usb_vicam_exit(void)
+static void __exit
+usb_vicam_exit(void)
 {
-	/* deregister this driver with the USB subsystem */
+	DBG(KERN_INFO
+	       "ViCam-based WebCam driver shutdown\n");
+
 	usb_deregister(&vicam_driver);
+#ifdef CONFIG_PROC_FS
+	vicam_destroy_proc_root();
+#endif
 }
 
 module_init(usb_vicam_init);
 module_exit(usb_vicam_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/vicam.h linux-2.4.21-pre6/drivers/usb/vicam.h
--- linux-2.4.20/drivers/usb/vicam.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/vicam.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,81 +0,0 @@
-/*
- *
- * Vista Imaging ViCAM / 3Com HomeConnect Usermode Driver
- * Christopher L Cheney (C) 2001
- * 
- */
-
-#ifndef __LINUX_VICAM_H
-#define __LINUX_VICAM_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)
-
-#define VICAM_NUMFRAMES 30
-#define VICAM_NUMSBUF 1
-
-/* USB REQUEST NUMBERS */
-#define VICAM_REQ_VENDOR	0xff
-#define VICAM_REQ_CAMERA_POWER	0x50
-#define VICAM_REQ_CAPTURE	0x51
-#define VICAM_REQ_LED_CONTROL	0x55
-#define VICAM_REQ_GET_SOMETHIN	0x56
- 
-/* not required but lets you know camera is on */
-/* camera must be on to turn on led */
-/* 0x01 always on  0x03 on when picture taken (flashes) */
-
-struct picture_parm
-{
-	int width;
-	int height;
-	int brightness;
-	int hue;
-	int colour;
-	int contrast;
-	int whiteness;
-	int depth;
-	int palette;
-};
-
-struct vicam_scratch {
-        unsigned char *data;
-        volatile int state;
-        int offset;
-        int length;
-};
-
-/* Structure to hold all of our device specific stuff */
-struct usb_vicam
-{
-	struct video_device vdev;
-	struct usb_device *udev;
-
-	int open_count;	/* number of times this port has been opened */
-	struct semaphore sem;			/* locks this structure */
-	wait_queue_head_t wait;			/* Processes waiting */ 
-
-	int streaming;
-
-	/* v4l stuff */
-	char *camera_name;
-	char *fbuf;
-	struct urb *urb[VICAM_NUMSBUF];
-	int sizes;
-	int *width;
-	int *height;
-	int maxframesize;
-	struct picture_parm win;
-	struct proc_dir_entry *proc_entry;      /* /proc/se401/videoX */
-	struct urb readurb;
-};
-
-#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/usb/vicamurbs.h linux-2.4.21-pre6/drivers/usb/vicamurbs.h
--- linux-2.4.20/drivers/usb/vicamurbs.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/drivers/usb/vicamurbs.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,324 +0,0 @@
-/*
- *
- * Vista Imaging ViCAM / 3Com HomeConnect Usermode Driver
- * Christopher L Cheney (C) 2001
- * 
- */
-
-
-#ifndef __LINUX_VICAMURBS_H
-#define __LINUX_VICAMURBS_H
-
-/* -------------------------------------------------------------------------- */
-
-/* FIXME - Figure out transfers so that this doesn't need to be here
- *
- * Notice: in pieces below, "0" means other code will fill it while "0x00" means this is zero */
-
-/* Request 0x51 Image Setup */
-
-/* 128x122 3D80 size */
-static unsigned char s128x122bw[] = {
-  0,    0x34, 0xF4, 0x00, 0x00, 0x00, 0,    0,
-  0x00, 0x02, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00
-};
-
-/* 256x242 ? 0xF280 size */
-static unsigned char s256x242bw[] = {
-  0,    0x03, 0xC8, 0x03, 0x00, 0x00, 0,    0,
-  0x00, 0x04, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00
-};
-
-/* 512x242 0x1E480 size */
-static unsigned char s512x242bw[] = {
-  0,    0x05, 0x90, 0x07, 0x00, 0x00, 0,    0,
-  0x00, 0x08, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00
-};
-
-/* In s512x242:
-   byte 0: gain -- higher number means brighter image
-   byte 6, 7: shutter speed, little-endian; set this to 15600 * (shutter speed) - 1. (Where shutter speed is something like 1/1000).
-*/
-
-/* -------------------------------------------------------------------------- */
-
-static unsigned char fsetup[] = {
-  0xB6, 0xC3, 0x01, 0x00, 0x06, 0x64,
-
-  0x00, 0x00
-};
-
-static unsigned char firmware1[] = {
-  0xB6, 0xC3, 0x1F, 0x00, 0x02, 0x64,
-
-  0xE7, 0x67, 0xFD, 0xFF, 0x0E, 0xC0, 0xE7, 0x09,
-  0xDE, 0x00, 0x8E, 0x00, 0xC0, 0x09, 0x40, 0x03,
-  0xC0, 0x17, 0x44, 0x03, 0x4B, 0xAF, 0xC0, 0x07,
-  0x00, 0x00, 0x4B, 0xAF, 0x97, 0xCF, 0x00, 0x00
-};
-
-static unsigned char findex1[] = {
-  0xB6, 0xC3, 0x03, 0x00, 0x03, 0x64,
-
-  0x18, 0x00, 0x00, 0x00
-};
-
-static unsigned char firmware2[] = {
-  0xB6, 0xC3, 0x8F, 0x06, 0x02, 0x64,
-
-  0xE7, 0x07, 0x00, 0x00, 0x08, 0xC0, 0xE7, 0x07,
-  0x00, 0x00, 0x3E, 0xC0, 0xE7, 0x07, 0x54, 0x01,
-  0xAA, 0x00, 0xE7, 0x07, 0xC8, 0x05, 0xB6, 0x00,
-  0xE7, 0x07, 0x42, 0x01, 0xD2, 0x00, 0xE7, 0x07,
-  0x7C, 0x00, 0x16, 0x00, 0xE7, 0x07, 0x56, 0x00,
-  0x18, 0x00, 0xE7, 0x07, 0x06, 0x00, 0x92, 0xC0,
-  0xE7, 0x07, 0x00, 0x00, 0x1E, 0xC0, 0xE7, 0x07,
-  0xFF, 0xFF, 0x22, 0xC0, 0xE7, 0x07, 0x04, 0x00,
-  0x24, 0xC0, 0xE7, 0x07, 0xEC, 0x27, 0x28, 0xC0,
-  0xE7, 0x07, 0x16, 0x01, 0x8E, 0x00, 0xE7, 0x87,
-  0x01, 0x00, 0x0E, 0xC0, 0x97, 0xCF, 0xD7, 0x09,
-  0x00, 0xC0, 0xE7, 0x77, 0x01, 0x00, 0x92, 0xC0,
-  0x09, 0xC1, 0xE7, 0x09, 0xFE, 0x05, 0x24, 0x01,
-  0xE7, 0x09, 0x04, 0x06, 0x26, 0x01, 0xE7, 0x07,
-  0x07, 0x00, 0x92, 0xC0, 0xE7, 0x05, 0x00, 0xC0,
-  0xC0, 0xDF, 0x97, 0xCF, 0x17, 0x00, 0x57, 0x00,
-  0x17, 0x02, 0xD7, 0x09, 0x00, 0xC0, 0xE7, 0x77,
-  0x01, 0x00, 0x92, 0xC0, 0x0A, 0xC1, 0xE7, 0x57,
-  0xFF, 0xFF, 0xFA, 0x05, 0x0D, 0xC0, 0xE7, 0x57,
-  0x00, 0x00, 0xFA, 0x05, 0x0F, 0xC0, 0x9F, 0xAF,
-  0xC6, 0x00, 0xE7, 0x05, 0x00, 0xC0, 0xC8, 0x05,
-  0xC1, 0x05, 0xC0, 0x05, 0xC0, 0xDF, 0x97, 0xCF,
-  0x27, 0xDA, 0xFA, 0x05, 0xEF, 0x07, 0x01, 0x00,
-  0x0B, 0x06, 0x73, 0xCF, 0x9F, 0xAF, 0x78, 0x01,
-  0x9F, 0xAF, 0x1A, 0x03, 0x6E, 0xCF, 0xE7, 0x09,
-  0xFC, 0x05, 0x24, 0x01, 0xE7, 0x09, 0x02, 0x06,
-  0x26, 0x01, 0xE7, 0x07, 0x07, 0x00, 0x92, 0xC0,
-  0xE7, 0x09, 0xFC, 0x05, 0xFE, 0x05, 0xE7, 0x09,
-  0x02, 0x06, 0x04, 0x06, 0xE7, 0x09, 0x00, 0x06,
-  0xFC, 0x05, 0xE7, 0x09, 0xFE, 0x05, 0x00, 0x06,
-  0x27, 0xDA, 0xFA, 0x05, 0xE7, 0x57, 0x01, 0x00,
-  0xFA, 0x05, 0x02, 0xCA, 0x04, 0xC0, 0x97, 0xCF,
-  0x9F, 0xAF, 0x66, 0x05, 0x97, 0xCF, 0xE7, 0x07,
-  0x40, 0x00, 0x02, 0x06, 0xC8, 0x09, 0xFC, 0x05,
-  0x9F, 0xAF, 0xDA, 0x02, 0x97, 0xCF, 0xCF, 0x17,
-  0x02, 0x00, 0xEF, 0x57, 0x81, 0x00, 0x09, 0x06,
-  0x9F, 0xA0, 0xB6, 0x01, 0xEF, 0x57, 0x80, 0x00,
-  0x09, 0x06, 0x9F, 0xA0, 0x40, 0x02, 0xEF, 0x57,
-  0x01, 0x00, 0x0B, 0x06, 0x9F, 0xA0, 0x46, 0x03,
-  0xE7, 0x07, 0x01, 0x00, 0x0A, 0xC0, 0x46, 0xAF,
-  0x47, 0xAF, 0x9F, 0xAF, 0x40, 0x02, 0xE7, 0x07,
-  0x2E, 0x00, 0x0A, 0xC0, 0xEF, 0x87, 0x80, 0x00,
-  0x09, 0x06, 0x97, 0xCF, 0x00, 0x0E, 0x01, 0x00,
-  0xC0, 0x57, 0x51, 0x00, 0x9F, 0xC0, 0x9E, 0x02,
-  0xC0, 0x57, 0x50, 0x00, 0x20, 0xC0, 0xC0, 0x57,
-  0x55, 0x00, 0x12, 0xC0, 0xC0, 0x57, 0x56, 0x00,
-  0x9F, 0xC0, 0x72, 0x02, 0x9F, 0xCF, 0xD6, 0x02,
-  0xC1, 0x0B, 0x08, 0x06, 0x01, 0xD0, 0x6F, 0x90,
-  0x08, 0x06, 0xC0, 0x07, 0x08, 0x00, 0xC1, 0x0B,
-  0x08, 0x06, 0x9F, 0xAF, 0x28, 0x05, 0x97, 0xCF,
-  0x2F, 0x0E, 0x02, 0x00, 0x08, 0x06, 0xC0, 0x07,
-  0x08, 0x00, 0xC1, 0x0B, 0x08, 0x06, 0x9F, 0xAF,
-  0x28, 0x05, 0x9F, 0xCF, 0xD6, 0x02, 0x2F, 0x0E,
-  0x02, 0x00, 0x09, 0x06, 0xEF, 0x87, 0x80, 0x00,
-  0x09, 0x06, 0x9F, 0xCF, 0xD6, 0x02, 0xEF, 0x67,
-  0x7F, 0xFF, 0x09, 0x06, 0xE7, 0x67, 0xFF, 0xFD,
-  0x22, 0xC0, 0xE7, 0x67, 0xEF, 0xFF, 0x24, 0xC0,
-  0xE7, 0x87, 0x10, 0x00, 0x28, 0xC0, 0x9F, 0xAF,
-  0xB8, 0x05, 0xE7, 0x87, 0xE0, 0x21, 0x24, 0xC0,
-  0x9F, 0xAF, 0xA8, 0x05, 0xE7, 0x87, 0x08, 0x00,
-  0x24, 0xC0, 0xE7, 0x67, 0xDF, 0xFF, 0x24, 0xC0,
-  0xC8, 0x07, 0x0A, 0x00, 0xC0, 0x07, 0x00, 0x00,
-  0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05,
-  0x9F, 0xAF, 0xB8, 0x05, 0xC0, 0x07, 0x9E, 0x00,
-  0x9F, 0xAF, 0x44, 0x05, 0xE7, 0x67, 0xFF, 0xFE,
-  0x24, 0xC0, 0xC0, 0x09, 0x20, 0xC0, 0xE7, 0x87,
-  0x00, 0x01, 0x24, 0xC0, 0xC0, 0x77, 0x00, 0x02,
-  0x0F, 0xC1, 0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0,
-  0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x87,
-  0x08, 0x00, 0x24, 0xC0, 0x08, 0xDA, 0x5E, 0xC1,
-  0xEF, 0x07, 0x80, 0x00, 0x09, 0x06, 0x97, 0xCF,
-  0xEF, 0x07, 0x01, 0x00, 0x0A, 0x06, 0x97, 0xCF,
-  0xEF, 0x07, 0x00, 0x00, 0x0B, 0x06, 0xEF, 0x07,
-  0x00, 0x00, 0x0A, 0x06, 0xEF, 0x67, 0x7F, 0xFF,
-  0x09, 0x06, 0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06,
-  0xE7, 0x67, 0xEF, 0xFF, 0x28, 0xC0, 0xE7, 0x67,
-  0x17, 0xD8, 0x24, 0xC0, 0xE7, 0x07, 0x00, 0x00,
-  0x1E, 0xC0, 0xE7, 0x07, 0xFF, 0xFF, 0x22, 0xC0,
-  0x97, 0xCF, 0xC8, 0x07, 0x0E, 0x06, 0x9F, 0xAF,
-  0xDA, 0x02, 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05,
-  0xE7, 0x07, 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07,
-  0x0E, 0x06, 0xF4, 0x05, 0xE7, 0x07, 0xD6, 0x02,
-  0xF8, 0x05, 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07,
-  0x00, 0x80, 0x50, 0xAF, 0x97, 0xCF, 0x2F, 0x0C,
-  0x02, 0x00, 0x07, 0x06, 0x2F, 0x0C, 0x04, 0x00,
-  0x06, 0x06, 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05,
-  0xE7, 0x07, 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07,
-  0xE2, 0x05, 0xF4, 0x05, 0xE7, 0x07, 0xCE, 0x02,
-  0xF8, 0x05, 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07,
-  0x00, 0x80, 0x51, 0xAF, 0x97, 0xCF, 0x9F, 0xAF,
-  0x66, 0x04, 0x9F, 0xAF, 0x1A, 0x03, 0x59, 0xAF,
-  0x97, 0xCF, 0xC0, 0x07, 0x0E, 0x00, 0xC1, 0x0B,
-  0x0C, 0x06, 0x41, 0xD1, 0x9F, 0xAF, 0x28, 0x05,
-  0xC0, 0x07, 0x3C, 0x00, 0x9F, 0xAF, 0x44, 0x05,
-  0x68, 0x00, 0xC0, 0x07, 0x3B, 0x00, 0x9F, 0xAF,
-  0x44, 0x05, 0x6F, 0x00, 0x0C, 0x06, 0x68, 0x00,
-  0xE0, 0x07, 0x04, 0x01, 0xE8, 0x0B, 0x0A, 0x06,
-  0xE8, 0x07, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x02,
-  0xE0, 0x07, 0xEC, 0x01, 0xE0, 0x07, 0xFC, 0xFF,
-  0x97, 0xCF, 0xE7, 0x07, 0xFF, 0xFF, 0xFA, 0x05,
-  0xEF, 0x07, 0x00, 0x00, 0x0B, 0x06, 0xE7, 0x07,
-  0x0E, 0x06, 0x24, 0x01, 0xE7, 0x07, 0x0E, 0x06,
-  0xFE, 0x05, 0xE7, 0x07, 0x40, 0x00, 0x26, 0x01,
-  0xE7, 0x07, 0x40, 0x00, 0x04, 0x06, 0xE7, 0x07,
-  0x07, 0x00, 0x92, 0xC0, 0x97, 0xCF, 0xEF, 0x07,
-  0x02, 0x00, 0x0B, 0x06, 0x9F, 0xAF, 0x78, 0x01,
-  0xEF, 0x77, 0x80, 0x00, 0x07, 0x06, 0x9F, 0xC0,
-  0x14, 0x04, 0xEF, 0x77, 0x01, 0x00, 0x07, 0x06,
-  0x37, 0xC0, 0xEF, 0x77, 0x01, 0x00, 0x0D, 0x06,
-  0x0F, 0xC1, 0xEF, 0x07, 0x01, 0x00, 0x0D, 0x06,
-  0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00,
-  0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x01, 0x00,
-  0xC1, 0x07, 0x02, 0x00, 0x9F, 0xAF, 0x28, 0x05,
-  0xC8, 0x07, 0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05,
-  0xC0, 0x07, 0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05,
-  0xC1, 0x77, 0x03, 0x00, 0x02, 0xC1, 0x08, 0xDA,
-  0x75, 0xC1, 0xC1, 0x77, 0x01, 0x00, 0x0A, 0xC1,
-  0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07, 0x02, 0x00,
-  0x9F, 0xAF, 0x28, 0x05, 0xEF, 0x07, 0x01, 0x00,
-  0x06, 0x06, 0x2C, 0xCF, 0xC0, 0x07, 0x01, 0x00,
-  0xC1, 0x07, 0x04, 0x00, 0x9F, 0xAF, 0x28, 0x05,
-  0xEF, 0x07, 0x00, 0x00, 0x06, 0x06, 0x22, 0xCF,
-  0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06, 0xEF, 0x57,
-  0x01, 0x00, 0x06, 0x06, 0x1B, 0xC0, 0xC0, 0x07,
-  0x01, 0x00, 0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF,
-  0x28, 0x05, 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07,
-  0x30, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07,
-  0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07,
-  0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x67,
-  0x03, 0x00, 0xC1, 0x57, 0x03, 0x00, 0x02, 0xC0,
-  0x08, 0xDA, 0x73, 0xC1, 0xC0, 0x07, 0x02, 0x00,
-  0xC1, 0x07, 0x12, 0x00, 0xEF, 0x57, 0x00, 0x00,
-  0x06, 0x06, 0x02, 0xC0, 0xC1, 0x07, 0x23, 0x00,
-  0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x14, 0x00,
-  0xC1, 0x0B, 0xEA, 0x05, 0x9F, 0xAF, 0x28, 0x05,
-  0xC0, 0x07, 0x3E, 0x00, 0x9F, 0xAF, 0x0A, 0x05,
-  0xE7, 0x09, 0xE4, 0x05, 0xFA, 0x05, 0x27, 0xD8,
-  0xFA, 0x05, 0xE7, 0x07, 0x0E, 0x06, 0xFC, 0x05,
-  0xE7, 0x07, 0x4E, 0x06, 0x00, 0x06, 0xE7, 0x07,
-  0x40, 0x00, 0x02, 0x06, 0x9F, 0xAF, 0x66, 0x05,
-  0x9F, 0xAF, 0xC6, 0x00, 0x97, 0xCF, 0xC1, 0x0B,
-  0xE2, 0x05, 0x41, 0xD0, 0x01, 0xD2, 0xC1, 0x17,
-  0x23, 0x00, 0x9F, 0xAF, 0xDC, 0x04, 0xC0, 0x07,
-  0x04, 0x00, 0xC1, 0x0B, 0xE3, 0x05, 0x9F, 0xAF,
-  0x28, 0x05, 0xC0, 0x07, 0x06, 0x00, 0xC1, 0x09,
-  0xE6, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
-  0x07, 0x00, 0xC1, 0x09, 0xE6, 0x05, 0xC1, 0xD1,
-  0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0B, 0x00,
-  0xC1, 0x09, 0xE8, 0x05, 0x9F, 0xAF, 0x28, 0x05,
-  0xC0, 0x07, 0x0C, 0x00, 0xC1, 0x09, 0xE8, 0x05,
-  0xC1, 0xD1, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
-  0x0D, 0x00, 0xC1, 0x07, 0x09, 0x00, 0x9F, 0xAF,
-  0x28, 0x05, 0xC0, 0x07, 0x03, 0x00, 0xC1, 0x07,
-  0x32, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
-  0x0F, 0x00, 0xC1, 0x07, 0x00, 0x00, 0x9F, 0xAF,
-  0x28, 0x05, 0x97, 0xCF, 0xE7, 0x67, 0xFF, 0xD9,
-  0x24, 0xC0, 0xC8, 0x07, 0x0A, 0x00, 0x40, 0x00,
-  0xC0, 0x67, 0x00, 0x02, 0x27, 0x80, 0x24, 0xC0,
-  0xE7, 0x87, 0x00, 0x04, 0x24, 0xC0, 0xE7, 0x67,
-  0xFF, 0xF9, 0x24, 0xC0, 0x01, 0xD2, 0x08, 0xDA,
-  0x72, 0xC1, 0xE7, 0x87, 0x00, 0x20, 0x24, 0xC0,
-  0x97, 0xCF, 0x27, 0x00, 0x1E, 0xC0, 0xE7, 0x87,
-  0xFF, 0x00, 0x22, 0xC0, 0xE7, 0x67, 0x7F, 0xFF,
-  0x24, 0xC0, 0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0,
-  0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0, 0x97, 0xCF,
-  0x9F, 0xAF, 0x0A, 0x05, 0x67, 0x00, 0x1E, 0xC0,
-  0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x87,
-  0x40, 0x00, 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00,
-  0x24, 0xC0, 0x97, 0xCF, 0x9F, 0xAF, 0x0A, 0x05,
-  0xE7, 0x67, 0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67,
-  0xFF, 0xFE, 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xFE,
-  0x24, 0xC0, 0xC1, 0x09, 0x20, 0xC0, 0xE7, 0x87,
-  0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF, 0xC0, 0x07,
-  0x40, 0x00, 0xC8, 0x09, 0xFC, 0x05, 0xE7, 0x67,
-  0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE,
-  0x24, 0xC0, 0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0,
-  0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0x00, 0xDA,
-  0xE8, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x40, 0x00,
-  0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0,
-  0x00, 0xDA, 0xE8, 0x09, 0x20, 0xC0, 0x6D, 0xC1,
-  0xE7, 0x87, 0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF,
-  0xE7, 0x07, 0x32, 0x00, 0x12, 0xC0, 0xE7, 0x77,
-  0x00, 0x80, 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF,
-  0xE7, 0x07, 0x20, 0x4E, 0x12, 0xC0, 0xE7, 0x77,
-  0x00, 0x80, 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF,
-  0x09, 0x02, 0x19, 0x00, 0x01, 0x01, 0x00, 0x80,
-  0x96, 0x09, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00,
-  0x00, 0x00, 0x07, 0x05, 0x81, 0x02, 0x40, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  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 unsigned char findex2[] = {
-  0xB6, 0xC3, 0x2F, 0x01, 0x03, 0x64,
-
-  0x0E, 0x00, 0x14, 0x00, 0x1A, 0x00, 0x20, 0x00,
-  0x26, 0x00, 0x4A, 0x00, 0x64, 0x00, 0x6A, 0x00,
-  0x92, 0x00, 0x9A, 0x00, 0xA0, 0x00, 0xB2, 0x00,
-  0xB8, 0x00, 0xBE, 0x00, 0xC2, 0x00, 0xC8, 0x00,
-  0xCE, 0x00, 0xDC, 0x00, 0xDA, 0x00, 0xE2, 0x00,
-  0xE0, 0x00, 0xE8, 0x00, 0xE6, 0x00, 0xEE, 0x00,
-  0xEC, 0x00, 0xF2, 0x00, 0xF8, 0x00, 0x02, 0x01,
-  0x0A, 0x01, 0x0E, 0x01, 0x12, 0x01, 0x1E, 0x01,
-  0x22, 0x01, 0x28, 0x01, 0x2C, 0x01, 0x32, 0x01,
-  0x36, 0x01, 0x44, 0x01, 0x50, 0x01, 0x5E, 0x01,
-  0x72, 0x01, 0x76, 0x01, 0x7A, 0x01, 0x80, 0x01,
-  0x88, 0x01, 0x8C, 0x01, 0x94, 0x01, 0x9C, 0x01,
-  0xA0, 0x01, 0xA4, 0x01, 0xAA, 0x01, 0xB0, 0x01,
-  0xB4, 0x01, 0xBA, 0x01, 0xD0, 0x01, 0xDA, 0x01,
-  0xF6, 0x01, 0xFA, 0x01, 0x02, 0x02, 0x34, 0x02,
-  0x3C, 0x02, 0x44, 0x02, 0x4A, 0x02, 0x50, 0x02,
-  0x56, 0x02, 0x74, 0x02, 0x78, 0x02, 0x7E, 0x02,
-  0x84, 0x02, 0x8A, 0x02, 0x88, 0x02, 0x90, 0x02,
-  0x8E, 0x02, 0x94, 0x02, 0xA2, 0x02, 0xA8, 0x02,
-  0xAE, 0x02, 0xB4, 0x02, 0xBA, 0x02, 0xB8, 0x02,
-  0xC0, 0x02, 0xBE, 0x02, 0xC4, 0x02, 0xD0, 0x02,
-  0xD4, 0x02, 0xE0, 0x02, 0xE6, 0x02, 0xEE, 0x02,
-  0xF8, 0x02, 0xFC, 0x02, 0x06, 0x03, 0x1E, 0x03,
-  0x24, 0x03, 0x28, 0x03, 0x30, 0x03, 0x2E, 0x03,
-  0x3C, 0x03, 0x4A, 0x03, 0x4E, 0x03, 0x54, 0x03,
-  0x58, 0x03, 0x5E, 0x03, 0x66, 0x03, 0x6E, 0x03,
-  0x7A, 0x03, 0x86, 0x03, 0x8E, 0x03, 0x96, 0x03,
-  0xB2, 0x03, 0xB8, 0x03, 0xC6, 0x03, 0xCC, 0x03,
-  0xD4, 0x03, 0xDA, 0x03, 0xE8, 0x03, 0xF4, 0x03,
-  0xFC, 0x03, 0x04, 0x04, 0x20, 0x04, 0x2A, 0x04,
-  0x32, 0x04, 0x36, 0x04, 0x3E, 0x04, 0x44, 0x04,
-  0x42, 0x04, 0x48, 0x04, 0x4E, 0x04, 0x4C, 0x04,
-  0x54, 0x04, 0x52, 0x04, 0x5A, 0x04, 0x5E, 0x04,
-  0x62, 0x04, 0x68, 0x04, 0x74, 0x04, 0x7C, 0x04,
-  0x80, 0x04, 0x88, 0x04, 0x8C, 0x04, 0x94, 0x04,
-  0x9A, 0x04, 0xA2, 0x04, 0xA6, 0x04, 0xAE, 0x04,
-  0xB4, 0x04, 0xC0, 0x04, 0xCC, 0x04, 0xD8, 0x04,
-  0x2A, 0x05, 0x46, 0x05, 0x6C, 0x05, 0x00, 0x00
-};
-
-#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/Config.in linux-2.4.21-pre6/drivers/video/Config.in
--- linux-2.4.20/drivers/video/Config.in	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/Config.in	2003-03-26 23:49:39.000000000 +0000
@@ -80,7 +80,7 @@
       bool '  Generic STI frame buffer device support' CONFIG_FB_STI
    fi
    if [ "$CONFIG_MAC" = "y" ]; then
-      define_bool CONFIG_FB_MAC y
+      bool '  Generic Macintosh display support' CONFIG_FB_MAC
       bool '  Apple "valkyrie" display support' CONFIG_FB_VALKYRIE
 #      bool '  Apple DAFB display support' CONFIG_FB_DAFB
    fi
@@ -124,14 +124,20 @@
 	 if [ "$CONFIG_FB_MATROX" != "n" ]; then
 	    bool '    Millennium I/II support' CONFIG_FB_MATROX_MILLENIUM
 	    bool '    Mystique support' CONFIG_FB_MATROX_MYSTIQUE
-	    bool '    G100/G200/G400/G450/G550 support' CONFIG_FB_MATROX_G100
+ 	    bool '    G100/G200/G400/G450/G550 support' CONFIG_FB_MATROX_G450
+ 	    if [ "$CONFIG_FB_MATROX_G450" = "n" ]; then
+ 	       bool '    G100/G200/G400 support' CONFIG_FB_MATROX_G100A
+ 	    fi
+ 	    if [ "$CONFIG_FB_MATROX_G450" = "y" -o "$CONFIG_FB_MATROX_G100A" = "y" ]; then
+ 	       define_bool CONFIG_FB_MATROX_G100 y
+ 	    fi
             if [ "$CONFIG_I2C" != "n" ]; then
 	       dep_tristate '      Matrox I2C support' CONFIG_FB_MATROX_I2C $CONFIG_FB_MATROX $CONFIG_I2C_ALGOBIT
 	       if [ "$CONFIG_FB_MATROX_G100" = "y" ]; then
 	          dep_tristate '      G400 second head support' CONFIG_FB_MATROX_MAVEN $CONFIG_FB_MATROX_I2C
 	       fi
             fi
-            dep_tristate '      G450/G550 second head support (mandatory for G550)' CONFIG_FB_MATROX_G450 $CONFIG_FB_MATROX_G100
+            dep_tristate '    Matrox /proc interface' CONFIG_FB_MATROX_PROC $CONFIG_FB_MATROX
 	    bool '    Multihead support' CONFIG_FB_MATROX_MULTIHEAD
 	 fi
 	 tristate '  ATI Mach64 display support (EXPERIMENTAL)' CONFIG_FB_ATY
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/Makefile linux-2.4.21-pre6/drivers/video/Makefile
--- linux-2.4.20/drivers/video/Makefile	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/Makefile	2003-03-26 23:49:07.000000000 +0000
@@ -102,6 +102,11 @@
 obj-y				  += matrox/matrox.o
 endif
 
+subdir-$(CONFIG_FB_INTEL)	  += intel
+ifeq ($(CONFIG_FB_INTEL),y)
+obj-y				  += intel/intelfb.o
+endif
+
 subdir-$(CONFIG_FB_RIVA)	  += riva
 ifeq ($(CONFIG_FB_RIVA),y)
 obj-y				  += riva/rivafb.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/S3triofb.c linux-2.4.21-pre6/drivers/video/S3triofb.c
--- linux-2.4.20/drivers/video/S3triofb.c	2001-09-13 23:04:43.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/S3triofb.c	2003-03-26 23:49:34.000000000 +0000
@@ -17,8 +17,7 @@
  */
 
 /*
-	Bugs : + OF dependencies should be removed.
-               + This driver should be merged with the CyberVision driver. The
+	Bugs : + This driver should be merged with the CyberVision driver. The
                  CyberVision is a Zorro III implementation of the S3Trio64 chip.
 
 */
@@ -37,9 +36,6 @@
 #include <linux/fb.h>
 #include <linux/init.h>
 #include <linux/selection.h>
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/pci-bridge.h>
 #include <linux/pci.h>
 #ifdef CONFIG_FB_COMPAT_XPMAC
 #include <asm/vc_ioctl.h>
@@ -60,7 +56,9 @@
 
 #define IO_OUT16VAL(v, r)       (((v) << 8) | (r))
 
+
 static int currcon = 0;
+static int disabled;
 static struct display disp;
 static struct fb_info fb_info;
 static struct { u_char red, green, blue, pad; } palette[256];
@@ -68,14 +66,20 @@
 static char *s3trio_base;
 
 static struct fb_fix_screeninfo fb_fix;
-static struct fb_var_screeninfo fb_var = { 0, };
-
+static struct fb_var_screeninfo S3triofb_default_var = {
+	640, 480, 640, 480, 0, 0, 8, 0,
+	{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+	0, 0, -1, FB_ACCELF_TEXT, 39722, 40, 24, 32, 11, 96, 2,
+	FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
+	FB_VMODE_NONINTERLACED
+};
+static struct fb_var_screeninfo fb_var = { 0,};
 
     /*
      *  Interface used by the world
      */
 
-static void __init s3triofb_of_init(struct device_node *dp);
+static void __init s3triofb_pci_init(struct pci_dev *dp);
 static int s3trio_get_fix(struct fb_fix_screeninfo *fix, int con,
 			  struct fb_info *info);
 static int s3trio_get_var(struct fb_var_screeninfo *var, int con,
@@ -259,15 +263,42 @@
     return 0;
 }
 
+int __init s3triofb_setup(char *options) {
+	char *this_opt;
+
+	if (!options || !*options)
+		return 0;
+
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		if (!*this_opt)
+			continue;
+
+		if (!strcmp(this_opt, "disabled"))
+			disabled = 1;
+	}
+	return 0;
+}
 
 int __init s3triofb_init(void)
 {
-	struct device_node *dp;
+	struct pci_dev *dp = NULL;
 
-	dp = find_devices("S3Trio");
-	if (dp != 0)
-	    s3triofb_of_init(dp);
-	return 0;
+	if (disabled)
+		return -ENXIO;
+
+	dp = pci_find_device(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_TRIO, dp);
+	if ((dp != 0) && ((dp->class >> 16) == PCI_BASE_CLASS_DISPLAY)) {
+		s3triofb_pci_init(dp);
+		return 0;
+	} else
+		return -ENODEV;
+}
+
+static void __exit s3triofb_exit(void)
+{
+    unregister_framebuffer(&fb_info);
+    iounmap(s3trio_base);
+    /* XXX unshare VGA regions */
 }
 
 void __init s3trio_resetaccel(void){
@@ -313,111 +344,69 @@
 	outw( MF_PIX_CONTROL | MFA_SRC_FOREGR_MIX,  0xbee8);
 }
 
-int __init s3trio_init(struct device_node *dp){
-
-    u_char bus, dev;
-    unsigned int t32;
-    unsigned short cmd;
-
-	pci_device_loc(dp,&bus,&dev);
-                pcibios_read_config_dword(bus, dev, PCI_VENDOR_ID, &t32);
-                if(t32 == (PCI_DEVICE_ID_S3_TRIO << 16) + PCI_VENDOR_ID_S3) {
-                        pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_0, &t32);
-                        pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_1, &t32);
-			pcibios_read_config_word(bus, dev, PCI_COMMAND,&cmd);
-
-			pcibios_write_config_word(bus, dev, PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
-
-			pcibios_write_config_dword(bus, dev, PCI_BASE_ADDRESS_0,0xffffffff);
-                        pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_0, &t32);
-
-/* This is a gross hack as OF only maps enough memory for the framebuffer and
-   we want to use MMIO too. We should find out which chunk of address space
-   we can use here */
-			pcibios_write_config_dword(bus,dev,PCI_BASE_ADDRESS_0,0xc6000000);
-
-			/* unlock s3 */
-
-			outb(0x01, 0x3C3);
-
-			outb(inb(0x03CC) | 1, 0x3c2);
-
-			outw(IO_OUT16VAL(0x48, 0x38),0x03D4);
-			outw(IO_OUT16VAL(0xA0, 0x39),0x03D4);
-			outb(0x33,0x3d4);
-			outw(IO_OUT16VAL((inb(0x3d5) & ~(0x2 | 0x10 |  0x40)) |
-					  0x20, 0x33), 0x3d4);
-
-			outw(IO_OUT16VAL(0x6, 0x8), 0x3c4);
-
-			/* switch to MMIO only mode */
-
-			outb(0x58, 0x3d4);
-			outw(IO_OUT16VAL(inb(0x3d5) | 3 | 0x10, 0x58), 0x3d4);
-			outw(IO_OUT16VAL(8, 0x53), 0x3d4);
-
-			/* switch off I/O accesses */
-
-#if 0
-			pcibios_write_config_word(bus, dev, PCI_COMMAND,
-				        PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
-#endif
-			return 1;
-                }
+int __init s3trio_init(struct pci_dev *dp)
+{
+	/* unlock s3 */
+	outb(0x01, 0x3C3);
+	outb(inb(0x03CC) | 1, 0x3c2);
+	outw(IO_OUT16VAL(0x48, 0x38),0x03D4);
+	outw(IO_OUT16VAL(0xA0, 0x39),0x03D4);
+	outb(0x33,0x3d4);
+	outw(IO_OUT16VAL((inb(0x3d5) & ~(0x2 | 0x10 |  0x40)) |
+			  0x20, 0x33), 0x3d4);
+
+	outw(IO_OUT16VAL(0x6, 0x8), 0x3c4);
+	printk("S3trio: unlocked s3\n");
+
+	/* switch to MMIO only mode */
+	outb(0x58, 0x3d4);
+	outw(IO_OUT16VAL(inb(0x3d5) | 3 | 0x10, 0x58), 0x3d4);
+	outw(IO_OUT16VAL(8, 0x53), 0x3d4);
+	printk("S3trio: switched to mmio only mode\n");
 
-	return 0;
+	return 1;
 }
 
 
     /*
      *  Initialisation
-     *  We heavily rely on OF for the moment. This needs fixing.
      */
 
-static void __init s3triofb_of_init(struct device_node *dp)
+static void __init s3triofb_pci_init(struct pci_dev *dp)
 {
-    int i, *pp, len;
+    int i;
     unsigned long address, size;
     u_long *CursorBase;
+    u16 cmd;
 
-    strncat(s3trio_name, dp->name, sizeof(s3trio_name));
-    s3trio_name[sizeof(s3trio_name)-1] = '\0';
     strcpy(fb_fix.id, s3trio_name);
 
-    if((pp = (int *)get_property(dp, "vendor-id", &len)) != NULL
-	&& *pp!=PCI_VENDOR_ID_S3) {
-	printk("%s: can't find S3 Trio board\n", dp->full_name);
-	return;
-    }
+    fb_var = S3triofb_default_var;
+    fb_fix.line_length = fb_var.xres_virtual;
+    fb_fix.smem_len = fb_fix.line_length*fb_var.yres;
 
-    if((pp = (int *)get_property(dp, "device-id", &len)) != NULL
-	&& *pp!=PCI_DEVICE_ID_S3_TRIO) {
-	printk("%s: can't find S3 Trio board\n", dp->full_name);
-	return;
+    /* This driver cannot cope if the firmware has not initialised the
+     * device.  So, if the device isn't enabled we simply return
+     */
+    pci_read_config_word(dp, PCI_COMMAND, &cmd);
+    if (!(cmd & PCI_COMMAND_MEMORY)) {
+	    printk(KERN_NOTICE "S3trio: card was not initialised by firmware\n");
+	    return;
     }
 
-    if ((pp = (int *)get_property(dp, "depth", &len)) != NULL
-	&& len == sizeof(int) && *pp != 8) {
-	printk("%s: can't use depth = %d\n", dp->full_name, *pp);
-	return;
+    /* Enable it anyway */
+    if (pci_enable_device(dp)) {
+	    printk(KERN_ERR "S3trio: failed to enable PCI device\n");
+	    return;
     }
-    if ((pp = (int *)get_property(dp, "width", &len)) != NULL
-	&& len == sizeof(int))
-	fb_var.xres = fb_var.xres_virtual = *pp;
-    if ((pp = (int *)get_property(dp, "height", &len)) != NULL
-	&& len == sizeof(int))
-	fb_var.yres = fb_var.yres_virtual = *pp;
-    if ((pp = (int *)get_property(dp, "linebytes", &len)) != NULL
-	&& len == sizeof(int))
-	fb_fix.line_length = *pp;
-    else
-	fb_fix.line_length = fb_var.xres_virtual;
-    fb_fix.smem_len = fb_fix.line_length*fb_var.yres;
 
-    address = 0xc6000000;
-    size = 64*1024*1024;
-    if (!request_mem_region(address, size, "S3triofb"))
+    /* There is only one memory region and it covers the mmio and fb areas */
+    address = pci_resource_start(dp, 0);
+    size    = pci_resource_len(dp, 0); /* size = 64*1024*1024; */
+    if (!request_mem_region(address, size, "S3triofb")) {
+	printk("S3trio: failed to allocate memory region\n");
 	return;
+    }
 
     s3trio_init(dp);
     s3trio_base = ioremap(address, size);
@@ -552,8 +541,7 @@
 #endif
     disp.scrollmode = fb_var.accel_flags & FB_ACCELF_TEXT ? 0 : SCROLL_YREDRAW;
 
-    strcpy(fb_info.modename, "Trio64 ");
-    strncat(fb_info.modename, dp->full_name, sizeof(fb_info.modename));
+    strcpy(fb_info.modename, "Trio64");
     fb_info.node = -1;
     fb_info.fbops = &s3trio_ops;
 #if 0
@@ -591,7 +579,7 @@
 	return;
 
     printk("fb%d: S3 Trio frame buffer device on %s\n",
-	   GET_FB_IDX(fb_info.node), dp->full_name);
+	   GET_FB_IDX(fb_info.node), dp->name);
 }
 
 
@@ -859,4 +847,8 @@
 };
 #endif
 
+#ifdef MODULE
+module_init(s3triofb_init);
 MODULE_LICENSE("GPL");
+#endif
+module_exit(s3triofb_exit);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/amifb.c linux-2.4.21-pre6/drivers/video/amifb.c
--- linux-2.4.20/drivers/video/amifb.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/amifb.c	2003-03-26 23:49:25.000000000 +0000
@@ -1785,7 +1785,7 @@
 
 	ami_init_copper();
 
-	if (request_irq(IRQ_AMIGA_VERTB, amifb_interrupt, 0,
+	if (request_irq(IRQ_AMIGA_COPPER, amifb_interrupt, 0,
 	                "fb vertb handler", &currentpar)) {
 		err = -EBUSY;
 		goto amifb_error;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/atafb.c linux-2.4.21-pre6/drivers/video/atafb.c
--- linux-2.4.20/drivers/video/atafb.c	2001-10-25 07:02:26.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/atafb.c	2003-03-26 23:49:07.000000000 +0000
@@ -1193,7 +1193,7 @@
 	par->HBB = gend2 - par->HHT - 2;
 #if 0
 	/* One more Videl constraint: data fetch of two lines must not overlap */
-	if (par->HDB & 0x200  &&  par->HDB & ~0x200 - par->HDE <= 5) {
+	if ((par->HDB & 0x200)  &&  (par->HDB & ~0x200) - par->HDE <= 5) {
 		/* if this happens increase margins, decrease hfreq. */
 	}
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/aty128fb.c linux-2.4.21-pre6/drivers/video/aty128fb.c
--- linux-2.4.20/drivers/video/aty128fb.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/aty128fb.c	2003-03-26 23:49:38.000000000 +0000
@@ -2531,7 +2531,7 @@
 	reg |= LVDS_BL_MOD_EN | LVDS_BLON;
 	if (on && level > BACKLIGHT_OFF) {
 		reg |= LVDS_DIGION;
-		if (!reg & LVDS_ON) {
+		if ((reg & LVDS_ON) == 0) {
 			reg &= ~LVDS_BLON;
 			aty_st_le32(LVDS_GEN_CNTL, reg);
 			(void)aty_ld_le32(LVDS_GEN_CNTL);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/clgenfb.c linux-2.4.21-pre6/drivers/video/clgenfb.c
--- linux-2.4.20/drivers/video/clgenfb.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/clgenfb.c	2003-03-26 23:49:25.000000000 +0000
@@ -1,7 +1,7 @@
 /*
  * drivers/video/clgenfb.c - driver for Cirrus Logic chipsets
  *
- * Copyright 1999-2001 Jeff Garzik <jgarzik@mandrakesoft.com>
+ * Copyright 1999-2001 Jeff Garzik <jgarzik@pobox.com>
  *
  * Contributors (thanks, all!)
  *
@@ -15,6 +15,9 @@
  *	Lars Hecking:
  *	Amiga updates and testing.
  *
+ *	Cliff Matthews <ctm@ardi.com>:
+ *	16bpp fix for CL-GD7548 (uses info from XFree86 4.2.0 source)
+ *
  * Original clgenfb author:  Frank Neumann
  *
  * Based on retz3fb.c and clgen.c:
@@ -403,6 +406,9 @@
 
 #ifdef CONFIG_PCI
 	struct pci_dev *pdev;
+#define IS_7548(x) ((x)->pdev->device == PCI_DEVICE_ID_CIRRUS_7548)
+#else
+#define IS_7548(x) (FALSE)
 #endif
 };
 
@@ -970,7 +976,10 @@
 
 	DPRINTK ("desired pixclock: %ld kHz\n", freq);
 
-	maxclock = clgen_board_info[fb_info->btype].maxclock;
+	if (IS_7548(fb_info))
+		maxclock = 80100;
+	else
+		maxclock = clgen_board_info[fb_info->btype].maxclock;
 	_par->multiplexing = 0;
 
 	/* If the frequency is greater than we can support, we might be able
@@ -1478,10 +1487,17 @@
 
 		case BT_ALPINE:
 			DPRINTK (" (for GD543x)\n");
-			if (_par->HorizRes >= 1024)
-				vga_wseq (fb_info->regs, CL_SEQR7, 0xa7);
-			else
-				vga_wseq (fb_info->regs, CL_SEQR7, 0xa3);
+			if (IS_7548(fb_info)) {
+				vga_wseq (fb_info->regs, CL_SEQR7, 
+					  (vga_rseq (fb_info->regs, CL_SEQR7) & 0xE0)
+					  | 0x17);
+				WHDR (fb_info, 0xC1);
+			} else {
+				if (_par->HorizRes >= 1024)
+					vga_wseq (fb_info->regs, CL_SEQR7, 0xa7);
+				else
+					vga_wseq (fb_info->regs, CL_SEQR7, 0xa3);
+			}	
 			clgen_set_mclk (fb_info, _par->mclk, _par->divMCLK);
 			break;
 
@@ -1594,6 +1610,11 @@
 			_par->var.bits_per_pixel);
 	}
 
+	if (IS_7548(fb_info)) {
+		vga_wseq (fb_info->regs, CL_SEQR2D, 
+			vga_rseq (fb_info->regs, CL_SEQR2D) | 0xC0);
+	}
+
 	vga_wcrt (fb_info->regs, VGA_CRTC_OFFSET, offset & 0xff);
 	tmp = 0x22;
 	if (offset & 0x100)
@@ -2884,7 +2905,7 @@
      *  Modularization
      */
 
-MODULE_AUTHOR("Copyright 1999,2000 Jeff Garzik <jgarzik@mandrakesoft.com>");
+MODULE_AUTHOR("Copyright 1999,2000 Jeff Garzik <jgarzik@pobox.com>");
 MODULE_DESCRIPTION("Accelerated FBDev driver for Cirrus Logic chips");
 MODULE_LICENSE("GPL");
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/clgenfb.h linux-2.4.21-pre6/drivers/video/clgenfb.h
--- linux-2.4.20/drivers/video/clgenfb.h	2000-01-06 18:23:46.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/clgenfb.h	2003-03-26 23:49:50.000000000 +0000
@@ -1,7 +1,7 @@
 /*
  * drivers/video/clgenfb.h - Cirrus Logic chipset constants
  *
- * Copyright 1999 Jeff Garzik <jgarzik@mandrakesoft.com>
+ * Copyright 1999 Jeff Garzik <jgarzik@pobox.com>
  *
  * Original clgenfb author:  Frank Neumann
  *
@@ -60,6 +60,7 @@
 #define CL_SEQR1D	0x1d	/* VCLK2 Denominator and Post-Scalar Value */
 #define CL_SEQR1E	0x1e	/* VCLK3 Denominator and Post-Scalar Value */
 #define CL_SEQR1F	0x1f	/* BIOS ROM write enable and MCLK Select */
+#define CL_SEQR2D	0x2d	/* unknown, snagged from XFree86 4.2.0 */
 
 /*** CRT Controller Registers ***/
 #define CL_CRT22	0x22	/* Graphics Data Latches ReadBack */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/dnfb.c linux-2.4.21-pre6/drivers/video/dnfb.c
--- linux-2.4.20/drivers/video/dnfb.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/dnfb.c	2003-03-26 23:49:20.000000000 +0000
@@ -107,12 +107,6 @@
 
 #define SWAP(A) ((A>>8) | ((A&0xff) <<8))
 
-#if 0
-#define outb(a,d) *(char *)(a)=(d)
-#define outw(a,d) *(unsigned short *)a=d
-#endif
-
-
 /* frame buffer operations */
 
 static int dn_fb_get_fix(struct fb_fix_screeninfo *fix, int con, 
@@ -322,12 +316,12 @@
  
 	/* now we have registered we can safely setup the hardware */
 
-        outb(RESET_CREG,  AP_CONTROL_3A);
-        outw(0x0,  AP_WRITE_ENABLE);
-        outb(NORMAL_MODE, AP_CONTROL_0); 
-        outb((AD_BLT | DST_EQ_SRC | NORM_CREG1),  AP_CONTROL_1);
-        outb(S_DATA_PLN,  AP_CONTROL_2);
-        outw(SWAP(0x3), AP_ROP_1);
+        out_8(AP_CONTROL_3A, RESET_CREG);
+        out_be16(AP_WRITE_ENABLE, 0x0);
+        out_8(AP_CONTROL_0, NORMAL_MODE); 
+        out_8(AP_CONTROL_1, (AD_BLT | DST_EQ_SRC | NORM_CREG1));
+        out_8(AP_CONTROL_2, S_DATA_PLN);
+        out_be16(AP_ROP_1, SWAP(0x3));
 
         printk("apollo frame buffer alive and kicking !\n");
 
@@ -354,10 +348,10 @@
 static void dnfbcon_blank(int blank,  struct fb_info *info) {
 
 	if(blank)  {
-        	outb(0x0,  AP_CONTROL_3A);
+		out_8(AP_CONTROL_3A, 0x0);
 	}
 	else {
-	        outb(0x1,  AP_CONTROL_3A);
+	        out_8(AP_CONTROL_3A, 0x1);
 	}
 
 	return ;
@@ -383,7 +377,8 @@
 		x_word_count=(x_end>>4) - (x_dest >> 4) + 1;
 		start_mask=0xffff0000 >> (x_dest & 0xf);
 		end_mask=0x7ffff >> (x_end & 0xf);
-		outb((((x_dest & 0xf) - (x_src &0xf))  % 16)|(0x4 << 5),AP_CONTROL_0);
+		out_8(AP_CONTROL_0,
+		      (((x_dest & 0xf) - (x_src &0xf))  % 16)|(0x4 << 5));
 		if((x_dest & 0xf) < (x_src & 0xf))
 			pre_read=1;
 	}
@@ -393,26 +388,27 @@
 		x_word_count=(x_dest>>4) - (x_end >> 4) + 1;
 		start_mask=0x7ffff >> (x_dest & 0xf);
 		end_mask=0xffff0000 >> (x_end & 0xf);
-		outb(((-((x_src & 0xf) - (x_dest &0xf))) % 16)|(0x4 << 5),AP_CONTROL_0);
+		out_8(AP_CONTROL_0,
+		      ((-((x_src & 0xf) - (x_dest &0xf))) % 16)|(0x4 << 5));
 		if((x_dest & 0xf) > (x_src & 0xf))
 			pre_read=1;
 	}
 
 	for(i=0;i<y_count;i++) {
 
-		outb(0xc | (dest >> 16), AP_CONTROL_3A);
-			
+		out_8(AP_CONTROL_3A, 0xc | (dest >> 16));
+
 		if(pre_read) {
 			dummy=*src;
 			src+=incr;
 		}
 
 		if(x_word_count) {
-			outb(start_mask,AP_WRITE_ENABLE);
+			out_8(AP_WRITE_ENABLE, start_mask);
 			*src=dest;
 			src+=incr;
 			dest+=incr;
-			outb(0,AP_WRITE_ENABLE);
+			out_8(AP_WRITE_ENABLE, 0);
 
 			for(j=1;j<(x_word_count-1);j++) {
 				*src=dest;
@@ -420,13 +416,13 @@
 				dest+=incr;
 			}
 
-			outb(start_mask,AP_WRITE_ENABLE);
+			out_8(AP_WRITE_ENABLE, start_mask);
 			*src=dest;
 			dest+=incr;
 			src+=incr;
 		}
 		else {
-			outb(start_mask | end_mask, AP_WRITE_ENABLE);
+			out_8(AP_WRITE_ENABLE, start_mask | end_mask);
 			*src=dest;
 			dest+=incr;
 			src+=incr;
@@ -434,7 +430,7 @@
 		src+=(y_delta/16);
 		dest+=(y_delta/16);
 	}
-	outb(NORMAL_MODE,AP_CONTROL_0);
+	out_8(AP_CONTROL_0, NORMAL_MODE);
 }
 
 static void bmove_apollofb(struct display *p, int sy, int sx, int dy, int dx,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/fbmem.c linux-2.4.21-pre6/drivers/video/fbmem.c
--- linux-2.4.20/drivers/video/fbmem.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/fbmem.c	2003-03-26 23:48:57.000000000 +0000
@@ -647,6 +647,8 @@
 	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 #elif defined(__sh__)
 	pgprot_val(vma->vm_page_prot) &= ~_PAGE_CACHABLE;
+#elif defined(__hppa__)
+	pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; 
 #elif defined(__ia64__)
 	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
 #elif defined(__hppa__)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/intel/Makefile linux-2.4.21-pre6/drivers/video/intel/Makefile
--- linux-2.4.20/drivers/video/intel/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/intel/Makefile	2003-03-26 23:49:06.000000000 +0000
@@ -0,0 +1,18 @@
+# $DHD: linux/drivers/video/intel/Makefile,v 1.1.2.2 2003/02/05 00:07:45 dawes Exp $
+# $TG$
+
+O_TARGET := intelfb.o
+
+obj-$(CONFIG_FB_INTEL)	+= intelfbdrv.o intelfbhw.o
+
+include $(TOPDIR)/Rules.make
+
+intelfbdrv.o: builtinmodes.c
+
+builtinmodes.c: modes.c
+	rm -f builtinmodes.c
+	ln -s modes.c builtinmodes.c
+
+clean:
+	rm -f core *.o *.a *.s builtinmodes.c
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/intel/builtinmodes.c linux-2.4.21-pre6/drivers/video/intel/builtinmodes.c
--- linux-2.4.20/drivers/video/intel/builtinmodes.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/intel/builtinmodes.c	2003-03-26 23:49:20.000000000 +0000
@@ -0,0 +1,222 @@
+
+/*
+ * THIS FILE IS AUTOMATICALLY GENERATED BY fbmode.pl -- DO NOT EDIT
+ */
+
+static struct fb_videomode modedb[] = {
+    {
+	/* 640x350 @ 85 Hz, 37.9 kHz hsync */
+	"640x350@85", 85, 640, 350, 31746, 96, 32, 60, 32, 64, 3,
+	FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 640x400 @ 85 Hz, 37.9 kHz hsync */
+	"640x400@85", 85, 640, 400, 31746, 96, 32, 41, 1, 64, 3,
+	FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 720x400 @ 85 Hz, 37.9 kHz hsync */
+	"720x400@85", 85, 720, 400, 28169, 108, 36, 42, 1, 72, 3,
+	FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 640x480 @ 60 Hz, 31.5 kHz hsync */
+	"640x480@60", 60, 640, 480, 39683, 48, 16, 33, 10, 96, 2,
+	0, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 640x480 @ 73 Hz, 37.9 kHz hsync */
+	"640x480@73", 73, 640, 480, 31746, 128, 24, 29, 9, 40, 2,
+	0, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 640x480 @ 75 Hz, 37.5 kHz hsync */
+	"640x480@75", 75, 640, 480, 31746, 120, 16, 16, 1, 64, 3,
+	0, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 640x480 @ 85 Hz, 43.3 kHz hsync */
+	"640x480@85", 85, 640, 480, 27778, 80, 56, 25, 1, 56, 3,
+	0, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 800x600 @ 56 Hz, 35.2 kHz hsync */
+	"800x600@56", 56, 800, 600, 27778, 128, 24, 22, 1, 72, 2,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 800x600 @ 60 Hz, 37.9 kHz hsync */
+	"800x600@60", 60, 800, 600, 25000, 88, 40, 23, 1, 128, 4,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 800x600 @ 72 Hz, 48.1 kHz hsync */
+	"800x600@72", 72, 800, 600, 20000, 64, 56, 23, 37, 120, 6,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 800x600 @ 75 Hz, 46.9 kHz hsync */
+	"800x600@75", 75, 800, 600, 20202, 160, 16, 21, 1, 80, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 800x600 @ 85 Hz, 53.7 kHz hsync */
+	"800x600@85", 85, 800, 600, 17762, 152, 32, 27, 1, 64, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1024x768 @ 60 Hz, 48.4 kHz hsync */
+	"1024x768@60", 60, 1024, 768, 15385, 160, 24, 29, 3, 136, 6,
+	0, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1024x768 @ 70 Hz, 56.5 kHz hsync */
+	"1024x768@70", 70, 1024, 768, 13333, 144, 24, 29, 3, 136, 6,
+	0, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1024x768 @ 75 Hz, 60.1 kHz hsync */
+	"1024x768@75", 75, 1024, 768, 12690, 176, 16, 28, 1, 96, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1024x768 @ 85 Hz, 68.7 kHz hsync */
+	"1024x768@85", 85, 1024, 768, 10582, 208, 48, 36, 1, 96, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1152x864 @ 75 Hz, 67.5 kHz hsync */
+	"1152x864@75", 75, 1152, 864, 9259, 256, 64, 32, 1, 128, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1280x960 @ 60 Hz, 60.0 kHz hsync */
+	"1280x960@60", 60, 1280, 960, 9259, 312, 96, 36, 1, 112, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1280x960 @ 85 Hz, 85.9 kHz hsync */
+	"1280x960@85", 85, 1280, 960, 6734, 224, 64, 47, 1, 160, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1280x1024 @ 60 Hz, 64.0 kHz hsync */
+	"1280x1024@60", 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1280x1024 @ 75 Hz, 80.0 kHz hsync */
+	"1280x1024@75", 75, 1280, 1024, 7407, 248, 16, 38, 1, 144, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1280x1024 @ 85 Hz, 91.1 kHz hsync */
+	"1280x1024@85", 85, 1280, 1024, 6349, 224, 64, 44, 1, 160, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1600x1200 @ 60 Hz, 75.0 kHz hsync */
+	"1600x1200@60", 60, 1600, 1200, 6173, 304, 64, 46, 1, 192, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1600x1200 @ 65 Hz, 81.2 kHz hsync */
+	"1600x1200@65", 65, 1600, 1200, 5698, 304, 64, 46, 1, 192, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1600x1200 @ 70 Hz, 87.5 kHz hsync */
+	"1600x1200@70", 70, 1600, 1200, 5291, 304, 64, 46, 1, 192, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1600x1200 @ 75 Hz, 93.8 kHz hsync */
+	"1600x1200@75", 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1600x1200 @ 85 Hz, 106.2 kHz hsync */
+	"1600x1200@85", 85, 1600, 1200, 4357, 304, 64, 46, 1, 192, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1792x1344 @ 60 Hz, 83.7 kHz hsync */
+	"1792x1344@60", 60, 1792, 1344, 4883, 328, 128, 46, 1, 200, 3,
+	FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1792x1344 @ 75 Hz, 106.3 kHz hsync */
+	"1792x1344@75", 75, 1792, 1344, 3831, 352, 96, 69, 1, 216, 3,
+	FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1856x1392 @ 60 Hz, 86.4 kHz hsync */
+	"1856x1392@60", 60, 1856, 1392, 4581, 352, 96, 43, 1, 224, 3,
+	FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1856x1392 @ 75 Hz, 112.5 kHz hsync */
+	"1856x1392@75", 75, 1856, 1392, 3472, 352, 128, 104, 1, 224, 3,
+	FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1920x1440 @ 60 Hz, 90.0 kHz hsync */
+	"1920x1440@60", 60, 1920, 1440, 4274, 344, 128, 56, 1, 208, 3,
+	FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1920x1440 @ 75 Hz, 112.5 kHz hsync */
+	"1920x1440@75", 75, 1920, 1440, 3367, 352, 144, 56, 1, 224, 3,
+	FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 832x624 @ 75 Hz, 49.7 kHz hsync */
+	"832x624@75", 75, 832, 624, 17457, 224, 32, 39, 1, 64, 3,
+	0, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1152x768 @ 55 Hz, 44.2 kHz hsync */
+	"1152x768@55", 55, 1152, 768, 15386, 158, 26, 29, 3, 136, 6,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1400x1050 @ 60 Hz, 64.9 kHz hsync */
+	"1400x1050@60", 60, 1400, 1050, 8197, 240, 88, 18, 2, 152, 12,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1400x1050 @ 75 Hz, 81.5 kHz hsync */
+	"1400x1050@75", 75, 1400, 1050, 6418, 128, 64, 26, 2, 320, 12,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1600x1024 @ 60 Hz, 64.0 kHz hsync */
+	"1600x1024@60", 60, 1600, 1024, 9354, 30, 20, 37, 3, 20, 3,
+	0, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1920x1440 @ 85 Hz, 128.5 kHz hsync */
+	"1920x1440@85", 85, 1920, 1440, 2930, 368, 152, 68, 1, 216, 3,
+	FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 2048x1536 @ 60 Hz, 95.3 kHz hsync */
+	"2048x1536@60", 60, 2048, 1536, 3746, 376, 152, 49, 1, 224, 3,
+	FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 2048x1536 @ 75 Hz, 120.2 kHz hsync */
+	"2048x1536@75", 75, 2048, 1536, 2937, 392, 168, 63, 1, 224, 3,
+	FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 2048x1536 @ 85 Hz, 137.0 kHz hsync */
+	"2048x1536@85", 85, 2048, 1536, 2577, 392, 168, 72, 1, 224, 3,
+	FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    }
+};
+
+static int num_modes = sizeof(modedb) / sizeof(modedb[0]);
+
+#define DFLT_MODE 3
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/intel/intelfb.h linux-2.4.21-pre6/drivers/video/intel/intelfb.h
--- linux-2.4.20/drivers/video/intel/intelfb.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/intel/intelfb.h	2003-03-26 23:49:39.000000000 +0000
@@ -0,0 +1,385 @@
+#ifndef _INTELFB_H
+#define _INTELFB_H
+
+/* $DHD: intelfb/intelfb.h,v 1.38 2003/02/06 17:29:41 dawes Exp $ */
+/* $TG$ */
+
+
+/*** Version/name ***/
+#define INTELFB_VERSION			"0.7.5"
+#define INTELFB_MODULE_NAME		"intelfb"
+#define SUPPORTED_CHIPSETS		"830M/845G/852GM/855GM/865G"
+
+
+/*** Debug/feature defines ***/
+
+#ifndef DEBUG
+#define DEBUG				0
+#endif
+
+#ifndef VERBOSE
+#define VERBOSE				1
+#endif
+
+#ifndef REGDUMP
+#define REGDUMP				0
+#endif
+
+#ifndef DETECT_VGA_CLASS_ONLY
+#define DETECT_VGA_CLASS_ONLY		1
+#endif
+
+#ifndef FIXED_MODE
+#define FIXED_MODE			0
+#endif
+
+#ifndef ALLOCATE_FOR_PANNING
+#define ALLOCATE_FOR_PANNING		0
+#endif
+
+#ifndef BAILOUT_EARLY
+#define BAILOUT_EARLY			0
+#endif
+
+#ifndef TEST_MODE_TO_HW
+#define TEST_MODE_TO_HW			0
+#endif
+
+#ifndef USE_SYNC_PAGE
+#define USE_SYNC_PAGE			1
+#endif
+
+#ifndef MOBILE_HW_CURSOR
+#define MOBILE_HW_CURSOR		0
+#endif
+
+#ifndef PREFERRED_MODE
+#define PREFERRED_MODE			"1024x768-16@60"
+#endif
+
+/*** hw-related values ***/
+
+/* PCI ids for supported devices */
+#define PCI_DEVICE_ID_INTEL_830M	0x3577
+#define PCI_DEVICE_ID_INTEL_845G	0x2562
+#define PCI_DEVICE_ID_INTEL_85XGM	0x3582
+#define PCI_DEVICE_ID_INTEL_865G	0x2572
+
+/* Size of MMIO region */
+#define INTEL_REG_SIZE			0x80000
+
+#define STRIDE_ALIGNMENT		16
+
+#define PAT_ROP_GXCOPY                  0xf0
+#define PAT_ROP_GXXOR                   0x5a
+
+#define PALETTE_8_ENTRIES		256
+
+
+/*** Macros ***/
+
+/* basic arithmetic */
+#define KB(x)			((x) * 1024)
+#define MB(x)			((x) * 1024 * 1024)
+#define BtoKB(x)		((x) / 1024)
+#define BtoMB(x)		((x) / 1024 / 1024)
+
+#define ROUND_UP_TO(x, y)	(((x) + (y) - 1) / (y) * (y))
+#define ROUND_DOWN_TO(x, y)	((x) / (y) * (y))
+#define ROUND_UP_TO_PAGE(x)	ROUND_UP_TO((x), PAGE_SIZE)
+#define ROUND_DOWN_TO_PAGE(x)	ROUND_DOWN_TO((x), PAGE_SIZE)
+
+/* messages */
+#define PFX			INTELFB_MODULE_NAME ": "
+
+#define ERR_MSG(fmt, args...)	printk(KERN_ERR PFX fmt, ## args)
+#define WRN_MSG(fmt, args...)	printk(KERN_WARNING PFX fmt, ## args)
+#define NOT_MSG(fmt, args...)	printk(KERN_NOTICE PFX fmt, ## args)
+#define INF_MSG(fmt, args...)	printk(KERN_INFO PFX fmt, ## args)
+#if DEBUG
+#define DBG_MSG(fmt, args...)	printk(KERN_DEBUG PFX fmt, ## args)
+#else
+#define DBG_MSG(fmt, args...)	while (0) printk(fmt, ## args)
+#endif
+
+/* get commonly used pointers */
+#define GET_DINFO(info)		(struct intelfb_info *)(info)
+#define GET_DISP(info, con)	((con) < 0) ? (info)->disp : &fb_display[con]
+
+/* module parameters */
+#define INTELFB_INT_PARAM(name, default, desc)				\
+	static int name = default;					\
+	MODULE_PARM(name, "i");						\
+	MODULE_PARM_DESC(name, desc);
+
+#define INTELFB_STR_PARAM(name, default, desc)				\
+	static const char *name = default;				\
+	MODULE_PARM(name, "s");						\
+	MODULE_PARM_DESC(name, desc);
+
+/* misc macros */
+#define TEXT_ACCEL(d, v)						\
+	((d)->accel && (d)->ring_active &&				\
+	 ((v)->accel_flags & FB_ACCELF_TEXT))
+
+#define USE_DRAWGLYPH(d)						\
+	((d)->chipset == INTEL_865G)
+
+#define NOACCEL_CHIPSET(d)						\
+	((d)->chipset != INTEL_865G)
+
+#ifndef LockPage
+#define LockPage(page)		set_bit(PG_locked, &(page)->flags)
+#endif
+#ifndef UnlockPage
+#define UnlockPage(page)	unlock_page(page)
+#endif
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+#define FB_SET_CMAP(a, b, c, d) fb_set_cmap(a, b, d)
+#else
+#define FB_SET_CMAP(a, b, c, d) fb_set_cmap(a, b, c, d)
+#endif
+
+
+/*** Driver paramters ***/
+
+#define RINGBUFFER_SIZE		KB(64)
+#define HW_CURSOR_SIZE		KB(4)
+
+
+/*** Data Types ***/
+
+/* supported chipsets */
+enum intel_chips {
+	INTEL_830M,
+	INTEL_845G,
+	INTEL_85XGM,
+	INTEL_852GM,
+	INTEL_852GME,
+	INTEL_855GM,
+	INTEL_855GME,
+	INTEL_865G
+};
+
+struct intelfb_hwstate {
+	u32 vga0_divisor;
+	u32 vga1_divisor;
+	u32 vga_pd;
+	u32 dpll_a;
+	u32 dpll_b;
+	u32 fpa0;
+	u32 fpa1;
+	u32 fpb0;
+	u32 fpb1;
+	u32 palette_a[PALETTE_8_ENTRIES];
+	u32 palette_b[PALETTE_8_ENTRIES];
+	u32 htotal_a;
+	u32 hblank_a;
+	u32 hsync_a;
+	u32 vtotal_a;
+	u32 vblank_a;
+	u32 vsync_a;
+	u32 src_size_a;
+	u32 bclrpat_a;
+	u32 htotal_b;
+	u32 hblank_b;
+	u32 hsync_b;
+	u32 vtotal_b;
+	u32 vblank_b;
+	u32 vsync_b;
+	u32 src_size_b;
+	u32 bclrpat_b;
+	u32 adpa;
+	u32 dvoa;
+	u32 dvob;
+	u32 dvoc;
+	u32 dvoa_srcdim;
+	u32 dvob_srcdim;
+	u32 dvoc_srcdim;
+	u32 lvds;
+	u32 pipe_a_conf;
+	u32 pipe_b_conf;
+	u32 disp_arb;
+	u32 cursor_a_control;
+	u32 cursor_b_control;
+	u32 cursor_a_base;
+	u32 cursor_b_base;
+	u32 cursor_size;
+	u32 disp_a_ctrl;
+	u32 disp_b_ctrl;
+	u32 disp_a_base;
+	u32 disp_b_base;
+	u32 cursor_a_palette[4];
+	u32 cursor_b_palette[4];
+	u32 disp_a_stride;
+	u32 disp_b_stride;
+	u32 vgacntrl;
+	u32 add_id;
+	u32 swf0x[7];
+	u32 swf1x[7];
+	u32 swf3x[3];
+	u32 fence[8];
+	u32 instpm;
+	u32 mem_mode;
+	u32 fw_blc_0;
+	u32 fw_blc_1;
+};
+
+struct intelfb_info {
+	struct fb_info info;
+
+	const char *name;
+
+	u32 fb_base_phys;
+	u32 mmio_base_phys;
+
+	u32 fb_base;
+	u32 mmio_base;
+
+	u32 fb_offset;
+
+	struct pci_dev *pdev;
+
+	/* Ring buffer */
+	u32 ring_base_phys;
+	u32 ring_base;
+	u32 ring_size;
+	u32 ring_head;
+	u32 ring_tail;
+	u32 ring_tail_mask;
+	u32 ring_space;
+
+	/* HW cursor */
+	u32 cursor_base_phys;
+	u32 cursor_offset;
+	u32 cursor_base;
+	u32 cursor_size;
+	u32 cursor_page_virt;
+	u32 cursor_base_real;
+
+#if USE_SYNC_PAGE
+	/* 2D synchronisation */
+	u32 syncpage_virt;
+	u32 syncpage_phys;
+#endif
+
+	struct display disp;
+	int currcon;
+	struct display *currcon_display;
+
+	struct { u8 red, green, blue, pad; } palette[256];
+
+	int pci_chipset;
+	int chipset;
+	int mobile;
+
+	int video_ram;
+	int aperture_size;
+	int stolen_size;
+	int bpp, depth;
+	u32 visual;
+
+	int xres, yres, pitch;
+	int pixclock;
+
+	int pipe;
+
+	int accel;
+	int hwcursor;
+	int fixed_mode;
+
+	int ring_active;
+
+#if defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB32)
+	union {
+#if defined(FBCON_HAS_CFB16)
+		u_int16_t cfb16[16];
+#endif
+#if defined(FBCON_HAS_CFB32)
+		u_int32_t cfb32[16];
+#endif
+	} con_cmap;
+#endif
+
+	int vc_mode;
+
+	struct intelfb_hwstate save_state;
+
+	int registered;
+
+	int initial_vga;
+	struct fb_var_screeninfo initial_var;
+	u32 initial_fb_base;
+	u32 initial_video_ram;
+	u32 initial_pitch;
+
+	struct {
+		int type;
+		int state;
+		int on;
+		int enabled;
+		int blanked;
+		int w, u, d;
+		int x, y, redraw;
+		unsigned long cursorimage;
+		struct timer_list timer;
+	} cursor;
+	spinlock_t DAClock;
+};
+
+
+/*** Functions ***/
+
+/* intelfb.c */
+extern int intelfb_var_to_depth(const struct fb_var_screeninfo *var);
+extern void intelfb_create_cursor_shape(struct intelfb_info *dinfo,
+					struct display *disp);
+
+/* intelfbhw.c */
+
+extern int intelfbhw_get_chipset(struct pci_dev *pdev, const char **name,
+				 int *chipset, int *mobile);
+extern int intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size,
+				int *stolen_size);
+extern const char *intelfbhw_check_non_crt(struct intelfb_info *dinfo);
+extern int intelfbhw_validate_mode(struct intelfb_info *dinfo, int con,
+				   struct fb_var_screeninfo *var);
+extern int intelfbhw_pan_display(struct fb_var_screeninfo *var, int con,
+				 struct fb_info *info);
+extern void intelfbhw_do_blank(int blank, struct fb_info *info);
+extern void intelfbhw_setcolreg(struct intelfb_info *dinfo, unsigned regno,
+				unsigned red, unsigned green, unsigned blue,
+				unsigned transp);
+extern int intelfbhw_read_hw_state(struct intelfb_info *dinfo,
+				   struct intelfb_hwstate *hw, int flag);
+extern void intelfbhw_print_hw_state(struct intelfb_info *dinfo,
+				     struct intelfb_hwstate *hw);
+extern int intelfbhw_mode_to_hw(struct intelfb_info *dinfo,
+				struct intelfb_hwstate *hw,
+				struct fb_var_screeninfo *var);
+extern int intelfbhw_program_mode(struct intelfb_info *dinfo,
+				  const struct intelfb_hwstate *hw, int blank);
+extern void intelfbhw_do_sync(struct intelfb_info *dinfo);
+extern void intelfbhw_2d_stop(struct intelfb_info *dinfo);
+extern void intelfbhw_2d_start(struct intelfb_info *dinfo);
+extern void intelfbhw_do_fillrect(struct intelfb_info *dinfo, u32 x, u32 y,
+				  u32 w, u32 h, u32 color, u32 pitch, u32 bpp,
+				  u32 rop);
+extern void intelfbhw_do_bitblt(struct intelfb_info *dinfo, u32 curx, u32 cury,
+				u32 dstx, u32 dsty, u32 w, u32 h, u32 pitch,
+				u32 bpp);
+extern int intelfbhw_do_drawglyph(struct intelfb_info *dinfo, u32 fg, u32 bg,
+				  u32 w, u32 h, u8* cdat, u32 x, u32 y,
+				  u32 pitch, u32 bpp);
+extern void intelfbhw_cursor_init(struct intelfb_info *dinfo);
+extern void intelfbhw_cursor_hide(struct intelfb_info *dinfo);
+extern void intelfbhw_cursor_show(struct intelfb_info *dinfo);
+extern void intelfbhw_cursor_setpos(struct intelfb_info *dinfo, int x, int y);
+extern void intelfbhw_cursor_setcolor(struct intelfb_info *dinfo, u32 bg,
+				      u32 fg);
+extern void intelfbhw_cursor_load(struct intelfb_info *dinfo,
+				  struct display *disp);
+
+
+#endif /* _INTELFB_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/intel/intelfbdrv.c linux-2.4.21-pre6/drivers/video/intel/intelfbdrv.c
--- linux-2.4.20/drivers/video/intel/intelfbdrv.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/intel/intelfbdrv.c	2003-03-26 23:48:59.000000000 +0000
@@ -0,0 +1,2219 @@
+/*
+ * intelfb
+ *
+ * Linux framebuffer driver for Intel(R) 830M/845G/852GM/855GM/865G
+ * integrated graphics chips.
+ *
+ * Copyright (C) 2002, 2003 David Dawes <dawes@tungstengraphics.com>
+ *
+ * This driver consists of two parts.  The first part (intelfbdrv.c) provides
+ * the basic fbdev interfaces, is derived in part from the radeonfb and
+ * vesafb drivers, and is covered by the GPL.  The second part (intelfbhw.c)
+ * provides the code to program the hardware.  Most of it is derived from
+ * the i810/i830 XFree86 driver.  The HW-specific code is covered here
+ * under a dual license (GPL and MIT/XFree86 license).
+ *
+ * Author: David Dawes
+ *
+ */
+
+/* $DHD: intelfb/intelfbdrv.c,v 1.15 2003/02/06 17:50:08 dawes Exp $ */
+/* $TG$ */
+
+/*
+ * Changes:
+ *    01/2003 - Initial driver (0.1.0), no mode switching, no acceleration.
+ *		This initial version is a basic core that works a lot like
+ *		the vesafb driver.  It must be built-in to the kernel,
+ *		and the initial video mode must be set with vga=XXX at
+ *		boot time.  (David Dawes)
+ *
+ *    01/2003 - Version 0.2.0: Mode switching added, colormap support
+ *		implemented, Y panning, and soft screen blanking implemented.
+ *		No acceleration yet.  (David Dawes)
+ *
+ *    01/2003 - Version 0.3.0: fbcon acceleration support added.  Module
+ *		option handling added.  (David Dawes)
+ *
+ *    01/2003 - Version 0.4.0: fbcon HW cursor support added.  (David Dawes)
+ *
+ *    01/2003 - Version 0.4.1: Add auto-generation of built-in modes.
+ *		(David Dawes)
+ *
+ *    02/2003 - Version 0.4.2: Add check for active non-CRT devices, and 
+ *		mode validation checks.  (David Dawes)
+ *
+ *    02/2003 - Version 0.4.3: Check when the VC is in graphics mode so that
+ *		acceleration is disabled while an XFree86 server is running.
+ *		(David Dawes)
+ *
+ *    02/2003 - Version 0.4.4: Monitor DPMS support.  (David Dawes)
+ *
+ *    02/2003 - Version 0.4.5: Basic XFree86 + fbdev working.  (David Dawes)
+ *
+ *    02/2003 - Version 0.5.0: Modify to work with the 2.5.32 kernel as well
+ *		as 2.4.x kernels.  (David Dawes)
+ *
+ *    02/2003 - Version 0.6.0: Split out HW-specifics into a separate file.
+ *		(David Dawes)
+ *
+ *    02/2003 - Version 0.7.0: Test on 852GM/855GM.  Acceleration and HW
+ *		cursor are disabled on this platform.  (David Dawes)
+ *
+ *    02/2003 - Version 0.7.1: Test on 845G.  Acceleration is disabled
+ *		on this platform.  (David Dawes)
+ *
+ *    02/2003 - Version 0.7.2: Test on 830M.  Acceleration and HW
+ *		cursor are disabled on this platform.  (David Dawes)
+ *
+ *    02/2003 - Version 0.7.3: Fix 8-bit modes for mobile platforms
+ *		(David Dawes)
+ *
+ *    02/2003 - Version 0.7.4: Add checks for FB and FBCON_HAS_CFB* configured
+ *		in the kernel, and add mode bpp verification and default
+ *		bpp selection based on which FBCON_HAS_CFB* are configured.
+ *		(David Dawes)
+ *
+ *    02/2003 - Version 0.7.5: Add basic package/install scripts based on the
+ *		DRI packaging scripts.  (David Dawes)
+ *
+ * TODO:
+ *  - 
+ *
+ * Wish List:
+ *  - Check clock limits for 845G and 830M.
+ *  - Test on SMP config.
+ *  - Check if any functions/data should be __devinit, etc.
+ *  - See if it's feasible to get/use DDC/EDID info.
+ *  - MTRR support.
+ *  - See if module unloading can work.
+ *  - See if driver works built-in to 2.5.32 kernel.
+ *  - Check acceleration problems on 830M-855GM.
+ *  - Add gtf support so that arbitrary modes can be calculated.
+ *  - Port driver to latest 2.5.x fbdev interface.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/console.h>
+#include <linux/selection.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+#include <linux/kd.h>
+#include <linux/vt_kern.h>
+#include <linux/pagemap.h>
+#include <linux/version.h>
+
+#include <asm/io.h>
+
+#include <video/fbcon.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb32.h>
+
+#include "intelfb.h"
+
+#include "builtinmodes.c"
+
+/*
+ * Limiting the class to PCI_CLASS_DISPLAY_VGA prevents function 1 of the
+ * mobile chipsets from being registered.
+ */
+#if DETECT_VGA_CLASS_ONLY
+#define INTELFB_CLASS_MASK ~0 << 8
+#else
+#define INTELFB_CLASS_MASK 0
+#endif
+
+static struct pci_device_id intelfb_pci_table[] __devinitdata = {
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_830M, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_830M },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_845G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_845G },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_85XGM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_85XGM },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_865G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_865G },
+	{ 0, }
+};
+
+/* Global data */
+static int num_registered = 0;
+
+
+/* Forward declarations */
+static int intelfb_get_fix(struct fb_fix_screeninfo *fix, int con,
+			   struct fb_info *info);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+static int intelfb_get_var(struct fb_var_screeninfo *var, int con,
+			   struct fb_info *info);
+#endif
+static int intelfb_set_var(struct fb_var_screeninfo *var, int con,
+			   struct fb_info *info);
+static int intelfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+			    struct fb_info *info);
+static int intelfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+			    struct fb_info *info);
+static int intelfb_ioctl(struct inode *inode, struct file *file,
+			 unsigned int cmd, unsigned long arg, int con,
+			 struct fb_info *info);
+static int intelfb_switch(int con, struct fb_info *info);
+static int intelfb_updatevar(int con, struct fb_info *info);
+static int intelfb_blank(int blank, struct fb_info *info);
+static int intelfb_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+			     unsigned *blue, unsigned *transp,
+			     struct fb_info *info);
+static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			     unsigned blue, unsigned transp,
+			     struct fb_info *info);
+static int intelfb_pci_register(struct pci_dev *pdev,
+				const struct pci_device_id *ent);
+static void __devexit intelfb_pci_unregister(struct pci_dev *pdev);
+static int __devinit intelfb_set_fbinfo(struct intelfb_info *dinfo);
+static void intelfb_set_dispsw(struct intelfb_info *dinfo,
+			       struct display *disp);
+static void mode_to_var(const struct fb_videomode *mode,
+			struct fb_var_screeninfo *var, u32 bpp);
+static int intelfb_set_mode(struct intelfb_info *dinfo,
+			    struct fb_var_screeninfo *var,
+			    struct display *disp, int blank);
+static void intelfb_do_install_cmap(int con, struct fb_info *info);
+static void update_dinfo(struct intelfb_info *dinfo,
+			 struct fb_var_screeninfo *var, struct display *disp);
+static void intelfb_flashcursor(unsigned long ptr);
+static void fbcon_intelfb_setup(struct display *p);
+static void fbcon_intelfb_bmove(struct display *p, int sy, int sx, int dy,
+				int dx, int height, int width);
+static void fbcon_intelfb_clear(struct vc_data *conp, struct display *p,
+				int sy, int sx, int height, int width);
+static void fbcon_intelfb_putc(struct vc_data *conp, struct display *p,
+			       int c, int yy, int xx);
+static void fbcon_intelfb_putcs(struct vc_data *conp, struct display *p,
+				const unsigned short *s, int count,
+				int yy, int xx);
+static void fbcon_intelfb_revc(struct display *p, int xx, int yy);
+static void fbcon_intelfb_clear_margins(struct vc_data *conp,
+					struct display *p, int bottom_only);
+static void fbcon_intelfb_cursor(struct display *disp, int mode, int x, int y);
+
+/* fb ops */
+static struct fb_ops intel_fb_ops = {
+	.owner =		THIS_MODULE,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	.fb_get_fix =		intelfb_get_fix,
+	.fb_get_var =		intelfb_get_var,
+#else
+	.fb_blank =		intelfb_blank,
+	.fb_setcolreg =		intelfb_setcolreg,
+#endif
+	.fb_set_var =		intelfb_set_var,
+	.fb_get_cmap =		intelfb_get_cmap,
+	.fb_set_cmap =		intelfb_set_cmap,
+	.fb_pan_display	=	intelfbhw_pan_display,
+	.fb_ioctl =		intelfb_ioctl
+};
+
+/* PCI driver module table */
+static struct pci_driver intelfb_driver = {
+	.name =			INTELFB_MODULE_NAME,
+	.id_table =		intelfb_pci_table,
+	.probe =		intelfb_pci_register,
+	.remove =		__devexit_p(intelfb_pci_unregister)
+};
+
+/* fbcon acceleration */
+static struct display_switch fbcon_intelfb = {
+	.setup =		fbcon_intelfb_setup,
+	.bmove =		fbcon_intelfb_bmove,
+	.clear =		fbcon_intelfb_clear,
+	.putc =			fbcon_intelfb_putc,
+	.putcs =		fbcon_intelfb_putcs,
+	.revc =			fbcon_intelfb_revc,
+	.cursor =		fbcon_intelfb_cursor,
+	.clear_margins =	fbcon_intelfb_clear_margins,
+	.fontwidthmask =	FONTWIDTHRANGE(4, 16)
+};
+
+/* Module description/parameters */
+MODULE_AUTHOR("David Dawes <dawes@tungstengraphics.com>");
+MODULE_DESCRIPTION(
+	"Framebuffer driver for Intel(R) " SUPPORTED_CHIPSETS " chipsets");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DEVICE_TABLE(pci, intelfb_pci_table);
+
+INTELFB_INT_PARAM(accel, 1, "Enable console acceleration");
+INTELFB_INT_PARAM(hwcursor, 1, "Enable HW cursor");
+INTELFB_INT_PARAM(fixed, 0, "Disable mode switching");
+INTELFB_INT_PARAM(noinit, 0, "Don't initialise graphics mode when loading");
+INTELFB_INT_PARAM(noregister, 0, "Don't register, just probe and exit (debug)");
+INTELFB_INT_PARAM(probeonly, 0, "Do a minimal probe (debug)");
+INTELFB_INT_PARAM(idonly, 0,
+		  "Just identify without doing anything else (debug)");
+INTELFB_INT_PARAM(bailearly, 0, "Bail out early, depending on value (debug)");
+INTELFB_STR_PARAM(mode, NULL,
+		  "Initial video mode \"<xres>x<yres>[-<depth>][@<refresh>]\"");
+INTELFB_STR_PARAM(font, NULL, "Specify which built-in font to use");
+
+
+/* module load/unload entry points */
+int __init
+intelfb_init(void)
+{
+	DBG_MSG("intelfb_init\n");
+
+	INF_MSG("Framebuffer driver for "
+		"Intel(R) " SUPPORTED_CHIPSETS " chipsets\n");
+	INF_MSG("Version " INTELFB_VERSION
+		", written by David Dawes <dawes@tungstengraphics.com>\n");
+
+	if (idonly)
+		return -ENODEV;
+
+	return pci_module_init(&intelfb_driver);
+}
+
+void __exit
+intelfb_exit(void)
+{
+	DBG_MSG("intelfb_exit\n");
+	pci_unregister_driver(&intelfb_driver);
+}
+
+#ifndef MODULE
+#define OPT_EQUAL(opt, name) (!strncmp(opt, name, strlen(name)))
+#define OPT_INTVAL(opt, name) simple_strtoul(opt + strlen(name), NULL, 0)
+#define OPT_STRVAL(opt, name) (opt + strlen(name))
+
+static __inline__ char *
+get_opt_string(const char *this_opt, const char *name)
+{
+	const char *p;
+	int i;
+	char *ret;
+
+	p = OPT_STRVAL(this_opt, name);
+	i = 0;
+	while (p[i] && p[i] != ' ' && p[i] != ',')
+		i++;
+	ret = kmalloc(i + 1, GFP_KERNEL);
+	if (ret) {
+		strncpy(ret, p, i);
+		ret[i] = '\0';
+	}
+	return ret;
+}
+
+static __inline__ int
+get_opt_bool(const char *this_opt, const char *name, int *ret)
+{
+	if (!ret)
+		return 0;
+
+	if (OPT_EQUAL(this_opt, name)) {
+		if (this_opt[strlen(name)] == '=')
+			*ret = simple_strtoul(this_opt + strlen(name) + 1,
+					      NULL, 0);
+		else
+			*ret = 1;
+	} else {
+		if (OPT_EQUAL(this_opt, "no") && OPT_EQUAL(this_opt + 2, name))
+			*ret = 0;
+		else
+			return 0;
+	}
+	return 1;
+}
+
+int __init
+intelfb_setup(char *options)
+{
+	char *this_opt;
+
+	DBG_MSG("intelfb_setup\n");
+
+	if (!options || !*options) {
+		DBG_MSG("no options\n");
+		return 0;
+	} else
+		DBG_MSG("options: %s\n", options);
+
+	/*
+	 * These are the built-in options analogous to the module parameters
+	 * defined above.
+	 *
+	 * The syntax is:
+	 *
+	 *    video=intelfb:[mode][,<param>=<val>] ...
+	 *
+	 * e.g.,
+	 *
+	 *    video=intelfb:1024x768-16@75,accel=0
+	 */
+
+	while ((this_opt = strsep(&options, ","))) {
+		if (!*this_opt)
+			continue;
+		if (get_opt_bool(this_opt, "accel", &accel))
+			;
+		else if (get_opt_bool(this_opt, "hwcursor", &hwcursor))
+			;
+		else if (get_opt_bool(this_opt, "fixed", &fixed))
+			;
+		else if (get_opt_bool(this_opt, "init", &noinit))
+			noinit = !noinit;
+		else if (OPT_EQUAL(this_opt, "font="))
+			font = get_opt_string(this_opt, "font=");
+		else if (OPT_EQUAL(this_opt, "mode="))
+			mode = get_opt_string(this_opt, "mode=");
+		else
+			mode = this_opt;
+	}
+
+	return 0;
+}
+#endif
+
+#ifdef MODULE
+module_init(intelfb_init);
+module_exit(intelfb_exit);
+#endif
+
+static void
+cleanup(struct intelfb_info *dinfo)
+{
+	DBG_MSG("cleanup\n");
+
+	if (!dinfo)
+		return;
+
+	if (dinfo->registered)
+		unregister_framebuffer(&(dinfo->info));
+
+	if (&dinfo->cursor.timer)
+		del_timer_sync(&dinfo->cursor.timer);
+
+#if USE_SYNC_PAGE
+	if (dinfo->syncpage_virt) {
+		struct page *pg = virt_to_page((void *)dinfo->syncpage_virt);
+		if (pg) {
+			put_page(pg);
+			UnlockPage(pg);
+			free_page(dinfo->syncpage_virt);
+		}
+	}
+#endif
+
+	if (dinfo->cursor_base)
+		iounmap((void *)dinfo->cursor_base);
+	if (dinfo->ring_base)
+		iounmap((void *)dinfo->ring_base);
+	if (dinfo->fb_base)
+		iounmap((void *)dinfo->fb_base);
+	if (dinfo->mmio_base)
+		iounmap((void *)dinfo->mmio_base);
+	if (dinfo->mmio_base_phys && dinfo->pdev)
+		release_mem_region(dinfo->mmio_base_phys,
+				   pci_resource_len(dinfo->pdev, 1));
+	if (dinfo->fb_base_phys && dinfo->pdev)
+		release_mem_region(dinfo->fb_base_phys,
+				   pci_resource_len(dinfo->pdev, 0));
+	kfree(dinfo);
+}
+
+#define bailout(dinfo) do {						\
+	DBG_MSG("bailout\n");						\
+	cleanup(dinfo);							\
+	INF_MSG("Not going to register framebuffer, exiting...\n");	\
+	return -ENODEV;							\
+} while (0)
+
+
+int
+intelfb_var_to_depth(const struct fb_var_screeninfo *var)
+{
+#if 0
+	DBG_MSG("intelfb_var_to_depth: bpp: %d, green.length is %d\n",
+		var->bits_per_pixel, var->green.length);
+#endif
+
+	switch (var->bits_per_pixel) {
+	case 16:
+		return (var->green.length == 6) ? 16 : 15;
+	case 32:
+		return 24;
+	default:
+		return var->bits_per_pixel;
+	}
+}
+
+static void
+get_initial_mode(struct intelfb_info *dinfo)
+{
+	struct fb_var_screeninfo *var;
+	int xtot, ytot;
+
+	DBG_MSG("get_initial_mode\n");
+
+	dinfo->initial_vga = 1;
+	dinfo->initial_fb_base = screen_info.lfb_base;
+	dinfo->initial_video_ram = screen_info.lfb_size * KB(64);
+	dinfo->initial_pitch = screen_info.lfb_linelength;
+
+	var = &dinfo->initial_var;
+	memset(var, 0, sizeof(*var));
+	var->xres = screen_info.lfb_width;
+	var->yres = screen_info.lfb_height;
+	var->xres_virtual = var->xres;
+#if ALLOCATE_FOR_PANNING
+	/* Allow use of half of the video ram for panning */
+	var->yres_virtual =
+		dinfo->initial_video_ram / 2 / dinfo->initial_pitch;
+	if (var->yres_virtual < var->yres)
+		var->yres_virtual = var->yres;
+#else
+	var->yres_virtual = var->yres;
+#endif
+	var->bits_per_pixel = screen_info.lfb_depth;
+	switch (screen_info.lfb_depth) {
+	case 15:
+		var->bits_per_pixel = 16;
+		break;
+	case 24:
+		var->bits_per_pixel = 32;
+		break;
+	}
+
+	DBG_MSG("Initial info: FB is 0x%x/0x%x (%d kByte)\n",
+		dinfo->initial_fb_base, dinfo->initial_video_ram,
+		BtoKB(dinfo->initial_video_ram));
+
+	DBG_MSG("Initial info: mode is %dx%d-%d (%d)\n",
+		var->xres, var->yres, var->bits_per_pixel,
+		dinfo->initial_pitch);
+
+	/* Dummy timing values (assume 60Hz) */
+	var->left_margin = (var->xres / 8) & 0xf8;
+	var->right_margin = 32;
+	var->upper_margin = 16;
+	var->lower_margin = 4;
+	var->hsync_len = (var->xres / 8) & 0xf8;
+	var->vsync_len = 4;
+
+	xtot = var->xres + var->left_margin +
+		var->right_margin + var->hsync_len;
+	ytot = var->yres + var->upper_margin +
+		var->lower_margin + var->vsync_len;
+	var->pixclock = 10000000 / xtot * 1000 / ytot * 100 / 60;
+
+	var->height = -1;
+	var->width = -1;
+
+	if (var->bits_per_pixel > 8) {
+		var->red.offset = screen_info.red_pos;
+		var->red.length = screen_info.red_size;
+		var->green.offset = screen_info.green_pos;
+		var->green.length = screen_info.green_size;
+		var->blue.offset = screen_info.blue_pos;
+		var->blue.length = screen_info.blue_size;
+		var->transp.offset = screen_info.rsvd_pos;
+		var->transp.length = screen_info.rsvd_size;
+	} else {
+		var->red.length = 8;
+		var->green.length = 8;
+		var->blue.length = 8;
+	}
+}
+
+static int
+intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	struct intelfb_info *dinfo;
+	int i, j, err;
+	const char *s;
+
+	DBG_MSG("intelfb_pci_register\n");
+
+	num_registered++;
+	if (num_registered != 1) {
+		ERR_MSG("Attempted to register %d devices "
+			"(should be only 1).\n", num_registered);
+		return -ENODEV;
+	}
+
+	if (!(dinfo = kmalloc(sizeof(struct intelfb_info), GFP_KERNEL))) {
+		ERR_MSG("Could not allocate memory for intelfb_info.\n");
+		return -ENODEV;
+	}
+
+	memset(dinfo, 0, sizeof(*dinfo));
+	dinfo->pdev = pdev;
+
+	/* Enable device. */
+	if ((err = pci_enable_device(pdev))) {
+		ERR_MSG("Cannot enable device.\n");
+		cleanup(dinfo);
+		return -ENODEV;
+	}
+
+	/* Set base addresses. */
+	dinfo->fb_base_phys = pci_resource_start(pdev, 0);
+	dinfo->mmio_base_phys = pci_resource_start(pdev, 1);
+
+	DBG_MSG("fb region: 0x%lx/0x%lx, MMIO region: 0x%lx/0x%lx\n",
+		pci_resource_start(pdev, 0), pci_resource_len(pdev, 0),
+		pci_resource_start(pdev, 1), pci_resource_len(pdev, 1));
+
+	/* Reserve the fb and MMIO regions */
+	if (!request_mem_region(dinfo->fb_base_phys, pci_resource_len(pdev, 0),
+				INTELFB_MODULE_NAME)) {
+		ERR_MSG("Cannot reserve FB region.\n");
+		cleanup(dinfo);
+		return -ENODEV;
+	}
+	if (!request_mem_region(dinfo->mmio_base_phys,
+				pci_resource_len(pdev, 1),
+				INTELFB_MODULE_NAME)) {
+		ERR_MSG("Cannot reserve MMIO region.\n");
+		cleanup(dinfo);
+		return -ENODEV;
+	}
+
+	/* Map the MMIO region. */
+	dinfo->mmio_base = (u32)ioremap(dinfo->mmio_base_phys, INTEL_REG_SIZE);
+	if (!dinfo->mmio_base) {
+		ERR_MSG("Cannot map MMIO.\n");
+		cleanup(dinfo);
+		return -ENODEV;
+	}
+
+	/* Get the chipset info. */
+	dinfo->pci_chipset = pdev->device;
+
+	if (intelfbhw_get_chipset(pdev, &dinfo->name, &dinfo->chipset,
+				  &dinfo->mobile)) {
+		cleanup(dinfo);
+		return -ENODEV;
+	}
+
+	if (intelfbhw_get_memory(pdev, &dinfo->aperture_size,
+				 &dinfo->stolen_size)) {
+		cleanup(dinfo);
+		return -ENODEV;
+	}
+
+	INF_MSG("%02x:%02x.%d: %s, aperture size %dMB, "
+		"stolen memory %dkB\n",
+		pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
+		dinfo->name, BtoMB(dinfo->aperture_size),
+		BtoKB(dinfo->stolen_size));
+
+	/* Set these from the options. */
+	dinfo->accel = accel;
+	dinfo->hwcursor = hwcursor;
+
+	if (NOACCEL_CHIPSET(dinfo) && dinfo->accel == 1) {
+		INF_MSG("Acceleration is not supported for the %s chipset.\n",
+			dinfo->name);
+		dinfo->accel = 0;
+	}
+
+	/*
+	 * For now, set the video ram size to the stolen size rounded
+	 * down to a page multiple.  This means the agpgart driver doesn't
+	 * need to get involved.
+	 */
+	dinfo->video_ram = ROUND_DOWN_TO_PAGE(dinfo->stolen_size);
+
+	/* Allocate space for the ring buffer and HW cursor. */
+	if (dinfo->accel) {
+		dinfo->ring_size = RINGBUFFER_SIZE;
+		dinfo->video_ram -= dinfo->ring_size;
+		dinfo->ring_base_phys = dinfo->fb_base_phys + dinfo->video_ram;
+		dinfo->ring_tail_mask = dinfo->ring_size - 1;
+	}
+	if (dinfo->hwcursor && !dinfo->mobile) {
+		dinfo->cursor_size = HW_CURSOR_SIZE;
+		dinfo->video_ram -= dinfo->cursor_size;
+		dinfo->cursor_offset = dinfo->video_ram;
+		dinfo->cursor_base_phys = dinfo->fb_base_phys +
+					  dinfo->cursor_offset;
+	}
+
+	/* Framebuffer starts at offset 0. */
+	dinfo->fb_offset = 0;
+	dinfo->video_ram -= dinfo->fb_offset;
+
+	/* Map the FB region.  Only map the memory used as video ram. */
+	dinfo->fb_base = (u32)ioremap(dinfo->fb_base_phys + dinfo->fb_offset,
+				      dinfo->video_ram);
+	if (!dinfo->fb_base) {
+		ERR_MSG("Cannot map framebuffer.\n");
+		cleanup(dinfo);
+		return -ENODEV;
+	}
+
+	if (dinfo->accel) {
+		/* Map the ring buffer. */
+		dinfo->ring_base = (u32)ioremap(dinfo->ring_base_phys,
+						dinfo->ring_size);
+		if (!dinfo->ring_base) {
+			dinfo->accel = 0;
+			WRN_MSG("Cannot map ring buffer: "
+				"acceleration disabled.\n");
+		}
+	}
+
+	if (dinfo->hwcursor && !dinfo->mobile) {
+		/* Map the HW cursor buffer. */
+		dinfo->cursor_base = (u32)ioremap(dinfo->cursor_base_phys,
+						  dinfo->cursor_size);
+		if (!dinfo->cursor_base) {
+			WRN_MSG("Cannot map the HW cursor space: "
+				"HW cursor disabled.\n");
+			dinfo->hwcursor = 0;
+		}
+	}
+
+	/*
+	 * For mobile platforms, a physical page address is needed for the
+	 * HW cursor.  Allocate it here and insert it into the GTT.
+	 * If/when this driver is modified to be aware of the agpgart
+	 * driver, it can be used to obtain/insert the page.
+	 */
+	if (dinfo->hwcursor && dinfo->mobile) {
+#if !MOBILE_HW_CURSOR
+		dinfo->hwcursor = 0;
+		INF_MSG("HW cursor is not supported for mobile platforms.\n");
+#else
+		struct page *pg;
+
+		/*
+		 * Allocate a page of physical memory for the graphics
+		 * engine to write to for synchronisation purposes.
+		 */
+		pg = alloc_page(GFP_KERNEL);
+		if (!pg) {
+			WRN_MSG("Cannot allocate a page for the HW cursor.  "
+				"Disabling the HW cursor.");
+			dinfo->hwcursor = 0;
+		} else {
+			get_page(pg);
+			LockPage(pg);
+			dinfo->cursor_page_virt = (u32)page_address(pg);
+			dinfo->cursor_base_real =
+						virt_to_phys(page_address(pg));
+
+			/*
+			 * XXX Add code to insert GTT entry and map the
+			 * appropriate part of the aperture as
+			 * dinfo->cursor_base.
+			 */
+		}
+#endif
+	}
+	DBG_MSG("fb: 0x%x(+ 0x%x)/0x%x (0x%x)\n",
+		dinfo->fb_base_phys, dinfo->fb_offset, dinfo->video_ram,
+		dinfo->fb_base);
+	DBG_MSG("MMIO: 0x%x/0x%x (0x%x)\n",
+		dinfo->mmio_base_phys, INTEL_REG_SIZE, dinfo->mmio_base);
+	DBG_MSG("ring buffer: 0x%x/0x%x (0x%x)\n",
+		dinfo->ring_base_phys, dinfo->ring_size, dinfo->ring_base);
+	DBG_MSG("HW cursor: 0x%x/0x%x (0x%x) (offset 0x%x) (phys 0x%x)\n",
+		dinfo->cursor_base_phys, dinfo->cursor_size,
+		dinfo->cursor_base, dinfo->cursor_offset,
+		dinfo->cursor_base_real);
+
+	DBG_MSG("options: accel = %d, fixed = %d, noinit = %d\n",
+		accel, fixed, noinit);
+	DBG_MSG("options: mode = \"%s\", font = \"%s\"\n",
+		mode ? mode : "", font ? font : "");
+
+	if (probeonly)
+		bailout(dinfo);
+
+	dinfo->fixed_mode = fixed;
+
+	/*
+	 * Check if the LVDS port or any DVO ports are enabled.  If so,
+	 * don't allow mode switching.
+	 */
+	if ((s = intelfbhw_check_non_crt(dinfo))) {
+		WRN_MSG("Non-CRT device is enabled (%s).  "
+			"Disabling mode switching.\n", s);
+		dinfo->fixed_mode = 1;
+	}
+
+	if (bailearly == 1)
+		bailout(dinfo);
+
+	if (dinfo->fixed_mode && ORIG_VIDEO_ISVGA != VIDEO_TYPE_VLFB) {
+		ERR_MSG("Video mode must be programmed at boot time.\n");
+		cleanup(dinfo);
+		return -ENODEV;
+	}
+
+	if (bailearly == 2)
+		bailout(dinfo);
+
+	/* Initialise dinfo and related data. */
+	/* If an initial mode was programmed at boot time, get its details. */
+	if (ORIG_VIDEO_ISVGA == VIDEO_TYPE_VLFB)
+		get_initial_mode(dinfo);
+
+	if (bailearly == 3)
+		bailout(dinfo);
+
+#if 0
+	if (dinfo->fixed_mode) {
+		/*
+		 * XXX Check video ram amounts and remap if the region already
+		 * mapped is too small because of ring/cursor allocations.
+		 */
+		update_dinfo(dinfo, &dinfo->initial_var, NULL);
+	}
+#endif
+
+	/* currcon will be set by the first switch. */
+	dinfo->currcon = -1;
+	dinfo->vc_mode = KD_TEXT;
+
+#if USE_SYNC_PAGE
+	if (dinfo->accel) {
+		struct page *pg;
+
+		/*
+		 * Allocate a page of physical memory for the graphics
+		 * engine to write to for synchronisation purposes.
+		 */
+		pg = alloc_page(GFP_KERNEL);
+		if (!pg) {
+			WRN_MSG("Cannot allocate a page for 2D accel.  "
+				"Disabling acceleration.");
+			dinfo->accel = 0;
+		} else {
+			get_page(pg);
+			LockPage(pg);
+			dinfo->syncpage_virt = (u32)page_address(pg);
+			dinfo->syncpage_phys = virt_to_phys(page_address(pg));
+			/* Write zero to the first dword */
+			writel(0, dinfo->syncpage_virt);
+			DBG_MSG("2D sync page: 0x%x (0x%x)\n",
+				dinfo->syncpage_phys, dinfo->syncpage_virt);
+		}
+	}
+#endif
+
+	if (bailearly == 4)
+		bailout(dinfo);
+
+
+	if (intelfb_set_fbinfo(dinfo)) {
+		cleanup(dinfo);
+		return -ENODEV;
+	}
+
+	if (bailearly == 5)
+		bailout(dinfo);
+
+	for (i = 0; i < 16; i++) {
+		j = color_table[i];
+		dinfo->palette[i].red = default_red[j];
+		dinfo->palette[i].green = default_grn[j];
+		dinfo->palette[i].blue = default_blu[j];
+	}
+
+	if (bailearly == 6)
+		bailout(dinfo);
+
+	pci_set_drvdata(pdev, dinfo);
+
+	/* Save the initial register state. */
+	i = intelfbhw_read_hw_state(dinfo, &dinfo->save_state,
+				    bailearly > 6 ? bailearly - 6 : 0);
+	if (i != 0) {
+		DBG_MSG("intelfbhw_read_hw_state returned %d\n", i);
+		bailout(dinfo);
+	}
+
+	intelfbhw_print_hw_state(dinfo, &dinfo->save_state);
+
+	if (bailearly == 18)
+		bailout(dinfo);
+
+#if TEST_MODE_TO_HW
+	{
+		struct intelfb_hwstate hw;
+		struct fb_var_screeninfo var;
+		int i;
+
+		for (i = 0; i < num_modes; i++) {
+			mode_to_var(&modedb[i], &var, 8);
+			intelfbhw_read_hw_state(dinfo, &hw, 0);
+			if (intelfbhw_mode_to_hw(dinfo, &hw, &var)) {
+				DGB_MSG("Failed to set hw for mode %dx%d\n",
+					var.xres, var.yres);
+			} else {
+				DGB_MSG("HW state for mode %dx%d\n",
+					var.xres, var.yres);
+				intelfbhw_print_hw_state(dinfo, &hw);
+			}
+		}
+	}
+#endif
+
+	/* Cursor initialisation */
+	if (dinfo->hwcursor) {
+		init_timer(&dinfo->cursor.timer);
+		dinfo->cursor.timer.function = intelfb_flashcursor;
+		dinfo->cursor.timer.data = (unsigned long)dinfo;
+		dinfo->cursor.state = CM_ERASE;
+		spin_lock_init(&dinfo->DAClock);
+	}
+	
+	if (bailearly == 19)
+		bailout(dinfo);
+
+
+	if (noregister)
+		bailout(dinfo);
+
+	if (register_framebuffer(&(dinfo->info)) < 0) {
+		ERR_MSG("Cannot register framebuffer.\n");
+		cleanup(dinfo);
+		return -ENODEV;
+	}
+
+	dinfo->registered = 1;
+
+	return 0;
+}
+
+static void __devexit
+intelfb_pci_unregister(struct pci_dev *pdev)
+{
+	struct intelfb_info *dinfo = pci_get_drvdata(pdev);
+
+	DBG_MSG("intelfb_pci_unregister\n");
+
+	if (!dinfo)
+		return;
+
+	cleanup(dinfo);
+
+	pci_set_drvdata(pdev, NULL);
+}
+
+/*
+ * A simplified version of fb_find_mode.  The latter doesn't seem to work
+ * too well -- haven't figured out why yet.
+ */
+static int
+intelfb_find_mode(struct fb_var_screeninfo *var,
+		  struct fb_info *info, const char *mode_option,
+		  const struct fb_videomode *db, unsigned int dbsize,
+		  const struct fb_videomode *default_mode,
+		  unsigned int default_bpp)
+{
+	int i;
+	char mname[20] = "", tmp[20] = "", *p, *q;
+	unsigned int bpp = 0;
+
+	DBG_MSG("intelfb_find_mode\n");
+
+	/* Set up defaults */
+	if (!db) {
+		db = modedb;
+		dbsize = sizeof(modedb) / sizeof(*modedb);
+	}
+
+	if (!default_bpp)
+#if defined(FBCON_HAS_CFB8)
+		default_bpp = 8;
+#elif defined(FBCON_HAS_CFB16)
+		default_bpp = 16;
+#elif defined(FBCON_HAS_CFB32)
+		default_bpp = 32;
+#endif
+
+	var->activate = FB_ACTIVATE_TEST;
+	if (mode_option && *mode_option) {
+		if (strlen(mode_option) < sizeof(tmp) - 1) {
+			strcat(tmp, mode_option);
+			q = tmp;
+			p = strsep(&q, "-");
+			strcat(mname, p);
+			if (q) {
+				p = strsep(&q, "@");
+				bpp = simple_strtoul(p, NULL, 10);
+				if (q) {
+					strcat(mname, "@");
+					strcat(mname, q);
+				}
+			}
+		}
+		if (!bpp)
+			bpp = default_bpp;
+		DBG_MSG("Mode is %s, bpp %d\n", mname, bpp);
+	}
+	if (*mname) {
+		for (i = 0; i < dbsize; i++) {
+			if (!strncmp(db[i].name, mname, strlen(mname))) {
+				mode_to_var(&db[i], var, bpp);
+				if (!intelfb_set_var(var, -1, info))
+					return 1;
+			}
+		}
+	}
+
+	if (!default_mode)
+		return 0;
+
+	mode_to_var(default_mode, var, default_bpp);
+	if (!intelfb_set_var(var, -1, info))
+		return 3;
+
+	for (i = 0; i < dbsize; i++) {
+		mode_to_var(&db[i], var, default_bpp);
+		if (!intelfb_set_var(var, -1, info))
+			return 4;
+	}
+
+	return 0;
+}
+
+static __inline__ int
+var_to_refresh(const struct fb_var_screeninfo *var)
+{
+	int xtot = var->xres + var->left_margin + var->right_margin +
+		   var->hsync_len;
+	int ytot = var->yres + var->upper_margin + var->lower_margin +
+		   var->vsync_len;
+
+	return (1000000000 / var->pixclock * 1000 + 500) / xtot / ytot;
+}
+
+/* Various intialisation functions */
+
+static int __devinit
+intelfb_init_disp_var(struct intelfb_info *dinfo)
+{
+	int msrc = 0;
+
+	DBG_MSG("intelfb_init_disp_var\n");
+
+	if (dinfo->fixed_mode) {
+		dinfo->disp.var = dinfo->initial_var;
+		msrc = 5;
+	} else {
+		if (mode) {
+			msrc = intelfb_find_mode(&dinfo->disp.var,
+						 &dinfo->info, mode,
+						 modedb, num_modes, NULL, 0);
+			if (msrc)
+				msrc |= 8;
+		}
+		if (!msrc) {
+			msrc = intelfb_find_mode(&dinfo->disp.var,
+						 &dinfo->info, PREFERRED_MODE,
+						 modedb, num_modes,
+						 &modedb[DFLT_MODE], 0);
+		}
+	}
+
+	if (!msrc) {
+		ERR_MSG("Cannot find a suitable video mode.\n");
+		return 1;
+	}
+
+	INF_MSG("Initial video mode is %dx%d-%d@%d.\n", dinfo->disp.var.xres,
+		dinfo->disp.var.yres, intelfb_var_to_depth(&dinfo->disp.var),
+		var_to_refresh(&dinfo->disp.var));
+
+	DBG_MSG("Initial video mode is from %d.\n", msrc);
+
+	if (dinfo->accel)
+		dinfo->disp.var.accel_flags |= FB_ACCELF_TEXT;
+	else
+		dinfo->disp.var.accel_flags &= ~FB_ACCELF_TEXT;
+
+	return 0;
+}
+
+static void
+intelfb_set_dispsw(struct intelfb_info *dinfo, struct display *disp)
+{
+	DBG_MSG("intelfb_set_dispsw: (bpp is %d)\n", disp->var.bits_per_pixel);
+
+	disp->dispsw_data = NULL;
+	disp->dispsw = NULL;
+
+	switch (disp->var.bits_per_pixel) {
+#ifdef FBCON_HAS_CFB8
+	case 8:
+		break;
+#endif
+#ifdef FBCON_HAS_CFB16
+	case 16:
+		disp->dispsw_data = &dinfo->con_cmap.cfb16;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB32
+	case 32:
+		disp->dispsw_data = &dinfo->con_cmap.cfb32;
+		break;
+#endif
+	default:
+		WRN_MSG("Setting fbcon_dummy renderer (bpp is %d).\n",
+			disp->var.bits_per_pixel);
+		disp->dispsw = &fbcon_dummy;
+	}
+	/* For all supported bpp. */
+	if (!disp->dispsw)
+		disp->dispsw = &fbcon_intelfb;
+}
+
+static int __devinit
+intelfb_init_disp(struct intelfb_info *dinfo)
+{
+	struct fb_info *info;
+	struct display *disp;
+
+	DBG_MSG("intelfb_init_disp\n");
+
+	info = &dinfo->info;
+	disp = &dinfo->disp;
+
+	if (intelfb_init_disp_var(dinfo))
+		return 1;
+
+	info->disp = disp;
+
+	update_dinfo(dinfo, &disp->var, disp);
+
+	intelfb_set_dispsw(dinfo, disp);
+
+	dinfo->currcon_display = disp;
+
+	return 0;
+}
+
+static int __devinit
+intelfb_set_fbinfo(struct intelfb_info *dinfo)
+{
+	struct fb_info *info;
+
+	DBG_MSG("intelfb_set_fbinfo\n");
+
+	info = &dinfo->info;
+
+	strcpy(info->modename, dinfo->name);
+	info->node = NODEV;
+	info->flags = FBINFO_FLAG_DEFAULT;
+	info->fbops = &intel_fb_ops;
+	info->display_fg = NULL;
+	info->changevar = NULL;
+	info->switch_con = intelfb_switch;
+	info->updatevar = intelfb_updatevar;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	info->blank = intelfbhw_do_blank;
+#endif
+
+	if (intelfb_init_disp(dinfo))
+		return 1;
+	return 0;
+}
+
+/* Update dinfo to match the active video mode. */
+static void
+update_dinfo(struct intelfb_info *dinfo, struct fb_var_screeninfo *var,
+	     struct display *disp)
+{
+	DBG_MSG("update_dinfo\n");
+
+	dinfo->bpp = var->bits_per_pixel;
+	dinfo->depth = intelfb_var_to_depth(var);
+	dinfo->xres = var->xres;
+	dinfo->yres = var->xres;
+	dinfo->pixclock = var->pixclock;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+	intelfb_get_fix(&dinfo->info.fix, dinfo->currcon, &dinfo->info);
+#endif
+
+	switch (dinfo->bpp) {
+#ifdef FBCON_HAS_CFB8
+	case 8:
+		dinfo->visual = FB_VISUAL_PSEUDOCOLOR;
+		dinfo->pitch = disp->var.xres_virtual;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB16
+	case 16:
+		dinfo->visual = FB_VISUAL_TRUECOLOR;
+		dinfo->pitch = disp->var.xres_virtual * 2;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB32
+	case 32:
+		dinfo->visual = FB_VISUAL_TRUECOLOR;
+		dinfo->pitch = disp->var.xres_virtual * 4;
+		break;
+#endif
+	}
+
+	/* Make sure the line length is a aligned correctly. */
+	dinfo->pitch = ROUND_UP_TO(dinfo->pitch, STRIDE_ALIGNMENT);
+
+	if (dinfo->fixed_mode)
+		dinfo->pitch = dinfo->initial_pitch;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	disp->screen_base = (char *)dinfo->fb_base;
+	disp->visual = dinfo->visual;
+	disp->line_length = dinfo->pitch;
+	disp->type = FB_TYPE_PACKED_PIXELS;
+	disp->type_aux = 0;
+	disp->ypanstep = 1;
+	disp->ywrapstep = 0;
+#else
+	dinfo->info.screen_base = (char *)dinfo->fb_base;
+	dinfo->info.fix.line_length = dinfo->pitch;
+	dinfo->info.fix.visual = dinfo->visual;
+#endif
+	disp->can_soft_blank = 1;
+	disp->inverse = 0;
+	DBG_MSG("disp->scrollmode is 0x%x\n", disp->scrollmode);
+	if (disp->var.yres_virtual == disp->var.yres &&
+	    !(disp->var.accel_flags & FB_ACCELF_TEXT)) {
+		/* No space for panning. */
+		disp->scrollmode = SCROLL_YREDRAW;
+	} else {
+		disp->scrollmode = __SCROLL_YMOVE;
+	}
+}
+
+/* fbops functions */
+
+static int
+intelfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
+{
+	struct intelfb_info *dinfo = GET_DINFO(info);
+	struct display *disp;
+
+	DBG_MSG("intelfb_get_fix\n");
+
+	disp = GET_DISP(info, con);
+
+	memset(fix, 0, sizeof(*fix));
+	strcpy(fix->id, dinfo->name);
+	fix->smem_start = dinfo->fb_base_phys;
+	fix->smem_len = dinfo->video_ram;
+	fix->type = FB_TYPE_PACKED_PIXELS;
+	fix->type_aux = 0;
+	fix->visual = dinfo->visual;
+	fix->xpanstep = 8;
+	fix->ypanstep = 1;
+	fix->ywrapstep = 0;
+	fix->line_length = dinfo->pitch;
+	fix->mmio_start = dinfo->mmio_base_phys;
+	fix->mmio_len = INTEL_REG_SIZE;
+	fix->accel = FB_ACCEL_NONE;
+	return 0;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+static int
+intelfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
+{
+	struct intelfb_info *dinfo = GET_DINFO(info);
+
+	DBG_MSG("intelfb_get_var\n");
+
+	if (con == -1)
+		*var = dinfo->disp.var;
+	else
+		*var = fb_display[con].var;
+
+	return 0;
+}
+#endif
+
+static int
+intelfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
+{
+	struct display *disp;
+	int change_var = 0;
+	struct fb_var_screeninfo v;
+	struct intelfb_info *dinfo;
+	int ret;
+	static int first = 1;
+
+	DBG_MSG("intelfb_set_var: con is %d, accel_flags is %d\n",
+		con, var->accel_flags);
+
+	dinfo = GET_DINFO(info);
+	disp = GET_DISP(info, con);
+
+	if (intelfbhw_validate_mode(dinfo, con, var) != 0)
+		return -EINVAL;
+	
+	memcpy(&v, var, sizeof(v));
+
+	/* Check for a supported bpp. */
+	if (v.bits_per_pixel <= 8) {
+#ifdef FBCON_HAS_CFB8
+		v.bits_per_pixel = 8;
+#else
+		return -EINVAL;
+#endif
+	} else if (v.bits_per_pixel <= 16) {
+#ifdef FBCON_HAS_CFB16
+		if (v.bits_per_pixel == 16)
+			v.green.length = 6;
+		v.bits_per_pixel = 16;
+#else
+		return -EINVAL;
+#endif
+	} else if (v.bits_per_pixel <= 32) {
+#ifdef FBCON_HAS_CFB32
+		v.bits_per_pixel = 32;
+#else
+		return -EINVAL;
+#endif
+	} else
+		return -EINVAL;
+
+	if (con < 0) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+		info->var = *var;
+#endif
+		return 0;
+	}
+
+
+	change_var = ((disp->var.xres != var->xres) ||
+		      (disp->var.yres != var->yres) ||
+		      (disp->var.xres_virtual != var->xres_virtual) ||
+		      (disp->var.yres_virtual != var->yres_virtual) ||
+		      (disp->var.bits_per_pixel != var->bits_per_pixel) ||
+		      memcmp(&disp->var.red, &var->red, sizeof(var->red)) ||
+		      memcmp(&disp->var.green, &var->green,
+			     sizeof(var->green)) ||
+		      memcmp(&disp->var.blue, &var->blue, sizeof(var->blue)));
+
+	if (dinfo->fixed_mode &&
+	    (change_var ||
+	     var->yres_virtual > dinfo->initial_var.yres_virtual ||
+	     var->yres_virtual < dinfo->initial_var.yres ||
+	     var->xoffset || var->nonstd)) {
+		if (first) {
+			ERR_MSG("Changing the video mode is not supported.\n");
+			first = 0;
+		}
+		return -EINVAL;
+	}
+
+	if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW)
+		return 0;
+
+	switch (intelfb_var_to_depth(&v)) {
+#ifdef FBCON_HAS_CFB8
+	case 8:
+		v.red.offset = v.green.offset = v.blue.offset = 0;
+		v.red.length = v.green.length = v.blue.length = 8;
+		v.transp.offset = v.transp.length = 0;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB16
+	case 15:
+		v.red.offset = 10;
+		v.green.offset = 5;
+		v.blue.offset = 0;
+		v.red.length = v.green.length = v.blue.length = 5;
+		v.transp.offset = v.transp.length = 0;
+		break;
+	case 16:
+		v.red.offset = 11;
+		v.green.offset = 5;
+		v.blue.offset = 0;
+		v.red.length = 5;
+		v.green.length = 6;
+		v.blue.length = 5;
+		v.transp.offset = v.transp.length = 0;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB32
+	case 24:
+		v.red.offset = 16;
+		v.green.offset = 8;
+		v.blue.offset = 0;
+		v.red.length = v.green.length = v.blue.length = 8;
+		v.transp.offset = v.transp.length = 0;
+		break;
+	case 32:
+		v.red.offset = 16;
+		v.green.offset = 8;
+		v.blue.offset = 0;
+		v.red.length = v.green.length = v.blue.length = 8;
+		v.transp.offset = 24;
+		v.transp.length = 8;
+		break;
+#endif
+	}
+
+	if (v.xoffset < 0)
+		v.xoffset = 0;
+	if (v.yoffset < 0)
+		v.yoffset = 0;
+
+	if (v.xoffset > v.xres_virtual - v.xres)
+		v.xoffset = v.xres_virtual - v.xres;
+	if (v.yoffset > v.yres_virtual - v.yres)
+		v.yoffset = v.yres_virtual - v.yres;
+
+	v.red.msb_right = v.green.msb_right = v.blue.msb_right =
+			  v.transp.msb_right = 0;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+	info->var = v;
+#endif
+
+	memcpy(&disp->var, &v, sizeof(v));
+
+	update_dinfo(dinfo, &v, disp);
+
+	intelfb_set_dispsw(dinfo, disp);
+
+	if (change_var) {
+		if (info && info->changevar)
+			info->changevar(con);
+	}
+
+	intelfb_blank(1, info);
+
+#if 0
+	if (dinfo->hwcursor)
+		intelfbhw_cursor_hide(dinfo);
+#endif
+
+	intelfbhw_2d_stop(dinfo);
+
+	if (!dinfo->fixed_mode) {
+		mdelay(100);
+		if ((ret = intelfb_set_mode(dinfo, &v, disp, 1)))
+			return ret;
+
+		mdelay(100);
+	}
+
+	if (dinfo->vc_mode == KD_TEXT) {
+		intelfb_do_install_cmap(con, info);
+
+		if (dinfo->hwcursor) {
+			del_timer(&dinfo->cursor.timer);
+			dinfo->cursor.state = CM_ERASE;
+			if (disp->conp) {
+				intelfbhw_cursor_init(dinfo);
+				intelfbhw_cursor_load(dinfo, disp);
+				dinfo->cursor.redraw = 1;
+			}
+		}
+
+		mdelay(100);
+
+		intelfbhw_2d_start(dinfo);
+#if 0
+		if (dinfo->hwcursor)
+			intelfbhw_cursor_show(dinfo);
+#endif
+
+		if (v.yoffset != 0)
+			intelfbhw_pan_display(&v, con, info);
+	} else {
+		dinfo->cursor.enabled = 0;
+	}
+
+	intelfb_blank(0, info);
+
+	return 0;
+}
+
+static int
+intelfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
+{
+	struct intelfb_info *dinfo = GET_DINFO(info);
+	struct display *disp = GET_DISP(info, con);
+
+	DBG_MSG("intelfb_get_cmap: con = %d, bpp = %d\n", con,
+		disp->var.bits_per_pixel);
+
+	if (con == dinfo->currcon)
+		return fb_get_cmap(cmap, kspc, intelfb_getcolreg, info);
+	else if (disp->cmap.len)
+		fb_copy_cmap(&disp->cmap, cmap, kspc ? 0 : 2);
+	else {
+		int cmap_len = (disp->var.bits_per_pixel > 8) ? 16 : 256;
+		fb_copy_cmap(fb_default_cmap(cmap_len), cmap, kspc ? 0 : 2);
+	}
+	return 0;
+}
+
+static int
+intelfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
+{
+	struct intelfb_info *dinfo = GET_DINFO(info);
+	struct display *disp = GET_DISP(info, con);
+	unsigned int cmap_len;
+	int err;
+
+	DBG_MSG("intelfb_set_cmap: con = %d, bpp = %d\n", con,
+		disp->var.bits_per_pixel);
+
+	cmap_len = (disp->var.bits_per_pixel > 8) ? 16 : 256;
+	if (!disp->cmap.len) {
+		err = fb_alloc_cmap(&disp->cmap, cmap_len, 0);
+		if (err)
+			return err;
+	}
+	if (con == dinfo->currcon)
+		return FB_SET_CMAP(cmap, kspc, intelfb_setcolreg, info);
+	else
+		fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1);
+	
+	return 0;
+}
+
+/* When/if we have our own ioctls. */
+static int
+intelfb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	      unsigned long arg, int con, struct fb_info *info)
+{
+	DBG_MSG("intelfb_ioctl\n");
+	return -EINVAL;
+}
+
+static int
+intelfb_switch(int con, struct fb_info *info)
+{
+	struct intelfb_info *dinfo = GET_DINFO(info);
+	struct display *disp;
+	struct fb_cmap *cmap;
+	int switchmode = 0;
+
+	DBG_MSG("intelfb_switch: con = %d, currcon = %d\n",
+		con, dinfo->currcon);
+
+	disp = GET_DISP(info, con);
+	if (dinfo->currcon >= 0) {
+		cmap = &dinfo->currcon_display->cmap;
+		if (cmap->len)
+			fb_get_cmap(cmap, 1, intelfb_getcolreg, info);
+	}
+
+	switchmode = (con != dinfo->currcon);
+
+	dinfo->currcon = con;
+	dinfo->vc_mode = con >= 0 ? vt_cons[con]->vc_mode : KD_TEXT;
+	dinfo->currcon_display = disp;
+	disp->var.activate = FB_ACTIVATE_NOW;
+
+	if (switchmode) {
+		intelfb_set_var(&disp->var, con, info);
+		intelfb_do_install_cmap(con, info);
+	}
+
+	return 0;
+}
+
+/* Called whenever there's panning. */
+static int
+intelfb_updatevar(int con, struct fb_info *info)
+{
+	struct display *disp = GET_DISP(info, con);
+
+	DBG_MSG("intelfb_updatevar\n");
+
+	if (con < 0)
+		return -EINVAL;
+	else
+		return intelfbhw_pan_display(&disp->var, con, info);
+}
+
+static int
+intelfb_blank(int blank, struct fb_info *info)
+{
+	intelfbhw_do_blank(blank, info);
+	return 0;
+}
+
+static int
+intelfb_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+		  unsigned *blue, unsigned *transp, struct fb_info *info)
+{
+	struct intelfb_info *dinfo = GET_DINFO(info);
+
+#if 0
+	DBG_MSG("intelfb_getcolreg\n");
+#endif
+
+	if (regno > 255)
+		return 1;
+
+	*red = (dinfo->palette[regno].red<<8) | dinfo->palette[regno].red;
+	*green = (dinfo->palette[regno].green<<8) | dinfo->palette[regno].green;
+	*blue = (dinfo->palette[regno].blue<<8) | dinfo->palette[regno].blue;
+	*transp = 0;
+
+	return 0;
+}
+
+static int
+intelfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+		  unsigned blue, unsigned transp, struct fb_info *info)
+{
+	struct intelfb_info *dinfo = GET_DINFO(info);
+
+#if 1
+	DBG_MSG("intelfb_setcolreg: regno %d, depth %d\n", regno, dinfo->depth);
+#endif
+
+	if ((dinfo->depth > 8 && regno > 16) || regno > 255)
+		return 1;
+
+	switch (dinfo->depth) {
+#ifdef FBCON_HAS_CFB8
+	case 8:
+		{
+			red >>= 8;
+			green >>= 8;
+			blue >>= 8;
+
+			dinfo->palette[regno].red = red;
+			dinfo->palette[regno].green = green;
+			dinfo->palette[regno].blue = blue;
+
+			intelfbhw_setcolreg(dinfo, regno, red, green, blue,
+					    transp);
+		}
+		break;
+#endif
+#ifdef FBCON_HAS_CFB16
+	case 15:
+		dinfo->con_cmap.cfb16[regno] = ((red & 0xf800) >>  1) |
+					       ((green & 0xf800) >>  6) |
+					       ((blue & 0xf800) >> 11);
+		break;
+	case 16:
+		dinfo->con_cmap.cfb16[regno] = (red & 0xf800) |
+					       ((green & 0xfc00) >>  5) |
+					       ((blue  & 0xf800) >> 11);
+		break;
+#endif
+#ifdef FBCON_HAS_CFB32
+	case 24:
+		dinfo->con_cmap.cfb32[regno] = ((red & 0xff00) << 8) |
+					       (green & 0xff00) |
+					       ((blue  & 0xff00) >> 8);
+		break;
+	}
+#endif
+	return 0;
+}
+
+/* Convert a mode to a var, also making the bpp a supported value. */
+static void
+mode_to_var(const struct fb_videomode *mode, struct fb_var_screeninfo *var,
+	    u32 bpp)
+{
+	if (!mode || !var)
+		return;
+
+	var->xres = mode->xres;
+	var->yres = mode->yres;
+	var->xres_virtual = mode->xres;
+	var->yres_virtual = mode->yres;
+	var->xoffset = 0;
+	var->yoffset = 0;
+	if (bpp <= 8)
+		var->bits_per_pixel = 8;
+	else if (bpp <= 16) {
+		if (bpp == 16)
+			var->green.length = 6;
+		var->bits_per_pixel = 16;
+	} else if (bpp <= 32)
+		var->bits_per_pixel = 32;
+	else {
+		WRN_MSG("var_to_mode: bad bpp: %d\n", bpp);
+		var->bits_per_pixel = bpp;
+	}
+	var->pixclock = mode->pixclock;
+	var->left_margin = mode->left_margin;
+	var->right_margin = mode->right_margin;
+	var->upper_margin = mode->upper_margin;
+	var->lower_margin = mode->lower_margin;
+	var->hsync_len = mode->hsync_len;
+	var->vsync_len = mode->vsync_len;
+	var->sync = mode->sync;
+	var->vmode = mode->vmode;
+	var->width = -1;
+	var->height = -1;
+}
+
+static int
+intelfb_set_mode(struct intelfb_info *dinfo, struct fb_var_screeninfo *var,
+		 struct display *disp, int blank)
+{
+	struct intelfb_hwstate hw;
+
+	DBG_MSG("intelfb_set_mode (%dx%d-%d)\n", var->xres, var->yres,
+		intelfb_var_to_depth(var));
+
+	memcpy(&hw, &dinfo->save_state, sizeof(hw));
+	if (intelfbhw_mode_to_hw(dinfo, &hw, var))
+		return -EINVAL;
+	intelfbhw_print_hw_state(dinfo, &hw);
+	if (intelfbhw_program_mode(dinfo, &hw, blank))
+		return -EINVAL;
+
+	update_dinfo(dinfo, var, disp);
+
+	return 0;
+}
+
+static void
+intelfb_do_install_cmap(int con, struct fb_info *info)
+{
+	struct intelfb_info *dinfo = GET_DINFO(info);
+	struct display *disp;
+
+	if (con != dinfo->currcon)
+		return;
+
+	disp = GET_DISP(info, con);
+	if (disp->cmap.len)
+		FB_SET_CMAP(&disp->cmap, 1, intelfb_setcolreg, info);
+	else {
+		int size = (disp->var.bits_per_pixel > 8) ? 16 : 256;
+		FB_SET_CMAP(fb_default_cmap(size), 1, intelfb_setcolreg, info);
+	}
+}
+
+static void
+check_vc_mode(struct intelfb_info *dinfo)
+{
+#if VERBOSE > 1
+	DBG_MSG("check_vc_mode\n");
+#endif
+
+	if (dinfo->currcon >= 0) {
+		if (vt_cons[dinfo->currcon]->vc_mode != dinfo->vc_mode) {
+			dinfo->vc_mode = vt_cons[dinfo->currcon]->vc_mode;
+			if (dinfo->vc_mode == KD_GRAPHICS) {
+				DBG_MSG("vc_mode changed to KD_GRAPHICS\n");
+				intelfbhw_2d_stop(dinfo);
+				if (dinfo->cursor.enabled) {
+					intelfbhw_cursor_hide(dinfo);
+					dinfo->cursor.enabled = 1;
+				}
+			} else {
+				DBG_MSG("vc_mode changed to KD_TEXT\n");
+				intelfbhw_2d_start(dinfo);
+#if 0
+				if (dinfo->cursor.enabled)
+					intelfbhw_cursor_show(dinfo);
+#endif
+			}
+		}
+	}
+}
+
+static void
+fbcon_intelfb_setup(struct display *p)
+{
+	struct intelfb_info *dinfo = GET_DINFO(p->fb_info);
+
+	DBG_MSG("fbcon_intelfb_setup: accel: %d bpp: %d\n",
+		TEXT_ACCEL(dinfo, &p->var), p->var.bits_per_pixel);
+
+	switch (p->var.bits_per_pixel) {
+#ifdef FBCON_HAS_CFB8
+	case 8:
+		fbcon_cfb8.setup(p);
+		break;
+#endif
+#ifdef FBCON_HAS_CFB16
+	case 16:
+		fbcon_cfb16.setup(p);
+		break;
+#endif
+#ifdef FBCON_HAS_CFB32
+	case 32:
+		fbcon_cfb32.setup(p);
+		break;
+#endif
+	}
+}
+
+static void
+fbcon_intelfb_bmove(struct display *p, int sy, int sx, int dy, int dx,
+		    int height, int width)
+{
+	struct intelfb_info *dinfo = GET_DINFO(p->fb_info);
+
+#if VERBOSE > 0
+	DBG_MSG("fbcon_intelfb_bmove: accel: %d, bpp: %d\n",
+		TEXT_ACCEL(dinfo, &p->var), p->var.bits_per_pixel);
+#endif
+
+	if (TEXT_ACCEL(dinfo, &p->var)) {
+		intelfbhw_do_bitblt(dinfo, fontwidth(p) * sx,
+				    fontheight(p) * sy,
+				    fontwidth(p) * dx, fontheight(p) * dy,
+				    fontwidth(p) * width,
+				    fontheight(p) * height,
+				    dinfo->pitch, p->var.bits_per_pixel);
+		intelfbhw_do_sync(dinfo);
+		return;
+	}
+
+	/* Non-accel fallback */
+	switch (p->var.bits_per_pixel) {
+#ifdef FBCON_HAS_CFB8
+	case 8:
+		fbcon_cfb8.bmove(p, sy, sx, dy, dx, height, width);
+		break;
+#endif
+#ifdef FBCON_HAS_CFB16
+	case 16:
+		fbcon_cfb16.bmove(p, sy, sx, dy, dx, height, width);
+		break;
+#endif
+#ifdef FBCON_HAS_CFB32
+	case 32:
+		fbcon_cfb32.bmove(p, sy, sx, dy, dx, height, width);
+		break;
+#endif
+	}
+}
+
+static void
+fbcon_intelfb_clear(struct vc_data *conp, struct display *p, int sy, int sx,
+		    int height, int width)
+{
+	struct intelfb_info *dinfo = GET_DINFO(p->fb_info);
+
+#if VERBOSE > 0
+	DBG_MSG("fbcon_intelfb_clear: accel: %d, bpp: %d\n",
+		TEXT_ACCEL(dinfo, &p->var), p->var.bits_per_pixel);
+#endif
+
+	if (TEXT_ACCEL(dinfo, &p->var)) {
+		u32 bg = 0;
+
+		switch (p->var.bits_per_pixel) {
+		case 8:
+			bg = attr_bgcol_ec(p, conp);
+			break;
+		case 16:
+			bg = ((u16 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
+			break;
+		case 32:
+			bg = ((u32 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
+			break;
+		}
+		intelfbhw_do_fillrect(dinfo, fontwidth(p) * sx,
+				      fontheight(p) * sy, fontwidth(p) * width,
+				      fontheight(p) * height, bg, dinfo->pitch,
+				      p->var.bits_per_pixel, PAT_ROP_GXCOPY);
+		intelfbhw_do_sync(dinfo);
+		return;
+	}
+
+	/* Non-accel fallback */
+	switch (p->var.bits_per_pixel) {
+#ifdef FBCON_HAS_CFB8
+	case 8:
+		fbcon_cfb8.clear(conp, p, sy, sx, height, width);
+		break;
+#endif
+#ifdef FBCON_HAS_CFB16
+	case 16:
+		fbcon_cfb16.clear(conp, p, sy, sx, height, width);
+		break;
+#endif
+#ifdef FBCON_HAS_CFB32
+	case 32:
+		fbcon_cfb32.clear(conp, p, sy, sx, height, width);
+		break;
+#endif
+	}
+}
+
+static void
+fbcon_intelfb_putc(struct vc_data *conp, struct display *p, int c,
+		   int yy, int xx)
+{
+	struct intelfb_info *dinfo = GET_DINFO(p->fb_info);
+
+#if VERBOSE > 0
+	DBG_MSG("fbcon_intelfb_putc: accel: %d, bpp: %d\n",
+		TEXT_ACCEL(dinfo, &p->var), p->var.bits_per_pixel);
+#endif
+
+	/* intelfbhw_do_drawglyph() has problems with the 852GM/855GM */
+	if (TEXT_ACCEL(dinfo, &p->var) && USE_DRAWGLYPH(dinfo)) {
+		u32 bg = 0, fg = 0;
+		u8 *cdat;
+		int fw;
+
+		switch (p->var.bits_per_pixel) {
+		case 8:
+			bg = attr_bgcol(p, c);
+			fg = attr_fgcol(p, c);
+			break;
+		case 16:
+			bg = ((u16 *)p->dispsw_data)[attr_bgcol(p, c)];
+			fg = ((u16 *)p->dispsw_data)[attr_fgcol(p, c)];
+			break;
+		case 32:
+			bg = ((u32 *)p->dispsw_data)[attr_bgcol(p, c)];
+			fg = ((u32 *)p->dispsw_data)[attr_fgcol(p, c)];
+			break;
+		}
+
+		fw = ROUND_UP_TO(fontwidth(p), 8) / 8;
+		cdat = p->fontdata + (c & p->charmask) * fontheight(p) * fw;
+
+		if (intelfbhw_do_drawglyph(dinfo, fg, bg, fontwidth(p),
+					   fontheight(p), cdat,
+					   xx * fontwidth(p),
+					   yy * fontheight(p), dinfo->pitch,
+					   p->var.bits_per_pixel)) {
+			intelfbhw_do_sync(dinfo);
+			return;
+		}
+	}
+
+	if (TEXT_ACCEL(dinfo, &p->var))
+		intelfbhw_do_sync(dinfo);
+
+	/* Non-accel fallback */
+	switch (p->var.bits_per_pixel) {
+#ifdef FBCON_HAS_CFB8
+	case 8:
+		fbcon_cfb8.putc(conp, p, c, yy, xx);
+		break;
+#endif
+#ifdef FBCON_HAS_CFB16
+	case 16:
+		fbcon_cfb16.putc(conp, p, c, yy, xx);
+		break;
+#endif
+#ifdef FBCON_HAS_CFB32
+	case 32:
+		fbcon_cfb32.putc(conp, p, c, yy, xx);
+		break;
+#endif
+	}
+}
+
+static void
+fbcon_intelfb_putcs(struct vc_data *conp, struct display *p,
+		    const unsigned short *s, int count, int yy, int xx)
+{
+	struct intelfb_info *dinfo = GET_DINFO(p->fb_info);
+
+#if VERBOSE > 0
+	DBG_MSG("fbcon_intelfb_putcs: accel: %d, bpp: %d, (%d,%d) %d\n",
+		TEXT_ACCEL(dinfo, &p->var), p->var.bits_per_pixel,
+		xx, yy, count);
+#endif
+
+	if (TEXT_ACCEL(dinfo, &p->var) && USE_DRAWGLYPH(dinfo)) {
+		u32 bg = 0, fg = 0;
+		u8 *cdat;
+		int fw;
+		u16 c = scr_readw(s);
+
+		switch (p->var.bits_per_pixel) {
+		case 8:
+			bg = attr_bgcol(p, c);
+			fg = attr_fgcol(p, c);
+			break;
+		case 16:
+			bg = ((u16 *)p->dispsw_data)[attr_bgcol(p, c)];
+			fg = ((u16 *)p->dispsw_data)[attr_fgcol(p, c)];
+			break;
+		case 32:
+			bg = ((u32 *)p->dispsw_data)[attr_bgcol(p, c)];
+			fg = ((u32 *)p->dispsw_data)[attr_fgcol(p, c)];
+			break;
+		}
+		fw = ROUND_UP_TO(fontwidth(p), 8) / 8;
+		while (count--) {
+			cdat = p->fontdata + (scr_readw(s++) & p->charmask) *
+			       fontheight(p) * fw;
+
+			intelfbhw_do_drawglyph(dinfo, fg, bg, fontwidth(p),
+					       fontheight(p), cdat,
+					       xx * fontwidth(p),
+					       yy * fontheight(p),
+					       dinfo->pitch,
+					       p->var.bits_per_pixel);
+			xx++;
+		}
+		intelfbhw_do_sync(dinfo);
+		return;
+	}
+
+	if (TEXT_ACCEL(dinfo, &p->var))
+		intelfbhw_do_sync(dinfo);
+
+	/* Non-accel fallback */
+	switch (p->var.bits_per_pixel) {
+#ifdef FBCON_HAS_CFB8
+	case 8:
+		fbcon_cfb8.putcs(conp, p, s, count, yy, xx);
+		break;
+#endif
+#ifdef FBCON_HAS_CFB16
+	case 16:
+		fbcon_cfb16.putcs(conp, p, s, count, yy, xx);
+		break;
+#endif
+#ifdef FBCON_HAS_CFB32
+	case 32:
+		fbcon_cfb32.putcs(conp, p, s, count, yy, xx);
+		break;
+#endif
+	}
+}
+
+static void
+fbcon_intelfb_revc(struct display *p, int xx, int yy)
+{
+	struct intelfb_info *dinfo = GET_DINFO(p->fb_info);
+
+#if VERBOSE > 0
+	DBG_MSG("fbcon_intelfb_revc: accel: %d, bpp: %d\n",
+		TEXT_ACCEL(dinfo, &p->var), p->var.bits_per_pixel);
+#endif
+
+	if (TEXT_ACCEL(dinfo, &p->var)) {
+		int bpp = p->var.bits_per_pixel;
+		u32 xor_mask = bpp == 8 ? 0x0f : 0xffffffff;
+
+		intelfbhw_do_fillrect(dinfo, xx * fontwidth(p),
+				      yy * fontheight(p), fontwidth(p),
+				      fontheight(p), xor_mask, dinfo->pitch,
+				      bpp, PAT_ROP_GXXOR);
+		intelfbhw_do_sync(dinfo);
+		return;
+	}
+
+	/* Non-accel fallback */
+	switch (p->var.bits_per_pixel) {
+#ifdef FBCON_HAS_CFB8
+	case 8:
+		fbcon_cfb8.revc(p, xx, yy);
+		break;
+#endif
+#ifdef FBCON_HAS_CFB16
+	case 16:
+		fbcon_cfb16.revc(p, xx, yy);
+		break;
+#endif
+#ifdef FBCON_HAS_CFB32
+	case 32:
+		fbcon_cfb32.revc(p, xx, yy);
+		break;
+#endif
+	}
+}
+
+static void
+fbcon_intelfb_clear_margins(struct vc_data *conp, struct display *p,
+			    int bottom_only)
+{
+	struct intelfb_info *dinfo = GET_DINFO(p->fb_info);
+
+#if VERBOSE > 0
+	DBG_MSG("fbcon_intelfb_clear_margins: accel: %d, bpp: %d\n",
+		TEXT_ACCEL(dinfo, &p->var), p->var.bits_per_pixel);
+#endif
+
+	if (TEXT_ACCEL(dinfo, &p->var)) {
+		u32 cw, ch, rw, bh, rs, bs;
+
+		cw = fontwidth(p);
+		ch = fontheight(p);
+		rw = p->var.xres % cw;
+		bh = p->var.yres % ch;
+		rs = p->var.xres - rw;
+		bs = p->var.yres - bh;
+
+		if (!bottom_only && rw) {
+			intelfbhw_do_fillrect(dinfo, p->var.xoffset + rs, 0,
+					      rw, p->var.yres_virtual, 0,
+					      dinfo->pitch,
+					      p->var.bits_per_pixel,
+					      PAT_ROP_GXCOPY);
+		}
+		if (bh) {
+			intelfbhw_do_fillrect(dinfo, p->var.xoffset,
+					      p->var.yoffset + bs, rs, bh, 0,
+					      dinfo->pitch,
+					      p->var.bits_per_pixel,
+					      PAT_ROP_GXCOPY);
+		}
+		if ((!bottom_only && rw) || bh) {
+			intelfbhw_do_sync(dinfo);
+		}
+		return;
+	}
+
+	/* Non-accel fallback */
+	switch (p->var.bits_per_pixel) {
+#ifdef FBCON_HAS_CFB8
+	case 8:
+		fbcon_cfb8.clear_margins(conp, p, bottom_only);
+		break;
+#endif
+#ifdef FBCON_HAS_CFB16
+	case 16:
+		fbcon_cfb16.clear_margins(conp, p, bottom_only);
+		break;
+#endif
+#ifdef FBCON_HAS_CFB32
+	case 32:
+		fbcon_cfb32.clear_margins(conp, p, bottom_only);
+		break;
+#endif
+	}
+}
+
+void
+intelfb_create_cursor_shape(struct intelfb_info *dinfo, struct display *disp)
+{
+	u32 h, cu, cd;
+
+	DBG_MSG("intelfb_create_cursor_shape\n");
+
+	h = fontheight(disp);
+	cd = h;
+	if (cd >= 10)
+		cd --;
+	dinfo->cursor.type = disp->conp->vc_cursor_type & CUR_HWMASK;
+	switch (dinfo->cursor.type) {
+	case CUR_NONE:
+		cu = cd;
+		break;
+	case CUR_UNDERLINE:
+		cu = cd - 2;
+		break;
+	case CUR_LOWER_THIRD:
+		cu = (h * 2) / 3;
+		break;
+	case CUR_LOWER_HALF:
+		cu = h / 2;
+		break;
+	case CUR_TWO_THIRDS:
+		cu = h / 3;
+		break;
+	case CUR_BLOCK:
+	default:
+		cu = 0;
+		cd = h;
+		break;
+	}
+	dinfo->cursor.w = fontwidth(disp);
+	dinfo->cursor.u = cu;
+	dinfo->cursor.d = cd;
+}
+
+static void
+intelfb_flashcursor(unsigned long ptr)
+{
+	struct intelfb_info *dinfo = (struct intelfb_info *)ptr;
+	unsigned long flags;
+
+#if VERBOSE > 2
+	DBG_MSG("intelfb_flashcursor\n");
+#endif
+
+	spin_lock_irqsave(&dinfo->DAClock, flags);
+	if (dinfo->cursor.enabled) {
+		if (dinfo->cursor.on)
+			intelfbhw_cursor_hide(dinfo);
+		else
+			intelfbhw_cursor_show(dinfo);
+		dinfo->cursor.enabled = 1;
+	}
+	dinfo->cursor.timer.expires = jiffies + HZ / 2;
+	add_timer(&dinfo->cursor.timer);
+	spin_unlock_irqrestore(&dinfo->DAClock, flags);
+}
+
+static void
+fbcon_intelfb_cursor(struct display *disp, int mode, int x, int y)
+{
+	unsigned long flags = 0;
+	struct intelfb_info *dinfo = GET_DINFO(disp->fb_info);
+
+#if VERBOSE > 0
+	DBG_MSG("fbcon_intelfb_cursor, mode is %d (%d)\n",
+		mode, dinfo->cursor.state);
+#endif
+
+	/*
+	 * This appears to be the first place that we can detect changes
+	 * in vc_mode.  We need to know this so that acceleration can be
+	 * enabled or disabled so that it won't interfere with an XFree86
+	 * server.
+	 */
+	check_vc_mode(dinfo);
+
+	if (!dinfo->hwcursor) {
+		disp->dispsw->cursor = NULL;
+		fb_con.con_cursor(disp->conp, mode);
+		disp->dispsw->cursor = fbcon_intelfb_cursor;
+		return;
+	}
+
+	if (mode == CM_ERASE) {
+		if (dinfo->cursor.state != CM_ERASE) {
+			spin_lock_irqsave(&dinfo->DAClock, flags);
+			dinfo->cursor.state = CM_ERASE;
+			intelfbhw_cursor_hide(dinfo);
+			del_timer(&dinfo->cursor.timer);
+			spin_unlock_irqrestore(&dinfo->DAClock, flags);
+		}
+		return;
+	}
+	if ((disp->conp->vc_cursor_type & CUR_HWMASK) != dinfo->cursor.type)
+		intelfbhw_cursor_load(dinfo, disp);
+	x *= fontwidth(disp);
+	y *= fontheight(disp);
+	y -= disp->var.yoffset;
+	x -= disp->var.xoffset;
+	spin_lock_irqsave(&dinfo->DAClock, flags);
+	if (x != dinfo->cursor.x || y != dinfo->cursor.y ||
+	    dinfo->cursor.redraw) {
+#if 1
+		intelfbhw_cursor_hide(dinfo);
+#endif
+		intelfbhw_cursor_setcolor(dinfo, 0, 0xffffff);
+		intelfbhw_cursor_setpos(dinfo, x, y);
+	}
+	dinfo->cursor.state = CM_DRAW;
+	mod_timer(&dinfo->cursor.timer, jiffies + HZ / 2);
+	intelfbhw_cursor_show(dinfo);
+	spin_unlock_irqrestore(&dinfo->DAClock, flags);
+}
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/intel/intelfbhw.c linux-2.4.21-pre6/drivers/video/intel/intelfbhw.c
--- linux-2.4.20/drivers/video/intel/intelfbhw.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/intel/intelfbhw.c	2003-03-26 23:48:58.000000000 +0000
@@ -0,0 +1,1778 @@
+/*
+ * intelfb
+ *
+ * Linux framebuffer driver for Intel(R) 865G integrated graphics chips.
+ *
+ * Copyright (C) 2002, 2003 David Dawes <dawes@tungstengraphics.com>
+ *
+ * This driver consists of two parts.  The first part (intelfbdrv.c) provides
+ * the basic fbdev interfaces, is derived in part from the radeonfb and
+ * vesafb drivers, and is covered by the GPL.  The second part (intelfbhw.c)
+ * provides the code to program the hardware.  Most of it is derived from
+ * the i810/i830 XFree86 driver.  The HW-specific code is covered here
+ * under a dual license (GPL and MIT/XFree86 license).
+ *
+ * Author: David Dawes
+ *
+ */
+
+/* $DHD: intelfb/intelfbhw.c,v 1.7 2003/02/06 00:53:11 dawes Exp $ */
+/* $TG$ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/console.h>
+#include <linux/selection.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+#include <linux/kd.h>
+#include <linux/vt_kern.h>
+#include <linux/pagemap.h>
+#include <linux/version.h>
+
+#include <asm/io.h>
+
+#include <video/fbcon.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb32.h>
+
+#include "intelfb.h"
+#include "intelfbhw.h"
+
+int
+intelfbhw_get_chipset(struct pci_dev *pdev, const char **name, int *chipset,
+		      int *mobile)
+{
+	u32 tmp;
+
+	if (!pdev || !name || !chipset || !mobile)
+		return 1;
+
+	switch (pdev->device) {
+	case PCI_DEVICE_ID_INTEL_830M:
+		*name = "Intel(R) 830M";
+		*chipset = INTEL_830M;
+		*mobile = 1;
+		return 0;
+	case PCI_DEVICE_ID_INTEL_845G:
+		*name = "Intel(R) 845G";
+		*chipset = INTEL_845G;
+		*mobile = 0;
+		return 0;
+	case PCI_DEVICE_ID_INTEL_85XGM:
+		tmp = 0;
+		*mobile = 1;
+		pci_read_config_dword(pdev, INTEL_85X_CAPID, &tmp);
+		switch ((tmp >> INTEL_85X_VARIANT_SHIFT) &
+			INTEL_85X_VARIANT_MASK) {
+		case INTEL_VAR_855GME:
+			*name = "Intel(R) 855GME";
+			*chipset = INTEL_855GME;
+			return 0;
+		case INTEL_VAR_855GM:
+			*name = "Intel(R) 855GM";
+			*chipset = INTEL_855GM;
+			return 0;
+		case INTEL_VAR_852GME:
+			*name = "Intel(R) 852GME";
+			*chipset = INTEL_852GME;
+			return 0;
+		case INTEL_VAR_852GM:
+			*name = "Intel(R) 852GM";
+			*chipset = INTEL_852GM;
+			return 0;
+		default:
+			*name = "Intel(R) 852GM/855GM";
+			*chipset = INTEL_85XGM;
+			return 0;
+		}
+		break;
+	case PCI_DEVICE_ID_INTEL_865G:
+		*name = "Intel(R) 865G";
+		*chipset = INTEL_865G;
+		*mobile = 0;
+		return 0;
+	default:
+		return 1;
+	}
+}
+
+int
+intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size,
+		     int *stolen_size)
+{
+	struct pci_dev *bridge_dev;
+	u16 tmp;
+
+	if (!pdev || !aperture_size || !stolen_size)
+		return 1;
+
+	/* Find the bridge device.  It is always 0:0.0 */
+	if (!(bridge_dev = pci_find_slot(0, PCI_DEVFN(0, 0)))) {
+		ERR_MSG("cannot find bridge device\n");
+		return 1;
+	}
+
+	/* Get the fb aperture size and "stolen" memory amount. */
+	tmp = 0;
+	pci_read_config_word(bridge_dev, INTEL_GMCH_CTRL, &tmp);
+	switch (pdev->device) {
+	case PCI_DEVICE_ID_INTEL_830M:
+	case PCI_DEVICE_ID_INTEL_845G:
+		if ((tmp & INTEL_GMCH_MEM_MASK) == INTEL_GMCH_MEM_64M)
+			*aperture_size = MB(64);
+		else
+			*aperture_size = MB(128);
+		switch (tmp & INTEL_830_GMCH_GMS_MASK) {
+		case INTEL_830_GMCH_GMS_STOLEN_512:
+			*stolen_size = KB(512) - KB(132);
+			return 0;
+		case INTEL_830_GMCH_GMS_STOLEN_1024:
+			*stolen_size = MB(1) - KB(132);
+			return 0;
+		case INTEL_830_GMCH_GMS_STOLEN_8192:
+			*stolen_size = MB(8) - KB(132);
+			return 0;
+		case INTEL_830_GMCH_GMS_LOCAL:
+			ERR_MSG("only local memory found\n");
+			return 1;
+		case INTEL_830_GMCH_GMS_DISABLED:
+			ERR_MSG("video memory is disabled\n");
+			return 1;
+		default:
+			ERR_MSG("unexpected GMCH_GMS value: 0x%02x\n",
+				tmp & INTEL_830_GMCH_GMS_MASK);
+			return 1;
+		}
+		break;
+	default:
+		*aperture_size = MB(128);
+		switch (tmp & INTEL_855_GMCH_GMS_MASK) {
+		case INTEL_855_GMCH_GMS_STOLEN_1M:
+			*stolen_size = MB(1) - KB(132);
+			return 0;
+		case INTEL_855_GMCH_GMS_STOLEN_4M:
+			*stolen_size = MB(4) - KB(132);
+			return 0;
+		case INTEL_855_GMCH_GMS_STOLEN_8M:
+			*stolen_size = MB(8) - KB(132);
+			return 0;
+		case INTEL_855_GMCH_GMS_STOLEN_16M:
+			*stolen_size = MB(16) - KB(132);
+			return 0;
+		case INTEL_855_GMCH_GMS_STOLEN_32M:
+			*stolen_size = MB(32) - KB(132);
+			return 0;
+		case INTEL_855_GMCH_GMS_DISABLED:
+			ERR_MSG("video memory is disabled\n");
+			return 0;
+		default:
+			ERR_MSG("unexpected GMCH_GMS value: 0x%02x\n",
+				tmp & INTEL_855_GMCH_GMS_MASK);
+			return 1;
+		}
+	}
+}
+
+const char *
+intelfbhw_check_non_crt(struct intelfb_info *dinfo)
+{
+	if (INREG(LVDS) & PORT_ENABLE)
+		return "LVDS port";
+	else if (INREG(DVOA) & PORT_ENABLE)
+		return "DVO port A";
+	else if (INREG(DVOB) & PORT_ENABLE)
+		return "DVO port B";
+	else if (INREG(DVOC) & PORT_ENABLE)
+		return "DVO port C";
+	else
+		return NULL;
+}
+
+int
+intelfbhw_validate_mode(struct intelfb_info *dinfo, int con,
+			struct fb_var_screeninfo *var)
+{
+	int bytes_per_pixel;
+	int tmp;
+
+	DBG_MSG("intelfbhw_validate_mode\n");
+
+	bytes_per_pixel = var->bits_per_pixel / 8;
+	if (bytes_per_pixel == 3)
+		bytes_per_pixel = 4;
+
+	/* Check if enough video memory. */
+	tmp = var->yres_virtual * var->xres_virtual * bytes_per_pixel;
+	if (tmp > dinfo->video_ram) {
+		if (con >= 0)
+			WRN_MSG("Not enough video ram for mode "
+				"(%d KByte vs %d KByte).\n",
+				BtoKB(tmp), BtoKB(dinfo->video_ram));
+		return 1;
+	}
+
+	/* Check if x/y limits are OK. */
+	if (var->xres - 1 > HACTIVE_MASK) {
+		if (con >= 0)
+			WRN_MSG("X resolution too large (%d vs %d).\n",
+				var->xres, HACTIVE_MASK + 1);
+		return 1;
+	}
+	if (var->yres - 1 > VACTIVE_MASK) {
+		if (con >= 0)
+			WRN_MSG("Y resolution too large (%d vs %d).\n",
+				var->yres, VACTIVE_MASK + 1);
+		return 1;
+	}
+
+	/* Check for interlaced/doublescan modes. */
+	if (var->vmode & FB_VMODE_INTERLACED) {
+		if (con >= 0)
+			WRN_MSG("Mode is interlaced.\n");
+		return 1;
+	}
+	if (var->vmode & FB_VMODE_DOUBLE) {
+		if (con >= 0)
+			WRN_MSG("Mode is double-scan.\n");
+		return 1;
+	}
+
+	/* Check if clock is OK. */
+	tmp = 1000000000 / var->pixclock;
+	if (tmp < MIN_CLOCK) {
+		if (con >= 0)
+			WRN_MSG("Pixel clock is too low (%d MHz vs %d MHz).\n",
+				(tmp + 500) / 1000, MIN_CLOCK / 1000);
+		return 1;
+	}
+	if (tmp > MAX_CLOCK) {
+		if (con >= 0)
+			WRN_MSG("Pixel clock is too high (%d MHz vs %d MHz).\n",
+				(tmp + 500) / 1000, MAX_CLOCK / 1000);
+		return 1;
+	}
+
+	return 0;
+}
+
+int
+intelfbhw_pan_display(struct fb_var_screeninfo *var, int con,
+		      struct fb_info *info)
+{
+	struct intelfb_info *dinfo = GET_DINFO(info);
+	u32 offset, xoffset, yoffset;
+
+	DBG_MSG("intelfbhw_pan_display\n");
+
+	if (con != dinfo->currcon)
+		return 0;
+
+	xoffset = ROUND_DOWN_TO(var->xoffset, 8);
+	yoffset = var->yoffset;
+
+	if ((xoffset + var->xres > var->xres_virtual) ||
+	    (yoffset + var->yres > var->yres_virtual))
+		return EINVAL;
+
+	offset = (yoffset * dinfo->pitch) +
+		 (xoffset * var->bits_per_pixel) / 8;
+
+	OUTREG(DSPABASE, offset);
+
+	return 0;
+}
+
+/* Blank the screen. */
+void
+intelfbhw_do_blank(int blank, struct fb_info *info)
+{
+	struct intelfb_info *dinfo = GET_DINFO(info);
+	u32 tmp;
+
+	DBG_MSG("intelfbhw_do_blank: blank is %d\n", blank);
+
+	/* Turn plane A on or off */
+	tmp = INREG(DSPACNTR);
+	if (blank)
+		tmp &= ~DISPPLANE_PLANE_ENABLE;
+	else
+		tmp |= DISPPLANE_PLANE_ENABLE;
+	OUTREG(DSPACNTR, tmp);
+	/* Flush */
+	tmp = INREG(DSPABASE);
+	OUTREG(DSPABASE, tmp);
+
+	/* Turn off/on the HW cursor */
+#if VERBOSE > 0
+	DBG_MSG("cursor.enabled is %d\n", dinfo->cursor.enabled);
+#endif
+	if (dinfo->cursor.enabled) {
+		if (blank) {
+			intelfbhw_cursor_hide(dinfo);
+		} else {
+			intelfbhw_cursor_show(dinfo);
+		}
+		dinfo->cursor.enabled = 1;
+	}
+	dinfo->cursor.blanked = blank;
+
+	/* Set DPMS level */
+	tmp = INREG(ADPA) & ~ADPA_DPMS_CONTROL_MASK;
+	switch (blank) {
+	case 0:
+	case 1:
+		tmp |= ADPA_DPMS_D0;
+		break;
+	case 2:
+		tmp |= ADPA_DPMS_D1;
+		break;
+	case 3:
+		tmp |= ADPA_DPMS_D2;
+		break;
+	case 4:
+		tmp |= ADPA_DPMS_D3;
+		break;
+	}
+	OUTREG(ADPA, tmp);
+	
+	return;
+}
+
+
+void
+intelfbhw_setcolreg(struct intelfb_info *dinfo, unsigned regno,
+		    unsigned red, unsigned green, unsigned blue,
+		    unsigned transp)
+{
+#if VERBOSE > 1
+	DBG_MSG("intelfbhw_setcolreg: %d: (%d, %d, %d)\n",
+		regno, red, green, blue);
+#endif
+
+	u32 palette_reg = (dinfo->pipe == PIPE_A) ?
+			  PALETTE_A : PALETTE_B;
+
+	OUTREG(palette_reg + (regno << 2), 
+	       (red << PALETTE_8_RED_SHIFT) |
+	       (green << PALETTE_8_GREEN_SHIFT) |
+	       (blue << PALETTE_8_BLUE_SHIFT));
+}
+
+
+int
+intelfbhw_read_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
+			int flag)
+{
+	int i;
+
+	DBG_MSG("intelfbhw_read_hw_state\n");
+
+	if (!hw || !dinfo)
+		return -1;
+
+	/* Read in as much of the HW state as possible. */
+	hw->vga0_divisor = INREG(VGA0_DIVISOR);
+	hw->vga1_divisor = INREG(VGA1_DIVISOR);
+	hw->vga_pd = INREG(VGAPD);
+	hw->dpll_a = INREG(DPLL_A);
+	hw->dpll_b = INREG(DPLL_B);
+	hw->fpa0 = INREG(FPA0);
+	hw->fpa1 = INREG(FPA1);
+	hw->fpb0 = INREG(FPB0);
+	hw->fpb1 = INREG(FPB1);
+
+	if (flag == 1)
+		return flag;
+
+#if 0
+	/* This seems to be a problem with the 852GM/855GM */
+	for (i = 0; i < PALETTE_8_ENTRIES; i++) {
+		hw->palette_a[i] = INREG(PALETTE_A + (i << 2));
+		hw->palette_b[i] = INREG(PALETTE_B + (i << 2));
+	}
+#endif
+
+	if (flag == 2)
+		return flag;
+
+	hw->htotal_a = INREG(HTOTAL_A);
+	hw->hblank_a = INREG(HBLANK_A);
+	hw->hsync_a = INREG(HSYNC_A);
+	hw->vtotal_a = INREG(VTOTAL_A);
+	hw->vblank_a = INREG(VBLANK_A);
+	hw->vsync_a = INREG(VSYNC_A);
+	hw->src_size_a = INREG(SRC_SIZE_A);
+	hw->bclrpat_a = INREG(BCLRPAT_A);
+	hw->htotal_b = INREG(HTOTAL_B);
+	hw->hblank_b = INREG(HBLANK_B);
+	hw->hsync_b = INREG(HSYNC_B);
+	hw->vtotal_b = INREG(VTOTAL_B);
+	hw->vblank_b = INREG(VBLANK_B);
+	hw->vsync_b = INREG(VSYNC_B);
+	hw->src_size_b = INREG(SRC_SIZE_B);
+	hw->bclrpat_b = INREG(BCLRPAT_B);
+
+	if (flag == 3)
+		return flag;
+
+	hw->adpa = INREG(ADPA);
+	hw->dvoa = INREG(DVOA);
+	hw->dvob = INREG(DVOB);
+	hw->dvoc = INREG(DVOC);
+	hw->dvoa_srcdim = INREG(DVOA_SRCDIM);
+	hw->dvob_srcdim = INREG(DVOB_SRCDIM);
+	hw->dvoc_srcdim = INREG(DVOC_SRCDIM);
+	hw->lvds = INREG(LVDS);
+
+	if (flag == 4)
+		return flag;
+
+	hw->pipe_a_conf = INREG(PIPEACONF);
+	hw->pipe_b_conf = INREG(PIPEBCONF);
+	hw->disp_arb = INREG(DISPARB);
+
+	if (flag == 5)
+		return flag;
+
+	hw->cursor_a_control = INREG(CURSOR_A_CONTROL);
+	hw->cursor_b_control = INREG(CURSOR_B_CONTROL);
+	hw->cursor_a_base = INREG(CURSOR_A_BASEADDR);
+	hw->cursor_b_base = INREG(CURSOR_B_BASEADDR);
+
+	if (flag == 6)
+		return flag;
+
+	for (i = 0; i < 4; i++) {
+		hw->cursor_a_palette[i] = INREG(CURSOR_A_PALETTE0 + (i << 2));
+		hw->cursor_b_palette[i] = INREG(CURSOR_B_PALETTE0 + (i << 2));
+	}
+
+	if (flag == 7)
+		return flag;
+
+	hw->cursor_size = INREG(CURSOR_SIZE);
+
+	if (flag == 8)
+		return flag;
+
+	hw->disp_a_ctrl = INREG(DSPACNTR);
+	hw->disp_b_ctrl = INREG(DSPBCNTR);
+	hw->disp_a_base = INREG(DSPABASE);
+	hw->disp_b_base = INREG(DSPBBASE);
+	hw->disp_a_stride = INREG(DSPASTRIDE);
+	hw->disp_b_stride = INREG(DSPBSTRIDE);
+
+	if (flag == 9)
+		return flag;
+
+	hw->vgacntrl = INREG(VGACNTRL);
+
+	if (flag == 10)
+		return flag;
+
+	hw->add_id = INREG(ADD_ID);
+
+	if (flag == 11)
+		return flag;
+
+	for (i = 0; i < 7; i++) {
+		hw->swf0x[i] = INREG(SWF00 + (i << 2));
+		hw->swf1x[i] = INREG(SWF10 + (i << 2));
+		if (i < 3)
+			hw->swf3x[i] = INREG(SWF30 + (i << 2));
+	}
+
+	for (i = 0; i < 8; i++)
+		hw->fence[i] = INREG(FENCE + (i << 2));
+
+	hw->instpm = INREG(INSTPM);
+	hw->mem_mode = INREG(MEM_MODE);
+	hw->fw_blc_0 = INREG(FW_BLC_0);
+	hw->fw_blc_1 = INREG(FW_BLC_1);
+
+	return 0;
+}
+
+
+void
+intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
+{
+#if REGDUMP
+	int i, m1, m2, n, p1, p2;
+
+	DBG_MSG("intelfbhw_print_hw_state\n");
+
+	if (!hw || !dinfo)
+		return;
+	/* Read in as much of the HW state as possible. */
+	printk("hw state dump start\n");
+	printk("	VGA0_DIVISOR:		0x%08x\n", hw->vga0_divisor);
+	printk("	VGA1_DIVISOR:		0x%08x\n", hw->vga1_divisor);
+	printk("	VGAPD: 			0x%08x\n", hw->vga_pd);
+	n = (hw->vga0_divisor >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
+	m1 = (hw->vga0_divisor >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
+	m2 = (hw->vga0_divisor >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
+	if (hw->vga_pd & VGAPD_0_P1_FORCE_DIV2)
+		p1 = 0;
+	else
+		p1 = (hw->vga_pd >> VGAPD_0_P1_SHIFT) & DPLL_P1_MASK;
+	p2 = (hw->vga_pd >> VGAPD_0_P2_SHIFT) & DPLL_P2_MASK;
+	printk("	VGA0: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
+		m1, m2, n, p1, p2);
+	printk("	VGA0: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2));
+	
+	n = (hw->vga1_divisor >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
+	m1 = (hw->vga1_divisor >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
+	m2 = (hw->vga1_divisor >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
+	if (hw->vga_pd & VGAPD_1_P1_FORCE_DIV2)
+		p1 = 0;
+	else
+		p1 = (hw->vga_pd >> VGAPD_1_P1_SHIFT) & DPLL_P1_MASK;
+	p2 = (hw->vga_pd >> VGAPD_1_P2_SHIFT) & DPLL_P2_MASK;
+	printk("	VGA1: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
+		m1, m2, n, p1, p2);
+	printk("	VGA1: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2));
+	
+	printk("	DPLL_A:			0x%08x\n", hw->dpll_a);
+	printk("	DPLL_B:			0x%08x\n", hw->dpll_b);
+	printk("	FPA0:			0x%08x\n", hw->fpa0);
+	printk("	FPA1:			0x%08x\n", hw->fpa1);
+	printk("	FPB0:			0x%08x\n", hw->fpb0);
+	printk("	FPB1:			0x%08x\n", hw->fpb1);
+
+	n = (hw->fpa0 >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
+	m1 = (hw->fpa0 >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
+	m2 = (hw->fpa0 >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
+	if (hw->dpll_a & DPLL_P1_FORCE_DIV2)
+		p1 = 0;
+	else
+		p1 = (hw->dpll_a >> DPLL_P1_SHIFT) & DPLL_P1_MASK;
+	p2 = (hw->dpll_a >> DPLL_P2_SHIFT) & DPLL_P2_MASK;
+	printk("	PLLA0: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
+		m1, m2, n, p1, p2);
+	printk("	PLLA0: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2));
+
+	n = (hw->fpa1 >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
+	m1 = (hw->fpa1 >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
+	m2 = (hw->fpa1 >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
+	if (hw->dpll_a & DPLL_P1_FORCE_DIV2)
+		p1 = 0;
+	else
+		p1 = (hw->dpll_a >> DPLL_P1_SHIFT) & DPLL_P1_MASK;
+	p2 = (hw->dpll_a >> DPLL_P2_SHIFT) & DPLL_P2_MASK;
+	printk("	PLLA1: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
+		m1, m2, n, p1, p2);
+	printk("	PLLA1: clock is %d\n", CALC_VCLOCK(m1, m2, n, p1, p2));
+	
+#if 0
+	printk("	PALETTE_A:\n");
+	for (i = 0; i < PALETTE_8_ENTRIES)
+		printk("	%3d:	0x%08x\n", i, hw->palette_a[i];
+	printk("	PALETTE_B:\n");
+	for (i = 0; i < PALETTE_8_ENTRIES)
+		printk("	%3d:	0x%08x\n", i, hw->palette_b[i];
+#endif
+
+	printk("	HTOTAL_A:		0x%08x\n", hw->htotal_a);
+	printk("	HBLANK_A:		0x%08x\n", hw->hblank_a);
+	printk("	HSYNC_A:		0x%08x\n", hw->hsync_a);
+	printk("	VTOTAL_A:		0x%08x\n", hw->vtotal_a);
+	printk("	VBLANK_A:		0x%08x\n", hw->vblank_a);
+	printk("	VSYNC_A:		0x%08x\n", hw->vsync_a);
+	printk("	SRC_SIZE_A:		0x%08x\n", hw->src_size_a);
+	printk("	BCLRPAT_A:		0x%08x\n", hw->bclrpat_a);
+	printk("	HTOTAL_B:		0x%08x\n", hw->htotal_b);
+	printk("	HBLANK_B:		0x%08x\n", hw->hblank_b);
+	printk("	HSYNC_B:		0x%08x\n", hw->hsync_b);
+	printk("	VTOTAL_B:		0x%08x\n", hw->vtotal_b);
+	printk("	VBLANK_B:		0x%08x\n", hw->vblank_b);
+	printk("	VSYNC_B:		0x%08x\n", hw->vsync_b);
+	printk("	SRC_SIZE_B:		0x%08x\n", hw->src_size_b);
+	printk("	BCLRPAT_B:		0x%08x\n", hw->bclrpat_b);
+
+	printk("	ADPA:			0x%08x\n", hw->adpa);
+	printk("	DVOA:			0x%08x\n", hw->dvoa);
+	printk("	DVOB:			0x%08x\n", hw->dvob);
+	printk("	DVOC:			0x%08x\n", hw->dvoc);
+	printk("	DVOA_SRCDIM:		0x%08x\n", hw->dvoa_srcdim);
+	printk("	DVOB_SRCDIM:		0x%08x\n", hw->dvob_srcdim);
+	printk("	DVOC_SRCDIM:		0x%08x\n", hw->dvoc_srcdim);
+	printk("	LVDS:			0x%08x\n", hw->lvds);
+
+	printk("	PIPEACONF:		0x%08x\n", hw->pipe_a_conf);
+	printk("	PIPEBCONF:		0x%08x\n", hw->pipe_b_conf);
+	printk("	DISPARB:		0x%08x\n", hw->disp_arb);
+
+	printk("	CURSOR_A_CONTROL:	0x%08x\n", hw->cursor_a_control);
+	printk("	CURSOR_B_CONTROL:	0x%08x\n", hw->cursor_b_control);
+	printk("	CURSOR_A_BASEADDR:	0x%08x\n", hw->cursor_a_base);
+	printk("	CURSOR_B_BASEADDR:	0x%08x\n", hw->cursor_b_base);
+
+	printk("	CURSOR_A_PALETTE:	");
+	for (i = 0; i < 4; i++) {
+		printk("0x%08x", hw->cursor_a_palette[i]);
+		if (i < 3)
+			printk(", ");
+	}
+	printk("\n");
+	printk("	CURSOR_B_PALETTE:	");
+	for (i = 0; i < 4; i++) {
+		printk("0x%08x", hw->cursor_b_palette[i]);
+		if (i < 3)
+			printk(", ");
+	}
+	printk("\n");
+
+	printk("	CURSOR_SIZE:		0x%08x\n", hw->cursor_size);
+
+	printk("	DSPACNTR:		0x%08x\n", hw->disp_a_ctrl);
+	printk("	DSPBCNTR:		0x%08x\n", hw->disp_b_ctrl);
+	printk("	DSPABASE:		0x%08x\n", hw->disp_a_base);
+	printk("	DSPBBASE:		0x%08x\n", hw->disp_b_base);
+	printk("	DSPASTRIDE:		0x%08x\n", hw->disp_a_stride);
+	printk("	DSPBSTRIDE:		0x%08x\n", hw->disp_b_stride);
+
+	printk("	VGACNTRL:		0x%08x\n", hw->vgacntrl);
+	printk("	ADD_ID:			0x%08x\n", hw->add_id);
+
+	for (i = 0; i < 7; i++) {
+		printk("	SWF0%d			0x%08x\n", i,
+			hw->swf0x[i]);
+	}
+	for (i = 0; i < 7; i++) {
+		printk("	SWF1%d			0x%08x\n", i,
+			hw->swf1x[i]);
+	}
+	for (i = 0; i < 3; i++) {
+		printk("	SWF3%d			0x%08x\n", i,
+			hw->swf3x[i]);
+	}
+	for (i = 0; i < 8; i++)
+		printk("	FENCE%d			0x%08x\n", i,
+			hw->fence[i]);
+
+	printk("	INSTPM			0x%08x\n", hw->instpm);
+	printk("	MEM_MODE		0x%08x\n", hw->mem_mode);
+	printk("	FW_BLC_0		0x%08x\n", hw->fw_blc_0);
+	printk("	FW_BLC_1		0x%08x\n", hw->fw_blc_1);
+
+	printk("hw state dump end\n");
+#endif
+}
+
+/* Split the M parameter into M1 and M2. */
+static int
+splitm(unsigned int m, unsigned int *retm1, unsigned int *retm2)
+{
+	int m1, m2;
+
+	m1 = (m - 2 - (MIN_M2 + MAX_M2) / 2) / 5 - 2;
+	if (m1 < MIN_M1)
+		m1 = MIN_M1;
+	if (m1 > MAX_M1)
+		m1 = MAX_M1;
+	m2 = m - 5 * (m1 + 2) - 2;
+	if (m2 < MIN_M2 || m2 > MAX_M2 || m2 >= m1) {
+		return 1;
+	} else {
+		*retm1 = (unsigned int)m1;
+		*retm2 = (unsigned int)m2;
+		return 0;
+	}
+}
+
+/* Split the P parameter into P1 and P2. */
+static int
+splitp(unsigned int p, unsigned int *retp1, unsigned int *retp2)
+{
+	int p1, p2;
+
+	if (p % 4 == 0)
+		p2 = 1;
+	else
+		p2 = 0;
+	p1 = (p / (1 << (p2 + 1))) - 2;
+	if (p % 4 == 0 && p1 < MIN_P1) {
+		p2 = 0;
+		p1 = (p / (1 << (p2 + 1))) - 2;
+	}
+	if (p1  < MIN_P1 || p1 > MAX_P1 || (p1 + 2) * (1 << (p2 + 1)) != p) {
+		return 1;
+	} else {
+		*retp1 = (unsigned int)p1;
+		*retp2 = (unsigned int)p2;
+		return 0;
+	}
+}
+
+static int
+calc_pll_params(int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *retp1,
+		u32 *retp2, u32 *retclock)
+{
+	u32 m1, m2, n, p1, p2, n1;
+	u32 f_vco, p, p_best = 0, m, f_out;
+	u32 err_max, err_target, err_best = 10000000;
+	u32 n_best = 0, m_best = 0, f_best, f_err;
+	u32 p_min, p_max, p_inc, div_min, div_max;
+
+	/* Accept 0.5% difference, but aim for 0.1% */
+	err_max = 5 * clock / 1000;
+	err_target = clock / 1000;
+
+	DBG_MSG("Clock is %d\n", clock);
+
+	div_max = MAX_VCO_FREQ / clock;
+	div_min = ROUND_UP_TO(MIN_VCO_FREQ, clock) / clock;
+
+	if (clock <= P_TRANSITION_CLOCK)
+		p_inc = 4;
+	else
+		p_inc = 2;
+	p_min = ROUND_UP_TO(div_min, p_inc);
+	p_max = ROUND_DOWN_TO(div_max, p_inc);
+	if (p_min < MIN_P)
+		p_min = 4;
+	if (p_max > MAX_P)
+		p_max = 128;
+
+	DBG_MSG("p range is %d-%d (%d)\n", p_min, p_max, p_inc);
+
+	p = p_min;
+	do {
+		if (splitp(p, &p1, &p2)) {
+			WRN_MSG("cannot split p = %d\n", p);
+			p += p_inc;
+			continue;
+		}
+		n = MIN_N;
+		f_vco = clock * p;
+
+		do {
+			m = ROUND_UP_TO(f_vco * n, PLL_REFCLK) / PLL_REFCLK;
+			if (m < MIN_M)
+				m = MIN_M;
+			if (m > MAX_M)
+				m = MAX_M;
+			f_out = CALC_VCLOCK3(m, n, p);
+			if (splitm(m, &m1, &m2)) {
+				WRN_MSG("cannot split m = %d\n", m);
+				n++;
+				continue;
+			}
+			if (clock > f_out)
+				f_err = clock - f_out;
+			else
+				f_err = f_out - clock;
+			
+			if (f_err < err_best) {
+				m_best = m;
+				n_best = n;
+				p_best = p;
+				f_best = f_out;
+				err_best = f_err;
+			}
+			n++;
+		} while ((n <= MAX_N) && (f_out >= clock));
+		p += p_inc;
+	} while ((p <= p_max));
+
+	if (!m_best) {
+		WRN_MSG("cannot find parameters for clock %d\n", clock);
+		return 1;
+	}
+	m = m_best;
+	n = n_best;
+	p = p_best;
+	splitm(m, &m1, &m2);
+	splitp(p, &p1, &p2);
+	n1 = n - 2;
+	
+	DBG_MSG("m, n, p: %d (%d,%d), %d (%d), %d (%d,%d), "
+		"f: %d (%d), VCO: %d\n",
+		m, m1, m2, n, n1, p, p1, p2,
+		CALC_VCLOCK3(m, n, p), CALC_VCLOCK(m1, m2, n1, p1, p2),
+		CALC_VCLOCK3(m, n, p) * p);
+	*retm1 = m1;
+	*retm2 = m2;
+	*retn = n1;
+	*retp1 = p1;
+	*retp2 = p2;
+	*retclock = CALC_VCLOCK(m1, m2, n1, p1, p2);
+	
+	return 0;
+}
+
+static __inline__ int
+check_overflow(u32 value, u32 limit, const char *description)
+{
+	if (value > limit) {
+		WRN_MSG("%s value %d exceeds limit %d\n",
+			description, value, limit);
+		return 1;
+	}
+	return 0;
+}
+
+/* It is assumed that hw is filled in with the initial state information. */
+int
+intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
+		     struct fb_var_screeninfo *var)
+{
+	int pipe = PIPE_A;
+	u32 *dpll, *fp0, *fp1;
+	u32 m1, m2, n, p1, p2, clock_target, clock;
+	u32 hsync_start, hsync_end, hblank_start, hblank_end, htotal, hactive;
+	u32 vsync_start, vsync_end, vblank_start, vblank_end, vtotal, vactive;
+	u32 vsync_pol, hsync_pol;
+	u32 *vs, *vb, *vt, *hs, *hb, *ht, *ss, *pipe_conf;
+	struct display *disp;
+
+	DBG_MSG("intelfbhw_mode_to_hw\n");
+
+	disp = GET_DISP(&dinfo->info, dinfo->currcon);
+
+	/* Disable VGA */
+	hw->vgacntrl |= VGA_DISABLE;
+
+	/* Check whether pipe A or pipe B is enabled. */
+	if (hw->pipe_a_conf & PIPECONF_ENABLE)
+		pipe = PIPE_A;
+	else if (hw->pipe_b_conf & PIPECONF_ENABLE)
+		pipe = PIPE_B;
+	
+	/* Set which pipe's registers will be set. */
+	if (pipe == PIPE_B) {
+		dpll = &hw->dpll_b;
+		fp0 = &hw->fpb0;
+		fp1 = &hw->fpb1;
+		hs = &hw->hsync_b;
+		hb = &hw->hblank_b;
+		ht = &hw->htotal_b;
+		vs = &hw->vsync_b;
+		vb = &hw->vblank_b;
+		vt = &hw->vtotal_b;
+		ss = &hw->src_size_b;
+		pipe_conf = &hw->pipe_b_conf;
+	} else {
+		dpll = &hw->dpll_a;
+		fp0 = &hw->fpa0;
+		fp1 = &hw->fpa1;
+		hs = &hw->hsync_a;
+		hb = &hw->hblank_a;
+		ht = &hw->htotal_a;
+		vs = &hw->vsync_a;
+		vb = &hw->vblank_a;
+		vt = &hw->vtotal_a;
+		ss = &hw->src_size_a;
+		pipe_conf = &hw->pipe_a_conf;
+	}
+
+	/* Use ADPA register for sync control. */
+	hw->adpa &= ~ADPA_USE_VGA_HVPOLARITY;
+
+	/* sync polarity */
+	hsync_pol = (var->sync & FB_SYNC_HOR_HIGH_ACT) ?
+			ADPA_SYNC_ACTIVE_HIGH : ADPA_SYNC_ACTIVE_LOW;
+	vsync_pol = (var->sync & FB_SYNC_VERT_HIGH_ACT) ?
+			ADPA_SYNC_ACTIVE_HIGH : ADPA_SYNC_ACTIVE_LOW;
+	hw->adpa &= ~((ADPA_SYNC_ACTIVE_MASK << ADPA_VSYNC_ACTIVE_SHIFT) |
+		      (ADPA_SYNC_ACTIVE_MASK << ADPA_HSYNC_ACTIVE_SHIFT));
+	hw->adpa |= (hsync_pol << ADPA_HSYNC_ACTIVE_SHIFT) |
+		    (vsync_pol << ADPA_VSYNC_ACTIVE_SHIFT);
+
+	/* Connect correct pipe to the analog port DAC */
+	hw->adpa &= ~(PIPE_MASK << ADPA_PIPE_SELECT_SHIFT);
+	hw->adpa |= (pipe << ADPA_PIPE_SELECT_SHIFT);
+
+	/* Set DPMS state to D0 (on) */
+	hw->adpa &= ~ADPA_DPMS_CONTROL_MASK;
+	hw->adpa |= ADPA_DPMS_D0;
+
+	*dpll |= (DPLL_VCO_ENABLE | DPLL_VGA_MODE_DISABLE);
+	*dpll &= ~(DPLL_RATE_SELECT_MASK | DPLL_REFERENCE_SELECT_MASK);
+	*dpll |= (DPLL_REFERENCE_DEFAULT | DPLL_RATE_SELECT_FP0);
+
+	/* Desired clock in kHz */
+	clock_target = 1000000000 / var->pixclock;
+	if (calc_pll_params(clock_target, &m1, &m2, &n, &p1, &p2, &clock)) {
+		WRN_MSG("calc_pll_params failed\n");
+		return 1;
+	}
+
+	/* Check for overflow. */
+	if (check_overflow(p1, DPLL_P1_MASK, "PLL P1 parameter"))
+		return 1;
+	if (check_overflow(p2, DPLL_P2_MASK, "PLL P2 parameter"))
+		return 1;
+	if (check_overflow(m1, FP_DIVISOR_MASK, "PLL M1 parameter"))
+		return 1;
+	if (check_overflow(m2, FP_DIVISOR_MASK, "PLL M2 parameter"))
+		return 1;
+	if (check_overflow(n, FP_DIVISOR_MASK, "PLL N parameter"))
+		return 1;
+
+	*dpll &= ~DPLL_P1_FORCE_DIV2;
+	*dpll &= ~((DPLL_P2_MASK << DPLL_P2_SHIFT) |
+		   (DPLL_P1_MASK << DPLL_P1_SHIFT));
+	*dpll |= (p2 << DPLL_P2_SHIFT) | (p1 << DPLL_P1_SHIFT);
+	*fp0 = (n << FP_N_DIVISOR_SHIFT) |
+	       (m1 << FP_M1_DIVISOR_SHIFT) |
+	       (m2 << FP_M2_DIVISOR_SHIFT);
+	*fp1 = *fp0;
+
+	/* Make sure DVOB and DVOC are disabled for now. */
+	hw->dvob &= ~PORT_ENABLE;
+	hw->dvoc &= ~PORT_ENABLE;
+
+	/* Use display plane A. */
+	hw->disp_a_ctrl |= DISPPLANE_PLANE_ENABLE;
+	hw->disp_a_ctrl &= ~DISPPLANE_GAMMA_ENABLE;
+	hw->disp_a_ctrl &= ~DISPPLANE_PIXFORMAT_MASK;
+	switch (intelfb_var_to_depth(var)) {
+	case 8:
+		hw->disp_a_ctrl |= DISPPLANE_8BPP | DISPPLANE_GAMMA_ENABLE;
+		break;
+	case 15:
+		hw->disp_a_ctrl |= DISPPLANE_15_16BPP;
+		break;
+	case 16:
+		hw->disp_a_ctrl |= DISPPLANE_16BPP;
+		break;
+	case 24:
+		hw->disp_a_ctrl |= DISPPLANE_32BPP_NO_ALPHA;
+		break;
+	}
+	hw->disp_a_ctrl &= ~(PIPE_MASK << DISPPLANE_SEL_PIPE_SHIFT);
+	hw->disp_a_ctrl |= (pipe << DISPPLANE_SEL_PIPE_SHIFT);
+
+	/* Set CRTC registers. */
+	hactive = var->xres;
+	hsync_start = hactive + var->right_margin;
+	hsync_end = hsync_start + var->hsync_len;
+	htotal = hsync_end + var->left_margin;
+	hblank_start = hactive;
+	hblank_end = htotal;
+
+	DBG_MSG("H: act %d, ss %d, se %d, tot %d bs %d, be %d\n",
+		hactive, hsync_start, hsync_end, htotal, hblank_start,
+		hblank_end);
+
+	vactive = var->yres;
+	vsync_start = vactive + var->lower_margin;
+	vsync_end = vsync_start + var->vsync_len;
+	vtotal = vsync_end + var->upper_margin;
+	vblank_start = vactive;
+	vblank_end = vtotal;
+	vblank_end = vsync_end + 1;
+
+	DBG_MSG("V: act %d, ss %d, se %d, tot %d bs %d, be %d\n",
+		vactive, vsync_start, vsync_end, vtotal, vblank_start,
+		vblank_end);
+
+	/* Adjust for register values, and check for overflow. */
+	hactive--;
+	if (check_overflow(hactive, HACTIVE_MASK, "CRTC hactive"))
+		return 1;
+	hsync_start--;
+	if (check_overflow(hsync_start, HSYNCSTART_MASK, "CRTC hsync_start"))
+		return 1;
+	hsync_end--;
+	if (check_overflow(hsync_end, HSYNCEND_MASK, "CRTC hsync_end"))
+		return 1;
+	htotal--;
+	if (check_overflow(htotal, HTOTAL_MASK, "CRTC htotal"))
+		return 1;
+	hblank_start--;
+	if (check_overflow(hblank_start, HBLANKSTART_MASK, "CRTC hblank_start"))
+		return 1;
+	hblank_end--;
+	if (check_overflow(hblank_end, HBLANKEND_MASK, "CRTC hblank_end"))
+		return 1;
+
+	vactive--;
+	if (check_overflow(vactive, VACTIVE_MASK, "CRTC vactive"))
+		return 1;
+	vsync_start--;
+	if (check_overflow(vsync_start, VSYNCSTART_MASK, "CRTC vsync_start"))
+		return 1;
+	vsync_end--;
+	if (check_overflow(vsync_end, VSYNCEND_MASK, "CRTC vsync_end"))
+		return 1;
+	vtotal--;
+	if (check_overflow(vtotal, VTOTAL_MASK, "CRTC vtotal"))
+		return 1;
+	vblank_start--;
+	if (check_overflow(vblank_start, VBLANKSTART_MASK, "CRTC vblank_start"))
+		return 1;
+	vblank_end--;
+	if (check_overflow(vblank_end, VBLANKEND_MASK, "CRTC vblank_end"))
+		return 1;
+
+	*ht = (htotal << HTOTAL_SHIFT) | (hactive << HACTIVE_SHIFT);
+	*hb = (hblank_start << HBLANKSTART_SHIFT) |
+	      (hblank_end << HSYNCEND_SHIFT);
+	*hs = (hsync_start << HSYNCSTART_SHIFT) | (hsync_end << HSYNCEND_SHIFT);
+
+	*vt = (vtotal << VTOTAL_SHIFT) | (vactive << VACTIVE_SHIFT);
+	*vb = (vblank_start << VBLANKSTART_SHIFT) |
+	      (vblank_end << VSYNCEND_SHIFT);
+	*vs = (vsync_start << VSYNCSTART_SHIFT) | (vsync_end << VSYNCEND_SHIFT);
+	*ss = (hactive << SRC_SIZE_HORIZ_SHIFT) |
+	      (vactive << SRC_SIZE_VERT_SHIFT);
+
+	/* Start address and stride. */
+	if (dinfo->pitch)
+		hw->disp_a_stride = dinfo->pitch;
+	else
+		hw->disp_a_stride = var->xres_virtual * var->bits_per_pixel / 8;
+	DBG_MSG("pitch is %d\n", hw->disp_a_stride);
+
+	hw->disp_a_base = hw->disp_a_stride * var->yoffset +
+			  var->xoffset * var->bits_per_pixel / 8;
+
+	/* Check stride alignment. */
+	if (hw->disp_a_stride % STRIDE_ALIGNMENT != 0) {
+		WRN_MSG("display stride %d has bad alignment %d\n",
+			hw->disp_a_stride, STRIDE_ALIGNMENT);
+		return 1;
+	}
+
+	/* Set the palette to 8-bit mode. */
+	*pipe_conf &= ~PIPECONF_GAMMA;
+	return 0;
+}
+
+/* Program a (non-VGA) video mode. */
+int
+intelfbhw_program_mode(struct intelfb_info *dinfo,
+		     const struct intelfb_hwstate *hw, int blank)
+{
+	int pipe = PIPE_A;
+	u32 tmp;
+	const u32 *dpll, *fp0, *fp1, *pipe_conf;
+	const u32 *hs, *ht, *hb, *vs, *vt, *vb, *ss;
+	u32 dpll_reg, fp0_reg, fp1_reg, pipe_conf_reg;
+	u32 hsync_reg, htotal_reg, hblank_reg;
+	u32 vsync_reg, vtotal_reg, vblank_reg;
+	u32 src_size_reg;
+
+	/* Assume single pipe, display plane A, analog CRT. */
+
+	DBG_MSG("intelfbhw_program_mode\n");
+
+	/* Disable VGA */
+	tmp = INREG(VGACNTRL);
+	tmp |= VGA_DISABLE;
+	OUTREG(VGACNTRL, tmp);
+
+	/* Check whether pipe A or pipe B is enabled. */
+	if (hw->pipe_a_conf & PIPECONF_ENABLE)
+		pipe = PIPE_A;
+	else if (hw->pipe_b_conf & PIPECONF_ENABLE)
+		pipe = PIPE_B;
+
+	dinfo->pipe = pipe;
+
+	if (pipe == PIPE_B) {
+		dpll = &hw->dpll_b;
+		fp0 = &hw->fpb0;
+		fp1 = &hw->fpb1;
+		pipe_conf = &hw->pipe_b_conf;
+		hs = &hw->hsync_b;
+		hb = &hw->hblank_b;
+		ht = &hw->htotal_b;
+		vs = &hw->vsync_b;
+		vb = &hw->vblank_b;
+		vt = &hw->vtotal_b;
+		ss = &hw->src_size_b;
+		dpll_reg = DPLL_B;
+		fp0_reg = FPB0;
+		fp1_reg = FPB1;
+		pipe_conf_reg = PIPEBCONF;
+		hsync_reg = HSYNC_B;
+		htotal_reg = HTOTAL_B;
+		hblank_reg = HBLANK_B;
+		vsync_reg = VSYNC_B;
+		vtotal_reg = VTOTAL_B;
+		vblank_reg = VBLANK_B;
+		src_size_reg = SRC_SIZE_B;
+	} else {
+		dpll = &hw->dpll_a;
+		fp0 = &hw->fpa0;
+		fp1 = &hw->fpa1;
+		pipe_conf = &hw->pipe_a_conf;
+		hs = &hw->hsync_a;
+		hb = &hw->hblank_a;
+		ht = &hw->htotal_a;
+		vs = &hw->vsync_a;
+		vb = &hw->vblank_a;
+		vt = &hw->vtotal_a;
+		ss = &hw->src_size_a;
+		dpll_reg = DPLL_A;
+		fp0_reg = FPA0;
+		fp1_reg = FPA1;
+		pipe_conf_reg = PIPEACONF;
+		hsync_reg = HSYNC_A;
+		htotal_reg = HTOTAL_A;
+		hblank_reg = HBLANK_A;
+		vsync_reg = VSYNC_A;
+		vtotal_reg = VTOTAL_A;
+		vblank_reg = VBLANK_A;
+		src_size_reg = SRC_SIZE_A;
+	}
+
+	/* Disable planes A and B. */
+	tmp = INREG(DSPACNTR);
+	tmp &= ~DISPPLANE_PLANE_ENABLE;
+	OUTREG(DSPACNTR, tmp);
+	tmp = INREG(DSPBCNTR);
+	tmp &= ~DISPPLANE_PLANE_ENABLE;
+	OUTREG(DSPBCNTR, tmp);
+
+	/* Wait for vblank.  For now, just wait for a 50Hz cycle (20ms)) */
+	mdelay(20);
+
+	/* Disable Sync */
+	tmp = INREG(ADPA);
+	tmp &= ~ADPA_DPMS_CONTROL_MASK;
+	tmp |= ADPA_DPMS_D3;
+	OUTREG(ADPA, tmp);
+
+	/* turn off pipe */
+	tmp = INREG(pipe_conf_reg);
+	tmp &= ~PIPECONF_ENABLE;
+	OUTREG(pipe_conf_reg, tmp);
+
+	/* turn off PLL */
+	tmp = INREG(dpll_reg);
+	dpll_reg &= ~DPLL_VCO_ENABLE;
+	OUTREG(dpll_reg, tmp);
+
+	/* Set PLL parameters */
+	OUTREG(dpll_reg, *dpll & ~DPLL_VCO_ENABLE);
+	OUTREG(fp0_reg, *fp0);
+	OUTREG(fp1_reg, *fp1);
+
+	/* Set pipe parameters */
+	OUTREG(hsync_reg, *hs);
+	OUTREG(hblank_reg, *hb);
+	OUTREG(htotal_reg, *ht);
+	OUTREG(vsync_reg, *vs);
+	OUTREG(vblank_reg, *vb);
+	OUTREG(vtotal_reg, *vt);
+	OUTREG(src_size_reg, *ss);
+	
+	/* Set ADPA */
+	OUTREG(ADPA, (hw->adpa & ~(ADPA_DPMS_CONTROL_MASK)) | ADPA_DPMS_D3);
+
+	/* Enable PLL */
+	tmp = INREG(dpll_reg);
+	tmp |= DPLL_VCO_ENABLE;
+	OUTREG(dpll_reg, tmp);
+
+	/* Enable pipe */
+	OUTREG(pipe_conf_reg, *pipe_conf | PIPECONF_ENABLE);
+
+	/* Enable sync */
+	tmp = INREG(ADPA);
+	tmp &= ~ADPA_DPMS_CONTROL_MASK;
+	tmp |= ADPA_DPMS_D0;
+	OUTREG(ADPA, tmp);
+
+	/* setup display plane */
+	OUTREG(DSPACNTR, hw->disp_a_ctrl & ~DISPPLANE_PLANE_ENABLE);
+	OUTREG(DSPASTRIDE, hw->disp_a_stride);
+	OUTREG(DSPABASE, hw->disp_a_base);
+
+	/* Enable plane */
+	if (!blank) {
+		tmp = INREG(DSPACNTR);
+		tmp |= DISPPLANE_PLANE_ENABLE;
+		OUTREG(DSPACNTR, tmp);
+		OUTREG(DSPABASE, hw->disp_a_base);
+	}
+
+	return 0;
+}
+
+static int
+wait_ring(struct intelfb_info *dinfo, int n)
+{
+	int i = 0;
+	unsigned long end;
+	u32 last_head = INREG(PRI_RING_HEAD) & RING_HEAD_MASK;
+
+#if 0
+	DBG_MSG("wait_ring: %d\n", n);
+#endif
+
+	end = jiffies + (HZ * 3);
+	while (dinfo->ring_space < n) {
+		dinfo->ring_head = INREG(PRI_RING_HEAD) & RING_HEAD_MASK;
+		dinfo->ring_space = dinfo->ring_head -
+				    (dinfo->ring_tail + RING_MIN_FREE);
+		if (dinfo->ring_space < 0)
+			dinfo->ring_space += dinfo->ring_size;
+		if (dinfo->ring_head != last_head) {
+			end = jiffies + (HZ * 3);
+			last_head = dinfo->ring_head;
+		}
+		i++;
+		if (time_before(end, jiffies)) {
+			WRN_MSG("space: %d wanted %d\n", dinfo->ring_space, n);
+			WRN_MSG("lockup\n");
+			break;
+		}
+		udelay(1);
+	}
+	return i;
+}
+
+void
+intelfbhw_do_sync(struct intelfb_info *dinfo)
+{
+#if USE_SYNC_PAGE
+	u32 newval;
+#endif
+	u32 tmp;
+	int i = 0;
+
+#if VERBOSE > 0
+	DBG_MSG("intelfbhw_do_sync\n");
+#endif
+
+#if USE_SYNC_PAGE
+	/*
+	 * Although doing MI_STORE_DWORD_IMM after the MI_FLUSH is supposed
+	 * to make sure everything is synchronised, there is still some
+	 * mis-ordering of operations when mixing 2D with direct CPU
+	 * writes to the framebuffer.
+	 */
+	newval = readl(dinfo->syncpage_virt);
+	newval++;
+#if VERBOSE > 0
+	DBG_MSG("intelfbhw_do_sync: %d\n", newval);
+#endif
+	START_RING(6);
+	OUT_RING(MI_FLUSH | MI_WRITE_DIRTY_STATE);
+	OUT_RING(MI_NOOP);
+	OUT_RING(MI_STORE_DWORD_IMM);
+	OUT_RING(dinfo->syncpage_phys);
+	OUT_RING(newval);
+	OUT_RING(MI_NOOP);
+	ADVANCE_RING();
+	while ((tmp = readl(dinfo->syncpage_virt)) != newval && i < 10000) {
+		i++;
+		udelay(10);
+	}
+	if (tmp != newval) {
+		DBG_MSG("intelfbhw_do_sync: STORE_DWORD_IMM returns %d "
+			"instead of %d\n", tmp, newval);
+	} else {
+#if VERBOSE > 1
+		DBG_MSG("intelfbhw_do_sync: done in %d iterations\n", i);
+#endif
+	}
+#else
+	/*
+	 * Send a flush, then wait until the ring is empty.  This is what
+	 * the XFree86 driver does, and actually it doesn't seem a lot worse
+	 * than the recommended method (both have problems).
+	 */
+	START_RING(2);
+	OUT_RING(MI_FLUSH | MI_WRITE_DIRTY_STATE);
+	OUT_RING(MI_NOOP);
+	ADVANCE_RING();
+	wait_ring(dinfo, dinfo->ring_size - RING_MIN_FREE);
+	dinfo->ring_space = dinfo->ring_size - RING_MIN_FREE;
+#endif
+}
+
+static void
+refresh_ring(struct intelfb_info *dinfo)
+{
+	DBG_MSG("refresh_ring\n");
+
+	dinfo->ring_head = INREG(PRI_RING_HEAD) & RING_HEAD_MASK;
+	dinfo->ring_tail = INREG(PRI_RING_TAIL) & RING_TAIL_MASK;
+	dinfo->ring_space = dinfo->ring_head -
+			    (dinfo->ring_tail + RING_MIN_FREE);
+	if (dinfo->ring_space < 0)
+		dinfo->ring_space += dinfo->ring_size;
+}
+
+static void
+reset_state(struct intelfb_info *dinfo)
+{
+	int i;
+	u32 tmp;
+
+	DBG_MSG("reset_state\n");
+
+	for (i = 0; i < FENCE_NUM; i++)
+		OUTREG(FENCE + (i << 2), 0);
+
+	/* Flush the ring buffer if it's enabled. */
+	tmp = INREG(PRI_RING_LENGTH);
+	if (tmp & RING_ENABLE) {
+		DBG_MSG("reset_state: ring was enabled\n");
+		refresh_ring(dinfo);
+		intelfbhw_do_sync(dinfo);
+		DO_RING_IDLE();
+	}
+
+	OUTREG(PRI_RING_LENGTH, 0);
+	OUTREG(PRI_RING_HEAD, 0);
+	OUTREG(PRI_RING_TAIL, 0);
+	OUTREG(PRI_RING_START, 0);
+}
+
+/* Stop the 2D engine, and turn off the ring buffer. */
+void
+intelfbhw_2d_stop(struct intelfb_info *dinfo)
+{
+	DBG_MSG("intelfbhw_2d_stop: accel: %d, ring_active: %d\n", dinfo->accel,
+		dinfo->ring_active);
+
+	if (!dinfo->accel)
+		return;
+
+	dinfo->ring_active = 0;
+	reset_state(dinfo);
+}
+
+/*
+ * Enable the ring buffer, and initialise the 2D engine.
+ * It is assumed that the graphics engine has been stopped by previously
+ * calling intelfb_2d_stop().
+ */
+void
+intelfbhw_2d_start(struct intelfb_info *dinfo)
+{
+	DBG_MSG("intelfbhw_2d_start: accel: %d, ring_active: %d\n",
+		dinfo->accel, dinfo->ring_active);
+
+	if (!dinfo->accel)
+		return;
+
+	/* Initialise the primary ring buffer. */
+	OUTREG(PRI_RING_LENGTH, 0);
+	OUTREG(PRI_RING_TAIL, 0);
+	OUTREG(PRI_RING_HEAD, 0);
+
+	OUTREG(PRI_RING_START, dinfo->ring_base_phys & RING_START_MASK);
+	OUTREG(PRI_RING_LENGTH,
+		((dinfo->ring_size - GTT_PAGE_SIZE) & RING_LENGTH_MASK) |
+		RING_NO_REPORT | RING_ENABLE);
+	refresh_ring(dinfo);
+	dinfo->ring_active = 1;
+
+	DBG_MSG("INSTPM was 0x%08x, setting to 0x%08x\n", INREG(INSTPM),
+		0x1f << 16);
+	OUTREG(INSTPM, 0x1f << 16);
+	OUTREG(INSTPM, 0x1f << 16);
+}
+
+/* 2D fillrect (solid fill or invert) */
+void
+intelfbhw_do_fillrect(struct intelfb_info *dinfo, u32 x, u32 y, u32 w, u32 h,
+		      u32 color, u32 pitch, u32 bpp, u32 rop)
+{
+	u32 br00, br09, br13, br14, br16;
+
+#if VERBOSE > 1
+	DBG_MSG("intelfbhw_do_fillrect: (%d,%d) %dx%d, c 0x%06x, p %d bpp %d, "
+		"rop 0x%02x\n", x, y, w, h, color, pitch, bpp, rop);
+#endif
+
+	br00 = COLOR_BLT_CMD;
+	br09 = dinfo->fb_offset + (y * pitch + x * (bpp / 8));
+	br13 = (rop << ROP_SHIFT) | pitch;
+	br14 = (h << HEIGHT_SHIFT) | ((w * bpp / 8) << WIDTH_SHIFT);
+	br16 = color;
+
+	switch (bpp) {
+	case 8:
+		br13 |= COLOR_DEPTH_8;
+		break;
+	case 16:
+		br13 |= COLOR_DEPTH_16;
+		break;
+	case 32:
+		br13 |= COLOR_DEPTH_32;
+		br00 |= WRITE_ALPHA | WRITE_RGB;
+		break;
+	}
+
+	START_RING(6);
+	OUT_RING(br00);
+	OUT_RING(br13);
+	OUT_RING(br14);
+	OUT_RING(br09);
+	OUT_RING(br16);
+	OUT_RING(MI_NOOP);
+	ADVANCE_RING();
+}
+
+void
+intelfbhw_do_bitblt(struct intelfb_info *dinfo, u32 curx, u32 cury,
+		    u32 dstx, u32 dsty, u32 w, u32 h, u32 pitch, u32 bpp)
+{
+	u32 br00, br09, br11, br12, br13, br22, br23, br26;
+
+#if VERBOSE > 0
+	DBG_MSG("intelfbhw_do_bitblt: (%d,%d)->(%d,%d) %dx%d, p %d bpp %d\n",
+		curx, cury, dstx, dsty, w, h, pitch, bpp);
+#endif
+
+	br00 = XY_SRC_COPY_BLT_CMD;
+	br09 = dinfo->fb_offset;
+	br11 = (pitch << PITCH_SHIFT);
+	br12 = dinfo->fb_offset;
+	br13 = (SRC_ROP_GXCOPY << ROP_SHIFT) | (pitch << PITCH_SHIFT);
+	br22 = (dstx << WIDTH_SHIFT) | (dsty << HEIGHT_SHIFT);
+	br23 = ((dstx + w) << WIDTH_SHIFT) |
+	       ((dsty + h) << HEIGHT_SHIFT);
+	br26 = (curx << WIDTH_SHIFT) | (cury << HEIGHT_SHIFT);
+
+	switch (bpp) {
+	case 8:
+		br13 |= COLOR_DEPTH_8;
+		break;
+	case 16:
+		br13 |= COLOR_DEPTH_16;
+		break;
+	case 32:
+		br13 |= COLOR_DEPTH_32;
+		br00 |= WRITE_ALPHA | WRITE_RGB;
+		break;
+	}
+
+	START_RING(8);
+	OUT_RING(br00);
+	OUT_RING(br13);
+	OUT_RING(br22);
+	OUT_RING(br23);
+	OUT_RING(br09);
+	OUT_RING(br26);
+	OUT_RING(br11);
+	OUT_RING(br12);
+	ADVANCE_RING();
+}
+
+int
+intelfbhw_do_drawglyph(struct intelfb_info *dinfo, u32 fg, u32 bg, u32 w, u32 h,
+		       u8* cdat, u32 x, u32 y, u32 pitch, u32 bpp)
+{
+	int i, n = 0, fw_bytes, bytes_per_src_line;
+	int nbytes, ndwords, pad, tmp;
+	u16 *wcdat;
+	u32 *dwcdat;
+	u32 br00, br09, br13, br18, br19, br22, br23;
+
+#if 0
+	DBG_MSG("intelfbhw_do_drawglyph: (%d,%d) %dx%d\n", x, y, w, h);
+#endif
+
+	/* Support fonts up to 32 pixels wide. */
+	if (w > 32)
+		return 0;
+
+	/* Number of bytes required for each cdat scanline. */
+	fw_bytes = ROUND_UP_TO(w, 8) / 8;
+
+	/* Src scanlines are word (16-bit) padded. */
+	bytes_per_src_line = ROUND_UP_TO(fw_bytes, 2);
+
+	/* Total bytes of padded scanline data to write out. */
+	nbytes = h * bytes_per_src_line;
+
+	/*
+	 * Check if the glyph data exceeds the immediate mode limit.
+	 * It would take a large font (1K pixels) to hit this limit.
+	 */
+	if (nbytes > MAX_MONO_IMM_SIZE)
+		return 0;
+
+	/* Src data is packaged a dword (32-bit) at a time. */
+	ndwords = ROUND_UP_TO(nbytes, 4) / 4;
+
+	/* Ring has to be padded to a quad word. */
+	pad = ndwords % 2;
+
+	/* For easy reference of the glyph data in different sized chunks. */
+	wcdat = (u16 *)cdat;
+	dwcdat = (u32 *)cdat;
+
+	tmp = (XY_MONO_SRC_IMM_BLT_CMD & DW_LENGTH_MASK) + ndwords;
+	br00 = (XY_MONO_SRC_IMM_BLT_CMD & ~DW_LENGTH_MASK) | tmp;
+	br09 = dinfo->fb_offset;
+	br13 = (SRC_ROP_GXCOPY << ROP_SHIFT) | (pitch << PITCH_SHIFT);
+	br18 = bg;
+	br19 = fg;
+	br22 = (x << WIDTH_SHIFT) | (y << HEIGHT_SHIFT);
+	br23 = ((x + w) << WIDTH_SHIFT) | ((y + h) << HEIGHT_SHIFT);
+
+	switch (bpp) {
+	case 8:
+		br13 |= COLOR_DEPTH_8;
+		break;
+	case 16:
+		br13 |= COLOR_DEPTH_16;
+		break;
+	case 32:
+		br13 |= COLOR_DEPTH_32;
+		br00 |= WRITE_ALPHA | WRITE_RGB;
+		break;
+	}
+
+#if 0
+	DBG_MSG("ndwords + pad is %d, pad is %d\n", ndwords + pad, pad);
+#endif
+	START_RING(ndwords + pad);
+	OUT_RING(br00);
+	OUT_RING(br13);
+	OUT_RING(br22);
+	OUT_RING(br23);
+	OUT_RING(br09);
+	OUT_RING(br18);
+	OUT_RING(br19);
+	i = h;
+	switch (fw_bytes) {
+	case 1:
+		while (i >= 2) {
+			OUT_RING(cdat[0] | cdat[1] << 16);
+			cdat +=2;
+			i -= 2;
+			n++;
+		}
+		if (i) {
+			OUT_RING(cdat[0]);
+			n++;
+		}
+		break;
+	case 2:
+		while (i >= 2) {
+			OUT_RING(wcdat[0] | wcdat[1] << 16);
+			wcdat += 2;
+			i -= 2;
+			n++;
+		}
+		if (i) {
+			OUT_RING(wcdat[0]);
+			n++;
+		}
+		break;
+	case 3:
+		while (i) {
+			OUT_RING(wcdat[0] | cdat[3] << 16);
+			wcdat += 2;
+			cdat += 4;
+			i--;
+			n++;
+		}
+		break;
+	case 4:
+		while(i) {
+			OUT_RING(dwcdat[0]);
+			i--;
+			n++;
+		}
+	}
+	if (pad) {
+		OUT_RING(MI_NOOP);
+		n++;
+	}
+#if 0
+	DBG_MSG("%d immediate bytes + pad\n", n);
+#endif
+	ADVANCE_RING();
+	return 1;
+}
+
+/* HW cursor functions. */
+void
+intelfbhw_cursor_init(struct intelfb_info *dinfo)
+{
+	u32 tmp;
+
+	DBG_MSG("intelfbhw_cursor_init\n");
+
+	if (!dinfo->cursor_base)
+		return;
+
+	if (dinfo->mobile) {
+		if (!dinfo->cursor_base_real)
+			return;
+		tmp = INREG(CURSOR_A_CONTROL);
+		tmp &= ~(CURSOR_MODE_MASK | CURSOR_MOBILE_GAMMA_ENABLE |
+			 CURSOR_MEM_TYPE_LOCAL |
+			 (1 << CURSOR_PIPE_SELECT_SHIFT));
+		tmp |= CURSOR_MODE_DISABLE;
+		OUTREG(CURSOR_A_CONTROL, tmp);
+		OUTREG(CURSOR_A_BASEADDR, dinfo->cursor_base_real);
+	} else {
+#if 0
+		tmp = INREG(CURSOR_CONTROL);
+		tmp &= ~(CURSOR_FORMAT_MASK | CURSOR_GAMMA_ENABLE |
+			 CURSOR_ENABLE | CURSOR_STRIDE_MASK);
+#endif
+		tmp = CURSOR_FORMAT_3C;
+		OUTREG(CURSOR_CONTROL, tmp);
+		OUTREG(CURSOR_A_BASEADDR, dinfo->cursor_offset);
+		tmp = (64 << CURSOR_SIZE_H_SHIFT) |
+		      (64 << CURSOR_SIZE_V_SHIFT);
+		OUTREG(CURSOR_SIZE, tmp);
+	}
+}
+
+void
+intelfbhw_cursor_hide(struct intelfb_info *dinfo)
+{
+	u32 tmp;
+
+#if VERBOSE > 1
+	DBG_MSG("intelfbhw_cursor_hide\n");
+#endif
+
+	if (!dinfo->cursor_base)
+		return;
+
+	dinfo->cursor.enabled = 0;
+	dinfo->cursor.on = 0;
+	if (dinfo->mobile) {
+		if (!dinfo->cursor_base_real)
+			return;
+		tmp = INREG(CURSOR_A_CONTROL);
+		tmp &= ~CURSOR_MODE_MASK;
+		tmp |= CURSOR_MODE_DISABLE;
+		OUTREG(CURSOR_A_CONTROL, tmp);
+		/* Flush changes */
+		OUTREG(CURSOR_A_BASEADDR, dinfo->cursor_base_real);
+	} else {
+		tmp = INREG(CURSOR_CONTROL);
+		tmp &= ~CURSOR_ENABLE;
+		OUTREG(CURSOR_CONTROL, tmp);
+	}
+}
+
+void
+intelfbhw_cursor_show(struct intelfb_info *dinfo)
+{
+	u32 tmp;
+
+#if VERBOSE > 1
+	DBG_MSG("intelfbhw_cursor_show\n");
+#endif
+
+	if (!dinfo->cursor_base)
+		return;
+
+	dinfo->cursor.on = 1;
+	dinfo->cursor.enabled = 1;
+
+	if (dinfo->cursor.blanked)
+		return;
+
+	if (dinfo->mobile) {
+		if (!dinfo->cursor_base_real)
+			return;
+		tmp = INREG(CURSOR_A_CONTROL);
+		tmp &= ~CURSOR_MODE_MASK;
+		tmp |= CURSOR_MODE_64_4C_AX;
+		OUTREG(CURSOR_A_CONTROL, tmp);
+		/* Flush changes */
+		OUTREG(CURSOR_A_BASEADDR, dinfo->cursor_base_real);
+	} else {
+		tmp = INREG(CURSOR_CONTROL);
+		tmp |= CURSOR_ENABLE;
+		OUTREG(CURSOR_CONTROL, tmp);
+	}
+}
+
+void
+intelfbhw_cursor_setpos(struct intelfb_info *dinfo, int x, int y)
+{
+	u32 tmp;
+
+#if VERBOSE > 1
+	DBG_MSG("intelfbhw_cursor_setpos: (%d, %d)\n", x, y);
+#endif
+
+	/*
+	 * Sets the position.  The coordinates are assumed to already
+	 * have any offset adjusted.  Assume that the cursor is never
+	 * completely off-screen, and that x, y are always >= 0.
+	 */
+
+	if (!dinfo->cursor_base)
+		return;
+
+	tmp = ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT) |
+	      ((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT);
+	OUTREG(CURSOR_A_POSITION, tmp);
+}
+
+void
+intelfbhw_cursor_setcolor(struct intelfb_info *dinfo, u32 bg, u32 fg)
+{
+#if VERBOSE > 1
+	DBG_MSG("intelfbhw_cursor_setcolor\n");
+#endif
+
+	if (!dinfo->cursor_base)
+		return;
+
+	OUTREG(CURSOR_A_PALETTE0, bg & CURSOR_PALETTE_MASK);
+	OUTREG(CURSOR_A_PALETTE1, fg & CURSOR_PALETTE_MASK);
+	OUTREG(CURSOR_A_PALETTE2, fg & CURSOR_PALETTE_MASK);
+	OUTREG(CURSOR_A_PALETTE3, bg & CURSOR_PALETTE_MASK);
+}
+
+void
+intelfbhw_cursor_load(struct intelfb_info *dinfo, struct display *disp)
+{
+	u32 xline, mline;
+	int i;
+
+	DBG_MSG("intelfbhw_cursor_load\n");
+
+	if (!dinfo->cursor_base)
+		return;
+
+	intelfb_create_cursor_shape(dinfo, disp);
+	xline = (1 << dinfo->cursor.w) - 1;
+	mline = ~xline;
+	for (i = 0; i < dinfo->cursor.u; i++) {
+		writel(~0, dinfo->cursor_base + i * 16);
+		writel(~0, dinfo->cursor_base + i * 16 + 4);
+		writel(0, dinfo->cursor_base + i * 16 + 8);
+		writel(0, dinfo->cursor_base + i * 16 + 12);
+	}
+	for (; i < dinfo->cursor.d; i++) {
+		writel(mline, dinfo->cursor_base + i * 16);
+		writel(~0, dinfo->cursor_base + i * 16 + 4);
+		writel(xline, dinfo->cursor_base + i * 16 + 8);
+		writel(0, dinfo->cursor_base + i * 16 + 12);
+	}
+	for (; i < 64; i++) {
+		writel(~0, dinfo->cursor_base + i * 16);
+		writel(~0, dinfo->cursor_base + i * 16 + 4);
+		writel(0, dinfo->cursor_base + i * 16 + 8);
+		writel(0, dinfo->cursor_base + i * 16 + 12);
+	}
+}
+
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/intel/intelfbhw.h linux-2.4.21-pre6/drivers/video/intel/intelfbhw.h
--- linux-2.4.20/drivers/video/intel/intelfbhw.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/intel/intelfbhw.h	2003-03-26 23:49:20.000000000 +0000
@@ -0,0 +1,513 @@
+#ifndef _INTELFBHW_H
+#define _INTELFBHW_H
+
+/* $DHD: intelfb/intelfbhw.h,v 1.3 2003/02/05 20:23:56 dawes Exp $ */
+/* $TG$ */
+
+
+/*** HW-specific data ***/
+
+/* Information about the 852GM/855GM variants */
+#define INTEL_85X_CAPID		0x44
+#define INTEL_85X_VARIANT_MASK		0x7
+#define INTEL_85X_VARIANT_SHIFT		5
+#define INTEL_VAR_855GME		0x0
+#define INTEL_VAR_855GM			0x4
+#define INTEL_VAR_852GME		0x2
+#define INTEL_VAR_852GM			0x5
+
+/*
+ * The Bridge device's PCI config space has information about the
+ * fb aperture size and the amount of pre-reserved memory.
+ */
+#define INTEL_GMCH_CTRL		0x52
+#define INTEL_GMCH_ENABLED		0x4
+#define INTEL_GMCH_MEM_MASK		0x1
+#define INTEL_GMCH_MEM_64M		0x1
+#define INTEL_GMCH_MEM_128M		0
+
+#define INTEL_830_GMCH_GMS_MASK		(0x7 << 4)
+#define INTEL_830_GMCH_GMS_DISABLED	(0x0 << 4)
+#define INTEL_830_GMCH_GMS_LOCAL	(0x1 << 4)
+#define INTEL_830_GMCH_GMS_STOLEN_512	(0x2 << 4)
+#define INTEL_830_GMCH_GMS_STOLEN_1024	(0x3 << 4)
+#define INTEL_830_GMCH_GMS_STOLEN_8192	(0x4 << 4)
+
+#define INTEL_855_GMCH_GMS_MASK		(0x7 << 4)
+#define INTEL_855_GMCH_GMS_DISABLED	(0x0 << 4)
+#define INTEL_855_GMCH_GMS_STOLEN_1M	(0x1 << 4)
+#define INTEL_855_GMCH_GMS_STOLEN_4M	(0x2 << 4)
+#define INTEL_855_GMCH_GMS_STOLEN_8M	(0x3 << 4)
+#define INTEL_855_GMCH_GMS_STOLEN_16M	(0x4 << 4)
+#define INTEL_855_GMCH_GMS_STOLEN_32M	(0x5 << 4)
+
+/* GTT page size */
+#define GTT_PAGE_SIZE		4096
+
+/* HW registers */
+
+/* Fence registers */
+#define FENCE			0x2000
+#define FENCE_NUM			8
+
+/* Primary ring buffer */
+#define PRI_RING_TAIL		0x2030
+#define RING_TAIL_MASK			0x001ffff8
+#define RING_INUSE			0x1
+
+#define PRI_RING_HEAD		0x2034
+#define RING_HEAD_WRAP_MASK		0x7ff
+#define RING_HEAD_WRAP_SHIFT		21
+#define RING_HEAD_MASK			0x001ffffc
+
+#define PRI_RING_START		0x2038
+#define RING_START_MASK			0xfffff000
+
+#define PRI_RING_LENGTH		0x203c
+#define RING_LENGTH_MASK		0x001ff000
+#define RING_REPORT_MASK		(0x3 << 1)
+#define RING_NO_REPORT			(0x0 << 1)
+#define RING_REPORT_64K			(0x1 << 1)
+#define RING_REPORT_4K			(0x2 << 1)
+#define RING_REPORT_128K		(0x3 << 1)
+#define RING_ENABLE			0x1
+
+/*
+ * Tail can't wrap to any closer than RING_MIN_FREE bytes of the head,
+ * and the last RING_MIN_FREE bytes need to be padded with MI_NOOP
+ */
+#define RING_MIN_FREE			64
+
+#define INSTDONE		0x2090
+#define PRI_RING_EMPTY			1
+
+#define INSTPM			0x20c0
+#define SYNC_FLUSH_ENABLE		(1 << 5)
+
+#define MEM_MODE		0x20cc
+
+#define MASK_SHIFT			16
+
+#define FW_BLC_0		0x20d8
+#define FW_DISPA_WM_SHIFT		0
+#define FW_DISPA_WM_MASK		0x3f
+#define FW_DISPA_BL_SHIFT		8
+#define FW_DISPA_BL_MASK		0xf
+#define FW_DISPB_WM_SHIFT		16
+#define FW_DISPB_WM_MASK		0x1f
+#define FW_DISPB_BL_SHIFT		24
+#define FW_DISPB_BL_MASK		0x7
+
+#define FW_BLC_1		0x20dc
+#define FW_DISPC_WM_SHIFT		0
+#define FW_DISPC_WM_MASK		0x1f
+#define FW_DISPC_BL_SHIFT		8
+#define FW_DISPC_BL_MASK		0x7
+
+
+/* PLL registers */
+#define VGA0_DIVISOR		0x06000
+#define VGA1_DIVISOR		0x06004
+#define VGAPD			0x06010
+#define VGAPD_0_P1_SHIFT		0
+#define VGAPD_0_P1_FORCE_DIV2		(1 << 5)
+#define VGAPD_0_P2_SHIFT		7
+#define VGAPD_1_P1_SHIFT		8
+#define VGAPD_1_P1_FORCE_DIV2		(1 << 13)
+#define VGAPD_1_P2_SHIFT		15
+
+#define DPLL_A			0x06014
+#define DPLL_B			0x06018
+#define DPLL_VCO_ENABLE			(1 << 31)
+#define DPLL_2X_CLOCK_ENABLE		(1 << 30)
+#define DPLL_SYNCLOCK_ENABLE		(1 << 29)
+#define DPLL_VGA_MODE_DISABLE		(1 << 28)
+#define DPLL_P2_MASK			1
+#define DPLL_P2_SHIFT			23
+#define DPLL_P1_FORCE_DIV2		(1 << 21)
+#define DPLL_P1_MASK			0x1f
+#define DPLL_P1_SHIFT			16
+#define DPLL_REFERENCE_SELECT_MASK	(0x3 << 13)
+#define DPLL_REFERENCE_DEFAULT		(0x0 << 13)
+#define DPLL_REFERENCE_TVCLK		(0x2 << 13)
+#define DPLL_RATE_SELECT_MASK		(1 << 8)
+#define DPLL_RATE_SELECT_FP0		(0 << 8)
+#define DPLL_RATE_SELECT_FP1		(1 << 8)
+
+#define FPA0			0x06040
+#define FPA1			0x06044
+#define FPB0			0x06048
+#define FPB1			0x0604c
+#define FP_DIVISOR_MASK			0x3f
+#define FP_N_DIVISOR_SHIFT		16
+#define FP_M1_DIVISOR_SHIFT		8
+#define FP_M2_DIVISOR_SHIFT		0
+
+/* PLL parameters (these are for 852GM/855GM/865G, check earlier chips). */
+/* Clock values are in units of kHz */
+#define PLL_REFCLK		48000
+#define MIN_VCO_FREQ		930000
+#define MAX_VCO_FREQ		1400000
+#define MIN_CLOCK		25000
+#define MAX_CLOCK		350000
+#define P_TRANSITION_CLOCK	165000
+#define MIN_M			108
+#define MAX_M			140
+#define MIN_M1			18
+#define MAX_M1			26
+#define MIN_M2			6
+#define MAX_M2			16
+#define MIN_P			4
+#define MAX_P			128
+#define MIN_P1			0
+#define MAX_P1			31
+#define MIN_N			3
+#define MAX_N			16
+
+#define CALC_VCLOCK(m1, m2, n, p1, p2) \
+        ((PLL_REFCLK * (5 * ((m1) + 2) + ((m2) + 2)) / ((n) + 2)) / \
+        (((p1) + 2) * (1 << (p2 + 1))))
+
+#define CALC_VCLOCK3(m, n, p)	((PLL_REFCLK * (m) / (n)) / (p))
+
+/* Two pipes */
+#define PIPE_A			0
+#define PIPE_B			1
+#define PIPE_MASK		1
+
+/* palette registers */
+#define PALETTE_A		0x0a000
+#define PALETTE_B		0x0a800
+#ifndef PALETTE_8_ENTRIES
+#define PALETTE_8_ENTRIES		256
+#endif
+#define PALETTE_8_SIZE			(PALETTE_8_ENTRIES * 4)
+#define PALETTE_10_ENTRIES		128
+#define PALETTE_8_SIZE			(PALETTE_10_ENTRIES * 8)
+#define PALETTE_8_MASK			0xff
+#define PALETTE_8_RED_SHIFT		16
+#define PALETTE_8_GREEN_SHIFT		8
+#define PALETTE_8_BLUE_SHIFT		0
+
+/* CRTC registers */
+#define HTOTAL_A		0x60000
+#define HBLANK_A		0x60004
+#define HSYNC_A			0x60008
+#define VTOTAL_A		0x6000c
+#define VBLANK_A		0x60010
+#define VSYNC_A			0x60014
+#define SRC_SIZE_A		0x6001c
+#define BCLRPAT_A		0x60020
+
+#define HTOTAL_B		0x61000
+#define HBLANK_B		0x61004
+#define HSYNC_B			0x61008
+#define VTOTAL_B		0x6100c
+#define VBLANK_B		0x61010
+#define VSYNC_B			0x61014
+#define SRC_SIZE_B		0x6101c
+#define BCLRPAT_B		0x61020
+
+#define HTOTAL_MASK			0xfff
+#define HTOTAL_SHIFT			16
+#define HACTIVE_MASK			0x7ff
+#define HACTIVE_SHIFT			0
+#define HBLANKEND_MASK			0xfff
+#define HBLANKEND_SHIFT			16
+#define HBLANKSTART_MASK		0xfff
+#define HBLANKSTART_SHIFT		0
+#define HSYNCEND_MASK			0xfff
+#define HSYNCEND_SHIFT			16
+#define HSYNCSTART_MASK			0xfff
+#define HSYNCSTART_SHIFT		0
+#define VTOTAL_MASK			0xfff
+#define VTOTAL_SHIFT			16
+#define VACTIVE_MASK			0x7ff
+#define VACTIVE_SHIFT			0
+#define VBLANKEND_MASK			0xfff
+#define VBLANKEND_SHIFT			16
+#define VBLANKSTART_MASK		0xfff
+#define VBLANKSTART_SHIFT		0
+#define VSYNCEND_MASK			0xfff
+#define VSYNCEND_SHIFT			16
+#define VSYNCSTART_MASK			0xfff
+#define VSYNCSTART_SHIFT		0
+#define SRC_SIZE_HORIZ_MASK		0x7ff
+#define SRC_SIZE_HORIZ_SHIFT		16
+#define SRC_SIZE_VERT_MASK		0x7ff
+#define SRC_SIZE_VERT_SHIFT		0
+
+#define ADPA			0x61100
+#define ADPA_DAC_ENABLE			(1 << 31)
+#define ADPA_DAC_DISABLE		0
+#define ADPA_PIPE_SELECT_SHIFT		30
+#define ADPA_USE_VGA_HVPOLARITY		(1 << 15)
+#define ADPA_SETS_HVPOLARITY		0
+#define ADPA_DPMS_CONTROL_MASK		(0x3 << 10)
+#define ADPA_DPMS_D0			(0x0 << 10)
+#define ADPA_DPMS_D2			(0x1 << 10)
+#define ADPA_DPMS_D1			(0x2 << 10)
+#define ADPA_DPMS_D3			(0x3 << 10)
+#define ADPA_VSYNC_ACTIVE_SHIFT		4
+#define ADPA_HSYNC_ACTIVE_SHIFT		3
+#define ADPA_SYNC_ACTIVE_MASK		1
+#define ADPA_SYNC_ACTIVE_HIGH		1
+#define ADPA_SYNC_ACTIVE_LOW		0
+
+#define DVOA			0x61120
+#define DVOB			0x61140
+#define DVOC			0x61160
+#define LVDS			0x61180
+#define PORT_ENABLE			(1 << 31)
+
+#define DVOA_SRCDIM		0x61124
+#define DVOB_SRCDIM		0x61144
+#define DVOC_SRCDIM		0x61164
+
+#define PIPEACONF		0x70008
+#define PIPEBCONF		0x71008
+#define PIPECONF_ENABLE			(1 << 31)
+#define PIPECONF_DISABLE		0
+#define PIPECONF_DOUBLE_WIDE		(1 << 30)
+#define PIPECONF_SINGLE_WIDE		0
+#define PIPECONF_LOCKED			(1 << 25)
+#define PIPECONF_UNLOCKED		0
+#define PIPECONF_GAMMA			(1 << 24)
+#define PIPECONF_PALETTE		0
+
+#define DISPARB			0x70030
+#define DISPARB_AEND_MASK		0x1ff
+#define DISPARB_AEND_SHIFT		0
+#define DISPARB_BEND_MASK		0x3ff
+#define DISPARB_BEND_SHIFT		9
+
+/* Desktop HW cursor */
+#define CURSOR_CONTROL		0x70080
+#define CURSOR_ENABLE			(1 << 31)
+#define CURSOR_GAMMA_ENABLE		(1 << 30)
+#define CURSOR_STRIDE_MASK		(0x3 << 28)
+#define CURSOR_STRIDE_256		(0x0 << 28)
+#define CURSOR_STRIDE_512		(0x1 << 28)
+#define CURSOR_STRIDE_1K		(0x2 << 28)
+#define CURSOR_STRIDE_2K		(0x3 << 28)
+#define CURSOR_FORMAT_MASK		(0x7 << 24)
+#define CURSOR_FORMAT_2C		(0x0 << 24)
+#define CURSOR_FORMAT_3C		(0x1 << 24)
+#define CURSOR_FORMAT_4C		(0x2 << 24)
+#define CURSOR_FORMAT_ARGB		(0x4 << 24)
+#define CURSOR_FORMAT_XRGB		(0x5 << 24)
+
+/* Mobile HW cursor (and i810) */
+#define CURSOR_A_CONTROL	CURSOR_CONTROL
+#define CURSOR_B_CONTROL	0x700c0
+#define CURSOR_MODE_MASK		0x27
+#define CURSOR_MODE_DISABLE		0
+#define CURSOR_MODE_64_3C		0x04
+#define CURSOR_MODE_64_4C_AX		0x05
+#define CURSOR_MODE_64_4C		0x06
+#define CURSOR_MODE_64_32B_AX		0x07
+#define CURSOR_MODE_64_ARGB_AX		0x27
+#define CURSOR_PIPE_SELECT_SHIFT	28
+#define CURSOR_MOBILE_GAMMA_ENABLE	(1 << 26)
+#define CURSOR_MEM_TYPE_LOCAL		(1 << 25)
+
+/* All platforms (desktop has no pipe B) */
+#define CURSOR_A_BASEADDR	0x70084
+#define CURSOR_B_BASEADDR	0x700c4
+#define CURSOR_BASE_MASK		0xffffff00
+
+#define CURSOR_A_POSITION	0x70088
+#define CURSOR_B_POSITION	0x700c8
+#define CURSOR_POS_SIGN			(1 << 15)
+#define CURSOR_POS_MASK			0x7ff
+#define CURSOR_X_SHIFT			0
+#define CURSOR_Y_SHIFT			16
+
+#define CURSOR_A_PALETTE0	0x70090
+#define CURSOR_A_PALETTE1	0x70094
+#define CURSOR_A_PALETTE2	0x70098
+#define CURSOR_A_PALETTE3	0x7009c
+#define CURSOR_B_PALETTE0	0x700d0
+#define CURSOR_B_PALETTE1	0x700d4
+#define CURSOR_B_PALETTE2	0x700d8
+#define CURSOR_B_PALETTE3	0x700dc
+#define CURSOR_COLOR_MASK			0xff
+#define CURSOR_RED_SHIFT			16
+#define CURSOR_GREEN_SHIFT			8
+#define CURSOR_BLUE_SHIFT			0
+#define CURSOR_PALETTE_MASK			0xffffff
+
+/* Desktop only */
+#define CURSOR_SIZE		0x700a0
+#define CURSOR_SIZE_MASK		0x3ff
+#define CURSOR_SIZE_H_SHIFT		0
+#define CURSOR_SIZE_V_SHIFT		12
+
+#define DSPACNTR		0x70180
+#define DSPBCNTR		0x71180
+#define DISPPLANE_PLANE_ENABLE		(1 << 31)
+#define DISPPLANE_PLANE_DISABLE		0
+#define DISPPLANE_GAMMA_ENABLE		(1<<30)
+#define DISPPLANE_GAMMA_DISABLE		0
+#define DISPPLANE_PIXFORMAT_MASK	(0xf<<26)
+#define DISPPLANE_8BPP			(0x2<<26)
+#define DISPPLANE_15_16BPP		(0x4<<26)
+#define DISPPLANE_16BPP			(0x5<<26)
+#define DISPPLANE_32BPP_NO_ALPHA 	(0x6<<26)
+#define DISPPLANE_32BPP			(0x7<<26)
+#define DISPPLANE_STEREO_ENABLE		(1<<25)
+#define DISPPLANE_STEREO_DISABLE	0
+#define DISPPLANE_SEL_PIPE_SHIFT	24
+#define DISPPLANE_SRC_KEY_ENABLE	(1<<22)
+#define DISPPLANE_SRC_KEY_DISABLE	0
+#define DISPPLANE_LINE_DOUBLE		(1<<20)
+#define DISPPLANE_NO_LINE_DOUBLE	0
+#define DISPPLANE_STEREO_POLARITY_FIRST	0
+#define DISPPLANE_STEREO_POLARITY_SECOND (1<<18)
+/* plane B only */
+#define DISPPLANE_ALPHA_TRANS_ENABLE	(1<<15)
+#define DISPPLANE_ALPHA_TRANS_DISABLE	0
+#define DISPPLANE_SPRITE_ABOVE_DISPLAYA	0
+#define DISPPLANE_SPRITE_ABOVE_OVERLAY	1
+
+#define DSPABASE		0x70184
+#define DSPASTRIDE		0x70188
+
+#define DSPBBASE		0x71184
+#define DSPBSTRIDE		0x71188
+
+#define VGACNTRL		0x71400
+#define VGA_DISABLE			(1 << 31)
+#define VGA_ENABLE			0
+#define VGA_PIPE_SELECT_SHIFT		29
+#define VGA_PALETTE_READ_SELECT		23
+#define VGA_PALETTE_A_WRITE_DISABLE	(1 << 22)
+#define VGA_PALETTE_B_WRITE_DISABLE	(1 << 21)
+#define VGA_LEGACY_PALETTE		(1 << 20)
+#define VGA_6BIT_DAC			0
+#define VGA_8BIT_DAC			(1 << 20)
+
+#define ADD_ID			0x71408
+#define ADD_ID_MASK			0xff
+
+/* BIOS scratch area registers (830M and 845G). */
+#define SWF0			0x71410
+#define SWF1			0x71414
+#define SWF2			0x71418
+#define SWF3			0x7141c
+#define SWF4			0x71420
+#define SWF5			0x71424
+#define SWF6			0x71428
+
+/* BIOS scratch area registers (852GM, 855GM, 865G). */
+#define SWF00			0x70410
+#define SWF01			0x70414
+#define SWF02			0x70418
+#define SWF03			0x7041c
+#define SWF04			0x70420
+#define SWF05			0x70424
+#define SWF06			0x70428
+
+#define SWF10			SWF0
+#define SWF11			SWF1
+#define SWF12			SWF2
+#define SWF13			SWF3
+#define SWF14			SWF4
+#define SWF15			SWF5
+#define SWF16			SWF6
+
+#define SWF30			0x72414
+#define SWF31			0x72418
+#define SWF32			0x7241c
+
+/* Memory Commands */
+#define MI_NOOP			(0x00 << 23)
+#define MI_NOOP_WRITE_ID		(1 << 22)
+#define MI_NOOP_ID_MASK			((1 << 22) - 1)
+
+#define MI_FLUSH		(0x03 << 23)
+#define MI_WRITE_DIRTY_STATE		(1 << 4)
+#define MI_END_SCENE			(1 << 3)
+#define MI_INHIBIT_RENDER_CACHE_FLUSH	(1 << 2)
+#define MI_INVALIDATE_MAP_CACHE		(1 << 0)
+
+#define MI_STORE_DWORD_IMM	((0x20 << 23) | 1)
+
+/* 2D Commands */
+#define COLOR_BLT_CMD		((2 << 29) | (0x40 << 22) | 3)
+#define XY_COLOR_BLT_CMD	((2 << 29) | (0x50 << 22) | 4)
+#define XY_SETUP_CLIP_BLT_CMD	((2 << 29) | (0x03 << 22) | 1)
+#define XY_SRC_COPY_BLT_CMD	((2 << 29) | (0x53 << 22) | 6)
+#define SRC_COPY_BLT_CMD	((2 << 29) | (0x43 << 22) | 4)
+#define XY_MONO_PAT_BLT_CMD	((2 << 29) | (0x52 << 22) | 7)
+#define XY_MONO_SRC_BLT_CMD	((2 << 29) | (0x54 << 22) | 6)
+#define XY_MONO_SRC_IMM_BLT_CMD	((2 << 29) | (0x71 << 22) | 5)
+
+#define DW_LENGTH_MASK			0xff
+
+#define WRITE_ALPHA			(1 << 21)
+#define WRITE_RGB			(1 << 20)
+#define VERT_SEED			(3 << 8)
+#define HORIZ_SEED			(3 << 12)
+
+#define COLOR_DEPTH_8			(0 << 24)
+#define COLOR_DEPTH_16			(1 << 24)
+#define COLOR_DEPTH_32			(3 << 24)
+
+#define SRC_ROP_GXCOPY			0xcc
+#define SRC_ROP_GXXOR			0x66
+
+#define PITCH_SHIFT			0
+#define ROP_SHIFT			16
+#define WIDTH_SHIFT			0
+#define HEIGHT_SHIFT			16
+
+/* in bytes */
+#define MAX_MONO_IMM_SIZE		128
+
+
+/*** Macros ***/
+
+/* I/O macros */
+#define INREG8(addr)		readb(dinfo->mmio_base + (addr))
+#define INREG(addr)		readl(dinfo->mmio_base + (addr))
+#define OUTREG8(addr, val)	writeb((val), dinfo->mmio_base + (addr))
+#define OUTREG(addr, val)	writel((val), dinfo->mmio_base + (addr))
+
+/* Ring buffer macros */
+#define OUT_RING(n)	do {						\
+	writel((n), dinfo->ring_base + dinfo->ring_tail);		\
+	dinfo->ring_tail += 4;						\
+	dinfo->ring_tail &= dinfo->ring_tail_mask;			\
+} while (0)
+
+#define START_RING(n)	do {						\
+	u32 needed;							\
+	needed = (n) * 4;						\
+	if (dinfo->ring_tail + needed >					\
+	    dinfo->ring_tail_mask - RING_MIN_FREE) {			\
+		needed += dinfo->ring_tail_mask + 1 - dinfo->ring_tail;	\
+	}								\
+	if (dinfo->ring_space < needed)					\
+		wait_ring(dinfo, needed);				\
+	dinfo->ring_space -= needed;					\
+	while (needed > (n) * 4) {					\
+		OUT_RING(MI_NOOP);					\
+		needed -= 4;						\
+	}								\
+} while (0)
+
+#define ADVANCE_RING()	do {						\
+	OUTREG(PRI_RING_TAIL, dinfo->ring_tail);			\
+} while (0)
+
+#define DO_RING_IDLE()	do {						\
+	u32 head, tail;							\
+	do {								\
+		head = INREG(PRI_RING_HEAD) & RING_HEAD_MASK;		\
+		tail = INREG(PRI_RING_TAIL) & RING_TAIL_MASK;		\
+		udelay(10);						\
+	} while (head != tail);						\
+} while (0)
+
+#endif /* _INTELFBHW_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/intel/modes.c linux-2.4.21-pre6/drivers/video/intel/modes.c
--- linux-2.4.20/drivers/video/intel/modes.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/intel/modes.c	2003-03-26 23:48:59.000000000 +0000
@@ -0,0 +1,222 @@
+
+/*
+ * THIS FILE IS AUTOMATICALLY GENERATED BY fbmode.pl -- DO NOT EDIT
+ */
+
+static struct fb_videomode modedb[] = {
+    {
+	/* 640x350 @ 85 Hz, 37.9 kHz hsync */
+	"640x350@85", 85, 640, 350, 31746, 96, 32, 60, 32, 64, 3,
+	FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 640x400 @ 85 Hz, 37.9 kHz hsync */
+	"640x400@85", 85, 640, 400, 31746, 96, 32, 41, 1, 64, 3,
+	FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 720x400 @ 85 Hz, 37.9 kHz hsync */
+	"720x400@85", 85, 720, 400, 28169, 108, 36, 42, 1, 72, 3,
+	FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 640x480 @ 60 Hz, 31.5 kHz hsync */
+	"640x480@60", 60, 640, 480, 39683, 48, 16, 33, 10, 96, 2,
+	0, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 640x480 @ 73 Hz, 37.9 kHz hsync */
+	"640x480@73", 73, 640, 480, 31746, 128, 24, 29, 9, 40, 2,
+	0, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 640x480 @ 75 Hz, 37.5 kHz hsync */
+	"640x480@75", 75, 640, 480, 31746, 120, 16, 16, 1, 64, 3,
+	0, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 640x480 @ 85 Hz, 43.3 kHz hsync */
+	"640x480@85", 85, 640, 480, 27778, 80, 56, 25, 1, 56, 3,
+	0, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 800x600 @ 56 Hz, 35.2 kHz hsync */
+	"800x600@56", 56, 800, 600, 27778, 128, 24, 22, 1, 72, 2,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 800x600 @ 60 Hz, 37.9 kHz hsync */
+	"800x600@60", 60, 800, 600, 25000, 88, 40, 23, 1, 128, 4,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 800x600 @ 72 Hz, 48.1 kHz hsync */
+	"800x600@72", 72, 800, 600, 20000, 64, 56, 23, 37, 120, 6,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 800x600 @ 75 Hz, 46.9 kHz hsync */
+	"800x600@75", 75, 800, 600, 20202, 160, 16, 21, 1, 80, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 800x600 @ 85 Hz, 53.7 kHz hsync */
+	"800x600@85", 85, 800, 600, 17762, 152, 32, 27, 1, 64, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1024x768 @ 60 Hz, 48.4 kHz hsync */
+	"1024x768@60", 60, 1024, 768, 15385, 160, 24, 29, 3, 136, 6,
+	0, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1024x768 @ 70 Hz, 56.5 kHz hsync */
+	"1024x768@70", 70, 1024, 768, 13333, 144, 24, 29, 3, 136, 6,
+	0, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1024x768 @ 75 Hz, 60.1 kHz hsync */
+	"1024x768@75", 75, 1024, 768, 12690, 176, 16, 28, 1, 96, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1024x768 @ 85 Hz, 68.7 kHz hsync */
+	"1024x768@85", 85, 1024, 768, 10582, 208, 48, 36, 1, 96, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1152x864 @ 75 Hz, 67.5 kHz hsync */
+	"1152x864@75", 75, 1152, 864, 9259, 256, 64, 32, 1, 128, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1280x960 @ 60 Hz, 60.0 kHz hsync */
+	"1280x960@60", 60, 1280, 960, 9259, 312, 96, 36, 1, 112, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1280x960 @ 85 Hz, 85.9 kHz hsync */
+	"1280x960@85", 85, 1280, 960, 6734, 224, 64, 47, 1, 160, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1280x1024 @ 60 Hz, 64.0 kHz hsync */
+	"1280x1024@60", 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1280x1024 @ 75 Hz, 80.0 kHz hsync */
+	"1280x1024@75", 75, 1280, 1024, 7407, 248, 16, 38, 1, 144, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1280x1024 @ 85 Hz, 91.1 kHz hsync */
+	"1280x1024@85", 85, 1280, 1024, 6349, 224, 64, 44, 1, 160, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1600x1200 @ 60 Hz, 75.0 kHz hsync */
+	"1600x1200@60", 60, 1600, 1200, 6173, 304, 64, 46, 1, 192, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1600x1200 @ 65 Hz, 81.2 kHz hsync */
+	"1600x1200@65", 65, 1600, 1200, 5698, 304, 64, 46, 1, 192, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1600x1200 @ 70 Hz, 87.5 kHz hsync */
+	"1600x1200@70", 70, 1600, 1200, 5291, 304, 64, 46, 1, 192, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1600x1200 @ 75 Hz, 93.8 kHz hsync */
+	"1600x1200@75", 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1600x1200 @ 85 Hz, 106.2 kHz hsync */
+	"1600x1200@85", 85, 1600, 1200, 4357, 304, 64, 46, 1, 192, 3,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1792x1344 @ 60 Hz, 83.7 kHz hsync */
+	"1792x1344@60", 60, 1792, 1344, 4883, 328, 128, 46, 1, 200, 3,
+	FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1792x1344 @ 75 Hz, 106.3 kHz hsync */
+	"1792x1344@75", 75, 1792, 1344, 3831, 352, 96, 69, 1, 216, 3,
+	FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1856x1392 @ 60 Hz, 86.4 kHz hsync */
+	"1856x1392@60", 60, 1856, 1392, 4581, 352, 96, 43, 1, 224, 3,
+	FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1856x1392 @ 75 Hz, 112.5 kHz hsync */
+	"1856x1392@75", 75, 1856, 1392, 3472, 352, 128, 104, 1, 224, 3,
+	FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1920x1440 @ 60 Hz, 90.0 kHz hsync */
+	"1920x1440@60", 60, 1920, 1440, 4274, 344, 128, 56, 1, 208, 3,
+	FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1920x1440 @ 75 Hz, 112.5 kHz hsync */
+	"1920x1440@75", 75, 1920, 1440, 3367, 352, 144, 56, 1, 224, 3,
+	FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 832x624 @ 75 Hz, 49.7 kHz hsync */
+	"832x624@75", 75, 832, 624, 17457, 224, 32, 39, 1, 64, 3,
+	0, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1152x768 @ 55 Hz, 44.2 kHz hsync */
+	"1152x768@55", 55, 1152, 768, 15386, 158, 26, 29, 3, 136, 6,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1400x1050 @ 60 Hz, 64.9 kHz hsync */
+	"1400x1050@60", 60, 1400, 1050, 8197, 240, 88, 18, 2, 152, 12,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1400x1050 @ 75 Hz, 81.5 kHz hsync */
+	"1400x1050@75", 75, 1400, 1050, 6418, 128, 64, 26, 2, 320, 12,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1600x1024 @ 60 Hz, 64.0 kHz hsync */
+	"1600x1024@60", 60, 1600, 1024, 9354, 30, 20, 37, 3, 20, 3,
+	0, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 1920x1440 @ 85 Hz, 128.5 kHz hsync */
+	"1920x1440@85", 85, 1920, 1440, 2930, 368, 152, 68, 1, 216, 3,
+	FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 2048x1536 @ 60 Hz, 95.3 kHz hsync */
+	"2048x1536@60", 60, 2048, 1536, 3746, 376, 152, 49, 1, 224, 3,
+	FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 2048x1536 @ 75 Hz, 120.2 kHz hsync */
+	"2048x1536@75", 75, 2048, 1536, 2937, 392, 168, 63, 1, 224, 3,
+	FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+    {
+	/* 2048x1536 @ 85 Hz, 137.0 kHz hsync */
+	"2048x1536@85", 85, 2048, 1536, 2577, 392, 168, 72, 1, 224, 3,
+	FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    }
+};
+
+static int num_modes = sizeof(modedb) / sizeof(modedb[0]);
+
+#define DFLT_MODE 3
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/matrox/Makefile linux-2.4.21-pre6/drivers/video/matrox/Makefile
--- linux-2.4.20/drivers/video/matrox/Makefile	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/matrox/Makefile	2003-03-26 23:49:19.000000000 +0000
@@ -7,16 +7,17 @@
 # All of the (potential) objects that export symbols.
 # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
 
-export-objs    :=  matroxfb_base.o matroxfb_accel.o matroxfb_DAC1064.o matroxfb_Ti3026.o matroxfb_misc.o g450_pll.o
+export-objs    :=  matroxfb_base.o matroxfb_accel.o matroxfb_DAC1064.o matroxfb_Ti3026.o matroxfb_misc.o g450_pll.o matroxfb_g450.o
 
 # Each configuration option enables a list of files.
 
 my-obj-$(CONFIG_FB_MATROX_G100)	  := g450_pll.o
+my-obj-$(CONFIG_FB_MATROX_G450)   += matroxfb_g450.o matroxfb_crtc2.o
 
 obj-$(CONFIG_FB_MATROX)           += matroxfb_base.o matroxfb_accel.o matroxfb_DAC1064.o matroxfb_Ti3026.o matroxfb_misc.o $(my-obj-y)
 obj-$(CONFIG_FB_MATROX_I2C)       += i2c-matroxfb.o
 obj-$(CONFIG_FB_MATROX_MAVEN)     += matroxfb_maven.o matroxfb_crtc2.o
-obj-$(CONFIG_FB_MATROX_G450)	  += matroxfb_g450.o matroxfb_crtc2.o
+obj-$(CONFIG_FB_MATROX_PROC)	  += matroxfb_proc.o
 
 include $(TOPDIR)/Rules.make
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/matrox/g450_pll.c linux-2.4.21-pre6/drivers/video/matrox/g450_pll.c
--- linux-2.4.20/drivers/video/matrox/g450_pll.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/matrox/g450_pll.c	2003-03-26 23:49:40.000000000 +0000
@@ -2,11 +2,11 @@
  *
  * Hardware accelerated Matrox PCI cards - G450/G550 PLL control.
  *
- * (c) 2001 Petr Vandrovec <vandrove@vc.cvut.cz>
+ * (c) 2001-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
  *
  * Portions Copyright (c) 2001 Matrox Graphics Inc.
  *
- * Version: 1.62 2001/11/29
+ * Version: 1.64 2002/06/10
  *
  * 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
@@ -33,6 +33,10 @@
 	return (ACCESS_FBINFO(features).pll.ref_freq * n + (m >> 1)) / m;
 }
 
+unsigned int g450_mnp2f(CPMINFO unsigned int mnp) {
+	return g450_vco2f(mnp, g450_mnp2vco(PMINFO mnp));
+}
+
 static inline unsigned int pll_freq_delta(unsigned int f1, unsigned int f2) {
 	if (f2 < f1) {
     		f2 = f1 - f2;
@@ -52,40 +56,42 @@
 	m = (mnp >> 16) & 0xFF;
 	p = mnp & 0xFF;
 
-	if (m == 0 || m == 0xFF) {
-		if (m == 0) {
-			if (p & 0x40) {
-				return NO_MORE_MNP;
+	do {
+		if (m == 0 || m == 0xFF) {
+			if (m == 0) {
+				if (p & 0x40) {
+					return NO_MORE_MNP;
+				}
+			        if (p & 3) {
+					p--;
+				} else {
+					p = 0x40;
+				}
+				tvco >>= 1;
+				if (tvco < pi->vcomin) {
+					return NO_MORE_MNP;
+				}
+				*fvco = tvco;
 			}
-		        if (p & 3) {
-				p--;
+
+			p &= 0x43;
+			if (tvco < 550000) {
+/*				p |= 0x00; */
+			} else if (tvco < 700000) {
+				p |= 0x08;
+			} else if (tvco < 1000000) {
+				p |= 0x10;
+			} else if (tvco < 1150000) {
+				p |= 0x18;
 			} else {
-				p = 0x40;
+				p |= 0x20;
 			}
-			tvco >>= 1;
-			if (tvco < pi->vcomin) {
-				return NO_MORE_MNP;
-			}
-			*fvco = tvco;
-		}
-
-		p &= 0x43;
-		if (tvco < 550000) {
-/*			p |= 0x00; */
-		} else if (tvco < 700000) {
-			p |= 0x08;
-		} else if (tvco < 1000000) {
-			p |= 0x10;
-		} else if (tvco < 1150000) {
-			p |= 0x18;
+			m = 9;
 		} else {
-			p |= 0x20;
+			m--;
 		}
-		m = 9;
-	} else {
-		m--;
-	}
-        n = ((tvco * (m+1) + ACCESS_FBINFO(features).pll.ref_freq) / (ACCESS_FBINFO(features).pll.ref_freq * 2)) - 2;
+        	n = ((tvco * (m+1) + ACCESS_FBINFO(features).pll.ref_freq) / (ACCESS_FBINFO(features).pll.ref_freq * 2)) - 2;
+	} while (n < 0x03 || n > 0x7A);
 	return (m << 16) | (n << 8) | p;
 }
 
@@ -219,7 +225,7 @@
 	}
 }
 
-static inline void g450_setpll_cond(WPMINFO unsigned int mnp, unsigned int pll) {
+void matroxfb_g450_setpll_cond(WPMINFO unsigned int mnp, unsigned int pll) {
 	if (g450_cmppll(PMINFO mnp, pll)) {
 		g450_setpll(PMINFO mnp, pll);
 	}
@@ -385,10 +391,8 @@
 			unsigned int vco;
 			unsigned int delta;
 
-			if ((mnp & 0xFF00) < 0x0300 || (mnp & 0xFF00) > 0x7A00) {
-				continue;
-			}
 			vco = g450_mnp2vco(PMINFO mnp);
+#if 0			
 			if (pll == M_VIDEO_PLL) {
 				unsigned int big, small;
 
@@ -406,6 +410,7 @@
 					continue;
 				}
 			}
+#endif			
 			delta = pll_freq_delta(fout, g450_vco2f(mnp, vco));
 			for (idx = mnpcount; idx > 0; idx--) {
 				/* == is important; due to nextpll algorithm we get
@@ -426,7 +431,7 @@
 	}
 	/* VideoPLL and PixelPLL matched: do nothing... In all other cases we should get at least one frequency */
 	if (!mnpcount) {
-		return 1;
+		return -EBUSY;
 	}
 	{
 		unsigned long flags;
@@ -435,15 +440,15 @@
 		matroxfb_DAC_lock_irqsave(flags);
 		mnp = g450_checkcache(PMINFO ci, mnparray[0]);
 		if (mnp != NO_MORE_MNP) {
-			g450_setpll_cond(PMINFO mnp, pll);
+			matroxfb_g450_setpll_cond(PMINFO mnp, pll);
 		} else {
 			mnp = g450_findworkingpll(PMINFO pll, mnparray, mnpcount);
 			g450_addcache(ci, mnparray[0], mnp);
 		}
 		updatehwstate_clk(&ACCESS_FBINFO(hw), mnp, pll);
 		matroxfb_DAC_unlock_irqrestore(flags);
+		return mnp;
 	}
-	return 0;
 }
 
 /* It must be greater than number of possible PLL values.
@@ -465,8 +470,10 @@
 }
 
 EXPORT_SYMBOL(matroxfb_g450_setclk);
+EXPORT_SYMBOL(g450_mnp2f);
+EXPORT_SYMBOL(matroxfb_g450_setpll_cond);
 
-MODULE_AUTHOR("(c) 2001 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_AUTHOR("(c) 2001-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
 MODULE_DESCRIPTION("Matrox G450/G550 PLL driver");
 
 MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/matrox/g450_pll.h linux-2.4.21-pre6/drivers/video/matrox/g450_pll.h
--- linux-2.4.20/drivers/video/matrox/g450_pll.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/matrox/g450_pll.h	2003-03-26 23:49:51.000000000 +0000
@@ -4,5 +4,7 @@
 #include "matroxfb_base.h"
 
 int matroxfb_g450_setclk(WPMINFO unsigned int fout, unsigned int pll);
+unsigned int g450_mnp2f(CPMINFO unsigned int mnp);
+void matroxfb_g450_setpll_cond(WPMINFO unsigned int mnp, unsigned int pll);
 
 #endif	/* __G450_PLL_H__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/matrox/i2c-matroxfb.c linux-2.4.21-pre6/drivers/video/matrox/i2c-matroxfb.c
--- linux-2.4.20/drivers/video/matrox/i2c-matroxfb.c	2001-11-09 22:07:41.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/matrox/i2c-matroxfb.c	2003-03-26 23:49:35.000000000 +0000
@@ -2,9 +2,9 @@
  *
  * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
  *
- * (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz>
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
  *
- * Version: 1.51 2001/01/19
+ * Version: 1.64 2002/06/10
  *
  * See matroxfb_base.c for contributors.
  *
@@ -30,6 +30,12 @@
 
 /******************************************************/
 
+struct matroxfb_dh_maven_info {
+	struct i2c_bit_adapter	maven;
+	struct i2c_bit_adapter	ddc1;
+	struct i2c_bit_adapter	ddc2;
+};
+
 static int matroxfb_read_gpio(struct matrox_fb_info* minfo) {
 	unsigned long flags;
 	int v;
@@ -40,7 +46,7 @@
 	return v;
 }
 
-static inline void matroxfb_set_gpio(struct matrox_fb_info* minfo, int mask, int val) {
+static void matroxfb_set_gpio(struct matrox_fb_info* minfo, int mask, int val) {
 	unsigned long flags;
 	int v;
 
@@ -53,7 +59,7 @@
 }
 
 /* software I2C functions */
-static void matroxfb_i2c_set(struct matrox_fb_info* minfo, int mask, int state) {
+static inline void matroxfb_i2c_set(struct matrox_fb_info* minfo, int mask, int state) {
 	if (state)
 		state = 0;
 	else
@@ -61,68 +67,24 @@
 	matroxfb_set_gpio(minfo, ~mask, state);
 }
 
-static void matroxfb_maven_setsda(void* data, int state) {
-	matroxfb_i2c_set(data, MAT_DATA, state);
-}
-
-static void matroxfb_maven_setscl(void* data, int state) {
-	matroxfb_i2c_set(data, MAT_CLK, state);
-}
-
-static int matroxfb_maven_getsda(void* data) {
-	return (matroxfb_read_gpio(data) & MAT_DATA) ? 1 : 0;
+static void matroxfb_gpio_setsda(void* data, int state) {
+	struct i2c_bit_adapter* b = data;
+	matroxfb_i2c_set(b->minfo, b->mask.data, state);
 }
 
-static int matroxfb_maven_getscl(void* data) {
-	return (matroxfb_read_gpio(data) & MAT_CLK) ? 1 : 0;
+static void matroxfb_gpio_setscl(void* data, int state) {
+	struct i2c_bit_adapter* b = data;
+	matroxfb_i2c_set(b->minfo, b->mask.clock, state);
 }
 
-static void matroxfb_ddc1_setsda(void* data, int state) {
-	matroxfb_i2c_set(data, DDC1_DATA, state);
+static int matroxfb_gpio_getsda(void* data) {
+	struct i2c_bit_adapter* b = data;
+	return (matroxfb_read_gpio(b->minfo) & b->mask.data) ? 1 : 0;
 }
 
-static void matroxfb_ddc1_setscl(void* data, int state) {
-	matroxfb_i2c_set(data, DDC1_CLK, state);
-}
-
-static int matroxfb_ddc1_getsda(void* data) {
-	return (matroxfb_read_gpio(data) & DDC1_DATA) ? 1 : 0;
-}
-
-static int matroxfb_ddc1_getscl(void* data) {
-	return (matroxfb_read_gpio(data) & DDC1_CLK) ? 1 : 0;
-}
-
-static void matroxfb_ddc1b_setsda(void* data, int state) {
-	matroxfb_i2c_set(data, DDC1B_DATA, state);
-}
-
-static void matroxfb_ddc1b_setscl(void* data, int state) {
-	matroxfb_i2c_set(data, DDC1B_CLK, state);
-}
-
-static int matroxfb_ddc1b_getsda(void* data) {
-	return (matroxfb_read_gpio(data) & DDC1B_DATA) ? 1 : 0;
-}
-
-static int matroxfb_ddc1b_getscl(void* data) {
-	return (matroxfb_read_gpio(data) & DDC1B_CLK) ? 1 : 0;
-}
-
-static void matroxfb_ddc2_setsda(void* data, int state) {
-	matroxfb_i2c_set(data, DDC2_DATA, state);
-}
-
-static void matroxfb_ddc2_setscl(void* data, int state) {
-	matroxfb_i2c_set(data, DDC2_CLK, state);
-}
-
-static int matroxfb_ddc2_getsda(void* data) {
-	return (matroxfb_read_gpio(data) & DDC2_DATA) ? 1 : 0;
-}
-
-static int matroxfb_ddc2_getscl(void* data) {
-	return (matroxfb_read_gpio(data) & DDC2_CLK) ? 1 : 0;
+static int matroxfb_gpio_getscl(void* data) {
+	struct i2c_bit_adapter* b = data;
+	return (matroxfb_read_gpio(b->minfo) & b->mask.clock) ? 1 : 0;
 }
 
 static void matroxfb_dh_inc_use(struct i2c_adapter* dummy) {
@@ -133,97 +95,36 @@
 	MOD_DEC_USE_COUNT;
 }
 
-static struct i2c_adapter matroxmaven_i2c_adapter_template =
+static struct i2c_adapter matrox_i2c_adapter_template =
 {
-	"",
-	I2C_HW_B_G400,
-
-	NULL,
-	NULL,
-
-	matroxfb_dh_inc_use,
-	matroxfb_dh_dec_use,
-	NULL,
-	NULL,
-	NULL,
+	.id =		I2C_HW_B_G400,
+	.inc_use =	matroxfb_dh_inc_use,
+	.dec_use =	matroxfb_dh_dec_use,
 };
 
-static struct i2c_algo_bit_data matroxmaven_i2c_algo_template =
+static struct i2c_algo_bit_data matrox_i2c_algo_template =
 {
 	NULL,
-	matroxfb_maven_setsda,
-	matroxfb_maven_setscl,
-	matroxfb_maven_getsda,
-	matroxfb_maven_getscl,
+	matroxfb_gpio_setsda,
+	matroxfb_gpio_setscl,
+	matroxfb_gpio_getsda,
+	matroxfb_gpio_getscl,
 	10, 10, 100,
 };
 
-static struct i2c_adapter matrox_ddc1_adapter_template =
-{
-	"",
-	I2C_HW_B_G400, /* DDC */
-
-	NULL,
-	NULL,
-
-	matroxfb_dh_inc_use,
-	matroxfb_dh_dec_use,
-	NULL,
-	NULL,
-	NULL,
-};
-
-static struct i2c_algo_bit_data matrox_ddc1_algo_template =
-{
-	NULL,
-	matroxfb_ddc1_setsda,
-	matroxfb_ddc1_setscl,
-	matroxfb_ddc1_getsda,
-	matroxfb_ddc1_getscl,
-	10, 10, 100,
-};
-
-static struct i2c_algo_bit_data matrox_ddc1b_algo_template =
-{
-	NULL,
-	matroxfb_ddc1b_setsda,
-	matroxfb_ddc1b_setscl,
-	matroxfb_ddc1b_getsda,
-	matroxfb_ddc1b_getscl,
-	10, 10, 100,
-};
-
-static struct i2c_adapter matrox_ddc2_adapter_template =
-{
-	"",
-	I2C_HW_B_G400,	/* DDC */
-
-	NULL,
-	NULL,
-
-	matroxfb_dh_inc_use, /* should increment matroxfb_maven usage too, this DDC is coupled with maven_client */
-	matroxfb_dh_dec_use, /* should decrement matroxfb_maven usage too */
-	NULL,
-	NULL,
-	NULL,
-};
-
-static struct i2c_algo_bit_data matrox_ddc2_algo_template =
-{
-	NULL,
-	matroxfb_ddc2_setsda,
-	matroxfb_ddc2_setscl,
-	matroxfb_ddc2_getsda,
-	matroxfb_ddc2_getscl,
-	10, 10, 100,
-};
-
-static int i2c_bus_reg(struct i2c_bit_adapter* b, struct matrox_fb_info* minfo) {
+static int i2c_bus_reg(struct i2c_bit_adapter* b, struct matrox_fb_info* minfo, 
+		unsigned int data, unsigned int clock, const char* name) {
 	int err;
 
-	b->adapter.data = minfo;
+	b->minfo = minfo;
+	b->mask.data = data;
+	b->mask.clock = clock;
+	b->adapter = matrox_i2c_adapter_template;
+	sprintf(b->adapter.name, name, GET_FB_IDX(minfo->fbcon.node));
+	b->adapter.data = b;
 	b->adapter.algo_data = &b->bac;
-	b->bac.data = minfo;
+	b->bac = matrox_i2c_algo_template;
+	b->bac.data = b;
 	err = i2c_bit_add_bus(&b->adapter);
 	b->initialized = !err;
 	return err;
@@ -236,50 +137,14 @@
 	}
 }
 
-static inline int i2c_maven_init(struct matroxfb_dh_maven_info* minfo2) {
-	struct i2c_bit_adapter *b = &minfo2->maven;
-
-	b->adapter = matroxmaven_i2c_adapter_template;
-	b->bac = matroxmaven_i2c_algo_template;
-	sprintf(b->adapter.name, "MAVEN:fb%u on i2c-matroxfb", GET_FB_IDX(minfo2->primary_dev->fbcon.node));
-	return i2c_bus_reg(b, minfo2->primary_dev);
-}
-
 static inline void i2c_maven_done(struct matroxfb_dh_maven_info* minfo2) {
 	i2c_bit_bus_del(&minfo2->maven);
 }
 
-static inline int i2c_ddc1_init(struct matroxfb_dh_maven_info* minfo2) {
-	struct i2c_bit_adapter *b = &minfo2->ddc1;
-
-	b->adapter = matrox_ddc1_adapter_template;
-	b->bac = matrox_ddc1_algo_template;
-	sprintf(b->adapter.name, "DDC:fb%u #0 on i2c-matroxfb", GET_FB_IDX(minfo2->primary_dev->fbcon.node));
-	return i2c_bus_reg(b, minfo2->primary_dev);
-}
-
-static inline int i2c_ddc1b_init(struct matroxfb_dh_maven_info* minfo2) {
-	struct i2c_bit_adapter *b = &minfo2->ddc1;
-
-	b->adapter = matrox_ddc1_adapter_template;
-	b->bac = matrox_ddc1b_algo_template;
-	sprintf(b->adapter.name, "DDC:fb%u #0 on i2c-matroxfb", GET_FB_IDX(minfo2->primary_dev->fbcon.node));
-	return i2c_bus_reg(b, minfo2->primary_dev);
-}
-
 static inline void i2c_ddc1_done(struct matroxfb_dh_maven_info* minfo2) {
 	i2c_bit_bus_del(&minfo2->ddc1);
 }
 
-static inline int i2c_ddc2_init(struct matroxfb_dh_maven_info* minfo2) {
-	struct i2c_bit_adapter *b = &minfo2->ddc2;
-
-	b->adapter = matrox_ddc2_adapter_template;
-	b->bac = matrox_ddc2_algo_template;
-	sprintf(b->adapter.name, "DDC:fb%u #1 on i2c-matroxfb", GET_FB_IDX(minfo2->primary_dev->fbcon.node));
-	return i2c_bus_reg(b, minfo2->primary_dev);
-}
-
 static inline void i2c_ddc2_done(struct matroxfb_dh_maven_info* minfo2) {
 	i2c_bit_bus_del(&minfo2->ddc2);
 }
@@ -299,24 +164,26 @@
 	matroxfb_DAC_unlock_irqrestore(flags);
 
 	memset(m2info, 0, sizeof(*m2info));
-	m2info->maven.minfo = m2info;
-	m2info->ddc1.minfo = m2info;
-	m2info->ddc2.minfo = m2info;
-	m2info->primary_dev = minfo;
-
-	if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGA2064W ||
-	    ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGA2164W ||
-	    ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGA2164W_AGP)
-		err = i2c_ddc1b_init(m2info);
-	else
-		err = i2c_ddc1_init(m2info);
+
+	switch (ACCESS_FBINFO(chip)) {
+		case MGA_2064:
+		case MGA_2164:
+			err = i2c_bus_reg(&m2info->ddc1, minfo, DDC1B_DATA, DDC1B_CLK, "DDC:fb%u #0 on i2c-matroxfb");
+			break;
+		default:
+			err = i2c_bus_reg(&m2info->ddc1, minfo, DDC1_DATA, DDC1_CLK, "DDC:fb%u #0 on i2c-matroxfb");
+			break;
+	}
 	if (err)
 		goto fail_ddc1;
-	if (ACCESS_FBINFO(devflags.maven_capable)) {
-		err = i2c_ddc2_init(m2info);
-		if (err)
+	if (ACCESS_FBINFO(devflags.dualhead)) {
+		err = i2c_bus_reg(&m2info->ddc2, minfo, DDC2_DATA, DDC2_CLK, "DDC:fb%u #1 on i2c-matroxfb");
+		if (err == -ENODEV) {
+			printk(KERN_INFO "i2c-matroxfb: VGA->TV plug detected, DDC unavailable.\n");
+		} else if (err)
 			printk(KERN_INFO "i2c-matroxfb: Could not register secondary output i2c bus. Continuing anyway.\n");
-		err = i2c_maven_init(m2info);
+		/* Register maven bus even on G450/G550 */
+		err = i2c_bus_reg(&m2info->maven, minfo, MAT_DATA, MAT_CLK, "MAVEN:fb%u on i2c-matroxfb");
 		if (err)
 			printk(KERN_INFO "i2c-matroxfb: Could not register Maven i2c bus. Continuing anyway.\n");
 	}
@@ -337,10 +204,10 @@
 }
 
 static struct matroxfb_driver i2c_matroxfb = {
-	LIST_HEAD_INIT(i2c_matroxfb.node),
-	"i2c-matroxfb",
-	i2c_matroxfb_probe,
-	i2c_matroxfb_remove,
+	.node =		LIST_HEAD_INIT(i2c_matroxfb.node),
+	.name =		"i2c-matroxfb",
+	.probe = 	i2c_matroxfb_probe,
+	.remove =	i2c_matroxfb_remove,
 };
 
 static int __init i2c_matroxfb_init(void) {
@@ -355,7 +222,7 @@
 	matroxfb_unregister_driver(&i2c_matroxfb);
 }
 
-MODULE_AUTHOR("(c) 1999-2001 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
 MODULE_DESCRIPTION("Support module providing I2C buses present on Matrox videocards");
 
 module_init(i2c_matroxfb_init);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/matrox/matroxfb_DAC1064.c linux-2.4.21-pre6/drivers/video/matrox/matroxfb_DAC1064.c
--- linux-2.4.20/drivers/video/matrox/matroxfb_DAC1064.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/matrox/matroxfb_DAC1064.c	2003-03-26 23:49:35.000000000 +0000
@@ -2,11 +2,11 @@
  *
  * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
  *
- * (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz>
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
  *
  * Portions Copyright (c) 2001 Matrox Graphics Inc.
  *
- * Version: 1.62 2001/11/29
+ * Version: 1.64 2002/06/10
  *
  * See matroxfb_base.c for contributors.
  *
@@ -161,37 +161,20 @@
 	unsigned int p;
 
 	DBG("DAC1064_calcclock")
+	
+	/* only for devices older than G450 */
 
 	fvco = PLL_calcclock(PMINFO freq, fmax, in, feed, &p);
 	
-	if (ACCESS_FBINFO(devflags.g450dac)) {
-		if (fvco <= 300000)		/* 276-324 */
-			;
-		else if (fvco <= 400000)	/* 378-438 */
-			p |= 0x08;
-		else if (fvco <= 550000)	/* 540-567 */
-			p |= 0x10;
-		else if (fvco <= 690000)	/* 675-695 */
-			p |= 0x18;
-		else if (fvco <= 800000)	/* 776-803 */
-			p |= 0x20;
-		else if (fvco <= 891000)	/* 891-891 */
-			p |= 0x28;
-		else if (fvco <= 940000)	/* 931-945 */
-			p |= 0x30;
-		else				/* <959 */
-			p |= 0x38;
-	} else {
-		p = (1 << p) - 1;
-		if (fvco <= 100000)
-			;
-		else if (fvco <= 140000)
-			p |= 0x08;
-		else if (fvco <= 180000)
-			p |= 0x10;
-		else
-			p |= 0x18;
-	}
+	p = (1 << p) - 1;
+	if (fvco <= 100000)
+		;
+	else if (fvco <= 140000)
+		p |= 0x08;
+	else if (fvco <= 180000)
+		p |= 0x10;
+	else
+		p |= 0x18;
 	*post = p;
 }
 
@@ -293,31 +276,169 @@
 	hw->MXoptionReg = mx;
 }
 
+#ifdef CONFIG_FB_MATROX_G450
+static void g450_set_plls(WPMINFO2) {
+	u_int32_t c2_ctl;
+	unsigned int pxc;
+	struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
+	int pixelmnp;
+	int videomnp;
+	
+	c2_ctl = hw->crtc2.ctl & ~0x4007;	/* Clear PLL + enable for CRTC2 */
+	c2_ctl |= 0x0001;			/* Enable CRTC2 */
+	hw->DACreg[POS1064_XPWRCTRL] &= ~0x02;	/* Stop VIDEO PLL */
+	pixelmnp = ACCESS_FBINFO(crtc1).mnp;
+	videomnp = ACCESS_FBINFO(crtc2).mnp;
+	if (videomnp < 0) {
+		c2_ctl &= ~0x0001;			/* Disable CRTC2 */
+		hw->DACreg[POS1064_XPWRCTRL] &= ~0x10;	/* Powerdown CRTC2 */
+	} else if (ACCESS_FBINFO(crtc2).pixclock == ACCESS_FBINFO(features).pll.ref_freq) {
+		c2_ctl |=  0x4002;	/* Use reference directly */
+	} else if (videomnp == pixelmnp) {
+		c2_ctl |=  0x0004;	/* Use pixel PLL */
+	} else {
+		if (0 == ((videomnp ^ pixelmnp) & 0xFFFFFF00)) {
+			/* PIXEL and VIDEO PLL must not use same frequency. We modify N
+			   of PIXEL PLL in such case because of VIDEO PLL may be source
+			   of TVO clocks, and chroma subcarrier is derived from its
+			   pixel clocks */
+			pixelmnp += 0x000100;
+		}
+		c2_ctl |=  0x0006;	/* Use video PLL */
+		hw->DACreg[POS1064_XPWRCTRL] |= 0x02;
+		
+		outDAC1064(PMINFO M1064_XPWRCTRL, hw->DACreg[POS1064_XPWRCTRL]);
+		matroxfb_g450_setpll_cond(PMINFO videomnp, M_VIDEO_PLL);
+	}
+
+	hw->DACreg[POS1064_XPIXCLKCTRL] &= ~M1064_XPIXCLKCTRL_PLL_UP;
+	if (pixelmnp >= 0) {
+		hw->DACreg[POS1064_XPIXCLKCTRL] |= M1064_XPIXCLKCTRL_PLL_UP;
+		
+		outDAC1064(PMINFO M1064_XPIXCLKCTRL, hw->DACreg[POS1064_XPIXCLKCTRL]);
+		matroxfb_g450_setpll_cond(PMINFO pixelmnp, M_PIXEL_PLL_C);
+	}
+	if (c2_ctl != hw->crtc2.ctl) {
+		hw->crtc2.ctl = c2_ctl;
+		mga_outl(0x3C10, c2_ctl);
+	}
+
+	pxc = ACCESS_FBINFO(crtc1).pixclock;
+	if (pxc == 0 || ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_CRTC2) {
+		pxc = ACCESS_FBINFO(crtc2).pixclock;
+	}
+	if (ACCESS_FBINFO(chip) == MGA_G550) {
+		if (pxc < 45000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x00;	/* 0-50 */
+		} else if (pxc < 55000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x08;	/* 34-62 */
+		} else if (pxc < 70000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x10;	/* 42-78 */
+		} else if (pxc < 85000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x18;	/* 62-92 */
+		} else if (pxc < 100000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x20;	/* 74-108 */
+		} else if (pxc < 115000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x28;	/* 94-122 */
+		} else if (pxc < 125000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x30;	/* 108-132 */
+		} else {
+			hw->DACreg[POS1064_XPANMODE] = 0x38;	/* 120-168 */
+		}
+	} else {
+		/* G450 */
+		if (pxc < 45000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x00;	/* 0-54 */
+		} else if (pxc < 65000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x08;	/* 38-70 */
+		} else if (pxc < 85000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x10;	/* 56-96 */
+		} else if (pxc < 105000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x18;	/* 80-114 */
+		} else if (pxc < 135000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x20;	/* 102-144 */
+		} else if (pxc < 160000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x28;	/* 132-166 */
+		} else if (pxc < 175000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x30;	/* 154-182 */
+		} else {
+			hw->DACreg[POS1064_XPANMODE] = 0x38;	/* 170-204 */
+		}
+	}
+}
+#endif
+
 void DAC1064_global_init(WPMINFO2) {
 	struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
 
 	hw->DACreg[POS1064_XMISCCTRL] &= M1064_XMISCCTRL_DAC_WIDTHMASK;
 	hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_LUT_EN;
 	hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL;
-	hw->DACreg[POS1064_XOUTPUTCONN] = 0x01;	/* output #1 enabled */
-	if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) {
-		if (ACCESS_FBINFO(devflags.g450dac)) {
-			hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL2;
-			hw->DACreg[POS1064_XOUTPUTCONN] = 0x05;	/* output #1 enabled; CRTC1 connected to output #2 */
-		} else {
+#ifdef CONFIG_FB_MATROX_G450
+	if (ACCESS_FBINFO(devflags.g450dac)) {
+		hw->DACreg[POS1064_XPWRCTRL] = 0x1F;	/* powerup everything */
+		hw->DACreg[POS1064_XOUTPUTCONN] = 0x00;	/* disable outputs */
+		hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_DAC_EN;
+		switch (ACCESS_FBINFO(outputs[0]).src) {
+			case MATROXFB_SRC_CRTC1:
+			case MATROXFB_SRC_CRTC2:
+				hw->DACreg[POS1064_XOUTPUTCONN] |= 0x01;	/* enable output; CRTC1/2 selection is in CRTC2 ctl */
+				break;
+			case MATROXFB_SRC_NONE:
+				hw->DACreg[POS1064_XMISCCTRL] &= ~M1064_XMISCCTRL_DAC_EN;
+				break;
+		}
+		switch (ACCESS_FBINFO(outputs[1]).src) {
+			case MATROXFB_SRC_CRTC1:
+				hw->DACreg[POS1064_XOUTPUTCONN] |= 0x04;
+				break;
+			case MATROXFB_SRC_CRTC2:
+				if (ACCESS_FBINFO(outputs[1]).mode == MATROXFB_OUTPUT_MODE_MONITOR) {
+					hw->DACreg[POS1064_XOUTPUTCONN] |= 0x08;
+				} else {
+					hw->DACreg[POS1064_XOUTPUTCONN] |= 0x0C;
+				}
+				break;
+			case MATROXFB_SRC_NONE:
+				hw->DACreg[POS1064_XPWRCTRL] &= ~0x01;		/* Poweroff DAC2 */
+				break;
+		}
+		switch (ACCESS_FBINFO(outputs[2]).src) {
+			case MATROXFB_SRC_CRTC1:
+				hw->DACreg[POS1064_XOUTPUTCONN] |= 0x20;
+				break;
+			case MATROXFB_SRC_CRTC2:
+				hw->DACreg[POS1064_XOUTPUTCONN] |= 0x40;
+				break;
+			case MATROXFB_SRC_NONE:
+#if 0
+				/* HELP! If we boot without DFP connected to DVI, we can
+				   poweroff TMDS. But if we boot with DFP connected,
+				   TMDS generated clocks are used instead of ALL pixclocks
+				   available... If someone knows which register
+				   handles it, please reveal this secret to me... */			
+				hw->DACreg[POS1064_XPWRCTRL] &= ~0x04;		/* Poweroff TMDS */
+#endif				
+				break;
+		}
+		/* Now set timming related variables... */
+		g450_set_plls(PMINFO2);
+	} else
+#endif
+	{
+		if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC1) {
 			hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_EXT;
 			hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_MAFC12;
-		}
-	} else if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) {
-		hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_C2_MAFC12;
-		hw->DACreg[POS1064_XOUTPUTCONN] = 0x09; /* output #1 enabled; CRTC2 connected to output #2 */
-	} else if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP)
-		hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_PANELLINK | G400_XMISCCTRL_VDO_MAFC12;
-	else
-		hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_DIS;
+		} else if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC2) {
+			hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_C2_MAFC12;
+		} else if (ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_CRTC1)
+			hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_PANELLINK | G400_XMISCCTRL_VDO_MAFC12;
+		else
+			hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_DIS;
 
-	if ((ACCESS_FBINFO(output.ph) | ACCESS_FBINFO(output.sh)) & MATROXFB_OUTPUT_CONN_PRIMARY)
-		hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_DAC_EN;
+		if (ACCESS_FBINFO(outputs[0]).src != MATROXFB_SRC_NONE)
+			hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_DAC_EN;
+	}
 }
 
 void DAC1064_global_restore(WPMINFO2) {
@@ -329,8 +450,9 @@
 		outDAC1064(PMINFO 0x20, 0x04);
 		outDAC1064(PMINFO 0x1F, ACCESS_FBINFO(devflags.dfp_type));
 		if (ACCESS_FBINFO(devflags.g450dac)) {
-			outDAC1064(PMINFO M1064_XSYNCCTRL, 0xCC);	/* only matrox know... */
-			outDAC1064(PMINFO M1064_XPWRCTRL, 0x1F);	/* powerup everything */
+			outDAC1064(PMINFO M1064_XSYNCCTRL, 0xCC);
+			outDAC1064(PMINFO M1064_XPWRCTRL, hw->DACreg[POS1064_XPWRCTRL]);
+			outDAC1064(PMINFO M1064_XPANMODE, hw->DACreg[POS1064_XPANMODE]);
 			outDAC1064(PMINFO M1064_XOUTPUTCONN, hw->DACreg[POS1064_XOUTPUTCONN]);
 		}
 	}
@@ -368,13 +490,13 @@
 			return 1;	/* unsupported depth */
 		}
 	}
-
-	DAC1064_global_init(PMINFO2);
 	hw->DACreg[POS1064_XVREFCTRL] = ACCESS_FBINFO(features.DAC1064.xvrefctrl);
 	hw->DACreg[POS1064_XGENCTRL] &= ~M1064_XGENCTRL_SYNC_ON_GREEN_MASK;
 	hw->DACreg[POS1064_XGENCTRL] |= (m->sync & FB_SYNC_ON_GREEN)?M1064_XGENCTRL_SYNC_ON_GREEN:M1064_XGENCTRL_NO_SYNC_ON_GREEN;
 	hw->DACreg[POS1064_XCURADDL] = ACCESS_FBINFO(features.DAC1064.cursorimage) >> 10;
 	hw->DACreg[POS1064_XCURADDH] = ACCESS_FBINFO(features.DAC1064.cursorimage) >> 18;
+
+	DAC1064_global_init(PMINFO2);
 	return 0;
 }
 
@@ -471,13 +593,8 @@
 #endif
 }
 
-static int m1064_compute(void* outdev, struct my_timming* m) {
-#define minfo ((struct matrox_fb_info*)outdev)
-#ifdef CONFIG_FB_MATROX_G450
-	if (ACCESS_FBINFO(devflags.g450dac)) {
-		matroxfb_g450_setclk(PMINFO m->pixclock, M_PIXEL_PLL_C);
-	} else 
-#endif
+static int m1064_compute(void* out, struct my_timming* m) {
+#define minfo ((struct matrox_fb_info*)out)
 	{
 		int i;
 		int tmout;
@@ -504,38 +621,31 @@
 	return 0;
 }
 
-static int m1064_program(void* outdev) {
-	/* nothing, hardware is set in m1064_compute */
-	return 0;
-}
-
-static int m1064_start(void* outdev) {
-	/* nothing */
-	return 0;
-}
-
-static void m1064_incuse(void* outdev) {
-	/* nothing yet; MODULE_INC_USE in future... */
-}
-
-static void m1064_decuse(void* outdev) {
-	/* nothing yet; MODULE_DEC_USE in future... */
-}
+static struct matrox_altout m1064 = {
+	.owner   = THIS_MODULE,
+	.name	 = "Primary output",
+	.compute = m1064_compute,
+};
 
-static int m1064_setmode(void* outdev, u_int32_t mode) {
-	if (mode != MATROXFB_OUTPUT_MODE_MONITOR)
-		return -EINVAL;
+#ifdef CONFIG_FB_MATROX_G450
+static int g450_compute(void* out, struct my_timming* m) {
+#define minfo ((struct matrox_fb_info*)out)
+	if (m->mnp < 0) {
+		m->mnp = matroxfb_g450_setclk(PMINFO m->pixclock, (m->crtc == MATROXFB_SRC_CRTC1) ? M_PIXEL_PLL_C : M_VIDEO_PLL);
+		if (m->mnp >= 0) {
+			m->pixclock = g450_mnp2f(PMINFO m->mnp);
+		}
+	}
+#undef minfo
 	return 0;
 }
 
-static struct matrox_altout m1064 = {
-	m1064_compute,
-	m1064_program,
-	m1064_start,
-	m1064_incuse,
-	m1064_decuse,
-	m1064_setmode
+static struct matrox_altout g450out = {
+	.owner   = THIS_MODULE,
+	.name	 = "Primary output",
+	.compute = g450_compute,
 };
+#endif
 
 #endif /* NEED_DAC1064 */
 
@@ -680,7 +790,10 @@
 	ACCESS_FBINFO(features.accel.has_cacheflush) = 1;
 	ACCESS_FBINFO(cursor.timer.function) = matroxfb_DAC1064_flashcursor;
 
-	ACCESS_FBINFO(primout) = &m1064;
+	ACCESS_FBINFO(outputs[0]).output = &m1064;
+	ACCESS_FBINFO(outputs[0]).src = MATROXFB_SRC_CRTC1;
+	ACCESS_FBINFO(outputs[0]).data = MINFO;
+	ACCESS_FBINFO(outputs[0]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
 
 	if (ACCESS_FBINFO(devflags.noinit))
 		return 0;	/* do not modify settings */
@@ -715,6 +828,7 @@
 #endif
 
 #ifdef CONFIG_FB_MATROX_G100
+#ifdef CONFIG_FB_MATROX_G450
 static void g450_mclk_init(WPMINFO2) {
 	/* switch all clocks to PCI source */
 	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, ACCESS_FBINFO(hw).MXoptionReg | 4);
@@ -726,8 +840,13 @@
 	    ((ACCESS_FBINFO(values).reg.opt3 & 0x300000) == 0x300000)) {
 		matroxfb_g450_setclk(PMINFO ACCESS_FBINFO(values.pll.video), M_VIDEO_PLL);
 	} else {
-		/* slow down video clocks... */
-		matroxfb_g450_setclk(PMINFO 0, M_VIDEO_PLL);
+		unsigned long flags;
+		unsigned int pwr;
+		
+		matroxfb_DAC_lock_irqsave(flags);
+		pwr = inDAC1064(PMINFO M1064_XPWRCTRL) & ~0x02;
+		outDAC1064(PMINFO M1064_XPWRCTRL, pwr);
+		matroxfb_DAC_unlock_irqrestore(flags);
 	}
 	matroxfb_g450_setclk(PMINFO ACCESS_FBINFO(values.pll.system), M_SYSTEM_PLL);
 	
@@ -827,6 +946,10 @@
 	
 	return;
 }
+#else
+static inline void g450_preinit(WPMINFO2) {
+}
+#endif
 
 static int MGAG100_preinit(WPMINFO2) {
 	static const int vxres_g100[] = {  512,        640, 768,  800,  832,  960,
@@ -864,7 +987,17 @@
 	ACCESS_FBINFO(capable.plnwt) = ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG100
 			? ACCESS_FBINFO(devflags.sgram) : 1;
 
-	ACCESS_FBINFO(primout) = &m1064;
+#ifdef CONFIG_FB_MATROX_G450
+	if (ACCESS_FBINFO(devflags.g450dac)) {
+		ACCESS_FBINFO(outputs[0]).output = &g450out;
+	} else
+#endif
+	{
+		ACCESS_FBINFO(outputs[0]).output = &m1064;
+	}
+	ACCESS_FBINFO(outputs[0]).src = MATROXFB_SRC_CRTC1;
+	ACCESS_FBINFO(outputs[0]).data = MINFO;
+	ACCESS_FBINFO(outputs[0]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
 
 	if (ACCESS_FBINFO(devflags.g450dac)) {
 		/* we must do this always, BIOS does not do it for us
@@ -895,8 +1028,7 @@
 
 		hw->MXoptionReg |= 0x1080;
 		pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
-		mga_outl(M_CTLWTST, 0x00000300);
-		/* mga_outl(M_CTLWTST, 0x03258A31); */
+		mga_outl(M_CTLWTST, ACCESS_FBINFO(values).reg.mctlwtst);
 		udelay(100);
 		mga_outb(0x1C05, 0x00);
 		mga_outb(0x1C05, 0x80);
@@ -947,17 +1079,18 @@
 		pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION2_REG, reg50);
 
 		if (ACCESS_FBINFO(devflags.memtype) == -1)
-			ACCESS_FBINFO(devflags.memtype) = 0;
-		hw->MXoptionReg |= (ACCESS_FBINFO(devflags.memtype) & 7) << 10;
+			hw->MXoptionReg |= ACCESS_FBINFO(values).reg.opt & 0x1C00;
+		else
+			hw->MXoptionReg |= (ACCESS_FBINFO(devflags.memtype) & 7) << 10;
 		if (ACCESS_FBINFO(devflags.sgram))
 			hw->MXoptionReg |= 0x4000;
-		mga_outl(M_CTLWTST, 0x042450A1);
-		mga_outl(M_MEMRDBK, 0x00000108);
+		mga_outl(M_CTLWTST, ACCESS_FBINFO(values).reg.mctlwtst);
+		mga_outl(M_MEMRDBK, ACCESS_FBINFO(values).reg.memrdbk);
 		udelay(200);
 		mga_outl(M_MACCESS, 0x00000000);
 		mga_outl(M_MACCESS, 0x00008000);
 		udelay(100);
-		mga_outl(M_MEMRDBK, 0x00000108);
+		mga_outl(M_MEMRDBK, ACCESS_FBINFO(values).reg.memrdbk);
 		hw->MXoptionReg |= 0x00040020;
 	}
 	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/matrox/matroxfb_DAC1064.h linux-2.4.21-pre6/drivers/video/matrox/matroxfb_DAC1064.h
--- linux-2.4.20/drivers/video/matrox/matroxfb_DAC1064.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/matrox/matroxfb_DAC1064.h	2003-03-26 23:49:34.000000000 +0000
@@ -146,6 +146,8 @@
 
 #define M1064_XPWRCTRL		0xA0
 
+#define M1064_XPANMODE		0xA2
+
 enum POS1064 {
 	POS1064_XCURADDL=0, POS1064_XCURADDH, POS1064_XCURCTRL,
 	POS1064_XCURCOL0RED, POS1064_XCURCOL0GREEN, POS1064_XCURCOL0BLUE,
@@ -156,7 +158,7 @@
 	POS1064_XGENIOCTRL, POS1064_XGENIODATA, POS1064_XZOOMCTRL, POS1064_XSENSETEST,
 	POS1064_XCRCBITSEL,
 	POS1064_XCOLKEYMASKL, POS1064_XCOLKEYMASKH, POS1064_XCOLKEYL, POS1064_XCOLKEYH,
-	POS1064_XOUTPUTCONN };
+	POS1064_XOUTPUTCONN, POS1064_XPANMODE, POS1064_XPWRCTRL };
 
 
 #endif	/* __MATROXFB_DAC1064_H__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/matrox/matroxfb_Ti3026.c linux-2.4.21-pre6/drivers/video/matrox/matroxfb_Ti3026.c
--- linux-2.4.20/drivers/video/matrox/matroxfb_Ti3026.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/matrox/matroxfb_Ti3026.c	2003-03-26 23:48:58.000000000 +0000
@@ -2,11 +2,11 @@
  *
  * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
  *
- * (c) 1998,1999,2000 Petr Vandrovec <vandrove@vc.cvut.cz>
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
  *
  * Portions Copyright (c) 2001 Matrox Graphics Inc.
  *
- * Version: 1.62 2000/11/29
+ * Version: 1.64 2002/06/10
  *
  * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
  *
@@ -84,6 +84,7 @@
 #include "matroxfb_Ti3026.h"
 #include "matroxfb_misc.h"
 #include "matroxfb_accel.h"
+#include <linux/matroxfb.h>
 
 #ifdef CONFIG_FB_MATROX_MILLENIUM
 #define outTi3026 matroxfb_DAC_out
@@ -811,6 +812,11 @@
 	ti3026_ramdac_init(PMINFO2);
 }
 
+static struct matrox_altout ti3026_output = {
+	.owner   = THIS_MODULE,
+	.name	 = "Primary output",
+};
+
 static int Ti3026_preinit(WPMINFO2) {
 	static const int vxres_mill2[] = { 512,        640, 768,  800,  832,  960,
 					  1024, 1152, 1280,      1600, 1664, 1920,
@@ -829,6 +835,11 @@
 	ACCESS_FBINFO(capable.vxres) = isMilleniumII(MINFO)?vxres_mill2:vxres_mill1;
 	ACCESS_FBINFO(cursor.timer.function) = matroxfb_ti3026_flashcursor;
 
+	ACCESS_FBINFO(outputs[0]).data = MINFO;
+	ACCESS_FBINFO(outputs[0]).output = &ti3026_output;
+	ACCESS_FBINFO(outputs[0]).src = MATROXFB_SRC_CRTC1;
+	ACCESS_FBINFO(outputs[0]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
+
 	if (ACCESS_FBINFO(devflags.noinit))
 		return 0;
 	/* preserve VGA I/O, BIOS and PPC */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/matrox/matroxfb_accel.c linux-2.4.21-pre6/drivers/video/matrox/matroxfb_accel.c
--- linux-2.4.20/drivers/video/matrox/matroxfb_accel.c	2001-10-15 20:47:13.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/matrox/matroxfb_accel.c	2003-03-26 23:48:58.000000000 +0000
@@ -143,6 +143,8 @@
 	ACCESS_FBINFO(accel.m_opmode) = mopmode;
 }
 
+EXPORT_SYMBOL(matrox_cfbX_init);
+
 static void matrox_cfbX_bmove(struct display* p, int sy, int sx, int dy, int dx, int height, int width) {
 	int pixx = p->var.xres_virtual, start, end;
 	CRITFLAGS
@@ -756,6 +758,7 @@
 }
 #endif
 
+#if defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB24) || defined(FBCON_HAS_CFB32)
 static void matrox_cfbX_revc(struct display* p, int xx, int yy) {
 	CRITFLAGS
 	MINFO_FROM_DISP(p);
@@ -776,6 +779,7 @@
 
 	CRITEND
 }
+#endif
 
 static void matrox_cfbX_clear_margins(struct vc_data* conp, struct display* p, int bottom_only) {
 	unsigned int bottom_height, right_width;
@@ -943,7 +947,7 @@
 	CRITEND
 }
 
-void matrox_text_createcursor(WPMINFO struct display* p) {
+static void matrox_text_createcursor(WPMINFO struct display* p) {
 	CRITFLAGS
 
 	if (ACCESS_FBINFO(currcon_display) != p)
@@ -1029,6 +1033,8 @@
 	var->xres_virtual = vxres * hf;
 }
 
+EXPORT_SYMBOL(matrox_text_round);
+
 static int matrox_text_setfont(struct display* p, int width, int height) {
 	DBG("matrox_text_setfont");
 
@@ -1223,6 +1229,8 @@
 	}
 }
 
+EXPORT_SYMBOL(initMatrox);
+
 void matrox_init_putc(WPMINFO struct display* p, void (*dac_createcursor)(WPMINFO struct display* p)) {
 	int i;
 
@@ -1245,4 +1253,7 @@
 		ACCESS_FBINFO(curr.putcs) = matrox_cfbX_putcs;
 	}
 }
+
+EXPORT_SYMBOL(matrox_init_putc);
+
 MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/matrox/matroxfb_accel.h linux-2.4.21-pre6/drivers/video/matrox/matroxfb_accel.h
--- linux-2.4.20/drivers/video/matrox/matroxfb_accel.h	2000-12-11 21:16:53.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/matrox/matroxfb_accel.h	2003-03-26 23:49:18.000000000 +0000
@@ -5,7 +5,6 @@
 
 void matrox_init_putc(WPMINFO struct display* p, void (*)(WPMINFO struct display *p));
 void matrox_cfbX_init(WPMINFO struct display* p);
-void matrox_text_createcursor(WPMINFO struct display* p);
 void matrox_text_round(CPMINFO struct fb_var_screeninfo* var, struct display* p);
 void initMatrox(WPMINFO struct display* p);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/matrox/matroxfb_base.c linux-2.4.21-pre6/drivers/video/matrox/matroxfb_base.c
--- linux-2.4.20/drivers/video/matrox/matroxfb_base.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/matrox/matroxfb_base.c	2003-03-26 23:49:50.000000000 +0000
@@ -2,11 +2,11 @@
  *
  * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
  *
- * (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz>
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
  *
  * Portions Copyright (c) 2001 Matrox Graphics Inc.
  *
- * Version: 1.62 2001/11/29
+ * Version: 1.64 2002/06/10
  *
  * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
  *
@@ -77,6 +77,15 @@
  *               "Uns Lider" <unslider@miranda.org>
  *                     G100 PLNWT fixes
  *
+ *               "Denis Zaitsev" <zzz@cd-club.ru>
+ *                     Fixes
+ *
+ *               "Mike Pieper" <mike@pieper-family.de>
+ *                     TVOut enhandcements, V4L2 control interface.
+ *
+ *               "Diego Biurrun" <diego@biurrun.de>
+ *                     DFP testing
+ *
  * (following author is not in any relation with this code, but his code
  *  is included in this driver)
  *
@@ -100,6 +109,7 @@
 #include "matroxfb_Ti3026.h"
 #include "matroxfb_maven.h"
 #include "matroxfb_crtc2.h"
+#include "matroxfb_g450.h"
 #include <linux/matroxfb.h>
 #include <asm/uaccess.h>
 
@@ -199,6 +209,7 @@
 	}
 	matroxfb_unregister_device(MINFO);
 	unregister_framebuffer(&ACCESS_FBINFO(fbcon));
+	matroxfb_g450_shutdown(PMINFO2);
 	del_timer_sync(&ACCESS_FBINFO(cursor.timer));
 #ifdef CONFIG_MTRR
 	if (ACCESS_FBINFO(mtrr.vram_valid))
@@ -220,7 +231,7 @@
 
 static int matroxfb_open(struct fb_info *info, int user)
 {
-#define minfo ((struct matrox_fb_info*)info)
+#define minfo (list_entry(info, struct matrox_fb_info, fbcon))
 	DBG_LOOP("matroxfb_open")
 
 	if (ACCESS_FBINFO(dead)) {
@@ -233,7 +244,7 @@
 
 static int matroxfb_release(struct fb_info *info, int user)
 {
-#define minfo ((struct matrox_fb_info*)info)
+#define minfo (list_entry(info, struct matrox_fb_info, fbcon))
 	DBG_LOOP("matroxfb_release")
 
 	if (!(--ACCESS_FBINFO(usecount)) && ACCESS_FBINFO(dead)) {
@@ -245,7 +256,7 @@
 
 static int matroxfb_pan_display(struct fb_var_screeninfo *var, int con,
 		struct fb_info* info) {
-#define minfo ((struct matrox_fb_info*)info)
+#define minfo (list_entry(info, struct matrox_fb_info, fbcon))
 
 	DBG("matroxfb_pan_display")
 
@@ -271,7 +282,7 @@
 
 static int matroxfb_updatevar(int con, struct fb_info *info)
 {
-#define minfo ((struct matrox_fb_info*)info)
+#define minfo (list_entry(info, struct matrox_fb_info, fbcon))
 	DBG("matroxfb_updatevar");
 
 	matrox_pan_var(PMINFO &fb_display[con].var);
@@ -391,12 +402,43 @@
 }
 
 static int matroxfb_decode_var(CPMINFO struct display* p, struct fb_var_screeninfo *var, int *visual, int *video_cmap_len, unsigned int* ydstorg) {
+	struct RGBT {
+		unsigned char bpp;
+		struct {
+			unsigned char offset,
+				      length;
+		} red,
+		  green,
+		  blue,
+		  transp;
+		signed char visual;
+	};
+	static const struct RGBT table[]= {
+#if defined FBCON_HAS_VGATEXT
+		{ 0,{ 0,6},{0,6},{0,6},{ 0,0},MX_VISUAL_PSEUDOCOLOR},
+#endif
+#if defined FBCON_HAS_CFB4 || defined FBCON_HAS_CFB8
+		{ 8,{ 0,8},{0,8},{0,8},{ 0,0},MX_VISUAL_PSEUDOCOLOR},
+#endif
+#if defined FBCON_HAS_CFB16
+		{15,{10,5},{5,5},{0,5},{15,1},MX_VISUAL_DIRECTCOLOR},
+		{16,{11,5},{5,6},{0,5},{ 0,0},MX_VISUAL_DIRECTCOLOR},
+#endif
+#if defined FBCON_HAS_CFB24
+		{24,{16,8},{8,8},{0,8},{ 0,0},MX_VISUAL_DIRECTCOLOR},
+#endif
+#if defined FBCON_HAS_CFB32
+		{32,{16,8},{8,8},{0,8},{24,8},MX_VISUAL_DIRECTCOLOR}
+#endif
+	};
+	struct RGBT const *rgbt;
+	unsigned int bpp = var->bits_per_pixel;
 	unsigned int vramlen;
 	unsigned int memlen;
 
 	DBG("matroxfb_decode_var")
 
-	switch (var->bits_per_pixel) {
+	switch (bpp) {
 #ifdef FBCON_HAS_VGATEXT
 		case 0:	 if (!ACCESS_FBINFO(capable.text)) return -EINVAL;
 			 break;
@@ -425,22 +467,22 @@
 		var->yres_virtual = var->yres;
 	if (var->xres_virtual < var->xres)
 		var->xres_virtual = var->xres;
-	if (var->bits_per_pixel) {
-		var->xres_virtual = matroxfb_pitch_adjust(PMINFO var->xres_virtual, var->bits_per_pixel);
-		memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8;
+	if (bpp) {
+		var->xres_virtual = matroxfb_pitch_adjust(PMINFO var->xres_virtual, bpp);
+		memlen = var->xres_virtual * bpp * var->yres_virtual / 8;
 		if (memlen > vramlen) {
-			var->yres_virtual = vramlen * 8 / (var->xres_virtual * var->bits_per_pixel);
-			memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8;
+			var->yres_virtual = vramlen * 8 / (var->xres_virtual * bpp);
+			memlen = var->xres_virtual * bpp * var->yres_virtual / 8;
 		}
 		/* There is hardware bug that no line can cross 4MB boundary */
 		/* give up for CFB24, it is impossible to easy workaround it */
 		/* for other try to do something */
 		if (!ACCESS_FBINFO(capable.cross4MB) && (memlen > 0x400000)) {
-			if (var->bits_per_pixel == 24) {
+			if (bpp == 24) {
 				/* sorry */
 			} else {
 				unsigned int linelen;
-				unsigned int m1 = linelen = var->xres_virtual * var->bits_per_pixel / 8;
+				unsigned int m1 = linelen = var->xres_virtual * bpp / 8;
 				unsigned int m2 = PAGE_SIZE;	/* or 128 if you do not need PAGE ALIGNED address */
 				unsigned int max_yres;
 
@@ -484,104 +526,43 @@
 	if (var->yoffset + var->yres > var->yres_virtual)
 		var->yoffset = var->yres_virtual - var->yres;
 
-	if (var->bits_per_pixel == 0) {
-		var->red.offset = 0;
-		var->red.length = 6;
-		var->green.offset = 0;
-		var->green.length = 6;
-		var->blue.offset = 0;
-		var->blue.length = 6;
-		var->transp.offset = 0;
-		var->transp.length = 0;
-		*visual = MX_VISUAL_PSEUDOCOLOR;
-	} else if (var->bits_per_pixel == 4) {
-		var->red.offset = 0;
-		var->red.length = 8;
-		var->green.offset = 0;
-		var->green.length = 8;
-		var->blue.offset = 0;
-		var->blue.length = 8;
-		var->transp.offset = 0;
-		var->transp.length = 0;
-		*visual = MX_VISUAL_PSEUDOCOLOR;
-	} else if (var->bits_per_pixel <= 8) {
-		var->red.offset = 0;
-		var->red.length = 8;
-		var->green.offset = 0;
-		var->green.length = 8;
-		var->blue.offset = 0;
-		var->blue.length = 8;
-		var->transp.offset = 0;
-		var->transp.length = 0;
-		*visual = MX_VISUAL_PSEUDOCOLOR;
-	} else {
-		if (var->bits_per_pixel <= 16) {
-			if (var->green.length == 5) {
-				var->red.offset    = 10;
-				var->red.length    = 5;
-				var->green.offset  = 5;
-				var->green.length  = 5;
-				var->blue.offset   = 0;
-				var->blue.length   = 5;
-				var->transp.offset = 15;
-				var->transp.length = 1;
-			} else {
-				var->red.offset    = 11;
-				var->red.length    = 5;
-				var->green.offset  = 5;
-				var->green.length  = 6;
-				var->blue.offset   = 0;
-				var->blue.length   = 5;
-				var->transp.offset = 0;
-				var->transp.length = 0;
-			}
-		} else if (var->bits_per_pixel <= 24) {
-			var->red.offset    = 16;
-			var->red.length    = 8;
-			var->green.offset  = 8;
-			var->green.length  = 8;
-			var->blue.offset   = 0;
-			var->blue.length   = 8;
-			var->transp.offset = 0;
-			var->transp.length = 0;
-		} else {
-			var->red.offset    = 16;
-			var->red.length    = 8;
-			var->green.offset  = 8;
-			var->green.length  = 8;
-			var->blue.offset   = 0;
-			var->blue.length   = 8;
-			var->transp.offset = 24;
-			var->transp.length = 8;
-		}
-		dprintk("matroxfb: truecolor: "
-		       "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
-		       var->transp.length,
-		       var->red.length,
-		       var->green.length,
-		       var->blue.length,
-		       var->transp.offset,
-		       var->red.offset,
-		       var->green.offset,
-		       var->blue.offset);
-		*visual = MX_VISUAL_DIRECTCOLOR;
+	if (bpp == 16 && var->green.length == 5) {
+		bpp--; /* an artifical value - 15 */
 	}
+
+	for (rgbt = table; rgbt->bpp < bpp; rgbt++);
+#define	SETCLR(clr)\
+	var->clr.offset = rgbt->clr.offset;\
+	var->clr.length = rgbt->clr.length
+	SETCLR(red);
+	SETCLR(green);
+	SETCLR(blue);
+	SETCLR(transp);
+#undef	SETCLR
+	*visual = rgbt->visual;
+
+	if (bpp > 8)
+		dprintk("matroxfb: truecolor: "
+			"size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
+			var->transp.length, var->red.length, var->green.length, var->blue.length,
+			var->transp.offset, var->red.offset, var->green.offset, var->blue.offset);
+
 	*video_cmap_len = matroxfb_get_cmap_len(var);
 	dprintk(KERN_INFO "requested %d*%d/%dbpp (%d*%d)\n", var->xres, var->yres, var->bits_per_pixel,
 				var->xres_virtual, var->yres_virtual);
 	return 0;
 }
 
-static int matrox_setcolreg(unsigned regno, unsigned red, unsigned green,
-			    unsigned blue, unsigned transp,
-			    struct fb_info *fb_info)
+static int matroxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			      unsigned blue, unsigned transp,
+			      struct fb_info *fb_info)
 {
 	struct display* p;
 #ifdef CONFIG_FB_MATROX_MULTIHEAD
-	struct matrox_fb_info* minfo = (struct matrox_fb_info*)fb_info;
+	struct matrox_fb_info* minfo = list_entry(fb_info, struct matrox_fb_info, fbcon);
 #endif
 
-	DBG("matrox_setcolreg")
+	DBG("matroxfb_setcolreg")
 
 	/*
 	 *  Set a single color register. The values supplied are
@@ -656,15 +637,17 @@
 	return 0;
 }
 
-static void do_install_cmap(WPMINFO struct display* dsp)
+static inline void my_install_cmap(WPMINFO2)
 {
-	DBG("do_install_cmap")
+	/* Do not touch this code if you do not understand what it does! */
+	/* Never try to use do_install_cmap() instead. It is crap. */
+	struct fb_cmap* cmap = &ACCESS_FBINFO(currcon_display)->cmap;
 
-	if (dsp->cmap.len)
-		fb_set_cmap(&dsp->cmap, 1, matrox_setcolreg, &ACCESS_FBINFO(fbcon));
+	if (cmap->len)
+		fb_set_cmap(cmap, 1, matroxfb_setcolreg, &ACCESS_FBINFO(fbcon));
 	else
 		fb_set_cmap(fb_default_cmap(ACCESS_FBINFO(curr.cmap_len)),
-			    1, matrox_setcolreg, &ACCESS_FBINFO(fbcon));
+			    1, matroxfb_setcolreg, &ACCESS_FBINFO(fbcon));
 }
 
 static int matroxfb_get_fix(struct fb_fix_screeninfo *fix, int con,
@@ -673,7 +656,7 @@
 	struct display* p;
 	DBG("matroxfb_get_fix")
 
-#define minfo ((struct matrox_fb_info*)info)
+#define minfo (list_entry(info, struct matrox_fb_info, fbcon))
 
 	if (ACCESS_FBINFO(dead)) {
 		return -ENXIO;
@@ -684,7 +667,7 @@
 	else
 		p = ACCESS_FBINFO(fbcon.disp);
 
-	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+	memset(fix, 0, sizeof(*fix));
 	strcpy(fix->id,"MATROX");
 
 	fix->smem_start = ACCESS_FBINFO(video.base) + ACCESS_FBINFO(curr.ydstorg.bytes);
@@ -706,7 +689,7 @@
 static int matroxfb_get_var(struct fb_var_screeninfo *var, int con,
 			 struct fb_info *info)
 {
-#define minfo ((struct matrox_fb_info*)info)
+#define minfo (list_entry(info, struct matrox_fb_info, fbcon))
 	DBG("matroxfb_get_var")
 
 	if(con < 0)
@@ -720,7 +703,7 @@
 static int matroxfb_set_var(struct fb_var_screeninfo *var, int con,
 			 struct fb_info *info)
 {
-#define minfo ((struct matrox_fb_info*)info)
+#define minfo (list_entry(info, struct matrox_fb_info, fbcon))
 	int err;
 	int visual;
 	int cmap_len;
@@ -760,7 +743,7 @@
 	}
 	display->var = *var;
 	/* cmap */
-	display->screen_base = vaddr_va(ACCESS_FBINFO(video.vbase)) + ydstorg;
+	display->screen_base = ACCESS_FBINFO(fbcon.screen_base) = vaddr_va(ACCESS_FBINFO(video.vbase)) + ydstorg;
 	display->visual = visual;
 	display->ypanstep = 1;
 	display->ywrapstep = 0;
@@ -816,8 +799,10 @@
 
 		{	struct my_timming mt;
 			struct matrox_hw_state* hw;
+			int out;
 
 			matroxfb_var2my(var, &mt);
+			mt.crtc = MATROXFB_SRC_CRTC1;
 			/* CRTC1 delays */
 			switch (var->bits_per_pixel) {
 				case  0:	mt.delay = 31 + 0; break;
@@ -832,6 +817,16 @@
 			del_timer_sync(&ACCESS_FBINFO(cursor.timer));
 			ACCESS_FBINFO(cursor.state) = CM_ERASE;
 
+			down_read(&ACCESS_FBINFO(altout).lock);
+			for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+				if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC1 &&
+				    ACCESS_FBINFO(outputs[out]).output->compute) {
+					ACCESS_FBINFO(outputs[out]).output->compute(ACCESS_FBINFO(outputs[out]).data, &mt);
+				}
+			}
+			up_read(&ACCESS_FBINFO(altout).lock);
+			ACCESS_FBINFO(crtc1).pixclock = mt.pixclock;
+			ACCESS_FBINFO(crtc1).mnp = mt.mnp;
 			ACCESS_FBINFO(hw_switch->init(PMINFO &mt, display));
 			if (display->type == FB_TYPE_TEXT) {
 				if (fontheight(display))
@@ -847,40 +842,25 @@
 			hw->CRTC[0x0C] = (pos & 0xFF00) >> 8;
 			hw->CRTCEXT[0] = (hw->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40);
 			hw->CRTCEXT[8] = pos >> 21;
-			if (ACCESS_FBINFO(output.ph) & (MATROXFB_OUTPUT_CONN_PRIMARY | MATROXFB_OUTPUT_CONN_DFP)) {
-				if (ACCESS_FBINFO(primout))
-					ACCESS_FBINFO(primout)->compute(MINFO, &mt);
-			}
-			if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) {
-				down_read(&ACCESS_FBINFO(altout.lock));
-				if (ACCESS_FBINFO(altout.output))
-					ACCESS_FBINFO(altout.output)->compute(ACCESS_FBINFO(altout.device), &mt);
-				up_read(&ACCESS_FBINFO(altout.lock));
-			}
+		
 			ACCESS_FBINFO(hw_switch->restore(PMINFO display));
-			if (ACCESS_FBINFO(output.ph) & (MATROXFB_OUTPUT_CONN_PRIMARY | MATROXFB_OUTPUT_CONN_DFP)) {
-				if (ACCESS_FBINFO(primout))
-					ACCESS_FBINFO(primout)->program(MINFO);
-			}
-			if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) {
-				down_read(&ACCESS_FBINFO(altout.lock));
-				if (ACCESS_FBINFO(altout.output))
-					ACCESS_FBINFO(altout.output)->program(ACCESS_FBINFO(altout.device));
-				up_read(&ACCESS_FBINFO(altout.lock));
+			down_read(&ACCESS_FBINFO(altout).lock);
+			for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+				if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC1 &&
+				    ACCESS_FBINFO(outputs[out]).output->program) {
+					ACCESS_FBINFO(outputs[out]).output->program(ACCESS_FBINFO(outputs[out]).data);
+				}
 			}
 			ACCESS_FBINFO(cursor.redraw) = 1;
-			if (ACCESS_FBINFO(output.ph) & (MATROXFB_OUTPUT_CONN_PRIMARY | MATROXFB_OUTPUT_CONN_DFP)) {
-				if (ACCESS_FBINFO(primout))
-					ACCESS_FBINFO(primout)->start(MINFO);
-			}
-			if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) {
-				down_read(&ACCESS_FBINFO(altout.lock));
-				if (ACCESS_FBINFO(altout.output))
-					ACCESS_FBINFO(altout.output)->start(ACCESS_FBINFO(altout.device));
-				up_read(&ACCESS_FBINFO(altout.lock));
+			for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+				if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC1 &&
+				    ACCESS_FBINFO(outputs[out]).output->start) {
+					ACCESS_FBINFO(outputs[out]).output->start(ACCESS_FBINFO(outputs[out]).data);
+				}
 			}
+			up_read(&ACCESS_FBINFO(altout).lock);
 			matrox_cfbX_init(PMINFO display);
-			do_install_cmap(PMINFO display);
+			my_install_cmap(PMINFO2);
 #if defined(CONFIG_FB_COMPAT_XPMAC)
 			if (console_fb_info == &ACCESS_FBINFO(fbcon)) {
 				int vmode, cmode;
@@ -913,7 +893,7 @@
 
 	DBG("matrox_getcolreg")
 
-#define minfo ((struct matrox_fb_info*)info)
+#define minfo (list_entry(info, struct matrox_fb_info, fbcon))
 	/*
 	 *  Read a single color register and split it into colors/transparent.
 	 *  Return != 0 for invalid regno.
@@ -933,7 +913,7 @@
 static int matroxfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
 			     struct fb_info *info)
 {
-#define minfo ((struct matrox_fb_info*)info)
+#define minfo (list_entry(info, struct matrox_fb_info, fbcon))
 	struct display* dsp = (con < 0) ? ACCESS_FBINFO(fbcon.disp)
 					: fb_display + con;
 
@@ -959,7 +939,7 @@
 {
 	unsigned int cmap_len;
 	struct display* dsp = (con < 0) ? info->disp : (fb_display + con);
-#define minfo ((struct matrox_fb_info*)info)
+#define minfo (list_entry(info, struct matrox_fb_info, fbcon))
 
 	DBG("matroxfb_set_cmap")
 
@@ -976,7 +956,7 @@
 			return err;
 	}
 	if (con == ACCESS_FBINFO(currcon)) {			/* current console? */
-		return fb_set_cmap(cmap, kspc, matrox_setcolreg, info);
+		return fb_set_cmap(cmap, kspc, matroxfb_setcolreg, info);
 	} else
 		fb_copy_cmap(cmap, &dsp->cmap, kspc ? 0 : 1);
 	return 0;
@@ -1006,11 +986,16 @@
 	return 0;
 }
 
+static struct matrox_altout panellink_output = {
+	.owner   = THIS_MODULE,
+	.name	 = "Panellink output",
+};
+
 static int matroxfb_ioctl(struct inode *inode, struct file *file,
 			  unsigned int cmd, unsigned long arg, int con,
 			  struct fb_info *info)
 {
-#define minfo ((struct matrox_fb_info*)info)
+#define minfo (list_entry(info, struct matrox_fb_info, fbcon))
 	DBG("matroxfb_ioctl")
 
 	if (ACCESS_FBINFO(dead)) {
@@ -1033,80 +1018,74 @@
 		case MATROXFB_SET_OUTPUT_MODE:
 			{
 				struct matroxioc_output_mode mom;
+				struct matrox_altout *oproc;
 				int val;
 
 				if (copy_from_user(&mom, (struct matroxioc_output_mode*)arg, sizeof(mom)))
 					return -EFAULT;
-				if (mom.output >= sizeof(u_int32_t))
-					return -EINVAL;
-				switch (mom.output) {
-					case MATROXFB_OUTPUT_PRIMARY:
-						if (mom.mode != MATROXFB_OUTPUT_MODE_MONITOR)
-							return -EINVAL;
-						/* mode did not change... */
-						return 0;
-					case MATROXFB_OUTPUT_SECONDARY:
+				if (mom.output >= MATROXFB_MAX_OUTPUTS)
+					return -ENXIO;
+				down_read(&ACCESS_FBINFO(altout.lock));
+				oproc = ACCESS_FBINFO(outputs[mom.output]).output;
+				if (!oproc) {
+					val = -ENXIO;
+				} else if (!oproc->verifymode) {
+					if (mom.mode == MATROXFB_OUTPUT_MODE_MONITOR) {
+						val = 0;
+					} else {
 						val = -EINVAL;
-						down_read(&ACCESS_FBINFO(altout.lock));
-						if (ACCESS_FBINFO(altout.output) && ACCESS_FBINFO(altout.device))
-							val = ACCESS_FBINFO(altout.output)->setmode(ACCESS_FBINFO(altout.device), mom.mode);
-						up_read(&ACCESS_FBINFO(altout.lock));
-						if (val != 1)
-							return val;
-						if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY)
-							matroxfb_switch(ACCESS_FBINFO(currcon), info);
-						if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) {
+					}
+				} else {
+					val = oproc->verifymode(ACCESS_FBINFO(outputs[mom.output]).data, mom.mode);
+				}
+				if (!val) {
+					if (ACCESS_FBINFO(outputs[mom.output]).mode != mom.mode) {
+						ACCESS_FBINFO(outputs[mom.output]).mode = mom.mode;
+						val = 1;
+					}
+				}
+				up_read(&ACCESS_FBINFO(altout.lock));
+				if (val != 1)
+					return val;
+				switch (ACCESS_FBINFO(outputs[mom.output]).src) {
+					case MATROXFB_SRC_CRTC1:
+						matroxfb_switch(ACCESS_FBINFO(currcon), info);
+						break;
+					case MATROXFB_SRC_CRTC2:
+						{
 							struct matroxfb_dh_fb_info* crtc2;
 
 							down_read(&ACCESS_FBINFO(crtc2.lock));
-							crtc2 = (struct matroxfb_dh_fb_info*)(ACCESS_FBINFO(crtc2.info));
+							crtc2 = ACCESS_FBINFO(crtc2.info);
 							if (crtc2)
 								crtc2->fbcon.switch_con(crtc2->currcon, &crtc2->fbcon);
 							up_read(&ACCESS_FBINFO(crtc2.lock));
 						}
-						return 0;
-					case MATROXFB_OUTPUT_DFP:
-						if (!(ACCESS_FBINFO(output.all) & MATROXFB_OUTPUT_CONN_DFP))
-							return -ENXIO;
-						if (mom.mode!= MATROXFB_OUTPUT_MODE_MONITOR)
-							return -EINVAL;
-						/* mode did not change... */
-						return 0;
-					default:
-						return -EINVAL;
+						break;
 				}
 				return 0;
 			}
 		case MATROXFB_GET_OUTPUT_MODE:
 			{
 				struct matroxioc_output_mode mom;
+				struct matrox_altout *oproc;
 				int val;
 
 				if (copy_from_user(&mom, (struct matroxioc_output_mode*)arg, sizeof(mom)))
 					return -EFAULT;
-				if (mom.output >= sizeof(u_int32_t))
-					return -EINVAL;
-				switch (mom.output) {
-					case MATROXFB_OUTPUT_PRIMARY:
-						mom.mode = MATROXFB_OUTPUT_MODE_MONITOR;
-						break;
-					case MATROXFB_OUTPUT_SECONDARY:
-						val = -EINVAL;
-						down_read(&ACCESS_FBINFO(altout.lock));
-						if (ACCESS_FBINFO(altout.output) && ACCESS_FBINFO(altout.device))
-							val = ACCESS_FBINFO(altout.output)->getmode(ACCESS_FBINFO(altout.device), &mom.mode);
-						up_read(&ACCESS_FBINFO(altout.lock));
-						if (val)
-							return val;
-						break;
-					case MATROXFB_OUTPUT_DFP:
-						if (!(ACCESS_FBINFO(output.all) & MATROXFB_OUTPUT_CONN_DFP))
-							return -ENXIO;
-						mom.mode = MATROXFB_OUTPUT_MODE_MONITOR;
-						break;
-					default:
-						return -EINVAL;
+				if (mom.output >= MATROXFB_MAX_OUTPUTS)
+					return -ENXIO;
+				down_read(&ACCESS_FBINFO(altout.lock));
+				oproc = ACCESS_FBINFO(outputs[mom.output]).output;
+				if (!oproc) {
+					val = -ENXIO;
+				} else {
+					mom.mode = ACCESS_FBINFO(outputs[mom.output]).mode;
+					val = 0;
 				}
+				up_read(&ACCESS_FBINFO(altout.lock));
+				if (val)
+					return val;
 				if (copy_to_user((struct matroxioc_output_mode*)arg, &mom, sizeof(mom)))
 					return -EFAULT;
 				return 0;
@@ -1114,55 +1093,248 @@
 		case MATROXFB_SET_OUTPUT_CONNECTION:
 			{
 				u_int32_t tmp;
+				int i;
+				int changes;
 
 				if (copy_from_user(&tmp, (u_int32_t*)arg, sizeof(tmp)))
 					return -EFAULT;
-				if (tmp & ~ACCESS_FBINFO(output.all))
-					return -EINVAL;
-				if (tmp & ACCESS_FBINFO(output.sh))
-					return -EINVAL;
-				if (tmp & MATROXFB_OUTPUT_CONN_DFP) {
-					if (tmp & MATROXFB_OUTPUT_CONN_SECONDARY)
-						return -EINVAL;
-					if (ACCESS_FBINFO(output.sh))
-						return -EINVAL;
+				for (i = 0; i < 32; i++) {
+					if (tmp & (1 << i)) {
+						if (i >= MATROXFB_MAX_OUTPUTS)
+							return -ENXIO;
+						if (!ACCESS_FBINFO(outputs[i]).output)
+							return -ENXIO;
+						switch (ACCESS_FBINFO(outputs[i]).src) {
+							case MATROXFB_SRC_NONE:
+							case MATROXFB_SRC_CRTC1:
+								break;
+							default:
+								return -EBUSY;
+						}
+					}
 				}
-				if (tmp == ACCESS_FBINFO(output.ph))
+				if (ACCESS_FBINFO(devflags.panellink)) {
+					if (tmp & MATROXFB_OUTPUT_CONN_DFP) {
+						if (tmp & MATROXFB_OUTPUT_CONN_SECONDARY)
+							return -EINVAL;
+						for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
+							if (ACCESS_FBINFO(outputs[i]).src == MATROXFB_SRC_CRTC2) {
+								return -EBUSY;
+							}
+						}
+					}
+				}
+				changes = 0;
+				for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
+					if (tmp & (1 << i)) {
+						if (ACCESS_FBINFO(outputs[i]).src != MATROXFB_SRC_CRTC1) {
+							changes = 1;
+							ACCESS_FBINFO(outputs[i]).src = MATROXFB_SRC_CRTC1;
+						}
+					} else if (ACCESS_FBINFO(outputs[i]).src == MATROXFB_SRC_CRTC1) {
+						changes = 1;
+						ACCESS_FBINFO(outputs[i]).src = MATROXFB_SRC_NONE;
+					}
+				}
+				if (!changes)
 					return 0;
-				ACCESS_FBINFO(output.ph) = tmp;
 				matroxfb_switch(ACCESS_FBINFO(currcon), info);
 				return 0;
 			}
 		case MATROXFB_GET_OUTPUT_CONNECTION:
 			{
-				if (put_user(ACCESS_FBINFO(output.ph), (u_int32_t*)arg))
+				u_int32_t conn = 0;
+				int i;
+
+				for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
+					if (ACCESS_FBINFO(outputs[i]).src == MATROXFB_SRC_CRTC1) {
+						conn |= 1 << i;
+					}
+				}
+				if (put_user(conn, (u_int32_t*)arg))
 					return -EFAULT;
 				return 0;
 			}
 		case MATROXFB_GET_AVAILABLE_OUTPUTS:
 			{
-				u_int32_t tmp;
+				u_int32_t conn = 0;
+				int i;
 
-				tmp = ACCESS_FBINFO(output.all) & ~ACCESS_FBINFO(output.sh);
-				if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP)
-					tmp &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
-				if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY)
-					tmp &= ~MATROXFB_OUTPUT_CONN_DFP;
-				if (put_user(tmp, (u_int32_t*)arg))
+				for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
+					if (ACCESS_FBINFO(outputs[i]).output) {
+						switch (ACCESS_FBINFO(outputs[i]).src) {
+							case MATROXFB_SRC_NONE:
+							case MATROXFB_SRC_CRTC1:
+								conn |= 1 << i;
+								break;
+						}
+					}
+				}
+				if (ACCESS_FBINFO(devflags.panellink)) {
+					if (conn & MATROXFB_OUTPUT_CONN_DFP)
+						conn &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
+					if (conn & MATROXFB_OUTPUT_CONN_SECONDARY)
+						conn &= ~MATROXFB_OUTPUT_CONN_DFP;
+				}
+				if (put_user(conn, (u_int32_t*)arg))
 					return -EFAULT;
 				return 0;
 			}
 		case MATROXFB_GET_ALL_OUTPUTS:
 			{
-				if (put_user(ACCESS_FBINFO(output.all), (u_int32_t*)arg))
+				u_int32_t conn = 0;
+				int i;
+
+				for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
+					if (ACCESS_FBINFO(outputs[i]).output) {
+						conn |= 1 << i;
+					}
+				}
+				if (put_user(conn, (u_int32_t*)arg))
+					return -EFAULT;
+				return 0;
+			}
+		case 0x80585600:
+			{
+				struct {
+					char name[32];
+					int type;
+					int inputs;
+					int outputs;
+					int audios;
+					int maxwidth;
+					int maxheight;
+					int minwidth;
+					int minheight;
+					int maxframerate;
+					__u32 flags;
+					__u32 reserved[4];
+				} r;
+				
+				memset(&r, 0, sizeof(r));
+				strcat(r.name, "Matrox TVO");
+				r.type = 2; // output
+				r.inputs = 0;
+				r.outputs = 1;
+				r.audios = 0;
+				r.maxwidth = 1023;	// max visible width
+				r.maxheight = 625;	// max picture height: full PAL
+				r.minwidth = 512;	// min visible width... ~480
+				r.minheight = 480;	// min picture height: visible portion of NTSC
+				r.maxframerate = 60;	// max: NTSC, 60Hz interlaced
+				r.flags = 0;		// nothing is supported...
+				if (copy_to_user((void*)arg, &r, sizeof(r)))
 					return -EFAULT;
 				return 0;
+				
+			}
+		case MATROXFB_TVOQUERYCTRL:
+			{
+				struct matroxfb_queryctrl qctrl;
+				int err;
+
+				if (copy_from_user(&qctrl, (struct matroxfb_queryctrl*)arg, sizeof(qctrl)))
+					return -EFAULT;
+
+				down_read(&ACCESS_FBINFO(altout).lock);
+				if (!ACCESS_FBINFO(outputs[1]).output) {
+					err = -ENXIO;
+				} else if (ACCESS_FBINFO(outputs[1]).output->getqueryctrl) {
+					err = ACCESS_FBINFO(outputs[1]).output->getqueryctrl(ACCESS_FBINFO(outputs[1]).data, &qctrl);
+				} else {
+					err = -EINVAL;
+				}
+				up_read(&ACCESS_FBINFO(altout).lock);
+				if (err >= 0 &&
+				    copy_to_user((struct matroxfb_queryctrl*)arg, &qctrl, sizeof(qctrl)))
+					return -EFAULT;
+				return err;
+			}
+		case MATROXFB_G_TVOCTRL:
+			{
+				struct matroxfb_control ctrl;
+				int err;
+
+				if (copy_from_user(&ctrl, (struct matroxfb_control*)arg, sizeof(ctrl)))
+					return -EFAULT;
+
+				down_read(&ACCESS_FBINFO(altout).lock);
+				if (!ACCESS_FBINFO(outputs[1]).output) {
+					err = -ENXIO;
+				} else if (ACCESS_FBINFO(outputs[1]).output->getctrl) {
+					err = ACCESS_FBINFO(outputs[1]).output->getctrl(ACCESS_FBINFO(outputs[1]).data, &ctrl);
+				} else {
+					err = -EINVAL;
+				}
+				up_read(&ACCESS_FBINFO(altout).lock);
+				if (err >= 0 &&
+				    copy_to_user((struct matroxfb_control*)arg, &ctrl, sizeof(ctrl)))
+					return -EFAULT;
+				return err;
+			}
+		case MATROXFB_S_TVOCTRL:
+			{
+				struct matroxfb_control ctrl;
+				int err;
+
+				if (copy_from_user(&ctrl, (struct matroxfb_control*)arg, sizeof(ctrl)))
+					return -EFAULT;
+
+				down_read(&ACCESS_FBINFO(altout).lock);
+				if (!ACCESS_FBINFO(outputs[1]).output) {
+					err = -ENXIO;
+				} else if (ACCESS_FBINFO(outputs[1]).output->setctrl) {
+					err = ACCESS_FBINFO(outputs[1]).output->setctrl(ACCESS_FBINFO(outputs[1]).data, &ctrl);
+				} else {
+					err = -EINVAL;
+				}
+				up_read(&ACCESS_FBINFO(altout).lock);
+				return err;
 			}
 	}
-	return -EINVAL;
+	return -ENOTTY;
 #undef minfo
 }
 
+/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
+
+static int matroxfb_blank(int blank, struct fb_info *info)
+{
+#define minfo (list_entry(info, struct matrox_fb_info, fbcon))
+	int seq;
+	int crtc;
+	CRITFLAGS
+
+	DBG("matroxfb_blank")
+
+	if (ACCESS_FBINFO(dead))
+		return 1;
+
+	switch (blank) {
+		case 1:  seq = 0x20; crtc = 0x00; break; /* works ??? */
+		case 2:  seq = 0x20; crtc = 0x10; break;
+		case 3:  seq = 0x20; crtc = 0x20; break;
+		case 4:  seq = 0x20; crtc = 0x30; break;
+		default: seq = 0x00; crtc = 0x00; break;
+	}
+
+	CRITBEGIN
+
+	mga_outb(M_SEQ_INDEX, 1);
+	mga_outb(M_SEQ_DATA, (mga_inb(M_SEQ_DATA) & ~0x20) | seq);
+	mga_outb(M_EXTVGA_INDEX, 1);
+	mga_outb(M_EXTVGA_DATA, (mga_inb(M_EXTVGA_DATA) & ~0x30) | crtc);
+
+	CRITEND
+	return 0;
+#undef minfo
+}
+
+static void matroxfb_blank24(int blank, struct fb_info *info)
+{
+	matroxfb_blank(blank, info);
+}
+
 static struct fb_ops matroxfb_ops = {
 	owner:		THIS_MODULE,
 	fb_open:	matroxfb_open,
@@ -1178,7 +1350,7 @@
 
 int matroxfb_switch(int con, struct fb_info *info)
 {
-#define minfo ((struct matrox_fb_info*)info)
+#define minfo (list_entry(info, struct matrox_fb_info, fbcon))
 	struct fb_cmap* cmap;
 	struct display *p;
 
@@ -1226,40 +1398,6 @@
 #undef minfo
 }
 
-/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
-
-static void matroxfb_blank(int blank, struct fb_info *info)
-{
-#define minfo ((struct matrox_fb_info*)info)
-	int seq;
-	int crtc;
-	CRITFLAGS
-
-	DBG("matroxfb_blank")
-
-	if (ACCESS_FBINFO(dead))
-		return;
-
-	switch (blank) {
-		case 1:  seq = 0x20; crtc = 0x00; break; /* works ??? */
-		case 2:  seq = 0x20; crtc = 0x10; break;
-		case 3:  seq = 0x20; crtc = 0x20; break;
-		case 4:  seq = 0x20; crtc = 0x30; break;
-		default: seq = 0x00; crtc = 0x00; break;
-	}
-
-	CRITBEGIN
-
-	mga_outb(M_SEQ_INDEX, 1);
-	mga_outb(M_SEQ_DATA, (mga_inb(M_SEQ_DATA) & ~0x20) | seq);
-	mga_outb(M_EXTVGA_INDEX, 1);
-	mga_outb(M_EXTVGA_DATA, (mga_inb(M_EXTVGA_DATA) & ~0x30) | crtc);
-
-	CRITEND
-
-#undef minfo
-}
-
 #define RSDepth(X)	(((X) >> 8) & 0x0F)
 #define RS8bpp		0x1
 #define RS15bpp		0x2
@@ -1407,10 +1545,10 @@
 #define DEVF_VIDEO64BIT		0x0001
 #define	DEVF_SWAPS		0x0002
 #define DEVF_SRCORG		0x0004
-#define DEVF_BOTHDACS		0x0008	/* put CRTC1 on both outputs by default */
+#define DEVF_DUALHEAD		0x0008
 #define DEVF_CROSS4MB		0x0010
 #define DEVF_TEXT4B		0x0020
-#define DEVF_DDC_8_2		0x0040
+/* #define DEVF_recycled	0x0040	*/
 /* #define DEVF_recycled	0x0080	*/
 #define DEVF_SUPPORT32MB	0x0100
 #define DEVF_ANY_VXRES		0x0200
@@ -1420,14 +1558,14 @@
 #define DEVF_PANELLINK_CAPABLE	0x2000
 #define DEVF_G450DAC		0x4000
 
-#define DEVF_GCORE	(DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB | DEVF_DDC_8_2)
-#define DEVF_G2CORE	(DEVF_GCORE | DEVF_ANY_VXRES | DEVF_MAVEN_CAPABLE | DEVF_PANELLINK_CAPABLE | DEVF_SRCORG)
+#define DEVF_GCORE	(DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB)
+#define DEVF_G2CORE	(DEVF_GCORE | DEVF_ANY_VXRES | DEVF_MAVEN_CAPABLE | DEVF_PANELLINK_CAPABLE | DEVF_SRCORG | DEVF_DUALHEAD)
 #define DEVF_G100	(DEVF_GCORE) /* no doc, no vxres... */
 #define DEVF_G200	(DEVF_G2CORE)
 #define DEVF_G400	(DEVF_G2CORE | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2)
 /* if you'll find how to drive DFP... */
-#define DEVF_G450	(DEVF_GCORE | DEVF_ANY_VXRES | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2 | DEVF_G450DAC | DEVF_SRCORG)
-#define DEVF_G550	(DEVF_G450 | DEVF_BOTHDACS)
+#define DEVF_G450	(DEVF_GCORE | DEVF_ANY_VXRES | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2 | DEVF_G450DAC | DEVF_SRCORG | DEVF_DUALHEAD)
+#define DEVF_G550	(DEVF_G450)
 
 static struct board {
 	unsigned short vendor, device, rev, svid, sid;
@@ -1621,27 +1759,24 @@
 		ACCESS_FBINFO(devflags.text_type_aux) = FB_AUX_TEXT_MGA_STEP8;
 	}
 #ifdef CONFIG_FB_MATROX_32MB
-	ACCESS_FBINFO(devflags.support32MB) = b->flags & DEVF_SUPPORT32MB;
+	ACCESS_FBINFO(devflags.support32MB) = (b->flags & DEVF_SUPPORT32MB) != 0;
 #endif
 	ACCESS_FBINFO(devflags.precise_width) = !(b->flags & DEVF_ANY_VXRES);
-	ACCESS_FBINFO(devflags.crtc2) = b->flags & DEVF_CRTC2;
-	ACCESS_FBINFO(devflags.maven_capable) = b->flags & DEVF_MAVEN_CAPABLE;
+	ACCESS_FBINFO(devflags.crtc2) = (b->flags & DEVF_CRTC2) != 0;
+	ACCESS_FBINFO(devflags.maven_capable) = (b->flags & DEVF_MAVEN_CAPABLE) != 0;
+	ACCESS_FBINFO(devflags.dualhead) = (b->flags & DEVF_DUALHEAD) != 0;
 	if (b->flags & DEVF_PANELLINK_CAPABLE) {
-		ACCESS_FBINFO(output.all) |= MATROXFB_OUTPUT_CONN_DFP;
+		ACCESS_FBINFO(outputs[2]).data = MINFO;
+		ACCESS_FBINFO(outputs[2]).output = &panellink_output;
 		if (dfp)
-			ACCESS_FBINFO(output.ph) |= MATROXFB_OUTPUT_CONN_DFP;
-	}
-	if (b->flags & DEVF_BOTHDACS) {
-#ifdef CONFIG_FB_MATROX_G450	
-		ACCESS_FBINFO(output.all) |= MATROXFB_OUTPUT_CONN_SECONDARY;
-		ACCESS_FBINFO(output.ph) |= MATROXFB_OUTPUT_CONN_SECONDARY;
-#else
-		printk(KERN_INFO "Only digital output of G550 is now working (in analog mode). Enable G450 support in\n");
-		printk(KERN_INFO "kernel configuration if you have analog monitor connected to G550 analog output.\n");
-#endif
+			ACCESS_FBINFO(outputs[2]).src = MATROXFB_SRC_CRTC1;
+		else
+			ACCESS_FBINFO(outputs[2]).src = MATROXFB_SRC_NONE;
+		ACCESS_FBINFO(outputs[2]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
+		ACCESS_FBINFO(devflags.panellink) = 1;
 	}
 	ACCESS_FBINFO(devflags.dfp_type) = dfp_type;
-	ACCESS_FBINFO(devflags.g450dac) = b->flags & DEVF_G450DAC;
+	ACCESS_FBINFO(devflags.g450dac) = (b->flags & DEVF_G450DAC) != 0;
 	ACCESS_FBINFO(devflags.textstep) = ACCESS_FBINFO(devflags.vgastep) * ACCESS_FBINFO(devflags.textmode);
 	ACCESS_FBINFO(devflags.textvram) = 65536 / ACCESS_FBINFO(devflags.textmode);
 
@@ -1747,6 +1882,7 @@
 
 	if (!ACCESS_FBINFO(devflags.novga))
 		request_region(0x3C0, 32, "matrox");
+	matroxfb_g450_connect(PMINFO2);
 	ACCESS_FBINFO(hw_switch->reset(PMINFO2));
 
 	ACCESS_FBINFO(fbcon.monspecs.hfmin) = 0;
@@ -1775,7 +1911,7 @@
 	ACCESS_FBINFO(fbcon.disp) = d;
 	ACCESS_FBINFO(fbcon.switch_con) = &matroxfb_switch;
 	ACCESS_FBINFO(fbcon.updatevar) = &matroxfb_updatevar;
-	ACCESS_FBINFO(fbcon.blank) = &matroxfb_blank;
+	ACCESS_FBINFO(fbcon.blank) = &matroxfb_blank24;
 	/* after __init time we are like module... no logo */
 	ACCESS_FBINFO(fbcon.flags) = hotplug ? FBINFO_FLAG_MODULE : FBINFO_FLAG_DEFAULT;
 	ACCESS_FBINFO(video.len_usable) &= PAGE_MASK;
@@ -1907,6 +2043,7 @@
 	}
 	return 0;
 failVideoIO:;
+	matroxfb_g450_shutdown(PMINFO2);
 	mga_iounmap(ACCESS_FBINFO(video.vbase));
 failCtrlIO:;
 	mga_iounmap(ACCESS_FBINFO(mmio.vbase));
@@ -2094,10 +2231,6 @@
 	init_rwsem(&ACCESS_FBINFO(crtc2.lock));
 	init_rwsem(&ACCESS_FBINFO(altout.lock));
 
-	ACCESS_FBINFO(output.all) = MATROXFB_OUTPUT_CONN_PRIMARY;
-	ACCESS_FBINFO(output.ph) = MATROXFB_OUTPUT_CONN_PRIMARY;
-	ACCESS_FBINFO(output.sh) = 0;
-
 	err = initMatrox2(PMINFO d, b);
 	if (!err) {
 #ifndef CONFIG_FB_MATROX_MULTIHEAD
@@ -2511,8 +2644,8 @@
 
 /* *************************** init module code **************************** */
 
-MODULE_AUTHOR("(c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz>");
-MODULE_DESCRIPTION("Accelerated FBDev driver for Matrox Millennium/Mystique/G100/G200/G400/G450");
+MODULE_AUTHOR("(c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_DESCRIPTION("Accelerated FBDev driver for Matrox Millennium/Mystique/G100/G200/G400/G450/G550");
 MODULE_LICENSE("GPL");
 
 MODULE_PARM(mem, "i");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/matrox/matroxfb_base.h linux-2.4.21-pre6/drivers/video/matrox/matroxfb_base.h
--- linux-2.4.20/drivers/video/matrox/matroxfb_base.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/matrox/matroxfb_base.h	2003-03-26 23:49:39.000000000 +0000
@@ -108,7 +108,7 @@
 #endif
 #endif
 
-#if defined(__alpha__) || defined(__m68k__)
+#if defined(__alpha__) || defined(__mc68000__)
 #define READx_WORKS
 #define MEMCPYTOIO_WORKS
 #else
@@ -124,7 +124,7 @@
 #endif
 #endif
 
-#if defined(__m68k__)
+#if defined(__mc68000__)
 #define MAP_BUSTOVIRT
 #else
 #define MAP_IOREMAP
@@ -291,6 +291,8 @@
 
 struct my_timming {
 	unsigned int pixclock;
+	int mnp;
+	unsigned int crtc;
 	unsigned int HDisplay;
 	unsigned int HSyncStart;
 	unsigned int HSyncEnd;
@@ -367,6 +369,10 @@
 	u_int16_t hcorr;
 };
 
+struct matrox_crtc2 {
+	u_int32_t ctl, hparam, hsync, vparam, vsync, preload, datactl;
+};
+
 struct matrox_hw_state {
 	u_int32_t	MXoptionReg;
 	unsigned char	DACclk[6];
@@ -384,10 +390,7 @@
 	/* TVOut only */
 	struct mavenregs	maven;
 
-	/* CRTC2 only */
-	/* u_int32_t	TBD */
-
-	unsigned int	vidclk;
+	struct matrox_crtc2	crtc2;
 };
 
 struct matrox_accel_data {
@@ -398,16 +401,28 @@
 	u_int32_t	m_opmode;
 };
 
+struct matroxfb_queryctrl;
+struct matroxfb_control;
+
 struct matrox_altout {
+	struct module	*owner;
+	const char	*name;
 	int		(*compute)(void* altout_dev, struct my_timming* input);
 	int		(*program)(void* altout_dev);
 	int		(*start)(void* altout_dev);
-	void		(*incuse)(void* altout_dev);
-	void		(*decuse)(void* altout_dev);
-	int		(*setmode)(void* altout_dev, u_int32_t mode);
-	int		(*getmode)(void* altout_dev, u_int32_t* mode);
+	int		(*verifymode)(void* altout_dev, u_int32_t mode);
+	int		(*getqueryctrl)(void* altout_dev,
+					struct matroxfb_queryctrl* ctrl);
+	int		(*getctrl)(void* altout_dev, 
+				   struct matroxfb_control* ctrl);
+	int		(*setctrl)(void* altout_dev, 
+				   struct matroxfb_control* ctrl);
 };
 
+#define MATROXFB_SRC_NONE	0
+#define MATROXFB_SRC_CRTC1	1
+#define MATROXFB_SRC_CRTC2	2
+
 enum mga_chip { MGA_2064, MGA_2164, MGA_1064, MGA_1164, MGA_G100, MGA_G200, MGA_G400, MGA_G450, MGA_G550 };
 
 struct matrox_bios {
@@ -424,9 +439,9 @@
 
 struct matrox_switch;
 struct matroxfb_driver;
+struct matroxfb_dh_fb_info;
 
 struct matrox_fb_info {
-	/* fb_info must be first */
 	struct fb_info		fbcon;
 
 	struct list_head	next_fb;
@@ -442,21 +457,19 @@
 	struct pci_dev*		pcidev;
 
 	struct {
-		u_int32_t	all;
-		u_int32_t	ph;
-		u_int32_t	sh;
-			      } output;
-	struct matrox_altout*	primout;
-	struct {
-	struct fb_info*		info;
 	struct rw_semaphore	lock;
-			      } crtc2;
 	struct {
-	struct matrox_altout*	output;
-	void*			device;
-	struct rw_semaphore	lock;
+		int brightness, contrast, saturation, hue, gamma;
+		int testout, deflicker;
+				} tvo_params;
 			      } altout;
-
+#define MATROXFB_MAX_OUTPUTS		3
+	struct {
+	unsigned int		src;
+	struct matrox_altout*	output;
+	void*			data;
+	unsigned int		mode;
+			      } outputs[MATROXFB_MAX_OUTPUTS];
 #define MATROXFB_MAX_FB_DRIVERS		5
 	struct matroxfb_driver* (drivers[MATROXFB_MAX_FB_DRIVERS]);
 	void*			(drivers_data[MATROXFB_MAX_FB_DRIVERS]);
@@ -545,6 +558,8 @@
 		int		memtype;
 		int		g450dac;
 		int		dfp_type;
+		int		panellink;	/* G400 DFP possible (not G450/G550) */
+		int		dualhead;
 		unsigned int	fbResource;
 			      } devflags;
 	struct display_switch	dispsw;
@@ -561,6 +576,16 @@
 			      } cursor;
 	struct matrox_bios	bios;
 	struct {
+		unsigned int	pixclock;
+		int		mnp;
+			      } crtc1;
+	struct {
+		unsigned int 	pixclock;
+		int		mnp;
+	struct matroxfb_dh_fb_info*	info;
+	struct rw_semaphore	lock;
+			      } crtc2;
+	struct {
 		struct matrox_pll_limits	pixel;
 		struct matrox_pll_limits	system;
 		struct matrox_pll_limits	video;
@@ -625,7 +650,7 @@
 #define PMINFO   PMINFO2 ,
 
 static inline struct matrox_fb_info* mxinfo(const struct display* p) {
-	return (struct matrox_fb_info*)p->fb_info;
+	return list_entry(p->fb_info, struct matrox_fb_info, fbcon);
 }
 
 #define PMXINFO(p)	   mxinfo(p),
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/matrox/matroxfb_crtc2.c linux-2.4.21-pre6/drivers/video/matrox/matroxfb_crtc2.c
--- linux-2.4.20/drivers/video/matrox/matroxfb_crtc2.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/matrox/matroxfb_crtc2.c	2003-03-26 23:49:20.000000000 +0000
@@ -2,11 +2,11 @@
  *
  * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
  *
- * (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz>
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
  *
  * Portions Copyright (c) 2001 Matrox Graphics Inc.
  *
- * Version: 1.62 2001/11/29
+ * Version: 1.64 2002/06/10
  *
  */
 
@@ -28,8 +28,8 @@
 
 static int matroxfb_dh_getcolreg(unsigned regno, unsigned *red, unsigned *green,
 		unsigned *blue, unsigned *transp, struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
-	if (regno > 16)
+#define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
+	if (regno >= 16)
 		return 1;
 	*red = m2info->palette[regno].red;
 	*blue = m2info->palette[regno].blue;
@@ -41,10 +41,10 @@
 
 static int matroxfb_dh_setcolreg(unsigned regno, unsigned red, unsigned green,
 		unsigned blue, unsigned transp, struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
 	struct display* p;
 
-	if (regno > 16)
+	if (regno >= 16)
 		return 1;
 	m2info->palette[regno].red = red;
 	m2info->palette[regno].blue = blue;
@@ -84,86 +84,129 @@
 #undef m2info
 }
 
-static void do_install_cmap(struct matroxfb_dh_fb_info* m2info, struct display* p) {
-	if (p->cmap.len)
-		fb_set_cmap(&p->cmap, 1, matroxfb_dh_setcolreg, &m2info->fbcon);
+static inline void my_install_cmap(struct matroxfb_dh_fb_info* m2info)
+{
+	/* Do not touch this code if you do not understand what it does! */
+	/* Never try to use do_install_cmap() instead. It is crap. */
+	struct fb_cmap* cmap = &m2info->currcon_display->cmap;
+	
+	if (cmap->len)
+		fb_set_cmap(cmap, 1, matroxfb_dh_setcolreg, &m2info->fbcon);
 	else
 		fb_set_cmap(fb_default_cmap(16), 1, matroxfb_dh_setcolreg, &m2info->fbcon);
 }
 
+
 static void matroxfb_dh_restore(struct matroxfb_dh_fb_info* m2info,
 		struct my_timming* mt,
 		struct display* p,
 		int mode,
 		unsigned int pos) {
-	u_int32_t tmp;
+	struct matrox_crtc2 c2;
 	MINFO_FROM(m2info->primary_dev);
 
 	switch (mode) {
 		case 15:
-			tmp = 0x00200000;
+			c2.ctl = 0x00200000;
 			break;
 		case 16:
-			tmp = 0x00400000;
+			c2.ctl = 0x00400000;
 			break;
 /*		case 32: */
 		default:
-			tmp = 0x00800000;
+			c2.ctl = 0x00800000;
 			break;
 	}
-
-	if (ACCESS_FBINFO(output.sh)) {
-		tmp |= 0x00000001;	/* enable CRTC2 */
-
-		if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) {
-			if (ACCESS_FBINFO(devflags.g450dac)) {
-				tmp |= 0x00000006; /* source from secondary pixel PLL */
-				/* no vidrst */
-			} else {
-				tmp |= 0x00000002; /* source from VDOCLK */
-				tmp |= 0xC0000000; /* enable vvidrst & hvidrst */
-				/* MGA TVO is our clock source */
+	c2.ctl |= 0x00000001;	/* enable CRTC2 */
+	c2.datactl = 0;
+	if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC2) {
+		if (ACCESS_FBINFO(devflags.g450dac)) {
+			c2.ctl |= 0x00000006; /* source from secondary pixel PLL */
+			/* no vidrst when in monitor mode */
+			if (ACCESS_FBINFO(outputs[1]).mode != MATROXFB_OUTPUT_MODE_MONITOR) {
+				c2.ctl |=  0xC0001000; /* Enable H/V vidrst */
 			}
-		} else if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) {
-			tmp |= 0x00000004; /* source from pixclock */
-			/* PIXPLL is our clock source */
-		}
-
-		if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY)
-			tmp |= 0x00100000;	/* connect CRTC2 to DAC */
+		} else {
+			c2.ctl |= 0x00000002; /* source from VDOCLK */
+			c2.ctl |= 0xC0000000; /* enable vvidrst & hvidrst */
+			/* MGA TVO is our clock source */
+		}
+	} else if (ACCESS_FBINFO(outputs[0]).src == MATROXFB_SRC_CRTC2) {
+		c2.ctl |= 0x00000004; /* source from pixclock */
+		/* PIXPLL is our clock source */
+	}
+	if (ACCESS_FBINFO(outputs[0]).src == MATROXFB_SRC_CRTC2) {
+		c2.ctl |= 0x00100000;	/* connect CRTC2 to DAC */
 	}
 	if (mt->interlaced) {
-		tmp |= 0x02000000;	/* interlaced, second field is bigger, as G450 apparently ignores it */
+		c2.ctl |= 0x02000000;	/* interlaced, second field is bigger, as G450 apparently ignores it */
 		mt->VDisplay >>= 1;
 		mt->VSyncStart >>= 1;
 		mt->VSyncEnd >>= 1;
 		mt->VTotal >>= 1;
 	}
-	mga_outl(0x3C10, tmp | 0x10000000);	/* depth and so on... 0x10000000 is VIDRST polarity */
-	mga_outl(0x3C14, ((mt->HDisplay - 8) << 16) | (mt->HTotal - 8));
-	mga_outl(0x3C18, ((mt->HSyncEnd - 8) << 16) | (mt->HSyncStart - 8));
-	mga_outl(0x3C1C, ((mt->VDisplay - 1) << 16) | (mt->VTotal - 1));
-	mga_outl(0x3C20, ((mt->VSyncEnd - 1) << 16) | (mt->VSyncStart - 1));
-	mga_outl(0x3C24, ((mt->VSyncStart) << 16) | (mt->HSyncStart));	/* preload */
+	if ((mt->HTotal & 7) == 2) {
+		c2.datactl |= 0x00000010;
+		mt->HTotal &= ~7;
+	}
+	c2.ctl |= 0x10000000;	/* 0x10000000 is VIDRST polarity */
+	c2.hparam = ((mt->HDisplay - 8) << 16) | (mt->HTotal - 8);
+	c2.hsync = ((mt->HSyncEnd - 8) << 16) | (mt->HSyncStart - 8);
+	c2.vparam = ((mt->VDisplay - 1) << 16) | (mt->VTotal - 1);
+	c2.vsync = ((mt->VSyncEnd - 1) << 16) | (mt->VSyncStart - 1);
+	c2.preload = ((mt->VSyncStart) << 16) | (mt->HSyncStart);
+	mga_outl(0x3C14, c2.hparam);
+	mga_outl(0x3C18, c2.hsync);
+	mga_outl(0x3C1C, c2.vparam);
+	mga_outl(0x3C20, c2.vsync);
+	mga_outl(0x3C24, c2.preload);
 	{
 		u_int32_t linelen = p->var.xres_virtual * (p->var.bits_per_pixel >> 3);
-		if (mt->interlaced) {
+		if (c2.ctl & 0x02000000) {
 			/* field #0 is smaller, so... */
 			mga_outl(0x3C2C, pos);			/* field #1 vmemory start */
 			mga_outl(0x3C28, pos + linelen);	/* field #0 vmemory start */
 			linelen <<= 1;
+			m2info->interlaced = 1;
 		} else {
 			mga_outl(0x3C28, pos);		/* vmemory start */
+			m2info->interlaced = 0;
 		}
 		mga_outl(0x3C40, linelen);
 	}
-	tmp = 0x0FFF0000;		/* line compare */
-	if (mt->sync & FB_SYNC_HOR_HIGH_ACT)
-		tmp |= 0x00000100;
-	if (mt->sync & FB_SYNC_VERT_HIGH_ACT)
-		tmp |= 0x00000200;
-	mga_outl(0x3C44, tmp);
-	mga_outl(0x3C4C, 0);		/* data control */
+	mga_outl(0x3C4C, c2.datactl);		/* data control */
+	if (c2.ctl & 0x02000000) {
+		int i;
+
+		mga_outl(0x3C10, c2.ctl & ~0x02000000);
+                for (i = 0; i < 2; i++) {
+                        unsigned int nl;
+                        unsigned int lastl = 0;
+
+                        while ((nl = mga_inl(0x3C48) & 0xFFF) >= lastl) {
+                                lastl = nl;
+                        }
+                }
+	}
+        mga_outl(0x3C10, c2.ctl);
+	ACCESS_FBINFO(hw).crtc2.ctl = c2.ctl;
+	{
+		u_int32_t tmp;
+
+		tmp = 0x0FFF0000;		/* line compare */
+		if (mt->sync & FB_SYNC_HOR_HIGH_ACT)
+			tmp |= 0x00000100;
+		if (mt->sync & FB_SYNC_VERT_HIGH_ACT)
+			tmp |= 0x00000200;
+		mga_outl(0x3C44, tmp);
+	}
+}
+
+static void matroxfb_dh_disable(struct matroxfb_dh_fb_info* m2info) {
+	MINFO_FROM(m2info->primary_dev);
+
+	mga_outl(0x3C10, 0x00000004);	/* disable CRTC2, CRTC1->DAC1, PLL as clock source */
+	ACCESS_FBINFO(hw).crtc2.ctl = 0x00000004;
 }
 
 static void matroxfb_dh_cfbX_init(struct matroxfb_dh_fb_info* m2info,
@@ -176,19 +219,18 @@
 	unsigned int pos;
 	unsigned int linelen;
 	unsigned int pixelsize;
+	MINFO_FROM(m2info->primary_dev);
 
-#define minfo (m2info->primary_dev)
 	pixelsize = var->bits_per_pixel >> 3;
 	linelen = var->xres_virtual * pixelsize;
 	pos = var->yoffset * linelen + var->xoffset * pixelsize;
 	pos += m2info->video.offbase;
-	if (var->vmode & FB_VMODE_INTERLACED) {
+	if (m2info->interlaced) {
 		mga_outl(0x3C2C, pos);
 		mga_outl(0x3C28, pos + linelen);
 	} else {
 		mga_outl(0x3C28, pos);
 	}
-#undef minfo
 }
 
 static int matroxfb_dh_decode_var(struct matroxfb_dh_fb_info* m2info,
@@ -292,7 +334,7 @@
 }
 
 static int matroxfb_dh_open(struct fb_info* info, int user) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
 	MINFO_FROM(m2info->primary_dev);
 
 	if (MINFO) {
@@ -305,7 +347,7 @@
 }
 
 static int matroxfb_dh_release(struct fb_info* info, int user) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
 	MINFO_FROM(m2info->primary_dev);
 
 	if (MINFO) {
@@ -316,7 +358,7 @@
 
 static int matroxfb_dh_get_fix(struct fb_fix_screeninfo* fix, int con,
 		struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
 	struct display* p;
 
 	if (con >= 0)
@@ -345,7 +387,7 @@
 
 static int matroxfb_dh_get_var(struct fb_var_screeninfo* var, int con,
 		struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
 	if (con < 0)
 		*var = m2info->fbcon.disp->var;
 	else
@@ -356,7 +398,7 @@
 
 static int matroxfb_dh_set_var(struct fb_var_screeninfo* var, int con,
 		struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
 	struct display* p;
 	int chgvar;
 	int visual;
@@ -390,7 +432,7 @@
 		chgvar = 0;
 	p->var = *var;
 	/* cmap */
-	p->screen_base = vaddr_va(m2info->video.vbase);
+	p->screen_base = m2info->fbcon.screen_base = vaddr_va(m2info->video.vbase);
 	p->visual = visual;
 	p->ypanstep = 1;
 	p->ywrapstep = 0;
@@ -405,48 +447,52 @@
 	if (con == m2info->currcon) {
 		struct my_timming mt;
 		unsigned int pos;
+		int out;
+		int cnt;
 
 		matroxfb_var2my(var, &mt);
+		mt.crtc = MATROXFB_SRC_CRTC2;
 		/* CRTC2 delay */
 		mt.delay = 34;
 
 		pos = (var->yoffset * var->xres_virtual + var->xoffset) * var->bits_per_pixel >> 3;
 		pos += m2info->video.offbase;
-		DAC1064_global_init(PMINFO2);
-		if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) {
-			if (ACCESS_FBINFO(primout))
-				ACCESS_FBINFO(primout)->compute(MINFO, &mt);
+		cnt = 0;
+		down_read(&ACCESS_FBINFO(altout).lock);
+		for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+			if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2) {
+				cnt++;
+				if (ACCESS_FBINFO(outputs[out]).output->compute) {
+					ACCESS_FBINFO(outputs[out]).output->compute(ACCESS_FBINFO(outputs[out]).data, &mt);
+				}
+			}
 		}
-		if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) {
-			down_read(&ACCESS_FBINFO(altout.lock));
-			if (ACCESS_FBINFO(altout.output))
-				ACCESS_FBINFO(altout.output)->compute(ACCESS_FBINFO(altout.device), &mt);
-			up_read(&ACCESS_FBINFO(altout.lock));
+		ACCESS_FBINFO(crtc2).pixclock = mt.pixclock;
+		ACCESS_FBINFO(crtc2).mnp = mt.mnp;
+		up_read(&ACCESS_FBINFO(altout).lock);
+		if (cnt) {
+			matroxfb_dh_restore(m2info, &mt, p, mode, pos);
+		} else {
+			matroxfb_dh_disable(m2info);
 		}
-		matroxfb_dh_restore(m2info, &mt, p, mode, pos);
+		DAC1064_global_init(PMINFO2);
 		DAC1064_global_restore(PMINFO2);
-		if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) {
-			if (ACCESS_FBINFO(primout))
-				ACCESS_FBINFO(primout)->program(MINFO);
-		}
-		if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) {
-			down_read(&ACCESS_FBINFO(altout.lock));
-			if (ACCESS_FBINFO(altout.output))
-				ACCESS_FBINFO(altout.output)->program(ACCESS_FBINFO(altout.device));
-			up_read(&ACCESS_FBINFO(altout.lock));
-		}
-		if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) {
-			if (ACCESS_FBINFO(primout))
-				ACCESS_FBINFO(primout)->start(MINFO);
+		down_read(&ACCESS_FBINFO(altout).lock);
+		for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+			if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2 &&
+			    ACCESS_FBINFO(outputs[out]).output->program) {
+				ACCESS_FBINFO(outputs[out]).output->program(ACCESS_FBINFO(outputs[out]).data);
+			}
 		}
-		if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) {
-			down_read(&ACCESS_FBINFO(altout.lock));
-			if (ACCESS_FBINFO(altout.output))
-				ACCESS_FBINFO(altout.output)->start(ACCESS_FBINFO(altout.device));
-			up_read(&ACCESS_FBINFO(altout.lock));
+		for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+			if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2 &&
+			    ACCESS_FBINFO(outputs[out]).output->start) {
+				ACCESS_FBINFO(outputs[out]).output->start(ACCESS_FBINFO(outputs[out]).data);
+			}
 		}
+		up_read(&ACCESS_FBINFO(altout).lock);
 		matroxfb_dh_cfbX_init(m2info, p);
-		do_install_cmap(m2info, p);
+		my_install_cmap(m2info);
 	}
 	return 0;
 #undef m2info
@@ -454,7 +500,7 @@
 
 static int matroxfb_dh_get_cmap(struct fb_cmap* cmap, int kspc, int con,
 		struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
 	struct display* dsp;
 
 	if (con < 0)
@@ -473,7 +519,7 @@
 
 static int matroxfb_dh_set_cmap(struct fb_cmap* cmap, int kspc, int con,
 		struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
 	struct display* dsp;
 
 	if (con < 0)
@@ -497,7 +543,7 @@
 
 static int matroxfb_dh_pan_display(struct fb_var_screeninfo* var, int con,
 		struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
 	if (var->xoffset + fb_display[con].var.xres > fb_display[con].var.xres_virtual ||
 	    var->yoffset + fb_display[con].var.yres > fb_display[con].var.yres_virtual)
 		return -EINVAL;
@@ -530,7 +576,7 @@
 		unsigned long arg,
 		int con,
 		struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
 	MINFO_FROM(m2info->primary_dev);
 
 	DBG("matroxfb_crtc2_ioctl")
@@ -557,38 +603,84 @@
 		case MATROXFB_SET_OUTPUT_CONNECTION:
 			{
 				u_int32_t tmp;
+				int out;
+				int changes;
 
 				if (get_user(tmp, (u_int32_t*)arg))
 					return -EFAULT;
-				if (tmp & ~ACCESS_FBINFO(output.all))
-					return -EINVAL;
-				if (tmp & ACCESS_FBINFO(output.ph))
-					return -EINVAL;
-				if (tmp & MATROXFB_OUTPUT_CONN_DFP)
-					return -EINVAL;
-				if ((ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP) && tmp)
-					return -EINVAL;
-				if (tmp == ACCESS_FBINFO(output.sh))
+				for (out = 0; out < 32; out++) {
+					if (tmp & (1 << out)) {
+						if (out >= MATROXFB_MAX_OUTPUTS)
+							return -ENXIO;
+						if (!ACCESS_FBINFO(outputs[out]).output)
+							return -ENXIO;
+						switch (ACCESS_FBINFO(outputs[out]).src) {
+							case MATROXFB_SRC_NONE:
+							case MATROXFB_SRC_CRTC2:
+								break;
+							default:
+								return -EBUSY;
+						}
+					}
+				}
+				if (ACCESS_FBINFO(devflags.panellink)) {
+					if (tmp & MATROXFB_OUTPUT_CONN_DFP)
+						return -EINVAL;
+					if ((ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_CRTC1) && tmp)
+						return -EBUSY;
+				}
+				changes = 0;
+				for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+					if (tmp & (1 << out)) {
+						if (ACCESS_FBINFO(outputs[out]).src != MATROXFB_SRC_CRTC2) {
+							changes = 1;
+							ACCESS_FBINFO(outputs[out]).src = MATROXFB_SRC_CRTC2;
+						}
+					} else if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2) {
+						changes = 1;
+						ACCESS_FBINFO(outputs[out]).src = MATROXFB_SRC_NONE;
+					}
+				}
+				if (!changes)
 					return 0;
-				ACCESS_FBINFO(output.sh) = tmp;
 				matroxfb_dh_switch(m2info->currcon, info);
 				return 0;
 			}
 		case MATROXFB_GET_OUTPUT_CONNECTION:
 			{
-				if (put_user(ACCESS_FBINFO(output.sh), (u_int32_t*)arg))
+				u_int32_t conn = 0;
+				int out;
+
+				for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+					if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2) {
+						conn |= 1 << out;
+					}
+				}
+				if (put_user(conn, (u_int32_t*)arg))
 					return -EFAULT;
 				return 0;
 			}
 		case MATROXFB_GET_AVAILABLE_OUTPUTS:
 			{
-				u_int32_t tmp;
+				u_int32_t tmp = 0;
+				int out;
 
-				/* we do not support DFP from CRTC2 */
-				tmp = ACCESS_FBINFO(output.all) & ~ACCESS_FBINFO(output.ph) & ~MATROXFB_OUTPUT_CONN_DFP;
-				/* CRTC1 in DFP mode disables CRTC2 at all (I know, I'm lazy) */
-				if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP)
-					tmp = 0;
+				for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+					if (ACCESS_FBINFO(outputs[out]).output) {
+						switch (ACCESS_FBINFO(outputs[out]).src) {
+							case MATROXFB_SRC_NONE:
+							case MATROXFB_SRC_CRTC2:
+								tmp |= 1 << out;
+								break;
+						}
+					}
+				}
+				if (ACCESS_FBINFO(devflags.panellink)) {
+					tmp &= ~MATROXFB_OUTPUT_CONN_DFP;
+					if (ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_CRTC1) {
+						tmp = 0;
+					}
+				}
 				if (put_user(tmp, (u_int32_t*)arg))
 					return -EFAULT;
 				return 0;
@@ -598,6 +690,24 @@
 #undef m2info
 }
 
+static int matroxfb_dh_blank(int blank, struct fb_info* info) {
+#define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
+	switch (blank) {
+		case 1:
+		case 2:
+		case 3:
+		case 4:
+		default:;
+	}
+	/* do something... */
+	return 0;
+#undef m2info
+}
+
+static void matroxfb_dh_blank24(int blank, struct fb_info* info) {
+	matroxfb_dh_blank(blank, info);
+}
+
 static struct fb_ops matroxfb_dh_ops = {
 	owner:		THIS_MODULE,
 	fb_open:	matroxfb_dh_open,
@@ -612,7 +722,7 @@
 };
 
 static int matroxfb_dh_switch(int con, struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
 	struct fb_cmap* cmap;
 	struct display* p;
 
@@ -635,25 +745,12 @@
 }
 
 static int matroxfb_dh_updatevar(int con, struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
 	matroxfb_dh_pan_var(m2info, &fb_display[con].var);
 	return 0;
 #undef m2info
 }
 
-static void matroxfb_dh_blank(int blank, struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
-	switch (blank) {
-		case 1:
-		case 2:
-		case 3:
-		case 4:
-		default:;
-	}
-	/* do something... */
-#undef m2info
-}
-
 static struct fb_var_screeninfo matroxfb_dh_defined = {
 		640,480,640,480,/* W,H, virtual W,H */
 		0,0,		/* offset */
@@ -692,7 +789,7 @@
 	m2info->fbcon.disp = d;
 	m2info->fbcon.switch_con = &matroxfb_dh_switch;
 	m2info->fbcon.updatevar = &matroxfb_dh_updatevar;
-	m2info->fbcon.blank = &matroxfb_dh_blank;
+	m2info->fbcon.blank = &matroxfb_dh_blank24;
 	m2info->fbcon.flags = FBINFO_FLAG_DEFAULT;
 	m2info->currcon = -1;
 	m2info->currcon_display = d;
@@ -722,11 +819,10 @@
 	/*
 	 *  If we have unused output, connect CRTC2 to it...
 	 */
-	if ((ACCESS_FBINFO(output.all) & MATROXFB_OUTPUT_CONN_SECONDARY) && 
-	   !(ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) &&
-	   !(ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP)) {
-		ACCESS_FBINFO(output.sh) |= MATROXFB_OUTPUT_CONN_SECONDARY;
-		ACCESS_FBINFO(output.sh) &= ~MATROXFB_OUTPUT_CONN_DFP;
+	if (ACCESS_FBINFO(outputs[1]).output &&
+	    ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_NONE &&
+	    ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_NONE) {
+		ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_CRTC2;
 	}
 
 	matroxfb_dh_set_var(&matroxfb_dh_defined, -2, &m2info->fbcon);
@@ -739,7 +835,7 @@
 	}
 	down_write(&ACCESS_FBINFO(crtc2.lock));
 	oldcrtc2 = ACCESS_FBINFO(crtc2.info);
-	ACCESS_FBINFO(crtc2.info) = &m2info->fbcon;
+	ACCESS_FBINFO(crtc2.info) = m2info;
 	up_write(&ACCESS_FBINFO(crtc2.lock));
 	if (oldcrtc2) {
 		printk(KERN_ERR "matroxfb_crtc2: Internal consistency check failed: crtc2 already present: %p\n",
@@ -768,16 +864,16 @@
 #define minfo (m2info->primary_dev)
 	if (m2info->fbcon_registered) {
 		int id;
-		struct fb_info* crtc2;
+		struct matroxfb_dh_fb_info* crtc2;
 
 		down_write(&ACCESS_FBINFO(crtc2.lock));
 		crtc2 = ACCESS_FBINFO(crtc2.info);
-		if (crtc2 == &m2info->fbcon)
+		if (crtc2 == m2info)
 			ACCESS_FBINFO(crtc2.info) = NULL;
 		up_write(&ACCESS_FBINFO(crtc2.lock));
-		if (crtc2 != &m2info->fbcon) {
+		if (crtc2 != m2info) {
 			printk(KERN_ERR "matroxfb_crtc2: Internal consistency check failed: crtc2 mismatch at unload: %p != %p\n",
-				crtc2, &m2info->fbcon);
+				crtc2, m2info);
 			printk(KERN_ERR "matroxfb_crtc2: Expect kernel crash after module unload.\n");
 			return;
 		}
@@ -815,6 +911,7 @@
 
 static void matroxfb_crtc2_remove(struct matrox_fb_info* minfo, void* crtc2) {
 	matroxfb_dh_deregisterfb(crtc2);
+	kfree(crtc2);
 }
 
 static struct matroxfb_driver crtc2 = {
@@ -831,7 +928,7 @@
 	matroxfb_unregister_driver(&crtc2);
 }
 
-MODULE_AUTHOR("(c) 1999-2001 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
 MODULE_DESCRIPTION("Matrox G400 CRTC2 driver");
 MODULE_LICENSE("GPL");
 module_init(matroxfb_crtc2_init);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/matrox/matroxfb_crtc2.h linux-2.4.21-pre6/drivers/video/matrox/matroxfb_crtc2.h
--- linux-2.4.20/drivers/video/matrox/matroxfb_crtc2.h	2000-12-11 21:16:53.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/matrox/matroxfb_crtc2.h	2003-03-26 23:49:08.000000000 +0000
@@ -29,6 +29,8 @@
 
 	int			currcon;
 	struct display*		currcon_display;
+	
+	int			interlaced:1;
 
 	union {
 #ifdef FBCON_HAS_CFB16
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/matrox/matroxfb_g450.c linux-2.4.21-pre6/drivers/video/matrox/matroxfb_g450.c
--- linux-2.4.20/drivers/video/matrox/matroxfb_g450.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/matrox/matroxfb_g450.c	2003-03-26 23:49:20.000000000 +0000
@@ -2,145 +2,634 @@
  *
  * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
  *
- * (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz>
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
  *
  * Portions Copyright (c) 2001 Matrox Graphics Inc.
  *
- * Version: 1.62 2001/11/29
+ * Version: 1.64 2002/06/02
  *
  * See matroxfb_base.c for contributors.
  *
  */
 
-#include "matroxfb_g450.h"
+#include "matroxfb_base.h"
 #include "matroxfb_misc.h"
 #include "matroxfb_DAC1064.h"
 #include "g450_pll.h"
 #include <linux/matroxfb.h>
 #include <asm/uaccess.h>
+#include <asm/div64.h>
 
-static int matroxfb_g450_compute(void* md, struct my_timming* mt) {
-#define m2info ((struct matroxfb_g450_info*)md)
-#define minfo (m2info->primary_dev)
-	ACCESS_FBINFO(hw).vidclk = mt->pixclock;
-#undef minfo
-#undef m2info
-	return 0;
+/* Definition of the various controls */
+struct mctl {
+	struct matroxfb_queryctrl desc;
+	size_t control;
+};
+
+#define BLMIN	0xF3
+#define WLMAX	0x3FF
+
+static const struct mctl g450_controls[] =
+{	{ { MATROXFB_CID_BRIGHTNESS,
+	  "brightness",
+	  0, WLMAX-BLMIN, 1, 370-BLMIN, 
+	  MATROXFB_CTRL_TYPE_INTEGER, 0, 0,
+	  "picture"
+	}, offsetof(struct matrox_fb_info, altout.tvo_params.brightness) },
+	{ { MATROXFB_CID_CONTRAST,
+	  "contrast",
+	  0, 1023, 1, 127, 
+	  MATROXFB_CTRL_TYPE_INTEGER, 0, 0,
+	  "picture"
+	}, offsetof(struct matrox_fb_info, altout.tvo_params.contrast) },
+	{ { MATROXFB_CID_SATURATION,
+	  "saturation",
+	  0, 255, 1, 165, 
+	  MATROXFB_CTRL_TYPE_INTEGER, 0, 0,
+	  "picture"
+	}, offsetof(struct matrox_fb_info, altout.tvo_params.saturation) },
+	{ { MATROXFB_CID_HUE,
+	  "hue",
+	  0, 255, 1, 0, 
+	  MATROXFB_CTRL_TYPE_INTEGER, 0, 0,
+	  "picture"
+	}, offsetof(struct matrox_fb_info, altout.tvo_params.hue) },
+	{ { MATROXFB_CID_TESTOUT,
+	  "test output",
+	  0, 1, 1, 0, 
+	  MATROXFB_CTRL_TYPE_BOOLEAN, 0, 0,
+	  "picture"
+	}, offsetof(struct matrox_fb_info, altout.tvo_params.testout) },
+};
+
+#define G450CTRLS (sizeof(g450_controls)/sizeof(g450_controls[0]))
+
+/* Return: positive number: id found
+           -EINVAL:         id not found, return failure
+	   -ENOENT:         id not found, create fake disabled control */
+static int get_ctrl_id(__u32 v4l2_id) {
+	int i;
+
+	for (i = 0; i < G450CTRLS; i++) {
+		if (v4l2_id < g450_controls[i].desc.id) {
+			if (g450_controls[i].desc.id == 0x08000000) {
+				return -EINVAL;
+			}
+			return -ENOENT;
+		}
+		if (v4l2_id == g450_controls[i].desc.id) {
+			return i;
+		}
+	}
+	return -EINVAL;
 }
 
-static int matroxfb_g450_program(void* md) {
-#define m2info ((struct matroxfb_g450_info*)md)
-#define minfo (m2info->primary_dev)
-	matroxfb_g450_setclk(PMINFO ACCESS_FBINFO(hw).vidclk, M_VIDEO_PLL);
-#undef minfo
-#undef m2info	
-	return 0;
+static inline int* get_ctrl_ptr(WPMINFO unsigned int idx) {
+	return (int*)((char*)MINFO + g450_controls[idx].control);
 }
 
-static int matroxfb_g450_start(void* md) {
-	return 0;
+static void tvo_fill_defaults(WPMINFO2) {
+	unsigned int i;
+	
+	for (i = 0; i < G450CTRLS; i++) {
+		*get_ctrl_ptr(PMINFO i) = g450_controls[i].desc.default_value;
+	}
 }
 
-static void matroxfb_g450_incuse(void* md) {
-	MOD_INC_USE_COUNT;
+static int cve2_get_reg(WPMINFO int reg) {
+	unsigned long flags;
+	int val;
+	
+	matroxfb_DAC_lock_irqsave(flags);
+	matroxfb_DAC_out(PMINFO 0x87, reg);
+	val = matroxfb_DAC_in(PMINFO 0x88);
+	matroxfb_DAC_unlock_irqrestore(flags);
+	return val;
 }
 
-static void matroxfb_g450_decuse(void* md) {
-	MOD_DEC_USE_COUNT;
+static void cve2_set_reg(WPMINFO int reg, int val) {
+	unsigned long flags;
+
+	matroxfb_DAC_lock_irqsave(flags);
+	matroxfb_DAC_out(PMINFO 0x87, reg);
+	matroxfb_DAC_out(PMINFO 0x88, val);
+	matroxfb_DAC_unlock_irqrestore(flags);
+}
+
+static void cve2_set_reg10(WPMINFO int reg, int val) {
+	unsigned long flags;
+
+	matroxfb_DAC_lock_irqsave(flags);
+	matroxfb_DAC_out(PMINFO 0x87, reg);
+	matroxfb_DAC_out(PMINFO 0x88, val >> 2);
+	matroxfb_DAC_out(PMINFO 0x87, reg + 1);
+	matroxfb_DAC_out(PMINFO 0x88, val & 3);
+	matroxfb_DAC_unlock_irqrestore(flags);
+}
+
+static void g450_compute_bwlevel(CPMINFO int *bl, int *wl) {
+	const int b = ACCESS_FBINFO(altout.tvo_params.brightness) + BLMIN;
+	const int c = ACCESS_FBINFO(altout.tvo_params.contrast);
+
+	*bl = max(b - c, BLMIN);
+	*wl = min(b + c, WLMAX);
 }
 
-static int matroxfb_g450_set_mode(void* md, u_int32_t arg) {
-	if (arg == MATROXFB_OUTPUT_MODE_MONITOR) {
-		return 1;
+static int g450_query_ctrl(void* md, struct matroxfb_queryctrl *p) {
+	int i;
+	
+	i = get_ctrl_id(p->id);
+	if (i >= 0) {
+		*p = g450_controls[i].desc;
+		return 0;
+	}
+	if (i == -ENOENT) {
+		static const struct matroxfb_queryctrl disctrl = 
+			{ 0, "", 0, 0, 0, 0, 0, 1, 1, "Disabled" };
+			
+		i = p->id;
+		*p = disctrl;
+		p->id = i;
+		sprintf(p->name, "Ctrl #%08X", i);
+		return 0;
 	}
 	return -EINVAL;
 }
 
-static int matroxfb_g450_get_mode(void* md, u_int32_t* arg) {
-	*arg = MATROXFB_OUTPUT_MODE_MONITOR;
+static int g450_set_ctrl(void* md, struct matroxfb_control *p) {
+	int i;
+	MINFO_FROM(md);
+	
+	i = get_ctrl_id(p->id);
+	if (i < 0) return -EINVAL;
+
+	/*
+	 * Check if changed.
+	 */
+	if (p->value == *get_ctrl_ptr(PMINFO i)) return 0;
+
+	/*
+	 * Check limits.
+	 */
+	if (p->value > g450_controls[i].desc.maximum) return -EINVAL;
+	if (p->value < g450_controls[i].desc.minimum) return -EINVAL;
+
+	/*
+	 * Store new value.
+	 */
+	*get_ctrl_ptr(PMINFO i) = p->value;
+
+	switch (p->id) {
+		case MATROXFB_CID_BRIGHTNESS:
+		case MATROXFB_CID_CONTRAST:
+			{
+				int blacklevel, whitelevel;
+				g450_compute_bwlevel(PMINFO &blacklevel, &whitelevel);
+				cve2_set_reg10(PMINFO 0x0e, blacklevel);
+				cve2_set_reg10(PMINFO 0x1e, whitelevel);
+			}
+			break;
+		case MATROXFB_CID_SATURATION:
+			cve2_set_reg(PMINFO 0x20, p->value);
+			cve2_set_reg(PMINFO 0x22, p->value);
+			break;
+		case MATROXFB_CID_HUE:
+			cve2_set_reg(PMINFO 0x25, p->value);
+			break;
+		case MATROXFB_CID_TESTOUT:
+			{
+				unsigned char val = cve2_get_reg (PMINFO 0x05);
+				if (p->value) val |=  0x02;
+				else          val &= ~0x02;
+				cve2_set_reg(PMINFO 0x05, val);
+			}
+			break;
+	}
+	
+
+	return 0;
+}
+
+static int g450_get_ctrl(void* md, struct matroxfb_control *p) {
+	int i;
+	MINFO_FROM(md);
+	
+	i = get_ctrl_id(p->id);
+	if (i < 0) return -EINVAL;
+	p->value = *get_ctrl_ptr(PMINFO i);
 	return 0;
 }
 
-static struct matrox_altout matroxfb_g450_altout = {
-	matroxfb_g450_compute,
-	matroxfb_g450_program,
-	matroxfb_g450_start,
-	matroxfb_g450_incuse,
-	matroxfb_g450_decuse,
-	matroxfb_g450_set_mode,
-	matroxfb_g450_get_mode
+struct output_desc {
+	unsigned int	h_vis;
+	unsigned int	h_f_porch;
+	unsigned int	h_sync;
+	unsigned int	h_b_porch;
+	unsigned long long int	chromasc;
+	unsigned int	burst;
+	unsigned int	v_total;
 };
 
-static int matroxfb_g450_connect(struct matroxfb_g450_info* m2info) {
-	MINFO_FROM(m2info->primary_dev);
+static void computeRegs(WPMINFO struct mavenregs* r, struct my_timming* mt, const struct output_desc* outd) {
+	u_int32_t chromasc;
+	u_int32_t hlen;
+	u_int32_t hsl;
+	u_int32_t hbp;
+	u_int32_t hfp;
+	u_int32_t hvis;
+	unsigned int pixclock;
+	unsigned long long piic;
+	int mnp;
+	int over;
+	
+	r->regs[0x80] = 0x03;	/* | 0x40 for SCART */
 
-	down_write(&ACCESS_FBINFO(altout.lock));
-	ACCESS_FBINFO(altout.device) = m2info;
-	ACCESS_FBINFO(altout.output) = &matroxfb_g450_altout;
-	up_write(&ACCESS_FBINFO(altout.lock));
-	ACCESS_FBINFO(output.all) |= MATROXFB_OUTPUT_CONN_SECONDARY;
-	matroxfb_switch(ACCESS_FBINFO(currcon), (struct fb_info*)MINFO);	
-	return 0;
+	hvis = ((mt->HDisplay << 1) + 3) & ~3;
+	
+	if (hvis >= 2048) {
+		hvis = 2044;
+	}
+	
+	piic = 1000000000ULL * hvis;
+	do_div(piic, outd->h_vis);
+
+	dprintk(KERN_DEBUG "Want %u kHz pixclock\n", (unsigned int)piic);
+	
+	mnp = matroxfb_g450_setclk(PMINFO piic, M_VIDEO_PLL);
+	
+	mt->mnp = mnp;
+	mt->pixclock = g450_mnp2f(PMINFO mnp);
+
+	dprintk(KERN_DEBUG "MNP=%08X\n", mnp);
+
+	pixclock = 1000000000U / mt->pixclock;
+
+	dprintk(KERN_DEBUG "Got %u ps pixclock\n", pixclock);
+
+	piic = outd->chromasc;
+	do_div(piic, mt->pixclock);
+	chromasc = piic;
+	
+	dprintk(KERN_DEBUG "Chroma is %08X\n", chromasc);
+
+	r->regs[0] = piic >> 24;
+	r->regs[1] = piic >> 16;
+	r->regs[2] = piic >>  8;
+	r->regs[3] = piic >>  0;
+	hbp = (((outd->h_b_porch + pixclock) / pixclock)) & ~1;
+	hfp = (((outd->h_f_porch + pixclock) / pixclock)) & ~1;
+	hsl = (((outd->h_sync + pixclock) / pixclock)) & ~1;
+	hlen = hvis + hfp + hsl + hbp;
+	over = hlen & 0x0F;
+	
+	dprintk(KERN_DEBUG "WL: vis=%u, hf=%u, hs=%u, hb=%u, total=%u\n", hvis, hfp, hsl, hbp, hlen);
+
+	if (over) {
+		hfp -= over;
+		hlen -= over;
+		if (over <= 2) {
+		} else if (over < 10) {
+			hfp += 4;
+			hlen += 4;
+		} else {
+			hfp += 16;
+			hlen += 16;
+		}
+	}
+
+	/* maybe cve2 has requirement 800 < hlen < 1184 */
+	r->regs[0x08] = hsl;
+	r->regs[0x09] = (outd->burst + pixclock - 1) / pixclock;	/* burst length */
+	r->regs[0x0A] = hbp;
+	r->regs[0x2C] = hfp;
+	r->regs[0x31] = hvis / 8;
+	r->regs[0x32] = hvis & 7;
+	
+	dprintk(KERN_DEBUG "PG: vis=%04X, hf=%02X, hs=%02X, hb=%02X, total=%04X\n", hvis, hfp, hsl, hbp, hlen);
+
+	r->regs[0x84] = 1;	/* x sync point */
+	r->regs[0x85] = 0;
+	hvis = hvis >> 1;
+	hlen = hlen >> 1;
+	
+	dprintk(KERN_DEBUG "hlen=%u hvis=%u\n", hlen, hvis);
+
+	mt->interlaced = 1;
+
+	mt->HDisplay = hvis & ~7;
+	mt->HSyncStart = mt->HDisplay + 8;
+	mt->HSyncEnd = (hlen & ~7) - 8;
+	mt->HTotal = hlen;
+
+	{
+		int upper;
+		unsigned int vtotal;
+		unsigned int vsyncend;
+		unsigned int vdisplay;
+		
+		vtotal = mt->VTotal;
+		vsyncend = mt->VSyncEnd;
+		vdisplay = mt->VDisplay;
+		if (vtotal < outd->v_total) {
+			unsigned int yovr = outd->v_total - vtotal;
+			
+			vsyncend += yovr >> 1;
+		} else if (vtotal > outd->v_total) {
+			vdisplay = outd->v_total - 4;
+			vsyncend = outd->v_total;
+		}
+		upper = (outd->v_total - vsyncend) >> 1;	/* in field lines */
+		r->regs[0x17] = outd->v_total / 4;
+		r->regs[0x18] = outd->v_total & 3;
+		r->regs[0x33] = upper - 1;	/* upper blanking */
+		r->regs[0x82] = upper;		/* y sync point */
+		r->regs[0x83] = upper >> 8;
+		
+		mt->VDisplay = vdisplay;
+		mt->VSyncStart = outd->v_total - 2;
+		mt->VSyncEnd = outd->v_total;
+		mt->VTotal = outd->v_total;
+	}
+}
+
+static void cve2_init_TVdata(int norm, struct mavenregs* data, const struct output_desc** outd) {
+	static const struct output_desc paloutd = {
+		.h_vis	   = 52148148,	// ps
+		.h_f_porch =  1407407,	// ps
+		.h_sync    =  4666667,	// ps
+		.h_b_porch =  5777778,	// ps
+		.chromasc  = 19042247534182ULL,	// 4433618.750 Hz
+		.burst     =  2518518,	// ps
+		.v_total   =      625,
+	};
+	static const struct output_desc ntscoutd = {
+		.h_vis     = 52888889,	// ps
+		.h_f_porch =  1333333,	// ps
+		.h_sync    =  4666667,	// ps
+		.h_b_porch =  4666667,	// ps
+		.chromasc  = 15374030659475ULL,	// 3579545.454 Hz
+		.burst     =  2418418,	// ps
+		.v_total   =      525,	// lines
+	};
+
+	static const struct mavenregs palregs = { {
+		0x2A, 0x09, 0x8A, 0xCB,	/* 00: chroma subcarrier */
+		0x00,
+		0x00,	/* test */
+		0xF9,	/* modified by code (F9 written...) */
+		0x00,	/* ? not written */
+		0x7E,	/* 08 */
+		0x44,	/* 09 */
+		0x9C,	/* 0A */
+		0x2E,	/* 0B */
+		0x21,	/* 0C */
+		0x00,	/* ? not written */
+//		0x3F, 0x03, /* 0E-0F */
+		0x3C, 0x03,
+		0x3C, 0x03, /* 10-11 */
+		0x1A,	/* 12 */
+		0x2A,	/* 13 */
+		0x1C, 0x3D, 0x14, /* 14-16 */
+		0x9C, 0x01, /* 17-18 */
+		0x00,	/* 19 */
+		0xFE,	/* 1A */
+		0x7E,	/* 1B */
+		0x60,	/* 1C */
+		0x05,	/* 1D */
+//		0x89, 0x03, /* 1E-1F */
+		0xAD, 0x03,
+//		0x72,	/* 20 */
+		0xA5,
+		0x07,	/* 21 */
+//		0x72,	/* 22 */
+		0xA5,
+		0x00,	/* 23 */
+		0x00,	/* 24 */
+		0x00,	/* 25 */
+		0x08,	/* 26 */
+		0x04,	/* 27 */
+		0x00,	/* 28 */
+		0x1A,	/* 29 */
+		0x55, 0x01, /* 2A-2B */
+		0x26,	/* 2C */
+		0x07, 0x7E, /* 2D-2E */
+		0x02, 0x54, /* 2F-30 */
+		0xB0, 0x00, /* 31-32 */
+		0x14,	/* 33 */
+		0x49,	/* 34 */
+		0x00,	/* 35 written multiple times */
+		0x00,	/* 36 not written */
+		0xA3,	/* 37 */
+		0xC8,	/* 38 */
+		0x22,	/* 39 */
+		0x02,	/* 3A */
+		0x22,	/* 3B */
+		0x3F, 0x03, /* 3C-3D */
+		0x00,	/* 3E written multiple times */
+		0x00,	/* 3F not written */
+	} };
+	static struct mavenregs ntscregs = { {
+		0x21, 0xF0, 0x7C, 0x1F,	/* 00: chroma subcarrier */
+		0x00,
+		0x00,	/* test */
+		0xF9,	/* modified by code (F9 written...) */
+		0x00,	/* ? not written */
+		0x7E,	/* 08 */
+		0x43,	/* 09 */
+		0x7E,	/* 0A */
+		0x3D,	/* 0B */
+		0x00,	/* 0C */
+		0x00,	/* ? not written */
+		0x41, 0x00, /* 0E-0F */
+		0x3C, 0x00, /* 10-11 */
+		0x17,	/* 12 */
+		0x21,	/* 13 */
+		0x1B, 0x1B, 0x24, /* 14-16 */
+		0x83, 0x01, /* 17-18 */
+		0x00,	/* 19 */
+		0x0F,	/* 1A */
+		0x0F,	/* 1B */
+		0x60,	/* 1C */
+		0x05,	/* 1D */
+		//0x89, 0x02, /* 1E-1F */
+		0xC0, 0x02, /* 1E-1F */
+		//0x5F,	/* 20 */
+		0x9C,	/* 20 */
+		0x04,	/* 21 */
+		//0x5F,	/* 22 */
+		0x9C,	/* 22 */
+		0x01,	/* 23 */
+		0x02,	/* 24 */
+		0x00,	/* 25 */
+		0x0A,	/* 26 */
+		0x05,	/* 27 */
+		0x00,	/* 28 */
+		0x10,	/* 29 */
+		0xFF, 0x03, /* 2A-2B */
+		0x24,	/* 2C */
+		0x0F, 0x78, /* 2D-2E */
+		0x00, 0x00, /* 2F-30 */
+		0xB2, 0x04, /* 31-32 */
+		0x14,	/* 33 */
+		0x02,	/* 34 */
+		0x00,	/* 35 written multiple times */
+		0x00,	/* 36 not written */
+		0xA3,	/* 37 */
+		0xC8,	/* 38 */
+		0x15,	/* 39 */
+		0x05,	/* 3A */
+		0x3B,	/* 3B */
+		0x3C, 0x00, /* 3C-3D */
+		0x00,	/* 3E written multiple times */
+		0x00,	/* never written */
+	} };
+
+	if (norm == MATROXFB_OUTPUT_MODE_PAL) {
+		*data = palregs;
+		*outd = &paloutd;
+	} else {
+  		*data = ntscregs;
+		*outd = &ntscoutd;
+	}
+ 	return;
 }
 
-static void matroxfb_g450_shutdown(struct matroxfb_g450_info* m2info) {
-	MINFO_FROM(m2info->primary_dev);
+#define LR(x) cve2_set_reg(PMINFO (x), m->regs[(x)])
+static void cve2_init_TV(WPMINFO const struct mavenregs* m) {
+	int i;
+
+	LR(0x80);
+	LR(0x82); LR(0x83);
+	LR(0x84); LR(0x85);
 	
-	if (MINFO) {
-		ACCESS_FBINFO(output.all) &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
-		ACCESS_FBINFO(output.ph) &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
-		ACCESS_FBINFO(output.sh) &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
-		down_write(&ACCESS_FBINFO(altout.lock));
-		ACCESS_FBINFO(altout.device) = NULL;
-		ACCESS_FBINFO(altout.output) = NULL;
-		up_write(&ACCESS_FBINFO(altout.lock));
-		m2info->primary_dev = NULL;
+	cve2_set_reg(PMINFO 0x3E, 0x01);
+	
+	for (i = 0; i < 0x3E; i++) {
+		LR(i);
 	}
+	cve2_set_reg(PMINFO 0x3E, 0x00);
 }
 
-/* we do not have __setup() yet */
-static void* matroxfb_g450_probe(struct matrox_fb_info* minfo) {
-	struct matroxfb_g450_info* m2info;
+static int matroxfb_g450_compute(void* md, struct my_timming* mt) {
+	MINFO_FROM(md);
 
-	/* hardware is not G450... */
-	if (!ACCESS_FBINFO(devflags.g450dac))
-		return NULL;
-	m2info = (struct matroxfb_g450_info*)kmalloc(sizeof(*m2info), GFP_KERNEL);
-	if (!m2info) {
-		printk(KERN_ERR "matroxfb_g450: Not enough memory for G450 DAC control structs\n");
-		return NULL;
+	dprintk(KERN_DEBUG "Computing, mode=%u\n", ACCESS_FBINFO(outputs[1]).mode);
+
+	if (mt->crtc == MATROXFB_SRC_CRTC2 &&
+	    ACCESS_FBINFO(outputs[1]).mode != MATROXFB_OUTPUT_MODE_MONITOR) {
+		const struct output_desc* outd;
+
+		cve2_init_TVdata(ACCESS_FBINFO(outputs[1]).mode, &ACCESS_FBINFO(hw).maven, &outd);
+		{
+			int blacklevel, whitelevel;
+			g450_compute_bwlevel(PMINFO &blacklevel, &whitelevel);
+			ACCESS_FBINFO(hw).maven.regs[0x0E] = blacklevel >> 2;
+			ACCESS_FBINFO(hw).maven.regs[0x0F] = blacklevel & 3;
+			ACCESS_FBINFO(hw).maven.regs[0x1E] = whitelevel >> 2;
+			ACCESS_FBINFO(hw).maven.regs[0x1F] = whitelevel & 3;
+
+			ACCESS_FBINFO(hw).maven.regs[0x20] =
+			ACCESS_FBINFO(hw).maven.regs[0x22] = ACCESS_FBINFO(altout.tvo_params.saturation);
+
+			ACCESS_FBINFO(hw).maven.regs[0x25] = ACCESS_FBINFO(altout.tvo_params.hue);
+
+			if (ACCESS_FBINFO(altout.tvo_params.testout)) {
+				ACCESS_FBINFO(hw).maven.regs[0x05] |= 0x02;
+			}
+		}
+		computeRegs(PMINFO &ACCESS_FBINFO(hw).maven, mt, outd);
+	} else if (mt->mnp < 0) {
+		/* We must program clocks before CRTC2, otherwise interlaced mode
+		   startup may fail */
+		mt->mnp = matroxfb_g450_setclk(PMINFO mt->pixclock, (mt->crtc == MATROXFB_SRC_CRTC1) ? M_PIXEL_PLL_C : M_VIDEO_PLL);
+		mt->pixclock = g450_mnp2f(PMINFO mt->mnp);
 	}
-	memset(m2info, 0, sizeof(*m2info));
-	m2info->primary_dev = MINFO;
-	if (matroxfb_g450_connect(m2info)) {
-		kfree(m2info);
-		printk(KERN_ERR "matroxfb_g450: G450 DAC failed to initialize\n");
-		return NULL;
+	dprintk(KERN_DEBUG "Pixclock = %u\n", mt->pixclock);
+	return 0;
+}
+
+static int matroxfb_g450_program(void* md) {
+	MINFO_FROM(md);
+	
+	if (ACCESS_FBINFO(outputs[1]).mode != MATROXFB_OUTPUT_MODE_MONITOR) {
+		cve2_init_TV(PMINFO &ACCESS_FBINFO(hw).maven);
 	}
-	return m2info;
+	return 0;
 }
 
-static void matroxfb_g450_remove(struct matrox_fb_info* minfo, void* g450) {
-	matroxfb_g450_shutdown(g450);
-	kfree(g450);
+static int matroxfb_g450_verify_mode(void* md, u_int32_t arg) {
+	MINFO_FROM(md);
+	
+	switch (arg) {
+		case MATROXFB_OUTPUT_MODE_PAL:
+		case MATROXFB_OUTPUT_MODE_NTSC:
+		case MATROXFB_OUTPUT_MODE_MONITOR:
+			return 0;
+	}
+	return -EINVAL;
 }
 
-static struct matroxfb_driver g450 = {
-		name:	"Matrox G450 output #2",
-		probe:	matroxfb_g450_probe,
-		remove:	matroxfb_g450_remove };
+static int g450_dvi_compute(void* md, struct my_timming* mt) {
+	MINFO_FROM(md);
 
-static int matroxfb_g450_init(void) {
-	matroxfb_register_driver(&g450);
+	if (mt->mnp < 0) {
+		mt->mnp = matroxfb_g450_setclk(PMINFO mt->pixclock, (mt->crtc == MATROXFB_SRC_CRTC1) ? M_PIXEL_PLL_C : M_VIDEO_PLL);
+		mt->pixclock = g450_mnp2f(PMINFO mt->mnp);
+	}
 	return 0;
 }
 
-static void matroxfb_g450_exit(void) {
-	matroxfb_unregister_driver(&g450);
+static struct matrox_altout matroxfb_g450_altout = {
+	.owner   = THIS_MODULE,
+	.name	 = "Secondary output",
+	.compute = matroxfb_g450_compute,
+	.program = matroxfb_g450_program,
+	.verifymode = matroxfb_g450_verify_mode,
+	.getqueryctrl = g450_query_ctrl,
+	.getctrl = g450_get_ctrl,
+	.setctrl = g450_set_ctrl,
+};
+
+static struct matrox_altout matroxfb_g450_dvi = {
+	.owner   = THIS_MODULE,
+	.name	 = "DVI output",
+	.compute = g450_dvi_compute,
+};
+
+void matroxfb_g450_connect(WPMINFO2) {
+	if (ACCESS_FBINFO(devflags.g450dac)) {
+		down_write(&ACCESS_FBINFO(altout.lock));
+		tvo_fill_defaults(PMINFO2);
+		ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_CRTC1;
+		ACCESS_FBINFO(outputs[1]).data = MINFO;
+		ACCESS_FBINFO(outputs[1]).output = &matroxfb_g450_altout;
+		ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
+		ACCESS_FBINFO(outputs[2]).src = MATROXFB_SRC_CRTC1;
+		ACCESS_FBINFO(outputs[2]).data = MINFO;
+		ACCESS_FBINFO(outputs[2]).output = &matroxfb_g450_dvi;
+		ACCESS_FBINFO(outputs[2]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
+		up_write(&ACCESS_FBINFO(altout.lock));
+	}
 }
 
-MODULE_AUTHOR("(c) 2000-2001 Petr Vandrovec <vandrove@vc.cvut.cz>");
-MODULE_DESCRIPTION("Matrox G450 secondary output driver");
+void matroxfb_g450_shutdown(WPMINFO2) {
+	if (ACCESS_FBINFO(devflags.g450dac)) {
+		down_write(&ACCESS_FBINFO(altout.lock));
+		ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_NONE;
+		ACCESS_FBINFO(outputs[1]).output = NULL;
+		ACCESS_FBINFO(outputs[1]).data = NULL;
+		ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
+		ACCESS_FBINFO(outputs[2]).src = MATROXFB_SRC_NONE;
+		ACCESS_FBINFO(outputs[2]).output = NULL;
+		ACCESS_FBINFO(outputs[2]).data = NULL;
+		ACCESS_FBINFO(outputs[2]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
+		up_write(&ACCESS_FBINFO(altout.lock));
+	}
+}
+
+EXPORT_SYMBOL(matroxfb_g450_connect);
+EXPORT_SYMBOL(matroxfb_g450_shutdown);
+
+MODULE_AUTHOR("(c) 2000-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_DESCRIPTION("Matrox G450/G550 output driver");
 MODULE_LICENSE("GPL");
-module_init(matroxfb_g450_init);
-module_exit(matroxfb_g450_exit);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/matrox/matroxfb_g450.h linux-2.4.21-pre6/drivers/video/matrox/matroxfb_g450.h
--- linux-2.4.20/drivers/video/matrox/matroxfb_g450.h	2001-11-09 22:07:41.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/matrox/matroxfb_g450.h	2003-03-26 23:49:37.000000000 +0000
@@ -1,12 +1,14 @@
 #ifndef __MATROXFB_G450_H__
 #define __MATROXFB_G450_H__
 
-#include <linux/ioctl.h>
 #include "matroxfb_base.h"
 
-struct matroxfb_g450_info {
-	struct matrox_fb_info*	primary_dev;
-	unsigned int		timmings;
-};
+#ifdef CONFIG_FB_MATROX_G450
+void matroxfb_g450_connect(WPMINFO2);
+void matroxfb_g450_shutdown(WPMINFO2);
+#else
+static inline void matroxfb_g450_connect(WPMINFO2) { };
+static inline void matroxfb_g450_shutdown(WPMINFO2) { };
+#endif
 
-#endif /* __MATROXFB_MAVEN_H__ */
+#endif /* __MATROXFB_G450_H__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/matrox/matroxfb_maven.c linux-2.4.21-pre6/drivers/video/matrox/matroxfb_maven.c
--- linux-2.4.20/drivers/video/matrox/matroxfb_maven.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/matrox/matroxfb_maven.c	2003-03-26 23:48:57.000000000 +0000
@@ -2,11 +2,11 @@
  *
  * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
  *
- * (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz>
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
  *
  * Portions Copyright (c) 2001 Matrox Graphics Inc.
  *
- * Version: 1.62 2001/11/29
+ * Version: 1.64 2002/06/10
  *
  * See matroxfb_base.c for contributors.
  *
@@ -30,13 +30,125 @@
 #define MGATVO_B	1
 #define MGATVO_C	2
 
+static const struct maven_gamma {
+  unsigned char reg83;
+  unsigned char reg84;
+  unsigned char reg85;
+  unsigned char reg86;
+  unsigned char reg87;
+  unsigned char reg88;
+  unsigned char reg89;
+  unsigned char reg8a;
+  unsigned char reg8b;
+} maven_gamma[] = {
+  { 131, 57, 223, 15, 117, 212, 251, 91, 156},
+  { 133, 61, 128, 63, 180, 147, 195, 100, 180},
+  { 131, 19, 63, 31, 50, 66, 171, 64, 176},
+  { 0, 0, 0, 31, 16, 16, 16, 100, 200},
+  { 8, 23, 47, 73, 147, 244, 220, 80, 195},
+  { 22, 43, 64, 80, 147, 115, 58, 85, 168},
+  { 34, 60, 80, 214, 147, 212, 188, 85, 167},
+  { 45, 77, 96, 216, 147, 99, 91, 85, 159},
+  { 56, 76, 112, 107, 147, 212, 148, 64, 144},
+  { 65, 91, 128, 137, 147, 196, 17, 69, 148},
+  { 72, 104, 136, 138, 147, 180, 245, 73, 147},
+  { 87, 116, 143, 126, 16, 83, 229, 77, 144},
+  { 95, 119, 152, 254, 244, 83, 221, 77, 151},
+  { 100, 129, 159, 156, 244, 148, 197, 77, 160},
+  { 105, 141, 167, 247, 244, 132, 181, 84, 166},
+  { 105, 147, 168, 247, 244, 245, 181, 90, 170},
+  { 120, 153, 175, 248, 212, 229, 165, 90, 180},
+  { 119, 156, 176, 248, 244, 229, 84, 74, 160},
+  { 119, 158, 183, 248, 244, 229, 149, 78, 165}
+};
+
+/* Definition of the various controls */
+struct mctl {
+	struct matroxfb_queryctrl desc;
+	size_t control;
+};
+
+#define BLMIN	0x0FF
+#define WLMAX	0x3FF
+
+static const struct mctl maven_controls[] =
+{	{ { MATROXFB_CID_BRIGHTNESS,
+	  "brightness",
+	  0, WLMAX - BLMIN, 1, 379 - BLMIN, 
+	  MATROXFB_CTRL_TYPE_INTEGER, 0, 0,
+	  "picture"
+	}, offsetof(struct matrox_fb_info, altout.tvo_params.brightness) },
+	{ { MATROXFB_CID_CONTRAST,
+	  "contrast",
+	  0, 1023, 1, 127, 
+	  MATROXFB_CTRL_TYPE_INTEGER, 0, 0,
+	  "picture"
+	}, offsetof(struct matrox_fb_info, altout.tvo_params.contrast) },
+	{ { MATROXFB_CID_SATURATION,
+	  "saturation",
+	  0, 255, 1, 155, 
+	  MATROXFB_CTRL_TYPE_INTEGER, 0, 0,
+	  "picture"
+	}, offsetof(struct matrox_fb_info, altout.tvo_params.saturation) },
+	{ { MATROXFB_CID_HUE,
+	  "hue",
+	  0, 255, 1, 0, 
+	  MATROXFB_CTRL_TYPE_INTEGER, 0, 0,
+	  "picture"
+	}, offsetof(struct matrox_fb_info, altout.tvo_params.hue) },
+	{ { MATROXFB_CID_GAMMA,
+	  "gamma",
+	  0, sizeof(maven_gamma)/sizeof(maven_gamma[0])-1, 1, 3, 
+	  MATROXFB_CTRL_TYPE_INTEGER, 0, 0,
+	  "picture"
+	}, offsetof(struct matrox_fb_info, altout.tvo_params.gamma) },
+	{ { MATROXFB_CID_TESTOUT,
+	  "test output",
+	  0, 1, 1, 0, 
+	  MATROXFB_CTRL_TYPE_BOOLEAN, 0, 0,
+	  "picture"
+	}, offsetof(struct matrox_fb_info, altout.tvo_params.testout) },
+	{ { MATROXFB_CID_DEFLICKER,
+	  "deflicker mode",
+	  0, 2, 1, 0, 
+	  MATROXFB_CTRL_TYPE_INTEGER, 0, 0,
+	  "picture"
+	}, offsetof(struct matrox_fb_info, altout.tvo_params.deflicker) },
+
+};
+
+#define MAVCTRLS (sizeof(maven_controls)/sizeof(maven_controls[0]))
+
+/* Return: positive number: id found
+           -EINVAL:         id not found, return failure
+	   -ENOENT:         id not found, create fake disabled control */
+static int get_ctrl_id(__u32 v4l2_id) {
+	int i;
+
+	for (i = 0; i < MAVCTRLS; i++) {
+		if (v4l2_id < maven_controls[i].desc.id) {
+			if (maven_controls[i].desc.id == 0x08000000) {
+				return -EINVAL;
+			}
+			return -ENOENT;
+		}
+		if (v4l2_id == maven_controls[i].desc.id) {
+			return i;
+		}
+	}
+	return -EINVAL;
+}
+
 struct maven_data {
 	struct matrox_fb_info*		primary_head;
 	struct i2c_client*		client;
-	int				mode;
 	int				version;
 };
 
+static int* get_ctrl_ptr(struct maven_data* md, int idx) {
+	return (int*)((char*)(md->primary_head) + maven_controls[idx].control);
+}
+
 static int maven_get_reg(struct i2c_client* c, char reg) {
 	char dst;
 	struct i2c_msg msgs[] = {{ c->addr, I2C_M_REV_DIR_ADDR, sizeof(reg), &reg },
@@ -127,8 +239,8 @@
 	fwant = htotal * vtotal;
 	fmax = pll->vco_freq_max / ctl->den;
 
-	printk(KERN_DEBUG "want: %u, xtal: %u, h: %u, v: %u, fmax: %u\n",
-		fwant, fxtal, htotal, vtotal, fmax);
+/*	printk(KERN_DEBUG "want: %u, xtal: %u, h: %u, v: %u, fmax: %u\n",
+		fwant, fxtal, htotal, vtotal, fmax);	*/
 	for (p = 1; p <= pll->post_shift_max; p++) {
 		if (fwant * 2 > fmax)
 			break;
@@ -163,9 +275,9 @@
 			ln = ln - scrlen;
 			if (ln > htotal)
 				continue;
-			printk(KERN_DEBUG "Match: %u / %u / %u / %u\n", n, m, p, ln);
+			dprintk(KERN_DEBUG "Match: %u / %u / %u / %u\n", n, m, p, ln);
 			if (ln > besth2) {
-				printk(KERN_DEBUG "Better...\n");
+				dprintk(KERN_DEBUG "Better...\n");
 				*h2 = besth2 = ln;
 				*post = p;
 				*in = m;
@@ -221,6 +333,38 @@
 	return;
 }
 
+static unsigned char maven_compute_deflicker (const struct maven_data* md) {
+	unsigned char df;
+	
+	df = (md->version == MGATVO_B?0x40:0x00);
+	switch (md->primary_head->altout.tvo_params.deflicker) {
+		case 0:
+/*			df |= 0x00; */
+			break;
+		case 1:
+			df |= 0xB1;
+			break;
+		case 2:
+			df |= 0xA2;
+			break;
+	}
+	return df;
+}
+
+static void maven_compute_bwlevel (const struct maven_data* md,
+				   int *bl, int *wl) {
+	const int b = md->primary_head->altout.tvo_params.brightness + BLMIN;
+	const int c = md->primary_head->altout.tvo_params.contrast;
+
+	*bl = max(b - c, BLMIN);
+	*wl = min(b + c, WLMAX);
+}
+
+static const struct maven_gamma* maven_compute_gamma (const struct maven_data* md) {
+ 	return maven_gamma + md->primary_head->altout.tvo_params.gamma;
+}
+
+
 static void maven_init_TVdata(const struct maven_data* md, struct mavenregs* data) {
 	static struct mavenregs palregs = { {
 		0x2A, 0x09, 0x8A, 0xCB,	/* 00: chroma subcarrier */
@@ -326,26 +470,50 @@
 		0x00,	/* 3E written multiple times */
 		0x00,	/* never written */
 	}, MODE_NTSC, 525, 60 };
+	MINFO_FROM(md->primary_head);
 
-	if (md->mode & MODE_PAL)
+	if (ACCESS_FBINFO(outputs[1].mode) == MODE_PAL)
 		*data = palregs;
-	else
-		*data = ntscregs;
-
-	data->regs[0x93] = 0xA2;
-
-	/* gamma correction registers */
-	data->regs[0x83] = 0x00;
-	data->regs[0x84] = 0x00;
-	data->regs[0x85] = 0x00;
-	data->regs[0x86] = 0x1F;
-	data->regs[0x87] = 0x10;
-	data->regs[0x88] = 0x10;
-	data->regs[0x89] = 0x10;
-	data->regs[0x8A] = 0x64;	/* 100 */
-	data->regs[0x8B] = 0xC8;	/* 200 */
-
-	return;
+  	else
+  		*data = ntscregs;
+  
+ 	/* Set deflicker */
+ 	data->regs[0x93] = maven_compute_deflicker(md);
+ 
+ 	/* set gamma */
+ 	{
+		const struct maven_gamma* g;
+		g = maven_compute_gamma(md);
+		data->regs[0x83] = g->reg83;
+		data->regs[0x84] = g->reg84;
+		data->regs[0x85] = g->reg85;
+		data->regs[0x86] = g->reg86;
+		data->regs[0x87] = g->reg87;
+		data->regs[0x88] = g->reg88;
+		data->regs[0x89] = g->reg89;
+		data->regs[0x8A] = g->reg8a;
+		data->regs[0x8B] = g->reg8b;
+ 	}
+ 
+ 	/* Set contrast / brightness */
+ 	{
+		int bl, wl;
+		maven_compute_bwlevel (md, &bl, &wl);
+		data->regs[0x0e] = bl >> 2;
+		data->regs[0x0f] = bl & 3;
+		data->regs[0x1e] = wl >> 2;
+		data->regs[0x1f] = wl & 3;
+ 	}
+
+ 	/* Set saturation */
+ 	{
+		data->regs[0x20] =
+		data->regs[0x22] = ACCESS_FBINFO(altout.tvo_params.saturation);
+ 	}
+ 
+ 	/* Set HUE */
+	data->regs[0x25] = ACCESS_FBINFO(altout.tvo_params.hue);
+ 	return;
 }
 
 #define LR(x) maven_set_reg(c, (x), m->regs[(x)])
@@ -386,7 +554,7 @@
 	LRP(0x17);
 	LR(0x0B);
 	LR(0x0C);
-	if (m->mode & MODE_PAL) {
+	if (m->mode == MODE_PAL) {
 		maven_set_reg(c, 0x35, 0x10); /* ... */
 	} else {
 		maven_set_reg(c, 0x35, 0x0F); /* ... */
@@ -424,7 +592,7 @@
 	LR(0x27);
 	LR(0x21);
 	LRP(0x2A);
-	if (m->mode & MODE_PAL)
+	if (m->mode == MODE_PAL)
 		maven_set_reg(c, 0x35, 0x1D);	/* ... */
 	else
 		maven_set_reg(c, 0x35, 0x1C);
@@ -473,7 +641,7 @@
 	LR(0xC2);
 
 	maven_get_reg(c, 0x8D);
-	maven_set_reg(c, 0x8D, 0x00);
+	maven_set_reg(c, 0x8D, 0x04);
 
 	LR(0x20);	/* saturation #1 */
 	LR(0x22);	/* saturation #2 */
@@ -498,7 +666,7 @@
 	LR(0x8B);
 
 	val = maven_get_reg(c, 0x8D);
-	val &= 0x10;			/* 0x10 or anything ored with it */
+	val &= 0x14;			/* 0x10 or anything ored with it */
 	maven_set_reg(c, 0x8D, val);
 
 	LR(0x33);
@@ -524,7 +692,7 @@
 	LR(0x27);
 	LR(0x21);
 	LRP(0x2A);
-	if (m->mode & MODE_PAL)
+	if (m->mode == MODE_PAL)
 		maven_set_reg(c, 0x35, 0x1D);
 	else
 		maven_set_reg(c, 0x35, 0x1C);
@@ -562,7 +730,7 @@
 		unsigned int a, b, c, h2;
 		unsigned int h = ht + 2 + x;
 
-		if (!matroxfb_mavenclock((m->mode & MODE_PAL) ? &maven_PAL : &maven_NTSC, h, vt, &a, &b, &c, &h2)) {
+		if (!matroxfb_mavenclock((m->mode == MODE_PAL) ? &maven_PAL : &maven_NTSC, h, vt, &a, &b, &c, &h2)) {
 			unsigned int diff = h - h2;
 
 			if (diff < err) {
@@ -584,8 +752,8 @@
 	unsigned int tmpi;
 	unsigned int a, bv, c;
 
-	m->mode = md->mode;
-	if (MODE_TV(md->mode)) {
+	m->mode = md->primary_head->outputs[1].mode;
+	if (MODE_TV(m->mode)) {
 		unsigned int lmargin;
 		unsigned int umargin;
 		unsigned int vslen;
@@ -804,7 +972,7 @@
 	m->regs[0xB0] = 0x03;	/* output: monitor */
 	m->regs[0xB1] = 0xA0;	/* ??? */
 	m->regs[0x8C] = 0x20;	/* must be set... */
-	m->regs[0x8D] = 0x00;	/* defaults to 0x10: test signal */
+	m->regs[0x8D] = 0x04;	/* defaults to 0x10: test signal */
 	m->regs[0xB9] = 0x1A;	/* defaults to 0x2C: too bright */
 	m->regs[0xBF] = 0x22;	/* makes picture stable */
 
@@ -849,25 +1017,122 @@
 	return 0;
 }
 
-static inline int maven_resync(struct maven_data* md) {
+static inline int maven_start(struct maven_data* md) {
 	struct i2c_client* c = md->client;
 	maven_set_reg(c, 0x95, 0x20);	/* start whole thing */
 	return 0;
 }
 
-static int maven_set_output_mode(struct maven_data* md, u_int32_t arg) {
-	switch (arg) {
-		case MATROXFB_OUTPUT_MODE_PAL:
-		case MATROXFB_OUTPUT_MODE_NTSC:
-		case MATROXFB_OUTPUT_MODE_MONITOR:
-			md->mode = arg;
-			return 1;
+static int maven_get_queryctrl (struct maven_data* md, 
+				struct matroxfb_queryctrl *p) {
+	int i;
+	
+	i = get_ctrl_id(p->id);
+	if (i >= 0) {
+		*p = maven_controls[i].desc;
+		return 0;
+	}
+	if (i == -ENOENT) {
+		static const struct matroxfb_queryctrl disctrl = 
+			{ 0, "", 0, 0, 0, 0, 0, 1, 1, "Disabled" };
+			
+		i = p->id;
+		*p = disctrl;
+		p->id = i;
+		sprintf(p->name, "Ctrl #%08X", i);
+		return 0;
 	}
 	return -EINVAL;
 }
 
-static int maven_get_output_mode(struct maven_data* md, u_int32_t *arg) {
-	*arg = md->mode;
+static int maven_set_control (struct maven_data* md, 
+			      struct matroxfb_control *p) {
+	int i;
+	
+	i = get_ctrl_id(p->id);
+	if (i < 0) return -EINVAL;
+
+	/*
+	 * Check if changed.
+	 */
+	if (p->value == *get_ctrl_ptr(md, i)) return 0;
+
+	/*
+	 * Check limits.
+	 */
+	if (p->value > maven_controls[i].desc.maximum) return -EINVAL;
+	if (p->value < maven_controls[i].desc.minimum) return -EINVAL;
+
+	/*
+	 * Store new value.
+	 */
+	*get_ctrl_ptr(md, i) = p->value;
+
+	switch (p->id) {
+		case MATROXFB_CID_BRIGHTNESS:
+		case MATROXFB_CID_CONTRAST:
+		{
+		  int blacklevel, whitelevel;
+		  maven_compute_bwlevel(md, &blacklevel, &whitelevel);
+		  blacklevel = (blacklevel >> 2) | ((blacklevel & 3) << 8);
+		  whitelevel = (whitelevel >> 2) | ((whitelevel & 3) << 8);
+		  maven_set_reg_pair(md->client, 0x0e, blacklevel);
+		  maven_set_reg_pair(md->client, 0x1e, whitelevel);
+		}
+		break;
+		case MATROXFB_CID_SATURATION:
+		{
+		  maven_set_reg(md->client, 0x20, p->value);
+		  maven_set_reg(md->client, 0x22, p->value);
+		}
+		break;
+		case MATROXFB_CID_HUE:
+		{
+		  maven_set_reg(md->client, 0x25, p->value);
+		}
+		break;
+		case MATROXFB_CID_GAMMA:
+		{
+		  const struct maven_gamma* g;
+		  g = maven_compute_gamma(md);
+		  maven_set_reg(md->client, 0x83, g->reg83);
+		  maven_set_reg(md->client, 0x84, g->reg84);
+		  maven_set_reg(md->client, 0x85, g->reg85);
+		  maven_set_reg(md->client, 0x86, g->reg86);
+		  maven_set_reg(md->client, 0x87, g->reg87);
+		  maven_set_reg(md->client, 0x88, g->reg88);
+		  maven_set_reg(md->client, 0x89, g->reg89);
+		  maven_set_reg(md->client, 0x8a, g->reg8a);
+		  maven_set_reg(md->client, 0x8b, g->reg8b);
+		}
+		break;
+		case MATROXFB_CID_TESTOUT:
+		{
+			unsigned char val 
+			  = maven_get_reg (md->client,0x8d);
+			if (p->value) val |= 0x10;
+			else          val &= ~0x10;
+			maven_set_reg (md->client, 0x8d, val);
+		}
+		break;
+		case MATROXFB_CID_DEFLICKER:
+		{
+		  maven_set_reg(md->client, 0x93, maven_compute_deflicker(md));
+		}
+		break;
+	}
+	
+
+	return 0;
+}
+
+static int maven_get_control (struct maven_data* md, 
+			      struct matroxfb_control *p) {
+	int i;
+	
+	i = get_ctrl_id(p->id);
+	if (i < 0) return -EINVAL;
+	p->value = *get_ctrl_ptr(md, i);
 	return 0;
 }
 
@@ -890,56 +1155,73 @@
 }
 
 static int maven_out_start(void* md) {
-	return maven_resync(md);
+	return maven_start(md);
 }
 
-static void maven_out_incuse(void* md) {
-	if (md)
-		i2c_inc_use_client(((struct maven_data*)md)->client);
+static int maven_out_verify_mode(void* md, u_int32_t arg) {
+	switch (arg) {
+		case MATROXFB_OUTPUT_MODE_PAL:
+		case MATROXFB_OUTPUT_MODE_NTSC:
+		case MATROXFB_OUTPUT_MODE_MONITOR:
+			return 0;
+	}
+	return -EINVAL;
 }
 
-static void maven_out_decuse(void* md) {
-	if (md)
-		i2c_dec_use_client(((struct maven_data*)md)->client);
+static int maven_out_get_queryctrl(void* md, struct matroxfb_queryctrl* p) {
+        return maven_get_queryctrl(md, p);
 }
 
-static int maven_out_set_mode(void* md, u_int32_t arg) {
-	return maven_set_output_mode(md, arg);
+static int maven_out_get_ctrl(void* md, struct matroxfb_control* p) {
+	return maven_get_control(md, p);
 }
 
-static int maven_out_get_mode(void* md, u_int32_t* arg) {
-	return maven_get_output_mode(md, arg);
+static int maven_out_set_ctrl(void* md, struct matroxfb_control* p) {
+	return maven_set_control(md, p);
 }
 
 static struct matrox_altout maven_altout = {
-	maven_out_compute,
-	maven_out_program,
-	maven_out_start,
-	maven_out_incuse,
-	maven_out_decuse,
-	maven_out_set_mode,
-	maven_out_get_mode
+	.owner   = THIS_MODULE,
+	.name	 = "Secondary output",
+	.compute = maven_out_compute,
+	.program = maven_out_program,
+	.start   = maven_out_start,
+	.verifymode = maven_out_verify_mode,
+	.getqueryctrl = maven_out_get_queryctrl,
+	.getctrl = maven_out_get_ctrl,
+	.setctrl = maven_out_set_ctrl,
 };
 
 static int maven_init_client(struct i2c_client* clnt) {
 	struct i2c_adapter* a = clnt->adapter;
 	struct maven_data* md = clnt->data;
-	struct matroxfb_dh_maven_info* m2info __attribute__((unused)) = ((struct i2c_bit_adapter*)a)->minfo;
-	MINFO_FROM(m2info->primary_dev);
+	MINFO_FROM(list_entry(a, struct i2c_bit_adapter, adapter)->minfo);
 
-	md->mode = MODE_MONITOR;
 	md->primary_head = MINFO;
 	md->client = clnt;
 	down_write(&ACCESS_FBINFO(altout.lock));
-	ACCESS_FBINFO(altout.device) = md;
-	ACCESS_FBINFO(altout.output) = &maven_altout;
+	ACCESS_FBINFO(outputs[1]).output = &maven_altout;
+	ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_NONE;
+	ACCESS_FBINFO(outputs[1]).data = md;
+	ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
 	up_write(&ACCESS_FBINFO(altout.lock));
-	ACCESS_FBINFO(output.all) |= MATROXFB_OUTPUT_CONN_SECONDARY;
 	if (maven_get_reg(clnt, 0xB2) < 0x14) {
 		md->version = MGATVO_B;
+		/* Tweak some things for this old chip */
 	} else {
 		md->version = MGATVO_C;
 	}
+	/*
+	 * Set all parameters to its initial values.
+	 */
+	{
+		unsigned int i;
+
+		for (i = 0; i < MAVCTRLS; ++i) {
+			*get_ctrl_ptr(md, i) = maven_controls[i].desc.default_value;
+		}
+	}
+
 	return 0;
 }
 
@@ -947,13 +1229,14 @@
 	struct maven_data* md = clnt->data;
 
 	if (md->primary_head) {
-		md->primary_head->output.all &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
-		md->primary_head->output.ph &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
-		md->primary_head->output.sh &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
-		down_write(&md->primary_head->altout.lock);
-		md->primary_head->altout.device = NULL;
-		md->primary_head->altout.output = NULL;
-		up_write(&md->primary_head->altout.lock);
+		MINFO_FROM(md->primary_head);
+
+		down_write(&ACCESS_FBINFO(altout.lock));
+		ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_NONE;
+		ACCESS_FBINFO(outputs[1]).output = NULL;
+		ACCESS_FBINFO(outputs[1]).data = NULL;
+		ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
+		up_write(&ACCESS_FBINFO(altout.lock));
 		md->primary_head = NULL;
 	}
 	return 0;
@@ -1066,7 +1349,7 @@
 		i2c_del_driver(&maven_driver);
 }
 
-MODULE_AUTHOR("(c) 1999-2001 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
 MODULE_DESCRIPTION("Matrox G200/G400 Matrox MGA-TVO driver");
 MODULE_LICENSE("GPL");
 module_init(matroxfb_maven_init);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/matrox/matroxfb_maven.h linux-2.4.21-pre6/drivers/video/matrox/matroxfb_maven.h
--- linux-2.4.20/drivers/video/matrox/matroxfb_maven.h	2000-12-11 21:16:53.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/matrox/matroxfb_maven.h	2003-03-26 23:49:55.000000000 +0000
@@ -6,21 +6,15 @@
 #include <linux/i2c-algo-bit.h>
 #include "matroxfb_base.h"
 
-struct matroxfb_dh_maven_info;
-
 struct i2c_bit_adapter {
 	struct i2c_adapter		adapter;
 	int				initialized;
 	struct i2c_algo_bit_data	bac;
-	struct matroxfb_dh_maven_info  *minfo;
-};
-
-struct matroxfb_dh_maven_info {
-	struct matrox_fb_info*	primary_dev;
-
-	struct i2c_bit_adapter	maven;
-	struct i2c_bit_adapter	ddc1;
-	struct i2c_bit_adapter	ddc2;
+	struct matrox_fb_info*		minfo;
+	struct {
+		unsigned int		data;
+		unsigned int		clock;
+				      } mask;
 };
 
 #endif /* __MATROXFB_MAVEN_H__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/matrox/matroxfb_misc.c linux-2.4.21-pre6/drivers/video/matrox/matroxfb_misc.c
--- linux-2.4.20/drivers/video/matrox/matroxfb_misc.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/matrox/matroxfb_misc.c	2003-03-26 23:49:50.000000000 +0000
@@ -2,11 +2,11 @@
  *
  * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
  *
- * (c) 1998,1999,2000,2001 Petr Vandrovec <vandrove@vc.cvut.cz>
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
  *
  * Portions Copyright (c) 2001 Matrox Graphics Inc.
  *
- * Version: 1.62 2001/11/29
+ * Version: 1.66 2002/10/14
  *
  * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
  *
@@ -146,6 +146,7 @@
 	if (!pixclock) pixclock = 10000;	/* 10ns = 100MHz */
 	mt->pixclock = 1000000000 / pixclock;
 	if (mt->pixclock < 1) mt->pixclock = 1;
+	mt->mnp = -1;
 	mt->dblscan = var->vmode & FB_VMODE_DOUBLE;
 	mt->interlaced = var->vmode & FB_VMODE_INTERLACED;
 	mt->HDisplay = var->xres;
@@ -360,7 +361,8 @@
 			  ((hd      & 0x100) >> 7) | /* blanking */
 			  ((hs      & 0x100) >> 6) | /* sync start */
 			   (hbe     & 0x040);	 /* end hor. blanking */
-	if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY)
+	/* FIXME: Enable vidrst only on G400, and only if TV-out is used */
+	if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC1)
 		hw->CRTCEXT[1] |= 0x88;		/* enable horizontal and vertical vidrst */
 	hw->CRTCEXT[2] =  ((vt & 0xC00) >> 10) |
 			  ((vd & 0x400) >>  8) |	/* disp end */
@@ -847,7 +849,7 @@
 					  ( bd->pins[86]        & 0x0000000F);
 	MINFO->values.reg.opt		= ((bd->pins[53] << 15) & 0x00400000) |
 					  ((bd->pins[53] << 22) & 0x10000000) |
-					  ((bd->pins[53] << 10) & 0x00001C00);
+					  ((bd->pins[53] <<  7) & 0x00001C00);
 	MINFO->values.reg.opt3		= get_u32(bd->pins + 67);
 	MINFO->values.pll.system	= (bd->pins[ 65] == 0xFF) ? 200000 			: bd->pins[ 65] * 4000;
 	MINFO->features.pll.ref_freq	= (bd->pins[ 92] & 0x01) ? 14318 : 27000;
@@ -872,7 +874,7 @@
 	mult = bd->pins[4]?8000:6000;
 	
 	MINFO->limits.pixel.vcomax	= (bd->pins[ 38] == 0xFF) ? 600000			: bd->pins[ 38] * mult;
-	MINFO->limits.system.vcomax	= (bd->pins[ 36] == 0xFF) ? MINFO->limits.pixel.vcomax	: bd->pins[ 39] * mult;
+	MINFO->limits.system.vcomax	= (bd->pins[ 36] == 0xFF) ? MINFO->limits.pixel.vcomax	: bd->pins[ 36] * mult;
 	MINFO->limits.video.vcomax	= (bd->pins[ 37] == 0xFF) ? MINFO->limits.system.vcomax	: bd->pins[ 37] * mult;
 	MINFO->limits.pixel.vcomin	= (bd->pins[123] == 0xFF) ? 256000			: bd->pins[123] * mult;
 	MINFO->limits.system.vcomin	= (bd->pins[121] == 0xFF) ? MINFO->limits.pixel.vcomin	: bd->pins[121] * mult;
@@ -992,6 +994,27 @@
 	parse_bios(vaddr_va(ACCESS_FBINFO(video).vbase), &ACCESS_FBINFO(bios));
 	pci_write_config_dword(pdev, PCI_ROM_ADDRESS, biosbase);
 	pci_write_config_dword(pdev, PCI_OPTION_REG, opt);
+#ifdef CONFIG_X86
+	if (!ACCESS_FBINFO(bios).bios_valid) {
+		unsigned char* b;
+		
+		b = ioremap(0x000C0000, 65536);
+		if (!b) {
+			printk(KERN_INFO "matroxfb: Unable to map legacy BIOS\n");
+		} else {
+			unsigned int ven = readb(b+0x64+0) | (readb(b+0x64+1) << 8);
+			unsigned int dev = readb(b+0x64+2) | (readb(b+0x64+3) << 8);
+			
+			if (ven != pdev->vendor || dev != pdev->device) {
+				printk(KERN_INFO "matroxfb: Legacy BIOS is for %04X:%04X, while this device is %04X:%04X\n",
+					ven, dev, pdev->vendor, pdev->device);
+			} else {
+				parse_bios(b, &ACCESS_FBINFO(bios));
+			}
+			iounmap(b);
+		}
+	}
+#endif
 	matroxfb_set_limits(PMINFO &ACCESS_FBINFO(bios));
 }
 
@@ -1011,6 +1034,6 @@
 EXPORT_SYMBOL(matroxfb_vgaHWrestore);		/* DAC1064, Ti3026 */
 EXPORT_SYMBOL(matroxfb_read_pins);
 
-MODULE_AUTHOR("(c) 1999-2001 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
 MODULE_DESCRIPTION("Miscellaneous support for Matrox video cards");
 MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/matrox/matroxfb_proc.c linux-2.4.21-pre6/drivers/video/matrox/matroxfb_proc.c
--- linux-2.4.20/drivers/video/matrox/matroxfb_proc.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/matrox/matroxfb_proc.c	2003-03-26 23:49:38.000000000 +0000
@@ -0,0 +1,151 @@
+/*
+ *
+ * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
+ *
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
+ *
+ * Version: 1.64 2002/06/10
+ *
+ */
+
+#include "matroxfb_base.h"
+#include <linux/proc_fs.h>
+
+static struct proc_dir_entry* mga_pde;
+
+struct procinfo {
+	struct matrox_fb_info* info;
+	struct proc_dir_entry* pde;
+};
+
+static inline void remove_pde(struct proc_dir_entry* pde) {
+	if (pde) {
+		remove_proc_entry(pde->name, pde->parent);
+	}
+}
+
+#ifndef CONFIG_PROC_FS
+static int bios_read_proc(char* buffer, char** start, off_t offset,
+			  int size, int *eof, void *data) {
+	return 0;
+}
+
+static int pins_read_proc(char* buffer, char** start, off_t offset,
+			  int size, int *eof, void *data) {
+	return 0;
+}
+#else
+/* This macro frees the machine specific function from bounds checking and
+ * this like that... */
+#define PRINT_PROC(fmt,args...)					\
+	do {							\
+		len += sprintf(buffer+len, fmt, ##args );	\
+		if (begin + len > offset + size)		\
+			break;					\
+		if (begin + len < offset) {			\
+			begin += len;				\
+			len = 0;				\
+		}						\
+	} while(0)
+
+static int bios_read_proc(char* buffer, char** start, off_t offset,
+			  int size, int *eof, void *data) {
+	int len = 0;
+	off_t begin = 0;
+	struct matrox_bios* bd = data;
+
+	do {
+		*eof = 0;
+		if (bd->bios_valid) {
+			PRINT_PROC("BIOS:   %u.%u.%u\n", bd->version.vMaj, bd->version.vMin, bd->version.vRev);
+			PRINT_PROC("Output: 0x%02X\n", bd->output.state);
+			PRINT_PROC("TVOut:  %s\n", bd->output.tvout?"yes":"no");
+			PRINT_PROC("PINS:   %s\n", bd->pins_len ? "found" : "not found");
+			PRINT_PROC("Info:   %p\n", bd);
+		} else {
+			PRINT_PROC("BIOS:   Invalid\n");
+		}
+		*eof = 1;
+	} while (0);
+	if (offset >= begin + len)
+		return 0;
+	*start = buffer + (offset - begin);
+	return size < begin + len - offset ? size : begin + len - offset;
+}
+
+static int pins_read_proc(char* buffer, char** start, off_t offset,
+			  int size, int *eof, void *data) {
+	struct matrox_bios* bd = data;
+	
+	if (offset >= bd->pins_len) {
+		*eof = 1;
+		return 0;
+	}
+	if (offset + size >= bd->pins_len) {
+		size = bd->pins_len - offset;
+		*eof = 1;
+	}
+	memcpy(buffer, bd->pins + offset, size);
+	*start = buffer;
+	return size;
+}
+#endif /* CONFIG_PROC_FS */
+
+static void* matroxfb_proc_probe(struct matrox_fb_info* minfo) {
+	struct procinfo* binfo;
+	char b[10];
+
+	binfo = (struct procinfo*)kmalloc(sizeof(*binfo), GFP_KERNEL);
+	if (!binfo) {
+		printk(KERN_ERR "matroxfb_proc: Not enough memory for /proc control structs\n");
+		return NULL;
+	}
+	binfo->info = minfo;
+	sprintf(b, "fb%u", GET_FB_IDX(minfo->fbcon.node));
+	binfo->pde = proc_mkdir(b, mga_pde);
+	if (binfo->pde) {
+		create_proc_read_entry("bios", 0, binfo->pde, bios_read_proc, &minfo->bios);
+		if (minfo->bios.pins_len) {
+			struct proc_dir_entry* p = create_proc_read_entry("pins", 0, binfo->pde, pins_read_proc, &minfo->bios);
+			if (p) {
+				p->size = minfo->bios.pins_len;
+			}
+		}
+	}
+	return binfo;
+}
+
+static void matroxfb_proc_remove(struct matrox_fb_info* minfo, void* binfoI) {
+	struct procinfo* binfo = binfoI;
+
+	if (binfo->pde) {
+		remove_proc_entry("pins", binfo->pde);
+		remove_proc_entry("bios", binfo->pde);
+		remove_pde(binfo->pde);
+	}
+	kfree(binfo);
+}
+
+static struct matroxfb_driver procfn = {
+	.name =		"Matrox /proc driver",
+	.probe =	matroxfb_proc_probe,
+	.remove =	matroxfb_proc_remove
+};
+
+static int matroxfb_proc_init(void) {
+	mga_pde = proc_mkdir("driver/mga", NULL);
+	matroxfb_register_driver(&procfn);
+	return 0;
+}
+
+static void matroxfb_proc_exit(void) {
+	matroxfb_unregister_driver(&procfn);
+	remove_pde(mga_pde);
+}
+
+MODULE_AUTHOR("(c) 2001-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_DESCRIPTION("Matrox /proc driver");
+MODULE_LICENSE("GPL");
+module_init(matroxfb_proc_init);
+module_exit(matroxfb_proc_exit);
+/* we do not have __setup() */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/neofb.c linux-2.4.21-pre6/drivers/video/neofb.c
--- linux-2.4.20/drivers/video/neofb.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/neofb.c	2003-03-26 23:49:39.000000000 +0000
@@ -2253,7 +2253,7 @@
   /*
    * Our driver data
    */
-  dev->driver_data = info;
+  pci_set_drvdata(dev, info);
 
   return 0;
 
@@ -2267,7 +2267,7 @@
 
 static void __devexit neofb_remove (struct pci_dev *dev)
 {
-  struct neofb_info *info = (struct neofb_info *)dev->driver_data;
+  struct neofb_info *info = pci_get_drvdata(dev);
 
   DBG("neofb_remove");
 
@@ -2289,7 +2289,7 @@
        * Ensure that the driver data is no longer
        * valid.
        */
-      dev->driver_data = NULL;
+      pci_set_drvdata(dev, NULL);
     }
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/pmagb-b-fb.h linux-2.4.21-pre6/drivers/video/pmagb-b-fb.h
--- linux-2.4.20/drivers/video/pmagb-b-fb.h	2001-04-18 18:49:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/pmagb-b-fb.h	2003-03-26 23:49:40.000000000 +0000
@@ -4,7 +4,7 @@
  *      TurboChannel PMAGB-B framebuffer card support,
  *      Copyright (C) 1999, 2000, 2001 by
  *      Michael Engel <engel@unix-ag.org> and 
- *      Karsten Merker <merker@linxutag.org>
+ *      Karsten Merker <merker@linuxtag.org>
  *      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 -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/radeonfb.c linux-2.4.21-pre6/drivers/video/radeonfb.c
--- linux-2.4.20/drivers/video/radeonfb.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/radeonfb.c	2003-03-26 23:49:55.000000000 +0000
@@ -2778,7 +2778,7 @@
 	lvds_gen_cntl |= (LVDS_BL_MOD_EN | LVDS_BLON);
 	if (on && (level > BACKLIGHT_OFF)) {
 		lvds_gen_cntl |= LVDS_DIGON;
-		if (!lvds_gen_cntl & LVDS_ON) {
+		if ((lvds_gen_cntl & LVDS_ON) == 0) {
 			lvds_gen_cntl &= ~LVDS_BLON;
 			OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
 			(void)INREG(LVDS_GEN_CNTL);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/riva/accel.c linux-2.4.21-pre6/drivers/video/riva/accel.c
--- linux-2.4.20/drivers/video/riva/accel.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/riva/accel.c	2003-03-26 23:49:39.000000000 +0000
@@ -243,10 +243,17 @@
 	setup:		fbcon_riva8_setup,
 	bmove:		fbcon_riva_bmove,
 	clear:		fbcon_riva8_clear,
+#ifdef __BIG_ENDIAN
+	putc:		fbcon_cfb8_putc,
+	putcs:		fbcon_cfb8_putcs,
+	revc:		fbcon_cfb8_revc,
+	clear_margins:	fbcon_cfb8_clear_margins,
+#else
 	putc:		fbcon_riva8_putc,
 	putcs:		fbcon_riva8_putcs,
 	revc:		fbcon_riva8_revc,
 	clear_margins:	fbcon_riva8_clear_margins,
+#endif	
 	fontwidthmask:	FONTWIDTHRANGE(4, 16)
 };
 #endif
@@ -346,10 +353,17 @@
 	setup:		fbcon_riva16_setup,
 	bmove:		fbcon_riva_bmove,
 	clear:		fbcon_riva16_clear,
+#ifdef __BIG_ENDIAN
+	putc:		fbcon_cfb16_putc,
+	putcs:		fbcon_cfb16_putcs,
+	revc:		fbcon_cfb16_revc,
+	clear_margins:	fbcon_cfb16_clear_margins,
+#else
 	putc:		fbcon_riva16_putc,
 	putcs:		fbcon_riva16_putcs,
 	revc:		fbcon_riva1632_revc,
 	clear_margins:	fbcon_riva16_clear_margins,
+#endif
 	fontwidthmask:	FONTWIDTHRANGE(4, 16)
 };
 #endif
@@ -420,10 +434,17 @@
 	setup:		fbcon_riva32_setup,
 	bmove:		fbcon_riva_bmove,
 	clear:		fbcon_riva32_clear,
+#ifdef __BIG_ENDIAN
+	putc:		fbcon_cfb32_putc,
+	putcs:		fbcon_cfb32_putcs,
+	revc:		fbcon_cfb32_revc,
+	clear_margins:	fbcon_cfb32_clear_margins,
+#else
 	putc:		fbcon_riva32_putc,
 	putcs:		fbcon_riva32_putcs,
 	revc:		fbcon_riva1632_revc,
 	clear_margins:	fbcon_riva32_clear_margins,
+#endif
 	fontwidthmask:	FONTWIDTHRANGE(4, 16)
 };
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/riva/fbdev.c linux-2.4.21-pre6/drivers/video/riva/fbdev.c
--- linux-2.4.20/drivers/video/riva/fbdev.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/riva/fbdev.c	2003-03-26 23:49:09.000000000 +0000
@@ -1,9 +1,12 @@
 /*
- * linux/drivers/video/riva/fbdev.c - nVidia RIVA 128/TNT/TNT2 fb driver
+ * linux/drivers/video/riva/fbdev.c
  *
- * Maintained by Ani Joshi <ajoshi@shell.unixbox.com>
+ * nVidia RIVA 128/TNT/TNT2/GeForce2/3 fb driver
+ *
+ * Maintained by Ani Joshi <ajoshi@kernel.crashing.org>
  *
  * Copyright 1999-2000 Jeff Garzik
+ * Copyright 2000-2003 Ani Joshi
  *
  * Contributors:
  *
@@ -55,7 +58,7 @@
 
 
 /* version number of this driver */
-#define RIVAFB_VERSION "0.9.3"
+#define RIVAFB_VERSION "0.9.4"
 
 
 
@@ -95,7 +98,11 @@
 #define CURSOR_HIDE_DELAY		(20)
 #define CURSOR_SHOW_DELAY		(3)
 
+#ifdef __BIG_ENDIAN
+#define CURSOR_COLOR		0xff7f
+#else
 #define CURSOR_COLOR		0x7fff
+#endif
 #define TRANSPARENT_COLOR	0x0000
 #define MAX_CURS		32
 
@@ -863,6 +870,7 @@
 	struct riva_regs newmode;
 	int bpp, width, hDisplaySize, hDisplay, hStart,
 	    hEnd, hTotal, height, vDisplay, vStart, vEnd, vTotal, dotClock;
+	int hBlankStart, hBlankEnd, vBlankStart, vBlankEnd;
 
 	/* time to calculate */
 
@@ -879,6 +887,8 @@
 		video_mode->hsync_len) / 8 - 1;
 	hTotal = (hDisplaySize + video_mode->right_margin +
 		  video_mode->hsync_len + video_mode->left_margin) / 8 - 1;
+	hBlankStart = hDisplay;
+	hBlankEnd = hTotal;
 	height = video_mode->yres_virtual;
 	vDisplay = video_mode->yres - 1;
 	vStart = video_mode->yres + video_mode->lower_margin - 1;
@@ -886,35 +896,63 @@
 	       video_mode->vsync_len - 1;
 	vTotal = video_mode->yres + video_mode->lower_margin +
 		 video_mode->vsync_len + video_mode->upper_margin + 2;
+	vBlankStart = vDisplay;
+	vBlankEnd = vTotal;
 	dotClock = 1000000000 / video_mode->pixclock;
 
 	memcpy(&newmode, &reg_template, sizeof(struct riva_regs));
 
+	newmode.ext.screen = SetBitField(hBlankEnd,6:6,4:4)
+                  | SetBitField(vBlankStart,10:10,3:3)
+                  | SetBitField(vStart,10:10,2:2)
+                  | SetBitField(vDisplay,10:10,1:1)
+                  | SetBitField(vTotal,10:10,0:0);
+    
+    	newmode.ext.horiz  = SetBitField(hTotal,8:8,0:0)
+                  | SetBitField(hDisplay,8:8,1:1)
+                  | SetBitField(hBlankStart,8:8,2:2)
+                  | SetBitField(hStart,8:8,3:3);
+
+    	newmode.ext.extra  = SetBitField(vTotal,11:11,0:0)
+                    | SetBitField(vDisplay,11:11,2:2)
+                    | SetBitField(vStart,11:11,4:4)
+                    | SetBitField(vBlankStart,11:11,6:6);
+
+	if (rinfo->riva.flatPanel) {
+		vStart = vTotal - 3;
+		vEnd = vTotal - 2;
+		vBlankStart = vStart;
+		hStart = hTotal - 3;
+		hEnd = hTotal - 2;
+		hBlankEnd = hTotal + 4;
+	}
+
 	newmode.crtc[0x0] = Set8Bits (hTotal - 4);
 	newmode.crtc[0x1] = Set8Bits (hDisplay);
-	newmode.crtc[0x2] = Set8Bits (hDisplay);
-	newmode.crtc[0x3] = SetBitField (hTotal, 4: 0, 4:0) | SetBit (7);
+	newmode.crtc[0x2] = Set8Bits (hBlankStart);
+	newmode.crtc[0x3] = SetBitField(hBlankEnd,4:0,4:0)
+                | SetBit(7);
 	newmode.crtc[0x4] = Set8Bits (hStart);
-	newmode.crtc[0x5] = SetBitField (hTotal, 5: 5, 7:7)
-		| SetBitField (hEnd, 4: 0, 4:0);
+	newmode.crtc[0x5] = SetBitField (hBlankEnd, 5: 5, 7:7)
+ 		| SetBitField (hEnd, 4: 0, 4:0);
 	newmode.crtc[0x6] = SetBitField (vTotal, 7: 0, 7:0);
 	newmode.crtc[0x7] = SetBitField (vTotal, 8: 8, 0:0)
 		| SetBitField (vDisplay, 8: 8, 1:1)
 		| SetBitField (vStart, 8: 8, 2:2)
-		| SetBitField (vDisplay, 8: 8, 3:3)
+		| SetBitField (vBlankStart, 8: 8, 3:3)
 		| SetBit (4)
 		| SetBitField (vTotal, 9: 9, 5:5)
 		| SetBitField (vDisplay, 9: 9, 6:6)
 		| SetBitField (vStart, 9: 9, 7:7);
-	newmode.crtc[0x9] = SetBitField (vDisplay, 9: 9, 5:5)
+	newmode.crtc[0x9] = SetBitField (vBlankStart, 9: 9, 5:5)
 		| SetBit (6);
 	newmode.crtc[0x10] = Set8Bits (vStart);
 	newmode.crtc[0x11] = SetBitField (vEnd, 3: 0, 3:0)
 		| SetBit (5);
 	newmode.crtc[0x12] = Set8Bits (vDisplay);
 	newmode.crtc[0x13] = ((width / 8) * ((bpp + 1) / 8)) & 0xFF;
-	newmode.crtc[0x15] = Set8Bits (vDisplay);
-	newmode.crtc[0x16] = Set8Bits (vTotal + 1);
+	newmode.crtc[0x15] = Set8Bits (vBlankStart);
+	newmode.crtc[0x16] = Set8Bits (vBlankEnd);
 
 	newmode.ext.bpp = bpp;
 	newmode.ext.width = width;
@@ -925,11 +963,31 @@
 				  hTotal, height, vDisplay, vStart, vEnd,
 				  vTotal, dotClock);
 
+	newmode.ext.scale = rinfo->riva.PRAMDAC[0x00000848/4] & 0xfff000ff;
+
+	if (rinfo->riva.flatPanel) {
+		newmode.ext.pixel |= (1 << 7);
+		newmode.ext.scale |= (1 << 8);
+	}
+
+	newmode.ext.vpll2 = rinfo->riva.PRAMDAC[0x00000520/4];
+
+#if defined(__powerpc__)
+	/*
+	 * XXX only Mac cards use second DAC for flat panel
+	 */
+	if (rinfo->riva.flatPanel) {
+		newmode.ext.pllsel |= 0x20000800;
+		newmode.ext.vpll2 = newmode.ext.vpll;
+	}
+#endif
 	rinfo->current_state = newmode;
 	riva_load_state(rinfo, &rinfo->current_state);
 
 	rinfo->riva.LockUnlock(&rinfo->riva, 0); /* important for HW cursor */
 	rivafb_download_cursor(rinfo);
+
+	rivafb_blank(0, (struct fb_info *)rinfo);
 }
 
 /**
@@ -1780,6 +1838,10 @@
 		fb_find_mode(&rinfo->disp.var, &rinfo->info, mode_option,
 			     NULL, 0, NULL, 8);
 #endif
+	if (rinfo->use_default_var)
+		/* We will use the modified default var */
+		rinfo->disp.var = rivafb_default_var;
+
 	return 0;
 }
 
@@ -1850,6 +1912,117 @@
 	return 0;
 }
 
+#ifdef CONFIG_ALL_PPC
+static int riva_get_EDID_OF(struct rivafb_info *rinfo)
+{
+	struct device_node *dp;
+	unsigned char *pedid = NULL;
+
+	dp = pci_device_to_OF_node(rinfo->pd);
+	pedid = (unsigned char *)get_property(dp, "EDID,B", 0);
+
+	if (pedid) {
+		rinfo->EDID = pedid;
+		return 1;
+	} else
+		return 0;
+}
+#endif /* CONFIG_ALL_PPC */
+
+static int riva_dfp_parse_EDID(struct rivafb_info *rinfo)
+{
+	unsigned char *block = rinfo->EDID;
+
+	if (!block)
+		return 0;
+
+	/* jump to detailed timing block section */
+	block += 54;
+
+        rinfo->clock = (block[0] + (block[1] << 8));
+        rinfo->panel_xres = (block[2] + ((block[4] & 0xf0) << 4));
+        rinfo->hblank = (block[3] + ((block[4] & 0x0f) << 8));
+        rinfo->panel_yres = (block[5] + ((block[7] & 0xf0) << 4));
+        rinfo->vblank = (block[6] + ((block[7] & 0x0f) << 8));
+        rinfo->hOver_plus = (block[8] + ((block[11] & 0xc0) << 2));
+        rinfo->hSync_width = (block[9] + ((block[11] & 0x30) << 4));
+        rinfo->vOver_plus = ((block[10] >> 4) + ((block[11] & 0x0c) << 2));
+        rinfo->vSync_width = ((block[10] & 0x0f) + ((block[11] & 0x03) << 4));
+        rinfo->interlaced = ((block[17] & 0x80) >> 7);
+        rinfo->synct = ((block[17] & 0x18) >> 3);
+        rinfo->misc = ((block[17] & 0x06) >> 1);
+        rinfo->hAct_high = rinfo->vAct_high = 0;
+        if (rinfo->synct == 3) {
+                if (rinfo->misc & 2)
+                        rinfo->hAct_high = 1;
+                if (rinfo->misc & 1)
+                        rinfo->vAct_high = 1;
+	}
+
+	printk("rivafb: detected DFP panel size from EDID: %dx%d\n",
+		rinfo->panel_xres, rinfo->panel_yres);
+
+	rinfo->got_dfpinfo = 1;
+
+	return 1;
+}
+
+static void riva_update_default_var(struct rivafb_info *rinfo)
+{
+	struct fb_var_screeninfo *var = &rivafb_default_var;
+
+        var->xres = rinfo->panel_xres;
+        var->yres = rinfo->panel_yres;
+        var->xres_virtual = rinfo->panel_xres;
+        var->yres_virtual = rinfo->panel_yres;
+        var->xoffset = var->yoffset = 0;
+        var->bits_per_pixel = 8;
+        var->pixclock = 100000000 / rinfo->clock;
+        var->left_margin = (rinfo->hblank - rinfo->hOver_plus - rinfo->hSync_width);
+        var->right_margin = rinfo->hOver_plus;
+        var->upper_margin = (rinfo->vblank - rinfo->vOver_plus - rinfo->vSync_width);
+        var->lower_margin = rinfo->vOver_plus;
+        var->hsync_len = rinfo->hSync_width;
+        var->vsync_len = rinfo->vSync_width;
+        var->sync = 0;
+
+        if (rinfo->synct == 3) {
+                if (rinfo->hAct_high)
+                        var->sync |= FB_SYNC_HOR_HIGH_ACT;
+                if (rinfo->vAct_high)
+                        var->sync |= FB_SYNC_VERT_HIGH_ACT;
+        }
+ 
+        var->vmode = 0;
+        if (rinfo->interlaced)
+                var->vmode |= FB_VMODE_INTERLACED;
+
+	if (!noaccel)
+		var->accel_flags |= FB_ACCELF_TEXT;
+        
+        rinfo->use_default_var = 1;
+}
+
+
+static void riva_get_EDID(struct rivafb_info *rinfo)
+{
+#ifdef CONFIG_ALL_PPC
+	if (!riva_get_EDID_OF(rinfo))
+		printk("rivafb: could not retrieve EDID from OF\n");
+#else
+	/* XXX use other methods later */
+#endif
+}
+
+
+static void riva_get_dfpinfo(struct rivafb_info *rinfo)
+{
+	if (riva_dfp_parse_EDID(rinfo))
+		riva_update_default_var(rinfo);
+
+	rinfo->riva.flatPanel = rinfo->got_dfpinfo;
+}
+
 
 
 /* ------------------------------------------------------------------------- *
@@ -1880,15 +2053,18 @@
 	rinfo->base0_region_size = pci_resource_len(pd, 0);
 	rinfo->base1_region_size = pci_resource_len(pd, 1);
 
+	{
+		/* enable IO and mem if not already done */
+		unsigned short cmd;
+
+		pci_read_config_word(pd, PCI_COMMAND, &cmd);
+		cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+		pci_write_config_word(pd, PCI_COMMAND, cmd);
+	}
+ 
 	rinfo->ctrl_base_phys = pci_resource_start(rinfo->pd, 0);
 	rinfo->fb_base_phys = pci_resource_start(rinfo->pd, 1);
 
-	if (!request_mem_region(rinfo->ctrl_base_phys,
-				rinfo->base0_region_size, "rivafb")) {
-		printk(KERN_ERR PFX "cannot reserve MMIO region\n");
-		goto err_out_kfree;
-	}
-
 	rinfo->ctrl_base = ioremap(rinfo->ctrl_base_phys,
 				   rinfo->base0_region_size);
 	if (!rinfo->ctrl_base) {
@@ -1896,6 +2072,10 @@
 		goto err_out_free_base1;
 	}
 	
+	riva_get_EDID(rinfo);
+
+	riva_get_dfpinfo(rinfo);
+
 	rinfo->riva.EnableIRQ = 0;
 	rinfo->riva.PRAMDAC = (unsigned *)(rinfo->ctrl_base + 0x00680000);
 	rinfo->riva.PFB = (unsigned *)(rinfo->ctrl_base + 0x00100000);
@@ -1944,6 +2124,19 @@
 		break;
 	}
 
+#if defined(__powerpc__)
+	/*
+	 * XXX Mac cards use the second DAC for the panel
+	 */
+	if (rinfo->riva.flatPanel) {
+		printk("rivafb: using second CRTC\n");
+		rinfo->riva.PCIO = rinfo->riva.PCIO + 0x2000;
+		rinfo->riva.PCRTC = rinfo->riva.PCRTC + 0x800;
+		rinfo->riva.PRAMDAC = rinfo->riva.PRAMDAC + 0x800;
+		rinfo->riva.PDIO = rinfo->riva.PDIO + 0x2000;
+	}
+#endif
+
 	RivaGetConfig(&rinfo->riva);
 
 	rinfo->ram_amount = rinfo->riva.RamAmountKBytes * 1024;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/riva/nv4ref.h linux-2.4.21-pre6/drivers/video/riva/nv4ref.h
--- linux-2.4.20/drivers/video/riva/nv4ref.h	2000-02-29 19:07:04.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/riva/nv4ref.h	2003-03-26 23:49:20.000000000 +0000
@@ -41,7 +41,7 @@
  * GPL licensing note -- nVidia is allowing a liberal interpretation of
  * the documentation restriction above, to merely say that this nVidia's
  * copyright and disclaimer should be included with all code derived
- * from this source.  -- Jeff Garzik <jgarzik@mandrakesoft.com>, 01/Nov/99 
+ * from this source.  -- Jeff Garzik <jgarzik@pobox.com>, 01/Nov/99 
  */
 
  /***************************************************************************\
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/riva/riva_hw.c linux-2.4.21-pre6/drivers/video/riva/riva_hw.c
--- linux-2.4.20/drivers/video/riva/riva_hw.c	2002-02-25 19:38:07.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/riva/riva_hw.c	2003-03-26 23:49:19.000000000 +0000
@@ -41,7 +41,7 @@
  * GPL licensing note -- nVidia is allowing a liberal interpretation of
  * the documentation restriction above, to merely say that this nVidia's
  * copyright and disclaimer should be included with all code derived
- * from this source.  -- Jeff Garzik <jgarzik@mandrakesoft.com>, 01/Nov/99 
+ * from this source.  -- Jeff Garzik <jgarzik@pobox.com>, 01/Nov/99 
  */
 
 /* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/riva_hw.c,v 1.8 2000/02/08 17:19:11 dawes Exp $ */
@@ -1449,6 +1449,16 @@
 		chip->PGRAPH[0x000009A4/4] = chip->PFB[0x00000200/4];
 		chip->PGRAPH[0x000009A8/4] = chip->PFB[0x00000204/4];
 	    }
+
+	    chip->PFB[0x00000240/4] = 0;
+	    chip->PFB[0x00000244/4] = 0;
+	    chip->PFB[0x00000248/4] = 0;
+	    chip->PFB[0x0000024C/4] = 0;
+	    chip->PFB[0x00000250/4] = 0;
+	    chip->PFB[0x00000244/4] = 0;
+	    chip->PFB[0x00000248/4] = 0;
+	    chip->PFB[0x0000024C/4] = 0;
+
             chip->PGRAPH[0x00000B00/4] = chip->PFB[0x00000240/4];
             chip->PGRAPH[0x00000B04/4] = chip->PFB[0x00000244/4];
             chip->PGRAPH[0x00000B08/4] = chip->PFB[0x00000248/4];
@@ -1522,6 +1532,15 @@
             chip->PGRAPH[0x00000F50/4] = 0x00000040;
             for (i = 0; i < 4; i++)
                 chip->PGRAPH[0x00000F54/4] = 0x00000000;
+
+	    if (chip->flatPanel) {
+		VGA_WR08(chip->PCIO, 0x3d4, 0x53);
+		VGA_WR08(chip->PCIO, 0x3d5, 0);
+		VGA_WR08(chip->PCIO, 0x3d4, 0x54);
+		VGA_WR08(chip->PCIO, 0x3d5, 0);
+		VGA_WR08(chip->PCIO, 0x3d4, 0x21);
+		VGA_WR08(chip->PCIO, 0x3d5, 0xfa);
+	    }
             break;
     }
     LOAD_FIXED_STATE(Riva,FIFO);
@@ -1547,6 +1566,16 @@
     VGA_WR08(chip->PCIO, 0x03D5, state->cursor0);
     VGA_WR08(chip->PCIO, 0x03D4, 0x31);
     VGA_WR08(chip->PCIO, 0x03D5, state->cursor1);
+    VGA_WR08(chip->PCIO, 0x03D4, 0x41);
+    VGA_WR08(chip->PCIO, 0x03D5, state->extra);
+
+    if (!chip->flatPanel) {
+        chip->PRAMDAC[0x00000508/4]  = state->vpll;
+        chip->PRAMDAC[0x00000520/4]  = state->vpll2;
+        chip->PRAMDAC[0x0000050C/4]  = state->pllsel;
+    } else {
+	chip->PRAMDAC[0x00000848/4]  = state->scale;
+    }
     chip->PRAMDAC[0x00000300/4]  = state->cursor2;
     chip->PRAMDAC[0x00000508/4]  = state->vpll;
     chip->PRAMDAC[0x0000050C/4]  = state->pllsel;
@@ -1598,10 +1627,14 @@
     state->cursor0      = VGA_RD08(chip->PCIO, 0x03D5);
     VGA_WR08(chip->PCIO, 0x03D4, 0x31);
     state->cursor1      = VGA_RD08(chip->PCIO, 0x03D5);
+    VGA_WR08(chip->PCIO, 0x03D4, 0x41);
+    state->extra        = VGA_RD08(chip->PCIO, 0x03D5);
     state->cursor2      = chip->PRAMDAC[0x00000300/4];
     state->vpll         = chip->PRAMDAC[0x00000508/4];
+    state->vpll2        = chip->PRAMDAC[0x00000520/4];
     state->pllsel       = chip->PRAMDAC[0x0000050C/4];
     state->general      = chip->PRAMDAC[0x00000600/4];
+    state->scale	= chip->PRAMDAC[0x00000848/4];
     state->config       = chip->PFB[0x00000200/4];
     switch (chip->Architecture)
     {
@@ -1910,6 +1943,9 @@
     RIVA_HW_INST *chip
 )
 {
+#if defined(__BIG_ENDIAN)
+    chip->PMC[0x00000004/4] = 0x01000001;
+#endif
     /*
      * Fill in chip configuration.
      */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/riva/riva_hw.h linux-2.4.21-pre6/drivers/video/riva/riva_hw.h
--- linux-2.4.20/drivers/video/riva/riva_hw.h	2002-02-25 19:38:07.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/riva/riva_hw.h	2003-03-26 23:49:29.000000000 +0000
@@ -41,7 +41,7 @@
  * GPL licensing note -- nVidia is allowing a liberal interpretation of
  * the documentation restriction above, to merely say that this nVidia's
  * copyright and disclaimer should be included with all code derived
- * from this source.  -- Jeff Garzik <jgarzik@mandrakesoft.com>, 01/Nov/99 
+ * from this source.  -- Jeff Garzik <jgarzik@pobox.com>, 01/Nov/99 
  */
 
 /* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/riva_hw.h,v 1.6 2000/02/08 17:19:12 dawes Exp $ */
@@ -59,8 +59,14 @@
 /*
  * HW access macros.
  */
+#if defined(__powerpc__)
+#include <asm/io.h>
+#define NV_WR08(p,i,d)	out_8(p+i, d)
+#define NV_RD08(p,i)	in_8(p+i)
+#else
 #define NV_WR08(p,i,d)  (((U008 *)(p))[i]=(d))
 #define NV_RD08(p,i)    (((U008 *)(p))[i])
+#endif
 #define NV_WR16(p,i,d)  (((U016 *)(p))[(i)/2]=(d))
 #define NV_RD16(p,i)    (((U016 *)(p))[(i)/2])
 #define NV_WR32(p,i,d)  (((U032 *)(p))[(i)/4]=(d))
@@ -88,8 +94,12 @@
 typedef volatile struct
 {
     U032 reserved00[4];
+#ifdef __BIG_ENDIAN
+    U032 FifoFree;
+#else
     U016 FifoFree;
     U016 Nop;
+#endif 
     U032 reserved01[0x0BB];
     U032 Rop3;
 } RivaRop;
@@ -99,8 +109,12 @@
 typedef volatile struct
 {
     U032 reserved00[4];
+#ifdef __BIG_ENDIAN
+    U032 FifoFree;
+#else
     U016 FifoFree;
     U016 Nop;
+#endif
     U032 reserved01[0x0BD];
     U032 Shape;
     U032 reserved03[0x001];
@@ -114,8 +128,12 @@
 typedef volatile struct
 {
     U032 reserved00[4];
+#ifdef __BIG_ENDIAN
+    U032 FifoFree;
+#else
     U016 FifoFree;
     U016 Nop;
+#endif
     U032 reserved01[0x0BB];
     U032 TopLeft;
     U032 WidthHeight;
@@ -126,8 +144,12 @@
 typedef volatile struct
 {
     U032 reserved00[4];
+#ifdef __BIG_ENDIAN
+    U032 FifoFree;
+#else
     U016 FifoFree;
     U016 Nop[1];
+#endif
     U032 reserved01[0x0BC];
     U032 Color;
     U032 reserved03[0x03E];
@@ -140,8 +162,12 @@
 typedef volatile struct
 {
     U032 reserved00[4];
+#ifdef __BIG_ENDIAN
+    U032 FifoFree;
+#else
     U016 FifoFree;
     U016 Nop;
+#endif
     U032 reserved01[0x0BB];
     U032 TopLeftSrc;
     U032 TopLeftDst;
@@ -153,8 +179,12 @@
 typedef volatile struct
 {
     U032 reserved00[4];
+#ifdef __BIG_ENDIAN
+    U032 FifoFree;
+#else
     U016 FifoFree;
     U016 Nop[1];
+#endif
     U032 reserved01[0x0BC];
     U032 TopLeft;
     U032 WidthHeight;
@@ -168,8 +198,12 @@
 typedef volatile struct
 {
     U032 reserved00[4];
+#ifdef __BIG_ENDIAN
+    U032 FifoFree;
+#else
     U016 FifoFree;
     U016 Nop;
+#endif
     U032 reserved01[0x0BB];
     U032 reserved03[(0x040)-1];
     U032 Color1A;
@@ -230,8 +264,12 @@
 typedef volatile struct
 {
     U032 reserved00[4];
+#ifdef __BIG_ENDIAN
+    U032 FifoFree;
+#else
     U016 FifoFree;
     U016 Nop;
+#endif    
     U032 reserved01[0x0BC];
     U032 TextureOffset;
     U032 TextureFormat;
@@ -256,8 +294,12 @@
 typedef volatile struct
 {
     U032 reserved00[4];
+#ifdef __BIG_ENDIAN
+    U032 FifoFree;
+#else
     U016 FifoFree;
     U016 Nop;
+#endif    
     U032 reserved01[0x0BB];
     U032 ColorKey;
     U032 TextureOffset;
@@ -290,8 +332,12 @@
 typedef volatile struct
 {
     U032 reserved00[4];
+#ifdef __BIG_ENDIAN
+    U032 FifoFree;
+#else
     U016 FifoFree;
     U016 Nop[1];
+#endif    
     U032 reserved01[0x0BC];
     U032 Color;             /* source color               0304-0307*/
     U032 Reserved02[0x03e];
@@ -321,16 +367,24 @@
 typedef volatile struct
 {
     U032 reserved00[4];
+#ifdef __BIG_ENDIAN
+    U032 FifoFree;
+#else
     U016 FifoFree;
     U016 Nop;
+#endif
     U032 reserved01[0x0BE];
     U032 Offset;
 } RivaSurface;
 typedef volatile struct
 {
     U032 reserved00[4];
+#ifdef __BIG_ENDIAN
+    U032 FifoFree;
+#else
     U016 FifoFree;
     U016 Nop;
+#endif
     U032 reserved01[0x0BD];
     U032 Pitch;
     U032 RenderBufferOffset;
@@ -364,6 +418,7 @@
     U032 VBlankBit;
     U032 FifoFreeCount;
     U032 FifoEmptyCount;
+    U032 flatPanel;
     /*
      * Non-FIFO registers.
      */
@@ -424,11 +479,14 @@
     U032 repaint0;
     U032 repaint1;
     U032 screen;
+    U032 scale;
+    U032 extra;
     U032 pixel;
     U032 horiz;
     U032 arbitration0;
     U032 arbitration1;
     U032 vpll;
+    U032 vpll2;
     U032 pllsel;
     U032 general;
     U032 config;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/riva/riva_tbl.h linux-2.4.21-pre6/drivers/video/riva/riva_tbl.h
--- linux-2.4.20/drivers/video/riva/riva_tbl.h	2001-02-13 21:15:05.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/riva/riva_tbl.h	2003-03-26 23:49:29.000000000 +0000
@@ -41,7 +41,7 @@
  * GPL licensing note -- nVidia is allowing a liberal interpretation of
  * the documentation restriction above, to merely say that this nVidia's
  * copyright and disclaimer should be included with all code derived
- * from this source.  -- Jeff Garzik <jgarzik@mandrakesoft.com>, 01/Nov/99 
+ * from this source.  -- Jeff Garzik <jgarzik@pobox.com>, 01/Nov/99 
  */
 
 /* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/riva_tbl.h,v 1.5 2000/02/08 17:19:12 dawes Exp $ */
@@ -830,29 +830,45 @@
     {0x00000501, 0x01FFFFFF},
     {0x00000502, 0x00000002},
     {0x00000503, 0x00000002},
+#ifdef __BIG_ENDIAN
+    {0x00000508, 0x01088043},
+#else
     {0x00000508, 0x01008043},
+#endif
     {0x0000050A, 0x00000000},
     {0x0000050B, 0x00000000},
+#ifdef __BIG_ENDIAN
+    {0x0000050C, 0x01088019},
+#else
     {0x0000050C, 0x01008019},
+#endif
     {0x0000050E, 0x00000000},
     {0x0000050F, 0x00000000},
-#if 1
-    {0x00000510, 0x01008018},
+#ifdef __BIG_ENDIAN
+    {0x00000510, 0x01088018},
 #else
-    {0x00000510, 0x01008044},
+    {0x00000510, 0x01008018},
 #endif
     {0x00000512, 0x00000000},
     {0x00000513, 0x00000000},
+#ifdef __BIG_ENDIAN
+    {0x00000514, 0x01088021},
+#else
     {0x00000514, 0x01008021},
+#endif
     {0x00000516, 0x00000000},
     {0x00000517, 0x00000000},
+#ifdef __BIG_ENDIAN
+    {0x00000518, 0x0108805F},
+#else
     {0x00000518, 0x0100805F},
+#endif
     {0x0000051A, 0x00000000},
     {0x0000051B, 0x00000000},
-#if 1
-    {0x0000051C, 0x0100804B},
+#ifdef __BIG_ENDIAN
+    {0x0000051C, 0x0108804B},
 #else
-    {0x0000051C, 0x0100804A},
+    {0x0000051C, 0x0100804B},
 #endif
     {0x0000051E, 0x00000000},
     {0x0000051F, 0x00000000},
@@ -868,10 +884,18 @@
     {0x00000529, 0x00000D01},
     {0x0000052A, 0x11401140},
     {0x0000052B, 0x00000000},
+#ifdef __BIG_ENDIAN
+    {0x0000052C, 0x00080058},
+#else
     {0x0000052C, 0x00000058},
+#endif
     {0x0000052E, 0x11401140},
     {0x0000052F, 0x00000000},
+#ifdef __BIG_ENDIAN
+    {0x00000530, 0x00080059},
+#else
     {0x00000530, 0x00000059},
+#endif
     {0x00000532, 0x11401140},
     {0x00000533, 0x00000000},
     {0x00000534, 0x0000005A},
@@ -882,7 +906,14 @@
     {0x0000053B, 0x00000000},
     {0x0000053C, 0x00000093},
     {0x0000053E, 0x11401140},
-    {0x0000053F, 0x00000000} 
+    {0x0000053F, 0x00000000},
+#ifdef __BIG_ENDIAN
+    {0x00000540, 0x0308A01C},
+#else
+    {0x00000540, 0x0300A01C},
+#endif
+    {0x00000542, 0x11401140},
+    {0x00000543, 0x00000000}
 };
 static unsigned nv10TablePRAMIN_8BPP[][2] =
 {
@@ -898,7 +929,8 @@
     {0x0000052E, 0x00000302},
     {0x00000535, 0x00000000},
     {0x00000539, 0x00000000},
-    {0x0000053D, 0x00000000} 
+    {0x0000053D, 0x00000000},
+    {0x00000541, 0x00000302}
 };
 static unsigned nv10TablePRAMIN_15BPP[][2] =
 {
@@ -914,7 +946,8 @@
     {0x0000052E, 0x00000902},
     {0x00000535, 0x00000902},
     {0x00000539, 0x00000902}, 
-    {0x0000053D, 0x00000902} 
+    {0x0000053D, 0x00000902}, 
+    {0x00000541, 0x00000902}
 };
 static unsigned nv10TablePRAMIN_16BPP[][2] =
 {
@@ -930,7 +963,8 @@
     {0x0000052E, 0x00000C02},
     {0x00000535, 0x00000C02},
     {0x00000539, 0x00000C02},
-    {0x0000053D, 0x00000C02} 
+    {0x0000053D, 0x00000C02},
+    {0x00000541, 0x00000C02}
 };
 static unsigned nv10TablePRAMIN_32BPP[][2] =
 {
@@ -946,6 +980,7 @@
     {0x0000052E, 0x00000E02},
     {0x00000535, 0x00000E02},
     {0x00000539, 0x00000E02},
-    {0x0000053D, 0x00000E02} 
+    {0x0000053D, 0x00000E02},
+    {0x00000541, 0x00000E02}
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/riva/rivafb.h linux-2.4.21-pre6/drivers/video/riva/rivafb.h
--- linux-2.4.20/drivers/video/riva/rivafb.h	2001-04-18 18:49:12.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/riva/rivafb.h	2003-03-26 23:49:25.000000000 +0000
@@ -51,6 +51,8 @@
 	struct riva_regs initial_state;	/* initial startup video mode */
 	struct riva_regs current_state;
 
+	unsigned char *EDID;
+
 	struct display disp;
 	int currcon;
 	struct display *currcon_display;
@@ -67,6 +69,16 @@
 
 	riva_cfb8_cmap_t palette[256];	/* VGA DAC palette cache */
 
+	int panel_xres, panel_yres;
+	int clock;
+	int hOver_plus, hSync_width, hblank;
+	int vOver_plus, vSync_width, vblank;
+	int hAct_high, vAct_high, interlaced;
+	int synct, misc;
+
+	int use_default_var;
+	int got_dfpinfo;
+
 #if defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB32)
 	union {
 #ifdef FBCON_HAS_CFB16
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/sis/sis_accel.c linux-2.4.21-pre6/drivers/video/sis/sis_accel.c
--- linux-2.4.20/drivers/video/sis/sis_accel.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/sis/sis_accel.c	2003-03-26 23:49:40.000000000 +0000
@@ -40,7 +40,9 @@
 #include <linux/sisfb.h>
 
 #include <asm/io.h>
+#ifdef CONFIG_MTRR
 #include <asm/mtrr.h>
+#endif
 
 #include <video/fbcon.h>
 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/sis/sis_main.c linux-2.4.21-pre6/drivers/video/sis/sis_main.c
--- linux-2.4.20/drivers/video/sis/sis_main.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/sis/sis_main.c	2003-03-26 23:49:50.000000000 +0000
@@ -51,7 +51,9 @@
 #include <linux/sisfb.h>
 
 #include <asm/io.h>
+#ifdef CONFIG_MTRR
 #include <asm/mtrr.h>
+#endif
 
 #include <video/fbcon.h>
 #include <video/fbcon-cfb8.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/sti/sticore.c linux-2.4.21-pre6/drivers/video/sti/sticore.c
--- linux-2.4.20/drivers/video/sti/sticore.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/sti/sticore.c	2003-03-26 23:49:40.000000000 +0000
@@ -467,6 +467,7 @@
 	return 0;
 }
 
+#ifdef CONFIG_FB
 struct sti_cooked_font * __init
 sti_select_fbfont( struct sti_cooked_rom *cooked_rom, char *fbfont_name )
 {
@@ -523,6 +524,13 @@
 
 	return cooked_font;
 }
+#else
+struct sti_cooked_font * __init
+sti_select_fbfont(struct sti_cooked_rom *cooked_rom, char *fbfont_name)
+{
+	return NULL;
+}
+#endif
 
 struct sti_cooked_font * __init
 sti_select_font(struct sti_cooked_rom *rom,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/sti/stifb.c linux-2.4.21-pre6/drivers/video/sti/stifb.c
--- linux-2.4.20/drivers/video/sti/stifb.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/sti/stifb.c	2003-03-26 23:49:20.000000000 +0000
@@ -133,7 +133,7 @@
 #endif			
 };
 
-static int stifb_force_bpp[MAX_STI_ROMS] = {0, };
+static int stifb_force_bpp[MAX_STI_ROMS];
 
 /* ------------------- chipset specific functions -------------------------- */
 
@@ -1290,7 +1290,10 @@
 		fb->id = S9000_ID_A1659A;
 		break;
 	case S9000_ID_A1439A:	/* CRX24/A1439A */
-		bpp = 32;
+		if (force_bpp == 8 || force_bpp == 32)
+		  bpp = force_bpp;
+		else
+		  bpp = 32;
 		break;
 	case S9000_ID_HCRX:	/* Hyperdrive/HCRX */
 		memset(&fb->ngle_rom, 0, sizeof(fb->ngle_rom));
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/drivers/video/vga.h linux-2.4.21-pre6/drivers/video/vga.h
--- linux-2.4.20/drivers/video/vga.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/drivers/video/vga.h	2003-03-26 23:49:08.000000000 +0000
@@ -1,7 +1,7 @@
 /*
  * linux/include/video/vga.h -- standard VGA chipset interaction
  *
- * Copyright 1999 Jeff Garzik <jgarzik@mandrakesoft.com>
+ * Copyright 1999 Jeff Garzik <jgarzik@pobox.com>
  * 
  * Copyright history from vga16fb.c:
  *	Copyright 1999 Ben Pfaff and Petr Vandrovec
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/befs/TODO linux-2.4.21-pre6/fs/befs/TODO
--- linux-2.4.20/fs/befs/TODO	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/befs/TODO	2003-03-26 23:49:38.000000000 +0000
@@ -3,14 +3,9 @@
 
 * Convert comments to the Kernel-Doc format.
 
-* Befs_fs.h has gotten big and messy. No reason not to break it up into 
-	smaller peices.
-
 * See if Alexander Viro's option parser made it into the kernel tree. 
 	Use that if we can. (include/linux/parser.h)
 
 * See if we really need separate types for on-disk and in-memory 
 	representations of the superblock and inode.
 
-* We need a wrapper around the kernel's disk cache stuff. Then it would be 
-	easy to slip in stuff like using the pagecache.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/befs/attribute.c linux-2.4.21-pre6/fs/befs/attribute.c
--- linux-2.4.20/fs/befs/attribute.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/befs/attribute.c	2003-03-26 23:48:58.000000000 +0000
@@ -12,7 +12,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 
-#include "befs_fs.h"
+#include "befs.h"
 #include "endian.h"
 
 #define SD_DATA(sd)\
@@ -27,7 +27,6 @@
 
 befs_small_data *find_small_data(struct super_block *sb, befs_inode * inode,
 				 const char *name);
-
 int
  read_small_data(struct super_block *sb, befs_inode * inode,
 		 befs_small_data * sdata, void *buf, size_t bufsize);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/befs/befs.h linux-2.4.21-pre6/fs/befs/befs.h
--- linux-2.4.20/fs/befs/befs.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/fs/befs/befs.h	2003-03-26 23:48:57.000000000 +0000
@@ -0,0 +1,152 @@
+/*
+ * befs_fs.h
+ *
+ * Copyright (C) 2001-2002 Will Dyson <will_dyson@pobox.com>
+ * Copyright (C) 1999 Makoto Kato (m_kato@ga2.so-net.ne.jp)
+ */
+
+#ifndef _LINUX_BEFS_H
+#define _LINUX_BEFS_H
+
+#include "befs_fs_types.h"
+
+/* used in debug.c */
+#define BEFS_VERSION "0.9.3"
+
+typedef u64 befs_blocknr_t;
+typedef u32 vfs_blocknr_t;
+
+/*
+ * BeFS in memory structures
+ */
+
+typedef struct befs_mount_options {
+	gid_t gid;
+	uid_t uid;
+	int use_gid;
+	int use_uid;
+	int debug;
+	char *iocharset;
+} befs_mount_options;
+
+typedef struct befs_sb_info {
+	u32 magic1;
+	u32 block_size;
+	u32 block_shift;
+	int byte_order;
+	befs_off_t num_blocks;
+	befs_off_t used_blocks;
+	u32 inode_size;
+	u32 magic2;
+
+	/* Allocation group information */
+	u32 blocks_per_ag;
+	u32 ag_shift;
+	u32 num_ags;
+
+	/* jornal log entry */
+	befs_block_run log_blocks;
+	befs_off_t log_start;
+	befs_off_t log_end;
+
+	befs_inode_addr root_dir;
+	befs_inode_addr indices;
+	u32 magic3;
+
+	befs_mount_options mount_opts;
+	struct nls_table *nls;
+
+} befs_sb_info;
+
+typedef struct befs_inode_info {
+	u32 i_flags;
+	u32 i_type;
+
+	befs_inode_addr i_inode_num;
+	befs_inode_addr i_parent;
+	befs_inode_addr i_attribute;
+
+	union {
+		befs_data_stream ds;
+		char symlink[BEFS_SYMLINK_LEN];
+	} i_data;
+
+} befs_inode_info;
+
+enum befs_err {
+	BEFS_OK,
+	BEFS_ERR,
+	BEFS_BAD_INODE,
+	BEFS_BT_END,
+	BEFS_BT_EMPTY,
+	BEFS_BT_MATCH,
+	BEFS_BT_PARMATCH,
+	BEFS_BT_NOT_FOUND
+};
+
+/****************************/
+/* debug.c */
+void befs_error(const struct super_block *sb, const char *fmt, ...);
+void befs_warning(const struct super_block *sb, const char *fmt, ...);
+void befs_debug(const struct super_block *sb, const char *fmt, ...);
+
+void befs_dump_super_block(const struct super_block *sb, befs_super_block *);
+void befs_dump_inode(const struct super_block *sb, befs_inode *);
+void befs_dump_index_entry(const struct super_block *sb, befs_btree_super *);
+void befs_dump_index_node(const struct super_block *sb, befs_btree_nodehead *);
+void befs_dump_inode_addr(const struct super_block *sb, befs_inode_addr);
+/****************************/
+
+/* Gets a pointer to the private portion of the super_block
+ * structure from the public part
+ */
+static inline befs_sb_info *
+BEFS_SB(const struct super_block *super)
+{
+	return (befs_sb_info *) super->u.generic_sbp;
+}
+
+static inline befs_inode_info *
+BEFS_I(const struct inode *inode)
+{
+	return (befs_inode_info *) inode->u.generic_ip;
+}
+
+static inline befs_blocknr_t
+iaddr2blockno(struct super_block *sb, befs_inode_addr * iaddr)
+{
+	return ((iaddr->allocation_group << BEFS_SB(sb)->ag_shift) +
+		iaddr->start);
+}
+
+static inline befs_inode_addr
+blockno2iaddr(struct super_block *sb, befs_blocknr_t blockno)
+{
+	befs_inode_addr iaddr;
+	iaddr.allocation_group = blockno >> BEFS_SB(sb)->ag_shift;
+	iaddr.start =
+	    blockno - (iaddr.allocation_group << BEFS_SB(sb)->ag_shift);
+	iaddr.len = 1;
+
+	return iaddr;
+}
+
+static inline unsigned int
+befs_iaddrs_per_block(struct super_block *sb)
+{
+	return BEFS_SB(sb)->block_size / sizeof (befs_inode_addr);
+}
+
+static inline int
+befs_iaddr_is_empty(befs_inode_addr * iaddr)
+{
+	return (!iaddr->allocation_group) && (!iaddr->start) && (!iaddr->len);
+}
+
+static inline size_t
+befs_brun_size(struct super_block *sb, befs_block_run run)
+{
+	return BEFS_SB(sb)->block_size * run.len;
+}
+
+#endif				/* _LINUX_BEFS_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/befs/befs_fs.h linux-2.4.21-pre6/fs/befs/befs_fs.h
--- linux-2.4.20/fs/befs/befs_fs.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/befs/befs_fs.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,200 +0,0 @@
-/*
- * befs_fs.h
- *
- * Copyright (C) 2001-2002 Will Dyson <will_dyson@pobox.com>
- * Copyright (C) 1999 Makoto Kato (m_kato@ga2.so-net.ne.jp)
- */
-
-#ifndef _LINUX_BEFS_FS
-#define _LINUX_BEFS_FS
-
-#include "befs_fs_types.h"
-#include "compatibility.h"
-
-/* used in debug.c */
-#define BEFS_VERSION "0.9.2"
-
-typedef __u64 befs_blocknr_t;
-typedef __u32 vfs_blocknr_t;
-
-/*
- * BeFS in memory structures
- */
-
-typedef struct befs_mount_options {
-	gid_t gid;
-	uid_t uid;
-	int use_gid;
-	int use_uid;
-	int debug;
-	char *iocharset;
-} befs_mount_options;
-
-typedef struct befs_sb_info {
-	__u32 magic1;
-	__u32 block_size;
-	__u32 block_shift;
-	__u32 byte_order;
-	befs_off_t num_blocks;
-	befs_off_t used_blocks;
-	__u32 inode_size;
-	__u32 magic2;
-
-	/* Allocation group information */
-	__u32 blocks_per_ag;
-	__u32 ag_shift;
-	__u32 num_ags;
-
-	/* jornal log entry */
-	befs_block_run log_blocks;
-	befs_off_t log_start;
-	befs_off_t log_end;
-
-	befs_inode_addr root_dir;
-	befs_inode_addr indices;
-	__u32 magic3;
-
-	befs_mount_options mount_opts;
-	struct nls_table *nls;
-
-} befs_sb_info;
-
-typedef struct befs_inode_info {
-	__u32 i_flags;
-	__u32 i_type;
-
-	befs_inode_addr i_inode_num;
-	befs_inode_addr i_parent;
-	befs_inode_addr i_attribute;
-
-	union {
-		befs_data_stream ds;
-		char symlink[BEFS_SYMLINK_LEN];
-	} i_data;
-
-} befs_inode_info;
-
-enum befs_err {
-	BEFS_OK,
-	BEFS_ERR,
-	BEFS_BAD_INODE,
-	BEFS_BT_END,
-	BEFS_BT_EMPTY,
-	BEFS_BT_MATCH,
-	BEFS_BT_PARMATCH,
-	BEFS_BT_NOT_FOUND
-};
-
-/****************************/
-/* io.c */
-struct buffer_head *befs_bread_iaddr(struct super_block *sb,
-				     befs_inode_addr iaddr);
-
-struct buffer_head *befs_bread(struct super_block *sb, befs_blocknr_t block);
-/****************************/
-
-/****************************/
-/* datastream.c */
-struct buffer_head *befs_read_datastream(struct super_block *sb,
-					 befs_data_stream * ds, befs_off_t pos,
-					 uint * off);
-
-int befs_fblock2brun(struct super_block *sb, befs_data_stream * data,
-		     befs_blocknr_t fblock, befs_block_run * run);
-
-size_t befs_read_lsymlink(struct super_block *sb, befs_data_stream * data,
-			  void *buff, befs_off_t len);
-
-befs_blocknr_t befs_count_blocks(struct super_block *sb, befs_data_stream * ds);
-
-extern const befs_inode_addr BAD_IADDR;
-/****************************/
-
-/****************************/
-/* debug.c */
-void befs_error(const struct super_block *sb, const char *fmt, ...);
-void befs_warning(const struct super_block *sb, const char *fmt, ...);
-void befs_debug(const struct super_block *sb, const char *fmt, ...);
-
-void befs_dump_super_block(const struct super_block *sb, befs_super_block *);
-void befs_dump_inode(const struct super_block *sb, befs_inode *);
-void befs_dump_index_entry(const struct super_block *sb, befs_btree_super *);
-void befs_dump_index_node(const struct super_block *sb, befs_btree_nodehead *);
-void befs_dump_inode_addr(const struct super_block *sb, befs_inode_addr);
-/****************************/
-
-/****************************/
-/* btree.c */
-int befs_btree_find(struct super_block *sb, befs_data_stream * ds,
-		    const char *key, befs_off_t * value);
-
-int befs_btree_read(struct super_block *sb, befs_data_stream * ds,
-		    loff_t key_no, size_t bufsize, char *keybuf,
-		    size_t * keysize, befs_off_t * value);
-/****************************/
-
-/****************************/
-/* super.c */
-int befs_load_sb(struct super_block *sb, befs_super_block * disk_sb);
-int befs_check_sb(struct super_block *sb);
-/****************************/
-
-/****************************/
-/* inode.c */
-int befs_check_inode(struct super_block *sb, befs_inode * raw_inode,
-		     befs_blocknr_t inode);
-/****************************/
-
-/* Gets a pointer to the private portion of the super_block
- * structure from the public part
- */
-static inline befs_sb_info *
-BEFS_SB(const struct super_block *super)
-{
-	return (befs_sb_info *) super->u.generic_sbp;
-}
-
-static inline befs_inode_info *
-BEFS_I(const struct inode *inode)
-{
-	return (befs_inode_info *) inode->u.generic_ip;
-}
-
-static inline befs_blocknr_t
-iaddr2blockno(struct super_block *sb, befs_inode_addr * iaddr)
-{
-	return ((iaddr->allocation_group << BEFS_SB(sb)->ag_shift) +
-		iaddr->start);
-}
-
-static inline befs_inode_addr
-blockno2iaddr(struct super_block *sb, befs_blocknr_t blockno)
-{
-	befs_inode_addr iaddr;
-	iaddr.allocation_group = blockno >> BEFS_SB(sb)->ag_shift;
-	iaddr.start =
-	    blockno - (iaddr.allocation_group << BEFS_SB(sb)->ag_shift);
-	iaddr.len = 1;
-
-	return iaddr;
-}
-
-static inline unsigned int
-befs_iaddrs_per_block(struct super_block *sb)
-{
-	return BEFS_SB(sb)->block_size / sizeof (befs_inode_addr);
-}
-
-static inline int
-befs_iaddr_is_empty(befs_inode_addr * iaddr)
-{
-	return (!iaddr->allocation_group) && (!iaddr->start) && (!iaddr->len);
-}
-
-static inline size_t
-befs_brun_size(struct super_block *sb, befs_block_run run)
-{
-	return BEFS_SB(sb)->block_size * run.len;
-}
-
-#endif				/* _LINUX_BEFS_FS */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/befs/befs_fs_types.h linux-2.4.21-pre6/fs/befs/befs_fs_types.h
--- linux-2.4.20/fs/befs/befs_fs_types.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/befs/befs_fs_types.h	2003-03-26 23:49:18.000000000 +0000
@@ -45,15 +45,17 @@
  */
 
 enum super_flags {
+	BEFS_BYTESEX_BE,
+	BEFS_BYTESEX_LE,
 	BEFS_CLEAN = 0x434c454e,
 	BEFS_DIRTY = 0x44495254,
-	BEFS_BYTESEX_BE = 0x45474942,
-	BEFS_BYTESEX_LE = 0x42494745,
 	BEFS_SUPER_MAGIC1 = 0x42465331,	/* BFS1 */
 	BEFS_SUPER_MAGIC2 = 0xdd121031,
 	BEFS_SUPER_MAGIC3 = 0x15b6830e,
 };
 
+#define BEFS_BYTEORDER_NATIVE 0x42494745
+
 #define BEFS_SUPER_MAGIC BEFS_SUPER_MAGIC1
 
 /*
@@ -77,15 +79,15 @@
  * On-Disk datastructures of BeFS
  */
 
-typedef __u64 befs_off_t;
-typedef __u64 befs_time_t;
+typedef u64 befs_off_t;
+typedef u64 befs_time_t;
 typedef void befs_binode_etc;
 
 /* Block runs */
 typedef struct {
-	__u32 allocation_group;
-	__u16 start;
-	__u16 len;
+	u32 allocation_group;
+	u16 start;
+	u16 len;
 } PACKED befs_block_run;
 
 typedef befs_block_run befs_inode_addr;
@@ -95,29 +97,29 @@
  */
 typedef struct {
 	char name[B_OS_NAME_LENGTH];
-	__u32 magic1;
-	__u32 fs_byte_order;
+	u32 magic1;
+	u32 fs_byte_order;
 
-	__u32 block_size;
-	__u32 block_shift;
+	u32 block_size;
+	u32 block_shift;
 
 	befs_off_t num_blocks;
 	befs_off_t used_blocks;
 
-	__u32 inode_size;
+	u32 inode_size;
 
-	__u32 magic2;
-	__u32 blocks_per_ag;
-	__u32 ag_shift;
-	__u32 num_ags;
+	u32 magic2;
+	u32 blocks_per_ag;
+	u32 ag_shift;
+	u32 num_ags;
 
-	__u32 flags;
+	u32 flags;
 
 	befs_block_run log_blocks;
 	befs_off_t log_start;
 	befs_off_t log_end;
 
-	__u32 magic3;
+	u32 magic3;
 	befs_inode_addr root_dir;
 	befs_inode_addr indices;
 
@@ -139,35 +141,35 @@
 
 /* Attribute */
 typedef struct {
-	__u32 type;
-	__u16 name_size;
-	__u16 data_size;
+	u32 type;
+	u16 name_size;
+	u16 data_size;
 	char name[1];
 } PACKED befs_small_data;
 
 /* Inode structure */
 typedef struct {
-	__u32 magic1;
+	u32 magic1;
 	befs_inode_addr inode_num;
-	__u32 uid;
-	__u32 gid;
-	__u32 mode;
-	__u32 flags;
+	u32 uid;
+	u32 gid;
+	u32 mode;
+	u32 flags;
 	befs_time_t create_time;
 	befs_time_t last_modified_time;
 	befs_inode_addr parent;
 	befs_inode_addr attributes;
-	__u32 type;
+	u32 type;
 
-	__u32 inode_size;
-	__u32 etc;		/* not use */
+	u32 inode_size;
+	u32 etc;		/* not use */
 
 	union {
 		befs_data_stream datastream;
 		char symlink[BEFS_SYMLINK_LEN];
 	} data;
 
-	__u32 pad[4];		/* not use */
+	u32 pad[4];		/* not use */
 	befs_small_data small_data[1];
 } PACKED befs_inode;
 
@@ -188,10 +190,10 @@
 };
 
 typedef struct {
-	__u32 magic;
-	__u32 node_size;
-	__u32 max_depth;
-	__u32 data_type;
+	u32 magic;
+	u32 node_size;
+	u32 max_depth;
+	u32 data_type;
 	befs_off_t root_node_ptr;
 	befs_off_t free_node_ptr;
 	befs_off_t max_size;
@@ -204,8 +206,8 @@
 	befs_off_t left;
 	befs_off_t right;
 	befs_off_t overflow;
-	__u16 all_key_count;
-	__u16 all_key_length;
+	u16 all_key_count;
+	u16 all_key_length;
 } PACKED befs_btree_nodehead;
 
 #endif				/* _LINUX_BEFS_FS_TYPES */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/befs/btree.c linux-2.4.21-pre6/fs/befs/btree.c
--- linux-2.4.20/fs/befs/btree.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/befs/btree.c	2003-03-26 23:49:55.000000000 +0000
@@ -26,7 +26,9 @@
 #include <linux/slab.h>
 #include <linux/mm.h>
 
-#include "befs_fs.h"
+#include "befs.h"
+#include "btree.h"
+#include "datastream.h"
 #include "endian.h"
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/befs/btree.h linux-2.4.21-pre6/fs/befs/btree.h
--- linux-2.4.20/fs/befs/btree.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/fs/befs/btree.h	2003-03-26 23:49:07.000000000 +0000
@@ -0,0 +1,11 @@
+/*
+ * btree.h
+ * 
+ */
+
+int befs_btree_find(struct super_block *sb, befs_data_stream * ds,
+		    const char *key, befs_off_t * value);
+
+int befs_btree_read(struct super_block *sb, befs_data_stream * ds,
+		    loff_t key_no, size_t bufsize, char *keybuf,
+		    size_t * keysize, befs_off_t * value);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/befs/compatibility.h linux-2.4.21-pre6/fs/befs/compatibility.h
--- linux-2.4.20/fs/befs/compatibility.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/befs/compatibility.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,26 +0,0 @@
-/*
- * linux/fs/befs/compatiblity.h
- *
- * Copyright (C) 2001 Will Dyson <will_dyson@pobox.com>
- *   AKA <will@cs.earlham.edu>
- *
- * This file trys to take care of differences between
- * kernel versions
- */
-
-#include <linux/version.h>
-
-/* New interfaces in 2.4.10 */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10)
-
-#define min_t(type,x,y) \
-({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
-
-#define max_t(type,x,y) \
-({ type __x = (x); type __y = (y); __x > __y ? __x: __y; })
-
-#define vsnprintf(buf, n, fmt, args) vsprintf(buf, fmt, args)
-
-#define MODULE_LICENSE(x)
-
-#endif				/* LINUX_VERSION_CODE */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/befs/datastream.c linux-2.4.21-pre6/fs/befs/datastream.c
--- linux-2.4.20/fs/befs/datastream.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/befs/datastream.c	2003-03-26 23:49:20.000000000 +0000
@@ -15,7 +15,9 @@
 #include <linux/string.h>
 #include <linux/slab.h>
 
-#include "befs_fs.h"
+#include "befs.h"
+#include "datastream.h"
+#include "io.h"
 #include "endian.h"
 
 const befs_inode_addr BAD_IADDR = { 0, 0, 0 };
@@ -466,8 +468,7 @@
 	}
 
 	dbl_indir_block = befs_bread(sb,
-				     iaddr2blockno(sb,
-						   &data->double_indirect) +
+				     iaddr2blockno(sb, &data->double_indirect) +
 				     dbl_which_block);
 	if (dbl_indir_block == NULL) {
 		befs_error(sb, "befs_read_brun_dblindirect() couldn't read the "
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/befs/datastream.h linux-2.4.21-pre6/fs/befs/datastream.h
--- linux-2.4.20/fs/befs/datastream.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/fs/befs/datastream.h	2003-03-26 23:49:51.000000000 +0000
@@ -0,0 +1,18 @@
+/*
+ * datastream.h
+ *
+ */
+
+struct buffer_head *befs_read_datastream(struct super_block *sb,
+					 befs_data_stream * ds, befs_off_t pos,
+					 uint * off);
+
+int befs_fblock2brun(struct super_block *sb, befs_data_stream * data,
+		     befs_blocknr_t fblock, befs_block_run * run);
+
+size_t befs_read_lsymlink(struct super_block *sb, befs_data_stream * data,
+			  void *buff, befs_off_t len);
+
+befs_blocknr_t befs_count_blocks(struct super_block *sb, befs_data_stream * ds);
+
+extern const befs_inode_addr BAD_IADDR;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/befs/debug.c linux-2.4.21-pre6/fs/befs/debug.c
--- linux-2.4.20/fs/befs/debug.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/befs/debug.c	2003-03-26 23:49:29.000000000 +0000
@@ -20,7 +20,7 @@
 
 #endif				/* __KERNEL__ */
 
-#include "befs_fs.h"
+#include "befs.h"
 #include "endian.h"
 
 #define ERRBUFSIZE 1024
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/befs/endian.h linux-2.4.21-pre6/fs/befs/endian.h
--- linux-2.4.20/fs/befs/endian.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/befs/endian.h	2003-03-26 23:49:25.000000000 +0000
@@ -10,7 +10,6 @@
 #define LINUX_BEFS_ENDIAN
 
 #include <linux/byteorder/generic.h>
-#include "befs_fs.h"
 
 static inline u64
 fs64_to_cpu(const struct super_block *sb, u64 n)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/befs/inode.c linux-2.4.21-pre6/fs/befs/inode.c
--- linux-2.4.20/fs/befs/inode.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/befs/inode.c	2003-03-26 23:49:50.000000000 +0000
@@ -6,7 +6,8 @@
 
 #include <linux/fs.h>
 
-#include "befs_fs.h"
+#include "befs.h"
+#include "inode.h"
 #include "endian.h"
 
 /*
@@ -18,9 +19,9 @@
 befs_check_inode(struct super_block *sb, befs_inode * raw_inode,
 		 befs_blocknr_t inode)
 {
-	__u32 magic1 = fs32_to_cpu(sb, raw_inode->magic1);
+	u32 magic1 = fs32_to_cpu(sb, raw_inode->magic1);
 	befs_inode_addr ino_num = fsrun_to_cpu(sb, raw_inode->inode_num);
-	__u32 flags = fs32_to_cpu(sb, raw_inode->flags);
+	u32 flags = fs32_to_cpu(sb, raw_inode->flags);
 
 	/* check magic header. */
 	if (magic1 != BEFS_INODE_MAGIC1) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/befs/inode.h linux-2.4.21-pre6/fs/befs/inode.h
--- linux-2.4.20/fs/befs/inode.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/fs/befs/inode.h	2003-03-26 23:49:35.000000000 +0000
@@ -0,0 +1,7 @@
+/*
+ * inode.h
+ * 
+ */
+
+int befs_check_inode(struct super_block *sb, befs_inode * raw_inode,
+		     befs_blocknr_t inode);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/befs/io.c linux-2.4.21-pre6/fs/befs/io.c
--- linux-2.4.20/fs/befs/io.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/befs/io.c	2003-03-26 23:49:50.000000000 +0000
@@ -13,7 +13,8 @@
 
 #include <linux/fs.h>
 
-#include "befs_fs.h"
+#include "befs.h"
+#include "io.h"
 
 /*
  * Converts befs notion of disk addr to a disk offset and uses
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/befs/io.h linux-2.4.21-pre6/fs/befs/io.h
--- linux-2.4.20/fs/befs/io.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/fs/befs/io.h	2003-03-26 23:48:58.000000000 +0000
@@ -0,0 +1,8 @@
+/*
+ * io.h
+ */
+
+struct buffer_head *befs_bread_iaddr(struct super_block *sb,
+				     befs_inode_addr iaddr);
+
+struct buffer_head *befs_bread(struct super_block *sb, befs_blocknr_t block);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/befs/linuxvfs.c linux-2.4.21-pre6/fs/befs/linuxvfs.c
--- linux-2.4.20/fs/befs/linuxvfs.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/befs/linuxvfs.c	2003-03-26 23:49:39.000000000 +0000
@@ -15,7 +15,12 @@
 #include <linux/string.h>
 #include <linux/nls.h>
 
-#include "befs_fs.h"
+#include "befs.h"
+#include "btree.h"
+#include "inode.h"
+#include "datastream.h"
+#include "super.h"
+#include "io.h"
 #include "endian.h"
 
 EXPORT_NO_SYMBOLS;
@@ -35,42 +40,55 @@
 static void befs_clear_inode(struct inode *ino);
 static int befs_init_inodecache(void);
 static void befs_destroy_inodecache(void);
+
 static int befs_readlink(struct dentry *, char *, int);
 static int befs_follow_link(struct dentry *, struct nameidata *nd);
+
 static int befs_utf2nls(struct super_block *sb, const char *in, int in_len,
 			char **out, int *out_len);
 static int befs_nls2utf(struct super_block *sb, const char *in, int in_len,
 			char **out, int *out_len);
+
 static void befs_put_super(struct super_block *);
 static struct super_block *befs_read_super(struct super_block *, void *, int);
 static int befs_remount(struct super_block *, int *, char *);
 static int befs_statfs(struct super_block *, struct statfs *);
 static int parse_options(char *, befs_mount_options *);
 
+static ssize_t befs_listxattr(struct dentry *dentry, char *buffer, size_t size);
+static ssize_t befs_getxattr(struct dentry *dentry, const char *name,
+			     void *buffer, size_t size);
+static int befs_setxattr(struct dentry *dentry, const char *name, void *value,
+			 size_t size, int flags);
+static int befs_removexattr(struct dentry *dentry, const char *name);
+
+/* slab cache for befs_inode_info objects */
+static kmem_cache_t *befs_inode_cachep;
+
 static const struct super_operations befs_sops = {
 	read_inode:befs_read_inode,	/* initialize & read inode */
 	clear_inode:befs_clear_inode,	/* uninit inode */
 	put_super:befs_put_super,	/* uninit super */
 	statfs:befs_statfs,	/* statfs */
-	remount_fs:befs_remount	/* remount_fs */
+	remount_fs:befs_remount,
 };
 
-/* slab cache for befs_inode_info objects */
-static kmem_cache_t *befs_inode_cachep;
-
 struct file_operations befs_dir_operations = {
-	read:generic_read_dir,	/* read */
-	readdir:befs_readdir,	/* readdir */
+	read:generic_read_dir,
+	readdir:befs_readdir,
 };
 
 struct inode_operations befs_dir_inode_operations = {
-	lookup:befs_lookup,	/* lookup */
+	lookup:befs_lookup,
 };
 
 struct file_operations befs_file_operations = {
 	llseek:default_llseek,
-	read:generic_file_read,	/* read */
-	mmap:generic_file_mmap,	/* mmap */
+	read:generic_file_read,
+	mmap:generic_file_mmap,
+};
+
+struct inode_operations befs_file_inode_operations = {
 };
 
 struct address_space_operations befs_aops = {
@@ -80,8 +98,8 @@
 };
 
 static struct inode_operations befs_symlink_inode_operations = {
-	readlink:befs_readlink,	/* readlink */
-	follow_link:befs_follow_link	/* follow_link */
+	readlink:befs_readlink,
+	follow_link:befs_follow_link,
 };
 
 /* 
@@ -353,12 +371,7 @@
 	    (time_t) (fs64_to_cpu(sb, raw_inode->last_modified_time) >> 16);
 	inode->i_ctime = inode->i_mtime;
 	inode->i_atime = inode->i_mtime;
-
-/* Bloody hell, Linus. Why add this in a stable series? */
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,9)
 	inode->i_blkbits = befs_sb->block_shift;
-#endif
-
 	inode->i_blksize = befs_sb->block_size;
 
 	befs_ino->i_inode_num = fsrun_to_cpu(sb, raw_inode->inode_num);
@@ -387,6 +400,7 @@
 
 	if (S_ISREG(inode->i_mode)) {
 		inode->i_fop = &befs_file_operations;
+		inode->i_op = &befs_file_inode_operations;
 	} else if (S_ISDIR(inode->i_mode)) {
 		inode->i_op = &befs_dir_inode_operations;
 		inode->i_fop = &befs_dir_operations;
@@ -539,7 +553,7 @@
 	wchar_t uni;
 	int unilen, utflen;
 	char *result;
-	int maxlen = in_len; /* The utf8->nls conversion cant make more chars */
+	int maxlen = in_len;	/* The utf8->nls conversion cant make more chars */
 
 	befs_debug(sb, "---> utf2nls()");
 
@@ -661,6 +675,37 @@
 	return -EILSEQ;
 }
 
+/****Xattr****/
+
+static ssize_t
+befs_listxattr(struct dentry *dentry, char *buffer, size_t size)
+{
+	printk(KERN_ERR "befs_listxattr called\n");
+	return 0;
+}
+
+static ssize_t
+befs_getxattr(struct dentry *dentry, const char *name,
+	      void *buffer, size_t size)
+{
+	return 0;
+}
+
+static int
+befs_setxattr(struct dentry *dentry, const char *name,
+	      void *value, size_t size, int flags)
+{
+	return 0;
+}
+
+static int
+befs_removexattr(struct dentry *dentry, const char *name)
+{
+	return 0;
+}
+
+/****Superblock****/
+
 static int
 parse_options(char *options, befs_mount_options * opts)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/befs/super.c linux-2.4.21-pre6/fs/befs/super.c
--- linux-2.4.20/fs/befs/super.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/befs/super.c	2003-03-26 23:49:30.000000000 +0000
@@ -9,7 +9,8 @@
 
 #include <linux/fs.h>
 
-#include "befs_fs.h"
+#include "befs.h"
+#include "super.h"
 #include "endian.h"
 
 /**
@@ -25,8 +26,11 @@
 {
 	befs_sb_info *befs_sb = BEFS_SB(sb);
 
-	/* byte_order is special, no byte-swap */
-	befs_sb->byte_order = disk_sb->fs_byte_order;
+	/* Check the byte order of the filesystem */
+	if (le32_to_cpu(disk_sb->fs_byte_order) == BEFS_BYTEORDER_NATIVE)
+		befs_sb->byte_order = BEFS_BYTESEX_LE;
+	else if (be32_to_cpu(disk_sb->fs_byte_order) == BEFS_BYTEORDER_NATIVE)
+		befs_sb->byte_order = BEFS_BYTESEX_BE;
 
 	befs_sb->magic1 = fs32_to_cpu(sb, disk_sb->magic1);
 	befs_sb->magic2 = fs32_to_cpu(sb, disk_sb->magic2);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/befs/super.h linux-2.4.21-pre6/fs/befs/super.h
--- linux-2.4.20/fs/befs/super.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/fs/befs/super.h	2003-03-26 23:49:25.000000000 +0000
@@ -0,0 +1,7 @@
+/*
+ * super.h
+ */
+
+int befs_load_sb(struct super_block *sb, befs_super_block * disk_sb);
+
+int befs_check_sb(struct super_block *sb);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/buffer.c linux-2.4.21-pre6/fs/buffer.c
--- linux-2.4.20/fs/buffer.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/buffer.c	2003-03-26 23:49:40.000000000 +0000
@@ -328,6 +328,8 @@
 	if (sb->s_dirt && sb->s_op && sb->s_op->write_super)
 		sb->s_op->write_super(sb);
 	unlock_super(sb);
+	if (sb->s_op && sb->s_op->sync_fs)
+		sb->s_op->sync_fs(sb);
 	unlock_kernel();
 
 	return sync_buffers(dev, 1);
@@ -346,7 +348,7 @@
 	lock_kernel();
 	sync_inodes(dev);
 	DQUOT_SYNC(dev);
-	sync_supers(dev);
+	sync_supers(dev, 1);
 	unlock_kernel();
 
 	return sync_buffers(dev, 1);
@@ -583,37 +585,29 @@
 	return bh;
 }
 
-void buffer_insert_inode_queue(struct buffer_head *bh, struct inode *inode)
+void buffer_insert_list(struct buffer_head *bh, struct list_head *list)
 {
 	spin_lock(&lru_list_lock);
-	if (bh->b_inode)
+	if (buffer_attached(bh))
 		list_del(&bh->b_inode_buffers);
-	bh->b_inode = inode;
-	list_add(&bh->b_inode_buffers, &inode->i_dirty_buffers);
+	set_buffer_attached(bh);
+	list_add(&bh->b_inode_buffers, list);
 	spin_unlock(&lru_list_lock);
 }
 
-void buffer_insert_inode_data_queue(struct buffer_head *bh, struct inode *inode)
-{
-	spin_lock(&lru_list_lock);
-	if (bh->b_inode)
-		list_del(&bh->b_inode_buffers);
-	bh->b_inode = inode;
-	list_add(&bh->b_inode_buffers, &inode->i_dirty_data_buffers);
-	spin_unlock(&lru_list_lock);
-}
-
-/* The caller must have the lru_list lock before calling the 
-   remove_inode_queue functions.  */
+/*
+ * The caller must have the lru_list lock before calling the 
+ * remove_inode_queue functions.
+ */
 static void __remove_inode_queue(struct buffer_head *bh)
 {
-	bh->b_inode = NULL;
 	list_del(&bh->b_inode_buffers);
+	clear_buffer_attached(bh);
 }
 
 static inline void remove_inode_queue(struct buffer_head *bh)
 {
-	if (bh->b_inode)
+	if (buffer_attached(bh))
 		__remove_inode_queue(bh);
 }
 
@@ -695,13 +689,13 @@
 			/* All buffers in the lru lists are mapped */
 			if (!buffer_mapped(bh))
 				BUG();
-			if (buffer_dirty(bh))
+			if (buffer_dirty(bh) && destroy_dirty_buffers)
 				printk("invalidate: dirty buffer\n");
 			if (!atomic_read(&bh->b_count)) {
 				if (destroy_dirty_buffers || !buffer_dirty(bh)) {
 					remove_inode_queue(bh);
 				}
-			} else
+			} else if (!bdev->bd_openers)
 				printk("invalidate: busy buffer\n");
 
 			write_unlock(&hash_table_lock);
@@ -831,10 +825,10 @@
 int fsync_buffers_list(struct list_head *list)
 {
 	struct buffer_head *bh;
-	struct inode tmp;
+	struct list_head tmp;
 	int err = 0, err2;
 	
-	INIT_LIST_HEAD(&tmp.i_dirty_buffers);
+	INIT_LIST_HEAD(&tmp);
 	
 	spin_lock(&lru_list_lock);
 
@@ -842,10 +836,10 @@
 		bh = BH_ENTRY(list->next);
 		list_del(&bh->b_inode_buffers);
 		if (!buffer_dirty(bh) && !buffer_locked(bh))
-			bh->b_inode = NULL;
+			clear_buffer_attached(bh);
 		else {
-			bh->b_inode = &tmp;
-			list_add(&bh->b_inode_buffers, &tmp.i_dirty_buffers);
+			set_buffer_attached(bh);
+			list_add(&bh->b_inode_buffers, &tmp);
 			if (buffer_dirty(bh)) {
 				get_bh(bh);
 				spin_unlock(&lru_list_lock);
@@ -865,8 +859,8 @@
 		}
 	}
 
-	while (!list_empty(&tmp.i_dirty_buffers)) {
-		bh = BH_ENTRY(tmp.i_dirty_buffers.prev);
+	while (!list_empty(&tmp)) {
+		bh = BH_ENTRY(tmp.prev);
 		remove_inode_queue(bh);
 		get_bh(bh);
 		spin_unlock(&lru_list_lock);
@@ -1138,7 +1132,7 @@
  */
 static void __put_unused_buffer_head(struct buffer_head * bh)
 {
-	if (bh->b_inode)
+	if (unlikely(buffer_attached(bh)))
 		BUG();
 	if (nr_unused_buffer_heads >= MAX_UNUSED_BUFFERS) {
 		kmem_cache_free(bh_cachep, bh);
@@ -2833,7 +2827,7 @@
 {
 	lock_kernel();
 	sync_unlocked_inodes();
-	sync_supers(0);
+	sync_supers(0, 0);
 	unlock_kernel();
 
 	for (;;) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/dcache.c linux-2.4.21-pre6/fs/dcache.c
--- linux-2.4.20/fs/dcache.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/dcache.c	2003-03-26 23:49:07.000000000 +0000
@@ -977,21 +977,24 @@
 		namelen = dentry->d_name.len;
 		buflen -= namelen + 1;
 		if (buflen < 0)
-			break;
+			return ERR_PTR(-ENAMETOOLONG);
 		end -= namelen;
 		memcpy(end, dentry->d_name.name, namelen);
 		*--end = '/';
 		retval = end;
 		dentry = parent;
 	}
+
 	return retval;
+
 global_root:
 	namelen = dentry->d_name.len;
 	buflen -= namelen;
 	if (buflen >= 0) {
 		retval -= namelen-1;	/* hit the slash */
 		memcpy(retval, dentry->d_name.name, namelen);
-	}
+	} else
+		retval = ERR_PTR(-ENAMETOOLONG);
 	return retval;
 }
 
@@ -1040,6 +1043,10 @@
 		cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE);
 		spin_unlock(&dcache_lock);
 
+		error = PTR_ERR(cwd);
+		if (IS_ERR(cwd))
+			goto out;
+
 		error = -ERANGE;
 		len = PAGE_SIZE + page - cwd;
 		if (len <= size) {
@@ -1049,6 +1056,8 @@
 		}
 	} else
 		spin_unlock(&dcache_lock);
+
+out:
 	dput(pwd);
 	mntput(pwdmnt);
 	dput(root);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/exec.c linux-2.4.21-pre6/fs/exec.c
--- linux-2.4.20/fs/exec.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/exec.c	2003-03-26 23:49:29.000000000 +0000
@@ -35,6 +35,8 @@
 #include <linux/highmem.h>
 #include <linux/spinlock.h>
 #include <linux/personality.h>
+#include <linux/swap.h>
+#include <linux/utsname.h>
 #define __NO_VERSION__
 #include <linux/module.h>
 
@@ -47,6 +49,8 @@
 #endif
 
 int core_uses_pid;
+char core_pattern[65] = "core";
+/* The maximal length of core_pattern is also specified in sysctl.c */ 
 
 static struct linux_binfmt *formats;
 static rwlock_t binfmt_lock = RW_LOCK_UNLOCKED;
@@ -572,8 +576,10 @@
 
 	current->sas_ss_sp = current->sas_ss_size = 0;
 
-	if (current->euid == current->uid && current->egid == current->gid)
+	if (current->euid == current->uid && current->egid == current->gid) {
 		current->mm->dumpable = 1;
+		current->task_dumpable = 1;
+	}
 	name = bprm->filename;
 	for (i=0; (ch = *(name++)) != '\0';) {
 		if (ch == '/')
@@ -953,10 +959,126 @@
 		__MOD_DEC_USE_COUNT(old->module);
 }
 
+#define CORENAME_MAX_SIZE 64
+
+/* format_corename will inspect the pattern parameter, and output a
+ * name into corename, which must have space for at least
+ * CORENAME_MAX_SIZE bytes plus one byte for the zero terminator.
+ */
+void format_corename(char *corename, const char *pattern, long signr)
+{
+	const char *pat_ptr = pattern;
+	char *out_ptr = corename;
+	char *const out_end = corename + CORENAME_MAX_SIZE;
+	int rc;
+	int pid_in_pattern = 0;
+
+	/* Repeat as long as we have more pattern to process and more output
+	   space */
+	while (*pat_ptr) {
+		if (*pat_ptr != '%') {
+			if (out_ptr == out_end)
+				goto out;
+			*out_ptr++ = *pat_ptr++;
+		} else {
+			switch (*++pat_ptr) {
+			case 0:
+				goto out;
+			/* Double percent, output one percent */
+			case '%':
+				if (out_ptr == out_end)
+					goto out;
+				*out_ptr++ = '%';
+				break;
+			/* pid */
+			case 'p':
+				pid_in_pattern = 1;
+				rc = snprintf(out_ptr, out_end - out_ptr,
+					      "%d", current->pid);
+				if (rc > out_end - out_ptr)
+					goto out;
+				out_ptr += rc;
+				break;
+			/* uid */
+			case 'u':
+				rc = snprintf(out_ptr, out_end - out_ptr,
+					      "%d", current->uid);
+				if (rc > out_end - out_ptr)
+					goto out;
+				out_ptr += rc;
+				break;
+			/* gid */
+			case 'g':
+				rc = snprintf(out_ptr, out_end - out_ptr,
+					      "%d", current->gid);
+				if (rc > out_end - out_ptr)
+					goto out;
+				out_ptr += rc;
+				break;
+			/* signal that caused the coredump */
+			case 's':
+				rc = snprintf(out_ptr, out_end - out_ptr,
+					      "%ld", signr);
+				if (rc > out_end - out_ptr)
+					goto out;
+				out_ptr += rc;
+				break;
+			/* UNIX time of coredump */
+			case 't': {
+				struct timeval tv;
+				do_gettimeofday(&tv);
+				rc = snprintf(out_ptr, out_end - out_ptr,
+					      "%ld", tv.tv_sec);
+				if (rc > out_end - out_ptr)
+					goto out;
+				out_ptr += rc;
+				break;
+			}
+			/* hostname */
+			case 'h':
+				down_read(&uts_sem);
+				rc = snprintf(out_ptr, out_end - out_ptr,
+					      "%s", system_utsname.nodename);
+				up_read(&uts_sem);
+				if (rc > out_end - out_ptr)
+					goto out;
+				out_ptr += rc;
+				break;
+			/* executable */
+			case 'e':
+				rc = snprintf(out_ptr, out_end - out_ptr,
+					      "%s", current->comm);
+				if (rc > out_end - out_ptr)
+					goto out;
+				out_ptr += rc;
+				break;
+			default:
+				break;
+			}
+			++pat_ptr;
+		}
+	}
+	/* Backward compatibility with core_uses_pid:
+	 *
+	 * If core_pattern does not include a %p (as is the default)
+	 * and core_uses_pid is set, then .%pid will be appended to
+	 * the filename */
+	if (!pid_in_pattern
+            && (core_uses_pid || atomic_read(&current->mm->mm_users) != 1)) {
+		rc = snprintf(out_ptr, out_end - out_ptr,
+			      ".%d", current->pid);
+		if (rc > out_end - out_ptr)
+			goto out;
+		out_ptr += rc;
+	}
+      out:
+	*out_ptr = 0;
+}
+
 int do_coredump(long signr, struct pt_regs * regs)
 {
 	struct linux_binfmt * binfmt;
-	char corename[6+sizeof(current->comm)+10];
+	char corename[CORENAME_MAX_SIZE + 1];
 	struct file * file;
 	struct inode * inode;
 	int retval = 0;
@@ -965,15 +1087,13 @@
 	binfmt = current->binfmt;
 	if (!binfmt || !binfmt->core_dump)
 		goto fail;
-	if (!current->mm->dumpable)
+	if (!is_dumpable(current))
 		goto fail;
 	current->mm->dumpable = 0;
 	if (current->rlim[RLIMIT_CORE].rlim_cur < binfmt->min_coredump)
 		goto fail;
 
-	memcpy(corename,"core", 5); /* include trailing \0 */
- 	if (core_uses_pid || atomic_read(&current->mm->mm_users) != 1)
- 		sprintf(&corename[4], ".%d", current->pid);
+ 	format_corename(corename, core_pattern, signr);
 	file = filp_open(corename, O_CREAT | 2 | O_NOFOLLOW, 0600);
 	if (IS_ERR(file))
 		goto fail;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/ext2/ialloc.c linux-2.4.21-pre6/fs/ext2/ialloc.c
--- linux-2.4.20/fs/ext2/ialloc.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/ext2/ialloc.c	2003-03-26 23:49:39.000000000 +0000
@@ -390,8 +390,7 @@
 	if (S_ISLNK(mode))
 		inode->u.ext2_i.i_flags &= ~(EXT2_IMMUTABLE_FL|EXT2_APPEND_FL);
 	inode->u.ext2_i.i_block_group = group;
-	if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL)
-		inode->i_flags |= S_SYNC;
+	ext2_set_inode_flags(inode);
 	insert_inode_hash(inode);
 	inode->i_generation = event++;
 	mark_inode_dirty(inode);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/ext2/inode.c linux-2.4.21-pre6/fs/ext2/inode.c
--- linux-2.4.20/fs/ext2/inode.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/ext2/inode.c	2003-03-26 23:49:00.000000000 +0000
@@ -877,6 +877,21 @@
 	}
 }
 
+void ext2_set_inode_flags(struct inode *inode)
+{
+	unsigned int flags = inode->u.ext2_i.i_flags;
+
+	inode->i_flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME);
+	if (flags & EXT2_SYNC_FL)
+		inode->i_flags |= S_SYNC;
+	if (flags & EXT2_APPEND_FL)
+		inode->i_flags |= S_APPEND;
+	if (flags & EXT2_IMMUTABLE_FL)
+		inode->i_flags |= S_IMMUTABLE;
+	if (flags & EXT2_NOATIME_FL)
+		inode->i_flags |= S_NOATIME;
+}
+
 void ext2_read_inode (struct inode * inode)
 {
 	struct buffer_head * bh;
@@ -997,22 +1012,7 @@
 				   le32_to_cpu(raw_inode->i_block[0]));
 	brelse (bh);
 	inode->i_attr_flags = 0;
-	if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL) {
-		inode->i_attr_flags |= ATTR_FLAG_SYNCRONOUS;
-		inode->i_flags |= S_SYNC;
-	}
-	if (inode->u.ext2_i.i_flags & EXT2_APPEND_FL) {
-		inode->i_attr_flags |= ATTR_FLAG_APPEND;
-		inode->i_flags |= S_APPEND;
-	}
-	if (inode->u.ext2_i.i_flags & EXT2_IMMUTABLE_FL) {
-		inode->i_attr_flags |= ATTR_FLAG_IMMUTABLE;
-		inode->i_flags |= S_IMMUTABLE;
-	}
-	if (inode->u.ext2_i.i_flags & EXT2_NOATIME_FL) {
-		inode->i_attr_flags |= ATTR_FLAG_NOATIME;
-		inode->i_flags |= S_NOATIME;
-	}
+	ext2_set_inode_flags(inode);
 	return;
 	
 bad_inode:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/ext2/ioctl.c linux-2.4.21-pre6/fs/ext2/ioctl.c
--- linux-2.4.20/fs/ext2/ioctl.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/ext2/ioctl.c	2003-03-26 23:49:39.000000000 +0000
@@ -53,22 +53,7 @@
 		flags |= oldflags & ~EXT2_FL_USER_MODIFIABLE;
 		inode->u.ext2_i.i_flags = flags;
 
-		if (flags & EXT2_SYNC_FL)
-			inode->i_flags |= S_SYNC;
-		else
-			inode->i_flags &= ~S_SYNC;
-		if (flags & EXT2_APPEND_FL)
-			inode->i_flags |= S_APPEND;
-		else
-			inode->i_flags &= ~S_APPEND;
-		if (flags & EXT2_IMMUTABLE_FL)
-			inode->i_flags |= S_IMMUTABLE;
-		else
-			inode->i_flags &= ~S_IMMUTABLE;
-		if (flags & EXT2_NOATIME_FL)
-			inode->i_flags |= S_NOATIME;
-		else
-			inode->i_flags &= ~S_NOATIME;
+		ext2_set_inode_flags(inode);
 		inode->i_ctime = CURRENT_TIME;
 		mark_inode_dirty(inode);
 		return 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/ext3/ialloc.c linux-2.4.21-pre6/fs/ext3/ialloc.c
--- linux-2.4.20/fs/ext3/ialloc.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/ext3/ialloc.c	2003-03-26 23:49:39.000000000 +0000
@@ -64,8 +64,8 @@
 	if (!bh) {
 		ext3_error (sb, "read_inode_bitmap",
 			    "Cannot read inode bitmap - "
-			    "block_group = %lu, inode_bitmap = %lu",
-			    block_group, (unsigned long) gdp->bg_inode_bitmap);
+			    "block_group = %lu, inode_bitmap = %u",
+			    block_group, gdp->bg_inode_bitmap);
 		retval = -EIO;
 	}
 	/*
@@ -500,8 +500,7 @@
 #endif
 	inode->u.ext3_i.i_block_group = i;
 	
-	if (inode->u.ext3_i.i_flags & EXT3_SYNC_FL)
-		inode->i_flags |= S_SYNC;
+	ext3_set_inode_flags(inode);
 	if (IS_SYNC(inode))
 		handle->h_sync = 1;
 	insert_inode_hash(inode);
@@ -531,19 +530,19 @@
 }
 
 /* Verify that we are loading a valid orphan from disk */
-struct inode *ext3_orphan_get (struct super_block * sb, ino_t ino)
+struct inode *ext3_orphan_get(struct super_block *sb, unsigned long ino)
 {
-	ino_t max_ino = le32_to_cpu(EXT3_SB(sb)->s_es->s_inodes_count);
+	unsigned long max_ino = le32_to_cpu(EXT3_SB(sb)->s_es->s_inodes_count);
 	unsigned long block_group;
 	int bit;
 	int bitmap_nr;
 	struct buffer_head *bh;
 	struct inode *inode = NULL;
-	
+
 	/* Error cases - e2fsck has already cleaned up for us */
 	if (ino > max_ino) {
 		ext3_warning(sb, __FUNCTION__,
-			     "bad orphan ino %ld!  e2fsck was run?\n", ino);
+			     "bad orphan ino %lu!  e2fsck was run?\n", ino);
 		return NULL;
 	}
 
@@ -552,7 +551,7 @@
 	if ((bitmap_nr = load_inode_bitmap(sb, block_group)) < 0 ||
 	    !(bh = EXT3_SB(sb)->s_inode_bitmap[bitmap_nr])) {
 		ext3_warning(sb, __FUNCTION__,
-			     "inode bitmap error for orphan %ld\n", ino);
+			     "inode bitmap error for orphan %lu\n", ino);
 		return NULL;
 	}
 
@@ -563,16 +562,16 @@
 	if (!ext3_test_bit(bit, bh->b_data) || !(inode = iget(sb, ino)) ||
 	    is_bad_inode(inode) || NEXT_ORPHAN(inode) > max_ino) {
 		ext3_warning(sb, __FUNCTION__,
-			     "bad orphan inode %ld!  e2fsck was run?\n", ino);
+			     "bad orphan inode %lu!  e2fsck was run?\n", ino);
 		printk(KERN_NOTICE "ext3_test_bit(bit=%d, block=%ld) = %d\n",
 		       bit, bh->b_blocknr, ext3_test_bit(bit, bh->b_data));
 		printk(KERN_NOTICE "inode=%p\n", inode);
 		if (inode) {
 			printk(KERN_NOTICE "is_bad_inode(inode)=%d\n",
 			       is_bad_inode(inode));
-			printk(KERN_NOTICE "NEXT_ORPHAN(inode)=%d\n",
+			printk(KERN_NOTICE "NEXT_ORPHAN(inode)=%u\n",
 			       NEXT_ORPHAN(inode));
-			printk(KERN_NOTICE "max_ino=%ld\n", max_ino);
+			printk(KERN_NOTICE "max_ino=%lu\n", max_ino);
 		}
 		/* Avoid freeing blocks if we got a bad deleted inode */
 		if (inode && inode->i_nlink == 0)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/ext3/inode.c linux-2.4.21-pre6/fs/ext3/inode.c
--- linux-2.4.20/fs/ext3/inode.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/ext3/inode.c	2003-03-26 23:49:50.000000000 +0000
@@ -87,6 +87,34 @@
 	return err;
 }
 
+/*
+ * Work out how many blocks we need to progress with the next chunk of a
+ * truncate transaction.
+ */
+
+static unsigned long blocks_for_truncate(struct inode *inode) 
+{
+	unsigned long needed;
+	
+	needed = inode->i_blocks >> (inode->i_sb->s_blocksize_bits - 9);
+
+	/* Give ourselves just enough room to cope with inodes in which
+	 * i_blocks is corrupt: we've seen disk corruptions in the past
+	 * which resulted in random data in an inode which looked enough
+	 * like a regular file for ext3 to try to delete it.  Things
+	 * will go a bit crazy if that happens, but at least we should
+	 * try not to panic the whole kernel. */
+	if (needed < 2)
+		needed = 2;
+
+	/* But we need to bound the transaction so we don't overflow the
+	 * journal. */
+	if (needed > EXT3_MAX_TRANS_DATA) 
+		needed = EXT3_MAX_TRANS_DATA;
+
+	return EXT3_DATA_TRANS_BLOCKS + needed;
+}
+	
 /* 
  * Truncate transactions can be complex and absolutely huge.  So we need to
  * be able to restart the transaction at a conventient checkpoint to make
@@ -100,14 +128,9 @@
 
 static handle_t *start_transaction(struct inode *inode) 
 {
-	long needed;
 	handle_t *result;
 	
-	needed = inode->i_blocks;
-	if (needed > EXT3_MAX_TRANS_DATA) 
-		needed = EXT3_MAX_TRANS_DATA;
-	
-	result = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS + needed);
+	result = ext3_journal_start(inode, blocks_for_truncate(inode));
 	if (!IS_ERR(result))
 		return result;
 	
@@ -123,14 +146,9 @@
  */
 static int try_to_extend_transaction(handle_t *handle, struct inode *inode)
 {
-	long needed;
-	
 	if (handle->h_buffer_credits > EXT3_RESERVE_TRANS_BLOCKS)
 		return 0;
-	needed = inode->i_blocks;
-	if (needed > EXT3_MAX_TRANS_DATA) 
-		needed = EXT3_MAX_TRANS_DATA;
-	if (!ext3_journal_extend(handle, EXT3_RESERVE_TRANS_BLOCKS + needed))
+	if (!ext3_journal_extend(handle, blocks_for_truncate(inode)))
 		return 0;
 	return 1;
 }
@@ -142,11 +160,8 @@
  */
 static int ext3_journal_test_restart(handle_t *handle, struct inode *inode)
 {
-	long needed = inode->i_blocks;
-	if (needed > EXT3_MAX_TRANS_DATA) 
-		needed = EXT3_MAX_TRANS_DATA;
 	jbd_debug(2, "restarting handle %p\n", handle);
-	return ext3_journal_restart(handle, EXT3_DATA_TRANS_BLOCKS + needed);
+	return ext3_journal_restart(handle, blocks_for_truncate(inode));
 }
 
 /*
@@ -2053,6 +2068,22 @@
 	return -EIO;
 }
 
+void ext3_set_inode_flags(struct inode *inode)
+{
+	unsigned int flags = inode->u.ext3_i.i_flags;
+
+	inode->i_flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME);
+	if (flags & EXT3_SYNC_FL)
+		inode->i_flags |= S_SYNC;
+	if (flags & EXT3_APPEND_FL)
+		inode->i_flags |= S_APPEND;
+	if (flags & EXT3_IMMUTABLE_FL)
+		inode->i_flags |= S_IMMUTABLE;
+	if (flags & EXT3_NOATIME_FL)
+		inode->i_flags |= S_NOATIME;
+}
+
+
 void ext3_read_inode(struct inode * inode)
 {
 	struct ext3_iloc iloc;
@@ -2150,23 +2181,7 @@
 	} else 
 		init_special_inode(inode, inode->i_mode,
 				   le32_to_cpu(iloc.raw_inode->i_block[0]));
-	/* inode->i_attr_flags = 0;				unused */
-	if (inode->u.ext3_i.i_flags & EXT3_SYNC_FL) {
-		/* inode->i_attr_flags |= ATTR_FLAG_SYNCRONOUS; unused */
-		inode->i_flags |= S_SYNC;
-	}
-	if (inode->u.ext3_i.i_flags & EXT3_APPEND_FL) {
-		/* inode->i_attr_flags |= ATTR_FLAG_APPEND;	unused */
-		inode->i_flags |= S_APPEND;
-	}
-	if (inode->u.ext3_i.i_flags & EXT3_IMMUTABLE_FL) {
-		/* inode->i_attr_flags |= ATTR_FLAG_IMMUTABLE;	unused */
-		inode->i_flags |= S_IMMUTABLE;
-	}
-	if (inode->u.ext3_i.i_flags & EXT3_NOATIME_FL) {
-		/* inode->i_attr_flags |= ATTR_FLAG_NOATIME;	unused */
-		inode->i_flags |= S_NOATIME;
-	}
+	ext3_set_inode_flags(inode);
 	return;
 	
 bad_inode:
@@ -2270,7 +2285,7 @@
 			}
 		}
 	}
-	raw_inode->i_generation = le32_to_cpu(inode->i_generation);
+	raw_inode->i_generation = cpu_to_le32(inode->i_generation);
 	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
 		raw_inode->i_block[0] =
 			cpu_to_le32(kdev_t_to_nr(inode->i_rdev));
@@ -2553,7 +2568,7 @@
 	handle_t *handle;
 
 	lock_kernel();
-	handle = ext3_journal_start(inode, 1);
+	handle = ext3_journal_start(inode, 2);
 	if (IS_ERR(handle))
 		goto out;
 	if (current_handle &&
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/ext3/ioctl.c linux-2.4.21-pre6/fs/ext3/ioctl.c
--- linux-2.4.20/fs/ext3/ioctl.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/ext3/ioctl.c	2003-03-26 23:49:30.000000000 +0000
@@ -81,22 +81,7 @@
 		flags |= oldflags & ~EXT3_FL_USER_MODIFIABLE;
 		inode->u.ext3_i.i_flags = flags;
 
-		if (flags & EXT3_SYNC_FL)
-			inode->i_flags |= S_SYNC;
-		else
-			inode->i_flags &= ~S_SYNC;
-		if (flags & EXT3_APPEND_FL)
-			inode->i_flags |= S_APPEND;
-		else
-			inode->i_flags &= ~S_APPEND;
-		if (flags & EXT3_IMMUTABLE_FL)
-			inode->i_flags |= S_IMMUTABLE;
-		else
-			inode->i_flags &= ~S_IMMUTABLE;
-		if (flags & EXT3_NOATIME_FL)
-			inode->i_flags |= S_NOATIME;
-		else
-			inode->i_flags &= ~S_NOATIME;
+		ext3_set_inode_flags(inode);
 		inode->i_ctime = CURRENT_TIME;
 
 		err = ext3_mark_iloc_dirty(handle, inode, &iloc);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/ext3/namei.c linux-2.4.21-pre6/fs/ext3/namei.c
--- linux-2.4.20/fs/ext3/namei.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/ext3/namei.c	2003-03-26 23:49:40.000000000 +0000
@@ -429,8 +429,11 @@
 {
 	int err = ext3_add_entry(handle, dentry, inode);
 	if (!err) {
-		d_instantiate(dentry, inode);
-		return 0;
+		err = ext3_mark_inode_dirty(handle, inode);
+		if (err == 0) {
+			d_instantiate(dentry, inode);
+			return 0;
+		}
 	}
 	ext3_dec_count(handle, inode);
 	iput(inode);
@@ -465,7 +468,6 @@
 		inode->i_fop = &ext3_file_operations;
 		inode->i_mapping->a_ops = &ext3_aops;
 		err = ext3_add_nondir(handle, dentry, inode);
-		ext3_mark_inode_dirty(handle, inode);
 	}
 	ext3_journal_stop(handle, dir);
 	return err;
@@ -490,7 +492,6 @@
 	if (!IS_ERR(inode)) {
 		init_special_inode(inode, mode, rdev);
 		err = ext3_add_nondir(handle, dentry, inode);
-		ext3_mark_inode_dirty(handle, inode);
 	}
 	ext3_journal_stop(handle, dir);
 	return err;
@@ -715,10 +716,10 @@
 {
 	struct list_head *prev;
 	struct ext3_sb_info *sbi;
-	ino_t ino_next; 
+	unsigned long ino_next;
 	struct ext3_iloc iloc;
 	int err = 0;
-	
+
 	lock_super(inode->i_sb);
 	if (list_empty(&inode->u.ext3_i.i_orphan)) {
 		unlock_super(inode->i_sb);
@@ -729,7 +730,7 @@
 	prev = inode->u.ext3_i.i_orphan.prev;
 	sbi = EXT3_SB(inode->i_sb);
 
-	jbd_debug(4, "remove inode %ld from orphan list\n", inode->i_ino);
+	jbd_debug(4, "remove inode %lu from orphan list\n", inode->i_ino);
 
 	list_del(&inode->u.ext3_i.i_orphan);
 	INIT_LIST_HEAD(&inode->u.ext3_i.i_orphan);
@@ -740,13 +741,13 @@
 	 * list in memory. */
 	if (!handle)
 		goto out;
-	
+
 	err = ext3_reserve_inode_write(handle, inode, &iloc);
 	if (err)
 		goto out_err;
 
 	if (prev == &sbi->s_orphan) {
-		jbd_debug(4, "superblock will point to %ld\n", ino_next);
+		jbd_debug(4, "superblock will point to %lu\n", ino_next);
 		BUFFER_TRACE(sbi->s_sbh, "get_write_access");
 		err = ext3_journal_get_write_access(handle, sbi->s_sbh);
 		if (err)
@@ -757,8 +758,8 @@
 		struct ext3_iloc iloc2;
 		struct inode *i_prev =
 			list_entry(prev, struct inode, u.ext3_i.i_orphan);
-		
-		jbd_debug(4, "orphan inode %ld will point to %ld\n",
+
+		jbd_debug(4, "orphan inode %lu will point to %lu\n",
 			  i_prev->i_ino, ino_next);
 		err = ext3_reserve_inode_write(handle, i_prev, &iloc2);
 		if (err)
@@ -773,7 +774,7 @@
 	if (err)
 		goto out_brelse;
 
-out_err: 	
+out_err:
 	ext3_std_error(inode->i_sb, err);
 out:
 	unlock_super(inode->i_sb);
@@ -934,7 +935,6 @@
 	}
 	inode->u.ext3_i.i_disksize = inode->i_size;
 	err = ext3_add_nondir(handle, dentry, inode);
-	ext3_mark_inode_dirty(handle, inode);
 out_stop:
 	ext3_journal_stop(handle, dir);
 	return err;
@@ -971,7 +971,6 @@
 	atomic_inc(&inode->i_count);
 
 	err = ext3_add_nondir(handle, dentry, inode);
-	ext3_mark_inode_dirty(handle, inode);
 	ext3_journal_stop(handle, dir);
 	return err;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/ext3/super.c linux-2.4.21-pre6/fs/ext3/super.c
--- linux-2.4.20/fs/ext3/super.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/ext3/super.c	2003-03-26 23:49:54.000000000 +0000
@@ -47,6 +47,8 @@
 static void ext3_clear_journal_err(struct super_block * sb,
 				   struct ext3_super_block * es);
 
+static int ext3_sync_fs(struct super_block * sb);
+
 #ifdef CONFIG_JBD_DEBUG
 int journal_no_write[2];
 
@@ -454,6 +456,7 @@
 	delete_inode:	ext3_delete_inode,	/* BKL not held.  We take it */
 	put_super:	ext3_put_super,		/* BKL held */
 	write_super:	ext3_write_super,	/* BKL held */
+	sync_fs:	ext3_sync_fs,
 	write_super_lockfs: ext3_write_super_lockfs, /* BKL not held. Take it */
 	unlockfs:	ext3_unlockfs,		/* BKL not held.  We take it */
 	statfs:		ext3_statfs,		/* BKL held */
@@ -1577,24 +1580,22 @@
  * This implicitly triggers the writebehind on sync().
  */
 
-static int do_sync_supers = 0;
-MODULE_PARM(do_sync_supers, "i");
-MODULE_PARM_DESC(do_sync_supers, "Write superblocks synchronously");
-
 void ext3_write_super (struct super_block * sb)
 {
+	if (down_trylock(&sb->s_lock) == 0)
+		BUG();
+	sb->s_dirt = 0;
+	log_start_commit(EXT3_SB(sb)->s_journal, NULL);
+}
+
+static int ext3_sync_fs(struct super_block *sb)
+{
 	tid_t target;
 	
-	if (down_trylock(&sb->s_lock) == 0)
-		BUG();		/* aviro detector */
 	sb->s_dirt = 0;
 	target = log_start_commit(EXT3_SB(sb)->s_journal, NULL);
-
-	if (do_sync_supers) {
-		unlock_super(sb);
-		log_wait_commit(EXT3_SB(sb)->s_journal, target);
-		lock_super(sb);
-	}
+	log_wait_commit(EXT3_SB(sb)->s_journal, target);
+	return 0;
 }
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/inode.c linux-2.4.21-pre6/fs/inode.c
--- linux-2.4.20/fs/inode.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/fs/inode.c	2003-03-26 23:49:55.000000000 +0000
@@ -75,13 +75,59 @@
 
 static kmem_cache_t * inode_cachep;
 
-#define alloc_inode() \
-	 ((struct inode *) kmem_cache_alloc(inode_cachep, SLAB_KERNEL))
+static struct inode *alloc_inode(struct super_block *sb)
+{
+	static struct address_space_operations empty_aops;
+	static struct inode_operations empty_iops;
+	static struct file_operations empty_fops;
+	struct inode *inode;
+
+	if (sb->s_op->alloc_inode)
+		inode = sb->s_op->alloc_inode(sb);
+	else {
+		inode = (struct inode *) kmem_cache_alloc(inode_cachep, SLAB_KERNEL);
+		/* will die */
+		if (inode)
+			memset(&inode->u, 0, sizeof(inode->u));
+	}
+
+	if (inode) {
+		struct address_space * const mapping = &inode->i_data;
+
+		inode->i_sb = sb;
+		inode->i_dev = sb->s_dev;
+		inode->i_blkbits = sb->s_blocksize_bits;
+		inode->i_flags = 0;
+		atomic_set(&inode->i_count, 1);
+		inode->i_sock = 0;
+		inode->i_op = &empty_iops;
+		inode->i_fop = &empty_fops;
+		inode->i_nlink = 1;
+		atomic_set(&inode->i_writecount, 0);
+		inode->i_size = 0;
+		inode->i_blocks = 0;
+		inode->i_generation = 0;
+		memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
+		inode->i_pipe = NULL;
+		inode->i_bdev = NULL;
+		inode->i_cdev = NULL;
+
+		mapping->a_ops = &empty_aops;
+		mapping->host = inode;
+		mapping->gfp_mask = GFP_HIGHUSER;
+		inode->i_mapping = mapping;
+	}
+	return inode;
+}
+
 static void destroy_inode(struct inode *inode) 
 {
 	if (inode_has_buffers(inode))
 		BUG();
-	kmem_cache_free(inode_cachep, (inode));
+	if (inode->i_sb->s_op->destroy_inode)
+		inode->i_sb->s_op->destroy_inode(inode);
+	else
+		kmem_cache_free(inode_cachep, inode);
 }
 
 
@@ -90,27 +136,30 @@
  * once, because the fields are idempotent across use
  * of the inode, so let the slab aware of that.
  */
+void inode_init_once(struct inode *inode)
+{
+	memset(inode, 0, sizeof(*inode));
+	init_waitqueue_head(&inode->i_wait);
+	INIT_LIST_HEAD(&inode->i_hash);
+	INIT_LIST_HEAD(&inode->i_data.clean_pages);
+	INIT_LIST_HEAD(&inode->i_data.dirty_pages);
+	INIT_LIST_HEAD(&inode->i_data.locked_pages);
+	INIT_LIST_HEAD(&inode->i_dentry);
+	INIT_LIST_HEAD(&inode->i_dirty_buffers);
+	INIT_LIST_HEAD(&inode->i_dirty_data_buffers);
+	INIT_LIST_HEAD(&inode->i_devices);
+	sema_init(&inode->i_sem, 1);
+	sema_init(&inode->i_zombie, 1);
+	spin_lock_init(&inode->i_data.i_shared_lock);
+}
+
 static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
 {
 	struct inode * inode = (struct inode *) foo;
 
 	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
 	    SLAB_CTOR_CONSTRUCTOR)
-	{
-		memset(inode, 0, sizeof(*inode));
-		init_waitqueue_head(&inode->i_wait);
-		INIT_LIST_HEAD(&inode->i_hash);
-		INIT_LIST_HEAD(&inode->i_data.clean_pages);
-		INIT_LIST_HEAD(&inode->i_data.dirty_pages);
-		INIT_LIST_HEAD(&inode->i_data.locked_pages);
-		INIT_LIST_HEAD(&inode->i_dentry);
-		INIT_LIST_HEAD(&inode->i_dirty_buffers);
-		INIT_LIST_HEAD(&inode->i_dirty_data_buffers);
-		INIT_LIST_HEAD(&inode->i_devices);
-		sema_init(&inode->i_sem, 1);
-		sema_init(&inode->i_zombie, 1);
-		spin_lock_init(&inode->i_data.i_shared_lock);
-	}
+		inode_init_once(inode);
 }
 
 /*
@@ -757,72 +806,28 @@
 	return inode;
 }
 
-/*
- * This just initializes the inode fields
- * to known values before returning the inode..
- *
- * i_sb, i_ino, i_count, i_state and the lists have
- * been initialized elsewhere..
- */
-static void clean_inode(struct inode *inode)
-{
-	static struct address_space_operations empty_aops;
-	static struct inode_operations empty_iops;
-	static struct file_operations empty_fops;
-	memset(&inode->u, 0, sizeof(inode->u));
-	inode->i_sock = 0;
-	inode->i_op = &empty_iops;
-	inode->i_fop = &empty_fops;
-	inode->i_nlink = 1;
-	atomic_set(&inode->i_writecount, 0);
-	inode->i_size = 0;
-	inode->i_blocks = 0;
-	inode->i_generation = 0;
-	memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
-	inode->i_pipe = NULL;
-	inode->i_bdev = NULL;
-	inode->i_cdev = NULL;
-	inode->i_data.a_ops = &empty_aops;
-	inode->i_data.host = inode;
-	inode->i_data.gfp_mask = GFP_HIGHUSER;
-	inode->i_mapping = &inode->i_data;
-}
-
 /**
- * get_empty_inode 	- obtain an inode
- *
- * This is called by things like the networking layer
- * etc that want to get an inode without any inode
- * number, or filesystems that allocate new inodes with
- * no pre-existing information.
+ *	new_inode 	- obtain an inode
+ *	@sb: superblock
  *
- * On a successful return the inode pointer is returned. On a failure
- * a %NULL pointer is returned. The returned inode is not on any superblock
- * lists.
+ *	Allocates a new inode for given superblock.
  */
  
-struct inode * get_empty_inode(void)
+struct inode * new_inode(struct super_block *sb)
 {
 	static unsigned long last_ino;
 	struct inode * inode;
 
 	spin_lock_prefetch(&inode_lock);
 	
-	inode = alloc_inode();
-	if (inode)
-	{
+	inode = alloc_inode(sb);
+	if (inode) {
 		spin_lock(&inode_lock);
 		inodes_stat.nr_inodes++;
 		list_add(&inode->i_list, &inode_in_use);
-		inode->i_sb = NULL;
-		inode->i_dev = 0;
-		inode->i_blkbits = 0;
 		inode->i_ino = ++last_ino;
-		inode->i_flags = 0;
-		atomic_set(&inode->i_count, 1);
 		inode->i_state = 0;
 		spin_unlock(&inode_lock);
-		clean_inode(inode);
 	}
 	return inode;
 }
@@ -837,7 +842,7 @@
 {
 	struct inode * inode;
 
-	inode = alloc_inode();
+	inode = alloc_inode(sb);
 	if (inode) {
 		struct inode * old;
 
@@ -848,17 +853,10 @@
 			inodes_stat.nr_inodes++;
 			list_add(&inode->i_list, &inode_in_use);
 			list_add(&inode->i_hash, head);
-			inode->i_sb = sb;
-			inode->i_dev = sb->s_dev;
-			inode->i_blkbits = sb->s_blocksize_bits;
 			inode->i_ino = ino;
-			inode->i_flags = 0;
-			atomic_set(&inode->i_count, 1);
 			inode->i_state = I_LOCK;
 			spin_unlock(&inode_lock);
 
-			clean_inode(inode);
-
 			/* reiserfs specific hack right here.  We don't
 			** want this to last, and are looking for VFS changes
 			** that will allow us to get rid of it.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/jbd/journal.c linux-2.4.21-pre6/fs/jbd/journal.c
--- linux-2.4.20/fs/jbd/journal.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/jbd/journal.c	2003-03-26 23:49:09.000000000 +0000
@@ -730,14 +730,21 @@
  * need to set up all of the mapping information to tell the journaling
  * system where the journal blocks are.
  *
- * journal_init_dev creates a journal which maps a fixed contiguous
- * range of blocks on an arbitrary block device.
- *
- * journal_init_inode creates a journal which maps an on-disk inode as
- * the journal.  The inode must exist already, must support bmap() and
- * must have all data blocks preallocated.
  */
 
+ /**
+  *  journal_t * journal_init_dev() - creates an initialises a journal structure
+  *  @kdev: Block device on which to create the journal
+  *  @fs_dev: Device which hold journalled filesystem for this journal.
+  *  @start: Block nr Start of journal.
+  *  @len:  Lenght of the journal in blocks.
+  *  @blocksize: blocksize of journalling device
+  *  @returns: a newly created journal_t *
+  *  
+  *  journal_init_dev creates a journal which maps a fixed contiguous
+  *  range of blocks on an arbitrary block device.
+  * 
+  */
 journal_t * journal_init_dev(kdev_t dev, kdev_t fs_dev,
 			int start, int len, int blocksize)
 {
@@ -760,7 +767,15 @@
 
 	return journal;
 }
-
+ 
+/** 
+ *  journal_t * journal_init_inode () - creates a journal which maps to a inode.
+ *  @inode: An inode to create the journal in
+ *  
+ * journal_init_inode creates a journal which maps an on-disk inode as
+ * the journal.  The inode must exist already, must support bmap() and
+ * must have all data blocks preallocated.
+ */
 journal_t * journal_init_inode (struct inode *inode)
 {
 	struct buffer_head *bh;
@@ -850,12 +865,15 @@
 	return 0;
 }
 
-/*
+/** 
+ * int journal_create() - Initialise the new journal file
+ * @journal: Journal to create. This structure must have been initialised
+ * 
  * Given a journal_t structure which tells us which disk blocks we can
  * use, create a new journal superblock and initialise all of the
- * journal fields from scratch.  */
-
-int journal_create (journal_t *journal)
+ * journal fields from scratch.  
+ **/
+int journal_create(journal_t *journal)
 {
 	unsigned long blocknr;
 	struct buffer_head *bh;
@@ -916,11 +934,14 @@
 	return journal_reset(journal);
 }
 
-/*
+/** 
+ * void journal_update_superblock() - Update journal sb on disk.
+ * @journal: The journal to update.
+ * @wait: Set to '0' if you don't want to wait for IO completion.
+ *
  * Update a journal's dynamic superblock fields and write it to disk,
  * optionally waiting for the IO to complete.
-*/
-
+ */
 void journal_update_superblock(journal_t *journal, int wait)
 {
 	journal_superblock_t *sb = journal->j_superblock;
@@ -1036,12 +1057,14 @@
 }
 
 
-/*
+/**
+ * int journal_load() - Read journal from disk.
+ * @journal: Journal to act on.
+ * 
  * Given a journal_t structure which tells us which disk blocks contain
  * a journal, read the journal from disk to initialise the in-memory
  * structures.
  */
-
 int journal_load(journal_t *journal)
 {
 	int err;
@@ -1086,11 +1109,13 @@
 	return -EIO;
 }
 
-/*
+/**
+ * void journal_destroy() - Release a journal_t structure.
+ * @journal: Journal to act on.
+* 
  * Release a journal_t structure once it is no longer in use by the
  * journaled object.
  */
-
 void journal_destroy (journal_t *journal)
 {
 	/* Wait for the commit thread to wake up and die. */
@@ -1128,8 +1153,12 @@
 }
 
 
-/* Published API: Check whether the journal uses all of a given set of
- * features.  Return true (non-zero) if it does. */
+/**
+ *int journal_check_used_features () - Check if features specified are used.
+ * 
+ * Check whether the journal uses all of a given set of
+ * features.  Return true (non-zero) if it does. 
+ **/
 
 int journal_check_used_features (journal_t *journal, unsigned long compat,
 				 unsigned long ro, unsigned long incompat)
@@ -1151,7 +1180,10 @@
 	return 0;
 }
 
-/* Published API: Check whether the journaling code supports the use of
+/**
+ * int journal_check_available_features() - Check feature set in journalling layer
+ * 
+ * Check whether the journaling code supports the use of
  * all of a given set of features on this journal.  Return true
  * (non-zero) if it can. */
 
@@ -1180,8 +1212,13 @@
 	return 0;
 }
 
-/* Published API: Mark a given journal feature as present on the
- * superblock.  Returns true if the requested features could be set. */
+/**
+ * int journal_set_features () - Mark a given journal feature in the superblock
+ *
+ * Mark a given journal feature as present on the
+ * superblock.  Returns true if the requested features could be set. 
+ *
+ */
 
 int journal_set_features (journal_t *journal, unsigned long compat,
 			  unsigned long ro, unsigned long incompat)
@@ -1207,12 +1244,12 @@
 }
 
 
-/*
- * Published API:
+/**
+ * int journal_update_format () - Update on-disk journal structure.
+ *
  * Given an initialised but unloaded journal struct, poke about in the
  * on-disk structure to update it to the most recent supported version.
  */
-
 int journal_update_format (journal_t *journal)
 {
 	journal_superblock_t *sb;
@@ -1262,7 +1299,10 @@
 }
 
 
-/*
+/**
+ * int journal_flush () - Flush journal
+ * @journal: Journal to act on.
+ * 
  * Flush all data for a given journal to disk and empty the journal.
  * Filesystems can use this when remounting readonly to ensure that
  * recovery does not need to happen on remount.
@@ -1316,12 +1356,16 @@
 	return err;
 }
 
-/*
+/**
+ * int journal_wipe() - Wipe journal contents
+ * @journal: Journal to act on.
+ * @write: flag (see below)
+ * 
  * Wipe out all of the contents of a journal, safely.  This will produce
  * a warning if the journal contains any valid recovery information.
  * Must be called between journal_init_*() and journal_load().
  *
- * If (write) is non-zero, then we wipe out the journal on disk; otherwise
+ * If 'write' is non-zero, then we wipe out the journal on disk; otherwise
  * we merely suppress recovery.
  */
 
@@ -1370,43 +1414,11 @@
 }
 
 /*
- * journal_abort: perform a complete, immediate shutdown of the ENTIRE
- * journal (not of a single transaction).  This operation cannot be
- * undone without closing and reopening the journal.
- *
- * The journal_abort function is intended to support higher level error
- * recovery mechanisms such as the ext2/ext3 remount-readonly error
- * mode.
- *
- * Journal abort has very specific semantics.  Any existing dirty,
- * unjournaled buffers in the main filesystem will still be written to
- * disk by bdflush, but the journaling mechanism will be suspended
- * immediately and no further transaction commits will be honoured.
+ * Journal abort has very specific semantics, which we describe
+ * for journal abort. 
  *
- * Any dirty, journaled buffers will be written back to disk without
- * hitting the journal.  Atomicity cannot be guaranteed on an aborted
- * filesystem, but we _do_ attempt to leave as much data as possible
- * behind for fsck to use for cleanup.
- *
- * Any attempt to get a new transaction handle on a journal which is in
- * ABORT state will just result in an -EROFS error return.  A
- * journal_stop on an existing handle will return -EIO if we have
- * entered abort state during the update.
- *
- * Recursive transactions are not disturbed by journal abort until the
- * final journal_stop, which will receive the -EIO error.
- *
- * Finally, the journal_abort call allows the caller to supply an errno
- * which will be recored (if possible) in the journal superblock.  This
- * allows a client to record failure conditions in the middle of a
- * transaction without having to complete the transaction to record the
- * failure to disk.  ext3_error, for example, now uses this
- * functionality.
- *
- * Errors which originate from within the journaling layer will NOT
- * supply an errno; a null errno implies that absolutely no further
- * writes are done to the journal (unless there are any already in
- * progress).
+ * Two internal function, which provide abort to te jbd layer
+ * itself are here.
  */
 
 /* Quick version for internal journal use (doesn't lock the journal).
@@ -1444,7 +1456,52 @@
 		journal_update_superblock(journal, 1);
 }
 
-/* Full version for external use */
+/**
+ * void journal_abort () - Shutdown the journal immediately.
+ * @journal: the journal to shutdown.
+ * @errno:   an error number to record in the journal indicating
+ *           the reason for the shutdown.
+ *
+ * Perform a complete, immediate shutdown of the ENTIRE
+ * journal (not of a single transaction).  This operation cannot be
+ * undone without closing and reopening the journal.
+ *           
+ * The journal_abort function is intended to support higher level error
+ * recovery mechanisms such as the ext2/ext3 remount-readonly error
+ * mode.
+ *
+ * Journal abort has very specific semantics.  Any existing dirty,
+ * unjournaled buffers in the main filesystem will still be written to
+ * disk by bdflush, but the journaling mechanism will be suspended
+ * immediately and no further transaction commits will be honoured.
+ *
+ * Any dirty, journaled buffers will be written back to disk without
+ * hitting the journal.  Atomicity cannot be guaranteed on an aborted
+ * filesystem, but we _do_ attempt to leave as much data as possible
+ * behind for fsck to use for cleanup.
+ *
+ * Any attempt to get a new transaction handle on a journal which is in
+ * ABORT state will just result in an -EROFS error return.  A
+ * journal_stop on an existing handle will return -EIO if we have
+ * entered abort state during the update.
+ *
+ * Recursive transactions are not disturbed by journal abort until the
+ * final journal_stop, which will receive the -EIO error.
+ *
+ * Finally, the journal_abort call allows the caller to supply an errno
+ * which will be recorded (if possible) in the journal superblock.  This
+ * allows a client to record failure conditions in the middle of a
+ * transaction without having to complete the transaction to record the
+ * failure to disk.  ext3_error, for example, now uses this
+ * functionality.
+ *
+ * Errors which originate from within the journaling layer will NOT
+ * supply an errno; a null errno implies that absolutely no further
+ * writes are done to the journal (unless there are any already in
+ * progress).
+ * 
+ */
+
 void journal_abort (journal_t *journal, int errno)
 {
 	lock_journal(journal);
@@ -1452,6 +1509,17 @@
 	unlock_journal(journal);
 }
 
+/** 
+ * int journal_errno () - returns the journal's error state.
+ * @journal: journal to examine.
+ *
+ * This is the errno numbet set with journal_abort(), the last
+ * time the journal was mounted - if the journal was stopped
+ * without calling abort this will be 0.
+ *
+ * If the journal has been aborted on this mount time -EROFS will
+ * be returned.
+ */
 int journal_errno (journal_t *journal)
 {
 	int err;
@@ -1465,6 +1533,14 @@
 	return err;
 }
 
+
+
+/** 
+ * int journal_clear_err () - clears the journal's error state
+ *
+ * An error must be cleared or Acked to take a FS out of readonly
+ * mode.
+ */
 int journal_clear_err (journal_t *journal)
 {
 	int err = 0;
@@ -1478,6 +1554,13 @@
 	return err;
 }
 
+
+/** 
+ * void journal_ack_err() - Ack journal err.
+ *
+ * An error must be cleared or Acked to take a FS out of readonly
+ * mode.
+ */
 void journal_ack_err (journal_t *journal)
 {
 	lock_journal(journal);
@@ -1664,8 +1747,8 @@
  *
  * Whenever a buffer has an attached journal_head, its ->b_state:BH_JBD bit
  * is set.  This bit is tested in core kernel code where we need to take
- * JBD-specific actions.  Testing the zeroness of ->b_private is not reliable
- * there.
+ * JBD-specific actions.  Testing the zeroness of ->b_journal_head is not
+ * reliable there.
  *
  * When a buffer has its BH_JBD bit set, its ->b_count is elevated by one.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/jbd/recovery.c linux-2.4.21-pre6/fs/jbd/recovery.c
--- linux-2.4.20/fs/jbd/recovery.c	2002-02-25 19:38:08.000000000 +0000
+++ linux-2.4.21-pre6/fs/jbd/recovery.c	2003-03-26 23:49:51.000000000 +0000
@@ -207,20 +207,22 @@
 		var -= ((journal)->j_last - (journal)->j_first);	\
 } while (0)
 
-/*
- * journal_recover
- *
+/**
+ * int journal_recover(journal_t *journal) - recovers a on-disk journal
+ * @journal: the journal to recover
+ * 
  * The primary function for recovering the log contents when mounting a
  * journaled device.  
- * 
+ */
+int journal_recover(journal_t *journal)
+{
+/*
  * Recovery is done in three passes.  In the first pass, we look for the
  * end of the log.  In the second, we assemble the list of revoke
  * blocks.  In the third and final pass, we replay any un-revoked blocks
  * in the log.  
  */
 
-int journal_recover(journal_t *journal)
-{
 	int			err;
 	journal_superblock_t *	sb;
 
@@ -264,20 +266,23 @@
 	return err;
 }
 
-/*
- * journal_skip_recovery
- *
+/**
+ * int journal_skip_recovery() - Start journal and wipe exiting records 
+ * @journal: journal to startup
+ * 
  * Locate any valid recovery information from the journal and set up the
  * journal structures in memory to ignore it (presumably because the
  * caller has evidence that it is out of date).  
- *
+ * This function does'nt appear to be exorted..
+ */
+int journal_skip_recovery(journal_t *journal)
+{
+/*
  * We perform one pass over the journal to allow us to tell the user how
  * much recovery information is being erased, and to let us initialise
  * the journal transaction sequence numbers to the next unused ID. 
  */
 
-int journal_skip_recovery(journal_t *journal)
-{
 	int			err;
 	journal_superblock_t *	sb;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/jbd/transaction.c linux-2.4.21-pre6/fs/jbd/transaction.c
--- linux-2.4.20/fs/jbd/transaction.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/jbd/transaction.c	2003-03-26 23:49:25.000000000 +0000
@@ -223,19 +223,20 @@
 	return handle;
 }
 
-/*
- * Obtain a new handle.  
+/**
+ * handle_t *journal_start() - Obtain a new handle.  
+ * @journal: Journal to start transaction on.
+ * @nblocks: number of block buffer we might modify
  *
  * We make sure that the transaction can guarantee at least nblocks of
  * modified buffers in the log.  We block until the log can guarantee
  * that much space.  
  *
- * This function is visible to journal users (like ext2fs), so is not
+ * This function is visible to journal users (like ext3fs), so is not
  * called with the journal already locked.
  *
  * Return a pointer to a newly allocated handle, or NULL on failure
  */
-
 handle_t *journal_start(journal_t *journal, int nblocks)
 {
 	handle_t *handle = journal_current_handle();
@@ -325,7 +326,11 @@
 	return ret;
 }
 
-/*
+/**
+ * handle_t *journal_try_start() - Don't block, but try and get a handle
+ * @journal: Journal to start transaction on.
+ * @nblocks: number of block buffer we might modify
+ * 
  * Try to start a handle, but non-blockingly.  If we weren't able
  * to, return an ERR_PTR value.
  */
@@ -369,16 +374,18 @@
 	return handle;
 }
 
-/*
- * journal_extend: extend buffer credits.
- *
+/**
+ * int journal_extend() - extend buffer credits.
+ * @handle:  handle to 'extend'
+ * @nblocks: nr blocks to try to extend by.
+ * 
  * Some transactions, such as large extends and truncates, can be done
  * atomically all at once or in several stages.  The operation requests
  * a credit for a number of buffer modications in advance, but can
  * extend its credit if it needs more.  
  *
  * journal_extend tries to give the running handle more buffer credits.
- * It does not guarantee that allocation: this is a best-effort only.
+ * It does not guarantee that allocation - this is a best-effort only.
  * The calling process MUST be able to deal cleanly with a failure to
  * extend here.
  *
@@ -387,7 +394,6 @@
  * return code < 0 implies an error
  * return code > 0 implies normal transaction-full status.
  */
-
 int journal_extend (handle_t *handle, int nblocks)
 {
 	transaction_t *transaction = handle->h_transaction;
@@ -436,8 +442,12 @@
 }
 
 
-/*
- * journal_restart: restart a handle for a multi-transaction filesystem
+/**
+ * int journal_restart() - restart a handle .
+ * @handle:  handle to restart
+ * @nblocks: nr credits requested
+ * 
+ * Restart a handle for a multi-transaction filesystem
  * operation.
  *
  * If the journal_extend() call above fails to grant new buffer credits
@@ -479,8 +489,9 @@
 }
 
 
-/* 
- * Barrier operation: establish a transaction barrier. 
+/**
+ * void journal_lock_updates () - establish a transaction barrier.
+ * @journal:  Journal to establish a barrier on.
  *
  * This locks out any further updates from being started, and blocks
  * until all existing updates have completed, returning only once the
@@ -488,7 +499,6 @@
  *
  * The journal lock should not be held on entry.
  */
-
 void journal_lock_updates (journal_t *journal)
 {
 	lock_journal(journal);
@@ -516,12 +526,14 @@
 	down(&journal->j_barrier);
 }
 
-/*
+/**
+ * void journal_unlock_updates (journal_t* journal) - release barrier
+ * @journal:  Journal to release the barrier on.
+ * 
  * Release a transaction barrier obtained with journal_lock_updates().
  *
  * Should be called without the journal lock held.
  */
-
 void journal_unlock_updates (journal_t *journal)
 {
 	lock_journal(journal);
@@ -535,23 +547,14 @@
 }
 
 /*
- * journal_get_write_access: notify intent to modify a buffer for metadata
- * (not data) update.
- *
- * If the buffer is already part of the current transaction, then there
- * is nothing we need to do.  If it is already part of a prior
+ * if the buffer is already part of the current transaction, then there
+ * is nothing we need to do.  if it is already part of a prior
  * transaction which we are still committing to disk, then we need to
  * make sure that we do not overwrite the old copy: we do copy-out to
- * preserve the copy going to disk.  We also account the buffer against
+ * preserve the copy going to disk.  we also account the buffer against
  * the handle's metadata buffer credits (unless the buffer is already
  * part of the transaction, that is).
- *
- * Returns an error code or 0 on success.
- *
- * In full data journalling mode the buffer may be of type BJ_AsyncData,
- * because we're write()ing a buffer which is also part of a shared mapping.
  */
-
 static int
 do_get_write_access(handle_t *handle, struct journal_head *jh, int force_copy) 
 {
@@ -666,7 +669,8 @@
 			spin_unlock(&journal_datalist_lock);
 			unlock_journal(journal);
 			/* commit wakes up all shadow buffers after IO */
-			sleep_on(&jh2bh(jh)->b_wait);
+			wait_event(jh2bh(jh)->b_wait,
+						jh->b_jlist != BJ_Shadow);
 			lock_journal(journal);
 			goto repeat;
 		}
@@ -756,6 +760,17 @@
 	return error;
 }
 
+/**
+ * int journal_get_write_access() - notify intent to modify a buffer for metadata (not data) update.
+ * @handle: transaction to add buffer modifications to
+ * @bh:     bh to be used for metadata writes
+ *
+ * Returns an error code or 0 on success.
+ *
+ * In full data journalling mode the buffer may be of type BJ_AsyncData,
+ * because we're write()ing a buffer which is also part of a shared mapping.
+ */
+
 int journal_get_write_access (handle_t *handle, struct buffer_head *bh) 
 {
 	transaction_t *transaction = handle->h_transaction;
@@ -786,6 +801,13 @@
  * There is no lock ranking violation: it was a newly created,
  * unlocked buffer beforehand. */
 
+/**
+ * int journal_get_create_access () - notify intent to use newly created bh
+ * @handle: ransaction to new buffer to
+ * @bh: new buffer.
+ *
+ * Call this if you create a new bh.
+ */
 int journal_get_create_access (handle_t *handle, struct buffer_head *bh) 
 {
 	transaction_t *transaction = handle->h_transaction;
@@ -847,13 +869,14 @@
 
 
 
-/*
- * journal_get_undo_access: Notify intent to modify metadata with non-
- * rewindable consequences
- *
+/**
+ * int journal_get_undo_access() -  Notify intent to modify metadata with non-rewindable consequences
+ * @handle: transaction
+ * @bh: buffer to undo
+ * 
  * Sometimes there is a need to distinguish between metadata which has
  * been committed to disk and that which has not.  The ext3fs code uses
- * this for freeing and allocating space: we have to make sure that we
+ * this for freeing and allocating space, we have to make sure that we
  * do not reuse freed space until the deallocation has been committed,
  * since if we overwrote that space we would make the delete
  * un-rewindable in case of a crash.
@@ -865,13 +888,12 @@
  * as we know that the buffer has definitely been committed to disk.
  * 
  * We never need to know which transaction the committed data is part
- * of: buffers touched here are guaranteed to be dirtied later and so
+ * of, buffers touched here are guaranteed to be dirtied later and so
  * will be committed to a new transaction in due course, at which point
  * we can discard the old committed data pointer.
  *
  * Returns error number or 0 on success.  
  */
-
 int journal_get_undo_access (handle_t *handle, struct buffer_head *bh)
 {
 	journal_t *journal = handle->h_transaction->t_journal;
@@ -913,10 +935,12 @@
 	return err;
 }
 
-/* 
- * journal_dirty_data: mark a buffer as containing dirty data which
- * needs to be flushed before we can commit the current transaction.  
- *
+/** 
+ * int journal_dirty_data() -  mark a buffer as containing dirty data which needs to be flushed before we can commit the current transaction.  
+ * @handle: transaction
+ * @bh: bufferhead to mark
+ * @async: flag
+ * 
  * The buffer is placed on the transaction's data list and is marked as
  * belonging to the transaction.
  *
@@ -925,7 +949,10 @@
  * t_async_datalist.
  * 
  * Returns error number or 0 on success.  
- *
+ */
+int journal_dirty_data (handle_t *handle, struct buffer_head *bh, int async)
+{
+/*
  * journal_dirty_data() can be called via page_launder->ext3_writepage
  * by kswapd.  So it cannot block.  Happily, there's nothing here
  * which needs lock_journal if `async' is set.
@@ -934,9 +961,6 @@
  * between BJ_AsyncData and BJ_SyncData according to who tried to
  * change its state last.
  */
-
-int journal_dirty_data (handle_t *handle, struct buffer_head *bh, int async)
-{
 	journal_t *journal = handle->h_transaction->t_journal;
 	int need_brelse = 0;
 	int wanted_jlist = async ? BJ_AsyncData : BJ_SyncData;
@@ -1079,24 +1103,28 @@
 	return 0;
 }
 
-/* 
- * journal_dirty_metadata: mark a buffer as containing dirty metadata
- * which needs to be journaled as part of the current transaction.
+/** 
+ * int journal_dirty_metadata() -  mark a buffer as containing dirty metadata
+ * @handle: transaction to add buffer to.
+ * @bh: buffer to mark 
+ * 
+ * mark dirty metadata which needs to be journaled as part of the current transaction.
  *
  * The buffer is placed on the transaction's metadata list and is marked
  * as belonging to the transaction.  
  *
+ * Returns error number or 0 on success.  
+ */
+int journal_dirty_metadata (handle_t *handle, struct buffer_head *bh)
+{
+/*
  * Special care needs to be taken if the buffer already belongs to the
  * current committing transaction (in which case we should have frozen
  * data present for that commit).  In that case, we don't relink the
  * buffer: that only gets done when the old transaction finally
  * completes its commit.
  * 
- * Returns error number or 0 on success.  
  */
-
-int journal_dirty_metadata (handle_t *handle, struct buffer_head *bh)
-{
 	transaction_t *transaction = handle->h_transaction;
 	journal_t *journal = transaction->t_journal;
 	struct journal_head *jh = bh2jh(bh);
@@ -1182,9 +1210,12 @@
 }
 #endif
 
-/* 
- * journal_forget: bforget() for potentially-journaled buffers.  We can
- * only do the bforget if there are no commits pending against the
+/** 
+ * void journal_forget() - bforget() for potentially-journaled buffers.
+ * @handle: transaction handle
+ * @bh:     bh to 'forget'
+ *
+ * We can only do the bforget if there are no commits pending against the
  * buffer.  If the buffer is dirty in the current running transaction we
  * can safely unlink it. 
  *
@@ -1196,7 +1227,6 @@
  * Allow this call even if the handle has aborted --- it may be part of
  * the caller's cleanup after an abort.
  */
-
 void journal_forget (handle_t *handle, struct buffer_head *bh)
 {
 	transaction_t *transaction = handle->h_transaction;
@@ -1357,7 +1387,10 @@
 	jcb->jcb_func = func;
 }
 
-/*
+/**
+ * int journal_stop() - complete a transaction
+ * @handle: tranaction to complete.
+ * 
  * All done for a particular handle.
  *
  * There is not much action needed here.  We just return any remaining
@@ -1370,7 +1403,6 @@
  * return -EIO if a journal_abort has been executed since the
  * transaction began.
  */
-
 int journal_stop(handle_t *handle)
 {
 	transaction_t *transaction = handle->h_transaction;
@@ -1455,8 +1487,10 @@
 	return err;
 }
 
-/*
- * For synchronous operations: force any uncommitted trasnactions
+/**int journal_force_commit() - force any uncommitted transactions
+ * @journal: journal to force
+ *
+ * For synchronous operations: force any uncommitted transactions
  * to disk.  May seem kludgy, but it reuses all the handle batching
  * code in a very simple manner.
  */
@@ -1660,6 +1694,26 @@
 	return 0;
 }
 
+
+/** 
+ * int journal_try_to_free_buffers() - try to free page buffers.
+ * @journal: journal for operation
+ * @page: to try and free
+ * @gfp_mask: 'IO' mode for try_to_free_buffers()
+ *
+ * 
+ * For all the buffers on this page,
+ * if they are fully written out ordered data, move them onto BUF_CLEAN
+ * so try_to_free_buffers() can reap them.
+ * 
+ * This function returns non-zero if we wish try_to_free_buffers()
+ * to be called. We do this if the page is releasable by try_to_free_buffers().
+ * We also do it if the page has locked or dirty buffers and the caller wants
+ * us to perform sync or async writeout.
+ */
+int journal_try_to_free_buffers(journal_t *journal, 
+				struct page *page, int gfp_mask)
+{
 /*
  * journal_try_to_free_buffers().  For all the buffers on this page,
  * if they are fully written out ordered data, move them onto BUF_CLEAN
@@ -1684,14 +1738,7 @@
  * cannot happen because we never reallocate freed data as metadata
  * while the data is part of a transaction.  Yes?
  *
- * This function returns non-zero if we wish try_to_free_buffers()
- * to be called. We do this is the page is releasable by try_to_free_buffers().
- * We also do it if the page has locked or dirty buffers and the caller wants
- * us to perform sync or async writeout.
  */
-int journal_try_to_free_buffers(journal_t *journal, 
-				struct page *page, int gfp_mask)
-{
 	struct buffer_head *bh;
 	struct buffer_head *tmp;
 	int locked_or_dirty = 0;
@@ -1903,8 +1950,15 @@
 	return may_free;
 }
 
-/*
- * Return non-zero if the page's buffers were successfully reaped
+/** 
+ * int journal_flushpage() 
+ * @journal: journal to use for flush... 
+ * @page:    page to flush
+ * @offset:  length of page to flush.
+ *
+ * Reap page buffers containing data after offset in page.
+ *
+ * Return non-zero if the page's buffers were successfully reaped.
  */
 int journal_flushpage(journal_t *journal, 
 		      struct page *page, 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/jffs/intrep.c linux-2.4.21-pre6/fs/jffs/intrep.c
--- linux-2.4.20/fs/jffs/intrep.c	2001-10-04 22:13:18.000000000 +0000
+++ linux-2.4.21-pre6/fs/jffs/intrep.c	2003-03-26 23:49:40.000000000 +0000
@@ -1910,7 +1910,7 @@
 	}
 
 	if ((err = flash_safe_writev(fmc->mtd, node_iovec, iovec_cnt,
-				    pos) < 0)) {
+				    pos)) < 0) {
 		jffs_fmfree_partly(fmc, fm, 0);
 		jffs_fm_write_unlock(fmc);
 		printk(KERN_ERR "JFFS: jffs_write_node: Failed to write, "
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/jfs/file.c linux-2.4.21-pre6/fs/jfs/file.c
--- linux-2.4.20/fs/jfs/file.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/jfs/file.c	2003-03-26 23:49:40.000000000 +0000
@@ -26,6 +26,7 @@
 
 
 extern int jfs_commit_inode(struct inode *, int);
+extern void jfs_truncate(struct inode *);
 
 int jfs_fsync(struct file *file, struct dentry *dentry, int datasync)
 {
@@ -44,59 +45,6 @@
 	return rc ? -EIO : 0;
 }
 
-/*
- * Guts of jfs_truncate.  Called with locks already held.  Can be called
- * with directory for truncating directory index table.
- */
-void jfs_truncate_nolock(struct inode *ip, loff_t length)
-{
-	loff_t newsize;
-	tid_t tid;
-
-	ASSERT(length >= 0);
-
-	if (test_cflag(COMMIT_Nolink, ip)) {
-		xtTruncate(0, ip, length, COMMIT_WMAP);
-		return;
-	}
-
-	do {
-		tid = txBegin(ip->i_sb, 0);
-
-		/*
-		 * The commit_sem cannot be taken before txBegin.
-		 * txBegin may block and there is a chance the inode
-		 * could be marked dirty and need to be committed
-		 * before txBegin unblocks
-		 */
-		down(&JFS_IP(ip)->commit_sem);
-
-		newsize = xtTruncate(tid, ip, length,
-				     COMMIT_TRUNCATE | COMMIT_PWMAP);
-		if (newsize < 0) {
-			txEnd(tid);
-			up(&JFS_IP(ip)->commit_sem);
-			break;
-		}
-
-		ip->i_mtime = ip->i_ctime = CURRENT_TIME;
-		mark_inode_dirty(ip);
-
-		txCommit(tid, 1, &ip, 0);
-		txEnd(tid);
-		up(&JFS_IP(ip)->commit_sem);
-	} while (newsize > length);	/* Truncate isn't always atomic */
-}
-
-static void jfs_truncate(struct inode *ip)
-{
-	jFYI(1, ("jfs_truncate: size = 0x%lx\n", (ulong) ip->i_size));
-
-	IWRITE_LOCK(ip);
-	jfs_truncate_nolock(ip, ip->i_size);
-	IWRITE_UNLOCK(ip);
-}
-
 static int jfs_open(struct inode *inode, struct file *file)
 {
 	int rc;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/jfs/inode.c linux-2.4.21-pre6/fs/jfs/inode.c
--- linux-2.4.20/fs/jfs/inode.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/jfs/inode.c	2003-03-26 23:49:25.000000000 +0000
@@ -21,6 +21,7 @@
 //#include <linux/locks.h>
 #include "jfs_incore.h"
 #include "jfs_filsys.h"
+#include "jfs_dmap.h"
 #include "jfs_imap.h"
 #include "jfs_extent.h"
 #include "jfs_unicode.h"
@@ -39,23 +40,27 @@
 {
 	struct jfs_inode_info *ji = JFS_IP(inode);
 
-	jFYI(1, ("jfs_clear_inode called ip = 0x%p\n", inode));
+	if (is_bad_inode(inode))
+		/*
+		 * We free the fs-dependent structure before making the
+		 * inode bad
+		 */
+		return;
+
+	jfs_info("jfs_clear_inode called ip = 0x%p", inode);
 
 	if (ji->active_ag != -1) {
-		printk(KERN_ERR "jfs_clear_inode, active_ag = %d\n",
-		       ji->active_ag);
-		printk(KERN_ERR "i_ino = %ld, i_mode = %o\n",
-		       inode->i_ino, inode->i_mode);
+		struct bmap *bmap = JFS_SBI(inode->i_sb)->bmap;
+		atomic_dec(&bmap->db_active[ji->active_ag]);
 	}
 
-	ASSERT(list_empty(&ji->mp_list));
 	ASSERT(list_empty(&ji->anon_inode_list));
 
 	if (ji->atlhead) {
-		jERROR(1, ("jfs_clear_inode: inode %p has anonymous tlocks\n",
-					inode));
-		jERROR(1, ("i_state = 0x%lx, cflag = 0x%lx\n",
-					inode->i_state, ji->cflag));
+		jfs_err("jfs_clear_inode: inode %p has anonymous tlocks",
+			inode);
+		jfs_err("i_state = 0x%lx, cflag = 0x%lx", inode->i_state,
+			ji->cflag);
 	}
 
 	free_jfs_inode(inode);
@@ -67,10 +72,10 @@
 
 	rc = alloc_jfs_inode(inode);
 	if (rc) {
-		jFYI(1, ("In jfs_read_inode, alloc_jfs_inode failed"));
+		jfs_warn("In jfs_read_inode, alloc_jfs_inode failed");
 		goto bad_inode;
 	}
-	jFYI(1, ("In jfs_read_inode, inode = 0x%p\n", inode));
+	jfs_info("In jfs_read_inode, inode = 0x%p", inode);
 
 	if (diRead(inode))
 		goto bad_inode_free;
@@ -85,7 +90,7 @@
 		inode->i_mapping->a_ops = &jfs_aops;
 		inode->i_mapping->gfp_mask = GFP_NOFS;
 	} else if (S_ISLNK(inode->i_mode)) {
-		if (inode->i_size > IDATASIZE) {
+		if (inode->i_size >= IDATASIZE) {
 			inode->i_op = &page_symlink_inode_operations;
 			inode->i_mapping->a_ops = &jfs_aops;
 		} else
@@ -116,7 +121,7 @@
 	tid_t tid;
 	static int noisy = 5;
 
-	jFYI(1, ("In jfs_commit_inode, inode = 0x%p\n", inode));
+	jfs_info("In jfs_commit_inode, inode = 0x%p", inode);
 
 	/*
 	 * Don't commit if inode has been committed since last being
@@ -131,9 +136,9 @@
 		 * partitions and may think inode is dirty
 		 */
 		if (!special_file(inode->i_mode) && noisy) {
-			jERROR(1, ("jfs_commit_inode(0x%p) called on "
-				   "read-only volume\n", inode));
-			jERROR(1, ("Is remount racy?\n"));
+			jfs_err("jfs_commit_inode(0x%p) called on "
+				   "read-only volume", inode);
+			jfs_err("Is remount racy?");
 			noisy--;
 		}
 		return 0;
@@ -159,13 +164,13 @@
 		return;
 
 	if (jfs_commit_inode(inode, wait)) {
-		jERROR(1, ("jfs_write_inode: jfs_commit_inode failed!\n"));
+		jfs_err("jfs_write_inode: jfs_commit_inode failed!");
 	}
 }
 
 void jfs_delete_inode(struct inode *inode)
 {
-	jFYI(1, ("In jfs_delete_inode, inode = 0x%p\n", inode));
+	jfs_info("In jfs_delete_inode, inode = 0x%p", inode);
 
 	if (test_cflag(COMMIT_Freewmap, inode))
 		freeZeroLink(inode);
@@ -184,9 +189,8 @@
 			/* kernel allows writes to devices on read-only
 			 * partitions and may try to mark inode dirty
 			 */
-			jERROR(1, ("jfs_dirty_inode called on "
-				   "read-only volume\n"));
-			jERROR(1, ("Is remount racy?\n"));
+			jfs_err("jfs_dirty_inode called on read-only volume");
+			jfs_err("Is remount racy?");
 			noisy--;
 		}
 		return;
@@ -339,3 +343,58 @@
 	.bmap		= jfs_bmap,
 	.direct_IO	= jfs_direct_IO,
 };
+
+/*
+ * Guts of jfs_truncate.  Called with locks already held.  Can be called
+ * with directory for truncating directory index table.
+ */
+void jfs_truncate_nolock(struct inode *ip, loff_t length)
+{
+	loff_t newsize;
+	tid_t tid;
+
+	ASSERT(length >= 0);
+
+	if (test_cflag(COMMIT_Nolink, ip)) {
+		xtTruncate(0, ip, length, COMMIT_WMAP);
+		return;
+	}
+
+	do {
+		tid = txBegin(ip->i_sb, 0);
+
+		/*
+		 * The commit_sem cannot be taken before txBegin.
+		 * txBegin may block and there is a chance the inode
+		 * could be marked dirty and need to be committed
+		 * before txBegin unblocks
+		 */
+		down(&JFS_IP(ip)->commit_sem);
+
+		newsize = xtTruncate(tid, ip, length,
+				     COMMIT_TRUNCATE | COMMIT_PWMAP);
+		if (newsize < 0) {
+			txEnd(tid);
+			up(&JFS_IP(ip)->commit_sem);
+			break;
+		}
+
+		ip->i_mtime = ip->i_ctime = CURRENT_TIME;
+		mark_inode_dirty(ip);
+
+		txCommit(tid, 1, &ip, 0);
+		txEnd(tid);
+		up(&JFS_IP(ip)->commit_sem);
+	} while (newsize > length);	/* Truncate isn't always atomic */
+}
+
+void jfs_truncate(struct inode *ip)
+{
+	jfs_info("jfs_truncate: size = 0x%lx", (ulong) ip->i_size);
+
+	block_truncate_page(ip->i_mapping, ip->i_size, jfs_get_block);
+
+	IWRITE_LOCK(ip);
+	jfs_truncate_nolock(ip, ip->i_size);
+	IWRITE_UNLOCK(ip);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/jfs/jfs_btree.h linux-2.4.21-pre6/fs/jfs/jfs_btree.h
--- linux-2.4.20/fs/jfs/jfs_btree.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/jfs/jfs_btree.h	2003-03-26 23:49:35.000000000 +0000
@@ -71,19 +71,16 @@
 		MP = (struct metapage *)&JFS_IP(IP)->bxflag;\
 		P = (TYPE *)&JFS_IP(IP)->ROOT;\
 		RC = 0;\
-		jEVENT(0,("%d BT_GETPAGE returning root\n", __LINE__));\
 	}\
 	else\
 	{\
-		jEVENT(0,("%d BT_GETPAGE reading block %d\n", __LINE__,\
-			 (int)BN));\
 		MP = read_metapage((IP), BN, SIZE, 1);\
 		if (MP) {\
 			RC = 0;\
 			P = (MP)->data;\
 		} else {\
 			P = NULL;\
-			jERROR(1,("bread failed!\n"));\
+			jfs_err("bread failed!");\
 			RC = EIO;\
 		}\
 	}\
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/jfs/jfs_debug.c linux-2.4.21-pre6/fs/jfs/jfs_debug.c
--- linux-2.4.20/fs/jfs/jfs_debug.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/jfs/jfs_debug.c	2003-03-26 23:49:30.000000000 +0000
@@ -100,6 +100,7 @@
 
 #ifdef CONFIG_JFS_STATISTICS
 extern read_proc_t jfs_lmstats_read;
+extern read_proc_t jfs_txstats_read;
 extern read_proc_t jfs_xtstat_read;
 extern read_proc_t jfs_mpstat_read;
 #endif
@@ -111,6 +112,7 @@
 } Entries[] = {
 #ifdef CONFIG_JFS_STATISTICS
 	{ "lmstats",	jfs_lmstats_read, },
+	{ "txstats",	jfs_txstats_read, },
 	{ "xtstat",	jfs_xtstat_read, },
 	{ "mpstat",	jfs_mpstat_read, },
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/jfs/jfs_debug.h linux-2.4.21-pre6/fs/jfs/jfs_debug.h
--- linux-2.4.20/fs/jfs/jfs_debug.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/jfs/jfs_debug.h	2003-03-26 23:49:39.000000000 +0000
@@ -41,13 +41,13 @@
 /* kgdb stuff */
 #define assert(p) KERNEL_ASSERT(#p, p)
 #else
-#define assert(p) {\
-if (!(p))\
-	{\
-		printk("assert(%s)\n",#p);\
-		BUG();\
-	}\
-}
+#define assert(p) do {	\
+	if (!(p)) {	\
+		printk(KERN_CRIT "BUG at %s:%d assert(%s)\n",	\
+		       __FILE__, __LINE__, #p);			\
+		BUG();	\
+	}		\
+} while (0)
 #endif
 
 /*
@@ -57,33 +57,52 @@
 #ifdef CONFIG_JFS_DEBUG
 #define ASSERT(p) assert(p)
 
+/* printk verbosity */
+#define JFS_LOGLEVEL_ERR 1
+#define JFS_LOGLEVEL_WARN 2
+#define JFS_LOGLEVEL_DEBUG 3
+#define JFS_LOGLEVEL_INFO 4
+
+extern int jfsloglevel;
+
 /* dump memory contents */
 extern void dump_mem(char *label, void *data, int length);
-extern int jfsloglevel;
 
 /* information message: e.g., configuration, major event */
-#define jFYI(button, prspec) \
-	do { if (button && jfsloglevel > 1) printk prspec; } while (0)
+#define jfs_info(fmt, arg...) do {			\
+	if (jfsloglevel >= JFS_LOGLEVEL_INFO)		\
+		printk(KERN_INFO fmt "\n", ## arg);	\
+} while (0)
+
+/* debug message: ad hoc */
+#define jfs_debug(fmt, arg...) do {			\
+	if (jfsloglevel >= JFS_LOGLEVEL_DEBUG)		\
+		printk(KERN_DEBUG fmt "\n", ## arg);	\
+} while (0)
+
+/* warn message: */
+#define jfs_warn(fmt, arg...) do {			\
+	if (jfsloglevel >= JFS_LOGLEVEL_WARN)		\
+		printk(KERN_WARNING fmt "\n", ## arg);	\
+} while (0)
 
 /* error event message: e.g., i/o error */
-extern int jfsERROR;
-#define jERROR(button, prspec) \
-	do { if (button && jfsloglevel > 0) { printk prspec; } } while (0)
-
-/* debug event message: */
-#define jEVENT(button,prspec) \
-	do { if (button) printk prspec; } while (0)
+#define jfs_err(fmt, arg...) do {			\
+	if (jfsloglevel >= JFS_LOGLEVEL_ERR)		\
+		printk(KERN_ERR fmt "\n", ## arg);	\
+} while (0)
 
 /*
  *	debug OFF
  *	---------
  */
 #else				/* CONFIG_JFS_DEBUG */
-#define dump_mem(label,data,length)
-#define ASSERT(p)
-#define jEVENT(button,prspec)
-#define jERROR(button,prspec)
-#define jFYI(button,prspec)
+#define dump_mem(label,data,length) do {} while (0)
+#define ASSERT(p) do {} while (0)
+#define jfs_info(fmt, arg...) do {} while (0)
+#define jfs_debug(fmt, arg...) do {} while (0)
+#define jfs_warn(fmt, arg...) do {} while (0)
+#define jfs_err(fmt, arg...) do {} while (0)
 #endif				/* CONFIG_JFS_DEBUG */
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/jfs/jfs_dmap.c linux-2.4.21-pre6/fs/jfs/jfs_dmap.c
--- linux-2.4.20/fs/jfs/jfs_dmap.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/jfs/jfs_dmap.c	2003-03-26 23:49:20.000000000 +0000
@@ -22,6 +22,7 @@
 #include "jfs_imap.h"
 #include "jfs_lock.h"
 #include "jfs_metapage.h"
+#include "jfs_superblock.h"
 #include "jfs_debug.h"
 
 /*
@@ -314,7 +315,7 @@
 			   BMAPBLKNO << JFS_SBI(ipbmap->i_sb)->l2nbperpage,
 			   PSIZE, 0);
 	if (mp == NULL) {
-		jERROR(1,("dbSync: read_metapage failed!\n"));
+		jfs_err("dbSync: read_metapage failed!");
 		return (EIO);
 	}
 	/* copy the in-memory version of the bmap to the on-disk version */
@@ -381,7 +382,22 @@
 	IREAD_LOCK(ipbmap);
 
 	/* block to be freed better be within the mapsize. */
-	assert(blkno + nblocks <= bmp->db_mapsize);
+	if (unlikely(blkno + nblocks > bmp->db_mapsize)) {
+		/*
+		 * Trying to catch a bug here
+		 */
+		printk(KERN_ERR
+		       "JFS: dbFree asked to free block larger than mapsize\n");
+		printk(KERN_ERR
+		       "blkno = 0x%Lx, nblocks = 0x%Lx, mapsize = 0x%Lx\n",
+		       blkno, nblocks, bmp->db_mapsize);
+		printk(KERN_ERR "ino = %ld, cflag = %lx\n", ip->i_ino,
+		       JFS_IP(ip)->cflag);
+		dump_stack();
+		/* Make sure fsck fixes things back up */
+		updateSuper(ip->i_sb, FM_DIRTY);
+		return -EIO;	/* Nobody checks the return code */
+	}
 
 	/*
 	 * free the blocks a dmap at a time.
@@ -1444,10 +1460,10 @@
 		/* assert(!(rc == ENOSPC && bmp->db_agfree[agno] == bmp->db_agsize)); */
 		if ((rc == ENOSPC) &&
 		    (bmp->db_agfree[agno] == bmp->db_agsize)) {
-			jERROR(1,
-			       ("dbAllocAG: removed assert, but still need to debug here\nblkno = 0x%Lx, nblocks = 0x%Lx\n",
+			jfs_err("dbAllocAG: removed assert, but still need to "
+				"debug here\nblkno = 0x%Lx, nblocks = 0x%Lx",
 				(unsigned long long) blkno,
-				(unsigned long long) nblocks));
+				(unsigned long long) nblocks);
 		}
 		return (rc);
 	}
@@ -1829,8 +1845,7 @@
 			 * to indicate that we have leaked blocks.
 			 */
 			fsDirty();	/* !!! */
-			jERROR(1,
-			       ("dbAllocCtl: I/O Error: Block Leakage.\n"));
+			jfs_err("dbAllocCtl: I/O Error: Block Leakage.");
 			continue;
 		}
 		dp = (struct dmap *) mp->data;
@@ -1843,7 +1858,7 @@
 			 */
 			release_metapage(mp);
 			fsDirty();	/* !!! */
-			jERROR(1, ("dbAllocCtl: Block Leakage.\n"));
+			jfs_err("dbAllocCtl: Block Leakage.");
 			continue;
 		}
 
@@ -3276,9 +3291,8 @@
 
 	newsize = blkno + nblocks;
 
-	jEVENT(0, ("dbExtendFS: blkno:%Ld nblocks:%Ld newsize:%Ld\n",
-		   (long long) blkno, (long long) nblocks,
-		   (long long) newsize));
+	jfs_info("dbExtendFS: blkno:%Ld nblocks:%Ld newsize:%Ld",
+		 (long long) blkno, (long long) nblocks, (long long) newsize);
 
 	/*
 	 *      initialize bmap control page.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/jfs/jfs_dtree.c linux-2.4.21-pre6/fs/jfs/jfs_dtree.c
--- linux-2.4.20/fs/jfs/jfs_dtree.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/jfs/jfs_dtree.c	2003-03-26 23:49:53.000000000 +0000
@@ -130,7 +130,7 @@
 		if (((P)->header.nextindex > (((BN)==0)?DTROOTMAXSLOT:(P)->header.maxslot)) ||\
 		    ((BN) && ((P)->header.maxslot > DTPAGEMAXSLOT)))\
 		{\
-			jERROR(1,("DT_GETPAGE: dtree page corrupt\n"));\
+			jfs_err("DT_GETPAGE: dtree page corrupt");\
 			BT_PUTPAGE(MP);\
 			updateSuper((IP)->i_sb, FM_DIRTY);\
 			MP = NULL;\
@@ -200,6 +200,47 @@
 #define ciToUpper(c)	UniStrupr((c)->name)
 
 /*
+ *	read_index_page()
+ *
+ *	Reads a page of a directory's index table.
+ *	Having metadata mapped into the directory inode's address space
+ *	presents a multitude of problems.  We avoid this by mapping to
+ *	the absolute address space outside of the *_metapage routines
+ */
+static struct metapage *read_index_page(struct inode *inode, s64 blkno)
+{
+	int rc;
+	s64 xaddr;
+	int xflag;
+	s32 xlen;
+
+	rc = xtLookup(inode, blkno, 1, &xflag, &xaddr, &xlen, 1);
+	if (rc || (xlen == 0))
+		return NULL;
+
+	return read_metapage(inode, xaddr, PSIZE, 1);
+}
+
+/*
+ *	get_index_page()
+ *
+ *	Same as get_index_page(), but get's a new page without reading
+ */
+static struct metapage *get_index_page(struct inode *inode, s64 blkno)
+{
+	int rc;
+	s64 xaddr;
+	int xflag;
+	s32 xlen;
+
+	rc = xtLookup(inode, blkno, 1, &xflag, &xaddr, &xlen, 1);
+	if (rc || (xlen == 0))
+		return NULL;
+
+	return get_metapage(inode, xaddr, PSIZE, 1);
+}
+
+/*
  *	find_index()
  *
  *	Returns dtree page containing directory table entry for specified
@@ -208,7 +249,7 @@
  *	mp must be released by caller.
  */
 static struct dir_table_slot *find_index(struct inode *ip, u32 index,
-					 struct metapage ** mp)
+					 struct metapage ** mp, s64 *lblock)
 {
 	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
 	s64 blkno;
@@ -219,15 +260,14 @@
 
 	if (index < 2) {
 		if (maxWarnings) {
-			jERROR(1, ("find_entry called with index = %d\n",
-				   index));
+			jfs_warn("find_entry called with index = %d", index);
 			maxWarnings--;
 		}
 		return 0;
 	}
 
 	if (index >= jfs_ip->next_index) {
-		jFYI(1, ("find_entry called with index >= next_index\n"));
+		jfs_warn("find_entry called with index >= next_index");
 		return 0;
 	}
 
@@ -243,15 +283,16 @@
 		blkno = ((offset + 1) >> L2PSIZE) <<
 		    JFS_SBI(ip->i_sb)->l2nbperpage;
 
-		if (*mp && ((*mp)->index != blkno)) {
+		if (*mp && (*lblock != blkno)) {
 			release_metapage(*mp);
 			*mp = 0;
 		}
-		if (*mp == 0)
-			*mp = read_metapage(ip, blkno, PSIZE, 0);
 		if (*mp == 0) {
-			jERROR(1,
-			       ("free_index: error reading directory table\n"));
+			*lblock = blkno;
+			*mp = read_index_page(ip, blkno);
+		}
+		if (*mp == 0) {
+			jfs_err("free_index: error reading directory table");
 			return 0;
 		}
 
@@ -312,8 +353,8 @@
 	ASSERT(DO_INDEX(ip));
 
 	if (jfs_ip->next_index < 2) {
-		jERROR(1, ("next_index = %d.  Please fix this!\n",
-			   jfs_ip->next_index));
+		jfs_warn("add_index: next_index = %d.  Resetting!",
+			   jfs_ip->next_index);
 		jfs_ip->next_index = 2;
 	}
 
@@ -362,14 +403,14 @@
 		if ((rc =
 		     xtInsert(tid, ip, 0, 0, sbi->nbperpage,
 			      &xaddr, 0))) {
-			jFYI(1, ("add_index: xtInsert failed!\n"));
+			jfs_warn("add_index: xtInsert failed!");
 			return -1;
 		}
 		ip->i_size = PSIZE;
 		ip->i_blocks += LBLK2PBLK(sb, sbi->nbperpage);
 
-		if ((mp = get_metapage(ip, 0, ip->i_blksize, 0)) == 0) {
-			jERROR(1, ("add_index: get_metapage failed!\n"));
+		if ((mp = get_index_page(ip, 0)) == 0) {
+			jfs_err("add_index: get_metapage failed!");
 			xtTruncate(tid, ip, 0, COMMIT_PWMAP);
 			return -1;
 		}
@@ -404,22 +445,22 @@
 		if ((rc =
 		     xtInsert(tid, ip, 0, blkno, sbi->nbperpage,
 			      &xaddr, 0))) {
-			jFYI(1, ("add_index: xtInsert failed!\n"));
+			jfs_warn("add_index: xtInsert failed!");
 			jfs_ip->next_index--;
 			return -1;
 		}
 		ip->i_size += PSIZE;
 		ip->i_blocks += LBLK2PBLK(sb, sbi->nbperpage);
 
-		if ((mp = get_metapage(ip, blkno, PSIZE, 0)))
+		if ((mp = get_index_page(ip, blkno)))
 			memset(mp->data, 0, PSIZE);	/* Just looks better */
 		else
 			xtTruncate(tid, ip, offset, COMMIT_PWMAP);
 	} else
-		mp = read_metapage(ip, blkno, PSIZE, 0);
+		mp = read_index_page(ip, blkno);
 
 	if (mp == 0) {
-		jERROR(1, ("add_index: get/read_metapage failed!\n"));
+		jfs_err("add_index: get/read_metapage failed!");
 		return -1;
 	}
 
@@ -445,9 +486,10 @@
 static void free_index(tid_t tid, struct inode *ip, u32 index, u32 next)
 {
 	struct dir_table_slot *dirtab_slot;
+	s64 lblock;
 	struct metapage *mp = 0;
 
-	dirtab_slot = find_index(ip, index, &mp);
+	dirtab_slot = find_index(ip, index, &mp, &lblock);
 
 	if (dirtab_slot == 0)
 		return;
@@ -470,11 +512,11 @@
  *	Changes an entry in the directory index table
  */
 static void modify_index(tid_t tid, struct inode *ip, u32 index, s64 bn,
-			 int slot, struct metapage ** mp)
+			 int slot, struct metapage ** mp, u64 *lblock)
 {
 	struct dir_table_slot *dirtab_slot;
 
-	dirtab_slot = find_index(ip, index, mp);
+	dirtab_slot = find_index(ip, index, mp, lblock);
 
 	if (dirtab_slot == 0)
 		return;
@@ -497,10 +539,11 @@
 static int read_index(struct inode *ip, u32 index,
 		     struct dir_table_slot * dirtab_slot)
 {
+	s64 lblock;
 	struct metapage *mp = 0;
 	struct dir_table_slot *slot;
 
-	slot = find_index(ip, index, &mp);
+	slot = find_index(ip, index, &mp, &lblock);
 	if (slot == 0) {
 		return -EIO;
 	}
@@ -725,7 +768,7 @@
 			/* Something's corrupted, mark filesytem dirty so
 			 * chkdsk will fix it.
 			 */
-			jERROR(1, ("stack overrun in dtSearch!\n"));
+			jfs_err("stack overrun in dtSearch!");
 			updateSuper(sb, FM_DIRTY);
 			rc = EIO;
 			goto out;
@@ -1136,7 +1179,7 @@
 			break;
 
 		default:
-			jERROR(2, ("dtSplitUp(): UFO!\n"));
+			jfs_err("dtSplitUp(): UFO!");
 			break;
 		}
 
@@ -1287,8 +1330,7 @@
 	if (rmp == NULL)
 		return EIO;
 
-	jEVENT(0,
-	       ("dtSplitPage: ip:0x%p smp:0x%p rmp:0x%p\n", ip, smp, rmp));
+	jfs_info("dtSplitPage: ip:0x%p smp:0x%p rmp:0x%p", ip, smp, rmp);
 
 	BT_MARK_DIRTY(rmp, ip);
 	/*
@@ -1394,9 +1436,8 @@
 		 * acquire a transaction lock on the next page
 		 */
 		tlck = txLock(tid, ip, mp, tlckDTREE | tlckRELINK);
-		jEVENT(0,
-		       ("dtSplitPage: tlck = 0x%p, ip = 0x%p, mp=0x%p\n",
-			tlck, ip, mp));
+		jfs_info("dtSplitPage: tlck = 0x%p, ip = 0x%p, mp=0x%p",
+			tlck, ip, mp);
 		dtlck = (struct dt_lock *) & tlck->lock;
 
 		/* linelock header of previous right sibling page */
@@ -1491,12 +1532,14 @@
 	 * Update directory index table for entries now in right page
 	 */
 	if ((rp->header.flag & BT_LEAF) && DO_INDEX(ip)) {
+		s64 lblock;
+
 		mp = 0;
 		stbl = DT_GETSTBL(rp);
 		for (n = 0; n < rp->header.nextindex; n++) {
 			ldtentry = (struct ldtentry *) & rp->slot[stbl[n]];
 			modify_index(tid, ip, le32_to_cpu(ldtentry->index),
-				     rbn, n, &mp);
+				     rbn, n, &mp, &lblock);
 		}
 		if (mp)
 			release_metapage(mp);
@@ -1536,7 +1579,6 @@
 
 	ip->i_blocks += LBLK2PBLK(sb, lengthPXD(pxd));
 
-	jEVENT(0, ("dtSplitPage: ip:0x%p sp:0x%p rp:0x%p\n", ip, sp, rp));
 	return 0;
 }
 
@@ -1616,6 +1658,8 @@
 		 * Update directory index table to reflect new page address
 		 */
 		if (DO_INDEX(ip)) {
+			s64 lblock;
+
 			mp = 0;
 			stbl = DT_GETSTBL(sp);
 			for (n = 0; n < sp->header.nextindex; n++) {
@@ -1623,7 +1667,7 @@
 				    (struct ldtentry *) & sp->slot[stbl[n]];
 				modify_index(tid, ip,
 					     le32_to_cpu(ldtentry->index),
-					     xaddr, n, &mp);
+					     xaddr, n, &mp, &lblock);
 			}
 			if (mp)
 				release_metapage(mp);
@@ -1635,8 +1679,7 @@
 	 */
 	sp->header.self = *pxd;
 
-	jEVENT(0,
-	       ("dtExtendPage: ip:0x%p smp:0x%p sp:0x%p\n", ip, smp, sp));
+	jfs_info("dtExtendPage: ip:0x%p smp:0x%p sp:0x%p", ip, smp, sp);
 
 	BT_MARK_DIRTY(smp, ip);
 	/*
@@ -1774,10 +1817,6 @@
 				 ((JFS_IP(ip)->acl.flag & DXD_EXTENT) ?
 				  lengthDXD(&JFS_IP(ip)->acl) : 0));
 
-	jEVENT(0,
-	       ("dtExtendPage: ip:0x%p smp:0x%p sp:0x%p\n", ip, smp, sp));
-
-
 	DT_PUTPAGE(pmp);
 	return 0;
 }
@@ -1911,6 +1950,7 @@
 	 * Update directory index table for entries now in right page
 	 */
 	if ((rp->header.flag & BT_LEAF) && DO_INDEX(ip)) {
+		s64 lblock;
 		struct metapage *mp = 0;
 		struct ldtentry *ldtentry;
 
@@ -1918,7 +1958,7 @@
 		for (n = 0; n < rp->header.nextindex; n++) {
 			ldtentry = (struct ldtentry *) & rp->slot[stbl[n]];
 			modify_index(tid, ip, le32_to_cpu(ldtentry->index),
-				     rbn, n, &mp);
+				     rbn, n, &mp, &lblock);
 		}
 		if (mp)
 			release_metapage(mp);
@@ -2120,6 +2160,8 @@
 		 * Update directory index table for entries moved in stbl
 		 */
 		if (DO_INDEX(ip) && index < p->header.nextindex) {
+			s64 lblock;
+
 			imp = 0;
 			stbl = DT_GETSTBL(p);
 			for (i = index; i < p->header.nextindex; i++) {
@@ -2127,7 +2169,7 @@
 				    (struct ldtentry *) & p->slot[stbl[i]];
 				modify_index(tid, ip,
 					     le32_to_cpu(ldtentry->index),
-					     bn, i, &imp);
+					     bn, i, &imp, &lblock);
 			}
 			if (imp)
 				release_metapage(imp);
@@ -2368,9 +2410,9 @@
 	oxaddr = addressPXD(opxd);
 	xlen = lengthPXD(opxd);
 
-	jEVENT(0, ("dtRelocate: lmxaddr:%Ld xaddr:%Ld:%Ld xlen:%d\n",
+	jfs_info("dtRelocate: lmxaddr:%Ld xaddr:%Ld:%Ld xlen:%d",
 		   (long long)lmxaddr, (long long)oxaddr, (long long)nxaddr,
-		   xlen));
+		   xlen);
 
 	/*
 	 *      1. get the internal parent dtpage covering
@@ -2382,7 +2424,7 @@
 
 	/* retrieve search result */
 	DT_GETSEARCH(ip, btstack.top, bn, pmp, pp, index);
-	jEVENT(0, ("dtRelocate: parent router entry validated.\n"));
+	jfs_info("dtRelocate: parent router entry validated.");
 
 	/*
 	 *      2. relocate the target dtpage
@@ -2488,7 +2530,7 @@
 #endif /* _STILL_TO_PORT */
 	/* unpin the relocated page */
 	DT_PUTPAGE(mp);
-	jEVENT(0, ("dtRelocate: target dtpage relocated.\n"));
+	jfs_info("dtRelocate: target dtpage relocated.");
 
 	/* the moved extent is dtpage, then a LOG_NOREDOPAGE log rec
 	 * needs to be written (in logredo(), the LOG_NOREDOPAGE log rec
@@ -2516,7 +2558,7 @@
 	 * acquire tlck for the parent entry covering the target dtpage;
 	 * write LOG_REDOPAGE to apply after image only;
 	 */
-	jEVENT(0, ("dtRelocate: update parent router entry.\n"));
+	jfs_info("dtRelocate: update parent router entry.");
 	tlck = txLock(tid, ip, pmp, tlckDTREE | tlckENTRY);
 	dtlck = (struct dt_lock *) & tlck->lock;
 	lv = & dtlck->lv[dtlck->index];
@@ -2675,9 +2717,8 @@
 		 * action: update prev pointer;
 		 */
 		tlck = txLock(tid, ip, mp, tlckDTREE | tlckRELINK);
-		jEVENT(0,
-		       ("dtRelink nextbn: tlck = 0x%p, ip = 0x%p, mp=0x%p\n",
-			tlck, ip, mp));
+		jfs_info("dtRelink nextbn: tlck = 0x%p, ip = 0x%p, mp=0x%p",
+			tlck, ip, mp);
 		dtlck = (struct dt_lock *) & tlck->lock;
 
 		/* linelock header */
@@ -2705,9 +2746,8 @@
 		 * action: update next pointer;
 		 */
 		tlck = txLock(tid, ip, mp, tlckDTREE | tlckRELINK);
-		jEVENT(0,
-		       ("dtRelink prevbn: tlck = 0x%p, ip = 0x%p, mp=0x%p\n",
-			tlck, ip, mp));
+		jfs_info("dtRelink prevbn: tlck = 0x%p, ip = 0x%p, mp=0x%p",
+			tlck, ip, mp);
 		dtlck = (struct dt_lock *) & tlck->lock;
 
 		/* linelock header */
@@ -2769,12 +2809,6 @@
 			set_cflag(COMMIT_Stale, ip);
 
 			tblk->xflag = xflag_save;
-			/*
-			 * Tells jfs_metapage code that the metadata pages
-			 * for the index table are no longer useful, and
-			 * remove them from page cache.
-			 */
-			invalidate_inode_metapages(ip);
 		} else
 			ip->i_size = 1;
 
@@ -2944,7 +2978,6 @@
 	int d_namleft, len, outlen;
 	unsigned long dirent_buf;
 	char *name_ptr;
-	int dtlhdrdatalen;
 	u32 dir_index;
 	int do_index = 0;
 	uint loop_count = 0;
@@ -2964,7 +2997,6 @@
 		 *                      -1 = End of directory
 		 */
 		do_index = 1;
-		dtlhdrdatalen = DTLHDRDATALEN;
 
 		dir_index = (u32) filp->f_pos;
 
@@ -2985,8 +3017,8 @@
 			}
 			if (dirtab_slot.flag == DIR_INDEX_FREE) {
 				if (loop_count++ > JFS_IP(ip)->next_index) {
-					jERROR(1, ("jfs_readdir detected "
-						   "infinite loop!\n"));
+					jfs_err("jfs_readdir detected "
+						   "infinite loop!");
 					filp->f_pos = DIREND;
 					return 0;
 				}
@@ -3005,7 +3037,7 @@
 				return 0;
 			}
 			if (p->header.flag & BT_INTERNAL) {
-				jERROR(1,("jfs_readdir: bad index table\n"));
+				jfs_err("jfs_readdir: bad index table");
 				DT_PUTPAGE(mp);
 				filp->f_pos = -1;
 				return 0;
@@ -3049,8 +3081,6 @@
 		 * pn > 0:              Real entries, pn=1 -> leftmost page
 		 * pn = index = -1:     No more entries
 		 */
-		dtlhdrdatalen = DTLHDRDATALEN_LEGACY;
-
 		dtpos = filp->f_pos;
 		if (dtpos == 0) {
 			/* build "." entry */
@@ -3070,8 +3100,8 @@
 					    PARENT(ip), DT_DIR))
 					return 0;
 			} else {
-				jERROR(1,
-				       ("jfs_readdir called with invalid offset!\n"));
+				jfs_err("jfs_readdir called with "
+					"invalid offset!");
 			}
 			dtoffset->pn = 1;
 			dtoffset->index = 0;
@@ -3084,9 +3114,8 @@
 		}
 
 		if ((rc = dtReadNext(ip, &filp->f_pos, &btstack))) {
-			jERROR(1,
-			       ("jfs_readdir: unexpected rc = %d from dtReadNext\n",
-				rc));
+			jfs_err("jfs_readdir: unexpected rc = %d "
+				"from dtReadNext", rc);
 			filp->f_pos = DIREND;
 			return 0;
 		}
@@ -3103,7 +3132,7 @@
 	dirent_buf = __get_free_page(GFP_KERNEL);
 	if (dirent_buf == 0) {
 		DT_PUTPAGE(mp);
-		jERROR(1, ("jfs_readdir: __get_free_page failed!\n"));
+		jfs_warn("jfs_readdir: __get_free_page failed!");
 		filp->f_pos = DIREND;
 		return -ENOMEM;
 	}
@@ -3175,9 +3204,10 @@
 				d_namleft -= len;
 				/* Sanity Check */
 				if (d_namleft == 0) {
-					jERROR(1,("JFS:Dtree error: "
-					  "ino = %ld, bn=%Ld, index = %d\n",
-						  (long)ip->i_ino, (long long)bn, i));
+					jfs_err("JFS:Dtree error: ino = "
+						"%ld, bn=%Ld, index = %d",
+						(long)ip->i_ino,(long long)bn,
+						i);
 					updateSuper(ip->i_sb, FM_DIRTY);
 					goto skip_one;
 				}
@@ -3919,6 +3949,8 @@
 		memmove(stbl + index + 1, stbl + index, nextindex - index);
 
 		if ((p->header.flag & BT_LEAF) && data->leaf.ip) {
+			s64 lblock;
+
 			/*
 			 * Need to update slot number for entries that moved
 			 * in the stbl
@@ -3928,7 +3960,7 @@
 				lh = (struct ldtentry *) & (p->slot[stbl[n]]);
 				modify_index(data->leaf.tid, data->leaf.ip,
 					     le32_to_cpu(lh->index), bn, n,
-					     &mp);
+					     &mp, &lblock);
 			}
 			if (mp)
 				release_metapage(mp);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/jfs/jfs_extent.c linux-2.4.21-pre6/fs/jfs/jfs_extent.c
--- linux-2.4.20/fs/jfs/jfs_extent.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/jfs/jfs_extent.c	2003-03-26 23:49:40.000000000 +0000
@@ -91,7 +91,7 @@
 {
 	struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
 	s64 nxlen, nxaddr, xoff, hint, xaddr = 0;
-	int rc, nbperpage;
+	int rc;
 	int xflag;
 
 	/* This blocks if we are low on resources */
@@ -104,9 +104,6 @@
 	if (xlen > MAXXLEN)
 		xlen = MAXXLEN;
 
-	/* get the number of blocks per page */
-	nbperpage = sbi->nbperpage;
-
 	/* get the page's starting extent offset */
 	xoff = pno << sbi->l2nbperpage;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/jfs/jfs_imap.c linux-2.4.21-pre6/fs/jfs/jfs_imap.c
--- linux-2.4.20/fs/jfs/jfs_imap.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/jfs/jfs_imap.c	2003-03-26 23:49:35.000000000 +0000
@@ -136,7 +136,7 @@
 	/* allocate the in-memory inode map control structure. */
 	imap = (struct inomap *) kmalloc(sizeof(struct inomap), GFP_KERNEL);
 	if (imap == NULL) {
-		jERROR(1, ("diMount: kmalloc returned NULL!\n"));
+		jfs_err("diMount: kmalloc returned NULL!");
 		return (ENOMEM);
 	}
 
@@ -252,7 +252,7 @@
 			  IMAPBLKNO << JFS_SBI(ipimap->i_sb)->l2nbperpage,
 			  PSIZE, 0);
 	if (mp == NULL) {
-		jERROR(1,("diSync: get_metapage failed!\n"));
+		jfs_err("diSync: get_metapage failed!");
 		return EIO;
 	}
 
@@ -337,7 +337,7 @@
 	uint pageno;
 	int rel_inode;
 
-	jFYI(1, ("diRead: ino = %ld\n", ip->i_ino));
+	jfs_info("diRead: ino = %ld", ip->i_ino);
 
 	ipimap = sbi->ipimap;
 	JFS_IP(ip)->ipimap = ipimap;
@@ -351,7 +351,7 @@
 	rc = diIAGRead(imap, iagno, &mp);
 	IREAD_UNLOCK(ipimap);
 	if (rc) {
-		jERROR(1, ("diRead: diIAGRead returned %d\n", rc));
+		jfs_err("diRead: diIAGRead returned %d", rc);
 		return (rc);
 	}
 
@@ -398,7 +398,7 @@
 	/* read the page of disk inode */
 	mp = read_metapage(ipimap, pageno << sbi->l2nbperpage, PSIZE, 1);
 	if (mp == 0) {
-		jERROR(1, ("diRead: read_metapage failed\n"));
+		jfs_err("diRead: read_metapage failed");
 		return EIO;
 	}
 
@@ -407,7 +407,7 @@
 	dp += rel_inode;
 
 	if (ip->i_ino != le32_to_cpu(dp->di_number)) {
-		jERROR(1, ("diRead: i_ino != di_number\n"));
+		jfs_err("diRead: i_ino != di_number");
 		updateSuper(ip->i_sb, FM_DIRTY);
 		rc = EIO;
 	} else if (le32_to_cpu(dp->di_nlink) == 0)
@@ -459,8 +459,7 @@
 
 	ip = new_inode(sb);
 	if (ip == NULL) {
-		jERROR(1,
-		       ("diReadSpecial: new_inode returned NULL!\n"));
+		jfs_err("diReadSpecial: new_inode returned NULL!");
 		return ip;
 	}
 
@@ -486,9 +485,6 @@
 	address += inum >> 3;	/* 8 inodes per 4K page */
 
 	/* read the page of fixed disk inode (AIT) in raw mode */
-	jEVENT(0,
-	       ("Reading aggregate inode %d from block %d\n", (uint) inum,
-		address));
 	mp = read_metapage(ip, address << sbi->l2nbperpage, PSIZE, 1);
 	if (mp == NULL) {
 		ip->i_sb = NULL;
@@ -559,13 +555,10 @@
 	address += inum >> 3;	/* 8 inodes per 4K page */
 
 	/* read the page of fixed disk inode (AIT) in raw mode */
-	jEVENT(0,
-	       ("Reading aggregate inode %d from block %d\n", (uint) inum,
-		address));
 	mp = read_metapage(ip, address << sbi->l2nbperpage, PSIZE, 1);
 	if (mp == NULL) {
-		jERROR(1,
-		       ("diWriteSpecial: failed to read aggregate inode extent!\n"));
+		jfs_err("diWriteSpecial: failed to read aggregate inode "
+			"extent!");
 		return;
 	}
 
@@ -592,7 +585,7 @@
 void diFreeSpecial(struct inode *ip)
 {
 	if (ip == NULL) {
-		jERROR(1, ("diFreeSpecial called with NULL ip!\n"));
+		jfs_err("diFreeSpecial called with NULL ip!");
 		return;
 	}
 	fsync_inode_data_buffers(ip);
@@ -799,7 +792,7 @@
 			       lv->length << L2DTSLOTSIZE);
 		}
 	} else {
-		jERROR(1, ("diWrite: UFO tlock\n"));
+		jfs_err("diWrite: UFO tlock");
 	}
 
       inlineData:
@@ -931,8 +924,8 @@
 	 */
 	//assert(iagno < imap->im_nextiag);
 	if (iagno >= imap->im_nextiag) {
-		jERROR(1, ("diFree: inum = %d, iagno = %d, nextiag = %d\n",
-			   (uint) inum, iagno, imap->im_nextiag));
+		jfs_err("diFree: inum = %d, iagno = %d, nextiag = %d",
+			(uint) inum, iagno, imap->im_nextiag);
 		dump_mem("imap", imap, 32);
 		updateSuper(ip->i_sb, FM_DIRTY);
 		return EIO;
@@ -979,7 +972,7 @@
 	bitmap = le32_to_cpu(iagp->wmap[extno]) & ~mask;
 
 	if (imap->im_agctl[agno].numfree > imap->im_agctl[agno].numinos) {
-		jERROR(1,("diFree: numfree > numinos\n"));
+		jfs_err("diFree: numfree > numinos");
 		release_metapage(mp);
 		IREAD_UNLOCK(ipimap);
 		AG_UNLOCK(imap, agno);
@@ -1175,7 +1168,7 @@
 	 * invalidate any page of the inode extent freed from buffer cache;
 	 */
 	freepxd = iagp->inoext[extno];
-	invalidate_pxd_metapages(ip->i_sb->s_bdev->bd_inode, freepxd);
+	invalidate_pxd_metapages(ip, freepxd);
 
 	/*
 	 *      update iag list(s) (careful update step 2)
@@ -1689,7 +1682,7 @@
 	numinos = imap->im_agctl[agno].numinos;
 
 	if (numfree > numinos) {
-		jERROR(1,("diAllocAG: numfree > numinos\n"));
+		jfs_err("diAllocAG: numfree > numinos");
 		updateSuper(ip->i_sb, FM_DIRTY);
 		return EIO;
 	}
@@ -1840,9 +1833,8 @@
 	 */
 	//assert(iagp->nfreeinos);
 	if (!iagp->nfreeinos) {
-		jERROR(1,
-		       ("diAllocIno: nfreeinos = 0, but iag on freelist\n"));
-		jERROR(1, ("  agno = %d, iagno = %d\n", agno, iagno));
+		jfs_err("diAllocIno: nfreeinos = 0, but iag on freelist");
+		jfs_err("  agno = %d, iagno = %d", agno, iagno);
 		dump_mem("iag", iagp, 64);
 		updateSuper(ip->i_sb, FM_DIRTY);
 		return EIO;
@@ -2769,18 +2761,14 @@
 		 * the inode will be freed from working map at the release
 		 * of last reference release;
 		 */
-//              assert(le32_to_cpu(iagp->wmap[extno]) & mask);
 		if (!(le32_to_cpu(iagp->wmap[extno]) & mask)) {
-			jERROR(1,
-			       ("diUpdatePMap: inode %ld not marked as allocated in wmap!\n",
-				inum));
+			jfs_err("diUpdatePMap: inode %ld not marked as "
+				"allocated in wmap!", inum);
 			updateSuper(ipimap->i_sb, FM_DIRTY);
 		}
-//              assert(le32_to_cpu(iagp->pmap[extno]) & mask);
 		if (!(le32_to_cpu(iagp->pmap[extno]) & mask)) {
-			jERROR(1,
-			       ("diUpdatePMap: inode %ld not marked as allocated in pmap!\n",
-				inum));
+			jfs_err("diUpdatePMap: inode %ld not marked as "
+				"allocated in pmap!", inum);
 			updateSuper(ipimap->i_sb, FM_DIRTY);
 		}
 		/* update the bitmap for the extent of the freed inode */
@@ -2857,9 +2845,9 @@
 	int numinos, xnuminos = 0, xnumfree = 0;
 	s64 agstart;
 
-	jEVENT(0, ("diExtendFS: nextiag:%d numinos:%d numfree:%d\n",
+	jfs_info("diExtendFS: nextiag:%d numinos:%d numfree:%d",
 		   imap->im_nextiag, atomic_read(&imap->im_numinos),
-		   atomic_read(&imap->im_numfree)));
+		   atomic_read(&imap->im_numfree));
 
 	/*
 	 *      reconstruct imap 
@@ -2984,7 +2972,6 @@
 	struct buffer_head *bh;
 	struct inode *ip;
 	tid_t tid;
-	int rc;
 
 	/* if AIT2 ipmap2 is bad, do not try to update it */
 	if (JFS_SBI(sb)->mntflag & JFS_BAD_SAIT)	/* s_flag */
@@ -2992,7 +2979,7 @@
 	ip = diReadSpecial(sb, FILESYSTEM_I, 1);
 	if (ip == NULL) {
 		JFS_SBI(sb)->mntflag |= JFS_BAD_SAIT;
-		if ((rc = readSuper(sb, &bh)))
+		if (readSuper(sb, &bh))
 			return;
 		j_sb = (struct jfs_superblock *)bh->b_data;
 		j_sb->s_flag |= JFS_BAD_SAIT;
@@ -3007,7 +2994,7 @@
 	/* start transaction */
 	tid = txBegin(sb, COMMIT_FORCE);
 	/* update the inode map addressing structure to point to it */
-	if ((rc = xtInsert(tid, ip, 0, blkno, xlen, xaddr, 0))) {
+	if (xtInsert(tid, ip, 0, blkno, xlen, xaddr, 0)) {
 		JFS_SBI(sb)->mntflag |= JFS_BAD_SAIT;
 		txAbort(tid, 1);
 		goto cleanup;
@@ -3016,7 +3003,7 @@
 	/* update the inode map's inode to reflect the extension */
 	ip->i_size += PSIZE;
 	ip->i_blocks += LBLK2PBLK(sb, xlen);
-	rc = txCommit(tid, 1, &ip, COMMIT_FORCE);
+	txCommit(tid, 1, &ip, COMMIT_FORCE);
       cleanup:
 	txEnd(tid);
 	diFreeSpecial(ip);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/jfs/jfs_incore.h linux-2.4.21-pre6/fs/jfs/jfs_incore.h
--- linux-2.4.20/fs/jfs/jfs_incore.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/jfs/jfs_incore.h	2003-03-26 23:49:19.000000000 +0000
@@ -55,7 +55,6 @@
 	lid_t	atlhead;	/* anonymous tlock list head	*/
 	lid_t	atltail;	/* anonymous tlock list tail	*/
 	struct list_head anon_inode_list; /* inodes having anonymous txns */
-	struct list_head mp_list; /* metapages in inode's address space */
 	/*
 	 * rdwrlock serializes xtree between reads & writes and synchronizes
 	 * changes to special inodes.  It's use would be redundant on
@@ -112,7 +111,6 @@
 	COMMIT_Inlineea,	/* commit inode inline EA */
 	COMMIT_Freewmap,	/* free WMAP at iClose() */
 	COMMIT_Dirty,		/* Inode is really dirty */
-	COMMIT_Holdlock,	/* Hold the IWRITE_LOCK until commit is done */
 	COMMIT_Dirtable,	/* commit changes to di_dirtable */
 	COMMIT_Stale,		/* data extent is no longer valid */
 	COMMIT_Synclist,	/* metadata pages on group commit synclist */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/jfs/jfs_inode.c linux-2.4.21-pre6/fs/jfs/jfs_inode.c
--- linux-2.4.20/fs/jfs/jfs_inode.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/jfs/jfs_inode.c	2003-03-26 23:49:55.000000000 +0000
@@ -40,7 +40,7 @@
 
 	inode = new_inode(sb);
 	if (!inode) {
-		jERROR(1, ("ialloc: new_inode returned NULL!\n"));
+		jfs_warn("ialloc: new_inode returned NULL!");
 		return inode;
 	}
 
@@ -54,7 +54,7 @@
 
 	rc = diAlloc(parent, S_ISDIR(mode), inode);
 	if (rc) {
-		jERROR(1, ("ialloc: diAlloc returned %d!\n", rc));
+		jfs_warn("ialloc: diAlloc returned %d!", rc);
 		free_jfs_inode(inode);
 		make_bad_inode(inode);
 		iput(inode);
@@ -96,7 +96,7 @@
 	jfs_inode->atltail = 0;
 	jfs_inode->xtlid = 0;
 
-	jFYI(1, ("ialloc returns inode = 0x%p\n", inode));
+	jfs_info("ialloc returns inode = 0x%p\n", inode);
 
 	return inode;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/jfs/jfs_logmgr.c linux-2.4.21-pre6/fs/jfs/jfs_logmgr.c
--- linux-2.4.20/fs/jfs/jfs_logmgr.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/jfs/jfs_logmgr.c	2003-03-26 23:49:35.000000000 +0000
@@ -95,7 +95,7 @@
 #define LOGGC_LOCK_INIT(log)	spin_lock_init(&(log)->gclock)
 #define LOGGC_LOCK(log)		spin_lock_irq(&(log)->gclock)
 #define LOGGC_UNLOCK(log)	spin_unlock_irq(&(log)->gclock)
-#define LOGGC_WAKEUP(tblk)	wake_up(&(tblk)->gcwait)
+#define LOGGC_WAKEUP(tblk)	wake_up_all(&(tblk)->gcwait)
 
 /*
  *	log sync serialization (per log)
@@ -183,9 +183,8 @@
 static void lbmDirectWrite(struct jfs_log * log, struct lbuf * bp, int flag);
 static int lbmIOWait(struct lbuf * bp, int flag);
 static void lbmIODone(struct buffer_head *bh, int);
-
-void lbmStartIO(struct lbuf * bp);
-void lmGCwrite(struct jfs_log * log, int cant_block);
+static void lbmStartIO(struct lbuf * bp);
+static void lmGCwrite(struct jfs_log * log, int cant_block);
 
 
 /*
@@ -196,6 +195,8 @@
 	uint commit;		/* # of commit */
 	uint pagedone;		/* # of page written */
 	uint submitted;		/* # of pages submitted */
+	uint full_page;		/* # of full pages submitted */
+	uint partial_page;	/* # of partial pages submitted */
 } lmStat;
 #endif
 
@@ -219,8 +220,8 @@
 	int diffp, difft;
 	struct metapage *mp = NULL;
 
-	jFYI(1, ("lmLog: log:0x%p tblk:0x%p, lrd:0x%p tlck:0x%p\n",
-		 log, tblk, lrd, tlck));
+	jfs_info("lmLog: log:0x%p tblk:0x%p, lrd:0x%p tlck:0x%p",
+		 log, tblk, lrd, tlck);
 
 	LOG_LOCK(log);
 
@@ -388,7 +389,7 @@
 	}
 #endif				/* _JFS_WIP */
 	else {
-		jERROR(2, ("lmWriteRecord: UFO tlck:0x%p\n", tlck));
+		jfs_err("lmWriteRecord: UFO tlck:0x%p", tlck);
 		return 0;	/* Probably should trap */
 	}
 	l2linesize = linelock->l2linesize;
@@ -447,9 +448,8 @@
 		lvd->offset = cpu_to_le16(lv->offset);
 		lvd->length = cpu_to_le16(lv->length);
 		dstoffset += 4;
-		jFYI(1,
-		     ("lmWriteRecord: lv offset:%d length:%d\n",
-		      lv->offset, lv->length));
+		jfs_info("lmWriteRecord: lv offset:%d length:%d",
+			 lv->offset, lv->length);
 	}
 
 	if ((i = linelock->next)) {
@@ -490,9 +490,8 @@
 
 		if (lrd->type & cpu_to_le16(LOG_COMMIT)) {
 			tblk->clsn = lsn;
-			jFYI(1,
-			     ("wr: tclsn:0x%x, beor:0x%x\n", tblk->clsn,
-			      bp->l_eor));
+			jfs_info("wr: tclsn:0x%x, beor:0x%x", tblk->clsn,
+				 bp->l_eor);
 
 			INCREMENT(lmStat.commit);	/* # of commit */
 
@@ -511,7 +510,6 @@
 			tblk->bp = log->bp;
 			tblk->pn = log->page;
 			tblk->eor = log->eor;
-			init_waitqueue_head(&tblk->gcwait);
 
 			/* enqueue transaction to commit queue */
 			tblk->cqnext = NULL;
@@ -524,10 +522,8 @@
 			LOGGC_UNLOCK(log);
 		}
 
-		jFYI(1,
-		     ("lmWriteRecord: lrd:0x%04x bp:0x%p pn:%d eor:0x%x\n",
-		      le16_to_cpu(lrd->type), log->bp, log->page,
-		      dstoffset));
+		jfs_info("lmWriteRecord: lrd:0x%04x bp:0x%p pn:%d eor:0x%x",
+			le16_to_cpu(lrd->type), log->bp, log->page, dstoffset);
 
 		/* page not full ? */
 		if (dstoffset < LOGPSIZE - LOGPTLRSIZE)
@@ -567,8 +563,6 @@
 	struct lbuf *nextbp;
 	struct tblock *tblk;
 
-	jFYI(1, ("lmNextPage\n"));
-
 	/* get current log page number and log sequence page number */
 	pn = log->page;
 	bp = log->bp;
@@ -597,21 +591,21 @@
 		/* mark tblk for end-of-page */
 		tblk->flag |= tblkGC_EOP;
 
-		/* if page is not already on write queue,
-		 * just enqueue (no lbmWRITE to prevent redrive)
-		 * buffer to wqueue to ensure correct serial order
-		 * of the pages since log pages will be added
-		 * continuously (tblk bound with the page hasn't
-		 * got around to init write of the page, either
-		 * preempted or the page got filled by its COMMIT
-		 * record);
-		 * pages with COMMIT are paged out explicitly by
-		 * tblk in lmGroupCommit();
-		 */
-		if (bp->l_wqnext == NULL) {
-			/* bp->l_ceor = bp->l_eor; */
-			/* lp->h.eor = lp->t.eor = bp->l_ceor; */
-			lbmWrite(log, bp, 0, 0);
+		if (log->cflag & logGC_PAGEOUT) {
+			/* if page is not already on write queue,
+			 * just enqueue (no lbmWRITE to prevent redrive)
+			 * buffer to wqueue to ensure correct serial order
+			 * of the pages since log pages will be added
+			 * continuously
+			 */
+			if (bp->l_wqnext == NULL)
+				lbmWrite(log, bp, 0, 0);
+		} else {
+			/*
+			 * No current GC leader, initiate group commit
+			 */
+			log->cflag |= logGC_PAGEOUT;
+			lmGCwrite(log, 0);
 		}
 	}
 	/* page is not bound with outstanding tblk:
@@ -644,7 +638,6 @@
 	lp->h.page = lp->t.page = cpu_to_le32(lspn + 1);
 	lp->h.eor = lp->t.eor = cpu_to_le16(LOGPHDRSIZE);
 
-	jFYI(1, ("lmNextPage done\n"));
 	return 0;
 }
 
@@ -678,24 +671,31 @@
 		LOGGC_UNLOCK(log);
 		return rc;
 	}
-	jFYI(1,
-	     ("lmGroup Commit: tblk = 0x%p, gcrtc = %d\n", tblk,
-	      log->gcrtc));
+	jfs_info("lmGroup Commit: tblk = 0x%p, gcrtc = %d", tblk, log->gcrtc);
 
-	/*
-	 * group commit pageout in progress
-	 */
-	if ((!(log->cflag & logGC_PAGEOUT)) && log->cqueue.head) {
+	if (tblk->xflag & COMMIT_LAZY)
+		tblk->flag |= tblkGC_LAZY;
+
+	if ((!(log->cflag & logGC_PAGEOUT)) && log->cqueue.head &&
+	    (!(tblk->xflag & COMMIT_LAZY) || test_bit(log_FLUSH, &log->flag))) {
 		/*
-		 * only transaction in the commit queue:
+		 * No pageout in progress
 		 *
-		 * start one-transaction group commit as
-		 * its group leader.
+		 * start group commit as its group leader.
 		 */
 		log->cflag |= logGC_PAGEOUT;
 
 		lmGCwrite(log, 0);
 	}
+
+	if (tblk->xflag & COMMIT_LAZY) {
+		/*
+		 * Lazy transactions can leave now
+		 */
+		LOGGC_UNLOCK(log);
+		return 0;
+	}
+
 	/* lmGCwrite gives up LOGGC_LOCK, check again */
 
 	if (tblk->flag & tblkGC_COMMITTED) {
@@ -709,12 +709,6 @@
 	/* upcount transaction waiting for completion
 	 */
 	log->gcrtc++;
-
-	if (tblk->xflag & COMMIT_LAZY) {
-		tblk->flag |= tblkGC_LAZY;
-		LOGGC_UNLOCK(log);
-		return 0;
-	}
 	tblk->flag |= tblkGC_READY;
 
 	__SLEEP_COND(tblk->gcwait, (tblk->flag & tblkGC_COMMITTED),
@@ -741,7 +735,7 @@
  *	LOGGC_LOCK must be held by caller.
  *	N.B. LOG_LOCK is NOT held during lmGroupCommit().
  */
-void lmGCwrite(struct jfs_log * log, int cant_write)
+static void lmGCwrite(struct jfs_log * log, int cant_write)
 {
 	struct lbuf *bp;
 	struct logpage *lp;
@@ -780,20 +774,16 @@
 		tblk->flag |= tblkGC_FREE;
 		bp->l_ceor = bp->l_eor;
 		lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_ceor);
-		jEVENT(0,
-		       ("gc: tclsn:0x%x, bceor:0x%x\n", tblk->clsn,
-			bp->l_ceor));
 		lbmWrite(log, bp, lbmWRITE | lbmRELEASE | lbmGC,
 			 cant_write);
+		INCREMENT(lmStat.full_page);
 	}
 	/* page is not yet full */
 	else {
 		bp->l_ceor = tblk->eor;	/* ? bp->l_ceor = bp->l_eor; */
 		lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_ceor);
-		jEVENT(0,
-		       ("gc: tclsn:0x%x, bceor:0x%x\n", tblk->clsn,
-			bp->l_ceor));
 		lbmWrite(log, bp, lbmWRITE | lbmGC, cant_write);
+		INCREMENT(lmStat.partial_page);
 	}
 }
 
@@ -840,9 +830,14 @@
 		tblk->flag &= ~tblkGC_QUEUE;
 		tblk->cqnext = 0;
 
-		jEVENT(0,
-		       ("lmPostGC: tblk = 0x%p, flag = 0x%x\n", tblk,
-			tblk->flag));
+		if (tblk == log->flush_tblk) {
+			/* we can stop flushing the log now */
+			clear_bit(log_FLUSH, &log->flag);
+			log->flush_tblk = NULL;
+		}
+
+		jfs_info("lmPostGC: tblk = 0x%p, flag = 0x%x", tblk,
+			 tblk->flag);
 
 		if (!(tblk->xflag & COMMIT_FORCE))
 			/*
@@ -853,10 +848,10 @@
 			/* state transition: COMMIT -> COMMITTED */
 			tblk->flag |= tblkGC_COMMITTED;
 
-			if (tblk->flag & tblkGC_READY) {
+			if (tblk->flag & tblkGC_READY)
 				log->gcrtc--;
-				LOGGC_WAKEUP(tblk);
-			}
+
+			LOGGC_WAKEUP(tblk);
 		}
 
 		/* was page full before pageout ?
@@ -872,7 +867,7 @@
 			lp = (struct logpage *) bp->l_ldata;
 			bp->l_ceor = bp->l_eor;
 			lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_eor);
-			jEVENT(0, ("lmPostGC: calling lbmWrite\n"));
+			jfs_info("lmPostGC: calling lbmWrite");
 			lbmWrite(log, bp, lbmWRITE | lbmRELEASE | lbmFREE,
 				 1);
 		}
@@ -881,11 +876,14 @@
 
 	/* are there any transactions who have entered lnGroupCommit()
 	 * (whose COMMITs are after that of the last log page written.
-	 * They are waiting for new group commit (above at (SLEEP 1)):
+	 * They are waiting for new group commit (above at (SLEEP 1))
+	 * or lazy transactions are on a full (queued) log page,
 	 * select the latest ready transaction as new group leader and
 	 * wake her up to lead her group.
 	 */
-	if ((log->gcrtc > 0) && log->cqueue.head)
+	if ((tblk = log->cqueue.head) &&
+	    ((log->gcrtc > 0) || (tblk->bp->l_wqnext != NULL) ||
+	     test_bit(log_FLUSH, &log->flag)))
 		/*
 		 * Call lmGCwrite with new group leader
 		 */
@@ -893,8 +891,8 @@
 
 	/* no transaction are ready yet (transactions are only just
 	 * queued (GC_QUEUE) and not entered for group commit yet).
-	 * let the first transaction entering group commit
-	 * will elect hetself as new group leader.
+	 * the first transaction entering group commit
+	 * will elect herself as new group leader.
 	 */
 	else
 		log->cflag &= ~logGC_PAGEOUT;
@@ -995,8 +993,7 @@
 	delta = LOGSYNC_DELTA(logsize);
 	more = min(free / 2, delta);
 	if (more < 2 * LOGPSIZE) {
-		jEVENT(1,
-		       ("\n ... Log Wrap ... Log Wrap ... Log Wrap ...\n\n"));
+		jfs_warn("\n ... Log Wrap ... Log Wrap ... Log Wrap ...\n");
 		/*
 		 *      log wrapping
 		 *
@@ -1035,8 +1032,12 @@
 	 */
 	if (written > LOGSYNC_BARRIER(logsize) && logsize > 32 * LOGPSIZE) {
 		set_bit(log_SYNCBARRIER, &log->flag);
-		jFYI(1, ("log barrier on: lsn=0x%x syncpt=0x%x\n", lsn,
-			 log->syncpt));
+		jfs_info("log barrier on: lsn=0x%x syncpt=0x%x", lsn,
+			 log->syncpt);
+		/*
+		 * We may have to initiate group commit
+		 */
+		jfs_flush_journal(log, 0);
 	}
 
 	return lsn;
@@ -1130,7 +1131,6 @@
 		goto shutdown;
 
       out:
-	jFYI(1, ("lmLogOpen: exit(0)\n"));
 	*logptr = log;
 	return 0;
 
@@ -1146,7 +1146,7 @@
       free:		/* free log descriptor */
 	kfree(log);
 
-	jFYI(1, ("lmLogOpen: exit(%d)\n", rc));
+	jfs_warn("lmLogOpen: exit(%d)", rc);
 	return rc;
 }
 
@@ -1179,7 +1179,7 @@
 	struct logpage *lp;
 	int lsn;
 
-	jFYI(1, ("lmLogInit: log:0x%p\n", log));
+	jfs_info("lmLogInit: log:0x%p", log);
 
 	/*
 	 * log inode is overlaid on generic inode where
@@ -1205,14 +1205,14 @@
 	logsuper = (struct logsuper *) bpsuper->l_ldata;
 
 	if (logsuper->magic != cpu_to_le32(LOGMAGIC)) {
-		jERROR(1, ("*** Log Format Error ! ***\n"));
+		jfs_warn("*** Log Format Error ! ***");
 		rc = EINVAL;
 		goto errout20;
 	}
 
 	/* logredo() should have been run successfully. */
 	if (logsuper->state != cpu_to_le32(LOGREDONE)) {
-		jERROR(1, ("*** Log Is Dirty ! ***\n"));
+		jfs_warn("*** Log Is Dirty ! ***");
 		rc = EINVAL;
 		goto errout20;
 	}
@@ -1223,19 +1223,17 @@
 			rc = EINVAL;
 			goto errout20;
 		}
-		jFYI(0,
-		     ("lmLogInit: inline log:0x%p base:0x%Lx size:0x%x\n",
-		      log, (unsigned long long) log->base, log->size));
+		jfs_info("lmLogInit: inline log:0x%p base:0x%Lx size:0x%x",
+			log, (unsigned long long) log->base, log->size);
 	} else {
 		if (memcmp(logsuper->uuid, log->uuid, 16)) {
-			jERROR(1,("wrong uuid on JFS log device\n"));
+			jfs_warn("wrong uuid on JFS log device");
 			goto errout20;
 		}
 		log->size = le32_to_cpu(logsuper->size);
 		log->l2bsize = le32_to_cpu(logsuper->l2bsize);
-		jFYI(0,
-		     ("lmLogInit: external log:0x%p base:0x%Lx size:0x%x\n",
-		      log, (unsigned long long) log->base, log->size));
+		jfs_info("lmLogInit: external log:0x%p base:0x%Lx size:0x%x",
+			log, (unsigned long long) log->base, log->size);
 	}
 
 	log->page = le32_to_cpu(logsuper->end) / LOGPSIZE;
@@ -1250,9 +1248,9 @@
 
 	lp = (struct logpage *) bp->l_ldata;
 
-	jFYI(1, ("lmLogInit: lsn:0x%x page:%d eor:%d:%d\n",
+	jfs_info("lmLogInit: lsn:0x%x page:%d eor:%d:%d",
 		 le32_to_cpu(logsuper->end), log->page, log->eor,
-		 le16_to_cpu(lp->h.eor)));
+		 le16_to_cpu(lp->h.eor));
 
 //      ASSERT(log->eor == lp->h.eor);
 
@@ -1300,14 +1298,15 @@
 	log->sync = log->syncpt;
 	log->nextsync = LOGSYNC_DELTA(log->logsize);
 
-	jFYI(1, ("lmLogInit: lsn:0x%x syncpt:0x%x sync:0x%x\n",
-		 log->lsn, log->syncpt, log->sync));
+	jfs_info("lmLogInit: lsn:0x%x syncpt:0x%x sync:0x%x",
+		 log->lsn, log->syncpt, log->sync);
 
 	LOGSYNC_LOCK_INIT(log);
 
 	INIT_LIST_HEAD(&log->synclist);
 
-	log->cqueue.head = log->cqueue.tail = 0;
+	log->cqueue.head = log->cqueue.tail = NULL;
+	log->flush_tblk = NULL;
 
 	log->count = 0;
 
@@ -1326,7 +1325,6 @@
 	if ((rc = lbmIOWait(bpsuper, lbmFREE)))
 		goto errout30;
 
-	jFYI(1, ("lmLogInit: exit(%d)\n", rc));
 	return 0;
 
 	/*
@@ -1341,7 +1339,7 @@
       errout10:		/* unwind lbmLogInit() */
 	lbmLogShutdown(log);
 
-	jFYI(1, ("lmLogInit: exit(%d)\n", rc));
+	jfs_warn("lmLogInit: exit(%d)", rc);
 	return rc;
 }
 
@@ -1363,7 +1361,7 @@
 {
 	int rc;
 
-	jFYI(1, ("lmLogClose: log:0x%p\n", log));
+	jfs_info("lmLogClose: log:0x%p", log);
 
 	if (!test_bit(log_INLINELOG, &log->flag))
 		goto externalLog;
@@ -1383,28 +1381,88 @@
 	blkdev_put(log->bdev, BDEV_FS);
 
       out:
-	jFYI(0, ("lmLogClose: exit(%d)\n", rc));
+	jfs_info("lmLogClose: exit(%d)", rc);
 	return rc;
 }
 
 
 /*
- * NAME:	lmLogWait()
+ * NAME:	jfs_flush_journal()
  *
- * FUNCTION:	wait for all outstanding log records to be written to disk
+ * FUNCTION:	initiate write of any outstanding transactions to the journal
+ *		and optionally wait until they are all written to disk
+ *
+ *		wait == 0  flush until latest txn is committed, don't wait
+ *		wait == 1  flush until latest txn is committed, wait
+ *		wait > 1   flush until all txn's are complete, wait
  */
-void lmLogWait(struct jfs_log *log)
+void jfs_flush_journal(struct jfs_log *log, int wait)
 {
 	int i;
+	struct tblock *target;
 
-	jFYI(1, ("lmLogWait: log:0x%p\n", log));
+	jfs_info("jfs_flush_journal: log:0x%p wait=%d", log, wait);
 
-	if (log->cqueue.head || !list_empty(&log->synclist)) {
+	LOGGC_LOCK(log);
+
+	target = log->cqueue.head;
+
+	if (target) {
 		/*
-		 * If there was very recent activity, we may need to wait
-		 * for the lazycommit thread to catch up
+		 * This ensures that we will keep writing to the journal as long
+		 * as there are unwritten commit records
 		 */
 
+		if (test_bit(log_FLUSH, &log->flag)) {
+			/*
+			 * We're already flushing.
+			 * if flush_tblk is NULL, we are flushing everything,
+			 * so leave it that way.  Otherwise, update it to the
+			 * latest transaction
+			 */
+			if (log->flush_tblk)
+				log->flush_tblk = target;
+		} else {
+			/* Only flush until latest transaction is committed */
+			log->flush_tblk = target;
+			set_bit(log_FLUSH, &log->flag);
+
+			/*
+			 * Initiate I/O on outstanding transactions
+			 */
+			if (!(log->cflag & logGC_PAGEOUT)) {
+				log->cflag |= logGC_PAGEOUT;
+				lmGCwrite(log, 0);
+			}
+		}
+	}
+	if ((wait > 1) || test_bit(log_SYNCBARRIER, &log->flag)) {
+		/* Flush until all activity complete */
+		set_bit(log_FLUSH, &log->flag);
+		log->flush_tblk = NULL;
+	}
+
+	if (wait && target && !(target->flag & tblkGC_COMMITTED)) {
+		DECLARE_WAITQUEUE(__wait, current);
+
+		add_wait_queue(&target->gcwait, &__wait);
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		LOGGC_UNLOCK(log);
+		schedule();
+		current->state = TASK_RUNNING;
+		LOGGC_LOCK(log);
+		remove_wait_queue(&target->gcwait, &__wait);
+	}
+	LOGGC_UNLOCK(log);
+
+	if (wait < 2)
+		return;
+
+	/*
+	 * If there was recent activity, we may need to wait
+	 * for the lazycommit thread to catch up
+	 */
+	if (log->cqueue.head || !list_empty(&log->synclist)) {
 		for (i = 0; i < 800; i++) {	/* Too much? */
 			current->state = TASK_INTERRUPTIBLE;
 			schedule_timeout(HZ / 4);
@@ -1415,6 +1473,7 @@
 	}
 	assert(log->cqueue.head == NULL);
 	assert(list_empty(&log->synclist));
+	clear_bit(log_FLUSH, &log->flag);
 }
 
 /*
@@ -1441,9 +1500,9 @@
 	struct lbuf *bp;
 	struct logpage *lp;
 
-	jFYI(1, ("lmLogShutdown: log:0x%p\n", log));
+	jfs_info("lmLogShutdown: log:0x%p", log);
 
-	lmLogWait(log);
+	jfs_flush_journal(log, 2);
 
 	/*
 	 * We need to make sure all of the "written" metapages
@@ -1481,8 +1540,8 @@
 	lbmDirectWrite(log, bpsuper, lbmWRITE | lbmRELEASE | lbmSYNC);
 	rc = lbmIOWait(bpsuper, lbmFREE);
 
-	jFYI(1, ("lmLogShutdown: lsn:0x%x page:%d eor:%d\n",
-		 lsn, log->page, log->eor));
+	jfs_info("lmLogShutdown: lsn:0x%x page:%d eor:%d",
+		 lsn, log->page, log->eor);
 
       out:    
 	/*
@@ -1491,7 +1550,7 @@
 	lbmLogShutdown(log);
 
 	if (rc) {
-		jFYI(1, ("lmLogShutdown: exit(%d)\n", rc));
+		jfs_warn("lmLogShutdown: exit(%d)", rc);
 	}
 	return rc;
 }
@@ -1532,7 +1591,7 @@
 				break;
 			}
 		if (i == MAX_ACTIVE) {
-			jERROR(1,("Too many file systems sharing journal!\n"));
+			jfs_warn("Too many file systems sharing journal!");
 			lbmFree(bpsuper);
 			return EMFILE;	/* Is there a better rc? */
 		}
@@ -1543,7 +1602,7 @@
 				break;
 			}
 		if (i == MAX_ACTIVE) {
-			jERROR(1,("Somebody stomped on the journal!\n"));
+			jfs_warn("Somebody stomped on the journal!");
 			lbmFree(bpsuper);
 			return EIO;
 		}
@@ -1592,7 +1651,7 @@
 	int i;
 	struct lbuf *lbuf;
 
-	jFYI(1, ("lbmLogInit: log:0x%p\n", log));
+	jfs_info("lbmLogInit: log:0x%p", log);
 
 	/* initialize current buffer cursor */
 	log->bp = NULL;
@@ -1655,7 +1714,7 @@
 {
 	struct lbuf *lbuf;
 
-	jFYI(1, ("lbmLogShutdown: log:0x%p\n", log));
+	jfs_info("lbmLogShutdown: log:0x%p", log);
 
 	lbuf = log->lbuf_free;
 	while (lbuf) {
@@ -1769,7 +1828,7 @@
 	 * allocate a log buffer
 	 */
 	*bpp = bp = lbmAllocate(log, pn);
-	jFYI(1, ("lbmRead: bp:0x%p pn:0x%x\n", bp, pn));
+	jfs_info("lbmRead: bp:0x%p pn:0x%x", bp, pn);
 
 	bp->l_flag |= lbmREAD;
 	bp->l_bh.b_reqnext = NULL;
@@ -1809,8 +1868,7 @@
 	struct lbuf *tail;
 	unsigned long flags;
 
-	jFYI(1, ("lbmWrite: bp:0x%p flag:0x%x pn:0x%x\n",
-		 bp, flag, bp->l_pn));
+	jfs_info("lbmWrite: bp:0x%p flag:0x%x pn:0x%x", bp, flag, bp->l_pn);
 
 	/* map the logical block address to physical block address */
 	bp->l_blkno =
@@ -1874,8 +1932,8 @@
  */
 static void lbmDirectWrite(struct jfs_log * log, struct lbuf * bp, int flag)
 {
-	jEVENT(0, ("lbmDirectWrite: bp:0x%p flag:0x%x pn:0x%x\n",
-		   bp, flag, bp->l_pn));
+	jfs_info("lbmDirectWrite: bp:0x%p flag:0x%x pn:0x%x",
+		 bp, flag, bp->l_pn);
 
 	/*
 	 * initialize buffer for device driver
@@ -1902,9 +1960,9 @@
  *
  * serialization: LCACHE_LOCK() is NOT held during log i/o;
  */
-void lbmStartIO(struct lbuf * bp)
+static void lbmStartIO(struct lbuf * bp)
 {
-	jFYI(1, ("lbmStartIO\n"));
+	jfs_info("lbmStartIO");
 
 	bp->l_bh.b_reqnext = NULL;
 	set_bit(BH_Dirty, &bp->l_bh.b_state);
@@ -1920,8 +1978,6 @@
 
 	INCREMENT(lmStat.submitted);
 	run_task_queue(&tq_disk);
-
-	jFYI(1, ("lbmStartIO done\n"));
 }
 
 
@@ -1933,9 +1989,7 @@
 	unsigned long flags;
 	int rc = 0;
 
-	jFYI(1,
-	     ("lbmIOWait1: bp:0x%p flag:0x%x:0x%x\n", bp, bp->l_flag,
-	      flag));
+	jfs_info("lbmIOWait1: bp:0x%p flag:0x%x:0x%x", bp, bp->l_flag, flag);
 
 	LCACHE_LOCK(flags);		/* disable+lock */
 
@@ -1948,9 +2002,7 @@
 
 	LCACHE_UNLOCK(flags);	/* unlock+enable */
 
-	jFYI(1,
-	     ("lbmIOWait2: bp:0x%p flag:0x%x:0x%x\n", bp, bp->l_flag,
-	      flag));
+	jfs_info("lbmIOWait2: bp:0x%p flag:0x%x:0x%x", bp, bp->l_flag, flag);
 	return rc;
 }
 
@@ -1969,7 +2021,7 @@
 	/*
 	 * get back jfs buffer bound to the i/o buffer
 	 */
-	jEVENT(0, ("lbmIODone: bp:0x%p flag:0x%x\n", bp, bp->l_flag));
+	jfs_info("lbmIODone: bp:0x%p flag:0x%x", bp, bp->l_flag);
 
 	LCACHE_LOCK(flags);		/* disable+lock */
 
@@ -1979,7 +2031,7 @@
 	if (!uptodate) {
 		bp->l_flag |= lbmERROR;
 
-		jERROR(1, ("lbmIODone: I/O error in JFS log\n"));
+		jfs_err("lbmIODone: I/O error in JFS log");
 	}
 
 	/*
@@ -2103,8 +2155,6 @@
 {
 	struct lbuf *bp;
 
-	jFYI(1, ("jfsIOWait is here!\n"));
-
 	lock_kernel();
 
 	daemonize();
@@ -2139,7 +2189,7 @@
 		remove_wait_queue(&jfs_IO_thread_wait, &wq);
 	} while (!jfs_stop_threads);
 
-	jFYI(1,("jfsIOWait being killed!\n"));
+	jfs_info("jfsIOWait being killed!");
 	complete(&jfsIOwait);
 	return 0;
 }
@@ -2171,8 +2221,8 @@
 	int npages = 0;
 	struct lbuf *bp;
 
-	jFYI(0, ("lmLogFormat: logAddress:%Ld logSize:%d\n",
-		 (long long)logAddress, logSize));
+	jfs_info("lmLogFormat: logAddress:%Ld logSize:%d",
+		 (long long)logAddress, logSize);
 
 	/* allocate a log buffer */
 	bp = lbmAllocate(log, 1);
@@ -2288,10 +2338,14 @@
 		       "================\n"
 		       "commits = %d\n"
 		       "writes submitted = %d\n"
-		       "writes completed = %d\n",
+		       "writes completed = %d\n"
+		       "full pages submitted = %d\n"
+		       "partial pages submitted = %d\n",
 		       lmStat.commit,
 		       lmStat.submitted,
-		       lmStat.pagedone);
+		       lmStat.pagedone,
+		       lmStat.full_page,
+		       lmStat.partial_page);
 
 	begin = offset;
 	*start = buffer + begin;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/jfs/jfs_logmgr.h linux-2.4.21-pre6/fs/jfs/jfs_logmgr.h
--- linux-2.4.20/fs/jfs/jfs_logmgr.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/jfs/jfs_logmgr.h	2003-03-26 23:49:39.000000000 +0000
@@ -403,6 +403,7 @@
 		struct tblock *head;
 		struct tblock *tail;
 	} cqueue;
+	struct tblock *flush_tblk; /* tblk we're waiting on for flush */
 	int gcrtc;		/* 4: GC_READY transaction count */
 	struct tblock *gclrt;	/* 4: latest GC_READY transaction */
 	spinlock_t gclock;	/* 4: group commit lock */
@@ -424,6 +425,7 @@
 #define log_INLINELOG	1
 #define log_SYNCBARRIER	2
 #define log_QUIESCE	3
+#define log_FLUSH	4
 
 /*
  * group commit flag
@@ -502,11 +504,11 @@
 }
 
 extern int lmLogOpen(struct super_block *sb, struct jfs_log ** log);
-extern void lmLogWait(struct jfs_log * log);
 extern int lmLogClose(struct super_block *sb, struct jfs_log * log);
 extern int lmLogSync(struct jfs_log * log, int nosyncwait);
 extern int lmLogShutdown(struct jfs_log * log);
 extern int lmLogInit(struct jfs_log * log);
 extern int lmLogFormat(struct jfs_log *log, s64 logAddress, int logSize);
+extern void jfs_flush_journal(struct jfs_log * log, int wait);
 
 #endif				/* _H_JFS_LOGMGR */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/jfs/jfs_metapage.c linux-2.4.21-pre6/fs/jfs/jfs_metapage.c
--- linux-2.4.20/fs/jfs/jfs_metapage.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/jfs/jfs_metapage.c	2003-03-26 23:49:50.000000000 +0000
@@ -276,8 +276,7 @@
 	unsigned long page_index;
 	unsigned long page_offset;
 
-	jFYI(1, ("__get_metapage: inode = 0x%p, lblock = 0x%lx\n",
-		 inode, lblock));
+	jfs_info("__get_metapage: inode = 0x%p, lblock = 0x%lx", inode, lblock);
 
 	if (absolute)
 		mapping = inode->i_sb->s_bdev->bd_inode->i_mapping;
@@ -298,7 +297,7 @@
 			clear_bit(META_discard, &mp->flag);
 		}
 		mp->count++;
-		jFYI(1, ("__get_metapage: found 0x%p, in hash\n", mp));
+		jfs_info("__get_metapage: found 0x%p, in hash", mp);
 		assert(mp->logical_size == size);
 		lock_metapage(mp);
 		spin_unlock(&meta_lock);
@@ -310,7 +309,7 @@
 		    l2bsize;
 		if ((page_offset + size) > PAGE_CACHE_SIZE) {
 			spin_unlock(&meta_lock);
-			jERROR(1, ("MetaData crosses page boundary!!\n"));
+			jfs_err("MetaData crosses page boundary!!");
 			return NULL;
 		}
 		
@@ -352,41 +351,36 @@
 		mp->page = 0;
 		mp->logical_size = size;
 		add_to_hash(mp, hash_ptr);
-		if (!absolute)
-			list_add(&mp->inode_list, &JFS_IP(inode)->mp_list);
 		spin_unlock(&meta_lock);
 
 		if (new) {
-			jFYI(1,
-			     ("__get_metapage: Calling grab_cache_page\n"));
+			jfs_info("__get_metapage: Calling grab_cache_page");
 			mp->page = grab_cache_page(mapping, page_index);
 			if (!mp->page) {
-				jERROR(1, ("grab_cache_page failed!\n"));
+				jfs_err("grab_cache_page failed!");
 				goto freeit;
-			} else
+			} else {
 				INCREMENT(mpStat.pagealloc);
+				UnlockPage(mp->page);
+			}
 		} else {
-			jFYI(1,
-			     ("__get_metapage: Calling read_cache_page\n"));
+			jfs_info("__get_metapage: Calling read_cache_page");
 			mp->page = read_cache_page(mapping, lblock,
 				    (filler_t *)mapping->a_ops->readpage, NULL);
 			if (IS_ERR(mp->page)) {
-				jERROR(1, ("read_cache_page failed!\n"));
+				jfs_err("read_cache_page failed!");
 				goto freeit;
 			} else
 				INCREMENT(mpStat.pagealloc);
-			lock_page(mp->page);
 		}
 		mp->data = kmap(mp->page) + page_offset;
 	}
-	jFYI(1, ("__get_metapage: returning = 0x%p\n", mp));
+	jfs_info("__get_metapage: returning = 0x%p", mp);
 	return mp;
 
 freeit:
 	spin_lock(&meta_lock);
 	remove_from_hash(mp, hash_ptr);
-	if (!absolute)
-		list_del(&mp->inode_list);
 	__free_metapage(mp);
 	spin_unlock(&meta_lock);
 	return NULL;
@@ -416,7 +410,7 @@
 	unsigned long page_offset;
 	int rc;
 
-	jFYI(1, ("__write_metapage: mp = 0x%p\n", mp));
+	jfs_info("__write_metapage: mp = 0x%p", mp);
 
 	if (test_bit(META_discard, &mp->flag)) {
 		/*
@@ -430,12 +424,14 @@
 	page_offset =
 	    (mp->index - (page_index << l2BlocksPerPage)) << l2bsize;
 
+	lock_page(mp->page);
 	rc = mp->mapping->a_ops->prepare_write(NULL, mp->page, page_offset,
 					       page_offset +
 					       mp->logical_size);
 	if (rc) {
-		jERROR(1, ("prepare_write return %d!\n", rc));
+		jfs_err("prepare_write return %d!", rc);
 		ClearPageUptodate(mp->page);
+		UnlockPage(mp->page);
 		kunmap(mp->page);
 		clear_bit(META_dirty, &mp->flag);
 		return;
@@ -444,12 +440,13 @@
 					      page_offset +
 					      mp->logical_size);
 	if (rc) {
-		jERROR(1, ("commit_write returned %d\n", rc));
+		jfs_err("commit_write returned %d", rc);
 	}
 
+	UnlockPage(mp->page);
 	clear_bit(META_dirty, &mp->flag);
 
-	jFYI(1, ("__write_metapage done\n"));
+	jfs_info("__write_metapage done");
 }
 
 static inline void sync_metapage(struct metapage *mp)
@@ -473,9 +470,7 @@
 {
 	struct jfs_log *log;
 
-	jFYI(1,
-	     ("release_metapage: mp = 0x%p, flag = 0x%lx\n", mp,
-	      mp->flag));
+	jfs_info("release_metapage: mp = 0x%p, flag = 0x%lx", mp, mp->flag);
 
 	spin_lock(&meta_lock);
 	if (test_bit(META_forced, &mp->flag)) {
@@ -491,8 +486,6 @@
 		spin_unlock(&meta_lock);
 	} else {
 		remove_from_hash(mp, meta_hash(mp->mapping, mp->index));
-		if (!test_bit(META_absolute, &mp->flag))
-			list_del(&mp->inode_list);
 		spin_unlock(&meta_lock);
 
 		if (mp->page) {
@@ -500,7 +493,6 @@
 			mp->data = 0;
 			if (test_bit(META_dirty, &mp->flag))
 				__write_metapage(mp);
-			UnlockPage(mp->page);
 			if (test_bit(META_sync, &mp->flag)) {
 				sync_metapage(mp);
 				clear_bit(META_sync, &mp->flag);
@@ -509,7 +501,7 @@
 			if (test_bit(META_discard, &mp->flag)) {
 				lock_page(mp->page);
 				block_flushpage(mp->page, 0);
-				unlock_page(mp->page);
+				UnlockPage(mp->page);
 			}
 
 			page_cache_release(mp->page);
@@ -532,7 +524,6 @@
 
 		free_metapage(mp);
 	}
-	jFYI(1, ("release_metapage: done\n"));
 }
 
 void __invalidate_metapages(struct inode *ip, s64 addr, int len)
@@ -540,7 +531,8 @@
 	struct metapage **hash_ptr;
 	unsigned long lblock;
 	int l2BlocksPerPage = PAGE_CACHE_SHIFT - ip->i_blkbits;
-	struct address_space *mapping = ip->i_mapping;
+	/* All callers are interested in block device's mapping */
+	struct address_space *mapping = ip->i_sb->s_bdev->bd_inode->i_mapping;
 	struct metapage *mp;
 	struct page *page;
 
@@ -556,10 +548,9 @@
 		if (mp) {
 			set_bit(META_discard, &mp->flag);
 			spin_unlock(&meta_lock);
-			/*
-			 * If in the metapage cache, we've got the page locked
-			 */
+			lock_page(mp->page);
 			block_flushpage(mp->page, 0);
+			UnlockPage(mp->page);
 		} else {
 			spin_unlock(&meta_lock);
 			page = find_lock_page(mapping, lblock>>l2BlocksPerPage);
@@ -571,27 +562,6 @@
 	}
 }
 
-void invalidate_inode_metapages(struct inode *inode)
-{
-	struct list_head *ptr;
-	struct metapage *mp;
-
-	spin_lock(&meta_lock);
-	list_for_each(ptr, &JFS_IP(inode)->mp_list) {
-		mp = list_entry(ptr, struct metapage, inode_list);
-		clear_bit(META_dirty, &mp->flag);
-		set_bit(META_discard, &mp->flag);
-		kunmap(mp->page);
-		UnlockPage(mp->page);
-		page_cache_release(mp->page);
-		INCREMENT(mpStat.pagefree);
-		mp->data = 0;
-		mp->page = 0;
-	}
-	spin_unlock(&meta_lock);
-	truncate_inode_pages(inode->i_mapping, 0);
-}
-
 #ifdef CONFIG_JFS_STATISTICS
 int jfs_mpstat_read(char *buffer, char **start, off_t offset, int length,
 		    int *eof, void *data)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/jfs/jfs_metapage.h linux-2.4.21-pre6/fs/jfs/jfs_metapage.h
--- linux-2.4.20/fs/jfs/jfs_metapage.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/jfs/jfs_metapage.h	2003-03-26 23:49:25.000000000 +0000
@@ -38,7 +38,6 @@
 	struct metapage *hash_prev;
 	struct metapage *hash_next;	/* Also used for free list */
 
-	struct list_head inode_list;	/* per-inode metapage list */
 	/*
 	 * mapping & index become redundant, but we need these here to
 	 * add the metapage to the hash before we have the real page
@@ -109,9 +108,7 @@
 	__invalidate_metapages((ip), addressPXD(&(pxd)), lengthPXD(&(pxd)))
 #define invalidate_dxd_metapages(ip, dxd) \
 	__invalidate_metapages((ip), addressDXD(&(dxd)), lengthDXD(&(dxd)))
+#define invalidate_xad_metapages(ip, xad) \
+	__invalidate_metapages((ip), addressXAD(&(xad)), lengthXAD(&(xad)))
 
-/*
- * This one uses mp_list to invalidate all pages for an inode
- */
-extern void invalidate_inode_metapages(struct inode *inode);
 #endif				/* _H_JFS_METAPAGE */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/jfs/jfs_mount.c linux-2.4.21-pre6/fs/jfs/jfs_mount.c
--- linux-2.4.20/fs/jfs/jfs_mount.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/jfs/jfs_mount.c	2003-03-26 23:49:21.000000000 +0000
@@ -87,8 +87,6 @@
 	struct inode *ipimap = NULL;
 	struct inode *ipbmap = NULL;
 
-	jFYI(1, ("\nMount JFS\n"));
-
 	/*
 	 * read/validate superblock 
 	 * (initialize mount inode from the superblock)
@@ -99,21 +97,19 @@
 
 	ipaimap = diReadSpecial(sb, AGGREGATE_I, 0);
 	if (ipaimap == NULL) {
-		jERROR(1, ("jfs_mount: Faild to read AGGREGATE_I\n"));
+		jfs_err("jfs_mount: Faild to read AGGREGATE_I");
 		rc = EIO;
 		goto errout20;
 	}
 	sbi->ipaimap = ipaimap;
 
-	jFYI(1, ("jfs_mount: ipaimap:0x%p\n", ipaimap));
+	jfs_info("jfs_mount: ipaimap:0x%p", ipaimap);
 
 	/*
 	 * initialize aggregate inode allocation map
 	 */
 	if ((rc = diMount(ipaimap))) {
-		jERROR(1,
-		       ("jfs_mount: diMount(ipaimap) failed w/rc = %d\n",
-			rc));
+		jfs_err("jfs_mount: diMount(ipaimap) failed w/rc = %d", rc);
 		goto errout21;
 	}
 
@@ -126,7 +122,7 @@
 		goto errout22;
 	}
 
-	jFYI(1, ("jfs_mount: ipbmap:0x%p\n", ipbmap));
+	jfs_info("jfs_mount: ipbmap:0x%p", ipbmap);
 
 	sbi->ipbmap = ipbmap;
 
@@ -134,7 +130,7 @@
 	 * initialize aggregate block allocation map
 	 */
 	if ((rc = dbMount(ipbmap))) {
-		jERROR(1, ("jfs_mount: dbMount failed w/rc = %d\n", rc));
+		jfs_err("jfs_mount: dbMount failed w/rc = %d", rc);
 		goto errout22;
 	}
 
@@ -152,22 +148,20 @@
 	if ((sbi->mntflag & JFS_BAD_SAIT) == 0) {
 		ipaimap2 = diReadSpecial(sb, AGGREGATE_I, 1);
 		if (ipaimap2 == 0) {
-			jERROR(1,
-			       ("jfs_mount: Faild to read AGGREGATE_I\n"));
+			jfs_err("jfs_mount: Faild to read AGGREGATE_I");
 			rc = EIO;
 			goto errout35;
 		}
 		sbi->ipaimap2 = ipaimap2;
 
-		jFYI(1, ("jfs_mount: ipaimap2:0x%p\n", ipaimap2));
+		jfs_info("jfs_mount: ipaimap2:0x%p", ipaimap2);
 
 		/*
 		 * initialize secondary aggregate inode allocation map
 		 */
 		if ((rc = diMount(ipaimap2))) {
-			jERROR(1,
-			       ("jfs_mount: diMount(ipaimap2) failed, rc = %d\n",
-				rc));
+			jfs_err("jfs_mount: diMount(ipaimap2) failed, rc = %d",
+				rc);
 			goto errout35;
 		}
 	} else
@@ -182,23 +176,22 @@
 	 */
 	ipimap = diReadSpecial(sb, FILESYSTEM_I, 0);
 	if (ipimap == NULL) {
-		jERROR(1, ("jfs_mount: Failed to read FILESYSTEM_I\n"));
+		jfs_err("jfs_mount: Failed to read FILESYSTEM_I");
 		/* open fileset secondary inode allocation map */
 		rc = EIO;
 		goto errout40;
 	}
-	jFYI(1, ("jfs_mount: ipimap:0x%p\n", ipimap));
+	jfs_info("jfs_mount: ipimap:0x%p", ipimap);
 
 	/* map further access of per fileset inodes by the fileset inode */
 	sbi->ipimap = ipimap;
 
 	/* initialize fileset inode allocation map */
 	if ((rc = diMount(ipimap))) {
-		jERROR(1, ("jfs_mount: diMount failed w/rc = %d\n", rc));
+		jfs_err("jfs_mount: diMount failed w/rc = %d", rc);
 		goto errout41;
 	}
 
-	jFYI(1, ("Mount JFS Complete.\n"));
 	goto out;
 
 	/*
@@ -234,9 +227,9 @@
 
       out:
 
-	if (rc) {
-		jERROR(1, ("Mount JFS Failure: %d\n", rc));
-	}
+	if (rc)
+		jfs_err("Mount JFS Failure: %d", rc);
+
 	return rc;
 }
 
@@ -265,13 +258,13 @@
 		truncate_inode_pages(sbi->ipbmap->i_mapping, 0);
 		diUnmount(sbi->ipimap, 1);
 		if ((rc = diMount(sbi->ipimap))) {
-			jERROR(1,("jfs_mount_rw: diMount failed!\n"));
+			jfs_err("jfs_mount_rw: diMount failed!");
 			return rc;
 		}
 
 		dbUnmount(sbi->ipbmap, 1);
 		if ((rc = dbMount(sbi->ipbmap))) {
-			jERROR(1,("jfs_mount_rw: dbMount failed!\n"));
+			jfs_err("jfs_mount_rw: dbMount failed!");
 			return rc;
 		}
 	}
@@ -288,8 +281,7 @@
 	 * update file system superblock;
 	 */
 	if ((rc = updateSuper(sb, FM_MOUNT))) {
-		jERROR(1,
-		       ("jfs_mount: updateSuper failed w/rc = %d\n", rc));
+		jfs_err("jfs_mount: updateSuper failed w/rc = %d", rc);
 		lmLogClose(sb, log);
 		JFS_SBI(sb)->log = 0;
 		return rc;
@@ -343,15 +335,15 @@
 	bsize = le32_to_cpu(j_sb->s_bsize);
 #ifdef _JFS_4K
 	if (bsize != PSIZE) {
-		jERROR(1, ("Currently only 4K block size supported!\n"));
+		jfs_err("Currently only 4K block size supported!");
 		rc = EINVAL;
 		goto out;
 	}
 #endif				/* _JFS_4K */
 
-	jFYI(1, ("superblock: flag:0x%08x state:0x%08x size:0x%Lx\n",
+	jfs_info("superblock: flag:0x%08x state:0x%08x size:0x%Lx",
 		 le32_to_cpu(j_sb->s_flag), le32_to_cpu(j_sb->s_state),
-		 (unsigned long long) le64_to_cpu(j_sb->s_size)));
+		 (unsigned long long) le64_to_cpu(j_sb->s_size));
 
 	/* validate the descriptors for Secondary AIM and AIT */
 	if ((j_sb->s_flag & cpu_to_le32(JFS_BAD_SAIT)) !=
@@ -375,15 +367,11 @@
 	if ((j_sb->s_flag & cpu_to_le32(JFS_GROUPCOMMIT)) !=
 	    cpu_to_le32(JFS_GROUPCOMMIT))
 		j_sb->s_flag |= cpu_to_le32(JFS_GROUPCOMMIT);
-	jFYI(0, ("superblock: flag:0x%08x state:0x%08x size:0x%Lx\n",
-		 le32_to_cpu(j_sb->s_flag), le32_to_cpu(j_sb->s_state),
-		 (unsigned long long) le64_to_cpu(j_sb->s_size)));
 
 	/* validate fs state */
 	if (j_sb->s_state != cpu_to_le32(FM_CLEAN) &&
 	    !(sb->s_flags & MS_RDONLY)) {
-		jERROR(1,
-		       ("jfs_mount: Mount Failure: File System Dirty.\n"));
+		jfs_err("jfs_mount: Mount Failure: File System Dirty.");
 		rc = EINVAL;
 		goto out;
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/jfs/jfs_txnmgr.c linux-2.4.21-pre6/fs/jfs/jfs_txnmgr.c
--- linux-2.4.20/fs/jfs/jfs_txnmgr.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/jfs/jfs_txnmgr.c	2003-03-26 23:49:19.000000000 +0000
@@ -69,6 +69,7 @@
 	wait_queue_head_t freelockwait;	/* eventlist of free tlock */
 	wait_queue_head_t lowlockwait;	/* eventlist of ample tlocks */
 	int tlocksInUse;	/* Number of tlocks in use */
+	int TlocksLow;		/* Indicates low number of available tlocks */
 	spinlock_t LazyLock;	/* synchronize sync_queue & unlock_queue */
 /*	struct tblock *sync_queue; * Transactions waiting for data sync */
 	struct tblock *unlock_queue;	/* Txns waiting to be released */
@@ -78,6 +79,20 @@
 					   that couldn't be sync'ed */
 } TxAnchor;
 
+#ifdef CONFIG_JFS_STATISTICS
+struct {
+	uint txBegin;
+	uint txBegin_barrier;
+	uint txBegin_lockslow;
+	uint txBegin_freetid;
+	uint txBeginAnon;
+	uint txBeginAnon_barrier;
+	uint txBeginAnon_lockslow;
+	uint txLockAlloc;
+	uint txLockAlloc_freelock;
+} TxStat;
+#endif
+
 static int nTxBlock = 512;	/* number of transaction blocks */
 struct tblock *TxBlock;	        /* transaction block table */
 
@@ -85,7 +100,6 @@
 static int TxLockLWM = 4096*.4;	/* Low water mark for number of txLocks used */
 static int TxLockHWM = 4096*.8;	/* High water mark for number of txLocks used */
 struct tlock *TxLock;           /* transaction lock table */
-static int TlocksLow = 0;	/* Indicates low number of available tlocks */
 
 
 /*
@@ -142,7 +156,7 @@
 /*
  * external references
  */
-extern int lmGroupCommit(struct jfs_log * log, struct tblock * tblk);
+extern int lmGroupCommit(struct jfs_log *, struct tblock *);
 extern void lmSync(struct jfs_log *);
 extern int jfs_commit_inode(struct inode *, int);
 extern int jfs_stop_threads;
@@ -189,13 +203,18 @@
 {
 	lid_t lid;
 
+	INCREMENT(TxStat.txLockAlloc);
+	if (!TxAnchor.freelock) {
+		INCREMENT(TxStat.txLockAlloc_freelock);
+	}
+
 	while (!(lid = TxAnchor.freelock))
 		TXN_SLEEP(&TxAnchor.freelockwait);
 	TxAnchor.freelock = TxLock[lid].next;
 	HIGHWATERMARK(stattx.maxlid, lid);
-	if ((++TxAnchor.tlocksInUse > TxLockHWM) && (TlocksLow == 0)) {
-		jEVENT(0,("txLockAlloc TlocksLow\n"));
-		TlocksLow = 1;
+	if ((++TxAnchor.tlocksInUse > TxLockHWM) && (TxAnchor.TlocksLow == 0)) {
+		jfs_info("txLockAlloc TlocksLow");
+		TxAnchor.TlocksLow = 1;
 		wake_up(&jfs_sync_thread_wait);
 	}
 
@@ -207,9 +226,9 @@
 	TxLock[lid].next = TxAnchor.freelock;
 	TxAnchor.freelock = lid;
 	TxAnchor.tlocksInUse--;
-	if (TlocksLow && (TxAnchor.tlocksInUse < TxLockLWM)) {
-		jEVENT(0,("txLockFree TlocksLow no more\n"));
-		TlocksLow = 0;
+	if (TxAnchor.TlocksLow && (TxAnchor.tlocksInUse < TxLockLWM)) {
+		jfs_info("txLockFree TlocksLow no more");
+		TxAnchor.TlocksLow = 0;
 		TXN_WAKEUP(&TxAnchor.lowlockwait);
 	}
 	TXN_WAKEUP(&TxAnchor.freelockwait);
@@ -316,11 +335,13 @@
 	struct tblock *tblk;
 	struct jfs_log *log;
 
-	jFYI(1, ("txBegin: flag = 0x%x\n", flag));
+	jfs_info("txBegin: flag = 0x%x", flag);
 	log = JFS_SBI(sb)->log;
 
 	TXN_LOCK();
 
+	INCREMENT(TxStat.txBegin);
+
       retry:
 	if (!(flag & COMMIT_FORCE)) {
 		/*
@@ -328,6 +349,7 @@
 		 */
 		if (test_bit(log_SYNCBARRIER, &log->flag) ||
 		    test_bit(log_QUIESCE, &log->flag)) {
+			INCREMENT(TxStat.txBegin_barrier);
 			TXN_SLEEP(&log->syncwait);
 			goto retry;
 		}
@@ -338,7 +360,8 @@
 		 * unless COMMIT_FORCE or COMMIT_INODE (which may ultimately
 		 * free tlocks)
 		 */
-		if (TlocksLow) {
+		if (TxAnchor.TlocksLow) {
+			INCREMENT(TxStat.txBegin_lockslow);
 			TXN_SLEEP(&TxAnchor.lowlockwait);
 			goto retry;
 		}
@@ -348,16 +371,18 @@
 	 * allocate transaction id/block
 	 */
 	if ((t = TxAnchor.freetid) == 0) {
-		jFYI(1, ("txBegin: waiting for free tid\n"));
+		jfs_info("txBegin: waiting for free tid");
+		INCREMENT(TxStat.txBegin_freetid);
 		TXN_SLEEP(&TxAnchor.freewait);
 		goto retry;
 	}
 
 	tblk = tid_to_tblock(t);
 
-	if ((tblk->next == 0) && (current != jfsCommitTask)) {
-		/* Save one tblk for jfsCommit thread */
-		jFYI(1, ("txBegin: waiting for free tid\n"));
+	if ((tblk->next == 0) && !(flag & COMMIT_FORCE)) {
+		/* Don't let a non-forced transaction take the last tblk */
+		jfs_info("txBegin: waiting for free tid");
+		INCREMENT(TxStat.txBegin_freetid);
 		TXN_SLEEP(&TxAnchor.freewait);
 		goto retry;
 	}
@@ -387,7 +412,7 @@
 
 	TXN_UNLOCK();
 
-	jFYI(1, ("txBegin: returning tid = %d\n", t));
+	jfs_info("txBegin: returning tid = %d", t);
 
 	return t;
 }
@@ -411,6 +436,7 @@
 	log = JFS_SBI(sb)->log;
 
 	TXN_LOCK();
+	INCREMENT(TxStat.txBeginAnon);
 
       retry:
 	/*
@@ -418,6 +444,7 @@
 	 */
 	if (test_bit(log_SYNCBARRIER, &log->flag) ||
 	    test_bit(log_QUIESCE, &log->flag)) {
+		INCREMENT(TxStat.txBeginAnon_barrier);
 		TXN_SLEEP(&log->syncwait);
 		goto retry;
 	}
@@ -425,7 +452,8 @@
 	/*
 	 * Don't begin transaction if we're getting starved for tlocks
 	 */
-	if (TlocksLow) {
+	if (TxAnchor.TlocksLow) {
+		INCREMENT(TxStat.txBeginAnon_lockslow);
 		TXN_SLEEP(&TxAnchor.lowlockwait);
 		goto retry;
 	}
@@ -447,7 +475,7 @@
 	struct tblock *tblk = tid_to_tblock(tid);
 	struct jfs_log *log;
 
-	jFYI(1, ("txEnd: tid = %d\n", tid));
+	jfs_info("txEnd: tid = %d", tid);
 	TXN_LOCK();
 
 	/*
@@ -467,9 +495,7 @@
 	 * routine.
 	 */
 	if (tblk->flag & tblkGC_LAZY) {
-		jFYI(1,
-		     ("txEnd called w/lazy tid: %d, tblk = 0x%p\n",
-		      tid, tblk));
+		jfs_info("txEnd called w/lazy tid: %d, tblk = 0x%p", tid, tblk);
 		TXN_UNLOCK();
 
 		spin_lock_irq(&log->gclock);	// LOGGC_LOCK
@@ -478,7 +504,7 @@
 		return;
 	}
 
-	jFYI(1, ("txEnd: tid: %d, tblk = 0x%p\n", tid, tblk));
+	jfs_info("txEnd: tid: %d, tblk = 0x%p", tid, tblk);
 
 	assert(tblk->next == 0);
 
@@ -491,22 +517,24 @@
 	/*
 	 * mark the tblock not active
 	 */
-	--log->active;
+	if (--log->active == 0) {
+		clear_bit(log_FLUSH, &log->flag);
 
-	/*
-	 * synchronize with logsync barrier
-	 */
-	if (test_bit(log_SYNCBARRIER, &log->flag) && log->active == 0) {
-		/* forward log syncpt */
-		/* lmSync(log); */
+		/*
+		 * synchronize with logsync barrier
+		 */
+		if (test_bit(log_SYNCBARRIER, &log->flag)) {
+			/* forward log syncpt */
+			/* lmSync(log); */
 
-		jFYI(1, ("     log barrier off: 0x%x\n", log->lsn));
+			jfs_info("log barrier off: 0x%x", log->lsn);
 
-		/* enable new transactions start */
-		clear_bit(log_SYNCBARRIER, &log->flag);
+			/* enable new transactions start */
+			clear_bit(log_SYNCBARRIER, &log->flag);
 
-		/* wakeup all waitors for logsync barrier */
-		TXN_WAKEUP(&log->syncwait);
+			/* wakeup all waitors for logsync barrier */
+			TXN_WAKEUP(&log->syncwait);
+		}
 	}
 
 	/*
@@ -515,7 +543,6 @@
 	TXN_WAKEUP(&TxAnchor.freewait);
 
 	TXN_UNLOCK();
-	jFYI(1, ("txEnd: exitting\n"));
 }
 
 
@@ -562,8 +589,7 @@
 	if (lid == 0)
 		goto allocateLock;
 
-	jFYI(1, ("txLock: tid:%d ip:0x%p mp:0x%p lid:%d\n",
-		 tid, ip, mp, lid));
+	jfs_info("txLock: tid:%d ip:0x%p mp:0x%p lid:%d", tid, ip, mp, lid);
 
 	/* is page locked by the requester transaction ? */
 	tlck = lid_to_tlock(lid);
@@ -649,9 +675,8 @@
 		mark_metapage_dirty(mp);
 		atomic_inc(&mp->nohomeok);
 
-		jFYI(1,
-		     ("locking mp = 0x%p, nohomeok = %d tid = %d tlck = 0x%p\n",
-		      mp, atomic_read(&mp->nohomeok), tid, tlck));
+		jfs_info("locking mp = 0x%p, nohomeok = %d tid = %d tlck = 0x%p",
+			 mp, atomic_read(&mp->nohomeok), tid, tlck);
 
 		/* if anonymous transaction, and buffer is on the group
 		 * commit synclist, mark inode to show this.  This will
@@ -747,7 +772,7 @@
 		break;
 
 	default:
-		jERROR(1, ("UFO tlock:0x%p\n", tlck));
+		jfs_err("UFO tlock:0x%p", tlck);
 	}
 
 	/*
@@ -767,7 +792,7 @@
 	/* Only locks on ipimap or ipaimap should reach here */
 	/* assert(jfs_ip->fileset == AGGREGATE_I); */
 	if (jfs_ip->fileset != AGGREGATE_I) {
-		jERROR(1, ("txLock: trying to lock locked page!\n"));
+		jfs_err("txLock: trying to lock locked page!");
 		dump_mem("ip", ip, sizeof(struct inode));
 		dump_mem("mp", mp, sizeof(struct metapage));
 		dump_mem("Locker's tblk", tid_to_tblock(tid),
@@ -778,10 +803,10 @@
 	INCREMENT(stattx.waitlock);	/* statistics */
 	release_metapage(mp);
 
-	jEVENT(0, ("txLock: in waitLock, tid = %d, xtid = %d, lid = %d\n",
-		   tid, xtid, lid));
+	jfs_info("txLock: in waitLock, tid = %d, xtid = %d, lid = %d",
+		 tid, xtid, lid);
 	TXN_SLEEP_DROP_LOCK(&tid_to_tblock(xtid)->waitor);
-	jEVENT(0, ("txLock: awakened     tid = %d, lid = %d\n", tid, lid));
+	jfs_info("txLock: awakened     tid = %d, lid = %d", tid, lid);
 
 	return NULL;
 }
@@ -842,7 +867,7 @@
 	struct jfs_log *log;
 	int difft, diffp;
 
-	jFYI(1, ("txUnlock: tblk = 0x%p\n", tblk));
+	jfs_info("txUnlock: tblk = 0x%p", tblk);
 	log = JFS_SBI(tblk->sb)->log;
 
 	/*
@@ -852,7 +877,7 @@
 		tlck = lid_to_tlock(lid);
 		next = tlck->next;
 
-		jFYI(1, ("unlocking lid = %d, tlck = 0x%p\n", lid, tlck));
+		jfs_info("unlocking lid = %d, tlck = 0x%p", lid, tlck);
 
 		/* unbind page from tlock */
 		if ((mp = tlck->mp) != NULL &&
@@ -1086,7 +1111,7 @@
 	ino_t top;
 	struct super_block *sb;
 
-	jFYI(1, ("txCommit, tid = %d, flag = %d\n", tid, flag));
+	jfs_info("txCommit, tid = %d, flag = %d", tid, flag);
 	/* is read-only file system ? */
 	if (isReadOnly(iplist[0])) {
 		rc = EROFS;
@@ -1272,7 +1297,7 @@
 		rc = rc1;
 
       TheEnd:
-	jFYI(1, ("txCommit: tid = %d, returning %d\n", tid, rc));
+	jfs_info("txCommit: tid = %d, returning %d", tid, rc);
 	return rc;
 }
 
@@ -1336,7 +1361,7 @@
 			break;
 
 		default:
-			jERROR(1, ("UFO tlock:0x%p\n", tlck));
+			jfs_err("UFO tlock:0x%p", tlck);
 		}
 		if (tlck->mp)
 			release_metapage(tlck->mp);
@@ -1422,9 +1447,8 @@
 
 		/* mark page as homeward bound */
 		tlck->flag |= tlckWRITEPAGE;
-	} else {
-		jERROR(2, ("diLog: UFO type tlck:0x%p\n", tlck));
-	}
+	} else
+		jfs_err("diLog: UFO type tlck:0x%p", tlck);
 #ifdef  _JFS_WIP
 	/*
 	 *      alloc/free external EA extent
@@ -1473,10 +1497,6 @@
 {
 	struct metapage *mp;
 	pxd_t *pxd;
-	int rc;
-	s64 xaddr;
-	int xflag;
-	s32 xlen;
 
 	mp = tlck->mp;
 
@@ -1501,13 +1521,7 @@
 		return 0;
 	}
 
-	rc = xtLookup(tlck->ip, mp->index, 1, &xflag, &xaddr, &xlen, 1);
-	if (rc || (xlen == 0)) {
-		jERROR(1, ("dataLog: can't find physical address\n"));
-		return 0;
-	}
-
-	PXDaddress(pxd, xaddr);
+	PXDaddress(pxd, mp->index);
 	PXDlength(pxd, mp->logical_size >> tblk->sb->s_blocksize_bits);
 
 	lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, tlck));
@@ -1527,12 +1541,10 @@
 void dtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
 	   struct tlock * tlck)
 {
-	struct inode *ip;
 	struct metapage *mp;
 	struct pxd_lock *pxdlock;
 	pxd_t *pxd;
 
-	ip = tlck->ip;
 	mp = tlck->mp;
 
 	/* initialize as REDOPAGE/NOREDOPAGE record format */
@@ -1724,9 +1736,8 @@
 			xadlock->xdlist = &p->xad[lwm];
 			tblk->xflag &= ~COMMIT_LAZY;
 		}
-		jFYI(1,
-		     ("xtLog: alloc ip:0x%p mp:0x%p tlck:0x%p lwm:%d count:%d\n",
-		      tlck->ip, mp, tlck, lwm, xadlock->count));
+		jfs_info("xtLog: alloc ip:0x%p mp:0x%p tlck:0x%p lwm:%d "
+			 "count:%d", tlck->ip, mp, tlck, lwm, xadlock->count);
 
 		maplock->index = 1;
 
@@ -1813,22 +1824,13 @@
 		} else {
 			/*
 			 * xdlist will point to into inode's xtree, ensure
-			 * that transaction is not committed lazily unless
-			 * we're deleting the inode (unlink).  In that case
-			 * we have special logic for the inode to be
-			 * unlocked by the lazy commit thread.
+			 * that transaction is not committed lazily.
 			 */
 			xadlock->xdlist = &p->xad[XTENTRYSTART];
-			if ((tblk->xflag & COMMIT_LAZY) &&
-			    (tblk->xflag & COMMIT_DELETE) &&
-			    (tblk->ip == ip))
-				set_cflag(COMMIT_Holdlock, ip);
-			else
-				tblk->xflag &= ~COMMIT_LAZY;
+			tblk->xflag &= ~COMMIT_LAZY;
 		}
-		jFYI(1,
-		     ("xtLog: free ip:0x%p mp:0x%p count:%d lwm:2\n",
-		      tlck->ip, mp, xadlock->count));
+		jfs_info("xtLog: free ip:0x%p mp:0x%p count:%d lwm:2",
+			 tlck->ip, mp, xadlock->count);
 
 		maplock->index = 1;
 
@@ -1956,9 +1958,9 @@
 			xadlock->count = next - lwm;
 			xadlock->xdlist = &p->xad[lwm];
 
-			jFYI(1,
-			     ("xtLog: alloc ip:0x%p mp:0x%p count:%d lwm:%d next:%d\n",
-			      tlck->ip, mp, xadlock->count, lwm, next));
+			jfs_info("xtLog: alloc ip:0x%p mp:0x%p count:%d "
+				 "lwm:%d next:%d",
+				 tlck->ip, mp, xadlock->count, lwm, next);
 			maplock->index++;
 			xadlock++;
 		}
@@ -1980,9 +1982,8 @@
 			pxdlock->count = 1;
 			pxdlock->pxd = tpxd;
 
-			jFYI(1,
-			     ("xtLog: truncate ip:0x%p mp:0x%p count:%d hwm:%d\n",
-			      ip, mp, pxdlock->count, hwm));
+			jfs_info("xtLog: truncate ip:0x%p mp:0x%p count:%d "
+				 "hwm:%d", ip, mp, pxdlock->count, hwm);
 			maplock->index++;
 			xadlock++;
 		}
@@ -2000,9 +2001,9 @@
 			xadlock->count = hwm - next + 1;
 			xadlock->xdlist = &p->xad[next];
 
-			jFYI(1,
-			     ("xtLog: free ip:0x%p mp:0x%p count:%d next:%d hwm:%d\n",
-			      tlck->ip, mp, xadlock->count, next, hwm));
+			jfs_info("xtLog: free ip:0x%p mp:0x%p count:%d "
+				 "next:%d hwm:%d",
+				 tlck->ip, mp, xadlock->count, next, hwm);
 			maplock->index++;
 		}
 
@@ -2089,9 +2090,9 @@
 			lrd->log.updatemap.pxd = pxdlock->pxd;
 			lrd->backchain =
 			    cpu_to_le32(lmLog(log, tblk, lrd, NULL));
-			jFYI(1, ("mapLog: xaddr:0x%lx xlen:0x%x\n",
+			jfs_info("mapLog: xaddr:0x%lx xlen:0x%x",
 				 (ulong) addressPXD(&pxdlock->pxd),
-				 lengthPXD(&pxdlock->pxd)));
+				 lengthPXD(&pxdlock->pxd));
 		}
 
 		/* update bmap */
@@ -2197,9 +2198,21 @@
 				tlck->flag &= ~tlckWRITEPAGE;
 
 				/* do not release page to freelist */
+
+				/*
+				 * The "right" thing to do here is to
+				 * synchronously write the metadata.
+				 * With the current implementation this
+				 * is hard since write_metapage requires
+				 * us to kunmap & remap the page.  If we
+				 * have tlocks pointing into the metadata
+				 * pages, we don't want to do this.  I think
+				 * we can get by with synchronously writing
+				 * the pages when they are released.
+				 */
 				assert(atomic_read(&mp->nohomeok));
-				hold_metapage(mp, 0);
-				write_metapage(mp);
+				set_bit(META_dirty, &mp->flag);
+				set_bit(META_sync, &mp->flag);
 			}
 		}
 	}
@@ -2344,10 +2357,6 @@
 		ip = tblk->ip;
 		diUpdatePMap(ipimap, ip->i_ino, TRUE, tblk);
 		ipimap->i_state |= I_DIRTY;
-		if (test_and_clear_cflag(COMMIT_Holdlock, ip)) {
-			if (tblk->flag & tblkGC_LAZY)
-				IWRITE_UNLOCK(ip);
-		}
 		iput(ip);
 	}
 }
@@ -2399,9 +2408,8 @@
 				dbUpdatePMap(ipbmap, FALSE, xaddr,
 					     (s64) xlen, tblk);
 				xad->flag &= ~(XAD_NEW | XAD_EXTENDED);
-				jFYI(1,
-				     ("allocPMap: xaddr:0x%lx xlen:%d\n",
-				      (ulong) xaddr, xlen));
+				jfs_info("allocPMap: xaddr:0x%lx xlen:%d",
+					 (ulong) xaddr, xlen);
 			}
 		}
 	} else if (maplock->flag & mlckALLOCPXD) {
@@ -2409,9 +2417,7 @@
 		xaddr = addressPXD(&pxdlock->pxd);
 		xlen = lengthPXD(&pxdlock->pxd);
 		dbUpdatePMap(ipbmap, FALSE, xaddr, (s64) xlen, tblk);
-		jFYI(1,
-		     ("allocPMap: xaddr:0x%lx xlen:%d\n", (ulong) xaddr,
-		      xlen));
+		jfs_info("allocPMap: xaddr:0x%lx xlen:%d", (ulong) xaddr, xlen);
 	} else {		/* (maplock->flag & mlckALLOCPXDLIST) */
 
 		pxdlistlock = (struct xdlistlock *) maplock;
@@ -2421,9 +2427,8 @@
 			xlen = lengthPXD(pxd);
 			dbUpdatePMap(ipbmap, FALSE, xaddr, (s64) xlen,
 				     tblk);
-			jFYI(1,
-			     ("allocPMap: xaddr:0x%lx xlen:%d\n",
-			      (ulong) xaddr, xlen));
+			jfs_info("allocPMap: xaddr:0x%lx xlen:%d",
+				 (ulong) xaddr, xlen);
 		}
 	}
 }
@@ -2449,9 +2454,8 @@
 	pxd_t *pxd;
 	int n;
 
-	jFYI(1,
-	     ("txFreeMap: tblk:0x%p maplock:0x%p maptype:0x%x\n",
-	      tblk, maplock, maptype));
+	jfs_info("txFreeMap: tblk:0x%p maplock:0x%p maptype:0x%x",
+		 tblk, maplock, maptype);
 
 	/*
 	 * free from persistent map;
@@ -2466,9 +2470,9 @@
 					xlen = lengthXAD(xad);
 					dbUpdatePMap(ipbmap, TRUE, xaddr,
 						     (s64) xlen, tblk);
-					jFYI(1,
-					     ("freePMap: xaddr:0x%lx xlen:%d\n",
-					      (ulong) xaddr, xlen));
+					jfs_info("freePMap: xaddr:0x%lx "
+						 "xlen:%d",
+						 (ulong) xaddr, xlen);
 				}
 			}
 		} else if (maplock->flag & mlckFREEPXD) {
@@ -2477,9 +2481,8 @@
 			xlen = lengthPXD(&pxdlock->pxd);
 			dbUpdatePMap(ipbmap, TRUE, xaddr, (s64) xlen,
 				     tblk);
-			jFYI(1,
-			     ("freePMap: xaddr:0x%lx xlen:%d\n",
-			      (ulong) xaddr, xlen));
+			jfs_info("freePMap: xaddr:0x%lx xlen:%d",
+				 (ulong) xaddr, xlen);
 		} else {	/* (maplock->flag & mlckALLOCPXDLIST) */
 
 			pxdlistlock = (struct xdlistlock *) maplock;
@@ -2489,9 +2492,8 @@
 				xlen = lengthPXD(pxd);
 				dbUpdatePMap(ipbmap, TRUE, xaddr,
 					     (s64) xlen, tblk);
-				jFYI(1,
-				     ("freePMap: xaddr:0x%lx xlen:%d\n",
-				      (ulong) xaddr, xlen));
+				jfs_info("freePMap: xaddr:0x%lx xlen:%d",
+					 (ulong) xaddr, xlen);
 			}
 		}
 	}
@@ -2508,18 +2510,16 @@
 				xlen = lengthXAD(xad);
 				dbFree(ip, xaddr, (s64) xlen);
 				xad->flag = 0;
-				jFYI(1,
-				     ("freeWMap: xaddr:0x%lx xlen:%d\n",
-				      (ulong) xaddr, xlen));
+				jfs_info("freeWMap: xaddr:0x%lx xlen:%d",
+					 (ulong) xaddr, xlen);
 			}
 		} else if (maplock->flag & mlckFREEPXD) {
 			pxdlock = (struct pxd_lock *) maplock;
 			xaddr = addressPXD(&pxdlock->pxd);
 			xlen = lengthPXD(&pxdlock->pxd);
 			dbFree(ip, xaddr, (s64) xlen);
-			jFYI(1,
-			     ("freeWMap: xaddr:0x%lx xlen:%d\n",
-			      (ulong) xaddr, xlen));
+			jfs_info("freeWMap: xaddr:0x%lx xlen:%d",
+				 (ulong) xaddr, xlen);
 		} else {	/* (maplock->flag & mlckFREEPXDLIST) */
 
 			pxdlistlock = (struct xdlistlock *) maplock;
@@ -2528,9 +2528,8 @@
 				xaddr = addressPXD(pxd);
 				xlen = lengthPXD(pxd);
 				dbFree(ip, xaddr, (s64) xlen);
-				jFYI(1,
-				     ("freeWMap: xaddr:0x%lx xlen:%d\n",
-				      (ulong) xaddr, xlen));
+				jfs_info("freeWMap: xaddr:0x%lx xlen:%d",
+					 (ulong) xaddr, xlen);
 			}
 		}
 	}
@@ -2595,7 +2594,7 @@
 	struct metapage *mp;
 	struct tblock *tblk = tid_to_tblock(tid);
 
-	jEVENT(1, ("txAbort: tid:%d dirty:0x%x\n", tid, dirty));
+	jfs_warn("txAbort: tid:%d dirty:0x%x", tid, dirty);
 
 	/*
 	 * free tlocks of the transaction
@@ -2658,7 +2657,7 @@
 	struct metapage *mp;
 
 	assert(exval == EIO || exval == ENOMEM);
-	jEVENT(1, ("txAbortCommit: cd:0x%p\n", cd));
+	jfs_warn("txAbortCommit: cd:0x%p", cd);
 
 	/*
 	 * free tlocks of the transaction
@@ -2713,11 +2712,11 @@
 	       ((tblk->flag & tblkGC_UNLOCKED) == 0)) {
 		/* We must have gotten ahead of the user thread
 		 */
-		jFYI(1, ("txLazyCommit: tblk 0x%p not unlocked\n", tblk));
+		jfs_info("txLazyCommit: tblk 0x%p not unlocked", tblk);
 		schedule();
 	}
 
-	jFYI(1, ("txLazyCommit: processing tblk 0x%p\n", tblk));
+	jfs_info("txLazyCommit: processing tblk 0x%p", tblk);
 
 	txUpdateMap(tblk);
 
@@ -2727,11 +2726,10 @@
 
 	tblk->flag |= tblkGC_COMMITTED;
 
-	if ((tblk->flag & tblkGC_READY) || (tblk->flag & tblkGC_LAZY))
+	if (tblk->flag & tblkGC_READY)
 		log->gcrtc--;
 
-	if (tblk->flag & tblkGC_READY)
-		wake_up(&tblk->gcwait);	// LOGGC_WAKEUP
+	wake_up_all(&tblk->gcwait);	// LOGGC_WAKEUP
 
 	/*
 	 * Can't release log->gclock until we've tested tblk->flag
@@ -2744,7 +2742,7 @@
 	} else
 		spin_unlock_irq(&log->gclock);	// LOGGC_UNLOCK
 
-	jFYI(1, ("txLazyCommit: done: tblk = 0x%p\n", tblk));
+	jfs_info("txLazyCommit: done: tblk = 0x%p", tblk);
 }
 
 /*
@@ -2826,9 +2824,9 @@
 	} while (!jfs_stop_threads);
 
 	if (TxAnchor.unlock_queue)
-		jERROR(1, ("jfs_lazycommit being killed with pending transactions!\n"));
+		jfs_err("jfs_lazycommit being killed w/pending transactions!");
 	else
-		jFYI(1, ("jfs_lazycommit being killed\n"));
+		jfs_info("jfs_lazycommit being killed\n");
 	complete(&jfsIOwait);
 	return 0;
 }
@@ -2888,7 +2886,6 @@
 	struct inode *ip;
 	struct jfs_inode_info *jfs_ip;
 	struct jfs_log *log = JFS_SBI(sb)->log;
-	int rc;
 	tid_t tid;
 
 	set_bit(log_QUIESCE, &log->flag);
@@ -2908,7 +2905,7 @@
 		TXN_UNLOCK();
 		tid = txBegin(ip->i_sb, COMMIT_INODE | COMMIT_FORCE);
 		down(&jfs_ip->commit_sem);
-		rc = txCommit(tid, 1, &ip, 0);
+		txCommit(tid, 1, &ip, 0);
 		txEnd(tid);
 		up(&jfs_ip->commit_sem);
 		/*
@@ -2929,6 +2926,11 @@
 		goto restart;
 	}
 	TXN_UNLOCK();
+
+	/*
+	 * We may need to kick off the group commit
+	 */
+	jfs_flush_journal(log, 0);
 }
 
 /*
@@ -2979,7 +2981,7 @@
 		 * write each inode on the anonymous inode list
 		 */
 		TXN_LOCK();
-		while (TlocksLow && !list_empty(&TxAnchor.anon_list)) {
+		while (TxAnchor.TlocksLow && !list_empty(&TxAnchor.anon_list)) {
 			jfs_ip = list_entry(TxAnchor.anon_list.next,
 					    struct jfs_inode_info,
 					    anon_inode_list);
@@ -2995,8 +2997,7 @@
 				 * when it is committed
 				 */
 				TXN_UNLOCK();
-				tid = txBegin(ip->i_sb,
-					      COMMIT_INODE | COMMIT_FORCE);
+				tid = txBegin(ip->i_sb, COMMIT_INODE);
 				rc = txCommit(tid, 1, &ip, 0);
 				txEnd(tid);
 				up(&jfs_ip->commit_sem);
@@ -3034,7 +3035,7 @@
 		remove_wait_queue(&jfs_sync_thread_wait, &wq);
 	} while (!jfs_stop_threads);
 
-	jFYI(1, ("jfs_sync being killed\n"));
+	jfs_info("jfs_sync being killed");
 	complete(&jfsIOwait);
 	return 0;
 }
@@ -3065,6 +3066,7 @@
 		       "freelockwait = %s\n"
 		       "lowlockwait = %s\n"
 		       "tlocksInUse = %d\n"
+		       "TlocksLow = %d\n"
 		       "unlock_queue = 0x%p\n"
 		       "unlock_tail = 0x%p\n",
 		       TxAnchor.freetid,
@@ -3073,6 +3075,7 @@
 		       freelockwait,
 		       lowlockwait,
 		       TxAnchor.tlocksInUse,
+		       TxAnchor.TlocksLow,
 		       TxAnchor.unlock_queue,
 		       TxAnchor.unlock_tail);
 
@@ -3091,3 +3094,48 @@
 	return len;
 }
 #endif
+
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_JFS_STATISTICS)
+int jfs_txstats_read(char *buffer, char **start, off_t offset, int length,
+		     int *eof, void *data)
+{
+	int len = 0;
+	off_t begin;
+
+	len += sprintf(buffer,
+		       "JFS TxStats\n"
+		       "===========\n"
+		       "calls to txBegin = %d\n"
+		       "txBegin blocked by sync barrier = %d\n"
+		       "txBegin blocked by tlocks low = %d\n"
+		       "txBegin blocked by no free tid = %d\n"
+		       "calls to txBeginAnon = %d\n"
+		       "txBeginAnon blocked by sync barrier = %d\n"
+		       "txBeginAnon blocked by tlocks low = %d\n"
+		       "calls to txLockAlloc = %d\n"
+		       "tLockAlloc blocked by no free lock = %d\n",
+		       TxStat.txBegin,
+		       TxStat.txBegin_barrier,
+		       TxStat.txBegin_lockslow,
+		       TxStat.txBegin_freetid,
+		       TxStat.txBeginAnon,
+		       TxStat.txBeginAnon_barrier,
+		       TxStat.txBeginAnon_lockslow,
+		       TxStat.txLockAlloc,
+		       TxStat.txLockAlloc_freelock);
+
+	begin = offset;
+	*start = buffer + begin;
+	len -= begin;
+
+	if (len > length)
+		len = length;
+	else
+		*eof = 1;
+
+	if (len < 0)
+		len = 0;
+
+	return len;
+}
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/jfs/jfs_umount.c linux-2.4.21-pre6/fs/jfs/jfs_umount.c
--- linux-2.4.20/fs/jfs/jfs_umount.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/jfs/jfs_umount.c	2003-03-26 23:49:50.000000000 +0000
@@ -57,7 +57,7 @@
 	struct jfs_log *log;
 	int rc = 0;
 
-	jFYI(1, ("\n	UnMount JFS: sb:0x%p\n", sb));
+	jfs_info("UnMount JFS: sb:0x%p", sb);
 
 	/*
 	 *      update superblock and close log 
@@ -68,12 +68,11 @@
 		/*
 		 * Wait for outstanding transactions to be written to log: 
 		 */
-		lmLogWait(log);
+		jfs_flush_journal(log, 2);
 
 	/*
 	 * close fileset inode allocation map (aka fileset inode)
 	 */
-	jEVENT(0, ("jfs_umount: close ipimap:0x%p\n", ipimap));
 	diUnmount(ipimap, 0);
 
 	diFreeSpecial(ipimap);
@@ -84,7 +83,6 @@
 	 */
 	ipaimap2 = sbi->ipaimap2;
 	if (ipaimap2) {
-		jEVENT(0, ("jfs_umount: close ipaimap2:0x%p\n", ipaimap2));
 		diUnmount(ipaimap2, 0);
 		diFreeSpecial(ipaimap2);
 		sbi->ipaimap2 = NULL;
@@ -94,7 +92,6 @@
 	 * close aggregate inode allocation map
 	 */
 	ipaimap = sbi->ipaimap;
-	jEVENT(0, ("jfs_umount: close ipaimap:0x%p\n", ipaimap));
 	diUnmount(ipaimap, 0);
 	diFreeSpecial(ipaimap);
 	sbi->ipaimap = NULL;
@@ -102,7 +99,6 @@
 	/*
 	 * close aggregate block allocation map
 	 */
-	jEVENT(0, ("jfs_umount: close ipbmap:%p\n", ipbmap));
 	dbUnmount(ipbmap, 0);
 
 	diFreeSpecial(ipbmap);
@@ -132,7 +128,7 @@
 		 */
 		rc = lmLogClose(sb, log);
 	}
-	jFYI(0, ("	UnMount JFS Complete: %d\n", rc));
+	jfs_info("UnMount JFS Complete: rc = %d", rc);
 	return rc;
 }
 
@@ -150,7 +146,7 @@
 	 *
 	 * remove file system from log active file system list.
 	 */
-	lmLogWait(log);
+	jfs_flush_journal(log, 2);
 
 	/*
 	 * Make sure all metadata makes it to disk
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/jfs/jfs_unicode.c linux-2.4.21-pre6/fs/jfs/jfs_unicode.c
--- linux-2.4.20/fs/jfs/jfs_unicode.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/jfs/jfs_unicode.c	2003-03-26 23:49:50.000000000 +0000
@@ -47,7 +47,6 @@
 		}
 	}
 	to[outlen] = 0;
-	jEVENT(0, ("jfs_strfromUCS returning %d - '%s'\n", outlen, to));
 	return outlen;
 }
 
@@ -63,22 +62,17 @@
 	int charlen;
 	int i;
 
-	jEVENT(0, ("jfs_strtoUCS - '%s'\n", from));
-
 	for (i = 0; len && *from; i++, from += charlen, len -= charlen) {
 		charlen = codepage->char2uni(from, len, &to[i]);
 		if (charlen < 1) {
-			jERROR(1, ("jfs_strtoUCS: char2uni returned %d.\n",
-				   charlen));
-			jERROR(1, ("charset = %s, char = 0x%x\n",
-				   codepage->charset, (unsigned char) *from));
+			jfs_err("jfs_strtoUCS: char2uni returned %d.", charlen);
+			jfs_err("charset = %s, char = 0x%x",
+				codepage->charset, (unsigned char) *from);
 			to[i] = 0x003f;	/* a question mark */
 			charlen = 1;
 		}
 	}
 
-	jEVENT(0, (" returning %d\n", i));
-
 	to[i] = 0;
 	return i;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/jfs/jfs_xtree.c linux-2.4.21-pre6/fs/jfs/jfs_xtree.c
--- linux-2.4.20/fs/jfs/jfs_xtree.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/jfs/jfs_xtree.c	2003-03-26 23:49:55.000000000 +0000
@@ -69,7 +69,7 @@
                     (le16_to_cpu((P)->header.nextindex) > le16_to_cpu((P)->header.maxentry)) ||\
                     (le16_to_cpu((P)->header.maxentry) > (((BN)==0)?XTROOTMAXSLOT:PSIZE>>L2XTSLOTSIZE)))\
                 {\
-                        jERROR(1,("XT_GETPAGE: xtree page corrupt\n"));\
+                        jfs_err("XT_GETPAGE: xtree page corrupt");\
 			BT_PUTPAGE(MP);\
 			updateSuper((IP)->i_sb, FM_DIRTY);\
 			MP = NULL;\
@@ -169,9 +169,8 @@
 		size = ((u64) ip->i_size + (JFS_SBI(ip->i_sb)->bsize - 1)) >>
 		    JFS_SBI(ip->i_sb)->l2bsize;
 		if (lstart >= size) {
-			jERROR(1,
-			       ("xtLookup: lstart (0x%lx) >= size (0x%lx)\n",
-				(ulong) lstart, (ulong) size));
+			jfs_err("xtLookup: lstart (0x%lx) >= size (0x%lx)",
+				(ulong) lstart, (ulong) size);
 			return 0;
 		}
 	}
@@ -181,7 +180,7 @@
 	 */
 //search:
 	if ((rc = xtSearch(ip, lstart, &cmp, &btstack, 0))) {
-		jERROR(1, ("xtLookup: xtSearch returned %d\n", rc));
+		jfs_err("xtLookup: xtSearch returned %d", rc);
 		return rc;
 	}
 
@@ -198,10 +197,8 @@
 	 * lstart is a page start address,
 	 * i.e., lstart cannot start in a hole;
 	 */
-	if (cmp) {
-		jFYI(1, ("xtLookup: cmp = %d\n", cmp));
+	if (cmp)
 		goto out;
-	}
 
 	/*
 	 * lxd covered by xad
@@ -212,10 +209,6 @@
 	xend = xoff + xlen;
 	xaddr = addressXAD(xad);
 
-	jEVENT(0,
-	       ("index = %d, xoff = 0x%lx, xlen = 0x%x, xaddr = 0x%lx\n",
-		index, (ulong) xoff, xlen, (ulong) xaddr));
-
 	/* initialize new pxd */
 	*pflag = xad->flag;
 	*paddr = xaddr + (lstart - xoff);
@@ -802,8 +795,7 @@
 	struct tlock *tlck;
 	struct xtlock *xtlck;
 
-	jFYI(1,
-	     ("xtInsert: nxoff:0x%lx nxlen:0x%x\n", (ulong) xoff, xlen));
+	jfs_info("xtInsert: nxoff:0x%lx nxlen:0x%x", (ulong) xoff, xlen);
 
 	/*
 	 *      search for the entry location at which to insert:
@@ -1248,8 +1240,7 @@
 	if (rmp == NULL)
 		return EIO;
 
-	jEVENT(0,
-	       ("xtSplitPage: ip:0x%p smp:0x%p rmp:0x%p\n", ip, smp, rmp));
+	jfs_info("xtSplitPage: ip:0x%p smp:0x%p rmp:0x%p", ip, smp, rmp);
 
 	BT_MARK_DIRTY(rmp, ip);
 	/*
@@ -1324,7 +1315,7 @@
 
 		ip->i_blocks += LBLK2PBLK(ip->i_sb, lengthPXD(pxd));
 
-		jEVENT(0, ("xtSplitPage: sp:0x%p rp:0x%p\n", sp, rp));
+		jfs_info("xtSplitPage: sp:0x%p rp:0x%p", sp, rp);
 		return 0;
 	}
 
@@ -1440,7 +1431,7 @@
 
 	ip->i_blocks += LBLK2PBLK(ip->i_sb, lengthPXD(pxd));
 
-	jEVENT(0, ("xtSplitPage: sp:0x%p rp:0x%p\n", sp, rp));
+	jfs_info("xtSplitPage: sp:0x%p rp:0x%p", sp, rp);
 	return rc;
 }
 
@@ -1496,7 +1487,7 @@
 	if (rmp == NULL)
 		return EIO;
 
-	jEVENT(0, ("xtSplitRoot: ip:0x%p rmp:0x%p\n", ip, rmp));
+	jfs_info("xtSplitRoot: ip:0x%p rmp:0x%p", ip, rmp);
 
 	/*
 	 * acquire a transaction lock on the new right page;
@@ -1581,7 +1572,7 @@
 
 	ip->i_blocks += LBLK2PBLK(ip->i_sb, lengthPXD(pxd));
 
-	jEVENT(0, ("xtSplitRoot: sp:0x%p rp:0x%p\n", sp, rp));
+	jfs_info("xtSplitRoot: sp:0x%p rp:0x%p", sp, rp);
 	return 0;
 }
 
@@ -1615,8 +1606,7 @@
 	struct xtlock *xtlck = 0;
 	int rootsplit = 0;
 
-	jFYI(1,
-	     ("xtExtend: nxoff:0x%lx nxlen:0x%x\n", (ulong) xoff, xlen));
+	jfs_info("xtExtend: nxoff:0x%lx nxlen:0x%x", (ulong) xoff, xlen);
 
 	/* there must exist extent to be extended */
 	if ((rc = xtSearch(ip, xoff - 1, &cmp, &btstack, XT_INSERT)))
@@ -1628,9 +1618,6 @@
 
 	/* extension must be contiguous */
 	xad = &p->xad[index];
-	jFYI(0, ("xtExtend: xoff:0x%lx xlen:0x%x xaddr:0x%lx\n",
-		 (ulong) offsetXAD(xad), lengthXAD(xad),
-		 (ulong) addressXAD(xad)));
 	assert((offsetXAD(xad) + lengthXAD(xad)) == xoff);
 
 	/*
@@ -1893,10 +1880,6 @@
 			PXDlength(&pxdlock->pxd, rlen);
 			pxdlock->index = 1;
 		}
-		jEVENT(0,
-		       ("xtTailgate: free extent xaddr:0x%lx xlen:0x%x\n",
-			(ulong) addressPXD(&pxdlock->pxd),
-			lengthPXD(&pxdlock->pxd)));
 	} else
 		/* free from WMAP */
 		dbFree(ip, addressXAD(xad) + llen, (s64) rlen);
@@ -2408,9 +2391,8 @@
 
 	xaddr = *xaddrp;
 	xlen = *xlenp;
-	jEVENT(0,
-	       ("xtAppend: xoff:0x%lx maxblocks:%d xlen:%d xaddr:0x%lx\n",
-		(ulong) xoff, maxblocks, xlen, (ulong) xaddr));
+	jfs_info("xtAppend: xoff:0x%lx maxblocks:%d xlen:%d xaddr:0x%lx",
+		 (ulong) xoff, maxblocks, xlen, (ulong) xaddr);
 
 	/*
 	 *      search for the entry location at which to insert:
@@ -2747,9 +2729,8 @@
 			p->header.nextindex =
 			    cpu_to_le16(le16_to_cpu(p->header.nextindex) -
 					1);
-			jEVENT(0,
-			       ("xtDeleteUp(entry): 0x%lx[%d]\n",
-				(ulong) parent->bn, index));
+			jfs_info("xtDeleteUp(entry): 0x%lx[%d]",
+				 (ulong) parent->bn, index);
 		}
 
 		/* unpin the parent page */
@@ -2809,10 +2790,8 @@
 	if (offset >= ip->i_size)
 		return ESTALE;	/* stale extent */
 
-	jEVENT(0,
-	       ("xtRelocate: xtype:%d xoff:0x%lx xlen:0x%x xaddr:0x%lx:0x%lx\n",
-		xtype, (ulong) xoff, xlen, (ulong) oxaddr,
-		(ulong) nxaddr));
+	jfs_info("xtRelocate: xtype:%d xoff:0x%lx xlen:0x%x xaddr:0x%lx:0x%lx",
+		 xtype, (ulong) xoff, xlen, (ulong) oxaddr, (ulong) nxaddr);
 
 	/*
 	 *      1. get and validate the parent xtpage/xad entry
@@ -2855,7 +2834,7 @@
 		 */
 		xad = &pp->xad[index];
 	}
-	jEVENT(0, ("xtRelocate: parent xad entry validated.\n"));
+	jfs_info("xtRelocate: parent xad entry validated.");
 
 	/*
 	 *      2. relocate the extent
@@ -2926,7 +2905,7 @@
 		/* get back parent page */
 		rc = xtSearch(ip, xoff, &cmp, &btstack, 0);
 		XT_GETSEARCH(ip, btstack.top, bn, pmp, pp, index);
-		jEVENT(0, ("xtRelocate: target data extent relocated.\n"));
+		jfs_info("xtRelocate: target data extent relocated.");
 	} else {		/* (xtype  == XTPAGE) */
 
 		/*
@@ -3026,7 +3005,7 @@
 
 		/* unpin the target page to new homeward bound */
 		XT_PUTPAGE(mp);
-		jEVENT(0, ("xtRelocate: target xtpage relocated.\n"));
+		jfs_info("xtRelocate: target xtpage relocated.");
 	}
 
 	/*
@@ -3067,7 +3046,7 @@
 	 * update which will write LOG_REDOPAGE and update bmap for
 	 * allocation of XAD_NEW destination extent;
 	 */
-	jEVENT(0, ("xtRelocate: update parent xad entry.\n"));
+	jfs_info("xtRelocate: update parent xad entry.");
 	BT_MARK_DIRTY(pmp, ip);
 	tlck = txLock(tid, ip, pmp, tlckXTREE | tlckGROW);
 	xtlck = (struct xtlock *) & tlck->lock;
@@ -3289,14 +3268,13 @@
 void xtInitRoot(tid_t tid, struct inode *ip)
 {
 	xtpage_t *p;
-	struct tlock *tlck;
 
 	/*
 	 * acquire a transaction lock on the root
 	 *
 	 * action:
 	 */
-	tlck = txLock(tid, ip, (struct metapage *) &JFS_IP(ip)->bxflag,
+	txLock(tid, ip, (struct metapage *) &JFS_IP(ip)->bxflag,
 		      tlckXTREE | tlckNEW);
 	p = &JFS_IP(ip)->i_xtroot;
 
@@ -3518,6 +3496,13 @@
 		xaddr = addressXAD(xad);
 
 		/*
+		 * The "data" for a directory is indexed by the block
+		 * device's address space.  This metadata must be invalidated
+		 * here
+		 */
+		if (S_ISDIR(ip->i_mode) && (teof == 0))
+			invalidate_xad_metapages(ip, *xad);
+		/*
 		 * entry beyond eof: continue scan of current page
 		 *          xad
 		 * ---|---=======------->
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/jfs/namei.c linux-2.4.21-pre6/fs/jfs/namei.c
--- linux-2.4.20/fs/jfs/namei.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/jfs/namei.c	2003-03-26 23:49:08.000000000 +0000
@@ -67,7 +67,7 @@
 	struct inode *iplist[2];
 	struct tblock *tblk;
 
-	jFYI(1, ("jfs_create: dip:0x%p name:%s\n", dip, dentry->d_name.name));
+	jfs_info("jfs_create: dip:0x%p name:%s", dip, dentry->d_name.name);
 
 	/*
 	 * search parent directory for entry/freespace
@@ -93,7 +93,7 @@
 	down(&JFS_IP(ip)->commit_sem);
 
 	if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE))) {
-		jERROR(1, ("jfs_create: dtSearch returned %d\n", rc));
+		jfs_err("jfs_create: dtSearch returned %d", rc);
 		goto out3;
 	}
 
@@ -115,7 +115,7 @@
 	 */
 	ino = ip->i_ino;
 	if ((rc = dtInsert(tid, dip, &dname, &ino, &btstack))) {
-		jERROR(1, ("jfs_create: dtInsert returned %d\n", rc));
+		jfs_err("jfs_create: dtInsert returned %d", rc);
 		if (rc == EIO)
 			txAbort(tid, 1);	/* Marks Filesystem dirty */
 		else
@@ -151,7 +151,7 @@
 
       out1:
 
-	jFYI(1, ("jfs_create: rc:%d\n", -rc));
+	jfs_info("jfs_create: rc:%d", -rc);
 	return -rc;
 }
 
@@ -182,7 +182,7 @@
 	struct inode *iplist[2];
 	struct tblock *tblk;
 
-	jFYI(1, ("jfs_mkdir: dip:0x%p name:%s\n", dip, dentry->d_name.name));
+	jfs_info("jfs_mkdir: dip:0x%p name:%s", dip, dentry->d_name.name);
 
 	/* link count overflow on parent directory ? */
 	if (dip->i_nlink == JFS_LINK_MAX) {
@@ -214,7 +214,7 @@
 	down(&JFS_IP(ip)->commit_sem);
 
 	if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE))) {
-		jERROR(1, ("jfs_mkdir: dtSearch returned %d\n", rc));
+		jfs_err("jfs_mkdir: dtSearch returned %d", rc);
 		goto out3;
 	}
 
@@ -236,7 +236,7 @@
 	 */
 	ino = ip->i_ino;
 	if ((rc = dtInsert(tid, dip, &dname, &ino, &btstack))) {
-		jERROR(1, ("jfs_mkdir: dtInsert returned %d\n", rc));
+		jfs_err("jfs_mkdir: dtInsert returned %d", rc);
 
 		if (rc == EIO)
 			txAbort(tid, 1);	/* Marks Filesystem dirty */
@@ -276,7 +276,7 @@
 
       out1:
 
-	jFYI(1, ("jfs_mkdir: rc:%d\n", -rc));
+	jfs_info("jfs_mkdir: rc:%d", -rc);
 	return -rc;
 }
 
@@ -309,7 +309,7 @@
 	struct inode *iplist[2];
 	struct tblock *tblk;
 
-	jFYI(1, ("jfs_rmdir: dip:0x%p name:%s\n", dip, dentry->d_name.name));
+	jfs_info("jfs_rmdir: dip:0x%p name:%s", dip, dentry->d_name.name);
 
 	/* directory must be empty to be removed */
 	if (!dtEmpty(ip)) {
@@ -338,7 +338,7 @@
 	 */
 	ino = ip->i_ino;
 	if ((rc = dtDelete(tid, dip, &dname, &ino, JFS_REMOVE))) {
-		jERROR(1, ("jfs_rmdir: dtDelete returned %d\n", rc));
+		jfs_err("jfs_rmdir: dtDelete returned %d", rc);
 		if (rc == EIO)
 			txAbort(tid, 1);
 		txEnd(tid);
@@ -398,7 +398,7 @@
 	free_UCSname(&dname);
 
       out:
-	jFYI(1, ("jfs_rmdir: rc:%d\n", rc));
+	jfs_info("jfs_rmdir: rc:%d", rc);
 	return -rc;
 }
 
@@ -434,7 +434,7 @@
 	s64 new_size = 0;
 	int commit_flag;
 
-	jFYI(1, ("jfs_unlink: dip:0x%p name:%s\n", dip, dentry->d_name.name));
+	jfs_info("jfs_unlink: dip:0x%p name:%s", dip, dentry->d_name.name);
 
 	if ((rc = get_UCSname(&dname, dentry, JFS_SBI(dip->i_sb)->nls_tab)))
 		goto out;
@@ -454,7 +454,7 @@
 	 */
 	ino = ip->i_ino;
 	if ((rc = dtDelete(tid, dip, &dname, &ino, JFS_REMOVE))) {
-		jERROR(1, ("jfs_unlink: dtDelete returned %d\n", rc));
+		jfs_err("jfs_unlink: dtDelete returned %d", rc);
 		if (rc == EIO)
 			txAbort(tid, 1);	/* Marks FS Dirty */
 		txEnd(tid);
@@ -531,8 +531,7 @@
 	if (ip->i_nlink == 0)
 		set_cflag(COMMIT_Nolink, ip);
 
-	if (!test_cflag(COMMIT_Holdlock, ip))
-		IWRITE_UNLOCK(ip);
+	IWRITE_UNLOCK(ip);
 
 	/*
 	 * Truncating the directory index table is not guaranteed.  It
@@ -548,7 +547,7 @@
       out1:
 	free_UCSname(&dname);
       out:
-	jFYI(1, ("jfs_unlink: rc:%d\n", -rc));
+	jfs_info("jfs_unlink: rc:%d", -rc);
 	return -rc;
 }
 
@@ -581,7 +580,7 @@
 	int filetype;
 	struct tblock *tblk;
 
-	jFYI(1, ("commitZeroLink: tid = %d, ip = 0x%p\n", tid, ip));
+	jfs_info("commitZeroLink: tid = %d, ip = 0x%p", tid, ip);
 
 	filetype = ip->i_mode & S_IFMT;
 	switch (filetype) {
@@ -589,7 +588,7 @@
 		break;
 	case S_IFLNK:
 		/* fast symbolic link */
-		if (ip->i_size <= 256) {
+		if (ip->i_size < IDATASIZE) {
 			ip->i_size = 0;
 			return 0;
 		}
@@ -649,7 +648,7 @@
 	int rc = 0;
 	int type;
 
-	jFYI(1, ("freeZeroLink: ip = 0x%p\n", ip));
+	jfs_info("freeZeroLink: ip = 0x%p", ip);
 
 	/* return if not reg or symbolic link or if size is
 	 * already ok.
@@ -661,7 +660,7 @@
 		break;
 	case S_IFLNK:
 		/* if its contained in inode nothing to do */
-		if (ip->i_size <= 256)
+		if (ip->i_size < IDATASIZE)
 			return 0;
 		break;
 	default:
@@ -755,9 +754,8 @@
 	struct btstack btstack;
 	struct inode *iplist[2];
 
-	jFYI(1,
-	     ("jfs_link: %s %s\n", old_dentry->d_name.name,
-	      dentry->d_name.name));
+	jfs_info("jfs_link: %s %s", old_dentry->d_name.name,
+		 dentry->d_name.name);
 
 	/* JFS does NOT support link() on directories */
 	if (S_ISDIR(ip->i_mode))
@@ -806,7 +804,7 @@
 	up(&JFS_IP(dir)->commit_sem);
 	up(&JFS_IP(ip)->commit_sem);
 
-	jFYI(1, ("jfs_link: rc:%d\n", rc));
+	jfs_info("jfs_link: rc:%d", rc);
 	return -rc;
 }
 
@@ -847,7 +845,7 @@
 
 	struct inode *iplist[2];
 
-	jFYI(1, ("jfs_symlink: dip:0x%p name:%s\n", dip, name));
+	jfs_info("jfs_symlink: dip:0x%p name:%s", dip, name);
 
 	ssize = strlen(name) + 1;
 
@@ -890,7 +888,7 @@
 
 
 	if ((rc = dtInsert(tid, dip, &dname, &ino, &btstack))) {
-		jERROR(1, ("jfs_symlink: dtInsert returned %d\n", rc));
+		jfs_err("jfs_symlink: dtInsert returned %d", rc);
 		/* discard ne inode */
 		goto out3;
 
@@ -925,15 +923,14 @@
 		if (ssize > sizeof (JFS_IP(ip)->i_inline))
 			JFS_IP(ip)->mode2 &= ~INLINEEA;
 
-		jFYI(1,
-		     ("jfs_symlink: fast symlink added  ssize:%d name:%s \n",
-		      ssize, name));
+		jfs_info("jfs_symlink: fast symlink added  ssize:%d name:%s ",
+			 ssize, name);
 	}
 	/*
 	 * write source path name in a single extent
 	 */
 	else {
-		jFYI(1, ("jfs_symlink: allocate extent ip:0x%p\n", ip));
+		jfs_info("jfs_symlink: allocate extent ip:0x%p", ip);
 
 		ip->i_op = &page_symlink_inode_operations;
 		ip->i_mapping->a_ops = &jfs_aops;
@@ -1020,7 +1017,7 @@
 	free_UCSname(&dname);
 
       out1:
-	jFYI(1, ("jfs_symlink: rc:%d\n", -rc));
+	jfs_info("jfs_symlink: rc:%d", -rc);
 	return -rc;
 }
 
@@ -1051,9 +1048,8 @@
 	int commit_flag;
 
 
-	jFYI(1,
-	     ("jfs_rename: %s %s\n", old_dentry->d_name.name,
-	      new_dentry->d_name.name));
+	jfs_info("jfs_rename: %s %s", old_dentry->d_name.name,
+		 new_dentry->d_name.name);
 
 	old_ip = old_dentry->d_inode;
 	new_ip = new_dentry->d_inode;
@@ -1155,18 +1151,16 @@
 		rc = dtSearch(new_dir, &new_dname, &ino, &btstack,
 			      JFS_CREATE);
 		if (rc) {
-			jERROR(1,
-			       ("jfs_rename didn't expect dtSearch to fail w/rc = %d\n",
-				rc));
+			jfs_err("jfs_rename didn't expect dtSearch to fail "
+				"w/rc = %d", rc);
 			goto out4;
 		}
 
 		ino = old_ip->i_ino;
 		rc = dtInsert(tid, new_dir, &new_dname, &ino, &btstack);
 		if (rc) {
-			jERROR(1,
-			       ("jfs_rename: dtInsert failed w/rc = %d\n",
-				rc));
+			jfs_err("jfs_rename: dtInsert failed w/rc = %d",
+				rc);
 			goto out4;
 		}
 		if (S_ISDIR(old_ip->i_mode))
@@ -1179,9 +1173,8 @@
 	ino = old_ip->i_ino;
 	rc = dtDelete(tid, old_dir, &old_dname, &ino, JFS_REMOVE);
 	if (rc) {
-		jERROR(1,
-		       ("jfs_rename did not expect dtDelete to return rc = %d\n",
-			rc));
+		jfs_err("jfs_rename did not expect dtDelete to return rc = %d",
+			rc);
 		txAbort(tid, 1);	/* Marks Filesystem dirty */
 		goto out4;
 	}
@@ -1242,14 +1235,6 @@
 
 	rc = txCommit(tid, ipcount, iplist, commit_flag);
 
-	/*
-	 * Don't unlock new_ip if COMMIT_HOLDLOCK is set
-	 */
-	if (new_ip && test_cflag(COMMIT_Holdlock, new_ip)) {
-		up(&JFS_IP(new_ip)->commit_sem);
-		new_ip = 0;
-	}
-
       out4:
 	txEnd(tid);
 
@@ -1292,7 +1277,7 @@
 		clear_cflag(COMMIT_Stale, old_dir);
 	}
 
-	jFYI(1, ("jfs_rename: returning %d\n", rc));
+	jfs_info("jfs_rename: returning %d", rc);
 	return -rc;
 }
 
@@ -1313,7 +1298,7 @@
 	tid_t tid;
 	struct tblock *tblk;
 
-	jFYI(1, ("jfs_mknod: %s\n", dentry->d_name.name));
+	jfs_info("jfs_mknod: %s", dentry->d_name.name);
 
 	if ((rc = get_UCSname(&dname, dentry, JFS_SBI(dir->i_sb)->nls_tab)))
 		goto out;
@@ -1368,7 +1353,7 @@
 	free_UCSname(&dname);
 
       out:
-	jFYI(1, ("jfs_mknod: returning %d\n", rc));
+	jfs_info("jfs_mknod: returning %d", rc);
 	return -rc;
 }
 
@@ -1382,7 +1367,7 @@
 	int len = dentry->d_name.len;
 	int rc;
 
-	jFYI(1, ("jfs_lookup: name = %s\n", name));
+	jfs_info("jfs_lookup: name = %s", name);
 
 
 	if ((name[0] == '.') && (len == 1))
@@ -1399,17 +1384,14 @@
 			d_add(dentry, NULL);
 			return ERR_PTR(0);
 		} else if (rc) {
-			jERROR(1,
-			       ("jfs_lookup: dtSearch returned %d\n", rc));
+			jfs_err("jfs_lookup: dtSearch returned %d", rc);
 			return ERR_PTR(-rc);
 		}
 	}
 
 	ip = iget(dip->i_sb, inum);
 	if (ip == NULL) {
-		jERROR(1,
-		       ("jfs_lookup: iget failed on inum %d\n",
-			(uint) inum));
+		jfs_err("jfs_lookup: iget failed on inum %d", (uint) inum);
 		return ERR_PTR(-EACCES);
 	}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/jfs/resize.c linux-2.4.21-pre6/fs/jfs/resize.c
--- linux-2.4.20/fs/jfs/resize.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/jfs/resize.c	2003-03-26 23:49:54.000000000 +0000
@@ -29,6 +29,8 @@
 #include "jfs_txnmgr.h"
 #include "jfs_debug.h"
 
+extern s64 jfs_get_volume_size(struct super_block *);
+
 #define BITSPERPAGE     (PSIZE << 3)
 #define L2MEGABYTE      20
 #define MEGABYTE        (1 << L2MEGABYTE)
@@ -97,7 +99,7 @@
 		goto out;
 	}
 
-	VolumeSize = sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits;
+	VolumeSize = jfs_get_volume_size(sb);
 	if (VolumeSize) {
 		if (newLVSize > VolumeSize) {
 			printk(KERN_WARNING "jfs_extendfs: invalid size\n");
@@ -512,7 +514,7 @@
 		mark_buffer_dirty(bh);
 		ll_rw_block(WRITE, 1, &bh2);
 		wait_on_buffer(bh2);
-		brelse(bh);
+		brelse(bh2);
 	}
 
 	/* write primary superblock */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/jfs/super.c linux-2.4.21-pre6/fs/jfs/super.c
--- linux-2.4.20/fs/jfs/super.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/jfs/super.c	2003-03-26 23:49:39.000000000 +0000
@@ -20,6 +20,7 @@
 #include <linux/config.h>
 #include <linux/fs.h>
 #include <linux/module.h>
+#include <linux/blkdev.h>
 #include <linux/completion.h>
 #include <asm/uaccess.h>
 #include "jfs_incore.h"
@@ -44,7 +45,7 @@
 DECLARE_COMPLETION(jfsIOwait);
 
 #ifdef CONFIG_JFS_DEBUG
-int jfsloglevel = 1;
+int jfsloglevel = JFS_LOGLEVEL_WARN;
 MODULE_PARM(jfsloglevel, "i");
 MODULE_PARM_DESC(jfsloglevel, "Specify JFS loglevel (0, 1 or 2)");
 #endif
@@ -82,7 +83,7 @@
 	s64 maxinodes;
 	struct inomap *imap = JFS_IP(sbi->ipimap)->i_imap;
 
-	jFYI(1, ("In jfs_statfs\n"));
+	jfs_info("In jfs_statfs");
 	buf->f_type = JFS_SUPER_MAGIC;
 	buf->f_bsize = sbi->bsize;
 	buf->f_blocks = sbi->bmap->db_mapsize;
@@ -113,17 +114,34 @@
 	struct jfs_sb_info *sbi = JFS_SBI(sb);
 	int rc;
 
-	jFYI(1, ("In jfs_put_super\n"));
+	jfs_info("In jfs_put_super");
 	rc = jfs_umount(sb);
-	if (rc) {
-		jERROR(1, ("jfs_umount failed with return code %d\n", rc));
-	}
+	if (rc)
+		jfs_err("jfs_umount failed with return code %d", rc);
 	unload_nls(sbi->nls_tab);
 	sbi->nls_tab = NULL;
 
 	kfree(sbi);
 }
 
+s64 jfs_get_volume_size(struct super_block *sb)
+{
+	uint blocks = 0;
+	s64 bytes;
+	kdev_t dev = sb->s_dev;
+	int major = MAJOR(dev);
+	int minor = MINOR(dev);
+
+	if (blk_size[major]) {
+		blocks = blk_size[major][minor];
+		if (blocks) {
+			bytes = ((s64)blocks) << BLOCK_SIZE_BITS;
+			return bytes >> sb->s_blocksize_bits;
+		}
+	}
+	return 0;
+}
+
 static int parse_options(char *options, struct super_block *sb, s64 *newLVSize)
 {
 	void *nls_map = NULL;
@@ -152,8 +170,7 @@
 			}
 		} else if (!strcmp(this_char, "resize")) {
 			if (!value || !*value) {
-				*newLVSize = sb->s_bdev->bd_inode->i_size >>
-					sb->s_blocksize_bits;
+				*newLVSize = jfs_get_volume_size(sb);
 				if (*newLVSize == 0)
 					printk(KERN_ERR
 					 "JFS: Cannot determine volume size\n");
@@ -222,9 +239,8 @@
 	int rc;
 	s64 newLVSize = 0;
 
-	jFYI(1,
-	     ("In jfs_read_super s_dev=0x%x s_flags=0x%lx\n", sb->s_dev,
-	      sb->s_flags));
+	jfs_info("In jfs_read_super s_dev=0x%x s_flags=0x%lx", sb->s_dev,
+		 sb->s_flags);
 
 	sbi = kmalloc(sizeof (struct jfs_sb_info), GFP_KERNEL);
 	if (!sbi)
@@ -255,8 +271,7 @@
 	rc = jfs_mount(sb);
 	if (rc) {
 		if (!silent) {
-			jERROR(1,
-			       ("jfs_mount failed w/return code = %d\n", rc));
+			jfs_err("jfs_mount failed w/return code = %d", rc);
 		}
 		goto out_kfree;
 	}
@@ -266,9 +281,8 @@
 		rc = jfs_mount_rw(sb, 0);
 		if (rc) {
 			if (!silent) {
-				jERROR(1,
-				       ("jfs_mount_rw failed w/return code = %d\n",
-					rc));
+				jfs_err("jfs_mount_rw failed, return code = %d",
+					rc);
 			}
 			goto out_no_rw;
 		}
@@ -299,14 +313,14 @@
 	return sb;
 
 out_no_root:
-	jEVENT(1, ("jfs_read_super: get root inode failed\n"));
+	jfs_err("jfs_read_super: get root inode failed");
 	if (inode)
 		iput(inode);
 
 out_no_rw:
 	rc = jfs_umount(sb);
 	if (rc) {
-		jERROR(1, ("jfs_umount failed with return code %d\n", rc));
+		jfs_err("jfs_umount failed with return code %d", rc);
 	}
 out_kfree:
 	if (sbi->nls_tab)
@@ -334,14 +348,24 @@
 
 	if (!(sb->s_flags & MS_RDONLY)) {
 		if ((rc = lmLogInit(log)))
-			jERROR(1,
-			       ("jfs_unlock failed with return code %d\n", rc));
+			jfs_err("jfs_unlock failed with return code %d", rc);
 		else
 			txResume(sb);
 	}
 }
 
 
+static int jfs_sync_fs(struct super_block *sb)
+{
+	struct jfs_log *log = JFS_SBI(sb)->log;
+
+	/* log == NULL indicates read-only mount */
+	if (log)
+		jfs_flush_journal(log, 1);
+
+	return 0;
+}
+
 static struct super_operations jfs_super_operations = {
 	.read_inode	= jfs_read_inode,
 	.dirty_inode	= jfs_dirty_inode,
@@ -349,6 +373,7 @@
 	.clear_inode	= jfs_clear_inode,
 	.delete_inode	= jfs_delete_inode,
 	.put_super	= jfs_put_super,
+	.sync_fs	= jfs_sync_fs,
 	.write_super_lockfs = jfs_write_super_lockfs,
 	.unlockfs       = jfs_unlockfs,
 	.statfs		= jfs_statfs,
@@ -374,7 +399,6 @@
 	if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) ==
 	    SLAB_CTOR_CONSTRUCTOR) {
 		INIT_LIST_HEAD(&jfs_ip->anon_inode_list);
-		INIT_LIST_HEAD(&jfs_ip->mp_list);
 		init_rwsem(&jfs_ip->rdwrlock);
 		init_MUTEX(&jfs_ip->commit_sem);
 		jfs_ip->atlhead = 0;
@@ -397,7 +421,7 @@
 	 */
 	rc = metapage_init();
 	if (rc) {
-		jERROR(1, ("metapage_init failed w/rc = %d\n", rc));
+		jfs_err("metapage_init failed w/rc = %d", rc);
 		goto free_slab;
 	}
 
@@ -406,7 +430,7 @@
 	 */
 	rc = txInit();
 	if (rc) {
-		jERROR(1, ("txInit failed w/rc = %d\n", rc));
+		jfs_err("txInit failed w/rc = %d", rc);
 		goto free_metapage;
 	}
 
@@ -416,8 +440,7 @@
 	jfsIOthread = kernel_thread(jfsIOWait, 0,
 				    CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
 	if (jfsIOthread < 0) {
-		jERROR(1,
-		       ("init_jfs_fs: fork failed w/rc = %d\n", jfsIOthread));
+		jfs_err("init_jfs_fs: fork failed w/rc = %d", jfsIOthread);
 		goto end_txmngr;
 	}
 	wait_for_completion(&jfsIOwait);	/* Wait until thread starts */
@@ -425,9 +448,7 @@
 	jfsCommitThread = kernel_thread(jfs_lazycommit, 0,
 					CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
 	if (jfsCommitThread < 0) {
-		jERROR(1,
-		       ("init_jfs_fs: fork failed w/rc = %d\n",
-			jfsCommitThread));
+		jfs_err("init_jfs_fs: fork failed w/rc = %d", jfsCommitThread);
 		goto kill_iotask;
 	}
 	wait_for_completion(&jfsIOwait);	/* Wait until thread starts */
@@ -435,8 +456,7 @@
 	jfsSyncThread = kernel_thread(jfs_sync, 0,
 				      CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
 	if (jfsSyncThread < 0) {
-		jERROR(1,
-		       ("init_jfs_fs: fork failed w/rc = %d\n", jfsSyncThread));
+		jfs_err("init_jfs_fs: fork failed w/rc = %d", jfsSyncThread);
 		goto kill_committask;
 	}
 	wait_for_completion(&jfsIOwait);	/* Wait until thread starts */
@@ -466,7 +486,7 @@
 
 static void __exit exit_jfs_fs(void)
 {
-	jFYI(1, ("exit_jfs_fs called\n"));
+	jfs_info("exit_jfs_fs called");
 
 	jfs_stop_threads = 1;
 	txExit();
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/lockd/svc.c linux-2.4.21-pre6/fs/lockd/svc.c
--- linux-2.4.20/fs/lockd/svc.c	2001-10-21 17:32:33.000000000 +0000
+++ linux-2.4.21-pre6/fs/lockd/svc.c	2003-03-26 23:49:49.000000000 +0000
@@ -72,11 +72,6 @@
 	return grace_period + jiffies;
 }
 
-static inline void clear_grace_period(void)
-{
-	nlmsvc_grace_period = 0;
-}
-
 /*
  * This is the lockd kernel thread
  */
@@ -142,10 +137,8 @@
 		 * (Theoretically, there shouldn't even be blocked locks
 		 * during grace period).
 		 */
-		if (!nlmsvc_grace_period) {
+		if (!nlmsvc_grace_period)
 			timeout = nlmsvc_retry_blocked();
-		} else if (time_before(grace_period_expire, jiffies))
-			clear_grace_period();
 
 		/*
 		 * Find a socket with data available and call its
@@ -175,6 +168,9 @@
 				nlmsvc_ops->exp_getclient(&rqstp->rq_addr);
 		}
 
+		if (nlmsvc_grace_period &&
+		    time_before(grace_period_expire, jiffies))
+			nlmsvc_grace_period = 0;
 		svc_process(serv, rqstp);
 
 		/* Unlock export hash tables */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/locks.c linux-2.4.21-pre6/fs/locks.c
--- linux-2.4.20/fs/locks.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/locks.c	2003-03-26 23:49:30.000000000 +0000
@@ -274,9 +274,18 @@
 		return -EINVAL;
 	}
 
-	if (((start += l->l_start) < 0) || (l->l_len < 0))
+	/* POSIX-1996 leaves the case l->l_len < 0 undefined;
+	   POSIX-2001 defines it. */
+	start += l->l_start;
+	if (l->l_len < 0) {
+		end = start - 1;
+		start += l->l_len;
+	} else {
+		end = start + l->l_len - 1;
+	}
+
+	if (start < 0)
 		return -EINVAL;
-	end = start + l->l_len - 1;
 	if (l->l_len > 0 && end < 0)
 		return -EOVERFLOW;
 	fl->fl_start = start;	/* we record the absolute position */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/namei.c linux-2.4.21-pre6/fs/namei.c
--- linux-2.4.20/fs/namei.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/namei.c	2003-03-26 23:49:26.000000000 +0000
@@ -1974,8 +1974,10 @@
 	 * bloody create() on broken symlinks. Furrfu...
 	 */
 	name = __getname();
-	if (!name)
+	if (!name) {
+		path_release(nd);
 		return -ENOMEM;
+	}
 	strcpy(name, nd->last.name);
 	nd->last.name = name;
 	return 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/namespace.c linux-2.4.21-pre6/fs/namespace.c
--- linux-2.4.20/fs/namespace.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/namespace.c	2003-03-26 23:49:50.000000000 +0000
@@ -24,13 +24,12 @@
 struct vfsmount *do_kern_mount(const char *type, int flags, char *name, void *data);
 int do_remount_sb(struct super_block *sb, int flags, void * data);
 void kill_super(struct super_block *sb);
+extern int __init init_rootfs(void);
 
 static struct list_head *mount_hashtable;
 static int hash_mask, hash_bits;
 static kmem_cache_t *mnt_cache; 
 
-extern void init_rootfs(void);
-
 static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry)
 {
 	unsigned long tmp = ((unsigned long) mnt / L1_CACHE_BYTES);
@@ -1023,15 +1022,10 @@
 	if (!mnt_cache)
 		panic("Cannot create vfsmount cache");
 
-	mempages >>= (16 - PAGE_SHIFT);
-	mempages *= sizeof(struct list_head);
-	for (order = 0; ((1UL << order) << PAGE_SHIFT) < mempages; order++)
-		;
-
-	do {
-		mount_hashtable = (struct list_head *)
-			__get_free_pages(GFP_ATOMIC, order);
-	} while (mount_hashtable == NULL && --order >= 0);
+	/* using single pointer list heads would save half of the hash table. */
+	order = 0; 
+	mount_hashtable = (struct list_head *)
+		__get_free_pages(GFP_ATOMIC, order);
 
 	if (!mount_hashtable)
 		panic("Failed to allocate mount hash table\n");
@@ -1055,8 +1049,9 @@
 	nr_hash = 1UL << hash_bits;
 	hash_mask = nr_hash-1;
 
-	printk("Mount-cache hash table entries: %d (order: %ld, %ld bytes)\n",
-			nr_hash, order, (PAGE_SIZE << order));
+	printk(KERN_INFO "Mount cache hash table entries: %d"
+		" (order: %ld, %ld bytes)\n",
+		nr_hash, order, (PAGE_SIZE << order));
 
 	/* And initialize the newly allocated array */
 	d = mount_hashtable;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/nfs/file.c linux-2.4.21-pre6/fs/nfs/file.c
--- linux-2.4.20/fs/nfs/file.c	2002-02-25 19:38:09.000000000 +0000
+++ linux-2.4.21-pre6/fs/nfs/file.c	2003-03-26 23:49:50.000000000 +0000
@@ -187,6 +187,7 @@
 	if (!inode)
 		return 0;
 
+	NFS_SetPageSync(page);
 	rpages = NFS_SERVER(inode)->rpages;
 	result = nfs_pagein_inode(inode, index, rpages);
 	if (result < 0)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/nfs/nfsroot.c linux-2.4.21-pre6/fs/nfs/nfsroot.c
--- linux-2.4.20/fs/nfs/nfsroot.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/nfs/nfsroot.c	2003-03-26 23:49:50.000000000 +0000
@@ -384,10 +384,11 @@
 					"number from server, using default\n");
 			port = nfsd_port;
 		}
-		nfs_port = htons(port);
+		nfs_port = port;
 		dprintk("Root-NFS: Portmapper on server returned %d "
 			"as nfsd port\n", port);
 	}
+	nfs_port = htons(nfs_port);
 
 	if ((port = root_nfs_getport(NFS_MNT_PROGRAM, mountd_ver, proto)) < 0) {
 		printk(KERN_ERR "Root-NFS: Unable to get mountd port "
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/nfs/pagelist.c linux-2.4.21-pre6/fs/nfs/pagelist.c
--- linux-2.4.20/fs/nfs/pagelist.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/nfs/pagelist.c	2003-03-26 23:49:29.000000000 +0000
@@ -134,9 +134,12 @@
 		req->wb_cred = NULL;
 	}
 	if (req->wb_page) {
+		atomic_dec(&NFS_REQUESTLIST(req->wb_inode)->nr_requests);
+#ifdef NFS_PARANOIA
+		BUG_ON(atomic_read(&NFS_REQUESTLIST(req->wb_inode)->nr_requests) < 0);
+#endif
 		page_cache_release(req->wb_page);
 		req->wb_page = NULL;
-		atomic_dec(&NFS_REQUESTLIST(req->wb_inode)->nr_requests);
 	}
 }
 
@@ -159,14 +162,9 @@
 	spin_unlock(&nfs_wreq_lock);
 
 #ifdef NFS_PARANOIA
-	if (!list_empty(&req->wb_list))
-		BUG();
-	if (!list_empty(&req->wb_hash))
-		BUG();
-	if (NFS_WBACK_BUSY(req))
-		BUG();
-	if (atomic_read(&NFS_REQUESTLIST(req->wb_inode)->nr_requests) < 0)
-		BUG();
+	BUG_ON(!list_empty(&req->wb_list));
+	BUG_ON(!list_empty(&req->wb_hash));
+	BUG_ON(NFS_WBACK_BUSY(req));
 #endif
 
 	/* Release struct file or cached credential */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/nfs/read.c linux-2.4.21-pre6/fs/nfs/read.c
--- linux-2.4.20/fs/nfs/read.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/nfs/read.c	2003-03-26 23:48:57.000000000 +0000
@@ -171,11 +171,16 @@
 	struct nfs_page	*new;
 
 	new = nfs_create_request(nfs_file_cred(file), inode, page, 0, PAGE_CACHE_SIZE);
-	if (IS_ERR(new))
+	if (IS_ERR(new)) {
+		SetPageError(page);
+		NFS_ClearPageSync(page);
+		UnlockPage(page);
 		return PTR_ERR(new);
+	}
 	nfs_mark_request_read(new);
 
-	if (inode->u.nfs_i.nread >= NFS_SERVER(inode)->rpages ||
+	if (NFS_TestClearPageSync(page) ||
+	    inode->u.nfs_i.nread >= NFS_SERVER(inode)->rpages ||
 	    page_index(page) == (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT)
 		nfs_pagein_inode(inode, 0, 0);
 	return 0;
@@ -222,6 +227,7 @@
 		req = nfs_list_entry(head->next);
 		page = req->wb_page;
 		nfs_list_remove_request(req);
+		NFS_ClearPageSync(page);
 		SetPageError(page);
 		UnlockPage(page);
 		nfs_clear_request(req);
@@ -418,17 +424,13 @@
 				memset(p + count, 0, PAGE_CACHE_SIZE - count);
 				kunmap(page);
 				count = 0;
-				if (data->res.eof)
-					SetPageUptodate(page);
-				else
-					SetPageError(page);
-			} else {
+			} else
 				count -= PAGE_CACHE_SIZE;
-				SetPageUptodate(page);
-			}
+			SetPageUptodate(page);
 		} else
 			SetPageError(page);
 		flush_dcache_page(page);
+		NFS_ClearPageSync(page);
 		UnlockPage(page);
 
 		dprintk("NFS: read (%x/%Ld %d@%Ld)\n",
@@ -482,6 +484,7 @@
 	return error;
 
 out_error:
+	NFS_ClearPageSync(page);
 	UnlockPage(page);
 	goto out;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/nfs/symlink.c linux-2.4.21-pre6/fs/nfs/symlink.c
--- linux-2.4.20/fs/nfs/symlink.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/nfs/symlink.c	2003-03-26 23:48:57.000000000 +0000
@@ -46,7 +46,6 @@
 
 error:
 	SetPageError(page);
-	kunmap(page);
 	UnlockPage(page);
 	return -EIO;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/nfsd/nfs3proc.c linux-2.4.21-pre6/fs/nfsd/nfs3proc.c
--- linux-2.4.20/fs/nfsd/nfs3proc.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/nfsd/nfs3proc.c	2003-03-26 23:49:29.000000000 +0000
@@ -672,7 +672,7 @@
   PROC(setattr,  sattr,		wccstat,	fhandle,  RC_REPLBUFF, ST+WC),
   PROC(lookup,	 dirop,		dirop,		fhandle2, RC_NOCACHE, ST+FH+pAT+pAT),
   PROC(access,	 access,	access,		fhandle,  RC_NOCACHE, ST+pAT+1),
-  PROC(readlink, fhandle,	readlink,	fhandle,  RC_NOCACHE, ST+pAT+1+256),
+  PROC(readlink, fhandle,	readlink,	fhandle,  RC_NOCACHE, ST+pAT+1+NFS3_MAXPATHLEN/4),
   PROC(read,	 read,		read,		fhandle, RC_NOCACHE, ST+pAT+4+NFSSVC_MAXBLKSIZE),
   PROC(write,	 write,		write,		fhandle,  RC_REPLBUFF, ST+WC+4),
   PROC(create,	 create,	create,		fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC),
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/nfsd/nfs3xdr.c linux-2.4.21-pre6/fs/nfsd/nfs3xdr.c
--- linux-2.4.20/fs/nfsd/nfs3xdr.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/nfsd/nfs3xdr.c	2003-03-26 23:48:57.000000000 +0000
@@ -52,7 +52,7 @@
 static inline u32 *
 decode_fh(u32 *p, struct svc_fh *fhp)
 {
-	int size;
+	unsigned int size;
 	fh_init(fhp, NFS3_FHSIZE);
 	size = ntohl(*p++);
 	if (size > NFS3_FHSIZE)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/nfsd/nfsfh.c linux-2.4.21-pre6/fs/nfsd/nfsfh.c
--- linux-2.4.20/fs/nfsd/nfsfh.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/nfsd/nfsfh.c	2003-03-26 23:49:29.000000000 +0000
@@ -620,6 +620,13 @@
 			switch (fh->fh_fileid_type) {
 			case 0:
 				dentry = dget(exp->ex_dentry);
+				/* need to revalidate the inode */
+				inode = dentry->d_inode;
+				if (inode->i_op && inode->i_op->revalidate)
+					if (inode->i_op->revalidate(dentry)) {
+						dput(dentry);
+						dentry = ERR_PTR(-ESTALE);
+					}
 				break;
 			default:
 				dentry = find_fh_dentry(exp->ex_dentry->d_inode->i_sb,
@@ -671,11 +678,16 @@
 
 	/* Type can be negative to e.g. exclude directories from linking */
 	if (type > 0 && (inode->i_mode & S_IFMT) != type) {
-		error = (type == S_IFDIR)? nfserr_notdir : nfserr_isdir;
+		if (type == S_IFDIR)
+			error = nfserr_notdir;
+		else if ((inode->i_mode & S_IFMT) == S_IFDIR)
+			error = nfserr_isdir;
+		else
+			error = nfserr_inval;
 		goto out;
 	}
 	if (type < 0 && (inode->i_mode & S_IFMT) == -type) {
-		error = (type == -S_IFDIR)? nfserr_notdir : nfserr_isdir;
+		error = (type == -S_IFDIR)? nfserr_isdir : nfserr_notdir;
 		goto out;
 	}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/nfsd/nfsproc.c linux-2.4.21-pre6/fs/nfsd/nfsproc.c
--- linux-2.4.20/fs/nfsd/nfsproc.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/nfsd/nfsproc.c	2003-03-26 23:49:25.000000000 +0000
@@ -545,7 +545,7 @@
   PROC(setattr,  sattrargs,	attrstat,	fhandle,	RC_REPLBUFF, ST+AT),
   PROC(none,	 void,		void,		none,		RC_NOCACHE, ST),
   PROC(lookup,	 diropargs,	diropres,	fhandle,	RC_NOCACHE, ST+FH+AT),
-  PROC(readlink, fhandle,	readlinkres,	none,		RC_NOCACHE, ST+1+256),
+  PROC(readlink, fhandle,	readlinkres,	none,		RC_NOCACHE, ST+1+NFS_MAXPATHLEN/4),
   PROC(read,	 readargs,	readres,	fhandle,	RC_NOCACHE, ST+AT+1+NFSSVC_MAXBLKSIZE),
   PROC(none,	 void,		void,		none,		RC_NOCACHE, ST),
   PROC(write,	 writeargs,	attrstat,	fhandle,	RC_REPLBUFF, ST+AT),
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/nfsd/nfsxdr.c linux-2.4.21-pre6/fs/nfsd/nfsxdr.c
--- linux-2.4.20/fs/nfsd/nfsxdr.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/nfsd/nfsxdr.c	2003-03-26 23:48:58.000000000 +0000
@@ -385,7 +385,7 @@
 {
 	struct statfs	*stat = &resp->stats;
 
-	*p++ = htonl(8 * 1024);		/* max transfer size */
+	*p++ = htonl(NFSSVC_MAXBLKSIZE);	/* max transfer size */
 	*p++ = htonl(stat->f_bsize);
 	*p++ = htonl(stat->f_blocks);
 	*p++ = htonl(stat->f_bfree);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/nfsd/vfs.c linux-2.4.21-pre6/fs/nfsd/vfs.c
--- linux-2.4.20/fs/nfsd/vfs.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/nfsd/vfs.c	2003-03-26 23:49:30.000000000 +0000
@@ -168,11 +168,13 @@
 			mntput(mnt);
 		}
 	}
-	/*
-	 * Note: we compose the file handle now, but as the
-	 * dentry may be negative, it may need to be updated.
-	 */
-	err = fh_compose(resfh, exp, dentry, fhp);
+
+	if (dentry->d_inode && dentry->d_inode->i_op &&
+	    dentry->d_inode->i_op->revalidate &&
+	    dentry->d_inode->i_op->revalidate(dentry))
+		err = nfserr_noent;
+	else
+		err = fh_compose(resfh, exp, dentry, fhp);
 	if (!err && !dentry->d_inode)
 		err = nfserr_noent;
 out:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/proc/generic.c linux-2.4.21-pre6/fs/proc/generic.c
--- linux-2.4.20/fs/proc/generic.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/fs/proc/generic.c	2003-03-26 23:49:55.000000000 +0000
@@ -456,7 +456,11 @@
 		ent->data = kmalloc((ent->size=strlen(dest))+1, GFP_KERNEL);
 		if (ent->data) {
 			strcpy((char*)ent->data,dest);
-			proc_register(parent, ent);
+			if (proc_register(parent, ent) < 0) {
+				kfree(ent->data);
+				kfree(ent);
+				ent = NULL;
+			}
 		} else {
 			kfree(ent);
 			ent = NULL;
@@ -473,7 +477,10 @@
 	ent = proc_create(&parent,name,mode,1);
 	if (ent) {
 		ent->rdev = rdev;
-		proc_register(parent, ent);
+		if (proc_register(parent, ent) < 0) {
+			kfree(ent);
+			ent = NULL;
+		}
 	}
 	return ent;
 }
@@ -488,7 +495,10 @@
 		ent->proc_fops = &proc_dir_operations;
 		ent->proc_iops = &proc_dir_inode_operations;
 
-		proc_register(parent, ent);
+		if (proc_register(parent, ent) < 0) {
+			kfree(ent);
+			ent = NULL;
+		}
 	}
 	return ent;
 }
@@ -517,7 +527,10 @@
 			ent->proc_fops = &proc_dir_operations;
 			ent->proc_iops = &proc_dir_inode_operations;
 		}
-		proc_register(parent, ent);
+		if (proc_register(parent, ent) < 0) {
+			kfree(ent);
+			ent = NULL;
+		}
 	}
 	return ent;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/proc/inode.c linux-2.4.21-pre6/fs/proc/inode.c
--- linux-2.4.20/fs/proc/inode.c	2001-11-17 19:24:32.000000000 +0000
+++ linux-2.4.21-pre6/fs/proc/inode.c	2003-03-26 23:49:54.000000000 +0000
@@ -22,7 +22,7 @@
 
 extern void free_proc_entry(struct proc_dir_entry *);
 
-struct proc_dir_entry * de_get(struct proc_dir_entry *de)
+static inline struct proc_dir_entry * de_get(struct proc_dir_entry *de)
 {
 	if (de)
 		atomic_inc(&de->count);
@@ -32,7 +32,7 @@
 /*
  * Decrements the use count and checks for deferred deletion.
  */
-void de_put(struct proc_dir_entry *de)
+static void de_put(struct proc_dir_entry *de)
 {
 	if (de) {	
 		lock_kernel();		
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/proc/proc_misc.c linux-2.4.21-pre6/fs/proc/proc_misc.c
--- linux-2.4.20/fs/proc/proc_misc.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/proc/proc_misc.c	2003-03-26 23:49:08.000000000 +0000
@@ -344,7 +344,7 @@
 			kstat.pswpout,
 			sum
 	);
-#if !defined(CONFIG_ARCH_S390)
+#if !defined(CONFIG_ARCH_S390) && !defined(CONFIG_ALPHA)
 	for (i = 0 ; i < NR_IRQS ; i++)
 		proc_sprintf(page, &off, &len,
 			     " %u", kstat_irqs(i));
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/read_write.c linux-2.4.21-pre6/fs/read_write.c
--- linux-2.4.20/fs/read_write.c	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/fs/read_write.c	2003-03-26 23:49:49.000000000 +0000
@@ -218,7 +218,7 @@
 	typedef ssize_t (*io_fn_t)(struct file *, char *, size_t, loff_t *);
 	typedef ssize_t (*iov_fn_t)(struct file *, const struct iovec *, unsigned long, loff_t *);
 
-	ssize_t tot_len;
+	size_t tot_len;
 	struct iovec iovstack[UIO_FASTIOV];
 	struct iovec *iov=iovstack;
 	ssize_t ret, i;
@@ -259,12 +259,19 @@
 	tot_len = 0;
 	ret = -EINVAL;
 	for (i = 0 ; i < count ; i++) {
-		ssize_t tmp = tot_len;
 		ssize_t len = (ssize_t) iov[i].iov_len;
 		if (len < 0)	/* size_t not fitting an ssize_t .. */
 			goto out;
 		tot_len += len;
-		if (tot_len < tmp) /* maths overflow on the ssize_t */
+		/* We must do this work unsigned - signed overflow is
+		   undefined and gcc 3.2 now uses that fact sometimes... 
+		   
+		   FIXME: put in a proper limits.h for each platform */
+#if BITS_PER_LONG==64
+		if (tot_len > 0x7FFFFFFFFFFFFFFFUL)
+#else
+		if (tot_len > 0x7FFFFFFFUL)
+#endif		
 			goto out;
 	}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/reiserfs/fix_node.c linux-2.4.21-pre6/fs/reiserfs/fix_node.c
--- linux-2.4.20/fs/reiserfs/fix_node.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/reiserfs/fix_node.c	2003-03-26 23:49:24.000000000 +0000
@@ -2059,7 +2059,7 @@
 	    /* getting memory with GFP_KERNEL priority may involve
                balancing now (due to indirect_to_direct conversion on
                dcache shrinking). So, release path and collected
-               resourses here */
+               resources here */
 	    free_buffers_in_tb (tb);
 	    buf = reiserfs_kmalloc(size, GFP_NOFS, tb->tb_sb);
 	    if ( !buf ) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/reiserfs/inode.c linux-2.4.21-pre6/fs/reiserfs/inode.c
--- linux-2.4.20/fs/reiserfs/inode.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/reiserfs/inode.c	2003-03-26 23:49:25.000000000 +0000
@@ -102,9 +102,9 @@
 }
 
 static void add_to_flushlist(struct inode *inode, struct buffer_head *bh) {
-    struct inode *jinode = &(SB_JOURNAL(inode->i_sb)->j_dummy_inode) ;
+    struct reiserfs_journal *j = SB_JOURNAL(inode->i_sb) ;
 
-    buffer_insert_inode_queue(bh, jinode) ;
+    buffer_insert_list(bh, &j->j_dirty_buffers) ;
 }
 
 //
@@ -418,6 +418,7 @@
 			struct buffer_head * bh_result, int create) {
     int ret ;
 
+    bh_result->b_page = NULL;
     ret = reiserfs_get_block(inode, block, bh_result, create) ;
 
     /* don't allow direct io onto tail pages */
@@ -428,6 +429,14 @@
 	reiserfs_unmap_buffer(bh_result);
         ret = -EINVAL ;
     }
+    /* Possible unpacked tail. Flush the data before pages have
+       disappeared */
+    if (inode->u.reiserfs_i.i_flags & i_pack_on_close_mask) {
+	lock_kernel();
+	reiserfs_commit_for_inode(inode);
+	inode->u.reiserfs_i.i_flags &= ~i_pack_on_close_mask;
+	unlock_kernel();
+    }
     return ret ;
 }
 
@@ -566,7 +575,12 @@
 	return ret;
     }
 
-    inode->u.reiserfs_i.i_flags |= i_pack_on_close_mask;
+    /* If file is of such a size, that it might have a tail and tails are enabled
+    ** we should mark it as possibly needing tail packing on close
+    */
+    if ( (have_large_tails (inode->i_sb) && inode->i_size < block_size (inode)*4) ||
+	 (have_small_tails (inode->i_sb) && inode->i_size < block_size(inode)) )
+	inode->u.reiserfs_i.i_flags |= i_pack_on_close_mask;
 
     windex = push_journal_writer("reiserfs_get_block") ;
   
@@ -757,15 +771,21 @@
 	    */
 	    mark_buffer_uptodate (unbh, 1);
 
-	    /* we've converted the tail, so we must 
-	    ** flush unbh before the transaction commits
+	    /* unbh->b_page == NULL in case of DIRECT_IO request, this means
+	       buffer will disappear shortly, so it should not be added to
+	       any of our lists.
 	    */
-	    add_to_flushlist(inode, unbh) ;
+	    if ( unbh->b_page ) {
+		/* we've converted the tail, so we must 
+		** flush unbh before the transaction commits
+		*/
+		add_to_flushlist(inode, unbh) ;
 
-	    /* mark it dirty now to prevent commit_write from adding
-	     ** this buffer to the inode's dirty buffer list
-	     */
-	    __mark_buffer_dirty(unbh) ;
+		/* mark it dirty now to prevent commit_write from adding
+		 ** this buffer to the inode's dirty buffer list
+		 */
+		__mark_buffer_dirty(unbh) ;
+	    }
 
 	    //inode->i_blocks += inode->i_sb->s_blocksize / 512;
 	    //mark_tail_converted (inode);
@@ -1463,13 +1483,22 @@
 /* inserts the stat data into the tree, and then calls
    reiserfs_new_directory (to insert ".", ".." item if new object is
    directory) or reiserfs_new_symlink (to insert symlink body if new
-   object is symlink) or nothing (if new object is regular file) */
-struct inode * reiserfs_new_inode (struct reiserfs_transaction_handle *th,
-				   struct inode * dir, int mode, 
-				   const char * symname, 
-				   int i_size, /* 0 for regular, EMTRY_DIR_SIZE for dirs,
-						  strlen (symname) for symlinks)*/
-				   struct dentry *dentry, struct inode *inode, int * err)
+   object is symlink) or nothing (if new object is regular file)
+
+   NOTE! uid and gid must already be set in the inode.  If we return
+   non-zero due to an error, we have to drop the quota previously allocated
+   for the fresh inode.  This can only be done outside a transaction, so
+   if we return non-zero, we also end the transaction.
+
+   */
+int reiserfs_new_inode (struct reiserfs_transaction_handle *th,
+				struct inode * dir, int mode,
+				const char * symname,
+				/* 0 for regular, EMTRY_DIR_SIZE for dirs,
+				   strlen (symname) for symlinks) */
+				int i_size,
+				struct dentry *dentry,
+				struct inode *inode)
 {
     struct super_block * sb;
     INITIALIZE_PATH (path_to_key);
@@ -1477,11 +1506,11 @@
     struct item_head ih;
     struct stat_data sd;
     int retval;
+    int err ;
   
     if (!dir || !dir->i_nlink) {
-	*err = -EPERM;
-	iput(inode) ;
-	return NULL;
+	err = -EPERM ;
+	goto out_bad_inode ;
     }
 
     sb = dir->i_sb;
@@ -1489,13 +1518,16 @@
 	    dir -> u.reiserfs_i.i_attrs & REISERFS_INHERIT_MASK;
     sd_attrs_to_i_attrs( inode -> u.reiserfs_i.i_attrs, inode );
 
+    /* symlink cannot be immutable or append only, right? */
+    if( S_ISLNK( inode -> i_mode ) )
+	    inode -> i_flags &= ~ ( S_IMMUTABLE | S_APPEND );
+
     /* item head of new item */
     ih.ih_key.k_dir_id = INODE_PKEY (dir)->k_objectid;
     ih.ih_key.k_objectid = cpu_to_le32 (reiserfs_get_unused_objectid (th));
     if (!ih.ih_key.k_objectid) {
-	iput(inode) ;
-	*err = -ENOMEM;
-	return NULL;
+	err = -ENOMEM ;
+	goto out_bad_inode ;
     }
     if (old_format_only (sb))
       /* not a perfect generation count, as object ids can be reused, but this
@@ -1511,12 +1543,24 @@
 #else
       inode->i_generation = ++event;
 #endif
+    /* fill stat data */
+    inode->i_nlink = (S_ISDIR (mode) ? 2 : 1);
+
+    /* uid and gid must already be set by the caller for quota init */
+
+    inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+    inode->i_size = i_size;
+    inode->i_blocks = (inode->i_size + 511) >> 9;
+    inode->u.reiserfs_i.i_first_direct_byte = S_ISLNK(mode) ? 1 : 
+      U32_MAX/*NO_BYTES_IN_DIRECT_ITEM*/;
+
+    INIT_LIST_HEAD(&inode->u.reiserfs_i.i_prealloc_list) ;
+
     if (old_format_only (sb))
 	make_le_item_head (&ih, 0, KEY_FORMAT_3_5, SD_OFFSET, TYPE_STAT_DATA, SD_V1_SIZE, MAX_US_INT);
     else
 	make_le_item_head (&ih, 0, KEY_FORMAT_3_6, SD_OFFSET, TYPE_STAT_DATA, SD_SIZE, MAX_US_INT);
 
-
     /* key to search for correct place for new stat data */
     _make_cpu_key (&key, KEY_FORMAT_3_6, le32_to_cpu (ih.ih_key.k_dir_id),
 		   le32_to_cpu (ih.ih_key.k_objectid), SD_OFFSET, TYPE_STAT_DATA, 3/*key length*/);
@@ -1524,47 +1568,21 @@
     /* find proper place for inserting of stat data */
     retval = search_item (sb, &key, &path_to_key);
     if (retval == IO_ERROR) {
-	iput (inode);
-	*err = -EIO;
-	return NULL;
+	err = -EIO;
+	goto out_bad_inode;
     }
     if (retval == ITEM_FOUND) {
 	pathrelse (&path_to_key);
-	iput (inode);
-	*err = -EEXIST;
-	return NULL;
+	err = -EEXIST;
+	goto out_bad_inode;
     }
 
-    /* fill stat data */
-    inode->i_mode = mode;
-    inode->i_nlink = (S_ISDIR (mode) ? 2 : 1);
-    inode->i_uid = current->fsuid;
-    if (dir->i_mode & S_ISGID) {
-	inode->i_gid = dir->i_gid;
-	if (S_ISDIR(mode))
-	    inode->i_mode |= S_ISGID;
-    } else
-	inode->i_gid = current->fsgid;
-
-    /* symlink cannot be immutable or append only, right? */
-    if( S_ISLNK( inode -> i_mode ) )
-	    inode -> i_flags &= ~ ( S_IMMUTABLE | S_APPEND );
-
-    inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
-    inode->i_size = i_size;
-    inode->i_blocks = (inode->i_size + 511) >> 9;
-    inode->u.reiserfs_i.i_first_direct_byte = S_ISLNK(mode) ? 1 : 
-      U32_MAX/*NO_BYTES_IN_DIRECT_ITEM*/;
-
-    INIT_LIST_HEAD(&inode->u.reiserfs_i.i_prealloc_list) ;
-
     if (old_format_only (sb)) {
 	if (inode->i_uid & ~0xffff || inode->i_gid & ~0xffff) {
 	    pathrelse (&path_to_key);
 	    /* i_uid or i_gid is too big to be stored in stat data v3.5 */
-	    iput (inode);
-	    *err = -EINVAL;
-	    return NULL;
+	    err = -EINVAL;
+	    goto out_bad_inode;
 	}
 	inode2sd_v1 (&sd, inode);
     } else
@@ -1595,10 +1613,9 @@
 #endif
     retval = reiserfs_insert_item (th, &path_to_key, &key, &ih, (char *)(&sd));
     if (retval) {
-	iput (inode);
-	*err = retval;
 	reiserfs_check_path(&path_to_key) ;
-	return NULL;
+	err = retval;
+	goto out_bad_inode;
     }
 
 #ifdef DISPLACE_NEW_PACKING_LOCALITIES
@@ -1617,19 +1634,30 @@
 	retval = reiserfs_new_symlink (th, &ih, &path_to_key, symname, i_size);
     }
     if (retval) {
-      inode->i_nlink = 0;
-	iput (inode);
-	*err = retval;
+	err = retval;
 	reiserfs_check_path(&path_to_key) ;
-	return NULL;
+	journal_end(th, th->t_super, th->t_blocks_allocated) ;
+	goto out_inserted_sd;
     }
 
     insert_inode_hash (inode);
-    // we do not mark inode dirty: on disk content matches to the
-    // in-core one
+    reiserfs_update_sd(th, inode) ;
     reiserfs_check_path(&path_to_key) ;
 
-    return inode;
+    return 0;
+out_bad_inode:
+    /* Invalidate the object, nothing was inserted yet */
+    INODE_PKEY(inode)->k_objectid = 0;
+
+    /* dquot_drop must be done outside a transaction */
+    journal_end(th, th->t_super, th->t_blocks_allocated) ;
+    make_bad_inode(inode);
+
+out_inserted_sd:
+    inode->i_nlink = 0;
+    th->t_trans_id = 0 ; /* so the caller can't use this handle later */
+    iput(inode) ;
+    return err;
 }
 
 /*
@@ -2054,6 +2082,13 @@
     if (pos > inode->i_size) {
 	struct reiserfs_transaction_handle th ;
 	lock_kernel();
+	/* If the file have grown beyond the border where it
+	   can have a tail, unmark it as needing a tail
+	   packing */
+	if ( (have_large_tails (inode->i_sb) && inode->i_size < block_size (inode)*4) ||
+	     (have_small_tails (inode->i_sb) && inode->i_size < block_size(inode)) )
+	    inode->u.reiserfs_i.i_flags &= ~i_pack_on_close_mask;
+
 	journal_begin(&th, inode->i_sb, 1) ;
 	reiserfs_update_inode_transaction(inode) ;
 	inode->i_size = pos ;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/reiserfs/journal.c linux-2.4.21-pre6/fs/reiserfs/journal.c
--- linux-2.4.20/fs/reiserfs/journal.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/reiserfs/journal.c	2003-03-26 23:49:40.000000000 +0000
@@ -1401,6 +1401,10 @@
 		     *newest_mount_id) ;
       return -1 ;
     }
+    if ( le32_to_cpu(desc->j_len) > sb_journal_trans_max(SB_DISK_SUPER_BLOCK(p_s_sb)) ) {
+      reiserfs_warning("journal-2018: Bad transaction length %d encountered, ignoring transaction\n", le32_to_cpu(desc->j_len));
+      return -1 ;
+    }
     offset = d_bh->b_blocknr - reiserfs_get_journal_block(p_s_sb) ;
 
     /* ok, we have a journal description block, lets see if the transaction was valid */
@@ -1416,11 +1420,12 @@
 		     le32_to_cpu(commit->j_trans_id), 
 		     le32_to_cpu(commit->j_len));
       brelse(c_bh) ;
-      if (oldest_invalid_trans_id)
-        *oldest_invalid_trans_id = le32_to_cpu(desc->j_trans_id) ;
+      if (oldest_invalid_trans_id) {
+	*oldest_invalid_trans_id = le32_to_cpu(desc->j_trans_id) ;
 	reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1004: "
 	               "transaction_is_valid setting oldest invalid trans_id "
 		       "to %d\n", le32_to_cpu(desc->j_trans_id)) ;
+	}
       return -1; 
     }
     brelse(c_bh) ;
@@ -1517,9 +1522,14 @@
     } else {
       real_blocks[i] = sb_getblk(p_s_sb, le32_to_cpu(commit->j_realblock[i - JOURNAL_TRANS_HALF])) ;
     }
+    if ( real_blocks[i]->b_blocknr > SB_BLOCK_COUNT(p_s_sb) ) {
+      reiserfs_warning("journal-1207: REPLAY FAILURE fsck required! Block to replay is outside of filesystem\n");
+      goto abort_replay;
+    }
     if (real_blocks[i]->b_blocknr >= reiserfs_get_journal_block(p_s_sb) &&
         real_blocks[i]->b_blocknr < (reiserfs_get_journal_block(p_s_sb)+JOURNAL_BLOCK_COUNT)) {
       reiserfs_warning("journal-1204: REPLAY FAILURE fsck required! Trying to replay onto a log block\n") ;
+abort_replay:
       brelse_array(log_blocks, i) ;
       brelse_array(real_blocks, i) ;
       brelse(c_bh) ;
@@ -1937,7 +1947,7 @@
   memset(journal_writers, 0, sizeof(char *) * 512) ; /* debug code */
 
   INIT_LIST_HEAD(&SB_JOURNAL(p_s_sb)->j_bitmap_nodes) ;
-  INIT_LIST_HEAD(&(SB_JOURNAL(p_s_sb)->j_dummy_inode.i_dirty_buffers)) ;
+  INIT_LIST_HEAD(&SB_JOURNAL(p_s_sb)->j_dirty_buffers) ;
   reiserfs_allocate_list_bitmaps(p_s_sb, SB_JOURNAL(p_s_sb)->j_list_bitmap, 
                                  SB_BMAP_NR(p_s_sb)) ;
   allocate_bitmap_nodes(p_s_sb) ;
@@ -2933,7 +2943,7 @@
   SB_JOURNAL_LIST_INDEX(p_s_sb) = jindex ;
 
   /* write any buffers that must hit disk before this commit is done */
-  fsync_inode_buffers(&(SB_JOURNAL(p_s_sb)->j_dummy_inode)) ;
+  fsync_buffers_list(&(SB_JOURNAL(p_s_sb)->j_dirty_buffers)) ;
 
   /* honor the flush and async wishes from the caller */
   if (flush) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/reiserfs/namei.c linux-2.4.21-pre6/fs/reiserfs/namei.c
--- linux-2.4.20/fs/reiserfs/namei.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/reiserfs/namei.c	2003-03-26 23:49:40.000000000 +0000
@@ -488,27 +488,58 @@
     return 0;
 }
 
+/* quota utility function, call if you've had to abort after calling
+** new_inode_init, and have not called reiserfs_new_inode yet.
+** This should only be called on inodes that do not hav stat data
+** inserted into the tree yet.
+*/
+static int drop_new_inode(struct inode *inode) {
+    make_bad_inode(inode) ;
+    iput(inode) ;
+    return 0 ;
+}
+
+/* utility function that does setup for reiserfs_new_inode.  
+** DQUOT_ALLOC_INODE cannot be called inside a transaction, so we had
+** to pull some bits of reiserfs_new_inode out into this func.
+*/
+static int new_inode_init(struct inode *inode, struct inode *dir, int mode) {
 
+    /* the quota init calls have to know who to charge the quota to, so
+    ** we have to set uid and gid here
+    */
+    inode->i_uid = current->fsuid;
+    inode->i_mode = mode;
+
+    if (dir->i_mode & S_ISGID) {
+        inode->i_gid = dir->i_gid;
+        if (S_ISDIR(mode))
+            inode->i_mode |= S_ISGID;
+    } else
+        inode->i_gid = current->fsgid;
+
+    return 0 ;
+}
+  
 static int reiserfs_create (struct inode * dir, struct dentry *dentry, int mode)
 {
     int retval;
     struct inode * inode;
-    int windex ;
     int jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 ;
     struct reiserfs_transaction_handle th ;
 
-
     if (!(inode = new_inode(dir->i_sb))) {
 	return -ENOMEM ;
     }
+    retval = new_inode_init(inode, dir, mode) ;
+    if (retval)
+	return retval ;
+
     journal_begin(&th, dir->i_sb, jbegin_count) ;
     th.t_caller = "create" ;
-    windex = push_journal_writer("reiserfs_create") ;
-    inode = reiserfs_new_inode (&th, dir, mode, 0, 0/*i_size*/, dentry, inode, &retval);
-    if (!inode) {
-	pop_journal_writer(windex) ;
-	journal_end(&th, dir->i_sb, jbegin_count) ;
-	return retval;
+    retval = reiserfs_new_inode (&th, dir, mode, 0, 0/*i_size*/, dentry, inode);
+    if (retval) {
+	goto out_failed ;
     }
 	
     inode->i_op = &reiserfs_file_inode_operations;
@@ -520,20 +551,19 @@
     if (retval) {
 	inode->i_nlink--;
 	reiserfs_update_sd (&th, inode);
-	pop_journal_writer(windex) ;
-	// FIXME: should we put iput here and have stat data deleted
-	// in the same transactioin
 	journal_end(&th, dir->i_sb, jbegin_count) ;
-	iput (inode);
-	return retval;
+	iput(inode) ;
+	goto out_failed ;
     }
     reiserfs_update_inode_transaction(inode) ;
     reiserfs_update_inode_transaction(dir) ;
 
     d_instantiate(dentry, inode);
-    pop_journal_writer(windex) ;
     journal_end(&th, dir->i_sb, jbegin_count) ;
     return 0;
+
+out_failed:
+    return retval ;
 }
 
 
@@ -541,21 +571,21 @@
 {
     int retval;
     struct inode * inode;
-    int windex ;
     struct reiserfs_transaction_handle th ;
     int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3; 
 
     if (!(inode = new_inode(dir->i_sb))) {
 	return -ENOMEM ;
     }
+    retval = new_inode_init(inode, dir, mode) ;
+    if (retval)
+        return retval ;
+
     journal_begin(&th, dir->i_sb, jbegin_count) ;
-    windex = push_journal_writer("reiserfs_mknod") ;
 
-    inode = reiserfs_new_inode (&th, dir, mode, 0, 0/*i_size*/, dentry, inode, &retval);
-    if (!inode) {
-	pop_journal_writer(windex) ;
-	journal_end(&th, dir->i_sb, jbegin_count) ;
-	return retval;
+    retval = reiserfs_new_inode(&th, dir, mode, 0, 0/*i_size*/, dentry, inode);
+    if (retval) {
+	goto out_failed; 
     }
 
     init_special_inode(inode, mode, rdev) ;
@@ -571,16 +601,17 @@
     if (retval) {
 	inode->i_nlink--;
 	reiserfs_update_sd (&th, inode);
-	pop_journal_writer(windex) ;
 	journal_end(&th, dir->i_sb, jbegin_count) ;
-	iput (inode);
-	return retval;
+	iput(inode) ;
+        goto out_failed; 
     }
 
     d_instantiate(dentry, inode);
-    pop_journal_writer(windex) ;
     journal_end(&th, dir->i_sb, jbegin_count) ;
     return 0;
+
+out_failed:
+    return retval ;
 }
 
 
@@ -588,15 +619,18 @@
 {
     int retval;
     struct inode * inode;
-    int windex ;
     struct reiserfs_transaction_handle th ;
     int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3; 
 
+    mode = S_IFDIR | mode;
     if (!(inode = new_inode(dir->i_sb))) {
 	return -ENOMEM ;
     }
+    retval = new_inode_init(inode, dir, mode) ;
+    if (retval)
+	return retval ;
+
     journal_begin(&th, dir->i_sb, jbegin_count) ;
-    windex = push_journal_writer("reiserfs_mkdir") ;
 
     /* inc the link count now, so another writer doesn't overflow it while
     ** we sleep later on.
@@ -607,15 +641,13 @@
     /* set flag that new packing locality created and new blocks for the content     * of that directory are not displaced yet */
     dir->u.reiserfs_i.new_packing_locality = 1;
 #endif
-    mode = S_IFDIR | mode;
-    inode = reiserfs_new_inode (&th, dir, mode, 0/*symlink*/,
-				old_format_only (dir->i_sb) ? EMPTY_DIR_SIZE_V1 : EMPTY_DIR_SIZE,
-				dentry, inode, &retval);
-    if (!inode) {
-	pop_journal_writer(windex) ;
+    retval = reiserfs_new_inode(&th, dir, mode, 0/*symlink*/,
+				old_format_only (dir->i_sb) ?
+				EMPTY_DIR_SIZE_V1 : EMPTY_DIR_SIZE,
+				dentry, inode) ;
+    if (retval) {
 	dir->i_nlink-- ;
-	journal_end(&th, dir->i_sb, jbegin_count) ;
-	return retval;
+	goto out_failed ;
     }
     reiserfs_update_inode_transaction(inode) ;
     reiserfs_update_inode_transaction(dir) ;
@@ -630,19 +662,20 @@
 	inode->i_nlink = 0;
 	DEC_DIR_INODE_NLINK(dir);
 	reiserfs_update_sd (&th, inode);
-	pop_journal_writer(windex) ;
 	journal_end(&th, dir->i_sb, jbegin_count) ;
-	iput (inode);
-	return retval;
+	iput(inode) ;
+	goto out_failed ;
     }
 
     // the above add_entry did not update dir's stat data
     reiserfs_update_sd (&th, dir);
 
     d_instantiate(dentry, inode);
-    pop_journal_writer(windex) ;
     journal_end(&th, dir->i_sb, jbegin_count) ;
     return 0;
+
+out_failed:
+    return retval ;
 }
 
 static inline int reiserfs_empty_dir(struct inode *inode) {
@@ -820,7 +853,7 @@
     struct inode * inode;
     char * name;
     int item_len;
-    int windex ;
+    int mode = S_IFLNK | S_IRWXUGO ;
     struct reiserfs_transaction_handle th ;
     int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3; 
 
@@ -828,31 +861,34 @@
     if (!(inode = new_inode(parent_dir->i_sb))) {
   	return -ENOMEM ;
     }
+    retval = new_inode_init(inode, parent_dir, mode) ;
+    if (retval) {
+	return retval ;
+    }
 
     item_len = ROUND_UP (strlen (symname));
     if (item_len > MAX_DIRECT_ITEM_LEN (parent_dir->i_sb->s_blocksize)) {
-	iput(inode) ;
-	return -ENAMETOOLONG;
+	retval = -ENAMETOOLONG;
+	drop_new_inode(inode) ;
+	goto out_failed ;
     }
   
     name = reiserfs_kmalloc (item_len, GFP_NOFS, parent_dir->i_sb);
     if (!name) {
-	iput(inode) ;
-	return -ENOMEM;
+	retval = -ENOMEM;
+	drop_new_inode(inode) ;
+	goto out_failed ;
     }
     memcpy (name, symname, strlen (symname));
     padd_item (name, item_len, strlen (symname));
 
     journal_begin(&th, parent_dir->i_sb, jbegin_count) ;
-    windex = push_journal_writer("reiserfs_symlink") ;
 
-    inode = reiserfs_new_inode (&th, parent_dir, S_IFLNK | S_IRWXUGO, name, strlen (symname), dentry,
-				inode, &retval);
+    retval = reiserfs_new_inode(&th, parent_dir, mode, name,
+				strlen(symname), dentry, inode) ;
     reiserfs_kfree (name, item_len, parent_dir->i_sb);
-    if (inode == 0) { /* reiserfs_new_inode iputs for us */
-	pop_journal_writer(windex) ;
-	journal_end(&th, parent_dir->i_sb, jbegin_count) ;
-	return retval;
+    if (retval) {
+	goto out_failed ;
     }
 
     reiserfs_update_inode_transaction(inode) ;
@@ -870,16 +906,17 @@
     if (retval) {
 	inode->i_nlink--;
 	reiserfs_update_sd (&th, inode);
-	pop_journal_writer(windex) ;
 	journal_end(&th, parent_dir->i_sb, jbegin_count) ;
-	iput (inode);
-	return retval;
+	iput(inode) ;
+	goto out_failed ;
     }
 
     d_instantiate(dentry, inode);
-    pop_journal_writer(windex) ;
     journal_end(&th, parent_dir->i_sb, jbegin_count) ;
     return 0;
+
+out_failed:
+    return retval ;
 }
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/reiserfs/stree.c linux-2.4.21-pre6/fs/reiserfs/stree.c
--- linux-2.4.20/fs/reiserfs/stree.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/reiserfs/stree.c	2003-03-26 23:49:50.000000000 +0000
@@ -1125,6 +1125,21 @@
 		journal_mark_dirty (th, p_s_sb, p_s_bh);
 		inode->i_blocks -= p_s_sb->s_blocksize / 512;
 		reiserfs_free_block(th, tmp);
+		/* In case of big fragmentation it is possible that each block
+		   freed will cause dirtying of one more bitmap and then we will
+		   quickly overflow our transaction space. This is a
+		   counter-measure against that scenario */
+		if (journal_transaction_should_end(th, th->t_blocks_allocated)) {
+		    int orig_len_alloc = th->t_blocks_allocated ;
+		    pathrelse(p_s_path) ;
+
+		    journal_end(th, p_s_sb, orig_len_alloc) ;
+		    journal_begin(th, p_s_sb, orig_len_alloc) ;
+		    reiserfs_update_inode_transaction(inode) ;
+		    need_research = 1;
+		    break;
+		}
+
 		if ( item_moved (&s_ih, p_s_path) )  {
 			need_research = 1;
 			break ;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/reiserfs/super.c linux-2.4.21-pre6/fs/reiserfs/super.c
--- linux-2.4.20/fs/reiserfs/super.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/reiserfs/super.c	2003-03-26 23:49:35.000000000 +0000
@@ -5,6 +5,7 @@
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/sched.h>
+#include <linux/blkdev.h>
 #include <linux/vmalloc.h>
 #include <asm/uaccess.h>
 #include <linux/reiserfs_fs.h>
@@ -420,7 +421,7 @@
 
 /* possible values for "-o hash=" and bits which are to be set in s_mount_opt
    of reiserfs specific part of in-core super block */
-const arg_desc_t hash[] = {
+static const arg_desc_t hash[] = {
     {"rupasov", FORCE_RUPASOV_HASH},
     {"tea", FORCE_TEA_HASH},
     {"r5", FORCE_R5_HASH},
@@ -431,7 +432,7 @@
 
 /* possible values for "-o block-allocator=" and bits which are to be set in
    s_mount_opt of reiserfs specific part of in-core super block */
-const arg_desc_t balloc[] = {
+static const arg_desc_t balloc[] = {
     {"noborder", REISERFS_NO_BORDER},
     {"no_unhashed_relocation", REISERFS_NO_UNHASHED_RELOCATION},
     {"hashed_relocation", REISERFS_HASHED_RELOCATION},
@@ -439,7 +440,7 @@
     {NULL, 0}
 };
 
-const arg_desc_t tails[] = {
+static const arg_desc_t tails[] = {
     {"on", REISERFS_LARGETAIL},
     {"off", -1},
     {"small", REISERFS_SMALLTAIL},
@@ -865,7 +866,7 @@
     brelse (bh);
 
     if (s->s_blocksize != 4096) {
-	printk("Unsupported reiserfs blocksize: %d on %s, only 4096 bytes "
+	printk("Unsupported reiserfs blocksize: %ld on %s, only 4096 bytes "
 	       "blocksize is supported.\n", s->s_blocksize, kdevname (s->s_dev));
 	return 1;
     }
@@ -941,8 +942,7 @@
     ll_rw_block(READ, 1, &(SB_AP_BITMAP(s)[i].bh)) ;
     wait_on_buffer(SB_AP_BITMAP(s)[i].bh) ;
     if (!buffer_uptodate(SB_AP_BITMAP(s)[i].bh)) {
-      printk("reread_meta_blocks, error reading bitmap block number %d at
-      %ld\n", i, SB_AP_BITMAP(s)[i].bh->b_blocknr) ;
+      printk("reread_meta_blocks, error reading bitmap block number %d at %ld\n", i, SB_AP_BITMAP(s)[i].bh->b_blocknr) ;
       return 1 ;
     }
   }
@@ -1112,7 +1112,6 @@
     struct inode *root_inode;
     kdev_t dev = s->s_dev;
     int j;
-    extern int *blksize_size[];
     struct reiserfs_transaction_handle th ;
     int old_format = 0;
     unsigned long blocks;
@@ -1161,6 +1160,16 @@
 
     rs = SB_DISK_SUPER_BLOCK (s);
 
+    /* Let's do basic sanity check to verify that underlying device is not
+       smaller than the filesystem. If the check fails then abort and scream,
+       because bad stuff will happen otherwise. */
+   if ( blk_size[MAJOR(dev)][MINOR(dev)] < sb_block_count(rs)*(sb_blocksize(rs)>>10) ) {
+	printk("Filesystem on %s cannot be mounted because it is bigger than the device\n", kdevname(dev));
+	printk("You may need to run fsck or increase size of your LVM partition\n");
+	printk("Or may be you forgot to reboot after fdisk when it told you to\n");
+	return NULL;
+    }
+
     s->u.reiserfs_sb.s_mount_state = SB_REISERFS_STATE(s);
     s->u.reiserfs_sb.s_mount_state = REISERFS_VALID_FS ;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/reiserfs/tail_conversion.c linux-2.4.21-pre6/fs/reiserfs/tail_conversion.c
--- linux-2.4.20/fs/reiserfs/tail_conversion.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/reiserfs/tail_conversion.c	2003-03-26 23:49:39.000000000 +0000
@@ -105,8 +105,10 @@
 	/* we only send the unbh pointer if the buffer is not up to date.
 	** this avoids overwriting good data from writepage() with old data
 	** from the disk or buffer cache
+	** Special case: unbh->b_page will be NULL if we are coming through
+	** DIRECT_IO handler here.
 	*/
-	if (buffer_uptodate(unbh) || Page_Uptodate(unbh->b_page)) {
+	if ( !unbh->b_page || buffer_uptodate(unbh) || Page_Uptodate(unbh->b_page)) {
 	    up_to_date_bh = NULL ;
 	} else {
 	    up_to_date_bh = unbh ;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/select.c linux-2.4.21-pre6/fs/select.c
--- linux-2.4.20/fs/select.c	2001-09-10 20:04:33.000000000 +0000
+++ linux-2.4.21-pre6/fs/select.c	2003-03-26 23:48:58.000000000 +0000
@@ -417,7 +417,7 @@
 	int nchunks, nleft;
 
 	/* Do a sanity check on nfds ... */
-	if (nfds > NR_OPEN)
+	if (nfds > current->files->max_fdset && nfds > OPEN_MAX)
 		return -EINVAL;
 
 	if (timeout) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/seq_file.c linux-2.4.21-pre6/fs/seq_file.c
--- linux-2.4.20/fs/seq_file.c	2001-11-18 02:16:22.000000000 +0000
+++ linux-2.4.21-pre6/fs/seq_file.c	2003-03-26 23:49:50.000000000 +0000
@@ -94,8 +94,10 @@
 		m->buf = kmalloc(m->size <<= 1, GFP_KERNEL);
 		if (!m->buf)
 			goto Enomem;
+		m->count = 0;
 	}
 	m->op->stop(m, p);
+	m->count = 0;
 	goto Done;
 Fill:
 	/* they want more? let's try to get some more */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/fs/super.c linux-2.4.21-pre6/fs/super.c
--- linux-2.4.20/fs/super.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/fs/super.c	2003-03-26 23:49:35.000000000 +0000
@@ -262,6 +262,7 @@
  */
 static struct super_block *alloc_super(void)
 {
+	static struct super_operations empty_sops = {};
 	struct super_block *s = kmalloc(sizeof(struct super_block),  GFP_USER);
 	if (s) {
 		memset(s, 0, sizeof(struct super_block));
@@ -279,6 +280,7 @@
 		sema_init(&s->s_dquot.dqio_sem, 1);
 		sema_init(&s->s_dquot.dqoff_sem, 1);
 		s->s_maxbytes = MAX_NON_LFS;
+		s->s_op = &empty_sops;
 	}
 	return s;
 }
@@ -445,7 +447,7 @@
  * hold up the sync while mounting a device. (The newly
  * mounted device won't need syncing.)
  */
-void sync_supers(kdev_t dev)
+void sync_supers(kdev_t dev, int wait)
 {
 	struct super_block * sb;
 
@@ -454,6 +456,8 @@
 		if (sb) {
 			if (sb->s_dirt)
 				write_super(sb);
+			if (wait && sb->s_op && sb->s_op->sync_fs)
+				sb->s_op->sync_fs(sb);
 			drop_super(sb);
 		}
 		return;
@@ -467,6 +471,8 @@
 			spin_unlock(&sb_lock);
 			down_read(&sb->s_umount);
 			write_super(sb);
+			if (wait && sb->s_root && sb->s_op && sb->s_op->sync_fs)
+				sb->s_op->sync_fs(sb);
 			drop_super(sb);
 			goto restart;
 		} else
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-alpha/agp_backend.h linux-2.4.21-pre6/include/asm-alpha/agp_backend.h
--- linux-2.4.20/include/asm-alpha/agp_backend.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-alpha/agp_backend.h	2003-03-26 23:49:25.000000000 +0000
@@ -0,0 +1,43 @@
+#ifndef _ALPHA_AGP_BACKEND_H
+#define _ALPHA_AGP_BACKEND_H 1
+
+typedef	union _alpha_agp_mode {
+	struct {
+		u32 rate : 3;
+		u32 reserved0 : 1;
+		u32 fw : 1;
+		u32 fourgb : 1;
+		u32 reserved1 : 2;
+		u32 enable : 1;
+		u32 sba : 1;
+		u32 reserved2 : 14;
+		u32 rq : 8;
+	} bits;
+	u32 lw;
+} alpha_agp_mode;
+
+typedef struct _alpha_agp_info {
+	enum chipset_type type;
+	struct pci_controller *hose;
+	struct {
+		dma_addr_t bus_base;
+		unsigned long size;
+		void *sysdata;
+	} aperture;
+	alpha_agp_mode capability;
+	alpha_agp_mode mode;
+	void *private;
+	struct alpha_agp_ops *ops;
+} alpha_agp_info;
+
+struct alpha_agp_ops {
+	int (*setup)(alpha_agp_info *);
+	void (*cleanup)(alpha_agp_info *);
+	int (*configure)(alpha_agp_info *);
+	int (*bind)(alpha_agp_info *, off_t, agp_memory *);
+	int (*unbind)(alpha_agp_info *, off_t, agp_memory *);
+	unsigned long (*translate)(alpha_agp_info *, dma_addr_t);
+};
+
+
+#endif /* _ALPHA_AGP_BACKEND_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-alpha/console.h linux-2.4.21-pre6/include/asm-alpha/console.h
--- linux-2.4.20/include/asm-alpha/console.h	2001-08-12 17:51:41.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-alpha/console.h	2003-03-26 23:49:20.000000000 +0000
@@ -10,6 +10,8 @@
 #define CCB_SET_TERM_INT	0x04
 #define CCB_SET_TERM_CTL	0x05
 #define CCB_PROCESS_KEYCODE	0x06
+#define CCB_OPEN_CONSOLE	0x07
+#define CCB_CLOSE_CONSOLE	0x08
 
 #define CCB_OPEN		0x10
 #define CCB_CLOSE		0x11
@@ -47,6 +49,9 @@
 #ifdef __KERNEL__
 #ifndef __ASSEMBLY__
 extern long callback_puts(long unit, const char *s, long length);
+extern long callback_getc(long unit);
+extern long callback_open_console(void);
+extern long callback_close_console(void);
 extern long callback_open(const char *device, long length);
 extern long callback_close(long unit);
 extern long callback_read(long channel, long count, const char *buf, long lbn);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-alpha/core_cia.h linux-2.4.21-pre6/include/asm-alpha/core_cia.h
--- linux-2.4.20/include/asm-alpha/core_cia.h	2001-11-09 21:45:35.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-alpha/core_cia.h	2003-03-26 23:48:57.000000000 +0000
@@ -202,6 +202,10 @@
 #define CIA_IOC_PCI_W3_MASK		(IDENT_ADDR + 0x8760000740UL)
 #define CIA_IOC_PCI_T3_BASE		(IDENT_ADDR + 0x8760000780UL)
 
+#define CIA_IOC_PCI_Wn_BASE(N)	  (IDENT_ADDR + 0x8760000400UL + (N)*0x100)
+#define CIA_IOC_PCI_Wn_MASK(N)	  (IDENT_ADDR + 0x8760000440UL + (N)*0x100)
+#define CIA_IOC_PCI_Tn_BASE(N)	  (IDENT_ADDR + 0x8760000480UL + (N)*0x100)
+
 #define CIA_IOC_PCI_W_DAC		(IDENT_ADDR + 0x87600007C0UL)
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-alpha/core_irongate.h linux-2.4.21-pre6/include/asm-alpha/core_irongate.h
--- linux-2.4.20/include/asm-alpha/core_irongate.h	2001-11-09 21:45:35.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-alpha/core_irongate.h	2003-03-26 23:49:25.000000000 +0000
@@ -50,13 +50,14 @@
 
 	igcsr32 bacsr10;		/* 0x40 - base address chip selects */
 	igcsr32 bacsr32;		/* 0x44 - base address chip selects */
-	igcsr32 bacsr54;		/* 0x48 - base address chip selects */
+	igcsr32 bacsr54_eccms761;	/* 0x48 - 751: base addr. chip selects
+						  761: ECC, mode/status */
 
 	igcsr32 rsrvd2[1];		/* 0x4C-0x4F reserved */
 
 	igcsr32 drammap;		/* 0x50 - address mapping control */
 	igcsr32 dramtm;			/* 0x54 - timing, driver strength */
-	igcsr32 dramms;			/* 0x58 - ECC, mode/status */
+	igcsr32 dramms;			/* 0x58 - DRAM mode/status */
 
 	igcsr32 rsrvd3[1];		/* 0x5C-0x5F reserved */
 
@@ -73,7 +74,10 @@
 	igcsr32 pciarb;			/* 0x84 - PCI arbitration control */
 	igcsr32 pcicfg;			/* 0x88 - PCI config status */
 
-	igcsr32 rsrvd6[5];		/* 0x8C-0x9F reserved */
+	igcsr32 rsrvd6[4];		/* 0x8C-0x9B reserved */
+
+	igcsr32 pci_mem;		/* 0x9C - PCI top of memory,
+						  761 only */
 
 	/* AGP (bus 1) control registers */
 	igcsr32 agpcap;			/* 0xA0 - AGP Capability Identifier */
@@ -102,6 +106,7 @@
 
 } Irongate1;
 
+extern igcsr32 *IronECC;
 
 /*
  * Memory spaces:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-alpha/core_marvel.h linux-2.4.21-pre6/include/asm-alpha/core_marvel.h
--- linux-2.4.20/include/asm-alpha/core_marvel.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-alpha/core_marvel.h	2003-03-26 23:49:06.000000000 +0000
@@ -0,0 +1,579 @@
+/*
+ * Marvel systems use the IO7 I/O chip provides PCI/PCIX/AGP access
+ *
+ * This file is based on:
+ *
+ * Marvel / EV7 System Programmer's Manual
+ * Revision 1.00
+ * 14 May 2001
+ */
+
+#ifndef __ALPHA_MARVEL__H__
+#define __ALPHA_MARVEL__H__
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+
+#include <asm/compiler.h>
+
+#define MARVEL_MAX_PIDS		 32 /* as long as we rely on 43-bit superpage */
+#define MARVEL_IRQ_VEC_PE_SHIFT	(10)
+#define MARVEL_IRQ_VEC_IRQ_MASK	((1 << MARVEL_IRQ_VEC_PE_SHIFT) - 1)
+#define MARVEL_NR_IRQS		\
+	(16 + (MARVEL_MAX_PIDS * (1 << MARVEL_IRQ_VEC_PE_SHIFT)))
+
+/*
+ * EV7 RBOX Registers
+ */
+typedef struct {
+	volatile unsigned long csr __attribute__((aligned(16)));
+} ev7_csr;
+
+typedef struct {
+	ev7_csr	RBOX_CFG;		/* 0x0000 */
+	ev7_csr	RBOX_NSVC;
+	ev7_csr	RBOX_EWVC;
+	ev7_csr	RBOX_WHAMI;
+	ev7_csr	RBOX_TCTL;		/* 0x0040 */
+	ev7_csr	RBOX_INT;
+	ev7_csr	RBOX_IMASK;
+	ev7_csr	RBOX_IREQ;
+	ev7_csr	RBOX_INTQ;		/* 0x0080 */
+	ev7_csr	RBOX_INTA;
+	ev7_csr	RBOX_IT;
+	ev7_csr	RBOX_SCRATCH1;
+	ev7_csr	RBOX_SCRATCH2;		/* 0x00c0 */
+	ev7_csr	RBOX_L_ERR;
+} ev7_csrs;
+
+/*
+ * EV7 CSR addressing macros
+ */
+#define EV7_MASK40(addr)        ((addr) & ((1UL << 41) - 1))
+#define EV7_KERN_ADDR(addr)	((void *)(IDENT_ADDR | EV7_MASK40(addr)))
+
+#define EV7_PE_MASK		0x1ffUL /* 9 bits ( 256 + mem/io ) */
+#define EV7_IPE(pe)		((~((long)(pe)) & EV7_PE_MASK) << 35)
+
+#define EV7_CSR_PHYS(pe, off)	(EV7_IPE(pe) | (0x7FFCUL << 20) | (off))
+#define EV7_CSRS_PHYS(pe)	(EV7_CSR_PHYS(pe, 0UL))
+
+#define EV7_CSR_KERN(pe, off)	(EV7_KERN_ADDR(EV7_CSR_PHYS(pe, off)))
+#define EV7_CSRS_KERN(pe)	(EV7_KERN_ADDR(EV7_CSRS_PHYS(pe)))
+
+#define EV7_CSR_OFFSET(name)	((unsigned long)&((ev7_csrs *)NULL)->name.csr)
+
+/*
+ * IO7 registers
+ */
+typedef struct {
+	volatile unsigned long csr __attribute__((aligned(64)));
+} io7_csr;
+
+typedef struct {
+	/* I/O Port Control Registers */
+	io7_csr	POx_CTRL;	       	/* 0x0000 */
+	io7_csr	POx_CACHE_CTL;
+	io7_csr POx_TIMER;
+	io7_csr POx_IO_ADR_EXT;
+	io7_csr	POx_MEM_ADR_EXT;	/* 0x0100 */
+	io7_csr POx_XCAL_CTRL;
+	io7_csr rsvd1[2];	/* ?? spec doesn't show 0x180 */
+	io7_csr POx_DM_SOURCE;		/* ox0200 */
+	io7_csr POx_DM_DEST;
+	io7_csr POx_DM_SIZE;
+	io7_csr POx_DM_STATE;
+	io7_csr rsvd2[4];		/* 0x0300 */
+
+	/* AGP Control Registers -- port 3 only */
+	io7_csr AGP_CAP_ID;		/* 0x0400 */
+	io7_csr AGP_STAT;
+	io7_csr	AGP_CMD;
+	io7_csr	rsvd3;
+
+	/* I/O Port Monitor Registers */
+	io7_csr	POx_MONCTL;		/* 0x0500 */
+	io7_csr POx_CTRA;
+	io7_csr POx_CTRB;
+	io7_csr POx_CTR56;
+	io7_csr POx_SCRATCH;		/* 0x0600 */
+	io7_csr POx_XTRA_A;
+	io7_csr POx_XTRA_TS;
+	io7_csr POx_XTRA_Z;
+	io7_csr rsvd4;			/* 0x0700 */
+	io7_csr POx_THRESHA;
+	io7_csr POx_THRESHB;
+	io7_csr rsvd5[33];
+
+	/* System Address Space Window Control Registers */
+
+	io7_csr POx_WBASE[4];		/* 0x1000 */
+	io7_csr POx_WMASK[4];
+	io7_csr POx_TBASE[4];
+	io7_csr POx_SG_TBIA;
+	io7_csr POx_MSI_WBASE;
+	io7_csr rsvd6[50];
+
+	/* I/O Port Error Registers */
+	io7_csr POx_ERR_SUM;
+	io7_csr POx_FIRST_ERR;
+	io7_csr POx_MSK_HEI;
+	io7_csr POx_TLB_ERR;
+	io7_csr POx_SPL_COMPLT;
+	io7_csr POx_TRANS_SUM;
+	io7_csr POx_FRC_PCI_ERR;
+	io7_csr POx_MULT_ERR;
+	io7_csr rsvd7[8];
+
+	/* I/O Port End of Interrupt Registers */
+	io7_csr EOI_DAT;
+	io7_csr rsvd8[7];
+	io7_csr POx_IACK_SPECIAL;
+	io7_csr rsvd9[103];
+} io7_ioport_csrs;
+
+typedef struct {
+	io7_csr IO_ASIC_REV;		/* 0x30.0000 */
+	io7_csr IO_SYS_REV;
+	io7_csr SER_CHAIN3;
+	io7_csr PO7_RST1;
+	io7_csr PO7_RST2;		/* 0x30.0100 */
+	io7_csr POx_RST[4];
+	io7_csr IO7_DWNH;
+	io7_csr IO7_MAF;
+	io7_csr IO7_MAF_TO;
+	io7_csr IO7_ACC_CLUMP;		/* 0x30.0300 */
+	io7_csr IO7_PMASK;
+	io7_csr IO7_IOMASK;
+	io7_csr IO7_UPH;
+	io7_csr IO7_UPH_TO;		/* 0x30.0400 */
+	io7_csr RBX_IREQ_OFF;
+	io7_csr RBX_INTA_OFF;
+	io7_csr INT_RTY;
+	io7_csr PO7_MONCTL;		/* 0x30.0500 */
+	io7_csr PO7_CTRA;
+	io7_csr PO7_CTRB;
+	io7_csr PO7_CTR56;
+	io7_csr PO7_SCRATCH;		/* 0x30.0600 */
+	io7_csr PO7_XTRA_A;
+	io7_csr PO7_XTRA_TS;
+	io7_csr PO7_XTRA_Z;
+	io7_csr PO7_PMASK;		/* 0x30.0700 */
+	io7_csr PO7_THRESHA;
+	io7_csr PO7_THRESHB;
+	io7_csr rsvd1[97];
+	io7_csr PO7_ERROR_SUM;		/* 0x30.2000 */
+	io7_csr PO7_BHOLE_MASK;
+	io7_csr PO7_HEI_MSK;
+	io7_csr PO7_CRD_MSK;
+	io7_csr PO7_UNCRR_SYM;		/* 0x30.2100 */
+	io7_csr PO7_CRRCT_SYM;
+	io7_csr PO7_ERR_PKT[2];
+	io7_csr PO7_UGBGE_SYM;		/* 0x30.2200 */
+	io7_csr rsbv2[887];
+	io7_csr PO7_LSI_CTL[128];	/* 0x31.0000 */
+	io7_csr rsvd3[123];
+	io7_csr HLT_CTL;		/* 0x31.3ec0 */
+	io7_csr HPI_CTL;		/* 0x31.3f00 */
+	io7_csr CRD_CTL;
+	io7_csr STV_CTL;
+	io7_csr HEI_CTL;
+	io7_csr PO7_MSI_CTL[16];	/* 0x31.4000 */
+	io7_csr rsvd4[240];
+
+	/*
+	 * Interrupt Diagnostic / Test
+	 */
+	struct {
+		io7_csr INT_PND;
+		io7_csr INT_CLR;
+		io7_csr INT_EOI;
+		io7_csr rsvd[29];
+	} INT_DIAG[4];
+	io7_csr rsvd5[125];	    	/* 0x31.a000 */
+	io7_csr MISC_PND;		/* 0x31.b800 */
+	io7_csr rsvd6[31];
+	io7_csr MSI_PND[16];		/* 0x31.c000 */
+	io7_csr rsvd7[16];
+	io7_csr MSI_CLR[16];		/* 0x31.c800 */
+} io7_port7_csrs;
+
+/* 
+ * IO7 DMA Window Base register (POx_WBASEx)
+ */
+#define wbase_m_ena  0x1
+#define wbase_m_sg   0x2
+#define wbase_m_dac  0x4
+#define wbase_m_addr 0xFFF00000
+union IO7_POx_WBASE {
+	struct {
+		unsigned ena : 1;	/* <0>			*/
+		unsigned sg : 1;	/* <1>			*/
+		unsigned dac : 1;	/* <2> -- window 3 only */
+		unsigned rsvd1 : 17; 
+		unsigned addr : 12;	/* <31:20>		*/
+		unsigned rsvd2 : 32;
+	} bits;
+	unsigned as_long[2];
+	unsigned as_quad;
+};
+
+/*
+ * IO7 IID (Interrupt IDentifier) format
+ *
+ * For level-sensitive interrupts, int_num is encoded as:
+ *
+ *	bus/port	slot/device	INTx
+ *	<7:5>		<4:2>		<1:0>
+ */
+union IO7_IID {
+	struct {
+		unsigned int_num : 9;		/* <8:0>    	*/
+		unsigned tpu_mask : 4;		/* <12:9> rsvd	*/
+		unsigned msi : 1;		/* 13		*/
+		unsigned ipe : 10;		/* <23:14>	*/
+		unsigned long rsvd : 40;		
+	} bits;
+	unsigned int as_long[2];
+	unsigned long as_quad;
+};
+
+/*
+ * IO7 addressing macros
+ */
+#define IO7_KERN_ADDR(addr)	(EV7_KERN_ADDR(addr))
+
+#define IO7_PORT_MASK	   	0x07UL	/* 3 bits of port 	   */
+
+#define IO7_IPE(pe)		(EV7_IPE(pe))
+#define IO7_IPORT(port)		((~((long)(port)) & IO7_PORT_MASK) << 32)
+
+#define IO7_HOSE(pe, port)	(IO7_IPE(pe) | IO7_IPORT(port))
+
+#define IO7_MEM_PHYS(pe, port)	(IO7_HOSE(pe, port) | 0x00000000UL)
+#define IO7_CONF_PHYS(pe, port)	(IO7_HOSE(pe, port) | 0xFE000000UL)
+#define IO7_IO_PHYS(pe, port)	(IO7_HOSE(pe, port) | 0xFF000000UL)
+#define IO7_CSR_PHYS(pe, port, off) \
+                                (IO7_HOSE(pe, port) | 0xFF800000UL | (off))
+#define IO7_CSRS_PHYS(pe, port)	(IO7_CSR_PHYS(pe, port, 0UL))
+#define IO7_PORT7_CSRS_PHYS(pe) (IO7_CSR_PHYS(pe, 7, 0x300000UL))
+
+#define IO7_MEM_KERN(pe, port)      (IO7_KERN_ADDR(IO7_MEM_PHYS(pe, port)))
+#define IO7_CONF_KERN(pe, port)     (IO7_KERN_ADDR(IO7_CONF_PHYS(pe, port)))
+#define IO7_IO_KERN(pe, port)       (IO7_KERN_ADDR(IO7_IO_PHYS(pe, port)))
+#define IO7_CSR_KERN(pe, port, off) (IO7_KERN_ADDR(IO7_CSR_PHYS(pe,port,off)))
+#define IO7_CSRS_KERN(pe, port)     (IO7_KERN_ADDR(IO7_CSRS_PHYS(pe, port)))
+#define IO7_PORT7_CSRS_KERN(pe)	    (IO7_KERN_ADDR(IO7_PORT7_CSRS_PHYS(pe)))
+
+#define IO7_PLL_RNGA(pll)	(((pll) >> 3) & 0x7)
+#define IO7_PLL_RNGB(pll)	(((pll) >> 6) & 0x7)
+
+#define IO7_MEM_SPACE		(2UL * 1024 * 1024 * 1024)	/* 2GB MEM */
+#define IO7_IO_SPACE		(8UL * 1024 * 1024)		/* 8MB I/O */
+
+ 
+/* 
+ * Offset between ram physical addresses and pci64 DAC addresses
+ */
+#define IO7_DAC_OFFSET		(1UL << 49)
+
+/*
+ * This is needed to satisify the IO() macro used in initializing the machvec
+ */
+#define MARVEL_IACK_SC 							\
+        ((unsigned long)						\
+	 (&(((io7_ioport_csrs *)IO7_CSRS_KERN(0, 0))->POx_IACK_SPECIAL)))
+
+#ifdef __KERNEL__
+
+/*
+ * IO7 structs
+ */
+#define IO7_NUM_PORTS 4
+#define IO7_AGP_PORT  3
+
+struct io7_port {
+	struct io7 *io7;
+	struct pci_controller *hose;
+
+	int enabled;
+	unsigned int port;
+	io7_ioport_csrs *csrs;
+
+	unsigned long saved_wbase[4];
+	unsigned long saved_wmask[4];
+	unsigned long saved_tbase[4];
+};
+
+struct io7 {
+	struct io7 *next;
+
+	unsigned int pe;
+	io7_port7_csrs *csrs;
+	struct io7_port ports[IO7_NUM_PORTS];
+
+	spinlock_t irq_lock;
+};
+
+#ifndef __EXTERN_INLINE
+# define __EXTERN_INLINE extern inline
+# define __IO_EXTERN_INLINE
+#endif
+
+/*
+ * I/O functions. All access through linear space.
+ */
+
+#define vucp	volatile unsigned char *
+#define vusp	volatile unsigned short *
+#define vuip	volatile unsigned int *
+#define vulp	volatile unsigned long *
+
+#ifdef CONFIG_VGA_HOSE
+extern struct pci_controller *pci_vga_hose;
+
+# define __marvel_is_port_vga(a)	\
+        (((a) >= 0x3b0) && ((a) < 0x3e0) && ((a) != 0x3b3) && ((a) != 0x3d3))
+# define __marvel_is_mem_vga(a)	(((a) >= 0xa0000) && ((a) <= 0xc0000))
+# define FIXUP_IOADDR_VGA(a) do {			\
+	if (pci_vga_hose && __marvel_is_port_vga(a))	\
+		a += pci_vga_hose->io_space->start;	\
+    } while(0)
+#else
+# define FIXUP_IOADDR_VGA(a)
+#endif 
+
+#define __marvel_is_port_kbd(a)	(((a) == 0x60) || ((a) == 0x64))
+#define __marvel_is_port_rtc(a)	(((a) == 0x70) || ((a) == 0x71))
+
+#define FIXUP_IOADDR_LEGACY(a)
+
+#define FIXUP_IOADDR(a) do {				\
+	FIXUP_IOADDR_VGA(a);				\
+        FIXUP_IOADDR_LEGACY(a);				\
+    } while(0)
+
+#if 0
+# define IOBUG(x) printk x
+# define IOBUG_FILTER_IOADDR(a, x)	\
+    if (!__marvel_is_port_kbd(a) && !__marvel_is_port_rtc(a)) IOBUG(x)
+#else
+# define IOBUG(x)
+# define IOBUG_FILTER_IOADDR(a, x)
+#endif
+
+extern u8 __marvel_rtc_io(int write, u8 b, unsigned long addr);
+#define __marvel_rtc_inb(a)	__marvel_rtc_io(0, 0, (a))
+#define __marvel_rtc_outb(b, a)	__marvel_rtc_io(1, (b), (a))
+
+__EXTERN_INLINE int marvel_is_ioaddr(unsigned long addr)
+{
+	return (addr & (1UL << 40)) != 0; /*FIXME - hardwire*/
+}
+
+__EXTERN_INLINE u8 marvel_inb(unsigned long addr)
+{
+	FIXUP_IOADDR(addr);
+	if (!marvel_is_ioaddr(addr)) {
+		if (__marvel_is_port_kbd(addr))
+			return (u8)0;
+		if (__marvel_is_port_rtc(addr))
+			return __marvel_rtc_inb(addr);
+		IOBUG_FILTER_IOADDR(addr, 
+				    ("Bad IO addr %lx - reading -1\n", addr));
+		return (u8)-1;
+	}
+	return __kernel_ldbu(*(vucp)addr);
+}
+
+__EXTERN_INLINE void marvel_outb(u8 b, unsigned long addr)
+{
+	FIXUP_IOADDR(addr);
+	if (!marvel_is_ioaddr(addr)) {
+		if (__marvel_is_port_rtc(addr)) 
+			return (void)__marvel_rtc_outb(b, addr);
+		IOBUG_FILTER_IOADDR(addr, 
+				    ("Bad IO addr %lx - reading -1\n", addr));
+		return;
+	}
+	__kernel_stb(b, *(vucp)addr);
+	mb();
+}
+
+__EXTERN_INLINE u16 marvel_inw(unsigned long addr)
+{
+	FIXUP_IOADDR(addr);
+	if (!marvel_is_ioaddr(addr)) {
+		IOBUG_FILTER_IOADDR(addr, 
+				    ("Bad IO addr %lx - reading -1\n", addr));
+		return (u16)-1;
+	}
+	return __kernel_ldwu(*(vusp)addr);
+}
+
+__EXTERN_INLINE void marvel_outw(u16 w, unsigned long addr)
+{
+	FIXUP_IOADDR(addr);
+	if (!marvel_is_ioaddr(addr)) {
+		IOBUG_FILTER_IOADDR(addr, 
+				    ("Bad IO addr %lx - reading -1\n", addr));
+		return;
+	}
+	__kernel_stw(w, *(vusp)addr);
+	mb();
+}
+
+__EXTERN_INLINE u32 marvel_inl(unsigned long addr)
+{
+	FIXUP_IOADDR(addr);
+	if (!marvel_is_ioaddr(addr)) {
+		IOBUG_FILTER_IOADDR(addr, 
+				    ("Bad IO addr %lx - reading -1\n", addr));
+		return (u32)-1;
+	}
+	return *(vuip)addr;
+}
+
+__EXTERN_INLINE void marvel_outl(u32 l, unsigned long addr)
+{
+	FIXUP_IOADDR(addr);
+	if (!marvel_is_ioaddr(addr)) {
+		IOBUG_FILTER_IOADDR(addr, 
+				    ("Bad IO addr %lx - reading -1\n", addr));
+		return;
+	}
+	*(vuip)addr = l;
+	mb();
+}
+
+/*
+ * Memory functions.  All accesses through linear space.
+ */
+
+extern unsigned long marvel_ioremap(unsigned long addr, unsigned long size);
+extern void marvel_iounmap(unsigned long addr);
+
+__EXTERN_INLINE u8 marvel_readb(unsigned long addr)
+{
+	if (!marvel_is_ioaddr(addr)) {
+		IOBUG(("Bad MEM addr %lx - reading -1\n", addr));
+		return (u8)-1;
+	}
+	return __kernel_ldbu(*(vucp)addr);
+}
+
+__EXTERN_INLINE u16 marvel_readw(unsigned long addr)
+{
+	if (!marvel_is_ioaddr(addr)) {
+		IOBUG(("Bad MEM addr %lx - reading -1\n", addr));
+		return (u16)-1;
+	}
+	return __kernel_ldwu(*(vusp)addr);
+}
+
+__EXTERN_INLINE u32 marvel_readl(unsigned long addr)
+{
+	if (!marvel_is_ioaddr(addr)) {
+		IOBUG(("Bad MEM addr %lx - reading -1\n", addr));
+		return (u32)-1;
+	}
+	return *(vuip)addr;
+}
+
+__EXTERN_INLINE u64 marvel_readq(unsigned long addr)
+{
+	if (!marvel_is_ioaddr(addr)) {
+		IOBUG(("Bad MEM addr %lx - reading -1\n", addr));
+		return (u64)-1;
+	}
+	return *(vulp)addr;
+}
+
+__EXTERN_INLINE void marvel_writeb(u8 b, unsigned long addr)
+{
+	if (!marvel_is_ioaddr(addr)) {
+		IOBUG(("Bad MEM addr %lx - dropping store\n", addr));
+		return;
+	}
+	__kernel_stb(b, *(vucp)addr);
+}
+
+__EXTERN_INLINE void marvel_writew(u16 w, unsigned long addr)
+{
+	if (!marvel_is_ioaddr(addr)) {
+		IOBUG(("Bad MEM addr %lx - dropping store\n", addr));
+		return;
+	}
+	__kernel_stw(w, *(vusp)addr);
+}
+
+__EXTERN_INLINE void marvel_writel(u32 l, unsigned long addr)
+{
+	if (!marvel_is_ioaddr(addr)) {
+		IOBUG(("Bad MEM addr %lx - dropping store\n", addr));
+		return;
+	}
+	*(vuip)addr = l;
+}
+
+__EXTERN_INLINE void marvel_writeq(u64 q, unsigned long addr)
+{
+	if (!marvel_is_ioaddr(addr)) {
+		IOBUG(("Bad MEM addr %lx - dropping store\n", addr));
+		return;
+	}
+	*(vulp)addr = q;
+}
+
+#undef FIXUP_IOADDR
+#undef FIXUP_IOADDR_LEGACY
+#undef FIXUP_IOADDR_VGA
+
+#undef vucp
+#undef vusp
+#undef vuip
+#undef vulp
+
+#ifdef __WANT_IO_DEF
+
+#define __inb(p)		marvel_inb((unsigned long)(p))
+#define __inw(p)		marvel_inw((unsigned long)(p))
+#define __inl(p)		marvel_inl((unsigned long)(p))
+#define __outb(x,p)		marvel_outb((x),(unsigned long)(p))
+#define __outw(x,p)		marvel_outw((x),(unsigned long)(p))
+#define __outl(x,p)		marvel_outl((x),(unsigned long)(p))
+#define __readb(a)		marvel_readb((unsigned long)(a))
+#define __readw(a)		marvel_readw((unsigned long)(a))
+#define __readl(a)		marvel_readl((unsigned long)(a))
+#define __readq(a)		marvel_readq((unsigned long)(a))
+#define __writeb(x,a)		marvel_writeb((x),(unsigned long)(a))
+#define __writew(x,a)		marvel_writew((x),(unsigned long)(a))
+#define __writel(x,a)		marvel_writel((x),(unsigned long)(a))
+#define __writeq(x,a)		marvel_writeq((x),(unsigned long)(a))
+#define __ioremap(a,s)		marvel_ioremap((unsigned long)(a),(s))
+#define __iounmap(a)		marvel_iounmap((unsigned long)(a))
+#define __is_ioaddr(a)		marvel_is_ioaddr((unsigned long)(a))
+
+/* Disable direct inlining of these calls with the debug checks present.  */
+#if 0
+#define __raw_readb(a)		__readb(a)
+#define __raw_readw(a)		__readw(a)
+#define __raw_readl(a)		__readl(a)
+#define __raw_readq(a)		__readq(a)
+#define __raw_writeb(v,a)	__writeb(v,a)
+#define __raw_writew(v,a)	__writew(v,a)
+#define __raw_writel(v,a)	__writel(v,a)
+#define __raw_writeq(v,a)	__writeq(v,a)
+#endif
+
+#endif /* __WANT_IO_DEF */
+
+#ifdef __IO_EXTERN_INLINE
+# undef __EXTERN_INLINE
+# undef __IO_EXTERN_INLINE
+#endif
+
+#endif /* __KERNEL__ */
+
+#endif /* __ALPHA_MARVEL__H__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-alpha/core_t2.h linux-2.4.21-pre6/include/asm-alpha/core_t2.h
--- linux-2.4.20/include/asm-alpha/core_t2.h	2001-11-09 21:45:35.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-alpha/core_t2.h	2003-03-26 23:49:39.000000000 +0000
@@ -19,7 +19,7 @@
  *
  */
 
-#define T2_MEM_R1_MASK 0x03ffffff  /* Mem sparse region 1 mask is 26 bits */
+#define T2_MEM_R1_MASK 0x07ffffff  /* Mem sparse region 1 mask is 26 bits */
 
 /* GAMMA-SABLE is a SABLE with EV5-based CPUs */
 #define _GAMMA_BIAS		0x8000000000UL
@@ -402,13 +402,17 @@
  *
  */
 
+#define t2_set_hae { \
+	msb = addr  >> 27; \
+	addr &= T2_MEM_R1_MASK; \
+	set_hae(msb); \
+}
+
 __EXTERN_INLINE u8 t2_readb(unsigned long addr)
 {
 	unsigned long result, msb;
 
-	msb = addr & 0xE0000000;
-	addr &= T2_MEM_R1_MASK;
-	set_hae(msb);
+	t2_set_hae;
 
 	result = *(vip) ((addr << 5) + T2_SPARSE_MEM + 0x00);
 	return __kernel_extbl(result, addr & 3);
@@ -418,9 +422,7 @@
 {
 	unsigned long result, msb;
 
-	msb = addr & 0xE0000000;
-	addr &= T2_MEM_R1_MASK;
-	set_hae(msb);
+	t2_set_hae;
 
 	result = *(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x08);
 	return __kernel_extwl(result, addr & 3);
@@ -431,9 +433,7 @@
 {
 	unsigned long msb;
 
-	msb = addr & 0xE0000000;
-	addr &= T2_MEM_R1_MASK;
-	set_hae(msb);
+	t2_set_hae;
 
 	return *(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x18);
 }
@@ -442,9 +442,7 @@
 {
 	unsigned long r0, r1, work, msb;
 
-	msb = addr & 0xE0000000;
-	addr &= T2_MEM_R1_MASK;
-	set_hae(msb);
+	t2_set_hae;
 
 	work = (addr << 5) + T2_SPARSE_MEM + 0x18;
 	r0 = *(vuip)(work);
@@ -456,9 +454,7 @@
 {
 	unsigned long msb, w;
 
-	msb = addr & 0xE0000000;
-	addr &= T2_MEM_R1_MASK;
-	set_hae(msb);
+	t2_set_hae;
 
 	w = __kernel_insbl(b, addr & 3);
 	*(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x00) = w;
@@ -468,9 +464,7 @@
 {
 	unsigned long msb, w;
 
-	msb = addr & 0xE0000000;
-	addr &= T2_MEM_R1_MASK;
-	set_hae(msb);
+	t2_set_hae;
 
 	w = __kernel_inswl(b, addr & 3);
 	*(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x08) = w;
@@ -481,9 +475,7 @@
 {
 	unsigned long msb;
 
-	msb = addr & 0xE0000000;
-	addr &= T2_MEM_R1_MASK;
-	set_hae(msb);
+	t2_set_hae;
 
 	*(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x18) = b;
 }
@@ -492,9 +484,7 @@
 {
 	unsigned long msb, work;
 
-	msb = addr & 0xE0000000;
-	addr &= T2_MEM_R1_MASK;
-	set_hae(msb);
+	t2_set_hae;
 
 	work = (addr << 5) + T2_SPARSE_MEM + 0x18;
 	*(vuip)work = b;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-alpha/core_titan.h linux-2.4.21-pre6/include/asm-alpha/core_titan.h
--- linux-2.4.20/include/asm-alpha/core_titan.h	2001-11-09 21:45:35.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-alpha/core_titan.h	2003-03-26 23:49:25.000000000 +0000
@@ -2,6 +2,7 @@
 #define __ALPHA_TITAN__H__
 
 #include <linux/types.h>
+#include <linux/pci.h>
 #include <asm/compiler.h>
 
 /*
@@ -293,13 +294,15 @@
  * 		2 - pachip 0 / A Port
  *      	3 - pachip 1 / A Port
  */
-#define TITAN_HOSE(h)		(((unsigned long)(h)) << 33)
+#define TITAN_HOSE_SHIFT       (33) 
+#define TITAN_HOSE(h)		(((unsigned long)(h)) << TITAN_HOSE_SHIFT)
 #define TITAN_BASE		(IDENT_ADDR + TI_BIAS)
 #define TITAN_MEM(h)	     	(TITAN_BASE+TITAN_HOSE(h)+0x000000000UL)
 #define _TITAN_IACK_SC(h)    	(TITAN_BASE+TITAN_HOSE(h)+0x1F8000000UL)
 #define TITAN_IO(h)	     	(TITAN_BASE+TITAN_HOSE(h)+0x1FC000000UL)
 #define TITAN_CONF(h)	     	(TITAN_BASE+TITAN_HOSE(h)+0x1FE000000UL)
 
+#define TITAN_HOSE_MASK		TITAN_HOSE(3)
 #define TITAN_IACK_SC	     	_TITAN_IACK_SC(0) /* hack! */
 
 /* 
@@ -427,17 +430,8 @@
  * Memory functions.  all accesses are done through linear space.
  */
 
-__EXTERN_INLINE unsigned long titan_ioremap(unsigned long addr, 
-					    unsigned long size
-					    __attribute__((unused)))
-{
-	return addr + TITAN_MEM_BIAS;
-}
-
-__EXTERN_INLINE void titan_iounmap(unsigned long addr)
-{
-	return;
-}
+extern unsigned long titan_ioremap(unsigned long addr, unsigned long size);
+extern void titan_iounmap(unsigned long addr);
 
 __EXTERN_INLINE int titan_is_ioaddr(unsigned long addr)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-alpha/delay.h linux-2.4.21-pre6/include/asm-alpha/delay.h
--- linux-2.4.20/include/asm-alpha/delay.h	2001-06-20 18:10:27.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-alpha/delay.h	2003-03-26 23:49:30.000000000 +0000
@@ -2,7 +2,7 @@
 #define __ALPHA_DELAY_H
 
 extern void __delay(int loops);
-extern void __udelay(unsigned long usecs, unsigned long lpj);
+extern void ndelay(unsigned long nsecs);
 extern void udelay(unsigned long usecs);
 
 #endif /* defined(__ALPHA_DELAY_H) */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-alpha/dma.h linux-2.4.21-pre6/include/asm-alpha/dma.h
--- linux-2.4.20/include/asm-alpha/dma.h	1999-11-27 23:27:49.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-alpha/dma.h	2003-03-26 23:49:54.000000000 +0000
@@ -75,34 +75,49 @@
 
 #define MAX_DMA_CHANNELS	8
 
-/* The maximum address that we can perform a DMA transfer to on Alpha XL,
-   due to a hardware SIO (PCI<->ISA bus bridge) chip limitation, is 64MB.
-   See <asm/apecs.h> for more info.
+/*
+  ISA DMA limitations on Alpha platforms,
+
+  These may be due to SIO (PCI<->ISA bridge) chipset limitation, or
+  just a wiring limit.
+*/
+
+/* The maximum address for ISA DMA transfer on Alpha XL, due to an
+   hardware SIO limitation, is 64MB.
 */
-/* The maximum address that we can perform a DMA transfer to on RUFFIAN,
-   due to a hardware SIO (PCI<->ISA bus bridge) chip limitation, is 16MB.
-   See <asm/pyxis.h> for more info.
+#define ALPHA_XL_MAX_DMA_ADDRESS	(IDENT_ADDR+0x04000000UL)
+
+/* The maximum address for ISA DMA transfer on RUFFIAN and NAUTILUS,
+   due to an hardware SIO limitation, is 16MB.
 */
-/* NOTE: we must define the maximum as something less than 64Mb, to prevent 
-   virt_to_bus() from returning an address in the first window, for a
-   data area that goes beyond the 64Mb first DMA window. Sigh...
-   We MUST coordinate the maximum with <asm/apecs.h> for consistency.
-   For now, this limit is set to 48Mb...
+#define ALPHA_RUFFIAN_MAX_DMA_ADDRESS	(IDENT_ADDR+0x01000000UL)
+#define ALPHA_NAUTILUS_MAX_DMA_ADDRESS	(IDENT_ADDR+0x01000000UL)
+
+/* The maximum address for ISA DMA transfer on SABLE, and some ALCORs,
+   due to an hardware SIO chip limitation, is 2GB.
+*/
+#define ALPHA_SABLE_MAX_DMA_ADDRESS	(IDENT_ADDR+0x80000000UL)
+#define ALPHA_ALCOR_MAX_DMA_ADDRESS	(IDENT_ADDR+0x80000000UL)
+
+/*
+  Maximum address for all the others is the complete 32-bit bus
+  address space.
 */
-#define ALPHA_XL_MAX_DMA_ADDRESS	(IDENT_ADDR+0x3000000UL)
-#define ALPHA_RUFFIAN_MAX_DMA_ADDRESS	(IDENT_ADDR+0x1000000UL)
-#define ALPHA_NAUTILUS_MAX_DMA_ADDRESS	(IDENT_ADDR+0x1000000UL)
-#define ALPHA_MAX_DMA_ADDRESS		(~0UL)
+#define ALPHA_MAX_DMA_ADDRESS		(IDENT_ADDR+0x100000000UL)
 
 #ifdef CONFIG_ALPHA_GENERIC
 # define MAX_DMA_ADDRESS		(alpha_mv.max_dma_address)
 #else
-# ifdef CONFIG_ALPHA_XL
+# if defined(CONFIG_ALPHA_XL)
 #  define MAX_DMA_ADDRESS		ALPHA_XL_MAX_DMA_ADDRESS
 # elif defined(CONFIG_ALPHA_RUFFIAN)
 #  define MAX_DMA_ADDRESS		ALPHA_RUFFIAN_MAX_DMA_ADDRESS
 # elif defined(CONFIG_ALPHA_NAUTILUS)
 #  define MAX_DMA_ADDRESS		ALPHA_NAUTILUS_MAX_DMA_ADDRESS
+# elif defined(CONFIG_ALPHA_SABLE)
+#  define MAX_DMA_ADDRESS		ALPHA_SABLE_MAX_DMA_ADDRESS
+# elif defined(CONFIG_ALPHA_ALCOR)
+#  define MAX_DMA_ADDRESS		ALPHA_ALCOR_MAX_DMA_ADDRESS
 # else
 #  define MAX_DMA_ADDRESS		ALPHA_MAX_DMA_ADDRESS
 # endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-alpha/elf.h linux-2.4.21-pre6/include/asm-alpha/elf.h
--- linux-2.4.20/include/asm-alpha/elf.h	2000-09-22 21:07:43.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-alpha/elf.h	2003-03-26 23:49:39.000000000 +0000
@@ -52,51 +52,13 @@
 
 #define ELF_PLAT_INIT(_r)       _r->r0 = 0
 
-/* Use the same format as the OSF/1 procfs interface.  The register
-   layout is sane.  However, since dump_thread() creates the funky
-   layout that ECOFF coredumps want, we need to undo that layout here.
-   Eventually, it would be nice if the ECOFF core-dump had to do the
-   translation, then ELF_CORE_COPY_REGS() would become trivial and
-   faster.  */
-#define ELF_CORE_COPY_REGS(_dest,_regs)				\
-{								\
-	struct user _dump;					\
-								\
-	dump_thread(_regs, &_dump);				\
-	_dest[ 0] = _dump.regs[EF_V0];				\
-	_dest[ 1] = _dump.regs[EF_T0];				\
-	_dest[ 2] = _dump.regs[EF_T1];				\
-	_dest[ 3] = _dump.regs[EF_T2];				\
-	_dest[ 4] = _dump.regs[EF_T3];				\
-	_dest[ 5] = _dump.regs[EF_T4];				\
-	_dest[ 6] = _dump.regs[EF_T5];				\
-	_dest[ 7] = _dump.regs[EF_T6];				\
-	_dest[ 8] = _dump.regs[EF_T7];				\
-	_dest[ 9] = _dump.regs[EF_S0];				\
-	_dest[10] = _dump.regs[EF_S1];				\
-	_dest[11] = _dump.regs[EF_S2];				\
-	_dest[12] = _dump.regs[EF_S3];				\
-	_dest[13] = _dump.regs[EF_S4];				\
-	_dest[14] = _dump.regs[EF_S5];				\
-	_dest[15] = _dump.regs[EF_S6];				\
-	_dest[16] = _dump.regs[EF_A0];				\
-	_dest[17] = _dump.regs[EF_A1];				\
-	_dest[18] = _dump.regs[EF_A2];				\
-	_dest[19] = _dump.regs[EF_A3];				\
-	_dest[20] = _dump.regs[EF_A4];				\
-	_dest[21] = _dump.regs[EF_A5];				\
-	_dest[22] = _dump.regs[EF_T8];				\
-	_dest[23] = _dump.regs[EF_T9];				\
-	_dest[24] = _dump.regs[EF_T10];				\
-	_dest[25] = _dump.regs[EF_T11];				\
-	_dest[26] = _dump.regs[EF_RA];				\
-	_dest[27] = _dump.regs[EF_T12];				\
-	_dest[28] = _dump.regs[EF_AT];				\
-	_dest[29] = _dump.regs[EF_GP];				\
-	_dest[30] = _dump.regs[EF_SP];				\
-	_dest[31] = _dump.regs[EF_PC];	/* store PC here */	\
-	_dest[32] = _dump.regs[EF_PS];				\
-}
+/* The registers are layed out in pt_regs for PAL and syscall
+   convenience.  Re-order them for the linear elf_gregset_t.  */
+
+extern void dump_elf_thread(elf_greg_t *, struct pt_regs *,
+			    struct task_struct *);
+#define ELF_CORE_COPY_REGS(DEST, REGS) \
+	dump_elf_thread(DEST, REGS, current);
 
 /* This yields a mask that user programs can use to figure out what
    instruction set this CPU supports.  This is trivial on Alpha, 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-alpha/floppy.h linux-2.4.21-pre6/include/asm-alpha/floppy.h
--- linux-2.4.20/include/asm-alpha/floppy.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-alpha/floppy.h	2003-03-26 23:49:54.000000000 +0000
@@ -92,25 +92,22 @@
 
 /*
  * Most Alphas have no problems with floppy DMA crossing 64k borders,
- * except for XL and RUFFIAN.  They are also the only one with DMA
- * limits, so we use that to test in the generic kernel.
+ * except for certain ones, like XL and RUFFIAN.
+ *
+ * However, the test is simple and fast, and this *is* floppy, after all,
+ * so we do it for all platforms, just to make sure.
+ *
+ * This is advantageous in other circumstances as well, as in moving
+ * about the PCI DMA windows and forcing the floppy to start doing
+ * scatter-gather when it never had before, and there *is* a problem
+ * on that platform... ;-}
  */
 
-#define __CROSS_64KB(a,s)					\
+#define CROSS_64KB(a,s)						\
 ({ unsigned long __s64 = (unsigned long)(a);			\
    unsigned long __e64 = __s64 + (unsigned long)(s) - 1;	\
    (__s64 ^ __e64) & ~0xfffful; })
 
-#ifdef CONFIG_ALPHA_GENERIC
-# define CROSS_64KB(a,s)   (__CROSS_64KB(a,s) && ~alpha_mv.max_dma_address)
-#else
-# if defined(CONFIG_ALPHA_XL) || defined(CONFIG_ALPHA_RUFFIAN) || defined(CONFIG_ALPHA_NAUTILUS)
-#  define CROSS_64KB(a,s)  __CROSS_64KB(a,s)
-# else
-#  define CROSS_64KB(a,s)  (0)
-# endif
-#endif
-
 #define EXTRA_FLOPPY_PARAMS
 
 #endif /* __ASM_ALPHA_FLOPPY_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-alpha/gct.h linux-2.4.21-pre6/include/asm-alpha/gct.h
--- linux-2.4.20/include/asm-alpha/gct.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-alpha/gct.h	2003-03-26 23:48:59.000000000 +0000
@@ -0,0 +1,58 @@
+#ifndef __ALPHA_GCT_H
+#define __ALPHA_GCT_H
+
+typedef u64 gct_id;
+typedef u64 gct6_handle;
+
+typedef struct __gct6_node {
+	u8 type;	
+	u8 subtype;
+	u16 size;
+	u32 hd_extension;
+	gct6_handle owner;
+	gct6_handle active_user;
+	gct_id id;
+	u64 flags;
+	u16 rev;
+	u16 change_counter;
+	u16 max_child;
+	u16 reserved1;
+	gct6_handle saved_owner;
+	gct6_handle affinity;
+	gct6_handle parent;
+	gct6_handle next;
+	gct6_handle prev;
+	gct6_handle child;
+	u64 fw_flags;
+	u64 os_usage;
+	u64 fru_id;
+	u32 checksum;
+	u32 magic;	/* 'GLXY' */
+} gct6_node;
+
+typedef struct {
+	u8 type;	
+	u8 subtype;
+	void (*callout)(gct6_node *);
+} gct6_search_struct;
+
+#define GCT_NODE_MAGIC	  0x59584c47	/* 'GLXY' */
+
+/* 
+ * node types 
+ */
+#define GCT_TYPE_HOSE			0x0E
+
+/*
+ * node subtypes
+ */
+#define GCT_SUBTYPE_IO_PORT_MODULE	0x2C
+
+#define GCT_NODE_PTR(off) ((gct6_node *)((char *)hwrpb + 		\
+					 hwrpb->frut_offset + 		\
+					 (gct6_handle)(off)))		\
+
+int gct6_find_nodes(gct6_node *, gct6_search_struct *);
+
+#endif /* __ALPHA_GCT_H */
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-alpha/hdreg.h linux-2.4.21-pre6/include/asm-alpha/hdreg.h
--- linux-2.4.20/include/asm-alpha/hdreg.h	1999-05-13 18:00:08.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-alpha/hdreg.h	2003-03-26 23:49:35.000000000 +0000
@@ -7,6 +7,7 @@
 #ifndef __ASMalpha_HDREG_H
 #define __ASMalpha_HDREG_H
 
-typedef unsigned short ide_ioreg_t;
+//typedef unsigned short ide_ioreg_t;
+typedef unsigned long ide_ioreg_t;
 
 #endif /* __ASMalpha_HDREG_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-alpha/hwrpb.h linux-2.4.21-pre6/include/asm-alpha/hwrpb.h
--- linux-2.4.20/include/asm-alpha/hwrpb.h	2001-11-03 01:39:20.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-alpha/hwrpb.h	2003-03-26 23:49:34.000000000 +0000
@@ -64,6 +64,7 @@
 #define ST_DEC_CUSCO		 36	/* CUSCO systype	*/
 #define ST_DEC_EIGER		 37	/* Eiger systype	*/
 #define ST_DEC_TITAN		 38	/* Titan systype	*/
+#define ST_DEC_MARVEL		 39	/* Marvel systype	*/
 
 /* UNOFFICIAL!!! */
 #define ST_UNOFFICIAL_BIAS	100
@@ -109,6 +110,9 @@
 	unsigned long ipc_buffer[21];
 	unsigned long palcode_avail[16];
 	unsigned long compatibility;
+	unsigned long console_data_log_pa;
+	unsigned long console_data_log_length;
+	unsigned long bcache_info;
 };
 
 struct procdesc_struct {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-alpha/ide.h linux-2.4.21-pre6/include/asm-alpha/ide.h
--- linux-2.4.20/include/asm-alpha/ide.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-alpha/ide.h	2003-03-26 23:49:25.000000000 +0000
@@ -19,8 +19,6 @@
 #define MAX_HWIFS	4
 #endif
 
-#define ide__sti()	__sti()
-
 static __inline__ int ide_default_irq(ide_ioreg_t base)
 {
 	switch (base) {
@@ -82,42 +80,7 @@
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned bit0		: 1;
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned reserved456	: 3;
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-	} b;
-} control_t;
-
-#define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
-#define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
-#define ide_check_region(from,extent)		check_region((from), (extent))
-#define ide_request_region(from,extent,name)	request_region((from), (extent), (name))
-#define ide_release_region(from,extent)		release_region((from), (extent))
-
-/*
- * The following are not needed for the non-m68k ports
- */
-#define ide_ack_intr(hwif)		(1)
-#define ide_fix_driveid(id)		do {} while (0)
-#define ide_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
+#include <asm-generic/ide_iops.h>
 
 #endif /* __KERNEL__ */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-alpha/io.h linux-2.4.21-pre6/include/asm-alpha/io.h
--- linux-2.4.20/include/asm-alpha/io.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-alpha/io.h	2003-03-26 23:49:29.000000000 +0000
@@ -19,6 +19,7 @@
 #include <linux/kernel.h>
 #include <asm/system.h>
 #include <asm/machvec.h>
+#include <asm/hwrpb.h>
 
 /*
  * We try to avoid hae updates (thus the cache), but when we
@@ -50,6 +51,7 @@
 /*
  * Change virtual addresses to physical addresses and vv.
  */
+#ifdef USE_48_BIT_KSEG
 static inline unsigned long virt_to_phys(void *address)
 {
 	return (unsigned long)address - IDENT_ADDR;
@@ -59,6 +61,26 @@
 {
 	return (void *) (address + IDENT_ADDR);
 }
+#else
+static inline unsigned long virt_to_phys(void *address)
+{
+        unsigned long phys = (unsigned long)address;
+
+	/* Sign-extend from bit 41.  */
+	phys <<= (64 - 41);
+	phys = (long)phys >> (64 - 41);
+
+	/* Crop to the physical address width of the processor.  */
+        phys &= (1ul << hwrpb->pa_bits) - 1;
+
+        return phys;
+}
+
+static inline void * phys_to_virt(unsigned long address)
+{
+        return (void *)(IDENT_ADDR + (address & ((1ul << 41) - 1)));
+}
+#endif
 
 #define page_to_phys(page)	PAGE_TO_PA(page)
 
@@ -164,6 +186,8 @@
 # include <asm/jensen.h>
 #elif defined(CONFIG_ALPHA_LCA)
 # include <asm/core_lca.h>
+#elif defined(CONFIG_ALPHA_MARVEL)
+# include <asm/core_marvel.h>
 #elif defined(CONFIG_ALPHA_MCPCIA)
 # include <asm/core_mcpcia.h>
 #elif defined(CONFIG_ALPHA_POLARIS)
@@ -433,7 +457,9 @@
 
 #define eth_io_copy_and_sum(skb,src,len,unused) \
   memcpy_fromio((skb)->data,(src),(len))
-
+#define isa_eth_io_copy_and_sum(skb,src,len,unused) \
+  isa_memcpy_fromio((skb)->data,(src),(len))
+ 
 static inline int
 check_signature(unsigned long io_addr, const unsigned char *signature,
 		int length)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-alpha/irq.h linux-2.4.21-pre6/include/asm-alpha/irq.h
--- linux-2.4.20/include/asm-alpha/irq.h	2001-08-12 17:38:47.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-alpha/irq.h	2003-03-26 23:49:35.000000000 +0000
@@ -16,7 +16,7 @@
    many places throughout the kernel to size static arrays.  That's ok,
    we'll use alpha_mv.nr_irqs when we want the real thing.  */
 
-# define NR_IRQS	2048 /* enuff for WILDFIRE with 8 QBBs */
+# define NR_IRQS	(32768 + 16)	/* marvel - 32 pids */
 
 #elif defined(CONFIG_ALPHA_CABRIOLET) || \
       defined(CONFIG_ALPHA_EB66P)     || \
@@ -57,6 +57,9 @@
 #elif defined(CONFIG_ALPHA_WILDFIRE)
 # define NR_IRQS	2048 /* enuff for 8 QBBs */
 
+#elif defined(CONFIG_ALPHA_MARVEL)
+# define NR_IRQS	(32768 + 16)	/* marvel - 32 pids */
+
 #else /* everyone else */
 # define NR_IRQS	16
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-alpha/machvec.h linux-2.4.21-pre6/include/asm-alpha/machvec.h
--- linux-2.4.20/include/asm-alpha/machvec.h	2001-11-09 21:45:35.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-alpha/machvec.h	2003-03-26 23:49:07.000000000 +0000
@@ -22,6 +22,7 @@
 struct pci_dev;
 struct pci_ops;
 struct pci_controller;
+struct _alpha_agp_info;
 
 struct alpha_machine_vector
 {
@@ -80,6 +81,7 @@
 	void (*device_interrupt)(unsigned long vector, struct pt_regs *regs);
 	void (*machine_check)(u64 vector, u64 la, struct pt_regs *regs);
 
+	void (*smp_callin)(void);
 	void (*init_arch)(void);
 	void (*init_irq)(void);
 	void (*init_rtc)(void);
@@ -90,8 +92,16 @@
 	int (*pci_map_irq)(struct pci_dev *, u8, u8);
 	struct pci_ops *pci_ops;
 
+	struct _alpha_agp_info *(*agp_info)(void);
+
 	const char *vector_name;
 
+	/* NUMA information */
+	int (*pa_to_nid)(unsigned long);
+	int (*cpuid_to_nid)(int);
+	unsigned long (*node_mem_start)(int);
+	unsigned long (*node_mem_size)(int);
+
 	/* System specific parameters.  */
 	union {
 	    struct {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-alpha/mmu_context.h linux-2.4.21-pre6/include/asm-alpha/mmu_context.h
--- linux-2.4.20/include/asm-alpha/mmu_context.h	2000-12-29 22:07:23.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-alpha/mmu_context.h	2003-03-26 23:49:39.000000000 +0000
@@ -32,7 +32,7 @@
 		"call_pal %2 #__reload_thread"
 		: "=r"(v0), "=r"(a0)
 		: "i"(PAL_swpctx), "r"(a0)
-		: "$1", "$16", "$22", "$23", "$24", "$25");
+		: "$1", "$22", "$23", "$24", "$25");
 
 	return v0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-alpha/mmzone.h linux-2.4.21-pre6/include/asm-alpha/mmzone.h
--- linux-2.4.20/include/asm-alpha/mmzone.h	2001-05-24 22:20:18.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-alpha/mmzone.h	2003-03-26 23:49:27.000000000 +0000
@@ -34,15 +34,19 @@
 
 extern plat_pg_data_t *plat_node_data[];
 
-#ifdef CONFIG_ALPHA_WILDFIRE
-# define ALPHA_PA_TO_NID(pa)	((pa) >> 36)	/* 16 nodes max due 43bit kseg */
-#define NODE_MAX_MEM_SIZE	(64L * 1024L * 1024L * 1024L) /* 64 GB */
-#define MAX_NUMNODES		WILDFIRE_MAX_QBB
-#else
-# define ALPHA_PA_TO_NID(pa)	(0)
-#define NODE_MAX_MEM_SIZE	(~0UL)
-#define MAX_NUMNODES		1
-#endif
+#define ALPHA_PA_TO_NID(pa)		\
+        (alpha_mv.pa_to_nid 		\
+	 ? alpha_mv.pa_to_nid(pa)	\
+	 : (0))
+#define NODE_MEM_START(nid)		\
+        (alpha_mv.node_mem_start 	\
+	 ? alpha_mv.node_mem_start(nid) \
+	 : (0UL))
+#define NODE_MEM_SIZE(nid)		\
+        (alpha_mv.node_mem_size 	\
+	 ? alpha_mv.node_mem_size(nid) 	\
+	 : ((nid) ? (0UL) : (~0UL)))
+#define MAX_NUMNODES		128		/* marvel */
 
 #define PHYSADDR_TO_NID(pa)		ALPHA_PA_TO_NID(pa)
 #define PLAT_NODE_DATA(n)		(plat_node_data[(n)])
@@ -86,7 +90,7 @@
 
 /*
  * Given a kaddr, ADDR_TO_MAPBASE finds the owning node of the memory
- * and returns the the mem_map of that node.
+ * and returns the mem_map of that node.
  */
 #define ADDR_TO_MAPBASE(kaddr) \
 			NODE_MEM_MAP(KVADDR_TO_NID((unsigned long)(kaddr)))
@@ -112,12 +116,8 @@
 #define NODE_SCHEDULE_DATA(nid)	(&((PLAT_NODE_DATA(nid))->schedule_data))
 #endif
 
-#ifdef CONFIG_ALPHA_WILDFIRE
-/* With wildfire assume 4 CPUs per node */
-#define cputonode(cpu)	((cpu) >> 2)
-#else
-#define cputonode(cpu)	0
-#endif /* CONFIG_ALPHA_WILDFIRE */
+#define cputonode(cpu) 	\
+        (alpha_mv.cpuid_to_nid ? alpha_mv.cpuid_to_nid(cpu) : 0)
 
 #define numa_node_id()	cputonode(smp_processor_id())
 #endif /* CONFIG_NUMA */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-alpha/pci.h linux-2.4.21-pre6/include/asm-alpha/pci.h
--- linux-2.4.20/include/asm-alpha/pci.h	2002-02-25 19:38:09.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-alpha/pci.h	2003-03-26 23:48:57.000000000 +0000
@@ -42,6 +42,8 @@
 
 	struct pci_iommu_arena *sg_pci;
 	struct pci_iommu_arena *sg_isa;
+
+	void *sysdata;
 };
 
 /* Override the logic in pci_scan_bus for skipping already-configured
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-alpha/processor.h linux-2.4.21-pre6/include/asm-alpha/processor.h
--- linux-2.4.20/include/asm-alpha/processor.h	2001-10-05 19:11:05.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-alpha/processor.h	2003-03-26 23:49:55.000000000 +0000
@@ -119,7 +119,7 @@
 extern void release_thread(struct task_struct *);
 
 /* Create a kernel thread without removing it from tasklists.  */
-extern long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
+extern long arch_kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
 
 #define copy_segments(tsk, mm)		do { } while (0)
 #define release_segments(mm)		do { } while (0)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-alpha/regdef.h linux-2.4.21-pre6/include/asm-alpha/regdef.h
--- linux-2.4.20/include/asm-alpha/regdef.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-alpha/regdef.h	2003-03-26 23:49:21.000000000 +0000
@@ -0,0 +1,44 @@
+#ifndef __alpha_regdef_h__
+#define __alpha_regdef_h__
+
+#define v0	$0	/* function return value */
+
+#define t0	$1	/* temporary registers (caller-saved) */
+#define t1	$2
+#define t2	$3
+#define t3	$4
+#define t4	$5
+#define t5	$6
+#define t6	$7
+#define t7	$8
+
+#define	s0	$9	/* saved-registers (callee-saved registers) */
+#define	s1	$10
+#define	s2	$11
+#define	s3	$12
+#define	s4	$13
+#define	s5	$14
+#define	s6	$15
+#define	fp	s6	/* frame-pointer (s6 in frame-less procedures) */
+
+#define a0	$16	/* argument registers (caller-saved) */
+#define a1	$17
+#define a2	$18
+#define a3	$19
+#define a4	$20
+#define a5	$21
+
+#define t8	$22	/* more temps (caller-saved) */
+#define t9	$23
+#define t10	$24
+#define t11	$25
+#define ra	$26	/* return address register */
+#define t12	$27
+
+#define pv	t12	/* procedure-variable register */
+#define AT	$at	/* assembler temporary */
+#define gp	$29	/* global pointer */
+#define sp	$30	/* stack pointer */
+#define zero	$31	/* reads as zero, writes are noops */
+
+#endif /* __alpha_regdef_h__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-alpha/system.h linux-2.4.21-pre6/include/asm-alpha/system.h
--- linux-2.4.20/include/asm-alpha/system.h	2001-10-05 01:47:08.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-alpha/system.h	2003-03-26 23:49:40.000000000 +0000
@@ -23,7 +23,7 @@
 #ifdef CONFIG_ALPHA_LEGACY_START_ADDRESS
 #define KERNEL_START_PHYS	0x300000 /* Old bootloaders hardcoded this.  */
 #else
-#define KERNEL_START_PHYS	0x800000 /* Wildfire has a huge console */
+#define KERNEL_START_PHYS	0x1000000 /* required: Wildfire/Titan/Marvel */
 #endif
 
 #define KERNEL_START	(PAGE_OFFSET+KERNEL_START_PHYS)
@@ -61,7 +61,8 @@
 	int		retry	:  1;	/* retry flag */
 	unsigned int	proc_offset;	/* processor-specific offset */
 	unsigned int	sys_offset;	/* system-specific offset */
-	unsigned long	code;		/* machine check code */
+	unsigned int	code;		/* machine check code */
+	unsigned int	frame_rev;	/* frame revision */
 };
 
 /* Machine Check Frame for uncorrectable errors (Large format)
@@ -117,11 +118,11 @@
 	unsigned long DC0_SYNDROME;
 	unsigned long C_STAT;
 	unsigned long C_STS;
-	unsigned long RESERVED0;
+	unsigned long MM_STAT;
 	unsigned long EXC_ADDR;
 	unsigned long IER_CM;
 	unsigned long ISUM;
-	unsigned long MM_STAT;
+	unsigned long RESERVED0;
 	unsigned long PAL_BASE;
 	unsigned long I_CTL;
 	unsigned long PCTX;
@@ -309,9 +310,11 @@
 #define __sti()			do { barrier(); setipl(IPL_MIN); } while(0)
 #define __save_flags(flags)	((flags) = rdps())
 #define __save_and_cli(flags)	do { (flags) = swpipl(IPL_MAX); barrier(); } while(0)
+#define __save_and_sti(flags)	do { barrier(); (flags) = swpipl(IPL_MIN); } while(0)
 #define __restore_flags(flags)	do { barrier(); setipl(flags); barrier(); } while(0)
 
 #define local_irq_save(flags)		__save_and_cli(flags)
+#define local_irq_set(flags)            __save_and_sti(flags)
 #define local_irq_restore(flags)	__restore_flags(flags)
 #define local_irq_disable()		__cli()
 #define local_irq_enable()		__sti()
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-alpha/timex.h linux-2.4.21-pre6/include/asm-alpha/timex.h
--- linux-2.4.20/include/asm-alpha/timex.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-alpha/timex.h	2003-03-26 23:49:39.000000000 +0000
@@ -18,7 +18,6 @@
  */
 
 typedef unsigned int cycles_t;
-extern cycles_t cacheflush_time;
 
 static inline cycles_t get_cycles (void)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-arm/arch-anakin/system.h linux-2.4.21-pre6/include/asm-arm/arch-anakin/system.h
--- linux-2.4.20/include/asm-arm/arch-anakin/system.h	2001-08-12 18:14:00.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-arm/arch-anakin/system.h	2003-03-26 23:49:07.000000000 +0000
@@ -15,8 +15,7 @@
 #ifndef __ASM_ARCH_SYSTEM_H
 #define __ASM_ARCH_SYSTEM_H
 
-static inline void
-arch_idle(void)
+static inline void arch_idle(void)
 {
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-arm/arch-cl7500/system.h linux-2.4.21-pre6/include/asm-arm/arch-cl7500/system.h
--- linux-2.4.20/include/asm-arm/arch-cl7500/system.h	2001-04-12 19:20:31.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-arm/arch-cl7500/system.h	2003-03-26 23:49:54.000000000 +0000
@@ -18,6 +18,6 @@
 	do {					\
 		iomd_writeb(0, IOMD_ROMCR0);	\
 		cpu_reset(0);			\
-	} while (0);
+	} while (0)
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-arm/arch-clps711x/system.h linux-2.4.21-pre6/include/asm-arm/arch-clps711x/system.h
--- linux-2.4.20/include/asm-arm/arch-clps711x/system.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-arm/arch-clps711x/system.h	2003-03-26 23:48:58.000000000 +0000
@@ -24,7 +24,7 @@
 #include <asm/arch/hardware.h>
 #include <asm/hardware/clps7111.h>
 
-static void arch_idle(void)
+static inline void arch_idle(void)
 {
 	clps_writel(1, HALT);
 	__asm__ __volatile__(
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-arm/arch-sa1100/keyboard.h linux-2.4.21-pre6/include/asm-arm/arch-sa1100/keyboard.h
--- linux-2.4.20/include/asm-arm/arch-sa1100/keyboard.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-arm/arch-sa1100/keyboard.h	2003-03-26 23:49:35.000000000 +0000
@@ -10,8 +10,8 @@
 #include <asm/mach-types.h>
 #include <asm/arch/assabet.h>
 
-#define kbd_disable_irq()	do { } while(0);
-#define kbd_enable_irq()	do { } while(0);
+#define kbd_disable_irq()	do { } while(0)
+#define kbd_enable_irq()	do { } while(0)
 
 extern int sa1111_kbd_init_hw(void);
 extern void gc_kbd_init_hw(void);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-arm/hdreg.h linux-2.4.21-pre6/include/asm-arm/hdreg.h
--- linux-2.4.20/include/asm-arm/hdreg.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-arm/hdreg.h	2003-03-26 23:49:38.000000000 +0000
@@ -7,7 +7,8 @@
 #ifndef __ASMARM_HDREG_H
 #define __ASMARM_HDREG_H
 
-typedef unsigned int ide_ioreg_t;
+//typedef unsigned int ide_ioreg_t;
+typedef unsigned long ide_ioreg_t;
 
 #endif /* __ASMARM_HDREG_H */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-arm/ide.h linux-2.4.21-pre6/include/asm-arm/ide.h
--- linux-2.4.20/include/asm-arm/ide.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-arm/ide.h	2003-03-26 23:49:34.000000000 +0000
@@ -17,47 +17,8 @@
 #define MAX_HWIFS	4
 #endif
 
-#define ide__sti()	__sti()
-
 #include <asm/arch/ide.h>
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned bit0		: 1;
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned reserved456	: 3;
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-	} b;
-} control_t;
-
-#define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
-#define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
-#define ide_check_region(from,extent)		check_region((from), (extent))
-#define ide_request_region(from,extent,name)	request_region((from), (extent), (name))
-#define ide_release_region(from,extent)		release_region((from), (extent))
-
-/*
- * The following are not needed for the non-m68k ports
- */
-#define ide_ack_intr(hwif)		(1)
-#define ide_fix_driveid(id)		do {} while (0)
-#define ide_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
-
 /*
  * We always use the new IDE port registering,
  * so these are fixed here.
@@ -65,6 +26,8 @@
 #define ide_default_io_base(i)		((ide_ioreg_t)0)
 #define ide_default_irq(b)		(0)
 
+#include <asm-generic/ide_iops.h>
+
 #endif /* __KERNEL__ */
 
 #endif /* __ASMARM_IDE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-arm/proc-armo/system.h linux-2.4.21-pre6/include/asm-arm/proc-armo/system.h
--- linux-2.4.20/include/asm-arm/proc-armo/system.h	2001-08-12 18:14:00.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-arm/proc-armo/system.h	2003-03-26 23:49:25.000000000 +0000
@@ -127,4 +127,6 @@
 	  : "memory");					\
 	} while (0)
 
+#define __save_and_sti(x)	({__save_flags(x);__sti();})
+
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-arm/proc-armv/system.h linux-2.4.21-pre6/include/asm-arm/proc-armv/system.h
--- linux-2.4.20/include/asm-arm/proc-armv/system.h	2001-08-12 18:14:00.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-arm/proc-armv/system.h	2003-03-26 23:48:58.000000000 +0000
@@ -141,6 +141,8 @@
 	: "r" (x)						\
 	: "memory")
 
+#define __save_and_sti(x)	({__save_flags(x);__sti();})
+
 #if defined(CONFIG_CPU_SA1100) || defined(CONFIG_CPU_SA110)
 /*
  * On the StrongARM, "swp" is terminally broken since it bypasses the
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-arm/processor.h linux-2.4.21-pre6/include/asm-arm/processor.h
--- linux-2.4.20/include/asm-arm/processor.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-arm/processor.h	2003-03-26 23:49:38.000000000 +0000
@@ -117,7 +117,7 @@
 /*
  * Create a new kernel thread
  */
-extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
+extern int arch_kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
 
 #endif
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-arm/system.h linux-2.4.21-pre6/include/asm-arm/system.h
--- linux-2.4.20/include/asm-arm/system.h	2000-11-28 01:07:59.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-arm/system.h	2003-03-26 23:49:07.000000000 +0000
@@ -58,6 +58,7 @@
 
 /* For spinlocks etc */
 #define local_irq_save(x)	__save_flags_cli(x)
+#define local_irq_set(x)	__save_and_sti(x)
 #define local_irq_restore(x)	__restore_flags(x)
 #define local_irq_disable()	__cli()
 #define local_irq_enable()	__sti()
@@ -82,6 +83,8 @@
 #define save_flags(x)		__save_flags(x)
 #define restore_flags(x)	__restore_flags(x)
 #define save_flags_cli(x)	__save_flags_cli(x)
+#define save_and_cli(x)		__save_flags_cli(x)
+#define save_and_sti(x)		__save_flags_sti(x)
 
 #endif /* CONFIG_SMP */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-arm/xor.h linux-2.4.21-pre6/include/asm-arm/xor.h
--- linux-2.4.20/include/asm-arm/xor.h	2001-06-27 21:12:04.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-arm/xor.h	2003-03-26 23:49:35.000000000 +0000
@@ -125,11 +125,11 @@
 }
 
 static struct xor_block_template xor_block_arm4regs = {
-	name:	"arm4regs",
-	do_2:	xor_arm4regs_2,
-	do_3:	xor_arm4regs_3,
-	do_4:	xor_arm4regs_4,
-	do_5:	xor_arm4regs_5,
+	.name	= "arm4regs",
+	.do_2	= xor_arm4regs_2,
+	.do_3	= xor_arm4regs_3,
+	.do_4	= xor_arm4regs_4,
+	.do_5	= xor_arm4regs_5,
 };
 
 #undef XOR_TRY_TEMPLATES
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-cris/atomic.h linux-2.4.21-pre6/include/asm-cris/atomic.h
--- linux-2.4.20/include/asm-cris/atomic.h	2001-07-26 22:10:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-cris/atomic.h	2003-03-26 23:48:58.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: atomic.h,v 1.3 2001/07/25 16:15:19 bjornw Exp $ */
+/* $Id: atomic.h,v 1.4 2002/11/20 18:20:17 hp Exp $ */
 
 #ifndef __ASM_CRIS_ATOMIC__
 #define __ASM_CRIS_ATOMIC__
@@ -27,7 +27,7 @@
 
 /* These should be written in asm but we do it in C for now. */
 
-static __inline__ void atomic_add(int i, volatile atomic_t *v)
+extern __inline__ void atomic_add(int i, volatile atomic_t *v)
 {
 	unsigned long flags;
 	save_flags(flags);
@@ -36,7 +36,7 @@
 	restore_flags(flags);
 }
 
-static __inline__ void atomic_sub(int i, volatile atomic_t *v)
+extern __inline__ void atomic_sub(int i, volatile atomic_t *v)
 {
 	unsigned long flags;
 	save_flags(flags);
@@ -45,7 +45,7 @@
 	restore_flags(flags);
 }
 
-static __inline__ int atomic_add_return(int i, volatile atomic_t *v)
+extern __inline__ int atomic_add_return(int i, volatile atomic_t *v)
 {
 	unsigned long flags;
 	int retval;
@@ -56,7 +56,7 @@
 	return retval;
 }
 
-static __inline__ int atomic_sub_return(int i, volatile atomic_t *v)
+extern __inline__ int atomic_sub_return(int i, volatile atomic_t *v)
 {
 	unsigned long flags;
 	int retval;
@@ -67,7 +67,7 @@
 	return retval;
 }
 
-static __inline__ int atomic_sub_and_test(int i, volatile atomic_t *v)
+extern __inline__ int atomic_sub_and_test(int i, volatile atomic_t *v)
 {
 	int retval;
 	unsigned long flags;
@@ -78,7 +78,7 @@
 	return retval;
 }
 
-static __inline__ void atomic_inc(volatile atomic_t *v)
+extern __inline__ void atomic_inc(volatile atomic_t *v)
 {
 	unsigned long flags;
 	save_flags(flags);
@@ -87,7 +87,7 @@
 	restore_flags(flags);
 }
 
-static __inline__ void atomic_dec(volatile atomic_t *v)
+extern __inline__ void atomic_dec(volatile atomic_t *v)
 {
 	unsigned long flags;
 	save_flags(flags);
@@ -96,7 +96,7 @@
 	restore_flags(flags);
 }
 
-static __inline__ int atomic_inc_return(volatile atomic_t *v)
+extern __inline__ int atomic_inc_return(volatile atomic_t *v)
 {
 	unsigned long flags;
 	int retval;
@@ -107,7 +107,7 @@
 	return retval;
 }
 
-static __inline__ int atomic_dec_return(volatile atomic_t *v)
+extern __inline__ int atomic_dec_return(volatile atomic_t *v)
 {
 	unsigned long flags;
 	int retval;
@@ -117,7 +117,7 @@
 	restore_flags(flags);
 	return retval;
 }
-static __inline__ int atomic_dec_and_test(volatile atomic_t *v)
+extern __inline__ int atomic_dec_and_test(volatile atomic_t *v)
 {
 	int retval;
 	unsigned long flags;
@@ -128,7 +128,7 @@
 	return retval;
 }
 
-static __inline__ int atomic_inc_and_test(volatile atomic_t *v)
+extern __inline__ int atomic_inc_and_test(volatile atomic_t *v)
 {
 	int retval;
 	unsigned long flags;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-cris/bitops.h linux-2.4.21-pre6/include/asm-cris/bitops.h
--- linux-2.4.20/include/asm-cris/bitops.h	2002-02-25 19:38:10.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-cris/bitops.h	2003-03-26 23:49:29.000000000 +0000
@@ -89,7 +89,7 @@
  * It also implies a memory barrier.
  */
 
-static __inline__ int test_and_set_bit(int nr, void *addr)
+extern __inline__ int test_and_set_bit(int nr, void *addr)
 {
 	unsigned int mask, retval;
 	unsigned long flags;
@@ -120,7 +120,7 @@
  * It also implies a memory barrier.
  */
 
-static __inline__ int test_and_clear_bit(int nr, void *addr)
+extern __inline__ int test_and_clear_bit(int nr, void *addr)
 {
 	unsigned int mask, retval;
 	unsigned long flags;
@@ -146,7 +146,7 @@
  * but actually fail.  You must protect multiple accesses with a lock.
  */
 
-static __inline__ int __test_and_clear_bit(int nr, void *addr)
+extern __inline__ int __test_and_clear_bit(int nr, void *addr)
 {
 	unsigned int mask, retval;
 	unsigned int *adr = (unsigned int *)addr;
@@ -166,7 +166,7 @@
  * It also implies a memory barrier.
  */
 
-static __inline__ int test_and_change_bit(int nr, void *addr)
+extern __inline__ int test_and_change_bit(int nr, void *addr)
 {
 	unsigned int mask, retval;
 	unsigned long flags;
@@ -183,7 +183,7 @@
 
 /* WARNING: non atomic and it can be reordered! */
 
-static __inline__ int __test_and_change_bit(int nr, void *addr)
+extern __inline__ int __test_and_change_bit(int nr, void *addr)
 {
 	unsigned int mask, retval;
 	unsigned int *adr = (unsigned int *)addr;
@@ -204,7 +204,7 @@
  * This routine doesn't need to be atomic.
  */
 
-static __inline__ int test_bit(int nr, const void *addr)
+extern __inline__ int test_bit(int nr, const void *addr)
 {
 	unsigned int mask;
 	unsigned int *adr = (unsigned int *)addr;
@@ -225,7 +225,7 @@
  * number.  They differ in that the first function also inverts all bits
  * in the input.
  */
-static __inline__ unsigned long cris_swapnwbrlz(unsigned long w)
+extern __inline__ unsigned long cris_swapnwbrlz(unsigned long w)
 {
 	/* Let's just say we return the result in the same register as the
 	   input.  Saying we clobber the input but can return the result
@@ -241,7 +241,7 @@
 	return res;
 }
 
-static __inline__ unsigned long cris_swapwbrlz(unsigned long w)
+extern __inline__ unsigned long cris_swapwbrlz(unsigned long w)
 {
 	unsigned res;
 	__asm__ ("swapwbr %0 \n\t"
@@ -255,7 +255,7 @@
  * ffz = Find First Zero in word. Undefined if no zero exists,
  * so code should check against ~0UL first..
  */
-static __inline__ unsigned long ffz(unsigned long w)
+extern __inline__ unsigned long ffz(unsigned long w)
 {
 	/* The generic_ffs function is used to avoid the asm when the
 	   argument is a constant.  */
@@ -268,7 +268,7 @@
  * Somewhat like ffz but the equivalent of generic_ffs: in contrast to
  * ffz we return the first one-bit *plus one*.
  */
-static __inline__ unsigned long ffs(unsigned long w)
+extern __inline__ unsigned long kernel_ffs(unsigned long w)
 {
 	/* The generic_ffs function is used to avoid the asm when the
 	   argument is a constant.  */
@@ -277,13 +277,20 @@
 		: w ? cris_swapwbrlz (w) + 1 : 0;
 }
 
+/*
+ * Since we define it "external", it collides with the built-in
+ * definition, which doesn't have the same semantics.  We don't want to
+ * use -fno-builtin, so just hide the name ffs.
+ */
+#define ffs kernel_ffs
+
 /**
  * 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)
+extern __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;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-cris/byteorder.h linux-2.4.21-pre6/include/asm-cris/byteorder.h
--- linux-2.4.20/include/asm-cris/byteorder.h	2001-02-09 00:32:44.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-cris/byteorder.h	2003-03-26 23:48:58.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: byteorder.h,v 1.1 2000/07/10 16:32:31 bjornw Exp $ */
+/* $Id: byteorder.h,v 1.2 2002/11/20 18:20:17 hp Exp $ */
 
 #ifndef _CRIS_BYTEORDER_H
 #define _CRIS_BYTEORDER_H
@@ -12,14 +12,14 @@
  * them together into ntohl etc.
  */
 
-static __inline__ __const__ __u32 ___arch__swab32(__u32 x)
+extern __inline__ __const__ __u32 ___arch__swab32(__u32 x)
 {
 	__asm__ ("swapwb %0" : "=r" (x) : "0" (x));
   
 	return(x);
 }
 
-static __inline__ __const__ __u16 ___arch__swab16(__u16 x)
+extern __inline__ __const__ __u16 ___arch__swab16(__u16 x)
 {
 	__asm__ ("swapb %0" : "=r" (x) : "0" (x));
 	
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-cris/checksum.h linux-2.4.21-pre6/include/asm-cris/checksum.h
--- linux-2.4.20/include/asm-cris/checksum.h	2001-10-08 18:43:54.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-cris/checksum.h	2003-03-26 23:49:40.000000000 +0000
@@ -32,7 +32,7 @@
  *	Fold a partial checksum into a word
  */
 
-static inline unsigned int csum_fold(unsigned int sum)
+extern inline unsigned int csum_fold(unsigned int sum)
 {
 	/* the while loop is unnecessary really, it's always enough with two
 	   iterations */
@@ -50,7 +50,7 @@
  * to split all of those into 16-bit components, then add.
  */
 
-static inline unsigned int
+extern inline unsigned int
 csum_tcpudp_nofold(unsigned long saddr, unsigned long daddr, unsigned short len,
 		   unsigned short proto, unsigned int sum)
 {
@@ -78,7 +78,7 @@
  *
  */
 
-static inline unsigned short ip_fast_csum(unsigned char * iph,
+extern inline unsigned short ip_fast_csum(unsigned char * iph,
 					  unsigned int ihl)
 {
 	return csum_fold(csum_partial(iph, ihl * 4, 0));
@@ -89,7 +89,7 @@
  * returns a 16-bit checksum, already complemented
  */
 
-static inline unsigned short int csum_tcpudp_magic(unsigned long saddr,
+extern inline unsigned short int csum_tcpudp_magic(unsigned long saddr,
 						   unsigned long daddr,
 						   unsigned short len,
 						   unsigned short proto,
@@ -103,7 +103,7 @@
  * in icmp.c
  */
 
-static inline unsigned short ip_compute_csum(unsigned char * buff, int len) {
+extern inline unsigned short ip_compute_csum(unsigned char * buff, int len) {
 	return csum_fold (csum_partial(buff, len, 0));
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-cris/current.h linux-2.4.21-pre6/include/asm-cris/current.h
--- linux-2.4.20/include/asm-cris/current.h	2001-10-08 18:43:54.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-cris/current.h	2003-03-26 23:49:35.000000000 +0000
@@ -3,7 +3,7 @@
 
 struct task_struct;
 
-static inline struct task_struct * get_current(void)
+extern inline struct task_struct * get_current(void)
 {
         struct task_struct *current;
         __asm__("and.d $sp,%0; ":"=r" (current) : "0" (~8191UL));
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-cris/ide.h linux-2.4.21-pre6/include/asm-cris/ide.h
--- linux-2.4.20/include/asm-cris/ide.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-cris/ide.h	2003-03-26 23:49:09.000000000 +0000
@@ -22,9 +22,7 @@
 
 #define MAX_HWIFS	4
 
-#define ide__sti()	__sti()
-
-static __inline__ int ide_default_irq(ide_ioreg_t base)
+extern __inline__ int ide_default_irq(ide_ioreg_t base)
 {
 	/* all IDE busses share the same IRQ, number 4.
 	 * this has the side-effect that ide-probe.c will cluster our 4 interfaces
@@ -34,7 +32,7 @@
 	return 4; 
 }
 
-static __inline__ ide_ioreg_t ide_default_io_base(int index)
+extern __inline__ ide_ioreg_t ide_default_io_base(int index)
 {
 	/* we have no real I/O base address per interface, since all go through the
 	 * same register. but in a bitfield in that register, we have the i/f number.
@@ -53,7 +51,7 @@
  * of the ide_default_io_base call above. ctrl_port will be 0, but that is don't care for us.
  */
 
-static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
+extern __inline__ void ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
 {
 	int i;
 
@@ -76,7 +74,7 @@
 	hw->io_ports[IDE_IRQ_OFFSET] = 0;
 }
 
-static __inline__ void ide_init_default_hwifs(void)
+extern __inline__ void ide_init_default_hwifs(void)
 {
 	hw_regs_t hw;
 	int index;
@@ -88,67 +86,11 @@
 	}
 }
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all                    : 8;    /* all of the bits together */
-	struct {
-		unsigned bit0           : 1;
-		unsigned nIEN           : 1;    /* device INTRQ to host */
-		unsigned SRST           : 1;    /* host soft reset bit */
-		unsigned bit3           : 1;    /* ATA-2 thingy */
-		unsigned reserved456    : 3;
-		unsigned HOB            : 1;    /* 48-bit address ordering */
-	} b;
-} control_t;
-
 /* some configuration options we don't need */
 
 #undef SUPPORT_VLB_SYNC
 #define SUPPORT_VLB_SYNC 0
 
-#undef SUPPORT_SLOW_DATA_PORTS
-#define SUPPORT_SLOW_DATA_PORTS	0
-
-/* request and free a normal interrupt */
-
-#define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
-#define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
-
-/* ide-probe.c calls ide_request_region and stuff on the io_ports defined,
- * but since they are not actually memory-mapped in the ETRAX driver, we don't
- * do anything.
- */
-
-#define ide_check_region(from,extent)		(0)
-#define ide_request_region(from,extent,name)	do {} while(0)
-#define ide_release_region(from,extent)		do {} while(0)
-
-/*
- * The following are not needed for the non-m68k ports
- */
-#define ide_ack_intr(hwif)		(1)
-#define ide_fix_driveid(id)		do {} while (0)
-#define ide_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
-
-/* the drive addressing is done through a controller register on the Etrax CPU */
-void OUT_BYTE(unsigned char data, ide_ioreg_t reg);
-unsigned char IN_BYTE(ide_ioreg_t reg);
-
-/* this tells ide.h not to define the standard macros */
-#define HAVE_ARCH_OUT_BYTE
-#define HAVE_ARCH_IN_BYTE
-
 #endif /* __KERNEL__ */
 
 #endif /* __ASMCRIS_IDE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-cris/io.h linux-2.4.21-pre6/include/asm-cris/io.h
--- linux-2.4.20/include/asm-cris/io.h	2001-10-08 18:43:54.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-cris/io.h	2003-03-26 23:49:50.000000000 +0000
@@ -3,6 +3,8 @@
 
 #include <asm/page.h>   /* for __va, __pa */
 #include <asm/svinto.h>
+#include <linux/sched.h>
+#include <asm/pgtable.h>
 #include <linux/config.h>
 
 /* Console I/O for simulated etrax100.  Use #ifdef so erroneous
@@ -199,16 +201,18 @@
  * Change virtual addresses to physical addresses and vv.
  */
 
-static inline unsigned long virt_to_phys(volatile void * address)
+extern inline unsigned long virt_to_phys(volatile void * address)
 {
 	return __pa(address);
 }
 
-static inline void * phys_to_virt(unsigned long address)
+extern inline void * phys_to_virt(unsigned long address)
 {
 	return __va(address);
 }
 
+#define page_to_phys(page)	__pa(__page_address(page))
+
 extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
 
 extern inline void * ioremap (unsigned long offset, unsigned long size)
@@ -216,6 +220,8 @@
 	return __ioremap(offset, size, 0);
 }
 
+extern void iounmap(void *addr);
+
 /*
  * IO bus memory addresses are also 1:1 with the physical address
  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-cris/mmu_context.h linux-2.4.21-pre6/include/asm-cris/mmu_context.h
--- linux-2.4.20/include/asm-cris/mmu_context.h	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-cris/mmu_context.h	2003-03-26 23:49:25.000000000 +0000
@@ -15,7 +15,7 @@
 
 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)
+extern inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu)
 {
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-cris/pgalloc.h linux-2.4.21-pre6/include/asm-cris/pgalloc.h
--- linux-2.4.20/include/asm-cris/pgalloc.h	2001-05-01 23:05:00.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-cris/pgalloc.h	2003-03-26 23:49:54.000000000 +0000
@@ -58,7 +58,7 @@
         pgtable_cache_size++;
 }
 
-static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address)
+extern inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address)
 {
         pte_t *pte;
 
@@ -68,7 +68,7 @@
         return pte;
 }
 
-static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address)
+extern inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address)
 {
         unsigned long *ret;
 
@@ -80,14 +80,14 @@
         return (pte_t *)ret;
 }
 
-static __inline__ void pte_free_fast(pte_t *pte)
+extern __inline__ void pte_free_fast(pte_t *pte)
 {
         *(unsigned long *)pte = (unsigned long) pte_quicklist;
         pte_quicklist = (unsigned long *) pte;
         pgtable_cache_size++;
 }
 
-static __inline__ void pte_free_slow(pte_t *pte)
+extern __inline__ void pte_free_slow(pte_t *pte)
 {
         free_page((unsigned long)pte);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-cris/pgtable.h linux-2.4.21-pre6/include/asm-cris/pgtable.h
--- linux-2.4.20/include/asm-cris/pgtable.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-cris/pgtable.h	2003-03-26 23:48:58.000000000 +0000
@@ -3,6 +3,12 @@
  * HISTORY:
  *
  * $Log: pgtable.h,v $
+ * Revision 1.17  2002/12/02 08:14:08  starvik
+ * Merge of Linux 2.4.20
+ *
+ * Revision 1.16  2002/11/20 18:20:17  hp
+ * Make all static inline functions extern inline.
+ *
  * Revision 1.15  2002/04/23 15:37:52  bjornw
  * Removed page_address and added flush_icache_user_range
  *
@@ -149,14 +155,14 @@
 			    unsigned long start,
 			    unsigned long end);
 
-static inline void flush_tlb_pgtables(struct mm_struct *mm,
+extern inline void flush_tlb_pgtables(struct mm_struct *mm,
                                       unsigned long start, unsigned long end)
 {
         /* CRIS does not keep any page table caches in TLB */
 }
 
 
-static inline void flush_tlb(void) 
+extern inline void flush_tlb(void) 
 {
 	flush_tlb_mm(current->mm);
 }
@@ -166,6 +172,8 @@
  * hook is made available.
  */
 #define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval))
+#define set_pte_atomic(pteptr, pteval) ((*(pteptr)) = (pteval))
+
 /*
  * (pmds are folded into pgds so this doesn't get actually called,
  * but the define is needed for a generic inline function.)
@@ -303,53 +311,53 @@
  * setup: the pgd is never bad, and a pmd always exists (as it's folded
  * into the pgd entry)
  */
-static inline int pgd_none(pgd_t pgd)		{ return 0; }
-static inline int pgd_bad(pgd_t pgd)		{ return 0; }
-static inline int pgd_present(pgd_t pgd)	{ return 1; }
-static inline void pgd_clear(pgd_t * pgdp)	{ }
+extern inline int pgd_none(pgd_t pgd)		{ return 0; }
+extern inline int pgd_bad(pgd_t pgd)		{ return 0; }
+extern inline int pgd_present(pgd_t pgd)	{ return 1; }
+extern inline void pgd_clear(pgd_t * pgdp)	{ }
 
 /*
  * The following only work if pte_present() is true.
  * Undefined behaviour if not..
  */
 
-static inline int pte_read(pte_t pte)           { return pte_val(pte) & _PAGE_READ; }
-static inline int pte_write(pte_t pte)          { return pte_val(pte) & _PAGE_WRITE; }
-static inline int pte_exec(pte_t pte)           { return pte_val(pte) & _PAGE_READ; }
-static inline int pte_dirty(pte_t pte)          { return pte_val(pte) & _PAGE_MODIFIED; }
-static inline int pte_young(pte_t pte)          { return pte_val(pte) & _PAGE_ACCESSED; }
+extern inline int pte_read(pte_t pte)           { return pte_val(pte) & _PAGE_READ; }
+extern inline int pte_write(pte_t pte)          { return pte_val(pte) & _PAGE_WRITE; }
+extern inline int pte_exec(pte_t pte)           { return pte_val(pte) & _PAGE_READ; }
+extern inline int pte_dirty(pte_t pte)          { return pte_val(pte) & _PAGE_MODIFIED; }
+extern inline int pte_young(pte_t pte)          { return pte_val(pte) & _PAGE_ACCESSED; }
 
-static inline pte_t pte_wrprotect(pte_t pte)
+extern inline pte_t pte_wrprotect(pte_t pte)
 {
         pte_val(pte) &= ~(_PAGE_WRITE | _PAGE_SILENT_WRITE);
         return pte;
 }
 
-static inline pte_t pte_rdprotect(pte_t pte)
+extern inline pte_t pte_rdprotect(pte_t pte)
 {
         pte_val(pte) &= ~(_PAGE_READ | _PAGE_SILENT_READ);
 	return pte;
 }
 
-static inline pte_t pte_exprotect(pte_t pte)
+extern inline pte_t pte_exprotect(pte_t pte)
 {
         pte_val(pte) &= ~(_PAGE_READ | _PAGE_SILENT_READ);
 	return pte;
 }
 
-static inline pte_t pte_mkclean(pte_t pte)
+extern inline pte_t pte_mkclean(pte_t pte)
 {
 	pte_val(pte) &= ~(_PAGE_MODIFIED | _PAGE_SILENT_WRITE); 
 	return pte; 
 }
 
-static inline pte_t pte_mkold(pte_t pte)
+extern inline pte_t pte_mkold(pte_t pte)
 {
 	pte_val(pte) &= ~(_PAGE_ACCESSED | _PAGE_SILENT_READ);
 	return pte;
 }
 
-static inline pte_t pte_mkwrite(pte_t pte)
+extern inline pte_t pte_mkwrite(pte_t pte)
 {
         pte_val(pte) |= _PAGE_WRITE;
         if (pte_val(pte) & _PAGE_MODIFIED)
@@ -357,7 +365,7 @@
         return pte;
 }
 
-static inline pte_t pte_mkread(pte_t pte)
+extern inline pte_t pte_mkread(pte_t pte)
 {
         pte_val(pte) |= _PAGE_READ;
         if (pte_val(pte) & _PAGE_ACCESSED)
@@ -365,7 +373,7 @@
         return pte;
 }
 
-static inline pte_t pte_mkexec(pte_t pte)
+extern inline pte_t pte_mkexec(pte_t pte)
 {
         pte_val(pte) |= _PAGE_READ;
         if (pte_val(pte) & _PAGE_ACCESSED)
@@ -373,7 +381,7 @@
         return pte;
 }
 
-static inline pte_t pte_mkdirty(pte_t pte)
+extern inline pte_t pte_mkdirty(pte_t pte)
 {
         pte_val(pte) |= _PAGE_MODIFIED;
         if (pte_val(pte) & _PAGE_WRITE)
@@ -381,7 +389,7 @@
         return pte;
 }
 
-static inline pte_t pte_mkyoung(pte_t pte)
+extern inline pte_t pte_mkyoung(pte_t pte)
 {
         pte_val(pte) |= _PAGE_ACCESSED;
         if (pte_val(pte) & _PAGE_READ)
@@ -405,7 +413,7 @@
  * addresses (the 0xc0xxxxxx's) goes as void *'s.
  */
 
-static inline pte_t __mk_pte(void * page, pgprot_t pgprot)
+extern inline pte_t __mk_pte(void * page, pgprot_t pgprot)
 {
 	pte_t pte;
 	/* the PTE needs a physical address */
@@ -423,7 +431,7 @@
         __pte;                                                          \
 })
 
-static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 { pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; }
 
 
@@ -432,7 +440,7 @@
  * pte_pagenr refers to the page-number counted starting from the virtual DRAM start
  */
 
-static inline unsigned long __pte_page(pte_t pte)
+extern inline unsigned long __pte_page(pte_t pte)
 {
 	/* the PTE contains a physical address */
 	return (unsigned long)__va(pte_val(pte) & PAGE_MASK);
@@ -450,17 +458,17 @@
  * don't need the __pa and __va transformations.
  */
 
-static inline unsigned long pmd_page(pmd_t pmd)
+extern inline unsigned long pmd_page(pmd_t pmd)
 { return pmd_val(pmd) & PAGE_MASK; }
 
-static inline void pmd_set(pmd_t * pmdp, pte_t * ptep)
+extern inline void pmd_set(pmd_t * pmdp, pte_t * ptep)
 { pmd_val(*pmdp) = _PAGE_TABLE | (unsigned long) ptep; }
 
 /* to find an entry in a page-table-directory. */
 #define pgd_index(address) ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
 
 /* to find an entry in a page-table-directory */
-static inline pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address)
+extern inline pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address)
 {
 	return mm->pgd + pgd_index(address);
 }
@@ -469,13 +477,13 @@
 #define pgd_offset_k(address) pgd_offset(&init_mm, address)
 
 /* Find an entry in the second-level page table.. */
-static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
+extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
 {
 	return (pmd_t *) dir;
 }
 
 /* Find an entry in the third-level page table.. */ 
-static inline pte_t * pte_offset(pmd_t * dir, unsigned long address)
+extern inline pte_t * pte_offset(pmd_t * dir, unsigned long address)
 {
 	return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1));
 }
@@ -495,7 +503,7 @@
  * 
  * Actually I am not sure on what this could be used for.
  */
-static inline void update_mmu_cache(struct vm_area_struct * vma,
+extern inline void update_mmu_cache(struct vm_area_struct * vma,
 	unsigned long address, pte_t pte)
 {
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-cris/posix_types.h linux-2.4.21-pre6/include/asm-cris/posix_types.h
--- linux-2.4.20/include/asm-cris/posix_types.h	2001-02-09 00:32:44.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-cris/posix_types.h	2003-03-26 23:49:15.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: posix_types.h,v 1.1 2000/07/10 16:32:31 bjornw Exp $ */
+/* $Id: posix_types.h,v 1.2 2002/09/26 14:44:59 hp Exp $ */
 
 /* We cheat a bit and use our C-coded bitops functions from asm/bitops.h */
 /* I guess we should write these in assembler because they are used often. */
@@ -23,7 +23,7 @@
 typedef unsigned short  __kernel_ipc_pid_t;
 typedef unsigned short	__kernel_uid_t;
 typedef unsigned short	__kernel_gid_t;
-typedef unsigned long	__kernel_size_t;
+typedef __SIZE_TYPE__	__kernel_size_t;
 typedef long		__kernel_ssize_t;
 typedef int		__kernel_ptrdiff_t;
 typedef long		__kernel_time_t;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-cris/processor.h linux-2.4.21-pre6/include/asm-cris/processor.h
--- linux-2.4.20/include/asm-cris/processor.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-cris/processor.h	2003-03-26 23:49:38.000000000 +0000
@@ -81,7 +81,7 @@
 #define INIT_THREAD  { \
    0, 0, 0x20 }  /* ccr = int enable, nothing else */
 
-extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
+extern int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
 /* give the thread a program location
  * set user-mode (The 'U' flag (User mode flag) is CCR/DCCR bit 8) 
@@ -116,13 +116,13 @@
  * Free current thread data structures etc..
  */
 
-static inline void exit_thread(void)
+extern inline void exit_thread(void)
 {
         /* Nothing needs to be done.  */
 }
 
 /* Free all resources held by a thread. */
-static inline void release_thread(struct task_struct *dead_task)
+extern inline void release_thread(struct task_struct *dead_task)
 {
         /* Nothing needs to be done.  */
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-cris/rtc.h linux-2.4.21-pre6/include/asm-cris/rtc.h
--- linux-2.4.20/include/asm-cris/rtc.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-cris/rtc.h	2003-03-26 23:49:00.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: rtc.h,v 1.5 2002/08/14 11:04:10 sebsjo Exp $ */
+/* $Id: rtc.h,v 1.8 2002/11/20 14:27:25 oskarp Exp $ */
 
 #ifndef __RTC_H__
 #define __RTC_H__
@@ -53,17 +53,23 @@
 #  define RTC_MINUTE_ALARM	0x09
 #  define RTC_HOUR_ALARM	0x0a
 #  define RTC_DAY_ALARM		0x0b
-#  define RTC_WEEKDAY_ALARM 0x0c
+#  define RTC_WEEKDAY_ALARM 0x0c	/* Not coded in BCD! */
 
 #endif
 
 #ifdef CONFIG_ETRAX_DS1302
+extern unsigned char ds1302_readreg(int reg);
+extern void ds1302_writereg(int reg, unsigned char val);
+extern int ds1302_init(void);
 #  define CMOS_READ(x) ds1302_readreg(x)
 #  define CMOS_WRITE(val,reg) ds1302_writereg(reg,val)
 #  define RTC_INIT() ds1302_init()
 #elif defined(CONFIG_ETRAX_PCF8563)
-#  define CMOS_READ(x) i2c_readreg(RTC_I2C_READ, x)
-#  define CMOS_WRITE(val,reg) i2c_writereg(RTC_I2C_WRITE,reg,val)
+extern unsigned char pcf8563_readreg(int reg);
+extern void pcf8563_writereg(int reg, unsigned char val);
+extern int pcf8563_init(void);
+#  define CMOS_READ(x) pcf8563_readreg(x)
+#  define CMOS_WRITE(val,reg) pcf8563_writereg(reg,val)
 #  define RTC_INIT() pcf8563_init()
 #else
   /* No RTC configured so we shouldn't try to access any. */
@@ -94,17 +100,10 @@
 };
 
 /* ioctl() calls that are permitted to the /dev/rtc interface. */
-#ifdef CONFIG_ETRAX_DS1302
-#  define DS1302_MAGIC 'p'
-#  define RTC_RD_TIME		_IOR(DS1302_MAGIC, 0x09, struct rtc_time) 	/* Read RTC time. */
-#  define RTC_SET_TIME		_IOW(DS1302_MAGIC, 0x0a, struct rtc_time) 	/* Set RTC time. */
-#  define RTC_SET_CHARGE  	_IOW(DS1302_MAGIC, 0x0b, int) 				/* Set CHARGE mode. */
-#elif defined(CONFIG_ETRAX_PCF8563)
-#  define PCF8563_MAGIC 'T'
-#  define RTC_RD_TIME		_IOR(PCF8563_MAGIC, 0x01, struct rtc_time)	/* Read RTC time. */
-#  define RTC_SET_TIME		_IOW(PCF8563_MAGIC, 0x02, struct rtc_time)	/* Set RTC time. */
-#  define RTC_SET_CHARGE  	_IOW(PCF8563_MAGIC, 0x03, int) 		
-#  define RTC_MAX_IOCTL 3
-#endif
+#define RTC_MAGIC 'p'
+#define RTC_RD_TIME		_IOR(RTC_MAGIC, 0x09, struct rtc_time)	/* Read RTC time. */
+#define RTC_SET_TIME		_IOW(RTC_MAGIC, 0x0a, struct rtc_time)	/* Set RTC time. */
+#define RTC_SET_CHARGE  	_IOW(RTC_MAGIC, 0x0b, int) 		
+#define RTC_MAX_IOCTL 0x0b
 
 #endif /* __RTC_H__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-cris/scatterlist.h linux-2.4.21-pre6/include/asm-cris/scatterlist.h
--- linux-2.4.20/include/asm-cris/scatterlist.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-cris/scatterlist.h	2003-03-26 23:48:57.000000000 +0000
@@ -0,0 +1,18 @@
+#ifndef __ASM_CRIS_SCATTERLIST_H
+#define __ASM_CRIS_SCATTERLIST_H
+
+struct scatterlist {
+	char *  address;    /* Location data is to be transferred to */
+	unsigned int length;
+
+	/* The following is i386 highmem junk - not used by us */
+	struct page * page; /* Location for highmem page, if any */
+	unsigned int offset;/* for highmem, page offset */
+
+};
+
+/* i386 junk */
+
+#define ISA_DMA_THRESHOLD (0x1fffffff)
+
+#endif /* !(__ASM_CRIS_SCATTERLIST_H) */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-cris/semaphore-helper.h linux-2.4.21-pre6/include/asm-cris/semaphore-helper.h
--- linux-2.4.20/include/asm-cris/semaphore-helper.h	2001-05-01 23:05:00.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-cris/semaphore-helper.h	2003-03-26 23:49:34.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: semaphore-helper.h,v 1.3 2001/03/26 15:00:33 orjanf Exp $
+/* $Id: semaphore-helper.h,v 1.4 2002/11/20 18:20:17 hp Exp $
  *
  * SMP- and interrupt-safe semaphores helper functions. Generic versions, no
  * optimizations whatsoever... 
@@ -19,12 +19,12 @@
 /*
  * These two _must_ execute atomically wrt each other.
  */
-static inline void wake_one_more(struct semaphore * sem)
+extern inline void wake_one_more(struct semaphore * sem)
 {
 	atomic_inc(&sem->waking);
 }
 
-static inline int waking_non_zero(struct semaphore *sem)
+extern inline int waking_non_zero(struct semaphore *sem)
 {
 	unsigned long flags;
 	int ret = 0;
@@ -38,7 +38,7 @@
 	return ret;
 }
 
-static inline int waking_non_zero_interruptible(struct semaphore *sem,
+extern inline int waking_non_zero_interruptible(struct semaphore *sem,
 						struct task_struct *tsk)
 {
 	int ret = 0;
@@ -56,7 +56,7 @@
 	return ret;
 }
 
-static inline int waking_non_zero_trylock(struct semaphore *sem)
+extern inline int waking_non_zero_trylock(struct semaphore *sem)
 {
         int ret = 1;
 	unsigned long flags;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-cris/semaphore.h linux-2.4.21-pre6/include/asm-cris/semaphore.h
--- linux-2.4.20/include/asm-cris/semaphore.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-cris/semaphore.h	2003-03-26 23:49:26.000000000 +0000
@@ -1,4 +1,4 @@
-/* $Id: semaphore.h,v 1.3 2001/05/08 13:54:09 bjornw Exp $ */
+/* $Id: semaphore.h,v 1.5 2002/12/02 08:14:08 starvik Exp $ */
 
 /* On the i386 these are coded in asm, perhaps we should as well. Later.. */
 
@@ -54,12 +54,12 @@
 	*sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val);
 }
 
-static inline void init_MUTEX (struct semaphore *sem)
+extern inline void init_MUTEX (struct semaphore *sem)
 {
         sema_init(sem, 1);
 }
 
-static inline void init_MUTEX_LOCKED (struct semaphore *sem)
+extern inline void init_MUTEX_LOCKED (struct semaphore *sem)
 {
         sema_init(sem, 0);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-cris/sv_addr_ag.h linux-2.4.21-pre6/include/asm-cris/sv_addr_ag.h
--- linux-2.4.20/include/asm-cris/sv_addr_ag.h	2001-02-09 00:32:44.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-cris/sv_addr_ag.h	2003-03-26 23:49:54.000000000 +0000
@@ -25,33 +25,41 @@
 
 /* IO_MASK returns a mask for a specified bitfield in a register.
    Note that this macro doesn't work when field width is 32 bits. */
-#define IO_MASK(reg,field) \
-    ( ( ( 1 << reg##__##field##__WIDTH ) - 1 ) << reg##__##field##__BITNR )
+#define IO_MASK(reg, field) IO_MASK_ (reg##_, field##_)
+#define IO_MASK_(reg_, field_) \
+    ( ( ( 1 << reg_##_##field_##_WIDTH ) - 1 ) << reg_##_##field_##_BITNR )
 
 /* IO_STATE returns a constant corresponding to a one of the symbolic
    states that the bitfield can have. (Shifted to correct position)  */
-#define IO_STATE(reg,field,state) \
-    ( reg##__##field##__##state << reg##__##field##__BITNR )
+#define IO_STATE(reg, field, state) IO_STATE_ (reg##_, field##_, _##state)
+#define IO_STATE_(reg_, field_, _state) \
+    ( reg_##_##field_##_state << reg_##_##field_##_BITNR )
 
 /* IO_EXTRACT returns the masked and shifted value corresponding to the
    bitfield can have. */
-#define IO_EXTRACT(reg,field,val) ( (( ( ( 1 << reg##__##field##__WIDTH ) \
-     - 1 ) << reg##__##field##__BITNR ) & (val)) >> reg##__##field##__BITNR )
+#define IO_EXTRACT(reg, field, val) IO_EXTRACT_ (reg##_, field##_, val)
+#define IO_EXTRACT_(reg_, field_, val) ( (( ( ( 1 << reg_##_##field_##_WIDTH ) \
+     - 1 ) << reg_##_##field_##_BITNR ) & (val)) >> reg_##_##field_##_BITNR )
 
 /* IO_STATE_VALUE returns a constant corresponding to a one of the symbolic
    states that the bitfield can have. (Not shifted)  */
-#define IO_STATE_VALUE(reg,field,state) ( reg##__##field##__##state )
+#define IO_STATE_VALUE(reg, field, state) \
+    IO_STATE_VALUE_ (reg##_, field##_, _##state)
+#define IO_STATE_VALUE_(reg_, field_, _state) ( reg_##_##field_##_state )
 
 /* IO_FIELD shifts the val parameter to be aligned with the bitfield
    specified. */
-#define IO_FIELD(reg,field,val) ((val) << reg##__##field##__BITNR)
+#define IO_FIELD(reg, field, val) IO_FIELD_ (reg##_, field##_, val)
+#define IO_FIELD_(reg_, field_, val) ((val) << reg_##_##field_##_BITNR)
 
 /* IO_BITNR returns the starting bitnumber of a bitfield. Bit 0 is
    LSB and the returned bitnumber is LSB of the field. */
-#define IO_BITNR(reg,field) (reg##__##field##__BITNR)
+#define IO_BITNR(reg, field) IO_BITNR_ (reg##_, field##_)
+#define IO_BITNR_(reg_, field_) (reg_##_##field_##_BITNR)
 
 /* IO_WIDTH returns the width, in bits, of a bitfield. */
-#define IO_WIDTH(reg,field) (reg##__##field##__WIDTH)
+#define IO_WIDTH(reg, field) IO_WIDTH_ (reg##_, field##_)
+#define IO_WIDTH_(reg_, field_) (reg_##_##field_##_WIDTH)
 
 /*--- Obsolete. Kept for backw compatibility. ---*/
 /* Reads (or writes) a byte/uword/udword from the specified mode
@@ -66,7 +74,9 @@
 !*-----------------------------------------------------------*/
 
 #define MEM_CSE0_START (0x00000000)
+#define MEM_CSE0_SIZE (0x04000000)
 #define MEM_CSE1_START (0x04000000)
+#define MEM_CSE1_SIZE (0x04000000)
 #define MEM_CSR0_START (0x08000000)
 #define MEM_CSR1_START (0x0c000000)
 #define MEM_CSP0_START (0x10000000)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-cris/system.h linux-2.4.21-pre6/include/asm-cris/system.h
--- linux-2.4.20/include/asm-cris/system.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-cris/system.h	2003-03-26 23:49:40.000000000 +0000
@@ -16,7 +16,7 @@
 
 /* read the CPU version register */
 
-static inline unsigned long rdvr(void) { 
+extern inline unsigned long rdvr(void) { 
 	unsigned char vr;
 	__asm__ volatile ("move $vr,%0" : "=rm" (vr));
 	return vr;
@@ -24,7 +24,7 @@
 
 /* read/write the user-mode stackpointer */
 
-static inline unsigned long rdusp(void) {
+extern inline unsigned long rdusp(void) {
 	unsigned long usp;
 	__asm__ __volatile__("move $usp,%0" : "=rm" (usp));
 	return usp;
@@ -35,13 +35,13 @@
 
 /* read the current stackpointer */
 
-static inline unsigned long rdsp(void) {
+extern inline unsigned long rdsp(void) {
 	unsigned long sp;
 	__asm__ __volatile__("move.d $sp,%0" : "=rm" (sp));
 	return sp;
 }
 
-static inline unsigned long _get_base(char * addr)
+extern inline unsigned long _get_base(char * addr)
 {
   return 0;
 }
@@ -69,6 +69,7 @@
 
 /* For spinlocks etc */
 #define local_irq_save(x) __asm__ __volatile__ ("move $ccr,%0\n\tdi" : "=rm" (x) : : "memory"); 
+#define local_irq_set(x) __asm__ __volatile__ ("move $ccr,%0\n\tei" : "=rm" (x) : : "memory");
 #define local_irq_restore(x) restore_flags(x)
 
 #define local_irq_disable()  cli()
@@ -80,9 +81,10 @@
 #define sti() __sti()
 #define save_flags(x) __save_flags(x)
 #define restore_flags(x) __restore_flags(x)
-#define save_and_cli(x) do { __save_flags(x); cli(); } while(0)
+#define save_and_cli(x) do { save_flags(x); cli(); } while(0)
+#define save_and_sti(x) do { save_flags(x); sti(); } while(0)
 
-static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
+extern inline unsigned long __xchg(unsigned long x, void * ptr, int size)
 {
   /* since Etrax doesn't have any atomic xchg instructions, we need to disable
      irq's (if enabled) and do it with move.d's */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-cris/timex.h linux-2.4.21-pre6/include/asm-cris/timex.h
--- linux-2.4.20/include/asm-cris/timex.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-cris/timex.h	2003-03-26 23:49:25.000000000 +0000
@@ -26,7 +26,7 @@
 
 unsigned long get_ns_in_jiffie(void);
 
-static inline unsigned long get_us_in_jiffie_highres(void)
+extern inline unsigned long get_us_in_jiffie_highres(void)
 {
 	return get_ns_in_jiffie()/1000;
 }
@@ -37,7 +37,7 @@
 
 typedef unsigned int cycles_t;
 
-static inline cycles_t get_cycles(void)
+extern inline cycles_t get_cycles(void)
 {
         return 0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-cris/uaccess.h linux-2.4.21-pre6/include/asm-cris/uaccess.h
--- linux-2.4.20/include/asm-cris/uaccess.h	2001-11-09 22:11:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-cris/uaccess.h	2003-03-26 23:49:07.000000000 +0000
@@ -3,6 +3,9 @@
  *	       Hans-Peter Nilsson (hp@axis.com)
  *
  * $Log: uaccess.h,v $
+ * Revision 1.9  2002/11/20 18:20:17  hp
+ * Make all static inline functions extern inline.
+ *
  * Revision 1.8  2001/10/29 13:01:48  bjornw
  * Removed unused variable tmp2 in strnlen_user
  *
@@ -321,7 +324,7 @@
  * (without the null byte)
  */
 
-static inline long         
+extern inline long         
 __do_strncpy_from_user(char *dst, const char *src, long count)
 {
 	long res;
@@ -381,7 +384,7 @@
 	return res;
 }
 
-static inline unsigned long
+extern inline unsigned long
 __generic_copy_to_user(void *to, const void *from, unsigned long n)
 {
 	if (access_ok(VERIFY_WRITE, to, n))
@@ -389,7 +392,7 @@
 	return n;
 }
 
-static inline unsigned long
+extern inline unsigned long
 __generic_copy_from_user(void *to, const void *from, unsigned long n)
 {
 	if (access_ok(VERIFY_READ, from, n))
@@ -397,7 +400,7 @@
 	return n;
 }
 
-static inline unsigned long
+extern inline unsigned long
 __generic_clear_user(void *to, unsigned long n)
 {
 	if (access_ok(VERIFY_WRITE, to, n))
@@ -405,13 +408,13 @@
 	return n;
 }
 
-static inline long
+extern inline long
 __strncpy_from_user(char *dst, const char *src, long count)
 {
 	return __do_strncpy_from_user(dst, src, count);
 }
 
-static inline long
+extern inline long
 strncpy_from_user(char *dst, const char *src, long count)
 {
 	long res = -EFAULT;
@@ -871,7 +874,7 @@
 /* Note that if these expand awfully if made into switch constructs, so
    don't do that.  */
 
-static inline unsigned long
+extern inline unsigned long
 __constant_copy_from_user(void *to, const void *from, unsigned long n)
 {
 	unsigned long ret = 0;
@@ -921,7 +924,7 @@
 
 /* Ditto, don't make a switch out of this.  */
 
-static inline unsigned long
+extern inline unsigned long
 __constant_copy_to_user(void *to, const void *from, unsigned long n)
 {
 	unsigned long ret = 0;
@@ -971,7 +974,7 @@
 
 /* No switch, please.  */
 
-static inline unsigned long
+extern inline unsigned long
 __constant_clear_user(void *to, unsigned long n)
 {
 	unsigned long ret = 0;
@@ -1026,19 +1029,19 @@
  * used in fast paths and have only a small space overhead.
  */
 
-static inline unsigned long
+extern inline unsigned long
 __generic_copy_from_user_nocheck(void *to, const void *from, unsigned long n)
 {
 	return __copy_user_zeroing(to,from,n);
 }
 
-static inline unsigned long
+extern inline unsigned long
 __generic_copy_to_user_nocheck(void *to, const void *from, unsigned long n)
 {
 	return __copy_user(to,from,n);
 }
 
-static inline unsigned long
+extern inline unsigned long
 __generic_clear_user_nocheck(void *to, unsigned long n)
 {
 	return __do_clear_user(to,n);
@@ -1057,7 +1060,7 @@
  * or 0 for error.  Return a value greater than N if too long.
  */
 
-static inline long
+extern inline long
 strnlen_user(const char *s, long n)
 {
 	long res, tmp1;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-cris/unistd.h linux-2.4.21-pre6/include/asm-cris/unistd.h
--- linux-2.4.20/include/asm-cris/unistd.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-cris/unistd.h	2003-03-26 23:49:29.000000000 +0000
@@ -230,18 +230,51 @@
 #define __NR_security           223     /* syscall for security modules */
 #define __NR_gettid             224
 #define __NR_readahead          225
-#define __NR_tkill              226
+#define __NR_setxattr		226
+#define __NR_lsetxattr		227
+#define __NR_fsetxattr		228
+#define __NR_getxattr		229
+#define __NR_lgetxattr		230
+#define __NR_fgetxattr		231
+#define __NR_listxattr		232
+#define __NR_llistxattr		233
+#define __NR_flistxattr		234
+#define __NR_removexattr	235
+#define __NR_lremovexattr	236
+#define __NR_fremovexattr	237
+#define __NR_tkill		238
+#define __NR_sendfile64		239
+#define __NR_futex		240
+#define __NR_sched_setaffinity	241
+#define __NR_sched_getaffinity	242
+#define __NR_set_thread_area	243
+#define __NR_get_thread_area	244
+#define __NR_io_setup		245
+#define __NR_io_destroy		246
+#define __NR_io_getevents	247
+#define __NR_io_submit		248
+#define __NR_io_cancel		249
+#define __NR_alloc_hugepages	250
+#define __NR_free_hugepages	251
+#define __NR_exit_group		252
 
 /* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */
+/*
+ * Don't remove the .ifnc tests; they are an insurance against
+ * any hard-to-spot gcc register allocation bugs.
+ */
 #define _syscall0(type,name) \
 type name(void) \
 { \
   register long __a __asm__ ("r10"); \
-  __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \
+  register long __n_ __asm__ ("r9") = (__NR_##name); \
+  __asm__ __volatile__ (".ifnc %0%1,$r10$r9\n\t" \
+			".err\n\t" \
+			".endif\n\t" \
+			"break 13" \
 			: "=r" (__a) \
-			: "g" (__NR_##name) \
-			: "r10", "r9"); \
-  if(__a >= 0) \
+			: "r" (__n_)); \
+  if (__a >= 0) \
      return (type) __a; \
   errno = -__a; \
   return (type) -1; \
@@ -251,11 +284,14 @@
 type name(type1 arg1) \
 { \
   register long __a __asm__ ("r10") = (long) arg1; \
-  __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \
+  register long __n_ __asm__ ("r9") = (__NR_##name); \
+  __asm__ __volatile__ (".ifnc %0%1,$r10$r9\n\t" \
+			".err\n\t" \
+			".endif\n\t" \
+			"break 13" \
 			: "=r" (__a) \
-			: "g" (__NR_##name), "0" (__a) \
-			: "r10", "r9"); \
-  if(__a >= 0) \
+			: "r" (__n_), "0" (__a)); \
+  if (__a >= 0) \
      return (type) __a; \
   errno = -__a; \
   return (type) -1; \
@@ -266,11 +302,14 @@
 { \
   register long __a __asm__ ("r10") = (long) arg1; \
   register long __b __asm__ ("r11") = (long) arg2; \
-  __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \
+  register long __n_ __asm__ ("r9") = (__NR_##name); \
+  __asm__ __volatile__ (".ifnc %0%1%3,$r10$r9$r11\n\t" \
+			".err\n\t" \
+			".endif\n\t" \
+			"break 13" \
 			: "=r" (__a) \
-			: "g" (__NR_##name), "0" (__a), "r" (__b) \
-			: "r10", "r9"); \
-  if(__a >= 0) \
+			: "r" (__n_), "0" (__a), "r" (__b)); \
+  if (__a >= 0) \
      return (type) __a; \
   errno = -__a; \
   return (type) -1; \
@@ -282,11 +321,14 @@
   register long __a __asm__ ("r10") = (long) arg1; \
   register long __b __asm__ ("r11") = (long) arg2; \
   register long __c __asm__ ("r12") = (long) arg3; \
-  __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \
+  register long __n_ __asm__ ("r9") = (__NR_##name); \
+  __asm__ __volatile__ (".ifnc %0%1%3%4,$r10$r9$r11$r12\n\t" \
+			".err\n\t" \
+			".endif\n\t" \
+			"break 13" \
 			: "=r" (__a) \
-			: "g" (__NR_##name), "0" (__a), "r" (__b), "r" (__c) \
-			: "r10", "r9"); \
-  if(__a >= 0) \
+			: "r" (__n_), "0" (__a), "r" (__b), "r" (__c)); \
+  if (__a >= 0) \
      return (type) __a; \
   errno = -__a; \
   return (type) -1; \
@@ -299,12 +341,15 @@
   register long __b __asm__ ("r11") = (long) arg2; \
   register long __c __asm__ ("r12") = (long) arg3; \
   register long __d __asm__ ("r13") = (long) arg4; \
-  __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \
-			: "=r" (__a) \
-			: "g" (__NR_##name), "0" (__a), "r" (__b), \
-			  "r" (__c), "r" (__d) \
-			: "r10", "r9"); \
-  if(__a >= 0) \
+  register long __n_ __asm__ ("r9") = (__NR_##name); \
+  __asm__ __volatile__ (".ifnc %0%1%3%4%5,$r10$r9$r11$r12$r13\n\t" \
+			".err\n\t" \
+			".endif\n\t" \
+			"break 13" \
+			: "=r" (__a) \
+			: "r" (__n_), "0" (__a), "r" (__b), \
+			  "r" (__c), "r" (__d)); \
+  if (__a >= 0) \
      return (type) __a; \
   errno = -__a; \
   return (type) -1; \
@@ -318,13 +363,16 @@
   register long __b __asm__ ("r11") = (long) arg2; \
   register long __c __asm__ ("r12") = (long) arg3; \
   register long __d __asm__ ("r13") = (long) arg4; \
-  __asm__ __volatile__ ("move %6,$mof\n\t" \
-			"movu.w %1,$r9\n\tbreak 13" \
-			: "=r" (__a) \
-			: "g" (__NR_##name), "0" (__a), "r" (__b), \
-			  "r" (__c), "r" (__d), "g" (arg5) \
-			: "r10", "r9"); \
-  if(__a >= 0) \
+  register long __n_ __asm__ ("r9") = (__NR_##name); \
+  __asm__ __volatile__ (".ifnc %0%1%3%4%5,$r10$r9$r11$r12$r13\n\t" \
+			".err\n\t" \
+			".endif\n\t" \
+			"move %6,$mof\n\t" \
+			"break 13" \
+			: "=r" (__a) \
+			: "r" (__n_), "0" (__a), "r" (__b), \
+			  "r" (__c), "r" (__d), "g" (arg5)); \
+  if (__a >= 0) \
      return (type) __a; \
   errno = -__a; \
   return (type) -1; \
@@ -338,13 +386,17 @@
   register long __b __asm__ ("r11") = (long) arg2; \
   register long __c __asm__ ("r12") = (long) arg3; \
   register long __d __asm__ ("r13") = (long) arg4; \
-  __asm__ __volatile__ ("move %6,$mof\n\tmove %7,$srp\n\t" \
-			"movu.w %1,$r9\n\tbreak 13" \
+  register long __n_ __asm__ ("r9") = (__NR_##name); \
+  __asm__ __volatile__ (".ifnc %0%1%3%4%5,$r10$r9$r11$r12$r13\n\t" \
+			".err\n\t" \
+			".endif\n\t" \
+			"move %6,$mof\n\tmove %7,$srp\n\t" \
+			"break 13" \
 			: "=r" (__a) \
-			: "g" (__NR_##name), "0" (__a), "r" (__b), \
+			: "r" (__n_), "0" (__a), "r" (__b), \
 			  "r" (__c), "r" (__d), "g" (arg5), "g" (arg6)\
-			: "r10", "r9", "srp"); \
-  if(__a >= 0) \
+			: "srp"); \
+  if (__a >= 0) \
      return (type) __a; \
   errno = -__a; \
   return (type) -1; \
@@ -365,30 +417,40 @@
  * some others too.
  */
 #define __NR__exit __NR_exit
-static inline _syscall0(int,idle)
-static inline _syscall0(int,fork)
-static inline _syscall2(int,clone,unsigned long,flags,char *,esp)
-static inline _syscall0(int,pause)
-static inline _syscall0(int,setup)
-static inline _syscall0(int,sync)
-static inline _syscall0(pid_t,setsid)
-static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count)
-static inline _syscall1(int,dup,int,fd)
-static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
-static inline _syscall3(int,open,const char *,file,int,flag,int,mode)
-static inline _syscall1(int,close,int,fd)
-static inline _syscall1(int,_exit,int,exitcode)
-static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
-static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count)
+extern inline _syscall0(int,idle)
+extern inline _syscall0(int,fork)
+extern inline _syscall2(int,clone,unsigned long,flags,char *,esp)
+extern inline _syscall0(int,pause)
+extern inline _syscall0(int,setup)
+extern inline _syscall0(int,sync)
+extern inline _syscall0(pid_t,setsid)
+extern inline _syscall3(int,write,int,fd,const char *,buf,off_t,count)
+extern inline _syscall1(int,dup,int,fd)
+extern inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
+extern inline _syscall3(int,open,const char *,file,int,flag,int,mode)
+extern inline _syscall1(int,close,int,fd)
+
+/*
+ * Since we define it "external", it collides with the built-in
+ * definition, which has the "noreturn" attribute and will cause
+ * complaints.  We don't want to use -fno-builtin, so just use a
+ * different name when in the kernel.
+ */
+#ifdef __KERNEL__
+#define _exit kernel_syscall_exit
+#endif
+extern inline _syscall1(int,_exit,int,exitcode)
+extern inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
+extern inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count)
 
   /* the following are just while developing the elinux port! */
 
-static inline _syscall3(int,read,int,fd,char *,buf,off_t,count)
-static inline _syscall2(int,socketcall,int,call,unsigned long *,args)
-static inline _syscall3(int,ioctl,unsigned int,fd,unsigned int,cmd,unsigned long,arg)
-static inline _syscall5(int,mount,const char *,a,const char *,b,const char *,c,unsigned long,rwflag,const void *,data)
+extern inline _syscall3(int,read,int,fd,char *,buf,off_t,count)
+extern inline _syscall2(int,socketcall,int,call,unsigned long *,args)
+extern inline _syscall3(int,ioctl,unsigned int,fd,unsigned int,cmd,unsigned long,arg)
+extern inline _syscall5(int,mount,const char *,a,const char *,b,const char *,c,unsigned long,rwflag,const void *,data)
 
-static inline pid_t wait(int * wait_stat)
+extern inline pid_t wait(int * wait_stat)
 {
 	return waitpid(-1,wait_stat,0);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-generic/ide_iops.h linux-2.4.21-pre6/include/asm-generic/ide_iops.h
--- linux-2.4.20/include/asm-generic/ide_iops.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-generic/ide_iops.h	2003-03-26 23:49:50.000000000 +0000
@@ -0,0 +1,38 @@
+/* Generic I/O and MEMIO string operations.  */
+
+#define __ide_insw	insw
+#define __ide_insl	insl
+#define __ide_outsw	outsw
+#define __ide_outsl	outsl
+
+static __inline__ void __ide_mm_insw(unsigned long port, void *addr, u32 count)
+{
+	while (count--) {
+		*(u16 *)addr = readw(port);
+		addr += 2;
+	}
+}
+
+static __inline__ void __ide_mm_insl(unsigned long port, void *addr, u32 count)
+{
+	while (count--) {
+		*(u32 *)addr = readl(port);
+		addr += 4;
+	}
+}
+
+static __inline__ void __ide_mm_outsw(unsigned long port, void *addr, u32 count)
+{
+	while (count--) {
+		writew(*(u16 *)addr, port);
+		addr += 2;
+	}
+}
+
+static __inline__ void __ide_mm_outsl(unsigned long port, void *addr, u32 count)
+{
+	while (count--) {
+		writel(*(u32 *)addr, port);
+		addr += 4;
+	}
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-i386/apicdef.h linux-2.4.21-pre6/include/asm-i386/apicdef.h
--- linux-2.4.20/include/asm-i386/apicdef.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-i386/apicdef.h	2003-03-26 23:49:40.000000000 +0000
@@ -32,6 +32,7 @@
 #define			SET_APIC_LOGICAL_ID(x)	(((x)<<24))
 #define			APIC_ALL_CPUS		0xFF
 #define		APIC_DFR	0xE0
+#define			APIC_DFR_CLUSTER	0x0FFFFFFFul	/* Clustered */
 #define			APIC_DFR_FLAT		0xFFFFFFFFul	/* Flat mode */
 #define		APIC_SPIV	0xF0
 #define			APIC_SPIV_FOCUS_DISABLED	(1<<9)
@@ -58,6 +59,7 @@
 #define			APIC_INT_LEVELTRIG	0x08000
 #define			APIC_INT_ASSERT		0x04000
 #define			APIC_ICR_BUSY		0x01000
+#define			APIC_DEST_PHYSICAL	0x00000
 #define			APIC_DEST_LOGICAL	0x00800
 #define			APIC_DM_FIXED		0x00000
 #define			APIC_DM_LOWEST		0x00100
@@ -108,11 +110,18 @@
 
 #define APIC_BASE (fix_to_virt(FIX_APIC_BASE))
 
+#ifdef CONFIG_X86_CLUSTERED_APIC
+#define MAX_IO_APICS 32
+#else
 #define MAX_IO_APICS 8
+#endif
+
 
 /*
- * The broadcast ID is 0xF for old APICs.
+ * The broadcast ID is 0xF for old APICs and 0xFF for xAPICs.  SAPICs
+ * don't broadcast (yet?), but if they did, they might use 0xFFFF.
  */
+#define APIC_BROADCAST_ID_XAPIC (0xFF)
 #define APIC_BROADCAST_ID_APIC  (0x0F)
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-i386/byteorder.h linux-2.4.21-pre6/include/asm-i386/byteorder.h
--- linux-2.4.20/include/asm-i386/byteorder.h	2001-11-22 19:46:18.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-i386/byteorder.h	2003-03-26 23:49:40.000000000 +0000
@@ -24,21 +24,41 @@
 	return x;
 }
 
+/* gcc should generate this for open coded C now too. May be worth switching to 
+   it because inline assembly cannot be scheduled. -AK */
 static __inline__ __const__ __u16 ___arch__swab16(__u16 x)
 {
-	__asm__("xchgb %b0,%h0"		/* swap bytes		*/ \
-		: "=q" (x) \
-		:  "0" (x)); \
+	__asm__("xchgb %b0,%h0"		/* swap bytes		*/
+		: "=q" (x)
+		:  "0" (x));
 		return x;
 }
 
+
+static inline __u64 ___arch__swab64(__u64 val) 
+{ 
+	union { 
+		struct { __u32 a,b; } s;
+		__u64 u;
+	} v;
+	v.u = val;
+#ifdef CONFIG_X86_BSWAP
+	asm("bswapl %0 ; bswapl %1 ; xchgl %0,%1" 
+	    : "=r" (v.s.a), "=r" (v.s.b) 
+	    : "0" (v.s.a), "1" (v.s.b)); 
+#else
+   v.s.a = ___arch__swab32(v.s.a); 
+	v.s.b = ___arch__swab32(v.s.b); 
+	asm("xchgl %0,%1" : "=r" (v.s.a), "=r" (v.s.b) : "0" (v.s.a), "1" (v.s.b));
+#endif
+	return v.u;	
+} 
+
+#define __arch__swab64(x) ___arch__swab64(x)
 #define __arch__swab32(x) ___arch__swab32(x)
 #define __arch__swab16(x) ___arch__swab16(x)
 
-#if !defined(__STRICT_ANSI__) || defined(__KERNEL__)
-#  define __BYTEORDER_HAS_U64__
-#  define __SWAB_64_THRU_32__
-#endif
+#define __BYTEORDER_HAS_U64__
 
 #endif /* __GNUC__ */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-i386/cpufeature.h linux-2.4.21-pre6/include/asm-i386/cpufeature.h
--- linux-2.4.20/include/asm-i386/cpufeature.h	2001-12-21 17:42:03.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-i386/cpufeature.h	2003-03-26 23:49:09.000000000 +0000
@@ -64,6 +64,8 @@
 #define X86_FEATURE_CYRIX_ARR	(3*32+ 2) /* Cyrix ARRs (= MTRRs) */
 #define X86_FEATURE_CENTAUR_MCR	(3*32+ 3) /* Centaur MCRs (= MTRRs) */
 
+#define cpu_has(c, bit)            test_bit(bit, (c)->x86_capability)
+
 #endif /* __ASM_I386_CPUFEATURE_H */
 
 /* 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-i386/delay.h linux-2.4.21-pre6/include/asm-i386/delay.h
--- linux-2.4.20/include/asm-i386/delay.h	2000-12-31 18:26:18.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-i386/delay.h	2003-03-26 23:48:57.000000000 +0000
@@ -8,13 +8,19 @@
  */
  
 extern void __bad_udelay(void);
+extern void __bad_ndelay(void);
 
 extern void __udelay(unsigned long usecs);
+extern void __ndelay(unsigned long nsecs);
 extern void __const_udelay(unsigned long usecs);
 extern void __delay(unsigned long loops);
 
 #define udelay(n) (__builtin_constant_p(n) ? \
 	((n) > 20000 ? __bad_udelay() : __const_udelay((n) * 0x10c6ul)) : \
 	__udelay(n))
+	
+#define ndelay(n) (__builtin_constant_p(n) ? \
+	((n) > 20000 ? __bad_ndelay() : __const_udelay((n) * 5ul)) : \
+	__ndelay(n))
 
 #endif /* defined(_I386_DELAY_H) */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-i386/fixmap.h linux-2.4.21-pre6/include/asm-i386/fixmap.h
--- linux-2.4.20/include/asm-i386/fixmap.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-i386/fixmap.h	2003-03-26 23:48:59.000000000 +0000
@@ -64,6 +64,9 @@
 #ifndef CONFIG_X86_F00F_WORKS_OK
 	FIX_F00F,
 #endif
+#ifdef CONFIG_X86_SUMMIT
+	FIX_CYCLONE_TIMER, /*cyclone timer register*/
+#endif 
 #ifdef CONFIG_HIGHMEM
 	FIX_KMAP_BEGIN,	/* reserved pte's for temporary kernel mappings */
 	FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-i386/floppy.h linux-2.4.21-pre6/include/asm-i386/floppy.h
--- linux-2.4.20/include/asm-i386/floppy.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-i386/floppy.h	2003-03-26 23:49:18.000000000 +0000
@@ -22,7 +22,7 @@
  * floppy accesses go through the track buffer.
  */
 #define _CROSS_64KB(a,s,vdma) \
-(!vdma && ((unsigned long)(a)/K_64 != ((unsigned long)(a) + (s) - 1) / K_64))
+(!(vdma) && ((unsigned long)(a)/K_64 != ((unsigned long)(a) + (s) - 1) / K_64))
 
 #define CROSS_64KB(a,s) _CROSS_64KB(a,s,use_virtual_dma & 1)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-i386/hdreg.h linux-2.4.21-pre6/include/asm-i386/hdreg.h
--- linux-2.4.20/include/asm-i386/hdreg.h	1999-05-13 18:00:08.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-i386/hdreg.h	2003-03-26 23:49:00.000000000 +0000
@@ -7,6 +7,7 @@
 #ifndef __ASMi386_HDREG_H
 #define __ASMi386_HDREG_H
 
-typedef unsigned short ide_ioreg_t;
+//typedef unsigned short ide_ioreg_t;
+typedef unsigned long ide_ioreg_t;
 
 #endif /* __ASMi386_HDREG_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-i386/highmem.h linux-2.4.21-pre6/include/asm-i386/highmem.h
--- linux-2.4.20/include/asm-i386/highmem.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-i386/highmem.h	2003-03-26 23:49:06.000000000 +0000
@@ -56,16 +56,19 @@
 #define PKMAP_NR(virt)  ((virt-PKMAP_BASE) >> PAGE_SHIFT)
 #define PKMAP_ADDR(nr)  (PKMAP_BASE + ((nr) << PAGE_SHIFT))
 
-extern void * FASTCALL(kmap_high(struct page *page));
+extern void * FASTCALL(kmap_high(struct page *page, int nonblocking));
 extern void FASTCALL(kunmap_high(struct page *page));
 
-static inline void *kmap(struct page *page)
+#define kmap(page) __kmap(page, 0)
+#define kmap_nonblock(page) __kmap(page, 1)
+
+static inline void *__kmap(struct page *page, int nonblocking)
 {
 	if (in_interrupt())
 		out_of_line_bug();
 	if (page < highmem_start_page)
 		return page_address(page);
-	return kmap_high(page);
+	return kmap_high(page, nonblocking);
 }
 
 static inline void kunmap(struct page *page)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-i386/ide.h linux-2.4.21-pre6/include/asm-i386/ide.h
--- linux-2.4.20/include/asm-i386/ide.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-i386/ide.h	2003-03-26 23:49:06.000000000 +0000
@@ -23,8 +23,6 @@
 # endif
 #endif
 
-#define ide__sti()	__sti()
-
 static __inline__ int ide_default_irq(ide_ioreg_t base)
 {
 	switch (base) {
@@ -79,6 +77,7 @@
 	int index;
 
 	for(index = 0; index < MAX_HWIFS; index++) {
+		memset(&hw, 0, sizeof hw);
 		ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL);
 		hw.irq = ide_default_irq(ide_default_io_base(index));
 		ide_register_hw(&hw, NULL);
@@ -86,42 +85,7 @@
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned bit0		: 1;
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned reserved456	: 3;
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-	} b;
-} control_t;
-
-#define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
-#define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
-#define ide_check_region(from,extent)		check_region((from), (extent))
-#define ide_request_region(from,extent,name)	request_region((from), (extent), (name))
-#define ide_release_region(from,extent)		release_region((from), (extent))
-
-/*
- * The following are not needed for the non-m68k ports
- */
-#define ide_ack_intr(hwif)		(1)
-#define ide_fix_driveid(id)		do {} while (0)
-#define ide_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
+#include <asm-generic/ide_iops.h>
 
 #endif /* __KERNEL__ */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-i386/io.h linux-2.4.21-pre6/include/asm-i386/io.h
--- linux-2.4.20/include/asm-i386/io.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-i386/io.h	2003-03-26 23:49:35.000000000 +0000
@@ -187,9 +187,9 @@
 #define __raw_writew writew
 #define __raw_writel writel
 
-#define memset_io(a,b,c)	memset(__io_virt(a),(b),(c))
-#define memcpy_fromio(a,b,c)	memcpy((a),__io_virt(b),(c))
-#define memcpy_toio(a,b,c)	memcpy(__io_virt(a),(b),(c))
+#define memset_io(a,b,c)	__memset(__io_virt(a),(b),(c))
+#define memcpy_fromio(a,b,c)	__memcpy((a),__io_virt(b),(c))
+#define memcpy_toio(a,b,c)	__memcpy(__io_virt(a),(b),(c))
 
 /*
  * ISA space is 'always mapped' on a typical x86 system, no need to
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-i386/io_apic.h linux-2.4.21-pre6/include/asm-i386/io_apic.h
--- linux-2.4.20/include/asm-i386/io_apic.h	2002-02-25 19:38:12.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-i386/io_apic.h	2003-03-26 23:49:50.000000000 +0000
@@ -97,7 +97,7 @@
 extern int mp_irq_entries;
 
 /* MP IRQ source entries */
-extern struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES];
+extern struct mpc_config_intsrc *mp_irqs;
 
 /* non-0 if default (table-less) MP configuration */
 extern int mpc_default_type;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-i386/mpspec.h linux-2.4.21-pre6/include/asm-i386/mpspec.h
--- linux-2.4.20/include/asm-i386/mpspec.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-i386/mpspec.h	2003-03-26 23:48:57.000000000 +0000
@@ -15,12 +15,13 @@
 
 /*
  * a maximum of 16 APICs with the current APIC ID architecture.
+ * xAPICs can have up to 256.  SAPICs have 16 ID bits.
  */
-#ifdef CONFIG_MULTIQUAD
+#ifdef CONFIG_X86_CLUSTERED_APIC
 #define MAX_APICS 256
-#else /* !CONFIG_MULTIQUAD */
+#else
 #define MAX_APICS 16
-#endif /* CONFIG_MULTIQUAD */
+#endif
 
 #define MAX_MPC_ENTRY 1024
 
@@ -197,11 +198,11 @@
 	MP_BUS_PCI,
 	MP_BUS_MCA
 };
-extern int mp_bus_id_to_type [MAX_MP_BUSSES];
-extern int mp_bus_id_to_node [MAX_MP_BUSSES];
-extern int mp_bus_id_to_local [MAX_MP_BUSSES];
+extern int *mp_bus_id_to_type;
+extern int *mp_bus_id_to_node;
+extern int *mp_bus_id_to_local;
+extern int *mp_bus_id_to_pci_bus;
 extern int quad_local_to_mp_bus_id [NR_CPUS/4][4];
-extern int mp_bus_id_to_pci_bus [MAX_MP_BUSSES];
 
 extern unsigned int boot_cpu_physical_apicid;
 extern unsigned long phys_cpu_present_map;
@@ -210,11 +211,9 @@
 extern void get_smp_config (void);
 extern int nr_ioapics;
 extern int apic_version [MAX_APICS];
-extern int mp_bus_id_to_type [MAX_MP_BUSSES];
 extern int mp_irq_entries;
-extern struct mpc_config_intsrc mp_irqs [MAX_IRQ_SOURCES];
+extern struct mpc_config_intsrc *mp_irqs;
 extern int mpc_default_type;
-extern int mp_bus_id_to_pci_bus [MAX_MP_BUSSES];
 extern int mp_current_pci_id;
 extern unsigned long mp_lapic_addr;
 extern int pic_mode;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-i386/msr.h linux-2.4.21-pre6/include/asm-i386/msr.h
--- linux-2.4.20/include/asm-i386/msr.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-i386/msr.h	2003-03-26 23:48:58.000000000 +0000
@@ -87,6 +87,7 @@
 #define MSR_K7_EVNTSEL0			0xC0010000
 #define MSR_K7_PERFCTR0			0xC0010004
 #define MSR_K7_HWCR			0xC0010015
+#define MSR_K7_CLK_CTL			0xC001001b
 #define MSR_K7_FID_VID_CTL		0xC0010041
 #define MSR_K7_VID_STATUS		0xC0010042
 
@@ -114,5 +115,7 @@
 /* Transmeta defined MSRs */
 #define MSR_TMTA_LONGRUN_CTRL		0x80868010
 #define MSR_TMTA_LONGRUN_FLAGS		0x80868011
+#define MSR_TMTA_LRTI_READOUT		0x80868018
+#define MSR_TMTA_LRTI_VOLT_MHZ		0x8086801a
 
 #endif /* __ASM_MSR_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-i386/pci.h linux-2.4.21-pre6/include/asm-i386/pci.h
--- linux-2.4.20/include/asm-i386/pci.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-i386/pci.h	2003-03-26 23:49:34.000000000 +0000
@@ -103,7 +103,9 @@
 	if (direction == PCI_DMA_NONE)
 		out_of_line_bug();
 
-	return (dma_addr_t)(page - mem_map) * PAGE_SIZE + offset;
+	return ((dma_addr_t)(page - mem_map) *
+		(dma_addr_t) PAGE_SIZE +
+		(dma_addr_t) offset);
 }
 
 static inline void pci_unmap_page(struct pci_dev *hwdev, dma_addr_t dma_address,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-i386/processor.h linux-2.4.21-pre6/include/asm-i386/processor.h
--- linux-2.4.20/include/asm-i386/processor.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-i386/processor.h	2003-03-26 23:48:59.000000000 +0000
@@ -433,7 +433,7 @@
 /*
  * create a kernel thread without removing it from tasklists
  */
-extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
+extern int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
 /* Copy and release all segment info associated with a VM */
 extern void copy_segments(struct task_struct *p, struct mm_struct * mm);
@@ -483,7 +483,7 @@
 #define cpu_relax()	rep_nop()
 
 /* Prefetch instructions for Pentium III and AMD Athlon */
-#ifdef 	CONFIG_MPENTIUMIII
+#if defined(CONFIG_MPENTIUMIII) || defined (CONFIG_MPENTIUM4)
 
 #define ARCH_HAS_PREFETCH
 extern inline void prefetch(const void *x)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-i386/smpboot.h linux-2.4.21-pre6/include/asm-i386/smpboot.h
--- linux-2.4.20/include/asm-i386/smpboot.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-i386/smpboot.h	2003-03-26 23:49:30.000000000 +0000
@@ -8,54 +8,74 @@
 	CLUSTERED_APIC_NUMAQ
 };
 
-#ifdef CONFIG_MULTIQUAD
- #define clustered_apic_mode (CLUSTERED_APIC_NUMAQ)
-#else /* !CONFIG_MULTIQUAD */
- #define clustered_apic_mode (CLUSTERED_APIC_NONE)
-#endif /* CONFIG_MULTIQUAD */
-
-#ifdef CONFIG_X86_LOCAL_APIC
+#ifdef CONFIG_X86_CLUSTERED_APIC
+extern unsigned int apic_broadcast_id;
+extern unsigned char clustered_apic_mode;
 extern unsigned char esr_disable;
-static inline int target_cpus(void)
+extern unsigned char int_delivery_mode;
+extern unsigned int int_dest_addr_mode;
+extern int cyclone_setup(char*);
+
+static inline void detect_clustered_apic(char* oem, char* prod)
 {
-	switch(clustered_apic_mode){
-		case CLUSTERED_APIC_NUMAQ:
-			/* Broadcast intrs to local quad only. */
-			return APIC_BROADCAST_ID_APIC;
-		default:
+	/*
+	 * Can't recognize Summit xAPICs at present, so use the OEM ID.
+	 */
+	if (!strncmp(oem, "IBM ENSW", 8) && !strncmp(prod, "VIGIL SMP", 9)){
+		clustered_apic_mode = CLUSTERED_APIC_XAPIC;
+		apic_broadcast_id = APIC_BROADCAST_ID_XAPIC;
+		int_dest_addr_mode = APIC_DEST_PHYSICAL;
+		int_delivery_mode = dest_Fixed;
+		esr_disable = 1;
+		/*Start cyclone clock*/
+		cyclone_setup(0);
+	}
+	else if (!strncmp(oem, "IBM NUMA", 8)){
+		clustered_apic_mode = CLUSTERED_APIC_NUMAQ;
+		apic_broadcast_id = APIC_BROADCAST_ID_APIC;
+		int_dest_addr_mode = APIC_DEST_LOGICAL;
+		int_delivery_mode = dest_LowestPrio;
+		esr_disable = 1;
 	}
-	return cpu_online_map;
 }
-#ifdef CONFIG_X86_IO_APIC
-extern unsigned char int_delivery_mode;
-extern unsigned int int_dest_addr_mode;
 #define	INT_DEST_ADDR_MODE (int_dest_addr_mode)
 #define	INT_DELIVERY_MODE (int_delivery_mode)
-#endif /* CONFIG_X86_IO_APIC */
-#else /* CONFIG_X86_LOCAL_APIC */
+#else /* CONFIG_X86_CLUSTERED_APIC */
+#define apic_broadcast_id (APIC_BROADCAST_ID_APIC)
+#define clustered_apic_mode (CLUSTERED_APIC_NONE)
 #define esr_disable (0)
-#define target_cpus() (0x01)
-#ifdef CONFIG_X86_IO_APIC
+#define detect_clustered_apic(x,y)
 #define INT_DEST_ADDR_MODE (APIC_DEST_LOGICAL)	/* logical delivery */
 #define INT_DELIVERY_MODE (dest_LowestPrio)
-#endif /* CONFIG_X86_IO_APIC */
-#endif /* CONFIG_X86_LOCAL_APIC */
+#endif /* CONFIG_X86_CLUSTERED_APIC */
+#define BAD_APICID 0xFFu
 
 #define TRAMPOLINE_LOW phys_to_virt((clustered_apic_mode == CLUSTERED_APIC_NUMAQ)?0x8:0x467)
 #define TRAMPOLINE_HIGH phys_to_virt((clustered_apic_mode == CLUSTERED_APIC_NUMAQ)?0xa:0x469)
 
 #define boot_cpu_apicid ((clustered_apic_mode == CLUSTERED_APIC_NUMAQ)?boot_cpu_logical_apicid:boot_cpu_physical_apicid)
 
+extern unsigned char raw_phys_apicid[NR_CPUS];
+
 /*
  * How to map from the cpu_present_map
  */
 static inline int cpu_present_to_apicid(int mps_cpu)
 {
+	if (clustered_apic_mode == CLUSTERED_APIC_XAPIC)
+		return raw_phys_apicid[mps_cpu];
 	if(clustered_apic_mode == CLUSTERED_APIC_NUMAQ)
 		return (mps_cpu/4)*16 + (1<<(mps_cpu%4));
 	return mps_cpu;
 }
 
+static inline unsigned long apicid_to_phys_cpu_present(int apicid)
+{
+	if(clustered_apic_mode)
+		return 1UL << (((apicid >> 4) << 2) + (apicid & 0x3));
+	return 1UL << apicid;
+}
+
 #define physical_to_logical_apicid(phys_apic) ( (1ul << (phys_apic & 0x3)) | (phys_apic & 0xF0u) )
 
 /*
@@ -79,4 +99,23 @@
 #define cpu_to_boot_apicid(cpu) cpu_2_physical_apicid[cpu]
 #endif /* CONFIG_MULTIQUAD */
 
+#ifdef CONFIG_X86_CLUSTERED_APIC
+static inline int target_cpus(void)
+{
+	static int cpu;
+	switch(clustered_apic_mode){
+		case CLUSTERED_APIC_NUMAQ:
+			/* Broadcast intrs to local quad only. */
+			return APIC_BROADCAST_ID_APIC;
+		case CLUSTERED_APIC_XAPIC:
+			/*round robin the interrupts*/
+			cpu = (cpu+1)%smp_num_cpus;
+			return cpu_to_physical_apicid(cpu);
+		default:
+	}
+	return cpu_online_map;
+}
+#else
+#define target_cpus() (cpu_online_map)
+#endif
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-i386/smplock.h linux-2.4.21-pre6/include/asm-i386/smplock.h
--- linux-2.4.20/include/asm-i386/smplock.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-i386/smplock.h	2003-03-26 23:49:24.000000000 +0000
@@ -1,3 +1,6 @@
+#ifndef __ASM_SMPLOCK_H
+#define __ASM_SMPLOCK_H
+
 /*
  * <asm/smplock.h>
  *
@@ -74,3 +77,5 @@
 		 "=m" (current->lock_depth));
 #endif
 }
+
+#endif /* __ASM_SMPLOCK_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-i386/system.h linux-2.4.21-pre6/include/asm-i386/system.h
--- linux-2.4.20/include/asm-i386/system.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-i386/system.h	2003-03-26 23:48:58.000000000 +0000
@@ -322,8 +322,18 @@
 /* used in the idle loop; sti takes one instruction cycle to complete */
 #define safe_halt()		__asm__ __volatile__("sti; hlt": : :"memory")
 
+#define __save_and_cli(x)	do { __save_flags(x); __cli(); } while(0);
+#define __save_and_sti(x)	do { __save_flags(x); __sti(); } while(0);
+
 /* For spinlocks etc */
+#if 0
 #define local_irq_save(x)	__asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */ :"memory")
+#define local_irq_set(x)	__asm__ __volatile__("pushfl ; popl %0 ; sti":"=g" (x): /* no input */ :"memory")
+#else
+#define local_irq_save(x)	__save_and_cli(x)
+#define local_irq_set(x)	__save_and_sti(x)
+#endif
+
 #define local_irq_restore(x)	__restore_flags(x)
 #define local_irq_disable()	__cli()
 #define local_irq_enable()	__sti()
@@ -338,6 +348,8 @@
 #define sti() __global_sti()
 #define save_flags(x) ((x)=__global_save_flags())
 #define restore_flags(x) __global_restore_flags(x)
+#define save_and_cli(x) do { save_flags(x); cli(); } while(0);
+#define save_and_sti(x) do { save_flags(x); sti(); } while(0);
 
 #else
 
@@ -345,6 +357,8 @@
 #define sti() __sti()
 #define save_flags(x) __save_flags(x)
 #define restore_flags(x) __restore_flags(x)
+#define save_and_cli(x) __save_and_cli(x)
+#define save_and_sti(x) __save_and_sti(x)
 
 #endif
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/acpi.h linux-2.4.21-pre6/include/asm-ia64/acpi.h
--- linux-2.4.20/include/asm-ia64/acpi.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/acpi.h	2003-03-26 23:49:30.000000000 +0000
@@ -56,7 +56,7 @@
 
 #define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) \
 	do { \
-	__asm__ volatile ("1:  ld4      r29=%1\n"  \
+	__asm__ volatile ("1:  ld4      r29=[%1]\n"  \
 		";;\n"                  \
 		"mov    ar.ccv=r29\n"   \
 		"mov    r2=r29\n"       \
@@ -68,7 +68,7 @@
 		";;\n"                  \
 		"add    r29=r29,r30\n"  \
 		";;\n"                  \
-		"cmpxchg4.acq   r30=%1,r29,ar.ccv\n" \
+		"cmpxchg4.acq   r30=[%1],r29,ar.ccv\n" \
 		";;\n"                  \
 		"cmp.eq p6,p7=r2,r30\n" \
 		"(p7) br.dpnt.few 1b\n" \
@@ -76,24 +76,24 @@
 		";;\n"                  \
 		"(p8) mov %0=-1\n"      \
 		"(p9) mov %0=r0\n"      \
-		:"=r"(Acq):"m"(GLptr):"r2","r29","r30","memory"); \
+		:"=r"(Acq):"r"(GLptr):"r2","r29","r30","memory"); \
 	} while (0)
 
 #define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq) \
 	do { \
-	__asm__ volatile ("1:  ld4      r29=%1\n" \
+	__asm__ volatile ("1:  ld4      r29=[%1]\n" \
 		";;\n"                  \
 		"mov    ar.ccv=r29\n"   \
 		"mov    r2=r29\n"       \
 		"and    r29=-4,r29\n"   \
 		";;\n"                  \
-		"cmpxchg4.acq   r30=%1,r29,ar.ccv\n" \
+		"cmpxchg4.acq   r30=[%1],r29,ar.ccv\n" \
 		";;\n"                  \
 		"cmp.eq p6,p7=r2,r30\n" \
 		"(p7) br.dpnt.few 1b\n" \
 		"and    %0=1,r2\n"      \
 		";;\n"                  \
-		:"=r"(Acq):"m"(GLptr):"r2","r29","r30","memory"); \
+		:"=r"(Acq):"r"(GLptr):"r2","r29","r30","memory"); \
 	} while (0)
 
 const char *acpi_get_sysname (void);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/bitops.h linux-2.4.21-pre6/include/asm-ia64/bitops.h
--- linux-2.4.20/include/asm-ia64/bitops.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/bitops.h	2003-03-26 23:49:54.000000000 +0000
@@ -2,8 +2,8 @@
 #define _ASM_IA64_BITOPS_H
 
 /*
- * Copyright (C) 1998-2001 Hewlett-Packard Co
- * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998-2003 Hewlett-Packard Co
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
 #include <asm/system.h>
@@ -289,7 +289,7 @@
 static inline unsigned long
 ia64_fls (unsigned long x)
 {
-	double d = x;
+	long double d = x;
 	long exp;
 
 	__asm__ ("getf.exp %0=%1" : "=r"(exp) : "f"(d));
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/delay.h linux-2.4.21-pre6/include/asm-ia64/delay.h
--- linux-2.4.20/include/asm-ia64/delay.h	2001-04-05 19:51:47.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/delay.h	2003-03-26 23:48:58.000000000 +0000
@@ -82,4 +82,14 @@
 		/* skip */;
 }
 
+static __inline__ void
+ndelay (unsigned long nsecs)
+{
+	unsigned long start = ia64_get_itc();
+	unsigned long cycles = nsecs*local_cpu_data->cyc_per_usec/1000;
+
+	while (ia64_get_itc() - start < cycles)
+		/* skip */;
+}
+
 #endif /* _ASM_IA64_DELAY_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/hdreg.h linux-2.4.21-pre6/include/asm-ia64/hdreg.h
--- linux-2.4.20/include/asm-ia64/hdreg.h	2000-02-07 02:42:40.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/hdreg.h	2003-03-26 23:49:31.000000000 +0000
@@ -7,6 +7,7 @@
 #ifndef __ASM_IA64_HDREG_H
 #define __ASM_IA64_HDREG_H
 
-typedef unsigned short ide_ioreg_t;
+//typedef unsigned short ide_ioreg_t;
+typedef unsigned long ide_ioreg_t;
 
 #endif /* __ASM_IA64_HDREG_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/ia32.h linux-2.4.21-pre6/include/asm-ia64/ia32.h
--- linux-2.4.20/include/asm-ia64/ia32.h	2001-11-09 22:26:17.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/ia32.h	2003-03-26 23:49:55.000000000 +0000
@@ -73,6 +73,17 @@
        unsigned short exponent;
 };
 
+struct _fpxreg_ia32 {
+        unsigned short significand[4];
+        unsigned short exponent;
+        unsigned short padding[3];
+};
+
+struct _xmmreg_ia32 {
+        unsigned int element[4];
+};
+
+
 struct _fpstate_ia32 {
        unsigned int    cw,
 		       sw,
@@ -82,7 +93,16 @@
 		       dataoff,
 		       datasel;
        struct _fpreg_ia32      _st[8];
-       unsigned int    status;
+       unsigned short  status;
+       unsigned short  magic;          /* 0xffff = regular FPU data only */
+
+       /* FXSR FPU environment */
+       unsigned int         _fxsr_env[6];   /* FXSR FPU env is ignored */
+       unsigned int         mxcsr;
+       unsigned int         reserved;
+       struct _fpxreg_ia32  _fxsr_st[8];    /* FXSR FPU reg data is ignored */
+       struct _xmmreg_ia32  _xmm[8];
+       unsigned int         padding[56];
 };
 
 struct sigcontext_ia32 {
@@ -110,6 +130,44 @@
        unsigned int cr2;
 };
 
+/* user.h */
+/*
+ * IA32 (Pentium III/4) FXSR, SSE support
+ *
+ * Provide support for the GDB 5.0+ PTRACE_{GET|SET}FPXREGS requests for
+ * interacting with the FXSR-format floating point environment.  Floating
+ * point data can be accessed in the regular format in the usual manner,
+ * and both the standard and SIMD floating point data can be accessed via
+ * the new ptrace requests.  In either case, changes to the FPU environment
+ * will be reflected in the task's state as expected.
+ */
+struct ia32_user_i387_struct {
+	int	cwd;
+	int	swd;
+	int	twd;
+	int	fip;
+	int	fcs;
+	int	foo;
+	int	fos;
+	int	st_space[20];	/* 8*10 bytes for each FP-reg = 80 bytes */
+};
+
+struct ia32_user_fxsr_struct {
+	unsigned short	cwd;
+	unsigned short	swd;
+	unsigned short	twd;
+	unsigned short	fop;
+	int	fip;
+	int	fcs;
+	int	foo;
+	int	fos;
+	int	mxcsr;
+	int	reserved;
+	int	st_space[32];	/* 8*16 bytes for each FP-reg = 128 bytes */
+	int	xmm_space[32];	/* 8*16 bytes for each XMM-reg = 128 bytes */
+	int	padding[56];
+};
+
 /* signal.h */
 #define _IA32_NSIG	       64
 #define _IA32_NSIG_BPW	       32
@@ -443,6 +501,8 @@
 #define IA32_PTRACE_SETREGS	13
 #define IA32_PTRACE_GETFPREGS	14
 #define IA32_PTRACE_SETFPREGS	15
+#define IA32_PTRACE_GETFPXREGS	18
+#define IA32_PTRACE_SETFPXREGS	19
 
 #define ia32_start_thread(regs,new_ip,new_sp) do {				\
 	set_fs(USER_DS);							\
@@ -485,6 +545,18 @@
 extern unsigned long ia32_do_mmap (struct file *, unsigned long, unsigned long, int, int, loff_t);
 extern void ia32_load_segment_descriptors (struct task_struct *task);
 
+#define ia32f2ia64f(dst,src) \
+	do { \
+	register double f6 asm ("f6"); \
+	asm volatile ("ldfe f6=[%2];; stf.spill [%1]=f6" : "=f"(f6): "r"(dst), "r"(src) : "memory"); \
+	} while(0)
+
+#define ia64f2ia32f(dst,src) \
+	do { \
+	register double f6 asm ("f6"); \
+	asm volatile ("ldf.fill f6=[%2];; stfe [%1]=f6" : "=f"(f6): "r"(dst),  "r"(src) : "memory"); \
+	} while(0)
+
 #endif /* !CONFIG_IA32_SUPPORT */
 
 #endif /* _ASM_IA64_IA32_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/ide.h linux-2.4.21-pre6/include/asm-ia64/ide.h
--- linux-2.4.20/include/asm-ia64/ide.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/ide.h	2003-03-26 23:48:58.000000000 +0000
@@ -25,8 +25,6 @@
 # endif
 #endif
 
-#define ide__sti()	__sti()
-
 static __inline__ int ide_default_irq(ide_ioreg_t base)
 {
 	switch (base) {
@@ -88,42 +86,7 @@
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned bit0		: 1;
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned reserved456	: 3;
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-	} b;
-} control_t;
-
-#define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
-#define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
-#define ide_check_region(from,extent)		check_region((from), (extent))
-#define ide_request_region(from,extent,name)	request_region((from), (extent), (name))
-#define ide_release_region(from,extent)		release_region((from), (extent))
-
-/*
- * The following are not needed for the non-m68k ports
- */
-#define ide_ack_intr(hwif)		(1)
-#define ide_fix_driveid(id)		do {} while (0)
-#define ide_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
+#include <asm-generic/ide_iops.h>
 
 #endif /* __KERNEL__ */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/io.h linux-2.4.21-pre6/include/asm-ia64/io.h
--- linux-2.4.20/include/asm-ia64/io.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/io.h	2003-03-26 23:48:59.000000000 +0000
@@ -13,7 +13,7 @@
  * over and over again with slight variations and possibly making a
  * mistake somewhere.
  *
- * Copyright (C) 1998-2001 Hewlett-Packard Co
+ * Copyright (C) 1998-2002 Hewlett-Packard Co
  *	David Mosberger-Tang <davidm@hpl.hp.com>
  * Copyright (C) 1999 Asit Mallick <asit.k.mallick@intel.com>
  * Copyright (C) 1999 Don Dugger <don.dugger@intel.com>
@@ -32,6 +32,24 @@
  */
 #define IO_SPACE_LIMIT		0xffffffffffffffffUL
 
+#define MAX_IO_SPACES			16
+#define IO_SPACE_BITS			24
+#define IO_SPACE_SIZE			(1UL << IO_SPACE_BITS)
+
+#define IO_SPACE_NR(port)		((port) >> IO_SPACE_BITS)
+#define IO_SPACE_BASE(space)		((space) << IO_SPACE_BITS)
+#define IO_SPACE_PORT(port)		((port) & (IO_SPACE_SIZE - 1))
+
+#define IO_SPACE_SPARSE_ENCODING(p)	((((p) >> 2) << 12) | (p & 0xfff))
+
+struct io_space {
+	unsigned long mmio_base;	/* base in MMIO space */
+	int sparse;
+};
+
+extern struct io_space io_space[];
+extern unsigned int num_io_spaces;
+
 # ifdef __KERNEL__
 
 #include <asm/machvec.h>
@@ -80,11 +98,17 @@
 static inline void*
 __ia64_mk_io_addr (unsigned long port)
 {
-	const unsigned long io_base = __ia64_get_io_port_base();
-	unsigned long addr;
+	struct io_space *space;
+	unsigned long offset;
+
+	space = &io_space[IO_SPACE_NR(port)];
+	port = IO_SPACE_PORT(port);
+	if (space->sparse)
+		offset = IO_SPACE_SPARSE_ENCODING(port);
+	else
+		offset = port;
 
-	addr = io_base | ((port >> 2) << 12) | (port & 0xfff);
-	return (void *) addr;
+	return (void *) (space->mmio_base | offset);
 }
 
 /*
@@ -261,9 +285,9 @@
 }
 
 /*
- * Unfortunately, some platforms are broken and do not follow the
- * IA-64 architecture specification regarding legacy I/O support.
- * Thus, we have to make these operations platform dependent...
+ * Unfortunately, some platforms are broken and do not follow the IA-64 architecture
+ * specification regarding legacy I/O support.  Thus, we have to make these operations
+ * platform dependent...
  */
 #define __inb		platform_inb
 #define __inw		platform_inw
@@ -272,18 +296,18 @@
 #define __outw		platform_outw
 #define __outl		platform_outl
 
-#define inb		__inb
-#define inw		__inw
-#define inl		__inl
-#define insb		__insb
-#define insw		__insw
-#define insl		__insl
-#define outb		__outb
-#define outw		__outw
-#define outl		__outl
-#define outsb		__outsb
-#define outsw		__outsw
-#define outsl		__outsl
+#define inb(p)		__inb(p)
+#define inw(p)		__inw(p)
+#define inl(p)		__inl(p)
+#define insb(p,d,c)	__insb(p,d,c)
+#define insw(p,d,c)	__insw(p,d,c)
+#define insl(p,d,c)	__insl(p,d,c)
+#define outb(v,p)	__outb(v,p)
+#define outw(v,p)	__outw(v,p)
+#define outl(v,p)	__outl(v,p)
+#define outsb(p,s,c)	__outsb(p,s,c)
+#define outsw(p,s,c)	__outsw(p,s,c)
+#define outsl(p,s,c)	__outsl(p,s,c)
 
 /*
  * The address passed to these functions are ioremap()ped already.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/machvec.h linux-2.4.21-pre6/include/asm-ia64/machvec.h
--- linux-2.4.20/include/asm-ia64/machvec.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/machvec.h	2003-03-26 23:48:57.000000000 +0000
@@ -25,7 +25,7 @@
 typedef void ia64_mv_irq_init_t (void);
 typedef void ia64_mv_pci_fixup_t (int);
 typedef void ia64_mv_pci_enable_device_t (struct pci_dev *);
-typedef unsigned long ia64_mv_map_nr_t (unsigned long);
+typedef unsigned long ia64_mv_map_nr_t (void *);
 typedef void ia64_mv_mca_init_t (void);
 typedef void ia64_mv_mca_handler_t (void);
 typedef void ia64_mv_cmci_handler_t (int, void *, struct pt_regs *);
@@ -46,7 +46,6 @@
 typedef void ia64_mv_pci_unmap_sg (struct pci_dev *, struct scatterlist *, int, int);
 typedef void ia64_mv_pci_dma_sync_single (struct pci_dev *, dma_addr_t, size_t, int);
 typedef void ia64_mv_pci_dma_sync_sg (struct pci_dev *, struct scatterlist *, int, int);
-typedef unsigned long ia64_mv_pci_dma_address (struct scatterlist *);
 typedef int ia64_mv_pci_dma_supported (struct pci_dev *, u64);
 
 /*
@@ -104,7 +103,6 @@
 #  define platform_pci_unmap_sg		ia64_mv.unmap_sg
 #  define platform_pci_dma_sync_single	ia64_mv.sync_single
 #  define platform_pci_dma_sync_sg	ia64_mv.sync_sg
-#  define platform_pci_dma_address	ia64_mv.dma_address
 #  define platform_pci_dma_supported	ia64_mv.dma_supported
 #  define platform_irq_desc		ia64_mv.irq_desc
 #  define platform_irq_to_vector	ia64_mv.irq_to_vector
@@ -140,7 +138,6 @@
 	ia64_mv_pci_unmap_sg *unmap_sg;
 	ia64_mv_pci_dma_sync_single *sync_single;
 	ia64_mv_pci_dma_sync_sg *sync_sg;
-	ia64_mv_pci_dma_address *dma_address;
 	ia64_mv_pci_dma_supported *dma_supported;
 	ia64_mv_irq_desc *irq_desc;
 	ia64_mv_irq_to_vector *irq_to_vector;
@@ -177,7 +174,6 @@
 	platform_pci_unmap_sg,			\
 	platform_pci_dma_sync_single,		\
 	platform_pci_dma_sync_sg,		\
-	platform_pci_dma_address,		\
 	platform_pci_dma_supported,		\
 	platform_irq_desc,			\
 	platform_irq_to_vector,			\
@@ -209,7 +205,6 @@
 extern ia64_mv_pci_unmap_sg swiotlb_unmap_sg;
 extern ia64_mv_pci_dma_sync_single swiotlb_sync_single;
 extern ia64_mv_pci_dma_sync_sg swiotlb_sync_sg;
-extern ia64_mv_pci_dma_address swiotlb_dma_address;
 extern ia64_mv_pci_dma_supported swiotlb_pci_dma_supported;
 
 /*
@@ -276,9 +271,6 @@
 #ifndef platform_pci_dma_sync_sg
 # define platform_pci_dma_sync_sg	swiotlb_sync_sg
 #endif
-#ifndef platform_pci_dma_address
-# define  platform_pci_dma_address	swiotlb_dma_address
-#endif
 #ifndef platform_pci_dma_supported
 # define  platform_pci_dma_supported	swiotlb_pci_dma_supported
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/machvec_hpzx1.h linux-2.4.21-pre6/include/asm-ia64/machvec_hpzx1.h
--- linux-2.4.20/include/asm-ia64/machvec_hpzx1.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/machvec_hpzx1.h	2003-03-26 23:48:57.000000000 +0000
@@ -11,7 +11,6 @@
 extern ia64_mv_pci_unmap_single sba_unmap_single;
 extern ia64_mv_pci_map_sg sba_map_sg;
 extern ia64_mv_pci_unmap_sg sba_unmap_sg;
-extern ia64_mv_pci_dma_address sba_dma_address;
 extern ia64_mv_pci_dma_supported sba_dma_supported;
 
 /*
@@ -35,7 +34,6 @@
 #define platform_pci_unmap_sg		sba_unmap_sg
 #define platform_pci_dma_sync_single	((ia64_mv_pci_dma_sync_single *) machvec_noop)
 #define platform_pci_dma_sync_sg	((ia64_mv_pci_dma_sync_sg *) machvec_noop)
-#define platform_pci_dma_address	sba_dma_address
 #define platform_pci_dma_supported	sba_dma_supported
 
 #endif /* _ASM_IA64_MACHVEC_HPZX1_h */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/machvec_sn1.h linux-2.4.21-pre6/include/asm-ia64/machvec_sn1.h
--- linux-2.4.20/include/asm-ia64/machvec_sn1.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/machvec_sn1.h	2003-03-26 23:49:50.000000000 +0000
@@ -42,7 +42,6 @@
 extern ia64_mv_irq_desc sn_irq_desc;
 extern ia64_mv_irq_to_vector sn_irq_to_vector;
 extern ia64_mv_local_vector_to_irq sn_local_vector_to_irq;
-extern ia64_mv_valid_irq sn_valid_irq;
 extern ia64_mv_pci_fixup_t sn_pci_fixup;
 extern ia64_mv_inb_t sn_inb;
 extern ia64_mv_inw_t sn_inw;
@@ -58,7 +57,6 @@
 extern ia64_mv_pci_unmap_sg		sn_pci_unmap_sg;
 extern ia64_mv_pci_dma_sync_single	sn_pci_dma_sync_single;
 extern ia64_mv_pci_dma_sync_sg		sn_pci_dma_sync_sg;
-extern ia64_mv_pci_dma_address		sn_dma_address;
 extern ia64_mv_pci_dma_supported	sn_pci_dma_supported;
 
 /*
@@ -81,11 +79,10 @@
 #define platform_inl			sn_inl
 #define platform_outb			sn_outb
 #define platform_outw			sn_outw
-#define platform_oul			sn_outl
+#define platform_outl			sn_outl
 #define platform_irq_desc		sn_irq_desc
 #define platform_irq_to_vector		sn_irq_to_vector
 #define platform_local_vector_to_irq	sn_local_vector_to_irq
-#define platform_valid_irq		sn_valid_irq
 #define platform_pci_dma_init		machvec_noop
 #define platform_pci_alloc_consistent	sn_pci_alloc_consistent
 #define platform_pci_free_consistent	sn_pci_free_consistent
@@ -95,7 +92,6 @@
 #define platform_pci_unmap_sg		sn_pci_unmap_sg
 #define platform_pci_dma_sync_single	sn_pci_dma_sync_single
 #define platform_pci_dma_sync_sg	sn_pci_dma_sync_sg
-#define platform_pci_dma_address	sn_dma_address
 #define platform_pci_dma_supported	sn_pci_dma_supported
 
 #endif /* _ASM_IA64_MACHVEC_SN1_h */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/machvec_sn2.h linux-2.4.21-pre6/include/asm-ia64/machvec_sn2.h
--- linux-2.4.20/include/asm-ia64/machvec_sn2.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/machvec_sn2.h	2003-03-26 23:48:58.000000000 +0000
@@ -42,7 +42,6 @@
 extern ia64_mv_irq_desc sn_irq_desc;
 extern ia64_mv_irq_to_vector sn_irq_to_vector;
 extern ia64_mv_local_vector_to_irq sn_local_vector_to_irq;
-extern ia64_mv_valid_irq sn_valid_irq;
 extern ia64_mv_pci_fixup_t sn_pci_fixup;
 extern ia64_mv_inb_t sn_inb;
 extern ia64_mv_inw_t sn_inw;
@@ -58,7 +57,6 @@
 extern ia64_mv_pci_unmap_sg		sn_pci_unmap_sg;
 extern ia64_mv_pci_dma_sync_single	sn_pci_dma_sync_single;
 extern ia64_mv_pci_dma_sync_sg		sn_pci_dma_sync_sg;
-extern ia64_mv_pci_dma_address		sn_dma_address;
 extern ia64_mv_pci_dma_supported	sn_pci_dma_supported;
 
 /*
@@ -81,11 +79,10 @@
 #define platform_inl			sn_inl
 #define platform_outb			sn_outb
 #define platform_outw			sn_outw
-#define platform_oul			sn_outl
+#define platform_outl			sn_outl
 #define platform_irq_desc		sn_irq_desc
 #define platform_irq_to_vector		sn_irq_to_vector
 #define platform_local_vector_to_irq	sn_local_vector_to_irq
-#define platform_valid_irq		sn_valid_irq
 #define platform_pci_dma_init		machvec_noop
 #define platform_pci_alloc_consistent	sn_pci_alloc_consistent
 #define platform_pci_free_consistent	sn_pci_free_consistent
@@ -95,7 +92,6 @@
 #define platform_pci_unmap_sg		sn_pci_unmap_sg
 #define platform_pci_dma_sync_single	sn_pci_dma_sync_single
 #define platform_pci_dma_sync_sg	sn_pci_dma_sync_sg
-#define platform_pci_dma_address	sn_dma_address
 #define platform_pci_dma_supported	sn_pci_dma_supported
 
 #endif /* _ASM_IA64_MACHVEC_SN2_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/mc146818rtc.h linux-2.4.21-pre6/include/asm-ia64/mc146818rtc.h
--- linux-2.4.20/include/asm-ia64/mc146818rtc.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/mc146818rtc.h	2003-03-26 23:49:20.000000000 +0000
@@ -0,0 +1,10 @@
+#ifndef _ASM_IA64_MC146818RTC_H
+#define _ASM_IA64_MC146818RTC_H
+
+/*
+ * Machine dependent access functions for RTC registers.
+ */
+
+/* empty include file to satisfy the include in genrtc.c */
+
+#endif /* _ASM_IA64_MC146818RTC_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/mca.h linux-2.4.21-pre6/include/asm-ia64/mca.h
--- linux-2.4.20/include/asm-ia64/mca.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/mca.h	2003-03-26 23:49:18.000000000 +0000
@@ -103,6 +103,8 @@
 	IA64_MCA_NEW_CONTEXT	=	-1	/* SAL to return to new context */
 };
 
+#define MIN_STATE_AREA_SIZE     57
+
 typedef struct ia64_mca_os_to_sal_state_s {
 	u64		imots_os_status;	/*   OS status to SAL as to what happened
 						 *   with the MCA handling.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/mca_asm.h linux-2.4.21-pre6/include/asm-ia64/mca_asm.h
--- linux-2.4.20/include/asm-ia64/mca_asm.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/mca_asm.h	2003-03-26 23:49:54.000000000 +0000
@@ -16,6 +16,7 @@
 #define PSR_I		14
 #define	PSR_DT		17
 #define PSR_RT		27
+#define PSR_MC		35
 #define PSR_IT		36
 #define PSR_BN		44
 
@@ -107,6 +108,8 @@
 	;;										\
 	dep	temp1 = 0, temp1, PSR_IC, 1;						\
 	;;										\
+	dep	temp1 = -1, temp1, PSR_MC, 1;						\
+	;;										\
 	movl	temp2 = start_addr;							\
 	mov	cr.ipsr = temp1;							\
 	;;										\
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/mmu.h linux-2.4.21-pre6/include/asm-ia64/mmu.h
--- linux-2.4.20/include/asm-ia64/mmu.h	2000-12-29 22:07:23.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/mmu.h	2003-03-26 23:48:58.000000000 +0000
@@ -1,7 +1,11 @@
 #ifndef __MMU_H
 #define __MMU_H
 
-/* Default "unsigned long" context */
-typedef unsigned long mm_context_t;
+/*
+ * Type for a context number.  We declare it volatile to ensure proper ordering when it's
+ * accessed outside of spinlock'd critical sections (e.g., as done in activate_mm() and
+ * init_new_context()).
+ */
+typedef volatile unsigned long mm_context_t;
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/mmu_context.h linux-2.4.21-pre6/include/asm-ia64/mmu_context.h
--- linux-2.4.20/include/asm-ia64/mmu_context.h	2001-11-09 22:26:17.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/mmu_context.h	2003-03-26 23:49:07.000000000 +0000
@@ -44,26 +44,32 @@
 {
 }
 
-static inline void
-get_new_mmu_context (struct mm_struct *mm)
+static inline mm_context_t
+get_mmu_context (struct mm_struct *mm)
 {
+	mm_context_t context = mm->context;
+
+	if (context)
+		return context;
+
 	spin_lock(&ia64_ctx.lock);
 	{
-		if (ia64_ctx.next >= ia64_ctx.limit)
-			wrap_mmu_context(mm);
-		mm->context = ia64_ctx.next++;
+		/* re-check, now that we've got the lock: */
+		context = mm->context;
+		if (context == 0) {
+			if (ia64_ctx.next >= ia64_ctx.limit)
+				wrap_mmu_context(mm);
+			mm->context = context = ia64_ctx.next++;
+		}
 	}
 	spin_unlock(&ia64_ctx.lock);
-
-}
-
-static inline void
-get_mmu_context (struct mm_struct *mm)
-{
-	if (mm->context == 0)
-		get_new_mmu_context(mm);
+	return context;
 }
 
+/*
+ * Initialize context number to some sane value.  MM is guaranteed to be a brand-new
+ * address-space, so no TLB flushing is needed, ever.
+ */
 static inline int
 init_new_context (struct task_struct *p, struct mm_struct *mm)
 {
@@ -78,13 +84,13 @@
 }
 
 static inline void
-reload_context (struct mm_struct *mm)
+reload_context (mm_context_t context)
 {
 	unsigned long rid;
 	unsigned long rid_incr = 0;
 	unsigned long rr0, rr1, rr2, rr3, rr4;
 
-	rid = mm->context << 3;	/* make space for encoding the region number */
+	rid = context << 3;	/* make space for encoding the region number */
 	rid_incr = 1 << 8;
 
 	/* encode the region id, preferred page size, and VHPT enable bit: */
@@ -103,6 +109,18 @@
 	ia64_insn_group_barrier();
 }
 
+static inline void
+activate_context (struct mm_struct *mm)
+{
+	mm_context_t context;
+
+	do {
+		context = get_mmu_context(mm);
+		reload_context(context);
+		/* in the unlikely event of a TLB-flush by another thread, redo the load: */
+	} while (unlikely(context != mm->context));
+}
+
 /*
  * Switch from address space PREV to address space NEXT.
  */
@@ -110,12 +128,11 @@
 activate_mm (struct mm_struct *prev, struct mm_struct *next)
 {
 	/*
-	 * We may get interrupts here, but that's OK because interrupt
-	 * handlers cannot touch user-space.
+	 * We may get interrupts here, but that's OK because interrupt handlers cannot
+	 * touch user-space.
 	 */
 	ia64_set_kr(IA64_KR_PT_BASE, __pa(next->pgd));
-	get_mmu_context(next);
-	reload_context(next);
+	activate_context(next);
 }
 
 #define switch_mm(prev_mm,next_mm,next_task,cpu)	activate_mm(prev_mm, next_mm)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/offsets.h linux-2.4.21-pre6/include/asm-ia64/offsets.h
--- linux-2.4.20/include/asm-ia64/offsets.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/offsets.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,142 +0,0 @@
-#ifndef _ASM_IA64_OFFSETS_H
-#define _ASM_IA64_OFFSETS_H
-/*
- * DO NOT MODIFY
- *
- * This file was generated by arch/ia64/tools/print_offsets.awk.
- *
- */
-#define PT_PTRACED_BIT		0
-#define PT_TRACESYS_BIT		1
-#define IA64_TASK_SIZE			3424	/* 0xd60 */
-#define IA64_PT_REGS_SIZE		400	/* 0x190 */
-#define IA64_SWITCH_STACK_SIZE		560	/* 0x230 */
-#define IA64_SIGINFO_SIZE		128	/* 0x80 */
-#define IA64_CPU_SIZE			16384	/* 0x4000 */
-#define SIGFRAME_SIZE			2816	/* 0xb00 */
-#define UNW_FRAME_INFO_SIZE		448	/* 0x1c0 */
-
-#define IA64_TASK_PTRACE_OFFSET		48	/* 0x30 */
-#define IA64_TASK_SIGPENDING_OFFSET	16	/* 0x10 */
-#define IA64_TASK_NEED_RESCHED_OFFSET	40	/* 0x28 */
-#define IA64_TASK_PROCESSOR_OFFSET	96	/* 0x60 */
-#define IA64_TASK_THREAD_OFFSET		992	/* 0x3e0 */
-#define IA64_TASK_THREAD_KSP_OFFSET	992	/* 0x3e0 */
-#define IA64_TASK_PFM_OVFL_BLOCK_RESET_OFFSET 1616	/* 0x650 */
-#define IA64_TASK_PID_OFFSET		228	/* 0xe4 */
-#define IA64_TASK_MM_OFFSET		88	/* 0x58 */
-#define IA64_PT_REGS_CR_IPSR_OFFSET	0	/* 0x0 */
-#define IA64_PT_REGS_CR_IIP_OFFSET	8	/* 0x8 */
-#define IA64_PT_REGS_CR_IFS_OFFSET	16	/* 0x10 */
-#define IA64_PT_REGS_AR_UNAT_OFFSET	24	/* 0x18 */
-#define IA64_PT_REGS_AR_PFS_OFFSET	32	/* 0x20 */
-#define IA64_PT_REGS_AR_RSC_OFFSET	40	/* 0x28 */
-#define IA64_PT_REGS_AR_RNAT_OFFSET	48	/* 0x30 */
-#define IA64_PT_REGS_AR_BSPSTORE_OFFSET	56	/* 0x38 */
-#define IA64_PT_REGS_PR_OFFSET		64	/* 0x40 */
-#define IA64_PT_REGS_B6_OFFSET		72	/* 0x48 */
-#define IA64_PT_REGS_LOADRS_OFFSET	80	/* 0x50 */
-#define IA64_PT_REGS_R1_OFFSET		88	/* 0x58 */
-#define IA64_PT_REGS_R2_OFFSET		96	/* 0x60 */
-#define IA64_PT_REGS_R3_OFFSET		104	/* 0x68 */
-#define IA64_PT_REGS_R12_OFFSET		112	/* 0x70 */
-#define IA64_PT_REGS_R13_OFFSET		120	/* 0x78 */
-#define IA64_PT_REGS_R14_OFFSET		128	/* 0x80 */
-#define IA64_PT_REGS_R15_OFFSET		136	/* 0x88 */
-#define IA64_PT_REGS_R8_OFFSET		144	/* 0x90 */
-#define IA64_PT_REGS_R9_OFFSET		152	/* 0x98 */
-#define IA64_PT_REGS_R10_OFFSET		160	/* 0xa0 */
-#define IA64_PT_REGS_R11_OFFSET		168	/* 0xa8 */
-#define IA64_PT_REGS_R16_OFFSET		176	/* 0xb0 */
-#define IA64_PT_REGS_R17_OFFSET		184	/* 0xb8 */
-#define IA64_PT_REGS_R18_OFFSET		192	/* 0xc0 */
-#define IA64_PT_REGS_R19_OFFSET		200	/* 0xc8 */
-#define IA64_PT_REGS_R20_OFFSET		208	/* 0xd0 */
-#define IA64_PT_REGS_R21_OFFSET		216	/* 0xd8 */
-#define IA64_PT_REGS_R22_OFFSET		224	/* 0xe0 */
-#define IA64_PT_REGS_R23_OFFSET		232	/* 0xe8 */
-#define IA64_PT_REGS_R24_OFFSET		240	/* 0xf0 */
-#define IA64_PT_REGS_R25_OFFSET		248	/* 0xf8 */
-#define IA64_PT_REGS_R26_OFFSET		256	/* 0x100 */
-#define IA64_PT_REGS_R27_OFFSET		264	/* 0x108 */
-#define IA64_PT_REGS_R28_OFFSET		272	/* 0x110 */
-#define IA64_PT_REGS_R29_OFFSET		280	/* 0x118 */
-#define IA64_PT_REGS_R30_OFFSET		288	/* 0x120 */
-#define IA64_PT_REGS_R31_OFFSET		296	/* 0x128 */
-#define IA64_PT_REGS_AR_CCV_OFFSET	304	/* 0x130 */
-#define IA64_PT_REGS_AR_FPSR_OFFSET	312	/* 0x138 */
-#define IA64_PT_REGS_B0_OFFSET		320	/* 0x140 */
-#define IA64_PT_REGS_B7_OFFSET		328	/* 0x148 */
-#define IA64_PT_REGS_F6_OFFSET		336	/* 0x150 */
-#define IA64_PT_REGS_F7_OFFSET		352	/* 0x160 */
-#define IA64_PT_REGS_F8_OFFSET		368	/* 0x170 */
-#define IA64_PT_REGS_F9_OFFSET		384	/* 0x180 */
-#define IA64_SWITCH_STACK_CALLER_UNAT_OFFSET 0	/* 0x0 */
-#define IA64_SWITCH_STACK_AR_FPSR_OFFSET 8	/* 0x8 */
-#define IA64_SWITCH_STACK_F2_OFFSET	16	/* 0x10 */
-#define IA64_SWITCH_STACK_F3_OFFSET	32	/* 0x20 */
-#define IA64_SWITCH_STACK_F4_OFFSET	48	/* 0x30 */
-#define IA64_SWITCH_STACK_F5_OFFSET	64	/* 0x40 */
-#define IA64_SWITCH_STACK_F10_OFFSET	80	/* 0x50 */
-#define IA64_SWITCH_STACK_F11_OFFSET	96	/* 0x60 */
-#define IA64_SWITCH_STACK_F12_OFFSET	112	/* 0x70 */
-#define IA64_SWITCH_STACK_F13_OFFSET	128	/* 0x80 */
-#define IA64_SWITCH_STACK_F14_OFFSET	144	/* 0x90 */
-#define IA64_SWITCH_STACK_F15_OFFSET	160	/* 0xa0 */
-#define IA64_SWITCH_STACK_F16_OFFSET	176	/* 0xb0 */
-#define IA64_SWITCH_STACK_F17_OFFSET	192	/* 0xc0 */
-#define IA64_SWITCH_STACK_F18_OFFSET	208	/* 0xd0 */
-#define IA64_SWITCH_STACK_F19_OFFSET	224	/* 0xe0 */
-#define IA64_SWITCH_STACK_F20_OFFSET	240	/* 0xf0 */
-#define IA64_SWITCH_STACK_F21_OFFSET	256	/* 0x100 */
-#define IA64_SWITCH_STACK_F22_OFFSET	272	/* 0x110 */
-#define IA64_SWITCH_STACK_F23_OFFSET	288	/* 0x120 */
-#define IA64_SWITCH_STACK_F24_OFFSET	304	/* 0x130 */
-#define IA64_SWITCH_STACK_F25_OFFSET	320	/* 0x140 */
-#define IA64_SWITCH_STACK_F26_OFFSET	336	/* 0x150 */
-#define IA64_SWITCH_STACK_F27_OFFSET	352	/* 0x160 */
-#define IA64_SWITCH_STACK_F28_OFFSET	368	/* 0x170 */
-#define IA64_SWITCH_STACK_F29_OFFSET	384	/* 0x180 */
-#define IA64_SWITCH_STACK_F30_OFFSET	400	/* 0x190 */
-#define IA64_SWITCH_STACK_F31_OFFSET	416	/* 0x1a0 */
-#define IA64_SWITCH_STACK_R4_OFFSET	432	/* 0x1b0 */
-#define IA64_SWITCH_STACK_R5_OFFSET	440	/* 0x1b8 */
-#define IA64_SWITCH_STACK_R6_OFFSET	448	/* 0x1c0 */
-#define IA64_SWITCH_STACK_R7_OFFSET	456	/* 0x1c8 */
-#define IA64_SWITCH_STACK_B0_OFFSET	464	/* 0x1d0 */
-#define IA64_SWITCH_STACK_B1_OFFSET	472	/* 0x1d8 */
-#define IA64_SWITCH_STACK_B2_OFFSET	480	/* 0x1e0 */
-#define IA64_SWITCH_STACK_B3_OFFSET	488	/* 0x1e8 */
-#define IA64_SWITCH_STACK_B4_OFFSET	496	/* 0x1f0 */
-#define IA64_SWITCH_STACK_B5_OFFSET	504	/* 0x1f8 */
-#define IA64_SWITCH_STACK_AR_PFS_OFFSET	512	/* 0x200 */
-#define IA64_SWITCH_STACK_AR_LC_OFFSET	520	/* 0x208 */
-#define IA64_SWITCH_STACK_AR_UNAT_OFFSET 528	/* 0x210 */
-#define IA64_SWITCH_STACK_AR_RNAT_OFFSET 536	/* 0x218 */
-#define IA64_SWITCH_STACK_AR_BSPSTORE_OFFSET 544	/* 0x220 */
-#define IA64_SWITCH_STACK_PR_OFFSET	552	/* 0x228 */
-#define IA64_SIGCONTEXT_IP_OFFSET	40	/* 0x28 */
-#define IA64_SIGCONTEXT_AR_BSP_OFFSET	72	/* 0x48 */
-#define IA64_SIGCONTEXT_AR_FPSR_OFFSET	104	/* 0x68 */
-#define IA64_SIGCONTEXT_AR_RNAT_OFFSET	80	/* 0x50 */
-#define IA64_SIGCONTEXT_AR_UNAT_OFFSET	96	/* 0x60 */
-#define IA64_SIGCONTEXT_B0_OFFSET	136	/* 0x88 */
-#define IA64_SIGCONTEXT_CFM_OFFSET	48	/* 0x30 */
-#define IA64_SIGCONTEXT_FLAGS_OFFSET	0	/* 0x0 */
-#define IA64_SIGCONTEXT_FR6_OFFSET	560	/* 0x230 */
-#define IA64_SIGCONTEXT_PR_OFFSET	128	/* 0x80 */
-#define IA64_SIGCONTEXT_R12_OFFSET	296	/* 0x128 */
-#define IA64_SIGCONTEXT_RBS_BASE_OFFSET	2512	/* 0x9d0 */
-#define IA64_SIGCONTEXT_LOADRS_OFFSET	2520	/* 0x9d8 */
-#define IA64_SIGFRAME_ARG0_OFFSET	0	/* 0x0 */
-#define IA64_SIGFRAME_ARG1_OFFSET	8	/* 0x8 */
-#define IA64_SIGFRAME_ARG2_OFFSET	16	/* 0x10 */
-#define IA64_SIGFRAME_HANDLER_OFFSET	24	/* 0x18 */
-#define IA64_SIGFRAME_SIGCONTEXT_OFFSET	160	/* 0xa0 */
-#define IA64_CLONE_VFORK		16384	/* 0x4000 */
-#define IA64_CLONE_VM			256	/* 0x100 */
-#define IA64_CPU_IRQ_COUNT_OFFSET	0	/* 0x0 */
-#define IA64_CPU_BH_COUNT_OFFSET	4	/* 0x4 */
-#define IA64_CPU_PHYS_STACKED_SIZE_P8_OFFSET 12	/* 0xc */
-
-#endif /* _ASM_IA64_OFFSETS_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/page.h linux-2.4.21-pre6/include/asm-ia64/page.h
--- linux-2.4.20/include/asm-ia64/page.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/page.h	2003-03-26 23:49:07.000000000 +0000
@@ -65,13 +65,10 @@
 # define virt_to_page(kaddr)	(mem_map + MAP_NR_DENSE(kaddr))
 # define page_to_phys(page)	((page - mem_map) << PAGE_SHIFT)
 #endif
-#ifdef CONFIG_VIRTUAL_MEM_MAP
-  struct page;
-  extern int ia64_page_valid (struct page *);
-# define VALID_PAGE(page)	(((page - mem_map) < max_mapnr) && ia64_page_valid(page))
-#else
-# define VALID_PAGE(page)	((page - mem_map) < max_mapnr)
-#endif
+
+struct page;
+extern int ia64_page_valid (struct page *);
+#define VALID_PAGE(page)	(((page - mem_map) < max_mapnr) && ia64_page_valid(page))
 
 typedef union ia64_va {
 	struct {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/pal.h linux-2.4.21-pre6/include/asm-ia64/pal.h
--- linux-2.4.20/include/asm-ia64/pal.h	2001-12-21 17:42:03.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/pal.h	2003-03-26 23:49:07.000000000 +0000
@@ -78,6 +78,7 @@
 #ifndef __ASSEMBLY__
 
 #include <linux/types.h>
+#include <asm/fpu.h>
 
 /*
  * Data types needed to pass information into PAL procedures and
@@ -650,11 +651,43 @@
 extern struct ia64_pal_retval ia64_pal_call_phys_static (u64, u64, u64, u64);
 extern struct ia64_pal_retval ia64_pal_call_phys_stacked (u64, u64, u64, u64);
 
-#define PAL_CALL(iprv,a0,a1,a2,a3)		iprv = ia64_pal_call_static(a0, a1, a2, a3, 0)
-#define PAL_CALL_IC_OFF(iprv,a0,a1,a2,a3)	iprv = ia64_pal_call_static(a0, a1, a2, a3, 1)
-#define PAL_CALL_STK(iprv,a0,a1,a2,a3)		iprv = ia64_pal_call_stacked(a0, a1, a2, a3)
-#define PAL_CALL_PHYS(iprv,a0,a1,a2,a3)		iprv = ia64_pal_call_phys_static(a0, a1, a2, a3)
-#define PAL_CALL_PHYS_STK(iprv,a0,a1,a2,a3)	iprv = ia64_pal_call_phys_stacked(a0, a1, a2, a3)
+extern void ia64_save_scratch_fpregs(struct ia64_fpreg *);
+extern void ia64_load_scratch_fpregs(struct ia64_fpreg *);
+
+#define PAL_CALL(iprv,a0,a1,a2,a3) do {                 \
+	struct ia64_fpreg fr[6];                        \
+	ia64_save_scratch_fpregs(fr);                     \
+	iprv = ia64_pal_call_static(a0, a1, a2, a3, 0); \
+	ia64_load_scratch_fpregs(fr);                  \
+} while (0)
+
+#define PAL_CALL_IC_OFF(iprv,a0,a1,a2,a3) do {          \
+	struct ia64_fpreg fr[6];                        \
+	ia64_save_scratch_fpregs(fr);                     \
+	iprv = ia64_pal_call_static(a0, a1, a2, a3, 1); \
+	ia64_load_scratch_fpregs(fr);                  \
+} while (0)
+
+#define PAL_CALL_STK(iprv,a0,a1,a2,a3) do {             \
+	struct ia64_fpreg fr[6];                        \
+	ia64_save_scratch_fpregs(fr);                     \
+	iprv = ia64_pal_call_stacked(a0, a1, a2, a3);   \
+	ia64_load_scratch_fpregs(fr);                  \
+} while (0)
+
+#define PAL_CALL_PHYS(iprv,a0,a1,a2,a3) do {            \
+	struct ia64_fpreg fr[6];                        \
+	ia64_save_scratch_fpregs(fr);                     \
+	iprv = ia64_pal_call_phys_static(a0, a1, a2, a3);\
+	ia64_load_scratch_fpregs(fr);                  \
+} while (0)
+
+#define PAL_CALL_PHYS_STK(iprv,a0,a1,a2,a3) do {        \
+	struct ia64_fpreg fr[6];                        \
+	ia64_save_scratch_fpregs(fr);                     \
+	iprv = ia64_pal_call_phys_stacked(a0, a1, a2, a3); \
+	ia64_load_scratch_fpregs(fr);                  \
+} while (0)
 
 typedef int (*ia64_pal_handler) (u64, ...);
 extern ia64_pal_handler ia64_pal;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/pci.h linux-2.4.21-pre6/include/asm-ia64/pci.h
--- linux-2.4.20/include/asm-ia64/pci.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/pci.h	2003-03-26 23:49:54.000000000 +0000
@@ -26,6 +26,13 @@
 
 struct pci_dev;
 
+/*
+ * The PCI address space does equal the physical memory address space.
+ * The networking and block device layers use this boolean for bounce
+ * buffer decisions.
+ */
+#define PCI_DMA_BUS_IS_PHYS	(1)
+
 static inline void
 pcibios_set_master (struct pci_dev *dev)
 {
@@ -49,7 +56,6 @@
 #define pci_unmap_sg			platform_pci_unmap_sg
 #define pci_dma_sync_single		platform_pci_dma_sync_single
 #define pci_dma_sync_sg			platform_pci_dma_sync_sg
-#define sg_dma_address			platform_pci_dma_address
 #define pci_dma_supported		platform_pci_dma_supported
 
 /* pci_unmap_{single,page} is not a nop, thus... */
@@ -76,18 +82,25 @@
 /* Return the index of the PCI controller for device PDEV. */
 #define pci_controller_num(PDEV)	(0)
 
-#define sg_dma_len(sg)		((sg)->length)
+#define sg_dma_address(sg)	((sg)->dma_address)
+#define sg_dma_len(sg)		((sg)->dma_length)
 
 #define HAVE_PCI_MMAP
 extern int pci_mmap_page_range (struct pci_dev *dev, struct vm_area_struct *vma,
 				enum pci_mmap_state mmap_state, int write_combine);
 
+struct pci_window {
+	struct resource resource;
+	u64 offset;
+};
+
 struct pci_controller {
 	void *acpi_handle;
 	void *iommu;
 	int segment;
 
-	u64 mem_offset;
+	unsigned int windows;
+	struct pci_window *window;
 
 	void *platform_data;
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/perfmon.h linux-2.4.21-pre6/include/asm-ia64/perfmon.h
--- linux-2.4.20/include/asm-ia64/perfmon.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/perfmon.h	2003-03-26 23:49:40.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2001-2002 Hewlett-Packard Co
+ * Copyright (C) 2001-2003 Hewlett-Packard Co
  *               Stephane Eranian <eranian@hpl.hp.com>
  */
 
@@ -40,11 +40,13 @@
 #define PFM_FL_INHERIT_ALL	 0x02	/* always clone pfm_context across fork() */
 #define PFM_FL_NOTIFY_BLOCK    	 0x04	/* block task on user level notifications */
 #define PFM_FL_SYSTEM_WIDE	 0x08	/* create a system wide context */
+#define PFM_FL_EXCL_IDLE         0x20   /* exclude idle task from system wide session */
 
 /*
  * PMC flags
  */
 #define PFM_REGFL_OVFL_NOTIFY	0x1	/* send notification on overflow */
+#define PFM_REGFL_RANDOM	0x2	/* randomize sampling interval */
 
 /*
  * PMD/PMC/IBR/DBR return flags (ignored on input)
@@ -85,9 +87,12 @@
 	unsigned long	reg_long_reset;	/* reset after sampling buffer overflow (large) */
 	unsigned long	reg_short_reset;/* reset after counter overflow (small) */
 
-	unsigned long	reg_reset_pmds[4]; /* which other counters to reset on overflow */
+	unsigned long	reg_reset_pmds[4];   /* which other counters to reset on overflow */
+	unsigned long	reg_random_seed;     /* seed value when randomization is used */
+	unsigned long	reg_random_mask;     /* bitmask used to limit random value */
+	unsigned long	reg_last_reset_value;/* last value used to reset the PMD (PFM_READ_PMDS) */
 
-	unsigned long   reserved[16];	/* for future use */
+	unsigned long   reserved[13];	/* for future use */
 } pfarg_reg_t;
 
 typedef struct {
@@ -104,6 +109,31 @@
 } pfarg_features_t;
 
 /*
+ * Entry header in the sampling buffer.
+ * The header is directly followed with the PMDS saved in increasing index 
+ * order: PMD4, PMD5, .... How many PMDs are present is determined by the 
+ * user program during context creation.
+ *
+ * XXX: in this version of the entry, only up to 64 registers can be recorded
+ * This should be enough for quite some time. Always check sampling format
+ * before parsing entries!
+ *
+ * In the case where multiple counters overflow at the same time, the
+ * last_reset_value member indicates the initial value of the PMD with
+ * the smallest index.  For instance, if PMD2 and PMD5 have overflowed,
+ * the last_reset_value member contains the initial value of PMD2.
+ */
+typedef struct {
+	int		pid;		 /* identification of process */
+	int		cpu;		 /* which cpu was used */
+	unsigned long	last_reset_value;/* initial value of overflowed counter */
+	unsigned long	stamp;		 /* timestamp (unique per CPU) */
+	unsigned long	ip;		 /* where did the overflow interrupt happened */
+	unsigned long	regs;		 /* bitmask of which registers overflowed */
+	unsigned long   period;		 /* unused */
+} perfmon_smpl_entry_t;
+
+/*
  * This header is at the beginning of the sampling buffer returned to the user.
  * It is exported as Read-Only at this point. It is directly followed by the
  * first record.
@@ -120,7 +150,7 @@
  * Define the version numbers for both perfmon as a whole and the sampling buffer format.
  */
 #define PFM_VERSION_MAJ		1U
-#define PFM_VERSION_MIN		0U
+#define PFM_VERSION_MIN		3U
 #define PFM_VERSION		(((PFM_VERSION_MAJ&0xffff)<<16)|(PFM_VERSION_MIN & 0xffff))
 
 #define PFM_SMPL_VERSION_MAJ	1U
@@ -131,35 +161,15 @@
 #define PFM_VERSION_MAJOR(x)	(((x)>>16) & 0xffff)
 #define PFM_VERSION_MINOR(x)	((x) & 0xffff)
 
-/*
- * Entry header in the sampling buffer.
- * The header is directly followed with the PMDS saved in increasing index 
- * order: PMD4, PMD5, .... How many PMDs are present is determined by the 
- * user program during context creation.
- *
- * XXX: in this version of the entry, only up to 64 registers can be recorded
- * This should be enough for quite some time. Always check sampling format
- * before parsing entries!
- *
- * Inn the case where multiple counters have overflowed at the same time, the 
- * rate field indicate the initial value of the first PMD, based on the index.
- * For instance, if PMD2 and PMD5 have ovewrflowed for this entry, the rate field
- * will show the initial value of PMD2.
- */
-typedef struct {
-	int		pid;		/* identification of process */
-	int		cpu;		/* which cpu was used */
-	unsigned long	rate;		/* initial value of overflowed counter */
-	unsigned long	stamp;		/* timestamp */
-	unsigned long	ip;		/* where did the overflow interrupt happened */
-	unsigned long	regs;		/* bitmask of which registers overflowed */
-	unsigned long   period;		/* sampling period used by overflowed counter (smallest pmd index) */
-} perfmon_smpl_entry_t;
-
-extern int perfmonctl(pid_t pid, int cmd, void *arg, int narg);
 
 #ifdef __KERNEL__
 
+extern long perfmonctl(pid_t pid, int cmd, void *arg, int narg);
+
+typedef struct {
+	void (*handler)(int irq, void *arg, struct pt_regs *regs);
+} pfm_intr_handler_desc_t;
+
 extern void pfm_save_regs (struct task_struct *);
 extern void pfm_load_regs (struct task_struct *);
 
@@ -171,8 +181,22 @@
 extern int  pfm_use_debug_registers(struct task_struct *);
 extern int  pfm_release_debug_registers(struct task_struct *);
 extern int  pfm_cleanup_smpl_buf(struct task_struct *);
-extern void pfm_syst_wide_update_task(struct task_struct *, int);
-extern void perfmon_init_percpu(void);
+extern void pfm_syst_wide_update_task(struct task_struct *, unsigned long info, int is_ctxswin);
+extern void pfm_init_percpu(void);
+
+/* 
+ * hooks to allow VTune/Prospect to cooperate with perfmon.
+ * (reserved for system wide monitoring modules only)
+ */
+extern int pfm_install_alternate_syswide_subsystem(pfm_intr_handler_desc_t *h);
+extern int pfm_remove_alternate_syswide_subsystem(pfm_intr_handler_desc_t *h);
+
+/*
+ * describe the content of the local_cpu_date->pfm_syst_info field
+ */
+#define PFM_CPUINFO_SYST_WIDE	0x1	/* if set a system wide session exist on the CPU */
+#define PFM_CPUINFO_DCR_PP	0x2	/* if set a system wide session started on the CPU */
+#define PFM_CPUINFO_EXCL_IDLE	0x4	/* system wide session excludes the idle task */
 
 #endif /* __KERNEL__ */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/pgalloc.h linux-2.4.21-pre6/include/asm-ia64/pgalloc.h
--- linux-2.4.20/include/asm-ia64/pgalloc.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/pgalloc.h	2003-03-26 23:48:58.000000000 +0000
@@ -157,29 +157,44 @@
  * Flush everything (kernel mapping may also have changed due to
  * vmalloc/vfree).
  */
-extern void __flush_tlb_all (void);
+extern void local_flush_tlb_all (void);
 
 #ifdef CONFIG_SMP
   extern void smp_flush_tlb_all (void);
+  extern void smp_flush_tlb_mm (struct mm_struct *mm);
 # define flush_tlb_all()	smp_flush_tlb_all()
 #else
-# define flush_tlb_all()	__flush_tlb_all()
+# define flush_tlb_all()	local_flush_tlb_all()
 #endif
 
+static inline void
+local_flush_tlb_mm (struct mm_struct *mm)
+{
+	if (mm == current->active_mm)
+		activate_context(mm);
+}
+
 /*
- * Flush a specified user mapping
+ * Flush a specified user mapping.  This is called, e.g., as a result of fork() and
+ * exit().  fork() ends up here because the copy-on-write mechanism needs to write-protect
+ * the PTEs of the parent task.
  */
 static inline void
 flush_tlb_mm (struct mm_struct *mm)
 {
-	if (mm) {
-		mm->context = 0;
-		if (mm == current->active_mm) {
-			/* This is called, e.g., as a result of exec().  */
-			get_new_mmu_context(mm);
-			reload_context(mm);
-		}
-	}
+	if (!mm)
+		return;
+
+	mm->context = 0;
+
+	if (atomic_read(&mm->mm_users) == 0)
+		return;		/* happens as a result of exit_mmap() */
+
+#ifdef CONFIG_SMP
+	smp_flush_tlb_mm(mm);
+#else
+	local_flush_tlb_mm(mm);
+#endif
 }
 
 extern void flush_tlb_range (struct mm_struct *mm, unsigned long start, unsigned long end);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/pgtable.h linux-2.4.21-pre6/include/asm-ia64/pgtable.h
--- linux-2.4.20/include/asm-ia64/pgtable.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/pgtable.h	2003-03-26 23:49:25.000000000 +0000
@@ -198,13 +198,9 @@
 
 #define VMALLOC_START		(0xa000000000000000 + 3*PAGE_SIZE)
 #define VMALLOC_VMADDR(x)	((unsigned long)(x))
-#ifdef CONFIG_VIRTUAL_MEM_MAP
-# define VMALLOC_END_INIT        (0xa000000000000000 + (1UL << (4*PAGE_SHIFT - 9))) 
-# define VMALLOC_END             vmalloc_end
-  extern unsigned long vmalloc_end;
-#else
-# define VMALLOC_END		(0xa000000000000000 + (1UL << (4*PAGE_SHIFT - 9)))
-#endif
+#define VMALLOC_END_INIT        (0xa000000000000000 + (1UL << (4*PAGE_SHIFT - 9))) 
+#define VMALLOC_END             vmalloc_end
+extern unsigned long vmalloc_end;
 
 /*
  * Conversion functions: convert a page and protection to a page entry,
@@ -284,11 +280,7 @@
  * works bypasses the caches, but does allow for consecutive writes to
  * be combined into single (but larger) write transactions.
  */
-#ifdef CONFIG_MCKINLEY_A0_SPECIFIC
-# define pgprot_writecombine(prot)	prot
-#else
-# define pgprot_writecombine(prot)	__pgprot((pgprot_val(prot) & ~_PAGE_MA_MASK) | _PAGE_MA_WC)
-#endif
+#define pgprot_writecombine(prot)	__pgprot((pgprot_val(prot) & ~_PAGE_MA_MASK) | _PAGE_MA_WC)
 
 /*
  * Return the region index for virtual address ADDRESS.
@@ -448,8 +440,6 @@
  */
 #define pgtable_cache_init()	do { } while (0)
 
-#ifdef CONFIG_VIRTUAL_MEM_MAP
-
 /* arch mem_map init routines are needed due to holes in a virtual mem_map */
 #define HAVE_ARCH_MEMMAP_INIT
 
@@ -460,8 +450,6 @@
 	struct page *start, struct page *end, int zone,
 	unsigned long start_paddr, int highmem);
 
-#endif /* CONFIG_VIRTUAL_MEM_MAP */
-
 # endif /* !__ASSEMBLY__ */
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/processor.h linux-2.4.21-pre6/include/asm-ia64/processor.h
--- linux-2.4.20/include/asm-ia64/processor.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/processor.h	2003-03-26 23:49:27.000000000 +0000
@@ -167,16 +167,15 @@
 	__u32 ptce_count[2];
 	__u32 ptce_stride[2];
 	struct task_struct *ksoftirqd;	/* kernel softirq daemon for this CPU */
+# ifdef CONFIG_PERFMON
+	unsigned long pfm_syst_info;
+# endif
 #ifdef CONFIG_SMP
 	int processor;
 	__u64 loops_per_jiffy;
 	__u64 ipi_count;
 	__u64 prof_counter;
 	__u64 prof_multiplier;
-# ifdef CONFIG_PERFMON
-	__u32 pfm_syst_wide;
-	__u32 pfm_dcr_pp;
-# endif
 	union {
 		/*
 		 *  This is written to by *other* CPUs,
@@ -373,7 +372,7 @@
  * do_basic_setup() and the timing is such that free_initmem() has
  * been called already.
  */
-extern int kernel_thread (int (*fn)(void *), void *arg, unsigned long flags);
+extern int arch_kernel_thread (int (*fn)(void *), void *arg, unsigned long flags);
 
 /* Copy and release all segment info associated with a VM */
 #define copy_segments(tsk, mm)			do { } while (0)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sal.h linux-2.4.21-pre6/include/asm-ia64/sal.h
--- linux-2.4.20/include/asm-ia64/sal.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sal.h	2003-03-26 23:49:54.000000000 +0000
@@ -38,9 +38,12 @@
 
 # define SAL_CALL(result,args...) do {			\
 	unsigned long flags;				\
+	struct ia64_fpreg fr[6];                        \
+	ia64_save_scratch_fpregs(fr);                   \
 	spin_lock_irqsave(&sal_lock, flags);		\
 	__SAL_CALL(result,args);			\
 	spin_unlock_irqrestore(&sal_lock, flags);	\
+	ia64_load_scratch_fpregs(fr);                   \
 } while (0)
 
 #define SAL_SET_VECTORS			0x01000000
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/scatterlist.h linux-2.4.21-pre6/include/asm-ia64/scatterlist.h
--- linux-2.4.20/include/asm-ia64/scatterlist.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/scatterlist.h	2003-03-26 23:49:39.000000000 +0000
@@ -9,12 +9,13 @@
 struct scatterlist {
 	/* This will disappear in 2.5.x: */
 	char *address;		/* location data is to be transferred to, NULL for highmem page */
-	char *orig_address;	/* for use by swiotlb */
 
 	/* These two are only valid if ADDRESS member of this struct is NULL.  */
 	struct page *page;
 	unsigned int offset;
 	unsigned int length;	/* buffer length */
+	dma_addr_t dma_address;
+	unsigned int dma_length;
 };
 
 #define ISA_DMA_THRESHOLD	(~0UL)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/siginfo.h linux-2.4.21-pre6/include/asm-ia64/siginfo.h
--- linux-2.4.20/include/asm-ia64/siginfo.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/siginfo.h	2003-03-26 23:49:29.000000000 +0000
@@ -266,8 +266,8 @@
 	if (from->si_code < 0)
 		memcpy(to, from, sizeof(siginfo_t));
 	else
-		/* _sigchld is currently the largest know union member */
-		memcpy(to, from, 3*sizeof(int) + sizeof(from->_sifields._sigchld));
+		/* _sigprof is currently the largest know union member */
+		memcpy(to, from, 4*sizeof(int) + sizeof(from->_sifields._sigprof));
 }
 
 extern int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/addrs.h linux-2.4.21-pre6/include/asm-ia64/sn/addrs.h
--- linux-2.4.20/include/asm-ia64/sn/addrs.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/addrs.h	2003-03-26 23:49:10.000000000 +0000
@@ -1,14 +1,11 @@
-
 /*
- *
  * 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) 1992-1999,2001 Silicon Graphics, Inc.  All rights reserved.
+ * Copyright (c) 1992-1999,2001-2002 Silicon Graphics, Inc. All rights reserved.
  */
 
-
 #ifndef _ASM_IA64_SN_ADDRS_H
 #define _ASM_IA64_SN_ADDRS_H
 
@@ -58,14 +55,14 @@
 #define NODE_OFFSET(_n)		(UINT64_CAST (_n) << NODE_SIZE_BITS)
 #endif
 
-#define NODE_CAC_BASE(_n)	(CAC_BASE   + NODE_OFFSET(_n))
+#define NODE_CAC_BASE(_n)	(CAC_BASE  + NODE_OFFSET(_n))
 #define NODE_HSPEC_BASE(_n)	(HSPEC_BASE + NODE_OFFSET(_n))
 #define NODE_IO_BASE(_n)	(IO_BASE    + NODE_OFFSET(_n))
 #define NODE_MSPEC_BASE(_n)	(MSPEC_BASE + NODE_OFFSET(_n))
 #define NODE_UNCAC_BASE(_n)	(UNCAC_BASE + NODE_OFFSET(_n))
 
 #define TO_NODE(_n, _x)		(NODE_OFFSET(_n)     | ((_x)		   ))
-#define TO_NODE_CAC(_n, _x)	(NODE_CAC_BASE(_n)   | ((_x) & TO_PHYS_MASK))
+#define TO_NODE_CAC(_n, _x)	(NODE_CAC_BASE(_n) | ((_x) & TO_PHYS_MASK))
 #define TO_NODE_UNCAC(_n, _x)	(NODE_UNCAC_BASE(_n) | ((_x) & TO_PHYS_MASK))
 #define TO_NODE_MSPEC(_n, _x)	(NODE_MSPEC_BASE(_n) | ((_x) & TO_PHYS_MASK))
 #define TO_NODE_HSPEC(_n, _x)	(NODE_HSPEC_BASE(_n) | ((_x) & TO_PHYS_MASK))
@@ -227,8 +224,8 @@
 
 #ifndef __ASSEMBLY__
 
-#define HUB_L(_a)			*(_a)
-#define	HUB_S(_a, _d)			*(_a) = (_d)
+#define HUB_L(_a)			(*((volatile typeof(*_a) *)_a))
+#define	HUB_S(_a, _d)			(*((volatile typeof(*_a) *)_a) = (_d))
 
 #define LOCAL_HUB_L(_r)			HUB_L(LOCAL_HUB_ADDR(_r))
 #define LOCAL_HUB_S(_r, _d)		HUB_S(LOCAL_HUB_ADDR(_r), (_d))
@@ -326,7 +323,7 @@
 #define GDA_SIZE(nasid)		KLD_GDA(nasid)->size
 
 #define NODE_OFFSET_TO_K0(_nasid, _off)					\
-	(PAGE_OFFSET | NODE_OFFSET(_nasid) | (_off))
+	(CACHEABLE_MEM_SPACE | NODE_OFFSET(_nasid) | (_off))
 
 #endif /* __ASSEMBLY__ */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/alenlist.h linux-2.4.21-pre6/include/asm-ia64/sn/alenlist.h
--- linux-2.4.20/include/asm-ia64/sn/alenlist.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/alenlist.h	2003-03-26 23:48:57.000000000 +0000
@@ -15,7 +15,7 @@
 
 /*
  * An Address/Length List is used when setting up for an I/O DMA operation.
- * A driver creates an Address/Length List that describes to the the DMA 
+ * A driver creates an Address/Length List that describes to the DMA 
  * interface where in memory the DMA should go.  The bus interface sets up 
  * mapping registers, if required, and returns a suitable list of "physical 
  * addresses" or "I/O address" to the driver.  The driver then uses these 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/arc/hinv.h linux-2.4.21-pre6/include/asm-ia64/sn/arc/hinv.h
--- linux-2.4.20/include/asm-ia64/sn/arc/hinv.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/arc/hinv.h	2003-03-26 23:49:18.000000000 +0000
@@ -1,13 +1,11 @@
 /*
- *
  * 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 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 
-
 /* $Id$
  *
  * ARCS hardware/memory inventory/configuration and system ID definitions.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/arc/types.h linux-2.4.21-pre6/include/asm-ia64/sn/arc/types.h
--- linux-2.4.20/include/asm-ia64/sn/arc/types.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/arc/types.h	2003-03-26 23:49:54.000000000 +0000
@@ -3,8 +3,8 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
+ * Copyright (c) 1999,2001-2002 Silicon Graphics, Inc.  All Rights Reserved.
  * Copyright 1999 Ralf Baechle (ralf@gnu.org)
- * Copyright 1999,2001 Silicon Graphics, Inc.
  */
 #ifndef _ASM_SN_ARC_TYPES_H
 #define _ASM_SN_ARC_TYPES_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/arch.h linux-2.4.21-pre6/include/asm-ia64/sn/arch.h
--- linux-2.4.20/include/asm-ia64/sn/arch.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/arch.h	2003-03-26 23:49:30.000000000 +0000
@@ -43,6 +43,7 @@
 #define INVALID_NASID		((nasid_t)-1)
 #define INVALID_CNODEID		((cnodeid_t)-1)
 #define INVALID_PNODEID		((pnodeid_t)-1)
+#define INVALID_SLAB            (slabid_t)-1
 #define INVALID_MODULE		((moduleid_t)-1)
 #define	INVALID_PARTID		((partid_t)-1)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/bte.h linux-2.4.21-pre6/include/asm-ia64/sn/bte.h
--- linux-2.4.20/include/asm-ia64/sn/bte.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/bte.h	2003-03-26 23:49:25.000000000 +0000
@@ -1,11 +1,38 @@
 /*
- * 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-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify it 
+ * under the terms of version 2 of the GNU General Public License 
+ * as published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope that it would be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
+ * 
+ * Further, this software is distributed without any warranty that it is 
+ * free of the rightful claim of any third person regarding infringement 
+ * or the like.  Any license provided herein, whether implied or 
+ * otherwise, applies only to this software file.  Patent licenses, if 
+ * any, provided herein do not apply to combinations of this program with 
+ * other software, or any other product whatsoever.
+ * 
+ * You should have received a copy of the GNU General Public 
+ * License along with this program; if not, write the Free Software 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
  * 
- * Copyright (c) 2001-2002 Silicon Graphics, Inc.  All rights reserved.
+ * Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, 
+ * Mountain View, CA  94043, or:
+ * 
+ * http://www.sgi.com 
+ * 
+ * For further information regarding this notice, see: 
+ * 
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan
  */
 
+
 #ifndef _ASM_IA64_SN_BTE_H
 #define _ASM_IA64_SN_BTE_H
 
@@ -15,10 +42,6 @@
 #include <linux/cache.h>
 #include <asm/sn/io.h>
 
-#define L1_CACHE_MASK (L1_CACHE_BYTES - 1)	/* Mask to retrieve
-						 * the offset into this
-						 * cache line.*/
-
 /* BTE status register only supports 16 bits for length field */
 #define BTE_LEN_BITS (16)
 #define BTE_LEN_MASK ((1 << BTE_LEN_BITS) - 1)
@@ -71,14 +94,14 @@
 	u64 volatile notify ____cacheline_aligned;
 	char *bte_base_addr ____cacheline_aligned;
 	spinlock_t spinlock;
-	u64 idealTransferTimeout;
-	u64 idealTransferTimeoutReached;
-	u64 mostRecentSrc;
-	u64 mostRecentDest;
-	u64 mostRecentLen;
-	u64 mostRecentMode;
-	u64 volatile *mostRecentNotification;
-	void *bteTestBuf;
+	u64 ideal_xfr_tmo;	/* Time out */
+	u64 ideal_xfr_tmo_cnt;
+	/* u64 most_recent_src;
+	 * u64 most_recent_dest;
+	 * u64 most_recent_len;
+	 * u64 most_recent_mode; */
+	u64 volatile *most_rcnt_na;
+	void *bte_test_buf;
 } bteinfo_t;
 
 /* Possible results from bte_copy and bte_unaligned_copy */
@@ -89,4 +112,6 @@
 	BTEFAIL_DIR		/* Diretory error */
 } bte_result_t;
 
+void bte_reset_nasid(nasid_t);
+
 #endif				/* _ASM_IA64_SN_BTE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/bte_copy.h linux-2.4.21-pre6/include/asm-ia64/sn/bte_copy.h
--- linux-2.4.20/include/asm-ia64/sn/bte_copy.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/bte_copy.h	2003-03-26 23:49:55.000000000 +0000
@@ -1,9 +1,35 @@
 /*
- * 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-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify it 
+ * under the terms of version 2 of the GNU General Public License 
+ * as published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope that it would be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
+ * 
+ * Further, this software is distributed without any warranty that it is 
+ * free of the rightful claim of any third person regarding infringement 
+ * or the like.  Any license provided herein, whether implied or 
+ * otherwise, applies only to this software file.  Patent licenses, if 
+ * any, provided herein do not apply to combinations of this program with 
+ * other software, or any other product whatsoever.
+ * 
+ * You should have received a copy of the GNU General Public 
+ * License along with this program; if not, write the Free Software 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ * 
+ * Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, 
+ * Mountain View, CA  94043, or:
+ * 
+ * http://www.sgi.com 
+ * 
+ * For further information regarding this notice, see: 
  * 
- * Copyright (c) 2001-2002 Silicon Graphics, Inc.  All rights reserved.
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan
  */
 
 #ifndef _ASM_IA64_SN_BTE_COPY_H
@@ -11,21 +37,40 @@
 
 #ident "$Revision: 1.1 $"
 
+#include <linux/timer.h>
 #include <asm/sn/bte.h>
 #include <asm/sn/sgi.h>
 #include <asm/sn/pda.h>
 #include <asm/delay.h>
 
 /*
- * BTE_LOCKING support - Undefining the following line will
- * adapt the bte_copy code to support one bte per cpu in
+ * BTE_LOCKING support - When CONFIG_IA64_SGI_BTE_LOCKING is
+ * not defined, the bte_copy code supports one bte per cpu in
  * synchronous mode.  Even if bte_copy is called with a
  * notify address, the bte will spin and wait for the transfer
  * to complete.  By defining the following, spin_locks and
  * busy checks are placed around the initiation of a BTE
  * transfer and multiple bte's per cpu are supported.
  */
+#if 0
 #define CONFIG_IA64_SGI_BTE_LOCKING 1
+#endif
+
+/*
+ * Handle locking of the bte interfaces.
+ *
+ * All transfers spinlock the interface before setting up the SHUB
+ * registers.  Sync transfers hold the lock until all processing is
+ * complete.  Async transfers release the lock as soon as the transfer
+ * is initiated.
+ *
+ * To determine if an interface is available, we must check both the
+ * busy bit and the spinlock for that interface.
+ */
+#define BTE_LOCK_IF_AVAIL(_x) (\
+	(*pda.cpu_bte_if[_x]->most_rcnt_na & IBLS_BUSY) && \
+	(!(spin_trylock(&(pda.cpu_bte_if[_x]->spinlock)))) \
+	)
 
 /*
  * Some macros to simplify reading.
@@ -33,39 +78,71 @@
  * Start with macros to locate the BTE control registers.
  */
 
-#define BTEREG_LNSTAT_ADDR (bte->bte_base_addr)
-#define BTEREG_SOURCE_ADDR (bte->bte_base_addr + IIO_IBSA0 - IIO_IBLS0)
-#define BTEREG_DEST_ADDR (bte->bte_base_addr + IIO_IBDA0 - IIO_IBLS0)
-#define BTEREG_CTRL_ADDR ((volatile char *)bte->bte_base_addr + IIO_IBCT0 - IIO_IBLS0)
-#define BTEREG_NOTIF_ADDR (bte->bte_base_addr + IIO_IBNA0 - IIO_IBLS0)
+#define BTEREG_LNSTAT_ADDR ((u64 *)(bte->bte_base_addr))
+#define BTEREG_SRC_ADDR ((u64 *)(bte->bte_base_addr + BTEOFF_SRC))
+#define BTEREG_DEST_ADDR ((u64 *)(bte->bte_base_addr + BTEOFF_DEST))
+#define BTEREG_CTRL_ADDR ((u64 *)(bte->bte_base_addr + BTEOFF_CTRL))
+#define BTEREG_NOTIF_ADDR ((u64 *)(bte->bte_base_addr + BTEOFF_NOTIFY))
 
 /* Some macros to force the IBCT0 value valid. */
 
 #define BTE_VALID_MODES BTE_NOTIFY
 #define BTE_VLD_MODE(x) (x & BTE_VALID_MODES)
 
-// #define DEBUG_BTE
-// #define DEBUG_BTE_VERBOSE
-// #define DEBUG_TIME_BTE
-
-#ifdef DEBUG_BTE
-#  define DPRINTK(x) printk x	// Terse
-#  ifdef DEBUG_BTE_VERBOSE
-#    define DPRINTKV(x) printk x	// Verbose
+// #define BTE_DEBUG
+// #define BTE_DEBUG_VERBOSE
+// #define BTE_TIME
+
+#ifdef BTE_DEBUG
+#  define BTE_PRINTK(x) printk x	/* Terse */
+#  ifdef BTE_DEBUG_VERBOSE
+#    define BTE_PRINTKV(x) printk x	/* Verbose */
 #  else
-#    define DPRINTKV(x)
-#  endif
+#    define BTE_PRINTKV(x)
+#  endif /* BTE_DEBUG_VERBOSE */
 #else
-#  define DPRINTK(x)
-#  define DPRINTKV(x)
-#endif
-
-#ifdef DEBUG_TIME_BTE
-extern u64 BteSetupTime;
-extern u64 BteTransferTime;
-extern u64 BteTeardownTime;
-extern u64 BteExecuteTime;
-#endif
+#  define BTE_PRINTK(x)
+#  define BTE_PRINTKV(x)
+#endif /* BTE_DEBUG */
+
+#define BTE_IDEAL_TMO(x) (jiffies + \
+	(HZ / BTE_MAXT_LINES_PER_SECOND * x))
+
+#ifdef BTE_TIME
+volatile extern u64 bte_setup_time;
+volatile extern u64 bte_transfer_time;
+volatile extern u64 bte_tear_down_time;
+volatile extern u64 bte_execute_time;
+
+#define BTE_TIME_DECLARE() \
+	u64 btcp_strt_tm = 0; \
+	u64 btcp_cplt_tm = 0; \
+	u64 xfr_strt_tm = 0; \
+	u64 xfr_cplt_tm = 0; \
+
+#define BTE_TIME_START() \
+	btcp_strt_tm = xfr_strt_tm = xfr_cplt_tm = ia64_get_itc();
+
+#define BTE_TIME_XFR_START() \
+	xfr_strt_tm = ia64_get_itc();
+
+#define BTE_TIME_XFR_STOP() \
+	xfr_cplt_tm = ia64_get_itc();
+
+#define BTE_TIME_STOP() \
+	btcp_cplt_tm = ia64_get_itc(); \
+	bte_setup_time = xfr_strt_tm - btcp_strt_tm; \
+	bte_transfer_time = xfr_cplt_tm - xfr_strt_tm; \
+	bte_tear_down_time = btcp_cplt_tm - xfr_cplt_tm; \
+	bte_execute_time = btcp_cplt_tm - btcp_strt_tm; \
+
+#else /* BTE_TIME */
+#define BTE_TIME_DECLARE()
+#define BTE_TIME_START()
+#define BTE_TIME_XFR_START()
+#define BTE_TIME_XFR_STOP()
+#define BTE_TIME_STOP()
+#endif /* BTE_TIME */
 
 /*
  * bte_copy(src, dest, len, mode, notification)
@@ -91,25 +168,19 @@
 {
 #ifdef CONFIG_IA64_SGI_BTE_LOCKING
 	int bte_to_use;
-#endif
-
-#ifdef DEBUG_TIME_BTE
-	u64 invokeTime = 0;
-	u64 completeTime = 0;
-	u64 xferStartTime = 0;
-	u64 xferCompleteTime = 0;
-#endif
-	u64 transferSize;
+#endif /* CONFIG_IA64_SGI_BTE_LOCKING */
+	u64 transfer_size;
+	u64 lines_remaining;
 	bteinfo_t *bte;
+	BTE_TIME_DECLARE();
 
-#ifdef DEBUG_TIME_BTE
-	invokeTime = ia64_get_itc();
-#endif
+	BTE_TIME_START();
 
-	DPRINTK(("bte_copy (0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx)\n",
-		 src, dest, len, mode, notification));
+	BTE_PRINTK(("bte_copy (0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx)\n",
+		    src, dest, len, mode, notification));
 
 	if (len == 0) {
+		BTE_TIME_STOP();
 		return (BTE_SUCCESS);
 	}
 
@@ -123,17 +194,15 @@
 		bte_to_use = 0;
 
 		/* Attempt to lock one of the BTE interfaces */
-		while ((*pda.cpubte[bte_to_use]->
-			mostRecentNotification & IBLS_BUSY)
-		       &&
-		       (!(spin_trylock
-			  (&(pda.cpubte[bte_to_use]->spinlock))))
-		       && (bte_to_use < BTES_PER_NODE)) {
+		while ((bte_to_use < BTES_PER_NODE) &&
+		       BTE_LOCK_IF_AVAIL(bte_to_use)) {
+
 			bte_to_use++;
 		}
 
 		if ((bte_to_use >= BTES_PER_NODE) &&
 		    !(mode & BTE_WACQUIRE)) {
+			BTE_TIME_STOP();
 			return (BTEFAIL_NOTAVAIL);
 		}
 
@@ -141,12 +210,12 @@
 	}
 	while (bte_to_use >= BTES_PER_NODE);
 
-	bte = pda.cpubte[bte_to_use];
-	DPRINTKV(("Got a lock on bte %d\n", bte_to_use));
+	bte = pda.cpu_bte_if[bte_to_use];
+	BTE_PRINTKV(("Got a lock on bte %d\n", bte_to_use));
 #else
 	/* Assuming one BTE per CPU. */
-	bte = pda.cpubte[0];
-#endif
+	bte = pda.cpu_bte_if[0];
+#endif /* CONFIG_IA64_SGI_BTE_LOCKING */
 
 	/*
 	 * The following are removed for optimization but is
@@ -160,65 +229,51 @@
 	 */
 	if (notification == NULL) {
 		/* User does not want to be notified. */
-		bte->mostRecentNotification = &bte->notify;
+		bte->most_rcnt_na = &bte->notify;
 	} else {
-		bte->mostRecentNotification = notification;
+		bte->most_rcnt_na = notification;
 	}
 
 	/* Calculate the number of cache lines to transfer. */
-	transferSize = ((len >> L1_CACHE_SHIFT) & BTE_LEN_MASK);
+	transfer_size = ((len >> L1_CACHE_SHIFT) & BTE_LEN_MASK);
 
-	DPRINTKV(("Calculated transfer size of %d cache lines\n",
-		  transferSize));
+	BTE_PRINTKV(("Calculated transfer size of %d cache lines\n",
+		     transfer_size));
 
 	/* Initialize the notification to a known value. */
-	*bte->mostRecentNotification = -1L;
+	*bte->most_rcnt_na = -1L;
 
 
-	DPRINTKV(("Before, status is 0x%lx and notify is 0x%lx\n",
-		  HUB_L(BTEREG_LNSTAT_ADDR),
-		  *bte->mostRecentNotification));
+	BTE_PRINTKV(("Before, status is 0x%lx and notify is 0x%lx\n",
+		     HUB_L(BTEREG_LNSTAT_ADDR),
+		     *bte->most_rcnt_na));
 
 	/* Set the status reg busy bit and transfer length */
-	DPRINTKV(("IBLS - HUB_S(0x%lx, 0x%lx)\n",
-		  BTEREG_LNSTAT_ADDR, IBLS_BUSY | transferSize));
-	HUB_S(BTEREG_LNSTAT_ADDR, IBLS_BUSY | transferSize);
-
-
-	DPRINTKV(("After setting status, status is 0x%lx and notify is 0x%lx\n", HUB_L(BTEREG_LNSTAT_ADDR), *bte->mostRecentNotification));
+	BTE_PRINTKV(("IBLS - HUB_S(0x%lx, 0x%lx)\n",
+		     BTEREG_LNSTAT_ADDR, IBLS_BUSY | transfer_size));
+	HUB_S(BTEREG_LNSTAT_ADDR, (IBLS_BUSY | transfer_size));
 
 	/* Set the source and destination registers */
-	DPRINTKV(("IBSA - HUB_S(0x%lx, 0x%lx)\n", BTEREG_SOURCE_ADDR,
-		  src));
-	HUB_S(BTEREG_SOURCE_ADDR, src);
-	DPRINTKV(("IBDA - HUB_S(0x%lx, 0x%lx)\n", BTEREG_DEST_ADDR, dest));
-	HUB_S(BTEREG_DEST_ADDR, dest);
-
+	BTE_PRINTKV(("IBSA - HUB_S(0x%lx, 0x%lx)\n", BTEREG_SRC_ADDR,
+		     (TO_PHYS(src))));
+	HUB_S(BTEREG_SRC_ADDR, (TO_PHYS(src)));
+	BTE_PRINTKV(("IBDA - HUB_S(0x%lx, 0x%lx)\n", BTEREG_DEST_ADDR,
+		     (TO_PHYS(dest))));
+	HUB_S(BTEREG_DEST_ADDR, (TO_PHYS(dest)));
 
 	/* Set the notification register */
-	DPRINTKV(("IBNA - HUB_S(0x%lx, 0x%lx)\n", BTEREG_NOTIF_ADDR,
-		  __pa(bte->mostRecentNotification)));
-	HUB_S(BTEREG_NOTIF_ADDR, (__pa(bte->mostRecentNotification)));
-
-
-	DPRINTKV(("Set Notify, status is 0x%lx and notify is 0x%lx\n",
-		  HUB_L(BTEREG_LNSTAT_ADDR),
-		  *bte->mostRecentNotification));
+	BTE_PRINTKV(("IBNA - HUB_S(0x%lx, 0x%lx)\n", BTEREG_NOTIF_ADDR,
+		     (TO_PHYS(__pa(bte->most_rcnt_na)))));
+	HUB_S(BTEREG_NOTIF_ADDR, (TO_PHYS(__pa(bte->most_rcnt_na))));
 
 	/* Initiate the transfer */
-	DPRINTKV(("IBCT - HUB_S(0x%lx, 0x%lx)\n", BTEREG_CTRL_ADDR, mode));
-#ifdef DEBUG_TIME_BTE
-	xferStartTime = ia64_get_itc();
-#endif
+	BTE_PRINTKV(("IBCT - HUB_S(0x%lx, 0x%lx)\n", BTEREG_CTRL_ADDR, mode));
+	BTE_TIME_XFR_START();
 	HUB_S(BTEREG_CTRL_ADDR, BTE_VLD_MODE(mode));
 
-	DPRINTKV(("Initiated, status is 0x%lx and notify is 0x%lx\n",
-		  HUB_L(BTEREG_LNSTAT_ADDR),
-		  *bte->mostRecentNotification));
-
-	// >>> Temporarily work around not getting a notification
-	// from medusa.
-	// *bte->mostRecentNotification = HUB_L(bte->bte_base_addr);
+	BTE_PRINTKV(("Initiated, status is 0x%lx and notify is 0x%lx\n",
+		     HUB_L(BTEREG_LNSTAT_ADDR),
+		     *bte->most_rcnt_na));
 
 	if (notification == NULL) {
 		/*
@@ -240,56 +295,75 @@
 		 * delay from hardware completing our request and
 		 * our detecting the failure.
 		 */
-		bte->idealTransferTimeout = jiffies +
-		    (HZ / BTE_MAXT_LINES_PER_SECOND * transferSize);
+		bte->ideal_xfr_tmo = BTE_IDEAL_TMO(transfer_size);
 
-		while ((IBLS_BUSY & bte->notify)) {
+		while (bte->notify == -1UL) {
 			/*
 			 * Notification Workaround: When the max
 			 * theoretical time has elapsed, read the hub
 			 * status register into the notification area.
 			 * This fakes the shub performing the copy.
 			 */
-			if (jiffies > bte->idealTransferTimeout) {
-				bte->notify = HUB_L(bte->bte_base_addr);
-				bte->idealTransferTimeoutReached++;
-				bte->idealTransferTimeout = jiffies +
-				    (HZ / BTE_MAXT_LINES_PER_SECOND *
-				     (bte->notify & BTE_LEN_MASK));
+			BTE_PRINTKV(("  Timing.  IBLS = 0x%lx, "
+				     "notify= 0x%lx\n",
+				     HUB_L(BTEREG_LNSTAT_ADDR),
+				     bte->notify));
+			if (time_after(jiffies, bte->ideal_xfr_tmo)) {
+				lines_remaining = HUB_L(BTEREG_LNSTAT_ADDR) &
+					BTE_LEN_MASK;
+				bte->ideal_xfr_tmo_cnt++;
+				bte->ideal_xfr_tmo =
+					BTE_IDEAL_TMO(lines_remaining);
+
+				BTE_PRINTKV(("  Timeout.  cpu %d "
+					     "IBLS = 0x%lx, "
+					     "notify= 0x%lx, "
+					     "Lines remaining = %d. "
+					     "New timeout = %d.\n",
+					     smp_processor_id(),
+					     HUB_L(BTEREG_LNSTAT_ADDR),
+					     bte->notify,
+					     lines_remaining,
+					     bte->ideal_xfr_tmo));
 			}
 		}
-#ifdef DEBUG_TIME_BTE
-		xferCompleteTime = ia64_get_itc();
-#endif
+		BTE_PRINTKV((" Delay Done.  IBLS = 0x%lx, notify= 0x%lx\n",
+			     HUB_L(BTEREG_LNSTAT_ADDR),
+			  bte->notify));
+		BTE_TIME_XFR_STOP();
 		if (bte->notify & IBLS_ERROR) {
 			/* >>> Need to do real error checking. */
-			transferSize = 0;
+			transfer_size = 0;
 
 #ifdef CONFIG_IA64_SGI_BTE_LOCKING
 			spin_unlock(&(bte->spinlock));
-#endif
+#endif /* CONFIG_IA64_SGI_BTE_LOCKING */
+			BTE_PRINTKV(("Erroring status is 0x%lx and "
+				     "notify is 0x%lx\n",
+				     HUB_L(BTEREG_LNSTAT_ADDR),
+				     bte->notify));
+
+			BTE_TIME_STOP();
+			bte->notify = 0L;
 			return (BTEFAIL_ERROR);
 		}
 
 	}
 #ifdef CONFIG_IA64_SGI_BTE_LOCKING
 	spin_unlock(&(bte->spinlock));
-#endif
-#ifdef DEBUG_TIME_BTE
-	completeTime = ia64_get_itc();
+#endif /* CONFIG_IA64_SGI_BTE_LOCKING */
+	BTE_TIME_STOP();
+	BTE_PRINTKV(("Returning status is 0x%lx and notify is 0x%lx\n",
+		     HUB_L(BTEREG_LNSTAT_ADDR),
+		     *bte->most_rcnt_na));
 
-	BteSetupTime = xferStartTime - invokeTime;
-	BteTransferTime = xferCompleteTime - xferStartTime;
-	BteTeardownTime = completeTime - xferCompleteTime;
-	BteExecuteTime = completeTime - invokeTime;
-#endif
 	return (BTE_SUCCESS);
 }
 
 /*
  * Define the bte_unaligned_copy as an extern.
  */
-extern bte_result_t bte_unaligned_copy(u64, u64, u64, u64, char *);
+extern bte_result_t bte_unaligned_copy(u64, u64, u64, u64);
 
 /*
  * The following is the prefered way of calling bte_unaligned_copy
@@ -299,13 +373,10 @@
  * until the transfer is complete.  In order to get the asynch
  * version of bte_copy, you must perform this check yourself.
  */
-#define BTE_UNALIGNED_COPY(src, dest, len, mode, bteBlock) \
-	if ((len & L1_CACHE_MASK) || \
-	    (src & L1_CACHE_MASK) || \
-	    (dest & L1_CACHE_MASK)) { \
-		bte_unaligned_copy (src, dest, len, mode, bteBlock); \
-	} else { \
-		bte_copy(src, dest, len, mode, NULL); \
-	}
+#define BTE_UNALIGNED_COPY(src, dest, len, mode)			\
+	(((len & L1_CACHE_MASK) || (src & L1_CACHE_MASK) ||		\
+	  (dest & L1_CACHE_MASK)) ?					\
+		bte_unaligned_copy(src, dest, len, mode) :		\
+		bte_copy(src, dest, len, mode, NULL))
 
-#endif				/* _ASM_IA64_SN_BTE_COPY_H */
+#endif /* _ASM_IA64_SN_BTE_COPY_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/cdl.h linux-2.4.21-pre6/include/asm-ia64/sn/cdl.h
--- linux-2.4.20/include/asm-ia64/sn/cdl.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/cdl.h	2003-03-26 23:49:49.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 #ifndef _ASM_IA64_SN_CDL_H
 #define _ASM_IA64_SN_CDL_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/clksupport.h linux-2.4.21-pre6/include/asm-ia64/sn/clksupport.h
--- linux-2.4.20/include/asm-ia64/sn/clksupport.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/clksupport.h	2003-03-26 23:49:50.000000000 +0000
@@ -29,22 +29,30 @@
 #include <asm/sn/addrs.h>
 
 typedef long clkreg_t;
-extern long sn_rtc_cycles_per_second;
+extern unsigned long sn_rtc_cycles_per_second;
 
 
 #if defined(CONFIG_IA64_SGI_SN1)
 #include <asm/sn/sn1/bedrock.h>
 #include <asm/sn/sn1/hubpi_next.h>
+
+extern nasid_t master_nasid;
+
+#define RTC_MASK		(0x007fffffffffffff)
 /* clocks are not synchronized yet on SN1  - used node 0 (problem if no NASID 0) */
-#define RTC_COUNTER_ADDR	((clkreg_t*)REMOTE_HUB_ADDR(0, PI_RT_COUNTER))
-#define RTC_COMPARE_A_ADDR      ((clkreg_t*)REMOTE_HUB_ADDR(0, PI_RT_COMPARE_A))
-#define RTC_COMPARE_B_ADDR      ((clkreg_t*)REMOTE_HUB_ADDR(0, PI_RT_COMPARE_B))
-#define RTC_INT_PENDING_A_ADDR  ((clkreg_t*)REMOTE_HUB_ADDR(0, PI_RT_INT_PEND_A))
-#define RTC_INT_PENDING_B_ADDR  ((clkreg_t*)REMOTE_HUB_ADDR(0, PI_RT_INT_PEND_B))
-#define RTC_INT_ENABLED_A_ADDR  ((clkreg_t*)REMOTE_HUB_ADDR(0, PI_RT_INT_EN_A))
-#define RTC_INT_ENABLED_B_ADDR  ((clkreg_t*)REMOTE_HUB_ADDR(0, PI_RT_INT_EN_B))
-#else
+#define RTC_COUNTER_ADDR	((clkreg_t*)REMOTE_HUB_ADDR(master_nasid, PI_RT_COUNTER))
+#define RTC_COMPARE_A_ADDR      ((clkreg_t*)REMOTE_HUB_ADDR(master_nasid, PI_RT_COMPARE_A))
+#define RTC_COMPARE_B_ADDR      ((clkreg_t*)REMOTE_HUB_ADDR(master_nasid, PI_RT_COMPARE_B))
+#define RTC_INT_PENDING_A_ADDR  ((clkreg_t*)REMOTE_HUB_ADDR(master_nasid, PI_RT_INT_PEND_A))
+#define RTC_INT_PENDING_B_ADDR  ((clkreg_t*)REMOTE_HUB_ADDR(master_nasid, PI_RT_INT_PEND_B))
+#define RTC_INT_ENABLED_A_ADDR  ((clkreg_t*)REMOTE_HUB_ADDR(master_nasid, PI_RT_INT_EN_A))
+#define RTC_INT_ENABLED_B_ADDR  ((clkreg_t*)REMOTE_HUB_ADDR(master_nasid, PI_RT_INT_EN_B))
+#else	/* !CONFIG_IA64_SGI_SN1 */
+#include <asm/sn/addrs.h>
+#include <asm/sn/sn2/addrs.h>
+#include <asm/sn/sn2/shubio.h>
 #include <asm/sn/sn2/shub_mmr.h>
+#define RTC_MASK		(SH_RTC_MASK)
 #define RTC_COUNTER_ADDR	((clkreg_t*)LOCAL_MMR_ADDR(SH_RTC))
 #define RTC_COMPARE_A_ADDR      ((clkreg_t*)LOCAL_MMR_ADDR(SH_RTC))
 #define RTC_COMPARE_B_ADDR      ((clkreg_t*)LOCAL_MMR_ADDR(SH_RTC))
@@ -52,7 +60,7 @@
 #define RTC_INT_PENDING_B_ADDR  ((clkreg_t*)LOCAL_MMR_ADDR(SH_RTC))
 #define RTC_INT_ENABLED_A_ADDR  ((clkreg_t*)LOCAL_MMR_ADDR(SH_RTC))
 #define RTC_INT_ENABLED_B_ADDR  ((clkreg_t*)LOCAL_MMR_ADDR(SH_RTC))
-#endif
+#endif	/* CONFIG_IA64_SGI_SN1 */
 
 
 #define GET_RTC_COUNTER()	(*RTC_COUNTER_ADDR)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/dmamap.h linux-2.4.21-pre6/include/asm-ia64/sn/dmamap.h
--- linux-2.4.20/include/asm-ia64/sn/dmamap.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/dmamap.h	2003-03-26 23:49:30.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 #ifndef _ASM_IA64_SN_DMAMAP_H
 #define _ASM_IA64_SN_DMAMAP_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/eeprom.h linux-2.4.21-pre6/include/asm-ia64/sn/eeprom.h
--- linux-2.4.20/include/asm-ia64/sn/eeprom.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/eeprom.h	2003-03-26 23:49:39.000000000 +0000
@@ -11,6 +11,7 @@
 #ifndef _ASM_IA64_SN_EEPROM_H
 #define _ASM_IA64_SN_EEPROM_H
 
+#include <linux/config.h>
 #include <asm/sn/sgi.h>
 #include <asm/sn/vector.h>
 #include <asm/sn/xtalk/xbow.h>
@@ -291,6 +292,8 @@
 /* functions & macros for obtaining "NIC-like" strings from EEPROMs
  */
 
+#ifdef CONFIG_IA64_SGI_SN1
+
 int eeprom_str( char *nic_str, nasid_t nasid, int component );
 int vector_eeprom_str( char *nic_str, nasid_t nasid,
 		       int component, net_vec_t path );
@@ -300,6 +303,7 @@
 #define RBRICK_EEPROM_STR(s,n,p)  vector_eeprom_str((s),(n),R_BRICK,p)
 #define VECTOR_EEPROM_STR(s,n,p)  vector_eeprom_str((s),(n),VECTOR,p)
 
+#endif	/* CONFIG_IA64_SGI_SN1 */
 
 
 /* functions for obtaining formatted records from EEPROMs
@@ -313,13 +317,6 @@
 			net_vec_t path, int component );
 
 
-/* functions providing unique id's for duplonet and i/o discovery
- */
-
-int cbrick_uid_get( nasid_t nasid, uint64_t *uid );
-int rbrick_uid_get( nasid_t nasid, net_vec_t path, uint64_t *uid );
-int iobrick_uid_get( nasid_t nasid, uint64_t *uid );
-
 
 /* retrieve the ethernet MAC address for an I-brick
  */
@@ -384,8 +381,4 @@
 		          ( IO_BRICK, NASID_GET((r)), (v), 0 ) \
 		      : nic_bridge_vertex_info((v), (r)) )
 
-#define HUB_UID_GET(n,v,p)	cbrick_uid_get((n),(p))
-#define ROUTER_UID_GET(d,p)	rbrick_uid_get(get_nasid(),(d),(p))
-#define XBOW_UID_GET(n,p)	iobrick_uid_get((n),(p))
-
 #endif /* _ASM_IA64_SN_EEPROM_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/fetchop.h linux-2.4.21-pre6/include/asm-ia64/sn/fetchop.h
--- linux-2.4.20/include/asm-ia64/sn/fetchop.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/fetchop.h	2003-03-26 23:48:59.000000000 +0000
@@ -7,10 +7,11 @@
  * Copyright (c) 2001-2002 Silicon Graphics, Inc.  All rights reserved.
  */
 
-
 #ifndef _ASM_IA64_SN_FETCHOP_H
 #define _ASM_IA64_SN_FETCHOP_H
 
+#include <linux/config.h>
+
 #define FETCHOP_BASENAME	"sgi_fetchop"
 #define FETCHOP_FULLNAME	"/dev/sgi_fetchop"
 
@@ -30,11 +31,71 @@
 #define FETCHOP_CLEAR_CACHE	56
 
 #define FETCHOP_LOAD_OP(addr, op) ( \
-         *(long *)((char*) (addr) + (op)))
+         *(volatile long *)((char*) (addr) + (op)))
 
 #define FETCHOP_STORE_OP(addr, op, x) ( \
-         *(long *)((char*) (addr) + (op)) = \
-              (long) (x))
+         *(volatile long *)((char*) (addr) + (op)) = (long) (x))
+
+#ifdef __KERNEL__
+
+/*
+ * Initialize a FETCHOP line. The argument should point to the beginning
+ * of the line.
+ * 	SN1 - region mask is in word 0, data in word 1
+ * 	SN2 - no region mask. Data in word 0
+ */
+#ifdef CONFIG_IA64_SGI_SN1
+#define FETCHOP_INIT_LINE(p)	*(p) = 0xffffffffffffffffUL
+#elif CONFIG_IA64_SGI_SN2
+#define FETCHOP_INIT_LINE(p)
+#endif
+
+/*
+ * Convert a region 7 (kaddr) address to the address of the fetchop variable
+ */
+#define FETCHOP_KADDR_TO_MSPEC_ADDR(kaddr)	TO_MSPEC(kaddr)
+
+/*
+ * Convert a page struct (page) address to the address of the first
+ * fetchop variable in the page
+ */
+#define FETCHOP_PAGE_TO_MSPEC_ADDR(page)	FETCHOP_KADDR_TO_MSPEC_ADDR(__pa(page_address(page)))
+
+
+/*
+ * Each Atomic Memory Operation (AMO formerly known as fetchop)
+ * variable is 64 bytes long.  The first 8 bytes are used.  The
+ * remaining 56 bytes are unaddressable due to the operation taking
+ * that portion of the address.
+ * 
+ * NOTE: The AMO_t _MUST_ be placed in either the first or second half
+ * of the cache line.  The cache line _MUST NOT_ be used for anything
+ * other than additional AMO_t entries.  This is because there are two
+ * addresses which reference the same physical cache line.  One will
+ * be a cached entry with the memory type bits all set.  This address
+ * may be loaded into processor cache.  The AMO_t will be referenced
+ * uncached via the memory special memory type.  If any portion of the
+ * cached cache-line is modified, when that line is flushed, it will
+ * overwrite the uncached value in physical memory and lead to
+ * inconsistency.
+ */
+typedef struct {
+
+#ifdef CONFIG_IA64_SGI_SN1
+	u64 permissions;
+#endif
+        u64 variable;
+
+#ifdef CONFIG_IA64_SGI_SN1
+        u64 unused[6];
+#else
+        u64 unused[7];
+#endif
+
+} AMO_t;
+
+
+#endif /* __KERNEL__ */
 
 #endif /* _ASM_IA64_SN_FETCHOP_H */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/gda.h linux-2.4.21-pre6/include/asm-ia64/sn/gda.h
--- linux-2.4.20/include/asm-ia64/sn/gda.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/gda.h	2003-03-26 23:49:50.000000000 +0000
@@ -6,7 +6,7 @@
  *
  * Derived from IRIX <sys/SN/gda.h>.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  *
  * gda.h -- Contains the data structure for the global data area,
  * 	The GDA contains information communicated between the
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/geo.h linux-2.4.21-pre6/include/asm-ia64/sn/geo.h
--- linux-2.4.20/include/asm-ia64/sn/geo.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/geo.h	2003-03-26 23:49:50.000000000 +0000
@@ -0,0 +1,54 @@
+/* $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) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#ifndef __SYS_GEO_H__
+#define __SYS_GEO_H__
+
+/* Include a platform-specific geo.h.  It must define at least:
+ *   geoid_t:		Geographic identifier data type
+ *   geo_type_t:	Data type for the kind of geoid this is
+ *   GEO_TYPE_xxx:	Values for geo_type_t vars, eg. GEO_TYPE_NODE
+ *   GEO_MAX_LEN:	The maximum length of a geoid, formatted for printing
+ */
+
+#include <linux/config.h>
+
+#ifdef CONFIG_IA64_SGI_SN2
+#include <asm/sn/sn2/geo.h>
+#else
+
+#error <<BOMB! need geo.h for this platform >>
+
+#endif /* !SN2 && ... */
+
+/* Declarations applicable to all platforms */
+
+/* parameter for hwcfg_format_geoid() */
+#define GEO_FORMAT_HWGRAPH	1
+#define GEO_FORMAT_BRIEF	2
+
+/* (the parameter for hwcfg_format_geoid_compt() is defined in the
+ * platform-specific geo.h file) */
+
+/* Routines for manipulating geoid_t values */
+
+extern moduleid_t geo_module(geoid_t g);
+extern slabid_t geo_slab(geoid_t g);
+extern geo_type_t geo_type(geoid_t g);
+extern int geo_valid(geoid_t g);
+extern int geo_cmp(geoid_t g0, geoid_t g1);
+extern geoid_t geo_new(geo_type_t type, ...);
+
+extern geoid_t hwcfg_parse_geoid(char *buffer);
+extern void hwcfg_format_geoid(char *buffer, geoid_t m, int fmt);
+extern void hwcfg_format_geoid_compt(char *buffer, geoid_t m, int compt);
+extern geoid_t hwcfg_geo_get_self(geo_type_t type);
+extern geoid_t hwcfg_geo_get_by_nasid(geo_type_t type, nasid_t nasid);
+
+#endif /* __SYS_GEO_H__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/hack.h linux-2.4.21-pre6/include/asm-ia64/sn/hack.h
--- linux-2.4.20/include/asm-ia64/sn/hack.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/hack.h	2003-03-26 23:49:09.000000000 +0000
@@ -1,10 +1,9 @@
 /*
- *
  * 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 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 
 
@@ -22,9 +21,6 @@
 struct cred { int x; };
 
 
-#define mrlock(_s, _t, _u)
-#define mrunlock(_s)
-
 /*
  * Hardware Graph routines that are currently stubbed!
  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/hcl.h linux-2.4.21-pre6/include/asm-ia64/sn/hcl.h
--- linux-2.4.20/include/asm-ia64/sn/hcl.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/hcl.h	2003-03-26 23:49:29.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 #ifndef _ASM_IA64_SN_HCL_H
 #define _ASM_IA64_SN_HCL_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/hires_clock.h linux-2.4.21-pre6/include/asm-ia64/sn/hires_clock.h
--- linux-2.4.20/include/asm-ia64/sn/hires_clock.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/hires_clock.h	2003-03-26 23:49:50.000000000 +0000
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2001-2002 Silicon Graphics, Inc. All rights reserved.
  *
  * SGI Hi Resolution Clock
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/ifconfig_net.h linux-2.4.21-pre6/include/asm-ia64/sn/ifconfig_net.h
--- linux-2.4.20/include/asm-ia64/sn/ifconfig_net.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/ifconfig_net.h	2003-03-26 23:49:54.000000000 +0000
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 
 #ifndef _ASM_IA64_SN_IFCONFIG_NET_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/intr_public.h linux-2.4.21-pre6/include/asm-ia64/sn/intr_public.h
--- linux-2.4.20/include/asm-ia64/sn/intr_public.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/intr_public.h	2003-03-26 23:49:55.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 #ifndef _ASM_IA64_SN_INTR_PUBLIC_H
 #define _ASM_IA64_SN_INTR_PUBLIC_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/io.h linux-2.4.21-pre6/include/asm-ia64/sn/io.h
--- linux-2.4.20/include/asm-ia64/sn/io.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/io.h	2003-03-26 23:49:06.000000000 +0000
@@ -3,8 +3,8 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
+ * Copyright (C) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
  * Copyright (C) 2000 Ralf Baechle
- * Copyright (C) 2000-2001 Silicon Graphics, Inc.
  */
 #ifndef _ASM_IA64_SN_IO_H
 #define _ASM_IA64_SN_IO_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/ioc4.h linux-2.4.21-pre6/include/asm-ia64/sn/ioc4.h
--- linux-2.4.20/include/asm-ia64/sn/ioc4.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/ioc4.h	2003-03-26 23:49:39.000000000 +0000
@@ -0,0 +1,801 @@
+/*
+ * Copyright (c) 2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify it 
+ * under the terms of version 2 of the GNU General Public License 
+ * as published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope that it would be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
+ * 
+ * Further, this software is distributed without any warranty that it is 
+ * free of the rightful claim of any third person regarding infringement 
+ * or the like.  Any license provided herein, whether implied or 
+ * otherwise, applies only to this software file.  Patent licenses, if 
+ * any, provided herein do not apply to combinations of this program with 
+ * other software, or any other product whatsoever.
+ * 
+ * You should have received a copy of the GNU General Public 
+ * License along with this program; if not, write the Free Software 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ * 
+ * Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, 
+ * Mountain View, CA  94043, or:
+ * 
+ * http://www.sgi.com 
+ * 
+ */
+
+#ifndef _ASM_IA64_SN_IOC4_H
+#define _ASM_IA64_SN_IOC4_H
+
+#if 0
+
+/*
+ * ioc4.h - IOC4 chip header file
+ */
+
+/* Notes:
+ * The IOC4 chip is a 32-bit PCI device that provides 4 serial ports,
+ * an IDE bus interface, a PC keyboard/mouse interface, and a real-time
+ * external interrupt interface.
+ *
+ * It includes an optimized DMA buffer management, and a store-and-forward
+ * buffer RAM.
+ *
+ * All IOC4 registers are 32 bits wide.
+ */
+typedef __uint32_t ioc4reg_t;
+
+/*
+ * PCI Configuration Space Register Address Map, use offset from IOC4 PCI
+ * configuration base such that this can be used for multiple IOC4s
+ */
+#define IOC4_PCI_ID		0x0	/* ID */
+
+#define IOC4_VENDOR_ID_NUM	0x10A9
+#define IOC4_DEVICE_ID_NUM	0x100A 
+#define IOC4_ADDRSPACE_MASK	0xfff00000ULL
+
+#define IOC4_PCI_SCR		0x4 /* Status/Command */
+#define IOC4_PCI_REV		0x8 /* Revision */
+#define IOC4_PCI_LAT		0xC /* Latency Timer */
+#define IOC4_PCI_BAR0		0x10 /* IOC4 base address 0 */
+#define IOC4_PCI_SIDV		0x2c /* Subsys ID and vendor */
+#define IOC4_PCI_CAP 		0x34 /* Capability pointer */
+#define IOC4_PCI_LATGNTINT      0x3c /* Max_lat, min_gnt, int_pin, int_line */
+
+/*
+ * PCI Memory Space Map 
+ */
+#define IOC4_PCI_ERR_ADDR_L     0x000	/* Low Error Address */
+#define IOC4_PCI_ERR_ADDR_VLD	     (0x1 << 0)
+#define IOC4_PCI_ERR_ADDR_MST_ID_MSK (0xf << 1)
+#define IOC4_PCI_ERR_ADDR_MUL_ERR    (0x1 << 5)
+#define IOC4_PCI_ERR_ADDR_ADDR_MSK   (0x3ffffff << 6)
+
+/* Master IDs contained in PCI_ERR_ADDR_MST_ID_MSK */
+#define IOC4_MST_ID_S0_TX		0
+#define IOC4_MST_ID_S0_RX		1
+#define IOC4_MST_ID_S1_TX		2
+#define IOC4_MST_ID_S1_RX		3
+#define IOC4_MST_ID_S2_TX		4
+#define IOC4_MST_ID_S2_RX		5
+#define IOC4_MST_ID_S3_TX		6
+#define IOC4_MST_ID_S3_RX		7
+#define IOC4_MST_ID_ATA 		8
+
+#define IOC4_PCI_ERR_ADDR_H	0x004	/* High Error Address */
+
+#define IOC4_SIO_IR	        0x008	/* SIO Interrupt Register */
+#define IOC4_OTHER_IR	        0x00C	/* Other Interrupt Register */
+
+/* These registers are read-only for general kernel code. To modify
+ * them use the functions in ioc4.c
+ */
+#define IOC4_SIO_IES_RO         0x010	/* SIO Interrupt Enable Set Reg */
+#define IOC4_OTHER_IES_RO       0x014	/* Other Interrupt Enable Set Reg */
+#define IOC4_SIO_IEC_RO         0x018	/* SIO Interrupt Enable Clear Reg */
+#define IOC4_OTHER_IEC_RO       0x01C	/* Other Interrupt Enable Clear Reg */
+
+#define IOC4_SIO_CR	        0x020	/* SIO Control Reg */
+#define IOC4_INT_OUT	        0x028	/* INT_OUT Reg (realtime interrupt) */
+#define IOC4_GPCR_S	        0x030	/* GenericPIO Cntrl Set Register */
+#define IOC4_GPCR_C	        0x034	/* GenericPIO Cntrl Clear Register */
+#define IOC4_GPDR	        0x038	/* GenericPIO Data Register */
+#define IOC4_GPPR_0	        0x040	/* GenericPIO Pin Registers */
+#define IOC4_GPPR_OFF	        0x4
+#define IOC4_GPPR(x)	        (IOC4_GPPR_0+(x)*IOC4_GPPR_OFF)
+
+/* ATAPI Registers */
+#define IOC4_ATA_0              0x100	/* Data w/timing */
+#define IOC4_ATA_1              0x104	/* Error/Features w/timing */
+#define IOC4_ATA_2              0x108	/* Sector Count w/timing */
+#define IOC4_ATA_3              0x10C	/* Sector Number w/timing */
+#define IOC4_ATA_4              0x110   /* Cyliner Low w/timing */
+#define IOC4_ATA_5              0x114	/* Cylinder High w/timing */
+#define IOC4_ATA_6              0x118	/* Device/Head w/timing */
+#define IOC4_ATA_7              0x11C	/* Status/Command w/timing */
+#define IOC4_ATA_0_AUX          0x120	/* Aux Status/Device Cntrl w/timing */
+#define IOC4_ATA_TIMING       	0x140	/* Timing value register 0 */
+#define IOC4_ATA_DMA_PTR_L      0x144   /* Low Memory Pointer to DMA List */
+#define IOC4_ATA_DMA_PTR_H      0x148   /* High Memory Pointer to DMA List */
+#define IOC4_ATA_DMA_ADDR_L     0x14C   /* Low Memory DMA Address */
+#define IOC4_ATA_DMA_ADDR_H     0x150   /* High Memory DMA Addresss */
+#define IOC4_ATA_BC_DEV         0x154	/* DMA Byte Count at Device */
+#define IOC4_ATA_BC_MEM         0x158	/* DMA Byte Count at Memory */
+#define IOC4_ATA_DMA_CTRL       0x15C	/* DMA Control/Status */
+
+/* Keyboard and Mouse Registers */
+#define IOC4_KM_CSR	        0x200	/* Kbd and Mouse Cntrl/Status Reg */
+#define IOC4_K_RD	        0x204	/* Kbd Read Data Register */
+#define IOC4_M_RD	        0x208	/* Mouse Read Data Register */
+#define IOC4_K_WD	        0x20C	/* Kbd Write Data Register */
+#define IOC4_M_WD	        0x210	/* Mouse Write Data Register */
+
+/* Serial Port Registers used for DMA mode serial I/O */
+#define IOC4_SBBR01_H	        0x300	/* Serial Port Ring Buffers 
+                                           Base Reg High for Channels 0 1*/
+#define IOC4_SBBR01_L	        0x304	/* Serial Port Ring Buffers 
+                                           Base Reg Low for Channels 0 1 */
+#define IOC4_SBBR23_H	        0x308	/* Serial Port Ring Buffers 
+                                           Base Reg High for Channels 2 3*/
+#define IOC4_SBBR23_L	        0x30C	/* Serial Port Ring Buffers 
+                                           Base Reg Low for Channels 2 3 */
+
+#define IOC4_SSCR_0	        0x310	/* Serial Port 0 Control */
+#define IOC4_STPIR_0	        0x314	/* Serial Port 0 TX Produce */
+#define IOC4_STCIR_0	        0x318	/* Serial Port 0 TX Consume */
+#define IOC4_SRPIR_0	        0x31C	/* Serial Port 0 RX Produce */
+#define IOC4_SRCIR_0	        0x320	/* Serial Port 0 RX Consume */
+#define IOC4_SRTR_0	        0x324	/* Serial Port 0 Receive Timer Reg */
+#define IOC4_SHADOW_0		0x328	/* Serial Port 0 16550 Shadow Reg */
+
+#define IOC4_SSCR_1	        0x32C	/* Serial Port 1 Control */
+#define IOC4_STPIR_1	        0x330	/* Serial Port 1 TX Produce */
+#define IOC4_STCIR_1	        0x334	/* Serial Port 1 TX Consume */
+#define IOC4_SRPIR_1	        0x338   /* Serial Port 1 RX Produce */
+#define IOC4_SRCIR_1	        0x33C	/* Serial Port 1 RX Consume */
+#define IOC4_SRTR_1	        0x340	/* Serial Port 1 Receive Timer Reg */
+#define IOC4_SHADOW_1		0x344	/* Serial Port 1 16550 Shadow Reg */
+
+#define IOC4_SSCR_2	        0x348	/* Serial Port 2 Control */
+#define IOC4_STPIR_2	        0x34C	/* Serial Port 2 TX Produce */
+#define IOC4_STCIR_2	        0x350	/* Serial Port 2 TX Consume */
+#define IOC4_SRPIR_2	        0x354	/* Serial Port 2 RX Produce */
+#define IOC4_SRCIR_2	        0x358	/* Serial Port 2 RX Consume */
+#define IOC4_SRTR_2	        0x35C	/* Serial Port 2 Receive Timer Reg */
+#define IOC4_SHADOW_2		0x360	/* Serial Port 2 16550 Shadow Reg */
+
+#define IOC4_SSCR_3	        0x364	/* Serial Port 3 Control */
+#define IOC4_STPIR_3	        0x368	/* Serial Port 3 TX Produce */
+#define IOC4_STCIR_3	        0x36C	/* Serial Port 3 TX Consume */
+#define IOC4_SRPIR_3	        0x370	/* Serial Port 3 RX Produce */
+#define IOC4_SRCIR_3	        0x374	/* Serial Port 3 RX Consume */
+#define IOC4_SRTR_3	        0x378	/* Serial Port 3 Receive Timer Reg */
+#define IOC4_SHADOW_3		0x37C	/* Serial Port 3 16550 Shadow Reg */
+
+#define IOC4_UART0_BASE         0x380   /* UART 0 */
+#define IOC4_UART1_BASE         0x388   /* UART 1 */
+#define IOC4_UART2_BASE         0x390   /* UART 2 */
+#define IOC4_UART3_BASE         0x398   /* UART 3 */
+
+/* Private page address aliases for usermode mapping */
+#define IOC4_INT_OUT_P	        0x04000	/* INT_OUT Reg */
+
+#define IOC4_SSCR_0_P	        0x08000 /* Serial Port 0 */
+#define IOC4_STPIR_0_P	        0x08004
+#define IOC4_STCIR_0_P	        0x08008	/* (read-only) */
+#define IOC4_SRPIR_0_P	        0x0800C	/* (read-only) */
+#define IOC4_SRCIR_0_P	        0x08010
+#define IOC4_SRTR_0_P	        0x08014
+#define IOC4_UART_LSMSMCR_0_P   0x08018	/* (read-only) */
+
+#define IOC4_SSCR_1_P	        0x0C000	/* Serial Port 1 */
+#define IOC4_STPIR_1_P	        0x0C004
+#define IOC4_STCIR_1_P	        0x0C008	/* (read-only) */
+#define IOC4_SRPIR_1_P	        0x0C00C	/* (read-only) */
+#define IOC4_SRCIR_1_P	        0x0C010
+#define IOC4_SRTR_1_P	        0x0C014
+#define IOC4_UART_LSMSMCR_1_P   0x0C018	/* (read-only) */
+
+#define IOC4_SSCR_2_P	        0x10000	/* Serial Port 2 */
+#define IOC4_STPIR_2_P	        0x10004
+#define IOC4_STCIR_2_P	        0x10008	/* (read-only) */
+#define IOC4_SRPIR_2_P	        0x1000C	/* (read-only) */
+#define IOC4_SRCIR_2_P	        0x10010
+#define IOC4_SRTR_2_P	        0x10014
+#define IOC4_UART_LSMSMCR_2_P   0x10018	/* (read-only) */
+
+#define IOC4_SSCR_3_P	        0x14000	/* Serial Port 3 */
+#define IOC4_STPIR_3_P	        0x14004
+#define IOC4_STCIR_3_P	        0x14008	/* (read-only) */
+#define IOC4_SRPIR_3_P	        0x1400C	/* (read-only) */
+#define IOC4_SRCIR_3_P	        0x14010
+#define IOC4_SRTR_3_P	        0x14014
+#define IOC4_UART_LSMSMCR_3_P   0x14018	/* (read-only) */
+
+#define IOC4_ALIAS_PAGE_SIZE	0x4000
+
+/* Interrupt types */
+typedef enum ioc4_intr_type_e {
+    ioc4_sio_intr_type,
+    ioc4_other_intr_type,
+    ioc4_num_intr_types
+} ioc4_intr_type_t;
+#define ioc4_first_intr_type    ioc4_sio_intr_type
+
+/* Bitmasks for IOC4_SIO_IR, IOC4_SIO_IEC, and IOC4_SIO_IES  */
+#define IOC4_SIO_IR_S0_TX_MT		0x00000001 /* Serial port 0 TX empty */
+#define IOC4_SIO_IR_S0_RX_FULL		0x00000002 /* Port 0 RX buf full */
+#define IOC4_SIO_IR_S0_RX_HIGH		0x00000004 /* Port 0 RX hiwat */
+#define IOC4_SIO_IR_S0_RX_TIMER		0x00000008 /* Port 0 RX timeout */
+#define IOC4_SIO_IR_S0_DELTA_DCD	0x00000010 /* Port 0 delta DCD */
+#define IOC4_SIO_IR_S0_DELTA_CTS	0x00000020 /* Port 0 delta CTS */
+#define IOC4_SIO_IR_S0_INT	        0x00000040 /* Port 0 pass-thru intr */
+#define IOC4_SIO_IR_S0_TX_EXPLICIT	0x00000080 /* Port 0 explicit TX thru */
+#define IOC4_SIO_IR_S1_TX_MT		0x00000100 /* Serial port 1 */
+#define IOC4_SIO_IR_S1_RX_FULL		0x00000200 /* */
+#define IOC4_SIO_IR_S1_RX_HIGH		0x00000400 /* */
+#define IOC4_SIO_IR_S1_RX_TIMER		0x00000800 /* */
+#define IOC4_SIO_IR_S1_DELTA_DCD	0x00001000 /* */
+#define IOC4_SIO_IR_S1_DELTA_CTS	0x00002000 /* */
+#define IOC4_SIO_IR_S1_INT		0x00004000 /* */
+#define IOC4_SIO_IR_S1_TX_EXPLICIT	0x00008000 /* */
+#define IOC4_SIO_IR_S2_TX_MT		0x00010000 /* Serial port 2 */
+#define IOC4_SIO_IR_S2_RX_FULL		0x00020000 /* */
+#define IOC4_SIO_IR_S2_RX_HIGH		0x00040000 /* */
+#define IOC4_SIO_IR_S2_RX_TIMER		0x00080000 /* */
+#define IOC4_SIO_IR_S2_DELTA_DCD	0x00100000 /* */
+#define IOC4_SIO_IR_S2_DELTA_CTS	0x00200000 /* */
+#define IOC4_SIO_IR_S2_INT		0x00400000 /* */
+#define IOC4_SIO_IR_S2_TX_EXPLICIT	0x00800000 /* */
+#define IOC4_SIO_IR_S3_TX_MT		0x01000000 /* Serial port 3 */
+#define IOC4_SIO_IR_S3_RX_FULL		0x02000000 /* */
+#define IOC4_SIO_IR_S3_RX_HIGH		0x04000000 /* */
+#define IOC4_SIO_IR_S3_RX_TIMER		0x08000000 /* */
+#define IOC4_SIO_IR_S3_DELTA_DCD	0x10000000 /* */
+#define IOC4_SIO_IR_S3_DELTA_CTS	0x20000000 /* */
+#define IOC4_SIO_IR_S3_INT		0x40000000 /* */
+#define IOC4_SIO_IR_S3_TX_EXPLICIT	0x80000000 /* */
+
+/* Per device interrupt masks */
+#define IOC4_SIO_IR_S0		(IOC4_SIO_IR_S0_TX_MT | \
+				 IOC4_SIO_IR_S0_RX_FULL | \
+				 IOC4_SIO_IR_S0_RX_HIGH | \
+				 IOC4_SIO_IR_S0_RX_TIMER | \
+				 IOC4_SIO_IR_S0_DELTA_DCD | \
+				 IOC4_SIO_IR_S0_DELTA_CTS | \
+				 IOC4_SIO_IR_S0_INT | \
+				 IOC4_SIO_IR_S0_TX_EXPLICIT)
+#define IOC4_SIO_IR_S1		(IOC4_SIO_IR_S1_TX_MT | \
+				 IOC4_SIO_IR_S1_RX_FULL | \
+				 IOC4_SIO_IR_S1_RX_HIGH | \
+				 IOC4_SIO_IR_S1_RX_TIMER | \
+				 IOC4_SIO_IR_S1_DELTA_DCD | \
+				 IOC4_SIO_IR_S1_DELTA_CTS | \
+				 IOC4_SIO_IR_S1_INT | \
+				 IOC4_SIO_IR_S1_TX_EXPLICIT)
+#define IOC4_SIO_IR_S2		(IOC4_SIO_IR_S2_TX_MT | \
+				 IOC4_SIO_IR_S2_RX_FULL | \
+				 IOC4_SIO_IR_S2_RX_HIGH | \
+				 IOC4_SIO_IR_S2_RX_TIMER | \
+				 IOC4_SIO_IR_S2_DELTA_DCD | \
+				 IOC4_SIO_IR_S2_DELTA_CTS | \
+				 IOC4_SIO_IR_S2_INT | \
+				 IOC4_SIO_IR_S2_TX_EXPLICIT)
+#define IOC4_SIO_IR_S3		(IOC4_SIO_IR_S3_TX_MT | \
+				 IOC4_SIO_IR_S3_RX_FULL | \
+				 IOC4_SIO_IR_S3_RX_HIGH | \
+				 IOC4_SIO_IR_S3_RX_TIMER | \
+				 IOC4_SIO_IR_S3_DELTA_DCD | \
+				 IOC4_SIO_IR_S3_DELTA_CTS | \
+				 IOC4_SIO_IR_S3_INT | \
+				 IOC4_SIO_IR_S3_TX_EXPLICIT)
+
+/* Bitmasks for IOC4_OTHER_IR, IOC4_OTHER_IEC, and IOC4_OTHER_IES  */
+#define IOC4_OTHER_IR_ATA_INT           0x00000001 /* ATAPI intr pass-thru */
+#define IOC4_OTHER_IR_ATA_MEMERR        0x00000002 /* ATAPI DMA PCI error */
+#define IOC4_OTHER_IR_S0_MEMERR         0x00000004 /* Port 0 PCI error */
+#define IOC4_OTHER_IR_S1_MEMERR         0x00000008 /* Port 1 PCI error */
+#define IOC4_OTHER_IR_S2_MEMERR         0x00000010 /* Port 2 PCI error */
+#define IOC4_OTHER_IR_S3_MEMERR         0x00000020 /* Port 3 PCI error */
+#define IOC4_OTHER_IR_KBD_INT		0x00000040 /* Kbd/mouse intr */
+#define IOC4_OTHER_IR_ATA_DMAINT        0x00000089 /* ATAPI DMA intr */
+#define IOC4_OTHER_IR_RT_INT		0x00800000 /* RT output pulse */
+#define IOC4_OTHER_IR_GEN_INT1		0x02000000 /* RT input pulse */
+#define IOC4_OTHER_IR_GEN_INT_SHIFT	        25
+
+/* Per device interrupt masks */
+#define IOC4_OTHER_IR_ATA       (IOC4_OTHER_IR_ATA_INT | \
+				 IOC4_OTHER_IR_ATA_MEMERR | \
+				 IOC4_OTHER_IR_ATA_DMAINT)
+#define IOC4_OTHER_IR_RT	(IOC4_OTHER_IR_RT_INT | IOC4_OTHER_IR_GEN_INT1)
+
+/* Macro to load pending interrupts */
+#define IOC4_PENDING_SIO_INTRS(mem)     (PCI_INW(&((mem)->sio_ir)) & \
+				         PCI_INW(&((mem)->sio_ies_ro)))
+#define IOC4_PENDING_OTHER_INTRS(mem)   (PCI_INW(&((mem)->other_ir)) & \
+				         PCI_INW(&((mem)->other_ies_ro)))
+
+/* Bitmasks for IOC4_SIO_CR */
+#define IOC4_SIO_SR_CMD_PULSE		0x00000004 /* Byte bus strobe length */
+#define IOC4_SIO_CR_CMD_PULSE_SHIFT              0
+#define IOC4_SIO_CR_ARB_DIAG		0x00000070 /* Current non-ATA PCI bus
+                                                      requester (ro) */
+#define IOC4_SIO_CR_ARB_DIAG_TX0	0x00000000
+#define IOC4_SIO_CR_ARB_DIAG_RX0	0x00000010
+#define IOC4_SIO_CR_ARB_DIAG_TX1	0x00000020
+#define IOC4_SIO_CR_ARB_DIAG_RX1	0x00000030
+#define IOC4_SIO_CR_ARB_DIAG_TX2	0x00000040
+#define IOC4_SIO_CR_ARB_DIAG_RX2	0x00000050
+#define IOC4_SIO_CR_ARB_DIAG_TX3	0x00000060
+#define IOC4_SIO_CR_ARB_DIAG_RX3	0x00000070
+#define IOC4_SIO_CR_SIO_DIAG_IDLE	0x00000080 /* 0 -> active request among
+                                                      serial ports (ro) */
+#define IOC4_SIO_CR_ATA_DIAG_IDLE	0x00000100 /* 0 -> active request from
+                                                      ATA port */
+#define IOC4_SIO_CR_ATA_DIAG_ACTIVE     0x00000200 /* 1 -> ATA request is winner */ 
+
+/* Bitmasks for IOC4_INT_OUT */
+#define IOC4_INT_OUT_COUNT	        0x0000ffff /* Pulse interval timer */
+#define IOC4_INT_OUT_MODE	        0x00070000 /* Mode mask */
+#define IOC4_INT_OUT_MODE_0             0x00000000 /* Set output to 0 */
+#define IOC4_INT_OUT_MODE_1             0x00040000 /* Set output to 1 */
+#define IOC4_INT_OUT_MODE_1PULSE        0x00050000 /* Send 1 pulse */
+#define IOC4_INT_OUT_MODE_PULSES        0x00060000 /* Send 1 pulse every interval */
+#define IOC4_INT_OUT_MODE_SQW           0x00070000 /* Toggle output every interval */
+#define IOC4_INT_OUT_DIAG	        0x40000000 /* Diag mode */
+#define IOC4_INT_OUT_INT_OUT            0x80000000 /* Current state of INT_OUT */
+
+/* Time constants for IOC4_INT_OUT */
+#define IOC4_INT_OUT_NS_PER_TICK        (15 * 520) /* 15 ns PCI clock, multi=520 */
+#define IOC4_INT_OUT_TICKS_PER_PULSE             3 /* Outgoing pulse lasts 3
+                                                      ticks */
+#define IOC4_INT_OUT_US_TO_COUNT(x)	           /* Convert uS to a count value */ \
+	(((x) * 10 + IOC4_INT_OUT_NS_PER_TICK / 200) *	\
+	 100 / IOC4_INT_OUT_NS_PER_TICK - 1)
+#define IOC4_INT_OUT_COUNT_TO_US(x)	           /* Convert count value to uS */ \
+	(((x) + 1) * IOC4_INT_OUT_NS_PER_TICK / 1000)
+#define IOC4_INT_OUT_MIN_TICKS                   3 /* Min period is width of
+                                                      pulse in "ticks" */
+#define IOC4_INT_OUT_MAX_TICKS  IOC4_INT_OUT_COUNT /* Largest possible count */
+
+/* Bitmasks for IOC4_GPCR */
+#define IOC4_GPCR_DIR	                0x000000ff /* Tristate pin in or out */
+#define IOC4_GPCR_DIR_PIN(x)              (1<<(x)) /* Access one of the DIR bits */
+#define IOC4_GPCR_EDGE	                0x0000ff00 /* Extint edge or level
+                                                      sensitive */
+#define IOC4_GPCR_EDGE_PIN(x)        (1<<((x)+7 )) /* Access one of the EDGE bits */
+
+/* Values for IOC4_GPCR */
+#define IOC4_GPCR_INT_OUT_EN            0x00100000 /* Enable INT_OUT to pin 0 */
+#define IOC4_GPCR_DIR_SER0_XCVR         0x00000010 /* Port 0 Transceiver select
+                                                      enable */
+#define IOC4_GPCR_DIR_SER1_XCVR         0x00000020 /* Port 1 Transceiver select
+                                                      enable */
+#define IOC4_GPCR_DIR_SER2_XCVR         0x00000040 /* Port 2 Transceiver select
+                                                      enable */
+#define IOC4_GPCR_DIR_SER3_XCVR         0x00000080 /* Port 3 Transceiver select
+                                                      enable */
+
+/* Defs for some of the generic I/O pins */
+#define IOC4_GPCR_UART0_MODESEL	              0x10 /* Pin is output to port 0
+                                                      mode sel */
+#define IOC4_GPCR_UART1_MODESEL	              0x20 /* Pin is output to port 1
+                                                      mode sel */
+#define IOC4_GPCR_UART2_MODESEL	              0x40 /* Pin is output to port 2
+                                                      mode sel */
+#define IOC4_GPCR_UART3_MODESEL	              0x80 /* Pin is output to port 3
+                                                      mode sel */
+
+#define IOC4_GPPR_UART0_MODESEL_PIN	         4 /* GIO pin controlling
+                                                      uart 0 mode select */
+#define IOC4_GPPR_UART1_MODESEL_PIN	         5 /* GIO pin controlling
+                                                      uart 1 mode select */
+#define IOC4_GPPR_UART2_MODESEL_PIN	         6 /* GIO pin controlling
+                                                      uart 2 mode select */
+#define IOC4_GPPR_UART3_MODESEL_PIN	         7 /* GIO pin controlling
+                                                      uart 3 mode select */
+
+/* Bitmasks for IOC4_ATA_TIMING */
+#define IOC4_ATA_TIMING_ADR_SETUP	0x00000003 /* Clocks of addr set-up */
+#define IOC4_ATA_TIMING_PULSE_WIDTH	0x000001f8 /* Clocks of read or write
+                                                      pulse width */
+#define IOC4_ATA_TIMING_RECOVERY	0x0000fe00 /* Clocks before next read
+                                                      or write */
+#define IOC4_ATA_TIMING_USE_IORDY	0x00010000 /* PIO uses IORDY */
+
+/* Bitmasks for address list elements pointed to by IOC4_ATA_DMA_PTR_<L|H> */
+#define IOC4_ATA_ALE_DMA_ADDRESS        0xfffffffffffffffe
+
+/* Bitmasks for byte count list elements pointed to by IOC4_ATA_DMA_PTR_<L|H> */
+#define IOC4_ATA_BCLE_BYTE_COUNT        0x000000000000fffe
+#define IOC4_ATA_BCLE_LIST_END          0x0000000080000000
+
+/* Bitmasks for IOC4_ATA_BC_<DEV|MEM> */
+#define IOC4_ATA_BC_BYTE_CNT            0x0001fffe /* Byte count */
+
+/* Bitmasks for IOC4_ATA_DMA_CTRL */
+#define IOC4_ATA_DMA_CTRL_STRAT		0x00000001 /* 1 -> start DMA engine */
+#define IOC4_ATA_DMA_CTRL_STOP		0x00000002 /* 1 -> stop DMA engine */
+#define IOC4_ATA_DMA_CTRL_DIR		0x00000004 /* 1 -> ATA bus data copied
+                                                      to memory */
+#define IOC4_ATA_DMA_CTRL_ACTIVE	0x00000008 /* DMA channel is active */
+#define IOC4_ATA_DMA_CTRL_MEM_ERROR	0x00000010 /* DMA engine encountered 
+						      a PCI error */
+/* Bitmasks for IOC4_KM_CSR */
+#define IOC4_KM_CSR_K_WRT_PEND  0x00000001 /* Kbd port xmitting or resetting */
+#define IOC4_KM_CSR_M_WRT_PEND  0x00000002 /* Mouse port xmitting or resetting */
+#define IOC4_KM_CSR_K_LCB       0x00000004 /* Line Cntrl Bit for last KBD write */
+#define IOC4_KM_CSR_M_LCB       0x00000008 /* Same for mouse */
+#define IOC4_KM_CSR_K_DATA      0x00000010 /* State of kbd data line */
+#define IOC4_KM_CSR_K_CLK       0x00000020 /* State of kbd clock line */
+#define IOC4_KM_CSR_K_PULL_DATA 0x00000040 /* Pull kbd data line low */
+#define IOC4_KM_CSR_K_PULL_CLK  0x00000080 /* Pull kbd clock line low */
+#define IOC4_KM_CSR_M_DATA      0x00000100 /* State of mouse data line */
+#define IOC4_KM_CSR_M_CLK       0x00000200 /* State of mouse clock line */
+#define IOC4_KM_CSR_M_PULL_DATA 0x00000400 /* Pull mouse data line low */
+#define IOC4_KM_CSR_M_PULL_CLK  0x00000800 /* Pull mouse clock line low */
+#define IOC4_KM_CSR_EMM_MODE	0x00001000 /* Emulation mode */
+#define IOC4_KM_CSR_SIM_MODE	0x00002000 /* Clock X8 */
+#define IOC4_KM_CSR_K_SM_IDLE   0x00004000 /* Keyboard is idle */
+#define IOC4_KM_CSR_M_SM_IDLE   0x00008000 /* Mouse is idle */
+#define IOC4_KM_CSR_K_TO	0x00010000 /* Keyboard trying to send/receive */
+#define IOC4_KM_CSR_M_TO        0x00020000 /* Mouse trying to send/receive */
+#define IOC4_KM_CSR_K_TO_EN     0x00040000 /* KM_CSR_K_TO + KM_CSR_K_TO_EN =
+                                              cause SIO_IR to assert */
+#define IOC4_KM_CSR_M_TO_EN	0x00080000 /* KM_CSR_M_TO + KM_CSR_M_TO_EN =
+                                              cause SIO_IR to assert */
+#define IOC4_KM_CSR_K_CLAMP_ONE	0x00100000 /* Pull K_CLK low after rec. one char */
+#define IOC4_KM_CSR_M_CLAMP_ONE	0x00200000 /* Pull M_CLK low after rec. one char */
+#define IOC4_KM_CSR_K_CLAMP_THREE \
+                           	0x00400000 /* Pull K_CLK low after rec. three chars */
+#define IOC4_KM_CSR_M_CLAMP_THREE \
+                            	0x00800000 /* Pull M_CLK low after rec. three char */
+
+/* Bitmasks for IOC4_K_RD and IOC4_M_RD */
+#define IOC4_KM_RD_DATA_2       0x000000ff /* 3rd char recvd since last read */
+#define IOC4_KM_RD_DATA_2_SHIFT          0
+#define IOC4_KM_RD_DATA_1       0x0000ff00 /* 2nd char recvd since last read */
+#define IOC4_KM_RD_DATA_1_SHIFT          8
+#define IOC4_KM_RD_DATA_0	0x00ff0000 /* 1st char recvd since last read */
+#define IOC4_KM_RD_DATA_0_SHIFT         16
+#define IOC4_KM_RD_FRAME_ERR_2  0x01000000 /* Framing or parity error in byte 2 */
+#define IOC4_KM_RD_FRAME_ERR_1  0x02000000 /* Same for byte 1 */
+#define IOC4_KM_RD_FRAME_ERR_0  0x04000000 /* Same for byte 0 */
+
+#define IOC4_KM_RD_KBD_MSE      0x08000000 /* 0 if from kbd, 1 if from mouse */
+#define IOC4_KM_RD_OFLO	        0x10000000 /* 4th char recvd before this read */
+#define IOC4_KM_RD_VALID_2      0x20000000 /* DATA_2 valid */
+#define IOC4_KM_RD_VALID_1      0x40000000 /* DATA_1 valid */
+#define IOC4_KM_RD_VALID_0      0x80000000 /* DATA_0 valid */
+#define IOC4_KM_RD_VALID_ALL    (IOC4_KM_RD_VALID_0 | IOC4_KM_RD_VALID_1 | \
+                                 IOC4_KM_RD_VALID_2)
+
+/* Bitmasks for IOC4_K_WD & IOC4_M_WD */
+#define IOC4_KM_WD_WRT_DATA     0x000000ff /* Write to keyboard/mouse port */
+#define IOC4_KM_WD_WRT_DATA_SHIFT        0
+
+/* Bitmasks for serial RX status byte */
+#define IOC4_RXSB_OVERRUN       0x01       /* Char(s) lost */
+#define IOC4_RXSB_PAR_ERR	0x02	   /* Parity error */
+#define IOC4_RXSB_FRAME_ERR	0x04	   /* Framing error */
+#define IOC4_RXSB_BREAK	        0x08	   /* Break character */
+#define IOC4_RXSB_CTS	        0x10	   /* State of CTS */
+#define IOC4_RXSB_DCD	        0x20	   /* State of DCD */
+#define IOC4_RXSB_MODEM_VALID   0x40	   /* DCD, CTS, and OVERRUN are valid */
+#define IOC4_RXSB_DATA_VALID    0x80	   /* Data byte, FRAME_ERR PAR_ERR & BREAK valid */
+
+/* Bitmasks for serial TX control byte */
+#define IOC4_TXCB_INT_WHEN_DONE 0x20       /* Interrupt after this byte is sent */
+#define IOC4_TXCB_INVALID	0x00	   /* Byte is invalid */
+#define IOC4_TXCB_VALID	        0x40	   /* Byte is valid */
+#define IOC4_TXCB_MCR	        0x80	   /* Data<7:0> to modem control register */
+#define IOC4_TXCB_DELAY	        0xc0	   /* Delay data<7:0> mSec */
+
+/* Bitmasks for IOC4_SBBR_L */
+#define IOC4_SBBR_L_SIZE	0x00000001 /* 0 == 1KB rings, 1 == 4KB rings */
+#define IOC4_SBBR_L_BASE	0xfffff000 /* Lower serial ring base addr */
+
+/* Bitmasks for IOC4_SSCR_<3:0> */
+#define IOC4_SSCR_RX_THRESHOLD  0x000001ff /* Hiwater mark */
+#define IOC4_SSCR_TX_TIMER_BUSY 0x00010000 /* TX timer in progress */
+#define IOC4_SSCR_HFC_EN	0x00020000 /* Hardware flow control enabled */
+#define IOC4_SSCR_RX_RING_DCD   0x00040000 /* Post RX record on delta-DCD */
+#define IOC4_SSCR_RX_RING_CTS   0x00080000 /* Post RX record on delta-CTS */
+#define IOC4_SSCR_DIAG	        0x00200000 /* Bypass clock divider for sim */
+#define IOC4_SSCR_RX_DRAIN	0x08000000 /* Drain RX buffer to memory */
+#define IOC4_SSCR_DMA_EN	0x10000000 /* Enable ring buffer DMA */
+#define IOC4_SSCR_DMA_PAUSE	0x20000000 /* Pause DMA */
+#define IOC4_SSCR_PAUSE_STATE   0x40000000 /* Sets when PAUSE takes effect */
+#define IOC4_SSCR_RESET	        0x80000000 /* Reset DMA channels */
+
+/* All producer/comsumer pointers are the same bitfield */
+#define IOC4_PROD_CONS_PTR_4K   0x00000ff8 /* For 4K buffers */
+#define IOC4_PROD_CONS_PTR_1K   0x000003f8 /* For 1K buffers */
+#define IOC4_PROD_CONS_PTR_OFF           3
+
+/* Bitmasks for IOC4_STPIR_<3:0> */
+/* Reserved for future register definitions */
+
+/* Bitmasks for IOC4_STCIR_<3:0> */
+#define IOC4_STCIR_BYTE_CNT     0x0f000000 /* Bytes in unpacker */
+#define IOC4_STCIR_BYTE_CNT_SHIFT       24
+
+/* Bitmasks for IOC4_SRPIR_<3:0> */
+#define IOC4_SRPIR_BYTE_CNT	0x0f000000 /* Bytes in packer */
+#define IOC4_SRPIR_BYTE_CNT_SHIFT       24
+
+/* Bitmasks for IOC4_SRCIR_<3:0> */
+#define IOC4_SRCIR_ARM	        0x80000000 /* Arm RX timer */
+
+/* Bitmasks for IOC4_SHADOW_<3:0> */
+#define IOC4_SHADOW_DR          0x00000001  /* Data ready */
+#define IOC4_SHADOW_OE          0x00000002  /* Overrun error */
+#define IOC4_SHADOW_PE          0x00000004  /* Parity error */
+#define IOC4_SHADOW_FE          0x00000008  /* Framing error */
+#define IOC4_SHADOW_BI          0x00000010  /* Break interrupt */
+#define IOC4_SHADOW_THRE        0x00000020  /* Xmit holding register empty */
+#define IOC4_SHADOW_TEMT        0x00000040  /* Xmit shift register empty */
+#define IOC4_SHADOW_RFCE        0x00000080  /* Char in RX fifo has an error */
+#define IOC4_SHADOW_DCTS        0x00010000  /* Delta clear to send */
+#define IOC4_SHADOW_DDCD        0x00080000  /* Delta data carrier detect */
+#define IOC4_SHADOW_CTS         0x00100000  /* Clear to send */
+#define IOC4_SHADOW_DCD         0x00800000  /* Data carrier detect */
+#define IOC4_SHADOW_DTR         0x01000000  /* Data terminal ready */
+#define IOC4_SHADOW_RTS         0x02000000  /* Request to send */
+#define IOC4_SHADOW_OUT1        0x04000000  /* 16550 OUT1 bit */
+#define IOC4_SHADOW_OUT2        0x08000000  /* 16550 OUT2 bit */
+#define IOC4_SHADOW_LOOP        0x10000000  /* Loopback enabled */
+
+/* Bitmasks for IOC4_SRTR_<3:0> */
+#define IOC4_SRTR_CNT	        0x00000fff /* Reload value for RX timer */
+#define IOC4_SRTR_CNT_VAL	0x0fff0000 /* Current value of RX timer */
+#define IOC4_SRTR_CNT_VAL_SHIFT         16
+#define IOC4_SRTR_HZ                 16000 /* SRTR clock frequency */
+
+/* Serial port register map used for DMA and PIO serial I/O */
+typedef volatile struct ioc4_serialregs {
+    ioc4reg_t		    sscr;
+    ioc4reg_t		    stpir;
+    ioc4reg_t		    stcir;
+    ioc4reg_t		    srpir;
+    ioc4reg_t		    srcir;
+    ioc4reg_t		    srtr;
+    ioc4reg_t		    shadow;
+} ioc4_sregs_t;
+
+/* IOC4 UART register map */
+typedef volatile struct ioc4_uartregs {
+    union {
+        char                    rbr;    /* read only, DLAB == 0 */
+        char                    thr;    /* write only, DLAB == 0 */
+        char                    dll;    /* DLAB == 1 */
+    } u1;
+    union {
+        char                    ier;    /* DLAB == 0 */
+        char                    dlm;    /* DLAB == 1 */
+    } u2;
+    union {
+        char                    iir;    /* read only */
+        char                    fcr;    /* write only */
+    } u3;
+    char                    i4u_lcr;
+    char                    i4u_mcr;
+    char                    i4u_lsr;
+    char                    i4u_msr;
+    char                    i4u_scr;
+} ioc4_uart_t;
+
+#define i4u_rbr u1.rbr
+#define i4u_thr u1.thr
+#define i4u_dll u1.dll
+#define i4u_ier u2.ier
+#define i4u_dlm u2.dlm
+#define i4u_iir u3.iir
+#define i4u_fcr u3.fcr
+
+/* PCI config space register map */
+typedef volatile struct ioc4_configregs {
+    ioc4reg_t		    pci_id;
+    ioc4reg_t		    pci_scr;
+    ioc4reg_t		    pci_rev;
+    ioc4reg_t		    pci_lat;
+    ioc4reg_t		    pci_bar0;
+    ioc4reg_t		    pci_bar1;
+    ioc4reg_t               pci_bar2_not_implemented;
+    ioc4reg_t               pci_cis_ptr_not_implemented;
+    ioc4reg_t		    pci_sidv;
+    ioc4reg_t		    pci_rom_bar_not_implemented;
+    ioc4reg_t		    pci_cap;
+    ioc4reg_t		    pci_rsv;
+    ioc4reg_t		    pci_latgntint;
+
+    char                    pci_fill1[0x58 - 0x3c - 4];
+
+    ioc4reg_t               pci_pcix;
+    ioc4reg_t               pci_pcixstatus;
+} ioc4_cfg_t;
+
+/* PCI memory space register map addressed using pci_bar0 */
+typedef volatile struct ioc4_memregs {
+
+    /* Miscellaneous IOC4  registers */
+    ioc4reg_t		    pci_err_addr_l;
+    ioc4reg_t		    pci_err_addr_h;
+    ioc4reg_t		    sio_ir;
+    ioc4reg_t		    other_ir;
+
+    /* These registers are read-only for general kernel code.  To
+     * modify them use the functions in ioc4.c.
+     */
+    ioc4reg_t		    sio_ies_ro;
+    ioc4reg_t		    other_ies_ro;
+    ioc4reg_t		    sio_iec_ro;
+    ioc4reg_t		    other_iec_ro;
+    ioc4reg_t		    sio_cr;
+    ioc4reg_t		    misc_fill1;
+    ioc4reg_t		    int_out;
+    ioc4reg_t		    misc_fill2;
+    ioc4reg_t		    gpcr_s;
+    ioc4reg_t		    gpcr_c;
+    ioc4reg_t		    gpdr;
+    ioc4reg_t		    misc_fill3;
+    ioc4reg_t		    gppr_0;
+    ioc4reg_t		    gppr_1;
+    ioc4reg_t		    gppr_2;
+    ioc4reg_t		    gppr_3;
+    ioc4reg_t		    gppr_4;
+    ioc4reg_t		    gppr_5;
+    ioc4reg_t		    gppr_6;
+    ioc4reg_t		    gppr_7;
+
+    char		    misc_fill4[0x100 - 0x5C - 4];
+
+    /* ATA/ATAP registers */
+    ioc4reg_t		    ata_0;
+    ioc4reg_t		    ata_1;
+    ioc4reg_t		    ata_2;
+    ioc4reg_t		    ata_3;
+    ioc4reg_t		    ata_4;
+    ioc4reg_t		    ata_5;
+    ioc4reg_t		    ata_6;
+    ioc4reg_t		    ata_7;
+    ioc4reg_t		    ata_aux;
+
+    char		    ata_fill1[0x140 - 0x120 - 4];
+
+    ioc4reg_t		    ata_timing;
+    ioc4reg_t		    ata_dma_ptr_l;
+    ioc4reg_t		    ata_dma_ptr_h;
+    ioc4reg_t		    ata_dma_addr_l;
+    ioc4reg_t		    ata_dma_addr_h;
+    ioc4reg_t		    ata_bc_dev;
+    ioc4reg_t		    ata_bc_mem;
+    ioc4reg_t		    ata_dma_ctrl;
+
+    char		    ata_fill2[0x200 - 0x15C - 4];
+
+    /* Keyboard and mouse registers */
+    ioc4reg_t		    km_csr;
+    ioc4reg_t		    k_rd;
+    ioc4reg_t		    m_rd;
+    ioc4reg_t		    k_wd;
+    ioc4reg_t		    m_wd;
+
+    char		    km_fill1[0x300 - 0x210 - 4];
+
+    /* Serial port registers used for DMA serial I/O */
+    ioc4reg_t		    sbbr01_l;
+    ioc4reg_t		    sbbr01_h;
+    ioc4reg_t		    sbbr23_l;
+    ioc4reg_t		    sbbr23_h;
+
+    ioc4_sregs_t	    port_0;
+    ioc4_sregs_t	    port_1;
+    ioc4_sregs_t	    port_2;
+    ioc4_sregs_t	    port_3;
+
+    ioc4_uart_t		    uart_0;
+    ioc4_uart_t		    uart_1;
+    ioc4_uart_t		    uart_2;
+    ioc4_uart_t		    uart_3;
+} ioc4_mem_t;
+
+#endif	/* 0 */
+
+/*
+ * Bytebus device space
+ */
+#define IOC4_BYTEBUS_DEV0	0x80000L  /* Addressed using pci_bar0 */ 
+#define IOC4_BYTEBUS_DEV1	0xA0000L  /* Addressed using pci_bar0 */
+#define IOC4_BYTEBUS_DEV2	0xC0000L  /* Addressed using pci_bar0 */
+#define IOC4_BYTEBUS_DEV3	0xE0000L  /* Addressed using pci_bar0 */
+
+#if 0
+/* UART clock speed */
+#define IOC4_SER_XIN_CLK        66000000
+
+typedef enum ioc4_subdevs_e {
+    ioc4_subdev_generic,
+    ioc4_subdev_kbms,
+    ioc4_subdev_tty0,
+    ioc4_subdev_tty1,
+    ioc4_subdev_tty2,
+    ioc4_subdev_tty3,
+    ioc4_subdev_rt,
+    ioc4_nsubdevs
+} ioc4_subdev_t;
+
+/* Subdevice disable bits,
+ * from the standard INFO_LBL_SUBDEVS
+ */
+#define IOC4_SDB_TTY0		(1 << ioc4_subdev_tty0)
+#define IOC4_SDB_TTY1		(1 << ioc4_subdev_tty1)
+#define IOC4_SDB_TTY2		(1 << ioc4_subdev_tty2)
+#define IOC4_SDB_TTY3		(1 << ioc4_subdev_tty3)
+#define IOC4_SDB_KBMS		(1 << ioc4_subdev_kbms)
+#define IOC4_SDB_RT		(1 << ioc4_subdev_rt)
+#define IOC4_SDB_GENERIC	(1 << ioc4_subdev_generic)
+
+#define IOC4_ALL_SUBDEVS	((1 << ioc4_nsubdevs) - 1)
+
+#define IOC4_SDB_SERIAL		(IOC4_SDB_TTY0 | IOC4_SDB_TTY1 | IOC4_SDB_TTY2 | IOC4_SDB_TTY3)
+
+#define IOC4_STD_SUBDEVS	IOC4_ALL_SUBDEVS
+
+#define IOC4_INTA_SUBDEVS	(IOC4_SDB_SERIAL | IOC4_SDB_KBMS | IOC4_SDB_RT | IOC4_SDB_GENERIC)
+
+extern int		ioc4_subdev_enabled(vertex_hdl_t, ioc4_subdev_t);
+extern void		ioc4_subdev_enables(vertex_hdl_t, ulong_t);
+extern void		ioc4_subdev_enable(vertex_hdl_t, ioc4_subdev_t);
+extern void		ioc4_subdev_disable(vertex_hdl_t, ioc4_subdev_t);
+
+/* Macros to read and write the SIO_IEC and SIO_IES registers (see the
+ * comments in ioc4.c for details on why this is necessary
+ */
+#define IOC4_W_IES	0
+#define IOC4_W_IEC	1
+extern void		ioc4_write_ireg(void *, ioc4reg_t, int, ioc4_intr_type_t);
+
+#define IOC4_WRITE_IES(ioc4, val, type)	ioc4_write_ireg(ioc4, val, IOC4_W_IES, type)
+#define IOC4_WRITE_IEC(ioc4, val, type)	ioc4_write_ireg(ioc4, val, IOC4_W_IEC, type)
+
+typedef void
+ioc4_intr_func_f	(intr_arg_t, ioc4reg_t);
+
+typedef void
+ioc4_intr_connect_f	(vertex_hdl_t conn_vhdl,
+			 ioc4_intr_type_t,
+			 ioc4reg_t,
+			 ioc4_intr_func_f *,
+			 intr_arg_t info,
+			 vertex_hdl_t owner_vhdl,
+			 vertex_hdl_t intr_dev_vhdl,
+			 int (*)(intr_arg_t));
+
+typedef void
+ioc4_intr_disconnect_f	(vertex_hdl_t conn_vhdl,
+			 ioc4_intr_type_t,
+			 ioc4reg_t,
+			 ioc4_intr_func_f *,
+			 intr_arg_t info,
+			 vertex_hdl_t owner_vhdl);
+
+ioc4_intr_disconnect_f	ioc4_intr_disconnect;
+ioc4_intr_connect_f	ioc4_intr_connect;
+
+extern int		ioc4_is_console(vertex_hdl_t conn_vhdl);
+
+extern void		ioc4_mlreset(ioc4_cfg_t *, ioc4_mem_t *);
+
+extern intr_func_f	ioc4_intr;
+
+extern ioc4_mem_t      *ioc4_mem_ptr(void *ioc4_fastinfo);
+
+typedef ioc4_intr_func_f *ioc4_intr_func_t;
+
+#endif	/* 0 */
+#endif				/* _ASM_IA64_SN_IOC4_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/ioerror.h linux-2.4.21-pre6/include/asm-ia64/sn/ioerror.h
--- linux-2.4.20/include/asm-ia64/sn/ioerror.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/ioerror.h	2003-03-26 23:49:20.000000000 +0000
@@ -121,7 +121,7 @@
  */
 
 typedef struct io_error_s {
-    /* Bit fields indicating which sturcture fields are valid */
+    /* Bit fields indicating which structure fields are valid */
     union {
 	struct {
 	    unsigned                ievb_errortype:1;
@@ -138,6 +138,7 @@
 	    unsigned                ievb_memaddr:1;
 	    unsigned		    ievb_epc:1;
 	    unsigned		    ievb_ef:1;
+	    unsigned		    ievb_tnum:1;
 	} iev_b;
 	unsigned                iev_a;
     } ie_v;
@@ -156,13 +157,14 @@
     paddr_t                 ie_memaddr;		/* Physical memory address       */
     caddr_t		    ie_epc;		/* pc when error reported	 */
     caddr_t		    ie_ef;		/* eframe when error reported	 */
-
+    short		    ie_tnum;		/* Xtalk TNUM field */
 } ioerror_t;
 
 #define	IOERROR_INIT(e)		do { (e)->ie_v.iev_a = 0; } while (0)
 #define	IOERROR_SETVALUE(e,f,v)	do { (e)->ie_ ## f = (v); (e)->ie_v.iev_b.ievb_ ## f = 1; } while (0)
-#define	IOERROR_FIELDVALID(e,f)	(((e)->ie_v.iev_b.ievb_ ## f) != 0)
-#define	IOERROR_GETVALUE(e,f)	(ASSERT(IOERROR_FIELDVALID(e,f)),((e)->ie_ ## f))
+#define	IOERROR_FIELDVALID(e,f)	((unsigned long long)((e)->ie_v.iev_b.ievb_ ## f) != (unsigned long long) 0)
+#define	IOERROR_NOGETVALUE(e,f)	(ASSERT(IOERROR_FIELDVALID(e,f)), ((e)->ie_ ## f))
+#define	IOERROR_GETVALUE(p,e,f)	ASSERT(IOERROR_FIELDVALID(e,f)); p=((e)->ie_ ## f)
 
 /* hub code likes to call the SysAD address "hubaddr" ... */
 #define	ie_hubaddr	ie_sysioaddr
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/iograph.h linux-2.4.21-pre6/include/asm-ia64/sn/iograph.h
--- linux-2.4.20/include/asm-ia64/sn/iograph.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/iograph.h	2003-03-26 23:49:00.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 #ifndef _ASM_IA64_SN_IOGRAPH_H
 #define _ASM_IA64_SN_IOGRAPH_H
@@ -32,6 +32,7 @@
 #define EDGE_LBL_CONTROLLER		"controller"
 #define EDGE_LBL_CPU			"cpu"
 #define EDGE_LBL_CPUNUM			"cpunum"
+#define EDGE_LBL_DIRECT			"direct"
 #define EDGE_LBL_DISABLED		"disabled"
 #define EDGE_LBL_DISK			"disk"
 #define EDGE_LBL_DMA_ENGINE             "dma_engine"    /* Only available on
@@ -67,6 +68,7 @@
 #define EDGE_LBL_HPC			"hpc"
 #define EDGE_LBL_GFX			"gfx"
 #define EDGE_LBL_HUB			"hub"		/* For SN0 */
+#define EDGE_LBL_HW			"hw"
 #define EDGE_LBL_SYNERGY		"synergy"	/* For SNIA only */
 #define EDGE_LBL_IBUS			"ibus"		/* For EVEREST */
 #define EDGE_LBL_INTERCONNECT		"link"
@@ -74,6 +76,8 @@
 #define EDGE_LBL_IO4			"io4"		/* For EVEREST */
 #define EDGE_LBL_IOC3			"ioc3"
 #define EDGE_LBL_LUN                    "lun"
+#define EDGE_LBL_LINUX                  "linux"
+#define EDGE_LBL_LINUX_BUS              EDGE_LBL_LINUX "/busnum"
 #define EDGE_LBL_MACE                   "mace" 		/* O2 mace */
 #define EDGE_LBL_MACHDEP                "machdep"       /* Platform depedent devices */
 #define EDGE_LBL_MASTER			".master"
@@ -86,6 +90,9 @@
 #define EDGE_LBL_NVRAM			"nvram"
 #define EDGE_LBL_PARTITION		"partition"
 #define EDGE_LBL_PCI			"pci"
+#define EDGE_LBL_PCIX			"pci-x"
+#define EDGE_LBL_PCIX_0			EDGE_LBL_PCIX "/0"
+#define EDGE_LBL_PCIX_1			EDGE_LBL_PCIX "/1"
 #define EDGE_LBL_PORT			"port"
 #define EDGE_LBL_PROM			"prom"
 #define EDGE_LBL_RACK			"rack"
@@ -112,6 +119,7 @@
 #define EDGE_LBL_XPLINK			"xplink" 	/* Cross partition */
 #define	EDGE_LBL_XPLINK_NET		"net" 		/* XP network devs */
 #define	EDGE_LBL_XPLINK_RAW		"raw"		/* XP Raw devs */
+#define EDGE_LBL_SLAB			"slab"		/* Slab of a module */
 #define	EDGE_LBL_XPLINK_KERNEL		"kernel"	/* XP kernel devs */
 #define	EDGE_LBL_XPLINK_ADMIN		"admin"	   	/* Partition admin */
 #define	EDGE_LBL_KAIO			"kaio"	   	/* Kernel async i/o poll */
@@ -202,7 +210,7 @@
 
 #include <asm/sn/xtalk/xbow.h>	/* For get MAX_PORT_NUM */
 
-int io_brick_map_widget(char, int);
+int io_brick_map_widget(int, int);
 int io_path_map_widget(devfs_handle_t);
 
 /*
@@ -210,8 +218,7 @@
  */
 
 struct io_brick_map_s {
-    char                ibm_type;                  /* brick type, e.g. */
-                                                   /* 'I' for Ibrick   */
+    int                 ibm_type;                  /* brick type */
     int                 ibm_map_wid[MAX_PORT_NUM]; /* wid to int map */
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/klclock.h linux-2.4.21-pre6/include/asm-ia64/sn/klclock.h
--- linux-2.4.20/include/asm-ia64/sn/klclock.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/klclock.h	2003-03-26 23:49:50.000000000 +0000
@@ -3,13 +3,14 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1996, 2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1996, 2001-2002 Silicon Graphics, Inc. All rights reserved.
  * Copyright (C) 2001 by Ralf Baechle
  */
 #ifndef _ASM_IA64_SN_KLCLOCK_H
 #define _ASM_IA64_SN_KLCLOCK_H
 
 #include <asm/sn/ioc3.h>
+#include <asm/sn/ioc4.h>
 
 #define RTC_BASE_ADDR		(unsigned char *)(nvram_base)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/klconfig.h linux-2.4.21-pre6/include/asm-ia64/sn/klconfig.h
--- linux-2.4.20/include/asm-ia64/sn/klconfig.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/klconfig.h	2003-03-26 23:49:25.000000000 +0000
@@ -55,6 +55,10 @@
 #include <asm/sn/sn2/shub_md.h>
 #endif
 
+#ifdef CONFIG_IA64_SGI_SN2
+#include <asm/sn/geo.h>
+#endif
+
 #define KLCFGINFO_MAGIC	0xbeedbabe
 
 typedef s32 klconf_off_t;
@@ -335,8 +339,8 @@
 
 #define KLCLASS_IOBRICK	0x70		/* IP35 iobrick */
 
-#define KLCLASS_MAX	7		/* Bump this if a new CLASS is added */
-#define KLTYPE_MAX	10		/* Bump this if a new CLASS is added */
+#define KLCLASS_MAX	8		/* Bump this if a new CLASS is added */
+#define KLTYPE_MAX	11		/* Bump this if a new CLASS is added */
 
 #define KLCLASS_UNKNOWN	0xf0
 
@@ -353,7 +357,7 @@
 #define KLTYPE_WEIRDCPU (KLCLASS_CPU | 0x0)
 #define KLTYPE_SNIA	(KLCLASS_CPU | 0x1)
 
-#define KLTYPE_WEIRDIO	(KLCLASS_IO  | 0x0)
+#define KLTYPE_WEIRDIO	(KLCLASS_IOBRICK  | 0x0)
 #define KLTYPE_BASEIO	(KLCLASS_IO  | 0x1) /* IOC3, SuperIO, Bridge, SCSI */
 #define KLTYPE_IO6	KLTYPE_BASEIO       /* Additional name */
 #define KLTYPE_4CHSCSI	(KLCLASS_IO  | 0x2)
@@ -433,7 +437,11 @@
  	unsigned char 	brd_flags;        /* Enabled, Disabled etc */
 	unsigned char 	brd_slot;         /* slot number */
 	unsigned short	brd_debugsw;      /* Debug switches */
+#ifdef CONFIG_IA64_SGI_SN2
+	geoid_t		brd_geoid;	  /* geo id */
+#else
 	moduleid_t	brd_module;       /* module to which it belongs */
+#endif
 	partid_t 	brd_partition;    /* Partition number */
         unsigned short 	brd_diagval;      /* diagnostic value */
         unsigned short 	brd_diagparm;     /* diagnostic parameter */
@@ -448,6 +456,9 @@
 	confidence_t	brd_confidence;	  /* confidence that the board is bad */
 	nasid_t		brd_owner;        /* who owns this board */
 	unsigned char 	brd_nic_flags;    /* To handle 8 more NICs */
+#ifdef CONFIG_IA64_SGI_SN2
+	char		pad[32];	  /* future expansion */
+#endif
 	char		brd_name[32];
 } lboard_t;
 
@@ -570,6 +581,10 @@
 #define KLSTRUCT_USB		34
 #define KLSTRUCT_USBKBD		35
 #define KLSTRUCT_USBMS		36
+#define KLSTRUCT_SCSI_CTLR	37
+#define KLSTRUCT_PEBRICK	38
+#define KLSTRUCT_GIGE           39
+#define KLSTRUCT_IDE		40
 
 /*
  * These are the indices of various components within a lboard structure.
@@ -611,6 +626,9 @@
 	nasid_t		port_nasid;
 	unsigned char	port_flag;
 	klconf_off_t	port_offset;
+#ifdef CONFIG_IA64_SGI_SN2
+	short		port_num;
+#endif
 } klport_t;
 
 typedef struct klcpu_s {                          /* CPU */
@@ -620,6 +638,9 @@
     	unsigned short 	cpu_speed;	/* Speed in MHZ */
     	unsigned short 	cpu_scachesz;	/* secondary cache size in MB */
     	unsigned short 	cpu_scachespeed;/* secondary cache speed in MHz */
+#ifdef CONFIG_IA64_SGI_SN2
+	unsigned long	pad;
+#endif
 } klcpu_t ;
 
 #define CPU_STRUCT_VERSION   2
@@ -627,16 +648,28 @@
 typedef struct klhub_s {			/* HUB */
 	klinfo_t 	hub_info;
 	uint 		hub_flags;		/* PCFG_HUB_xxx flags */
+#ifdef CONFIG_IA64_SGI_SN2
+#define MAX_NI_PORTS                    2
+	klport_t	hub_port[MAX_NI_PORTS + 1];/* hub is connected to this */
+#else
 	klport_t	hub_port;		/* hub is connected to this */
+#endif
 	nic_t		hub_box_nic;		/* nic of containing box */
 	klconf_off_t	hub_mfg_nic;		/* MFG NIC string */
 	u64		hub_speed;		/* Speed of hub in HZ */
+#ifdef CONFIG_IA64_SGI_SN2
+	moduleid_t	hub_io_module;		/* attached io module */
+	unsigned long	pad;
+#endif
 } klhub_t ;
 
 typedef struct klhub_uart_s {			/* HUB */
 	klinfo_t 	hubuart_info;
 	uint 		hubuart_flags;		/* PCFG_HUB_xxx flags */
 	nic_t		hubuart_box_nic;	/* nic of containing box */
+#ifdef CONFIG_IA64_SGI_SN2
+	unsigned long	pad;
+#endif
 } klhub_uart_t ;
 
 #define MEMORY_STRUCT_VERSION   2
@@ -647,6 +680,9 @@
 	short		membnk_dimm_select; /* bank to physical addr mapping*/
 	short		membnk_bnksz[MD_MEM_BANKS]; /* Memory bank sizes */
 	short		membnk_attr;
+#ifdef CONFIG_IA64_SGI_SN2
+	unsigned long	pad;
+#endif
 } klmembnk_t ;
 
 #define KLCONFIG_MEMBNK_SIZE(_info, _bank)	\
@@ -665,6 +701,9 @@
               char snum_str[MAX_SERIAL_NUM_SIZE];
               unsigned long long       snum_int;
       } snum;
+#ifdef CONFIG_IA64_SGI_SN2
+      unsigned long   pad;
+#endif
 } klmod_serial_num_t;
 
 /* Macros needed to access serial number structure in lboard_t.
@@ -682,6 +721,9 @@
     	klport_t	xbow_port_info[MAX_XBOW_LINKS] ; /* Module number */
         int		xbow_master_hub_link;
         /* type of brd connected+component struct ptr+flags */
+#ifdef CONFIG_IA64_SGI_SN2
+	unsigned long	pad;
+#endif
 } klxbow_t ;
 
 #define MAX_PCI_SLOTS 8
@@ -700,6 +742,9 @@
     	pci_t    	pci_specific  ;    /* PCI Board config info */
 	klpci_device_t	bri_devices[MAX_PCI_DEVS] ;	/* PCI IDs */
 	klconf_off_t	bri_mfg_nic ;
+#ifdef CONFIG_IA64_SGI_SN2
+	unsigned long	pad;
+#endif
 } klbri_t ;
 
 #define MAX_IOC3_TTY	2
@@ -713,6 +758,9 @@
 	klinfo_t	ioc3_enet ;
 	klconf_off_t	ioc3_enet_off ;
 	klconf_off_t	ioc3_kbd_off ;
+#ifdef CONFIG_IA64_SGI_SN2
+	unsigned long	pad;
+#endif
 } klioc3_t ;
 
 #define MAX_VME_SLOTS 8
@@ -721,12 +769,18 @@
 	klinfo_t 	vmeb_info ;
 	vmeb_t		vmeb_specific ;
     	klconf_off_t   	vmeb_brdinfo[MAX_VME_SLOTS]   ;    /* VME Board config info */
+#ifdef CONFIG_IA64_SGI_SN2
+	unsigned long	pad;
+#endif
 } klvmeb_t ;
 
 typedef struct klvmed_s {                          /* VME DEVICE - VME BOARD */
 	klinfo_t	vmed_info ;
 	vmed_t		vmed_specific ;
     	klconf_off_t   	vmed_brdinfo[MAX_VME_SLOTS]   ;    /* VME Board config info */
+#ifdef CONFIG_IA64_SGI_SN2
+	unsigned long	pad;
+#endif
 } klvmed_t ;
 
 #define ROUTER_VECTOR_VERS	2
@@ -739,6 +793,9 @@
     	klport_t 	rou_port[MAX_ROUTER_PORTS + 1] ; /* array index 1 to 6 */
 	klconf_off_t	rou_mfg_nic ;     /* MFG NIC string */
 	u64	rou_vector;	  /* vector from master node */
+#ifdef CONFIG_IA64_SGI_SN2
+	unsigned long   pad;
+#endif
 } klrou_t ;
 
 /*
@@ -763,16 +820,25 @@
 	graphics_t	gfx_specific;
 	klconf_off_t    pad0;		/* for compatibility with older proms */
 	klconf_off_t    gfx_mfg_nic;
+#ifdef CONFIG_IA64_SGI_SN2
+	unsigned long	pad;
+#endif
 } klgfx_t;
 
 typedef struct klxthd_s {   
 	klinfo_t 	xthd_info ;
 	klconf_off_t	xthd_mfg_nic ;        /* MFG NIC string */
+#ifdef CONFIG_IA64_SGI_SN2
+	unsigned long	pad;
+#endif
 } klxthd_t ;
 
 typedef struct kltpu_s {                     /* TPU board */
 	klinfo_t 	tpu_info ;
 	klconf_off_t	tpu_mfg_nic ;        /* MFG NIC string */
+#ifdef CONFIG_IA64_SGI_SN2
+	unsigned long	pad;
+#endif
 } kltpu_t ;
 
 typedef struct klgsn_s {                     /* GSN board */
@@ -789,36 +855,64 @@
  * that as the size to be klmalloced.
  */
 
-typedef struct klscsi_s {                          /* SCSI Controller */
+typedef struct klscsi_s {                          /* SCSI Bus */
 	klinfo_t 	scsi_info ;
     	scsi_t       	scsi_specific   ; 
 	unsigned char 	scsi_numdevs ;
 	klconf_off_t	scsi_devinfo[MAX_SCSI_DEVS] ; 
+#ifdef CONFIG_IA64_SGI_SN2
+	unsigned long	pad;
+#endif
 } klscsi_t ;
 
+typedef struct klscctl_s {                          /* SCSI Controller */
+	klinfo_t 	scsi_info ;
+	uint		type;
+	uint		scsi_buscnt;                        /* # busses this cntlr */
+	void		*scsi_bus[2];                       /* Pointer to 2 klscsi_t's */
+#ifdef CONFIG_IA64_SGI_SN2
+	unsigned long	pad;
+#endif
+} klscctl_t ;
+
 typedef struct klscdev_s {                          /* SCSI device */
 	klinfo_t 	scdev_info ;
 	struct scsidisk_data *scdev_cfg ; /* driver fills up this */
+#ifdef CONFIG_IA64_SGI_SN2
+	unsigned long	pad;
+#endif
 } klscdev_t ;
 
 typedef struct klttydev_s {                          /* TTY device */
 	klinfo_t 	ttydev_info ;
 	struct terminal_data *ttydev_cfg ; /* driver fills up this */
+#ifdef CONFIG_IA64_SGI_SN2
+	unsigned long	pad;
+#endif
 } klttydev_t ;
 
 typedef struct klenetdev_s {                          /* ENET device */
 	klinfo_t 	enetdev_info ;
 	struct net_data *enetdev_cfg ; /* driver fills up this */
+#ifdef CONFIG_IA64_SGI_SN2
+	unsigned long	pad;
+#endif
 } klenetdev_t ;
 
 typedef struct klkbddev_s {                          /* KBD device */
 	klinfo_t 	kbddev_info ;
 	struct keyboard_data *kbddev_cfg ; /* driver fills up this */
+#ifdef CONFIG_IA64_SGI_SN2
+	unsigned long	pad;
+#endif
 } klkbddev_t ;
 
 typedef struct klmsdev_s {                          /* mouse device */
         klinfo_t        msdev_info ;
         void 		*msdev_cfg ; 
+#ifdef CONFIG_IA64_SGI_SN2
+	unsigned long	pad;
+#endif
 } klmsdev_t ;
 
 #define MAX_FDDI_DEVS 10 /* XXX Is this true */
@@ -827,11 +921,17 @@
 	klinfo_t 	fddi_info ;
     	fddi_t        	fddi_specific ;       
 	klconf_off_t	fddi_devinfo[MAX_FDDI_DEVS] ;
+#ifdef CONFIG_IA64_SGI_SN2
+	unsigned long	pad;
+#endif
 } klfddi_t ;
 
 typedef struct klmio_s {                          /* MIO */
 	klinfo_t 	mio_info ;
     	mio_t       	mio_specific   ; 
+#ifdef CONFIG_IA64_SGI_SN2
+	unsigned long	pad;
+#endif
 } klmio_t ;
 
 /*
@@ -842,6 +942,9 @@
 	klinfo_t	usb_info;	/* controller info */
 	void		*usb_bus;	/* handle to usb_bus_t */
 	uint64_t	usb_controller;	/* ptr to controller info */
+#ifdef CONFIG_IA64_SGI_SN2
+	unsigned long	pad;
+#endif
 } klusb_t ; 
 
 typedef union klcomp_s {
@@ -856,6 +959,7 @@
 	klrou_t		kc_rou;
 	klgfx_t		kc_gfx;
 	klscsi_t	kc_scsi;
+	klscctl_t	kc_scsi_ctl;
 	klscdev_t	kc_scsi_dev;
 	klfddi_t	kc_fddi;
 	klmio_t		kc_mio;
@@ -929,26 +1033,38 @@
 extern lboard_t *find_gfxpipe(int pipenum);
 extern void setup_gfxpipe_link(devfs_handle_t vhdl,int pipenum);
 extern lboard_t *find_lboard_class(lboard_t *start, unsigned char brd_class);
+#ifdef CONFIG_IA64_SGI_SN2
+extern lboard_t *find_lboard_module_class(lboard_t *start, geoid_t geoid,
+						unsigned char brd_class);
+#else
 extern lboard_t *find_lboard_module_class(lboard_t *start, moduleid_t mod,
                                                unsigned char brd_class);
+#endif
 extern lboard_t *find_nic_lboard(lboard_t *, nic_t);
 extern lboard_t *find_nic_type_lboard(nasid_t, unsigned char, nic_t);
+#ifdef CONFIG_IA64_SGI_SN2
+extern lboard_t *find_lboard_modslot(lboard_t *start, geoid_t geoid);
+extern lboard_t *find_lboard_module(lboard_t *start, geoid_t geoid);
+extern lboard_t *get_board_name(nasid_t nasid, geoid_t geoid, slotid_t slot, char *name);
+#else
 extern lboard_t *find_lboard_modslot(lboard_t *start, moduleid_t mod, slotid_t slot);
 extern lboard_t *find_lboard_module(lboard_t *start, moduleid_t mod);
 extern lboard_t *get_board_name(nasid_t nasid, moduleid_t mod, slotid_t slot, char *name);
+#endif
 extern int	config_find_nic_router(nasid_t, nic_t, lboard_t **, klrou_t**);
 extern int	config_find_nic_hub(nasid_t, nic_t, lboard_t **, klhub_t**);
 extern int	config_find_xbow(nasid_t, lboard_t **, klxbow_t**);
 extern int 	update_klcfg_cpuinfo(nasid_t, int);
 extern void 	board_to_path(lboard_t *brd, char *path);
+#ifdef CONFIG_IA64_SGI_SN2
 extern moduleid_t get_module_id(nasid_t nasid);
+#endif
 extern void 	nic_name_convert(char *old_name, char *new_name);
 extern int 	module_brds(nasid_t nasid, lboard_t **module_brds, int n);
 extern lboard_t *brd_from_key(uint64_t key);
 extern void 	device_component_canonical_name_get(lboard_t *,klinfo_t *,
 						    char *);
 extern int	board_serial_number_get(lboard_t *,char *);
-extern int	is_master_baseio(nasid_t,moduleid_t,slotid_t);
 extern nasid_t	get_actual_nasid(lboard_t *brd) ;
 extern net_vec_t klcfg_discover_route(lboard_t *, lboard_t *, int);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/ksys/elsc.h linux-2.4.21-pre6/include/asm-ia64/sn/ksys/elsc.h
--- linux-2.4.20/include/asm-ia64/sn/ksys/elsc.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/ksys/elsc.h	2003-03-26 23:49:53.000000000 +0000
@@ -9,8 +9,11 @@
 #ifndef _ASM_SN_KSYS_ELSC_H
 #define _ASM_SN_KSYS_ELSC_H
 
+#include <linux/config.h>
 #include <asm/sn/ksys/l1.h>
 
+#ifdef CONFIG_IA64_SGI_SN1
+
 #define ELSC_ACP_MAX		86		/* 84+cr+lf */
 #define ELSC_LINE_MAX		(ELSC_ACP_MAX - 2)
 
@@ -73,7 +76,6 @@
 int	elsc_power_cycle(elsc_t *e);
 int	elsc_system_reset(elsc_t *e);
 int	elsc_dip_switches(elsc_t *e);
-int	elsc_nic_get(elsc_t *e, uint64_t *nic, int verbose);
 
 int	_elsc_hbt(elsc_t *e, int ival, int rdly);
 
@@ -83,6 +85,9 @@
 
 elsc_t	       *get_elsc(void);
 
+#endif	/* CONFIG_IA64_SGI_SN1 */
+
+
 /*
  * Error codes
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/ksys/l1.h linux-2.4.21-pre6/include/asm-ia64/sn/ksys/l1.h
--- linux-2.4.20/include/asm-ia64/sn/ksys/l1.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/ksys/l1.h	2003-03-26 23:49:25.000000000 +0000
@@ -10,11 +10,15 @@
 #ifndef _ASM_SN_KSYS_L1_H
 #define _ASM_SN_KSYS_L1_H
 
+#include <linux/config.h>
 #include <asm/sn/vector.h>
 #include <asm/sn/addrs.h>
 #include <asm/atomic.h>
 #include <asm/sn/sv.h>
 
+
+#ifdef CONFIG_IA64_SGI_SN1
+
 #define BRL1_QSIZE	128	/* power of 2 is more efficient */
 #define BRL1_BUFSZ	264	/* needs to be large enough
 				 * to hold 2 flags, escaped
@@ -109,8 +113,6 @@
 #define BRL1_RESET	7
 
 
-#ifndef __ASSEMBLY__
-
 /*
  * l1sc_t structure-- tracks protocol state, open subchannels, etc.
  */
@@ -148,7 +150,6 @@
 
     sc_cq_t	 garbage_q;	/* a place to put unsolicited packets */
     sc_cq_t	 oq[BRL1_OQS];	/* elscuart output queues */
-
 } l1sc_t;
 
 
@@ -169,6 +170,7 @@
 #define SC_TIMEDOUT	(-9)
 #define SC_NSUBCH	(-10)
 
+#endif	/* CONFIG_IA64_SGI_SN1 */
 
 /* L1 Target Addresses */
 /*
@@ -179,21 +181,38 @@
  * id (L1 functionality is divided into several independent "tasks"
  * that can each receive command requests and transmit responses)
  */
+#ifdef CONFIG_IA64_SGI_SN1
 #define L1_ADDR_TYPE_SHFT	28
 #define L1_ADDR_TYPE_MASK	0xF0000000
+#else
+#define L1_ADDR_TYPE_SHFT	8
+#define L1_ADDR_TYPE_MASK	0xFF00
+#endif	/* CONFIG_IA64_SGI_SN1 */
 #define L1_ADDR_TYPE_L1		0x00	/* L1 system controller */
 #define L1_ADDR_TYPE_L2		0x01	/* L2 system controller */
 #define L1_ADDR_TYPE_L3		0x02	/* L3 system controller */
 #define L1_ADDR_TYPE_CBRICK	0x03	/* attached C brick	*/
 #define L1_ADDR_TYPE_IOBRICK	0x04	/* attached I/O brick	*/
 
+#ifdef CONFIG_IA64_SGI_SN1
 #define L1_ADDR_RACK_SHFT	18
 #define L1_ADDR_RACK_MASK	0x0FFC0000
 #define	L1_ADDR_RACK_LOCAL	0x3ff	/* local brick's rack	*/
+#else
+#define L1_ADDR_RACK_SHFT	16
+#define L1_ADDR_RACK_MASK	0xFFFF00
+#define	L1_ADDR_RACK_LOCAL	0xffff	/* local brick's rack	*/
+#endif /* CONFIG_IA64_SGI_SN1 */
 
+#ifdef CONFIG_IA64_SGI_SN1
 #define L1_ADDR_BAY_SHFT	12
 #define L1_ADDR_BAY_MASK	0x0003F000
 #define	L1_ADDR_BAY_LOCAL	0x3f	/* local brick's bay	*/
+#else
+#define L1_ADDR_BAY_SHFT	0
+#define L1_ADDR_BAY_MASK	0xFF
+#define	L1_ADDR_BAY_LOCAL	0xff	/* local brick's bay	*/
+#endif	/* CONFIG_IA64_SGI_SN1 */
 
 #define L1_ADDR_TASK_SHFT	0
 #define L1_ADDR_TASK_MASK	0x0000001F
@@ -268,13 +287,16 @@
 #define L1_REQ_EXEC_CMD		0x0000	/* interpret and execute an ASCII
 					   command string */
 
-
 /* brick type response codes */
-#define L1_BRICKTYPE_C	0x43
-#define L1_BRICKTYPE_I	0x49
-#define L1_BRICKTYPE_P	0x50
-#define L1_BRICKTYPE_R  0x52
-#define L1_BRICKTYPE_X  0x58
+#define L1_BRICKTYPE_IP45       0x34            /* 4 */
+#define L1_BRICKTYPE_C          0x43            /* C */
+#define L1_BRICKTYPE_I          0x49            /* I */
+#define L1_BRICKTYPE_P          0x50            /* P */
+#define L1_BRICKTYPE_R          0x52            /* R */
+#define L1_BRICKTYPE_X          0x58            /* X */
+#define L1_BRICKTYPE_X2         0x59            /* Y */
+#define L1_BRICKTYPE_N          0x4e            /* N */
+#define L1_BRICKTYPE_PX		0x23		/* # */
 
 /* EEPROM codes (for the "read EEPROM" request) */
 /* c brick */
@@ -306,7 +328,6 @@
     (*(l1addr_t *)(addr) = (l1addr_t)(trb) |				\
     			     ((l1addr_t)(tsk) << L1_ADDR_TASK_SHFT))
 
-
 #define L1_DISPLAY_LINE_LENGTH	12	/* L1 display characters/line */
 
 #ifdef L1_DISP_2LINES
@@ -316,10 +337,12 @@
 					 * to system software */
 #endif
 
-#define SC_EVENT_CLASS_MASK ((unsigned short)0xff00)
-
 #define bzero(d, n)	memset((d), 0, (n))
 
+#ifdef CONFIG_IA64_SGI_SN1
+
+#define SC_EVENT_CLASS_MASK ((unsigned short)0xff00)
+
 /* public interfaces to L1 system controller */
 
 int	sc_open( l1sc_t *sc, uint target );
@@ -348,15 +371,18 @@
 #define get_l1sc	get_elsc
 #define get_master_l1sc get_l1sc
 
-int	router_module_get( nasid_t nasid, net_vec_t path );
-
 int	iobrick_rack_bay_type_get( l1sc_t *sc, uint *rack,
 				   uint *bay, uint *brick_type );
 int	iobrick_module_get( l1sc_t *sc );
 int	iobrick_pci_slot_pwr( l1sc_t *sc, int bus, int slot, int up );
 int	iobrick_pci_bus_pwr( l1sc_t *sc, int bus, int up );
 int	iobrick_sc_version( l1sc_t *sc, char *result );
+#else
+int	elsc_display_line(nasid_t nasid, char *line, int lnum);
+int	iobrick_rack_bay_type_get( nasid_t nasid, uint *rack,
+				   uint *bay, uint *brick_type );
+int	iobrick_module_get( nasid_t nasid );
+#endif	/* CONFIG_IA64_SGI_SN1 */
 
 
-#endif /* !__ASSEMBLY__ */
 #endif /* _ASM_SN_KSYS_L1_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/leds.h linux-2.4.21-pre6/include/asm-ia64/sn/leds.h
--- linux-2.4.20/include/asm-ia64/sn/leds.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/leds.h	2003-03-26 23:49:56.000000000 +0000
@@ -15,7 +15,7 @@
 #include <asm/sn/pda.h>
 
 #ifdef CONFIG_IA64_SGI_SN1
-#define LED0		0xc0000b00100000c0LL	/* ZZZ fixme */
+#define LED0		0xc0000b00100000c0LL
 #define LED_CPU_SHIFT	3
 #else
 #include <asm/sn/sn2/shub.h>
@@ -25,7 +25,13 @@
 
 #define LED_CPU_HEARTBEAT	0x01
 #define LED_CPU_ACTIVITY	0x02
+#ifdef LED_WAR
+#define LED_ALWAYS_SET		0x64	/* SN2 hw workaround: always set 0x60 */
+#define LED_MASK_AUTOTEST	0x9e
+#else /* LED_WAR */
+#define LED_ALWAYS_SET		0x00
 #define LED_MASK_AUTOTEST	0xfe
+#endif /* LED_WAR */
 
 /*
  * Basic macros for flashing the LEDS on an SGI, SN1.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/module.h linux-2.4.21-pre6/include/asm-ia64/sn/module.h
--- linux-2.4.20/include/asm-ia64/sn/module.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/module.h	2003-03-26 23:49:25.000000000 +0000
@@ -13,12 +13,13 @@
 #endif
 
 
+#include <linux/config.h>
 #include <asm/sn/systeminfo.h>
 #include <asm/sn/klconfig.h>
 #include <asm/sn/ksys/elsc.h>
 
 #define MODULE_MAX			128
-#define MODULE_MAX_NODES		1
+#define MODULE_MAX_NODES		2
 #define MODULE_HIST_CNT			16
 #define MAX_MODULE_LEN			16
 
@@ -32,6 +33,127 @@
 #define MODULE_FORMAT_LONG	2
 
 
+#ifdef CONFIG_IA64_SGI_SN2
+
+/*
+ *	Module id format
+ *
+ *	31-16	Rack ID (encoded class, group, number - 16-bit unsigned int)
+ *	 15-8	Brick type (8-bit ascii character)
+ *	  7-0	Bay (brick position in rack (0-63) - 8-bit unsigned int)
+ *
+ */
+
+/*
+ * Macros for getting the brick type
+ */
+#define MODULE_BTYPE_MASK	0xff00
+#define MODULE_BTYPE_SHFT	8
+#define MODULE_GET_BTYPE(_m)	(((_m) & MODULE_BTYPE_MASK) >> MODULE_BTYPE_SHFT)
+#define MODULE_BT_TO_CHAR(_b)	((char)(_b))
+#define MODULE_GET_BTCHAR(_m)	(MODULE_BT_TO_CHAR(MODULE_GET_BTYPE(_m)))
+
+/*
+ * Macros for getting the rack ID.
+ */
+#define MODULE_RACK_MASK	0xffff0000
+#define MODULE_RACK_SHFT	16
+#define MODULE_GET_RACK(_m)	(((_m) & MODULE_RACK_MASK) >> MODULE_RACK_SHFT)
+
+/*
+ * Macros for getting the brick position
+ */
+#define MODULE_BPOS_MASK	0x00ff
+#define MODULE_BPOS_SHFT	0
+#define MODULE_GET_BPOS(_m)	(((_m) & MODULE_BPOS_MASK) >> MODULE_BPOS_SHFT)
+
+/*
+ * Macros for constructing moduleid_t's
+ */
+#define RBT_TO_MODULE(_r, _b, _t) ((_r) << MODULE_RACK_SHFT | \
+				   (_b) << MODULE_BPOS_SHFT | \
+				   (_t) << MODULE_BTYPE_SHFT)
+
+/*
+ * Macros for encoding and decoding rack IDs
+ * A rack number consists of three parts:
+ *   class (0==CPU/mixed, 1==I/O), group, number
+ *
+ * Rack number is stored just as it is displayed on the screen:
+ * a 3-decimal-digit number.
+ */
+#define RACK_CLASS_DVDR		100
+#define RACK_GROUP_DVDR		10
+#define RACK_NUM_DVDR		1
+
+#define RACK_CREATE_RACKID(_c, _g, _n)	((_c) * RACK_CLASS_DVDR +	\
+	(_g) * RACK_GROUP_DVDR + (_n) * RACK_NUM_DVDR)
+
+#define RACK_GET_CLASS(_r)              ((_r) / RACK_CLASS_DVDR)
+#define RACK_GET_GROUP(_r)              (((_r) - RACK_GET_CLASS(_r) *   \
+            RACK_CLASS_DVDR) / RACK_GROUP_DVDR)
+#define RACK_GET_NUM(_r)                (((_r) - RACK_GET_CLASS(_r) *   \
+            RACK_CLASS_DVDR - RACK_GET_GROUP(_r) *      \
+            RACK_GROUP_DVDR) / RACK_NUM_DVDR)
+
+/*
+ * Macros for encoding and decoding rack IDs
+ * A rack number consists of three parts:
+ *   class	1 bit, 0==CPU/mixed, 1==I/O
+ *   group	2 bits for CPU/mixed, 3 bits for I/O
+ *   number	3 bits for CPU/mixed, 2 bits for I/O (1 based)
+ */
+#define RACK_GROUP_BITS(_r)	(RACK_GET_CLASS(_r) ? 3 : 2)
+#define RACK_NUM_BITS(_r)	(RACK_GET_CLASS(_r) ? 2 : 3)
+
+#define RACK_CLASS_MASK(_r)	0x20
+#define RACK_CLASS_SHFT(_r)	5
+#define RACK_ADD_CLASS(_r, _c)	\
+	((_r) |= (_c) << RACK_CLASS_SHFT(_r) & RACK_CLASS_MASK(_r))
+
+#define RACK_GROUP_SHFT(_r)	RACK_NUM_BITS(_r)
+#define RACK_GROUP_MASK(_r)	\
+	( (((unsigned)1<<RACK_GROUP_BITS(_r)) - 1) << RACK_GROUP_SHFT(_r) )
+#define RACK_ADD_GROUP(_r, _g)	\
+	((_r) |= (_g) << RACK_GROUP_SHFT(_r) & RACK_GROUP_MASK(_r))
+
+#define RACK_NUM_SHFT(_r)	0
+#define RACK_NUM_MASK(_r)	\
+	( (((unsigned)1<<RACK_NUM_BITS(_r)) - 1) << RACK_NUM_SHFT(_r) )
+#define RACK_ADD_NUM(_r, _n)	\
+	((_r) |= ((_n) - 1) << RACK_NUM_SHFT(_r) & RACK_NUM_MASK(_r))
+
+
+/*
+ * Brick type definitions
+ */
+#define MAX_BRICK_TYPES         256 /* brick type is stored as uchar */
+
+extern char brick_types[];
+
+#define MODULE_CBRICK           0
+#define MODULE_RBRICK           1
+#define MODULE_IBRICK           2
+#define MODULE_KBRICK           3
+#define MODULE_XBRICK           4
+#define MODULE_DBRICK           5
+#define MODULE_PBRICK           6
+#define MODULE_NBRICK           7
+#define MODULE_PEBRICK          8
+#define MODULE_PXBRICK          9
+
+/*
+ * Moduleid_t comparison macros
+ */
+/* Don't compare the brick type:  only the position is significant */
+#define MODULE_CMP(_m1, _m2)    (((_m1)&(MODULE_RACK_MASK|MODULE_BPOS_MASK)) -\
+                                 ((_m2)&(MODULE_RACK_MASK|MODULE_BPOS_MASK)))
+#define MODULE_MATCH(_m1, _m2)  (MODULE_CMP((_m1),(_m2)) == 0)
+
+
+#else
+#if defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)
+
 /*
  *	Module id format
  *
@@ -116,6 +238,9 @@
 #define MODULE_XBRICK		4
 #define MODULE_DBRICK		5
 #define MODULE_PBRICK		6
+#define MODULE_NBRICK           7
+#define MODULE_PEBRICK          8
+#define MODULE_PXBRICK          9
 
 /*
  * Moduleid_t comparison macros
@@ -125,6 +250,18 @@
 				 ((_m2)&(MODULE_RACK_MASK|MODULE_BPOS_MASK)))
 #define MODULE_MATCH(_m1, _m2)	(MODULE_CMP((_m1),(_m2)) == 0)
 
+#else
+
+/*
+ * Some code that uses this macro will not be conditionally compiled.
+ */
+#define MODULE_GET_BTCHAR(_m)	('?')
+#define MODULE_CMP(_m1, _m2)	((_m1) - (_m2))
+#define MODULE_MATCH(_m1, _m2)	(MODULE_CMP((_m1),(_m2)) == 0)
+
+#endif /* SN1 */
+#endif /* SN2 */
+
 typedef struct module_s module_t;
 
 struct module_s {
@@ -134,6 +271,9 @@
 
     /* List of nodes in this module */
     cnodeid_t		nodes[MODULE_MAX_NODES];
+#ifdef CONFIG_IA64_SGI_SN2
+    geoid_t		geoid[MODULE_MAX_NODES];
+#endif
     int			nodecnt;	/* Number of nodes in array        */
 
     /* Fields for Module System Controller */
@@ -141,9 +281,10 @@
     int			shutdown;	/* Shutdown in progress            */
     struct semaphore	thdcnt;		/* Threads finished counter        */
 
+#ifdef CONFIG_IA64_SGI_SN1
     elsc_t		elsc;
     spinlock_t		elsclock;
-
+#endif
     time_t		intrhist[MODULE_HIST_CNT];
     int			histptr;
 
@@ -171,7 +312,9 @@
 
 extern module_t	       *module_lookup(moduleid_t id);
 
+#if defined(CONFIG_IA64_SGI_SN1)
 extern elsc_t	       *get_elsc(void);
+#endif
 
 extern int		get_kmod_info(cmoduleid_t cmod,
 				      module_info_t *mod_info);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/nag.h linux-2.4.21-pre6/include/asm-ia64/sn/nag.h
--- linux-2.4.20/include/asm-ia64/sn/nag.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/nag.h	2003-03-26 23:49:39.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (c) 2001 Silicon Graphics, Inc.  All rights reserved.
+ * Copyright (c) 2001-2002 Silicon Graphics, Inc.  All rights reserved.
 */
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/nodepda.h linux-2.4.21-pre6/include/asm-ia64/sn/nodepda.h
--- linux-2.4.20/include/asm-ia64/sn/nodepda.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/nodepda.h	2003-03-26 23:49:10.000000000 +0000
@@ -70,7 +70,11 @@
 	nasid_t		xbow_peer;	/* NASID of our peer hub on xbow */
 	struct semaphore xbow_sema;	/* Sema for xbow synchronization */
 	slotid_t	slotdesc;
+#ifdef CONFIG_IA64_SGI_SN2
+	geoid_t		geoid;
+#else
 	moduleid_t	module_id;	/* Module ID (redundant local copy) */
+#endif
 	module_t	*module;	/* Pointer to containing module */
 	xwidgetnum_t 	basew_id;
 	devfs_handle_t 	basew_xc;
@@ -91,7 +95,8 @@
 	/*
 	 * The BTEs on this node are shared by the local cpus
 	 */
-	bteinfo_t	node_bte_info[BTES_PER_NODE];
+	bteinfo_t	bte_if[BTES_PER_NODE];	/* Virtual Interface */
+	char		bte_cleanup[5 * L1_CACHE_BYTES] ____cacheline_aligned;
 
 #if defined(CONFIG_IA64_SGI_SN1)
 	subnode_pda_t	snpda[NUM_SUBNODES];
@@ -124,7 +129,7 @@
 #ifdef CONFIG_IA64_SGI_SN2
 struct irqpda_s {
 	int num_irq_used;
-	char irq_flags[NR_IRQS];
+	char irq_flags[NR_IVECS];
 };
 
 typedef struct irqpda_s irqpda_t;
@@ -160,7 +165,11 @@
 /*
  * Macros to access data structures inside nodepda 
  */
+#ifdef CONFIG_IA64_SGI_SN2
+#define NODE_MODULEID(cnode)    geo_module((NODEPDA(cnode)->geoid))
+#else
 #define NODE_MODULEID(cnode)	(NODEPDA(cnode)->module_id)
+#endif
 #define NODE_SLOTID(cnode)	(NODEPDA(cnode)->slotdesc)
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/pci/bridge.h linux-2.4.21-pre6/include/asm-ia64/sn/pci/bridge.h
--- linux-2.4.20/include/asm-ia64/sn/pci/bridge.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/pci/bridge.h	2003-03-26 23:49:10.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (c) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 #ifndef _ASM_SN_PCI_BRIDGE_H
 #define _ASM_SN_PCI_BRIDGE_H
@@ -12,9 +12,40 @@
 
 /*
  * bridge.h - header file for bridge chip and bridge portion of xbridge chip
+ *
+ * Also including offsets for unique PIC registers.
+ * The PIC asic is a follow-on to Xbridge and most of it's registers are
+ * identical to those of Xbridge.  PIC is different than Xbridge in that
+ * it will accept 64 bit register access and that, in some cases, data
+ * is kept in bits 63:32.   PIC registers that are identical to Xbridge
+ * may be accessed identically to the Xbridge registers, allowing for lots
+ * of code reuse.  Here are the access rules as described in the PIC
+ * manual:
+ * 
+ * 	o Read a word on a DW boundary returns D31:00 of reg.
+ * 	o Read a DW on a DW boundary returns D63:00 of reg.
+ * 	o Write a word on a DW boundary loads D31:00 of reg.
+ * 	o Write a DW on a DW boundary loads D63:00 of reg.
+ * 	o No support for word boundary access that is not double word
+ *           aligned.
+ * 
+ * So we can reuse a lot of bridge_s for PIC.  In bridge_s are included
+ * #define tags and unions for 64 bit access to PIC registers.
+ * For a detailed PIC register layout see pic.h.
  */
 
+#include <linux/config.h>
 #include <asm/sn/xtalk/xwidget.h>
+#ifndef CONFIG_IA64_SGI_SN1
+#include <asm/sn/pci/pic.h>
+
+extern int io_get_sh_swapper(nasid_t);
+#define BRIDGE_REG_GET32(reg) \
+                __swab32( *(volatile uint32_t *) (((uint64_t)reg)^4) )
+
+#define BRIDGE_REG_SET32(reg) \
+                *(volatile uint32_t *) (((uint64_t)reg)^4)
+#endif	/* CONFIG_IA64_SGI_SN1 */
 
 /* I/O page size */
 
@@ -36,6 +67,8 @@
 #define BRIDGE_ATE_RAM_SIZE     (BRIDGE_INTERNAL_ATES<<3)	/* 1kB ATE */
 #define XBRIDGE_ATE_RAM_SIZE    (XBRIDGE_INTERNAL_ATES<<3)	/* 8kB ATE */
 
+#define PIC_WR_REQ_BUFSIZE      256
+
 #define BRIDGE_CONFIG_BASE	0x20000		/* start of bridge's */
 						/* map to each device's */
 						/* config space */
@@ -78,7 +111,502 @@
  * Generated from Bridge spec dated 04oct95
  */
 
-#ifdef LITTLE_ENDIAN
+#ifndef CONFIG_IA64_SGI_SN1
+
+/*
+ * pic_widget_cfg_s is a local definition of widget_cfg_t but with
+ * a union of 64bit & 32bit registers, since PIC has 64bit widget
+ * registers but BRIDGE and XBRIDGE have 32bit.	 PIC registers that
+ * have valid bits (ie. not just reserved) in the upper 32bits are
+ * defined as a union so we can access them as 64bit for PIC and
+ * as 32bit for BRIDGE and XBRIDGE.
+ */ 
+typedef volatile struct pic_widget_cfg_s {
+    bridgereg_t		    _b_wid_id;		    /* 0x000004 */
+    bridgereg_t		    _pad_000000;
+
+    union {
+	picreg_t	    _p_wid_stat;	    /* 0x000008 */
+	struct {
+	    bridgereg_t	    _b_wid_stat;	    /* 0x00000C */
+	    bridgereg_t	    _b_pad_000008;
+	} _b;
+    } u_wid_stat;
+    #define __p_wid_stat_64 u_wid_stat._p_wid_stat
+    #define __b_wid_stat u_wid_stat._b._b_wid_stat
+
+    bridgereg_t		    _b_wid_err_upper;	    /* 0x000014 */
+    bridgereg_t		    _pad_000010;
+
+    union {
+	picreg_t	    _p_wid_err_lower;	    /* 0x000018 */
+	struct {
+	    bridgereg_t	    _b_wid_err_lower;	    /* 0x00001C */
+	    bridgereg_t	    _b_pad_000018;
+	} _b;
+    } u_wid_err_lower;
+    #define __p_wid_err_64 u_wid_err_lower._p_wid_err_lower
+    #define __b_wid_err_lower u_wid_err_lower._b._b_wid_err_lower
+
+    union {
+	picreg_t	    _p_wid_control;	    /* 0x000020 */
+	struct {
+	    bridgereg_t	    _b_wid_control;	    /* 0x000024 */
+	    bridgereg_t	    _b_pad_000020;
+	} _b;
+    } u_wid_control;
+    #define __p_wid_control_64 u_wid_control._p_wid_control
+    #define __b_wid_control u_wid_control._b._b_wid_control
+
+    bridgereg_t		    _b_wid_req_timeout;	    /* 0x00002C */
+    bridgereg_t		    _pad_000028;
+
+    bridgereg_t		    _b_wid_int_upper;	    /* 0x000034 */
+    bridgereg_t		    _pad_000030;
+
+    union {
+	picreg_t	    _p_wid_int_lower;	    /* 0x000038 */
+	struct {
+	    bridgereg_t	    _b_wid_int_lower;	    /* 0x00003C */
+	    bridgereg_t	    _b_pad_000038;
+	} _b;
+    } u_wid_int_lower;
+    #define __p_wid_int_64 u_wid_int_lower._p_wid_int_lower
+    #define __b_wid_int_lower u_wid_int_lower._b._b_wid_int_lower
+
+    bridgereg_t		    _b_wid_err_cmdword;	    /* 0x000044 */
+    bridgereg_t		    _pad_000040;
+
+    bridgereg_t		    _b_wid_llp;		    /* 0x00004C */
+    bridgereg_t		    _pad_000048;
+
+    bridgereg_t		    _b_wid_tflush;	    /* 0x000054 */
+    bridgereg_t		    _pad_000050;
+} pic_widget_cfg_t;
+
+/*
+ * BRIDGE, XBRIDGE, PIC register definitions.  NOTE: Prior to PIC, registers
+ * were a 32bit quantity and double word aligned (and only accessable as a
+ * 32bit word.  PIC registers are 64bits and accessable as words or double
+ * words.  PIC registers that have valid bits (ie. not just reserved) in the
+ * upper 32bits are defined as a union of one 64bit picreg_t and two 32bit
+ * bridgereg_t so we can access them both ways.
+ *
+ * It is generally preferred that hardware registers on the bridge are
+ * located from C code via this structure.
+ *
+ * Generated from Bridge spec dated 04oct95
+ */
+
+typedef volatile struct bridge_s {
+
+    /* 0x000000-0x00FFFF -- Local Registers */
+
+    /* 0x000000-0x000057 -- Standard Widget Configuration */
+    union {
+	widget_cfg_t	    xtalk_widget_def;	    /* 0x000000 */
+	pic_widget_cfg_t    local_widget_def;	    /* 0x000000 */
+    } u_wid;
+
+    /* 32bit widget register access via the widget_cfg_t */
+    #define b_widget u_wid.xtalk_widget_def
+
+    /* 32bit widget register access via the pic_widget_cfg_t */
+    #define b_wid_id u_wid.local_widget_def._b_wid_id
+    #define b_wid_stat u_wid.local_widget_def.__b_wid_stat
+    #define b_wid_err_upper u_wid.local_widget_def._b_wid_err_upper
+    #define b_wid_err_lower u_wid.local_widget_def.__b_wid_err_lower
+    #define b_wid_control u_wid.local_widget_def.__b_wid_control
+    #define b_wid_req_timeout u_wid.local_widget_def._b_wid_req_timeout
+    #define b_wid_int_upper u_wid.local_widget_def._b_wid_int_upper
+    #define b_wid_int_lower u_wid.local_widget_def.__b_wid_int_lower
+    #define b_wid_err_cmdword u_wid.local_widget_def._b_wid_err_cmdword
+    #define b_wid_llp u_wid.local_widget_def._b_wid_llp
+    #define b_wid_tflush u_wid.local_widget_def._b_wid_tflush
+
+    /* 64bit widget register access via the pic_widget_cfg_t */
+    #define p_wid_stat_64 u_wid.local_widget_def.__p_wid_stat_64
+    #define p_wid_err_64 u_wid.local_widget_def.__p_wid_err_64
+    #define p_wid_control_64 u_wid.local_widget_def.__p_wid_control_64
+    #define p_wid_int_64 u_wid.local_widget_def.__p_wid_int_64
+
+    /* 0x000058-0x00007F -- Bridge-specific Widget Configuration */
+    bridgereg_t             b_wid_aux_err;          /* 0x00005C */
+    bridgereg_t             _pad_000058;
+
+    bridgereg_t             b_wid_resp_upper;       /* 0x000064 */
+    bridgereg_t             _pad_000060;
+
+    union {
+        picreg_t            _p_wid_resp_lower;      /* 0x000068 */
+        struct {
+            bridgereg_t     _b_wid_resp_lower;      /* 0x00006C */
+            bridgereg_t     _b_pad_000068;
+        } _b;
+    } u_wid_resp_lower;
+    #define p_wid_resp_64 u_wid_resp_lower._p_wid_resp_lower
+    #define b_wid_resp_lower u_wid_resp_lower._b._b_wid_resp_lower
+
+    bridgereg_t             b_wid_tst_pin_ctrl;     /* 0x000074 */
+    bridgereg_t             _pad_000070;
+
+    union {
+        picreg_t            _p_addr_lkerr;          /* 0x000078 */
+        struct {
+            bridgereg_t     _b_pad_00007C;
+            bridgereg_t     _b_pad_000078;
+        } _b;
+    } u_addr_lkerr;
+    #define p_addr_lkerr_64 u_addr_lkerr._p_addr_lkerr
+
+    /* 0x000080-0x00008F -- PMU */
+    bridgereg_t		    b_dir_map;		    /* 0x000084 */
+    bridgereg_t		    _pad_000080;
+
+    bridgereg_t		    _pad_00008C;
+    bridgereg_t		    _pad_000088;
+
+    /* 0x000090-0x00009F -- SSRAM */
+    bridgereg_t             b_ram_perr_or_map_fault;/* 0x000094 */
+    bridgereg_t		    _pad_000090;
+    #define b_ram_perr  b_ram_perr_or_map_fault     /* Bridge */
+    #define b_map_fault b_ram_perr_or_map_fault     /* Xbridge & PIC */
+
+    bridgereg_t		    _pad_00009C;
+    bridgereg_t		    _pad_000098;
+
+    /* 0x0000A0-0x0000AF -- Arbitration */
+    bridgereg_t		    b_arb;		    /* 0x0000A4 */
+    bridgereg_t		    _pad_0000A0;
+
+    bridgereg_t		    _pad_0000AC;
+    bridgereg_t		    _pad_0000A8;
+
+    /* 0x0000B0-0x0000BF -- Number In A Can or ATE Parity Error */
+    union {
+	picreg_t	    _p_ate_parity_err;	    /* 0x0000B0 */
+	struct {
+	    bridgereg_t	    _b_nic;		    /* 0x0000B4 */
+	    bridgereg_t	    _b_pad_0000B0;
+	} _b;
+    } u_ate_parity_err_or_nic;
+    #define p_ate_parity_err_64 u_ate_parity_err_or_nic._p_ate_parity_err
+    #define b_nic u_ate_parity_err_or_nic._b._b_nic
+
+    bridgereg_t		    _pad_0000BC;
+    bridgereg_t		    _pad_0000B8;
+
+    /* 0x0000C0-0x0000FF -- PCI/GIO */
+    bridgereg_t		    b_bus_timeout;	    /* 0x0000C4 */
+    bridgereg_t		    _pad_0000C0;
+    #define b_pci_bus_timeout b_bus_timeout
+
+    bridgereg_t		    b_pci_cfg;		    /* 0x0000CC */
+    bridgereg_t		    _pad_0000C8;
+
+    bridgereg_t		    b_pci_err_upper;	    /* 0x0000D4 */
+    bridgereg_t		    _pad_0000D0;
+    #define b_gio_err_upper b_pci_err_upper
+
+    union {
+	picreg_t	    _p_pci_err_lower;	    /* 0x0000D8 */
+	struct {
+	    bridgereg_t	    _b_pci_err_lower;	    /* 0x0000DC */
+	    bridgereg_t	    _b_pad_0000D8;
+	} _b;
+    } u_pci_err_lower;
+    #define p_pci_err_64 u_pci_err_lower._p_pci_err_lower
+    #define b_pci_err_lower u_pci_err_lower._b._b_pci_err_lower
+    #define b_gio_err_lower b_pci_err_lower
+
+    bridgereg_t		    _pad_0000E0[8];
+
+    /* 0x000100-0x0001FF -- Interrupt */
+    union {
+	picreg_t	    _p_int_status;	    /* 0x000100 */		
+	struct {
+	    bridgereg_t	    _b_int_status;	    /* 0x000104 */
+	    bridgereg_t	    _b_pad_000100;
+	} _b;
+    } u_int_status;
+    #define p_int_status_64 u_int_status._p_int_status
+    #define b_int_status u_int_status._b._b_int_status
+
+    union {
+	picreg_t	    _p_int_enable;	    /* 0x000108 */		
+	struct {
+	    bridgereg_t	    _b_int_enable;	    /* 0x00010C */
+	    bridgereg_t	    _b_pad_000108;
+	} _b;
+    } u_int_enable;
+    #define p_int_enable_64 u_int_enable._p_int_enable
+    #define b_int_enable u_int_enable._b._b_int_enable
+
+    union {
+	picreg_t	    _p_int_rst_stat;	    /* 0x000110 */		
+	struct {
+	    bridgereg_t	    _b_int_rst_stat;	    /* 0x000114 */
+	    bridgereg_t	    _b_pad_000110;
+	} _b;
+    } u_int_rst_stat;
+    #define p_int_rst_stat_64 u_int_rst_stat._p_int_rst_stat
+    #define b_int_rst_stat u_int_rst_stat._b._b_int_rst_stat
+
+    bridgereg_t		    b_int_mode;		    /* 0x00011C */
+    bridgereg_t		    _pad_000118;
+
+    bridgereg_t		    b_int_device;	    /* 0x000124 */
+    bridgereg_t		    _pad_000120;
+
+    bridgereg_t		    b_int_host_err;	    /* 0x00012C */
+    bridgereg_t		    _pad_000128;
+
+    union {
+	picreg_t	    _p_int_addr[8];	    /* 0x0001{30,,,68} */
+	struct {
+	    bridgereg_t	    addr;		    /* 0x0001{34,,,6C} */
+	    bridgereg_t	    _b_pad;
+	} _b[8];
+    } u_int_addr;
+    #define p_int_addr_64 u_int_addr._p_int_addr
+    #define b_int_addr u_int_addr._b
+
+    union {
+	picreg_t	    _p_err_int_view;	    /* 0x000170 */
+	struct {
+	    bridgereg_t	    _b_err_int_view;	    /* 0x000174 */
+	    bridgereg_t	    _b_pad_000170;
+	} _b;
+    } u_err_int_view;
+    #define p_err_int_view_64 u_err_int_view._p_err_int_view
+    #define b_err_int_view u_err_int_view._b._b_err_int_view
+
+    union {
+	picreg_t	    _p_mult_int;	    /* 0x000178 */
+	struct {
+	    bridgereg_t	    _b_mult_int;	    /* 0x00017C */
+	    bridgereg_t	    _b_pad_000178;
+	} _b;
+    } u_mult_int;
+    #define p_mult_int_64 u_mult_int._p_mult_int
+    #define b_mult_int u_mult_int._b._b_mult_int
+
+    struct {
+	bridgereg_t	    intr;		    /* 0x0001{84,,,BC} */
+	bridgereg_t	    __pad;
+    } b_force_always[8];
+
+    struct {
+	bridgereg_t	    intr;		    /* 0x0001{C4,,,FC} */
+	bridgereg_t	    __pad;
+    } b_force_pin[8];
+
+    /* 0x000200-0x0003FF -- Device */
+    struct {
+	bridgereg_t	    reg;		    /* 0x0002{04,,,3C} */
+	bridgereg_t	    __pad;
+    } b_device[8];
+
+    struct {
+	bridgereg_t	    reg;		    /* 0x0002{44,,,7C} */
+	bridgereg_t	    __pad;
+    } b_wr_req_buf[8];
+
+    struct {
+	bridgereg_t	    reg;		    /* 0x0002{84,,,8C} */
+	bridgereg_t	    __pad;
+    } b_rrb_map[2];
+    #define b_even_resp	b_rrb_map[0].reg	    /* 0x000284 */
+    #define b_odd_resp	b_rrb_map[1].reg	    /* 0x00028C */
+
+    bridgereg_t		    b_resp_status;	    /* 0x000294 */
+    bridgereg_t		    _pad_000290;
+
+    bridgereg_t		    b_resp_clear;	    /* 0x00029C */
+    bridgereg_t		    _pad_000298;
+
+    bridgereg_t		    _pad_0002A0[24];
+
+    /* Xbridge/PIC only */
+    union {
+	struct {
+	    picreg_t	    lower;		    /* 0x0003{08,,,F8} */
+	    picreg_t	    upper;		    /* 0x0003{00,,,F0} */
+	} _p[16];
+	struct {
+	    bridgereg_t	    upper;		    /* 0x0003{04,,,F4} */
+	    bridgereg_t	    _b_pad1;
+	    bridgereg_t	    lower;		    /* 0x0003{0C,,,FC} */
+	    bridgereg_t	    _b_pad2;
+	} _b[16];
+    } u_buf_addr_match;
+    #define p_buf_addr_match_64 u_buf_addr_match._p
+    #define b_buf_addr_match u_buf_addr_match._b
+
+    /* 0x000400-0x0005FF -- Performance Monitor Registers (even only) */
+    struct {
+	bridgereg_t	    flush_w_touch;	    /* 0x000{404,,,5C4} */
+	bridgereg_t	    __pad1;
+	bridgereg_t	    flush_wo_touch;	    /* 0x000{40C,,,5CC} */
+	bridgereg_t	    __pad2;
+	bridgereg_t	    inflight;		    /* 0x000{414,,,5D4} */
+	bridgereg_t	    __pad3;
+	bridgereg_t	    prefetch;		    /* 0x000{41C,,,5DC} */
+	bridgereg_t	    __pad4;
+	bridgereg_t	    total_pci_retry;	    /* 0x000{424,,,5E4} */
+	bridgereg_t	    __pad5;
+	bridgereg_t	    max_pci_retry;	    /* 0x000{42C,,,5EC} */
+	bridgereg_t	    __pad6;
+	bridgereg_t	    max_latency;	    /* 0x000{434,,,5F4} */
+	bridgereg_t	    __pad7;
+	bridgereg_t	    clear_all;		    /* 0x000{43C,,,5FC} */
+	bridgereg_t	    __pad8;
+    } b_buf_count[8];
+
+    /*
+     * "PCI/X registers that are specific to PIC".   See pic.h.
+     */
+
+    /* 0x000600-0x0009FF -- PCI/X registers */
+    picreg_t		    p_pcix_bus_err_addr_64;     /* 0x000600 */
+    picreg_t		    p_pcix_bus_err_attr_64;     /* 0x000608 */
+    picreg_t		    p_pcix_bus_err_data_64;     /* 0x000610 */
+    picreg_t		    p_pcix_pio_split_addr_64;	/* 0x000618 */
+    picreg_t		    p_pcix_pio_split_attr_64;	/* 0x000620 */
+    picreg_t		    p_pcix_dma_req_err_attr_64; /* 0x000628 */
+    picreg_t		    p_pcix_dma_req_err_addr_64;	/* 0x000630 */
+    picreg_t		    p_pcix_timeout_64;		/* 0x000638 */
+
+    picreg_t		    _pad_000600[120];
+
+    /* 0x000A00-0x000BFF -- PCI/X Read&Write Buffer */
+    struct {
+    	picreg_t	    p_buf_attr;		    /* 0X000{A08,,,AF8} */
+    	picreg_t	    p_buf_addr;		    /* 0x000{A00,,,AF0} */
+    } p_pcix_read_buf_64[16];
+
+    struct {
+	picreg_t	    p_buf_attr;		    /* 0x000{B08,,,BE8} */
+	picreg_t	    p_buf_addr;		    /* 0x000{B00,,,BE0} */
+	picreg_t	    __pad1;		    /* 0x000{B18,,,BF8} */
+	picreg_t	    p_buf_valid;	    /* 0x000{B10,,,BF0} */
+    } p_pcix_write_buf_64[8];
+
+    /* 
+     * end "PCI/X registers that are specific to PIC"
+     */
+
+    char		    _pad_000c00[0x010000 - 0x000c00];
+
+    /* 0x010000-0x011fff -- Internal Address Translation Entry RAM */
+    /*
+     * Xbridge and PIC have 1024 internal ATE's and the Bridge has 128.
+     * Make enough room for the Xbridge/PIC ATE's and depend on runtime
+     * checks to limit access to bridge ATE's.
+     *
+     * In [X]bridge the internal ATE Ram is writen as double words only,
+     * but due to internal design issues it is read back as single words. 
+     * i.e:
+     *   b_int_ate_ram[index].hi.rd << 32 | xb_int_ate_ram_lo[index].rd
+     */
+    union {
+	bridge_ate_t	    wr;	/* write-only */    /* 0x01{0000,,,1FF8} */
+	struct {
+	    bridgereg_t	    rd; /* read-only */     /* 0x01{0004,,,1FFC} */
+	    bridgereg_t	    _p_pad;
+	} hi;
+    } b_int_ate_ram[XBRIDGE_INTERNAL_ATES];
+    #define b_int_ate_ram_lo(idx) b_int_ate_ram[idx+512].hi.rd
+
+    /* 0x012000-0x013fff -- Internal Address Translation Entry RAM LOW */
+    struct {
+	bridgereg_t	    rd; /* read-only */	    /* 0x01{2004,,,3FFC} */
+	bridgereg_t	    _p_pad;
+    } xb_int_ate_ram_lo[XBRIDGE_INTERNAL_ATES];
+
+    char		    _pad_014000[0x18000 - 0x014000];
+
+    /* 0x18000-0x197F8 -- PIC Write Request Ram */
+				/* 0x18000 - 0x187F8 */
+    picreg_t		    p_wr_req_lower[PIC_WR_REQ_BUFSIZE];
+				/* 0x18800 - 0x18FF8 */
+    picreg_t		    p_wr_req_upper[PIC_WR_REQ_BUFSIZE];
+				/* 0x19000 - 0x197F8 */
+    picreg_t		    p_wr_req_parity[PIC_WR_REQ_BUFSIZE];
+
+    char		    _pad_019800[0x20000 - 0x019800];
+
+    /* 0x020000-0x027FFF -- PCI Device Configuration Spaces */
+    union {				/* make all access sizes available. */
+	uchar_t		    c[0x1000 / 1];	    /* 0x02{0000,,,7FFF} */
+	uint16_t	    s[0x1000 / 2];	    /* 0x02{0000,,,7FFF} */
+	uint32_t	    l[0x1000 / 4];	    /* 0x02{0000,,,7FFF} */
+	uint64_t	    d[0x1000 / 8];	    /* 0x02{0000,,,7FFF} */
+	union {
+	    uchar_t	    c[0x100 / 1];
+	    uint16_t	    s[0x100 / 2];
+	    uint32_t	    l[0x100 / 4];
+	    uint64_t	    d[0x100 / 8];
+	} f[8];
+    } b_type0_cfg_dev[8];			    /* 0x02{0000,,,7FFF} */
+
+    /* 0x028000-0x028FFF -- PCI Type 1 Configuration Space */
+    union {				/* make all access sizes available. */
+	uchar_t		    c[0x1000 / 1];
+	uint16_t	    s[0x1000 / 2];
+	uint32_t	    l[0x1000 / 4];
+	uint64_t	    d[0x1000 / 8];
+        union {
+            uchar_t         c[0x100 / 1];
+            uint16_t        s[0x100 / 2];
+            uint32_t        l[0x100 / 4];
+            uint64_t        d[0x100 / 8];
+	} f[8];
+    } b_type1_cfg;				    /* 0x028000-0x029000 */
+
+    char		    _pad_029000[0x007000];  /* 0x029000-0x030000 */
+
+    /* 0x030000-0x030007 -- PCI Interrupt Acknowledge Cycle */
+    union {
+	uchar_t		    c[8 / 1];
+	uint16_t	    s[8 / 2];
+	uint32_t	    l[8 / 4];
+	uint64_t	    d[8 / 8];
+    } b_pci_iack;				    /* 0x030000-0x030007 */
+
+    uchar_t		    _pad_030007[0x04fff8];  /* 0x030008-0x07FFFF */
+
+    /* 0x080000-0x0FFFFF -- External Address Translation Entry RAM */
+    bridge_ate_t	    b_ext_ate_ram[0x10000];
+
+    /* 0x100000-0x1FFFFF -- Reserved */
+    char		    _pad_100000[0x200000-0x100000];
+
+    /* 0x200000-0xBFFFFF -- PCI/GIO Device Spaces */
+    union {				/* make all access sizes available. */
+	uchar_t		    c[0x100000 / 1];
+	uint16_t	    s[0x100000 / 2];
+	uint32_t	    l[0x100000 / 4];
+	uint64_t	    d[0x100000 / 8];
+    } b_devio_raw[10];
+
+    /* b_devio macro is a bit strange; it reflects the
+     * fact that the Bridge ASIC provides 2M for the
+     * first two DevIO windows and 1M for the other six.
+     */
+    #define b_devio(n)	b_devio_raw[((n)<2)?(n*2):(n+2)]
+
+    /* 0xC00000-0xFFFFFF -- External Flash Proms 1,0 */
+    union {				/* make all access sizes available. */
+	uchar_t		    c[0x400000 / 1];	/* read-only */
+	uint16_t	    s[0x400000 / 2];	/* read-write */
+	uint32_t	    l[0x400000 / 4];	/* read-only */
+	uint64_t	    d[0x400000 / 8];	/* read-only */
+    } b_external_flash;
+} bridge_t;
+
+#else	/* CONFIG_IA64_SGI_SN1 */
+
 
 typedef volatile struct bridge_s {
 
@@ -311,6 +839,12 @@
 	uint16_t		s[0x1000 / 2];
 	uint32_t		l[0x1000 / 4];
 	uint64_t		d[0x1000 / 8];
+        union {
+            uchar_t         c[0x100 / 1];
+            uint16_t        s[0x100 / 2];
+            uint32_t        l[0x100 / 4];
+            uint64_t        d[0x100 / 8];
+	} f[8];
     } b_type1_cfg;				    /* 0x028000-0x029000 */
 
     char		    _pad_029000[0x007000];  /* 0x029000-0x030000 */
@@ -354,286 +888,7 @@
     } b_external_flash;			/* 0xC00000 */
 } bridge_t;
 
-#else
-
-/*
- * Field formats for Error Command Word and Auxillary Error Command Word
- * of bridge.
- */
-typedef struct bridge_err_cmdword_s {
-    union {
-	uint32_t		cmd_word;
-	struct {
-	    uint32_t		    didn:4,	/* Destination ID */
-				    sidn:4,	/* SOurce ID	  */
-				    pactyp:4,	/* Packet type	  */
-				    tnum:5,	/* Trans Number	  */
-				    coh:1,	/* Coh Transacti  */
-				    ds:2,	/* Data size	  */
-				    gbr:1,	/* GBR enable	  */
-				    vbpm:1,	/* VBPM message	  */
-				    error:1,	/* Error occurred */
-				    barr:1,	/* Barrier op	  */
-				    rsvd:8;
-	} berr_st;
-    } berr_un;
-} bridge_err_cmdword_t;
-
-typedef volatile struct bridge_s {
-
-    /* Local Registers                                 0x000000-0x00FFFF */
-
-    /* standard widget configuration                   0x000000-0x000057 */
-    widget_cfg_t            b_widget;               /* 0x000000 */
-
-    /* helper fieldnames for accessing bridge widget */
-
-#define b_wid_id                        b_widget.w_id
-#define b_wid_stat                      b_widget.w_status
-#define b_wid_err_upper                 b_widget.w_err_upper_addr
-#define b_wid_err_lower                 b_widget.w_err_lower_addr
-#define b_wid_control                   b_widget.w_control
-#define b_wid_req_timeout               b_widget.w_req_timeout
-#define b_wid_int_upper                 b_widget.w_intdest_upper_addr
-#define b_wid_int_lower                 b_widget.w_intdest_lower_addr
-#define b_wid_err_cmdword               b_widget.w_err_cmd_word
-#define b_wid_llp                       b_widget.w_llp_cfg
-#define b_wid_tflush                    b_widget.w_tflush
-
-    /* bridge-specific widget configuration            0x000058-0x00007F */
-    bridgereg_t             _pad_000058;
-    bridgereg_t             b_wid_aux_err;          /* 0x00005C */
-    bridgereg_t             _pad_000060;
-    bridgereg_t             b_wid_resp_upper;       /* 0x000064 */
-    bridgereg_t             _pad_000068;
-    bridgereg_t             b_wid_resp_lower;       /* 0x00006C */
-    bridgereg_t             _pad_000070;
-    bridgereg_t             b_wid_tst_pin_ctrl;     /* 0x000074 */
-    bridgereg_t             _pad_000078[2];
-
-    /* PMU & Map                                       0x000080-0x00008F */
-    bridgereg_t             _pad_000080;
-    bridgereg_t             b_dir_map;              /* 0x000084 */
-    bridgereg_t             _pad_000088[2];
-
-    /* SSRAM                                           0x000090-0x00009F */
-    bridgereg_t             _pad_000090;
-    bridgereg_t             b_ram_perr_or_map_fault;/* 0x000094 */
-#define b_ram_perr  b_ram_perr_or_map_fault     /* Bridge */
-#define b_map_fault b_ram_perr_or_map_fault     /* Xbridge */
-    bridgereg_t             _pad_000098[2];
-
-    /* Arbitration                                     0x0000A0-0x0000AF */
-    bridgereg_t             _pad_0000A0;
-    bridgereg_t             b_arb;                  /* 0x0000A4 */
-    bridgereg_t             _pad_0000A8[2];
-
-    /* Number In A Can                                 0x0000B0-0x0000BF */
-    bridgereg_t             _pad_0000B0;
-    bridgereg_t             b_nic;                  /* 0x0000B4 */
-    bridgereg_t             _pad_0000B8[2];
-
-    /* PCI/GIO                                         0x0000C0-0x0000FF */
-    bridgereg_t             _pad_0000C0;
-    bridgereg_t             b_bus_timeout;          /* 0x0000C4 */
-#define b_pci_bus_timeout b_bus_timeout
-
-    bridgereg_t             _pad_0000C8;
-    bridgereg_t             b_pci_cfg;              /* 0x0000CC */
-    bridgereg_t             _pad_0000D0;
-    bridgereg_t             b_pci_err_upper;        /* 0x0000D4 */
-    bridgereg_t             _pad_0000D8;
-    bridgereg_t             b_pci_err_lower;        /* 0x0000DC */
-    bridgereg_t             _pad_0000E0[8];
-#define b_gio_err_lower b_pci_err_lower
-#define b_gio_err_upper b_pci_err_upper
-
-    /* Interrupt                                       0x000100-0x0001FF */
-    bridgereg_t             _pad_000100;
-    bridgereg_t             b_int_status;           /* 0x000104 */
-    bridgereg_t             _pad_000108;
-    bridgereg_t             b_int_enable;           /* 0x00010C */
-    bridgereg_t             _pad_000110;
-    bridgereg_t             b_int_rst_stat;         /* 0x000114 */
-    bridgereg_t             _pad_000118;
-    bridgereg_t             b_int_mode;             /* 0x00011C */
-    bridgereg_t             _pad_000120;
-    bridgereg_t             b_int_device;           /* 0x000124 */
-    bridgereg_t             _pad_000128;
-    bridgereg_t             b_int_host_err;         /* 0x00012C */
-
-    struct {
-        bridgereg_t             __pad;              /* 0x0001{30,,,68} */
-        bridgereg_t             addr;               /* 0x0001{34,,,6C} */
-    } b_int_addr[8];                                /* 0x000130 */
-
-    bridgereg_t             _pad_000170;
-    bridgereg_t             b_err_int_view;         /* 0x000174 */
-    bridgereg_t             _pad_000178;
-    bridgereg_t             b_mult_int;             /* 0x00017c */
-
-    struct {
-        bridgereg_t             __pad;              /* 0x0001{80,,,B8} */
-        bridgereg_t             intr;               /* 0x0001{84,,,BC} */
-    } b_force_always[8];                            /* 0x000180 */
-
-    struct {
-        bridgereg_t             __pad;              /* 0x0001{C0,,,F8} */
-        bridgereg_t             intr;               /* 0x0001{C4,,,FC} */
-    } b_force_pin[8];                               /* 0x0001C0 */
-
-    /* Device                                          0x000200-0x0003FF */
-    struct {
-        bridgereg_t             __pad;              /* 0x0002{00,,,38} */
-        bridgereg_t             reg;                /* 0x0002{04,,,3C} */
-    } b_device[8];                                  /* 0x000200 */
-
-    struct {
-        bridgereg_t             __pad;              /* 0x0002{40,,,78} */
-        bridgereg_t             reg;                /* 0x0002{44,,,7C} */
-    } b_wr_req_buf[8];                              /* 0x000240 */
-
-    struct {
-        bridgereg_t             __pad;              /* 0x0002{80,,,88} */
-        bridgereg_t             reg;                /* 0x0002{84,,,8C} */
-    } b_rrb_map[2];                                 /* 0x000280 */
-#define b_even_resp     b_rrb_map[0].reg            /* 0x000284 */
-#define b_odd_resp      b_rrb_map[1].reg            /* 0x00028C */
-
-    bridgereg_t             _pad_000290;
-    bridgereg_t             b_resp_status;          /* 0x000294 */
-    bridgereg_t             _pad_000298;
-    bridgereg_t             b_resp_clear;           /* 0x00029C */
-
-    bridgereg_t             _pad_0002A0[24];
-
-    /* Xbridge only */
-    struct {
-        bridgereg_t             __pad1;             /* 0x0003{00,,,F0} */
-        bridgereg_t             upper;              /* 0x0003{04,,,F4} */
-        bridgereg_t             __pad2;             /* 0x0003{08,,,F8} */
-        bridgereg_t             lower;              /* 0x0003{0C,,,FC} */
-    } b_buf_addr_match[16];
-
-    /* Performance Monitor Registers (even only) */
-    struct {
-        bridgereg_t             __pad1;             /* 0x000400,,,5C0 */
-        bridgereg_t             flush_w_touch;      /* 0x000404,,,5C4 */
-        bridgereg_t             __pad2;             /* 0x000408,,,5C8 */
-        bridgereg_t             flush_wo_touch;     /* 0x00040C,,,5CC */
-        bridgereg_t             __pad3;             /* 0x000410,,,5D0 */
-        bridgereg_t             inflight;           /* 0x000414,,,5D4 */
-        bridgereg_t             __pad4;             /* 0x000418,,,5D8 */
-        bridgereg_t             prefetch;           /* 0x00041C,,,5DC */
-        bridgereg_t             __pad5;             /* 0x000420,,,5E0 */
-        bridgereg_t             total_pci_retry;    /* 0x000424,,,5E4 */
-        bridgereg_t             __pad6;             /* 0x000428,,,5E8 */
-        bridgereg_t             max_pci_retry;      /* 0x00042C,,,5EC */
-        bridgereg_t             __pad7;             /* 0x000430,,,5F0 */
-        bridgereg_t             max_latency;        /* 0x000434,,,5F4 */
-        bridgereg_t             __pad8;             /* 0x000438,,,5F8 */
-        bridgereg_t             clear_all;          /* 0x00043C,,,5FC */
-    } b_buf_count[8];
-
-    char                    _pad_000600[0x010000 - 0x000600];
-
-    /*
-     * The Xbridge has 1024 internal ATE's and the Bridge has 128.
-     * Make enough room for the Xbridge ATE's and depend on runtime
-     * checks to limit access to bridge ATE's.
-     */
-
-    /* Internal Address Translation Entry RAM          0x010000-0x011fff */
-    union {
-        bridge_ate_t            wr;             /* write-only */
-        struct {
-            bridgereg_t             _p_pad;
-            bridgereg_t             rd;         /* read-only */
-        }                       hi;
-    }                       b_int_ate_ram[XBRIDGE_INTERNAL_ATES];
-
-#define b_int_ate_ram_lo(idx) b_int_ate_ram[idx+512].hi.rd
-
-    /* the xbridge read path for internal ates starts at 0x12000.
-     * I don't believe we ever try to read the ates.
-     */
-    /* Internal Address Translation Entry RAM LOW       0x012000-0x013fff */
-    struct {
-        bridgereg_t             _p_pad;
-        bridgereg_t             rd;             /* read-only */
-    }                       xb_int_ate_ram_lo[XBRIDGE_INTERNAL_ATES];
-
-    char                    _pad_014000[0x20000 - 0x014000];
-
-    /* PCI Device Configuration Spaces                 0x020000-0x027FFF */
-    union {                             /* make all access sizes available. */
-        uchar_t                 c[0x1000 / 1];
-        uint16_t                s[0x1000 / 2];
-        uint32_t              l[0x1000 / 4];
-        uint64_t              d[0x1000 / 8];
-        union {
-            uchar_t             c[0x100 / 1];
-            uint16_t            s[0x100 / 2];
-            uint32_t          l[0x100 / 4];
-            uint64_t          d[0x100 / 8];
-        }                       f[8];
-    } b_type0_cfg_dev[8];                           /* 0x020000 */
-
-
-    /* PCI Type 1 Configuration Space                  0x028000-0x028FFF */
-    union {                             /* make all access sizes available. */
-        uchar_t                 c[0x1000 / 1];
-        uint16_t                s[0x1000 / 2];
-        uint32_t              l[0x1000 / 4];
-        uint64_t              d[0x1000 / 8];
-    } b_type1_cfg;                                  /* 0x028000-0x029000 */
-
-    char                    _pad_029000[0x007000];  /* 0x029000-0x030000 */
-
-    /* PCI Interrupt Acknowledge Cycle                 0x030000 */
-    union {
-        uchar_t                 c[8 / 1];
-        uint16_t                s[8 / 2];
-        uint32_t              l[8 / 4];
-        uint64_t              d[8 / 8];
-    } b_pci_iack;                                   /* 0x030000 */
-
-    uchar_t                 _pad_030007[0x04fff8];  /* 0x030008-0x07FFFF */
-
-    /* External Address Translation Entry RAM          0x080000-0x0FFFFF */
-    bridge_ate_t            b_ext_ate_ram[0x10000];
-
-    /* Reserved                                        0x100000-0x1FFFFF */
-    char                    _pad_100000[0x200000-0x100000];
-
-    /* PCI/GIO Device Spaces                           0x200000-0xBFFFFF */
-    union {                             /* make all access sizes available. */
-        uchar_t                 c[0x100000 / 1];
-        uint16_t                s[0x100000 / 2];
-        uint32_t              l[0x100000 / 4];
-        uint64_t              d[0x100000 / 8];
-    } b_devio_raw[10];                  /* 0x200000 */
-
-    /* b_devio macro is a bit strange; it reflects the
-     * fact that the Bridge ASIC provides 2M for the
-     * first two DevIO windows and 1M for the other six.
-     */
-#define b_devio(n)      b_devio_raw[((n)<2)?(n*2):(n+2)]
-
-    /* External Flash Proms 1,0                        0xC00000-0xFFFFFF */
-    union {                             /* make all access sizes available. */
-        uchar_t                 c[0x400000 / 1];        /* read-only */
-        uint16_t                s[0x400000 / 2];        /* read-write */
-        uint32_t              l[0x400000 / 4];        /* read-only */
-        uint64_t              d[0x400000 / 8];        /* read-only */
-    } b_external_flash;                 /* 0xC00000 */
-} bridge_t;
-
-#endif
-
-
-
-
+#endif	/* CONFIG_IA64_SGI_SN1 */
 
 
 #define berr_field	berr_un.berr_st
@@ -873,7 +1128,12 @@
 
 /* end of Performance Monitor Registers */
 
-/* Byte offset macros for Bridge I/O space */
+/* Byte offset macros for Bridge I/O space.
+ *
+ * NOTE: Where applicable please use the PCIBR_xxx or PCIBRIDGE_xxx
+ * macros (below) as they will handle [X]Bridge and PIC. For example,
+ * PCIBRIDGE_TYPE0_CFG_DEV0() vs BRIDGE_TYPE0_CFG_DEV0
+ */
 
 #define BRIDGE_ATE_RAM		0x00010000	/* Internal Addr Xlat Ram */
 
@@ -905,7 +1165,55 @@
 #ifndef __ASSEMBLY__
 
 #define BRIDGE_DEVIO(x)		((x)<=1 ? BRIDGE_DEVIO0+(x)*BRIDGE_DEVIO_2MB : BRIDGE_DEVIO2+((x)-2)*BRIDGE_DEVIO_1MB)
-#endif				/* __ASSEMBLY__ */
+
+/*
+ * The device space macros for PIC are more complicated because the PIC has
+ * two PCI/X bridges under the same widget.  For PIC bus 0, the addresses are
+ * basically the same as for the [X]Bridge.  For PIC bus 1, the addresses are
+ * offset by 0x800000.   Here are two sets of macros.  They are 
+ * "PCIBRIDGE_xxx" that return the address based on the supplied bus number
+ * and also equivalent "PCIBR_xxx" macros that may be used with a
+ * pcibr_soft_s structure.   Both should work with all bridges.
+ */
+#define PIC_BUS1_OFFSET 0x800000
+
+#define PCIBRIDGE_TYPE0_CFG_DEV0(busnum) \
+    ((busnum) ? BRIDGE_TYPE0_CFG_DEV0 + PIC_BUS1_OFFSET : \
+                    BRIDGE_TYPE0_CFG_DEV0)
+#define PCIBRIDGE_TYPE1_CFG(busnum) \
+    ((busnum) ? BRIDGE_TYPE1_CFG + PIC_BUS1_OFFSET : BRIDGE_TYPE1_CFG)
+#define PCIBRIDGE_TYPE0_CFG_DEV(busnum, s) \
+        (PCIBRIDGE_TYPE0_CFG_DEV0(busnum)+\
+        (s)*BRIDGE_TYPE0_CFG_SLOT_OFF)
+#define PCIBRIDGE_TYPE0_CFG_DEVF(busnum, s, f) \
+        (PCIBRIDGE_TYPE0_CFG_DEV0(busnum)+\
+        (s)*BRIDGE_TYPE0_CFG_SLOT_OFF+\
+        (f)*BRIDGE_TYPE0_CFG_FUNC_OFF)
+#define PCIBRIDGE_DEVIO0(busnum) ((busnum) ? \
+        (BRIDGE_DEVIO0 + PIC_BUS1_OFFSET) : BRIDGE_DEVIO0)
+#define PCIBRIDGE_DEVIO1(busnum) ((busnum) ? \
+        (BRIDGE_DEVIO1 + PIC_BUS1_OFFSET) : BRIDGE_DEVIO1)
+#define PCIBRIDGE_DEVIO2(busnum) ((busnum) ? \
+        (BRIDGE_DEVIO2 + PIC_BUS1_OFFSET) : BRIDGE_DEVIO2)
+#define PCIBRIDGE_DEVIO(busnum, x) \
+    ((x)<=1 ? PCIBRIDGE_DEVIO0(busnum)+(x)*BRIDGE_DEVIO_2MB : \
+        PCIBRIDGE_DEVIO2(busnum)+((x)-2)*BRIDGE_DEVIO_1MB)
+
+#define PCIBR_BRIDGE_DEVIO0(ps)     PCIBRIDGE_DEVIO0((ps)->bs_busnum)
+#define PCIBR_BRIDGE_DEVIO1(ps)     PCIBRIDGE_DEVIO1((ps)->bs_busnum)
+#define PCIBR_BRIDGE_DEVIO2(ps)     PCIBRIDGE_DEVIO2((ps)->bs_busnum)
+#define PCIBR_BRIDGE_DEVIO(ps, s)   PCIBRIDGE_DEVIO((ps)->bs_busnum, s)
+
+#define PCIBR_TYPE1_CFG(ps)         PCIBRIDGE_TYPE1_CFG((ps)->bs_busnum)
+#define PCIBR_BUS_TYPE0_CFG_DEV0(ps) PCIBR_TYPE0_CFG_DEV(ps, 0)
+#define PCIBR_TYPE0_CFG_DEV(ps, s) \
+    ((IS_PIC_SOFT(ps)) ? PCIBRIDGE_TYPE0_CFG_DEV((ps)->bs_busnum, s+1) : \
+		  	     PCIBRIDGE_TYPE0_CFG_DEV((ps)->bs_busnum, s))
+#define PCIBR_BUS_TYPE0_CFG_DEVF(ps,s,f) \
+    ((IS_PIC_SOFT(ps)) ? PCIBRIDGE_TYPE0_CFG_DEVF((ps)->bs_busnum,(s+1),f) : \
+			     PCIBRIDGE_TYPE0_CFG_DEVF((ps)->bs_busnum,s,f))
+
+#endif				/* LANGUAGE_C */
 
 #define BRIDGE_EXTERNAL_FLASH	0x00C00000	/* External Flash PROMS */
 
@@ -929,6 +1237,17 @@
 #define XBRIDGE_REV_A			0x1
 #define XBRIDGE_REV_B			0x2
 
+/* macros to determine bridge type. 'wid' == widget identification */
+#define IS_BRIDGE(wid) (XWIDGET_PART_NUM(wid) == BRIDGE_WIDGET_PART_NUM && \
+			XWIDGET_MFG_NUM(wid) == BRIDGE_WIDGET_MFGR_NUM)
+#define IS_XBRIDGE(wid) (XWIDGET_PART_NUM(wid) == XBRIDGE_WIDGET_PART_NUM && \
+			XWIDGET_MFG_NUM(wid) == XBRIDGE_WIDGET_MFGR_NUM)
+#define IS_PIC_BUS0(wid) (XWIDGET_PART_NUM(wid) == PIC_WIDGET_PART_NUM_BUS0 && \
+			XWIDGET_MFG_NUM(wid) == PIC_WIDGET_MFGR_NUM)
+#define IS_PIC_BUS1(wid) (XWIDGET_PART_NUM(wid) == PIC_WIDGET_PART_NUM_BUS1 && \
+			XWIDGET_MFG_NUM(wid) == PIC_WIDGET_MFGR_NUM)
+#define IS_PIC_BRIDGE(wid) (IS_PIC_BUS0(wid) || IS_PIC_BUS1(wid))
+
 /* Part + Rev numbers allows distinction and acscending sequence */
 #define BRIDGE_PART_REV_A	(BRIDGE_WIDGET_PART_NUM << 4 | BRIDGE_REV_A)
 #define BRIDGE_PART_REV_B	(BRIDGE_WIDGET_PART_NUM << 4 | BRIDGE_REV_B)
@@ -938,7 +1257,8 @@
 #define XBRIDGE_PART_REV_B	(XBRIDGE_WIDGET_PART_NUM << 4 | XBRIDGE_REV_B)
 
 /* Bridge widget status register bits definition */
-
+#define PIC_STAT_PCIX_SPEED             (0x3ull << 34)
+#define PIC_STAT_PCIX_ACTIVE            (0x1ull << 33)
 #define BRIDGE_STAT_LLP_REC_CNT		(0xFFu << 24)
 #define BRIDGE_STAT_LLP_TX_CNT		(0xFF << 16)
 #define BRIDGE_STAT_FLASH_SELECT	(0x1 << 6)
@@ -946,7 +1266,18 @@
 #define BRIDGE_STAT_PENDING		(0x1F << 0)
 
 /* Bridge widget control register bits definition */
-#define BRIDGE_CTRL_FLASH_WR_EN		(0x1ul << 31)
+#define PIC_CTRL_NO_SNOOP		(0x1ull << 62)
+#define PIC_CTRL_RELAX_ORDER		(0x1ull << 61)
+#define PIC_CTRL_BUS_NUM(x)		((unsigned long long)(x) << 48)
+#define PIC_CTRL_BUS_NUM_MASK		(PIC_CTRL_BUS_NUM(0xff))
+#define PIC_CTRL_DEV_NUM(x)		((unsigned long long)(x) << 43)
+#define PIC_CTRL_DEV_NUM_MASK		(PIC_CTRL_DEV_NUM(0x1f))
+#define PIC_CTRL_FUN_NUM(x)		((unsigned long long)(x) << 40)
+#define PIC_CTRL_FUN_NUM_MASK		(PIC_CTRL_FUN_NUM(0x7))
+#define PIC_CTRL_PAR_EN_REQ		(0x1ull << 29)
+#define PIC_CTRL_PAR_EN_RESP		(0x1ull << 30)
+#define PIC_CTRL_PAR_EN_ATE		(0x1ull << 31)
+#define BRIDGE_CTRL_FLASH_WR_EN		(0x1ul << 31)   /* bridge only */
 #define BRIDGE_CTRL_EN_CLK50		(0x1 << 30)
 #define BRIDGE_CTRL_EN_CLK40		(0x1 << 29)
 #define BRIDGE_CTRL_EN_CLK33		(0x1 << 28)
@@ -970,6 +1301,8 @@
 #define BRIDGE_CTRL_CLR_RLLP_CNT	(0x1 << 11)
 #define BRIDGE_CTRL_CLR_TLLP_CNT	(0x1 << 10)
 #define BRIDGE_CTRL_SYS_END		(0x1 << 9)
+#define BRIDGE_CTRL_PCI_SPEED		(0x3 << 4)
+
 #define BRIDGE_CTRL_BUS_SPEED(n)        ((n) << 4)
 #define BRIDGE_CTRL_BUS_SPEED_MASK      (BRIDGE_CTRL_BUS_SPEED(0x3))
 #define BRIDGE_CTRL_BUS_SPEED_33        0x00
@@ -1023,6 +1356,20 @@
 #define BRIDGE_BUS_PCI_RETRY_MASK	BRIDGE_BUS_PCI_RETRY_CNT(0x3ff)
 
 /* Bridge interrupt status register bits definition */
+#define PIC_ISR_PCIX_SPLIT_MSG_PE	(0x1ull << 45)
+#define PIC_ISR_PCIX_SPLIT_EMSG		(0x1ull << 44)
+#define PIC_ISR_PCIX_SPLIT_TO		(0x1ull << 43)
+#define PIC_ISR_PCIX_UNEX_COMP		(0x1ull << 42)
+#define PIC_ISR_INT_RAM_PERR		(0x1ull << 41)
+#define PIC_ISR_PCIX_ARB_ERR		(0x1ull << 40)
+#define PIC_ISR_PCIX_REQ_TOUT		(0x1ull << 39)
+#define PIC_ISR_PCIX_TABORT		(0x1ull << 38)
+#define PIC_ISR_PCIX_PERR		(0x1ull << 37)
+#define PIC_ISR_PCIX_SERR		(0x1ull << 36)
+#define PIC_ISR_PCIX_MRETRY		(0x1ull << 35)
+#define PIC_ISR_PCIX_MTOUT		(0x1ull << 34)
+#define PIC_ISR_PCIX_DA_PARITY		(0x1ull << 33)
+#define PIC_ISR_PCIX_AD_PARITY		(0x1ull << 32)
 #define BRIDGE_ISR_MULTI_ERR		(0x1u << 31)	/* bridge only */
 #define BRIDGE_ISR_PMU_ESIZE_FAULT	(0x1 << 30)	/* bridge only */
 #define BRIDGE_ISR_PAGE_FAULT		(0x1 << 30)	/* xbridge only */
@@ -1058,12 +1405,18 @@
 		 BRIDGE_ISR_LLP_TCTY)
 
 #define BRIDGE_ISR_PCIBUS_PIOERR	\
-		(BRIDGE_ISR_PCI_MST_TIMEOUT|BRIDGE_ISR_PCI_ABORT)
+		(BRIDGE_ISR_PCI_MST_TIMEOUT|BRIDGE_ISR_PCI_ABORT|	\
+		 PIC_ISR_PCIX_MTOUT|PIC_ISR_PCIX_TABORT)
 
 #define BRIDGE_ISR_PCIBUS_ERROR		\
 		(BRIDGE_ISR_PCIBUS_PIOERR|BRIDGE_ISR_PCI_PERR|		\
 		 BRIDGE_ISR_PCI_SERR|BRIDGE_ISR_PCI_RETRY_CNT|		\
-		 BRIDGE_ISR_PCI_PARITY)
+		 BRIDGE_ISR_PCI_PARITY|PIC_ISR_PCIX_PERR|		\
+		 PIC_ISR_PCIX_SERR|PIC_ISR_PCIX_MRETRY|			\
+		 PIC_ISR_PCIX_AD_PARITY|PIC_ISR_PCIX_DA_PARITY|		\
+		 PIC_ISR_PCIX_REQ_TOUT|PIC_ISR_PCIX_UNEX_COMP|		\
+		 PIC_ISR_PCIX_SPLIT_TO|PIC_ISR_PCIX_SPLIT_EMSG|		\
+		 PIC_ISR_PCIX_SPLIT_MSG_PE)
 
 #define BRIDGE_ISR_XTALK_ERROR		\
 		(BRIDGE_ISR_XREAD_REQ_TIMEOUT|BRIDGE_ISR_XREQ_FIFO_OFLOW|\
@@ -1075,20 +1428,39 @@
 #define BRIDGE_ISR_ERRORS		\
 		(BRIDGE_ISR_LINK_ERROR|BRIDGE_ISR_PCIBUS_ERROR|		\
 		 BRIDGE_ISR_XTALK_ERROR|BRIDGE_ISR_SSRAM_PERR|		\
-		 BRIDGE_ISR_PMU_ESIZE_FAULT)
+		 BRIDGE_ISR_PMU_ESIZE_FAULT|PIC_ISR_PCIX_ARB_ERR|	\
+		 PIC_ISR_INT_RAM_PERR)
 
 /*
  * List of Errors which are fatal and kill the sytem
  */
 #define BRIDGE_ISR_ERROR_FATAL		\
 		((BRIDGE_ISR_XTALK_ERROR & ~BRIDGE_ISR_XREAD_REQ_TIMEOUT)|\
-		 BRIDGE_ISR_PCI_SERR|BRIDGE_ISR_PCI_PARITY )
+		 BRIDGE_ISR_PCI_SERR|BRIDGE_ISR_PCI_PARITY|		  \
+		 PIC_ISR_PCIX_SERR|PIC_ISR_PCIX_AD_PARITY|		  \
+		 PIC_ISR_PCIX_DA_PARITY|				  \
+		 PIC_ISR_INT_RAM_PERR|PIC_ISR_PCIX_SPLIT_MSG_PE )
 
 #define BRIDGE_ISR_ERROR_DUMP		\
 		(BRIDGE_ISR_PCIBUS_ERROR|BRIDGE_ISR_PMU_ESIZE_FAULT|	\
-		 BRIDGE_ISR_XTALK_ERROR|BRIDGE_ISR_SSRAM_PERR)
+		 BRIDGE_ISR_XTALK_ERROR|BRIDGE_ISR_SSRAM_PERR|		\
+		 PIC_ISR_PCIX_ARB_ERR|PIC_ISR_INT_RAM_PERR)
 
 /* Bridge interrupt enable register bits definition */
+#define PIC_IMR_PCIX_SPLIT_MSG_PE	PIC_ISR_PCIX_SPLIT_MSG_PE
+#define PIC_IMR_PCIX_SPLIT_EMSG		PIC_ISR_PCIX_SPLIT_EMSG
+#define PIC_IMR_PCIX_SPLIT_TO		PIC_ISR_PCIX_SPLIT_TO
+#define PIC_IMR_PCIX_UNEX_COMP		PIC_ISR_PCIX_UNEX_COMP
+#define PIC_IMR_INT_RAM_PERR		PIC_ISR_INT_RAM_PERR
+#define PIC_IMR_PCIX_ARB_ERR		PIC_ISR_PCIX_ARB_ERR
+#define PIC_IMR_PCIX_REQ_TOUR		PIC_ISR_PCIX_REQ_TOUT
+#define PIC_IMR_PCIX_TABORT		PIC_ISR_PCIX_TABORT
+#define PIC_IMR_PCIX_PERR		PIC_ISR_PCIX_PERR
+#define PIC_IMR_PCIX_SERR		PIC_ISR_PCIX_SERR
+#define PIC_IMR_PCIX_MRETRY		PIC_ISR_PCIX_MRETRY
+#define PIC_IMR_PCIX_MTOUT		PIC_ISR_PCIX_MTOUT
+#define PIC_IMR_PCIX_DA_PARITY		PIC_ISR_PCIX_DA_PARITY
+#define PIC_IMR_PCIX_AD_PARITY		PIC_ISR_PCIX_AD_PARITY
 #define BRIDGE_IMR_UNEXP_RESP		BRIDGE_ISR_UNEXP_RESP
 #define BRIDGE_IMR_PMU_ESIZE_FAULT	BRIDGE_ISR_PMU_ESIZE_FAULT
 #define BRIDGE_IMR_BAD_XRESP_PKT	BRIDGE_ISR_BAD_XRESP_PKT
@@ -1116,7 +1488,46 @@
 #define BRIDGE_IMR_INT_MSK		BRIDGE_ISR_INT_MSK
 #define BRIDGE_IMR_INT(x)		BRIDGE_ISR_INT(x)
 
-/* Bridge interrupt reset register bits definition */
+/* 
+ * Bridge interrupt reset register bits definition.  Note, PIC can
+ * reset indiviual error interrupts, BRIDGE & XBRIDGE can only do 
+ * groups of them.
+ */
+#define PIC_IRR_PCIX_SPLIT_MSG_PE	PIC_ISR_PCIX_SPLIT_MSG_PE
+#define PIC_IRR_PCIX_SPLIT_EMSG		PIC_ISR_PCIX_SPLIT_EMSG
+#define PIC_IRR_PCIX_SPLIT_TO		PIC_ISR_PCIX_SPLIT_TO
+#define PIC_IRR_PCIX_UNEX_COMP		PIC_ISR_PCIX_UNEX_COMP
+#define PIC_IRR_INT_RAM_PERR		PIC_ISR_INT_RAM_PERR
+#define PIC_IRR_PCIX_ARB_ERR		PIC_ISR_PCIX_ARB_ERR
+#define PIC_IRR_PCIX_REQ_TOUT		PIC_ISR_PCIX_REQ_TOUT
+#define PIC_IRR_PCIX_TABORT		PIC_ISR_PCIX_TABORT
+#define PIC_IRR_PCIX_PERR		PIC_ISR_PCIX_PERR
+#define PIC_IRR_PCIX_SERR		PIC_ISR_PCIX_SERR
+#define PIC_IRR_PCIX_MRETRY		PIC_ISR_PCIX_MRETRY
+#define PIC_IRR_PCIX_MTOUT		PIC_ISR_PCIX_MTOUT
+#define PIC_IRR_PCIX_DA_PARITY		PIC_ISR_PCIX_DA_PARITY
+#define PIC_IRR_PCIX_AD_PARITY		PIC_ISR_PCIX_AD_PARITY
+#define PIC_IRR_PAGE_FAULT		BRIDGE_ISR_PAGE_FAULT
+#define PIC_IRR_UNEXP_RESP		BRIDGE_ISR_UNEXP_RESP
+#define PIC_IRR_BAD_XRESP_PKT		BRIDGE_ISR_BAD_XRESP_PKT
+#define PIC_IRR_BAD_XREQ_PKT		BRIDGE_ISR_BAD_XREQ_PKT
+#define PIC_IRR_RESP_XTLK_ERR		BRIDGE_ISR_RESP_XTLK_ERR
+#define PIC_IRR_REQ_XTLK_ERR		BRIDGE_ISR_REQ_XTLK_ERR
+#define PIC_IRR_INVLD_ADDR		BRIDGE_ISR_INVLD_ADDR
+#define PIC_IRR_UNSUPPORTED_XOP		BRIDGE_ISR_UNSUPPORTED_XOP
+#define PIC_IRR_XREQ_FIFO_OFLOW		BRIDGE_ISR_XREQ_FIFO_OFLOW
+#define PIC_IRR_LLP_REC_SNERR		BRIDGE_ISR_LLP_REC_SNERR
+#define PIC_IRR_LLP_REC_CBERR		BRIDGE_ISR_LLP_REC_CBERR
+#define PIC_IRR_LLP_RCTY		BRIDGE_ISR_LLP_RCTY
+#define PIC_IRR_LLP_TX_RETRY		BRIDGE_ISR_LLP_TX_RETRY
+#define PIC_IRR_LLP_TCTY		BRIDGE_ISR_LLP_TCTY
+#define PIC_IRR_PCI_ABORT		BRIDGE_ISR_PCI_ABORT
+#define PIC_IRR_PCI_PARITY		BRIDGE_ISR_PCI_PARITY
+#define PIC_IRR_PCI_SERR		BRIDGE_ISR_PCI_SERR
+#define PIC_IRR_PCI_PERR		BRIDGE_ISR_PCI_PERR
+#define PIC_IRR_PCI_MST_TIMEOUT		BRIDGE_ISR_PCI_MST_TIMEOUT
+#define PIC_IRR_PCI_RETRY_CNT		BRIDGE_ISR_PCI_RETRY_CNT
+#define PIC_IRR_XREAD_REQ_TIMEOUT	BRIDGE_ISR_XREAD_REQ_TIMEOUT
 #define BRIDGE_IRR_MULTI_CLR		(0x1 << 6)
 #define BRIDGE_IRR_CRP_GRP_CLR		(0x1 << 5)
 #define BRIDGE_IRR_RESP_BUF_GRP_CLR	(0x1 << 4)
@@ -1153,6 +1564,21 @@
 #define BRIDGE_IRR_GIO_GRP		(BRIDGE_ISR_GIO_B_ENBL_ERR | \
 					 BRIDGE_ISR_GIO_MST_TIMEOUT)
 
+#define PIC_IRR_RAM_GRP			PIC_ISR_INT_RAM_PERR
+
+#define PIC_PCIX_GRP_CLR		(PIC_IRR_PCIX_AD_PARITY | \
+					 PIC_IRR_PCIX_DA_PARITY | \
+					 PIC_IRR_PCIX_MTOUT | \
+					 PIC_IRR_PCIX_MRETRY | \
+					 PIC_IRR_PCIX_SERR | \
+					 PIC_IRR_PCIX_PERR | \
+					 PIC_IRR_PCIX_TABORT | \
+					 PIC_ISR_PCIX_REQ_TOUT | \
+					 PIC_ISR_PCIX_UNEX_COMP | \
+					 PIC_ISR_PCIX_SPLIT_TO | \
+					 PIC_ISR_PCIX_SPLIT_EMSG | \
+					 PIC_ISR_PCIX_SPLIT_MSG_PE)
+
 /* Bridge INT_DEV register bits definition */
 #define BRIDGE_INT_DEV_SHFT(n)		((n)*3)
 #define BRIDGE_INT_DEV_MASK(n)		(0x7 << BRIDGE_INT_DEV_SHFT(n))
@@ -1162,6 +1588,10 @@
 #define BRIDGE_INT_ADDR_HOST		0x0003FF00
 #define BRIDGE_INT_ADDR_FLD		0x000000FF
 
+/* PIC interrupt(x) register bits definition */
+#define PIC_INT_ADDR_FLD                0x00FF000000000000
+#define PIC_INT_ADDR_HOST               0x0000FFFFFFFFFFFF
+
 #define BRIDGE_TMO_PCI_RETRY_HLD_MASK	0x1f0000
 #define BRIDGE_TMO_GIO_TIMEOUT_MASK	0x001000
 #define BRIDGE_TMO_PCI_RETRY_CNT_MASK	0x0003ff
@@ -1239,8 +1669,13 @@
 /* RRB assignment register */
 #define	BRIDGE_RRB_EN	0x8	/* after shifting down */
 #define	BRIDGE_RRB_DEV	0x7	/* after shifting down */
-#define	BRIDGE_RRB_VDEV	0x4	/* after shifting down */
-#define	BRIDGE_RRB_PDEV	0x3	/* after shifting down */
+#define	BRIDGE_RRB_VDEV	0x4	/* after shifting down, 2 virtual channels */
+#define	BRIDGE_RRB_PDEV	0x3	/* after shifting down, 8 devices */
+
+#define	PIC_RRB_EN	0x8	/* after shifting down */
+#define	PIC_RRB_DEV	0x7	/* after shifting down */
+#define	PIC_RRB_VDEV	0x6	/* after shifting down, 4 virtual channels */
+#define	PIC_RRB_PDEV	0x1	/* after shifting down, 4 devices */
 
 /* RRB status register */
 #define	BRIDGE_RRB_VALID(r)	(0x00010000<<(r))
@@ -1249,6 +1684,15 @@
 /* RRB clear register */
 #define	BRIDGE_RRB_CLEAR(r)	(0x00000001<<(r))
 
+/* Defines for the virtual channels so we dont hardcode 0-3 within code */
+#define VCHAN0	0	/* virtual channel 0 (ie. the "normal" channel) */
+#define VCHAN1	1	/* virtual channel 1 */
+#define VCHAN2	2	/* virtual channel 2 - PIC only */
+#define VCHAN3	3	/* virtual channel 3 - PIC only */
+
+/* PIC: PCI-X Read Buffer Attribute Register (RBAR) */
+#define NUM_RBAR 16	/* number of RBAR registers */
+
 /* xbox system controller declarations */
 #define XBOX_BRIDGE_WID         8
 #define FLASH_PROM1_BASE        0xE00000 /* To read the xbox sysctlr status */
@@ -1401,8 +1845,10 @@
 #define ATE_SWAP_ON(x)		((x) |= (1 << ATE_SWAPSHIFT))
 #define ATE_SWAP_OFF(x)		((x) &= ~(1 << ATE_SWAPSHIFT))
 
-#define is_xbridge(bridge) \
-        (XWIDGET_PART_NUM(bridge->b_wid_id) == XBRIDGE_WIDGET_PART_NUM)
+#define is_xbridge(bridge) IS_XBRIDGE(bridge->b_wid_id)
+#define is_pic(bridge) IS_PIC_BRIDGE(bridge->b_wid_id)
+
+/* extern declarations */
 
 #ifndef __ASSEMBLY__
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/pci/pci_bus_cvlink.h linux-2.4.21-pre6/include/asm-ia64/sn/pci/pci_bus_cvlink.h
--- linux-2.4.20/include/asm-ia64/sn/pci/pci_bus_cvlink.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/pci/pci_bus_cvlink.h	2003-03-26 23:49:34.000000000 +0000
@@ -41,6 +41,8 @@
 #define IS_PCI32G(dev)	((dev)->dma_mask >= 0xffffffff)
 #define IS_PCI32L(dev)	((dev)->dma_mask < 0xffffffff)
 
+#define IS_PIC_DEVICE(dev) ((struct sn_device_sysdata *)dev->sysdata)->isPIC
+
 #define PCIDEV_VERTEX(pci_dev) \
 	(((struct sn_device_sysdata *)((pci_dev)->sysdata))->vhdl)
 
@@ -54,6 +56,7 @@
 struct sn_device_sysdata {
         devfs_handle_t  vhdl;
 	int		isa64;
+	int		isPIC;
 	volatile unsigned int *dma_buf_sync;
 	volatile unsigned int *xbow_buf_sync;
 };
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/pci/pci_defs.h linux-2.4.21-pre6/include/asm-ia64/sn/pci/pci_defs.h
--- linux-2.4.20/include/asm-ia64/sn/pci/pci_defs.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/pci/pci_defs.h	2003-03-26 23:49:21.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (c) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 #ifndef _ASM_SN_PCI_PCI_DEFS_H
 #define _ASM_SN_PCI_PCI_DEFS_H
@@ -39,7 +39,7 @@
  * the PCI spec.
  */
 #define	PCI_TYPE1_BUS_MASK	0x00FF0000
-#define	PCI_TYPE1_SLOT_MASK	0x0000F100
+#define	PCI_TYPE1_SLOT_MASK	0x0000F800
 #define	PCI_TYPE1_FUNC_MASK	0x00000700
 #define	PCI_TYPE1_REG_MASK	0x000000FF
 
@@ -68,14 +68,14 @@
 
 /* NOTE: if you are using a C "switch" statement to
  * differentiate between the Config space registers, be
- * aware that PCI_CFG_CLASS_CODE and PCI_CFG_BASE_CLASS
+ * aware that PCI_CFG_CLASS_CODE and PCI_CFG_PROG_IF
  * are the same offset.
  */
 #define	PCI_CFG_REV_ID		0x08		/* Revision Id (1 byte) */
 #define	PCI_CFG_CLASS_CODE	0x09		/* Class Code (3 bytes) */
-#define	PCI_CFG_BASE_CLASS	0x09		/* Base Class (1 byte) */
+#define	PCI_CFG_PROG_IF		0x09		/* Prog Interface (1 byte) */
 #define	PCI_CFG_SUB_CLASS	0x0A		/* Sub Class (1 byte) */
-#define	PCI_CFG_PROG_IF		0x0B		/* Prog Interface (1 byte) */
+#define	PCI_CFG_BASE_CLASS	0x0B		/* Base Class (1 byte) */
 
 #define	PCI_CFG_CACHE_LINE	0x0C		/* Cache line size (1 byte) */
 #define	PCI_CFG_LATENCY_TIMER	0x0D		/* Latency Timer (1 byte) */
@@ -99,11 +99,10 @@
 #define	PCI_CFG_SUBSYS_ID	0x2E		/* Subsystem ID */
 
 #define	PCI_EXPANSION_ROM	0x30		/* Expansion Rom Base (4B) */
+#define	PCI_CAPABILITIES_PTR	0x34		/* Capabilities Pointer */
 
 #define	PCI_INTR_LINE		0x3C		/* Interrupt Line (1B) */
 #define	PCI_INTR_PIN		0x3D		/* Interrupt Pin (1B) */
-#define	PCI_MIN_GNT		0x3E		/* Minimum Grant (1B) */
-#define	PCI_MAX_LAT		0x3F		/* Maximum Latency (1B) */
 
 #define PCI_CFG_VEND_SPECIFIC	0x40		/* first vendor specific reg */
 
@@ -126,6 +125,8 @@
 #define PCI_CFG_PPB_IOLIMHI		0x32	/* IO Limit Addr bits 16..31 */
 #define	PCI_CFG_PPB_SUB_VENDOR		0x34	/* Subsystem Vendor ID */
 #define	PCI_CFG_PPB_SUB_DEVICE		0x36	/* Subsystem Device ID */
+#define	PCI_CFG_PPB_ROM_BASE		0x38	/* ROM base address */
+#define	PCI_CFG_PPB_INT_LINE		0x3C	/* Interrupt Line */
 #define	PCI_CFG_PPB_INT_PIN		0x3D	/* Interrupt Pin */
 #define	PCI_CFG_PPB_BRIDGE_CTRL		0x3E	/* Bridge Control */
      /* XXX- these might be DEC 21152 specific */
@@ -165,6 +166,7 @@
 #define	PCI_STAT_F_BK_BK_CAP	0x0080		/* Fast Back-to-Back Capable */
 #define	PCI_STAT_UDF_SUPP	0x0040		/* UDF Supported */
 #define	PCI_STAT_66MHZ_CAP	0x0020		/* 66 MHz Capable */
+#define	PCI_STAT_CAP_LIST	0x0010		/* Capabilities List */
 
 /* BIST Register Layout (0x0F) */
 #define	PCI_BIST_BIST_CAP	0x80		/* BIST Capable */
@@ -173,13 +175,63 @@
 #define	PCI_BIST_CMPL_OK	0x00		/* 0 value is completion OK */
 
 /* Base Address Register 0x10 */
+#define PCI_BA_IO_CODEMASK	0x3		/* bottom 2 bits encode I/O BAR type */
 #define	PCI_BA_IO_SPACE		0x1		/* I/O Space Marker */
+
+#define PCI_BA_MEM_CODEMASK	0xf		/* bottom 4 bits encode MEM BAR type */
 #define	PCI_BA_MEM_LOCATION	0x6		/* 2 bits for location avail */
 #define	PCI_BA_MEM_32BIT	0x0		/* Anywhere in 32bit space */
 #define	PCI_BA_MEM_1MEG		0x2		/* Locate below 1 Meg */
 #define	PCI_BA_MEM_64BIT	0x4		/* Anywhere in 64bit space */
 #define	PCI_BA_PREFETCH		0x8		/* Prefetchable, no side effect */
 
+#define PCI_BA_ROM_CODEMASK	0x1		/* bottom bit control expansion ROM enable */
+#define PCI_BA_ROM_ENABLE	0x1		/* enable expansion ROM */
+
+/* Bridge Control Register 0x3e */
+#define PCI_BCTRL_DTO_SERR	0x0800		/* Discard Timer timeout generates SERR on primary bus */
+#define PCI_BCTRL_DTO		0x0400		/* Discard Timer timeout status */
+#define PCI_BCTRL_DTO_SEC	0x0200		/* Secondary Discard Timer: 0 => 2^15 PCI clock cycles, 1 => 2^10 */
+#define PCI_BCTRL_DTO_PRI	0x0100		/* Primary Discard Timer: 0 => 2^15 PCI clock cycles, 1 => 2^10 */
+#define PCI_BCTRL_F_BK_BK_ENABLE 0x0080		/* Enable Fast Back-to-Back on secondary bus */
+#define PCI_BCTRL_RESET_SEC	0x0040		/* Reset Secondary bus */
+#define PCI_BCTRL_MSTR_ABT_MODE	0x0020		/* Master Abort Mode: 0 => do not report Master-Aborts */
+#define PCI_BCTRL_VGA_AF_ENABLE	0x0008		/* Enable VGA Address Forwarding */
+#define PCI_BCTRL_ISA_AF_ENABLE	0x0004		/* Enable ISA Address Forwarding */
+#define PCI_BCTRL_SERR_ENABLE	0x0002		/* Enable forwarding of SERR from secondary bus to primary bus */
+#define PCI_BCTRL_PAR_ERR_RESP	0x0001		/* Enable Parity Error Response reporting on secondary interface */
+
+/*
+ * PCI 2.2 introduces the concept of ``capability lists.''  Capability lists
+ * provide a flexible mechanism for a device or bridge to advertise one or
+ * more standardized capabilities such as the presense of a power management
+ * interface, etc.  The presense of a capability list is indicated by
+ * PCI_STAT_CAP_LIST being non-zero in the PCI_CFG_STATUS register.  If
+ * PCI_STAT_CAP_LIST is set, then PCI_CFG_CAP_PTR is a ``pointer'' into the
+ * device-specific portion of the configuration header where the first
+ * capability block is stored.  This ``pointer'' is a single byte which
+ * contains an offset from the beginning of the configuration header.  The
+ * bottom two bits of the pointer are reserved and should be masked off to
+ * determine the offset.  Each capability block contains a capability ID, a
+ * ``pointer'' to the next capability (another offset where a zero terminates
+ * the list) and capability-specific data.  Each capability block starts with
+ * the capability ID and the ``next capability pointer.''  All data following
+ * this are capability-dependent.
+ */
+#define PCI_CAP_ID		0x00		/* Capability ID (1B) */
+#define PCI_CAP_PTR		0x01		/* Capability ``pointer'' (1B) */
+
+/* PCI Capability IDs */
+#define	PCI_CAP_PM		0x01		/* PCI Power Management */
+#define	PCI_CAP_AGP		0x02		/* Accelerated Graphics Port */
+#define	PCI_CAP_VPD		0x03		/* Vital Product Data (VPD) */
+#define	PCI_CAP_SID		0x04		/* Slot Identification */
+#define PCI_CAP_MSI		0x05		/* Message Signaled Intr */
+#define	PCI_CAP_HS		0x06		/* CompactPCI Hot Swap */
+#define	PCI_CAP_PCIX		0x07		/* PCI-X */
+#define PCI_CAP_ID_HT		0x08		/* HyperTransport */
+
+
 /* PIO interface macros */
 
 #ifndef IOC3_EMULATION
@@ -210,10 +262,6 @@
 #endif /* !IOC3_EMULATION */
 						/* effects on reads, merges */
 
-#ifdef CONFIG_SGI_IP22
-#define BYTECOUNT_W_GIO	    0xbf400000
-#endif
-
 /*
  * Definition of address layouts for PCI Config mechanism #1
  * XXX- These largely duplicate PCI_TYPE1 constants at the top
@@ -240,4 +288,139 @@
 #define PCI_IO_MAP_INCR			0x1000
 #endif /* CONFIG_SGI_IP32 */
 
+/*
+ * Class codes
+ */
+#define PCI_CFG_CLASS_PRE20	0x00
+#define PCI_CFG_CLASS_STORAGE	0x01
+#define PCI_CFG_CLASS_NETWORK	0x02
+#define PCI_CFG_CLASS_DISPLAY	0x03
+#define PCI_CFG_CLASS_MMEDIA	0x04
+#define PCI_CFG_CLASS_MEMORY	0x05
+#define PCI_CFG_CLASS_BRIDGE	0x06
+#define PCI_CFG_CLASS_COMM	0x07
+#define PCI_CFG_CLASS_BASE	0x08
+#define PCI_CFG_CLASS_INPUT	0x09
+#define PCI_CFG_CLASS_DOCK	0x0A
+#define PCI_CFG_CLASS_PROC	0x0B
+#define PCI_CFG_CLASS_SERIALBUS	0x0C
+#define PCI_CFG_CLASS_OTHER	0xFF
+
+/*
+ * Important Subclasses
+ */
+#define PCI_CFG_SUBCLASS_BRIDGE_HOST	0x00
+#define PCI_CFG_SUBCLASS_BRIDGE_ISA	0x01
+#define PCI_CFG_SUBCLASS_BRIDGE_EISA	0x02
+#define PCI_CFG_SUBCLASS_BRIDGE_MC	0x03
+#define PCI_CFG_SUBCLASS_BRIDGE_PCI	0x04
+#define PCI_CFG_SUBCLASS_BRIDGE_PCMCIA	0x05
+#define PCI_CFG_SUBCLASS_BRIDGE_NUBUS	0x06
+#define PCI_CFG_SUBCLASS_BRIDGE_CARDBUS	0x07
+#define PCI_CFG_SUBCLASS_BRIDGE_OTHER	0x80
+
+#ifndef __ASSEMBLY__
+
+/*
+ * PCI config space definition
+ */
+typedef volatile struct pci_cfg_s {
+	uint16_t	dev_id;
+	uint16_t	vendor_id;
+	uint16_t	status;
+	uint16_t	cmd;
+	uchar_t		class;
+	uchar_t		sub_class;
+	uchar_t		prog_if;
+	uchar_t		rev;
+	uchar_t		bist;
+	uchar_t		hdr_type;
+	uchar_t		lt;
+	uchar_t		line_size;
+	uint32_t	bar[6];
+	uint32_t	cardbus;
+	uint16_t	subsys_dev_id;
+	uint16_t	subsys_vendor_id;
+	uint32_t	exp_rom;
+	uint32_t	res[2];
+	uchar_t		max_lat;
+	uchar_t		min_gnt;
+	uchar_t		int_pin;
+	uchar_t		int_line;
+} pci_cfg_t;
+
+/*
+ * PCI Type 1 config space definition for PCI to PCI Bridges (PPBs)
+ */
+typedef volatile struct pci_cfg1_s {
+	uint16_t	dev_id;
+	uint16_t	vendor_id;
+	uint16_t	status;
+	uint16_t	cmd;
+	uchar_t		class;
+	uchar_t		sub_class;
+	uchar_t		prog_if;
+	uchar_t		rev;
+	uchar_t		bist;
+	uchar_t		hdr_type;
+	uchar_t		lt;
+	uchar_t		line_size;
+	uint32_t	bar[2];
+	uchar_t		slt;
+	uchar_t		sub_bus_num;
+	uchar_t		snd_bus_num;
+	uchar_t		pri_bus_num;
+	uint16_t	snd_status;
+	uchar_t		io_limit;
+	uchar_t		io_base;
+	uint16_t	mem_limit;
+	uint16_t	mem_base;
+	uint16_t	pmem_limit;
+	uint16_t	pmem_base;
+	uint32_t	pmem_limit_upper;
+	uint32_t	pmem_base_upper;
+	uint16_t	io_limit_upper;
+	uint16_t	io_base_upper;
+	uint32_t	res;
+	uint32_t	exp_rom;
+	uint16_t	ppb_control;
+	uchar_t		int_pin;
+	uchar_t		int_line;
+} pci_cfg1_t;
+
+/*
+ * PCI-X Capability
+ */
+typedef volatile struct cap_pcix_cmd_reg_s {
+	uint16_t	reserved1:              9,
+			max_split:		3,
+			max_mem_read_cnt:	2,
+			enable_relaxed_order:	1,
+			data_parity_enable:	1;
+} cap_pcix_cmd_reg_t;
+
+typedef volatile struct cap_pcix_stat_reg_s {
+	uint32_t	reserved1:		2,
+			split_complt_err:	1,
+			max_cum_read:		3,
+			max_out_split:		3,
+			max_mem_read_cnt:	2,
+			device_complex:		1,
+			unexpect_split_complt:	1,
+			split_complt_discard:	1,
+			mhz133_capable:		1,
+			bit64_device:		1,
+			bus_num:		8,
+			dev_num:		5,
+			func_num:		3;
+} cap_pcix_stat_reg_t;
+
+typedef volatile struct cap_pcix_type0_s {
+	cap_pcix_cmd_reg_t	pcix_type0_command;
+	uchar_t			pcix_cap_nxt;
+	uchar_t			pcix_cap_id;
+	cap_pcix_stat_reg_t	pcix_type0_status;
+} cap_pcix_type0_t;
+
+#endif	/* __ASSEMBLY__ */
 #endif /* _ASM_SN_PCI_PCI_DEFS_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/pci/pciba.h linux-2.4.21-pre6/include/asm-ia64/sn/pci/pciba.h
--- linux-2.4.20/include/asm-ia64/sn/pci/pciba.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/pci/pciba.h	2003-03-26 23:49:06.000000000 +0000
@@ -3,7 +3,7 @@
  * Public License.  See the file "COPYING" in the main directory of
  * this archive for more details.
  *
- * Copyright (C) 1997, 2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1997, 2001-2002 Silicon Graphics, Inc. All rights reserved.
  *
  */
 
@@ -91,6 +91,13 @@
 #define	PCIIOCDMAALLOC		_IOWR(0,1,uint64_t)
 #define	PCIIOCDMAFREE		_IOW(0,1,uint64_t)
 
+/* pio cache-mode ioctl defines.  current only uncached accelerated */
+#define PCIBA_CACHE_MODE_SET	1
+#define PCIBA_CACHE_MODE_CLEAR	2
+#ifdef PIOMAP_UNC_ACC
+#define PCIBA_UNCACHED_ACCEL	PIOMAP_UNC_ACC
+#endif
+
 /* The parameter for PCIIOCDMAALLOC needs to contain
  * both the size of the request and the flag values
  * to be used in setting up the DMA.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/pci/pcibr.h linux-2.4.21-pre6/include/asm-ia64/sn/pci/pcibr.h
--- linux-2.4.20/include/asm-ia64/sn/pci/pcibr.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/pci/pcibr.h	2003-03-26 23:49:20.000000000 +0000
@@ -4,13 +4,14 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 #ifndef _ASM_SN_PCI_PCIBR_H
 #define _ASM_SN_PCI_PCIBR_H
 
 #if defined(__KERNEL__)
 
+#include <linux/config.h>
 #include <asm/sn/dmamap.h>
 #include <asm/sn/driver.h>
 #include <asm/sn/pio.h>
@@ -75,6 +76,7 @@
  */
 
 extern pciio_provider_t pcibr_provider;
+extern pciio_provider_t pci_pic_provider;
 
 /* =====================================================================
  *    secondary entry points: pcibr PCI bus provider
@@ -182,7 +184,11 @@
 
 extern void		pcibr_intr_free(pcibr_intr_t intr);
 
+#ifdef CONFIG_IA64_SGI_SN1
 extern int		pcibr_intr_connect(pcibr_intr_t intr);
+#else
+extern int		pcibr_intr_connect(pcibr_intr_t intr, intr_func_t, intr_arg_t);
+#endif
 
 extern void		pcibr_intr_disconnect(pcibr_intr_t intr);
 
@@ -215,9 +221,11 @@
 extern int		pcibr_error_devenable(devfs_handle_t pconn_vhdl,
 					      int error_code);
 
+#ifdef PIC_LATER
 extern pciio_slot_t	pcibr_error_extract(devfs_handle_t pcibr_vhdl,
 					    pciio_space_t *spacep,
 					    iopaddr_t *addrp);
+#endif
 
 extern int		pcibr_wrb_flush(devfs_handle_t pconn_vhdl);
 extern int		pcibr_rrb_check(devfs_handle_t pconn_vhdl,
@@ -226,11 +234,13 @@
 					int *count_reserved,
 					int *count_pool);
 
+#ifndef CONFIG_IA64_SGI_SN1
 extern int		pcibr_alloc_all_rrbs(devfs_handle_t vhdl, int even_odd,
 					     int dev_1_rrbs, int virt1,
 					     int dev_2_rrbs, int virt2,
 					     int dev_3_rrbs, int virt3,
 					     int dev_4_rrbs, int virt4);
+#endif
 
 typedef void
 rrb_alloc_funct_f	(devfs_handle_t xconn_vhdl,
@@ -340,7 +350,11 @@
 extern void		pcibr_hints_subdevs(devfs_handle_t, pciio_slot_t, ulong);
 extern void		pcibr_hints_handsoff(devfs_handle_t);
 
+#ifdef CONFIG_IA64_SGI_SN1
 typedef unsigned	pcibr_intr_bits_f(pciio_info_t, pciio_intr_line_t);
+#else
+typedef unsigned	pcibr_intr_bits_f(pciio_info_t, pciio_intr_line_t, int);
+#endif
 extern void		pcibr_hints_intr_bits(devfs_handle_t, pcibr_intr_bits_f *);
 
 extern int		pcibr_asic_rev(devfs_handle_t);
@@ -414,13 +428,9 @@
     char                    resp_l1_msg[L1_QSIZE + 1];
 };
 
-struct pcibr_slot_info_req_s {
-   int                      req_slot;
-   pcibr_slot_info_resp_t   req_respp;
-   int                      req_size;
-};
-
 struct pcibr_slot_info_resp_s {
+    short		    resp_bs_bridge_type;
+    short		    resp_bs_bridge_mode;
     int                     resp_has_host;
     char                    resp_host_slot;
     devfs_handle_t            resp_slot_conn;
@@ -438,17 +448,22 @@
     unsigned                resp_bss_d64_flags;
     iopaddr_t               resp_bss_d32_base;
     unsigned                resp_bss_d32_flags;
-    int                     resp_bss_ext_ates_active;
+    atomic_t                resp_bss_ext_ates_active;
     volatile unsigned      *resp_bss_cmd_pointer;
     unsigned                resp_bss_cmd_shadow;
     int                     resp_bs_rrb_valid;
-    int                     resp_bs_rrb_valid_v;
+    int                     resp_bs_rrb_valid_v1;
+    int                     resp_bs_rrb_valid_v2;
+    int                     resp_bs_rrb_valid_v3;
     int                     resp_bs_rrb_res;
     bridgereg_t             resp_b_resp;
     bridgereg_t             resp_b_int_device;
     bridgereg_t             resp_b_int_enable;
     bridgereg_t             resp_b_int_host;
-
+#ifndef CONFIG_IA64_SGI_SN1
+    picreg_t		    resp_p_int_enable;
+    picreg_t		    resp_p_int_host;
+#endif
     struct pcibr_slot_func_info_resp_s {
         int                     resp_f_status;
         char                    resp_f_slot_name[MAXDEVNAME];
@@ -507,6 +522,9 @@
 #define PCI_SLOT_RRB_ALLOC_ERR   24     /* slot initial rrb alloc error */
 #define PCI_SLOT_DRV_ATTACH_ERR  25     /* driver attach error */
 #define PCI_SLOT_DRV_DETACH_ERR  26     /* driver detach error */
+/* EFBIG                         27    */
+#define PCI_MULTI_FUNC_ERR       28     /* multi-function card error */
+#define PCI_SLOT_RBAR_ALLOC_ERR  29     /* slot PCI-X RBAR alloc error */
 /* ERANGE                        34    */
 /* EUNATCH                       42    */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/pci/pcibr_private.h linux-2.4.21-pre6/include/asm-ia64/sn/pci/pcibr_private.h
--- linux-2.4.20/include/asm-ia64/sn/pci/pcibr_private.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/pci/pcibr_private.h	2003-03-26 23:48:57.000000000 +0000
@@ -15,6 +15,7 @@
  * should ever peek into this file.
  */
 
+#include <linux/config.h>
 #include <asm/sn/pci/pcibr.h>
 #include <asm/sn/pci/pciio_private.h>
 #include <asm/sn/ksys/l1.h>
@@ -34,6 +35,68 @@
 typedef struct pcibr_intr_wrap_s *pcibr_intr_wrap_t;
 typedef struct pcibr_intr_cbuf_s *pcibr_intr_cbuf_t;
 
+typedef volatile unsigned *cfg_p;
+typedef volatile bridgereg_t *reg_p;
+
+/*
+ * extern functions
+ */
+cfg_p pcibr_slot_config_addr(bridge_t *, pciio_slot_t, int);
+cfg_p pcibr_func_config_addr(bridge_t *, pciio_bus_t bus, pciio_slot_t, pciio_function_t, int);
+unsigned pcibr_slot_config_get(bridge_t *, pciio_slot_t, int);
+unsigned pcibr_func_config_get(bridge_t *, pciio_slot_t, pciio_function_t, int);
+void pcibr_debug(uint32_t, devfs_handle_t, char *, ...);
+void pcibr_slot_config_set(bridge_t *, pciio_slot_t, int, unsigned);
+void pcibr_func_config_set(bridge_t *, pciio_slot_t, pciio_function_t, int, 
+								unsigned);
+/*
+ * PCIBR_DEBUG() macro and debug bitmask defines
+ */
+/* low freqency debug events (ie. initialization, resource allocation,...) */
+#define PCIBR_DEBUG_INIT	0x00000001  /* bridge init */
+#define PCIBR_DEBUG_HINTS	0x00000002  /* bridge hints */
+#define PCIBR_DEBUG_ATTACH	0x00000004  /* bridge attach */
+#define PCIBR_DEBUG_DETACH	0x00000008  /* bridge detach */
+#define PCIBR_DEBUG_ATE		0x00000010  /* bridge ATE allocation */
+#define PCIBR_DEBUG_RRB		0x00000020  /* bridge RRB allocation */
+#define PCIBR_DEBUG_RBAR	0x00000040  /* bridge RBAR allocation */
+#define PCIBR_DEBUG_PROBE	0x00000080  /* bridge device probing */
+#define PCIBR_DEBUG_INTR_ERROR  0x00000100  /* bridge error interrupt */
+#define PCIBR_DEBUG_ERROR_HDLR  0x00000200  /* bridge error handler */
+#define PCIBR_DEBUG_CONFIG	0x00000400  /* device's config space */
+#define PCIBR_DEBUG_BAR		0x00000800  /* device's BAR allocations */
+#define PCIBR_DEBUG_INTR_ALLOC	0x00001000  /* device's intr allocation */
+#define PCIBR_DEBUG_DEV_ATTACH	0x00002000  /* device's attach */
+#define PCIBR_DEBUG_DEV_DETACH	0x00004000  /* device's detach */
+#define PCIBR_DEBUG_HOTPLUG	0x00008000
+
+/* high freqency debug events (ie. map allocation, direct translation,...) */
+#define PCIBR_DEBUG_DEVREG	0x04000000  /* bridges device reg sets */
+#define PCIBR_DEBUG_PIOMAP	0x08000000  /* pcibr_piomap */
+#define PCIBR_DEBUG_PIODIR	0x10000000  /* pcibr_piotrans */
+#define PCIBR_DEBUG_DMAMAP	0x20000000  /* pcibr_dmamap */
+#define PCIBR_DEBUG_DMADIR	0x40000000  /* pcibr_dmatrans */
+#define PCIBR_DEBUG_INTR	0x80000000  /* interrupts */
+
+extern char	 *pcibr_debug_module;
+extern int	  pcibr_debug_widget;
+extern int	  pcibr_debug_slot;
+extern uint32_t pcibr_debug_mask;
+
+/* For low frequency events (ie. initialization, resource allocation,...) */
+#define PCIBR_DEBUG_ALWAYS(args) pcibr_debug args ;
+
+/* XXX: habeck: maybe make PCIBR_DEBUG() always available?  Even in non-
+ * debug kernels?  If tracing isn't enabled (i.e pcibr_debug_mask isn't
+ * set, then the overhead for this macro is just an extra 'if' check.
+ */
+/* For high frequency events (ie. map allocation, direct translation,...) */
+#if 1 || DEBUG
+#define PCIBR_DEBUG(args) PCIBR_DEBUG_ALWAYS(args)
+#else	/* DEBUG */
+#define PCIBR_DEBUG(args)
+#endif	/* DEBUG */
+
 /*
  * Bridge sets up PIO using this information.
  */
@@ -100,6 +163,8 @@
 #define	bi_flags	bi_pi.pi_flags	/* PCIBR_INTR flags */
 #define	bi_dev		bi_pi.pi_dev	/* associated pci card */
 #define	bi_lines	bi_pi.pi_lines	/* which PCI interrupt line(s) */
+#define bi_func		bi_pi.pi_func	/* handler function (when connected) */
+#define bi_arg		bi_pi.pi_arg	/* handler parameter (when connected) */
 #define bi_mustruncpu	bi_pi.pi_mustruncpu /* Where we must run. */
 #define bi_irq		bi_pi.pi_irq	/* IRQ assigned. */
 #define bi_cpu		bi_pi.pi_cpu	/* cpu assigned. */
@@ -108,9 +173,43 @@
     struct pcibr_intr_cbuf_s bi_ibuf;	/* circular buffer of wrap ptrs */
 };
 
+
+/* 
+ * PCIBR_INFO_SLOT_GET_EXT returns the external slot number that the card
+ * resides in.  (i.e the slot number silk screened on the back of the I/O 
+ * brick).  PCIBR_INFO_SLOT_GET_INT returns the internal slot (or device)
+ * number used by the pcibr code to represent that external slot (i.e to 
+ * set bit patterns in BRIDGE/PIC registers to represent the device, or to
+ * offset into an array, or ...).
+ *
+ * In BRIDGE and XBRIDGE the external slot and internal device numbering 
+ * are the same.  (0->0, 1->1, 2->2,... 7->7)  BUT in the PIC the external
+ * slot number is always 1 greater than the internal device number (1->0, 
+ * 2->1, 3->2, 4->3).  This is due to the fact that the PCI-X spec requires
+ * that the 'bridge' (i.e PIC) be designated as 'device 0', thus external
+ * slot numbering can't start at zero.
+ *
+ * PCIBR_DEVICE_TO_SLOT converts an internal device number to an external
+ * slot number.  NOTE: PCIIO_SLOT_NONE stays as PCIIO_SLOT_NONE.
+ *
+ * PCIBR_SLOT_TO_DEVICE converts an external slot number to an internal
+ * device number.  NOTE: PCIIO_SLOT_NONE stays as PCIIO_SLOT_NONE.
+ */
+#define PCIBR_INFO_SLOT_GET_EXT(info)	    (((pcibr_info_t)info)->f_slot)
+#define PCIBR_INFO_SLOT_GET_INT(info)	    (((pcibr_info_t)info)->f_dev)
+
+#define PCIBR_DEVICE_TO_SLOT(pcibr_soft, dev_num) \
+	(((dev_num) != PCIIO_SLOT_NONE) ? \
+	    (IS_PIC_SOFT((pcibr_soft)) ? ((dev_num) + 1) : (dev_num)) : \
+	    PCIIO_SLOT_NONE)
+
+#define PCIBR_SLOT_TO_DEVICE(pcibr_soft, slot) \
+        (((slot) != PCIIO_SLOT_NONE) ? \
+            (IS_PIC_SOFT((pcibr_soft)) ? ((slot) - 1) : (slot)) : \
+            PCIIO_SLOT_NONE)
+
 /*
- * per-connect point pcibr data, including
- * standard pciio data in-line:
+ * per-connect point pcibr data, including standard pciio data in-line:
  */
 struct pcibr_info_s {
     struct pciio_info_s	    f_c;	/* MUST BE FIRST. */
@@ -125,15 +224,18 @@
 #define	f_pops		f_c.c_pops	/* cached provider from c_master */
 #define	f_efunc		f_c.c_efunc	/* error handling function */
 #define	f_einfo		f_c.c_einfo	/* first parameter for efunc */
-#define	f_window	f_c.c_window	/* state of BASE regs */
-#define	f_rbase		f_c.c_rbase	/* expansion rom base */
-#define	f_rsize		f_c.c_rsize	/* expansion rom size */
-#define	f_piospace	f_c.c_piospace	/* additional I/O spaces allocated */
+#define f_window        f_c.c_window    /* state of BASE regs */
+#define	f_rwindow	f_c.c_rwindow	/* expansion ROM BASE regs */
+#define	f_rbase		f_c.c_rbase	/* expansion ROM base */
+#define	f_rsize		f_c.c_rsize	/* expansion ROM size */
+#define f_piospace      f_c.c_piospace  /* additional I/O spaces allocated */
 
     /* pcibr-specific connection state */
     int			    f_ibit[4];	/* Bridge bit for each INTx */
     pcibr_piomap_t	    f_piomap;
     int                     f_att_det_error;
+    pciio_slot_t	    f_dev;	/* which device the card represents */
+    cap_pcix_type0_t	   *f_pcix_cap;	/* pointer to the pcix capability */
 };
 
 /* =====================================================================
@@ -152,15 +254,91 @@
 struct pcibr_intr_wrap_s {
     pcibr_soft_t            iw_soft;	/* which bridge */
     volatile bridgereg_t   *iw_stat;	/* ptr to b_int_status */
+#ifdef CONFIG_IA64_SGI_SN1
     bridgereg_t             iw_intr;	/* bit in b_int_status */
+#else
+    bridgereg_t             iw_ibit;	/* bit in b_int_status */
+#endif
     pcibr_intr_list_t       iw_list;	/* ghostbusters! */
     int			    iw_hdlrcnt;	/* running handler count */
     int			    iw_shared;  /* if Bridge bit is shared */
     int			    iw_connected; /* if already connected */
 };
 
-#define	PCIBR_ISR_ERR_START	8
-#define PCIBR_ISR_MAX_ERRS 	32
+#define	PCIBR_ISR_ERR_START		8
+#define PCIBR_ISR_MAX_ERRS_BRIDGE 	32
+#define PCIBR_ISR_MAX_ERRS_PIC		45
+#define PCIBR_ISR_MAX_ERRS	PCIBR_ISR_MAX_ERRS_PIC
+
+/*
+ * PCI Base Address Register window allocation constants.
+ * To reduce the size of the internal resource mapping structures, do
+ * not use the entire PCI bus I/O address space
+ */ 
+#define PCIBR_BUS_IO_BASE      0x100000
+#define PCIBR_BUS_IO_MAX       0x0FFFFFFF
+#define PCIBR_BUS_IO_PAGE      0x100000
+
+#define PCIBR_BUS_SWIN_BASE    _PAGESZ
+#define PCIBR_BUS_SWIN_MAX     0x000FFFFF
+#define PCIBR_BUS_SWIN_PAGE    _PAGESZ
+
+#define PCIBR_BUS_MEM_BASE     0x200000
+#define PCIBR_BUS_MEM_MAX      0x3FFFFFFF
+#define PCIBR_BUS_MEM_PAGE     0x100000
+
+/* defines for pcibr_soft_s->bs_bridge_type */
+#define PCIBR_BRIDGETYPE_BRIDGE		0
+#define PCIBR_BRIDGETYPE_XBRIDGE	1
+#define PCIBR_BRIDGETYPE_PIC		2
+#define IS_XBRIDGE_SOFT(ps) (ps->bs_bridge_type == PCIBR_BRIDGETYPE_XBRIDGE)
+#define IS_PIC_SOFT(ps)     (ps->bs_bridge_type == PCIBR_BRIDGETYPE_PIC)
+#define IS_BRIDGE_SOFT(ps)  (ps->bs_bridge_type == PCIBR_BRIDGETYPE_BRIDGE)
+#define IS_XBRIDGE_OR_PIC_SOFT(ps) (IS_XBRIDGE_SOFT(ps) || IS_PIC_SOFT(ps))
+
+/*
+ * Runtime checks for workarounds.
+ */
+#define PCIBR_WAR_ENABLED(pv, pcibr_soft) \
+	((1 << XWIDGET_PART_REV_NUM_REV(pcibr_soft->bs_rev_num)) & pv)
+/*
+ * Defines for individual WARs. Each is a bitmask of applicable
+ * part revision numbers. (1 << 1) == rev A, (1 << 2) == rev B, etc.
+ */
+#define PV854697 (~0)     /* PIC: write 64bit regs as 64bits. permanent */
+#define PV854827 (~0)     /* PIC: fake widget 0xf presence bit. permanent */
+#define PV855271 (~0)     /* PIC: use virt chan iff 64-bit device. permanent */
+#define PV855272 (1 << 1) /* PIC: runaway interrupt WAR */
+#define PV856155 (1 << 1) /* PIC: arbitration WAR */
+#define PV856864 (1 << 1) /* PIC: lower timeout to free TNUMs quicker */
+#define PV856866 (1 << 1) /* PIC: avoid rrb's 0/1/8/9. */
+#define PV862253 (1 << 1) /* PIC: don't enable write req RAM parity checking */
+#define PV867308 (3 << 1) /* PIC: make LLP error interrupts FATAL for PIC */
+
+
+/* defines for pcibr_soft_s->bs_bridge_mode */
+#define PCIBR_BRIDGEMODE_PCI_33		0x0
+#define PCIBR_BRIDGEMODE_PCI_66		0x2
+#define PCIBR_BRIDGEMODE_PCIX_66	0x3
+#define PCIBR_BRIDGEMODE_PCIX_100	0x5
+#define PCIBR_BRIDGEMODE_PCIX_133	0x7
+#define BUSSPEED_MASK			0x6
+#define BUSTYPE_MASK			0x1
+
+#define IS_PCI(ps)	(!IS_PCIX(ps))
+#define IS_PCIX(ps)	((ps)->bs_bridge_mode & BUSTYPE_MASK)
+
+#define IS_33MHZ(ps)	((ps)->bs_bridge_mode == PCIBR_BRIDGEMODE_PCI_33)
+#define IS_66MHZ(ps)	(((ps)->bs_bridge_mode == PCIBR_BRIDGEMODE_PCI_66) || \
+			 ((ps)->bs_bridge_mode == PCIBR_BRIDGEMODE_PCIX_66))
+#define IS_100MHZ(ps)	((ps)->bs_bridge_mode == PCIBR_BRIDGEMODE_PCIX_100)
+#define IS_133MHZ(ps)	((ps)->bs_bridge_mode == PCIBR_BRIDGEMODE_PCIX_133)
+
+
+/* Number of PCI slots.   NOTE: this works as long as the first slot
+ * is zero.  Otherwise use ((ps->bs_max_slot+1) - ps->bs_min_slot)
+ */
+#define PCIBR_NUM_SLOTS(ps) (ps->bs_max_slot+1)
 
 /* =====================================================================
  *            Bridge Device State structure
@@ -172,7 +350,7 @@
 struct pcibr_soft_s {
     devfs_handle_t          bs_conn;		/* xtalk connection point */
     devfs_handle_t          bs_vhdl;		/* vertex owned by pcibr */
-    int                     bs_int_enable;	/* Mask of enabled intrs */
+    uint64_t                bs_int_enable;	/* Mask of enabled intrs */
     bridge_t               *bs_base;		/* PIO pointer to Bridge chip */
     char                   *bs_name;		/* hw graph name */
     xwidgetnum_t            bs_xid;		/* Bridge's xtalk ID number */
@@ -180,7 +358,11 @@
     xwidgetnum_t            bs_mxid;		/* master's xtalk ID number */
     pciio_slot_t            bs_first_slot;      /* first existing slot */
     pciio_slot_t            bs_last_slot;       /* last existing slot */
-
+    pciio_slot_t            bs_last_reset;      /* last slot to reset */
+    pciio_slot_t	    bs_min_slot;	/* lowest possible slot */
+    pciio_slot_t	    bs_max_slot;	/* highest possible slot */
+    pcibr_soft_t	    bs_peers_soft;	/* PICs other bus's soft */
+    int			    bs_busnum;		/* PIC has two pci busses */
 
     iopaddr_t               bs_dir_xbase;	/* xtalk address for 32-bit PCI direct map */
     xwidgetnum_t	    bs_dir_xport;	/* xtalk port for 32-bit PCI direct map */
@@ -188,14 +370,23 @@
     struct map             *bs_int_ate_map;	/* rmalloc map for internal ATEs */
     struct map             *bs_ext_ate_map;	/* rmalloc map for external ATEs */
     short		    bs_int_ate_size;	/* number of internal ates */
-    short		    bs_xbridge;		/* if 1 then xbridge */
-
+    short		    bs_bridge_type;	/* see defines above */
+    short		    bs_bridge_mode;	/* see defines above */
+#ifdef CONFIG_IA64_SGI_SN1
+#define bs_xbridge	    bs_bridge_type
+#endif
     int                     bs_rev_num;		/* revision number of Bridge */
 
-    unsigned                bs_dma_flags;	/* revision-implied DMA flags */
+    /* bs_dma_flags are the forced dma flags used on all DMAs. Used for
+     * working around ASIC rev issues and protocol specific requirements
+     */
+    unsigned                bs_dma_flags;	/* forced DMA flags */
 
+#ifdef CONFIG_IA64_SGI_SN1
     l1sc_t                 *bs_l1sc;            /* io brick l1 system cntr */
+#endif
     moduleid_t		    bs_moduleid;	/* io brick moduleid */
+    short		    bs_bricktype;	/* io brick type */
 
     /*
      * Lock used primarily to get mutual exclusion while managing any
@@ -222,7 +413,8 @@
 	pciio_slot_t            host_slot;
 	devfs_handle_t		slot_conn;
 
-	int			slot_status;
+        /* PCI Hot-Plug status word */
+        int 			slot_status;
 
 	/* Potentially several connection points
 	 * for this slot. bss_ninfo is how many,
@@ -299,24 +491,53 @@
 
     pcibr_intr_bits_f	       *bs_intr_bits;
 
+    /* PIC PCI-X Read Buffer Management :
+     * bs_pcix_num_funcs: the total number of PCI-X functions
+     *  on the bus
+     * bs_pcix_split_tot: total number of outstanding split
+     *  transactions requested by all functions on the bus
+     * bs_pcix_rbar_percent_allowed: the percentage of the
+     *  total number of buffers a function requested that are 
+     *  available to it, not including the 1 RBAR guaranteed 
+     *  to it.
+     * bs_pcix_rbar_inuse: number of RBARs in use.
+     * bs_pcix_rbar_avail: number of RBARs available.  NOTE:
+     *  this value can go negative if we oversubscribe the 
+     *  RBARs.  (i.e.  We have 16 RBARs but 17 functions).
+     */
+    int			    bs_pcix_num_funcs;
+    int			    bs_pcix_split_tot;
+    int			    bs_pcix_rbar_percent_allowed;
+
+    int			    bs_pcix_rbar_inuse;
+    int			    bs_pcix_rbar_avail;
+
+
     /* RRB MANAGEMENT
      * bs_rrb_fixed: bitmap of slots whose RRB
      *	allocations we should not "automatically" change
      * bs_rrb_avail: number of RRBs that have not
      *  been allocated or reserved for {even,odd} slots
-     * bs_rrb_res: number of RRBs reserved for the
+     * bs_rrb_res: number of RRBs currently reserved for the
      *	use of the index slot number
-     * bs_rrb_valid: number of RRBs marked valid
-     *	for the indexed slot number; indexes 8-15
-     *	are for the virtual channels for slots 0-7.
+     * bs_rrb_res_dflt: number of RRBs reserved at boot
+     *  time for the use of the index slot number
+     * bs_rrb_valid: number of RRBs currently marked valid
+     *	for the indexed slot/vchan number; array[slot][vchan]
+     * bs_rrb_valid_dflt: number of RRBs marked valid at boot
+     *  time for the indexed slot/vchan number; array[slot][vchan]
      */
     int                     bs_rrb_fixed;
-    int			    bs_rrb_avail[2];
-    int			    bs_rrb_res[8];
+    int                     bs_rrb_avail[2];
+    int                     bs_rrb_res[8];
     int                     bs_rrb_res_dflt[8];
+#ifdef CONFIG_IA64_SGI_SN1
     int                     bs_rrb_valid[16];
     int                     bs_rrb_valid_dflt[16];
-
+#else
+    int			    bs_rrb_valid[8][4];
+    int			    bs_rrb_valid_dflt[8][4];
+#endif
     struct {
 	/* Each Bridge interrupt bit has a single XIO
 	 * interrupt channel allocated.
@@ -347,35 +568,55 @@
      * Note that there is no locking while looking at this data structure.
      * There should not be any race between bus error code and
      * error interrupt code.. will look into this if needed.
+     *
+     * NOTE: The above discussion of error interrupt processing is
+     *       no longer true. Whether it should again be true, is
+     *       being looked into.
      */
     struct br_errintr_info {
 	int                     bserr_toutcnt;
 #ifdef LATER
 	toid_t                  bserr_toutid;	/* Timeout started by errintr */
-#endif
-	iopaddr_t               bserr_addr;	/* Address where error occurred */
-	bridgereg_t             bserr_intstat;	/* interrupts active at error time */
+#endif	/* LATER */
+	iopaddr_t               bserr_addr;	/* Address where error occured */
+	uint64_t		bserr_intstat;	/* interrupts active at error dump */
     } bs_errinfo;
 
     /*
      * PCI Bus Space allocation data structure.
-     * This info is used to satisfy the callers of pcibr_piospace_alloc
-     * interface. Most of these users need "large" amounts of PIO
-     * space (typically in Megabytes), and they generally tend to
-     * take once and never release..
-     * For Now use a simple algorithm to manage it. On allocation,
-     * Update the _base field to reflect next free address.
      *
-     * Freeing does nothing.. So, once allocated, it's gone for good.
+     * The resource mapping functions rmalloc() and rmfree() are used
+     * to manage the PCI bus I/O, small window, and memory  address 
+     * spaces.
+     *
+     * This info is used to assign PCI bus space addresses to cards
+     * via their BARs and to the callers of the pcibr_piospace_alloc()
+     * interface.
+     *
+     * Users of the pcibr_piospace_alloc() interface, such as the VME
+     * Universe chip, need PCI bus space that is not acquired by BARs.
+     * Most of these users need "large" amounts of PIO space (typically
+     * in Megabytes), and they generally tend to take once and never
+     * release. 
      */
+#ifdef CONFIG_IA64_SGI_SN1
     struct br_pcisp_info {
-	iopaddr_t               pci_io_base;
-	iopaddr_t               pci_io_last;
-	iopaddr_t               pci_swin_base;
-	iopaddr_t               pci_swin_last;
-	iopaddr_t               pci_mem_base;
-	iopaddr_t               pci_mem_last;
+        iopaddr_t               pci_io_base;
+        iopaddr_t               pci_io_last;
+        iopaddr_t               pci_swin_base;
+        iopaddr_t               pci_swin_last;
+        iopaddr_t               pci_mem_base;
+        iopaddr_t               pci_mem_last;
     } bs_spinfo;
+#endif	/* CONFIG_IA64_SGI_SN1 */
+    struct pciio_win_map_s	bs_io_win_map;	/* I/O addr space */
+    struct pciio_win_map_s	bs_swin_map;	/* Small window addr space */
+    struct pciio_win_map_s	bs_mem_win_map;	/* Memory addr space */
+
+    int                   bs_bus_addr_status;    /* Bus space status */
+
+#define PCIBR_BUS_ADDR_MEM_FREED       1  /* Reserved PROM mem addr freed */
+#define PCIBR_BUS_ADDR_IO_FREED        2  /* Reserved PROM I/O addr freed */
 
     struct bs_errintr_stat_s {
 	uint32_t              bs_errcount_total;
@@ -437,13 +678,6 @@
 #define pcibr_soft_get(v)       ((pcibr_soft_t)hwgraph_fastinfo_get((v)))
 #define pcibr_soft_set(v,i)     (hwgraph_fastinfo_set((v), (arbitrary_info_t)(i)))
 
-/* Use io spin locks. This ensures that all the PIO writes from a particular
- * CPU to a particular IO device are synched before the start of the next
- * set of PIO operations to the same device.
- */
-#define pcibr_lock(pcibr_soft)		io_splock(&pcibr_soft->bs_lock)
-#define pcibr_unlock(pcibr_soft,s)	io_spunlock(&pcibr_soft->bs_lock,s)
-
 /*
  * mem alloc/free macros
  */
@@ -455,13 +689,37 @@
 #define NEW(ptr)	NEWA(ptr,1)
 #define DEL(ptr)	DELA(ptr,1)
 
-typedef volatile unsigned *cfg_p;
-typedef volatile bridgereg_t *reg_p;
+#ifndef CONFIG_IA64_SGI_SN1
+/*
+ * Additional PIO spaces per slot are
+ * recorded in this structure.
+ */
+struct pciio_piospace_s {
+    pciio_piospace_t        next;	/* another space for this device */
+    char                    free;	/* 1 if free, 0 if in use */
+    pciio_space_t           space;	/* Which space is in use */
+    iopaddr_t               start;	/* Starting address of the PIO space */
+    size_t                  count;	/* size of PIO space */
+};
+#endif	/* CONFIG_IA64_SGI_SN1 */
 
-#define PCIBR_RRB_SLOT_VIRTUAL  8
-#define PCIBR_VALID_SLOT(s)     (s < 8)
+/* Use io spin locks. This ensures that all the PIO writes from a particular
+ * CPU to a particular IO device are synched before the start of the next
+ * set of PIO operations to the same device.
+ */
+#ifdef PCI_LATER
+#define pcibr_lock(pcibr_soft)		io_splock(pcibr_soft->bs_lock)
+#define pcibr_unlock(pcibr_soft, s)	io_spunlock(pcibr_soft->bs_lock,s)
+#else
+#define pcibr_lock(pcibr_soft)		1
+#define pcibr_unlock(pcibr_soft, s)	
+#endif	/* PCI_LATER */
+
+#ifndef CONFIG_IA64_SGI_SN1
+#define PCIBR_VALID_SLOT(ps, s)     (s < PCIBR_NUM_SLOTS(ps))
 #define PCIBR_D64_BASE_UNSET    (0xFFFFFFFFFFFFFFFF)
 #define PCIBR_D32_BASE_UNSET    (0xFFFFFFFF)
+#endif
 #define INFO_LBL_PCIBR_ASIC_REV "_pcibr_asic_rev"
 
 #define PCIBR_SOFT_LIST 1
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/pci/pciio.h linux-2.4.21-pre6/include/asm-ia64/sn/pci/pciio.h
--- linux-2.4.20/include/asm-ia64/sn/pci/pciio.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/pci/pciio.h	2003-03-26 23:48:57.000000000 +0000
@@ -13,6 +13,7 @@
  * pciio.h -- platform-independent PCI interface
  */
 
+#include <linux/config.h>
 #include <asm/sn/ioerror.h>
 #include <asm/sn/driver.h>
 #include <asm/sn/hcl.h>
@@ -207,6 +208,9 @@
 typedef struct pciio_intr_s *pciio_intr_t;
 typedef struct pciio_info_s *pciio_info_t;
 typedef struct pciio_piospace_s *pciio_piospace_t;
+typedef struct pciio_win_info_s *pciio_win_info_t;
+typedef struct pciio_win_map_s *pciio_win_map_t;
+typedef struct pciio_win_alloc_s *pciio_win_alloc_t;
 
 /* PIO MANAGEMENT */
 
@@ -382,8 +386,13 @@
 typedef void
 pciio_intr_free_f       (pciio_intr_t intr_hdl);
 
+#ifdef CONFIG_IA64_SGI_SN1
 typedef int
 pciio_intr_connect_f    (pciio_intr_t intr_hdl);	/* pciio intr resource handle */
+#else
+typedef int
+pciio_intr_connect_f    (pciio_intr_t intr_hdl, intr_func_t intr_func, intr_arg_t intr_arg);	/* pciio intr resource handle */
+#endif
 
 typedef void
 pciio_intr_disconnect_f (pciio_intr_t intr_hdl);
@@ -627,6 +636,44 @@
 			devfs_handle_t pcicard,   /* vertex created by pciio_device_register */
                         int drv_flags);
 
+
+/* create and initialize empty window mapping resource */
+extern pciio_win_map_t
+pciio_device_win_map_new(pciio_win_map_t win_map,	/* preallocated win map structure */
+			 size_t region_size,		/* size of region to be tracked */
+			 size_t page_size);		/* allocation page size */
+
+/* destroy window mapping resource freeing up ancillary resources */
+extern void
+pciio_device_win_map_free(pciio_win_map_t win_map);	/* preallocated win map structure */
+
+/* populate window mapping with free range of addresses */
+extern void
+pciio_device_win_populate(pciio_win_map_t win_map,	/* win map */
+			  iopaddr_t ioaddr,		/* base address of free range */
+			  size_t size);			/* size of free range */
+
+/* allocate window from mapping resource */
+#ifdef CONFIG_IA64_SGI_SN1
+extern iopaddr_t
+pciio_device_win_alloc(pciio_win_map_t win_map,		/* win map */
+		       pciio_win_alloc_t win_alloc,	/* opaque allocation cookie */
+		       size_t size,			/* size of allocation */
+		       size_t align);			/* alignment of allocation */
+#else
+extern iopaddr_t
+pciio_device_win_alloc(pciio_win_map_t win_map,		/* win map */
+		       pciio_win_alloc_t win_alloc,	/* opaque allocation cookie */
+		       size_t start,			/* start unit, or 0 */
+		       size_t size,			/* size of allocation */
+		       size_t align);			/* alignment of allocation */
+#endif
+
+/* free previously allocated window */
+extern void
+pciio_device_win_free(pciio_win_alloc_t win_alloc);	/* opaque allocation cookie */
+
+
 /*
  * Generic PCI interface, for use with all PCI providers
  * and all PCI devices.
@@ -644,52 +691,6 @@
 extern ulong            pciio_pio_mapsz_get(pciio_piomap_t pciio_piomap);
 extern caddr_t          pciio_pio_kvaddr_get(pciio_piomap_t pciio_piomap);
 
-#ifdef LATER
-#ifdef USE_PCI_PIO
-extern uint8_t 		pciio_pio_read8(volatile uint8_t *addr);
-extern uint16_t 	pciio_pio_read16(volatile uint16_t *addr);
-extern uint32_t 	pciio_pio_read32(volatile uint32_t *addr);
-extern uint64_t 	pciio_pio_read64(volatile uint64_t *addr);
-extern void 		pciio_pio_write8(uint8_t val, volatile uint8_t *addr);
-extern void 		pciio_pio_write16(uint16_t val, volatile uint16_t *addr);
-extern void 		pciio_pio_write32(uint32_t val, volatile uint32_t *addr);
-extern void 		pciio_pio_write64(uint64_t val, volatile uint64_t *addr);
-#else /* !USE_PCI_PIO */
-__inline uint8_t pciio_pio_read8(volatile uint8_t *addr)
-{ 
-	return *addr; 
-}
-__inline uint16_t pciio_pio_read16(volatile uint16_t *addr)
-{
-	return *addr; 
-}
-__inline uint32_t pciio_pio_read32(volatile uint32_t *addr)
-{
-	return *addr; 
-}
-__inline uint64_t pciio_pio_read64(volatile uint64_t *addr)
-{
-	return *addr;
-}
-__inline void pciio_pio_write8(uint8_t val, volatile uint8_t *addr)
-{
-	*addr = val;
-}
-__inline void pciio_pio_write16(uint16_t val, volatile uint16_t *addr)
-{
-	*addr = val;
-}
-__inline void pciio_pio_write32(uint32_t val, volatile uint32_t *addr)
-{
-	*addr = val;
-}
-__inline void pciio_pio_write64(uint64_t val, volatile uint64_t *addr)
-{
-	*addr = val;
-}
-#endif /* USE_PCI_PIO */
-#endif	/* LATER */
-
 /* Generic PCI dma interfaces */
 extern devfs_handle_t     pciio_dma_dev_get(pciio_dmamap_t pciio_dmamap);
 
@@ -701,8 +702,10 @@
 /* Generic pci slot information access interface */
 extern pciio_info_t     pciio_info_chk(devfs_handle_t vhdl);
 extern pciio_info_t     pciio_info_get(devfs_handle_t vhdl);
+extern pciio_info_t     pciio_hostinfo_get(devfs_handle_t vhdl);
 extern void             pciio_info_set(devfs_handle_t vhdl, pciio_info_t widget_info);
 extern devfs_handle_t     pciio_info_dev_get(pciio_info_t pciio_info);
+extern devfs_handle_t     pciio_info_hostdev_get(pciio_info_t pciio_info);
 extern pciio_bus_t	pciio_info_bus_get(pciio_info_t pciio_info);
 extern pciio_slot_t     pciio_info_slot_get(pciio_info_t pciio_info);
 extern pciio_function_t	pciio_info_function_get(pciio_info_t pciio_info);
@@ -718,7 +721,7 @@
 extern size_t		pciio_info_bar_size_get(pciio_info_t, int);
 extern iopaddr_t	pciio_info_rom_base_get(pciio_info_t);
 extern size_t		pciio_info_rom_size_get(pciio_info_t);
-
+extern int		pciio_info_type1_get(pciio_info_t);
 extern int              pciio_error_handler(devfs_handle_t, int, ioerror_mode_t, ioerror_t *);
 extern int		pciio_dma_enabled(devfs_handle_t);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/pci/pciio_private.h linux-2.4.21-pre6/include/asm-ia64/sn/pci/pciio_private.h
--- linux-2.4.20/include/asm-ia64/sn/pci/pciio_private.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/pci/pciio_private.h	2003-03-26 23:48:57.000000000 +0000
@@ -10,6 +10,7 @@
 #define _ASM_SN_PCI_PCIIO_PRIVATE_H
 
 #include <asm/sn/pci/pciio.h>
+#include <asm/sn/pci/pci_defs.h>
 
 /*
  * pciio_private.h -- private definitions for pciio
@@ -49,6 +50,8 @@
     devfs_handle_t            pi_dev;	/* associated pci card */
     device_desc_t	    pi_dev_desc;	/* override device descriptor */
     pciio_intr_line_t       pi_lines;	/* which interrupt line(s) */
+    intr_func_t             pi_func;	/* handler function (when connected) */
+    intr_arg_t              pi_arg;	/* handler parameter (when connected) */
     cpuid_t                 pi_mustruncpu; /* Where we must run. */
     int                     pi_irq;     /* IRQ assigned */
     int                     pi_cpu;     /* cpu assigned */
@@ -59,6 +62,39 @@
 #define PCIIO_INTR_NOTHREAD	2	/* interrupt handler wants to be called at interrupt level */
 
 /*
+ * Some PCI provider implementations keep track of PCI window Base Address
+ * Register (BAR) address range assignment via the rmalloc()/rmfree() arena
+ * management routines.  These implementations use the following data
+ * structure for each allocation address space (e.g. memory, I/O, small
+ * window, etc.).
+ *
+ * The ``page size'' encodes the minimum allocation unit and must be a power
+ * of 2.  The main use of this allocation ``page size'' is to control the
+ * number of free address ranges that the mapping allocation software will
+ * need to track.  Smaller values will allow more efficient use of the address
+ * ranges but will result in much larger allocation map structures ...  For
+ * instance, if we want to manage allocations for a 256MB address range,
+ * choosing a 1MB allocation page size will result in up to 1MB being wasted
+ * for allocation requests smaller than 1MB.  The worst case allocation
+ * pattern for the allocation software to track would be a pattern of 1MB
+ * allocated, 1MB free.  This results in the need to track up to 128 free
+ * ranges.
+ */
+struct pciio_win_map_s {
+	struct map	*wm_map;	/* window address map */
+	int		wm_page_size;	/* allocation ``page size'' */
+};
+
+/*
+ * Opaque structure used to keep track of window allocation information.
+ */
+struct pciio_win_alloc_s {
+	pciio_win_map_t	wa_map;		/* window map allocation is from */
+	unsigned long	wa_base;	/* allocation starting page number */
+	size_t		wa_pages;	/* number of pages in allocation */
+};
+
+/*
  * Each PCI Card has one of these.
  */
 
@@ -76,17 +112,17 @@
     error_handler_f        *c_efunc;	/* error handling function */
     error_handler_arg_t     c_einfo;	/* first parameter for efunc */
 
-    struct {				/* state of BASE regs */
-	pciio_space_t		w_space;
-	iopaddr_t		w_base;
-	size_t			w_size;
-        int                     w_devio_index;  /* DevIO[] register used to
-                                                   access this window */
-    }			    c_window[6];
-
-    unsigned		    c_rbase;	/* EXPANSION ROM base addr */
-    unsigned		    c_rsize;	/* EXPANSION ROM size (bytes) */
-
+    struct pciio_win_info_s {           /* state of BASE regs */
+        pciio_space_t           w_space;
+        iopaddr_t               w_base;
+        size_t                  w_size;
+        int                     w_devio_index;   /* DevIO[] register used to
+                                                    access this window */
+	struct pciio_win_alloc_s w_win_alloc;    /* window allocation cookie */
+    }                       c_window[PCI_CFG_BASE_ADDRS + 1];
+#define c_rwindow	c_window[PCI_CFG_BASE_ADDRS]	/* EXPANSION ROM window */
+#define c_rbase		c_rwindow.w_base		/* EXPANSION ROM base addr */
+#define c_rsize		c_rwindow.w_size		/* EXPANSION ROM size (bytes) */
     pciio_piospace_t	    c_piospace;	/* additional I/O spaces allocated */
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/pci/pic.h linux-2.4.21-pre6/include/asm-ia64/sn/pci/pic.h
--- linux-2.4.20/include/asm-ia64/sn/pci/pic.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/pci/pic.h	2003-03-26 23:49:00.000000000 +0000
@@ -0,0 +1,2001 @@
+/* $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) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+#ifndef _ASM_SN_PCI_PIC_H
+#define _ASM_SN_PCI_PIC_H
+
+
+/*
+ * The PIC ASIC is a follow-on to the Bridge and Xbridge ASICs.
+ * It shares many of the same registers as those chips and therefore
+ * the primary structure for the PIC will be bridge_s as defined
+ * in irix/kern/sys/PCI/bridge.h.   This file is intended as a complement
+ * to bridge.h, which includes this file.  
+ */
+
+/*
+ * PIC AS DEVICE ZERO
+ * ------------------
+ *
+ * PIC handles PCI/X busses.  PCI/X requires that the 'bridge' (i.e. PIC)
+ * be designated as 'device 0'.   That is a departure from earlier SGI
+ * PCI bridges.  Because of that we use config space 1 to access the
+ * config space of the first actual PCI device on the bus. 
+ * Here's what the PIC manual says:
+ *
+ *     The current PCI-X bus specification now defines that the parent
+ *     hosts bus bridge (PIC for example) must be device 0 on bus 0. PIC
+ *     reduced the total number of devices from 8 to 4 and removed the
+ *     device registers and windows, now only supporting devices 0,1,2, and
+ *     3. PIC did leave all 8 configuration space windows. The reason was
+ *     there was nothing to gain by removing them. Here in lies the problem.
+ *     The device numbering we do using 0 through 3 is unrelated to the device
+ *     numbering which PCI-X requires in configuration space. In the past we
+ *     correlated Configs pace and our device space 0 <-> 0, 1 <-> 1, etc.
+ *     PCI-X requires we start a 1, not 0 and currently the PX brick
+ *     does associate our:
+ * 
+ *         device 0 with configuration space window 1,
+ *         device 1 with configuration space window 2, 
+ *         device 2 with configuration space window 3,
+ *         device 3 with configuration space window 4.
+ *
+ * The net effect is that all config space access are off-by-one with 
+ * relation to other per-slot accesses on the PIC.   
+ * Here is a table that shows some of that:
+ *
+ *                               Internal Slot#
+ *           |
+ *           |     0         1        2         3
+ * ----------|---------------------------------------
+ * config    |  0x21000   0x22000  0x23000   0x24000
+ *           |
+ * even rrb  |  0[0]      n/a      1[0]      n/a	[] == implied even/odd
+ *           |
+ * odd rrb   |  n/a       0[1]     n/a       1[1]
+ *           |
+ * int dev   |  00       01        10        11
+ *           |
+ * ext slot# |  1        2         3         4
+ * ----------|---------------------------------------
+ */
+
+
+#ifndef __ASSEMBLY__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// #include <sys/types.h>
+#include <asm/sn/pci/pciio.h>
+
+
+/*********************************************************************
+ *    bus provider function table
+ *
+ *	Normally, this table is only handed off explicitly
+ *	during provider initialization, and the PCI generic
+ *	layer will stash a pointer to it in the vertex; however,
+ *	exporting it explicitly enables a performance hack in
+ *	the generic PCI provider where if we know at compile
+ *	time that the only possible PCI provider is a
+ *	pcibr, we can go directly to this ops table.
+ */
+
+extern pciio_provider_t pci_pic_provider;
+
+
+/*********************************************************************
+ * misc defines
+ *
+ */
+#define PIC_WIDGET_PART_NUM_BUS0 0xd102
+#define PIC_WIDGET_PART_NUM_BUS1 0xd112
+#define PIC_WIDGET_MFGR_NUM 0x24
+#define PIC_WIDGET_REV_A  0x1
+
+#define IS_PIC_PART_REV_A(rev) \
+	((rev == (PIC_WIDGET_PART_NUM_BUS0 << 4 | PIC_WIDGET_REV_A)) || \
+	(rev == (PIC_WIDGET_PART_NUM_BUS1 << 4 | PIC_WIDGET_REV_A)))
+
+/*********************************************************************
+ * register offset defines
+ *
+ */
+	/* Identification Register  -- read-only */
+#define PIC_IDENTIFICATION 0x00000000
+
+	/* Status Register  -- read-only */
+#define PIC_STATUS 0x00000008
+
+	/* Upper Address Holding Register Bus Side Errors  -- read-only */
+#define PIC_UPPER_ADDR_REG_BUS_SIDE_ERRS 0x00000010
+
+	/* Lower Address Holding Register Bus Side Errors  -- read-only */
+#define PIC_LOWER_ADDR_REG_BUS_SIDE_ERRS 0x00000018
+
+	/* Control Register  -- read/write */
+#define PIC_CONTROL 0x00000020
+
+	/* PCI Request Time-out Value Register  -- read/write */
+#define PIC_PCI_REQ_TIME_OUT_VALUE 0x00000028
+
+	/* Interrupt Destination Upper Address Register  -- read/write */
+#define PIC_INTR_DEST_UPPER_ADDR 0x00000030
+
+	/* Interrupt Destination Lower Address Register  -- read/write */
+#define PIC_INTR_DEST_LOWER_ADDR 0x00000038
+
+	/* Command Word Holding Register Bus Side  -- read-only */
+#define PIC_CMD_WORD_REG_BUS_SIDE 0x00000040
+
+	/* LLP Configuration Register (Bus 0 Only)  -- read/write */
+#define PIC_LLP_CFG_REG_(BUS_0_ONLY) 0x00000048
+
+	/* PCI Target Flush Register  -- read-only */
+#define PIC_PCI_TARGET_FLUSH 0x00000050
+
+	/* Command Word Holding Register Link Side  -- read-only */
+#define PIC_CMD_WORD_REG_LINK_SIDE 0x00000058
+
+	/* Response Buffer Error Upper Address Holding  -- read-only */
+#define PIC_RESP_BUF_ERR_UPPER_ADDR_ 0x00000060
+
+	/* Response Buffer Error Lower Address Holding  -- read-only */
+#define PIC_RESP_BUF_ERR_LOWER_ADDR_ 0x00000068
+
+	/* Test Pin Control Register  -- read/write */
+#define PIC_TEST_PIN_CONTROL 0x00000070
+
+	/* Address Holding Register Link Side Errors  -- read-only */
+#define PIC_ADDR_REG_LINK_SIDE_ERRS 0x00000078
+
+	/* Direct Map Register  -- read/write */
+#define PIC_DIRECT_MAP 0x00000080
+
+	/* PCI Map Fault Address Register  -- read-only */
+#define PIC_PCI_MAP_FAULT_ADDR 0x00000090
+
+	/* Arbitration Priority Register  -- read/write */
+#define PIC_ARBITRATION_PRIORITY 0x000000A0
+
+	/* Internal Ram Parity Error Register  -- read-only */
+#define PIC_INTERNAL_RAM_PARITY_ERR 0x000000B0
+
+	/* PCI Time-out Register  -- read/write */
+#define PIC_PCI_TIME_OUT 0x000000C0
+
+	/* PCI Type 1 Configuration Register  -- read/write */
+#define PIC_PCI_TYPE_1_CFG 0x000000C8
+
+	/* PCI Bus Error Upper Address Holding Register  -- read-only */
+#define PIC_PCI_BUS_ERR_UPPER_ADDR_ 0x000000D0
+
+	/* PCI Bus Error Lower Address Holding Register  -- read-only */
+#define PIC_PCI_BUS_ERR_LOWER_ADDR_ 0x000000D8
+
+	/* PCIX Error Address Register  -- read-only */
+#define PIC_PCIX_ERR_ADDR 0x000000E0
+
+	/* PCIX Error Attribute Register  -- read-only */
+#define PIC_PCIX_ERR_ATTRIBUTE 0x000000E8
+
+	/* PCIX Error Data Register  -- read-only */
+#define PIC_PCIX_ERR_DATA 0x000000F0
+
+	/* PCIX Read Request Timeout Error Register  -- read-only */
+#define PIC_PCIX_READ_REQ_TIMEOUT_ERR 0x000000F8
+
+	/* Interrupt Status Register  -- read-only */
+#define PIC_INTR_STATUS 0x00000100
+
+	/* Interrupt Enable Register  -- read/write */
+#define PIC_INTR_ENABLE 0x00000108
+
+	/* Reset Interrupt Status Register  -- write-only */
+#define PIC_RESET_INTR_STATUS 0x00000110
+
+	/* Interrupt Mode Register  -- read/write */
+#define PIC_INTR_MODE 0x00000118
+
+	/* Interrupt Device Register  -- read/write */
+#define PIC_INTR_DEVICE 0x00000120
+
+	/* Host Error Field Register  -- read/write */
+#define PIC_HOST_ERR_FIELD 0x00000128
+
+	/* Interrupt Pin 0 Host Address Register  -- read/write */
+#define PIC_INTR_PIN_0_HOST_ADDR 0x00000130
+
+	/* Interrupt Pin 1 Host Address Register  -- read/write */
+#define PIC_INTR_PIN_1_HOST_ADDR 0x00000138
+
+	/* Interrupt Pin 2 Host Address Register  -- read/write */
+#define PIC_INTR_PIN_2_HOST_ADDR 0x00000140
+
+	/* Interrupt Pin 3 Host Address Register  -- read/write */
+#define PIC_INTR_PIN_3_HOST_ADDR 0x00000148
+
+	/* Interrupt Pin 4 Host Address Register  -- read/write */
+#define PIC_INTR_PIN_4_HOST_ADDR 0x00000150
+
+	/* Interrupt Pin 5 Host Address Register  -- read/write */
+#define PIC_INTR_PIN_5_HOST_ADDR 0x00000158
+
+	/* Interrupt Pin 6 Host Address Register  -- read/write */
+#define PIC_INTR_PIN_6_HOST_ADDR 0x00000160
+
+	/* Interrupt Pin 7 Host Address Register  -- read/write */
+#define PIC_INTR_PIN_7_HOST_ADDR 0x00000168
+
+	/* Error Interrupt View Register  -- read-only */
+#define PIC_ERR_INTR_VIEW 0x00000170
+
+	/* Multiple Interrupt Register  -- read-only */
+#define PIC_MULTIPLE_INTR 0x00000178
+
+	/* Force Always Interrupt 0 Register  -- write-only */
+#define PIC_FORCE_ALWAYS_INTR_0 0x00000180
+
+	/* Force Always Interrupt 1 Register  -- write-only */
+#define PIC_FORCE_ALWAYS_INTR_1 0x00000188
+
+	/* Force Always Interrupt 2 Register  -- write-only */
+#define PIC_FORCE_ALWAYS_INTR_2 0x00000190
+
+	/* Force Always Interrupt 3 Register  -- write-only */
+#define PIC_FORCE_ALWAYS_INTR_3 0x00000198
+
+	/* Force Always Interrupt 4 Register  -- write-only */
+#define PIC_FORCE_ALWAYS_INTR_4 0x000001A0
+
+	/* Force Always Interrupt 5 Register  -- write-only */
+#define PIC_FORCE_ALWAYS_INTR_5 0x000001A8
+
+	/* Force Always Interrupt 6 Register  -- write-only */
+#define PIC_FORCE_ALWAYS_INTR_6 0x000001B0
+
+	/* Force Always Interrupt 7 Register  -- write-only */
+#define PIC_FORCE_ALWAYS_INTR_7 0x000001B8
+
+	/* Force w/Pin Interrupt 0 Register  -- write-only */
+#define PIC_FORCE_PIN_INTR_0 0x000001C0
+
+	/* Force w/Pin Interrupt 1 Register  -- write-only */
+#define PIC_FORCE_PIN_INTR_1 0x000001C8
+
+	/* Force w/Pin Interrupt 2 Register  -- write-only */
+#define PIC_FORCE_PIN_INTR_2 0x000001D0
+
+	/* Force w/Pin Interrupt 3 Register  -- write-only */
+#define PIC_FORCE_PIN_INTR_3 0x000001D8
+
+	/* Force w/Pin Interrupt 4 Register  -- write-only */
+#define PIC_FORCE_PIN_INTR_4 0x000001E0
+
+	/* Force w/Pin Interrupt 5 Register  -- write-only */
+#define PIC_FORCE_PIN_INTR_5 0x000001E8
+
+	/* Force w/Pin Interrupt 6 Register  -- write-only */
+#define PIC_FORCE_PIN_INTR_6 0x000001F0
+
+	/* Force w/Pin Interrupt 7 Register  -- write-only */
+#define PIC_FORCE_PIN_INTR_7 0x000001F8
+
+	/* Device 0 Register  -- read/write */
+#define PIC_DEVICE_0 0x00000200
+
+	/* Device 1 Register  -- read/write */
+#define PIC_DEVICE_1 0x00000208
+
+	/* Device 2 Register  -- read/write */
+#define PIC_DEVICE_2 0x00000210
+
+	/* Device 3 Register  -- read/write */
+#define PIC_DEVICE_3 0x00000218
+
+	/* Device 0 Write Request Buffer Register  -- read-only */
+#define PIC_DEVICE_0_WRITE_REQ_BUF 0x00000240
+
+	/* Device 1 Write Request Buffer Register  -- read-only */
+#define PIC_DEVICE_1_WRITE_REQ_BUF 0x00000248
+
+	/* Device 2 Write Request Buffer Register  -- read-only */
+#define PIC_DEVICE_2_WRITE_REQ_BUF 0x00000250
+
+	/* Device 3 Write Request Buffer Register  -- read-only */
+#define PIC_DEVICE_3_WRITE_REQ_BUF 0x00000258
+
+	/* Even Device Response Buffer Register  -- read/write */
+#define PIC_EVEN_DEVICE_RESP_BUF 0x00000280
+
+	/* Odd Device Response Buffer Register  -- read/write */
+#define PIC_ODD_DEVICE_RESP_BUF 0x00000288
+
+	/* Read Response Buffer Status Register  -- read-only */
+#define PIC_READ_RESP_BUF_STATUS 0x00000290
+
+	/* Read Response Buffer Clear Register  -- write-only */
+#define PIC_READ_RESP_BUF_CLEAR 0x00000298
+
+	/* PCI RR 0 Upper Address Match Register  -- read-only */
+#define PIC_PCI_RR_0_UPPER_ADDR_MATCH 0x00000300
+
+	/* PCI RR 0 Lower Address Match Register  -- read-only */
+#define PIC_PCI_RR_0_LOWER_ADDR_MATCH 0x00000308
+
+	/* PCI RR 1 Upper Address Match Register  -- read-only */
+#define PIC_PCI_RR_1_UPPER_ADDR_MATCH 0x00000310
+
+	/* PCI RR 1 Lower Address Match Register  -- read-only */
+#define PIC_PCI_RR_1_LOWER_ADDR_MATCH 0x00000318
+
+	/* PCI RR 2 Upper Address Match Register  -- read-only */
+#define PIC_PCI_RR_2_UPPER_ADDR_MATCH 0x00000320
+
+	/* PCI RR 2 Lower Address Match Register  -- read-only */
+#define PIC_PCI_RR_2_LOWER_ADDR_MATCH 0x00000328
+
+	/* PCI RR 3 Upper Address Match Register  -- read-only */
+#define PIC_PCI_RR_3_UPPER_ADDR_MATCH 0x00000330
+
+	/* PCI RR 3 Lower Address Match Register  -- read-only */
+#define PIC_PCI_RR_3_LOWER_ADDR_MATCH 0x00000338
+
+	/* PCI RR 4 Upper Address Match Register  -- read-only */
+#define PIC_PCI_RR_4_UPPER_ADDR_MATCH 0x00000340
+
+	/* PCI RR 4 Lower Address Match Register  -- read-only */
+#define PIC_PCI_RR_4_LOWER_ADDR_MATCH 0x00000348
+
+	/* PCI RR 5 Upper Address Match Register  -- read-only */
+#define PIC_PCI_RR_5_UPPER_ADDR_MATCH 0x00000350
+
+	/* PCI RR 5 Lower Address Match Register  -- read-only */
+#define PIC_PCI_RR_5_LOWER_ADDR_MATCH 0x00000358
+
+	/* PCI RR 6 Upper Address Match Register  -- read-only */
+#define PIC_PCI_RR_6_UPPER_ADDR_MATCH 0x00000360
+
+	/* PCI RR 6 Lower Address Match Register  -- read-only */
+#define PIC_PCI_RR_6_LOWER_ADDR_MATCH 0x00000368
+
+	/* PCI RR 7 Upper Address Match Register  -- read-only */
+#define PIC_PCI_RR_7_UPPER_ADDR_MATCH 0x00000370
+
+	/* PCI RR 7 Lower Address Match Register  -- read-only */
+#define PIC_PCI_RR_7_LOWER_ADDR_MATCH 0x00000378
+
+	/* PCI RR 8 Upper Address Match Register  -- read-only */
+#define PIC_PCI_RR_8_UPPER_ADDR_MATCH 0x00000380
+
+	/* PCI RR 8 Lower Address Match Register  -- read-only */
+#define PIC_PCI_RR_8_LOWER_ADDR_MATCH 0x00000388
+
+	/* PCI RR 9 Upper Address Match Register  -- read-only */
+#define PIC_PCI_RR_9_UPPER_ADDR_MATCH 0x00000390
+
+	/* PCI RR 9 Lower Address Match Register  -- read-only */
+#define PIC_PCI_RR_9_LOWER_ADDR_MATCH 0x00000398
+
+	/* PCI RR 10 Upper Address Match Register  -- read-only */
+#define PIC_PCI_RR_10_UPPER_ADDR_MATCH 0x000003A0
+
+	/* PCI RR 10 Lower Address Match Register  -- read-only */
+#define PIC_PCI_RR_10_LOWER_ADDR_MATCH 0x000003A8
+
+	/* PCI RR 11 Upper Address Match Register  -- read-only */
+#define PIC_PCI_RR_11_UPPER_ADDR_MATCH 0x000003B0
+
+	/* PCI RR 11 Lower Address Match Register  -- read-only */
+#define PIC_PCI_RR_11_LOWER_ADDR_MATCH 0x000003B8
+
+	/* PCI RR 12 Upper Address Match Register  -- read-only */
+#define PIC_PCI_RR_12_UPPER_ADDR_MATCH 0x000003C0
+
+	/* PCI RR 12 Lower Address Match Register  -- read-only */
+#define PIC_PCI_RR_12_LOWER_ADDR_MATCH 0x000003C8
+
+	/* PCI RR 13 Upper Address Match Register  -- read-only */
+#define PIC_PCI_RR_13_UPPER_ADDR_MATCH 0x000003D0
+
+	/* PCI RR 13 Lower Address Match Register  -- read-only */
+#define PIC_PCI_RR_13_LOWER_ADDR_MATCH 0x000003D8
+
+	/* PCI RR 14 Upper Address Match Register  -- read-only */
+#define PIC_PCI_RR_14_UPPER_ADDR_MATCH 0x000003E0
+
+	/* PCI RR 14 Lower Address Match Register  -- read-only */
+#define PIC_PCI_RR_14_LOWER_ADDR_MATCH 0x000003E8
+
+	/* PCI RR 15 Upper Address Match Register  -- read-only */
+#define PIC_PCI_RR_15_UPPER_ADDR_MATCH 0x000003F0
+
+	/* PCI RR 15 Lower Address Match Register  -- read-only */
+#define PIC_PCI_RR_15_LOWER_ADDR_MATCH 0x000003F8
+
+	/* Buffer 0 Flush Count with Data Touch Register  -- read/write */
+#define PIC_BUF_0_FLUSH_CNT_WITH_DATA_TOUCH 0x00000400
+
+	/* Buffer 0 Flush Count w/o Data Touch Register  -- read/write */
+#define PIC_BUF_0_FLUSH_CNT_W_O_DATA_TOUCH 0x00000408
+
+	/* Buffer 0 Request in Flight Count Register  -- read/write */
+#define PIC_BUF_0_REQ_IN_FLIGHT_CNT 0x00000410
+
+	/* Buffer 0 Prefetch Request Count Register  -- read/write */
+#define PIC_BUF_0_PREFETCH_REQ_CNT 0x00000418
+
+	/* Buffer 0 Total PCI Retry Count Register  -- read/write */
+#define PIC_BUF_0_TOTAL_PCI_RETRY_CNT 0x00000420
+
+	/* Buffer 0 Max PCI Retry Count Register  -- read/write */
+#define PIC_BUF_0_MAX_PCI_RETRY_CNT 0x00000428
+
+	/* Buffer 0 Max Latency Count Register  -- read/write */
+#define PIC_BUF_0_MAX_LATENCY_CNT 0x00000430
+
+	/* Buffer 0 Clear All Register  -- read/write */
+#define PIC_BUF_0_CLEAR_ALL 0x00000438
+
+	/* Buffer 2 Flush Count with Data Touch Register  -- read/write */
+#define PIC_BUF_2_FLUSH_CNT_WITH_DATA_TOUCH 0x00000440
+
+	/* Buffer 2 Flush Count w/o Data Touch Register  -- read/write */
+#define PIC_BUF_2_FLUSH_CNT_W_O_DATA_TOUCH 0x00000448
+
+	/* Buffer 2 Request in Flight Count Register  -- read/write */
+#define PIC_BUF_2_REQ_IN_FLIGHT_CNT 0x00000450
+
+	/* Buffer 2 Prefetch Request Count Register  -- read/write */
+#define PIC_BUF_2_PREFETCH_REQ_CNT 0x00000458
+
+	/* Buffer 2 Total PCI Retry Count Register  -- read/write */
+#define PIC_BUF_2_TOTAL_PCI_RETRY_CNT 0x00000460
+
+	/* Buffer 2 Max PCI Retry Count Register  -- read/write */
+#define PIC_BUF_2_MAX_PCI_RETRY_CNT 0x00000468
+
+	/* Buffer 2 Max Latency Count Register  -- read/write */
+#define PIC_BUF_2_MAX_LATENCY_CNT 0x00000470
+
+	/* Buffer 2 Clear All Register  -- read/write */
+#define PIC_BUF_2_CLEAR_ALL 0x00000478
+
+	/* Buffer 4 Flush Count with Data Touch Register  -- read/write */
+#define PIC_BUF_4_FLUSH_CNT_WITH_DATA_TOUCH 0x00000480
+
+	/* Buffer 4 Flush Count w/o Data Touch Register  -- read/write */
+#define PIC_BUF_4_FLUSH_CNT_W_O_DATA_TOUCH 0x00000488
+
+	/* Buffer 4 Request in Flight Count Register  -- read/write */
+#define PIC_BUF_4_REQ_IN_FLIGHT_CNT 0x00000490
+
+	/* Buffer 4 Prefetch Request Count Register  -- read/write */
+#define PIC_BUF_4_PREFETCH_REQ_CNT 0x00000498
+
+	/* Buffer 4 Total PCI Retry Count Register  -- read/write */
+#define PIC_BUF_4_TOTAL_PCI_RETRY_CNT 0x000004A0
+
+	/* Buffer 4 Max PCI Retry Count Register  -- read/write */
+#define PIC_BUF_4_MAX_PCI_RETRY_CNT 0x000004A8
+
+	/* Buffer 4 Max Latency Count Register  -- read/write */
+#define PIC_BUF_4_MAX_LATENCY_CNT 0x000004B0
+
+	/* Buffer 4 Clear All Register  -- read/write */
+#define PIC_BUF_4_CLEAR_ALL 0x000004B8
+
+	/* Buffer 6 Flush Count with Data Touch Register  -- read/write */
+#define PIC_BUF_6_FLUSH_CNT_WITH_DATA_TOUCH 0x000004C0
+
+	/* Buffer 6 Flush Count w/o Data Touch Register  -- read/write */
+#define PIC_BUF_6_FLUSH_CNT_W_O_DATA_TOUCH 0x000004C8
+
+	/* Buffer 6 Request in Flight Count Register  -- read/write */
+#define PIC_BUF_6_REQ_IN_FLIGHT_CNT 0x000004D0
+
+	/* Buffer 6 Prefetch Request Count Register  -- read/write */
+#define PIC_BUF_6_PREFETCH_REQ_CNT 0x000004D8
+
+	/* Buffer 6 Total PCI Retry Count Register  -- read/write */
+#define PIC_BUF_6_TOTAL_PCI_RETRY_CNT 0x000004E0
+
+	/* Buffer 6 Max PCI Retry Count Register  -- read/write */
+#define PIC_BUF_6_MAX_PCI_RETRY_CNT 0x000004E8
+
+	/* Buffer 6 Max Latency Count Register  -- read/write */
+#define PIC_BUF_6_MAX_LATENCY_CNT 0x000004F0
+
+	/* Buffer 6 Clear All Register  -- read/write */
+#define PIC_BUF_6_CLEAR_ALL 0x000004F8
+
+	/* Buffer 8 Flush Count with Data Touch Register  -- read/write */
+#define PIC_BUF_8_FLUSH_CNT_WITH_DATA_TOUCH 0x00000500
+
+	/* Buffer 8 Flush Count w/o Data Touch Register  -- read/write */
+#define PIC_BUF_8_FLUSH_CNT_W_O_DATA_TOUCH 0x00000508
+
+	/* Buffer 8 Request in Flight Count Register  -- read/write */
+#define PIC_BUF_8_REQ_IN_FLIGHT_CNT 0x00000510
+
+	/* Buffer 8 Prefetch Request Count Register  -- read/write */
+#define PIC_BUF_8_PREFETCH_REQ_CNT 0x00000518
+
+	/* Buffer 8 Total PCI Retry Count Register  -- read/write */
+#define PIC_BUF_8_TOTAL_PCI_RETRY_CNT 0x00000520
+
+	/* Buffer 8 Max PCI Retry Count Register  -- read/write */
+#define PIC_BUF_8_MAX_PCI_RETRY_CNT 0x00000528
+
+	/* Buffer 8 Max Latency Count Register  -- read/write */
+#define PIC_BUF_8_MAX_LATENCY_CNT 0x00000530
+
+	/* Buffer 8 Clear All Register  -- read/write */
+#define PIC_BUF_8_CLEAR_ALL 0x00000538
+
+	/* Buffer 10 Flush Count with Data Touch Register  -- read/write */
+#define PIC_BUF_10_FLUSH_CNT_WITH_DATA_TOUCH 0x00000540
+
+	/* Buffer 10 Flush Count w/o Data Touch Register  -- read/write */
+#define PIC_BUF_10_FLUSH_CNT_W_O_DATA_TOUCH 0x00000548
+
+	/* Buffer 10 Request in Flight Count Register  -- read/write */
+#define PIC_BUF_10_REQ_IN_FLIGHT_CNT 0x00000550
+
+	/* Buffer 10 Prefetch Request Count Register  -- read/write */
+#define PIC_BUF_10_PREFETCH_REQ_CNT 0x00000558
+
+	/* Buffer 10 Total PCI Retry Count Register  -- read/write */
+#define PIC_BUF_10_TOTAL_PCI_RETRY_CNT 0x00000560
+
+	/* Buffer 10 Max PCI Retry Count Register  -- read/write */
+#define PIC_BUF_10_MAX_PCI_RETRY_CNT 0x00000568
+
+	/* Buffer 10 Max Latency Count Register  -- read/write */
+#define PIC_BUF_10_MAX_LATENCY_CNT 0x00000570
+
+	/* Buffer 10 Clear All Register  -- read/write */
+#define PIC_BUF_10_CLEAR_ALL 0x00000578
+
+	/* Buffer 12 Flush Count with Data Touch Register  -- read/write */
+#define PIC_BUF_12_FLUSH_CNT_WITH_DATA_TOUCH 0x00000580
+
+	/* Buffer 12 Flush Count w/o Data Touch Register  -- read/write */
+#define PIC_BUF_12_FLUSH_CNT_W_O_DATA_TOUCH 0x00000588
+
+	/* Buffer 12 Request in Flight Count Register  -- read/write */
+#define PIC_BUF_12_REQ_IN_FLIGHT_CNT 0x00000590
+
+	/* Buffer 12 Prefetch Request Count Register  -- read/write */
+#define PIC_BUF_12_PREFETCH_REQ_CNT 0x00000598
+
+	/* Buffer 12 Total PCI Retry Count Register  -- read/write */
+#define PIC_BUF_12_TOTAL_PCI_RETRY_CNT 0x000005A0
+
+	/* Buffer 12 Max PCI Retry Count Register  -- read/write */
+#define PIC_BUF_12_MAX_PCI_RETRY_CNT 0x000005A8
+
+	/* Buffer 12 Max Latency Count Register  -- read/write */
+#define PIC_BUF_12_MAX_LATENCY_CNT 0x000005B0
+
+	/* Buffer 12 Clear All Register  -- read/write */
+#define PIC_BUF_12_CLEAR_ALL 0x000005B8
+
+	/* Buffer 14 Flush Count with Data Touch Register  -- read/write */
+#define PIC_BUF_14_FLUSH_CNT_WITH_DATA_TOUCH 0x000005C0
+
+	/* Buffer 14 Flush Count w/o Data Touch Register  -- read/write */
+#define PIC_BUF_14_FLUSH_CNT_W_O_DATA_TOUCH 0x000005C8
+
+	/* Buffer 14 Request in Flight Count Register  -- read/write */
+#define PIC_BUF_14_REQ_IN_FLIGHT_CNT 0x000005D0
+
+	/* Buffer 14 Prefetch Request Count Register  -- read/write */
+#define PIC_BUF_14_PREFETCH_REQ_CNT 0x000005D8
+
+	/* Buffer 14 Total PCI Retry Count Register  -- read/write */
+#define PIC_BUF_14_TOTAL_PCI_RETRY_CNT 0x000005E0
+
+	/* Buffer 14 Max PCI Retry Count Register  -- read/write */
+#define PIC_BUF_14_MAX_PCI_RETRY_CNT 0x000005E8
+
+	/* Buffer 14 Max Latency Count Register  -- read/write */
+#define PIC_BUF_14_MAX_LATENCY_CNT 0x000005F0
+
+	/* Buffer 14 Clear All Register  -- read/write */
+#define PIC_BUF_14_CLEAR_ALL 0x000005F8
+
+	/* PCIX Read Buffer 0 Address Register  -- read-only */
+#define PIC_PCIX_READ_BUF_0_ADDR 0x00000A00
+
+	/* PCIX Read Buffer 0 Attribute Register  -- read-only */
+#define PIC_PCIX_READ_BUF_0_ATTRIBUTE 0x00000A08
+
+	/* PCIX Read Buffer 1 Address Register  -- read-only */
+#define PIC_PCIX_READ_BUF_1_ADDR 0x00000A10
+
+	/* PCIX Read Buffer 1 Attribute Register  -- read-only */
+#define PIC_PCIX_READ_BUF_1_ATTRIBUTE 0x00000A18
+
+	/* PCIX Read Buffer 2 Address Register  -- read-only */
+#define PIC_PCIX_READ_BUF_2_ADDR 0x00000A20
+
+	/* PCIX Read Buffer 2 Attribute Register  -- read-only */
+#define PIC_PCIX_READ_BUF_2_ATTRIBUTE 0x00000A28
+
+	/* PCIX Read Buffer 3 Address Register  -- read-only */
+#define PIC_PCIX_READ_BUF_3_ADDR 0x00000A30
+
+	/* PCIX Read Buffer 3 Attribute Register  -- read-only */
+#define PIC_PCIX_READ_BUF_3_ATTRIBUTE 0x00000A38
+
+	/* PCIX Read Buffer 4 Address Register  -- read-only */
+#define PIC_PCIX_READ_BUF_4_ADDR 0x00000A40
+
+	/* PCIX Read Buffer 4 Attribute Register  -- read-only */
+#define PIC_PCIX_READ_BUF_4_ATTRIBUTE 0x00000A48
+
+	/* PCIX Read Buffer 5 Address Register  -- read-only */
+#define PIC_PCIX_READ_BUF_5_ADDR 0x00000A50
+
+	/* PCIX Read Buffer 5 Attribute Register  -- read-only */
+#define PIC_PCIX_READ_BUF_5_ATTRIBUTE 0x00000A58
+
+	/* PCIX Read Buffer 6 Address Register  -- read-only */
+#define PIC_PCIX_READ_BUF_6_ADDR 0x00000A60
+
+	/* PCIX Read Buffer 6 Attribute Register  -- read-only */
+#define PIC_PCIX_READ_BUF_6_ATTRIBUTE 0x00000A68
+
+	/* PCIX Read Buffer 7 Address Register  -- read-only */
+#define PIC_PCIX_READ_BUF_7_ADDR 0x00000A70
+
+	/* PCIX Read Buffer 7 Attribute Register  -- read-only */
+#define PIC_PCIX_READ_BUF_7_ATTRIBUTE 0x00000A78
+
+	/* PCIX Read Buffer 8 Address Register  -- read-only */
+#define PIC_PCIX_READ_BUF_8_ADDR 0x00000A80
+
+	/* PCIX Read Buffer 8 Attribute Register  -- read-only */
+#define PIC_PCIX_READ_BUF_8_ATTRIBUTE 0x00000A88
+
+	/* PCIX Read Buffer 9 Address Register  -- read-only */
+#define PIC_PCIX_READ_BUF_9_ADDR 0x00000A90
+
+	/* PCIX Read Buffer 9 Attribute Register  -- read-only */
+#define PIC_PCIX_READ_BUF_9_ATTRIBUTE 0x00000A98
+
+	/* PCIX Read Buffer 10 Address Register  -- read-only */
+#define PIC_PCIX_READ_BUF_10_ADDR 0x00000AA0
+
+	/* PCIX Read Buffer 10 Attribute Register  -- read-only */
+#define PIC_PCIX_READ_BUF_10_ATTRIBUTE 0x00000AA8
+
+	/* PCIX Read Buffer 11 Address Register  -- read-only */
+#define PIC_PCIX_READ_BUF_11_ADDR 0x00000AB0
+
+	/* PCIX Read Buffer 11 Attribute Register  -- read-only */
+#define PIC_PCIX_READ_BUF_11_ATTRIBUTE 0x00000AB8
+
+	/* PCIX Read Buffer 12 Address Register  -- read-only */
+#define PIC_PCIX_READ_BUF_12_ADDR 0x00000AC0
+
+	/* PCIX Read Buffer 12 Attribute Register  -- read-only */
+#define PIC_PCIX_READ_BUF_12_ATTRIBUTE 0x00000AC8
+
+	/* PCIX Read Buffer 13 Address Register  -- read-only */
+#define PIC_PCIX_READ_BUF_13_ADDR 0x00000AD0
+
+	/* PCIX Read Buffer 13 Attribute Register  -- read-only */
+#define PIC_PCIX_READ_BUF_13_ATTRIBUTE 0x00000AD8
+
+	/* PCIX Read Buffer 14 Address Register  -- read-only */
+#define PIC_PCIX_READ_BUF_14_ADDR 0x00000AE0
+
+	/* PCIX Read Buffer 14 Attribute Register  -- read-only */
+#define PIC_PCIX_READ_BUF_14_ATTRIBUTE 0x00000AE8
+
+	/* PCIX Read Buffer 15 Address Register  -- read-only */
+#define PIC_PCIX_READ_BUF_15_ADDR 0x00000AF0
+
+	/* PCIX Read Buffer 15 Attribute Register  -- read-only */
+#define PIC_PCIX_READ_BUF_15_ATTRIBUTE 0x00000AF8
+
+	/* PCIX Write Buffer 0 Address Register  -- read-only */
+#define PIC_PCIX_WRITE_BUF_0_ADDR 0x00000B00
+
+	/* PCIX Write Buffer 0 Attribute Register  -- read-only */
+#define PIC_PCIX_WRITE_BUF_0_ATTRIBUTE 0x00000B08
+
+	/* PCIX Write Buffer 0 Valid Register  -- read-only */
+#define PIC_PCIX_WRITE_BUF_0_VALID 0x00000B10
+
+	/* PCIX Write Buffer 1 Address Register  -- read-only */
+#define PIC_PCIX_WRITE_BUF_1_ADDR 0x00000B20
+
+	/* PCIX Write Buffer 1 Attribute Register  -- read-only */
+#define PIC_PCIX_WRITE_BUF_1_ATTRIBUTE 0x00000B28
+
+	/* PCIX Write Buffer 1 Valid Register  -- read-only */
+#define PIC_PCIX_WRITE_BUF_1_VALID 0x00000B30
+
+	/* PCIX Write Buffer 2 Address Register  -- read-only */
+#define PIC_PCIX_WRITE_BUF_2_ADDR 0x00000B40
+
+	/* PCIX Write Buffer 2 Attribute Register  -- read-only */
+#define PIC_PCIX_WRITE_BUF_2_ATTRIBUTE 0x00000B48
+
+	/* PCIX Write Buffer 2 Valid Register  -- read-only */
+#define PIC_PCIX_WRITE_BUF_2_VALID 0x00000B50
+
+	/* PCIX Write Buffer 3 Address Register  -- read-only */
+#define PIC_PCIX_WRITE_BUF_3_ADDR 0x00000B60
+
+	/* PCIX Write Buffer 3 Attribute Register  -- read-only */
+#define PIC_PCIX_WRITE_BUF_3_ATTRIBUTE 0x00000B68
+
+	/* PCIX Write Buffer 3 Valid Register  -- read-only */
+#define PIC_PCIX_WRITE_BUF_3_VALID 0x00000B70
+
+	/* PCIX Write Buffer 4 Address Register  -- read-only */
+#define PIC_PCIX_WRITE_BUF_4_ADDR 0x00000B80
+
+	/* PCIX Write Buffer 4 Attribute Register  -- read-only */
+#define PIC_PCIX_WRITE_BUF_4_ATTRIBUTE 0x00000B88
+
+	/* PCIX Write Buffer 4 Valid Register  -- read-only */
+#define PIC_PCIX_WRITE_BUF_4_VALID 0x00000B90
+
+	/* PCIX Write Buffer 5 Address Register  -- read-only */
+#define PIC_PCIX_WRITE_BUF_5_ADDR 0x00000BA0
+
+	/* PCIX Write Buffer 5 Attribute Register  -- read-only */
+#define PIC_PCIX_WRITE_BUF_5_ATTRIBUTE 0x00000BA8
+
+	/* PCIX Write Buffer 5 Valid Register  -- read-only */
+#define PIC_PCIX_WRITE_BUF_5_VALID 0x00000BB0
+
+	/* PCIX Write Buffer 6 Address Register  -- read-only */
+#define PIC_PCIX_WRITE_BUF_6_ADDR 0x00000BC0
+
+	/* PCIX Write Buffer 6 Attribute Register  -- read-only */
+#define PIC_PCIX_WRITE_BUF_6_ATTRIBUTE 0x00000BC8
+
+	/* PCIX Write Buffer 6 Valid Register  -- read-only */
+#define PIC_PCIX_WRITE_BUF_6_VALID 0x00000BD0
+
+	/* PCIX Write Buffer 7 Address Register  -- read-only */
+#define PIC_PCIX_WRITE_BUF_7_ADDR 0x00000BE0
+
+	/* PCIX Write Buffer 7 Attribute Register  -- read-only */
+#define PIC_PCIX_WRITE_BUF_7_ATTRIBUTE 0x00000BE8
+
+	/* PCIX Write Buffer 7 Valid Register  -- read-only */
+#define PIC_PCIX_WRITE_BUF_7_VALID 0x00000BF0
+
+/*********************************************************************
+ * misc typedefs
+ *
+ */
+typedef uint64_t picreg_t;
+
+/*********************************************************************
+ * PIC register structures
+ *
+ */
+
+/*
+ * Identification Register
+ *
+ * The Identification register is a read only register used by the host CPU
+ * during configuration to determine the type of the widget. The format is
+ * the same as defined in IEEE 1149.1 JTAG Device Identification Register.
+ */
+	typedef union pic_id_reg_u {
+		picreg_t	pic_id_reg_regval;
+		struct {
+			picreg_t          :	32; /* 63:32 */
+			picreg_t rev_num  :	4; /* 31:28 */
+			picreg_t part_num :	16; /* 27:12 */
+			picreg_t mfg_num  :	11; /* 11:1 */
+			picreg_t          :	1; /* 0:0 */
+		} pic_id_reg_fld_s;
+	} pic_id_reg_u_t;
+/*
+ * Status Register
+ *
+ * The status register is a read register which holds status information of the
+ * Bus Subsection.
+ */
+	typedef union pic_stat_reg_u {
+		picreg_t	pic_stat_reg_regval;
+		struct {
+			picreg_t                :	28; /* 63:36 */
+			picreg_t pci_x_speed    :	2; /* 35:34 */
+			picreg_t pci_x_active   :	1; /* 33:33 */
+			picreg_t                :	1; /* 32:32 */
+			picreg_t llp_rec_cnt    :	8; /* 31:24 */
+			picreg_t llp_tx_cnt     :	8; /* 23:16 */
+			picreg_t rx_credit_cnt  :	4; /* 15:12 */
+			picreg_t tx_credit_cnt  :	4; /* 11:8 */
+			picreg_t pci_misc_input :	8; /* 7:0 */
+		} pic_stat_reg_fld_s;
+	} pic_stat_reg_u_t;
+/*
+ * Upper Address Holding Register Bus Side Errors
+ *
+ * The upper address holding register is a read only register which contains
+ * the upper 16-bits of the address when certain error occurs (see error cases
+ * chapter). Subsequent errors are not logged until the error is cleared. The
+ * last logged value is held until the group is cleared and enabled.
+ */
+	typedef union pic_upper_bus_err_u {
+		picreg_t	pic_upper_bus_err_regval;
+		struct {
+			picreg_t          :	32; /* 63:32 */
+			picreg_t          :	16; /* 31:16 */
+			picreg_t upp_addr :	16; /* 15:0 */
+		} pic_upper_bus_err_fld_s;
+	} pic_upper_bus_err_u_t;
+/*
+ * Lower Address Holding Register Bus Side Errors
+ *
+ * The lower address holding register is a read only register which contains
+ * the address which either can be accessed as a word or double word. Sub-
+ * sequent errors are not logged until the error is cleared. The last logged
+ * value is held until the group is cleared and enabled.
+ */
+	typedef union pic_lower_bus_err_u {
+		picreg_t	pic_lower_bus_err_regval;
+		struct {
+			picreg_t          :	16; /* 63:48 */
+			picreg_t upp_addr :	16; /* 47:32 */
+			picreg_t low_addr :	32; /* 31:0 */
+		} pic_lower_bus_err_fld_s;
+	} pic_lower_bus_err_u_t;
+/*
+ * Control Register
+ *
+ * The control register is a read/write register which holds control informa-
+ * tion for the bus subsection.
+ */
+	typedef union pic_control_reg_u {
+		picreg_t	pic_control_reg_regval;
+		struct {
+			picreg_t                :	32; /* 63:32 */
+			picreg_t                :	4; /* 31:28 */
+			picreg_t rst_pin_n      :	4; /* 27:24 */
+			picreg_t                :	1; /* 23:23 */
+			picreg_t mem_swap       :	1; /* 22:22 */
+			picreg_t page_size      :	1; /* 21:21 */
+			picreg_t                :	4; /* 20:17 */
+			picreg_t f_bad_pkt      :	1; /* 16:16 */
+			picreg_t llp_xbar_crd   :	4; /* 15:12 */
+			picreg_t clr_rllp_cnt   :	1; /* 11:11 */
+			picreg_t clr_tllp_cnt   :	1; /* 10:10 */
+			picreg_t sys_end        :	1; /* 9:9 */
+			picreg_t                :	3; /* 8:6 */
+			picreg_t pci_speed      :	2; /* 5:4 */
+			picreg_t widget_id      :	4; /* 3:0 */
+		} pic_control_reg_fld_s;
+	} pic_control_reg_u_t;
+/*
+ * PCI/PCI-X Request Time-out Value Register
+ *
+ * This register contains the reload value for the response timer. The request
+ * timer counts every 960 nS (32 PCI clocks)
+ */
+	typedef union pic_pci_req_to_u {
+		picreg_t	pic_pci_req_to_regval;
+		struct {
+			picreg_t          :	32; /* 63:32 */
+			picreg_t          :	12; /* 31:20 */
+			picreg_t time_out :	20; /* 19:0 */
+		} pic_pci_req_to_fld_s;
+	} pic_pci_req_to_u_t;
+/*
+ * Interrupt Destination Upper Address Register
+ *
+ * The interrupt destination upper address register is a read/write register
+ * containing the upper 16-bits of address of the host to which the interrupt
+ * is targeted. In addition the target ID is also contained in this register for
+ * use in Crosstalk mode.
+ */
+	typedef union pic_int_desc_upper_u {
+		picreg_t	pic_int_desc_upper_regval;
+		struct {
+			picreg_t           :	32; /* 63:32 */
+			picreg_t           :	12; /* 31:20 */
+			picreg_t target_id :	4; /* 19:16 */
+			picreg_t upp_addr  :	16; /* 15:0 */
+		} pic_int_desc_upper_fld_s;
+	} pic_int_desc_upper_u_t;
+/*
+ * Interrupt Destination Lower Address Register
+ *
+ * The interrupt destination lower address register is a read/write register
+ * which contains the entire address of the host to which the interrupt is tar-
+ * geted. In addition the target ID is also contained in this register for use in
+ * Crosstalk mode.
+ */
+	typedef union pic_int_desc_lower_u {
+		picreg_t	pic_int_desc_lower_regval;
+		struct {
+			picreg_t           :	12; /* 63:52 */
+			picreg_t target_id :	4; /* 51:48 */
+			picreg_t upp_addr  :	16; /* 47:32 */
+			picreg_t low_addr  :	32; /* 31:0 */
+		} pic_int_desc_lower_fld_s;
+	} pic_int_desc_lower_u_t;
+/*
+ * Command Word Holding Register Bus Side Errors
+ *
+ * The command word holding is a read register that holds the command
+ * word of a Crosstalk packet when errors occur on the link side (see error
+ * chapter). Errors are indicated with error bits in the interrupt status regis-
+ * ter. Subsequent errors are not logged until the interrupt is cleared..
+ */
+	typedef union pic_cmd_word_bus_err_u {
+		picreg_t	pic_cmd_word_bus_err_regval;
+		struct {
+			picreg_t          :	32; /* 63:32 */
+			picreg_t didn     :	4; /* 31:28 */
+			picreg_t sidn     :	4; /* 27:24 */
+			picreg_t pactyp   :	4; /* 23:20 */
+			picreg_t tnum     :	5; /* 19:15 */
+			picreg_t coherent :	1; /* 14:14 */
+			picreg_t ds       :	2; /* 13:12 */
+			picreg_t gbr      :	1; /* 11:11 */
+			picreg_t vbpm     :	1; /* 10:10 */
+			picreg_t error    :	1; /* 9:9 */
+			picreg_t barrier  :	1; /* 8:8 */
+			picreg_t          :	8; /* 7:0 */
+		} pic_cmd_word_bus_err_fld_s;
+	} pic_cmd_word_bus_err_u_t;
+/*
+ * LLP Configuration Register
+ *
+ * This register contains the configuration information for the LLP modules
+ * and is only valid on bus 0 side.
+ */
+	typedef union pic_llp_cfg_u {
+		picreg_t	pic_llp_cfg_regval;
+		struct {
+			picreg_t                 :	32; /* 63:32 */
+			picreg_t                 :	6; /* 31:26 */
+			picreg_t llp_maxretry    :	10; /* 25:16 */
+			picreg_t llp_nulltimeout :	6; /* 15:10 */
+			picreg_t llp_maxburst    :	10; /* 9:0 */
+		} pic_llp_cfg_fld_s;
+	} pic_llp_cfg_u_t;
+/*
+ * PCI/PCI-X Target Flush Register
+ *
+ * When read, this register will return a 0x00 after all previous transfers to
+ * the PCI bus subsection have completed.
+ */
+
+/*
+ * Command Word Holding Register Link Side Errors
+ *
+ * The command word holding is a read-only register that holds the com-
+ * mand word of a Crosstalk packet when request fifo overflow or unexpect-
+ * ed response errors occur. Errors are indicated with error bits in the
+ * interrupt status register. Subsequent errors are not logged until this inter-
+ * rupt is cleared.
+ */
+	typedef union pic_cmd_word_link_err_u {
+		picreg_t	pic_cmd_word_link_err_regval;
+		struct {
+			picreg_t          :	32; /* 63:32 */
+			picreg_t didn     :	4; /* 31:28 */
+			picreg_t sidn     :	4; /* 27:24 */
+			picreg_t pactyp   :	4; /* 23:20 */
+			picreg_t tnum     :	5; /* 19:15 */
+			picreg_t coherent :	1; /* 14:14 */
+			picreg_t ds       :	2; /* 13:12 */
+			picreg_t gbr      :	1; /* 11:11 */
+			picreg_t vbpm     :	1; /* 10:10 */
+			picreg_t error    :	1; /* 9:9 */
+			picreg_t barrier  :	1; /* 8:8 */
+			picreg_t          :	8; /* 7:0 */
+		} pic_cmd_word_link_err_fld_s;
+	} pic_cmd_word_link_err_u_t;
+/*
+ * PCI Response Buffer Error Upper Address Holding Reg
+ *
+ * The response buffer error upper address holding register is a read only
+ * register which contains the upper 16-bits of the address when error asso-
+ * ciated with response buffer entries occur. Subsequent errors are not
+ * logged until the interrupt is cleared.
+ */
+	typedef union pic_pci_rbuf_err_upper_u {
+		picreg_t	pic_pci_rbuf_err_upper_regval;
+		struct {
+			picreg_t          :	32; /* 63:32 */
+			picreg_t          :	9; /* 31:23 */
+			picreg_t dev_num  :	3; /* 22:20 */
+			picreg_t buff_num :	4; /* 19:16 */
+			picreg_t upp_addr :	16; /* 15:0 */
+		} pic_pci_rbuf_err_upper_fld_s;
+	} pic_pci_rbuf_err_upper_u_t;
+/*
+ * PCI Response Buffer Error Lower Address Holding Reg
+ *
+ * The response buffer error lower address holding register is a read only
+ * register which contains the address of the error associated with response
+ * buffer entries. Subsequent errors are not logged until the interrupt is
+ * cleared.
+ */
+	typedef union pic_pci_rbuf_err_lower_u {
+		picreg_t	pic_pci_rbuf_err_lower_regval;
+		struct {
+			picreg_t          :	9; /* 63:55 */
+			picreg_t dev_num  :	3; /* 54:52 */
+			picreg_t buff_num :	4; /* 51:48 */
+			picreg_t upp_addr :	16; /* 47:32 */
+			picreg_t low_addr :	32; /* 31:0 */
+		} pic_pci_rbuf_err_lower_fld_s;
+	} pic_pci_rbuf_err_lower_u_t;
+/*
+ * Test Pin Control Register
+ *
+ * This register selects the output function and value to the four test pins on
+ * the PIC .
+ */
+	typedef union pic_test_pin_cntl_u {
+		picreg_t	pic_test_pin_cntl_regval;
+		struct {
+			picreg_t            :	32; /* 63:32 */
+			picreg_t            :	8; /* 31:24 */
+			picreg_t tdata_out  :	8; /* 23:16 */
+			picreg_t sel_tpin_7 :	2; /* 15:14 */
+			picreg_t sel_tpin_6 :	2; /* 13:12 */
+			picreg_t sel_tpin_5 :	2; /* 11:10 */
+			picreg_t sel_tpin_4 :	2; /* 9:8 */
+			picreg_t sel_tpin_3 :	2; /* 7:6 */
+			picreg_t sel_tpin_2 :	2; /* 5:4 */
+			picreg_t sel_tpin_1 :	2; /* 3:2 */
+			picreg_t sel_tpin_0 :	2; /* 1:0 */
+		} pic_test_pin_cntl_fld_s;
+	} pic_test_pin_cntl_u_t;
+/*
+ * Address Holding Register Link Side Errors
+ *
+ * The address holding register is a read only register which contains the ad-
+ * dress which either can be accessed as a word or double word. Subsequent
+ * errors are not logged until the error is cleared. The last logged value is
+ * held until the group is cleared and enabled.
+ */
+	typedef union pic_p_addr_lkerr_u {
+		picreg_t	pic_p_addr_lkerr_regval;
+		struct {
+			picreg_t          :	16; /* 63:48 */
+			picreg_t upp_addr :	16; /* 47:32 */
+			picreg_t low_addr :	32; /* 31:0 */
+		} pic_p_addr_lkerr_fld_s;
+	} pic_p_addr_lkerr_u_t;
+/*
+ * PCI Direct Mapping Register
+ *
+ * This register is used to relocate a 2 GByte region for PCI to Crosstalk
+ * transfers.
+ */
+	typedef union pic_p_dir_map_u {
+		picreg_t	pic_p_dir_map_regval;
+		struct {
+			picreg_t            :	32; /* 63:32 */
+			picreg_t            :	8; /* 31:24 */
+			picreg_t dir_w_id   :	4; /* 23:20 */
+			picreg_t            :	2; /* 19:18 */
+			picreg_t dir_add512 :	1; /* 17:17 */
+			picreg_t dir_off    :	17; /* 16:0 */
+		} pic_p_dir_map_fld_s;
+	} pic_p_dir_map_u_t;
+/*
+ * PCI Page Map Fault Address Register
+ *
+ * This register contains the address and device number when a page map
+ * fault occurred.
+ */
+	typedef union pic_p_map_fault_u {
+		picreg_t	pic_p_map_fault_regval;
+		struct {
+			picreg_t             :	32; /* 63:32 */
+			picreg_t             :	10; /* 31:22 */
+			picreg_t pci_addr    :	18; /* 21:4 */
+			picreg_t             :	1; /* 3:3 */
+			picreg_t pci_dev_num :	3; /* 2:0 */
+		} pic_p_map_fault_fld_s;
+	} pic_p_map_fault_u_t;
+/*
+ * Arbitration Register
+ *
+ * This register defines the priority and bus time out timing in PCI bus arbi-
+ * tration.
+ */
+	typedef union pic_p_arb_u {
+		picreg_t	pic_p_arb_regval;
+		struct {
+			picreg_t               :	32; /* 63:32 */
+			picreg_t               :	8; /* 31:24 */
+			picreg_t dev_broke     :	4; /* 23:20 */
+			picreg_t               :	2; /* 19:18 */
+			picreg_t req_wait_tick :	2; /* 17:16 */
+			picreg_t               :	4; /* 15:12 */
+			picreg_t req_wait_en   :	4; /* 11:8 */
+			picreg_t disarb        :	1; /* 7:7 */
+			picreg_t freeze_gnt    :	1; /* 6:6 */
+			picreg_t               :	1; /* 5:5 */
+			picreg_t en_bridge_hi  :	2; /* 4:3 */
+			picreg_t               :	1; /* 2:2 */
+			picreg_t en_bridge_lo  :	2; /* 1:0 */
+		} pic_p_arb_fld_s;
+	} pic_p_arb_u_t;
+/*
+ * Internal Ram Parity Error Register
+ *
+ * This register logs information about parity errors on internal ram access.
+ */
+	typedef union pic_p_ram_perr_u {
+		picreg_t	pic_p_ram_perr_regval;
+		struct {
+			picreg_t         	     :	6; /* 63:58 */
+			picreg_t ate_err_addr        :	10; /* 57:48 */
+			picreg_t         	     :	7; /* 47:41 */
+			picreg_t rd_resp_err_addr    :	9; /* 40:32 */
+			picreg_t wrt_resp_err_addr   :	8; /* 31:24 */
+			picreg_t         	     :	2; /* 23:22 */
+			picreg_t ate_err 	     :	1; /* 21:21 */
+			picreg_t rd_resp_err         :	1; /* 20:20 */
+			picreg_t wrt_resp_err        :	1; /* 19:19 */
+			picreg_t dbe_ate 	     :	3; /* 18:16 */
+			picreg_t dbe_rd  	     :	8; /* 15:8 */
+			picreg_t dbe_wrt 	     :	8; /* 7:0 */
+		} pic_p_ram_perr_fld_s;
+	} pic_p_ram_perr_u_t;
+/*
+ * Time-out Register
+ *
+ * This register determines retry hold off and max retries allowed for PIO
+ * accesses to PCI/PCI-X.
+ */
+	typedef union pic_p_bus_timeout_u {
+		picreg_t	pic_p_bus_timeout_regval;
+		struct {
+			picreg_t               :	32; /* 63:32 */
+			picreg_t               :	11; /* 31:21 */
+			picreg_t pci_retry_hld :	5; /* 20:16 */
+			picreg_t               :	6; /* 15:10 */
+			picreg_t pci_retry_cnt :	10; /* 9:0 */
+		} pic_p_bus_timeout_fld_s;
+	} pic_p_bus_timeout_u_t;
+/*
+ * PCI/PCI-X Type 1 Configuration Register
+ *
+ * This register is use during accesses to the PCI/PCI-X type 1 configuration
+ * space. The bits in this register are used to supplement the address during
+ * the configuration cycle to select the correct secondary bus and device.
+ */
+	typedef union pic_type1_cfg_u {
+		picreg_t	pic_type1_cfg_regval;
+		struct {
+			picreg_t         :	32; /* 63:32 */
+			picreg_t         :	8; /* 31:24 */
+			picreg_t bus_num :	8; /* 23:16 */
+			picreg_t dev_num :	5; /* 15:11 */
+			picreg_t         :	11; /* 10:0 */
+		} pic_type1_cfg_fld_s;
+	} pic_type1_cfg_u_t;
+/*
+ * PCI Bus Error Upper Address Holding Register
+ *
+ * This register holds the value of the upper address on the PCI Bus when an
+ * error occurs.
+ */
+	typedef union pic_p_pci_err_upper_u {
+		picreg_t	pic_p_pci_err_upper_regval;
+		struct {
+			picreg_t                :	32; /* 63:32 */
+			picreg_t                :	4; /* 31:28 */
+			picreg_t pci_xtalk_did  :	4; /* 27:24 */
+			picreg_t                :	2; /* 23:22 */
+			picreg_t pci_dac        :	1; /* 21:21 */
+			picreg_t pci_dev_master :	1; /* 20:20 */
+			picreg_t pci_vdev       :	1; /* 19:19 */
+			picreg_t pci_dev_num    :	3; /* 18:16 */
+			picreg_t pci_uaddr_err  :	16; /* 15:0 */
+		} pic_p_pci_err_upper_fld_s;
+	} pic_p_pci_err_upper_u_t;
+/*
+ * PCI Bus Error Lower Address Holding Register
+ *
+ * This register holds the value of the lower address on the PCI Bus when an
+ * error occurs.
+ */
+	typedef union pic_p_pci_err_lower_u {
+		picreg_t	pic_p_pci_err_lower_regval;
+		struct {
+			picreg_t                :	4; /* 63:60 */
+			picreg_t pci_xtalk_did  :	4; /* 59:56 */
+			picreg_t                :	2; /* 55:54 */
+			picreg_t pci_dac        :	1; /* 53:53 */
+			picreg_t pci_dev_master :	1; /* 52:52 */
+			picreg_t pci_vdev       :	1; /* 51:51 */
+			picreg_t pci_dev_num    :	3; /* 50:48 */
+			picreg_t pci_uaddr_err  :	16; /* 47:32 */
+			picreg_t pci_laddr_err  :	32; /* 31:0 */
+		} pic_p_pci_err_lower_fld_s;
+	} pic_p_pci_err_lower_u_t;
+/*
+ * PCI-X Error Address Register
+ *
+ * This register contains the address on the PCI-X bus when an error oc-
+ * curred.
+ */
+	typedef union pic_p_pcix_err_addr_u {
+		picreg_t	pic_p_pcix_err_addr_regval;
+		struct {
+			picreg_t pcix_err_addr :	64; /* 63:0 */
+		} pic_p_pcix_err_addr_fld_s;
+	} pic_p_pcix_err_addr_u_t;
+/*
+ * PCI-X Error Attribute Register
+ *
+ * This register contains the attribute data on the PCI-X bus when an error
+ * occurred.
+ */
+	typedef union pic_p_pcix_err_attr_u {
+		picreg_t	pic_p_pcix_err_attr_regval;
+		struct {
+			picreg_t            :	16; /* 63:48 */
+			picreg_t bus_cmd    :	4; /* 47:44 */
+			picreg_t byte_cnt   :	12; /* 43:32 */
+			picreg_t            :	1; /* 31:31 */
+			picreg_t ns         :	1; /* 30:30 */
+			picreg_t ro         :	1; /* 29:29 */
+			picreg_t tag        :	5; /* 28:24 */
+			picreg_t bus_num    :	8; /* 23:16 */
+			picreg_t dev_num    :	5; /* 15:11 */
+			picreg_t fun_num    :	3; /* 10:8 */
+			picreg_t l_byte_cnt :	8; /* 7:0 */
+		} pic_p_pcix_err_attr_fld_s;
+	} pic_p_pcix_err_attr_u_t;
+/*
+ * PCI-X Error Data Register
+ *
+ * This register contains the Data on the PCI-X bus when an error occurred.
+ */
+	typedef union pic_p_pcix_err_data_u {
+		picreg_t	pic_p_pcix_err_data_regval;
+		struct {
+			picreg_t pcix_err_data :	64; /* 63:0 */
+		} pic_p_pcix_err_data_fld_s;
+	} pic_p_pcix_err_data_u_t;
+/*
+ * PCI-X Read Request Timeout Error Register
+ *
+ * This register contains a pointer into the PCI-X read data structure.
+ */
+	typedef union pic_p_pcix_read_req_to_u {
+		picreg_t	pic_p_pcix_read_req_to_regval;
+		struct {
+			picreg_t                :	55; /* 63:9 */
+			picreg_t rd_buff_loc    :	5; /* 8:4 */
+			picreg_t rd_buff_struct :	4; /* 3:0 */
+		} pic_p_pcix_read_req_to_fld_s;
+	} pic_p_pcix_read_req_to_u_t;
+/*
+ * INT_STATUS Register
+ *
+ * This is the current interrupt status register which maintains the current
+ * status of all the interrupting devices which generated a n interrupt. This
+ * register is read only and all the bits are active high. A high bit at
+ * INT_STATE means the corresponding INT_N pin has been asserted
+ * (low).
+ */
+	typedef union pic_p_int_status_u {
+		picreg_t	pic_p_int_status_regval;
+		struct {
+			picreg_t                  :	22; /* 63:42 */
+			picreg_t int_ram_perr     :	1; /* 41:41 */
+			picreg_t bus_arb_broke    :	1; /* 40:40 */
+			picreg_t pci_x_req_tout   :	1; /* 39:39 */
+			picreg_t pci_x_tabort     :	1; /* 38:38 */
+			picreg_t pci_x_perr       :	1; /* 37:37 */
+			picreg_t pci_x_serr       :	1; /* 36:36 */
+			picreg_t pci_x_mretry     :	1; /* 35:35 */
+			picreg_t pci_x_mtout      :	1; /* 34:34 */
+			picreg_t pci_x_da_parity  :	1; /* 33:33 */
+			picreg_t pci_x_ad_parity  :	1; /* 32:32 */
+			picreg_t                  :	1; /* 31:31 */
+			picreg_t pmu_page_fault   :	1; /* 30:30 */
+			picreg_t unexpected_resp  :	1; /* 29:29 */
+			picreg_t bad_xresp_packet :	1; /* 28:28 */
+			picreg_t bad_xreq_packet  :	1; /* 27:27 */
+			picreg_t resp_xtalk_error :	1; /* 26:26 */
+			picreg_t req_xtalk_error  :	1; /* 25:25 */
+			picreg_t invalid_access   :	1; /* 24:24 */
+			picreg_t unsupported_xop  :	1; /* 23:23 */
+			picreg_t xreq_fifo_oflow  :	1; /* 22:22 */
+			picreg_t llp_rec_snerror  :	1; /* 21:21 */
+			picreg_t llp_rec_cberror  :	1; /* 20:20 */
+			picreg_t llp_rcty         :	1; /* 19:19 */
+			picreg_t llp_tx_retry     :	1; /* 18:18 */
+			picreg_t llp_tcty         :	1; /* 17:17 */
+			picreg_t                  :	1; /* 16:16 */
+			picreg_t pci_abort        :	1; /* 15:15 */
+			picreg_t pci_parity       :	1; /* 14:14 */
+			picreg_t pci_serr         :	1; /* 13:13 */
+			picreg_t pci_perr         :	1; /* 12:12 */
+			picreg_t pci_master_tout  :	1; /* 11:11 */
+			picreg_t pci_retry_cnt    :	1; /* 10:10 */
+			picreg_t xread_req_tout   :	1; /* 9:9 */
+			picreg_t                  :	1; /* 8:8 */
+			picreg_t int_state        :	8; /* 7:0 */
+		} pic_p_int_status_fld_s;
+	} pic_p_int_status_u_t;
+/*
+ * Interrupt Enable Register
+ *
+ * This register enables the reporting of interrupt to the host. Each bit in this
+ * register corresponds to the same bit in Interrupt Status register. All bits
+ * are zero after reset.
+ */
+	typedef union pic_p_int_enable_u {
+		picreg_t	pic_p_int_enable_regval;
+		struct {
+			picreg_t                     :	22; /* 63:42 */
+			picreg_t en_int_ram_perr     :	1; /* 41:41 */
+			picreg_t en_bus_arb_broke    :	1; /* 40:40 */
+			picreg_t en_pci_x_req_tout   :	1; /* 39:39 */
+			picreg_t en_pci_x_tabort     :	1; /* 38:38 */
+			picreg_t en_pci_x_perr       :	1; /* 37:37 */
+			picreg_t en_pci_x_serr       :	1; /* 36:36 */
+			picreg_t en_pci_x_mretry     :	1; /* 35:35 */
+			picreg_t en_pci_x_mtout      :	1; /* 34:34 */
+			picreg_t en_pci_x_da_parity  :	1; /* 33:33 */
+			picreg_t en_pci_x_ad_parity  :	1; /* 32:32 */
+			picreg_t                     :	1; /* 31:31 */
+			picreg_t en_pmu_page_fault   :	1; /* 30:30 */
+			picreg_t en_unexpected_resp  :	1; /* 29:29 */
+			picreg_t en_bad_xresp_packet :	1; /* 28:28 */
+			picreg_t en_bad_xreq_packet  :	1; /* 27:27 */
+			picreg_t en_resp_xtalk_error :	1; /* 26:26 */
+			picreg_t en_req_xtalk_error  :	1; /* 25:25 */
+			picreg_t en_invalid_access   :	1; /* 24:24 */
+			picreg_t en_unsupported_xop  :	1; /* 23:23 */
+			picreg_t en_xreq_fifo_oflow  :	1; /* 22:22 */
+			picreg_t en_llp_rec_snerror  :	1; /* 21:21 */
+			picreg_t en_llp_rec_cberror  :	1; /* 20:20 */
+			picreg_t en_llp_rcty         :	1; /* 19:19 */
+			picreg_t en_llp_tx_retry     :	1; /* 18:18 */
+			picreg_t en_llp_tcty         :	1; /* 17:17 */
+			picreg_t                     :	1; /* 16:16 */
+			picreg_t en_pci_abort        :	1; /* 15:15 */
+			picreg_t en_pci_parity       :	1; /* 14:14 */
+			picreg_t en_pci_serr         :	1; /* 13:13 */
+			picreg_t en_pci_perr         :	1; /* 12:12 */
+			picreg_t en_pci_master_tout  :	1; /* 11:11 */
+			picreg_t en_pci_retry_cnt    :	1; /* 10:10 */
+			picreg_t en_xread_req_tout   :	1; /* 9:9 */
+			picreg_t                     :	1; /* 8:8 */
+			picreg_t en_int_state        :	8; /* 7:0 */
+		} pic_p_int_enable_fld_s;
+	} pic_p_int_enable_u_t;
+/*
+ * Reset Interrupt Register
+ *
+ * A write of a "1" clears the bit and rearms the error registers. Writes also
+ * clear the error view register.
+ */
+	typedef union pic_p_int_rst_u {
+		picreg_t	pic_p_int_rst_regval;
+		struct {
+			picreg_t                       :	22; /* 63:42 */
+			picreg_t logv_int_ram_perr     :	1; /* 41:41 */
+			picreg_t logv_bus_arb_broke    :	1; /* 40:40 */
+			picreg_t logv_pci_x_req_tout   :	1; /* 39:39 */
+			picreg_t logv_pci_x_tabort     :	1; /* 38:38 */
+			picreg_t logv_pci_x_perr       :	1; /* 37:37 */
+			picreg_t logv_pci_x_serr       :	1; /* 36:36 */
+			picreg_t logv_pci_x_mretry     :	1; /* 35:35 */
+			picreg_t logv_pci_x_mtout      :	1; /* 34:34 */
+			picreg_t logv_pci_x_da_parity  :	1; /* 33:33 */
+			picreg_t logv_pci_x_ad_parity  :	1; /* 32:32 */
+			picreg_t                       :	1; /* 31:31 */
+			picreg_t logv_pmu_page_fault   :	1; /* 30:30 */
+			picreg_t logv_unexpected_resp  :	1; /* 29:29 */
+			picreg_t logv_bad_xresp_packet :	1; /* 28:28 */
+			picreg_t logv_bad_xreq_packet  :	1; /* 27:27 */
+			picreg_t logv_resp_xtalk_error :	1; /* 26:26 */
+			picreg_t logv_req_xtalk_error  :	1; /* 25:25 */
+			picreg_t logv_invalid_access   :	1; /* 24:24 */
+			picreg_t logv_unsupported_xop  :	1; /* 23:23 */
+			picreg_t logv_xreq_fifo_oflow  :	1; /* 22:22 */
+			picreg_t logv_llp_rec_snerror  :	1; /* 21:21 */
+			picreg_t logv_llp_rec_cberror  :	1; /* 20:20 */
+			picreg_t logv_llp_rcty         :	1; /* 19:19 */
+			picreg_t logv_llp_tx_retry     :	1; /* 18:18 */
+			picreg_t logv_llp_tcty         :	1; /* 17:17 */
+			picreg_t                       :	1; /* 16:16 */
+			picreg_t logv_pci_abort        :	1; /* 15:15 */
+			picreg_t logv_pci_parity       :	1; /* 14:14 */
+			picreg_t logv_pci_serr         :	1; /* 13:13 */
+			picreg_t logv_pci_perr         :	1; /* 12:12 */
+			picreg_t logv_pci_master_tout  :	1; /* 11:11 */
+			picreg_t logv_pci_retry_cnt    :	1; /* 10:10 */
+			picreg_t logv_xread_req_tout   :	1; /* 9:9 */
+                        picreg_t                       :        2; /* 8:7 */
+			picreg_t multi_clr             :	1; /* 6:6 */
+			picreg_t                       :	6; /* 5:0 */
+		} pic_p_int_rst_fld_s;
+	} pic_p_int_rst_u_t;
+
+/*
+ * Interrupt Mode Register
+ *
+ * This register defines the interrupting mode of the INT_N pins.
+ */
+	typedef union pic_p_int_mode_u {
+		picreg_t	pic_p_int_mode_regval;
+		struct {
+			picreg_t            :	32; /* 63:32 */
+			picreg_t            :	24; /* 31:8 */
+			picreg_t en_clr_pkt :	8; /* 7:0 */
+		} pic_p_int_mode_fld_s;
+	} pic_p_int_mode_u_t;
+/*
+ * Interrupt Device Select Register
+ *
+ * This register associates interrupt pins with devices thus allowing buffer
+ * management (flushing) when a device interrupt occurs.
+ */
+	typedef union pic_p_int_device_u {
+		picreg_t	pic_p_int_device_regval;
+		struct {
+			picreg_t          :	32; /* 63:32 */
+			picreg_t          :	8; /* 31:24 */
+			picreg_t int7_dev :	3; /* 23:21 */
+			picreg_t int6_dev :	3; /* 20:18 */
+			picreg_t int5_dev :	3; /* 17:15 */
+			picreg_t int4_dev :	3; /* 14:12 */
+			picreg_t int3_dev :	3; /* 11:9 */
+			picreg_t int2_dev :	3; /* 8:6 */
+			picreg_t int1_dev :	3; /* 5:3 */
+			picreg_t int0_dev :	3; /* 2:0 */
+		} pic_p_int_device_fld_s;
+	} pic_p_int_device_u_t;
+/*
+ * Host Error Interrupt Field Register
+ *
+ * This register tells which bit location in the host's Interrupt Status register
+ * to set or reset when any error condition happens.
+ */
+	typedef union pic_p_int_host_err_u {
+		picreg_t	pic_p_int_host_err_regval;
+		struct {
+			picreg_t                :	32; /* 63:32 */
+			picreg_t                :	24; /* 31:8 */
+			picreg_t bridge_err_fld :	8; /* 7:0 */
+		} pic_p_int_host_err_fld_s;
+	} pic_p_int_host_err_u_t;
+/*
+ * Interrupt (x) Host Address Register
+ *
+ * This register allow different host address to be assigned to each interrupt
+ * pin and the bit in the host.
+ */
+	typedef union pic_p_int_addr_u {
+		picreg_t	pic_p_int_addr_regval;
+		struct {
+			picreg_t          :	8; /* 63:56 */
+			picreg_t int_fld  :	8; /* 55:48 */
+			picreg_t int_addr :	48; /* 47:0 */
+		} pic_p_int_addr_fld_s;
+	} pic_p_int_addr_u_t;
+/*
+ * Error Interrupt View Register
+ *
+ * This register contains the view of which interrupt occur even if they are
+ * not currently enabled. The group clear is used to clear these bits just like
+ * the interrupt status register bits.
+ */
+	typedef union pic_p_err_int_view_u {
+		picreg_t	pic_p_err_int_view_regval;
+		struct {
+			picreg_t                  :	22; /* 63:42 */
+			picreg_t int_ram_perr     :	1; /* 41:41 */
+			picreg_t bus_arb_broke    :	1; /* 40:40 */
+			picreg_t pci_x_req_tout   :	1; /* 39:39 */
+			picreg_t pci_x_tabort     :	1; /* 38:38 */
+			picreg_t pci_x_perr       :	1; /* 37:37 */
+			picreg_t pci_x_serr       :	1; /* 36:36 */
+			picreg_t pci_x_mretry     :	1; /* 35:35 */
+			picreg_t pci_x_mtout      :	1; /* 34:34 */
+			picreg_t pci_x_da_parity  :	1; /* 33:33 */
+			picreg_t pci_x_ad_parity  :	1; /* 32:32 */
+			picreg_t                  :	1; /* 31:31 */
+			picreg_t pmu_page_fault   :	1; /* 30:30 */
+			picreg_t unexpected_resp  :	1; /* 29:29 */
+			picreg_t bad_xresp_packet :	1; /* 28:28 */
+			picreg_t bad_xreq_packet  :	1; /* 27:27 */
+			picreg_t resp_xtalk_error :	1; /* 26:26 */
+			picreg_t req_xtalk_error  :	1; /* 25:25 */
+			picreg_t invalid_access   :	1; /* 24:24 */
+			picreg_t unsupported_xop  :	1; /* 23:23 */
+			picreg_t xreq_fifo_oflow  :	1; /* 22:22 */
+			picreg_t llp_rec_snerror  :	1; /* 21:21 */
+			picreg_t llp_rec_cberror  :	1; /* 20:20 */
+			picreg_t llp_rcty         :	1; /* 19:19 */
+			picreg_t llp_tx_retry     :	1; /* 18:18 */
+			picreg_t llp_tcty         :	1; /* 17:17 */
+			picreg_t                  :	1; /* 16:16 */
+			picreg_t pci_abort        :	1; /* 15:15 */
+			picreg_t pci_parity       :	1; /* 14:14 */
+			picreg_t pci_serr         :	1; /* 13:13 */
+			picreg_t pci_perr         :	1; /* 12:12 */
+			picreg_t pci_master_tout  :	1; /* 11:11 */
+			picreg_t pci_retry_cnt    :	1; /* 10:10 */
+			picreg_t xread_req_tout   :	1; /* 9:9 */
+			picreg_t                  :	9; /* 8:0 */
+		} pic_p_err_int_view_fld_s;
+	} pic_p_err_int_view_u_t;
+
+
+/*
+ * Multiple Interrupt Register
+ *
+ * This register indicates if any interrupt occurs more than once without be-
+ * ing cleared.
+ */
+	typedef union pic_p_mult_int_u {
+		picreg_t	pic_p_mult_int_regval;
+		struct {
+			picreg_t                  :	22; /* 63:42 */
+			picreg_t int_ram_perr     :	1; /* 41:41 */
+			picreg_t bus_arb_broke    :	1; /* 40:40 */
+			picreg_t pci_x_req_tout   :	1; /* 39:39 */
+			picreg_t pci_x_tabort     :	1; /* 38:38 */
+			picreg_t pci_x_perr       :	1; /* 37:37 */
+			picreg_t pci_x_serr       :	1; /* 36:36 */
+			picreg_t pci_x_mretry     :	1; /* 35:35 */
+			picreg_t pci_x_mtout      :	1; /* 34:34 */
+			picreg_t pci_x_da_parity  :	1; /* 33:33 */
+			picreg_t pci_x_ad_parity  :	1; /* 32:32 */
+			picreg_t                  :	1; /* 31:31 */
+			picreg_t pmu_page_fault   :	1; /* 30:30 */
+			picreg_t unexpected_resp  :	1; /* 29:29 */
+			picreg_t bad_xresp_packet :	1; /* 28:28 */
+			picreg_t bad_xreq_packet  :	1; /* 27:27 */
+			picreg_t resp_xtalk_error :	1; /* 26:26 */
+			picreg_t req_xtalk_error  :	1; /* 25:25 */
+			picreg_t invalid_access   :	1; /* 24:24 */
+			picreg_t unsupported_xop  :	1; /* 23:23 */
+			picreg_t xreq_fifo_oflow  :	1; /* 22:22 */
+			picreg_t llp_rec_snerror  :	1; /* 21:21 */
+			picreg_t llp_rec_cberror  :	1; /* 20:20 */
+			picreg_t llp_rcty         :	1; /* 19:19 */
+			picreg_t llp_tx_retry     :	1; /* 18:18 */
+			picreg_t llp_tcty         :	1; /* 17:17 */
+			picreg_t                  :	1; /* 16:16 */
+			picreg_t pci_abort        :	1; /* 15:15 */
+			picreg_t pci_parity       :	1; /* 14:14 */
+			picreg_t pci_serr         :	1; /* 13:13 */
+			picreg_t pci_perr         :	1; /* 12:12 */
+			picreg_t pci_master_tout  :	1; /* 11:11 */
+			picreg_t pci_retry_cnt    :	1; /* 10:10 */
+			picreg_t xread_req_tout   :	1; /* 9:9 */
+			picreg_t                  :	1; /* 8:8 */
+			picreg_t int_state        :	8; /* 7:0 */
+		} pic_p_mult_int_fld_s;
+	} pic_p_mult_int_u_t;
+/*
+ * Force Always Interrupt (x) Register
+ *
+ * A write to this data independent write only register will force a set inter-
+ * rupt to occur as if the interrupt line had transitioned. If the interrupt line
+ * is already active an addition set interrupt packet is set. All buffer flush op-
+ * erations also occur on this operation.
+ */
+
+
+/*
+ * Force Interrupt (x) Register
+ *
+ * A write to this data independent write only register in conjunction with
+ * the assertion of the corresponding interrupt line will force a set interrupt
+ * to occur as if the interrupt line had transitioned. The interrupt line must
+ * be active for this operation to generate a set packet, otherwise the write
+ * PIO is ignored. All buffer flush operations also occur when the set packet
+ * is sent on this operation.
+ */
+
+
+/*
+ * Device Registers
+ *
+ * The Device registers contain device specific and mapping information.
+ */
+	typedef union pic_device_reg_u {
+		picreg_t	pic_device_reg_regval;
+		struct {
+			picreg_t               :	32; /* 63:32 */
+			picreg_t               :	2; /* 31:30 */
+			picreg_t en_virtual1   :	1; /* 29:29 */
+			picreg_t en_error_lock :	1; /* 28:28 */
+			picreg_t en_page_chk   :	1; /* 27:27 */
+			picreg_t force_pci_par :	1; /* 26:26 */
+			picreg_t en_virtual0   :	1; /* 25:25 */
+			picreg_t               :	1; /* 24:24 */
+			picreg_t dir_wrt_gen   :	1; /* 23:23 */
+			picreg_t dev_size      :	1; /* 22:22 */
+			picreg_t real_time     :	1; /* 21:21 */
+			picreg_t               :	1; /* 20:20 */
+			picreg_t swap_direct   :	1; /* 19:19 */
+			picreg_t prefetch      :	1; /* 18:18 */
+			picreg_t precise       :	1; /* 17:17 */
+			picreg_t coherent      :	1; /* 16:16 */
+			picreg_t barrier       :	1; /* 15:15 */
+			picreg_t gbr           :	1; /* 14:14 */
+			picreg_t dev_swap      :	1; /* 13:13 */
+			picreg_t dev_io_mem    :	1; /* 12:12 */
+			picreg_t dev_off       :	12; /* 11:0 */
+		} pic_device_reg_fld_s;
+	} pic_device_reg_u_t;
+/*
+ * Device (x) Write Request Buffer Flush
+ *
+ * When read, this register will return a 0x00 after the write buffer associat-
+ * ed with the device has been flushed. (PCI Only)
+ */
+
+
+/*
+ * Even Device Read Response Buffer Register (PCI Only)
+ *
+ * This register is use to allocate the read response buffers for the even num-
+ * bered devices. (0,2)
+ */
+	typedef union pic_p_even_resp_u {
+		picreg_t	pic_p_even_resp_regval;
+		struct {
+			picreg_t              :	32; /* 63:32 */
+			picreg_t buff_14_en   :	1; /* 31:31 */
+			picreg_t buff_14_vdev :	2; /* 30:29 */
+			picreg_t buff_14_pdev :	1; /* 28:28 */
+			picreg_t buff_12_en   :	1; /* 27:27 */
+			picreg_t buff_12_vdev :	2; /* 26:25 */
+			picreg_t buff_12_pdev :	1; /* 24:24 */
+			picreg_t buff_10_en   :	1; /* 23:23 */
+			picreg_t buff_10_vdev :	2; /* 22:21 */
+			picreg_t buff_10_pdev :	1; /* 20:20 */
+			picreg_t buff_8_en    :	1; /* 19:19 */
+			picreg_t buff_8_vdev  :	2; /* 18:17 */
+			picreg_t buff_8_pdev  :	1; /* 16:16 */
+			picreg_t buff_6_en    :	1; /* 15:15 */
+			picreg_t buff_6_vdev  :	2; /* 14:13 */
+			picreg_t buff_6_pdev  :	1; /* 12:12 */
+			picreg_t buff_4_en    :	1; /* 11:11 */
+			picreg_t buff_4_vdev  :	2; /* 10:9 */
+			picreg_t buff_4_pdev  :	1; /* 8:8 */
+			picreg_t buff_2_en    :	1; /* 7:7 */
+			picreg_t buff_2_vdev  :	2; /* 6:5 */
+			picreg_t buff_2_pdev  :	1; /* 4:4 */
+			picreg_t buff_0_en    :	1; /* 3:3 */
+			picreg_t buff_0_vdev  :	2; /* 2:1 */
+			picreg_t buff_0_pdev  :	1; /* 0:0 */
+		} pic_p_even_resp_fld_s;
+	} pic_p_even_resp_u_t;
+/*
+ * Odd Device Read Response Buffer Register (PCI Only)
+ *
+ * This register is use to allocate the read response buffers for the odd num-
+ * bered devices. (1,3))
+ */
+	typedef union pic_p_odd_resp_u {
+		picreg_t	pic_p_odd_resp_regval;
+		struct {
+			picreg_t              :	32; /* 63:32 */
+			picreg_t buff_15_en   :	1; /* 31:31 */
+			picreg_t buff_15_vdev :	2; /* 30:29 */
+			picreg_t buff_15_pdev :	1; /* 28:28 */
+			picreg_t buff_13_en   :	1; /* 27:27 */
+			picreg_t buff_13_vdev :	2; /* 26:25 */
+			picreg_t buff_13_pdev :	1; /* 24:24 */
+			picreg_t buff_11_en   :	1; /* 23:23 */
+			picreg_t buff_11_vdev :	2; /* 22:21 */
+			picreg_t buff_11_pdev :	1; /* 20:20 */
+			picreg_t buff_9_en    :	1; /* 19:19 */
+			picreg_t buff_9_vdev  :	2; /* 18:17 */
+			picreg_t buff_9_pdev  :	1; /* 16:16 */
+			picreg_t buff_7_en    :	1; /* 15:15 */
+			picreg_t buff_7_vdev  :	2; /* 14:13 */
+			picreg_t buff_7_pdev  :	1; /* 12:12 */
+			picreg_t buff_5_en    :	1; /* 11:11 */
+			picreg_t buff_5_vdev  :	2; /* 10:9 */
+			picreg_t buff_5_pdev  :	1; /* 8:8 */
+			picreg_t buff_3_en    :	1; /* 7:7 */
+			picreg_t buff_3_vdev  :	2; /* 6:5 */
+			picreg_t buff_3_pdev  :	1; /* 4:4 */
+			picreg_t buff_1_en    :	1; /* 3:3 */
+			picreg_t buff_1_vdev  :	2; /* 2:1 */
+			picreg_t buff_1_pdev  :	1; /* 0:0 */
+		} pic_p_odd_resp_fld_s;
+	} pic_p_odd_resp_u_t;
+/*
+ * Read Response Buffer Status Register (PCI Only)
+ *
+ * This read only register contains the current response buffer status.
+ */
+	typedef union pic_p_resp_status_u {
+		picreg_t	pic_p_resp_status_regval;
+		struct {
+			picreg_t           :	32; /* 63:32 */
+			picreg_t rrb_valid :	16; /* 31:16 */
+			picreg_t rrb_inuse :	16; /* 15:0 */
+		} pic_p_resp_status_fld_s;
+	} pic_p_resp_status_u_t;
+/*
+ * Read Response Buffer Clear Register (PCI Only)
+ *
+ * A write to this register clears the current contents of the buffer.
+ */
+	typedef union pic_p_resp_clear_u {
+		picreg_t	pic_p_resp_clear_regval;
+		struct {
+			picreg_t           :	32; /* 63:32 */
+			picreg_t           :	16; /* 31:16 */
+			picreg_t rrb_clear :	16; /* 15:0 */
+		} pic_p_resp_clear_fld_s;
+	} pic_p_resp_clear_u_t;
+/*
+ * PCI Read Response Buffer (x) Upper Address Match
+ *
+ * The PCI Bridge read response buffer upper address register is a read only
+ * register which contains the upper 16-bits of the address and status used to
+ * select the buffer for a PCI transaction.
+ */
+	typedef union pic_p_buf_upper_addr_match_u {
+		picreg_t	pic_p_buf_upper_addr_match_regval;
+		struct {
+			picreg_t          :	32; /* 63:32 */
+			picreg_t filled   :	1; /* 31:31 */
+			picreg_t armed    :	1; /* 30:30 */
+			picreg_t flush    :	1; /* 29:29 */
+			picreg_t xerr     :	1; /* 28:28 */
+			picreg_t pkterr   :	1; /* 27:27 */
+			picreg_t timeout  :	1; /* 26:26 */
+			picreg_t prefetch :	1; /* 25:25 */
+			picreg_t precise  :	1; /* 24:24 */
+			picreg_t dw_be    :	8; /* 23:16 */
+			picreg_t upp_addr :	16; /* 15:0 */
+		} pic_p_buf_upper_addr_match_fld_s;
+	} pic_p_buf_upper_addr_match_u_t;
+/*
+ * PCI Read Response Buffer (x) Lower Address Match
+ *
+ * The PCI Bridge read response buffer lower address Match register is a
+ * read only register which contains the address and status used to select the
+ * buffer for a PCI transaction.
+ */
+	typedef union pic_p_buf_lower_addr_match_u {
+		picreg_t	pic_p_buf_lower_addr_match_regval;
+		struct {
+			picreg_t filled   :	1; /* 63:63 */
+			picreg_t armed    :	1; /* 62:62 */
+			picreg_t flush    :	1; /* 61:61 */
+			picreg_t xerr     :	1; /* 60:60 */
+			picreg_t pkterr   :	1; /* 59:59 */
+			picreg_t timeout  :	1; /* 58:58 */
+			picreg_t prefetch :	1; /* 57:57 */
+			picreg_t precise  :	1; /* 56:56 */
+			picreg_t dw_be    :	8; /* 55:48 */
+			picreg_t upp_addr :	16; /* 47:32 */
+			picreg_t low_addr :	32; /* 31:0 */
+		} pic_p_buf_lower_addr_match_fld_s;
+	} pic_p_buf_lower_addr_match_u_t;
+/*
+ * PCI Buffer (x) Flush Count with Data Touch Register
+ *
+ * This counter is incremented each time the corresponding response buffer
+ * is flushed after at least a single data element in the buffer is used. A word
+ * write to this address clears the count.
+ */
+	typedef union pic_flush_w_touch_u {
+		picreg_t	pic_flush_w_touch_regval;
+		struct {
+			picreg_t           :	32; /* 63:32 */
+			picreg_t           :	16; /* 31:16 */
+			picreg_t touch_cnt :	16; /* 15:0 */
+		} pic_flush_w_touch_fld_s;
+	} pic_flush_w_touch_u_t;
+/*
+ * PCI Buffer (x) Flush Count w/o Data Touch Register
+ *
+ * This counter is incremented each time the corresponding response buffer
+ * is flushed without any data element in the buffer being used. A word
+ * write to this address clears the count.
+ */
+	typedef union pic_flush_wo_touch_u {
+		picreg_t	pic_flush_wo_touch_regval;
+		struct {
+			picreg_t             :	32; /* 63:32 */
+			picreg_t             :	16; /* 31:16 */
+			picreg_t notouch_cnt :	16; /* 15:0 */
+		} pic_flush_wo_touch_fld_s;
+	} pic_flush_wo_touch_u_t;
+/*
+ * PCI Buffer (x) Request in Flight Count Register
+ *
+ * This counter is incremented on each bus clock while the request is in-
+ * flight. A word write to this address clears the count. ]
+ */
+	typedef union pic_inflight_u {
+		picreg_t	pic_inflight_regval;
+		struct {
+			picreg_t              :	32; /* 63:32 */
+			picreg_t              :	16; /* 31:16 */
+			picreg_t inflight_cnt :	16; /* 15:0 */
+		} pic_inflight_fld_s;
+	} pic_inflight_u_t;
+/*
+ * PCI Buffer (x) Prefetch Request Count Register
+ *
+ * This counter is incremented each time the request using this buffer was
+ * generated from the prefetcher. A word write to this address clears the
+ * count.
+ */
+	typedef union pic_prefetch_u {
+		picreg_t	pic_prefetch_regval;
+		struct {
+			picreg_t              :	32; /* 63:32 */
+			picreg_t              :	16; /* 31:16 */
+			picreg_t prefetch_cnt :	16; /* 15:0 */
+		} pic_prefetch_fld_s;
+	} pic_prefetch_u_t;
+/*
+ * PCI Buffer (x) Total PCI Retry Count Register
+ *
+ * This counter is incremented each time a PCI bus retry occurs and the ad-
+ * dress matches the tag for the selected buffer. The buffer must also has this
+ * request in-flight. A word write to this address clears the count.
+ */
+	typedef union pic_total_pci_retry_u {
+		picreg_t	pic_total_pci_retry_regval;
+		struct {
+			picreg_t           :	32; /* 63:32 */
+			picreg_t           :	16; /* 31:16 */
+			picreg_t retry_cnt :	16; /* 15:0 */
+		} pic_total_pci_retry_fld_s;
+	} pic_total_pci_retry_u_t;
+/*
+ * PCI Buffer (x) Max PCI Retry Count Register
+ *
+ * This counter is contains the maximum retry count for a single request
+ * which was in-flight for this buffer. A word write to this address clears the
+ * count.
+ */
+	typedef union pic_max_pci_retry_u {
+		picreg_t	pic_max_pci_retry_regval;
+		struct {
+			picreg_t               :	32; /* 63:32 */
+			picreg_t               :	16; /* 31:16 */
+			picreg_t max_retry_cnt :	16; /* 15:0 */
+		} pic_max_pci_retry_fld_s;
+	} pic_max_pci_retry_u_t;
+/*
+ * PCI Buffer (x) Max Latency Count Register
+ *
+ * This counter is contains the maximum count (in bus clocks) for a single
+ * request which was in-flight for this buffer. A word write to this address
+ * clears the count.
+ */
+	typedef union pic_max_latency_u {
+		picreg_t	pic_max_latency_regval;
+		struct {
+			picreg_t                 :	32; /* 63:32 */
+			picreg_t                 :	16; /* 31:16 */
+			picreg_t max_latency_cnt :	16; /* 15:0 */
+		} pic_max_latency_fld_s;
+	} pic_max_latency_u_t;
+/*
+ * PCI Buffer (x) Clear All Register
+ *
+ * Any access to this register clears all the count values for the (x) registers.
+ */
+
+
+/*
+ * PCI-X Registers
+ *
+ * This register contains the address in the read buffer structure. There are
+ * 16 read buffer structures.
+ */
+	typedef union pic_rd_buf_addr_u {
+		picreg_t	pic_rd_buf_addr_regval;
+		struct {
+			picreg_t pcix_err_addr :	64; /* 63:0 */
+		} pic_rd_buf_addr_fld_s;
+	} pic_rd_buf_addr_u_t;
+/*
+ * PCI-X Read Buffer (x) Attribute Register
+ *
+ * This register contains the attribute data in the read buffer structure. There
+ * are  16 read buffer structures.
+ */
+	typedef union pic_px_read_buf_attr_u {
+		picreg_t	pic_px_read_buf_attr_regval;
+		struct {
+			picreg_t                :	16; /* 63:48 */
+			picreg_t bus_cmd        :	4; /* 47:44 */
+			picreg_t byte_cnt       :	12; /* 43:32 */
+			picreg_t entry_valid    :	1; /* 31:31 */
+			picreg_t ns             :	1; /* 30:30 */
+			picreg_t ro             :	1; /* 29:29 */
+			picreg_t tag            :	5; /* 28:24 */
+			picreg_t bus_num        :	8; /* 23:16 */
+			picreg_t dev_num        :	5; /* 15:11 */
+			picreg_t fun_num        :	3; /* 10:8 */
+			picreg_t                :	2; /* 7:6 */
+			picreg_t f_buffer_index :	6; /* 5:0 */
+		} pic_px_read_buf_attr_fld_s;
+	} pic_px_read_buf_attr_u_t;
+/*
+ * PCI-X Write Buffer (x) Address Register
+ *
+ * This register contains the address in the write buffer structure. There are
+ * 8 write buffer structures.
+ */
+	typedef union pic_px_write_buf_addr_u {
+		picreg_t	pic_px_write_buf_addr_regval;
+		struct {
+			picreg_t pcix_err_addr :	64; /* 63:0 */
+		} pic_px_write_buf_addr_fld_s;
+	} pic_px_write_buf_addr_u_t;
+/*
+ * PCI-X Write Buffer (x) Attribute Register
+ *
+ * This register contains the attribute data in the write buffer structure.
+ * There are 8 write buffer structures.
+ */
+	typedef union pic_px_write_buf_attr_u {
+		picreg_t	pic_px_write_buf_attr_regval;
+		struct {
+			picreg_t                :	16; /* 63:48 */
+			picreg_t bus_cmd        :	4; /* 47:44 */
+			picreg_t byte_cnt       :	12; /* 43:32 */
+			picreg_t entry_valid    :	1; /* 31:31 */
+			picreg_t ns             :	1; /* 30:30 */
+			picreg_t ro             :	1; /* 29:29 */
+			picreg_t tag            :	5; /* 28:24 */
+			picreg_t bus_num        :	8; /* 23:16 */
+			picreg_t dev_num        :	5; /* 15:11 */
+			picreg_t fun_num        :	3; /* 10:8 */
+			picreg_t                :	2; /* 7:6 */
+			picreg_t f_buffer_index :	6; /* 5:0 */
+		} pic_px_write_buf_attr_fld_s;
+	} pic_px_write_buf_attr_u_t;
+/*
+ * PCI-X Write Buffer (x) Valid Register
+ *
+ * This register contains the valid or inuse cache lines for this buffer struc-
+ * ture.
+ */
+	typedef union pic_px_write_buf_valid_u {
+		picreg_t	pic_px_write_buf_valid_regval;
+		struct {
+			picreg_t                :	32; /* 63:32 */
+			picreg_t wrt_valid_buff :	32; /* 31:0 */
+		} pic_px_write_buf_valid_fld_s;
+	} pic_px_write_buf_valid_u_t;
+
+#endif				/* __ASSEMBLY__ */
+#endif                          /* _ASM_SN_PCI_PIC_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/pda.h linux-2.4.21-pre6/include/asm-ia64/sn/pda.h
--- linux-2.4.20/include/asm-ia64/sn/pda.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/pda.h	2003-03-26 23:49:10.000000000 +0000
@@ -25,7 +25,14 @@
  * all SN per-cpu data structures. 
  */
 
-
+#ifdef BUS_INT_WAR
+#define POLL_ENTRIES	50
+typedef struct {
+	int	irq;
+	int	interval;
+	short	tick;
+} sn_poll_entry_t;
+#endif
 
 typedef struct pda_s {
 
@@ -56,8 +63,15 @@
 #endif
 	volatile unsigned long *bedrock_rev_id;
 	volatile unsigned long *pio_write_status_addr;
+	volatile unsigned long *pio_shub_war_cam_addr;
+	volatile unsigned long *mem_write_status_addr;
+
+	bteinfo_t *cpu_bte_if[BTES_PER_NODE];	/* cpu interface order */
 
-	bteinfo_t *cpubte[BTES_PER_NODE];
+#ifdef BUS_INT_WAR
+	sn_poll_entry_t	pda_poll_entries[POLL_ENTRIES];
+	int		pda_poll_entry_count;
+#endif
 } pda_t;
 
 
@@ -80,5 +94,7 @@
 
 #define pda		(*((pda_t *) PDAADDR))
 
+#define pdacpu(cpu)	(*((pda_t *) ((long)cpu_data(cpu) + CPU_DATA_END)))
+
 
 #endif /* _ASM_IA64_SN_PDA_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/rw_mmr.h linux-2.4.21-pre6/include/asm-ia64/sn/rw_mmr.h
--- linux-2.4.20/include/asm-ia64/sn/rw_mmr.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/rw_mmr.h	2003-03-26 23:49:54.000000000 +0000
@@ -0,0 +1,73 @@
+/*
+ * 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) 2002 Silicon Graphics, Inc.  All Rights Reserved.
+ */
+#ifndef _ASM_IA64_SN_RW_MMR_H
+#define _ASM_IA64_SN_RW_MMR_H
+
+
+/*
+ * This file contains macros used to access MMR registers via
+ * uncached physical addresses.
+ * 	pio_phys_read_mmr  - read an MMR
+ * 	pio_phys_write_mmr - write an MMR
+ * 	pio_atomic_phys_write_mmrs - atomically write 2 MMRs with psr.ic=0
+ * 		(interrupt collection)
+ *
+ * Addresses passed to these routines should be uncached physical addresses
+ * ie., 0x80000....
+ */
+
+
+extern inline long
+pio_phys_read_mmr(volatile long *mmr) 
+{
+	long val;
+        asm volatile
+            ("mov r2=psr;;"
+             "rsm psr.i | psr.dt;;"
+             "srlz.i;;"
+             "ld8.acq %0=[%1];;"
+             "mov psr.l=r2;;"
+             "srlz.i;;"
+             : "=r"(val)
+             : "r"(mmr)
+	     : "r2");
+        return val;
+}
+
+
+
+extern inline void
+pio_phys_write_mmr(volatile long *mmr, long val) 
+{
+        asm volatile
+            ("mov r2=psr;;"
+             "rsm psr.i | psr.dt;;"
+             "srlz.i;;"
+             "st8.rel [%0]=%1;;"
+             "mov psr.l=r2;;"
+             "srlz.i;;"
+	     :: "r"(mmr), "r"(val)
+             : "r2", "memory");
+}            
+
+extern inline void
+pio_atomic_phys_write_mmrs(volatile long *mmr1, long val1, volatile long *mmr2, long val2) 
+{
+        asm volatile
+            ("mov r2=psr;;"
+             "rsm psr.i | psr.dt | psr.ic;;"
+             "srlz.i;;"
+             "st8.rel [%0]=%1;"
+             "st8.rel [%2]=%3;;"
+             "mov psr.l=r2;;"
+             "srlz.i;;"
+	     :: "r"(mmr1), "r"(val1), "r"(mmr2), "r"(val2)
+             : "r2", "memory");
+}            
+
+#endif /* _ASM_IA64_SN_RW_MMR_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/sgi.h linux-2.4.21-pre6/include/asm-ia64/sn/sgi.h
--- linux-2.4.20/include/asm-ia64/sn/sgi.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/sgi.h	2003-03-26 23:48:58.000000000 +0000
@@ -18,82 +18,6 @@
 #include <linux/mm.h>
 #include <linux/devfs_fs_kernel.h>
 
-// This devfs stuff needs a better home .....
-
-struct directory_type
-{
-    struct devfs_entry *first;
-    struct devfs_entry *last;
-    unsigned int num_removable;
-};
-
-struct file_type
-{
-    unsigned long size;
-};
-
-struct device_type
-{
-    unsigned short major;
-    unsigned short minor;
-};
-
-struct fcb_type  /*  File, char, block type  */
-{
-    uid_t default_uid;
-    gid_t default_gid;
-    void *ops;
-    union 
-    {
-	struct file_type file;
-	struct device_type device;
-    }
-    u;
-    unsigned char auto_owner:1;
-    unsigned char aopen_notify:1;
-    unsigned char removable:1;  /*  Belongs in device_type, but save space   */
-    unsigned char open:1;       /*  Not entirely correct                     */
-};
-
-struct symlink_type
-{
-    unsigned int length;  /*  Not including the NULL-termimator  */
-    char *linkname;       /*  This is NULL-terminated            */
-};
-
-struct fifo_type
-{
-    uid_t uid;
-    gid_t gid;
-};
-
-struct devfs_entry
-{
-    void *info;
-    union 
-    {
-	struct directory_type dir;
-	struct fcb_type fcb;
-	struct symlink_type symlink;
-	struct fifo_type fifo;
-    }
-    u;
-    struct devfs_entry *prev;    /*  Previous entry in the parent directory  */
-    struct devfs_entry *next;    /*  Next entry in the parent directory      */
-    struct devfs_entry *parent;  /*  The parent directory                    */
-    struct devfs_entry *slave;   /*  Another entry to unregister             */
-    struct devfs_inode *first_inode;
-    struct devfs_inode *last_inode;
-    umode_t mode;
-    unsigned short namelen;  /*  I think 64k+ filenames are a way off...  */
-    unsigned char registered:1;
-    unsigned char show_unreg:1;
-    unsigned char hide:1;
-    unsigned char no_persistence /*:1*/;
-    char name[1];            /*  This is just a dummy: the allocated array is
-				 bigger. This is NULL-terminated  */
-};
-
 typedef int64_t  __psint_t;	/* needed by klgraph.c */
 
 typedef enum { B_FALSE, B_TRUE } boolean_t;
@@ -223,6 +147,31 @@
 #define cpu_enabled(cpu)	(1)
 #endif
 
+/* print_register() defs */
+
+/*
+ * register values
+ * map between numeric values and symbolic values
+ */
+struct reg_values {
+	unsigned long long rv_value;
+	char *rv_name;
+};
+
+/*
+ * register descriptors are used for formatted prints of register values
+ * rd_mask and rd_shift must be defined, other entries may be null
+ */
+struct reg_desc {
+	unsigned long long rd_mask;	/* mask to extract field */
+	int rd_shift;		/* shift for extracted value, - >>, + << */
+	char *rd_name;		/* field name */
+	char *rd_format;	/* format to print field */
+	struct reg_values *rd_values;	/* symbolic names of values */
+};
+
+extern void print_register(unsigned long long, struct reg_desc *);
+
 #include <asm/sn/hack.h>	/* for now */
 
 #endif /* _ASM_IA64_SN_SGI_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/simulator.h linux-2.4.21-pre6/include/asm-ia64/sn/simulator.h
--- linux-2.4.20/include/asm-ia64/sn/simulator.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/simulator.h	2003-03-26 23:49:40.000000000 +0000
@@ -5,7 +5,7 @@
  * 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 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 
 #include <linux/config.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/slotnum.h linux-2.4.21-pre6/include/asm-ia64/sn/slotnum.h
--- linux-2.4.20/include/asm-ia64/sn/slotnum.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/slotnum.h	2003-03-26 23:49:55.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 #ifndef _ASM_IA64_SN_SLOTNUM_H
 #define _ASM_IA64_SN_SLOTNUM_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/sn1/addrs.h linux-2.4.21-pre6/include/asm-ia64/sn/sn1/addrs.h
--- linux-2.4.20/include/asm-ia64/sn/sn1/addrs.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/sn1/addrs.h	2003-03-26 23:49:35.000000000 +0000
@@ -41,7 +41,8 @@
  * use some new ANSI preprocessor stuff to paste these on where needed.
  */
 
-#define CAC_BASE                0xe000000000000000
+#define CACHEABLE_MEM_SPACE     0xe000000000000000
+#define CAC_BASE		CACHEABLE_MEM_SPACE
 #define HSPEC_BASE              0xc0000b0000000000
 #define HSPEC_SWIZ_BASE         0xc000030000000000
 #define IO_BASE                 0xc0000a0000000000
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/sn1/arch.h linux-2.4.21-pre6/include/asm-ia64/sn/sn1/arch.h
--- linux-2.4.20/include/asm-ia64/sn/sn1/arch.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/sn1/arch.h	2003-03-26 23:49:08.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 #ifndef _ASM_IA64_SN_SN1_ARCH_H
 #define _ASM_IA64_SN_SN1_ARCH_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/sn1/hubdev.h linux-2.4.21-pre6/include/asm-ia64/sn/sn1/hubdev.h
--- linux-2.4.20/include/asm-ia64/sn/sn1/hubdev.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/sn1/hubdev.h	2003-03-26 23:49:29.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 
 #ifndef _ASM_IA64_SN_SN1_HUBDEV_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/sn1/hubio.h linux-2.4.21-pre6/include/asm-ia64/sn/sn1/hubio.h
--- linux-2.4.20/include/asm-ia64/sn/sn1/hubio.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/sn1/hubio.h	2003-03-26 23:49:51.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 
 /************************************************************************
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/sn1/hublb.h linux-2.4.21-pre6/include/asm-ia64/sn/sn1/hublb.h
--- linux-2.4.20/include/asm-ia64/sn/sn1/hublb.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/sn1/hublb.h	2003-03-26 23:49:24.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 
 /************************************************************************
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/sn1/hublb_next.h linux-2.4.21-pre6/include/asm-ia64/sn/sn1/hublb_next.h
--- linux-2.4.20/include/asm-ia64/sn/sn1/hublb_next.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/sn1/hublb_next.h	2003-03-26 23:49:08.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 #ifndef _ASM_IA64_SN_SN1_HUBLB_NEXT_H
 #define _ASM_IA64_SN_SN1_HUBLB_NEXT_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/sn1/hubmd.h linux-2.4.21-pre6/include/asm-ia64/sn/sn1/hubmd.h
--- linux-2.4.20/include/asm-ia64/sn/sn1/hubmd.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/sn1/hubmd.h	2003-03-26 23:49:50.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 #ifndef _ASM_IA64_SN_SN1_HUBMD_H
 #define _ASM_IA64_SN_SN1_HUBMD_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/sn1/hubni.h linux-2.4.21-pre6/include/asm-ia64/sn/sn1/hubni.h
--- linux-2.4.20/include/asm-ia64/sn/sn1/hubni.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/sn1/hubni.h	2003-03-26 23:49:39.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 #ifndef _ASM_IA64_SN_SN1_HUBNI_H
 #define _ASM_IA64_SN_SN1_HUBNI_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/sn1/hubni_next.h linux-2.4.21-pre6/include/asm-ia64/sn/sn1/hubni_next.h
--- linux-2.4.20/include/asm-ia64/sn/sn1/hubni_next.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/sn1/hubni_next.h	2003-03-26 23:49:55.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 #ifndef _ASM_IA64_SN_SN1_HUBNI_NEXT_H
 #define _ASM_IA64_SN_SN1_HUBNI_NEXT_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/sn1/hubpi.h linux-2.4.21-pre6/include/asm-ia64/sn/sn1/hubpi.h
--- linux-2.4.20/include/asm-ia64/sn/sn1/hubpi.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/sn1/hubpi.h	2003-03-26 23:49:27.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 #ifndef _ASM_IA64_SN_SN1_HUBPI_H
 #define _ASM_IA64_SN_SN1_HUBPI_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/sn1/hubpi_next.h linux-2.4.21-pre6/include/asm-ia64/sn/sn1/hubpi_next.h
--- linux-2.4.20/include/asm-ia64/sn/sn1/hubpi_next.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/sn1/hubpi_next.h	2003-03-26 23:49:53.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 #ifndef _ASM_IA64_SN_SN1_HUBPI_NEXT_H
 #define _ASM_IA64_SN_SN1_HUBPI_NEXT_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/sn1/hubspc.h linux-2.4.21-pre6/include/asm-ia64/sn/sn1/hubspc.h
--- linux-2.4.20/include/asm-ia64/sn/sn1/hubspc.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/sn1/hubspc.h	2003-03-26 23:49:07.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 #ifndef _ASM_IA64_SN_SN1_HUBSPC_H
 #define _ASM_IA64_SN_SN1_HUBSPC_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/sn1/hubstat.h linux-2.4.21-pre6/include/asm-ia64/sn/sn1/hubstat.h
--- linux-2.4.20/include/asm-ia64/sn/sn1/hubstat.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/sn1/hubstat.h	2003-03-26 23:49:39.000000000 +0000
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2000 - 2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 
 #ifndef _ASM_IA64_SN_SN1_HUBSTAT_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/sn1/hubxb.h linux-2.4.21-pre6/include/asm-ia64/sn/sn1/hubxb.h
--- linux-2.4.20/include/asm-ia64/sn/sn1/hubxb.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/sn1/hubxb.h	2003-03-26 23:49:40.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 #ifndef _ASM_IA64_SN_SN1_HUBXB_H
 #define _ASM_IA64_SN_SN1_HUBXB_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/sn1/hubxb_next.h linux-2.4.21-pre6/include/asm-ia64/sn/sn1/hubxb_next.h
--- linux-2.4.20/include/asm-ia64/sn/sn1/hubxb_next.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/sn1/hubxb_next.h	2003-03-26 23:49:25.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 #ifndef _ASM_IA64_SN_SN1_HUBXB_NEXT_H
 #define _ASM_IA64_SN_SN1_HUBXB_NEXT_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/sn1/hwcntrs.h linux-2.4.21-pre6/include/asm-ia64/sn/sn1/hwcntrs.h
--- linux-2.4.20/include/asm-ia64/sn/sn1/hwcntrs.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/sn1/hwcntrs.h	2003-03-26 23:49:19.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 #ifndef _ASM_IA64_SN_SN1_HWCNTRS_H
 #define _ASM_IA64_SN_SN1_HWCNTRS_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/sn1/intr_public.h linux-2.4.21-pre6/include/asm-ia64/sn/sn1/intr_public.h
--- linux-2.4.20/include/asm-ia64/sn/sn1/intr_public.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/sn1/intr_public.h	2003-03-26 23:49:26.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 #ifndef _ASM_IA64_SN_SN1_INTR_PUBLIC_H
 #define _ASM_IA64_SN_SN1_INTR_PUBLIC_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/sn1/mem_refcnt.h linux-2.4.21-pre6/include/asm-ia64/sn/sn1/mem_refcnt.h
--- linux-2.4.20/include/asm-ia64/sn/sn1/mem_refcnt.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/sn1/mem_refcnt.h	2003-03-26 23:48:58.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 #ifndef _ASM_IA64_SN_SN1_MEM_REFCNT_H
 #define _ASM_IA64_SN_SN1_MEM_REFCNT_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/sn1/slotnum.h linux-2.4.21-pre6/include/asm-ia64/sn/sn1/slotnum.h
--- linux-2.4.20/include/asm-ia64/sn/sn1/slotnum.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/sn1/slotnum.h	2003-03-26 23:49:30.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 
 #ifndef _ASM_IA64_SN_SN1_SLOTNUM_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/sn1/sn_private.h linux-2.4.21-pre6/include/asm-ia64/sn/sn1/sn_private.h
--- linux-2.4.20/include/asm-ia64/sn/sn1/sn_private.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/sn1/sn_private.h	2003-03-26 23:49:10.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 #ifndef _ASM_IA64_SN_SN1_SN_PRIVATE_H
 #define _ASM_IA64_SN_SN1_SN_PRIVATE_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/sn1/synergy.h linux-2.4.21-pre6/include/asm-ia64/sn/sn1/synergy.h
--- linux-2.4.20/include/asm-ia64/sn/sn1/synergy.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/sn1/synergy.h	2003-03-26 23:49:55.000000000 +0000
@@ -54,9 +54,6 @@
 
 #define WRITE_LOCAL_SYNERGY_REG(addr, value)	__synergy_out(addr, value)
 
-#define HUB_L(_a)               *(_a)
-#define HUB_S(_a, _d)           *(_a) = (_d)
-
 #define HSPEC_SYNERGY0_0        0x04000000    /* Synergy0 Registers     */
 #define HSPEC_SYNERGY1_0        0x05000000    /* Synergy1 Registers     */
 #define HS_SYNERGY_STRIDE       (HSPEC_SYNERGY1_0 - HSPEC_SYNERGY0_0)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/sn2/addrs.h linux-2.4.21-pre6/include/asm-ia64/sn/sn2/addrs.h
--- linux-2.4.20/include/asm-ia64/sn/sn2/addrs.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/sn2/addrs.h	2003-03-26 23:48:58.000000000 +0000
@@ -53,19 +53,26 @@
 
 /* Regions determined by AS */
 #define LOCAL_MMR_SPACE		0xc000008000000000	/* Local MMR space */
+#define LOCAL_PHYS_MMR_SPACE	0x8000008000000000	/* Local PhysicalMMR space */
 #define LOCAL_MEM_SPACE		0xc000010000000000	/* Local Memory space */
 #define GLOBAL_MMR_SPACE	0xc000000800000000	/* Global MMR space */
+#define GLOBAL_PHYS_MMR_SPACE	0x0000000800000000	/* Global Physical MMR space */
 #define GET_SPACE		0xc000001000000000	/* GET space */
 #define AMO_SPACE		0xc000002000000000	/* AMO space */
 #define CACHEABLE_MEM_SPACE	0xe000003000000000	/* Cacheable memory space */
 #define UNCACHED                0xc000000000000000      /* UnCacheable memory space */
+#define UNCACHED_PHYS           0x8000000000000000      /* UnCacheable physical memory space */
+
+#define PHYS_MEM_SPACE		0x0000003000000000	/* physical memory space */
 
 /* SN2 address macros */
 #define NID_SHFT		38
 #define LOCAL_MMR_ADDR(a)	(UNCACHED | LOCAL_MMR_SPACE | (a))
+#define LOCAL_MMR_PHYS_ADDR(a)	(UNCACHED_PHYS | LOCAL_PHYS_MMR_SPACE | (a))
 #define LOCAL_MEM_ADDR(a)	(LOCAL_MEM_SPACE | (a))
 #define REMOTE_ADDR(n,a)	((((unsigned long)(n))<<NID_SHFT) | (a))
 #define GLOBAL_MMR_ADDR(n,a)	(UNCACHED | GLOBAL_MMR_SPACE | REMOTE_ADDR(n,a))
+#define GLOBAL_MMR_PHYS_ADDR(n,a) (UNCACHED_PHYS | GLOBAL_PHYS_MMR_SPACE | REMOTE_ADDR(n,a))
 #define GET_ADDR(n,a)		(GET_SPACE | REMOTE_ADDR(n,a))
 #define AMO_ADDR(n,a)		(UNCACHED | AMO_SPACE | REMOTE_ADDR(n,a))
 #define GLOBAL_MEM_ADDR(n,a)	(CACHEABLE_MEM_SPACE | REMOTE_ADDR(n,a))
@@ -104,15 +111,19 @@
 #define NASID_MASK              (UINT64_CAST NASID_BITMASK << NASID_SHFT)
 #define NASID_GET(_pa)          (int) ((UINT64_CAST (_pa) >>            \
                                         NASID_SHFT) & NASID_BITMASK)
-#ifdef __IA64
 #define PHYS_TO_DMA(x)          ( ((x & NASID_MASK) >> 2) |             \
                                   (x & (NODE_ADDRSPACE_SIZE - 1)) )
-#else
-#define PHYS_TO_DMA(x)          ( (x) )
-#endif
 
 #define CHANGE_NASID(n,x)	({ia64_sn2_pa_t _v; _v.l = (long) (x); _v.f.nasid = n; _v.p;})
 
+/*
+ * Determine if a physical address should be referenced as cached or uncached. 
+ * For now, assume all memory is cached and everything else is noncached.
+ * (Later, we may need to special case areas of memory to be reference uncached).
+ */
+#define IS_CACHED_ADDRESS(x)	(((x) & PHYS_MEM_SPACE) == PHYS_MEM_SPACE)
+
+
 #ifndef __ASSEMBLY__
 #define NODE_SWIN_BASE(nasid, widget)                                   \
         ((widget == 0) ? NODE_BWIN_BASE((nasid), SWIN0_BIGWIN)          \
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/sn2/arch.h linux-2.4.21-pre6/include/asm-ia64/sn/sn2/arch.h
--- linux-2.4.20/include/asm-ia64/sn/sn2/arch.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/sn2/arch.h	2003-03-26 23:49:54.000000000 +0000
@@ -61,6 +61,4 @@
 #define TO_SLICE(subn, local)	(((subn) << SUBNODE_SHFT) | \
 				 ((local) << LOCALCPU_SHFT))
 
-typedef u64 mmr_t;
-
 #endif /* _ASM_IA64_SN_SN2_ARCH_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/sn2/geo.h linux-2.4.21-pre6/include/asm-ia64/sn/sn2/geo.h
--- linux-2.4.20/include/asm-ia64/sn/sn2/geo.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/sn2/geo.h	2003-03-26 23:49:40.000000000 +0000
@@ -0,0 +1,109 @@
+/* $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) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#ifndef __SYS_SN_SN2_GEO_H__
+#define __SYS_SN_SN2_GEO_H__
+
+/* Headers required by declarations in this file */
+
+#include <asm/sn/slotnum.h>
+
+
+/* The geoid_t implementation below is based loosely on the pcfg_t
+   implementation in sys/SN/promcfg.h. */
+
+/* Type declaractions */
+
+/* Size of a geoid_t structure (must be before decl. of geoid_u) */
+#define GEOID_SIZE	8	/* Would 16 be better?  The size can
+				   be different on different platforms. */
+
+#define MAX_SLABS	0xe	/* slabs per module */
+
+typedef unsigned char	geo_type_t;
+
+/* Fields common to all substructures */
+typedef struct geo_any_s {
+    moduleid_t	module;		/* The module (box) this h/w lives in */
+    geo_type_t	type;		/* What type of h/w is named by this geoid_t */
+    slabid_t	slab;		/* The logical assembly within the module */
+} geo_any_t;
+
+/* Additional fields for particular types of hardware */
+typedef struct geo_node_s {
+    geo_any_t	any;		/* No additional fields needed */
+} geo_node_t;
+
+typedef struct geo_rtr_s {
+    geo_any_t	any;		/* No additional fields needed */
+} geo_rtr_t;
+
+typedef struct geo_iocntl_s {
+    geo_any_t	any;		/* No additional fields needed */
+} geo_iocntl_t;
+
+typedef struct geo_pcicard_s {
+    geo_iocntl_t	any;
+    char		bus;	/* Bus/widget number */
+    slotid_t		slot;	/* PCI slot number */
+} geo_pcicard_t;
+
+/* Subcomponents of a node */
+typedef struct geo_cpu_s {
+    geo_node_t	node;
+    char	slice;		/* Which CPU on the node */
+} geo_cpu_t;
+
+typedef struct geo_mem_s {
+    geo_node_t	node;
+    char	membus;		/* The memory bus on the node */
+    char	memslot;	/* The memory slot on the bus */
+} geo_mem_t;
+
+
+typedef union geoid_u {
+    geo_any_t	any;
+    geo_node_t	node;
+    geo_iocntl_t	iocntl;
+    geo_pcicard_t	pcicard;
+    geo_rtr_t	rtr;
+    geo_cpu_t	cpu;
+    geo_mem_t	mem;
+    char	padsize[GEOID_SIZE];
+} geoid_t;
+
+
+/* Preprocessor macros */
+
+#define GEO_MAX_LEN	48	/* max. formatted length, plus some pad:
+				   module/001c07/slab/5/node/memory/2/slot/4 */
+
+/* Values for geo_type_t */
+#define GEO_TYPE_INVALID	0
+#define GEO_TYPE_MODULE		1
+#define GEO_TYPE_NODE		2
+#define GEO_TYPE_RTR		3
+#define GEO_TYPE_IOCNTL		4
+#define GEO_TYPE_IOCARD		5
+#define GEO_TYPE_CPU		6
+#define GEO_TYPE_MEM		7
+#define GEO_TYPE_MAX		(GEO_TYPE_MEM+1)
+
+/* Parameter for hwcfg_format_geoid_compt() */
+#define GEO_COMPT_MODULE	1
+#define GEO_COMPT_SLAB		2
+#define GEO_COMPT_IOBUS		3
+#define GEO_COMPT_IOSLOT	4
+#define GEO_COMPT_CPU		5
+#define GEO_COMPT_MEMBUS	6
+#define GEO_COMPT_MEMSLOT	7
+
+#define GEO_INVALID_STR		"<invalid>"
+
+#endif /* __SYS_SN_SN2_GEO_H__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/sn2/intr.h linux-2.4.21-pre6/include/asm-ia64/sn/sn2/intr.h
--- linux-2.4.20/include/asm-ia64/sn/sn2/intr.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/sn2/intr.h	2003-03-26 23:49:20.000000000 +0000
@@ -13,8 +13,8 @@
 #define SGI_SHUB_ERROR_VECTOR   (0xea)
 
 // These two IRQ's are used by partitioning.
+#define SGI_XPC_ACTIVATE		(0x30)
 #define SGI_XPC_NOTIFY			(0xe7)
-#define SGI_XPART_ACTIVATE		(0x30)
 
 #define IA64_SN2_FIRST_DEVICE_VECTOR	(0x31)
 #define IA64_SN2_LAST_DEVICE_VECTOR	(0xe6)
@@ -22,4 +22,6 @@
 #define SN2_IRQ_RESERVED        (0x1)
 #define SN2_IRQ_CONNECTED       (0x2)
 
+#define SN2_IRQ_PER_HUB         (2048)
+
 #endif /* _ASM_IA64_SN_SN2_INTR_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/sn2/shub.h linux-2.4.21-pre6/include/asm-ia64/sn/sn2/shub.h
--- linux-2.4.20/include/asm-ia64/sn/sn2/shub.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/sn2/shub.h	2003-03-26 23:49:02.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (c) 2001 Silicon Graphics, Inc.  All rights reserved.
+ * Copyright (c) 2001-2002 Silicon Graphics, Inc.  All rights reserved.
  */
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/sn2/shub_mmr.h linux-2.4.21-pre6/include/asm-ia64/sn/sn2/shub_mmr.h
--- linux-2.4.20/include/asm-ia64/sn/sn2/shub_mmr.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/sn2/shub_mmr.h	2003-03-26 23:49:26.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (c) 2001 Silicon Graphics, Inc.  All rights reserved.
+ * Copyright (c) 2001-2002 Silicon Graphics, Inc.  All rights reserved.
  */
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/sn2/shubio.h linux-2.4.21-pre6/include/asm-ia64/sn/sn2/shubio.h
--- linux-2.4.20/include/asm-ia64/sn/sn2/shubio.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/sn2/shubio.h	2003-03-26 23:49:25.000000000 +0000
@@ -3089,11 +3089,11 @@
         #define IIO_FIRST_PC_ENTRY 12
  */
 
-#define IIO_ICRB_A(_x)  (IIO_ICRB_0 + (6 * IIO_ICRB_OFFSET * (_x)))
-#define IIO_ICRB_B(_x)  (IIO_ICRB_A(_x) + 1*IIO_ICRB_OFFSET)
-#define IIO_ICRB_C(_x)  (IIO_ICRB_A(_x) + 2*IIO_ICRB_OFFSET)
-#define IIO_ICRB_D(_x)  (IIO_ICRB_A(_x) + 3*IIO_ICRB_OFFSET)
-#define IIO_ICRB_E(_x)  (IIO_ICRB_A(_x) + 4*IIO_ICRB_OFFSET)
+#define IIO_ICRB_A(_x)  ((u64)(IIO_ICRB_0 + (6 * IIO_ICRB_OFFSET * (_x))))
+#define IIO_ICRB_B(_x)  ((u64)((char *)IIO_ICRB_A(_x) + 1*IIO_ICRB_OFFSET))
+#define IIO_ICRB_C(_x)  ((u64)((char *)IIO_ICRB_A(_x) + 2*IIO_ICRB_OFFSET))
+#define IIO_ICRB_D(_x)  ((u64)((char *)IIO_ICRB_A(_x) + 3*IIO_ICRB_OFFSET))
+#define IIO_ICRB_E(_x)  ((u64)((char *)IIO_ICRB_A(_x) + 4*IIO_ICRB_OFFSET))
 
 #define TNUM_TO_WIDGET_DEV(_tnum)	(_tnum & 0x7)
 
@@ -3288,12 +3288,9 @@
 #ifndef __ASSEMBLY__
 
 /*
- * Easy access macros for CRBs, all 4 registers (A-D)
+ * Easy access macros for CRBs, all 5 registers (A-E)
  */
 typedef ii_icrb0_a_u_t icrba_t;
-#define a_lnetuce       ii_icrb0_a_fld_s.ia_ln_uce
-#define a_mark          ii_icrb0_a_fld_s.ia_mark
-#define a_xerr          ii_icrb0_a_fld_s.ia_xt_err
 #define a_sidn          ii_icrb0_a_fld_s.ia_sidn
 #define a_tnum          ii_icrb0_a_fld_s.ia_tnum
 #define a_addr          ii_icrb0_a_fld_s.ia_addr
@@ -3302,35 +3299,56 @@
 #define a_regvalue	ii_icrb0_a_regval
 
 typedef ii_icrb0_b_u_t icrbb_t;
-#define b_error         ii_icrb0_b_fld_s.ib_error
-#define b_ecode         ii_icrb0_b_fld_s.ib_errcode
-#define b_cohtrans      ii_icrb0_b_fld_s.ib_ct
-#define b_xtsize        ii_icrb0_b_fld_s.ib_size
-#define b_source        ii_icrb0_b_fld_s.ib_source
+#define b_use_old       ii_icrb0_b_fld_s.ib_use_old
 #define b_imsgtype      ii_icrb0_b_fld_s.ib_imsgtype
 #define b_imsg          ii_icrb0_b_fld_s.ib_imsg
 #define b_initiator     ii_icrb0_b_fld_s.ib_init
+#define b_exc           ii_icrb0_b_fld_s.ib_exc
+#define b_ackcnt        ii_icrb0_b_fld_s.ib_ack_cnt
+#define b_resp          ii_icrb0_b_fld_s.ib_resp
+#define b_ack           ii_icrb0_b_fld_s.ib_ack
+#define b_hold          ii_icrb0_b_fld_s.ib_hold
+#define b_wb            ii_icrb0_b_fld_s.ib_wb
+#define b_intvn         ii_icrb0_b_fld_s.ib_intvn
+#define b_stall_ib      ii_icrb0_b_fld_s.ib_stall_ib
+#define b_stall_int     ii_icrb0_b_fld_s.ib_stall__intr
+#define b_stall_bte_0   ii_icrb0_b_fld_s.ib_stall__bte_0
+#define b_stall_bte_1   ii_icrb0_b_fld_s.ib_stall__bte_1
+#define b_error         ii_icrb0_b_fld_s.ib_error
+#define b_ecode         ii_icrb0_b_fld_s.ib_errcode
+#define b_lnetuce       ii_icrb0_b_fld_s.ib_ln_uce
+#define b_mark          ii_icrb0_b_fld_s.ib_mark
+#define b_xerr          ii_icrb0_b_fld_s.ib_xt_err
 #define b_regvalue	ii_icrb0_b_regval
 
 typedef ii_icrb0_c_u_t icrbc_t;
-#define c_btenum        ii_icrb0_c_fld_s.ic_bte_num
-#define c_pricnt        ii_icrb0_c_fld_s.ic_pr_cnt
-#define c_pripsc        ii_icrb0_c_fld_s.ic_pr_psc
-#define c_bteaddr       ii_icrb0_c_fld_s.ic_pa_be /* ic_pa_be fld has 2 names*/
-#define c_benable       ii_icrb0_c_fld_s.ic_pa_be /* ic_pa_be fld has 2 names*/
 #define c_suppl         ii_icrb0_c_fld_s.ic_suppl
 #define c_barrop        ii_icrb0_c_fld_s.ic_bo
 #define c_doresp        ii_icrb0_c_fld_s.ic_resprqd
 #define c_gbr           ii_icrb0_c_fld_s.ic_gbr
+#define c_btenum        ii_icrb0_c_fld_s.ic_bte_num
+#define c_cohtrans      ii_icrb0_c_fld_s.ic_ct
+#define c_xtsize        ii_icrb0_c_fld_s.ic_size
+#define c_source        ii_icrb0_c_fld_s.ic_source
 #define c_regvalue	ii_icrb0_c_regval
 
+
 typedef ii_icrb0_d_u_t icrbd_t;
+#define d_sleep         ii_icrb0_d_fld_s.id_sleep
+#define d_pricnt        ii_icrb0_d_fld_s.id_pr_cnt
+#define d_pripsc        ii_icrb0_d_fld_s.id_pr_psc
 #define d_bteop         ii_icrb0_d_fld_s.id_bte_op
-#define icrbd_ctxtvld   ii_icrb0_d_fld_s.id_cvld
-#define icrbd_toutvld   ii_icrb0_d_fld_s.id_tvld
-#define icrbd_context   ii_icrb0_d_fld_s.id_context
+#define d_bteaddr       ii_icrb0_d_fld_s.id_pa_be /* ic_pa_be fld has 2 names*/
+#define d_benable       ii_icrb0_d_fld_s.id_pa_be /* ic_pa_be fld has 2 names*/
 #define d_regvalue	ii_icrb0_d_regval
 
+typedef ii_icrb0_e_u_t icrbe_t;
+#define icrbe_ctxtvld   ii_icrb0_e_fld_s.ie_cvld
+#define icrbe_toutvld   ii_icrb0_e_fld_s.ie_tvld
+#define icrbe_context   ii_icrb0_e_fld_s.ie_context
+#define icrbe_timeout   ii_icrb0_e_fld_s.ie_timeout
+#define e_regvalue	ii_icrb0_e_regval
+
 #endif /* __ASSEMBLY__ */
 
 /* Number of widgets supported by shub */
@@ -3570,8 +3588,9 @@
 
 extern int
 hub_intr_connect(       hub_intr_t intr_hdl,    /* xtalk intr resource hndl */
-                        xtalk_intr_setfunc_t setfunc,
-                                                /* func to set intr hw */
+			intr_func_t intr_func,          /* xtalk intr handler */
+			void *intr_arg,                 /* arg to intr handler */
+                        xtalk_intr_setfunc_t setfunc, /* func to set intr hw */
                         void *setfunc_arg);     /* arg to setfunc */
 
 extern void
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/sn2/slotnum.h linux-2.4.21-pre6/include/asm-ia64/sn/sn2/slotnum.h
--- linux-2.4.20/include/asm-ia64/sn/sn2/slotnum.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/sn2/slotnum.h	2003-03-26 23:49:25.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (c) 1992 - 1997,2001 Silicon Graphics, Inc.  All rights reserved.
+ * Copyright (c) 1992-1997,2001-2002 Silicon Graphics, Inc. All rights reserved.
  */
 
 #ifndef _ASM_IA64_SN_SN2_SLOTNUM_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/sn2/sn_private.h linux-2.4.21-pre6/include/asm-ia64/sn/sn2/sn_private.h
--- linux-2.4.20/include/asm-ia64/sn/sn2/sn_private.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/sn2/sn_private.h	2003-03-26 23:49:54.000000000 +0000
@@ -27,7 +27,7 @@
 extern nasid_t get_console_nasid(void);
 extern char get_console_pcislot(void);
 
-extern int is_master_nasid_widget(nasid_t test_nasid, xwidgetnum_t test_wid);
+extern int is_master_baseio_nasid_widget(nasid_t test_nasid, xwidgetnum_t test_wid);
 
 /* memsupport.c */
 extern void poison_state_alter_range(__psunsigned_t start, int len, int poison);
@@ -43,8 +43,10 @@
 extern void set_dir_state_UNOWNED(paddr_t);
 extern int is_POISONED_dir_state(paddr_t);
 extern int is_UNOWNED_dir_state(paddr_t);
+#ifdef LATER
 extern void get_dir_ent(paddr_t paddr, int *state,
 			uint64_t *vec_ptr, hubreg_t *elo);
+#endif
 
 /* intr.c */
 extern int intr_reserve_level(cpuid_t cpu, int level, int err, devfs_handle_t owner_dev, char *name);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/sn_cpuid.h linux-2.4.21-pre6/include/asm-ia64/sn/sn_cpuid.h
--- linux-2.4.20/include/asm-ia64/sn/sn_cpuid.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/sn_cpuid.h	2003-03-26 23:49:08.000000000 +0000
@@ -121,13 +121,19 @@
 #endif
 
 /*
- * NOTE: id & eid refer to Intels definitions of the LID register
- *	(id = NASID, eid = slice)
+ * NOTE: id & eid refer to Intel's definitions of the LID register
+ * 
  * NOTE: on non-MP systems, only cpuid 0 exists
  */
-#define id_eid_to_cpu_physical_id(id,eid)       (((id)<<8) | (eid))
-#define id_eid_to_cpuid(id,eid)         	(cpu_logical_id(id_eid_to_cpu_physical_id((id),(eid))))
+#define id_eid_to_cpu_physical_id(id,eid)	 	(((id)<<8) | (eid))
 
+#define nasid_slice_to_cpuid(nasid,slice)		(cpu_logical_id(nasid_slice_to_cpu_physical_id((nasid),(slice))))
+
+#ifdef CONFIG_IA64_SGI_SN1
+#define nasid_slice_to_cpu_physical_id(nasid, slice)	(((nasid)<<8) | (slice))
+#else
+#define nasid_slice_to_cpu_physical_id(nasid, slice)	(((slice)<<12) | (nasid))
+#endif
 
 /*
  * The following table/struct  is used for managing PTC coherency domains.
@@ -196,7 +202,8 @@
 /*
  * cnode_slice_to_cpuid - convert a codeid & slice to a cpuid
  */
-#define cnode_slice_to_cpuid(cnodeid,slice) (id_eid_to_cpuid(cnodeid_to_nasid(cnodeid),(slice)))
+
+#define cnode_slice_to_cpuid(cnodeid,slice) (nasid_slice_to_cpuid(cnodeid_to_nasid(cnodeid),(slice)))
  
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/sn_fru.h linux-2.4.21-pre6/include/asm-ia64/sn/sn_fru.h
--- linux-2.4.20/include/asm-ia64/sn/sn_fru.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/sn_fru.h	2003-03-26 23:48:59.000000000 +0000
@@ -4,8 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 1999-2001 Silicon Graphics, Inc. 
- * All rights reserved.
+ * Copyright (C) 1992-1997,1999-2002 Silicon Graphics, Inc. All rights reserved.
  */
 #ifndef _ASM_IA64_SN_SN_FRU_H
 #define _ASM_IA64_SN_SN_FRU_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/sn_private.h linux-2.4.21-pre6/include/asm-ia64/sn/sn_private.h
--- linux-2.4.20/include/asm-ia64/sn/sn_private.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/sn_private.h	2003-03-26 23:49:05.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 #ifndef _ASM_IA64_SN_SN_PRIVATE_H
 #define _ASM_IA64_SN_SN_PRIVATE_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/sn_sal.h linux-2.4.21-pre6/include/asm-ia64/sn/sn_sal.h
--- linux-2.4.20/include/asm-ia64/sn/sn_sal.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/sn_sal.h	2003-03-26 23:49:39.000000000 +0000
@@ -12,18 +12,22 @@
  */
 
 
+#include <linux/config.h>
 #include <asm/sal.h>
 #include <asm/sn/sn_cpuid.h>
+#include <asm/sn/arch.h>
 
 
 // SGI Specific Calls
 #define  SN_SAL_POD_MODE                           0x02000001
 #define  SN_SAL_SYSTEM_RESET                       0x02000002
 #define  SN_SAL_PROBE                              0x02000003
-#define  SN_SAL_GET_CONSOLE_NASID                  0x02000004
+#define  SN_SAL_GET_MASTER_NASID                   0x02000004
 #define	 SN_SAL_GET_KLCONFIG_ADDR		   0x02000005
 #define  SN_SAL_LOG_CE				   0x02000006
 #define  SN_SAL_REGISTER_CE			   0x02000007
+#define  SN_SAL_GET_PARTITION_ADDR		   0x02000009
+#define  SN_SAL_PRINT_ERROR			   0x02000012
 #define  SN_SAL_CONSOLE_PUTC                       0x02000021
 #define  SN_SAL_CONSOLE_GETC                       0x02000022
 #define  SN_SAL_CONSOLE_PUTS                       0x02000023
@@ -31,6 +35,19 @@
 #define  SN_SAL_CONSOLE_GETS_TIMEOUT               0x02000025
 #define  SN_SAL_CONSOLE_POLL                       0x02000026
 #define  SN_SAL_CONSOLE_INTR                       0x02000027
+#define  SN_SAL_CONSOLE_PUTB			   0x02000028
+#define  SN_SAL_SYSCTL_MODID_GET	           0x02000031
+#define  SN_SAL_SYSCTL_GET                         0x02000032
+#define  SN_SAL_SYSCTL_IOBRICK_MODULE_GET          0x02000033
+#define  SN_SAL_SYSCTL_IO_PORTSPEED_GET            0x02000035
+#define  SN_SAL_SYSCTL_SLAB_GET                    0x02000036
+#define  SN_SAL_BUS_CONFIG		   	   0x02000037
+#define  SN_SAL_SYS_SERIAL_GET			   0x02000038
+#define  SN_SAL_PARTITION_SERIAL_GET		   0x02000039
+#define  SN_SAL_SYSCTL_PARTITION_GET		   0x0200003a
+#define  SN_SAL_SYSTEM_POWER_DOWN		   0x0200003b
+#define  SN_SAL_GET_MASTER_BASEIO_NASID		   0x0200003c
+
 
 /*
  * Service-specific constants
@@ -43,7 +60,58 @@
 #define SAL_CONSOLE_INTR_ON     1       /* turn the interrupt on */
 
 
+/*
+ * SN_SAL_GET_PARTITION_ADDR return constants
+ */
+#define SALRET_MORE_PASSES	1
+#define SALRET_OK		0
+#define SALRET_INVALID_ARG	-2
+#define SALRET_ERROR		-3
+
+
+/**
+ * sn_sal_rev_major - get the major SGI SAL revision number
+ *
+ * The SGI PROM stores its version in sal_[ab]_rev_(major|minor).
+ * This routine simply extracts the major value from the
+ * @ia64_sal_systab structure constructed by ia64_sal_init().
+ */
+static inline int
+sn_sal_rev_major(void)
+{
+	struct ia64_sal_systab *systab = efi.sal_systab;
+
+	return (int)systab->sal_b_rev_major;
+}
+
+/**
+ * sn_sal_rev_minor - get the minor SGI SAL revision number
+ *
+ * The SGI PROM stores its version in sal_[ab]_rev_(major|minor).
+ * This routine simply extracts the minor value from the
+ * @ia64_sal_systab structure constructed by ia64_sal_init().
+ */
+static inline int
+sn_sal_rev_minor(void)
+{
+	struct ia64_sal_systab *systab = efi.sal_systab;
+	
+	return (int)systab->sal_b_rev_minor;
+}
 
+/*
+ * Specify the minimum PROM revsion required for this kernel.
+ * Note that they're stored in hex format...
+ */
+#ifdef CONFIG_IA64_SGI_SN1
+#define SN_SAL_MIN_MAJOR	0x0
+#define SN_SAL_MIN_MINOR	0x03 /* SN1 PROMs are stuck at rev 0.03 */
+#elif defined(CONFIG_IA64_SGI_SN2)
+#define SN_SAL_MIN_MAJOR	0x0
+#define SN_SAL_MIN_MINOR	0x11
+#else
+#error "must specify which PROM revisions this kernel needs"
+#endif /* CONFIG_IA64_SGI_SN1 */
 
 u64 ia64_sn_probe_io_slot(long paddr, long size, void *data_ptr);
 
@@ -60,7 +128,7 @@
 	ret_stuff.v0 = (uint64_t)0;
 	ret_stuff.v1 = (uint64_t)0;
 	ret_stuff.v2 = (uint64_t)0;
-	SAL_CALL(ret_stuff, SN_SAL_GET_CONSOLE_NASID, 0, 0, 0, 0, 0, 0, 0);
+	SAL_CALL(ret_stuff, SN_SAL_GET_MASTER_NASID, 0, 0, 0, 0, 0, 0, 0);
 
 	if (ret_stuff.status < 0)
 		return ret_stuff.status;
@@ -69,6 +137,28 @@
 	return ret_stuff.v0;
 }
 
+/*
+ * Returns the master baseio nasid, if the call fails, return an illegal
+ * value.
+ */
+static inline u64
+ia64_sn_get_master_baseio_nasid(void)
+{
+	struct ia64_sal_retval ret_stuff;
+
+	ret_stuff.status = (uint64_t)0;
+	ret_stuff.v0 = (uint64_t)0;
+	ret_stuff.v1 = (uint64_t)0;
+	ret_stuff.v2 = (uint64_t)0;
+	SAL_CALL(ret_stuff, SN_SAL_GET_MASTER_BASEIO_NASID, 0, 0, 0, 0, 0, 0, 0);
+
+	if (ret_stuff.status < 0)
+		return ret_stuff.status;
+
+	/* Master baseio nasid is in 'v0' */
+	return ret_stuff.v0;
+}
+
 static inline u64
 ia64_sn_get_klconfig_addr(nasid_t nasid)
 {
@@ -109,7 +199,7 @@
 	ret_stuff.v0 = (uint64_t)0;
 	ret_stuff.v1 = (uint64_t)0;
 	ret_stuff.v2 = (uint64_t)0;
-	SAL_CALL(ret_stuff, SN_SAL_CONSOLE_GETC, 0, 0, 0, 0, 0, 0, 0);
+	SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_GETC, 0, 0, 0, 0, 0, 0, 0);
 
 	/* character is in 'v0' */
 	*ch = (int)ret_stuff.v0;
@@ -129,7 +219,58 @@
 	ret_stuff.v0 = (uint64_t)0;
 	ret_stuff.v1 = (uint64_t)0;
 	ret_stuff.v2 = (uint64_t)0;
-	SAL_CALL(ret_stuff, SN_SAL_CONSOLE_PUTC, (uint64_t)ch, 0, 0, 0, 0, 0, 0);
+	SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_PUTC, (uint64_t)ch, 0, 0, 0, 0, 0, 0);
+
+	return ret_stuff.status;
+}
+
+/*
+ * Sends the given buffer to the console.
+ */
+static inline u64
+ia64_sn_console_putb(char *buf, int len)
+{
+	struct ia64_sal_retval ret_stuff;
+
+	ret_stuff.status = (uint64_t)0;
+	ret_stuff.v0 = (uint64_t)0;
+	ret_stuff.v1 = (uint64_t)0;
+	ret_stuff.v2 = (uint64_t)0;
+	SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_PUTB, (uint64_t)buf, (uint64_t)len, 0, 0, 0, 0, 0);
+
+	return ret_stuff.status;
+}
+
+/*
+ * Print a platform error record
+ */
+static inline u64
+ia64_sn_plat_specific_err_print(int (*hook)(const char*, ...), char *rec)
+{
+	struct ia64_sal_retval ret_stuff;
+
+	ret_stuff.status = (uint64_t)0;
+	ret_stuff.v0 = (uint64_t)0;
+	ret_stuff.v1 = (uint64_t)0;
+	ret_stuff.v2 = (uint64_t)0;
+	SAL_CALL_NOLOCK(ret_stuff, SN_SAL_PRINT_ERROR, (uint64_t)hook, (uint64_t)rec, 0, 0, 0, 0, 0);
+
+	return ret_stuff.status;
+}
+
+/*
+ * Check for Platform errors
+ */
+static inline u64
+ia64_sn_plat_cpei_handler(void)
+{
+	struct ia64_sal_retval ret_stuff;
+
+	ret_stuff.status = (uint64_t)0;
+	ret_stuff.v0 = (uint64_t)0;
+	ret_stuff.v1 = (uint64_t)0;
+	ret_stuff.v2 = (uint64_t)0;
+	SAL_CALL_NOLOCK(ret_stuff, SN_SAL_LOG_CE, 0, 0, 0, 0, 0, 0, 0);
 
 	return ret_stuff.status;
 }
@@ -146,7 +287,27 @@
 	ret_stuff.v0 = (uint64_t)0;
 	ret_stuff.v1 = (uint64_t)0;
 	ret_stuff.v2 = (uint64_t)0;
-	SAL_CALL(ret_stuff, SN_SAL_CONSOLE_POLL, 0, 0, 0, 0, 0, 0, 0);
+	SAL_CALL_NOLOCK(ret_stuff, SN_SAL_CONSOLE_POLL, 0, 0, 0, 0, 0, 0, 0);
+
+	/* result is in 'v0' */
+	*result = (int)ret_stuff.v0;
+
+	return ret_stuff.status;
+}
+
+/*
+ * Returns the iobrick module Id
+ */
+static inline u64
+ia64_sn_sysctl_iobrick_module_get(nasid_t nasid, int *result)
+{
+	struct ia64_sal_retval ret_stuff;
+
+	ret_stuff.status = (uint64_t)0;
+	ret_stuff.v0 = (uint64_t)0;
+	ret_stuff.v1 = (uint64_t)0;
+	ret_stuff.v2 = (uint64_t)0;
+	SAL_CALL(ret_stuff, SN_SAL_SYSCTL_IOBRICK_MODULE_GET, nasid, 0, 0, 0, 0, 0, 0);
 
 	/* result is in 'v0' */
 	*result = (int)ret_stuff.v0;
@@ -154,4 +315,115 @@
 	return ret_stuff.status;
 }
 
+/**
+ * ia64_sn_pod_mode - call the SN_SAL_POD_MODE function
+ *
+ * SN_SAL_POD_MODE actually takes an argument, but it's always
+ * 0 when we call it from the kernel, so we don't have to expose
+ * it to the caller.
+ */
+static inline u64
+ia64_sn_pod_mode(void)
+{
+	struct ia64_sal_retval isrv;
+	SAL_CALL(isrv, SN_SAL_POD_MODE, 0, 0, 0, 0, 0, 0, 0);
+	if (isrv.status)
+		return 0;
+	return isrv.v0;
+}
+
+/*
+ * Retrieve the system serial number as an ASCII string.
+ */
+static inline u64
+ia64_sn_sys_serial_get(char *buf)
+{
+	struct ia64_sal_retval ret_stuff;
+	SAL_CALL(ret_stuff, SN_SAL_SYS_SERIAL_GET, buf, 0, 0, 0, 0, 0, 0);
+	return ret_stuff.status;
+}
+
+extern char sn_system_serial_number_string[];
+extern u64 sn_partition_serial_number;
+
+static inline char *
+sn_system_serial_number(void) {
+	if (sn_system_serial_number_string[0]) {
+		return(sn_system_serial_number_string);
+	} else {
+		ia64_sn_sys_serial_get(sn_system_serial_number_string);
+		return(sn_system_serial_number_string);
+	}
+}
+	
+
+/*
+ * Returns a unique id number for this system and partition (suitable for
+ * use with license managers), based in part on the system serial number.
+ */
+static inline u64
+ia64_sn_partition_serial_get(void)
+{
+	struct ia64_sal_retval ret_stuff;
+	SAL_CALL(ret_stuff, SN_SAL_PARTITION_SERIAL_GET, 0, 0, 0, 0, 0, 0, 0);
+	if (ret_stuff.status != 0)
+	    return 0;
+	return ret_stuff.v0;
+}
+
+static inline u64
+sn_partition_serial_number_val(void) {
+	if (sn_partition_serial_number) {
+		return(sn_partition_serial_number);
+	} else {
+		return(sn_partition_serial_number = ia64_sn_partition_serial_get());
+	}
+}
+
+/*
+ * Returns the partition id of the nasid passed in as an argument,
+ * or INVALID_PARTID if the partition id cannot be retrieved.
+ */
+static inline partid_t
+ia64_sn_sysctl_partition_get(nasid_t nasid)
+{
+	struct ia64_sal_retval ret_stuff;
+	SAL_CALL(ret_stuff, SN_SAL_SYSCTL_PARTITION_GET, nasid,
+		 0, 0, 0, 0, 0, 0);
+	if (ret_stuff.status != 0)
+	    return INVALID_PARTID;
+	return ((partid_t)ret_stuff.v0);
+}
+
+#ifdef CONFIG_IA64_SGI_SN2
+/*
+ * Returns the partition id of the current processor.
+ */
+
+extern partid_t sn_partid;
+
+static inline partid_t
+sn_local_partid(void) {
+	if (sn_partid < 0) {
+		return (sn_partid = ia64_sn_sysctl_partition_get(cpuid_to_nasid(smp_processor_id())));
+	} else {
+		return sn_partid;
+	}
+}
+
+#endif /* CONFIG_IA64_SGI_SN2 */
+
+/*
+ * Turns off system power.
+ */
+static inline void
+ia64_sn_power_down(void)
+{
+	struct ia64_sal_retval ret_stuff;
+	SAL_CALL(ret_stuff, SN_SAL_SYSTEM_POWER_DOWN, 0, 0, 0, 0, 0, 0, 0);
+	while(1);
+	/* never returns */
+}
+
+
 #endif /* _ASM_IA64_SN_SN_SAL_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/snconfig.h linux-2.4.21-pre6/include/asm-ia64/sn/snconfig.h
--- linux-2.4.20/include/asm-ia64/sn/snconfig.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/snconfig.h	2003-03-26 23:49:29.000000000 +0000
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2000-2001 Silicon Graphics, Inc.
+ * Copyright (C) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
  */
 #ifndef _ASM_IA64_SN_SNCONFIG_H
 #define _ASM_IA64_SN_SNCONFIG_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/sndrv.h linux-2.4.21-pre6/include/asm-ia64/sn/sndrv.h
--- linux-2.4.20/include/asm-ia64/sn/sndrv.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/sndrv.h	2003-03-26 23:48:57.000000000 +0000
@@ -1,3 +1,35 @@
+/*
+ * Copyright (c) 2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify it 
+ * under the terms of version 2 of the GNU General Public License 
+ * as published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope that it would be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
+ * 
+ * Further, this software is distributed without any warranty that it is 
+ * free of the rightful claim of any third person regarding infringement 
+ * or the like.  Any license provided herein, whether implied or 
+ * otherwise, applies only to this software file.  Patent licenses, if 
+ * any, provided herein do not apply to combinations of this program with 
+ * other software, or any other product whatsoever.
+ * 
+ * You should have received a copy of the GNU General Public 
+ * License along with this program; if not, write the Free Software 
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ * 
+ * Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, 
+ * Mountain View, CA  94043, or:
+ * 
+ * http://www.sgi.com 
+ * 
+ * For further information regarding this notice, see: 
+ * 
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan
+ */
+
 #ifndef _ASM_IA64_SN_SNDRV_H
 #define _ASM_IA64_SN_SNDRV_H
 
@@ -27,6 +59,13 @@
 #define SNDRV_SYNERGY_ENABLE		34
 #define SNDRV_SYNERGY_FREQ		35
 
+/* see shubstats_ioctl() */
+#define SNDRV_SHUB_INFOSIZE		40
+#define SNDRV_SHUB_CONFIGURE		41
+#define SNDRV_SHUB_RESETSTATS		42
+#define SNDRV_SHUB_GETSTATS		43
+#define SNDRV_SHUB_GETNASID		44
+
 /* Devices */
 #define SNDRV_UKNOWN_DEVICE		-1
 #define SNDRV_ROUTER_DEVICE		1
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/sv.h linux-2.4.21-pre6/include/asm-ia64/sn/sv.h
--- linux-2.4.20/include/asm-ia64/sn/sv.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/sv.h	2003-03-26 23:49:18.000000000 +0000
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2000-2001 Silicon Graphics, Inc.  All rights reserved
+ * Copyright (C) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This implemenation of synchronization variables is heavily based on
  * one done by Steve Lord <lord@sgi.com>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/types.h linux-2.4.21-pre6/include/asm-ia64/sn/types.h
--- linux-2.4.20/include/asm-ia64/sn/types.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/types.h	2003-03-26 23:49:29.000000000 +0000
@@ -9,14 +9,21 @@
 #ifndef _ASM_IA64_SN_TYPES_H
 #define _ASM_IA64_SN_TYPES_H
 
+#include <linux/config.h>
 #include <linux/types.h>
 
 typedef unsigned long 	cpuid_t;
 typedef unsigned long 	cpumask_t;
 typedef signed short	nasid_t;	/* node id in numa-as-id space */
 typedef signed char	partid_t;	/* partition ID type */
+#ifdef CONFIG_IA64_SGI_SN2
+typedef unsigned int    moduleid_t;     /* user-visible module number type */
+typedef unsigned int    cmoduleid_t;    /* kernel compact module id type */
+#else
 typedef signed short	moduleid_t;	/* user-visible module number type */
 typedef signed short	cmoduleid_t;	/* kernel compact module id type */
+#endif
+typedef signed char slabid_t;
 typedef unsigned char	clusterid_t;	/* Clusterid of the cell */
 
 typedef uint64_t __psunsigned_t;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/uart16550.h linux-2.4.21-pre6/include/asm-ia64/sn/uart16550.h
--- linux-2.4.20/include/asm-ia64/sn/uart16550.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/uart16550.h	2003-03-26 23:49:51.000000000 +0000
@@ -4,7 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All rights reserved.
  */
 
 #ifndef _ASM_IA64_SN_UART16550_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/xtalk/xbow.h linux-2.4.21-pre6/include/asm-ia64/sn/xtalk/xbow.h
--- linux-2.4.20/include/asm-ia64/sn/xtalk/xbow.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/xtalk/xbow.h	2003-03-26 23:49:19.000000000 +0000
@@ -4,8 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc.
- * Copyright (C) 2000 by Colin Ngam
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All Rights Reserved.
  */
 #ifndef _ASM_SN_SN_XTALK_XBOW_H
 #define _ASM_SN_SN_XTALK_XBOW_H
@@ -14,6 +13,7 @@
  * xbow.h - header file for crossbow chip and xbow section of xbridge
  */
 
+#include <linux/config.h>
 #include <asm/sn/xtalk/xtalk.h>
 #include <asm/sn/xtalk/xwidget.h>
 #include <asm/sn/xtalk/xswitch.h>
@@ -42,6 +42,13 @@
 #define MAX_PORT_NUM	0x10	/* maximum port number + 1 */
 #define XBOW_WIDGET_ID	0	/* xbow is itself widget 0 */
 
+#define XBOW_HUBLINK_LOW  0xa
+#define XBOW_HUBLINK_HIGH 0xb
+
+#define XBOW_PEER_LINK(link) (link == XBOW_HUBLINK_LOW) ? \
+                                XBOW_HUBLINK_HIGH : XBOW_HUBLINK_LOW
+
+
 #define	XBOW_CREDIT	4
 
 #define MAX_XBOW_NAME 	16
@@ -384,6 +391,7 @@
 #define XXBOW_WIDGET_PART_NUM	0xd000		/* Xbridge */
 #define	XBOW_WIDGET_MFGR_NUM	0x0
 #define	XXBOW_WIDGET_MFGR_NUM	0x0
+#define PXBOW_WIDGET_PART_NUM   0xd100          /* PIC */
 
 #define	XBOW_REV_1_0		0x1	/* xbow rev 1.0 is "1" */
 #define	XBOW_REV_1_1		0x2	/* xbow rev 1.1 is "2" */
@@ -398,8 +406,22 @@
 #define	XBOW_WID_ARB_RELOAD_INT	0x3f	/* GBR reload interval */
 
 
-#define nasid_has_xbridge(nasid)	\
-	(XWIDGET_PART_NUM(XWIDGET_ID_READ(nasid, 0)) == XXBOW_WIDGET_PART_NUM)
+#ifdef	CONFIG_IA64_SGI_SN1
+#define nasid_has_xbridge(nasid)        \
+        (XWIDGET_PART_NUM(XWIDGET_ID_READ(nasid, 0)) == XXBOW_WIDGET_PART_NUM)
+#endif
+
+#define IS_XBRIDGE_XBOW(wid) \
+        (XWIDGET_PART_NUM(wid) == XXBOW_WIDGET_PART_NUM && \
+                        XWIDGET_MFG_NUM(wid) == XXBOW_WIDGET_MFGR_NUM)
+
+#define IS_PIC_XBOW(wid) \
+        (XWIDGET_PART_NUM(wid) == PXBOW_WIDGET_PART_NUM && \
+                        XWIDGET_MFG_NUM(wid) == XXBOW_WIDGET_MFGR_NUM)
+
+#define XBOW_WAR_ENABLED(pv, widid) ((1 << XWIDGET_REV_NUM(widid)) & pv)
+#define PV854827 (~0)     /* PIC: fake widget 0xf presence bit. permanent */
+#define PV863579 (1 << 1) /* PIC: PIO to PIC register */
 
 
 #ifndef __ASSEMBLY__
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/xtalk/xtalk.h linux-2.4.21-pre6/include/asm-ia64/sn/xtalk/xtalk.h
--- linux-2.4.20/include/asm-ia64/sn/xtalk/xtalk.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/xtalk/xtalk.h	2003-03-26 23:49:00.000000000 +0000
@@ -8,6 +8,7 @@
  */
 #ifndef _ASM_SN_XTALK_XTALK_H
 #define _ASM_SN_XTALK_XTALK_H
+#include <linux/config.h>
 
 /*
  * xtalk.h -- platform-independent crosstalk interface
@@ -202,10 +203,19 @@
 typedef void
 xtalk_intr_free_f       (xtalk_intr_t intr_hdl);
 
+#ifdef CONFIG_IA64_SGI_SN1
 typedef int
 xtalk_intr_connect_f    (xtalk_intr_t intr_hdl,		/* xtalk intr resource handle */
 			 xtalk_intr_setfunc_f *setfunc,		/* func to set intr hw */
 			 void *setfunc_arg);	/* arg to setfunc */
+#else
+typedef int
+xtalk_intr_connect_f    (xtalk_intr_t intr_hdl,		/* xtalk intr resource handle */
+			intr_func_t intr_func,         /* xtalk intr handler */
+			void *intr_arg,	/* arg to intr handler */
+			xtalk_intr_setfunc_f *setfunc,		/* func to set intr hw */
+			void *setfunc_arg);	/* arg to setfunc */
+#endif
 
 typedef void
 xtalk_intr_disconnect_f (xtalk_intr_t intr_hdl);
@@ -391,8 +401,5 @@
 
 extern void		xtalk_iterate(char *prefix, xtalk_iter_f *func);
 
-extern int		xtalk_device_powerup(devfs_handle_t, xwidgetnum_t);
-extern int		xtalk_device_shutdown(devfs_handle_t, xwidgetnum_t);
-
 #endif				/* __KERNEL__ */
 #endif				/* _ASM_SN_XTALK_XTALK_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/xtalk/xtalk_private.h linux-2.4.21-pre6/include/asm-ia64/sn/xtalk/xtalk_private.h
--- linux-2.4.20/include/asm-ia64/sn/xtalk/xtalk_private.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/xtalk/xtalk_private.h	2003-03-26 23:49:50.000000000 +0000
@@ -60,12 +60,12 @@
 		 ((_hwid)->mfg_num == XBOW_WIDGET_MFGR_NUM ))
 
 #define	xwidget_hwid_is_sn1_xswitch(_hwid)	\
-		(((_hwid)->part_num == XXBOW_WIDGET_PART_NUM ) &&  	\
+		(((_hwid)->part_num == XXBOW_WIDGET_PART_NUM ||		\
+		  (_hwid)->part_num == PXBOW_WIDGET_PART_NUM) &&  	\
 		 ((_hwid)->mfg_num == XXBOW_WIDGET_MFGR_NUM ))
 
 #define	xwidget_hwid_is_xswitch(_hwid)	\
-		(xwidget_hwid_is_sn0_xswitch(_hwid) ||			\
-			xwidget_hwid_is_sn1_xswitch(_hwid))
+			xwidget_hwid_is_sn1_xswitch(_hwid)
 
 /* common iograph info for all widgets,
  * stashed in FASTINFO of widget connection points.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/xtalk/xtalkaddrs.h linux-2.4.21-pre6/include/asm-ia64/sn/xtalk/xtalkaddrs.h
--- linux-2.4.20/include/asm-ia64/sn/xtalk/xtalkaddrs.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/xtalk/xtalkaddrs.h	2003-03-26 23:49:51.000000000 +0000
@@ -4,8 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc.
- * Copyright (C) 2000 by Colin Ngam
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All Rights Reserved.
  */
 #ifndef _ASM_SN_XTALK_XTALKADDRS_H
 #define _ASM_SN_XTALK_XTALKADDRS_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/sn/xtalk/xwidget.h linux-2.4.21-pre6/include/asm-ia64/sn/xtalk/xwidget.h
--- linux-2.4.20/include/asm-ia64/sn/xtalk/xwidget.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/sn/xtalk/xwidget.h	2003-03-26 23:48:57.000000000 +0000
@@ -4,8 +4,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc.
- * Copyright (C) 2000 by Colin Ngam
+ * Copyright (C) 1992-1997,2000-2002 Silicon Graphics, Inc. All Rights Reserved.
  */
 #ifndef __ASM_SN_XTALK_XWIDGET_H__
 #define __ASM_SN_XTALK_XWIDGET_H__
@@ -58,6 +57,7 @@
 #define XWIDGET_MFG_NUM(widgetid) (((widgetid) & WIDGET_MFG_NUM) >> WIDGET_MFG_NUM_SHFT)
 #define XWIDGET_PART_REV_NUM(widgetid) ((XWIDGET_PART_NUM(widgetid) << 4) | \
 					XWIDGET_REV_NUM(widgetid))
+#define XWIDGET_PART_REV_NUM_REV(partrev) (partrev & 0xf)
 
 /* WIDGET_STATUS */
 #define WIDGET_LLP_REC_CNT		0xff000000
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/system.h linux-2.4.21-pre6/include/asm-ia64/system.h
--- linux-2.4.20/include/asm-ia64/system.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/system.h	2003-03-26 23:49:31.000000000 +0000
@@ -122,7 +122,7 @@
 	unsigned long ip, psr;								\
 											\
 	__asm__ __volatile__ ("mov %0=psr;; rsm psr.i;;" : "=r" (psr) :: "memory");	\
-	if (psr & (1UL << 14)) {							\
+	if (psr & IA64_PSR_I) {								\
 		__asm__ ("mov %0=ip" : "=r"(ip));					\
 		last_cli_ip = ip;							\
 	}										\
@@ -134,12 +134,23 @@
 	unsigned long ip, psr;								\
 											\
 	__asm__ __volatile__ ("mov %0=psr;; rsm psr.i;;" : "=r" (psr) :: "memory");	\
-	if (psr & (1UL << 14)) {							\
+	if (psr & IA64_PSR_I) {								\
 		__asm__ ("mov %0=ip" : "=r"(ip));					\
 		last_cli_ip = ip;							\
 	}										\
 } while (0)
 
+# define local_irq_set(x)								\
+do {											\
+	unsigned long psr;								\
+											\
+	__asm__ __volatile__ ("mov %0=psr;;"						\
+			      "ssm psr.i;;"						\
+			      "srlz.d"							\
+			      : "=r" (psr) :: "memory");				\
+	(x) = psr;									\
+} while (0)
+
 # define local_irq_restore(x)							\
 do {										\
 	unsigned long ip, old_psr, psr = (x);					\
@@ -148,7 +159,7 @@
 			      "cmp.ne p6,p7=%1,r0;;"				\
 			      "(p6) ssm psr.i;"					\
 			      "(p7) rsm psr.i;;"				\
-			      "srlz.d"						\
+			      "(p6) srlz.d"					\
 			      : "=&r" (old_psr) : "r"((psr) & IA64_PSR_I)	\
 			      : "p6", "p7", "memory");				\
 	if ((old_psr & IA64_PSR_I) && !(psr & IA64_PSR_I)) {			\
@@ -163,6 +174,10 @@
 						      : "=r" (x) :: "memory")
 # define local_irq_disable()	__asm__ __volatile__ (";; rsm psr.i;;" ::: "memory")
 /* (potentially) setting psr.i requires data serialization: */
+# define local_irq_set(x)	__asm__ __volatile__ ("mov %0=psr;;"			\
+						      "ssm psr.i;;"			\
+						      "srlz.d"				\
+						      : "=r" (x) :: "memory")
 # define local_irq_restore(x)	__asm__ __volatile__ ("cmp.ne p6,p7=%0,r0;;"		\
 						      "(p6) ssm psr.i;"			\
 						      "(p7) rsm psr.i;;"		\
@@ -176,7 +191,9 @@
 #define __cli()			local_irq_disable ()
 #define __save_flags(flags)	__asm__ __volatile__ ("mov %0=psr" : "=r" (flags) :: "memory")
 #define __save_and_cli(flags)	local_irq_save(flags)
+#define __save_and_sti(flags)	local_irq_set(flags)
 #define save_and_cli(flags)	__save_and_cli(flags)
+#define save_and_sti(flags)	__save_and_sti(flags)
 #define __sti()			local_irq_enable ()
 #define __restore_flags(flags)	local_irq_restore(flags)
 
@@ -384,8 +401,8 @@
 extern void ia64_save_extra (struct task_struct *task);
 extern void ia64_load_extra (struct task_struct *task);
 
-#if defined(CONFIG_SMP) && defined(CONFIG_PERFMON)
-# define PERFMON_IS_SYSWIDE() (local_cpu_data->pfm_syst_wide != 0)
+#ifdef CONFIG_PERFMON
+# define PERFMON_IS_SYSWIDE() (local_cpu_data->pfm_syst_info & 0x1)
 #else
 # define PERFMON_IS_SYSWIDE() (0)
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ia64/unistd.h linux-2.4.21-pre6/include/asm-ia64/unistd.h
--- linux-2.4.20/include/asm-ia64/unistd.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ia64/unistd.h	2003-03-26 23:49:07.000000000 +0000
@@ -206,12 +206,23 @@
 #define __NR_getdents64			1214
 #define __NR_getunwind			1215
 #define __NR_readahead			1216
-/*
- * 1217-1228: reserved for xattr
- * 1230-1232: reserved for futex and sched_[sg]etaffinity.
- */
+#define __NR_setxattr			1217
+#define __NR_lsetxattr			1218
+#define __NR_fsetxattr			1219
+#define __NR_getxattr			1220
+#define __NR_lgetxattr			1221
+#define __NR_fgetxattr			1222
+#define __NR_listxattr			1223
+#define __NR_llistxattr			1224
+#define __NR_flistxattr			1225
+#define __NR_removexattr		1226
+#define __NR_lremovexattr		1227
+#define __NR_fremovexattr		1228
 #define __NR_tkill			1229
-#define __NR_security			1233 /* syscall for security modules */
+/* 1230-1232: reserved for futex and sched_[sg]etaffinity */
+#define __NR_security			1233
+/* 1234-1235: reserved for {alloc,free}_hugepages */
+/* 1238-1242: reserved for io_{setup,destroy,getevents,submit,cancel} */
 
 #if !defined(__ASSEMBLY__) && !defined(ASSEMBLER)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-m68k/amigahw.h linux-2.4.21-pre6/include/asm-m68k/amigahw.h
--- linux-2.4.20/include/asm-m68k/amigahw.h	2001-06-12 02:15:27.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-m68k/amigahw.h	2003-03-26 23:49:52.000000000 +0000
@@ -324,7 +324,7 @@
 };
 #define TOD3000_CNTRL1_HOLD	0
 #define TOD3000_CNTRL1_FREE	9
-#define TOD_3000 ((struct tod3000 *)(zTwoBase+0xDC0000))
+#define tod_3000 ((*(volatile struct tod3000 *)(zTwoBase+0xDC0000)))
 
 struct tod2000 {
   unsigned int  :28, second2:4;	/* lower digit */
@@ -349,6 +349,6 @@
 #define TOD2000_CNTRL1_BUSY	(1<<1)
 #define TOD2000_CNTRL3_24HMODE	(1<<2)
 #define TOD2000_HOUR1_PM	(1<<2)
-#define TOD_2000 ((struct tod2000 *)(zTwoBase+0xDC0000))
+#define tod_2000 ((*(volatile struct tod2000 *)(zTwoBase+0xDC0000)))
 
 #endif /* _M68K_AMIGAHW_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-m68k/apollohw.h linux-2.4.21-pre6/include/asm-m68k/apollohw.h
--- linux-2.4.20/include/asm-m68k/apollohw.h	2000-01-26 20:44:21.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-m68k/apollohw.h	2003-03-26 23:49:00.000000000 +0000
@@ -101,9 +101,4 @@
 
 #define isaIO2mem(x) (((((x) & 0x3f8)  << 7) | (((x) & 0xfc00) >> 6) | ((x) & 0x7)) + 0x40000 + IO_BASE)
 
-#define inb(addr) (*((volatile unsigned char *)(addr)))
-#define outb(val,addr) (*((volatile unsigned char *)(addr)) = (val))
-#define inw(addr) (*((volatile unsigned short *)(addr)))
-#define outw(val,addr) (*((volatile unsigned short *)(addr)) = (val))
-
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-m68k/dvma.h linux-2.4.21-pre6/include/asm-m68k/dvma.h
--- linux-2.4.20/include/asm-m68k/dvma.h	2001-06-12 02:15:27.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-m68k/dvma.h	2003-03-26 23:49:40.000000000 +0000
@@ -22,7 +22,8 @@
 
 #define dvma_malloc(x) dvma_malloc_align(x, 0)
 #define dvma_map(x, y) dvma_map_align(x, y, 0)
-
+#define dvma_map_vme(x, y) (dvma_map(x, y) & 0xfffff)
+#define dvma_map_align_vme(x, y, z) (dvma_map_align (x, y, z) & 0xfffff)
 extern unsigned long dvma_map_align(unsigned long kaddr, int len, 
 			    int align);
 extern void *dvma_malloc_align(unsigned long len, unsigned long align);
@@ -52,6 +53,8 @@
 /* virt <-> phys conversions */
 #define dvma_vtop(x) ((unsigned long)(x) & 0xffffff)
 #define dvma_ptov(x) ((unsigned long)(x) | 0xf000000)
+#define dvma_vtovme(x) ((unsigned long)(x) & 0x00fffff)
+#define dvma_vmetov(x) ((unsigned long)(x) | 0xff00000)
 #define dvma_vtob(x) dvma_vtop(x)
 #define dvma_btov(x) dvma_ptov(x)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-m68k/floppy.h linux-2.4.21-pre6/include/asm-m68k/floppy.h
--- linux-2.4.20/include/asm-m68k/floppy.h	2001-10-25 20:53:55.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-m68k/floppy.h	2003-03-26 23:49:49.000000000 +0000
@@ -9,7 +9,7 @@
  *
  * Copyright (C) 1999, 2000, 2001
  *
- * Sun3x support added 2/4/2000 Sam Creasey (sammy@oh.verio.com)
+ * Sun3x support added 2/4/2000 Sam Creasey (sammy@sammy.net)
  *
  */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-m68k/hdreg.h linux-2.4.21-pre6/include/asm-m68k/hdreg.h
--- linux-2.4.20/include/asm-m68k/hdreg.h	1999-05-13 18:00:09.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-m68k/hdreg.h	2003-03-26 23:49:24.000000000 +0000
@@ -9,5 +9,6 @@
 
 typedef unsigned int   q40ide_ioreg_t;
 typedef unsigned char * ide_ioreg_t;
+//typedef unsigned long ide_ioreg_t;
 
 #endif /* _M68K_HDREG_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-m68k/ide.h linux-2.4.21-pre6/include/asm-m68k/ide.h
--- linux-2.4.20/include/asm-m68k/ide.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-m68k/ide.h	2003-03-26 23:48:58.000000000 +0000
@@ -50,6 +50,9 @@
 #define MAX_HWIFS	4	/* same as the other archs */
 #endif
 
+/*
+ * FIXME: IOPS struct calls needed for taskfile.
+ */
 
 static __inline__ int ide_default_irq(ide_ioreg_t base)
 {
@@ -80,29 +83,6 @@
 {
 }
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned bit7		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned head		: 4;	/* always zeros here */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-		unsigned reserved456	: 3;
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned bit0		: 1;
-	} b;
-} control_t;
-
 static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
 			unsigned long flags, const char *device, void *dev_id)
 {
@@ -190,22 +170,26 @@
 
 #define ADDR_TRANS_B(_addr_) (_addr_)
 #define ADDR_TRANS_W(_addr_) (_addr_)
+#define ADDR_TRANS_L(_addr_) (_addr_)
 
 #else
 
 #define ADDR_TRANS_B(_addr_) (MACH_IS_Q40 ? ((unsigned char *)Q40_ISA_IO_B(_addr_)) : (_addr_))
 #define ADDR_TRANS_W(_addr_) (MACH_IS_Q40 ? ((unsigned char *)Q40_ISA_IO_W(_addr_)) : (_addr_))
+#define ADDR_TRANS_L(_addr_) (MACH_IS_Q40 ? ((unsigned char *)Q40_ISA_IO_L(_addr_)) : (_addr_))
 #endif
 
-#define HAVE_ARCH_OUT_BYTE
+#define HAVE_ARCH_OUT_BYTE 1
 
 #define OUT_BYTE(v,p)	out_8(ADDR_TRANS_B((p)), (v))
 #define OUT_WORD(v,p)	out_be16(ADDR_TRANS_W((p)), (v))
+#define OUT_LONG(v,p)	out_be32(ADDR_TRANS_L((p)), (v))
 
-#define HAVE_ARCH_IN_BYTE
+#define HAVE_ARCH_IN_BYTE 1
 
 #define IN_BYTE(p)	in_8(ADDR_TRANS_B((p)))
 #define IN_WORD(p)	in_be16(ADDR_TRANS_W((p)))
+#define IN_LONG(p)	in_be32(ADDR_TRANS_L((p)))
 
 #define insw(port, buf, nr) raw_insw(ADDR_TRANS_W(port), buf, nr)
 #define outsw(port, buf, nr) raw_outsw(ADDR_TRANS_W(port), buf, nr)
@@ -227,19 +211,6 @@
 #endif /* CONFIG_ATARI || CONFIG_Q40 */
 
 
-#define T_CHAR          (0x0000)        /* char:  don't touch  */
-#define T_SHORT         (0x4000)        /* short: 12 -> 21     */
-#define T_INT           (0x8000)        /* int:   1234 -> 4321 */
-#define T_TEXT          (0xc000)        /* text:  12 -> 21     */
-
-#define T_MASK_TYPE     (0xc000)
-#define T_MASK_COUNT    (0x3fff)
-
-#define D_CHAR(cnt)     (T_CHAR  | (cnt))
-#define D_SHORT(cnt)    (T_SHORT | (cnt))
-#define D_INT(cnt)      (T_INT   | (cnt))
-#define D_TEXT(cnt)     (T_TEXT  | (cnt))
-
 /* Q40 and Atari have byteswapped IDE bus and since many interesting
  * values in the identification string are text, chars and words they
  * happened to be almost correct without swapping.. However *_capacity 
@@ -248,83 +219,11 @@
 #define M68K_IDE_SWAPW  (MACH_IS_Q40 || MACH_IS_ATARI)
 #endif
 
-#if defined(CONFIG_AMIGA) || defined (CONFIG_MAC) || defined(M68K_IDE_SWAPW)
-static u_short driveid_types[] = {
-	D_SHORT(10),	/* config - vendor2 */
-	D_TEXT(20),	/* serial_no */
-	D_SHORT(3),	/* buf_type, buf_size - ecc_bytes */
-	D_TEXT(48),	/* fw_rev - model */
-	D_CHAR(2),	/* max_multsect - vendor3 */
-	D_SHORT(1),	/* dword_io */
-	D_CHAR(2),	/* vendor4 - capability */
-	D_SHORT(1),	/* reserved50 */
-	D_CHAR(4),	/* vendor5 - tDMA */
-	D_SHORT(4),	/* field_valid - cur_sectors */
-	D_INT(1),	/* cur_capacity */
-	D_CHAR(2),	/* multsect - multsect_valid */
-	D_INT(1),	/* lba_capacity */
-	D_SHORT(194)	/* dma_1word - reserved */
-};
-
-#define num_driveid_types       (sizeof(driveid_types)/sizeof(*driveid_types))
-#endif /* CONFIG_AMIGA */
-
-static __inline__ void ide_fix_driveid(struct hd_driveid *id)
-{
-#if defined(CONFIG_AMIGA) || defined (CONFIG_MAC) || defined(M68K_IDE_SWAPW)
-   u_char *p = (u_char *)id;
-   int i, j, cnt;
-   u_char t;
-
-   if (!MACH_IS_AMIGA && !MACH_IS_MAC && !MACH_IS_Q40 && !MACH_IS_ATARI)
-   	return;
-#ifdef M68K_IDE_SWAPW
-   if (M68K_IDE_SWAPW)    /* fix bus byteorder first */
-      for (i=0; i < 512; i+=2) {
-	 t = p[i]; p[i] = p[i+1]; p[i+1] = t; 
-      }
-#endif
-   for (i = 0; i < num_driveid_types; i++) {
-      cnt = driveid_types[i] & T_MASK_COUNT;
-      switch (driveid_types[i] & T_MASK_TYPE) {
-         case T_CHAR:
-            p += cnt;
-            break;
-         case T_SHORT:
-            for (j = 0; j < cnt; j++) {
-	       t = p[0];
-	       p[0] = p[1];
-	       p[1] = t;
-               p += 2;
-            }
-            break;
-         case T_INT:
-            for (j = 0; j < cnt; j++) {
-	       t = p[0];
-	       p[0] = p[3];
-	       p[3] = t;
-	       t = p[1];
-	       p[1] = p[2];
-	       p[2] = t;
-               p += 4;
-            }
-            break;
-         case T_TEXT:
-            for (j = 0; j < cnt; j += 2) {
-	       t = p[0];
-	       p[0] = p[1];
-	       p[1] = t;
-               p += 2;
-            }
-            break;
-      }
-   }
-#endif /* CONFIG_AMIGA */
-}
+#ifdef CONFIG_ATARI
+#define IDE_ARCH_LOCK 1
 
 static __inline__ void ide_release_lock (int *ide_lock)
 {
-#ifdef CONFIG_ATARI
 	if (MACH_IS_ATARI) {
 		if (*ide_lock == 0) {
 			printk("ide_release_lock: bug\n");
@@ -333,12 +232,10 @@
 		*ide_lock = 0;
 		stdma_release();
 	}
-#endif /* CONFIG_ATARI */
 }
 
 static __inline__ void ide_get_lock (int *ide_lock, void (*handler)(int, void *, struct pt_regs *), void *data)
 {
-#ifdef CONFIG_ATARI
 	if (MACH_IS_ATARI) {
 		if (*ide_lock == 0) {
 			if (in_interrupt() > 0)
@@ -347,39 +244,8 @@
 			*ide_lock = 1;
 		}
 	}
-#endif /* CONFIG_ATARI */
 }
-
-#define ide_ack_intr(hwif)	((hwif)->hw.ack_intr ? (hwif)->hw.ack_intr(hwif) : 1)
-
-/*
- * On the Atari, we sometimes can't enable interrupts:
- */
-
-/* MSch: changed sti() to STI() wherever possible in ide.c; moved STI() def. 
- * to asm/ide.h 
- */
-/* The Atari interrupt structure strictly requires that the IPL isn't lowered
- * uncontrolled in an interrupt handler. In the concrete case, the IDE
- * interrupt is already a slow int, so the irq is already disabled at the time
- * the handler is called, and the IPL has been lowered to the minimum value
- * possible. To avoid going below that, STI() checks for being called inside
- * an interrupt, and in that case it does nothing. Hope that is reasonable and
- * works. (Roman)
- */
-#ifdef MACH_ATARI_ONLY
-#define	ide__sti()					\
-    do {						\
-	if (!in_interrupt()) __sti();			\
-    } while(0)
-#elif defined(CONFIG_ATARI)
-#define	ide__sti()						\
-    do {							\
-	if (!MACH_IS_ATARI || !in_interrupt()) sti();		\
-    } while(0)
-#else /* !defined(CONFIG_ATARI) */
-#define	ide__sti()	__sti()
-#endif
+#endif /* CONFIG_ATARI */
 
 #endif /* __KERNEL__ */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-m68k/io.h linux-2.4.21-pre6/include/asm-m68k/io.h
--- linux-2.4.20/include/asm-m68k/io.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-m68k/io.h	2003-03-26 23:49:49.000000000 +0000
@@ -162,7 +162,9 @@
 #ifdef CONFIG_GG2
     case GG2_ISA: return GG2_ISA_MEM_B(addr);
 #endif
-      /* FIXME: any ISA mem mapping for PCMCIA? */
+#ifdef CONFIG_AMIGA_PCMCIA
+    case AG_ISA: return addr;
+#endif
     default: return 0; /* avoid warnings, just in case */
     }
 }
@@ -176,6 +178,9 @@
 #ifdef CONFIG_GG2
     case GG2_ISA: return GG2_ISA_MEM_W(addr);
 #endif
+#ifdef CONFIG_AMIGA_PCMCIA
+    case AG_ISA: return addr;
+#endif
     default: return 0; /* avoid warnings, just in case */
     }
 }
@@ -187,9 +192,9 @@
 #define isa_outw(val,port) (ISA_SEX ? out_be16(isa_itw(port),(val)) : out_le16(isa_itw(port),(val)))
 
 #define isa_readb(p)       in_8(isa_mtb(p))
-#define isa_readw(p)       in_le16(isa_mtw(p))
+#define isa_readw(p)       (ISA_SEX ? in_be16(isa_mtw(p)) : in_le16(isa_mtw(p)))
 #define isa_writeb(val,p)  out_8(isa_mtb(p),(val))
-#define isa_writew(val,p)  out_le16(isa_mtw(p),(val))
+#define isa_writew(val,p)  (ISA_SEX ? out_be16(isa_mtw(p),(val)) : out_le16(isa_mtw(p),(val)))
 
 static inline void isa_delay(void)
 {
@@ -280,23 +285,6 @@
 #endif /* CONFIG_PCI */
 
 
-/* Values for nocacheflag and cmode */
-#define IOMAP_FULL_CACHING		0
-#define IOMAP_NOCACHE_SER		1
-#define IOMAP_NOCACHE_NONSER		2
-#define IOMAP_WRITETHROUGH		3
-
-/*
- * Change "struct page" to physical address.
- */
-#define page_to_phys(page)	((page - mem_map) << PAGE_SHIFT)
-
-extern void iounmap(void *addr);
-
-extern void *__ioremap(unsigned long physaddr, unsigned long size,
-		       int cacheflag);
-extern void __iounmap(void *addr, unsigned long size);
-
 extern inline void *ioremap(unsigned long physaddr, unsigned long size)
 {
 	return __ioremap(physaddr, size, IOMAP_NOCACHE_SER);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-m68k/macintosh.h linux-2.4.21-pre6/include/asm-m68k/macintosh.h
--- linux-2.4.20/include/asm-m68k/macintosh.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-m68k/macintosh.h	2003-03-26 23:48:57.000000000 +0000
@@ -74,9 +74,9 @@
 #define MAC_IDE_BABOON		3
 
 #define MAC_SCC_II		1
-#define MAC_SCC_QUADRA		2
-#define MAC_SCC_QUADRA2		3
-#define MAC_SCC_IOP		4
+#define MAC_SCC_IOP		2
+#define MAC_SCC_QUADRA		3
+#define MAC_SCC_PSC		4
 
 #define MAC_ETHER_NONE		0	
 #define MAC_ETHER_SONIC		1
@@ -137,6 +137,7 @@
 #define MAC_MODEL_P475F		90	/* aka: P475 w/ FPU (no LC040) */
 #define MAC_MODEL_P575		92	/* aka: LC575, P577/P578 */
 #define MAC_MODEL_Q605		94
+#define MAC_MODEL_Q605_ACC	95	/* Q605 accelerated to 33 MHz */
 #define MAC_MODEL_Q630		98	/* aka: LC630, P630/631/635/636/637/638/640 */
 #define MAC_MODEL_P588		99	/* aka: LC580, P580 */
 #define MAC_MODEL_PB280		102
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-m68k/nubus.h linux-2.4.21-pre6/include/asm-m68k/nubus.h
--- linux-2.4.20/include/asm-m68k/nubus.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-m68k/nubus.h	2003-03-26 23:49:19.000000000 +0000
@@ -1,7 +1,7 @@
 #ifndef _ASM_M68K_NUBUS_H
 #define _ASM_M68K_NUBUS_H
 
-#include <asm/io.h>
+#include <asm/raw_io.h>
 
 #define nubus_readb raw_inb
 #define nubus_readw raw_inw
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-m68k/page.h linux-2.4.21-pre6/include/asm-m68k/page.h
--- linux-2.4.20/include/asm-m68k/page.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-m68k/page.h	2003-03-26 23:49:39.000000000 +0000
@@ -6,10 +6,13 @@
 /* PAGE_SHIFT determines the page size */
 #ifndef CONFIG_SUN3
 #define PAGE_SHIFT	(12)
-#define PAGE_SIZE	(4096)
 #else
 #define PAGE_SHIFT	(13)
-#define PAGE_SIZE	(8192)
+#endif
+#ifdef __ASSEMBLY__
+#define PAGE_SIZE	(1 << PAGE_SHIFT)
+#else
+#define PAGE_SIZE	(1UL << PAGE_SHIFT)
 #endif
 #define PAGE_MASK	(~(PAGE_SIZE-1))
 
@@ -141,7 +144,7 @@
 {
      if(x == 0)
 	  return 0;
-     if(x > PAGE_OFFSET)
+     if(x >= PAGE_OFFSET)
         return (x-PAGE_OFFSET);
      else
         return (x+0x2000000);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-m68k/processor.h linux-2.4.21-pre6/include/asm-m68k/processor.h
--- linux-2.4.20/include/asm-m68k/processor.h	2001-10-05 19:11:05.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-m68k/processor.h	2003-03-26 23:49:50.000000000 +0000
@@ -105,7 +105,7 @@
 {
 }
 
-extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
+extern int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
 #define copy_segments(tsk, mm)		do { } while (0)
 #define release_segments(mm)		do { } while (0)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-m68k/raw_io.h linux-2.4.21-pre6/include/asm-m68k/raw_io.h
--- linux-2.4.20/include/asm-m68k/raw_io.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-m68k/raw_io.h	2003-03-26 23:49:56.000000000 +0000
@@ -11,6 +11,19 @@
 #ifdef __KERNEL__
 
 
+/* Values for nocacheflag and cmode */
+#define IOMAP_FULL_CACHING		0
+#define IOMAP_NOCACHE_SER		1
+#define IOMAP_NOCACHE_NONSER		2
+#define IOMAP_WRITETHROUGH		3
+
+extern void iounmap(void *addr);
+
+extern void *__ioremap(unsigned long physaddr, unsigned long size,
+		       int cacheflag);
+extern void __iounmap(void *addr, unsigned long size);
+
+
 /* ++roman: The assignments to temp. vars avoid that gcc sometimes generates
  * two accesses to memory, which may be undesirable for some devices.
  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-m68k/sbus.h linux-2.4.21-pre6/include/asm-m68k/sbus.h
--- linux-2.4.20/include/asm-m68k/sbus.h	2001-06-12 02:15:27.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-m68k/sbus.h	2003-03-26 23:49:36.000000000 +0000
@@ -5,7 +5,7 @@
 #ifndef __M68K_SBUS_H
 #define __M68K_SBUS_H
 
-struct linux_sbus_device {
+struct sbus_dev {
 	struct {
 		unsigned int which_io;
 		unsigned int phys_addr;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-m68k/sun3-head.h linux-2.4.21-pre6/include/asm-m68k/sun3-head.h
--- linux-2.4.20/include/asm-m68k/sun3-head.h	1999-09-04 20:06:41.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-m68k/sun3-head.h	2003-03-26 23:49:39.000000000 +0000
@@ -9,4 +9,4 @@
 #define FC_SUPERD    5
 #define FC_CPU      7
 
-#endif __SUN3_HEAD_H
+#endif /* __SUN3_HEAD_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-m68k/sun3ints.h linux-2.4.21-pre6/include/asm-m68k/sun3ints.h
--- linux-2.4.20/include/asm-m68k/sun3ints.h	2001-06-12 02:15:27.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-m68k/sun3ints.h	2003-03-26 23:48:58.000000000 +0000
@@ -20,6 +20,8 @@
 #include <asm/intersil.h>
 #include <asm/oplib.h>
 
+#define SUN3_INT_VECS 192
+
 void sun3_enable_irq(unsigned int irq);
 void sun3_disable_irq(unsigned int irq);
 int sun3_request_irq(unsigned int irq,
@@ -36,5 +38,11 @@
 extern void sun3_process_int(int, struct pt_regs *);
 extern volatile unsigned char* sun3_intreg;
 
+/* master list of VME vectors -- don't fuck with this */
+#define SUN3_VEC_FLOPPY 0x40
+#define SUN3_VEC_VMESCSI0 0x40
+#define SUN3_VEC_VMESCSI1 0x41
+#define SUN3_VEC_CG 0xA8
+
 
 #endif /* SUN3INTS_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-m68k/sun3mmu.h linux-2.4.21-pre6/include/asm-m68k/sun3mmu.h
--- linux-2.4.20/include/asm-m68k/sun3mmu.h	1999-09-04 20:06:41.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-m68k/sun3mmu.h	2003-03-26 23:49:36.000000000 +0000
@@ -161,6 +161,10 @@
 	return;
 }
 
+extern void *sun3_ioremap(unsigned long phys, unsigned long size,
+			  unsigned long type);
+
+extern int sun3_map_test(unsigned long addr, char *val);
 
 #endif	/* !__ASSEMBLY__ */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-m68k/sun3xflop.h linux-2.4.21-pre6/include/asm-m68k/sun3xflop.h
--- linux-2.4.20/include/asm-m68k/sun3xflop.h	2001-10-25 20:53:55.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-m68k/sun3xflop.h	2003-03-26 23:49:54.000000000 +0000
@@ -3,7 +3,7 @@
  * Derived partially from asm-sparc/floppy.h, which is:
  *     Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  *
- * Sun3x version 2/4/2000 Sam Creasey (sammy@oh.verio.com)
+ * Sun3x version 2/4/2000 Sam Creasey (sammy@sammy.net)
  */
 
 #ifndef __ASM_SUN3X_FLOPPY_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-m68k/system.h linux-2.4.21-pre6/include/asm-m68k/system.h
--- linux-2.4.20/include/asm-m68k/system.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-m68k/system.h	2003-03-26 23:49:09.000000000 +0000
@@ -47,7 +47,6 @@
   (last) = _last; \
 }
 
-
 /* interrupt control.. */
 #if 0
 #define __sti() asm volatile ("andiw %0,%%sr": : "i" (ALLOWINT) : "memory")
@@ -64,6 +63,7 @@
 
 /* For spinlocks etc */
 #define local_irq_save(x)	({ __save_flags(x); __cli(); })
+#define local_irq_set(x)	({ __save_flags(x); __sti(); })
 #define local_irq_restore(x)	__restore_flags(x)
 #define local_irq_disable()	__cli()
 #define local_irq_enable()	__sti()
@@ -72,7 +72,8 @@
 #define sti()			__sti()
 #define save_flags(x)		__save_flags(x)
 #define restore_flags(x)	__restore_flags(x)
-#define save_and_cli(flags)   do { save_flags(flags); cli(); } while(0)
+#define save_and_cli(x)		do { save_flags(x); cli(); } while(0)
+#define save_and_set(x)		do { save_flags(x); sti(); } while(0)
 
 /*
  * Force strict CPU ordering.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-m68k/virtconvert.h linux-2.4.21-pre6/include/asm-m68k/virtconvert.h
--- linux-2.4.20/include/asm-m68k/virtconvert.h	2000-01-26 20:44:21.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-m68k/virtconvert.h	2003-03-26 23:49:50.000000000 +0000
@@ -85,5 +85,12 @@
 #define bus_to_virt phys_to_virt
 #endif
 
+/*
+ * Change "struct page" to physical address.
+ */
+
+#define __page_address(page)      (PAGE_OFFSET + (((page) - mem_map) << PAGE_SHIFT))
+#define page_to_phys(page)       virt_to_phys((void *)__page_address(page))
+
 #endif
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-m68k/zorro.h linux-2.4.21-pre6/include/asm-m68k/zorro.h
--- linux-2.4.20/include/asm-m68k/zorro.h	2001-10-25 20:53:55.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-m68k/zorro.h	2003-03-26 23:49:19.000000000 +0000
@@ -1,5 +1,6 @@
 #ifndef _ASM_M68K_ZORRO_H
 #define _ASM_M68K_ZORRO_H
+
 #include <asm/raw_io.h>
 
 #define z_readb raw_inb
@@ -14,22 +15,6 @@
 #define z_memcpy_fromio(a,b,c)	memcpy((a),(void *)(b),(c))
 #define z_memcpy_toio(a,b,c)	memcpy((void *)(a),(b),(c))
 
-
-/* Values for nocacheflag and cmode */
-#ifndef IOMAP_FULL_CACHING		
-#define IOMAP_FULL_CACHING		0
-#define IOMAP_NOCACHE_SER		1
-#define IOMAP_NOCACHE_NONSER		2
-#define IOMAP_WRITETHROUGH		3
-#endif
-
-extern void iounmap(void *addr);
-
-extern void *__ioremap(unsigned long physaddr, unsigned long size,
-		       int cacheflag);
-extern void __iounmap(void *addr, unsigned long size);
-
-
 extern inline void *z_remap_nocache_ser(unsigned long physaddr, 
 					  unsigned long size)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-mips/ide.h linux-2.4.21-pre6/include/asm-mips/ide.h
--- linux-2.4.20/include/asm-mips/ide.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-mips/ide.h	2003-03-26 23:49:50.000000000 +0000
@@ -24,21 +24,11 @@
 # endif
 #endif
 
-#define ide__sti()	__sti()
-
 struct ide_ops {
 	int (*ide_default_irq)(ide_ioreg_t base);
 	ide_ioreg_t (*ide_default_io_base)(int index);
 	void (*ide_init_hwif_ports)(hw_regs_t *hw, ide_ioreg_t data_port,
 	                            ide_ioreg_t ctrl_port, int *irq);
-	int (*ide_request_irq)(unsigned int irq, void (*handler)(int, void *,
-	                       struct pt_regs *), unsigned long flags,
-	                       const char *device, void *dev_id);
-	void (*ide_free_irq)(unsigned int irq, void *dev_id);
-	int (*ide_check_region) (ide_ioreg_t from, unsigned int extent);
-	void (*ide_request_region)(ide_ioreg_t from, unsigned int extent,
-	                        const char *name);
-	void (*ide_release_region)(ide_ioreg_t from, unsigned int extent);
 };
 
 extern struct ide_ops *ide_ops;
@@ -73,74 +63,6 @@
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-#ifdef __MIPSEB__
-		unsigned bit7		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned head		: 4;	/* always zeros here */
-#else
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-#endif
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-#ifdef __MIPSEB__
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-		unsigned reserved456	: 3;
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned bit0		: 1;
-#else
-		unsigned bit0		: 1;
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned reserved456	: 3;
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-#endif
-	} b;
-} control_t;
-
-static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int,void *, struct pt_regs *),
-			unsigned long flags, const char *device, void *dev_id)
-{
-	return ide_ops->ide_request_irq(irq, handler, flags, device, dev_id);
-}
-
-static __inline__ void ide_free_irq(unsigned int irq, void *dev_id)
-{
-	ide_ops->ide_free_irq(irq, dev_id);
-}
-
-static __inline__ int ide_check_region (ide_ioreg_t from, unsigned int extent)
-{
-	return ide_ops->ide_check_region(from, extent);
-}
-
-static __inline__ void ide_request_region(ide_ioreg_t from,
-                                          unsigned int extent, const char *name)
-{
-	ide_ops->ide_request_region(from, extent, name);
-}
-
-static __inline__ void ide_release_region(ide_ioreg_t from,
-                                          unsigned int extent)
-{
-	ide_ops->ide_release_region(from, extent);
-}
-
 #undef  SUPPORT_VLB_SYNC
 #define SUPPORT_VLB_SYNC 0
 
@@ -197,94 +119,8 @@
 	}
 }
 
-#define T_CHAR          (0x0000)        /* char:  don't touch  */
-#define T_SHORT         (0x4000)        /* short: 12 -> 21     */
-#define T_INT           (0x8000)        /* int:   1234 -> 4321 */
-#define T_TEXT          (0xc000)        /* text:  12 -> 21     */
-
-#define T_MASK_TYPE     (0xc000)
-#define T_MASK_COUNT    (0x3fff)
-
-#define D_CHAR(cnt)     (T_CHAR  | (cnt))
-#define D_SHORT(cnt)    (T_SHORT | (cnt))
-#define D_INT(cnt)      (T_INT   | (cnt))
-#define D_TEXT(cnt)     (T_TEXT  | (cnt))
-
-static u_short driveid_types[] = {
-	D_SHORT(10),	/* config - vendor2 */
-	D_TEXT(20),	/* serial_no */
-	D_SHORT(3),	/* buf_type - ecc_bytes */
-	D_TEXT(48),	/* fw_rev - model */
-	D_CHAR(2),	/* max_multsect - vendor3 */
-	D_SHORT(1),	/* dword_io */
-	D_CHAR(2),	/* vendor4 - capability */
-	D_SHORT(1),	/* reserved50 */
-	D_CHAR(4),	/* vendor5 - tDMA */
-	D_SHORT(4),	/* field_valid - cur_sectors */
-	D_INT(1),	/* cur_capacity */
-	D_CHAR(2),	/* multsect - multsect_valid */
-	D_INT(1),	/* lba_capacity */
-	D_SHORT(194)	/* dma_1word - reservedyy */
-};
-
-#define num_driveid_types       (sizeof(driveid_types)/sizeof(*driveid_types))
-
-static __inline__ void ide_fix_driveid(struct hd_driveid *id)
-{
-	u_char *p = (u_char *)id;
-	int i, j, cnt;
-	u_char t;
-
-	for (i = 0; i < num_driveid_types; i++) {
-		cnt = driveid_types[i] & T_MASK_COUNT;
-		switch (driveid_types[i] & T_MASK_TYPE) {
-		case T_CHAR:
-			p += cnt;
-			break;
-		case T_SHORT:
-			for (j = 0; j < cnt; j++) {
-				t = p[0];
-				p[0] = p[1];
-				p[1] = t;
-				p += 2;
-			}
-			break;
-		case T_INT:
-			for (j = 0; j < cnt; j++) {
-				t = p[0];
-				p[0] = p[3];
-				p[3] = t;
-				t = p[1];
-				p[1] = p[2];
-				p[2] = t;
-				p += 4;
-			}
-			break;
-		case T_TEXT:
-			for (j = 0; j < cnt; j += 2) {
-				t = p[0];
-				p[0] = p[1];
-				p[1] = t;
-				p += 2;
-			}
-			break;
-		};
-	}
-}
-
-#else /* defined(CONFIG_SWAP_IO_SPACE) && defined(__MIPSEB__)  */
-
-#define ide_fix_driveid(id)		do {} while (0)
-
 #endif
 
-/*
- * The following are not needed for the non-m68k ports
- */
-#define ide_ack_intr(hwif)		(1)
-#define ide_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
-
 #endif /* __KERNEL__ */
 
 #endif /* __ASM_IDE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-mips/processor.h linux-2.4.21-pre6/include/asm-mips/processor.h
--- linux-2.4.20/include/asm-mips/processor.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-mips/processor.h	2003-03-26 23:48:58.000000000 +0000
@@ -188,7 +188,7 @@
 /* Free all resources held by a thread. */
 #define release_thread(thread) do { } while(0)
 
-extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
+extern int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
 /* Copy and release all segment info associated with a VM */
 #define copy_segments(p, mm) do { } while(0)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-mips/system.h linux-2.4.21-pre6/include/asm-mips/system.h
--- linux-2.4.20/include/asm-mips/system.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-mips/system.h	2003-03-26 23:49:34.000000000 +0000
@@ -114,6 +114,8 @@
 	: /* no inputs */						\
 	: "memory")
 
+#define __save_and_sti(x)	do { __save_flags(x); __sti(); } while(0);
+
 __asm__(".macro\t__restore_flags flags\n\t"
 	".set\tnoreorder\n\t"
 	".set\tnoat\n\t"
@@ -152,6 +154,7 @@
 #  define save_flags(x) do { x = __global_save_flags(); } while (0)
 #  define restore_flags(x) __global_restore_flags(x)
 #  define save_and_cli(x) do { save_flags(x); cli(); } while(0)
+#  define save_and_sti(x) do { save_flags(x); sti(); } while(0)
 
 #else /* Single processor */
 
@@ -160,11 +163,13 @@
 #  define save_flags(x) __save_flags(x)
 #  define save_and_cli(x) __save_and_cli(x)
 #  define restore_flags(x) __restore_flags(x)
+#  define save_and_sti(x) __save_and_sti(x)
 
 #endif /* SMP */
 
 /* For spinlocks etc */
 #define local_irq_save(x)	__save_and_cli(x)
+#define local_irq_set(x)	__save_and_sti(x)
 #define local_irq_restore(x)	__restore_flags(x)
 #define local_irq_disable()	__cli()
 #define local_irq_enable()	__sti()
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-mips64/ide.h linux-2.4.21-pre6/include/asm-mips64/ide.h
--- linux-2.4.20/include/asm-mips64/ide.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-mips64/ide.h	2003-03-26 23:48:58.000000000 +0000
@@ -28,21 +28,11 @@
 # endif
 #endif
 
-#define ide__sti()	__sti()
-
 struct ide_ops {
 	int (*ide_default_irq)(ide_ioreg_t base);
 	ide_ioreg_t (*ide_default_io_base)(int index);
 	void (*ide_init_hwif_ports)(hw_regs_t *hw, ide_ioreg_t data_port,
 	                            ide_ioreg_t ctrl_port, int *irq);
-	int (*ide_request_irq)(unsigned int irq, void (*handler)(int, void *,
-	                       struct pt_regs *), unsigned long flags,
-	                       const char *device, void *dev_id);
-	void (*ide_free_irq)(unsigned int irq, void *dev_id);
-	int (*ide_check_region) (ide_ioreg_t from, unsigned int extent);
-	void (*ide_request_region)(ide_ioreg_t from, unsigned int extent,
-	                        const char *name);
-	void (*ide_release_region)(ide_ioreg_t from, unsigned int extent);
 };
 
 extern struct ide_ops *ide_ops;
@@ -77,215 +67,50 @@
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-#ifdef __MIPSEB__
-		unsigned bit7           : 1;    /* always 1 */
-		unsigned lba            : 1;    /* using LBA instead of CHS */
-		unsigned bit5           : 1;    /* always 1 */
-		unsigned unit           : 1;    /* drive select number, 0 or 1 */
-		unsigned head           : 4;    /* always zeros here */
-#else
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-#endif
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-#ifdef __MIPSEB__
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-		unsigned reserved456	: 3;
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned bit0		: 1;
-#else
-		unsigned bit0		: 1;
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned reserved456	: 3;
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-#endif
-	} b;
-} control_t;
-
-static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int,void *, struct pt_regs *),
-			unsigned long flags, const char *device, void *dev_id)
-{
-	return ide_ops->ide_request_irq(irq, handler, flags, device, dev_id);
-}
-
-static __inline__ void ide_free_irq(unsigned int irq, void *dev_id)
-{
-	ide_ops->ide_free_irq(irq, dev_id);
-}
-
-static __inline__ int ide_check_region (ide_ioreg_t from, unsigned int extent)
-{
-	return ide_ops->ide_check_region(from, extent);
-}
-
-static __inline__ void ide_request_region(ide_ioreg_t from,
-                                          unsigned int extent, const char *name)
-{
-	ide_ops->ide_request_region(from, extent, name);
-}
-
-static __inline__ void ide_release_region(ide_ioreg_t from,
-                                          unsigned int extent)
-{
-	ide_ops->ide_release_region(from, extent);
-}
-
-
 #if defined(CONFIG_SWAP_IO_SPACE) && defined(__MIPSEB__)
 
-/* get rid of defs from io.h - ide has its private and conflicting versions */
-#ifdef insw
-#undef insw
-#endif
-#ifdef outsw
-#undef outsw
-#endif
 #ifdef insl
 #undef insl
 #endif
 #ifdef outsl
 #undef outsl
 #endif
-
-#define insw(port, addr, count) ide_insw(port, addr, count)
-#define insl(port, addr, count) ide_insl(port, addr, count)
-#define outsw(port, addr, count) ide_outsw(port, addr, count)
-#define outsl(port, addr, count) ide_outsl(port, addr, count)
-
-static inline void ide_insw(unsigned long port, void *addr, unsigned int count)
-{
-       while (count--) {
-               *(u16 *)addr = *(volatile u16 *)(mips_io_port_base + port);
-               addr += 2;
-       }
-}
-
-static inline void ide_outsw(unsigned long port, void *addr, unsigned int count)
-{
-       while (count--) {
-               *(volatile u16 *)(mips_io_port_base + (port)) = *(u16 *)addr;
-               addr += 2;
-       }
-}
-
-static inline void ide_insl(unsigned long port, void *addr, unsigned int count)
-{
-       while (count--) {
-               *(u32 *)addr = *(volatile u32 *)(mips_io_port_base + port);
-               addr += 4;
-       }
-}
-
-static inline void ide_outsl(unsigned long port, void *addr, unsigned int count)
-{
-       while (count--) {
-               *(volatile u32 *)(mips_io_port_base + (port)) = *(u32 *)addr;
-               addr += 4;
-       }
-}
-
-#define T_CHAR          (0x0000)        /* char:  don't touch  */
-#define T_SHORT         (0x4000)        /* short: 12 -> 21     */
-#define T_INT           (0x8000)        /* int:   1234 -> 4321 */
-#define T_TEXT          (0xc000)        /* text:  12 -> 21     */
-
-#define T_MASK_TYPE     (0xc000)
-#define T_MASK_COUNT    (0x3fff)
-
-#define D_CHAR(cnt)     (T_CHAR  | (cnt))
-#define D_SHORT(cnt)    (T_SHORT | (cnt))
-#define D_INT(cnt)      (T_INT   | (cnt))
-#define D_TEXT(cnt)     (T_TEXT  | (cnt))
-
-static u_short driveid_types[] = {
-	D_SHORT(10),	/* config - vendor2 */
-	D_TEXT(20),	/* serial_no */
-	D_SHORT(3),	/* buf_type - ecc_bytes */
-	D_TEXT(48),	/* fw_rev - model */
-	D_CHAR(2),	/* max_multsect - vendor3 */
-	D_SHORT(1),	/* dword_io */
-	D_CHAR(2),	/* vendor4 - capability */
-	D_SHORT(1),	/* reserved50 */
-	D_CHAR(4),	/* vendor5 - tDMA */
-	D_SHORT(4),	/* field_valid - cur_sectors */
-	D_INT(1),	/* cur_capacity */
-	D_CHAR(2),	/* multsect - multsect_valid */
-	D_INT(1),	/* lba_capacity */
-	D_SHORT(194)	/* dma_1word - reservedyy */
-};
-
-#define num_driveid_types       (sizeof(driveid_types)/sizeof(*driveid_types))
-
-static __inline__ void ide_fix_driveid(struct hd_driveid *id)
-{
-	u_char *p = (u_char *)id;
-	int i, j, cnt;
-	u_char t;
-
-	for (i = 0; i < num_driveid_types; i++) {
-		cnt = driveid_types[i] & T_MASK_COUNT;
-		switch (driveid_types[i] & T_MASK_TYPE) {
-		case T_CHAR:
-			p += cnt;
-			break;
-		case T_SHORT:
-			for (j = 0; j < cnt; j++) {
-				t = p[0];
-				p[0] = p[1];
-				p[1] = t;
-				p += 2;
-			}
-			break;
-		case T_INT:
-			for (j = 0; j < cnt; j++) {
-				t = p[0];
-				p[0] = p[3];
-				p[3] = t;
-				t = p[1];
-				p[1] = p[2];
-				p[2] = t;
-				p += 4;
-			}
-			break;
-		case T_TEXT:
-			for (j = 0; j < cnt; j += 2) {
-				t = p[0];
-				p[0] = p[1];
-				p[1] = t;
-				p += 2;
-			}
-			break;
-		};
-	}
-}
-
-#else /* defined(CONFIG_SWAP_IO_SPACE) && defined(__MIPSEB__)  */
-
-#define ide_fix_driveid(id)		do {} while (0)
-
+#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)
 
-/*
- * The following are not needed for the non-m68k ports
- */
-#define ide_ack_intr(hwif)		(1)
-#define ide_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
+#endif /* defined(CONFIG_SWAP_IO_SPACE) && defined(__MIPSEB__)  */
 
 #endif /* __KERNEL__ */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-mips64/processor.h linux-2.4.21-pre6/include/asm-mips64/processor.h
--- linux-2.4.20/include/asm-mips64/processor.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-mips64/processor.h	2003-03-26 23:49:39.000000000 +0000
@@ -231,7 +231,7 @@
 /* Free all resources held by a thread. */
 #define release_thread(thread) do { } while(0)
 
-extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
+extern int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
 /* Copy and release all segment info associated with a VM */
 #define copy_segments(p, mm) do { } while(0)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-mips64/system.h linux-2.4.21-pre6/include/asm-mips64/system.h
--- linux-2.4.20/include/asm-mips64/system.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-mips64/system.h	2003-03-26 23:49:34.000000000 +0000
@@ -109,6 +109,8 @@
 	: /* no inputs */						\
 	: "memory")
 
+#define __save_and_sti(x)       do { __save_flags(x); __sti(); } while(0);
+
 __asm__(".macro\t__restore_flags flags\n\t"
 	".set\tnoreorder\n\t"
 	".set\tnoat\n\t"
@@ -147,6 +149,7 @@
 #define save_flags(x) ((x)=__global_save_flags())
 #define restore_flags(x) __global_restore_flags(x)
 #define save_and_cli(x) do { save_flags(x); cli(); } while(0)
+#define save_and_sti(x) do { save_flags(x); sti(); } while(0)
 
 #else
 
@@ -155,11 +158,13 @@
 #define save_flags(x) __save_flags(x)
 #define restore_flags(x) __restore_flags(x)
 #define save_and_cli(x) __save_and_cli(x)
+#define save_and_sti(x) __save_and_sti(x)
 
 #endif /* CONFIG_SMP */
 
 /* For spinlocks etc */
 #define local_irq_save(x)	__save_and_cli(x)
+#define local_irq_set(x)	__save_and_sti(x)
 #define local_irq_restore(x)	__restore_flags(x)
 #define local_irq_disable()	__cli()
 #define local_irq_enable()	__sti()
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-parisc/atomic.h linux-2.4.21-pre6/include/asm-parisc/atomic.h
--- linux-2.4.20/include/asm-parisc/atomic.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-parisc/atomic.h	2003-03-26 23:49:25.000000000 +0000
@@ -13,8 +13,9 @@
  * And probably incredibly slow on parisc.  OTOH, we don't
  * have to write any serious assembly.   prumpf
  */
-
 #ifdef CONFIG_SMP
+#include <asm/spinlock_t.h>
+
 /* Use an array of spinlocks for our atomic_ts.
 ** Hash function to index into a different SPINLOCK.
 ** Since "a" is usually an address, ">>8" makes one spinlock per 64-bytes.
@@ -23,25 +24,33 @@
 #  define ATOMIC_HASH(a) (&__atomic_hash[(((unsigned long) a)>>8)&(ATOMIC_HASH_SIZE-1)])
 
 extern spinlock_t __atomic_hash[ATOMIC_HASH_SIZE];
-/* copied from <asm/spinlock.h> and modified */
-#  define SPIN_LOCK(x) \
-	do { while(__ldcw(&(x)->lock) == 0); } while(0)
-	
-#  define SPIN_UNLOCK(x) \
-	do { (x)->lock = 1; } while(0)
-#else
-#  define ATOMIC_HASH_SIZE 1
-#  define ATOMIC_HASH(a)	(0)
 
-/* copied from <linux/spinlock.h> and modified */
-#  define SPIN_LOCK(x) (void)(x)
-	
-#  define SPIN_UNLOCK(x) do { } while(0)
-#endif
+/* copied from <asm/spinlock.h> and modified.
+ * No CONFIG_DEBUG_SPINLOCK support.
+ *
+ * XXX REVISIT these could be renamed and moved to spinlock_t.h as well
+ */
+#define SPIN_LOCK(x)	do { while(__ldcw(&(x)->lock) == 0); } while(0)
+#define SPIN_UNLOCK(x)  do { (x)->lock = 1; } while(0)
+
+#else	/* CONFIG_SMP */
+
+#define ATOMIC_HASH_SIZE 1
+#define ATOMIC_HASH(a)	(0)
+
+#define SPIN_LOCK(x) (void)(x)
+#define SPIN_UNLOCK(x) do { } while(0)
+
+#endif	/* CONFIG_SMP */
 
 /* copied from <linux/spinlock.h> and modified */
-#define SPIN_LOCK_IRQSAVE(lock, flags)		do { local_irq_save(flags);       SPIN_LOCK(lock); } while (0)
-#define SPIN_UNLOCK_IRQRESTORE(lock, flags)	do { SPIN_UNLOCK(lock);  local_irq_restore(flags); } while (0)
+#define SPIN_LOCK_IRQSAVE(lock, flags)	do { \
+	local_irq_save(flags); 	SPIN_LOCK(lock); \
+} while (0)
+
+#define SPIN_UNLOCK_IRQRESTORE(lock, flags) do { \
+	SPIN_UNLOCK(lock);  local_irq_restore(flags); \
+} while (0)
 
 /* Note that we need not lock read accesses - aligned word writes/reads
  * are atomic, so a reader never sees unconsistent values.
@@ -54,22 +63,10 @@
 } atomic_t;
 
 
-/*
-** xchg/cmpxchg moved from asm/system.h - ggg
-*/
-
-#if 1
 /* This should get optimized out since it's never called.
 ** Or get a link error if xchg is used "wrong".
 */
 extern void __xchg_called_with_bad_pointer(void);
-#else
-static inline void __xchg_called_with_bad_pointer(void)
-{
-	extern void panic(const char * fmt, ...);
-	panic("xchg called with bad pointer");
-}
-#endif
 
 /* __xchg32/64 defined in arch/parisc/lib/bitops.c */
 extern unsigned long __xchg8(char, char *);
@@ -98,7 +95,7 @@
 /*
 ** REVISIT - Abandoned use of LDCW in xchg() for now:
 ** o need to test sizeof(*ptr) to avoid clearing adjacent bytes
-** o and while we are at it, could __LP64__ code use LDCD too?
+** o and while we are at it, could 64-bit code use LDCD too?
 **
 **	if (__builtin_constant_p(x) && (x == NULL))
 **		if (((unsigned long)p & 0xf) == 0)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-parisc/hdreg.h linux-2.4.21-pre6/include/asm-parisc/hdreg.h
--- linux-2.4.20/include/asm-parisc/hdreg.h	2000-12-05 20:29:39.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-parisc/hdreg.h	2003-03-26 23:49:07.000000000 +0000
@@ -1,6 +1,7 @@
 #ifndef _ASM_HDREG_H
 #define _ASM_HDREG_H
 
-typedef unsigned short ide_ioreg_t;
+//typedef unsigned short ide_ioreg_t;
+typedef unsigned long ide_ioreg_t;
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-parisc/ide.h linux-2.4.21-pre6/include/asm-parisc/ide.h
--- linux-2.4.20/include/asm-parisc/ide.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-parisc/ide.h	2003-03-26 23:49:27.000000000 +0000
@@ -20,6 +20,8 @@
 #define MAX_HWIFS	2
 #endif
 
+#define ide__sti()      __sti()
+
 static __inline__ int ide_default_irq(ide_ioreg_t base)
 {
 	switch (base) {
@@ -78,93 +80,28 @@
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
-#define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
-#define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
-#define ide_check_region(from,extent)		check_region((from), (extent))
-#define ide_request_region(from,extent,name)	request_region((from), (extent), (name))
-#define ide_release_region(from,extent)		release_region((from), (extent))
-
-#define T_CHAR          (0x0000)        /* char:  don't touch  */
-#define T_SHORT         (0x4000)        /* short: 12 -> 21     */
-#define T_INT           (0x8000)        /* int:   1234 -> 4321 */
-#define T_TEXT          (0xc000)        /* text:  12 -> 21     */
-
-#define T_MASK_TYPE     (0xc000)
-#define T_MASK_COUNT    (0x3fff)
-
-#define D_CHAR(cnt)     (T_CHAR  | (cnt))
-#define D_SHORT(cnt)    (T_SHORT | (cnt))
-#define D_INT(cnt)      (T_INT   | (cnt))
-#define D_TEXT(cnt)     (T_TEXT  | (cnt))
-
-static u_short driveid_types[] = {
-	D_SHORT(10),	/* config - vendor2 */
-	D_TEXT(20),	/* serial_no */
-	D_SHORT(3),	/* buf_type - ecc_bytes */
-	D_TEXT(48),	/* fw_rev - model */
-	D_CHAR(2),	/* max_multsect - vendor3 */
-	D_SHORT(1),	/* dword_io */
-	D_CHAR(2),	/* vendor4 - capability */
-	D_SHORT(1),	/* reserved50 */
-	D_CHAR(4),	/* vendor5 - tDMA */
-	D_SHORT(4),	/* field_valid - cur_sectors */
-	D_INT(1),	/* cur_capacity */
-	D_CHAR(2),	/* multsect - multsect_valid */
-	D_INT(1),	/* lba_capacity */
-	D_SHORT(194)	/* dma_1word - reservedyy */
-};
-
-#define num_driveid_types       (sizeof(driveid_types)/sizeof(*driveid_types))
-
-static __inline__ void ide_fix_driveid(struct hd_driveid *id)
-{
-	u_char *p = (u_char *)id;
-	int i, j, cnt;
-	u_char t;
-
-	for (i = 0; i < num_driveid_types; i++) {
-		cnt = driveid_types[i] & T_MASK_COUNT;
-		switch (driveid_types[i] & T_MASK_TYPE) {
-		case T_CHAR:
-			p += cnt;
-			break;
-		case T_SHORT:
-			for (j = 0; j < cnt; j++) {
-				t = p[0];
-				p[0] = p[1];
-				p[1] = t;
-				p += 2;
-			}
-			break;
-		case T_INT:
-			for (j = 0; j < cnt; j++) {
-				t = p[0];
-				p[0] = p[3];
-				p[3] = t;
-				t = p[1];
-				p[1] = p[2];
-				p[2] = t;
-				p += 4;
-			}
-			break;
-		case T_TEXT:
-			for (j = 0; j < cnt; j += 2) {
-				t = p[0];
-				p[0] = p[1];
-				p[1] = t;
-				p += 2;
-			}
-			break;
-		};
-	}
-}
-
-/*
- * The following are not needed for the non-m68k ports
- */
-#define ide_ack_intr(hwif)		(1)
-#define ide_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned bit7		: 1;	/* always 1 */
+		unsigned lba		: 1;	/* using LBA instead of CHS */
+		unsigned bit5		: 1;	/* always 1 */
+		unsigned unit		: 1;	/* drive select number, 0 or 1 */
+		unsigned head		: 4;	/* always zeros here */
+	} b;
+} select_t;
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned bit0		: 1;
+		unsigned nIEN		: 1;	/* device INTRQ to host */
+		unsigned SRST		: 1;	/* host soft reset bit */
+		unsigned bit3		: 1;	/* ATA-2 thingy */
+		unsigned reserved456	: 3;
+		unsigned HOB		: 1;	/* 48-bit address ordering */
+	} b;
+} control_t;
 
 #endif /* __KERNEL__ */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-parisc/pci.h linux-2.4.21-pre6/include/asm-parisc/pci.h
--- linux-2.4.20/include/asm-parisc/pci.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-parisc/pci.h	2003-03-26 23:49:09.000000000 +0000
@@ -81,6 +81,11 @@
 #define PCI_BUS_ADDR(hba,a)	((a) - hba->lmmio_space_offset)
 #define PCI_HOST_ADDR(hba,a)	((a) + hba->lmmio_space_offset)
 
+/* The PCI address space equals the physical memory address space.
+   The networking and block device layers use this boolean for bounce buffer
+   decisions.  */
+#define PCI_DMA_BUS_IS_PHYS  1
+
 /*
 ** KLUGE: linux/pci.h include asm/pci.h BEFORE declaring struct pci_bus
 ** (This eliminates some of the warnings).
@@ -273,7 +278,7 @@
 int ccio_allocate_resource(const struct parisc_device *dev,
 		struct resource *res, unsigned long size,
 		unsigned long min, unsigned long max, unsigned long align,
-		void (*alignf)(void *, struct resource *, unsigned long),
+		void (*alignf)(void *, struct resource *, unsigned long, unsigned long),
 		void *alignf_data);
 #else /* !CONFIG_IOMMU_CCIO */
 #define ccio_get_iommu(dev) NULL
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-parisc/pdc.h linux-2.4.21-pre6/include/asm-parisc/pdc.h
--- linux-2.4.20/include/asm-parisc/pdc.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-parisc/pdc.h	2003-03-26 23:48:57.000000000 +0000
@@ -476,7 +476,7 @@
 #define PDC_TYPE_SYSTEM_MAP	 1 /* 32-bit, but supports PDC_SYSTEM_MAP */
 #define PDC_TYPE_SNAKE		 2 /* Doesn't support SYSTEM_MAP */
 
-#define is_pdc_pat()    (pdc_type == PDC_TYPE_PAT)
+#define is_pdc_pat()	(pdc_type == PDC_TYPE_PAT)
 
 struct pdc_chassis_info {       /* for PDC_CHASSIS_INFO */
 	unsigned long actcnt;   /* actual number of bytes returned */
@@ -817,10 +817,13 @@
 
 /* IODC ENTRY_IO() */
 #define ENTRY_IO_BOOTIN		0
+#define ENTRY_IO_BOOTOUT	1
 #define ENTRY_IO_CIN		2
 #define ENTRY_IO_COUT		3
 #define ENTRY_IO_CLOSE		4
 #define ENTRY_IO_GETMSG		9
+#define ENTRY_IO_BBLOCK_IN	16
+#define ENTRY_IO_BBLOCK_OUT	17
 
 /* IODC ENTRY_SPA() */
 
@@ -912,6 +915,7 @@
 
 int pdc_add_valid(unsigned long address);
 int pdc_chassis_info(struct pdc_chassis_info *chassis_info, void *led_info, unsigned long len);
+int pdc_chassis_disp(unsigned long disp);
 int pdc_coproc_cfg(struct pdc_coproc_cfg *pdc_coproc_info);
 int pdc_iodc_read(unsigned long *actcnt, unsigned long hpa, unsigned int index,
 		  void *iodc_data, unsigned int iodc_data_size);
@@ -958,6 +962,8 @@
                  unsigned long glob_cfg);
 
 #ifdef __LP64__
+int pdc_pat_chassis_send_log(unsigned long status, unsigned long data);
+
 int pdc_pat_cell_get_number(struct pdc_pat_cell_num *cell_info);
 int pdc_pat_cell_module(unsigned long *actcnt, unsigned long ploc, unsigned long mod,
 			unsigned long view_type, void *mem_addr);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-parisc/pdc_chassis.h linux-2.4.21-pre6/include/asm-parisc/pdc_chassis.h
--- linux-2.4.20/include/asm-parisc/pdc_chassis.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-parisc/pdc_chassis.h	2003-03-26 23:49:55.000000000 +0000
@@ -0,0 +1,382 @@
+/*
+ *		include/asm-parisc/pdc_chassis.h
+ *
+ *		Copyright (C) 2002 Laurent Canet <canetl@esiee.fr>
+ *		Copyright (C) 2002 Thibaut Varene <varenet@esiee.fr>
+ *
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2, or (at your option)
+ *      any later version.
+ *      
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *      
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *      TODO:	- handle processor number on SMP systems (Reporting Entity ID)
+ *      	- handle message ID
+ *      	- handle timestamps
+ */
+ 
+
+#ifndef _PARISC_PDC_CHASSIS_H
+#define _PARISC_PDC_CHASSIS_H
+
+/*
+ * ----------
+ * Prototypes
+ * ----------
+ */
+
+int pdc_chassis_send_status(int message);
+void __init parisc_pdc_chassis_init(void);
+
+
+/*
+ * -----------------
+ * Direct call names
+ * -----------------
+ * They setup everything for you, the Log message and the corresponding LED state
+ */
+
+#define PDC_CHASSIS_DIRECT_BSTART	0
+#define PDC_CHASSIS_DIRECT_BCOMPLETE	1
+#define PDC_CHASSIS_DIRECT_SHUTDOWN	2
+#define PDC_CHASSIS_DIRECT_PANIC	3
+#define PDC_CHASSIS_DIRECT_HPMC		4
+#define PDC_CHASSIS_DIRECT_LPMC		5
+#define PDC_CHASSIS_DIRECT_DUMP		6	/* not yet implemented */
+#define PDC_CHASSIS_DIRECT_OOPS		7	/* not yet implemented */
+
+
+/*
+ * ------------
+ * LEDs control
+ * ------------
+ * Set the three LEDs -- Run, Attn, and Fault.
+ */
+
+/* Old PDC LED control */
+#define PDC_CHASSIS_DISP_DATA(v)	((unsigned long)(v) << 17)
+
+/* 
+ * Available PDC PAT LED states
+ */
+
+#define PDC_CHASSIS_LED_RUN_OFF		(0ULL << 4)
+#define PDC_CHASSIS_LED_RUN_FLASH	(1ULL << 4)
+#define PDC_CHASSIS_LED_RUN_ON		(2ULL << 4)
+#define PDC_CHASSIS_LED_RUN_NC		(3ULL << 4)
+#define PDC_CHASSIS_LED_ATTN_OFF	(0ULL << 6)
+#define PDC_CHASSIS_LED_ATTN_FLASH	(1ULL << 6)
+#define PDC_CHASSIS_LED_ATTN_NC		(3ULL << 6)	/* ATTN ON is invalid */
+#define PDC_CHASSIS_LED_FAULT_OFF	(0ULL << 8)
+#define PDC_CHASSIS_LED_FAULT_FLASH	(1ULL << 8)
+#define PDC_CHASSIS_LED_FAULT_ON	(2ULL << 8)
+#define PDC_CHASSIS_LED_FAULT_NC	(3ULL << 8)
+#define PDC_CHASSIS_LED_VALID		(1ULL << 10)
+
+/* 
+ * Valid PDC PAT LED states combinations
+ */
+
+/* System running normally */
+#define PDC_CHASSIS_LSTATE_RUN_NORMAL	(PDC_CHASSIS_LED_RUN_ON		| \
+					 PDC_CHASSIS_LED_ATTN_OFF	| \
+					 PDC_CHASSIS_LED_FAULT_OFF	| \
+					 PDC_CHASSIS_LED_VALID		)
+/* System crashed and rebooted itself successfully */
+#define PDC_CHASSIS_LSTATE_RUN_CRASHREC	(PDC_CHASSIS_LED_RUN_ON		| \
+					 PDC_CHASSIS_LED_ATTN_OFF	| \
+					 PDC_CHASSIS_LED_FAULT_FLASH	| \
+					 PDC_CHASSIS_LED_VALID		)
+/* There was a system interruption that did not take the system down */
+#define PDC_CHASSIS_LSTATE_RUN_SYSINT	(PDC_CHASSIS_LED_RUN_ON		| \
+					 PDC_CHASSIS_LED_ATTN_FLASH	| \
+					 PDC_CHASSIS_LED_FAULT_OFF	| \
+					 PDC_CHASSIS_LED_VALID		)
+/* System running and unexpected reboot or non-critical error detected */
+#define PDC_CHASSIS_LSTATE_RUN_NCRIT	(PDC_CHASSIS_LED_RUN_ON		| \
+					 PDC_CHASSIS_LED_ATTN_FLASH	| \
+					 PDC_CHASSIS_LED_FAULT_FLASH	| \
+					 PDC_CHASSIS_LED_VALID		)
+/* Executing non-OS code */
+#define PDC_CHASSIS_LSTATE_NONOS	(PDC_CHASSIS_LED_RUN_FLASH	| \
+					 PDC_CHASSIS_LED_ATTN_OFF	| \
+					 PDC_CHASSIS_LED_FAULT_OFF	| \
+					 PDC_CHASSIS_LED_VALID		)
+/* Boot failed - Executing non-OS code */
+#define PDC_CHASSIS_LSTATE_NONOS_BFAIL	(PDC_CHASSIS_LED_RUN_FLASH	| \
+					 PDC_CHASSIS_LED_ATTN_OFF	| \
+					 PDC_CHASSIS_LED_FAULT_ON	| \
+					 PDC_CHASSIS_LED_VALID		)
+/* Unexpected reboot occured - Executing non-OS code */
+#define PDC_CHASSIS_LSTATE_NONOS_UNEXP	(PDC_CHASSIS_LED_RUN_FLASH	| \
+					 PDC_CHASSIS_LED_ATTN_OFF	| \
+					 PDC_CHASSIS_LED_FAULT_FLASH	| \
+					 PDC_CHASSIS_LED_VALID		)
+/* Executing non-OS code - Non-critical error detected */
+#define PDC_CHASSIS_LSTATE_NONOS_NCRIT	(PDC_CHASSIS_LED_RUN_FLASH	| \
+					 PDC_CHASSIS_LED_ATTN_FLASH	| \
+					 PDC_CHASSIS_LED_FAULT_OFF	| \
+					 PDC_CHASSIS_LED_VALID		)
+/* Boot failed - Executing non-OS code - Non-critical error detected */
+#define PDC_CHASSIS_LSTATE_BFAIL_NCRIT	(PDC_CHASSIS_LED_RUN_FLASH	| \
+					 PDC_CHASSIS_LED_ATTN_FLASH	| \
+					 PDC_CHASSIS_LED_FAULT_ON	| \
+					 PDC_CHASSIS_LED_VALID		)
+/* Unexpected reboot/recovering - Executing non-OS code - Non-critical error detected */
+#define PDC_CHASSIS_LSTATE_UNEXP_NCRIT	(PDC_CHASSIS_LED_RUN_FLASH	| \
+					 PDC_CHASSIS_LED_ATTN_FLASH	| \
+					 PDC_CHASSIS_LED_FAULT_FLASH	| \
+					 PDC_CHASSIS_LED_VALID		)
+/* Cannot execute PDC */
+#define PDC_CHASSIS_LSTATE_CANNOT_PDC	(PDC_CHASSIS_LED_RUN_OFF	| \
+					 PDC_CHASSIS_LED_ATTN_OFF	| \
+					 PDC_CHASSIS_LED_FAULT_OFF	| \
+					 PDC_CHASSIS_LED_VALID		)
+/* Boot failed - OS not up - PDC has detected a failure that prevents boot */
+#define PDC_CHASSIS_LSTATE_FATAL_BFAIL	(PDC_CHASSIS_LED_RUN_OFF	| \
+					 PDC_CHASSIS_LED_ATTN_OFF	| \
+					 PDC_CHASSIS_LED_FAULT_ON	| \
+					 PDC_CHASSIS_LED_VALID		)
+/* No code running - Non-critical error detected (double fault situation) */
+#define PDC_CHASSIS_LSTATE_NOCODE_NCRIT	(PDC_CHASSIS_LED_RUN_OFF	| \
+					 PDC_CHASSIS_LED_ATTN_FLASH	| \
+					 PDC_CHASSIS_LED_FAULT_OFF	| \
+					 PDC_CHASSIS_LED_VALID		)
+/* Boot failed - OS not up - Fatal failure detected - Non-critical error detected */
+#define PDC_CHASSIS_LSTATE_FATAL_NCRIT	(PDC_CHASSIS_LED_RUN_OFF	| \
+					 PDC_CHASSIS_LED_ATTN_FLASH	| \
+					 PDC_CHASSIS_LED_FAULT_ON	| \
+					 PDC_CHASSIS_LED_VALID		)
+/* All other states are invalid */
+
+
+/*
+ * --------------
+ * PDC Log events
+ * --------------
+ * Here follows bits needed to fill up the log event sent to PDC_CHASSIS
+ * The log message contains: Alert level, Source, Source detail,
+ * Source ID, Problem detail, Caller activity, Activity status, 
+ * Caller subactivity, Reporting entity type, Reporting entity ID,
+ * Data type, Unique message ID and EOM. 
+ */
+
+/* Alert level */
+#define PDC_CHASSIS_ALERT_FORWARD	(0ULL << 36)	/* no failure detected */
+#define PDC_CHASSIS_ALERT_SERPROC	(1ULL << 36)	/* service proc - no failure */
+#define PDC_CHASSIS_ALERT_NURGENT	(2ULL << 36)	/* non-urgent operator attn */
+#define PDC_CHASSIS_ALERT_BLOCKED	(3ULL << 36)	/* system blocked */
+#define PDC_CHASSIS_ALERT_CONF_CHG	(4ULL << 36)	/* unexpected configuration change */
+#define PDC_CHASSIS_ALERT_ENV_PB	(5ULL << 36)	/* boot possible, environmental pb */
+#define PDC_CHASSIS_ALERT_PENDING	(6ULL << 36)	/* boot possible, pending failure */
+#define PDC_CHASSIS_ALERT_PERF_IMP	(8ULL << 36)	/* boot possible, performance impaired */
+#define PDC_CHASSIS_ALERT_FUNC_IMP	(10ULL << 36)	/* boot possible, functionality impaired */
+#define PDC_CHASSIS_ALERT_SOFT_FAIL	(12ULL << 36)	/* software failure */
+#define PDC_CHASSIS_ALERT_HANG		(13ULL << 36)	/* system hang */
+#define PDC_CHASSIS_ALERT_ENV_FATAL	(14ULL << 36)	/* fatal power or environmental pb */
+#define PDC_CHASSIS_ALERT_HW_FATAL	(15ULL << 36)	/* fatal hardware problem */
+
+/* Source */
+#define PDC_CHASSIS_SRC_NONE		(0ULL << 28)	/* unknown, no source stated */
+#define PDC_CHASSIS_SRC_PROC		(1ULL << 28)	/* processor */
+/* For later use ? */
+#define PDC_CHASSIS_SRC_PROC_CACHE	(2ULL << 28)	/* processor cache*/
+#define PDC_CHASSIS_SRC_PDH		(3ULL << 28)	/* processor dependent hardware */
+#define PDC_CHASSIS_SRC_PWR		(4ULL << 28)	/* power */
+#define PDC_CHASSIS_SRC_FAB		(5ULL << 28)	/* fabric connector */
+#define PDC_CHASSIS_SRC_PLATi		(6ULL << 28)	/* platform */
+#define PDC_CHASSIS_SRC_MEM		(7ULL << 28)	/* memory */
+#define PDC_CHASSIS_SRC_IO		(8ULL << 28)	/* I/O */
+#define PDC_CHASSIS_SRC_CELL		(9ULL << 28)	/* cell */
+#define PDC_CHASSIS_SRC_PD		(10ULL << 28)	/* protected domain */
+
+/* Source detail field */
+#define PDC_CHASSIS_SRC_D_PROC		(1ULL << 24)	/* processor general */
+
+/* Source ID - platform dependent */
+#define PDC_CHASSIS_SRC_ID_UNSPEC	(0ULL << 16)
+
+/* Problem detail - problem source dependent */
+#define PDC_CHASSIS_PB_D_PROC_NONE	(0ULL << 32)	/* no problem detail */
+#define PDC_CHASSIS_PB_D_PROC_TIMEOUT	(4ULL << 32)	/* timeout */
+
+/* Caller activity */
+#define PDC_CHASSIS_CALL_ACT_HPUX_BL	(7ULL << 12)	/* Boot Loader */
+#define PDC_CHASSIS_CALL_ACT_HPUX_PD	(8ULL << 12)	/* SAL_PD activities */
+#define PDC_CHASSIS_CALL_ACT_HPUX_EVENT	(9ULL << 12)	/* SAL_EVENTS activities */
+#define PDC_CHASSIS_CALL_ACT_HPUX_IO	(10ULL << 12)	/* SAL_IO activities */
+#define PDC_CHASSIS_CALL_ACT_HPUX_PANIC	(11ULL << 12)	/* System panic */
+#define PDC_CHASSIS_CALL_ACT_HPUX_INIT	(12ULL << 12)	/* System initialization */
+#define PDC_CHASSIS_CALL_ACT_HPUX_SHUT	(13ULL << 12)	/* System shutdown */
+#define PDC_CHASSIS_CALL_ACT_HPUX_WARN	(14ULL << 12)	/* System warning */
+#define PDC_CHASSIS_CALL_ACT_HPUX_DU	(15ULL << 12)	/* Display_Activity() update */
+
+/* Activity status - implementation dependent */
+#define PDC_CHASSIS_ACT_STATUS_UNSPEC	(0ULL << 0)
+
+/* Caller subactivity - implementation dependent */
+/* FIXME: other subactivities ? */
+#define PDC_CHASSIS_CALL_SACT_UNSPEC	(0ULL << 4)	/* implementation dependent */
+
+/* Reporting entity type */
+#define PDC_CHASSIS_RET_GENERICOS	(12ULL << 52)	/* generic OSes */
+#define PDC_CHASSIS_RET_IA64_NT		(13ULL << 52)	/* IA-64 NT */
+#define PDC_CHASSIS_RET_HPUX		(14ULL << 52)	/* HP-UX */
+#define PDC_CHASSIS_RET_DIAG		(15ULL << 52)	/* offline diagnostics & utilities */
+
+/* Reporting entity ID */
+#define PDC_CHASSIS_REID_UNSPEC		(0ULL << 44)
+
+/* Data type */
+#define PDC_CHASSIS_DT_NONE		(0ULL << 59)	/* data field unused */
+/* For later use ? Do we need these ? */
+#define PDC_CHASSIS_DT_PHYS_ADDR	(1ULL << 59)	/* physical address */
+#define PDC_CHASSIS_DT_DATA_EXPECT	(2ULL << 59)	/* expected data */
+#define PDC_CHASSIS_DT_ACTUAL		(3ULL << 59)	/* actual data */
+#define PDC_CHASSIS_DT_PHYS_LOC		(4ULL << 59)	/* physical location */
+#define PDC_CHASSIS_DT_PHYS_LOC_EXT	(5ULL << 59)	/* physical location extension */
+#define PDC_CHASSIS_DT_TAG		(6ULL << 59)	/* tag */
+#define PDC_CHASSIS_DT_SYNDROME		(7ULL << 59)	/* syndrome */
+#define PDC_CHASSIS_DT_CODE_ADDR	(8ULL << 59)	/* code address */
+#define PDC_CHASSIS_DT_ASCII_MSG	(9ULL << 59)	/* ascii message */
+#define PDC_CHASSIS_DT_POST		(10ULL << 59)	/* POST code */
+#define PDC_CHASSIS_DT_TIMESTAMP	(11ULL << 59)	/* timestamp */
+#define PDC_CHASSIS_DT_DEV_STAT		(12ULL << 59)	/* device status */
+#define PDC_CHASSIS_DT_DEV_TYPE		(13ULL << 59)	/* device type */
+#define PDC_CHASSIS_DT_PB_DET		(14ULL << 59)	/* problem detail */
+#define PDC_CHASSIS_DT_ACT_LEV		(15ULL << 59)	/* activity level/timeout */
+#define PDC_CHASSIS_DT_SER_NUM		(16ULL << 59)	/* serial number */
+#define PDC_CHASSIS_DT_REV_NUM		(17ULL << 59)	/* revision number */
+#define PDC_CHASSIS_DT_INTERRUPT	(18ULL << 59)	/* interruption information */
+#define PDC_CHASSIS_DT_TEST_NUM		(19ULL << 59)	/* test number */
+#define PDC_CHASSIS_DT_STATE_CHG	(20ULL << 59)	/* major changes in system state */
+#define PDC_CHASSIS_DT_PROC_DEALLOC	(21ULL << 59)	/* processor deallocate */
+#define PDC_CHASSIS_DT_RESET		(30ULL << 59)	/* reset type and cause */
+#define PDC_CHASSIS_DT_PA_LEGACY	(31ULL << 59)	/* legacy PA hex chassis code */
+
+/* System states - part of major changes in system state data field */
+#define PDC_CHASSIS_SYSTATE_BSTART	(0ULL << 0)	/* boot start */
+#define PDC_CHASSIS_SYSTATE_BCOMP	(1ULL << 0)	/* boot complete */
+#define PDC_CHASSIS_SYSTATE_CHANGE	(2ULL << 0)	/* major change */
+#define PDC_CHASSIS_SYSTATE_LED		(3ULL << 0)	/* LED change */
+#define PDC_CHASSIS_SYSTATE_PANIC	(9ULL << 0)	/* OS Panic */
+#define PDC_CHASSIS_SYSTATE_DUMP	(10ULL << 0)	/* memory dump */
+#define PDC_CHASSIS_SYSTATE_HPMC	(11ULL << 0)	/* processing HPMC */
+#define PDC_CHASSIS_SYSTATE_HALT	(15ULL << 0)	/* system halted */
+
+/* Message ID */
+#define PDC_CHASSIS_MSG_ID		(0ULL << 40)	/* we do not handle msg IDs atm */
+
+/* EOM - separates log entries */
+#define PDC_CHASSIS_EOM_CLEAR		(0ULL << 43)
+#define PDC_CHASSIS_EOM_SET		(1ULL << 43)
+
+/*
+ * Preformated well known messages
+ */
+
+/* Boot started */
+#define PDC_CHASSIS_PMSG_BSTART		(PDC_CHASSIS_ALERT_SERPROC	| \
+					 PDC_CHASSIS_SRC_PROC		| \
+					 PDC_CHASSIS_SRC_D_PROC		| \
+					 PDC_CHASSIS_SRC_ID_UNSPEC	| \
+					 PDC_CHASSIS_PB_D_PROC_NONE	| \
+					 PDC_CHASSIS_CALL_ACT_HPUX_INIT	| \
+					 PDC_CHASSIS_ACT_STATUS_UNSPEC	| \
+					 PDC_CHASSIS_CALL_SACT_UNSPEC	| \
+					 PDC_CHASSIS_RET_HPUX		| \
+					 PDC_CHASSIS_REID_UNSPEC	| \
+					 PDC_CHASSIS_DT_STATE_CHG	| \
+					 PDC_CHASSIS_SYSTATE_BSTART	| \
+					 PDC_CHASSIS_MSG_ID		| \
+					 PDC_CHASSIS_EOM_SET		)
+
+/* Boot complete */
+#define PDC_CHASSIS_PMSG_BCOMPLETE	(PDC_CHASSIS_ALERT_SERPROC	| \
+					 PDC_CHASSIS_SRC_PROC		| \
+					 PDC_CHASSIS_SRC_D_PROC		| \
+					 PDC_CHASSIS_SRC_ID_UNSPEC	| \
+					 PDC_CHASSIS_PB_D_PROC_NONE	| \
+					 PDC_CHASSIS_CALL_ACT_HPUX_INIT	| \
+					 PDC_CHASSIS_ACT_STATUS_UNSPEC	| \
+					 PDC_CHASSIS_CALL_SACT_UNSPEC	| \
+					 PDC_CHASSIS_RET_HPUX		| \
+					 PDC_CHASSIS_REID_UNSPEC	| \
+					 PDC_CHASSIS_DT_STATE_CHG	| \
+					 PDC_CHASSIS_SYSTATE_BCOMP	| \
+					 PDC_CHASSIS_MSG_ID		| \
+					 PDC_CHASSIS_EOM_SET		)
+
+/* Shutdown */
+#define PDC_CHASSIS_PMSG_SHUTDOWN	(PDC_CHASSIS_ALERT_SERPROC	| \
+					 PDC_CHASSIS_SRC_PROC		| \
+					 PDC_CHASSIS_SRC_D_PROC		| \
+					 PDC_CHASSIS_SRC_ID_UNSPEC	| \
+					 PDC_CHASSIS_PB_D_PROC_NONE	| \
+					 PDC_CHASSIS_CALL_ACT_HPUX_SHUT	| \
+					 PDC_CHASSIS_ACT_STATUS_UNSPEC	| \
+					 PDC_CHASSIS_CALL_SACT_UNSPEC	| \
+					 PDC_CHASSIS_RET_HPUX		| \
+					 PDC_CHASSIS_REID_UNSPEC	| \
+					 PDC_CHASSIS_DT_STATE_CHG	| \
+					 PDC_CHASSIS_SYSTATE_HALT	| \
+					 PDC_CHASSIS_MSG_ID		| \
+					 PDC_CHASSIS_EOM_SET		)
+
+/* Panic */
+#define PDC_CHASSIS_PMSG_PANIC		(PDC_CHASSIS_ALERT_SOFT_FAIL	| \
+					 PDC_CHASSIS_SRC_PROC		| \
+					 PDC_CHASSIS_SRC_D_PROC		| \
+					 PDC_CHASSIS_SRC_ID_UNSPEC	| \
+					 PDC_CHASSIS_PB_D_PROC_NONE	| \
+					 PDC_CHASSIS_CALL_ACT_HPUX_PANIC| \
+					 PDC_CHASSIS_ACT_STATUS_UNSPEC	| \
+					 PDC_CHASSIS_CALL_SACT_UNSPEC	| \
+					 PDC_CHASSIS_RET_HPUX		| \
+					 PDC_CHASSIS_REID_UNSPEC	| \
+					 PDC_CHASSIS_DT_STATE_CHG	| \
+					 PDC_CHASSIS_SYSTATE_PANIC	| \
+					 PDC_CHASSIS_MSG_ID		| \
+					 PDC_CHASSIS_EOM_SET		)
+
+// FIXME: extrapolated data
+/* HPMC */
+#define PDC_CHASSIS_PMSG_HPMC		(PDC_CHASSIS_ALERT_CONF_CHG /*?*/	| \
+					 PDC_CHASSIS_SRC_PROC		| \
+					 PDC_CHASSIS_SRC_D_PROC		| \
+					 PDC_CHASSIS_SRC_ID_UNSPEC	| \
+					 PDC_CHASSIS_PB_D_PROC_NONE	| \
+					 PDC_CHASSIS_CALL_ACT_HPUX_WARN	| \
+					 PDC_CHASSIS_RET_HPUX		| \
+					 PDC_CHASSIS_DT_STATE_CHG	| \
+					 PDC_CHASSIS_SYSTATE_HPMC	| \
+					 PDC_CHASSIS_MSG_ID		| \
+					 PDC_CHASSIS_EOM_SET		)
+
+/* LPMC */
+#define PDC_CHASSIS_PMSG_LPMC		(PDC_CHASSIS_ALERT_BLOCKED /*?*/| \
+					 PDC_CHASSIS_SRC_PROC		| \
+					 PDC_CHASSIS_SRC_D_PROC		| \
+					 PDC_CHASSIS_SRC_ID_UNSPEC	| \
+					 PDC_CHASSIS_PB_D_PROC_NONE	| \
+					 PDC_CHASSIS_CALL_ACT_HPUX_WARN	| \
+					 PDC_CHASSIS_ACT_STATUS_UNSPEC	| \
+					 PDC_CHASSIS_CALL_SACT_UNSPEC	| \
+					 PDC_CHASSIS_RET_HPUX		| \
+					 PDC_CHASSIS_REID_UNSPEC	| \
+					 PDC_CHASSIS_DT_STATE_CHG	| \
+					 PDC_CHASSIS_SYSTATE_CHANGE	| \
+					 PDC_CHASSIS_MSG_ID		| \
+					 PDC_CHASSIS_EOM_SET		)
+
+#endif /* _PARISC_PDC_CHASSIS_H */
+/* vim: set ts=8 */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-parisc/pgalloc.h linux-2.4.21-pre6/include/asm-parisc/pgalloc.h
--- linux-2.4.20/include/asm-parisc/pgalloc.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-parisc/pgalloc.h	2003-03-26 23:49:55.000000000 +0000
@@ -123,6 +123,9 @@
 
 #define flush_icache_page(vma,page)	do { flush_kernel_dcache_page(page_address(page)); flush_kernel_icache_page(page_address(page)); } while (0)
 
+#define flush_icache_user_range(vma, page, addr, len) \
+	flush_user_icache_range(addr, addr + len);
+
 #define flush_icache_range(s,e)		do { flush_kernel_dcache_range_asm(s,e); flush_kernel_icache_range_asm(s,e); } while (0)
 
 /* TLB flushing routines.... */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-parisc/pgtable.h linux-2.4.21-pre6/include/asm-parisc/pgtable.h
--- linux-2.4.20/include/asm-parisc/pgtable.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-parisc/pgtable.h	2003-03-26 23:49:25.000000000 +0000
@@ -281,6 +281,11 @@
 	__pte;								\
 })
 
+/* 
+ * Change "struct page" to physical address.
+ */
+#define page_to_phys(page)      PAGE_TO_PA(page)
+
 #ifdef CONFIG_DISCONTIGMEM
 #define PAGE_TO_PA(page) \
 		((((page)-(page)->zone->zone_mem_map) << PAGE_SHIFT) \
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-parisc/processor.h linux-2.4.21-pre6/include/asm-parisc/processor.h
--- linux-2.4.20/include/asm-parisc/processor.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-parisc/processor.h	2003-03-26 23:49:55.000000000 +0000
@@ -9,6 +9,7 @@
 #define __ASM_PARISC_PROCESSOR_H
 
 #ifndef __ASSEMBLY__
+#include <linux/config.h>
 #include <linux/threads.h>
 
 #include <asm/hardware.h>
@@ -17,6 +18,9 @@
 #include <asm/ptrace.h>
 #include <asm/types.h>
 #include <asm/system.h>
+#ifdef CONFIG_SMP
+#include <asm/spinlock_t.h>
+#endif
 #endif /* __ASSEMBLY__ */
 
 /*
@@ -71,7 +75,6 @@
 */
 struct cpuinfo_parisc {
 
-	struct irq_region *region;
 	unsigned long it_value;     /* Interval Timer value at last timer Intr */
 	unsigned long it_delta;     /* Interval Timer delta (tic_10ms / HZ * 100) */
 	unsigned long irq_count;    /* number of IRQ's since boot */
@@ -289,7 +292,7 @@
 
 /* Free all resources held by a thread. */
 extern void release_thread(struct task_struct *);
-extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
+extern int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
 extern void map_hpux_gateway_page(struct task_struct *tsk, struct mm_struct *mm);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-parisc/rtc.h linux-2.4.21-pre6/include/asm-parisc/rtc.h
--- linux-2.4.20/include/asm-parisc/rtc.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-parisc/rtc.h	2003-03-26 23:48:59.000000000 +0000
@@ -0,0 +1,132 @@
+/* include/asm-parisc/rtc.h */
+
+#ifndef _ASM_RTC_H
+#define _ASM_RTC_H
+
+#ifdef __KERNEL__
+
+#include <linux/rtc.h>
+#include <asm/errno.h>
+
+#define RTC_PIE 0x40		/* periodic interrupt enable */
+#define RTC_AIE 0x20		/* alarm interrupt enable */
+#define RTC_UIE 0x10		/* update-finished interrupt enable */
+
+#define RTC_BATT_BAD 0x100	/* battery bad */
+
+/* some dummy definitions */
+#define RTC_SQWE 0x08		/* enable square-wave output */
+#define RTC_DM_BINARY 0x04	/* all time/date values are BCD if clear */
+#define RTC_24H 0x02		/* 24 hour mode - else hours bit 7 means pm */
+#define RTC_DST_EN 0x01	        /* auto switch DST - works f. USA only */
+
+
+/* constants for calculation */
+#define SECS_PER_HOUR   (60 * 60)
+#define SECS_PER_DAY    (SECS_PER_HOUR * 24)
+
+#define __isleap(year) \
+  ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
+
+
+/* How many days come before each month (0-12).  */
+static const unsigned short int __mon_yday[2][13] =
+{
+	/* Normal years.  */
+	{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
+	/* Leap years.  */
+	{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
+};
+
+static inline unsigned int get_rtc_time(struct rtc_time *wtime)
+{
+	/*
+	 * Only the values that we read from the RTC are set. We leave
+	 * tm_wday, tm_yday and tm_isdst untouched. Even though the
+	 * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated
+	 * by the RTC when initially set to a non-zero value.
+	 */
+	
+	struct pdc_tod tod_data;
+	long int days, rem, y;
+	const unsigned short int *ip;
+
+	if (pdc_tod_read(&tod_data) < 0)
+		return (RTC_24H | RTC_BATT_BAD);
+
+	
+	// most of the remainder of this function is:
+	//	Copyright (C) 1991, 1993, 1997, 1998 Free Software Foundation, Inc.
+	//	This was originally a part of the GNU C Library.
+	//      It is distributed under the GPL, and was swiped from offtime.c
+
+
+	days = tod_data.tod_sec / SECS_PER_DAY;
+	rem = tod_data.tod_sec % SECS_PER_DAY;
+
+	wtime->tm_hour = rem / SECS_PER_HOUR;
+	rem %= SECS_PER_HOUR;
+	wtime->tm_min = rem / 60;
+	wtime->tm_sec = rem % 60;
+
+	y = 1970;
+	
+#define DIV(a, b) ((a) / (b) - ((a) % (b) < 0))
+#define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400))
+
+	while (days < 0 || days >= (__isleap (y) ? 366 : 365))
+	{
+		/* Guess a corrected year, assuming 365 days per year.  */
+		long int yg = y + days / 365 - (days % 365 < 0);
+
+		/* Adjust DAYS and Y to match the guessed year.  */
+		days -= ((yg - y) * 365
+			 + LEAPS_THRU_END_OF (yg - 1)
+			 - LEAPS_THRU_END_OF (y - 1));
+		y = yg;
+	}
+	wtime->tm_year = y - 1900;
+#undef DIV
+#undef LEAPS_THRU_END_OF
+
+	ip = __mon_yday[__isleap(y)];
+	for (y = 11; days < (long int) ip[y]; --y)
+		continue;
+	days -= ip[y];
+	wtime->tm_mon = y;
+	wtime->tm_mday = days + 1;
+	
+	return (RTC_24H);
+}
+
+static inline int set_rtc_time(struct rtc_time *wtime)
+{
+	u_int32_t secs;
+
+	secs = mktime(wtime->tm_year + 1900, wtime->tm_mon + 1, wtime->tm_mday, 
+		      wtime->tm_hour, wtime->tm_min, wtime->tm_sec);
+
+	if (pdc_tod_set(secs, 0) < 0)
+		return -EINVAL;
+	else
+		return 0;
+}
+
+static inline unsigned int get_rtc_ss(void)
+{
+	return -EINVAL;
+}
+
+static inline int get_rtc_pll(struct rtc_pll_info *pll)
+{
+	return -EINVAL;
+}
+static inline int set_rtc_pll(struct rtc_pll_info *pll)
+{
+	return -EINVAL;
+}
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM__RTC_H */
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-parisc/scatterlist.h linux-2.4.21-pre6/include/asm-parisc/scatterlist.h
--- linux-2.4.20/include/asm-parisc/scatterlist.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-parisc/scatterlist.h	2003-03-26 23:49:50.000000000 +0000
@@ -23,7 +23,7 @@
 };
 
 #define sg_virt_addr(sg) (((sg)->address) ? ((sg)->address) : \
-		((sg)->page->virtual + (sg)->offset))
+		(page_address((sg)->page) + (sg)->offset))
 
 #define sg_dma_address(sg) ((sg)->iova)
 #define sg_dma_len(sg)     ((sg)->iova_length)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-parisc/spinlock.h linux-2.4.21-pre6/include/asm-parisc/spinlock.h
--- linux-2.4.20/include/asm-parisc/spinlock.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-parisc/spinlock.h	2003-03-26 23:49:25.000000000 +0000
@@ -1,35 +1,9 @@
 #ifndef __ASM_SPINLOCK_H
 #define __ASM_SPINLOCK_H
 
-#include <asm/system.h>
-
-/* Note that PA-RISC has to use `1' to mean unlocked and `0' to mean locked
- * since it only has load-and-zero.
- */
-
-#undef SPIN_LOCK_UNLOCKED
-#define SPIN_LOCK_UNLOCKED (spinlock_t) { 1 }
-
-#define spin_lock_init(x)	do { (x)->lock = 1; } while(0)
-
-#define spin_is_locked(x) ((x)->lock == 0)
-
-#define spin_unlock_wait(x)	do { barrier(); } while(((volatile spinlock_t *)(x))->lock == 0)
-
-#if 1
-#define spin_lock(x) do { \
-	while (__ldcw (&(x)->lock) == 0) \
-		while (((x)->lock) == 0) ; } while (0)
-
-#else
-#define spin_lock(x) \
-	do { while(__ldcw(&(x)->lock) == 0); } while(0)
-#endif
-	
-#define spin_unlock(x) \
-	do { (x)->lock = 1; } while(0)
-
-#define spin_trylock(x) (__ldcw(&(x)->lock) != 0)
+#include <asm/spinlock_t.h>		/* get spinlock primitives */
+#include <asm/psw.h>			/* local_* primitives need PSW_I */
+#include <asm/system_irqsave.h>		/* get local_* primitives */
 
 /*
  * Read-write spinlocks, allowing multiple readers
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-parisc/spinlock_t.h linux-2.4.21-pre6/include/asm-parisc/spinlock_t.h
--- linux-2.4.20/include/asm-parisc/spinlock_t.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-parisc/spinlock_t.h	2003-03-26 23:49:40.000000000 +0000
@@ -0,0 +1,59 @@
+#ifndef __PARISC_SPINLOCK_T_H
+#define __PARISC_SPINLOCK_T_H
+
+/* LDCW, the only atomic read-write operation PA-RISC has. *sigh*.
+ *
+ * Note that PA-RISC has to use `1' to mean unlocked and `0' to mean locked
+ * since it only has load-and-zero.
+ */
+#define __ldcw(a) ({ \
+	unsigned __ret; \
+	__asm__ __volatile__("ldcw 0(%1),%0" : "=r" (__ret) : "r" (a)); \
+	__ret; \
+})
+
+/*
+ * Your basic SMP spinlocks, allowing only a single CPU anywhere
+ */
+
+typedef struct {
+	volatile unsigned int __attribute__((aligned(16))) lock;
+#ifdef CONFIG_DEBUG_SPINLOCK
+	volatile unsigned long owner_pc;
+	volatile unsigned long owner_cpu;
+#endif
+} spinlock_t;
+
+#ifndef CONFIG_DEBUG_SPINLOCK
+#define SPIN_LOCK_UNLOCKED (spinlock_t) { 1 }
+
+/* Define 6 spinlock primitives that don't depend on anything else. */
+
+#define spin_lock_init(x)       do { (x)->lock = 1; } while(0)
+#define spin_is_locked(x)       ((x)->lock == 0)
+#define spin_trylock(x)		(__ldcw(&(x)->lock) != 0)
+#define spin_unlock(x)		do { (x)->lock = 1; } while(0)
+
+#define spin_unlock_wait(x)     do { barrier(); } while(((volatile spinlock_t *)(x))->lock == 0)
+
+#define spin_lock(x) do { \
+	while (__ldcw (&(x)->lock) == 0) \
+		while ((x)->lock == 0) ; \
+} while (0)
+
+#else
+
+#define SPIN_LOCK_UNLOCKED (spinlock_t) { 1, 0, 0 }
+
+/* Define 6 spinlock primitives that don't depend on anything else. */
+
+#define spin_lock_init(x)       do { (x)->lock = 1; (x)->owner_cpu = 0; (x)->owner_pc = 0; } while(0)
+#define spin_is_locked(x)       ((x)->lock == 0)
+void spin_lock(spinlock_t *lock);
+int spin_trylock(spinlock_t *lock);
+void spin_unlock(spinlock_t *lock);
+#define spin_unlock_wait(x)     do { barrier(); } while(((volatile spinlock_t *)(x))->lock == 0)
+
+#endif
+
+#endif /* __PARISC_SPINLOCK_T_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-parisc/system.h linux-2.4.21-pre6/include/asm-parisc/system.h
--- linux-2.4.20/include/asm-parisc/system.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-parisc/system.h	2003-03-26 23:48:59.000000000 +0000
@@ -3,6 +3,11 @@
 
 #include <linux/config.h>
 #include <asm/psw.h>
+#include <asm/system_irqsave.h>
+
+#ifdef CONFIG_SMP
+#include <asm/spinlock_t.h>
+#endif
 
 /* The program status word as bitfields.  */
 struct pa_psw {
@@ -51,22 +56,6 @@
 } while(0)
 
 
-
-/* interrupt control */
-#define __save_flags(x)	__asm__ __volatile__("ssm 0, %0" : "=r" (x) : : "memory")
-#define __restore_flags(x) __asm__ __volatile__("mtsm %0" : : "r" (x) : "memory")
-#define __cli()	__asm__ __volatile__("rsm %0,%%r0\n" : : "i" (PSW_I) : "memory" )
-#define __sti()	__asm__ __volatile__("ssm %0,%%r0\n" : : "i" (PSW_I) : "memory" )
-
-#define local_irq_save(x) \
-	__asm__ __volatile__("rsm %1,%0" : "=r" (x) :"i" (PSW_I) : "memory" )
-#define local_irq_set(x) \
-	__asm__ __volatile__("ssm %1,%0" : "=r" (x) :"i" (PSW_I) : "memory" )
-#define local_irq_restore(x) \
-	__asm__ __volatile__("mtsm %0" : : "r" (x) : "memory" )
-#define local_irq_disable() __cli()
-#define local_irq_enable()  __sti()
-
 #ifdef CONFIG_SMP
 extern void __global_cli(void);
 extern void __global_sti(void);
@@ -77,7 +66,7 @@
 #define sti() __global_sti()
 #define save_flags(x) ((x)=__global_save_flags())
 #define restore_flags(x) __global_restore_flags(x)
- 
+
 #else
 
 #define cli() __cli()
@@ -153,23 +142,4 @@
 
 #define set_mb(var, value) do { var = value; mb(); } while (0)
 
-
-/* LDCW, the only atomic read-write operation PA-RISC has. *sigh*.  */
-#define __ldcw(a) ({ \
-	unsigned __ret; \
-	__asm__ __volatile__("ldcw 0(%1),%0" : "=r" (__ret) : "r" (a)); \
-	__ret; \
-})
-
-
-#ifdef CONFIG_SMP
-/*
- * Your basic SMP spinlocks, allowing only a single CPU anywhere
- */
-
-typedef struct {
-	volatile unsigned int __attribute__((aligned(16))) lock;
-} spinlock_t;
-#endif
-
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-parisc/system_irqsave.h linux-2.4.21-pre6/include/asm-parisc/system_irqsave.h
--- linux-2.4.20/include/asm-parisc/system_irqsave.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-parisc/system_irqsave.h	2003-03-26 23:49:31.000000000 +0000
@@ -0,0 +1,17 @@
+#ifndef __PARISC_SYSTEM_IRQSAVE_H
+#define __PARISC_SYSTEM_IRQSAVE_H
+
+/* interrupt control */
+#define __save_flags(x)	__asm__ __volatile__("ssm 0, %0" : "=r" (x) : : "memory")
+#define __restore_flags(x) __asm__ __volatile__("mtsm %0" : : "r" (x) : "memory")
+#define __cli()	__asm__ __volatile__("rsm %0,%%r0\n" : : "i" (PSW_I) : "memory" )
+#define __sti()	__asm__ __volatile__("ssm %0,%%r0\n" : : "i" (PSW_I) : "memory" )
+
+#define local_irq_save(x) \
+	__asm__ __volatile__("rsm %1,%0" : "=r" (x) :"i" (PSW_I) : "memory" )
+#define local_irq_restore(x) \
+	__asm__ __volatile__("mtsm %0" : : "r" (x) : "memory" )
+#define local_irq_disable() __cli()
+#define local_irq_enable()  __sti()
+
+#endif /* __PARISC_SYSTEM_IRQSAVE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-parisc/uaccess.h linux-2.4.21-pre6/include/asm-parisc/uaccess.h
--- linux-2.4.20/include/asm-parisc/uaccess.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-parisc/uaccess.h	2003-03-26 23:49:19.000000000 +0000
@@ -37,8 +37,8 @@
 #if BITS_PER_LONG == 32
 #define LDD_KERNEL(ptr)		BUG()
 #define LDD_USER(ptr)		BUG()
-#define STD_KERNEL(x, ptr)	BUG()
-#define STD_USER(x, ptr)	BUG()
+#define STD_KERNEL(x, ptr) __put_kernel_asm64(x,ptr)
+#define STD_USER(x, ptr) __put_user_asm64(x,ptr)
 #else
 #define LDD_KERNEL(ptr) __get_kernel_asm("ldd",ptr)
 #define LDD_USER(ptr) __get_user_asm("ldd",ptr)
@@ -210,6 +210,43 @@
 		 "\t.previous"                              \
 		: "=r"(__pu_err)                            \
 		: "r"(ptr), "r"(x), "0"(__pu_err))
+
+static inline void __put_kernel_asm64(u64 x, void *ptr)
+{
+	u32 hi = x>>32;
+	u32 lo = x&0xffffffff;
+	__asm__ __volatile__ (
+		"\n1:\tstw %1,0(%0)\n"
+		"\n2:\tstw %2,4(%0)\n"
+		"3:\n"
+		"\t.section __ex_table,\"a\"\n"
+		 "\t.word\t1b\n"
+		 "\t.word\t(3b-1b)+1\n"
+		 "\t.word\t2b\n"
+		 "\t.word\t(3b-2b)+1\n"
+		 "\t.previous"
+		: : "r"(ptr), "r"(hi), "r"(lo));
+
+}
+
+static inline void __put_user_asm64(u64 x, void *ptr)
+{
+	u32 hi = x>>32;
+	u32 lo = x&0xffffffff;
+	__asm__ __volatile__ (
+		"\n1:\tstw %1,0(%%sr3,%0)\n"
+		"\n2:\tstw %2,4(%%sr3,%0)\n"
+		"3:\n"
+		"\t.section __ex_table,\"a\"\n"
+		 "\t.word\t1b\n"
+		 "\t.word\t(3b-1b)+1\n"
+		 "\t.word\t2b\n"
+		 "\t.word\t(3b-2b)+1\n"
+		 "\t.previous"
+		: : "r"(ptr), "r"(hi), "r"(lo));
+
+}
+
 #endif
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-parisc/unistd.h linux-2.4.21-pre6/include/asm-parisc/unistd.h
--- linux-2.4.20/include/asm-parisc/unistd.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-parisc/unistd.h	2003-03-26 23:48:57.000000000 +0000
@@ -700,8 +700,9 @@
 #define __NR_acl_set            (__NR_Linux + 205)
 #define __NR_gettid             (__NR_Linux + 206)
 #define __NR_readahead          (__NR_Linux + 207)
+#define __NR_tkill              (__NR_Linux + 208)
 
-#define __NR_Linux_syscalls     207
+#define __NR_Linux_syscalls     208
 
 #define HPUX_GATEWAY_ADDR       0xC0000004
 #define LINUX_GATEWAY_ADDR      0x100
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/8xx_immap.h linux-2.4.21-pre6/include/asm-ppc/8xx_immap.h
--- linux-2.4.20/include/asm-ppc/8xx_immap.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/8xx_immap.h	2003-03-26 23:49:34.000000000 +0000
@@ -1,8 +1,4 @@
 /*
- * BK Id: SCCS/s.8xx_immap.h 1.5 05/17/01 18:14:24 cort
- */
-
-/*
  * MPC8xx Internal Memory Map
  * Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/a.out.h linux-2.4.21-pre6/include/asm-ppc/a.out.h
--- linux-2.4.20/include/asm-ppc/a.out.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/a.out.h	2003-03-26 23:49:39.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.a.out.h 1.5 05/17/01 18:14:24 cort
- */
 #ifndef __PPC_A_OUT_H__
 #define __PPC_A_OUT_H__
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/amigahw.h linux-2.4.21-pre6/include/asm-ppc/amigahw.h
--- linux-2.4.20/include/asm-ppc/amigahw.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/amigahw.h	2003-03-26 23:48:57.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.amigahw.h 1.5 05/17/01 18:14:24 cort
- */
 #ifdef __KERNEL__
 #ifndef __ASMPPC_AMIGAHW_H
 #define __ASMPPC_AMIGAHW_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/amigaints.h linux-2.4.21-pre6/include/asm-ppc/amigaints.h
--- linux-2.4.20/include/asm-ppc/amigaints.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/amigaints.h	2003-03-26 23:48:57.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
 ** amigaints.h -- Amiga Linux interrupt handling structs and prototypes
 **
 ** Copyright 1992 by Greg Harp
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/amigappc.h linux-2.4.21-pre6/include/asm-ppc/amigappc.h
--- linux-2.4.20/include/asm-ppc/amigappc.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/amigappc.h	2003-03-26 23:49:09.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.amigappc.h 1.5 05/17/01 18:14:24 cort
- */
-/*
 ** asm-m68k/amigappc.h -- This header defines some values and pointers for
 **                        the Phase 5 PowerUp card.
 **
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/amigayle.h linux-2.4.21-pre6/include/asm-ppc/amigayle.h
--- linux-2.4.20/include/asm-ppc/amigayle.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/amigayle.h	2003-03-26 23:49:18.000000000 +0000
@@ -1,4 +1 @@
-/*
- * BK Id: SCCS/s.amigayle.h 1.5 05/17/01 18:14:24 cort
- */
 #include <asm-m68k/amigayle.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/amipcmcia.h linux-2.4.21-pre6/include/asm-ppc/amipcmcia.h
--- linux-2.4.20/include/asm-ppc/amipcmcia.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/amipcmcia.h	2003-03-26 23:49:07.000000000 +0000
@@ -1,4 +1 @@
-/*
- * BK Id: SCCS/s.amipcmcia.h 1.5 05/17/01 18:14:24 cort
- */
 #include <asm-m68k/amipcmcia.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/atomic.h linux-2.4.21-pre6/include/asm-ppc/atomic.h
--- linux-2.4.20/include/asm-ppc/atomic.h	2001-11-03 01:43:54.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/atomic.h	2003-03-26 23:49:19.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.atomic.h 1.15 10/28/01 10:37:22 trini
- */
-/*
  * PowerPC atomic operations
  */
 
@@ -26,14 +23,24 @@
 #define SMP_ISYNC
 #endif
 
+/* Erratum #77 on the 405 means we need a sync or dcbt before every stwcx.
+ * The old ATOMIC_SYNC_FIX covered some but not all of this.
+ */
+#ifdef CONFIG_IBM405_ERR77
+#define PPC405_ERR77(ra,rb)	"dcbt " #ra "," #rb ";"
+#else
+#define PPC405_ERR77(ra,rb)
+#endif
+
 static __inline__ void atomic_add(int a, atomic_t *v)
 {
 	int t;
 
 	__asm__ __volatile__(
 "1:	lwarx	%0,0,%3		# atomic_add\n\
-	add	%0,%2,%0\n\
-	stwcx.	%0,0,%3\n\
+	add	%0,%2,%0\n"
+	PPC405_ERR77(0,%3)
+"	stwcx.	%0,0,%3 \n\
 	bne-	1b"
 	: "=&r" (t), "=m" (v->counter)
 	: "r" (a), "r" (&v->counter), "m" (v->counter)
@@ -46,8 +53,9 @@
 
 	__asm__ __volatile__(
 "1:	lwarx	%0,0,%2		# atomic_add_return\n\
-	add	%0,%1,%0\n\
-	stwcx.	%0,0,%2\n\
+	add	%0,%1,%0\n"
+	PPC405_ERR77(0,%2)
+"	stwcx.	%0,0,%2 \n\
 	bne-	1b"
 	SMP_ISYNC
 	: "=&r" (t)
@@ -63,8 +71,9 @@
 
 	__asm__ __volatile__(
 "1:	lwarx	%0,0,%3		# atomic_sub\n\
-	subf	%0,%2,%0\n\
-	stwcx.	%0,0,%3\n\
+	subf	%0,%2,%0\n"
+	PPC405_ERR77(0,%3)
+"	stwcx.	%0,0,%3 \n\
 	bne-	1b"
 	: "=&r" (t), "=m" (v->counter)
 	: "r" (a), "r" (&v->counter), "m" (v->counter)
@@ -77,8 +86,9 @@
 
 	__asm__ __volatile__(
 "1:	lwarx	%0,0,%2		# atomic_sub_return\n\
-	subf	%0,%1,%0\n\
-	stwcx.	%0,0,%2\n\
+	subf	%0,%1,%0\n"
+	PPC405_ERR77(0,%2)
+"	stwcx.	%0,0,%2 \n\
 	bne-	1b"
 	SMP_ISYNC
 	: "=&r" (t)
@@ -94,8 +104,9 @@
 
 	__asm__ __volatile__(
 "1:	lwarx	%0,0,%2		# atomic_inc\n\
-	addic	%0,%0,1\n\
-	stwcx.	%0,0,%2\n\
+	addic	%0,%0,1\n"
+	PPC405_ERR77(0,%2)
+"	stwcx.	%0,0,%2 \n\
 	bne-	1b"
 	: "=&r" (t), "=m" (v->counter)
 	: "r" (&v->counter), "m" (v->counter)
@@ -108,8 +119,9 @@
 
 	__asm__ __volatile__(
 "1:	lwarx	%0,0,%1		# atomic_inc_return\n\
-	addic	%0,%0,1\n\
-	stwcx.	%0,0,%1\n\
+	addic	%0,%0,1\n"
+	PPC405_ERR77(0,%1)
+"	stwcx.	%0,0,%1 \n\
 	bne-	1b"
 	SMP_ISYNC
 	: "=&r" (t)
@@ -125,8 +137,9 @@
 
 	__asm__ __volatile__(
 "1:	lwarx	%0,0,%2		# atomic_dec\n\
-	addic	%0,%0,-1\n\
-	stwcx.	%0,0,%2\n\
+	addic	%0,%0,-1\n"
+	PPC405_ERR77(0,%2)\
+"	stwcx.	%0,0,%2\n\
 	bne-	1b"
 	: "=&r" (t), "=m" (v->counter)
 	: "r" (&v->counter), "m" (v->counter)
@@ -139,8 +152,9 @@
 
 	__asm__ __volatile__(
 "1:	lwarx	%0,0,%1		# atomic_dec_return\n\
-	addic	%0,%0,-1\n\
-	stwcx.	%0,0,%1\n\
+	addic	%0,%0,-1\n"
+	PPC405_ERR77(0,%1)
+"	stwcx.	%0,0,%1\n\
 	bne-	1b"
 	SMP_ISYNC
 	: "=&r" (t)
@@ -164,8 +178,9 @@
 	__asm__ __volatile__(
 "1:	lwarx	%0,0,%1		# atomic_dec_if_positive\n\
 	addic.	%0,%0,-1\n\
-	blt-	2f\n\
-	stwcx.	%0,0,%1\n\
+	blt-	2f\n"
+	PPC405_ERR77(0,%1)
+"	stwcx.	%0,0,%1\n\
 	bne-	1b"
 	SMP_ISYNC
 	"\n\
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/backlight.h linux-2.4.21-pre6/include/asm-ppc/backlight.h
--- linux-2.4.20/include/asm-ppc/backlight.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/backlight.h	2003-03-26 23:49:29.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.backlight.h 1.5 05/17/01 18:14:24 cort
- */
-/*
  * Routines for handling backlight control on PowerBooks
  * 
  * For now, implementation resides in arch/ppc/kernel/pmac_support.c
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/bitops.h linux-2.4.21-pre6/include/asm-ppc/bitops.h
--- linux-2.4.20/include/asm-ppc/bitops.h	2001-06-12 02:15:27.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/bitops.h	2003-03-26 23:49:39.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.bitops.h 1.9 05/26/01 14:48:14 paulus
- */
-/*
  * bitops.h: Bit string operations on the ppc
  */
 
@@ -11,6 +8,7 @@
 
 #include <linux/config.h>
 #include <asm/byteorder.h>
+#include <asm/atomic.h>
 
 /*
  * The test_and_*_bit operations are taken to imply a memory barrier
@@ -36,8 +34,9 @@
 	
 	__asm__ __volatile__("\n\
 1:	lwarx	%0,0,%3 \n\
-	or	%0,%0,%2 \n\
-	stwcx.	%0,0,%3 \n\
+	or	%0,%0,%2 \n"
+	PPC405_ERR77(0,%3)
+"	stwcx.	%0,0,%3 \n\
 	bne-	1b"
 	: "=&r" (old), "=m" (*p)
 	: "r" (mask), "r" (p), "m" (*p)
@@ -69,8 +68,9 @@
 
 	__asm__ __volatile__("\n\
 1:	lwarx	%0,0,%3 \n\
-	andc	%0,%0,%2 \n\
-	stwcx.	%0,0,%3 \n\
+	andc	%0,%0,%2 \n"
+	PPC405_ERR77(0,%3)
+"	stwcx.	%0,0,%3 \n\
 	bne-	1b"
 	: "=&r" (old), "=m" (*p)
 	: "r" (mask), "r" (p), "m" (*p)
@@ -96,8 +96,9 @@
 
 	__asm__ __volatile__("\n\
 1:	lwarx	%0,0,%3 \n\
-	xor	%0,%0,%2 \n\
-	stwcx.	%0,0,%3 \n\
+	xor	%0,%0,%2 \n"
+	PPC405_ERR77(0,%3)
+"	stwcx.	%0,0,%3 \n\
 	bne-	1b"
 	: "=&r" (old), "=m" (*p)
 	: "r" (mask), "r" (p), "m" (*p)
@@ -126,8 +127,9 @@
 
 	__asm__ __volatile__(SMP_WMB "\n\
 1:	lwarx	%0,0,%4 \n\
-	or	%1,%0,%3 \n\
-	stwcx.	%1,0,%4 \n\
+	or	%1,%0,%3 \n"
+	PPC405_ERR77(0,%4)
+"	stwcx.	%1,0,%4 \n\
 	bne	1b"
 	SMP_MB
 	: "=&r" (old), "=&r" (t), "=m" (*p)
@@ -158,8 +160,9 @@
 
 	__asm__ __volatile__(SMP_WMB "\n\
 1:	lwarx	%0,0,%4 \n\
-	andc	%1,%0,%3 \n\
-	stwcx.	%1,0,%4 \n\
+	andc	%1,%0,%3 \n"
+	PPC405_ERR77(0,%4)
+"	stwcx.	%1,0,%4 \n\
 	bne	1b"
 	SMP_MB
 	: "=&r" (old), "=&r" (t), "=m" (*p)
@@ -190,8 +193,9 @@
 
 	__asm__ __volatile__(SMP_WMB "\n\
 1:	lwarx	%0,0,%4 \n\
-	xor	%1,%0,%3 \n\
-	stwcx.	%1,0,%4 \n\
+	xor	%1,%0,%3 \n"
+	PPC405_ERR77(0,%4)
+"	stwcx.	%1,0,%4 \n\
 	bne	1b"
 	SMP_MB
 	: "=&r" (old), "=&r" (t), "=m" (*p)
@@ -237,8 +241,6 @@
 	return __ilog2(x & -x);
 }
 
-#ifdef __KERNEL__
-
 /*
  * ffs: find first bit set. This is defined the same way as
  * the libc and compiler builtin ffs routines, therefore
@@ -258,8 +260,6 @@
 #define hweight16(x) generic_hweight16(x)
 #define hweight8(x) generic_hweight8(x)
 
-#endif /* __KERNEL__ */
-
 /*
  * This implementation of find_{first,next}_zero_bit was stolen from
  * Linus' asm-alpha/bitops.h.
@@ -306,8 +306,6 @@
 }
 
 
-#ifdef __KERNEL__
-
 #define ext2_set_bit(nr, addr)		__test_and_set_bit((nr) ^ 0x18, addr)
 #define ext2_clear_bit(nr, addr)	__test_and_clear_bit((nr) ^ 0x18, addr)
 
@@ -371,7 +369,5 @@
 #define minix_test_bit(nr,addr) ext2_test_bit(nr,addr)
 #define minix_find_first_zero_bit(addr,size) ext2_find_first_zero_bit(addr,size)
 
-#endif	/* __KERNEL__ */
-
 #endif /* _PPC_BITOPS_H */
 #endif /* __KERNEL__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/bootinfo.h linux-2.4.21-pre6/include/asm-ppc/bootinfo.h
--- linux-2.4.20/include/asm-ppc/bootinfo.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/bootinfo.h	2003-03-26 23:49:30.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Non-machine dependent bootinfo structure.  Basic idea
  * borrowed from the m68k.
  *
@@ -32,6 +29,7 @@
 #define BI_SYSMAP		0x1015
 #define BI_MACHTYPE		0x1016
 #define BI_MEMSIZE		0x1017
+#define BI_BOARD_INFO		0x1018
 
 extern struct bi_record *find_bootinfo(void);
 extern void parse_bootinfo(struct bi_record *rec);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/bootx.h linux-2.4.21-pre6/include/asm-ppc/bootx.h
--- linux-2.4.20/include/asm-ppc/bootx.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/bootx.h	2003-03-26 23:49:25.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.bootx.h 1.5 05/17/01 18:14:24 cort
- */
-/*
  * This file describes the structure passed from the BootX application
  * (for MacOS) when it is used to boot Linux.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/btext.h linux-2.4.21-pre6/include/asm-ppc/btext.h
--- linux-2.4.20/include/asm-ppc/btext.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/btext.h	2003-03-26 23:49:30.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Definitions for using the procedures in btext.c.
  *
  * Benjamin Herrenschmidt <benh@kernel.crashing.org>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/bugs.h linux-2.4.21-pre6/include/asm-ppc/bugs.h
--- linux-2.4.20/include/asm-ppc/bugs.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/bugs.h	2003-03-26 23:49:34.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.bugs.h 1.5 05/17/01 18:14:24 cort
- */
-/*
  * This file is included by 'init/main.c'
  */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/byteorder.h linux-2.4.21-pre6/include/asm-ppc/byteorder.h
--- linux-2.4.20/include/asm-ppc/byteorder.h	2001-11-03 01:43:54.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/byteorder.h	2003-03-26 23:49:35.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.byteorder.h 1.8 10/11/01 13:02:49 trini
- */
 #ifndef _PPC_BYTEORDER_H
 #define _PPC_BYTEORDER_H
 
@@ -35,17 +32,29 @@
 	__asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*addr) : "r" (val), "r" (addr));
 }
 
-/* alas, egcs sounds like it has a bug in this code that doesn't use the
-   inline asm correctly, and can cause file corruption. Until I hear that
-   it's fixed, I can live without the extra speed. I hope. */
-#if 0
+extern __inline__ unsigned long long ld_le64(const volatile unsigned long long *addr)
+{
+	unsigned char *taddr = (unsigned char *) addr;
+	unsigned long long val;
+
+	__asm__ __volatile__ ("lwbrx %L0,0,%1" : "=r" (val) : "r" (taddr),   "m" (*addr));
+	__asm__ __volatile__ ("lwbrx  %0,0,%1" : "=r" (val) : "r" (taddr+4), "m" (*addr), "0" (val));
+	return val;
+}
+
+extern __inline__ void st_le64(volatile unsigned long long *addr, const unsigned long long val)
+{
+	unsigned char *taddr = (unsigned char *) addr;
+
+	__asm__ __volatile__ ("stwbrx %L1,0,%2" : "=m" (*addr) : "r" (val), "r" (taddr));
+	__asm__ __volatile__ ("stwbrx  %1,0,%2" : "=m" (*addr) : "r" (val), "r" (taddr+4));
+}
+
 static __inline__ __const__ __u16 ___arch__swab16(__u16 value)
 {
 	__u16 result;
 
-	__asm__("rlwimi %0,%1,8,16,23"
-	    : "=r" (result)
-	    : "r" (value), "0" (value >> 8));
+	__asm__("rlwimi %0,%2,8,16,23" : "=&r" (result) : "0" (value >> 8), "r" (value));
 	return result;
 }
 
@@ -53,24 +62,24 @@
 {
 	__u32 result;
 
-	__asm__("rlwimi %0,%1,24,16,23\n\t"
-	    "rlwimi %0,%1,8,8,15\n\t"
-	    "rlwimi %0,%1,24,0,7"
-	    : "=r" (result)
-	    : "r" (value), "0" (value >> 24));
+	__asm__("rlwimi %0,%2,24,16,23" : "=&r" (result) : "0" (value>>24), "r" (value));
+	__asm__("rlwimi %0,%2,8,8,15"   : "=&r" (result) : "0" (result),    "r" (value));
+	__asm__("rlwimi %0,%2,24,0,7"   : "=&r" (result) : "0" (result),    "r" (value));
+
 	return result;
 }
 #define __arch__swab32(x) ___arch__swab32(x)
 #define __arch__swab16(x) ___arch__swab16(x)
-#endif /* 0 */
 
 /* The same, but returns converted value from the location pointer by addr. */
 #define __arch__swab16p(addr) ld_le16(addr)
 #define __arch__swab32p(addr) ld_le32(addr)
+#define __arch__swab64p(addr) ld_le64(addr)
 
 /* The same, but do the conversion in situ, ie. put the value back to addr. */
 #define __arch__swab16s(addr) st_le16(addr,*addr)
 #define __arch__swab32s(addr) st_le32(addr,*addr)
+#define __arch__swab64s(addr) st_le64(addr,*addr)
 
 #endif /* __KERNEL__ */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/cache.h linux-2.4.21-pre6/include/asm-ppc/cache.h
--- linux-2.4.20/include/asm-ppc/cache.h	2001-11-03 01:43:54.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/cache.h	2003-03-26 23:49:55.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.cache.h 1.10 10/18/01 15:02:09 trini
- */
-/*
  * include/asm-ppc/cache.h
  */
 #ifdef __KERNEL__
@@ -15,15 +12,15 @@
 #if defined(CONFIG_8xx) || defined(CONFIG_403GCX)
 #define	L1_CACHE_LINE_SIZE	16
 #define LG_L1_CACHE_LINE_SIZE	4
-#define MAX_L1_COPY_PREFETCH	1
+#define MAX_COPY_PREFETCH	1
 #elif defined(CONFIG_PPC64BRIDGE)
 #define L1_CACHE_LINE_SIZE	128
 #define LG_L1_CACHE_LINE_SIZE	7
-#define MAX_L1_COPY_PREFETCH	1
+#define MAX_COPY_PREFETCH	1
 #else
 #define	L1_CACHE_LINE_SIZE  32
 #define LG_L1_CACHE_LINE_SIZE	5
-#define MAX_L1_COPY_PREFETCH	4
+#define MAX_COPY_PREFETCH	4
 #endif
 
 #define	L1_CACHE_BYTES L1_CACHE_LINE_SIZE
@@ -40,9 +37,10 @@
 		 __section__(".data.cacheline_aligned")))
 #endif
 
-#if defined(__KERNEL__) && !defined(__ASSEMBLY__)
+#ifndef __ASSEMBLY__
 extern void flush_dcache_range(unsigned long start, unsigned long stop);
-
+extern void invalidate_dcache_range(unsigned long start, unsigned long stop);
+extern void clean_dcache_range(unsigned long start, unsigned long stop);
 #endif /* __ASSEMBLY__ */
 
 /* prep registers for L2 */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/checksum.h linux-2.4.21-pre6/include/asm-ppc/checksum.h
--- linux-2.4.20/include/asm-ppc/checksum.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/checksum.h	2003-03-26 23:49:21.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.checksum.h 1.8 05/17/01 18:14:24 cort
- */
 #ifdef __KERNEL__
 #ifndef _PPC_CHECKSUM_H
 #define _PPC_CHECKSUM_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/commproc.h linux-2.4.21-pre6/include/asm-ppc/commproc.h
--- linux-2.4.20/include/asm-ppc/commproc.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/commproc.h	2003-03-26 23:49:40.000000000 +0000
@@ -1,8 +1,4 @@
 /*
- * BK Id: SCCS/s.commproc.h 1.16 09/27/01 12:41:09 trini
- */
-
-/*
  * MPC8xx Communication Processor Module.
  * Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
  *
@@ -796,5 +792,6 @@
 extern void cpm_install_handler(int vec, 
 		void (*handler)(void *, struct pt_regs *regs), void *dev_id);
 extern void cpm_free_handler(int vec);
+extern const char *cpm_int_name[];
 
 #endif /* __CPM_8XX__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/cpm_8260.h linux-2.4.21-pre6/include/asm-ppc/cpm_8260.h
--- linux-2.4.20/include/asm-ppc/cpm_8260.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/cpm_8260.h	2003-03-26 23:49:35.000000000 +0000
@@ -1,8 +1,4 @@
 /*
- * BK Id: SCCS/s.cpm_8260.h 1.7 05/17/01 18:14:24 cort
- */
-
-/*
  * MPC8260 Communication Processor Module.
  * Copyright (c) 1999 Dan Malek (dmalek@jlc.net)
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/cputable.h linux-2.4.21-pre6/include/asm-ppc/cputable.h
--- linux-2.4.20/include/asm-ppc/cputable.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/cputable.h	2003-03-26 23:49:34.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  include/asm-ppc/cputable.h
  *
  *  Copyright (C) 2001 Ben. Herrenschmidt (benh@kernel.crashing.org)
@@ -76,6 +73,7 @@
 #define CPU_FTR_L3_DISABLE_NAP		0x00001000
 #define CPU_FTR_NAP_DISABLE_L2_PR	0x00002000
 #define CPU_FTR_DUAL_PLL_750FX		0x00004000
+#define CPU_FTR_NO_DPM			0x00008000
 
 #ifdef __ASSEMBLY__
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/current.h linux-2.4.21-pre6/include/asm-ppc/current.h
--- linux-2.4.20/include/asm-ppc/current.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/current.h	2003-03-26 23:49:07.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.current.h 1.5 05/17/01 18:14:24 cort
- */
 #ifdef __KERNEL__
 #ifndef _PPC_CURRENT_H
 #define _PPC_CURRENT_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/dbdma.h linux-2.4.21-pre6/include/asm-ppc/dbdma.h
--- linux-2.4.20/include/asm-ppc/dbdma.h	2002-02-25 19:38:12.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/dbdma.h	2003-03-26 23:49:55.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.dbdma.h 1.8 12/01/01 20:09:11 benh
- */
-/*
  * Definitions for using the Apple Descriptor-Based DMA controller
  * in Power Macintosh computers.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/delay.h linux-2.4.21-pre6/include/asm-ppc/delay.h
--- linux-2.4.20/include/asm-ppc/delay.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/delay.h	2003-03-26 23:49:50.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.delay.h 1.7 05/17/01 18:14:24 cort
- */
 #ifdef __KERNEL__
 #ifndef _PPC_DELAY_H
 #define _PPC_DELAY_H
@@ -18,36 +15,52 @@
 
 extern unsigned long loops_per_jiffy;
 
-/* maximum permitted argument to udelay */
-#define __MAX_UDELAY	1000000
-
 extern void __delay(unsigned int loops);
 
-/* N.B. the `secs' parameter here is a fixed-point number with
-   the binary point to the left of the most-significant bit. */
-extern __inline__ void __const_udelay(unsigned int secs)
+/*
+ * Note that 19 * 226 == 4294 ==~ 2^32 / 10^6, so
+ * loops = (4294 * usecs * loops_per_jiffy * HZ) / 2^32.
+ *
+ * The mulhwu instruction gives us loops = (a * b) / 2^32.
+ * We choose a = usecs * 19 * HZ and b = loops_per_jiffy * 226
+ * because this lets us support a wide range of HZ and
+ * loops_per_jiffy values without either a or b overflowing 2^32.
+ * Thus we need usecs * HZ <= (2^32 - 1) / 19 = 226050910 and
+ * loops_per_jiffy <= (2^32 - 1) / 226 = 19004280
+ * (which corresponds to ~3800 bogomips at HZ = 100).
+ *  -- paulus
+ */
+#define __MAX_UDELAY	(226050910/HZ)	/* maximum udelay argument */
+#define __MAX_NDELAY	(4294967295/HZ)	/* maximum ndelay argument */
+
+extern __inline__ void __udelay(unsigned int x)
 {
 	unsigned int loops;
 
 	__asm__("mulhwu %0,%1,%2" : "=r" (loops) :
-		"r" (secs), "r" (loops_per_jiffy));
-	__delay(loops * HZ);
+		"r" (x), "r" (loops_per_jiffy * 226));
+	__delay(loops);
 }
 
-/*
- * note that 4294 == 2^32 / 10^6, multiplying by 4294 converts from
- * microseconds to a 32-bit fixed-point number of seconds.
- */
-extern __inline__ void __udelay(unsigned int usecs)
+extern __inline__ void __ndelay(unsigned int x)
 {
-	__const_udelay(usecs * 4294);
+	unsigned int loops;
+
+	__asm__("mulhwu %0,%1,%2" : "=r" (loops) :
+		"r" (x), "r" (loops_per_jiffy * 5));
+	__delay(loops);
 }
 
 extern void __bad_udelay(void);		/* deliberately undefined */
+extern void __bad_ndelay(void);		/* deliberately undefined */
 
 #define udelay(n) (__builtin_constant_p(n)? \
-		   ((n) > __MAX_UDELAY? __bad_udelay(): __const_udelay((n) * 4294u)) : \
-		   __udelay(n))
+	((n) > __MAX_UDELAY? __bad_udelay(): __udelay((n) * (19 * HZ))) : \
+	__udelay((n) * (19 * HZ)))
+
+#define ndelay(n) (__builtin_constant_p(n)? \
+	((n) > __MAX_NDELAY? __bad_ndelay(): __ndelay((n) * HZ)) : \
+	__ndelay((n) * HZ))
 
 #endif /* defined(_PPC_DELAY_H) */
 #endif /* __KERNEL__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/div64.h linux-2.4.21-pre6/include/asm-ppc/div64.h
--- linux-2.4.20/include/asm-ppc/div64.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/div64.h	2003-03-26 23:49:55.000000000 +0000
@@ -1,13 +1,23 @@
-/*
- * BK Id: SCCS/s.div64.h 1.5 05/17/01 18:14:24 cort
- */
 #ifndef __PPC_DIV64
 #define __PPC_DIV64
 
-#define do_div(n,base) ({ \
-int __res; \
-__res = ((unsigned long) n) % (unsigned) base; \
-n = ((unsigned long) n) / (unsigned) base; \
-__res; })
+#include <linux/types.h>
+
+extern u32 __div64_32(u64 *dividend, u32 div);
+
+#define do_div(n, div)	({			\
+	u64 __n = (n);				\
+	u32 __d = (div);			\
+	u32 __q, __r;				\
+	if ((__n >> 32) == 0) {			\
+		__q = (u32)__n / __d;		\
+		__r = (u32)__n - __q * __d;	\
+		(n) = __q;			\
+	} else {				\
+		__r = __div64_32(&__n, __d);	\
+		(n) = __n;			\
+	}					\
+	__r;					\
+})
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/dma.h linux-2.4.21-pre6/include/asm-ppc/dma.h
--- linux-2.4.20/include/asm-ppc/dma.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/dma.h	2003-03-26 23:49:54.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.dma.h 1.8 05/17/01 18:14:24 cort
- */
-/*
  * linux/include/asm/dma.h: Defines for using and allocating dma channels.
  * Written by Hennus Bergman, 1992.
  * High DMA channel support & info by Hannu Savolainen
@@ -27,7 +24,7 @@
  * not valid for the PReP platform.  Take what you read
  * with a grain of salt.
  */
- 
+
 
 #ifndef _ASM_DMA_H
 #define _ASM_DMA_H
@@ -38,13 +35,12 @@
 
 /* The maximum address that we can perform a DMA transfer to on this platform */
 /* Doesn't really apply... */
-#define MAX_DMA_ADDRESS      0xFFFFFFFF
+#define MAX_DMA_ADDRESS		0xFFFFFFFF
 
 /* in arch/ppc/kernel/setup.c -- Cort */
 extern unsigned long DMA_MODE_WRITE, DMA_MODE_READ;
 extern unsigned long ISA_DMA_THRESHOLD;
 
-
 #ifdef HAVE_REALLY_SLOW_DMA_CONTROLLER
 #define dma_outb	outb_p
 #else
@@ -69,7 +65,7 @@
  *  - page registers for 5-7 don't use data bit 0, represent 128K pages
  *  - page registers for 0-3 use bit 0, represent 64K pages
  *
- * On PReP, DMA transfers are limited to the lower 16MB of _physical_ memory.  
+ * On PReP, DMA transfers are limited to the lower 16MB of _physical_ memory.
  * On CHRP, the W83C553F (and VLSI Tollgate?) support full 32 bit addressing.
  * Note that addresses loaded into registers must be _physical_ addresses,
  * not logical addresses (which may differ if paging is active).
@@ -80,7 +76,7 @@
  *    |  ...  |   |  ... |   |  ... |
  *    |  ...  |   |  ... |   |  ... |
  *    |  ...  |   |  ... |   |  ... |
- *   P7  ...  P0  A7 ... A0  A7 ... A0   
+ *   P7  ...  P0  A7 ... A0  A7 ... A0
  * |    Page    | Addr MSB | Addr LSB |   (DMA registers)
  *
  *  Address mapping for channels 5-7:
@@ -89,7 +85,7 @@
  *    |  ...  |   \   \   ... \  \  \  ... \  \
  *    |  ...  |    \   \   ... \  \  \  ... \  (not used)
  *    |  ...  |     \   \   ... \  \  \  ... \
- *   P7  ...  P1 (0) A7 A6  ... A0 A7 A6 ... A0   
+ *   P7  ...  P1 (0) A7 A6  ... A0 A7 A6 ... A0
  * |      Page      |  Addr MSB   |  Addr LSB  |   (DMA registers)
  *
  * Again, channels 5-7 transfer _physical_ words (16 bits), so addresses
@@ -98,23 +94,15 @@
  *
  * Transfer count (_not # bytes_) is limited to 64K, represented as actual
  * count - 1 : 64K => 0xFFFF, 1 => 0x0000.  Thus, count is always 1 or more,
- * and up to 128K bytes may be transferred on channels 5-7 in one operation. 
+ * and up to 128K bytes may be transferred on channels 5-7 in one operation.
  *
  */
 
-/* used in nasty hack for sound - see prep_setup_arch() -- Cort */
+/* see prep_setup_arch() for detailed informations */
+#if defined(CONFIG_SOUND_CS4232) && defined(CONFIG_ALL_PPC)
 extern long ppc_cs4232_dma, ppc_cs4232_dma2;
-#if defined(CONFIG_CS4232)
-#if defined(CONFIG_ALL_PPC)
 #define SND_DMA1 ppc_cs4232_dma
 #define SND_DMA2 ppc_cs4232_dma2
-#else /* !CONFIG_ALL_PPC */
-#define SND_DMA1 -1
-#define SND_DMA2 -1
-#endif /* CONFIG_ALL_PPC */
-#elif defined(CONFIG_MSS)
-#define SND_DMA1 CONFIG_MSS_DMA
-#define SND_DMA2 CONFIG_MSS_DMA2
 #else
 #define SND_DMA1 -1
 #define SND_DMA2 -1
@@ -127,67 +115,67 @@
 /* DMA controller registers */
 #define DMA1_CMD_REG		0x08	/* command register (w) */
 #define DMA1_STAT_REG		0x08	/* status register (r) */
-#define DMA1_REQ_REG            0x09    /* request register (w) */
+#define DMA1_REQ_REG		0x09	/* request register (w) */
 #define DMA1_MASK_REG		0x0A	/* single-channel mask (w) */
 #define DMA1_MODE_REG		0x0B	/* mode register (w) */
 #define DMA1_CLEAR_FF_REG	0x0C	/* clear pointer flip-flop (w) */
-#define DMA1_TEMP_REG           0x0D    /* Temporary Register (r) */
+#define DMA1_TEMP_REG		0x0D	/* Temporary Register (r) */
 #define DMA1_RESET_REG		0x0D	/* Master Clear (w) */
-#define DMA1_CLR_MASK_REG       0x0E    /* Clear Mask */
-#define DMA1_MASK_ALL_REG       0x0F    /* all-channels mask (w) */
+#define DMA1_CLR_MASK_REG	0x0E	/* Clear Mask */
+#define DMA1_MASK_ALL_REG	0x0F	/* all-channels mask (w) */
 
 #define DMA2_CMD_REG		0xD0	/* command register (w) */
 #define DMA2_STAT_REG		0xD0	/* status register (r) */
-#define DMA2_REQ_REG            0xD2    /* request register (w) */
+#define DMA2_REQ_REG		0xD2	/* request register (w) */
 #define DMA2_MASK_REG		0xD4	/* single-channel mask (w) */
 #define DMA2_MODE_REG		0xD6	/* mode register (w) */
 #define DMA2_CLEAR_FF_REG	0xD8	/* clear pointer flip-flop (w) */
-#define DMA2_TEMP_REG           0xDA    /* Temporary Register (r) */
+#define DMA2_TEMP_REG		0xDA	/* Temporary Register (r) */
 #define DMA2_RESET_REG		0xDA	/* Master Clear (w) */
-#define DMA2_CLR_MASK_REG       0xDC    /* Clear Mask */
-#define DMA2_MASK_ALL_REG       0xDE    /* all-channels mask (w) */
+#define DMA2_CLR_MASK_REG	0xDC	/* Clear Mask */
+#define DMA2_MASK_ALL_REG	0xDE	/* all-channels mask (w) */
 
-#define DMA_ADDR_0              0x00    /* DMA address registers */
-#define DMA_ADDR_1              0x02
-#define DMA_ADDR_2              0x04
-#define DMA_ADDR_3              0x06
-#define DMA_ADDR_4              0xC0
-#define DMA_ADDR_5              0xC4
-#define DMA_ADDR_6              0xC8
-#define DMA_ADDR_7              0xCC
-
-#define DMA_CNT_0               0x01    /* DMA count registers */
-#define DMA_CNT_1               0x03
-#define DMA_CNT_2               0x05
-#define DMA_CNT_3               0x07
-#define DMA_CNT_4               0xC2
-#define DMA_CNT_5               0xC6
-#define DMA_CNT_6               0xCA
-#define DMA_CNT_7               0xCE
-
-#define DMA_LO_PAGE_0              0x87    /* DMA page registers */
-#define DMA_LO_PAGE_1              0x83
-#define DMA_LO_PAGE_2              0x81
-#define DMA_LO_PAGE_3              0x82
-#define DMA_LO_PAGE_5              0x8B
-#define DMA_LO_PAGE_6              0x89
-#define DMA_LO_PAGE_7              0x8A
-
-#define DMA_HI_PAGE_0              0x487    /* DMA page registers */
-#define DMA_HI_PAGE_1              0x483
-#define DMA_HI_PAGE_2              0x481
-#define DMA_HI_PAGE_3              0x482
-#define DMA_HI_PAGE_5              0x48B
-#define DMA_HI_PAGE_6              0x489
-#define DMA_HI_PAGE_7              0x48A
+#define DMA_ADDR_0		0x00	/* DMA address registers */
+#define DMA_ADDR_1		0x02
+#define DMA_ADDR_2		0x04
+#define DMA_ADDR_3		0x06
+#define DMA_ADDR_4		0xC0
+#define DMA_ADDR_5		0xC4
+#define DMA_ADDR_6		0xC8
+#define DMA_ADDR_7		0xCC
+
+#define DMA_CNT_0		0x01	/* DMA count registers */
+#define DMA_CNT_1		0x03
+#define DMA_CNT_2		0x05
+#define DMA_CNT_3		0x07
+#define DMA_CNT_4		0xC2
+#define DMA_CNT_5		0xC6
+#define DMA_CNT_6		0xCA
+#define DMA_CNT_7		0xCE
+
+#define DMA_LO_PAGE_0		0x87	/* DMA page registers */
+#define DMA_LO_PAGE_1		0x83
+#define DMA_LO_PAGE_2		0x81
+#define DMA_LO_PAGE_3		0x82
+#define DMA_LO_PAGE_5		0x8B
+#define DMA_LO_PAGE_6		0x89
+#define DMA_LO_PAGE_7		0x8A
+
+#define DMA_HI_PAGE_0		0x487	/* DMA page registers */
+#define DMA_HI_PAGE_1		0x483
+#define DMA_HI_PAGE_2		0x481
+#define DMA_HI_PAGE_3		0x482
+#define DMA_HI_PAGE_5		0x48B
+#define DMA_HI_PAGE_6		0x489
+#define DMA_HI_PAGE_7		0x48A
 
-#define DMA1_EXT_REG               0x40B
-#define DMA2_EXT_REG               0x4D6
+#define DMA1_EXT_REG		0x40B
+#define DMA2_EXT_REG		0x4D6
 
-#define DMA_MODE_CASCADE 0xC0   /* pass thru DREQ->HRQ, DACK<-HLDA only */
-#define DMA_AUTOINIT   	 0x10
+#define DMA_MODE_CASCADE	0xC0	/* pass thru DREQ->HRQ, DACK<-HLDA only */
+#define DMA_AUTOINIT		0x10
 
-extern spinlock_t  dma_spin_lock;
+extern spinlock_t dma_spin_lock;
 
 static __inline__ unsigned long claim_dma_lock(void)
 {
@@ -206,27 +194,23 @@
 {
 	unsigned char ucDmaCmd=0x00;
 
-	if (dmanr != 4)
-	{
-		dma_outb(0, DMA2_MASK_REG);  /* This may not be enabled */
-		dma_outb(ucDmaCmd, DMA2_CMD_REG);  /* Enable group */
+	if (dmanr != 4)	{
+		dma_outb(0, DMA2_MASK_REG);	/* This may not be enabled */
+		dma_outb(ucDmaCmd, DMA2_CMD_REG);	/* Enable group */
 	}
-	if (dmanr<=3)
-	{
-		dma_outb(dmanr,  DMA1_MASK_REG);
-		dma_outb(ucDmaCmd, DMA1_CMD_REG);  /* Enable group */
+	if (dmanr <= 3) {
+		dma_outb(dmanr, DMA1_MASK_REG);
+		dma_outb(ucDmaCmd, DMA1_CMD_REG);	/* Enable group */
 	} else
-	{
-		dma_outb(dmanr & 3,  DMA2_MASK_REG);
-	}
+		dma_outb(dmanr & 3, DMA2_MASK_REG);
 }
 
 static __inline__ void disable_dma(unsigned int dmanr)
 {
-	if (dmanr<=3)
-		dma_outb(dmanr | 4,  DMA1_MASK_REG);
+	if (dmanr <= 3)
+		dma_outb(dmanr | 4, DMA1_MASK_REG);
 	else
-		dma_outb((dmanr & 3) | 4,  DMA2_MASK_REG);
+		dma_outb((dmanr & 3) | 4, DMA2_MASK_REG);
 }
 
 /* Clear the 'DMA Pointer Flip Flop'.
@@ -238,19 +222,19 @@
  */
 static __inline__ void clear_dma_ff(unsigned int dmanr)
 {
-	if (dmanr<=3)
-		dma_outb(0,  DMA1_CLEAR_FF_REG);
+	if (dmanr <= 3)
+		dma_outb(0, DMA1_CLEAR_FF_REG);
 	else
-		dma_outb(0,  DMA2_CLEAR_FF_REG);
+		dma_outb(0, DMA2_CLEAR_FF_REG);
 }
 
 /* set mode (above) for a specific DMA channel */
 static __inline__ void set_dma_mode(unsigned int dmanr, char mode)
 {
-	if (dmanr<=3)
-		dma_outb(mode | dmanr,  DMA1_MODE_REG);
+	if (dmanr <= 3)
+		dma_outb(mode | dmanr, DMA1_MODE_REG);
 	else
-		dma_outb(mode | (dmanr&3),  DMA2_MODE_REG);
+		dma_outb(mode | (dmanr & 3), DMA2_MODE_REG);
 }
 
 /* Set only the page register bits of the transfer address.
@@ -263,41 +247,41 @@
 	switch(dmanr) {
 		case 0:
 			dma_outb(pagenr, DMA_LO_PAGE_0);
-                        dma_outb(pagenr>>8, DMA_HI_PAGE_0);
+			dma_outb(pagenr >> 8, DMA_HI_PAGE_0);
 			break;
 		case 1:
 			dma_outb(pagenr, DMA_LO_PAGE_1);
-                        dma_outb(pagenr>>8, DMA_HI_PAGE_1);
+			dma_outb(pagenr >> 8, DMA_HI_PAGE_1);
 			break;
 		case 2:
 			dma_outb(pagenr, DMA_LO_PAGE_2);
-			dma_outb(pagenr>>8, DMA_HI_PAGE_2); 
+			dma_outb(pagenr >> 8, DMA_HI_PAGE_2);
 			break;
 		case 3:
 			dma_outb(pagenr, DMA_LO_PAGE_3);
-			dma_outb(pagenr>>8, DMA_HI_PAGE_3); 
+			dma_outb(pagenr >> 8, DMA_HI_PAGE_3);
 			break;
-	        case 5:
-		        if (SND_DMA1 == 5 || SND_DMA2 == 5)
+		case 5:
+			if (SND_DMA1 == 5 || SND_DMA2 == 5)
 				dma_outb(pagenr, DMA_LO_PAGE_5);
 			else
 				dma_outb(pagenr & 0xfe, DMA_LO_PAGE_5);
-                        dma_outb(pagenr>>8, DMA_HI_PAGE_5);
+			dma_outb(pagenr >> 8, DMA_HI_PAGE_5);
 			break;
 		case 6:
-		        if (SND_DMA1 == 6 || SND_DMA2 == 6)
+			if (SND_DMA1 == 6 || SND_DMA2 == 6)
 				dma_outb(pagenr, DMA_LO_PAGE_6);
 			else
 				dma_outb(pagenr & 0xfe, DMA_LO_PAGE_6);
-			dma_outb(pagenr>>8, DMA_HI_PAGE_6);
+			dma_outb(pagenr >> 8, DMA_HI_PAGE_6);
 			break;
 		case 7:
 			if (SND_DMA1 == 7 || SND_DMA2 == 7)
 				dma_outb(pagenr, DMA_LO_PAGE_7);
 			else
 				dma_outb(pagenr & 0xfe, DMA_LO_PAGE_7);
-			dma_outb(pagenr>>8, DMA_HI_PAGE_7);
-		  break;
+			dma_outb(pagenr >> 8, DMA_HI_PAGE_7);
+			break;
 	}
 }
 
@@ -307,20 +291,19 @@
  */
 static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int phys)
 {
-	if (dmanr <= 3)  {
-	    dma_outb( phys & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE );
-            dma_outb( (phys>>8) & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE );
-	}  else  {
-	  if (dmanr == SND_DMA1 || dmanr == SND_DMA2) {
-	    dma_outb( phys  & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE );
-	    dma_outb( (phys>>8)  & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE );
-	    dma_outb( (dmanr&3), DMA2_EXT_REG);
-	  } else {
-	    dma_outb( (phys>>1) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE );
-	    dma_outb( (phys>>9) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE );
-	  }
+	if (dmanr <= 3) {
+		dma_outb(phys & 0xff, ((dmanr & 3) << 1) + IO_DMA1_BASE );
+		dma_outb((phys >> 8) & 0xff, ((dmanr & 3) << 1) + IO_DMA1_BASE);
+	} else if (dmanr == SND_DMA1 || dmanr == SND_DMA2) {
+		dma_outb(phys  & 0xff, ((dmanr & 3) << 2) + IO_DMA2_BASE );
+		dma_outb((phys >> 8)  & 0xff, ((dmanr & 3) << 2) +
+				IO_DMA2_BASE);
+		dma_outb((dmanr & 3), DMA2_EXT_REG);
+	} else {
+		dma_outb((phys >> 1) & 0xff, ((dmanr & 3) << 2) + IO_DMA2_BASE);
+		dma_outb((phys >> 9) & 0xff, ((dmanr & 3) << 2) + IO_DMA2_BASE);
 	}
-	set_dma_page(dmanr, phys>>16);
+	set_dma_page(dmanr, phys >> 16);
 }
 
 
@@ -334,22 +317,23 @@
  */
 static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count)
 {
-        count--;
-	if (dmanr <= 3)  {
-	    dma_outb( count & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE );
-	    dma_outb( (count>>8) & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE );
-        } else {
-	  if (dmanr == SND_DMA1 || dmanr == SND_DMA2) {
-	    dma_outb( count & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE );
-	    dma_outb( (count>>8) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE );
-	  } else {
-	    dma_outb( (count>>1) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE );
-	    dma_outb( (count>>9) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE );
-	  }
-        }
+	count--;
+	if (dmanr <= 3) {
+		dma_outb(count & 0xff, ((dmanr & 3) << 1) + 1 + IO_DMA1_BASE);
+		dma_outb((count >> 8) & 0xff, ((dmanr & 3) << 1) + 1 +
+				IO_DMA1_BASE);
+	} else if (dmanr == SND_DMA1 || dmanr == SND_DMA2) {
+		dma_outb( count & 0xff, ((dmanr & 3) << 2) + 2 + IO_DMA2_BASE);
+		dma_outb( (count >> 8) & 0xff, ((dmanr & 3) << 2) + 2 +
+				IO_DMA2_BASE);
+	} else {
+		dma_outb((count >> 1) & 0xff, ((dmanr & 3) << 2) + 2 +
+				IO_DMA2_BASE);
+		dma_outb((count >> 9) & 0xff, ((dmanr & 3) << 2) + 2 +
+				IO_DMA2_BASE);
+	}
 }
 
-
 /* Get DMA residue count. After a DMA transfer, this
  * should return zero. Reading this while a DMA transfer is
  * still in progress will return unpredictable results.
@@ -360,27 +344,32 @@
  */
 static __inline__ int get_dma_residue(unsigned int dmanr)
 {
-	unsigned int io_port = (dmanr<=3)? ((dmanr&3)<<1) + 1 + IO_DMA1_BASE
-					 : ((dmanr&3)<<2) + 2 + IO_DMA2_BASE;
+	unsigned int io_port = (dmanr <= 3) ?
+		((dmanr & 3) << 1) + 1 + IO_DMA1_BASE
+		: ((dmanr & 3) << 2) + 2 + IO_DMA2_BASE;
 
 	/* using short to get 16-bit wrap around */
 	unsigned short count;
 
 	count = 1 + dma_inb(io_port);
 	count += dma_inb(io_port) << 8;
-	
+
 	return (dmanr <= 3 || dmanr == SND_DMA1 || dmanr == SND_DMA2)
-	  ? count : (count<<1);
+		? count : (count<<1);
+
 }
 
 /* These are in kernel/dma.c: */
-extern int request_dma(unsigned int dmanr, const char * device_id);	/* reserve a DMA channel */
-extern void free_dma(unsigned int dmanr);	/* release it again */
+
+/* reserve a DMA channel */
+extern int request_dma(unsigned int dmanr, const char * device_id);
+/* release it again */
+extern void free_dma(unsigned int dmanr);
 
 #ifdef CONFIG_PCI
-extern int isa_dma_bridge_buggy;                                        
-#else                                                         
-#define isa_dma_bridge_buggy   (0)
+extern int isa_dma_bridge_buggy;
+#else
+#define isa_dma_bridge_buggy	(0)
 #endif
 #endif /* _ASM_DMA_H */
 #endif /* __KERNEL__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/elf.h linux-2.4.21-pre6/include/asm-ppc/elf.h
--- linux-2.4.20/include/asm-ppc/elf.h	2001-08-28 13:58:33.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/elf.h	2003-03-26 23:48:57.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.elf.h 1.14 08/21/01 16:07:48 trini
- */
 #ifndef __PPC_ELF_H
 #define __PPC_ELF_H
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/errno.h linux-2.4.21-pre6/include/asm-ppc/errno.h
--- linux-2.4.20/include/asm-ppc/errno.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/errno.h	2003-03-26 23:49:19.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.errno.h 1.7 05/17/01 18:14:24 cort
- */
 #ifndef _PPC_ERRNO_H
 #define _PPC_ERRNO_H
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/fcntl.h linux-2.4.21-pre6/include/asm-ppc/fcntl.h
--- linux-2.4.20/include/asm-ppc/fcntl.h	2001-11-03 01:43:54.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/fcntl.h	2003-03-26 23:49:39.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fcntl.h 1.8 09/19/01 23:06:01 paulus
- */
 #ifndef _PPC_FCNTL_H
 #define _PPC_FCNTL_H
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/floppy.h linux-2.4.21-pre6/include/asm-ppc/floppy.h
--- linux-2.4.20/include/asm-ppc/floppy.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/floppy.h	2003-03-26 23:49:26.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.floppy.h 1.5 05/17/01 18:14:24 cort
- */
-/*
  * Architecture specific parts of the Floppy driver
  *
  * This file is subject to the terms and conditions of the GNU General Public
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/gg2.h linux-2.4.21-pre6/include/asm-ppc/gg2.h
--- linux-2.4.20/include/asm-ppc/gg2.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/gg2.h	2003-03-26 23:49:08.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  asm-ppc/gg2.h -- VLSI VAS96011/12 `Golden Gate 2' register definitions
  *
  *  Copyright (C) 1997 Geert Uytterhoeven
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/hardirq.h linux-2.4.21-pre6/include/asm-ppc/hardirq.h
--- linux-2.4.20/include/asm-ppc/hardirq.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/hardirq.h	2003-03-26 23:48:57.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #ifdef __KERNEL__
 #ifndef __ASM_HARDIRQ_H
 #define __ASM_HARDIRQ_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/hdreg.h linux-2.4.21-pre6/include/asm-ppc/hdreg.h
--- linux-2.4.20/include/asm-ppc/hdreg.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/hdreg.h	2003-03-26 23:49:08.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.hdreg.h 1.5 05/17/01 18:14:24 cort
- */
-/*
  *  linux/include/asm-ppc/hdreg.h
  *
  *  Copyright (C) 1994-1996  Linus Torvalds & authors
@@ -14,7 +11,8 @@
 #ifndef __ASMPPC_HDREG_H
 #define __ASMPPC_HDREG_H
 
-typedef unsigned int ide_ioreg_t;
+//typedef unsigned int ide_ioreg_t;
+typedef unsigned long ide_ioreg_t;
 
 #endif /* __ASMPPC_HDREG_H */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/heathrow.h linux-2.4.21-pre6/include/asm-ppc/heathrow.h
--- linux-2.4.20/include/asm-ppc/heathrow.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/heathrow.h	2003-03-26 23:49:18.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.heathrow.h 1.12 03/19/02 15:53:56 benh
- */
-/*
  * heathrow.h: definitions for using the "Heathrow" I/O controller chip.
  *
  * Grabbed from Open Firmware definitions on a PowerBook G3 Series
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/highmem.h linux-2.4.21-pre6/include/asm-ppc/highmem.h
--- linux-2.4.20/include/asm-ppc/highmem.h	2001-07-02 21:34:57.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/highmem.h	2003-03-26 23:49:34.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.highmem.h 1.10 06/28/01 15:50:17 paulus
- */
-/*
  * highmem.h: virtual kernel memory mappings for high memory
  *
  * PowerPC version, stolen from the i386 version.
@@ -52,16 +49,19 @@
 
 #define KMAP_FIX_BEGIN	(0xfe400000UL)
 
-extern void *kmap_high(struct page *page);
+extern void *kmap_high(struct page *page, int nonblock);
 extern void kunmap_high(struct page *page);
 
-static inline void *kmap(struct page *page)
+#define kmap(page)		__kmap(page, 0)
+#define kmap_nonblock(page)	__kmap(page, 1)
+
+static inline void *__kmap(struct page *page, int nonblock)
 {
 	if (in_interrupt())
 		BUG();
 	if (page < highmem_start_page)
 		return page_address(page);
-	return kmap_high(page);
+	return kmap_high(page, nonblock);
 }
 
 static inline void kunmap(struct page *page)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/hw_irq.h linux-2.4.21-pre6/include/asm-ppc/hw_irq.h
--- linux-2.4.20/include/asm-ppc/hw_irq.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/hw_irq.h	2003-03-26 23:49:50.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.hw_irq.h 1.10 05/17/01 18:14:24 cort
- */
-/*
  * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu>
  */
 #ifdef __KERNEL__
@@ -21,6 +18,7 @@
 
 #define __save_flags(flags) __save_flags_ptr((unsigned long *)&flags)
 #define __save_and_cli(flags) ({__save_flags(flags);__cli();})
+#define __save_and_sti(flags) ({__save_flags(flags);__sti();})
 
 extern void do_lost_interrupts(unsigned long);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/hydra.h linux-2.4.21-pre6/include/asm-ppc/hydra.h
--- linux-2.4.20/include/asm-ppc/hydra.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/hydra.h	2003-03-26 23:49:39.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.hydra.h 1.5 05/17/01 18:14:24 cort
- */
-/*
  *  asm-ppc/hydra.h -- Mac I/O `Hydra' definitions
  *
  *  Copyright (C) 1997 Geert Uytterhoeven
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/i8259.h linux-2.4.21-pre6/include/asm-ppc/i8259.h
--- linux-2.4.20/include/asm-ppc/i8259.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/i8259.h	2003-03-26 23:49:08.000000000 +0000
@@ -1,7 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
-
 #ifndef _PPC_KERNEL_i8259_H
 #define _PPC_KERNEL_i8259_H
 
@@ -11,6 +7,5 @@
 
 void i8259_init(unsigned long int_ack);
 int i8259_irq(struct pt_regs *regs);
-int i8259_poll(struct pt_regs *regs);
 
 #endif /* _PPC_KERNEL_i8259_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/ide.h linux-2.4.21-pre6/include/asm-ppc/ide.h
--- linux-2.4.20/include/asm-ppc/ide.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/ide.h	2003-03-26 23:49:27.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.ide.h 1.16 09/28/01 07:54:24 trini
- */
-/*
  *  linux/include/asm-ppc/ide.h
  *
  *  Copyright (C) 1994-1996 Linus Torvalds & authors */
@@ -30,17 +27,9 @@
 #include <linux/ioport.h>
 #include <asm/io.h>
 
-extern void ppc_generic_ide_fix_driveid(struct hd_driveid *id);
-
 struct ide_machdep_calls {
         int         (*default_irq)(ide_ioreg_t base);
         ide_ioreg_t (*default_io_base)(int index);
-        int         (*ide_check_region)(ide_ioreg_t from, unsigned int extent);
-        void        (*ide_request_region)(ide_ioreg_t from,
-                                      unsigned int extent,
-                                      const char *name);
-        void        (*ide_release_region)(ide_ioreg_t from,
-                                      unsigned int extent);
         void        (*ide_init_hwif)(hw_regs_t *hw,
                                      ide_ioreg_t data_port,
                                      ide_ioreg_t ctrl_port,
@@ -49,16 +38,11 @@
 
 extern struct ide_machdep_calls ppc_ide_md;
 
-void ppc_generic_ide_fix_driveid(struct hd_driveid *id);
-#define ide_fix_driveid(id)	ppc_generic_ide_fix_driveid((id))
-
 #undef	SUPPORT_SLOW_DATA_PORTS
 #define	SUPPORT_SLOW_DATA_PORTS	0
 #undef	SUPPORT_VLB_SYNC
 #define SUPPORT_VLB_SYNC	0
 
-#define ide__sti()	__sti()
-
 static __inline__ int ide_default_irq(ide_ioreg_t base)
 {
 	if (ppc_ide_md.default_irq)
@@ -77,8 +61,24 @@
 					   ide_ioreg_t data_port,
 					   ide_ioreg_t ctrl_port, int *irq)
 {
-	if (ppc_ide_md.ide_init_hwif != NULL)
+	ide_ioreg_t reg = data_port;
+	int i;
+
+	if (ppc_ide_md.ide_init_hwif != NULL) {
 		ppc_ide_md.ide_init_hwif(hw, data_port, ctrl_port, irq);
+		return;
+	}
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
+		hw->io_ports[i] = reg++;
+	if (ctrl_port) {
+		hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
+	} else {
+		hw->io_ports[IDE_CONTROL_OFFSET] =
+			hw->io_ports[IDE_DATA_OFFSET] + 0x206;
+	}
+	if (irq != NULL)
+		*irq = 0;
+	hw->io_ports[IDE_IRQ_OFFSET] = 0;
 }
 
 static __inline__ void ide_init_default_hwifs(void)
@@ -99,67 +99,18 @@
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
-static __inline__ int ide_check_region (ide_ioreg_t from, unsigned int extent)
-{
-	if (ppc_ide_md.ide_check_region)
-		return ppc_ide_md.ide_check_region(from, extent);
-	return 0;
-}
-
-static __inline__ void ide_request_region (ide_ioreg_t from, unsigned int extent, const char *name)
-{
-	if (ppc_ide_md.ide_request_region)
-		ppc_ide_md.ide_request_region(from, extent, name);
-}
-
-static __inline__ void ide_release_region (ide_ioreg_t from, unsigned int extent)
-{
-	if (ppc_ide_md.ide_release_region)
-		ppc_ide_md.ide_release_region(from, extent);
-}
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned bit7		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned unit		: 1;	/* drive select number, 0/1 */
-		unsigned head		: 4;	/* always zeros here */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-		unsigned reserved456	: 3;
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned bit0		: 1;
-	} b;
-} control_t;
-
-#if !defined(ide_request_irq)
-#define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
-#endif
-
-#if !defined(ide_free_irq)
-#define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
-#endif
+#define __ide_mm_insw(p, a, c)	_insw_ns((volatile u16 *)(p), (a), (c))
+#define __ide_mm_insl(p, a, c)	_insl_ns((volatile u32 *)(p), (a), (c))
+#define __ide_mm_outsw(p, a, c)	_outsw_ns((volatile u16 *)(p), (a), (c))
+#define __ide_mm_outsl(p, a, c)	_outsl_ns((volatile u32 *)(p), (a), (c))
 
 /*
  * The following are not needed for the non-m68k ports
  * unless direct IDE on 8xx
  */
 #if (defined CONFIG_APUS || defined CONFIG_BLK_DEV_MPC8xx_IDE )
-#define ide_ack_intr(hwif) (hwif->hw.ack_intr ? hwif->hw.ack_intr(hwif) : 1)
-#else
-#define ide_ack_intr(hwif)		(1)
+#define IDE_ARCH_ACK_INTR 1
 #endif
-#define ide_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
 
 #endif /* __KERNEL__ */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/immap_8260.h linux-2.4.21-pre6/include/asm-ppc/immap_8260.h
--- linux-2.4.20/include/asm-ppc/immap_8260.h	2001-07-19 01:01:03.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/immap_8260.h	2003-03-26 23:49:39.000000000 +0000
@@ -1,8 +1,4 @@
 /*
- * BK Id: SCCS/s.immap_8260.h 1.8 07/18/01 15:46:50 trini
- */
-
-/*
  * MPC8260 Internal Memory Map
  * Copyright (c) 1999 Dan Malek (dmalek@jlc.net)
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/io.h linux-2.4.21-pre6/include/asm-ppc/io.h
--- linux-2.4.20/include/asm-ppc/io.h	2001-11-03 01:43:54.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/io.h	2003-03-26 23:49:20.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.io.h 1.14 10/16/01 15:58:42 trini
- */
 #ifdef __KERNEL__
 #ifndef _PPC_IO_H
 #define _PPC_IO_H
@@ -181,7 +178,6 @@
 #define memcpy_fromio(a,b,c)   memcpy((a),(void *)(b),(c))
 #define memcpy_toio(a,b,c)	memcpy((void *)(a),(b),(c))
 
-#ifdef __KERNEL__
 /*
  * Map in an area of physical address space, for accessing
  * I/O devices etc.
@@ -250,11 +246,9 @@
 /*
  * Change "struct page" to physical address.
  */
-#define page_to_phys(page)	((page - mem_map) << PAGE_SHIFT)
+#define page_to_phys(page)	(((page - mem_map) << PAGE_SHIFT) + PPC_MEMSTART)
 #define page_to_bus(page)	(page_to_phys(page) + PCI_DRAM_OFFSET)
 
-#endif /* __KERNEL__ */
-
 /*
  * Enforce In-order Execution of I/O:
  * Acts as a barrier to ensure all previous I/O accesses have
@@ -265,7 +259,7 @@
 	__asm__ __volatile__ ("eieio" : : : "memory");
 }
 
-/* Enforce in-order execution of data I/O. 
+/* Enforce in-order execution of data I/O.
  * No distinction between read/write on PPC; use eieio for all three.
  */
 #define iobarrier_rw() eieio()
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/ioctl.h linux-2.4.21-pre6/include/asm-ppc/ioctl.h
--- linux-2.4.20/include/asm-ppc/ioctl.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/ioctl.h	2003-03-26 23:49:35.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.ioctl.h 1.5 05/17/01 18:14:24 cort
- */
 #ifndef _PPC_IOCTL_H
 #define _PPC_IOCTL_H
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/ioctls.h linux-2.4.21-pre6/include/asm-ppc/ioctls.h
--- linux-2.4.20/include/asm-ppc/ioctls.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/ioctls.h	2003-03-26 23:49:19.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.ioctls.h 1.7 05/17/01 18:14:24 cort
- */
 #ifndef _ASM_PPC_IOCTLS_H
 #define _ASM_PPC_IOCTLS_H
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/ipc.h linux-2.4.21-pre6/include/asm-ppc/ipc.h
--- linux-2.4.20/include/asm-ppc/ipc.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/ipc.h	2003-03-26 23:49:55.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.ipc.h 1.5 05/17/01 18:14:24 cort
- */
 #ifndef __PPC_IPC_H__
 #define __PPC_IPC_H__
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/ipcbuf.h linux-2.4.21-pre6/include/asm-ppc/ipcbuf.h
--- linux-2.4.20/include/asm-ppc/ipcbuf.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/ipcbuf.h	2003-03-26 23:48:59.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.ipcbuf.h 1.5 05/17/01 18:14:24 cort
- */
 #ifndef __PPC_IPCBUF_H__
 #define __PPC_IPCBUF_H__
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/irq.h linux-2.4.21-pre6/include/asm-ppc/irq.h
--- linux-2.4.20/include/asm-ppc/irq.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/irq.h	2003-03-26 23:49:07.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #ifdef __KERNEL__
 #ifndef _ASM_IRQ_H
 #define _ASM_IRQ_H
@@ -13,6 +10,19 @@
 extern void disable_irq_nosync(unsigned int);
 extern void enable_irq(unsigned int);
 
+/*
+ * These constants are used for passing information about interrupt
+ * signal polarity and level/edge sensing to the low-level PIC chip
+ * drivers.
+ */
+#define IRQ_SENSE_MASK		0x1
+#define IRQ_SENSE_LEVEL		0x1	/* interrupt on active level */
+#define IRQ_SENSE_EDGE		0x0	/* interrupt triggered by edge */
+
+#define IRQ_POLARITY_MASK	0x2
+#define IRQ_POLARITY_POSITIVE	0x2	/* high level or low->high edge */
+#define IRQ_POLARITY_NEGATIVE	0x0	/* low level or high->low edge */
+
 #if defined(CONFIG_4xx)
 
 /*
@@ -55,6 +65,10 @@
 
 #elif defined(CONFIG_8xx)
 
+/* Now include the board configuration specific associations.
+*/
+#include <asm/mpc8xx.h>
+
 /* The MPC8xx cores have 16 possible interrupts.  There are eight
  * possible level sensitive interrupts assigned and generated internally
  * from such devices as CPM, PCMCIA, RTC, PIT, TimeBase and Decrementer.
@@ -63,10 +77,22 @@
  *
  * On some implementations, there is also the possibility of an 8259
  * through the PCI and PCI-ISA bridges.
+ *
+ * We are "flattening" the interrupt vectors of the cascaded CPM
+ * and 8259 interrupt controllers so that we can uniquely identify
+ * any interrupt source with a single integer.
  */
 #define NR_SIU_INTS	16
+#define NR_CPM_INTS	32
+#ifndef NR_8259_INTS
+#define NR_8259_INTS 0
+#endif
 
-#define NR_IRQS	(NR_SIU_INTS + NR_8259_INTS)
+#define SIU_IRQ_OFFSET		0
+#define CPM_IRQ_OFFSET		(SIU_IRQ_OFFSET + NR_SIU_INTS)
+#define I8259_IRQ_OFFSET	(CPM_IRQ_OFFSET + NR_CPM_INTS)
+
+#define NR_IRQS	(NR_SIU_INTS + NR_CPM_INTS + NR_8259_INTS)
 
 /* These values must be zero-based and map 1:1 with the SIU configuration.
  * They are used throughout the 8xx I/O subsystem to generate
@@ -91,10 +117,6 @@
 #define	SIU_IRQ7	(14)
 #define	SIU_LEVEL7	(15)
 
-/* Now include the board configuration specific associations.
-*/
-#include <asm/mpc8xx.h>
-
 /* The internal interrupts we can configure as we see fit.
  * My personal preference is CPM at level 2, which puts it above the
  * MBX PCI/ISA/IDE interrupts.
@@ -147,17 +169,55 @@
  */
 #define NR_SIU_INTS	64
 
-/* There are many more than these, we will add them as we need them.
-*/
+#define	SIU_INT_ERROR		((uint)0x00)
+#define	SIU_INT_I2C		((uint)0x01)
+#define	SIU_INT_SPI		((uint)0x02)
+#define	SIU_INT_RISC		((uint)0x03)
 #define	SIU_INT_SMC1		((uint)0x04)
 #define	SIU_INT_SMC2		((uint)0x05)
+#define	SIU_INT_IDMA1		((uint)0x06)
+#define	SIU_INT_IDMA2		((uint)0x07)
+#define	SIU_INT_IDMA3		((uint)0x08)
+#define	SIU_INT_IDMA4		((uint)0x09)
+#define	SIU_INT_SDMA		((uint)0x0a)
+#define	SIU_INT_TIMER1		((uint)0x0c)
+#define	SIU_INT_TIMER2		((uint)0x0d)
+#define	SIU_INT_TIMER3		((uint)0x0e)
+#define	SIU_INT_TIMER4		((uint)0x0f)
+#define	SIU_INT_TMCNT		((uint)0x10)
+#define	SIU_INT_PIT		((uint)0x11)
+#define	SIU_INT_IRQ1		((uint)0x13)
+#define	SIU_INT_IRQ2		((uint)0x14)
+#define	SIU_INT_IRQ3		((uint)0x15)
+#define	SIU_INT_IRQ4		((uint)0x16)
+#define	SIU_INT_IRQ5		((uint)0x17)
+#define	SIU_INT_IRQ6		((uint)0x18)
+#define	SIU_INT_IRQ7		((uint)0x19)
 #define	SIU_INT_FCC1		((uint)0x20)
 #define	SIU_INT_FCC2		((uint)0x21)
 #define	SIU_INT_FCC3		((uint)0x22)
+#define	SIU_INT_MCC1		((uint)0x24)
+#define	SIU_INT_MCC2		((uint)0x25)
 #define	SIU_INT_SCC1		((uint)0x28)
 #define	SIU_INT_SCC2		((uint)0x29)
 #define	SIU_INT_SCC3		((uint)0x2a)
 #define	SIU_INT_SCC4		((uint)0x2b)
+#define	SIU_INT_PC15		((uint)0x30)
+#define	SIU_INT_PC14		((uint)0x31)
+#define	SIU_INT_PC13		((uint)0x32)
+#define	SIU_INT_PC12		((uint)0x33)
+#define	SIU_INT_PC11		((uint)0x34)
+#define	SIU_INT_PC10		((uint)0x35)
+#define	SIU_INT_PC9		((uint)0x36)
+#define	SIU_INT_PC8		((uint)0x37)
+#define	SIU_INT_PC7		((uint)0x38)
+#define	SIU_INT_PC6		((uint)0x39)
+#define	SIU_INT_PC5		((uint)0x3a)
+#define	SIU_INT_PC4		((uint)0x3b)
+#define	SIU_INT_PC3		((uint)0x3c)
+#define	SIU_INT_PC2		((uint)0x3d)
+#define	SIU_INT_PC1		((uint)0x3e)
+#define	SIU_INT_PC0		((uint)0x3f)
 
 #endif /* CONFIG_8260 */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/keyboard.h linux-2.4.21-pre6/include/asm-ppc/keyboard.h
--- linux-2.4.20/include/asm-ppc/keyboard.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/keyboard.h	2003-03-26 23:49:50.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  linux/include/asm-ppc/keyboard.h
  *
  *  Created 3 Nov 1996 by Geert Uytterhoeven
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/keylargo.h linux-2.4.21-pre6/include/asm-ppc/keylargo.h
--- linux-2.4.20/include/asm-ppc/keylargo.h	2002-02-25 19:38:12.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/keylargo.h	2003-03-26 23:49:40.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.keylargo.h 1.17 01/20/02 23:53:12 benh
- */
-/*
  * keylargo.h: definitions for using the "KeyLargo" I/O controller chip.
  *
  */
@@ -13,12 +10,13 @@
 #define KL_PANGEA_REV		0x100
 
 /* offset from base for feature control registers */
-#define KEYLARGO_MBCR		0x34	/* Media bay control/status */
+#define KEYLARGO_MBCR		0x34	/* KL Only, Media bay control/status */
 #define KEYLARGO_FCR0		0x38
 #define KEYLARGO_FCR1		0x3c
 #define KEYLARGO_FCR2		0x40
 #define KEYLARGO_FCR3		0x44
 #define KEYLARGO_FCR4		0x48
+#define KEYLARGO_FCR5		0x4c	/* Pangea only */
 
 /* GPIO registers */
 #define KEYLARGO_GPIO_LEVELS0		0x50
@@ -88,76 +86,111 @@
 #define KL_MBCR_MB1_DEV_RESET		0x02000000
 #define KL_MBCR_MB1_ENABLE		0x01000000
 
-#define KL0_SCC_B_INTF_ENABLE		0x00000001
+#define KL0_SCC_B_INTF_ENABLE		0x00000001	/* (KL Only) */
 #define KL0_SCC_A_INTF_ENABLE		0x00000002
 #define KL0_SCC_SLOWPCLK		0x00000004
 #define KL0_SCC_RESET			0x00000008
 #define KL0_SCCA_ENABLE			0x00000010
 #define KL0_SCCB_ENABLE			0x00000020
 #define KL0_SCC_CELL_ENABLE		0x00000040
-#define KL0_IRDA_HIGH_BAND		0x00000100
-#define KL0_IRDA_SOURCE2_SEL		0x00000200
-#define KL0_IRDA_SOURCE1_SEL		0x00000400
-#define KL0_IRDA_RESET			0x00000800
-#define KL0_IRDA_DEFAULT1		0x00001000
-#define KL0_IRDA_DEFAULT0		0x00002000
-#define KL0_IRDA_FAST_CONNECT		0x00004000
-#define KL0_IRDA_ENABLE			0x00008000
-#define KL0_IRDA_CLK32_ENABLE		0x00010000
-#define KL0_IRDA_CLK19_ENABLE		0x00020000
+#define KL0_IRDA_HIGH_BAND		0x00000100	/* (KL Only) */
+#define KL0_IRDA_SOURCE2_SEL		0x00000200	/* (KL Only) */
+#define KL0_IRDA_SOURCE1_SEL		0x00000400	/* (KL Only) */
+#define KL0_PG_USB0_PMI_ENABLE		0x00000400	/* (Pangea/Intrepid Only) */
+#define KL0_IRDA_RESET			0x00000800	/* (KL Only) */
+#define KL0_PG_USB0_REF_SUSPEND_SEL	0x00000800	/* (Pangea/Intrepid Only) */
+#define KL0_IRDA_DEFAULT1		0x00001000	/* (KL Only) */
+#define KL0_PG_USB0_REF_SUSPEND		0x00001000	/* (Pangea/Intrepid Only) */
+#define KL0_IRDA_DEFAULT0		0x00002000	/* (KL Only) */
+#define KL0_PG_USB0_PAD_SUSPEND		0x00002000	/* (Pangea/Intrepid Only) */
+#define KL0_IRDA_FAST_CONNECT		0x00004000	/* (KL Only) */
+#define KL0_PG_USB1_PMI_ENABLE		0x00004000	/* (Pangea/Intrepid Only) */
+#define KL0_IRDA_ENABLE			0x00008000	/* (KL Only) */
+#define KL0_PG_USB1_REF_SUSPEND_SEL	0x00008000	/* (Pangea/Intrepid Only) */
+#define KL0_IRDA_CLK32_ENABLE		0x00010000	/* (KL Only) */
+#define KL0_PG_USB1_REF_SUSPEND		0x00010000	/* (Pangea/Intrepid Only) */
+#define KL0_IRDA_CLK19_ENABLE		0x00020000	/* (KL Only) */
+#define KL0_PG_USB1_PAD_SUSPEND		0x00020000	/* (Pangea/Intrepid Only) */
 #define KL0_USB0_PAD_SUSPEND0		0x00040000
 #define KL0_USB0_PAD_SUSPEND1		0x00080000
 #define KL0_USB0_CELL_ENABLE		0x00100000
 #define KL0_USB1_PAD_SUSPEND0		0x00400000
 #define KL0_USB1_PAD_SUSPEND1		0x00800000
 #define KL0_USB1_CELL_ENABLE		0x01000000
-#define KL0_USB_REF_SUSPEND		0x10000000
+#define KL0_USB_REF_SUSPEND		0x10000000	/* (KL Only) */
 
 #define KL0_SERIAL_ENABLE		(KL0_SCC_B_INTF_ENABLE | \
 					KL0_SCC_SLOWPCLK | \
 					KL0_SCC_CELL_ENABLE | KL0_SCCA_ENABLE)
 
-#define KL1_AUDIO_SEL_22MCLK		0x00000002
-#define KL1_AUDIO_CLK_ENABLE_BIT	0x00000008
-#define KL1_AUDIO_CLK_OUT_ENABLE	0x00000020	/* Burgundy only ? */
-#define KL1_AUDIO_CELL_ENABLE		0x00000040
-#define KL1_AUDIO_CHOOSE		0x00000080	/* Burgundy only ? */
+#define KL1_USB2_PMI_ENABLE		0x00000001	/* Intrepid only */
+#define KL1_AUDIO_SEL_22MCLK		0x00000002	/* KL/Pangea only */
+#define KL1_USB2_REF_SUSPEND_SEL	0x00000002	/* Intrepid only */
+#define KL1_USB2_REF_SUSPEND		0x00000004	/* Intrepid only */
+#define KL1_AUDIO_CLK_ENABLE_BIT	0x00000008	/* KL/Pangea only */
+#define KL1_USB2_PAD_SUSPEND_SEL	0x00000008	/* Intrepid only */
+#define KL1_USB2_PAD_SUSPEND0		0x00000010	/* Intrepid only */
+#define KL1_AUDIO_CLK_OUT_ENABLE	0x00000020	/* KL/Pangea only */
+#define KL1_USB2_PAD_SUSPEND1		0x00000020	/* Intrepid only */
+#define KL1_AUDIO_CELL_ENABLE		0x00000040	/* KL/Pangea only */
+#define KL1_USB2_CELL_ENABLE		0x00000040	/* Intrepid only */
+#define KL1_AUDIO_CHOOSE		0x00000080	/* KL/Pangea only */
+#define KL1_I2S0_CHOOSE			0x00000200	/* KL Only */
 #define KL1_I2S0_CELL_ENABLE		0x00000400
 #define KL1_I2S0_CLK_ENABLE_BIT		0x00001000
 #define KL1_I2S0_ENABLE			0x00002000
 #define KL1_I2S1_CELL_ENABLE		0x00020000
 #define KL1_I2S1_CLK_ENABLE_BIT		0x00080000
 #define KL1_I2S1_ENABLE			0x00100000
-#define KL1_EIDE0_ENABLE		0x00800000
-#define KL1_EIDE0_RESET_N		0x01000000
-#define KL1_EIDE1_ENABLE		0x04000000
-#define KL1_EIDE1_RESET_N		0x08000000
-#define KL1_UIDE_ENABLE			0x20000000
-#define KL1_UIDE_RESET_N		0x40000000
+#define KL1_EIDE0_ENABLE		0x00800000	/* KL/Intrepid Only */
+#define KL1_EIDE0_RESET_N		0x01000000	/* KL/Intrepid Only */
+#define KL1_EIDE1_ENABLE		0x04000000	/* KL Only */
+#define KL1_EIDE1_RESET_N		0x08000000	/* KL Only */
+#define KL1_UIDE_ENABLE			0x20000000	/* KL/Pangea Only */
+#define KL1_UIDE_RESET_N		0x40000000	/* KL/Pangea Only */
 
 #define KL2_IOBUS_ENABLE		0x00000002
-#define KL2_SLEEP_STATE_BIT		0x00000100
+#define KL2_SLEEP_STATE_BIT		0x00000100	/* KL Only */
+#define KL2_PG_STOP_ALL_CLOCKS		0x00000100	/* Pangea Only */
 #define KL2_MPIC_ENABLE			0x00020000
-#define KL2_ALT_DATA_OUT		0x02000000
+#define KL2_CARDSLOT_RESET		0x00040000	/* Pangea/Intrepid Only */
+#define KL2_ALT_DATA_OUT		0x02000000	/* KL Only ??? */
 #define KL2_MEM_IS_BIG			0x04000000
 #define KL2_CARDSEL_16			0x08000000
 
-#define KL3_SHUTDOWN_PLL_TOTAL		0x00000001
-#define KL3_SHUTDOWN_PLLKW6		0x00000002
-#define KL3_SHUTDOWN_PLLKW4		0x00000004
-#define KL3_SHUTDOWN_PLLKW35		0x00000008
-#define KL3_SHUTDOWN_PLLKW12		0x00000010
-#define KL3_PLL_RESET			0x00000020
-#define KL3_SHUTDOWN_PLL2X		0x00000080
-#define KL3_CLK66_ENABLE		0x00000100
+#define KL3_SHUTDOWN_PLL_TOTAL		0x00000001	/* KL/Pangea only */
+#define KL3_SHUTDOWN_PLLKW6		0x00000002	/* KL/Pangea only */
+#define KL3_IT_SHUTDOWN_PLL3		0x00000002	/* Intrepid only */
+#define KL3_SHUTDOWN_PLLKW4		0x00000004	/* KL/Pangea only */
+#define KL3_IT_SHUTDOWN_PLL2		0x00000004	/* Intrepid only */
+#define KL3_SHUTDOWN_PLLKW35		0x00000008	/* KL/Pangea only */
+#define KL3_IT_SHUTDOWN_PLL1		0x00000008	/* Intrepid only */
+#define KL3_SHUTDOWN_PLLKW12		0x00000010	/* KL Only */
+#define KL3_IT_ENABLE_PLL3_SHUTDOWN	0x00000010	/* Intrepid only */
+#define KL3_PLL_RESET			0x00000020	/* KL/Pangea only */
+#define KL3_IT_ENABLE_PLL2_SHUTDOWN	0x00000020	/* Intrepid only */
+#define KL3_IT_ENABLE_PLL1_SHUTDOWN	0x00000010	/* Intrepid only */
+#define KL3_SHUTDOWN_PLL2X		0x00000080	/* KL Only */
+#define KL3_CLK66_ENABLE		0x00000100	/* KL Only */
 #define KL3_CLK49_ENABLE		0x00000200
 #define KL3_CLK45_ENABLE		0x00000400
-#define KL3_CLK31_ENABLE		0x00000800
+#define KL3_CLK31_ENABLE		0x00000800	/* KL/Pangea only */
 #define KL3_TIMER_CLK18_ENABLE		0x00001000
 #define KL3_I2S1_CLK18_ENABLE		0x00002000
 #define KL3_I2S0_CLK18_ENABLE		0x00004000
-#define KL3_VIA_CLK16_ENABLE		0x00008000
-#define KL3_STOPPING33_ENABLED		0x00080000
+#define KL3_VIA_CLK16_ENABLE		0x00008000	/* KL/Pangea only */
+#define KL3_IT_VIA_CLK32_ENABLE		0x00008000	/* Intrepid only */
+#define KL3_STOPPING33_ENABLED		0x00080000	/* KL Only */
+#define KL3_PG_PLL_ENABLE_TEST		0x00080000	/* Pangea Only */
+
+/* Intrepid USB bus 2, port 0,1 */
+#define KL3_IT_PORT_WAKEUP_ENABLE(p)		(0x00080000 << ((p)<<3))
+#define KL3_IT_PORT_RESUME_WAKE_EN(p)		(0x00040000 << ((p)<<3))
+#define KL3_IT_PORT_CONNECT_WAKE_EN(p)		(0x00020000 << ((p)<<3))
+#define KL3_IT_PORT_DISCONNECT_WAKE_EN(p)	(0x00010000 << ((p)<<3))
+#define KL3_IT_PORT_RESUME_STAT(p)		(0x00300000 << ((p)<<3))
+#define KL3_IT_PORT_CONNECT_STAT(p)		(0x00200000 << ((p)<<3))
+#define KL3_IT_PORT_DISCONNECT_STAT(p)		(0x00100000 << ((p)<<3))
 
 /* Port 0,1 : bus 0, port 2,3 : bus 1 */
 #define KL4_PORT_WAKEUP_ENABLE(p)	(0x00000008 << ((p)<<3))
@@ -168,3 +201,10 @@
 #define KL4_PORT_CONNECT_STAT(p)	(0x00000020 << ((p)<<3))
 #define KL4_PORT_DISCONNECT_STAT(p)	(0x00000010 << ((p)<<3))
 
+/* Pangea and Intrepid only */
+#define KL5_VIA_USE_CLK31		0x000000001	/* Pangea Only */
+#define KL5_SCC_USE_CLK31		0x000000002	/* Pangea Only */
+#define KL5_PWM_CLK32_EN		0x000000004
+#define KL5_CLK3_68_EN			0x000000010
+#define KL5_CLK32_EN			0x000000020
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/kgdb.h linux-2.4.21-pre6/include/asm-ppc/kgdb.h
--- linux-2.4.20/include/asm-ppc/kgdb.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/kgdb.h	2003-03-26 23:49:07.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.kgdb.h 1.5 05/17/01 18:14:24 cort
- */
-/*
  * kgdb.h: Defines and declarations for serial line source level
  *         remote debugging of the Linux kernel using gdb.
  *
@@ -15,7 +12,7 @@
 
 #ifndef __ASSEMBLY__
 /* To initialize the serial, first thing called */
-extern void zs_kgdb_hook(int tty_num);
+extern void kgdb_map_scc(void);
 /* To init the kgdb engine. (called by serial hook)*/
 extern void set_debug_traps(void);
 
@@ -38,8 +35,6 @@
 void kgdb(struct pt_regs *regs);
 int kgdb_iabr_match(struct pt_regs *regs);
 int kgdb_dabr_match(struct pt_regs *regs);
-static void kgdb_fault_handler(struct pt_regs *regs);
-static void handle_exception (struct pt_regs *regs);
 
 /*
  * external low-level support routines (ie macserial.c)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/kmap_types.h linux-2.4.21-pre6/include/asm-ppc/kmap_types.h
--- linux-2.4.20/include/asm-ppc/kmap_types.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/kmap_types.h	2003-03-26 23:49:09.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.kmap_types.h 1.9 08/29/01 14:03:05 paulus
- */
 #ifdef __KERNEL__
 #ifndef _ASM_KMAP_TYPES_H
 #define _ASM_KMAP_TYPES_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/linux_logo.h linux-2.4.21-pre6/include/asm-ppc/linux_logo.h
--- linux-2.4.20/include/asm-ppc/linux_logo.h	2001-06-12 02:15:27.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/linux_logo.h	2003-03-26 23:49:53.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.linux_logo.h 1.7 05/17/01 18:14:24 cort
- */
-/*
  * include/asm-ppc/linux_logo.h: A linux logo to be displayed on boot
  * (pinched from the sparc port).
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/m48t35.h linux-2.4.21-pre6/include/asm-ppc/m48t35.h
--- linux-2.4.20/include/asm-ppc/m48t35.h	2001-11-03 01:43:54.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/m48t35.h	2003-03-26 23:48:57.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.m48t35.h 1.8 10/16/01 15:58:42 trini
- */
-/*
  *  Registers for the SGS-Thomson M48T35 Timekeeper RAM chip
  *  and
  *  Registers for the SGS-Thomson M48T37 Timekeeper RAM chip
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/machdep.h linux-2.4.21-pre6/include/asm-ppc/machdep.h
--- linux-2.4.20/include/asm-ppc/machdep.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/machdep.h	2003-03-26 23:49:21.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #ifdef __KERNEL__
 #ifndef _PPC_MACHDEP_H
 #define _PPC_MACHDEP_H
@@ -48,6 +45,7 @@
 	unsigned long	(*find_end_of_memory)(void);
 	void		(*setup_io_mappings)(void);
 
+	void		(*early_serial_map)(void);
   	void		(*progress)(char *, unsigned short);
 
 	unsigned char 	(*nvram_read_val)(int addr);
@@ -106,6 +104,9 @@
 	 */
 	int (*feature_call)(unsigned int feature, ...);
 
+	/* Hook for board-specific info passed by the bootloader */
+	void (*board_info)(void *bdinfo, int bdinfo_size);
+
 #ifdef CONFIG_SMP
 	/* functions for dealing with other cpus */
 	struct smp_ops_t *smp_ops;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/mc146818rtc.h linux-2.4.21-pre6/include/asm-ppc/mc146818rtc.h
--- linux-2.4.20/include/asm-ppc/mc146818rtc.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/mc146818rtc.h	2003-03-26 23:49:24.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.mc146818rtc.h 1.5 05/17/01 18:14:25 cort
- */
-/*
  * Machine dependent access functions for RTC registers.
  */
 #ifdef __KERNEL__
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/md.h linux-2.4.21-pre6/include/asm-ppc/md.h
--- linux-2.4.20/include/asm-ppc/md.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/md.h	2003-03-26 23:49:51.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.md.h 1.5 05/17/01 18:14:25 cort
- */
-/*
  * md.h: High speed xor_block operation for RAID4/5 
  *
  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/mediabay.h linux-2.4.21-pre6/include/asm-ppc/mediabay.h
--- linux-2.4.20/include/asm-ppc/mediabay.h	2002-02-25 19:38:12.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/mediabay.h	2003-03-26 23:49:07.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.mediabay.h 1.8 12/01/01 20:09:11 benh
- */
-/*
  * mediabay.h: definitions for using the media bay
  * on PowerBook 3400 and similar computers.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/mk48t59.h linux-2.4.21-pre6/include/asm-ppc/mk48t59.h
--- linux-2.4.20/include/asm-ppc/mk48t59.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/mk48t59.h	2003-03-26 23:49:20.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.mk48t59.h 1.5 05/17/01 18:14:25 cort
- */
-/*
  * Registers for the mk48t59 real-time-clock
  */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/mman.h linux-2.4.21-pre6/include/asm-ppc/mman.h
--- linux-2.4.20/include/asm-ppc/mman.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/mman.h	2003-03-26 23:49:56.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.mman.h 1.7 05/17/01 18:14:25 cort
- */
 #ifndef __PPC_MMAN_H__
 #define __PPC_MMAN_H__
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/mmu.h linux-2.4.21-pre6/include/asm-ppc/mmu.h
--- linux-2.4.20/include/asm-ppc/mmu.h	2001-07-02 21:34:57.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/mmu.h	2003-03-26 23:49:54.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.mmu.h 1.10 06/28/01 15:50:17 paulus
- */
-/*
  * PowerPC memory management structures
  */
 
@@ -43,6 +40,9 @@
 	unsigned long pp:2;	/* Page protection */
 } PTE; 
 
+extern PTE *Hash, *Hash_end;
+extern unsigned long Hash_size, Hash_mask;
+
 /* Values for PP (assumes Ks=0, Kp=1) */
 #define PP_RWXX	0	/* Supervisor read/write, User none */
 #define PP_RWRX 1	/* Supervisor read/write, User read */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/mmu_context.h linux-2.4.21-pre6/include/asm-ppc/mmu_context.h
--- linux-2.4.20/include/asm-ppc/mmu_context.h	2001-10-02 16:12:44.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/mmu_context.h	2003-03-26 23:48:58.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.mmu_context.h 1.18 09/26/01 16:02:49 paulus
- */
 #ifdef __KERNEL__
 #ifndef __PPC_MMU_CONTEXT_H
 #define __PPC_MMU_CONTEXT_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/module.h linux-2.4.21-pre6/include/asm-ppc/module.h
--- linux-2.4.20/include/asm-ppc/module.h	2001-09-13 23:33:03.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/module.h	2003-03-26 23:49:21.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.module.h 1.5 05/17/01 18:14:25 cort
- */
 #ifndef _ASM_PPC_MODULE_H
 #define _ASM_PPC_MODULE_H
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/mpc10x.h linux-2.4.21-pre6/include/asm-ppc/mpc10x.h
--- linux-2.4.20/include/asm-ppc/mpc10x.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/mpc10x.h	2003-03-26 23:49:40.000000000 +0000
@@ -0,0 +1,167 @@
+/*
+ * arch/ppc/kernel/mpc10x.h
+ * 
+ * Common routines for the Motorola SPS MPC106/8240/107 Host bridge/Mem
+ * ctlr/EPIC/etc.
+ *
+ * Author: Mark A. Greer
+ *         mgreer@mvista.com
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+#ifndef __PPC_KERNEL_MPC10X_H
+#define __PPC_KERNEL_MPC10X_H
+
+#include <linux/pci_ids.h>
+#include <asm/pci-bridge.h>
+
+/*
+ * The values here don't completely map everything but should work in most
+ * cases.
+ *
+ * MAP A (PReP Map)
+ *   Processor: 0x80000000 - 0x807fffff -> PCI I/O: 0x00000000 - 0x007fffff
+ *   Processor: 0xc0000000 - 0xdfffffff -> PCI MEM: 0x00000000 - 0x1fffffff
+ *   PCI MEM:   0x80000000 -> Processor System Memory: 0x00000000
+ *   EUMB mapped to: ioremap_base - 0x00100000 (ioremap_base - 1 MB)
+ *
+ * MAP B (CHRP Map)
+ *   Processor: 0xfe000000 - 0xfebfffff -> PCI I/O: 0x00000000 - 0x00bfffff
+ *   Processor: 0x80000000 - 0xbfffffff -> PCI MEM: 0x80000000 - 0xbfffffff
+ *   PCI MEM:   0x00000000 -> Processor System Memory: 0x00000000
+ *   EUMB mapped to: ioremap_base - 0x00100000 (ioremap_base - 1 MB)
+ */
+
+/*
+ * Define the vendor/device IDs for the various bridges--should be added to
+ * <linux/pci_ids.h>
+ */
+#define	MPC10X_BRIDGE_106	((PCI_DEVICE_ID_MOTOROLA_MPC106 << 16) |  \
+				  PCI_VENDOR_ID_MOTOROLA)
+#define	MPC10X_BRIDGE_8240	((0x0003 << 16) | PCI_VENDOR_ID_MOTOROLA)
+#define	MPC10X_BRIDGE_107	((0x0004 << 16) | PCI_VENDOR_ID_MOTOROLA)
+#define	MPC10X_BRIDGE_8245	((0x0006 << 16) | PCI_VENDOR_ID_MOTOROLA)
+
+/* Define the type of map to use */
+#define	MPC10X_MEM_MAP_A		1
+#define	MPC10X_MEM_MAP_B		2
+
+/* Map A (PReP Map) Defines */
+#define	MPC10X_MAPA_CNFG_ADDR		0x80000cf8
+#define	MPC10X_MAPA_CNFG_DATA		0x80000cfc
+
+#define MPC10X_MAPA_ISA_IO_BASE		0x80000000
+#define MPC10X_MAPA_ISA_MEM_BASE	0xc0000000
+#define	MPC10X_MAPA_DRAM_OFFSET		0x80000000
+
+#define	MPC10X_MAPA_PCI_IO_START	0x00000000
+#define	MPC10X_MAPA_PCI_IO_END	       (0x00800000 - 1)
+#define	MPC10X_MAPA_PCI_MEM_START	0x00000000
+#define	MPC10X_MAPA_PCI_MEM_END	       (0x20000000 - 1)
+
+#define	MPC10X_MAPA_PCI_MEM_OFFSET	(MPC10X_MAPA_ISA_MEM_BASE -	\
+					 MPC10X_MAPA_PCI_MEM_START)
+
+/* Map B (CHRP Map) Defines */
+#define	MPC10X_MAPB_CNFG_ADDR		0xfec00000
+#define	MPC10X_MAPB_CNFG_DATA		0xfee00000
+
+#define MPC10X_MAPB_ISA_IO_BASE		0xfe000000
+#define MPC10X_MAPB_ISA_MEM_BASE	0x80000000
+#define	MPC10X_MAPB_DRAM_OFFSET		0x00000000
+
+#define	MPC10X_MAPB_PCI_IO_START	0x00000000
+#define	MPC10X_MAPB_PCI_IO_END	       (0x00c00000 - 1)
+#define	MPC10X_MAPB_PCI_MEM_START	0x80000000
+#define	MPC10X_MAPB_PCI_MEM_END	       (0xc0000000 - 1)
+
+#define	MPC10X_MAPB_PCI_MEM_OFFSET	(MPC10X_MAPB_ISA_MEM_BASE -	\
+					 MPC10X_MAPB_PCI_MEM_START)
+
+/* Set hose members to values appropriate for the mem map used */
+#define	MPC10X_SETUP_HOSE(hose, map) {					\
+	(hose)->pci_mem_offset = MPC10X_MAP##map##_PCI_MEM_OFFSET;	\
+	(hose)->io_space.start = MPC10X_MAP##map##_PCI_IO_START;	\
+	(hose)->io_space.end = MPC10X_MAP##map##_PCI_IO_END;		\
+	(hose)->mem_space.start = MPC10X_MAP##map##_PCI_MEM_START;	\
+	(hose)->mem_space.end = MPC10X_MAP##map##_PCI_MEM_END;		\
+	(hose)->io_base_virt = (void *)MPC10X_MAP##map##_ISA_IO_BASE;	\
+}
+
+
+/* Miscellaneous Configuration register offsets */
+#define	MPC10X_CFG_PIR_REG		0x09
+#define	MPC10X_CFG_PIR_HOST_BRIDGE	0x00
+#define	MPC10X_CFG_PIR_AGENT		0x01
+
+#define	MPC10X_CFG_EUMBBAR		0x78
+
+#define	MPC10X_CFG_PICR1_REG		0xa8
+#define	MPC10X_CFG_PICR1_ADDR_MAP_MASK	0x00010000
+#define	MPC10X_CFG_PICR1_ADDR_MAP_A	0x00010000
+#define	MPC10X_CFG_PICR1_ADDR_MAP_B	0x00000000
+#define	MPC10X_CFG_PICR1_ST_GATH_EN	0x00000040
+
+#define	MPC10X_CFG_MAPB_OPTIONS_REG	0xe0
+#define	MPC10X_CFG_MAPB_OPTIONS_CFAE	0x80	/* CPU_FD_ALIAS_EN */
+#define	MPC10X_CFG_MAPB_OPTIONS_PFAE	0x40	/* PCI_FD_ALIAS_EN */
+#define	MPC10X_CFG_MAPB_OPTIONS_DR	0x20	/* DLL_RESET */
+#define	MPC10X_CFG_MAPB_OPTIONS_PCICH	0x80	/* PCI_COMPATIBILITY_HOLE */
+#define	MPC10X_CFG_MAPB_OPTIONS_PROCCH	0x40	/* PROC_COMPATIBILITY_HOLE */
+
+/* Define offsets for the memory controller registers in the config space */
+#define MPC10X_MCTLR_MEM_START_1	0x80	/* Banks 0-3 */
+#define MPC10X_MCTLR_MEM_START_2	0x84	/* Banks 4-7 */
+#define MPC10X_MCTLR_EXT_MEM_START_1	0x88	/* Banks 0-3 */
+#define MPC10X_MCTLR_EXT_MEM_START_2	0x8c	/* Banks 4-7 */
+
+#define MPC10X_MCTLR_MEM_END_1		0x90	/* Banks 0-3 */
+#define MPC10X_MCTLR_MEM_END_2i		0x94	/* Banks 4-7 */
+#define MPC10X_MCTLR_EXT_MEM_END_1	0x98	/* Banks 0-3 */
+#define MPC10X_MCTLR_EXT_MEM_END_2	0x9c	/* Banks 4-7 */
+
+#define MPC10X_MCTLR_MEM_BANK_ENABLES	0xa0
+
+/* Define some offset in the EUMB */
+#define	MPC10X_EUMB_SIZE		0x00100000 /* Total EUMB size (1MB) */
+
+#define MPC10X_EUMB_MU_OFFSET		0x00000000 /* Msg Unit reg offset */
+#define MPC10X_EUMB_MU_SIZE		0x00001000 /* Msg Unit reg size */
+#define MPC10X_EUMB_DMA_OFFSET		0x00001000 /* DMA Unit reg offset */
+#define MPC10X_EUMB_DMA_SIZE		0x00001000 /* DMA Unit reg size  */
+#define MPC10X_EUMB_ATU_OFFSET		0x00002000 /* Addr xlate reg offset */
+#define MPC10X_EUMB_ATU_SIZE		0x00001000 /* Addr xlate reg size  */
+#define MPC10X_EUMB_I2C_OFFSET		0x00003000 /* I2C Unit reg offset */
+#define MPC10X_EUMB_I2C_SIZE		0x00001000 /* I2C Unit reg size  */
+#define MPC10X_EUMB_DUART_OFFSET	0x00004000 /* DUART Unit reg offset (8245) */
+#define MPC10X_EUMB_DUART_SIZE		0x00001000 /* DUART Unit reg size (8245) */
+#define	MPC10X_EUMB_EPIC_OFFSET		0x00040000 /* EPIC offset in EUMB */
+#define	MPC10X_EUMB_EPIC_SIZE		0x00030000 /* EPIC size */
+#define MPC10X_EUMB_PM_OFFSET		0x000fe000 /* Performance Monitor reg offset (8245) */
+#define MPC10X_EUMB_PM_SIZE		0x00001000 /* Performance Monitor reg size (8245) */
+#define MPC10X_EUMB_WP_OFFSET		0x000ff000 /* Data path diagnostic, watchpoint reg offset */
+#define MPC10X_EUMB_WP_SIZE		0x00001000 /* Data path diagnostic, watchpoint reg size */
+
+/*
+ * Define some recommended places to put the EUMB regs.
+ * For both maps, recommend putting the EUMB from 0xeff00000 to 0xefffffff.
+ */
+extern unsigned long			ioremap_base;
+#define	MPC10X_MAPA_EUMB_BASE		(ioremap_base - MPC10X_EUMB_SIZE)
+#define	MPC10X_MAPB_EUMB_BASE		MPC10X_MAPA_EUMB_BASE
+
+
+int mpc10x_bridge_init(struct pci_controller *hose,
+		       uint current_map,
+		       uint new_map,
+		       uint phys_eumb_base);
+unsigned long mpc10x_get_mem_size(uint mem_map);
+int mpc10x_enable_store_gathering(struct pci_controller *hose);
+int mpc10x_disable_store_gathering(struct pci_controller *hose);
+
+#endif	/* __PPC_KERNEL_MPC10X_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/mpc8260.h linux-2.4.21-pre6/include/asm-ppc/mpc8260.h
--- linux-2.4.20/include/asm-ppc/mpc8260.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/mpc8260.h	2003-03-26 23:48:57.000000000 +0000
@@ -1,7 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
-
 /* This is the single file included by all MPC8260 build options.
  * Since there are many different boards and no standard configuration,
  * we have a unique include file for each.  Rather than change every
@@ -27,20 +23,14 @@
 #define _ISA_MEM_BASE   0
 #define PCI_DRAM_OFFSET 0
 
+#ifndef __ASSEMBLY__
 /* The "residual" data board information structure the boot loader
  * hands to us.
  */
 extern unsigned char __res[];
+#endif /* __ASSEMBLY__ */
 
-/* I need this to get pt_regs.......
-*/
-#include <asm/ptrace.h>
-
-extern int request_8xxirq(unsigned int irq,
-		       void (*handler)(int, void *, struct pt_regs *),
-		       unsigned long flags, 
-		       const char *device,
-		       void *dev_id);
+#define request_8xxirq request_irq
 
 #endif /* CONFIG_8260 */
 #endif /* !__CONFIG_8260_DEFS */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/mpc8xx.h linux-2.4.21-pre6/include/asm-ppc/mpc8xx.h
--- linux-2.4.20/include/asm-ppc/mpc8xx.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/mpc8xx.h	2003-03-26 23:49:54.000000000 +0000
@@ -1,7 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
-
 /* This is the single file included by all MPC8xx build options.
  * Since there are many different boards and no standard configuration,
  * we have a unique include file for each.  Rather than change every
@@ -49,26 +45,32 @@
 #endif
 
 
-/* Currently, all 8xx boards that support a processor to PCI/ISA bridge
- * use the same memory map.
- */
-#if 0
-#if defined(CONFIG_PCI) && defined(PCI_ISA_IO_ADDR)
+/* The PCI_ISA_IO_ADDR, PCI_ISA_MEM_ADDR, and PCI_DRAM_OFFSET macros
+ * must be defined in the board-specific header file for targets that
+ * need them.  Default values are defined here for targets that don't need
+ * them.
+  */
+#if defined(CONFIG_PCI)
+#if !defined(_IO_BASE)
 #define	_IO_BASE PCI_ISA_IO_ADDR
+#endif
+#if !defined(_ISA_MEM_BASE)
 #define	_ISA_MEM_BASE PCI_ISA_MEM_ADDR
-#define PCI_DRAM_OFFSET 0x80000000
-#else
-#define _IO_BASE        0
-#define _ISA_MEM_BASE   0
+#endif
+#if !defined(PCI_DRAM_OFFSET)
 #define PCI_DRAM_OFFSET 0
 #endif
-#else
-#if !defined(_IO_BASE)  /* defined in board specific header */
+#else	/* if defined(CONFIG_PCI) */
+#if !defined(_IO_BASE)
 #define _IO_BASE        0
 #endif
+#if !defined(_ISA_MEM_BASE)
 #define _ISA_MEM_BASE   0
+#endif
+#if !defined(PCI_DRAM_OFFSET)
 #define PCI_DRAM_OFFSET 0
 #endif
+#endif	/* if defined(CONFIG_PCI) */
 
 #ifndef __ASSEMBLY__
 extern unsigned long isa_io_base;
@@ -80,12 +82,8 @@
  */
 extern unsigned char __res[];
 
-struct pt_regs;
-extern int request_8xxirq(unsigned int irq,
-		       void (*handler)(int, void *, struct pt_regs *),
-		       unsigned long flags, 
-		       const char *device,
-		       void *dev_id);
+#define request_8xxirq request_irq
+
 #endif /* !__ASSEMBLY__ */
 #endif /* CONFIG_8xx */
 #endif /* __CONFIG_8xx_DEFS */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/msgbuf.h linux-2.4.21-pre6/include/asm-ppc/msgbuf.h
--- linux-2.4.20/include/asm-ppc/msgbuf.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/msgbuf.h	2003-03-26 23:48:59.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.msgbuf.h 1.5 05/17/01 18:14:25 cort
- */
 #ifndef _PPC_MSGBUF_H
 #define _PPC_MSGBUF_H
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/namei.h linux-2.4.21-pre6/include/asm-ppc/namei.h
--- linux-2.4.20/include/asm-ppc/namei.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/namei.h	2003-03-26 23:49:50.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.namei.h 1.5 05/17/01 18:14:25 cort
- */
 /* linux/include/asm-ppc/namei.h
  * Adapted from linux/include/asm-alpha/namei.h
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/nvram.h linux-2.4.21-pre6/include/asm-ppc/nvram.h
--- linux-2.4.20/include/asm-ppc/nvram.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/nvram.h	2003-03-26 23:49:55.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.nvram.h 1.5 05/17/01 18:14:25 cort
- */
-/*
  * PreP compliant NVRAM access
  */
 
@@ -42,8 +39,6 @@
 	pmac_nvram_NR		/* MacOS Name Registry partition */
 };
 
-#ifdef __KERNEL__
-
 /* Return partition offset in nvram */
 extern int	pmac_get_partition(int partition);
 
@@ -51,8 +46,6 @@
 extern u8	pmac_xpram_read(int xpaddr);
 extern void	pmac_xpram_write(int xpaddr, u8 data);
 
-#endif /* __KERNEL__ */
-
 /* Some offsets in XPRAM */
 #define PMAC_XPRAM_MACHINE_LOC	0xe4
 #define PMAC_XPRAM_SOUND_VOLUME	0x08
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/ohare.h linux-2.4.21-pre6/include/asm-ppc/ohare.h
--- linux-2.4.20/include/asm-ppc/ohare.h	2002-02-25 19:38:12.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/ohare.h	2003-03-26 23:49:08.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.ohare.h 1.8 12/01/01 20:09:11 benh
- */
-/*
  * ohare.h: definitions for using the "O'Hare" I/O controller chip.
  *
  * Copyright (C) 1997 Paul Mackerras.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/open_pic.h linux-2.4.21-pre6/include/asm-ppc/open_pic.h
--- linux-2.4.20/include/asm-ppc/open_pic.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/open_pic.h	2003-03-26 23:49:26.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/kernel/open_pic.h -- OpenPIC Interrupt Handling
  *
  *  Copyright (C) 1997 Geert Uytterhoeven
@@ -42,7 +39,10 @@
 
 /* Exported functions */
 extern void openpic_set_sources(int first_irq, int num_irqs, void *isr);
-extern void openpic_init(int, int, unsigned char *, int);
+extern void openpic_init(int linux_irq_offset);
+extern void openpic_init_nmi_irq(u_int irq);
+extern void openpic_hookup_cascade(u_int irq, char *name,
+				   int (*cascade_fn)(struct pt_regs *));
 extern u_int openpic_irq(void);
 extern void openpic_eoi(void);
 extern void openpic_request_IPIs(void);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/page.h linux-2.4.21-pre6/include/asm-ppc/page.h
--- linux-2.4.20/include/asm-ppc/page.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/page.h	2003-03-26 23:49:20.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.page.h 1.8 08/19/01 20:06:47 paulus
- */
 #ifndef _PPC_PAGE_H
 #define _PPC_PAGE_H
 
@@ -76,7 +73,7 @@
 
 
 /* align addr on a size boundry - adjust address up if needed -- Cort */
-#define _ALIGN(addr,size)	(((addr)+size-1)&(~(size-1)))
+#define _ALIGN(addr,size)	(((addr)+(size)-1)&(~((size)-1)))
 
 /* to align the pointer to the (next) page boundary */
 #define PAGE_ALIGN(addr)	(((addr)+PAGE_SIZE-1)&PAGE_MASK)
@@ -86,6 +83,17 @@
 extern void clear_user_page(void *page, unsigned long vaddr);
 extern void copy_user_page(void *to, void *from, unsigned long vaddr);
 
+extern unsigned long ppc_memstart;
+extern unsigned long ppc_memoffset;
+#ifndef CONFIG_APUS
+#define PPC_MEMSTART	0
+#define PPC_MEMOFFSET	PAGE_OFFSET
+#else
+#define PPC_MEMSTART	ppc_memstart
+#define PPC_MEMOFFSET	ppc_memoffset
+#endif
+
+#if defined(CONFIG_APUS) && !defined(MODULE)
 /* map phys->virtual and virtual->phys for RAM pages */
 static inline unsigned long ___pa(unsigned long v)
 { 
@@ -113,12 +121,17 @@
 
 	return (void*) v;
 }
-#define __pa(x) ___pa ((unsigned long)(x))
-#define __va(x) ___va ((unsigned long)(x))
+#else
+#define ___pa(vaddr) ((vaddr)-PPC_MEMOFFSET)
+#define ___va(paddr) ((paddr)+PPC_MEMOFFSET)
+#endif
+
+#define __pa(x) ___pa((unsigned long)(x))
+#define __va(x) ((void *)(___va((unsigned long)(x))))
 
 #define MAP_PAGE_RESERVED	(1<<15)
-#define virt_to_page(kaddr)	(mem_map + (((unsigned long)kaddr-PAGE_OFFSET) >> PAGE_SHIFT))
-#define VALID_PAGE(page)	((page - mem_map) < max_mapnr)
+#define virt_to_page(kaddr)	(mem_map + (((unsigned long)(kaddr)-PAGE_OFFSET) >> PAGE_SHIFT))
+#define VALID_PAGE(page)	(((page) - mem_map) < max_mapnr)
 
 extern unsigned long get_zero_page_fast(void);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/param.h linux-2.4.21-pre6/include/asm-ppc/param.h
--- linux-2.4.20/include/asm-ppc/param.h	2001-08-28 13:58:33.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/param.h	2003-03-26 23:49:31.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.param.h 1.8 08/20/01 22:50:29 paulus
- */
 #ifndef _ASM_PPC_PARAM_H
 #define _ASM_PPC_PARAM_H
 
@@ -22,6 +19,6 @@
 
 #ifdef __KERNEL__
 # define CLOCKS_PER_SEC	HZ	/* frequency at which times() counts */
-#endif
+#endif /* __KERNEL__ */
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/parport.h linux-2.4.21-pre6/include/asm-ppc/parport.h
--- linux-2.4.20/include/asm-ppc/parport.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/parport.h	2003-03-26 23:49:50.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.parport.h 1.5 05/17/01 18:14:25 cort
- */
-/*
  * parport.h: platform-specific PC-style parport initialisation
  *
  * Copyright (C) 1999, 2000  Tim Waugh <tim@cyberelk.demon.co.uk>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/pci-bridge.h linux-2.4.21-pre6/include/asm-ppc/pci-bridge.h
--- linux-2.4.20/include/asm-ppc/pci-bridge.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/pci-bridge.h	2003-03-26 23:49:02.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #ifdef __KERNEL__
 #ifndef _ASM_PCI_BRIDGE_H
 #define _ASM_PCI_BRIDGE_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/pci.h linux-2.4.21-pre6/include/asm-ppc/pci.h
--- linux-2.4.20/include/asm-ppc/pci.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/pci.h	2003-03-26 23:49:50.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.pci.h 1.16 10/15/01 22:51:33 paulus
- */
 #ifndef __PPC_PCI_H
 #define __PPC_PCI_H
 #ifdef __KERNEL__
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/pgalloc.h linux-2.4.21-pre6/include/asm-ppc/pgalloc.h
--- linux-2.4.20/include/asm-ppc/pgalloc.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/pgalloc.h	2003-03-26 23:48:57.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.pgalloc.h 1.9 05/17/01 18:14:25 cort
- */
 #ifdef __KERNEL__
 #ifndef _PPC_PGALLOC_H
 #define _PPC_PGALLOC_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/pgtable.h linux-2.4.21-pre6/include/asm-ppc/pgtable.h
--- linux-2.4.20/include/asm-ppc/pgtable.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/pgtable.h	2003-03-26 23:49:18.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #ifdef __KERNEL__
 #ifndef _PPC_PGTABLE_H
 #define _PPC_PGTABLE_H
@@ -333,7 +330,7 @@
 #define	pmd_present(pmd)	((pmd_val(pmd) & PAGE_MASK) != 0)
 #define	pmd_clear(pmdp)		do { pmd_val(*(pmdp)) = 0; } while (0)
 
-#define pte_page(x)		(mem_map+(unsigned long)((pte_val(x) >> PAGE_SHIFT)))
+#define pte_page(x)		(mem_map+(unsigned long)((pte_val(x)-PPC_MEMSTART) >> PAGE_SHIFT))
 
 #ifndef __ASSEMBLY__
 /*
@@ -399,7 +396,7 @@
 #define mk_pte(page,pgprot) \
 ({									\
 	pte_t pte;							\
-	pte_val(pte) = ((page - mem_map) << PAGE_SHIFT) | pgprot_val(pgprot); \
+	pte_val(pte) = (((page - mem_map) << PAGE_SHIFT) + PPC_MEMSTART) | pgprot_val(pgprot); \
 	pte;							\
 })
 
@@ -423,8 +420,9 @@
 	__asm__ __volatile__("\
 1:	lwarx	%0,0,%3\n\
 	andc	%1,%0,%4\n\
-	or	%1,%1,%5\n\
-	stwcx.	%1,0,%3\n\
+	or	%1,%1,%5\n"
+	PPC405_ERR77(0,%3)
+"	stwcx.	%1,0,%3\n\
 	bne-	1b"
 	: "=&r" (old), "=&r" (tmp), "=m" (*p)
 	: "r" (p), "r" (clr), "r" (set), "m" (*p)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/pmac_feature.h linux-2.4.21-pre6/include/asm-ppc/pmac_feature.h
--- linux-2.4.20/include/asm-ppc/pmac_feature.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/pmac_feature.h	2003-03-26 23:49:10.000000000 +0000
@@ -32,9 +32,13 @@
 #define __PPC_ASM_PMAC_FEATURE_H
 
 /*
- * Known Mac motherboard models
+ * Known OldWorld Mac motherboard models
  * 
  * Please, report any error here to benh@kernel.crashing.org, thanks !
+ * 
+ * Note that I don't fully maintain this list for Core99 & MacRISC2
+ * and I'm considering removing all NewWorld entries from it and
+ * entirely rely on the model string.
  */
 
 /* PowerSurge are the first generation of PCI Pmacs. This include
@@ -85,8 +89,9 @@
 #define PMAC_TYPE_QUICKSILVER		0x45	/* QuickSilver G4s */
 #define PMAC_TYPE_PISMO			0x46	/* Pismo PowerBook */
 #define PMAC_TYPE_TITANIUM		0x47	/* Titanium PowerBook */
-#define PMAC_TYPE_TITANIUM2		0x48	/* Titanium II PowerBook */
-#define PMAC_TYPE_TITANIUM3		0x49	/* Titanium III PowerBook (with L3) */
+#define PMAC_TYPE_TITANIUM2		0x48	/* Titanium II PowerBook (no L3, M6) */
+#define PMAC_TYPE_TITANIUM3		0x49	/* Titanium III PowerBook (with L3 & M7) */
+#define PMAC_TYPE_TITANIUM4		0x50	/* Titanium IV PowerBook (with L3 & M9) */
 #define PMAC_TYPE_EMAC			0x50	/* eMac */
 #define PMAC_TYPE_UNKNOWN_CORE99	0x5f
 
@@ -101,6 +106,10 @@
 #define PMAC_TYPE_FLAT_PANEL_IMAC	0x102	/* Flat panel iMac */
 #define PMAC_TYPE_UNKNOWN_PANGEA	0x10f
 
+/* MacRISC2 machines based on the Intrepid chipset
+ */
+#define PMAC_TYPE_UNKNOWN_INTREPID	0x11f	/* Generic */
+
 /*
  * Motherboard flags
  */
@@ -108,6 +117,7 @@
 #define PMAC_MB_CAN_SLEEP		0x00000001
 #define PMAC_MB_HAS_FW_POWER		0x00000002
 #define PMAC_MB_OLD_CORE99		0x00000004
+#define PMAC_MB_MOBILE			0x00000008
 
 /*
  * Feature calls supported on pmac
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/pnp.h linux-2.4.21-pre6/include/asm-ppc/pnp.h
--- linux-2.4.20/include/asm-ppc/pnp.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/pnp.h	2003-03-26 23:48:58.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.pnp.h 1.5 05/17/01 18:14:25 cort
- */
 #ifdef __KERNEL__
 /* 11/02/95                                                                   */
 /*----------------------------------------------------------------------------*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/poll.h linux-2.4.21-pre6/include/asm-ppc/poll.h
--- linux-2.4.20/include/asm-ppc/poll.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/poll.h	2003-03-26 23:49:34.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.poll.h 1.5 05/17/01 18:14:25 cort
- */
 #ifndef __PPC_POLL_H
 #define __PPC_POLL_H
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/posix_types.h linux-2.4.21-pre6/include/asm-ppc/posix_types.h
--- linux-2.4.20/include/asm-ppc/posix_types.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/posix_types.h	2003-03-26 23:49:34.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.posix_types.h 1.5 05/17/01 18:14:25 cort
- */
 #ifndef _PPC_POSIX_TYPES_H
 #define _PPC_POSIX_TYPES_H
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/ppc4xx.h linux-2.4.21-pre6/include/asm-ppc/ppc4xx.h
--- linux-2.4.20/include/asm-ppc/ppc4xx.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/ppc4xx.h	2003-03-26 23:49:39.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.ppc4xx.h 1.3 05/17/01 18:14:25 cort
- */
-/*
  *
  *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/ppc4xx_pic.h linux-2.4.21-pre6/include/asm-ppc/ppc4xx_pic.h
--- linux-2.4.20/include/asm-ppc/ppc4xx_pic.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/ppc4xx_pic.h	2003-03-26 23:49:29.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.ppc4xx_pic.h 1.8 06/15/01 13:56:56 paulus
- */
-/*
  *
  *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/ppc4xx_serial.h linux-2.4.21-pre6/include/asm-ppc/ppc4xx_serial.h
--- linux-2.4.20/include/asm-ppc/ppc4xx_serial.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/ppc4xx_serial.h	2003-03-26 23:49:19.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.ppc4xx_serial.h 1.3 05/17/01 18:14:25 cort
- */
-/*
  *    Copyright 2000 MontaVista Software Inc.
  *	PPC405GP modifications
  * 	Author: MontaVista Software, Inc.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/ppc_asm.h linux-2.4.21-pre6/include/asm-ppc/ppc_asm.h
--- linux-2.4.20/include/asm-ppc/ppc_asm.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/ppc_asm.h	2003-03-26 23:49:00.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * include/asm-ppc/ppc_asm.h
  *
  * Definitions used by various bits of low-level assembly code on PowerPC.
@@ -155,6 +152,14 @@
 #define CLR_TOP32(r)
 #endif /* CONFIG_PPC64BRIDGE */
 
+#ifdef CONFIG_IBM405_ERR77
+#define PPC405_ERR77(ra,rb)	dcbt	ra, rb;
+#define	PPC405_ERR77_SYNC	sync;
+#else
+#define PPC405_ERR77(ra,rb)
+#define PPC405_ERR77_SYNC
+#endif
+
 /* The boring bits... */
 
 /* Condition Register Bit Fields */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/prep_nvram.h linux-2.4.21-pre6/include/asm-ppc/prep_nvram.h
--- linux-2.4.20/include/asm-ppc/prep_nvram.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/prep_nvram.h	2003-03-26 23:49:50.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.prep_nvram.h 1.7 05/17/01 18:14:25 cort
- */
-/*
  * PreP compliant NVRAM access
  */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/processor.h linux-2.4.21-pre6/include/asm-ppc/processor.h
--- linux-2.4.20/include/asm-ppc/processor.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/processor.h	2003-03-26 23:48:58.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #ifdef __KERNEL__
 #ifndef __ASM_PPC_PROCESSOR_H
 #define __ASM_PPC_PROCESSOR_H
@@ -12,6 +9,7 @@
 #define current_text_addr() ({ __label__ _l; _l: &&_l;})
 
 #include <linux/config.h>
+#include <linux/stringify.h>
 
 #include <asm/ptrace.h>
 #include <asm/types.h>
@@ -452,7 +450,8 @@
 #define	ICMP	SPRN_ICMP	/* Instruction TLB Compare Register */
 #define	IMISS	SPRN_IMISS	/* Instruction TLB Miss Register */
 #define	IMMR	SPRN_IMMR      	/* PPC 860/821 Internal Memory Map Register */
-#define	L2CR	SPRN_L2CR    	/* PPC 750 L2 control register */
+#define	L2CR	SPRN_L2CR    	/* Classic PPC L2 cache control register */
+#define	L3CR	SPRN_L3CR	/* PPC 745x L3 cache control register */
 #define	LR	SPRN_LR
 #define	PVR	SPRN_PVR	/* Processor Version */
 #define	RPA	SPRN_RPA	/* Required Physical Address Register */
@@ -565,22 +564,19 @@
 
 /* Macros for setting and retrieving special purpose registers */
 
-#define stringify(s)	tostring(s)
-#define tostring(s)	#s
-
 #define mfdcr(rn)	({unsigned int rval; \
-			asm volatile("mfdcr %0," stringify(rn) \
+			asm volatile("mfdcr %0," __stringify(rn) \
 				     : "=r" (rval)); rval;})
-#define mtdcr(rn, v)	asm volatile("mtdcr " stringify(rn) ",%0" : : "r" (v))
+#define mtdcr(rn, v)	asm volatile("mtdcr " __stringify(rn) ",%0" : : "r" (v))
 
 #define mfmsr()		({unsigned int rval; \
 			asm volatile("mfmsr %0" : "=r" (rval)); rval;})
 #define mtmsr(v)	asm volatile("mtmsr %0" : : "r" (v))
 
 #define mfspr(rn)	({unsigned int rval; \
-			asm volatile("mfspr %0," stringify(rn) \
+			asm volatile("mfspr %0," __stringify(rn) \
 				     : "=r" (rval)); rval;})
-#define mtspr(rn, v)	asm volatile("mtspr " stringify(rn) ",%0" : : "r" (v))
+#define mtspr(rn, v)	asm volatile("mtspr " __stringify(rn) ",%0" : : "r" (v))
 
 /* Segment Registers */
 
@@ -626,7 +622,7 @@
 /*
  * Create a new kernel thread.
  */
-extern long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
+extern long arch_kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
 
 /*
  * Bus types
@@ -659,10 +655,10 @@
 
 struct thread_struct {
 	unsigned long	ksp;		/* Kernel stack pointer */
-	unsigned long	wchan;		/* Event task is sleeping on */
 	struct pt_regs	*regs;		/* Pointer to saved register state */
 	mm_segment_t	fs;		/* for get_fs() validation */
 	void		*pgdir;		/* root of page-table tree */
+	int		fpexc_mode;	/* floating-point exception mode */
 	signed long     last_syscall;
 	double		fpr[32];	/* Complete floating point set */
 	unsigned long	fpscr_pad;	/* fpr ... fpscr must be contiguous */
@@ -677,13 +673,10 @@
 #define INIT_SP		(sizeof(init_stack) + (unsigned long) &init_stack)
 
 #define INIT_THREAD  { \
-	INIT_SP, /* ksp */ \
-	0, /* wchan */ \
-	0, /* regs */ \
-	KERNEL_DS, /*fs*/ \
-	swapper_pg_dir, /* pgdir */ \
-	0, /* last_syscall */ \
-	{0}, 0, 0 \
+	.ksp = INIT_SP, \
+	.fs = KERNEL_DS, \
+	.pgdir = swapper_pg_dir, \
+	.fpexc_mode = MSR_FE0 | MSR_FE1, \
 }
 
 /*
@@ -702,6 +695,13 @@
 #define KSTK_EIP(tsk)  ((tsk)->thread.regs? (tsk)->thread.regs->nip: 0)
 #define KSTK_ESP(tsk)  ((tsk)->thread.regs? (tsk)->thread.regs->gpr[1]: 0)
 
+/* Get/set floating-point exception mode */
+#define GET_FPEXC_CTL(tsk, adr)	get_fpexc_mode((tsk), (adr))
+#define SET_FPEXC_CTL(tsk, val)	set_fpexc_mode((tsk), (val))
+
+extern int get_fpexc_mode(struct task_struct *tsk, unsigned long adr);
+extern int set_fpexc_mode(struct task_struct *tsk, unsigned int val);
+
 /*
  * NOTE! The task struct and the stack go together
  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/prom.h linux-2.4.21-pre6/include/asm-ppc/prom.h
--- linux-2.4.20/include/asm-ppc/prom.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/prom.h	2003-03-26 23:49:50.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Definitions for talking to the Open Firmware PROM on
  * Power Macintosh computers.
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/ptrace.h linux-2.4.21-pre6/include/asm-ppc/ptrace.h
--- linux-2.4.20/include/asm-ppc/ptrace.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/ptrace.h	2003-03-26 23:48:57.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.ptrace.h 1.8 01/17/02 23:05:50 paulus
- */
 #ifndef _PPC_PTRACE_H
 #define _PPC_PTRACE_H
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/raven.h linux-2.4.21-pre6/include/asm-ppc/raven.h
--- linux-2.4.20/include/asm-ppc/raven.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/raven.h	2003-03-26 23:49:40.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.raven.h 1.7 05/17/01 18:14:25 cort
- */
-/*
  *  asm-ppc/raven.h -- Raven MPIC chip.
  *
  *  Copyright (C) 1998 Johnnie Peters
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/residual.h linux-2.4.21-pre6/include/asm-ppc/residual.h
--- linux-2.4.20/include/asm-ppc/residual.h	2001-08-28 13:58:33.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/residual.h	2003-03-26 23:49:35.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.residual.h 1.8 08/09/01 09:11:24 trini
- */
 /* 7/18/95                                                                    */
 /*----------------------------------------------------------------------------*/
 /*      Residual Data header definitions and prototypes                       */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/resource.h linux-2.4.21-pre6/include/asm-ppc/resource.h
--- linux-2.4.20/include/asm-ppc/resource.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/resource.h	2003-03-26 23:49:30.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.resource.h 1.5 05/17/01 18:14:25 cort
- */
 #ifndef _PPC_RESOURCE_H
 #define _PPC_RESOURCE_H
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/rwsem.h linux-2.4.21-pre6/include/asm-ppc/rwsem.h
--- linux-2.4.20/include/asm-ppc/rwsem.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/rwsem.h	2003-03-26 23:49:55.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * include/asm-ppc/rwsem.h: R/W semaphores for PPC using the stuff
  * in lib/rwsem.c.  Adapted largely from include/asm-i386/rwsem.h
  * by Paul Mackerras <paulus@samba.org>.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/scatterlist.h linux-2.4.21-pre6/include/asm-ppc/scatterlist.h
--- linux-2.4.20/include/asm-ppc/scatterlist.h	2001-10-21 17:13:07.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/scatterlist.h	2003-03-26 23:48:59.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.scatterlist.h 1.9 10/15/01 22:51:33 paulus
- */
 #ifdef __KERNEL__
 #ifndef _PPC_SCATTERLIST_H
 #define _PPC_SCATTERLIST_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/sections.h linux-2.4.21-pre6/include/asm-ppc/sections.h
--- linux-2.4.20/include/asm-ppc/sections.h	2001-09-08 19:38:42.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/sections.h	2003-03-26 23:49:55.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.sections.h 1.11 09/08/01 15:47:43 paulus
- */
 #ifdef __KERNEL__
 #ifndef _PPC_SECTIONS_H
 #define _PPC_SECTIONS_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/segment.h linux-2.4.21-pre6/include/asm-ppc/segment.h
--- linux-2.4.20/include/asm-ppc/segment.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/segment.h	2003-03-26 23:49:20.000000000 +0000
@@ -1,4 +1 @@
-/*
- * BK Id: SCCS/s.segment.h 1.7 05/17/01 18:14:25 cort
- */
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/semaphore.h linux-2.4.21-pre6/include/asm-ppc/semaphore.h
--- linux-2.4.20/include/asm-ppc/semaphore.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/semaphore.h	2003-03-26 23:49:39.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.semaphore.h 1.15 05/17/01 18:14:25 cort
- */
 #ifndef _PPC_SEMAPHORE_H
 #define _PPC_SEMAPHORE_H
 
@@ -12,7 +9,7 @@
  * -- Ani Joshi (ajoshi@unixbox.com)
  *
  * Remove spinlock-based RW semaphores; RW semaphore definitions are
- * now in rwsem.h and we use the the generic lib/rwsem.c implementation.
+ * now in rwsem.h and we use the generic lib/rwsem.c implementation.
  * Rework semaphores to use atomic_dec_if_positive.
  * -- Paul Mackerras (paulus@samba.org)
  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/sembuf.h linux-2.4.21-pre6/include/asm-ppc/sembuf.h
--- linux-2.4.20/include/asm-ppc/sembuf.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/sembuf.h	2003-03-26 23:49:54.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.sembuf.h 1.5 05/17/01 18:14:25 cort
- */
 #ifndef _PPC_SEMBUF_H
 #define _PPC_SEMBUF_H
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/serial.h linux-2.4.21-pre6/include/asm-ppc/serial.h
--- linux-2.4.20/include/asm-ppc/serial.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/serial.h	2003-03-26 23:49:54.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * include/asm-ppc/serial.h
  */
 
@@ -13,6 +10,8 @@
 
 #if defined(CONFIG_GEMINI)
 #include <platforms/gemini_serial.h>
+#elif defined(CONFIG_LOPEC)
+#include <platforms/lopec_serial.h>
 #elif defined(CONFIG_SPRUCE)
 #include <platforms/spruce.h>
 #elif defined(CONFIG_4xx)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/setup.h linux-2.4.21-pre6/include/asm-ppc/setup.h
--- linux-2.4.20/include/asm-ppc/setup.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/setup.h	2003-03-26 23:49:27.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.setup.h 1.5 05/17/01 18:14:25 cort
- */
 #ifdef __KERNEL__
 #ifndef _PPC_SETUP_H
 #define _PPC_SETUP_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/shmbuf.h linux-2.4.21-pre6/include/asm-ppc/shmbuf.h
--- linux-2.4.20/include/asm-ppc/shmbuf.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/shmbuf.h	2003-03-26 23:49:40.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.shmbuf.h 1.5 05/17/01 18:14:25 cort
- */
 #ifndef _PPC_SHMBUF_H
 #define _PPC_SHMBUF_H
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/shmparam.h linux-2.4.21-pre6/include/asm-ppc/shmparam.h
--- linux-2.4.20/include/asm-ppc/shmparam.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/shmparam.h	2003-03-26 23:49:19.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.shmparam.h 1.5 05/17/01 18:14:25 cort
- */
 #ifndef _PPC_SHMPARAM_H
 #define _PPC_SHMPARAM_H
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/sigcontext.h linux-2.4.21-pre6/include/asm-ppc/sigcontext.h
--- linux-2.4.20/include/asm-ppc/sigcontext.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/sigcontext.h	2003-03-26 23:48:57.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.sigcontext.h 1.5 05/17/01 18:14:25 cort
- */
 #ifndef _ASM_PPC_SIGCONTEXT_H
 #define _ASM_PPC_SIGCONTEXT_H
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/siginfo.h linux-2.4.21-pre6/include/asm-ppc/siginfo.h
--- linux-2.4.20/include/asm-ppc/siginfo.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/siginfo.h	2003-03-26 23:48:57.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.siginfo.h 1.5 05/17/01 18:14:25 cort
- */
 #ifndef _PPC_SIGINFO_H
 #define _PPC_SIGINFO_H
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/signal.h linux-2.4.21-pre6/include/asm-ppc/signal.h
--- linux-2.4.20/include/asm-ppc/signal.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/signal.h	2003-03-26 23:49:02.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.signal.h 1.5 05/17/01 18:14:25 cort
- */
 #ifndef _ASMPPC_SIGNAL_H
 #define _ASMPPC_SIGNAL_H
 
@@ -114,7 +111,7 @@
 #define SA_PROBE		SA_ONESHOT
 #define SA_SAMPLE_RANDOM	SA_RESTART
 #define SA_SHIRQ		0x04000000
-#endif
+#endif /* __KERNEL__ */
 
 #define SIG_BLOCK          0	/* for blocking signals */
 #define SIG_UNBLOCK        1	/* for unblocking signals */
@@ -153,7 +150,6 @@
 
 #ifdef __KERNEL__
 #include <asm/sigcontext.h>
-
-#endif
+#endif /* __KERNEL__ */
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/smp.h linux-2.4.21-pre6/include/asm-ppc/smp.h
--- linux-2.4.20/include/asm-ppc/smp.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/smp.h	2003-03-26 23:49:09.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.smp.h 1.14 03/28/02 16:54:23 hozer
- */
 /* smp.h: PPC specific SMP stuff.
  *
  * Original was a copy of sparc smp.h.  Now heavily modified
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/smplock.h linux-2.4.21-pre6/include/asm-ppc/smplock.h
--- linux-2.4.20/include/asm-ppc/smplock.h	2001-11-03 01:43:54.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/smplock.h	2003-03-26 23:49:19.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.smplock.h 1.10 10/23/01 08:09:35 trini
- */
-/*
  * <asm/smplock.h>
  *
  * Default SMP lock implementation
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/socket.h linux-2.4.21-pre6/include/asm-ppc/socket.h
--- linux-2.4.20/include/asm-ppc/socket.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/socket.h	2003-03-26 23:49:34.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.socket.h 1.6 05/17/01 18:14:25 cort
- */
 #ifndef _ASM_SOCKET_H
 #define _ASM_SOCKET_H
 
@@ -68,6 +65,6 @@
 					/* other similar things on the	*/
 					/* user level.			*/
 #define	SOCK_MAX	(SOCK_PACKET+1)
-#endif
+#endif /* __KERNEL__ */
 
 #endif /* _ASM_SOCKET_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/sockios.h linux-2.4.21-pre6/include/asm-ppc/sockios.h
--- linux-2.4.20/include/asm-ppc/sockios.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/sockios.h	2003-03-26 23:48:58.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.sockios.h 1.5 05/17/01 18:14:25 cort
- */
 #ifndef _ASM_PPC_SOCKIOS_H
 #define _ASM_PPC_SOCKIOS_H
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/softirq.h linux-2.4.21-pre6/include/asm-ppc/softirq.h
--- linux-2.4.20/include/asm-ppc/softirq.h	2001-09-08 19:02:31.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/softirq.h	2003-03-26 23:49:50.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.softirq.h 1.13 07/12/01 20:02:34 paulus
- */
 #ifdef __KERNEL__
 #ifndef __ASM_SOFTIRQ_H
 #define __ASM_SOFTIRQ_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/spinlock.h linux-2.4.21-pre6/include/asm-ppc/spinlock.h
--- linux-2.4.20/include/asm-ppc/spinlock.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/spinlock.h	2003-03-26 23:49:29.000000000 +0000
@@ -1,10 +1,8 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #ifndef __ASM_SPINLOCK_H
 #define __ASM_SPINLOCK_H
 
 #include <asm/system.h>
+#include <asm/processor.h>
 
 #if defined(CONFIG_DEBUG_SPINLOCK)
 #define SPINLOCK_DEBUG 1
@@ -54,14 +52,15 @@
 	unsigned long tmp;
 
 	__asm__ __volatile__(
-	"b	1f			# spin_lock\n\
+	"b	1f		# spin_lock\n\
 2:	lwzx	%0,0,%1\n\
 	cmpwi	0,%0,0\n\
 	bne+	2b\n\
 1:	lwarx	%0,0,%1\n\
 	cmpwi	0,%0,0\n\
-	bne-	2b\n\
-	stwcx.	%2,0,%1\n\
+	bne-	2b\n"
+	PPC405_ERR77(0,%1)
+"	stwcx.	%2,0,%1\n\
 	bne-	2b\n\
 	isync"
 	: "=&r"(tmp)
@@ -124,15 +123,16 @@
 	unsigned int tmp;
 
 	__asm__ __volatile__(
-	"b		2f		# read_lock\n\
-1:	lwzx		%0,0,%1\n\
-	cmpwi		0,%0,0\n\
-	blt+		1b\n\
-2:	lwarx		%0,0,%1\n\
-	addic.		%0,%0,1\n\
-	ble-		1b\n\
-	stwcx.		%0,0,%1\n\
-	bne-		2b\n\
+	"b	2f		# read_lock\n\
+1:	lwzx	%0,0,%1\n\
+	cmpwi	0,%0,0\n\
+	blt+	1b\n\
+2:	lwarx	%0,0,%1\n\
+	addic.	%0,%0,1\n\
+	ble-	1b\n"
+	PPC405_ERR77(0,%1)
+"	stwcx.	%0,0,%1\n\
+	bne-	2b\n\
 	isync"
 	: "=&r"(tmp)
 	: "r"(&rw->lock)
@@ -144,11 +144,12 @@
 	unsigned int tmp;
 
 	__asm__ __volatile__(
-	"eieio				# read_unlock\n\
-1:	lwarx		%0,0,%1\n\
-	addic		%0,%0,-1\n\
-	stwcx.		%0,0,%1\n\
-	bne-		1b"
+	"eieio			# read_unlock\n\
+1:	lwarx	%0,0,%1\n\
+	addic	%0,%0,-1\n"
+	PPC405_ERR77(0,%1)
+"	stwcx.	%0,0,%1\n\
+	bne-	1b"
 	: "=&r"(tmp)
 	: "r"(&rw->lock)
 	: "cr0", "memory");
@@ -159,15 +160,16 @@
 	unsigned int tmp;
 
 	__asm__ __volatile__(
-	"b		2f		# write_lock\n\
-1:	lwzx		%0,0,%1\n\
-	cmpwi		0,%0,0\n\
-	bne+		1b\n\
-2:	lwarx		%0,0,%1\n\
-	cmpwi		0,%0,0\n\
-	bne-		1b\n\
-	stwcx.		%2,0,%1\n\
-	bne-		2b\n\
+	"b	2f		# write_lock\n\
+1:	lwzx	%0,0,%1\n\
+	cmpwi	0,%0,0\n\
+	bne+	1b\n\
+2:	lwarx	%0,0,%1\n\
+	cmpwi	0,%0,0\n\
+	bne-	1b\n"
+	PPC405_ERR77(0,%1)
+"	stwcx.	%2,0,%1\n\
+	bne-	2b\n\
 	isync"
 	: "=&r"(tmp)
 	: "r"(&rw->lock), "r"(-1)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/stat.h linux-2.4.21-pre6/include/asm-ppc/stat.h
--- linux-2.4.20/include/asm-ppc/stat.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/stat.h	2003-03-26 23:48:58.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.stat.h 1.5 05/17/01 18:14:26 cort
- */
 #ifndef _PPC_STAT_H
 #define _PPC_STAT_H
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/statfs.h linux-2.4.21-pre6/include/asm-ppc/statfs.h
--- linux-2.4.20/include/asm-ppc/statfs.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/statfs.h	2003-03-26 23:49:07.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.statfs.h 1.5 05/17/01 18:14:26 cort
- */
 #ifndef _PPC_STATFS_H
 #define _PPC_STATFS_H
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/string.h linux-2.4.21-pre6/include/asm-ppc/string.h
--- linux-2.4.20/include/asm-ppc/string.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/string.h	2003-03-26 23:49:50.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.string.h 1.5 05/17/01 18:14:26 cort
- */
 #ifndef _PPC_STRING_H_
 #define _PPC_STRING_H_
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/system.h linux-2.4.21-pre6/include/asm-ppc/system.h
--- linux-2.4.20/include/asm-ppc/system.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/system.h	2003-03-26 23:49:31.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.system.h 1.20 03/19/02 15:04:39 benh
- */
-/*
  * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu>
  */
 #ifndef __PPC_SYSTEM_H
@@ -105,6 +102,7 @@
 #define save_flags(flags)	__save_flags(flags)
 #define restore_flags(flags)	__restore_flags(flags)
 #define save_and_cli(flags)	__save_and_cli(flags)
+#define save_and_sti(flags)	__save_and_sti(flags)
 
 #else /* CONFIG_SMP */
 
@@ -117,11 +115,15 @@
 #define save_flags(x) ((x)=__global_save_flags())
 #define restore_flags(x) __global_restore_flags(x)
 
+#define save_and_cli(x) do { save_flags(x); cli(); } while(0);
+#define save_and_sti(x) do { save_flags(x); sti(); } while(0);
+
 #endif /* !CONFIG_SMP */
 
 #define local_irq_disable()		__cli()
 #define local_irq_enable()		__sti()
 #define local_irq_save(flags)		__save_and_cli(flags)
+#define local_irq_set(flags)		__save_and_sti(flags)
 #define local_irq_restore(flags)	__restore_flags(flags)
 
 static __inline__ unsigned long
@@ -130,8 +132,9 @@
 	unsigned long prev;
 
 	__asm__ __volatile__ ("\n\
-1:	lwarx	%0,0,%2 \n\
-	stwcx.	%3,0,%2 \n\
+1:	lwarx	%0,0,%2 \n"
+	PPC405_ERR77(0,%2)
+"	stwcx.	%3,0,%2 \n\
 	bne-	1b"
 	: "=&r" (prev), "=m" (*(volatile unsigned long *)p)
 	: "r" (p), "r" (val), "m" (*(volatile unsigned long *)p)
@@ -181,8 +184,9 @@
 	__asm__ __volatile__ ("\n\
 1:	lwarx	%0,0,%2 \n\
 	cmpw	0,%0,%3 \n\
-	bne	2f \n\
-	stwcx.	%4,0,%2 \n\
+	bne	2f \n"
+	PPC405_ERR77(0,%2)
+"	stwcx.	%4,0,%2 \n\
 	bne-	1b\n"
 #ifdef CONFIG_SMP
 "	sync\n"
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/termbits.h linux-2.4.21-pre6/include/asm-ppc/termbits.h
--- linux-2.4.20/include/asm-ppc/termbits.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/termbits.h	2003-03-26 23:48:59.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.termbits.h 1.5 05/17/01 18:14:26 cort
- */
 #ifndef _PPC_TERMBITS_H
 #define _PPC_TERMBITS_H
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/termios.h linux-2.4.21-pre6/include/asm-ppc/termios.h
--- linux-2.4.20/include/asm-ppc/termios.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/termios.h	2003-03-26 23:49:55.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #ifndef _PPC_TERMIOS_H
 #define _PPC_TERMIOS_H
 
@@ -156,7 +153,7 @@
 #ifdef __KERNEL__
 /*                   ^C  ^\ del  ^U  ^D   1   0   0   0   0  ^W  ^R  ^Z  ^Q  ^S  ^V  ^U  */
 #define INIT_C_CC "\003\034\177\025\004\001\000\000\000\000\027\022\032\021\023\026\025" 
-#endif
+#endif	/* __KERNEL__ */
 
 /* modem lines */
 #define TIOCM_LE	0x001
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/time.h linux-2.4.21-pre6/include/asm-ppc/time.h
--- linux-2.4.20/include/asm-ppc/time.h	2001-11-03 01:43:54.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/time.h	2003-03-26 23:48:59.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.time.h 1.17 10/23/01 08:09:35 trini
- */
-/*
  * Common time prototypes and such for all ppc machines.
  *
  * Written by Cort Dougan (cort@fsmlabs.com) to merge
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/timex.h linux-2.4.21-pre6/include/asm-ppc/timex.h
--- linux-2.4.20/include/asm-ppc/timex.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/timex.h	2003-03-26 23:49:39.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.timex.h 1.8 08/15/01 22:43:07 paulus
- */
-/*
  * linux/include/asm-ppc/timex.h
  *
  * ppc architecture timex specifications
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/tlb.h linux-2.4.21-pre6/include/asm-ppc/tlb.h
--- linux-2.4.20/include/asm-ppc/tlb.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/tlb.h	2003-03-26 23:48:57.000000000 +0000
@@ -1,4 +1 @@
-/*
- * BK Id: SCCS/s.tlb.h 1.5 05/17/01 18:14:26 cort
- */
 #include <asm-generic/tlb.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/todc.h linux-2.4.21-pre6/include/asm-ppc/todc.h
--- linux-2.4.20/include/asm-ppc/todc.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/todc.h	2003-03-26 23:49:50.000000000 +0000
@@ -7,12 +7,10 @@
  * Author: Mark A. Greer
  *         mgreer@mvista.com
  *
- * Copyright 2001 MontaVista Software Inc.
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
+ * 2001 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
  */
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/traps.h linux-2.4.21-pre6/include/asm-ppc/traps.h
--- linux-2.4.20/include/asm-ppc/traps.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/traps.h	2003-03-26 23:49:24.000000000 +0000
@@ -1,4 +1 @@
-/*
- * BK Id: SCCS/s.traps.h 1.5 05/17/01 18:14:26 cort
- */
 #include <asm-m68k/traps.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/types.h linux-2.4.21-pre6/include/asm-ppc/types.h
--- linux-2.4.20/include/asm-ppc/types.h	2001-10-21 17:13:07.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/types.h	2003-03-26 23:49:54.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.types.h 1.10 10/15/01 22:51:33 paulus
- */
 #ifndef _PPC_TYPES_H
 #define _PPC_TYPES_H
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/uaccess.h linux-2.4.21-pre6/include/asm-ppc/uaccess.h
--- linux-2.4.20/include/asm-ppc/uaccess.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/uaccess.h	2003-03-26 23:48:58.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.uaccess.h 1.10 05/21/02 21:44:32 paulus
- */
 #ifdef __KERNEL__
 #ifndef _PPC_UACCESS_H
 #define _PPC_UACCESS_H
@@ -188,7 +185,7 @@
 	  case 1: __get_user_asm(x,ptr,retval,"lbz"); break;	\
 	  case 2: __get_user_asm(x,ptr,retval,"lhz"); break;	\
 	  case 4: __get_user_asm(x,ptr,retval,"lwz"); break;	\
-	  case 8: __get_user_asm2(x, ptr, retval);		\
+	  case 8: __get_user_asm2(x, ptr, retval); break;	\
 	  default: (x) = __get_user_bad();			\
 	}							\
 } while (0)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/ucontext.h linux-2.4.21-pre6/include/asm-ppc/ucontext.h
--- linux-2.4.20/include/asm-ppc/ucontext.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/ucontext.h	2003-03-26 23:49:50.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.ucontext.h 1.5 05/17/01 18:14:26 cort
- */
 #ifndef _ASMPPC_UCONTEXT_H
 #define _ASMPPC_UCONTEXT_H
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/unaligned.h linux-2.4.21-pre6/include/asm-ppc/unaligned.h
--- linux-2.4.20/include/asm-ppc/unaligned.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/unaligned.h	2003-03-26 23:49:50.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.unaligned.h 1.5 05/17/01 18:14:26 cort
- */
 #ifdef __KERNEL__
 #ifndef __PPC_UNALIGNED_H
 #define __PPC_UNALIGNED_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/uninorth.h linux-2.4.21-pre6/include/asm-ppc/uninorth.h
--- linux-2.4.20/include/asm-ppc/uninorth.h	2001-11-03 01:43:54.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/uninorth.h	2003-03-26 23:49:54.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.uninorth.h 1.13 10/23/01 08:09:35 trini
- */
-/*
  * uninorth.h: definitions for using the "UniNorth" host bridge chip
  *             from Apple. This chip is used on "Core99" machines
  *
@@ -31,6 +28,7 @@
 #define UNI_N_CFG_GART_INVAL		0x00000001
 #define UNI_N_CFG_GART_ENABLE		0x00000100
 #define UNI_N_CFG_GART_2xRESET		0x00010000
+#define UNI_N_CFG_GART_DISSBADET	0x00020000
 
 /* My understanding of UniNorth AGP as of UniNorth rev 1.0x,
  * revision 1.5 (x4 AGP) may need further changes.
@@ -97,6 +95,7 @@
 #define UNI_N_CLOCK_CNTL_PCI		0x00000001	/* PCI2 clock control */
 #define UNI_N_CLOCK_CNTL_GMAC		0x00000002	/* GMAC clock control */
 #define UNI_N_CLOCK_CNTL_FW		0x00000004	/* FireWire clock control */
+#define UNI_N_CLOCK_CNTL_ATA100		0x00000010	/* ATA-100 clock control (U2) */
 
 /* Power Management control */
 #define UNI_N_POWER_MGT			0x0030
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/unistd.h linux-2.4.21-pre6/include/asm-ppc/unistd.h
--- linux-2.4.20/include/asm-ppc/unistd.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/unistd.h	2003-03-26 23:49:10.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.unistd.h 1.11 10/18/01 17:29:53 trini
- */
 #ifndef _ASM_PPC_UNISTD_H_
 #define _ASM_PPC_UNISTD_H_
 
@@ -117,10 +114,10 @@
 #define __NR_lstat		107
 #define __NR_fstat		108
 #define __NR_olduname		109
-#define __NR_iopl		110
+/* 110 was __NR_iopl */
 #define __NR_vhangup		111
 #define __NR_idle		112
-#define __NR_vm86		113
+/* 113 was __NR_vm86 */
 #define __NR_wait4		114
 #define __NR_swapoff		115
 #define __NR_sysinfo		116
@@ -130,7 +127,7 @@
 #define __NR_clone		120
 #define __NR_setdomainname	121
 #define __NR_uname		122
-#define __NR_modify_ldt		123
+/* 123 was __NR_modify_ldt */
 #define __NR_adjtimex		124
 #define __NR_mprotect		125
 #define __NR_sigprocmask	126
@@ -244,173 +241,102 @@
 
 #define __NR(n)	#n
 
+/* On powerpc a system call basically clobbers the same registers like a
+ * function call, with the exception of LR (which is needed for the
+ * "sc; bnslr" sequence) and CR (where only CR0.SO is clobbered to signal
+ * an error return status).
+ */
 
-#define __syscall_return(type) \
-	return (__sc_err & 0x10000000 ? errno = __sc_ret, __sc_ret = -1 : 0), \
-	       (type) __sc_ret
-
-#define __syscall_clobbers \
-	"r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12"
-
-#define _syscall0(type,name)						\
-type name(void)								\
-{									\
+#define __syscall_nr(nr, type, name, args...)				\
 	unsigned long __sc_ret, __sc_err;				\
 	{								\
-		register unsigned long __sc_0 __asm__ ("r0");		\
-		register unsigned long __sc_3 __asm__ ("r3");		\
+		register unsigned long __sc_0  __asm__ ("r0");		\
+		register unsigned long __sc_3  __asm__ ("r3");		\
+		register unsigned long __sc_4  __asm__ ("r4");		\
+		register unsigned long __sc_5  __asm__ ("r5");		\
+		register unsigned long __sc_6  __asm__ ("r6");		\
+		register unsigned long __sc_7  __asm__ ("r7");		\
 									\
-		__sc_0 = __NR_##name;					\
+		__sc_loadargs_##nr(name, args);				\
 		__asm__ __volatile__					\
 			("sc           \n\t"				\
-			 "mfcr %1      "				\
-			: "=&r" (__sc_3), "=&r" (__sc_0)		\
-			: "0"   (__sc_3), "1"   (__sc_0)		\
-			: __syscall_clobbers);				\
+			 "mfcr %0      "				\
+			: "=&r" (__sc_0),				\
+			  "=&r" (__sc_3),  "=&r" (__sc_4),		\
+			  "=&r" (__sc_5),  "=&r" (__sc_6),		\
+			  "=&r" (__sc_7)				\
+			: __sc_asm_input_##nr				\
+			: "cr0", "ctr", "memory",			\
+			  "r8", "r9", "r10","r11", "r12");		\
 		__sc_ret = __sc_3;					\
 		__sc_err = __sc_0;					\
 	}								\
-	__syscall_return (type);					\
+	if (__sc_err & 0x10000000)					\
+	{								\
+		errno = __sc_ret;					\
+		__sc_ret = -1;						\
+	}								\
+	return (type) __sc_ret
+
+#define __sc_loadargs_0(name, dummy...)					\
+	__sc_0 = __NR_##name
+#define __sc_loadargs_1(name, arg1)					\
+	__sc_loadargs_0(name);						\
+	__sc_3 = (unsigned long) (arg1)
+#define __sc_loadargs_2(name, arg1, arg2)				\
+	__sc_loadargs_1(name, arg1);					\
+	__sc_4 = (unsigned long) (arg2)
+#define __sc_loadargs_3(name, arg1, arg2, arg3)				\
+	__sc_loadargs_2(name, arg1, arg2);				\
+	__sc_5 = (unsigned long) (arg3)
+#define __sc_loadargs_4(name, arg1, arg2, arg3, arg4)			\
+	__sc_loadargs_3(name, arg1, arg2, arg3);			\
+	__sc_6 = (unsigned long) (arg4)
+#define __sc_loadargs_5(name, arg1, arg2, arg3, arg4, arg5)		\
+	__sc_loadargs_4(name, arg1, arg2, arg3, arg4);			\
+	__sc_7 = (unsigned long) (arg5)
+
+#define __sc_asm_input_0 "0" (__sc_0)
+#define __sc_asm_input_1 __sc_asm_input_0, "1" (__sc_3)
+#define __sc_asm_input_2 __sc_asm_input_1, "2" (__sc_4)
+#define __sc_asm_input_3 __sc_asm_input_2, "3" (__sc_5)
+#define __sc_asm_input_4 __sc_asm_input_3, "4" (__sc_6)
+#define __sc_asm_input_5 __sc_asm_input_4, "5" (__sc_7)
+
+#define _syscall0(type,name)						\
+type name(void)								\
+{									\
+	__syscall_nr(0, type, name);					\
 }
 
 #define _syscall1(type,name,type1,arg1)					\
 type name(type1 arg1)							\
 {									\
-	unsigned long __sc_ret, __sc_err;				\
-	{								\
-		register unsigned long __sc_0 __asm__ ("r0");		\
-		register unsigned long __sc_3 __asm__ ("r3");		\
-									\
-		__sc_3 = (unsigned long) (arg1);			\
-		__sc_0 = __NR_##name;					\
-		__asm__ __volatile__					\
-			("sc           \n\t"				\
-			 "mfcr %1      "				\
-			: "=&r" (__sc_3), "=&r" (__sc_0)		\
-			: "0"   (__sc_3), "1"   (__sc_0)		\
-			: __syscall_clobbers);				\
-		__sc_ret = __sc_3;					\
-		__sc_err = __sc_0;					\
-	}								\
-	__syscall_return (type);					\
+	__syscall_nr(1, type, name, arg1);				\
 }
 
 #define _syscall2(type,name,type1,arg1,type2,arg2)			\
 type name(type1 arg1, type2 arg2)					\
 {									\
-	unsigned long __sc_ret, __sc_err;				\
-	{								\
-		register unsigned long __sc_0 __asm__ ("r0");		\
-		register unsigned long __sc_3 __asm__ ("r3");		\
-		register unsigned long __sc_4 __asm__ ("r4");		\
-									\
-		__sc_3 = (unsigned long) (arg1);			\
-		__sc_4 = (unsigned long) (arg2);			\
-		__sc_0 = __NR_##name;					\
-		__asm__ __volatile__					\
-			("sc           \n\t"				\
-			 "mfcr %1      "				\
-			: "=&r" (__sc_3), "=&r" (__sc_0)		\
-			: "0"   (__sc_3), "1"   (__sc_0),		\
-			  "r"   (__sc_4)				\
-			: __syscall_clobbers);				\
-		__sc_ret = __sc_3;					\
-		__sc_err = __sc_0;					\
-	}								\
-	__syscall_return (type);					\
+	__syscall_nr(2, type, name, arg1, arg2);			\
 }
 
 #define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3)		\
 type name(type1 arg1, type2 arg2, type3 arg3)				\
 {									\
-	unsigned long __sc_ret, __sc_err;				\
-	{								\
-		register unsigned long __sc_0 __asm__ ("r0");		\
-		register unsigned long __sc_3 __asm__ ("r3");		\
-		register unsigned long __sc_4 __asm__ ("r4");		\
-		register unsigned long __sc_5 __asm__ ("r5");		\
-									\
-		__sc_3 = (unsigned long) (arg1);			\
-		__sc_4 = (unsigned long) (arg2);			\
-		__sc_5 = (unsigned long) (arg3);			\
-		__sc_0 = __NR_##name;					\
-		__asm__ __volatile__					\
-			("sc           \n\t"				\
-			 "mfcr %1      "				\
-			: "=&r" (__sc_3), "=&r" (__sc_0)		\
-			: "0"   (__sc_3), "1"   (__sc_0),		\
-			  "r"   (__sc_4),				\
-			  "r"   (__sc_5)				\
-			: __syscall_clobbers);				\
-		__sc_ret = __sc_3;					\
-		__sc_err = __sc_0;					\
-	}								\
-	__syscall_return (type);					\
+	__syscall_nr(3, type, name, arg1, arg2, arg3);			\
 }
 
 #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
 type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4)		\
 {									\
-	unsigned long __sc_ret, __sc_err;				\
-	{								\
-		register unsigned long __sc_0 __asm__ ("r0");		\
-		register unsigned long __sc_3 __asm__ ("r3");		\
-		register unsigned long __sc_4 __asm__ ("r4");		\
-		register unsigned long __sc_5 __asm__ ("r5");		\
-		register unsigned long __sc_6 __asm__ ("r6");		\
-									\
-		__sc_3 = (unsigned long) (arg1);			\
-		__sc_4 = (unsigned long) (arg2);			\
-		__sc_5 = (unsigned long) (arg3);			\
-		__sc_6 = (unsigned long) (arg4);			\
-		__sc_0 = __NR_##name;					\
-		__asm__ __volatile__					\
-			("sc           \n\t"				\
-			 "mfcr %1      "				\
-			: "=&r" (__sc_3), "=&r" (__sc_0)		\
-			: "0"   (__sc_3), "1"   (__sc_0),		\
-			  "r"   (__sc_4),				\
-			  "r"   (__sc_5),				\
-			  "r"   (__sc_6)				\
-			: __syscall_clobbers);				\
-		__sc_ret = __sc_3;					\
-		__sc_err = __sc_0;					\
-	}								\
-	__syscall_return (type);					\
+	__syscall_nr(4, type, name, arg1, arg2, arg3, arg4);		\
 }
 
 #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5) \
 type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5)	\
 {									\
-	unsigned long __sc_ret, __sc_err;				\
-	{								\
-		register unsigned long __sc_0 __asm__ ("r0");		\
-		register unsigned long __sc_3 __asm__ ("r3");		\
-		register unsigned long __sc_4 __asm__ ("r4");		\
-		register unsigned long __sc_5 __asm__ ("r5");		\
-		register unsigned long __sc_6 __asm__ ("r6");		\
-		register unsigned long __sc_7 __asm__ ("r7");		\
-									\
-		__sc_3 = (unsigned long) (arg1);			\
-		__sc_4 = (unsigned long) (arg2);			\
-		__sc_5 = (unsigned long) (arg3);			\
-		__sc_6 = (unsigned long) (arg4);			\
-		__sc_7 = (unsigned long) (arg5);			\
-		__sc_0 = __NR_##name;					\
-		__asm__ __volatile__					\
-			("sc           \n\t"				\
-			 "mfcr %1      "				\
-			: "=&r" (__sc_3), "=&r" (__sc_0)		\
-			: "0"   (__sc_3), "1"   (__sc_0),		\
-			  "r"   (__sc_4),				\
-			  "r"   (__sc_5),				\
-			  "r"   (__sc_6),				\
-			  "r"   (__sc_7)				\
-			: __syscall_clobbers);				\
-		__sc_ret = __sc_3;					\
-		__sc_err = __sc_0;					\
-	}								\
-	__syscall_return (type);					\
+	__syscall_nr(5, type, name, arg1, arg2, arg3, arg4, arg5);	\
 }
 
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/user.h linux-2.4.21-pre6/include/asm-ppc/user.h
--- linux-2.4.20/include/asm-ppc/user.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/user.h	2003-03-26 23:49:40.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.user.h 1.5 05/17/01 18:14:26 cort
- */
 #ifdef __KERNEL__
 #ifndef _PPC_USER_H
 #define _PPC_USER_H
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/vc_ioctl.h linux-2.4.21-pre6/include/asm-ppc/vc_ioctl.h
--- linux-2.4.20/include/asm-ppc/vc_ioctl.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/vc_ioctl.h	2003-03-26 23:49:50.000000000 +0000
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.vc_ioctl.h 1.5 05/17/01 18:14:26 cort
- */
 #ifndef _LINUX_VC_IOCTL_H
 #define _LINUX_VC_IOCTL_H
 
@@ -41,6 +38,6 @@
 extern int console_powermode(int);
 extern struct vc_mode display_info;
 extern struct fb_info *console_fb_info;
-#endif
+#endif /* __KERNEL__ */
 
 #endif /* _LINUX_VC_IOCTL_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/vga.h linux-2.4.21-pre6/include/asm-ppc/vga.h
--- linux-2.4.20/include/asm-ppc/vga.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/vga.h	2003-03-26 23:49:38.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.vga.h 1.5 05/17/01 18:14:26 cort
- */
-/*
  *	Access to VGA videoram
  *
  *	(c) 1998 Martin Mares <mj@ucw.cz>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/walnut.h linux-2.4.21-pre6/include/asm-ppc/walnut.h
--- linux-2.4.20/include/asm-ppc/walnut.h	2001-10-08 18:43:01.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/walnut.h	2003-03-26 23:49:35.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.walnut.h 1.10 09/14/01 17:37:56 trini
- */
-/*
  *
  *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/xics.h linux-2.4.21-pre6/include/asm-ppc/xics.h
--- linux-2.4.20/include/asm-ppc/xics.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/xics.h	2003-03-26 23:49:40.000000000 +0000
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.xics.h 1.5 05/17/01 18:14:22 cort
- */
-/*
  * arch/ppc/kernel/xics.h
  *
  * Copyright 2000 IBM Corporation.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc/xor.h linux-2.4.21-pre6/include/asm-ppc/xor.h
--- linux-2.4.20/include/asm-ppc/xor.h	2001-05-21 22:02:06.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc/xor.h	2003-03-26 23:49:38.000000000 +0000
@@ -1,4 +1 @@
-/*
- * BK Id: SCCS/s.xor.h 1.5 05/17/01 18:14:26 cort
- */
 #include <asm-generic/xor.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/a.out.h linux-2.4.21-pre6/include/asm-ppc64/a.out.h
--- linux-2.4.20/include/asm-ppc64/a.out.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/a.out.h	2003-03-26 23:49:02.000000000 +0000
@@ -31,7 +31,7 @@
 #ifdef __KERNEL__
 
 /* 64-bit user address space is less PGDIR_SIZE due to pgd_index() bug. */
-#define STACK_TOP_USER64 (TASK_SIZE_USER64 - PGDIR_SIZE)
+#define STACK_TOP_USER64 (TASK_SIZE_USER64)
 
 /* Give 32-bit user space a full 4G address space to live in. */
 #define STACK_TOP_USER32 (TASK_SIZE_USER32)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/bitops.h linux-2.4.21-pre6/include/asm-ppc64/bitops.h
--- linux-2.4.20/include/asm-ppc64/bitops.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/bitops.h	2003-03-26 23:49:10.000000000 +0000
@@ -33,7 +33,6 @@
 
 #ifdef __KERNEL__
 
-#include <asm/byteorder.h>
 #include <asm/memory.h>
 
 /*
@@ -243,35 +242,30 @@
 }
 
 
-
 /*
- * ffz = Find First Zero in word. Undefined if no zero exists,
- *    Determines the bit position of the LEAST significant
- *    (rightmost) 0 bit in the specified DOUBLE-WORD.
- *    The returned bit position will be zero-based, starting
- *    from the right side (63 - 0).
- *    the code should check against ~0UL first..
+ * ffz = Find First Zero in word.
+ * Determines the bit position of the least significant (rightmost) 0 bit
+ * in the specified double word. The returned bit position will be zero-based,
+ * starting from the right side (63 - 0).
  */
 static __inline__ unsigned long ffz(unsigned long x)
 {
-	u32  tempRC;
-
-	/* Change all of x's 1s to 0s and 0s to 1s in x.
-	 * And insure at least 1 zero exists in the 8 byte area.
-	 */
+	/* no zero exists anywhere in the 8 byte area. */
 	if ((x = ~x) == 0)
-		/* no zero exists anywhere in the 8 byte area. */
 		return 64;
 
-	/* Calculate the bit position of the least significant '1' bit in x
-	 * (since x has been changed this will actually be the least
-	 * significant '0' bit in the original x).
-	 * Note: (x & -x) gives us a mask that is the LEAST significant
-	 * (RIGHT-most) 1-bit of the value in x.
+	/*
+	 * Calculate the bit position of the least signficant '1' bit in x
+	 * (since x has been changed this will actually be the least signficant
+	 * '0' bit in * the original x).  Note: (x & -x) gives us a mask that
+	 * is the least significant * (RIGHT-most) 1-bit of the value in x.
 	 */
-	tempRC = __ilog2(x & -x);
+	return __ilog2(x & -x);
+}
 
-	return tempRC;
+static __inline__ int __ffs(unsigned long x)
+{
+	return __ilog2(x & -x);
 }
 
 /*
@@ -281,11 +275,17 @@
  */
 static __inline__ int ffs(int x)
 {
-	int result = ffz(~x);
-	return x ? result+1 : 0;
+	unsigned long i = (unsigned long)x;
+	return __ilog2(i & -i) + 1;
 }
 
 /*
+ * fls: find last (most-significant) bit set.
+ * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
+ */
+#define fls(x) generic_fls(x)
+
+/*
  * hweightN: returns the hamming weight (i.e. the number
  * of bits set) of a N-bit word
  */
@@ -293,139 +293,82 @@
 #define hweight16(x) generic_hweight16(x)
 #define hweight8(x) generic_hweight8(x)
 
-extern unsigned long find_next_zero_bit(void * addr, unsigned long size,
-					unsigned long offset);
-/*
- * The optimizer actually does good code for this case..
- */
-#define find_first_zero_bit(addr, size) find_next_zero_bit((addr), (size), 0)
-
-/* Bitmap functions for the ext2 filesystem. */
-#define _EXT2_HAVE_ASM_BITOPS_
+extern unsigned long find_next_zero_bit(unsigned long* addr, unsigned long size, unsigned long offset);
+#define find_first_zero_bit(addr, size) \
+	find_next_zero_bit((addr), (size), 0)
+
+extern unsigned long find_next_bit(unsigned long* addr, unsigned long size, unsigned long offset);
+#define find_first_bit(addr, size) \
+	find_next_bit((addr), (size), 0)
+
+extern unsigned long find_next_zero_le_bit(unsigned long *addr, unsigned long size, unsigned long offset);
+#define find_first_zero_le_bit(addr, size) \
+	find_next_zero_le_bit((addr), (size), 0)
 
-static __inline__ int ext2_set_bit(int nr, void* addr)
+static __inline__ int test_le_bit(unsigned long nr, __const__ unsigned long * addr)
 {
-	/* This method needs to take into account the fact that the ext2 file system represents
-	 *  it's bitmaps as "little endian" unsigned integers.
-	 * Note: this method is not atomic, but ext2 does not need it to be.
-	 */
-	int mask;
-	int oldbit;
-	unsigned char* ADDR = (unsigned char*) addr;
-
-	/* Determine the BYTE containing the specified bit
-	 * (nr) - important as if we go to a byte there are no
-	 * little endian concerns.
-	 */
-	ADDR += nr >> 3;
-	mask = 1 << (nr & 0x07);  /* Create a mask to the bit within this byte. */
-	oldbit = *ADDR & mask;  /* Save the bit's previous value. */
-	*ADDR |= mask;  /* Turn the bit on. */
-	return oldbit;  /* Return the bit's previous value. */
+	__const__ unsigned char	*ADDR = (__const__ unsigned char *) addr;
+	return (ADDR[nr >> 3] >> (nr & 7)) & 1;
 }
 
-static __inline__ int ext2_clear_bit(int nr, void* addr)
+/*
+ * non-atomic versions
+ */
+static __inline__ void __set_le_bit(unsigned long nr, unsigned long *addr)
 {
-	/* This method needs to take into account the fact that the ext2 file system represents
-	 * | it's bitmaps as "little endian" unsigned integers.
-	 * Note: this method is not atomic, but ext2 does not need it to be.
-	 */
-        int     mask;
-        int oldbit;
-        unsigned char* ADDR = (unsigned char*) addr;
-
-	/* Determine the BYTE containing the specified bit (nr)
-	 *  - important as if we go to a byte there are no little endian concerns.
-	 */
-        ADDR += nr >> 3;
-        mask = 1 << (nr & 0x07);  /* Create a mask to the bit within this byte. */
-        oldbit = *ADDR & mask;  /* Save the bit's previous value. */
-        *ADDR = *ADDR & ~mask;  /* Turn the bit off. */
-        return oldbit;  /* Return the bit's previous value. */
-}
+	unsigned char *ADDR = (unsigned char *)addr;
 
-static __inline__ int ext2_test_bit(int nr, __const__ void * addr)
-{
-	/* This method needs to take into account the fact that the ext2 file system represents
-	 * | it's bitmaps as "little endian" unsigned integers.
-	 * Determine the BYTE containing the specified bit (nr),
-	 *   then shift to the right the correct number of bits and return that bit's value.
-	 */
-	__const__ unsigned char	*ADDR = (__const__ unsigned char *) addr;
-	return (ADDR[nr >> 3] >> (nr & 7)) & 1;
+	ADDR += nr >> 3;
+	*ADDR |= 1 << (nr & 0x07);
 }
 
-/* Returns the bit position of the most significant 1 bit in a WORD. */
-static __inline__ int ext2_ilog2(unsigned int x)
+static __inline__ void __clear_le_bit(unsigned long nr, unsigned long *addr)
 {
-        int lz;
+	unsigned char *ADDR = (unsigned char *)addr;
 
-        asm ("cntlzw %0,%1" : "=r" (lz) : "r" (x));
-        return 31 - lz;
+	ADDR += nr >> 3;
+	*ADDR &= ~(1 << (nr & 0x07));
 }
 
-/* ext2_ffz = ext2's Find First Zero.
- *    Determines the bit position of the LEAST significant (rightmost) 0 bit in the specified WORD.
- *    The returned bit position will be zero-based, starting from the right side (31 - 0).
- */
-static __inline__ int ext2_ffz(unsigned int x)
+static __inline__ int __test_and_set_le_bit(unsigned long nr, unsigned long *addr)
 {
-	u32  tempRC;
-	/* Change all of x's 1s to 0s and 0s to 1s in x.  And insure at least 1 zero exists in the word. */
-	if ((x = ~x) == 0)
-		/* no zero exists anywhere in the 4 byte area. */
-		return 32;
-	/* Calculate the bit position of the least significant '1' bit in x
-	 * (since x has been changed this will actually be the least
-	 * significant '0' bit in the original x).
-	 * Note: (x & -x) gives us a mask that is the LEAST significant
-	 * (RIGHT-most) 1-bit of the value in x.
-	 */
-	tempRC = ext2_ilog2(x & -x);
-	return tempRC;
+	int mask, retval;
+	unsigned char *ADDR = (unsigned char *)addr;
+
+	ADDR += nr >> 3;
+	mask = 1 << (nr & 0x07);
+	retval = (mask & *ADDR) != 0;
+	*ADDR |= mask;
+	return retval;
 }
 
-static __inline__ u32 ext2_find_next_zero_bit(void* addr, u32 size, u32 offset)
+static __inline__ int __test_and_clear_le_bit(unsigned long nr, unsigned long *addr)
 {
-	/* This method needs to take into account the fact that the ext2 file system represents
-	 * | it's bitmaps as "little endian" unsigned integers.
-	 */
-        unsigned int *p = ((unsigned int *) addr) + (offset >> 5);
-        unsigned int result = offset & ~31;
-        unsigned int tmp;
-
-        if (offset >= size)
-                return size;
-        size -= result;
-        offset &= 31;
-        if (offset) {
-                tmp = cpu_to_le32p(p++);
-                tmp |= ~0U >> (32-offset); /* bug or feature ? */
-                if (size < 32)
-                        goto found_first;
-                if (tmp != ~0)
-                        goto found_middle;
-                size -= 32;
-                result += 32;
-        }
-        while (size >= 32) {
-                if ((tmp = cpu_to_le32p(p++)) != ~0)
-                        goto found_middle;
-                result += 32;
-                size -= 32;
-        }
-        if (!size)
-                return result;
-        tmp = cpu_to_le32p(p);
-found_first:
-        tmp |= ~0 << size;
-        if (tmp == ~0)          /* Are any bits zero? */
-                return result + size; /* Nope. */
-found_middle:
-        return result + ext2_ffz(tmp);
-}
+	int mask, retval;
+	unsigned char *ADDR = (unsigned char *)addr;
 
-#define ext2_find_first_zero_bit(addr, size) ext2_find_next_zero_bit((addr), (size), 0)
+	ADDR += nr >> 3;
+	mask = 1 << (nr & 0x07);
+	retval = (mask & *ADDR) != 0;
+	*ADDR &= ~mask;
+	return retval;
+}
+
+#define ext2_set_bit(nr,addr) \
+	__test_and_set_le_bit((nr),(unsigned long*)addr)
+#define ext2_clear_bit(nr, addr) \
+	__test_and_clear_le_bit((nr),(unsigned long*)addr)
+#define ext2_test_bit(nr, addr)      test_le_bit((nr),(unsigned long*)addr)
+#define ext2_find_first_zero_bit(addr, size) \
+	find_first_zero_le_bit((unsigned long*)addr, size)
+#define ext2_find_next_zero_bit(addr, size, off) \
+	find_next_zero_le_bit((unsigned long*)addr, size, off)
+
+#define minix_test_and_set_bit(nr,addr)		test_and_set_bit(nr,addr)
+#define minix_set_bit(nr,addr)			set_bit(nr,addr)
+#define minix_test_and_clear_bit(nr,addr)	test_and_clear_bit(nr,addr)
+#define minix_test_bit(nr,addr)			test_bit(nr,addr)
+#define minix_find_first_zero_bit(addr,size)	find_first_zero_bit(addr,size)
 
 #endif /* __KERNEL__ */
 #endif /* _PPC64_BITOPS_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/delay.h linux-2.4.21-pre6/include/asm-ppc64/delay.h
--- linux-2.4.20/include/asm-ppc64/delay.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/delay.h	2003-03-26 23:49:40.000000000 +0000
@@ -19,6 +19,7 @@
 /* define these here to prevent circular dependencies */ 
 #define __HMT_low()	asm volatile("or 1,1,1")
 #define __HMT_medium()	asm volatile("or 2,2,2")
+#define __barrier()	asm volatile("":::"memory")
 
 static inline unsigned long __get_tb(void)
 {
@@ -34,6 +35,8 @@
 
 	while((__get_tb()-start) < loops)
 		__HMT_low();
+	__HMT_medium();
+	__barrier();
 }
 
 static inline void udelay(unsigned long usecs)
@@ -41,7 +44,13 @@
 	unsigned long loops = tb_ticks_per_usec * usecs;
 
 	__delay(loops);
-	__HMT_medium();
+}
+
+static inline void ndelay(unsigned long nsecs)
+{
+	unsigned long loops = (tb_ticks_per_usec * nsecs) / 1000;
+
+	__delay(loops);
 }
 #endif /* !__ASSEMBLY__ */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/eeh.h linux-2.4.21-pre6/include/asm-ppc64/eeh.h
--- linux-2.4.20/include/asm-ppc64/eeh.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/eeh.h	2003-03-26 23:49:20.000000000 +0000
@@ -27,25 +27,26 @@
 
 struct pci_dev;
 
-#define IO_UNMAPPED_REGION_ID 0xaUL
-
-#define IO_TOKEN_TO_ADDR(token) ((((unsigned long)(token)) & 0xFFFFFFFF) | (0xEUL << 60))
-/* Flag bits encoded in the 3 unused function bits of devfn */
-#define EEH_TOKEN_DISABLED (1UL << 34UL)	/* eeh is disabled for this token */
-#define IS_EEH_TOKEN_DISABLED(token) ((unsigned long)(token) & EEH_TOKEN_DISABLED)
-
-#define EEH_STATE_OVERRIDE 1   /* IOA does not require eeh traps */
-#define EEH_STATE_FAILURE  16  /* */
+/* I/O addresses are converted to EEH "tokens" such that a driver will cause
+ * a bad page fault if the address is used directly (i.e. these addresses are
+ * never actually mapped.  Translation between IO <-> EEH region is 1 to 1.
+ */
+#define IO_TOKEN_TO_ADDR(token) (((unsigned long)(token) & ~(0xfUL << REGION_SHIFT)) | \
+				(IO_REGION_ID << REGION_SHIFT))
+#define IO_ADDR_TO_TOKEN(addr) (((unsigned long)(addr) & ~(0xfUL << REGION_SHIFT)) | \
+				(EEH_REGION_ID << REGION_SHIFT))
+
+/* Values for eeh_mode bits in device_node */
+#define EEH_MODE_SUPPORTED	(1<<0)
+#define EEH_MODE_NOCHECK	(1<<1)
 
 /* This is for profiling only */
 extern unsigned long eeh_total_mmio_ffs;
 
-extern int eeh_implemented;
-
 void eeh_init(void);
-static inline int is_eeh_implemented(void) { return eeh_implemented; }
 int eeh_get_state(unsigned long ea);
 unsigned long eeh_check_failure(void *token, unsigned long val);
+void *eeh_ioremap(unsigned long addr, void *vaddr);
 
 #define EEH_DISABLE		0
 #define EEH_ENABLE		1
@@ -58,15 +59,11 @@
  */
 int is_eeh_configured(struct pci_dev *dev);
 
-/* Generate an EEH token.
- * The high nibble of the offset is cleared, otherwise bounds checking is performed.
- * Use IO_TOKEN_TO_ADDR(token) to translate this token back to a mapped virtual addr.
- * Do NOT do this to perform IO -- use the read/write macros!
- */
-unsigned long eeh_token(unsigned long phb,
-			unsigned long bus,
-			unsigned long devfn,
-			unsigned long offset);
+/* Translate a (possible) eeh token to a physical addr.
+ * If "token" is not an eeh token it is simply returned under
+ * the assumption that it is already a physical addr.
+ */
+unsigned long eeh_token_to_phys(unsigned long token);
 
 extern void *memcpy(void *, const void *, unsigned long);
 extern void *memset(void *,int, unsigned long);
@@ -77,15 +74,16 @@
  * If EEH is off for a device and it is a memory BAR, ioremap will
  * map it to the IOREGION.  In this case addr == vaddr and since these
  * should be in registers we compare them first.  Next we check for
- * all ones which is perhaps fastest as ~val.  Finally we weed out
- * EEH disabled IO BARs.
+ * ff's which indicates a (very) possible failure.
  *
  * If this macro yields TRUE, the caller relays to eeh_check_failure()
  * which does further tests out of line.
  */
-/* #define EEH_POSSIBLE_ERROR(addr, vaddr, val) ((vaddr) != (addr) && ~(val) == 0 && !IS_EEH_TOKEN_DISABLED(addr)) */
+/* #define EEH_POSSIBLE_IO_ERROR(val) (~(val) == 0) */
+/* #define EEH_POSSIBLE_ERROR(addr, vaddr, val) ((vaddr) != (addr) && EEH_POSSIBLE_IO_ERROR(val) */
 /* This version is rearranged to collect some profiling data */
-#define EEH_POSSIBLE_ERROR(addr, vaddr, val) (~(val) == 0 && (++eeh_total_mmio_ffs, (vaddr) != (addr) && !IS_EEH_TOKEN_DISABLED(addr)))
+#define EEH_POSSIBLE_IO_ERROR(val) (~(val) == 0 && ++eeh_total_mmio_ffs)
+#define EEH_POSSIBLE_ERROR(addr, vaddr, val) (EEH_POSSIBLE_IO_ERROR(val) && (vaddr) != (addr))
 
 /* 
  * MMIO read/write operations with EEH support.
@@ -149,38 +147,56 @@
 	memcpy(vdest, src, n);
 }
 
-static inline void eeh_insb(volatile u8 *addr, void *buf, int n) {
-	volatile u8 *vaddr = (volatile u8 *)IO_TOKEN_TO_ADDR(addr);
-	_insb(vaddr, buf, n);
-	/* ToDo: look for ff's in buf[n] */
-}
+/* The I/O macros must handle ISA ports as well as PCI I/O bars.
+ * ISA does not implement EEH and ISA may not exist in the system.
+ * For PCI we check for EEH failures.
+ */
+#define _IO_IS_ISA(port) ((port) < 0x10000)
+#define _IO_HAS_ISA_BUS	(isa_io_base != 0)
 
-static inline void eeh_outsb(volatile u8 *addr, const void *buf, int n) {
-	volatile u8 *vaddr = (volatile u8 *)IO_TOKEN_TO_ADDR(addr);
-	_outsb(vaddr, buf, n);
+static inline u8 eeh_inb(unsigned long port) {
+	u8 val;
+	if (_IO_IS_ISA(port) && !_IO_HAS_ISA_BUS)
+		return ~0;
+	val = in_8((u8 *)(port+pci_io_base));
+	if (!_IO_IS_ISA(port) && EEH_POSSIBLE_IO_ERROR(val))
+		return eeh_check_failure((void*)(port+pci_io_base), val);
+	return val;
 }
 
-static inline void eeh_insw_ns(volatile u16 *addr, void *buf, int n) {
-	volatile u16 *vaddr = (volatile u16 *)IO_TOKEN_TO_ADDR(addr);
-	_insw_ns(vaddr, buf, n);
-	/* ToDo: look for ffff's in buf[n] */
+static inline void eeh_outb(u8 val, unsigned long port) {
+	if (!_IO_IS_ISA(port) || _IO_HAS_ISA_BUS)
+		return out_8((u8 *)(port+pci_io_base), val);
 }
 
-static inline void eeh_outsw_ns(volatile u16 *addr, const void *buf, int n) {
-	volatile u16 *vaddr = (volatile u16 *)IO_TOKEN_TO_ADDR(addr);
-	_outsw_ns(vaddr, buf, n);
+static inline u16 eeh_inw(unsigned long port) {
+	u16 val;
+	if (_IO_IS_ISA(port) && !_IO_HAS_ISA_BUS)
+		return ~0;
+	val = in_le16((u16 *)(port+pci_io_base));
+	if (!_IO_IS_ISA(port) && EEH_POSSIBLE_IO_ERROR(val))
+		return eeh_check_failure((void*)(port+pci_io_base), val);
+	return val;
 }
 
-static inline void eeh_insl_ns(volatile u32 *addr, void *buf, int n) {
-	volatile u32 *vaddr = (volatile u32 *)IO_TOKEN_TO_ADDR(addr);
-	_insl_ns(vaddr, buf, n);
-	/* ToDo: look for ffffffff's in buf[n] */
+static inline void eeh_outw(u16 val, unsigned long port) {
+	if (!_IO_IS_ISA(port) || _IO_HAS_ISA_BUS)
+		return out_le16((u16 *)(port+pci_io_base), val);
 }
 
-static inline void eeh_outsl_ns(volatile u32 *addr, const void *buf, int n) {
-	volatile u32 *vaddr = (volatile u32 *)IO_TOKEN_TO_ADDR(addr);
-	_outsl_ns(vaddr, buf, n);
+static inline u32 eeh_inl(unsigned long port) {
+	u32 val;
+	if (_IO_IS_ISA(port) && !_IO_HAS_ISA_BUS)
+		return ~0;
+	val = in_le32((u32 *)(port+pci_io_base));
+	if (!_IO_IS_ISA(port) && EEH_POSSIBLE_IO_ERROR(val))
+		return eeh_check_failure((void*)(port+pci_io_base), val);
+	return val;
 }
 
+static inline void eeh_outl(u32 val, unsigned long port) {
+	if (!_IO_IS_ISA(port) || _IO_HAS_ISA_BUS)
+		return out_le32((u32 *)(port+pci_io_base), val);
+}
 
 #endif /* _EEH_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/elf.h linux-2.4.21-pre6/include/asm-ppc64/elf.h
--- linux-2.4.20/include/asm-ppc64/elf.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/elf.h	2003-03-26 23:49:56.000000000 +0000
@@ -43,6 +43,8 @@
 typedef double elf_fpreg_t;
 typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
 
+#ifdef __KERNEL__
+
 /*
  * This is used to ensure we don't load something for the wrong architecture.
  */
@@ -87,15 +89,13 @@
 #define ELF_PLATFORM	(NULL)
 
 
-#define ELF_PLAT_INIT(_r, load_addr)	do { \
+#define ELF_PLAT_INIT(_r)	do { \
 	memset(_r->gpr, 0, sizeof(_r->gpr)); \
 	_r->ctr = _r->link = _r->xer = _r->ccr = 0; \
-	_r->gpr[2] = load_addr; \
 } while (0)
 
 
 
-#ifdef __KERNEL__
 #define SET_PERSONALITY(ex, ibcs2)				\
 do {	if ((ex).e_ident[EI_CLASS] == ELFCLASS32)		\
 		current->thread.flags |= PPC_FLAG_32BIT;	\
@@ -106,7 +106,6 @@
 	else if (current->personality != PER_LINUX32)		\
 		set_personality(PER_LINUX);			\
 } while (0)
-#endif
 
 /*
  * We need to put in some extra aux table entries to tell glibc what
@@ -146,4 +145,5 @@
 	NEW_AUX_ENT(1, AT_IGNOREPPC, AT_IGNOREPPC);			\
  } while (0)
 
+#endif /* __KERNEL__ */
 #endif /* __PPC64_ELF_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/hvcall.h linux-2.4.21-pre6/include/asm-ppc64/hvcall.h
--- linux-2.4.20/include/asm-ppc64/hvcall.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/hvcall.h	2003-03-26 23:49:10.000000000 +0000
@@ -57,6 +57,7 @@
 #define H_IPI			0x6c
 #define H_IPOLL			0x70
 #define H_XIRR			0x74
+#define H_PERFMON		0x7c
 
 #define HSC			".long 0x44000022\n"
 #define H_ENTER_r3		"li	3, 0x08\n"
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/hw_irq.h linux-2.4.21-pre6/include/asm-ppc64/hw_irq.h
--- linux-2.4.20/include/asm-ppc64/hw_irq.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/hw_irq.h	2003-03-26 23:49:35.000000000 +0000
@@ -31,11 +31,15 @@
 #define __save_flags(flags)	((flags) = __no_use_save_flags())
 #define __restore_flags(flags)	__no_use_restore_flags((unsigned long)flags)
 #define __save_and_cli(flags)	({__save_flags(flags);__cli();})
+#define __save_and_sti(flags)	({__save_flags(flags);__sti();})
 
 #else
 
 #define __save_flags(flags)	((flags) = mfmsr())
-#define __restore_flags(flags)	mtmsrd(flags)
+#define __restore_flags(flags) do { \
+	__asm__ __volatile__("": : :"memory"); \
+	mtmsrd(flags); \
+} while(0)
 
 static inline void __cli(void)
 {
@@ -63,6 +67,7 @@
 }
 
 #define __save_and_cli(flags)          __do_save_and_cli(&flags)
+#define __save_and_sti(flags)		({__save_flags(flags);__sti();})
 
 #endif /* CONFIG_PPC_ISERIES */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/iSeries/HvCall.h linux-2.4.21-pre6/include/asm-ppc64/iSeries/HvCall.h
--- linux-2.4.20/include/asm-ppc64/iSeries/HvCall.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/iSeries/HvCall.h	2003-03-26 23:49:35.000000000 +0000
@@ -130,6 +130,7 @@
 #define HvCallBaseRouter28				HvCallBase + 28
 #define HvCallBaseRouter29				HvCallBase + 29
 #define HvCallBaseRouter30				HvCallBase + 30
+#define HvCallBaseSetDebugBus 				HvCallBase + 31
 
 #define HvCallCcSetDABR  				HvCallCc + 7
 
@@ -205,5 +206,10 @@
 	HvCall1(HvCallCcSetDABR, val);
 }
 
+static inline void HvCall_setDebugBus(unsigned long val)
+{
+	HvCall1(HvCallBaseSetDebugBus, val);
+}
+
 #endif // _HVCALL_H
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/ide.h linux-2.4.21-pre6/include/asm-ppc64/ide.h
--- linux-2.4.20/include/asm-ppc64/ide.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/ide.h	2003-03-26 23:49:29.000000000 +0000
@@ -22,11 +22,6 @@
 #define MAX_HWIFS	4
 #endif
 
-#define ide__sti()	__sti()
-
-void ppc64_ide_fix_driveid(struct hd_driveid *id);
-#define ide_fix_driveid(id)	ppc64_ide_fix_driveid((id))
-
 static __inline__ int ide_default_irq(ide_ioreg_t base) { return 0; }
 static __inline__ ide_ioreg_t ide_default_io_base(int index) { return 0; }
 
@@ -53,29 +48,7 @@
 {
 }
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-	} select_t;
-
-#define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
-#define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
-#define ide_check_region(from,extent)		check_region((from), (extent))
-#define ide_request_region(from,extent,name)	request_region((from), (extent), (name))
-#define ide_release_region(from,extent)		release_region((from), (extent))
-
-/*
- * The following are not needed for the non-m68k ports
- */
-#define ide_ack_intr(hwif)		(1)
-#define ide_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
+#include <asm-generic/ide_iops.h>
 
 #endif /* __KERNEL__ */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/io.h linux-2.4.21-pre6/include/asm-ppc64/io.h
--- linux-2.4.20/include/asm-ppc64/io.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/io.h	2003-03-26 23:49:40.000000000 +0000
@@ -50,7 +50,6 @@
 #define outw(data,addr)		writew(data,((unsigned long)(addr)))  
 #define outl(data,addr)		writel(data,((unsigned long)(addr)))
 #else
-#define IS_MAPPED_VADDR(port)	((unsigned long)(port) >> 60UL)
 #define readb(addr)		eeh_readb((void*)(addr))  
 #define readw(addr)		eeh_readw((void*)(addr))  
 #define readl(addr)		eeh_readl((void*)(addr))
@@ -60,26 +59,36 @@
 #define memset_io(a,b,c)	eeh_memset_io((void *)(a),(b),(c))
 #define memcpy_fromio(a,b,c)	eeh_memcpy_fromio((a),(void *)(b),(c))
 #define memcpy_toio(a,b,c)	eeh_memcpy_toio((void *)(a),(b),(c))
-#define inb(port)		_inb((unsigned long)port)
-#define outb(val, port)		_outb(val, (unsigned long)port)
-#define inw(port)		_inw((unsigned long)port)
-#define outw(val, port)		_outw(val, (unsigned long)port)
-#define inl(port)		_inl((unsigned long)port)
-#define outl(val, port)		_outl(val, (unsigned long)port)
+#define inb(port)		eeh_inb((unsigned long)port)
+#define outb(val, port)		eeh_outb(val, (unsigned long)port)
+#define inw(port)		eeh_inw((unsigned long)port)
+#define outw(val, port)		eeh_outw(val, (unsigned long)port)
+#define inl(port)		eeh_inl((unsigned long)port)
+#define outl(val, port)		eeh_outl(val, (unsigned long)port)
 
 /*
  * The insw/outsw/insl/outsl macros don't do byte-swapping.
  * They are only used in practice for transferring buffers which
  * are arrays of bytes, and byte-swapping is not appropriate in
  * that case.  - paulus */
-#define insb(port, buf, ns)	eeh_insb((u8 *)(port), (buf), (ns))
-#define outsb(port, buf, ns)	eeh_outsb((u8 *)(port), (buf), (ns))
-#define insw(port, buf, ns)	eeh_insw_ns((u16 *)(port), (buf), (ns))
-#define outsw(port, buf, ns)	eeh_outsw_ns((u16 *)(port), (buf), (ns))
-#define insl(port, buf, nl)	eeh_insl_ns((u32 *)(port), (buf), (nl))
-#define outsl(port, buf, nl)	eeh_outsl_ns((u32 *)(port), (buf), (nl))
+#define insb(port, buf, ns)	_insb((u8 *)((port)+pci_io_base), (buf), (ns))
+#define outsb(port, buf, ns)	_outsb((u8 *)((port)+pci_io_base), (buf), (ns))
+#define insw(port, buf, ns)	_insw_ns((u16 *)((port)+pci_io_base), (buf), (ns))
+#define outsw(port, buf, ns)	_outsw_ns((u16 *)((port)+pci_io_base), (buf), (ns))
+#define insl(port, buf, nl)	_insl_ns((u32 *)((port)+pci_io_base), (buf), (nl))
+#define outsl(port, buf, nl)	_outsl_ns((u32 *)((port)+pci_io_base), (buf), (nl))
 #endif
 
+extern void _insb(volatile u8 *port, void *buf, int ns);
+extern void _outsb(volatile u8 *port, const void *buf, int ns);
+extern void _insw(volatile u16 *port, void *buf, int ns);
+extern void _outsw(volatile u16 *port, const void *buf, int ns);
+extern void _insl(volatile u32 *port, void *buf, int nl);
+extern void _outsl(volatile u32 *port, const void *buf, int nl);
+extern void _insw_ns(volatile u16 *port, void *buf, int ns);
+extern void _outsw_ns(volatile u16 *port, const void *buf, int ns);
+extern void _insl_ns(volatile u32 *port, void *buf, int nl);
+extern void _outsl_ns(volatile u32 *port, const void *buf, int nl);
 
 /*
  * output pause versions need a delay at least for the
@@ -92,27 +101,15 @@
 #define inl_p(port)             inl(port)
 #define outl_p(val, port)       (udelay(1), outl((val, (port)))
 
-
-extern void _insb(volatile u8 *port, void *buf, int ns);
-extern void _outsb(volatile u8 *port, const void *buf, int ns);
-extern void _insw(volatile u16 *port, void *buf, int ns);
-extern void _outsw(volatile u16 *port, const void *buf, int ns);
-extern void _insl(volatile u32 *port, void *buf, int nl);
-extern void _outsl(volatile u32 *port, const void *buf, int nl);
-extern void _insw_ns(volatile u16 *port, void *buf, int ns);
-extern void _outsw_ns(volatile u16 *port, const void *buf, int ns);
-extern void _insl_ns(volatile u32 *port, void *buf, int nl);
-extern void _outsl_ns(volatile u32 *port, const void *buf, int nl);
-
 /*
  * The *_ns versions below don't do byte-swapping.
  * Neither do the standard versions now, these are just here
  * for older code.
  */
-#define insw_ns(port, buf, ns)	insw(port, buf, ns)
-#define outsw_ns(port, buf, ns)	outsw(port, buf, ns)
-#define insl_ns(port, buf, nl)	insl(port, buf, nl)
-#define outsl_ns(port, buf, nl)	outsl(port, buf, nl)
+#define insw_ns(port, buf, ns)	_insw_ns((u16 *)((port)+pci_io_base), (buf), (ns))
+#define outsw_ns(port, buf, ns)	_outsw_ns((u16 *)((port)+pci_io_base), (buf), (ns))
+#define insl_ns(port, buf, nl)	_insl_ns((u32 *)((port)+pci_io_base), (buf), (nl))
+#define outsl_ns(port, buf, nl)	_outsl_ns((u32 *)((port)+pci_io_base), (buf), (nl))
 
 
 #define IO_SPACE_LIMIT ~(0UL)
@@ -151,11 +148,12 @@
 #endif
 	return (void *) __va(address);
 }
- 
+
 /*
  * Change "struct page" to physical address.
  */
-#define page_to_phys(page)	((page - mem_map) << PAGE_SHIFT)
+#define page_to_phys(page)      ((page - mem_map) << PAGE_SHIFT)
+
 
 #endif /* __KERNEL__ */
 
@@ -248,49 +246,6 @@
 
 #ifndef CONFIG_PPC_ISERIES 
 #include <asm/eeh.h>
-
-static inline u8 _inb(unsigned long port) {
-	if (IS_MAPPED_VADDR(port))
-		return readb((void *)port);
-	else if (_IO_BASE)
-		return in_8((u8 *)((port)+_IO_BASE));
-	else
-		return 0xff;
-}
-static inline void _outb(u8 val, unsigned long port) {
-	if (IS_MAPPED_VADDR(port))
-		return writeb(val, (void *)port);
-	else if (_IO_BASE)
-		out_8((u8 *)((port)+_IO_BASE), val);
-}
-static inline u16 _inw(unsigned long port) {
-	if (IS_MAPPED_VADDR(port))
-		return readw((void *)port);
-	else if (_IO_BASE)
-		return in_le16((u16 *)((port)+_IO_BASE));
-	else
-		return 0xffff;
-}
-static inline void _outw(u16 val, unsigned long port) {
-	if (IS_MAPPED_VADDR(port))
-		return writew(val, (void *)port);
-	else if (_IO_BASE)
-		out_le16((u16 *)((port)+_IO_BASE), val);
-}
-static inline u32 _inl(unsigned long port) {
-	if (IS_MAPPED_VADDR(port))
-		return readl((void *)port);
-	else if (_IO_BASE)
-		return in_le32((u32 *)((port)+_IO_BASE));
-	else
-		return 0xffffffff;
-}
-static inline void _outl(u32 val, unsigned long port) {
-	if (IS_MAPPED_VADDR(port))
-		return writel(val, (void *)port);
-	else if (_IO_BASE)
-		out_le32((u32 *)((port)+_IO_BASE), val);
-}
 #endif
 
 #ifdef __KERNEL__
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/ioctls.h linux-2.4.21-pre6/include/asm-ppc64/ioctls.h
--- linux-2.4.20/include/asm-ppc64/ioctls.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/ioctls.h	2003-03-26 23:49:19.000000000 +0000
@@ -96,6 +96,7 @@
 #define TIOCGSID	0x5429  /* Return the session ID of FD */
 #define TIOCGPTN	_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
 #define TIOCSPTLCK	_IOW('T',0x31, int)  /* Lock/unlock Pty */
+#define TIOCGDEV	_IOR('T',0x32, unsigned int) /* Get real dev no below /dev/console */
 
 #define TIOCSERCONFIG	0x5453
 #define TIOCSERGWILD	0x5454
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/ipc.h linux-2.4.21-pre6/include/asm-ppc64/ipc.h
--- linux-2.4.20/include/asm-ppc64/ipc.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/ipc.h	2003-03-26 23:49:50.000000000 +0000
@@ -4,7 +4,7 @@
 /* 
  * These are used to wrap system calls on PowerPC.
  *
- * See arch/ppc/kernel/syscalls.c for ugly details..
+ * See arch/ppc64/kernel/syscalls.c for ugly details..
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -12,8 +12,8 @@
  * 2 of the License, or (at your option) any later version.
  */
 struct ipc_kludge {
-	u32 msgp;
-	s32 msgtyp;
+	struct msgbuf *msgp;
+	long msgtyp;
 };
 
 #define SEMOP		 1
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/lmb.h linux-2.4.21-pre6/include/asm-ppc64/lmb.h
--- linux-2.4.20/include/asm-ppc64/lmb.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/lmb.h	2003-03-26 23:49:54.000000000 +0000
@@ -13,6 +13,7 @@
  * 2 of the License, or (at your option) any later version.
  */
 
+#include <linux/config.h>
 #include <asm/prom.h>
 
 extern unsigned long reloc_offset(void);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/memory.h linux-2.4.21-pre6/include/asm-ppc64/memory.h
--- linux-2.4.20/include/asm-ppc64/memory.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/memory.h	2003-03-26 23:49:34.000000000 +0000
@@ -41,4 +41,24 @@
 #define isync_on_smp()	__asm__ __volatile__("": : :"memory")
 #endif
 
+/* Macros for adjusting thread priority (hardware multi-threading) */
+
+#if defined(CONFIG_PPC_ISERIES) || defined(CONFIG_HMT)
+#define HMT_low()	asm volatile("or 1,1,1		# low priority")
+#define HMT_medium()	asm volatile("or 2,2,2		# medium priority")
+#define HMT_high()	asm volatile("or 3,3,3		# high priority")
+
+#define HMT_LOW		"\tor	1,1,1		# low priority\n"
+#define HMT_MEDIUM	"\tor	2,2,2		# medium priority\n"
+#define HMT_HIGH	"\tor	3,3,3		# high priority\n"
+#else
+#define HMT_low()	do { } while(0)
+#define HMT_medium()	do { } while(0)
+#define HMT_high()	do { } while(0)
+
+#define HMT_LOW
+#define HMT_MEDIUM
+#define HMT_LOW
+#endif
+
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/mmu.h linux-2.4.21-pre6/include/asm-ppc64/mmu.h
--- linux-2.4.20/include/asm-ppc64/mmu.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/mmu.h	2003-03-26 23:49:27.000000000 +0000
@@ -168,17 +168,23 @@
 #define PP_RWRW 2	/* Supervisor read/write, User read/write */
 #define PP_RXRX 3	/* Supervisor read,       User read */
 
-
 typedef struct {
 	HPTE *		htab;
 	unsigned long	htab_num_ptegs;
 	unsigned long	htab_hash_mask;
 	unsigned long	next_round_robin;
 	unsigned long   last_kernel_address;
+	unsigned long   htab_lock_shift;
 } HTAB;
 
 extern HTAB htab_data;
 
+#include <linux/cache.h>
+#include <asm/spinlock.h>
+typedef struct {
+	spinlock_t lock;
+} ____cacheline_aligned hash_table_lock_t;
+
 void invalidate_hpte( unsigned long slot );
 long select_hpte_slot( unsigned long vpn );
 void create_valid_hpte( unsigned long slot, unsigned long vpn,
@@ -227,12 +233,18 @@
 		asm volatile("clrldi	%0,%0,16\n\
 			      tlbie	%0,0" : : "r"(va) : "memory");
 	}
-
 	asm volatile("eieio; tlbsync; ptesync": : :"memory");
 }
  
 #endif /* __ASSEMBLY__ */
 
+/*
+ * Location of cpu0's segment table
+ */
+#define STAB0_PAGE	0x9
+#define STAB0_PHYS_ADDR	(STAB0_PAGE<<PAGE_SHIFT)
+#define STAB0_VIRT_ADDR	(KERNELBASE+STAB0_PHYS_ADDR)
+
 /* Block size masks */
 #define BL_128K	0x000
 #define BL_256K 0x001
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/mmu_context.h linux-2.4.21-pre6/include/asm-ppc64/mmu_context.h
--- linux-2.4.20/include/asm-ppc64/mmu_context.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/mmu_context.h	2003-03-26 23:49:08.000000000 +0000
@@ -67,11 +67,12 @@
 init_new_context(struct task_struct *tsk, struct mm_struct *mm)
 {
 	long head, size;
+	unsigned long flags;
 
-	spin_lock( &mmu_context_queue.lock );
+	spin_lock_irqsave(&mmu_context_queue.lock, flags);
 
 	if ( (size = mmu_context_queue.size) <= 0 ) {
-		spin_unlock( &mmu_context_queue.lock );
+		spin_unlock_irqrestore(&mmu_context_queue.lock, flags);
 		return -ENOMEM;
 	}
 
@@ -82,7 +83,7 @@
 	mmu_context_queue.head = head;
 	mmu_context_queue.size = size-1;
 
-	spin_unlock( &mmu_context_queue.lock );
+	spin_unlock_irqrestore(&mmu_context_queue.lock, flags);
 
 	return 0;
 }
@@ -94,11 +95,12 @@
 destroy_context(struct mm_struct *mm)
 {
 	long index, size = mmu_context_queue.size;
+	unsigned long flags;
 
-	spin_lock( &mmu_context_queue.lock );
+	spin_lock_irqsave(&mmu_context_queue.lock, flags);
 
 	if ( (size = mmu_context_queue.size) >= NUM_USER_CONTEXT ) {
-		spin_unlock( &mmu_context_queue.lock );
+		spin_unlock_irqrestore(&mmu_context_queue.lock, flags);
 		mmu_context_underflow();
 	}
 
@@ -115,9 +117,10 @@
 	mmu_context_queue.size = size+1;
 	mmu_context_queue.elements[index] = mm->context;
 
-	spin_unlock( &mmu_context_queue.lock );
+	spin_unlock_irqrestore(&mmu_context_queue.lock, flags);
 }
 
+extern void flush_stab(void);
 
 /*
  * switch_mm is the entry point called from the architecture independent
@@ -127,8 +130,6 @@
 switch_mm(struct mm_struct *prev, struct mm_struct *next,
 	  struct task_struct *tsk, int cpu)
 {
-	tsk->thread.pgdir = next->pgd;	/* cache the pgdir in the thread 
-					   maybe not needed any more */
 	flush_stab();
 }
 
@@ -136,13 +137,8 @@
  * After we have set current->mm to a new value, this activates
  * the context for the new mm so we see the new mappings.
  */
-static inline void
-activate_mm(struct mm_struct *active_mm, struct mm_struct *mm)
-{
-	current->thread.pgdir = mm->pgd;
-	flush_stab();
-}
-
+#define activate_mm(active_mm, mm) \
+	switch_mm(active_mm, mm, current, smp_processor_id());
 
 #define VSID_RANDOMIZER 42470972311
 #define VSID_MASK	0xfffffffff
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/naca.h linux-2.4.21-pre6/include/asm-ppc64/naca.h
--- linux-2.4.20/include/asm-ppc64/naca.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/naca.h	2003-03-26 23:48:58.000000000 +0000
@@ -11,6 +11,7 @@
  */
 
 #include <asm/types.h>
+#include <asm/systemcfg.h>
 
 struct naca_struct {
 	/*==================================================================
@@ -29,47 +30,14 @@
 	u64 interrupt_controller;	/* Type of int controller    0x40 */ 
 	u64 slb_size;			/* SLB size in entries       0x48 */
 	u64 pftSize;			/* Log 2 of page table size  0x50 */
-	u64 resv0[5];                   /* Reserved           0x58 - 0x7F */
-
-	/*==================================================================
-	 * Cache line 2: 0x0080 - 0x00FF
-	 * Kernel / User data
-	 *==================================================================
-	 */
-	u8  eye_catcher[6];             /* Eyecatcher: PPC64         0x00 */
-	u16 version;                    /* Version number            0x06 */
-	u16 platform;			/* Platform flags            0x08 */
-	u16 processor;			/* Processor type            0x0A */
-	u32 processorCount;		/* # of physical processors  0x0C */
-	u64 physicalMemorySize;		/* Size of real memory(B)    0x10 */
-
-	u16 dCacheL1Size;	        /* L1 d-cache size           0x18 */
-	u16 dCacheL1LineSize;		/* L1 d-cache line size      0x1A */
-	u16 dCacheL1LogLineSize;	/* L1 d-cache line size Log2 0x1C */
-	u16 dCacheL1LinesPerPage;	/* L1 d-cache lines / page   0x1E */
-	u16 dCacheL1Assoc;              /* L1 d-cache associativity  0x20 */
-
-	u16 iCacheL1Size;	        /* L1 i-cache size           0x22 */
-	u16 iCacheL1LineSize;		/* L1 i-cache line size      0x24 */
-	u16 iCacheL1LogLineSize;	/* L1 i-cache line size Log2 0x26 */
-	u16 iCacheL1LinesPerPage;	/* L1 i-cache lines / page   0x28 */
-	u16 iCacheL1Assoc;              /* L1 i-cache associativity  0x2A */
-
-	u16 cacheL2Size;	        /* L2 cache size             0x2C */
-	u16 cacheL2Assoc;	        /* L2 cache associativity    0x2E */
-
-	u64 tb_orig_stamp;              /* Timebase at boot          0x30 */
-	u64 tb_ticks_per_sec;           /* Timebase tics / sec       0x38 */
-	u64 tb_to_xs;                   /* Inverse of TB to 2^20     0x40 */
-	u64 stamp_xsec;                 /*                           0x48 */
-	volatile u64 tb_update_count;   /* Timebase atomicity ctr    0x50 */
-	u32 tz_minuteswest;             /* Minutes west of Greenwich 0x58 */
-	u32 tz_dsttime;                 /* Type of dst correction    0x5C */
-
-	u64 resv1[4];                   /* Reserverd          0x60 - 0x7F */
+	void *systemcfg;		/* Pointer to systemcfg data 0x58 */
+	u32 dCacheL1LogLineSize;	/* L1 d-cache line size Log2 0x60 */
+	u32 dCacheL1LinesPerPage;	/* L1 d-cache lines / page   0x64 */
+	u32 iCacheL1LogLineSize;	/* L1 i-cache line size Log2 0x68 */
+	u32 iCacheL1LinesPerPage;	/* L1 i-cache lines / page   0x6c */
+	u64 resv0[2];                   /* Reserved           0x70 - 0x7F */
 };
 
-
 extern struct naca_struct *naca;
 
 #endif /* _NACA_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/paca.h linux-2.4.21-pre6/include/asm-ppc64/paca.h
--- linux-2.4.20/include/asm-ppc64/paca.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/paca.h	2003-03-26 23:49:50.000000000 +0000
@@ -131,9 +131,8 @@
  * CACHE_LINE_19 - 20 Profile Data
  *=====================================================================================
  */
-	u32 pmc[12];                    /* Default pmc value		*/	
+	u64 pmc[12];                    /* Default pmc value		*/	
 	u64 pmcc[8];                    /* Cumulative pmc counts        */
-	u64 rsvd5a[2];
 
 	u32 prof_multiplier;		/*					 */
 	u32 prof_shift;			/* iSeries shift for profile bucket size */
@@ -144,7 +143,7 @@
 	u8  prof_mode;                  /* */
 	u8  rsvv5b[3];
 	u64 prof_counter;		/*					 */
-	u8  rsvd5c[128-8*6];
+	u8  rsvd5c[256-8*26];
 
 /*=====================================================================================
  * CACHE_LINE_20-30
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/page.h linux-2.4.21-pre6/include/asm-ppc64/page.h
--- linux-2.4.20/include/asm-ppc64/page.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/page.h	2003-03-26 23:49:49.000000000 +0000
@@ -14,7 +14,11 @@
 
 /* PAGE_SHIFT determines the page size */
 #define PAGE_SHIFT	12
+#ifndef __ASSEMBLY__
 #define PAGE_SIZE	(1UL << PAGE_SHIFT)
+#else
+# define PAGE_SIZE	(1 << PAGE_SHIFT)
+#endif
 #define PAGE_MASK	(~(PAGE_SIZE-1))
 #define PAGE_OFFSET_MASK (PAGE_SIZE-1)
 
@@ -32,6 +36,7 @@
 #ifdef __KERNEL__
 #ifndef __ASSEMBLY__
 #include <asm/naca.h>
+#include <asm/systemcfg.h>
 
 #define STRICT_MM_TYPECHECKS
 
@@ -57,7 +62,7 @@
 {
 	unsigned long lines, line_size;
 
-	line_size = naca->dCacheL1LineSize; 
+	line_size = systemcfg->dCacheL1LineSize; 
 	lines = naca->dCacheL1LinesPerPage;
 
 	__asm__ __volatile__(
@@ -129,7 +134,7 @@
 /* extern void kdb(kdb_reason_t reason, int error, kdb_eframe_t ef); */
 #define BUG() do { \
       printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
-      kdb(KDB_REASON_OOPS, 0, (kdb_eframe_t) 0); \
+      kdb(KDB_REASON_CALL, 0, (kdb_eframe_t) 0); \
 } while (0)
 #else
 #define BUG() do { \
@@ -189,9 +194,11 @@
 #define KERNELBASE      PAGE_OFFSET
 #define VMALLOCBASE     0xD000000000000000
 #define IOREGIONBASE    0xE000000000000000
+#define EEHREGIONBASE   0xA000000000000000
 #define BOLTEDBASE      0xB000000000000000
 
 #define IO_REGION_ID       (IOREGIONBASE>>REGION_SHIFT)
+#define EEH_REGION_ID      (EEHREGIONBASE>>REGION_SHIFT)
 #define VMALLOC_REGION_ID  (VMALLOCBASE>>REGION_SHIFT)
 #define KERNEL_REGION_ID   (KERNELBASE>>REGION_SHIFT)
 #define BOLTED_REGION_ID   (BOLTEDBASE>>REGION_SHIFT)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/perfmon.h linux-2.4.21-pre6/include/asm-ppc64/perfmon.h
--- linux-2.4.20/include/asm-ppc64/perfmon.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/perfmon.h	2003-03-26 23:49:50.000000000 +0000
@@ -29,17 +29,23 @@
 	u64 trace_buffer;
 	u64 trace_length;
 	u64 trace_end;
+	u64 timeslice_buffer;
+	u64 timeslice_length;
 	u64 state;
 };
 
 struct pmc_header {
-	int type;
-	int pid;
+	int subcmd;
+	union {
+		int type;
+		int pid;	/* PID to trace */
+		int slice; 	/* Timeslice ID */
+	} vdata;
 	int resv[30];
 };
 
 struct pmc_struct {
-        int pmc[11];
+        unsigned long pmc[11];
 };
 
 struct pmc_info_struct {
@@ -59,29 +65,51 @@
 };
 
 enum {
-	PMC_OP_ALLOC         = 1,
-	PMC_OP_FREE          = 2,
-	PMC_OP_CLEAR         = 4,
-	PMC_OP_DUMP          = 5,
-	PMC_OP_DUMP_HARDWARE = 6,
-	PMC_OP_DECR_PROFILE  = 20,
-	PMC_OP_PMC_PROFILE   = 21,
-	PMC_OP_SET           = 30,
-	PMC_OP_SET_USER      = 31,
-	PMC_OP_END           = 30
+	PMC_CMD_BUFFER       = 1,
+	PMC_CMD_DUMP         = 2,
+	PMC_CMD_DECR_PROFILE = 3,
+	PMC_CMD_PROFILE      = 4,
+	PMC_CMD_TRACE        = 5,
+	PMC_CMD_TIMESLICE    = 6
 };
 
+enum {
+	PMC_SUBCMD_BUFFER_ALLOC         = 1,
+	PMC_SUBCMD_BUFFER_FREE          = 2,
+	PMC_SUBCMD_BUFFER_CLEAR         = 3 
+};
 
-#define	PMC_TRACE_CMD 0xFF
+enum {
+	PMC_SUBCMD_DUMP_COUNTERS        = 1,
+	PMC_SUBCMD_DUMP_HARDWARE        = 2
+};
 
 enum {
-	PMC_TYPE_DERC_PROFILE  = 1,
-	PMC_TYPE_CYCLE         = 2,
-	PMC_TYPE_PROFILE       = 3,
-	PMC_TYPE_DCACHE        = 4,
-	PMC_TYPE_L2_MISS       = 5,
-	PMC_TYPE_LWARCX        = 6,
-	PMC_TYPE_END           = 6
+	PMC_SUBCMD_PROFILE_CYCLE        = 1,
+};
+
+enum {
+	PMC_SUBCMD_TIMESLICE_ENABLE     = 1,
+	PMC_SUBCMD_TIMESLICE_DISABLE    = 2,
+	PMC_SUBCMD_TIMESLICE_SET        = 3
+};
+
+#define	PMC_TRACE_CMD 0xFF
+
+/*
+ * The following types are not used by the kernel; they are put into the
+ * trace as flag records for the user space tools to interpret.
+ */
+enum  {
+	PMC_TYPE_DERC_PROFILE   = 1,
+	PMC_TYPE_CYCLE          = 2,
+	PMC_TYPE_PROFILE        = 3,
+	PMC_TYPE_DCACHE         = 4,
+	PMC_TYPE_L2_MISS        = 5,
+	PMC_TYPE_LWARCX         = 6,
+	PMC_TYPE_TIMESLICE      = 7,
+        PMC_TYPE_TIMESLICE_DUMP = 8,
+	PMC_TYPE_END            = 8
 };
 #endif
 
@@ -91,4 +119,5 @@
 #define	PMC_STATE_PROFILE_KERN    0x11
 #define	PMC_STATE_TRACE_KERN      0x20
 #define	PMC_STATE_TRACE_USER      0x21
+#define	PMC_STATE_TIMESLICE       0x40
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/pgtable.h linux-2.4.21-pre6/include/asm-ppc64/pgtable.h
--- linux-2.4.20/include/asm-ppc64/pgtable.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/pgtable.h	2003-03-26 23:48:57.000000000 +0000
@@ -100,9 +100,9 @@
 /* preserving _PAGE_SECONDARY | _PAGE_GROUP_IX */
 #define _PAGE_CHG_MASK	(PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_HPTEFLAGS)
 
-#define _PAGE_BASE	_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_COHERENT
+#define _PAGE_BASE	(_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_COHERENT)
 
-#define _PAGE_WRENABLE	_PAGE_RW | _PAGE_DIRTY 
+#define _PAGE_WRENABLE	(_PAGE_RW | _PAGE_DIRTY)
 
 /* __pgprot defined in asm-ppc64/page.h */
 #define PAGE_NONE	__pgprot(_PAGE_PRESENT | _PAGE_ACCESSED)
@@ -415,7 +415,11 @@
  */
 #define kern_addr_valid(addr)	(1)
 
-#define io_remap_page_range remap_page_range 
+#ifdef CONFIG_PPC_ISERIES
+#define io_remap_page_range remap_page_range
+#else
+extern int io_remap_page_range(unsigned long from, unsigned long to, unsigned long size, pgprot_t prot);
+#endif
 
 /*
  * No page table caches to initialise
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/posix_types.h linux-2.4.21-pre6/include/asm-ppc64/posix_types.h
--- linux-2.4.20/include/asm-ppc64/posix_types.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/posix_types.h	2003-03-26 23:49:08.000000000 +0000
@@ -11,19 +11,10 @@
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  */
-#if 0
-# define DRENG_TYPES
-#endif
 
-#ifdef DRENG_TYPES
 typedef unsigned long	__kernel_dev_t;
 typedef unsigned long	__kernel_ino_t;
 typedef unsigned long  	__kernel_nlink_t;
-#else
-typedef unsigned int	__kernel_dev_t;
-typedef unsigned int	__kernel_ino_t;
-typedef unsigned int  	__kernel_nlink_t;
-#endif
 typedef unsigned int	__kernel_mode_t;
 typedef long		__kernel_off_t;
 typedef long long	__kernel_loff_t;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/ppc32.h linux-2.4.21-pre6/include/asm-ppc64/ppc32.h
--- linux-2.4.20/include/asm-ppc64/ppc32.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/ppc32.h	2003-03-26 23:49:06.000000000 +0000
@@ -43,25 +43,25 @@
 })
 
 /* These are here to support 32-bit syscalls on a 64-bit kernel. */
-typedef unsigned int           __kernel_size_t32;
-typedef int                    __kernel_ssize_t32;
-typedef int                    __kernel_ptrdiff_t32;
-typedef int                    __kernel_time_t32;
-typedef int                    __kernel_clock_t32;
-typedef int                    __kernel_pid_t32;
-typedef unsigned short         __kernel_ipc_pid_t32;
-typedef unsigned int           __kernel_uid_t32;
-typedef unsigned int           __kernel_gid_t32;
-typedef unsigned int           __kernel_dev_t32;
-typedef unsigned int           __kernel_ino_t32;
-typedef unsigned int           __kernel_mode_t32;
-typedef unsigned int           __kernel_umode_t32;
-typedef short                  __kernel_nlink_t32;
-typedef int                    __kernel_daddr_t32;
-typedef int                    __kernel_off_t32;
-typedef unsigned int           __kernel_caddr_t32;
-typedef int 		       __kernel_loff_t32;
-/* typedef __kernel_fsid_t        __kernel_fsid_t32; */
+typedef unsigned int	__kernel_size_t32;
+typedef int		__kernel_ssize_t32;
+typedef int		__kernel_ptrdiff_t32;
+typedef int		__kernel_time_t32;
+typedef int		__kernel_clock_t32;
+typedef int		__kernel_pid_t32;
+typedef unsigned short	__kernel_ipc_pid_t32;
+typedef unsigned int	__kernel_uid_t32;
+typedef unsigned int	__kernel_gid_t32;
+typedef unsigned int	__kernel_dev_t32;
+typedef unsigned int	__kernel_ino_t32;
+typedef unsigned int	__kernel_mode_t32;
+typedef unsigned int	__kernel_umode_t32;
+typedef short		__kernel_nlink_t32;
+typedef int		__kernel_daddr_t32;
+typedef int		__kernel_off_t32;
+typedef unsigned int	__kernel_caddr_t32;
+typedef int		__kernel_loff_t32;
+typedef int		__kernel_key_t32;
 
 struct statfs32 {
 	int f_type;
@@ -87,12 +87,12 @@
 	int si_code;
 
 	union {
-		int _pad[SI_PAD_SIZE];
+		int _pad[SI_PAD_SIZE32];
 
 		/* kill() */
 		struct {
 			__kernel_pid_t32 _pid;		/* sender's pid */
-			unsigned int _uid;		/* sender's uid */
+			__kernel_uid_t32 _uid;		/* sender's uid */
 		} _kill;
 
 		/* POSIX.1b timers */
@@ -104,14 +104,14 @@
 		/* POSIX.1b signals */
 		struct {
 			__kernel_pid_t32 _pid;		/* sender's pid */
-			unsigned int _uid;		/* sender's uid */
+			__kernel_uid_t32 _uid;		/* sender's uid */
 			sigval_t32 _sigval;
 		} _rt;
 
 		/* SIGCHLD */
 		struct {
 			__kernel_pid_t32 _pid;		/* which child */
-			unsigned int _uid;		/* sender's uid */
+			__kernel_uid_t32 _uid;		/* sender's uid */
 			int _status;			/* exit code */
 			__kernel_clock_t32 _utime;
 			__kernel_clock_t32 _stime;
@@ -119,8 +119,7 @@
 
 		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGEMT */
 		struct {
-			u32 _addr; /* faulting insn/memory ref. */
-			int _trapno;
+			unsigned int _addr; /* faulting insn/memory ref. */
 		} _sigfault;
 
 		/* SIGPOLL */
@@ -136,10 +135,10 @@
 
 typedef unsigned int __old_sigset_t32;
 struct __old_sigaction32 {
-	unsigned		sa_handler;
+	unsigned int		sa_handler;
 	__old_sigset_t32  	sa_mask;
 	unsigned int    	sa_flags;
-	unsigned		sa_restorer;     /* not used by Linux/SPARC yet */
+	unsigned int		sa_restorer;     /* not used by Linux/SPARC yet */
 };
 
 
@@ -153,8 +152,7 @@
 } sigset32_t;
 
 struct sigaction32 {
-       unsigned int  sa_handler;	/* Really a pointer, but need to deal 
-					     with 32 bits */
+       unsigned int  sa_handler;	/* Really a pointer, but need to deal with 32 bits */
        unsigned int sa_flags;
        unsigned int sa_restorer;	/* Another 32 bit pointer */
        sigset32_t sa_mask;		/* A 32 bit mask */
@@ -212,7 +210,7 @@
 	unsigned int   st_ctime;
 };
 
-struct sigcontext32_struct {
+struct sigcontext32 {
 	unsigned int	_unused[4];
 	int		signal;
 	unsigned int	handler;
@@ -224,9 +222,36 @@
 	unsigned int	  uc_flags;
 	unsigned int 	  uc_link;
 	stack_32_t	  uc_stack;
-	struct sigcontext32_struct uc_mcontext;
+	struct sigcontext32 uc_mcontext;
 	sigset_t	  uc_sigmask;	/* mask last for extensibility */
 };
 
+struct ipc_kludge_32 {
+	unsigned int msgp;
+	int msgtyp;
+};
+
+struct ipc_perm32 {
+        __kernel_key_t32  key;
+        __kernel_uid_t32  uid;
+        __kernel_gid_t32  gid;
+        __kernel_uid_t32  cuid;
+        __kernel_gid_t32  cgid;
+        __kernel_mode_t32 mode; 
+        unsigned short  seq;
+};
+
+struct ipc64_perm32 {
+	__kernel_key_t32 key;
+	__kernel_uid_t32 uid;
+	__kernel_gid_t32 gid;
+	__kernel_uid_t32 cuid;
+	__kernel_gid_t32 cgid;
+	__kernel_mode_t32 mode;
+	unsigned int	seq;
+	unsigned int	__pad1;
+	unsigned long	__unused1;
+	unsigned long	__unused2;
+};
 
 #endif  /* _PPC64_PPC32_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/ppcdebug.h linux-2.4.21-pre6/include/asm-ppc64/ppcdebug.h
--- linux-2.4.20/include/asm-ppc64/ppcdebug.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/ppcdebug.h	2003-03-26 23:49:26.000000000 +0000
@@ -29,41 +29,45 @@
  * code.  They must be set statically, any attempt to change them dynamically
  * would be a very bad idea.
  */
-#define PPCDBG_MMINIT        PPCDBG_BITVAL(0)
-#define PPCDBG_MM            PPCDBG_BITVAL(1)
-#define PPCDBG_SYS32         PPCDBG_BITVAL(2)
-#define PPCDBG_SYS32NI       PPCDBG_BITVAL(3)
-#define PPCDBG_SYS32X	     PPCDBG_BITVAL(4)
-#define PPCDBG_SYS32M	     PPCDBG_BITVAL(5)
-#define PPCDBG_SYS64         PPCDBG_BITVAL(6)
-#define PPCDBG_SYS64NI       PPCDBG_BITVAL(7)
-#define PPCDBG_SYS64X	     PPCDBG_BITVAL(8)
-#define PPCDBG_SIGNAL        PPCDBG_BITVAL(9)
-#define PPCDBG_SIGNALXMON    PPCDBG_BITVAL(10)
-#define PPCDBG_BINFMT32      PPCDBG_BITVAL(11)
-#define PPCDBG_BINFMT64      PPCDBG_BITVAL(12)
-#define PPCDBG_BINFMTXMON    PPCDBG_BITVAL(13)
-#define PPCDBG_BINFMT_32ADDR PPCDBG_BITVAL(14)
-#define PPCDBG_ALIGNFIXUP    PPCDBG_BITVAL(15)
-#define PPCDBG_TCEINIT       PPCDBG_BITVAL(16)
-#define PPCDBG_TCE           PPCDBG_BITVAL(17)
-#define PPCDBG_PHBINIT       PPCDBG_BITVAL(18)
-#define PPCDBG_SMP           PPCDBG_BITVAL(19)
-#define PPCDBG_BOOT          PPCDBG_BITVAL(20)
-#define PPCDBG_BUSWALK       PPCDBG_BITVAL(21)
-#define PPCDBG_PROM	     PPCDBG_BITVAL(22)
-#define PPCDBG_RTAS	     PPCDBG_BITVAL(23)
-#define PPCDBG_HTABSTRESS    PPCDBG_BITVAL(62)
-#define PPCDBG_HTABSIZE      PPCDBG_BITVAL(63)
-#define PPCDBG_NONE          (0UL)
-#define PPCDBG_ALL           (0xffffffffUL)
-
-/* The default initial value for the debug switch */
-#define PPC_DEBUG_DEFAULT    0 
-/* #define PPC_DEBUG_DEFAULT    PPCDBG_ALL        */
+#define PPCDBG_MMINIT		PPCDBG_BITVAL(0)
+#define PPCDBG_MM		PPCDBG_BITVAL(1)
+#define PPCDBG_SYS32		PPCDBG_BITVAL(2)
+#define PPCDBG_SYS32NI		PPCDBG_BITVAL(3)
+#define PPCDBG_SYS32X		PPCDBG_BITVAL(4)
+#define PPCDBG_SYS32M		PPCDBG_BITVAL(5)
+#define PPCDBG_SYS64		PPCDBG_BITVAL(6)
+#define PPCDBG_SYS64NI		PPCDBG_BITVAL(7)
+#define PPCDBG_SYS64X		PPCDBG_BITVAL(8)
+#define PPCDBG_SIGNAL		PPCDBG_BITVAL(9)
+#define PPCDBG_SIGNAL64		PPCDBG_BITVAL(10)
+#define PPCDBG_SIGNALXMON	PPCDBG_BITVAL(11)
+#define PPCDBG_BINFMT32		PPCDBG_BITVAL(12)
+#define PPCDBG_BINFMT64		PPCDBG_BITVAL(13)
+#define PPCDBG_BINFMTXMON	PPCDBG_BITVAL(14)
+#define PPCDBG_BINFMT_32ADDR	PPCDBG_BITVAL(15)
+#define PPCDBG_ALIGNFIXUP	PPCDBG_BITVAL(16)
+#define PPCDBG_TCEINIT		PPCDBG_BITVAL(17)
+#define PPCDBG_TCE		PPCDBG_BITVAL(18)
+#define PPCDBG_PHBINIT		PPCDBG_BITVAL(19)
+#define PPCDBG_SMP		PPCDBG_BITVAL(20)
+#define PPCDBG_BOOT		PPCDBG_BITVAL(21)
+#define PPCDBG_BUSWALK		PPCDBG_BITVAL(22)
+#define PPCDBG_PROM		PPCDBG_BITVAL(23)
+#define PPCDBG_RTAS		PPCDBG_BITVAL(24)
+#define PPCDBG_HTABSTRESS	PPCDBG_BITVAL(62)
+#define PPCDBG_HTABSIZE		PPCDBG_BITVAL(63)
+#define PPCDBG_NONE		(0UL)
+#define PPCDBG_ALL		(0xffffffffUL)
 
 #define PPCDBG_NUM_FLAGS     64
 
+/* The default initial value for the debug switch */
+#if 0
+# define PPC_DEBUG_DEFAULT	PPCDBG_ALL
+#else
+# define PPC_DEBUG_DEFAULT	PPCDBG_NONE 
+#endif
+
 #ifdef WANT_PPCDBG_TAB
 /* A table of debug switch names to allow name lookup in xmon 
  * (and whoever else wants it.
@@ -73,7 +77,7 @@
 	"mminit", 	"mm",
 	"syscall32", 	"syscall32_ni", "syscall32x",	"syscall32m",
 	"syscall64", 	"syscall64_ni", "syscall64x",
-	"signal",	"signal_xmon",
+	"signal",	"signal64",	"signal_xmon",
 	"binfmt32",	"binfmt64",	"binfmt_xmon",	"binfmt_32addr",
 	"alignfixup",   "tceinit",      "tce",          "phb_init",     
 	"smp",          "boot",         "buswalk",	"prom",
@@ -102,6 +106,7 @@
 #ifdef CONFIG_KDB
 #include <linux/kdb.h>
 #define PPCDBG_ENTER_DEBUGGER() kdb(KDB_REASON_CALL, 0, 0)
+#define PPCDBG_ENTER_DEBUGGER_REGS(X) kdb(KDB_REASON_CALL, 0, X)
 #endif
 
 #else
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/processor.h linux-2.4.21-pre6/include/asm-ppc64/processor.h
--- linux-2.4.20/include/asm-ppc64/processor.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/processor.h	2003-03-26 23:49:19.000000000 +0000
@@ -473,8 +473,6 @@
 #define	  IOCR_SPC	0x00000001
 
 
-/* Processor Version Register */
-
 /* Processor Version Register (PVR) field extraction */
 
 #define	PVR_VER(pvr)  (((pvr) >>  16) & 0xFFFF)	/* Version field */
@@ -588,11 +586,6 @@
 #define RUNLATCH	0x0001
 #define RUN_FLAG	0x0002
 
-/* Macros for adjusting thread priority (hardware multi-threading) */
-#define HMT_low()	asm volatile("or 1,1,1")
-#define HMT_medium()	asm volatile("or 2,2,2")
-#define HMT_high()	asm volatile("or 3,3,3")
-
 /* Size of an exception stack frame contained in the paca. */
 #define EXC_FRAME_SIZE 64
 
@@ -609,7 +602,7 @@
 /*
  * Create a new kernel thread.
  */
-extern long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
+extern long arch_kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
 
 /*
  * Bus types
@@ -625,7 +618,8 @@
 
 #ifdef __KERNEL__
 /* 64-bit user address space is 41-bits (2TBs user VM) */
-#define TASK_SIZE_USER64 (0x0000020000000000UL)
+/* Subtract PGDIR_SIZE to work around a bug in free_pgtables */ 
+#define TASK_SIZE_USER64 (0x0000020000000000UL - PGDIR_SIZE)
 
 /* 
  * 32-bit user address space is 4GB - 1 page 
@@ -659,8 +653,10 @@
 	signed long     last_syscall;
 	unsigned long	flags;
 	double		fpr[32];	/* Complete floating point set */
-	unsigned long	fpscr_pad;	/* fpr ... fpscr must be contiguous */
-	unsigned long	fpscr;		/* Floating point status */
+	unsigned long	fpscr;		/* Floating point status (plus pad) */
+	unsigned long	fpexc_mode;	/* Floating-point exception mode */
+	unsigned long	saved_msr;	/* Save MSR across signal handlers */
+	unsigned long	saved_softe;	/* Ditto for Soft Enable/Disable */
 };
 
 #define PPC_FLAG_32BIT		0x01
@@ -675,7 +671,9 @@
 	swapper_pg_dir, /* pgdir */ \
 	0, /* last_syscall */ \
 	PPC_FLAG_RUN_LIGHT, /* flags */ \
-	{0}, 0, 0 \
+	{0}, /* fprs */ \
+	0, /* fpscr */ \
+	MSR_FE0|MSR_FE1, /* fpexc_mode */ \
 }
 
 /*
@@ -705,6 +703,24 @@
 #define KSTK_EIP(tsk)  ((tsk)->thread.regs? (tsk)->thread.regs->nip: 0)
 #define KSTK_ESP(tsk)  ((tsk)->thread.regs? (tsk)->thread.regs->gpr[1]: 0)
 
+/* Get/set floating-point exception mode */
+#define GET_FPEXC_CTL(tsk, adr)	get_fpexc_mode((tsk), (adr))
+#define SET_FPEXC_CTL(tsk, val)	set_fpexc_mode((tsk), (val))
+
+extern int get_fpexc_mode(struct task_struct *tsk, unsigned long adr);
+extern int set_fpexc_mode(struct task_struct *tsk, unsigned int val);
+
+static inline unsigned int __unpack_fe01(unsigned long msr_bits)
+{
+	return ((msr_bits & MSR_FE0) >> 10) | ((msr_bits & MSR_FE1) >> 8);
+}
+
+static inline unsigned long __pack_fe01(unsigned int fpmode)
+{
+	return ((fpmode << 10) & MSR_FE0) | ((fpmode << 8) & MSR_FE1);
+}
+
+
 /*
  * NOTE! The task struct and the stack go together
  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/prom.h linux-2.4.21-pre6/include/asm-ppc64/prom.h
--- linux-2.4.20/include/asm-ppc64/prom.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/prom.h	2003-03-26 23:49:18.000000000 +0000
@@ -125,11 +125,17 @@
 	int	n_intrs;
 	struct	interrupt_info *intrs;
 	char	*full_name;
+
+	/* PCI stuff probably doesn't belong here */
 	int	busno;			/* for pci devices */
 	int	devfn;			/* for pci devices */
+#define DN_STATUS_BIST_FAILED (1<<0)
+	int	status;			/* Current device status (non-zero is bad) */
+	int	eeh_mode;		/* See eeh.h for possible EEH_MODEs */
+	int	eeh_config_addr;
 	struct  pci_controller *phb;	/* for pci devices */
 	struct	TceTable *tce_table;	/* for phb's or bridges */
-#define DN_STATUS_BIST_FAILED (1<<0)
+
 	struct	property *properties;
 	struct	device_node *parent;
 	struct	device_node *child;
@@ -170,6 +176,7 @@
 };
 
 extern struct prom_t prom;
+extern char *of_stdout_device;
 
 /* Prototypes */
 extern void abort(void);
@@ -194,5 +201,6 @@
 extern int prom_n_addr_cells(struct device_node* np);
 extern int prom_n_size_cells(struct device_node* np);
 extern void prom_get_irq_senses(unsigned char *senses, int off, int max);
+extern void prom_add_property(struct device_node* np, struct property* prop);
 
 #endif /* _PPC64_PROM_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/ptrace.h linux-2.4.21-pre6/include/asm-ppc64/ptrace.h
--- linux-2.4.20/include/asm-ppc64/ptrace.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/ptrace.h	2003-03-26 23:49:50.000000000 +0000
@@ -66,9 +66,8 @@
 
 #define STACK_FRAME_OVERHEAD	112	/* size of minimum stack frame */
 
-/* Size of stack frame allocated when calling signal handler. */
-/* FIXME: What should this be on 64-bit kernel (64 for 32-bit) */
-#define __SIGNAL_FRAMESIZE	64
+/* Size of dummy stack frame allocated when calling signal handler. */
+#define __SIGNAL_FRAMESIZE	128
 #define __SIGNAL_FRAMESIZE32	64
 
 #define instruction_pointer(regs) ((regs)->nip)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/rtas.h linux-2.4.21-pre6/include/asm-ppc64/rtas.h
--- linux-2.4.20/include/asm-ppc64/rtas.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/rtas.h	2003-03-26 23:49:25.000000000 +0000
@@ -168,5 +168,13 @@
 
 extern struct proc_dir_entry *rtas_proc_dir;
 
+/* Some RTAS ops require a data buffer and that buffer must be < 4G.
+ * Rather than having a memory allocator, just use this buffer
+ * (get the lock first), make the RTAS call.  Copy the data instead
+ * of holding the buffer for long.
+ */
+#define RTAS_DATA_BUF_SIZE 1024
+extern spinlock_t rtas_data_buf_lock;
+extern char rtas_data_buf[RTAS_DATA_BUF_SIZE];
 
 #endif /* _PPC64_RTAS_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/rwsem.h linux-2.4.21-pre6/include/asm-ppc64/rwsem.h
--- linux-2.4.20/include/asm-ppc64/rwsem.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/rwsem.h	2003-03-26 23:49:30.000000000 +0000
@@ -79,6 +79,20 @@
 		rwsem_down_read_failed(sem);
 }
 
+static inline int __down_read_trylock(struct rw_semaphore *sem)
+{
+	int tmp;
+
+	while ((tmp = sem->count) >= 0) {
+		if (tmp == cmpxchg(&sem->count, tmp,
+				   tmp + RWSEM_ACTIVE_READ_BIAS)) {
+			smp_wmb();
+			return 1;
+		}
+	}
+	return 0;
+}
+
 /*
  * lock for writing
  */
@@ -94,6 +108,16 @@
 		rwsem_down_write_failed(sem);
 }
 
+static inline int __down_write_trylock(struct rw_semaphore *sem)
+{
+	int tmp;
+
+	tmp = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE,
+		      RWSEM_ACTIVE_WRITE_BIAS);
+	smp_wmb();
+	return tmp == RWSEM_UNLOCKED_VALUE;
+}
+
 /*
  * unlock after reading
  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/sigcontext.h linux-2.4.21-pre6/include/asm-ppc64/sigcontext.h
--- linux-2.4.20/include/asm-ppc64/sigcontext.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/sigcontext.h	2003-03-26 23:49:08.000000000 +0000
@@ -9,13 +9,18 @@
  */
 
 #include <asm/ptrace.h>
+#include <asm/elf.h>
 
-struct sigcontext_struct {
+
+struct sigcontext {
 	unsigned long	_unused[4];
 	int		signal;
+	int		_pad0;
 	unsigned long	handler;
 	unsigned long	oldmask;
-	struct pt_regs 	*regs;
+	struct pt_regs	*regs;
+	elf_gregset_t	gp_regs;
+	elf_fpregset_t	fp_regs;
 };
 
 #endif /* _ASM_PPC64_SIGCONTEXT_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/siginfo.h linux-2.4.21-pre6/include/asm-ppc64/siginfo.h
--- linux-2.4.20/include/asm-ppc64/siginfo.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/siginfo.h	2003-03-26 23:49:35.000000000 +0000
@@ -17,7 +17,8 @@
 } sigval_t;
 
 #define SI_MAX_SIZE	128
-#define SI_PAD_SIZE	((SI_MAX_SIZE/sizeof(int)) - 3)
+#define SI_PAD_SIZE	((SI_MAX_SIZE/sizeof(int)) - 4)
+#define SI_PAD_SIZE32	((SI_MAX_SIZE/sizeof(int)) - 3)
 
 typedef struct siginfo {
 	int si_signo;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/signal.h linux-2.4.21-pre6/include/asm-ppc64/signal.h
--- linux-2.4.20/include/asm-ppc64/signal.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/signal.h	2003-03-26 23:49:15.000000000 +0000
@@ -10,7 +10,7 @@
 #define _NSIG_BPW	64
 #define _NSIG_WORDS	(_NSIG / _NSIG_BPW)
 
-typedef unsigned long old_sigset_t;		/* at least 32 bits */
+typedef unsigned long old_sigset_t;
 
 typedef struct {
 	unsigned long sig[_NSIG_WORDS];
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/smp.h linux-2.4.21-pre6/include/asm-ppc64/smp.h
--- linux-2.4.20/include/asm-ppc64/smp.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/smp.h	2003-03-26 23:49:40.000000000 +0000
@@ -19,6 +19,7 @@
 
 #include <linux/config.h>
 #include <linux/kernel.h>
+#include <linux/threads.h>	/* for NR_CPUS */
 
 #ifdef CONFIG_SMP
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/smplock.h linux-2.4.21-pre6/include/asm-ppc64/smplock.h
--- linux-2.4.20/include/asm-ppc64/smplock.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/smplock.h	2003-03-26 23:49:35.000000000 +0000
@@ -10,6 +10,7 @@
  */
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
+#include <asm/current.h>
 
 extern spinlock_t kernel_flag;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/stat.h linux-2.4.21-pre6/include/asm-ppc64/stat.h
--- linux-2.4.20/include/asm-ppc64/stat.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/stat.h	2003-03-26 23:48:57.000000000 +0000
@@ -27,8 +27,8 @@
 struct stat {
 	dev_t		st_dev;
 	ino_t		st_ino;
-	mode_t		st_mode;
 	nlink_t		st_nlink;
+	mode_t		st_mode;
 	uid_t 		st_uid;
 	gid_t 		st_gid;
 	dev_t		st_rdev;
@@ -43,6 +43,7 @@
 	unsigned long  	__unused3;
 	unsigned long  	__unused4;
 	unsigned long  	__unused5;
+	unsigned long  	__unused6;
 };
 
 /* This matches struct stat64 in glibc2.1. */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/syscall.h linux-2.4.21-pre6/include/asm-ppc64/syscall.h
--- linux-2.4.20/include/asm-ppc64/syscall.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/syscall.h	2003-03-26 23:49:54.000000000 +0000
@@ -0,0 +1,8 @@
+#ifndef _ASM_SYSCALL_H
+#define _ASM_SYSCALL_H
+
+/*
+ * Prototypes for architecture-specific Linux syscalls.
+ */
+
+#endif /* _ASM_SYSCALL_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/system.h linux-2.4.21-pre6/include/asm-ppc64/system.h
--- linux-2.4.20/include/asm-ppc64/system.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/system.h	2003-03-26 23:49:27.000000000 +0000
@@ -90,6 +90,7 @@
 #define save_flags(flags)	__save_flags(flags)
 #define restore_flags(flags)	__restore_flags(flags)
 #define save_and_cli(flags)	__save_and_cli(flags)
+#define save_and_sti(flags)	__save_and_sti(flags)
 
 #else /* CONFIG_SMP */
 
@@ -102,11 +103,15 @@
 #define save_flags(x) ((x)=__global_save_flags())
 #define restore_flags(x) __global_restore_flags(x)
 
+#define save_and_cli(x) do { save_flags(x); cli(); } while(0);
+#define save_and_sti(x) do { save_flags(x); sti(); } while(0);
+
 #endif /* !CONFIG_SMP */
 
 #define local_irq_disable()		__cli()
 #define local_irq_enable()		__sti()
 #define local_irq_save(flags)		__save_and_cli(flags)
+#define local_irq_set(flags)		__save_and_sti(flags)
 #define local_irq_restore(flags)	__restore_flags(flags)
 
 static __inline__ int __is_processor(unsigned long pv)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/systemcfg.h linux-2.4.21-pre6/include/asm-ppc64/systemcfg.h
--- linux-2.4.20/include/asm-ppc64/systemcfg.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/systemcfg.h	2003-03-26 23:49:35.000000000 +0000
@@ -0,0 +1,101 @@
+#ifndef _SYSTEMCFG_H
+#define _SYSTEMCFG_H
+
+/* 
+ * Copyright (C) 2002 Peter Bergner <bergner@vnet.ibm.com>, IBM
+ *
+ * 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.
+ */
+
+/* Change Activity:
+ * 2002/09/30 : bergner  : Created
+ * End Change Activity 
+ */
+
+
+#ifndef __KERNEL__
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <linux/types.h>
+#endif
+
+/*
+ * If the major version changes we are incompatible.
+ * Minor version changes are a hint.
+ */
+#define SYSTEMCFG_MAJOR 1
+#define SYSTEMCFG_MINOR 0
+
+struct systemcfg {
+	__u8  eye_catcher[16];		/* Eyecatcher: SYSTEMCFG:PPC64	0x00 */
+	struct {			/* Systemcfg version numbers	     */
+		__u32 major;		/* Major number			0x10 */
+		__u32 minor;		/* Minor number			0x14 */
+	} version;
+
+	__u32 platform;			/* Platform flags		0x18 */
+	__u32 processor;		/* Processor type		0x1C */
+	__u64 processorCount;		/* # of physical processors	0x20 */
+	__u64 physicalMemorySize;	/* Size of real memory(B)	0x28 */
+	__u64 tb_orig_stamp;		/* Timebase at boot		0x30 */
+	__u64 tb_ticks_per_sec;		/* Timebase tics / sec		0x38 */
+	__u64 tb_to_xs;			/* Inverse of TB to 2^20	0x40 */
+	__u64 stamp_xsec;		/*				0x48 */
+	__u64 tb_update_count;		/* Timebase atomicity ctr	0x50 */
+	__u32 tz_minuteswest;		/* Minutes west of Greenwich	0x58 */
+	__u32 tz_dsttime;		/* Type of dst correction	0x5C */
+	__u32 dCacheL1Size;		/* L1 d-cache size		0x60 */
+	__u32 dCacheL1LineSize;		/* L1 d-cache line size		0x64 */
+	__u32 iCacheL1Size;		/* L1 i-cache size		0x68 */
+	__u32 iCacheL1LineSize;		/* L1 i-cache line size		0x6C */
+	__u8  reserved0[3984];		/* Reserve rest of page		0x70 */
+};
+
+#ifdef __KERNEL__
+extern struct systemcfg *systemcfg;
+#else
+
+/* Processor Version Register (PVR) field extraction */
+#define PVR_VER(pvr)  (((pvr) >>  16) & 0xFFFF) /* Version field */
+#define PVR_REV(pvr)  (((pvr) >>   0) & 0xFFFF) /* Revison field */
+
+/* Processor Version Numbers */
+#define PV_NORTHSTAR    0x0033
+#define PV_PULSAR       0x0034
+#define PV_POWER4       0x0035
+#define PV_ICESTAR      0x0036
+#define PV_SSTAR        0x0037
+#define PV_POWER4p      0x0038
+#define PV_630          0x0040
+#define PV_630p         0x0041
+
+/* Platforms supported by PPC64 */
+#define PLATFORM_PSERIES      0x0100
+#define PLATFORM_PSERIES_LPAR 0x0101
+#define PLATFORM_ISERIES_LPAR 0x0201
+
+
+static inline volatile struct systemcfg *systemcfg_init(void)
+{
+	int fd = open("/proc/ppc64/systemcfg", O_RDONLY);
+	volatile struct systemcfg *ret;
+
+	if (fd == -1)
+		return 0;
+	ret = mmap(0, sizeof(struct systemcfg), PROT_READ, MAP_SHARED, fd, 0);
+	close(fd);
+	if (!ret)
+		return 0;
+	if (ret->version.major != SYSTEMCFG_MAJOR || ret->version.minor < SYSTEMCFG_MINOR) {
+		munmap((void *)ret, sizeof(struct systemcfg));
+		return 0;
+	}
+	return ret;
+}
+#endif /* __KERNEL__ */
+
+#endif /* _SYSTEMCFG_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/termios.h linux-2.4.21-pre6/include/asm-ppc64/termios.h
--- linux-2.4.20/include/asm-ppc64/termios.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/termios.h	2003-03-26 23:49:50.000000000 +0000
@@ -192,8 +192,6 @@
 #define TIOCM_OUT2	0x4000
 #define TIOCM_LOOP	0x8000
 
-#define TIOCM_MODEM_BITS       TIOCM_OUT2      /* IRDA support */
-
 /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
 #define TIOCSER_TEMT    0x01	/* Transmitter physically empty */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/timex.h linux-2.4.21-pre6/include/asm-ppc64/timex.h
--- linux-2.4.20/include/asm-ppc64/timex.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/timex.h	2003-03-26 23:49:18.000000000 +0000
@@ -28,7 +28,7 @@
 	return ret;
 }
 
-#define vxtime_lock()          do {} while (0)
-#define vxtime_unlock()                do {} while (0)
+#define vxtime_lock()		do {} while (0)
+#define vxtime_unlock()		do {} while (0)
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/types.h linux-2.4.21-pre6/include/asm-ppc64/types.h
--- linux-2.4.20/include/asm-ppc64/types.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/types.h	2003-03-26 23:49:10.000000000 +0000
@@ -64,6 +64,12 @@
 typedef u32 dma_addr_t;
 typedef u64 dma64_addr_t;
 
+typedef struct {
+	unsigned long entry;
+	unsigned long toc;
+	unsigned long env;
+} func_descr_t;
+
 #endif /* __KERNEL__ */
 #endif /* __ASSEMBLY__ */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/uaccess.h linux-2.4.21-pre6/include/asm-ppc64/uaccess.h
--- linux-2.4.20/include/asm-ppc64/uaccess.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/uaccess.h	2003-03-26 23:48:57.000000000 +0000
@@ -11,6 +11,7 @@
 #ifndef __ASSEMBLY__
 #include <linux/sched.h>
 #include <linux/errno.h>
+#include <asm/pgtable.h>
 #include <asm/processor.h>
 
 #define VERIFY_READ	0
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/ucontext.h linux-2.4.21-pre6/include/asm-ppc64/ucontext.h
--- linux-2.4.20/include/asm-ppc64/ucontext.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/ucontext.h	2003-03-26 23:49:37.000000000 +0000
@@ -1,10 +1,9 @@
-#ifndef _ASMPPC64_UCONTEXT_H
-#define _ASMPPC64_UCONTEXT_H
+#ifndef _ASM_PPC64_UCONTEXT_H
+#define _ASM_PPC64_UCONTEXT_H
 
 #include <asm/sigcontext.h>
 
-/* Copied from i386. 
- *
+/*
  * 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
@@ -15,8 +14,9 @@
 	unsigned long	  uc_flags;
 	struct ucontext  *uc_link;
 	stack_t		  uc_stack;
-	struct sigcontext_struct uc_mcontext;
-	sigset_t	  uc_sigmask;	/* mask last for extensibility */
+	sigset_t	  uc_sigmask;
+	sigset_t	  __unsued[15];	/* Allow for uc_sigmask growth */
+	struct sigcontext uc_mcontext;  /* last for extensibility */
 };
 
-#endif /* _ASMPPC64_UCONTEXT_H */
+#endif /* _ASM_PPC64_UCONTEXT_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-ppc64/unistd.h linux-2.4.21-pre6/include/asm-ppc64/unistd.h
--- linux-2.4.20/include/asm-ppc64/unistd.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-ppc64/unistd.h	2003-03-26 23:49:15.000000000 +0000
@@ -200,6 +200,7 @@
 #define __NR_putpmsg		188	/* some people actually want streams */
 #define __NR_vfork		189
 #define __NR_ugetrlimit		190	/* SuS compliant getrlimit */
+#define __NR_readahead		191
 #define __NR_mmap2		192
 #define __NR_truncate64		193
 #define __NR_ftruncate64	194
@@ -216,7 +217,6 @@
 #define __NR_madvise		205
 #define __NR_mincore		206
 #define __NR_gettid		207
-#if 0 /* Reserved syscalls */
 #define __NR_tkill		208
 #define __NR_setxattr		209
 #define __NR_lsetxattr		210
@@ -231,7 +231,19 @@
 #define __NR_lremovexattr	219
 #define __NR_fremovexattr	220
 #define __NR_futex		221
-#endif
+#define __NR_sched_setaffinity	222     
+#define __NR_sched_getaffinity	223
+#define __NR_security		224
+#define __NR_tuxcall		225
+#define __NR_sendfile64		226
+#define __NR_io_setup		227
+#define __NR_io_destroy		228
+#define __NR_io_getevents	229
+#define __NR_io_submit		230
+#define __NR_io_cancel		231
+#define __NR_alloc_hugepages	232
+#define __NR_free_hugepages	233
+#define __NR_exit_group		234
 
 #define __NR(n)	#n
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-s390/ebcdic.h linux-2.4.21-pre6/include/asm-s390/ebcdic.h
--- linux-2.4.20/include/asm-s390/ebcdic.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-s390/ebcdic.h	2003-03-26 23:49:34.000000000 +0000
@@ -32,7 +32,7 @@
                 "0: tr   0(256,%0),0(%2)\n"
 		"   la   %0,256(%0)\n"
 		"1: ahi  %1,-256\n"
-		"   jp   0b\n"
+		"   jnm  0b\n"
 		"   ex   %1,0(1)"
                 : "+&a" (addr), "+&a" (nr)
                 : "a" (codepage) : "cc", "memory", "1" );
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-s390/idals.h linux-2.4.21-pre6/include/asm-s390/idals.h
--- linux-2.4.20/include/asm-s390/idals.h	2002-02-25 19:38:13.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-s390/idals.h	2003-03-26 23:49:05.000000000 +0000
@@ -1,74 +1,258 @@
 /* 
-   * File...........: linux/include/asm-s390x/idals.h
-   * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
-   * Bugreports.to..: <Linux390@de.ibm.com>
-   * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000a
-   
-   * History of changes
-   * 07/24/00 new file
+ * File...........: linux/include/asm-s390x/idals.h
+ * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
+ *		    Martin Schwidefsky <schwidefsky@de.ibm.com>
+ * Bugreports.to..: <Linux390@de.ibm.com>
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000a
+ 
+ * History of changes
+ * 07/24/00 new file
+ * 05/04/02 code restructuring.
  */
+
+#ifndef _S390_IDALS_H
+#define _S390_IDALS_H
+
 #include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/slab.h>
 #include <asm/irq.h>
+#include <asm/uaccess.h>
 
+#ifdef CONFIG_ARCH_S390X
+#define IDA_SIZE_LOG 12 /* 11 for 2k , 12 for 4k */
+#else
 #define IDA_SIZE_LOG 11 /* 11 for 2k , 12 for 4k */
+#endif
 #define IDA_BLOCK_SIZE (1L<<IDA_SIZE_LOG)
 
-static inline addr_t *
-idal_alloc ( int nridaws )
+/*
+ * Test if an address/length pair needs an idal list.
+ */
+static inline int
+idal_is_needed(void *vaddr, unsigned int length)
 {
-	if ( nridaws > 33 )
-		BUG();
-	return kmalloc(nridaws * sizeof(addr_t), GFP_ATOMIC | GFP_DMA );
+#if defined(CONFIG_ARCH_S390X)
+	return ((__pa(vaddr) + length) >> 31) != 0;
+#else
+	return 0;
+#endif
 }
 
-static inline void 
-idal_free ( addr_t *idal )
+
+/*
+ * Return the number of idal words needed for an address/length pair.
+ */
+static inline unsigned int
+idal_nr_words(void *vaddr, unsigned int length)
 {
-	kfree (idal);
+#if defined(CONFIG_ARCH_S390X)
+	if (idal_is_needed(vaddr, length))
+		return ((__pa(vaddr) & (IDA_BLOCK_SIZE-1)) + length + 
+			(IDA_BLOCK_SIZE-1)) >> IDA_SIZE_LOG;
+#endif
+	return 0;
 }
 
+/*
+ * Create the list of idal words for an address/length pair.
+ */
+static inline unsigned long *
+idal_create_words(unsigned long *idaws, void *vaddr, unsigned int length)
+{
 #if defined(CONFIG_ARCH_S390X)
-extern unsigned long __create_idal(unsigned long address, int count);
+	unsigned long paddr;
+	unsigned int cidaw;
+
+	paddr = __pa(vaddr);
+	cidaw = ((paddr & (IDA_BLOCK_SIZE-1)) + length + 
+		 (IDA_BLOCK_SIZE-1)) >> IDA_SIZE_LOG;
+	*idaws++ = paddr;
+	paddr &= -IDA_BLOCK_SIZE;
+	while (--cidaw > 0) {
+		paddr += IDA_BLOCK_SIZE;
+		*idaws++ = paddr;
+	}
 #endif
+	return idaws;
+}
 
 /*
- * Function: set_normalized_cda
- * sets the address of the data in CCW
- * if necessary it allocates an IDAL and sets sthe appropriate flags
+ * Sets the address of the data in CCW.
+ * If necessary it allocates an IDAL and sets the appropriate flags.
  */
 static inline int
-set_normalized_cda(ccw1_t * ccw, unsigned long address)
+set_normalized_cda(ccw1_t * ccw, void *vaddr)
 {
-	int ret = 0;
-
 #if defined (CONFIG_ARCH_S390X)
-	if (((address + ccw->count) >> 31) != 0) {
-		if (ccw->flags & CCW_FLAG_IDA)
-			BUG();
-		address = __create_idal(address, ccw->count);
-		if (address)
-			ccw->flags |= CCW_FLAG_IDA;
-		else
-			ret = -ENOMEM;
+	unsigned int nridaws;
+	unsigned long *idal;
+
+	if (ccw->flags & CCW_FLAG_IDA)
+		return -EINVAL;
+	nridaws = idal_nr_words(vaddr, ccw->count);
+	if (nridaws > 0) {
+		idal = kmalloc(nridaws * sizeof(unsigned long),
+			       GFP_ATOMIC | GFP_DMA );
+		if (idal == NULL)
+			return -ENOMEM;
+		idal_create_words(idal, vaddr, ccw->count);
+		ccw->flags |= CCW_FLAG_IDA;
+		vaddr = idal;
 	}
 #endif
-	ccw->cda = (__u32) address;
-	return ret;
+	ccw->cda = (__u32)(unsigned long) vaddr;
+	return 0;
 }
 
 /*
- * Function: clear_normalized_cda
- * releases any allocated IDAL related to the CCW
+ * Releases any allocated IDAL related to the CCW.
  */
 static inline void
-clear_normalized_cda ( ccw1_t * ccw ) 
+clear_normalized_cda(ccw1_t * ccw)
 {
 #if defined(CONFIG_ARCH_S390X)
-	if ( ccw -> flags & CCW_FLAG_IDA ) {
-		idal_free ( (addr_t *)(unsigned long) (ccw -> cda ));
-		ccw -> flags &= ~CCW_FLAG_IDA;
+	if (ccw->flags & CCW_FLAG_IDA) {
+		kfree((void *)(unsigned long) ccw->cda);
+		ccw->flags &= ~CCW_FLAG_IDA;
 	}
 #endif
-	ccw -> cda = 0;
+	ccw->cda = 0;
 }
 
+/*
+ * Idal buffer extension
+ */
+struct idal_buffer {
+	size_t size;
+	size_t page_order;
+	void *data[0];
+};
+
+/*
+ * Allocate an idal buffer
+ */
+static inline struct idal_buffer *
+idal_buffer_alloc(size_t size, int page_order)
+{
+	struct idal_buffer *ib;
+	int nr_chunks, nr_ptrs, i;
+
+	nr_ptrs = (size + IDA_BLOCK_SIZE - 1) >> IDA_SIZE_LOG;
+	nr_chunks = (4096 << page_order) >> IDA_SIZE_LOG;
+	ib = kmalloc(sizeof(struct idal_buffer) + nr_ptrs*sizeof(void *),
+		     GFP_DMA | GFP_KERNEL);
+	if (ib == NULL)
+		return ERR_PTR(-ENOMEM);
+	ib->size = size;
+	ib->page_order = page_order;
+	for (i = 0; i < nr_ptrs; i++) {
+		if ((i & (nr_chunks - 1)) != 0) {
+			ib->data[i] = ib->data[i-1] + IDA_BLOCK_SIZE;
+			continue;
+		}
+		ib->data[i] = (void *)
+			__get_free_pages(GFP_KERNEL, page_order);
+		if (ib->data[i] != NULL)
+			continue;
+		// Not enough memory
+		while (i >= nr_chunks) {
+			i -= nr_chunks;
+			free_pages((unsigned long) ib->data[i],
+				   ib->page_order);
+		}
+		kfree(ib);
+		return ERR_PTR(-ENOMEM);
+	}
+	return ib;
+}
+
+/*
+ * Free an idal buffer.
+ */
+static inline void
+idal_buffer_free(struct idal_buffer *ib)
+{
+	int nr_chunks, nr_ptrs, i;
+
+	nr_ptrs = (ib->size + IDA_BLOCK_SIZE - 1) >> IDA_SIZE_LOG;
+	nr_chunks = (4096 << ib->page_order) >> IDA_SIZE_LOG;
+	for (i = 0; i < nr_ptrs; i += nr_chunks)
+		free_pages((unsigned long) ib->data[i], ib->page_order);
+	kfree(ib);
+}
+
+/*
+ * Test if a idal list is really needed.
+ */
+static inline int
+__idal_buffer_is_needed(struct idal_buffer *ib)
+{
+#ifdef CONFIG_ARCH_S390X
+	return ib->size > (4096 << ib->page_order) ||
+		idal_is_needed(ib->data[0], ib->size);
+#else
+	return ib->size > (4096 << ib->page_order);
+#endif
+}
+
+/*
+ * Set channel data address to idal buffer.
+ */
+static inline void
+idal_buffer_set_cda(struct idal_buffer *ib, ccw1_t *ccw)
+{
+	if (__idal_buffer_is_needed(ib)) {
+		// setup idals;
+		ccw->cda = (u32)(addr_t) ib->data;
+		ccw->flags |= CCW_FLAG_IDA;
+	} else
+		// we do not need idals - use direct addressing
+		ccw->cda = (u32)(addr_t) ib->data[0];
+	ccw->count = ib->size;
+}
+
+/*
+ * Copy count bytes from an idal buffer to user memory
+ */
+static inline size_t
+idal_buffer_to_user(struct idal_buffer *ib, void *to, size_t count)
+{
+	size_t left;
+	int i;
+
+	if (count > ib->size)
+		BUG();
+	for (i = 0; count > IDA_BLOCK_SIZE; i++) {
+		left = copy_to_user(to, ib->data[i], IDA_BLOCK_SIZE);
+		if (left)
+			return left + count - IDA_BLOCK_SIZE;
+		(addr_t) to += IDA_BLOCK_SIZE;
+		count -= IDA_BLOCK_SIZE;
+	}
+	return copy_to_user(to, ib->data[i], count);
+}
+
+/*
+ * Copy count bytes from user memory to an idal buffer
+ */
+static inline size_t
+idal_buffer_from_user(struct idal_buffer *ib, void *from, size_t count)
+{
+	size_t left;
+	int i;
+
+	if (count > ib->size)
+		BUG();
+	for (i = 0; count > IDA_BLOCK_SIZE; i++) {
+		left = copy_from_user(ib->data[i], from, IDA_BLOCK_SIZE);
+		if (left)
+			return left + count - IDA_BLOCK_SIZE;
+		(addr_t) from += IDA_BLOCK_SIZE;
+		count -= IDA_BLOCK_SIZE;
+	}
+	return copy_from_user(ib->data[i], from, count);
+}
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-s390/ide.h linux-2.4.21-pre6/include/asm-s390/ide.h
--- linux-2.4.20/include/asm-s390/ide.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-s390/ide.h	2003-03-26 23:49:39.000000000 +0000
@@ -15,45 +15,6 @@
 #define MAX_HWIFS	0
 #endif
 
-#define ide__sti()	do {} while (0)
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned bit0		: 1;
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned reserved456	: 3;
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-	} b;
-} control_t;
-
-#define ide_request_irq(irq,hand,flg,dev,id)	do {} while (0)
-#define ide_free_irq(irq,dev_id)		do {} while (0)
-#define ide_check_region(from,extent)		do {} while (0)
-#define ide_request_region(from,extent,name)	do {} while (0)
-#define ide_release_region(from,extent)		do {} while (0)
-
-/*
- * The following are not needed for the non-m68k ports
- */
-#define ide_ack_intr(hwif)		(1)
-#define ide_fix_driveid(id)		do {} while (0)
-#define ide_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
-
 /*
  * We always use the new IDE port registering,
  * so these are fixed here.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-s390/io.h linux-2.4.21-pre6/include/asm-s390/io.h
--- linux-2.4.20/include/asm-s390/io.h	2001-07-25 21:12:02.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-s390/io.h	2003-03-26 23:49:50.000000000 +0000
@@ -40,6 +40,11 @@
         return __io_virt(address);
 }
 
+/*
+ * Change "struct page" to physical address.
+ */
+#define page_to_phys(page)	((page - mem_map) << PAGE_SHIFT)
+
 extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
 
 extern inline void * ioremap (unsigned long offset, unsigned long size)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-s390/page.h linux-2.4.21-pre6/include/asm-s390/page.h
--- linux-2.4.20/include/asm-s390/page.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-s390/page.h	2003-03-26 23:49:09.000000000 +0000
@@ -9,6 +9,7 @@
 #ifndef _S390_PAGE_H
 #define _S390_PAGE_H
 
+#include <asm/errno.h>
 #include <asm/setup.h>
 #include <asm/types.h>
 
@@ -17,6 +18,9 @@
 #define PAGE_SIZE       (1UL << PAGE_SHIFT)
 #define PAGE_MASK       (~(PAGE_SIZE-1))
 
+#define STORAGE_ACC_KEY		6
+#define STORAGE_ACC_KEY_MASK	(STORAGE_ACC_KEY<<4)
+
 #ifdef __KERNEL__
 #ifndef __ASSEMBLY__
 
@@ -64,7 +68,7 @@
 
 #define BUG() do { \
         printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
-        __asm__ __volatile__(".word 0x0000"); \
+        __asm__ __volatile__(".long 0"); \
 } while (0)                                       
 
 #define PAGE_BUG(page) do { \
@@ -120,6 +124,59 @@
 #define virt_to_page(kaddr)	(mem_map + (__pa(kaddr) >> PAGE_SHIFT))
 #define VALID_PAGE(page)	((page - mem_map) < max_mapnr)
 
+/* the pfix table of all mem addresses */
+extern void* *pfix_table;
+#define pfix_get_page_addr(ptr) (pfix_table[(unsigned long)ptr>>PAGE_SHIFT])
+#define pfix_get_addr(ptr) (pfix_get_page_addr(ptr)+ \
+			    ((unsigned long)ptr&PAGE_MASK))
+
+/*
+ * These functions allow to lock and unlock pages in VM. They need
+ * the absolute address of the page to be locked or unlocked. This will
+ * only work if the diag98 option in the user directory is enabled for
+ * the guest.
+ */
+
+/* if result is 0, addr will become the host absolute address */
+extern __inline__ int pfix_lock_page(void *addr)
+{
+        int ret = -ENOMEM;
+
+        if (!MACHINE_HAS_PFIX)
+                return -ENOSYS;
+
+        __asm__ __volatile__(
+                "   l     0,%1\n"  /* parameter in gpr 0 */
+                "   lhi   2,0\n"   /* function code is 0 */
+                "   diag  2,0,0x98\n" /* result in gpr 1 */
+                "   jnz   0f\n"
+                "   lhi   %0,0\n"
+                "0: l     %1,1\n"  /* gpr1 contains host absol. addr */
+                : "+d" (ret), "+d" ((unsigned long)addr) : 
+                : "0", "1", "2", "cc" );
+        return ret;
+}
+
+extern __inline__ int pfix_unlock_page(unsigned long addr)
+{
+        int ret = -EINVAL;
+
+        if (!MACHINE_HAS_PFIX)
+                return -ENOSYS;
+
+        __asm__ __volatile__(
+                "   lr    0,%1\n"  /* parameter in gpr 0 */
+                "   lhi   2,4\n"   /* function code is 4 */
+                "   diag  2,0,0x98\n" /* result in gpr 1 */
+                "   jnz   0f\n"
+                "   lhi   %0,0\n"
+                "0:\n"
+                : "+d" (ret)
+                : "a" (addr)
+                : "0", "1", "2", "cc" );
+        return ret;
+}
+
 #define VM_DATA_DEFAULT_FLAGS	(VM_READ | VM_WRITE | VM_EXEC | \
 				 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-s390/pci.h linux-2.4.21-pre6/include/asm-s390/pci.h
--- linux-2.4.20/include/asm-s390/pci.h	2001-07-04 18:50:39.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-s390/pci.h	2003-03-26 23:49:50.000000000 +0000
@@ -5,5 +5,11 @@
  * includes it even if CONFIG_PCI is not set.
  */
 
+/* The PCI address space does equal the physical memory
+ * address space.  The networking and block device layers use
+ * this boolean for bounce buffer decisions.
+ */
+#define PCI_DMA_BUS_IS_PHYS     (1)
+
 #endif /* __ASM_S390_PCI_H */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-s390/pgalloc.h linux-2.4.21-pre6/include/asm-s390/pgalloc.h
--- linux-2.4.20/include/asm-s390/pgalloc.h	2001-10-11 16:43:38.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-s390/pgalloc.h	2003-03-26 23:49:40.000000000 +0000
@@ -237,14 +237,15 @@
 
 static inline void __flush_tlb_mm(struct mm_struct * mm)
 {
-	if ((smp_num_cpus > 1) &&
-	    ((atomic_read(&mm->mm_count) != 1) ||
-	     (mm->cpu_vm_mask != (1UL << smp_processor_id())))) {
-		mm->cpu_vm_mask = (1UL << smp_processor_id());
+	if (mm->cpu_vm_mask != (1UL << smp_processor_id())) {
+		/* mm was active on more than one cpu. */
+		if (mm == current->active_mm &&
+		    atomic_read(&mm->mm_users) == 1)
+			/* this cpu is the only one using the mm. */
+			mm->cpu_vm_mask = 1UL << smp_processor_id();
 		global_flush_tlb();
-	} else {                 
+	} else
 		local_flush_tlb();
-	}
 }
 
 static inline void flush_tlb(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-s390/pgtable.h linux-2.4.21-pre6/include/asm-s390/pgtable.h
--- linux-2.4.20/include/asm-s390/pgtable.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-s390/pgtable.h	2003-03-26 23:49:51.000000000 +0000
@@ -236,12 +236,22 @@
 		pte_val(pteval) &= ~_PAGE_MKCLEAN;
                
 		asm volatile ("sske %0,%1" 
-				: : "d" (0), "a" (pte_val(pteval)));
+				: : "d" (STORAGE_ACC_KEY_MASK),
+				"a" (pte_val(pteval)));
 	}
 
 	*pteptr = pteval;
 }
 
+extern inline void set_access_key(pte_t pteval)
+{
+	asm volatile ("    iske 0,%1\n"
+		      "    or   0,%0\n"
+		      "    sske 0,%1\n"
+			: : "d" (STORAGE_ACC_KEY_MASK),
+			"a" (pte_val(pteval)) : "0", "cc");
+}
+
 #define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT))
 
 /*
@@ -333,7 +343,7 @@
 
 extern inline pte_t pte_mkwrite(pte_t pte) 
 {
-	pte_val(pte) &= ~_PAGE_RO;
+	pte_val(pte) &= ~(_PAGE_RO | _PAGE_ISCLEAN);
 	return pte;
 }
 
@@ -394,7 +404,7 @@
 	/* We can't clear the changed bit atomically. For now we
          * clear (!) the page referenced bit. */
 	asm volatile ("sske %0,%1" 
-	              : : "d" (0), "a" (*ptep));
+	              : : "d" (STORAGE_ACC_KEY_MASK), "a" (*ptep));
 	return 1;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-s390/processor.h linux-2.4.21-pre6/include/asm-s390/processor.h
--- linux-2.4.20/include/asm-s390/processor.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-s390/processor.h	2003-03-26 23:49:37.000000000 +0000
@@ -113,7 +113,7 @@
 
 /* Free all resources held by a thread. */
 extern void release_thread(struct task_struct *);
-extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
+extern int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
 /* Copy and release all segment info associated with a VM */
 #define copy_segments(nr, mm)           do { } while (0)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-s390/rwsem.h linux-2.4.21-pre6/include/asm-s390/rwsem.h
--- linux-2.4.20/include/asm-s390/rwsem.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-s390/rwsem.h	2003-03-26 23:49:00.000000000 +0000
@@ -105,6 +105,27 @@
 }
 
 /*
+ * trylock for reading -- returns 1 if successful, 0 if contention
+ */
+static inline int __down_read_trylock(struct rw_semaphore *sem)
+{
+	signed long old, new;
+
+	__asm__ __volatile__(
+		"   l    %0,0(%2)\n"
+		"0: ltr  %1,%0\n"
+		"   jm   1f\n"
+		"   ahi  %1,%3\n"
+		"   cs   %0,%1,0(%2)\n"
+		"   jl   0b\n"
+		"1:"
+                : "=&d" (old), "=&d" (new)
+		: "a" (&sem->count), "i" (RWSEM_ACTIVE_READ_BIAS)
+		: "cc", "memory" );
+	return old >= 0 ? 1 : 0;
+}
+
+/*
  * lock for writing
  */
 static inline void __down_write(struct rw_semaphore *sem)
@@ -126,6 +147,26 @@
 }
 
 /*
+ * trylock for writing -- returns 1 if successful, 0 if contention
+ */
+static inline int __down_write_trylock(struct rw_semaphore *sem)
+{
+	signed long old;
+
+	__asm__ __volatile__(
+		"   l    %0,0(%1)\n"
+		"0: ltr  %0,%0\n"
+		"   jnz  1f\n"
+		"   cs   %0,%2,0(%1)\n"
+		"   jl   0b\n"
+		"1:"
+                : "=&d" (old)
+		: "a" (&sem->count), "d" (RWSEM_ACTIVE_WRITE_BIAS)
+		: "cc", "memory" );
+	return (old == RWSEM_UNLOCKED_VALUE) ? 1 : 0;
+}
+
+/*
  * unlock after reading
  */
 static inline void __up_read(struct rw_semaphore *sem)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-s390/setup.h linux-2.4.21-pre6/include/asm-s390/setup.h
--- linux-2.4.20/include/asm-s390/setup.h	2002-02-25 19:38:13.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-s390/setup.h	2003-03-26 23:49:54.000000000 +0000
@@ -30,6 +30,7 @@
 #define MACHINE_IS_P390  (machine_flags & 4)
 #define MACHINE_HAS_CSP  (machine_flags & 8)
 #define MACHINE_HAS_MVPG (machine_flags & 16)
+#define MACHINE_HAS_PFIX (machine_flags & 128)
 
 #define MACHINE_HAS_HWC  (!MACHINE_IS_P390)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-s390/system.h linux-2.4.21-pre6/include/asm-s390/system.h
--- linux-2.4.20/include/asm-s390/system.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-s390/system.h	2003-03-26 23:49:37.000000000 +0000
@@ -206,8 +206,12 @@
                 : "cc", "0", "1", "2"); \
         })
 
+#define __save_and_cli(x)	do { __save_flags(x); __cli(); } while(0);
+#define __save_and_sti(x)	do { __save_flags(x); __sti(); } while(0);
+
 /* For spinlocks etc */
 #define local_irq_save(x)	((x) = __cli())
+#define local_irq_set(x)	__save_and_sti(x)
 #define local_irq_restore(x)	__restore_flags(x)
 #define local_irq_disable()	__cli()
 #define local_irq_enable()	__sti()
@@ -223,6 +227,8 @@
 #define sti() __global_sti()
 #define save_flags(x) ((x)=__global_save_flags())
 #define restore_flags(x) __global_restore_flags(x)
+#define save_and_cli(x) do { save_flags(x); cli(); } while(0);
+#define save_and_sti(x) do { save_flags(x); sti(); } while(0);
 
 extern void smp_ctl_set_bit(int cr, int bit);
 extern void smp_ctl_clear_bit(int cr, int bit);
@@ -235,6 +241,8 @@
 #define sti() __sti()
 #define save_flags(x) __save_flags(x)
 #define restore_flags(x) __restore_flags(x)
+#define save_and_cli(x) __save_and_cli(x)
+#define save_and_sti(x) __save_and_sti(x)
 
 #define ctl_set_bit(cr, bit) __ctl_set_bit(cr, bit)
 #define ctl_clear_bit(cr, bit) __ctl_clear_bit(cr, bit)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-s390/types.h linux-2.4.21-pre6/include/asm-s390/types.h
--- linux-2.4.20/include/asm-s390/types.h	2001-04-12 02:02:28.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-s390/types.h	2003-03-26 23:49:39.000000000 +0000
@@ -54,6 +54,7 @@
 #define BITS_PER_LONG 32
 
 typedef u32 dma_addr_t;
+typedef u32 dma64_addr_t;
 
 typedef union {
 	unsigned long long pair;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-s390/unistd.h linux-2.4.21-pre6/include/asm-s390/unistd.h
--- linux-2.4.20/include/asm-s390/unistd.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-s390/unistd.h	2003-03-26 23:49:39.000000000 +0000
@@ -212,6 +212,7 @@
 #define __NR_madvise            219
 #define __NR_getdents64		220
 #define __NR_fcntl64		221
+#define __NR_readahead		222
 /*
  * Numbers 224-235 are reserved for posix acl
  */
@@ -229,31 +230,33 @@
         return (type) (res);                                 \
 } while (0)
 
-#define _svc_clobber "2", "cc", "memory"
+#define _svc_clobber "cc", "memory"
 
 #define _syscall0(type,name)                                 \
 type name(void) {                                            \
+        register long __svcres asm("2");                     \
         long __res;                                          \
         __asm__ __volatile__ (                               \
                 "    svc %b1\n"                              \
-                "    lr  %0,2"                               \
-                : "=d" (__res)                               \
+                : "=d" (__svcres)                            \
                 : "i" (__NR_##name)                          \
                 : _svc_clobber );                            \
+	__res = __svcres;                                    \
         __syscall_return(type,__res);                        \
 }
 
 #define _syscall1(type,name,type1,arg1)                      \
 type name(type1 arg1) {                                      \
         register type1 __arg1 asm("2") = arg1;               \
+        register long __svcres asm("2");                     \
         long __res;                                          \
         __asm__ __volatile__ (                               \
                 "    svc %b1\n"                              \
-                "    lr  %0,2"                               \
-                : "=d" (__res)                               \
+                : "=d" (__svcres)                            \
                 : "i" (__NR_##name),                         \
-                  "d" (__arg1)                               \
+                  "0" (__arg1)                               \
                 : _svc_clobber );                            \
+        __res = __svcres;                                    \
         __syscall_return(type,__res);                        \
 }
 
@@ -261,15 +264,16 @@
 type name(type1 arg1, type2 arg2) {                          \
         register type1 __arg1 asm("2") = arg1;               \
         register type2 __arg2 asm("3") = arg2;               \
+        register long __svcres asm("2");                     \
         long __res;                                          \
         __asm__ __volatile__ (                               \
                 "    svc %b1\n"                              \
-                "    lr  %0,2"                               \
-                : "=d" (__res)                               \
+                : "=d" (__svcres)                            \
                 : "i" (__NR_##name),                         \
-                  "d" (__arg1),                              \
+                  "0" (__arg1),                              \
                   "d" (__arg2)                               \
                 : _svc_clobber );                            \
+        __res = __svcres;                                    \
         __syscall_return(type,__res);                        \
 }
 
@@ -278,16 +282,17 @@
         register type1 __arg1 asm("2") = arg1;               \
         register type2 __arg2 asm("3") = arg2;               \
         register type3 __arg3 asm("4") = arg3;               \
+        register long __svcres asm("2");                     \
         long __res;                                          \
         __asm__ __volatile__ (                               \
                 "    svc %b1\n"                              \
-                "    lr  %0,2"                               \
-                : "=d" (__res)                               \
+                : "=d" (__svcres)                            \
                 : "i" (__NR_##name),                         \
-                  "d" (__arg1),                              \
+                  "0" (__arg1),                              \
                   "d" (__arg2),                              \
                   "d" (__arg3)                               \
                 : _svc_clobber );                            \
+        __res = __svcres;                                    \
         __syscall_return(type,__res);                        \
 }
 
@@ -298,17 +303,18 @@
         register type2 __arg2 asm("3") = arg2;               \
         register type3 __arg3 asm("4") = arg3;               \
         register type4 __arg4 asm("5") = arg4;               \
+        register long __svcres asm("2");                     \
         long __res;                                          \
         __asm__ __volatile__ (                               \
                 "    svc %b1\n"                              \
-                "    lr  %0,2"                               \
-                : "=d" (__res)                               \
+                : "=d" (__svcres)                            \
                 : "i" (__NR_##name),                         \
-                  "d" (__arg1),                              \
+                  "0" (__arg1),                              \
                   "d" (__arg2),                              \
                   "d" (__arg3),                              \
                   "d" (__arg4)                               \
                 : _svc_clobber );                            \
+        __res = __svcres;                                    \
         __syscall_return(type,__res);                        \
 }
 
@@ -321,18 +327,19 @@
         register type3 __arg3 asm("4") = arg3;               \
         register type4 __arg4 asm("5") = arg4;               \
         register type5 __arg5 asm("6") = arg5;               \
+        register long __svcres asm("2");                     \
         long __res;                                          \
         __asm__ __volatile__ (                               \
                 "    svc %b1\n"                              \
-                "    lr  %0,2"                               \
-                : "=d" (__res)                               \
+                : "=d" (__svcres)                            \
                 : "i" (__NR_##name),                         \
-                  "d" (__arg1),                              \
+                  "0" (__arg1),                              \
                   "d" (__arg2),                              \
                   "d" (__arg3),                              \
                   "d" (__arg4),                              \
                   "d" (__arg5)                               \
                 : _svc_clobber );                            \
+        __res = __svcres;                                    \
         __syscall_return(type,__res);                        \
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-s390x/ebcdic.h linux-2.4.21-pre6/include/asm-s390x/ebcdic.h
--- linux-2.4.20/include/asm-s390x/ebcdic.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-s390x/ebcdic.h	2003-03-26 23:49:30.000000000 +0000
@@ -32,7 +32,7 @@
 		"0: tr    0(256,%0),0(%2)\n"
 		"   la    %0,256(%0)\n"
 		"1: ahi   %1,-256\n"
-		"   jp    0b\n"
+		"   jnm   0b\n"
 		"   ex    %1,0(1)"
 		: "+&a" (addr), "+&a" (nr)
 		: "a" (codepage) : "cc", "memory", "1" );
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-s390x/idals.h linux-2.4.21-pre6/include/asm-s390x/idals.h
--- linux-2.4.20/include/asm-s390x/idals.h	2001-07-25 21:12:02.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-s390x/idals.h	2003-03-26 23:49:50.000000000 +0000
@@ -1,74 +1,258 @@
 /* 
-   * File...........: linux/include/asm-s390x/idals.h
-   * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
-   * Bugreports.to..: <Linux390@de.ibm.com>
-   * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000a
-   
-   * History of changes
-   * 07/24/00 new file
+ * File...........: linux/include/asm-s390x/idals.h
+ * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
+ *		    Martin Schwidefsky <schwidefsky@de.ibm.com>
+ * Bugreports.to..: <Linux390@de.ibm.com>
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000a
+ 
+ * History of changes
+ * 07/24/00 new file
+ * 05/04/02 code restructuring.
  */
+
+#ifndef _S390_IDALS_H
+#define _S390_IDALS_H
+
 #include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/slab.h>
 #include <asm/irq.h>
+#include <asm/uaccess.h>
 
+#ifdef CONFIG_ARCH_S390X
 #define IDA_SIZE_LOG 12 /* 11 for 2k , 12 for 4k */
+#else
+#define IDA_SIZE_LOG 11 /* 11 for 2k , 12 for 4k */
+#endif
 #define IDA_BLOCK_SIZE (1L<<IDA_SIZE_LOG)
 
-static inline addr_t *
-idal_alloc ( int nridaws )
+/*
+ * Test if an address/length pair needs an idal list.
+ */
+static inline int
+idal_is_needed(void *vaddr, unsigned int length)
 {
-	if ( nridaws > 33 )
-		BUG();
-	return kmalloc(nridaws * sizeof(addr_t), GFP_ATOMIC | GFP_DMA );
+#if defined(CONFIG_ARCH_S390X)
+	return ((__pa(vaddr) + length) >> 31) != 0;
+#else
+	return 0;
+#endif
 }
 
-static inline void 
-idal_free ( addr_t *idal )
+
+/*
+ * Return the number of idal words needed for an address/length pair.
+ */
+static inline unsigned int
+idal_nr_words(void *vaddr, unsigned int length)
 {
-	kfree (idal);
+#if defined(CONFIG_ARCH_S390X)
+	if (idal_is_needed(vaddr, length))
+		return ((__pa(vaddr) & (IDA_BLOCK_SIZE-1)) + length + 
+			(IDA_BLOCK_SIZE-1)) >> IDA_SIZE_LOG;
+#endif
+	return 0;
 }
 
+/*
+ * Create the list of idal words for an address/length pair.
+ */
+static inline unsigned long *
+idal_create_words(unsigned long *idaws, void *vaddr, unsigned int length)
+{
 #if defined(CONFIG_ARCH_S390X)
-extern unsigned long __create_idal(unsigned long address, int count);
+	unsigned long paddr;
+	unsigned int cidaw;
+
+	paddr = __pa(vaddr);
+	cidaw = ((paddr & (IDA_BLOCK_SIZE-1)) + length + 
+		 (IDA_BLOCK_SIZE-1)) >> IDA_SIZE_LOG;
+	*idaws++ = paddr;
+	paddr &= -IDA_BLOCK_SIZE;
+	while (--cidaw > 0) {
+		paddr += IDA_BLOCK_SIZE;
+		*idaws++ = paddr;
+	}
 #endif
+	return idaws;
+}
 
 /*
- * Function: set_normalized_cda
- * sets the address of the data in CCW
- * if necessary it allocates an IDAL and sets sthe appropriate flags
+ * Sets the address of the data in CCW.
+ * If necessary it allocates an IDAL and sets the appropriate flags.
  */
 static inline int
-set_normalized_cda(ccw1_t * ccw, unsigned long address)
+set_normalized_cda(ccw1_t * ccw, void *vaddr)
 {
-	int ret = 0;
-
 #if defined (CONFIG_ARCH_S390X)
-	if (((address + ccw->count) >> 31) != 0) {
-		if (ccw->flags & CCW_FLAG_IDA)
-			BUG();
-		address = __create_idal(address, ccw->count);
-		if (address)
-			ccw->flags |= CCW_FLAG_IDA;
-		else
-			ret = -ENOMEM;
+	unsigned int nridaws;
+	unsigned long *idal;
+
+	if (ccw->flags & CCW_FLAG_IDA)
+		return -EINVAL;
+	nridaws = idal_nr_words(vaddr, ccw->count);
+	if (nridaws > 0) {
+		idal = kmalloc(nridaws * sizeof(unsigned long),
+			       GFP_ATOMIC | GFP_DMA );
+		if (idal == NULL)
+			return -ENOMEM;
+		idal_create_words(idal, vaddr, ccw->count);
+		ccw->flags |= CCW_FLAG_IDA;
+		vaddr = idal;
 	}
 #endif
-	ccw->cda = (__u32) address;
-	return ret;
+	ccw->cda = (__u32)(unsigned long) vaddr;
+	return 0;
 }
 
 /*
- * Function: clear_normalized_cda
- * releases any allocated IDAL related to the CCW
+ * Releases any allocated IDAL related to the CCW.
  */
 static inline void
-clear_normalized_cda ( ccw1_t * ccw ) 
+clear_normalized_cda(ccw1_t * ccw)
 {
 #if defined(CONFIG_ARCH_S390X)
-	if ( ccw -> flags & CCW_FLAG_IDA ) {
-		idal_free ( (addr_t *)(unsigned long) (ccw -> cda ));
-		ccw -> flags &= ~CCW_FLAG_IDA;
+	if (ccw->flags & CCW_FLAG_IDA) {
+		kfree((void *)(unsigned long) ccw->cda);
+		ccw->flags &= ~CCW_FLAG_IDA;
 	}
 #endif
-	ccw -> cda = 0;
+	ccw->cda = 0;
 }
 
+/*
+ * Idal buffer extension
+ */
+struct idal_buffer {
+	size_t size;
+	size_t page_order;
+	void *data[0];
+};
+
+/*
+ * Allocate an idal buffer
+ */
+static inline struct idal_buffer *
+idal_buffer_alloc(size_t size, int page_order)
+{
+	struct idal_buffer *ib;
+	int nr_chunks, nr_ptrs, i;
+
+	nr_ptrs = (size + IDA_BLOCK_SIZE - 1) >> IDA_SIZE_LOG;
+	nr_chunks = (4096 << page_order) >> IDA_SIZE_LOG;
+	ib = kmalloc(sizeof(struct idal_buffer) + nr_ptrs*sizeof(void *),
+		     GFP_DMA | GFP_KERNEL);
+	if (ib == NULL)
+		return ERR_PTR(-ENOMEM);
+	ib->size = size;
+	ib->page_order = page_order;
+	for (i = 0; i < nr_ptrs; i++) {
+		if ((i & (nr_chunks - 1)) != 0) {
+			ib->data[i] = ib->data[i-1] + IDA_BLOCK_SIZE;
+			continue;
+		}
+		ib->data[i] = (void *)
+			__get_free_pages(GFP_KERNEL, page_order);
+		if (ib->data[i] != NULL)
+			continue;
+		// Not enough memory
+		while (i >= nr_chunks) {
+			i -= nr_chunks;
+			free_pages((unsigned long) ib->data[i],
+				   ib->page_order);
+		}
+		kfree(ib);
+		return ERR_PTR(-ENOMEM);
+	}
+	return ib;
+}
+
+/*
+ * Free an idal buffer.
+ */
+static inline void
+idal_buffer_free(struct idal_buffer *ib)
+{
+	int nr_chunks, nr_ptrs, i;
+
+	nr_ptrs = (ib->size + IDA_BLOCK_SIZE - 1) >> IDA_SIZE_LOG;
+	nr_chunks = (4096 << ib->page_order) >> IDA_SIZE_LOG;
+	for (i = 0; i < nr_ptrs; i += nr_chunks)
+		free_pages((unsigned long) ib->data[i], ib->page_order);
+	kfree(ib);
+}
+
+/*
+ * Test if a idal list is really needed.
+ */
+static inline int
+__idal_buffer_is_needed(struct idal_buffer *ib)
+{
+#ifdef CONFIG_ARCH_S390X
+	return ib->size > (4096 << ib->page_order) ||
+		idal_is_needed(ib->data[0], ib->size);
+#else
+	return ib->size > (4096 << ib->page_order);
+#endif
+}
+
+/*
+ * Set channel data address to idal buffer.
+ */
+static inline void
+idal_buffer_set_cda(struct idal_buffer *ib, ccw1_t *ccw)
+{
+	if (__idal_buffer_is_needed(ib)) {
+		// setup idals;
+		ccw->cda = (u32)(addr_t) ib->data;
+		ccw->flags |= CCW_FLAG_IDA;
+	} else
+		// we do not need idals - use direct addressing
+		ccw->cda = (u32)(addr_t) ib->data[0];
+	ccw->count = ib->size;
+}
+
+/*
+ * Copy count bytes from an idal buffer to user memory
+ */
+static inline size_t
+idal_buffer_to_user(struct idal_buffer *ib, void *to, size_t count)
+{
+	size_t left;
+	int i;
+
+	if (count > ib->size)
+		BUG();
+	for (i = 0; count > IDA_BLOCK_SIZE; i++) {
+		left = copy_to_user(to, ib->data[i], IDA_BLOCK_SIZE);
+		if (left)
+			return left + count - IDA_BLOCK_SIZE;
+		(addr_t) to += IDA_BLOCK_SIZE;
+		count -= IDA_BLOCK_SIZE;
+	}
+	return copy_to_user(to, ib->data[i], count);
+}
+
+/*
+ * Copy count bytes from user memory to an idal buffer
+ */
+static inline size_t
+idal_buffer_from_user(struct idal_buffer *ib, void *from, size_t count)
+{
+	size_t left;
+	int i;
+
+	if (count > ib->size)
+		BUG();
+	for (i = 0; count > IDA_BLOCK_SIZE; i++) {
+		left = copy_from_user(ib->data[i], from, IDA_BLOCK_SIZE);
+		if (left)
+			return left + count - IDA_BLOCK_SIZE;
+		(addr_t) from += IDA_BLOCK_SIZE;
+		count -= IDA_BLOCK_SIZE;
+	}
+	return copy_from_user(ib->data[i], from, count);
+}
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-s390x/ide.h linux-2.4.21-pre6/include/asm-s390x/ide.h
--- linux-2.4.20/include/asm-s390x/ide.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-s390x/ide.h	2003-03-26 23:48:58.000000000 +0000
@@ -15,45 +15,6 @@
 #define MAX_HWIFS	0
 #endif
 
-#define ide__sti()	do {} while (0)
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned bit0		: 1;
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned reserved456	: 3;
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-	} b;
-} control_t;
-
-#define ide_request_irq(irq,hand,flg,dev,id)	do {} while (0)
-#define ide_free_irq(irq,dev_id)		do {} while (0)
-#define ide_check_region(from,extent)		do {} while (0)
-#define ide_request_region(from,extent,name)	do {} while (0)
-#define ide_release_region(from,extent)		do {} while (0)
-
-/*
- * The following are not needed for the non-m68k ports
- */
-#define ide_ack_intr(hwif)		(1)
-#define ide_fix_driveid(id)		do {} while (0)
-#define ide_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
-
 /*
  * We always use the new IDE port registering,
  * so these are fixed here.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-s390x/io.h linux-2.4.21-pre6/include/asm-s390x/io.h
--- linux-2.4.20/include/asm-s390x/io.h	2001-07-25 21:12:02.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-s390x/io.h	2003-03-26 23:49:09.000000000 +0000
@@ -40,6 +40,11 @@
         return __io_virt(address);
 }
 
+/*
+ * Change "struct page" to physical address.
+ */
+#define page_to_phys(page)	((page - mem_map) << PAGE_SHIFT)
+
 extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
 
 extern inline void * ioremap (unsigned long offset, unsigned long size)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-s390x/page.h linux-2.4.21-pre6/include/asm-s390x/page.h
--- linux-2.4.20/include/asm-s390x/page.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-s390x/page.h	2003-03-26 23:48:58.000000000 +0000
@@ -9,6 +9,7 @@
 #ifndef _S390_PAGE_H
 #define _S390_PAGE_H
 
+#include <asm/errno.h>
 #include <asm/setup.h>
 
 /* PAGE_SHIFT determines the page size */
@@ -16,6 +17,9 @@
 #define PAGE_SIZE       (1UL << PAGE_SHIFT)
 #define PAGE_MASK       (~(PAGE_SIZE-1))
 
+#define STORAGE_ACC_KEY		6
+#define STORAGE_ACC_KEY_MASK	(STORAGE_ACC_KEY<<4)
+
 #ifdef __KERNEL__
 #ifndef __ASSEMBLY__
 
@@ -126,6 +130,59 @@
 #define virt_to_page(kaddr)	(mem_map + (__pa(kaddr) >> PAGE_SHIFT))
 #define VALID_PAGE(page)	((page - mem_map) < max_mapnr)
 
+/* the pfix table of all mem addresses */
+extern void* *pfix_table;
+#define pfix_get_page_addr(ptr) (pfix_table[(unsigned long)ptr>>PAGE_SHIFT])
+#define pfix_get_addr(ptr) (pfix_get_page_addr(ptr)+ \
+			    ((unsigned long)ptr&PAGE_MASK))
+
+/*
+ * These two functions allow to lock and unlock pages in VM. They need
+ * the absolute address of the page to be locked or unlocked. This will
+ * only work if the diag98 option in the user directory is enabled for
+ * the guest.
+ */
+
+/* if result is 0, addr will become the host absolute address */
+extern __inline__ int pfix_lock_page(void *addr)
+{
+        int ret = -ENOMEM;
+
+        if (!MACHINE_HAS_PFIX)
+                return -ENOSYS;
+
+        __asm__ __volatile__(
+                "   lg    0,%1\n"  /* parameter in gpr 0 */
+                "   lghi  2,0\n"   /* function code is 0 */
+                "   diag  2,0,0x98\n" /* result in gpr 1 */
+                "   jnz   0f\n"
+                "   lghi  %0,0\n"
+                "0: lg    %1,1\n"  /* gpr1 contains host absol. addr */
+                : "+d" (ret), "+d" ((unsigned long)addr) : 
+                : "0", "1", "2", "cc" );
+        return ret;
+}
+
+extern __inline__ int pfix_unlock_page(unsigned long addr)
+{
+        int ret = -EINVAL;
+
+        if (!MACHINE_HAS_PFIX)
+                return -ENOSYS;
+
+        __asm__ __volatile__(
+                "   lgr   0,%1\n"  /* parameter in gpr 0 */
+                "   lghi  2,4\n"   /* function code is 4 */
+                "   diag  2,0,0x98\n" /* result in gpr 1 */
+                "   jnz   0f\n"
+                "   lghi  %0,0\n"
+                "0:\n"
+                : "+d" (ret)
+                : "a" (addr)
+                : "0", "1", "2", "cc" );
+        return ret;
+}
+
 #define VM_DATA_DEFAULT_FLAGS	(VM_READ | VM_WRITE | VM_EXEC | \
 				 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-s390x/pci.h linux-2.4.21-pre6/include/asm-s390x/pci.h
--- linux-2.4.20/include/asm-s390x/pci.h	2001-07-25 21:12:02.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-s390x/pci.h	2003-03-26 23:48:59.000000000 +0000
@@ -5,5 +5,11 @@
  * includes it even if CONFIG_PCI is not set.
  */
 
+/* The PCI address space does equal the physical memory
+ * address space.  The networking and block device layers use
+ * this boolean for bounce buffer decisions.
+ */
+#define PCI_DMA_BUS_IS_PHYS     (1)
+
 #endif /* __ASM_S390_PCI_H */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-s390x/pgalloc.h linux-2.4.21-pre6/include/asm-s390x/pgalloc.h
--- linux-2.4.20/include/asm-s390x/pgalloc.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-s390x/pgalloc.h	2003-03-26 23:49:08.000000000 +0000
@@ -266,14 +266,15 @@
  */
 static inline void __flush_tlb_mm(struct mm_struct * mm)
 {
-	if ((smp_num_cpus > 1) &&
-	    ((atomic_read(&mm->mm_count) != 1) ||
-	     (mm->cpu_vm_mask != (1UL << smp_processor_id())))) {
-		mm->cpu_vm_mask = (1UL << smp_processor_id());
+	if (mm->cpu_vm_mask != (1UL << smp_processor_id())) {
+		/* mm was active on more than one cpu. */
+		if (mm == current->active_mm &&
+		    atomic_read(&mm->mm_users) == 1)
+			/* this cpu is the only one using the mm. */
+			mm->cpu_vm_mask = 1UL << smp_processor_id();
 		global_flush_tlb();
-	} else {                 
+	} else
 		local_flush_tlb();
-	}
 }
 
 static inline void flush_tlb(void)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-s390x/pgtable.h linux-2.4.21-pre6/include/asm-s390x/pgtable.h
--- linux-2.4.20/include/asm-s390x/pgtable.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-s390x/pgtable.h	2003-03-26 23:49:34.000000000 +0000
@@ -233,12 +233,22 @@
 		pte_val(pteval) &= ~_PAGE_MKCLEAN;
                
 		asm volatile ("sske %0,%1" 
-				: : "d" (0), "a" (pte_val(pteval)));
+				: : "d" (STORAGE_ACC_KEY_MASK),
+				"a" (pte_val(pteval)));
 	}
 
 	*pteptr = pteval;
 }
 
+extern inline void set_access_key(pte_t pteval)
+{
+	asm volatile ("    iske 0,%1\n"
+		      "    or   0,%0\n"
+		      "    sske 0,%1\n"
+			: : "d" (STORAGE_ACC_KEY_MASK),
+			"a" (pte_val(pteval)) : "0", "cc");
+}
+
 #define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT))
 
 /*
@@ -391,7 +401,7 @@
 
 extern inline pte_t pte_mkwrite(pte_t pte)
 {
-	pte_val(pte) &= ~_PAGE_RO;
+	pte_val(pte) &= ~(_PAGE_RO | _PAGE_ISCLEAN);
 	return pte;
 }
 
@@ -452,7 +462,7 @@
 	/* We can't clear the changed bit atomically. For now we
          * clear (!) the page referenced bit. */
 	asm volatile ("sske %0,%1" 
-	              : : "d" (0), "a" (*ptep));
+	              : : "d" (STORAGE_ACC_KEY_MASK), "a" (*ptep));
 	return 1;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-s390x/processor.h linux-2.4.21-pre6/include/asm-s390x/processor.h
--- linux-2.4.20/include/asm-s390x/processor.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-s390x/processor.h	2003-03-26 23:49:20.000000000 +0000
@@ -128,7 +128,7 @@
 
 /* Free all resources held by a thread. */
 extern void release_thread(struct task_struct *);
-extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
+extern int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
 /* Copy and release all segment info associated with a VM */
 #define copy_segments(nr, mm)           do { } while (0)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-s390x/rwsem.h linux-2.4.21-pre6/include/asm-s390x/rwsem.h
--- linux-2.4.20/include/asm-s390x/rwsem.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-s390x/rwsem.h	2003-03-26 23:49:16.000000000 +0000
@@ -105,6 +105,27 @@
 }
 
 /*
+ * trylock for reading -- returns 1 if successful, 0 if contention
+ */
+static inline int __down_read_trylock(struct rw_semaphore *sem)
+{
+	signed long old, new;
+
+	__asm__ __volatile__(
+		"   lg   %0,0(%2)\n"
+		"0: ltgr %1,%0\n"
+		"   jm   1f\n"
+		"   aghi %1,%3\n"
+		"   csg  %0,%1,0(%2)\n"
+		"   jl   0b\n"
+		"1:"
+                : "=&d" (old), "=&d" (new)
+		: "a" (&sem->count), "i" (RWSEM_ACTIVE_READ_BIAS)
+		: "cc", "memory" );
+	return old >= 0 ? 1 : 0;
+}
+
+/*
  * lock for writing
  */
 static inline void __down_write(struct rw_semaphore *sem)
@@ -126,6 +147,26 @@
 }
 
 /*
+ * trylock for writing -- returns 1 if successful, 0 if contention
+ */
+static inline int __down_write_trylock(struct rw_semaphore *sem)
+{
+	signed long old;
+
+	__asm__ __volatile__(
+		"   lg   %0,0(%1)\n"
+		"0: ltgr %0,%0\n"
+		"   jnz  1f\n"
+		"   csg  %0,%2,0(%1)\n"
+		"   jl   0b\n"
+		"1:"
+                : "=&d" (old)
+		: "a" (&sem->count), "d" (RWSEM_ACTIVE_WRITE_BIAS)
+		: "cc", "memory" );
+	return (old == RWSEM_UNLOCKED_VALUE) ? 1 : 0;
+}
+
+/*
  * unlock after reading
  */
 static inline void __up_read(struct rw_semaphore *sem)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-s390x/setup.h linux-2.4.21-pre6/include/asm-s390x/setup.h
--- linux-2.4.20/include/asm-s390x/setup.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-s390x/setup.h	2003-03-26 23:49:00.000000000 +0000
@@ -29,6 +29,7 @@
 #define MACHINE_IS_P390		(machine_flags & 4)
 #define MACHINE_HAS_MVPG	(machine_flags & 16)
 #define MACHINE_HAS_DIAG44	(machine_flags & 32)
+#define MACHINE_HAS_PFIX  	(machine_flags & 128)
 
 #define MACHINE_HAS_HWC		(!MACHINE_IS_P390)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-s390x/system.h linux-2.4.21-pre6/include/asm-s390x/system.h
--- linux-2.4.20/include/asm-s390x/system.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-s390x/system.h	2003-03-26 23:49:54.000000000 +0000
@@ -216,8 +216,13 @@
                 : "cc", "0", "1", "2"); \
         })
 
+
+#define __save_and_cli(x)       do { __save_flags(x); __cli(); } while(0);
+#define __save_and_sti(x)       do { __save_flags(x); __sti(); } while(0);
+
 /* For spinlocks etc */
 #define local_irq_save(x)	((x) = __cli())
+#define local_irq_set(x)	__save_and_sti(x)
 #define local_irq_restore(x)	__restore_flags(x)
 #define local_irq_disable()	__cli()
 #define local_irq_enable()	__sti()
@@ -233,6 +238,8 @@
 #define sti() __global_sti()
 #define save_flags(x) ((x)=__global_save_flags())
 #define restore_flags(x) __global_restore_flags(x)
+#define save_and_cli(x) do { save_flags(x); cli(); } while(0);
+#define save_and_sti(x) do { save_flags(x); sti(); } while(0);
 
 extern void smp_ctl_set_bit(int cr, int bit);
 extern void smp_ctl_clear_bit(int cr, int bit);
@@ -245,6 +252,8 @@
 #define sti() __sti()
 #define save_flags(x) __save_flags(x)
 #define restore_flags(x) __restore_flags(x)
+#define save_and_cli(x) __save_and_cli(x)
+#define save_and_sti(x) __save_and_sti(x)
 
 #define ctl_set_bit(cr, bit) __ctl_set_bit(cr, bit)
 #define ctl_clear_bit(cr, bit) __ctl_clear_bit(cr, bit)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-s390x/types.h linux-2.4.21-pre6/include/asm-s390x/types.h
--- linux-2.4.20/include/asm-s390x/types.h	2001-04-12 02:02:29.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-s390x/types.h	2003-03-26 23:49:30.000000000 +0000
@@ -56,6 +56,7 @@
 #define BITS_PER_LONG 64
 
 typedef u32 dma_addr_t;
+typedef u64 dma64_addr_t;
 
 #endif                                 /* __KERNEL__                       */
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-s390x/unistd.h linux-2.4.21-pre6/include/asm-s390x/unistd.h
--- linux-2.4.20/include/asm-s390x/unistd.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-s390x/unistd.h	2003-03-26 23:49:08.000000000 +0000
@@ -180,6 +180,7 @@
 #define __NR_pivot_root         217
 #define __NR_mincore            218
 #define __NR_madvise            219
+#define __NR_readahead		222
 /*
  * Numbers 224-235 are reserved for posix acl
  */
@@ -198,31 +199,33 @@
         return (type) (res);                                 \
 } while (0)
 
-#define _svc_clobber "2", "cc", "memory"
+#define _svc_clobber "cc", "memory"
 
 #define _syscall0(type,name)                                 \
 type name(void) {                                            \
+        register long __svcres asm("2");                     \
         long __res;                                          \
         __asm__ __volatile__ (                               \
                 "    svc %b1\n"                              \
-                "    lgr  %0,2"                              \
-                : "=d" (__res)                               \
+                : "=d" (__svcres)                            \
                 : "i" (__NR_##name)                          \
                 : _svc_clobber );                            \
+        __res = __svcres;                                    \
         __syscall_return(type,__res);                        \
 }
 
 #define _syscall1(type,name,type1,arg1)                      \
 type name(type1 arg1) {                                      \
         register type1 __arg1 asm("2") = arg1;               \
+        register long __svcres asm("2");                     \
         long __res;                                          \
         __asm__ __volatile__ (                               \
                 "    svc %b1\n"                              \
-                "    lgr  %0,2"                              \
-                : "=d" (__res)                               \
+                : "=d" (__svcres)                            \
                 : "i" (__NR_##name),                         \
-                  "d" (__arg1)                               \
+                  "0" (__arg1)                               \
                 : _svc_clobber );                            \
+        __res = __svcres;                                    \
         __syscall_return(type,__res);                        \
 }
 
@@ -230,15 +233,16 @@
 type name(type1 arg1, type2 arg2) {                          \
         register type1 __arg1 asm("2") = arg1;               \
         register type2 __arg2 asm("3") = arg2;               \
+        register long __svcres asm("2");                     \
         long __res;                                          \
         __asm__ __volatile__ (                               \
                 "    svc %b1\n"                              \
-                "    lgr  %0,2"                              \
-                : "=d" (__res)                               \
+                : "=d" (__svcres)                            \
                 : "i" (__NR_##name),                         \
-                  "d" (__arg1),                              \
+                  "0" (__arg1),                              \
                   "d" (__arg2)                               \
                 : _svc_clobber );                            \
+        __res = __svcres;                                    \
         __syscall_return(type,__res);                        \
 }
 
@@ -247,16 +251,17 @@
         register type1 __arg1 asm("2") = arg1;               \
         register type2 __arg2 asm("3") = arg2;               \
         register type3 __arg3 asm("4") = arg3;               \
+        register long __svcres asm("2");                     \
         long __res;                                          \
         __asm__ __volatile__ (                               \
                 "    svc %b1\n"                              \
-                "    lgr  %0,2"                              \
-                : "=d" (__res)                               \
+                : "=d" (__svcres)                            \
                 : "i" (__NR_##name),                         \
-                  "d" (__arg1),                              \
+                  "0" (__arg1),                              \
                   "d" (__arg2),                              \
                   "d" (__arg3)                               \
                 : _svc_clobber );                            \
+        __res = __svcres;                                    \
         __syscall_return(type,__res);                        \
 }
 
@@ -267,17 +272,18 @@
         register type2 __arg2 asm("3") = arg2;               \
         register type3 __arg3 asm("4") = arg3;               \
         register type4 __arg4 asm("5") = arg4;               \
+        register long __svcres asm("2");                     \
         long __res;                                          \
         __asm__ __volatile__ (                               \
                 "    svc %b1\n"                              \
-                "    lgr  %0,2"                              \
-                : "=d" (__res)                               \
+                : "=d" (__svcres)                            \
                 : "i" (__NR_##name),                         \
-                  "d" (__arg1),                              \
+                  "0" (__arg1),                              \
                   "d" (__arg2),                              \
                   "d" (__arg3),                              \
                   "d" (__arg4)                               \
                 : _svc_clobber );                            \
+        __res = __svcres;                                    \
         __syscall_return(type,__res);                        \
 }
 
@@ -290,18 +296,19 @@
         register type3 __arg3 asm("4") = arg3;               \
         register type4 __arg4 asm("5") = arg4;               \
         register type5 __arg5 asm("6") = arg5;               \
+        register long __svcres asm("2");                     \
         long __res;                                          \
         __asm__ __volatile__ (                               \
                 "    svc %b1\n"                              \
-                "    lgr  %0,2"                              \
-                : "=d" (__res)                               \
+                : "=d" (__svcres)                            \
                 : "i" (__NR_##name),                         \
-                  "d" (__arg1),                              \
+                  "0" (__arg1),                              \
                   "d" (__arg2),                              \
                   "d" (__arg3),                              \
                   "d" (__arg4),                              \
                   "d" (__arg5)                               \
                 : _svc_clobber );                            \
+        __res = __svcres;                                    \
         __syscall_return(type,__res);                        \
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-sh/hdreg.h linux-2.4.21-pre6/include/asm-sh/hdreg.h
--- linux-2.4.20/include/asm-sh/hdreg.h	2000-03-05 17:33:55.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-sh/hdreg.h	2003-03-26 23:49:20.000000000 +0000
@@ -7,6 +7,7 @@
 #ifndef __ASM_SH_HDREG_H
 #define __ASM_SH_HDREG_H
 
-typedef unsigned int ide_ioreg_t;
+//typedef unsigned int ide_ioreg_t;
+typedef unsigned long ide_ioreg_t;
 
 #endif /* __ASM_SH_HDREG_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-sh/ide.h linux-2.4.21-pre6/include/asm-sh/ide.h
--- linux-2.4.20/include/asm-sh/ide.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-sh/ide.h	2003-03-26 23:49:19.000000000 +0000
@@ -22,8 +22,6 @@
 #define MAX_HWIFS	2
 #endif
 
-#define ide__sti()	__sti()
-
 static __inline__ int ide_default_irq_hp600(ide_ioreg_t base)
 {
 	switch (base) {
@@ -107,42 +105,7 @@
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned bit0		: 1;
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned reserved456	: 3;
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-	} b;
-} control_t;
-
-#define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
-#define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
-#define ide_check_region(from,extent)		check_region((from), (extent))
-#define ide_request_region(from,extent,name)	request_region((from), (extent), (name))
-#define ide_release_region(from,extent)		release_region((from), (extent))
-
-/*
- * The following are not needed for the non-m68k ports
- */
-#define ide_ack_intr(hwif)		(1)
-#define ide_fix_driveid(id)		do {} while (0)
-#define ide_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
+#include <asm-generic/ide_iops.h>
 
 #endif /* __KERNEL__ */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-sh/processor.h linux-2.4.21-pre6/include/asm-sh/processor.h
--- linux-2.4.20/include/asm-sh/processor.h	2001-10-05 19:11:05.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-sh/processor.h	2003-03-26 23:49:25.000000000 +0000
@@ -137,7 +137,7 @@
 /*
  * create a kernel thread without removing it from tasklists
  */
-extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
+extern int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
 /*
  * Bus types
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-sh/system.h linux-2.4.21-pre6/include/asm-sh/system.h
--- linux-2.4.20/include/asm-sh/system.h	2001-09-08 19:29:09.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-sh/system.h	2003-03-26 23:49:54.000000000 +0000
@@ -215,8 +215,11 @@
 		: "=&r" (__dummy));			\
 } while (0)
 
+#define __save_and_sti(x)       do { __save_flags(x); __sti(); } while(0);
+
 /* For spinlocks etc */
 #define local_irq_save(x)	x = __save_and_cli()
+#define local_irq_set(x)	__save_and_sti(x)
 #define local_irq_restore(x)	__restore_flags(x)
 #define local_irq_disable()	__cli()
 #define local_irq_enable()	__sti()
@@ -231,13 +234,14 @@
 #define sti() __global_sti()
 #define save_flags(x) ((x)=__global_save_flags())
 #define restore_flags(x) __global_restore_flags(x)
-
+#define save_and_sti(x) do { save_flags(x); sti(); } while(0);
 #else
 
 #define cli() __cli()
 #define sti() __sti()
 #define save_flags(x) __save_flags(x)
 #define save_and_cli(x) x = __save_and_cli()
+#define save_and_sti(x) __save_and_sti(x)
 #define restore_flags(x) __restore_flags(x)
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-sparc/delay.h linux-2.4.21-pre6/include/asm-sparc/delay.h
--- linux-2.4.20/include/asm-sparc/delay.h	2001-01-01 18:37:41.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-sparc/delay.h	2003-03-26 23:49:20.000000000 +0000
@@ -21,5 +21,6 @@
 
 /* This is too messy with inline asm on the Sparc. */
 extern void udelay(unsigned long usecs);
+extern void ndelay(unsigned long usecs);
 
 #endif /* defined(__SPARC_DELAY_H) */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-sparc/highmem.h linux-2.4.21-pre6/include/asm-sparc/highmem.h
--- linux-2.4.20/include/asm-sparc/highmem.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-sparc/highmem.h	2003-03-26 23:49:55.000000000 +0000
@@ -27,7 +27,7 @@
 #define HIGHMEM_DEBUG 1
 
 /* in mm/highmem.c */
-extern void *kmap_high(struct page *page);
+extern void *kmap_high(struct page *page, int nonblocking);
 extern void kunmap_high(struct page *page);
 
 /* declarations for highmem.c */
@@ -60,13 +60,16 @@
 void *kmap_atomic(struct page *page, enum km_type type);
 void kunmap_atomic(void *kvaddr, enum km_type type);
 
-static inline void *kmap(struct page *page)
+#define kmap(page) __kmap(page, 0)
+#define kmap_nonblock(page) __kmap(page, 1)
+
+static inline void *__kmap(struct page *page, int nonblocking)
 {
 	if (in_interrupt())
 		BUG();
 	if (page < highmem_start_page)
 		return page_address(page);
-	return kmap_high(page);
+	return kmap_high(page, nonblocking);
 }
 
 static inline void kunmap(struct page *page)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-sparc/ide.h linux-2.4.21-pre6/include/asm-sparc/ide.h
--- linux-2.4.20/include/asm-sparc/ide.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-sparc/ide.h	2003-03-26 23:49:39.000000000 +0000
@@ -20,8 +20,6 @@
 #undef  MAX_HWIFS
 #define MAX_HWIFS	2
 
-#define	ide__sti()	__sti()
-
 static __inline__ int ide_default_irq(ide_ioreg_t base)
 {
 	return 0;
@@ -73,56 +71,6 @@
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
-typedef union {
-	unsigned int		all	: 8;	/* all of the bits together */
-	struct {
-		unsigned int	bit7	: 1;
-		unsigned int	lba	: 1;
-		unsigned int	bit5	: 1;
-		unsigned int	unit	: 1;
-		unsigned int	head	: 4;
-	} b;
-} select_t;
-
-typedef union {
-	unsigned int all		: 8;	/* all of the bits together */
-	struct {
-		unsigned int HOB	: 1;	/* 48-bit address ordering */
-		unsigned int reserved456: 3;
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned int SRST	: 1;	/* host soft reset bit */
-		unsigned int nIEN	: 1;	/* device INTRQ to host */
-		unsigned int bit0	: 1;
-	} b;
-} control_t;
-
-static __inline__ int ide_request_irq(unsigned int irq,
-				      void (*handler)(int, void *, struct pt_regs *),
-				      unsigned long flags, const char *name, void *devid)
-{
-	return request_irq(irq, handler, SA_SHIRQ, name, devid);
-}
-
-static __inline__ void ide_free_irq(unsigned int irq, void *dev_id)
-{
-	free_irq(irq, dev_id);
-}
-
-static __inline__ int ide_check_region(ide_ioreg_t base, unsigned int size)
-{
-	/* We leave these empty because pcic.c calls sparc_alloc_io() */
-	return 0;
-}
-
-static __inline__ void ide_request_region(ide_ioreg_t base, unsigned int size,
-					  const char *name)
-{
-}
-
-static __inline__ void ide_release_region(ide_ioreg_t base, unsigned int size)
-{
-}
-
 #undef  SUPPORT_SLOW_DATA_PORTS
 #define SUPPORT_SLOW_DATA_PORTS 0
 
@@ -215,103 +163,6 @@
 	/* __flush_dcache_range((unsigned long)src, end); */ /* P3 see hme */
 }
 
-static __inline__ void ide_fix_driveid(struct hd_driveid *id)
-{
-	int i;
-	u16 *stringcast;
-
-	id->config         = __le16_to_cpu(id->config);
-	id->cyls           = __le16_to_cpu(id->cyls);
-	id->reserved2      = __le16_to_cpu(id->reserved2);
-	id->heads          = __le16_to_cpu(id->heads);
-	id->track_bytes    = __le16_to_cpu(id->track_bytes);
-	id->sector_bytes   = __le16_to_cpu(id->sector_bytes);
-	id->sectors        = __le16_to_cpu(id->sectors);
-	id->vendor0        = __le16_to_cpu(id->vendor0);
-	id->vendor1        = __le16_to_cpu(id->vendor1);
-	id->vendor2        = __le16_to_cpu(id->vendor2);
-	stringcast = (u16 *)&id->serial_no[0];
-	for (i = 0; i < (20/2); i++)
-	        stringcast[i] = __le16_to_cpu(stringcast[i]);
-	id->buf_type       = __le16_to_cpu(id->buf_type);
-	id->buf_size       = __le16_to_cpu(id->buf_size);
-	id->ecc_bytes      = __le16_to_cpu(id->ecc_bytes);
-	stringcast = (u16 *)&id->fw_rev[0];
-	for (i = 0; i < (8/2); i++)
-	        stringcast[i] = __le16_to_cpu(stringcast[i]);
-	stringcast = (u16 *)&id->model[0];
-	for (i = 0; i < (40/2); i++)
-	        stringcast[i] = __le16_to_cpu(stringcast[i]);
-	id->dword_io       = __le16_to_cpu(id->dword_io);
-	id->reserved50     = __le16_to_cpu(id->reserved50);
-	id->field_valid    = __le16_to_cpu(id->field_valid);
-	id->cur_cyls       = __le16_to_cpu(id->cur_cyls);
-	id->cur_heads      = __le16_to_cpu(id->cur_heads);
-	id->cur_sectors    = __le16_to_cpu(id->cur_sectors);
-	id->cur_capacity0  = __le16_to_cpu(id->cur_capacity0);
-	id->cur_capacity1  = __le16_to_cpu(id->cur_capacity1);
-	id->lba_capacity   = __le32_to_cpu(id->lba_capacity);
-	id->dma_1word      = __le16_to_cpu(id->dma_1word);
-	id->dma_mword      = __le16_to_cpu(id->dma_mword);
-	id->eide_pio_modes = __le16_to_cpu(id->eide_pio_modes);
-	id->eide_dma_min   = __le16_to_cpu(id->eide_dma_min);
-	id->eide_dma_time  = __le16_to_cpu(id->eide_dma_time);
-	id->eide_pio       = __le16_to_cpu(id->eide_pio);
-	id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy);
-	for (i = 0; i < 2; i++)
-		id->words69_70[i] = __le16_to_cpu(id->words69_70[i]);
-        for (i = 0; i < 4; i++)
-                id->words71_74[i] = __le16_to_cpu(id->words71_74[i]);
-	id->queue_depth	   = __le16_to_cpu(id->queue_depth);
-	for (i = 0; i < 4; i++)
-		id->words76_79[i] = __le16_to_cpu(id->words76_79[i]);
-	id->major_rev_num  = __le16_to_cpu(id->major_rev_num);
-	id->minor_rev_num  = __le16_to_cpu(id->minor_rev_num);
-	id->command_set_1  = __le16_to_cpu(id->command_set_1);
-	id->command_set_2  = __le16_to_cpu(id->command_set_2);
-	id->cfsse          = __le16_to_cpu(id->cfsse);
-	id->cfs_enable_1   = __le16_to_cpu(id->cfs_enable_1);
-	id->cfs_enable_2   = __le16_to_cpu(id->cfs_enable_2);
-	id->csf_default    = __le16_to_cpu(id->csf_default);
-	id->dma_ultra      = __le16_to_cpu(id->dma_ultra);
-	id->word89         = __le16_to_cpu(id->word89);
-	id->word90         = __le16_to_cpu(id->word90);
-	id->CurAPMvalues   = __le16_to_cpu(id->CurAPMvalues);
-	id->word92         = __le16_to_cpu(id->word92);
-	id->hw_config      = __le16_to_cpu(id->hw_config);
-	id->acoustic       = __le16_to_cpu(id->acoustic);
-	for (i = 0; i < 5; i++)
-		id->words95_99[i]  = __le16_to_cpu(id->words95_99[i]);
-	id->lba_capacity_2 = __le64_to_cpu(id->lba_capacity_2);
-	for (i = 0; i < 22; i++)
-		id->words104_125[i]   = __le16_to_cpu(id->words104_125[i]);
-	id->last_lun       = __le16_to_cpu(id->last_lun);
-	id->word127        = __le16_to_cpu(id->word127);
-	id->dlf            = __le16_to_cpu(id->dlf);
-	id->csfo           = __le16_to_cpu(id->csfo);
-	for (i = 0; i < 26; i++)
-		id->words130_155[i] = __le16_to_cpu(id->words130_155[i]);
-	id->word156        = __le16_to_cpu(id->word156);
-	for (i = 0; i < 3; i++)
-		id->words157_159[i] = __le16_to_cpu(id->words157_159[i]);
-	id->cfa_power      = __le16_to_cpu(id->cfa_power);
-	for (i = 0; i < 14; i++)
-		id->words161_175[i] = __le16_to_cpu(id->words161_175[i]);
-	for (i = 0; i < 31; i++)
-		id->words176_205[i] = __le16_to_cpu(id->words176_205[i]);
-	for (i = 0; i < 48; i++)
-		id->words206_254[i] = __le16_to_cpu(id->words206_254[i]);
-	id->integrity_word  = __le16_to_cpu(id->integrity_word);
-}
-
-/*
- * The following are not needed for the non-m68k ports
- */
-#define ide_ack_intr(hwif)		(1)
-/* #define ide_ack_intr(hwif)	((hwif)->hw.ack_intr ? (hwif)->hw.ack_intr(hwif) : 1) */
-#define ide_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
-
 #endif /* __KERNEL__ */
 
 #endif /* _SPARC_IDE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-sparc/ioctl.h linux-2.4.21-pre6/include/asm-sparc/ioctl.h
--- linux-2.4.20/include/asm-sparc/ioctl.h	1999-12-21 06:05:52.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-sparc/ioctl.h	2003-03-26 23:49:18.000000000 +0000
@@ -2,23 +2,35 @@
 #ifndef _SPARC_IOCTL_H
 #define _SPARC_IOCTL_H
 
+/*
+ * Our DIR and SIZE overlap in order to simulteneously provide
+ * a non-zero _IOC_NONE (for binary compatibility) and
+ * 14 bits of size as on i386. Here's the layout:
+ *
+ *   0xE0000000   DIR
+ *   0x80000000     DIR = WRITE
+ *   0x40000000     DIR = READ
+ *   0x20000000     DIR = NONE
+ *   0x3FFF0000   SIZE (overlaps NONE bit)
+ *   0x0000FF00   TYPE
+ *   0x000000FF   NR (CMD)
+ */
+
 #define _IOC_NRBITS      8
 #define _IOC_TYPEBITS    8
-#define _IOC_SIZEBITS    8
-#define _IOC_RESVBITS    5
+#define _IOC_SIZEBITS   13	/* Actually 14, see below. */
 #define _IOC_DIRBITS     3
 
 #define _IOC_NRMASK      ((1 << _IOC_NRBITS)-1)
 #define _IOC_TYPEMASK    ((1 << _IOC_TYPEBITS)-1)
-#define _IOC_RESVMASK    ((1 << _IOC_RESVBITS)-1)
 #define _IOC_SIZEMASK    ((1 << _IOC_SIZEBITS)-1)
+#define _IOC_XSIZEMASK   ((1 << (_IOC_SIZEBITS+1))-1)
 #define _IOC_DIRMASK     ((1 << _IOC_DIRBITS)-1)
 
 #define _IOC_NRSHIFT     0
 #define _IOC_TYPESHIFT   (_IOC_NRSHIFT + _IOC_NRBITS)
 #define _IOC_SIZESHIFT   (_IOC_TYPESHIFT + _IOC_TYPEBITS)
-#define _IOC_RESVSHIFT   (_IOC_SIZESHIFT + _IOC_SIZEBITS)
-#define _IOC_DIRSHIFT    (_IOC_RESVSHIFT + _IOC_RESVBITS)
+#define _IOC_DIRSHIFT    (_IOC_SIZESHIFT + _IOC_SIZEBITS)
 
 #define _IOC_NONE        1U
 #define _IOC_READ        2U
@@ -35,17 +47,20 @@
 #define _IOW(type,nr,size)  _IOC(_IOC_WRITE,(type),(nr),sizeof(size))
 #define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size))
 
-#define _IOC_DIR(nr)        (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)
+/* Used to decode ioctl numbers in drivers despite the leading underscore... */
+#define _IOC_DIR(nr)    \
+ ( (((((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK) & (_IOC_WRITE|_IOC_READ)) != 0)?   \
+                            (((nr) >> _IOC_DIRSHIFT) & (_IOC_WRITE|_IOC_READ)):  \
+                            (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK) )
 #define _IOC_TYPE(nr)       (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)
 #define _IOC_NR(nr)         (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)
-#define _IOC_SIZE(nr)       (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)
-
-/* ...and for the PCMCIA... */
+#define _IOC_SIZE(nr)       (((nr) >> _IOC_SIZESHIFT) & _IOC_XSIZEMASK)
 
+/* ...and for the PCMCIA and sound. */
 #define IOC_IN          (_IOC_WRITE << _IOC_DIRSHIFT)
 #define IOC_OUT         (_IOC_READ << _IOC_DIRSHIFT)
 #define IOC_INOUT       ((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT)
-#define IOCSIZE_MASK    (_IOC_SIZEMASK << _IOC_SIZESHIFT)
+#define IOCSIZE_MASK    (_IOC_XSIZEMASK << _IOC_SIZESHIFT)
 #define IOCSIZE_SHIFT   (_IOC_SIZESHIFT)
 
 #endif /* !(_SPARC_IOCTL_H) */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-sparc/irq.h linux-2.4.21-pre6/include/asm-sparc/irq.h
--- linux-2.4.20/include/asm-sparc/irq.h	2000-08-29 04:20:03.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-sparc/irq.h	2003-03-26 23:48:57.000000000 +0000
@@ -19,7 +19,7 @@
 BTFIXUPDEF_CALL(char *, __irq_itoa, unsigned int)
 #define __irq_itoa(irq) BTFIXUP_CALL(__irq_itoa)(irq)
 
-#define NR_IRQS    15
+#define NR_IRQS    16
 
 /* Dave Redman (djhr@tadpole.co.uk)
  * changed these to function pointers.. it saves cycles and will allow
@@ -45,7 +45,7 @@
 #define clear_profile_irq(cpu) BTFIXUP_CALL(clear_profile_irq)(cpu)
 #define load_profile_irq(cpu,limit) BTFIXUP_CALL(load_profile_irq)(cpu,limit)
 
-extern void (*init_timers)(void (*lvl10_irq)(int, void *, struct pt_regs *));
+extern void (*sparc_init_timers)(void (*lvl10_irq)(int, void *, struct pt_regs *));
 extern void claim_ticker14(void (*irq_handler)(int, void *, struct pt_regs *),
 			   int irq,
 			   unsigned int timeout);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-sparc/mman.h linux-2.4.21-pre6/include/asm-sparc/mman.h
--- linux-2.4.20/include/asm-sparc/mman.h	2000-03-15 08:37:50.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-sparc/mman.h	2003-03-26 23:49:55.000000000 +0000
@@ -20,7 +20,7 @@
 #define MAP_LOCKED      0x100           /* lock the mapping */
 #define _MAP_NEW        0x80000000      /* Binary compatibility is fun... */
 
-#define MAP_GROWSDOWN	0x0100		/* stack-like segment */
+#define MAP_GROWSDOWN	0x0200		/* stack-like segment */
 #define MAP_DENYWRITE	0x0800		/* ETXTBSY */
 #define MAP_EXECUTABLE	0x1000		/* mark it as an executable */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-sparc/oplib.h linux-2.4.21-pre6/include/asm-sparc/oplib.h
--- linux-2.4.20/include/asm-sparc/oplib.h	2002-02-25 19:38:13.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-sparc/oplib.h	2003-03-26 23:49:55.000000000 +0000
@@ -153,8 +153,9 @@
 /* Blocking put character to console. */
 extern void prom_putchar(char character);
 
-/* Prom's internal printf routine, don't use in kernel/boot code. */
-void prom_printf(char *fmt, ...);
+/* Prom's internal routines, don't use in kernel/boot code. */
+extern void prom_printf(char *fmt, ...);
+extern void prom_write(const char *buf, unsigned int len);
 
 /* Query for input device type */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-sparc/processor.h linux-2.4.21-pre6/include/asm-sparc/processor.h
--- linux-2.4.20/include/asm-sparc/processor.h	2001-10-11 06:42:47.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-sparc/processor.h	2003-03-26 23:49:37.000000000 +0000
@@ -146,7 +146,7 @@
 
 /* Free all resources held by a thread. */
 #define release_thread(tsk)		do { } while(0)
-extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
+extern pid_t arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
 
 #define copy_segments(tsk, mm)		do { } while (0)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-sparc/sbus.h linux-2.4.21-pre6/include/asm-sparc/sbus.h
--- linux-2.4.20/include/asm-sparc/sbus.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-sparc/sbus.h	2003-03-26 23:49:09.000000000 +0000
@@ -121,4 +121,15 @@
 extern void sbus_dma_sync_single(struct sbus_dev *, dma_addr_t, size_t, int);
 extern void sbus_dma_sync_sg(struct sbus_dev *, struct scatterlist *, int, int);
 
+/* Eric Brower (ebrower@usa.net)
+ * Translate SBus interrupt levels to ino values--
+ * this is used when converting sbus "interrupts" OBP 
+ * node values to "intr" node values, and is platform 
+ * dependent.  If only we could call OBP with 
+ * "sbus-intr>cpu (sbint -- ino)" from kernel...
+ * See .../drivers/sbus/sbus.c for details.
+ */
+BTFIXUPDEF_CALL(unsigned int, sbint_to_irq, struct sbus_dev *sdev, unsigned int)
+#define sbint_to_irq(sdev, sbint) BTFIXUP_CALL(sbint_to_irq)(sdev, sbint)
+
 #endif /* !(_SPARC_SBUS_H) */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-sparc/system.h linux-2.4.21-pre6/include/asm-sparc/system.h
--- linux-2.4.20/include/asm-sparc/system.h	2001-10-30 23:08:11.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-sparc/system.h	2003-03-26 23:49:50.000000000 +0000
@@ -132,6 +132,7 @@
 	"wr	%%g4, 0x20, %%psr\n\t"							\
 	"nop\n\t"									\
 	"nop\n\t"									\
+	"nop\n\t"	/* LEON needs this: load to %sp depends on CWP. */		\
 	"ldd	[%%g6 + %4], %%sp\n\t"							\
 	"wr	%%g5, 0x0, %%wim\n\t"							\
 	"ldd	[%%sp + 0x00], %%l0\n\t"						\
@@ -146,7 +147,7 @@
 	  "i" ((const unsigned long)(&((struct task_struct *)0)->thread.kpsr)),		\
 	  "i" ((const unsigned long)(&((struct task_struct *)0)->thread.ksp)),		\
 	  "r" (task_pc)									\
-	: "g1", "g2", "g3", "g4", "g5", "g7", "l0", "l1",				\
+	: "g1", "g2", "g3", "g4", "g5", "g7", "l0", "l1", "l3",				\
 	"l4", "l5", "l6", "l7", "i0", "i1", "i2", "i3", "i4", "i5", "o0", "o1", "o2",	\
 	"o3");										\
 here:;  } while(0)
@@ -241,12 +242,31 @@
 	return retval;
 }
 
+extern __inline__ unsigned long read_psr_and_sti(void)
+{
+	unsigned long retval;
+
+	__asm__ __volatile__(
+		"rd	%%psr, %0\n\t"
+		"nop; nop; nop;\n\t"	/* Sun4m + Cypress + SMP bug */
+		"andn	%0, %1, %%g1\n\t"
+		"wr	%%g1, 0x0, %%psr\n\t"
+		"nop; nop; nop\n\t"
+		: "=r" (retval)
+		: "i" (PSR_PIL)
+		: "g1", "memory");
+
+	return retval;
+}
+
 #define __save_flags(flags)	((flags) = getipl())
 #define __save_and_cli(flags)	((flags) = read_psr_and_cli())
+#define __save_and_sti(flags)	((flags) = read_psr_and_sti())
 #define __restore_flags(flags)	setipl((flags))
 #define local_irq_disable()		__cli()
 #define local_irq_enable()		__sti()
 #define local_irq_save(flags)		__save_and_cli(flags)
+#define local_irq_set(flags)		__save_and_sti(flags)
 #define local_irq_restore(flags)	__restore_flags(flags)
 
 #ifdef CONFIG_SMP
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-sparc/unistd.h linux-2.4.21-pre6/include/asm-sparc/unistd.h
--- linux-2.4.20/include/asm-sparc/unistd.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-sparc/unistd.h	2003-03-26 23:49:02.000000000 +0000
@@ -184,24 +184,24 @@
 /* #define __NR_exportfs        166    SunOS Specific                              */
 #define __NR_mount              167 /* Common                                      */
 #define __NR_ustat              168 /* Common                                      */
-/* #define __NR_semsys          169    SunOS Specific                              */
-/* #define __NR_msgsys          170    SunOS Specific                              */
-/* #define __NR_shmsys          171    SunOS Specific                              */
-/* #define __NR_auditsys        172    SunOS Specific                              */
-/* #define __NR_rfssys          173    SunOS Specific                              */
+#define __NR_setxattr           169 /* SunOS: semsys                               */
+#define __NR_lsetxattr          170 /* SunOS: msgsys                               */
+#define __NR_fsetxattr          171 /* SunOS: shmsys                               */
+#define __NR_getxattr           172 /* SunOS: auditsys                             */
+#define __NR_lgetxattr          173 /* SunOS: rfssys                               */
 #define __NR_getdents           174 /* Common                                      */
 #define __NR_setsid             175 /* Common                                      */
 #define __NR_fchdir             176 /* Common                                      */
-/* #define __NR_fchroot         177    SunOS Specific                              */
-/* #define __NR_vpixsys         178    SunOS Specific                              */
-/* #define __NR_aioread         179    SunOS Specific                              */
-/* #define __NR_aiowrite        180    SunOS Specific                              */
-/* #define __NR_aiowait         181    SunOS Specific                              */
-/* #define __NR_aiocancel       182    SunOS Specific                              */
+#define __NR_fgetxattr          177 /* SunOS: fchroot                              */
+#define __NR_listxattr          178 /* SunOS: vpixsys                              */
+#define __NR_llistxattr         179 /* SunOS: aioread                              */
+#define __NR_flistxattr         180 /* SunOS: aiowrite                             */
+#define __NR_removexattr        181 /* SunOS: aiowait                              */
+#define __NR_lremovexattr       182 /* SunOS: aiocancel                            */
 #define __NR_sigpending         183 /* Common                                      */
 #define __NR_query_module	184 /* Linux Specific				   */
 #define __NR_setpgid            185 /* Common                                      */
-/* #define __NR_pathconf        186    SunOS Specific                              */
+#define __NR_fremovexattr       186 /* SunOS: pathconf                             */
 #define __NR_tkill              187 /* SunOS: fpathconf                            */
 /* #define __NR_sysconf         188    SunOS Specific                              */
 #define __NR_uname              189 /* Linux Specific                              */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-sparc/vac-ops.h linux-2.4.21-pre6/include/asm-sparc/vac-ops.h
--- linux-2.4.20/include/asm-sparc/vac-ops.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-sparc/vac-ops.h	2003-03-26 23:49:20.000000000 +0000
@@ -98,8 +98,8 @@
 	unsigned int num_bytes;     /* Size of the cache */
 	unsigned int num_lines;     /* Number of cache lines */
 	unsigned int do_hwflushes;  /* Hardware flushing available? */
-	enum { NONE, WRITE_THROUGH,
-	    WRITE_BACK } type;      /* What type of VAC? */
+	enum { VAC_NONE, VAC_WRITE_THROUGH,
+	    VAC_WRITE_BACK } type;  /* What type of VAC? */
 	unsigned int linesize;      /* Size of each line in bytes */
 	unsigned int log2lsize;     /* log2(linesize) */
 	unsigned int on;            /* VAC is enabled */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-sparc64/delay.h linux-2.4.21-pre6/include/asm-sparc64/delay.h
--- linux-2.4.20/include/asm-sparc64/delay.h	2002-02-25 19:38:13.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-sparc64/delay.h	2003-03-26 23:49:07.000000000 +0000
@@ -45,6 +45,19 @@
 	__delay(usecs * HZ);
 }
 
+extern __inline__ void __ndelay(unsigned long usecs, unsigned long lps)
+{
+	usecs *= 0x0000000000000005UL;		/* 2**32 / 10000 */
+
+	__asm__ __volatile__(
+"	mulx	%1, %2, %0\n"
+"	srlx	%0, 32, %0\n"
+	: "=r" (usecs)
+	: "r" (usecs), "r" (lps));
+
+	__delay(usecs * HZ);
+}
+
 #ifdef CONFIG_SMP
 #define __udelay_val cpu_data[smp_processor_id()].udelay_val
 #else
@@ -52,6 +65,7 @@
 #endif
 
 #define udelay(usecs) __udelay((usecs),__udelay_val)
+#define ndelay(usecs) __ndelay((usecs),__udelay_val)
 
 #endif /* !__ASSEMBLY__ */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-sparc64/elf.h linux-2.4.21-pre6/include/asm-sparc64/elf.h
--- linux-2.4.20/include/asm-sparc64/elf.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-sparc64/elf.h	2003-03-26 23:49:25.000000000 +0000
@@ -109,8 +109,9 @@
 	if (flags != current->thread.flags) {		\
 		/* flush_thread will update pgd cache */\
 		current->thread.flags |= SPARC_FLAG_ABI_PENDING; \
+	} else {					\
+		current->thread.flags &= ~SPARC_FLAG_ABI_PENDING; \
 	}						\
-							\
 	if (ibcs2)					\
 		set_personality(PER_SVR4);		\
 	else if (current->personality != PER_LINUX32)	\
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-sparc64/ide.h linux-2.4.21-pre6/include/asm-sparc64/ide.h
--- linux-2.4.20/include/asm-sparc64/ide.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-sparc64/ide.h	2003-03-26 23:49:29.000000000 +0000
@@ -20,8 +20,6 @@
 #undef  MAX_HWIFS
 #define MAX_HWIFS	2
 
-#define	ide__sti()	__sti()
-
 static __inline__ int ide_default_irq(ide_ioreg_t base)
 {
 	return 0;
@@ -69,57 +67,6 @@
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
-typedef union {
-	unsigned int		all	: 8;	/* all of the bits together */
-	struct {
-		unsigned int	bit7	: 1;
-		unsigned int	lba	: 1;
-		unsigned int	bit5	: 1;
-		unsigned int	unit	: 1;
-		unsigned int	head	: 4;
-	} b;
-} select_t;
-
-typedef union {
-	unsigned int all		: 8;	/* all of the bits together */
-	struct {
-		unsigned int HOB	: 1;	/* 48-bit address ordering */
-		unsigned int reserved456: 3;
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned int SRST	: 1;	/* host soft reset bit */
-		unsigned int nIEN	: 1;	/* device INTRQ to host */
-		unsigned int bit0	: 1;
-	} b;
-} control_t;
-
-static __inline__ int ide_request_irq(unsigned int irq,
-				      void (*handler)(int, void *, struct pt_regs *),
-				      unsigned long flags, const char *name, void *devid)
-{
-	return request_irq(irq, handler, SA_SHIRQ, name, devid);
-}
-
-static __inline__ void ide_free_irq(unsigned int irq, void *dev_id)
-{
-	free_irq(irq, dev_id);
-}
-
-static __inline__ int ide_check_region(ide_ioreg_t base, unsigned int size)
-{
-	return check_region(base, size);
-}
-
-static __inline__ void ide_request_region(ide_ioreg_t base, unsigned int size,
-					  const char *name)
-{
-	request_region(base, size, name);
-}
-
-static __inline__ void ide_release_region(ide_ioreg_t base, unsigned int size)
-{
-	release_region(base, size);
-}
-
 #undef  SUPPORT_SLOW_DATA_PORTS
 #define SUPPORT_SLOW_DATA_PORTS 0
 
@@ -129,26 +76,16 @@
 #undef  HD_DATA
 #define HD_DATA ((ide_ioreg_t)0)
 
-/* From m68k code... */
-
-#ifdef insl
-#undef insl
-#endif
-#ifdef outsl
-#undef outsl
-#endif
-#ifdef insw
-#undef insw
-#endif
-#ifdef outsw
-#undef outsw
-#endif
-
-#define insl(data_reg, buffer, wcount) insw(data_reg, buffer, (wcount)<<1)
-#define outsl(data_reg, buffer, wcount) outsw(data_reg, buffer, (wcount)<<1)
-
-#define insw(port, buf, nr) ide_insw((port), (buf), (nr))
-#define outsw(port, buf, nr) ide_outsw((port), (buf), (nr))
+#define __ide_insl(data_reg, buffer, wcount) \
+	__ide_insw(data_reg, buffer, (wcount)<<1)
+#define __ide_outsl(data_reg, buffer, wcount) \
+	__ide_outsw(data_reg, buffer, (wcount)<<1)
+
+/* On sparc64, I/O ports and MMIO registers are accessed identically.  */
+#define __ide_mm_insw	__ide_insw
+#define __ide_mm_insl	__ide_insl
+#define __ide_mm_outsw	__ide_outsw
+#define __ide_mm_outsl	__ide_outsl
 
 static __inline__ unsigned int inw_be(unsigned long addr)
 {
@@ -161,9 +98,9 @@
 	return ret;
 }
 
-static __inline__ void ide_insw(unsigned long port,
-				void *dst,
-				unsigned long count)
+static __inline__ void __ide_insw(unsigned long port,
+				  void *dst,
+				  u32 count)
 {
 #if (L1DCACHE_SIZE > PAGE_SIZE)		/* is there D$ aliasing problem */
 	unsigned long end = (unsigned long)dst + (count << 1);
@@ -200,9 +137,9 @@
 			     : "r" (w), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E));
 }
 
-static __inline__ void ide_outsw(unsigned long port,
-				 const void *src,
-				 unsigned long count)
+static __inline__ void __ide_outsw(unsigned long port,
+				   void *src,
+				   u32 count)
 {
 #if (L1DCACHE_SIZE > PAGE_SIZE)		/* is there D$ aliasing problem */
 	unsigned long end = (unsigned long)src + (count << 1);
@@ -232,102 +169,6 @@
 #endif
 }
 
-static __inline__ void ide_fix_driveid(struct hd_driveid *id)
-{
-	int i;
-	u16 *stringcast;
-
-	id->config         = __le16_to_cpu(id->config);
-	id->cyls           = __le16_to_cpu(id->cyls);
-	id->reserved2      = __le16_to_cpu(id->reserved2);
-	id->heads          = __le16_to_cpu(id->heads);
-	id->track_bytes    = __le16_to_cpu(id->track_bytes);
-	id->sector_bytes   = __le16_to_cpu(id->sector_bytes);
-	id->sectors        = __le16_to_cpu(id->sectors);
-	id->vendor0        = __le16_to_cpu(id->vendor0);
-	id->vendor1        = __le16_to_cpu(id->vendor1);
-	id->vendor2        = __le16_to_cpu(id->vendor2);
-	stringcast = (u16 *)&id->serial_no[0];
-	for (i = 0; i < (20/2); i++)
-	        stringcast[i] = __le16_to_cpu(stringcast[i]);
-	id->buf_type       = __le16_to_cpu(id->buf_type);
-	id->buf_size       = __le16_to_cpu(id->buf_size);
-	id->ecc_bytes      = __le16_to_cpu(id->ecc_bytes);
-	stringcast = (u16 *)&id->fw_rev[0];
-	for (i = 0; i < (8/2); i++)
-	        stringcast[i] = __le16_to_cpu(stringcast[i]);
-	stringcast = (u16 *)&id->model[0];
-	for (i = 0; i < (40/2); i++)
-	        stringcast[i] = __le16_to_cpu(stringcast[i]);
-	id->dword_io       = __le16_to_cpu(id->dword_io);
-	id->reserved50     = __le16_to_cpu(id->reserved50);
-	id->field_valid    = __le16_to_cpu(id->field_valid);
-	id->cur_cyls       = __le16_to_cpu(id->cur_cyls);
-	id->cur_heads      = __le16_to_cpu(id->cur_heads);
-	id->cur_sectors    = __le16_to_cpu(id->cur_sectors);
-	id->cur_capacity0  = __le16_to_cpu(id->cur_capacity0);
-	id->cur_capacity1  = __le16_to_cpu(id->cur_capacity1);
-	id->lba_capacity   = __le32_to_cpu(id->lba_capacity);
-	id->dma_1word      = __le16_to_cpu(id->dma_1word);
-	id->dma_mword      = __le16_to_cpu(id->dma_mword);
-	id->eide_pio_modes = __le16_to_cpu(id->eide_pio_modes);
-	id->eide_dma_min   = __le16_to_cpu(id->eide_dma_min);
-	id->eide_dma_time  = __le16_to_cpu(id->eide_dma_time);
-	id->eide_pio       = __le16_to_cpu(id->eide_pio);
-	id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy);
-	for (i = 0; i < 2; i++)
-		id->words69_70[i] = __le16_to_cpu(id->words69_70[i]);
-        for (i = 0; i < 4; i++)
-                id->words71_74[i] = __le16_to_cpu(id->words71_74[i]);
-	id->queue_depth	   = __le16_to_cpu(id->queue_depth);
-	for (i = 0; i < 4; i++)
-		id->words76_79[i] = __le16_to_cpu(id->words76_79[i]);
-	id->major_rev_num  = __le16_to_cpu(id->major_rev_num);
-	id->minor_rev_num  = __le16_to_cpu(id->minor_rev_num);
-	id->command_set_1  = __le16_to_cpu(id->command_set_1);
-	id->command_set_2  = __le16_to_cpu(id->command_set_2);
-	id->cfsse          = __le16_to_cpu(id->cfsse);
-	id->cfs_enable_1   = __le16_to_cpu(id->cfs_enable_1);
-	id->cfs_enable_2   = __le16_to_cpu(id->cfs_enable_2);
-	id->csf_default    = __le16_to_cpu(id->csf_default);
-	id->dma_ultra      = __le16_to_cpu(id->dma_ultra);
-	id->word89         = __le16_to_cpu(id->word89);
-	id->word90         = __le16_to_cpu(id->word90);
-	id->CurAPMvalues   = __le16_to_cpu(id->CurAPMvalues);
-	id->word92         = __le16_to_cpu(id->word92);
-	id->hw_config      = __le16_to_cpu(id->hw_config);
-	id->acoustic       = __le16_to_cpu(id->acoustic);
-	for (i = 0; i < 5; i++)
-		id->words95_99[i]  = __le16_to_cpu(id->words95_99[i]);
-	id->lba_capacity_2 = __le64_to_cpu(id->lba_capacity_2);
-	for (i = 0; i < 22; i++)
-		id->words104_125[i]   = __le16_to_cpu(id->words104_125[i]);
-	id->last_lun       = __le16_to_cpu(id->last_lun);
-	id->word127        = __le16_to_cpu(id->word127);
-	id->dlf            = __le16_to_cpu(id->dlf);
-	id->csfo           = __le16_to_cpu(id->csfo);
-	for (i = 0; i < 26; i++)
-		id->words130_155[i] = __le16_to_cpu(id->words130_155[i]);
-	id->word156        = __le16_to_cpu(id->word156);
-	for (i = 0; i < 3; i++)
-		id->words157_159[i] = __le16_to_cpu(id->words157_159[i]);
-	id->cfa_power      = __le16_to_cpu(id->cfa_power);
-	for (i = 0; i < 14; i++)
-		id->words161_175[i] = __le16_to_cpu(id->words161_175[i]);
-	for (i = 0; i < 31; i++)
-		id->words176_205[i] = __le16_to_cpu(id->words176_205[i]);
-	for (i = 0; i < 48; i++)
-		id->words206_254[i] = __le16_to_cpu(id->words206_254[i]);
-	id->integrity_word  = __le16_to_cpu(id->integrity_word);
-}
-
-/*
- * The following are not needed for the non-m68k ports
- */
-#define ide_ack_intr(hwif)		(1)
-#define ide_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
-
 #endif /* __KERNEL__ */
 
 #endif /* _SPARC64_IDE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-sparc64/ioctl.h linux-2.4.21-pre6/include/asm-sparc64/ioctl.h
--- linux-2.4.20/include/asm-sparc64/ioctl.h	1998-10-27 17:52:21.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-sparc64/ioctl.h	2003-03-26 23:49:20.000000000 +0000
@@ -2,23 +2,35 @@
 #ifndef _SPARC64_IOCTL_H
 #define _SPARC64_IOCTL_H
 
+/*
+ * Our DIR and SIZE overlap in order to simulteneously provide
+ * a non-zero _IOC_NONE (for binary compatibility) and
+ * 14 bits of size as on i386. Here's the layout:
+ *
+ *   0xE0000000   DIR
+ *   0x80000000     DIR = WRITE
+ *   0x40000000     DIR = READ
+ *   0x20000000     DIR = NONE
+ *   0x3FFF0000   SIZE (overlaps NONE bit)
+ *   0x0000FF00   TYPE
+ *   0x000000FF   NR (CMD)
+ */
+
 #define _IOC_NRBITS      8
 #define _IOC_TYPEBITS    8
-#define _IOC_SIZEBITS    8
-#define _IOC_RESVBITS    5
+#define _IOC_SIZEBITS   13	/* Actually 14, see below. */
 #define _IOC_DIRBITS     3
 
 #define _IOC_NRMASK      ((1 << _IOC_NRBITS)-1)
 #define _IOC_TYPEMASK    ((1 << _IOC_TYPEBITS)-1)
-#define _IOC_RESVMASK    ((1 << _IOC_RESVBITS)-1)
 #define _IOC_SIZEMASK    ((1 << _IOC_SIZEBITS)-1)
+#define _IOC_XSIZEMASK   ((1 << (_IOC_SIZEBITS+1))-1)
 #define _IOC_DIRMASK     ((1 << _IOC_DIRBITS)-1)
 
 #define _IOC_NRSHIFT     0
 #define _IOC_TYPESHIFT   (_IOC_NRSHIFT + _IOC_NRBITS)
 #define _IOC_SIZESHIFT   (_IOC_TYPESHIFT + _IOC_TYPEBITS)
-#define _IOC_RESVSHIFT   (_IOC_SIZESHIFT + _IOC_SIZEBITS)
-#define _IOC_DIRSHIFT    (_IOC_RESVSHIFT + _IOC_RESVBITS)
+#define _IOC_DIRSHIFT    (_IOC_SIZESHIFT + _IOC_SIZEBITS)
 
 #define _IOC_NONE        1U
 #define _IOC_READ        2U
@@ -35,17 +47,20 @@
 #define _IOW(type,nr,size)  _IOC(_IOC_WRITE,(type),(nr),sizeof(size))
 #define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size))
 
-#define _IOC_DIR(nr)        (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)
+/* Used to decode ioctl numbers in drivers despite the leading underscore... */
+#define _IOC_DIR(nr)    \
+ ( (((((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK) & (_IOC_WRITE|_IOC_READ)) != 0)?   \
+                            (((nr) >> _IOC_DIRSHIFT) & (_IOC_WRITE|_IOC_READ)):  \
+                            (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK) )
 #define _IOC_TYPE(nr)       (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)
 #define _IOC_NR(nr)         (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)
-#define _IOC_SIZE(nr)       (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)
-
-/* ...and for the PCMCIA... */
+#define _IOC_SIZE(nr)       (((nr) >> _IOC_SIZESHIFT) & _IOC_XSIZEMASK)
 
+/* ...and for the PCMCIA and sound. */
 #define IOC_IN          (_IOC_WRITE << _IOC_DIRSHIFT)
 #define IOC_OUT         (_IOC_READ << _IOC_DIRSHIFT)
 #define IOC_INOUT       ((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT)
-#define IOCSIZE_MASK    (_IOC_SIZEMASK << _IOC_SIZESHIFT)
+#define IOCSIZE_MASK    (_IOC_XSIZEMASK << _IOC_SIZESHIFT)
 #define IOCSIZE_SHIFT   (_IOC_SIZESHIFT)
 
 #endif /* !(_SPARC64_IOCTL_H) */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-sparc64/irq.h linux-2.4.21-pre6/include/asm-sparc64/irq.h
--- linux-2.4.20/include/asm-sparc64/irq.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-sparc64/irq.h	2003-03-26 23:49:39.000000000 +0000
@@ -109,13 +109,11 @@
 	return buff;
 }
 
-#define NR_IRQS    15
+#define NR_IRQS    16
 
 extern void disable_irq(unsigned int);
 #define disable_irq_nosync disable_irq
 extern void enable_irq(unsigned int);
-extern void init_timers(void (*lvl10_irq)(int, void *, struct pt_regs *),
-			unsigned long *);
 extern unsigned int build_irq(int pil, int inofixup, unsigned long iclr, unsigned long imap);
 extern unsigned int sbus_build_irq(void *sbus, unsigned int ino);
 extern unsigned int psycho_build_irq(void *psycho, int imap_off, int ino, int need_dma_sync);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-sparc64/mman.h linux-2.4.21-pre6/include/asm-sparc64/mman.h
--- linux-2.4.20/include/asm-sparc64/mman.h	2000-03-15 08:37:50.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-sparc64/mman.h	2003-03-26 23:49:38.000000000 +0000
@@ -20,7 +20,7 @@
 #define MAP_LOCKED      0x100           /* lock the mapping */
 #define _MAP_NEW        0x80000000      /* Binary compatibility is fun... */
 
-#define MAP_GROWSDOWN	0x0100		/* stack-like segment */
+#define MAP_GROWSDOWN	0x0200		/* stack-like segment */
 #define MAP_DENYWRITE	0x0800		/* ETXTBSY */
 #define MAP_EXECUTABLE	0x1000		/* mark it as an executable */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-sparc64/processor.h linux-2.4.21-pre6/include/asm-sparc64/processor.h
--- linux-2.4.20/include/asm-sparc64/processor.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-sparc64/processor.h	2003-03-26 23:48:58.000000000 +0000
@@ -270,7 +270,7 @@
 /* Free all resources held by a thread. */
 #define release_thread(tsk)		do { } while(0)
 
-extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
+extern pid_t arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
 #define copy_segments(tsk, mm)		do { } while (0)
 #define release_segments(mm)		do { } while (0)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-sparc64/spitfire.h linux-2.4.21-pre6/include/asm-sparc64/spitfire.h
--- linux-2.4.20/include/asm-sparc64/spitfire.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-sparc64/spitfire.h	2003-03-26 23:49:20.000000000 +0000
@@ -45,8 +45,6 @@
 
 extern enum ultra_tlb_layout tlb_type;
 
-#define SPARC64_USE_STICK	(tlb_type != spitfire)
-
 #define CHEETAH_HIGHEST_LOCKED_TLBENT	(16 - 1)
 
 #define L1DCACHE_SIZE		0x4000
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-sparc64/system.h linux-2.4.21-pre6/include/asm-sparc64/system.h
--- linux-2.4.20/include/asm-sparc64/system.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-sparc64/system.h	2003-03-26 23:48:58.000000000 +0000
@@ -62,12 +62,23 @@
 	retval; \
 })
 
+#define read_pil_and_sti() \
+({	unsigned long retval; \
+	__asm__ __volatile__("rdpr	%%pil, %0\n\t" \
+			     "wrpr	0, %%pil" \
+			     : "=r" (retval) \
+			     : : "memory"); \
+	retval; \
+})
+
 #define __save_flags(flags)		((flags) = getipl())
 #define __save_and_cli(flags)		((flags) = read_pil_and_cli())
+#define __save_and_sti(flags)		((flags) = read_pil_and_sti())
 #define __restore_flags(flags)		setipl((flags))
 #define local_irq_disable()		__cli()
 #define local_irq_enable()		__sti()
 #define local_irq_save(flags)		__save_and_cli(flags)
+#define local_irq_set(flags)		__save_and_sti(flags)
 #define local_irq_restore(flags)	__restore_flags(flags)
 
 #ifndef CONFIG_SMP
@@ -172,6 +183,11 @@
 	 * not preserve it's value.  Hairy, but it lets us remove 2 loads
 	 * and 2 stores in this critical code path.  -DaveM
 	 */
+#if __GNUC__ >= 3
+#define EXTRA_CLOBBER ,"%l1"
+#else
+#define EXTRA_CLOBBER
+#endif
 #define switch_to(prev, next, last)						\
 do {	CHECK_LOCKS(prev);							\
 	if (current->thread.flags & SPARC_FLAG_PERFCTR) {			\
@@ -220,10 +236,11 @@
 	  "i" ((const unsigned long)(&((struct task_struct *)0)->thread.flags)),\
 	  "i" ((const unsigned long)(&((struct task_struct *)0)->thread.cwp)),	\
 	  "i" (SPARC_FLAG_NEWCHILD)						\
-	: "cc", "g1", "g2", "g3", "g5", "g7",					\
-	  "l2", "l3", "l4", "l5", "l6", "l7",					\
+	: "cc",									\
+                "g1", "g2", "g3",       "g5",       "g7",			\
+	              "l2", "l3", "l4", "l5", "l6", "l7",			\
 	  "i0", "i1", "i2", "i3", "i4", "i5",					\
-	  "o0", "o1", "o2", "o3", "o4", "o5", "o7");				\
+	  "o0", "o1", "o2", "o3", "o4", "o5",       "o7" EXTRA_CLOBBER);	\
 	/* If you fuck with this, update ret_from_syscall code too. */		\
 	if (current->thread.flags & SPARC_FLAG_PERFCTR) {			\
 		write_pcr(current->thread.pcr_reg);				\
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-sparc64/timer.h linux-2.4.21-pre6/include/asm-sparc64/timer.h
--- linux-2.4.20/include/asm-sparc64/timer.h	2000-05-22 16:50:55.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-sparc64/timer.h	2003-03-26 23:49:07.000000000 +0000
@@ -50,6 +50,17 @@
  */
 #define SUN5_HZ_TO_LIMIT(__hz)  (1000000/(__hz))
 
+struct sparc64_tick_ops {
+	void (*init_tick)(unsigned long);
+	unsigned long (*get_tick)(void);
+	unsigned long (*get_compare)(void);
+	unsigned long (*add_tick)(unsigned long, unsigned long);
+	unsigned long (*add_compare)(unsigned long);
+	unsigned long softint_mask;
+};
+
+extern struct sparc64_tick_ops *tick_ops;
+
 #ifdef CONFIG_SMP
 extern unsigned long timer_tick_offset;
 extern void timer_tick_interrupt(struct pt_regs *);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-sparc64/unistd.h linux-2.4.21-pre6/include/asm-sparc64/unistd.h
--- linux-2.4.20/include/asm-sparc64/unistd.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-sparc64/unistd.h	2003-03-26 23:49:09.000000000 +0000
@@ -184,24 +184,24 @@
 /* #define __NR_exportfs        166    SunOS Specific                              */
 #define __NR_mount              167 /* Common                                      */
 #define __NR_ustat              168 /* Common                                      */
-/* #define __NR_semsys          169    SunOS Specific                              */
-/* #define __NR_msgsys          170    SunOS Specific                              */
-/* #define __NR_shmsys          171    SunOS Specific                              */
-/* #define __NR_auditsys        172    SunOS Specific                              */
-/* #define __NR_rfssys          173    SunOS Specific                              */
+#define __NR_setxattr           169 /* SunOS: semsys                               */
+#define __NR_lsetxattr          170 /* SunOS: msgsys                               */
+#define __NR_fsetxattr          171 /* SunOS: shmsys                               */
+#define __NR_getxattr           172 /* SunOS: auditsys                             */
+#define __NR_lgetxattr          173 /* SunOS: rfssys                               */
 #define __NR_getdents           174 /* Common                                      */
 #define __NR_setsid             175 /* Common                                      */
 #define __NR_fchdir             176 /* Common                                      */
-/* #define __NR_fchroot         177    SunOS Specific                              */
-/* #define __NR_vpixsys         178    SunOS Specific                              */
-/* #define __NR_aioread         179    SunOS Specific                              */
-/* #define __NR_aiowrite        180    SunOS Specific                              */
-/* #define __NR_aiowait         181    SunOS Specific                              */
-/* #define __NR_aiocancel       182    SunOS Specific                              */
+#define __NR_fgetxattr          177 /* SunOS: fchroot                              */
+#define __NR_listxattr          178 /* SunOS: vpixsys                              */
+#define __NR_llistxattr         179 /* SunOS: aioread                              */
+#define __NR_flistxattr         180 /* SunOS: aiowrite                             */
+#define __NR_removexattr        181 /* SunOS: aiowait                              */
+#define __NR_lremovexattr       182 /* SunOS: aiocancel                            */
 #define __NR_sigpending         183 /* Common                                      */
 #define __NR_query_module	184 /* Linux Specific				   */
 #define __NR_setpgid            185 /* Common                                      */
-/* #define __NR_pathconf        186    SunOS Specific                              */
+#define __NR_fremovexattr       186 /* SunOS: pathconf                             */
 #define __NR_tkill              187 /* SunOS: fpathconf                            */
 /* #define __NR_sysconf         188    SunOS Specific                              */
 #define __NR_uname              189 /* Linux Specific                              */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-x86_64/apic.h linux-2.4.21-pre6/include/asm-x86_64/apic.h
--- linux-2.4.20/include/asm-x86_64/apic.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-x86_64/apic.h	2003-03-26 23:48:57.000000000 +0000
@@ -78,7 +78,7 @@
 extern void smp_local_timer_interrupt (struct pt_regs * regs);
 extern void setup_APIC_clocks (void);
 extern void setup_apic_nmi_watchdog (void);
-extern inline void nmi_watchdog_tick (struct pt_regs * regs);
+extern inline void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason);
 extern int APIC_init_uniprocessor (void);
 extern void disable_APIC_timer(void);
 extern void enable_APIC_timer(void);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-x86_64/bitops.h linux-2.4.21-pre6/include/asm-x86_64/bitops.h
--- linux-2.4.20/include/asm-x86_64/bitops.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-x86_64/bitops.h	2003-03-26 23:49:50.000000000 +0000
@@ -372,7 +372,7 @@
 	__asm__("bsfl %1,%0\n\t"
 		"jnz 1f\n\t"
 		"movl $-1,%0\n"
-		"1:" : "=r" (r) : "rm" (x));
+		"1:" : "=r" (r) : "g" (x));
 	return r+1;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-x86_64/checksum.h linux-2.4.21-pre6/include/asm-x86_64/checksum.h
--- linux-2.4.20/include/asm-x86_64/checksum.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-x86_64/checksum.h	2003-03-26 23:48:58.000000000 +0000
@@ -125,7 +125,7 @@
  * Before filling it in it needs to be csum_fold()'ed.
  * buff should be aligned to a 64bit boundary if possible.
  */ 
-extern unsigned int csum_partial(const unsigned char *buff, int len, unsigned int sum);
+extern unsigned int csum_partial(const unsigned char *buff, unsigned len, unsigned int sum);
 
 #define  _HAVE_ARCH_COPY_AND_CSUM_FROM_USER 1
 #define HAVE_CSUM_COPY_USER 1
@@ -179,4 +179,14 @@
 csum_ipv6_magic(struct in6_addr *saddr, struct in6_addr *daddr,
 		__u32 len, unsigned short proto, unsigned int sum);
 
+static inline unsigned add32_with_carry(unsigned a, unsigned b)
+{
+	asm("addl %2,%0\n\t"
+	    "adcl $0,%0" 
+	    : "=r" (a) 
+	    : "0" (a), "r" (b));
+	return a;
+}
+
 #endif
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-x86_64/debugreg.h linux-2.4.21-pre6/include/asm-x86_64/debugreg.h
--- linux-2.4.20/include/asm-x86_64/debugreg.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-x86_64/debugreg.h	2003-03-26 23:49:34.000000000 +0000
@@ -58,7 +58,7 @@
    We can slow the instruction pipeline for instructions coming via the
    gdt or the ldt if we want to.  I am not sure why this is an advantage */
 
-#define DR_CONTROL_RESERVED (0xFC00) /* Reserved by Intel */
+#define DR_CONTROL_RESERVED (0xFFFFFFFF0000FC00UL) /* Reserved */
 #define DR_LOCAL_SLOWDOWN (0x100)   /* Local slow the pipeline */
 #define DR_GLOBAL_SLOWDOWN (0x200)  /* Global slow the pipeline */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-x86_64/delay.h linux-2.4.21-pre6/include/asm-x86_64/delay.h
--- linux-2.4.20/include/asm-x86_64/delay.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-x86_64/delay.h	2003-03-26 23:49:53.000000000 +0000
@@ -8,8 +8,10 @@
  */
  
 extern void __bad_udelay(void);
+extern void __bad_ndelay(void);
 
 extern void __udelay(unsigned long usecs);
+extern void __ndelay(unsigned long usecs);
 extern void __const_udelay(unsigned long usecs);
 extern void __delay(unsigned long loops);
 
@@ -17,4 +19,8 @@
 	((n) > 20000 ? __bad_udelay() : __const_udelay((n) * 0x10c6ul)) : \
 	__udelay(n))
 
+#define ndelay(n) (__builtin_constant_p(n) ? \
+       ((n) > 20000 ? __bad_ndelay() : __const_udelay((n) * 5ul)) : \
+       __ndelay(n))
+
 #endif /* defined(_X8664_DELAY_H) */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-x86_64/floppy.h linux-2.4.21-pre6/include/asm-x86_64/floppy.h
--- linux-2.4.20/include/asm-x86_64/floppy.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-x86_64/floppy.h	2003-03-26 23:49:54.000000000 +0000
@@ -22,7 +22,7 @@
  * floppy accesses go through the track buffer.
  */
 #define _CROSS_64KB(a,s,vdma) \
-(!vdma && ((unsigned long)(a)/K_64 != ((unsigned long)(a) + (s) - 1) / K_64))
+(!(vdma) && ((unsigned long)(a)/K_64 != ((unsigned long)(a) + (s) - 1) / K_64))
 
 #define CROSS_64KB(a,s) _CROSS_64KB(a,s,use_virtual_dma & 1)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-x86_64/hdreg.h linux-2.4.21-pre6/include/asm-x86_64/hdreg.h
--- linux-2.4.20/include/asm-x86_64/hdreg.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-x86_64/hdreg.h	2003-03-26 23:49:20.000000000 +0000
@@ -7,6 +7,7 @@
 #ifndef __ASMx86_64_HDREG_H
 #define __ASMx86_64_HDREG_H
 
-typedef unsigned short ide_ioreg_t;
+//typedef unsigned short ide_ioreg_t;
+typedef unsigned long ide_ioreg_t;
 
 #endif /* __ASMx86_64_HDREG_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-x86_64/hw_irq.h linux-2.4.21-pre6/include/asm-x86_64/hw_irq.h
--- linux-2.4.20/include/asm-x86_64/hw_irq.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-x86_64/hw_irq.h	2003-03-26 23:49:20.000000000 +0000
@@ -1,6 +1,7 @@
 #ifndef _ASM_HW_IRQ_H
 #define _ASM_HW_IRQ_H
 
+#ifndef __ASSEMBLY__
 /*
  *	linux/include/asm/hw_irq.h
  *
@@ -13,13 +14,16 @@
  *
  *	hacked by Andi Kleen for x86-64.
  * 
- *  $Id: hw_irq.h,v 1.29 2002/04/15 23:43:12 ak Exp $
+ *  $Id: hw_irq.h,v 1.31 2003/02/18 18:35:55 ak Exp $
  */
 
 #include <linux/config.h>
+#include <linux/stddef.h>
 #include <asm/atomic.h>
 #include <asm/irq.h>
 
+#endif
+
 /*
  * IDT vectors usable for external interrupt sources start
  * at 0x20:
@@ -27,7 +31,6 @@
 #define FIRST_EXTERNAL_VECTOR	0x20
 
 #define IA32_SYSCALL_VECTOR	0x80
-#define KDBENTER_VECTOR		0x81
 
 
 /*
@@ -47,9 +50,8 @@
 #define ERROR_APIC_VECTOR	0xfe
 #define INVALIDATE_TLB_VECTOR	0xfd
 #define RESCHEDULE_VECTOR	0xfc
-#define KDB_VECTOR		0xfa
+/* 0xfa free */
 #define CALL_FUNCTION_VECTOR	0xfb
-#define KDB_VECTOR              0xfa
 
 /*
  * Local APIC timer IRQ vector is on a different priority level,
@@ -66,6 +68,7 @@
 #define FIRST_DEVICE_VECTOR	0x31
 #define FIRST_SYSTEM_VECTOR	0xef
 
+#ifndef __ASSEMBLY__
 extern int irq_vector[NR_IRQS];
 #define IO_APIC_VECTOR(irq)	irq_vector[irq]
 
@@ -100,58 +103,18 @@
 
 #define IO_APIC_IRQ(x) (((x) >= 16) || ((1<<(x)) & io_apic_irqs))
 
-#define __STR(x) #x
-#define STR(x) __STR(x)
-
 #include <asm/ptrace.h>
-#ifndef ASM_OFFSET_H
-#include <asm/offset.h>
-#endif
 
-/* IF:off, stack contains irq number on origrax */ 
-#define IRQ_ENTER								\
-"	cld ;"									\
-"	pushq %rdi ;"								\
-"	pushq %rsi ;"								\
-"	pushq %rdx ;"								\
-"	pushq %rcx ;"								\
-"	pushq %rax ;"								\
-"	pushq %r8 ;"								\
-"	pushq %r9 ;"								\
-"	pushq %r10 ;"								\
-"	pushq %r11 ;"								\
-"	leaq -48(%rsp),%rdi	;"						\
-"	testl $3,136(%rdi)	;"						\
-"	je 1f ;"								\
-"	swapgs ;"								\
-"1:	addl $1,%gs: " STR(pda_irqcount) ";"					\
-"	movq %gs: " STR(pda_irqstackptr) ",%rax ;"				\
-"	cmoveq %rax,%rsp ;"							\
-"	pushq %rdi ;" 
+extern void reschedule_interrupt(void);
+extern void invalidate_interrupt(void);
+extern void call_function_interrupt(void);
+extern void apic_timer_interrupt(void);
+extern void spurious_interrupt(void);
+extern void error_interrupt(void);
 
 #define IRQ_NAME2(nr) nr##_interrupt(void)
 #define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr)
 
-/*
- *	SMP has a few special interrupts for IPI messages
- */
-
-	/* there is a second layer of macro just to get the symbolic
-	   name for the vector evaluated. This change is for RTLinux */
-#define BUILD_SMP_INTERRUPT(x,v) XBUILD_SMP_INTERRUPT(x,v)
-#define XBUILD_SMP_INTERRUPT(x,v)\
-asmlinkage void x(void); \
-asmlinkage void call_##x(void); \
-__asm__( \
-"\n"__ALIGN_STR"\n" \
-SYMBOL_NAME_STR(x) ":\n\t" \
-	"push $" #v "-256;" \
-	IRQ_ENTER \
-	"call " SYMBOL_NAME_STR(smp_##x) " ; " \
-	"jmp ret_from_intr")
-
-#define BUILD_COMMON_IRQ()
-
 #define BUILD_IRQ(nr) \
 asmlinkage void IRQ_NAME(nr); \
 __asm__( \
@@ -202,4 +165,6 @@
 static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {}
 #endif
 
+#endif
+
 #endif /* _ASM_HW_IRQ_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-x86_64/i387.h linux-2.4.21-pre6/include/asm-x86_64/i387.h
--- linux-2.4.20/include/asm-x86_64/i387.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-x86_64/i387.h	2003-03-26 23:49:19.000000000 +0000
@@ -17,8 +17,8 @@
 #include <asm/sigcontext.h>
 #include <asm/user.h>
 
-extern void init_fpu(void);
-int save_i387( struct _fpstate *buf);
+extern void init_fpu(struct task_struct *child);
+extern int save_i387(struct _fpstate *buf);
 
 /*
  * FPU lazy state save handling...
@@ -110,7 +110,7 @@
 {
 	struct task_struct *tsk = current;
 	if (tsk->flags & PF_USEDFPU) {
-		asm volatile("fxsave %0 ; fnclex"
+		asm volatile("rex64 ; fxsave %0 ; fnclex"
 			      : "=m" (tsk->thread.i387.fxsave));
 		tsk->flags &= ~PF_USEDFPU;
 		return;
@@ -134,18 +134,4 @@
 	return restore_fpu_checking((struct i387_fxsave_struct *)buf);
 }
 
-
-static inline void empty_fpu(struct task_struct *child)
-{
-	if (!child->used_math) {
-		/* Simulate an empty FPU. */
-		memset(&child->thread.i387.fxsave,0,sizeof(struct i387_fxsave_struct));
-		child->thread.i387.fxsave.cwd = 0x037f; 
-		child->thread.i387.fxsave.swd = 0;
-		child->thread.i387.fxsave.twd = 0; 
-		child->thread.i387.fxsave.mxcsr = 0x1f80;
-	}
-	child->used_math = 1; 
-}		
-
 #endif /* __ASM_X86_64_I387_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-x86_64/ia32.h linux-2.4.21-pre6/include/asm-x86_64/ia32.h
--- linux-2.4.20/include/asm-x86_64/ia32.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-x86_64/ia32.h	2003-03-26 23:49:51.000000000 +0000
@@ -234,12 +234,6 @@
 	int iov_len; 
 };
 
-
-#ifdef __KERNEL__
-struct iovec *get_iovec32(struct iovec32 *iov32, struct iovec *iov_buf, u32 count, int type);
-#endif
-
-
 #endif /* !CONFIG_IA32_SUPPORT */
  
 #endif 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-x86_64/ia32_unistd.h linux-2.4.21-pre6/include/asm-x86_64/ia32_unistd.h
--- linux-2.4.20/include/asm-x86_64/ia32_unistd.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-x86_64/ia32_unistd.h	2003-03-26 23:49:06.000000000 +0000
@@ -232,22 +232,24 @@
 #define __NR_ia32_security		223
 #define __NR_ia32_gettid		224
 #define __NR_ia32_readahead		225
+#define __NR_ia32_setxattr		226
+#define __NR_ia32_lsetxattr		227
+#define __NR_ia32_fsetxattr		228
+#define __NR_ia32_getxattr		229
+#define __NR_ia32_lgetxattr		230
+#define __NR_ia32_fgetxattr		231
+#define __NR_ia32_listxattr		232
+#define __NR_ia32_llistxattr		233
+#define __NR_ia32_flistxattr		234
+#define __NR_ia32_removexattr	235
+#define __NR_ia32_lremovexattr	236
+#define __NR_ia32_fremovexattr	237
+#define __NR_ia32_tkill		238
 #define __NR_ia32_sendfile64		239
 #define __NR_ia32_futex		240
 #define __NR_ia32_sched_setaffinity	241
 #define __NR_ia32_sched_getaffinity	242
-#define __NR_ia32_set_thread_area	243
-#define __NR_ia32_get_thread_area	244
-#define __NR_ia32_io_setup		245
-#define __NR_ia32_io_destroy		246
-#define __NR_ia32_io_getevents	247
-#define __NR_ia32_io_submit		248
-#define __NR_ia32_io_cancel		249
-#define __NR_ia32_alloc_hugepages	250
-#define __NR_ia32_free_hugepages	251
-#define __NR_ia32_exit_group		252
 
-
-#define IA32_NR_syscalls 260
+#define IA32_NR_syscalls 245
 
 #endif /* _ASM_X86_64_IA32_UNISTD_H_ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-x86_64/ide.h linux-2.4.21-pre6/include/asm-x86_64/ide.h
--- linux-2.4.20/include/asm-x86_64/ide.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-x86_64/ide.h	2003-03-26 23:49:19.000000000 +0000
@@ -5,7 +5,7 @@
  */
 
 /*
- *  This file contains the x86_64 architecture specific IDE code.
+ *  This file contains the i386 architecture specific IDE code.
  */
 
 #ifndef __ASMx86_64_IDE_H
@@ -23,8 +23,6 @@
 # endif
 #endif
 
-#define ide__sti()	__sti()
-
 static __inline__ int ide_default_irq(ide_ioreg_t base)
 {
 	switch (base) {
@@ -79,6 +77,7 @@
 	int index;
 
 	for(index = 0; index < MAX_HWIFS; index++) {
+		memset(&hw, 0, sizeof hw);
 		ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL);
 		hw.irq = ide_default_irq(ide_default_io_base(index));
 		ide_register_hw(&hw, NULL);
@@ -86,42 +85,7 @@
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned bit0		: 1;
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned reserved456	: 3;
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-	} b;
-} control_t;
-
-#define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
-#define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
-#define ide_check_region(from,extent)		check_region((from), (extent))
-#define ide_request_region(from,extent,name)	request_region((from), (extent), (name))
-#define ide_release_region(from,extent)		release_region((from), (extent))
-
-/*
- * The following are not needed for the non-m68k ports
- */
-#define ide_ack_intr(hwif)		(1)
-#define ide_fix_driveid(id)		do {} while (0)
-#define ide_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
+#include <asm-generic/ide_iops.h>
 
 #endif /* __KERNEL__ */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-x86_64/io.h linux-2.4.21-pre6/include/asm-x86_64/io.h
--- linux-2.4.20/include/asm-x86_64/io.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-x86_64/io.h	2003-03-26 23:49:54.000000000 +0000
@@ -182,16 +182,20 @@
 #define readb(addr) (*(volatile unsigned char *) __io_virt(addr))
 #define readw(addr) (*(volatile unsigned short *) __io_virt(addr))
 #define readl(addr) (*(volatile unsigned int *) __io_virt(addr))
+#define readq(addr) (*(volatile unsigned long *) __io_virt(addr))
 #define __raw_readb readb
 #define __raw_readw readw
 #define __raw_readl readl
+#define __raw_readq readq
 
 #define writeb(b,addr) (*(volatile unsigned char *) __io_virt(addr) = (b))
 #define writew(b,addr) (*(volatile unsigned short *) __io_virt(addr) = (b))
 #define writel(b,addr) (*(volatile unsigned int *) __io_virt(addr) = (b))
+#define writeq(b,addr) (*(volatile unsigned long *) __io_virt(addr) = (b))
 #define __raw_writeb writeb
 #define __raw_writew writew
 #define __raw_writel writel
+#define __raw_writeq writeq
 
 void *memcpy_fromio(void*,const void*,unsigned); 
 void *memcpy_toio(void*,const void*,unsigned); 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-x86_64/kdebug.h linux-2.4.21-pre6/include/asm-x86_64/kdebug.h
--- linux-2.4.20/include/asm-x86_64/kdebug.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-x86_64/kdebug.h	2003-03-26 23:49:06.000000000 +0000
@@ -9,8 +9,12 @@
 	struct pt_regs *regs;
 	const char *str;
 	long err; 
+	int trapnr;
+	int signr;
 }; 
 
+/* Note - you should never unregister because that can race with NMIs.
+   If you really want to do it use RCU infrastructure. */
 extern struct notifier_block *die_chain;
 
 /* Grossly misnamed. */
@@ -21,18 +25,21 @@
 	DIE_PANIC,
 	DIE_NMI,
 	DIE_DIE,
+	DIE_NMIWATCHDOG,
+	DIE_KERNELDEBUG,
+	DIE_TRAP,
+	DIE_GPF,
 	DIE_CALL,
-	DIE_CPUINIT,	/* not really a die, but .. */
-	DIE_TRAPINIT,	/* not really a die, but .. */
-	DIE_STOP, 
 }; 
 
-static inline int notify_die(enum die_val val,char *str,struct pt_regs *regs,long err)
+static inline int notify_die(enum die_val val,char *str,struct pt_regs *regs,long err,int trap,int sig)
 { 
-	struct die_args args = { regs: regs, str: str, err: err }; 
+	struct die_args args = { regs: regs, str: str, err: err, trapnr: trap,
+	signr: sig}; 
 	return notifier_call_chain(&die_chain, val, &args); 
 } 
 
+
 extern int printk_address(unsigned long address);
 extern void die(const char *,struct pt_regs *,long);
 extern void show_stack(unsigned long* esp);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-x86_64/kmap_types.h linux-2.4.21-pre6/include/asm-x86_64/kmap_types.h
--- linux-2.4.20/include/asm-x86_64/kmap_types.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-x86_64/kmap_types.h	2003-03-26 23:49:31.000000000 +0000
@@ -3,11 +3,10 @@
 
 enum km_type {
 	KM_BOUNCE_READ,
-	KM_SKB_SUNRPC_DATA,
+	KM_SKB_DATA,
 	KM_SKB_DATA_SOFTIRQ,
 	KM_USER0,
 	KM_USER1,
-	KM_BH_IRQ,
 	KM_TYPE_NR
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-x86_64/page.h linux-2.4.21-pre6/include/asm-x86_64/page.h
--- linux-2.4.20/include/asm-x86_64/page.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-x86_64/page.h	2003-03-26 23:49:49.000000000 +0000
@@ -1,6 +1,8 @@
 #ifndef _X86_64_PAGE_H
 #define _X86_64_PAGE_H
 
+#include <linux/stringify.h>
+
 /* PAGE_SHIFT determines the page size */
 #define PAGE_SHIFT	12
 #ifdef __ASSEMBLY__
@@ -23,6 +25,8 @@
 
 /* Changing the next two defines should be enough to increase the kernel stack */
 /* We still hope 8K is enough, but ... */
+/* Currently it is actually ~6k. This would change when task_struct moves into
+   an own slab. */
 #define THREAD_ORDER    1
 #define THREAD_SIZE    (2*PAGE_SIZE)
 
@@ -45,7 +49,7 @@
 typedef struct { unsigned long pmd; } pmd_t;
 typedef struct { unsigned long pgd; } pgd_t;
 typedef struct { unsigned long pml4; } pml4_t;
-#define PTE_MASK	PAGE_MASK
+#define PTE_MASK	PHYSICAL_PAGE_MASK
 
 typedef struct { unsigned long pgprot; } pgprot_t;
 
@@ -74,8 +78,6 @@
 #ifndef __ASSEMBLY__
 
 #include <linux/config.h>
-#include <linux/stringify.h>
-
 
 /*
  * Tell the user there is some problem.  The exception handler decodes this frame.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-x86_64/pci.h linux-2.4.21-pre6/include/asm-x86_64/pci.h
--- linux-2.4.20/include/asm-x86_64/pci.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-x86_64/pci.h	2003-03-26 23:49:55.000000000 +0000
@@ -66,10 +66,11 @@
  * Once the device is given the dma address, the device owns this memory
  * until either pci_unmap_single or pci_dma_sync_single is performed.
  */
-extern dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
-			  size_t size, int direction);
+extern dma_addr_t __pci_map_single(struct pci_dev *hwdev, void *ptr,
+			  size_t size, int direction, int flush);
 
-extern void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t addr,
+
+void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t addr,
 				   size_t size, int direction);
 
 /*
@@ -115,8 +116,8 @@
 
 
 #else
-static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
-					size_t size, int direction)
+static inline dma_addr_t __pci_map_single(struct pci_dev *hwdev, void *ptr,
+					size_t size, int direction, int flush)
 {
 	dma_addr_t addr; 
 
@@ -203,6 +204,11 @@
 extern void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
 			 int nents, int direction);
 
+static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
+			  size_t size, int direction)
+{
+	return __pci_map_single(hwdev,ptr,size,direction,1); 
+}
 
 #define pci_unmap_page pci_unmap_single
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-x86_64/pda.h linux-2.4.21-pre6/include/asm-x86_64/pda.h
--- linux-2.4.20/include/asm-x86_64/pda.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-x86_64/pda.h	2003-03-26 23:49:50.000000000 +0000
@@ -1,10 +1,6 @@
 #ifndef X86_64_PDA_H
 #define X86_64_PDA_H
 
-#include <linux/stddef.h>
-#ifndef ASM_OFFSET_H
-#include <asm/offset.h>
-#endif
 #include <linux/cache.h>
 
 /* Per processor datastructure. %gs points to it while the kernel runs */ 
@@ -38,18 +34,16 @@
  */ 
 #define sizeof_field(type,field)  (sizeof(((type *)0)->field))
 #define typeof_field(type,field)  typeof(((type *)0)->field)
-#ifndef __STR
-#define __STR(x) #x
-#endif
-#define __STR2(x) __STR(x) 
 
 extern void __bad_pda_field(void);
+/* Don't use offsetof because it requires too much infrastructure */
+#define pda_offset(field) ((unsigned long)&((struct x8664_pda *)0)->field)
 
 #define pda_to_op(op,field,val) do { \
        switch (sizeof_field(struct x8664_pda, field)) { 		\
-       case 2: asm volatile(op "w %0,%%gs:" __STR2(pda_ ## field) ::"r" (val):"memory"); break;	\
-       case 4: asm volatile(op "l %0,%%gs:" __STR2(pda_ ## field) ::"r" (val):"memory"); break;	\
-       case 8: asm volatile(op "q %0,%%gs:" __STR2(pda_ ## field) ::"r" (val):"memory"); break;	\
+       case 2: asm volatile(op "w %0,%%gs:%c1" :: "r" (val), "i"(pda_offset(field)):"memory"); break;	\
+       case 4: asm volatile(op "l %0,%%gs:%c1" :: "r" (val), "i"(pda_offset(field)):"memory"); break;	\
+       case 8: asm volatile(op "q %0,%%gs:%c1" :: "r" (val), "i"(pda_offset(field)):"memory"); break;	\
        default: __bad_pda_field(); 					\
        } \
        } while (0)
@@ -58,9 +52,9 @@
 #define pda_from_op(op,field) ({ \
        typedef typeof_field(struct x8664_pda, field) T__; T__ ret__; \
        switch (sizeof_field(struct x8664_pda, field)) { 		\
-       case 2: asm volatile(op "w %%gs:" __STR2(pda_ ## field) ",%0":"=r" (ret__)::"memory"); break;	\
-       case 4: asm volatile(op "l %%gs:" __STR2(pda_ ## field) ",%0":"=r" (ret__)::"memory"); break;	\
-       case 8: asm volatile(op "q %%gs:" __STR2(pda_ ## field) ",%0":"=r" (ret__)::"memory"); break;	\
+       case 2: asm volatile(op "w %%gs:%c1,%0":"=r" (ret__): "i" (pda_offset(field)):"memory"); break;	\
+       case 4: asm volatile(op "l %%gs:%c1,%0":"=r" (ret__): "i" (pda_offset(field)):"memory"); break;	\
+       case 8: asm volatile(op "q %%gs:%c1,%0":"=r" (ret__): "i" (pda_offset(field)):"memory"); break;	\
        default: __bad_pda_field(); 					\
        } \
        ret__; })
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-x86_64/pgtable.h linux-2.4.21-pre6/include/asm-x86_64/pgtable.h
--- linux-2.4.20/include/asm-x86_64/pgtable.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-x86_64/pgtable.h	2003-03-26 23:49:35.000000000 +0000
@@ -156,12 +156,12 @@
 /* Find an entry in the second-level page table.. */
 #define pmd_offset(dir, address) ((pmd_t *) pgd_page(*(dir)) + \
 			__pmd_offset(address))
-#define __mk_pmd(address,prot) ((pmd_t) { (address) | pgprot_val(prot) })
+#define __mk_pmd(address,prot) ((pmd_t) { ((address) | pgprot_val(prot)) & __supported_pte_mask})
 
 #define ptep_get_and_clear(xp)	__pte(xchg(&(xp)->pte, 0))
 #define pte_same(a, b)		((a).pte == (b).pte)
-#define __mk_pte(page_nr,pgprot) __pte(((page_nr) << PAGE_SHIFT) | pgprot_val(pgprot))
-
+#define __mk_pte(page_nr,pgprot) \
+	__pte(((page_nr) << PAGE_SHIFT) | (pgprot_val(pgprot) & __supported_pte_mask))
 #define PML4_SIZE	(1UL << PML4_SHIFT)
 #define PML4_MASK	(~(PML4_SIZE-1))
 #define PMD_SIZE	(1UL << PMD_SHIFT)
@@ -230,13 +230,20 @@
 
 #define PAGE_NONE	__pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED)
 #define PAGE_SHARED	__pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED)
-#define PAGE_COPY	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
-#define PAGE_READONLY	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
+#define PAGE_SHARED_NOEXEC	__pgprot(_PAGE_NX | _PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED)
+#define PAGE_COPY	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_NX)
+
+#define PAGE_COPY_EXEC  \
+	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
+#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_NX)
+#define PAGE_READONLY_EXEC \
+	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
+#define PAGE_EXECONLY PAGE_READONLY_EXEC
 
 #define PAGE_LARGE (_PAGE_PSE|_PAGE_PRESENT) 
 
 #define __PAGE_KERNEL \
-	(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
+	(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_NX)
 #define __PAGE_KERNEL_NOCACHE   (__PAGE_KERNEL | _PAGE_PCD)
 #define __PAGE_KERNEL_RO        (__PAGE_KERNEL & ~_PAGE_RW)
 #define __PAGE_KERNEL_VSYSCALL	(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
@@ -249,32 +256,34 @@
 extern unsigned long __supported_pte_mask; 
 #define __PTE_SUPP(x) __pgprot((x) & __supported_pte_mask)
 
-#define PAGE_KERNEL __PTE_SUPP((__PAGE_KERNEL|_PAGE_GLOBAL) )
-#define PAGE_KERNEL_RO __PTE_SUPP(__PAGE_KERNEL_RO|_PAGE_GLOBAL)
-#define PAGE_KERNEL_NOCACHE __PTE_SUPP(__PAGE_KERNEL_NOCACHE|_PAGE_GLOBAL)
-#define PAGE_KERNEL_VSYSCALL __PTE_SUPP(__PAGE_KERNEL_VSYSCALL|_PAGE_GLOBAL)
-#define PAGE_KERNEL_LARGE __PTE_SUPP(__PAGE_KERNEL_LARGE|_PAGE_GLOBAL)
-#define PAGE_KERNEL_LARGE_NOCACHE __PTE_SUPP(__PAGE_KERNEL_LARGE_NOCACHE|_PAGE_GLOBAL)
-#define PAGE_USER_NOCACHE_RO __PTE_SUPP(__PAGE_USER_NOCACHE_RO|_PAGE_GLOBAL)
-#define PAGE_KERNEL_EXECUTABLE __PTE_SUPP(__PAGE_KERNEL_EXECUTABLE|_PAGE_GLOBAL)
+/* _NX is masked away in mk_pmd/pte */
+
+#define PAGE_KERNEL __PTE_SUPP(__PAGE_KERNEL|_PAGE_GLOBAL)
+#define PAGE_KERNEL_RO __pgprot(__PAGE_KERNEL_RO|_PAGE_GLOBAL)
+#define PAGE_KERNEL_NOCACHE __pgprot(__PAGE_KERNEL_NOCACHE|_PAGE_GLOBAL)
+#define PAGE_KERNEL_VSYSCALL __pgprot(__PAGE_KERNEL_VSYSCALL|_PAGE_GLOBAL)
+#define PAGE_KERNEL_LARGE __pgprot(__PAGE_KERNEL_LARGE|_PAGE_GLOBAL)
+#define PAGE_KERNEL_LARGE_NOCACHE __pgprot(__PAGE_KERNEL_LARGE_NOCACHE|_PAGE_GLOBAL)
+#define PAGE_USER_NOCACHE_RO __pgprot(__PAGE_USER_NOCACHE_RO|_PAGE_GLOBAL)
+#define PAGE_KERNEL_EXECUTABLE __pgprot(__PAGE_KERNEL_EXECUTABLE|_PAGE_GLOBAL)
 
 /*         xwr */
 #define __P000	PAGE_NONE
 #define __P001	PAGE_READONLY
 #define __P010	PAGE_COPY
 #define __P011	PAGE_COPY
-#define __P100	PAGE_READONLY
-#define __P101	PAGE_READONLY
-#define __P110	PAGE_COPY
-#define __P111	PAGE_COPY
+#define __P100	PAGE_EXECONLY
+#define __P101	PAGE_READONLY_EXEC
+#define __P110	PAGE_COPY_EXEC
+#define __P111	PAGE_COPY_EXEC
 
 /*         xwr */
 #define __S000	PAGE_NONE
 #define __S001	PAGE_READONLY
-#define __S010	PAGE_SHARED
-#define __S011	PAGE_SHARED
-#define __S100	PAGE_READONLY
-#define __S101	PAGE_READONLY
+#define __S010	PAGE_SHARED_NOEXEC
+#define __S011	PAGE_SHARED_NOEXEC
+#define __S100	PAGE_EXECONLY
+#define __S101	PAGE_READONLY_EXEC
 #define __S110	PAGE_SHARED
 #define __S111	PAGE_SHARED
 
@@ -342,6 +351,7 @@
 	pte_t __pte; 								 \
 	unsigned long __val = page_to_phys(page);  			 \
 	__val |= pgprot_val(pgprot);						 \
+	__val &= __supported_pte_mask;						\
  	set_pte(&__pte, __pte(__val));						 \
  	__pte;									 \
 }) 
@@ -350,13 +360,15 @@
 static inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
 { 
 	pte_t __pte; 
-	set_pte(&__pte, __pte(physpage + pgprot_val(pgprot))); 
+	set_pte(&__pte, __pte(physpage + (pgprot_val(pgprot) & __supported_pte_mask))); 
 	return __pte;
 }
 
 extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 { 
-	set_pte(&pte, __pte((pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot))); 
+	set_pte(&pte, 
+		__pte(((pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot))  &
+		      __supported_pte_mask));
 	return pte; 
 }
 
@@ -376,7 +388,7 @@
    Other CPUs get synced lazily via the page fault handler. */
 #define pgd_offset_k(address) \
 	__pgd_offset_k( \
-       (pgd_t *)__va(pml4_val(init_level4_pgt[pml4_index(address)]) & PAGE_MASK), address)
+       (pgd_t *)__va(pml4_val(init_level4_pgt[pml4_index(address)]) & PHYSICAL_PAGE_MASK), address)
 
 #define __pmd_offset(address) \
 		(((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1))
@@ -388,12 +400,12 @@
 			__pte_offset(address))
 
 /* never use these in the common code */
-#define pml4_page(level4) ((unsigned long) __va(pml4_val(level4) & PAGE_MASK))
+#define pml4_page(level4) ((unsigned long) __va(pml4_val(level4) & PHYSICAL_PAGE_MASK))
 #define pml4_index(address) (((address) >> PML4_SHIFT) & (PTRS_PER_PML4-1))
 #define pml4_offset_k(address) ((pml4_t *)read_pda(level4_pgt) + pml4_index(address))
 #define level3_offset_k(dir, address) ((pgd_t *) pml4_page(*(dir)) + pgd_index(address))
 #define mk_kernel_pml4(address,prot) ((pml4_t){(address) | pgprot_val(prot)})
-
+#define pml4_present(pml4) (pml4_val(pml4) & _PAGE_PRESENT)
 
 /*
  * x86 doesn't have any external MMU info: the kernel page
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-x86_64/processor.h linux-2.4.21-pre6/include/asm-x86_64/processor.h
--- linux-2.4.20/include/asm-x86_64/processor.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-x86_64/processor.h	2003-03-26 23:49:55.000000000 +0000
@@ -51,6 +51,8 @@
 				    call  */
 	int	x86_clflush_size;
 	int	x86_tlbsize;	/* number of 4K pages in DTLB/ITLB combined(in pages)*/
+        __u8    x86_virt_bits, x86_phys_bits;
+        __u32   x86_power; 
 	unsigned long loops_per_jiffy;
 } ____cacheline_aligned;
 
@@ -256,7 +258,7 @@
 /* This decides where the kernel will search for a free chunk of vm
  * space during mmap's.
  */
-#define TASK_UNMAPPED_32 0x40000000
+#define TASK_UNMAPPED_32 0xa0000000
 #define TASK_UNMAPPED_64 (TASK_SIZE/3) 
 #define TASK_UNMAPPED_BASE	\
 	((current->thread.flags & THREAD_IA32) ? TASK_UNMAPPED_32 : TASK_UNMAPPED_64)  
@@ -302,7 +304,7 @@
 	u16 reserved5;
 	u16 io_map_base;
 	u32 io_bitmap[IO_BITMAP_SIZE];
-} __attribute__((packed));
+} __attribute__((packed)) ____cacheline_aligned;
 
 struct thread_struct {
 	unsigned long	rsp0;
@@ -335,10 +337,13 @@
 #define NMI_STACK 3 
 #define N_EXCEPTION_STACKS 3  /* hw limit: 7 */
 #define EXCEPTION_STKSZ 1024
+#define EXCEPTION_STK_ORDER 0
+
+extern void load_gs_index(unsigned);
 
 #define start_thread(regs,new_rip,new_rsp) do { \
-	__asm__("movl %0,%%fs; movl %0,%%es; movl %0,%%ds": :"r" (0));		 \
-	wrmsrl(MSR_KERNEL_GS_BASE, 0);						 \
+	asm volatile("movl %0,%%fs; movl %0,%%es; movl %0,%%ds": :"r" (0));	 \
+	load_gs_index(0);							\
 	(regs)->rip = (new_rip);						 \
 	(regs)->rsp = (new_rsp);						 \
 	write_pda(oldrsp, (new_rsp));						 \
@@ -393,6 +398,13 @@
 	__asm__ __volatile__("rep;nop");
 }
 
+/* Avoid speculative execution by the CPU */
+extern inline void sync_core(void)
+{ 
+	int tmp;
+	asm volatile("cpuid" : "=a" (tmp) : "0" (1) : "ebx","ecx","edx","memory");
+} 
+
 #define cpu_has_fpu 1
 
 #define ARCH_HAS_PREFETCH
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-x86_64/proto.h linux-2.4.21-pre6/include/asm-x86_64/proto.h
--- linux-2.4.20/include/asm-x86_64/proto.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-x86_64/proto.h	2003-03-26 23:48:59.000000000 +0000
@@ -34,9 +34,10 @@
 extern void reserve_bootmem_generic(unsigned long phys, unsigned len);
 extern void free_bootmem_generic(unsigned long phys, unsigned len);
 
-extern unsigned long start_pfn, end_pfn; 
+extern unsigned long start_pfn, end_pfn, end_pfn_map; 
 
 extern void show_stack(unsigned long * rsp);
+extern void show_trace(unsigned long *stack);
 
 #define round_up(x,y) (((x) + (y) - 1) & ~((y)-1))
 #define round_down(x,y) ((x) & ~((y)-1))
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-x86_64/rwsem.h linux-2.4.21-pre6/include/asm-x86_64/rwsem.h
--- linux-2.4.20/include/asm-x86_64/rwsem.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-x86_64/rwsem.h	2003-03-26 23:48:59.000000000 +0000
@@ -5,7 +5,6 @@
  *
  * Derived from asm-i386/semaphore.h and asm-i386/rwsem.h
  *
- * Trylock by Brian Watson (Brian.J.Watson@compaq.com).
  *
  * The MSW of the count is the negated number of active writers and waiting
  * lockers, and the LSW is the total number of active locks
@@ -114,30 +113,6 @@
 		: "memory", "cc");
 }
 
-
-/*
- * trylock for reading -- returns 1 if successful, 0 if contention
- */
-static inline int __down_read_trylock(struct rw_semaphore *sem)
-{
-	__s32 result, tmp;
-	__asm__ __volatile__(
-		"# beginning __down_read_trylock\n\t"
-		"  movl      %0,%1\n\t"
-		"1:\n\t"
-		"  movl	     %1,%2\n\t"
-		"  addl      %3,%2\n\t"
-		"  jle	     2f\n\t"
-LOCK_PREFIX	"  cmpxchgl  %2,%0\n\t"
-		"  jnz	     1b\n\t"
-		"2:\n\t"
-		"# ending __down_read_trylock\n\t"
-		: "+m"(sem->count), "=&a"(result), "=&r"(tmp)
-		: "i"(RWSEM_ACTIVE_READ_BIAS)
-		: "memory", "cc");
-	return result>=0 ? 1 : 0;
-}
-
 /*
  * lock for writing
  */
@@ -164,19 +139,6 @@
 }
 
 /*
- * trylock for writing -- returns 1 if successful, 0 if contention
- */
-static inline int __down_write_trylock(struct rw_semaphore *sem)
-{
-	signed long ret = cmpxchg(&sem->count,
-				  RWSEM_UNLOCKED_VALUE, 
-				  RWSEM_ACTIVE_WRITE_BIAS);
-	if (ret == RWSEM_UNLOCKED_VALUE)
-		return 1;
-	return 0;
-}
-
-/*
  * unlock after reading
  */
 static inline void __up_read(struct rw_semaphore *sem)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-x86_64/scatterlist.h linux-2.4.21-pre6/include/asm-x86_64/scatterlist.h
--- linux-2.4.20/include/asm-x86_64/scatterlist.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-x86_64/scatterlist.h	2003-03-26 23:48:59.000000000 +0000
@@ -1,32 +1,14 @@
 #ifndef _X8664_SCATTERLIST_H
 #define _X8664_SCATTERLIST_H
 
-/*
- * Drivers must set either ->address or (preferred) ->page and ->offset
- * to indicate where data must be transferred to/from.
- *
- * Using ->page is recommended since it handles highmem data as well as
- * low mem. ->address is restricted to data which has a virtual mapping, and
- * it will go away in the future. Updating to ->page can be automated very
- * easily -- something like
- *
- * sg->address = some_ptr;
- *
- * can be rewritten as
- *
- * sg->page = virt_to_page(some_ptr);
- * sg->offset = (unsigned long) some_ptr & ~PAGE_MASK;
- *
- * and that's it. There's no excuse for not highmem enabling YOUR driver. /jens
- */
 struct scatterlist {
     char *  address;    /* Location data is to be transferred to, NULL for
 			 * highmem page */
     struct page * page; /* Location for highmem page, if any */
     unsigned int offset;/* for highmem, page offset */
 
-    dma_addr_t dma_address;
     unsigned int length;
+    dma_addr_t dma_address;
 };
 
 #define ISA_DMA_THRESHOLD (0x00ffffff)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-x86_64/segment.h linux-2.4.21-pre6/include/asm-x86_64/segment.h
--- linux-2.4.20/include/asm-x86_64/segment.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-x86_64/segment.h	2003-03-26 23:48:59.000000000 +0000
@@ -9,7 +9,6 @@
 /* 
  * we cannot use the same code segment descriptor for user and kernel
  * even not in the long flat model, because of different DPL /kkeil 
- * The segment offset needs to contain a RPL. Grr. -AK
  * GDT layout to get 64bit syscall right (sysret hardcodes gdt offsets) 
  */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-x86_64/semaphore.h linux-2.4.21-pre6/include/asm-x86_64/semaphore.h
--- linux-2.4.20/include/asm-x86_64/semaphore.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-x86_64/semaphore.h	2003-03-26 23:49:54.000000000 +0000
@@ -124,13 +124,10 @@
 		LOCK "decl %0\n\t"     /* --sem->count */
 		"js 2f\n"
 		"1:\n"
-                ".subsection 1\n" \
-                ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" \
-                "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" \
-                ".endif\n" \
+		LOCK_SECTION_START("")
 		"2:\tcall __down_failed\n\t"
 		"jmp 1b\n"
-		".subsection 0"
+		LOCK_SECTION_END
 		:"=m" (sem->count)
 		:"D" (sem)
 		:"memory");
@@ -154,13 +151,10 @@
 		"js 2f\n\t"
 		"xorl %0,%0\n"
 		"1:\n"
-                ".subsection 1\n" \
-               ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" \
-                "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" \
-                ".endif\n" \
+		LOCK_SECTION_START("")
 		"2:\tcall __down_failed_interruptible\n\t"
 		"jmp 1b\n"
-		".subsection 0"
+		LOCK_SECTION_END
 		:"=a" (result), "=m" (sem->count)
 		:"D" (sem)
 		:"memory");
@@ -185,13 +179,10 @@
 		"js 2f\n\t"
 		"xorl %0,%0\n"
 		"1:\n"
-                ".subsection 1\n" \
-                ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" \
-                "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" \
-                ".endif\n" \
+		LOCK_SECTION_START("")
 		"2:\tcall __down_failed_trylock\n\t"
 		"jmp 1b\n"
-		".subsection 0"
+		LOCK_SECTION_END
 		:"=a" (result), "=m" (sem->count)
 		:"D" (sem)
 		:"memory","cc");
@@ -214,13 +205,10 @@
 		LOCK "incl %0\n\t"     /* ++sem->count */
 		"jle 2f\n"
 		"1:\n"
-                ".subsection 1\n" \
-                ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" \
-                "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" \
-                ".endif\n" \
+		LOCK_SECTION_START("")
 		"2:\tcall __up_wakeup\n\t"
 		"jmp 1b\n"
-		".subsection 0"
+		LOCK_SECTION_END
 		:"=m" (sem->count)
 		:"D" (sem)
 		:"memory");
@@ -228,7 +216,7 @@
 
 static inline int sem_getcount(struct semaphore *sem)
 {
-       return atomic_read(&sem->count);
+	return atomic_read(&sem->count);
 }
 
 #endif /* __KERNEL__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-x86_64/smp.h linux-2.4.21-pre6/include/asm-x86_64/smp.h
--- linux-2.4.20/include/asm-x86_64/smp.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-x86_64/smp.h	2003-03-26 23:49:55.000000000 +0000
@@ -88,6 +88,11 @@
 	return GET_APIC_ID(*(unsigned long *)(APIC_BASE+APIC_ID));
 }
 
+extern int apic_disabled;
+extern int slow_smp_processor_id(void);
+#define safe_smp_processor_id() \
+	(!apic_disabled ? hard_smp_processor_id() : slow_smp_processor_id())
+
 #endif /* !ASSEMBLY */
 
 #define NO_PROC_ID		0xFF		/* No processor magic marker */
@@ -112,5 +117,6 @@
 
 #ifndef CONFIG_SMP
 #define stack_smp_processor_id() 0
+#define safe_smp_processor_id() 0
 #endif
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-x86_64/softirq.h linux-2.4.21-pre6/include/asm-x86_64/softirq.h
--- linux-2.4.20/include/asm-x86_64/softirq.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-x86_64/softirq.h	2003-03-26 23:49:07.000000000 +0000
@@ -32,17 +32,12 @@
 			"cmpl $0, -8(%0);"				\
 			"jnz 2f;"					\
 			"1:;"						\
-									\
-                   ".subsection 1\n" \
-                   ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" \
-                   "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" \
-                   ".endif\n" \
+			LOCK_SECTION_START("") 		\
 			"2:"	\
 			"call do_softirq_thunk;"		\
 			""		\
 			"jmp 1b;"					\
-			".subsection 0;"				\
-									\
+			LOCK_SECTION_END			\
 		: /* no output */					\
 		: "r" (ptr)				\
 		/* no registers clobbered */ );				\
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-x86_64/spinlock.h linux-2.4.21-pre6/include/asm-x86_64/spinlock.h
--- linux-2.4.20/include/asm-x86_64/spinlock.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-x86_64/spinlock.h	2003-03-26 23:49:19.000000000 +0000
@@ -57,13 +57,13 @@
 	"\n1:\t" \
 	"lock ; decb %0\n\t" \
 	"js 2f\n" \
-	".section .text.lock,\"ax\"\n" \
+	LOCK_SECTION_START("") \
 	"2:\t" \
 	"cmpb $0,%0\n\t" \
 	"rep;nop\n\t" \
 	"jle 2b\n\t" \
 	"jmp 1b\n" \
-	".previous"
+	LOCK_SECTION_END
 
 /*
  * This works. Despite all the confusion.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-x86_64/system.h linux-2.4.21-pre6/include/asm-x86_64/system.h
--- linux-2.4.20/include/asm-x86_64/system.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-x86_64/system.h	2003-03-26 23:49:50.000000000 +0000
@@ -21,6 +21,23 @@
 #define __PUSH(x) "pushq %%" __STR(x) "\n\t"
 #define __POP(x)  "popq  %%" __STR(x) "\n\t"
 
+struct save_context_frame { 
+        unsigned long rbp; 
+        unsigned long rbx;
+	unsigned long r11;
+	unsigned long r10;
+	unsigned long r9;
+	unsigned long r8;
+	unsigned long rcx;
+	unsigned long rdx;
+	unsigned long r15;
+	unsigned long r14;
+	unsigned long r13;
+	unsigned long r12;
+	unsigned long rdi;
+	unsigned long rsi;
+};
+
 /* frame pointer must be last for get_wchan */
 #define SAVE_CONTEXT \
 	__PUSH(rsi) __PUSH(rdi) \
@@ -37,11 +54,12 @@
 	asm volatile(SAVE_CONTEXT					\
 		     "movq %%rsp,%0\n\t"	/* save RSP */		\
 		     "movq %3,%%rsp\n\t"	/* restore RSP */	\
-		     "leaq 1f(%%rip),%%rax\n\t"				\
+		     "leaq thread_return(%%rip),%%rax\n\t"		\
 		     "movq %%rax,%1\n\t"	/* save RIP */		\
 		     "pushq %4\n\t"		/* setup new RIP */	\
 		     "jmp __switch_to\n\t"				\
-		     "1:\n\t"						\
+		     ".globl thread_return\n"				\
+		     "thread_return:\n\t"				\
 		     RESTORE_CONTEXT					\
 		     :"=m" (prev->thread.rsp),"=m" (prev->thread.rip), "=a" (l) \
 		     :"m" (next->thread.rsp),"m" (next->thread.rip),	\
@@ -246,8 +264,12 @@
 /* used in the idle loop; sti takes one instruction cycle to complete */
 #define safe_halt()		__asm__ __volatile__("sti; hlt": : :"memory")
 
+#define __save_and_cli(x)      do { __save_flags(x); __cli(); } while(0)
+#define __save_and_sti(x)      do { __save_flags(x); __sti(); } while(0)
+
 /* For spinlocks etc */
 #define local_irq_save(x) 	do { warn_if_not_ulong(x); __asm__ __volatile__("# local_irq_save \n\t pushfq ; popq %0 ; cli":"=g" (x): /* no input */ :"memory"); } while (0)
+#define local_irq_set(x) 	do { warn_if_not_ulong(x); __asm__ __volatile__("# local_irq_set \n\t pushfq ; popq %0 ; sti":"=g" (x): /* no input */ :"memory"); } while (0)
 #define local_irq_restore(x)	__asm__ __volatile__("# local_irq_restore \n\t pushq %0 ; popfq": /* no output */ :"g" (x):"memory")
 #define local_irq_disable()	__cli()
 #define local_irq_enable()	__sti()
@@ -262,6 +284,8 @@
 #define sti() __global_sti()
 #define save_flags(x) ((x)=__global_save_flags())
 #define restore_flags(x) __global_restore_flags(x)
+#define save_and_cli(x) do { save_flags(x); cli(); } while(0);
+#define save_and_sti(x) do { save_flags(x); sti(); } while(0);
 
 #else
 
@@ -269,6 +293,8 @@
 #define sti() __sti()
 #define save_flags(x) __save_flags(x)
 #define restore_flags(x) __restore_flags(x)
+#define save_and_cli(x) __save_and_cli(x)
+#define save_and_sti(x) __save_and_sti(x)
 
 #endif
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-x86_64/timex.h linux-2.4.21-pre6/include/asm-x86_64/timex.h
--- linux-2.4.20/include/asm-x86_64/timex.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-x86_64/timex.h	2003-03-26 23:49:00.000000000 +0000
@@ -10,7 +10,7 @@
 #include <asm/msr.h>
 #include <asm/vsyscall.h>
 
-#define CLOCK_TICK_RATE (hpet.address ? hpet.hz : 1193182L)
+#define CLOCK_TICK_RATE (vxtime_hz)
 #define FINETUNE	((((((long)LATCH * HZ - CLOCK_TICK_RATE) << SHIFT_HZ) * \
 			1000000 / CLOCK_TICK_RATE) << (SHIFT_SCALE - SHIFT_HZ)) / HZ)
 
@@ -61,6 +61,8 @@
 #define HPET_T0_SETVAL		0x040
 #define HPET_T0_32BIT		0x100
 
-extern struct hpet_data hpet;
+extern struct vxtime_data vxtime;
+extern unsigned long vxtime_hz;
+extern unsigned long hpet_address;
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-x86_64/uaccess.h linux-2.4.21-pre6/include/asm-x86_64/uaccess.h
--- linux-2.4.20/include/asm-x86_64/uaccess.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-x86_64/uaccess.h	2003-03-26 23:49:39.000000000 +0000
@@ -71,9 +71,6 @@
 	unsigned long insn, fixup;
 };
 
-/* Returns 0 if exception not found and fixup otherwise.  */
-extern unsigned long search_exception_table(unsigned long);
-
 
 /*
  * These are the main single-value transfer routines.  They automatically
@@ -82,7 +79,7 @@
  * This gets kind of ugly. We want to return _two_ values in "get_user()"
  * and yet we don't want to do any pointers, because that is too much
  * of a performance impact. Thus we have a few rather ugly macros here,
- * and hide all the uglyness from the user.
+ * and hide all the ugliness from the user.
  *
  * The "__xxx" versions of the user access functions are versions that
  * do not verify the address space, that must have been done previously
@@ -103,7 +100,8 @@
 
 /* Careful: we have to cast the result to the type of the pointer for sign reasons */
 #define get_user(x,ptr)							\
-({	long __ret_gu,__val_gu;						\
+({	long __val_gu;							\
+	int __ret_gu; 							\
 	switch(sizeof (*(ptr))) {					\
 	case 1:  __get_user_x(1,__ret_gu,__val_gu,ptr); break;		\
 	case 2:  __get_user_x(2,__ret_gu,__val_gu,ptr); break;		\
@@ -138,7 +136,7 @@
 
 #define __put_user_nocheck(x,ptr,size)			\
 ({							\
-	long __pu_err;					\
+	int __pu_err;					\
 	__put_user_size((x),(ptr),(size),__pu_err);	\
 	__pu_err;					\
 })
@@ -146,7 +144,7 @@
 
 #define __put_user_check(x,ptr,size)			\
 ({							\
-	long __pu_err = -EFAULT;			\
+	int __pu_err = -EFAULT;				\
 	__typeof__(*(ptr)) *__pu_addr = (ptr);		\
 	if (access_ok(VERIFY_WRITE,__pu_addr,size))	\
 		__put_user_size((x),__pu_addr,(size),__pu_err);	\
@@ -157,10 +155,10 @@
 do {									\
 	retval = 0;							\
 	switch (size) {							\
-	  case 1: __put_user_asm(x,ptr,retval,"b","b","iq"); break;	\
-	  case 2: __put_user_asm(x,ptr,retval,"w","w","ir"); break;	\
-	  case 4: __put_user_asm(x,ptr,retval,"l","k","ir"); break;	\
-	  case 8: __put_user_asm(x,ptr,retval,"q","","ir"); break;	\
+	  case 1: __put_user_asm(x,ptr,retval,"b","b","iq",-EFAULT); break;\
+	  case 2: __put_user_asm(x,ptr,retval,"w","w","ir",-EFAULT); break;\
+	  case 4: __put_user_asm(x,ptr,retval,"l","k","ir",-EFAULT); break;\
+	  case 8: __put_user_asm(x,ptr,retval,"q","","ir",-EFAULT); break;\
 	  default: __put_user_bad();					\
 	}								\
 } while (0)
@@ -174,12 +172,12 @@
  * we do not write to any memory gcc knows about, so there are no
  * aliasing issues.
  */
-#define __put_user_asm(x, addr, err, itype, rtype, ltype)	\
+#define __put_user_asm(x, addr, err, itype, rtype, ltype, errno)	\
 	__asm__ __volatile__(				\
 		"1:	mov"itype" %"rtype"1,%2\n"	\
 		"2:\n"							\
 		".section .fixup,\"ax\"\n"		\
-		"3:	movq %3,%0\n"				\
+		"3:	mov %3,%0\n"				\
 		"	jmp 2b\n"					\
 		".previous\n"					\
 		".section __ex_table,\"a\"\n"	\
@@ -187,32 +185,33 @@
 		"	.quad 1b,3b\n"				\
 		".previous"						\
 		: "=r"(err)						\
-		: ltype (x), "m"(__m(addr)), "i"(-EFAULT), "0"(err))
+		: ltype (x), "m"(__m(addr)), "i"(errno), "0"(err))
 
 
 #define __get_user_nocheck(x,ptr,size)				\
 ({								\
-	long __gu_err, __gu_val;				\
+	int __gu_err;						\
+	long __gu_val;						\
 	__get_user_size(__gu_val,(ptr),(size),__gu_err);	\
 	(x) = (__typeof__(*(ptr)))__gu_val;			\
 	__gu_err;						\
 })
 
-extern long __get_user_bad(void);
+extern int __get_user_bad(void);
 
 #define __get_user_size(x,ptr,size,retval)				\
 do {									\
 	retval = 0;							\
 	switch (size) {							\
-	  case 1: __get_user_asm(x,ptr,retval,"b","b","=q"); break;	\
-	  case 2: __get_user_asm(x,ptr,retval,"w","w","=r"); break;	\
-	  case 4: __get_user_asm(x,ptr,retval,"l","k","=r"); break;	\
-	  case 8: __get_user_asm(x,ptr,retval,"q","","=r"); break;	\
+	  case 1: __get_user_asm(x,ptr,retval,"b","b","=q",-EFAULT); break;\
+	  case 2: __get_user_asm(x,ptr,retval,"w","w","=r",-EFAULT); break;\
+	  case 4: __get_user_asm(x,ptr,retval,"l","k","=r",-EFAULT); break;\
+	  case 8: __get_user_asm(x,ptr,retval,"q","","=r",-EFAULT); break;\
 	  default: (x) = __get_user_bad();				\
 	}								\
 } while (0)
 
-#define __get_user_asm(x, addr, err, itype, rtype, ltype)	\
+#define __get_user_asm(x, addr, err, itype, rtype, ltype, errno)	\
 	__asm__ __volatile__(					\
 		"1:	mov"itype" %2,%"rtype"1\n"		\
 		"2:\n"						\
@@ -226,29 +225,85 @@
 		"	.quad 1b,3b\n"				\
 		".previous"					\
 		: "=r"(err), ltype (x)				\
-		: "m"(__m(addr)), "i"(-EFAULT), "0"(err))
+		: "m"(__m(addr)), "i"(errno), "0"(err))
 
 /*
  * Copy To/From Userspace
- * 
- * This relies on an optimized common worker function.
- * 
- * Could do special inline versions for small constant copies, but avoid this
- * for now. It's not clear it is worth it. 
  */
 
+/* Handles exceptions in both to and from, but doesn't do access_ok */
 extern unsigned long copy_user_generic(void *to, const void *from, unsigned len); 
 
 extern unsigned long copy_to_user(void *to, const void *from, unsigned len); 
 extern unsigned long copy_from_user(void *to, const void *from, unsigned len); 
-#define __copy_to_user copy_user_generic
-#define __copy_from_user copy_user_generic
+
+static inline int __copy_from_user(void *dst, const void *src, unsigned size) 
+{ 
+	if (!__builtin_constant_p(size))
+		return copy_user_generic(dst,src,size);
+	int ret = 0; 
+	switch (size) { 
+	case 1:__get_user_asm(*(u8*)dst,(u8 *)src,ret,"b","b","=q",1); 
+		return ret;
+	case 2:__get_user_asm(*(u16*)dst,(u16*)src,ret,"w","w","=r",2);
+		return ret;
+	case 4:__get_user_asm(*(u32*)dst,(u32*)src,ret,"l","k","=r",4);
+		return ret;
+	case 8:__get_user_asm(*(u64*)dst,(u64*)src,ret,"q","","=r",8);
+		return ret; 
+	case 10:
+	       	__get_user_asm(*(u64*)dst,(u64*)src,ret,"q","","=r",16);
+		if (ret) return ret;
+		__get_user_asm(*(u16*)(8+dst),(u16*)(8+src),ret,"w","w","=r",2);
+		return ret; 
+	case 16:
+		__get_user_asm(*(u64*)dst,(u64*)src,ret,"q","","=r",16);
+		if (ret) return ret;
+		__get_user_asm(*(u64*)(8+dst),(u64*)(8+src),ret,"q","","=r",8);
+		return ret; 
+	default:
+		return copy_user_generic(dst,src,size); 
+	}
+}	
+
+static inline int __copy_to_user(void *dst, const void *src, unsigned size) 
+{ 
+	if (!__builtin_constant_p(size))
+		return copy_user_generic(dst,src,size);
+	int ret = 0; 
+	switch (size) { 
+	case 1:__put_user_asm(*(u8*)src,(u8 *)dst,ret,"b","b","iq",1); 
+		return ret;
+	case 2:__put_user_asm(*(u16*)src,(u16*)dst,ret,"w","w","ir",2);
+		return ret;
+	case 4:__put_user_asm(*(u32*)src,(u32*)dst,ret,"l","k","ir",4);
+		return ret;
+	case 8:__put_user_asm(*(u64*)src,(u64*)dst,ret,"q","","ir",8);
+		return ret; 
+	case 10:
+		__put_user_asm(*(u64*)src,(u64*)dst,ret,"q","","ir",10);
+		if (ret) return ret;
+		asm("":::"memory");
+		__put_user_asm(4[(u16*)src],4+(u16*)dst,ret,"w","w","ir",2);
+		return ret; 
+	case 16:
+		__put_user_asm(*(u64*)src,(u64*)dst,ret,"q","","ir",16);
+		if (ret) return ret;
+		asm("":::"memory");
+		__put_user_asm(1[(u64*)src],1+(u64*)dst,ret,"q","","ir",8);
+		return ret; 
+	default:
+		return copy_user_generic(dst,src,size); 
+	}
+}	
 
 long strncpy_from_user(char *dst, const char *src, long count);
 long __strncpy_from_user(char *dst, const char *src, long count);
-#define strlen_user(str) strnlen_user(str, ~0UL >> 1)
 long strnlen_user(const char *str, long n);
+long strlen_user(const char *str);
 unsigned long clear_user(void *mem, unsigned long len);
 unsigned long __clear_user(void *mem, unsigned long len);
 
+extern unsigned long search_exception_table(unsigned long);
+
 #endif /* __X86_64_UACCESS_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-x86_64/unistd.h linux-2.4.21-pre6/include/asm-x86_64/unistd.h
--- linux-2.4.20/include/asm-x86_64/unistd.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-x86_64/unistd.h	2003-03-26 23:49:19.000000000 +0000
@@ -483,8 +483,20 @@
 __SYSCALL(__NR_io_cancel, sys_ni_syscall)
 #define __NR_get_thread_area	211
 __SYSCALL(__NR_get_thread_area, sys_ni_syscall)
+#define __NR_lookup_dcookie     212
+__SYSCALL(__NR_lookup_dcookie, sys_ni_syscall)
+#define __NR_epoll_create       213
+__SYSCALL(__NR_epoll_create, sys_ni_syscall)
+#define __NR_epoll_ctl  214
+__SYSCALL(__NR_epoll_ctl, sys_ni_syscall)
+#define __NR_epoll_wait 215
+__SYSCALL(__NR_epoll_wait, sys_ni_syscall)
+#define __NR_remap_file_pages   216
+__SYSCALL(__NR_remap_file_pages, sys_ni_syscall)
+#define __NR_getdents64 217
+__SYSCALL(__NR_getdents64, sys_getdents64)
 
-#define __NR_syscall_max __NR_get_thread_area
+#define __NR_syscall_max __NR_getdents64
 
 #ifndef __NO_STUBS
 
@@ -549,10 +561,10 @@
 type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
 { \
 long __res; \
-__asm__ volatile ("movq %5,%%r10 ;" __syscall \
+__asm__ volatile ("movq %[a3],%%r10 ;" __syscall \
 	: "=a" (__res) \
 	: "0" (__NR_##name),"D" ((long)(arg1)),"S" ((long)(arg2)), \
-	  "d" ((long)(arg3)),"g" ((long)(arg4)) : __syscall_clobber,"r10" ); \
+	  "d" ((long)(arg3)), [a3] "g" ((long)(arg4)) : __syscall_clobber,"r10" ); \
 __syscall_return(type,__res); \
 } 
 
@@ -561,10 +573,10 @@
 type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
 { \
 long __res; \
-__asm__ volatile ("movq %5,%%r10 ; movq %6,%%r8 ; " __syscall \
+__asm__ volatile ("movq %[a3],%%r10 ; movq %[a4],%%r8 ; " __syscall \
 	: "=a" (__res) \
 	: "0" (__NR_##name),"D" ((long)(arg1)),"S" ((long)(arg2)), \
-	  "d" ((long)(arg3)),"g" ((long)(arg4)),"g" ((long)(arg5)) : \
+	  "d" ((long)(arg3)), [a3] "g" ((long)(arg4)), [a4] "g" ((long)(arg5)) : \
 	__syscall_clobber,"r8","r10" ); \
 __syscall_return(type,__res); \
 }
@@ -574,11 +586,11 @@
 type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \
 { \
 long __res; \
-__asm__ volatile ("movq %5,%%r10 ; movq %6,%%r8 ; movq %7,%%r9" __syscall \
+__asm__ volatile ("movq %[a3],%%r10 ; movq %[a4],%%r8 ; movq %[a5],%%r9" __syscall \
 	: "=a" (__res) \
 	: "0" (__NR_##name),"D" ((long)(arg1)),"S" ((long)(arg2)), \
-	  "d" ((long)(arg3)),"g" ((long)(arg4)),"g" ((long)(arg5), \
-	  "g" ((long)(arg6),) : \
+	  "d" ((long)(arg3)), [a3] "g" ((long)(arg4)), [a4] "g" ((long)(arg5), \
+	  [a5] "g" ((long)(arg6),) : \
 	__syscall_clobber,"r8","r10","r9" ); \
 __syscall_return(type,__res); \
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/asm-x86_64/vsyscall.h linux-2.4.21-pre6/include/asm-x86_64/vsyscall.h
--- linux-2.4.20/include/asm-x86_64/vsyscall.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/asm-x86_64/vsyscall.h	2003-03-26 23:49:25.000000000 +0000
@@ -15,29 +15,30 @@
 
 #ifdef __KERNEL__
 
-#define __section_hpet __attribute__ ((unused, __section__ (".hpet"), aligned(16)))
+#define __section_vxtime __attribute__ ((unused, __section__ (".vxtime"), aligned(16)))
 #define __section_wall_jiffies __attribute__ ((unused, __section__ (".wall_jiffies"), aligned(16)))
 #define __section_jiffies __attribute__ ((unused, __section__ (".jiffies"), aligned(16)))
 #define __section_sys_tz __attribute__ ((unused, __section__ (".sys_tz"), aligned(16)))
 #define __section_xtime __attribute__ ((unused, __section__ (".xtime"), aligned(16)))
 #define __section_vxtime_sequence __attribute__ ((unused, __section__ (".vxtime_sequence"), aligned(16)))
 
-struct hpet_data {
-	long address;		/* base address */
-	unsigned long hz;	/* HPET clocks / sec */
-	int trigger;		/* value at last interrupt */
+struct vxtime_data {
+	long last_tsc;
+	long tsc_quot;
+	long quot;
 	int last;
-	int offset;
-	unsigned long last_tsc;
-	long ticks;
+	int mode;
 };
 
+#define VXTIME_TSC	1
+#define	VXTIME_HPET	2
+
 #define hpet_readl(a)           readl(fix_to_virt(FIX_HPET_BASE) + a)
 #define hpet_writel(d,a)        writel(d, fix_to_virt(FIX_HPET_BASE) + a)
 
 /* vsyscall space (readonly) */
 extern long __vxtime_sequence[2];
-extern struct hpet_data __hpet;
+extern struct vxtime_data __vxtime;
 extern struct timeval __xtime;
 extern volatile unsigned long __jiffies;
 extern unsigned long __wall_jiffies;
@@ -45,7 +46,7 @@
 
 /* kernel space (writeable) */
 extern long vxtime_sequence[2];
-extern struct hpet_data hpet;
+extern struct vxtime_data vxtime;
 extern unsigned long wall_jiffies;
 extern struct timezone sys_tz;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/agp_backend.h linux-2.4.21-pre6/include/linux/agp_backend.h
--- linux-2.4.20/include/linux/agp_backend.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/agp_backend.h	2003-03-26 23:49:19.000000000 +0000
@@ -60,6 +60,8 @@
 	VIA_APOLLO_PRO,
 	VIA_APOLLO_KX133,
 	VIA_APOLLO_KT133,
+	VIA_APOLLO_P4X400,
+	VIA_APOLLO_KT400,
 	SIS_GENERIC,
 	AMD_GENERIC,
 	AMD_IRONGATE,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/atmdev.h linux-2.4.21-pre6/include/linux/atmdev.h
--- linux-2.4.20/include/linux/atmdev.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/atmdev.h	2003-03-26 23:49:20.000000000 +0000
@@ -302,7 +302,6 @@
 	int (*send)(struct atm_vcc *vcc,struct sk_buff *skb);
 	void		*dev_data;	/* per-device data */
 	void		*proto_data;	/* per-protocol data */
-	struct timeval	timestamp;	/* AAL timestamps */
 	struct sk_buff_head recvq;	/* receive queue */
 	struct k_atm_aal_stats *stats;	/* pointer to AAL stats group */
 	wait_queue_head_t sleep;	/* if socket is busy */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/auto_fs.h linux-2.4.21-pre6/include/linux/auto_fs.h
--- linux-2.4.20/include/linux/auto_fs.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/auto_fs.h	2003-03-26 23:48:57.000000000 +0000
@@ -45,7 +45,7 @@
  * If so, 32-bit user-space code should be backwards compatible.
  */
 
-#if defined(__sparc__) || defined(__mips__) || defined(__s390__) || defined(__x86_64__)
+#if !defined(__alpha__) && !defined(__ia64__)   
 typedef unsigned int autofs_wqt_t;
 #else
 typedef unsigned long autofs_wqt_t;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/blkcdb.h linux-2.4.21-pre6/include/linux/blkcdb.h
--- linux-2.4.20/include/linux/blkcdb.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/blkcdb.h	2003-03-26 23:48:57.000000000 +0000
@@ -0,0 +1,101 @@
+/*
+ * 2.5 Command Descriptor Block (CDB) Block Pre-Handler.
+ *
+ * Copyright (C) 2001 Andre Hedrick <andre@linux-ide.org>
+ *
+ * This program is free software; you can redistribute 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 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 Licens
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-
+ */
+
+#ifndef _LINUX_BLKCDB_H
+#define _LINUX_BLKCDB_H
+
+typedef struct cdb_list {
+#if 0
+        unsigned char cdb_0;
+        unsigned char cdb_1;
+        unsigned char cdb_2;
+        unsigned char cdb_3;
+        unsigned char cdb_4;
+        unsigned char cdb_5;
+        unsigned char cdb_6;
+        unsigned char cdb_7;
+        unsigned char cdb_8;
+        unsigned char cdb_9;
+        unsigned char cdb_10;
+        unsigned char cdb_11;
+        unsigned char cdb_12;
+        unsigned char cdb_13;
+        unsigned char cdb_14;
+        unsigned char cdb_15;
+#else
+        unsigned char cdb_regs[16];
+#endif
+} cdb_list_t;
+
+#if 0
+
+typedef cdb_list_t * (queue_proc) (kdev_t dev);
+
+request_queue_t *ide_get_queue (kdev_t dev)
+{
+        ide_hwif_t *hwif = (ide_hwif_t *)blk_dev[MAJOR(dev)].data;
+
+        return &hwif->drives[DEVICE_NR(dev) & 1].queue;
+}
+
+static request_queue_t *sd_find_queue(kdev_t dev)
+{
+        Scsi_Disk *dpnt;
+        int target;
+        target = DEVICE_NR(dev);
+
+        dpnt = &rscsi_disks[target];
+        if (!dpnt)
+                return NULL;    /* No such device */
+        return &dpnt->device->request_queue;
+}
+
+prebuilder:             NULL,
+block_device_operations
+struct block_device {
+
+void do_ide_request(request_queue_t *q)
+
+ide_do_request
+
+typedef cdb_list_t (request_cdb_proc) (request_queue_t *q);
+
+typedef cdb_list_t (request_cdb_proc) (request_queue_t *q);
+typedef void (request_fn_proc) (request_queue_t *q);
+
+srb
+
+switch (SCpnt->request.cmd)
+SCpnt->cmnd[0] = WRITE_6/READ_6;
+SCpnt->cmnd[1] = (SCpnt->device->scsi_level <= SCSI_2) ?
+			((SCpnt->lun << 5) & 0xe0) : 0;
+SCpnt->cmnd[2] = (unsigned char) (block >> 24) & 0xff;
+SCpnt->cmnd[3] = (unsigned char) (block >> 16) & 0xff;
+SCpnt->cmnd[4] = (unsigned char) (block >> 8) & 0xff;
+SCpnt->cmnd[5] = (unsigned char) block & 0xff;
+SCpnt->cmnd[6] = 0;
+SCpnt->cmnd[7] = (unsigned char) (this_count >> 8) & 0xff;
+SCpnt->cmnd[8] = (unsigned char) this_count & 0xff;
+SCpnt->cmnd[9] = 0;
+
+#endif
+
+#endif /* _LINUX_BLKCDB_H */
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/blkdev.h linux-2.4.21-pre6/include/linux/blkdev.h
--- linux-2.4.20/include/linux/blkdev.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/blkdev.h	2003-03-26 23:49:18.000000000 +0000
@@ -140,6 +140,22 @@
 	wait_queue_head_t	wait_for_requests[2];
 };
 
+#define blk_queue_plugged(q)	(q)->plugged
+#define blk_fs_request(rq)	((rq)->cmd == READ || (rq)->cmd == WRITE)
+#define blk_queue_empty(q)	list_empty(&(q)->queue_head)
+
+extern inline int rq_data_dir(struct request *rq)
+{
+	if (rq->cmd == READ)
+		return READ;
+	else if (rq->cmd == WRITE)
+		return WRITE;
+	else {
+		BUG();
+		return -1; /* ahem */
+	}
+}
+
 extern unsigned long blk_max_low_pfn, blk_max_pfn;
 
 #define BLK_BOUNCE_HIGH		(blk_max_low_pfn << PAGE_SHIFT)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/cciss_ioctl.h linux-2.4.21-pre6/include/linux/cciss_ioctl.h
--- linux-2.4.20/include/linux/cciss_ioctl.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/cciss_ioctl.h	2003-03-26 23:49:34.000000000 +0000
@@ -73,10 +73,10 @@
 #define TYPE_MSG				0x01
 
 // Type defs used in the following structs
-#define BYTE __u8
-#define WORD __u16
-#define HWORD __u16
-#define DWORD __u32
+typedef __u8 BYTE;
+typedef __u16 WORD; 
+typedef __u16 HWORD; 
+typedef __u32 DWORD; 
 
 #define CISS_MAX_LUN	16	
 
@@ -169,6 +169,18 @@
   BYTE			   *buf;
 } IOCTL_Command_struct;
 
+#define MAX_KMALLOC_SIZE 128000
+
+typedef struct _BIG_IOCTL_Command_struct {
+  LUNAddr_struct	   LUN_info;
+  RequestBlock_struct      Request;
+  ErrorInfo_struct  	   error_info; 
+  DWORD			   malloc_size; /* < MAX_KMALLOC_SIZE in cciss.c */
+  DWORD			   buf_size;    /* size in bytes of the buf */
+  				        /* < malloc_size * MAXSGENTRIES */
+  BYTE			   *buf;
+} BIG_IOCTL_Command_struct;
+
 typedef struct _LogvolInfo_struct{
    __u32	LunID;
    int		num_opens;  /* number of opens on the logical volume */
@@ -189,7 +201,11 @@
 #define CCISS_GETDRIVVER   _IOR(CCISS_IOC_MAGIC, 9, DriverVer_type)
 #define CCISS_REVALIDVOLS  _IO(CCISS_IOC_MAGIC, 10) /* obsolete */
 #define CCISS_PASSTHRU	   _IOWR(CCISS_IOC_MAGIC, 11, IOCTL_Command_struct)
+#define CCISS_DEREGDISK	   _IO(CCISS_IOC_MAGIC, 12)
+#define CCISS_REGNEWDISK  _IOW(CCISS_IOC_MAGIC, 13, __u64)
+#define CCISS_REGNEWD	   _IO(CCISS_IOC_MAGIC, 14)
+#define CCISS_RESCANDISK   _IO(CCISS_IOC_MAGIC, 16)
 #define CCISS_GETLUNINFO  _IOR(CCISS_IOC_MAGIC, 17, LogvolInfo_struct)
-
+#define CCISS_BIG_PASSTHRU _IOWR(CCISS_IOC_MAGIC, 18, BIG_IOCTL_Command_struct)
 
 #endif  
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/com20020.h linux-2.4.21-pre6/include/linux/com20020.h
--- linux-2.4.20/include/linux/com20020.h	2001-08-12 18:42:31.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/com20020.h	2003-03-26 23:49:07.000000000 +0000
@@ -32,7 +32,7 @@
 void com20020_remove(struct net_device *dev);
 
 /* The number of low I/O ports used by the card. */
-#define ARCNET_TOTAL_SIZE 9
+#define ARCNET_TOTAL_SIZE 8
 
 /* various register addresses */
 #define _INTMASK  (ioaddr+0)	/* writable */
@@ -59,6 +59,8 @@
 
 /* in SETUP register */
 #define PROMISCset	0x10	/* enable RCV_ALL */
+#define P1MODE          0x80    /* enable P1-MODE for Backplane */
+#define SLOWARB         0x01    /* enable Slow Arbitration for >=5Mbps */
 
 /* COM2002x */
 #define SUB_TENTATIVE	0	/* tentative node ID */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/console.h linux-2.4.21-pre6/include/linux/console.h
--- linux-2.4.20/include/linux/console.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/console.h	2003-03-26 23:49:34.000000000 +0000
@@ -90,6 +90,7 @@
 #define CON_PRINTBUFFER	(1)
 #define CON_CONSDEV	(2) /* Last on the command line */
 #define CON_ENABLED	(4)
+#define CON_BOOT	(8) /* Only used for initial boot */
 
 struct console
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/cyclades.h linux-2.4.21-pre6/include/linux/cyclades.h
--- linux-2.4.20/include/linux/cyclades.h	2002-02-25 19:38:13.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/cyclades.h	2003-03-26 23:49:55.000000000 +0000
@@ -514,9 +514,7 @@
     int nports;		/* Number of ports in the card */
     int bus_index;	/* address shift - 0 for ISA, 1 for PCI */
     int	intr_enabled;	/* FW Interrupt flag - 0 disabled, 1 enabled */
-    struct resource *resource;
-    unsigned long res_start;
-    unsigned long res_len;
+    struct pci_dev *pdev;
 #ifdef __KERNEL__
     spinlock_t card_lock;
 #else
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/ethtool.h linux-2.4.21-pre6/include/linux/ethtool.h
--- linux-2.4.20/include/linux/ethtool.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/ethtool.h	2003-03-26 23:49:19.000000000 +0000
@@ -2,7 +2,7 @@
  * ethtool.h: Defines for Linux ethtool.
  *
  * Copyright (C) 1998 David S. Miller (davem@redhat.com)
- * Copyright 2001 Jeff Garzik <jgarzik@mandrakesoft.com>
+ * Copyright 2001 Jeff Garzik <jgarzik@pobox.com>
  * Portions Copyright 2001 Sun Microsystems (thockin@sun.com)
  * Portions Copyright 2002 Intel (eli.kupermann@intel.com,
  *                                christopher.leech@intel.com,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/ext2_fs.h linux-2.4.21-pre6/include/linux/ext2_fs.h
--- linux-2.4.20/include/linux/ext2_fs.h	2001-11-22 19:46:52.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/ext2_fs.h	2003-03-26 23:49:07.000000000 +0000
@@ -587,6 +587,7 @@
 extern int ext2_sync_inode (struct inode *);
 extern void ext2_discard_prealloc (struct inode *);
 extern void ext2_truncate (struct inode *);
+extern void ext2_set_inode_flags(struct inode *inode);
 
 /* ioctl.c */
 extern int ext2_ioctl (struct inode *, struct file *, unsigned int,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/ext3_fs.h linux-2.4.21-pre6/include/linux/ext3_fs.h
--- linux-2.4.20/include/linux/ext3_fs.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/ext3_fs.h	2003-03-26 23:48:58.000000000 +0000
@@ -622,7 +622,7 @@
 /* ialloc.c */
 extern struct inode * ext3_new_inode (handle_t *, const struct inode *, int);
 extern void ext3_free_inode (handle_t *, struct inode *);
-extern struct inode * ext3_orphan_get (struct super_block *, ino_t);
+extern struct inode * ext3_orphan_get (struct super_block *, unsigned long);
 extern unsigned long ext3_count_free_inodes (struct super_block *);
 extern void ext3_check_inodes_bitmap (struct super_block *);
 extern unsigned long ext3_count_free (struct buffer_head *, unsigned);
@@ -642,6 +642,7 @@
 extern void ext3_dirty_inode(struct inode *);
 extern int ext3_change_inode_journal_flag(struct inode *, int);
 extern void ext3_truncate (struct inode *);
+extern void ext3_set_inode_flags(struct inode *);
 
 /* ioctl.c */
 extern int ext3_ioctl (struct inode *, struct file *, unsigned int,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/ext3_jbd.h linux-2.4.21-pre6/include/linux/ext3_jbd.h
--- linux-2.4.20/include/linux/ext3_jbd.h	2001-12-21 17:42:03.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/ext3_jbd.h	2003-03-26 23:49:05.000000000 +0000
@@ -28,7 +28,7 @@
  * indirection blocks, the group and superblock summaries, and the data
  * block to complete the transaction.  */
 
-#define EXT3_SINGLEDATA_TRANS_BLOCKS	8
+#define EXT3_SINGLEDATA_TRANS_BLOCKS	8U
 
 /* Define the minimum size for a transaction which modifies data.  This
  * needs to take into account the fact that we may end up modifying two
@@ -52,7 +52,7 @@
  * start off at the maximum transaction size and grow the transaction
  * optimistically as we go. */
 
-#define EXT3_MAX_TRANS_DATA		64
+#define EXT3_MAX_TRANS_DATA		64U
 
 /* We break up a large truncate or write transaction once the handle's
  * buffer credits gets this low, we need either to extend the
@@ -61,7 +61,7 @@
  * one block, plus two quota updates.  Quota allocations are not
  * needed. */
 
-#define EXT3_RESERVE_TRANS_BLOCKS	12
+#define EXT3_RESERVE_TRANS_BLOCKS	12U
 
 int
 ext3_mark_iloc_dirty(handle_t *handle, 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/fs.h linux-2.4.21-pre6/include/linux/fs.h
--- linux-2.4.20/include/linux/fs.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/fs.h	2003-03-26 23:49:19.000000000 +0000
@@ -219,6 +219,7 @@
 	BH_Async,	/* 1 if the buffer is under end_buffer_io_async I/O */
 	BH_Wait_IO,	/* 1 if we should write out this buffer */
 	BH_Launder,	/* 1 if we can throttle on this buffer */
+	BH_Attached,	/* 1 if b_inode_buffers is linked into a list */
 	BH_JBD,		/* 1 if it has an attached journal_head */
 
 	BH_PrivateStart,/* not a state bit, but the first bit available
@@ -266,7 +267,6 @@
 	unsigned long b_rsector;	/* Real buffer location on disk */
 	wait_queue_head_t b_wait;
 
-	struct inode *	     b_inode;
 	struct list_head     b_inode_buffers;	/* doubly linked list of inode dirty buffers */
 };
 
@@ -396,6 +396,7 @@
 	int (*releasepage) (struct page *, int);
 #define KERNEL_HAS_O_DIRECT /* this is for modules out of the kernel */
 	int (*direct_IO)(int, struct inode *, struct kiobuf *, unsigned long, int);
+	void (*removepage)(struct page *); /* called when page gets removed from the inode */
 };
 
 struct address_space {
@@ -879,6 +880,9 @@
  * without the big kernel lock held in all filesystems.
  */
 struct super_operations {
+   	struct inode *(*alloc_inode)(struct super_block *sb);
+	void (*destroy_inode)(struct inode *);
+
 	void (*read_inode) (struct inode *);
   
   	/* reiserfs kludge.  reiserfs needs 64 bits of information to
@@ -894,6 +898,7 @@
 	void (*delete_inode) (struct inode *);
 	void (*put_super) (struct super_block *);
 	void (*write_super) (struct super_block *);
+	int (*sync_fs) (struct super_block *);
 	void (*write_super_lockfs) (struct super_block *);
 	void (*unlockfs) (struct super_block *);
 	int (*statfs) (struct super_block *, struct statfs *);
@@ -1170,8 +1175,18 @@
 extern void FASTCALL(__mark_dirty(struct buffer_head *bh));
 extern void FASTCALL(__mark_buffer_dirty(struct buffer_head *bh));
 extern void FASTCALL(mark_buffer_dirty(struct buffer_head *bh));
-extern void FASTCALL(buffer_insert_inode_queue(struct buffer_head *, struct inode *));
-extern void FASTCALL(buffer_insert_inode_data_queue(struct buffer_head *, struct inode *));
+
+extern void FASTCALL(buffer_insert_list(struct buffer_head *, struct list_head *));
+
+static inline void buffer_insert_inode_queue(struct buffer_head *bh, struct inode *inode)
+{
+	buffer_insert_list(bh, &inode->i_dirty_buffers);
+}
+
+static inline void buffer_insert_inode_data_queue(struct buffer_head *bh, struct inode *inode)
+{
+	buffer_insert_list(bh, &inode->i_dirty_data_buffers);
+}
 
 static inline int atomic_set_buffer_dirty(struct buffer_head *bh)
 {
@@ -1186,6 +1201,21 @@
 		clear_bit(BH_Async, &bh->b_state);
 }
 
+static inline void set_buffer_attached(struct buffer_head *bh)
+{
+	set_bit(BH_Attached, &bh->b_state);
+}
+
+static inline void clear_buffer_attached(struct buffer_head *bh)
+{
+	clear_bit(BH_Attached, &bh->b_state);
+}
+
+static inline int buffer_attached(struct buffer_head *bh)
+{
+	return test_bit(BH_Attached, &bh->b_state);
+}
+
 /*
  * If an error happens during the make_request, this function
  * has to be recalled. It marks the buffer as clean and not
@@ -1240,7 +1270,7 @@
 extern int inode_has_buffers(struct inode *);
 extern int filemap_fdatasync(struct address_space *);
 extern int filemap_fdatawait(struct address_space *);
-extern void sync_supers(kdev_t);
+extern void sync_supers(kdev_t dev, int wait);
 extern int bmap(struct inode *, int);
 extern int notify_change(struct dentry *, struct iattr *);
 extern int permission(struct inode *, int);
@@ -1342,6 +1372,7 @@
 #define user_path_walk(name,nd)	 __user_walk(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, nd)
 #define user_path_walk_link(name,nd) __user_walk(name, LOOKUP_POSITIVE, nd)
 
+extern void inode_init_once(struct inode *);
 extern void iput(struct inode *);
 extern void force_delete(struct inode *);
 extern struct inode * igrab(struct inode *);
@@ -1355,18 +1386,7 @@
 }
 
 extern void clear_inode(struct inode *);
-extern struct inode * get_empty_inode(void);
-
-static inline struct inode * new_inode(struct super_block *sb)
-{
-	struct inode *inode = get_empty_inode();
-	if (inode) {
-		inode->i_sb = sb;
-		inode->i_dev = sb->s_dev;
-		inode->i_blkbits = sb->s_blocksize_bits;
-	}
-	return inode;
-}
+extern struct inode *new_inode(struct super_block *sb);
 extern void remove_suid(struct inode *inode);
 
 extern void insert_inode_hash(struct inode *);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/hdlc/ioctl.h linux-2.4.21-pre6/include/linux/hdlc/ioctl.h
--- linux-2.4.20/include/linux/hdlc/ioctl.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/hdlc/ioctl.h	2003-03-26 23:49:40.000000000 +0000
@@ -0,0 +1,55 @@
+#ifndef __HDLC_IOCTL_H__
+#define __HDLC_IOCTL_H__
+
+typedef struct { 
+	unsigned int clock_rate; /* bits per second */
+	unsigned int clock_type; /* internal, external, TX-internal etc. */
+	unsigned short loopback;
+} sync_serial_settings;          /* V.35, V.24, X.21 */
+
+typedef struct { 
+	unsigned int clock_rate; /* bits per second */
+	unsigned int clock_type; /* internal, external, TX-internal etc. */
+	unsigned short loopback;
+	unsigned int slot_map;
+} te1_settings;                  /* T1, E1 */
+
+typedef struct {
+	unsigned short encoding;
+	unsigned short parity;
+} raw_hdlc_proto;
+
+typedef struct {
+	unsigned int t391;
+	unsigned int t392;
+	unsigned int n391;
+	unsigned int n392;
+	unsigned int n393;
+	unsigned short lmi;
+	unsigned short dce; /* 1 for DCE (network side) operation */
+} fr_proto;
+
+typedef struct {
+	unsigned int dlci;
+} fr_proto_pvc;          /* for creating/deleting FR PVCs */
+
+typedef struct {
+    unsigned int interval;
+    unsigned int timeout;
+} cisco_proto;
+
+/* PPP doesn't need any info now - supply length = 0 to ioctl */
+
+union hdlc_settings {
+	raw_hdlc_proto		raw_hdlc;
+	cisco_proto		cisco;
+	fr_proto		fr;
+	fr_proto_pvc		fr_pvc;
+};
+
+union line_settings {
+	sync_serial_settings	sync;
+	te1_settings		te1;
+};
+
+#endif /* __HDLC_IOCTL_H__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/hdlc.h linux-2.4.21-pre6/include/linux/hdlc.h
--- linux-2.4.20/include/linux/hdlc.h	2001-07-26 20:51:45.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/hdlc.h	2003-03-26 23:49:55.000000000 +0000
@@ -1,7 +1,7 @@
 /*
  * Generic HDLC support routines for Linux
  *
- * Copyright (C) 1999, 2000 Krzysztof Halasa <khc@pm.waw.pl>
+ * Copyright (C) 1999-2002 Krzysztof Halasa <khc@pm.waw.pl>
  *
  * 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
@@ -12,64 +12,49 @@
 #ifndef __HDLC_H
 #define __HDLC_H
 
-/* Ioctls - to be changed */
-#define HDLCGSLOTMAP	(0x89F4) /* E1/T1 slot bitmap */
-#define HDLCGCLOCK	(0x89F5) /* clock sources */
-#define HDLCGCLOCKRATE	(0x89F6) /* clock rate */
-#define HDLCGMODE	(0x89F7) /* internal to hdlc.c - protocol used */
-#define HDLCGLINE	(0x89F8) /* physical interface */
-#define HDLCSSLOTMAP	(0x89F9)
-#define HDLCSCLOCK	(0x89FA)
-#define HDLCSCLOCKRATE	(0x89FB)
-#define HDLCSMODE	(0x89FC) /* internal to hdlc.c - select protocol */
-#define HDLCPVC		(0x89FD) /* internal to hdlc.c - create/delete PVC */
-#define HDLCSLINE	(0x89FE)
-#define HDLCRUN		(0x89FF) /* Download firmware and run board */
-
-/* Modes */
-#define MODE_NONE	0x00000000 /* Not initialized */
-#define MODE_DCE	0x00000080 /* DCE */
-#define MODE_HDLC	0x00000100 /* Raw HDLC frames */
-#define MODE_CISCO	0x00000200
-#define MODE_PPP	0x00000400
-#define MODE_FR		0x00000800 /* Any LMI */
-#define MODE_FR_ANSI	0x00000801
-#define MODE_FR_CCITT	0x00000802
-#define MODE_X25	0x00001000
-#define MODE_MASK	0x0000FF00
-#define MODE_SOFT	0x80000000 /* Driver modes, using hardware HDLC */
-
-/* Lines */
-#define LINE_DEFAULT	0x00000000
-#define LINE_V35	0x00000001
-#define LINE_RS232	0x00000002
-#define LINE_X21	0x00000003
-#define LINE_T1		0x00000004
-#define LINE_E1		0x00000005
-#define LINE_MASK	0x000000FF
-#define LINE_LOOPBACK	0x80000000 /* On-card loopback */
-
-#define CLOCK_EXT	0	/* External TX and RX clock - DTE */
-#define CLOCK_INT	1	/* Internal TX and RX clock - DCE */
-#define CLOCK_TXINT	2	/* Internal TX and external RX clock */
-#define CLOCK_TXFROMRX	3	/* TX clock derived from external RX clock */
+#define GENERIC_HDLC_VERSION 4	/* For synchronization with sethdlc utility */
 
+#define CLOCK_DEFAULT   0	/* Default setting */
+#define CLOCK_EXT	1	/* External TX and RX clock - DTE */
+#define CLOCK_INT	2	/* Internal TX and RX clock - DCE */
+#define CLOCK_TXINT	3	/* Internal TX and external RX clock */
+#define CLOCK_TXFROMRX	4	/* TX clock derived from external RX clock */
+
+
+#define ENCODING_DEFAULT	0 /* Default setting */
+#define ENCODING_NRZ		1
+#define ENCODING_NRZI		2
+#define ENCODING_FM_MARK	3
+#define ENCODING_FM_SPACE	4
+#define ENCODING_MANCHESTER	5
+
+
+#define PARITY_DEFAULT		0 /* Default setting */
+#define PARITY_NONE		1 /* No parity */
+#define PARITY_CRC16_PR0	2 /* CRC16, initial value 0x0000 */
+#define PARITY_CRC16_PR1	3 /* CRC16, initial value 0xFFFF */
+#define PARITY_CRC16_PR0_CCITT	4 /* CRC16, initial 0x0000, ITU-T version */
+#define PARITY_CRC16_PR1_CCITT	5 /* CRC16, initial 0xFFFF, ITU-T version */
+#define PARITY_CRC32_PR0_CCITT	6 /* CRC32, initial value 0x00000000 */
+#define PARITY_CRC32_PR1_CCITT	7 /* CRC32, initial value 0xFFFFFFFF */
+
+#define LMI_DEFAULT		0 /* Default setting */
+#define LMI_NONE		1 /* No LMI, all PVCs are static */
+#define LMI_ANSI		2 /* ANSI Annex D */
+#define LMI_CCITT		3 /* ITU-T Annex A */
 
-#define HDLC_MAX_MTU 1500	/* Ethernet 1500 bytes */
-#define HDLC_MAX_MRU (HDLC_MAX_MTU + 10) /* max 10 bytes for FR */
 
 #ifdef __KERNEL__
 
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
 #include <net/syncppp.h>
+#include <linux/hdlc/ioctl.h>
 
-#define MAXLEN_LMISTAT  20	/* max size of status enquiry frame */
+#define HDLC_MAX_MTU 1500	/* Ethernet 1500 bytes */
+#define HDLC_MAX_MRU (HDLC_MAX_MTU + 10) /* max 10 bytes for FR */
 
-#define LINK_STATE_RELIABLE 0x01
-#define LINK_STATE_REQUEST  0x02 /* full stat sent (DCE) / req pending (DTE) */
-#define LINK_STATE_CHANGED  0x04 /* change in PVCs state, send full report */
-#define LINK_STATE_FULLREP_SENT 0x08 /* full report sent */
+#define MAXLEN_LMISTAT  20	/* max size of status enquiry frame */
 
 #define PVC_STATE_NEW       0x01
 #define PVC_STATE_ACTIVE    0x02
@@ -112,6 +97,7 @@
 
 
 typedef struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
 	unsigned ea1  : 1;
 	unsigned cr   : 1;
 	unsigned dlcih: 6;
@@ -121,6 +107,19 @@
 	unsigned becn : 1;
 	unsigned fecn : 1;
 	unsigned dlcil: 4;
+#elif defined (__BIG_ENDIAN_BITFIELD)
+	unsigned dlcih: 6;
+	unsigned cr   : 1;
+	unsigned ea1  : 1;
+  
+	unsigned dlcil: 4;
+	unsigned fecn : 1;
+	unsigned becn : 1;
+	unsigned de   : 1;
+	unsigned ea2  : 1;
+#else
+#error  "Please fix <asm/byteorder.h>"
+#endif
 }__attribute__ ((packed)) fr_hdr;
 
 
@@ -151,63 +150,96 @@
 	struct hdlc_device_struct *master;
 	struct pvc_device_struct *next;
 
-	u8 state;
-	u8 newstate;
+	struct {
+		int active;
+		int new;
+		int deleted;
+		int fecn;
+		int becn;
+	}state;
 }pvc_device;
 
 
 
-typedef struct {
-	u32 last_errors;	/* last errors bit list */
-	int last_poll;		/* ! */
-	u8 T391;		/* ! link integrity verification polling timer */
-	u8 T392;		/* ! polling verification timer */
-	u8 N391;		/* full status polling counter */
-	u8 N392;		/* error threshold */
-	u8 N393;		/* monitored events count */
-	u8 N391cnt;
-
-	u8 state;		/* ! */
-	u32 txseq;		/* ! TX sequence number - Cisco uses 4 bytes */
-	u32 rxseq;		/* ! RX sequence number */
-}fr_lmi;			/* ! means used in Cisco HDLC as well */
-
-
 typedef struct hdlc_device_struct {
-	/* to be initialized by hardware driver: */
+	/* To be initialized by hardware driver */
 	struct net_device netdev; /* master net device - must be first */
 	struct net_device_stats stats;
 
-	struct ppp_device pppdev;
-	struct ppp_device *syncppp_ptr;
+	/* used by HDLC layer to take control over HDLC device from hw driver*/
+	int (*attach)(struct hdlc_device_struct *hdlc,
+		      unsigned short encoding, unsigned short parity);
 
-	/* set_mode may be NULL if HDLC-only board */
-	int (*set_mode)(struct hdlc_device_struct *hdlc, int mode);
-	int (*open)(struct hdlc_device_struct *hdlc);
-	void (*close)(struct hdlc_device_struct *hdlc);
-	int (*xmit)(struct hdlc_device_struct *hdlc, struct sk_buff *skb);
-	int (*ioctl)(struct hdlc_device_struct *hdlc, struct ifreq *ifr,
-		     int cmd);
-  
-	/* Only in "hardware" FR modes etc. - may be NULL */
-	int (*create_pvc)(pvc_device *pvc);
-	void (*destroy_pvc)(pvc_device *pvc);
-	int (*open_pvc)(pvc_device *pvc);
-	void (*close_pvc)(pvc_device *pvc);
-
-	/* for hdlc.c internal use only */
-	pvc_device *first_pvc;
-	u16 pvc_count;
-	int mode;
+	/* hardware driver must handle this instead of dev->hard_start_xmit */
+	int (*xmit)(struct sk_buff *skb, struct net_device *dev);
 
-	struct timer_list timer;
-	fr_lmi lmi;
+
+	/* Things below are for HDLC layer internal use only */
+	int (*ioctl)(struct net_device *dev, struct ifreq *ifr, int cmd);
+	int (*open)(struct hdlc_device_struct *hdlc);
+	void (*stop)(struct hdlc_device_struct *hdlc);
+	void (*proto_detach)(struct hdlc_device_struct *hdlc);
+	void (*netif_rx)(struct sk_buff *skb);
+	int proto;		/* IF_PROTO_HDLC/CISCO/FR/etc. */
+
+	union {
+		struct {
+			fr_proto settings;
+			pvc_device *first_pvc;
+			int pvc_count;
+
+			struct timer_list timer;
+			int last_poll;
+			int reliable;
+			int changed;
+			int request;
+			int fullrep_sent;
+			u32 last_errors; /* last errors bit list */
+			u8 n391cnt;
+			u8 txseq; /* TX sequence number */
+			u8 rxseq; /* RX sequence number */
+		}fr;
+
+		struct {
+			cisco_proto settings;
+
+			struct timer_list timer;
+			int last_poll;
+			int up;
+			u32 txseq; /* TX sequence number */
+			u32 rxseq; /* RX sequence number */
+		}cisco;
+
+		struct {
+			raw_hdlc_proto settings;
+		}raw_hdlc;
+
+		struct {
+			struct ppp_device pppdev;
+			struct ppp_device *syncppp_ptr;
+			int (*old_change_mtu)(struct net_device *dev,
+					      int new_mtu);
+		}ppp;
+	}state;
 }hdlc_device;
 
 
+
+int hdlc_raw_ioctl(hdlc_device *hdlc, struct ifreq *ifr);
+int hdlc_cisco_ioctl(hdlc_device *hdlc, struct ifreq *ifr);
+int hdlc_ppp_ioctl(hdlc_device *hdlc, struct ifreq *ifr);
+int hdlc_fr_ioctl(hdlc_device *hdlc, struct ifreq *ifr);
+int hdlc_x25_ioctl(hdlc_device *hdlc, struct ifreq *ifr);
+
+
+/* Exported from hdlc.o */
+
+/* Called by hardware driver when a user requests HDLC service */
+int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+
+/* Must be used by hardware driver on module startup/exit */
 int register_hdlc_device(hdlc_device *hdlc);
 void unregister_hdlc_device(hdlc_device *hdlc);
-void hdlc_netif_rx(hdlc_device *hdlc, struct sk_buff *skb);
 
 
 static __inline__ struct net_device* hdlc_to_dev(hdlc_device *hdlc)
@@ -246,33 +278,6 @@
 }
 
 
-static __inline__ u16 status_to_dlci(hdlc_device *hdlc, u8 *status, u8 *state)
-{
-	*state &= ~(PVC_STATE_ACTIVE | PVC_STATE_NEW);
-	if (status[2] & 0x08)
-		*state |= PVC_STATE_NEW;
-	else if (status[2] & 0x02)
-		*state |= PVC_STATE_ACTIVE;
-
-	return ((status[0] & 0x3F)<<4) | ((status[1] & 0x78)>>3);
-}
-
-
-static __inline__ void dlci_to_status(hdlc_device *hdlc, u16 dlci, u8 *status,
-				      u8 state)
-{
-	status[0] = (dlci>>4) & 0x3F;
-	status[1] = ((dlci<<3) & 0x78) | 0x80;
-	status[2] = 0x80;
-
-	if (state & PVC_STATE_NEW)
-		status[2] |= 0x08;
-	else if (state & PVC_STATE_ACTIVE)
-		status[2] |= 0x02;
-}
-
-
-
 static __inline__ u16 netdev_dlci(struct net_device *dev)
 {
 	return ntohs(*(u16*)dev->dev_addr);
@@ -282,37 +287,15 @@
 
 static __inline__ u16 q922_to_dlci(u8 *hdr)
 {
-	return ((hdr[0] & 0xFC)<<2) | ((hdr[1] & 0xF0)>>4);
+	return ((hdr[0] & 0xFC) << 2) | ((hdr[1] & 0xF0) >> 4);
 }
 
 
 
 static __inline__ void dlci_to_q922(u8 *hdr, u16 dlci)
 {
-	hdr[0] = (dlci>>2) & 0xFC;
-	hdr[1] = ((dlci<<4) & 0xF0) | 0x01;
-}
-
-
-
-static __inline__ int mode_is(hdlc_device *hdlc, int mask)
-{
-	return (hdlc->mode & mask) == mask;
-}
-
-
-
-static __inline__ pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci)
-{
-	pvc_device *pvc=hdlc->first_pvc;
-	
-	while (pvc) {
-		if (netdev_dlci(&pvc->netdev) == dlci)
-			return pvc;
-		pvc=pvc->next;
-	}
-
-	return NULL;
+	hdr[0] = (dlci >> 2) & 0xFC;
+	hdr[1] = ((dlci << 4) & 0xF0) | 0x01;
 }
 
 
@@ -332,5 +315,35 @@
 }
 
 
+
+/* Must be called by hardware driver when HDLC device is being opened */
+static __inline__ int hdlc_open(hdlc_device *hdlc)
+{
+	if (hdlc->proto == -1)
+		return -ENOSYS;		/* no protocol attached */
+
+	if (hdlc->open)
+		return hdlc->open(hdlc);
+	return 0;
+}
+
+
+/* Must be called by hardware driver when HDLC device is being closed */
+static __inline__ void hdlc_close(hdlc_device *hdlc)
+{
+	if (hdlc->stop)
+		hdlc->stop(hdlc);
+}
+
+
+/* May be used by hardware driver to gain control over HDLC device */
+static __inline__ void hdlc_proto_detach(hdlc_device *hdlc)
+{
+	if (hdlc->proto_detach)
+		hdlc->proto_detach(hdlc);
+	hdlc->proto_detach = NULL;
+}
+
+
 #endif /* __KERNEL */
 #endif /* __HDLC_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/hdreg.h linux-2.4.21-pre6/include/linux/hdreg.h
--- linux-2.4.20/include/linux/hdreg.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/hdreg.h	2003-03-26 23:49:35.000000000 +0000
@@ -34,6 +34,7 @@
 #define ECC_STAT		0x04	/* Corrected error */
 #define DRQ_STAT		0x08
 #define SEEK_STAT		0x10
+#define SRV_STAT		0x10
 #define WRERR_STAT		0x20
 #define READY_STAT		0x40
 #define BUSY_STAT		0x80
@@ -49,6 +50,13 @@
 #define BBD_ERR			0x80	/* pre-EIDE meaning:  block marked bad */
 #define ICRC_ERR		0x80	/* new meaning:  CRC error during transfer */
 
+/* Bits of HD_NSECTOR */
+#define CD			0x01
+#define IO			0x02
+#define REL			0x04
+#define TAG_MASK		0xf8
+
+
 /*
  * Command Header sizes for IOCTL commands
  *	HDIO_DRIVE_CMD, HDIO_DRIVE_TASK, and HDIO_DRIVE_TASKFILE
@@ -61,6 +69,8 @@
 typedef unsigned char task_ioreg_t;
 #endif
 
+typedef unsigned long sata_ioreg_t;
+
 #define HDIO_DRIVE_CMD_HDR_SIZE		4*sizeof(task_ioreg_t)
 #define HDIO_DRIVE_TASK_HDR_SIZE	8*sizeof(task_ioreg_t)
 #define HDIO_DRIVE_HOB_HDR_SIZE		8*sizeof(task_ioreg_t)
@@ -131,8 +141,8 @@
  */
 #define IDE_TASKFILE_STD_OUT_FLAGS	0xFE
 #define IDE_TASKFILE_STD_IN_FLAGS	0xFE
-#define IDE_HOB_STD_OUT_FLAGS		0xC0
-#define IDE_HOB_STD_IN_FLAGS		0xC0
+#define IDE_HOB_STD_OUT_FLAGS		0x3C
+#define IDE_HOB_STD_IN_FLAGS		0x3C
 
 typedef struct ide_task_request_s {
 	task_ioreg_t	io_ports[8];
@@ -177,37 +187,82 @@
 
 /* ATA/ATAPI Commands pre T13 Spec */
 #define WIN_NOP				0x00
+/*
+ *	0x01->0x02 Reserved
+ */
 #define CFA_REQ_EXT_ERROR_CODE		0x03 /* CFA Request Extended Error Code */
+/*
+ *	0x04->0x07 Reserved
+ */
 #define WIN_SRST			0x08 /* ATAPI soft reset command */
 #define WIN_DEVICE_RESET		0x08
-#define WIN_RESTORE			0x10
+/*
+ *	0x09->0x0F Reserved
+ */
+#define WIN_RECAL			0x10
+#define WIN_RESTORE			WIN_RECAL
+/*
+ *	0x10->0x1F Reserved
+ */
 #define WIN_READ			0x20 /* 28-Bit */
+#define WIN_READ_ONCE			0x21 /* 28-Bit without retries */
+#define WIN_READ_LONG			0x22 /* 28-Bit */
+#define WIN_READ_LONG_ONCE		0x23 /* 28-Bit without retries */
 #define WIN_READ_EXT			0x24 /* 48-Bit */
 #define WIN_READDMA_EXT			0x25 /* 48-Bit */
 #define WIN_READDMA_QUEUED_EXT		0x26 /* 48-Bit */
 #define WIN_READ_NATIVE_MAX_EXT		0x27 /* 48-Bit */
+/*
+ *	0x28
+ */
 #define WIN_MULTREAD_EXT		0x29 /* 48-Bit */
+/*
+ *	0x2A->0x2F Reserved
+ */
 #define WIN_WRITE			0x30 /* 28-Bit */
+#define WIN_WRITE_ONCE			0x31 /* 28-Bit without retries */
+#define WIN_WRITE_LONG			0x32 /* 28-Bit */
+#define WIN_WRITE_LONG_ONCE		0x33 /* 28-Bit without retries */
 #define WIN_WRITE_EXT			0x34 /* 48-Bit */
 #define WIN_WRITEDMA_EXT		0x35 /* 48-Bit */
 #define WIN_WRITEDMA_QUEUED_EXT		0x36 /* 48-Bit */
 #define WIN_SET_MAX_EXT			0x37 /* 48-Bit */
 #define CFA_WRITE_SECT_WO_ERASE		0x38 /* CFA Write Sectors without erase */
 #define WIN_MULTWRITE_EXT		0x39 /* 48-Bit */
+/*
+ *	0x3A->0x3B Reserved
+ */
 #define WIN_WRITE_VERIFY		0x3C /* 28-Bit */
+/*
+ *	0x3D->0x3F Reserved
+ */
 #define WIN_VERIFY			0x40 /* 28-Bit - Read Verify Sectors */
+#define WIN_VERIFY_ONCE			0x41 /* 28-Bit - without retries */
 #define WIN_VERIFY_EXT			0x42 /* 48-Bit */
+/*
+ *	0x43->0x4F Reserved
+ */
 #define WIN_FORMAT			0x50
+/*
+ *	0x51->0x5F Reserved
+ */
 #define WIN_INIT			0x60
-#define WIN_SEEK			0x70
+/*
+ *	0x61->0x5F Reserved
+ */
+#define WIN_SEEK			0x70 /* 0x70-0x7F Reserved */
 #define CFA_TRANSLATE_SECTOR		0x87 /* CFA Translate Sector */
 #define WIN_DIAGNOSE			0x90
 #define WIN_SPECIFY			0x91 /* set drive geometry translation */
 #define WIN_DOWNLOAD_MICROCODE		0x92
 #define WIN_STANDBYNOW2			0x94
+#define WIN_STANDBY2			0x96
 #define WIN_SETIDLE2			0x97
 #define WIN_CHECKPOWERMODE2		0x98
 #define WIN_SLEEPNOW2			0x99
+/*
+ *	0x9A VENDOR
+ */
 #define WIN_PACKETCMD			0xA0 /* Send a packet command. */
 #define WIN_PIDENTIFY			0xA1 /* identify ATAPI device	*/
 #define WIN_QUEUED_SERVICE		0xA2
@@ -218,10 +273,15 @@
 #define WIN_SETMULT			0xC6 /* enable/disable multiple mode */
 #define WIN_READDMA_QUEUED		0xC7 /* read sectors using Queued DMA transfers */
 #define WIN_READDMA			0xC8 /* read sectors using DMA transfers */
+#define WIN_READDMA_ONCE		0xC9 /* 28-Bit - without retries */
 #define WIN_WRITEDMA			0xCA /* write sectors using DMA transfers */
+#define WIN_WRITEDMA_ONCE		0xCB /* 28-Bit - without retries */
 #define WIN_WRITEDMA_QUEUED		0xCC /* write sectors using Queued DMA transfers */
 #define CFA_WRITE_MULTI_WO_ERASE	0xCD /* CFA Write multiple without erase */
 #define WIN_GETMEDIASTATUS		0xDA	
+#define WIN_ACKMEDIACHANGE		0xDB /* ATA-1, ATA-2 vendor */
+#define WIN_POSTBOOT			0xDC
+#define WIN_PREBOOT			0xDD
 #define WIN_DOORLOCK			0xDE /* lock door on removable drives */
 #define WIN_DOORUNLOCK			0xDF /* unlock door on removable drives */
 #define WIN_STANDBYNOW1			0xE0
@@ -233,6 +293,8 @@
 #define WIN_SLEEPNOW1			0xE6
 #define WIN_FLUSH_CACHE			0xE7
 #define WIN_WRITE_BUFFER		0xE8 /* force write only 1 sector */
+#define WIN_WRITE_SAME			0xE9 /* read ata-2 to use */
+	/* SET_FEATURES 0x22 or 0xDD */
 #define WIN_FLUSH_CACHE_EXT		0xEA /* 48-Bit */
 #define WIN_IDENTIFY			0xEC /* ask drive to identify itself	*/
 #define WIN_MEDIAEJECT			0xED
@@ -270,7 +332,7 @@
 #define SMART_HCYL_PASS			0xC2
 		
 /* WIN_SETFEATURES sub-commands */
-
+#define SETFEATURES_EN_8BIT	0x01	/* Enable 8-Bit Transfers */
 #define SETFEATURES_EN_WCACHE	0x02	/* Enable write cache */
 #define SETFEATURES_XFER	0x03	/* Set transfer mode */
 #	define XFER_UDMA_7	0x47	/* 0100|0111 */
@@ -295,22 +357,33 @@
 #	define XFER_PIO_SLOW	0x00	/* 0000|0000 */
 #define SETFEATURES_DIS_DEFECT	0x04	/* Disable Defect Management */
 #define SETFEATURES_EN_APM	0x05	/* Enable advanced power management */
+#define SETFEATURES_EN_SAME_R	0x22	/* for a region ATA-1 */
 #define SETFEATURES_DIS_MSN	0x31	/* Disable Media Status Notification */
+#define SETFEATURES_DIS_RETRY	0x33	/* Disable Retry */
 #define SETFEATURES_EN_AAM	0x42	/* Enable Automatic Acoustic Management */
+#define SETFEATURES_RW_LONG	0x44	/* Set Lenght of VS bytes */
+#define SETFEATURES_SET_CACHE	0x54	/* Set Cache segments to SC Reg. Val */
 #define SETFEATURES_DIS_RLA	0x55	/* Disable read look-ahead feature */
 #define SETFEATURES_EN_RI	0x5D	/* Enable release interrupt */
 #define SETFEATURES_EN_SI	0x5E	/* Enable SERVICE interrupt */
 #define SETFEATURES_DIS_RPOD	0x66	/* Disable reverting to power on defaults */
+#define SETFEATURES_DIS_ECC	0x77	/* Disable ECC byte count */
+#define SETFEATURES_DIS_8BIT	0x81	/* Disable 8-Bit Transfers */
 #define SETFEATURES_DIS_WCACHE	0x82	/* Disable write cache */
 #define SETFEATURES_EN_DEFECT	0x84	/* Enable Defect Management */
 #define SETFEATURES_DIS_APM	0x85	/* Disable advanced power management */
+#define SETFEATURES_EN_ECC	0x88	/* Enable ECC byte count */
 #define SETFEATURES_EN_MSN	0x95	/* Enable Media Status Notification */
+#define SETFEATURES_EN_RETRY	0x99	/* Enable Retry */
 #define SETFEATURES_EN_RLA	0xAA	/* Enable read look-ahead feature */
 #define SETFEATURES_PREFETCH	0xAB	/* Sets drive prefetch value */
+#define SETFEATURES_EN_REST	0xAC	/* ATA-1 */
+#define SETFEATURES_4B_RW_LONG	0xBB	/* Set Lenght of 4 bytes */
 #define SETFEATURES_DIS_AAM	0xC2	/* Disable Automatic Acoustic Management */
 #define SETFEATURES_EN_RPOD	0xCC	/* Enable reverting to power on defaults */
-#define SETFEATURES_DIS_RI	0xDD	/* Disable release interrupt */
-#define SETFEATURES_DIS_SI	0xDE	/* Disable SERVICE interrupt */
+#define SETFEATURES_DIS_RI	0xDD	/* Disable release interrupt ATAPI */
+#define SETFEATURES_EN_SAME_M	0xDD	/* for a entire device ATA-1 */
+#define SETFEATURES_DIS_SI	0xDE	/* Disable SERVICE interrupt ATAPI */
 
 /* WIN_SECURITY sub-commands */
 
@@ -341,6 +414,9 @@
 #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_SET_XFER		0x0306	/* set transfer rate via proc */
+
 #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 */
@@ -389,6 +465,9 @@
 #define HDIO_GETGEO_BIG		0x0330	/* */
 #define HDIO_GETGEO_BIG_RAW	0x0331	/* */
 
+#define HDIO_SET_IDE_SCSI	0x0338
+#define HDIO_SET_SCSI_IDE	0x0339
+
 #define __NEW_HD_DRIVE_ID
 /* structure returned by HDIO_GET_IDENTITY,
  * as per ANSI NCITS ATA6 rev.1b spec
@@ -501,7 +580,10 @@
 					 * cmd set-feature supported extensions
 					 * 15:	Shall be ZERO
 					 * 14:	Shall be ONE
-					 * 13:3	reserved
+					 * 13:6	reserved
+					 *  5:	General Purpose Logging
+					 *  4:	Streaming Feature Set
+					 *  3:	Media Card Pass Through
 					 *  2:	Media Serial Number Valid
 					 *  1:	SMART selt-test supported
 					 *  0:	SMART error logging
@@ -548,19 +630,22 @@
 					 * command set-feature default
 					 * 15:	Shall be ZERO
 					 * 14:	Shall be ONE
-					 * 13:3	reserved
+					 * 13:6	reserved
+					 *  5:	General Purpose Logging enabled
+					 *  4:	Valid CONFIGURE STREAM executed
+					 *  3:	Media Card Pass Through enabled
 					 *  2:	Media Serial Number Valid
 					 *  1:	SMART selt-test supported
 					 *  0:	SMART error logging
 					 */
 	unsigned short  dma_ultra;	/* (word 88) */
-	unsigned short	word89;		/* reserved (word 89) */
-	unsigned short	word90;		/* reserved (word 90) */
+	unsigned short	trseuc;		/* time required for security erase */
+	unsigned short	trsEuc;		/* time required for enhanced erase */
 	unsigned short	CurAPMvalues;	/* current APM values */
-	unsigned short	word92;		/* reserved (word 92) */
+	unsigned short	mprc;		/* master password revision code */
 	unsigned short	hw_config;	/* hardware config (word 93)
-					 * 15:
-					 * 14:
+					 * 15:	Shall be ZERO
+					 * 14:	Shall be ONE
 					 * 13:
 					 * 12:
 					 * 11:
@@ -574,18 +659,17 @@
 					 *  3:
 					 *  2:
 					 *  1:
-					 *  0:
+					 *  0:	Shall be ONE
 					 */
 	unsigned short	acoustic;	/* (word 94)
 					 * 15:8	Vendor's recommended value
 					 *  7:0	current value
 					 */
-	unsigned short	words95_99[5];	/* reserved words 95-99 */
-#if 0
-	unsigned short	words100_103[4]	;/* reserved words 100-103 */
-#else
+	unsigned short	msrqs;		/* min stream request size */
+	unsigned short	sxfert;		/* stream transfer time */
+	unsigned short	sal;		/* stream access latency */
+	unsigned int	spg;		/* stream performance granularity */
 	unsigned long long lba_capacity_2;/* 48-bit total number of sectors */
-#endif
 	unsigned short	words104_125[22];/* reserved words 104-125 */
 	unsigned short	last_lun;	/* (word 126) */
 	unsigned short	word127;	/* (word 127) Feature Set
@@ -626,9 +710,9 @@
 					 * 12
 					 * 11:0
 					 */
-	unsigned short	words161_175[14];/* Reserved for CFA */
-	unsigned short	words176_205[31];/* Current Media Serial Number */
-	unsigned short	words206_254[48];/* reserved words 206-254 */
+	unsigned short	words161_175[15];/* Reserved for CFA */
+	unsigned short	words176_205[30];/* Current Media Serial Number */
+	unsigned short	words206_254[49];/* reserved words 206-254 */
 	unsigned short	integrity_word;	/* (word 255)
 					 * 15:8 Checksum
 					 *  7:0 Signature
@@ -654,7 +738,7 @@
 
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
 int ide_register(int io_port, int ctl_port, int irq);
-void ide_unregister(unsigned int);
+int ide_unregister(unsigned int);
 #endif /* CONFIG_BLK_DEV_IDE || CONFIG_BLK_DEV_IDE_MODULE */
 
 #endif  /* __KERNEL__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/highmem.h linux-2.4.21-pre6/include/linux/highmem.h
--- linux-2.4.20/include/linux/highmem.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/highmem.h	2003-03-26 23:49:51.000000000 +0000
@@ -74,6 +74,7 @@
 
 #define bh_kmap(bh)			((bh)->b_data)
 #define bh_kunmap(bh)			do { } while (0)
+#define kmap_nonblock(page)            kmap(page)
 #define bh_kmap_irq(bh, flags)		((bh)->b_data)
 #define bh_kunmap_irq(bh, flags)	do { *(flags) = 0; } while (0)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/i2c-id.h linux-2.4.21-pre6/include/linux/i2c-id.h
--- linux-2.4.20/include/linux/i2c-id.h	2001-10-11 15:05:47.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/i2c-id.h	2003-03-26 23:48:59.000000000 +0000
@@ -90,6 +90,7 @@
 #define I2C_DRIVERID_DRP3510	43     /* ADR decoder (Astra Radio)	*/
 #define I2C_DRIVERID_SP5055	44     /* Satellite tuner		*/
 #define I2C_DRIVERID_STV0030	45     /* Multipurpose switch		*/
+#define I2C_DRIVERID_ADV717X   48     /* video encoder                 */
 
 #define I2C_DRIVERID_EXP0	0xF0	/* experimental use id's	*/
 #define I2C_DRIVERID_EXP1	0xF1
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/ide.h linux-2.4.21-pre6/include/linux/ide.h
--- linux-2.4.20/include/linux/ide.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/ide.h	2003-03-26 23:49:10.000000000 +0000
@@ -3,7 +3,7 @@
 /*
  *  linux/include/linux/ide.h
  *
- *  Copyright (C) 1994-1998  Linus Torvalds & authors
+ *  Copyright (C) 1994-2002  Linus Torvalds & authors
  */
 
 #include <linux/config.h>
@@ -14,7 +14,37 @@
 #include <linux/blkdev.h>
 #include <linux/proc_fs.h>
 #include <linux/devfs_fs_kernel.h>
+#include <linux/interrupt.h>
+#include <linux/bitops.h>
+#include <linux/highmem.h>
+#include <linux/pci.h>
+#include <asm/byteorder.h>
+#include <asm/system.h>
 #include <asm/hdreg.h>
+#include <asm/io.h>
+
+#define CLASSIC_BUILTINS_METHOD				1
+//#undef CLASSIC_BUILTINS_METHOD
+#define HWIF_PROBE_CLASSIC_METHOD			1
+//#undef HWIF_PROBE_CLASSIC_METHOD
+
+#ifdef CLASSIC_BUILTINS_METHOD
+#  undef FAKE_CLASSIC_ATTACH_METHOD
+#  undef DIRECT_HWIF_PROBE_ATTACH_METHOD
+#else /* ! CLASSIC_BUILTINS_METHOD */
+#  ifdef HWIF_PROBE_CLASSIC_METHOD
+#    undef FAKE_CLASSIC_ATTACH_METHOD
+#    undef DIRECT_HWIF_PROBE_ATTACH_METHOD
+#  else /* ! HWIF_PROBE_CLASSIC_METHOD */
+//#    define FAKE_CLASSIC_ATTACH_METHOD			1
+#    undef FAKE_CLASSIC_ATTACH_METHOD
+#    ifdef FAKE_CLASSIC_ATTACH_METHOD
+#      undef DIRECT_HWIF_PROBE_ATTACH_METHOD
+#    else /* ! FAKE_CLASSIC_ATTACH_METHOD */
+#      define DIRECT_HWIF_PROBE_ATTACH_METHOD		1
+#    endif /* FAKE_CLASSIC_ATTACH_METHOD */
+#  endif /* HWIF_PROBE_CLASSIC_METHOD */
+#endif /* CLASSIC_BUILTINS_METHOD */
 
 /*
  * This is the multiple IDE interface driver, as evolved from hd.c.
@@ -63,6 +93,13 @@
 #endif
 
 /*
+ * Used to indicate "no IRQ", should be a value that cannot be an IRQ
+ * number.
+ */
+ 
+#define IDE_NO_IRQ		(-1)
+
+/*
  * IDE_DRIVE_CMD is used to implement many features of the hdparm utility
  */
 #define IDE_DRIVE_CMD			99	/* (magic) undef to reduce kernel size*/
@@ -88,8 +125,17 @@
 #define ERROR_RECAL	1	/* Recalibrate every 2nd retry */
 
 /*
+ * Tune flags
+ */
+#define IDE_TUNE_BIOS		3
+#define IDE_TUNE_NOAUTO		2
+#define IDE_TUNE_AUTO		1
+#define IDE_TUNE_DEFAULT	0
+
+/*
  * state flags
  */
+
 #define DMA_PIO_RETRY	1	/* retrying in PIO */
 
 /*
@@ -160,9 +206,6 @@
 #define IDE_BCOUNTL_REG		IDE_LCYL_REG
 #define IDE_BCOUNTH_REG		IDE_HCYL_REG
 
-#define GET_ERR()		IN_BYTE(IDE_ERROR_REG)
-#define GET_STAT()		IN_BYTE(IDE_STATUS_REG)
-#define GET_ALTSTAT()		IN_BYTE(IDE_CONTROL_REG)
 #define OK_STAT(stat,good,bad)	(((stat)&((good)|(bad)))==(good))
 #define BAD_R_STAT		(BUSY_STAT   | ERR_STAT)
 #define BAD_W_STAT		(BAD_R_STAT  | WRERR_STAT)
@@ -170,6 +213,43 @@
 #define DRIVE_READY		(READY_STAT  | SEEK_STAT)
 #define DATA_READY		(DRQ_STAT)
 
+#define BAD_CRC			(ABRT_ERR    | ICRC_ERR)
+
+#define SATA_NR_PORTS		(3)	/* 16 possible ?? */
+
+#define SATA_STATUS_OFFSET	(0)
+#define SATA_STATUS_REG		(HWIF(drive)->sata_scr[SATA_STATUS_OFFSET])
+#define SATA_ERROR_OFFSET	(1)
+#define SATA_ERROR_REG		(HWIF(drive)->sata_scr[SATA_ERROR_OFFSET])
+#define SATA_CONTROL_OFFSET	(2)
+#define SATA_CONTROL_REG	(HWIF(drive)->sata_scr[SATA_CONTROL_OFFSET])
+
+#define SATA_MISC_OFFSET	(0)
+#define SATA_MISC_REG		(HWIF(drive)->sata_misc[SATA_MISC_OFFSET])
+#define SATA_PHY_OFFSET		(1)
+#define SATA_PHY_REG		(HWIF(drive)->sata_misc[SATA_PHY_OFFSET])
+#define SATA_IEN_OFFSET		(2)
+#define SATA_IEN_REG		(HWIF(drive)->sata_misc[SATA_IEN_OFFSET])
+
+/*
+ * Our Physical Region Descriptor (PRD) table should be large enough
+ * to handle the biggest I/O request we are likely to see.  Since requests
+ * can have no more than 256 sectors, and since the typical blocksize is
+ * two or more sectors, we could get by with a limit of 128 entries here for
+ * the usual worst case.  Most requests seem to include some contiguous blocks,
+ * further reducing the number of table entries required.
+ *
+ * The driver reverts to PIO mode for individual requests that exceed
+ * this limit (possible with 512 byte blocksizes, eg. MSDOS f/s), so handling
+ * 100% of all crazy scenarios here is not necessary.
+ *
+ * As it turns out though, we must allocate a full 4KB page for this,
+ * so the two PRD tables (ide0 & ide1) will each get half of that,
+ * allowing each to have about 256 entries (8 bytes each) from this.
+ */
+#define PRD_BYTES       8
+#define PRD_ENTRIES     (PAGE_SIZE / (2 * PRD_BYTES))
+
 /*
  * Some more useful definitions
  */
@@ -178,21 +258,12 @@
 #define PARTN_BITS	6	/* number of minor dev bits for partitions */
 #define PARTN_MASK	((1<<PARTN_BITS)-1)	/* a useful bit mask */
 #define MAX_DRIVES	2	/* per interface; 2 assumed by lots of code */
-#define CASCADE_DRIVES	8	/* per interface; 8|2 assumed by lots of code */
 #define SECTOR_SIZE	512
 #define SECTOR_WORDS	(SECTOR_SIZE / 4)	/* number of 32bit words per sector */
 #define IDE_LARGE_SEEK(b1,b2,t)	(((b1) > (b2) + (t)) || ((b2) > (b1) + (t)))
 #define IDE_MIN(a,b)	((a)<(b) ? (a):(b))
 #define IDE_MAX(a,b)	((a)>(b) ? (a):(b))
 
-#ifndef SPLIT_WORD
-#  define SPLIT_WORD(W,HB,LB) ((HB)=(W>>8), (LB)=(W-((W>>8)<<8)))
-#endif
-#ifndef MAKE_WORD
-#  define MAKE_WORD(W,HB,LB) ((W)=((HB<<8)+LB))
-#endif
-
-
 /*
  * Timeouts for various operations:
  */
@@ -207,39 +278,6 @@
 #define WAIT_CMD	(10*HZ)	/* 10sec  - maximum wait for an IRQ to happen */
 #define WAIT_MIN_SLEEP	(2*HZ/100)	/* 20msec - minimum sleep time */
 
-#define SELECT_DRIVE(hwif,drive)				\
-{								\
-	if (hwif->selectproc)					\
-		hwif->selectproc(drive);			\
-	OUT_BYTE((drive)->select.all, hwif->io_ports[IDE_SELECT_OFFSET]); \
-}
-
-#define SELECT_INTERRUPT(hwif,drive)				\
-{								\
-	if (hwif->intrproc)					\
-		hwif->intrproc(drive);				\
-	else							\
-		OUT_BYTE((drive)->ctl|2, hwif->io_ports[IDE_CONTROL_OFFSET]);	\
-}
-
-#define SELECT_MASK(hwif,drive,mask)				\
-{								\
-	if (hwif->maskproc)					\
-		hwif->maskproc(drive,mask);			\
-}
-
-#define SELECT_READ_WRITE(hwif,drive,func)			\
-{								\
-	if (hwif->rwproc)					\
-		hwif->rwproc(drive,func);			\
-}
-
-#define QUIRK_LIST(hwif,drive)					\
-{								\
-	if (hwif->quirkproc)					\
-		(drive)->quirk_list = hwif->quirkproc(drive);	\
-}
-
 #define HOST(hwif,chipset)					\
 {								\
 	return ((hwif)->chipset == chipset) ? 1 : 0;		\
@@ -267,7 +305,7 @@
 		ide_qd65xx,	ide_umc8672,	ide_ht6560b,
 		ide_pdc4030,	ide_rz1000,	ide_trm290,
 		ide_cmd646,	ide_cy82c693,	ide_4drives,
-		ide_pmac,	ide_etrax100
+		ide_pmac,	ide_etrax100,	ide_acorn
 } hwif_chipset_t;
 
 /*
@@ -280,6 +318,8 @@
 	ide_ack_intr_t	*ack_intr;		/* acknowledge interrupt */
 	void		*priv;			/* interface specific data */
 	hwif_chipset_t  chipset;
+	sata_ioreg_t	sata_scr[SATA_NR_PORTS];
+	sata_ioreg_t	sata_misc[SATA_NR_PORTS];
 } hw_regs_t;
 
 /*
@@ -296,34 +336,26 @@
 			ide_ioreg_t ctrl,
 			ide_ioreg_t intr,
 			ide_ack_intr_t *ack_intr,
+#if 0
+			ide_io_ops_t *iops,
+#endif
 			int irq);
 
 #include <asm/ide.h>
 
-/*
- * If the arch-dependant ide.h did not declare/define any OUT_BYTE
- * or IN_BYTE functions, we make some defaults here.
- */
-
-#ifndef HAVE_ARCH_OUT_BYTE
-#ifdef REALLY_FAST_IO
-#define OUT_BYTE(b,p)          outb((b),(p))
-#define OUT_WORD(w,p)          outw((w),(p))
+/* Currently only m68k, apus and m8xx need it */
+#ifdef IDE_ARCH_ACK_INTR
+extern int ide_irq_lock;
+# define ide_ack_intr(hwif) (hwif->hw.ack_intr ? hwif->hw.ack_intr(hwif) : 1)
 #else
-#define OUT_BYTE(b,p)          outb_p((b),(p))
-#define OUT_WORD(w,p)          outw_p((w),(p))
-#endif
+# define ide_ack_intr(hwif) (1)
 #endif
 
-#ifndef HAVE_ARCH_IN_BYTE
-#ifdef REALLY_FAST_IO
-#define IN_BYTE(p)             (byte)inb(p)
-#define IN_WORD(p)             (short)inw(p)
-#else
-#define IN_BYTE(p)             (byte)inb_p(p)
-#define IN_WORD(p)             (short)inw_p(p)
-#endif
-#endif
+/* Currently only Atari needs it */
+#ifndef IDE_ARCH_LOCK
+# define ide_release_lock(lock)			do {} while (0)
+# define ide_get_lock(lock, hdlr, data)		do {} while (0)
+#endif /* IDE_ARCH_LOCK */
 
 /*
  * Now for the data we need to maintain per-drive:  ide_drive_t
@@ -336,235 +368,636 @@
 #define ide_tape	0x1
 #define ide_floppy	0x0
 
+/*
+ * Special Driver Flags
+ *
+ * set_geometry	: respecify drive geometry
+ * recalibrate	: seek to cyl 0
+ * set_multmode	: set multmode count
+ * set_tune	: tune interface for drive
+ * serviced	: service command
+ * reserved	: unused
+ */
 typedef union {
-	unsigned all			: 8;	/* all of the bits together */
+	unsigned all			: 8;
 	struct {
-		unsigned set_geometry	: 1;	/* respecify drive geometry */
-		unsigned recalibrate	: 1;	/* seek to cyl 0      */
-		unsigned set_multmode	: 1;	/* set multmode count */
-		unsigned set_tune	: 1;	/* tune interface for drive */
-		unsigned reserved	: 4;	/* unused */
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		unsigned set_geometry	: 1;
+		unsigned recalibrate	: 1;
+		unsigned set_multmode	: 1;
+		unsigned set_tune	: 1;
+		unsigned serviced	: 1;
+		unsigned reserved	: 3;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		unsigned reserved	: 3;
+		unsigned serviced	: 1;
+		unsigned set_tune	: 1;
+		unsigned set_multmode	: 1;
+		unsigned recalibrate	: 1;
+		unsigned set_geometry	: 1;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
 	} b;
 } special_t;
 
+/*
+ * ATA DATA Register Special.
+ * ATA NSECTOR Count Register().
+ * ATAPI Byte Count Register.
+ * Channel index ordering pairs.
+ */
+typedef union {
+	unsigned all			:16;
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		unsigned low		:8;	/* LSB */
+		unsigned high		:8;	/* MSB */
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		unsigned high		:8;	/* MSB */
+		unsigned low		:8;	/* LSB */
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	} b;
+} ata_nsector_t, ata_data_t, atapi_bcount_t, ata_index_t;
+
+/*
+ * ATA-IDE Error Register
+ *
+ * mark		: Bad address mark
+ * tzero	: Couldn't find track 0
+ * abrt		: Aborted Command
+ * mcr		: Media Change Request
+ * id		: ID field not found
+ * mce		: Media Change Event
+ * ecc		: Uncorrectable ECC error
+ * bdd		: dual meaing
+ */
+typedef union {
+	unsigned all			:8;
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		unsigned mark		:1;
+		unsigned tzero		:1;
+		unsigned abrt		:1;
+		unsigned mcr		:1;
+		unsigned id		:1;
+		unsigned mce		:1;
+		unsigned ecc		:1;
+		unsigned bdd		:1;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		unsigned bdd		:1;
+		unsigned ecc		:1;
+		unsigned mce		:1;
+		unsigned id		:1;
+		unsigned mcr		:1;
+		unsigned abrt		:1;
+		unsigned tzero		:1;
+		unsigned mark		:1;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	} b;
+} ata_error_t;
+
+/*
+ * ATA-IDE Select Register, aka Device-Head
+ *
+ * head		: always zeros here
+ * unit		: drive select number: 0/1
+ * bit5		: always 1
+ * lba		: using LBA instead of CHS
+ * bit7		: always 1
+ */
+typedef union {
+	unsigned all			: 8;
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		unsigned head		: 4;
+		unsigned unit		: 1;
+		unsigned bit5		: 1;
+		unsigned lba		: 1;
+		unsigned bit7		: 1;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		unsigned bit7		: 1;
+		unsigned lba		: 1;
+		unsigned bit5		: 1;
+		unsigned unit		: 1;
+		unsigned head		: 4;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	} b;
+} select_t, ata_select_t;
+
+/*
+ * The ATA-IDE Status Register.
+ * The ATAPI Status Register.
+ *
+ * check	: Error occurred
+ * idx		: Index Error
+ * corr		: Correctable error occurred
+ * drq		: Data is request by the device
+ * dsc		: Disk Seek Complete			: ata
+ *		: Media access command finished		: atapi
+ * df		: Device Fault				: ata
+ *		: Reserved				: atapi
+ * drdy		: Ready, Command Mode Capable		: ata
+ *		: Ignored for ATAPI commands		: atapi
+ * bsy		: Disk is Busy
+ *		: The device has access to the command block
+ */
+typedef union {
+	unsigned all			:8;
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		unsigned check		:1;
+		unsigned idx		:1;
+		unsigned corr		:1;
+		unsigned drq		:1;
+		unsigned dsc		:1;
+		unsigned df		:1;
+		unsigned drdy		:1;
+		unsigned bsy		:1;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		unsigned bsy		:1;
+		unsigned drdy		:1;
+		unsigned df		:1;
+		unsigned dsc		:1;
+		unsigned drq		:1;
+		unsigned corr           :1;
+		unsigned idx		:1;
+		unsigned check		:1;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	} b;
+} ata_status_t, atapi_status_t;
+
+/*
+ * ATA-IDE Control Register
+ *
+ * bit0		: Should be set to zero
+ * nIEN		: device INTRQ to host
+ * SRST		: host soft reset bit
+ * bit3		: ATA-2 thingy, Should be set to 1
+ * reserved456	: Reserved
+ * HOB		: 48-bit address ordering, High Ordered Bit
+ */
+typedef union {
+	unsigned all			: 8;
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		unsigned bit0		: 1;
+		unsigned nIEN		: 1;
+		unsigned SRST		: 1;
+		unsigned bit3		: 1;
+		unsigned reserved456	: 3;
+		unsigned HOB		: 1;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		unsigned HOB		: 1;
+		unsigned reserved456	: 3;
+		unsigned bit3		: 1;
+		unsigned SRST		: 1;
+		unsigned nIEN		: 1;
+		unsigned bit0		: 1;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	} b;
+} ata_control_t;
+
+/*
+ * ATAPI Feature Register
+ *
+ * dma		: Using DMA or PIO
+ * reserved321	: Reserved
+ * reserved654	: Reserved (Tag Type)
+ * reserved7	: Reserved
+ */
+typedef union {
+	unsigned all			:8;
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		unsigned dma		:1;
+		unsigned reserved321	:3;
+		unsigned reserved654	:3;
+		unsigned reserved7	:1;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		unsigned reserved7	:1;
+		unsigned reserved654	:3;
+		unsigned reserved321	:3;
+		unsigned dma		:1;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	} b;
+} atapi_feature_t;
+
+/*
+ * ATAPI Interrupt Reason Register.
+ *
+ * cod		: Information transferred is command (1) or data (0)
+ * io		: The device requests us to read (1) or write (0)
+ * reserved	: Reserved
+ */
+typedef union {
+	unsigned all			:8;
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		unsigned cod		:1;
+		unsigned io		:1;
+		unsigned reserved	:6;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		unsigned reserved	:6;
+		unsigned io		:1;
+		unsigned cod		:1;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	} b;
+} atapi_ireason_t;
+
+/*
+ * The ATAPI error register.
+ *
+ * ili		: Illegal Length Indication
+ * eom		: End Of Media Detected
+ * abrt		: Aborted command - As defined by ATA
+ * mcr		: Media Change Requested - As defined by ATA
+ * sense_key	: Sense key of the last failed packet command
+ */
+typedef union {
+	unsigned all			:8;
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		unsigned ili		:1;
+		unsigned eom		:1;
+		unsigned abrt		:1;
+		unsigned mcr		:1;
+		unsigned sense_key	:4;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		unsigned sense_key	:4;
+		unsigned mcr		:1;
+		unsigned abrt		:1;
+		unsigned eom		:1;
+		unsigned ili		:1;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	} b;
+} atapi_error_t;
+
+/*
+ * ATAPI floppy Drive Select Register
+ *
+ * sam_lun	: Logical unit number
+ * reserved3	: Reserved
+ * drv		: The responding drive will be drive 0 (0) or drive 1 (1)
+ * one5		: Should be set to 1
+ * reserved6	: Reserved
+ * one7		: Should be set to 1
+ */
+typedef union {
+	unsigned all			:8;
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		unsigned sam_lun	:3;
+		unsigned reserved3	:1;
+		unsigned drv		:1;
+		unsigned one5		:1;
+		unsigned reserved6	:1;
+		unsigned one7		:1;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		unsigned one7		:1;
+		unsigned reserved6	:1;
+		unsigned one5		:1;
+		unsigned drv		:1;
+		unsigned reserved3	:1;
+		unsigned sam_lun	:3;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	} b;
+} atapi_select_t;
+
+struct ide_driver_s;
+struct ide_settings_s;
+
 typedef struct ide_drive_s {
-	request_queue_t		 queue;	/* request queue */
+	char		name[4];	/* drive name, such as "hda" */
+        char            driver_req[10];	/* requests specific driver */
+
+	request_queue_t		queue;	/* request queue */
+
+	wait_queue_head_t wqueue;	/* used to wait for drive in open() */
+	struct request		*rq;	/* current request */
 	struct ide_drive_s 	*next;	/* circular list of hwgroup drives */
+	struct ide_driver_s	*driver;/* (ide_driver_t *) */
+	void		*driver_data;	/* extra driver data */
+	struct hd_driveid	*id;	/* drive model identification info */
+	struct hd_struct	*part;	/* drive partition table */
+	struct proc_dir_entry *proc;	/* /proc/ide/ directory entry */
+	struct ide_settings_s *settings;/* /proc/ide/ drive settings */
+	devfs_handle_t		de;	/* directory for device */
+
+	struct hwif_s		*hwif;	/* actually (ide_hwif_t *) */
+
 	unsigned long sleep;		/* sleep until this time */
 	unsigned long service_start;	/* time we started last request */
 	unsigned long service_time;	/* service time of last request */
 	unsigned long timeout;		/* max time to wait for irq */
+
 	special_t	special;	/* special action flags */
-	byte     keep_settings;		/* restore settings after drive reset */
-	byte     using_dma;		/* disk is using dma for read/write */
-	byte	 retry_pio;		/* retrying dma capable host in pio */
-	byte	 state;			/* retry state */
-	byte     waiting_for_dma;	/* dma currently in progress */
-	byte     unmask;		/* flag: okay to unmask other irqs */
-	byte     slow;			/* flag: slow data port */
-	byte     bswap;			/* flag: byte swap data */
-	byte     dsc_overlap;		/* flag: DSC overlap */
-	byte     nice1;			/* flag: give potential excess bandwidth */
+	select_t	select;		/* basic drive/head select reg value */
+
+	u8	keep_settings;		/* restore settings after drive reset */
+	u8	autodma;		/* device can safely use dma on host */
+	u8	using_dma;		/* disk is using dma for read/write */
+	u8	using_tcq;		/* disk is using queueing */
+	u8	retry_pio;		/* retrying dma capable host in pio */
+	u8	state;			/* retry state */
+	u8	waiting_for_dma;	/* dma currently in progress */
+	u8	unmask;			/* okay to unmask other irqs */
+	u8	slow;			/* slow data port */
+	u8	bswap;			/* byte swap data */
+	u8	dsc_overlap;		/* DSC overlap */
+	u8	nice1;			/* give potential excess bandwidth */
+
 	unsigned present	: 1;	/* drive is physically present */
 	unsigned noprobe 	: 1;	/* from:  hdx=noprobe */
 	unsigned busy		: 1;	/* currently doing revalidate_disk() */
 	unsigned removable	: 1;	/* 1 if need to do check_media_change */
+	unsigned is_flash	: 1;	/* 1 if probed as flash */
 	unsigned forced_geom	: 1;	/* 1 if hdx=c,h,s was given at boot */
 	unsigned no_unmask	: 1;	/* disallow setting unmask bit */
 	unsigned no_io_32bit	: 1;	/* disallow enabling 32bit I/O */
-	unsigned nobios		: 1;	/* flag: do not probe bios for drive */
+	unsigned nobios		: 1;	/* do not probe bios for drive */
 	unsigned revalidate	: 1;	/* request revalidation */
-	unsigned atapi_overlap	: 1;	/* flag: ATAPI overlap (not supported) */
-	unsigned nice0		: 1;	/* flag: give obvious excess bandwidth */
-	unsigned nice2		: 1;	/* flag: give a share in our own bandwidth */
-	unsigned doorlocking	: 1;	/* flag: for removable only: door lock/unlock works */
+	unsigned atapi_overlap	: 1;	/* ATAPI overlap (not supported) */
+	unsigned nice0		: 1;	/* give obvious excess bandwidth */
+	unsigned nice2		: 1;	/* give a share in our own bandwidth */
+	unsigned doorlocking	: 1;	/* for removable only: door lock/unlock works */
 	unsigned autotune	: 2;	/* 1=autotune, 2=noautotune, 0=default */
 	unsigned remap_0_to_1	: 2;	/* 0=remap if ezdrive, 1=remap, 2=noremap */
 	unsigned ata_flash	: 1;	/* 1=present, 0=default */
-	unsigned	addressing;	/* : 2; 0=28-bit, 1=48-bit, 2=64-bit */
-	byte		scsi;		/* 0=default, 1=skip current ide-subdriver for ide-scsi emulation */
-	byte		media;		/* disk, cdrom, tape, floppy, ... */
-	select_t	select;		/* basic drive/head select reg value */
-	byte		ctl;		/* "normal" value for IDE_CONTROL_REG */
-	byte		ready_stat;	/* min status value for drive ready */
-	byte		mult_count;	/* current multiple sector setting */
-	byte 		mult_req;	/* requested multiple sector setting */
-	byte 		tune_req;	/* requested drive tuning setting */
-	byte		io_32bit;	/* 0=16-bit, 1=32-bit, 2/3=32bit+sync */
-	byte		bad_wstat;	/* used for ignoring WRERR_STAT */
-	byte		nowerr;		/* used for ignoring WRERR_STAT */
-	byte		sect0;		/* offset of first sector for DM6:DDO */
-	unsigned int	usage;		/* current "open()" count for drive */
-	byte 		head;		/* "real" number of heads */
-	byte		sect;		/* "real" sectors per track */
-	byte		bios_head;	/* BIOS/fdisk/LILO number of heads */
-	byte		bios_sect;	/* BIOS/fdisk/LILO sectors per track */
+	unsigned dead		: 1;	/* 1=dead, no new attachments */
+	unsigned addressing;		/*      : 3;
+					 *  0=28-bit
+					 *  1=48-bit
+					 *  2=48-bit doing 28-bit
+					 *  3=64-bit
+					 */
+
+	u8	scsi;		/* 0=default, 1=skip current ide-subdriver for ide-scsi emulation */
+        u8	quirk_list;	/* considered quirky, set for a specific host */
+        u8	suspend_reset;	/* drive suspend mode flag, soft-reset recovers */
+        u8	init_speed;	/* transfer rate set at boot */
+        u8	pio_speed;      /* unused by core, used by some drivers for fallback from DMA */
+        u8	current_speed;	/* current transfer rate set */
+        u8	dn;		/* now wide spread use */
+        u8	wcache;		/* status of write cache */
+	u8	acoustic;	/* acoustic management */
+	u8	media;		/* disk, cdrom, tape, floppy, ... */
+	u8	ctl;		/* "normal" value for IDE_CONTROL_REG */
+	u8	ready_stat;	/* min status value for drive ready */
+	u8	mult_count;	/* current multiple sector setting */
+	u8	mult_req;	/* requested multiple sector setting */
+	u8	tune_req;	/* requested drive tuning setting */
+	u8	io_32bit;	/* 0=16-bit, 1=32-bit, 2/3=32bit+sync */
+	u8	bad_wstat;	/* used for ignoring WRERR_STAT */
+	u8	nowerr;		/* used for ignoring WRERR_STAT */
+	u8	sect0;		/* offset of first sector for DM6:DDO */
+	u8	head;		/* "real" number of heads */
+	u8	sect;		/* "real" sectors per track */
+	u8	bios_head;	/* BIOS/fdisk/LILO number of heads */
+	u8	bios_sect;	/* BIOS/fdisk/LILO sectors per track */
+
 	unsigned int	bios_cyl;	/* BIOS/fdisk/LILO number of cyls */
 	unsigned int	cyl;		/* "real" number of cyls */
-	unsigned long	capacity;	/* total number of sectors */
-	unsigned long long capacity48;	/* total number of sectors */
-	unsigned int	drive_data;	/* for use by tuneproc/selectproc as needed */
-	void		  *hwif;	/* actually (ide_hwif_t *) */
-	wait_queue_head_t wqueue;	/* used to wait for drive in open() */
-	struct hd_driveid *id;		/* drive model identification info */
-	struct hd_struct  *part;	/* drive partition table */
-	char		name[4];	/* drive name, such as "hda" */
-	void 		*driver;	/* (ide_driver_t *) */
-	void		*driver_data;	/* extra driver data */
-	devfs_handle_t	de;		/* directory for device */
-	struct proc_dir_entry *proc;	/* /proc/ide/ directory entry */
-	void		*settings;	/* /proc/ide/ drive settings */
-	char		driver_req[10];	/* requests specific driver */
+	unsigned int	drive_data;	/* use by tuneproc/selectproc */
+	unsigned int	usage;		/* current "open()" count for drive */
+	unsigned int	failures;	/* current failure count */
+	unsigned int	max_failures;	/* maximum allowed failure count */
+
+	u32		capacity;	/* total number of sectors */
+	u64		capacity48;	/* total number of sectors */
+
 	int		last_lun;	/* last logical unit */
 	int		forced_lun;	/* if hdxlun was given at boot */
 	int		lun;		/* logical unit */
 	int		crc_count;	/* crc counter to reduce drive speed */
-	byte		quirk_list;	/* drive is considered quirky if set for a specific host */
-	byte		suspend_reset;	/* drive suspend mode flag, soft-reset recovers */
-	byte		init_speed;	/* transfer rate set at boot */
-	byte		current_speed;	/* current transfer rate set */
-	byte		dn;		/* now wide spread use */
-	byte		wcache;		/* status of write cache */
-	byte		acoustic;	/* acoustic management */
-	unsigned int	failures;	/* current failure count */
-	unsigned int	max_failures;	/* maximum allowed failure count */
 } ide_drive_t;
 
-/*
- * An ide_dmaproc_t() initiates/aborts DMA read/write operations on a drive.
- *
- * The caller is assumed to have selected the drive and programmed the drive's
- * sector address using CHS or LBA.  All that remains is to prepare for DMA
- * and then issue the actual read/write DMA/PIO command to the drive.
- *
- * Returns 0 if all went well.
- * Returns 1 if DMA read/write could not be started, in which case the caller
- * should either try again later, or revert to PIO for the current request.
- */
-typedef enum {	ide_dma_read,	ide_dma_write,		ide_dma_begin,
-		ide_dma_end,	ide_dma_check,		ide_dma_on,
-		ide_dma_off,	ide_dma_off_quietly,	ide_dma_test_irq,
-		ide_dma_bad_drive,			ide_dma_good_drive,
-		ide_dma_verbose,			ide_dma_retune,
-		ide_dma_lostirq,			ide_dma_timeout
-} ide_dma_action_t;
-
-typedef int (ide_dmaproc_t)(ide_dma_action_t, ide_drive_t *);
-
-/*
- * An ide_ideproc_t() performs CPU-polled transfers to/from a drive.
- * Arguments are: the drive, the buffer pointer, and the length (in bytes or
- * words depending on if it's an IDE or ATAPI call).
- *
- * If it is not defined for a controller, standard-code is used from ide.c.
- *
- * Controllers which are not memory-mapped in the standard way need to 
- * override that mechanism using this function to work.
- *
- */
-typedef enum { ideproc_ide_input_data,    ideproc_ide_output_data,
-	       ideproc_atapi_input_bytes, ideproc_atapi_output_bytes
-} ide_ide_action_t;
-
-typedef void (ide_ideproc_t)(ide_ide_action_t, ide_drive_t *, void *, unsigned int);
+typedef struct ide_pio_ops_s {
+	void (*ata_input_data)(ide_drive_t *, void *, u32);
+	void (*ata_output_data)(ide_drive_t *, void *, u32);
+
+	void (*atapi_input_bytes)(ide_drive_t *, void *, u32);
+	void (*atapi_output_bytes)(ide_drive_t *, void *, u32);
+} ide_pio_ops_t;
+
+typedef struct ide_dma_ops_s {
+	/* insert dma operations here! */
+	int (*ide_dma_read)(ide_drive_t *drive);
+	int (*ide_dma_write)(ide_drive_t *drive);
+	int (*ide_dma_begin)(ide_drive_t *drive);
+	int (*ide_dma_end)(ide_drive_t *drive);
+	int (*ide_dma_check)(ide_drive_t *drive);
+	int (*ide_dma_on)(ide_drive_t *drive);
+	int (*ide_dma_off)(ide_drive_t *drive);
+	int (*ide_dma_off_quietly)(ide_drive_t *drive);
+	int (*ide_dma_test_irq)(ide_drive_t *drive);
+	int (*ide_dma_host_on)(ide_drive_t *drive);
+	int (*ide_dma_host_off)(ide_drive_t *drive);
+	int (*ide_dma_bad_drive)(ide_drive_t *drive);
+	int (*ide_dma_good_drive)(ide_drive_t *drive);
+	int (*ide_dma_count)(ide_drive_t *drive);
+	int (*ide_dma_verbose)(ide_drive_t *drive);
+	int (*ide_dma_retune)(ide_drive_t *drive);
+	int (*ide_dma_lostirq)(ide_drive_t *drive);
+	int (*ide_dma_timeout)(ide_drive_t *drive);
+} ide_dma_ops_t;
 
 /*
- * An ide_tuneproc_t() is used to set the speed of an IDE interface
- * to a particular PIO mode.  The "byte" parameter is used
- * to select the PIO mode by number (0,1,2,3,4,5), and a value of 255
- * indicates that the interface driver should "auto-tune" the PIO mode
- * according to the drive capabilities in drive->id;
+ * mapping stuff, prepare for highmem...
  *
- * Not all interface types support tuning, and not all of those
- * support all possible PIO settings.  They may silently ignore
- * or round values as they see fit.
+ * temporarily mapping a (possible) highmem bio for PIO transfer
  */
-typedef void (ide_tuneproc_t) (ide_drive_t *, byte);
-typedef int (ide_speedproc_t) (ide_drive_t *, byte);
+#define ide_rq_offset(rq) \
+	(((rq)->hard_cur_sectors - (rq)->current_nr_sectors) << 9)
 
-/*
- * This is used to provide support for strange interfaces
- */
-typedef void (ide_selectproc_t) (ide_drive_t *);
-typedef void (ide_resetproc_t) (ide_drive_t *);
-typedef int (ide_quirkproc_t) (ide_drive_t *);
-typedef void (ide_intrproc_t) (ide_drive_t *);
-typedef void (ide_maskproc_t) (ide_drive_t *, int);
-typedef void (ide_rw_proc_t) (ide_drive_t *, ide_dma_action_t);
+extern inline void *ide_map_buffer(struct request *rq, unsigned long *flags)
+{
+	return bh_kmap_irq(rq->bh, flags) + ide_rq_offset(rq);
+}
 
-/*
- * ide soft-power support
- */
-typedef int (ide_busproc_t) (ide_drive_t *, int);
+extern inline void ide_unmap_buffer(char *buffer, unsigned long *flags)
+{
+	bh_kunmap_irq(buffer, flags);
+}
 
 #define IDE_CHIPSET_PCI_MASK	\
     ((1<<ide_pci)|(1<<ide_cmd646)|(1<<ide_ali14xx))
 #define IDE_CHIPSET_IS_PCI(c)	((IDE_CHIPSET_PCI_MASK >> (c)) & 1)
 
-#ifdef CONFIG_BLK_DEV_IDEPCI
-typedef struct ide_pci_devid_s {
-	unsigned short	vid;
-	unsigned short	did;
-} ide_pci_devid_t;
-
-#define IDE_PCI_DEVID_NULL	((ide_pci_devid_t){0,0})
-#define IDE_PCI_DEVID_EQ(a,b)	(a.vid == b.vid && a.did == b.did)
-#endif /* CONFIG_BLK_DEV_IDEPCI */
+struct ide_pci_device_s;
 
 typedef struct hwif_s {
-	struct hwif_s	*next;		/* for linked-list in ide_hwgroup_t */
-	void		*hwgroup;	/* actually (ide_hwgroup_t *) */
-	ide_ioreg_t	io_ports[IDE_NR_PORTS];	/* task file registers */
+	struct hwif_s *next;		/* for linked-list in ide_hwgroup_t */
+	struct hwif_s *mate;		/* other hwif from same PCI chip */
+	struct hwgroup_s *hwgroup;	/* actually (ide_hwgroup_t *) */
+	struct proc_dir_entry *proc;	/* /proc/ide/ directory entry */
+	struct gendisk *gd;		/* gendisk structure */
+
+	char name[6];			/* name of interface, eg. "ide0" */
+
+		/* task file registers for pata and sata */
+	ide_ioreg_t	io_ports[IDE_NR_PORTS];
+	sata_ioreg_t	sata_scr[SATA_NR_PORTS];
+	sata_ioreg_t	sata_misc[SATA_NR_PORTS];
+
 	hw_regs_t	hw;		/* Hardware info */
 	ide_drive_t	drives[MAX_DRIVES];	/* drive info */
-	struct gendisk	*gd;		/* gendisk structure */
-	ide_tuneproc_t	*tuneproc;	/* routine to tune PIO mode for drives */
-	ide_speedproc_t	*speedproc;	/* routine to retune DMA modes for drives */
-	ide_selectproc_t *selectproc;	/* tweaks hardware to select drive */
-	ide_resetproc_t	*resetproc;	/* routine to reset controller after a disk reset */
-	ide_intrproc_t	*intrproc;	/* special interrupt handling for shared pci interrupts */
-	ide_maskproc_t	*maskproc;	/* special host masking for drive selection */
-	ide_quirkproc_t	*quirkproc;	/* check host's drive quirk list */
-	ide_rw_proc_t	*rwproc;	/* adjust timing based upon rq->cmd direction */
-	ide_ideproc_t   *ideproc;       /* CPU-polled transfer routine */
-	ide_dmaproc_t	*dmaproc;	/* dma read/write/abort routine */
-	unsigned int	*dmatable_cpu;	/* dma physical region descriptor table (cpu view) */
-	dma_addr_t	dmatable_dma;	/* dma physical region descriptor table (dma view) */
-	struct scatterlist *sg_table;	/* Scatter-gather list used to build the above */
+
+	u8 major;	/* our major number */
+	u8 index;	/* 0 for ide0; 1 for ide1; ... */
+	u8 channel;	/* for dual-port chips: 0=primary, 1=secondary */
+	u8 straight8;	/* Alan's straight 8 check */
+	u8 bus_state;	/* power state of the IDE bus */
+
+	u8 atapi_dma;	/* host supports atapi_dma */
+	u8 ultra_mask;
+	u8 mwdma_mask;
+	u8 swdma_mask;
+
+	hwif_chipset_t chipset;	/* sub-module for tuning.. */
+
+	struct pci_dev  *pci_dev;	/* for pci chipsets */
+	struct ide_pci_device_s	*cds;	/* chipset device struct */
+
+#if 0
+	ide_hwif_ops_t	*hwifops;
+#else
+	/* routine is for HBA specific IDENTITY operations */
+	int	(*identify)(ide_drive_t *);
+	/* routine to tune PIO mode for drives */
+	void	(*tuneproc)(ide_drive_t *, u8);
+	/* routine to retune DMA modes for drives */
+	int	(*speedproc)(ide_drive_t *, u8);
+	/* tweaks hardware to select drive */
+	void	(*selectproc)(ide_drive_t *);
+	/* chipset polling based on hba specifics */
+	int	(*reset_poll)(ide_drive_t *);
+	/* chipset specific changes to default for device-hba resets */
+	void	(*pre_reset)(ide_drive_t *);
+	/* routine to reset controller after a disk reset */
+	void	(*resetproc)(ide_drive_t *);
+	/* special interrupt handling for shared pci interrupts */
+	void	(*intrproc)(ide_drive_t *);
+	/* special host masking for drive selection */
+	void	(*maskproc)(ide_drive_t *, int);
+	/* check host's drive quirk list */
+	int	(*quirkproc)(ide_drive_t *);
+	/* driver soft-power interface */
+	int	(*busproc)(ide_drive_t *, int);
+//	/* host rate limiter */
+//	u8	(*ratemask)(ide_drive_t *);
+//	/* device rate limiter */
+//	u8	(*ratefilter)(ide_drive_t *, u8);
+#endif
+
+#if 0
+	ide_pio_ops_t	*pioops;
+#else
+	void (*ata_input_data)(ide_drive_t *, void *, u32);
+	void (*ata_output_data)(ide_drive_t *, void *, u32);
+
+	void (*atapi_input_bytes)(ide_drive_t *, void *, u32);
+	void (*atapi_output_bytes)(ide_drive_t *, void *, u32);
+#endif
+
+#if 0
+	ide_dma_ops_t	*dmaops;
+#else
+	int (*ide_dma_read)(ide_drive_t *drive);
+	int (*ide_dma_write)(ide_drive_t *drive);
+	int (*ide_dma_begin)(ide_drive_t *drive);
+	int (*ide_dma_end)(ide_drive_t *drive);
+	int (*ide_dma_check)(ide_drive_t *drive);
+	int (*ide_dma_on)(ide_drive_t *drive);
+	int (*ide_dma_off)(ide_drive_t *drive);
+	int (*ide_dma_off_quietly)(ide_drive_t *drive);
+	int (*ide_dma_test_irq)(ide_drive_t *drive);
+	int (*ide_dma_host_on)(ide_drive_t *drive);
+	int (*ide_dma_host_off)(ide_drive_t *drive);
+	int (*ide_dma_bad_drive)(ide_drive_t *drive);
+	int (*ide_dma_good_drive)(ide_drive_t *drive);
+	int (*ide_dma_count)(ide_drive_t *drive);
+	int (*ide_dma_verbose)(ide_drive_t *drive);
+	int (*ide_dma_retune)(ide_drive_t *drive);
+	int (*ide_dma_lostirq)(ide_drive_t *drive);
+	int (*ide_dma_timeout)(ide_drive_t *drive);
+#endif
+
+	void (*OUTB)(u8 addr, unsigned long port);
+	void (*OUTBSYNC)(u8 addr, unsigned long port);
+	void (*OUTW)(u16 addr, unsigned long port);
+	void (*OUTL)(u32 addr, unsigned long port);
+	void (*OUTSW)(unsigned long port, void *addr, u32 count);
+	void (*OUTSL)(unsigned long port, void *addr, u32 count);
+
+	u8  (*INB)(unsigned long port);
+	u16 (*INW)(unsigned long port);
+	u32 (*INL)(unsigned long port);
+	void (*INSW)(unsigned long port, void *addr, u32 count);
+	void (*INSL)(unsigned long port, void *addr, u32 count);
+
+	/* dma physical region descriptor table (cpu view) */
+	unsigned int	*dmatable_cpu;
+	/* dma physical region descriptor table (dma view) */
+	dma_addr_t	dmatable_dma;
+	/* Scatter-gather list used to build the above */
+	struct scatterlist *sg_table;
 	int sg_nents;			/* Current number of entries in it */
 	int sg_dma_direction;		/* dma transfer direction */
 	int sg_dma_active;		/* is it in use */
-	struct hwif_s	*mate;		/* other hwif from same PCI chip */
+
+	int		mmio;		/* hosts iomio (0), mmio (1) or custom (2) select */
+	int		rqsize;		/* max sectors per request */
+	int		addressing;	/* hosts addressing */
+	int		irq;		/* our irq number */
+	int		initializing;	/* set while initializing self */
+
+	unsigned long	dma_master;	/* reference base addr dmabase */
 	unsigned long	dma_base;	/* base addr for dma ports */
+	unsigned long	dma_command;	/* dma command register */
+	unsigned long	dma_vendor1;	/* dma vendor 1 register */
+	unsigned long	dma_status;	/* dma status register */
+	unsigned long	dma_vendor3;	/* dma vendor 3 register */
+	unsigned long	dma_prdtable;	/* actual prd table address */
+	unsigned long	dma_base2;	/* extended base addr for dma ports */
+
 	unsigned	dma_extra;	/* extra addr for dma ports */
 	unsigned long	config_data;	/* for use by chipset-specific code */
 	unsigned long	select_data;	/* for use by chipset-specific code */
-	struct proc_dir_entry *proc;	/* /proc/ide/ directory entry */
-	int		irq;		/* our irq number */
-	byte		major;		/* our major number */
-	char 		name[6];	/* name of interface, eg. "ide0" */
-	byte		index;		/* 0 for ide0; 1 for ide1; ... */
-	hwif_chipset_t	chipset;	/* sub-module for tuning.. */
+#if (DISK_RECOVERY_TIME > 0)
+	unsigned long	last_time;	/* time when previous rq was done */
+#endif
+
+
 	unsigned	noprobe    : 1;	/* don't probe for this interface */
 	unsigned	present    : 1;	/* this interface exists */
-	unsigned	serialized : 1;	/* serialized operation with mate hwif */
+	unsigned	serialized : 1;	/* serialized all channel operation */
 	unsigned	sharing_irq: 1;	/* 1 = sharing irq with another hwif */
 	unsigned	reset      : 1;	/* reset after probe */
-	unsigned	autodma    : 1;	/* automatically try to enable DMA at boot */
+	unsigned	autodma    : 1;	/* auto-attempt using DMA at boot */
 	unsigned	udma_four  : 1;	/* 1=ATA-66 capable, 0=default */
-	unsigned	no_highio  : 1; /* don't trust pci dma mask, bounce */
-	byte		channel;	/* for dual-port chips: 0=primary, 1=secondary */
-#ifdef CONFIG_BLK_DEV_IDEPCI
-	struct pci_dev	*pci_dev;	/* for pci chipsets */
-	ide_pci_devid_t	pci_devid;	/* for pci chipsets: {VID,DID} */
-#endif /* CONFIG_BLK_DEV_IDEPCI */
-#if (DISK_RECOVERY_TIME > 0)
-	unsigned long	last_time;	/* time when previous rq was done */
-#endif
-	byte		straight8;	/* Alan's straight 8 check */
+	unsigned	highmem    : 1;	/* can do full 32-bit dma */
+	unsigned	no_dsc     : 1;	/* 0 default, 1 dsc_overlap disabled */
+
 	void		*hwif_data;	/* extra hwif data */
-	ide_busproc_t	*busproc;	/* driver soft-power interface */
-	byte		bus_state;	/* power state of the IDE bus */
 } ide_hwif_t;
 
 /*
@@ -572,7 +1005,7 @@
  */
 typedef enum {
 	ide_stopped,	/* no drive operation was started */
-	ide_started	/* a drive operation was started, and a handler was set */
+	ide_started	/* a drive operation was started, handler was set */
 } ide_startstop_t;
 
 /*
@@ -581,24 +1014,39 @@
 typedef ide_startstop_t (ide_pre_handler_t)(ide_drive_t *, struct request *);
 typedef ide_startstop_t (ide_handler_t)(ide_drive_t *);
 typedef ide_startstop_t (ide_post_handler_t)(ide_drive_t *);
-
-/*
- * when ide_timer_expiry fires, invoke a handler of this type
- * to decide what to do.
- */
 typedef int (ide_expiry_t)(ide_drive_t *);
 
 typedef struct hwgroup_s {
-	ide_handler_t		*handler;/* irq handler, if active */
-	volatile int		busy;	/* BOOL: protects all fields below */
-	int			sleeping; /* BOOL: wake us up on timer expiry */
-	ide_drive_t		*drive;	/* current drive */
-	ide_hwif_t		*hwif;	/* ptr to current hwif in linked-list */
-	struct request		*rq;	/* current request */
-	struct timer_list	timer;	/* failsafe timer */
-	struct request		wrq;	/* local copy of current write rq */
-	unsigned long		poll_timeout;	/* timeout value during long polls */
-	ide_expiry_t		*expiry;	/* queried upon timeouts */
+		/* irq handler, if active */
+	ide_startstop_t	(*handler)(ide_drive_t *);
+		/* irq handler, suspended if active */
+	ide_startstop_t	(*handler_save)(ide_drive_t *);
+		/* BOOL: protects all fields below */
+	volatile int busy;
+		/* BOOL: wake us up on timer expiry */
+	int sleeping;
+		/* current drive */
+	ide_drive_t *drive;
+		/* ptr to current hwif in linked-list */
+	ide_hwif_t *hwif;
+
+		/* for pci chipsets */
+	struct pci_dev *pci_dev;
+		/* chipset device struct */
+	struct ide_pci_device_s *cds;
+
+		/* current request */
+	struct request *rq;
+		/* failsafe timer */
+	struct timer_list timer;
+		/* local copy of current write rq */
+	struct request wrq;
+		/* timeout value during long polls */
+	unsigned long poll_timeout;
+		/* queried upon timeouts */
+	int (*expiry)(ide_drive_t *);
+		/* ide_system_bus_speed */
+	int pio_clock;
 } ide_hwgroup_t;
 
 /* structure attached to the request for IDE_TASK_CMDS */
@@ -651,14 +1099,14 @@
 } ide_proc_entry_t;
 
 #ifdef CONFIG_PROC_FS
-void proc_ide_create(void);
-void proc_ide_destroy(void);
-void recreate_proc_ide_device(ide_hwif_t *, ide_drive_t *);
-void destroy_proc_ide_device(ide_hwif_t *, ide_drive_t *);
-void destroy_proc_ide_drives(ide_hwif_t *);
-void create_proc_ide_interfaces(void);
-void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void *data);
-void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p);
+extern void proc_ide_create(void);
+extern void proc_ide_destroy(void);
+extern void recreate_proc_ide_device(ide_hwif_t *, ide_drive_t *);
+extern void destroy_proc_ide_device(ide_hwif_t *, ide_drive_t *);
+extern void destroy_proc_ide_drives(ide_hwif_t *);
+extern void create_proc_ide_interfaces(void);
+extern void ide_add_proc_entries(struct proc_dir_entry *, ide_proc_entry_t *, void *);
+extern void ide_remove_proc_entries(struct proc_dir_entry *, ide_proc_entry_t *);
 read_proc_t proc_ide_read_capacity;
 read_proc_t proc_ide_read_geometry;
 
@@ -686,51 +1134,39 @@
  */
 #define IDE_SUBDRIVER_VERSION	1
 
-typedef int		(ide_cleanup_proc)(ide_drive_t *);
-typedef int		(ide_standby_proc)(ide_drive_t *);
-typedef int		(ide_flushcache_proc)(ide_drive_t *);
-typedef ide_startstop_t	(ide_do_request_proc)(ide_drive_t *, struct request *, unsigned long);
-typedef void		(ide_end_request_proc)(byte, ide_hwgroup_t *);
-typedef int		(ide_ioctl_proc)(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long);
-typedef int		(ide_open_proc)(struct inode *, struct file *, ide_drive_t *);
-typedef void		(ide_release_proc)(struct inode *, struct file *, ide_drive_t *);
-typedef int		(ide_check_media_change_proc)(ide_drive_t *);
-typedef void		(ide_revalidate_proc)(ide_drive_t *);
-typedef void		(ide_pre_reset_proc)(ide_drive_t *);
-typedef unsigned long	(ide_capacity_proc)(ide_drive_t *);
-typedef ide_startstop_t	(ide_special_proc)(ide_drive_t *);
-typedef void		(ide_setting_proc)(ide_drive_t *);
-typedef int		(ide_reinit_proc)(ide_drive_t *);
-typedef void		(ata_prebuilder_proc)(ide_drive_t *);
-typedef void		(atapi_prebuilder_proc)(ide_drive_t *);
-
 typedef struct ide_driver_s {
 	const char			*name;
 	const char			*version;
-	byte				media;
+	u8				media;
 	unsigned busy			: 1;
 	unsigned supports_dma		: 1;
 	unsigned supports_dsc_overlap	: 1;
-	ide_cleanup_proc		*cleanup;
-	ide_standby_proc		*standby;
-	ide_flushcache_proc		*flushcache;
-	ide_do_request_proc		*do_request;
-	ide_end_request_proc		*end_request;
-	ide_ioctl_proc			*ioctl;
-	ide_open_proc			*open;
-	ide_release_proc		*release;
-	ide_check_media_change_proc	*media_change;
-	ide_revalidate_proc		*revalidate;
-	ide_pre_reset_proc		*pre_reset;
-	ide_capacity_proc		*capacity;
-	ide_special_proc		*special;
-	ide_proc_entry_t		*proc;
-	ide_reinit_proc			*reinit;
-	ata_prebuilder_proc		*ata_prebuilder;
-	atapi_prebuilder_proc		*atapi_prebuilder;
+	int		(*cleanup)(ide_drive_t *);
+	int		(*shutdown)(ide_drive_t *);
+	int		(*standby)(ide_drive_t *);
+	int		(*suspend)(ide_drive_t *);
+	int		(*resume)(ide_drive_t *);
+	int		(*flushcache)(ide_drive_t *);
+	ide_startstop_t	(*do_request)(ide_drive_t *, struct request *, unsigned long);
+	int		(*end_request)(ide_drive_t *, int);
+	u8		(*sense)(ide_drive_t *, const char *, u8);
+	ide_startstop_t	(*error)(ide_drive_t *, const char *, u8);
+	int		(*ioctl)(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long);
+	int		(*open)(struct inode *, struct file *, ide_drive_t *);
+	void		(*release)(struct inode *, struct file *, ide_drive_t *);
+	int		(*media_change)(ide_drive_t *);
+	void		(*revalidate)(ide_drive_t *);
+	void		(*pre_reset)(ide_drive_t *);
+	unsigned long	(*capacity)(ide_drive_t *);
+	ide_startstop_t	(*special)(ide_drive_t *);
+	ide_proc_entry_t	*proc;
+	int		(*init)(void);
+	int		(*attach)(ide_drive_t *);
+	void		(*ata_prebuilder)(ide_drive_t *);
+	void		(*atapi_prebuilder)(ide_drive_t *);
 } ide_driver_t;
 
-#define DRIVER(drive)		((ide_driver_t *)((drive)->driver))
+#define DRIVER(drive)		((drive)->driver)
 
 /*
  * IDE modules.
@@ -748,6 +1184,53 @@
 	struct ide_module_s		*next;
 } ide_module_t;
 
+typedef struct ide_devices_s {
+	char			name[4];		/* hdX */
+	unsigned		attached	: 1;	/* native */
+	unsigned		alttached	: 1;	/* alternate */
+	struct ide_devices_s	*next;
+} ide_devices_t;
+
+#if 0
+typedef enum {
+	IDE_MEDIA_FLOPPY	= ide_floppy,
+	IDE_MEDIA_TAPE		= ide_tape,
+	IDE_MEDIA_CDROM		= ide_cdrom,
+	IDE_MEDIA_OPTICAL	= ide_optical,
+	IDE_MEDIA_DISK		= ide_disk,
+	IDE_MEDIA_SCSI		= ide_scsi,
+} ide_media_type;
+
+struct ide_media {
+	ide_media_type type;
+	char name[4];
+	atomic_t refcount;	/* Maybe this should be a struct module*
+				   with MOD_INC instead */
+	struct list_head devices;
+};
+
+struct {
+	struct ide_media floppy;
+	struct ide_media tape;
+	struct ide_media cdrom;
+	struct ide_media optical;
+	struct ide_media disk;
+	struct ide_media scsi;
+} ide_medias;
+
+void __init init_media(void)
+{
+	memset(&ide_medias, 0, sizeof(ide_medias));
+
+	ide_medias.floppy.type	= IDE_MEDIA_FLOPPY;
+	ide_medias.tape.type	= IDE_MEDIA_TAPE;
+	ide_medias.cdrom.type	= IDE_MEDIA_CDROM;
+	ide_medias.optical.type	= IDE_MEDIA_OPTICAL;
+	ide_medias.disk.type	= IDE_MEDIA_DISK;
+	ide_medias.scsi.type	= IDE_MEDIA_SCSI;
+};
+#endif
+
 /*
  * ide_hwifs[] is the master data structure used to keep track
  * of just about everything in ide.c.  Whenever possible, routines
@@ -758,8 +1241,16 @@
  */
 #ifndef _IDE_C
 extern	ide_hwif_t	ide_hwifs[];		/* master data repository */
+extern	ide_module_t	*ide_chipsets;
 extern	ide_module_t	*ide_modules;
 extern	ide_module_t	*ide_probe;
+
+extern	ide_devices_t	*idedisk;
+extern	ide_devices_t	*idecd;
+extern	ide_devices_t	*idefloppy;
+extern	ide_devices_t	*idetape;
+extern	ide_devices_t	*idescsi;
+
 #endif
 extern int noautodma;
 
@@ -768,56 +1259,57 @@
  */
 #define IDE_DRIVER		/* Toggle some magic bits in blk.h */
 #define LOCAL_END_REQUEST	/* Don't generate end_request in blk.h */
+//#define DEVICE_NR(device)	(MINOR(device) >> PARTN_BITS)
 #include <linux/blk.h>
 
-void ide_end_request(byte uptodate, ide_hwgroup_t *hwgroup);
-
-/*
- * This is used for (nearly) all data transfers from/to the IDE interface
- * FIXME for 2.5, to a pointer pass verses memcpy........
- */
-void ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
-void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
+extern int ide_end_request(ide_drive_t *, int /* uptodate */);
 
 /*
- * This is used for (nearly) all ATAPI data transfers from/to the IDE interface
- * FIXME for 2.5, to a pointer pass verses memcpy........
+ * This is used on exit from the driver to designate the next irq handler
+ * and also to start the safety timer.
  */
-void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount);
-void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount);
-
-int drive_is_ready (ide_drive_t *drive);
+extern void ide_set_handler(ide_drive_t *, ide_handler_t *, unsigned int, ide_expiry_t *);
 
 /*
- * This is used on exit from the driver, to designate the next irq handler
- * and also to start the safety timer.
+ * This is used on exit from the driver to designate the next irq handler
+ * and start the safety time safely and atomically from the IRQ handler
+ * with respect to the command issue (which it also does)
  */
-void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int timeout, ide_expiry_t *expiry);
+extern void ide_execute_command(ide_drive_t *, task_ioreg_t cmd, ide_handler_t *, unsigned int, ide_expiry_t *);
 
 /*
  * Error reporting, in human readable form (luxurious, but a memory hog).
+ *
+ * (drive, msg, status)
  */
-byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat);
+extern u8 ide_dump_status(ide_drive_t *, const char *, u8);
 
 /*
  * ide_error() takes action based on the error returned by the controller.
  * The caller should return immediately after invoking this.
+ *
+ * (drive, msg, status)
  */
-ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, byte stat);
+extern ide_startstop_t ide_error(ide_drive_t *, const char *, u8);
 
 /*
  * Issue a simple drive command
  * The drive must be selected beforehand.
+ *
+ * (drive, command, nsector, handler)
  */
-void ide_cmd (ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler);
+extern void ide_cmd(ide_drive_t *, u8, u8, ide_handler_t *);
 
+extern void ide_fix_driveid(struct hd_driveid *);
 /*
  * ide_fixstring() cleans up and (optionally) byte-swaps a text string,
  * removing leading/trailing blanks and compressing internal blanks.
  * It is primarily used to tidy up the model name/number fields as
  * returned by the WIN_[P]IDENTIFY commands.
+ *
+ * (s, bytecount, byteswap)
  */
-void ide_fixstring (byte *s, const int bytecount, const int byteswap);
+extern void ide_fixstring(u8 *, const int, const int);
 
 /*
  * This routine busy-waits for the drive status to be not "busy".
@@ -826,43 +1318,44 @@
  * cases return 1 after doing "*startstop = ide_error()", and the
  * caller should return the updated value of "startstop" in this case.
  * "startstop" is unchanged when the function returns 0;
+ *  (startstop, drive, good, bad, timeout)
  */
-int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, byte good, byte bad, unsigned long timeout);
-
-int ide_wait_noerr (ide_drive_t *drive, byte good, byte bad, unsigned long timeout);
+extern int ide_wait_stat(ide_startstop_t *, ide_drive_t *, u8, u8, unsigned long);
 
 /*
  * This routine is called from the partition-table code in genhd.c
  * to "convert" a drive to a logical geometry with fewer than 1024 cyls.
  */
-int ide_xlate_1024 (kdev_t, int, int, const char *);
+extern int ide_xlate_1024(kdev_t, int, int, const char *);
 
 /*
  * Convert kdev_t structure into ide_drive_t * one.
  */
-ide_drive_t *get_info_ptr (kdev_t i_rdev);
+extern ide_drive_t *get_info_ptr(kdev_t i_rdev);
 
 /*
  * Return the current idea about the total capacity of this drive.
  */
-unsigned long current_capacity (ide_drive_t *drive);
+extern unsigned long current_capacity(ide_drive_t *);
+
+extern void ide_revalidate_drive(ide_drive_t *);
 
 /*
  * Start a reset operation for an IDE interface.
  * The caller should return immediately after invoking this.
  */
-ide_startstop_t ide_do_reset (ide_drive_t *);
+extern ide_startstop_t ide_do_reset(ide_drive_t *);
 
 /*
  * Re-Start an operation for an IDE interface.
  * The caller should return immediately after invoking this.
  */
-ide_startstop_t restart_request (ide_drive_t *);
+extern int restart_request(ide_drive_t *, struct request *);
 
 /*
  * This function is intended to be used prior to invoking ide_do_drive_cmd().
  */
-void ide_init_drive_cmd (struct request *rq);
+extern void ide_init_drive_cmd(struct request *);
 
 /*
  * "action" parameter type for ide_do_drive_cmd() below.
@@ -875,21 +1368,6 @@
 } ide_action_t;
 
 /*
- * temporarily mapping a (possible) highmem bio
- */
-#define ide_rq_offset(rq) (((rq)->hard_cur_sectors - (rq)->current_nr_sectors) << 9)
-
-extern inline void *ide_map_buffer(struct request *rq, unsigned long *flags)
-{
-	return bh_kmap_irq(rq->bh, flags) + ide_rq_offset(rq);
-}
-
-extern inline void ide_unmap_buffer(char *buffer, unsigned long *flags)
-{
-	bh_kunmap_irq(buffer, flags);
-}
-
-/*
  * This function issues a special IDE device request
  * onto the request queue.
  *
@@ -914,23 +1392,35 @@
  * for the new rq to be completed. This is again intended for careful
  * use by the ATAPI tape/cdrom driver code.
  */
-int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action);
+extern int ide_do_drive_cmd(ide_drive_t *, struct request *, ide_action_t);
 
 /*
  * Clean up after success/failure of an explicit drive cmd.
  * stat/err are used only when (HWGROUP(drive)->rq->cmd == IDE_DRIVE_CMD).
  * stat/err are used only when (HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASK_MASK).
+ *
+ * (ide_drive_t *drive, u8 stat, u8 err)
  */
-void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err);
+extern void ide_end_drive_cmd(ide_drive_t *, u8, u8);
 
 /*
- * Issue ATA command and wait for completion. use for implementing commands in kernel
+ * Issue ATA command and wait for completion.
+ * Use for implementing commands in kernel
+ *
+ *  (ide_drive_t *drive, u8 cmd, u8 nsect, u8 feature, u8 sectors, u8 *buf)
  */
-int ide_wait_cmd (ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *buf);
+extern int ide_wait_cmd(ide_drive_t *, u8, u8, u8, u8, u8 *);
+
+/* (ide_drive_t *drive, u8 *buf) */
+extern int ide_wait_cmd_task(ide_drive_t *, u8 *);
 
-int ide_wait_cmd_task (ide_drive_t *drive, byte *buf);
- 
 typedef struct ide_task_s {
+/*
+ *	struct hd_drive_task_hdr	tf;
+ *	task_struct_t		tf;
+ *	struct hd_drive_hob_hdr		hobf;
+ *	hob_struct_t		hobf;
+ */
 	task_ioreg_t		tfRegister[8];
 	task_ioreg_t		hobRegister[8];
 	ide_reg_valid_t		tf_out_flags;
@@ -940,71 +1430,147 @@
 	ide_pre_handler_t	*prehandler;
 	ide_handler_t		*handler;
 	ide_post_handler_t	*posthandler;
-	void			*special;	/* valid_t generally */
 	struct request		*rq;		/* copy of request */
-	unsigned long		block;		/* copy of block */
+	void			*special;	/* valid_t generally */
 } ide_task_t;
 
 typedef struct pkt_task_s {
+/*
+ *	struct hd_drive_task_hdr	pktf;
+ *	task_struct_t		pktf;
+ *	u8			pkcdb[12];
+ */
 	task_ioreg_t		tfRegister[8];
 	int			data_phase;
 	int			command_type;
 	ide_handler_t		*handler;
-	void			*special;
 	struct request		*rq;		/* copy of request */
-	unsigned long		block;		/* copy of block */
+	void			*special;
 } pkt_task_t;
 
-/*
- * taskfile io for disks for now...
- */
-ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task);
+extern inline void SELECT_DRIVE(ide_drive_t *);
+extern inline void SELECT_INTERRUPT(ide_drive_t *);
+extern inline void SELECT_MASK(ide_drive_t *, int);
+extern inline void QUIRK_LIST(ide_drive_t *);
+
+extern void ata_input_data(ide_drive_t *, void *, u32);
+extern void ata_output_data(ide_drive_t *, void *, u32);
+extern void atapi_input_bytes(ide_drive_t *, void *, u32);
+extern void atapi_output_bytes(ide_drive_t *, void *, u32);
+extern void taskfile_input_data(ide_drive_t *, void *, u32);
+extern void taskfile_output_data(ide_drive_t *, void *, u32);
+
+extern int drive_is_ready(ide_drive_t *);
+extern int wait_for_ready(ide_drive_t *, int /* timeout */);
 
 /*
- * Builds request from ide_ioctl
+ * taskfile io for disks for now...and builds request from ide_ioctl
  */
-void do_taskfile (ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, ide_handler_t *handler);
+extern ide_startstop_t do_rw_taskfile(ide_drive_t *, ide_task_t *);
+
+/* (ide_drive_t *drive, u8 stat, u8 err) */
+extern void ide_end_taskfile(ide_drive_t *, u8, u8);
 
 /*
  * Special Flagged Register Validation Caller
  */
-// ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task);
+extern ide_startstop_t flagged_taskfile(ide_drive_t *, ide_task_t *);
+
+extern ide_startstop_t set_multmode_intr(ide_drive_t *);
+extern ide_startstop_t set_geometry_intr(ide_drive_t *);
+extern ide_startstop_t recal_intr(ide_drive_t *);
+extern ide_startstop_t task_no_data_intr(ide_drive_t *);
+extern ide_startstop_t task_in_intr(ide_drive_t *);
+extern ide_startstop_t task_mulin_intr(ide_drive_t *);
+extern ide_startstop_t pre_task_out_intr(ide_drive_t *, struct request *);
+extern ide_startstop_t task_out_intr(ide_drive_t *);
+extern ide_startstop_t pre_task_mulout_intr(ide_drive_t *, struct request *);
+extern ide_startstop_t task_mulout_intr(ide_drive_t *);
+extern void ide_init_drive_taskfile(struct request *);
 
-ide_startstop_t set_multmode_intr (ide_drive_t *drive);
-ide_startstop_t set_geometry_intr (ide_drive_t *drive);
-ide_startstop_t recal_intr (ide_drive_t *drive);
-ide_startstop_t task_no_data_intr (ide_drive_t *drive);
-ide_startstop_t task_in_intr (ide_drive_t *drive);
-ide_startstop_t task_mulin_intr (ide_drive_t *drive);
-ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq);
-ide_startstop_t task_out_intr (ide_drive_t *drive);
-ide_startstop_t task_mulout_intr (ide_drive_t *drive);
-void ide_init_drive_taskfile (struct request *rq);
+extern int ide_raw_taskfile(ide_drive_t *, ide_task_t *, u8 *);
 
-int ide_wait_taskfile (ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, byte *buf);
+extern ide_pre_handler_t * ide_pre_handler_parser(struct hd_drive_task_hdr *, struct hd_drive_hob_hdr *);
 
-int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *cmd, byte *buf);
+extern ide_handler_t * ide_handler_parser(struct hd_drive_task_hdr *, struct hd_drive_hob_hdr *);
+
+extern ide_post_handler_t * ide_post_handler_parser(struct hd_drive_task_hdr *, struct hd_drive_hob_hdr *);
 
-ide_pre_handler_t * ide_pre_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile);
-ide_handler_t * ide_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile);
 /* Expects args is a full set of TF registers and parses the command type */
-int ide_cmd_type_parser (ide_task_t *args);
+extern int ide_cmd_type_parser(ide_task_t *);
+
+int ide_taskfile_ioctl(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long);
+int ide_cmd_ioctl(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long);
+int ide_task_ioctl(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long);
+
+#if 0
+
+#define IDEFLOPPY_PC_BUFFER_SIZE        256
+#define IDETAPE_PC_BUFFER_SIZE          256
+#define IDE_PC_BUFFER_SIZE          256
+
+typedef struct ide_packet_command_s {
+		/* Actual packet bytes */
+	u8 c[12];
+		/* On each retry, we increment retries */
+	int retries;
+		/* Error code */
+	int error;
+		/* Bytes to transfer */
+	int request_transfer;
+		/* Bytes actually transferred */
+	int actually_transferred;
+		/* Size of our data buffer */
+	int buffer_size;
+
+	struct buffer_head *bh;
+	u8 *b_data;
+		/* The corresponding request */
+	struct request *rq;
+# if 0
+		/* Scatter gather table */
+	struct scatterlist *sg;
+# endif
+	int b_count;
+		/* Data buffer */
+	u8 *buffer;
+		/* Pointer into the above buffer */
+	u8 *current_position;
+		/* Called when this packet command is completed */
+	ide_startstop_t (*callback) (ide_drive_t *);
+		/* Temporary buffer */
+	u8 pc_buffer[IDE_PC_BUFFER_SIZE];
+		/* Status/Action bit flags: long for set_bit */
+	unsigned long flags;
+} ide_pc_t;
+
+ide-cd orthoginal :-/
+struct packet_command {
+        char *buffer;
+        int buflen;
+        int stat;
+        int quiet;
+        int timeout;
+        struct request_sense *sense;
+        unsigned char c[12];
+};
 
-int ide_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+#endif
 
 #ifdef CONFIG_PKT_TASK_IOCTL
-int pkt_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+extern int pkt_taskfile_ioctl(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long);
 #endif /* CONFIG_PKT_TASK_IOCTL */
 
-void ide_delay_50ms (void);
-int system_bus_clock(void);
+extern void ide_delay_50ms(void);
+extern int system_bus_clock(void);
 
-byte ide_auto_reduce_xfer (ide_drive_t *drive);
-int ide_driveid_update (ide_drive_t *drive);
-int ide_ata66_check (ide_drive_t *drive, ide_task_t *args);
-int ide_config_drive_speed (ide_drive_t *drive, byte speed);
-byte eighty_ninty_three (ide_drive_t *drive);
-int set_transfer (ide_drive_t *drive, ide_task_t *args);
+extern u8 ide_auto_reduce_xfer(ide_drive_t *);
+extern int ide_driveid_update(ide_drive_t *);
+extern int ide_ata66_check(ide_drive_t *, ide_task_t *);
+extern int ide_config_drive_speed(ide_drive_t *, u8);
+extern u8 eighty_ninty_three (ide_drive_t *);
+extern int set_transfer(ide_drive_t *, ide_task_t *);
+extern int taskfile_lib_get_identify(ide_drive_t *drive, u8 *);
 
 /*
  * ide_system_bus_speed() returns what we think is the system VESA/PCI
@@ -1012,107 +1578,176 @@
  * The default is 40 for known PCI systems, 50 otherwise.
  * The "idebus=xx" parameter can be used to override this value.
  */
-int ide_system_bus_speed (void);
-
-/*
- * ide_multwrite() transfers a block of up to mcount sectors of data
- * to a drive as part of a disk multwrite operation.
- */
-int ide_multwrite (ide_drive_t *drive, unsigned int mcount);
+extern int ide_system_bus_speed(void);
 
 /*
  * ide_stall_queue() can be used by a drive to give excess bandwidth back
  * to the hwgroup by sleeping for timeout jiffies.
  */
-void ide_stall_queue (ide_drive_t *drive, unsigned long timeout);
+extern void ide_stall_queue(ide_drive_t *, unsigned long);
 
 /*
  * ide_get_queue() returns the queue which corresponds to a given device.
  */
-request_queue_t *ide_get_queue (kdev_t dev);
+extern request_queue_t *ide_get_queue(kdev_t dev);
 
 /*
  * CompactFlash cards and their brethern pretend to be removable hard disks,
  * but they never have a slave unit, and they don't have doorlock mechanisms.
- * This test catches them, and is invoked elsewhere when setting appropriate config bits.
+ * This test catches them, and is invoked elsewhere when setting appropriate
+ * config bits.
  */
-int drive_is_flashcard (ide_drive_t *drive);
+extern int drive_is_flashcard(ide_drive_t *);
 
-int ide_spin_wait_hwgroup (ide_drive_t *drive);
-void ide_timer_expiry (unsigned long data);
-void ide_intr (int irq, void *dev_id, struct pt_regs *regs);
-void do_ide_request (request_queue_t * q);
-void ide_init_subdrivers (void);
+extern int ide_spin_wait_hwgroup(ide_drive_t *);
+extern void ide_timer_expiry(unsigned long);
+extern void ide_intr(int irq, void *dev_id, struct pt_regs *regs);
+extern void do_ide_request(request_queue_t *);
+extern void ide_init_subdrivers(void);
 
-#ifndef _IDE_C
 extern struct block_device_operations ide_fops[];
 extern ide_proc_entry_t generic_subdriver_entries[];
-#endif
 
-int ide_reinit_drive (ide_drive_t *drive);
+extern int ide_attach_drive(ide_drive_t *);
+
+extern int ideprobe_init(void);
+extern int idedisk_attach(ide_drive_t *);
+extern int idedisk_init(void);
+extern int ide_cdrom_attach(ide_drive_t *);
+extern int ide_cdrom_init(void);
+extern int idetape_attach(ide_drive_t *);
+extern int idetape_init(void);
+extern int idefloppy_attach(ide_drive_t *);
+extern int idefloppy_init(void);
+extern int idescsi_attach(ide_drive_t *);
+extern int idescsi_init(void);
+
+extern void ide_scan_pcibus(int scan_direction) __init;
+extern int ide_pci_register_driver(struct pci_driver *driver);
+extern void ide_pci_unregister_driver(struct pci_driver *driver);
+
+extern void default_hwif_iops(ide_hwif_t *);
+extern void default_hwif_mmiops(ide_hwif_t *);
+extern void default_hwif_transport(ide_hwif_t *);
+
+
+extern int ide_register_module(ide_module_t *module);
+extern void ide_unregister_module(ide_module_t *module);
+extern ide_drive_t *ide_scan_devices(u8, const char *, ide_driver_t *, int);
+extern int ide_register_subdriver(ide_drive_t *, ide_driver_t *, int /* ver */);
+extern int ide_unregister_subdriver(ide_drive_t *);
+extern int ide_replace_subdriver(ide_drive_t *, const char * /* driver*/);
 
-#ifdef _IDE_C
-#ifdef CONFIG_BLK_DEV_IDE
-int ideprobe_init (void);
-#endif /* CONFIG_BLK_DEV_IDE */
-#ifdef CONFIG_BLK_DEV_IDEDISK
-int idedisk_reinit (ide_drive_t *drive);
-int idedisk_init (void);
-#endif /* CONFIG_BLK_DEV_IDEDISK */
-#ifdef CONFIG_BLK_DEV_IDECD
-int ide_cdrom_reinit (ide_drive_t *drive);
-int ide_cdrom_init (void);
-#endif /* CONFIG_BLK_DEV_IDECD */
-#ifdef CONFIG_BLK_DEV_IDETAPE
-int idetape_reinit (ide_drive_t *drive);
-int idetape_init (void);
-#endif /* CONFIG_BLK_DEV_IDETAPE */
-#ifdef CONFIG_BLK_DEV_IDEFLOPPY
-int idefloppy_reinit (ide_drive_t *drive);
-int idefloppy_init (void);
-#endif /* CONFIG_BLK_DEV_IDEFLOPPY */
-#ifdef CONFIG_BLK_DEV_IDESCSI
-int idescsi_reinit (ide_drive_t *drive);
-int idescsi_init (void);
-#endif /* CONFIG_BLK_DEV_IDESCSI */
-#endif /* _IDE_C */
-
-int ide_register_module (ide_module_t *module);
-void ide_unregister_module (ide_module_t *module);
-ide_drive_t *ide_scan_devices (byte media, const char *name, ide_driver_t *driver, int n);
-int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int version);
-int ide_unregister_subdriver (ide_drive_t *drive);
-int ide_replace_subdriver(ide_drive_t *drive, const char *driver);
+#ifdef CONFIG_PROC_FS
+typedef struct ide_pci_host_proc_s {
+	char				*name;
+        u8				set;
+	get_info_t			*get_info;
+	struct proc_dir_entry		*parent;
+	struct ide_pci_host_proc_s	*next;
+} ide_pci_host_proc_t;
+
+void ide_pci_register_host_proc(ide_pci_host_proc_t *);
+#endif /* CONFIG_PROC_FS */
 
-#ifdef CONFIG_BLK_DEV_IDEPCI
 #define ON_BOARD		1
 #define NEVER_BOARD		0
+
 #ifdef CONFIG_BLK_DEV_OFFBOARD
 #  define OFF_BOARD		ON_BOARD
 #else /* CONFIG_BLK_DEV_OFFBOARD */
 #  define OFF_BOARD		NEVER_BOARD
 #endif /* CONFIG_BLK_DEV_OFFBOARD */
 
-unsigned long ide_find_free_region (unsigned short size) __init;
-void ide_scan_pcibus (int scan_direction) __init;
-#endif
-#ifdef CONFIG_BLK_DEV_IDEDMA
+#define NODMA 0
+#define NOAUTODMA 1
+#define AUTODMA 2
+#define EOL 255
+
+typedef struct ide_pci_enablebit_s {
+	u8	reg;	/* byte pci reg holding the enable-bit */
+	u8	mask;	/* mask to isolate the enable-bit */
+	u8	val;	/* value of masked reg when "enabled" */
+} ide_pci_enablebit_t;
+
+typedef struct ide_pci_device_s {
+	u16			vendor;
+	u16			device;
+	char			*name;
+	void			(*init_setup)(struct pci_dev *, struct ide_pci_device_s *);
+	unsigned int		(*init_chipset)(struct pci_dev *, const char *);
+	void			(*init_iops)(ide_hwif_t *);
+	void                    (*init_hwif)(ide_hwif_t *);
+	void			(*init_dma)(ide_hwif_t *, unsigned long);
+	u8			channels;
+	u8			autodma;
+	ide_pci_enablebit_t	enablebits[2];
+	u8			bootable;
+	unsigned int		extra;
+	struct ide_pci_device_s	*next;
+} ide_pci_device_t;
+
+extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
+extern void ide_setup_pci_devices(struct pci_dev *, struct pci_dev *, ide_pci_device_t *);
+
 #define BAD_DMA_DRIVE		0
 #define GOOD_DMA_DRIVE		1
-int ide_build_dmatable (ide_drive_t *drive, ide_dma_action_t func);
-void ide_destroy_dmatable (ide_drive_t *drive);
-ide_startstop_t ide_dma_intr (ide_drive_t *drive);
-int check_drive_lists (ide_drive_t *drive, int good_bad);
-int report_drive_dmaing (ide_drive_t *drive);
-int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive);
-int ide_release_dma (ide_hwif_t *hwif);
-void ide_setup_dma (ide_hwif_t *hwif, unsigned long dmabase, unsigned int num_ports) __init;
-unsigned long ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const char *name) __init;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
+extern int ide_build_dmatable(ide_drive_t *, struct request *, int);
+extern void ide_destroy_dmatable(ide_drive_t *);
+extern ide_startstop_t ide_dma_intr(ide_drive_t *);
+extern int ide_release_dma(ide_hwif_t *);
+extern void ide_setup_dma(ide_hwif_t *, unsigned long, unsigned int);
+
+extern int __ide_dma_host_off(ide_drive_t *);
+extern int __ide_dma_off_quietly(ide_drive_t *);
+extern int __ide_dma_off(ide_drive_t *);
+extern int __ide_dma_host_on(ide_drive_t *);
+extern int __ide_dma_on(ide_drive_t *);
+extern int __ide_dma_check(ide_drive_t *);
+extern int __ide_dma_read(ide_drive_t *);
+extern int __ide_dma_write(ide_drive_t *);
+extern int __ide_dma_begin(ide_drive_t *);
+extern int __ide_dma_end(ide_drive_t *);
+extern int __ide_dma_test_irq(ide_drive_t *);
+extern int __ide_dma_bad_drive(ide_drive_t *);
+extern int __ide_dma_good_drive(ide_drive_t *);
+extern int __ide_dma_count(ide_drive_t *);
+extern int __ide_dma_verbose(ide_drive_t *);
+extern int __ide_dma_retune(ide_drive_t *);
+extern int __ide_dma_lostirq(ide_drive_t *);
+extern int __ide_dma_timeout(ide_drive_t *);
+#else
+static inline void ide_release_dma(ide_hwif_t *x) {;}
 #endif
 
-void hwif_unregister (ide_hwif_t *hwif);
+extern void hwif_unregister(ide_hwif_t *);
+
+extern void export_ide_init_queue(ide_drive_t *);
+extern u8 export_probe_for_drive(ide_drive_t *);
+extern int probe_hwif_init(ide_hwif_t *);
+
+static inline void *ide_get_hwifdata (ide_hwif_t * hwif)
+{
+	return hwif->hwif_data;
+}
+
+static inline void ide_set_hwifdata (ide_hwif_t * hwif, void *data)
+{
+	hwif->hwif_data = data;
+}
+
+/* ide-lib.c */
+extern u8 ide_dma_speed(ide_drive_t *drive, u8 mode);
+extern u8 ide_rate_filter(u8 mode, u8 speed);
+extern int ide_dma_enable(ide_drive_t *drive);
+extern char *ide_xfer_verbose(u8 xfer_rate);
+extern void ide_toggle_bounce(ide_drive_t *drive, int on);
+extern int ide_set_xfer_rate(ide_drive_t *drive, u8 rate);
+
+#define ide_lock		(io_request_lock)
+#define DRIVE_LOCK(drive)       ((drive)->queue.queue_lock)
 
-void export_ide_init_queue (ide_drive_t *drive);
-byte export_probe_for_drive (ide_drive_t *drive);
 
 #endif /* _IDE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/if.h linux-2.4.21-pre6/include/linux/if.h
--- linux-2.4.20/include/linux/if.h	2001-11-22 19:47:07.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/if.h	2003-03-26 23:49:35.000000000 +0000
@@ -21,6 +21,7 @@
 
 #include <linux/types.h>		/* for "__kernel_caddr_t" et al	*/
 #include <linux/socket.h>		/* for "struct sockaddr" et al	*/
+#include <linux/hdlc/ioctl.h>
 
 /* Standard interface flags (netdevice->flags). */
 #define	IFF_UP		0x1		/* interface is up		*/
@@ -48,6 +49,29 @@
 /* Private (from user) interface flags (netdevice->priv_flags). */
 #define IFF_802_1Q_VLAN 0x1             /* 802.1Q VLAN device.          */
 
+
+#define IF_GET_IFACE	0x0001		/* for querying only */
+#define IF_GET_PROTO	0x0002
+
+/* For definitions see hdlc.h */
+#define IF_IFACE_V35	0x1000		/* V.35 serial interface	*/
+#define IF_IFACE_V24	0x1001		/* V.24 serial interface	*/
+#define IF_IFACE_X21	0x1002		/* X.21 serial interface	*/
+#define IF_IFACE_T1	0x1003		/* T1 telco serial interface	*/
+#define IF_IFACE_E1	0x1004		/* E1 telco serial interface	*/
+#define IF_IFACE_SYNC_SERIAL 0x1005	/* cant'b be set by software	*/
+
+/* For definitions see hdlc.h */
+#define IF_PROTO_HDLC	0x2000		/* raw HDLC protocol		*/
+#define IF_PROTO_PPP	0x2001		/* PPP protocol			*/
+#define IF_PROTO_CISCO	0x2002		/* Cisco HDLC protocol		*/
+#define IF_PROTO_FR	0x2003		/* Frame Relay protocol		*/
+#define IF_PROTO_FR_ADD_PVC 0x2004	/*    Create FR PVC		*/
+#define IF_PROTO_FR_DEL_PVC 0x2005	/*    Delete FR PVC		*/
+#define IF_PROTO_X25	0x2006		/* X.25				*/
+
+
+
 /*
  *	Device mapping structure. I'd just gone off and designed a 
  *	beautiful scheme using only loadable modules with arguments
@@ -69,6 +93,23 @@
 	/* 3 bytes spare */
 };
 
+struct if_settings
+{
+	unsigned int type;	/* Type of physical device or protocol */
+	unsigned int size;	/* Size of the data allocated by the caller */
+	union {
+		/* {atm/eth/dsl}_settings anyone ? */
+		raw_hdlc_proto		*raw_hdlc;
+		cisco_proto		*cisco;
+		fr_proto		*fr;
+		fr_proto_pvc		*fr_pvc;
+
+		/* interface settings */
+		sync_serial_settings	*sync;
+		te1_settings		*te1;
+	} ifs_ifsu;
+};
+
 /*
  * Interface request structure used for socket
  * ioctl's.  All interface ioctl's must have parameter
@@ -98,6 +139,7 @@
 		char	ifru_slave[IFNAMSIZ];	/* Just fits the size */
 		char	ifru_newname[IFNAMSIZ];
 		char *	ifru_data;
+		struct	if_settings ifru_settings;
 	} ifr_ifru;
 };
 
@@ -117,6 +159,7 @@
 #define ifr_bandwidth	ifr_ifru.ifru_ivalue    /* link bandwidth	*/
 #define ifr_qlen	ifr_ifru.ifru_ivalue	/* Queue length 	*/
 #define ifr_newname	ifr_ifru.ifru_newname	/* New name		*/
+#define ifr_settings	ifr_ifru.ifru_settings	/* Device/proto settings*/
 
 /*
  * Structure used in SIOCGIFCONF request.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/if_bonding.h linux-2.4.21-pre6/include/linux/if_bonding.h
--- linux-2.4.20/include/linux/if_bonding.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/if_bonding.h	2003-03-26 23:49:20.000000000 +0000
@@ -37,9 +37,10 @@
 
 #define BOND_CHECK_MII_STATUS	(SIOCGMIIPHY)
 
-#define BOND_MODE_ROUNDROBIN    0
-#define BOND_MODE_ACTIVEBACKUP  1
-#define BOND_MODE_XOR           2 
+#define BOND_MODE_ROUNDROBIN	0
+#define BOND_MODE_ACTIVEBACKUP	1
+#define BOND_MODE_XOR		2
+#define BOND_MODE_BROADCAST	3
 
 /* each slave's link has 4 states */
 #define BOND_LINK_UP    0           /* link is up and running */
@@ -74,6 +75,7 @@
 	struct slave *prev;
 	struct net_device *dev;
 	short  delay;
+	unsigned long jiffies;	
 	char   link;    /* one of BOND_LINK_XXXX */
 	char   state;   /* one of BOND_STATE_XXXX */
 	unsigned short original_flags;
@@ -93,6 +95,8 @@
 	slave_t *next;
 	slave_t *prev;
 	slave_t *current_slave;
+	slave_t *primary_slave;
+	slave_t *current_arp_slave;
 	__s32 slave_cnt;
 	rwlock_t lock;
 	rwlock_t ptrlock;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/if_ether.h linux-2.4.21-pre6/include/linux/if_ether.h
--- linux-2.4.20/include/linux/if_ether.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/if_ether.h	2003-03-26 23:49:40.000000000 +0000
@@ -85,6 +85,7 @@
 #define ETH_P_CONTROL	0x0016		/* Card specific control frames */
 #define ETH_P_IRDA	0x0017		/* Linux-IrDA			*/
 #define ETH_P_ECONET	0x0018		/* Acorn Econet			*/
+#define ETH_P_HDLC	0x0019		/* HDLC frames			*/
 
 /*
  *	This is an Ethernet frame header.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/in6.h linux-2.4.21-pre6/include/linux/in6.h
--- linux-2.4.20/include/linux/in6.h	2001-11-22 19:46:18.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/in6.h	2003-03-26 23:49:41.000000000 +0000
@@ -156,6 +156,7 @@
 #define IPV6_MTU_DISCOVER	23
 #define IPV6_MTU		24
 #define IPV6_RECVERR		25
+#define IPV6_V6ONLY		26
 
 /* IPV6_MTU_DISCOVER values */
 #define IPV6_PMTUDISC_DONT		0
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/input.h linux-2.4.21-pre6/include/linux/input.h
--- linux-2.4.20/include/linux/input.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/input.h	2003-03-26 23:49:34.000000000 +0000
@@ -426,6 +426,7 @@
  */
 
 #define MSC_SERIAL		0x00
+#define MSC_PULSELED		0x01
 #define MSC_MAX			0x07
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/interrupt.h linux-2.4.21-pre6/include/linux/interrupt.h
--- linux-2.4.20/include/linux/interrupt.h	2001-11-22 19:46:19.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/interrupt.h	2003-03-26 23:48:57.000000000 +0000
@@ -10,6 +10,7 @@
 #include <asm/bitops.h>
 #include <asm/atomic.h>
 #include <asm/ptrace.h>
+#include <asm/system.h>
 
 struct irqaction {
 	void (*handler)(int, void *, struct pt_regs *);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/ipmi.h linux-2.4.21-pre6/include/linux/ipmi.h
--- linux-2.4.20/include/linux/ipmi.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/ipmi.h	2003-03-26 23:49:25.000000000 +0000
@@ -0,0 +1,516 @@
+/*
+ * ipmi.h
+ *
+ * MontaVista IPMI interface
+ *
+ * Author: MontaVista Software, Inc.
+ *         Corey Minyard <minyard@mvista.com>
+ *         source@mvista.com
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; either version 2 of the License, or (at your
+ *  option) any later version.
+ *
+ *
+ *  THIS 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.
+ *
+ *  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 __LINUX_IPMI_H
+#define __LINUX_IPMI_H
+
+#include <linux/ipmi_msgdefs.h>
+
+/*
+ * This file describes an interface to an IPMI driver.  You have to
+ * have a fairly good understanding of IPMI to use this, so go read
+ * the specs first before actually trying to do anything.
+ *
+ * With that said, this driver provides a multi-user interface to the
+ * IPMI driver, and it allows multiple IPMI physical interfaces below
+ * the driver.  The physical interfaces bind as a lower layer on the
+ * driver.  They appear as interfaces to the application using this
+ * interface.
+ *
+ * Multi-user means that multiple applications may use the driver,
+ * send commands, receive responses, etc.  The driver keeps track of
+ * commands the user sends and tracks the responses.  The responses
+ * will go back to the application that send the command.  If the
+ * response doesn't come back in time, the driver will return a
+ * timeout error response to the application.  Asynchronous events
+ * from the BMC event queue will go to all users bound to the driver.
+ * The incoming event queue in the BMC will automatically be flushed
+ * if it becomes full and it is queried once a second to see if
+ * anything is in it.  Incoming commands to the driver will get
+ * delivered as commands.
+ *
+ * This driver provides two main interfaces: one for in-kernel
+ * applications and another for userland applications.  The
+ * capabilities are basically the same for both interface, although
+ * the interfaces are somewhat different.  The stuff in the
+ * #ifdef KERNEL below is the in-kernel interface.  The userland
+ * interface is defined later in the file.  */
+
+
+
+/*
+ * This is an overlay for all the address types, so it's easy to
+ * determine the actual address type.  This is kind of like addresses
+ * work for sockets.
+ */
+#define IPMI_MAX_ADDR_SIZE 32
+struct ipmi_addr
+{
+	 /* Try to take these from the "Channel Medium Type" table
+	    in section 6.5 of the IPMI 1.5 manual. */
+	int   addr_type;
+	short channel;
+	char  data[IPMI_MAX_ADDR_SIZE];
+};
+
+/*
+ * When the address is not used, the type will be set to this value.
+ * The channel is the BMC's channel number for the channel (usually
+ * 0), or IPMC_BMC_CHANNEL if communicating directly with the BMC.
+ */
+#define IPMI_SYSTEM_INTERFACE_ADDR_TYPE	0x0c
+struct ipmi_system_interface_addr
+{
+	int           addr_type;
+	short         channel;
+	unsigned char lun;
+};
+
+/* An IPMB Address. */
+#define IPMI_IPMB_ADDR_TYPE		0x01
+/* Used for broadcast get device id as described in section 17.9 of the
+   IPMI 1.5 manual. */ 
+#define IPMI_IPMB_BROADCAST_ADDR_TYPE	0x41
+struct ipmi_ipmb_addr
+{
+	int           addr_type;
+	short         channel;
+	unsigned char slave_addr;
+	unsigned char lun;
+};
+
+
+/*
+ * Channel for talking directly with the BMC.  When using this
+ * channel, This is for the system interface address type only.  FIXME
+ * - is this right, or should we use -1?
+ */
+#define IPMI_BMC_CHANNEL  0xf
+#define IPMI_NUM_CHANNELS 0x10
+
+
+/*
+ * A raw IPMI message without any addressing.  This covers both
+ * commands and responses.  The completion code is always the first
+ * byte of data in the response (as the spec shows the messages laid
+ * out).
+ */
+struct ipmi_msg
+{
+	unsigned char  netfn;
+	unsigned char  cmd;
+	unsigned short data_len;
+	unsigned char  *data;
+};
+
+/*
+ * Various defines that are useful for IPMI applications.
+ */
+#define IPMI_INVALID_CMD_COMPLETION_CODE	0xC1
+#define IPMI_TIMEOUT_COMPLETION_CODE		0xC3
+#define IPMI_UNKNOWN_ERR_COMPLETION_CODE	0xff
+
+
+/*
+ * Receive types for messages coming from the receive interface.  This
+ * is used for the receive in-kernel interface and in the receive
+ * IOCTL.
+ */
+#define IPMI_RESPONSE_RECV_TYPE		1 /* A response to a command */
+#define IPMI_ASYNC_EVENT_RECV_TYPE	2 /* Something from the event queue */
+#define IPMI_CMD_RECV_TYPE		3 /* A command from somewhere else */
+/* Note that async events and received commands do not have a completion
+   code as the first byte of the incoming data, unlike a response. */
+
+
+
+#ifdef __KERNEL__
+
+/*
+ * The in-kernel interface.
+ */
+#include <linux/list.h>
+
+/* Opaque type for a IPMI message user.  One of these is needed to
+   send and receive messages. */
+typedef struct ipmi_user *ipmi_user_t;
+
+/*
+ * Stuff coming from the recieve interface comes as one of these.
+ * They are allocated, the receiver must free them with
+ * ipmi_free_recv_msg() when done with the message.  The link is not
+ * used after the message is delivered, so the upper layer may use the
+ * link to build a linked list, if it likes.
+ */
+struct ipmi_recv_msg
+{
+	struct list_head link;
+
+	/* The type of message as defined in the "Receive Types"
+           defines above. */
+	int              recv_type;
+
+	ipmi_user_t      user;
+	struct ipmi_addr addr;
+	long             msgid;
+	struct ipmi_msg  msg;
+
+	/* Call this when done with the message.  It will presumably free
+	   the message and do any other necessary cleanup. */
+	void (*done)(struct ipmi_recv_msg *msg);
+
+	/* Place-holder for the data, don't make any assumptions about
+	   the size or existance of this, since it may change. */
+	unsigned char   msg_data[IPMI_MAX_MSG_LENGTH];
+};
+
+/* Allocate and free the receive message. */
+static inline void ipmi_free_recv_msg(struct ipmi_recv_msg *msg)
+{
+	msg->done(msg);
+}
+struct ipmi_recv_msg *ipmi_alloc_recv_msg(void);
+
+struct ipmi_user_hndl
+{
+        /* Routine type to call when a message needs to be routed to
+	   the upper layer.  This will be called with some locks held,
+	   the only IPMI routines that can be called are ipmi_request
+	   and the alloc/free operations. */
+	void (*ipmi_recv_hndl)(struct ipmi_recv_msg *msg,
+			       void                 *handler_data);
+
+	/* Called when the interface detects a watchdog pre-timeout.  If
+	   this is NULL, it will be ignored for the user. */
+	void (*ipmi_watchdog_pretimeout)(void *handler_data);
+};
+
+/* Create a new user of the IPMI layer on the given interface number. */
+int ipmi_create_user(unsigned int          if_num,
+		     struct ipmi_user_hndl *handler,
+		     void                  *handler_data,
+		     ipmi_user_t           *user);
+
+/* Destroy the given user of the IPMI layer. */
+int ipmi_destroy_user(ipmi_user_t user);
+
+/* Get the IPMI version of the BMC we are talking to. */
+void ipmi_get_version(ipmi_user_t   user,
+		      unsigned char *major,
+		      unsigned char *minor);
+
+/* Set and get the slave address and LUN that we will use for our
+   source messages.  Note that this affects the interface, not just
+   this user, so it will affect all users of this interface.  This is
+   so some initialization code can come in and do the OEM-specific
+   things it takes to determine your address (if not the BMC) and set
+   it for everyone else. */
+void ipmi_set_my_address(ipmi_user_t   user,
+			 unsigned char address);
+unsigned char ipmi_get_my_address(ipmi_user_t user);
+void ipmi_set_my_LUN(ipmi_user_t   user,
+		     unsigned char LUN);
+unsigned char ipmi_get_my_LUN(ipmi_user_t user);
+
+/*
+ * Send a command request from the given user.  The address is the
+ * proper address for the channel type.  If this is a command, then
+ * the message response comes back, the receive handler for this user
+ * will be called with the given msgid value in the recv msg.  If this
+ * is a response to a command, then the msgid will be used as the
+ * sequence number for the response (truncated if necessary), so when
+ * sending a response you should use the sequence number you received
+ * in the msgid field of the received command.  If the priority is >
+ * 0, the message will go into a high-priority queue and be sent
+ * first.  Otherwise, it goes into a normal-priority queue.
+ */
+int ipmi_request(ipmi_user_t      user,
+		 struct ipmi_addr *addr,
+		 long             msgid,
+		 struct ipmi_msg  *msg,
+		 int              priority);
+
+/*
+ * Like ipmi_request, but lets you specify the slave return address.
+ */
+int ipmi_request_with_source(ipmi_user_t      user,
+			     struct ipmi_addr *addr,
+			     long             msgid,
+			     struct ipmi_msg  *msg,
+			     int              priority,
+			     unsigned char    source_address,
+			     unsigned char    source_lun);
+
+/*
+ * Like ipmi_request, but with messages supplied.  This will not
+ * allocate any memory, and the messages may be statically allocated
+ * (just make sure to do the "done" handling on them).  Note that this
+ * is primarily for the watchdog timer, since it should be able to
+ * send messages even if no memory is available.  This is subject to
+ * change as the system changes, so don't use it unless you REALLY
+ * have to.
+ */
+int ipmi_request_supply_msgs(ipmi_user_t          user,
+			     struct ipmi_addr     *addr,
+			     long                 msgid,
+			     struct ipmi_msg      *msg,
+			     void                 *supplied_smi,
+			     struct ipmi_recv_msg *supplied_recv,
+			     int                  priority);
+
+/*
+ * When commands come in to the SMS, the user can register to receive
+ * them.  Only one user can be listening on a specific netfn/cmd pair
+ * at a time, you will get an EBUSY error if the command is already
+ * registered.  If a command is received that does not have a user
+ * registered, the driver will automatically return the proper
+ * error.
+ */
+int ipmi_register_for_cmd(ipmi_user_t   user,
+			  unsigned char netfn,
+			  unsigned char cmd);
+int ipmi_unregister_for_cmd(ipmi_user_t   user,
+			    unsigned char netfn,
+			    unsigned char cmd);
+
+/*
+ * When the user is created, it will not receive IPMI events by
+ * default.  The user must set this to TRUE to get incoming events.
+ * The first user that sets this to TRUE will receive all events that
+ * have been queued while no one was waiting for events.
+ */
+int ipmi_set_gets_events(ipmi_user_t user, int val);
+
+/*
+ * Register the given user to handle all received IPMI commands.  This
+ * will fail if anyone is registered as a command receiver or if
+ * another is already registered to receive all commands.  NOTE THAT
+ * THIS IS FOR EMULATION USERS ONLY, DO NOT USER THIS FOR NORMAL
+ * STUFF.
+ */
+int ipmi_register_all_cmd_rcvr(ipmi_user_t user);
+int ipmi_unregister_all_cmd_rcvr(ipmi_user_t user);
+
+
+/*
+ * Called when a new SMI is registered.  This will also be called on
+ * every existing interface when a new watcher is registered with
+ * ipmi_smi_watcher_register().
+ */
+struct ipmi_smi_watcher
+{
+	struct list_head link;
+
+	/* These two are called with read locks held for the interface
+	   the watcher list.  So you can add and remove users from the
+	   IPMI interface, send messages, etc., but you cannot add
+	   or remove SMI watchers or SMI interfaces. */
+	void (*new_smi)(int if_num);
+	void (*smi_gone)(int if_num);
+};
+
+int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher);
+int ipmi_smi_watcher_unregister(struct ipmi_smi_watcher *watcher);
+
+/* The following are various helper functions for dealing with IPMI
+   addresses. */
+
+/* Return the maximum length of an IPMI address given it's type. */
+unsigned int ipmi_addr_length(int addr_type);
+
+/* Validate that the given IPMI address is valid. */
+int ipmi_validate_addr(struct ipmi_addr *addr, int len);
+
+/* Return 1 if the given addresses are equal, 0 if not. */
+int ipmi_addr_equal(struct ipmi_addr *addr1, struct ipmi_addr *addr2);
+
+#endif /* __KERNEL__ */
+
+
+/*
+ * The userland interface
+ */
+
+/*
+ * The userland interface for the IPMI driver is a standard character
+ * device, with each instance of an interface registered as a minor
+ * number under the major character device.
+ *
+ * The read and write calls do not work, to get messages in and out
+ * requires ioctl calls because of the complexity of the data.  select
+ * and poll do work, so you can wait for input using the file
+ * descriptor, you just can use read to get it.
+ *
+ * In general, you send a command down to the interface and receive
+ * responses back.  You can use the msgid value to correlate commands
+ * and responses, the driver will take care of figuring out which
+ * incoming messages are for which command and find the proper msgid
+ * value to report.  You will only receive reponses for commands you
+ * send.  Asynchronous events, however, go to all open users, so you
+ * must be ready to handle these (or ignore them if you don't care).
+ *
+ * The address type depends upon the channel type.  When talking
+ * directly to the BMC (IPMC_BMC_CHANNEL), the address is ignored
+ * (IPMI_UNUSED_ADDR_TYPE).  When talking to an IPMB channel, you must
+ * supply a valid IPMB address with the addr_type set properly.
+ *
+ * When talking to normal channels, the driver takes care of the
+ * details of formatting and sending messages on that channel.  You do
+ * not, for instance, have to format a send command, you just send
+ * whatever command you want to the channel, the driver will create
+ * the send command, automatically issue receive command and get even
+ * commands, and pass those up to the proper user.
+ */
+
+
+/* The magic IOCTL value for this interface. */
+#define IPMI_IOC_MAGIC 'i'
+
+
+/* Messages sent to the interface are this format. */
+struct ipmi_req
+{
+	unsigned char *addr; /* Address to send the message to. */
+	unsigned int  addr_len;
+
+	long    msgid; /* The sequence number for the message.  This
+			  exact value will be reported back in the
+			  response to this request if it is a command.
+			  If it is a response, this will be used as
+			  the sequence value for the response.  */
+
+	struct ipmi_msg msg;
+};
+/*
+ * Send a message to the interfaces.  error values are:
+ *   - EFAULT - an address supplied was invalid.
+ *   - EINVAL - The address supplied was not valid, or the command
+ *              was not allowed.
+ *   - EMSGSIZE - The message to was too large.
+ *   - ENOMEM - Buffers could not be allocated for the command.
+ */
+#define IPMICTL_SEND_COMMAND		_IOR(IPMI_IOC_MAGIC, 13,	\
+					     struct ipmi_req)
+
+/* Messages received from the interface are this format. */
+struct ipmi_recv
+{
+	int     recv_type; /* Is this a command, response or an
+			      asyncronous event. */
+
+	unsigned char *addr;    /* Address the message was from is put
+				   here.  The caller must supply the
+				   memory. */
+	unsigned int  addr_len; /* The size of the address buffer.
+				   The caller supplies the full buffer
+				   length, this value is updated to
+				   the actual message length when the
+				   message is received. */
+
+	long    msgid; /* The sequence number specified in the request
+			  if this is a response.  If this is a command,
+			  this will be the sequence number from the
+			  command. */
+
+	struct ipmi_msg msg; /* The data field must point to a buffer.
+				The data_size field must be set to the
+				size of the message buffer.  The
+				caller supplies the full buffer
+				length, this value is updated to the
+				actual message length when the message
+				is received. */
+};
+
+/*
+ * Receive a message.  error values:
+ *  - EAGAIN - no messages in the queue.
+ *  - EFAULT - an address supplied was invalid.
+ *  - EINVAL - The address supplied was not valid.
+ *  - EMSGSIZE - The message to was too large to fit into the message buffer,
+ *               the message will be left in the buffer. */
+#define IPMICTL_RECEIVE_MSG		_IOWR(IPMI_IOC_MAGIC, 12,	\
+					      struct ipmi_recv)
+
+/*
+ * Like RECEIVE_MSG, but if the message won't fit in the buffer, it
+ * will truncate the contents instead of leaving the data in the
+ * buffer.
+ */
+#define IPMICTL_RECEIVE_MSG_TRUNC	_IOWR(IPMI_IOC_MAGIC, 11,	\
+					      struct ipmi_recv)
+
+/* Register to get commands from other entities on this interface. */
+struct ipmi_cmdspec
+{
+	unsigned char netfn;
+	unsigned char cmd;
+};
+
+/* 
+ * Register to receive a specific command.  error values:
+ *   - EFAULT - an address supplied was invalid.
+ *   - EBUSY - The netfn/cmd supplied was already in use.
+ *   - ENOMEM - could not allocate memory for the entry.
+ */
+#define IPMICTL_REGISTER_FOR_CMD	_IOR(IPMI_IOC_MAGIC, 14,	\
+					     struct ipmi_cmdspec)
+/*
+ * Unregister a regsitered command.  error values:
+ *  - EFAULT - an address supplied was invalid.
+ *  - ENOENT - The netfn/cmd was not found registered for this user.
+ */
+#define IPMICTL_UNREGISTER_FOR_CMD	_IOR(IPMI_IOC_MAGIC, 15,	\
+					     struct ipmi_cmdspec)
+
+/* 
+ * Set whether this interface receives events.  Note that the first
+ * user registered for events will get all pending events for the
+ * interface.  error values:
+ *  - EFAULT - an address supplied was invalid.
+ */
+#define IPMICTL_SET_GETS_EVENTS_CMD	_IOR(IPMI_IOC_MAGIC, 16, int)
+
+/*
+ * Set and get the slave address and LUN that we will use for our
+ * source messages.  Note that this affects the interface, not just
+ * this user, so it will affect all users of this interface.  This is
+ * so some initialization code can come in and do the OEM-specific
+ * things it takes to determine your address (if not the BMC) and set
+ * it for everyone else.  You should probably leave the LUN alone.
+ */
+#define IPMICTL_SET_MY_ADDRESS_CMD	_IOR(IPMI_IOC_MAGIC, 17, unsigned int)
+#define IPMICTL_GET_MY_ADDRESS_CMD	_IOR(IPMI_IOC_MAGIC, 18, unsigned int)
+#define IPMICTL_SET_MY_LUN_CMD		_IOR(IPMI_IOC_MAGIC, 19, unsigned int)
+#define IPMICTL_GET_MY_LUN_CMD		_IOR(IPMI_IOC_MAGIC, 20, unsigned int)
+
+#endif /* __LINUX_IPMI_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/ipmi_msgdefs.h linux-2.4.21-pre6/include/linux/ipmi_msgdefs.h
--- linux-2.4.20/include/linux/ipmi_msgdefs.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/ipmi_msgdefs.h	2003-03-26 23:49:07.000000000 +0000
@@ -0,0 +1,58 @@
+/*
+ * ipmi_smi.h
+ *
+ * MontaVista IPMI system management interface
+ *
+ * Author: MontaVista Software, Inc.
+ *         Corey Minyard <minyard@mvista.com>
+ *         source@mvista.com
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; either version 2 of the License, or (at your
+ *  option) any later version.
+ *
+ *
+ *  THIS 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.
+ *
+ *  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 __LINUX_IPMI_MSGDEFS_H
+#define __LINUX_IPMI_MSGDEFS_H
+
+/* Various definitions for IPMI messages used by almost everything in
+   the IPMI stack. */
+
+#define IPMI_NETFN_APP_REQUEST	0x06
+#define IPMI_NETFN_APP_RESPONSE	0x07
+
+#define IPMI_BMC_SLAVE_ADDR	0x20
+
+#define IPMI_GET_DEVICE_ID_CMD		0x01
+
+#define IPMI_CLEAR_MSG_FLAGS_CMD	0x30
+#define IPMI_GET_MSG_FLAGS_CMD		0x31
+#define IPMI_SEND_MSG_CMD		0x34
+#define IPMI_GET_MSG_CMD		0x33
+
+#define IPMI_SET_BMC_GLOBAL_ENABLES_CMD	0x2e
+#define IPMI_GET_BMC_GLOBAL_ENABLES_CMD	0x2f
+#define IPMI_READ_EVENT_MSG_BUFFER_CMD	0x35
+
+#define IPMI_MAX_MSG_LENGTH	80
+
+#endif /* __LINUX_IPMI_MSGDEFS_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/ipmi_smi.h linux-2.4.21-pre6/include/linux/ipmi_smi.h
--- linux-2.4.20/include/linux/ipmi_smi.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/ipmi_smi.h	2003-03-26 23:49:50.000000000 +0000
@@ -0,0 +1,144 @@
+/*
+ * ipmi_smi.h
+ *
+ * MontaVista IPMI system management interface
+ *
+ * Author: MontaVista Software, Inc.
+ *         Corey Minyard <minyard@mvista.com>
+ *         source@mvista.com
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; either version 2 of the License, or (at your
+ *  option) any later version.
+ *
+ *
+ *  THIS 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.
+ *
+ *  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 __LINUX_IPMI_SMI_H
+#define __LINUX_IPMI_SMI_H
+
+#include <linux/ipmi_msgdefs.h>
+
+/* This files describes the interface for IPMI system management interface
+   drivers to bind into the IPMI message handler. */
+
+/* Structure for the low-level drivers. */
+typedef struct ipmi_smi *ipmi_smi_t;
+
+/*
+ * Messages to/from the lower layer.  The smi interface will take one
+ * of these to send. After the send has occurred and a response has
+ * been received, it will report this same data structure back up to
+ * the upper layer.  If an error occurs, it should fill in the
+ * response with an error code in the completion code location. When
+ * asyncronous data is received, one of these is allocated, the
+ * data_size is set to zero and the response holds the data from the
+ * get message or get event command that the interface initiated.
+ * Note that it is the interfaces responsibility to detect
+ * asynchronous data and messages and request them from the
+ * interface.
+ */
+struct ipmi_smi_msg
+{
+	struct list_head link;
+
+	long    msgid;
+	void    *user_data;
+
+	/* If 0, add to the end of the queue.  If 1, add to the beginning. */
+	int     prio;
+
+	int           data_size;
+	unsigned char data[IPMI_MAX_MSG_LENGTH];
+
+	int           rsp_size;
+	unsigned char rsp[IPMI_MAX_MSG_LENGTH];
+
+	/* Will be called when the system is done with the message
+           (presumably to free it). */
+	void (*done)(struct ipmi_smi_msg *msg);
+};
+
+struct ipmi_smi_handlers
+{
+	/* Called to enqueue an SMI message to be sent.  This
+	   operation is not allowed to fail.  If an error occurs, it
+	   should report back the error in a received message.  It may
+	   do this in the current call context, since no write locks
+	   are held when this is run.  If the priority is > 0, the
+	   message will go into a high-priority queue and be sent
+	   first.  Otherwise, it goes into a normal-priority queue. */
+	void (*sender)(void                *send_info,
+		       struct ipmi_smi_msg *msg,
+		       int                 priority);
+
+	/* Called by the upper layer to request that we try to get
+	   events from the BMC we are attached to. */
+	void (*request_events)(void *send_info);
+
+	/* Called when someone is using the interface, so the module can
+	   adjust it's use count.  Return zero if successful, or an
+	   errno if not. */
+	int (*new_user)(void *send_info);
+
+	/* Called when someone is no longer using the interface, so the
+	   module can adjust it's use count. */
+	void (*user_left)(void *send_info);
+
+	/* Called when the interface should go into "run to
+	   completion" mode.  If this call sets the value to true, the
+	   interface should make sure that all messages are flushed
+	   out and that none are pending, and any new requests are run
+	   to completion immediately. */
+	void (*set_run_to_completion)(void *send_info, int run_to_completion);
+};
+
+/* Add a low-level interface to the IPMI driver. */
+int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
+		      void                     *send_info,
+		      unsigned char            version_major,
+		      unsigned char            version_minor,
+		      ipmi_smi_t               *intf);
+
+/*
+ * Remove a low-level interface from the IPMI driver.  This will
+ * return an error if the interface is still in use by a user.
+ */
+int ipmi_unregister_smi(ipmi_smi_t intf);
+
+/*
+ * The lower layer reports received messages through this interface.
+ * The data_size should be zero if this is an asyncronous message.  If
+ * the lower layer gets an error sending a message, it should format
+ * an error response in the message response.
+ */
+void ipmi_smi_msg_received(ipmi_smi_t          intf,
+			   struct ipmi_smi_msg *msg);
+
+/* The lower layer received a watchdog pre-timeout on interface. */
+void ipmi_smi_watchdog_pretimeout(ipmi_smi_t intf);
+
+struct ipmi_smi_msg *ipmi_alloc_smi_msg(void);
+static inline void ipmi_free_smi_msg(struct ipmi_smi_msg *msg)
+{
+	msg->done(msg);
+}
+
+#endif /* __LINUX_IPMI_SMI_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/jbd.h linux-2.4.21-pre6/include/linux/jbd.h
--- linux-2.4.20/include/linux/jbd.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/jbd.h	2003-03-26 23:49:53.000000000 +0000
@@ -70,7 +70,38 @@
 #define JFS_MIN_JOURNAL_BLOCKS 1024
 
 #ifdef __KERNEL__
+
+/**
+ * typedef handle_t - The handle_t type represents a single atomic update being performed by some process.
+ *
+ * All filesystem modifications made by the process go
+ * through this handle.  Recursive operations (such as quota operations)
+ * are gathered into a single update.
+ *
+ * The buffer credits field is used to account for journaled buffers
+ * being modified by the running process.  To ensure that there is
+ * enough log space for all outstanding operations, we need to limit the
+ * number of outstanding buffers possible at any time.  When the
+ * operation completes, any buffer credits not used are credited back to
+ * the transaction, so that at all times we know how many buffers the
+ * outstanding updates on a transaction might possibly touch. 
+ * 
+ * This is an opaque datatype.
+ **/
 typedef struct handle_s		handle_t;	/* Atomic operation type */
+
+
+/**
+ * typedef journal_t - The journal_t maintains all of the journaling state information for a single filesystem.
+ *
+ * journal_t is linked to from the fs superblock structure.
+ * 
+ * We use the journal_t to keep track of all outstanding transaction
+ * activity on the filesystem, and to manage the state of the log
+ * writing process.
+ *
+ * This is an opaque datatype.
+ **/
 typedef struct journal_s	journal_t;	/* Journal control structure */
 #endif
 
@@ -266,7 +297,8 @@
 
 struct jbd_revoke_table_s;
 
-/* The handle_t type represents a single atomic update being performed
+/**
+ * The handle_t type represents a single atomic update being performed
  * by some process.  All filesystem modifications made by the process go
  * through this handle.  Recursive operations (such as quota operations)
  * are gathered into a single update.
@@ -277,7 +309,21 @@
  * number of outstanding buffers possible at any time.  When the
  * operation completes, any buffer credits not used are credited back to
  * the transaction, so that at all times we know how many buffers the
- * outstanding updates on a transaction might possibly touch. */
+ * outstanding updates on a transaction might possibly touch. 
+ *
+ * struct handle_s - The handle_s type is the concrete type associated with handle_t.
+ * @h_transaction: Which compound transaction is this update a part of?
+ * @h_buffer_credits: Number of remaining buffers we are allowed to dirty.
+ * @h_ref: Reference count on this handle
+ * @h_err: Field for caller's use to track errors through large fs operations
+ * @h_sync: flag for sync-on-close
+ * @h_jdata: flag to force data journaling
+ * @h_aborted: flag indicating fatal error on handle
+ **/
+
+/* Docbook can't yet cope with the bit fields, but will leave the documentation
+ * in so it can be fixed later. 
+ */
 
 struct handle_s 
 {
@@ -290,8 +336,8 @@
 	/* Reference count on this handle */
 	int			h_ref;
 
-	/* Field for caller's use to track errors through large fs
-	   operations */
+	/* Field for caller's use to track errors through large fs */
+	/* operations */
 	int			h_err;
 
 	/* List of application registered callbacks for this handle.
@@ -373,7 +419,7 @@
 	 */
 	struct journal_head *	t_async_datalist;
 	
-	/* Doubly-linked circular list of all forget buffers (superseded
+	/* Doubly-linked circular list of all forget buffers (superceded
            buffers which we can un-checkpoint once this transaction
            commits) */
 	struct journal_head *	t_forget;
@@ -425,21 +471,58 @@
 	struct list_head	t_jcb;
 };
 
-
-/* The journal_t maintains all of the journaling state information for a
- * single filesystem.  It is linked to from the fs superblock structure.
- * 
- * We use the journal_t to keep track of all outstanding transaction
- * activity on the filesystem, and to manage the state of the log
- * writing process. */
+/**
+ * struct journal_s - The journal_s type is the concrete type associated with journal_t.
+ * @j_flags:  General journaling state flags
+ * @j_errno:  Is there an outstanding uncleared error on the journal (from a prior abort)? 
+ * @j_sb_buffer: First part of superblock buffer
+ * @j_superblock: Second part of superblock buffer
+ * @j_format_version: Version of the superblock format
+ * @j_barrier_count:  Number of processes waiting to create a barrier lock
+ * @j_barrier: The barrier lock itself
+ * @j_running_transaction: The current running transaction..
+ * @j_committing_transaction: the transaction we are pushing to disk
+ * @j_checkpoint_transactions: a linked circular list of all transactions waiting for checkpointing
+ * @j_wait_transaction_locked: Wait queue for waiting for a locked transaction to start committing, or for a barrier lock to be released
+ * @j_wait_logspace: Wait queue for waiting for checkpointing to complete
+ * @j_wait_done_commit: Wait queue for waiting for commit to complete 
+ * @j_wait_checkpoint:  Wait queue to trigger checkpointing
+ * @j_wait_commit: Wait queue to trigger commit
+ * @j_wait_updates: Wait queue to wait for updates to complete
+ * @j_checkpoint_sem: Semaphore for locking against concurrent checkpoints
+ * @j_sem: The main journal lock, used by lock_journal() 
+ * @j_head: Journal head - identifies the first unused block in the journal
+ * @j_tail: Journal tail - identifies the oldest still-used block in the journal.
+ * @j_free: Journal free - how many free blocks are there in the journal?
+ * @j_first: The block number of the first usable block 
+ * @j_last: The block number one beyond the last usable block
+ * @j_dev: Device where we store the journal
+ * @j_blocksize: blocksize for the location where we store the journal.
+ * @j_blk_offset: starting block offset for into the device where we store the journal
+ * @j_fs_dev: Device which holds the client fs.  For internal journal this will be equal to j_dev
+ * @j_maxlen: Total maximum capacity of the journal region on disk.
+ * @j_inode: Optional inode where we store the journal.  If present, all  journal block numbers are mapped into this inode via bmap().
+ * @j_tail_sequence:  Sequence number of the oldest transaction in the log 
+ * @j_transaction_sequence: Sequence number of the next transaction to grant
+ * @j_commit_sequence: Sequence number of the most recently committed transaction
+ * @j_commit_request: Sequence number of the most recent transaction wanting commit 
+ * @j_uuid: Uuid of client object.
+ * @j_task: Pointer to the current commit thread for this journal
+ * @j_max_transaction_buffers:  Maximum number of metadata buffers to allow in a single compound commit transaction
+ * @j_commit_interval: What is the maximum transaction lifetime before we begin a commit?
+ * @j_commit_timer:  The timer used to wakeup the commit thread
+ * @j_commit_timer_active: Timer flag
+ * @j_all_journals:  Link all journals together - system-wide 
+ * @j_revoke: The revoke table - maintains the list of revoked blocks in the current transaction.
+ **/
 
 struct journal_s
 {
 	/* General journaling state flags */
 	unsigned long		j_flags;
 
-	/* Is there an outstanding uncleared error on the journal (from
-	 * a prior abort)? */
+	/* Is there an outstanding uncleared error on the journal (from */
+	/* a prior abort)? */
 	int			j_errno;
 	
 	/* The superblock buffer */
@@ -461,13 +544,13 @@
 	/* ... the transaction we are pushing to disk ... */
 	transaction_t *		j_committing_transaction;
 	
-	/* ... and a linked circular list of all transactions waiting
-	 * for checkpointing. */
+	/* ... and a linked circular list of all transactions waiting */
+	/* for checkpointing. */
 	/* Protected by journal_datalist_lock */
 	transaction_t *		j_checkpoint_transactions;
 
-	/* Wait queue for waiting for a locked transaction to start
-           committing, or for a barrier lock to be released */
+	/* Wait queue for waiting for a locked transaction to start */
+        /*  committing, or for a barrier lock to be released */
 	wait_queue_head_t	j_wait_transaction_locked;
 	
 	/* Wait queue for waiting for checkpointing to complete */
@@ -494,33 +577,33 @@
 	/* Journal head: identifies the first unused block in the journal. */
 	unsigned long		j_head;
 	
-	/* Journal tail: identifies the oldest still-used block in the
-	 * journal. */
+	/* Journal tail: identifies the oldest still-used block in the */
+	/* journal. */
 	unsigned long		j_tail;
 
 	/* Journal free: how many free blocks are there in the journal? */
 	unsigned long		j_free;
 
-	/* Journal start and end: the block numbers of the first usable
-	 * block and one beyond the last usable block in the journal. */
+	/* Journal start and end: the block numbers of the first usable */
+	/* block and one beyond the last usable block in the journal. */
 	unsigned long		j_first, j_last;
 
-	/* Device, blocksize and starting block offset for the location
-	 * where we store the journal. */
+	/* Device, blocksize and starting block offset for the location */
+	/* where we store the journal. */
 	kdev_t			j_dev;
 	int			j_blocksize;
 	unsigned int		j_blk_offset;
 
-	/* Device which holds the client fs.  For internal journal this
-	 * will be equal to j_dev. */
+	/* Device which holds the client fs.  For internal journal this */
+	/* will be equal to j_dev. */
 	kdev_t			j_fs_dev;
 
 	/* Total maximum capacity of the journal region on disk. */
 	unsigned int		j_maxlen;
 
-	/* Optional inode where we store the journal.  If present, all
-	 * journal block numbers are mapped into this inode via
-	 * bmap(). */
+	/* Optional inode where we store the journal.  If present, all */
+	/* journal block numbers are mapped into this inode via */
+	/* bmap(). */
 	struct inode *		j_inode;
 
 	/* Sequence number of the oldest transaction in the log */
@@ -532,23 +615,23 @@
 	/* Sequence number of the most recent transaction wanting commit */
 	tid_t			j_commit_request;
 
-	/* Journal uuid: identifies the object (filesystem, LVM volume
-	 * etc) backed by this journal.  This will eventually be
-	 * replaced by an array of uuids, allowing us to index multiple
-	 * devices within a single journal and to perform atomic updates
-	 * across them.  */
+	/* Journal uuid: identifies the object (filesystem, LVM volume   */
+	/* etc) backed by this journal.  This will eventually be         */
+	/* replaced by an array of uuids, allowing us to index multiple  */
+	/* devices within a single journal and to perform atomic updates */
+	/* across them.  */
 
 	__u8			j_uuid[16];
 
 	/* Pointer to the current commit thread for this journal */
 	struct task_struct *	j_task;
 
-	/* Maximum number of metadata buffers to allow in a single
-	 * compound commit transaction */
+	/* Maximum number of metadata buffers to allow in a single */
+	/* compound commit transaction */
 	int			j_max_transaction_buffers;
 
-	/* What is the maximum transaction lifetime before we begin a
-	 * commit? */
+	/* What is the maximum transaction lifetime before we begin a */
+	/* commit? */
 	unsigned long		j_commit_interval;
 
 	/* The timer used to wakeup the commit thread: */
@@ -558,8 +641,8 @@
 	/* Link all journals together - system-wide */
 	struct list_head	j_all_journals;
 
-	/* The revoke table: maintains the list of revoked blocks in the
-           current transaction. */
+	/* The revoke table: maintains the list of revoked blocks in the */
+        /*  current transaction. */
 	struct jbd_revoke_table_s *j_revoke;
 };
 
@@ -825,7 +908,7 @@
 #define BJ_SyncData	1	/* Normal data: flush before commit */
 #define BJ_AsyncData	2	/* writepage data: wait on it before commit */
 #define BJ_Metadata	3	/* Normal journaled metadata */
-#define BJ_Forget	4	/* Buffer superseded by this transaction */
+#define BJ_Forget	4	/* Buffer superceded by this transaction */
 #define BJ_IO		5	/* Buffer is for temporary IO use */
 #define BJ_Shadow	6	/* Buffer contents being shadowed to the log */
 #define BJ_LogCtl	7	/* Buffer contains log descriptors */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/kbd_kern.h linux-2.4.21-pre6/include/linux/kbd_kern.h
--- linux-2.4.20/include/linux/kbd_kern.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/kbd_kern.h	2003-03-26 23:49:51.000000000 +0000
@@ -72,6 +72,7 @@
 extern int do_poke_blanked_console;
 
 extern void (*kbd_ledfunc)(unsigned int led);
+extern void kbd_refresh_leds(void);
 
 extern void set_console(int nr);
 extern void schedule_console_callback(void);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/kernel_stat.h linux-2.4.21-pre6/include/linux/kernel_stat.h
--- linux-2.4.20/include/linux/kernel_stat.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/kernel_stat.h	2003-03-26 23:49:31.000000000 +0000
@@ -27,7 +27,7 @@
 	unsigned int pgpgin, pgpgout;
 	unsigned int pswpin, pswpout;
 #if defined (__hppa__) 
-	unsigned int irqs[NR_IRQ_REGS][IRQ_PER_REGION];
+	unsigned int irqs[NR_CPUS][NR_IRQ_REGS][IRQ_PER_REGION];
 #elif !defined(CONFIG_ARCH_S390)
 	unsigned int irqs[NR_CPUS][NR_IRQS];
 #endif
@@ -44,7 +44,12 @@
  */
 static inline int kstat_irqs (int irq)
 {
-	return kstat.irqs[IRQ_REGION(irq)][IRQ_OFFSET(irq)];
+	int i, sum=0; 
+
+	for (i = 0 ; i < smp_num_cpus ; i++)
+		sum += kstat.irqs[i][IRQ_REGION(irq)][IRQ_OFFSET(irq)];
+ 
+	return sum;
 }
 #elif !defined(CONFIG_ARCH_S390)
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/major.h linux-2.4.21-pre6/include/linux/major.h
--- linux-2.4.20/include/linux/major.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/major.h	2003-03-26 23:49:19.000000000 +0000
@@ -33,6 +33,7 @@
 #define MD_MAJOR        9
 #define MISC_MAJOR	10
 #define SCSI_CDROM_MAJOR 11
+#define	MUX_MAJOR	11	/* PA-RISC only */
 #define QIC02_TAPE_MAJOR 12
 #define XT_DISK_MAJOR	13
 #define SOUND_MAJOR	14
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/matroxfb.h linux-2.4.21-pre6/include/linux/matroxfb.h
--- linux-2.4.20/include/linux/matroxfb.h	2000-07-05 18:55:45.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/matroxfb.h	2003-03-26 23:48:59.000000000 +0000
@@ -30,5 +30,51 @@
 /* which outputs exist on this framebuffer */
 #define MATROXFB_GET_ALL_OUTPUTS	_IOR('n',0xFB,sizeof(__u32))
 
+struct matroxfb_queryctrl {
+  __u32 id;			/* ID for control */
+  char name[32];		/* A suggested label for this control */
+  int minimum;			/* Minimum value */
+  int maximum;			/* Maximum value */
+  unsigned int step;            /* The increment between values of an integer
+				   control that are distinct on the hardware */
+  int default_value;		/* Driver default value */
+  __u32 type;			/* Control type. */
+  __u32 flags;			/* Control flags */
+  __u32 category;               /* Control category code, useful for 
+				   separating controls by function */
+  char group[32];               /* A suggested label string for the 
+				   control group */
+  __u32 reserved[2];
+};
+
+enum matroxfb_ctrl_type {
+  MATROXFB_CTRL_TYPE_INTEGER=0,	/* An integer-valued control */
+  MATROXFB_CTRL_TYPE_BOOLEAN,	/* A boolean-valued control */
+  MATROXFB_CTRL_TYPE_MENU,	/* The control has a menu of choices */
+  MATROXFB_CTRL_TYPE_BUTTON /* A button which performs an action when clicked */
+};
+
+enum matroxfb_ctrl_id {
+  MATROXFB_CID_BRIGHTNESS=0x00980900,
+  MATROXFB_CID_CONTRAST,
+  MATROXFB_CID_SATURATION,
+  MATROXFB_CID_HUE,
+  MATROXFB_CID_GAMMA	 =0x00980910,
+  MATROXFB_CID_TESTOUT	 =0x08000000,
+  MATROXFB_CID_DEFLICKER,
+  MATROXFB_CID_LAST
+};
+  
+
+#define MATROXFB_TVOQUERYCTRL	_IOWR('V',36,struct matroxfb_queryctrl)
+   
+struct matroxfb_control {
+  __u32 id;			/* A driver-defined ID */
+  int value;			/* The current value, or new value */
+};
+
+#define MATROXFB_G_TVOCTRL	_IOWR('V',27,struct matroxfb_control)
+#define MATROXFB_S_TVOCTRL	_IOW ('V',28,struct matroxfb_control)
+
 #endif
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/meye.h linux-2.4.21-pre6/include/linux/meye.h
--- linux-2.4.20/include/linux/meye.h	2001-07-04 21:41:33.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/meye.h	2003-03-26 23:49:20.000000000 +0000
@@ -1,7 +1,9 @@
 /* 
  * Motion Eye video4linux driver for Sony Vaio PictureBook
  *
- * Copyright (C) 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
+ * Copyright (C) 2001-2003 Stelian Pop <stelian@popies.net>
+ *
+ * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
  *
  * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com>
  *
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/miscdevice.h linux-2.4.21-pre6/include/linux/miscdevice.h
--- linux-2.4.20/include/linux/miscdevice.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/miscdevice.h	2003-03-26 23:49:40.000000000 +0000
@@ -3,38 +3,39 @@
 
 #include <linux/devfs_fs_kernel.h>
 
-#define BUSMOUSE_MINOR 0
-#define PSMOUSE_MINOR  1
-#define MS_BUSMOUSE_MINOR 2
-#define ATIXL_BUSMOUSE_MINOR 3
-#define AMIGAMOUSE_MINOR 4
-#define ATARIMOUSE_MINOR 5
-#define SUN_MOUSE_MINOR 6
-#define APOLLO_MOUSE_MINOR 7
-#define PC110PAD_MINOR 9
-#define ADB_MOUSE_MINOR 10
-#define MK712_MINOR 15			/* MK712 touch screen */
+#define BUSMOUSE_MINOR		0
+#define PSMOUSE_MINOR		1
+#define MS_BUSMOUSE_MINOR	2
+#define ATIXL_BUSMOUSE_MINOR	3
+#define AMIGAMOUSE_MINOR	4
+#define ATARIMOUSE_MINOR	5
+#define SUN_MOUSE_MINOR		6
+#define APOLLO_MOUSE_MINOR	7
+#define PC110PAD_MINOR		9
+#define ADB_MOUSE_MINOR		10
+#define MK712_MINOR 		15	/* MK712 touch screen */
+#define SYNTH_MINOR    		25
 #define WATCHDOG_MINOR		130	/* Watchdog timer     */
 #define TEMP_MINOR		131	/* Temperature Sensor */
-#define RTC_MINOR 135
+#define RTC_MINOR		135
 #define EFI_RTC_MINOR		136	/* EFI Time services */
-#define SUN_OPENPROM_MINOR 139
-#define NVRAM_MINOR 144
-#define I2O_MINOR 166
+#define SUN_OPENPROM_MINOR	139
+#define NVRAM_MINOR		144
+#define I2O_MINOR		166
 #define MICROCODE_MINOR		184
-#define MWAVE_MINOR	219		/* ACP/Mwave Modem */
-#define MPT_MINOR	220
-#define MISC_DYNAMIC_MINOR 255
-
-#define SGI_GRAPHICS_MINOR   146
-#define SGI_OPENGL_MINOR     147
-#define SGI_GFX_MINOR        148
-#define SGI_STREAMS_MOUSE    149
-#define SGI_STREAMS_KEYBOARD 150
+#define MWAVE_MINOR		219	/* ACP/Mwave Modem */
+#define MPT_MINOR		220
+#define MISC_DYNAMIC_MINOR	255
+
+#define SGI_GRAPHICS_MINOR	146
+#define SGI_OPENGL_MINOR	147
+#define SGI_GFX_MINOR		148
+#define SGI_STREAMS_MOUSE	149
+#define SGI_STREAMS_KEYBOARD	150
 /* drivers/sgi/char/usema.c */
-#define SGI_USEMACLONE	     151
+#define SGI_USEMACLONE	    	151
 
-#define TUN_MINOR	     200
+#define TUN_MINOR	     	200
 
 extern int misc_init(void);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/mm.h linux-2.4.21-pre6/include/linux/mm.h
--- linux-2.4.20/include/linux/mm.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/mm.h	2003-03-26 23:48:59.000000000 +0000
@@ -297,6 +297,7 @@
 #define PG_arch_1		13
 #define PG_reserved		14
 #define PG_launder		15	/* written out by VM pressure.. */
+#define PG_fs_1			16	/* Filesystem specific */
 
 /* Make it prettier to test the above... */
 #define UnlockPage(page)	unlock_page(page)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/msdos_fs.h linux-2.4.21-pre6/include/linux/msdos_fs.h
--- linux-2.4.20/include/linux/msdos_fs.h	2001-10-12 20:48:42.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/msdos_fs.h	2003-03-26 23:49:51.000000000 +0000
@@ -70,9 +70,9 @@
 
 #define MSDOS_FAT12 4084 /* maximum number of clusters in a 12 bit FAT */
 
-#define EOF_FAT12 0xFF8		/* standard EOF */
-#define EOF_FAT16 0xFFF8
-#define EOF_FAT32 0xFFFFFF8
+#define EOF_FAT12 0xFFF		/* standard EOF */
+#define EOF_FAT16 0xFFFF
+#define EOF_FAT32 0xFFFFFFF
 #define EOF_FAT(s) (MSDOS_SB(s)->fat_bits == 32 ? EOF_FAT32 : \
 	MSDOS_SB(s)->fat_bits == 16 ? EOF_FAT16 : EOF_FAT12)
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/mtd/cfi.h linux-2.4.21-pre6/include/linux/mtd/cfi.h
--- linux-2.4.20/include/linux/mtd/cfi.h	2001-10-04 22:13:18.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/mtd/cfi.h	2003-03-26 23:49:30.000000000 +0000
@@ -1,7 +1,7 @@
 
 /* Common Flash Interface structures 
  * See http://support.intel.com/design/flash/technote/index.htm
- * $Id: cfi.h,v 1.25 2001/09/04 07:06:21 dwmw2 Exp $
+ * $Id: cfi.h,v 1.32 2002/09/05 05:15:32 acurtis Exp $
  */
 
 #ifndef __MTD_CFI_H__
@@ -18,13 +18,16 @@
  * You can optimize the code size and performance by defining only 
  * the geometry(ies) available on your hardware.
  * CFIDEV_INTERLEAVE_n, where  represents the interleave (number of chips to fill the bus width)
- * CFIDEV_BUSWIDTH_n, where n is the bus width in bytes (1, 2 or 4 bytes)
+ * CFIDEV_BUSWIDTH_n, where n is the bus width in bytes (1, 2, 4 or 8 bytes)
  *
  * By default, all (known) geometries are supported.
  */
 
 #ifndef CONFIG_MTD_CFI_GEOMETRY
 
+/* The default case - support all but 64-bit, which has
+   a performance penalty */
+
 #define CFIDEV_INTERLEAVE_1 (1)
 #define CFIDEV_INTERLEAVE_2 (2)
 #define CFIDEV_INTERLEAVE_4 (4)
@@ -33,8 +36,12 @@
 #define CFIDEV_BUSWIDTH_2 (2)
 #define CFIDEV_BUSWIDTH_4 (4)
 
+typedef __u32 cfi_word;
+
 #else
 
+/* Explicitly configured buswidth/interleave support */
+
 #ifdef CONFIG_MTD_CFI_I1
 #define CFIDEV_INTERLEAVE_1 (1)
 #endif
@@ -44,6 +51,9 @@
 #ifdef CONFIG_MTD_CFI_I4
 #define CFIDEV_INTERLEAVE_4 (4)
 #endif
+#ifdef CONFIG_MTD_CFI_I8
+#define CFIDEV_INTERLEAVE_8 (8)
+#endif
 
 #ifdef CONFIG_MTD_CFI_B1
 #define CFIDEV_BUSWIDTH_1 (1)
@@ -54,6 +64,27 @@
 #ifdef CONFIG_MTD_CFI_B4
 #define CFIDEV_BUSWIDTH_4 (4)
 #endif
+#ifdef CONFIG_MTD_CFI_B8
+#define CFIDEV_BUSWIDTH_8 (8)
+#endif
+
+/* pick the largest necessary */
+#ifdef CONFIG_MTD_CFI_B8
+typedef __u64 cfi_word;
+
+/* This only works if asm/io.h is included first */
+#ifndef __raw_readll
+#define __raw_readll(addr)	(*(volatile __u64 *)(addr))
+#endif
+#ifndef __raw_writell
+#define __raw_writell(v, addr)	(*(volatile __u64 *)(addr) = (v))
+#endif
+#define CFI_WORD_64
+#else  /* CONFIG_MTD_CFI_B8 */
+/* All others can use 32-bits. It's probably more efficient than
+   the smaller types anyway */
+typedef __u32 cfi_word;
+#endif /* CONFIG_MTD_CFI_B8 */
 
 #endif
 
@@ -61,12 +92,15 @@
  * The following macros are used to select the code to execute:
  *   cfi_buswidth_is_*()
  *   cfi_interleave_is_*()
- *   [where * is either 1, 2 or 4]
+ *   [where * is either 1, 2, 4, or 8]
  * Those macros should be used with 'if' statements.  If only one of few
  * geometry arrangements are selected, they expand to constants thus allowing
  * the compiler (most of them being 0) to optimize away all the unneeded code,
  * while still validating the syntax (which is not possible with embedded 
  * #if ... #endif constructs).
+ * The exception to this is the 64-bit versions, which need an extension
+ * to the cfi_word type, and cause compiler warnings about shifts being
+ * out of range.
  */
 
 #ifdef CFIDEV_INTERLEAVE_1
@@ -105,6 +139,18 @@
 # define cfi_interleave_is_4() (0)
 #endif
 
+#ifdef CFIDEV_INTERLEAVE_8
+# ifdef CFIDEV_INTERLEAVE
+#  undef CFIDEV_INTERLEAVE
+#  define CFIDEV_INTERLEAVE (cfi->interleave)
+# else
+#  define CFIDEV_INTERLEAVE CFIDEV_INTERLEAVE_8
+# endif
+# define cfi_interleave_is_8() (CFIDEV_INTERLEAVE == CFIDEV_INTERLEAVE_8)
+#else
+# define cfi_interleave_is_8() (0)
+#endif
+
 #ifndef CFIDEV_INTERLEAVE
 #error You must define at least one interleave to support!
 #endif
@@ -145,6 +191,18 @@
 # define cfi_buswidth_is_4() (0)
 #endif
 
+#ifdef CFIDEV_BUSWIDTH_8
+# ifdef CFIDEV_BUSWIDTH
+#  undef CFIDEV_BUSWIDTH
+#  define CFIDEV_BUSWIDTH (map->buswidth)
+# else
+#  define CFIDEV_BUSWIDTH CFIDEV_BUSWIDTH_8
+# endif
+# define cfi_buswidth_is_8() (CFIDEV_BUSWIDTH == CFIDEV_BUSWIDTH_8)
+#else
+# define cfi_buswidth_is_8() (0)
+#endif
+
 #ifndef CFIDEV_BUSWIDTH
 #error You must define at least one bus width to support!
 #endif
@@ -156,6 +214,7 @@
 #define CFI_DEVICETYPE_X8  (8 / 8)
 #define CFI_DEVICETYPE_X16 (16 / 8)
 #define CFI_DEVICETYPE_X32 (32 / 8)
+#define CFI_DEVICETYPE_X64 (64 / 8)
 
 /* NB: We keep these structures in memory in HOST byteorder, except
  * where individually noted.
@@ -206,6 +265,10 @@
   __u16 BlkStatusRegMask;
   __u8  VccOptimal;
   __u8  VppOptimal;
+  __u8  NumProtectionFields;
+  __u16 ProtRegAddr;
+  __u8  FactProtRegSize;
+  __u8  UserProtRegSize;
 } __attribute__((packed));
 
 struct cfi_pri_query {
@@ -229,8 +292,8 @@
 #define P_ID_RESERVED 65535
 
 
-#define CFI_MODE_CFI	0
-#define CFI_MODE_JEDEC	1
+#define CFI_MODE_CFI	1
+#define CFI_MODE_JEDEC	0
 
 struct cfi_private {
 	__u16 cmdset;
@@ -264,9 +327,9 @@
 /*
  * Transforms the CFI command for the given geometry (bus width & interleave.
  */
-static inline __u32 cfi_build_cmd(u_char cmd, struct map_info *map, struct cfi_private *cfi)
+static inline cfi_word cfi_build_cmd(u_char cmd, struct map_info *map, struct cfi_private *cfi)
 {
-	__u32 val = 0;
+	cfi_word val = 0;
 
 	if (cfi_buswidth_is_1()) {
 		/* 1 x8 device */
@@ -291,6 +354,27 @@
 			val = (cmd << 16) | cmd;
 			val = cpu_to_cfi32((val << 8) | val);
 		}
+#ifdef CFI_WORD_64
+	} else if (cfi_buswidth_is_8()) {
+		if (cfi_interleave_is_1()) {
+			/* 1 x64 device in x64 mode */
+			val = cpu_to_cfi64(cmd);
+		} else if (cfi_interleave_is_2()) {
+			/* 2 x32 device in x32 mode */
+			val = cmd;
+			val = cpu_to_cfi64((val << 32) | val);
+		} else if (cfi_interleave_is_4()) {
+			/* 4 (x16, x32 or x64) devices in x16 mode */
+			val = (cmd << 16) | cmd;
+			val = cpu_to_cfi64((val << 32) | val);
+		} else if (cfi_interleave_is_8()) {
+			/* 8 (x8, x16 or x32) devices in x8 mode */
+			val = (cmd << 8) | cmd;
+			val = (val << 16) | val;
+			val = (val << 32) | val;
+			val = cpu_to_cfi64(val);
+		}
+#endif /* CFI_WORD_64 */
 	}
 	return val;
 }
@@ -300,7 +384,7 @@
  * Read a value according to the bus width.
  */
 
-static inline __u32 cfi_read(struct map_info *map, __u32 addr)
+static inline cfi_word cfi_read(struct map_info *map, __u32 addr)
 {
 	if (cfi_buswidth_is_1()) {
 		return map->read8(map, addr);
@@ -308,6 +392,8 @@
 		return map->read16(map, addr);
 	} else if (cfi_buswidth_is_4()) {
 		return map->read32(map, addr);
+	} else if (cfi_buswidth_is_8()) {
+		return map->read64(map, addr);
 	} else {
 		return 0;
 	}
@@ -317,7 +403,7 @@
  * Write a value according to the bus width.
  */
 
-static inline void cfi_write(struct map_info *map, __u32 val, __u32 addr)
+static inline void cfi_write(struct map_info *map, cfi_word val, __u32 addr)
 {
 	if (cfi_buswidth_is_1()) {
 		map->write8(map, val, addr);
@@ -325,6 +411,8 @@
 		map->write16(map, val, addr);
 	} else if (cfi_buswidth_is_4()) {
 		map->write32(map, val, addr);
+	} else if (cfi_buswidth_is_8()) {
+		map->write64(map, val, addr);
 	}
 }
 
@@ -337,9 +425,9 @@
  */
 static inline __u32 cfi_send_gen_cmd(u_char cmd, __u32 cmd_addr, __u32 base,
 				struct map_info *map, struct cfi_private *cfi,
-				int type, __u32 *prev_val)
+				int type, cfi_word *prev_val)
 {
-	__u32 val;
+	cfi_word val;
 	__u32 addr = base + cfi_build_cmd_addr(cmd_addr, CFIDEV_INTERLEAVE, type);
 
 	val = cfi_build_cmd(cmd, map, cfi);
@@ -360,6 +448,8 @@
 		return cfi16_to_cpu(map->read16(map, addr));
 	} else if (cfi_buswidth_is_4()) {
 		return cfi32_to_cpu(map->read32(map, addr));
+	} else if (cfi_buswidth_is_8()) {
+		return cfi64_to_cpu(map->read64(map, addr));
 	} else {
 		return 0;
 	}
@@ -368,17 +458,17 @@
 static inline void cfi_udelay(int us)
 {
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-	if (current->need_resched) {
-		unsigned long t = us * HZ / 1000000;
-		if (t < 1)
-			t = 1;
+	unsigned long t = us * HZ / 1000000;
+	if (t) {
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		schedule_timeout(t);
+		return;
 	}
-	else
 #endif
-		udelay(us);
+	udelay(us);
+	cond_resched();
 }
+
 static inline void cfi_spin_lock(spinlock_t *mutex)
 {
 	spin_lock_bh(mutex);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/mtd/cfi_endian.h linux-2.4.21-pre6/include/linux/mtd/cfi_endian.h
--- linux-2.4.20/include/linux/mtd/cfi_endian.h	2001-10-04 22:13:18.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/mtd/cfi_endian.h	2003-03-26 23:48:57.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * $Id: cfi_endian.h,v 1.10 2001/06/18 11:00:46 abz Exp $
+ * $Id: cfi_endian.h,v 1.11 2002/01/30 23:20:48 awozniak Exp $
  *
  */
 
@@ -30,22 +30,28 @@
 #define cfi8_to_cpu(x) (x)
 #define cpu_to_cfi16(x) cpu_to_le16(x)
 #define cpu_to_cfi32(x) cpu_to_le32(x)
+#define cpu_to_cfi64(x) cpu_to_le64(x)
 #define cfi16_to_cpu(x) le16_to_cpu(x)
 #define cfi32_to_cpu(x) le32_to_cpu(x)
+#define cfi64_to_cpu(x) le64_to_cpu(x)
 #elif defined (CFI_BIG_ENDIAN)
 #define cpu_to_cfi8(x) (x)
 #define cfi8_to_cpu(x) (x)
 #define cpu_to_cfi16(x) cpu_to_be16(x)
 #define cpu_to_cfi32(x) cpu_to_be32(x)
+#define cpu_to_cfi64(x) cpu_to_be64(x)
 #define cfi16_to_cpu(x) be16_to_cpu(x)
 #define cfi32_to_cpu(x) be32_to_cpu(x)
+#define cfi64_to_cpu(x) be64_to_cpu(x)
 #elif defined (CFI_HOST_ENDIAN)
 #define cpu_to_cfi8(x) (x)
 #define cfi8_to_cpu(x) (x)
 #define cpu_to_cfi16(x) (x)
 #define cpu_to_cfi32(x) (x)
+#define cpu_to_cfi64(x) (x)
 #define cfi16_to_cpu(x) (x)
 #define cfi32_to_cpu(x) (x)
+#define cfi64_to_cpu(x) (x)
 #else
 #error No CFI endianness defined
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/mtd/compatmac.h linux-2.4.21-pre6/include/linux/mtd/compatmac.h
--- linux-2.4.20/include/linux/mtd/compatmac.h	2002-08-03 00:39:45.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/mtd/compatmac.h	2003-03-26 23:49:24.000000000 +0000
@@ -2,7 +2,7 @@
 /*
  * mtd/include/compatmac.h
  *
- * $Id: compatmac.h,v 1.4 2000/07/03 10:01:38 dwmw2 Exp $
+ * $Id: compatmac.h,v 1.45 2003/01/24 15:50:57 dwmw2 Exp $
  *
  * Extensions and omissions from the normal 'linux/compatmac.h'
  * files. hopefully this will end up empty as the 'real' one 
@@ -17,21 +17,158 @@
 #ifndef __LINUX_MTD_COMPATMAC_H__
 #define __LINUX_MTD_COMPATMAC_H__
 
-#include <linux/compatmac.h>
-#include <linux/types.h> /* used later in this header */
+#include <linux/config.h>
 #include <linux/module.h>
 #ifndef LINUX_VERSION_CODE
 #include <linux/version.h>
 #endif
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
-#include <linux/vmalloc.h>
+#ifndef VERSION_CODE
+#  define VERSION_CODE(vers,rel,seq) ( ((vers)<<16) | ((rel)<<8) | (seq) )
+#endif
+#ifndef KERNEL_VERSION
+#  define KERNEL_VERSION(a,b,c) VERSION_CODE(a,b,c)
 #endif
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,0,0)
 #  error "This kernel is too old: not supported by this file"
 #endif
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)
+#include <linux/types.h> /* used later in this header */
+
+#define memcpy_fromio(a,b,c)    memcpy((a),(void *)(b),(c))
+#define memcpy_toio(a,b,c)      memcpy((void *)(a),(b),(c))
+
+typedef struct wait_queue * wait_queue_head_t;
+
+#define DECLARE_WAITQUEUE(x,y) struct wait_queue x = {y,NULL}
+#define DECLARE_WAIT_QUEUE_HEAD(x) struct wait_queue *x = NULL
+#define init_waitqueue_head init_waitqueue
+#define DECLARE_MUTEX(x) struct semaphore x = MUTEX
+#define DECLARE_MUTEX_LOCKED(x) struct semaphore x = MUTEX_LOCKED
+
+/* from sysdep-2.1.h */
+#  include <asm/segment.h>
+#  define access_ok(t,a,sz)           (verify_area((t),(a),(sz)) ? 0 : 1)
+#  define verify_area_20              verify_area
+#  define copy_to_user(t,f,n)         (memcpy_tofs(t,f,n), 0)
+#  define __copy_to_user(t,f,n)       copy_to_user((t),(f),(n))
+#  define copy_to_user_ret(t,f,n,r)   copy_to_user((t),(f),(n))
+#  define copy_from_user(t,f,n)       (memcpy_fromfs((t),(f),(n)), 0)
+#  define __copy_from_user(t,f,n)     copy_from_user((t),(f),(n))
+#  define copy_from_user_ret(t,f,n,r) copy_from_user((t),(f),(n))
+//xxx #  define PUT_USER(val,add)           (put_user((val),(add)), 0)
+#  define Put_user(val,add)           (put_user((val),(add)), 0)
+#  define __PUT_USER(val,add)         PUT_USER((val),(add))
+#  define PUT_USER_RET(val,add,ret)   PUT_USER((val),(add))
+#  define GET_USER(dest,add)          ((dest)=get_user((add)), 0)
+#  define __GET_USER(dest,add)        GET_USER((dest),(add))
+#  define GET_USER_RET(dest,add,ret)  GET_USER((dest),(add))
+
+#define ioremap(offset,size) vremap(offset,size)
+#define iounmap(adr)	/* */
+
+#define EXPORT_SYMBOL(s) /* */
+#define EXPORT_SYMBOL_NOVERS(s) /* */
+
+/* 2.1.10 and 2.1.43 introduced new functions. They are worth using */
+
+#if LINUX_VERSION_CODE < VERSION_CODE(2,1,10)
+
+#  include <asm/byteorder.h>
+#  ifdef __LITTLE_ENDIAN
+#    define cpu_to_le16(x) (x)
+#    define cpu_to_le32(x) (x)
+#    define cpu_to_be16(x) htons((x))
+#    define cpu_to_be32(x) htonl((x))
+#  else
+#    define cpu_to_be16(x) (x)
+#    define cpu_to_be32(x) (x)
+     extern inline __u16 cpu_to_le16(__u16 x) { return (x<<8) | (x>>8);}
+     extern inline __u32 cpu_to_le32(__u32 x) { return((x>>24) |
+             ((x>>8)&0xff00) | ((x<<8)&0xff0000) | (x<<24));}
+#  endif
+
+#  define le16_to_cpu(x)  cpu_to_le16(x)
+#  define le32_to_cpu(x)  cpu_to_le32(x)
+#  define be16_to_cpu(x)  cpu_to_be16(x)
+#  define be32_to_cpu(x)  cpu_to_be32(x)
+
+#endif
+
+#if LINUX_VERSION_CODE < VERSION_CODE(2,1,43)
+#  define cpu_to_le16p(addr) (cpu_to_le16(*(addr)))
+#  define cpu_to_le32p(addr) (cpu_to_le32(*(addr)))
+#  define cpu_to_be16p(addr) (cpu_to_be16(*(addr)))
+#  define cpu_to_be32p(addr) (cpu_to_be32(*(addr)))
+
+   extern inline void cpu_to_le16s(__u16 *a) {*a = cpu_to_le16(*a);}
+   extern inline void cpu_to_le32s(__u16 *a) {*a = cpu_to_le32(*a);}
+   extern inline void cpu_to_be16s(__u16 *a) {*a = cpu_to_be16(*a);}
+   extern inline void cpu_to_be32s(__u16 *a) {*a = cpu_to_be32(*a);}
+
+#  define le16_to_cpup(x) cpu_to_le16p(x)
+#  define le32_to_cpup(x) cpu_to_le32p(x)
+#  define be16_to_cpup(x) cpu_to_be16p(x)
+#  define be32_to_cpup(x) cpu_to_be32p(x)
+
+#  define le16_to_cpus(x) cpu_to_le16s(x)
+#  define le32_to_cpus(x) cpu_to_le32s(x)
+#  define be16_to_cpus(x) cpu_to_be16s(x)
+#  define be32_to_cpus(x) cpu_to_be32s(x)
+#endif
+
+// from 2.2, linux/types.h
+#ifndef __BIT_TYPES_DEFINED__
+#define __BIT_TYPES_DEFINED__
+
+typedef         __u8            u_int8_t;
+typedef         __s8            int8_t;
+typedef         __u16           u_int16_t;
+typedef         __s16           int16_t;
+typedef         __u32           u_int32_t;
+typedef         __s32           int32_t;
+
+#endif /* !(__BIT_TYPES_DEFINED__) */
+
+#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)
+  typedef struct { } spinlock_t;
+  #define SPIN_LOCK_UNLOCKED (spinlock_t) { }
+#else
+  typedef struct { int gcc_is_buggy; } spinlock_t;
+  #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
+#endif
+
+#define spin_lock_init(lock)    do { } while(0)
+#define spin_lock(lock)         (void)(lock) /* Not "unused variable". */
+#define spin_trylock(lock)      (1)
+#define spin_unlock_wait(lock)  do { } while(0)
+#define spin_unlock(lock)       do { } while(0)
+#define spin_lock_irq(lock)     cli()
+#define spin_unlock_irq(lock)   sti()
+
+#define spin_lock_irqsave(lock, flags) \
+        do { save_flags(flags); cli(); } while (0)
+#define spin_unlock_irqrestore(lock, flags) \
+        restore_flags(flags)
+
+// Doesn't work when tqueue.h is included. 
+// #define queue_task                   queue_task_irq_off
+#define tty_flip_buffer_push(tty)    queue_task_irq_off(&tty->flip.tqueue, &tq_timer)
+#define signal_pending(current)      (current->signal & ~current->blocked)
+#define schedule_timeout(to)         do {current->timeout = jiffies + (to);schedule ();} while (0)
+#define time_after(t1,t2)            (((long)t1-t2) > 0)
+
+#else
+  #include <linux/compatmac.h>
+#endif  // LINUX_VERSION_CODE < 0x020100
+
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
+#include <linux/vmalloc.h>
+#endif
+
 /* Modularization issues */
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,18)
 #  define __USE_OLD_SYMTAB__
@@ -97,32 +234,60 @@
 #include <linux/init.h>
 #endif
 
-#if LINUX_VERSION_CODE < 0x20300
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)
 #define init_MUTEX(x) do {*(x) = MUTEX;} while (0)
+#define init_MUTEX_LOCKED(x) do {*(x) = MUTEX_LOCKED;} while (0)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
 #define RQFUNC_ARG void
 #define blkdev_dequeue_request(req) do {CURRENT = req->next;} while (0)
 #else
 #define RQFUNC_ARG request_queue_t *q
 #endif
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,32)
+#define blk_cleanup_queue(nr) do {blk_dev[nr].request_fn = 0;} while(0)
+#define BLK_DEFAULT_QUEUE(nr) (blk_dev[nr].request_fn)
+#define blk_init_queue(q, rq) do {q = rq;} while(0)
+#endif
+
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,0)
+#ifdef CONFIG_MODULES
 #define __MOD_INC_USE_COUNT(mod)                                        \
         (atomic_inc(&(mod)->uc.usecount), (mod)->flags |= MOD_VISITED|MOD_USED_ONCE)
 #define __MOD_DEC_USE_COUNT(mod)                                        \
         (atomic_dec(&(mod)->uc.usecount), (mod)->flags |= MOD_VISITED)
+#else
+#define __MOD_INC_USE_COUNT(mod)
+#define __MOD_DEC_USE_COUNT(mod)
+#endif
 #endif
 
 
+#ifndef HAVE_INTER_MODULE
+static inline void *inter_module_get(char *x) {return NULL;}
+static inline void *inter_module_get_request(char *x, char *y) {return NULL;}
+static inline void inter_module_put(const char *x) {}
+static inline void inter_module_register(const char *x, struct module *y, const void *z) {}
+static inline void inter_module_unregister(const char *x) {}
+#endif
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)
 
 #define DECLARE_WAIT_QUEUE_HEAD(x) struct wait_queue *x = NULL
 #define init_waitqueue_head init_waitqueue
 
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+
 static inline int try_inc_mod_count(struct module *mod)
 {
+#ifdef CONFIG_MODULES
 	if (mod)
 		__MOD_INC_USE_COUNT(mod);
+#endif
 	return 1;
 }
 #endif
@@ -190,13 +355,229 @@
 
 #if LINUX_VERSION_CODE < 0x20300
 #include <linux/interrupt.h>
-#define spin_lock_bh(lock) do {start_bh_atomic();spin_lock(lock);} while(0)
-#define spin_unlock_bh(lock) do {spin_unlock(lock);end_bh_atomic();} while(0)
+#define spin_lock_bh(lock) do {start_bh_atomic();spin_lock(lock);}while(0)
+#define spin_unlock_bh(lock) do {spin_unlock(lock);end_bh_atomic();}while(0)
 #else
 #include <asm/softirq.h>
 #include <linux/spinlock.h>
 #endif
 
-#endif /* __LINUX_MTD_COMPATMAC_H__ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)
+#define set_current_state(state_value)                        \
+        do { current->state = (state_value); } while (0)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,0) 
+static inline int invalidate_device(kdev_t dev, int do_sync) {
+
+	if (do_sync)
+		fsync_dev(dev);
+	
+	invalidate_buffers(dev);
+	return 0;
+}
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,4,5)
+static inline int invalidate_device(kdev_t dev, int do_sync) {
+	struct super_block *sb = get_super(dev);
+	int res = 0;
+
+	if (do_sync)
+		fsync_dev(dev);
+	
+	if (sb)
+		res = invalidate_inodes(sb);
+
+	invalidate_buffers(dev);
+	return res;
+}
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10)
+#undef min
+#undef max
+#undef min_t
+#undef max_t
+/*
+ * min()/max() macros that also do
+ * strict type-checking.. See the
+ * "unnecessary" pointer comparison.
+ */
+#define min(x,y) ({ \
+        const typeof(x) _x = (x);       \
+        const typeof(y) _y = (y);       \
+        (void) (&_x == &_y);            \
+        _x < _y ? _x : _y; })
+
+#define max(x,y) ({ \
+        const typeof(x) _x = (x);       \
+        const typeof(y) _y = (y);       \
+        (void) (&_x == &_y);            \
+        _x > _y ? _x : _y; })
+
+/*
+ * ..and if you can't take the strict
+ * types, you can specify one yourself.
+ *
+ * Or not use min/max at all, of course.
+ */
+#define min_t(type,x,y) \
+        ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
+#define max_t(type,x,y) \
+        ({ type __x = (x); type __y = (y); __x > __y ? __x: __y; })
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,7)
+struct completion {
+	struct semaphore s;
+};
+
+#define complete(c) up(&(c)->s)
+#define wait_for_completion(c) down(&(c)->s)
+#define init_completion(c) init_MUTEX_LOCKED(&(c)->s);
+
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,9)
+/* This came later */
+#define complete_and_exit(c, r) do { complete(c); do_exit(r); } while(0)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,9) || \
+    (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10) && !defined(__rh_config_h__))
+
+#include <linux/genhd.h>
 
+static inline void add_gendisk(struct gendisk *gp)
+{
+	gp->next = gendisk_head;
+	gendisk_head = gp;
+}
+
+static inline void del_gendisk(struct gendisk *gp)
+{
+	struct gendisk *gd, **gdp;
+
+	for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next))
+		if (*gdp == gp) {
+			gd = *gdp; *gdp = gd->next;
+			break;
+		}
+}
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18) && defined(MODULE)
+
+#define module_init(func)		\
+mod_init_t init_module(void) {		\
+	return func();			\
+}
+
+#define module_exit(func)		\
+mod_exit_t cleanup_module(void) {	\
+	return func();			\
+}
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,9) || \
+    (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10) && !defined(__rh_config_h__))
+#define MODULE_LICENSE(x) /* */
+#endif
 
+/* Removed for 2.4.21 kernel. This really should have been renamed
+   when it was changed -- this is a PITA */
+#if 0 && LINUX_VERSION_CODE < KERNEL_VERSION(2,5,5)
+#include <linux/sched.h>
+static inline void __recalc_sigpending(void)
+{
+	recalc_sigpending(current);
+}
+#undef recalc_sigpending
+#define recalc_sigpending() __recalc_sigpending ()
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,5)
+#define parent_ino(d) ((d)->d_parent->d_inode->i_ino)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,3)
+#define need_resched() (current->need_resched)
+#define cond_resched() do { if need_resched() schedule(); } while(0)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19)
+#ifndef yield
+#define yield() do { set_current_state(TASK_RUNNING); schedule(); } while(0)
+#endif
+#ifndef minor
+#define major(d) (MAJOR(to_kdev_t(d)))
+#define minor(d) (MINOR(to_kdev_t(d)))
+#endif
+#ifndef mk_kdev
+#define mk_kdev(ma,mi) MKDEV(ma,mi)
+#define kdev_t_to_nr(x)	(x)
+#endif
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
+	/* Is this right? */
+#define set_user_nice(tsk, n) do { (tsk)->priority = 20-(n); } while(0) 
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,4,21) && !defined(RED_HAT_LINUX_KERNEL)
+#define set_user_nice(tsk, n) do { (tsk)->nice = n; } while(0)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,21)
+#define rq_data_dir(x)	((x)->cmd)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+
+#define IS_REQ_CMD(req) (1)
+
+#define QUEUE_LOCK(q) (&io_request_lock)
+
+#define BLK_INIT_QUEUE(q, req, lock) blk_init_queue((q), (req)) 
+
+#else /* > 2.5.0 */
+
+#define IS_REQ_CMD(req) ((req)->flags & REQ_CMD)
+
+#define QUEUE_LOCK(q) ((q)->queue_lock)
+
+#define BLK_INIT_QUEUE(q, req, lock) blk_init_queue((q), (req), (lock)) 
+
+#endif
+
+/* Removed cos it broke stuff. Where is this required anyway? 
+ * #ifndef QUEUE_EMPTY
+ * #define QUEUE_EMPTY  (!CURRENT)
+ * #endif
+ */
+#if LINUX_VERSION_CODE < 0x20300
+#define QUEUE_PLUGGED (blk_dev[MAJOR_NR].plug_tq.sync)
+#elif LINUX_VERSION_CODE < 0x20500 //FIXME (Si)
+#define QUEUE_PLUGGED (blk_dev[MAJOR_NR].request_queue.plugged)
+#else
+#define QUEUE_PLUGGED (blk_queue_plugged(QUEUE))
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14)
+#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT
+#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT
+#else
+#define BLK_INC_USE_COUNT do {} while(0)
+#define BLK_DEC_USE_COUNT do {} while(0)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,12)
+#define PageUptodate(x) Page_Uptodate(x)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,48)
+#define get_seconds() CURRENT_TIME
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,53)
+#define generic_file_readonly_mmap generic_file_mmap
+#endif
+
+#endif /* __LINUX_MTD_COMPATMAC_H__ */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/mtd/flashchip.h linux-2.4.21-pre6/include/linux/mtd/flashchip.h
--- linux-2.4.20/include/linux/mtd/flashchip.h	2001-06-12 17:30:27.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/mtd/flashchip.h	2003-03-26 23:49:54.000000000 +0000
@@ -6,7 +6,7 @@
  *
  * (C) 2000 Red Hat. GPLd.
  *
- * $Id: flashchip.h,v 1.7 2001/01/18 03:52:36 nico Exp $
+ * $Id: flashchip.h,v 1.8 2002/10/21 13:20:52 jocke Exp $
  *
  */
 
@@ -36,6 +36,7 @@
 	FL_UNLOADING,
 	FL_LOCKING,
 	FL_UNLOCKING,
+	FL_POINT,
 	FL_UNKNOWN
 } flstate_t;
 
@@ -54,6 +55,7 @@
 	   a given offset, and we'll want to add the per-chip length field
 	   back in.
 	*/
+	int ref_point_counter;
 	flstate_t state;
 	flstate_t oldstate;
 	spinlock_t *mutex;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/mtd/ftl.h linux-2.4.21-pre6/include/linux/mtd/ftl.h
--- linux-2.4.20/include/linux/mtd/ftl.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/mtd/ftl.h	2003-03-26 23:49:08.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * $Id: ftl.h,v 1.5 2001/06/02 20:35:51 dwmw2 Exp $
+ * $Id: ftl.h,v 1.6 2003/01/24 13:20:04 dwmw2 Exp $
  * 
  * Derived from (and probably identical to):
  * ftl.h 1.7 1999/10/25 20:23:17
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/mtd/map.h linux-2.4.21-pre6/include/linux/mtd/map.h
--- linux-2.4.20/include/linux/mtd/map.h	2001-10-04 22:13:18.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/mtd/map.h	2003-03-26 23:49:30.000000000 +0000
@@ -1,6 +1,6 @@
 
 /* Overhauled routines for dealing with different mmap regions of flash */
-/* $Id: map.h,v 1.25 2001/09/09 15:04:17 dwmw2 Exp $ */
+/* $Id: map.h,v 1.29 2002/10/21 13:20:52 jocke Exp $ */
 
 #ifndef __LINUX_MTD_MAP_H__
 #define __LINUX_MTD_MAP_H__
@@ -33,6 +33,7 @@
 	__u8 (*read8)(struct map_info *, unsigned long);
 	__u16 (*read16)(struct map_info *, unsigned long);
 	__u32 (*read32)(struct map_info *, unsigned long);  
+	__u64 (*read64)(struct map_info *, unsigned long);  
 	/* If it returned a 'long' I'd call it readl.
 	 * It doesn't.
 	 * I won't.
@@ -42,8 +43,12 @@
 	void (*write8)(struct map_info *, __u8, unsigned long);
 	void (*write16)(struct map_info *, __u16, unsigned long);
 	void (*write32)(struct map_info *, __u32, unsigned long);
+	void (*write64)(struct map_info *, __u64, unsigned long);
 	void (*copy_to)(struct map_info *, unsigned long, const void *, ssize_t);
 
+	u_char * (*point) (struct map_info *, loff_t, size_t);
+	void (*unpoint) (struct map_info *, u_char *, loff_t, size_t);
+
 	void (*set_vpp)(struct map_info *, int);
 	/* We put these two here rather than a single void *map_priv, 
 	   because we want mappers to be able to have quickly-accessible
@@ -68,7 +73,7 @@
 void register_mtd_chip_driver(struct mtd_chip_driver *);
 void unregister_mtd_chip_driver(struct mtd_chip_driver *);
 
-struct mtd_info *do_map_probe(char *name, struct map_info *map);
+struct mtd_info *do_map_probe(const char *name, struct map_info *map);
 
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/mtd/mtd.h linux-2.4.21-pre6/include/linux/mtd/mtd.h
--- linux-2.4.20/include/linux/mtd/mtd.h	2001-06-12 17:30:27.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/mtd/mtd.h	2003-03-26 23:48:58.000000000 +0000
@@ -1,5 +1,5 @@
 
-/* $Id: mtd.h,v 1.33 2001/06/09 00:08:59 dwmw2 Exp $ */
+/* $Id: mtd.h,v 1.38 2003/01/12 16:30:19 spse Exp $ */
 
 #ifndef __MTD_MTD_H__
 #define __MTD_MTD_H__
@@ -93,6 +93,8 @@
 #define MEMUNLOCK               _IOW('M', 6, struct erase_info_user)
 #define MEMGETREGIONCOUNT	_IOR('M', 7, int)
 #define MEMGETREGIONINFO	_IOWR('M', 8, struct region_info_user)
+#define	MEMREADDATA             _IOWR('M', 9, struct mtd_oob_buf)
+#define	MEMWRITEDATA            _IOWR('M', 10, struct mtd_oob_buf)
 
 #ifndef __KERNEL__
 
@@ -168,25 +170,41 @@
 	int (*point) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf);
 
 	/* We probably shouldn't allow XIP if the unpoint isn't a NULL */
-	void (*unpoint) (struct mtd_info *mtd, u_char * addr);
+	void (*unpoint) (struct mtd_info *mtd, u_char * addr, loff_t from, size_t len);
 
 
 	int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
 	int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
 
-	int (*read_ecc) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, u_char *eccbuf);
-	int (*write_ecc) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf);
+	int (*read_ecc) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, u_char *eccbuf, int oobsel);
+	int (*write_ecc) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf, int oobsel);
 
 	int (*read_oob) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
 	int (*write_oob) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
 
+	/* 
+	 * Methods to access the protection register area, present in some 
+	 * flash devices. The user data is one time programmable but the
+	 * factory data is read only. 
+	 */
+	int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
+
+	int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
+
+	/* This function is not yet implemented */
+	int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
+
 	/* iovec-based read/write methods. We need these especially for NAND flash,
 	   with its limited number of write cycles per erase.
 	   NB: The 'count' parameter is the number of _vectors_, each of 
 	   which contains an (ofs, len) tuple.
 	*/
 	int (*readv) (struct mtd_info *mtd, struct iovec *vecs, unsigned long count, loff_t from, size_t *retlen);
+	int (*readv_ecc) (struct mtd_info *mtd, struct iovec *vecs, unsigned long count, loff_t from, 
+		size_t *retlen, u_char *eccbuf, int oobsel);
 	int (*writev) (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to, size_t *retlen);
+	int (*writev_ecc) (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to, 
+		size_t *retlen, u_char *eccbuf, int oobsel);
 
 	/* Sync */
 	void (*sync) (struct mtd_info *mtd);
@@ -239,6 +257,11 @@
 extern void register_mtd_user (struct mtd_notifier *new);
 extern int unregister_mtd_user (struct mtd_notifier *old);
 
+int default_mtd_writev(struct mtd_info *mtd, const struct iovec *vecs,
+		       unsigned long count, loff_t to, size_t *retlen);
+
+int default_mtd_readv(struct mtd_info *mtd, struct iovec *vecs,
+		      unsigned long count, loff_t from, size_t *retlen);
 
 #ifndef MTDC
 #define MTD_ERASE(mtd, args...) (*(mtd->erase))(mtd, args)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/mtd/nand.h linux-2.4.21-pre6/include/linux/mtd/nand.h
--- linux-2.4.20/include/linux/mtd/nand.h	2000-12-11 22:57:58.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/mtd/nand.h	2003-03-26 23:49:54.000000000 +0000
@@ -3,8 +3,9 @@
  *
  *  Copyright (c) 2000 David Woodhouse <dwmw2@mvhi.com>
  *                     Steven J. Hill <sjhill@cotw.com>
+ *		       Thomas Gleixner <tglx@linutronix.de>
  *
- * $Id: nand.h,v 1.8 2000/10/30 17:16:17 sjhill Exp $
+ * $Id: nand.h,v 1.19 2002/12/02 21:48:17 gleixner Exp $
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -23,6 +24,26 @@
  *			bat later if I did something naughty.
  *   10-11-2000 SJH     Added private NAND flash structure for driver
  *   10-24-2000 SJH     Added prototype for 'nand_scan' function
+ *   10-29-2001 TG	changed nand_chip structure to support 
+ *			hardwarespecific function for accessing control lines
+ *   02-21-2002 TG	added support for different read/write adress and
+ *			ready/busy line access function
+ *   02-26-2002 TG	added chip_delay to nand_chip structure to optimize
+ *			command delay times for different chips
+ *   04-28-2002 TG	OOB config defines moved from nand.c to avoid duplicate
+ *			defines in jffs2/wbuf.c
+ *   08-07-2002 TG	forced bad block location to byte 5 of OOB, even if
+ *			CONFIG_MTD_NAND_ECC_JFFS2 is not set
+ *   08-10-2002 TG	extensions to nand_chip structure to support HW-ECC
+ *
+ *   08-29-2002 tglx 	nand_chip structure: data_poi for selecting 
+ *			internal / fs-driver buffer
+ *			support for 6byte/512byte hardware ECC
+ *			read_ecc, write_ecc extended for different oob-layout
+ *			oob layout selections: NAND_NONE_OOB, NAND_JFFS2_OOB,
+ *			NAND_YAFFS_OOB
+ *  11-25-2002 tglx	Added Manufacturer code FUJITSU, NATIONAL
+ *			Split manufacturer and device ID structures 
  */
 #ifndef __LINUX_MTD_NAND_H
 #define __LINUX_MTD_NAND_H
@@ -36,6 +57,16 @@
 extern int nand_scan (struct mtd_info *mtd);
 
 /*
+ * Constants for hardware specific CLE/ALE/NCE function
+*/
+#define NAND_CTL_SETNCE 	1
+#define NAND_CTL_CLRNCE		2
+#define NAND_CTL_SETCLE		3
+#define NAND_CTL_CLRCLE		4
+#define NAND_CTL_SETALE		5
+#define NAND_CTL_CLRALE		6
+
+/*
  * Standard NAND flash commands
  */
 #define NAND_CMD_READ0		0
@@ -49,6 +80,29 @@
 #define NAND_CMD_ERASE2		0xd0
 #define NAND_CMD_RESET		0xff
 
+/* 
+ * Constants for ECC_MODES
+ *
+ * NONE:	No ECC
+ * SOFT:	Software ECC 3 byte ECC per 256 Byte data
+ * HW3_256:	Hardware ECC 3 byte ECC per 256 Byte data
+ * HW3_512:	Hardware ECC 3 byte ECC per 512 Byte data
+ *
+ *
+*/
+#define NAND_ECC_NONE		0
+#define NAND_ECC_SOFT		1
+#define NAND_ECC_HW3_256	2
+#define NAND_ECC_HW3_512	3
+#define NAND_ECC_HW6_512	4
+#define NAND_ECC_DISKONCHIP	5
+
+/*
+ * Constants for Hardware ECC
+*/
+#define NAND_ECC_READ		0
+#define NAND_ECC_WRITE		1
+	
 /*
  * Enumeration for NAND flash chip state
  */
@@ -60,20 +114,33 @@
 	FL_SYNCING
 } nand_state_t;
 
+
 /*
  * NAND Private Flash Chip Data
  *
  * Structure overview:
  *
- *  IO_ADDR - address to access the 8 I/O lines to the flash device
+ *  IO_ADDR_R - address to read the 8 I/O lines of the flash device 
+ *
+ *  IO_ADDR_W - address to write the 8 I/O lines of the flash device 
+ *
+ *  hwcontrol - hardwarespecific function for accesing control-lines
  *
- *  CTRL_ADDR - address where ALE, CLE and CE control bits are accessed
+ *  dev_ready - hardwarespecific function for accesing device ready/busy line
  *
- *  CLE - location in control word for Command Latch Enable bit
+ *  waitfunc - hardwarespecific function for wait on ready
  *
- *  ALE - location in control word for Address Latch Enable bit
+ *  calculate_ecc - function for ecc calculation or readback from ecc hardware
  *
- *  NCE - location in control word for nChip Enable bit
+ *  correct_data - function for ecc correction, matching to ecc generator (sw/hw)
+ *
+ *  enable_hwecc - function to enable (reset) hardware ecc generator
+ *
+ *  eccmod - mode of ecc: see constants
+ *
+ *  eccsize - databytes used per ecc-calculation
+ *
+ *  chip_delay - chip dependent delay for transfering data from array to read regs (tR)
  *
  *  chip_lock - spinlock used to protect access to this structure
  *
@@ -85,27 +152,32 @@
  *
  *  data_buf - data buffer passed to/from MTD user modules
  *
- *  ecc_code_buf - used only for holding calculated or read ECCs for
- *                 a page read or written when ECC is in use
+ *  data_cache - data cache for redundant page access and shadow for
+ *		 ECC failure
  *
- *  reserved - padding to make structure fall on word boundary if
- *             when ECC is in use
+ *  cache_page - number of last valid page in page_cache 
  */
 struct nand_chip {
-	unsigned long IO_ADDR;
-	unsigned long CTRL_ADDR;
-	unsigned int CLE;
-	unsigned int ALE;
-	unsigned int NCE;
-	spinlock_t chip_lock;
+	unsigned long 	IO_ADDR_R;
+	unsigned long 	IO_ADDR_W;
+	void 		(*hwcontrol)(int cmd);
+	int  		(*dev_ready)(void);
+	void 		(*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr);
+	int 		(*waitfunc)(struct mtd_info *mtd, struct nand_chip *this, int state);
+	void		(*calculate_ecc)(const u_char *dat, u_char *ecc_code);
+	int 		(*correct_data)(u_char *dat, u_char *read_ecc, u_char *calc_ecc);
+	void		(*enable_hwecc)(int mode);
+	int		eccmode;
+	int		eccsize;
+	int 		chip_delay;
+	spinlock_t 	chip_lock;
 	wait_queue_head_t wq;
-	nand_state_t state;
-	int page_shift;
-	u_char *data_buf;
-#ifdef CONFIG_MTD_NAND_ECC
-	u_char ecc_code_buf[6];
-	u_char reserved[2];
-#endif
+	nand_state_t 	state;
+	int 		page_shift;
+	u_char 		*data_buf;
+	u_char		*data_poi;
+	u_char 		*data_cache;
+	int		cache_page;
 };
 
 /*
@@ -113,17 +185,17 @@
  */
 #define NAND_MFR_TOSHIBA	0x98
 #define NAND_MFR_SAMSUNG	0xec
+#define NAND_MFR_FUJITSU	0x04
+#define NAND_MFR_NATIONAL	0x8f
 
 /*
  * NAND Flash Device ID Structure
  *
  * Structure overview:
  *
- *  name - Complete name of device
+ *  name - Identify the device type
  *
- *  manufacture_id - manufacturer ID code of device.
- *
- *  model_id - model ID code of device.
+ *  id -  device ID code
  *
  *  chipshift - total number of address bits for the device which
  *              is used to calculate address offsets and the total
@@ -143,12 +215,60 @@
  */
 struct nand_flash_dev {
 	char * name;
-	int manufacture_id;
-	int model_id;
+	int id;
 	int chipshift;
-	char page256;
-	char pageadrlen;
 	unsigned long erasesize;
+	char page256;
 };
 
+/*
+ * NAND Flash Manufacturer ID Structure
+ *
+ *  name - Manufacturer name
+ *
+ *  id - manufacturer ID code of device.
+*/
+struct nand_manufacturers {
+	int id;
+	char * name;
+};
+
+extern struct nand_flash_dev nand_flash_ids[];
+extern struct nand_manufacturers nand_manuf_ids[];
+
+/*
+* Constants for oob configuration
+*/
+#define NAND_BADBLOCK_POS		5
+
+#define NAND_NONE_OOB			0
+#define NAND_JFFS2_OOB			1
+#define NAND_YAFFS_OOB			2
+
+#define NAND_NOOB_ECCPOS0		0
+#define NAND_NOOB_ECCPOS1		1
+#define NAND_NOOB_ECCPOS2		2
+#define NAND_NOOB_ECCPOS3		3
+#define NAND_NOOB_ECCPOS4		6
+#define NAND_NOOB_ECCPOS5		7
+
+#define NAND_JFFS2_OOB_ECCPOS0		0
+#define NAND_JFFS2_OOB_ECCPOS1		1
+#define NAND_JFFS2_OOB_ECCPOS2		2
+#define NAND_JFFS2_OOB_ECCPOS3		3
+#define NAND_JFFS2_OOB_ECCPOS4		6
+#define NAND_JFFS2_OOB_ECCPOS5		7
+
+#define NAND_YAFFS_OOB_ECCPOS0		8
+#define NAND_YAFFS_OOB_ECCPOS1		9
+#define NAND_YAFFS_OOB_ECCPOS2		10
+#define NAND_YAFFS_OOB_ECCPOS3		13
+#define NAND_YAFFS_OOB_ECCPOS4		14
+#define NAND_YAFFS_OOB_ECCPOS5		15
+
+#define NAND_JFFS2_OOB8_FSDAPOS		6
+#define NAND_JFFS2_OOB16_FSDAPOS	8
+#define NAND_JFFS2_OOB8_FSDALEN		2
+#define NAND_JFFS2_OOB16_FSDALEN	8
+
 #endif /* __LINUX_MTD_NAND_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/mtd/nftl.h linux-2.4.21-pre6/include/linux/mtd/nftl.h
--- linux-2.4.20/include/linux/mtd/nftl.h	2001-06-12 17:30:27.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/mtd/nftl.h	2003-03-26 23:49:19.000000000 +0000
@@ -2,7 +2,7 @@
 /* Defines for NAND Flash Translation Layer  */
 /* (c) 1999 Machine Vision Holdings, Inc.    */
 /* Author: David Woodhouse <dwmw2@mvhi.com>  */
-/* $Id: nftl.h,v 1.10 2000/12/29 00:25:38 dwmw2 Exp $ */
+/* $Id: nftl.h,v 1.11 2002/06/18 13:54:24 dwmw2 Exp $ */
 
 #ifndef __MTD_NFTL_H__
 #define __MTD_NFTL_H__
@@ -97,7 +97,7 @@
 	__u16 lastEUN;                  /* should be suppressed */
 	__u16 numfreeEUNs;
 	__u16 LastFreeEUN; 		/* To speed up finding a free EUN */
-	__u32 long nr_sects;
+	__u32 nr_sects;
 	int head,sect,cyl;
 	__u16 *EUNtable; 		/* [numvunits]: First EUN for each virtual unit  */
 	__u16 *ReplUnitTable; 		/* [numEUNs]: ReplUnitNumber for each */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/mtd/pmc551.h linux-2.4.21-pre6/include/linux/mtd/pmc551.h
--- linux-2.4.20/include/linux/mtd/pmc551.h	2001-10-04 22:13:18.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/mtd/pmc551.h	2003-03-26 23:48:59.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * $Id: pmc551.h,v 1.4 2001/06/12 16:19:38 major Exp $
+ * $Id: pmc551.h,v 1.5 2003/01/24 16:49:53 dwmw2 Exp $
  *
  * PMC551 PCI Mezzanine Ram Device
  *
@@ -17,7 +17,7 @@
 
 #include <linux/mtd/mtd.h>
 
-#define PMC551_VERSION "$Id: pmc551.h,v 1.4 2001/06/12 16:19:38 major Exp $\n"\
+#define PMC551_VERSION "$Id: pmc551.h,v 1.5 2003/01/24 16:49:53 dwmw2 Exp $\n"\
        "Ramix PMC551 PCI Mezzanine Ram Driver. (C) 1999,2000 Nortel Networks.\n"
 
 /*
@@ -36,7 +36,7 @@
  * Function Prototypes
  */
 static int pmc551_erase(struct mtd_info *, struct erase_info *);
-static void pmc551_unpoint(struct mtd_info *, u_char *);
+static void pmc551_unpoint(struct mtd_info *, u_char *, loff_t, size_t);
 static int pmc551_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf);
 static int pmc551_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *);
 static int pmc551_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);        
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.4.21-pre6/include/linux/netfilter_ipv4/ip_conntrack.h
--- linux-2.4.20/include/linux/netfilter_ipv4/ip_conntrack.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/netfilter_ipv4/ip_conntrack.h	2003-03-26 23:49:29.000000000 +0000
@@ -6,6 +6,7 @@
 
 #include <linux/config.h>
 #include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
+#include <linux/bitops.h>
 #include <asm/atomic.h>
 
 enum ip_conntrack_info
@@ -41,6 +42,10 @@
 	/* Conntrack should never be early-expired. */
 	IPS_ASSURED_BIT = 2,
 	IPS_ASSURED = (1 << IPS_ASSURED_BIT),
+
+	/* Connection is confirmed: originating packet has left box */
+	IPS_CONFIRMED_BIT = 3,
+	IPS_CONFIRMED = (1 << IPS_CONFIRMED_BIT),
 };
 
 #include <linux/netfilter_ipv4/ip_conntrack_tcp.h>
@@ -159,7 +164,7 @@
 	struct ip_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX];
 
 	/* Have we seen traffic both ways yet? (bitset) */
-	volatile unsigned long status;
+	unsigned long status;
 
 	/* Timer function; drops refcnt when it goes off. */
 	struct timer_list timeout;
@@ -254,7 +259,7 @@
 /* It's confirmed if it is, or has been in the hash table. */
 static inline int is_confirmed(struct ip_conntrack *ct)
 {
-	return ct->tuplehash[IP_CT_DIR_ORIGINAL].list.next != NULL;
+	return test_bit(IPS_CONFIRMED_BIT, &ct->status);
 }
 
 extern unsigned int ip_conntrack_htable_size;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/netfilter_ipv4/ip_nat_helper.h linux-2.4.21-pre6/include/linux/netfilter_ipv4/ip_nat_helper.h
--- linux-2.4.20/include/linux/netfilter_ipv4/ip_nat_helper.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/netfilter_ipv4/ip_nat_helper.h	2003-03-26 23:49:19.000000000 +0000
@@ -50,6 +50,13 @@
 				unsigned int match_len,
 				char *rep_buffer,
 				unsigned int rep_len);
+extern int ip_nat_mangle_udp_packet(struct sk_buff **skb,
+				struct ip_conntrack *ct,
+				enum ip_conntrack_info ctinfo,
+				unsigned int match_offset,
+				unsigned int match_len,
+				char *rep_buffer,
+				unsigned int rep_len);
 extern int ip_nat_seq_adjust(struct sk_buff *skb,
 				struct ip_conntrack *ct,
 				enum ip_conntrack_info ctinfo);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/netfilter_ipv6/ip6t_ah.h linux-2.4.21-pre6/include/linux/netfilter_ipv6/ip6t_ah.h
--- linux-2.4.20/include/linux/netfilter_ipv6/ip6t_ah.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/netfilter_ipv6/ip6t_ah.h	2003-03-26 23:49:50.000000000 +0000
@@ -0,0 +1,30 @@
+#ifndef _IP6T_AH_H
+#define _IP6T_AH_H
+
+struct ip6t_ah
+{
+	u_int32_t spis[2];			/* Security Parameter Index */
+	u_int32_t hdrlen;			/* Header Length */
+	u_int8_t  hdrres;			/* Test of the Reserved Filed */
+	u_int8_t  invflags;			/* Inverse flags */
+};
+
+#define IP6T_AH_SPI 0x01
+#define IP6T_AH_LEN 0x02
+#define IP6T_AH_RES 0x04
+
+/* Values for "invflags" field in struct ip6t_ah. */
+#define IP6T_AH_INV_SPI		0x01	/* Invert the sense of spi. */
+#define IP6T_AH_INV_LEN		0x02	/* Invert the sense of length. */
+#define IP6T_AH_INV_MASK	0x03	/* All possible flags. */
+
+#define MASK_HOPOPTS    128
+#define MASK_DSTOPTS    64
+#define MASK_ROUTING    32
+#define MASK_FRAGMENT   16
+#define MASK_AH         8
+#define MASK_ESP        4
+#define MASK_NONE       2
+#define MASK_PROTO      1
+
+#endif /*_IP6T_AH_H*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/netfilter_ipv6/ip6t_esp.h linux-2.4.21-pre6/include/linux/netfilter_ipv6/ip6t_esp.h
--- linux-2.4.20/include/linux/netfilter_ipv6/ip6t_esp.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/netfilter_ipv6/ip6t_esp.h	2003-03-26 23:49:53.000000000 +0000
@@ -0,0 +1,23 @@
+#ifndef _IP6T_ESP_H
+#define _IP6T_ESP_H
+
+struct ip6t_esp
+{
+	u_int32_t spis[2];			/* Security Parameter Index */
+	u_int8_t  invflags;			/* Inverse flags */
+};
+
+#define MASK_HOPOPTS    128
+#define MASK_DSTOPTS    64
+#define MASK_ROUTING    32
+#define MASK_FRAGMENT   16
+#define MASK_AH         8
+#define MASK_ESP        4
+#define MASK_NONE       2
+#define MASK_PROTO      1
+
+/* Values for "invflags" field in struct ip6t_esp. */
+#define IP6T_ESP_INV_SPI		0x01	/* Invert the sense of spi. */
+#define IP6T_ESP_INV_MASK	0x01	/* All possible flags. */
+
+#endif /*_IP6T_ESP_H*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/netfilter_ipv6/ip6t_frag.h linux-2.4.21-pre6/include/linux/netfilter_ipv6/ip6t_frag.h
--- linux-2.4.20/include/linux/netfilter_ipv6/ip6t_frag.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/netfilter_ipv6/ip6t_frag.h	2003-03-26 23:49:07.000000000 +0000
@@ -0,0 +1,33 @@
+#ifndef _IP6T_FRAG_H
+#define _IP6T_FRAG_H
+
+struct ip6t_frag
+{
+	u_int32_t ids[2];			/* Security Parameter Index */
+	u_int32_t hdrlen;			/* Header Length */
+	u_int8_t  flags;			/*  */
+	u_int8_t  invflags;			/* Inverse flags */
+};
+
+#define IP6T_FRAG_IDS 		0x01
+#define IP6T_FRAG_LEN 		0x02
+#define IP6T_FRAG_RES 		0x04
+#define IP6T_FRAG_FST 		0x08
+#define IP6T_FRAG_MF  		0x10
+#define IP6T_FRAG_NMF  		0x20
+
+/* Values for "invflags" field in struct ip6t_frag. */
+#define IP6T_FRAG_INV_IDS	0x01	/* Invert the sense of ids. */
+#define IP6T_FRAG_INV_LEN	0x02	/* Invert the sense of length. */
+#define IP6T_FRAG_INV_MASK	0x03	/* All possible flags. */
+
+#define MASK_HOPOPTS    128
+#define MASK_DSTOPTS    64
+#define MASK_ROUTING    32
+#define MASK_FRAGMENT   16
+#define MASK_AH         8
+#define MASK_ESP        4
+#define MASK_NONE       2
+#define MASK_PROTO      1
+
+#endif /*_IP6T_FRAG_H*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/netfilter_ipv6/ip6t_hl.h linux-2.4.21-pre6/include/linux/netfilter_ipv6/ip6t_hl.h
--- linux-2.4.20/include/linux/netfilter_ipv6/ip6t_hl.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/netfilter_ipv6/ip6t_hl.h	2003-03-26 23:49:09.000000000 +0000
@@ -0,0 +1,22 @@
+/* ip6tables module for matching the Hop Limit value
+ * Maciej Soltysiak <solt@dns.toxicfilms.tv>
+ * Based on HW's ttl module */
+
+#ifndef _IP6T_HL_H
+#define _IP6T_HL_H
+
+enum {
+	IP6T_HL_EQ = 0,		/* equals */
+	IP6T_HL_NE,		/* not equals */
+	IP6T_HL_LT,		/* less than */
+	IP6T_HL_GT,		/* greater than */
+};
+
+
+struct ip6t_hl_info {
+	u_int8_t	mode;
+	u_int8_t	hop_limit;
+};
+
+
+#endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/netfilter_ipv6/ip6t_ipv6header.h linux-2.4.21-pre6/include/linux/netfilter_ipv6/ip6t_ipv6header.h
--- linux-2.4.20/include/linux/netfilter_ipv6/ip6t_ipv6header.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/netfilter_ipv6/ip6t_ipv6header.h	2003-03-26 23:49:29.000000000 +0000
@@ -0,0 +1,27 @@
+/* ipv6header match - matches IPv6 packets based
+on whether they contain certain headers */
+
+/* Original idea: Brad Chapman 
+ * Rewritten by: Andras Kis-Szabo <kisza@sch.bme.hu> */
+
+
+#ifndef __IPV6HEADER_H
+#define __IPV6HEADER_H
+
+struct ip6t_ipv6header_info
+{
+	u_int8_t matchflags;
+	u_int8_t invflags;
+	u_int8_t modeflag;
+};
+
+#define MASK_HOPOPTS    128
+#define MASK_DSTOPTS    64
+#define MASK_ROUTING    32
+#define MASK_FRAGMENT   16
+#define MASK_AH         8
+#define MASK_ESP        4
+#define MASK_NONE       2
+#define MASK_PROTO      1
+
+#endif /* __IPV6HEADER_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/netfilter_ipv6/ip6t_opts.h linux-2.4.21-pre6/include/linux/netfilter_ipv6/ip6t_opts.h
--- linux-2.4.20/include/linux/netfilter_ipv6/ip6t_opts.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/netfilter_ipv6/ip6t_opts.h	2003-03-26 23:49:51.000000000 +0000
@@ -0,0 +1,32 @@
+#ifndef _IP6T_OPTS_H
+#define _IP6T_OPTS_H
+
+#define IP6T_OPTS_OPTSNR 16
+
+struct ip6t_opts
+{
+	u_int32_t hdrlen;			/* Header Length */
+	u_int8_t flags;				/*  */
+	u_int8_t invflags;			/* Inverse flags */
+	u_int16_t opts[IP6T_OPTS_OPTSNR];	/* opts */
+	u_int8_t optsnr;			/* Nr of OPts */
+};
+
+#define IP6T_OPTS_LEN 		0x01
+#define IP6T_OPTS_OPTS 		0x02
+#define IP6T_OPTS_NSTRICT	0x04
+
+/* Values for "invflags" field in struct ip6t_rt. */
+#define IP6T_OPTS_INV_LEN	0x01	/* Invert the sense of length. */
+#define IP6T_OPTS_INV_MASK	0x01	/* All possible flags. */
+
+#define MASK_HOPOPTS    128
+#define MASK_DSTOPTS    64
+#define MASK_ROUTING    32
+#define MASK_FRAGMENT   16
+#define MASK_AH         8
+#define MASK_ESP        4
+#define MASK_NONE       2
+#define MASK_PROTO      1
+
+#endif /*_IP6T_OPTS_H*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/netfilter_ipv6/ip6t_rt.h linux-2.4.21-pre6/include/linux/netfilter_ipv6/ip6t_rt.h
--- linux-2.4.20/include/linux/netfilter_ipv6/ip6t_rt.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/netfilter_ipv6/ip6t_rt.h	2003-03-26 23:49:20.000000000 +0000
@@ -0,0 +1,42 @@
+#ifndef _IP6T_RT_H
+#define _IP6T_RT_H
+
+/*#include <linux/in6.h>*/
+
+#define IP6T_RT_HOPS 16
+
+struct ip6t_rt
+{
+	u_int32_t rt_type;			/* Routing Type */
+	u_int32_t segsleft[2];			/* Segments Left */
+	u_int32_t hdrlen;			/* Header Length */
+	u_int8_t  flags;			/*  */
+	u_int8_t  invflags;			/* Inverse flags */
+	struct in6_addr addrs[IP6T_RT_HOPS];	/* Hops */
+	u_int8_t addrnr;			/* Nr of Addresses */
+};
+
+#define IP6T_RT_TYP 		0x01
+#define IP6T_RT_SGS 		0x02
+#define IP6T_RT_LEN 		0x04
+#define IP6T_RT_RES 		0x08
+#define IP6T_RT_FST_MASK	0x30
+#define IP6T_RT_FST 		0x10
+#define IP6T_RT_FST_NSTRICT	0x20
+
+/* Values for "invflags" field in struct ip6t_rt. */
+#define IP6T_RT_INV_TYP		0x01	/* Invert the sense of type. */
+#define IP6T_RT_INV_SGS		0x02	/* Invert the sense of Segments. */
+#define IP6T_RT_INV_LEN		0x04	/* Invert the sense of length. */
+#define IP6T_RT_INV_MASK	0x07	/* All possible flags. */
+
+#define MASK_HOPOPTS    128
+#define MASK_DSTOPTS    64
+#define MASK_ROUTING    32
+#define MASK_FRAGMENT   16
+#define MASK_AH         8
+#define MASK_ESP        4
+#define MASK_NONE       2
+#define MASK_PROTO      1
+
+#endif /*_IP6T_RT_H*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/nfs_fs.h linux-2.4.21-pre6/include/linux/nfs_fs.h
--- linux-2.4.20/include/linux/nfs_fs.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/nfs_fs.h	2003-03-26 23:49:29.000000000 +0000
@@ -269,6 +269,10 @@
 extern int  nfs_scan_lru_read(struct nfs_server *, struct list_head *);
 extern int  nfs_scan_lru_read_timeout(struct nfs_server *, struct list_head *);
 
+#define NFS_SetPageSync(page)		set_bit(PG_fs_1, &(page)->flags)
+#define NFS_ClearPageSync(page)		clear_bit(PG_fs_1, &(page)->flags)
+#define NFS_TestClearPageSync(page)	test_and_clear_bit(PG_fs_1, &(page)->flags)
+
 /*
  * linux/fs/mount_clnt.c
  * (Used only by nfsroot module)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/nfsd/const.h linux-2.4.21-pre6/include/linux/nfsd/const.h
--- linux-2.4.20/include/linux/nfsd/const.h	2000-04-01 16:04:27.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/nfsd/const.h	2003-03-26 23:49:07.000000000 +0000
@@ -21,7 +21,7 @@
 /*
  * Maximum blocksize supported by daemon currently at 8K
  */
-#define NFSSVC_MAXBLKSIZE	8192
+#define NFSSVC_MAXBLKSIZE	(8*1024)
 
 #ifdef __KERNEL__
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/nubus.h linux-2.4.21-pre6/include/linux/nubus.h
--- linux-2.4.20/include/linux/nubus.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/nubus.h	2003-03-26 23:49:50.000000000 +0000
@@ -28,18 +28,18 @@
 };
 
 enum nubus_type_network {
-	NUBUS_TYPE_ETHERNET = 0x0001,
-	NUBUS_TYPE_RS232    = 0x0002
+	NUBUS_TYPE_ETHERNET 	 = 0x0001,
+	NUBUS_TYPE_RS232    	 = 0x0002
 };
 
 enum nubus_type_display {
-	NUBUS_TYPE_VIDEO = 0x0001
+	NUBUS_TYPE_VIDEO 	 = 0x0001
 };
 
 enum nubus_type_cpu {
-	NUBUS_TYPE_68020 = 0x0003,
-	NUBUS_TYPE_68030 = 0x0004,
-	NUBUS_TYPE_68040 = 0x0005
+	NUBUS_TYPE_68020 	 = 0x0003,
+	NUBUS_TYPE_68030 	 = 0x0004,
+	NUBUS_TYPE_68040 	 = 0x0005
 };
 
 /* Known <Cat,Type,SW,HW> tuples: (according to TattleTech and Slots)
@@ -80,22 +80,24 @@
 /* Add known DrSW values here */
 enum nubus_drsw {
 	/* NUBUS_CAT_DISPLAY */
-	NUBUS_DRSW_APPLE       = 0x0001,
-	NUBUS_DRSW_APPLE_HIRES = 0x0013, /* MacII HiRes card driver */
+	NUBUS_DRSW_APPLE       	= 0x0001,
+	NUBUS_DRSW_APPLE_HIRES 	= 0x0013, /* MacII HiRes card driver */
 	
 	/* NUBUS_CAT_NETWORK */
-	NUBUS_DRSW_CABLETRON        = 0x0001,
-	NUBUS_DRSW_SONIC_LC         = 0x0001,
-	NUBUS_DRSW_KINETICS         = 0x0103,
-	NUBUS_DRSW_ASANTE           = 0x0104,
-	NUBUS_DRSW_DAYNA            = 0x010b,
-	NUBUS_DRSW_FARALLON         = 0x010c,
-	NUBUS_DRSW_APPLE_SN         = 0x010f,
-	NUBUS_DRSW_FOCUS            = 0x011a,
-	NUBUS_DRSW_ASANTE_CS        = 0x011d, /* use asante SMC9194 driver */
+	NUBUS_DRSW_CABLETRON   	= 0x0001,
+	NUBUS_DRSW_SONIC_LC    	= 0x0001,
+	NUBUS_DRSW_KINETICS    	= 0x0103,
+	NUBUS_DRSW_ASANTE      	= 0x0104,
+	NUBUS_DRSW_DAYNA       	= 0x010b,
+	NUBUS_DRSW_FARALLON    	= 0x010c,
+	NUBUS_DRSW_APPLE_SN    	= 0x010f,
+	NUBUS_DRSW_DAYNA2	= 0x0115,
+	NUBUS_DRSW_FOCUS        = 0x011a,
+	NUBUS_DRSW_ASANTE_CS    = 0x011d, /* use asante SMC9194 driver */
+	NUBUS_DRSW_DAYNA_LC	= 0x011e,
 
 	/* NUBUS_CAT_CPU */
-	NUBUS_DRSW_NONE        = 0x0000,
+	NUBUS_DRSW_NONE        	= 0x0000,
 };
 
 /* DrHW: Uniquely identifies the hardware interface to a board (or at
@@ -106,11 +108,13 @@
 enum nubus_drhw {
 	/* NUBUS_CAT_DISPLAY */
 	NUBUS_DRHW_APPLE_TFB	= 0x0001, /* Toby frame buffer card */
+	NUBUS_DRHW_APPLE_HRVC	= 0x0013, /* Mac II High Res Video card */
 	NUBUS_DRHW_APPLE_RBV1   = 0x0018, /* IIci RBV video */
 	NUBUS_DRHW_APPLE_MDC    = 0x0019, /* Macintosh Display Card */
 	NUBUS_DRHW_APPLE_SONORA = 0x0022, /* Sonora built-in video */
+	NUBUS_DRHW_APPLE_JET 	= 0x0029, /* Jet framebuffer (DuoDock) */
 	NUBUS_DRHW_APPLE_VALKYRIE = 0x002e,
-	NUBUS_DRHW_APPLE_JET =    0x0029, /* Jet framebuffer (DuoDock) */
+	NUBUS_DRHW_THUNDER24	= 0x02cb, /* SuperMac Thunder/24 */
 	
 	/* NUBUS_CAT_NETWORK */
 	NUBUS_DRHW_INTERLAN     = 0x0100,
@@ -119,6 +123,11 @@
 	NUBUS_DRHW_CABLETRON    = 0x0109,
 	NUBUS_DRHW_ASANTE_LC    = 0x010f,
 	NUBUS_DRHW_SONIC        = 0x0110,
+	NUBUS_DRHW_SONIC_NB	= 0x0118,
+	NUBUS_DRHW_SONIC_LC	= 0x0119,
+	
+	/* NUBUS_CAT_COMMUNICATIONS */
+	NUBUS_DRHW_DOVEFAX	= 0x0100,
 };
 
 /* Resource IDs: These are the identifiers for the various weird and
@@ -153,8 +162,8 @@
 	NUBUS_RESID_SECONDINIT	 = 0x0026,
 
 	/* Not sure why Apple put these next two in here */
-	NUBUS_RESID_VIDNAMES = 0x0041,
-	NUBUS_RESID_VIDMODES = 0x007e
+	NUBUS_RESID_VIDNAMES 	 = 0x0041,
+	NUBUS_RESID_VIDMODES 	 = 0x007e
 };
 
 /* Fields within the vendor info directory */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/pci.h linux-2.4.21-pre6/include/linux/pci.h
--- linux-2.4.20/include/linux/pci.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/pci.h	2003-03-26 23:49:35.000000000 +0000
@@ -65,9 +65,9 @@
 #define  PCI_HEADER_TYPE_CARDBUS 2
 
 #define PCI_BIST		0x0f	/* 8 bits */
-#define PCI_BIST_CODE_MASK	0x0f	/* Return result */
-#define PCI_BIST_START		0x40	/* 1 to start BIST, 2 secs or less */
-#define PCI_BIST_CAPABLE	0x80	/* 1 if BIST capable */
+#define  PCI_BIST_CODE_MASK	0x0f	/* Return result */
+#define  PCI_BIST_START		0x40	/* 1 to start BIST, 2 secs or less */
+#define  PCI_BIST_CAPABLE	0x80	/* 1 if BIST capable */
 
 /*
  * Base addresses specify locations in memory or I/O space.
@@ -195,6 +195,7 @@
 #define  PCI_CAP_ID_SLOTID	0x04	/* Slot Identification */
 #define  PCI_CAP_ID_MSI		0x05	/* Message Signalled Interrupts */
 #define  PCI_CAP_ID_CHSWP	0x06	/* CompactPCI HotSwap */
+#define  PCI_CAP_ID_PCIX	0x07	/* PCI-X */
 #define PCI_CAP_LIST_NEXT	1	/* Next capability in the list */
 #define PCI_CAP_FLAGS		2	/* Capability defined flags (16 bits) */
 #define PCI_CAP_SIZEOF		4
@@ -271,6 +272,37 @@
 #define PCI_MSI_DATA_32		8	/* 16 bits of data for 32-bit devices */
 #define PCI_MSI_DATA_64		12	/* 16 bits of data for 64-bit devices */
 
+/* CompactPCI Hotswap Register */
+
+#define PCI_CHSWP_CSR		2	/* Control and Status Register */
+#define  PCI_CHSWP_DHA		0x01	/* Device Hiding Arm */
+#define  PCI_CHSWP_EIM		0x02	/* ENUM# Signal Mask */
+#define  PCI_CHSWP_PIE		0x04	/* Pending Insert or Extract */
+#define  PCI_CHSWP_LOO		0x08	/* LED On / Off */
+#define  PCI_CHSWP_PI		0x30	/* Programming Interface */
+#define  PCI_CHSWP_EXT		0x40	/* ENUM# status - extraction */
+#define  PCI_CHSWP_INS		0x80	/* ENUM# status - insertion */
+
+/* PCI-X registers */
+
+#define PCI_X_CMD		2	/* Modes & Features */
+#define  PCI_X_CMD_DPERR_E	0x0001	/* Data Parity Error Recovery Enable */
+#define  PCI_X_CMD_ERO		0x0002	/* Enable Relaxed Ordering */
+#define  PCI_X_CMD_MAX_READ	0x000c	/* Max Memory Read Byte Count */
+#define  PCI_X_CMD_MAX_SPLIT	0x0070	/* Max Outstanding Split Transactions */
+#define PCI_X_DEVFN		4	/* A copy of devfn. */
+#define PCI_X_BUSNR		5	/* Bus segment number */
+#define PCI_X_STATUS		6	/* PCI-X capabilities */
+#define  PCI_X_STATUS_64BIT	0x0001	/* 64-bit device */
+#define  PCI_X_STATUS_133MHZ	0x0002	/* 133 MHz capable */
+#define  PCI_X_STATUS_SPL_DISC	0x0004	/* Split Completion Discarded */
+#define  PCI_X_STATUS_UNX_SPL	0x0008	/* Unexpected Split Completion */
+#define  PCI_X_STATUS_COMPLEX	0x0010	/* Device Complexity */
+#define  PCI_X_STATUS_MAX_READ	0x0060	/* Designed Maximum Memory Read Count */
+#define  PCI_X_STATUS_MAX_SPLIT	0x0380	/* Design Max Outstanding Split Trans */
+#define  PCI_X_STATUS_MAX_CUM	0x1c00	/* Designed Max Cumulative Read Size */
+#define  PCI_X_STATUS_SPL_ERR	0x2000	/* Rcvd Split Completion Error Msg */
+
 /* Include the ID list */
 
 #include <linux/pci_ids.h>
@@ -767,6 +799,7 @@
 #define PCIPCI_NATOMA		4
 #define PCIPCI_VIAETBF		8
 #define PCIPCI_VSFX		16
+#define PCIPCI_ALIMAGIK		32
 
 #endif /* __KERNEL__ */
 #endif /* LINUX_PCI_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/pci_ids.h linux-2.4.21-pre6/include/linux/pci_ids.h
--- linux-2.4.20/include/linux/pci_ids.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/pci_ids.h	2003-03-26 23:49:31.000000000 +0000
@@ -136,6 +136,7 @@
 #define PCI_DEVICE_ID_COMPAQ_TACHYON	0xa0fc
 #define PCI_DEVICE_ID_COMPAQ_SMART2P	0xae10
 #define PCI_DEVICE_ID_COMPAQ_NETEL100	0xae32
+#define PCI_DEVICE_ID_COMPAQ_TRIFLEX_IDE 0xae33
 #define PCI_DEVICE_ID_COMPAQ_NETEL10	0xae34
 #define PCI_DEVICE_ID_COMPAQ_NETFLEX3I	0xae35
 #define PCI_DEVICE_ID_COMPAQ_NETEL100D	0xae40
@@ -143,6 +144,7 @@
 #define PCI_DEVICE_ID_COMPAQ_NETEL100I	0xb011
 #define PCI_DEVICE_ID_COMPAQ_CISS	0xb060
 #define PCI_DEVICE_ID_COMPAQ_CISSB	0xb178
+#define PCI_DEVICE_ID_COMPAQ_CISSC 	0x0046
 #define PCI_DEVICE_ID_COMPAQ_THUNDER	0xf130
 #define PCI_DEVICE_ID_COMPAQ_NETFLEX3B	0xf150
 
@@ -172,6 +174,8 @@
 #define PCI_DEVICE_ID_LSI_FC929_LAN	0x0623
 #define PCI_DEVICE_ID_LSI_FC919		0x0624
 #define PCI_DEVICE_ID_LSI_FC919_LAN	0x0625
+#define PCI_DEVICE_ID_LSI_FC929X	0x0626
+#define PCI_DEVICE_ID_LSI_FC919X	0x0628
 #define PCI_DEVICE_ID_NCR_YELLOWFIN	0x0701
 #define PCI_DEVICE_ID_LSI_61C102	0x0901
 #define PCI_DEVICE_ID_LSI_63C815	0x1000
@@ -265,6 +269,8 @@
 #define PCI_DEVICE_ID_ATI_RADEON_RB	0x5145
 #define PCI_DEVICE_ID_ATI_RADEON_RC	0x5146
 #define PCI_DEVICE_ID_ATI_RADEON_RD	0x5147
+/* RadeonIGP */
+#define PCI_DEVICE_ID_ATI_RADEON_IGP	0xCAB0
 
 #define PCI_VENDOR_ID_VLSI		0x1004
 #define PCI_DEVICE_ID_VLSI_82C592	0x0005
@@ -288,6 +294,12 @@
 #define PCI_DEVICE_ID_NS_87560_USB	0x0012
 #define PCI_DEVICE_ID_NS_83815		0x0020
 #define PCI_DEVICE_ID_NS_83820		0x0022
+#define PCI_DEVICE_ID_NS_SCx200_BRIDGE	0x0500
+#define PCI_DEVICE_ID_NS_SCx200_SMI	0x0501
+#define PCI_DEVICE_ID_NS_SCx200_IDE	0x0502
+#define PCI_DEVICE_ID_NS_SCx200_AUDIO	0x0503
+#define PCI_DEVICE_ID_NS_SCx200_VIDEO	0x0504
+#define PCI_DEVICE_ID_NS_SCx200_XBUS	0x0505
 #define PCI_DEVICE_ID_NS_87410		0xd001
 
 #define PCI_VENDOR_ID_TSENG		0x100c
@@ -372,7 +384,7 @@
 #define PCI_DEVICE_ID_AMD_FE_GATE_7006	0x7006
 #define PCI_DEVICE_ID_AMD_FE_GATE_7007	0x7007
 #define PCI_DEVICE_ID_AMD_FE_GATE_700C	0x700C
-#define PCI_DEVIDE_ID_AMD_FE_GATE_700D	0x700D
+#define PCI_DEVICE_ID_AMD_FE_GATE_700D	0x700D
 #define PCI_DEVICE_ID_AMD_FE_GATE_700E	0x700E
 #define PCI_DEVICE_ID_AMD_FE_GATE_700F	0x700F
 #define PCI_DEVICE_ID_AMD_COBRA_7400	0x7400
@@ -387,13 +399,20 @@
 #define PCI_DEVICE_ID_AMD_VIPER_7411	0x7411
 #define PCI_DEVICE_ID_AMD_VIPER_7413	0x7413
 #define PCI_DEVICE_ID_AMD_VIPER_7414	0x7414
-#define PCI_DEVICE_ID_AMD_VIPER_7440	0x7440
-#define PCI_DEVICE_ID_AMD_VIPER_7441	0x7441
-#define PCI_DEVICE_ID_AMD_VIPER_7443	0x7443
-#define PCI_DEVICE_ID_AMD_VIPER_7448	0x7448
-#define PCI_DEVICE_ID_AMD_VIPER_7449	0x7449
+#define PCI_DEVICE_ID_AMD_OPUS_7440	0x7440
+#	define PCI_DEVICE_ID_AMD_VIPER_7440	PCI_DEVICE_ID_AMD_OPUS_7440
+#define PCI_DEVICE_ID_AMD_OPUS_7441	0x7441
+#	define PCI_DEVICE_ID_AMD_VIPER_7441	PCI_DEVICE_ID_AMD_OPUS_7441
+#define PCI_DEVICE_ID_AMD_OPUS_7443	0x7443
+#	define PCI_DEVICE_ID_AMD_VIPER_7443	PCI_DEVICE_ID_AMD_OPUS_7443
+#define PCI_DEVICE_ID_AMD_OPUS_7448	0x7448
+# define	PCI_DEVICE_ID_AMD_VIPER_7448	PCI_DEVICE_ID_AMD_OPUS_7448
+#define PCI_DEVICE_ID_AMD_OPUS_7449	0x7449
+#	define PCI_DEVICE_ID_AMD_VIPER_7449	PCI_DEVICE_ID_AMD_OPUS_7449
+#define PCI_DEVICE_ID_AMD_8111_LAN	0x7462
 #define PCI_DEVICE_ID_AMD_8111_IDE     0x7469
 #define PCI_DEVICE_ID_AMD_8111_AC97    0x746d
+#define PCI_DEVICE_ID_AMD_8131_APIC     0x7450
 
 #define PCI_VENDOR_ID_TRIDENT		0x1023
 #define PCI_DEVICE_ID_TRIDENT_4DWAVE_DX	0x2000
@@ -477,20 +496,28 @@
 #define PCI_DEVICE_ID_SI_635		0x0635
 #define PCI_DEVICE_ID_SI_640		0x0640
 #define PCI_DEVICE_ID_SI_645		0x0645
-#define PCI_DEVICE_ID_SI_646        0x0646
+#define PCI_DEVICE_ID_SI_646		0x0646
+#define PCI_DEVICE_ID_SI_648		0x0648
 #define PCI_DEVICE_ID_SI_650		0x0650
+#define PCI_DEVICE_ID_SI_651		0x0651
+#define PCI_DEVICE_ID_SI_652		0x0652
 #define PCI_DEVICE_ID_SI_730		0x0730
 #define PCI_DEVICE_ID_SI_630_VGA	0x6300
 #define PCI_DEVICE_ID_SI_730_VGA	0x7300
 #define PCI_DEVICE_ID_SI_735		0x0735
 #define PCI_DEVICE_ID_SI_740		0x0740
 #define PCI_DEVICE_ID_SI_745		0x0745
+#define PCI_DEVICE_ID_SI_746		0x0746
+#define PCI_DEVICE_ID_SI_748		0x0748
 #define PCI_DEVICE_ID_SI_750		0x0750
+#define PCI_DEVICE_ID_SI_751		0x0751
+#define PCI_DEVICE_ID_SI_752		0x0752
 #define PCI_DEVICE_ID_SI_900		0x0900
 #define PCI_DEVICE_ID_SI_5107		0x5107
 #define PCI_DEVICE_ID_SI_5300		0x5300
 #define PCI_DEVICE_ID_SI_5511		0x5511
 #define PCI_DEVICE_ID_SI_5513		0x5513
+#define PCI_DEVICE_ID_SI_5518		0x5518
 #define PCI_DEVICE_ID_SI_5571		0x5571
 #define PCI_DEVICE_ID_SI_5591		0x5591
 #define PCI_DEVICE_ID_SI_5597		0x5597
@@ -740,7 +767,9 @@
 #define PCI_DEVICE_ID_CMD_648		0x0648
 #define PCI_DEVICE_ID_CMD_649		0x0649
 #define PCI_DEVICE_ID_CMD_670		0x0670
-#define PCI_DEVICE_ID_CMD_680		0x0680
+
+#define PCI_DEVICE_ID_SII_680		0x0680
+#define PCI_DEVICE_ID_SII_3112		0x3112
 
 #define PCI_VENDOR_ID_VISION		0x1098
 #define PCI_DEVICE_ID_VISION_QD8500	0x0001
@@ -801,6 +830,14 @@
 #define PCI_DEVICE_ID_3COM_3C905TX	0x9050
 #define PCI_DEVICE_ID_3COM_3C905T4	0x9051
 #define PCI_DEVICE_ID_3COM_3C905B_TX	0x9055
+#define PCI_DEVICE_ID_3COM_3CR990	0x9900
+#define PCI_DEVICE_ID_3COM_3CR990_TX_95	0x9902
+#define PCI_DEVICE_ID_3COM_3CR990_TX_97	0x9903
+#define PCI_DEVICE_ID_3COM_3CR990B	0x9904
+#define PCI_DEVICE_ID_3COM_3CR990_FX	0x9905
+#define PCI_DEVICE_ID_3COM_3CR990SVR95	0x9908
+#define PCI_DEVICE_ID_3COM_3CR990SVR97	0x9909
+#define PCI_DEVICE_ID_3COM_3CR990SVR	0x990a
 
 #define PCI_VENDOR_ID_SMC		0x10b8
 #define PCI_DEVICE_ID_SMC_EPIC100	0x0005
@@ -872,6 +909,7 @@
 #define PCI_DEVICE_ID_NVIDIA_UTNT2		0x0029
 #define PCI_DEVICE_ID_NVIDIA_VTNT2		0x002C
 #define PCI_DEVICE_ID_NVIDIA_UVTNT2		0x002D
+#define PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE	0x0065
 #define PCI_DEVICE_ID_NVIDIA_ITNT2		0x00A0
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE_SDR	0x0100
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE_DDR	0x0101
@@ -885,6 +923,7 @@
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE2_ULTRA	0x0152
 #define PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO	0x0153
 #define PCI_DEVICE_ID_NVIDIA_IGEFORCE2		0x01a0
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_IDE		0x01bc
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE3		0x0200
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE3_1		0x0201
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE3_2		0x0202
@@ -986,6 +1025,10 @@
 #define PCI_DEVICE_ID_VIA_8233C_0	0x3109
 #define PCI_DEVICE_ID_VIA_8361		0x3112
 #define PCI_DEVICE_ID_VIA_8233A		0x3147
+#define PCI_DEVICE_ID_VIA_P4X333   0x3168
+#define PCI_DEVICE_ID_VIA_8235        0x3177
+#define PCI_DEVICE_ID_VIA_8377_0  0x3189
+#define PCI_DEVICE_ID_VIA_8377_0	0x3189
 #define PCI_DEVICE_ID_VIA_86C100A	0x6100
 #define PCI_DEVICE_ID_VIA_8231		0x8231
 #define PCI_DEVICE_ID_VIA_8231_4	0x8235
@@ -1083,6 +1126,7 @@
 #define PCI_DEVICE_ID_SYSKONNECT_FP	0x4000
 #define PCI_DEVICE_ID_SYSKONNECT_TR	0x4200
 #define PCI_DEVICE_ID_SYSKONNECT_GE	0x4300
+#define PCI_DEVICE_ID_SYSKONNECT_YU	0x4320
 
 #define PCI_VENDOR_ID_VMIC		0x114a
 #define PCI_DEVICE_ID_VMIC_VME		0x7587
@@ -1124,6 +1168,7 @@
 #define PCI_DEVICE_ID_SERVERWORKS_OSB4IDE 0x0211
 #define PCI_DEVICE_ID_SERVERWORKS_CSB5IDE 0x0212
 #define PCI_DEVICE_ID_SERVERWORKS_CSB6IDE 0x0213
+#define PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2 0x0217
 #define PCI_DEVICE_ID_SERVERWORKS_OSB4USB 0x0220
 #define PCI_DEVICE_ID_SERVERWORKS_CSB5USB PCI_DEVICE_ID_SERVERWORKS_OSB4USB
 #define PCI_DEVICE_ID_SERVERWORKS_CSB6USB 0x0221
@@ -1544,6 +1589,9 @@
 #define PCI_DEVICE_ID_TIGON3_5702FE	0x164d
 #define PCI_DEVICE_ID_TIGON3_5702X	0x16a6
 #define PCI_DEVICE_ID_TIGON3_5703X	0x16a7
+#define PCI_DEVICE_ID_TIGON3_5704S	0x16a8
+#define PCI_DEVICE_ID_TIGON3_5702A3	0x16c6
+#define PCI_DEVICE_ID_TIGON3_5703A3	0x16c7
 
 #define PCI_VENDOR_ID_SYBA		0x1592
 #define PCI_DEVICE_ID_SYBA_2P_EPP	0x0782
@@ -1568,6 +1616,9 @@
 #define PCI_VENDOR_ID_TEKRAM		0x1de1
 #define PCI_DEVICE_ID_TEKRAM_DC290	0xdc29
 
+#define PCI_VENDOR_ID_HINT		0x3388
+#define PCI_DEVICE_ID_HINT_VXPROII_IDE	0x8013
+
 #define PCI_VENDOR_ID_3DLABS		0x3d3d
 #define PCI_DEVICE_ID_3DLABS_300SX	0x0001
 #define PCI_DEVICE_ID_3DLABS_500TX	0x0002
@@ -1629,7 +1680,11 @@
 #define PCI_DEVICE_ID_INTEL_82430	0x0486
 #define PCI_DEVICE_ID_INTEL_82434	0x04a3
 #define PCI_DEVICE_ID_INTEL_I960	0x0960
+#define PCI_DEVICE_ID_INTEL_I960RM	0x0962
 #define PCI_DEVICE_ID_INTEL_82562ET	0x1031
+
+#define PCI_DEVICE_ID_INTEL_82815_MC	0x1130
+
 #define PCI_DEVICE_ID_INTEL_82559ER	0x1209
 #define PCI_DEVICE_ID_INTEL_82092AA_0	0x1221
 #define PCI_DEVICE_ID_INTEL_82092AA_1	0x1222
@@ -1685,9 +1740,9 @@
 #define PCI_DEVICE_ID_INTEL_82801E_2	0x2452
 #define PCI_DEVICE_ID_INTEL_82801E_3	0x2453
 #define PCI_DEVICE_ID_INTEL_82801E_9	0x2459
-#define PCI_DEVICE_ID_INTEL_82801E_11	0x245b
-#define PCI_DEVICE_ID_INTEL_82801E_13	0x245d
-#define PCI_DEVICE_ID_INTEL_82801E_14	0x245e
+#define PCI_DEVICE_ID_INTEL_82801E_11	0x245B
+#define PCI_DEVICE_ID_INTEL_82801E_14	0x245D
+#define PCI_DEVICE_ID_INTEL_82801E_15	0x245E
 #define PCI_DEVICE_ID_INTEL_82801CA_0	0x2480
 #define PCI_DEVICE_ID_INTEL_82801CA_2	0x2482
 #define PCI_DEVICE_ID_INTEL_82801CA_3	0x2483
@@ -1728,6 +1783,7 @@
 #define PCI_DEVICE_ID_INTEL_82454GX	0x84c4
 #define PCI_DEVICE_ID_INTEL_82450GX	0x84c5
 #define PCI_DEVICE_ID_INTEL_82451NX	0x84ca
+#define PCI_DEVICE_ID_INTEL_82454NX	0x84cb
 
 #define PCI_VENDOR_ID_COMPUTONE		0x8e0e
 #define PCI_DEVICE_ID_COMPUTONE_IP2EX	0x0291
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/prctl.h linux-2.4.21-pre6/include/linux/prctl.h
--- linux-2.4.20/include/linux/prctl.h	2002-02-25 19:38:13.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/prctl.h	2003-03-26 23:49:40.000000000 +0000
@@ -26,4 +26,12 @@
 # define PR_FPEMU_NOPRINT	1	/* silently emulate fp operations accesses */
 # define PR_FPEMU_SIGFPE	2	/* don't emulate fp operations, send SIGFPE instead */
 
+/* Get/set floating-point exception mode (if meaningful) */
+#define PR_GET_FPEXC	11
+#define PR_SET_FPEXC	12
+# define PR_FP_EXC_DISABLED	0	/* FP exceptions disabled */
+# define PR_FP_EXC_NONRECOV	1	/* async non-recoverable exc. mode */
+# define PR_FP_EXC_ASYNC	2	/* async recoverable exception mode */
+# define PR_FP_EXC_PRECISE	3	/* precise exception mode */
+
 #endif /* _LINUX_PRCTL_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/raid/md.h linux-2.4.21-pre6/include/linux/raid/md.h
--- linux-2.4.20/include/linux/raid/md.h	2001-11-22 19:48:07.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/raid/md.h	2003-03-26 23:49:00.000000000 +0000
@@ -29,6 +29,7 @@
 #include <linux/module.h>
 #include <linux/hdreg.h>
 #include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #include <linux/smp_lock.h>
 #include <linux/delay.h>
 #include <net/checksum.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/raid/md_k.h linux-2.4.21-pre6/include/linux/raid/md_k.h
--- linux-2.4.20/include/linux/raid/md_k.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/raid/md_k.h	2003-03-26 23:48:59.000000000 +0000
@@ -171,6 +171,7 @@
 	struct block_device *bdev;	/* block device handle */
 
 	mdp_super_t *sb;
+	struct page *sb_page;
 	unsigned long sb_offset;
 
 	int alias_device;		/* device alias to the same disk */
@@ -223,7 +224,7 @@
 	int (*make_request)(mddev_t *mddev, int rw, struct buffer_head * bh);
 	int (*run)(mddev_t *mddev);
 	int (*stop)(mddev_t *mddev);
-	int (*status)(char *page, mddev_t *mddev);
+	void (*status)(struct seq_file *seq, mddev_t *mddev);
 	int (*error_handler)(mddev_t *mddev, kdev_t dev);
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/reiserfs_fs.h linux-2.4.21-pre6/include/linux/reiserfs_fs.h
--- linux-2.4.20/include/linux/reiserfs_fs.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/reiserfs_fs.h	2003-03-26 23:49:54.000000000 +0000
@@ -1748,11 +1748,12 @@
 struct inode * reiserfs_iget (struct super_block * s, 
 			      const struct cpu_key * key);
 
-
-struct inode * reiserfs_new_inode (struct reiserfs_transaction_handle *th, 
-				   struct inode * dir, int mode, 
-				   const char * symname, int item_len,
-				   struct dentry *dentry, struct inode *inode, int * err);
+int reiserfs_new_inode (struct reiserfs_transaction_handle *th,
+                               struct inode * dir, int mode,
+                               const char * symname,
+                               int i_size,
+                               struct dentry *dentry,
+                               struct inode *inode);
 int reiserfs_sync_inode (struct reiserfs_transaction_handle *th, struct inode * inode);
 void reiserfs_update_sd (struct reiserfs_transaction_handle *th, struct inode * inode);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/reiserfs_fs_sb.h linux-2.4.21-pre6/include/linux/reiserfs_fs_sb.h
--- linux-2.4.20/include/linux/reiserfs_fs_sb.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/reiserfs_fs_sb.h	2003-03-26 23:49:39.000000000 +0000
@@ -312,7 +312,7 @@
   int j_free_bitmap_nodes ;
   int j_used_bitmap_nodes ;
   struct list_head j_bitmap_nodes ;
-  struct inode j_dummy_inode ;
+  struct list_head j_dirty_buffers ;
   struct reiserfs_list_bitmap j_list_bitmap[JOURNAL_NUM_BITMAPS] ;	/* array of bitmaps to record the deleted blocks */
   struct reiserfs_journal_list j_journal_list[JOURNAL_LIST_COUNT] ;	    /* array of all the journal lists */
   struct reiserfs_journal_cnode *j_hash_table[JOURNAL_HASH_SIZE] ; 	    /* hash table for real buffer heads in current trans */ 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/sched.h linux-2.4.21-pre6/include/linux/sched.h
--- linux-2.4.20/include/linux/sched.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/sched.h	2003-03-26 23:49:06.000000000 +0000
@@ -163,6 +163,12 @@
 extern int start_context_thread(void);
 extern int current_is_keventd(void);
 
+#if CONFIG_SMP
+extern void set_cpus_allowed(struct task_struct *p, unsigned long new_mask);
+#else
+# define set_cpus_allowed(p, new_mask) do { } while (0)
+#endif
+
 /*
  * The default fd array needs to be at least BITS_PER_LONG,
  * as this is the granularity returned by copy_fdset().
@@ -339,6 +345,7 @@
 	/* ??? */
 	unsigned long personality;
 	int did_exec:1;
+	unsigned task_dumpable:1;
 	pid_t pid;
 	pid_t pgrp;
 	pid_t tty_old_pgrp;
@@ -448,6 +455,8 @@
 #define PT_TRACESYSGOOD	0x00000008
 #define PT_PTRACE_CAP	0x00000010	/* ptracer can follow suid-exec */
 
+#define is_dumpable(tsk)	((tsk)->task_dumpable && (tsk)->mm->dumpable)
+
 /*
  * Limit the stack by to some sane default: root can always
  * increase this limit if needed..  8MB seems reasonable.
@@ -482,8 +491,8 @@
     policy:		SCHED_OTHER,					\
     mm:			NULL,						\
     active_mm:		&init_mm,					\
-    cpus_runnable:	-1,						\
-    cpus_allowed:	-1,						\
+    cpus_runnable:	~0UL,						\
+    cpus_allowed:	~0UL,						\
     run_list:		LIST_HEAD_INIT(tsk.run_list),			\
     next_task:		&tsk,						\
     prev_task:		&tsk,						\
@@ -803,6 +812,8 @@
 extern void FASTCALL(add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t * wait));
 extern void FASTCALL(remove_wait_queue(wait_queue_head_t *q, wait_queue_t * wait));
 
+extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
+
 #define __wait_event(wq, condition) 					\
 do {									\
 	wait_queue_t __wait;						\
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/scx200.h linux-2.4.21-pre6/include/linux/scx200.h
--- linux-2.4.20/include/linux/scx200.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/scx200.h	2003-03-26 23:49:39.000000000 +0000
@@ -0,0 +1,56 @@
+/* linux/include/linux/scx200.h
+
+   Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
+
+   Defines for the National Semiconductor SCx200 Processors
+*/
+
+/* Interesting stuff for the National Semiconductor SCx200 CPU */
+
+/* F0 PCI Header/Bridge Configuration Registers */
+#define SCx200_DOCCS_BASE 0x78	/* DOCCS Base Address Register */
+#define SCx200_DOCCS_CTRL 0x7c	/* DOCCS Control Register */
+
+/* GPIO Register Block */
+#define SCx200_GPIO_SIZE 0x2c	/* Size of GPIO register block */
+
+/* General Configuration Block */
+#define SCx200_CB_BASE 0x9000	/* Base fixed at 0x9000 according to errata */
+
+/* Watchdog Timer */
+#define SCx200_WDT_OFFSET 0x00	/* offset within configuration block */
+#define SCx200_WDT_SIZE 0x05	/* size */
+
+#define SCx200_WDT_WDTO 0x00	/* Time-Out Register */
+#define SCx200_WDT_WDCNFG 0x02	/* Configuration Register */
+#define SCx200_WDT_WDSTS 0x04	/* Status Register */
+#define SCx200_WDT_WDSTS_WDOVF (1<<0) /* Overflow bit */
+
+/* High Resolution Timer */
+#define SCx200_TIMER_OFFSET 0x08
+#define SCx200_TIMER_SIZE 0x05
+
+/* Clock Generators */
+#define SCx200_CLOCKGEN_OFFSET 0x10
+#define SCx200_CLOCKGEN_SIZE 0x10
+
+/* Pin Multiplexing and Miscellaneous Configuration Registers */
+#define SCx200_MISC_OFFSET 0x30
+#define SCx200_MISC_SIZE 0x10
+
+#define SCx200_PMR 0x30		/* Pin Multiplexing Register */
+#define SCx200_MCR 0x34		/* Miscellaneous Configuration Register */
+#define SCx200_INTSEL 0x38	/* Interrupt Selection Register */
+#define SCx200_IID 0x3c		/* IA On a Chip Identification Number Reg */
+#define SCx200_REV 0x3d		/* Revision Register */
+#define SCx200_CBA 0x3e		/* Configuration Base Address Register */
+
+/* Verify that the configuration block really is there */
+#define scx200_cb_probe(base) (inw((base) + SCx200_CBA) == (base))
+
+/*
+    Local variables:
+        compile-command: "make -C ../.. bzImage modules"
+        c-basic-offset: 8
+    End:
+*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/scx200_gpio.h linux-2.4.21-pre6/include/linux/scx200_gpio.h
--- linux-2.4.20/include/linux/scx200_gpio.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/scx200_gpio.h	2003-03-26 23:49:19.000000000 +0000
@@ -0,0 +1,98 @@
+#include <linux/spinlock.h>
+
+u32 scx200_gpio_configure(int index, u32 set, u32 clear);
+void scx200_gpio_dump(unsigned index);
+
+extern unsigned scx200_gpio_base;
+extern spinlock_t scx200_gpio_lock;
+extern long scx200_gpio_shadow[2];
+
+#define scx200_gpio_present() (scx200_gpio_base!=0)
+
+/* Definitions to make sure I do the same thing in all functions */
+#define __SCx200_GPIO_BANK unsigned bank = index>>5
+#define __SCx200_GPIO_IOADDR unsigned short ioaddr = scx200_gpio_base+0x10*bank
+#define __SCx200_GPIO_SHADOW long *shadow = scx200_gpio_shadow+bank
+#define __SCx200_GPIO_INDEX index &= 31
+
+#define __SCx200_GPIO_OUT __asm__ __volatile__("outsl":"=mS" (shadow):"d" (ioaddr), "0" (shadow))
+
+/* returns the value of the GPIO pin */
+
+static inline int scx200_gpio_get(int index) {
+	__SCx200_GPIO_BANK;
+	__SCx200_GPIO_IOADDR + 0x04;
+	__SCx200_GPIO_INDEX;
+		
+	return (inl(ioaddr) & (1<<index)) ? 1 : 0;
+}
+
+/* return the value driven on the GPIO signal (the value that will be
+   driven if the GPIO is configured as an output, it might not be the
+   state of the GPIO right now if the GPIO is configured as an input) */
+
+static inline int scx200_gpio_current(int index) {
+        __SCx200_GPIO_BANK;
+	__SCx200_GPIO_INDEX;
+		
+	return (scx200_gpio_shadow[bank] & (1<<index)) ? 1 : 0;
+}
+
+/* drive the GPIO signal high */
+
+static inline void scx200_gpio_set_high(int index) {
+	__SCx200_GPIO_BANK;
+	__SCx200_GPIO_IOADDR;
+	__SCx200_GPIO_SHADOW;
+	__SCx200_GPIO_INDEX;
+	set_bit(index, shadow);
+	__SCx200_GPIO_OUT;
+}
+
+/* drive the GPIO signal low */
+
+static inline void scx200_gpio_set_low(int index) {
+	__SCx200_GPIO_BANK;
+	__SCx200_GPIO_IOADDR;
+	__SCx200_GPIO_SHADOW;
+	__SCx200_GPIO_INDEX;
+	clear_bit(index, shadow);
+	__SCx200_GPIO_OUT;
+}
+
+/* drive the GPIO signal to state */
+
+static inline void scx200_gpio_set(int index, int state) {
+	__SCx200_GPIO_BANK;
+	__SCx200_GPIO_IOADDR;
+	__SCx200_GPIO_SHADOW;
+	__SCx200_GPIO_INDEX;
+	if (state)
+		set_bit(index, shadow);
+	else
+		clear_bit(index, shadow);
+	__SCx200_GPIO_OUT;
+}
+
+/* toggle the GPIO signal */
+static inline void scx200_gpio_change(int index) {
+	__SCx200_GPIO_BANK;
+	__SCx200_GPIO_IOADDR;
+	__SCx200_GPIO_SHADOW;
+	__SCx200_GPIO_INDEX;
+	change_bit(index, shadow);
+	__SCx200_GPIO_OUT;
+}
+
+#undef __SCx200_GPIO_BANK
+#undef __SCx200_GPIO_IOADDR
+#undef __SCx200_GPIO_SHADOW
+#undef __SCx200_GPIO_INDEX
+#undef __SCx200_GPIO_OUT
+
+/*
+    Local variables:
+        compile-command: "make -C ../.. bzImage modules"
+        c-basic-offset: 8
+    End:
+*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/skbuff.h linux-2.4.21-pre6/include/linux/skbuff.h
--- linux-2.4.20/include/linux/skbuff.h	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/skbuff.h	2003-03-26 23:48:58.000000000 +0000
@@ -240,6 +240,7 @@
 						int newheadroom,
 						int newtailroom,
 						int priority);
+extern struct sk_buff *		skb_pad(struct sk_buff *skb, int pad);
 #define dev_kfree_skb(a)	kfree_skb(a)
 extern void	skb_over_panic(struct sk_buff *skb, int len, void *here);
 extern void	skb_under_panic(struct sk_buff *skb, int len, void *here);
@@ -751,7 +752,7 @@
 	return skb->data_len;
 }
 
-static inline int skb_headlen(const struct sk_buff *skb)
+static inline unsigned int skb_headlen(const struct sk_buff *skb)
 {
 	return skb->len - skb->data_len;
 }
@@ -1082,6 +1083,26 @@
 }
 
 /**
+ *	skb_padto	- pad an skbuff up to a minimal size
+ *	@skb: buffer to pad
+ *	@len: minimal length
+ *
+ *	Pads up a buffer to ensure the trailing bytes exist and are
+ *	blanked. If the buffer already contains sufficient data it
+ *	is untouched. Returns the buffer, which may be a replacement
+ *	for the original, or NULL for out of memory - in which case
+ *	the original buffer is still freed.
+ */
+ 
+static inline struct sk_buff *skb_padto(struct sk_buff *skb, unsigned int len)
+{
+	unsigned int size = skb->len;
+	if(likely(size >= len))
+		return skb;
+	return skb_pad(skb, len-size);
+}
+
+/**
  *	skb_linearize - convert paged skb to linear one
  *	@skb: buffer to linarize
  *	@gfp: allocation mode
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/sockios.h linux-2.4.21-pre6/include/linux/sockios.h
--- linux-2.4.20/include/linux/sockios.h	2001-11-07 22:39:36.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/sockios.h	2003-03-26 23:48:58.000000000 +0000
@@ -81,6 +81,8 @@
 #define SIOCGMIIREG	0x8948		/* Read MII PHY register.	*/
 #define SIOCSMIIREG	0x8949		/* Write MII PHY register.	*/
 
+#define SIOCWANDEV	0x894A		/* get/set netdev parameters	*/
+
 /* ARP cache control calls. */
 		    /*  0x8950 - 0x8952  * obsolete calls, don't re-use */
 #define SIOCDARP	0x8953		/* delete ARP table entry	*/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/sonypi.h linux-2.4.21-pre6/include/linux/sonypi.h
--- linux-2.4.20/include/linux/sonypi.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/sonypi.h	2003-03-26 23:49:29.000000000 +0000
@@ -1,7 +1,9 @@
 /* 
  * Sony Programmable I/O Control Device driver for VAIO
  *
- * Copyright (C) 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
+ * Copyright (C) 2001-2003 Stelian Pop <stelian@popies.net>
+ *
+ * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
  *
  * Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
  *
@@ -41,9 +43,9 @@
 #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_JOGDIAL_RELEASED		 6	/* obsolete */
 #define SONYPI_EVENT_CAPTURE_PRESSED		 7
-#define SONYPI_EVENT_CAPTURE_RELEASED		 8
+#define SONYPI_EVENT_CAPTURE_RELEASED		 8	/* obsolete */
 #define SONYPI_EVENT_CAPTURE_PARTIALPRESSED	 9
 #define SONYPI_EVENT_CAPTURE_PARTIALRELEASED	10
 #define SONYPI_EVENT_FNKEY_ESC			11
@@ -76,6 +78,22 @@
 #define SONYPI_EVENT_BLUETOOTH_ON		38
 #define SONYPI_EVENT_BLUETOOTH_OFF		39
 #define SONYPI_EVENT_HELP_PRESSED		40
+#define SONYPI_EVENT_FNKEY_ONLY			41
+#define SONYPI_EVENT_JOGDIAL_FAST_DOWN		42
+#define SONYPI_EVENT_JOGDIAL_FAST_UP		43
+#define SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED	44
+#define SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED	45
+#define SONYPI_EVENT_JOGDIAL_VFAST_DOWN		46
+#define SONYPI_EVENT_JOGDIAL_VFAST_UP		47
+#define SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED	48
+#define SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED	49
+#define SONYPI_EVENT_ZOOM_PRESSED		50
+#define SONYPI_EVENT_THUMBPHRASE_PRESSED	51
+#define SONYPI_EVENT_MEYE_FACE			52
+#define SONYPI_EVENT_MEYE_OPPOSITE		53
+#define SONYPI_EVENT_MEMORYSTICK_INSERT		54
+#define SONYPI_EVENT_MEMORYSTICK_EJECT		55
+#define SONYPI_EVENT_ANYBUTTON_RELEASED		56
 
 /* get/set brightness */
 #define SONYPI_IOCGBRT		_IOR('v', 0, __u8)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/soundcard.h linux-2.4.21-pre6/include/linux/soundcard.h
--- linux-2.4.20/include/linux/soundcard.h	2001-11-09 22:11:15.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/soundcard.h	2003-03-26 23:49:35.000000000 +0000
@@ -554,6 +554,16 @@
 #	define AFMT_MPEG		0x00000200	/* MPEG (2) audio */
 #	define AFMT_AC3		0x00000400	/* Dolby Digital AC3 */
 
+/* because they *do* exist and we want to use them --Monty */
+#	define AFMT_S24_LE	        0x00000800	
+#	define AFMT_S24_BE	        0x00001000	
+#	define AFMT_U24_LE	        0x00002000	
+#	define AFMT_U24_BE	        0x00004000	
+#	define AFMT_S32_LE	        0x00008000	
+#	define AFMT_S32_BE	        0x00010000	
+#	define AFMT_U32_LE	        0x00020000	
+#	define AFMT_U32_BE	        0x00040000	
+
 /*
  * Buffer status queries.
  */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/sunrpc/xdr.h linux-2.4.21-pre6/include/linux/sunrpc/xdr.h
--- linux-2.4.20/include/linux/sunrpc/xdr.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/sunrpc/xdr.h	2003-03-26 23:49:55.000000000 +0000
@@ -137,7 +137,7 @@
  * XDR buffer helper functions
  */
 extern int xdr_kmap(struct iovec *, struct xdr_buf *, unsigned int);
-extern void xdr_kunmap(struct xdr_buf *, unsigned int);
+extern void xdr_kunmap(struct xdr_buf *, unsigned int, int);
 extern void xdr_shift_buf(struct xdr_buf *, size_t);
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/swap.h linux-2.4.21-pre6/include/linux/swap.h
--- linux-2.4.20/include/linux/swap.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/swap.h	2003-03-26 23:48:58.000000000 +0000
@@ -147,7 +147,6 @@
 extern void get_swaphandle_info(swp_entry_t, unsigned long *, kdev_t *, 
 					struct inode **);
 extern int swap_duplicate(swp_entry_t);
-extern int swap_count(struct page *);
 extern int valid_swaphandles(swp_entry_t, unsigned long *);
 extern void swap_free(swp_entry_t);
 extern void free_swap_and_cache(swp_entry_t);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/sys.h linux-2.4.21-pre6/include/linux/sys.h
--- linux-2.4.20/include/linux/sys.h	1995-12-11 04:56:37.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/sys.h	2003-03-26 23:49:30.000000000 +0000
@@ -4,7 +4,7 @@
 /*
  * system call entry points ... but not all are defined
  */
-#define NR_syscalls 256
+#define NR_syscalls 270
 
 /*
  * These are system calls that will be removed at some time
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/sysctl.h linux-2.4.21-pre6/include/linux/sysctl.h
--- linux-2.4.20/include/linux/sysctl.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/sysctl.h	2003-03-26 23:48:58.000000000 +0000
@@ -124,6 +124,7 @@
 	KERN_CORE_USES_PID=52,		/* int: use core or core.%pid */
 	KERN_TAINTED=53,	/* int: various kernel tainted flags */
 	KERN_CADPID=54,		/* int: PID of the process to notify on CAD */
+ 	KERN_CORE_PATTERN=56,	/* string: pattern for core-files */
 };
 
 
@@ -292,7 +293,9 @@
 	NET_IPV4_NONLOCAL_BIND=88,
 	NET_IPV4_ICMP_RATELIMIT=89,
 	NET_IPV4_ICMP_RATEMASK=90,
-	NET_TCP_TW_REUSE=91
+	NET_TCP_TW_REUSE=91,
+	NET_TCP_FRTO=92,
+	NET_TCP_LOW_LATENCY=93
 };
 
 enum {
@@ -345,7 +348,9 @@
 enum {
 	NET_IPV6_CONF=16,
 	NET_IPV6_NEIGH=17,
-	NET_IPV6_ROUTE=18
+	NET_IPV6_ROUTE=18,
+	NET_IPV6_ICMP=19,
+	NET_IPV6_BINDV6ONLY=20
 };
 
 enum {
@@ -373,6 +378,11 @@
 	NET_IPV6_RTR_SOLICIT_DELAY=10
 };
 
+/* /proc/sys/net/ipv6/icmp */
+enum {
+	NET_IPV6_ICMP_RATELIMIT=1
+};
+
 /* /proc/sys/net/<protocol>/neigh/<dev> */
 enum {
 	NET_NEIGH_MCAST_SOLICIT=1,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/types.h linux-2.4.21-pre6/include/linux/types.h
--- linux-2.4.20/include/linux/types.h	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/types.h	2003-03-26 23:49:25.000000000 +0000
@@ -3,6 +3,13 @@
 
 #ifdef	__KERNEL__
 #include <linux/config.h>
+
+#define BITS_TO_LONGS(bits) \
+	(((bits)+BITS_PER_LONG-1)/BITS_PER_LONG)
+#define DECLARE_BITMAP(name,bits) \
+	unsigned long name[BITS_TO_LONGS(bits)]
+#define CLEAR_BITMAP(name,bits) \
+	memset(name, 0, BITS_TO_LONGS(bits)*sizeof(unsigned long))
 #endif
 
 #include <linux/posix_types.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/umem.h linux-2.4.21-pre6/include/linux/umem.h
--- linux-2.4.20/include/linux/umem.h	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/umem.h	2003-03-26 23:49:38.000000000 +0000
@@ -127,4 +127,5 @@
 
 #define PCI_VENDOR_ID_MICRO_MEMORY		0x1332
 #define PCI_DEVICE_ID_MICRO_MEMORY_5415CN	0x5415
+#define PCI_DEVICE_ID_MICRO_MEMORY_5425CN	0x5425
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/usb.h linux-2.4.21-pre6/include/linux/usb.h
--- linux-2.4.20/include/linux/usb.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/usb.h	2003-03-26 23:49:34.000000000 +0000
@@ -998,9 +998,16 @@
 #define PIPE_DEVEP_MASK		0x0007ff00
 
 /* The D0/D1 toggle bits */
-#define usb_gettoggle(dev, ep, out) (((dev)->toggle[out] >> ep) & 1)
-#define	usb_dotoggle(dev, ep, out)  ((dev)->toggle[out] ^= (1 << ep))
-#define usb_settoggle(dev, ep, out, bit) ((dev)->toggle[out] = ((dev)->toggle[out] & ~(1 << ep)) | ((bit) << ep))
+#define usb_gettoggle(dev, ep, out) (((dev)->toggle[out] >> (ep)) & 1)
+#define	usb_dotoggle(dev, ep, out)  ((dev)->toggle[out] ^= (1 << (ep)))
+static inline void usb_settoggle(struct usb_device *dev,
+				 unsigned int ep, 
+				 unsigned int out,
+				 int bit)
+{
+	dev->toggle[out] &= ~(1 << ep);
+	dev->toggle[out] |= bit << ep;
+}
 
 /* Endpoint halt control/status */
 #define usb_endpoint_out(ep_dir)	(((ep_dir >> 7) & 1) ^ 1)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/usb_scanner_ioctl.h linux-2.4.21-pre6/include/linux/usb_scanner_ioctl.h
--- linux-2.4.20/include/linux/usb_scanner_ioctl.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/usb_scanner_ioctl.h	2003-03-26 23:49:10.000000000 +0000
@@ -0,0 +1,9 @@
+/* USB Scanner IOCTLS */
+
+/* read vendor and product IDs from the scanner */
+#define SCANNER_IOCTL_VENDOR _IOR('U', 0x20, int)
+#define SCANNER_IOCTL_PRODUCT _IOR('U', 0x21, int)
+/* send/recv a control message to the scanner */
+#define SCANNER_IOCTL_CTRLMSG _IOWR('U', 0x22, struct usb_ctrlrequest )
+
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/videodev.h linux-2.4.21-pre6/include/linux/videodev.h
--- linux-2.4.20/include/linux/videodev.h	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/videodev.h	2003-03-26 23:49:56.000000000 +0000
@@ -403,6 +403,8 @@
 #define VID_HARDWARE_PWC	31	/* Philips webcams */
 #define VID_HARDWARE_MEYE	32	/* Sony Vaio MotionEye cameras */
 #define VID_HARDWARE_CPIA2	33
+#define VID_HARDWARE_VICAM	34	/* ViCam, 3Com Homeconnect */
+#define VID_HARDWARE_SF16FMR2	35
 
 #endif /* __LINUX_VIDEODEV_H */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/linux/wireless.h linux-2.4.21-pre6/include/linux/wireless.h
--- linux-2.4.20/include/linux/wireless.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/linux/wireless.h	2003-03-26 23:49:50.000000000 +0000
@@ -1,7 +1,7 @@
 /*
  * This file define a set of standard wireless extensions
  *
- * Version :	14	25.1.02
+ * Version :	15	12.7.02
  *
  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
  * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved.
@@ -80,7 +80,7 @@
  * (there is some stuff that will be added in the future...)
  * I just plan to increment with each new version.
  */
-#define WIRELESS_EXT	14
+#define WIRELESS_EXT	15
 
 /*
  * Changes :
@@ -153,17 +153,32 @@
  *	- Define additional specific event numbers
  *	- Add "addr" and "param" fields in union iwreq_data
  *	- AP scanning stuff (SIOCSIWSCAN and friends)
+ *
+ * V14 to V15
+ * ----------
+ *	- Add IW_PRIV_TYPE_ADDR for struct sockaddr private arg
+ *	- Make struct iw_freq signed (both m & e), add explicit padding
+ *	- Add IWEVCUSTOM for driver specific event/scanning token
+ *	- Add IW_MAX_GET_SPY for driver returning a lot of addresses
+ *	- Add IW_TXPOW_RANGE for range of Tx Powers
+ *	- Add IWEVREGISTERED & IWEVEXPIRED events for Access Points
+ *	- Add IW_MODE_MONITOR for passive monitor
  */
 
 /**************************** CONSTANTS ****************************/
 
 /* -------------------------- IOCTL LIST -------------------------- */
 
-/* Basic operations */
+/* Wireless Identification */
 #define SIOCSIWCOMMIT	0x8B00		/* Commit pending changes to driver */
 #define SIOCGIWNAME	0x8B01		/* get name == wireless protocol */
-#define SIOCSIWNWID	0x8B02		/* set network id (the cell) */
-#define SIOCGIWNWID	0x8B03		/* get network id */
+/* SIOCGIWNAME is used to verify the presence of Wireless Extensions.
+ * Common values : "IEEE 802.11-DS", "IEEE 802.11-FH", "IEEE 802.11b"...
+ * Don't put the name of your driver there, it's useless. */
+
+/* Basic operations */
+#define SIOCSIWNWID	0x8B02		/* set network id (pre-802.11) */
+#define SIOCGIWNWID	0x8B03		/* get network id (the cell) */
 #define SIOCSIWFREQ	0x8B04		/* set channel/frequency (Hz) */
 #define SIOCGIWFREQ	0x8B05		/* get channel/frequency (Hz) */
 #define SIOCSIWMODE	0x8B06		/* set operation mode */
@@ -178,16 +193,18 @@
 #define SIOCGIWPRIV	0x8B0D		/* get private ioctl interface info */
 #define SIOCSIWSTATS	0x8B0E		/* Unused */
 #define SIOCGIWSTATS	0x8B0F		/* Get /proc/net/wireless stats */
+/* SIOCGIWSTATS is strictly used between user space and the kernel, and
+ * is never passed to the driver (i.e. the driver will never see it). */
 
-/* Mobile IP support */
+/* Mobile IP support (statistics per MAC address) */
 #define SIOCSIWSPY	0x8B10		/* set spy addresses */
 #define SIOCGIWSPY	0x8B11		/* get spy info (quality of link) */
 
 /* Access Point manipulation */
 #define SIOCSIWAP	0x8B14		/* set access point MAC addresses */
 #define SIOCGIWAP	0x8B15		/* get access point MAC addresses */
-#define SIOCGIWAPLIST	0x8B17		/* get list of access point in range */
-#define SIOCSIWSCAN	0x8B18		/* trigger scanning */
+#define SIOCGIWAPLIST	0x8B17		/* Deprecated in favor of scanning */
+#define SIOCSIWSCAN	0x8B18		/* trigger scanning (list cells) */
 #define SIOCGIWSCAN	0x8B19		/* get scanning results */
 
 /* 802.11 specific support */
@@ -197,9 +214,7 @@
 #define SIOCGIWNICKN	0x8B1D		/* get node name/nickname */
 /* As the ESSID and NICKN are strings up to 32 bytes long, it doesn't fit
  * within the 'iwreq' structure, so we need to use the 'data' member to
- * point to a string in user space, like it is done for RANGE...
- * The "flags" member indicate if the ESSID is active or not (promiscuous).
- */
+ * point to a string in user space, like it is done for RANGE... */
 
 /* Other parameters useful in 802.11 and some other devices */
 #define SIOCSIWRATE	0x8B20		/* set default bit rate (bps) */
@@ -257,7 +272,10 @@
 /* Most events use the same identifier as ioctl requests */
 
 #define IWEVTXDROP	0x8C00		/* Packet dropped to excessive retry */
-#define IWEVQUAL	0x8C01		/* Quality part of statistics */
+#define IWEVQUAL	0x8C01		/* Quality part of statistics (scan) */
+#define IWEVCUSTOM	0x8C02		/* Driver specific ascii string */
+#define IWEVREGISTERED	0x8C03		/* Discovered a new node (AP mode) */
+#define IWEVEXPIRED	0x8C04		/* Expired a node (AP mode) */
 
 #define IWEVFIRST	0x8C00
 
@@ -273,7 +291,8 @@
 #define IW_PRIV_TYPE_BYTE	0x1000	/* Char as number */
 #define IW_PRIV_TYPE_CHAR	0x2000	/* Char as character */
 #define IW_PRIV_TYPE_INT	0x4000	/* 32 bits int */
-#define IW_PRIV_TYPE_FLOAT	0x5000
+#define IW_PRIV_TYPE_FLOAT	0x5000	/* struct iw_freq */
+#define IW_PRIV_TYPE_ADDR	0x6000	/* struct sockaddr */
 
 #define IW_PRIV_SIZE_FIXED	0x0800	/* Variable or fixed nuber of args */
 
@@ -297,13 +316,16 @@
 
 /* Maximum tx powers in the range struct */
 #define IW_MAX_TXPOWER		8
+/* Note : if you more than 8 TXPowers, just set the max and min or
+ * a few of them in the struct iw_range. */
 
 /* Maximum of address that you may set with SPY */
-#define IW_MAX_SPY		8
+#define IW_MAX_SPY		8	/* set */
+#define IW_MAX_GET_SPY		64	/* get */
 
 /* Maximum of address that you may get in the
    list of access points in range */
-#define IW_MAX_AP		8
+#define IW_MAX_AP		64
 
 /* Maximum size of the ESSID and NICKN strings */
 #define IW_ESSID_MAX_SIZE	32
@@ -315,6 +337,7 @@
 #define IW_MODE_MASTER	3	/* Synchronisation master or Access Point */
 #define IW_MODE_REPEAT	4	/* Wireless Repeater (forwarder) */
 #define IW_MODE_SECOND	5	/* Secondary master/repeater (backup) */
+#define IW_MODE_MONITOR	6	/* Passive monitor (listen only) */
 
 /* Maximum number of size of encoding token available
  * they are listed in the range structure */
@@ -350,8 +373,10 @@
 #define IW_POWER_RELATIVE	0x0004	/* Value is not in seconds/ms/us */
 
 /* Transmit Power flags available */
+#define IW_TXPOW_TYPE		0x00FF	/* Type of value */
 #define IW_TXPOW_DBM		0x0000	/* Value is in dBm */
 #define IW_TXPOW_MWATT		0x0001	/* Value is in mW */
+#define IW_TXPOW_RANGE		0x1000	/* Range of value between min/max */
 
 /* Retry limits and lifetime flags available */
 #define IW_RETRY_ON		0x0000	/* No details... */
@@ -376,6 +401,9 @@
 /* Maximum size of returned data */
 #define IW_SCAN_MAX_DATA	4096	/* In bytes */
 
+/* Max number of char in custom event - use multiple of them if needed */
+#define IW_CUSTOM_MAX		256	/* In bytes */
+
 /****************************** TYPES ******************************/
 
 /* --------------------------- SUBTYPES --------------------------- */
@@ -411,9 +439,10 @@
  */
 struct	iw_freq
 {
-	__u32		m;		/* Mantissa */
-	__u16		e;		/* Exponent */
+	__s32		m;		/* Mantissa */
+	__s16		e;		/* Exponent */
 	__u8		i;		/* List index (when in range struct) */
+	__u8		pad;		/* Unused - just for alignement */
 };
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/net/addrconf.h linux-2.4.21-pre6/include/net/addrconf.h
--- linux-2.4.20/include/net/addrconf.h	2001-11-22 19:50:06.000000000 +0000
+++ linux-2.4.21-pre6/include/net/addrconf.h	2003-03-26 23:49:19.000000000 +0000
@@ -191,5 +191,21 @@
 	return (addr->s6_addr32[0] & __constant_htonl(0xFF000000)) == __constant_htonl(0xFF000000);
 }
 
+static inline int ipv6_addr_is_ll_all_nodes(const struct in6_addr *addr)
+{
+	return (addr->s6_addr32[0] == htonl(0xff020000) &&
+		addr->s6_addr32[1] == 0 &&
+		addr->s6_addr32[2] == 0 &&
+		addr->s6_addr32[3] == htonl(0x00000001));
+}
+
+static inline int ipv6_addr_is_ll_all_routers(const struct in6_addr *addr)
+{
+	return (addr->s6_addr32[0] == htonl(0xff020000) &&
+		addr->s6_addr32[1] == 0 &&
+		addr->s6_addr32[2] == 0 &&
+		addr->s6_addr32[3] == htonl(0x00000002));
+}
+
 #endif
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/net/af_unix.h linux-2.4.21-pre6/include/net/af_unix.h
--- linux-2.4.20/include/net/af_unix.h	2000-04-24 20:43:04.000000000 +0000
+++ linux-2.4.21-pre6/include/net/af_unix.h	2003-03-26 23:49:50.000000000 +0000
@@ -13,9 +13,30 @@
 
 extern atomic_t unix_tot_inflight;
 
+static inline unix_socket *first_unix_socket(int *i)
+{
+	for (*i = 0; *i <= UNIX_HASH_SIZE; (*i)++) {
+		if (unix_socket_table[*i])
+			return unix_socket_table[*i];
+	}
+	return NULL;
+}
+
+static inline unix_socket *next_unix_socket(int *i, unix_socket *s)
+{
+	/* More in this chain? */
+	if (s->next)
+		return s->next;
+	/* Look for next non-empty chain. */
+	for ((*i)++; *i <= UNIX_HASH_SIZE; (*i)++) {
+		if (unix_socket_table[*i])
+			return unix_socket_table[*i];
+	}
+	return NULL;
+}
 
-#define forall_unix_sockets(i, s) for (i=0; i<=UNIX_HASH_SIZE; i++) \
-                                    for (s=unix_socket_table[i]; s; s=s->next)
+#define forall_unix_sockets(i, s) \
+	for (s = first_unix_socket(&(i)); s; s = next_unix_socket(&(i),(s)))
 
 struct unix_address
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/net/bluetooth/hci.h linux-2.4.21-pre6/include/net/bluetooth/hci.h
--- linux-2.4.20/include/net/bluetooth/hci.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/net/bluetooth/hci.h	2003-03-26 23:49:27.000000000 +0000
@@ -39,6 +39,8 @@
 #define HCI_DEV_UNREG   2
 #define HCI_DEV_UP	3
 #define HCI_DEV_DOWN	4
+#define HCI_DEV_SUSPEND	5
+#define HCI_DEV_RESUME	6
 
 /* HCI device types */
 #define HCI_VHCI	0
@@ -46,6 +48,7 @@
 #define HCI_PCCARD	2
 #define HCI_UART 	3
 #define HCI_RS232 	4
+#define HCI_PCI		5
 
 /* HCI device flags */
 enum {
@@ -436,6 +439,12 @@
 /* Status params */
 #define OGF_STATUS_PARAM 	0x05
 
+/* Testing commands */
+#define OGF_TESTING_CMD 	0x3e
+
+/* Vendor specific commands */
+#define OGF_VENDOR_CMD  	0x3f
+
 /* ---- HCI Events ---- */
 #define EVT_INQUIRY_COMPLETE 	0x01
 
@@ -542,7 +551,7 @@
 	bdaddr_t bdaddr;
 	__u8     role;
 } __attribute__ ((packed)) evt_role_change;
-#define EVT_ROLE_CHANGE_SIZE 1
+#define EVT_ROLE_CHANGE_SIZE 8
 
 #define EVT_PIN_CODE_REQ        0x16
 typedef struct {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/net/bluetooth/hci_core.h linux-2.4.21-pre6/include/net/bluetooth/hci_core.h
--- linux-2.4.20/include/net/bluetooth/hci_core.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/net/bluetooth/hci_core.h	2003-03-26 23:49:40.000000000 +0000
@@ -302,6 +302,8 @@
 struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst);
 int hci_register_dev(struct hci_dev *hdev);
 int hci_unregister_dev(struct hci_dev *hdev);
+int hci_suspend_dev(struct hci_dev *hdev);
+int hci_resume_dev(struct hci_dev *hdev);
 int hci_dev_open(__u16 dev);
 int hci_dev_close(__u16 dev);
 int hci_dev_reset(__u16 dev);
@@ -429,7 +431,6 @@
 int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *param);
 int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags);
 int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
-int hci_send_raw(struct sk_buff *skb);
 
 void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf);
 
@@ -447,7 +448,7 @@
 };
 
 /* HCI security filter */
-#define HCI_SFLT_MAX_OGF 4
+#define HCI_SFLT_MAX_OGF  5
 
 struct hci_sec_filter {
 	__u32 type_mask;
@@ -455,7 +456,6 @@
 	__u32 ocf_mask[HCI_SFLT_MAX_OGF + 1][4];
 };
 
-
 /* ----- HCI requests ----- */
 #define HCI_REQ_DONE	  0
 #define HCI_REQ_PEND	  1
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/net/bluetooth/rfcomm.h linux-2.4.21-pre6/include/net/bluetooth/rfcomm.h
--- linux-2.4.20/include/net/bluetooth/rfcomm.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/include/net/bluetooth/rfcomm.h	2003-03-26 23:48:59.000000000 +0000
@@ -0,0 +1,346 @@
+/* 
+   RFCOMM implementation for Linux Bluetooth stack (BlueZ).
+   Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
+   Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/* 
+   RPN support    -    Dirk Husemann <hud@zurich.ibm.com>
+*/
+
+/*
+ * $Id: rfcomm.h,v 1.31 2002/10/18 20:12:11 maxk Exp $
+ */
+
+#ifndef __RFCOMM_H
+#define __RFCOMM_H
+
+#define RFCOMM_PSM 3
+
+#define RFCOMM_CONN_TIMEOUT (HZ * 30)
+#define RFCOMM_DISC_TIMEOUT (HZ * 20)
+
+#define RFCOMM_DEFAULT_MTU	127
+#define RFCOMM_DEFAULT_CREDITS	7
+
+#define RFCOMM_MAX_L2CAP_MTU	1024
+#define RFCOMM_MAX_CREDITS	40
+
+#define RFCOMM_SKB_HEAD_RESERVE	8
+#define RFCOMM_SKB_TAIL_RESERVE	2
+#define RFCOMM_SKB_RESERVE	(RFCOMM_SKB_HEAD_RESERVE + RFCOMM_SKB_TAIL_RESERVE)
+
+#define RFCOMM_SABM	0x2f
+#define RFCOMM_DISC	0x43
+#define RFCOMM_UA	0x63
+#define RFCOMM_DM	0x0f
+#define RFCOMM_UIH	0xef
+
+#define RFCOMM_TEST	0x08
+#define RFCOMM_FCON	0x28
+#define RFCOMM_FCOFF	0x18
+#define RFCOMM_MSC	0x38
+#define RFCOMM_RPN	0x24
+#define RFCOMM_RLS	0x14
+#define RFCOMM_PN	0x20
+#define RFCOMM_NSC	0x04
+
+#define RFCOMM_V24_FC	0x02
+#define RFCOMM_V24_RTC	0x04
+#define RFCOMM_V24_RTR	0x08
+#define RFCOMM_V24_IC	0x40
+#define RFCOMM_V24_DV	0x80
+
+#define RFCOMM_RPN_BR_2400	0x0
+#define RFCOMM_RPN_BR_4800	0x1
+#define RFCOMM_RPN_BR_7200	0x2
+#define RFCOMM_RPN_BR_9600	0x3
+#define RFCOMM_RPN_BR_19200	0x4
+#define RFCOMM_RPN_BR_38400	0x5
+#define RFCOMM_RPN_BR_57600	0x6
+#define RFCOMM_RPN_BR_115200	0x7
+#define RFCOMM_RPN_BR_230400	0x8
+
+#define RFCOMM_RPN_DATA_5	0x0
+#define RFCOMM_RPN_DATA_6	0x1
+#define RFCOMM_RPN_DATA_7	0x2
+#define RFCOMM_RPN_DATA_8	0x3
+
+#define RFCOMM_RPN_STOP_1	0
+#define RFCOMM_RPN_STOP_15	1
+
+#define RFCOMM_RPN_PARITY_NONE	0x0
+#define RFCOMM_RPN_PARITY_ODD	0x4
+#define RFCOMM_RPN_PARITY_EVEN	0x5
+#define RFCOMM_RPN_PARITY_MARK	0x6
+#define RFCOMM_RPN_PARITY_SPACE	0x7
+
+#define RFCOMM_RPN_FLOW_NONE	0x00
+
+#define RFCOMM_RPN_XON_CHAR	0x11
+#define RFCOMM_RPN_XOFF_CHAR	0x13
+
+#define RFCOMM_RPN_PM_BITRATE		0x0001
+#define RFCOMM_RPN_PM_DATA		0x0002
+#define RFCOMM_RPN_PM_STOP		0x0004
+#define RFCOMM_RPN_PM_PARITY		0x0008
+#define RFCOMM_RPN_PM_PARITY_TYPE	0x0010
+#define RFCOMM_RPN_PM_XON		0x0020
+#define RFCOMM_RPN_PM_XOFF		0x0040
+#define RFCOMM_RPN_PM_FLOW		0x3F00
+
+#define RFCOMM_RPN_PM_ALL		0x3F7F
+
+struct rfcomm_hdr {
+	u8 addr;
+	u8 ctrl;
+	u8 len;    // Actual size can be 2 bytes
+} __attribute__ ((packed));
+
+struct rfcomm_cmd {
+	u8 addr;
+	u8 ctrl;
+	u8 len;
+	u8 fcs;
+} __attribute__ ((packed));
+
+struct rfcomm_mcc {
+	u8 type;
+	u8 len;
+} __attribute__ ((packed));
+
+struct rfcomm_pn {
+	u8  dlci;
+	u8  flow_ctrl;
+	u8  priority;
+	u8  ack_timer;
+	u16 mtu;
+	u8  max_retrans;
+	u8  credits;
+} __attribute__ ((packed));
+
+struct rfcomm_rpn {
+	u8  dlci;
+	u8  bit_rate;
+	u8  line_settings;
+	u8  flow_ctrl;
+	u8  xon_char;
+	u8  xoff_char;
+	u16 param_mask;
+} __attribute__ ((packed));
+
+struct rfcomm_msc {
+	u8  dlci;
+	u8  v24_sig;
+} __attribute__ ((packed));
+
+/* ---- Core structures, flags etc ---- */
+
+struct rfcomm_session {
+	struct list_head list;
+	struct socket   *sock;
+	unsigned long    state;
+	unsigned long    flags;
+	atomic_t         refcnt;
+	int              initiator;
+
+	/* Default DLC parameters */
+	uint   mtu;
+	uint   credits;
+
+	struct list_head dlcs;
+};
+
+struct rfcomm_dlc {
+	struct list_head      list;
+	struct rfcomm_session *session;
+	struct sk_buff_head   tx_queue;
+	struct timer_list     timer;
+
+	spinlock_t    lock;
+	unsigned long state;
+	unsigned long flags;
+	atomic_t      refcnt;
+	u8            dlci;
+	u8            addr;
+
+	uint          mtu;
+	u8            v24_sig;
+
+	uint          credits;
+	uint          rx_credits;
+	uint          tx_credits;
+
+	void          *owner;
+
+	void (*data_ready)(struct rfcomm_dlc *d, struct sk_buff *skb);
+	void (*state_change)(struct rfcomm_dlc *d, int err);
+	void (*modem_status)(struct rfcomm_dlc *d, u8 v24_sig);
+};
+
+/* DLC and session flags */
+#define RFCOMM_RX_THROTTLED 0
+#define RFCOMM_TX_THROTTLED 1
+#define RFCOMM_MSC_PENDING  2
+#define RFCOMM_TIMED_OUT    3
+
+/* Scheduling flags and events */
+#define RFCOMM_SCHED_STATE  0
+#define RFCOMM_SCHED_RX     1
+#define RFCOMM_SCHED_TX     2
+#define RFCOMM_SCHED_TIMEO  3
+#define RFCOMM_SCHED_WAKEUP 31
+
+extern struct task_struct *rfcomm_thread;
+extern unsigned long rfcomm_event;
+
+static inline void rfcomm_schedule(uint event)
+{
+	if (!rfcomm_thread)
+		return;
+
+	if (!test_and_set_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event))
+		wake_up_process(rfcomm_thread);
+}
+
+extern struct semaphore rfcomm_sem;
+#define rfcomm_lock()	down(&rfcomm_sem);
+#define rfcomm_unlock()	up(&rfcomm_sem);
+
+/* ---- RFCOMM DLCs (channels) ---- */
+struct rfcomm_dlc *rfcomm_dlc_alloc(int prio);
+void rfcomm_dlc_free(struct rfcomm_dlc *d);
+int  rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel);
+int  rfcomm_dlc_close(struct rfcomm_dlc *d, int reason);
+int  rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb);
+int  rfcomm_dlc_set_modem_status(struct rfcomm_dlc *d, u8 v24_sig);
+int  rfcomm_dlc_get_modem_status(struct rfcomm_dlc *d, u8 *v24_sig);
+
+#define rfcomm_dlc_lock(d)	spin_lock(&d->lock)
+#define rfcomm_dlc_unlock(d)	spin_unlock(&d->lock)
+
+static inline void rfcomm_dlc_hold(struct rfcomm_dlc *d)
+{
+	atomic_inc(&d->refcnt);
+}
+
+static inline void rfcomm_dlc_put(struct rfcomm_dlc *d)
+{
+	if (atomic_dec_and_test(&d->refcnt))
+		rfcomm_dlc_free(d);
+}
+
+extern void FASTCALL(__rfcomm_dlc_throttle(struct rfcomm_dlc *d));
+extern void FASTCALL(__rfcomm_dlc_unthrottle(struct rfcomm_dlc *d));
+
+static inline void rfcomm_dlc_throttle(struct rfcomm_dlc *d)
+{
+	if (!test_and_set_bit(RFCOMM_RX_THROTTLED, &d->flags))
+		__rfcomm_dlc_throttle(d);
+}
+
+static inline void rfcomm_dlc_unthrottle(struct rfcomm_dlc *d)
+{
+	if (test_and_clear_bit(RFCOMM_RX_THROTTLED, &d->flags))
+		__rfcomm_dlc_unthrottle(d);
+}
+
+/* ---- RFCOMM sessions ---- */
+struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state);
+struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst);
+struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst, int *err);
+void   rfcomm_session_del(struct rfcomm_session *s);
+void   rfcomm_session_close(struct rfcomm_session *s, int err);
+void   rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, bdaddr_t *dst);
+
+static inline void rfcomm_session_hold(struct rfcomm_session *s)
+{
+	atomic_inc(&s->refcnt);
+}
+
+static inline void rfcomm_session_put(struct rfcomm_session *s)
+{
+	if (atomic_dec_and_test(&s->refcnt))
+		rfcomm_session_del(s);
+}
+
+/* ---- RFCOMM chechsum ---- */
+extern u8 rfcomm_crc_table[];
+
+/* ---- RFCOMM sockets ---- */
+struct sockaddr_rc {
+	sa_family_t rc_family;
+	bdaddr_t    rc_bdaddr;
+	u8          rc_channel;
+};
+
+#define rfcomm_pi(sk)	((struct rfcomm_pinfo *) &sk->tp_pinfo)
+
+struct rfcomm_pinfo {
+	struct rfcomm_dlc *dlc;
+	u8 channel;
+};
+
+int  rfcomm_init_sockets(void);
+void rfcomm_cleanup_sockets(void);
+
+int  rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc **d);
+
+/* ---- RFCOMM TTY ---- */
+#define RFCOMM_MAX_DEV  256
+
+#define RFCOMMCREATEDEV		_IOW('R', 200, int)
+#define RFCOMMRELEASEDEV	_IOW('R', 201, int)
+#define RFCOMMGETDEVLIST	_IOR('R', 210, int)
+#define RFCOMMGETDEVINFO	_IOR('R', 211, int)
+#define RFCOMMSTEALDLC		_IOW('R', 220, int)
+
+#define RFCOMM_REUSE_DLC	0
+#define RFCOMM_RELEASE_ONHUP	1
+#define RFCOMM_HANGUP_NOW	2
+#define RFCOMM_TTY_ATTACHED	3
+
+struct rfcomm_dev_req {
+	s16      dev_id;
+	u32      flags;
+	bdaddr_t src;
+	bdaddr_t dst;
+	u8       channel;
+};
+
+struct rfcomm_dev_info {
+	s16      id;
+	u32      flags;
+	u16      state;
+	bdaddr_t src;
+	bdaddr_t dst;
+	u8       channel;
+};
+
+struct rfcomm_dev_list_req {
+	u16      dev_num;
+	struct   rfcomm_dev_info dev_info[0];
+};
+
+int  rfcomm_dev_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg);
+int  rfcomm_init_ttys(void);
+void rfcomm_cleanup_ttys(void);
+
+#endif /* __RFCOMM_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/net/ip6_route.h linux-2.4.21-pre6/include/net/ip6_route.h
--- linux-2.4.20/include/net/ip6_route.h	2000-12-11 21:30:48.000000000 +0000
+++ linux-2.4.21-pre6/include/net/ip6_route.h	2003-03-26 23:49:18.000000000 +0000
@@ -31,6 +31,8 @@
 extern struct dst_entry *	ip6_route_output(struct sock *sk,
 						 struct flowi *fl);
 
+extern int			ip6_route_me_harder(struct sk_buff *skb);
+
 extern void			ip6_route_init(void);
 extern void			ip6_route_cleanup(void);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/net/ipv6.h linux-2.4.21-pre6/include/net/ipv6.h
--- linux-2.4.20/include/net/ipv6.h	2001-11-22 19:47:43.000000000 +0000
+++ linux-2.4.21-pre6/include/net/ipv6.h	2003-03-26 23:49:20.000000000 +0000
@@ -74,6 +74,20 @@
 #define IPV6_ADDR_RESERVED	0x2000U	/* reserved address space */
 
 /*
+ *	Addr scopes
+ */
+#ifdef __KERNEL__
+#define IPV6_ADDR_MC_SCOPE(a)	\
+	((a)->s6_addr[1] & 0x0f)	/* nonstandard */
+#define __IPV6_ADDR_SCOPE_INVALID	-1
+#endif
+#define IPV6_ADDR_SCOPE_NODELOCAL	0x01
+#define IPV6_ADDR_SCOPE_LINKLOCAL	0x02
+#define IPV6_ADDR_SCOPE_SITELOCAL	0x05
+#define IPV6_ADDR_SCOPE_ORGLOCAL	0x08
+#define IPV6_ADDR_SCOPE_GLOBAL		0x0e
+
+/*
  *	fragmentation header
  */
 
@@ -88,6 +102,9 @@
 
 #include <net/sock.h>
 
+/* sysctls */
+extern int sysctl_ipv6_bindv6only;
+
 extern struct ipv6_mib		ipv6_statistics[NR_CPUS*2];
 #define IP6_INC_STATS(field)		SNMP_INC_STATS(ipv6_statistics, field)
 #define IP6_INC_STATS_BH(field)		SNMP_INC_STATS_BH(ipv6_statistics, field)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/net/irda/irlap.h linux-2.4.21-pre6/include/net/irda/irlap.h
--- linux-2.4.20/include/net/irda/irlap.h	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.21-pre6/include/net/irda/irlap.h	2003-03-26 23:49:31.000000000 +0000
@@ -31,8 +31,6 @@
 #include <linux/types.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
-#include <linux/ppp_defs.h>
-#include <linux/ppp-comp.h>
 #include <linux/timer.h>
 
 #include <net/irda/irlap_event.h>
@@ -52,8 +50,32 @@
 #define CBROADCAST 0xfe       /* Connection broadcast address */
 #define XID_FORMAT 0x01       /* Discovery XID format */
 
+/* Nobody seems to use this constant. */
 #define LAP_WINDOW_SIZE 8
-#define LAP_MAX_QUEUE  10
+/* We keep the LAP queue very small to minimise the amount of buffering.
+ * this improve latency and reduce resource consumption.
+ * This work only because we have synchronous refilling of IrLAP through
+ * the flow control mechanism (via scheduler and IrTTP).
+ * 2 buffers is the minimum we can work with, one that we send while polling
+ * IrTTP, and another to know that we should not send the pf bit.
+ * Jean II */
+#define LAP_HIGH_THRESHOLD     2
+/* Some rare non TTP clients don't implement flow control, and
+ * so don't comply with the above limit (and neither with this one).
+ * For IAP and management, it doesn't matter, because they never transmit much.
+ *.For IrLPT, this should be fixed.
+ * - Jean II */
+#define LAP_MAX_QUEUE 10
+/* Please note that all IrDA management frames (LMP/TTP conn req/disc and
+ * IAS queries) fall in the second category and are sent to LAP even if TTP
+ * is stopped. This means that those frames will wait only a maximum of
+ * two (2) data frames before beeing sent on the "wire", which speed up
+ * new socket setup when the link is saturated.
+ * Same story for two sockets competing for the medium : if one saturates
+ * the LAP, when the other want to transmit it only has to wait for
+ * maximum three (3) packets (2 + one scheduling), which improve performance
+ * of delay sensitive applications.
+ * Jean II */
 
 #define NR_EXPECTED     1
 #define NR_UNEXPECTED   0
@@ -216,4 +238,24 @@
 #define IRLAP_GET_HEADER_SIZE(self) (LAP_MAX_HEADER)
 #define IRLAP_GET_TX_QUEUE_LEN(self) skb_queue_len(&self->txq)
 
+/* Return TRUE if the node is in primary mode (i.e. master)
+ * - Jean II */
+static inline int irlap_is_primary(struct irlap_cb *self)
+{
+	int ret;
+	switch(self->state) {
+	case LAP_XMIT_P:
+	case LAP_NRM_P:
+		ret = 1;
+		break;
+	case LAP_XMIT_S:
+	case LAP_NRM_S:
+		ret = 0;
+		break;
+	default:
+		ret = -1;
+	}
+	return(ret);
+}
+
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/net/irda/irlmp.h linux-2.4.21-pre6/include/net/irda/irlmp.h
--- linux-2.4.20/include/net/irda/irlmp.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/net/irda/irlmp.h	2003-03-26 23:48:58.000000000 +0000
@@ -132,6 +132,7 @@
 
 	struct irlap_cb *irlap;   /* Instance of IrLAP layer */
 	hashbin_t *lsaps;         /* LSAP associated with this link */
+	struct lsap_cb *flow_next;	/* Next lsap to be polled for Tx */
 
 	__u8  caddr;  /* Connection address */
  	__u32 saddr;  /* Source device address */
@@ -235,6 +236,7 @@
 
 void irlmp_status_request(void);
 void irlmp_status_indication(struct lap_cb *, LINK_STATUS link, LOCK_STATUS lock);
+void irlmp_flow_indication(struct lap_cb *self, LOCAL_FLOW flow);
 
 int  irlmp_slsap_inuse(__u8 slsap);
 __u8 irlmp_find_free_slsap(void);
@@ -252,7 +254,9 @@
 
 static inline hashbin_t *irlmp_get_cachelog(void) { return irlmp->cachelog; }
 
-static inline int irlmp_get_lap_tx_queue_len(struct lsap_cb *self)
+/* Check if LAP queue is full.
+ * Used by IrTTP for low control, see comments in irlap.h - Jean II */
+static inline int irlmp_lap_tx_queue_full(struct lsap_cb *self)
 {
 	if (self == NULL)
 		return 0;
@@ -261,7 +265,7 @@
 	if (self->lap->irlap == NULL)
 		return 0;
 
-	return IRLAP_GET_TX_QUEUE_LEN(self->lap->irlap);
+	return(IRLAP_GET_TX_QUEUE_LEN(self->lap->irlap) >= LAP_HIGH_THRESHOLD);
 }
 
 /* After doing a irlmp_dup(), this get one of the two socket back into
@@ -274,6 +278,8 @@
 	self->dlsap_sel = LSAP_ANY;
 	self->lap = NULL;
 	self->lsap_state = LSAP_DISCONNECTED;
+	/* Started when we received the LM_CONNECT_INDICATION */
+	del_timer(&self->watchdog_timer);
 }
 
 #endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/net/irda/irttp.h linux-2.4.21-pre6/include/net/irda/irttp.h
--- linux-2.4.20/include/net/irda/irttp.h	2001-12-21 17:42:04.000000000 +0000
+++ linux-2.4.21-pre6/include/net/irda/irttp.h	2003-03-26 23:49:19.000000000 +0000
@@ -42,11 +42,48 @@
 #define TTP_PARAMETERS         0x80
 #define TTP_MORE               0x80
 
-#define DEFAULT_INITIAL_CREDIT 14
+/* Transmission queue sizes */
+/* Worst case scenario, two window of data - Jean II */
+#define TTP_TX_MAX_QUEUE	14
+/* We need to keep at least 5 frames to make sure that we can refill
+ * appropriately the LAP layer. LAP keeps only two buffers, and we need
+ * to have 7 to make a full window - Jean II */
+#define TTP_TX_LOW_THRESHOLD	5
+/* Most clients are synchronous with respect to flow control, so we can
+ * keep a low number of Tx buffers in TTP - Jean II */
+#define TTP_TX_HIGH_THRESHOLD	7
+
+/* Receive queue sizes */
+/* Minimum of credit that the peer should hold.
+ * If the peer has less credits than 9 frames, we will explicitely send
+ * him some credits (through irttp_give_credit() and a specific frame).
+ * Note that when we give credits it's likely that it won't be sent in
+ * this LAP window, but in the next one. So, we make sure that the peer
+ * has something to send while waiting for credits (one LAP window == 7
+ * + 1 frames while he process the credits). - Jean II */
+#define TTP_RX_MIN_CREDIT	8
+/* This is the default maximum number of credits held by the peer, so the
+ * default maximum number of frames he can send us before needing flow
+ * control answer from us (this may be negociated differently at TSAP setup).
+ * We want to minimise the number of times we have to explicitely send some
+ * credit to the peer, hoping we can piggyback it on the return data. In
+ * particular, it doesn't make sense for us to send credit more than once
+ * per LAP window.
+ * Moreover, giving credits has some latency, so we need strictly more than
+ * a LAP window, otherwise we may already have credits in our Tx queue.
+ * But on the other hand, we don't want to keep too many Rx buffer here
+ * before starting to flow control the other end, so make it exactly one
+ * LAP window + 1 + MIN_CREDITS. - Jean II */
+#define TTP_RX_DEFAULT_CREDIT	16
+/* Maximum number of credits we can allow the peer to have, and therefore
+ * maximum Rx queue size.
+ * Note that we try to deliver packets to the higher layer every time we
+ * receive something, so in normal mode the Rx queue will never contains
+ * more than one or two packets. - Jean II */
+#define TTP_RX_MAX_CREDIT	21
 
-#define TTP_LOW_THRESHOLD       4
-#define TTP_HIGH_THRESHOLD     10
-#define TTP_MAX_QUEUE          14
+/* What clients should use when calling ttp_open_tsap() */
+#define DEFAULT_INITIAL_CREDIT	TTP_RX_DEFAULT_CREDIT
 
 /* Some priorities for disconnect requests */
 #define P_NORMAL    0
@@ -90,7 +127,7 @@
 
 	struct net_device_stats stats;
 	struct timer_list todo_timer; 
-	
+
 	__u32 max_seg_size;     /* Max data that fit into an IrLAP frame */
 	__u8  max_header_size;
 
@@ -131,6 +168,7 @@
 void irttp_flow_request(struct tsap_cb *self, LOCAL_FLOW flow);
 void irttp_status_indication(void *instance,
 			     LINK_STATUS link, LOCK_STATUS lock);
+void irttp_flow_indication(void *instance, void *sap, LOCAL_FLOW flow);
 struct tsap_cb *irttp_dup(struct tsap_cb *self, void *instance);
 
 static __inline __u32 irttp_get_saddr(struct tsap_cb *self)
@@ -159,6 +197,18 @@
 	self->dtsap_sel = LSAP_ANY;
 }
 
+/* Return TRUE if the node is in primary mode (i.e. master)
+ * - Jean II */
+static inline int irttp_is_primary(struct tsap_cb *self)
+{
+	if ((self == NULL) ||
+	    (self->lsap == NULL) ||
+	    (self->lsap->lap == NULL) ||
+	    (self->lsap->lap->irlap == NULL))
+		return -2;
+	return(irlap_is_primary(self->lsap->lap->irlap));
+}
+
 extern struct irttp_cb *irttp;
 
 #endif /* IRTTP_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/net/iw_handler.h linux-2.4.21-pre6/include/net/iw_handler.h
--- linux-2.4.20/include/net/iw_handler.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/net/iw_handler.h	2003-03-26 23:49:29.000000000 +0000
@@ -1,7 +1,7 @@
 /*
  * This file define the new driver API for Wireless Extensions
  *
- * Version :	3	17.1.02
+ * Version :	4	21.6.02
  *
  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
  * Copyright (c) 2001-2002 Jean Tourrilhes, All Rights Reserved.
@@ -206,7 +206,7 @@
  * will be needed...
  * I just plan to increment with each new version.
  */
-#define IW_HANDLER_VERSION	3
+#define IW_HANDLER_VERSION	4
 
 /*
  * Changes :
@@ -217,6 +217,9 @@
  *	- Add Wireless Event support :
  *		o wireless_send_event() prototype
  *		o iwe_stream_add_event/point() inline functions
+ * V3 to V4
+ * --------
+ *	- Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes
  */
 
 /**************************** CONSTANTS ****************************/
@@ -233,10 +236,10 @@
 #define IW_HEADER_TYPE_CHAR	2	/* char [IFNAMSIZ] */
 #define IW_HEADER_TYPE_UINT	4	/* __u32 */
 #define IW_HEADER_TYPE_FREQ	5	/* struct iw_freq */
-#define IW_HEADER_TYPE_POINT	6	/* struct iw_point */
-#define IW_HEADER_TYPE_PARAM	7	/* struct iw_param */
-#define IW_HEADER_TYPE_ADDR	8	/* struct sockaddr */
-#define IW_HEADER_TYPE_QUAL	9	/* struct iw_quality */
+#define IW_HEADER_TYPE_ADDR	6	/* struct sockaddr */
+#define IW_HEADER_TYPE_POINT	8	/* struct iw_point */
+#define IW_HEADER_TYPE_PARAM	9	/* struct iw_param */
+#define IW_HEADER_TYPE_QUAL	10	/* struct iw_quality */
 
 /* Handling flags */
 /* Most are not implemented. I just use them as a reminder of some
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/net/sock.h linux-2.4.21-pre6/include/net/sock.h
--- linux-2.4.20/include/net/sock.h	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.21-pre6/include/net/sock.h	2003-03-26 23:49:50.000000000 +0000
@@ -171,7 +171,8 @@
 	__u8			mc_loop:1,
 	                        recverr:1,
 	                        sndflow:1,
-	                        pmtudisc:2;
+	                        pmtudisc:2,
+				ipv6only:1;
 
 	struct ipv6_mc_socklist	*ipv6_mc_list;
 	struct ipv6_fl_socklist *ipv6_fl_list;
@@ -188,6 +189,12 @@
 	struct icmp6_filter	filter;
 };
 
+#define __ipv6_only_sock(sk)	((sk)->net_pinfo.af_inet6.ipv6only)
+#define ipv6_only_sock(sk)	((sk)->family == PF_INET6 && \
+				 (sk)->net_pinfo.af_inet6.ipv6only)
+#else
+#define __ipv6_only_sock(sk)	0
+#define ipv6_only_sock(sk)	0
 #endif /* IPV6 */
 
 #if defined(CONFIG_INET) || defined(CONFIG_INET_MODULE)
@@ -417,6 +424,9 @@
 	unsigned int		keepalive_intvl;  /* time interval between keep alive probes */
 	int			linger2;
 
+	int                     frto_counter; /* Number of new acks after RTO */
+	__u32                   frto_highmark; /* snd_nxt when RTO occurred */
+
 	unsigned long last_synq_overflow; 
 };
 
@@ -892,27 +902,41 @@
 
 /**
  *	sk_filter - run a packet through a socket filter
+ *	@sk: sock associated with &sk_buff
  *	@skb: buffer to filter
- *	@filter: filter to apply
+ *	@needlock: set to 1 if the sock is not locked by caller.
  *
  * Run the filter code and then cut skb->data to correct size returned by
  * sk_run_filter. If pkt_len is 0 we toss packet. If skb->len is smaller
  * than pkt_len we keep whole skb->data. This is the socket level
  * wrapper to sk_run_filter. It returns 0 if the packet should
- * be accepted or 1 if the packet should be tossed.
+ * be accepted or -EPERM if the packet should be tossed.
  */
- 
-static inline int sk_filter(struct sk_buff *skb, struct sk_filter *filter)
+
+static inline int sk_filter(struct sock *sk, struct sk_buff *skb, int needlock)
 {
-	int pkt_len;
+	int err = 0;
 
-        pkt_len = sk_run_filter(skb, filter->insns, filter->len);
-        if(!pkt_len)
-                return 1;	/* Toss Packet */
-        else
-                skb_trim(skb, pkt_len);
+	if (sk->filter) {
+		struct sk_filter *filter;
+		
+		if (needlock)
+			bh_lock_sock(sk);
+		
+		filter = sk->filter;
+		if (filter) {
+			int pkt_len = sk_run_filter(skb, filter->insns,
+						    filter->len);
+			if (!pkt_len)
+				err = -EPERM;
+			else
+				skb_trim(skb, pkt_len);
+		}
 
-	return 0;
+		if (needlock)
+			bh_unlock_sock(sk);
+	}
+	return err;
 }
 
 /**
@@ -939,6 +963,13 @@
 	atomic_add(sk_filter_len(fp), &sk->omem_alloc);
 }
 
+#else
+
+static inline int sk_filter(struct sock *sk, struct sk_buff *skb, int needlock)
+{
+	return 0;
+}
+
 #endif /* CONFIG_FILTER */
 
 /*
@@ -1145,36 +1176,31 @@
 
 static inline int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
 {
+	int err = 0;
+
 	/* Cast skb->rcvbuf to unsigned... It's pointless, but reduces
 	   number of warnings when compiling with -W --ANK
 	 */
-	if (atomic_read(&sk->rmem_alloc) + skb->truesize >= (unsigned)sk->rcvbuf)
-                return -ENOMEM;
-
-#ifdef CONFIG_FILTER
-	if (sk->filter) {
-		int err = 0;
-		struct sk_filter *filter;
-
-		/* It would be deadlock, if sock_queue_rcv_skb is used
-		   with socket lock! We assume that users of this
-		   function are lock free.
-		 */
-		bh_lock_sock(sk);
-		if ((filter = sk->filter) != NULL && sk_filter(skb, filter))
-			err = -EPERM;
-		bh_unlock_sock(sk);
-		if (err)
-			return err;	/* Toss packet */
+	if (atomic_read(&sk->rmem_alloc) + skb->truesize >= (unsigned)sk->rcvbuf) {
+		err = -ENOMEM;
+		goto out;
 	}
-#endif /* CONFIG_FILTER */
+
+	/* It would be deadlock, if sock_queue_rcv_skb is used
+	   with socket lock! We assume that users of this
+	   function are lock free.
+	*/
+	err = sk_filter(sk, skb, 1);
+	if (err)
+		goto out;
 
 	skb->dev = NULL;
 	skb_set_owner_r(skb, sk);
 	skb_queue_tail(&sk->receive_queue, skb);
 	if (!sk->dead)
 		sk->data_ready(sk,skb->len);
-	return 0;
+out:
+	return err;
 }
 
 static inline int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/net/tcp.h linux-2.4.21-pre6/include/net/tcp.h
--- linux-2.4.20/include/net/tcp.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/include/net/tcp.h	2003-03-26 23:49:07.000000000 +0000
@@ -460,6 +460,8 @@
 extern int sysctl_tcp_app_win;
 extern int sysctl_tcp_adv_win_scale;
 extern int sysctl_tcp_tw_reuse;
+extern int sysctl_tcp_frto;
+extern int sysctl_tcp_low_latency;
 
 extern atomic_t tcp_memory_allocated;
 extern atomic_t tcp_sockets_allocated;
@@ -710,6 +712,7 @@
 extern int			tcp_child_process(struct sock *parent,
 						  struct sock *child,
 						  struct sk_buff *skb);
+extern void			tcp_enter_frto(struct sock *sk);
 extern void			tcp_enter_loss(struct sock *sk, int how);
 extern void			tcp_clear_retrans(struct tcp_opt *tp);
 extern void			tcp_update_metrics(struct sock *sk);
@@ -1325,7 +1328,7 @@
 {
 	struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
 
-	if (tp->ucopy.task) {
+	if (!sysctl_tcp_low_latency && tp->ucopy.task) {
 		__skb_queue_tail(&tp->ucopy.prequeue, skb);
 		tp->ucopy.memory += skb->truesize;
 		if (tp->ucopy.memory > sk->rcvbuf) {
@@ -1830,4 +1833,17 @@
 
 #define TCP_CHECK_TIMER(sk) do { } while (0)
 
+static inline int tcp_use_frto(const struct sock *sk)
+{
+	const struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+	
+	/* F-RTO must be activated in sysctl and there must be some
+	 * unsent new data, and the advertised window should allow
+	 * sending it.
+	 */
+	return (sysctl_tcp_frto && tp->send_head &&
+		!after(TCP_SKB_CB(tp->send_head)->end_seq,
+		       tp->snd_una + tp->snd_wnd));
+}
+
 #endif	/* _TCP_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/include/pcmcia/ciscode.h linux-2.4.21-pre6/include/pcmcia/ciscode.h
--- linux-2.4.20/include/pcmcia/ciscode.h	2001-12-21 17:42:04.000000000 +0000
+++ linux-2.4.21-pre6/include/pcmcia/ciscode.h	2003-03-26 23:49:50.000000000 +0000
@@ -1,5 +1,5 @@
 /*
- * ciscode.h 1.48 2001/08/24 12:16:12
+ * ciscode.h 1.57 2002/11/03 20:38:14
  *
  * The contents of this file are subject to the Mozilla Public License
  * Version 1.1 (the "License"); you may not use this file except in
@@ -60,6 +60,10 @@
 #define PRODID_INTEL_DUAL_RS232		0x0301
 #define PRODID_INTEL_2PLUS		0x8422
 
+#define MANFID_KME			0x0032
+#define PRODID_KME_KXLC005_A		0x0704
+#define PRODID_KME_KXLC005_B		0x2904
+
 #define MANFID_LINKSYS			0x0143
 #define PRODID_LINKSYS_PCMLM28		0xc0ab
 #define PRODID_LINKSYS_3400		0x3341
@@ -94,6 +98,8 @@
 #define PRODID_OSITECH_JACK_336		0x0007
 #define PRODID_OSITECH_SEVEN		0x0008
 
+#define MANFID_OXSEMI			0x0279
+
 #define MANFID_PIONEER			0x000b
 
 #define MANFID_PSION			0x016c
@@ -103,6 +109,7 @@
 #define PRODID_QUATECH_SPP100		0x0003
 #define PRODID_QUATECH_DUAL_RS232	0x0012
 #define PRODID_QUATECH_DUAL_RS232_D1	0x0007
+#define PRODID_QUATECH_DUAL_RS232_D2	0x0052
 #define PRODID_QUATECH_QUAD_RS232	0x001b
 #define PRODID_QUATECH_DUAL_RS422	0x000e
 #define PRODID_QUATECH_QUAD_RS422	0x0045
@@ -120,9 +127,12 @@
 
 #define MANFID_TDK			0x0105
 #define PRODID_TDK_CF010		0x0900
+#define PRODID_TDK_GN3410		0x4815
 
 #define MANFID_TOSHIBA			0x0098
 
+#define MANFID_UNGERMANN		0x02c0
+
 #define MANFID_XIRCOM			0x0105
 
 #endif /* _LINUX_CISCODE_H */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/init/do_mounts.c linux-2.4.21-pre6/init/do_mounts.c
--- linux-2.4.20/init/do_mounts.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/init/do_mounts.c	2003-03-26 23:49:25.000000000 +0000
@@ -593,7 +593,7 @@
 		rd_blocks >>= 1;
 
 	if (nblocks > rd_blocks) {
-		printk("RAMDISK: image too big! (%d/%d blocks)\n",
+		printk("RAMDISK: image too big! (%d/%lu blocks)\n",
 		       nblocks, rd_blocks);
 		goto done;
 	}
@@ -620,11 +620,11 @@
 		goto done;
 	}
 
-	printk(KERN_NOTICE "RAMDISK: Loading %d blocks [%d disk%s] into ram disk... ", 
+	printk(KERN_NOTICE "RAMDISK: Loading %d blocks [%ld disk%s] into ram disk... ", 
 		nblocks, ((nblocks-1)/devblocks)+1, nblocks>devblocks ? "s" : "");
 	for (i=0; i < nblocks; i++) {
 		if (i && (i % devblocks == 0)) {
-			printk("done disk #%d.\n", i/devblocks);
+			printk("done disk #%ld.\n", i/devblocks);
 			rotate = 0;
 			if (close(in_fd)) {
 				printk("Error closing the disk.\n");
@@ -636,7 +636,7 @@
 				printk("Error opening disk.\n");
 				goto noclose_input;
 			}
-			printk("Loading disk #%d... ", i/devblocks+1);
+			printk("Loading disk #%ld... ", i/devblocks+1);
 		}
 		read(in_fd, buf, BLOCK_SIZE);
 		write(out_fd, buf, BLOCK_SIZE);
@@ -813,6 +813,8 @@
 	sys_fchdir(root_fd);
 	sys_chroot(".");
 	sys_umount("/old/dev", 0);
+	close(old_fd);
+	close(root_fd);
 
 	if (real_root_dev == ram0) {
 		sys_chdir("/old");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/ipc/msg.c linux-2.4.21-pre6/ipc/msg.c
--- linux-2.4.20/ipc/msg.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/ipc/msg.c	2003-03-26 23:48:57.000000000 +0000
@@ -815,10 +815,12 @@
 		schedule();
 		current->state = TASK_RUNNING;
 
+		/* This introduces a race so we must always take
+		   the slow path
 		msg = (struct msg_msg*) msr_d.r_msg;
 		if(!IS_ERR(msg)) 
 			goto out_success;
-
+		*/
 		t = msg_lock(msqid);
 		if(t==NULL)
 			msqid=-1;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/kernel/fork.c linux-2.4.21-pre6/kernel/fork.c
--- linux-2.4.20/kernel/fork.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/kernel/fork.c	2003-03-26 23:49:06.000000000 +0000
@@ -27,6 +27,7 @@
 #include <asm/pgalloc.h>
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
+#include <asm/processor.h>
 
 /* The idle threads do not count.. */
 int nr_threads;
@@ -565,6 +566,31 @@
 	p->flags = new_flags;
 }
 
+long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+{
+	struct task_struct *task = current;
+	unsigned old_task_dumpable;
+	long ret;
+
+	/* lock out any potential ptracer */
+	task_lock(task);
+	if (task->ptrace) {
+		task_unlock(task);
+		return -EPERM;
+	}
+
+	old_task_dumpable = task->task_dumpable;
+	task->task_dumpable = 0;
+	task_unlock(task);
+
+	ret = arch_kernel_thread(fn, arg, flags);
+
+	/* never reached in child process, only in parent */
+	current->task_dumpable = old_task_dumpable;
+
+	return ret;
+}
+
 /*
  *  Ok, this is the main fork-routine. It copies the system process
  * information (task[nr]) and sets up the necessary registers. It also
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/kernel/ksyms.c linux-2.4.21-pre6/kernel/ksyms.c
--- linux-2.4.20/kernel/ksyms.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/kernel/ksyms.c	2003-03-26 23:48:58.000000000 +0000
@@ -142,6 +142,7 @@
 EXPORT_SYMBOL(iunique);
 EXPORT_SYMBOL(iget4);
 EXPORT_SYMBOL(iput);
+EXPORT_SYMBOL(inode_init_once);
 EXPORT_SYMBOL(force_delete);
 EXPORT_SYMBOL(follow_up);
 EXPORT_SYMBOL(follow_down);
@@ -451,6 +452,9 @@
 EXPORT_SYMBOL(interruptible_sleep_on_timeout);
 EXPORT_SYMBOL(schedule);
 EXPORT_SYMBOL(schedule_timeout);
+#if CONFIG_SMP
+EXPORT_SYMBOL(set_cpus_allowed);
+#endif
 EXPORT_SYMBOL(yield);
 EXPORT_SYMBOL(__cond_resched);
 EXPORT_SYMBOL(jiffies);
@@ -523,11 +527,10 @@
 EXPORT_SYMBOL(init_special_inode);
 EXPORT_SYMBOL(read_ahead);
 EXPORT_SYMBOL(get_hash_table);
-EXPORT_SYMBOL(get_empty_inode);
+EXPORT_SYMBOL(new_inode);
 EXPORT_SYMBOL(insert_inode_hash);
 EXPORT_SYMBOL(remove_inode_hash);
-EXPORT_SYMBOL(buffer_insert_inode_queue);
-EXPORT_SYMBOL(buffer_insert_inode_data_queue);
+EXPORT_SYMBOL(buffer_insert_list);
 EXPORT_SYMBOL(make_bad_inode);
 EXPORT_SYMBOL(is_bad_inode);
 EXPORT_SYMBOL(event);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/kernel/module.c linux-2.4.21-pre6/kernel/module.c
--- linux-2.4.20/kernel/module.c	2001-11-11 19:23:14.000000000 +0000
+++ linux-2.4.21-pre6/kernel/module.c	2003-03-26 23:49:09.000000000 +0000
@@ -303,7 +303,7 @@
 		error = namelen;
 		goto err0;
 	}
-	if (size < sizeof(struct module)+namelen) {
+	if (size < sizeof(struct module)+namelen+1) {
 		error = -EINVAL;
 		goto err1;
 	}
@@ -482,10 +482,10 @@
 		error = n_namelen;
 		goto err2;
 	}
-	if (namelen != n_namelen || strcmp(n_name, mod_tmp.name) != 0) {
+	if (namelen != n_namelen || strcmp(n_name, name_tmp) != 0) {
 		printk(KERN_ERR "init_module: changed module name to "
 				"`%s' from `%s'\n",
-		       n_name, mod_tmp.name);
+		       n_name, name_tmp);
 		goto err3;
 	}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/kernel/printk.c linux-2.4.21-pre6/kernel/printk.c
--- linux-2.4.20/kernel/printk.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.21-pre6/kernel/printk.c	2003-03-26 23:49:38.000000000 +0000
@@ -629,7 +629,7 @@
 	}
 	if (console->flags & CON_PRINTBUFFER) {
 		/*
-		 * release_cosole_sem() will print out the buffered messages for us.
+		 * release_console_sem() will print out the buffered messages for us.
 		 */
 		spin_lock_irqsave(&logbuf_lock, flags);
 		con_start = log_start;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/kernel/ptrace.c linux-2.4.21-pre6/kernel/ptrace.c
--- linux-2.4.20/kernel/ptrace.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.21-pre6/kernel/ptrace.c	2003-03-26 23:49:55.000000000 +0000
@@ -21,6 +21,10 @@
  */
 int ptrace_check_attach(struct task_struct *child, int kill)
 {
+	mb();
+	if (!is_dumpable(child))
+		return -EPERM;
+
 	if (!(child->ptrace & PT_PTRACED))
 		return -ESRCH;
 
@@ -70,7 +74,7 @@
  	    (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE))
 		goto bad;
 	rmb();
-	if (!task->mm->dumpable && !capable(CAP_SYS_PTRACE))
+	if (!is_dumpable(task) && !capable(CAP_SYS_PTRACE))
 		goto bad;
 	/* the same process cannot be attached many times */
 	if (task->ptrace & PT_PTRACED)
@@ -136,6 +140,8 @@
 	/* Worry about races with exit() */
 	task_lock(tsk);
 	mm = tsk->mm;
+	if (!is_dumpable(tsk) || (&init_mm == mm))
+		mm = NULL;
 	if (mm)
 		atomic_inc(&mm->mm_users);
 	task_unlock(tsk);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/kernel/sched.c linux-2.4.21-pre6/kernel/sched.c
--- linux-2.4.20/kernel/sched.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/kernel/sched.c	2003-03-26 23:49:19.000000000 +0000
@@ -116,7 +116,7 @@
 
 #define idle_task(cpu) (init_tasks[cpu_number_map(cpu)])
 #define can_schedule(p,cpu) \
-	((p)->cpus_runnable & (p)->cpus_allowed & (1 << cpu))
+	((p)->cpus_runnable & (p)->cpus_allowed & (1UL << cpu))
 
 #else
 
@@ -359,7 +359,7 @@
 	if (task_on_runqueue(p))
 		goto out;
 	add_to_runqueue(p);
-	if (!synchronous || !(p->cpus_allowed & (1 << smp_processor_id())))
+	if (!synchronous || !(p->cpus_allowed & (1UL << smp_processor_id())))
 		reschedule_idle(p);
 	success = 1;
 out:
@@ -850,6 +850,44 @@
 
 void scheduling_functions_end_here(void) { }
 
+#if CONFIG_SMP
+/**
+ * set_cpus_allowed() - change a given task's processor affinity
+ * @p: task to bind
+ * @new_mask: bitmask of allowed processors
+ *
+ * Upon return, the task is running on a legal processor.  Note the caller
+ * must have a valid reference to the task: it must not exit() prematurely.
+ * This call can sleep; do not hold locks on call.
+ */
+void set_cpus_allowed(struct task_struct *p, unsigned long new_mask)
+{
+	new_mask &= cpu_online_map;
+	BUG_ON(!new_mask);
+
+	p->cpus_allowed = new_mask;
+
+	/*
+	 * If the task is on a no-longer-allowed processor, we need to move
+	 * it.  If the task is not current, then set need_resched and send
+	 * its processor an IPI to reschedule.
+	 */
+	if (!(p->cpus_runnable & p->cpus_allowed)) {
+		if (p != current) {
+			p->need_resched = 1;
+			smp_send_reschedule(p->processor);
+		}
+		/*
+		 * Wait until we are on a legal processor.  If the task is
+		 * current, then we should be on a legal processor the next
+		 * time we reschedule.  Otherwise, we need to wait for the IPI.
+		 */
+		while (!(p->cpus_runnable & p->cpus_allowed))
+			schedule();
+	}
+}
+#endif /* CONFIG_SMP */
+
 #ifndef __alpha__
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/kernel/signal.c linux-2.4.21-pre6/kernel/signal.c
--- linux-2.4.20/kernel/signal.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/kernel/signal.c	2003-03-26 23:49:30.000000000 +0000
@@ -20,6 +20,14 @@
  * SLAB caches for signal bits.
  */
 
+#define DEBUG_SIG 0
+
+#if DEBUG_SIG
+#define SIG_SLAB_DEBUG	(SLAB_DEBUG_FREE | SLAB_RED_ZONE /* | SLAB_POISON */)
+#else
+#define SIG_SLAB_DEBUG	0
+#endif
+
 static kmem_cache_t *sigqueue_cachep;
 
 atomic_t nr_queued_signals;
@@ -31,7 +39,7 @@
 		kmem_cache_create("sigqueue",
 				  sizeof(struct sigqueue),
 				  __alignof__(struct sigqueue),
-				  0, NULL, NULL);
+				  SIG_SLAB_DEBUG, NULL, NULL);
 	if (!sigqueue_cachep)
 		panic("signals_init(): cannot create sigqueue SLAB cache");
 }
@@ -257,6 +265,11 @@
 {
 	int sig = 0;
 
+#if DEBUG_SIG
+printk("SIG dequeue (%s:%d): %d ", current->comm, current->pid,
+	signal_pending(current));
+#endif
+
 	sig = next_signal(current, mask);
 	if (sig) {
 		if (current->notifier) {
@@ -276,6 +289,10 @@
 	}
 	recalc_sigpending(current);
 
+#if DEBUG_SIG
+printk(" %d -> %d\n", signal_pending(current), sig);
+#endif
+
 	return sig;
 }
 
@@ -518,6 +535,11 @@
 	unsigned long flags;
 	int ret;
 
+
+#if DEBUG_SIG
+printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig);
+#endif
+
 	ret = -EINVAL;
 	if (sig < 0 || sig > _NSIG)
 		goto out_nolock;
@@ -552,6 +574,9 @@
 out:
 	spin_unlock_irqrestore(&t->sigmask_lock, flags);
 out_nolock:
+#if DEBUG_SIG
+printk(" %d -> %d\n", signal_pending(t), ret);
+#endif
 
 	return ret;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/kernel/sys.c linux-2.4.21-pre6/kernel/sys.c
--- linux-2.4.20/kernel/sys.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.21-pre6/kernel/sys.c	2003-03-26 23:49:06.000000000 +0000
@@ -18,6 +18,25 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
+#ifndef SET_UNALIGN_CTL
+# define SET_UNALIGN_CTL(a,b)	(-EINVAL)
+#endif
+#ifndef GET_UNALIGN_CTL
+# define GET_UNALIGN_CTL(a,b)	(-EINVAL)
+#endif
+#ifndef SET_FPEMU_CTL
+# define SET_FPEMU_CTL(a,b)	(-EINVAL)
+#endif
+#ifndef GET_FPEMU_CTL
+# define GET_FPEMU_CTL(a,b)	(-EINVAL)
+#endif
+#ifndef SET_FPEXC_CTL
+# define SET_FPEXC_CTL(a,b)	(-EINVAL)
+#endif
+#ifndef GET_FPEXC_CTL
+# define GET_FPEXC_CTL(a,b)	(-EINVAL)
+#endif
+
 /*
  * this is where the system-wide overflow UID and GID are defined, for
  * architectures that now have 32-bit UID/GID but didn't in the past
@@ -1219,7 +1238,7 @@
 			error = put_user(current->pdeath_signal, (int *)arg2);
 			break;
 		case PR_GET_DUMPABLE:
-			if (current->mm->dumpable)
+			if (is_dumpable(current))
 				error = 1;
 			break;
 		case PR_SET_DUMPABLE:
@@ -1227,38 +1246,27 @@
 				error = -EINVAL;
 				break;
 			}
-			current->mm->dumpable = arg2;
+			if (is_dumpable(current))
+				current->mm->dumpable = arg2;
 			break;
+
 	        case PR_SET_UNALIGN:
-#ifdef SET_UNALIGN_CTL
 			error = SET_UNALIGN_CTL(current, arg2);
-#else
-			error = -EINVAL;
-#endif
 			break;
-
 	        case PR_GET_UNALIGN:
-#ifdef GET_UNALIGN_CTL
 			error = GET_UNALIGN_CTL(current, arg2);
-#else
-			error = -EINVAL;
-#endif
 			break;
-
 	        case PR_SET_FPEMU:
-#ifdef SET_FPEMU_CTL
 			error = SET_FPEMU_CTL(current, arg2);
-#else
-			error = -EINVAL;
-#endif
 			break;
-
 	        case PR_GET_FPEMU:
-#ifdef GET_FPEMU_CTL
 			error = GET_FPEMU_CTL(current, arg2);
-#else
-			error = -EINVAL;
-#endif
+			break;
+		case PR_SET_FPEXC:
+			error = SET_FPEXC_CTL(current, arg2);
+			break;
+		case PR_GET_FPEXC:
+			error = GET_FPEXC_CTL(current, arg2);
 			break;
 
 		case PR_GET_KEEPCAPS:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/kernel/sysctl.c linux-2.4.21-pre6/kernel/sysctl.c
--- linux-2.4.20/kernel/sysctl.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.21-pre6/kernel/sysctl.c	2003-03-26 23:49:07.000000000 +0000
@@ -49,6 +49,7 @@
 extern int max_queued_signals;
 extern int sysrq_enabled;
 extern int core_uses_pid;
+extern char core_pattern[];
 extern int cad_pid;
 
 /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */
@@ -171,6 +172,8 @@
 	 0644, NULL, &proc_dointvec},
 	{KERN_CORE_USES_PID, "core_uses_pid", &core_uses_pid, sizeof(int),
 	 0644, NULL, &proc_dointvec},
+	{KERN_CORE_PATTERN, "core_pattern", core_pattern, 64,
+	 0644, NULL, &proc_dostring, &sysctl_string},
 	{KERN_TAINTED, "tainted", &tainted, sizeof(int),
 	 0644, NULL, &proc_dointvec},
 	{KERN_CAP_BSET, "cap-bound", &cap_bset, sizeof(kernel_cap_t),
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/mm/filemap.c linux-2.4.21-pre6/mm/filemap.c
--- linux-2.4.20/mm/filemap.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/mm/filemap.c	2003-03-26 23:49:25.000000000 +0000
@@ -95,6 +95,9 @@
 {
 	struct address_space * mapping = page->mapping;
 
+	if (mapping->a_ops->removepage)
+		mapping->a_ops->removepage(page);
+	
 	mapping->nrpages--;
 	list_del(&page->list);
 	page->mapping = NULL;
@@ -1569,7 +1572,7 @@
 	chunk_size = KIO_MAX_ATOMIC_IO << 10;
 
 	retval = -EINVAL;
-	if ((offset & blocksize_mask) || (count & blocksize_mask))
+	if ((offset & blocksize_mask) || (count & blocksize_mask) || ((unsigned long) buf & blocksize_mask))
 		goto out_free;
 	if (!mapping->a_ops->direct_IO)
 		goto out_free;
@@ -1740,7 +1743,7 @@
 	return written;
 }
 
-asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t count)
+static ssize_t common_sendfile(int out_fd, int in_fd, loff_t *offset, size_t count)
 {
 	ssize_t retval;
 	struct file * in_file, * out_file;
@@ -1785,27 +1788,19 @@
 	retval = 0;
 	if (count) {
 		read_descriptor_t desc;
-		loff_t pos = 0, *ppos;
-
-		retval = -EFAULT;
-		ppos = &in_file->f_pos;
-		if (offset) {
-			if (get_user(pos, offset))
-				goto fput_out;
-			ppos = &pos;
-		}
+		
+		if (!offset)
+			offset = &in_file->f_pos;
 
 		desc.written = 0;
 		desc.count = count;
 		desc.buf = (char *) out_file;
 		desc.error = 0;
-		do_generic_file_read(in_file, ppos, &desc, file_send_actor);
+		do_generic_file_read(in_file, offset, &desc, file_send_actor);
 
 		retval = desc.written;
 		if (!retval)
 			retval = desc.error;
-		if (offset)
-			put_user(pos, offset);
 	}
 
 fput_out:
@@ -1816,6 +1811,38 @@
 	return retval;
 }
 
+asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t count)
+{
+	loff_t pos, *ppos = NULL;
+	ssize_t ret;
+	if (offset) {
+		off_t off;
+		if (unlikely(get_user(off, offset)))
+			return -EFAULT;
+		pos = off;
+		ppos = &pos;
+	}
+	ret = common_sendfile(out_fd, in_fd, ppos, count);
+	if (offset)
+		put_user((off_t)pos, offset);
+	return ret;
+}
+
+asmlinkage ssize_t sys_sendfile64(int out_fd, int in_fd, loff_t *offset, size_t count)
+{
+	loff_t pos, *ppos = NULL;
+	ssize_t ret;
+	if (offset) {
+		if (unlikely(copy_from_user(&pos, offset, sizeof(loff_t))))
+			return -EFAULT;
+		ppos = &pos;
+	}
+	ret = common_sendfile(out_fd, in_fd, ppos, count);
+	if (offset)
+		put_user(pos, offset);
+	return ret;
+}
+
 static ssize_t do_readahead(struct file *file, unsigned long index, unsigned long nr)
 {
 	struct address_space *mapping = file->f_dentry->d_inode->i_mapping;
@@ -2940,7 +2967,7 @@
 	struct page	*page, *cached_page;
 	ssize_t		written;
 	long		status = 0;
-	int		err;
+	ssize_t		err;
 	unsigned	bytes;
 
 	if ((ssize_t) count < 0)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/mm/highmem.c linux-2.4.21-pre6/mm/highmem.c
--- linux-2.4.20/mm/highmem.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/mm/highmem.c	2003-03-26 23:49:49.000000000 +0000
@@ -77,7 +77,7 @@
 	flush_tlb_all();
 }
 
-static inline unsigned long map_new_virtual(struct page *page)
+static inline unsigned long map_new_virtual(struct page *page, int nonblocking)
 {
 	unsigned long vaddr;
 	int count;
@@ -96,6 +96,9 @@
 		if (--count)
 			continue;
 
+		if (nonblocking)
+			return 0;
+
 		/*
 		 * Sleep for somebody else to unmap their entries
 		 */
@@ -126,7 +129,7 @@
 	return vaddr;
 }
 
-void *kmap_high(struct page *page)
+void *kmap_high(struct page *page, int nonblocking)
 {
 	unsigned long vaddr;
 
@@ -138,11 +141,15 @@
 	 */
 	spin_lock(&kmap_lock);
 	vaddr = (unsigned long) page->virtual;
-	if (!vaddr)
-		vaddr = map_new_virtual(page);
+	if (!vaddr) {
+		vaddr = map_new_virtual(page, nonblocking);
+		if (!vaddr)
+			goto out;
+	}
 	pkmap_count[PKMAP_NR(vaddr)]++;
 	if (pkmap_count[PKMAP_NR(vaddr)] < 2)
 		BUG();
+ out:
 	spin_unlock(&kmap_lock);
 	return (void*) vaddr;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/mm/mmap.c linux-2.4.21-pre6/mm/mmap.c
--- linux-2.4.20/mm/mmap.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/mm/mmap.c	2003-03-26 23:49:00.000000000 +0000
@@ -403,10 +403,12 @@
 	if (file && (!file->f_op || !file->f_op->mmap))
 		return -ENODEV;
 
-	if ((len = PAGE_ALIGN(len)) == 0)
+	if (!len)
 		return addr;
 
-	if (len > TASK_SIZE)
+	len = PAGE_ALIGN(len);
+
+	if (len > TASK_SIZE || len == 0)
 		return -EINVAL;
 
 	/* offset overflow? */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/mm/shmem.c linux-2.4.21-pre6/mm/shmem.c
--- linux-2.4.20/mm/shmem.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/mm/shmem.c	2003-03-26 23:49:34.000000000 +0000
@@ -919,14 +919,13 @@
 	struct inode *inode = filp->f_dentry->d_inode;
 	struct address_space *mapping = inode->i_mapping;
 	unsigned long index, offset;
-	int nr = 1;
 
 	index = *ppos >> PAGE_CACHE_SHIFT;
 	offset = *ppos & ~PAGE_CACHE_MASK;
 
-	while (nr && desc->count) {
+	for (;;) {
 		struct page *page;
-		unsigned long end_index, nr;
+		unsigned long end_index, nr, ret;
 
 		end_index = inode->i_size >> PAGE_CACHE_SHIFT;
 		if (index > end_index)
@@ -956,12 +955,14 @@
 		 * "pos" here (the actor routine has to update the user buffer
 		 * pointers and the remaining count).
 		 */
-		nr = file_read_actor(desc, page, offset, nr);
-		offset += nr;
+		ret = file_read_actor(desc, page, offset, nr);
+		offset += ret;
 		index += offset >> PAGE_CACHE_SHIFT;
 		offset &= ~PAGE_CACHE_MASK;
 	
 		page_cache_release(page);
+		if (ret != nr || !desc->count)
+			break;
 	}
 
 	*ppos = ((loff_t) index << PAGE_CACHE_SHIFT) + offset;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/mm/slab.c linux-2.4.21-pre6/mm/slab.c
--- linux-2.4.20/mm/slab.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/mm/slab.c	2003-03-26 23:49:51.000000000 +0000
@@ -989,6 +989,8 @@
  * cache being allocated each time a module is loaded and unloaded, if the
  * module doesn't have persistent in-kernel storage across loads and unloads.
  *
+ * The cache must be empty before calling this function.
+ *
  * The caller must guarantee that noone will allocate memory from the cache
  * during the kmem_cache_destroy().
  */
@@ -1947,8 +1949,12 @@
 	name = cachep->name; 
 	{
 	char tmp; 
+	mm_segment_t	old_fs;
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
 	if (__get_user(tmp, name)) 
 		name = "broken"; 
+	set_fs(old_fs);
 	}       
 
 	seq_printf(m, "%-17s %6lu %6lu %6u %4lu %4lu %4u",
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/mm/swapfile.c linux-2.4.21-pre6/mm/swapfile.c
--- linux-2.4.20/mm/swapfile.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.21-pre6/mm/swapfile.c	2003-03-26 23:49:15.000000000 +0000
@@ -915,6 +915,11 @@
 		struct block_device_operations *bdops;
 		devfs_handle_t de;
 
+		if (is_mounted(dev)) {
+			error = -EBUSY;
+			goto bad_swap_2;
+		}
+
 		p->swap_device = dev;
 		set_blocksize(dev, PAGE_SIZE);
 		
@@ -1174,47 +1179,6 @@
 }
 
 /*
- * Page lock needs to be held in all cases to prevent races with
- * swap file deletion.
- */
-int swap_count(struct page *page)
-{
-	struct swap_info_struct * p;
-	unsigned long offset, type;
-	swp_entry_t entry;
-	int retval = 0;
-
-	entry.val = page->index;
-	if (!entry.val)
-		goto bad_entry;
-	type = SWP_TYPE(entry);
-	if (type >= nr_swapfiles)
-		goto bad_file;
-	p = type + swap_info;
-	offset = SWP_OFFSET(entry);
-	if (offset >= p->max)
-		goto bad_offset;
-	if (!p->swap_map[offset])
-		goto bad_unused;
-	retval = p->swap_map[offset];
-out:
-	return retval;
-
-bad_entry:
-	printk(KERN_ERR "swap_count: null entry!\n");
-	goto out;
-bad_file:
-	printk(KERN_ERR "swap_count: %s%08lx\n", Bad_file, entry.val);
-	goto out;
-bad_offset:
-	printk(KERN_ERR "swap_count: %s%08lx\n", Bad_offset, entry.val);
-	goto out;
-bad_unused:
-	printk(KERN_ERR "swap_count: %s%08lx\n", Unused_offset, entry.val);
-	goto out;
-}
-
-/*
  * Prior swap_duplicate protects against swap device deletion.
  */
 void get_swaphandle_info(swp_entry_t entry, unsigned long *offset, 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/mm/vmalloc.c linux-2.4.21-pre6/mm/vmalloc.c
--- linux-2.4.20/mm/vmalloc.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/mm/vmalloc.c	2003-03-26 23:49:40.000000000 +0000
@@ -170,7 +170,7 @@
 
 struct vm_struct * get_vm_area(unsigned long size, unsigned long flags)
 {
-	unsigned long addr;
+	unsigned long addr, next;
 	struct vm_struct **p, *tmp, *area;
 
 	area = (struct vm_struct *) kmalloc(sizeof(*area), GFP_KERNEL);
@@ -190,7 +190,9 @@
 			goto out;
 		if (size + addr <= (unsigned long) tmp->addr)
 			break;
-		addr = tmp->size + (unsigned long) tmp->addr;
+		next = tmp->size + (unsigned long) tmp->addr;
+		if (next > addr) 
+			addr = next;
 		if (addr > VMALLOC_END-size)
 			goto out;
 	}
@@ -238,10 +240,8 @@
 	struct vm_struct *area;
 
 	size = PAGE_ALIGN(size);
-	if (!size || (size >> PAGE_SHIFT) > num_physpages) {
-		BUG();
+	if (!size || (size >> PAGE_SHIFT) > num_physpages)
 		return NULL;
-	}
 	area = get_vm_area(size, VM_ALLOC);
 	if (!area)
 		return NULL;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/802/tr.c linux-2.4.21-pre6/net/802/tr.c
--- linux-2.4.20/net/802/tr.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.21-pre6/net/802/tr.c	2003-03-26 23:49:02.000000000 +0000
@@ -66,8 +66,7 @@
  *	up a lot.
  */
  
-rif_cache rif_table[RIF_TABLE_SIZE];
-
+static rif_cache rif_table[RIF_TABLE_SIZE];
 static spinlock_t rif_lock = SPIN_LOCK_UNLOCKED;
 
 #define RIF_TIMEOUT 60*10*HZ
@@ -93,10 +92,10 @@
 	int hdr_len;
 
 	/* 
-	 * Add the 802.2 SNAP header if IP as the IPv4 code calls  
+	 * Add the 802.2 SNAP header if IP as the IPv4/IPv6 code calls  
 	 * dev->hard_header directly.
 	 */
-	if (type == ETH_P_IP || type == ETH_P_ARP)
+	if (type == ETH_P_IP || type == ETH_P_IPV6 || type == ETH_P_ARP)
 	{
 		struct trllc *trllc=(struct trllc *)(trh+1);
 
@@ -218,6 +217,7 @@
 
 	if (trllc->dsap == EXTENDED_SAP &&
 	    (trllc->ethertype == ntohs(ETH_P_IP) ||
+	     trllc->ethertype == ntohs(ETH_P_IPV6) ||
 	     trllc->ethertype == ntohs(ETH_P_ARP)))
 	{
 		skb_pull(skb, sizeof(struct trllc));
@@ -327,9 +327,9 @@
 	int i;
 	unsigned int hash, rii_p = 0;
 	rif_cache entry;
+	unsigned long flags;
 
-
-	spin_lock_bh(&rif_lock);
+	spin_lock_irqsave(&rif_lock, flags);
 	
 	/*
 	 *	Firstly see if the entry exists
@@ -368,7 +368,7 @@
 		if(!entry) 
 		{
 			printk(KERN_DEBUG "tr.c: Couldn't malloc rif cache entry !\n");
-			spin_unlock_bh(&rif_lock);
+			spin_unlock_irqrestore(&rif_lock,flags);
 			return;
 		}
 
@@ -410,7 +410,7 @@
 		    }                                         
            	entry->last_used=jiffies;               
 	}
-	spin_unlock_bh(&rif_lock);
+	spin_unlock_irqrestore(&rif_lock,flags);
 }
 
 /*
@@ -468,6 +468,7 @@
 	off_t pos=0;
 	int size,i,j,rcf_len,segment,brdgnmb;
 	unsigned long now=jiffies;
+	unsigned long flags;
 
 	rif_cache entry;
 
@@ -476,7 +477,7 @@
 	pos+=size;
 	len+=size;
 
-	spin_lock_bh(&rif_lock);
+	spin_lock_irqsave(&rif_lock, flags);
 	for(i=0;i < RIF_TABLE_SIZE;i++) 
 	{
 		for(entry=rif_table[i];entry;entry=entry->next) {
@@ -525,7 +526,7 @@
 		if(pos>offset+length)
 			break;
 	}
-	spin_unlock_bh(&rif_lock);
+	spin_unlock_irqrestore(&rif_lock,flags);
 
 	*start=buffer+(offset-begin); /* Start of wanted data */
 	len-=(offset-begin);    /* Start slop */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/8021q/vlan.c linux-2.4.21-pre6/net/8021q/vlan.c
--- linux-2.4.20/net/8021q/vlan.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/8021q/vlan.c	2003-03-26 23:49:51.000000000 +0000
@@ -45,7 +45,7 @@
 
 static char vlan_fullname[] = "802.1Q VLAN Support";
 static unsigned int vlan_version = 1;
-static unsigned int vlan_release = 7;
+static unsigned int vlan_release = 8;
 static char vlan_copyright[] = "Ben Greear <greearb@candelatech.com>";
 static char vlan_buggyright[] = "David S. Miller <davem@redhat.com>";
 
@@ -229,12 +229,13 @@
 			if (real_dev->features &
 			    (NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER)) {
 				real_dev->vlan_rx_kill_vid(real_dev, vlan_id);
-			} else {
-				br_write_lock(BR_NETPROTO_LOCK);
-				grp->vlan_devices[vlan_id] = NULL;
-				br_write_unlock(BR_NETPROTO_LOCK);
 			}
 
+			br_write_lock(BR_NETPROTO_LOCK);
+			grp->vlan_devices[vlan_id] = NULL;
+			br_write_unlock(BR_NETPROTO_LOCK);
+
+
 			/* Caller unregisters (and if necessary, puts)
 			 * VLAN device, but we get rid of the reference to
 			 * real_dev here.
@@ -256,6 +257,12 @@
 				__grp_unhash(grp);
 				spin_unlock_bh(&vlan_group_lock);
 
+				/* Free the group, after we have removed it
+				 * from the hash.
+				 */
+				kfree(grp);
+				grp = NULL;
+
 				ret = 1;
 			}
 
@@ -626,6 +633,7 @@
 			ret = unregister_vlan_dev(dev,
 						  VLAN_DEV_INFO(vlandev)->vlan_id);
 
+			dev_put(vlandev);
 			unregister_netdevice(vlandev);
 
 			/* Group was destroyed? */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/8021q/vlan_dev.c linux-2.4.21-pre6/net/8021q/vlan_dev.c
--- linux-2.4.20/net/8021q/vlan_dev.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/8021q/vlan_dev.c	2003-03-26 23:49:54.000000000 +0000
@@ -738,7 +738,7 @@
 
 	while (dmi) {
 		dev_mc_delete(dev, dmi->dmi_addr, dmi->dmi_addrlen, 0);
-		printk(KERN_INFO "%s: del %.2x:%.2x:%.2x:%.2x:%.2x:%.2x mcast address from vlan interface\n",
+		printk(KERN_DEBUG "%s: del %.2x:%.2x:%.2x:%.2x:%.2x:%.2x mcast address from vlan interface\n",
 		       dev->name,
 		       dmi->dmi_addr[0],
 		       dmi->dmi_addr[1],
@@ -820,7 +820,7 @@
 		for (dmi = vlan_dev->mc_list; dmi != NULL; dmi = dmi->next) {
 			if (vlan_should_add_mc(dmi, VLAN_DEV_INFO(vlan_dev)->old_mc_list)) {
 				dev_mc_add(real_dev, dmi->dmi_addr, dmi->dmi_addrlen, 0);
-				printk(KERN_INFO "%s: add %.2x:%.2x:%.2x:%.2x:%.2x:%.2x mcast address to master interface\n",
+				printk(KERN_DEBUG "%s: add %.2x:%.2x:%.2x:%.2x:%.2x:%.2x mcast address to master interface\n",
 				       vlan_dev->name,
 				       dmi->dmi_addr[0],
 				       dmi->dmi_addr[1],
@@ -838,7 +838,7 @@
 				 * delete it from the real list on the underlying device.
 				 */
 				dev_mc_delete(real_dev, dmi->dmi_addr, dmi->dmi_addrlen, 0);
-				printk(KERN_INFO "%s: del %.2x:%.2x:%.2x:%.2x:%.2x:%.2x mcast address from master interface\n",
+				printk(KERN_DEBUG "%s: del %.2x:%.2x:%.2x:%.2x:%.2x:%.2x mcast address from master interface\n",
 				       vlan_dev->name,
 				       dmi->dmi_addr[0],
 				       dmi->dmi_addr[1],
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/atm/common.c linux-2.4.21-pre6/net/atm/common.c
--- linux-2.4.20/net/atm/common.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.21-pre6/net/atm/common.c	2003-03-26 23:49:56.000000000 +0000
@@ -128,7 +128,6 @@
 	vcc->push_oam = NULL;
 	vcc->vpi = vcc->vci = 0; /* no VCI/VPI yet */
 	vcc->atm_options = vcc->aal_options = 0;
-	vcc->timestamp.tv_sec = vcc->timestamp.tv_usec = 0;
 	init_waitqueue_head(&vcc->sleep);
 	skb_queue_head_init(&vcc->recvq);
 	skb_queue_head_init(&vcc->listenq);
@@ -387,7 +386,7 @@
 	set_current_state(TASK_RUNNING);
 	remove_wait_queue(&vcc->sleep,&wait);
 	if (error <= 0) return error;
-	vcc->timestamp = skb->stamp;
+	sock_recv_timestamp(m, vcc->sk, skb);
 	eff_len = skb->len > size ? size : skb->len;
 	if (skb->len > size) /* Not fit ?  Report it... */
 		m->msg_flags |= MSG_TRUNC;
@@ -619,13 +618,11 @@
 			kfree(tmp_buf);
 			goto done;
 		case SIOCGSTAMP: /* borrowed from IP */
-			if (!vcc->timestamp.tv_sec) {
+			if (!vcc->sk->stamp.tv_sec) {
 				ret_val = -ENOENT;
 				goto done;
 			}
-			vcc->timestamp.tv_sec += vcc->timestamp.tv_usec/1000000;
-			vcc->timestamp.tv_usec %= 1000000;
-			ret_val = copy_to_user((void *) arg,&vcc->timestamp,
+			ret_val = copy_to_user((void *) arg, &vcc->sk->stamp,
 			    sizeof(struct timeval)) ? -EFAULT : 0;
 			goto done;
 		case ATM_SETSC:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/atm/lec.c linux-2.4.21-pre6/net/atm/lec.c
--- linux-2.4.20/net/atm/lec.c	2001-09-30 19:26:08.000000000 +0000
+++ linux-2.4.21-pre6/net/atm/lec.c	2003-03-26 23:49:00.000000000 +0000
@@ -204,7 +204,8 @@
         struct lecdatahdr_8023 *lec_h;
         struct atm_vcc *send_vcc;
 	struct lec_arp_table *entry;
-        unsigned char *nb, *dst;
+        unsigned char *dst;
+	int min_frame_size;
 #ifdef CONFIG_TR
         unsigned char rdesc[ETH_ALEN]; /* Token Ring route descriptor */
 #endif
@@ -275,26 +276,24 @@
 #endif /* DUMP_PACKETS > 0 */
 
         /* Minimum ethernet-frame size */
-        if (skb->len <62) {
-                if (skb->truesize < 62) {
-                        printk("%s:data packet %d / %d\n",
-                               dev->name,
-                               skb->len,skb->truesize);
-                        nb=(unsigned char*)kmalloc(64, GFP_ATOMIC);
-                        if (nb == NULL) {
+#ifdef CONFIG_TR
+        if (priv->is_trdev)
+                min_frame_size = LEC_MINIMUM_8025_SIZE;
+	else
+#endif
+        min_frame_size = LEC_MINIMUM_8023_SIZE;
+        if (skb->len < min_frame_size) {
+                if (skb->truesize < min_frame_size) {
+                        skb2 = skb_copy_expand(skb, 0,
+                            min_frame_size - skb->truesize, GFP_ATOMIC);
                                 dev_kfree_skb(skb);
+                        if (skb2 == NULL) {
+                                priv->stats.tx_dropped++;
                                 return 0;
                         }
-                        memcpy(nb,skb->data,skb->len);
-                        kfree(skb->head);
-                        skb->head = skb->data = nb;
-                        skb->tail = nb+62;
-                        skb->end = nb+64;
-                        skb->len=62;
-                        skb->truesize = 64;
-                } else {
-                        skb->len = 62;
+                        skb = skb2;
                 }
+		skb_put(skb, min_frame_size - skb->len);
         }
         
         /* Send to right vcc */
@@ -623,6 +622,14 @@
         return 0;
 }
 
+static void lec_set_multicast_list(struct net_device *dev)
+{
+	/* by default, all multicast frames arrive over the bus.
+         * eventually support selective multicast service
+         */
+        return;
+}
+
 static void 
 lec_init(struct net_device *dev)
 {
@@ -632,7 +639,7 @@
         dev->hard_start_xmit = lec_send_packet;
 
         dev->get_stats = lec_get_stats;
-        dev->set_multicast_list = NULL;
+        dev->set_multicast_list = lec_set_multicast_list;
         dev->do_ioctl  = NULL;
         printk("%s: Initialized!\n",dev->name);
         return;
@@ -711,7 +718,7 @@
                         lec_arp_check_empties(priv, vcc, skb);
                 }
                 skb->dev = dev;
-                skb->data += 2; /* skip lec_id */
+                skb_pull(skb, 2); /* skip lec_id */
 #ifdef CONFIG_TR
                 if (priv->is_trdev) skb->protocol = tr_type_trans(skb, dev);
                 else
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/atm/lec.h linux-2.4.21-pre6/net/atm/lec.h
--- linux-2.4.20/net/atm/lec.h	2001-02-09 19:34:13.000000000 +0000
+++ linux-2.4.21-pre6/net/atm/lec.h	2003-03-26 23:49:25.000000000 +0000
@@ -38,6 +38,9 @@
   unsigned char h_source[ETH_ALEN];
 };
 
+#define LEC_MINIMUM_8023_SIZE   62
+#define LEC_MINIMUM_8025_SIZE   16
+
 /*
  * Operations that LANE2 capable device can do. Two first functions
  * are used to make the device do things. See spec 3.1.3 and 3.1.4.
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/bluetooth/Config.in linux-2.4.21-pre6/net/bluetooth/Config.in
--- linux-2.4.20/net/bluetooth/Config.in	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/bluetooth/Config.in	2003-03-26 23:49:50.000000000 +0000
@@ -1,8 +1,9 @@
 #
-# Bluetooth configuration
+# Bluetooth subsystem configuration
 #
 
 if [ "$CONFIG_NET" != "n" ]; then
+
    mainmenu_option next_comment
    comment 'Bluetooth support'
    dep_tristate 'Bluetooth subsystem support' CONFIG_BLUEZ $CONFIG_NET
@@ -10,9 +11,11 @@
    if [ "$CONFIG_BLUEZ" != "n" ]; then
       dep_tristate 'L2CAP protocol support' CONFIG_BLUEZ_L2CAP $CONFIG_BLUEZ
       dep_tristate 'SCO links support' CONFIG_BLUEZ_SCO $CONFIG_BLUEZ
+      source net/bluetooth/rfcomm/Config.in
       source net/bluetooth/bnep/Config.in
       source drivers/bluetooth/Config.in
    fi
+
    endmenu
 fi
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/bluetooth/Makefile linux-2.4.21-pre6/net/bluetooth/Makefile
--- linux-2.4.20/net/bluetooth/Makefile	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/bluetooth/Makefile	2003-03-26 23:49:09.000000000 +0000
@@ -1,6 +1,7 @@
 #
-# Makefile for the Bluetooth subsystem
+# Makefile for the Linux Bluetooth subsystem
 #
+
 O_TARGET    := bluetooth.o
 
 list-multi  := bluez.o
@@ -12,8 +13,13 @@
 obj-$(CONFIG_BLUEZ_L2CAP) += l2cap.o
 obj-$(CONFIG_BLUEZ_SCO) += sco.o
 
+subdir-$(CONFIG_BLUEZ_RFCOMM) += rfcomm
 subdir-$(CONFIG_BLUEZ_BNEP) += bnep
 
+ifeq ($(CONFIG_BLUEZ_RFCOMM),y)
+obj-y += rfcomm/rfcomm.o
+endif
+
 ifeq ($(CONFIG_BLUEZ_BNEP),y)
 obj-y += bnep/bnep.o
 endif
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/bluetooth/bnep/Config.in linux-2.4.21-pre6/net/bluetooth/bnep/Config.in
--- linux-2.4.20/net/bluetooth/bnep/Config.in	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/bluetooth/bnep/Config.in	2003-03-26 23:49:54.000000000 +0000
@@ -1,6 +1,11 @@
+#
+# Bluetooth BNEP layer configuration
+#
 
 dep_tristate 'BNEP protocol support' CONFIG_BLUEZ_BNEP $CONFIG_BLUEZ_L2CAP
+
 if [ "$CONFIG_BLUEZ_BNEP" != "n" ]; then
-   bool '  Multicast filter support' CONFIG_BNEP_MC_FILTER
-   bool '  Protocol filter support'  CONFIG_BNEP_PROTO_FILTER
+   bool '  Multicast filter support' CONFIG_BLUEZ_BNEP_MC_FILTER
+   bool '  Protocol filter support'  CONFIG_BLUEZ_BNEP_PROTO_FILTER
 fi
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/bluetooth/bnep/Makefile linux-2.4.21-pre6/net/bluetooth/bnep/Makefile
--- linux-2.4.20/net/bluetooth/bnep/Makefile	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/bluetooth/bnep/Makefile	2003-03-26 23:49:49.000000000 +0000
@@ -1,5 +1,5 @@
 #
-# Makefile for BNEP protocol
+# Makefile for the Linux Bluetooth BNEP layer
 #
 
 O_TARGET := bnep.o
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/bluetooth/bnep/bnep.h linux-2.4.21-pre6/net/bluetooth/bnep/bnep.h
--- linux-2.4.20/net/bluetooth/bnep/bnep.h	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/bluetooth/bnep/bnep.h	2003-03-26 23:49:55.000000000 +0000
@@ -112,25 +112,25 @@
 	__u8  data[0];
 } __attribute__((packed));
 
-// Ioctl interface
-#define BNEPCONADD      1
-#define BNEPCONDEL      2
-#define BNEPGETCONLIST  3
-#define BNEPGETCONINFO  4
+/* BNEP ioctl defines */
+#define BNEPCONNADD	_IOW('B', 200, int)
+#define BNEPCONNDEL	_IOW('B', 201, int)
+#define BNEPGETCONNLIST	_IOR('B', 210, int)
+#define BNEPGETCONNINFO	_IOR('B', 211, int)
 
-struct bnep_conadd_req {
+struct bnep_connadd_req {
 	int   sock;       // Connected socket
 	__u32 flags;
 	__u16 role;
 	char  device[16]; // Name of the Ethernet device
 };
 
-struct bnep_condel_req {
+struct bnep_conndel_req {
 	__u32 flags;
 	__u8  dst[ETH_ALEN];
 };
 
-struct bnep_coninfo {
+struct bnep_conninfo {
 	__u32 flags;
 	__u16 role;
 	__u16 state;	
@@ -138,9 +138,9 @@
 	char  device[16];
 };
 
-struct bnep_conlist_req {
+struct bnep_connlist_req {
 	__u32  cnum;
-	struct bnep_coninfo *ci;
+	struct bnep_conninfo *ci;
 };
 
 struct bnep_proto_filter {
@@ -148,10 +148,10 @@
 	__u16 end;
 };
 
-int bnep_add_connection(struct bnep_conadd_req *req, struct socket *sock);
-int bnep_del_connection(struct bnep_condel_req *req);
-int bnep_get_conlist(struct bnep_conlist_req *req);
-int bnep_get_coninfo(struct bnep_coninfo *ci);
+int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock);
+int bnep_del_connection(struct bnep_conndel_req *req);
+int bnep_get_connlist(struct bnep_connlist_req *req);
+int bnep_get_conninfo(struct bnep_conninfo *ci);
 
 // BNEP sessions
 struct bnep_session {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/bluetooth/bnep/core.c linux-2.4.21-pre6/net/bluetooth/bnep/core.c
--- linux-2.4.20/net/bluetooth/bnep/core.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/bluetooth/bnep/core.c	2003-03-26 23:49:55.000000000 +0000
@@ -58,17 +58,17 @@
 
 #include "bnep.h"
 
-#ifndef CONFIG_BNEP_DEBUG
+#ifndef CONFIG_BLUEZ_BNEP_DEBUG
 #undef  BT_DBG
 #define BT_DBG(D...)
 #endif
 
-#define VERSION "1.0"
+#define VERSION "1.1"
 
 static LIST_HEAD(bnep_session_list);
 static DECLARE_RWSEM(bnep_session_sem);
 
-static struct bnep_session *__bnep_get_session(__u8 *dst)
+static struct bnep_session *__bnep_get_session(u8 *dst)
 {
 	struct bnep_session *s;
 	struct list_head *p;
@@ -104,7 +104,7 @@
 	return sock->ops->sendmsg(sock, &s->msg, len, NULL);
 }
 
-static int bnep_send_rsp(struct bnep_session *s, __u8 ctrl, __u16 resp)
+static int bnep_send_rsp(struct bnep_session *s, u8 ctrl, u16 resp)
 {
 	struct bnep_control_rsp rsp;
 	rsp.type = BNEP_CONTROL;
@@ -113,23 +113,22 @@
 	return bnep_send(s, &rsp, sizeof(rsp));
 }
 
-static int bnep_ctrl_set_netfilter(struct bnep_session *s, struct sk_buff *skb)
+static int bnep_ctrl_set_netfilter(struct bnep_session *s, u16 *data, int len)
 {
-	__u16 *data;
 	int n;
-	
-	data = (void *) skb->data;
-	if (!skb_pull(skb, 2))
+
+	if (len < 2)
 		return -EILSEQ;
+	
 	n = ntohs(get_unaligned(data));
+	data++; len -= 2;
 
-	data = (void *) skb->data;
-	if (!skb_pull(skb, n))
+	if (len < n)
 		return -EILSEQ;
 
 	BT_DBG("filter len %d", n);
 
-#ifdef CONFIG_BNEP_PROTO_FILTER
+#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER
 	n /= 4;
 	if (n <= BNEP_MAX_PROTO_FILTERS) {
 		struct bnep_proto_filter *f = s->proto_filter;
@@ -155,23 +154,22 @@
 	return 0;
 }
 
-static int bnep_ctrl_set_mcfilter(struct bnep_session *s, struct sk_buff *skb)
+static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len)
 {
-	u8 *data;
 	int n;
-	
-	data = (void *) skb->data;
-	if (!skb_pull(skb, 2))
+
+	if (len < 2)
 		return -EILSEQ;
-	n = ntohs(get_unaligned((u16 *) data));
+	
+	n = ntohs(get_unaligned((u16 *) data)); 
+	data += 2; len -= 2;
 
-	data = (void *) skb->data;
-	if (!skb_pull(skb, n))
+	if (len < n)
 		return -EILSEQ;
 
 	BT_DBG("filter len %d", n);
 
-#ifdef CONFIG_BNEP_MC_FILTER
+#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
 	n /= (ETH_ALEN * 2);
 
 	if (n > 0) {
@@ -210,11 +208,12 @@
 	return 0;
 }
 
-static int bnep_rx_control(struct bnep_session *s, struct sk_buff *skb)
+static int bnep_rx_control(struct bnep_session *s, void *data, int len)
 {
+	u8  cmd = *(u8 *)data;
 	int err = 0;
-	__u8 cmd = *(__u8 *) skb->data;
-	skb_pull(skb, 1);
+
+	data++; len--;
 	
 	switch (cmd) {
 	case BNEP_CMD_NOT_UNDERSTOOD:
@@ -226,15 +225,15 @@
 		break;
 		
 	case BNEP_FILTER_NET_TYPE_SET:
-		err = bnep_ctrl_set_netfilter(s, skb);
+		err = bnep_ctrl_set_netfilter(s, data, len);
 		break;
 
 	case BNEP_FILTER_MULTI_ADDR_SET:
-		err = bnep_ctrl_set_mcfilter(s, skb);
+		err = bnep_ctrl_set_mcfilter(s, data, len);
 		break;
 
 	default: {
-			__u8 pkt[3];
+			u8 pkt[3];
 			pkt[0] = BNEP_CONTROL;
 			pkt[1] = BNEP_CMD_NOT_UNDERSTOOD;
 			pkt[2] = cmd;
@@ -262,13 +261,16 @@
 		
 		switch (h->type & BNEP_TYPE_MASK) {
 		case BNEP_EXT_CONTROL:
-			err = bnep_rx_control(s, skb);
+			bnep_rx_control(s, skb->data, skb->len);
 			break;
 
 		default:
-			/* Unknown extension */
-			if (!skb_pull(skb, h->len))
-				err = -EILSEQ;
+			/* Unknown extension, skip it. */
+			break;
+		}
+	
+		if (!skb_pull(skb, h->len)) {
+			err = -EILSEQ;
 			break;
 		}
 	} while (!err && (h->type & BNEP_EXT_HEADER));
@@ -276,7 +278,7 @@
 	return err;
 }
 
-static __u8 __bnep_rx_hlen[] = {
+static u8 __bnep_rx_hlen[] = {
 	ETH_HLEN,     /* BNEP_GENERAL */
 	0,            /* BNEP_CONTROL */
 	2,            /* BNEP_COMPRESSED */
@@ -289,18 +291,18 @@
 {
 	struct net_device *dev = &s->dev;
 	struct sk_buff *nskb;
-	__u8 type;
+	u8 type;
 
 	dev->last_rx = jiffies;
 	s->stats.rx_bytes += skb->len;
 
-	type = *(__u8 *) skb->data; skb_pull(skb, 1);
+	type = *(u8 *) skb->data; skb_pull(skb, 1);
 
 	if ((type & BNEP_TYPE_MASK) > BNEP_RX_TYPES)
 		goto badframe;
 	
 	if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) {
-		bnep_rx_control(s, skb);
+		bnep_rx_control(s, skb->data, skb->len);
 		kfree_skb(skb);
 		return 0;
 	}
@@ -311,7 +313,7 @@
 	if (!skb_pull(skb, __bnep_rx_hlen[type & BNEP_TYPE_MASK]))
 		goto badframe;
 
-	s->eh.h_proto = get_unaligned((__u16 *) (skb->data - 2));
+	s->eh.h_proto = get_unaligned((u16 *) (skb->data - 2));
 
 	if (type & BNEP_EXT_HEADER) {
 		if (bnep_rx_extension(s, skb) < 0)
@@ -322,7 +324,7 @@
 	if (ntohs(s->eh.h_proto) == 0x8100) {
 		if (!skb_pull(skb, 4))
 			goto badframe;
-		s->eh.h_proto = get_unaligned((__u16 *) (skb->data - 2));
+		s->eh.h_proto = get_unaligned((u16 *) (skb->data - 2));
 	}
 	
 	/* We have to alloc new skb and copy data here :(. Because original skb
@@ -344,7 +346,7 @@
 	case BNEP_COMPRESSED_SRC_ONLY:
 		memcpy(__skb_put(nskb, ETH_ALEN), s->eh.h_dest, ETH_ALEN);
 		memcpy(__skb_put(nskb, ETH_ALEN), skb->mac.raw, ETH_ALEN);
-		put_unaligned(s->eh.h_proto, (__u16 *) __skb_put(nskb, 2));
+		put_unaligned(s->eh.h_proto, (u16 *) __skb_put(nskb, 2));
 		break;
 
 	case BNEP_COMPRESSED_DST_ONLY:
@@ -354,7 +356,7 @@
 
 	case BNEP_GENERAL:
 		memcpy(__skb_put(nskb, ETH_ALEN * 2), skb->mac.raw, ETH_ALEN * 2);
-		put_unaligned(s->eh.h_proto, (__u16 *) __skb_put(nskb, 2));
+		put_unaligned(s->eh.h_proto, (u16 *) __skb_put(nskb, 2));
 		break;
 	}
 
@@ -374,7 +376,7 @@
 	return 0;
 }
 
-static __u8 __bnep_tx_types[] = {
+static u8 __bnep_tx_types[] = {
 	BNEP_GENERAL,
 	BNEP_COMPRESSED_SRC_ONLY,
 	BNEP_COMPRESSED_DST_ONLY,
@@ -387,7 +389,7 @@
 	struct socket *sock = s->sock;
 	struct iovec iv[3];
 	int len = 0, il = 0;
-	__u8 type = 0;
+	u8 type = 0;
 
 	BT_DBG("skb %p dev %p type %d", skb, skb->dev, skb->pkt_type);
 
@@ -503,11 +505,11 @@
 	return 0;
 }
 
-int bnep_add_connection(struct bnep_conadd_req *req, struct socket *sock)
+int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
 {
 	struct net_device *dev;
 	struct bnep_session *s, *ss;
-	__u8 dst[ETH_ALEN], src[ETH_ALEN];
+	u8 dst[ETH_ALEN], src[ETH_ALEN];
 	int err;
 
 	BT_DBG("");
@@ -535,6 +537,8 @@
 	else
 		strcpy(dev->name, "bnep%d");
 
+	memset(dev->broadcast, 0xff, ETH_ALEN);
+
 	/* This is rx header therefor addresses are swaped.
 	 * ie eh.h_dest is our local address. */
 	memcpy(s->eh.h_dest,   &src, ETH_ALEN);
@@ -546,12 +550,12 @@
 	
 	s->msg.msg_flags = MSG_NOSIGNAL;
 
-#ifdef CONFIG_BNEP_MC_FILTER
+#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
 	/* Set default mc filter */
 	set_bit(bnep_mc_hash(dev->broadcast), &s->mc_filter);
 #endif
 	
-#ifdef CONFIG_BNEP_PROTO_FILTER
+#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER
 	/* Set default protocol filter */
 
 	/* (IPv4, ARP)  */
@@ -592,7 +596,7 @@
 	return err;
 }
 
-int bnep_del_connection(struct bnep_condel_req *req)
+int bnep_del_connection(struct bnep_conndel_req *req)
 {
 	struct bnep_session *s;
 	int  err = 0;
@@ -617,7 +621,7 @@
 	return err;
 }
 
-static void __bnep_copy_ci(struct bnep_coninfo *ci, struct bnep_session *s)
+static void __bnep_copy_ci(struct bnep_conninfo *ci, struct bnep_session *s)
 {
 	memcpy(ci->dst, s->eh.h_source, ETH_ALEN);
 	strcpy(ci->device, s->dev.name);
@@ -626,7 +630,7 @@
 	ci->role  = s->role;
 }
 
-int bnep_get_conlist(struct bnep_conlist_req *req)
+int bnep_get_connlist(struct bnep_connlist_req *req)
 {
 	struct list_head *p;
 	int err = 0, n = 0;
@@ -635,7 +639,7 @@
 
 	list_for_each(p, &bnep_session_list) {
 		struct bnep_session *s;
-		struct bnep_coninfo ci;
+		struct bnep_conninfo ci;
 
 		s = list_entry(p, struct bnep_session, list);
 
@@ -657,7 +661,7 @@
 	return err;
 }
 
-int bnep_get_coninfo(struct bnep_coninfo *ci)
+int bnep_get_conninfo(struct bnep_conninfo *ci)
 {
 	struct bnep_session *s;
 	int err = 0;
@@ -676,17 +680,14 @@
 
 static int __init bnep_init_module(void)
 {
-	BT_INFO("BNEP: BNEP2 ver %s\n"
-		"BNEP: Copyright (C) 2002 Inventel\n"
-		"BNEP: Written 2001,2002 by\n"
-		"BNEP: \tClement Moreau <clement.moreau@inventel.fr> "
-			"David Libault <david.libault@inventel.fr>\n"
-		"BNEP: Copyright (C) 2002 Maxim Krasnyanskiy <maxk@qualcomm.com>",
-			VERSION);
-
+	bnep_crc32_init();
 	bnep_sock_init();
 
-	bnep_crc32_init();
+	BT_INFO("BlueZ BNEP ver %s", VERSION);
+	BT_INFO("Copyright (C) 2001,2002 Inventel Systemes");
+	BT_INFO("Written 2001,2002 by Clement Moreau <clement.moreau@inventel.fr>");
+	BT_INFO("Written 2001,2002 by David Libault <david.libault@inventel.fr>");
+	BT_INFO("Copyright (C) 2002 Maxim Krasnyanskiy <maxk@qualcomm.com>");
 
 	return 0;
 }
@@ -694,13 +695,12 @@
 static void __exit bnep_cleanup_module(void)
 {
 	bnep_sock_cleanup();
-
 	bnep_crc32_cleanup();
 }
 
 module_init(bnep_init_module);
 module_exit(bnep_cleanup_module);
 
-MODULE_DESCRIPTION("BNEP2 ver " VERSION);
-MODULE_AUTHOR("David Libault <david.libault@inventel.fr> Maxim Krasnyanskiy <maxk@qualcomm.com>");
+MODULE_DESCRIPTION("BlueZ BNEP ver " VERSION);
+MODULE_AUTHOR("David Libault <david.libault@inventel.fr>, Maxim Krasnyanskiy <maxk@qualcomm.com>");
 MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/bluetooth/bnep/netdev.c linux-2.4.21-pre6/net/bluetooth/bnep/netdev.c
--- linux-2.4.20/net/bluetooth/bnep/netdev.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/bluetooth/bnep/netdev.c	2003-03-26 23:49:40.000000000 +0000
@@ -46,7 +46,7 @@
 
 #include "bnep.h"
 
-#ifndef CONFIG_BNEP_DEBUG
+#ifndef CONFIG_BLUEZ_BNEP_DEBUG
 #undef  BT_DBG
 #define BT_DBG( A... )
 #endif
@@ -73,7 +73,7 @@
 
 static void bnep_net_set_mc_list(struct net_device *dev)
 {
-#ifdef CONFIG_BNEP_MC_FILTER
+#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
 	struct bnep_session *s = dev->priv;
 	struct sock *sk = s->sock->sk;
 	struct bnep_set_filter_req *r;
@@ -143,27 +143,31 @@
 	return -EINVAL;
 }
 
-#ifdef CONFIG_BNEP_MC_FILTER
+#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
 static inline int bnep_net_mc_filter(struct sk_buff *skb, struct bnep_session *s)
 {
 	struct ethhdr *eh = (void *) skb->data;
 
-	if ((eh->h_dest[0] & 1) && !test_bit(bnep_mc_hash(eh->h_dest), &s->mc_filter))
+	if ((eh->h_dest[0] & 1) && !test_bit(bnep_mc_hash(eh->h_dest), &s->mc_filter)) {
+		BT_DBG("BNEP: filtered skb %p, dst %.2x:%.2x:%.2x:%.2x:%.2x:%.2x", skb, 
+				eh->h_dest[0], eh->h_dest[1], eh->h_dest[2],
+				eh->h_dest[3], eh->h_dest[4], eh->h_dest[5]);
 		return 1;
+	}
 	return 0;
 }
 #endif
 
-#ifdef CONFIG_BNEP_PROTO_FILTER
+#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER
 /* Determine ether protocol. Based on eth_type_trans. */
-static inline __u16 bnep_net_eth_proto(struct sk_buff *skb)
+static inline u16 bnep_net_eth_proto(struct sk_buff *skb)
 {
 	struct ethhdr *eh = (void *) skb->data;
 	
 	if (ntohs(eh->h_proto) >= 1536)
 		return eh->h_proto;
 		
-	if (get_unaligned((__u16 *) skb->data) == 0xFFFF)
+	if (get_unaligned((u16 *) skb->data) == 0xFFFF)
 		return htons(ETH_P_802_3);
 		
 	return htons(ETH_P_802_2);
@@ -171,7 +175,7 @@
 
 static inline int bnep_net_proto_filter(struct sk_buff *skb, struct bnep_session *s)
 {
-	__u16 proto = bnep_net_eth_proto(skb);
+	u16 proto = bnep_net_eth_proto(skb);
 	struct bnep_proto_filter *f = s->proto_filter;
 	int i;
 	
@@ -192,14 +196,14 @@
 
 	BT_DBG("skb %p, dev %p", skb, dev);
 
-#ifdef CONFIG_BNEP_MC_FILTER
+#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
 	if (bnep_net_mc_filter(skb, s)) {
 		kfree_skb(skb);
 		return 0;
 	}
 #endif
 	
-#ifdef CONFIG_BNEP_PROTO_FILTER
+#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER
 	if (bnep_net_proto_filter(skb, s)) {
 		kfree_skb(skb);
 		return 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/bluetooth/bnep/sock.c linux-2.4.21-pre6/net/bluetooth/bnep/sock.c
--- linux-2.4.20/net/bluetooth/bnep/sock.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/bluetooth/bnep/sock.c	2003-03-26 23:49:40.000000000 +0000
@@ -50,7 +50,7 @@
 
 #include "bnep.h"
 
-#ifndef CONFIG_BNEP_DEBUG
+#ifndef CONFIG_BLUEZ_BNEP_DEBUG
 #undef  BT_DBG
 #define BT_DBG( A... )
 #endif
@@ -103,17 +103,17 @@
 
 static int bnep_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
-	struct bnep_conlist_req cl;
-	struct bnep_conadd_req  ca;
-	struct bnep_condel_req  cd;
-	struct bnep_coninfo ci;
+	struct bnep_connlist_req cl;
+	struct bnep_connadd_req  ca;
+	struct bnep_conndel_req  cd;
+	struct bnep_conninfo ci;
 	struct socket *nsock;
 	int err;
 
 	BT_DBG("cmd %x arg %lx", cmd, arg);
 
 	switch (cmd) {
-	case BNEPCONADD:
+	case BNEPCONNADD:
 		if (!capable(CAP_NET_ADMIN))
 			return -EACCES;
 
@@ -136,7 +136,7 @@
 
 		return err;
 	
-	case BNEPCONDEL:
+	case BNEPCONNDEL:
 		if (!capable(CAP_NET_ADMIN))
 			return -EACCES;
 
@@ -145,24 +145,24 @@
 	
 		return bnep_del_connection(&cd);
 
-	case BNEPGETCONLIST:
+	case BNEPGETCONNLIST:
 		if (copy_from_user(&cl, (void *) arg, sizeof(cl)))
 			return -EFAULT;
 
 		if (cl.cnum <= 0)
 			return -EINVAL;
 	
-		err = bnep_get_conlist(&cl);
+		err = bnep_get_connlist(&cl);
 		if (!err && copy_to_user((void *) arg, &cl, sizeof(cl)))
 			return -EFAULT;
 
 		return err;
 
-	case BNEPGETCONINFO:
+	case BNEPGETCONNINFO:
 		if (copy_from_user(&ci, (void *) arg, sizeof(ci)))
 			return -EFAULT;
 
-		err = bnep_get_coninfo(&ci);
+		err = bnep_get_conninfo(&ci);
 		if (!err && copy_to_user((void *) arg, &ci, sizeof(ci)))
 			return -EFAULT;
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/bluetooth/hci_core.c linux-2.4.21-pre6/net/bluetooth/hci_core.c
--- linux-2.4.20/net/bluetooth/hci_core.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/bluetooth/hci_core.c	2003-03-26 23:49:19.000000000 +0000
@@ -717,7 +717,7 @@
 	if (!dev_num)
 		return -EINVAL;
 	
-	size = dev_num * sizeof(struct hci_dev_req) + sizeof(__u16);
+	size = dev_num * sizeof(*dr) + sizeof(*dl);
 
 	if (verify_area(VERIFY_WRITE, (void *) arg, size))
 		return -EFAULT;
@@ -738,7 +738,7 @@
 	read_unlock_bh(&hdev_list_lock);
 
 	dl->dev_num = n;
-	size = n * sizeof(struct hci_dev_req) + sizeof(__u16);
+	size = n * sizeof(*dr) + sizeof(*dl);
 
 	copy_to_user((void *) arg, dl, size);
 	kfree(dl);
@@ -864,6 +864,22 @@
 	return 0;
 }
 
+/* Suspend HCI device */
+int hci_suspend_dev(struct hci_dev *hdev)
+{
+	hci_notify(hdev, HCI_DEV_SUSPEND);
+	hci_run_hotplug(hdev->name, "suspend");
+	return 0;
+}
+
+/* Resume HCI device */
+int hci_resume_dev(struct hci_dev *hdev)
+{
+	hci_notify(hdev, HCI_DEV_RESUME);
+	hci_run_hotplug(hdev->name, "resume");
+	return 0;
+}       
+
 /* Receive frame from HCI drivers */
 int hci_recv_frame(struct sk_buff *skb)
 {
@@ -959,40 +975,6 @@
 	return hdev->send(skb);
 }
 
-/* Send raw HCI frame */
-int hci_send_raw(struct sk_buff *skb)
-{
-	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
-
-	if (!hdev) {
-		kfree_skb(skb);
-		return -ENODEV;
-	}
-
-	BT_DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
-
-	if (!test_bit(HCI_RAW, &hdev->flags)) {
-		/* Queue frame according it's type */
-		switch (skb->pkt_type) {
-		case HCI_COMMAND_PKT:
-			skb_queue_tail(&hdev->cmd_q, skb);
-			hci_sched_cmd(hdev);
-			return 0;
-
-		case HCI_ACLDATA_PKT:
-		case HCI_SCODATA_PKT:
-			/* FIXME:
-		 	 * Check header here and queue to apropriate connection.
-		 	 */
-			break;
-		}
-	}
-
-	skb_queue_tail(&hdev->raw_q, skb);
-	hci_sched_tx(hdev);
-	return 0;
-}
-
 /* Send HCI command */
 int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *param)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/bluetooth/hci_sock.c linux-2.4.21-pre6/net/bluetooth/hci_sock.c
--- linux-2.4.20/net/bluetooth/hci_sock.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/bluetooth/hci_sock.c	2003-03-26 23:48:58.000000000 +0000
@@ -49,6 +49,7 @@
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
+#include <asm/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
@@ -68,14 +69,17 @@
 	{ 0xd9fe, 0x0 },
 	/* Commands */
 	{
+		{ 0x0 },
 		/* OGF_LINK_CTL */
-		{ 0x2a000002, 0x0, 0x0, 0x0 },
+		{ 0x2a000002, 0x0, 0x0, 0x0  },
 		/* OGF_LINK_POLICY */
-		{ 0x1200, 0x0, 0x0, 0x0     },
+		{ 0x1200, 0x0, 0x0, 0x0      },
 		/* OGF_HOST_CTL */
-		{ 0x80100000, 0xa, 0x0, 0x0 },
+		{ 0x80100000, 0x2a, 0x0, 0x0 },
 		/* OGF_INFO_PARAM */
-		{ 0x22a, 0x0, 0x0, 0x0      }
+		{ 0x22a, 0x0, 0x0, 0x0       },
+		/* OGF_STATUS_PARAM */
+		{ 0x2e, 0x0, 0x0, 0x0        }
 	}
 };
 
@@ -387,25 +391,37 @@
 
 	skb->pkt_type = *((unsigned char *) skb->data);
 	skb_pull(skb, 1);
+	skb->dev = (void *) hdev;
 
-	if (!capable(CAP_NET_RAW)) {
-		err = -EPERM;
+	if (skb->pkt_type == HCI_COMMAND_PKT) {
+		u16 opcode = __le16_to_cpu(get_unaligned((u16 *)skb->data));
+		u16 ogf = cmd_opcode_ogf(opcode);
+		u16 ocf = cmd_opcode_ocf(opcode);
+
+		if (((ogf > HCI_SFLT_MAX_OGF) || 
+				!hci_test_bit(ocf & HCI_FLT_OCF_BITS, &hci_sec_filter.ocf_mask[ogf])) &&
+		    			!capable(CAP_NET_RAW)) {
+			err = -EPERM;
+			goto drop;
+		}
 
-		if (skb->pkt_type == HCI_COMMAND_PKT) {
-			__u16 opcode = __le16_to_cpu(*(__u16 *)skb->data);
-			__u16 ogf = cmd_opcode_ogf(opcode) - 1;
-			__u16 ocf = cmd_opcode_ocf(opcode) & HCI_FLT_OCF_BITS;
-
-			if (ogf > HCI_SFLT_MAX_OGF ||
-					!hci_test_bit(ocf, &hci_sec_filter.ocf_mask[ogf]))
-				goto drop;
-		} else
+		if (test_bit(HCI_RAW, &hdev->flags) || (ogf == OGF_VENDOR_CMD)) {
+			skb_queue_tail(&hdev->raw_q, skb);
+			hci_sched_tx(hdev);
+		} else {
+			skb_queue_tail(&hdev->cmd_q, skb);
+			hci_sched_cmd(hdev);
+		}
+	} else {
+		if (!capable(CAP_NET_RAW)) {
+			err = -EPERM;
 			goto drop;
+		}
+
+		skb_queue_tail(&hdev->raw_q, skb);
+		hci_sched_tx(hdev);
 	}
-		
-	/* Send frame to HCI core */
-	skb->dev = (void *) hdev;
-	hci_send_raw(skb);
+
 	err = len;
 
 done:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/bluetooth/l2cap.c linux-2.4.21-pre6/net/bluetooth/l2cap.c
--- linux-2.4.20/net/bluetooth/l2cap.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/bluetooth/l2cap.c	2003-03-26 23:49:34.000000000 +0000
@@ -178,69 +178,12 @@
 	return 0;
 }
 
-int l2cap_connect(struct sock *sk)
-{
-	bdaddr_t *src = &bluez_pi(sk)->src;
-	bdaddr_t *dst = &bluez_pi(sk)->dst;
-	struct l2cap_conn *conn;
-	struct hci_conn   *hcon;
-	struct hci_dev    *hdev;
-	int err = 0;
-
-	BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), l2cap_pi(sk)->psm);
-
-	if (!(hdev = hci_get_route(dst, src)))
-		return -EHOSTUNREACH;
-
-	hci_dev_lock_bh(hdev);
-
-	err = -ENOMEM;
-
-	hcon = hci_connect(hdev, ACL_LINK, dst);
-	if (!hcon)
-		goto done;
-
-	conn = l2cap_conn_add(hcon, 0);
-	if (!conn) {
-		hci_conn_put(hcon);
-		goto done;
-	}
-
-	err = 0;
-
-	/* Update source addr of the socket */
-	bacpy(src, conn->src);
-
-	l2cap_chan_add(conn, sk, NULL);
-
-	sk->state = BT_CONNECT;
-	l2cap_sock_set_timer(sk, sk->sndtimeo);
-
-	if (hcon->state == BT_CONNECTED) {
-		if (sk->type == SOCK_SEQPACKET) {
-			l2cap_conn_req req;
-			req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
-			req.psm  = l2cap_pi(sk)->psm;
-			l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req);
-		} else {
-			l2cap_sock_clear_timer(sk);
-			sk->state = BT_CONNECTED;
-		}
-	}
-
-done:
-	hci_dev_unlock_bh(hdev);
-	hci_dev_put(hdev);
-	return err;
-}
-
 /* -------- Socket interface ---------- */
 static struct sock *__l2cap_get_sock_by_addr(__u16 psm, bdaddr_t *src)
 {
 	struct sock *sk;
 	for (sk = l2cap_sk_list.head; sk; sk = sk->next) {
-		if (l2cap_pi(sk)->psm == psm &&
-				!bacmp(&bluez_pi(sk)->src, src))
+		if (sk->sport == psm && !bacmp(&bluez_pi(sk)->src, src))
 			break;
 	}
 	return sk;
@@ -432,6 +375,9 @@
 	if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_DGRAM && sock->type != SOCK_RAW)
 		return -ESOCKTNOSUPPORT;
 
+	if (sock->type == SOCK_RAW && !capable(CAP_NET_RAW))
+		return -EPERM;
+	
 	sock->ops = &l2cap_sock_ops;
 
 	if (!(sk = l2cap_sock_alloc(sock, protocol, GFP_KERNEL)))
@@ -466,9 +412,9 @@
 		/* Save source address */
 		bacpy(&bluez_pi(sk)->src, &la->l2_bdaddr);
 		l2cap_pi(sk)->psm = la->l2_psm;
+		sk->sport = la->l2_psm;
 		sk->state = BT_BOUND;
 	}
-
 	write_unlock_bh(&l2cap_sk_list.lock);
 
 done:
@@ -476,6 +422,62 @@
 	return err;
 }
 
+static int l2cap_do_connect(struct sock *sk)
+{
+	bdaddr_t *src = &bluez_pi(sk)->src;
+	bdaddr_t *dst = &bluez_pi(sk)->dst;
+	struct l2cap_conn *conn;
+	struct hci_conn   *hcon;
+	struct hci_dev    *hdev;
+	int err = 0;
+
+	BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), l2cap_pi(sk)->psm);
+
+	if (!(hdev = hci_get_route(dst, src)))
+		return -EHOSTUNREACH;
+
+	hci_dev_lock_bh(hdev);
+
+	err = -ENOMEM;
+
+	hcon = hci_connect(hdev, ACL_LINK, dst);
+	if (!hcon)
+		goto done;
+
+	conn = l2cap_conn_add(hcon, 0);
+	if (!conn) {
+		hci_conn_put(hcon);
+		goto done;
+	}
+
+	err = 0;
+
+	/* Update source addr of the socket */
+	bacpy(src, conn->src);
+
+	l2cap_chan_add(conn, sk, NULL);
+
+	sk->state = BT_CONNECT;
+	l2cap_sock_set_timer(sk, sk->sndtimeo);
+
+	if (hcon->state == BT_CONNECTED) {
+		if (sk->type == SOCK_SEQPACKET) {
+			l2cap_conn_req req;
+			req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
+			req.psm  = l2cap_pi(sk)->psm;
+			l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req);
+		} else {
+			l2cap_sock_clear_timer(sk);
+			sk->state = BT_CONNECTED;
+		}
+	}
+
+done:
+	hci_dev_unlock_bh(hdev);
+	hci_dev_put(hdev);
+	return err;
+}
+
 static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
 {
 	struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
@@ -521,7 +523,7 @@
 	bacpy(&bluez_pi(sk)->dst, &la->l2_bdaddr);
 	l2cap_pi(sk)->psm = la->l2_psm;
 
-	if ((err = l2cap_connect(sk)))
+	if ((err = l2cap_do_connect(sk)))
 		goto done;
 
 wait:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/bluetooth/rfcomm/Config.in linux-2.4.21-pre6/net/bluetooth/rfcomm/Config.in
--- linux-2.4.20/net/bluetooth/rfcomm/Config.in	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/net/bluetooth/rfcomm/Config.in	2003-03-26 23:49:17.000000000 +0000
@@ -0,0 +1,10 @@
+#
+# Bluetooth RFCOMM layer configuration
+#
+
+dep_tristate 'RFCOMM protocol support' CONFIG_BLUEZ_RFCOMM $CONFIG_BLUEZ_L2CAP
+
+if [ "$CONFIG_BLUEZ_RFCOMM" != "n" ]; then
+   bool '  RFCOMM TTY support' CONFIG_BLUEZ_RFCOMM_TTY
+fi
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/bluetooth/rfcomm/Makefile linux-2.4.21-pre6/net/bluetooth/rfcomm/Makefile
--- linux-2.4.20/net/bluetooth/rfcomm/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/net/bluetooth/rfcomm/Makefile	2003-03-26 23:49:54.000000000 +0000
@@ -0,0 +1,11 @@
+#
+# Makefile for the Linux Bluetooth RFCOMM layer
+#
+
+O_TARGET := rfcomm.o
+
+obj-y				:= core.o sock.o crc.o
+obj-$(CONFIG_BLUEZ_RFCOMM_TTY)	+= tty.o
+obj-m				+= $(O_TARGET)
+
+include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/bluetooth/rfcomm/core.c linux-2.4.21-pre6/net/bluetooth/rfcomm/core.c
--- linux-2.4.20/net/bluetooth/rfcomm/core.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/net/bluetooth/rfcomm/core.c	2003-03-26 23:49:50.000000000 +0000
@@ -0,0 +1,1806 @@
+/* 
+   RFCOMM implementation for Linux Bluetooth stack (BlueZ).
+   Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
+   Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/* 
+   RPN support    -    Dirk Husemann <hud@zurich.ibm.com>
+*/
+
+/*
+ * RFCOMM core.
+ *
+ * $Id: core.c,v 1.46 2002/10/18 20:12:12 maxk Exp $
+ */
+
+#define __KERNEL_SYSCALLS__
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/net.h>
+#include <linux/proc_fs.h>
+#include <net/sock.h>
+#include <asm/uaccess.h>
+#include <asm/unaligned.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/l2cap.h>
+#include <net/bluetooth/rfcomm.h>
+
+#define VERSION "0.4"
+
+#ifndef CONFIG_BLUEZ_RFCOMM_DEBUG
+#undef  BT_DBG
+#define BT_DBG(D...)
+#endif
+
+struct task_struct *rfcomm_thread;
+DECLARE_MUTEX(rfcomm_sem);
+unsigned long rfcomm_event;
+
+static LIST_HEAD(session_list);
+static atomic_t terminate, running;
+
+static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len);
+static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci);
+static int rfcomm_send_disc(struct rfcomm_session *s, u8 dlci);
+static int rfcomm_queue_disc(struct rfcomm_dlc *d);
+static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type);
+static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d);
+static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig);
+static int rfcomm_send_test(struct rfcomm_session *s, int cr, u8 *pattern, int len);
+static int rfcomm_send_credits(struct rfcomm_session *s, u8 addr, u8 credits);
+static void rfcomm_make_uih(struct sk_buff *skb, u8 addr);
+
+static void rfcomm_process_connect(struct rfcomm_session *s);
+
+/* ---- RFCOMM frame parsing macros ---- */
+#define __get_dlci(b)     ((b & 0xfc) >> 2)
+#define __get_channel(b)  ((b & 0xf8) >> 3)
+#define __get_dir(b)      ((b & 0x04) >> 2)
+#define __get_type(b)     ((b & 0xef))
+
+#define __test_ea(b)      ((b & 0x01))
+#define __test_cr(b)      ((b & 0x02))
+#define __test_pf(b)      ((b & 0x10))
+
+#define __addr(cr, dlci)       (((dlci & 0x3f) << 2) | (cr << 1) | 0x01)
+#define __ctrl(type, pf)       (((type & 0xef) | (pf << 4)))
+#define __dlci(dir, chn)       (((chn & 0x1f) << 1) | dir)
+#define __srv_channel(dlci)    (dlci >> 1)
+#define __dir(dlci)            (dlci & 0x01)
+
+#define __len8(len)       (((len) << 1) | 1)
+#define __len16(len)      ((len) << 1)
+
+/* MCC macros */
+#define __mcc_type(cr, type)   (((type << 2) | (cr << 1) | 0x01))
+#define __get_mcc_type(b) ((b & 0xfc) >> 2)
+#define __get_mcc_len(b)  ((b & 0xfe) >> 1)
+
+/* RPN macros */
+#define __rpn_line_settings(data, stop, parity)  ((data & 0x3) | ((stop & 0x1) << 2) | ((parity & 0x3) << 3))
+#define __get_rpn_data_bits(line) ((line) & 0x3)
+#define __get_rpn_stop_bits(line) (((line) >> 2) & 0x1)
+#define __get_rpn_parity(line)    (((line) >> 3) & 0x3)
+
+/* ---- RFCOMM FCS computation ---- */
+
+/* CRC on 2 bytes */
+#define __crc(data) (rfcomm_crc_table[rfcomm_crc_table[0xff ^ data[0]] ^ data[1]])
+
+/* FCS on 2 bytes */ 
+static inline u8 __fcs(u8 *data)
+{
+	return (0xff - __crc(data));
+}
+
+/* FCS on 3 bytes */ 
+static inline u8 __fcs2(u8 *data)
+{
+	return (0xff - rfcomm_crc_table[__crc(data) ^ data[2]]);
+}
+
+/* Check FCS */
+static inline int __check_fcs(u8 *data, int type, u8 fcs)
+{
+	u8 f = __crc(data);
+
+	if (type != RFCOMM_UIH)
+		f = rfcomm_crc_table[f ^ data[2]];
+
+	return rfcomm_crc_table[f ^ fcs] != 0xcf;
+}
+
+/* ---- L2CAP callbacks ---- */
+static void rfcomm_l2state_change(struct sock *sk)
+{
+	BT_DBG("%p state %d", sk, sk->state);
+	rfcomm_schedule(RFCOMM_SCHED_STATE);
+}
+
+static void rfcomm_l2data_ready(struct sock *sk, int bytes)
+{
+	BT_DBG("%p bytes %d", sk, bytes);
+	rfcomm_schedule(RFCOMM_SCHED_RX);
+}
+
+static int rfcomm_l2sock_create(struct socket **sock)
+{
+	int err;
+
+	BT_DBG("");
+
+	err = sock_create(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP, sock);
+	if (!err) {
+		struct sock *sk = (*sock)->sk;
+		sk->data_ready   = rfcomm_l2data_ready;
+		sk->state_change = rfcomm_l2state_change;
+	}
+	return err;
+}
+
+/* ---- RFCOMM DLCs ---- */
+static void rfcomm_dlc_timeout(unsigned long arg)
+{
+	struct rfcomm_dlc *d = (void *) arg;
+
+	BT_DBG("dlc %p state %ld", d, d->state);
+
+	set_bit(RFCOMM_TIMED_OUT, &d->flags);
+	rfcomm_dlc_put(d);
+	rfcomm_schedule(RFCOMM_SCHED_TIMEO);
+}
+
+static void rfcomm_dlc_set_timer(struct rfcomm_dlc *d, long timeout)
+{
+	BT_DBG("dlc %p state %ld timeout %ld", d, d->state, timeout);
+
+	if (!mod_timer(&d->timer, jiffies + timeout))
+		rfcomm_dlc_hold(d);
+}
+
+static void rfcomm_dlc_clear_timer(struct rfcomm_dlc *d)
+{
+	BT_DBG("dlc %p state %ld", d, d->state);
+
+	if (timer_pending(&d->timer) && del_timer(&d->timer))
+		rfcomm_dlc_put(d);
+}
+
+static void rfcomm_dlc_clear_state(struct rfcomm_dlc *d)
+{
+	BT_DBG("%p", d);
+
+	d->state      = BT_OPEN;
+	d->flags      = 0;
+	d->mtu        = RFCOMM_DEFAULT_MTU;
+	d->v24_sig    = RFCOMM_V24_RTC | RFCOMM_V24_RTR | RFCOMM_V24_DV;
+
+	d->credits    = RFCOMM_MAX_CREDITS;
+	d->rx_credits = RFCOMM_DEFAULT_CREDITS;
+}
+
+struct rfcomm_dlc *rfcomm_dlc_alloc(int prio)
+{
+	struct rfcomm_dlc *d = kmalloc(sizeof(*d), prio);
+	if (!d)
+		return NULL;
+	memset(d, 0, sizeof(*d));
+
+	init_timer(&d->timer);
+	d->timer.function = rfcomm_dlc_timeout;
+	d->timer.data = (unsigned long) d;
+
+	skb_queue_head_init(&d->tx_queue);
+	spin_lock_init(&d->lock);
+	atomic_set(&d->refcnt, 1);
+
+	rfcomm_dlc_clear_state(d);
+	
+	BT_DBG("%p", d);
+	return d;
+}
+
+void rfcomm_dlc_free(struct rfcomm_dlc *d)
+{
+	BT_DBG("%p", d);
+
+	skb_queue_purge(&d->tx_queue);
+	kfree(d);
+}
+
+static void rfcomm_dlc_link(struct rfcomm_session *s, struct rfcomm_dlc *d)
+{
+	BT_DBG("dlc %p session %p", d, s);
+
+	rfcomm_session_hold(s);
+
+	rfcomm_dlc_hold(d);
+	list_add(&d->list, &s->dlcs);
+	d->session = s;
+}
+
+static void rfcomm_dlc_unlink(struct rfcomm_dlc *d)
+{
+	struct rfcomm_session *s = d->session;
+
+	BT_DBG("dlc %p refcnt %d session %p", d, atomic_read(&d->refcnt), s);
+
+	list_del(&d->list);
+	d->session = NULL;
+	rfcomm_dlc_put(d);
+
+	rfcomm_session_put(s);
+}
+
+static struct rfcomm_dlc *rfcomm_dlc_get(struct rfcomm_session *s, u8 dlci)
+{
+	struct rfcomm_dlc *d;
+	struct list_head *p;
+
+	list_for_each(p, &s->dlcs) {
+		d = list_entry(p, struct rfcomm_dlc, list);
+		if (d->dlci == dlci)
+			return d;
+	}
+	return NULL;
+}
+
+static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel)
+{
+	struct rfcomm_session *s;
+	u8 dlci = __dlci(0, channel);
+	int err = 0;
+
+	BT_DBG("dlc %p state %ld %s %s channel %d dlci %d", 
+			d, d->state, batostr(src), batostr(dst), channel, dlci);
+
+	if (dlci < 1 || dlci > 62)
+		return -EINVAL;
+
+	if (d->state != BT_OPEN && d->state != BT_CLOSED)
+		return 0;
+
+	s = rfcomm_session_get(src, dst);
+	if (!s) {
+		s = rfcomm_session_create(src, dst, &err);
+		if (!s)
+			return err;
+	}
+
+	/* Check if DLCI already exists */
+	if (rfcomm_dlc_get(s, dlci))
+		return -EBUSY;
+
+	rfcomm_dlc_clear_state(d);
+
+	d->dlci    = dlci;
+	d->addr    = __addr(s->initiator, dlci);
+
+	d->state   = BT_CONFIG;
+	rfcomm_dlc_link(s, d);
+
+	d->mtu     = s->mtu;
+	d->credits = s->credits;
+
+	if (s->state == BT_CONNECTED)
+		rfcomm_send_pn(s, 1, d);
+	rfcomm_dlc_set_timer(d, RFCOMM_CONN_TIMEOUT);
+	return 0;
+}
+
+int rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel)
+{
+	mm_segment_t fs;
+	int r;
+
+	rfcomm_lock();
+
+	fs = get_fs(); set_fs(KERNEL_DS);
+	r = __rfcomm_dlc_open(d, src, dst, channel);
+	set_fs(fs);
+
+	rfcomm_unlock();
+	return r;
+}
+
+static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
+{
+	struct rfcomm_session *s = d->session;
+	if (!s)
+		return 0;
+
+	BT_DBG("dlc %p state %ld dlci %d err %d session %p",
+			d, d->state, d->dlci, err, s);
+
+	switch (d->state) {
+	case BT_CONNECTED:
+	case BT_CONFIG:
+	case BT_CONNECT:
+		d->state = BT_DISCONN;
+		if (skb_queue_empty(&d->tx_queue)) {
+			rfcomm_send_disc(s, d->dlci);
+			rfcomm_dlc_set_timer(d, RFCOMM_DISC_TIMEOUT);
+		} else {
+			rfcomm_queue_disc(d);
+			rfcomm_dlc_set_timer(d, RFCOMM_DISC_TIMEOUT * 2);
+		}
+		break;
+
+	default:
+		rfcomm_dlc_clear_timer(d);
+
+		rfcomm_dlc_lock(d);
+		d->state = BT_CLOSED;
+		d->state_change(d, err);
+		rfcomm_dlc_unlock(d);
+
+		skb_queue_purge(&d->tx_queue);
+		rfcomm_dlc_unlink(d);
+	}
+
+	return 0;
+}
+
+int rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
+{
+	mm_segment_t fs;
+	int r;
+
+	rfcomm_lock();
+
+	fs = get_fs(); set_fs(KERNEL_DS);
+	r = __rfcomm_dlc_close(d, err);
+	set_fs(fs);
+
+	rfcomm_unlock();
+	return r;
+}
+
+int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb)
+{
+	int len = skb->len;
+
+	if (d->state != BT_CONNECTED)
+		return -ENOTCONN;
+
+	BT_DBG("dlc %p mtu %d len %d", d, d->mtu, len);
+
+	if (len > d->mtu)
+		return -EINVAL;
+
+	rfcomm_make_uih(skb, d->addr);
+	skb_queue_tail(&d->tx_queue, skb);
+
+	if (!test_bit(RFCOMM_TX_THROTTLED, &d->flags))
+		rfcomm_schedule(RFCOMM_SCHED_TX);
+	return len;
+}
+
+void __rfcomm_dlc_throttle(struct rfcomm_dlc *d)
+{
+	BT_DBG("dlc %p state %ld", d, d->state);
+
+	if (!d->credits) {
+		d->v24_sig |= RFCOMM_V24_FC;
+		set_bit(RFCOMM_MSC_PENDING, &d->flags);
+	}
+	rfcomm_schedule(RFCOMM_SCHED_TX);
+}
+
+void __rfcomm_dlc_unthrottle(struct rfcomm_dlc *d)
+{
+	BT_DBG("dlc %p state %ld", d, d->state);
+
+	if (!d->credits) {
+		d->v24_sig &= ~RFCOMM_V24_FC;
+		set_bit(RFCOMM_MSC_PENDING, &d->flags);
+	}
+	rfcomm_schedule(RFCOMM_SCHED_TX);
+}
+
+/* 
+   Set/get modem status functions use _local_ status i.e. what we report
+   to the other side.
+   Remote status is provided by dlc->modem_status() callback.
+ */
+int rfcomm_dlc_set_modem_status(struct rfcomm_dlc *d, u8 v24_sig)
+{
+	BT_DBG("dlc %p state %ld v24_sig 0x%x", 
+			d, d->state, v24_sig);
+
+	if (test_bit(RFCOMM_RX_THROTTLED, &d->flags))
+		v24_sig |= RFCOMM_V24_FC;
+	else
+		v24_sig &= ~RFCOMM_V24_FC;
+	
+	d->v24_sig = v24_sig;
+
+	if (!test_and_set_bit(RFCOMM_MSC_PENDING, &d->flags))
+		rfcomm_schedule(RFCOMM_SCHED_TX);
+
+	return 0;
+}
+
+int rfcomm_dlc_get_modem_status(struct rfcomm_dlc *d, u8 *v24_sig)
+{
+	BT_DBG("dlc %p state %ld v24_sig 0x%x", 
+			d, d->state, d->v24_sig);
+
+	*v24_sig = d->v24_sig;
+	return 0;
+}
+
+/* ---- RFCOMM sessions ---- */
+struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state)
+{
+	struct rfcomm_session *s = kmalloc(sizeof(*s), GFP_KERNEL);
+	if (!s)
+		return NULL;
+	memset(s, 0, sizeof(*s));
+	
+	BT_DBG("session %p sock %p", s, sock);
+
+	INIT_LIST_HEAD(&s->dlcs);
+	s->state = state;
+	s->sock  = sock;
+
+	s->mtu     = RFCOMM_DEFAULT_MTU;
+	s->credits = RFCOMM_MAX_CREDITS;
+	
+	list_add(&s->list, &session_list);
+
+	/* Do not increment module usage count for listeting sessions.
+	 * Otherwise we won't be able to unload the module. */
+	if (state != BT_LISTEN)
+		MOD_INC_USE_COUNT;
+	return s;
+}
+
+void rfcomm_session_del(struct rfcomm_session *s)
+{
+	int state = s->state;
+	
+	BT_DBG("session %p state %ld", s, s->state);
+
+	list_del(&s->list);
+
+	if (state == BT_CONNECTED)
+		rfcomm_send_disc(s, 0);
+
+	sock_release(s->sock);
+	kfree(s);
+
+	if (state != BT_LISTEN)
+		MOD_DEC_USE_COUNT;
+}
+
+struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst)
+{
+	struct rfcomm_session *s;
+	struct list_head *p, *n;
+	struct bluez_pinfo *pi;
+	list_for_each_safe(p, n, &session_list) {
+		s = list_entry(p, struct rfcomm_session, list);
+		pi = bluez_pi(s->sock->sk); 
+
+		if ((!bacmp(src, BDADDR_ANY) || !bacmp(&pi->src, src)) &&
+				!bacmp(&pi->dst, dst))
+			return s;
+	}
+	return NULL;
+}
+
+void rfcomm_session_close(struct rfcomm_session *s, int err)
+{
+	struct rfcomm_dlc *d;
+	struct list_head *p, *n;
+
+	BT_DBG("session %p state %ld err %d", s, s->state, err);
+
+	rfcomm_session_hold(s);
+
+	s->state = BT_CLOSED;
+
+	/* Close all dlcs */
+	list_for_each_safe(p, n, &s->dlcs) {
+		d = list_entry(p, struct rfcomm_dlc, list);
+		d->state = BT_CLOSED;
+		__rfcomm_dlc_close(d, err);
+	}
+
+	rfcomm_session_put(s);
+}
+
+struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst, int *err)
+{
+	struct rfcomm_session *s = NULL;
+	struct sockaddr_l2 addr;
+	struct l2cap_options opts;
+	struct socket *sock;
+	int    size;
+
+	BT_DBG("%s %s", batostr(src), batostr(dst));
+
+	*err = rfcomm_l2sock_create(&sock);
+	if (*err < 0)
+		return NULL;
+
+	bacpy(&addr.l2_bdaddr, src);
+	addr.l2_family = AF_BLUETOOTH;
+	addr.l2_psm    = 0;
+	*err = sock->ops->bind(sock, (struct sockaddr *) &addr, sizeof(addr));
+	if (*err < 0)
+		goto failed;
+
+	/* Set L2CAP options */
+	size = sizeof(opts);
+	sock->ops->getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, &size);
+	
+	opts.imtu = RFCOMM_MAX_L2CAP_MTU;
+	sock->ops->setsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, size);
+
+	s = rfcomm_session_add(sock, BT_BOUND);
+	if (!s) {
+		*err = -ENOMEM;
+		goto failed;
+	}
+
+	s->initiator = 1;
+
+	bacpy(&addr.l2_bdaddr, dst);
+	addr.l2_family = AF_BLUETOOTH;
+	addr.l2_psm    = htobs(RFCOMM_PSM);
+	*err = sock->ops->connect(sock, (struct sockaddr *) &addr, sizeof(addr), O_NONBLOCK);
+	if (*err == 0 || *err == -EAGAIN)
+		return s;
+
+	rfcomm_session_del(s);
+	return NULL;
+
+failed:
+	sock_release(sock);
+	return NULL;
+}
+
+void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, bdaddr_t *dst)
+{
+	struct sock *sk = s->sock->sk;
+	if (src)
+		bacpy(src, &bluez_pi(sk)->src);
+	if (dst)
+		bacpy(dst, &bluez_pi(sk)->dst);
+}
+
+/* ---- RFCOMM frame sending ---- */
+static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len)
+{
+	struct socket *sock = s->sock;
+	struct iovec iv = { data, len };
+	struct msghdr msg;
+	int err;
+
+	BT_DBG("session %p len %d", s, len);
+
+	memset(&msg, 0, sizeof(msg));
+	msg.msg_iovlen = 1;
+	msg.msg_iov = &iv;
+
+	err = sock->ops->sendmsg(sock, &msg, len, 0);
+	return err;
+}
+
+static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci)
+{
+	struct rfcomm_cmd cmd;
+
+	BT_DBG("%p dlci %d", s, dlci);
+
+	cmd.addr = __addr(s->initiator, dlci);
+	cmd.ctrl = __ctrl(RFCOMM_SABM, 1);
+	cmd.len  = __len8(0);
+	cmd.fcs  = __fcs2((u8 *) &cmd);
+
+	return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
+}
+
+static int rfcomm_send_ua(struct rfcomm_session *s, u8 dlci)
+{
+	struct rfcomm_cmd cmd;
+
+	BT_DBG("%p dlci %d", s, dlci);
+
+	cmd.addr = __addr(!s->initiator, dlci);
+	cmd.ctrl = __ctrl(RFCOMM_UA, 1);
+	cmd.len  = __len8(0);
+	cmd.fcs  = __fcs2((u8 *) &cmd);
+
+	return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
+}
+
+static int rfcomm_send_disc(struct rfcomm_session *s, u8 dlci)
+{
+	struct rfcomm_cmd cmd;
+
+	BT_DBG("%p dlci %d", s, dlci);
+
+	cmd.addr = __addr(s->initiator, dlci);
+	cmd.ctrl = __ctrl(RFCOMM_DISC, 1);
+	cmd.len  = __len8(0);
+	cmd.fcs  = __fcs2((u8 *) &cmd);
+
+	return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
+}
+
+static int rfcomm_queue_disc(struct rfcomm_dlc *d)
+{
+	struct rfcomm_cmd *cmd;
+	struct sk_buff *skb;
+
+	BT_DBG("dlc %p dlci %d", d, d->dlci);
+
+	skb = alloc_skb(sizeof(*cmd), GFP_KERNEL);
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (void *) __skb_put(skb, sizeof(*cmd));
+	cmd->addr = d->addr;
+	cmd->ctrl = __ctrl(RFCOMM_DISC, 1);
+	cmd->len  = __len8(0);
+	cmd->fcs  = __fcs2((u8 *) cmd);
+
+	skb_queue_tail(&d->tx_queue, skb);
+	rfcomm_schedule(RFCOMM_SCHED_TX);
+	return 0;
+}
+
+static int rfcomm_send_dm(struct rfcomm_session *s, u8 dlci)
+{
+	struct rfcomm_cmd cmd;
+
+	BT_DBG("%p dlci %d", s, dlci);
+
+	cmd.addr = __addr(!s->initiator, dlci);
+	cmd.ctrl = __ctrl(RFCOMM_DM, 1);
+	cmd.len  = __len8(0);
+	cmd.fcs  = __fcs2((u8 *) &cmd);
+
+	return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
+}
+
+static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type)
+{
+	struct rfcomm_hdr *hdr;
+	struct rfcomm_mcc *mcc;
+	u8 buf[16], *ptr = buf;
+
+	BT_DBG("%p cr %d type %d", s, cr, type);
+
+	hdr = (void *) ptr; ptr += sizeof(*hdr);
+	hdr->addr = __addr(s->initiator, 0);
+	hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
+	hdr->len  = __len8(sizeof(*mcc) + 1);
+
+	mcc = (void *) ptr; ptr += sizeof(*mcc);
+	mcc->type = __mcc_type(s->initiator, RFCOMM_NSC);
+	mcc->len  = __len8(1);
+
+	/* Type that we didn't like */
+	*ptr = __mcc_type(cr, type); ptr++;
+
+	*ptr = __fcs(buf); ptr++;
+
+	return rfcomm_send_frame(s, buf, ptr - buf);
+}
+
+static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d)
+{
+	struct rfcomm_hdr *hdr;
+	struct rfcomm_mcc *mcc;
+	struct rfcomm_pn  *pn;
+	u8 buf[16], *ptr = buf;
+
+	BT_DBG("%p cr %d dlci %d mtu %d", s, cr, d->dlci, d->mtu);
+
+	hdr = (void *) ptr; ptr += sizeof(*hdr);
+	hdr->addr = __addr(s->initiator, 0);
+	hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
+	hdr->len  = __len8(sizeof(*mcc) + sizeof(*pn));
+
+	mcc = (void *) ptr; ptr += sizeof(*mcc);
+	mcc->type = __mcc_type(s->initiator, RFCOMM_PN);
+	mcc->len  = __len8(sizeof(*pn));
+
+	pn = (void *) ptr; ptr += sizeof(*pn);
+	pn->dlci        = d->dlci;
+	pn->priority    = 0;
+	pn->ack_timer   = 0;
+	pn->max_retrans = 0;
+
+	if (d->credits) {
+		pn->flow_ctrl = cr ? 0xf0 : 0xe0;
+		pn->credits = RFCOMM_DEFAULT_CREDITS;
+	} else {
+		pn->flow_ctrl = 0;
+		pn->credits   = 0;
+	}
+
+	pn->mtu = htobs(d->mtu);
+
+	*ptr = __fcs(buf); ptr++;
+
+	return rfcomm_send_frame(s, buf, ptr - buf);
+}
+
+static int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci,
+			   u8 bit_rate, u8 data_bits, u8 stop_bits,
+			   u8 parity, u8 flow_ctrl_settings, 
+			   u8 xon_char, u8 xoff_char, u16 param_mask)
+{
+	struct rfcomm_hdr *hdr;
+	struct rfcomm_mcc *mcc;
+	struct rfcomm_rpn *rpn;
+	u8 buf[16], *ptr = buf;
+
+	BT_DBG("%p cr %d dlci %d bit_r 0x%x data_b 0x%x stop_b 0x%x parity 0x%x"
+	       "flwc_s 0x%x xon_c 0x%x xoff_c 0x%x p_mask 0x%x", 
+			s, cr, dlci, bit_rate, data_bits, stop_bits, parity, 
+			flow_ctrl_settings, xon_char, xoff_char, param_mask);
+
+	hdr = (void *) ptr; ptr += sizeof(*hdr);
+	hdr->addr = __addr(s->initiator, 0);
+	hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
+	hdr->len  = __len8(sizeof(*mcc) + sizeof(*rpn));
+
+	mcc = (void *) ptr; ptr += sizeof(*mcc);
+	mcc->type = __mcc_type(cr, RFCOMM_RPN);
+	mcc->len  = __len8(sizeof(*rpn));
+
+	rpn = (void *) ptr; ptr += sizeof(*rpn);
+	rpn->dlci          = __addr(1, dlci);
+	rpn->bit_rate      = bit_rate;
+	rpn->line_settings = __rpn_line_settings(data_bits, stop_bits, parity);
+	rpn->flow_ctrl     = flow_ctrl_settings;
+	rpn->xon_char      = xon_char;
+	rpn->xoff_char     = xoff_char;
+	rpn->param_mask    = param_mask;
+
+	*ptr = __fcs(buf); ptr++;
+
+	return rfcomm_send_frame(s, buf, ptr - buf);
+}
+
+static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig)
+{
+	struct rfcomm_hdr *hdr;
+	struct rfcomm_mcc *mcc;
+	struct rfcomm_msc *msc;
+	u8 buf[16], *ptr = buf;
+
+	BT_DBG("%p cr %d v24 0x%x", s, cr, v24_sig);
+
+	hdr = (void *) ptr; ptr += sizeof(*hdr);
+	hdr->addr = __addr(s->initiator, 0);
+	hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
+	hdr->len  = __len8(sizeof(*mcc) + sizeof(*msc));
+
+	mcc = (void *) ptr; ptr += sizeof(*mcc);
+	mcc->type = __mcc_type(cr, RFCOMM_MSC);
+	mcc->len  = __len8(sizeof(*msc));
+
+	msc = (void *) ptr; ptr += sizeof(*msc);
+	msc->dlci    = __addr(1, dlci);
+	msc->v24_sig = v24_sig;
+
+	*ptr = __fcs(buf); ptr++;
+
+	return rfcomm_send_frame(s, buf, ptr - buf);
+}
+
+static int rfcomm_send_test(struct rfcomm_session *s, int cr, u8 *pattern, int len)
+{
+	struct socket *sock = s->sock;
+	struct iovec iv[3];
+	struct msghdr msg;
+	unsigned char hdr[5], crc[1];
+
+	if (len > 125)
+		return -EINVAL;
+
+	BT_DBG("%p cr %d", s, cr);
+
+	hdr[0] = __addr(s->initiator, 0);
+	hdr[1] = __ctrl(RFCOMM_UIH, 0);
+	hdr[2] = 0x01 | ((len + 2) << 1);
+	hdr[3] = 0x01 | ((cr & 0x01) << 1) | (RFCOMM_TEST << 2);
+	hdr[4] = 0x01 | (len << 1);
+
+	crc[0] = __fcs(hdr);
+
+	iv[0].iov_base = hdr;
+	iv[0].iov_len  = 5;
+	iv[1].iov_base = pattern;
+	iv[1].iov_len  = len;
+	iv[2].iov_base = crc;
+	iv[2].iov_len  = 1;
+
+	memset(&msg, 0, sizeof(msg));
+	msg.msg_iovlen = 3;
+	msg.msg_iov = iv;
+	return sock->ops->sendmsg(sock, &msg, 6 + len, 0);
+}
+
+static int rfcomm_send_credits(struct rfcomm_session *s, u8 addr, u8 credits)
+{
+	struct rfcomm_hdr *hdr;
+	u8 buf[16], *ptr = buf;
+
+	BT_DBG("%p addr %d credits %d", s, addr, credits);
+
+	hdr = (void *) ptr; ptr += sizeof(*hdr);
+	hdr->addr = addr;
+	hdr->ctrl = __ctrl(RFCOMM_UIH, 1);
+	hdr->len  = __len8(0);
+
+	*ptr = credits; ptr++;
+
+	*ptr = __fcs(buf); ptr++;
+
+	return rfcomm_send_frame(s, buf, ptr - buf);
+}
+
+static void rfcomm_make_uih(struct sk_buff *skb, u8 addr)
+{
+	struct rfcomm_hdr *hdr;
+	int len = skb->len;
+	u8 *crc;
+
+	if (len > 127) {
+		hdr = (void *) skb_push(skb, 4);
+		put_unaligned(htobs(__len16(len)), (u16 *) &hdr->len);
+	} else {
+		hdr = (void *) skb_push(skb, 3);
+		hdr->len = __len8(len);
+	}
+	hdr->addr = addr;
+	hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
+
+	crc = skb_put(skb, 1);
+	*crc = __fcs((void *) hdr);
+}
+
+/* ---- RFCOMM frame reception ---- */
+static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci)
+{
+	BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
+
+	if (dlci) {
+		/* Data channel */
+		struct rfcomm_dlc *d = rfcomm_dlc_get(s, dlci);
+		if (!d) {
+			rfcomm_send_dm(s, dlci);
+			return 0;
+		}
+
+		switch (d->state) {
+		case BT_CONNECT:
+			rfcomm_dlc_clear_timer(d);
+
+			rfcomm_dlc_lock(d);
+			d->state = BT_CONNECTED;
+			d->state_change(d, 0);
+			rfcomm_dlc_unlock(d);
+
+			rfcomm_send_msc(s, 1, dlci, d->v24_sig);
+			break;
+
+		case BT_DISCONN:
+			d->state = BT_CLOSED;
+			__rfcomm_dlc_close(d, 0);
+			break;
+		}
+	} else {
+		/* Control channel */
+		switch (s->state) {
+		case BT_CONNECT:
+			s->state = BT_CONNECTED;
+			rfcomm_process_connect(s);
+			break;
+		}
+	}
+	return 0;
+}
+
+static int rfcomm_recv_dm(struct rfcomm_session *s, u8 dlci)
+{
+	int err = 0;
+
+	BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
+
+	if (dlci) {
+		/* Data DLC */
+		struct rfcomm_dlc *d = rfcomm_dlc_get(s, dlci);
+		if (d) {
+			if (d->state == BT_CONNECT || d->state == BT_CONFIG)
+				err = ECONNREFUSED;
+			else
+				err = ECONNRESET;
+
+			d->state = BT_CLOSED;
+			__rfcomm_dlc_close(d, err);
+		}
+	} else {
+		if (s->state == BT_CONNECT)
+			err = ECONNREFUSED;
+		else
+			err = ECONNRESET;
+
+		s->state = BT_CLOSED;
+		rfcomm_session_close(s, err);
+	}
+	return 0;
+}
+
+static int rfcomm_recv_disc(struct rfcomm_session *s, u8 dlci)
+{
+	int err = 0;
+
+	BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
+
+	if (dlci) {
+		struct rfcomm_dlc *d = rfcomm_dlc_get(s, dlci);
+		if (d) {
+			rfcomm_send_ua(s, dlci);
+
+			if (d->state == BT_CONNECT || d->state == BT_CONFIG)
+				err = ECONNREFUSED;
+			else
+				err = ECONNRESET;
+
+			d->state = BT_CLOSED;
+			__rfcomm_dlc_close(d, err);
+		} else 
+			rfcomm_send_dm(s, dlci);
+			
+	} else {
+		rfcomm_send_ua(s, 0);
+
+		if (s->state == BT_CONNECT)
+			err = ECONNREFUSED;
+		else
+			err = ECONNRESET;
+
+		s->state = BT_CLOSED;
+		rfcomm_session_close(s, err);
+	}
+
+	return 0;
+}
+
+static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci)
+{
+	struct rfcomm_dlc *d;
+	u8 channel;
+
+	BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
+
+	if (!dlci) {
+		rfcomm_send_ua(s, 0);
+
+		if (s->state == BT_OPEN) {
+			s->state = BT_CONNECTED;
+			rfcomm_process_connect(s);
+		}
+		return 0;
+	}
+
+	/* Check if DLC exists */
+	d = rfcomm_dlc_get(s, dlci);
+	if (d) {
+		if (d->state == BT_OPEN) {
+			/* DLC was previously opened by PN request */
+			rfcomm_send_ua(s, dlci);
+
+			rfcomm_dlc_lock(d);
+			d->state = BT_CONNECTED;
+			d->state_change(d, 0);
+			rfcomm_dlc_unlock(d);
+
+			rfcomm_send_msc(s, 1, dlci, d->v24_sig);
+		}
+		return 0;
+	}
+
+	/* Notify socket layer about incomming connection */
+	channel = __srv_channel(dlci);
+	if (rfcomm_connect_ind(s, channel, &d)) {
+		d->dlci = dlci;
+		d->addr = __addr(s->initiator, dlci);
+		rfcomm_dlc_link(s, d);
+
+		rfcomm_send_ua(s, dlci);
+
+		rfcomm_dlc_lock(d);
+		d->state = BT_CONNECTED;
+		d->state_change(d, 0);
+		rfcomm_dlc_unlock(d);
+	} else {
+		rfcomm_send_dm(s, dlci);
+	}
+
+	return 0;
+}
+
+static int rfcomm_apply_pn(struct rfcomm_dlc *d, int cr, struct rfcomm_pn *pn)
+{
+	BT_DBG("dlc %p state %ld dlci %d mtu %d fc 0x%x credits %d", 
+			d, d->state, d->dlci, pn->mtu, pn->flow_ctrl, pn->credits);
+
+	if (cr) {
+		if (pn->flow_ctrl == 0xf0) {
+			d->tx_credits = pn->credits;
+		} else {
+			set_bit(RFCOMM_TX_THROTTLED, &d->flags);
+			d->credits = 0;
+		}
+
+		d->mtu = btohs(pn->mtu);
+	} else {
+		if (pn->flow_ctrl == 0xe0) {
+			d->tx_credits = pn->credits;
+		} else {
+			set_bit(RFCOMM_TX_THROTTLED, &d->flags);
+			d->credits = 0;
+		}
+
+		d->mtu = btohs(pn->mtu);
+	}
+
+	return 0;
+}
+
+static int rfcomm_recv_pn(struct rfcomm_session *s, int cr, struct sk_buff *skb)
+{
+	struct rfcomm_pn *pn = (void *) skb->data;
+	struct rfcomm_dlc *d;
+	u8 dlci = pn->dlci;
+
+	BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
+
+	if (!dlci)
+		return 0;
+
+	d = rfcomm_dlc_get(s, dlci);
+	if (d) {
+		if (cr) {
+			/* PN request */
+			rfcomm_apply_pn(d, cr, pn);
+			rfcomm_send_pn(s, 0, d);
+		} else {
+			/* PN response */
+			switch (d->state) {
+			case BT_CONFIG:
+				rfcomm_apply_pn(d, cr, pn);
+				
+				d->state = BT_CONNECT;
+				rfcomm_send_sabm(s, d->dlci);
+				break;
+			}
+		}
+	} else {
+		u8 channel = __srv_channel(dlci);
+
+		if (!cr)
+			return 0;
+		
+		/* PN request for non existing DLC.
+		 * Assume incomming connection. */
+		if (rfcomm_connect_ind(s, channel, &d)) {
+			d->dlci = dlci;
+			d->addr = __addr(s->initiator, dlci);
+			rfcomm_dlc_link(s, d);
+
+			rfcomm_apply_pn(d, cr, pn);
+			
+			d->state = BT_OPEN;
+			rfcomm_send_pn(s, 0, d);
+		} else {
+			rfcomm_send_dm(s, dlci);
+		}
+	}
+	return 0;
+}
+
+static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_buff *skb)
+{
+	struct rfcomm_rpn *rpn = (void *) skb->data;
+	u8 dlci = __get_dlci(rpn->dlci);
+
+	u8 bit_rate  = 0;
+	u8 data_bits = 0;
+	u8 stop_bits = 0;
+	u8 parity    = 0;
+	u8 flow_ctrl = 0;
+	u8 xon_char  = 0;
+	u8 xoff_char = 0;
+	u16 rpn_mask = RFCOMM_RPN_PM_ALL;
+	
+	BT_DBG("dlci %d cr %d len 0x%x bitr 0x%x line 0x%x flow 0x%x xonc 0x%x xoffc 0x%x pm 0x%x", 
+	       dlci, cr, len, rpn->bit_rate, rpn->line_settings, rpn->flow_ctrl,
+	       rpn->xon_char, rpn->xoff_char, rpn->param_mask);
+	
+	if (!cr) 
+		return 0;
+	
+	if (len == 1) {
+		/* request: return default setting */
+		bit_rate  = RFCOMM_RPN_BR_115200;
+		data_bits = RFCOMM_RPN_DATA_8;
+		stop_bits = RFCOMM_RPN_STOP_1;
+		parity    = RFCOMM_RPN_PARITY_NONE;
+		flow_ctrl = RFCOMM_RPN_FLOW_NONE;
+		xon_char  = RFCOMM_RPN_XON_CHAR;
+		xoff_char = RFCOMM_RPN_XOFF_CHAR;
+
+		goto rpn_out;
+	}
+	/* check for sane values: ignore/accept bit_rate, 8 bits, 1 stop bit, no parity,
+	                          no flow control lines, normal XON/XOFF chars */
+	if (rpn->param_mask & RFCOMM_RPN_PM_DATA) {
+		data_bits = __get_rpn_data_bits(rpn->line_settings);
+		if (data_bits != RFCOMM_RPN_DATA_8) {
+			BT_DBG("RPN data bits mismatch 0x%x", data_bits);
+			data_bits = RFCOMM_RPN_DATA_8;
+			rpn_mask ^= RFCOMM_RPN_PM_DATA;
+		}
+	}
+	if (rpn->param_mask & RFCOMM_RPN_PM_STOP) {
+		stop_bits = __get_rpn_stop_bits(rpn->line_settings);
+		if (stop_bits != RFCOMM_RPN_STOP_1) {
+			BT_DBG("RPN stop bits mismatch 0x%x", stop_bits);
+			stop_bits = RFCOMM_RPN_STOP_1;
+			rpn_mask ^= RFCOMM_RPN_PM_STOP;
+		}
+	}
+	if (rpn->param_mask & RFCOMM_RPN_PM_PARITY) {
+		parity = __get_rpn_parity(rpn->line_settings);
+		if (parity != RFCOMM_RPN_PARITY_NONE) {
+			BT_DBG("RPN parity mismatch 0x%x", parity);
+			parity = RFCOMM_RPN_PARITY_NONE;
+			rpn_mask ^= RFCOMM_RPN_PM_PARITY;
+		}
+	}
+	if (rpn->param_mask & RFCOMM_RPN_PM_FLOW) {
+		if (rpn->flow_ctrl != RFCOMM_RPN_FLOW_NONE) {
+			BT_DBG("RPN flow ctrl mismatch 0x%x", rpn->flow_ctrl);
+			rpn->flow_ctrl = RFCOMM_RPN_FLOW_NONE;
+			rpn_mask ^= RFCOMM_RPN_PM_FLOW;
+		}
+	}
+	if (rpn->param_mask & RFCOMM_RPN_PM_XON) {
+		if (rpn->xon_char != RFCOMM_RPN_XON_CHAR) {
+			BT_DBG("RPN XON char mismatch 0x%x", rpn->xon_char);
+			rpn->xon_char = RFCOMM_RPN_XON_CHAR;
+			rpn_mask ^= RFCOMM_RPN_PM_XON;
+		}
+	}
+	if (rpn->param_mask & RFCOMM_RPN_PM_XOFF) {
+		if (rpn->xoff_char != RFCOMM_RPN_XOFF_CHAR) {
+			BT_DBG("RPN XOFF char mismatch 0x%x", rpn->xoff_char);
+			rpn->xoff_char = RFCOMM_RPN_XOFF_CHAR;
+			rpn_mask ^= RFCOMM_RPN_PM_XOFF;
+		}
+	}
+
+rpn_out:
+	rfcomm_send_rpn(s, 0, dlci, 
+			bit_rate, data_bits, stop_bits, parity, flow_ctrl,
+			xon_char, xoff_char, rpn_mask);
+
+	return 0;
+}
+
+static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb)
+{
+	struct rfcomm_msc *msc = (void *) skb->data;
+	struct rfcomm_dlc *d;
+	u8 dlci = __get_dlci(msc->dlci);
+
+	BT_DBG("dlci %d cr %d v24 0x%x", dlci, cr, msc->v24_sig);
+
+	if (!cr)
+		return 0;
+
+	d = rfcomm_dlc_get(s, dlci);
+	if (d) {
+		if (msc->v24_sig & RFCOMM_V24_FC && !d->credits)
+			set_bit(RFCOMM_TX_THROTTLED, &d->flags);
+		else
+			clear_bit(RFCOMM_TX_THROTTLED, &d->flags);
+		
+		rfcomm_dlc_lock(d);
+		if (d->modem_status)
+			d->modem_status(d, msc->v24_sig);
+		rfcomm_dlc_unlock(d);
+		
+		rfcomm_send_msc(s, 0, dlci, msc->v24_sig);
+	}
+	return 0;
+}
+
+static int rfcomm_recv_mcc(struct rfcomm_session *s, struct sk_buff *skb)
+{
+	struct rfcomm_mcc *mcc = (void *) skb->data;
+	u8 type, cr, len;
+
+	cr   = __test_cr(mcc->type);
+	type = __get_mcc_type(mcc->type);
+	len  = __get_mcc_len(mcc->len);
+
+	BT_DBG("%p type 0x%x cr %d", s, type, cr);
+
+	skb_pull(skb, 2);
+
+	switch (type) {
+	case RFCOMM_PN:
+		rfcomm_recv_pn(s, cr, skb);
+		break;
+
+	case RFCOMM_RPN:
+		rfcomm_recv_rpn(s, cr, len, skb);
+		break;
+
+	case RFCOMM_MSC:
+		rfcomm_recv_msc(s, cr, skb);
+		break;
+
+	case RFCOMM_TEST:
+		if (cr)
+			rfcomm_send_test(s, 0, skb->data, skb->len);
+		break;
+
+	case RFCOMM_NSC:
+		break;
+
+	default:
+		BT_ERR("Unknown control type 0x%02x", type);
+		rfcomm_send_nsc(s, cr, type);
+		break;
+	}
+	return 0;
+}
+
+static int rfcomm_recv_data(struct rfcomm_session *s, u8 dlci, int pf, struct sk_buff *skb)
+{
+	struct rfcomm_dlc *d;
+
+	BT_DBG("session %p state %ld dlci %d pf %d", s, s->state, dlci, pf);
+
+	d = rfcomm_dlc_get(s, dlci);
+	if (!d) {
+		rfcomm_send_dm(s, dlci);
+		goto drop;
+	}
+
+	if (pf && d->credits) {
+		u8 credits = *(u8 *) skb->data; skb_pull(skb, 1);
+
+		d->tx_credits += credits;
+		if (d->tx_credits)
+			clear_bit(RFCOMM_TX_THROTTLED, &d->flags);
+	}
+
+	if (skb->len && d->state == BT_CONNECTED) {
+		rfcomm_dlc_lock(d);
+		d->rx_credits--;
+		d->data_ready(d, skb);
+		rfcomm_dlc_unlock(d);
+		return 0;
+	}
+
+drop:
+	kfree_skb(skb);
+	return 0;
+}
+
+static int rfcomm_recv_frame(struct rfcomm_session *s, struct sk_buff *skb)
+{
+	struct rfcomm_hdr *hdr = (void *) skb->data;
+	u8 type, dlci, fcs;
+
+	dlci = __get_dlci(hdr->addr);
+	type = __get_type(hdr->ctrl);
+
+	/* Trim FCS */
+	skb->len--; skb->tail--;
+	fcs = *(u8 *) skb->tail;
+	
+	if (__check_fcs(skb->data, type, fcs)) {
+		BT_ERR("bad checksum in packet");
+		kfree_skb(skb);
+		return -EILSEQ;
+	}
+
+	if (__test_ea(hdr->len))
+		skb_pull(skb, 3);
+	else
+		skb_pull(skb, 4);
+	
+	switch (type) {
+	case RFCOMM_SABM:
+		if (__test_pf(hdr->ctrl))
+			rfcomm_recv_sabm(s, dlci);
+		break;
+
+	case RFCOMM_DISC:
+		if (__test_pf(hdr->ctrl))
+			rfcomm_recv_disc(s, dlci);
+		break;
+
+	case RFCOMM_UA:
+		if (__test_pf(hdr->ctrl))
+			rfcomm_recv_ua(s, dlci);
+		break;
+
+	case RFCOMM_DM:
+		rfcomm_recv_dm(s, dlci);
+		break;
+
+	case RFCOMM_UIH:
+		if (dlci)
+			return rfcomm_recv_data(s, dlci, __test_pf(hdr->ctrl), skb);
+
+		rfcomm_recv_mcc(s, skb);
+		break;
+
+	default:
+		BT_ERR("Unknown packet type 0x%02x\n", type);
+		break;
+	}
+	kfree_skb(skb);
+	return 0;
+}
+
+/* ---- Connection and data processing ---- */
+
+static void rfcomm_process_connect(struct rfcomm_session *s)
+{
+	struct rfcomm_dlc *d;
+	struct list_head *p, *n;
+
+	BT_DBG("session %p state %ld", s, s->state);
+
+	list_for_each_safe(p, n, &s->dlcs) {
+		d = list_entry(p, struct rfcomm_dlc, list);
+		if (d->state == BT_CONFIG) {
+			d->mtu = s->mtu;
+			rfcomm_send_pn(s, 1, d);
+		}
+	}
+}
+
+/* Send data queued for the DLC.
+ * Return number of frames left in the queue.
+ */
+static inline int rfcomm_process_tx(struct rfcomm_dlc *d)
+{
+	struct sk_buff *skb;
+	int err;
+
+	BT_DBG("dlc %p state %ld credits %d rx_credits %d tx_credits %d", 
+			d, d->state, d->credits, d->rx_credits, d->tx_credits);
+
+	/* Send pending MSC */
+	if (test_and_clear_bit(RFCOMM_MSC_PENDING, &d->flags))
+		rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig);
+	
+	if (d->credits) {
+		/* CFC enabled. 
+		 * Give them some credits */
+		if (!test_bit(RFCOMM_RX_THROTTLED, &d->flags) &&
+			       	d->rx_credits <= (d->credits >> 2)) {
+			rfcomm_send_credits(d->session, d->addr, d->credits - d->rx_credits);
+			d->rx_credits = d->credits;
+		}
+	} else {
+		/* CFC disabled. 
+		 * Give ourselves some credits */
+		d->tx_credits = RFCOMM_MAX_CREDITS;
+	}
+
+	if (test_bit(RFCOMM_TX_THROTTLED, &d->flags))
+		return skb_queue_len(&d->tx_queue);
+
+	while (d->tx_credits && (skb = skb_dequeue(&d->tx_queue))) {
+		err = rfcomm_send_frame(d->session, skb->data, skb->len);
+		if (err < 0) {
+			skb_queue_head(&d->tx_queue, skb);
+			break;
+		}
+		kfree_skb(skb);
+		d->tx_credits--;
+	}
+
+	if (d->credits && !d->tx_credits) {
+		/* We're out of TX credits.
+		 * Set TX_THROTTLED flag to avoid unnesary wakeups by dlc_send. */
+		set_bit(RFCOMM_TX_THROTTLED, &d->flags);
+	}
+
+	return skb_queue_len(&d->tx_queue);
+}
+
+static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
+{
+	struct rfcomm_dlc *d;
+	struct list_head *p, *n;
+
+	BT_DBG("session %p state %ld", s, s->state);
+
+	list_for_each_safe(p, n, &s->dlcs) {
+		d = list_entry(p, struct rfcomm_dlc, list);
+		if (test_bit(RFCOMM_TIMED_OUT, &d->flags)) {
+			__rfcomm_dlc_close(d, ETIMEDOUT);
+			continue;
+		}
+
+		if (d->state == BT_CONNECTED || d->state == BT_DISCONN)
+			rfcomm_process_tx(d);
+	}
+}
+
+static inline void rfcomm_process_rx(struct rfcomm_session *s)
+{
+	struct socket *sock = s->sock;
+	struct sock *sk = sock->sk;
+	struct sk_buff *skb;
+
+	BT_DBG("session %p state %ld qlen %d", s, s->state, skb_queue_len(&sk->receive_queue));
+
+	/* Get data directly from socket receive queue without copying it. */
+	while ((skb = skb_dequeue(&sk->receive_queue))) {
+		skb_orphan(skb);
+		rfcomm_recv_frame(s, skb);
+	}
+
+	if (sk->state == BT_CLOSED) {
+		if (!s->initiator)
+			rfcomm_session_put(s);
+
+		rfcomm_session_close(s, sk->err);
+	}
+}
+
+static inline void rfcomm_accept_connection(struct rfcomm_session *s)
+{
+	struct socket *sock = s->sock, *nsock;
+	int err;
+
+	/* Fast check for a new connection.
+	 * Avoids unnesesary socket allocations. */
+	if (list_empty(&bluez_pi(sock->sk)->accept_q))
+		return;
+
+	BT_DBG("session %p", s);
+
+	nsock = sock_alloc();
+	if (!nsock)
+		return;
+
+	nsock->type = sock->type;
+	nsock->ops  = sock->ops;
+	
+	err = sock->ops->accept(sock, nsock, O_NONBLOCK);
+	if (err < 0) {
+		sock_release(nsock);
+		return;
+	}
+
+	/* Set our callbacks */
+	nsock->sk->data_ready   = rfcomm_l2data_ready;
+	nsock->sk->state_change = rfcomm_l2state_change;
+
+	s = rfcomm_session_add(nsock, BT_OPEN);
+	if (s)
+		rfcomm_session_hold(s);
+	else
+		sock_release(nsock);
+}
+
+static inline void rfcomm_check_connection(struct rfcomm_session *s)
+{
+	struct sock *sk = s->sock->sk;
+
+	BT_DBG("%p state %ld", s, s->state);
+
+	switch(sk->state) {
+	case BT_CONNECTED:
+		s->state = BT_CONNECT;
+
+		/* We can adjust MTU on outgoing sessions.
+		 * L2CAP MTU minus UIH header and FCS. */
+		s->mtu = min(l2cap_pi(sk)->omtu, l2cap_pi(sk)->imtu) - 5;
+
+		rfcomm_send_sabm(s, 0);
+		break;
+
+	case BT_CLOSED:
+		s->state = BT_CLOSED;
+		rfcomm_session_close(s, sk->err);
+		break;
+	}
+}
+
+static inline void rfcomm_process_sessions(void)
+{
+	struct list_head *p, *n;
+
+	rfcomm_lock();
+
+	list_for_each_safe(p, n, &session_list) {
+		struct rfcomm_session *s;
+		s = list_entry(p, struct rfcomm_session, list);
+
+		if (s->state == BT_LISTEN) {
+			rfcomm_accept_connection(s);
+			continue;
+		}
+
+		rfcomm_session_hold(s);
+
+		switch (s->state) {
+		case BT_BOUND:
+			rfcomm_check_connection(s);
+			break;
+
+		default:
+			rfcomm_process_rx(s);
+			break;
+		}
+
+		rfcomm_process_dlcs(s);
+
+		rfcomm_session_put(s);
+	}
+	
+	rfcomm_unlock();
+}
+
+static void rfcomm_worker(void)
+{
+	BT_DBG("");
+
+	daemonize(); reparent_to_init();
+	set_fs(KERNEL_DS);
+
+	while (!atomic_read(&terminate)) {
+		if (!test_and_clear_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event)) {
+			/* No pending events. Let's sleep.
+			 * Incomming connections and data will wake us up. */
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule();
+		}
+
+		/* Process stuff */
+		rfcomm_process_sessions();
+	}
+	set_current_state(TASK_RUNNING);
+	return;
+}
+
+static int rfcomm_add_listener(bdaddr_t *ba)
+{
+	struct sockaddr_l2 addr;
+	struct l2cap_options opts;
+	struct socket *sock;
+	struct rfcomm_session *s;
+	int    size, err = 0;
+
+	/* Create socket */
+	err = rfcomm_l2sock_create(&sock);
+	if (err < 0) { 
+		BT_ERR("Create socket failed %d", err);
+		return err;
+	}
+
+	/* Bind socket */
+	bacpy(&addr.l2_bdaddr, ba);
+	addr.l2_family = AF_BLUETOOTH;
+	addr.l2_psm    = htobs(RFCOMM_PSM);
+	err = sock->ops->bind(sock, (struct sockaddr *) &addr, sizeof(addr));
+	if (err < 0) {
+		BT_ERR("Bind failed %d", err);
+		goto failed;
+	}
+
+	/* Set L2CAP options */
+	size = sizeof(opts);
+	sock->ops->getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, &size);
+
+	opts.imtu = RFCOMM_MAX_L2CAP_MTU;
+	sock->ops->setsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, size);
+
+	/* Start listening on the socket */
+	err = sock->ops->listen(sock, 10);
+	if (err) {
+		BT_ERR("Listen failed %d", err);
+		goto failed;
+	}
+
+	/* Add listening session */
+	s = rfcomm_session_add(sock, BT_LISTEN);
+	if (!s)
+		goto failed;
+
+	rfcomm_session_hold(s);
+	return 0;
+failed:
+	sock_release(sock);
+	return err;
+}
+
+static void rfcomm_kill_listener(void)
+{
+	struct rfcomm_session *s;
+	struct list_head *p, *n;
+
+	BT_DBG("");
+
+	list_for_each_safe(p, n, &session_list) {
+		s = list_entry(p, struct rfcomm_session, list);
+		rfcomm_session_del(s);
+	}
+}
+
+static int rfcomm_run(void *unused)
+{
+	rfcomm_thread = current;
+
+	atomic_inc(&running);
+
+	daemonize(); reparent_to_init();
+
+	sigfillset(&current->blocked);
+	set_fs(KERNEL_DS);
+
+	sprintf(current->comm, "krfcommd");
+
+	BT_DBG("");
+
+	rfcomm_add_listener(BDADDR_ANY);
+
+	rfcomm_worker();
+
+	rfcomm_kill_listener();
+
+	atomic_dec(&running);
+	return 0;
+}
+
+/* ---- Proc fs support ---- */
+static int rfcomm_dlc_dump(char *buf)
+{
+	struct rfcomm_session *s;
+	struct sock *sk;
+	struct list_head *p, *pp;
+	char *ptr = buf;
+
+	rfcomm_lock();
+
+	list_for_each(p, &session_list) {
+		s = list_entry(p, struct rfcomm_session, list);
+		sk = s->sock->sk;
+
+		list_for_each(pp, &s->dlcs) {
+		struct rfcomm_dlc *d;
+			d = list_entry(pp, struct rfcomm_dlc, list);
+
+			ptr += sprintf(ptr, "dlc %s %s %ld %d %d %d %d\n",
+				batostr(&bluez_pi(sk)->src), batostr(&bluez_pi(sk)->dst),
+				d->state, d->dlci, d->mtu, d->rx_credits, d->tx_credits);
+		}
+	}
+	
+	rfcomm_unlock();
+
+	return ptr - buf;
+}
+
+extern int rfcomm_sock_dump(char *buf);
+
+static int rfcomm_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv)
+{
+	char *ptr = buf;
+	int len;
+
+	BT_DBG("count %d, offset %ld", count, offset);
+
+	ptr += rfcomm_dlc_dump(ptr);
+	ptr += rfcomm_sock_dump(ptr);
+	len  = ptr - buf;
+
+	if (len <= count + offset)
+		*eof = 1;
+
+	*start = buf + offset;
+	len -= offset;
+
+	if (len > count)
+		len = count;
+	if (len < 0)
+		len = 0;
+
+	return len;
+}
+
+/* ---- Initialization ---- */
+int __init rfcomm_init(void)
+{
+	kernel_thread(rfcomm_run, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+
+	rfcomm_init_sockets();
+
+#ifdef CONFIG_BLUEZ_RFCOMM_TTY
+	rfcomm_init_ttys();
+#endif
+
+	create_proc_read_entry("bluetooth/rfcomm", 0, 0, rfcomm_read_proc, NULL);
+
+	BT_INFO("BlueZ RFCOMM ver %s", VERSION);
+	BT_INFO("Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>");
+	BT_INFO("Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>");
+	return 0;
+}
+
+void rfcomm_cleanup(void)
+{
+	/* Terminate working thread.
+	 * ie. Set terminate flag and wake it up */
+	atomic_inc(&terminate);
+	rfcomm_schedule(RFCOMM_SCHED_STATE);
+
+	/* Wait until thread is running */
+	while (atomic_read(&running))
+		schedule();
+
+	remove_proc_entry("bluetooth/rfcomm", NULL);
+
+#ifdef CONFIG_BLUEZ_RFCOMM_TTY
+	rfcomm_cleanup_ttys();
+#endif
+
+	rfcomm_cleanup_sockets();
+	return;
+}
+
+module_init(rfcomm_init);
+module_exit(rfcomm_cleanup);
+
+MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>");
+MODULE_DESCRIPTION("BlueZ RFCOMM ver " VERSION);
+MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/bluetooth/rfcomm/crc.c linux-2.4.21-pre6/net/bluetooth/rfcomm/crc.c
--- linux-2.4.20/net/bluetooth/rfcomm/crc.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/net/bluetooth/rfcomm/crc.c	2003-03-26 23:49:19.000000000 +0000
@@ -0,0 +1,71 @@
+/* 
+   RFCOMM implementation for Linux Bluetooth stack (BlueZ).
+   Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
+   Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ * RFCOMM FCS calculation.
+ *
+ * $Id: crc.c,v 1.2 2002/09/21 09:54:32 holtmann Exp $
+ */
+
+/* reversed, 8-bit, poly=0x07 */
+unsigned char rfcomm_crc_table[256] = { 
+	0x00, 0x91, 0xe3, 0x72, 0x07, 0x96, 0xe4, 0x75,
+	0x0e, 0x9f, 0xed, 0x7c, 0x09, 0x98, 0xea, 0x7b,
+	0x1c, 0x8d, 0xff, 0x6e, 0x1b, 0x8a, 0xf8, 0x69,
+	0x12, 0x83, 0xf1, 0x60, 0x15, 0x84, 0xf6, 0x67,
+
+	0x38, 0xa9, 0xdb, 0x4a, 0x3f, 0xae, 0xdc, 0x4d,
+	0x36, 0xa7, 0xd5, 0x44, 0x31, 0xa0, 0xd2, 0x43,
+	0x24, 0xb5, 0xc7, 0x56, 0x23, 0xb2, 0xc0, 0x51,
+	0x2a, 0xbb, 0xc9, 0x58, 0x2d, 0xbc, 0xce, 0x5f,
+
+	0x70, 0xe1, 0x93, 0x02, 0x77, 0xe6, 0x94, 0x05,
+	0x7e, 0xef, 0x9d, 0x0c, 0x79, 0xe8, 0x9a, 0x0b,
+	0x6c, 0xfd, 0x8f, 0x1e, 0x6b, 0xfa, 0x88, 0x19,
+	0x62, 0xf3, 0x81, 0x10, 0x65, 0xf4, 0x86, 0x17,
+
+	0x48, 0xd9, 0xab, 0x3a, 0x4f, 0xde, 0xac, 0x3d,
+	0x46, 0xd7, 0xa5, 0x34, 0x41, 0xd0, 0xa2, 0x33,
+	0x54, 0xc5, 0xb7, 0x26, 0x53, 0xc2, 0xb0, 0x21,
+	0x5a, 0xcb, 0xb9, 0x28, 0x5d, 0xcc, 0xbe, 0x2f,
+
+	0xe0, 0x71, 0x03, 0x92, 0xe7, 0x76, 0x04, 0x95,
+	0xee, 0x7f, 0x0d, 0x9c, 0xe9, 0x78, 0x0a, 0x9b,
+	0xfc, 0x6d, 0x1f, 0x8e, 0xfb, 0x6a, 0x18, 0x89,
+	0xf2, 0x63, 0x11, 0x80, 0xf5, 0x64, 0x16, 0x87,
+
+	0xd8, 0x49, 0x3b, 0xaa, 0xdf, 0x4e, 0x3c, 0xad,
+	0xd6, 0x47, 0x35, 0xa4, 0xd1, 0x40, 0x32, 0xa3,
+	0xc4, 0x55, 0x27, 0xb6, 0xc3, 0x52, 0x20, 0xb1,
+	0xca, 0x5b, 0x29, 0xb8, 0xcd, 0x5c, 0x2e, 0xbf,
+
+	0x90, 0x01, 0x73, 0xe2, 0x97, 0x06, 0x74, 0xe5,
+	0x9e, 0x0f, 0x7d, 0xec, 0x99, 0x08, 0x7a, 0xeb,
+	0x8c, 0x1d, 0x6f, 0xfe, 0x8b, 0x1a, 0x68, 0xf9,
+	0x82, 0x13, 0x61, 0xf0, 0x85, 0x14, 0x66, 0xf7,
+
+	0xa8, 0x39, 0x4b, 0xda, 0xaf, 0x3e, 0x4c, 0xdd,
+	0xa6, 0x37, 0x45, 0xd4, 0xa1, 0x30, 0x42, 0xd3,
+	0xb4, 0x25, 0x57, 0xc6, 0xb3, 0x22, 0x50, 0xc1,
+	0xba, 0x2b, 0x59, 0xc8, 0xbd, 0x2c, 0x5e, 0xcf
+};
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/bluetooth/rfcomm/sock.c linux-2.4.21-pre6/net/bluetooth/rfcomm/sock.c
--- linux-2.4.20/net/bluetooth/rfcomm/sock.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/net/bluetooth/rfcomm/sock.c	2003-03-26 23:49:40.000000000 +0000
@@ -0,0 +1,840 @@
+/* 
+   RFCOMM implementation for Linux Bluetooth stack (BlueZ).
+   Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
+   Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ * RFCOMM sockets.
+ *
+ * $Id: sock.c,v 1.30 2002/10/18 20:12:12 maxk Exp $
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/fcntl.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/interrupt.h>
+#include <linux/socket.h>
+#include <linux/skbuff.h>
+#include <linux/list.h>
+#include <net/sock.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/rfcomm.h>
+
+#ifndef CONFIG_BLUEZ_RFCOMM_DEBUG
+#undef  BT_DBG
+#define BT_DBG(D...)
+#endif
+
+static struct proto_ops rfcomm_sock_ops;
+
+static struct bluez_sock_list rfcomm_sk_list = {
+	lock: RW_LOCK_UNLOCKED
+};
+
+static void rfcomm_sock_close(struct sock *sk);
+static void rfcomm_sock_kill(struct sock *sk);
+
+/* ---- DLC callbacks ----
+ *
+ * called under rfcomm_dlc_lock()
+ */
+static void rfcomm_sk_data_ready(struct rfcomm_dlc *d, struct sk_buff *skb)
+{
+	struct sock *sk = d->owner;
+	if (!sk)
+		return;
+
+	atomic_add(skb->len, &sk->rmem_alloc);
+	skb_queue_tail(&sk->receive_queue, skb);
+	sk->data_ready(sk, skb->len);
+
+	if (atomic_read(&sk->rmem_alloc) >= sk->rcvbuf)
+		rfcomm_dlc_throttle(d);
+}
+
+static void rfcomm_sk_state_change(struct rfcomm_dlc *d, int err)
+{
+	struct sock *sk = d->owner, *parent;
+	if (!sk)
+		return;
+
+	BT_DBG("dlc %p state %ld err %d", d, d->state, err);
+
+	bh_lock_sock(sk);
+
+	if (err)
+		sk->err = err;
+	sk->state = d->state;
+
+	parent = bluez_pi(sk)->parent;
+	if (!parent) {
+		if (d->state == BT_CONNECTED)
+			rfcomm_session_getaddr(d->session, &bluez_pi(sk)->src, NULL);
+		sk->state_change(sk);
+	} else
+		parent->data_ready(parent, 0);
+
+	bh_unlock_sock(sk);
+}
+
+/* ---- Socket functions ---- */
+static struct sock *__rfcomm_get_sock_by_addr(u8 channel, bdaddr_t *src)
+{
+	struct sock *sk;
+
+	for (sk = rfcomm_sk_list.head; sk; sk = sk->next) {
+		if (rfcomm_pi(sk)->channel == channel && 
+				!bacmp(&bluez_pi(sk)->src, src))
+			break;
+	}
+
+	return sk;
+}
+
+/* Find socket with channel and source bdaddr.
+ * Returns closest match.
+ */
+static struct sock *__rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t *src)
+{
+	struct sock *sk, *sk1 = NULL;
+
+	for (sk = rfcomm_sk_list.head; sk; sk = sk->next) {
+		if (state && sk->state != state)
+			continue;
+
+		if (rfcomm_pi(sk)->channel == channel) {
+			/* Exact match. */
+			if (!bacmp(&bluez_pi(sk)->src, src))
+				break;
+
+			/* Closest match */
+			if (!bacmp(&bluez_pi(sk)->src, BDADDR_ANY))
+				sk1 = sk;
+		}
+	}
+	return sk ? sk : sk1;
+}
+
+/* Find socket with given address (channel, src).
+ * Returns locked socket */
+static inline struct sock *rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t *src)
+{
+	struct sock *s;
+	read_lock(&rfcomm_sk_list.lock);
+	s = __rfcomm_get_sock_by_channel(state, channel, src);
+	if (s) bh_lock_sock(s);
+	read_unlock(&rfcomm_sk_list.lock);
+	return s;
+}
+
+static void rfcomm_sock_destruct(struct sock *sk)
+{
+	struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
+
+	BT_DBG("sk %p dlc %p", sk, d);
+
+	skb_queue_purge(&sk->receive_queue);
+	skb_queue_purge(&sk->write_queue);
+
+	rfcomm_dlc_lock(d);
+	rfcomm_pi(sk)->dlc = NULL;
+	
+	/* Detach DLC if it's owned by this socket */
+	if (d->owner == sk)
+		d->owner = NULL;
+	rfcomm_dlc_unlock(d);
+
+	rfcomm_dlc_put(d);
+
+	MOD_DEC_USE_COUNT;
+}
+
+static void rfcomm_sock_cleanup_listen(struct sock *parent)
+{
+	struct sock *sk;
+
+	BT_DBG("parent %p", parent);
+
+	/* Close not yet accepted dlcs */
+	while ((sk = bluez_accept_dequeue(parent, NULL)))
+		rfcomm_sock_close(sk);
+
+	parent->state  = BT_CLOSED;
+	parent->zapped = 1;
+}
+
+/* Kill socket (only if zapped and orphan)
+ * Must be called on unlocked socket.
+ */
+static void rfcomm_sock_kill(struct sock *sk)
+{
+	if (!sk->zapped || sk->socket)
+		return;
+
+	BT_DBG("sk %p state %d refcnt %d", sk, sk->state, atomic_read(&sk->refcnt));
+
+	/* Kill poor orphan */
+	bluez_sock_unlink(&rfcomm_sk_list, sk);
+	sk->dead = 1;
+	sock_put(sk);
+}
+
+/* Close socket.
+ * Must be called on unlocked socket.
+ */
+static void rfcomm_sock_close(struct sock *sk)
+{
+	struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
+
+	lock_sock(sk);
+
+	BT_DBG("sk %p state %d socket %p", sk, sk->state, sk->socket);
+
+	switch (sk->state) {
+	case BT_LISTEN:
+		rfcomm_sock_cleanup_listen(sk);
+		break;
+
+	case BT_CONNECT:
+	case BT_CONNECT2:
+	case BT_CONFIG:
+	case BT_CONNECTED:
+		rfcomm_dlc_close(d, 0);
+
+	default:
+		sk->zapped = 1;
+		break;
+	};
+
+	release_sock(sk);
+
+	rfcomm_sock_kill(sk);
+}
+
+static void rfcomm_sock_init(struct sock *sk, struct sock *parent)
+{
+	BT_DBG("sk %p", sk);
+
+	if (parent) 
+		sk->type = parent->type;
+}
+
+static struct sock *rfcomm_sock_alloc(struct socket *sock, int proto, int prio)
+{
+	struct rfcomm_dlc *d;
+	struct sock *sk;
+
+	sk = sk_alloc(PF_BLUETOOTH, prio, 1);
+	if (!sk)
+		return NULL;
+
+	d = rfcomm_dlc_alloc(prio);
+	if (!d) {
+		sk_free(sk);
+		return NULL;
+	}
+	d->data_ready   = rfcomm_sk_data_ready;
+	d->state_change = rfcomm_sk_state_change;
+
+	rfcomm_pi(sk)->dlc = d;
+	d->owner = sk;
+
+	bluez_sock_init(sock, sk);
+
+	sk->zapped   = 0;
+
+	sk->destruct = rfcomm_sock_destruct;
+	sk->sndtimeo = RFCOMM_CONN_TIMEOUT;
+
+	sk->sndbuf   = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
+	sk->rcvbuf   = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
+
+	sk->protocol = proto;
+	sk->state    = BT_OPEN;
+
+	bluez_sock_link(&rfcomm_sk_list, sk);
+
+	BT_DBG("sk %p", sk);
+
+	MOD_INC_USE_COUNT;
+	return sk;
+}
+
+static int rfcomm_sock_create(struct socket *sock, int protocol)
+{
+	struct sock *sk;
+
+	BT_DBG("sock %p", sock);
+
+	sock->state = SS_UNCONNECTED;
+
+	if (sock->type != SOCK_STREAM && sock->type != SOCK_RAW)
+		return -ESOCKTNOSUPPORT;
+
+	sock->ops = &rfcomm_sock_ops;
+
+	if (!(sk = rfcomm_sock_alloc(sock, protocol, GFP_KERNEL)))
+		return -ENOMEM;
+
+	rfcomm_sock_init(sk, NULL);
+	return 0;
+}
+
+static int rfcomm_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
+{
+	struct sockaddr_rc *sa = (struct sockaddr_rc *) addr;
+	struct sock *sk = sock->sk;
+	int err = 0;
+
+	BT_DBG("sk %p %s", sk, batostr(&sa->rc_bdaddr));
+
+	if (!addr || addr->sa_family != AF_BLUETOOTH)
+		return -EINVAL;
+
+	lock_sock(sk);
+
+	if (sk->state != BT_OPEN) {
+		err = -EBADFD;
+		goto done;
+	}
+
+	write_lock_bh(&rfcomm_sk_list.lock);
+
+	if (sa->rc_channel && __rfcomm_get_sock_by_addr(sa->rc_channel, &sa->rc_bdaddr)) {
+		err = -EADDRINUSE;
+	} else {
+		/* Save source address */
+		bacpy(&bluez_pi(sk)->src, &sa->rc_bdaddr);
+		rfcomm_pi(sk)->channel = sa->rc_channel;
+		sk->state = BT_BOUND;
+	}
+
+	write_unlock_bh(&rfcomm_sk_list.lock);
+
+done:
+	release_sock(sk);
+	return err;
+}
+
+static int rfcomm_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
+{
+	struct sockaddr_rc *sa = (struct sockaddr_rc *) addr;
+	struct sock *sk = sock->sk;
+	struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
+	int err = 0;
+
+	BT_DBG("sk %p", sk);
+
+	if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_rc))
+		return -EINVAL;
+
+	if (sk->state != BT_OPEN && sk->state != BT_BOUND)
+		return -EBADFD;
+
+	if (sk->type != SOCK_STREAM)
+		return -EINVAL;
+
+	lock_sock(sk);
+
+	sk->state = BT_CONNECT;
+	bacpy(&bluez_pi(sk)->dst, &sa->rc_bdaddr);
+	rfcomm_pi(sk)->channel = sa->rc_channel;
+	
+	err = rfcomm_dlc_open(d, &bluez_pi(sk)->src, &sa->rc_bdaddr, sa->rc_channel);
+	if (!err)
+		err = bluez_sock_w4_connect(sk, flags);
+
+	release_sock(sk);
+	return err;
+}
+
+int rfcomm_sock_listen(struct socket *sock, int backlog)
+{
+	struct sock *sk = sock->sk;
+	int err = 0;
+
+	BT_DBG("sk %p backlog %d", sk, backlog);
+
+	lock_sock(sk);
+
+	if (sk->state != BT_BOUND) {
+		err = -EBADFD;
+		goto done;
+	}
+
+	sk->max_ack_backlog = backlog;
+	sk->ack_backlog = 0;
+	sk->state = BT_LISTEN;
+
+done:
+	release_sock(sk);
+	return err;
+}
+
+int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int flags)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	struct sock *sk = sock->sk, *nsk;
+	long timeo;
+	int err = 0;
+
+	lock_sock(sk);
+
+	if (sk->state != BT_LISTEN) {
+		err = -EBADFD;
+		goto done;
+	}
+
+	timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
+
+	BT_DBG("sk %p timeo %ld", sk, timeo);
+
+	/* Wait for an incoming connection. (wake-one). */
+	add_wait_queue_exclusive(sk->sleep, &wait);
+	while (!(nsk = bluez_accept_dequeue(sk, newsock))) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (!timeo) {
+			err = -EAGAIN;
+			break;
+		}
+
+		release_sock(sk);
+		timeo = schedule_timeout(timeo);
+		lock_sock(sk);
+
+		if (sk->state != BT_LISTEN) {
+			err = -EBADFD;
+			break;
+		}
+
+		if (signal_pending(current)) {
+			err = sock_intr_errno(timeo);
+			break;
+		}
+	}
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(sk->sleep, &wait);
+
+	if (err)
+		goto done;
+
+	newsock->state = SS_CONNECTED;
+
+	BT_DBG("new socket %p", nsk);
+
+done:
+	release_sock(sk);
+	return err;
+}
+
+static int rfcomm_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
+{
+	struct sockaddr_rc *sa = (struct sockaddr_rc *) addr;
+	struct sock *sk = sock->sk;
+
+	BT_DBG("sock %p, sk %p", sock, sk);
+
+	sa->rc_family  = AF_BLUETOOTH;
+	sa->rc_channel = rfcomm_pi(sk)->channel;
+	if (peer)
+		bacpy(&sa->rc_bdaddr, &bluez_pi(sk)->dst);
+	else
+		bacpy(&sa->rc_bdaddr, &bluez_pi(sk)->src);
+
+	*len = sizeof(struct sockaddr_rc);
+	return 0;
+}
+
+static int rfcomm_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len,
+			       struct scm_cookie *scm)
+{
+	struct sock *sk = sock->sk;
+	struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
+	struct sk_buff *skb;
+	int err, size;
+	int sent = 0;
+
+	if (msg->msg_flags & MSG_OOB)
+		return -EOPNOTSUPP;
+
+	if (sk->shutdown & SEND_SHUTDOWN)
+		return -EPIPE;
+
+	BT_DBG("sock %p, sk %p", sock, sk);
+
+	lock_sock(sk);
+
+	while (len) {
+		size = min_t(uint, len, d->mtu);
+		
+		skb = sock_alloc_send_skb(sk, size + RFCOMM_SKB_RESERVE,
+				msg->msg_flags & MSG_DONTWAIT, &err);
+		if (!skb)
+			break;
+		skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE);
+
+		err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
+		if (err) {
+			kfree_skb(skb);
+			sent = err;
+			break;
+		}
+
+		err = rfcomm_dlc_send(d, skb);
+		if (err < 0) {
+			kfree_skb(skb);
+			break;
+		}
+
+		sent += size;
+		len  -= size;
+	}
+
+	release_sock(sk);
+
+	return sent ? sent : err;
+}
+
+static long rfcomm_sock_data_wait(struct sock *sk, long timeo)
+{
+	DECLARE_WAITQUEUE(wait, current);
+
+	add_wait_queue(sk->sleep, &wait);
+	for (;;) {
+		set_current_state(TASK_INTERRUPTIBLE);
+
+		if (skb_queue_len(&sk->receive_queue) || sk->err || (sk->shutdown & RCV_SHUTDOWN) ||
+				signal_pending(current) || !timeo)
+			break;
+
+		set_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);
+		release_sock(sk);
+		timeo = schedule_timeout(timeo);
+		lock_sock(sk);
+		clear_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);
+	}
+
+	__set_current_state(TASK_RUNNING);
+	remove_wait_queue(sk->sleep, &wait);
+	return timeo;
+}
+
+static int rfcomm_sock_recvmsg(struct socket *sock, struct msghdr *msg, int size,
+			       int flags, struct scm_cookie *scm)
+{
+	struct sock *sk = sock->sk;
+	int target, err = 0, copied = 0;
+	long timeo;
+
+	if (sk->state != BT_CONNECTED)
+		return -EINVAL;
+
+	if (flags & MSG_OOB)
+		return -EOPNOTSUPP;
+
+	msg->msg_namelen = 0;
+
+	BT_DBG("sk %p size %d", sk, size);
+
+	lock_sock(sk);
+
+	target = sock_rcvlowat(sk, flags & MSG_WAITALL, size);
+	timeo  = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
+
+	do {
+		struct sk_buff *skb;
+		int chunk;
+
+		skb = skb_dequeue(&sk->receive_queue);
+		if (!skb) {
+			if (copied >= target)
+				break;
+
+			if ((err = sock_error(sk)) != 0)
+				break;
+			if (sk->shutdown & RCV_SHUTDOWN)
+				break;
+
+			err = -EAGAIN;
+			if (!timeo)
+				break;
+
+			timeo = rfcomm_sock_data_wait(sk, timeo);
+
+			if (signal_pending(current)) {
+				err = sock_intr_errno(timeo);
+				goto out;
+			}
+			continue;
+		}
+
+		chunk = min_t(unsigned int, skb->len, size);
+		if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) {
+			skb_queue_head(&sk->receive_queue, skb);
+			if (!copied)
+				copied = -EFAULT;
+			break;
+		}
+		copied += chunk;
+		size   -= chunk;
+
+		if (!(flags & MSG_PEEK)) {
+			atomic_sub(chunk, &sk->rmem_alloc);
+
+			skb_pull(skb, chunk);
+			if (skb->len) {
+				skb_queue_head(&sk->receive_queue, skb);
+				break;
+			}
+			kfree_skb(skb);
+
+		} else {
+			/* put message back and return */
+			skb_queue_head(&sk->receive_queue, skb);
+			break;
+		}
+	} while (size);
+
+out:
+	if (atomic_read(&sk->rmem_alloc) <= (sk->rcvbuf >> 2))
+		rfcomm_dlc_unthrottle(rfcomm_pi(sk)->dlc);
+
+	release_sock(sk);
+	return copied ? : err;
+}
+
+static int rfcomm_sock_shutdown(struct socket *sock, int how)
+{
+	struct sock *sk = sock->sk;
+
+	BT_DBG("sock %p, sk %p", sock, sk);
+
+	if (!sk) return 0;
+
+	lock_sock(sk);
+	sk->shutdown = SHUTDOWN_MASK;
+	if (sk->state == BT_CONNECTED)
+		rfcomm_dlc_close(rfcomm_pi(sk)->dlc, 0);
+	release_sock(sk);
+
+	return 0;
+}
+
+static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
+{
+	struct sock *sk = sock->sk;
+	int err = 0;
+
+	BT_DBG("sk %p", sk);
+
+	lock_sock(sk);
+
+	switch (optname) {
+	default:
+		err = -ENOPROTOOPT;
+		break;
+	};
+
+	release_sock(sk);
+	return err;
+}
+
+static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
+{
+	struct sock *sk = sock->sk;
+	int len, err = 0; 
+
+	BT_DBG("sk %p", sk);
+
+	if (get_user(len, optlen))
+		return -EFAULT;
+
+	lock_sock(sk);
+
+	switch (optname) {
+	default:
+		err = -ENOPROTOOPT;
+		break;
+	};
+
+	release_sock(sk);
+	return err;
+}
+
+static int rfcomm_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+	struct sock *sk = sock->sk;
+	int err;
+
+	lock_sock(sk);
+
+#ifdef CONFIG_BLUEZ_RFCOMM_TTY
+	err = rfcomm_dev_ioctl(sk, cmd, arg);
+#else
+	err = -EOPNOTSUPP;
+#endif
+
+	release_sock(sk);
+
+	return err;
+}
+
+static int rfcomm_sock_release(struct socket *sock)
+{
+	struct sock *sk = sock->sk;
+
+	BT_DBG("sock %p, sk %p", sock, sk);
+
+	if (!sk)
+		return 0;
+
+	sock_orphan(sk);
+	rfcomm_sock_close(sk);
+
+	return 0;
+}
+
+/* ---- RFCOMM core layer callbacks ---- 
+ *
+ * called under rfcomm_lock()
+ */
+int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc **d)
+{
+	struct sock *sk, *parent;
+	bdaddr_t src, dst;
+	int result = 0;
+
+	BT_DBG("session %p channel %d", s, channel);
+
+	rfcomm_session_getaddr(s, &src, &dst);
+
+	/* Check if we have socket listening on this channel */
+	parent = rfcomm_get_sock_by_channel(BT_LISTEN, channel, &src);
+	if (!parent)
+		return 0;
+
+	/* Check for backlog size */
+	if (parent->ack_backlog > parent->max_ack_backlog) {
+		BT_DBG("backlog full %d", parent->ack_backlog); 
+		goto done;
+	}
+
+	sk = rfcomm_sock_alloc(NULL, BTPROTO_RFCOMM, GFP_ATOMIC);
+	if (!sk)
+		goto done;
+
+	rfcomm_sock_init(sk, parent);
+	bacpy(&bluez_pi(sk)->src, &src);
+	bacpy(&bluez_pi(sk)->dst, &dst);
+	rfcomm_pi(sk)->channel = channel;
+
+	sk->state = BT_CONFIG;
+	bluez_accept_enqueue(parent, sk);
+
+	/* Accept connection and return socket DLC */
+	*d = rfcomm_pi(sk)->dlc;
+	result = 1;
+
+done:
+	bh_unlock_sock(parent);
+	return result;
+}
+
+/* ---- Proc fs support ---- */
+int rfcomm_sock_dump(char *buf)
+{
+	struct bluez_sock_list *list = &rfcomm_sk_list;
+	struct rfcomm_pinfo *pi;
+	struct sock *sk;
+	char *ptr = buf;
+
+	write_lock_bh(&list->lock);
+
+	for (sk = list->head; sk; sk = sk->next) {
+		pi = rfcomm_pi(sk);
+		ptr += sprintf(ptr, "sk  %s %s %d %d\n",
+				batostr(&bluez_pi(sk)->src), batostr(&bluez_pi(sk)->dst),
+				sk->state, rfcomm_pi(sk)->channel);
+	}
+
+	write_unlock_bh(&list->lock);
+
+	return ptr - buf;
+}
+
+static struct proto_ops rfcomm_sock_ops = {
+	family:		PF_BLUETOOTH,
+	release:	rfcomm_sock_release,
+	bind:		rfcomm_sock_bind,
+	connect:	rfcomm_sock_connect,
+	listen:		rfcomm_sock_listen,
+	accept:		rfcomm_sock_accept,
+	getname:	rfcomm_sock_getname,
+	sendmsg:	rfcomm_sock_sendmsg,
+	recvmsg:	rfcomm_sock_recvmsg,
+	shutdown:	rfcomm_sock_shutdown,
+	setsockopt:	rfcomm_sock_setsockopt,
+	getsockopt:	rfcomm_sock_getsockopt,
+	ioctl:		rfcomm_sock_ioctl,
+	poll:		bluez_sock_poll,
+	socketpair:	sock_no_socketpair,
+	mmap:		sock_no_mmap
+};
+
+static struct net_proto_family rfcomm_sock_family_ops = {
+	family:		PF_BLUETOOTH,
+	create:		rfcomm_sock_create
+};
+
+int rfcomm_init_sockets(void)
+{
+	int err;
+
+	if ((err = bluez_sock_register(BTPROTO_RFCOMM, &rfcomm_sock_family_ops))) {
+		BT_ERR("Can't register RFCOMM socket layer");
+		return err;
+	}
+
+	return 0;
+}
+
+void rfcomm_cleanup_sockets(void)
+{
+	int err;
+
+	/* Unregister socket, protocol and notifier */
+	if ((err = bluez_sock_unregister(BTPROTO_RFCOMM)))
+		BT_ERR("Can't unregister RFCOMM socket layer %d", err);
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/bluetooth/rfcomm/tty.c linux-2.4.21-pre6/net/bluetooth/rfcomm/tty.c
--- linux-2.4.20/net/bluetooth/rfcomm/tty.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/net/bluetooth/rfcomm/tty.c	2003-03-26 23:49:19.000000000 +0000
@@ -0,0 +1,914 @@
+/* 
+   RFCOMM implementation for Linux Bluetooth stack (BlueZ).
+   Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
+   Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 as
+   published by the Free Software Foundation;
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+   SOFTWARE IS DISCLAIMED.
+*/
+
+/*
+ * RFCOMM TTY.
+ *
+ * $Id: tty.c,v 1.26 2002/10/18 20:12:12 maxk Exp $
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/rfcomm.h>
+
+#ifndef CONFIG_BLUEZ_RFCOMM_DEBUG
+#undef  BT_DBG
+#define BT_DBG(D...)
+#endif
+
+#define RFCOMM_TTY_MAGIC 0x6d02		/* magic number for rfcomm struct */
+#define RFCOMM_TTY_PORTS RFCOMM_MAX_DEV	/* whole lotta rfcomm devices */
+#define RFCOMM_TTY_MAJOR 216		/* device node major id of the usb/bluetooth.c driver */
+#define RFCOMM_TTY_MINOR 0
+
+struct rfcomm_dev {
+	struct list_head	list;
+	atomic_t		refcnt;
+
+	char			name[12];
+	int			id;
+	unsigned long		flags;
+	int			opened;
+	int			err;
+
+	bdaddr_t		src;
+	bdaddr_t		dst;
+	u8 			channel;
+
+	uint 			modem_status;
+
+	struct rfcomm_dlc	*dlc;
+	struct tty_struct	*tty;
+	wait_queue_head_t       wait;
+	struct tasklet_struct   wakeup_task;
+
+	atomic_t 		wmem_alloc;
+	unsigned int 		sndbuf;
+};
+
+static LIST_HEAD(rfcomm_dev_list);
+static rwlock_t rfcomm_dev_lock = RW_LOCK_UNLOCKED;
+
+static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb);
+static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err);
+static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig);
+
+static void rfcomm_tty_wakeup(unsigned long arg);
+
+/* ---- Device functions ---- */
+static void rfcomm_dev_destruct(struct rfcomm_dev *dev)
+{
+	struct rfcomm_dlc *dlc = dev->dlc;
+
+	BT_DBG("dev %p dlc %p", dev, dlc);
+
+	rfcomm_dlc_lock(dlc);
+	/* Detach DLC if it's owned by this dev */
+	if (dlc->owner == dev)
+		dlc->owner = NULL;
+	rfcomm_dlc_unlock(dlc);
+
+	rfcomm_dlc_put(dlc);
+	kfree(dev);
+
+	MOD_DEC_USE_COUNT;
+}
+
+static inline void rfcomm_dev_hold(struct rfcomm_dev *dev)
+{
+	atomic_inc(&dev->refcnt);
+}
+
+static inline void rfcomm_dev_put(struct rfcomm_dev *dev)
+{
+	if (atomic_dec_and_test(&dev->refcnt))
+		rfcomm_dev_destruct(dev);
+}
+
+static struct rfcomm_dev *__rfcomm_dev_get(int id)
+{
+	struct rfcomm_dev *dev;
+	struct list_head  *p;
+
+	list_for_each(p, &rfcomm_dev_list) {
+		dev = list_entry(p, struct rfcomm_dev, list);
+		if (dev->id == id)
+			return dev;
+	}
+
+	return NULL;
+}
+
+static inline struct rfcomm_dev *rfcomm_dev_get(int id)
+{
+	struct rfcomm_dev *dev;
+
+	read_lock(&rfcomm_dev_lock);
+	dev = __rfcomm_dev_get(id);
+	read_unlock(&rfcomm_dev_lock);
+
+	if (dev) rfcomm_dev_hold(dev);
+	return dev;
+}
+
+static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
+{
+	struct rfcomm_dev *dev;
+	struct list_head *head = &rfcomm_dev_list, *p;
+	int err = 0;
+
+	BT_DBG("id %d channel %d", req->dev_id, req->channel);
+	
+	dev = kmalloc(sizeof(struct rfcomm_dev), GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+	memset(dev, 0, sizeof(struct rfcomm_dev));
+
+	write_lock_bh(&rfcomm_dev_lock);
+
+	if (req->dev_id < 0) {
+		dev->id = 0;
+
+		list_for_each(p, &rfcomm_dev_list) {
+			if (list_entry(p, struct rfcomm_dev, list)->id != dev->id)
+				break;
+
+			dev->id++;
+			head = p;
+		}
+	} else {
+		dev->id = req->dev_id;
+
+		list_for_each(p, &rfcomm_dev_list) {
+			struct rfcomm_dev *entry = list_entry(p, struct rfcomm_dev, list);
+
+			if (entry->id == dev->id) {
+				err = -EADDRINUSE;
+				goto out;
+			}
+
+			if (entry->id > dev->id - 1)
+				break;
+
+			head = p;
+		}
+	}
+
+	if ((dev->id < 0) || (dev->id > RFCOMM_MAX_DEV - 1)) {
+		err = -ENFILE;
+		goto out;
+	}
+
+	sprintf(dev->name, "rfcomm%d", dev->id);
+
+	list_add(&dev->list, head);
+	atomic_set(&dev->refcnt, 1);
+
+	bacpy(&dev->src, &req->src);
+	bacpy(&dev->dst, &req->dst);
+	dev->channel = req->channel;
+
+	dev->flags = req->flags & 
+		((1 << RFCOMM_RELEASE_ONHUP) | (1 << RFCOMM_REUSE_DLC));
+
+	dev->sndbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
+
+	init_waitqueue_head(&dev->wait);
+	tasklet_init(&dev->wakeup_task, rfcomm_tty_wakeup, (unsigned long) dev);
+
+	rfcomm_dlc_lock(dlc);
+	dlc->data_ready   = rfcomm_dev_data_ready;
+	dlc->state_change = rfcomm_dev_state_change;
+	dlc->modem_status = rfcomm_dev_modem_status;
+
+	dlc->owner = dev;
+	dev->dlc   = dlc;
+	rfcomm_dlc_unlock(dlc);
+
+	MOD_INC_USE_COUNT;
+	
+out:
+	write_unlock_bh(&rfcomm_dev_lock);
+
+	if (err) {
+		kfree(dev);
+		return err;
+	} else
+		return dev->id;
+}
+
+static void rfcomm_dev_del(struct rfcomm_dev *dev)
+{
+	BT_DBG("dev %p", dev);
+
+	write_lock_bh(&rfcomm_dev_lock);
+	list_del_init(&dev->list);
+	write_unlock_bh(&rfcomm_dev_lock);
+
+	rfcomm_dev_put(dev);
+}
+
+/* ---- Send buffer ---- */
+static void rfcomm_wfree(struct sk_buff *skb)
+{
+	struct rfcomm_dev *dev = (void *) skb->sk;
+	atomic_sub(skb->truesize, &dev->wmem_alloc);
+	if (test_bit(RFCOMM_TTY_ATTACHED, &dev->flags))
+		tasklet_schedule(&dev->wakeup_task);
+	rfcomm_dev_put(dev);
+}
+
+static inline void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *dev)
+{
+	rfcomm_dev_hold(dev);
+	atomic_add(skb->truesize, &dev->wmem_alloc);
+	skb->sk = (void *) dev;
+	skb->destructor = rfcomm_wfree;
+}
+
+static struct sk_buff *rfcomm_wmalloc(struct rfcomm_dev *dev, unsigned long size, int priority)
+{
+	if (atomic_read(&dev->wmem_alloc) < dev->sndbuf) {
+		struct sk_buff *skb = alloc_skb(size, priority);
+		if (skb) {
+			rfcomm_set_owner_w(skb, dev);
+			return skb;
+		}
+	}
+	return NULL;
+}
+
+/* ---- Device IOCTLs ---- */
+
+#define NOCAP_FLAGS ((1 << RFCOMM_REUSE_DLC) | (1 << RFCOMM_RELEASE_ONHUP))
+
+static int rfcomm_create_dev(struct sock *sk, unsigned long arg)
+{
+	struct rfcomm_dev_req req;
+	struct rfcomm_dlc *dlc;
+	int id;
+
+	if (copy_from_user(&req, (void *) arg, sizeof(req)))
+		return -EFAULT;
+
+	BT_DBG("sk %p dev_id %id flags 0x%x", sk, req.dev_id, req.flags);
+
+	if (req.flags != NOCAP_FLAGS && !capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	if (req.flags & (1 << RFCOMM_REUSE_DLC)) {
+		/* Socket must be connected */
+		if (sk->state != BT_CONNECTED)
+			return -EBADFD;
+
+		dlc = rfcomm_pi(sk)->dlc;
+		rfcomm_dlc_hold(dlc);
+	} else {
+		dlc = rfcomm_dlc_alloc(GFP_KERNEL);
+		if (!dlc)
+			return -ENOMEM;
+	}
+
+	id = rfcomm_dev_add(&req, dlc);
+	if (id < 0) {
+		rfcomm_dlc_put(dlc);
+		return id;
+	}
+
+	if (req.flags & (1 << RFCOMM_REUSE_DLC)) {
+		/* DLC is now used by device.
+		 * Socket must be disconnected */
+		sk->state = BT_CLOSED;
+	}
+
+	return id;
+}
+
+static int rfcomm_release_dev(unsigned long arg)
+{
+	struct rfcomm_dev_req req;
+	struct rfcomm_dev *dev;
+
+	if (copy_from_user(&req, (void *) arg, sizeof(req)))
+		return -EFAULT;
+
+	BT_DBG("dev_id %id flags 0x%x", req.dev_id, req.flags);
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	if (!(dev = rfcomm_dev_get(req.dev_id)))
+		return -ENODEV;
+
+	if (req.flags & (1 << RFCOMM_HANGUP_NOW))
+		rfcomm_dlc_close(dev->dlc, 0);
+
+	rfcomm_dev_del(dev);
+	rfcomm_dev_put(dev);
+	return 0;
+}
+
+static int rfcomm_get_dev_list(unsigned long arg)
+{
+	struct rfcomm_dev_list_req *dl;
+	struct rfcomm_dev_info *di;
+	struct list_head *p;
+	int n = 0, size;
+	u16 dev_num;
+
+	BT_DBG("");
+
+	if (get_user(dev_num, (u16 *) arg))
+		return -EFAULT;
+
+	if (!dev_num)
+		return -EINVAL;
+
+	size = sizeof(*dl) + dev_num * sizeof(*di);
+
+	if (verify_area(VERIFY_WRITE, (void *)arg, size))
+		return -EFAULT;
+
+	if (!(dl = kmalloc(size, GFP_KERNEL)))
+		return -ENOMEM;
+
+	di = dl->dev_info;
+
+	read_lock_bh(&rfcomm_dev_lock);
+
+	list_for_each(p, &rfcomm_dev_list) {
+		struct rfcomm_dev *dev = list_entry(p, struct rfcomm_dev, list);
+		(di + n)->id      = dev->id;
+		(di + n)->flags   = dev->flags;
+		(di + n)->state   = dev->dlc->state;
+		(di + n)->channel = dev->channel;
+		bacpy(&(di + n)->src, &dev->src);
+		bacpy(&(di + n)->dst, &dev->dst);
+		if (++n >= dev_num)
+			break;
+	}
+
+	read_unlock_bh(&rfcomm_dev_lock);
+
+	dl->dev_num = n;
+	size = sizeof(*dl) + n * sizeof(*di);
+
+	copy_to_user((void *) arg, dl, size);
+	kfree(dl);
+	return 0;
+}
+
+static int rfcomm_get_dev_info(unsigned long arg)
+{
+	struct rfcomm_dev *dev;
+	struct rfcomm_dev_info di;
+	int err = 0;
+
+	BT_DBG("");
+
+	if (copy_from_user(&di, (void *)arg, sizeof(di)))
+		return -EFAULT;
+
+	if (!(dev = rfcomm_dev_get(di.id)))
+		return -ENODEV;
+
+	di.flags   = dev->flags;
+	di.channel = dev->channel;
+	di.state   = dev->dlc->state;
+	bacpy(&di.src, &dev->src);
+	bacpy(&di.dst, &dev->dst);
+
+	if (copy_to_user((void *)arg, &di, sizeof(di)))
+		err = -EFAULT;
+
+	rfcomm_dev_put(dev);
+	return err;
+}
+
+int rfcomm_dev_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg)
+{
+	BT_DBG("cmd %d arg %ld", cmd, arg);
+
+	switch (cmd) {
+	case RFCOMMCREATEDEV:
+		return rfcomm_create_dev(sk, arg);
+
+	case RFCOMMRELEASEDEV:
+		return rfcomm_release_dev(arg);
+
+	case RFCOMMGETDEVLIST:
+		return rfcomm_get_dev_list(arg);
+
+	case RFCOMMGETDEVINFO:
+		return rfcomm_get_dev_info(arg);
+	}
+
+	return -EINVAL;
+}
+
+/* ---- DLC callbacks ---- */
+static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb)
+{
+	struct rfcomm_dev *dev = dlc->owner;
+	struct tty_struct *tty;
+       
+	if (!dev || !(tty = dev->tty)) {
+		kfree_skb(skb);
+		return;
+	}
+
+	BT_DBG("dlc %p tty %p len %d", dlc, tty, skb->len);
+
+	if (test_bit(TTY_DONT_FLIP, &tty->flags)) {
+		register int i;
+		for (i = 0; i < skb->len; i++) {
+			if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+				tty_flip_buffer_push(tty);
+
+			tty_insert_flip_char(tty, skb->data[i], 0);
+		}
+		tty_flip_buffer_push(tty);
+	} else
+		tty->ldisc.receive_buf(tty, skb->data, NULL, skb->len);
+
+	kfree_skb(skb);
+}
+
+static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err)
+{
+	struct rfcomm_dev *dev = dlc->owner;
+	if (!dev)
+		return;
+	
+	BT_DBG("dlc %p dev %p err %d", dlc, dev, err);
+
+	dev->err = err;
+	wake_up_interruptible(&dev->wait);
+
+	if (dlc->state == BT_CLOSED) {
+		if (!dev->tty) {
+			if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) {
+				rfcomm_dev_hold(dev);
+				rfcomm_dev_del(dev);
+
+				/* We have to drop DLC lock here, otherwise
+				 * rfcomm_dev_put() will dead lock if it's the last refference */
+				rfcomm_dlc_unlock(dlc);
+				rfcomm_dev_put(dev);
+				rfcomm_dlc_lock(dlc);
+			}
+		} else 
+			tty_hangup(dev->tty);
+	}
+}
+
+static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig)
+{
+	struct rfcomm_dev *dev = dlc->owner;
+	if (!dev)
+		return;
+	
+	BT_DBG("dlc %p dev %p v24_sig 0x%02x", dlc, dev, v24_sig);
+
+	dev->modem_status = 
+		((v24_sig & RFCOMM_V24_RTC) ? (TIOCM_DSR | TIOCM_DTR) : 0) |
+		((v24_sig & RFCOMM_V24_RTR) ? (TIOCM_RTS | TIOCM_CTS) : 0) |
+		((v24_sig & RFCOMM_V24_IC)  ? TIOCM_RI : 0) |
+		((v24_sig & RFCOMM_V24_DV)  ? TIOCM_CD : 0);
+}
+
+/* ---- TTY functions ---- */
+static void rfcomm_tty_wakeup(unsigned long arg)
+{
+	struct rfcomm_dev *dev = (void *) arg;
+	struct tty_struct *tty = dev->tty;
+	if (!tty)
+		return;
+
+	BT_DBG("dev %p tty %p", dev, tty);
+
+	if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && tty->ldisc.write_wakeup)
+                (tty->ldisc.write_wakeup)(tty);
+
+	wake_up_interruptible(&tty->write_wait);
+#ifdef SERIAL_HAVE_POLL_WAIT
+	wake_up_interruptible(&tty->poll_wait);
+#endif
+}
+
+static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	struct rfcomm_dev *dev;
+	struct rfcomm_dlc *dlc;
+	int err, id;
+
+	id = MINOR(tty->device) - tty->driver.minor_start;
+
+	BT_DBG("tty %p id %d", tty, id);
+
+	dev = rfcomm_dev_get(id);
+	if (!dev)
+		return -ENODEV;
+
+	BT_DBG("dev %p dst %s channel %d opened %d", dev, batostr(&dev->dst), dev->channel, dev->opened);
+
+	if (dev->opened++ != 0)
+		return 0;
+
+	dlc = dev->dlc;
+
+	/* Attach TTY and open DLC */
+
+	rfcomm_dlc_lock(dlc);
+	tty->driver_data = dev;
+	dev->tty = tty;
+	rfcomm_dlc_unlock(dlc);
+	set_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
+
+	err = rfcomm_dlc_open(dlc, &dev->src, &dev->dst, dev->channel);
+	if (err < 0)
+		return err;
+
+	/* Wait for DLC to connect */
+	add_wait_queue(&dev->wait, &wait);
+	while (1) {
+		set_current_state(TASK_INTERRUPTIBLE);
+
+		if (dlc->state == BT_CLOSED) {
+			err = -dev->err;
+			break;
+		}
+
+		if (dlc->state == BT_CONNECTED)
+			break;
+
+		if (signal_pending(current)) {
+			err = -EINTR;
+			break;
+		}
+
+		schedule();
+	}
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&dev->wait, &wait);
+
+	return err;
+}
+
+static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp)
+{
+	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
+	if (!dev)
+		return;
+
+	BT_DBG("tty %p dev %p dlc %p opened %d", tty, dev, dev->dlc, dev->opened);
+
+	if (--dev->opened == 0) {
+		/* Close DLC and dettach TTY */
+		rfcomm_dlc_close(dev->dlc, 0);
+
+		clear_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
+		tasklet_kill(&dev->wakeup_task);
+
+		rfcomm_dlc_lock(dev->dlc);
+		tty->driver_data = NULL;
+		dev->tty = NULL;
+		rfcomm_dlc_unlock(dev->dlc);
+	}
+
+	rfcomm_dev_put(dev);
+}
+
+static int rfcomm_tty_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count)
+{
+	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
+	struct rfcomm_dlc *dlc = dev->dlc;
+	struct sk_buff *skb;
+	int err = 0, sent = 0, size;
+
+	BT_DBG("tty %p from_user %d count %d", tty, from_user, count);
+
+	while (count) {
+		size = min_t(uint, count, dlc->mtu);
+
+		if (from_user)
+			skb = rfcomm_wmalloc(dev, size + RFCOMM_SKB_RESERVE, GFP_KERNEL);
+		else
+			skb = rfcomm_wmalloc(dev, size + RFCOMM_SKB_RESERVE, GFP_ATOMIC);
+		
+		if (!skb)
+			break;
+
+		skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE);
+
+		if (from_user)
+			copy_from_user(skb_put(skb, size), buf + sent, size);
+		else
+			memcpy(skb_put(skb, size), buf + sent, size);
+
+		if ((err = rfcomm_dlc_send(dlc, skb)) < 0) {
+			kfree_skb(skb);
+			break;
+		}
+
+		sent  += size;
+		count -= size;
+	}
+
+	return sent ? sent : err;
+}
+
+static int rfcomm_tty_write_room(struct tty_struct *tty)
+{
+	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
+	struct rfcomm_dlc *dlc = dev->dlc;
+
+	BT_DBG("tty %p", tty);
+
+	return dlc->mtu * (dlc->tx_credits ? : 10);
+}
+
+static int rfcomm_tty_set_modem_status(uint cmd, struct rfcomm_dlc *dlc, uint status)
+{
+	u8 v24_sig, mask;
+
+	BT_DBG("dlc %p cmd 0x%02x", dlc, cmd);
+
+	if (cmd == TIOCMSET)
+		v24_sig = 0;
+	else
+		rfcomm_dlc_get_modem_status(dlc, &v24_sig);
+
+	mask =  ((status & TIOCM_DSR) ? RFCOMM_V24_RTC : 0) |
+		((status & TIOCM_DTR) ? RFCOMM_V24_RTC : 0) |
+		((status & TIOCM_RTS) ? RFCOMM_V24_RTR : 0) |
+		((status & TIOCM_CTS) ? RFCOMM_V24_RTR : 0) |
+		((status & TIOCM_RI)  ? RFCOMM_V24_IC  : 0) |
+		((status & TIOCM_CD)  ? RFCOMM_V24_DV  : 0);
+
+	if (cmd == TIOCMBIC)
+		v24_sig &= ~mask;
+	else
+		v24_sig |= mask;
+
+	rfcomm_dlc_set_modem_status(dlc, v24_sig);
+	return 0;
+}
+
+static int rfcomm_tty_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
+	struct rfcomm_dlc *dlc = dev->dlc;
+	uint status;
+	int err;
+
+	BT_DBG("tty %p cmd 0x%02x", tty, cmd);
+
+	switch (cmd) {
+	case TCGETS:
+		BT_DBG("TCGETS is not supported");
+		return -ENOIOCTLCMD;
+
+	case TCSETS:
+		BT_DBG("TCSETS is not supported");
+		return -ENOIOCTLCMD;
+
+	case TIOCMGET:
+		BT_DBG("TIOCMGET");
+
+		return put_user(dev->modem_status, (unsigned int *)arg);
+
+	case TIOCMSET: /* Turns on and off the lines as specified by the mask */
+	case TIOCMBIS: /* Turns on the lines as specified by the mask */
+	case TIOCMBIC: /* Turns off the lines as specified by the mask */
+		if ((err = get_user(status, (unsigned int *)arg)))
+			return err;
+		return rfcomm_tty_set_modem_status(cmd, dlc, status);
+
+	case TIOCMIWAIT:
+		BT_DBG("TIOCMIWAIT");
+		break;
+
+	case TIOCGICOUNT:
+		BT_DBG("TIOCGICOUNT");
+		break;
+
+	case TIOCGSERIAL:
+		BT_ERR("TIOCGSERIAL is not supported");
+		return -ENOIOCTLCMD;
+
+	case TIOCSSERIAL:
+		BT_ERR("TIOCSSERIAL is not supported");
+		return -ENOIOCTLCMD;
+
+	case TIOCSERGSTRUCT:
+		BT_ERR("TIOCSERGSTRUCT is not supported");
+		return -ENOIOCTLCMD;
+
+	case TIOCSERGETLSR:
+		BT_ERR("TIOCSERGETLSR is not supported");
+		return -ENOIOCTLCMD;
+
+	case TIOCSERCONFIG:
+		BT_ERR("TIOCSERCONFIG is not supported");
+		return -ENOIOCTLCMD;
+
+	default:
+		return -ENOIOCTLCMD;	/* ioctls which we must ignore */
+
+	}
+
+	return -ENOIOCTLCMD;
+}
+
+#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+static void rfcomm_tty_set_termios(struct tty_struct *tty, struct termios *old)
+{
+	BT_DBG("tty %p", tty);
+
+	if ((tty->termios->c_cflag == old->c_cflag) &&
+		(RELEVANT_IFLAG(tty->termios->c_iflag) == RELEVANT_IFLAG(old->c_iflag)))
+		return;
+
+	/* handle turning off CRTSCTS */
+	if ((old->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) {
+		BT_DBG("turning off CRTSCTS");
+	}
+}
+
+static void rfcomm_tty_throttle(struct tty_struct *tty)
+{
+	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
+
+	BT_DBG("tty %p dev %p", tty, dev);
+	
+	rfcomm_dlc_throttle(dev->dlc);
+}
+
+static void rfcomm_tty_unthrottle(struct tty_struct *tty)
+{
+	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
+
+	BT_DBG("tty %p dev %p", tty, dev);
+	
+	rfcomm_dlc_unthrottle(dev->dlc);
+}
+
+static int rfcomm_tty_chars_in_buffer(struct tty_struct *tty)
+{
+	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
+	struct rfcomm_dlc *dlc = dev->dlc;
+
+	BT_DBG("tty %p dev %p", tty, dev);
+
+	if (skb_queue_len(&dlc->tx_queue))
+		return dlc->mtu;
+
+	return 0;
+}
+
+static void rfcomm_tty_flush_buffer(struct tty_struct *tty)
+{
+	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
+	if (!dev)
+		return;
+
+	BT_DBG("tty %p dev %p", tty, dev);
+
+	skb_queue_purge(&dev->dlc->tx_queue);
+
+	if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && tty->ldisc.write_wakeup)
+		tty->ldisc.write_wakeup(tty);
+}
+
+static void rfcomm_tty_send_xchar(struct tty_struct *tty, char ch)
+{
+	BT_DBG("tty %p ch %c", tty, ch);
+}
+
+static void rfcomm_tty_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+	BT_DBG("tty %p timeout %d", tty, timeout);
+}
+
+static void rfcomm_tty_hangup(struct tty_struct *tty)
+{
+	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
+	if (!dev)
+		return;
+
+	BT_DBG("tty %p dev %p", tty, dev);
+
+	rfcomm_tty_flush_buffer(tty);
+
+	if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags))
+		rfcomm_dev_del(dev);
+}
+
+static int rfcomm_tty_read_proc(char *buf, char **start, off_t offset, int len, int *eof, void *unused)
+{
+	return 0;
+}
+
+/* ---- TTY structure ---- */
+static int    rfcomm_tty_refcount;       /* If we manage several devices */
+
+static struct tty_struct *rfcomm_tty_table[RFCOMM_TTY_PORTS];
+static struct termios *rfcomm_tty_termios[RFCOMM_TTY_PORTS];
+static struct termios *rfcomm_tty_termios_locked[RFCOMM_TTY_PORTS];
+
+static struct tty_driver rfcomm_tty_driver = {
+	magic:			TTY_DRIVER_MAGIC,
+	driver_name:		"rfcomm",
+#ifdef CONFIG_DEVFS_FS
+	name:			"bluetooth/rfcomm/%d",
+#else
+	name:			"rfcomm",
+#endif
+	major:			RFCOMM_TTY_MAJOR,
+	minor_start:		RFCOMM_TTY_MINOR,
+	num:			RFCOMM_TTY_PORTS,
+	type:			TTY_DRIVER_TYPE_SERIAL,
+	subtype:		SERIAL_TYPE_NORMAL,
+	flags:			TTY_DRIVER_REAL_RAW,
+
+	refcount:		&rfcomm_tty_refcount,
+	table:			rfcomm_tty_table,
+	termios:		rfcomm_tty_termios,
+	termios_locked:		rfcomm_tty_termios_locked,
+
+	open:			rfcomm_tty_open,
+	close:			rfcomm_tty_close,
+	write:			rfcomm_tty_write,
+	write_room:		rfcomm_tty_write_room,
+	chars_in_buffer:	rfcomm_tty_chars_in_buffer,
+	flush_buffer:		rfcomm_tty_flush_buffer,
+	ioctl:			rfcomm_tty_ioctl,
+	throttle:		rfcomm_tty_throttle,
+	unthrottle:		rfcomm_tty_unthrottle,
+	set_termios:		rfcomm_tty_set_termios,
+	send_xchar:		rfcomm_tty_send_xchar,
+	stop:			NULL,
+	start:			NULL,
+	hangup:			rfcomm_tty_hangup,
+	wait_until_sent:	rfcomm_tty_wait_until_sent,
+	read_proc:		rfcomm_tty_read_proc,
+};
+
+int rfcomm_init_ttys(void)
+{
+	int i;
+
+	/* Initalize our global data */
+	for (i = 0; i < RFCOMM_TTY_PORTS; i++)
+		rfcomm_tty_table[i] = NULL;
+
+	/* Register the TTY driver */
+	rfcomm_tty_driver.init_termios = tty_std_termios;
+	rfcomm_tty_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	rfcomm_tty_driver.flags = TTY_DRIVER_REAL_RAW;
+
+	if (tty_register_driver(&rfcomm_tty_driver)) {
+		BT_ERR("Can't register RFCOMM TTY driver");
+		return -1;
+	}
+
+	return 0;
+}
+
+void rfcomm_cleanup_ttys(void)
+{
+	tty_unregister_driver(&rfcomm_tty_driver);
+	return;
+}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/bluetooth/sco.c linux-2.4.21-pre6/net/bluetooth/sco.c
--- linux-2.4.20/net/bluetooth/sco.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/bluetooth/sco.c	2003-03-26 23:49:55.000000000 +0000
@@ -678,7 +678,7 @@
 		
 		opts.mtu = sco_pi(sk)->conn->mtu;
 
-		BT_INFO("mtu %d", opts.mtu);
+		BT_DBG("mtu %d", opts.mtu);
 
 		len = MIN(len, sizeof(opts));
 		if (copy_to_user(optval, (char *)&opts, len))
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/bluetooth/syms.c linux-2.4.21-pre6/net/bluetooth/syms.c
--- linux-2.4.20/net/bluetooth/syms.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.21-pre6/net/bluetooth/syms.c	2003-03-26 23:48:58.000000000 +0000
@@ -44,6 +44,9 @@
 /* HCI Core */
 EXPORT_SYMBOL(hci_register_dev);
 EXPORT_SYMBOL(hci_unregister_dev);
+EXPORT_SYMBOL(hci_suspend_dev);
+EXPORT_SYMBOL(hci_resume_dev);
+
 EXPORT_SYMBOL(hci_register_proto);
 EXPORT_SYMBOL(hci_unregister_proto);
 
@@ -56,7 +59,7 @@
 EXPORT_SYMBOL(hci_recv_frame);
 EXPORT_SYMBOL(hci_send_acl);
 EXPORT_SYMBOL(hci_send_sco);
-EXPORT_SYMBOL(hci_send_raw);
+EXPORT_SYMBOL(hci_send_cmd);
 EXPORT_SYMBOL(hci_si_event);
 
 /* BlueZ lib */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/bridge/br_if.c linux-2.4.21-pre6/net/bridge/br_if.c
--- linux-2.4.20/net/bridge/br_if.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/bridge/br_if.c	2003-03-26 23:49:55.000000000 +0000
@@ -143,7 +143,7 @@
 	int i;
 	struct net_bridge_port *p;
 
-	p = kmalloc(sizeof(*p), GFP_KERNEL);
+	p = kmalloc(sizeof(*p), GFP_ATOMIC);
 	if (p == NULL)
 		return p;
 
@@ -153,8 +153,6 @@
 	p->path_cost = br_initial_port_cost(dev);
 	p->priority = 0x80;
 
-	dev->br_port = p;
-
 	for (i=1;i<255;i++)
 		if (br_get_port(br, i) == NULL)
 			break;
@@ -164,6 +162,8 @@
 		return NULL;
 	}
 
+	dev->br_port = p;
+
 	p->port_no = i;
 	br_init_port(p);
 	p->state = BR_STATE_DISABLED;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/bridge/br_ioctl.c linux-2.4.21-pre6/net/bridge/br_ioctl.c
--- linux-2.4.20/net/bridge/br_ioctl.c	2000-11-09 23:57:53.000000000 +0000
+++ linux-2.4.21-pre6/net/bridge/br_ioctl.c	2003-03-26 23:49:07.000000000 +0000
@@ -230,7 +230,7 @@
 	return -EOPNOTSUPP;
 }
 
-DECLARE_MUTEX(ioctl_mutex);
+static DECLARE_MUTEX(ioctl_mutex);
 
 int br_ioctl_deviceless_stub(unsigned long arg)
 {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/core/dev.c linux-2.4.21-pre6/net/core/dev.c
--- linux-2.4.20/net/core/dev.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/core/dev.c	2003-03-26 23:49:39.000000000 +0000
@@ -2155,7 +2155,8 @@
 			    cmd == SIOCETHTOOL ||
 			    cmd == SIOCGMIIPHY ||
 			    cmd == SIOCGMIIREG ||
-			    cmd == SIOCSMIIREG) {
+			    cmd == SIOCSMIIREG ||
+			    cmd == SIOCWANDEV) {
 				if (dev->do_ioctl) {
 					if (!netif_device_present(dev))
 						return -ENODEV;
@@ -2321,8 +2322,9 @@
 		 */	
 		 
 		default:
-			if (cmd >= SIOCDEVPRIVATE &&
-			    cmd <= SIOCDEVPRIVATE + 15) {
+			if (cmd == SIOCWANDEV ||
+			    (cmd >= SIOCDEVPRIVATE &&
+			     cmd <= SIOCDEVPRIVATE + 15)) {
 				dev_load(ifr.ifr_name);
 				dev_probe_lock();
 				rtnl_lock();
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/core/skbuff.c linux-2.4.21-pre6/net/core/skbuff.c
--- linux-2.4.20/net/core/skbuff.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.21-pre6/net/core/skbuff.c	2003-03-26 23:49:09.000000000 +0000
@@ -731,6 +731,36 @@
 	return n;
 }
 
+/**
+ *	skb_pad			-	zero pad the tail of an skb
+ *	@skb: buffer to pad
+ *	@pad: space to pad
+ *
+ *	Ensure that a buffer is followed by a padding area that is zero
+ *	filled. Used by network drivers which may DMA or transfer data
+ *	beyond the buffer end onto the wire.
+ *
+ *	May return NULL in out of memory cases.
+ */
+ 
+struct sk_buff *skb_pad(struct sk_buff *skb, int pad)
+{
+	struct sk_buff *nskb;
+	
+	/* If the skbuff is non linear tailroom is always zero.. */
+	if(skb_tailroom(skb) >= pad)
+	{
+		memset(skb->data+skb->len, 0, pad);
+		return skb;
+	}
+	
+	nskb = skb_copy_expand(skb, skb_headroom(skb), skb_tailroom(skb) + pad, GFP_ATOMIC);
+	kfree_skb(skb);
+	if(nskb)
+		memset(nskb->data+nskb->len, 0, pad);
+	return nskb;
+}	
+ 
 /* Trims skb to length len. It can change skb pointers, if "realloc" is 1.
  * If realloc==0 and trimming is impossible without change of data,
  * it is BUG().
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/core/sock.c linux-2.4.21-pre6/net/core/sock.c
--- linux-2.4.20/net/core/sock.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.21-pre6/net/core/sock.c	2003-03-26 23:49:50.000000000 +0000
@@ -793,6 +793,7 @@
 					page = alloc_pages(sk->allocation, 0);
 					if (!page) {
 						err = -ENOBUFS;
+						skb_shinfo(skb)->nr_frags = i;
 						kfree_skb(skb);
 						goto failure;
 					}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/core/wireless.c linux-2.4.21-pre6/net/core/wireless.c
--- linux-2.4.20/net/core/wireless.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/core/wireless.c	2003-03-26 23:49:09.000000000 +0000
@@ -33,8 +33,16 @@
  *	o Propagate events as rtnetlink IFLA_WIRELESS option
  *	o Generate event on selected SET requests
  *
- * v4 - 18.04.01 - Jean II
+ * v4 - 18.04.02 - Jean II
  *	o Fix stupid off by one in iw_ioctl_description : IW_ESSID_MAX_SIZE + 1
+ *
+ * v5 - 21.06.02 - Jean II
+ *	o Add IW_PRIV_TYPE_ADDR in priv_type_size (+cleanup)
+ *	o Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes
+ *	o Add IWEVCUSTOM for driver specific event/scanning token
+ *	o Turn on WE_STRICT_WRITE by default + kernel warning
+ *	o Fix WE_STRICT_WRITE in ioctl_export_private() (32 => iw_num)
+ *	o Fix off-by-one in test (extra_size <= IFNAMSIZ)
  */
 
 /***************************** INCLUDES *****************************/
@@ -50,8 +58,9 @@
 
 /**************************** CONSTANTS ****************************/
 
-/* This will be turned on later on... */
-#undef WE_STRICT_WRITE		/* Check write buffer size */
+/* Enough lenience, let's make sure things are proper... */
+#define WE_STRICT_WRITE		/* Check write buffer size */
+/* I'll probably drop both the define and kernel message in the next version */
 
 /* Debuging stuff */
 #undef WE_IOCTL_DEBUG		/* Debug IOCTL API */
@@ -106,7 +115,7 @@
 	/* SIOCSIWSPY */
 	{ IW_HEADER_TYPE_POINT, 0, sizeof(struct sockaddr), 0, IW_MAX_SPY, 0},
 	/* SIOCGIWSPY */
-	{ IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_SPY, 0},
+	{ IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_GET_SPY, 0},
 	/* -- hole -- */
 	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
 	/* -- hole -- */
@@ -176,25 +185,41 @@
 	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
 	/* IWEVQUAL */
 	{ IW_HEADER_TYPE_QUAL, 0, 0, 0, 0, 0},
+	/* IWEVCUSTOM */
+	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_CUSTOM_MAX, 0},
+	/* IWEVREGISTERED */
+	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
+	/* IWEVEXPIRED */
+	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
 };
 static const int standard_event_num = (sizeof(standard_event) /
 				       sizeof(struct iw_ioctl_description));
 
 /* Size (in bytes) of the various private data types */
-static const char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 };
+static const char priv_type_size[] = {
+	0,				/* IW_PRIV_TYPE_NONE */
+	1,				/* IW_PRIV_TYPE_BYTE */
+	1,				/* IW_PRIV_TYPE_CHAR */
+	0,				/* Not defined */
+	sizeof(__u32),			/* IW_PRIV_TYPE_INT */
+	sizeof(struct iw_freq),		/* IW_PRIV_TYPE_FLOAT */
+	sizeof(struct sockaddr),	/* IW_PRIV_TYPE_ADDR */
+	0,				/* Not defined */
+};
 
 /* Size (in bytes) of various events */
 static const int event_type_size[] = {
-	IW_EV_LCP_LEN,
+	IW_EV_LCP_LEN,			/* IW_HEADER_TYPE_NULL */
+	0,
+	IW_EV_CHAR_LEN,			/* IW_HEADER_TYPE_CHAR */
 	0,
-	IW_EV_CHAR_LEN,
+	IW_EV_UINT_LEN,			/* IW_HEADER_TYPE_UINT */
+	IW_EV_FREQ_LEN,			/* IW_HEADER_TYPE_FREQ */
+	IW_EV_ADDR_LEN,			/* IW_HEADER_TYPE_ADDR */
 	0,
-	IW_EV_UINT_LEN,
-	IW_EV_FREQ_LEN,
 	IW_EV_POINT_LEN,		/* Without variable payload */
-	IW_EV_PARAM_LEN,
-	IW_EV_ADDR_LEN,
-	IW_EV_QUAL_LEN,
+	IW_EV_PARAM_LEN,		/* IW_HEADER_TYPE_PARAM */
+	IW_EV_QUAL_LEN,			/* IW_HEADER_TYPE_QUAL */
 };
 
 /************************ COMMON SUBROUTINES ************************/
@@ -440,8 +465,10 @@
 		return -EFAULT;
 #ifdef WE_STRICT_WRITE
 	/* Check if there is enough buffer up there */
-	if(iwr->u.data.length < (SIOCIWLASTPRIV - SIOCIWFIRSTPRIV + 1))
+	if(iwr->u.data.length < dev->wireless_handlers->num_private_args) {
+		printk(KERN_ERR "%s (WE) : Buffer for request SIOCGIWPRIV too small (%d<%d)\n", dev->name, iwr->u.data.length, dev->wireless_handlers->num_private_args);
 		return -E2BIG;
+	}
 #endif	/* WE_STRICT_WRITE */
 
 	/* Set the number of available ioctls. */
@@ -471,6 +498,7 @@
 	const struct iw_ioctl_description *	descr;
 	struct iw_request_info			info;
 	int					ret = -EINVAL;
+	int					user_size = 0;
 
 	/* Get the description of the IOCTL */
 	if((cmd - SIOCIWFIRST) >= standard_ioctl_num)
@@ -518,11 +546,8 @@
 			/* Check NULL pointer */
 			if(iwr->u.data.pointer == NULL)
 				return -EFAULT;
-#ifdef WE_STRICT_WRITE
-			/* Check if there is enough buffer up there */
-			if(iwr->u.data.length < descr->max_tokens)
-				return -E2BIG;
-#endif	/* WE_STRICT_WRITE */
+			/* Save user space buffer size for checking */
+			user_size = iwr->u.data.length;
 		}
 
 #ifdef WE_IOCTL_DEBUG
@@ -559,6 +584,15 @@
 
 		/* If we have something to return to the user */
 		if (!ret && IW_IS_GET(cmd)) {
+#ifdef WE_STRICT_WRITE
+			/* Check if there is enough buffer up there */
+			if(user_size < iwr->u.data.length) {
+				printk(KERN_ERR "%s (WE) : Buffer for request %04X too small (%d<%d)\n", dev->name, cmd, user_size, iwr->u.data.length);
+				kfree(extra);
+				return -E2BIG;
+			}
+#endif	/* WE_STRICT_WRITE */
+
 			err = copy_to_user(iwr->u.data.pointer, extra,
 					   iwr->u.data.length *
 					   descr->token_size);
@@ -646,12 +680,18 @@
 	/* Compute the size of the set/get arguments */
 	if(descr != NULL) {
 		if(IW_IS_SET(cmd)) {
+			int	offset = 0;	/* For sub-ioctls */
+			/* Check for sub-ioctl handler */
+			if(descr->name[0] == '\0')
+				/* Reserve one int for sub-ioctl index */
+				offset = sizeof(__u32);
+
 			/* Size of set arguments */
 			extra_size = get_priv_size(descr->set_args);
 
 			/* Does it fits in iwr ? */
 			if((descr->set_args & IW_PRIV_SIZE_FIXED) &&
-			   (extra_size < IFNAMSIZ))
+			   ((extra_size + offset) <= IFNAMSIZ))
 				extra_size = 0;
 		} else {
 			/* Size of set arguments */
@@ -659,7 +699,7 @@
 
 			/* Does it fits in iwr ? */
 			if((descr->get_args & IW_PRIV_SIZE_FIXED) &&
-			   (extra_size < IFNAMSIZ))
+			   (extra_size <= IFNAMSIZ))
 				extra_size = 0;
 		}
 	}
@@ -925,7 +965,7 @@
 		 * The best the driver could do is to log an error message.
 		 * We will do it ourselves instead...
 		 */
-	  	printk(KERN_ERR "%s (WE) : Invalid Wireless Event (0x%04X)\n",
+	  	printk(KERN_ERR "%s (WE) : Invalid/Unknown Wireless Event (0x%04X)\n",
 		       dev->name, cmd);
 		return;
 	}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/decnet/dn_nsp_in.c linux-2.4.21-pre6/net/decnet/dn_nsp_in.c
--- linux-2.4.20/net/decnet/dn_nsp_in.c	2001-11-09 22:12:54.000000000 +0000
+++ linux-2.4.21-pre6/net/decnet/dn_nsp_in.c	2003-03-26 23:49:26.000000000 +0000
@@ -565,26 +565,19 @@
  */
 static __inline__ int dn_queue_skb(struct sock *sk, struct sk_buff *skb, int sig, struct sk_buff_head *queue)
 {
-#ifdef CONFIG_FILTER
-	struct sk_filter *filter;
-#endif
+	int err;
 
         /* Cast skb->rcvbuf to unsigned... It's pointless, but reduces
            number of warnings when compiling with -W --ANK
          */
-        if (atomic_read(&sk->rmem_alloc) + skb->truesize >= (unsigned)sk->rcvbuf
-)
-                return -ENOMEM;
-
-#ifdef CONFIG_FILTER
-        if (sk->filter) {
-		int err = 0;
-                if ((filter = sk->filter) != NULL && sk_filter(skb, sk->filter))
-                        err = -EPERM;  /* Toss packet */
-		if (err)
-			return err;
+        if (atomic_read(&sk->rmem_alloc) + skb->truesize >= (unsigned)sk->rcvbuf) {
+        	err = -ENOMEM;
+        	goto out;
         }
-#endif /* CONFIG_FILTER */
+
+	err = sk_filter(sk, skb, 0);
+	if (err)
+		goto out;
 
         skb_set_owner_r(skb, sk);
         skb_queue_tail(queue, skb);
@@ -602,8 +595,8 @@
 				    (sig == SIGURG) ? POLL_PRI : POLL_IN);
 	}
 	read_unlock(&sk->callback_lock);
-
-        return 0;
+out:
+        return err;
 }
 
 static void dn_nsp_otherdata(struct sock *sk, struct sk_buff *skb)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/econet/af_econet.c linux-2.4.21-pre6/net/econet/af_econet.c
--- linux-2.4.20/net/econet/af_econet.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.21-pre6/net/econet/af_econet.c	2003-03-26 23:49:39.000000000 +0000
@@ -306,6 +306,7 @@
 		
 		eb = (struct ec_cb *)&skb->cb;
 		
+		/* BUG: saddr may be NULL */
 		eb->cookie = saddr->cookie;
 		eb->sec = *saddr;
 		eb->sent = ec_tx_done;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv4/af_inet.c linux-2.4.21-pre6/net/ipv4/af_inet.c
--- linux-2.4.20/net/ipv4/af_inet.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv4/af_inet.c	2003-03-26 23:49:07.000000000 +0000
@@ -1038,6 +1038,7 @@
 	struct list_head *lh;
 	struct inet_protosw *answer;
 	int protocol = p->protocol;
+	struct list_head *last_perm;
 
 	br_write_lock_bh(BR_NETPROTO_LOCK);
 
@@ -1046,24 +1047,29 @@
 
 	/* If we are trying to override a permanent protocol, bail. */
 	answer = NULL;
+	last_perm = &inetsw[p->type];
 	list_for_each(lh, &inetsw[p->type]) {
 		answer = list_entry(lh, struct inet_protosw, list);
 
 		/* Check only the non-wild match. */
-		if (protocol == answer->protocol &&
-		    (INET_PROTOSW_PERMANENT & answer->flags))
-			break;
+		if (INET_PROTOSW_PERMANENT & answer->flags) {
+			if (protocol == answer->protocol)
+				break;
+			last_perm = lh;
+		}
 
 		answer = NULL;
 	}
 	if (answer)
 		goto out_permanent;
 
-	/* Add to the BEGINNING so that we override any existing
-	 * entry.  This means that when we remove this entry, the
+	/* Add the new entry after the last permanent entry if any, so that
+	 * the new entry does not override a permanent entry when matched with
+	 * a wild-card protocol. But it is allowed to override any existing
+	 * non-permanent entry.  This means that when we remove this entry, the 
 	 * system automatically returns to the old behavior.
 	 */
-	list_add(&p->list, &inetsw[p->type]);
+	list_add(&p->list, last_perm);
 out:
 	br_write_unlock_bh(BR_NETPROTO_LOCK);
 	return;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv4/devinet.c linux-2.4.21-pre6/net/ipv4/devinet.c
--- linux-2.4.20/net/ipv4/devinet.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv4/devinet.c	2003-03-26 23:49:19.000000000 +0000
@@ -786,6 +786,34 @@
 	return notifier_chain_unregister(&inetaddr_chain,nb);
 }
 
+/* Rename ifa_labels for a device name change. Make some effort to preserve existing
+ * alias numbering and to create unique labels if possible.
+*/
+static void inetdev_changename(struct net_device *dev, struct in_device *in_dev)
+{ 
+	struct in_ifaddr *ifa;
+	int named = 0;
+
+	for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) { 
+		char old[IFNAMSIZ], *dot; 
+
+		memcpy(old, ifa->ifa_label, IFNAMSIZ);
+		memcpy(ifa->ifa_label, dev->name, IFNAMSIZ); 
+		if (named++ == 0)
+			continue;
+		dot = strchr(ifa->ifa_label, ':');
+		if (dot == NULL) { 
+			sprintf(old, ":%d", named); 
+			dot = old;
+		}
+		if (strlen(dot) + strlen(dev->name) < IFNAMSIZ) { 
+			strcat(ifa->ifa_label, dot); 
+		} else { 
+			strcpy(ifa->ifa_label + (IFNAMSIZ - strlen(dot) - 1), dot); 
+		} 
+	}	
+} 
+
 /* Called only under RTNL semaphore */
 
 static int inetdev_event(struct notifier_block *this, unsigned long event, void *ptr)
@@ -833,14 +861,10 @@
 		inetdev_destroy(in_dev);
 		break;
 	case NETDEV_CHANGENAME:
-		if (in_dev->ifa_list) {
-			struct in_ifaddr *ifa;
-			for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next)
-				memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
-			/* Do not notify about label change, this event is
-			   not interesting to applications using netlink.
-			 */
-		}
+		/* Do not notify about label change, this event is
+		 * not interesting to applications using netlink.
+		 */
+		inetdev_changename(dev, in_dev);
 		break;
 	}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv4/fib_semantics.c linux-2.4.21-pre6/net/ipv4/fib_semantics.c
--- linux-2.4.20/net/ipv4/fib_semantics.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv4/fib_semantics.c	2003-03-26 23:49:09.000000000 +0000
@@ -1025,7 +1025,8 @@
 		len = sprintf(buffer, "%s\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u",
 			      fi->fib_dev ? fi->fib_dev->name : "*", prefix,
 			      fi->fib_nh->nh_gw, flags, 0, 0, fi->fib_priority,
-			      mask, fi->fib_advmss+40, fi->fib_window, fi->fib_rtt>>3);
+			      mask, (fi->fib_advmss ? fi->fib_advmss+40 : 0),
+			      fi->fib_window, fi->fib_rtt>>3);
 	} else {
 		len = sprintf(buffer, "*\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u",
 			      prefix, 0,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv4/icmp.c linux-2.4.21-pre6/net/ipv4/icmp.c
--- linux-2.4.20/net/ipv4/icmp.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv4/icmp.c	2003-03-26 23:49:30.000000000 +0000
@@ -178,55 +178,27 @@
 static struct icmp_control icmp_pointers[NR_ICMP_TYPES+1];
 
 /*
- *	The ICMP socket. This is the most convenient way to flow control
+ *	The ICMP socket(s). This is the most convenient way to flow control
  *	our ICMP output as well as maintain a clean interface throughout
  *	all layers. All Socketless IP sends will soon be gone.
  */
 	
-struct inode icmp_inode;
-struct socket *icmp_socket = &icmp_inode.u.socket_i;
+static struct inode __icmp_inode[NR_CPUS];
+#define icmp_socket (&__icmp_inode[smp_processor_id()].u.socket_i)
+#define icmp_socket_cpu(X) (&__icmp_inode[(X)].u.socket_i)
 
-/* ICMPv4 socket is only a bit non-reenterable (unlike ICMPv6,
-   which is strongly non-reenterable). A bit later it will be made
-   reenterable and the lock may be removed then.
- */
-
-static int icmp_xmit_holder = -1;
-
-static int icmp_xmit_lock_bh(void)
-{
-	if (!spin_trylock(&icmp_socket->sk->lock.slock)) {
-		if (icmp_xmit_holder == smp_processor_id())
-			return -EAGAIN;
-		spin_lock(&icmp_socket->sk->lock.slock);
-	}
-	icmp_xmit_holder = smp_processor_id();
-	return 0;
-}
-
-static __inline__ int icmp_xmit_lock(void)
+static void icmp_xmit_lock(void)
 {
-	int ret;
 	local_bh_disable();
-	ret = icmp_xmit_lock_bh();
-	if (ret)
-		local_bh_enable();
-	return ret;
-}
-
-static void icmp_xmit_unlock_bh(void)
-{
-	icmp_xmit_holder = -1;
-	spin_unlock(&icmp_socket->sk->lock.slock);
+	if (unlikely(!spin_trylock(&icmp_socket->sk->lock.slock)))
+		BUG();
 }
 
-static __inline__ void icmp_xmit_unlock(void)
+static void icmp_xmit_unlock(void)
 {
-	icmp_xmit_unlock_bh();
-	local_bh_enable();
+	spin_unlock_bh(&icmp_socket->sk->lock.slock);
 }
 
-
 /*
  *	Send an ICMP frame.
  */
@@ -348,8 +320,7 @@
 	if (ip_options_echo(&icmp_param->replyopts, skb))
 		return;
 
-	if (icmp_xmit_lock_bh())
-		return;
+	icmp_xmit_lock();
 
 	icmp_param->data.icmph.checksum=0;
 	icmp_param->csum=0;
@@ -374,7 +345,7 @@
 	}
 	ip_rt_put(rt);
 out:
-	icmp_xmit_unlock_bh();
+	icmp_xmit_unlock();
 }
 
 
@@ -456,8 +427,7 @@
 		}
 	}
 
-	if (icmp_xmit_lock())
-		return;
+	icmp_xmit_lock();
 
 	/*
 	 *	Construct source address and options.
@@ -985,29 +955,32 @@
 
 void __init icmp_init(struct net_proto_family *ops)
 {
-	int err;
+	int err, i;
 
-	icmp_inode.i_mode = S_IFSOCK;
-	icmp_inode.i_sock = 1;
-	icmp_inode.i_uid = 0;
-	icmp_inode.i_gid = 0;
-	init_waitqueue_head(&icmp_inode.i_wait);
-	init_waitqueue_head(&icmp_inode.u.socket_i.wait);
-
-	icmp_socket->inode = &icmp_inode;
-	icmp_socket->state = SS_UNCONNECTED;
-	icmp_socket->type=SOCK_RAW;
-
-	if ((err=ops->create(icmp_socket, IPPROTO_ICMP))<0)
-		panic("Failed to create the ICMP control socket.\n");
-	icmp_socket->sk->allocation=GFP_ATOMIC;
-	icmp_socket->sk->sndbuf = SK_WMEM_MAX*2;
-	icmp_socket->sk->protinfo.af_inet.ttl = MAXTTL;
-	icmp_socket->sk->protinfo.af_inet.pmtudisc = IP_PMTUDISC_DONT;
-
-	/* Unhash it so that IP input processing does not even
-	 * see it, we do not wish this socket to see incoming
-	 * packets.
-	 */
-	icmp_socket->sk->prot->unhash(icmp_socket->sk);
+	for (i = 0; i < NR_CPUS; i++) {
+		__icmp_inode[i].i_mode = S_IFSOCK;
+		__icmp_inode[i].i_sock = 1;
+		__icmp_inode[i].i_uid = 0;
+		__icmp_inode[i].i_gid = 0;
+		init_waitqueue_head(&__icmp_inode[i].i_wait);
+		init_waitqueue_head(&__icmp_inode[i].u.socket_i.wait);
+
+		icmp_socket_cpu(i)->inode = &__icmp_inode[i];
+		icmp_socket_cpu(i)->state = SS_UNCONNECTED;
+		icmp_socket_cpu(i)->type = SOCK_RAW;
+
+		if ((err=ops->create(icmp_socket_cpu(i), IPPROTO_ICMP)) < 0)
+			panic("Failed to create the ICMP control socket.\n");
+
+		icmp_socket_cpu(i)->sk->allocation=GFP_ATOMIC;
+		icmp_socket_cpu(i)->sk->sndbuf = SK_WMEM_MAX*2;
+		icmp_socket_cpu(i)->sk->protinfo.af_inet.ttl = MAXTTL;
+		icmp_socket_cpu(i)->sk->protinfo.af_inet.pmtudisc = IP_PMTUDISC_DONT;
+
+		/* Unhash it so that IP input processing does not even
+		 * see it, we do not wish this socket to see incoming
+		 * packets.
+		 */
+		icmp_socket_cpu(i)->sk->prot->unhash(icmp_socket_cpu(i)->sk);
+	}
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv4/ip_fragment.c linux-2.4.21-pre6/net/ipv4/ip_fragment.c
--- linux-2.4.20/net/ipv4/ip_fragment.c	2002-02-25 19:38:14.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv4/ip_fragment.c	2003-03-26 23:49:20.000000000 +0000
@@ -19,6 +19,7 @@
  *		Bill Hawes	:	Frag accounting and evictor fixes.
  *		John McDonald	:	0 length frag bug.
  *		Alexey Kuznetsov:	SMP races, threading, cleanup.
+ *		Patrick McHardy :	LRU queue of frag heads for evictor.
  */
 
 #include <linux/config.h>
@@ -26,6 +27,7 @@
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/skbuff.h>
+#include <linux/list.h>
 #include <linux/ip.h>
 #include <linux/icmp.h>
 #include <linux/netdevice.h>
@@ -67,6 +69,7 @@
 /* Describe an entry in the "incomplete datagrams" queue. */
 struct ipq {
 	struct ipq	*next;		/* linked list pointers			*/
+	struct list_head lru_list;	/* lru list member 			*/
 	u32		saddr;
 	u32		daddr;
 	u16		id;
@@ -94,6 +97,7 @@
 /* Per-bucket lock is easy to add now. */
 static struct ipq *ipq_hash[IPQ_HASHSZ];
 static rwlock_t ipfrag_lock = RW_LOCK_UNLOCKED;
+static LIST_HEAD(ipq_lru_list);
 int ip_frag_nqueues = 0;
 
 static __inline__ void __ipq_unlink(struct ipq *qp)
@@ -101,6 +105,7 @@
 	if(qp->next)
 		qp->next->pprev = qp->pprev;
 	*qp->pprev = qp->next;
+	list_del(&qp->lru_list);
 	ip_frag_nqueues--;
 }
 
@@ -202,39 +207,30 @@
  */
 static void ip_evictor(void)
 {
-	int i, progress;
+	struct ipq *qp;
+	struct list_head *tmp;
 
-	do {
+	for(;;) {
 		if (atomic_read(&ip_frag_mem) <= sysctl_ipfrag_low_thresh)
 			return;
-		progress = 0;
-		/* FIXME: Make LRU queue of frag heads. -DaveM */
-		for (i = 0; i < IPQ_HASHSZ; i++) {
-			struct ipq *qp;
-			if (ipq_hash[i] == NULL)
-				continue;
-
-			read_lock(&ipfrag_lock);
-			if ((qp = ipq_hash[i]) != NULL) {
-				/* find the oldest queue for this hash bucket */
-				while (qp->next)
-					qp = qp->next;
-				atomic_inc(&qp->refcnt);
-				read_unlock(&ipfrag_lock);
-
-				spin_lock(&qp->lock);
-				if (!(qp->last_in&COMPLETE))
-					ipq_kill(qp);
-				spin_unlock(&qp->lock);
-
-				ipq_put(qp);
-				IP_INC_STATS_BH(IpReasmFails);
-				progress = 1;
-				continue;
-			}
+		read_lock(&ipfrag_lock);
+		if (list_empty(&ipq_lru_list)) {
 			read_unlock(&ipfrag_lock);
+			return;
 		}
-	} while (progress);
+		tmp = ipq_lru_list.next;
+		qp = list_entry(tmp, struct ipq, lru_list);
+		atomic_inc(&qp->refcnt);
+		read_unlock(&ipfrag_lock);
+
+		spin_lock(&qp->lock);
+		if (!(qp->last_in&COMPLETE))
+			ipq_kill(qp);
+		spin_unlock(&qp->lock);
+
+		ipq_put(qp);
+		IP_INC_STATS_BH(IpReasmFails);
+	}
 }
 
 /*
@@ -302,6 +298,8 @@
 		qp->next->pprev = &qp->next;
 	ipq_hash[hash] = qp;
 	qp->pprev = &ipq_hash[hash];
+	INIT_LIST_HEAD(&qp->lru_list);
+	list_add_tail(&qp->lru_list, &ipq_lru_list);
 	ip_frag_nqueues++;
 	write_unlock(&ipfrag_lock);
 	return qp;
@@ -496,6 +494,10 @@
 	if (offset == 0)
 		qp->last_in |= FIRST_IN;
 
+	write_lock(&ipfrag_lock);
+	list_move_tail(&qp->lru_list, &ipq_lru_list);
+	write_unlock(&ipfrag_lock);
+
 	return;
 
 err:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv4/netfilter/ip_conntrack_core.c linux-2.4.21-pre6/net/ipv4/netfilter/ip_conntrack_core.c
--- linux-2.4.20/net/ipv4/netfilter/ip_conntrack_core.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv4/netfilter/ip_conntrack_core.c	2003-03-26 23:48:57.000000000 +0000
@@ -13,9 +13,6 @@
  *	- export ip_conntrack[_expect]_{find_get,put} functions
  * */
 
-#ifdef MODULE
-#define __NO_VERSION__
-#endif
 #include <linux/version.h>
 #include <linux/config.h>
 #include <linux/types.h>
@@ -292,9 +289,6 @@
 {
 	DEBUGP("clean_from_lists(%p)\n", ct);
 	MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
-	/* Remove from both hash lists: must not NULL out next ptrs,
-           otherwise we'll look unconfirmed.  Fortunately, LIST_DELETE
-           doesn't do this. --RR */
 	LIST_DELETE(&ip_conntrack_hash
 		    [hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple)],
 		    &ct->tuplehash[IP_CT_DIR_ORIGINAL]);
@@ -467,6 +461,7 @@
 		ct->timeout.expires += jiffies;
 		add_timer(&ct->timeout);
 		atomic_inc(&ct->ct_general.use);
+		set_bit(IPS_CONFIRMED_BIT, &ct->status);
 		WRITE_UNLOCK(&ip_conntrack_lock);
 		return NF_ACCEPT;
 	}
@@ -585,7 +580,7 @@
    connection.  Too bad: we're in trouble anyway. */
 static inline int unreplied(const struct ip_conntrack_tuple_hash *i)
 {
-	return !(i->ctrack->status & IPS_ASSURED);
+	return !(test_bit(IPS_ASSURED_BIT, &i->ctrack->status));
 }
 
 static int early_drop(struct list_head *chain)
@@ -720,7 +715,7 @@
 			conntrack, expected);
 		/* Welcome, Mr. Bond.  We've been expecting you... */
 		IP_NF_ASSERT(master_ct(conntrack));
-		conntrack->status = IPS_EXPECTED;
+		__set_bit(IPS_EXPECTED_BIT, &conntrack->status);
 		conntrack->master = expected;
 		expected->sibling = conntrack;
 		LIST_DELETE(&ip_conntrack_expect_list, expected);
@@ -768,11 +763,11 @@
 		*set_reply = 1;
 	} else {
 		/* Once we've had two way comms, always ESTABLISHED. */
-		if (h->ctrack->status & IPS_SEEN_REPLY) {
+		if (test_bit(IPS_SEEN_REPLY_BIT, &h->ctrack->status)) {
 			DEBUGP("ip_conntrack_in: normal packet for %p\n",
 			       h->ctrack);
 		        *ctinfo = IP_CT_ESTABLISHED;
-		} else if (h->ctrack->status & IPS_EXPECTED) {
+		} else if (test_bit(IPS_EXPECTED_BIT, &h->ctrack->status)) {
 			DEBUGP("ip_conntrack_in: related packet for %p\n",
 			       h->ctrack);
 			*ctinfo = IP_CT_RELATED;
@@ -966,23 +961,28 @@
 		   related_to->expecting >= related_to->helper->max_expected) {
 		struct list_head *cur_item;
 		/* old == NULL */
-	    	if (net_ratelimit())
-		    	printk(KERN_WARNING 
-		    	       "ip_conntrack: max number of expected "
-			       "connections %i of %s reached for "
-			       "%u.%u.%u.%u->%u.%u.%u.%u%s\n",
-		    	       related_to->helper->max_expected, 
-		    	       related_to->helper->name,
-		    	       NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip),
-		    	       NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip),
-		    	       related_to->helper->flags & IP_CT_HELPER_F_REUSE_EXPECT ?
-		    	       ", reusing" : "");
 		if (!(related_to->helper->flags & 
 		      IP_CT_HELPER_F_REUSE_EXPECT)) {
 			WRITE_UNLOCK(&ip_conntrack_lock);
+ 		    	if (net_ratelimit())
+ 			    	printk(KERN_WARNING
+				       "ip_conntrack: max number of expected "
+				       "connections %i of %s reached for "
+				       "%u.%u.%u.%u->%u.%u.%u.%u\n",
+				       related_to->helper->max_expected,
+				       related_to->helper->name,
+ 		    	       	       NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip),
+ 		    	       	       NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip));
 			return -EPERM;
 		}
-
+		DEBUGP("ip_conntrack: max number of expected "
+		       "connections %i of %s reached for "
+		       "%u.%u.%u.%u->%u.%u.%u.%u, reusing\n",
+ 		       related_to->helper->max_expected,
+		       related_to->helper->name,
+		       NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip),
+		       NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip));
+ 
 		/* choose the the oldest expectation to evict */
 		list_for_each(cur_item, &related_to->sibling_list) { 
 			struct ip_conntrack_expect *cur;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv4/netfilter/ip_conntrack_ftp.c linux-2.4.21-pre6/net/ipv4/netfilter/ip_conntrack_ftp.c
--- linux-2.4.20/net/ipv4/netfilter/ip_conntrack_ftp.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv4/netfilter/ip_conntrack_ftp.c	2003-03-26 23:49:51.000000000 +0000
@@ -32,7 +32,7 @@
 
 static int try_rfc959(const char *, size_t, u_int32_t [], char);
 static int try_eprt(const char *, size_t, u_int32_t [], char);
-static int try_espv_response(const char *, size_t, u_int32_t [], char);
+static int try_epsv_response(const char *, size_t, u_int32_t [], char);
 
 static struct ftp_search {
 	enum ip_conntrack_dir dir;
@@ -65,7 +65,7 @@
 		IP_CT_DIR_REPLY,
 		"229 ", sizeof("229 ") - 1, '(', ')',
 		IP_CT_FTP_EPSV,
-		try_espv_response,
+		try_epsv_response,
 	},
 };
 
@@ -157,7 +157,7 @@
 }
 
 /* Returns 0, or length of numbers: |||6446| */
-static int try_espv_response(const char *data, size_t dlen, u_int32_t array[6],
+static int try_epsv_response(const char *data, size_t dlen, u_int32_t array[6],
 			     char term)
 {
 	char delim;
@@ -200,9 +200,9 @@
 
 		DEBUGP("ftp: string mismatch\n");
 		for (i = 0; i < plen; i++) {
-			DEBUGFTP("ftp:char %u `%c'(%u) vs `%c'(%u)\n",
-				 i, data[i], data[i],
-				 pattern[i], pattern[i]);
+			DEBUGP("ftp:char %u `%c'(%u) vs `%c'(%u)\n",
+				i, data[i], data[i],
+				pattern[i], pattern[i]);
 		}
 #endif
 		return 0;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv4/netfilter/ip_conntrack_proto_tcp.c linux-2.4.21-pre6/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
--- linux-2.4.20/net/ipv4/netfilter/ip_conntrack_proto_tcp.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv4/netfilter/ip_conntrack_proto_tcp.c	2003-03-26 23:49:55.000000000 +0000
@@ -1,4 +1,3 @@
-#define __NO_VERSION__
 #include <linux/types.h>
 #include <linux/sched.h>
 #include <linux/timer.h>
@@ -186,13 +185,13 @@
 	    && tcph->syn && tcph->ack)
 		conntrack->proto.tcp.handshake_ack
 			= htonl(ntohl(tcph->seq) + 1);
-	WRITE_UNLOCK(&tcp_lock);
 
 	/* If only reply is a RST, we can consider ourselves not to
 	   have an established connection: this is a fairly common
 	   problem case, so we can delete the conntrack
 	   immediately.  --RR */
-	if (!(conntrack->status & IPS_SEEN_REPLY) && tcph->rst) {
+	if (!test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status) && tcph->rst) {
+		WRITE_UNLOCK(&tcp_lock);
 		if (del_timer(&conntrack->timeout))
 			conntrack->timeout.function((unsigned long)conntrack);
 	} else {
@@ -203,6 +202,7 @@
 		    && tcph->ack_seq == conntrack->proto.tcp.handshake_ack)
 			set_bit(IPS_ASSURED_BIT, &conntrack->status);
 
+		WRITE_UNLOCK(&tcp_lock);
 		ip_ct_refresh(conntrack, tcp_timeouts[newconntrack]);
 	}
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv4/netfilter/ip_conntrack_proto_udp.c linux-2.4.21-pre6/net/ipv4/netfilter/ip_conntrack_proto_udp.c
--- linux-2.4.20/net/ipv4/netfilter/ip_conntrack_proto_udp.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv4/netfilter/ip_conntrack_proto_udp.c	2003-03-26 23:48:57.000000000 +0000
@@ -51,7 +51,7 @@
 {
 	/* If we've seen traffic both ways, this is some kind of UDP
 	   stream.  Extend timeout. */
-	if (conntrack->status & IPS_SEEN_REPLY) {
+	if (test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) {
 		ip_ct_refresh(conntrack, UDP_STREAM_TIMEOUT);
 		/* Also, more likely to be important, and not a probe */
 		set_bit(IPS_ASSURED_BIT, &conntrack->status);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv4/netfilter/ip_conntrack_standalone.c linux-2.4.21-pre6/net/ipv4/netfilter/ip_conntrack_standalone.c
--- linux-2.4.20/net/ipv4/netfilter/ip_conntrack_standalone.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv4/netfilter/ip_conntrack_standalone.c	2003-03-26 23:49:35.000000000 +0000
@@ -77,7 +77,7 @@
 }
 
 static unsigned int
-print_conntrack(char *buffer, const struct ip_conntrack *conntrack)
+print_conntrack(char *buffer, struct ip_conntrack *conntrack)
 {
 	unsigned int len;
 	struct ip_conntrack_protocol *proto
@@ -95,12 +95,12 @@
 	len += print_tuple(buffer + len,
 			   &conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
 			   proto);
-	if (!(conntrack->status & IPS_SEEN_REPLY))
+	if (!(test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)))
 		len += sprintf(buffer + len, "[UNREPLIED] ");
 	len += print_tuple(buffer + len,
 			   &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple,
 			   proto);
-	if (conntrack->status & IPS_ASSURED)
+	if (test_bit(IPS_ASSURED_BIT, &conntrack->status))
 		len += sprintf(buffer + len, "[ASSURED] ");
 	len += sprintf(buffer + len, "use=%u ",
 		       atomic_read(&conntrack->ct_general.use));
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv4/netfilter/ip_nat_core.c linux-2.4.21-pre6/net/ipv4/netfilter/ip_nat_core.c
--- linux-2.4.20/net/ipv4/netfilter/ip_nat_core.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv4/netfilter/ip_nat_core.c	2003-03-26 23:49:08.000000000 +0000
@@ -2,9 +2,6 @@
 
 /* (c) 1999 Paul `Rusty' Russell.  Licenced under the GNU General
    Public Licence. */
-#ifdef MODULE
-#define __NO_VERSION__
-#endif
 #include <linux/version.h>
 #include <linux/module.h>
 #include <linux/types.h>
@@ -915,7 +912,7 @@
 		   packet, except it was never src/dst reversed, so
 		   where we would normally apply a dst manip, we apply
 		   a src, and vice versa. */
-		if (info->manips[i].hooknum == opposite_hook[hooknum]) {
+		if (info->manips[i].hooknum == hooknum) {
 			DEBUGP("icmp_reply: inner %s -> %u.%u.%u.%u %u\n",
 			       info->manips[i].maniptype == IP_NAT_MANIP_SRC
 			       ? "DST" : "SRC",
@@ -926,9 +923,9 @@
 				  &info->manips[i].manip,
 				  !info->manips[i].maniptype,
 				  &skb->nfcache);
-		/* Outer packet needs to have IP header NATed like
-                   it's a reply. */
-		} else if (info->manips[i].hooknum == hooknum) {
+			/* Outer packet needs to have IP header NATed like
+	                   it's a reply. */
+
 			/* Use mapping to map outer packet: 0 give no
                            per-proto mapping */
 			DEBUGP("icmp_reply: outer %s -> %u.%u.%u.%u\n",
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv4/netfilter/ip_nat_helper.c linux-2.4.21-pre6/net/ipv4/netfilter/ip_nat_helper.c
--- linux-2.4.20/net/ipv4/netfilter/ip_nat_helper.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv4/netfilter/ip_nat_helper.c	2003-03-26 23:49:09.000000000 +0000
@@ -8,6 +8,9 @@
  *		- add support for SACK adjustment 
  *	14 Mar 2002 Harald Welte <laforge@gnumonks.org>:
  *		- merge SACK support into newnat API
+ *	16 Aug 2002 Brian J. Murrell <netfilter@interlinx.bc.ca>:
+ *		- make ip_nat_resize_packet more generic (TCP and UDP)
+ *		- add ip_nat_mangle_udp_packet
  */
 #include <linux/version.h>
 #include <linux/config.h>
@@ -22,6 +25,7 @@
 #include <net/icmp.h>
 #include <net/ip.h>
 #include <net/tcp.h>
+#include <net/udp.h>
 
 #define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_nat_lock)
 #define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_nat_lock)
@@ -51,18 +55,12 @@
 		     int new_size)
 {
 	struct iphdr *iph;
-	struct tcphdr *tcph;
-	void *data;
 	int dir;
 	struct ip_nat_seq *this_way, *other_way;
 
 	DEBUGP("ip_nat_resize_packet: old_size = %u, new_size = %u\n",
 		(*skb)->len, new_size);
 
-	iph = (*skb)->nh.iph;
-	tcph = (void *)iph + iph->ihl*4;
-	data = (void *)tcph + tcph->doff*4;
-
 	dir = CTINFO2DIR(ctinfo);
 
 	this_way = &ct->nat.info.seq[dir];
@@ -84,37 +82,41 @@
 	}
 
 	iph = (*skb)->nh.iph;
-	tcph = (void *)iph + iph->ihl*4;
-	data = (void *)tcph + tcph->doff*4;
-
-	DEBUGP("ip_nat_resize_packet: Seq_offset before: ");
-	DUMP_OFFSET(this_way);
+	if (iph->protocol == IPPROTO_TCP) {
+		struct tcphdr *tcph = (void *)iph + iph->ihl*4;
+		void *data = (void *)tcph + tcph->doff*4;
+
+		DEBUGP("ip_nat_resize_packet: Seq_offset before: ");
+		DUMP_OFFSET(this_way);
+
+		LOCK_BH(&ip_nat_seqofs_lock);
+
+		/* SYN adjust. If it's uninitialized, of this is after last 
+		 * correction, record it: we don't handle more than one 
+		 * adjustment in the window, but do deal with common case of a 
+		 * retransmit */
+		if (this_way->offset_before == this_way->offset_after
+		    || before(this_way->correction_pos, ntohl(tcph->seq))) {
+			this_way->correction_pos = ntohl(tcph->seq);
+			this_way->offset_before = this_way->offset_after;
+			this_way->offset_after = (int32_t)
+				this_way->offset_before + new_size -
+				(*skb)->len;
+		}
 
-	LOCK_BH(&ip_nat_seqofs_lock);
+		UNLOCK_BH(&ip_nat_seqofs_lock);
 
-	/* SYN adjust. If it's uninitialized, of this is after last 
-	 * correction, record it: we don't handle more than one 
-	 * adjustment in the window, but do deal with common case of a 
-	 * retransmit */
-	if (this_way->offset_before == this_way->offset_after
-	    || before(this_way->correction_pos, ntohl(tcph->seq))) {
-		this_way->correction_pos = ntohl(tcph->seq);
-		this_way->offset_before = this_way->offset_after;
-		this_way->offset_after = (int32_t)
-			this_way->offset_before + new_size - (*skb)->len;
+		DEBUGP("ip_nat_resize_packet: Seq_offset after: ");
+		DUMP_OFFSET(this_way);
 	}
-
-	UNLOCK_BH(&ip_nat_seqofs_lock);
-
-	DEBUGP("ip_nat_resize_packet: Seq_offset after: ");
-	DUMP_OFFSET(this_way);
 	
 	return 1;
 }
 
 
 /* Generic function for mangling variable-length address changes inside
- * NATed connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX command in FTP).
+ * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX
+ * command in FTP).
  *
  * Takes care about all the nasty sequence number changes, checksumming,
  * skb enlargement, ...
@@ -174,10 +176,11 @@
 	tcph = (void *)iph + iph->ihl*4;
 	data = (void *)tcph + tcph->doff*4;
 
-	/* move post-replacement */
-	memmove(data + match_offset + rep_len,
-		 data + match_offset + match_len,
-		 (*skb)->tail - (data + match_offset + match_len));
+	if (rep_len != match_len)
+		/* move post-replacement */
+		memmove(data + match_offset + rep_len,
+			data + match_offset + match_len,
+			(*skb)->tail - (data + match_offset + match_len));
 
 	/* insert data from buffer */
 	memcpy(data + match_offset, rep_buffer, rep_len);
@@ -207,6 +210,114 @@
 
 	return 1;
 }
+			
+/* Generic function for mangling variable-length address changes inside
+ * NATed UDP connections (like the CONNECT DATA XXXXX MESG XXXXX INDEX XXXXX
+ * command in the Amanda protocol)
+ *
+ * Takes care about all the nasty sequence number changes, checksumming,
+ * skb enlargement, ...
+ *
+ * XXX - This function could be merged with ip_nat_mangle_tcp_packet which
+ *       should be fairly easy to do.
+ */
+int 
+ip_nat_mangle_udp_packet(struct sk_buff **skb,
+			 struct ip_conntrack *ct,
+			 enum ip_conntrack_info ctinfo,
+			 unsigned int match_offset,
+			 unsigned int match_len,
+			 char *rep_buffer,
+			 unsigned int rep_len)
+{
+	struct iphdr *iph = (*skb)->nh.iph;
+	struct udphdr *udph = (void *)iph + iph->ihl * 4;
+	unsigned char *data;
+	u_int32_t udplen, newlen, newudplen;
+
+	udplen = (*skb)->len - iph->ihl*4;
+	newudplen = udplen - match_len + rep_len;
+	newlen = iph->ihl*4 + newudplen;
+
+	if (newlen > 65535) {
+		if (net_ratelimit())
+			printk("ip_nat_mangle_udp_packet: nat'ed packet "
+				"exceeds maximum packet size\n");
+		return 0;
+	}
+
+	if ((*skb)->len != newlen) {
+		if (!ip_nat_resize_packet(skb, ct, ctinfo, newlen)) {
+			printk("resize_packet failed!!\n");
+			return 0;
+		}
+	}
+
+	/* Alexey says: if a hook changes _data_ ... it can break
+	   original packet sitting in tcp queue and this is fatal */
+	if (skb_cloned(*skb)) {
+		struct sk_buff *nskb = skb_copy(*skb, GFP_ATOMIC);
+		if (!nskb) {
+			if (net_ratelimit())
+				printk("Out of memory cloning TCP packet\n");
+			return 0;
+		}
+		/* Rest of kernel will get very unhappy if we pass it
+		   a suddenly-orphaned skbuff */
+		if ((*skb)->sk)
+			skb_set_owner_w(nskb, (*skb)->sk);
+		kfree_skb(*skb);
+		*skb = nskb;
+	}
+
+	/* skb may be copied !! */
+	iph = (*skb)->nh.iph;
+	udph = (void *)iph + iph->ihl*4;
+	data = (void *)udph + sizeof(struct udphdr);
+
+	if (rep_len != match_len)
+		/* move post-replacement */
+		memmove(data + match_offset + rep_len,
+			data + match_offset + match_len,
+			(*skb)->tail - (data + match_offset + match_len));
+
+	/* insert data from buffer */
+	memcpy(data + match_offset, rep_buffer, rep_len);
+
+	/* update skb info */
+	if (newlen > (*skb)->len) {
+		DEBUGP("ip_nat_mangle_udp_packet: Extending packet by "
+			"%u to %u bytes\n", newlen - (*skb)->len, newlen);
+		skb_put(*skb, newlen - (*skb)->len);
+	} else {
+		DEBUGP("ip_nat_mangle_udp_packet: Shrinking packet from "
+			"%u to %u bytes\n", (*skb)->len, newlen);
+		skb_trim(*skb, newlen);
+	}
+
+	/* update the length of the UDP and IP packets to the new values*/
+	udph->len = htons((*skb)->len - iph->ihl*4);
+	iph->tot_len = htons(newlen);
+
+	/* fix udp checksum if udp checksum was previously calculated */
+	if ((*skb)->csum != 0) {
+		(*skb)->csum = csum_partial((char *)udph +
+					    sizeof(struct udphdr),
+					    newudplen - sizeof(struct udphdr),
+					    0);
+
+		udph->check = 0;
+		udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr,
+						newudplen, IPPROTO_UDP,
+						csum_partial((char *)udph,
+							 sizeof(struct udphdr),
+							(*skb)->csum));
+	}
+
+	ip_send_check(iph);
+
+	return 1;
+}
 
 /* Adjust one found SACK option including checksum correction */
 static void
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv4/netfilter/ip_nat_rule.c linux-2.4.21-pre6/net/ipv4/netfilter/ip_nat_rule.c
--- linux-2.4.20/net/ipv4/netfilter/ip_nat_rule.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv4/netfilter/ip_nat_rule.c	2003-03-26 23:49:30.000000000 +0000
@@ -1,5 +1,4 @@
 /* Everything about the rules for NAT. */
-#define __NO_VERSION__
 #include <linux/types.h>
 #include <linux/ip.h>
 #include <linux/netfilter.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv4/netfilter/ip_nat_standalone.c linux-2.4.21-pre6/net/ipv4/netfilter/ip_nat_standalone.c
--- linux-2.4.20/net/ipv4/netfilter/ip_nat_standalone.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv4/netfilter/ip_nat_standalone.c	2003-03-26 23:49:19.000000000 +0000
@@ -358,5 +358,6 @@
 EXPORT_SYMBOL(ip_nat_helper_unregister);
 EXPORT_SYMBOL(ip_nat_cheat_check);
 EXPORT_SYMBOL(ip_nat_mangle_tcp_packet);
+EXPORT_SYMBOL(ip_nat_mangle_udp_packet);
 EXPORT_SYMBOL(ip_nat_used_tuple);
 MODULE_LICENSE("GPL");
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv4/netfilter/ip_tables.c linux-2.4.21-pre6/net/ipv4/netfilter/ip_tables.c
--- linux-2.4.20/net/ipv4/netfilter/ip_tables.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv4/netfilter/ip_tables.c	2003-03-26 23:49:19.000000000 +0000
@@ -68,13 +68,12 @@
 #define inline
 #endif
 
-/* Locking is simple: we assume at worst case there will be one packet
-   in user context and one from bottom halves (or soft irq if Alexey's
-   softnet patch was applied).
-
+/*
    We keep a set of rules for each CPU, so we can avoid write-locking
-   them; doing a readlock_bh() stops packets coming through if we're
-   in user context.
+   them in the softirq when updating the counters and therefore
+   only need to read-lock in the softirq; doing a write_lock_bh() in user
+   context stops packets coming through and allows user context to read
+   the counters or update the rules.
 
    To be cache friendly on SMP, we arrange them like so:
    [ n-entries ]
@@ -1630,7 +1629,7 @@
 		     u_int8_t type, u_int8_t code,
 		     int invert)
 {
-	return (type == test_type && code >= min_code && code <= max_code)
+	return ((test_type == 0xFF) || (type == test_type && code >= min_code && code <= max_code))
 		^ invert;
 }
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv4/netfilter/ipt_ECN.c linux-2.4.21-pre6/net/ipv4/netfilter/ipt_ECN.c
--- linux-2.4.20/net/ipv4/netfilter/ipt_ECN.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv4/netfilter/ipt_ECN.c	2003-03-26 23:49:20.000000000 +0000
@@ -87,8 +87,8 @@
 	}
 	
 	if (diffs[0] != *tcpflags) {
-		diffs[0] = htons(diffs[0]) ^ 0xFFFF;
-		diffs[1] = htons(*tcpflags);
+		diffs[0] = diffs[0] ^ 0xFFFF;
+		diffs[1] = *tcpflags;
 		tcph->check = csum_fold(csum_partial((char *)diffs,
 		                                    sizeof(diffs),
 		                                    tcph->check^0xFFFF));
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv4/netfilter/ipt_REJECT.c linux-2.4.21-pre6/net/ipv4/netfilter/ipt_REJECT.c
--- linux-2.4.20/net/ipv4/netfilter/ipt_REJECT.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv4/netfilter/ipt_REJECT.c	2003-03-26 23:49:20.000000000 +0000
@@ -6,6 +6,8 @@
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/ip.h>
+#include <linux/udp.h>
+#include <linux/icmp.h>
 #include <net/icmp.h>
 #include <net/ip.h>
 #include <net/tcp.h>
@@ -157,6 +159,7 @@
 static void send_unreach(struct sk_buff *skb_in, int code)
 {
 	struct iphdr *iph;
+	struct udphdr *udph;
 	struct icmphdr *icmph;
 	struct sk_buff *nskb;
 	u32 saddr;
@@ -186,6 +189,19 @@
 	if (iph->frag_off&htons(IP_OFFSET))
 		return;
 
+	/* if UDP checksum is set, verify it's correct */
+	if (iph->protocol == IPPROTO_UDP
+	    && skb_in->tail-(u8*)iph >= sizeof(struct udphdr)) {
+		int datalen = skb_in->len - (iph->ihl<<2);
+		udph = (struct udphdr *)((char *)iph + (iph->ihl<<2));
+		if (udph->check
+		    && csum_tcpudp_magic(iph->saddr, iph->daddr,
+		                         datalen, IPPROTO_UDP,
+		                         csum_partial((char *)udph, datalen,
+		                                      0)) != 0)
+			return;
+	}
+		    
 	/* If we send an ICMP error to an ICMP error a mess would result.. */
 	if (iph->protocol == IPPROTO_ICMP
 	    && skb_in->tail-(u8*)iph >= sizeof(struct icmphdr)) {
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv4/netfilter/ipt_ULOG.c linux-2.4.21-pre6/net/ipv4/netfilter/ipt_ULOG.c
--- linux-2.4.20/net/ipv4/netfilter/ipt_ULOG.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv4/netfilter/ipt_ULOG.c	2003-03-26 23:49:40.000000000 +0000
@@ -12,6 +12,7 @@
  * 	      module loadtime -HW
  * 2002/07/07 remove broken nflog_rcv() function -HW
  * 2002/08/29 fix shifted/unshifted nlgroup bug -HW
+ * 2002/10/30 fix uninitialized mac_len field - <Anders K. Pedersen>
  *
  * Released under the terms of the GPL
  *
@@ -31,7 +32,7 @@
  *   Specify, after how many clock ticks (intel: 100 per second) the queue
  * should be flushed even if it is not full yet.
  *
- * ipt_ULOG.c,v 1.21 2002/08/29 10:54:34 laforge Exp
+ * ipt_ULOG.c,v 1.22 2002/10/30 09:07:31 laforge Exp
  */
 
 #include <linux/module.h>
@@ -224,7 +225,8 @@
 	    && in->hard_header_len <= ULOG_MAC_LEN) {
 		memcpy(pm->mac, (*pskb)->mac.raw, in->hard_header_len);
 		pm->mac_len = in->hard_header_len;
-	}
+	} else
+		pm->mac_len = 0;
 
 	if (in)
 		strncpy(pm->indev_name, in->name, sizeof(pm->indev_name));
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv4/netfilter/ipt_multiport.c linux-2.4.21-pre6/net/ipv4/netfilter/ipt_multiport.c
--- linux-2.4.20/net/ipv4/netfilter/ipt_multiport.c	2001-09-30 19:26:08.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv4/netfilter/ipt_multiport.c	2003-03-26 23:49:09.000000000 +0000
@@ -78,7 +78,7 @@
 
 	/* Must specify proto == TCP/UDP, no unknown flags or bad count */
 	return (ip->proto == IPPROTO_TCP || ip->proto == IPPROTO_UDP)
-		&& !(ip->flags & IPT_INV_PROTO)
+		&& !(ip->invflags & IPT_INV_PROTO)
 		&& matchsize == IPT_ALIGN(sizeof(struct ipt_multiport))
 		&& (multiinfo->flags == IPT_MULTIPORT_SOURCE
 		    || multiinfo->flags == IPT_MULTIPORT_DESTINATION
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv4/netfilter/ipt_unclean.c linux-2.4.21-pre6/net/ipv4/netfilter/ipt_unclean.c
--- linux-2.4.20/net/ipv4/netfilter/ipt_unclean.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv4/netfilter/ipt_unclean.c	2003-03-26 23:49:40.000000000 +0000
@@ -521,6 +521,16 @@
 		return 0;
 	}
 
+	/* CHECK: Do not use what is unused.
+	 * First bit of fragmentation flags should be unused.
+	 * May be used by OS fingerprinting tools.
+	 * 04 Jun 2002, Maciej Soltysiak, solt@dns.toxicfilms.tv
+	 */
+	if (ntohs(iph->frag_off)>>15) {
+		limpk("IP unused bit set\n");
+		return 0;
+	}
+
 	/* Per-protocol checks. */
 	switch (iph->protocol) {
 	case IPPROTO_ICMP:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv4/route.c linux-2.4.21-pre6/net/ipv4/route.c
--- linux-2.4.20/net/ipv4/route.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv4/route.c	2003-03-26 23:49:55.000000000 +0000
@@ -2156,7 +2156,7 @@
 		struct net_device *dev = __dev_get_by_index(iif);
 		err = -ENODEV;
 		if (!dev)
-			goto out;
+			goto out_free;
 		skb->protocol	= htons(ETH_P_IP);
 		skb->dev	= dev;
 		local_bh_disable();
@@ -2171,10 +2171,8 @@
 			memcpy(&oif, RTA_DATA(rta[RTA_OIF - 1]), sizeof(int));
 		err = ip_route_output(&rt, dst, src, rtm->rtm_tos, oif);
 	}
-	if (err) {
-		kfree_skb(skb);
-		goto out;
-	}
+	if (err)
+		goto out_free;
 
 	skb->dst = &rt->u.dst;
 	if (rtm->rtm_flags & RTM_F_NOTIFY)
@@ -2185,16 +2183,20 @@
 	err = rt_fill_info(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq,
 				RTM_NEWROUTE, 0);
 	if (!err)
-		goto out;
+		goto out_free;
 	if (err < 0) {
 		err = -EMSGSIZE;
-		goto out;
+		goto out_free;
 	}
 
 	err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT);
 	if (err > 0)
 		err = 0;
 out:	return err;
+
+out_free:
+	kfree_skb(skb);
+	goto out;
 }
 
 int ip_rt_dump(struct sk_buff *skb,  struct netlink_callback *cb)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv4/sysctl_net_ipv4.c linux-2.4.21-pre6/net/ipv4/sysctl_net_ipv4.c
--- linux-2.4.20/net/ipv4/sysctl_net_ipv4.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv4/sysctl_net_ipv4.c	2003-03-26 23:49:50.000000000 +0000
@@ -221,6 +221,10 @@
 	 &sysctl_icmp_ratemask, sizeof(int), 0644, NULL, &proc_dointvec},
 	{NET_TCP_TW_REUSE, "tcp_tw_reuse",
 	 &sysctl_tcp_tw_reuse, sizeof(int), 0644, NULL, &proc_dointvec},
+	{NET_TCP_FRTO, "tcp_frto",
+	 &sysctl_tcp_frto, sizeof(int), 0644, NULL, &proc_dointvec},
+	{NET_TCP_LOW_LATENCY, "tcp_low_latency",
+	 &sysctl_tcp_low_latency, sizeof(int), 0644, NULL, &proc_dointvec},
 	{0}
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv4/tcp_input.c linux-2.4.21-pre6/net/ipv4/tcp_input.c
--- linux-2.4.20/net/ipv4/tcp_input.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv4/tcp_input.c	2003-03-26 23:49:17.000000000 +0000
@@ -60,6 +60,7 @@
  *		Pasi Sarolahti,
  *		Panu Kuhlberg:		Experimental audit of TCP (re)transmission
  *					engine. Lots of bugs are found.
+ *		Pasi Sarolahti:		F-RTO for dealing with spurious RTOs
  */
 
 #include <linux/config.h>
@@ -86,6 +87,7 @@
 int sysctl_tcp_stdurg = 0;
 int sysctl_tcp_rfc1337 = 0;
 int sysctl_tcp_max_orphans = NR_FILE;
+int sysctl_tcp_frto = 0;
 
 #define FLAG_DATA		0x01 /* Incoming frame contained data.		*/
 #define FLAG_WIN_UPDATE		0x02 /* Incoming ACK was a window update.	*/
@@ -955,6 +957,89 @@
 	return flag;
 }
 
+/* RTO occurred, but do not yet enter loss state. Instead, transmit two new
+ * segments to see from the next ACKs whether any data was really missing.
+ * If the RTO was spurious, new ACKs should arrive.
+ */
+void tcp_enter_frto(struct sock *sk)
+{
+	struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+	struct sk_buff *skb;
+
+	tp->frto_counter = 1;
+
+	if (tp->ca_state <= TCP_CA_Disorder ||
+            tp->snd_una == tp->high_seq ||
+            (tp->ca_state == TCP_CA_Loss && !tp->retransmits)) {
+		tp->prior_ssthresh = tcp_current_ssthresh(tp);
+		tp->snd_ssthresh = tcp_recalc_ssthresh(tp);
+	}
+
+	/* Have to clear retransmission markers here to keep the bookkeeping
+	 * in shape, even though we are not yet in Loss state.
+	 * If something was really lost, it is eventually caught up
+	 * in tcp_enter_frto_loss.
+	 */
+	tp->retrans_out = 0;
+	tp->undo_marker = tp->snd_una;
+	tp->undo_retrans = 0;
+
+	for_retrans_queue(skb, sk, tp) {
+		TCP_SKB_CB(skb)->sacked &= ~TCPCB_RETRANS;
+	}
+	tcp_sync_left_out(tp);
+
+	tp->ca_state = TCP_CA_Open;
+	tp->frto_highmark = tp->snd_nxt;
+}
+
+/* Enter Loss state after F-RTO was applied. Dupack arrived after RTO,
+ * which indicates that we should follow the traditional RTO recovery,
+ * i.e. mark everything lost and do go-back-N retransmission.
+ */
+void tcp_enter_frto_loss(struct sock *sk)
+{
+	struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+	struct sk_buff *skb;
+	int cnt = 0;
+
+	tp->sacked_out = 0;
+	tp->lost_out = 0;
+	tp->fackets_out = 0;
+
+	for_retrans_queue(skb, sk, tp) {
+		cnt++;
+		TCP_SKB_CB(skb)->sacked &= ~TCPCB_LOST;
+		if (!(TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_ACKED)) {
+
+			/* Do not mark those segments lost that were
+			 * forward transmitted after RTO
+			 */
+			if(!after(TCP_SKB_CB(skb)->end_seq,
+				   tp->frto_highmark)) {
+				TCP_SKB_CB(skb)->sacked |= TCPCB_LOST;
+				tp->lost_out++;
+			}
+		} else {
+			tp->sacked_out++;
+			tp->fackets_out = cnt;
+		}
+	}
+	tcp_sync_left_out(tp);
+
+	tp->snd_cwnd = tp->frto_counter + tcp_packets_in_flight(tp)+1;
+	tp->snd_cwnd_cnt = 0;
+	tp->snd_cwnd_stamp = tcp_time_stamp;
+	tp->undo_marker = 0;
+	tp->frto_counter = 0;
+
+	tp->reordering = min_t(unsigned int, tp->reordering,
+					     sysctl_tcp_reordering);
+	tp->ca_state = TCP_CA_Loss;
+	tp->high_seq = tp->frto_highmark;
+	TCP_ECN_queue_cwr(tp);
+}
+
 void tcp_clear_retrans(struct tcp_opt *tp)
 {
 	tp->left_out = 0;
@@ -1525,7 +1610,8 @@
 	/* E. Check state exit conditions. State can be terminated
 	 *    when high_seq is ACKed. */
 	if (tp->ca_state == TCP_CA_Open) {
-		BUG_TRAP(tp->retrans_out == 0);
+		if (!sysctl_tcp_frto)
+			BUG_TRAP(tp->retrans_out == 0);
 		tp->retrans_stamp = 0;
 	} else if (!before(tp->snd_una, tp->high_seq)) {
 		switch (tp->ca_state) {
@@ -1892,6 +1978,41 @@
 	return flag;
 }
 
+static void tcp_process_frto(struct sock *sk, u32 prior_snd_una)
+{
+	struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+	
+	tcp_sync_left_out(tp);
+	
+	if (tp->snd_una == prior_snd_una ||
+	    !before(tp->snd_una, tp->frto_highmark)) {
+		/* RTO was caused by loss, start retransmitting in
+		 * go-back-N slow start
+		 */
+		tcp_enter_frto_loss(sk);
+		return;
+	}
+
+	if (tp->frto_counter == 1) {
+		/* First ACK after RTO advances the window: allow two new
+		 * segments out.
+		 */
+		tp->snd_cwnd = tcp_packets_in_flight(tp) + 2;
+	} else {
+		/* Also the second ACK after RTO advances the window.
+		 * The RTO was likely spurious. Reduce cwnd and continue
+		 * in congestion avoidance
+		 */
+		tp->snd_cwnd = min(tp->snd_cwnd, tp->snd_ssthresh);
+		tcp_moderate_cwnd(tp);
+	}
+
+	/* F-RTO affects on two new ACKs following RTO.
+	 * At latest on third ACK the TCP behavor is back to normal.
+	 */
+	tp->frto_counter = (tp->frto_counter + 1) % 3;
+}
+
 /* This routine deals with incoming acks, but not outgoing ones. */
 static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag)
 {
@@ -1949,6 +2070,9 @@
 	/* See if we can take anything off of the retransmit queue. */
 	flag |= tcp_clean_rtx_queue(sk);
 
+	if (tp->frto_counter)
+		tcp_process_frto(sk, prior_snd_una);
+
 	if (tcp_ack_is_dubious(tp, flag)) {
 		/* Advanve CWND, if state allows this. */
 		if ((flag&FLAG_DATA_ACKED) && prior_in_flight >= tp->snd_cwnd &&
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv4/tcp_ipv4.c linux-2.4.21-pre6/net/ipv4/tcp_ipv4.c
--- linux-2.4.20/net/ipv4/tcp_ipv4.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv4/tcp_ipv4.c	2003-03-26 23:49:25.000000000 +0000
@@ -45,9 +45,13 @@
  *	Vitaly E. Lavrov	:	Transparent proxy revived after year coma.
  *	Andi Kleen		:	Fix new listen.
  *	Andi Kleen		:	Fix accept error reporting.
+ *	YOSHIFUJI Hideaki @USAGI and:	Support IPV6_V6ONLY socket option, which
+ *	Alexey Kuznetsov		allow both IPv4 and IPv6 sockets to bind
+ *					a single port at the same time.
  */
 
 #include <linux/config.h>
+
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/random.h>
@@ -66,6 +70,7 @@
 extern int sysctl_ip_dynaddr;
 extern int sysctl_ip_default_ttl;
 int sysctl_tcp_tw_reuse = 0;
+int sysctl_tcp_low_latency = 0;
 
 /* Check TCP sequence numbers in ICMP packets. */
 #define ICMP_MIN_LENGTH 8
@@ -182,6 +187,7 @@
 	for( ; sk2 != NULL; sk2 = sk2->bind_next) {
 		if (sk != sk2 &&
 		    sk2->reuse <= 1 &&
+		    !ipv6_only_sock(sk2) &&
 		    sk->bound_dev_if == sk2->bound_dev_if) {
 			if (!sk_reuse	||
 			    !sk2->reuse	||
@@ -418,23 +424,27 @@
 	struct sock *result = NULL;
 	int score, hiscore;
 
-	hiscore=0;
+	hiscore=-1;
 	for(; sk; sk = sk->next) {
-		if(sk->num == hnum) {
+		if(sk->num == hnum && !ipv6_only_sock(sk)) {
 			__u32 rcv_saddr = sk->rcv_saddr;
 
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+			score = sk->family == PF_INET ? 1 : 0;
+#else
 			score = 1;
+#endif
 			if(rcv_saddr) {
 				if (rcv_saddr != daddr)
 					continue;
-				score++;
+				score+=2;
 			}
 			if (sk->bound_dev_if) {
 				if (sk->bound_dev_if != dif)
 					continue;
-				score++;
+				score+=2;
 			}
-			if (score == 3)
+			if (score == 5)
 				return sk;
 			if (score > hiscore) {
 				hiscore = score;
@@ -456,6 +466,7 @@
 		if (sk->num == hnum &&
 		    sk->next == NULL &&
 		    (!sk->rcv_saddr || sk->rcv_saddr == daddr) &&
+		    (sk->family == PF_INET || !ipv6_only_sock(sk)) &&
 		    !sk->bound_dev_if)
 			goto sherry_cache;
 		sk = __tcp_v4_lookup_listener(sk, daddr, hnum, dif);
@@ -1652,12 +1663,6 @@
  */
 int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
 {
-#ifdef CONFIG_FILTER
-	struct sk_filter *filter = sk->filter;
-	if (filter && sk_filter(skb, filter))
-		goto discard;
-#endif /* CONFIG_FILTER */
-
   	IP_INC_STATS_BH(IpInDelivers);
 
 	if (sk->state == TCP_ESTABLISHED) { /* Fast path */
@@ -1761,6 +1766,9 @@
 	if (sk->state == TCP_TIME_WAIT)
 		goto do_time_wait;
 
+	if (sk_filter(sk, skb, 0))
+		goto discard_and_relse;
+
 	skb->dev = NULL;
 
 	bh_lock_sock(sk);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv4/tcp_minisocks.c linux-2.4.21-pre6/net/ipv4/tcp_minisocks.c
--- linux-2.4.20/net/ipv4/tcp_minisocks.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv4/tcp_minisocks.c	2003-03-26 23:49:18.000000000 +0000
@@ -715,6 +715,9 @@
 		newtp->snd_cwnd = 2;
 		newtp->snd_cwnd_cnt = 0;
 
+		newtp->frto_counter = 0;
+		newtp->frto_highmark = 0;
+
 		newtp->ca_state = TCP_CA_Open;
 		tcp_init_xmit_timers(newsk);
 		skb_queue_head_init(&newtp->out_of_order_queue);
@@ -935,6 +938,12 @@
 	if (flg & (TCP_FLAG_RST|TCP_FLAG_SYN))
 		goto embryonic_reset;
 
+	/* ACK sequence verified above, just make sure ACK is
+	 * set.  If ACK not set, just silently drop the packet.
+	 */
+	if (!(flg & TCP_FLAG_ACK))
+		return NULL;
+
 	/* If TCP_DEFER_ACCEPT is set, drop bare ACK. */
 	if (tp->defer_accept && TCP_SKB_CB(skb)->end_seq == req->rcv_isn+1) {
 		req->acked = 1;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv4/tcp_output.c linux-2.4.21-pre6/net/ipv4/tcp_output.c
--- linux-2.4.20/net/ipv4/tcp_output.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv4/tcp_output.c	2003-03-26 23:49:50.000000000 +0000
@@ -718,13 +718,13 @@
 		/* Ok.  We will be able to collapse the packet. */
 		__skb_unlink(next_skb, next_skb->list);
 
+		memcpy(skb_put(skb, next_skb_size), next_skb->data, next_skb_size);
+
 		if (next_skb->ip_summed == CHECKSUM_HW)
 			skb->ip_summed = CHECKSUM_HW;
 
-		if (skb->ip_summed != CHECKSUM_HW) {
-			memcpy(skb_put(skb, next_skb_size), next_skb->data, next_skb_size);
+		if (skb->ip_summed != CHECKSUM_HW)
 			skb->csum = csum_block_add(skb->csum, next_skb->csum, skb_size);
-		}
 
 		/* Update sequence range on original skb. */
 		TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(next_skb)->end_seq;
@@ -1431,7 +1431,8 @@
 	}
 
 	if (err <= 0) {
-		tp->backoff++;
+		if (tp->backoff < sysctl_tcp_retries2)
+			tp->backoff++;
 		tp->probes_out++;
 		tcp_reset_xmit_timer (sk, TCP_TIME_PROBE0, 
 				      min(tp->rto << tp->backoff, TCP_RTO_MAX));
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv4/tcp_timer.c linux-2.4.21-pre6/net/ipv4/tcp_timer.c
--- linux-2.4.20/net/ipv4/tcp_timer.c	2001-10-01 16:19:57.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv4/tcp_timer.c	2003-03-26 23:49:54.000000000 +0000
@@ -372,7 +372,11 @@
 		}
 	}
 
-	tcp_enter_loss(sk, 0);
+	if (tcp_use_frto(sk)) {
+		tcp_enter_frto(sk);
+	} else {
+		tcp_enter_loss(sk, 0);
+	}
 
 	if (tcp_retransmit_skb(sk, skb_peek(&sk->write_queue)) > 0) {
 		/* Retransmission failed because of local congestion,
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv4/udp.c linux-2.4.21-pre6/net/ipv4/udp.c
--- linux-2.4.20/net/ipv4/udp.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv4/udp.c	2003-03-26 23:49:09.000000000 +0000
@@ -61,6 +61,9 @@
  *					return ENOTCONN for unconnected sockets (POSIX)
  *		Janos Farkas	:	don't deliver multi/broadcasts to a different
  *					bound-to-device socket
+ *	YOSHIFUJI Hideaki @USAGI and:	Support IPV6_V6ONLY socket option, which
+ *	Alexey Kuznetsov:		allow both IPv4 and IPv6 sockets to bind
+ *					a single port at the same time.
  *
  *
  *		This program is free software; you can redistribute it and/or
@@ -85,6 +88,7 @@
 #include <linux/netdevice.h>
 #include <net/snmp.h>
 #include <net/ip.h>
+#include <net/ipv6.h>
 #include <net/protocol.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
@@ -159,6 +163,7 @@
 		     sk2 = sk2->next) {
 			if (sk2->num == snum &&
 			    sk2 != sk &&
+			    !ipv6_only_sock(sk2) &&
 			    sk2->bound_dev_if == sk->bound_dev_if &&
 			    (!sk2->rcv_saddr ||
 			     !sk->rcv_saddr ||
@@ -215,29 +220,34 @@
 	int badness = -1;
 
 	for(sk = udp_hash[hnum & (UDP_HTABLE_SIZE - 1)]; sk != NULL; sk = sk->next) {
-		if(sk->num == hnum) {
-			int score = 0;
+		if(sk->num == hnum && !ipv6_only_sock(sk)) {
+			int score;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+			score = sk->family == PF_INET ? 1 : 0;
+#else
+			score = 1;
+#endif
 			if(sk->rcv_saddr) {
 				if(sk->rcv_saddr != daddr)
 					continue;
-				score++;
+				score+=2;
 			}
 			if(sk->daddr) {
 				if(sk->daddr != saddr)
 					continue;
-				score++;
+				score+=2;
 			}
 			if(sk->dport) {
 				if(sk->dport != sport)
 					continue;
-				score++;
+				score+=2;
 			}
 			if(sk->bound_dev_if) {
 				if(sk->bound_dev_if != dif)
 					continue;
-				score++;
+				score+=2;
 			}
-			if(score == 4) {
+			if(score == 9) {
 				result = sk;
 				break;
 			} else if(score > badness) {
@@ -273,6 +283,7 @@
 		    (s->daddr && s->daddr!=rmt_addr)			||
 		    (s->dport != rmt_port && s->dport != 0)			||
 		    (s->rcv_saddr  && s->rcv_saddr != loc_addr)		||
+		    ipv6_only_sock(s)					||
 		    (s->bound_dev_if && s->bound_dev_if != dif))
 			continue;
 		break;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv6/addrconf.c linux-2.4.21-pre6/net/ipv6/addrconf.c
--- linux-2.4.20/net/ipv6/addrconf.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv6/addrconf.c	2003-03-26 23:49:30.000000000 +0000
@@ -786,7 +786,7 @@
 	struct in6_addr addr;
 
 	ipv6_addr_set(&addr,  htonl(0xFE800000), 0, 0, 0);
-	addrconf_prefix_route(&addr, 10, dev, 0, RTF_ADDRCONF);
+	addrconf_prefix_route(&addr, 64, dev, 0, RTF_ADDRCONF);
 }
 
 static struct inet6_dev *addrconf_add_dev(struct net_device *dev)
@@ -947,6 +947,7 @@
 				ipv6_ifa_notify((flags&IFA_F_DEPRECATED) ?
 						0 : RTM_NEWADDR, ifp);
 			in6_ifa_put(ifp);
+			addrconf_verify(0);
 		}
 	}
 	in6_dev_put(in6_dev);
@@ -1161,7 +1162,7 @@
 					flag |= IFA_HOST;
 				}
 				if (idev->dev->flags&IFF_POINTOPOINT)
-					plen = 10;
+					plen = 64;
 				else
 					plen = 96;
 
@@ -1211,7 +1212,7 @@
 {
 	struct inet6_ifaddr * ifp;
 
-	ifp = ipv6_add_addr(idev, addr, 10, IFA_LINK, IFA_F_PERMANENT);
+	ifp = ipv6_add_addr(idev, addr, 64, IFA_LINK, IFA_F_PERMANENT);
 	if (ifp) {
 		addrconf_dad_start(ifp);
 		in6_ifa_put(ifp);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv6/af_inet6.c linux-2.4.21-pre6/net/ipv6/af_inet6.c
--- linux-2.4.20/net/ipv6/af_inet6.c	2001-10-17 21:16:39.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv6/af_inet6.c	2003-03-26 23:48:58.000000000 +0000
@@ -88,6 +88,8 @@
 extern void ipv6_sysctl_unregister(void);
 #endif
 
+int sysctl_ipv6_bindv6only;
+
 #ifdef INET_REFCNT_DEBUG
 atomic_t inet6_sock_nr;
 #endif
@@ -173,6 +175,8 @@
 	sk->net_pinfo.af_inet6.mc_loop	  = 1;
 	sk->net_pinfo.af_inet6.pmtudisc	  = IPV6_PMTUDISC_WANT;
 
+	sk->net_pinfo.af_inet6.ipv6only	= sysctl_ipv6_bindv6only;
+	
 	/* Init the ipv4 part of the socket since we can have sockets
 	 * using v6 API for ipv4.
 	 */
@@ -538,6 +542,7 @@
 	struct list_head *lh;
 	struct inet_protosw *answer;
 	int protocol = p->protocol;
+	struct list_head *last_perm;
 
 	br_write_lock_bh(BR_NETPROTO_LOCK);
 
@@ -546,24 +551,29 @@
 
 	/* If we are trying to override a permanent protocol, bail. */
 	answer = NULL;
+	last_perm = &inetsw6[p->type];
 	list_for_each(lh, &inetsw6[p->type]) {
 		answer = list_entry(lh, struct inet_protosw, list);
 
 		/* Check only the non-wild match. */
-		if (protocol == answer->protocol &&
-		    (INET_PROTOSW_PERMANENT & answer->flags))
-			break;
+		if (INET_PROTOSW_PERMANENT & answer->flags) {
+			if (protocol == answer->protocol)
+				break;
+			last_perm = lh;
+		}
 
 		answer = NULL;
 	}
 	if (answer)
 		goto out_permanent;
 
-	/* Add to the BEGINNING so that we override any existing
-	 * entry.  This means that when we remove this entry, the
+	/* Add the new entry after the last permanent entry if any, so that
+	 * the new entry does not override a permanent entry when matched with
+	 * a wild-card protocol. But it is allowed to override any existing
+	 * non-permanent entry.  This means that when we remove this entry, the 
 	 * system automatically returns to the old behavior.
 	 */
-	list_add(&p->list, &inetsw6[p->type]);
+	list_add(&p->list, last_perm);
 out:
 	br_write_unlock_bh(BR_NETPROTO_LOCK);
 	return;
@@ -619,7 +629,7 @@
 	/*
 	 *	ipngwg API draft makes clear that the correct semantics
 	 *	for TCP and UDP is to consider one TCP and UDP instance
-	 *	in a host availiable by both INET and INET6 APIs and
+	 *	in a host available by both INET and INET6 APIs and
 	 *	able to communicate via both network protocols.
 	 */
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv6/datagram.c linux-2.4.21-pre6/net/ipv6/datagram.c
--- linux-2.4.20/net/ipv6/datagram.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv6/datagram.c	2003-03-26 23:49:06.000000000 +0000
@@ -158,6 +158,7 @@
 	if (serr->ee.ee_origin != SO_EE_ORIGIN_LOCAL) {
 		sin->sin6_family = AF_INET6;
 		sin->sin6_flowinfo = 0;
+		sin->sin6_scope_id = 0;
 		if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP6) {
 			memcpy(&sin->sin6_addr, &skb->nh.ipv6h->saddr, 16);
 			if (sk->net_pinfo.af_inet6.rxopt.all)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv6/exthdrs.c linux-2.4.21-pre6/net/ipv6/exthdrs.c
--- linux-2.4.20/net/ipv6/exthdrs.c	2001-06-21 04:00:55.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv6/exthdrs.c	2003-03-26 23:48:59.000000000 +0000
@@ -402,7 +402,13 @@
 	if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8))
 		goto fail;
 
-	len = (skb->h.raw[1]+1)<<2;
+	/*
+	 * RFC2402 2.2 Payload Length
+	 * The 8-bit field specifies the length of AH in 32-bit words 
+	 * (4-byte units), minus "2".
+	 * -- Noriaki Takamiya @USAGI Project
+	 */
+	len = (skb->h.raw[1]+2)<<2;
 
 	if (len&7)
 		goto fail;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv6/icmp.c linux-2.4.21-pre6/net/ipv6/icmp.c
--- linux-2.4.20/net/ipv6/icmp.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv6/icmp.c	2003-03-26 23:49:24.000000000 +0000
@@ -25,9 +25,9 @@
  *					add more length checks and other fixes.
  *	yoshfuji		:	ensure to sent parameter problem for
  *					fragments.
+ *	YOSHIFUJI Hideaki @USAGI:	added sysctl for icmp rate limit.
  */
 
-#define __NO_VERSION__
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/types.h>
@@ -40,6 +40,10 @@
 #include <linux/skbuff.h>
 #include <linux/init.h>
 
+#ifdef CONFIG_SYSCTL
+#include <linux/sysctl.h>
+#endif
+
 #include <linux/inet.h>
 #include <linux/netdevice.h>
 #include <linux/icmpv6.h>
@@ -63,10 +67,12 @@
 struct icmpv6_mib icmpv6_statistics[NR_CPUS*2];
 
 /*
- *	ICMP socket for flow control.
+ *	ICMP socket(s) for flow control.
  */
 
-struct socket *icmpv6_socket;
+static struct socket *__icmpv6_socket[NR_CPUS];
+#define icmpv6_socket	__icmpv6_socket[smp_processor_id()]
+#define icmpv6_socket_cpu(X) __icmpv6_socket[(X)]
 
 int icmpv6_rcv(struct sk_buff *skb);
 
@@ -91,43 +97,18 @@
 };
 
 
-static int icmpv6_xmit_holder = -1;
-
-static int icmpv6_xmit_lock_bh(void)
-{
-	if (!spin_trylock(&icmpv6_socket->sk->lock.slock)) {
-		if (icmpv6_xmit_holder == smp_processor_id())
-			return -EAGAIN;
-		spin_lock(&icmpv6_socket->sk->lock.slock);
-	}
-	icmpv6_xmit_holder = smp_processor_id();
-	return 0;
-}
-
-static __inline__ int icmpv6_xmit_lock(void)
+static void icmpv6_xmit_lock(void)
 {
-	int ret;
 	local_bh_disable();
-	ret = icmpv6_xmit_lock_bh();
-	if (ret)
-		local_bh_enable();
-	return ret;
+	if (unlikely(!spin_trylock(&icmpv6_socket->sk->lock.slock)))
+		BUG();
 }
 
-static void icmpv6_xmit_unlock_bh(void)
+static void icmpv6_xmit_unlock(void)
 {
-	icmpv6_xmit_holder = -1;
-	spin_unlock(&icmpv6_socket->sk->lock.slock);
+	spin_unlock_bh(&icmpv6_socket->sk->lock.slock);
 }
 
-static __inline__ void icmpv6_xmit_unlock(void)
-{
-	icmpv6_xmit_unlock_bh();
-	local_bh_enable();
-}
-
-
-
 /*
  *	getfrag callback
  */
@@ -344,8 +325,7 @@
 	fl.uli_u.icmpt.type = type;
 	fl.uli_u.icmpt.code = code;
 
-	if (icmpv6_xmit_lock())
-		return;
+	icmpv6_xmit_lock();
 
 	if (!icmpv6_xrlim_allow(sk, type, &fl))
 		goto out;
@@ -418,15 +398,14 @@
 	fl.uli_u.icmpt.type = ICMPV6_ECHO_REPLY;
 	fl.uli_u.icmpt.code = 0;
 
-	if (icmpv6_xmit_lock_bh())
-		return;
+	icmpv6_xmit_lock();
 
 	ip6_build_xmit(sk, icmpv6_getfrag, &msg, &fl, msg.len, NULL, -1,
 		       MSG_DONTWAIT);
 	ICMP6_INC_STATS_BH(Icmp6OutEchoReplies);
 	ICMP6_INC_STATS_BH(Icmp6OutMsgs);
 
-	icmpv6_xmit_unlock_bh();
+	icmpv6_xmit_unlock();
 }
 
 static void icmpv6_notify(struct sk_buff *skb, int type, int code, u32 info)
@@ -635,41 +614,53 @@
 int __init icmpv6_init(struct net_proto_family *ops)
 {
 	struct sock *sk;
-	int err;
+	int err, i, j;
 
-	icmpv6_socket = sock_alloc();
-	if (icmpv6_socket == NULL) {
-		printk(KERN_ERR
-		       "Failed to create the ICMP6 control socket.\n");
-		return -1;
-	}
-	icmpv6_socket->inode->i_uid = 0;
-	icmpv6_socket->inode->i_gid = 0;
-	icmpv6_socket->type = SOCK_RAW;
-
-	if ((err = ops->create(icmpv6_socket, IPPROTO_ICMPV6)) < 0) {
-		printk(KERN_ERR
-		       "Failed to initialize the ICMP6 control socket (err %d).\n",
-		       err);
-		sock_release(icmpv6_socket);
-		icmpv6_socket = NULL; /* for safety */
-		return err;
-	}
-
-	sk = icmpv6_socket->sk;
-	sk->allocation = GFP_ATOMIC;
-	sk->sndbuf = SK_WMEM_MAX*2;
-	sk->prot->unhash(sk);
+	for (i = 0; i < NR_CPUS; i++) {
+		icmpv6_socket_cpu(i) = sock_alloc();
+		if (icmpv6_socket_cpu(i) == NULL) {
+			printk(KERN_ERR
+			       "Failed to create the ICMP6 control socket.\n");
+			err = -1;
+			goto fail;
+		}
+		icmpv6_socket_cpu(i)->inode->i_uid = 0;
+		icmpv6_socket_cpu(i)->inode->i_gid = 0;
+		icmpv6_socket_cpu(i)->type = SOCK_RAW;
+
+		if ((err = ops->create(icmpv6_socket_cpu(i), IPPROTO_ICMPV6)) < 0) {
+			printk(KERN_ERR
+			       "Failed to initialize the ICMP6 control socket "
+			       "(err %d).\n",
+			       err);
+			goto fail;
+		}
+
+		sk = icmpv6_socket_cpu(i)->sk;
+		sk->allocation = GFP_ATOMIC;
+		sk->sndbuf = SK_WMEM_MAX*2;
+		sk->prot->unhash(sk);
+	}
 
 	inet6_add_protocol(&icmpv6_protocol);
 
 	return 0;
+fail:
+	for (j = 0; j < i; j++) {
+		sock_release(icmpv6_socket_cpu(j));
+		icmpv6_socket_cpu(j) = NULL;
+	}
+	return err;
 }
 
 void icmpv6_cleanup(void)
 {
-	sock_release(icmpv6_socket);
-	icmpv6_socket = NULL; /* For safety. */
+	int i;
+
+	for (i = 0; i < NR_CPUS; i++) {
+		sock_release(icmpv6_socket_cpu(i));
+		icmpv6_socket_cpu(i) = NULL;
+	}
 	inet6_del_protocol(&icmpv6_protocol);
 }
 
@@ -715,3 +706,12 @@
 
 	return fatal;
 }
+
+#ifdef CONFIG_SYSCTL
+ctl_table ipv6_icmp_table[] = {
+	{NET_IPV6_ICMP_RATELIMIT, "ratelimit",
+	&sysctl_icmpv6_time, sizeof(int), 0644, NULL, &proc_dointvec},
+	{0},
+};
+#endif
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv6/ip6_output.c linux-2.4.21-pre6/net/ipv6/ip6_output.c
--- linux-2.4.20/net/ipv6/ip6_output.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv6/ip6_output.c	2003-03-26 23:49:00.000000000 +0000
@@ -132,7 +132,7 @@
 
 
 #ifdef CONFIG_NETFILTER
-static int route6_me_harder(struct sk_buff *skb)
+int ip6_route_me_harder(struct sk_buff *skb)
 {
 	struct ipv6hdr *iph = skb->nh.ipv6h;
 	struct dst_entry *dst;
@@ -150,7 +150,7 @@
 
 	if (dst->error) {
 		if (net_ratelimit())
-			printk(KERN_DEBUG "route6_me_harder: No more route.\n");
+			printk(KERN_DEBUG "ip6_route_me_harder: No more route.\n");
 		return -EINVAL;
 	}
 
@@ -166,7 +166,7 @@
 {
 #ifdef CONFIG_NETFILTER
 	if (skb->nfcache & NFC_ALTERED){
-		if (route6_me_harder(skb) != 0){
+		if (ip6_route_me_harder(skb) != 0){
 			kfree_skb(skb);
 			return -EINVAL;
 		}
@@ -563,7 +563,7 @@
 		if (err) {
 #if IP6_DEBUG >= 2
 			printk(KERN_DEBUG "ip6_build_xmit: "
-			       "no availiable source address\n");
+			       "no available source address\n");
 #endif
 			goto out;
 		}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv6/ipv6_sockglue.c linux-2.4.21-pre6/net/ipv6/ipv6_sockglue.c
--- linux-2.4.20/net/ipv6/ipv6_sockglue.c	2001-09-20 21:12:56.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv6/ipv6_sockglue.c	2003-03-26 23:49:00.000000000 +0000
@@ -21,7 +21,6 @@
  *	o	Return an optlen of the truncated length if need be
  */
 
-#define __NO_VERSION__
 #include <linux/module.h>
 #include <linux/config.h>
 #include <linux/errno.h>
@@ -157,7 +156,8 @@
 				break;
 			}
 
-			if (!(ipv6_addr_type(&np->daddr) & IPV6_ADDR_MAPPED)) {
+			if (ipv6_only_sock(sk) ||
+			    !(ipv6_addr_type(&np->daddr) & IPV6_ADDR_MAPPED)) {
 				retv = -EADDRNOTAVAIL;
 				break;
 			}
@@ -203,6 +203,13 @@
 		}
 		goto e_inval;
 
+	case IPV6_V6ONLY:
+		if (sk->num)
+			goto e_inval;
+		np->ipv6only = valbool;
+		retv = 0;
+		break;
+
 	case IPV6_PKTINFO:
 		np->rxopt.bits.rxinfo = valbool;
 		retv = 0;
@@ -466,6 +473,10 @@
 		break;
 	}
 
+	case IPV6_V6ONLY:
+		val = np->ipv6only;
+		break;
+
 	case IPV6_PKTINFO:
 		val = np->rxopt.bits.rxinfo;
 		break;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv6/mcast.c linux-2.4.21-pre6/net/ipv6/mcast.c
--- linux-2.4.20/net/ipv6/mcast.c	2001-08-15 08:54:24.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv6/mcast.c	2003-03-26 23:49:25.000000000 +0000
@@ -18,9 +18,14 @@
 /* Changes:
  *
  *	yoshfuji	: fix format of router-alert option
+ *	YOSHIFUJI Hideaki @USAGI:
+ *		Fixed source address for MLD message based on
+ *		<draft-ietf-magma-mld-source-02.txt>.
+ *	YOSHIFUJI Hideaki @USAGI:
+ *		- Ignore Queries for invalid addresses.
+ *		- MLD for link-local addresses.
  */
 
-#define __NO_VERSION__
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/errno.h>
@@ -405,6 +410,7 @@
 	unsigned long resptime;
 	struct inet6_dev *idev;
 	struct icmp6hdr *hdr;
+	int addr_type;
 
 	if (!pskb_may_pull(skb, sizeof(struct in6_addr)))
 		return -EINVAL;
@@ -420,6 +426,11 @@
 	resptime = (resptime<<10)/(1024000/HZ);
 
 	addrp = (struct in6_addr *) (hdr + 1);
+	addr_type = ipv6_addr_type(addrp);
+
+	if (addr_type != IPV6_ADDR_ANY &&
+	    !(addr_type&IPV6_ADDR_MULTICAST))
+		return -EINVAL;
 
 	idev = in6_dev_get(skb->dev);
 
@@ -427,7 +438,7 @@
 		return 0;
 
 	read_lock(&idev->lock);
-	if (ipv6_addr_any(addrp)) {
+	if (addr_type == IPV6_ADDR_ANY) {
 		for (ma = idev->mc_list; ma; ma=ma->next)
 			igmp6_group_queried(ma, resptime);
 	} else {
@@ -451,6 +462,7 @@
 	struct in6_addr *addrp;
 	struct inet6_dev *idev;
 	struct icmp6hdr *hdr;
+	int addr_type;
 
 	/* Our own report looped back. Ignore it. */
 	if (skb->pkt_type == PACKET_LOOPBACK)
@@ -462,7 +474,9 @@
 	hdr = (struct icmp6hdr*) skb->h.raw;
 
 	/* Drop reports with not link local source */
-	if (!(ipv6_addr_type(&skb->nh.ipv6h->saddr)&IPV6_ADDR_LINKLOCAL))
+	addr_type = ipv6_addr_type(&skb->nh.ipv6h->saddr);
+	if (addr_type != IPV6_ADDR_ANY && 
+	    !(addr_type&IPV6_ADDR_LINKLOCAL))
 		return -EINVAL;
 
 	addrp = (struct in6_addr *) (hdr + 1);
@@ -529,11 +543,11 @@
 	}
 
 	if (ipv6_get_lladdr(dev, &addr_buf)) {
-#if MCAST_DEBUG >= 1
-		printk(KERN_DEBUG "igmp6: %s no linklocal address\n",
-		       dev->name);
-#endif
-		goto out;
+		/* <draft-ietf-magma-mld-source-02.txt>:
+		 * use unspecified address as the source address 
+		 * when a valid link-local address is not available.
+		 */
+		memset(&addr_buf, 0, sizeof(addr_buf));
 	}
 
 	ip6_nd_hdr(sk, skb, dev, &addr_buf, snd_addr, NEXTHDR_HOP, payload_len);
@@ -566,11 +580,9 @@
 static void igmp6_join_group(struct ifmcaddr6 *ma)
 {
 	unsigned long delay;
-	int addr_type;
-
-	addr_type = ipv6_addr_type(&ma->mca_addr);
 
-	if ((addr_type & (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_LOOPBACK)))
+	if (IPV6_ADDR_MC_SCOPE(&ma->mca_addr) < IPV6_ADDR_SCOPE_LINKLOCAL ||
+	    ipv6_addr_is_ll_all_nodes(&ma->mca_addr))
 		return;
 
 	igmp6_send(&ma->mca_addr, ma->idev->dev, ICMPV6_MGM_REPORT);
@@ -591,11 +603,8 @@
 
 static void igmp6_leave_group(struct ifmcaddr6 *ma)
 {
-	int addr_type;
-
-	addr_type = ipv6_addr_type(&ma->mca_addr);
-
-	if ((addr_type & IPV6_ADDR_LINKLOCAL))
+	if (IPV6_ADDR_MC_SCOPE(&ma->mca_addr) < IPV6_ADDR_SCOPE_LINKLOCAL ||
+	    ipv6_addr_is_ll_all_nodes(&ma->mca_addr))
 		return;
 
 	if (ma->mca_flags & MAF_LAST_REPORTER)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv6/ndisc.c linux-2.4.21-pre6/net/ipv6/ndisc.c
--- linux-2.4.20/net/ipv6/ndisc.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv6/ndisc.c	2003-03-26 23:48:59.000000000 +0000
@@ -42,7 +42,6 @@
 #define ND_PRINTK2 ND_PRINTK
 #endif
 
-#define __NO_VERSION__
 #include <linux/module.h>
 #include <linux/config.h>
 #include <linux/errno.h>
@@ -583,6 +582,253 @@
 	}
 }
 
+void ndisc_recv_ns(struct sk_buff *skb)
+{
+	struct nd_msg *msg = (struct nd_msg *)skb->h.raw;
+	struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
+	struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
+	u8 *lladdr = NULL;
+	int lladdrlen = 0;
+	u32 ndoptlen = skb->tail - msg->opt;
+	struct ndisc_options ndopts;
+	struct net_device *dev = skb->dev;
+	struct inet6_ifaddr *ifp;
+	struct neighbour *neigh;
+
+	if (skb->len < sizeof(struct nd_msg)) {
+		if (net_ratelimit())
+			printk(KERN_WARNING "ICMP NS: packet too short\n");
+		return;
+	}
+
+	if (ipv6_addr_type(&msg->target)&IPV6_ADDR_MULTICAST) {
+		if (net_ratelimit())
+			printk(KERN_WARNING "ICMP NS: target address is multicast\n");
+		return;
+	}
+
+	if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
+		if (net_ratelimit())
+			printk(KERN_WARNING "ICMP NS: invalid ND option, ignored.\n");
+		return;
+	}
+
+	if (ndopts.nd_opts_src_lladdr) {
+		lladdr = (u8*)(ndopts.nd_opts_src_lladdr + 1);
+		lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
+		if (lladdrlen != NDISC_OPT_SPACE(dev->addr_len)) {
+			if (net_ratelimit())
+				printk(KERN_WARNING "ICMP NS: bad lladdr length.\n");
+			return;
+		}
+	}
+
+	/* XXX: RFC2461 7.1.1:
+	 * 	If the IP source address is the unspecified address, there
+	 *	MUST NOT be source link-layer address option in the message.
+	 *
+	 *	NOTE! Linux kernel < 2.4.4 broke this rule.
+	 */
+		 	
+	/* XXX: RFC2461 7.1.1:
+	 *	If the IP source address is the unspecified address, the IP
+      	 *	destination address MUST be a solicited-node multicast address.
+	 */
+
+	if ((ifp = ipv6_get_ifaddr(&msg->target, dev)) != NULL) {
+		int addr_type = ipv6_addr_type(saddr);
+
+		if (ifp->flags & IFA_F_TENTATIVE) {
+			/* Address is tentative. If the source
+			   is unspecified address, it is someone
+			   does DAD, otherwise we ignore solicitations
+			   until DAD timer expires.
+			 */
+			if (addr_type == IPV6_ADDR_ANY) {
+				if (dev->type == ARPHRD_IEEE802_TR) { 
+					unsigned char *sadr = skb->mac.raw ;
+					if (((sadr[8] &0x7f) != (dev->dev_addr[0] & 0x7f)) ||
+					(sadr[9] != dev->dev_addr[1]) ||
+					(sadr[10] != dev->dev_addr[2]) ||
+					(sadr[11] != dev->dev_addr[3]) ||
+					(sadr[12] != dev->dev_addr[4]) ||
+					(sadr[13] != dev->dev_addr[5])) 
+					{
+						addrconf_dad_failure(ifp) ; 
+					}
+				} else {
+					addrconf_dad_failure(ifp);
+				}
+			} else
+				in6_ifa_put(ifp);
+			return;
+		}
+	
+		if (addr_type == IPV6_ADDR_ANY) {
+			struct in6_addr maddr;
+
+			ipv6_addr_all_nodes(&maddr);
+			ndisc_send_na(dev, NULL, &maddr, &ifp->addr, 
+				      ifp->idev->cnf.forwarding, 0, 
+				      ipv6_addr_type(&ifp->addr)&IPV6_ADDR_ANYCAST ? 0 : 1, 
+				      1);
+			in6_ifa_put(ifp);
+			return;
+		}
+
+		if (addr_type & IPV6_ADDR_UNICAST) {
+			int inc = ipv6_addr_type(daddr)&IPV6_ADDR_MULTICAST;
+
+			if (inc)
+				nd_tbl.stats.rcv_probes_mcast++;
+			else
+				nd_tbl.stats.rcv_probes_ucast++;
+
+			/* 
+			 *	update / create cache entry
+			 *	for the source adddress
+			 */
+
+			neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, dev);
+
+			if (neigh || !dev->hard_header) {
+				ndisc_send_na(dev, neigh, saddr, &ifp->addr, 
+					      ifp->idev->cnf.forwarding, 1, 
+					      ipv6_addr_type(&ifp->addr)&IPV6_ADDR_ANYCAST ? 0 : 1, 
+					      1);
+				if (neigh)
+					neigh_release(neigh);
+			}
+		}
+		in6_ifa_put(ifp);
+	} else {
+		struct inet6_dev *in6_dev = in6_dev_get(dev);
+		int addr_type = ipv6_addr_type(saddr);
+
+		if (in6_dev && in6_dev->cnf.forwarding &&
+		    (addr_type & IPV6_ADDR_UNICAST) &&
+		    pneigh_lookup(&nd_tbl, &msg->target, dev, 0)) {
+			int inc = ipv6_addr_type(daddr)&IPV6_ADDR_MULTICAST;
+
+			if (skb->stamp.tv_sec == 0 ||
+			    skb->pkt_type == PACKET_HOST ||
+			    inc == 0 ||
+			    in6_dev->nd_parms->proxy_delay == 0) {
+				if (inc)
+					nd_tbl.stats.rcv_probes_mcast++;
+				else
+					nd_tbl.stats.rcv_probes_ucast++;
+					
+				neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, dev);
+
+				if (neigh) {
+					ndisc_send_na(dev, neigh, saddr, &msg->target,
+						      0, 1, 0, 1);
+					neigh_release(neigh);
+				}
+			} else {
+				struct sk_buff *n = skb_clone(skb, GFP_ATOMIC);
+				if (n)
+					pneigh_enqueue(&nd_tbl, in6_dev->nd_parms, n);
+				in6_dev_put(in6_dev);
+				return;
+			}
+		}
+		if (in6_dev)
+			in6_dev_put(in6_dev);
+	}
+	return;
+}
+
+void ndisc_recv_na(struct sk_buff *skb)
+{
+	struct nd_msg *msg = (struct nd_msg *)skb->h.raw;
+	struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
+	struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
+	u8 *lladdr = NULL;
+	int lladdrlen = 0;
+	u32 ndoptlen = skb->tail - msg->opt;
+	struct ndisc_options ndopts;
+	struct net_device *dev = skb->dev;
+	struct inet6_ifaddr *ifp;
+	struct neighbour *neigh;
+
+	if (skb->len < sizeof(struct nd_msg)) {
+		if (net_ratelimit())
+			printk(KERN_WARNING "ICMP NA: packet too short\n");
+		return;
+	}
+
+	if (ipv6_addr_type(&msg->target)&IPV6_ADDR_MULTICAST) {
+		if (net_ratelimit())
+			printk(KERN_WARNING "NDISC NA: target address is multicast\n");
+		return;
+	}
+
+	if ((ipv6_addr_type(daddr)&IPV6_ADDR_MULTICAST) &&
+	    msg->icmph.icmp6_solicited) {
+		ND_PRINTK0("NDISC: solicited NA is multicasted\n");
+		return;
+	}
+		
+	if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
+		if (net_ratelimit())
+			printk(KERN_WARNING "ICMP NS: invalid ND option, ignored.\n");
+		return;
+	}
+	if (ndopts.nd_opts_tgt_lladdr) {
+		lladdr = (u8*)(ndopts.nd_opts_tgt_lladdr + 1);
+		lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3;
+		if (lladdrlen != NDISC_OPT_SPACE(dev->addr_len)) {
+			if (net_ratelimit())
+				printk(KERN_WARNING "NDISC NA: invalid lladdr length.\n");
+			return;
+		}
+	}
+	if ((ifp = ipv6_get_ifaddr(&msg->target, dev))) {
+		if (ifp->flags & IFA_F_TENTATIVE) {
+			addrconf_dad_failure(ifp);
+			return;
+		}
+		/* What should we make now? The advertisement
+		   is invalid, but ndisc specs say nothing
+		   about it. It could be misconfiguration, or
+		   an smart proxy agent tries to help us :-)
+		 */
+		ND_PRINTK0("%s: someone advertises our address!\n",
+			   ifp->idev->dev->name);
+		in6_ifa_put(ifp);
+		return;
+	}
+	neigh = neigh_lookup(&nd_tbl, &msg->target, dev);
+
+	if (neigh) {
+		if (neigh->flags & NTF_ROUTER) {
+			if (msg->icmph.icmp6_router == 0) {
+				/*
+				 *	Change: router to host
+				 */
+				struct rt6_info *rt;
+				rt = rt6_get_dflt_router(saddr, dev);
+				if (rt) {
+					/* It is safe only because
+					   we aer in BH */
+					dst_release(&rt->u.dst);
+					ip6_del_rt(rt);
+				}
+			}
+		} else {
+			if (msg->icmph.icmp6_router)
+				neigh->flags |= NTF_ROUTER;
+		}
+
+		neigh_update(neigh, lladdr,
+			     msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE,
+			     msg->icmph.icmp6_override, 1);
+		neigh_release(neigh);
+	}
+}
+
 static void ndisc_router_discovery(struct sk_buff *skb)
 {
         struct ra_msg *ra_msg = (struct ra_msg *) skb->h.raw;
@@ -623,6 +869,7 @@
 	}
 
 	if (!ndisc_parse_options(opt, optlen, &ndopts)) {
+		in6_dev_put(in6_dev);
 		if (net_ratelimit())
 			ND_PRINTK2(KERN_WARNING
 				   "ICMP6 RA: invalid ND option, ignored.\n");
@@ -990,12 +1237,7 @@
 
 int ndisc_rcv(struct sk_buff *skb)
 {
-	struct net_device *dev = skb->dev;
-	struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
-	struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
 	struct nd_msg *msg = (struct nd_msg *) skb->h.raw;
-	struct neighbour *neigh;
-	struct inet6_ifaddr *ifp;
 
 	__skb_push(skb, skb->data-skb->h.raw);
 
@@ -1015,241 +1257,12 @@
 
 	switch (msg->icmph.icmp6_type) {
 	case NDISC_NEIGHBOUR_SOLICITATION:
-	    {
-		struct nd_msg *msg = (struct nd_msg *)skb->h.raw;
-		u8 *lladdr = NULL;
-		int lladdrlen = 0;
-		u32 ndoptlen = skb->tail - msg->opt;
-		struct ndisc_options ndopts;
-
-		if (skb->len < sizeof(struct nd_msg)) {
-			if (net_ratelimit())
-				printk(KERN_WARNING "ICMP NS: packet too short\n");
-			return 0;
-		}
-
-		if (ipv6_addr_type(&msg->target)&IPV6_ADDR_MULTICAST) {
-			if (net_ratelimit())
-				printk(KERN_WARNING "ICMP NS: target address is multicast\n");
-			return 0;
-		}
-
-		if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
-			if (net_ratelimit())
-				printk(KERN_WARNING "ICMP NS: invalid ND option, ignored.\n");
-			return 0;
-		}
-
-		if (ndopts.nd_opts_src_lladdr) {
-			lladdr = (u8*)(ndopts.nd_opts_src_lladdr + 1);
-			lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
-			if (lladdrlen != NDISC_OPT_SPACE(skb->dev->addr_len)) {
-				if (net_ratelimit())
-					printk(KERN_WARNING "ICMP NS: bad lladdr length.\n");
-				return 0;
-			}
-		}
-
-		/* XXX: RFC2461 7.1.1:
-		 * 	If the IP source address is the unspecified address, there
-		 *	MUST NOT be source link-layer address option in the message.
-		 *
-		 *	NOTE! Linux kernel < 2.4.4 broke this rule.
-		 */
-		 	
-		/* XXX: RFC2461 7.1.1:
-		 *	If the IP source address is the unspecified address, the IP
-      		 *	destination address MUST be a solicited-node multicast address.
-		 */
-
-		if ((ifp = ipv6_get_ifaddr(&msg->target, dev)) != NULL) {
-			int addr_type = ipv6_addr_type(saddr);
-
-			if (ifp->flags & IFA_F_TENTATIVE) {
-				/* Address is tentative. If the source
-				   is unspecified address, it is someone
-				   does DAD, otherwise we ignore solicitations
-				   until DAD timer expires.
-				 */
-				if (addr_type == IPV6_ADDR_ANY) {
-					if (dev->type == ARPHRD_IEEE802_TR) { 
-						unsigned char *sadr = skb->mac.raw ;
-						if (((sadr[8] &0x7f) != (dev->dev_addr[0] & 0x7f)) ||
-						(sadr[9] != dev->dev_addr[1]) ||
-						(sadr[10] != dev->dev_addr[2]) ||
-						(sadr[11] != dev->dev_addr[3]) ||
-						(sadr[12] != dev->dev_addr[4]) ||
-						(sadr[13] != dev->dev_addr[5])) 
-						{
-							addrconf_dad_failure(ifp) ; 
-						}
-					} else {
-						addrconf_dad_failure(ifp);
-					}
-				} else
-					in6_ifa_put(ifp);
-				return 0;
-			}
-
-			if (addr_type == IPV6_ADDR_ANY) {
-				struct in6_addr maddr;
-
-				ipv6_addr_all_nodes(&maddr);
-				ndisc_send_na(dev, NULL, &maddr, &ifp->addr, 
-					      ifp->idev->cnf.forwarding, 0, 
-					      ipv6_addr_type(&ifp->addr)&IPV6_ADDR_ANYCAST ? 0 : 1, 
-					      1);
-				in6_ifa_put(ifp);
-				return 0;
-			}
-
-			if (addr_type & IPV6_ADDR_UNICAST) {
-				int inc = ipv6_addr_type(daddr)&IPV6_ADDR_MULTICAST;
-
-				if (inc)
-					nd_tbl.stats.rcv_probes_mcast++;
-				else
-					nd_tbl.stats.rcv_probes_ucast++;
-
-				/* 
-				 *	update / create cache entry
-				 *	for the source adddress
-				 */
-
-				neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, skb->dev);
-
-				if (neigh || !dev->hard_header) {
-					ndisc_send_na(dev, neigh, saddr, &ifp->addr, 
-						      ifp->idev->cnf.forwarding, 1, 
-						      ipv6_addr_type(&ifp->addr)&IPV6_ADDR_ANYCAST ? 0 : 1, 
-						      1);
-					if (neigh)
-						neigh_release(neigh);
-				}
-			}
-			in6_ifa_put(ifp);
-		} else {
-			struct inet6_dev *in6_dev = in6_dev_get(dev);
-			int addr_type = ipv6_addr_type(saddr);
-
-			if (in6_dev && in6_dev->cnf.forwarding &&
-			    (addr_type & IPV6_ADDR_UNICAST) &&
-			    pneigh_lookup(&nd_tbl, &msg->target, dev, 0)) {
-				int inc = ipv6_addr_type(daddr)&IPV6_ADDR_MULTICAST;
-
-				if (skb->stamp.tv_sec == 0 ||
-				    skb->pkt_type == PACKET_HOST ||
-				    inc == 0 ||
-				    in6_dev->nd_parms->proxy_delay == 0) {
-					if (inc)
-						nd_tbl.stats.rcv_probes_mcast++;
-					else
-						nd_tbl.stats.rcv_probes_ucast++;
-
-					
-					neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, skb->dev);
-
-					if (neigh) {
-						ndisc_send_na(dev, neigh, saddr, &msg->target,
-							      0, 1, 0, 1);
-						neigh_release(neigh);
-					}
-				} else {
-					struct sk_buff *n = skb_clone(skb, GFP_ATOMIC);
-					if (n)
-						pneigh_enqueue(&nd_tbl, in6_dev->nd_parms, n);
-					in6_dev_put(in6_dev);
-					return 0;
-				}
-			}
-			if (in6_dev)
-				in6_dev_put(in6_dev);
-			
-		}
-		return 0;
-	    }
+		ndisc_recv_ns(skb);
+		break;
 
 	case NDISC_NEIGHBOUR_ADVERTISEMENT:
-	    {
-		struct nd_msg *msg = (struct nd_msg *)skb->h.raw;
-		u8 *lladdr = NULL;
-		int lladdrlen = 0;
-		u32 ndoptlen = skb->tail - msg->opt;
-		struct ndisc_options ndopts;
-
-		if (skb->len < sizeof(struct nd_msg)) {
-			if (net_ratelimit())
-				printk(KERN_WARNING "ICMP NA: packet too short\n");
-			return 0;
-		}
-
-		if (ipv6_addr_type(&msg->target)&IPV6_ADDR_MULTICAST) {
-			if (net_ratelimit())
-				printk(KERN_WARNING "NDISC NA: target address is multicast\n");
-			return 0;
-		}
-
-		if ((ipv6_addr_type(daddr)&IPV6_ADDR_MULTICAST) &&
-		    msg->icmph.icmp6_solicited) {
-			ND_PRINTK0("NDISC: solicited NA is multicasted\n");
-			return 0;
-		}
-		
-		if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
-			if (net_ratelimit())
-				printk(KERN_WARNING "ICMP NS: invalid ND option, ignored.\n");
-			return 0;
-		}
-		if (ndopts.nd_opts_tgt_lladdr) {
-			lladdr = (u8*)(ndopts.nd_opts_tgt_lladdr + 1);
-			lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3;
-			if (lladdrlen != NDISC_OPT_SPACE(skb->dev->addr_len)) {
-				if (net_ratelimit())
-					printk(KERN_WARNING "NDISC NA: invalid lladdr length.\n");
-				return 0;
-			}
-		}
-		if ((ifp = ipv6_get_ifaddr(&msg->target, dev))) {
-			if (ifp->flags & IFA_F_TENTATIVE) {
-				addrconf_dad_failure(ifp);
-				return 0;
-			}
-			/* What should we make now? The advertisement
-			   is invalid, but ndisc specs say nothing
-			   about it. It could be misconfiguration, or
-			   an smart proxy agent tries to help us :-)
-			 */
-			ND_PRINTK0("%s: someone advertises our address!\n",
-				   ifp->idev->dev->name);
-			in6_ifa_put(ifp);
-			return 0;
-		}
-		neigh = neigh_lookup(&nd_tbl, &msg->target, skb->dev);
-
-		if (neigh) {
-			if (neigh->flags & NTF_ROUTER) {
-				if (msg->icmph.icmp6_router == 0) {
-					/*
-					 *	Change: router to host
-					 */
-					struct rt6_info *rt;
-					rt = rt6_get_dflt_router(saddr, skb->dev);
-					if (rt) {
-						ip6_del_rt(rt);
-					}
-				}
-			} else {
-				if (msg->icmph.icmp6_router)
-					neigh->flags |= NTF_ROUTER;
-			}
-
-			neigh_update(neigh, lladdr,
-				     msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE,
-				     msg->icmph.icmp6_override, 1);
-			neigh_release(neigh);
-		}
+		ndisc_recv_na(skb);
 		break;
-	    }
 
 	case NDISC_ROUTER_ADVERTISEMENT:
 		ndisc_router_discovery(skb);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv6/netfilter/Config.in linux-2.4.21-pre6/net/ipv6/netfilter/Config.in
--- linux-2.4.20/net/ipv6/netfilter/Config.in	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv6/netfilter/Config.in	2003-03-26 23:49:02.000000000 +0000
@@ -18,12 +18,28 @@
 # The simple matches.
   dep_tristate '  limit match support' CONFIG_IP6_NF_MATCH_LIMIT $CONFIG_IP6_NF_IPTABLES
   dep_tristate '  MAC address match support' CONFIG_IP6_NF_MATCH_MAC $CONFIG_IP6_NF_IPTABLES
+  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+    dep_tristate '  Routing header match support (EXPERIMENTAL)' CONFIG_IP6_NF_MATCH_RT $CONFIG_IP6_NF_IPTABLES
+  fi
+  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+    dep_tristate '  Hop-by-Hop and Dst opts header match (EXPERIMENTAL)' CONFIG_IP6_NF_MATCH_OPTS $CONFIG_IP6_NF_IPTABLES
+  fi
+  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+    dep_tristate '  Fragmentation header match support (EXPERIMENTAL)' CONFIG_IP6_NF_MATCH_FRAG $CONFIG_IP6_NF_IPTABLES
+  fi
+  dep_tristate '  HL match support' CONFIG_IP6_NF_MATCH_HL $CONFIG_IP6_NF_IPTABLES
   dep_tristate '  Multiple port match support' CONFIG_IP6_NF_MATCH_MULTIPORT $CONFIG_IP6_NF_IPTABLES
   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
     dep_tristate '  Owner match support (EXPERIMENTAL)' CONFIG_IP6_NF_MATCH_OWNER $CONFIG_IP6_NF_IPTABLES
   fi
 #  dep_tristate '  MAC address match support' CONFIG_IP6_NF_MATCH_MAC $CONFIG_IP6_NF_IPTABLES
   dep_tristate '  netfilter MARK match support' CONFIG_IP6_NF_MATCH_MARK $CONFIG_IP6_NF_IPTABLES
+  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+    dep_tristate '  IPv6 Extension Headers Match (EXPERIMENTAL)' CONFIG_IP6_NF_MATCH_IPV6HEADER $CONFIG_IP6_NF_IPTABLES
+  fi
+  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+    dep_tristate '  AH/ESP match support (EXPERIMENTAL)' CONFIG_IP6_NF_MATCH_AHESP $CONFIG_IP6_NF_IPTABLES
+  fi
   dep_tristate '  Packet Length match support' CONFIG_IP6_NF_MATCH_LENGTH $CONFIG_IP6_NF_IPTABLES
   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
     dep_tristate '  EUI64 address check (EXPERIMENTAL)' CONFIG_IP6_NF_MATCH_EUI64 $CONFIG_IP6_NF_IPTABLES
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv6/netfilter/Makefile linux-2.4.21-pre6/net/ipv6/netfilter/Makefile
--- linux-2.4.20/net/ipv6/netfilter/Makefile	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv6/netfilter/Makefile	2003-03-26 23:48:58.000000000 +0000
@@ -17,6 +17,11 @@
 obj-$(CONFIG_IP6_NF_MATCH_MARK) += ip6t_mark.o
 obj-$(CONFIG_IP6_NF_MATCH_LENGTH) += ip6t_length.o
 obj-$(CONFIG_IP6_NF_MATCH_MAC) += ip6t_mac.o
+obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o
+obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o ip6t_dst.o
+obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o
+obj-$(CONFIG_IP6_NF_MATCH_FRAG) += ip6t_frag.o
+obj-$(CONFIG_IP6_NF_MATCH_AHESP) += ip6t_esp.o ip6t_ah.o
 obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o
 obj-$(CONFIG_IP6_NF_MATCH_MULTIPORT) += ip6t_multiport.o
 obj-$(CONFIG_IP6_NF_MATCH_OWNER) += ip6t_owner.o
@@ -25,5 +30,6 @@
 obj-$(CONFIG_IP6_NF_TARGET_MARK) += ip6t_MARK.o
 obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o
 obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o
+obj-$(CONFIG_IP_NF_MATCH_HL) += ip6t_hl.o
 
 include $(TOPDIR)/Rules.make
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv6/netfilter/ip6_queue.c linux-2.4.21-pre6/net/ipv6/netfilter/ip6_queue.c
--- linux-2.4.20/net/ipv6/netfilter/ip6_queue.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv6/netfilter/ip6_queue.c	2003-03-26 23:49:24.000000000 +0000
@@ -326,45 +326,6 @@
 	return status;
 }
 
-/*
- * Taken from net/ipv6/ip6_output.c
- *
- * We should use the one there, but is defined static
- * so we put this just here and let the things as
- * they are now.
- *
- * If that one is modified, this one should be modified too.
- */
-static int
-route6_me_harder(struct sk_buff *skb)
-{
-	struct ipv6hdr *iph = skb->nh.ipv6h;
-	struct dst_entry *dst;
-	struct flowi fl;
-
-	fl.proto = iph->nexthdr;
-	fl.fl6_dst = &iph->daddr;
-	fl.fl6_src = &iph->saddr;
-	fl.oif = skb->sk ? skb->sk->bound_dev_if : 0;
-	fl.fl6_flowlabel = 0;
-	fl.uli_u.ports.dport = 0;
-	fl.uli_u.ports.sport = 0;
-
-	dst = ip6_route_output(skb->sk, &fl);
-
-	if (dst->error) {
-		if (net_ratelimit())
-			printk(KERN_DEBUG "route6_me_harder: No more route.\n");
-		return -EINVAL;
-	}
-
-	/* Drop old route. */
-	dst_release(skb->dst);
-
-	skb->dst = dst;
-	return 0;
-}
-
 static int
 ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct ipq_queue_entry *e)
 {
@@ -410,7 +371,7 @@
 		struct ipv6hdr *iph = e->skb->nh.ipv6h;
 		if (ipv6_addr_cmp(&iph->daddr, &e->rt_info.daddr) ||
 		    ipv6_addr_cmp(&iph->saddr, &e->rt_info.saddr))
-			return route6_me_harder(e->skb);
+			return ip6_route_me_harder(e->skb);
 	}
 	return 0;
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv6/netfilter/ip6t_ah.c linux-2.4.21-pre6/net/ipv6/netfilter/ip6t_ah.c
--- linux-2.4.20/net/ipv6/netfilter/ip6t_ah.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv6/netfilter/ip6t_ah.c	2003-03-26 23:49:38.000000000 +0000
@@ -0,0 +1,218 @@
+/* Kernel module to match AH parameters. */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ipv6.h>
+#include <linux/types.h>
+#include <net/checksum.h>
+#include <net/ipv6.h>
+
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter_ipv6/ip6t_ah.h>
+
+EXPORT_NO_SYMBOLS;
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("IPv6 AH match");
+MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+struct ahhdr {
+       __u8    nexthdr;
+       __u8    hdrlen;
+       __u16   reserved;
+       __u32   spi;
+};
+
+int ipv6_ext_hdr(u8 nexthdr)
+{
+        return ( (nexthdr == NEXTHDR_HOP)       ||
+                 (nexthdr == NEXTHDR_ROUTING)   ||
+                 (nexthdr == NEXTHDR_FRAGMENT)  ||
+                 (nexthdr == NEXTHDR_AUTH)      ||
+                 (nexthdr == NEXTHDR_ESP)       ||
+                 (nexthdr == NEXTHDR_NONE)      ||
+                 (nexthdr == NEXTHDR_DEST) );
+}
+
+/* Returns 1 if the spi is matched by the range, 0 otherwise */
+static inline int
+spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert)
+{
+       int r=0;
+       DEBUGP("ah spi_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ',
+              min,spi,max);
+       r=(spi >= min && spi <= max) ^ invert;
+       DEBUGP(" result %s\n",r? "PASS\n" : "FAILED\n");
+       return r;
+}
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      const void *protohdr,
+      u_int16_t datalen,
+      int *hotdrop)
+{
+       struct ahhdr *ah = NULL;
+       const struct ip6t_ah *ahinfo = matchinfo;
+       unsigned int temp;
+       int len;
+       u8 nexthdr;
+       unsigned int ptr;
+       unsigned int hdrlen = 0;
+
+       /*DEBUGP("IPv6 AH entered\n");*/
+       /* if (opt->auth == 0) return 0;
+       * It does not filled on output */
+
+       /* type of the 1st exthdr */
+       nexthdr = skb->nh.ipv6h->nexthdr;
+       /* pointer to the 1st exthdr */
+       ptr = sizeof(struct ipv6hdr);
+       /* available length */
+       len = skb->len - ptr;
+       temp = 0;
+
+        while (ipv6_ext_hdr(nexthdr)) {
+               struct ipv6_opt_hdr *hdr;
+
+              DEBUGP("ipv6_ah header iteration \n");
+
+              /* Is there enough space for the next ext header? */
+                if (len < (int)sizeof(struct ipv6_opt_hdr))
+                        return 0;
+              /* No more exthdr -> evaluate */
+                if (nexthdr == NEXTHDR_NONE) {
+                     break;
+              }
+              /* ESP -> evaluate */
+                if (nexthdr == NEXTHDR_ESP) {
+                     break;
+              }
+
+              hdr=(struct ipv6_opt_hdr *)skb->data+ptr;
+
+              /* Calculate the header length */
+                if (nexthdr == NEXTHDR_FRAGMENT) {
+                        hdrlen = 8;
+                } else if (nexthdr == NEXTHDR_AUTH)
+                        hdrlen = (hdr->hdrlen+2)<<2;
+                else
+                        hdrlen = ipv6_optlen(hdr);
+
+              /* AH -> evaluate */
+                if (nexthdr == NEXTHDR_AUTH) {
+                     temp |= MASK_AH;
+                     break;
+              }
+
+
+              /* set the flag */
+              switch (nexthdr){
+                     case NEXTHDR_HOP:
+                     case NEXTHDR_ROUTING:
+                     case NEXTHDR_FRAGMENT:
+                     case NEXTHDR_AUTH:
+                     case NEXTHDR_DEST:
+                            break;
+                     default:
+                            DEBUGP("ipv6_ah match: unknown nextheader %u\n",nexthdr);
+                            return 0;
+                            break;
+              }
+
+                nexthdr = hdr->nexthdr;
+                len -= hdrlen;
+                ptr += hdrlen;
+		if ( ptr > skb->len ) {
+			DEBUGP("ipv6_ah: new pointer too large! \n");
+			break;
+		}
+        }
+
+       /* AH header not found */
+       if ( temp != MASK_AH ) return 0;
+
+       if (len < (int)sizeof(struct ahhdr)){
+	       *hotdrop = 1;
+       		return 0;
+       }
+
+       ah=skb->data+ptr;
+
+       DEBUGP("IPv6 AH LEN %u %u ", hdrlen, ah->hdrlen);
+       DEBUGP("RES %04X ", ah->reserved);
+       DEBUGP("SPI %u %08X\n", ntohl(ah->spi), ntohl(ah->spi));
+
+       DEBUGP("IPv6 AH spi %02X ",
+       		(spi_match(ahinfo->spis[0], ahinfo->spis[1],
+                           ntohl(ah->spi),
+                           !!(ahinfo->invflags & IP6T_AH_INV_SPI))));
+       DEBUGP("len %02X %04X %02X ",
+       		ahinfo->hdrlen, hdrlen,
+       		(!ahinfo->hdrlen ||
+                           (ahinfo->hdrlen == hdrlen) ^
+                           !!(ahinfo->invflags & IP6T_AH_INV_LEN)));
+       DEBUGP("res %02X %04X %02X\n", 
+       		ahinfo->hdrres, ah->reserved,
+       		!(ahinfo->hdrres && ah->reserved));
+
+       return (ah != NULL)
+              &&
+              (spi_match(ahinfo->spis[0], ahinfo->spis[1],
+                           ntohl(ah->spi),
+                           !!(ahinfo->invflags & IP6T_AH_INV_SPI)))
+              &&
+              (!ahinfo->hdrlen ||
+                           (ahinfo->hdrlen == hdrlen) ^
+                           !!(ahinfo->invflags & IP6T_AH_INV_LEN))
+              &&
+              !(ahinfo->hdrres && ah->reserved);
+}
+
+/* Called when user tries to insert an entry of this type. */
+static int
+checkentry(const char *tablename,
+          const struct ip6t_ip6 *ip,
+          void *matchinfo,
+          unsigned int matchinfosize,
+          unsigned int hook_mask)
+{
+       const struct ip6t_ah *ahinfo = matchinfo;
+
+       if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_ah))) {
+              DEBUGP("ip6t_ah: matchsize %u != %u\n",
+                      matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_ah)));
+              return 0;
+       }
+       if (ahinfo->invflags & ~IP6T_AH_INV_MASK) {
+              DEBUGP("ip6t_ah: unknown flags %X\n",
+                      ahinfo->invflags);
+              return 0;
+       }
+
+       return 1;
+}
+
+static struct ip6t_match ah_match
+= { { NULL, NULL }, "ah", &match, &checkentry, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+       return ip6t_register_match(&ah_match);
+}
+
+static void __exit cleanup(void)
+{
+       ip6t_unregister_match(&ah_match);
+}
+
+module_init(init);
+module_exit(cleanup);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv6/netfilter/ip6t_dst.c linux-2.4.21-pre6/net/ipv6/netfilter/ip6t_dst.c
--- linux-2.4.20/net/ipv6/netfilter/ip6t_dst.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv6/netfilter/ip6t_dst.c	2003-03-26 23:49:31.000000000 +0000
@@ -0,0 +1,287 @@
+/* Kernel module to match Hop-by-Hop and Destination parameters. */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ipv6.h>
+#include <linux/types.h>
+#include <net/checksum.h>
+#include <net/ipv6.h>
+
+#include <asm/byteorder.h>
+
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter_ipv6/ip6t_opts.h>
+
+#define LOW(n)		(n & 0x00FF)
+
+#define HOPBYHOP	0
+
+EXPORT_NO_SYMBOLS;
+MODULE_LICENSE("GPL");
+#if HOPBYHOP
+MODULE_DESCRIPTION("IPv6 HbH match");
+#else
+MODULE_DESCRIPTION("IPv6 DST match");
+#endif
+MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+int ipv6_ext_hdr(u8 nexthdr)
+{
+        return ( (nexthdr == NEXTHDR_HOP)       ||
+                 (nexthdr == NEXTHDR_ROUTING)   ||
+                 (nexthdr == NEXTHDR_FRAGMENT)  ||
+                 (nexthdr == NEXTHDR_AUTH)      ||
+                 (nexthdr == NEXTHDR_ESP)       ||
+                 (nexthdr == NEXTHDR_NONE)      ||
+                 (nexthdr == NEXTHDR_DEST) );
+}
+
+/*
+ * (Type & 0xC0) >> 6
+ * 	0	-> ignorable
+ * 	1	-> must drop the packet
+ * 	2	-> send ICMP PARM PROB regardless and drop packet
+ * 	3	-> Send ICMP if not a multicast address and drop packet
+ *  (Type & 0x20) >> 5
+ *  	0	-> invariant
+ *  	1	-> can change the routing
+ *  (Type & 0x1F) Type
+ *      0	-> PAD0 (only 1 byte!)
+ *      1	-> PAD1 LENGTH info (total length = length + 2)
+ *      C0 | 2	-> JUMBO 4 x x x x ( xxxx > 64k )
+ *      5	-> RTALERT 2 x x
+ */
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      const void *protohdr,
+      u_int16_t datalen,
+      int *hotdrop)
+{
+       struct ipv6_opt_hdr *optsh = NULL;
+       const struct ip6t_opts *optinfo = matchinfo;
+       unsigned int temp;
+       unsigned int len;
+       u8 nexthdr;
+       unsigned int ptr;
+       unsigned int hdrlen = 0;
+       unsigned int ret = 0;
+       u_int16_t *optdesc = NULL;
+       
+       /* type of the 1st exthdr */
+       nexthdr = skb->nh.ipv6h->nexthdr;
+       /* pointer to the 1st exthdr */
+       ptr = sizeof(struct ipv6hdr);
+       /* available length */
+       len = skb->len - ptr;
+       temp = 0;
+
+        while (ipv6_ext_hdr(nexthdr)) {
+               struct ipv6_opt_hdr *hdr;
+
+              DEBUGP("ipv6_opts header iteration \n");
+
+              /* Is there enough space for the next ext header? */
+                if (len < (int)sizeof(struct ipv6_opt_hdr))
+                        return 0;
+              /* No more exthdr -> evaluate */
+                if (nexthdr == NEXTHDR_NONE) {
+                     break;
+              }
+              /* ESP -> evaluate */
+                if (nexthdr == NEXTHDR_ESP) {
+                     break;
+              }
+
+              hdr=(void *)(skb->data)+ptr;
+
+              /* Calculate the header length */
+                if (nexthdr == NEXTHDR_FRAGMENT) {
+                        hdrlen = 8;
+                } else if (nexthdr == NEXTHDR_AUTH)
+                        hdrlen = (hdr->hdrlen+2)<<2;
+                else
+                        hdrlen = ipv6_optlen(hdr);
+
+              /* OPTS -> evaluate */
+#if HOPBYHOP
+                if (nexthdr == NEXTHDR_HOP) {
+                     temp |= MASK_HOPOPTS;
+#else
+                if (nexthdr == NEXTHDR_DEST) {
+                     temp |= MASK_DSTOPTS;
+#endif
+                     break;
+              }
+
+
+              /* set the flag */
+              switch (nexthdr){
+                     case NEXTHDR_HOP:
+                     case NEXTHDR_ROUTING:
+                     case NEXTHDR_FRAGMENT:
+                     case NEXTHDR_AUTH:
+                     case NEXTHDR_DEST:
+                            break;
+                     default:
+                            DEBUGP("ipv6_opts match: unknown nextheader %u\n",nexthdr);
+                            return 0;
+                            break;
+              }
+
+                nexthdr = hdr->nexthdr;
+                len -= hdrlen;
+                ptr += hdrlen;
+		if ( ptr > skb->len ) {
+			DEBUGP("ipv6_opts: new pointer is too large! \n");
+			break;
+		}
+        }
+
+       /* OPTIONS header not found */
+#if HOPBYHOP
+       if ( temp != MASK_HOPOPTS ) return 0;
+#else
+       if ( temp != MASK_DSTOPTS ) return 0;
+#endif
+
+       if (len < (int)sizeof(struct ipv6_opt_hdr)){
+	       *hotdrop = 1;
+       		return 0;
+       }
+
+       if (len < hdrlen){
+	       /* Packet smaller than it's length field */
+       		return 0;
+       }
+
+       optsh=(void *)(skb->data)+ptr;
+
+       DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, optsh->hdrlen);
+
+       DEBUGP("len %02X %04X %02X ",
+       		optinfo->hdrlen, hdrlen,
+       		(!(optinfo->flags & IP6T_OPTS_LEN) ||
+                           ((optinfo->hdrlen == hdrlen) ^
+                           !!(optinfo->invflags & IP6T_OPTS_INV_LEN))));
+
+       ret = (optsh != NULL)
+       		&&
+	      	(!(optinfo->flags & IP6T_OPTS_LEN) ||
+                           ((optinfo->hdrlen == hdrlen) ^
+                           !!(optinfo->invflags & IP6T_OPTS_INV_LEN)));
+
+       temp = len = 0;
+       ptr += 2;
+       hdrlen -= 2;
+       if ( !(optinfo->flags & IP6T_OPTS_OPTS) ){
+	       return ret;
+	} else if (optinfo->flags & IP6T_OPTS_NSTRICT) {
+		DEBUGP("Not strict - not implemented");
+	} else {
+		DEBUGP("Strict ");
+		DEBUGP("#%d ",optinfo->optsnr);
+		for(temp=0; temp<optinfo->optsnr; temp++){
+			optdesc = (void *)(skb->data)+ptr;
+			/* Type check */
+			if ( (unsigned char)*optdesc != 
+				(optinfo->opts[temp] & 0xFF00)>>8 ){
+				DEBUGP("Tbad %02X %02X\n",
+						(unsigned char)*optdesc,
+						(optinfo->opts[temp] &
+						 0xFF00)>>8);
+				return 0;
+			} else {
+				DEBUGP("Tok ");
+			}
+			/* Length check */
+			if (((optinfo->opts[temp] & 0x00FF) != 0xFF) &&
+				(unsigned char)*optdesc != 0){
+				if ( ntohs((u16)*optdesc) != 
+						optinfo->opts[temp] ){
+					DEBUGP("Lbad %02X %04X %04X\n",
+							(unsigned char)*optdesc,
+							ntohs((u16)*optdesc),
+							optinfo->opts[temp]);
+					return 0;
+				} else {
+					DEBUGP("Lok ");
+				}
+			}
+			/* Step to the next */
+			if ((unsigned char)*optdesc == 0){
+				DEBUGP("PAD0 \n");
+				ptr++;
+				hdrlen--;
+			} else {
+				ptr += LOW(ntohs(*optdesc));
+				hdrlen -= LOW(ntohs(*optdesc));
+				DEBUGP("len%04X \n", 
+					LOW(ntohs(*optdesc)));
+			}
+			if (ptr > skb->len || ( !hdrlen && 
+				(temp != optinfo->optsnr - 1))) {
+				DEBUGP("new pointer is too large! \n");
+				break;
+			}
+		}
+		if (temp == optinfo->optsnr)
+			return ret;
+		else return 0;
+	}
+
+	return 0;
+}
+
+/* Called when user tries to insert an entry of this type. */
+static int
+checkentry(const char *tablename,
+          const struct ip6t_ip6 *ip,
+          void *matchinfo,
+          unsigned int matchinfosize,
+          unsigned int hook_mask)
+{
+       const struct ip6t_opts *optsinfo = matchinfo;
+
+       if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_opts))) {
+              DEBUGP("ip6t_opts: matchsize %u != %u\n",
+                      matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_opts)));
+              return 0;
+       }
+       if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) {
+              DEBUGP("ip6t_opts: unknown flags %X\n",
+                      optsinfo->invflags);
+              return 0;
+       }
+
+       return 1;
+}
+
+static struct ip6t_match opts_match
+#if HOPBYHOP
+= { { NULL, NULL }, "hbh", &match, &checkentry, NULL, THIS_MODULE };
+#else
+= { { NULL, NULL }, "dst", &match, &checkentry, NULL, THIS_MODULE };
+#endif
+
+static int __init init(void)
+{
+       return ip6t_register_match(&opts_match);
+}
+
+static void __exit cleanup(void)
+{
+       ip6t_unregister_match(&opts_match);
+}
+
+module_init(init);
+module_exit(cleanup);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv6/netfilter/ip6t_esp.c linux-2.4.21-pre6/net/ipv6/netfilter/ip6t_esp.c
--- linux-2.4.20/net/ipv6/netfilter/ip6t_esp.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv6/netfilter/ip6t_esp.c	2003-03-26 23:49:02.000000000 +0000
@@ -0,0 +1,186 @@
+/* Kernel module to match ESP parameters. */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ipv6.h>
+#include <linux/types.h>
+#include <net/checksum.h>
+#include <net/ipv6.h>
+
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter_ipv6/ip6t_esp.h>
+
+EXPORT_NO_SYMBOLS;
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("IPv6 ESP match");
+MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+struct esphdr {
+	__u32   spi;
+};
+
+int ipv6_ext_hdr(u8 nexthdr)
+{
+        return ( (nexthdr == NEXTHDR_HOP)       ||
+                 (nexthdr == NEXTHDR_ROUTING)   ||
+                 (nexthdr == NEXTHDR_FRAGMENT)  ||
+                 (nexthdr == NEXTHDR_AUTH)      ||
+                 (nexthdr == NEXTHDR_ESP)       ||
+                 (nexthdr == NEXTHDR_NONE)      ||
+                 (nexthdr == NEXTHDR_DEST) );
+}
+
+/* Returns 1 if the spi is matched by the range, 0 otherwise */
+static inline int
+spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert)
+{
+	int r=0;
+        DEBUGP("esp spi_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ',
+        	min,spi,max);
+	r=(spi >= min && spi <= max) ^ invert;
+	DEBUGP(" result %s\n",r? "PASS\n" : "FAILED\n");
+	return r;
+}
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      const void *protohdr,
+      u_int16_t datalen,
+      int *hotdrop)
+{
+	struct esphdr *esp = NULL;
+	const struct ip6t_esp *espinfo = matchinfo;
+	unsigned int temp;
+	int len;
+	u8 nexthdr;
+	unsigned int ptr;
+
+	/* Make sure this isn't an evil packet */
+	/*DEBUGP("ipv6_esp entered \n");*/
+
+	/* type of the 1st exthdr */
+	nexthdr = skb->nh.ipv6h->nexthdr;
+	/* pointer to the 1st exthdr */
+	ptr = sizeof(struct ipv6hdr);
+	/* available length */
+	len = skb->len - ptr;
+	temp = 0;
+
+        while (ipv6_ext_hdr(nexthdr)) {
+        	struct ipv6_opt_hdr *hdr;
+        	int hdrlen;
+
+		DEBUGP("ipv6_esp header iteration \n");
+
+		/* Is there enough space for the next ext header? */
+                if (len < (int)sizeof(struct ipv6_opt_hdr))
+                        return 0;
+		/* No more exthdr -> evaluate */
+                if (nexthdr == NEXTHDR_NONE) {
+			break;
+		}
+		/* ESP -> evaluate */
+                if (nexthdr == NEXTHDR_ESP) {
+			temp |= MASK_ESP;
+			break;
+		}
+
+		hdr=(struct ipv6_opt_hdr *)skb->data+ptr;
+
+		/* Calculate the header length */
+                if (nexthdr == NEXTHDR_FRAGMENT) {
+                        hdrlen = 8;
+                } else if (nexthdr == NEXTHDR_AUTH)
+                        hdrlen = (hdr->hdrlen+2)<<2;
+                else
+                        hdrlen = ipv6_optlen(hdr);
+
+		/* set the flag */
+		switch (nexthdr){
+			case NEXTHDR_HOP:
+			case NEXTHDR_ROUTING:
+			case NEXTHDR_FRAGMENT:
+			case NEXTHDR_AUTH:
+			case NEXTHDR_DEST:
+				break;
+			default:
+				DEBUGP("ipv6_esp match: unknown nextheader %u\n",nexthdr);
+				return 0;
+				break;
+		}
+
+                nexthdr = hdr->nexthdr;
+                len -= hdrlen;
+                ptr += hdrlen;
+		if ( ptr > skb->len ) {
+			DEBUGP("ipv6_esp: new pointer too large! \n");
+			break;
+		}
+        }
+
+	/* ESP header not found */
+	if ( temp != MASK_ESP ) return 0;
+
+       if (len < (int)sizeof(struct esphdr)){
+	       *hotdrop = 1;
+       		return 0;
+       }
+
+	esp=skb->data+ptr;
+
+	DEBUGP("IPv6 ESP SPI %u %08X\n", ntohl(esp->spi), ntohl(esp->spi));
+
+	return (esp != NULL)
+		&& spi_match(espinfo->spis[0], espinfo->spis[1],
+			      ntohl(esp->spi),
+			      !!(espinfo->invflags & IP6T_ESP_INV_SPI));
+}
+
+/* Called when user tries to insert an entry of this type. */
+static int
+checkentry(const char *tablename,
+	   const struct ip6t_ip6 *ip,
+	   void *matchinfo,
+	   unsigned int matchinfosize,
+	   unsigned int hook_mask)
+{
+	const struct ip6t_esp *espinfo = matchinfo;
+
+	if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_esp))) {
+		DEBUGP("ip6t_esp: matchsize %u != %u\n",
+			 matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_esp)));
+		return 0;
+	}
+	if (espinfo->invflags & ~IP6T_ESP_INV_MASK) {
+		DEBUGP("ip6t_esp: unknown flags %X\n",
+			 espinfo->invflags);
+		return 0;
+	}
+
+	return 1;
+}
+
+static struct ip6t_match esp_match
+= { { NULL, NULL }, "esp", &match, &checkentry, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+	return ip6t_register_match(&esp_match);
+}
+
+static void __exit cleanup(void)
+{
+	ip6t_unregister_match(&esp_match);
+}
+
+module_init(init);
+module_exit(cleanup);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv6/netfilter/ip6t_frag.c linux-2.4.21-pre6/net/ipv6/netfilter/ip6t_frag.c
--- linux-2.4.20/net/ipv6/netfilter/ip6t_frag.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv6/netfilter/ip6t_frag.c	2003-03-26 23:49:09.000000000 +0000
@@ -0,0 +1,250 @@
+/* Kernel module to match FRAG parameters. */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ipv6.h>
+#include <linux/types.h>
+#include <net/checksum.h>
+#include <net/ipv6.h>
+
+#include <asm/byteorder.h>
+
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter_ipv6/ip6t_frag.h>
+
+EXPORT_NO_SYMBOLS;
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("IPv6 FRAG match");
+MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+#if 0
+#if     BYTE_ORDER == BIG_ENDIAN
+#define IP6F_OFF_MASK       0xfff8  /* mask out offset from _offlg */
+#define IP6F_RESERVED_MASK  0x0006  /* reserved bits in ip6f_offlg */
+#define IP6F_MORE_FRAG      0x0001  /* more-fragments flag */
+#else   /* BYTE_ORDER == LITTLE_ENDIAN */
+#define IP6F_OFF_MASK       0xf8ff  /* mask out offset from _offlg */
+#define IP6F_RESERVED_MASK  0x0600  /* reserved bits in ip6f_offlg */
+#define IP6F_MORE_FRAG      0x0100  /* more-fragments flag */
+#endif
+#endif
+
+#define IP6F_OFF_MASK       0xf8ff  /* mask out offset from _offlg */
+#define IP6F_RESERVED_MASK  0x0600  /* reserved bits in ip6f_offlg */
+#define IP6F_MORE_FRAG      0x0100  /* more-fragments flag */
+
+struct fraghdr {
+       __u8    nexthdr;
+       __u8    hdrlen;
+       __u16   info;
+       __u32   id;
+};
+
+int ipv6_ext_hdr(u8 nexthdr)
+{
+        return ( (nexthdr == NEXTHDR_HOP)       ||
+                 (nexthdr == NEXTHDR_ROUTING)   ||
+                 (nexthdr == NEXTHDR_FRAGMENT)  ||
+                 (nexthdr == NEXTHDR_AUTH)      ||
+                 (nexthdr == NEXTHDR_ESP)       ||
+                 (nexthdr == NEXTHDR_NONE)      ||
+                 (nexthdr == NEXTHDR_DEST) );
+}
+
+/* Returns 1 if the id is matched by the range, 0 otherwise */
+static inline int
+id_match(u_int32_t min, u_int32_t max, u_int32_t id, int invert)
+{
+       int r=0;
+       DEBUGP("frag id_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ',
+              min,id,max);
+       r=(id >= min && id <= max) ^ invert;
+       DEBUGP(" result %s\n",r? "PASS" : "FAILED");
+       return r;
+}
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      const void *protohdr,
+      u_int16_t datalen,
+      int *hotdrop)
+{
+       struct fraghdr *frag = NULL;
+       const struct ip6t_frag *fraginfo = matchinfo;
+       unsigned int temp;
+       int len;
+       u8 nexthdr;
+       unsigned int ptr;
+       unsigned int hdrlen = 0;
+
+       /* type of the 1st exthdr */
+       nexthdr = skb->nh.ipv6h->nexthdr;
+       /* pointer to the 1st exthdr */
+       ptr = sizeof(struct ipv6hdr);
+       /* available length */
+       len = skb->len - ptr;
+       temp = 0;
+
+        while (ipv6_ext_hdr(nexthdr)) {
+               struct ipv6_opt_hdr *hdr;
+
+              DEBUGP("ipv6_frag header iteration \n");
+
+              /* Is there enough space for the next ext header? */
+                if (len < (int)sizeof(struct ipv6_opt_hdr))
+                        return 0;
+              /* No more exthdr -> evaluate */
+                if (nexthdr == NEXTHDR_NONE) {
+                     break;
+              }
+              /* ESP -> evaluate */
+                if (nexthdr == NEXTHDR_ESP) {
+                     break;
+              }
+
+              hdr=(struct ipv6_opt_hdr *)skb->data+ptr;
+
+              /* Calculate the header length */
+                if (nexthdr == NEXTHDR_FRAGMENT) {
+                        hdrlen = 8;
+                } else if (nexthdr == NEXTHDR_AUTH)
+                        hdrlen = (hdr->hdrlen+2)<<2;
+                else
+                        hdrlen = ipv6_optlen(hdr);
+
+              /* FRAG -> evaluate */
+                if (nexthdr == NEXTHDR_FRAGMENT) {
+                     temp |= MASK_FRAGMENT;
+                     break;
+              }
+
+
+              /* set the flag */
+              switch (nexthdr){
+                     case NEXTHDR_HOP:
+                     case NEXTHDR_ROUTING:
+                     case NEXTHDR_FRAGMENT:
+                     case NEXTHDR_AUTH:
+                     case NEXTHDR_DEST:
+                            break;
+                     default:
+                            DEBUGP("ipv6_frag match: unknown nextheader %u\n",nexthdr);
+                            return 0;
+                            break;
+              }
+
+                nexthdr = hdr->nexthdr;
+                len -= hdrlen;
+                ptr += hdrlen;
+		if ( ptr > skb->len ) {
+			DEBUGP("ipv6_frag: new pointer too large! \n");
+			break;
+		}
+        }
+
+       /* FRAG header not found */
+       if ( temp != MASK_FRAGMENT ) return 0;
+
+       if (len < (int)sizeof(struct fraghdr)){
+	       *hotdrop = 1;
+       		return 0;
+       }
+
+       frag=skb->data+ptr;
+
+       DEBUGP("IPv6 FRAG LEN %u %u ", hdrlen, frag->hdrlen);
+       DEBUGP("INFO %04X ", frag->info);
+       DEBUGP("OFFSET %04X ", frag->info & IP6F_OFF_MASK);
+       DEBUGP("RES %04X ", frag->info & IP6F_RESERVED_MASK);
+       DEBUGP("MF %04X ", frag->info & IP6F_MORE_FRAG);
+       DEBUGP("ID %u %08X\n", ntohl(frag->id), ntohl(frag->id));
+
+       DEBUGP("IPv6 FRAG id %02X ",
+       		(id_match(fraginfo->ids[0], fraginfo->ids[1],
+                           ntohl(frag->id),
+                           !!(fraginfo->invflags & IP6T_FRAG_INV_IDS))));
+       DEBUGP("len %02X %04X %02X ",
+       		fraginfo->hdrlen, hdrlen,
+       		(!fraginfo->hdrlen ||
+                           (fraginfo->hdrlen == hdrlen) ^
+                           !!(fraginfo->invflags & IP6T_FRAG_INV_LEN)));
+       DEBUGP("res %02X %02X %02X ", 
+       		(fraginfo->flags & IP6T_FRAG_RES), frag->info & IP6F_RESERVED_MASK,
+       		!((fraginfo->flags & IP6T_FRAG_RES) && (frag->info & IP6F_RESERVED_MASK)));
+       DEBUGP("first %02X %02X %02X ", 
+       		(fraginfo->flags & IP6T_FRAG_FST), frag->info & IP6F_OFF_MASK,
+       		!((fraginfo->flags & IP6T_FRAG_FST) && (frag->info & IP6F_OFF_MASK)));
+       DEBUGP("mf %02X %02X %02X ", 
+       		(fraginfo->flags & IP6T_FRAG_MF), frag->info & IP6F_MORE_FRAG,
+       		!((fraginfo->flags & IP6T_FRAG_MF) && !((frag->info & IP6F_MORE_FRAG))));
+       DEBUGP("last %02X %02X %02X\n", 
+       		(fraginfo->flags & IP6T_FRAG_NMF), frag->info & IP6F_MORE_FRAG,
+       		!((fraginfo->flags & IP6T_FRAG_NMF) && (frag->info & IP6F_MORE_FRAG)));
+
+       return (frag != NULL)
+       		&&
+       		(id_match(fraginfo->ids[0], fraginfo->ids[1],
+                           ntohl(frag->id),
+                           !!(fraginfo->invflags & IP6T_FRAG_INV_IDS)))
+		&&
+	      	(!fraginfo->hdrlen ||
+                           (fraginfo->hdrlen == hdrlen) ^
+                           !!(fraginfo->invflags & IP6T_FRAG_INV_LEN))
+		&&
+		!((fraginfo->flags & IP6T_FRAG_RES) && (frag->info & IP6F_RESERVED_MASK))
+		&&
+		!((fraginfo->flags & IP6T_FRAG_FST) && (frag->info & IP6F_OFF_MASK))
+		&&
+		!((fraginfo->flags & IP6T_FRAG_MF) && !((frag->info & IP6F_MORE_FRAG)))
+		&&
+		!((fraginfo->flags & IP6T_FRAG_NMF) && (frag->info & IP6F_MORE_FRAG));
+}
+
+/* Called when user tries to insert an entry of this type. */
+static int
+checkentry(const char *tablename,
+          const struct ip6t_ip6 *ip,
+          void *matchinfo,
+          unsigned int matchinfosize,
+          unsigned int hook_mask)
+{
+       const struct ip6t_frag *fraginfo = matchinfo;
+
+       if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_frag))) {
+              DEBUGP("ip6t_frag: matchsize %u != %u\n",
+                      matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_frag)));
+              return 0;
+       }
+       if (fraginfo->invflags & ~IP6T_FRAG_INV_MASK) {
+              DEBUGP("ip6t_frag: unknown flags %X\n",
+                      fraginfo->invflags);
+              return 0;
+       }
+
+       return 1;
+}
+
+static struct ip6t_match frag_match
+= { { NULL, NULL }, "frag", &match, &checkentry, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+       return ip6t_register_match(&frag_match);
+}
+
+static void __exit cleanup(void)
+{
+       ip6t_unregister_match(&frag_match);
+}
+
+module_init(init);
+module_exit(cleanup);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv6/netfilter/ip6t_hbh.c linux-2.4.21-pre6/net/ipv6/netfilter/ip6t_hbh.c
--- linux-2.4.20/net/ipv6/netfilter/ip6t_hbh.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv6/netfilter/ip6t_hbh.c	2003-03-26 23:49:39.000000000 +0000
@@ -0,0 +1,287 @@
+/* Kernel module to match Hop-by-Hop and Destination parameters. */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ipv6.h>
+#include <linux/types.h>
+#include <net/checksum.h>
+#include <net/ipv6.h>
+
+#include <asm/byteorder.h>
+
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter_ipv6/ip6t_opts.h>
+
+#define LOW(n)		(n & 0x00FF)
+
+#define HOPBYHOP	1
+
+EXPORT_NO_SYMBOLS;
+MODULE_LICENSE("GPL");
+#if HOPBYHOP
+MODULE_DESCRIPTION("IPv6 HbH match");
+#else
+MODULE_DESCRIPTION("IPv6 DST match");
+#endif
+MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+int ipv6_ext_hdr(u8 nexthdr)
+{
+        return ( (nexthdr == NEXTHDR_HOP)       ||
+                 (nexthdr == NEXTHDR_ROUTING)   ||
+                 (nexthdr == NEXTHDR_FRAGMENT)  ||
+                 (nexthdr == NEXTHDR_AUTH)      ||
+                 (nexthdr == NEXTHDR_ESP)       ||
+                 (nexthdr == NEXTHDR_NONE)      ||
+                 (nexthdr == NEXTHDR_DEST) );
+}
+
+/*
+ * (Type & 0xC0) >> 6
+ * 	0	-> ignorable
+ * 	1	-> must drop the packet
+ * 	2	-> send ICMP PARM PROB regardless and drop packet
+ * 	3	-> Send ICMP if not a multicast address and drop packet
+ *  (Type & 0x20) >> 5
+ *  	0	-> invariant
+ *  	1	-> can change the routing
+ *  (Type & 0x1F) Type
+ *      0	-> PAD0 (only 1 byte!)
+ *      1	-> PAD1 LENGTH info (total length = length + 2)
+ *      C0 | 2	-> JUMBO 4 x x x x ( xxxx > 64k )
+ *      5	-> RTALERT 2 x x
+ */
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      const void *protohdr,
+      u_int16_t datalen,
+      int *hotdrop)
+{
+       struct ipv6_opt_hdr *optsh = NULL;
+       const struct ip6t_opts *optinfo = matchinfo;
+       unsigned int temp;
+       unsigned int len;
+       u8 nexthdr;
+       unsigned int ptr;
+       unsigned int hdrlen = 0;
+       unsigned int ret = 0;
+       u_int16_t *optdesc = NULL;
+       
+       /* type of the 1st exthdr */
+       nexthdr = skb->nh.ipv6h->nexthdr;
+       /* pointer to the 1st exthdr */
+       ptr = sizeof(struct ipv6hdr);
+       /* available length */
+       len = skb->len - ptr;
+       temp = 0;
+
+        while (ipv6_ext_hdr(nexthdr)) {
+               struct ipv6_opt_hdr *hdr;
+
+              DEBUGP("ipv6_opts header iteration \n");
+
+              /* Is there enough space for the next ext header? */
+                if (len < (int)sizeof(struct ipv6_opt_hdr))
+                        return 0;
+              /* No more exthdr -> evaluate */
+                if (nexthdr == NEXTHDR_NONE) {
+                     break;
+              }
+              /* ESP -> evaluate */
+                if (nexthdr == NEXTHDR_ESP) {
+                     break;
+              }
+
+              hdr=(void *)(skb->data)+ptr;
+
+              /* Calculate the header length */
+                if (nexthdr == NEXTHDR_FRAGMENT) {
+                        hdrlen = 8;
+                } else if (nexthdr == NEXTHDR_AUTH)
+                        hdrlen = (hdr->hdrlen+2)<<2;
+                else
+                        hdrlen = ipv6_optlen(hdr);
+
+              /* OPTS -> evaluate */
+#if HOPBYHOP
+                if (nexthdr == NEXTHDR_HOP) {
+                     temp |= MASK_HOPOPTS;
+#else
+                if (nexthdr == NEXTHDR_DEST) {
+                     temp |= MASK_DSTOPTS;
+#endif
+                     break;
+              }
+
+
+              /* set the flag */
+              switch (nexthdr){
+                     case NEXTHDR_HOP:
+                     case NEXTHDR_ROUTING:
+                     case NEXTHDR_FRAGMENT:
+                     case NEXTHDR_AUTH:
+                     case NEXTHDR_DEST:
+                            break;
+                     default:
+                            DEBUGP("ipv6_opts match: unknown nextheader %u\n",nexthdr);
+                            return 0;
+                            break;
+              }
+
+                nexthdr = hdr->nexthdr;
+                len -= hdrlen;
+                ptr += hdrlen;
+		if ( ptr > skb->len ) {
+			DEBUGP("ipv6_opts: new pointer is too large! \n");
+			break;
+		}
+        }
+
+       /* OPTIONS header not found */
+#if HOPBYHOP
+       if ( temp != MASK_HOPOPTS ) return 0;
+#else
+       if ( temp != MASK_DSTOPTS ) return 0;
+#endif
+
+       if (len < (int)sizeof(struct ipv6_opt_hdr)){
+	       *hotdrop = 1;
+       		return 0;
+       }
+
+       if (len < hdrlen){
+	       /* Packet smaller than it's length field */
+       		return 0;
+       }
+
+       optsh=(void *)(skb->data)+ptr;
+
+       DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, optsh->hdrlen);
+
+       DEBUGP("len %02X %04X %02X ",
+       		optinfo->hdrlen, hdrlen,
+       		(!(optinfo->flags & IP6T_OPTS_LEN) ||
+                           ((optinfo->hdrlen == hdrlen) ^
+                           !!(optinfo->invflags & IP6T_OPTS_INV_LEN))));
+
+       ret = (optsh != NULL)
+       		&&
+	      	(!(optinfo->flags & IP6T_OPTS_LEN) ||
+                           ((optinfo->hdrlen == hdrlen) ^
+                           !!(optinfo->invflags & IP6T_OPTS_INV_LEN)));
+
+       temp = len = 0;
+       ptr += 2;
+       hdrlen -= 2;
+       if ( !(optinfo->flags & IP6T_OPTS_OPTS) ){
+	       return ret;
+	} else if (optinfo->flags & IP6T_OPTS_NSTRICT) {
+		DEBUGP("Not strict - not implemented");
+	} else {
+		DEBUGP("Strict ");
+		DEBUGP("#%d ",optinfo->optsnr);
+		for(temp=0; temp<optinfo->optsnr; temp++){
+			optdesc = (void *)(skb->data)+ptr;
+			/* Type check */
+			if ( (unsigned char)*optdesc != 
+				(optinfo->opts[temp] & 0xFF00)>>8 ){
+				DEBUGP("Tbad %02X %02X\n",
+						(unsigned char)*optdesc,
+						(optinfo->opts[temp] &
+						 0xFF00)>>8);
+				return 0;
+			} else {
+				DEBUGP("Tok ");
+			}
+			/* Length check */
+			if (((optinfo->opts[temp] & 0x00FF) != 0xFF) &&
+				(unsigned char)*optdesc != 0){
+				if ( ntohs((u16)*optdesc) != 
+						optinfo->opts[temp] ){
+					DEBUGP("Lbad %02X %04X %04X\n",
+							(unsigned char)*optdesc,
+							ntohs((u16)*optdesc),
+							optinfo->opts[temp]);
+					return 0;
+				} else {
+					DEBUGP("Lok ");
+				}
+			}
+			/* Step to the next */
+			if ((unsigned char)*optdesc == 0){
+				DEBUGP("PAD0 \n");
+				ptr++;
+				hdrlen--;
+			} else {
+				ptr += LOW(ntohs(*optdesc));
+				hdrlen -= LOW(ntohs(*optdesc));
+				DEBUGP("len%04X \n", 
+					LOW(ntohs(*optdesc)));
+			}
+			if (ptr > skb->len || ( !hdrlen && 
+				(temp != optinfo->optsnr - 1))) {
+				DEBUGP("new pointer is too large! \n");
+				break;
+			}
+		}
+		if (temp == optinfo->optsnr)
+			return ret;
+		else return 0;
+	}
+
+	return 0;
+}
+
+/* Called when user tries to insert an entry of this type. */
+static int
+checkentry(const char *tablename,
+          const struct ip6t_ip6 *ip,
+          void *matchinfo,
+          unsigned int matchinfosize,
+          unsigned int hook_mask)
+{
+       const struct ip6t_opts *optsinfo = matchinfo;
+
+       if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_opts))) {
+              DEBUGP("ip6t_opts: matchsize %u != %u\n",
+                      matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_opts)));
+              return 0;
+       }
+       if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) {
+              DEBUGP("ip6t_opts: unknown flags %X\n",
+                      optsinfo->invflags);
+              return 0;
+       }
+
+       return 1;
+}
+
+static struct ip6t_match opts_match
+#if HOPBYHOP
+= { { NULL, NULL }, "hbh", &match, &checkentry, NULL, THIS_MODULE };
+#else
+= { { NULL, NULL }, "dst", &match, &checkentry, NULL, THIS_MODULE };
+#endif
+
+static int __init init(void)
+{
+       return ip6t_register_match(&opts_match);
+}
+
+static void __exit cleanup(void)
+{
+       ip6t_unregister_match(&opts_match);
+}
+
+module_init(init);
+module_exit(cleanup);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv6/netfilter/ip6t_hl.c linux-2.4.21-pre6/net/ipv6/netfilter/ip6t_hl.c
--- linux-2.4.20/net/ipv6/netfilter/ip6t_hl.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv6/netfilter/ip6t_hl.c	2003-03-26 23:48:57.000000000 +0000
@@ -0,0 +1,74 @@
+/*
+ * Hop Limit matching module
+ * Maciej Soltysiak <solt@dns.toxicfilms.tv>
+ * Based on HW's ttl module
+ *
+ * This software is distributed under the terms  GNU GPL
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+
+#include <linux/netfilter_ipv6/ip6t_hl.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+
+MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>");
+MODULE_DESCRIPTION("IP tables Hop Limit matching module");
+MODULE_LICENSE("GPL");
+
+static int match(const struct sk_buff *skb, const struct net_device *in,
+		 const struct net_device *out, const void *matchinfo,
+		 int offset, const void *hdr, u_int16_t datalen,
+		 int *hotdrop)
+{
+	const struct ip6t_hl_info *info = matchinfo;
+	const struct ipv6hdr *ip6h = skb->nh.ipv6h;
+
+	switch (info->mode) {
+		case IP6T_HL_EQ:
+			return (ip6h->hop_limit == info->hop_limit);
+			break;
+		case IP6T_HL_NE:
+			return (!(ip6h->hop_limit == info->hop_limit));
+			break;
+		case IP6T_HL_LT:
+			return (ip6h->hop_limit < info->hop_limit);
+			break;
+		case IP6T_HL_GT:
+			return (ip6h->hop_limit > info->hop_limit);
+			break;
+		default:
+			printk(KERN_WARNING "ip6t_hl: unknown mode %d\n", 
+				info->mode);
+			return 0;
+	}
+
+	return 0;
+}
+
+static int checkentry(const char *tablename, const struct ip6t_ip6 *ip,
+		      void *matchinfo, unsigned int matchsize,
+		      unsigned int hook_mask)
+{
+	if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_hl_info)))
+		return 0;
+
+	return 1;
+}
+
+static struct ip6t_match hl_match = { { NULL, NULL }, "hl", &match,
+		&checkentry, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+	return ip6t_register_match(&hl_match);
+}
+
+static void __exit fini(void)
+{
+	ip6t_unregister_match(&hl_match);
+
+}
+
+module_init(init);
+module_exit(fini);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv6/netfilter/ip6t_ipv6header.c linux-2.4.21-pre6/net/ipv6/netfilter/ip6t_ipv6header.c
--- linux-2.4.20/net/ipv6/netfilter/ip6t_ipv6header.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv6/netfilter/ip6t_ipv6header.c	2003-03-26 23:48:58.000000000 +0000
@@ -0,0 +1,222 @@
+/* ipv6header match - matches IPv6 packets based
+on whether they contain certain headers */
+
+/* Original idea: Brad Chapman 
+ * Rewritten by: Andras Kis-Szabo <kisza@sch.bme.hu> */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ipv6.h>
+#include <linux/types.h>
+#include <net/checksum.h>
+#include <net/ipv6.h>
+
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter_ipv6/ip6t_ipv6header.h>
+
+EXPORT_NO_SYMBOLS;
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("IPv6 headers match");
+MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+int ipv6_ext_hdr(u8 nexthdr)
+{
+        return ( (nexthdr == NEXTHDR_HOP)       ||
+                 (nexthdr == NEXTHDR_ROUTING)   ||
+                 (nexthdr == NEXTHDR_FRAGMENT)  ||
+                 (nexthdr == NEXTHDR_AUTH)      ||
+                 (nexthdr == NEXTHDR_ESP)       ||
+                 (nexthdr == NEXTHDR_NONE)      ||
+                 (nexthdr == NEXTHDR_DEST) );
+}
+
+static int
+ipv6header_match(const struct sk_buff *skb,
+		 const struct net_device *in,
+		 const struct net_device *out,
+		 const void *matchinfo,
+		 int offset,
+		 const void *protohdr,
+		 u_int16_t datalen,
+		 int *hotdrop)
+{
+	const struct ip6t_ipv6header_info *info = matchinfo;
+	unsigned int temp;
+	int len;
+	u8 nexthdr;
+	unsigned int ptr;
+        struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
+
+	/* Make sure this isn't an evil packet */
+	DEBUGP("ipv6_header entered \n");
+
+	/* type of the 1st exthdr */
+	nexthdr = skb->nh.ipv6h->nexthdr;
+	/* pointer to the 1st exthdr */
+	ptr = sizeof(struct ipv6hdr);
+	/* available length */
+	len = skb->len - ptr;
+	temp = 0;
+
+	DEBUGP("ipv6_header nexthdr %02X \n",nexthdr);
+	DEBUGP("ipv6_header ptr %08X \n",ptr);
+	DEBUGP("ipv6_header skblen %04X \n",skb->len);
+	DEBUGP("ipv6_header skbdatalen %04X \n",skb->data_len);
+	DEBUGP("ipv6_header len %04X \n",len);
+#if 0
+	for (temp=0;temp<skb->len;temp++){
+		if (!(temp % 16 )) DEBUGP("\nipv6_header data ");
+		DEBUGP("%02X ",skb->data[temp]);
+	}
+#endif
+	DEBUGP("\nipv6_header h.raw %02X %02X %02X %02X \n",
+			skb->h.raw[0],
+			skb->h.raw[1],
+			skb->h.raw[2],
+			skb->h.raw[3]);
+	DEBUGP("ipv6_header nh.raw %02X %02X %02X %02X \n",
+			skb->nh.raw[0],
+			skb->nh.raw[1],
+			skb->nh.raw[2],
+			skb->nh.raw[3]);
+	DEBUGP("ipv6_header CB %02X %02X %02X %02X %02X %02X %02X \n",
+			opt->iif,
+			opt->ra,
+			opt->hop,
+			opt->auth,
+			opt->dst0,
+			opt->srcrt,
+			opt->dst1);
+
+	temp = 0;
+
+        while (ipv6_ext_hdr(nexthdr)) {
+        	struct ipv6_opt_hdr *hdr;
+        	int hdrlen;
+
+		DEBUGP("ipv6_header header iteration \n");
+
+		/* Is there enough space for the next ext header? */
+                if (len < (int)sizeof(struct ipv6_opt_hdr))
+                        return 0;
+		/* No more exthdr -> evaluate */
+                if (nexthdr == NEXTHDR_NONE) {
+			temp |= MASK_NONE;
+			break;
+		}
+		/* ESP -> evaluate */
+                if (nexthdr == NEXTHDR_ESP) {
+			temp |= MASK_ESP;
+			break;
+		}
+
+		hdr=(struct ipv6_opt_hdr *)skb->data+ptr;
+
+		/* Calculate the header length */
+                if (nexthdr == NEXTHDR_FRAGMENT) {
+                        hdrlen = 8;
+                } else if (nexthdr == NEXTHDR_AUTH)
+                        hdrlen = (hdr->hdrlen+2)<<2;
+                else
+                        hdrlen = ipv6_optlen(hdr);
+
+		DEBUGP("ipv6_header hdrlen %04X \n",hdrlen);
+
+		/* set the flag */
+		switch (nexthdr){
+			case NEXTHDR_HOP:
+				temp |= MASK_HOPOPTS;
+				break;
+			case NEXTHDR_ROUTING:
+				temp |= MASK_ROUTING;
+				break;
+			case NEXTHDR_FRAGMENT:
+				temp |= MASK_FRAGMENT;
+				break;
+			case NEXTHDR_AUTH:
+				temp |= MASK_AH;
+				break;
+			case NEXTHDR_DEST:
+				temp |= MASK_DSTOPTS;
+				break;
+			default:
+				DEBUGP("IPV6HEADER match: unknown nextheader %u\n",nexthdr);
+				return 0;
+				break;
+		}
+
+                nexthdr = hdr->nexthdr;
+                len -= hdrlen;
+                ptr += hdrlen;
+		if ( ptr > skb->len ) {
+			DEBUGP("ipv6_header new ptr %04X \n",ptr);
+			break;
+		}
+        }
+
+	if ( (nexthdr != NEXTHDR_NONE ) && (nexthdr != NEXTHDR_ESP) )
+		temp |= MASK_PROTO;
+
+	DEBUGP ("ipv6header: %02X %02X \n", temp, info->matchflags);
+
+	if (info->modeflag)
+		return (!( (temp & info->matchflags)
+			^ info->matchflags) ^ info->invflags);
+	else
+		return (!( temp ^ info->matchflags) ^ info->invflags);
+}
+
+static int
+ipv6header_checkentry(const char *tablename,
+		      const struct ip6t_ip6 *ip,
+		      void *matchinfo,
+		      unsigned int matchsize,
+		      unsigned int hook_mask)
+{
+	/* Check for obvious errors */
+	/* This match is valid in all hooks! */
+	if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_ipv6header_info))) {
+		DEBUGP("ip6t_ipv6header: matchsize != %u\n",
+			 IP6T_ALIGN(sizeof(struct ip6t_ipv6header_info)));
+		return 0;
+	}
+
+	return 1;
+}
+
+static void
+ipv6header_destroy(void *matchinfo,
+		   unsigned int matchinfosize)
+{
+	return;
+}
+
+static struct ip6t_match
+ip6t_ipv6header_match = {
+	{ NULL, NULL },
+	"ipv6header",
+	&ipv6header_match,
+	&ipv6header_checkentry,
+	&ipv6header_destroy,
+	THIS_MODULE
+};
+
+static int  __init ipv6header_init(void)
+{
+	return ip6t_register_match(&ip6t_ipv6header_match);
+}
+
+static void __exit ipv6header_exit(void)
+{
+	ip6t_unregister_match(&ip6t_ipv6header_match);
+}
+
+module_init(ipv6header_init);
+module_exit(ipv6header_exit);
+
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv6/netfilter/ip6t_rt.c linux-2.4.21-pre6/net/ipv6/netfilter/ip6t_rt.c
--- linux-2.4.20/net/ipv6/netfilter/ip6t_rt.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv6/netfilter/ip6t_rt.c	2003-03-26 23:49:07.000000000 +0000
@@ -0,0 +1,305 @@
+/* Kernel module to match ROUTING parameters. */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ipv6.h>
+#include <linux/types.h>
+#include <net/checksum.h>
+#include <net/ipv6.h>
+
+#include <asm/byteorder.h>
+
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter_ipv6/ip6t_rt.h>
+
+EXPORT_NO_SYMBOLS;
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("IPv6 RT match");
+MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+int ipv6_ext_hdr(u8 nexthdr)
+{
+        return ( (nexthdr == NEXTHDR_HOP)       ||
+                 (nexthdr == NEXTHDR_ROUTING)   ||
+                 (nexthdr == NEXTHDR_FRAGMENT)  ||
+                 (nexthdr == NEXTHDR_AUTH)      ||
+                 (nexthdr == NEXTHDR_ESP)       ||
+                 (nexthdr == NEXTHDR_NONE)      ||
+                 (nexthdr == NEXTHDR_DEST) );
+}
+
+/* Returns 1 if the id is matched by the range, 0 otherwise */
+static inline int
+segsleft_match(u_int32_t min, u_int32_t max, u_int32_t id, int invert)
+{
+       int r=0;
+       DEBUGP("rt segsleft_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ',
+              min,id,max);
+       r=(id >= min && id <= max) ^ invert;
+       DEBUGP(" result %s\n",r? "PASS" : "FAILED");
+       return r;
+}
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      const void *protohdr,
+      u_int16_t datalen,
+      int *hotdrop)
+{
+       struct ipv6_rt_hdr *route = NULL;
+       const struct ip6t_rt *rtinfo = matchinfo;
+       unsigned int temp;
+       unsigned int len;
+       u8 nexthdr;
+       unsigned int ptr;
+       unsigned int hdrlen = 0;
+       unsigned int ret = 0;
+
+       /* type of the 1st exthdr */
+       nexthdr = skb->nh.ipv6h->nexthdr;
+       /* pointer to the 1st exthdr */
+       ptr = sizeof(struct ipv6hdr);
+       /* available length */
+       len = skb->len - ptr;
+       temp = 0;
+
+        while (ipv6_ext_hdr(nexthdr)) {
+               struct ipv6_opt_hdr *hdr;
+
+              DEBUGP("ipv6_rt header iteration \n");
+
+              /* Is there enough space for the next ext header? */
+                if (len < (int)sizeof(struct ipv6_opt_hdr))
+                        return 0;
+              /* No more exthdr -> evaluate */
+                if (nexthdr == NEXTHDR_NONE) {
+                     break;
+              }
+              /* ESP -> evaluate */
+                if (nexthdr == NEXTHDR_ESP) {
+                     break;
+              }
+
+              hdr=(struct ipv6_opt_hdr *)skb->data+ptr;
+
+              /* Calculate the header length */
+                if (nexthdr == NEXTHDR_FRAGMENT) {
+                        hdrlen = 8;
+                } else if (nexthdr == NEXTHDR_AUTH)
+                        hdrlen = (hdr->hdrlen+2)<<2;
+                else
+                        hdrlen = ipv6_optlen(hdr);
+
+              /* ROUTING -> evaluate */
+                if (nexthdr == NEXTHDR_ROUTING) {
+                     temp |= MASK_ROUTING;
+                     break;
+              }
+
+
+              /* set the flag */
+              switch (nexthdr){
+                     case NEXTHDR_HOP:
+                     case NEXTHDR_ROUTING:
+                     case NEXTHDR_FRAGMENT:
+                     case NEXTHDR_AUTH:
+                     case NEXTHDR_DEST:
+                            break;
+                     default:
+                            DEBUGP("ipv6_rt match: unknown nextheader %u\n",nexthdr);
+                            return 0;
+                            break;
+              }
+
+                nexthdr = hdr->nexthdr;
+                len -= hdrlen;
+                ptr += hdrlen;
+		if ( ptr > skb->len ) {
+			DEBUGP("ipv6_rt: new pointer is too large! \n");
+			break;
+		}
+        }
+
+       /* ROUTING header not found */
+       if ( temp != MASK_ROUTING ) return 0;
+
+       if (len < (int)sizeof(struct ipv6_rt_hdr)){
+	       *hotdrop = 1;
+       		return 0;
+       }
+
+       if (len < hdrlen){
+	       /* Pcket smaller than its length field */
+       		return 0;
+       }
+
+       route=skb->data+ptr;
+
+       DEBUGP("IPv6 RT LEN %u %u ", hdrlen, route->hdrlen);
+       DEBUGP("TYPE %04X ", route->type);
+       DEBUGP("SGS_LEFT %u %08X\n", ntohl(route->segments_left), ntohl(route->segments_left));
+
+       DEBUGP("IPv6 RT segsleft %02X ",
+       		(segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1],
+                           ntohl(route->segments_left),
+                           !!(rtinfo->invflags & IP6T_RT_INV_SGS))));
+       DEBUGP("type %02X %02X %02X ",
+       		rtinfo->rt_type, route->type, 
+       		(!(rtinfo->flags & IP6T_RT_TYP) ||
+                           ((rtinfo->rt_type == route->type) ^
+                           !!(rtinfo->invflags & IP6T_RT_INV_TYP))));
+       DEBUGP("len %02X %04X %02X ",
+       		rtinfo->hdrlen, hdrlen,
+       		(!(rtinfo->flags & IP6T_RT_LEN) ||
+                           ((rtinfo->hdrlen == hdrlen) ^
+                           !!(rtinfo->invflags & IP6T_RT_INV_LEN))));
+       DEBUGP("res %02X %02X %02X ", 
+       		(rtinfo->flags & IP6T_RT_RES), ((struct rt0_hdr *)route)->bitmap,
+       		!((rtinfo->flags & IP6T_RT_RES) && (((struct rt0_hdr *)route)->bitmap)));
+
+       ret = (route != NULL)
+       		&&
+       		(segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1],
+                           ntohl(route->segments_left),
+                           !!(rtinfo->invflags & IP6T_RT_INV_SGS)))
+		&&
+	      	(!(rtinfo->flags & IP6T_RT_LEN) ||
+                           ((rtinfo->hdrlen == hdrlen) ^
+                           !!(rtinfo->invflags & IP6T_RT_INV_LEN)))
+		&&
+       		(!(rtinfo->flags & IP6T_RT_TYP) ||
+                           ((rtinfo->rt_type == route->type) ^
+                           !!(rtinfo->invflags & IP6T_RT_INV_TYP)))
+		&&
+       		!((rtinfo->flags & IP6T_RT_RES) && (((struct rt0_hdr *)route)->bitmap));
+
+	DEBUGP("#%d ",rtinfo->addrnr);
+       temp = len = ptr = 0;
+       if ( !(rtinfo->flags & IP6T_RT_FST) ){
+	       return ret;
+	} else if (rtinfo->flags & IP6T_RT_FST_NSTRICT) {
+		DEBUGP("Not strict ");
+		if ( rtinfo->addrnr > (unsigned int)((hdrlen-8)/16) ){
+			DEBUGP("There isn't enough space\n");
+			return 0;
+		} else {
+			DEBUGP("#%d ",rtinfo->addrnr);
+			ptr = 0;
+			for(temp=0; temp<(unsigned int)((hdrlen-8)/16); temp++){
+				len = 0;
+				while ((u8)(((struct rt0_hdr *)route)->
+						addr[temp].s6_addr[len]) ==
+					(u8)(rtinfo->addrs[ptr].s6_addr[len])){
+					DEBUGP("%02X?%02X ",
+		(u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]),
+					(u8)(rtinfo->addrs[ptr].s6_addr[len]));
+					len++;
+					if ( len == 16 ) break;
+				}
+				if (len==16) {
+					DEBUGP("ptr=%d temp=%d;\n",ptr,temp);
+					ptr++;
+				} else {
+					DEBUGP("%02X?%02X ",
+		(u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]),
+					(u8)(rtinfo->addrs[ptr].s6_addr[len]));
+					DEBUGP("!ptr=%d temp=%d;\n",ptr,temp);
+				}
+				if (ptr==rtinfo->addrnr) break;
+			}
+			DEBUGP("ptr=%d len=%d #%d\n",ptr,len, rtinfo->addrnr);
+			if ( (len == 16) && (ptr == rtinfo->addrnr))
+				return ret;
+			else return 0;
+		}
+	} else {
+		DEBUGP("Strict ");
+		if ( rtinfo->addrnr > (unsigned int)((hdrlen-8)/16) ){
+			DEBUGP("There isn't enough space\n");
+			return 0;
+		} else {
+			DEBUGP("#%d ",rtinfo->addrnr);
+			for(temp=0; temp<rtinfo->addrnr; temp++){
+				len = 0;
+				while ((u8)(((struct rt0_hdr *)route)->
+						addr[temp].s6_addr[len]) ==
+					(u8)(rtinfo->addrs[temp].s6_addr[len])){
+					DEBUGP("%02X?%02X ",
+		(u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]),
+					(u8)(rtinfo->addrs[temp].s6_addr[len]));
+					len++;
+					if ( len == 16 ) break;
+				}
+				if (len!=16) {
+					DEBUGP("%02X?%02X ",
+		(u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]),
+					(u8)(rtinfo->addrs[temp].s6_addr[len]));
+					DEBUGP("!len=%d temp=%d;\n",len,temp);
+					break;
+				}
+			}
+			DEBUGP("temp=%d len=%d #%d\n",temp,len,rtinfo->addrnr);
+			if ( (len == 16) && (temp == rtinfo->addrnr) && (temp == (unsigned int)((hdrlen-8)/16)))
+				return ret;
+			else return 0;
+		}
+	}
+
+	return 0;
+}
+
+/* Called when user tries to insert an entry of this type. */
+static int
+checkentry(const char *tablename,
+          const struct ip6t_ip6 *ip,
+          void *matchinfo,
+          unsigned int matchinfosize,
+          unsigned int hook_mask)
+{
+       const struct ip6t_rt *rtinfo = matchinfo;
+
+       if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_rt))) {
+              DEBUGP("ip6t_rt: matchsize %u != %u\n",
+                      matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_rt)));
+              return 0;
+       }
+       if (rtinfo->invflags & ~IP6T_RT_INV_MASK) {
+              DEBUGP("ip6t_rt: unknown flags %X\n",
+                      rtinfo->invflags);
+              return 0;
+       }
+       if ( (rtinfo->flags & (IP6T_RT_RES|IP6T_RT_FST_MASK)) && 
+		       (!(rtinfo->flags & IP6T_RT_TYP) || 
+		       (rtinfo->rt_type != 0) || 
+		       (rtinfo->invflags & IP6T_RT_INV_TYP)) ) {
+	      DEBUGP("`--rt-type 0' required before `--rt-0-*'");
+              return 0;
+       }
+
+       return 1;
+}
+
+static struct ip6t_match rt_match
+= { { NULL, NULL }, "rt", &match, &checkentry, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+       return ip6t_register_match(&rt_match);
+}
+
+static void __exit cleanup(void)
+{
+       ip6t_unregister_match(&rt_match);
+}
+
+module_init(init);
+module_exit(cleanup);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv6/netfilter/ip6table_mangle.c linux-2.4.21-pre6/net/ipv6/netfilter/ip6table_mangle.c
--- linux-2.4.20/net/ipv6/netfilter/ip6table_mangle.c	2002-02-25 19:38:14.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv6/netfilter/ip6table_mangle.c	2003-03-26 23:49:30.000000000 +0000
@@ -157,7 +157,7 @@
 	hop_limit = (*pskb)->nh.ipv6h->hop_limit;
 
 	/* flowlabel and prio (includes version, which shouldn't change either */
-	flowlabel = (u_int32_t) (*pskb)->nh.ipv6h;
+	flowlabel = *((u_int32_t *) (*pskb)->nh.ipv6h);
 
 	ret = ip6t_do_table(pskb, hook, in, out, &packet_mangler, NULL);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv6/reassembly.c linux-2.4.21-pre6/net/ipv6/reassembly.c
--- linux-2.4.20/net/ipv6/reassembly.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv6/reassembly.c	2003-03-26 23:49:25.000000000 +0000
@@ -22,6 +22,7 @@
  *
  *      Horst von Brand Add missing #include <linux/string.h>
  *	Alexey Kuznetsov	SMP races, threading, cleanup.
+ *	Patrick McHardy		LRU queue of frag heads for evictor.
  */
 #include <linux/config.h>
 #include <linux/errno.h>
@@ -30,6 +31,7 @@
 #include <linux/socket.h>
 #include <linux/sockios.h>
 #include <linux/sched.h>
+#include <linux/list.h>
 #include <linux/net.h>
 #include <linux/netdevice.h>
 #include <linux/in6.h>
@@ -67,6 +69,7 @@
 struct frag_queue
 {
 	struct frag_queue	*next;
+	struct list_head lru_list;		/* lru list member	*/
 
 	__u32			id;		/* fragment id		*/
 	struct in6_addr		saddr;
@@ -95,6 +98,7 @@
 
 static struct frag_queue *ip6_frag_hash[IP6Q_HASHSZ];
 static rwlock_t ip6_frag_lock = RW_LOCK_UNLOCKED;
+static LIST_HEAD(ip6_frag_lru_list);
 int ip6_frag_nqueues = 0;
 
 static __inline__ void __fq_unlink(struct frag_queue *fq)
@@ -102,6 +106,7 @@
 	if(fq->next)
 		fq->next->pprev = fq->pprev;
 	*fq->pprev = fq->next;
+	list_del(&fq->lru_list);
 	ip6_frag_nqueues--;
 }
 
@@ -193,38 +198,30 @@
 
 static void ip6_evictor(void)
 {
-	int i, progress;
+	struct frag_queue *fq;
+	struct list_head *tmp;
 
-	do {
+	for(;;) {
 		if (atomic_read(&ip6_frag_mem) <= sysctl_ip6frag_low_thresh)
 			return;
-		progress = 0;
-		for (i = 0; i < IP6Q_HASHSZ; i++) {
-			struct frag_queue *fq;
-			if (ip6_frag_hash[i] == NULL)
-				continue;
-
-			read_lock(&ip6_frag_lock);
-			if ((fq = ip6_frag_hash[i]) != NULL) {
-				/* find the oldest queue for this hash bucket */
-				while (fq->next)
-					fq = fq->next;
-				atomic_inc(&fq->refcnt);
-				read_unlock(&ip6_frag_lock);
-
-				spin_lock(&fq->lock);
-				if (!(fq->last_in&COMPLETE))
-					fq_kill(fq);
-				spin_unlock(&fq->lock);
-
-				fq_put(fq);
-				IP6_INC_STATS_BH(Ip6ReasmFails);
-				progress = 1;
-				continue;
-			}
+		read_lock(&ip6_frag_lock);
+		if (list_empty(&ip6_frag_lru_list)) {
 			read_unlock(&ip6_frag_lock);
+			return;
 		}
-	} while (progress);
+		tmp = ip6_frag_lru_list.next;
+		fq = list_entry(tmp, struct frag_queue, lru_list);
+		atomic_inc(&fq->refcnt);
+		read_unlock(&ip6_frag_lock);
+
+		spin_lock(&fq->lock);
+		if (!(fq->last_in&COMPLETE))
+			fq_kill(fq);
+		spin_unlock(&fq->lock);
+
+		fq_put(fq);
+		IP6_INC_STATS_BH(Ip6ReasmFails);
+	}
 }
 
 static void ip6_frag_expire(unsigned long data)
@@ -294,6 +291,8 @@
 		fq->next->pprev = &fq->next;
 	ip6_frag_hash[hash] = fq;
 	fq->pprev = &ip6_frag_hash[hash];
+	INIT_LIST_HEAD(&fq->lru_list);
+	list_add_tail(&fq->lru_list, &ip6_frag_lru_list);
 	ip6_frag_nqueues++;
 	write_unlock(&ip6_frag_lock);
 	return fq;
@@ -501,6 +500,9 @@
 		fq->nhoffset = nhoff;
 		fq->last_in |= FIRST_IN;
 	}
+	write_lock(&ip6_frag_lock);
+	list_move_tail(&fq->lru_list, &ip6_frag_lru_list);
+	write_unlock(&ip6_frag_lock);
 	return;
 
 err:
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv6/route.c linux-2.4.21-pre6/net/ipv6/route.c
--- linux-2.4.20/net/ipv6/route.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv6/route.c	2003-03-26 23:49:16.000000000 +0000
@@ -605,15 +605,17 @@
    Remove it only when all the things will work!
  */
 
-static void ipv6_wash_prefix(struct in6_addr *pfx, int plen)
+static void ipv6_addr_prefix(struct in6_addr *pfx,
+			     const struct in6_addr *addr, int plen)
 {
 	int b = plen&0x7;
-	int o = (plen + 7)>>3;
+	int o = plen>>3;
 
+	memcpy(pfx->s6_addr, addr, o);
 	if (o < 16)
 		memset(pfx->s6_addr + o, 0, 16 - o);
 	if (b != 0)
-		pfx->s6_addr[plen>>3] &= (0xFF<<(8-b));
+		pfx->s6_addr[o] = addr->s6_addr[o]&(0xff00 >> b);
 }
 
 static int ipv6_get_mtu(struct net_device *dev)
@@ -686,16 +688,16 @@
 			goto out;
 	}
 
-	ipv6_addr_copy(&rt->rt6i_dst.addr, &rtmsg->rtmsg_dst);
+	ipv6_addr_prefix(&rt->rt6i_dst.addr, 
+			 &rtmsg->rtmsg_dst, rtmsg->rtmsg_dst_len);
 	rt->rt6i_dst.plen = rtmsg->rtmsg_dst_len;
 	if (rt->rt6i_dst.plen == 128)
 	       rt->u.dst.flags = DST_HOST;
-	ipv6_wash_prefix(&rt->rt6i_dst.addr, rt->rt6i_dst.plen);
 
 #ifdef CONFIG_IPV6_SUBTREES
-	ipv6_addr_copy(&rt->rt6i_src.addr, &rtmsg->rtmsg_src);
+	ipv6_addr_prefix(&rt->rt6i_src.addr, 
+			 &rtmsg->rtmsg_src, rtmsg->rtmsg_src_len);
 	rt->rt6i_src.plen = rtmsg->rtmsg_src_len;
-	ipv6_wash_prefix(&rt->rt6i_src.addr, rt->rt6i_src.plen);
 #endif
 
 	rt->rt6i_metric = rtmsg->rtmsg_metric;
@@ -1397,6 +1399,9 @@
 	   caused by addrconf/ndisc.
 	*/
 	idev = __in6_dev_get(arg->dev);
+	if (idev == NULL)
+		return 0;
+
 	/* For administrative MTU increase, there is no way to discover 
 	   IPv6 PMTU increase, so PMTU increase should be updated here.
 	   Since RFC 1981 doesn't include administrative MTU increase
@@ -1689,14 +1694,14 @@
 {
 	struct rtattr **rta = arg;
 	int iif = 0;
-	int err;
+	int err = -ENOBUFS;
 	struct sk_buff *skb;
 	struct flowi fl;
 	struct rt6_info *rt;
 
 	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
 	if (skb == NULL)
-		return -ENOBUFS;
+		goto out;
 
 	/* Reserve room for dummy headers, this skb can pass
 	   through good chunk of routing engine.
@@ -1720,8 +1725,10 @@
 	if (iif) {
 		struct net_device *dev;
 		dev = __dev_get_by_index(iif);
-		if (!dev)
-			return -ENODEV;
+		if (!dev) {
+			err = -ENODEV;
+			goto out_free;
+		}
 	}
 
 	fl.oif = 0;
@@ -1738,13 +1745,19 @@
 			    fl.nl_u.ip6_u.saddr,
 			    iif,
 			    RTM_NEWROUTE, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq);
-	if (err < 0)
-		return -EMSGSIZE;
+	if (err < 0) {
+		err = -EMSGSIZE;
+		goto out_free;
+	}
 
 	err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT);
-	if (err < 0)
-		return err;
-	return 0;
+	if (err > 0)
+		err = 0;
+out:
+	return err;
+out_free:
+	kfree_skb(skb);
+	goto out;	
 }
 
 void inet6_rt_notify(int event, struct rt6_info *rt)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv6/sit.c linux-2.4.21-pre6/net/ipv6/sit.c
--- linux-2.4.20/net/ipv6/sit.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv6/sit.c	2003-03-26 23:49:54.000000000 +0000
@@ -18,7 +18,6 @@
  * Nate Thompson <nate@thebog.net>:		6to4 support
  */
 
-#define __NO_VERSION__
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/errno.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv6/sysctl_net_ipv6.c linux-2.4.21-pre6/net/ipv6/sysctl_net_ipv6.c
--- linux-2.4.20/net/ipv6/sysctl_net_ipv6.c	1998-03-01 22:40:42.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv6/sysctl_net_ipv6.c	2003-03-26 23:49:03.000000000 +0000
@@ -1,5 +1,8 @@
 /*
  * sysctl_net_ipv6.c: sysctl interface to net IPV6 subsystem.
+ *
+ * Changes:
+ * YOSHIFUJI Hideaki @USAGI:	added icmp sysctl table.
  */
 
 #include <linux/mm.h>
@@ -12,11 +15,15 @@
 #include <net/addrconf.h>
 
 extern ctl_table ipv6_route_table[];
+extern ctl_table ipv6_icmp_table[];
 
 #ifdef CONFIG_SYSCTL
 
 ctl_table ipv6_table[] = {
 	{NET_IPV6_ROUTE, "route", NULL, 0, 0555, ipv6_route_table},
+	{NET_IPV6_ICMP, "icmp", NULL, 0, 0500, ipv6_icmp_table},
+	{NET_IPV6_BINDV6ONLY, "bindv6only",
+	 &sysctl_ipv6_bindv6only, sizeof(int), 0644, NULL, &proc_dointvec},
 	{0}
 };
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv6/tcp_ipv6.c linux-2.4.21-pre6/net/ipv6/tcp_ipv6.c
--- linux-2.4.20/net/ipv6/tcp_ipv6.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv6/tcp_ipv6.c	2003-03-26 23:48:58.000000000 +0000
@@ -14,6 +14,9 @@
  *
  *	Fixes:
  *	Hideaki YOSHIFUJI	:	sin6_scope_id support
+ *	YOSHIFUJI Hideaki @USAGI and:	Support IPV6_V6ONLY socket option, which
+ *	Alexey Kuznetsov		allow both IPv4 and IPv6 sockets to bind
+ *					a single port at the same time.
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -21,7 +24,6 @@
  *      2 of the License, or (at your option) any later version.
  */
 
-#define __NO_VERSION__
 #include <linux/module.h>
 #include <linux/config.h>
 #include <linux/errno.h>
@@ -148,14 +150,23 @@
 					    !sk2->reuse	||
 					    sk2->state == TCP_LISTEN) {
 						/* NOTE: IPv6 tw bucket have different format */
-						if (!sk2->rcv_saddr	||
-						    addr_type == IPV6_ADDR_ANY ||
-						    !ipv6_addr_cmp(&sk->net_pinfo.af_inet6.rcv_saddr,
-								   sk2->state != TCP_TIME_WAIT ?
-								   &sk2->net_pinfo.af_inet6.rcv_saddr :
-								   &((struct tcp_tw_bucket*)sk)->v6_rcv_saddr) ||
-						    (addr_type==IPV6_ADDR_MAPPED && sk2->family==AF_INET &&
-						     sk->rcv_saddr==sk2->rcv_saddr))
+						if ((!sk2->rcv_saddr && !ipv6_only_sock(sk)) ||
+						    (sk2->family == AF_INET6 &&
+						     ipv6_addr_any(&sk2->net_pinfo.af_inet6.rcv_saddr) &&
+						     !(ipv6_only_sock(sk2) && addr_type == IPV6_ADDR_MAPPED)) ||
+						    (addr_type == IPV6_ADDR_ANY &&
+						     (!ipv6_only_sock(sk) ||
+						      !(sk2->family == AF_INET6 ? ipv6_addr_type(&sk2->net_pinfo.af_inet6.rcv_saddr) == IPV6_ADDR_MAPPED : 1))) ||
+						    (sk2->family == AF_INET6 &&
+						     !ipv6_addr_cmp(&sk->net_pinfo.af_inet6.rcv_saddr,
+								    sk2->state != TCP_TIME_WAIT ?
+								    &sk2->net_pinfo.af_inet6.rcv_saddr :
+								    &((struct tcp_tw_bucket*)sk)->v6_rcv_saddr)) ||
+						    (addr_type == IPV6_ADDR_MAPPED && 
+						     !ipv6_only_sock(sk2) &&
+						     (!sk2->rcv_saddr ||
+						      !sk->rcv_saddr ||
+						      sk->rcv_saddr == sk2->rcv_saddr)))
 							break;
 					}
 				}
@@ -602,6 +613,9 @@
 
 		SOCK_DEBUG(sk, "connect: ipv4 mapped\n");
 
+		if (__ipv6_only_sock(sk))
+			return -ENETUNREACH;
+
 		sin.sin_family = AF_INET;
 		sin.sin_port = usin->sin6_port;
 		sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3];
@@ -1412,9 +1426,6 @@
  */
 static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
 {
-#ifdef CONFIG_FILTER
-	struct sk_filter *filter;
-#endif
 	struct sk_buff *opt_skb = NULL;
 
 	/* Imagine: socket is IPv6. IPv4 packet arrives,
@@ -1428,12 +1439,6 @@
 	if (skb->protocol == htons(ETH_P_IP))
 		return tcp_v4_do_rcv(sk, skb);
 
-#ifdef CONFIG_FILTER
-	filter = sk->filter;
-	if (filter && sk_filter(skb, filter))
-		goto discard;
-#endif /* CONFIG_FILTER */
-
 	/*
 	 *	socket locking is here for SMP purposes as backlog rcv
 	 *	is currently called with bh processing disabled.
@@ -1586,6 +1591,9 @@
 	if(sk->state == TCP_TIME_WAIT)
 		goto do_time_wait;
 
+	if (sk_filter(sk, skb, 0))
+		goto discard_and_relse;
+		
 	skb->dev = NULL;
 
 	bh_lock_sock(sk);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/ipv6/udp.c linux-2.4.21-pre6/net/ipv6/udp.c
--- linux-2.4.20/net/ipv6/udp.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.21-pre6/net/ipv6/udp.c	2003-03-26 23:49:20.000000000 +0000
@@ -11,6 +11,9 @@
  *
  *	Fixes:
  *	Hideaki YOSHIFUJI	:	sin6_scope_id support
+ *	YOSHIFUJI Hideaki @USAGI and:	Support IPV6_V6ONLY socket option, which
+ *	Alexey Kuznetsov		allow both IPv4 and IPv6 sockets to bind
+ *					a single port at the same time.
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -106,13 +109,21 @@
 			if (sk2->num == snum &&
 			    sk2 != sk &&
 			    sk2->bound_dev_if == sk->bound_dev_if &&
-			    (!sk2->rcv_saddr ||
-			     addr_type == IPV6_ADDR_ANY ||
-			     !ipv6_addr_cmp(&sk->net_pinfo.af_inet6.rcv_saddr,
-					    &sk2->net_pinfo.af_inet6.rcv_saddr) ||
+			    ((!sk2->rcv_saddr && !ipv6_only_sock(sk)) ||
+			     (sk2->family == AF_INET6 && 
+			      ipv6_addr_any(&sk2->net_pinfo.af_inet6.rcv_saddr) &&
+			      !(ipv6_only_sock(sk2) && addr_type == IPV6_ADDR_MAPPED)) ||
+			     (addr_type == IPV6_ADDR_ANY && 
+			      (!ipv6_only_sock(sk) || 
+			       !(sk2->family == AF_INET6 ? (ipv6_addr_type(&sk2->net_pinfo.af_inet6.rcv_saddr) == IPV6_ADDR_MAPPED) : 1))) ||
+			     (sk2->family == AF_INET6 && 
+			      !ipv6_addr_cmp(&sk->net_pinfo.af_inet6.rcv_saddr,
+					     &sk2->net_pinfo.af_inet6.rcv_saddr)) ||
 			     (addr_type == IPV6_ADDR_MAPPED &&
-			      sk2->family == AF_INET &&
-			      sk->rcv_saddr == sk2->rcv_saddr)) &&
+			      !ipv6_only_sock(sk2) &&
+			      (!sk2->rcv_saddr || 
+			       !sk->rcv_saddr ||
+			       sk->rcv_saddr == sk2->rcv_saddr))) &&
 			    (!sk2->reuse || !sk->reuse))
 				goto fail;
 		}
@@ -221,6 +232,8 @@
 	int			err;
 
 	if (usin->sin6_family == AF_INET) {
+		if (__ipv6_only_sock(sk))
+			return -EAFNOSUPPORT;
 		err = udp_connect(sk, uaddr, addr_len);
 		goto ipv4_connected;
 	}
@@ -256,6 +269,9 @@
 	if (addr_type == IPV6_ADDR_MAPPED) {
 		struct sockaddr_in sin;
 
+		if (__ipv6_only_sock(sk))
+			return -ENETUNREACH;
+
 		sin.sin_family = AF_INET;
 		sin.sin_addr.s_addr = daddr->s6_addr32[3];
 		sin.sin_port = usin->sin6_port;
@@ -783,8 +799,11 @@
 	fl.oif = 0;
 
 	if (sin6) {
-		if (sin6->sin6_family == AF_INET)
+		if (sin6->sin6_family == AF_INET) {
+			if (__ipv6_only_sock(sk))
+				return -ENETUNREACH;
 			return udp_sendmsg(sk, msg, ulen);
+		}
 
 		if (addr_len < SIN6_LEN_RFC2133)
 			return -EINVAL;
@@ -831,6 +850,9 @@
 	if (addr_type == IPV6_ADDR_MAPPED) {
 		struct sockaddr_in sin;
 
+		if (__ipv6_only_sock(sk))
+			return -ENETUNREACH;
+
 		sin.sin_family = AF_INET;
 		sin.sin_addr.s_addr = daddr->s6_addr32[3];
 		sin.sin_port = udh.uh.dest;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/irda/ircomm/ircomm_core.c linux-2.4.21-pre6/net/irda/ircomm/ircomm_core.c
--- linux-2.4.20/net/irda/ircomm/ircomm_core.c	2002-02-25 19:38:14.000000000 +0000
+++ linux-2.4.21-pre6/net/irda/ircomm/ircomm_core.c	2003-03-26 23:48:57.000000000 +0000
@@ -498,7 +498,7 @@
 
 	self = (struct ircomm_cb *) hashbin_get_first(ircomm);
 	while (self != NULL) {
-		ASSERT(self->magic == IRCOMM_MAGIC, return len;);
+		ASSERT(self->magic == IRCOMM_MAGIC, break;);
 
 		if(self->line < 0x10)
 			len += sprintf(buf+len, "ircomm%d", self->line);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/irda/ircomm/ircomm_tty.c linux-2.4.21-pre6/net/irda/ircomm/ircomm_tty.c
--- linux-2.4.20/net/irda/ircomm/ircomm_tty.c	2002-11-28 23:53:16.000000000 +0000
+++ linux-2.4.21-pre6/net/irda/ircomm/ircomm_tty.c	2003-03-26 23:49:25.000000000 +0000
@@ -512,6 +512,9 @@
 	if (!tty)
 		return;
 
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+
 	save_flags(flags); 
 	cli();
 
@@ -523,9 +526,6 @@
 		return;
 	}
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
-
 	if ((tty->count == 1) && (self->open_count != 1)) {
 		/*
 		 * Uh, oh.  tty->count is 1, which means that the tty
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/irda/irda_device.c linux-2.4.21-pre6/net/irda/irda_device.c
--- linux-2.4.20/net/irda/irda_device.c	2002-02-25 19:38:14.000000000 +0000
+++ linux-2.4.21-pre6/net/irda/irda_device.c	2003-03-26 23:49:35.000000000 +0000
@@ -369,6 +369,12 @@
  *    time to complete. We do it this hairy way since we may have been
  *    called from interrupt context, so it's not possible to use
  *    schedule_timeout() 
+ * Two important notes :
+ *	o Make sure you irda_task_delete(task); in case you delete the
+ *	  calling instance.
+ *	o No real need to lock when calling this function, but you may
+ *	  want to lock within the task handler.
+ * Jean II
  */
 struct irda_task *irda_task_execute(void *instance, 
 				    IRDA_TASK_CALLBACK function, 
@@ -467,6 +473,9 @@
  * Function irda_device_init_dongle (self, type, qos)
  *
  *    Initialize attached dongle.
+ *
+ * Important : request_module require us to call this function with
+ * a process context and irq enabled. - Jean II
  */
 dongle_t *irda_device_dongle_init(struct net_device *dev, int type)
 {
@@ -478,6 +487,7 @@
 #ifdef CONFIG_KMOD
 	{
 	char modname[32];
+	ASSERT(!in_interrupt(), return NULL;);
 	/* Try to load the module needed */
 	sprintf(modname, "irda-dongle-%d", type);
 	request_module(modname);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/irda/irlap.c linux-2.4.21-pre6/net/irda/irlap.c
--- linux-2.4.20/net/irda/irlap.c	2002-11-28 23:53:16.000000000 +0000
+++ linux-2.4.21-pre6/net/irda/irlap.c	2003-03-26 23:49:29.000000000 +0000
@@ -1101,8 +1101,8 @@
 
 	self = (struct irlap_cb *) hashbin_get_first(irlap);
 	while (self != NULL) {
-		ASSERT(self != NULL, return -ENODEV;);
-		ASSERT(self->magic == LAP_MAGIC, return -EBADR;);
+		ASSERT(self != NULL, break;);
+		ASSERT(self->magic == LAP_MAGIC, break;);
 
 		len += sprintf(buf+len, "irlap%d ", i++);
 		len += sprintf(buf+len, "state: %s\n", 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/irda/irlap_event.c linux-2.4.21-pre6/net/irda/irlap_event.c
--- linux-2.4.20/net/irda/irlap_event.c	2002-11-28 23:53:16.000000000 +0000
+++ linux-2.4.21-pre6/net/irda/irlap_event.c	2003-03-26 23:49:40.000000000 +0000
@@ -253,19 +253,45 @@
 	case LAP_XMIT_P: /* FALLTHROUGH */
 	case LAP_XMIT_S:
 		/* 
+		 * We just received the pf bit and are at the beginning
+		 * of a new LAP transmit window.
 		 * Check if there are any queued data frames, and do not
 		 * try to disconnect link if we send any data frames, since
 		 * that will change the state away form XMIT
 		 */
+		IRDA_DEBUG(2, __FUNCTION__ "() : queue len = %d\n",
+			   skb_queue_len(&self->txq));
+
 		if (skb_queue_len(&self->txq)) {
 			/* Prevent race conditions with irlap_data_request() */
 			self->local_busy = TRUE;
 
+			/* Theory of operation.
+			 * We send frames up to when we fill the window or
+			 * reach line capacity. Those frames will queue up
+			 * in the device queue, and the driver will slowly
+			 * send them.
+			 * After each frame that we send, we poll the higher
+			 * layer for more data. It's the right time to do
+			 * that because the link layer need to perform the mtt
+			 * and then send the first frame, so we can afford
+			 * to send a bit of time in kernel space.
+			 * The explicit flow indication allow to minimise
+			 * buffers (== lower latency), to avoid higher layer
+			 * polling via timers (== less context switches) and
+			 * to implement a crude scheduler - Jean II */
+
 			/* Try to send away all queued data frames */
 			while ((skb = skb_dequeue(&self->txq)) != NULL) {
+				/* Send one frame */
 				ret = (*state[self->state])(self, SEND_I_CMD,
 							    skb, NULL);
 				kfree_skb(skb);
+
+				/* Poll the higher layers for one more frame */
+				irlmp_flow_indication(self->notify.instance,
+						      FLOW_START);
+
 				if (ret == -EPROTO)
 					break; /* Try again later! */
 			}
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/irda/irlmp.c linux-2.4.21-pre6/net/irda/irlmp.c
--- linux-2.4.20/net/irda/irlmp.c	2002-11-28 23:53:16.000000000 +0000
+++ linux-2.4.21-pre6/net/irda/irlmp.c	2003-03-26 23:49:54.000000000 +0000
@@ -236,6 +236,16 @@
 	lap = self->lap;
 	if (lap) {
 		ASSERT(lap->magic == LMP_LAP_MAGIC, return;);
+		/* We might close a LSAP before it has completed the
+		 * connection setup. In those case, higher layers won't
+		 * send a proper disconnect request. Harmless, except
+		 * that we will forget to close LAP... - Jean II */
+		if(self->lsap_state != LSAP_DISCONNECTED) {
+			self->lsap_state = LSAP_DISCONNECTED;
+			irlmp_do_lap_event(self->lap,
+					   LM_LAP_DISCONNECT_REQUEST, NULL);
+		}
+		/* Now, remove from the link */
 		lsap = hashbin_remove(lap->lsaps, (int) self, NULL);
 	}
 	self->lap = NULL;
@@ -1210,6 +1220,72 @@
 }
 
 /*
+ * Receive flow control indication from LAP.
+ * LAP want us to send it one more frame. We implement a simple round
+ * robin scheduler between the active sockets so that we get a bit of
+ * fairness. Note that the round robin is far from perfect, but it's
+ * better than nothing.
+ * We then poll the selected socket so that we can do synchronous
+ * refilling of IrLAP (which allow to minimise the number of buffers).
+ * Jean II
+ */
+void irlmp_flow_indication(struct lap_cb *self, LOCAL_FLOW flow)
+{
+	struct lsap_cb *next;
+	struct lsap_cb *curr;
+	int	lsap_todo;
+
+	ASSERT(self->magic == LMP_LAP_MAGIC, return;);
+	ASSERT(flow == FLOW_START, return;);
+
+	/* Get the number of lsap. That's the only safe way to know
+	 * that we have looped around... - Jean II */
+	lsap_todo = HASHBIN_GET_SIZE(self->lsaps);
+	IRDA_DEBUG(4, __FUNCTION__ "() : %d lsaps to scan\n", lsap_todo);
+
+	/* Poll lsap in order until the queue is full or until we
+	 * tried them all.
+	 * Most often, the current LSAP will have something to send,
+	 * so we will go through this loop only once. - Jean II */
+	while((lsap_todo--) &&
+	      (IRLAP_GET_TX_QUEUE_LEN(self->irlap) < LAP_HIGH_THRESHOLD)) {
+		/* Try to find the next lsap we should poll. */
+		next = self->flow_next;
+		if(next != NULL) {
+			/* Note that if there is only one LSAP on the LAP
+			 * (most common case), self->flow_next is always NULL,
+			 * so we always avoid this loop. - Jean II */
+			IRDA_DEBUG(4, __FUNCTION__ "() : searching my LSAP\n");
+
+			/* We look again in hashbins, because the lsap
+			 * might have gone away... - Jean II */
+			curr = (struct lsap_cb *) hashbin_get_first(self->lsaps);
+			while((curr != NULL ) && (curr != next))
+				curr = (struct lsap_cb *) hashbin_get_next(self->lsaps);
+		} else
+			curr = NULL;
+
+		/* If we have no lsap, restart from first one */
+		if(curr == NULL)
+			curr = (struct lsap_cb *) hashbin_get_first(self->lsaps);
+		/* Uh-oh... Paranoia */
+		if(curr == NULL)
+			break;
+
+		/* Next time, we will get the next one (or the first one) */
+		self->flow_next = (struct lsap_cb *) hashbin_get_next(self->lsaps);
+		IRDA_DEBUG(4, __FUNCTION__ "() : curr is %p, next was %p and is now %p, still %d to go - queue len = %d\n", curr, next, self->flow_next, lsap_todo, IRLAP_GET_TX_QUEUE_LEN(self->irlap));
+
+		/* Inform lsap user that it can send one more packet. */
+		if (curr->notify.flow_indication != NULL)
+			curr->notify.flow_indication(curr->notify.instance, 
+						     curr, flow);
+		else
+			IRDA_DEBUG(1, __FUNCTION__ "(), no handler\n");
+	}
+}
+
+/*
  * Function irlmp_hint_to_service (hint)
  *
  *    Returns a list of all servics contained in the given hint bits. This
@@ -1674,7 +1750,7 @@
 	len += sprintf( buf+len, "Unconnected LSAPs:\n");
 	self = (struct lsap_cb *) hashbin_get_first( irlmp->unconnected_lsaps);
 	while (self != NULL) {
-		ASSERT(self->magic == LMP_LSAP_MAGIC, return 0;);
+		ASSERT(self->magic == LMP_LSAP_MAGIC, break;);
 		len += sprintf(buf+len, "lsap state: %s, ", 
 			       irlsap_state[ self->lsap_state]);
 		len += sprintf(buf+len, 
@@ -1703,7 +1779,7 @@
 		len += sprintf(buf+len, "\n  Connected LSAPs:\n");
 		self = (struct lsap_cb *) hashbin_get_first(lap->lsaps);
 		while (self != NULL) {
-			ASSERT(self->magic == LMP_LSAP_MAGIC, return 0;);
+			ASSERT(self->magic == LMP_LSAP_MAGIC, break;);
 			len += sprintf(buf+len, "  lsap state: %s, ", 
 				       irlsap_state[ self->lsap_state]);
 			len += sprintf(buf+len, 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/irda/irlmp_event.c linux-2.4.21-pre6/net/irda/irlmp_event.c
--- linux-2.4.20/net/irda/irlmp_event.c	2002-11-28 23:53:16.000000000 +0000
+++ linux-2.4.21-pre6/net/irda/irlmp_event.c	2003-03-26 23:49:18.000000000 +0000
@@ -414,7 +414,7 @@
 
 			/* 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,
+			 * the LAP, not the state we wish 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
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/irda/irnet/irnet.h linux-2.4.21-pre6/net/irda/irnet/irnet.h
--- linux-2.4.20/net/irda/irnet/irnet.h	2002-11-28 23:53:16.000000000 +0000
+++ linux-2.4.21-pre6/net/irda/irnet/irnet.h	2003-03-26 23:49:50.000000000 +0000
@@ -217,6 +217,11 @@
  *	  Better fix in irnet_disconnect_indication() :
  *	  - if connected, kill pppd via hangup.
  *	  - if not connected, reenable ppp Tx, which trigger IrNET retry.
+ *
+ * v12 - 10.4.02 - Jean II
+ *	o Fix race condition in irnet_connect_indication().
+ *	  If the socket was already trying to connect, drop old connection
+ *	  and use new one only if acting as primary. See comments.
  */
 
 /***************************** INCLUDES *****************************/
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/irda/irnet/irnet_irda.c linux-2.4.21-pre6/net/irda/irnet/irnet_irda.c
--- linux-2.4.20/net/irda/irnet/irnet_irda.c	2002-11-28 23:53:16.000000000 +0000
+++ linux-2.4.21-pre6/net/irda/irnet/irnet_irda.c	2003-03-26 23:48:59.000000000 +0000
@@ -1340,46 +1340,80 @@
       return;
     }
 
-  /* Socket connecting ?
-   * Clear up flag : prevent irnet_disconnect_indication() to mess up tsap */
-  if(test_and_clear_bit(0, &new->ttp_connect))
-    {
-      /* The socket is trying to connect to the other end and may have sent
-       * a IrTTP connection request and is waiting for a connection response
-       * (that may never come).
-       * Now, the pain is that the socket may have opened a tsap and is
-       * waiting on it, while the other end is trying to connect to it on
-       * another tsap.
-       */
-      DERROR(IRDA_CB_ERROR, "Socket already connecting. Ouch !\n");
+  /* The following code is a bit tricky, so need comments ;-)
+   */
+  /* If ttp_connect is set, the socket is trying to connect to the other
+   * end and may have sent a IrTTP connection request and is waiting for
+   * a connection response (that may never come).
+   * Now, the pain is that the socket may have opened a tsap and is
+   * waiting on it, while the other end is trying to connect to it on
+   * another tsap.
+   * Because IrNET can be peer to peer, we need to workaround this.
+   * Furthermore, the way the irnetd script is implemented, the
+   * target will create a second IrNET connection back to the
+   * originator and expect the originator to bind this new connection
+   * to the original PPPD instance.
+   * And of course, if we don't use irnetd, we can have a race when
+   * both side try to connect simultaneously, which could leave both
+   * connections half closed (yuck).
+   * Conclusions :
+   *	1) The "originator" must accept the new connection and get rid
+   *	   of the old one so that irnetd works
+   *	2) One side must deny the new connection to avoid races,
+   *	   but both side must agree on which side it is...
+   * Most often, the originator is primary at the LAP layer.
+   * Jean II
+   */
+  /* Now, let's look at the way I wrote the test...
+   * We need to clear up the ttp_connect flag atomically to prevent
+   * irnet_disconnect_indication() to mess up the tsap we are going to close.
+   * We want to clear the ttp_connect flag only if we close the tsap,
+   * otherwise we will never close it, so we need to check for primary
+   * *before* doing the test on the flag.
+   * And of course, ALLOW_SIMULT_CONNECT can disable this entirely...
+   * Jean II
+   */
+
+  /* Socket already connecting ? On primary ? */
+  if(0
 #ifdef ALLOW_SIMULT_CONNECT
-      /* Cleanup the TSAP if necessary - IrIAP will be cleaned up later */
+     || ((irttp_is_primary(server->tsap) == 1)	/* primary */
+	 && (test_and_clear_bit(0, &new->ttp_connect)))
+#endif /* ALLOW_SIMULT_CONNECT */
+     )
+    {
+      DERROR(IRDA_CB_ERROR, "Socket already connecting, but going to reuse it !\n");
+
+      /* Cleanup the old TSAP if necessary - IrIAP will be cleaned up later */
       if(new->tsap != NULL)
 	{
-	  /* Close the connection the new socket was attempting.
-	   * This seems to be safe... */
+	  /* Close the old connection the new socket was attempting,
+	   * so that we can hook it up to the new connection.
+	   * It's now safe to do it... */
 	  irttp_close_tsap(new->tsap);
 	  new->tsap = NULL;
 	}
-      /* Note : no return, fall through... */
-#else /* ALLOW_SIMULT_CONNECT */
-      irnet_disconnect_server(server, skb);
-      return;
-#endif /* ALLOW_SIMULT_CONNECT */
     }
   else
-    /* If socket is not connecting or connected, tsap should be NULL */
-    if(new->tsap != NULL)
-      {
-	/* If we are here, we are also in irnet_disconnect_indication(),
-	 * and it's a nice race condition... On the other hand, we can't be
-	 * in irda_irnet_destroy() otherwise we would not have found the
-	 * socket in the hashbin. */
-	/* Better get out of here, otherwise we will mess up tsaps ! */
-	DERROR(IRDA_CB_ERROR, "Race condition detected, abort connect...\n");
-	irnet_disconnect_server(server, skb);
-	return;
-      }
+    {
+      /* Three options :
+       * 1) socket was not connecting or connected : ttp_connect should be 0.
+       * 2) we don't want to connect the socket because we are secondary or
+       * ALLOW_SIMULT_CONNECT is undefined. ttp_connect should be 1.
+       * 3) we are half way in irnet_disconnect_indication(), and it's a
+       * nice race condition... Fortunately, we can detect that by checking
+       * if tsap is still alive. On the other hand, we can't be in
+       * irda_irnet_destroy() otherwise we would not have found this
+       * socket in the hashbin.
+       * Jean II */
+      if((test_bit(0, &new->ttp_connect)) || (new->tsap != NULL))
+	{
+	  /* Don't mess this socket, somebody else in in charge... */
+	  DERROR(IRDA_CB_ERROR, "Race condition detected, socket in use, abort connect...\n");
+	  irnet_disconnect_server(server, skb);
+	  return;
+	}
+    }
 
   /* So : at this point, we have a socket, and it is idle. Good ! */
   irnet_connect_socket(server, new, qos, max_sdu_size, max_header_size);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/irda/irttp.c linux-2.4.21-pre6/net/irda/irttp.c
--- linux-2.4.20/net/irda/irttp.c	2001-11-09 22:22:17.000000000 +0000
+++ linux-2.4.21-pre6/net/irda/irttp.c	2003-03-26 23:49:40.000000000 +0000
@@ -59,8 +59,8 @@
 
 static void irttp_flush_queues(struct tsap_cb *self);
 static void irttp_fragment_skb(struct tsap_cb *self, struct sk_buff *skb);
-static void irttp_start_todo_timer(struct tsap_cb *self, int timeout);
 static struct sk_buff *irttp_reassemble_skb(struct tsap_cb *self);
+static void irttp_todo_expired(unsigned long data);
 static int irttp_param_max_sdu_size(void *instance, irda_param_t *param, 
 				    int get);
 
@@ -72,6 +72,8 @@
 static pi_major_info_t pi_major_call_table[] = {{ pi_minor_call_table, 2 }};
 static pi_param_info_t param_info = { pi_major_call_table, 1, 0x0f, 4 };
 
+/************************ GLOBAL PROCEDURES ************************/
+
 /*
  * Function irttp_init (void)
  *
@@ -126,6 +128,239 @@
 }
 #endif
 
+/*************************** SUBROUTINES ***************************/
+
+/*
+ * Function irttp_start_todo_timer (self, timeout)
+ *
+ *    Start todo timer. 
+ *
+ * Made it more effient and unsensitive to race conditions - Jean II
+ */
+static inline void irttp_start_todo_timer(struct tsap_cb *self, int timeout)
+{
+	/* Set new value for timer */
+	mod_timer(&self->todo_timer, jiffies + timeout);
+}
+
+/*
+ * Function irttp_todo_expired (data)
+ *
+ *    Todo timer has expired!
+ *
+ * One of the restriction of the timer is that it is run only on the timer
+ * interrupt which run every 10ms. This mean that even if you set the timer
+ * with a delay of 0, it may take up to 10ms before it's run.
+ * So, to minimise latency and keep cache fresh, we try to avoid using
+ * it as much as possible.
+ * Note : we can't use tasklets, because they can't be asynchronously
+ * killed (need user context), and we can't guarantee that here...
+ * Jean II
+ */
+static void irttp_todo_expired(unsigned long data)
+{
+	struct tsap_cb *self = (struct tsap_cb *) data;
+
+	/* Check that we still exist */
+	if (!self || self->magic != TTP_TSAP_MAGIC)
+		return;
+	
+	IRDA_DEBUG(4, __FUNCTION__ "(instance=%p)\n", self);
+
+	/* Try to make some progress, especially on Tx side - Jean II */
+	irttp_run_rx_queue(self);
+	irttp_run_tx_queue(self);
+
+	/* Check if time for disconnect */
+	if (test_bit(0, &self->disconnect_pend)) {
+		/* Check if it's possible to disconnect yet */
+		if (skb_queue_empty(&self->tx_queue)) {
+			/* Make sure disconnect is not pending anymore */
+			clear_bit(0, &self->disconnect_pend);	/* FALSE */
+
+			/* Note : self->disconnect_skb may be NULL */
+			irttp_disconnect_request(self, self->disconnect_skb,
+						 P_NORMAL);
+			self->disconnect_skb = NULL;
+		} else {
+			/* Try again later */
+			irttp_start_todo_timer(self, HZ/10);
+			
+			/* No reason to try and close now */
+			return;
+		}
+	}
+	
+	/* Check if it's closing time */
+	if (self->close_pend)
+		/* Finish cleanup */
+		irttp_close_tsap(self);
+}
+
+/*
+ * Function irttp_flush_queues (self)
+ *
+ *     Flushes (removes all frames) in transitt-buffer (tx_list)
+ */
+void irttp_flush_queues(struct tsap_cb *self)
+{
+	struct sk_buff* skb;
+	
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
+	
+	/* Deallocate frames waiting to be sent */
+	while ((skb = skb_dequeue(&self->tx_queue)) != NULL)
+		dev_kfree_skb(skb);
+	
+	/* Deallocate received frames */
+	while ((skb = skb_dequeue(&self->rx_queue)) != NULL)
+		dev_kfree_skb(skb);
+	
+	/* Deallocate received fragments */
+	while ((skb = skb_dequeue(&self->rx_fragments)) != NULL)
+		dev_kfree_skb(skb);
+}
+
+/*
+ * Function irttp_reassemble (self)
+ *
+ *    Makes a new (continuous) skb of all the fragments in the fragment
+ *    queue
+ *
+ */
+static struct sk_buff *irttp_reassemble_skb(struct tsap_cb *self)
+{
+	struct sk_buff *skb, *frag;
+	int n = 0;  /* Fragment index */
+	
+      	ASSERT(self != NULL, return NULL;);
+	ASSERT(self->magic == TTP_TSAP_MAGIC, return NULL;);
+
+	IRDA_DEBUG(2, __FUNCTION__ "(), self->rx_sdu_size=%d\n", 
+		   self->rx_sdu_size);
+
+	skb = dev_alloc_skb(TTP_HEADER + self->rx_sdu_size);
+	if (!skb)
+		return NULL;
+
+	/* 
+	 * Need to reserve space for TTP header in case this skb needs to 
+	 * be requeued in case delivery failes
+	 */
+	skb_reserve(skb, TTP_HEADER);
+	skb_put(skb, self->rx_sdu_size);
+
+	/*
+	 *  Copy all fragments to a new buffer
+	 */
+	while ((frag = skb_dequeue(&self->rx_fragments)) != NULL) {
+		memcpy(skb->data+n, frag->data, frag->len);
+		n += frag->len;
+		
+		dev_kfree_skb(frag);
+	}
+	IRDA_DEBUG(2, __FUNCTION__ "(), frame len=%d\n", n);
+
+	IRDA_DEBUG(2, __FUNCTION__ "(), rx_sdu_size=%d\n", self->rx_sdu_size);
+	ASSERT(n <= self->rx_sdu_size, return NULL;);
+
+	/* Set the new length */
+	skb_trim(skb, n);
+
+	self->rx_sdu_size = 0;
+
+	return skb;
+}
+
+/*
+ * Function irttp_fragment_skb (skb)
+ *
+ *    Fragments a frame and queues all the fragments for transmission
+ *
+ */
+static inline void irttp_fragment_skb(struct tsap_cb *self,
+				      struct sk_buff *skb)
+{
+	struct sk_buff *frag;
+	__u8 *frame;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
+	ASSERT(skb != NULL, return;);
+
+	/*
+	 *  Split frame into a number of segments
+	 */
+	while (skb->len > self->max_seg_size) {
+		IRDA_DEBUG(2, __FUNCTION__  "(), fragmenting ...\n");
+
+		/* Make new segment */
+		frag = dev_alloc_skb(self->max_seg_size+self->max_header_size);
+		if (!frag)
+			return;
+
+		skb_reserve(frag, self->max_header_size);
+
+		/* Copy data from the original skb into this fragment. */
+		memcpy(skb_put(frag, self->max_seg_size), skb->data, 
+		       self->max_seg_size);
+
+		/* Insert TTP header, with the more bit set */
+		frame = skb_push(frag, TTP_HEADER);
+		frame[0] = TTP_MORE;
+		
+		/* Hide the copied data from the original skb */
+		skb_pull(skb, self->max_seg_size);
+
+		/* Queue fragment */
+		skb_queue_tail(&self->tx_queue, frag);
+	}
+	/* Queue what is left of the original skb */
+	IRDA_DEBUG(2, __FUNCTION__  "(), queuing last segment\n");
+	
+	frame = skb_push(skb, TTP_HEADER);
+	frame[0] = 0x00; /* Clear more bit */
+
+	/* Queue fragment */
+	skb_queue_tail(&self->tx_queue, skb);
+}
+
+/*
+ * Function irttp_param_max_sdu_size (self, param)
+ *
+ *    Handle the MaxSduSize parameter in the connect frames, this function
+ *    will be called both when this parameter needs to be inserted into, and
+ *    extracted from the connect frames
+ */
+static int irttp_param_max_sdu_size(void *instance, irda_param_t *param, 
+				    int get)
+{
+	struct tsap_cb *self;
+
+	self = (struct tsap_cb *) instance;
+
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
+
+	if (get)
+		param->pv.i = self->tx_max_sdu_size;
+	else
+		self->tx_max_sdu_size = param->pv.i;
+
+	IRDA_DEBUG(1, __FUNCTION__ "(), MaxSduSize=%d\n", param->pv.i);
+	
+	return 0;
+}
+
+/*************************** CLIENT CALLS ***************************/
+/************************** LMP CALLBACKS **************************/
+/* Everything is happily mixed up. Waiting for next clean up - Jean II */
+
 /*
  * Function irttp_open_tsap (stsap, notify)
  *
@@ -157,7 +392,10 @@
 	memset(self, 0, sizeof(struct tsap_cb));
 	spin_lock_init(&self->lock);
 
+	/* Initialise todo timer */
 	init_timer(&self->todo_timer);
+	self->todo_timer.data     = (unsigned long) self;
+	self->todo_timer.function = &irttp_todo_expired;
 
 	/* Initialize callbacks for IrLMP to use */
 	irda_notify_init(&ttp_notify);
@@ -166,6 +404,7 @@
 	ttp_notify.disconnect_indication = irttp_disconnect_indication;
 	ttp_notify.data_indication = irttp_data_indication;
 	ttp_notify.udata_indication = irttp_udata_indication;
+	ttp_notify.flow_indication = irttp_flow_indication;
 	if(notify->status_indication != NULL)
 		ttp_notify.status_indication = irttp_status_indication;
 	ttp_notify.instance = self;
@@ -199,8 +438,8 @@
 
 	hashbin_insert(irttp->tsaps, (irda_queue_t *) self, (int) self, NULL);
 
-	if (credit > TTP_MAX_QUEUE)
-		self->initial_credit = TTP_MAX_QUEUE;
+	if (credit > TTP_RX_MAX_CREDIT)
+		self->initial_credit = TTP_RX_MAX_CREDIT;
 	else
 		self->initial_credit = credit;
 
@@ -224,7 +463,7 @@
 
 	del_timer(&self->todo_timer);
 
-	/* This one won't be cleaned up if we are diconnect_pend + close_pend
+	/* This one won't be cleaned up if we are disconnect_pend + close_pend
 	 * and we receive a disconnect_indication */
 	if (self->disconnect_skb)
 		dev_kfree_skb(self->disconnect_skb);
@@ -262,7 +501,7 @@
 			irttp_disconnect_request(self, NULL, P_NORMAL);
 		}
 		self->close_pend = TRUE;
-		irttp_start_todo_timer(self, 1*HZ);
+		irttp_start_todo_timer(self, HZ/10);
 
 		return 0; /* Will be back! */
 	}
@@ -327,6 +566,9 @@
 	ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
 	ASSERT(skb != NULL, return -1;);
 
+	IRDA_DEBUG(2, __FUNCTION__ " : queue len = %d\n",
+		   skb_queue_len(&self->tx_queue));
+
 	/* Check that nothing bad happens */
 	if ((skb->len == 0) || (!self->connected)) {
 		WARNING(__FUNCTION__ "(), No data, or not connected\n");
@@ -358,12 +600,14 @@
 	/* 
 	 *  Check if transmit queue is full
 	 */
-	if (skb_queue_len(&self->tx_queue) >= TTP_MAX_QUEUE) {
+	if (skb_queue_len(&self->tx_queue) >= TTP_TX_MAX_QUEUE) {
 		/*
 		 *  Give it a chance to empty itself
 		 */
 		irttp_run_tx_queue(self);
-		
+
+		/* Drop packet. This error code should trigger the caller
+		 * to requeue the packet in the client code - Jean II */
 		return -ENOBUFS;
 	}
        
@@ -387,20 +631,25 @@
 
 	/* Check if we can accept more data from client */
 	if ((!self->tx_sdu_busy) && 
-	    (skb_queue_len(&self->tx_queue) > TTP_HIGH_THRESHOLD)) {
-		
-		/* Tx queue filling up, so stop client */
-		self->tx_sdu_busy = TRUE;
-		
-	 	if (self->notify.flow_indication) {
+	    (skb_queue_len(&self->tx_queue) > TTP_TX_HIGH_THRESHOLD)) {
+		/* Tx queue filling up, so stop client. */
+		if (self->notify.flow_indication) {
  			self->notify.flow_indication(self->notify.instance, 
 						     self, FLOW_STOP);
 		}
- 	}
+		/* self->tx_sdu_busy is the state of the client.
+		 * Update state after notifying client to avoid
+		 * race condition with irttp_flow_indication().
+		 * If the queue empty itself after our test but before
+		 * we set the flag, we will fix ourselves below in
+		 * irttp_run_tx_queue().
+		 * Jean II */
+		self->tx_sdu_busy = TRUE;
+	}
 	
 	/* Try to make some progress */
 	irttp_run_tx_queue(self);
-	
+
 	return 0;
 }
 
@@ -416,28 +665,20 @@
 	unsigned long flags;
 	int n;
 
+	IRDA_DEBUG(2, __FUNCTION__ "() : send_credit = %d, queue_len = %d\n",
+		   self->send_credit, skb_queue_len(&self->tx_queue));
+
 	/* Get exclusive access to the tx queue, otherwise don't touch it */
 	if (irda_lock(&self->tx_queue_lock) == FALSE)
 		return;
 
-	/* Try to send out frames as long as we have credits */
+	/* Try to send out frames as long as we have credits
+	 * and as long as LAP is not full. If LAP is full, it will
+	 * poll us through irttp_flow_indication() - Jean II */
 	while ((self->send_credit > 0) &&
+	       (!irlmp_lap_tx_queue_full(self->lsap)) &&
 	       (skb = skb_dequeue(&self->tx_queue)))
 	{
-		/* 
-		 * Make sure we don't flood IrLAP with frames just because
-		 * the remote device has given us a lot of credits
-		 */
-		if (irlmp_get_lap_tx_queue_len(self->lsap) > LAP_MAX_QUEUE) {
-			/* Re-queue packet */
-			skb_queue_head(&self->tx_queue, skb);
-
-			/* Try later. Would be better if IrLAP could notify us */
-			irttp_start_todo_timer(self, MSECS_TO_JIFFIES(10));
-			
-			break;
-		}
-
 		/*
 		 *  Since we can transmit and receive frames concurrently, 
 		 *  the code below is a critical region and we must assure that
@@ -484,32 +725,35 @@
 		 * Jean II */
 		if (skb->sk != NULL) {
 			/* IrSOCK application, IrOBEX, ... */
-			IRDA_DEBUG(4, __FUNCTION__ "() : Detaching SKB from socket.\n");
-
-			/* That's the right way to do it - Jean II */
 			skb_orphan(skb);
-		} else {
-			/* IrCOMM over IrTTP, IrLAN, ... */
-			IRDA_DEBUG(4, __FUNCTION__ "() : Got SKB not attached to a socket.\n");
 		}
+			/* IrCOMM over IrTTP, IrLAN, ... */
 
 		/* Pass the skb to IrLMP - done */
 		irlmp_data_request(self->lsap, skb);
 		self->stats.tx_packets++;
+	}
 
-		/* Check if we can accept more frames from client */
-		if ((self->tx_sdu_busy) && 
-		    (skb_queue_len(&self->tx_queue) < TTP_LOW_THRESHOLD)) 
-		{
-			self->tx_sdu_busy = FALSE;
-			
-			if (self->notify.flow_indication)
-				self->notify.flow_indication(
-					self->notify.instance, self,
-					FLOW_START);
-		}
+	/* Check if we can accept more frames from client.
+	 * We don't want to wait until the todo timer to do that, and we
+	 * can't use tasklets (grr...), so we are obliged to give control
+	 * to client. That's ok, this test will be true not too often
+	 * (max once per LAP window) and we are called from places
+	 * where we can spend a bit of time doing stuff. - Jean II */
+	if ((self->tx_sdu_busy) && 
+	    (skb_queue_len(&self->tx_queue) < TTP_TX_LOW_THRESHOLD) &&
+	    (!self->close_pend))
+	{
+		if (self->notify.flow_indication)
+			self->notify.flow_indication(self->notify.instance,
+						     self, FLOW_START);
+
+		/* self->tx_sdu_busy is the state of the client.
+		 * We don't really have a race here, but it's always safer
+		 * to update our state after the client - Jean II */
+		self->tx_sdu_busy = FALSE;
 	}
-	
+
 	/* Reset lock */
 	self->tx_queue_lock = 0;
 }
@@ -520,7 +764,7 @@
  *    Send a dataless flowdata TTP-PDU and give available credit to peer
  *    TSAP
  */
-void irttp_give_credit(struct tsap_cb *self) 
+static inline void irttp_give_credit(struct tsap_cb *self) 
 {
 	struct sk_buff *tx_skb = NULL;
 	unsigned long flags;
@@ -531,7 +775,7 @@
 
 	IRDA_DEBUG(4, __FUNCTION__ "() send=%d,avail=%d,remote=%d\n", 
 		   self->send_credit, self->avail_credit, self->remote_credit);
-	
+
 	/* Give credit to peer */
 	tx_skb = dev_alloc_skb(64);
 	if (!tx_skb)
@@ -606,6 +850,7 @@
 				 struct sk_buff *skb)
 {
 	struct tsap_cb *self;
+	unsigned long flags;
 	int n;
 
 	self = (struct tsap_cb *) instance;
@@ -614,47 +859,66 @@
 
 	self->stats.rx_packets++;
 
+	/*  Deal with inbound credit
+	 *  Since we can transmit and receive frames concurrently, 
+	 *  the code below is a critical region and we must assure that
+	 *  nobody messes with the credits while we update them.
+	 */
+	spin_lock_irqsave(&self->lock, flags);
+	self->send_credit += n;
+	if (skb->len > 1)
+		self->remote_credit--;
+	spin_unlock_irqrestore(&self->lock, flags);
+
 	/* 
 	 *  Data or dataless packet? Dataless frames contains only the 
 	 *  TTP_HEADER. 
 	 */
 	if (skb->len > 1) {
-		/* Deal with inbound credit */
-		self->send_credit += n;
-		self->remote_credit--;
-		
 		/* 
 		 *  We don't remove the TTP header, since we must preserve the
 		 *  more bit, so the defragment routing knows what to do
 		 */
 		skb_queue_tail(&self->rx_queue, skb);
 	} else {
-		self->send_credit += n;	/* Dataless flowdata TTP-PDU */
+		/* Dataless flowdata TTP-PDU */
 		dev_kfree_skb(skb);
 	}
 
+
+	/* Push data to the higher layer.
+	 * We do it synchronously because running the todo timer for each
+	 * receive packet would be too much overhead and latency.
+	 * By passing control to the higher layer, we run the risk that
+	 * it may take time or grab a lock. Most often, the higher layer
+	 * will only put packet in a queue.
+	 * Anyway, packets are only dripping through the IrDA, so we can
+	 * have time before the next packet.
+	 * Further, we are run from NET_BH, so the worse that can happen is
+	 * us missing the optimal time to send back the PF bit in LAP.
+	 * Jean II */
 	irttp_run_rx_queue(self);
 
-	/* 
-	 *  Give avay some credits to peer? 
-	 */
-	if ((skb_queue_empty(&self->tx_queue)) && 
-	    (self->remote_credit < TTP_LOW_THRESHOLD) && 
-	    (self->avail_credit > 0)) 
-	{
-		/* Schedule to start immediately after this thread */
-		irttp_start_todo_timer(self, 0);
-		/*irttp_give_credit(self);*/
-	}
-	
+	/* We now give credits to peer in irttp_run_rx_queue().
+	 * We need to send credit *NOW*, otherwise we are going
+	 * to miss the next Tx window. The todo timer may take
+	 * a while before it's run... - Jean II */
+
 	/* 
 	 * If the peer device has given us some credits and we didn't have
-         * anyone from before, the we need to shedule the tx queue?  
+         * anyone from before, then we need to shedule the tx queue.
+	 * We need to do that because our Tx have stopped (so we may not
+	 * get any LAP flow indication) and the user may be stopped as
+	 * well. - Jean II
 	 */
 	if (self->send_credit == n) {
-		/*irttp_run_tx_queue(self);*/
-		irttp_start_todo_timer(self, 0);
+		/* Restart pushing stuff to LAP */
+		irttp_run_tx_queue(self);
+		/* Note : we don't want to schedule the todo timer
+		 * because it has horrible latency. No tasklets
+		 * because the tasklet API is broken. - Jean II */
 	}
+
 	return 0;
 }
 
@@ -687,6 +951,50 @@
 }
 
 /*
+ * Function irttp_flow_indication (self, reason)
+ *
+ *    Flow_indication : IrLAP tells us to send more data.
+ *
+ */
+void irttp_flow_indication(void *instance, void *sap, LOCAL_FLOW flow)
+{
+	struct tsap_cb *self;
+
+	self = (struct tsap_cb *) instance;
+	
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
+	
+	IRDA_DEBUG(4, __FUNCTION__ "(instance=%p)\n", self);
+
+	/* We are "polled" directly from LAP, and the LAP want to fill
+	 * its Tx window. We want to do our best to send it data, so that
+	 * we maximise the window. On the other hand, we want to limit the
+	 * amount of work here so that LAP doesn't hang forever waiting
+	 * for packets. - Jean II */
+
+	/* Try to send some packets. Currently, LAP calls us every time
+	 * there is one free slot, so we will send only one packet.
+	 * This allow the scheduler to do its round robin - Jean II */
+	irttp_run_tx_queue(self);
+
+	/* Note regarding the interraction with higher layer.
+	 * irttp_run_tx_queue() may call the client when its queue
+	 * start to empty, via notify.flow_indication(). Initially.
+	 * I wanted this to happen in a tasklet, to avoid client
+	 * grabbing the CPU, but we can't use tasklets safely. And timer
+	 * is definitely too slow.
+	 * This will happen only once per LAP window, and usually at
+	 * the third packet (unless window is smaller). LAP is still
+	 * doing mtt and sending first packet so it's sort of OK
+	 * to do that. Jean II */
+
+	/* If we need to send disconnect. try to do it now */
+	if(self->disconnect_pend)
+		irttp_start_todo_timer(self, 0);
+}
+
+/*
  * Function irttp_flow_request (self, command)
  *
  *    This funtion could be used by the upper layers to tell IrTTP to stop
@@ -709,7 +1017,10 @@
 		IRDA_DEBUG(1, __FUNCTION__ "(), flow start\n");
 		self->rx_sdu_busy = FALSE;
 		
+		/* Client say he can accept more data, try to free our
+		 * queues ASAP - Jean II */
 		irttp_run_rx_queue(self);
+
 		break;
 	default:
 		IRDA_DEBUG(1, __FUNCTION__ "(), Unknown flow command!\n");
@@ -1147,10 +1458,15 @@
 
 			irttp_run_tx_queue(self);
 
-			irttp_start_todo_timer(self, MSECS_TO_JIFFIES(1000));
+			irttp_start_todo_timer(self, HZ/10);
 			return -1;
 		}
 	}
+	/* Note : we don't need to check if self->rx_queue is full and the
+	 * state of self->rx_sdu_busy because the disconnect response will
+	 * be sent at the LMP level (so even if the peer has its Tx queue
+	 * full of data). - Jean II */
+
 	IRDA_DEBUG(1, __FUNCTION__ "(), Disconnecting ...\n");
 	self->connected = FALSE;
 
@@ -1281,8 +1597,7 @@
 	 *  Reassemble all frames in receive queue and deliver them
 	 */
 	while (!self->rx_sdu_busy && (skb = skb_dequeue(&self->rx_queue))) {
-		self->avail_credit++;
-
+		/* This bit will tell us if it's the last fragment or not */
 		more = skb->data[0] & 0x80;
 
 		/* Remove TTP header */
@@ -1293,7 +1608,7 @@
 
 		/*  
 		 * If SAR is disabled, or user has requested no reassembly
-		 * of received fragements then we just deliver them
+		 * of received fragments then we just deliver them
 		 * immediately. This can be requested by clients that
 		 * implements byte streams without any message boundaries
 		 */
@@ -1353,236 +1668,46 @@
 		}
 		self->rx_sdu_size = 0;
 	}
-	/* Reset lock */
-	self->rx_queue_lock = 0;
-}
-
-/*
- * Function irttp_flush_queues (self)
- *
- *     Flushes (removes all frames) in transitt-buffer (tx_list)
- */
-void irttp_flush_queues(struct tsap_cb *self)
-{
-	struct sk_buff* skb;
-	
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
-
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
-	
-	/* Deallocate frames waiting to be sent */
-	while ((skb = skb_dequeue(&self->tx_queue)) != NULL)
-		dev_kfree_skb(skb);
-	
-	/* Deallocate received frames */
-	while ((skb = skb_dequeue(&self->rx_queue)) != NULL)
-		dev_kfree_skb(skb);
-	
-	/* Deallocate received fragments */
-	while ((skb = skb_dequeue(&self->rx_fragments)) != NULL)
-		dev_kfree_skb(skb);
-}
-
-/*
- * Function irttp_reasseble (self)
- *
- *    Makes a new (continuous) skb of all the fragments in the fragment
- *    queue
- *
- */
-static struct sk_buff *irttp_reassemble_skb(struct tsap_cb *self)
-{
-	struct sk_buff *skb, *frag;
-	int n = 0;  /* Fragment index */
-	
-      	ASSERT(self != NULL, return NULL;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return NULL;);
-
-	IRDA_DEBUG(2, __FUNCTION__ "(), self->rx_sdu_size=%d\n", 
-		   self->rx_sdu_size);
-
-	skb = dev_alloc_skb(TTP_HEADER + self->rx_sdu_size);
-	if (!skb)
-		return NULL;
-
-	/* 
-	 * Need to reserve space for TTP header in case this skb needs to 
-	 * be requeued in case delivery failes
-	 */
-	skb_reserve(skb, TTP_HEADER);
-	skb_put(skb, self->rx_sdu_size);
-
-	/*
-	 *  Copy all fragments to a new buffer
-	 */
-	while ((frag = skb_dequeue(&self->rx_fragments)) != NULL) {
-		memcpy(skb->data+n, frag->data, frag->len);
-		n += frag->len;
-		
-		dev_kfree_skb(frag);
-	}
-	IRDA_DEBUG(2, __FUNCTION__ "(), frame len=%d\n", n);
-
-	IRDA_DEBUG(2, __FUNCTION__ "(), rx_sdu_size=%d\n", self->rx_sdu_size);
-	ASSERT(n <= self->rx_sdu_size, return NULL;);
-
-	/* Set the new length */
-	skb_trim(skb, n);
-
-	self->rx_sdu_size = 0;
-
-	return skb;
-}
-
-/*
- * Function irttp_fragment_skb (skb)
- *
- *    Fragments a frame and queues all the fragments for transmission
- *
- */
-static void irttp_fragment_skb(struct tsap_cb *self, struct sk_buff *skb)
-{
-	struct sk_buff *frag;
-	__u8 *frame;
-
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
-
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
-	ASSERT(skb != NULL, return;);
 
 	/*
-	 *  Split frame into a number of segments
+	 * It's not trivial to keep track of how many credits are available
+	 * by incrementing at each packet, because delivery may fail 
+	 * (irttp_do_data_indication() may requeue the frame) and because
+	 * we need to take care of fragmentation.
+	 * We want the other side to send up to initial_credit packets.
+	 * We have some frames in our queues, and we have already allowed it
+	 * to send remote_credit.
+	 * No need to spinlock, write is atomic and self correcting...
+	 * Jean II
 	 */
-	while (skb->len > self->max_seg_size) {
-		IRDA_DEBUG(2, __FUNCTION__  "(), fragmenting ...\n");
-
-		/* Make new segment */
-		frag = dev_alloc_skb(self->max_seg_size+self->max_header_size);
-		if (!frag)
-			return;
-
-		skb_reserve(frag, self->max_header_size);
-
-		/* Copy data from the original skb into this fragment. */
-		memcpy(skb_put(frag, self->max_seg_size), skb->data, 
-		       self->max_seg_size);
-
-		/* Insert TTP header, with the more bit set */
-		frame = skb_push(frag, TTP_HEADER);
-		frame[0] = TTP_MORE;
-		
-		/* Hide the copied data from the original skb */
-		skb_pull(skb, self->max_seg_size);
-
-		/* Queue fragment */
-		skb_queue_tail(&self->tx_queue, frag);
-	}
-	/* Queue what is left of the original skb */
-	IRDA_DEBUG(2, __FUNCTION__  "(), queuing last segment\n");
-	
-	frame = skb_push(skb, TTP_HEADER);
-	frame[0] = 0x00; /* Clear more bit */
-
-	/* Queue fragment */
-	skb_queue_tail(&self->tx_queue, skb);
-}
-
-/*
- * Function irttp_param_max_sdu_size (self, param)
- *
- *    Handle the MaxSduSize parameter in the connect frames, this function
- *    will be called both when this parameter needs to be inserted into, and
- *    extracted from the connect frames
- */
-static int irttp_param_max_sdu_size(void *instance, irda_param_t *param, 
-				    int get)
-{
-	struct tsap_cb *self;
-
-	self = (struct tsap_cb *) instance;
-
-	ASSERT(self != NULL, return -1;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
-
-	if (get)
-		param->pv.i = self->tx_max_sdu_size;
-	else
-		self->tx_max_sdu_size = param->pv.i;
-
-	IRDA_DEBUG(1, __FUNCTION__ "(), MaxSduSize=%d\n", param->pv.i);
-	
-	return 0;
-}
-
-/*
- * Function irttp_todo_expired (data)
- *
- *    Todo timer has expired!
- *
- */
-static void irttp_todo_expired(unsigned long data)
-{
-	struct tsap_cb *self = (struct tsap_cb *) data;
-
-	/* Check that we still exist */
-	if (!self || self->magic != TTP_TSAP_MAGIC)
-		return;
-	
-	irttp_run_rx_queue(self);
-	irttp_run_tx_queue(self);
-		
-	/*  Give avay some credits to peer?  */
-	if ((self->remote_credit < TTP_LOW_THRESHOLD) && 
-	    (self->avail_credit > 0) && (skb_queue_empty(&self->tx_queue)))
-	{
+	self->avail_credit = (self->initial_credit -
+			      (self->remote_credit +
+			       skb_queue_len(&self->rx_queue) +
+			       skb_queue_len(&self->rx_fragments)));
+
+	/* Do we have too much credits to send to peer ? */
+	if ((self->remote_credit <= TTP_RX_MIN_CREDIT) &&
+	    (self->avail_credit > 0)) {
+		/* Send explicit credit frame */
 		irttp_give_credit(self);
+		/* Note : do *NOT* check if tx_queue is non-empty, that
+		 * will produce deadlocks. I repeat : send a credit frame
+		 * even if we have something to send in our Tx queue.
+		 * If we have credits, it means that our Tx queue is blocked.
+		 *
+		 * Let's suppose the peer can't keep up with our Tx. He will
+		 * flow control us by not sending us any credits, and we
+		 * will stop Tx and start accumulating credits here.
+		 * Up to the point where the peer will stop its Tx queue,
+		 * for lack of credits.
+		 * Let's assume the peer application is single threaded.
+		 * It will block on Tx and never consume any Rx buffer.
+		 * Deadlock. Guaranteed. - Jean II
+		 */
 	}
 
-	/* Check if time for disconnect */
-	if (test_bit(0, &self->disconnect_pend)) {
-		/* Check if it's possible to disconnect yet */
-		if (skb_queue_empty(&self->tx_queue)) {
-			/* Make sure disconnect is not pending anymore */
-			clear_bit(0, &self->disconnect_pend);	/* FALSE */
-
-			/* Note : self->disconnect_skb may be NULL */
-			irttp_disconnect_request(self, self->disconnect_skb,
-						 P_NORMAL);
-			self->disconnect_skb = NULL;
-		} else {
-			/* Try again later */
-			irttp_start_todo_timer(self, 1*HZ);
-			
-			/* No reason to try and close now */
-			return;
-		}
-	}
-	
-	/* Check if it's closing time */
-	if (self->close_pend)
-		irttp_close_tsap(self);
-}
-
-/*
- * Function irttp_start_todo_timer (self, timeout)
- *
- *    Start todo timer. 
- *
- */
-static void irttp_start_todo_timer(struct tsap_cb *self, int timeout)
-{
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
-
-	del_timer(&self->todo_timer);
-	
-	self->todo_timer.data     = (unsigned long) self;
-	self->todo_timer.function = &irttp_todo_expired;
-	self->todo_timer.expires  = jiffies + timeout;
-
-	add_timer(&self->todo_timer);
+	/* Reset lock */
+	self->rx_queue_lock = 0;
 }
 
 #ifdef CONFIG_PROC_FS
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/irda/parameters.c linux-2.4.21-pre6/net/irda/parameters.c
--- linux-2.4.20/net/irda/parameters.c	2001-11-09 22:22:17.000000000 +0000
+++ linux-2.4.21-pre6/net/irda/parameters.c	2003-03-26 23:49:07.000000000 +0000
@@ -28,6 +28,7 @@
  *     
  ********************************************************************/
 
+#include <linux/types.h>
 #include <asm/unaligned.h>
 #include <asm/byteorder.h>
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/netlink/af_netlink.c linux-2.4.21-pre6/net/netlink/af_netlink.c
--- linux-2.4.20/net/netlink/af_netlink.c	2002-11-28 23:53:16.000000000 +0000
+++ linux-2.4.21-pre6/net/netlink/af_netlink.c	2003-03-26 23:49:39.000000000 +0000
@@ -562,6 +562,14 @@
 	read_unlock(&nl_table_lock);
 }
 
+static inline void netlink_rcv_wake(struct sock *sk)
+{
+	if (skb_queue_len(&sk->receive_queue) == 0)
+		clear_bit(0, &sk->protinfo.af_netlink->state);
+	if (!test_bit(0, &sk->protinfo.af_netlink->state))
+		wake_up_interruptible(&sk->protinfo.af_netlink->wait);
+}
+
 static int netlink_sendmsg(struct socket *sock, struct msghdr *msg, int len,
 			   struct scm_cookie *scm)
 {
@@ -675,12 +683,7 @@
 		netlink_dump(sk);
 
 out:
-	if (skb_queue_len(&sk->receive_queue) <= sk->rcvbuf/2) {
-		if (skb_queue_len(&sk->receive_queue) == 0)
-			clear_bit(0, &sk->protinfo.af_netlink->state);
-		if (!test_bit(0, &sk->protinfo.af_netlink->state))
-			wake_up_interruptible(&sk->protinfo.af_netlink->wait);
-	}
+	netlink_rcv_wake(sk);
 	return err ? : copied;
 }
 
@@ -688,13 +691,7 @@
 {
 	if (sk->protinfo.af_netlink->data_ready)
 		sk->protinfo.af_netlink->data_ready(sk, len);
-
-	if (skb_queue_len(&sk->receive_queue) <= sk->rcvbuf/2) {
-		if (skb_queue_len(&sk->receive_queue) == 0)
-			clear_bit(0, &sk->protinfo.af_netlink->state);
-		if (!test_bit(0, &sk->protinfo.af_netlink->state))
-			wake_up_interruptible(&sk->protinfo.af_netlink->wait);
-	}
+	netlink_rcv_wake(sk);
 }
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/netrom/nr_dev.c linux-2.4.21-pre6/net/netrom/nr_dev.c
--- linux-2.4.20/net/netrom/nr_dev.c	2001-06-28 00:10:55.000000000 +0000
+++ linux-2.4.21-pre6/net/netrom/nr_dev.c	2003-03-26 23:49:54.000000000 +0000
@@ -19,7 +19,6 @@
  */
 
 #include <linux/config.h>
-#define __NO_VERSION__
 #include <linux/module.h>
 #include <linux/proc_fs.h>
 #include <linux/kernel.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/netsyms.c linux-2.4.21-pre6/net/netsyms.c
--- linux-2.4.20/net/netsyms.c	2002-11-28 23:53:16.000000000 +0000
+++ linux-2.4.21-pre6/net/netsyms.c	2003-03-26 23:49:30.000000000 +0000
@@ -93,6 +93,7 @@
 /* Skbuff symbols. */
 EXPORT_SYMBOL(skb_over_panic);
 EXPORT_SYMBOL(skb_under_panic);
+EXPORT_SYMBOL(skb_pad);
 
 /* Socket layer registration */
 EXPORT_SYMBOL(sock_register);
@@ -294,6 +295,9 @@
 EXPORT_SYMBOL(unregister_inet6addr_notifier);
 #include <net/ip6_route.h>
 EXPORT_SYMBOL(ip6_route_output);
+#ifdef CONFIG_NETFILTER
+EXPORT_SYMBOL(ip6_route_me_harder);
+#endif
 #endif
 #if defined (CONFIG_IPV6_MODULE) || defined (CONFIG_KHTTPD) || defined (CONFIG_KHTTPD_MODULE)
 /* inet functions common to v4 and v6 */
@@ -389,6 +393,7 @@
 EXPORT_SYMBOL(sysctl_tcp_ecn);
 EXPORT_SYMBOL(tcp_cwnd_application_limited);
 EXPORT_SYMBOL(tcp_sendpage);
+EXPORT_SYMBOL(sysctl_tcp_low_latency);
 
 EXPORT_SYMBOL(tcp_write_xmit);
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/rose/rose_dev.c linux-2.4.21-pre6/net/rose/rose_dev.c
--- linux-2.4.20/net/rose/rose_dev.c	2001-06-28 00:10:55.000000000 +0000
+++ linux-2.4.21-pre6/net/rose/rose_dev.c	2003-03-26 23:49:19.000000000 +0000
@@ -15,7 +15,6 @@
  */
 
 #include <linux/config.h>
-#define __NO_VERSION__
 #include <linux/module.h>
 #include <linux/proc_fs.h>
 #include <linux/kernel.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/sched/sch_gred.c linux-2.4.21-pre6/net/sched/sch_gred.c
--- linux-2.4.20/net/sched/sch_gred.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.21-pre6/net/sched/sch_gred.c	2003-03-26 23:49:25.000000000 +0000
@@ -116,7 +116,7 @@
 	}
 
 
-	if ( ((skb->tc_index&0xf) > t->DPs) || !(q=t->tab[skb->tc_index&0xf])) {
+	if ( ((skb->tc_index&0xf) > (t->DPs -1)) || !(q=t->tab[skb->tc_index&0xf])) {
 		printk("GRED: setting to default (%d)\n ",t->def);
 		if (!(q=t->tab[t->def])) {
 			DPRINTK("GRED: setting to default FAILED! dropping!! "
@@ -328,18 +328,20 @@
 	struct tc_gred_qopt *ctl;
 	struct tc_gred_sopt *sopt;
 	struct rtattr *tb[TCA_GRED_STAB];
-	struct rtattr *tb2[TCA_GRED_STAB];
+	struct rtattr *tb2[TCA_GRED_DPS];
 	int i;
 
 	if (opt == NULL ||
 		rtattr_parse(tb, TCA_GRED_STAB, RTA_DATA(opt), RTA_PAYLOAD(opt)) )
 			return -EINVAL;
 
-	if (tb[TCA_GRED_PARMS-1] == 0 && tb[TCA_GRED_STAB-1] == 0 &&
-	    tb[TCA_GRED_DPS-1] != 0) {
+	if (tb[TCA_GRED_PARMS-1] == 0 && tb[TCA_GRED_STAB-1] == 0) {
 		rtattr_parse(tb2, TCA_GRED_DPS, RTA_DATA(opt),
 		    RTA_PAYLOAD(opt));
 
+		if (tb2[TCA_GRED_DPS-1] == 0)
+			return -EINVAL;
+
 		sopt = RTA_DATA(tb2[TCA_GRED_DPS-1]);
 		table->DPs=sopt->DPs;   
 		table->def=sopt->def_DP; 
@@ -471,16 +473,18 @@
 	struct gred_sched *table = (struct gred_sched *)sch->data;
 	struct tc_gred_sopt *sopt;
 	struct rtattr *tb[TCA_GRED_STAB];
-	struct rtattr *tb2[TCA_GRED_STAB];
+	struct rtattr *tb2[TCA_GRED_DPS];
 
 	if (opt == NULL ||
 		rtattr_parse(tb, TCA_GRED_STAB, RTA_DATA(opt), RTA_PAYLOAD(opt)) )
 			return -EINVAL;
 
-	if (tb[TCA_GRED_PARMS-1] == 0 && tb[TCA_GRED_STAB-1] == 0 &&
-	    tb[TCA_GRED_DPS-1] != 0) {
+	if (tb[TCA_GRED_PARMS-1] == 0 && tb[TCA_GRED_STAB-1] == 0 ) {
 		rtattr_parse(tb2, TCA_GRED_DPS, RTA_DATA(opt),RTA_PAYLOAD(opt));
 
+		if (tb2[TCA_GRED_DPS-1] == 0)
+			return -EINVAL;
+
 		sopt = RTA_DATA(tb2[TCA_GRED_DPS-1]);
 		table->DPs=sopt->DPs;   
 		table->def=sopt->def_DP; 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/sched/sch_htb.c linux-2.4.21-pre6/net/sched/sch_htb.c
--- linux-2.4.20/net/sched/sch_htb.c	2002-11-28 23:53:16.000000000 +0000
+++ linux-2.4.21-pre6/net/sched/sch_htb.c	2003-03-26 23:48:58.000000000 +0000
@@ -19,7 +19,7 @@
  *			created test case so that I was able to fix nasty bug
  *		and many others. thanks.
  *
- * $Id: sch_htb.c,v 1.14 2002/09/28 12:55:22 devik Exp devik $
+ * $Id: sch_htb.c,v 1.17 2003/01/29 09:22:18 devik Exp devik $
  */
 #include <linux/config.h>
 #include <linux/module.h>
@@ -71,16 +71,12 @@
 #define HTB_HYSTERESIS 1/* whether to use mode hysteresis for speedup */
 #define HTB_QLOCK(S) spin_lock_bh(&(S)->dev->queue_lock)
 #define HTB_QUNLOCK(S) spin_unlock_bh(&(S)->dev->queue_lock)
-#define HTB_VER 0x30007	/* major must be matched with number suplied by TC as version */
+#define HTB_VER 0x3000a	/* major must be matched with number suplied by TC as version */
 
 #if HTB_VER >> 16 != TC_HTB_PROTOVER
 #error "Mismatched sch_htb.c and pkt_sch.h"
 #endif
 
-/* temporary debug defines to be removed after beta stage */
-#define DEVIK_MEND(N)
-#define DEVIK_MSTART(N)
-
 /* debugging support; S is subsystem, these are defined:
   0 - netlink messages
   1 - enqueue
@@ -421,7 +417,6 @@
 	if ((delay <= 0 || delay > cl->mbuffer) && net_ratelimit())
 		printk(KERN_ERR "HTB: suspicious delay in wait_tree d=%ld cl=%X h=%d\n",delay,cl->classid,debug_hint);
 #endif
-	DEVIK_MSTART(9);
 	cl->pq_key = jiffies + PSCHED_US2JIFFIE(delay);
 	if (cl->pq_key == jiffies)
 		cl->pq_key++;
@@ -440,7 +435,6 @@
 	}
 	rb_link_node(&cl->pq_node, parent, p);
 	rb_insert_color(&cl->pq_node, &q->wait_pq[cl->level]);
-	DEVIK_MEND(9);
 }
 
 /**
@@ -689,7 +683,6 @@
     struct htb_sched *q = (struct htb_sched *)sch->data;
     struct htb_class *cl = htb_classify(skb,sch);
 
-    DEVIK_MSTART(0);
     if (cl == HTB_DIRECT || !cl) {
 	/* enqueue to helper queue */
 	if (q->direct_queue.qlen < q->direct_qlen && cl) {
@@ -698,25 +691,20 @@
 	} else {
 	    kfree_skb (skb);
 	    sch->stats.drops++;
-	    DEVIK_MEND(0);
 	    return NET_XMIT_DROP;
 	}
     } else if (cl->un.leaf.q->enqueue(skb, cl->un.leaf.q) != NET_XMIT_SUCCESS) {
 	sch->stats.drops++;
 	cl->stats.drops++;
-	DEVIK_MEND(0);
 	return NET_XMIT_DROP;
     } else {
 	cl->stats.packets++; cl->stats.bytes += skb->len;
-	DEVIK_MSTART(1);
 	htb_activate (q,cl);
-	DEVIK_MEND(1);
     }
 
     sch->q.qlen++;
     sch->stats.packets++; sch->stats.bytes += skb->len;
     HTB_DBG(1,1,"htb_enq_ok cl=%X skb=%p\n",cl?cl->classid:0,skb);
-    DEVIK_MEND(0);
     return NET_XMIT_SUCCESS;
 }
 
@@ -952,7 +940,6 @@
 	//struct htb_sched *q = (struct htb_sched *)sch->data;
 	struct htb_class *cl,*start;
 	/* look initial class up in the row */
-	DEVIK_MSTART(6);
 	start = cl = htb_lookup_leaf (q->row[level]+prio,prio,q->ptr[level]+prio);
 	
 	do {
@@ -971,8 +958,6 @@
 		cl = htb_lookup_leaf (q->row[level]+prio,prio,q->ptr[level]+prio);
 	} while (cl != start);
 
-	DEVIK_MEND(6);
-	DEVIK_MSTART(7);
 	if (likely(skb != NULL)) {
 		if ((cl->un.leaf.deficit[level] -= skb->len) < 0) {
 			HTB_DBG(4,2,"htb_next_cl oldptr=%p quant_add=%d\n",
@@ -984,11 +969,8 @@
 		   gives us slightly better performance */
 		if (!cl->un.leaf.q->q.qlen)
 			htb_deactivate (q,cl);
-	DEVIK_MSTART(8);
 		htb_charge_class (q,cl,level,skb->len);
-	DEVIK_MEND(8);
 	}
-	DEVIK_MEND(7);
 	return skb;
 }
 
@@ -1016,6 +998,9 @@
 	struct htb_sched *q = (struct htb_sched *)sch->data;
 	int level;
 	long min_delay;
+#ifdef HTB_DEBUG
+	int evs_used = 0;
+#endif
 
 	HTB_DBG(3,1,"htb_deq dircnt=%d qlen=%d\n",skb_queue_len(&q->direct_queue),
 			sch->q.qlen);
@@ -1027,27 +1012,26 @@
 		return skb;
 	}
 
-	DEVIK_MSTART(2);
 	if (!sch->q.qlen) goto fin;
 	PSCHED_GET_TIME(q->now);
 
-	min_delay = HZ*5;
+	min_delay = LONG_MAX;
 	q->nwc_hit = 0;
 	for (level = 0; level < TC_HTB_MAXDEPTH; level++) {
 		/* common case optimization - skip event handler quickly */
 		int m;
 		long delay;
-	DEVIK_MSTART(3);
 		if (jiffies - q->near_ev_cache[level] < 0x80000000 || 0) {
 			delay = htb_do_events(q,level);
 			q->near_ev_cache[level] += delay ? delay : HZ;
+#ifdef HTB_DEBUG
+			evs_used++;
+#endif
 		} else
 			delay = q->near_ev_cache[level] - jiffies;	
 		
 		if (delay && min_delay > delay) 
 			min_delay = delay;
-	DEVIK_MEND(3);
-	DEVIK_MSTART(5);
 		m = ~q->row_mask[level];
 		while (m != (int)(-1)) {
 			int prio = ffz (m);
@@ -1056,24 +1040,24 @@
 			if (likely(skb != NULL)) {
 				sch->q.qlen--;
 				sch->flags &= ~TCQ_F_THROTTLED;
-	DEVIK_MEND(5);
 				goto fin;
 			}
 		}
-	DEVIK_MEND(5);
 	}
-	DEVIK_MSTART(4);
 #ifdef HTB_DEBUG
-	if (!q->nwc_hit && min_delay >= 5*HZ && net_ratelimit()) { 
-		printk(KERN_ERR "HTB: mindelay=%ld, report it please !\n",min_delay);
-		htb_debug_dump(q);
+	if (!q->nwc_hit && min_delay >= 10*HZ && net_ratelimit()) {
+		if (min_delay == LONG_MAX) {
+			printk(KERN_ERR "HTB: dequeue bug (%d), report it please !\n",
+					evs_used);
+			htb_debug_dump(q);
+		} else 
+			printk(KERN_WARNING "HTB: mindelay=%ld, some class has "
+					"too small rate\n",min_delay);
 	}
 #endif
-	htb_delay_by (sch,min_delay);
-	DEVIK_MEND(4);
+	htb_delay_by (sch,min_delay > 5*HZ ? 5*HZ : min_delay);
 fin:
 	HTB_DBG(3,1,"htb_deq_end %s j=%lu skb=%p\n",sch->dev->name,jiffies,skb);
-	DEVIK_MEND(2);
 	return skb;
 }
 
@@ -1444,6 +1428,7 @@
 	if (!rtab || !ctab) goto failure;
 
 	if (!cl) { /* new class */
+		struct Qdisc *new_q;
 		/* check for valid classid */
 		if (!classid || TC_H_MAJ(classid^sch->handle) || htb_find(classid,sch))
 			goto failure;
@@ -1467,6 +1452,10 @@
 		cl->magic = HTB_CMAGIC;
 #endif
 
+		/* create leaf qdisc early because it uses kmalloc(GPF_KERNEL)
+		   so that can't be used inside of sch_tree_lock
+		   -- thanks to Karlis Peisenieks */
+		new_q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops);
 		sch_tree_lock(sch);
 		if (parent && !parent->level) {
 			/* turn parent into inner node */
@@ -1485,8 +1474,7 @@
 			memset (&parent->un.inner,0,sizeof(parent->un.inner));
 		}
 		/* leaf (we) needs elementary qdisc */
-		if (!(cl->un.leaf.q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops)))
-			cl->un.leaf.q = &noop_qdisc;
+		cl->un.leaf.q = new_q ? new_q : &noop_qdisc;
 
 		cl->classid = classid; cl->parent = parent;
 
@@ -1514,11 +1502,11 @@
 	if (!cl->level) {
 		cl->un.leaf.quantum = rtab->rate.rate / q->rate2quantum;
 		if (!hopt->quantum && cl->un.leaf.quantum < 1000) {
-			printk(KERN_WARNING "HTB: quantum of class %X is small. Consider r2q change.", cl->classid);
+			printk(KERN_WARNING "HTB: quantum of class %X is small. Consider r2q change.\n", cl->classid);
 			cl->un.leaf.quantum = 1000;
 		}
 		if (!hopt->quantum && cl->un.leaf.quantum > 200000) {
-			printk(KERN_WARNING "HTB: quantum of class %X is big. Consider r2q change.", cl->classid);
+			printk(KERN_WARNING "HTB: quantum of class %X is big. Consider r2q change.\n", cl->classid);
 			cl->un.leaf.quantum = 200000;
 		}
 		if (hopt->quantum)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/socket.c linux-2.4.21-pre6/net/socket.c
--- linux-2.4.20/net/socket.c	2002-11-28 23:53:16.000000000 +0000
+++ linux-2.4.21-pre6/net/socket.c	2003-03-26 23:49:27.000000000 +0000
@@ -436,11 +436,11 @@
 	struct inode * inode;
 	struct socket * sock;
 
-	inode = get_empty_inode();
+	inode = new_inode(sock_mnt->mnt_sb);
 	if (!inode)
 		return NULL;
 
-	inode->i_sb = sock_mnt->mnt_sb;
+	inode->i_dev = NODEV;
 	sock = socki_lookup(inode);
 
 	inode->i_mode = S_IFSOCK|S_IRWXUGO;
@@ -1253,7 +1253,7 @@
 		flags |= MSG_DONTWAIT;
 	err=sock_recvmsg(sock, &msg, size, flags);
 
-	if(err >= 0 && addr != NULL && msg.msg_namelen)
+	if(err >= 0 && addr != NULL)
 	{
 		err2=move_addr_to_user(address, msg.msg_namelen, addr, addr_len);
 		if(err2<0)
@@ -1477,7 +1477,7 @@
 		goto out_freeiov;
 	len = err;
 
-	if (uaddr != NULL && msg_sys.msg_namelen) {
+	if (uaddr != NULL) {
 		err = move_addr_to_user(addr, msg_sys.msg_namelen, uaddr, uaddr_len);
 		if (err < 0)
 			goto out_freeiov;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/sunrpc/clnt.c linux-2.4.21-pre6/net/sunrpc/clnt.c
--- linux-2.4.20/net/sunrpc/clnt.c	2002-11-28 23:53:16.000000000 +0000
+++ linux-2.4.21-pre6/net/sunrpc/clnt.c	2003-03-26 23:49:29.000000000 +0000
@@ -43,6 +43,7 @@
 static DECLARE_WAIT_QUEUE_HEAD(destroy_wait);
 
 
+static void	call_start(struct rpc_task *task);
 static void	call_reserve(struct rpc_task *task);
 static void	call_reserveresult(struct rpc_task *task);
 static void	call_allocate(struct rpc_task *task);
@@ -326,13 +327,9 @@
 		rpcauth_bindcred(task);
 
 	if (task->tk_status == 0)
-		task->tk_action = call_reserve;
+		task->tk_action = call_start;
 	else
 		task->tk_action = NULL;
-
-	/* Increment call count */
-	if (task->tk_msg.rpc_proc < task->tk_client->cl_maxproc)
-		rpcproc_count(task->tk_client, task->tk_msg.rpc_proc)++;
 }
 
 void
@@ -359,26 +356,48 @@
 	if (RPC_ASSASSINATED(task))
 		return;
 
-	task->tk_action = call_reserve;
-	rpcproc_count(task->tk_client, task->tk_msg.rpc_proc)++;
+	task->tk_action = call_start;
 }
 
 /*
- * 1.	Reserve an RPC call slot
+ * 0.  Initial state
+ *
+ *     Other FSM states can be visited zero or more times, but
+ *     this state is visited exactly once for each RPC.
  */
 static void
-call_reserve(struct rpc_task *task)
+call_start(struct rpc_task *task)
 {
 	struct rpc_clnt	*clnt = task->tk_client;
 
 	if (task->tk_msg.rpc_proc > clnt->cl_maxproc) {
-		printk(KERN_WARNING "%s (vers %d): bad procedure number %d\n",
-			clnt->cl_protname, clnt->cl_vers, task->tk_msg.rpc_proc);
+		printk(KERN_ERR "%s (vers %d): bad procedure number %d\n",
+				clnt->cl_protname, clnt->cl_vers,
+				task->tk_msg.rpc_proc);
 		rpc_exit(task, -EIO);
 		return;
 	}
 
+	dprintk("RPC: %4d call_start %s%d proc %d (%s)\n", task->tk_pid,
+		clnt->cl_protname, clnt->cl_vers, task->tk_msg.rpc_proc,
+		(RPC_IS_ASYNC(task) ? "async" : "sync"));
+
+	/* Increment call count */
+	rpcproc_count(clnt, task->tk_msg.rpc_proc)++;
+	clnt->cl_stats->rpccnt++;
+	task->tk_action = call_reserve;
+}
+
+/*
+ * 1.	Reserve an RPC call slot
+ */
+static void
+call_reserve(struct rpc_task *task)
+{
+	struct rpc_clnt	*clnt = task->tk_client;
+
 	dprintk("RPC: %4d call_reserve\n", task->tk_pid);
+
 	if (!rpcauth_uptodatecred(task)) {
 		task->tk_action = call_refresh;
 		return;
@@ -387,7 +406,6 @@
 	task->tk_status  = 0;
 	task->tk_action  = call_reserveresult;
 	task->tk_timeout = clnt->cl_timeout.to_resrvval;
-	clnt->cl_stats->rpccnt++;
 	xprt_reserve(task);
 }
 
@@ -645,7 +663,6 @@
 	case -ENOMEM:
 	case -EAGAIN:
 		task->tk_action = call_transmit;
-		clnt->cl_stats->rpcretrans++;
 		break;
 	default:
 		if (clnt->cl_chatty)
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/sunrpc/sched.c linux-2.4.21-pre6/net/sunrpc/sched.c
--- linux-2.4.20/net/sunrpc/sched.c	2002-11-28 23:53:16.000000000 +0000
+++ linux-2.4.21-pre6/net/sunrpc/sched.c	2003-03-26 23:49:40.000000000 +0000
@@ -169,10 +169,8 @@
 static inline void
 rpc_delete_timer(struct rpc_task *task)
 {
-	if (timer_pending(&task->tk_timer)) {
-		dprintk("RPC: %4d deleting timer\n", task->tk_pid);
-		del_timer_sync(&task->tk_timer);
-	}
+	dprintk("RPC: %4d deleting timer\n", task->tk_pid);
+	del_timer_sync(&task->tk_timer);
 }
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/sunrpc/stats.c linux-2.4.21-pre6/net/sunrpc/stats.c
--- linux-2.4.20/net/sunrpc/stats.c	2002-11-28 23:53:16.000000000 +0000
+++ linux-2.4.21-pre6/net/sunrpc/stats.c	2003-03-26 23:49:55.000000000 +0000
@@ -12,7 +12,6 @@
  * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
  */
 
-#define __NO_VERSION__
 #include <linux/module.h>
 
 #include <linux/init.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/sunrpc/sunrpc_syms.c linux-2.4.21-pre6/net/sunrpc/sunrpc_syms.c
--- linux-2.4.20/net/sunrpc/sunrpc_syms.c	2002-11-28 23:53:16.000000000 +0000
+++ linux-2.4.21-pre6/net/sunrpc/sunrpc_syms.c	2003-03-26 23:49:54.000000000 +0000
@@ -6,7 +6,6 @@
  * Copyright (C) 1997 Olaf Kirch <okir@monad.swb.de>
  */
 
-#define __NO_VERSION__
 #include <linux/config.h>
 #include <linux/module.h>
 
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/sunrpc/svc.c linux-2.4.21-pre6/net/sunrpc/svc.c
--- linux-2.4.20/net/sunrpc/svc.c	2002-11-28 23:53:16.000000000 +0000
+++ linux-2.4.21-pre6/net/sunrpc/svc.c	2003-03-26 23:49:54.000000000 +0000
@@ -333,8 +333,12 @@
 		}
 	} else {
 		dprintk("svc: calling dispatcher\n");
-		if (!versp->vs_dispatch(rqstp, statp))
+		if (!versp->vs_dispatch(rqstp, statp)) {
+			/* Release reply info */
+			if (procp->pc_release)
+				procp->pc_release(rqstp, NULL, rqstp->rq_resp);
 			goto dropit;
+		}
 	}
 
 	/* Check RPC status result */
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/sunrpc/svcsock.c linux-2.4.21-pre6/net/sunrpc/svcsock.c
--- linux-2.4.20/net/sunrpc/svcsock.c	2002-11-28 23:53:16.000000000 +0000
+++ linux-2.4.21-pre6/net/sunrpc/svcsock.c	2003-03-26 23:49:06.000000000 +0000
@@ -461,11 +461,8 @@
 		svc_sock_enqueue(svsk);
 	}
 
-	if (sk->sleep && waitqueue_active(sk->sleep)) {
-		printk(KERN_WARNING "RPC svc_write_space: some sleeping on %p\n",
-		       svsk);
+	if (sk->sleep && waitqueue_active(sk->sleep))
 		wake_up_interruptible(sk->sleep);
-	}
 }
 
 /*
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/sunrpc/sysctl.c linux-2.4.21-pre6/net/sunrpc/sysctl.c
--- linux-2.4.20/net/sunrpc/sysctl.c	2001-04-14 03:26:07.000000000 +0000
+++ linux-2.4.21-pre6/net/sunrpc/sysctl.c	2003-03-26 23:49:00.000000000 +0000
@@ -14,7 +14,6 @@
 #include <linux/ctype.h>
 #include <linux/fs.h>
 #include <linux/sysctl.h>
-#define __NO_VERSION__
 #include <linux/module.h>
 
 #include <asm/uaccess.h>
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/sunrpc/xdr.c linux-2.4.21-pre6/net/sunrpc/xdr.c
--- linux-2.4.20/net/sunrpc/xdr.c	2002-11-28 23:53:16.000000000 +0000
+++ linux-2.4.21-pre6/net/sunrpc/xdr.c	2003-03-26 23:49:50.000000000 +0000
@@ -180,7 +180,7 @@
 {
 	struct iovec	*iov = iov_base;
 	struct page	**ppage = xdr->pages;
-	unsigned int	len, pglen = xdr->page_len;
+	unsigned int	len, pglen = xdr->page_len, first_kmap;
 
 	len = xdr->head[0].iov_len;
 	if (base < len) {
@@ -203,9 +203,17 @@
 		ppage += base >> PAGE_CACHE_SHIFT;
 		base &= ~PAGE_CACHE_MASK;
 	}
+	first_kmap = 1;
 	do {
 		len = PAGE_CACHE_SIZE;
-		iov->iov_base = kmap(*ppage);
+		if (first_kmap) {
+			first_kmap = 0;
+			iov->iov_base = kmap(*ppage);
+		} else {
+			iov->iov_base = kmap_nonblock(*ppage);
+			if (!iov->iov_base)
+				goto out;
+		}
 		if (base) {
 			iov->iov_base += base;
 			len -= base;
@@ -223,20 +231,23 @@
 		iov->iov_base = (char *)xdr->tail[0].iov_base + base;
 		iov++;
 	}
+ out:
 	return (iov - iov_base);
 }
 
-void xdr_kunmap(struct xdr_buf *xdr, unsigned int base)
+void xdr_kunmap(struct xdr_buf *xdr, unsigned int base, int niov)
 {
 	struct page	**ppage = xdr->pages;
 	unsigned int	pglen = xdr->page_len;
 
 	if (!pglen)
 		return;
-	if (base > xdr->head[0].iov_len)
+	if (base >= xdr->head[0].iov_len)
 		base -= xdr->head[0].iov_len;
-	else
+	else {
+		niov--;
 		base = 0;
+	}
 
 	if (base >= pglen)
 		return;
@@ -250,7 +261,11 @@
 		 * we bump pglen here, and just subtract PAGE_CACHE_SIZE... */
 		pglen += base & ~PAGE_CACHE_MASK;
 	}
-	for (;;) {
+	/*
+	 * In case we could only do a partial xdr_kmap, all remaining iovecs
+	 * refer to pages. Otherwise we detect the end through pglen.
+	 */
+	for (; niov; niov--) {
 		flush_dcache_page(*ppage);
 		kunmap(*ppage);
 		if (pglen <= PAGE_CACHE_SIZE)
@@ -322,9 +337,22 @@
 xdr_shift_buf(struct xdr_buf *xdr, size_t len)
 {
 	struct iovec iov[MAX_IOVEC];
-	unsigned int nr;
+	unsigned int nr, len_part, n, skip;
+
+	skip = 0;
+	do {
+
+		nr = xdr_kmap(iov, xdr, skip);
+
+		len_part = 0;
+		for (n = 0; n < nr; n++)
+			len_part += iov[n].iov_len;
+
+		xdr_shift_iovec(iov, nr, len_part);
+
+		xdr_kunmap(xdr, skip, nr);
 
-	nr = xdr_kmap(iov, xdr, 0);
-	xdr_shift_iovec(iov, nr, len);
-	xdr_kunmap(xdr, 0);
+		skip += len_part;
+		len -= len_part;
+	} while (len);
 }
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/sunrpc/xprt.c linux-2.4.21-pre6/net/sunrpc/xprt.c
--- linux-2.4.20/net/sunrpc/xprt.c	2002-11-28 23:53:16.000000000 +0000
+++ linux-2.4.21-pre6/net/sunrpc/xprt.c	2003-03-26 23:49:07.000000000 +0000
@@ -226,23 +226,34 @@
 	/* Dont repeat bytes */
 	skip = req->rq_bytes_sent;
 	slen = xdr->len - skip;
-	niov = xdr_kmap(niv, xdr, skip);
+	oldfs = get_fs(); set_fs(get_ds());
+	do {
+		unsigned int slen_part, n;
 
-	msg.msg_flags   = MSG_DONTWAIT|MSG_NOSIGNAL;
-	msg.msg_iov	= niv;
-	msg.msg_iovlen	= niov;
-	msg.msg_name	= (struct sockaddr *) &xprt->addr;
-	msg.msg_namelen = sizeof(xprt->addr);
-	msg.msg_control = NULL;
-	msg.msg_controllen = 0;
+		niov = xdr_kmap(niv, xdr, skip);
 
-	oldfs = get_fs(); set_fs(get_ds());
-	clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags);
-	result = sock_sendmsg(sock, &msg, slen);
+		msg.msg_flags   = MSG_DONTWAIT|MSG_NOSIGNAL;
+		msg.msg_iov	= niv;
+		msg.msg_iovlen	= niov;
+		msg.msg_name	= (struct sockaddr *) &xprt->addr;
+		msg.msg_namelen = sizeof(xprt->addr);
+		msg.msg_control = NULL;
+		msg.msg_controllen = 0;
+
+		slen_part = 0;
+		for (n = 0; n < niov; n++)
+			slen_part += niv[n].iov_len;
+
+		clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags);
+		result = sock_sendmsg(sock, &msg, slen_part);
+
+		xdr_kunmap(xdr, skip, niov);
+
+		skip += slen_part;
+		slen -= slen_part;
+	} while (result >= 0 && slen);
 	set_fs(oldfs);
 
-	xdr_kunmap(xdr, skip);
-
 	dprintk("RPC:      xprt_sendmsg(%d) = %d\n", slen, result);
 
 	if (result >= 0)
@@ -1239,26 +1250,41 @@
 }
 
 /*
+ * Allocate a 'unique' XID
+ */
+static u32
+xprt_alloc_xid(void)
+{
+	static spinlock_t xid_lock = SPIN_LOCK_UNLOCKED;
+	static int need_init = 1;
+	static u32 xid;
+	u32 ret;
+
+	spin_lock(&xid_lock);
+	if (unlikely(need_init)) {
+		xid = CURRENT_TIME << 12;
+		need_init = 0;
+	}
+	ret = xid++;
+	spin_unlock(&xid_lock);
+	return ret;
+}
+
+/*
  * Initialize RPC request
  */
 static void
 xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt)
 {
 	struct rpc_rqst	*req = task->tk_rqstp;
-	static u32	xid = 0;
-
-	if (!xid)
-		xid = CURRENT_TIME << 12;
 
-	dprintk("RPC: %4d reserved req %p xid %08x\n", task->tk_pid, req, xid);
-	task->tk_status = 0;
 	req->rq_timeout = xprt->timeout;
 	req->rq_task	= task;
 	req->rq_xprt    = xprt;
-	req->rq_xid     = xid++;
-	if (!xid)
-		xid++;
+	req->rq_xid     = xprt_alloc_xid();
 	INIT_LIST_HEAD(&req->rq_list);
+	dprintk("RPC: %4d reserved req %p xid %08x\n", task->tk_pid,
+			req, req->rq_xid);
 }
 
 /*
@@ -1416,6 +1442,8 @@
 		sk->no_check = UDP_CSUM_NORCV;
 		xprt_set_connected(xprt);
 	} else {
+		struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+		tp->nonagle = 1;	/* disable Nagle's algorithm */
 		sk->data_ready = tcp_data_ready;
 		sk->state_change = tcp_state_change;
 		xprt_clear_connected(xprt);
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/net/x25/x25_link.c linux-2.4.21-pre6/net/x25/x25_link.c
--- linux-2.4.20/net/x25/x25_link.c	2001-06-30 02:38:26.000000000 +0000
+++ linux-2.4.21-pre6/net/x25/x25_link.c	2003-03-26 23:49:00.000000000 +0000
@@ -219,7 +219,7 @@
 
 	dptr = skb_put(skb, X25_STD_MIN_LEN + 2);
 
-	*dptr++ = ((lci >> 8) & 0x0F) | (neigh->extended) ? X25_GFI_EXTSEQ : X25_GFI_STDSEQ;
+	*dptr++ = ((lci >> 8) & 0x0F) | (neigh->extended ? X25_GFI_EXTSEQ : X25_GFI_STDSEQ);
 	*dptr++ = ((lci >> 0) & 0xFF);
 	*dptr++ = X25_CLEAR_REQUEST;
 	*dptr++ = cause;
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/scripts/Configure linux-2.4.21-pre6/scripts/Configure
--- linux-2.4.20/scripts/Configure	2001-07-02 20:56:40.000000000 +0000
+++ linux-2.4.21-pre6/scripts/Configure	2003-03-26 23:49:09.000000000 +0000
@@ -343,24 +343,14 @@
 #
 # int processes an integer argument with optional limits
 #
-#	int question define default [min max]
+#	int question define default
 #
 function int () {
 	old=$(eval echo "\${$2}")
 	def=${old:-$3}
-	if [ $# -gt 3 ]; then
-	  min=$4
-	else
-	  min=-10000000    # !!
-	fi
-	if [ $# -gt 4 ]; then
-	  max=$5
-	else
-	  max=10000000     # !!
-	fi
 	while :; do
 	  readln "$1 ($2) [$def] " "$def" "$old"
-	  if expr \( \( $ans + 0 \) \>= $min \) \& \( $ans \<= $max \) >/dev/null 2>&1 ; then
+	  if expr "$ans" : '[0-9]*$' > /dev/null; then
             define_int "$2" "$ans"
 	    break
           else
diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.20/scripts/split-include.c linux-2.4.21-pre6/scripts/split-include.c
--- linux-2.4.20/scripts/split-include.c	2002-08-03 00:39:46.000000000 +0000
+++ linux-2.4.21-pre6/scripts/split-include.c	2003-03-26 23:49:27.000000000 +0000
@@ -19,8 +19,8 @@
  *    KEY-5    (empty)     -           leave old empty file alone
  */
 
-#include <sys/stat.h>
 #include <sys/types.h>
+#include <sys/stat.h>
 
 #include <ctype.h>
 #include <errno.h>
